summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-06 02:44:24 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-06 02:44:24 +0000
commit8baab3c8d7a6f22888bd581cd5c6098fd2e4b5a8 (patch)
tree3537e168b860f2742f6029d70501b5ed7d15d345 /src
parentInitial commit. (diff)
downloadvim-8baab3c8d7a6f22888bd581cd5c6098fd2e4b5a8.tar.xz
vim-8baab3c8d7a6f22888bd581cd5c6098fd2e4b5a8.zip
Adding upstream version 2:8.1.0875.upstream/2%8.1.0875upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src')
-rw-r--r--src/GvimExt/GvimExt.reg20
-rw-r--r--src/GvimExt/Make_bc5.mak43
-rw-r--r--src/GvimExt/Make_ming.mak81
-rw-r--r--src/GvimExt/Makefile80
-rw-r--r--src/GvimExt/README.txt94
-rw-r--r--src/GvimExt/gvimext.cpp1090
-rw-r--r--src/GvimExt/gvimext.def8
-rw-r--r--src/GvimExt/gvimext.h181
-rw-r--r--src/GvimExt/gvimext.inf22
-rw-r--r--src/GvimExt/gvimext.rc111
-rw-r--r--src/GvimExt/gvimext_ming.def10
-rw-r--r--src/GvimExt/gvimext_ming.rc45
-rw-r--r--src/GvimExt/resource.h15
-rw-r--r--src/GvimExt/uninst.bat1
-rw-r--r--src/INSTALL384
-rw-r--r--src/INSTALLami.txt34
-rw-r--r--src/INSTALLmac.txt72
-rw-r--r--src/INSTALLpc.txt1051
-rw-r--r--src/INSTALLvms.txt393
-rw-r--r--src/INSTALLx.txt165
-rw-r--r--src/Make_all.mak15
-rw-r--r--src/Make_bc5.mak1060
-rw-r--r--src/Make_cyg.mak54
-rw-r--r--src/Make_cyg_ming.mak1165
-rw-r--r--src/Make_dice.mak285
-rw-r--r--src/Make_dvc.mak105
-rw-r--r--src/Make_ivc.mak763
-rw-r--r--src/Make_manx.mak438
-rw-r--r--src/Make_ming.mak51
-rw-r--r--src/Make_mint.mak56
-rw-r--r--src/Make_morph.mak95
-rw-r--r--src/Make_mvc.mak1701
-rw-r--r--src/Make_sas.mak440
-rw-r--r--src/Make_vms.mms858
-rw-r--r--src/Makefile3871
-rw-r--r--src/README.txt160
-rw-r--r--src/VisVim/Commands.cpp710
-rw-r--r--src/VisVim/Commands.h127
-rw-r--r--src/VisVim/DSAddIn.cpp160
-rw-r--r--src/VisVim/DSAddIn.h53
-rw-r--r--src/VisVim/OleAut.cpp781
-rw-r--r--src/VisVim/OleAut.h73
-rw-r--r--src/VisVim/README_VisVim.txt326
-rw-r--r--src/VisVim/Reg.cpp56
-rw-r--r--src/VisVim/Register.bat1
-rw-r--r--src/VisVim/Res/ToolbarL.bmpbin0 -> 2678 bytes
-rw-r--r--src/VisVim/Res/ToolbarM.bmpbin0 -> 758 bytes
-rw-r--r--src/VisVim/Resource.h30
-rw-r--r--src/VisVim/StdAfx.cpp6
-rw-r--r--src/VisVim/StdAfx.h73
-rw-r--r--src/VisVim/UnRegist.bat1
-rw-r--r--src/VisVim/VisVim.cpp152
-rw-r--r--src/VisVim/VisVim.def11
-rw-r--r--src/VisVim/VisVim.dllbin0 -> 49664 bytes
-rw-r--r--src/VisVim/VisVim.h33
-rw-r--r--src/VisVim/VisVim.mak205
-rw-r--r--src/VisVim/VisVim.odl61
-rw-r--r--src/VisVim/VisVim.rc202
-rw-r--r--src/VisVim/VsReadMe.txt91
-rw-r--r--src/alloc.h33
-rw-r--r--src/arabic.c715
-rw-r--r--src/arabic.h258
-rw-r--r--src/ascii.h186
-rwxr-xr-xsrc/auto/configure16142
-rw-r--r--src/autocmd.c2579
-rw-r--r--src/beval.c281
-rw-r--r--src/beval.h91
-rw-r--r--src/bigvim.bat5
-rw-r--r--src/bigvim64.bat7
-rw-r--r--src/blob.c258
-rw-r--r--src/blowfish.c683
-rw-r--r--src/buffer.c5948
-rw-r--r--src/channel.c6100
-rw-r--r--src/charset.c2093
-rw-r--r--src/config.h.in491
-rw-r--r--src/config.mk.dist5
-rw-r--r--src/config.mk.in175
-rwxr-xr-xsrc/configure10
-rw-r--r--src/configure.ac4486
-rw-r--r--src/create_cmdidxs.vim81
-rw-r--r--src/crypt.c605
-rw-r--r--src/crypt_zip.c152
-rw-r--r--src/dehqx.py45
-rw-r--r--src/dict.c920
-rw-r--r--src/diff.c3221
-rw-r--r--src/digraph.c2472
-rw-r--r--src/dimm.idl544
-rw-r--r--src/dlldata.c38
-rw-r--r--src/dosinst.c2845
-rw-r--r--src/dosinst.h531
-rw-r--r--src/edit.c10296
-rw-r--r--src/eval.c10837
-rw-r--r--src/evalfunc.c14809
-rw-r--r--src/ex_cmdidxs.h72
-rw-r--r--src/ex_cmds.c7754
-rw-r--r--src/ex_cmds.h1819
-rw-r--r--src/ex_cmds2.c5729
-rw-r--r--src/ex_docmd.c12587
-rw-r--r--src/ex_eval.c2294
-rw-r--r--src/ex_getln.c7484
-rw-r--r--src/farsi.c2179
-rw-r--r--src/farsi.h234
-rw-r--r--src/feature.h1352
-rw-r--r--src/fileio.c7872
-rw-r--r--src/fold.c3608
-rw-r--r--src/getchar.c5323
-rw-r--r--src/glbl_ime.cpp263
-rw-r--r--src/glbl_ime.h33
-rw-r--r--src/globals.h1670
-rw-r--r--src/gui.c5460
-rw-r--r--src/gui.h569
-rw-r--r--src/gui_at_fs.c2734
-rw-r--r--src/gui_at_sb.c1192
-rw-r--r--src/gui_at_sb.h161
-rw-r--r--src/gui_athena.c2292
-rw-r--r--src/gui_beval.c1225
-rw-r--r--src/gui_dwrite.cpp1345
-rw-r--r--src/gui_dwrite.h92
-rw-r--r--src/gui_gtk.c2609
-rw-r--r--src/gui_gtk_f.c896
-rw-r--r--src/gui_gtk_f.h85
-rw-r--r--src/gui_gtk_res.xml18
-rw-r--r--src/gui_gtk_vms.h740
-rw-r--r--src/gui_gtk_x11.c7162
-rw-r--r--src/gui_mac.c6731
-rw-r--r--src/gui_motif.c4020
-rw-r--r--src/gui_photon.c2959
-rw-r--r--src/gui_w32.c8930
-rw-r--r--src/gui_w32_rc.h8
-rw-r--r--src/gui_x11.c3396
-rw-r--r--src/gui_x11_pm.h92
-rw-r--r--src/gui_xmdlg.c1287
-rw-r--r--src/gui_xmebw.c1450
-rw-r--r--src/gui_xmebw.h72
-rw-r--r--src/gui_xmebwp.h88
-rw-r--r--src/gvim.exe.mnf38
-rw-r--r--src/gvimtutor8
-rw-r--r--src/hangulin.c1641
-rw-r--r--src/hardcopy.c3499
-rw-r--r--src/hashtab.c482
-rw-r--r--src/if_cscope.c2509
-rw-r--r--src/if_cscope.h73
-rw-r--r--src/if_lua.c2088
-rw-r--r--src/if_mzsch.c3824
-rw-r--r--src/if_mzsch.h76
-rw-r--r--src/if_ole.cpp813
-rw-r--r--src/if_ole.h292
-rw-r--r--src/if_ole.idl45
-rw-r--r--src/if_perl.xs1925
-rw-r--r--src/if_perl_msvc/stdbool.h3
-rw-r--r--src/if_perlsfio.c66
-rw-r--r--src/if_py_both.h6951
-rw-r--r--src/if_python.c1600
-rw-r--r--src/if_python3.c1696
-rw-r--r--src/if_ruby.c1741
-rw-r--r--src/if_tcl.c2109
-rw-r--r--src/if_xcmdsrv.c1527
-rw-r--r--src/iid_ole.c59
-rw-r--r--src/indent.c4460
-rw-r--r--src/infplist.xml74
-rw-r--r--src/install-sh501
-rwxr-xr-xsrc/installman.sh124
-rw-r--r--src/installml.sh170
-rw-r--r--src/iscygpty.c183
-rw-r--r--src/iscygpty.h41
-rw-r--r--src/json.c1108
-rw-r--r--src/json_test.c203
-rw-r--r--src/keymap.h507
-rw-r--r--src/kword_test.c81
-rw-r--r--src/libvterm/.bzrignore13
-rw-r--r--src/libvterm/.gitignore17
-rw-r--r--src/libvterm/LICENSE23
-rw-r--r--src/libvterm/Makefile141
-rw-r--r--src/libvterm/README30
-rw-r--r--src/libvterm/bin/unterm.c288
-rw-r--r--src/libvterm/bin/vterm-ctrl.c368
-rw-r--r--src/libvterm/bin/vterm-dump.c232
-rw-r--r--src/libvterm/doc/URLs14
-rw-r--r--src/libvterm/doc/seqs.txt227
-rw-r--r--src/libvterm/include/vterm.h435
-rw-r--r--src/libvterm/include/vterm_keycodes.h64
-rw-r--r--src/libvterm/src/encoding.c234
-rw-r--r--src/libvterm/src/encoding/DECdrawing.inc136
-rw-r--r--src/libvterm/src/encoding/DECdrawing.tbl31
-rw-r--r--src/libvterm/src/encoding/uk.inc136
-rw-r--r--src/libvterm/src/encoding/uk.tbl1
-rw-r--r--src/libvterm/src/keyboard.c229
-rw-r--r--src/libvterm/src/mouse.c98
-rw-r--r--src/libvterm/src/parser.c346
-rw-r--r--src/libvterm/src/pen.c516
-rw-r--r--src/libvterm/src/rect.h56
-rw-r--r--src/libvterm/src/state.c1925
-rw-r--r--src/libvterm/src/termscreen.c939
-rw-r--r--src/libvterm/src/unicode.c349
-rw-r--r--src/libvterm/src/utf8.h47
-rw-r--r--src/libvterm/src/vterm.c425
-rw-r--r--src/libvterm/src/vterm_internal.h263
-rw-r--r--src/libvterm/t/02parser.test200
-rw-r--r--src/libvterm/t/03encoding_utf8.test122
-rw-r--r--src/libvterm/t/10state_putglyph.test61
-rw-r--r--src/libvterm/t/11state_movecursor.test224
-rw-r--r--src/libvterm/t/12state_scroll.test150
-rw-r--r--src/libvterm/t/13state_edit.test300
-rw-r--r--src/libvterm/t/14state_encoding.test105
-rw-r--r--src/libvterm/t/15state_mode.test86
-rw-r--r--src/libvterm/t/16state_resize.test48
-rw-r--r--src/libvterm/t/17state_mouse.test172
-rw-r--r--src/libvterm/t/18state_termprops.test36
-rw-r--r--src/libvterm/t/20state_wrapping.test69
-rw-r--r--src/libvterm/t/21state_tabstops.test60
-rw-r--r--src/libvterm/t/22state_save.test64
-rw-r--r--src/libvterm/t/25state_input.test143
-rw-r--r--src/libvterm/t/26state_query.test62
-rw-r--r--src/libvterm/t/27state_reset.test32
-rw-r--r--src/libvterm/t/28state_dbl_wh.test61
-rw-r--r--src/libvterm/t/29state_fallback.test19
-rw-r--r--src/libvterm/t/30pen.test106
-rw-r--r--src/libvterm/t/40screen_ascii.test69
-rw-r--r--src/libvterm/t/41screen_unicode.test47
-rw-r--r--src/libvterm/t/42screen_damage.test155
-rw-r--r--src/libvterm/t/43screen_resize.test90
-rw-r--r--src/libvterm/t/44screen_pen.test55
-rw-r--r--src/libvterm/t/45screen_protect.test16
-rw-r--r--src/libvterm/t/46screen_extent.test11
-rw-r--r--src/libvterm/t/47screen_dbl_wh.test32
-rw-r--r--src/libvterm/t/48screen_termprops.test17
-rw-r--r--src/libvterm/t/90vttest_01-movement-1.test87
-rw-r--r--src/libvterm/t/90vttest_01-movement-2.test40
-rw-r--r--src/libvterm/t/90vttest_01-movement-3.test21
-rw-r--r--src/libvterm/t/90vttest_01-movement-4.test36
-rw-r--r--src/libvterm/t/90vttest_02-screen-1.test18
-rw-r--r--src/libvterm/t/90vttest_02-screen-2.test29
-rw-r--r--src/libvterm/t/90vttest_02-screen-3.test16
-rw-r--r--src/libvterm/t/90vttest_02-screen-4.test17
-rw-r--r--src/libvterm/t/92lp1640917.test13
-rw-r--r--src/libvterm/t/harness.c945
-rw-r--r--src/libvterm/t/run-test.pl196
-rw-r--r--src/libvterm/tbl2inc_c.pl51
-rw-r--r--src/libvterm/vterm.pc.in9
-rw-r--r--src/link.3907
-rwxr-xr-xsrc/link.sh151
-rw-r--r--src/list.c1010
-rw-r--r--src/macros.h336
-rw-r--r--src/main.c4296
-rw-r--r--src/mark.c2215
-rw-r--r--src/mbyte.c6936
-rw-r--r--src/memfile.c1491
-rw-r--r--src/memfile_test.c143
-rw-r--r--src/memline.c5679
-rw-r--r--src/menu.c2778
-rw-r--r--src/message.c5161
-rw-r--r--src/message_test.c107
-rw-r--r--src/misc1.c7122
-rw-r--r--src/misc2.c6579
-rw-r--r--src/move.c2864
-rw-r--r--src/msvc2008.bat7
-rw-r--r--src/msvc2010.bat7
-rw-r--r--src/msvc2015.bat37
-rw-r--r--src/msvcsetup.bat12
-rwxr-xr-xsrc/msys32.bat6
-rwxr-xr-xsrc/msys64.bat6
-rw-r--r--src/mysign1
-rw-r--r--src/nbdebug.c162
-rw-r--r--src/nbdebug.h72
-rw-r--r--src/netbeans.c3488
-rw-r--r--src/normal.c9560
-rw-r--r--src/ops.c7467
-rw-r--r--src/option.c13378
-rw-r--r--src/option.h1179
-rw-r--r--src/os_amiga.c1653
-rw-r--r--src/os_amiga.h230
-rw-r--r--src/os_beos.c200
-rw-r--r--src/os_beos.h27
-rw-r--r--src/os_beos.rsrcbin0 -> 6956 bytes
-rw-r--r--src/os_dos.h135
-rw-r--r--src/os_mac.h293
-rw-r--r--src/os_mac.rsr.hqx659
-rw-r--r--src/os_mac_conv.c586
-rw-r--r--src/os_mac_rsrc/app.icnsbin0 -> 47086 bytes
-rw-r--r--src/os_mac_rsrc/doc-txt.icnsbin0 -> 40106 bytes
-rw-r--r--src/os_mac_rsrc/doc.icnsbin0 -> 42287 bytes
-rw-r--r--src/os_macosx.m218
-rw-r--r--src/os_mint.h13
-rw-r--r--src/os_mswin.c3088
-rw-r--r--src/os_qnx.c157
-rw-r--r--src/os_qnx.h19
-rw-r--r--src/os_unix.c8113
-rw-r--r--src/os_unix.h494
-rw-r--r--src/os_unixx.h116
-rw-r--r--src/os_vms.c804
-rw-r--r--src/os_vms_conf.h205
-rw-r--r--src/os_vms_fix.com276
-rw-r--r--src/os_vms_mms.c77
-rw-r--r--src/os_w32dll.c24
-rw-r--r--src/os_w32exe.c137
-rw-r--r--src/os_win32.c7880
-rw-r--r--src/os_win32.h219
-rwxr-xr-xsrc/osdef.sh95
-rw-r--r--src/osdef1.h.in138
-rw-r--r--src/osdef2.h.in100
-rwxr-xr-xsrc/pathdef.sh11
-rw-r--r--src/po/Make_all.mak135
-rw-r--r--src/po/Make_cyg.mak79
-rw-r--r--src/po/Make_ming.mak98
-rw-r--r--src/po/Make_mvc.mak72
-rw-r--r--src/po/Makefile177
-rw-r--r--src/po/README.txt146
-rw-r--r--src/po/README_mingw.txt105
-rw-r--r--src/po/README_mvc.txt119
-rw-r--r--src/po/af.po5393
-rw-r--r--src/po/ca.po6939
-rw-r--r--src/po/check.vim213
-rw-r--r--src/po/cleanup.vim25
-rw-r--r--src/po/cs.cp1250.po4660
-rw-r--r--src/po/cs.po4660
-rw-r--r--src/po/da.po7098
-rw-r--r--src/po/de.po7381
-rw-r--r--src/po/en_GB.po767
-rw-r--r--src/po/eo.po7146
-rw-r--r--src/po/es.po8277
-rw-r--r--src/po/fi.po6993
-rw-r--r--src/po/fr.po7429
-rw-r--r--src/po/ga.po7511
-rw-r--r--src/po/it.po6553
-rw-r--r--src/po/ja.euc-jp.po7068
-rw-r--r--src/po/ja.po7068
-rw-r--r--src/po/ja.sjis.po7068
-rw-r--r--src/po/ko.UTF-8.po7009
-rw-r--r--src/po/ko.po7009
-rw-r--r--src/po/lv.po282
-rw-r--r--src/po/nb.po6166
-rw-r--r--src/po/nl.po5852
-rw-r--r--src/po/no.po6166
-rw-r--r--src/po/pl.UTF-8.po6904
-rw-r--r--src/po/pl.cp1250.po6904
-rw-r--r--src/po/pl.po6904
-rw-r--r--src/po/pt_BR.po7015
-rw-r--r--src/po/ru.cp1251.po7111
-rw-r--r--src/po/ru.po7111
-rw-r--r--src/po/sjiscorr.c48
-rw-r--r--src/po/sk.cp1250.po5822
-rw-r--r--src/po/sk.po5822
-rw-r--r--src/po/sr.po7115
-rw-r--r--src/po/sv.po6148
-rw-r--r--src/po/uk.cp1251.po7333
-rw-r--r--src/po/uk.po7333
-rw-r--r--src/po/vi.po5196
-rw-r--r--src/po/zh_CN.UTF-8.po6140
-rw-r--r--src/po/zh_CN.cp936.po6140
-rw-r--r--src/po/zh_CN.po6140
-rw-r--r--src/po/zh_TW.UTF-8.po5282
-rw-r--r--src/po/zh_TW.po5275
-rw-r--r--src/popupmnu.c1361
-rw-r--r--src/proto.h339
-rw-r--r--src/proto/arabic.pro3
-rw-r--r--src/proto/autocmd.pro39
-rw-r--r--src/proto/beval.pro6
-rw-r--r--src/proto/blob.pro16
-rw-r--r--src/proto/blowfish.pro6
-rw-r--r--src/proto/buffer.pro75
-rw-r--r--src/proto/channel.pro76
-rw-r--r--src/proto/charset.pro64
-rw-r--r--src/proto/crypt.pro22
-rw-r--r--src/proto/crypt_zip.pro5
-rw-r--r--src/proto/dict.pro32
-rw-r--r--src/proto/diff.pro29
-rw-r--r--src/proto/digraph.pro11
-rw-r--r--src/proto/edit.pro47
-rw-r--r--src/proto/eval.pro144
-rw-r--r--src/proto/evalfunc.pro15
-rw-r--r--src/proto/ex_cmds.pro61
-rw-r--r--src/proto/ex_cmds2.pro112
-rw-r--r--src/proto/ex_docmd.pro76
-rw-r--r--src/proto/ex_eval.pro34
-rw-r--r--src/proto/ex_getln.pro60
-rw-r--r--src/proto/farsi.pro12
-rw-r--r--src/proto/fileio.pro36
-rw-r--r--src/proto/fold.pro42
-rw-r--r--src/proto/getchar.pro70
-rw-r--r--src/proto/gui.pro70
-rw-r--r--src/proto/gui_athena.pro31
-rw-r--r--src/proto/gui_beval.pro9
-rw-r--r--src/proto/gui_gtk.pro22
-rw-r--r--src/proto/gui_gtk_gresources.pro5
-rw-r--r--src/proto/gui_gtk_x11.pro79
-rw-r--r--src/proto/gui_mac.pro151
-rw-r--r--src/proto/gui_motif.pro46
-rw-r--r--src/proto/gui_photon.pro70
-rw-r--r--src/proto/gui_w32.pro99
-rw-r--r--src/proto/gui_x11.pro73
-rw-r--r--src/proto/gui_xmdlg.pro3
-rw-r--r--src/proto/hangulin.pro11
-rw-r--r--src/proto/hardcopy.pro20
-rw-r--r--src/proto/hashtab.pro14
-rw-r--r--src/proto/if_cscope.pro12
-rw-r--r--src/proto/if_lua.pro11
-rw-r--r--src/proto/if_mzsch.pro17
-rw-r--r--src/proto/if_ole.pro5
-rw-r--r--src/proto/if_perl.pro9
-rw-r--r--src/proto/if_perlsfio.pro3
-rw-r--r--src/proto/if_python.pro13
-rw-r--r--src/proto/if_python3.pro13
-rw-r--r--src/proto/if_ruby.pro10
-rw-r--r--src/proto/if_tcl.pro10
-rw-r--r--src/proto/if_xcmdsrv.pro13
-rw-r--r--src/proto/indent.pro16
-rw-r--r--src/proto/json.pro7
-rw-r--r--src/proto/list.pro40
-rw-r--r--src/proto/main.pro17
-rw-r--r--src/proto/mark.pro38
-rw-r--r--src/proto/mbyte.pro101
-rw-r--r--src/proto/memfile.pro18
-rw-r--r--src/proto/memline.pro40
-rw-r--r--src/proto/menu.pro27
-rw-r--r--src/proto/message.pro83
-rw-r--r--src/proto/misc1.pro102
-rw-r--r--src/proto/misc2.pro119
-rw-r--r--src/proto/move.pro43
-rw-r--r--src/proto/netbeans.pro28
-rw-r--r--src/proto/normal.pro26
-rw-r--r--src/proto/ops.pro68
-rw-r--r--src/proto/option.pro85
-rw-r--r--src/proto/os_amiga.pro46
-rw-r--r--src/proto/os_beos.pro4
-rw-r--r--src/proto/os_mac_conv.pro12
-rw-r--r--src/proto/os_mswin.pro54
-rw-r--r--src/proto/os_qnx.pro8
-rw-r--r--src/proto/os_unix.pro86
-rw-r--r--src/proto/os_vms.pro16
-rw-r--r--src/proto/os_win32.pro76
-rw-r--r--src/proto/popupmnu.pro17
-rw-r--r--src/proto/pty.pro5
-rw-r--r--src/proto/quickfix.pro34
-rw-r--r--src/proto/regexp.pro20
-rw-r--r--src/proto/screen.pro64
-rw-r--r--src/proto/search.pro51
-rw-r--r--src/proto/sha256.pro9
-rw-r--r--src/proto/sign.pro27
-rw-r--r--src/proto/spell.pro38
-rw-r--r--src/proto/spellfile.pro9
-rw-r--r--src/proto/syntax.pro65
-rw-r--r--src/proto/tag.pro14
-rw-r--r--src/proto/term.pro83
-rw-r--r--src/proto/terminal.pro62
-rw-r--r--src/proto/termlib.pro8
-rw-r--r--src/proto/textprop.pro18
-rw-r--r--src/proto/ui.pro72
-rw-r--r--src/proto/undo.pro31
-rw-r--r--src/proto/userfunc.pro58
-rw-r--r--src/proto/version.pro11
-rw-r--r--src/proto/winclip.pro15
-rw-r--r--src/proto/window.pro98
-rw-r--r--src/protodef.h18
-rw-r--r--src/pty.c443
-rw-r--r--src/quickfix.c7252
-rw-r--r--src/regexp.c8291
-rw-r--r--src/regexp.h176
-rw-r--r--src/regexp_nfa.c7362
-rw-r--r--src/screen.c11034
-rw-r--r--src/search.c5751
-rw-r--r--src/sha256.c427
-rw-r--r--src/sign.c1941
-rw-r--r--src/spell.c8841
-rw-r--r--src/spell.h301
-rw-r--r--src/spellfile.c6651
-rw-r--r--src/structs.h3540
-rw-r--r--src/syntax.c10346
-rw-r--r--src/tag.c4209
-rw-r--r--src/tearoff.bmpbin0 -> 118 bytes
-rw-r--r--src/tee/Make_mvc.mak19
-rw-r--r--src/tee/Makefile21
-rw-r--r--src/tee/tee.c161
-rw-r--r--src/term.c7152
-rw-r--r--src/term.h210
-rw-r--r--src/terminal.c6370
-rw-r--r--src/termlib.c618
-rw-r--r--src/testdir/Make_all.mak418
-rw-r--r--src/testdir/Make_amiga.mak45
-rw-r--r--src/testdir/Make_dos.mak138
-rw-r--r--src/testdir/Make_ming.mak142
-rw-r--r--src/testdir/Make_vms.mms212
-rw-r--r--src/testdir/Makefile173
-rw-r--r--src/testdir/README.txt73
-rw-r--r--src/testdir/amiga.vim6
-rw-r--r--src/testdir/bench_re_freeze.in13
-rw-r--r--src/testdir/bench_re_freeze.vim13
-rw-r--r--src/testdir/color_ramp.vim41
-rw-r--r--src/testdir/dos.vim9
-rw-r--r--src/testdir/dotest.in3
-rw-r--r--src/testdir/dumps/Test_conceal_cul_01.dump20
-rw-r--r--src/testdir/dumps/Test_conceal_cul_02.dump20
-rw-r--r--src/testdir/dumps/Test_conceal_cul_03.dump20
-rw-r--r--src/testdir/dumps/Test_conceal_two_windows_01.dump20
-rw-r--r--src/testdir/dumps/Test_conceal_two_windows_02.dump20
-rw-r--r--src/testdir/dumps/Test_conceal_two_windows_03.dump20
-rw-r--r--src/testdir/dumps/Test_conceal_two_windows_04.dump20
-rw-r--r--src/testdir/dumps/Test_conceal_two_windows_05.dump20
-rw-r--r--src/testdir/dumps/Test_conceal_two_windows_06c.dump20
-rw-r--r--src/testdir/dumps/Test_conceal_two_windows_06i.dump20
-rw-r--r--src/testdir/dumps/Test_conceal_two_windows_06n.dump20
-rw-r--r--src/testdir/dumps/Test_conceal_two_windows_06v.dump20
-rw-r--r--src/testdir/dumps/Test_conceal_two_windows_07c.dump20
-rw-r--r--src/testdir/dumps/Test_conceal_two_windows_07i.dump20
-rw-r--r--src/testdir/dumps/Test_conceal_two_windows_07n.dump20
-rw-r--r--src/testdir/dumps/Test_conceal_two_windows_07v.dump20
-rw-r--r--src/testdir/dumps/Test_conceal_two_windows_08c.dump20
-rw-r--r--src/testdir/dumps/Test_conceal_two_windows_08i.dump20
-rw-r--r--src/testdir/dumps/Test_conceal_two_windows_08n.dump20
-rw-r--r--src/testdir/dumps/Test_conceal_two_windows_08v.dump20
-rw-r--r--src/testdir/dumps/Test_conceal_two_windows_09c.dump20
-rw-r--r--src/testdir/dumps/Test_conceal_two_windows_09i.dump20
-rw-r--r--src/testdir/dumps/Test_conceal_two_windows_09n.dump20
-rw-r--r--src/testdir/dumps/Test_conceal_two_windows_09v.dump20
-rw-r--r--src/testdir/dumps/Test_conceal_two_windows_10.dump20
-rw-r--r--src/testdir/dumps/Test_conceal_two_windows_11.dump20
-rw-r--r--src/testdir/dumps/Test_conceal_two_windows_12.dump20
-rw-r--r--src/testdir/dumps/Test_conceal_two_windows_13.dump20
-rw-r--r--src/testdir/dumps/Test_cursorline_yank_01.dump8
-rw-r--r--src/testdir/dumps/Test_diff_01.dump20
-rw-r--r--src/testdir/dumps/Test_diff_02.dump20
-rw-r--r--src/testdir/dumps/Test_diff_03.dump20
-rw-r--r--src/testdir/dumps/Test_diff_04.dump20
-rw-r--r--src/testdir/dumps/Test_diff_05.dump20
-rw-r--r--src/testdir/dumps/Test_diff_06.dump20
-rw-r--r--src/testdir/dumps/Test_diff_07.dump20
-rw-r--r--src/testdir/dumps/Test_diff_08.dump20
-rw-r--r--src/testdir/dumps/Test_diff_09.dump20
-rw-r--r--src/testdir/dumps/Test_diff_10.dump20
-rw-r--r--src/testdir/dumps/Test_diff_11.dump20
-rw-r--r--src/testdir/dumps/Test_diff_12.dump20
-rw-r--r--src/testdir/dumps/Test_diff_13.dump20
-rw-r--r--src/testdir/dumps/Test_diff_14.dump20
-rw-r--r--src/testdir/dumps/Test_diff_15.dump20
-rw-r--r--src/testdir/dumps/Test_diff_16.dump20
-rw-r--r--src/testdir/dumps/Test_diff_17.dump20
-rw-r--r--src/testdir/dumps/Test_diff_18.dump20
-rw-r--r--src/testdir/dumps/Test_diff_19.dump20
-rw-r--r--src/testdir/dumps/Test_diff_20.dump20
-rw-r--r--src/testdir/dumps/Test_diff_of_diff_01.dump20
-rw-r--r--src/testdir/dumps/Test_diff_with_cursorline_01.dump20
-rw-r--r--src/testdir/dumps/Test_diff_with_cursorline_02.dump20
-rw-r--r--src/testdir/dumps/Test_diff_with_cursorline_03.dump20
-rw-r--r--src/testdir/dumps/Test_folds_with_rnu_01.dump20
-rw-r--r--src/testdir/dumps/Test_folds_with_rnu_02.dump20
-rw-r--r--src/testdir/dumps/Test_incsearch_scrolling_01.dump9
-rw-r--r--src/testdir/dumps/Test_incsearch_search_01.dump9
-rw-r--r--src/testdir/dumps/Test_incsearch_search_02.dump9
-rw-r--r--src/testdir/dumps/Test_incsearch_sort_01.dump9
-rw-r--r--src/testdir/dumps/Test_incsearch_substitute_01.dump9
-rw-r--r--src/testdir/dumps/Test_incsearch_substitute_02.dump9
-rw-r--r--src/testdir/dumps/Test_incsearch_substitute_03.dump9
-rw-r--r--src/testdir/dumps/Test_incsearch_substitute_04.dump9
-rw-r--r--src/testdir/dumps/Test_incsearch_substitute_05.dump9
-rw-r--r--src/testdir/dumps/Test_incsearch_substitute_06.dump9
-rw-r--r--src/testdir/dumps/Test_incsearch_substitute_07.dump9
-rw-r--r--src/testdir/dumps/Test_incsearch_substitute_08.dump9
-rw-r--r--src/testdir/dumps/Test_incsearch_substitute_09.dump9
-rw-r--r--src/testdir/dumps/Test_incsearch_substitute_10.dump9
-rw-r--r--src/testdir/dumps/Test_incsearch_substitute_11.dump9
-rw-r--r--src/testdir/dumps/Test_incsearch_substitute_12.dump9
-rw-r--r--src/testdir/dumps/Test_incsearch_substitute_13.dump9
-rw-r--r--src/testdir/dumps/Test_incsearch_vimgrep_01.dump9
-rw-r--r--src/testdir/dumps/Test_incsearch_vimgrep_02.dump9
-rw-r--r--src/testdir/dumps/Test_incsearch_vimgrep_03.dump9
-rw-r--r--src/testdir/dumps/Test_incsearch_vimgrep_04.dump9
-rw-r--r--src/testdir/dumps/Test_incsearch_vimgrep_05.dump9
-rw-r--r--src/testdir/dumps/Test_popup_and_previewwindow_01.dump20
-rw-r--r--src/testdir/dumps/Test_popup_command_01.dump20
-rw-r--r--src/testdir/dumps/Test_popup_command_02.dump20
-rw-r--r--src/testdir/dumps/Test_popup_command_03.dump20
-rw-r--r--src/testdir/dumps/Test_popup_position_01.dump8
-rw-r--r--src/testdir/dumps/Test_popup_position_02.dump8
-rw-r--r--src/testdir/dumps/Test_popup_position_03.dump8
-rw-r--r--src/testdir/dumps/Test_popup_position_04.dump10
-rw-r--r--src/testdir/dumps/Test_syntax_c_01.dump20
-rw-r--r--src/testdir/dumps/Test_tenc_euc_jp_01.dump10
-rw-r--r--src/testdir/dumps/Test_textprop_01.dump6
-rw-r--r--src/testdir/gen_opt_test.vim226
-rw-r--r--src/testdir/gui_init.vim6
-rw-r--r--src/testdir/gui_preinit.vim7
-rw-r--r--src/testdir/if_ver-1.vim26
-rw-r--r--src/testdir/if_ver-2.vim10
-rw-r--r--src/testdir/lsan-suppress.txt3
-rw-r--r--src/testdir/python2/module.py2
-rw-r--r--src/testdir/python3/module.py2
-rw-r--r--src/testdir/python_after/after.py2
-rw-r--r--src/testdir/python_before/before.py1
-rw-r--r--src/testdir/python_before/before_1.py1
-rw-r--r--src/testdir/python_before/before_2.py1
-rw-r--r--src/testdir/pythonx/failing.py1
-rw-r--r--src/testdir/pythonx/failing_import.py1
-rw-r--r--src/testdir/pythonx/module.py1
-rw-r--r--src/testdir/pythonx/modulex.py1
-rw-r--r--src/testdir/pythonx/topmodule/__init__.py1
-rw-r--r--src/testdir/pythonx/topmodule/submodule/__init__.py1
-rw-r--r--src/testdir/pythonx/topmodule/submodule/subsubmodule/__init__.py1
-rw-r--r--src/testdir/pythonx/topmodule/submodule/subsubmodule/subsubsubmodule.py1
-rw-r--r--src/testdir/pyxfile/py2_magic.py4
-rw-r--r--src/testdir/pyxfile/py2_shebang.py4
-rw-r--r--src/testdir/pyxfile/py3_magic.py4
-rw-r--r--src/testdir/pyxfile/py3_shebang.py4
-rw-r--r--src/testdir/pyxfile/pyx.py2
-rw-r--r--src/testdir/runtest.vim401
-rw-r--r--src/testdir/samples/quickfix.txt4
-rw-r--r--src/testdir/samples/re.freeze.txt6
-rw-r--r--src/testdir/samples/test000bin0 -> 8 bytes
-rw-r--r--src/testdir/sautest/autoload/Test104.vim1
-rw-r--r--src/testdir/sautest/autoload/foo.vim7
-rw-r--r--src/testdir/sautest/autoload/footest.vim5
-rw-r--r--src/testdir/sautest/autoload/globone.vim1
-rw-r--r--src/testdir/sautest/autoload/globtwo.vim1
-rw-r--r--src/testdir/sautest/autoload/sourced.vim3
-rw-r--r--src/testdir/screendump.vim130
-rw-r--r--src/testdir/setup.vim33
-rw-r--r--src/testdir/setup_gui.vim32
-rw-r--r--src/testdir/shared.vim357
-rw-r--r--src/testdir/test1.in52
-rw-r--r--src/testdir/test1.ok1
-rw-r--r--src/testdir/test108.in88
-rw-r--r--src/testdir/test108.ok82
-rw-r--r--src/testdir/test11.in84
-rw-r--r--src/testdir/test11.ok61
-rw-r--r--src/testdir/test14.in100
-rw-r--r--src/testdir/test14.ok26
-rw-r--r--src/testdir/test17.in135
-rw-r--r--src/testdir/test17.ok33
-rw-r--r--src/testdir/test17a.in3
-rw-r--r--src/testdir/test29.in231
-rw-r--r--src/testdir/test29.ok97
-rw-r--r--src/testdir/test3.in2354
-rw-r--r--src/testdir/test3.ok2102
-rw-r--r--src/testdir/test30.in238
-rw-r--r--src/testdir/test30.ok130
-rw-r--r--src/testdir/test37.in116
-rw-r--r--src/testdir/test37.ok33
-rw-r--r--src/testdir/test39.in118
-rw-r--r--src/testdir/test39.okbin0 -> 662 bytes
-rw-r--r--src/testdir/test42.inbin0 -> 2368 bytes
-rw-r--r--src/testdir/test42.okbin0 -> 409 bytes
-rw-r--r--src/testdir/test44.in81
-rw-r--r--src/testdir/test44.ok25
-rw-r--r--src/testdir/test48.in83
-rw-r--r--src/testdir/test48.ok23
-rw-r--r--src/testdir/test49.in32
-rw-r--r--src/testdir/test49.ok84
-rw-r--r--src/testdir/test49.vim9009
-rw-r--r--src/testdir/test52.in65
-rw-r--r--src/testdir/test52.ok18
-rw-r--r--src/testdir/test59.in626
-rw-r--r--src/testdir/test59.ok270
-rw-r--r--src/testdir/test64.in654
-rw-r--r--src/testdir/test64.ok1107
-rw-r--r--src/testdir/test69.in192
-rw-r--r--src/testdir/test69.ok166
-rw-r--r--src/testdir/test70.in63
-rw-r--r--src/testdir/test70.ok6
-rw-r--r--src/testdir/test72.in146
-rw-r--r--src/testdir/test72.ok31
-rw-r--r--src/testdir/test77a.com8
-rw-r--r--src/testdir/test77a.in31
-rw-r--r--src/testdir/test77a.ok1
-rw-r--r--src/testdir/test83-tags22
-rw-r--r--src/testdir/test83-tags3102
-rw-r--r--src/testdir/test85.ok7
-rw-r--r--src/testdir/test86.in1711
-rw-r--r--src/testdir/test86.ok1445
-rw-r--r--src/testdir/test87.in1725
-rw-r--r--src/testdir/test87.ok1445
-rw-r--r--src/testdir/test88.in99
-rw-r--r--src/testdir/test88.ok29
-rw-r--r--src/testdir/test94.in257
-rw-r--r--src/testdir/test94.ok123
-rw-r--r--src/testdir/test95.in141
-rw-r--r--src/testdir/test95.ok140
-rw-r--r--src/testdir/test99.in69
-rw-r--r--src/testdir/test99.ok23
-rw-r--r--src/testdir/test_alot.vim68
-rw-r--r--src/testdir/test_alot_latin.vim7
-rw-r--r--src/testdir/test_alot_utf8.vim16
-rw-r--r--src/testdir/test_arabic.vim613
-rw-r--r--src/testdir/test_arglist.vim482
-rw-r--r--src/testdir/test_assert.vim218
-rw-r--r--src/testdir/test_assign.vim53
-rw-r--r--src/testdir/test_autochdir.vim27
-rw-r--r--src/testdir/test_autocmd.vim1418
-rw-r--r--src/testdir/test_autoload.vim17
-rw-r--r--src/testdir/test_backspace_opt.vim59
-rw-r--r--src/testdir/test_backup.vim58
-rw-r--r--src/testdir/test_behave.vim29
-rw-r--r--src/testdir/test_blob.vim320
-rw-r--r--src/testdir/test_blockedit.vim33
-rw-r--r--src/testdir/test_breakindent.vim617
-rw-r--r--src/testdir/test_bufline.vim141
-rw-r--r--src/testdir/test_bufwintabinfo.vim141
-rw-r--r--src/testdir/test_cd.vim67
-rw-r--r--src/testdir/test_cdo.vim205
-rw-r--r--src/testdir/test_changedtick.vim57
-rw-r--r--src/testdir/test_changelist.vim48
-rw-r--r--src/testdir/test_channel.py269
-rw-r--r--src/testdir/test_channel.vim2028
-rw-r--r--src/testdir/test_channel_pipe.py63
-rw-r--r--src/testdir/test_channel_write.py18
-rw-r--r--src/testdir/test_charsearch.vim62
-rw-r--r--src/testdir/test_charsearch_utf8.vim19
-rw-r--r--src/testdir/test_cindent.vim105
-rw-r--r--src/testdir/test_clientserver.vim104
-rw-r--r--src/testdir/test_close_count.vim174
-rw-r--r--src/testdir/test_cmdline.vim612
-rw-r--r--src/testdir/test_command_count.vim196
-rw-r--r--src/testdir/test_comparators.vim9
-rw-r--r--src/testdir/test_compiler.vim54
-rw-r--r--src/testdir/test_conceal.vim136
-rw-r--r--src/testdir/test_crypt.vim113
-rw-r--r--src/testdir/test_cscope.vim302
-rw-r--r--src/testdir/test_cursor_func.vim68
-rw-r--r--src/testdir/test_curswant.vim23
-rw-r--r--src/testdir/test_delete.vim107
-rw-r--r--src/testdir/test_diffmode.vim915
-rw-r--r--src/testdir/test_digraph.vim477
-rw-r--r--src/testdir/test_display.vim69
-rw-r--r--src/testdir/test_edit.vim1438
-rw-r--r--src/testdir/test_erasebackword.vim19
-rw-r--r--src/testdir/test_escaped_glob.vim33
-rw-r--r--src/testdir/test_eval.in249
-rw-r--r--src/testdir/test_eval.okbin0 -> 11279 bytes
-rw-r--r--src/testdir/test_eval_func.vim10
-rw-r--r--src/testdir/test_eval_stuff.vim96
-rw-r--r--src/testdir/test_ex_equal.vim32
-rw-r--r--src/testdir/test_ex_undo.vim19
-rw-r--r--src/testdir/test_ex_z.vim85
-rw-r--r--src/testdir/test_exec_while_if.vim53
-rw-r--r--src/testdir/test_execute_func.vim80
-rw-r--r--src/testdir/test_exists.vim321
-rw-r--r--src/testdir/test_exists_autocmd.vim26
-rw-r--r--src/testdir/test_exit.vim57
-rw-r--r--src/testdir/test_expand.vim49
-rw-r--r--src/testdir/test_expand_dllpath.vim32
-rw-r--r--src/testdir/test_expand_func.vim66
-rw-r--r--src/testdir/test_expr.vim514
-rw-r--r--src/testdir/test_expr_utf8.vim34
-rw-r--r--src/testdir/test_farsi.vim133
-rw-r--r--src/testdir/test_feedkeys.vim14
-rw-r--r--src/testdir/test_file_perm.vim24
-rw-r--r--src/testdir/test_file_size.vim58
-rw-r--r--src/testdir/test_filechanged.vim146
-rw-r--r--src/testdir/test_fileformat.vim33
-rw-r--r--src/testdir/test_filetype.vim603
-rw-r--r--src/testdir/test_filter_cmd.vim132
-rw-r--r--src/testdir/test_filter_map.vim86
-rw-r--r--src/testdir/test_find_complete.vim163
-rw-r--r--src/testdir/test_findfile.vim185
-rw-r--r--src/testdir/test_fixeol.vim48
-rw-r--r--src/testdir/test_float_func.vim331
-rw-r--r--src/testdir/test_fnameescape.vim21
-rw-r--r--src/testdir/test_fnamemodify.vim53
-rw-r--r--src/testdir/test_fold.vim743
-rw-r--r--src/testdir/test_functions.vim1248
-rw-r--r--src/testdir/test_ga.vim33
-rw-r--r--src/testdir/test_getcwd.vim112
-rw-r--r--src/testdir/test_getvar.vim104
-rw-r--r--src/testdir/test_gf.vim61
-rw-r--r--src/testdir/test_glob2regpat.vim30
-rw-r--r--src/testdir/test_global.vim20
-rw-r--r--src/testdir/test_gn.vim153
-rw-r--r--src/testdir/test_goto.vim373
-rw-r--r--src/testdir/test_gui.vim779
-rw-r--r--src/testdir/test_gui_init.vim61
-rw-r--r--src/testdir/test_hardcopy.vim89
-rw-r--r--src/testdir/test_help.vim51
-rw-r--r--src/testdir/test_help_tagjump.vim260
-rw-r--r--src/testdir/test_hide.vim97
-rw-r--r--src/testdir/test_highlight.vim554
-rw-r--r--src/testdir/test_history.vim111
-rw-r--r--src/testdir/test_hlsearch.vim65
-rw-r--r--src/testdir/test_iminsert.vim27
-rw-r--r--src/testdir/test_increment.vim781
-rw-r--r--src/testdir/test_increment_dbcs.vim27
-rw-r--r--src/testdir/test_ins_complete.vim312
-rw-r--r--src/testdir/test_job_fails.vim16
-rw-r--r--src/testdir/test_join.vim35
-rw-r--r--src/testdir/test_json.vim291
-rw-r--r--src/testdir/test_jumplist.vim62
-rw-r--r--src/testdir/test_jumps.vim11
-rw-r--r--src/testdir/test_lambda.vim292
-rw-r--r--src/testdir/test_langmap.vim28
-rw-r--r--src/testdir/test_largefile.vim34
-rw-r--r--src/testdir/test_let.vim27
-rw-r--r--src/testdir/test_lineending.vim19
-rw-r--r--src/testdir/test_lispwords.vim82
-rw-r--r--src/testdir/test_listchars.vim115
-rw-r--r--src/testdir/test_listdict.vim653
-rw-r--r--src/testdir/test_listlbr.vim235
-rw-r--r--src/testdir/test_listlbr_utf8.vim271
-rw-r--r--src/testdir/test_lua.vim575
-rw-r--r--src/testdir/test_makeencoding.py67
-rw-r--r--src/testdir/test_makeencoding.vim103
-rw-r--r--src/testdir/test_man.vim60
-rw-r--r--src/testdir/test_maparg.vim58
-rw-r--r--src/testdir/test_mapping.vim320
-rw-r--r--src/testdir/test_marks.vim176
-rw-r--r--src/testdir/test_match.vim241
-rw-r--r--src/testdir/test_matchadd_conceal.vim279
-rw-r--r--src/testdir/test_matchadd_conceal_utf8.vim43
-rw-r--r--src/testdir/test_menu.vim66
-rw-r--r--src/testdir/test_messages.vim94
-rw-r--r--src/testdir/test_mksession.vim498
-rw-r--r--src/testdir/test_mksession_utf8.vim105
-rw-r--r--src/testdir/test_modeline.vim94
-rw-r--r--src/testdir/test_move.vim40
-rw-r--r--src/testdir/test_nested_function.vim67
-rw-r--r--src/testdir/test_netbeans.py91
-rw-r--r--src/testdir/test_netbeans.vim86
-rw-r--r--src/testdir/test_normal.vim2544
-rw-r--r--src/testdir/test_number.vim254
-rw-r--r--src/testdir/test_options.vim520
-rw-r--r--src/testdir/test_packadd.vim357
-rw-r--r--src/testdir/test_partial.vim386
-rw-r--r--src/testdir/test_paste.vim112
-rw-r--r--src/testdir/test_perl.vim286
-rw-r--r--src/testdir/test_plus_arg_edit.vim34
-rw-r--r--src/testdir/test_popup.vim899
-rw-r--r--src/testdir/test_preview.vim13
-rw-r--r--src/testdir/test_profile.vim520
-rw-r--r--src/testdir/test_prompt_buffer.vim105
-rw-r--r--src/testdir/test_put.vim103
-rw-r--r--src/testdir/test_python2.vim65
-rw-r--r--src/testdir/test_python3.vim65
-rw-r--r--src/testdir/test_pyx2.vim74
-rw-r--r--src/testdir/test_pyx3.vim74
-rw-r--r--src/testdir/test_quickfix.vim3901
-rw-r--r--src/testdir/test_quotestar.vim154
-rw-r--r--src/testdir/test_recover.vim62
-rw-r--r--src/testdir/test_regex_char_classes.vim295
-rw-r--r--src/testdir/test_regexp_latin.vim86
-rw-r--r--src/testdir/test_regexp_utf8.vim208
-rw-r--r--src/testdir/test_registers.vim65
-rw-r--r--src/testdir/test_reltime.vim26
-rw-r--r--src/testdir/test_retab.vim77
-rw-r--r--src/testdir/test_ruby.vim379
-rw-r--r--src/testdir/test_scriptnames.vim26
-rw-r--r--src/testdir/test_scroll_opt.vim36
-rw-r--r--src/testdir/test_scrollbind.vim32
-rw-r--r--src/testdir/test_search.vim1189
-rw-r--r--src/testdir/test_searchpos.vim28
-rw-r--r--src/testdir/test_set.vim27
-rw-r--r--src/testdir/test_sha256.vim22
-rw-r--r--src/testdir/test_short_sleep.py11
-rw-r--r--src/testdir/test_shortpathname.vim70
-rw-r--r--src/testdir/test_signs.vim1340
-rw-r--r--src/testdir/test_smartindent.vim41
-rw-r--r--src/testdir/test_sort.vim1253
-rw-r--r--src/testdir/test_source.vim38
-rw-r--r--src/testdir/test_source_utf8.vim60
-rw-r--r--src/testdir/test_spell.vim887
-rw-r--r--src/testdir/test_startup.vim539
-rw-r--r--src/testdir/test_startup_utf8.vim83
-rw-r--r--src/testdir/test_stat.vim185
-rw-r--r--src/testdir/test_statusline.vim343
-rw-r--r--src/testdir/test_substitute.vim502
-rw-r--r--src/testdir/test_suspend.vim55
-rw-r--r--src/testdir/test_swap.vim166
-rw-r--r--src/testdir/test_syn_attr.vim818
-rw-r--r--src/testdir/test_syntax.vim585
-rw-r--r--src/testdir/test_system.vim92
-rw-r--r--src/testdir/test_tab.vim90
-rw-r--r--src/testdir/test_tabline.vim72
-rw-r--r--src/testdir/test_tabpage.vim558
-rw-r--r--src/testdir/test_tagcase.vim73
-rw-r--r--src/testdir/test_tagjump.vim369
-rw-r--r--src/testdir/test_taglist.vim86
-rw-r--r--src/testdir/test_tcl.vim680
-rw-r--r--src/testdir/test_termencoding.vim37
-rw-r--r--src/testdir/test_terminal.vim1758
-rw-r--r--src/testdir/test_terminal_fail.vim21
-rw-r--r--src/testdir/test_textformat.vim491
-rw-r--r--src/testdir/test_textobjects.vim259
-rw-r--r--src/testdir/test_textprop.vim552
-rw-r--r--src/testdir/test_timers.vim313
-rw-r--r--src/testdir/test_true_false.vim150
-rw-r--r--src/testdir/test_undo.vim444
-rw-r--r--src/testdir/test_unlet.vim57
-rw-r--r--src/testdir/test_user_func.vim96
-rw-r--r--src/testdir/test_usercommands.vim306
-rw-r--r--src/testdir/test_utf8.vim62
-rw-r--r--src/testdir/test_utf8_comparisons.vim91
-rw-r--r--src/testdir/test_vartabs.vim374
-rw-r--r--src/testdir/test_viminfo.vim534
-rw-r--r--src/testdir/test_vimscript.vim1448
-rw-r--r--src/testdir/test_virtualedit.vim75
-rw-r--r--src/testdir/test_visual.vim399
-rw-r--r--src/testdir/test_winbar.vim23
-rw-r--r--src/testdir/test_winbuf_close.vim160
-rw-r--r--src/testdir/test_window_cmd.vim618
-rw-r--r--src/testdir/test_window_id.vim123
-rw-r--r--src/testdir/test_windows_home.vim121
-rw-r--r--src/testdir/test_wordcount.vim104
-rw-r--r--src/testdir/test_writefile.vim152
-rw-r--r--src/testdir/test_xxd.vim183
-rw-r--r--src/testdir/unix.vim13
-rw-r--r--src/testdir/view_util.vim51
-rw-r--r--src/testdir/vms.vim6
-rw-r--r--src/textprop.c1081
-rw-r--r--src/toolbar.phi1283
-rwxr-xr-xsrc/toolcheck36
-rw-r--r--src/tools.bmpbin0 -> 4660 bytes
-rw-r--r--src/typemap14
-rw-r--r--src/ui.c3533
-rw-r--r--src/undo.c3592
-rw-r--r--src/uninstal.c428
-rw-r--r--src/userfunc.c3956
-rw-r--r--src/version.c3205
-rw-r--r--src/version.h42
-rw-r--r--src/vim.def4
-rw-r--r--src/vim.h2609
-rw-r--r--src/vim.icobin0 -> 1078 bytes
-rw-r--r--src/vim.rc123
-rw-r--r--src/vim.tlbbin0 -> 1792 bytes
-rw-r--r--src/vim_alert.icobin0 -> 1078 bytes
-rw-r--r--src/vim_error.icobin0 -> 1078 bytes
-rw-r--r--src/vim_icon.xbm14
-rw-r--r--src/vim_info.icobin0 -> 1078 bytes
-rw-r--r--src/vim_mask.xbm14
-rw-r--r--src/vim_quest.icobin0 -> 1078 bytes
-rw-r--r--src/vimio.h19
-rw-r--r--src/vimrun.c96
-rwxr-xr-xsrc/vimtutor74
-rwxr-xr-xsrc/which.sh12
-rw-r--r--src/winclip.c799
-rw-r--r--src/window.c7286
-rw-r--r--src/xdiff/COPYING504
-rw-r--r--src/xdiff/README.txt16
-rw-r--r--src/xdiff/xdiff.h147
-rw-r--r--src/xdiff/xdiffi.c1043
-rw-r--r--src/xdiff/xdiffi.h64
-rw-r--r--src/xdiff/xemit.c332
-rw-r--r--src/xdiff/xemit.h36
-rw-r--r--src/xdiff/xhistogram.c386
-rw-r--r--src/xdiff/xinclude.h65
-rw-r--r--src/xdiff/xmacros.h54
-rw-r--r--src/xdiff/xpatience.c393
-rw-r--r--src/xdiff/xprepare.c483
-rw-r--r--src/xdiff/xprepare.h34
-rw-r--r--src/xdiff/xtypes.h67
-rw-r--r--src/xdiff/xutils.c425
-rw-r--r--src/xdiff/xutils.h47
-rw-r--r--src/xpm/COPYRIGHT31
-rw-r--r--src/xpm/README.txt30
-rw-r--r--src/xpm/include/simx.h139
-rw-r--r--src/xpm/include/xpm.h501
-rw-r--r--src/xpm/x64/lib-vc14/libXpm.libbin0 -> 121904 bytes
-rw-r--r--src/xpm/x64/lib/libXpm.abin0 -> 73758 bytes
-rw-r--r--src/xpm/x64/lib/libXpm.libbin0 -> 195582 bytes
-rw-r--r--src/xpm/x86/lib-vc14/libXpm.libbin0 -> 86422 bytes
-rw-r--r--src/xpm/x86/lib/libXpm.abin0 -> 66414 bytes
-rw-r--r--src/xpm/x86/lib/libXpm.libbin0 -> 139938 bytes
-rw-r--r--src/xpm_w32.c56
-rw-r--r--src/xpm_w32.h7
-rw-r--r--src/xxd/Make_amiga.mak18
-rw-r--r--src/xxd/Make_bc5.mak18
-rw-r--r--src/xxd/Make_ming.mak28
-rw-r--r--src/xxd/Make_mvc.mak19
-rw-r--r--src/xxd/Make_vms.mms69
-rw-r--r--src/xxd/Makefile7
-rw-r--r--src/xxd/xxd.c890
964 files changed, 853027 insertions, 0 deletions
diff --git a/src/GvimExt/GvimExt.reg b/src/GvimExt/GvimExt.reg
new file mode 100644
index 0000000..2b8ebf0
--- /dev/null
+++ b/src/GvimExt/GvimExt.reg
@@ -0,0 +1,20 @@
+REGEDIT4
+
+[HKEY_CLASSES_ROOT\CLSID\{51EEE242-AD87-11d3-9C1E-0090278BBD99}]
+ @="Vim Shell Extension"
+[HKEY_CLASSES_ROOT\CLSID\{51EEE242-AD87-11d3-9C1E-0090278BBD99}\InProcServer32]
+ @="gvimext.dll"
+ "ThreadingModel"="Apartment"
+
+[HKEY_CLASSES_ROOT\*\shellex\ContextMenuHandlers\gvim]
+ @="{51EEE242-AD87-11d3-9C1E-0090278BBD99}"
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved]
+ "{51EEE242-AD87-11d3-9C1E-0090278BBD99}"="Vim Shell Extension"
+
+[HKEY_LOCAL_MACHINE\Software\Vim\Gvim]
+ "path"="gvim.exe"
+
+[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall\Vim 8.1]
+ "DisplayName"="Vim 8.1: Edit with Vim popup menu entry"
+ "UninstallString"="uninstal.exe"
diff --git a/src/GvimExt/Make_bc5.mak b/src/GvimExt/Make_bc5.mak
new file mode 100644
index 0000000..363c6d6
--- /dev/null
+++ b/src/GvimExt/Make_bc5.mak
@@ -0,0 +1,43 @@
+### USEDLL no for statically linked version of run-time, yes for DLL runtime
+### BOR path to root of Borland C install (c:\bc5)
+
+### (requires cc3250.dll be available in %PATH%)
+!if ("$(USEDLL)"=="")
+USEDLL = no
+!endif
+
+### BOR: root of the BC installation
+!if ("$(BOR)"=="")
+BOR = c:\bc5
+!endif
+
+CC = $(BOR)\bin\Bcc32
+BRC = $(BOR)\bin\brc32
+LINK = $(BOR)\BIN\ILink32
+INCLUDE = $(BOR)\include;.
+LIB = $(BOR)\lib
+
+!if ("$(USEDLL)"=="yes")
+RT_DEF = -D_RTLDLL
+RT_LIB = cw32i.lib
+!else
+RT_DEF =
+RT_LIB = cw32.lib
+!endif
+
+
+all : gvimext.dll
+
+gvimext.obj : gvimext.cpp gvimext.h
+ $(CC) -tWD -I$(INCLUDE) -c -DFEAT_GETTEXT $(RT_DEF) -w- gvimext.cpp
+
+gvimext.res : gvimext.rc
+ $(BRC) -r gvimext.rc
+
+gvimext.dll : gvimext.obj gvimext.res
+ $(LINK) -L$(LIB) -aa gvimext.obj, gvimext.dll, , c0d32.obj $(RT_LIB) import32.lib, gvimext.def, gvimext.res
+
+clean :
+ -@del gvimext.obj
+ -@del gvimext.res
+ -@del gvimext.dll
diff --git a/src/GvimExt/Make_ming.mak b/src/GvimExt/Make_ming.mak
new file mode 100644
index 0000000..a6ab3ae
--- /dev/null
+++ b/src/GvimExt/Make_ming.mak
@@ -0,0 +1,81 @@
+# Project: gvimext
+# Generates gvimext.dll with gcc.
+# To be used with MingW and Cygwin.
+#
+# Originally, the DLL base address was fixed: -Wl,--image-base=0x1C000000
+# Now it is allocated dymanically by the linker by evaluating all DLLs
+# already loaded in memory. The binary image contains as well information
+# for automatic pseudo-rebasing, if needed by the system. ALV 2004-02-29
+
+# If cross-compiling set this to yes, else set it to no
+CROSS = no
+#CROSS = yes
+# For the old MinGW 2.95 (the one you get e.g. with debian woody)
+# set the following variable to yes and check if the executables are
+# really named that way.
+# If you have a newer MinGW or you are using cygwin set it to no and
+# check also the executables
+MINGWOLD = no
+
+# Link against the shared versions of libgcc/libstdc++ by default. Set
+# STATIC_STDCPLUS to "yes" to link against static versions instead.
+STATIC_STDCPLUS=no
+#STATIC_STDCPLUS=yes
+
+# Note: -static-libstdc++ is not available until gcc 4.5.x.
+LDFLAGS += -shared
+ifeq (yes, $(STATIC_STDCPLUS))
+LDFLAGS += -static-libgcc -static-libstdc++
+endif
+
+ifeq ($(CROSS),yes)
+DEL = rm
+ifeq ($(MINGWOLD),yes)
+CXXFLAGS := -O2 -fvtable-thunks
+else
+CXXFLAGS := -O2
+endif
+else
+CXXFLAGS := -O2
+ifneq (sh.exe, $(SHELL))
+DEL = rm
+else
+DEL = del
+endif
+endif
+# Set the default $(WINVER) to make it work with WinXP.
+ifndef WINVER
+WINVER = 0x0501
+endif
+CXX := $(CROSS_COMPILE)g++
+WINDRES := $(CROSS_COMPILE)windres
+WINDRES_CXX = $(CXX)
+WINDRES_FLAGS = --preprocessor="$(WINDRES_CXX) -E -xc" -DRC_INVOKED
+LIBS := -luuid -lgdi32
+RES := gvimext.res
+DEFFILE = gvimext_ming.def
+OBJ := gvimext.o
+
+DLL := gvimext.dll
+
+.PHONY: all all-before all-after clean clean-custom
+
+all: all-before $(DLL) all-after
+
+$(DLL): $(OBJ) $(RES) $(DEFFILE)
+ $(CXX) $(LDFLAGS) $(CXXFLAGS) -s -o $@ \
+ -Wl,--enable-auto-image-base \
+ -Wl,--enable-auto-import \
+ -Wl,--whole-archive \
+ $^ \
+ -Wl,--no-whole-archive \
+ $(LIBS)
+
+gvimext.o: gvimext.cpp
+ $(CXX) $(CXXFLAGS) -DFEAT_GETTEXT -DWINVER=$(WINVER) -D_WIN32_WINNT=$(WINVER) -c $? -o $@
+
+$(RES): gvimext_ming.rc
+ $(WINDRES) $(WINDRES_FLAGS) --input-format=rc --output-format=coff -DMING $? -o $@
+
+clean: clean-custom
+ -$(DEL) $(OBJ) $(RES) $(DLL)
diff --git a/src/GvimExt/Makefile b/src/GvimExt/Makefile
new file mode 100644
index 0000000..27ff953
--- /dev/null
+++ b/src/GvimExt/Makefile
@@ -0,0 +1,80 @@
+# Makefile for GvimExt, using MSVC
+# Options:
+# DEBUG=yes Build debug version (for VC7 and maybe later)
+# CPUARG= /arch:IA32/AVX/etc, call from main makefile to set
+# automatically from CPUNR
+#
+
+TARGETOS = WINNT
+
+!ifndef APPVER
+APPVER = 5.01
+!endif
+
+!if "$(DEBUG)" != "yes"
+NODEBUG = 1
+!endif
+
+!ifdef PROCESSOR_ARCHITECTURE
+# On Windows NT
+! ifndef CPU
+CPU = i386
+! if !defined(PLATFORM) && defined(TARGET_CPU)
+PLATFORM = $(TARGET_CPU)
+! endif
+! ifdef PLATFORM
+! if ("$(PLATFORM)" == "x64") || ("$(PLATFORM)" == "X64")
+CPU = AMD64
+! elseif ("$(PLATFORM)" != "x86") && ("$(PLATFORM)" != "X86")
+! error *** ERROR Unknown target platform "$(PLATFORM)". Make aborted.
+! endif
+! endif
+! endif
+!else
+CPU = i386
+!endif
+
+!ifdef SDK_INCLUDE_DIR
+!include $(SDK_INCLUDE_DIR)\Win32.mak
+!elseif "$(USE_WIN32MAK)"=="yes"
+!include <Win32.mak>
+!else
+cc = cl
+link = link
+rc = rc
+cflags = -nologo -c
+lflags = -incremental:no -nologo
+rcflags = /r
+olelibsdll = ole32.lib uuid.lib oleaut32.lib user32.lib gdi32.lib advapi32.lib
+!endif
+
+# include CPUARG
+cflags = $(cflags) $(CPUARG)
+
+SUBSYSTEM = console
+!if "$(SUBSYSTEM_VER)" != ""
+SUBSYSTEM = $(SUBSYSTEM),$(SUBSYSTEM_VER)
+!endif
+
+all: gvimext.dll
+
+gvimext.dll: gvimext.obj \
+ gvimext.res
+ $(link) $(lflags) -dll -def:gvimext.def -base:0x1C000000 -out:$*.dll $** $(olelibsdll) shell32.lib comctl32.lib -subsystem:$(SUBSYSTEM)
+ if exist $*.dll.manifest mt -nologo -manifest $*.dll.manifest -outputresource:$*.dll;2
+
+gvimext.obj: gvimext.h
+
+.cpp.obj:
+ $(cc) $(cflags) -DFEAT_GETTEXT $(cvarsmt) $*.cpp
+
+gvimext.res: gvimext.rc
+ $(rc) /nologo $(rcflags) $(rcvars) gvimext.rc
+
+clean:
+ - if exist gvimext.dll del gvimext.dll
+ - if exist gvimext.lib del gvimext.lib
+ - if exist gvimext.exp del gvimext.exp
+ - if exist gvimext.obj del gvimext.obj
+ - if exist gvimext.res del gvimext.res
+ - if exist gvimext.dll.manifest del gvimext.dll.manifest
diff --git a/src/GvimExt/README.txt b/src/GvimExt/README.txt
new file mode 100644
index 0000000..4a75cfa
--- /dev/null
+++ b/src/GvimExt/README.txt
@@ -0,0 +1,94 @@
+README.txt for the gvimext DLL.
+
+Written by Tianmiao Hu. Edited by Bram Moolenaar.
+
+
+INSTALLATION
+
+To install the "Edit with Vim" popup menu entry, it is recommended to use the
+"install.exe" program. It will ask you a few questions and install the needed
+registry entries.
+
+In special situations you might want to make changes by hand. Check these
+items:
+- The gvimext.dll, gvim.exe and uninstal.exe either need to be in the search
+ path, or you have to set the full path in the registry entries. You could
+ move the gvimext.dll to the "windows\system" or "windows\system32"
+ directory, where the other DLL files are.
+- You can find the names of the used registry entries in the file
+ "GvimExt.reg". You can edit this file to add the paths. To install the
+ registry entries, right-click the gvimext.reg file and choose the "merge"
+ menu option.
+- The registry key [HKEY_LOCAL_MACHINE\Software\Vim\Gvim] is used by the
+ gvimext.dll. The value "path" specifies the location of "gvim.exe". If
+ gvim.exe is in the search path, the path can be omitted. The value "lang"
+ can be used to set the language, for example "de" for German. If "lang" is
+ omitted, the language set for Windows will be used.
+
+It is the preferred method to keep gvim.exe with the runtime files, so that
+Vim will find them (also the translated menu items are there).
+
+
+UNINSTALLATION
+
+To uninstall the "Edit with Vim" popup menu entry, it is recommended to use
+the "uninstal.exe" program.
+
+In special situations you might want to uninstall by hand:
+- Open the registry by running regedit.exe.
+- Delete all the keys listed in GvimExt.reg, except this one:
+ [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved]
+ For this key, only delete one value:
+ "{51EEE242-AD87-11d3-9C1E-0090278BBD99}"="Vim Shell Extension"
+- Delete the gvimext.dll, if you want. You might need to reboot the machine
+ in order to remove this file. A quick way is to log off and re-login.
+
+Another method is by using the uninst.bat script:
+ uninst gvimext.inf
+This batch file will remove all the registry keys from the system. Then you
+can remove the gvimext.dll file.
+Note: In order for this batch file to work, you must have two system files:
+rundll32.exe and setupapi.dll. I believe you will have rundll32.exe in your
+system. I know windows nt 4.0 with the service pack 4 has setupapi.dll. My
+windows 95 has setupapi.dll. I find that the internet explorer 4.0 comes with
+the setupapi.dll in file Ie4_5.cab.
+
+If you do encounter problems running this script, then probably you need to
+modify the uninst.bat to suit to your system. Basically, you must find out
+where are the locations for your rundll32.exe and setupapi.dll files. In
+windows nt, both files are under c:\winnt\system32 directory. In my windows 95
+system, I got setupapi.dll at c:\windows\system and rundll32.exe at
+c:\windows. So you might want to try something like:
+ rundll32.exe c:\windows\system\setupapi.dll,InstallHinfSection DefaultUninstall 128 %1
+where %1 can be substituted by gvimext.inf
+
+
+THE SOURCE CODE
+
+I have provided the source code here in hope that gvim users around world can
+further enhance this little dll. I believe the only thing you need to change
+is gvimext.cpp file. The important two functions you need to look at are
+QueryContextMenu and InvokeCommand. You can modify right-click menus in the
+QueryContextMenu function and invoke gvim in the InvokeCommand function. Note
+the selected files can be accessed from the DragQueryFile function. I am not
+familiar with the invoking options for gvim. I believe there are some
+improvements that can be made on that side.
+
+I use MS Visual C++ 6.0's nmake to make the gvimext.dll. I don't have a
+chance to try earlier versions of MSVC. The files that are required for build
+are:
+ gvimext.cpp
+ gvimext.h
+ gvimext.def
+ gvimext.rc
+ resource.h
+ Makefile
+
+To compile the DLL from the command line:
+ vcvars32
+ nmake -f Makefile
+
+If you did something interesting to this dll, please let me know
+@ tianmiao@acm.org.
+
+Happy vimming!!!
diff --git a/src/GvimExt/gvimext.cpp b/src/GvimExt/gvimext.cpp
new file mode 100644
index 0000000..b9d9d91
--- /dev/null
+++ b/src/GvimExt/gvimext.cpp
@@ -0,0 +1,1090 @@
+/* vi:set ts=8 sts=4 sw=4:
+ *
+ * VIM - Vi IMproved gvimext by Tianmiao Hu
+ *
+ * Do ":help uganda" in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ */
+
+/*
+ * gvimext is a DLL which is used for the "Edit with Vim" context menu
+ * extension. It implements a MS defined interface with the Shell.
+ *
+ * If you have any questions or any suggestions concerning gvimext, please
+ * contact Tianmiao Hu: tianmiao@acm.org.
+ */
+
+#include "gvimext.h"
+
+#ifdef __BORLANDC__
+# include <dir.h>
+# ifndef _strnicmp
+# define _strnicmp(a, b, c) strnicmp((a), (b), (c))
+# endif
+#else
+static char *searchpath(char *name);
+#endif
+
+// Always get an error while putting the following stuff to the
+// gvimext.h file as class protected variables, give up and
+// declare them as global stuff
+FORMATETC fmte = {CF_HDROP,
+ (DVTARGETDEVICE FAR *)NULL,
+ DVASPECT_CONTENT,
+ -1,
+ TYMED_HGLOBAL
+ };
+STGMEDIUM medium;
+HRESULT hres = 0;
+UINT cbFiles = 0;
+
+/* The buffers size used to be MAX_PATH (260 bytes), but that's not always
+ * enough */
+#define BUFSIZE 1100
+
+//
+// Get the name of the Gvim executable to use, with the path.
+// When "runtime" is non-zero, we were called to find the runtime directory.
+// Returns the path in name[BUFSIZE]. It's empty when it fails.
+//
+ static void
+getGvimName(char *name, int runtime)
+{
+ HKEY keyhandle;
+ DWORD hlen;
+
+ // Get the location of gvim from the registry.
+ name[0] = 0;
+ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Vim\\Gvim", 0,
+ KEY_READ, &keyhandle) == ERROR_SUCCESS)
+ {
+ hlen = BUFSIZE;
+ if (RegQueryValueEx(keyhandle, "path", 0, NULL, (BYTE *)name, &hlen)
+ != ERROR_SUCCESS)
+ name[0] = 0;
+ else
+ name[hlen] = 0;
+ RegCloseKey(keyhandle);
+ }
+
+ // Registry didn't work, use the search path.
+ if (name[0] == 0)
+ strcpy(name, searchpath((char *)"gvim.exe"));
+
+ if (!runtime)
+ {
+ // Only when looking for the executable, not the runtime dir, we can
+ // search for the batch file or a name without a path.
+ if (name[0] == 0)
+ strcpy(name, searchpath((char *)"gvim.bat"));
+ if (name[0] == 0)
+ strcpy(name, "gvim"); // finds gvim.bat or gvim.exe
+ }
+}
+
+ static void
+getGvimInvocation(char *name, int runtime)
+{
+ getGvimName(name, runtime);
+ // avoid that Vim tries to expand wildcards in the file names
+ strcat(name, " --literal");
+}
+
+ static void
+getGvimInvocationW(wchar_t *nameW)
+{
+ char *name;
+
+ name = (char *)malloc(BUFSIZE);
+ getGvimInvocation(name, 0);
+ mbstowcs(nameW, name, BUFSIZE);
+ free(name);
+}
+
+//
+// Get the Vim runtime directory into buf[BUFSIZE].
+// The result is empty when it failed.
+// When it works, the path ends in a slash or backslash.
+//
+ static void
+getRuntimeDir(char *buf)
+{
+ int idx;
+
+ getGvimName(buf, 1);
+ if (buf[0] != 0)
+ {
+ // When no path found, use the search path to expand it.
+ if (strchr(buf, '/') == NULL && strchr(buf, '\\') == NULL)
+ strcpy(buf, searchpath(buf));
+
+ // remove "gvim.exe" from the end
+ for (idx = (int)strlen(buf) - 1; idx >= 0; idx--)
+ if (buf[idx] == '\\' || buf[idx] == '/')
+ {
+ buf[idx + 1] = 0;
+ break;
+ }
+ }
+}
+
+HBITMAP IconToBitmap(HICON hIcon, HBRUSH hBackground, int width, int height)
+{
+ HDC hDC = GetDC(NULL);
+ HDC hMemDC = CreateCompatibleDC(hDC);
+ HBITMAP hMemBmp = CreateCompatibleBitmap(hDC, width, height);
+ HBITMAP hResultBmp = NULL;
+ HGDIOBJ hOrgBMP = SelectObject(hMemDC, hMemBmp);
+
+ DrawIconEx(hMemDC, 0, 0, hIcon, width, height, 0, hBackground, DI_NORMAL);
+
+ hResultBmp = hMemBmp;
+ hMemBmp = NULL;
+
+ SelectObject(hMemDC, hOrgBMP);
+ DeleteDC(hMemDC);
+ ReleaseDC(NULL, hDC);
+ DestroyIcon(hIcon);
+ return hResultBmp;
+}
+
+//
+// GETTEXT: translated messages and menu entries
+//
+#ifndef FEAT_GETTEXT
+# define _(x) x
+#else
+# define _(x) (*dyn_libintl_gettext)(x)
+# define VIMPACKAGE "vim"
+# ifndef GETTEXT_DLL
+# define GETTEXT_DLL "libintl.dll"
+# define GETTEXT_DLL_ALT "libintl-8.dll"
+# endif
+
+// Dummy functions
+static char *null_libintl_gettext(const char *);
+static char *null_libintl_textdomain(const char *);
+static char *null_libintl_bindtextdomain(const char *, const char *);
+static int dyn_libintl_init(char *dir);
+static void dyn_libintl_end(void);
+
+static wchar_t *oldenv = NULL;
+static HINSTANCE hLibintlDLL = 0;
+static char *(*dyn_libintl_gettext)(const char *) = null_libintl_gettext;
+static char *(*dyn_libintl_textdomain)(const char *) = null_libintl_textdomain;
+static char *(*dyn_libintl_bindtextdomain)(const char *, const char *)
+ = null_libintl_bindtextdomain;
+
+//
+// Attempt to load libintl.dll. If it doesn't work, use dummy functions.
+// "dir" is the directory where the libintl.dll might be.
+// Return 1 for success, 0 for failure.
+//
+ static int
+dyn_libintl_init(char *dir)
+{
+ int i;
+ static struct
+ {
+ char *name;
+ FARPROC *ptr;
+ } libintl_entry[] =
+ {
+ {(char *)"gettext", (FARPROC*)&dyn_libintl_gettext},
+ {(char *)"textdomain", (FARPROC*)&dyn_libintl_textdomain},
+ {(char *)"bindtextdomain", (FARPROC*)&dyn_libintl_bindtextdomain},
+ {NULL, NULL}
+ };
+ DWORD len, len2;
+ LPWSTR buf = NULL;
+ LPWSTR buf2 = NULL;
+
+ // No need to initialize twice.
+ if (hLibintlDLL)
+ return 1;
+
+ // Load gettext library from $VIMRUNTIME\GvimExt{64,32} directory.
+ // Add the directory to $PATH temporarily.
+ len = GetEnvironmentVariableW(L"PATH", NULL, 0);
+ len2 = MAX_PATH + 1 + len;
+ buf = (LPWSTR)malloc(len * sizeof(WCHAR));
+ buf2 = (LPWSTR)malloc(len2 * sizeof(WCHAR));
+ if (buf != NULL && buf2 != NULL)
+ {
+ GetEnvironmentVariableW(L"PATH", buf, len);
+#ifdef _WIN64
+ _snwprintf(buf2, len2, L"%S\\GvimExt64;%s", dir, buf);
+#else
+ _snwprintf(buf2, len2, L"%S\\GvimExt32;%s", dir, buf);
+#endif
+ SetEnvironmentVariableW(L"PATH", buf2);
+ hLibintlDLL = LoadLibrary(GETTEXT_DLL);
+#ifdef GETTEXT_DLL_ALT
+ if (!hLibintlDLL)
+ hLibintlDLL = LoadLibrary(GETTEXT_DLL_ALT);
+#endif
+ SetEnvironmentVariableW(L"PATH", buf);
+ }
+ free(buf);
+ free(buf2);
+ if (!hLibintlDLL)
+ return 0;
+
+ // Get the addresses of the functions we need.
+ for (i = 0; libintl_entry[i].name != NULL
+ && libintl_entry[i].ptr != NULL; ++i)
+ {
+ if ((*libintl_entry[i].ptr = GetProcAddress(hLibintlDLL,
+ libintl_entry[i].name)) == NULL)
+ {
+ dyn_libintl_end();
+ return 0;
+ }
+ }
+ return 1;
+}
+
+ static void
+dyn_libintl_end(void)
+{
+ if (hLibintlDLL)
+ FreeLibrary(hLibintlDLL);
+ hLibintlDLL = NULL;
+ dyn_libintl_gettext = null_libintl_gettext;
+ dyn_libintl_textdomain = null_libintl_textdomain;
+ dyn_libintl_bindtextdomain = null_libintl_bindtextdomain;
+}
+
+ static char *
+null_libintl_gettext(const char *msgid)
+{
+ return (char *)msgid;
+}
+
+ static char *
+null_libintl_bindtextdomain(const char * /* domainname */, const char * /* dirname */)
+{
+ return NULL;
+}
+
+ static char *
+null_libintl_textdomain(const char* /* domainname */)
+{
+ return NULL;
+}
+
+//
+// Setup for translating strings.
+//
+ static void
+dyn_gettext_load(void)
+{
+ char szBuff[BUFSIZE];
+ char szLang[BUFSIZE];
+ DWORD len;
+ HKEY keyhandle;
+ int gotlang = 0;
+
+ strcpy(szLang, "LANG=");
+
+ // First try getting the language from the registry, this can be
+ // used to overrule the system language.
+ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Vim\\Gvim", 0,
+ KEY_READ, &keyhandle) == ERROR_SUCCESS)
+ {
+ len = BUFSIZE;
+ if (RegQueryValueEx(keyhandle, "lang", 0, NULL, (BYTE*)szBuff, &len)
+ == ERROR_SUCCESS)
+ {
+ szBuff[len] = 0;
+ strcat(szLang, szBuff);
+ gotlang = 1;
+ }
+ RegCloseKey(keyhandle);
+ }
+
+ if (!gotlang && getenv("LANG") == NULL)
+ {
+ // Get the language from the system.
+ // Could use LOCALE_SISO639LANGNAME, but it's not in Win95.
+ // LOCALE_SABBREVLANGNAME gives us three letters, like "enu", we use
+ // only the first two.
+ len = GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SABBREVLANGNAME,
+ (LPTSTR)szBuff, BUFSIZE);
+ if (len >= 2 && _strnicmp(szBuff, "en", 2) != 0)
+ {
+ // There are a few exceptions (probably more)
+ if (_strnicmp(szBuff, "cht", 3) == 0
+ || _strnicmp(szBuff, "zht", 3) == 0)
+ strcpy(szBuff, "zh_TW");
+ else if (_strnicmp(szBuff, "chs", 3) == 0
+ || _strnicmp(szBuff, "zhc", 3) == 0)
+ strcpy(szBuff, "zh_CN");
+ else if (_strnicmp(szBuff, "jp", 2) == 0)
+ strcpy(szBuff, "ja");
+ else
+ szBuff[2] = 0; // truncate to two-letter code
+ strcat(szLang, szBuff);
+ gotlang = 1;
+ }
+ }
+ if (gotlang)
+ putenv(szLang);
+
+ // Try to locate the runtime files. The path is used to find libintl.dll
+ // and the vim.mo files.
+ getRuntimeDir(szBuff);
+ if (szBuff[0] != 0)
+ {
+ len = (DWORD)strlen(szBuff);
+ if (dyn_libintl_init(szBuff))
+ {
+ strcpy(szBuff + len, "lang");
+
+ (*dyn_libintl_bindtextdomain)(VIMPACKAGE, szBuff);
+ (*dyn_libintl_textdomain)(VIMPACKAGE);
+ }
+ }
+}
+
+ static void
+dyn_gettext_free(void)
+{
+ dyn_libintl_end();
+}
+#endif // FEAT_GETTEXT
+
+//
+// Global variables
+//
+UINT g_cRefThisDll = 0; // Reference count of this DLL.
+HINSTANCE g_hmodThisDll = NULL; // Handle to this DLL itself.
+
+
+//---------------------------------------------------------------------------
+// DllMain
+//---------------------------------------------------------------------------
+extern "C" int APIENTRY
+DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /* lpReserved */)
+{
+ switch (dwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ // Extension DLL one-time initialization
+ g_hmodThisDll = hInstance;
+ break;
+
+ case DLL_PROCESS_DETACH:
+ break;
+ }
+
+ return 1; // ok
+}
+
+ static void
+inc_cRefThisDLL()
+{
+#ifdef FEAT_GETTEXT
+ if (g_cRefThisDll == 0) {
+ dyn_gettext_load();
+ oldenv = GetEnvironmentStringsW();
+ }
+#endif
+ InterlockedIncrement((LPLONG)&g_cRefThisDll);
+}
+
+ static void
+dec_cRefThisDLL()
+{
+#ifdef FEAT_GETTEXT
+ if (InterlockedDecrement((LPLONG)&g_cRefThisDll) == 0) {
+ dyn_gettext_free();
+ if (oldenv != NULL) {
+ FreeEnvironmentStringsW(oldenv);
+ oldenv = NULL;
+ }
+ }
+#else
+ InterlockedDecrement((LPLONG)&g_cRefThisDll);
+#endif
+}
+
+//---------------------------------------------------------------------------
+// DllCanUnloadNow
+//---------------------------------------------------------------------------
+
+STDAPI DllCanUnloadNow(void)
+{
+ return (g_cRefThisDll == 0 ? S_OK : S_FALSE);
+}
+
+STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppvOut)
+{
+ *ppvOut = NULL;
+
+ if (IsEqualIID(rclsid, CLSID_ShellExtension))
+ {
+ CShellExtClassFactory *pcf = new CShellExtClassFactory;
+
+ return pcf->QueryInterface(riid, ppvOut);
+ }
+
+ return CLASS_E_CLASSNOTAVAILABLE;
+}
+
+CShellExtClassFactory::CShellExtClassFactory()
+{
+ m_cRef = 0L;
+
+ inc_cRefThisDLL();
+}
+
+CShellExtClassFactory::~CShellExtClassFactory()
+{
+ dec_cRefThisDLL();
+}
+
+STDMETHODIMP CShellExtClassFactory::QueryInterface(REFIID riid,
+ LPVOID FAR *ppv)
+{
+ *ppv = NULL;
+
+ // any interface on this object is the object pointer
+
+ if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IClassFactory))
+ {
+ *ppv = (LPCLASSFACTORY)this;
+
+ AddRef();
+
+ return NOERROR;
+ }
+
+ return E_NOINTERFACE;
+}
+
+STDMETHODIMP_(ULONG) CShellExtClassFactory::AddRef()
+{
+ return InterlockedIncrement((LPLONG)&m_cRef);
+}
+
+STDMETHODIMP_(ULONG) CShellExtClassFactory::Release()
+{
+ if (InterlockedDecrement((LPLONG)&m_cRef))
+ return m_cRef;
+
+ delete this;
+
+ return 0L;
+}
+
+STDMETHODIMP CShellExtClassFactory::CreateInstance(LPUNKNOWN pUnkOuter,
+ REFIID riid,
+ LPVOID *ppvObj)
+{
+ *ppvObj = NULL;
+
+ // Shell extensions typically don't support aggregation (inheritance)
+
+ if (pUnkOuter)
+ return CLASS_E_NOAGGREGATION;
+
+ // Create the main shell extension object. The shell will then call
+ // QueryInterface with IID_IShellExtInit--this is how shell extensions are
+ // initialized.
+
+ LPCSHELLEXT pShellExt = new CShellExt(); // create the CShellExt object
+
+ if (NULL == pShellExt)
+ return E_OUTOFMEMORY;
+
+ return pShellExt->QueryInterface(riid, ppvObj);
+}
+
+
+STDMETHODIMP CShellExtClassFactory::LockServer(BOOL /* fLock */)
+{
+ return NOERROR;
+}
+
+// *********************** CShellExt *************************
+CShellExt::CShellExt()
+{
+ m_cRef = 0L;
+ m_pDataObj = NULL;
+
+ inc_cRefThisDLL();
+
+ LoadMenuIcon();
+}
+
+CShellExt::~CShellExt()
+{
+ if (m_pDataObj)
+ m_pDataObj->Release();
+
+ dec_cRefThisDLL();
+
+ if (m_hVimIconBitmap)
+ DeleteObject(m_hVimIconBitmap);
+}
+
+STDMETHODIMP CShellExt::QueryInterface(REFIID riid, LPVOID FAR *ppv)
+{
+ *ppv = NULL;
+
+ if (IsEqualIID(riid, IID_IShellExtInit) || IsEqualIID(riid, IID_IUnknown))
+ {
+ *ppv = (LPSHELLEXTINIT)this;
+ }
+ else if (IsEqualIID(riid, IID_IContextMenu))
+ {
+ *ppv = (LPCONTEXTMENU)this;
+ }
+
+ if (*ppv)
+ {
+ AddRef();
+
+ return NOERROR;
+ }
+
+ return E_NOINTERFACE;
+}
+
+STDMETHODIMP_(ULONG) CShellExt::AddRef()
+{
+ return InterlockedIncrement((LPLONG)&m_cRef);
+}
+
+STDMETHODIMP_(ULONG) CShellExt::Release()
+{
+
+ if (InterlockedDecrement((LPLONG)&m_cRef))
+ return m_cRef;
+
+ delete this;
+
+ return 0L;
+}
+
+
+//
+// FUNCTION: CShellExt::Initialize(LPCITEMIDLIST, LPDATAOBJECT, HKEY)
+//
+// PURPOSE: Called by the shell when initializing a context menu or property
+// sheet extension.
+//
+// PARAMETERS:
+// pIDFolder - Specifies the parent folder
+// pDataObj - Specifies the set of items selected in that folder.
+// hRegKey - Specifies the type of the focused item in the selection.
+//
+// RETURN VALUE:
+//
+// NOERROR in all cases.
+//
+// COMMENTS: Note that at the time this function is called, we don't know
+// (or care) what type of shell extension is being initialized.
+// It could be a context menu or a property sheet.
+//
+
+STDMETHODIMP CShellExt::Initialize(LPCITEMIDLIST /* pIDFolder */,
+ LPDATAOBJECT pDataObj,
+ HKEY /* hRegKey */)
+{
+ // Initialize can be called more than once
+ if (m_pDataObj)
+ m_pDataObj->Release();
+
+ // duplicate the object pointer and registry handle
+
+ if (pDataObj)
+ {
+ m_pDataObj = pDataObj;
+ pDataObj->AddRef();
+ }
+
+ return NOERROR;
+}
+
+
+//
+// FUNCTION: CShellExt::QueryContextMenu(HMENU, UINT, UINT, UINT, UINT)
+//
+// PURPOSE: Called by the shell just before the context menu is displayed.
+// This is where you add your specific menu items.
+//
+// PARAMETERS:
+// hMenu - Handle to the context menu
+// indexMenu - Index of where to begin inserting menu items
+// idCmdFirst - Lowest value for new menu ID's
+// idCmtLast - Highest value for new menu ID's
+// uFlags - Specifies the context of the menu event
+//
+// RETURN VALUE:
+//
+//
+// COMMENTS:
+//
+
+STDMETHODIMP CShellExt::QueryContextMenu(HMENU hMenu,
+ UINT indexMenu,
+ UINT idCmdFirst,
+ UINT /* idCmdLast */,
+ UINT /* uFlags */)
+{
+ UINT idCmd = idCmdFirst;
+
+ hres = m_pDataObj->GetData(&fmte, &medium);
+ if (medium.hGlobal)
+ cbFiles = DragQueryFile((HDROP)medium.hGlobal, (UINT)-1, 0, 0);
+
+ // InsertMenu(hMenu, indexMenu++, MF_SEPARATOR|MF_BYPOSITION, 0, NULL);
+
+ // Initialize m_cntOfHWnd to 0
+ m_cntOfHWnd = 0;
+
+ HKEY keyhandle;
+ bool showExisting = true;
+ bool showIcons = true;
+
+ // Check whether "Edit with existing Vim" entries are disabled.
+ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Vim\\Gvim", 0,
+ KEY_READ, &keyhandle) == ERROR_SUCCESS)
+ {
+ if (RegQueryValueEx(keyhandle, "DisableEditWithExisting", 0, NULL,
+ NULL, NULL) == ERROR_SUCCESS)
+ showExisting = false;
+ if (RegQueryValueEx(keyhandle, "DisableContextMenuIcons", 0, NULL,
+ NULL, NULL) == ERROR_SUCCESS)
+ showIcons = false;
+ RegCloseKey(keyhandle);
+ }
+
+ // Retrieve all the vim instances, unless disabled.
+ if (showExisting)
+ EnumWindows(EnumWindowsProc, (LPARAM)this);
+
+ MENUITEMINFO mii = { sizeof(MENUITEMINFO) };
+ mii.fMask = MIIM_STRING | MIIM_ID;
+ if (showIcons)
+ {
+ mii.fMask |= MIIM_BITMAP;
+ mii.hbmpItem = m_hVimIconBitmap;
+ }
+
+ if (cbFiles > 1)
+ {
+ mii.wID = idCmd++;
+ mii.dwTypeData = _("Edit with &multiple Vims");
+ mii.cch = lstrlen(mii.dwTypeData);
+ InsertMenuItem(hMenu, indexMenu++, TRUE, &mii);
+
+ mii.wID = idCmd++;
+ mii.dwTypeData = _("Edit with single &Vim");
+ mii.cch = lstrlen(mii.dwTypeData);
+ InsertMenuItem(hMenu, indexMenu++, TRUE, &mii);
+
+ if (cbFiles <= 4)
+ {
+ // Can edit up to 4 files in diff mode
+ mii.wID = idCmd++;
+ mii.dwTypeData = _("Diff with Vim");
+ mii.cch = lstrlen(mii.dwTypeData);
+ InsertMenuItem(hMenu, indexMenu++, TRUE, &mii);
+ m_edit_existing_off = 3;
+ }
+ else
+ m_edit_existing_off = 2;
+
+ }
+ else
+ {
+ mii.wID = idCmd++;
+ mii.dwTypeData = _("Edit with &Vim");
+ mii.cch = lstrlen(mii.dwTypeData);
+ InsertMenuItem(hMenu, indexMenu++, TRUE, &mii);
+ m_edit_existing_off = 1;
+ }
+
+ HMENU hSubMenu = NULL;
+ if (m_cntOfHWnd > 1)
+ {
+ hSubMenu = CreatePopupMenu();
+ mii.fMask |= MIIM_SUBMENU;
+ mii.wID = idCmd;
+ mii.dwTypeData = _("Edit with existing Vim");
+ mii.cch = lstrlen(mii.dwTypeData);
+ mii.hSubMenu = hSubMenu;
+ InsertMenuItem(hMenu, indexMenu++, TRUE, &mii);
+ mii.fMask = mii.fMask & ~MIIM_SUBMENU;
+ mii.hSubMenu = NULL;
+ }
+ // Now display all the vim instances
+ for (int i = 0; i < m_cntOfHWnd; i++)
+ {
+ char title[BUFSIZE];
+ char temp[BUFSIZE];
+ int index;
+ HMENU hmenu;
+
+ // Obtain window title, continue if can not
+ if (GetWindowText(m_hWnd[i], title, BUFSIZE - 1) == 0)
+ continue;
+ // Truncate the title before the path, keep the file name
+ char *pos = strchr(title, '(');
+ if (pos != NULL)
+ {
+ if (pos > title && pos[-1] == ' ')
+ --pos;
+ *pos = 0;
+ }
+ // Now concatenate
+ if (m_cntOfHWnd > 1)
+ temp[0] = '\0';
+ else
+ {
+ strncpy(temp, _("Edit with existing Vim - "), BUFSIZE - 1);
+ temp[BUFSIZE - 1] = '\0';
+ }
+ strncat(temp, title, BUFSIZE - 1 - strlen(temp));
+ temp[BUFSIZE - 1] = '\0';
+
+ mii.wID = idCmd++;
+ mii.dwTypeData = temp;
+ mii.cch = lstrlen(mii.dwTypeData);
+ if (m_cntOfHWnd > 1)
+ {
+ hmenu = hSubMenu;
+ index = i;
+ }
+ else
+ {
+ hmenu = hMenu;
+ index = indexMenu++;
+ }
+ InsertMenuItem(hmenu, index, TRUE, &mii);
+ }
+ // InsertMenu(hMenu, indexMenu++, MF_SEPARATOR|MF_BYPOSITION, 0, NULL);
+
+ // Must return number of menu items we added.
+ return ResultFromShort(idCmd-idCmdFirst);
+}
+
+//
+// FUNCTION: CShellExt::InvokeCommand(LPCMINVOKECOMMANDINFO)
+//
+// PURPOSE: Called by the shell after the user has selected on of the
+// menu items that was added in QueryContextMenu().
+//
+// PARAMETERS:
+// lpcmi - Pointer to an CMINVOKECOMMANDINFO structure
+//
+// RETURN VALUE:
+//
+//
+// COMMENTS:
+//
+
+STDMETHODIMP CShellExt::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi)
+{
+ HRESULT hr = E_INVALIDARG;
+
+ // If HIWORD(lpcmi->lpVerb) then we have been called programmatically
+ // and lpVerb is a command that should be invoked. Otherwise, the shell
+ // has called us, and LOWORD(lpcmi->lpVerb) is the menu ID the user has
+ // selected. Actually, it's (menu ID - idCmdFirst) from QueryContextMenu().
+ if (!HIWORD(lpcmi->lpVerb))
+ {
+ UINT idCmd = LOWORD(lpcmi->lpVerb);
+
+ if (idCmd >= m_edit_existing_off)
+ {
+ // Existing with vim instance
+ hr = PushToWindow(lpcmi->hwnd,
+ lpcmi->lpDirectory,
+ lpcmi->lpVerb,
+ lpcmi->lpParameters,
+ lpcmi->nShow,
+ idCmd - m_edit_existing_off);
+ }
+ else
+ {
+ switch (idCmd)
+ {
+ case 0:
+ hr = InvokeGvim(lpcmi->hwnd,
+ lpcmi->lpDirectory,
+ lpcmi->lpVerb,
+ lpcmi->lpParameters,
+ lpcmi->nShow);
+ break;
+ case 1:
+ hr = InvokeSingleGvim(lpcmi->hwnd,
+ lpcmi->lpDirectory,
+ lpcmi->lpVerb,
+ lpcmi->lpParameters,
+ lpcmi->nShow,
+ 0);
+ break;
+ case 2:
+ hr = InvokeSingleGvim(lpcmi->hwnd,
+ lpcmi->lpDirectory,
+ lpcmi->lpVerb,
+ lpcmi->lpParameters,
+ lpcmi->nShow,
+ 1);
+ break;
+ }
+ }
+ }
+ return hr;
+}
+
+STDMETHODIMP CShellExt::PushToWindow(HWND /* hParent */,
+ LPCSTR /* pszWorkingDir */,
+ LPCSTR /* pszCmd */,
+ LPCSTR /* pszParam */,
+ int /* iShowCmd */,
+ int idHWnd)
+{
+ HWND hWnd = m_hWnd[idHWnd];
+
+ // Show and bring vim instance to foreground
+ if (IsIconic(hWnd) != 0)
+ ShowWindow(hWnd, SW_RESTORE);
+ else
+ ShowWindow(hWnd, SW_SHOW);
+ SetForegroundWindow(hWnd);
+
+ // Post the selected files to the vim instance
+ PostMessage(hWnd, WM_DROPFILES, (WPARAM)medium.hGlobal, 0);
+
+ return NOERROR;
+}
+
+STDMETHODIMP CShellExt::GetCommandString(UINT_PTR /* idCmd */,
+ UINT uFlags,
+ UINT FAR * /* reserved */,
+ LPSTR pszName,
+ UINT cchMax)
+{
+ if (uFlags == GCS_HELPTEXT && cchMax > 35)
+ lstrcpy(pszName, _("Edits the selected file(s) with Vim"));
+
+ return NOERROR;
+}
+
+BOOL CALLBACK CShellExt::EnumWindowsProc(HWND hWnd, LPARAM lParam)
+{
+ char temp[BUFSIZE];
+
+ // First do a bunch of check
+ // No invisible window
+ if (!IsWindowVisible(hWnd)) return TRUE;
+ // No child window ???
+ // if (GetParent(hWnd)) return TRUE;
+ // Class name should be Vim, if failed to get class name, return
+ if (GetClassName(hWnd, temp, sizeof(temp)) == 0)
+ return TRUE;
+ // Compare class name to that of vim, if not, return
+ if (_strnicmp(temp, "vim", sizeof("vim")) != 0)
+ return TRUE;
+ // First check if the number of vim instance exceeds MAX_HWND
+ CShellExt *cs = (CShellExt*) lParam;
+ if (cs->m_cntOfHWnd >= MAX_HWND) return TRUE;
+ // Now we get the vim window, put it into some kind of array
+ cs->m_hWnd[cs->m_cntOfHWnd] = hWnd;
+ cs->m_cntOfHWnd ++;
+
+ return TRUE; // continue enumeration (otherwise this would be false)
+}
+
+BOOL CShellExt::LoadMenuIcon()
+{
+ char vimExeFile[BUFSIZE];
+ getGvimName(vimExeFile, 1);
+ if (vimExeFile[0] == '\0')
+ return FALSE;
+ HICON hVimIcon;
+ if (ExtractIconEx(vimExeFile, 0, NULL, &hVimIcon, 1) == 0)
+ return FALSE;
+ m_hVimIconBitmap = IconToBitmap(hVimIcon,
+ GetSysColorBrush(COLOR_MENU),
+ GetSystemMetrics(SM_CXSMICON),
+ GetSystemMetrics(SM_CYSMICON));
+ return TRUE;
+}
+
+#ifndef __BORLANDC__
+ static char *
+searchpath(char *name)
+{
+ static char widename[2 * BUFSIZE];
+ static char location[2 * BUFSIZE + 2];
+
+ // There appears to be a bug in FindExecutableA() on Windows NT.
+ // Use FindExecutableW() instead...
+ MultiByteToWideChar(CP_ACP, 0, (LPCSTR)name, -1,
+ (LPWSTR)widename, BUFSIZE);
+ if (FindExecutableW((LPCWSTR)widename, (LPCWSTR)"",
+ (LPWSTR)location) > (HINSTANCE)32)
+ {
+ WideCharToMultiByte(CP_ACP, 0, (LPWSTR)location, -1,
+ (LPSTR)widename, 2 * BUFSIZE, NULL, NULL);
+ return widename;
+ }
+ return (char *)"";
+}
+#endif
+
+STDMETHODIMP CShellExt::InvokeGvim(HWND hParent,
+ LPCSTR /* pszWorkingDir */,
+ LPCSTR /* pszCmd */,
+ LPCSTR /* pszParam */,
+ int /* iShowCmd */)
+{
+ wchar_t m_szFileUserClickedOn[BUFSIZE];
+ wchar_t cmdStrW[BUFSIZE];
+ UINT i;
+
+ for (i = 0; i < cbFiles; i++)
+ {
+ DragQueryFileW((HDROP)medium.hGlobal,
+ i,
+ m_szFileUserClickedOn,
+ sizeof(m_szFileUserClickedOn));
+
+ getGvimInvocationW(cmdStrW);
+ wcscat(cmdStrW, L" \"");
+
+ if ((wcslen(cmdStrW) + wcslen(m_szFileUserClickedOn) + 2) < BUFSIZE)
+ {
+ wcscat(cmdStrW, m_szFileUserClickedOn);
+ wcscat(cmdStrW, L"\"");
+
+ STARTUPINFOW si;
+ PROCESS_INFORMATION pi;
+
+ ZeroMemory(&si, sizeof(si));
+ si.cb = sizeof(si);
+
+ // Start the child process.
+ if (!CreateProcessW(NULL, // No module name (use command line).
+ cmdStrW, // Command line.
+ NULL, // Process handle not inheritable.
+ NULL, // Thread handle not inheritable.
+ FALSE, // Set handle inheritance to FALSE.
+ oldenv == NULL ? 0 : CREATE_UNICODE_ENVIRONMENT,
+ oldenv, // Use unmodified environment block.
+ NULL, // Use parent's starting directory.
+ &si, // Pointer to STARTUPINFO structure.
+ &pi) // Pointer to PROCESS_INFORMATION structure.
+ )
+ {
+ MessageBox(
+ hParent,
+ _("Error creating process: Check if gvim is in your path!"),
+ _("gvimext.dll error"),
+ MB_OK);
+ }
+ else
+ {
+ CloseHandle( pi.hProcess );
+ CloseHandle( pi.hThread );
+ }
+ }
+ else
+ {
+ MessageBox(
+ hParent,
+ _("Path length too long!"),
+ _("gvimext.dll error"),
+ MB_OK);
+ }
+ }
+
+ return NOERROR;
+}
+
+
+STDMETHODIMP CShellExt::InvokeSingleGvim(HWND hParent,
+ LPCSTR /* pszWorkingDir */,
+ LPCSTR /* pszCmd */,
+ LPCSTR /* pszParam */,
+ int /* iShowCmd */,
+ int useDiff)
+{
+ wchar_t m_szFileUserClickedOn[BUFSIZE];
+ wchar_t *cmdStrW;
+ size_t cmdlen;
+ size_t len;
+ UINT i;
+
+ cmdlen = BUFSIZE;
+ cmdStrW = (wchar_t *) malloc(cmdlen * sizeof(wchar_t));
+ if (cmdStrW == NULL)
+ return E_FAIL;
+ getGvimInvocationW(cmdStrW);
+
+ if (useDiff)
+ wcscat(cmdStrW, L" -d");
+ for (i = 0; i < cbFiles; i++)
+ {
+ DragQueryFileW((HDROP)medium.hGlobal,
+ i,
+ m_szFileUserClickedOn,
+ sizeof(m_szFileUserClickedOn));
+
+ len = wcslen(cmdStrW) + wcslen(m_szFileUserClickedOn) + 4;
+ if (len > cmdlen)
+ {
+ cmdlen = len + BUFSIZE;
+ wchar_t *cmdStrW_new = (wchar_t *)realloc(cmdStrW, cmdlen * sizeof(wchar_t));
+ if (cmdStrW_new == NULL)
+ {
+ free(cmdStrW);
+ return E_FAIL;
+ }
+ cmdStrW = cmdStrW_new;
+ }
+ wcscat(cmdStrW, L" \"");
+ wcscat(cmdStrW, m_szFileUserClickedOn);
+ wcscat(cmdStrW, L"\"");
+ }
+
+ STARTUPINFOW si;
+ PROCESS_INFORMATION pi;
+
+ ZeroMemory(&si, sizeof(si));
+ si.cb = sizeof(si);
+
+ // Start the child process.
+ if (!CreateProcessW(NULL, // No module name (use command line).
+ cmdStrW, // Command line.
+ NULL, // Process handle not inheritable.
+ NULL, // Thread handle not inheritable.
+ FALSE, // Set handle inheritance to FALSE.
+ oldenv == NULL ? 0 : CREATE_UNICODE_ENVIRONMENT,
+ oldenv, // Use unmodified environment block.
+ NULL, // Use parent's starting directory.
+ &si, // Pointer to STARTUPINFO structure.
+ &pi) // Pointer to PROCESS_INFORMATION structure.
+ )
+ {
+ MessageBox(
+ hParent,
+ _("Error creating process: Check if gvim is in your path!"),
+ _("gvimext.dll error"),
+ MB_OK);
+ }
+ else
+ {
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+ }
+ free(cmdStrW);
+
+ return NOERROR;
+}
diff --git a/src/GvimExt/gvimext.def b/src/GvimExt/gvimext.def
new file mode 100644
index 0000000..e6d66f4
--- /dev/null
+++ b/src/GvimExt/gvimext.def
@@ -0,0 +1,8 @@
+;gvimdef.def : Declares the module parameters for the DLL.
+
+LIBRARY gvimext
+; DESCRIPTION 'Vim Shell Extension'
+
+EXPORTS
+ DllCanUnloadNow private
+ DllGetClassObject private
diff --git a/src/GvimExt/gvimext.h b/src/GvimExt/gvimext.h
new file mode 100644
index 0000000..e17f2ac
--- /dev/null
+++ b/src/GvimExt/gvimext.h
@@ -0,0 +1,181 @@
+/* vi:set ts=8 sts=4 sw=4:
+ *
+ * VIM - Vi IMproved gvimext by Tianmiao Hu
+ *
+ * Do ":help uganda" in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ */
+
+/*
+ * If you have any questions or any suggestions concerning gvimext, please
+ * contact Tianmiao Hu: tianmiao@acm.org.
+ */
+
+#if !defined(AFX_STDAFX_H__3389658B_AD83_11D3_9C1E_0090278BBD99__INCLUDED_)
+#define AFX_STDAFX_H__3389658B_AD83_11D3_9C1E_0090278BBD99__INCLUDED_
+
+#if defined(_MSC_VER) && _MSC_VER > 1000
+#pragma once
+#endif
+
+// Insert your headers here
+// #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
+
+//--------------------------------------------------------------
+// common user interface routines
+//
+//
+//--------------------------------------------------------------
+
+#ifndef STRICT
+# define STRICT
+#endif
+
+#define INC_OLE2 // WIN32, get ole2 from windows.h
+
+/* Visual Studio 2005 has 'deprecated' many of the standard CRT functions */
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+# define _CRT_SECURE_NO_DEPRECATE
+# define _CRT_NONSTDC_NO_DEPRECATE
+#endif
+
+#include <windows.h>
+#include <windowsx.h>
+#include <shlobj.h>
+#include <wchar.h>
+
+/* Accommodate old versions of VC that don't have a modern Platform SDK */
+#if (defined(_MSC_VER) && _MSC_VER < 1300) || !defined(MAXULONG_PTR)
+# undef UINT_PTR
+# define UINT_PTR UINT
+#endif
+
+#define ResultFromShort(i) ResultFromScode(MAKE_SCODE(SEVERITY_SUCCESS, 0, (USHORT)(i)))
+
+// Initialize GUIDs (should be done only and at-least once per DLL/EXE)
+//
+#pragma data_seg(".text")
+#define INITGUID
+#include <initguid.h>
+#include <shlguid.h>
+
+//
+// The class ID of this Shell extension class.
+//
+// class id: {51EEE242-AD87-11d3-9C1E-0090278BBD99}
+//
+//
+// NOTE!!! If you use this shell extension as a starting point,
+// you MUST change the GUID below. Simply run UUIDGEN.EXE
+// to generate a new GUID.
+//
+
+// {51EEE242-AD87-11d3-9C1E-0090278BBD99}
+// static const GUID <<name>> =
+// { 0x51eee242, 0xad87, 0x11d3, { 0x9c, 0x1e, 0x0, 0x90, 0x27, 0x8b, 0xbd, 0x99 } };
+//
+//
+
+// {51EEE242-AD87-11d3-9C1E-0090278BBD99}
+// IMPLEMENT_OLECREATE(<<class>>, <<external_name>>,
+// 0x51eee242, 0xad87, 0x11d3, 0x9c, 0x1e, 0x0, 0x90, 0x27, 0x8b, 0xbd, 0x99);
+//
+
+// {51EEE242-AD87-11d3-9C1E-0090278BBD99} -- this is the registry format
+DEFINE_GUID(CLSID_ShellExtension, 0x51eee242, 0xad87, 0x11d3, 0x9c, 0x1e, 0x0, 0x90, 0x27, 0x8b, 0xbd, 0x99);
+
+// this class factory object creates context menu handlers for windows 32 shell
+class CShellExtClassFactory : public IClassFactory
+{
+protected:
+ ULONG m_cRef;
+
+public:
+ CShellExtClassFactory();
+ ~CShellExtClassFactory();
+
+ //IUnknown members
+ STDMETHODIMP QueryInterface(REFIID, LPVOID FAR *);
+ STDMETHODIMP_(ULONG) AddRef();
+ STDMETHODIMP_(ULONG) Release();
+
+ //IClassFactory members
+ STDMETHODIMP CreateInstance(LPUNKNOWN, REFIID, LPVOID FAR *);
+ STDMETHODIMP LockServer(BOOL);
+
+};
+typedef CShellExtClassFactory *LPCSHELLEXTCLASSFACTORY;
+#define MAX_HWND 100
+
+// this is the actual OLE Shell context menu handler
+class CShellExt : public IContextMenu,
+ IShellExtInit
+{
+private:
+ BOOL LoadMenuIcon();
+
+protected:
+ ULONG m_cRef;
+ LPDATAOBJECT m_pDataObj;
+ UINT m_edit_existing_off;
+ HBITMAP m_hVimIconBitmap;
+
+ // For some reason, this callback must be static
+ static BOOL CALLBACK EnumWindowsProc(HWND hWnd, LPARAM lParam);
+
+ STDMETHODIMP PushToWindow(HWND hParent,
+ LPCSTR pszWorkingDir,
+ LPCSTR pszCmd,
+ LPCSTR pszParam,
+ int iShowCmd,
+ int idHWnd);
+
+ STDMETHODIMP InvokeGvim(HWND hParent,
+ LPCSTR pszWorkingDir,
+ LPCSTR pszCmd,
+ LPCSTR pszParam,
+ int iShowCmd);
+
+ STDMETHODIMP InvokeSingleGvim(HWND hParent,
+ LPCSTR pszWorkingDir,
+ LPCSTR pszCmd,
+ LPCSTR pszParam,
+ int iShowCmd,
+ int useDiff);
+
+public:
+ int m_cntOfHWnd;
+ HWND m_hWnd[MAX_HWND];
+ CShellExt();
+ ~CShellExt();
+
+ //IUnknown members
+ STDMETHODIMP QueryInterface(REFIID, LPVOID FAR *);
+ STDMETHODIMP_(ULONG) AddRef();
+ STDMETHODIMP_(ULONG) Release();
+
+ //IShell members
+ STDMETHODIMP QueryContextMenu(HMENU hMenu,
+ UINT indexMenu,
+ UINT idCmdFirst,
+ UINT idCmdLast,
+ UINT uFlags);
+
+ STDMETHODIMP InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi);
+
+ STDMETHODIMP GetCommandString(UINT_PTR idCmd,
+ UINT uFlags,
+ UINT FAR *reserved,
+ LPSTR pszName,
+ UINT cchMax);
+
+ //IShellExtInit methods
+ STDMETHODIMP Initialize(LPCITEMIDLIST pIDFolder,
+ LPDATAOBJECT pDataObj,
+ HKEY hKeyID);
+};
+
+typedef CShellExt *LPCSHELLEXT;
+#pragma data_seg()
+
+#endif
diff --git a/src/GvimExt/gvimext.inf b/src/GvimExt/gvimext.inf
new file mode 100644
index 0000000..8b45bb1
--- /dev/null
+++ b/src/GvimExt/gvimext.inf
@@ -0,0 +1,22 @@
+[Version]
+Signature="$Windows NT$""
+Provider="Tianmiao"
+
+[Manufacture]
+
+[DefaultInstall]
+AddReg=ThisDll.Add.Reg
+
+[DefaultUninstall]
+DelReg=ThisDLL.Add.Reg
+
+[ThisDll.Add.Reg]
+HKCR,CLSID\{51EEE242-AD87-11d3-9C1E-0090278BBD99}
+HKCR,CLSID\{51EEE242-AD87-11d3-9C1E-0090278BBD99}\InProcServer32
+HKCR,*\shellex\ContextMenuHandlers\gvim
+HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved",{51EEE242-AD87-11d3-9C1E-0090278BBD99}
+HKLM,Software\Vim\Gvim
+HKLM,"Software\Microsoft\Windows\CurrentVersion\Uninstall\Vim 6.0"
+
+[Strings]
+ThisDll="gvimext.dll"
diff --git a/src/GvimExt/gvimext.rc b/src/GvimExt/gvimext.rc
new file mode 100644
index 0000000..22102db
--- /dev/null
+++ b/src/GvimExt/gvimext.rc
@@ -0,0 +1,111 @@
+//Microsoft Developer Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#ifndef __BORLANDC__
+# include "winresrc.h"
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifndef _MAC
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,0,0,1
+ PRODUCTVERSION 1,0,0,1
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x3L
+#else
+ FILEFLAGS 0x2L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "Comments", "Developed using COM architecture!\0"
+ VALUE "CompanyName", "Tianmiao Hu's Developer Studio\0"
+ VALUE "FileDescription", "A small project for the context menu of gvim!\0"
+ VALUE "FileVersion", "1, 0, 0, 1\0"
+ VALUE "InternalName", "gvim right-click menu extension\0"
+ VALUE "LegalCopyright", "Copyright © 1999 Tianmiao Hu\0"
+ VALUE "LegalTrademarks", "Tianmiao Hu's Gvim Context Menu Extension\0"
+ VALUE "OriginalFilename", "gvimext.dll\0"
+ VALUE "PrivateBuild", "\0"
+ VALUE "ProductName", "Tianmiao Hu's gvimext context menu extension\0"
+ VALUE "ProductVersion", "1, 0, 0, 1\0"
+ VALUE "SpecialBuild", "\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
+
+#endif // !_MAC
+
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/src/GvimExt/gvimext_ming.def b/src/GvimExt/gvimext_ming.def
new file mode 100644
index 0000000..b96e1d3
--- /dev/null
+++ b/src/GvimExt/gvimext_ming.def
@@ -0,0 +1,10 @@
+;gvimdef_ming.def : Declares the module parameters for the DLL.
+;The mingw environment doesn't know anything about private declarations
+;Hence this is the same file as gvimext.def with private removed
+
+LIBRARY gvimext
+; DESCRIPTION 'Vim Shell Extension build with MinGW'
+
+EXPORTS
+ DllCanUnloadNow = DllCanUnloadNow@0
+ DllGetClassObject = DllGetClassObject@12
diff --git a/src/GvimExt/gvimext_ming.rc b/src/GvimExt/gvimext_ming.rc
new file mode 100644
index 0000000..6c69854
--- /dev/null
+++ b/src/GvimExt/gvimext_ming.rc
@@ -0,0 +1,45 @@
+#include <windows.h>
+#define xstr(x) str(x)
+#define str(x) #x
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,0,0,1
+ PRODUCTVERSION 1,0,0,1
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x3L
+#else
+ FILEFLAGS 0x2L
+#endif
+ FILEOS 0x4L
+ FILETYPE VFT_DLL
+ FILESUBTYPE 0x0L
+{
+ BLOCK "StringFileInfo"
+ {
+ BLOCK "040904b0"
+ {
+ VALUE "Comments", "Developed using COM architecture!\0"
+ VALUE "CompanyName", "Tianmiao Hu's Developer Studio\0"
+ VALUE "FileDescription", "A small project for the context menu of gvim!\0"
+ VALUE "FileVersion", "1, 0, 0, 1\0"
+ VALUE "InternalName", "gvim right-click menu extension\0"
+ VALUE "LegalCopyright", "Copyright © 1999 Tianmiao Hu\0"
+ VALUE "LegalTrademarks", "Tianmiao Hu's Gvim Context Menu Extension\0"
+ VALUE "OriginalFilename", "gvimext.dll\0"
+ VALUE "PrivateBuild", "\0"
+ VALUE "ProductName", "Tianmiao Hu's gvimext context menu extension\0"
+ VALUE "ProductVersion", "1, 0, 0, 1\0"
+
+#if defined(__GNUC__)
+ VALUE "SpecialBuild", "Build With " "MingW " xstr(__GNUC__) "." xstr(__GNUC_MINOR__) "." xstr(__GNUC_PATCHLEVEL__) " on " __DATE__ " " __TIME__ "\0"
+#else
+ VALUE "SpecialBuild", "Unknown compiler\0"
+
+#endif
+ }
+ }
+ BLOCK "VarFileInfo"
+ {
+ VALUE "Translation", 0x409, 1200
+ }
+}
diff --git a/src/GvimExt/resource.h b/src/GvimExt/resource.h
new file mode 100644
index 0000000..8ddc823
--- /dev/null
+++ b/src/GvimExt/resource.h
@@ -0,0 +1,15 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by gvimext.rc
+//
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 101
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1000
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/src/GvimExt/uninst.bat b/src/GvimExt/uninst.bat
new file mode 100644
index 0000000..71d14f6
--- /dev/null
+++ b/src/GvimExt/uninst.bat
@@ -0,0 +1 @@
+rundll32.exe setupapi,InstallHinfSection DefaultUninstall 128 %1
diff --git a/src/INSTALL b/src/INSTALL
new file mode 100644
index 0000000..3da9141
--- /dev/null
+++ b/src/INSTALL
@@ -0,0 +1,384 @@
+INSTALL - Installation of Vim on different machines.
+
+This file contains instructions for compiling Vim. If you already have an
+executable version of Vim, you don't need this.
+
+Contents:
+1. Generic
+2. Unix
+3. OS/2 (with EMX 0.9b)
+4. Atari MiNT
+
+See INSTALLami.txt for Amiga
+See INSTALLmac.txt for Macintosh
+See INSTALLpc.txt for PC (Windows XP/Vista/7/8/10)
+See INSTALLvms.txt for VMS
+See INSTALLx.txt for cross-compiling on Unix
+See ../READMEdir/README_390.txt for z/OS and OS/390 Unix
+See ../runtime/doc/os_beos.txt for BeBox
+
+
+1. Generic
+==========
+
+If you compile Vim without specifying anything, you will get the default
+behaviour as is documented, which should be fine for most people.
+
+For features that you can't enable/disable in another way, you can edit the
+file "feature.h" to match your preferences.
+
+
+2. Unix
+=======
+
+Summary:
+1. make run configure, compile and link
+2. make install installation in /usr/local
+
+This will include the GUI and X11 libraries, if you have them. If you want a
+version of Vim that is small and starts up quickly, see the Makefile for how
+to disable the GUI and X11. If you don't have GUI libraries and/or X11, these
+features will be disabled automatically.
+
+See the start of Makefile for more detailed instructions about how to compile
+Vim.
+
+If you need extra compiler and/or linker arguments, set $CFLAGS and/or $LIBS
+before starting configure. Example:
+
+ env CFLAGS=-I/usr/local/include LIBS=-lm make
+
+This is only needed for things that configure doesn't offer a specific argument
+for or figures out by itself. First try running configure without extra
+arguments.
+
+GNU Autoconf and a few other tools have been used to make Vim work on many
+different Unix systems. The advantage of this is that Vim should compile
+on most systems without any adjustments. The disadvantage is that when
+adjustments are required, it takes some time to understand what is happening.
+
+If configure finds all library files and then complains when linking that some
+of them can't be found, your linker doesn't return an error code for missing
+libraries. Vim should be linked fine anyway, mostly you can just ignore these
+errors.
+
+If you run configure by hand (not using the Makefile), remember that any
+changes in the Makefile have no influence on configure. This may be what you
+want, but maybe not!
+
+The advantage of running configure separately, is that you can write a script
+to build Vim, without changing the Makefile or feature.h. Example (using sh):
+
+ CFLAGS=-DCOMPILER_FLAG ./configure --enable-gui=motif
+
+One thing to watch out for: If the configure script itself changes, running
+"make" will execute it again, but without your arguments. Do "make clean" and
+run configure again.
+
+If you are compiling Vim for several machines, for each machine:
+ a. make shadow
+ b. mv shadow machine_name
+ c. cd machine_name
+ d. make; make install
+
+[Don't use a path for machine_name, just a directory name, otherwise the links
+that "make shadow" creates won't work.]
+
+
+Unix: COMPILING WITH/WITHOUT GUI
+
+NOTE: This is incomplete, look in Makefile for more info.
+
+These configure arguments can be used to select which GUI to use:
+--enable-gui=gtk or: gtk2, motif, athena or auto
+--disable-gtk-check
+--disable-motif-check
+--disable-athena-check
+
+--enable-gui defaults to "auto", so it will automatically look for a GUI (in
+the order of GTK, Motif, then Athena). If one is found, then is uses it and
+does not proceed to check any of the remaining ones. Otherwise, it moves on
+to the next one.
+
+--enable-{gtk,gtk2,kde,motif,athena}-check all default to "yes", such that if
+--enable-gui is "auto" (which it is by default), GTK, Motif, and Athena will
+be checked for. If you want to *exclude* a certain check, then you use
+--disable-{gtk,gtk2,kde,motif,athena}-check.
+
+For example, if --enable-gui is set to "auto", but you don't want it look for
+Motif, you then also specify --disable-motif-check. This results in only
+checking for GTK and Athena.
+
+Lastly, if you know which one you want to use, then you can just do
+--enable-gui={gtk,gtk2,kde,motif,athena}. So if you wanted to only use Motif,
+then you'd specify --enable-gui=motif. Once you specify what you want, the
+--enable-{gtk,gtk2,kde,motif,athena}-check options are ignored.
+
+On Linux you usually need GUI "-devel" packages. You may already have GTK
+libraries installed, but that doesn't mean you can compile Vim with GTK, you
+also need the header files.
+
+For compiling with the GTK+ GUI, you need a recent version of glib and gtk+.
+Configure checks for at least version 1.1.16. An older version is not selected
+automatically. If you want to use it anyway, run configure with
+"--disable-gtktest".
+GTK requires an ANSI C compiler. If you fail to compile Vim with GTK+ (it
+is the preferred choice), try selecting another one in the Makefile.
+If you are sure you have GTK installed, but for some reason configure says you
+do not, you may have left-over header files and/or library files from an older
+(and incompatible) version of GTK. if this is the case, please check
+auto/config.log for any error messages that may give you a hint as to what's
+happening.
+
+There used to be a KDE version of Vim, using Qt libraries, but since it didn't
+work very well and there was no maintainer it was dropped.
+
+
+Unix: COMPILING WITH MULTI-BYTE
+
+When you want to compile with the multi-byte features enabled, make sure you
+compile on a machine where the locale settings actually work, otherwise the
+configure tests may fail. You need to compile with "big" features:
+
+ ./configure --with-features=big
+
+Unix: COMPILING ON LINUX
+
+On Linux, when using -g to compile (which is default for gcc), the executable
+will probably be statically linked. If you don't want this, remove the -g
+option from CFLAGS.
+
+Unix: PUTTING vimrc IN /etc
+
+Some Linux distributions prefer to put the global vimrc file in /etc, and the
+Vim runtime files in /usr. This can be done with:
+ ./configure --prefix=/usr
+ make VIMRCLOC=/etc VIMRUNTIMEDIR=/usr/share/vim MAKE="make -e"
+
+Unix: COMPILING ON NeXT
+
+Add the "-posix" argument to the compiler by using one of these commands:
+ setenv CC 'cc -posix' (csh)
+ export CC='cc -posix' (sh)
+And run configure with "--disable-motif-check".
+
+Unix: LOCAL HEADERS AND LIBRARIES NOT IN /usr/local
+
+Sometimes it is necessary to search different path than /usr/local for locally
+installed headers (/usr/local/include) and libraries (/usr/local/lib).
+To search /stranger/include and /stranger/lib for locally installed
+headers and libraries, use:
+ ./configure --with-local-dir=/stranger
+And to not search for locally installed headers and libraries at all, use:
+ ./configure --without-local-dir
+
+
+3. OS/2
+=======
+
+OS/2 support was removed in patch 7.4.1008
+
+
+4. Atari MiNT
+=============
+
+[NOTE: this is quite old, it might not work anymore]
+
+To compile Vim for MiNT you may either copy Make_mint.mak to Makefile or use
+the Unix Makefile adapted for the MiNT configuration.
+
+Now proceed as described in the Unix section.
+
+Prerequisites:
+
+You need a curses or termcap library that supports non-alphanumeric
+termcap names. If you don't have any, link with termlib.o.
+
+-----------------------------------------------------------------------------
+
+The rest of this file is based on the INSTALL file that comes with GNU
+autoconf 2.12. Not everything applies to Vim. Read Makefile too!
+
+
+Basic Installation
+==================
+
+ These are generic installation instructions.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, a file
+`config.cache' that saves the results of its tests to speed up
+reconfiguring, and a file `config.log' containing compiler output
+(useful mainly for debugging `configure').
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If at some point `config.cache'
+contains results you don't want to keep, you may remove or edit it.
+
+ The file `configure.ac' is used to create `configure' by a program
+called `autoconf'. You only need `configure.ac' if you want to change
+it or regenerate `configure' using a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system. If you're
+ using `csh' on an old version of System V, you might need to type
+ `sh ./configure' instead to prevent `csh' from trying to execute
+ `configure' itself.
+
+ Running `configure' takes awhile. While running, it prints some
+ messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Optionally, type `make check' to run any self-tests that come with
+ the package.
+
+ 4. Type `make install' to install the programs and any data files and
+ documentation.
+
+ 5. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'. To also remove the
+ files that `configure' created (so you can compile the package for
+ a different kind of computer), type `make distclean'. There is
+ also a `make maintainer-clean' target, but that is intended mainly
+ for the package's developers. If you use it, you may have to get
+ all sorts of other programs in order to regenerate files that came
+ with the distribution.
+
+Compilers and Options
+=====================
+
+ Some systems require unusual options for compilation or linking that
+the `configure' script does not know about. You can give `configure'
+initial values for variables by setting them in the environment. Using
+a Bourne-compatible shell, you can do that on the command line like
+this:
+ CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
+
+Or on systems that have the `env' program, you can do it like this:
+ env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
+
+Compiling For Multiple Architectures
+====================================
+
+ You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+ If you have to use a `make' that does not support the `VPATH'
+variable, you have to compile the package for one architecture at a time
+in the source code directory. After you have installed the package for
+one architecture, use `make distclean' before reconfiguring for another
+architecture.
+
+Installation Names
+==================
+
+ By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc. You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+ In addition, if you use an unusual directory layout you can give
+options like `--bindir=PATH' to specify different values for particular
+kinds of files. Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+ Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+ There may be some features `configure' can not figure out
+automatically, but needs to determine by the type of host the package
+will run on. Usually `configure' can figure that out, but if it prints
+a message saying it can not guess the host type, give it the
+`--host=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name with three fields:
+ CPU-COMPANY-SYSTEM
+
+See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the host type.
+
+ If you are building compiler tools for cross-compiling, you can also
+use the `--target=TYPE' option to select the type of system they will
+produce code for and the `--build=TYPE' option to select the type of
+system on which you are compiling the package.
+
+Sharing Defaults
+================
+
+ If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Operation Controls
+==================
+
+ `configure' recognizes the following options to control how it
+operates.
+
+`--cache-file=FILE'
+ Use and save the results of the tests in FILE instead of
+ `./config.cache'. Set FILE to `/dev/null' to disable caching, for
+ debugging `configure'.
+
+`--help'
+ Print a summary of the options to `configure', and exit.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made. To
+ suppress all normal output, redirect it to `/dev/null' (any error
+ messages will still be shown).
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`--version'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`configure' also accepts some other, not widely useful, options.
diff --git a/src/INSTALLami.txt b/src/INSTALLami.txt
new file mode 100644
index 0000000..0acd6fd
--- /dev/null
+++ b/src/INSTALLami.txt
@@ -0,0 +1,34 @@
+INSTALLami.txt - Installation of Vim from source on Amiga
+
+This file contains instructions for compiling Vim. If you already have an
+executable version of Vim, you don't need this.
+
+The file "feature.h" can be edited to match your preferences. You can skip
+this, then you will get the default behavior as is documented, which should
+be fine for most people.
+
+
+Summary:
+make -f Make_manx.mak Manx C
+make -f Make_sas.mak Lattice/SAS C
+make -f Make_dice.mak DICE
+
+The Manx compiler is preferred, it was used to produce the Amiga executable
+and has been tested most. You should not get any errors or warnings.
+
+The SAS compiler can be used. Older versions (6.0 to 6.3) don't work with the
+optimizer switched on. This seems to be fixed with 6.5 or 6.56, but this has
+not been tested much. Also disable optimizing when the compiler runs out of
+memory or crashes the system (yes, that happens; did I say the Manx compiler
+is preferred?).
+
+The DICE makefile has been reported to work by one person only.
+
+You will have to set the "VIM" environment variable to the location of the
+documentation files.
+
+
+MorphOS
+
+Use the Make_morph.mak Makefile:
+ make -f Make_morph.mak
diff --git a/src/INSTALLmac.txt b/src/INSTALLmac.txt
new file mode 100644
index 0000000..e957682
--- /dev/null
+++ b/src/INSTALLmac.txt
@@ -0,0 +1,72 @@
+INSTALLmac.txt - Installation of Vim on Macintosh
+
+This file contains instructions for compiling Vim. If you already have an
+executable version of Vim, you don't need this.
+
+First, make sure you've installed Xcode or CommandLineToots. If not, open a
+terminal and do
+
+ $ make --version
+
+A window pops up instructing you to install the developer tools.
+
+
+----------------------------------------------------------------------------
+Summary
+----------------------------------------------------------------------------
+
+1 MacOS X
+ 1.1. Carbon interface
+ 1.2. X (Athena, GTK, Motif) or plain text.
+
+MacOS Classic is no longer supported. If you really want it use Vim 6.4.
+
+----------------------------------------------------------------------------
+1 MacOS X
+----------------------------------------------------------------------------
+
+1.0 Considerations
+
+ Only '/' supported as path separator.
+
+1.1 Carbon interface (default)
+
+ You can compile vim with the standard Unix routine:
+ cd .../src
+ make
+ 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).
+
+ To overrule the architecture do this before running make:
+
+ ./configure --with-mac-arch=intel
+ or
+ ./configure --with-mac-arch=ppc
+
+
+1.2 X-Windows or Plain Text
+
+ If you do not want the Carbon interface, you must explicitly tell
+ configure to use a different 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
+ gtk, gtk2, gnome, gnome2,
+
+ NOTE: You need to first install XFree86 and XDarwin.
+ Please visit http://www.XDarwin.org
+
+------------------------------------------------------
diff --git a/src/INSTALLpc.txt b/src/INSTALLpc.txt
new file mode 100644
index 0000000..634f4ad
--- /dev/null
+++ b/src/INSTALLpc.txt
@@ -0,0 +1,1051 @@
+INSTALLpc.txt - Installation of Vim on PC
+
+This file contains instructions for compiling Vim. If you already have an
+executable version of Vim, you don't need this.
+
+You can find the latest here: https://github.com/vim/vim-win32-installer
+This page also has links to install support for interfaces such as Perl,
+Python, Lua, etc.
+
+The file "feature.h" can be edited to match your preferences. You can skip
+this, then you will get the default behavior as is documented, which should
+be fine for most people.
+
+This document assumes that you are building Vim for Win32 or later (Windows
+XP/2003/Vista/7/8/10). There are also instructions for pre-XP systems, but
+they might no longer work.
+
+The recommended way is to build a 32 bit Vim, also on 64 bit systems. You can
+build a 64 bit Vim if you like, the executable will be bigger and Vim won't be
+any faster, but you can edit files larger than 2 Gbyte.
+
+
+Contents:
+1. Microsoft Visual C++
+2. Using MSYS2 with MinGW
+3. Using MinGW
+4. Cygwin
+5. Borland
+6. Cross compiling for Win32 from a Linux machine
+7. Building with Python support
+8. Building with Python3 support
+9. Building with Racket or MzScheme support
+10. Building with Lua support
+11. Building with Perl support
+12. Building with Ruby support
+13. Building with Tcl support
+14. Building with Terminal support
+15. Building with DirectX (DirectWrite) support
+16. Windows 3.1
+17. MS-DOS
+
+18. Installing after building from sources
+
+
+The currently recommended way (that means it has been verified to work) is
+using the "Visual Studio Community 2015" installation. This includes the SDK
+needed to target Windows XP. But not older Windows versions (95, 98), see
+|msvc-2008-express| below for that
+
+
+1. Microsoft Visual C++
+=======================
+
+We do not provide download links, since Microsoft keeps changing them. You
+can search for "Visual Studio Community 2015", for example. You will need to
+create a Microsoft account (it's free).
+
+When installing "Visual Studio Community 2015 with Update 3" make sure to
+select "custom" and check "Windows XP Support for C++" and all checkboxes
+under "Universal Windows App Development Tools"
+
+
+Visual Studio
+-------------
+
+Building with Visual Studio (VS 98, VS .NET, VS .NET 2003, VS 2005, VS 2008,
+VS2010, VS2012, VS2013 and VS2015) is straightforward. (These instructions
+should also work for VS 4 and VS 5.)
+
+Using VS C++ 2008 Express is recommended if you need the binary to run on
+Windows 95 or 97, see |msvc-2008-express| below.
+
+To build Vim from the command line with MSVC, use Make_mvc.mak.
+Visual Studio installed a batch file called vcvars32.bat, which you must
+run to set up paths for nmake and MSVC.
+
+nmake -f Make_mvc.mak console Win32 SDK or Microsoft Visual C++
+nmake -f Make_mvc.mak GUI=yes GUI Microsoft Visual C++
+nmake -f Make_mvc.mak OLE=yes OLE Microsoft Visual C++
+nmake -f Make_mvc.mak PERL=C:\Perl PYTHON=C:\Python etc.
+ Perl, Python, etc.
+
+Make_mvc.mak allows a Vim to be built with various different features and
+debug support. Debugging with MS Devstudio is provided by Make_dvc.mak.
+For a description of the use of Make_dvc.mak, look in Make_mvc.mak.
+
+For compiling Gvim with IME support on far-east Windows, add IME=yes
+to the parameters you pass to Make_mvc.mak.
+
+To build Vim from within the Visual Studio IDE, open the Make_ivc.mak project.
+(Note: Make_ivc.mak is not as rich as Make_mvc.mak, which allows for
+far more configuration.) Make_ivc.mak can also be built with nmake.
+
+nmake -f Make_ivc.mak CFG="Vim - Win32 Release gvim"
+ GUI Microsoft Visual C++ 4.x or later
+nmake -f Make_ivc.mak CFG="Vim - Win32 Release gvim OLE"
+ OLE Microsoft Visual C++ 4.x or later
+
+See the specific files for comments and options.
+
+These files have been supplied by George V. Reilly, Ben Singer, Ken Scott and
+Ron Aaron; they have been tested.
+
+
+Visual C++ 2008 Express Edition *msvc-2008-express*
+-------------------------------
+
+Visual C++ 2008 Express Edition can be downloaded for free from:
+ http://www.microsoft.com/express/downloads/
+This includes the IDE and the debugger.
+
+To set the environment execute the msvc2008.bat script. You can then build
+Vim with Make_mvc.mak.
+
+For building 64 bit binaries you also need to install the SDK:
+"Microsoft Windows SDK for Windows 7 and .NET Framework 3.5 SP1"
+You don't need the examples and documentation.
+
+If you get an error that Win32.mak can't be found, you have to set the
+variable SDK_INCLUDE_DIR. For example, on Windows 10, installation of MSVC
+puts include files in the following directory:
+ set SDK_INCLUDE_DIR=C:\Program Files\Microsoft SDKs\Windows\v6.0A\Include
+
+
+Visual C++ 2010 Express Edition *msvc-2010-express*
+-------------------------------
+
+Visual C++ 2010 Express Edition can be downloaded for free from:
+ http://www.microsoft.com/express/vc/Default.aspx
+This includes the IDE and the debugger.
+
+To set the environment execute the msvc2010.bat script. You can then build
+Vim with Make_mvc.mak.
+
+
+Targeting Windows XP with MSVC 2012 and later *new-msvc-windows-xp*
+---------------------------------------------
+
+Beginning with Visual C++ 2012, Microsoft changed the behavior of LINK.EXE
+so that it targets Windows 6.0 (Vista) by default. In order to override
+this, the target Windows version number needs to be passed to LINK like
+follows:
+ LINK ... /subsystem:console,5.01
+
+Make_mvc.mak now supports a macro SUBSYSTEM_VER to pass the Windows version.
+Use lines like follows to target Windows XP x86 (assuming using Visual C++
+2012 under 64-bit Windows):
+ set WinSdk71=%ProgramFiles(x86)%\Microsoft SDKs\Windows\v7.1A
+ set INCLUDE=%WinSdk71%\Include;%INCLUDE%
+ set LIB=%WinSdk71%\Lib;%LIB%
+ set CL=/D_USING_V110_SDK71_
+ nmake -f Make_mvc.mak ... WINVER=0x0501 SUBSYSTEM_VER=5.01
+
+To target Windows XP x64 instead of x86, you need to change the settings of
+LIB and SUBSYSTEM_VER:
+ ...
+ set LIB=%WinSdk71%\Lib\x64;%LIB%
+ ...
+ nmake -f Make_mvc.mak ... WINVER=0x0501 SUBSYSTEM_VER=5.02
+
+If you use Visual C++ 2015 (either Express or Community Edition), executing
+msvc2015.bat will set them automatically. For x86 builds run this without
+options:
+ msvc2015
+For x64 builds run this with the "x86_amd64" option:
+ msvc2015 x86_amd64
+This enables x86_x64 cross compiler. This works on any editions including
+Express edition.
+If you use Community (or Professional) edition, you can enable the x64 native
+compiler by using the "x64" option:
+ msvc2015 x64
+
+The following Visual C++ team blog can serve as a reference page:
+ http://blogs.msdn.com/b/vcblog/archive/2012/10/08/windows-xp-targeting-with-c-in-visual-studio-2012.aspx
+
+
+OLDER VERSIONS
+
+The minimal supported version is Windows XP. Building with older compilers
+might still work, but these instructions might be outdated.
+
+If you need the executable to run on Windows 98 or ME, use the 2003 one
+|msvc-2003-toolkit|.
+
+Visual C++ Toolkit 2003 *msvc-2003-toolkit*
+-----------------------
+
+You could download the Microsoft Visual C++ Toolkit 2003 from
+ http://msdn.microsoft.com/visualc/vctoolkit2003/
+Unfortunately this URL is no longer valid. Unofficial downloads appear to be
+available from links mentioned on these pages (use at your own risk):
+ http://www.filewatcher.com/m/VCToolkitSetup.exe.32952488.0.0.html
+ http://feargame.net/wiki/index.php?title=Building_Source_with_the_VC2003_Toolkit
+
+This contains the command-line tools (compiler, linker, CRT headers,
+and libraries) for Visual Studio .NET 2003, but not the Visual Studio IDE.
+To compile and debug Vim with the VC2003 Toolkit, you will also need
+|ms-platform-sdk|, |dotnet-1.1-redist|, |dotnet-1.1-sdk|,
+and |windbg-download|.
+
+It's easier to download Visual C++ 2008 Express Edition, |msvc-2008-express|,
+which is freely available in perpetuity.
+
+The free Code::Blocks IDE works with the VC2003 Toolkit, as described at
+ http://wiki.codeblocks.org/index.php?title=Integrating_Microsoft_Visual_Toolkit_2003_with_Code::Blocks_IDE
+(This site also takes you through configuring a number of other
+free C compilers for Win32.)
+
+To compile Vim using the VC2003 Toolkit and Make_mvc.mak, you must first
+execute the following commands in a cmd.exe window (the msvcsetup.bat batch
+file can be used):
+
+ set PATH=%SystemRoot%\Microsoft.NET\Framework\v1.1.4322;%PATH%
+ call "%VCToolkitInstallDir%vcvars32.bat"
+ set MSVCVer=7.1
+ call "%ProgramFiles%\Microsoft Platform SDK\SetEnv.Cmd"
+ set LIB=%ProgramFiles%\Microsoft Visual Studio .NET 2003\Vc7\lib;%LIB%
+
+Now you can build Vim with Make_mvc.mak.
+
+
+Getting the Windows Platform SDK *ms-platform-sdk*
+
+You will also need a copy of the Windows Platform SDK. Specifically, you need
+the Windows Core SDK subset of the Platform SDK, which contains the Windows
+headers and libraries. You need to search for it, Microsoft keeps changing
+the URL.
+
+
+Getting the .NET Framework 1.1 Runtime *dotnet-1.1-redist*
+
+You need the .NET Framework 1.1 Redistributable Package from
+ http://www.microsoft.com/downloads/details.aspx?familyid=262d25e3-f589-4842-8157-034d1e7cf3a3
+or from Windows Update:
+ http://windowsupdate.microsoft.com/
+This is needed to install |dotnet-1.1-sdk|. It also contains cvtres.exe,
+which is needed to link Vim.
+
+
+Getting the .NET Framework 1.1 SDK *dotnet-1.1-sdk*
+
+You need the .NET Framework 1.1 SDK from
+ http://www.microsoft.com/downloads/details.aspx?familyid=9b3a2ca6-3647-4070-9f41-a333c6b9181d
+This contains some additional libraries needed to compile Vim,
+such as msvcrt.lib. You must install |dotnet-1.1-redist| before
+installing the .NET 1.1 SDK.
+
+
+Getting the WinDbg debugger *windbg-download*
+
+The Debugging Tools for Windows can be downloaded from
+ http://www.microsoft.com/whdc/devtools/debugging/default.mspx
+This includes the WinDbg debugger, which you will want if you ever need
+to debug Vim itself. An earlier version of the Debugging Tools
+is also available through the Platform SDK, |ms-platform-sdk|.
+
+
+Visual C++ 2005 Express Edition *msvc-2005-express*
+-------------------------------
+
+Visual C++ 2005 Express Edition can be downloaded for free from:
+ http://msdn.microsoft.com/vstudio/express/visualC/default.aspx
+This includes the IDE and the debugger. You will also need
+|ms-platform-sdk|. You can build Vim with Make_mvc.mak.
+
+Instructions for integrating the Platform SDK into VC Express:
+ http://msdn.microsoft.com/vstudio/express/visualc/usingpsdk/default.aspx
+
+
+2. MSYS2 with MinGW
+===================
+
+2.1. Setup the basic msys2 environment
+
+Go to the official page of MSYS2: https://www.msys2.org
+Download an installer:
+
+* msys2-x86_64-YYYYMMDD.exe for 64-bit Windows
+ (Even if you want to build 32-bit Vim)
+* msys2-i686-YYYYMMDD.exe for 32-bit Windows
+
+Execute the installer and follow the instructions to update basic packages.
+At the end keep the checkbox checked to run msys2 now. If needed, you can
+open the window from the start menu, MSYS2 64 bit / MSYS2 MSYS.
+
+Execute:
+ $ pacman -Syu
+
+And restart MSYS2 console (select "MSYS2 MSYS" icon from the Start Menu).
+Then execute:
+ $ pacman -Su
+
+If pacman complains that `catgets` and `libcatgets` conflict with another
+package, select `y` to remove them.
+
+
+2.2. Install additional packages for building Vim
+
+The following package groups are required for building Vim:
+
+* base-devel
+* mingw-w64-i686-toolchain (for building 32-bit Vim)
+* mingw-w64-x86_64-toolchain (for building 64-bit Vim)
+
+(These groups also include some useful packages which are not used by Vim.)
+Use the following command to install them:
+
+ $ pacman -S base-devel mingw-w64-i686-toolchain mingw-w64-x86_64-toolchain
+
+Or you can use the `pacboy` command to avoid long package names:
+
+ $ pacboy -S base-devel: toolchain:m
+
+The suffix ":" means that it disables the package name translation.
+The suffix ":m" means both i686 and x86_64. You can also use the ":i" suffix
+to install only i686, and the ":x" suffix to install only x86_64.
+(See `pacboy help` for the help.)
+
+See also the pacman page in ArchWiki for the general usage of pacman:
+ https://wiki.archlinux.org/index.php/pacman
+
+MSYS2 has its own git package, and you can also install it via pacman:
+
+ $ pacman -S git
+
+
+2.3. Keep the build environment up-to-date
+
+After you have installed the build environment, you may want to keep it
+up-to-date (E.g. always use the latest GCC).
+In that case, you just need to execute the command:
+ $ pacman -Syu
+
+
+2.4. Build Vim
+
+Select one of the following icon from the Start Menu:
+
+* MSYS2 MinGW 32-bit (To build 32-bit versions of Vim)
+* MSYS2 MinGW 64-bit (To build 64-bit versions of Vim)
+
+Go to the source directory of Vim, then execute the make command. E.g.:
+
+ make -f Make_ming.mak
+ make -f Make_ming.mak GUI=no
+ make -f Make_ming.mak GUI=no DEBUG=yes
+
+NOTE: you can't execute vim.exe in the MSYS2 console, open a normal Windows
+console for that. You need to set $PATH to be able to build there, e.g.:
+
+ set PATH=c:\msys64\mingw32\bin;c:\msys64\usr\bin;%PATH%
+
+This command is in msys32.bat. Or for the 64 bit compiler use msys64.bat:
+
+ set PATH=c:\msys64\mingw64\bin;c:\msys64\usr\bin;%PATH%
+
+If you have msys64 in another location you will need to adjust the paths for
+that.
+
+
+3. MinGW
+========
+
+(written by Ron Aaron: <ronaharon@yahoo.com>)
+
+This is about how to produce a Win32 binary of gvim with MinGW.
+
+First, you need to get the 'mingw32' compiler, which is free for the download
+at:
+
+ http://www.mingw.org/
+
+or you can use 'MinGW-w64' compiler.
+
+ http://mingw-w64.sourceforge.net/
+
+Or a compiler provided on msys2:
+
+ https://msys2.github.io/
+
+Once you have downloaded the compiler binaries, unpack them on your hard disk
+somewhere, and put them on your PATH. If you are on Win95/98 you can edit
+your AUTOEXEC.BAT file with a line like:
+
+ set PATH=C:\MinGW\bin;%PATH%
+
+or on NT/2000/XP, go to the Control Panel, (Performance and Maintenance),
+System, Advanced, and edit the environment from there. If you use msys2
+compilers, set your installed paths (normally one of the following):
+
+ C:\msys32\mingw32\bin (32-bit msys2, targeting 32-bit builds)
+ C:\msys64\mingw32\bin (64-bit msys2, targeting 32-bit builds)
+ C:\msys64\mingw64\bin (64-bit msys2, targeting 64-bit builds)
+
+Test if gcc is on your path. From a CMD (or COMMAND on '95/98) window:
+
+ C:\> gcc --version
+ gcc (GCC) 4.8.1
+
+ C:\> mingw32-make --version
+ GNU Make 3.82.90 (...etc...)
+
+Now you are ready to rock 'n' roll. Unpack the vim sources (look on
+www.vim.org for exactly which version of the vim files you need).
+
+Change directory to 'vim\src':
+
+ C:\> cd vim\src
+ C:\VIM\SRC>
+
+and you type:
+
+ mingw32-make -f Make_ming.mak gvim.exe
+
+After churning for a while, you will end up with 'gvim.exe' in the 'vim\src'
+directory.
+
+You should not need to do *any* editing of any files to get vim compiled this
+way. If, for some reason, you want the console-mode-only version of vim (this
+is NOT recommended on Win32, especially on '95/'98!!!), you can use:
+
+ mingw32-make -f Make_ming.mak GUI=no vim.exe
+
+If you are dismayed by how big the EXE is, I strongly recommend you get 'UPX'
+(also free!) and compress the file (typical compression is 50%). UPX can be
+found at
+ http://www.upx.org/
+
+As of 2011, UPX still does not support compressing 64-bit EXE's; if you have
+built a 64-bit vim then an alternative to UPX is 'MPRESS'. MPRESS can be found
+at:
+ http://www.matcode.com/mpress.htm
+
+
+ADDITION: NLS support with MinGW
+
+(by Eduardo F. Amatria <eferna1@platea.pntic.mec.es>)
+
+If you want National Language Support, read the file src/po/README_mingw.txt.
+You need to uncomment lines in Make_ming.mak to have NLS defined.
+
+
+4. Cygwin
+=========
+
+Use Make_cyg.mak with Cygwin's GCC. See
+ http://users.skynet.be/antoine.mechelynck/vim/compile.htm
+
+With Cygnus gcc you should use the Unix Makefile instead (you need to get the
+Unix archive then). Then you get a Cygwin application (feels like Vim is
+running on Unix), while with Make_cyg.mak you get a Windows application (like
+with the other makefiles).
+
+
+5. Borland
+===========
+
+Use Make_bc5.mak with Borland C++ 5.x. See
+ http://users.skynet.be/antoine.mechelynck/vim/compile.htm
+
+
+6. Cross compiling for Win32 from a Linux machine
+=================================================
+
+[Update of 1) needs to be verified]
+
+If you like, you can compile the 'mingw' Win32 version from the comfort of
+your Linux (or other unix) box. To do this, you need to follow a few steps:
+ 1) Install the mingw32 cross-compiler. See
+ http://www.mingw.org/wiki/LinuxCrossMinGW
+ http://www.libsdl.org/extras/win32/cross/README.txt
+ 2) Get and unpack both the Unix sources and the extra archive
+ 3) in 'Make_cyg_ming.mak', set 'CROSS' to 'yes' instead of 'no'.
+ Make further changes to 'Make_cyg_ming.mak' and 'Make_ming.mak' as you
+ wish. If your cross-compiler prefix differs from the predefined value,
+ set 'CROSS_COMPILE' corresponding.
+ 4) make -f Make_ming.mak gvim.exe
+
+Now you have created the Windows binary from your Linux box! Have fun...
+
+
+7. Building with Python support
+===============================
+
+For building with MSVC 2008 the "Windows Installer" from www.python.org
+works fine.
+
+When building, you need to set the following variables at least:
+
+ PYTHON: Where Python is installed. E.g. C:\Python27
+ DYNAMIC_PYTHON: Whether dynamic linking is used. Usually, set to yes.
+ PYTHON_VER: Python version. E.g. 27 for Python 2.7.X.
+
+E.g. When using MSVC (as one line):
+
+ nmake -f Make_mvc.mak
+ PYTHON=C:\Python27 DYNAMIC_PYTHON=yes PYTHON_VER=27
+
+When using MinGW and link with the official Python (as one line):
+
+ mingw32-make -f Make_ming.mak
+ PYTHON=C:/Python27 DYNAMIC_PYTHON=yes PYTHON_VER=27
+
+When using msys2 and link with Python2 bundled with msys2 (as one line):
+
+ mingw32-make -f Make_ming.mak PYTHON=c:/msys64/mingw64
+ PYTHON_HOME=c:/msys64/mingw64
+ PYTHONINC=-Ic:/msys64/mingw64/include/python2.7
+ DYNAMIC_PYTHON=yes
+ PYTHON_VER=27
+ DYNAMIC_PYTHON_DLL=libpython2.7.dll
+ STATIC_STDCPLUS=yes
+
+(This is for 64-bit builds. For 32-bit builds, replace mingw64 with mingw32.)
+(STATIC_STDCPLUS is optional. Set to yes if you don't want to require
+libstdc++-6.dll.)
+
+
+(rest written by Ron Aaron: <ronaharon@yahoo.com>)
+
+Building with the mingw32 compiler, and the ActiveState ActivePython:
+ http://www.ActiveState.com/Products/ActivePython/
+
+After installing the ActivePython, you will have to create a 'mingw32'
+'libpython20.a' to link with:
+ cd $PYTHON/libs
+ pexports python20.dll > python20.def
+ dlltool -d python20.def -l libpython20.a
+
+Once that is done, edit the 'Make_ming.mak' so the PYTHON variable points to
+the root of the Python installation (C:\Python20, for example). If you are
+cross-compiling on Linux with the mingw32 setup, you need to also convert all
+the 'Include' files to *unix* line-endings. This bash command will do it
+easily:
+ for fil in *.h ; do vim -e -c 'set ff=unix|w|q' $fil
+
+Now just do:
+ make -f Make_ming.mak gvim.exe
+
+You will end up with a Python-enabled, Win32 version. Enjoy!
+
+
+8. Building with Python3 support
+================================
+
+For building with MSVC 2008 the "Windows Installer" from www.python.org
+works fine. Python 3.6 is recommended.
+
+When building, you need to set the following variables at least:
+
+ PYTHON3: Where Python3 is installed. E.g. C:\Python36
+ DYNAMIC_PYTHON3: Whether dynamic linking is used. Usually, set to yes.
+ PYTHON3_VER: Python3 version. E.g. 36 for Python 3.6.X.
+
+E.g. When using MSVC (as one line):
+
+ nmake -f Make_mvc.mak
+ PYTHON3=C:\Python36 DYNAMIC_PYTHON3=yes PYTHON3_VER=36
+
+When using MinGW and link with the official Python3 (as one line):
+
+ mingw32-make -f Make_ming.mak
+ PYTHON3=C:/Python36 DYNAMIC_PYTHON3=yes PYTHON3_VER=36
+
+When using msys2 and link with Python3 bundled with msys2 (as one line):
+
+ mingw32-make -f Make_ming.mak PYTHON3=c:/msys64/mingw64
+ PYTHON3_HOME=c:/msys64/mingw64
+ PYTHON3INC=-Ic:/msys64/mingw64/include/python3.6m
+ DYNAMIC_PYTHON3=yes
+ PYTHON3_VER=36
+ DYNAMIC_PYTHON3_DLL=libpython3.6m.dll
+ STATIC_STDCPLUS=yes
+
+(This is for 64-bit builds. For 32-bit builds, replace mingw64 with mingw32.)
+(STATIC_STDCPLUS is optional. Set to yes if you don't want to require
+libstdc++-6.dll.)
+
+
+9. Building with Racket or MzScheme support
+========================================
+
+1) Building with Racket support (newest)
+
+MzScheme and PLT Scheme names have been rebranded as Racket. Vim with Racket
+support can be built with either MSVC or MinGW (or Cygwin).
+Get it from https://download.racket-lang.org/
+
+Copy lib/libracket{version}.dll to your Windows system directory. The system
+directory depends on your Windows bitness and Vim bitness:
+ 32-bit Vim on 32-bit Windows: C:\Windows\System32
+ 32-bit Vim on 64-bit Windows: C:\Windows\SysWOW64
+ 64-bit Vim on 64-bit Windows: C:\Windows\System32
+
+For building you need to set the following variables:
+
+ MZSCHEME: Where Racket is installed.
+ E.g. C:\Program Files (x86)\Racket
+ DYNAMIC_MZSCHEME: Whether dynamic linking is used. Usually, set to yes.
+ MZSCHEME_VER: Racket DLL version which is used for the file name.
+ See below for a list of MZSCHEME_VER.
+ The DLL can be found under the lib directory. E.g.
+ C:\Program Files (x86)\Racket\lib\libracket3m_XXXXXX.dll
+ MZSCHEME_COLLECTS: (Optional) Path of the collects directory used at
+ runtime. Default: $(MZSCHEME)\collects
+ User can override this with the PLTCOLLECTS environment
+ variable.
+
+List of MZSCHEME_VER (incomplete):
+
+ Racket ver. | MZSCHEME_VER
+ ==========================
+ 6.3 | 3m_9z0ds0
+ 6.6 | 3m_a0solc
+ 6.8 | 3m_a1zjsw
+ 6.10 | 3m_a36fs8
+
+
+E.g. When using MSVC (as one line):
+
+ nmake -f Make_mvc.mak
+ MZSCHEME="C:\Program Files (x86)\Racket" DYNAMIC_MZSCHEME=yes
+ MZSCHEME_VER=3m_9z0ds0
+
+Or when using MinGW (as one line):
+
+ mingw32-make -f Make_ming.mak
+ MZSCHEME='C:/Program\ Files\ (x86)/Racket' DYNAMIC_MZSCHEME=yes
+ MZSCHEME_VER=3m_9z0ds0
+
+ Spaces should be escaped with '\'.
+
+
+2) Building with MzScheme support (older)
+
+(written by Sergey Khorev <sergey.khorev@gmail.com>)
+
+Vim with MzScheme (http://www.plt-scheme.org/software/mzscheme) support can
+be built with either MSVC, or MinGW, or Cygwin. Supported versions are 205 and
+above (including 299 and 30x series).
+
+The MSVC build is quite straightforward. Simply invoke (in one line)
+nmake -fMake_mvc.mak MZSCHEME=<Path-to-MzScheme>
+ [MZSCHEME_VER=<MzScheme-version>] [DYNAMIC_MZSCHEME=<yes or no>]
+where <MzScheme-version> is the last seven characters from MzScheme dll name
+(libmzschXXXXXXX.dll).
+If DYNAMIC_MZSCHEME=yes, resulting executable will not depend on MzScheme
+DLL's, but will load them in runtime on demand.
+
+Building dynamic MzScheme support on MinGW and Cygwin is similar. Take into
+account that <Path-to-MzScheme> should contain slashes rather than backslashes
+(e.g. d:/Develop/MzScheme)
+
+"Static" MzScheme support (Vim executable will depend on MzScheme DLLs
+explicitly) on MinGW and Cygwin requires additional step.
+
+libmzschXXXXXXX.dll and libmzgcXXXXXXX.dll should be copied from
+%WINDOWS%\System32 to other location (either build directory, some temporary
+dir or even MzScheme home).
+
+Pass that path as MZSCHEME_DLLS parameter for Make. E.g.,
+make -f Make_cyg.mak MZSCHEME=d:/Develop/MzScheme MZSCHEME_VER=209_000
+ MZSCHEME_DLLS=c:/Temp DYNAMIC_MZSCHEME=no
+
+After a successful build, these dlls can be freely removed, leaving them in
+%WINDOWS%\System32 only.
+
+
+
+10. Building with Lua support
+============================
+
+Vim with Lua support can be built with either MSVC or MinGW (or maybe Cygwin).
+You can use binaries from LuaBinaries: http://luabinaries.sourceforge.net/
+This also applies to when you get a Vim executable and don't build yourself,
+do the part up to "Build".
+
+1) Download and install LuaBinaries
+
+Go to the Download page of LuaBinaries:
+ http://luabinaries.sourceforge.net/download.html
+
+Download lua-X.Y.Z_Win32_dllw4_lib.zip for x86 or
+lua-X.Y.Z_Win64_dllw4_lib.zip for x64. You can use them both for MSVC and
+MinGW.
+
+Unpack it to a working directory. E.g. C:\projects\lua53.
+Lua's header files will be installed under the include directory.
+
+Copy luaXY.dll to your Windows system directory. The system directory depends
+on your Windows bitness and Vim bitness:
+ 32-bit Vim on 32-bit Windows: C:\Windows\System32
+ 32-bit Vim on 64-bit Windows: C:\Windows\SysWOW64
+ 64-bit Vim on 64-bit Windows: C:\Windows\System32
+
+Or another option is copying luaXY.dll to the directory where gvim.exe
+(or vim.exe) is.
+
+
+2) Build
+
+You need to set LUA, DYNAMIC_LUA and LUA_VER.
+
+ LUA: Where Lua's header files are installed. E.g. C:\projects\lua53.
+ DYNAMIC_LUA: Whether dynamic linking is used. Set to yes.
+ LUA_VER: Lua version. E.g. 53 for Lua 5.3.X.
+
+E.g. When using MSVC (as one line):
+
+ nmake -f Make_mvc.mak
+ LUA=C:\projects\lua53 DYNAMIC_LUA=yes LUA_VER=53
+
+Or when using MinGW (as one line):
+
+ mingw32-make -f Make_ming.mak
+ LUA=C:/projects/lua53 DYNAMIC_LUA=yes LUA_VER=53
+
+
+Or when using Cygwin (as one line) (untested):
+
+ make -f Make_cyg.mak
+ LUA=/cygdrive/c/projects/lua53 DYNAMIC_LUA=yes LUA_VER=53
+
+
+11. Building with Perl support
+==============================
+
+Vim with Perl support can be built with either MSVC or MinGW (or Cygwin).
+You can use binaries from ActiveState (ActivePerl) or Strawberry Perl.
+
+ http://www.activestate.com/activeperl
+ http://strawberryperl.com/
+
+When building, you need to set the following variables:
+
+ PERL: Where perl is installed. E.g. C:\Perl, C:\Strawberry\perl
+ DYNAMIC_PERL: Whether dynamic linking is used. Usually, set to yes.
+ PERL_VER: Perl version. E.g. 522 for Perl 5.22.X.
+
+E.g. When using MSVC (as one line):
+
+ nmake -f Make_mvc.mak
+ PERL=C:\Perl DYNAMIC_PERL=yes PERL_VER=522
+
+Or when using MinGW (as one line):
+
+ mingw32-make -f Make_ming.mak
+ PERL=C:/Perl DYNAMIC_PERL=yes PERL_VER=522
+
+
+12. Building with Ruby support
+==============================
+
+Vim with Ruby support can be built with either MSVC or MinGW (or Cygwin).
+Ruby doesn't provide the official Windows binaries. The most widely used
+Windows binaries might be RubyInstaller. Currently Ruby 2.4 is recommended.
+
+ http://rubyinstaller.org/
+
+If you use MinGW you can easily build with RubyInstaller, but if you use MSVC
+you need some tricks described below.
+(Another binary distribution is ActiveScriptRuby:
+ http://www.artonx.org/data/asr/)
+
+When building, you need to set the following variables at least:
+
+ RUBY: Where ruby is installed. E.g. C:\Ruby24
+ DYNAMIC_RUBY: Whether dynamic linking is used. Usually, set to yes.
+ RUBY_VER: Ruby version. E.g. 24 for Ruby 2.4.X.
+ RUBY_API_VER_LONG: Ruby API version in a long format.
+ E.g. 2.4.0 for Ruby 2.4.X.
+
+Ruby version vs. Ruby API version:
+
+ Ruby ver. | Ruby API ver.
+ =========================
+ 1.8.X | 1.8
+ 1.9.[1-3] | 1.9.1
+ 2.0.0 | 2.0.0
+ 2.X.Y | 2.X.0
+
+(Ruby 1.9.0 is excluded from the table because it is an unstable version.)
+
+
+A) Using MSVC
+
+If you want to link with ruby, normally you must use the same compiler as
+which was used to build the ruby binary. RubyInstaller is built with MinGW,
+so normally you cannot use MSVC for building Vim if you want to link with
+RubyInstaller. If you use a different compiler, there are mainly two problems:
+config.h and Ruby's DLL name. Here are the steps for working around them:
+
+ 1) Download and Install RubyInstaller.
+ You can install RubyInstaller with the default options and directory.
+ E.g.:
+ C:\Ruby24 (32-bit) or C:\Ruby24-x64 (64-bit)
+
+ Ruby 2.4.X is used in this example.
+
+ 2) Download Ruby 2.4.X's source code and generate config.h:
+
+ cd C:\projects
+ git clone https://github.com/ruby/ruby.git -b ruby_2_4
+ cd ruby
+ win32\configure.bat
+ nmake .config.h.time
+
+ Note that ruby_2_4 is the branch name for Ruby 2.4.X's source code.
+ There is no need to build whole Ruby, just config.h is needed.
+ If you use 32-bit MSVC 2015, the config.h is generated in the
+ .ext\include\i386-mswin32_140 directory.
+ If you use 64-bit MSVC 2015, the config.h is generated in the
+ .ext\include\x64-mswin64_140 directory.
+
+ 3) Install the generated config.h.
+
+ For 32-bit version:
+
+ xcopy /s .ext\include C:\Ruby24\include\ruby-2.4.0
+
+ For 64-bit version:
+
+ xcopy /s .ext\include C:\Ruby24-x64\include\ruby-2.4.0
+
+ Note that 2.4.0 is Ruby API version of Ruby 2.4.X.
+ You may need to close the console and reopen it to pick up the new $PATH.
+
+ 4) Build Vim. Note that you need to adjust some variables (as one line):
+
+ For 32-bit version:
+
+ nmake -f Make_mvc.mak
+ RUBY=C:\Ruby24 DYNAMIC_RUBY=yes RUBY_VER=24 RUBY_API_VER_LONG=2.4.0
+ RUBY_MSVCRT_NAME=msvcrt
+ WINVER=0x501
+
+ For 64-bit version, replace RUBY=C:\Ruby24 with RUBY=C:\Ruby24-x64.
+
+ If you set WINVER explicitly, it must be set to >=0x500, when building
+ with Ruby 2.1 or later. (Default is 0x501.)
+ When using this trick, you also need to set RUBY_MSVCRT_NAME to msvcrt
+ which is used for the Ruby's DLL name.
+
+B) Using MinGW
+
+Using MinGW is easier than using MSVC when linking with RubyInstaller.
+After you install RubyInstaller, just type this (as one line):
+
+ mingw32-make -f Make_ming.mak
+ RUBY=C:/Ruby24 DYNAMIC_RUBY=yes RUBY_VER=24 RUBY_API_VER_LONG=2.4.0
+ WINVER=0x600
+
+For 64-bit version, replace RUBY=C:/Ruby24 with RUBY=C:/Ruby24-x64.
+If you set WINVER explicitly, it must be set to >=0x500, when building with
+Ruby 2.1 or later. (Default is 0x600.)
+
+
+
+13. Building with Tcl support
+=============================
+
+Vim with Tcl support can be built with either MSVC or MinGW (or Cygwin).
+You can use binaries from ActiveState (ActiveTcl).
+
+ http://www.activestate.com/activetcl
+
+Alternatively, you can use the binaries provided by IronTcl from
+
+ https://www.irontcl.com/
+
+They might lack behind the latest version a bit, but should provide 64bit
+and 32bit versions even if ActiveTcl does not provide them anymore.
+
+For building with MSVC 2015 use version 8.6.6 or later.
+When building, you need to set the following variables:
+
+ TCL: Where tcl is installed. E.g. C:\Tcl86
+ DYNAMIC_TCL: Whether dynamic linking is used. Usually, set to yes.
+ TCL_VER: Tcl version in a short format. E.g. 86 for Tcl 8.6.X.
+ TCL_VER_LONG: Tcl version in a long format. E.g. 8.6 for Tcl 8.6.X.
+
+Sometimes the Tcl dll name changes. E.g. ActiveTcl 8.6.4 comes with tcl86.dll,
+but ActiveTcl 8.6.6 comes with tcl86t.dll. You can set the dll name by setting
+the TCL_DLL variable:
+ TCL_DLL=tcl86t.dll
+
+E.g. When using MSVC (as one line):
+
+ nmake -f Make_mvc.mak
+ TCL=C:\Tcl86 DYNAMIC_TCL=yes TCL_VER=86 TCL_VER_LONG=8.6
+
+Or when using MinGW (as one line):
+
+ mingw32-make -f Make_ming.mak
+ TCL=C:/Tcl86 DYNAMIC_TCL=yes TCL_VER=86 TCL_VER_LONG=8.6
+
+
+14. Building with Terminal support
+==================================
+
+Vim with Terminal support can be built with either MSVC, MinGW or Cygwin.
+This uses the included libvterm and winpty. No extra header files or
+libraries are needed for building. Just set TERMINAL to yes.
+
+E.g. When using MSVC:
+
+ nmake -f Make_mvc.mak TERMINAL=yes
+
+Or when using MinGW:
+
+ mingw32-make -f Make_ming.mak TERMINAL=yes
+
+
+15. Building with DirectX (DirectWrite) support
+===============================================
+
+Vim with DirectX (DirectWrite) support can be built with either MSVC or MinGW.
+This requires dwrite_2.h and some other header files which come with Windows
+SDK 8.1 or later (or MinGW-w64), if you want to enable color emoji support.
+This also requires MBYTE=yes which is enabled by default.
+
+A) Using MSVC
+
+If you use MSVC 2013 or later, Windows SDK 8.1 or later is used by default.
+You just need to specify DIRECTX=yes:
+
+ nmake -f Make_mvc.mak DIRECTX=yes
+
+If you use MSVC 2012 or earlier, the required header files are not available
+by default. However, you can use the header files from newer SDKs with older
+compilers. E.g.:
+
+ set "INCLUDE=%INCLUDE%;C:\Program Files (x86)\Windows Kits\8.1\Include\um"
+ nmake -f Make_mvc.mak DIRECTX=yes
+
+If you don't need color emoji support, only dwrite.h is required. You can use
+older compilers (e.g. VC2010) without Windows SDK 8.1. E.g.:
+
+ nmake -f Make_mvc.mak DIRECTX=yes COLOR_EMOJI=no
+
+B) Using MinGW-w64
+
+Just set DIRECTX to yes:
+
+ mingw32-make -f Make_ming.mak DIRECTX=yes
+
+
+16. Windows 3.1x
+================
+
+The Windows 3.1x support was removed in patch 7.4.1364.
+
+
+17. MS-DOS
+==========
+
+The MS-DOS support was removed in patch 7.4.1399. Only very old Vim versions
+work on MS-DOS because of the limited amount of memory available.
+
+
+18. Installing after building from sources
+==========================================
+
+[provided by Michael Soyka, updated by Ken Takata]
+
+After you've built the Vim binaries as described above, you're ready to
+install Vim on your system. However, if you've obtained the Vim sources
+using Git, Mercurial or by downloading them as a unix tar file, you must
+first create a "vim81" directory. If you instead downloaded the sources as
+zip files, you can skip this setup as the zip archives already have the
+correct directory structure.
+
+ A. Create a Vim "runtime" subdirectory named "vim81"
+ -----------------------------------------------------
+ If you obtained your Vim sources as zip files, you can skip this step.
+ Otherwise, continue reading.
+
+ Go to the directory that contains the Vim "src" and "runtime"
+ directories and create a new subdirectory named "vim81".
+
+ Copy the "runtime" files into "vim81":
+ copy runtime\* vim81
+
+ B. Copy the new binaries into the "vim81" directory
+ ----------------------------------------------------
+ Regardless of how you installed the Vim sources, you need to copy the
+ new binaries you created above into "vim81":
+
+ copy src\*.exe vim81
+ copy src\tee\tee.exe vim81
+ copy src\xxd\xxd.exe vim81
+
+ To install the "Edit with Vim" popup menu, you need both 32-bit and 64-bit
+ versions of gvimext.dll. They should be copied to "vim81\GvimExt32" and
+ "vim81\GvimExt64" respectively.
+ First, build the 32-bit version, then:
+
+ mkdir vim81\GvimExt32
+ copy src\GvimExt\gvimext.dll vim81\GvimExt32
+
+ Next, clean the 32-bit version and build the 64-bit version, then:
+
+ mkdir vim81\GvimExt64
+ copy src\GvimExt\gvimext.dll vim81\GvimExt64
+
+ C. Copy gettext and iconv DLLs into the "vim81" directory
+ ----------------------------------------------------------
+ Get gettext and iconv DLLs from the following site:
+ https://github.com/mlocati/gettext-iconv-windows/releases
+ Both 64- and 32-bit versions are needed.
+ Download the files gettextX.X.X.X-iconvX.XX-shared-{32,64}.zip, extract
+ DLLs and place them as follows:
+
+ vim81\
+ | libintl-8.dll
+ | libiconv-2.dll
+ | libgcc_s_sjlj-1.dll (only for 32-bit)
+ |
+ + GvimExt32\
+ | libintl-8.dll
+ | libiconv-2.dll
+ | libgcc_s_sjlj-1.dll
+ |
+ ` GvimExt64\
+ libintl-8.dll
+ libiconv-2.dll
+
+ The DLLs in the "vim81" should be the same bitness with the (g)vim.exe.
+
+ D. Move the "vim81" directory into the Vim installation subdirectory
+ ---------------------------------------------------------------------
+ Move the "vim81" subdirectory into the subdirectory where you want Vim
+ to be installed. Typically, this subdirectory will be named "vim".
+ If you already have a "vim81" subdirectory in "vim", delete it first
+ by running its uninstal.exe program.
+
+ E. Install Vim
+ ---------------
+ "cd" to your Vim installation subdirectory "vim\vim81" and run the
+ "install.exe" program. It will ask you a number of questions about
+ how you would like to have your Vim setup. Among these are:
+ - You can tell it to write a "_vimrc" file with your preferences in the
+ parent directory.
+ - It can also install an "Edit with Vim" entry in the Windows Explorer
+ popup menu.
+ - You can have it create batch files, so that you can run Vim from the
+ console or in a shell. You can select one of the directories in your
+ PATH or add the directory to PATH using the Windows Control Panel.
+ - Create entries for Vim on the desktop and in the Start menu.
+
+Happy Vimming!
diff --git a/src/INSTALLvms.txt b/src/INSTALLvms.txt
new file mode 100644
index 0000000..cbcbc49
--- /dev/null
+++ b/src/INSTALLvms.txt
@@ -0,0 +1,393 @@
+INSTALLvms.txt - Installation of Vim on OpenVMS
+
+Maintainer: Zoltan Arpadffy <arpadffy@polarhome.com>
+Last change: 2008 Jan 06
+
+This file contains instructions for compiling Vim on Openvms.
+If you already have an executable version of Vim, you don't need this.
+
+If you skip settings described here, then you will get the default Vim
+behavior as it is documented, which should be fine for most users.
+
+The file "feature.h" can be edited to match your preferences, but this files
+does not describe possibilities hidden in feature.h acrobatics, however
+parameters from MAKE_VMS.MMS actively uses and sets up parameters in relation
+with feature.h
+
+More information and case analysis you can found in os_vms.txt
+([runtime.doc]os_vms.txt or :help vms from vim prompt)
+
+Contents:
+1. Download files
+2. Configuration
+3. Compilation DECC
+4. Compilation VAXC
+5. CTAGS, XXD
+6. Deployment
+7. GTK and other features
+8. Notes
+9. Authors
+
+----------------------------------------------------------------------------
+1. Download files
+
+1.1. Visit the Vim ftp site (see ftp://ftp.vim.org/pub/vim/MIRRORS)
+ and obtain the following three files:
+
+ unix/vim-X.X-src.tar.gz
+ unix/vim-X.X-rt.tar.gz
+ extra/vim-X.X-extra.tar.gz
+
+ where X.X is the version number.
+
+1.2. Expand the three archives.
+
+1.3. Apply patches if they exist. (Patch files are found in the ftp
+ site in the "patches" directory.)
+
+1.4. You will need either the DECSET mms utility or the freely available clone
+ of it called mmk (VMS has no make utility in the standard distribution).
+ You can download mmk from http://www.openvms.digital.com/freeware/MMK/
+
+1.5. If you want to have Perl, Python or Tcl support in Vim you will need VMS
+ distributions for them as well.
+
+1.6 If you want to have GTK executable, you need to have properly installed
+ GTK libraries.
+
+NOTE: procedure in chapter 1 describes source code preparation from multi OS
+code, however it is available OpenVMS optimized (and tested) source code from:
+ftp://ftp.polarhome.com/pub/vim/source/vms/
+(http://www.polarhome.com/vim/files/source/vms/)
+
+Current OpenVMS source code as .zip or .tar.gz file is possible to download
+from CVS mirror ftp://ftp.polarhome.com/pub/cvs/SOURCE/
+(http://www.polarhome.com/cvs/SOURCE/)
+
+2. Configuration
+
+2.1. Edit vim-X.X/src/feature.h for your preference. (You can skip
+ this, then you will get the default behavior as is documented,
+ which should be fine for most people.)
+
+ For example, if you want to add the MULTI_BYTE feature, turn on
+ #define MULTI_BYTE
+
+2.2 Edit vim-X.X/src/Make_vms.mms to customize your Vim. Options are:
+
+ Parameter name : MODEL
+ Description : Build model selection
+ Options: : TINY - Almost no features enabled, not even
+ multiple windows
+ SMALL - Few features enabled, as basic as possible
+ NORMAL - A default selection of features enabled
+ BIG - Many features enabled, as rich as possible.
+ (OpenVMS default)
+ HUGE - All possible features enabled.
+ Uncommented - will default to BIG
+ Default : MODEL = BIG
+
+ Parameter name : GUI
+ Description : GUI or terminal mode executable
+ Options: : YES - GUI executable
+ Uncommented - char only
+ Default : GUI = YES
+
+ Parameter name : GTK
+ Description : Enable GTK in GUI mode.
+ It enables features as toolbar etc.
+ Options: : YES - GTK executable
+ Uncommented - without GTK
+ Default : Uncommented
+
+ Parameter name : XPM
+ Description : Enable XPM libraries in GUI/Motif mode.
+ It enables features as toolbar etc.
+ Options: : YES - GUI executable
+ Uncommented - without XPM
+ Default : Uncommented
+
+ Parameter name : DECC
+ Description : Compiler selection
+ Options: : YES - DECC compiler
+ Uncommented - VAXC compiler
+ Default : DECC = YES
+
+ Parameter name : CCVER
+ Description : Compiler version with :ver command
+ Options: : YES - Compiler version info will be added
+ Uncommented - will not be added
+ Default : CCVER = YES
+
+ Parameter name : DEBUG
+ Description : Building a debug version
+ Options: : YES - debug version will be built
+ Uncommented - building normal executable
+ Default : Uncommented
+
+ Parameter name : VIM_TCL
+ Description : Add Tcl support
+ Options: : YES - Build with support
+ Uncommented - build without support.
+ Default : Uncommented
+
+ Parameter name : VIM_PERL
+ Description : Add Perl support
+ Options: : YES - Build with support
+ Uncommented - build without support.
+ Default : Uncommented
+
+ Parameter name : VIM_PYTHON
+ Description : Add Python support
+ Options: : YES - Build with support
+ Uncommented - build without support.
+ Default : Uncommented
+
+ Parameter name : VIM_XIM
+ Description : X Input Method. For entering special languages
+ like chinese and Japanese. Please define just
+ one: VIM_XIM or VIM_HANGULIN
+ Options: : YES - Build with support
+ Uncommented - build without support.
+ Default : Uncommented
+
+ Parameter name : VIM_HANGULIN
+ Description : Internal Hangul input method. GUI only.
+ Please define just one: VIM_XIM or VIM_HANGULIN
+ Options: : YES - Build with support
+ Uncommented - build without support.
+ Default : Uncommented
+
+ Parameter name : VIM_TAG_ANYWHITE
+ Description : Allow any white space to separate the fields in a
+ tags file
+ When not defined, only a TAB is allowed.
+ Options: : YES - Build with support
+ Uncommented - build without support.
+ Default : Uncommented
+
+ You can edit the *_INC and *_LIB qualifiers, but it is really
+ not recommended for beginners.
+
+3. Compilation DECC
+
+3.1. If you have MSS on your system, the command
+
+ mms /descrip=Make_vms.mms
+
+ will start building your own customized version of Vim.
+ The adequate command for mmk is:
+
+ mmk /descrip=Make_vms.mms
+
+ NOTE: Because of empty /auto/config.h (needed for Unix configure) build
+ will fail with very strange messages. Therefore before building, it is
+ recommended to make one clean up, to prepare everything for OpenVMS
+ development. The command is:
+
+ mms /descrip=Make_vms.mms clean
+
+4. Compilation VAXC
+
+4.1. VAXC compiler is not fully ANSI C compatible in pre-processor directives
+ semantics, therefore you have to use a converter program what will do the
+ lion part of the job.
+
+ @os_vms_fix.com *.c *.h <.proto>*.pro
+
+ more information can be found in os_vms_fix.com file itself.
+
+ NOTE: even if os_vms_fix.com will fix all pre-processor directives it will
+ leave singe (long) line directives. You have to fix them manually.
+ Known problematic files are option.h and option.c
+
+4.2. After the conversion you can continue building as it has been described
+ above.
+
+5. CTAGS, XXD
+
+5.1. MMS_VIM.EXE is building together with VIM.EXE, but for CTAGS.EXE and
+ XXD.EXE you should change to subdirectory <.CTAGS> or <.XXD> and build
+ them separately.
+
+5.2. In these directories you can found one make file for VMS as well.
+ Please read the detailed build instructions in the related *.MMS file.
+
+6. Deployment
+
+6.1. Copy over all executables to the deployment directory.
+
+6.2. Vim uses a special directory structure to hold the document and runtime
+ files:
+
+ vim (or wherever)
+ |-- doc
+ |-- syntax
+ vimrc (system rc files)
+ gvimrc
+
+6.3 Define logicals VIM
+
+ define/nolog VIM device:[leading-path-here.vim]
+
+ to get vim.exe to find its document, filetype, and syntax files.
+
+ Now, if you are lucky you should have one own built, customized and
+ working Vim.
+
+7. GTK and other features
+
+7.1 General notes
+
+ To be able to build external GUI or language support you have to enable
+ related feature in MAKE_VMS.MMS file. Usually it need some extra tuning
+ around include files, shared libraries etc.
+
+ Please note, that leading "," are valuable for MMS/MMK syntax.
+
+ MAKE_VMS.MMS uses defines as described below:
+
+7.1.1 feature_DEF = ,"SOME_FEATURE"
+
+ Submits definition to compiler preprocessor to enable code blocks
+ defined with
+ #ifdef SOME_FEATURE
+ {some code here}
+ #endif
+
+ Example: TCL_DEF = ,"FEAT_TCL"
+
+
+7.1.2 feature_SRC = code1.c code2.c
+
+ Defines source code related with particular feature.
+ Example: TCL_SRC = if_tcl.c
+
+7.1.3 feature_OBJ = code1.obj code2.obj
+
+ Lists objects created from source codes listed in feature_SRC
+ Example: PERL_OBJ = if_perlsfio.obj if_perl.obj
+
+7.1.4 feature_LIB = ,OS_VMS_TCL.OPT/OPT
+
+ Defines the libraries that have to be used for build.
+ If it is an OPT file then MAKE_VMS.MMS creates OPT files
+ in gen_feature procedure.
+
+ Example:
+ PERL_LIB = ,OS_VMS_PERL.OPT/OPT
+
+.IFDEF VIM_PERL
+perl_env :
+ -@ write sys$output "creating OS_VMS_PERL.OPT file."
+ -@ open/write opt_file OS_VMS_PERL.OPT
+ -@ write opt_file "PERLSHR /share"
+ -@ close opt_file
+.ELSE
+perl_env :
+ -@ !
+.ENDIF
+
+
+7.1.5 feature_INC = ,dka0:[tcl80.generic]
+
+ Defines the directory where the necessary include files are.
+ Example: TCL_INC = ,dka0:[tcl80.generic]
+
+7.2 GTK
+
+ To build VIM with GTK you have to install GTK on your OpenVMS.
+ So far it works just on Alpha and IA64. More information at:
+ http://www.openvms.compaq.com/openvms/products/ips/gtk.html
+
+ You need also the OpenVMS Porting Library:
+ http://www.openvms.compaq.com/openvms/products/ips/porting.html
+
+ Source code for GTK and porting library that is used to build
+ VMS executables at polarhome.com are at
+ http://www.polarhome.com/vim/files/source/vms/
+
+ Enable GTK in make_vms.mms file with GTK = YES
+ Define GTK_ROOT that points to your GTK root directory.
+
+ You will need to edit GTKDIR variable in order to point
+ to GTK header files and libraries.
+
+ GTK_DIR = ALPHA$DKA0:[GTK128.]
+
+ ".]" at the end is very important.
+
+ Build it as normally.
+
+ Used sharable images are:
+ gtk_root:[glib]libglib.exe /share,-
+ gtk_root:[glib.gmodule]libgmodule.exe /share,-
+ gtk_root:[gtk.gdk]libgdk.exe /share,-
+ gtk_root:[gtk.gtk]libgtk.exe /share
+
+ During runtime it is suggested to have all these files installed and
+ copied to SYS$LIBRARY: to be able to use it without problems.
+ Also VMS_JACKETS.EXE from OpenVMS Porting Library.
+
+ Please note, that GTK uses /name=(as_is,short)/float=ieee/ieee=denorm
+ compiler directives that is not compatible with "standard" VMS usage,
+ therefore other external features might fail as PERL, PYTHON and TCL
+ support.
+
+7.3 PERL
+
+ You have to install OpenVMS perl package from:
+ http://www.openvms.compaq.com/openvms/products/ips/apache/csws_perl_relnotes.html or build on your own from sources downloaded from http://www.perl.org
+
+ You need defined PERLSHR logical that points to PERL shareable image
+ (or you can just copy over to SYS$LIBRARY:)
+
+ Enable Perl feature at make_vms.mms with VIM_PERL = YES
+
+ Edit PERL_INC = to point to perl includes directory where is extern.h
+
+ Build as usually.
+
+7.4 PYTHON
+
+ You have to install an OpenVMS python package.
+ Set up the normal Python work environment.
+
+ You have to have defined PYTHON_INCLUDE and PYTHON_OLB logicals.
+ PYTHON_INCLUDE should point to Python include files where for ex:
+ python.h is located.
+ Enable Python feature at make_vms.mms with VIM_PYTHON = YES
+
+ Build as usually.
+
+7.5 TCL
+
+ You have to install an OpenVMS TCL package.
+ Set up the normal TCL work environment.
+
+ You have to have defined TCLSHR logical that points to shareable image.
+
+ Enable TCL feature at make_vms.mms with VIM_TCL = YES
+
+ Edit TCL_INC = to point to TCL includes directory where is tcl.h
+
+ Build as usually.
+
+8. Notes
+
+8.1. New Compaq C compiler
+
+ If you are using Compaq C compiler V6.2 or newer, Informational messages
+ of the type QUESTCOMPARE will be displayed. You should ignore those
+ messages ; they are generated only because some test comparisons are done
+ with variables which type vary depending on the OS. Under VMS, those are
+ "unsigned" and the compiler issue a message whenever the comparison is
+ done with '<=' to 0. However, the code is correct and will behave as
+ expected.
+ ( Jerome Lauret <JLAURET@mail.chem.sunysb.edu> Vim 6.0n )
+ NOTE: from version 6.0ad Vim code has been reviewed and these warnings
+ have been corrected.
+
+9. Authors
+
+ Initial version, 2000 Jul 19, Zoltan Arpadffy <arpadffy@polarhome.com>
diff --git a/src/INSTALLx.txt b/src/INSTALLx.txt
new file mode 100644
index 0000000..e03f54d
--- /dev/null
+++ b/src/INSTALLx.txt
@@ -0,0 +1,165 @@
+INSTALLx.txt - cross-compiling Vim on Unix
+
+Content:
+ 1. Introduction
+ 2. Necessary arguments for "configure"
+ 3. Necessary environment variables for "configure"
+ 4. Example
+
+
+1. INTRODUCTION
+===============
+
+This document discusses cross-compiling VIM on Unix-like systems. We assume
+you are already familiar with cross-compiling and have a working cross-compile
+environment with at least the following components:
+
+ * a cross-compiler
+ * a libc to link against
+ * ncurses library to link against
+
+Discussing how to set up a cross-compile environment would go beyond the scope
+of this document. See http://www.kegel.com/crosstool/ for more information and
+a script that aids in setting up such an environment.
+
+
+The problem is that "configure" needs to compile and run small test programs
+to check for certain features. Running these test programs can't be done when
+cross-compiling so we need to pass the results these checks would produce via
+environment variables. See the list of variables and the examples at the end of
+this document.
+
+
+2. NECESSARY ARGUMENTS FOR "configure"
+======================================
+
+You need to set the following "configure" command line switches:
+
+--build=... :
+ The build system (i.e. the platform name of the system you compile on
+ right now).
+ For example, "i586-linux".
+
+--host=... :
+ The system on which VIM will be run. Quite often this the name of your
+ cross-compiler without the "-gcc".
+ For example, "powerpc-603-linux-gnu".
+
+--target=... :
+ Only relevant for compiling compilers. Set this to the same value as
+ --host.
+
+--with-tlib=... :
+ Which terminal library to use.
+ For example, "ncurses".
+
+
+3. NECESSARY ENVIRONMENT VARIABLES FOR "configure"
+==================================================
+
+Additionally to the variables listed here you might want to set the CPPFLAGS
+environment variable to enable optimization for your target system (e.g.
+"CPPFLAGS=-march=arm5te").
+
+The following variables need to be set:
+
+ac_cv_sizeof_int:
+ The size of an "int" C type in bytes. Should be "4" on all 32bit
+ machines.
+
+vi_cv_path_python_conf:
+ If Python support is enabled, set this variable to the path for
+ Python's library implementation. This is a path like
+ "/usr/lib/pythonX.Y/config" (the directory contains a file
+ "config.c").
+
+vi_cv_var_python_epfx:
+ If Python support is enabled, set this variable to the execution
+ prefix of your Python interpreter (that is, where it thinks it is
+ running).
+ This is the output of the following Python script:
+ import sys; print sys.exec_prefix
+
+vi_cv_var_python_pfx:
+ If Python support is enabled, set this variable to the prefix of your
+ Python interpreter (that is, where it was installed).
+ This is the output of the following Python script:
+ import sys; print sys.prefix
+
+vi_cv_var_python_version:
+ If Python support is enabled, set this variable to the version of the
+ Python interpreter that will be used.
+ This is the output of the following Python script:
+ import sys; print sys.version[:3]
+
+vim_cv_bcopy_handles_overlap:
+ Whether the "memmove" C library call is able to copy overlapping
+ memory regions. Set to "yes" if it does or "no" if it does not.
+ You only need to set this if vim_cv_memmove_handles_overlap is set
+ to "no".
+
+vim_cv_getcwd_broken:
+ Whether the "getcwd" C library call is broken. Set to "yes" if you
+ know that "getcwd" is implemented as 'system("sh -c pwd")', set to
+ "no" otherwise.
+
+vim_cv_memcpy_handles_overlap:
+ Whether the "memcpy" C library call is able to copy overlapping
+ memory regions. Set to "yes" if it does or "no" if it does not.
+ You only need to set this if both vim_cv_memmove_handles_overlap
+ and vim_cv_bcopy_handles_overlap are set to "no".
+
+vim_cv_memmove_handles_overlap:
+ Whether the "memmove" C library call is able to copy overlapping
+ memory regions. Set to "yes" if it does or "no" if it does not.
+
+vim_cv_stat_ignores_slash:
+ Whether the "stat" C library call ignores trailing slashes in the path
+ name. Set to "yes" if it ignores them or "no" if it does not ignore
+ them.
+
+vim_cv_tgetent:
+ Whether the "tgetent" terminal library call returns a zero or non-zero
+ value when it encounters an unknown terminal. Set to either the string
+ "zero" or "non-zero", corresponding.
+
+vim_cv_terminfo:
+ Whether the environment has terminfo support. Set to "yes" if so,
+ otherwise set to "no".
+
+vim_cv_toupper_broken:
+ Whether the "toupper" C library function works correctly. Set to "yes"
+ if you know it's broken, otherwise set to "no".
+
+vim_cv_tty_group:
+ The default group of pseudo terminals. Either set to the numeric value
+ of your tty group or to "world" if they are world accessible.
+
+vim_cv_tty_mode:
+ The default mode of pseudo terminals if they are not world accessible.
+ Most probably the value "0620".
+
+
+4. EXAMPLE:
+===========
+
+Assuming the target system string is "armeb-xscale-linux-gnu" (a Intel XScale
+system) with glibc and ncurses, the call to configure would look like this:
+
+ac_cv_sizeof_int=4 \
+vim_cv_getcwd_broken=no \
+vim_cv_memmove_handles_overlap=yes \
+vim_cv_stat_ignores_slash=yes \
+vim_cv_tgetent=zero \
+vim_cv_terminfo=yes \
+vim_cv_toupper_broken=no \
+vim_cv_tty_group=world \
+./configure \
+ --build=i586-linux \
+ --host=armeb-xscale-linux-gnu \
+ --target=armeb-xscale-linux-gnu \
+ --with-tlib=ncurses
+
+
+
+Written 2007 by Marc Haisenko <marc@darkdust.net> for the VIM project.
diff --git a/src/Make_all.mak b/src/Make_all.mak
new file mode 100644
index 0000000..591350f
--- /dev/null
+++ b/src/Make_all.mak
@@ -0,0 +1,15 @@
+#
+# Common Makefile, defines the list of tests to run and other things.
+#
+
+# Argument for running ctags.
+TAGS_FILES = \
+ *.c \
+ *.cpp \
+ *.h \
+ auto/*.c \
+ libvterm/src/*.c \
+ libvterm/src/*.h \
+ libvterm/include/*.h \
+ xdiff/*.c \
+ xdiff/*.h
diff --git a/src/Make_bc5.mak b/src/Make_bc5.mak
new file mode 100644
index 0000000..b2977e7
--- /dev/null
+++ b/src/Make_bc5.mak
@@ -0,0 +1,1060 @@
+#
+# Makefile for Vim.
+# Compiler: Borland C++ 5.0 and later 32-bit compiler
+# Targets: Win32 (Windows NT and Windows 95) (with/without GUI)
+#
+# NOTE: THIS IS OLD AND PROBABLY NO LONGER WORKS.
+#
+# Contributed by Ben Singer.
+# Updated 4/1997 by Ron Aaron
+# 2016: removed support for 16 bit DOS
+# 6/1997 - added support for 16 bit DOS
+# Note: this has been tested, and works, for BC5. Your mileage may vary.
+# Has been reported NOT to work with BC 4.52. Maybe it can be fixed?
+# 10/1997 - ron - fixed bugs w/ BC 5.02
+# 8/1998 - ron - updated with new targets, fixed some stuff
+# 3/2000 - Bram: Made it work with BC 5.5 free command line compiler,
+# cleaned up variables.
+# 6/2001 - Dan - Added support for compiling Python and TCL
+# 7/2001 - Dan - Added support for compiling Ruby
+#
+# It builds on Windows 95 and NT-Intel, producing the same binary in either
+# case. To build using Microsoft Visual C++, use Make_mvc.mak.
+#
+# This should work with the free Borland command line compiler, version 5.5.
+# You need at least sp1 (service pack 1). With sp2 it compiles faster.
+# Use a command like this:
+# <path>\bin\make /f Make_bc5.mak BOR=<path>
+#
+
+# let the make utility do the hard work:
+.AUTODEPEND
+.CACHEAUTODEPEND
+
+# VARIABLES:
+# name value (default)
+#
+# BOR path to root of Borland C install (c:\bc5)
+# LINK name of the linker ($(BOR)\bin\ilink32)
+# GUI no or yes: set to yes if you want the GUI version (yes)
+# LUA define to path to Lua dir to get Lua support (not defined)
+# LUA_VER define to version of Lua being used (51)
+# DYNAMIC_LUA no or yes: set to yes to load the Lua DLL dynamically (no)
+# PERL define to path to Perl dir to get Perl support (not defined)
+# PERL_VER define to version of Perl being used (56)
+# DYNAMIC_PERL no or yes: set to yes to load the Perl DLL dynamically (no)
+# PYTHON define to path to Python dir to get PYTHON support (not defined)
+# PYTHON_VER define to version of Python being used (22)
+# DYNAMIC_PYTHON no or yes: use yes to load the Python DLL dynamically (no)
+# PYTHON3 define to path to Python3 dir to get PYTHON3 support (not defined)
+# PYTHON3_VER define to version of Python3 being used (31)
+# DYNAMIC_PYTHON3 no or yes: use yes to load the Python3 DLL dynamically (no)
+# TCL define to path to TCL dir to get TCL support (not defined)
+# TCL_VER define to version of TCL being used (83)
+# DYNAMIC_TCL no or yes: use yes to load the TCL DLL dynamically (no)
+# RUBY define to path to Ruby dir to get Ruby support (not defined)
+# NOTE: You may have to remove the defines for uid_t and gid_t
+# from the Ruby config.h header file.
+# RUBY_VER define to version of Ruby being used (16)
+# NOTE: compilation on WinNT/2K/XP requires
+# at least version 1.6.5 of Ruby. Earlier versions
+# of Ruby will cause a compile error on these systems.
+# RUBY_VER_LONG same, but in format with dot. (1.6)
+# DYNAMIC_RUBY no or yes: use yes to load the Ruby DLL dynamically (no)
+# IME no or yes: set to yes for multi-byte IME support (yes)
+# DYNAMIC_IME no or yes: set to yes to load imm32.dll dynamically (yes)
+# GETTEXT no or yes: set to yes for multi-language support (yes)
+# ICONV no or yes: set to yes for dynamic iconv support (yes)
+# OLE no or yes: set to yes to make OLE gvim (no)
+# DEBUG no or yes: set to yes if you wish a DEBUGging build (no)
+# CODEGUARD no or yes: set to yes if you want to use CODEGUARD (no)
+# CPUNR 1 through 6: select -CPU argument to compile with (3)
+# 3 for 386, 4 for 486, 5 for pentium, 6 for pentium pro.
+# USEDLL no or yes: set to yes to use the Runtime library DLL (no)
+# For USEDLL=yes the cc3250.dll is required to run Vim.
+# VIMDLL no or yes: create vim32.dll, and stub (g)vim.exe (no)
+# ALIGN 1, 2 or 4: Alignment to use (4 for Win32)
+# FASTCALL no or yes: set to yes to use register-based function protocol (yes)
+# OPTIMIZE SPACE, SPEED, or MAXSPEED: type of optimization (MAXSPEED)
+# POSTSCRIPT no or yes: set to yes for PostScript printing
+# FEATURES TINY, SMALL, NORMAL, BIG or HUGE (BIG for WIN32)
+# WINVER 0x0400 or 0x0500: minimum Win32 version to support (0x0400)
+# CSCOPE no or yes: include support for Cscope interface (yes)
+# NETBEANS no or yes: include support for Netbeans interface; also
+# requires CHANNEL (yes if GUI
+# is yes)
+# NBDEBUG no or yes: include support for debugging Netbeans interface (no)
+# CHANNEL no or yes: include support for inter process communication (yes
+# if GUI is yes)
+# XPM define to path to XPM dir to get support for loading XPM images.
+
+### BOR: root of the BC installation
+!if ("$(BOR)"=="")
+BOR = c:\bc5
+!endif
+
+### LINK: Name of the linker: ilink32 (this is below)
+
+### GUI: yes for GUI version, no for console version
+!if ("$(GUI)"=="")
+GUI = yes
+!endif
+
+### IME: yes for multibyte support, no to disable it.
+!if ("$(IME)"=="")
+IME = yes
+!endif
+!if ("$(DYNAMIC_IME)"=="")
+DYNAMIC_IME = yes
+!endif
+
+### GETTEXT: yes for multilanguage support, no to disable it.
+!if ("$(GETTEXT)"=="")
+GETTEXT = yes
+!endif
+
+### ICONV: yes to enable dynamic-iconv support, no to disable it
+!if ("$(ICONV)"=="")
+ICONV = yes
+!endif
+
+### CSCOPE: yes to enable Cscope support, no to disable it
+!if ("$(CSCOPE)"=="")
+CSCOPE = yes
+!endif
+
+### NETBEANS: yes to enable NetBeans interface support, no to disable it
+!if ("$(NETBEANS)"=="") && ("$(GUI)"=="yes")
+NETBEANS = yes
+!endif
+
+### CHANNEL: yes to enable inter process communication, no to disable it
+!if ("$(CHANNEL)"=="") && ("$(GUI)"=="yes")
+CHANNEL = yes
+!endif
+
+### LUA: uncomment this line if you want lua support in vim
+# LUA=c:\lua
+
+### PERL: uncomment this line if you want perl support in vim
+# PERL=c:\perl
+
+### PYTHON: uncomment this line if you want python support in vim
+# PYTHON=c:\python22
+
+### PYTHON3: uncomment this line if you want python3 support in vim
+# PYTHON3=c:\python31
+
+### RUBY: uncomment this line if you want ruby support in vim
+# RUBY=c:\ruby
+
+### TCL: uncomment this line if you want tcl support in vim
+# TCL=c:\tcl
+
+### OLE: no for normal gvim, yes for OLE-capable gvim (only works with GUI)
+#OLE = yes
+
+### DEBUG: Uncomment to make an executable for debugging
+# DEBUG = yes
+!if ("$(DEBUG)"=="yes")
+DEBUG_FLAG = -v
+!endif
+
+### CODEGUARD: Uncomment to use the CODEGUARD stuff (BC 5.0 or later):
+# CODEGUARD = yes
+!if ("$(CODEGUARD)"=="yes")
+CODEGUARD_FLAG = -vG
+!endif
+
+### CPUNR: set your target processor (3 to 6)
+!if ("$(CPUNR)" == "i386") || ("$(CPUNR)" == "3")
+CPUNR = 3
+!elif ("$(CPUNR)" == "i486") || ("$(CPUNR)" == "4")
+CPUNR = 4
+!elif ("$(CPUNR)" == "i586") || ("$(CPUNR)" == "5")
+CPUNR = 5
+!elif ("$(CPUNR)" == "i686") || ("$(CPUNR)" == "6")
+CPUNR = 6
+!else
+CPUNR = 3
+!endif
+
+### Comment out to use precompiled headers (faster, but uses lots of disk!)
+HEADERS = -H -H=vim.csm -Hc
+
+### USEDLL: no for statically linked version of run-time, yes for DLL runtime
+!if ("$(USEDLL)"=="")
+USEDLL = no
+!endif
+
+### VIMDLL: yes for a DLL version of VIM (NOT RECOMMENDED), no otherwise
+#VIMDLL = yes
+
+### ALIGN: alignment you desire: (1,2 or 4: s/b 4 for Win32)
+!if ("$(ALIGN)"=="")
+ALIGN = 4
+!endif
+
+### FASTCALL: yes to use FASTCALL calling convention (RECOMMENDED!), no otherwise
+# Incompatible when calling external functions (like MSVC-compiled DLLs), so
+# don't use FASTCALL when linking with external libs.
+!if ("$(FASTCALL)"=="") && \
+ ("$(LUA)"=="") && \
+ ("$(PYTHON)"=="") && \
+ ("$(PYTHON3)"=="") && \
+ ("$(PERL)"=="") && \
+ ("$(TCL)"=="") && \
+ ("$(RUBY)"=="") && \
+ ("$(ICONV)"!="yes") && \
+ ("$(IME)"!="yes") && \
+ ("$(XPM)"=="")
+FASTCALL = yes
+!endif
+
+### OPTIMIZE: SPEED to optimize for speed, SPACE otherwise (SPEED RECOMMENDED)
+!if ("$(OPTIMIZE)"=="")
+OPTIMIZE = MAXSPEED
+!endif
+
+### FEATURES: TINY, SMALL, NORMAL, BIG or HUGE (BIG for WIN32)
+!if ("$(FEATURES)"=="")
+FEATURES = BIG
+!endif
+
+### POSTSCRIPT: uncomment this line if you want PostScript printing
+#POSTSCRIPT = yes
+
+###
+# If you have a fixed directory for $VIM or $VIMRUNTIME, other than the normal
+# default, use these lines.
+#VIMRCLOC = somewhere
+#VIMRUNTIMEDIR = somewhere
+
+### Set the default $(WINVER) to make it work with Bcc 5.5.
+!ifndef WINVER
+WINVER = 0x0400
+!endif
+
+#
+# Sanity checks for the above options:
+#
+
+OSTYPE = WIN32
+
+#
+# Optimizations: change as desired (RECOMMENDATION: Don't change!):
+#
+!if ("$(DEBUG)"=="yes")
+OPT = -Od -N
+!else
+!if ("$(OPTIMIZE)"=="SPACE")
+OPT = -O1 -f- -d
+!elif ("$(OPTIMIZE)"=="MAXSPEED")
+OPT = -O2 -f- -d -Ocavi -O
+!else
+OPT = -O2 -f- -d -Oc -O
+!endif
+!if ("$(FASTCALL)"=="yes")
+OPT = $(OPT) -pr
+!endif
+!if ("$(CODEGUARD)"!="yes")
+OPT = $(OPT) -vi-
+!endif
+!endif
+# shouldn't have to change:
+LIB = $(BOR)\lib
+INCLUDE = $(BOR)\include;.;proto
+DEFINES = -DFEAT_$(FEATURES) -DWIN32 -DHAVE_PATHDEF \
+ -DWINVER=$(WINVER) -D_WIN32_WINNT=$(WINVER)
+
+!ifdef LUA
+INTERP_DEFINES = $(INTERP_DEFINES) -DFEAT_LUA
+INCLUDE = $(LUA)\include;$(INCLUDE)
+! ifndef LUA_VER
+LUA_VER = 51
+! endif
+! if ("$(DYNAMIC_LUA)" == "yes")
+INTERP_DEFINES = $(INTERP_DEFINES) -DDYNAMIC_LUA -DDYNAMIC_LUA_DLL=\"lua$(LUA_VER).dll\"
+LUA_LIB_FLAG = /nodefaultlib:
+! endif
+!endif
+
+!ifdef PERL
+INTERP_DEFINES = $(INTERP_DEFINES) -DFEAT_PERL
+INCLUDE = $(PERL)\lib\core;$(INCLUDE)
+! ifndef PERL_VER
+PERL_VER = 56
+! endif
+! if ("$(DYNAMIC_PERL)" == "yes")
+! if ($(PERL_VER) > 55)
+INTERP_DEFINES = $(INTERP_DEFINES) -DDYNAMIC_PERL -DDYNAMIC_PERL_DLL=\"perl$(PERL_VER).dll\"
+PERL_LIB_FLAG = /nodefaultlib:
+! else
+! message "Cannot dynamically load Perl versions less than 5.6. Loading statically..."
+! endif
+! endif
+!endif
+
+!ifdef PYTHON
+!ifdef PYTHON3
+DYNAMIC_PYTHON=yes
+DYNAMIC_PYTHON3=yes
+!endif
+!endif
+
+!ifdef PYTHON
+INTERP_DEFINES = $(INTERP_DEFINES) -DFEAT_PYTHON
+!ifndef PYTHON_VER
+PYTHON_VER = 22
+!endif
+!if "$(DYNAMIC_PYTHON)" == "yes"
+INTERP_DEFINES = $(INTERP_DEFINES) -DDYNAMIC_PYTHON -DDYNAMIC_PYTHON_DLL=\"python$(PYTHON_VER).dll\"
+PYTHON_LIB_FLAG = /nodefaultlib:
+!endif
+!endif
+
+!ifdef PYTHON3
+INTERP_DEFINES = $(INTERP_DEFINES) -DFEAT_PYTHON3
+!ifndef PYTHON3_VER
+PYTHON3_VER = 31
+!endif
+!if "$(DYNAMIC_PYTHON3)" == "yes"
+INTERP_DEFINES = $(INTERP_DEFINES) -DDYNAMIC_PYTHON3 -DDYNAMIC_PYTHON3_DLL=\"python$(PYTHON3_VER).dll\"
+PYTHON3_LIB_FLAG = /nodefaultlib:
+!endif
+!endif
+
+
+!ifdef RUBY
+!ifndef RUBY_VER
+RUBY_VER = 16
+!endif
+!ifndef RUBY_VER_LONG
+RUBY_VER_LONG = 1.6
+!endif
+
+!if "$(RUBY_VER)" == "16"
+!ifndef RUBY_PLATFORM
+RUBY_PLATFORM = i586-mswin32
+!endif
+!ifndef RUBY_INSTALL_NAME
+RUBY_INSTALL_NAME = mswin32-ruby$(RUBY_VER)
+!endif
+!else
+!ifndef RUBY_PLATFORM
+RUBY_PLATFORM = i386-mswin32
+!endif
+!ifndef RUBY_INSTALL_NAME
+RUBY_INSTALL_NAME = msvcrt-ruby$(RUBY_VER)
+!endif
+!endif
+
+INTERP_DEFINES = $(INTERP_DEFINES) -DFEAT_RUBY
+INCLUDE = $(RUBY)\lib\ruby\$(RUBY_VER_LONG)\$(RUBY_PLATFORM);$(INCLUDE)
+
+!if "$(DYNAMIC_RUBY)" == "yes"
+INTERP_DEFINES = $(INTERP_DEFINES) -DDYNAMIC_RUBY -DDYNAMIC_RUBY_DLL=\"$(RUBY_INSTALL_NAME).dll\"
+INTERP_DEFINES = $(INTERP_DEFINES) -DDYNAMIC_RUBY_VER=$(RUBY_VER)
+RUBY_LIB_FLAG = /nodefaultlib:
+!endif
+!endif
+
+!ifdef TCL
+INTERP_DEFINES = $(INTERP_DEFINES) -DFEAT_TCL
+INCLUDE = $(TCL)\include;$(INCLUDE)
+!ifndef TCL_VER
+TCL_VER = 83
+!endif
+TCL_LIB = $(TCL)\lib\tcl$(TCL_VER).lib
+TCL_LIB_FLAG =
+!if "$(DYNAMIC_TCL)" == "yes"
+INTERP_DEFINES = $(INTERP_DEFINES) -DDYNAMIC_TCL -DDYNAMIC_TCL_DLL=\"tcl$(TCL_VER).dll\"
+TCL_LIB = tclstub$(TCL_VER)-bor.lib
+TCL_LIB_FLAG =
+!endif
+!endif
+#
+# DO NOT change below:
+#
+CPUARG = -$(CPUNR)
+ALIGNARG = -a$(ALIGN)
+#
+!if ("$(DEBUG)"=="yes")
+DEFINES=$(DEFINES) -DDEBUG -D_DEBUG
+!endif
+#
+!if ("$(OLE)"=="yes")
+DEFINES = $(DEFINES) -DFEAT_OLE
+!endif
+#
+!if ("$(IME)"=="yes")
+MBDEFINES = $(MBDEFINES) -DFEAT_MBYTE_IME
+!if ("$(DYNAMIC_IME)" == "yes")
+MBDEFINES = $(MBDEFINES) -DDYNAMIC_IME
+!endif
+!endif
+!if ("$(ICONV)"=="yes")
+MBDEFINES = $(MBDEFINES) -DDYNAMIC_ICONV
+!endif
+!if ("$(GETTEXT)"=="yes")
+MBDEFINES = $(MBDEFINES) -DDYNAMIC_GETTEXT
+!endif
+
+!if ("$(CSCOPE)"=="yes")
+DEFINES = $(DEFINES) -DFEAT_CSCOPE
+!endif
+
+!if ("$(GUI)"=="yes")
+DEFINES = $(DEFINES) -DFEAT_GUI_W32 -DFEAT_CLIPBOARD
+!if ("$(DEBUG)"=="yes")
+TARGET = gvimd.exe
+!else
+TARGET = gvim.exe
+!endif
+!if ("$(VIMDLL)"=="yes")
+EXETYPE=-WD
+DEFINES = $(DEFINES) -DVIMDLL
+!else
+EXETYPE=-W
+!endif
+STARTUPOBJ = c0w32.obj
+LINK2 = -aa
+RESFILE = vim.res
+!else
+!undef NETBEANS
+!undef CHANNEL
+!undef XPM
+!undef VIMDLL
+!if ("$(DEBUG)"=="yes")
+TARGET = vimd.exe
+!else
+# for now, anyway: VIMDLL is only for the GUI version
+TARGET = vim.exe
+!endif
+EXETYPE=-WC
+STARTUPOBJ = c0x32.obj
+LINK2 = -ap -OS -o -P
+RESFILE = vim.res
+!endif
+
+!if ("$(NETBEANS)"=="yes")
+!if ("$(CHANNEL)"!="yes")
+# cannot use Netbeans without CHANNEL
+NETBEANS = no
+!else
+DEFINES = $(DEFINES) -DFEAT_NETBEANS_INTG
+!if ("$(NBDEBUG)"=="yes")
+DEFINES = $(DEFINES) -DNBDEBUG
+NBDEBUG_DEP = nbdebug.h nbdebug.c
+!endif
+!endif
+!endif
+
+!if ("$(CHANNEL)"=="yes")
+DEFINES = $(DEFINES) -DFEAT_JOB_CHANNEL
+!endif
+
+!ifdef XPM
+!if ("$(GUI)"=="yes")
+DEFINES = $(DEFINES) -DFEAT_XPM_W32
+INCLUDE = $(XPM)\include;$(INCLUDE)
+!endif
+!endif
+
+!if ("$(USEDLL)"=="yes")
+DEFINES = $(DEFINES) -D_RTLDLL
+!endif
+
+!if ("$(DEBUG)"=="yes")
+OBJDIR = $(OSTYPE)\objdbg
+!else
+!if ("$(GUI)"=="yes")
+!if ("$(OLE)"=="yes")
+OBJDIR = $(OSTYPE)\oleobj
+!else
+OBJDIR = $(OSTYPE)\gobj
+!endif
+!else
+OBJDIR = $(OSTYPE)\obj
+!endif
+!endif
+
+!if ("$(POSTSCRIPT)"=="yes")
+DEFINES = $(DEFINES) -DMSWINPS
+!endif
+
+##### BASE COMPILER/TOOLS RULES #####
+MAKE = $(BOR)\bin\make
+CFLAGS = -w-aus -w-par -w-pch -w-ngu -w-csu -I$(INCLUDE)
+BRC = $(BOR)\BIN\brc32
+!if ("$(LINK)"=="")
+LINK = $(BOR)\BIN\ILink32
+!endif
+CC = $(BOR)\BIN\Bcc32
+LFLAGS = -OS -Tpe -c -m -L$(LIB) $(DEBUG_FLAG) $(LINK2)
+LFLAGSDLL = -Tpd -c -m -L$(LIB) $(DEBUG_FLAG) $(LINK2)
+CFLAGS = $(CFLAGS) -d -RT- -k- -Oi $(HEADERS) -f-
+
+CC1 = -c
+CC2 = -o
+CCARG = +$(OBJDIR)\bcc.cfg
+
+# implicit rules:
+
+# Without the following, the implicit rule in BUILTINS.MAK is picked up
+# for a rule for .c.obj rather than the local implicit rule
+.SUFFIXES
+.SUFFIXES .c .obj
+.path.c = .
+
+{.}.c{$(OBJDIR)}.obj:
+ $(CC) $(CCARG) $(CC1) -n$(OBJDIR)\ {$< }
+
+.cpp.obj:
+ $(CC) $(CCARG) $(CC1) $(CC2)$@ $*.cpp
+
+vimmain = \
+ $(OBJDIR)\os_w32exe.obj
+!if ("$(VIMDLL)"=="yes")
+vimwinmain = \
+ $(OBJDIR)\os_w32dll.obj
+!else
+vimwinmain = \
+ $(OBJDIR)\os_w32exe.obj
+!endif
+
+vimobj = \
+ $(OBJDIR)\arabic.obj \
+ $(OBJDIR)\autocmd.obj \
+ $(OBJDIR)\blowfish.obj \
+ $(OBJDIR)\buffer.obj \
+ $(OBJDIR)\charset.obj \
+ $(OBJDIR)\crypt.obj \
+ $(OBJDIR)\crypt_zip.obj \
+ $(OBJDIR)\dict.obj \
+ $(OBJDIR)\diff.obj \
+ $(OBJDIR)\digraph.obj \
+ $(OBJDIR)\edit.obj \
+ $(OBJDIR)\eval.obj \
+ $(OBJDIR)\evalfunc.obj \
+ $(OBJDIR)\ex_cmds.obj \
+ $(OBJDIR)\ex_cmds2.obj \
+ $(OBJDIR)\ex_docmd.obj \
+ $(OBJDIR)\ex_eval.obj \
+ $(OBJDIR)\ex_getln.obj \
+ $(OBJDIR)\farsi.obj \
+ $(OBJDIR)\fileio.obj \
+ $(OBJDIR)\fold.obj \
+ $(OBJDIR)\getchar.obj \
+ $(OBJDIR)\hardcopy.obj \
+ $(OBJDIR)\hashtab.obj \
+ $(OBJDIR)\indent.obj \
+ $(OBJDIR)\json.obj \
+ $(OBJDIR)\list.obj \
+ $(OBJDIR)\main.obj \
+ $(OBJDIR)\mark.obj \
+ $(OBJDIR)\memfile.obj \
+ $(OBJDIR)\memline.obj \
+ $(OBJDIR)\menu.obj \
+ $(OBJDIR)\message.obj \
+ $(OBJDIR)\misc1.obj \
+ $(OBJDIR)\misc2.obj \
+ $(OBJDIR)\move.obj \
+ $(OBJDIR)\mbyte.obj \
+ $(OBJDIR)\normal.obj \
+ $(OBJDIR)\ops.obj \
+ $(OBJDIR)\option.obj \
+ $(OBJDIR)\popupmnu.obj \
+ $(OBJDIR)\quickfix.obj \
+ $(OBJDIR)\regexp.obj \
+ $(OBJDIR)\screen.obj \
+ $(OBJDIR)\search.obj \
+ $(OBJDIR)\sha256.obj \
+ $(OBJDIR)\sign.obj \
+ $(OBJDIR)\spell.obj \
+ $(OBJDIR)\spellfile.obj \
+ $(OBJDIR)\syntax.obj \
+ $(OBJDIR)\tag.obj \
+ $(OBJDIR)\term.obj \
+ $(OBJDIR)\ui.obj \
+ $(OBJDIR)\undo.obj \
+ $(OBJDIR)\userfunc.obj \
+ $(OBJDIR)\version.obj \
+ $(OBJDIR)\window.obj \
+ $(OBJDIR)\pathdef.obj
+
+!if ("$(OLE)"=="yes")
+vimobj = $(vimobj) \
+ $(OBJDIR)\if_ole.obj
+!endif
+
+!ifdef LUA
+vimobj = $(vimobj) \
+ $(OBJDIR)\if_lua.obj
+!endif
+
+!ifdef PERL
+vimobj = $(vimobj) \
+ $(OBJDIR)\if_perl.obj
+!endif
+
+!ifdef PYTHON
+vimobj = $(vimobj) \
+ $(OBJDIR)\if_python.obj
+!endif
+
+!ifdef PYTHON3
+vimobj = $(vimobj) \
+ $(OBJDIR)\if_python3.obj
+!endif
+
+!ifdef RUBY
+vimobj = $(vimobj) \
+ $(OBJDIR)\if_ruby.obj
+!endif
+
+!ifdef TCL
+vimobj = $(vimobj) \
+ $(OBJDIR)\if_tcl.obj
+!endif
+
+!if ("$(CSCOPE)"=="yes")
+vimobj = $(vimobj) \
+ $(OBJDIR)\if_cscope.obj
+!endif
+
+!if ("$(NETBEANS)"=="yes")
+vimobj = $(vimobj) \
+ $(OBJDIR)\netbeans.obj
+!endif
+
+!if ("$(CHANNEL)"=="yes")
+vimobj = $(vimobj) \
+ $(OBJDIR)\channel.obj
+!endif
+
+!ifdef XPM
+vimobj = $(vimobj) \
+ $(OBJDIR)\xpm_w32.obj
+!endif
+
+!if ("$(VIMDLL)"=="yes")
+vimdllobj = $(vimobj)
+!if ("$(DEBUG)"=="yes")
+DLLTARGET = vim32d.dll
+!else
+DLLTARGET = vim32.dll
+!endif
+!else
+DLLTARGET = joebob
+!endif
+
+!if ("$(GUI)"=="yes")
+vimobj = $(vimobj) \
+ $(vimwinmain) \
+ $(OBJDIR)\gui.obj \
+ $(OBJDIR)\gui_beval.obj \
+ $(OBJDIR)\gui_w32.obj
+!endif
+
+vimobj = $(vimobj) \
+ $(OBJDIR)\os_win32.obj $(OBJDIR)\os_mswin.obj $(OBJDIR)\winclip.obj
+# Blab what we are going to do:
+MSG = Compiling $(OSTYPE) $(TARGET) $(OLETARGET), with:
+!if ("$(GUI)"=="yes")
+MSG = $(MSG) GUI
+!endif
+!if ("$(OLE)"=="yes")
+MSG = $(MSG) OLE
+!endif
+!if ("$(USEDLL)"=="yes")
+MSG = $(MSG) USEDLL
+!endif
+!if ("$(VIMDLL)"=="yes")
+MSG = $(MSG) VIMDLL
+!endif
+!if ("$(FASTCALL)"=="yes")
+MSG = $(MSG) FASTCALL
+!endif
+!if ("$(IME)"=="yes")
+MSG = $(MSG) IME
+! if "$(DYNAMIC_IME)" == "yes"
+MSG = $(MSG)(dynamic)
+! endif
+!endif
+!if ("$(GETTEXT)"=="yes")
+MSG = $(MSG) GETTEXT
+!endif
+!if ("$(ICONV)"=="yes")
+MSG = $(MSG) ICONV
+!endif
+!if ("$(DEBUG)"=="yes")
+MSG = $(MSG) DEBUG
+!endif
+!if ("$(CODEGUARD)"=="yes")
+MSG = $(MSG) CODEGUARD
+!endif
+!if ("$(CSCOPE)"=="yes")
+MSG = $(MSG) CSCOPE
+!endif
+!if ("$(NETBEANS)"=="yes")
+MSG = $(MSG) NETBEANS
+!endif
+!if ("$(CHANNEL)"=="yes")
+MSG = $(MSG) CHANNEL
+!endif
+!ifdef XPM
+MSG = $(MSG) XPM
+!endif
+!ifdef LUA
+MSG = $(MSG) LUA
+! if "$(DYNAMIC_LUA)" == "yes"
+MSG = $(MSG)(dynamic)
+! endif
+!endif
+!ifdef PERL
+MSG = $(MSG) PERL
+! if "$(DYNAMIC_PERL)" == "yes"
+MSG = $(MSG)(dynamic)
+! endif
+!endif
+!ifdef PYTHON
+MSG = $(MSG) PYTHON
+! if "$(DYNAMIC_PYTHON)" == "yes"
+MSG = $(MSG)(dynamic)
+! endif
+!endif
+!ifdef PYTHON3
+MSG = $(MSG) PYTHON3
+! if "$(DYNAMIC_PYTHON3)" == "yes"
+MSG = $(MSG)(dynamic)
+! endif
+!endif
+!ifdef RUBY
+MSG = $(MSG) RUBY
+! if "$(DYNAMIC_RUBY)" == "yes"
+MSG = $(MSG)(dynamic)
+! endif
+!endif
+!ifdef TCL
+MSG = $(MSG) TCL
+! if "$(DYNAMIC_TCL)" == "yes"
+MSG = $(MSG)(dynamic)
+! endif
+!endif
+MSG = $(MSG) cpu=$(CPUARG)
+MSG = $(MSG) Align=$(ALIGNARG)
+
+!message $(MSG)
+
+!if ("$(VIMDLL)"=="yes")
+TARGETS = $(DLLTARGET)
+!endif
+TARGETS = $(TARGETS) $(TARGET)
+
+# Targets:
+all: vim vimrun.exe install.exe xxd uninstal.exe GvimExt/gvimext.dll
+
+vim: $(OSTYPE) $(OBJDIR) $(OBJDIR)\bcc.cfg $(TARGETS)
+ @if exist $(OBJDIR)\version.obj del $(OBJDIR)\version.obj
+ @if exist auto\pathdef.c del auto\pathdef.c
+
+$(OSTYPE):
+ -@md $(OSTYPE)
+
+$(OBJDIR):
+ -@md $(OBJDIR)
+
+xxd:
+ @cd xxd
+ $(MAKE) /f Make_bc5.mak BOR="$(BOR)" BCC="$(CC)"
+ @cd ..
+
+GvimExt/gvimext.dll: GvimExt/gvimext.cpp GvimExt/gvimext.rc GvimExt/gvimext.h
+ cd GvimExt
+ $(MAKE) /f Make_bc5.mak USEDLL=$(USEDLL) BOR=$(BOR)
+ cd ..
+
+install.exe: dosinst.c $(OBJDIR)\bcc.cfg
+ $(CC) $(CCARG) -WC -DWIN32 -einstall dosinst.c
+
+uninstal.exe: uninstal.c $(OBJDIR)\bcc.cfg
+ $(CC) $(CCARG) -WC -DWIN32 -O2 -euninstal uninstal.c
+
+clean:
+!if "$(OS)" == "Windows_NT"
+ # For Windows NT/2000, doesn't work on Windows 95/98...
+ # $(COMSPEC) needed to ensure rmdir.exe is not run
+ -@$(COMSPEC) /C rmdir /Q /S $(OBJDIR)
+!else
+ # For Windows 95/98, doesn't work on Windows NT/2000...
+ -@deltree /y $(OBJDIR)
+!endif
+ -@del *.res
+ -@del vim32*.dll
+ -@del vim32*.lib
+ -@del *vim*.exe
+ -@del *install*.exe
+ -@del *.csm
+ -@del *.map
+ -@del *.ilc
+ -@del *.ild
+ -@del *.ilf
+ -@del *.ils
+ -@del *.tds
+!ifdef LUA
+ -@del lua.lib
+!endif
+!ifdef PERL
+ -@del perl.lib
+ -@del if_perl.c
+ -@del auto\if_perl.c
+!endif
+!ifdef PYTHON
+ -@del python.lib
+!endif
+!ifdef PYTHON3
+ -@del python3.lib
+!endif
+!ifdef RUBY
+ -@del ruby.lib
+!endif
+!ifdef TCL
+ -@del tcl.lib
+!endif
+!ifdef XPM
+ -@del xpm.lib
+!endif
+ cd xxd
+ $(MAKE) /f Make_bc5.mak BOR="$(BOR)" clean
+ cd ..
+ cd GvimExt
+ $(MAKE) /f Make_bc5.mak BOR="$(BOR)" clean
+ cd ..
+
+$(DLLTARGET): $(OBJDIR) $(vimdllobj)
+ $(LINK) @&&|
+ $(LFLAGSDLL) +
+ c0d32.obj +
+ $(vimdllobj)
+ $<,$*
+!if ("$(CODEGUARD)"=="yes")
+ cg32.lib+
+!endif
+# $(OSTYPE)==WIN32 causes os_mswin.c compilation. FEAT_SHORTCUT in it needs OLE
+ ole2w32.lib +
+ import32.lib+
+!ifdef LUA
+ $(LUA_LIB_FLAG)lua.lib+
+!endif
+!ifdef PERL
+ $(PERL_LIB_FLAG)perl.lib+
+!endif
+!ifdef PYTHON
+ $(PYTHON_LIB_FLAG)python.lib+
+!endif
+!ifdef PYTHON3
+ $(PYTHON3_LIB_FLAG)python3.lib+
+!endif
+!ifdef RUBY
+ $(RUBY_LIB_FLAG)ruby.lib+
+!endif
+!ifdef TCL
+ $(TCL_LIB_FLAG)tcl.lib+
+!endif
+!ifdef XPM
+ xpm.lib+
+!endif
+!if ("$(USEDLL)"=="yes")
+ cw32i.lib
+!else
+ cw32.lib
+!endif
+ vim.def
+|
+
+!if ("$(VIMDLL)"=="yes")
+$(TARGET): $(OBJDIR) $(DLLTARGET) $(vimmain) $(OBJDIR)\$(RESFILE)
+!else
+$(TARGET): $(OBJDIR) $(vimobj) $(OBJDIR)\$(RESFILE)
+!endif
+ $(LINK) @&&|
+ $(LFLAGS) +
+ $(STARTUPOBJ) +
+!if ("$(VIMDLL)"=="yes")
+ $(vimmain)
+!else
+ $(vimobj)
+!endif
+ $<,$*
+!if ("$(CODEGUARD)"=="yes")
+ cg32.lib+
+!endif
+# $(OSTYPE)==WIN32 causes os_mswin.c compilation. FEAT_SHORTCUT in it needs OLE
+ ole2w32.lib +
+ import32.lib+
+!ifdef LUA
+ $(LUA_LIB_FLAG)lua.lib+
+!endif
+!ifdef PERL
+ $(PERL_LIB_FLAG)perl.lib+
+!endif
+!ifdef PYTHON
+ $(PYTHON_LIB_FLAG)python.lib+
+!endif
+!ifdef PYTHON3
+ $(PYTHON3_LIB_FLAG)python3.lib+
+!endif
+!ifdef RUBY
+ $(RUBY_LIB_FLAG)ruby.lib+
+!endif
+!ifdef TCL
+ $(TCL_LIB_FLAG)tcl.lib+
+!endif
+!ifdef XPM
+ xpm.lib+
+!endif
+!if ("$(USEDLL)"=="yes")
+ cw32i.lib
+!else
+ cw32.lib
+!endif
+
+ $(OBJDIR)\$(RESFILE)
+|
+
+test:
+ cd testdir
+ $(MAKE) /NOLOGO -f Make_dos.mak win32
+ cd ..
+
+$(OBJDIR)\ex_docmd.obj: ex_docmd.c ex_cmds.h
+
+$(OBJDIR)\ex_eval.obj: ex_eval.c ex_cmds.h
+
+$(OBJDIR)\if_ole.obj: if_ole.cpp
+
+$(OBJDIR)\if_lua.obj: if_lua.c lua.lib
+ $(CC) $(CCARG) $(CC1) $(CC2)$@ -pc if_lua.c
+
+$(OBJDIR)\if_perl.obj: auto/if_perl.c perl.lib
+ $(CC) $(CCARG) $(CC1) $(CC2)$@ -pc auto/if_perl.c
+
+auto/if_perl.c: if_perl.xs typemap
+ $(PERL)\bin\perl.exe $(PERL)\lib\ExtUtils\xsubpp -prototypes -typemap \
+ $(PERL)\lib\ExtUtils\typemap if_perl.xs -output $@
+
+$(OBJDIR)\if_python.obj: if_python.c if_py_both.h python.lib
+ $(CC) -I$(PYTHON)\include $(CCARG) $(CC1) $(CC2)$@ -pc if_python.c
+
+$(OBJDIR)\if_python3.obj: if_python3.c if_py_both.h python3.lib
+ $(CC) -I$(PYTHON3)\include $(CCARG) $(CC1) $(CC2)$@ -pc if_python3.c
+
+$(OBJDIR)\if_ruby.obj: if_ruby.c ruby.lib
+ $(CC) $(CCARG) $(CC1) $(CC2)$@ -pc if_ruby.c
+
+$(OBJDIR)\if_tcl.obj: if_tcl.c tcl.lib
+ $(CC) $(CCARG) $(CC1) $(CC2)$@ -pc if_tcl.c
+
+$(OBJDIR)\xpm_w32.obj: xpm_w32.c xpm.lib
+ $(CC) $(CCARG) $(CC1) $(CC2)$@ -pc xpm_w32.c
+
+$(OBJDIR)\netbeans.obj: netbeans.c $(NBDEBUG_DEP)
+ $(CC) $(CCARG) $(CC1) $(CC2)$@ netbeans.c
+
+$(OBJDIR)\channel.obj: channel.c
+ $(CC) $(CCARG) $(CC1) $(CC2)$@ channel.c
+
+$(OBJDIR)\vim.res: vim.rc version.h tools.bmp tearoff.bmp \
+ vim.ico vim_error.ico vim_alert.ico vim_info.ico vim_quest.ico
+ $(BRC) -fo$(OBJDIR)\vim.res -i $(BOR)\include -w32 -r vim.rc @&&|
+ $(DEFINES)
+|
+
+$(OBJDIR)\pathdef.obj: auto\pathdef.c
+ $(CC) $(CCARG) $(CC1) $(CC2)$@ auto\pathdef.c
+
+
+# Need to escape both quotes and backslashes in $INTERP_DEFINES
+INTERP_DEFINES_ESC_BKS=$(INTERP_DEFINES:\=\\)
+INTERP_DEFINES_ESC=$(INTERP_DEFINES_ESC_BKS:"=\")
+
+# Note: the silly /*"*/ below are there to trick make into accepting
+# the # character as something other than a comment without messing up
+# the preprocessor directive.
+auto\pathdef.c::
+ -@md auto
+ @echo creating auto/pathdef.c
+ @copy /y &&|
+/* pathdef.c */
+/*"*/#include "vim.h"/*"*/
+
+char_u *default_vim_dir = (char_u *)"$(VIMRCLOC:\=\\)";
+char_u *default_vimruntime_dir = (char_u *)"$(VIMRUNTIMEDIR:\=\\)";
+char_u *all_cflags = (char_u *)"$(CC:\=\\) $(CFLAGS:\=\\) $(DEFINES) $(MBDEFINES) $(INTERP_DEFINES_ESC) $(OPT) $(EXETYPE) $(CPUARG) $(ALIGNARG) $(DEBUG_FLAG) $(CODEGUARD_FLAG)";
+char_u *all_lflags = (char_u *)"$(LINK:\=\\) $(LFLAGS:\=\\)";
+char_u *compiled_user = (char_u *)"$(USERNAME)";
+char_u *compiled_sys = (char_u *)"$(USERDOMAIN)";
+| auto\pathdef.c
+
+lua.lib: $(LUA)\lib\lua$(LUA_VER).lib
+ coff2omf $(LUA)\lib\lua$(LUA_VER).lib $@
+
+perl.lib: $(PERL)\lib\CORE\perl$(PERL_VER).lib
+ coff2omf $(PERL)\lib\CORE\perl$(PERL_VER).lib $@
+
+python.lib: $(PYTHON)\libs\python$(PYTHON_VER).lib
+ coff2omf $(PYTHON)\libs\python$(PYTHON_VER).lib $@
+
+python3.lib: $(PYTHON3)\libs\python$(PYTHON3_VER).lib
+ coff2omf $(PYTHON3)\libs\python$(PYTHON3_VER).lib $@
+
+ruby.lib: $(RUBY)\lib\$(RUBY_INSTALL_NAME).lib
+ coff2omf $(RUBY)\lib\$(RUBY_INSTALL_NAME).lib $@
+
+# For some reason, the coff2omf method doesn't work on libXpm.lib, so
+# we have to manually generate an import library straight from the DLL.
+xpm.lib: $(XPM)\lib\libXpm.lib
+ implib -a $@ $(XPM)\bin\libXpm.dll
+
+tcl.lib: $(TCL_LIB)
+!if ("$(DYNAMIC_TCL)" == "yes")
+ copy $(TCL_LIB) $@
+!else
+ coff2omf $(TCL_LIB) $@
+!endif
+
+!if ("$(DYNAMIC_TCL)" == "yes")
+tclstub$(TCL_VER)-bor.lib:
+ -@IF NOT EXIST $@ ECHO You must download tclstub$(TCL_VER)-bor.lib separately and\
+ place it in the src directory in order to compile a dynamic TCL-enabled\
+ (g)vim with the Borland compiler. You can get the tclstub$(TCL_VER)-bor.lib file\
+ at http://mywebpage.netscape.com/sharppeople/vim/tclstub$(TCL_VER)-bor.lib
+!endif
+
+# vimrun.exe:
+vimrun.exe: vimrun.c
+!if ("$(USEDLL)"=="yes")
+ $(CC) -WC -O1 -I$(INCLUDE) -L$(LIB) -D_RTLDLL vimrun.c cw32mti.lib
+!else
+ $(CC) -WC -O1 -I$(INCLUDE) -L$(LIB) vimrun.c
+!endif
+
+# The dependency on $(OBJDIR) is to have bcc.cfg generated each time.
+$(OBJDIR)\bcc.cfg: Make_bc5.mak $(OBJDIR)
+ copy /y &&|
+ $(CFLAGS)
+ -L$(LIB)
+ $(DEFINES)
+ $(MBDEFINES)
+ $(INTERP_DEFINES)
+ $(EXETYPE)
+ $(DEBUG_FLAG)
+ $(OPT)
+ $(CODEGUARD_FLAG)
+ $(CPUARG)
+ $(ALIGNARG)
+| $@
+
+# vi:set sts=4 sw=4:
+
diff --git a/src/Make_cyg.mak b/src/Make_cyg.mak
new file mode 100644
index 0000000..8c1b60e
--- /dev/null
+++ b/src/Make_cyg.mak
@@ -0,0 +1,54 @@
+#
+# Makefile for VIM on Win32, using MinGW cross compiler on Cygwin
+#
+# Also read INSTALLpc.txt!
+#
+# This compiles Vim as a Windows application. If you want Vim to run as a
+# Cygwin application use the Makefile (just like on Unix).
+#
+# The old Make_cyg.mak (maintained by Dan Sharp et al.) was merged into
+# Make_cyg_ming.mak. Note: USEDLL option was removed.
+# This file contains Cygwin specific settings. Common settings are contained
+# in Make_cyg_ming.mak.
+#
+# Last updated by Ken Takata.
+# Last Change: 2014 Oct 21
+
+
+# uncomment 'PERL' if you want a perl-enabled version
+#PERL=/cygdrive/c/perl
+
+# uncomment 'LUA' if you want a Lua-enabled version
+#LUA=/cygdrive/c/lua
+
+# uncomment 'MZSCHEME' if you want a MzScheme-enabled version
+#MZSCHEME=/cygdrive/d/plt
+
+# uncomment 'PYTHON' if you want a python-enabled version
+#PYTHON=/cygdrive/c/python20
+
+# uncomment 'PYTHON3' if you want a python3-enabled version
+#PYTHON3=/cygdrive/c/python31
+
+# uncomment 'TCL' if you want a Tcl-enabled version
+#TCL=/cygdrive/c/tcl
+
+# uncomment 'RUBY' if you want a Ruby-enabled version
+#RUBY=/cygdribe/c/ruby
+
+
+# Use MinGW(-w64) cross compiler.
+# There are three MinGW packages in Cygwin:
+# 32-bit: mingw-gcc-g++ and mingw64-i686-gcc-g++
+# 64-bit: mingw64-x86_64-gcc-g++
+# You may also need to set 'ARCH' in Make_cyg_ming.mak.
+CROSS_COMPILE = i686-pc-mingw32-
+#CROSS_COMPILE = i686-w64-mingw32-
+#CROSS_COMPILE = x86_64-w64-mingw32-
+
+
+# Do not change this.
+UNDER_CYGWIN = yes
+include Make_cyg_ming.mak
+
+# vim: set noet sw=8 ts=8 sts=0 wm=0 tw=0:
diff --git a/src/Make_cyg_ming.mak b/src/Make_cyg_ming.mak
new file mode 100644
index 0000000..1e26add
--- /dev/null
+++ b/src/Make_cyg_ming.mak
@@ -0,0 +1,1165 @@
+# Makefile for VIM on Win32 (Cygwin and MinGW)
+#
+# This file contains common part for Cygwin and MinGW and it is included
+# from Make_cyg.mak and Make_ming.mak.
+#
+# Info at http://www.mingw.org
+# Alternative x86 and 64-builds: http://mingw-w64.sourceforge.net
+# Also requires GNU make, which you can download from the same sites.
+# Get missing libraries from http://gnuwin32.sf.net.
+#
+# Tested on Win32 NT 4 and Win95.
+#
+# To make everything, just 'make -f Make_ming.mak'.
+# To make just e.g. gvim.exe, 'make -f Make_ming.mak gvim.exe'.
+# After a run, you can 'make -f Make_ming.mak clean' to clean up.
+#
+# NOTE: Sometimes 'GNU Make' will stop after building vimrun.exe -- I think
+# it's just run out of memory or something. Run again, and it will continue
+# with 'xxd'.
+#
+# "make upx" makes *compressed* versions of the 32 bit GUI and console EXEs,
+# using the excellent UPX compressor:
+# https://upx.github.io/
+# "make mpress" uses the MPRESS compressor for 32- and 64-bit EXEs:
+# http://www.matcode.com/mpress.htm
+#
+# Maintained by Ron Aaron <ronaharon@yahoo.com> et al.
+# Updated 2014 Oct 13.
+
+#>>>>> choose options:
+# FEATURES=[TINY | SMALL | NORMAL | BIG | HUGE]
+# Set to TINY to make minimal version (few features).
+FEATURES=HUGE
+
+# set to yes for a debug build
+DEBUG=no
+
+# set to yes to create a mapfile
+# MAP=yes
+
+# set to SIZE for size, SPEED for speed, MAXSPEED for maximum optimization
+OPTIMIZE=MAXSPEED
+
+# set to yes to make gvim, no for vim
+GUI=yes
+
+# set to no if you do not want to use DirectWrite (DirectX)
+# MinGW-w64 is needed, and ARCH should be set to i686 or x86-64.
+DIRECTX=yes
+
+# Disable Color emoji support
+# (default is yes if DIRECTX=yes, requires WinSDK 8.1 or later.)
+#COLOR_EMOJI=no
+
+# Set to one of i386, i486, i586, i686 as the minimum target processor.
+# For amd64/x64 architecture set ARCH=x86-64 .
+# If not set, it will be automatically detected. (Normally i686 or x86-64.)
+#ARCH=i686
+# Set to yes to cross-compile from unix; no=native Windows (and Cygwin).
+CROSS=no
+
+# Set to path to iconv.h and libiconv.a to enable using 'iconv.dll'.
+# Use "yes" when the path does not need to be define.
+#ICONV="."
+ICONV=yes
+GETTEXT=yes
+
+# Set to yes to include IME support.
+IME=yes
+DYNAMIC_IME=yes
+
+# Set to yes to enable writing a postscript file with :hardcopy.
+POSTSCRIPT=no
+
+# Set to yes to enable OLE support.
+OLE=no
+
+# Set the default $(WINVER). Use 0x0501 to make it work with WinXP.
+ifndef WINVER
+# WINVER = 0x0501
+WINVER = 0x0600
+endif
+
+# Set to yes to enable Cscope support.
+CSCOPE=yes
+
+# Set to yes to enable Netbeans support (requires CHANNEL).
+NETBEANS=$(GUI)
+
+# Set to yes to enable inter process communication.
+ifeq (HUGE, $(FEATURES))
+CHANNEL=yes
+else
+CHANNEL=$(GUI)
+endif
+
+# Set to yes to enable terminal support.
+ifeq (HUGE, $(FEATURES))
+TERMINAL=yes
+else
+TERMINAL=no
+endif
+
+ifndef CTAGS
+# this assumes ctags is Exuberant ctags
+CTAGS = ctags -I INIT+ --fields=+S
+endif
+
+# Link against the shared version of libstdc++ by default. Set
+# STATIC_STDCPLUS to "yes" to link against static version instead.
+ifndef STATIC_STDCPLUS
+STATIC_STDCPLUS=no
+endif
+
+
+# Link against the shared version of libwinpthread by default. Set
+# STATIC_WINPTHREAD to "yes" to link against static version instead.
+ifndef STATIC_WINPTHREAD
+STATIC_WINPTHREAD=$(STATIC_STDCPLUS)
+endif
+# If you use TDM-GCC(-64), change HAS_GCC_EH to "no".
+# This is used when STATIC_STDCPLUS=yes.
+HAS_GCC_EH=yes
+
+# If the user doesn't want gettext, undefine it.
+ifeq (no, $(GETTEXT))
+GETTEXT=
+endif
+# Added by E.F. Amatria <eferna1@platea.ptic.mec.es> 2001 Feb 23
+# Uncomment the first line and one of the following three if you want Native Language
+# Support. You'll need gnu_gettext.win32, a MINGW32 Windows PORT of gettext by
+# Franco Bez <franco.bez@gmx.de>. It may be found at
+# http://home.a-city.de/franco.bez/gettext/gettext_win32_en.html
+# Tested with mingw32 with GCC-2.95.2 on Win98
+# Updated 2001 Jun 9
+#GETTEXT=c:/gettext.win32.msvcrt
+#STATIC_GETTEXT=USE_STATIC_GETTEXT
+#DYNAMIC_GETTEXT=USE_GETTEXT_DLL
+#DYNAMIC_GETTEXT=USE_SAFE_GETTEXT_DLL
+SAFE_GETTEXT_DLL_OBJ = $(GETTEXT)/src/safe_gettext_dll/safe_gettext_dll.o
+# Alternatively, if you uncomment the two following lines, you get a "safe" version
+# without linking the safe_gettext_dll.o object file.
+#DYNAMIC_GETTEXT=DYNAMIC_GETTEXT
+#GETTEXT_DYNAMIC=gnu_gettext.dll
+INTLPATH=$(GETTEXT)/lib/mingw32
+INTLLIB=gnu_gettext
+
+# If you are using gettext-0.10.35 from http://sourceforge.net/projects/gettext
+# or gettext-0.10.37 from http://sourceforge.net/projects/mingwrep/
+# uncomment the following, but I can't build a static version with them, ?-(|
+#GETTEXT=c:/gettext-0.10.37-20010430
+#STATIC_GETTEXT=USE_STATIC_GETTEXT
+#DYNAMIC_GETTEXT=DYNAMIC_GETTEXT
+#INTLPATH=$(GETTEXT)/lib
+#INTLLIB=intl
+
+
+# Command definitions (depends on cross-compiling and shell)
+ifeq ($(CROSS),yes)
+# cross-compiler prefix:
+ifndef CROSS_COMPILE
+CROSS_COMPILE = i586-pc-mingw32msvc-
+endif
+DEL = rm
+MKDIR = mkdir -p
+DIRSLASH = /
+else
+# normal (Windows) compilation:
+ifndef CROSS_COMPILE
+CROSS_COMPILE =
+endif
+
+# About the "sh.exe" condition, as explained by Ken Takata:
+#
+# If the makefile is executed with mingw32-make and sh.exe is not found in
+# $PATH, then $SHELL is set to "sh.exe" (without any path). In this case,
+# unix-like commands might not work and a dos-style path is needed.
+#
+# If the makefile is executed with mingw32-make and sh.exe IS found in $PATH,
+# then $SHELL is set with the actual path of sh.exe (e.g.
+# "C:/msys64/usr/bin/sh.exe"). In this case, unix-like commands can be used.
+#
+# If it is executed by the "make" command from cmd.exe, $SHELL is set to
+# "/bin/sh". If the "make" command is in the $PATH, other unix-like commands
+# might also work.
+#
+# If it is executed by the "make" command from a unix-like shell,
+# $SHELL is set with the unix-style path (e.g. "/bin/bash").
+# In this case, unix-like commands can be used.
+#
+ifneq (sh.exe, $(SHELL))
+DEL = rm
+MKDIR = mkdir -p
+DIRSLASH = /
+else
+DEL = del
+MKDIR = mkdir
+DIRSLASH = \\
+endif
+endif
+CC := $(CROSS_COMPILE)gcc
+CXX := $(CROSS_COMPILE)g++
+ifeq ($(UNDER_CYGWIN),yes)
+WINDRES := $(CROSS_COMPILE)windres
+else
+WINDRES := windres
+endif
+WINDRES_CC = $(CC)
+
+# Get the default ARCH.
+ifndef ARCH
+ARCH := $(shell $(CC) -dumpmachine | sed -e 's/-.*//' -e 's/_/-/' -e 's/^mingw32$$/i686/')
+endif
+
+
+# Perl interface:
+# PERL=[Path to Perl directory] (Set inside Make_cyg.mak or Make_ming.mak)
+# DYNAMIC_PERL=yes (to load the Perl DLL dynamically)
+# PERL_VER=[Perl version, eg 56, 58, 510] (default is 524)
+ifdef PERL
+ifndef PERL_VER
+PERL_VER=524
+endif
+ifndef DYNAMIC_PERL
+DYNAMIC_PERL=yes
+endif
+# on Linux, for cross-compile, it's here:
+#PERLLIB=/home/ron/ActivePerl/lib
+# on NT, it's here:
+PERLEXE=$(PERL)/bin/perl
+PERLLIB=$(PERL)/lib
+PERLLIBS=$(PERLLIB)/Core
+ifeq ($(UNDER_CYGWIN),yes)
+PERLTYPEMAP:=$(shell cygpath -m $(PERLLIB)/ExtUtils/typemap)
+XSUBPPTRY:=$(shell cygpath -m $(PERLLIB)/ExtUtils/xsubpp)
+else
+PERLTYPEMAP=$(PERLLIB)/ExtUtils/typemap
+XSUBPPTRY=$(PERLLIB)/ExtUtils/xsubpp
+endif
+XSUBPP_EXISTS=$(shell $(PERLEXE) -e "print 1 unless -e '$(XSUBPPTRY)'")
+ifeq "$(XSUBPP_EXISTS)" ""
+XSUBPP=$(PERLEXE) $(XSUBPPTRY)
+else
+XSUBPP=xsubpp
+endif
+endif
+
+# Lua interface:
+# LUA=[Path to Lua directory] (Set inside Make_cyg.mak or Make_ming.mak)
+# LUA_LIBDIR=[Path to Lua library directory] (default: $LUA/lib)
+# LUA_INCDIR=[Path to Lua include directory] (default: $LUA/include)
+# DYNAMIC_LUA=yes (to load the Lua DLL dynamically)
+# LUA_VER=[Lua version, eg 51, 52] (default is 53)
+ifdef LUA
+ifndef DYNAMIC_LUA
+DYNAMIC_LUA=yes
+endif
+
+ifndef LUA_VER
+LUA_VER=53
+endif
+
+ifeq (no,$(DYNAMIC_LUA))
+LUA_LIBDIR = $(LUA)/lib
+LUA_LIB = -L$(LUA_LIBDIR) -llua
+endif
+
+endif
+
+# MzScheme interface:
+# MZSCHEME=[Path to MzScheme directory] (Set inside Make_cyg.mak or Make_ming.mak)
+# DYNAMIC_MZSCHEME=yes (to load the MzScheme DLL dynamically)
+# MZSCHEME_VER=[MzScheme version] (default is 3m_a0solc (6.6))
+# Used for the DLL file name. E.g.:
+# C:\Program Files (x86)\Racket\lib\libracket3m_XXXXXX.dll
+# MZSCHEME_DEBUG=no
+ifdef MZSCHEME
+ifndef DYNAMIC_MZSCHEME
+DYNAMIC_MZSCHEME=yes
+endif
+
+ifndef MZSCHEME_VER
+MZSCHEME_VER=3m_a0solc
+endif
+
+# for version 4.x we need to generate byte-code for Scheme base
+ifndef MZSCHEME_GENERATE_BASE
+MZSCHEME_GENERATE_BASE=no
+endif
+
+ifneq ($(wildcard $(MZSCHEME)/lib/msvc/libmzsch$(MZSCHEME_VER).lib),)
+MZSCHEME_MAIN_LIB=mzsch
+else
+MZSCHEME_MAIN_LIB=racket
+endif
+
+ifndef MZSCHEME_PRECISE_GC
+MZSCHEME_PRECISE_GC=no
+ifneq ($(wildcard $(MZSCHEME)\lib\lib$(MZSCHEME_MAIN_LIB)$(MZSCHEME_VER).dll),)
+ifeq ($(wildcard $(MZSCHEME)\lib\libmzgc$(MZSCHEME_VER).dll),)
+MZSCHEME_PRECISE_GC=yes
+endif
+else
+ifneq ($(wildcard $(MZSCHEME)\lib\msvc\lib$(MZSCHEME_MAIN_LIB)$(MZSCHEME_VER).lib),)
+ifeq ($(wildcard $(MZSCHEME)\lib\msvc\libmzgc$(MZSCHEME_VER).lib),)
+MZSCHEME_PRECISE_GC=yes
+endif
+endif
+endif
+endif
+
+ifeq (no,$(DYNAMIC_MZSCHEME))
+ifeq (yes,$(MZSCHEME_PRECISE_GC))
+MZSCHEME_LIB=-l$(MZSCHEME_MAIN_LIB)$(MZSCHEME_VER)
+else
+MZSCHEME_LIB=-l$(MZSCHEME_MAIN_LIB)$(MZSCHEME_VER) -lmzgc$(MZSCHEME_VER)
+endif
+# the modern MinGW can dynamically link to dlls directly.
+# point MZSCHEME_DLLS to where you put libmzschXXXXXXX.dll and libgcXXXXXXX.dll
+ifndef MZSCHEME_DLLS
+MZSCHEME_DLLS=$(MZSCHEME)
+endif
+MZSCHEME_LIBDIR=-L$(MZSCHEME_DLLS) -L$(MZSCHEME_DLLS)\lib
+endif
+
+endif
+
+# Python interface:
+# PYTHON=[Path to Python directory] (Set inside Make_cyg.mak or Make_ming.mak)
+# DYNAMIC_PYTHON=yes (to load the Python DLL dynamically)
+# PYTHON_VER=[Python version, eg 22, 23, ..., 27] (default is 27)
+ifdef PYTHON
+ifndef DYNAMIC_PYTHON
+DYNAMIC_PYTHON=yes
+endif
+
+ifndef PYTHON_VER
+PYTHON_VER=27
+endif
+ifndef DYNAMIC_PYTHON_DLL
+DYNAMIC_PYTHON_DLL=python$(PYTHON_VER).dll
+endif
+ifdef PYTHON_HOME
+PYTHON_HOME_DEF=-DPYTHON_HOME=\"$(PYTHON_HOME)\"
+endif
+
+ifeq (no,$(DYNAMIC_PYTHON))
+PYTHONLIB=-L$(PYTHON)/libs -lpython$(PYTHON_VER)
+endif
+# my include files are in 'win32inc' on Linux, and 'include' in the standard
+# NT distro (ActiveState)
+ifndef PYTHONINC
+ifeq ($(CROSS),no)
+PYTHONINC=-I $(PYTHON)/include
+else
+PYTHONINC=-I $(PYTHON)/win32inc
+endif
+endif
+endif
+
+# Python3 interface:
+# PYTHON3=[Path to Python3 directory] (Set inside Make_cyg.mak or Make_ming.mak)
+# DYNAMIC_PYTHON3=yes (to load the Python3 DLL dynamically)
+# PYTHON3_VER=[Python3 version, eg 31, 32] (default is 36)
+ifdef PYTHON3
+ifndef DYNAMIC_PYTHON3
+DYNAMIC_PYTHON3=yes
+endif
+
+ifndef PYTHON3_VER
+PYTHON3_VER=36
+endif
+ifndef DYNAMIC_PYTHON3_DLL
+DYNAMIC_PYTHON3_DLL=python$(PYTHON3_VER).dll
+endif
+ifdef PYTHON3_HOME
+PYTHON3_HOME_DEF=-DPYTHON3_HOME=L\"$(PYTHON3_HOME)\"
+endif
+
+ifeq (no,$(DYNAMIC_PYTHON3))
+PYTHON3LIB=-L$(PYTHON3)/libs -lpython$(PYTHON3_VER)
+endif
+
+ifndef PYTHON3INC
+ifeq ($(CROSS),no)
+PYTHON3INC=-I $(PYTHON3)/include
+else
+PYTHON3INC=-I $(PYTHON3)/win32inc
+endif
+endif
+endif
+
+# TCL interface:
+# TCL=[Path to TCL directory] (Set inside Make_cyg.mak or Make_ming.mak)
+# DYNAMIC_TCL=yes (to load the TCL DLL dynamically)
+# TCL_VER=[TCL version, eg 83, 84] (default is 86)
+# TCL_VER_LONG=[Tcl version, eg 8.3] (default is 8.6)
+# You must set TCL_VER_LONG when you set TCL_VER.
+# TCL_DLL=[TCL dll name, eg tcl86.dll] (default is tcl86.dll)
+ifdef TCL
+ifndef DYNAMIC_TCL
+DYNAMIC_TCL=yes
+endif
+ifndef TCL_VER
+TCL_VER = 86
+endif
+ifndef TCL_VER_LONG
+TCL_VER_LONG = 8.6
+endif
+ifndef TCL_DLL
+TCL_DLL = tcl$(TCL_VER).dll
+endif
+TCLINC += -I$(TCL)/include
+endif
+
+
+# Ruby interface:
+# RUBY=[Path to Ruby directory] (Set inside Make_cyg.mak or Make_ming.mak)
+# DYNAMIC_RUBY=yes (to load the Ruby DLL dynamically, "no" for static)
+# RUBY_VER=[Ruby version, eg 19, 22] (default is 22)
+# RUBY_API_VER_LONG=[Ruby API version, eg 1.8, 1.9.1, 2.2.0]
+# (default is 2.2.0)
+# You must set RUBY_API_VER_LONG when changing RUBY_VER.
+# Note: If you use Ruby 1.9.3, set as follows:
+# RUBY_VER=19
+# RUBY_API_VER_LONG=1.9.1 (not 1.9.3, because the API version is 1.9.1.)
+ifdef RUBY
+ifndef DYNAMIC_RUBY
+DYNAMIC_RUBY=yes
+endif
+# Set default value
+ifndef RUBY_VER
+RUBY_VER = 22
+endif
+ifndef RUBY_VER_LONG
+RUBY_VER_LONG = 2.2.0
+endif
+ifndef RUBY_API_VER_LONG
+RUBY_API_VER_LONG = $(RUBY_VER_LONG)
+endif
+ifndef RUBY_API_VER
+RUBY_API_VER = $(subst .,,$(RUBY_API_VER_LONG))
+endif
+
+ifndef RUBY_PLATFORM
+ifeq ($(RUBY_VER), 16)
+RUBY_PLATFORM = i586-mswin32
+else
+ifneq ($(wildcard $(RUBY)/lib/ruby/$(RUBY_API_VER_LONG)/i386-mingw32),)
+RUBY_PLATFORM = i386-mingw32
+else
+ifneq ($(wildcard $(RUBY)/lib/ruby/$(RUBY_API_VER_LONG)/x64-mingw32),)
+RUBY_PLATFORM = x64-mingw32
+else
+RUBY_PLATFORM = i386-mswin32
+endif
+endif
+endif
+endif
+
+ifndef RUBY_INSTALL_NAME
+ifeq ($(RUBY_VER), 16)
+RUBY_INSTALL_NAME = mswin32-ruby$(RUBY_API_VER)
+else
+ifndef RUBY_MSVCRT_NAME
+# Base name of msvcrXX.dll which is used by ruby's dll.
+RUBY_MSVCRT_NAME = msvcrt
+endif
+ifeq ($(ARCH),x86-64)
+RUBY_INSTALL_NAME = x64-$(RUBY_MSVCRT_NAME)-ruby$(RUBY_API_VER)
+else
+RUBY_INSTALL_NAME = $(RUBY_MSVCRT_NAME)-ruby$(RUBY_API_VER)
+endif
+endif
+endif
+
+ifeq (19, $(word 1,$(sort 19 $(RUBY_VER))))
+RUBY_19_OR_LATER = 1
+endif
+
+ifdef RUBY_19_OR_LATER
+RUBYINC = -I $(RUBY)/include/ruby-$(RUBY_API_VER_LONG) -I $(RUBY)/include/ruby-$(RUBY_API_VER_LONG)/$(RUBY_PLATFORM)
+else
+RUBYINC = -I $(RUBY)/lib/ruby/$(RUBY_API_VER_LONG)/$(RUBY_PLATFORM)
+endif
+ifeq (no, $(DYNAMIC_RUBY))
+RUBYLIB = -L$(RUBY)/lib -l$(RUBY_INSTALL_NAME)
+endif
+
+endif # RUBY
+
+# See feature.h for a list of options.
+# Any other defines can be included here.
+DEF_GUI=-DFEAT_GUI_W32 -DFEAT_CLIPBOARD
+DEFINES=-DWIN32 -DWINVER=$(WINVER) -D_WIN32_WINNT=$(WINVER) \
+ -DHAVE_PATHDEF -DFEAT_$(FEATURES) -DHAVE_STDINT_H
+ifeq ($(ARCH),x86-64)
+DEFINES+=-DMS_WIN64
+endif
+
+#>>>>> end of choices
+###########################################################################
+
+CFLAGS = -I. -Iproto $(DEFINES) -pipe -march=$(ARCH) -Wall
+CXXFLAGS = -std=gnu++11
+WINDRES_FLAGS = --preprocessor="$(WINDRES_CC) -E -xc" -DRC_INVOKED
+EXTRA_LIBS =
+
+ifdef GETTEXT
+DEFINES += -DHAVE_GETTEXT -DHAVE_LOCALE_H
+GETTEXTINCLUDE = $(GETTEXT)/include
+GETTEXTLIB = $(INTLPATH)
+ifeq (yes, $(GETTEXT))
+DEFINES += -DDYNAMIC_GETTEXT
+else
+ifdef DYNAMIC_GETTEXT
+DEFINES += -D$(DYNAMIC_GETTEXT)
+ifdef GETTEXT_DYNAMIC
+DEFINES += -DGETTEXT_DYNAMIC -DGETTEXT_DLL=\"$(GETTEXT_DYNAMIC)\"
+endif
+endif
+endif
+endif
+
+ifdef PERL
+CFLAGS += -I$(PERLLIBS) -DFEAT_PERL -DPERL_IMPLICIT_CONTEXT -DPERL_IMPLICIT_SYS
+ifeq (yes, $(DYNAMIC_PERL))
+CFLAGS += -DDYNAMIC_PERL -DDYNAMIC_PERL_DLL=\"perl$(PERL_VER).dll\"
+EXTRA_LIBS += -L$(PERLLIBS) -lperl$(PERL_VER)
+endif
+endif
+
+ifdef LUA
+LUA_INCDIR = $(LUA)/include
+CFLAGS += -I$(LUA_INCDIR) -I$(LUA) -DFEAT_LUA
+ifeq (yes, $(DYNAMIC_LUA))
+CFLAGS += -DDYNAMIC_LUA -DDYNAMIC_LUA_DLL=\"lua$(LUA_VER).dll\"
+endif
+endif
+
+ifdef MZSCHEME
+ifndef MZSCHEME_COLLECTS
+MZSCHEME_COLLECTS=$(MZSCHEME)/collects
+ifeq (yes, $(UNDER_CYGWIN))
+MZSCHEME_COLLECTS:=$(shell cygpath -m $(MZSCHEME_COLLECTS) | sed -e 's/ /\\ /g')
+endif
+endif
+CFLAGS += -I$(MZSCHEME)/include -DFEAT_MZSCHEME -DMZSCHEME_COLLECTS=\"$(MZSCHEME_COLLECTS)\"
+ifeq (yes, $(DYNAMIC_MZSCHEME))
+ifeq (yes, $(MZSCHEME_PRECISE_GC))
+# Precise GC does not use separate dll
+CFLAGS += -DDYNAMIC_MZSCHEME -DDYNAMIC_MZSCH_DLL=\"lib$(MZSCHEME_MAIN_LIB)$(MZSCHEME_VER).dll\" -DDYNAMIC_MZGC_DLL=\"lib$(MZSCHEME_MAIN_LIB)$(MZSCHEME_VER).dll\"
+else
+CFLAGS += -DDYNAMIC_MZSCHEME -DDYNAMIC_MZSCH_DLL=\"lib$(MZSCHEME_MAIN_LIB)$(MZSCHEME_VER).dll\" -DDYNAMIC_MZGC_DLL=\"libmzgc$(MZSCHEME_VER).dll\"
+endif
+endif
+ifeq (yes, "$(MZSCHEME_DEBUG)")
+CFLAGS += -DMZSCHEME_FORCE_GC
+endif
+endif
+
+ifdef RUBY
+CFLAGS += -DFEAT_RUBY $(RUBYINC)
+ifeq (yes, $(DYNAMIC_RUBY))
+CFLAGS += -DDYNAMIC_RUBY -DDYNAMIC_RUBY_DLL=\"$(RUBY_INSTALL_NAME).dll\"
+CFLAGS += -DDYNAMIC_RUBY_VER=$(RUBY_VER)
+endif
+ifeq (no, $(DYNAMIC_RUBY))
+CFLAGS += -DRUBY_VERSION=$(RUBY_VER)
+endif
+ifneq ($(findstring w64-mingw32,$(CC)),)
+# A workaround for MinGW-w64
+CFLAGS += -DHAVE_STRUCT_TIMESPEC -DHAVE_STRUCT_TIMEZONE
+endif
+endif
+
+ifdef PYTHON
+CFLAGS += -DFEAT_PYTHON
+ifeq (yes, $(DYNAMIC_PYTHON))
+CFLAGS += -DDYNAMIC_PYTHON -DDYNAMIC_PYTHON_DLL=\"$(DYNAMIC_PYTHON_DLL)\"
+endif
+endif
+
+ifdef PYTHON3
+CFLAGS += -DFEAT_PYTHON3
+ifeq (yes, $(DYNAMIC_PYTHON3))
+CFLAGS += -DDYNAMIC_PYTHON3 -DDYNAMIC_PYTHON3_DLL=\"$(DYNAMIC_PYTHON3_DLL)\"
+endif
+endif
+
+ifdef TCL
+CFLAGS += -DFEAT_TCL $(TCLINC)
+ifeq (yes, $(DYNAMIC_TCL))
+CFLAGS += -DDYNAMIC_TCL -DDYNAMIC_TCL_DLL=\"$(TCL_DLL)\" -DDYNAMIC_TCL_VER=\"$(TCL_VER_LONG)\"
+endif
+endif
+
+ifeq ($(POSTSCRIPT),yes)
+DEFINES += -DMSWINPS
+endif
+
+ifeq (yes, $(OLE))
+DEFINES += -DFEAT_OLE
+endif
+
+ifeq ($(CSCOPE),yes)
+DEFINES += -DFEAT_CSCOPE
+endif
+
+ifeq ($(NETBEANS),yes)
+# Only allow NETBEANS for a GUI build.
+ifeq (yes, $(GUI))
+DEFINES += -DFEAT_NETBEANS_INTG
+
+ifeq ($(NBDEBUG), yes)
+DEFINES += -DNBDEBUG
+NBDEBUG_INCL = nbdebug.h
+NBDEBUG_SRC = nbdebug.c
+endif
+endif
+endif
+
+ifeq ($(CHANNEL),yes)
+DEFINES += -DFEAT_JOB_CHANNEL
+endif
+
+ifeq ($(TERMINAL),yes)
+DEFINES += -DFEAT_TERMINAL
+TERM_DEPS = \
+ libvterm/include/vterm.h \
+ libvterm/include/vterm_keycodes.h \
+ libvterm/src/rect.h \
+ libvterm/src/utf8.h \
+ libvterm/src/vterm_internal.h
+endif
+
+# DirectWrite (DirectX)
+ifeq ($(DIRECTX),yes)
+# Only allow DirectWrite for a GUI build.
+ifeq (yes, $(GUI))
+DEFINES += -DFEAT_DIRECTX -DDYNAMIC_DIRECTX
+ifneq ($(COLOR_EMOJI),no)
+DEFINES += -DFEAT_DIRECTX_COLOR_EMOJI
+endif
+endif
+endif
+
+# Only allow XPM for a GUI build.
+ifeq (yes, $(GUI))
+
+ifndef XPM
+ifeq ($(ARCH),i386)
+XPM = xpm/x86
+endif
+ifeq ($(ARCH),i486)
+XPM = xpm/x86
+endif
+ifeq ($(ARCH),i586)
+XPM = xpm/x86
+endif
+ifeq ($(ARCH),i686)
+XPM = xpm/x86
+endif
+ifeq ($(ARCH),x86-64)
+XPM = xpm/x64
+endif
+endif
+ifdef XPM
+ifneq ($(XPM),no)
+CFLAGS += -DFEAT_XPM_W32 -I $(XPM)/include -I $(XPM)/../include
+endif
+endif
+
+endif
+
+ifeq ($(DEBUG),yes)
+CFLAGS += -g -fstack-check
+DEBUG_SUFFIX=d
+else
+ifeq ($(OPTIMIZE), SIZE)
+CFLAGS += -Os
+else
+ifeq ($(OPTIMIZE), MAXSPEED)
+CFLAGS += -O3
+CFLAGS += -fomit-frame-pointer -freg-struct-return
+else # SPEED
+CFLAGS += -O2
+endif
+endif
+CFLAGS += -s
+endif
+
+LIB = -lkernel32 -luser32 -lgdi32 -ladvapi32 -lcomdlg32 -lcomctl32 -lnetapi32 -lversion
+GUIOBJ = $(OUTDIR)/gui.o $(OUTDIR)/gui_w32.o $(OUTDIR)/gui_beval.o $(OUTDIR)/os_w32exe.o
+CUIOBJ = $(OUTDIR)/iscygpty.o
+OBJ = \
+ $(OUTDIR)/arabic.o \
+ $(OUTDIR)/autocmd.o \
+ $(OUTDIR)/beval.o \
+ $(OUTDIR)/blob.o \
+ $(OUTDIR)/blowfish.o \
+ $(OUTDIR)/buffer.o \
+ $(OUTDIR)/charset.o \
+ $(OUTDIR)/crypt.o \
+ $(OUTDIR)/crypt_zip.o \
+ $(OUTDIR)/dict.o \
+ $(OUTDIR)/diff.o \
+ $(OUTDIR)/digraph.o \
+ $(OUTDIR)/edit.o \
+ $(OUTDIR)/eval.o \
+ $(OUTDIR)/evalfunc.o \
+ $(OUTDIR)/ex_cmds.o \
+ $(OUTDIR)/ex_cmds2.o \
+ $(OUTDIR)/ex_docmd.o \
+ $(OUTDIR)/ex_eval.o \
+ $(OUTDIR)/ex_getln.o \
+ $(OUTDIR)/farsi.o \
+ $(OUTDIR)/fileio.o \
+ $(OUTDIR)/fold.o \
+ $(OUTDIR)/getchar.o \
+ $(OUTDIR)/hardcopy.o \
+ $(OUTDIR)/hashtab.o \
+ $(OUTDIR)/indent.o \
+ $(OUTDIR)/json.o \
+ $(OUTDIR)/list.o \
+ $(OUTDIR)/main.o \
+ $(OUTDIR)/mark.o \
+ $(OUTDIR)/memfile.o \
+ $(OUTDIR)/memline.o \
+ $(OUTDIR)/menu.o \
+ $(OUTDIR)/message.o \
+ $(OUTDIR)/misc1.o \
+ $(OUTDIR)/misc2.o \
+ $(OUTDIR)/move.o \
+ $(OUTDIR)/mbyte.o \
+ $(OUTDIR)/normal.o \
+ $(OUTDIR)/ops.o \
+ $(OUTDIR)/option.o \
+ $(OUTDIR)/os_win32.o \
+ $(OUTDIR)/os_mswin.o \
+ $(OUTDIR)/winclip.o \
+ $(OUTDIR)/pathdef.o \
+ $(OUTDIR)/popupmnu.o \
+ $(OUTDIR)/quickfix.o \
+ $(OUTDIR)/regexp.o \
+ $(OUTDIR)/screen.o \
+ $(OUTDIR)/search.o \
+ $(OUTDIR)/sha256.o \
+ $(OUTDIR)/sign.o \
+ $(OUTDIR)/spell.o \
+ $(OUTDIR)/spellfile.o \
+ $(OUTDIR)/syntax.o \
+ $(OUTDIR)/tag.o \
+ $(OUTDIR)/term.o \
+ $(OUTDIR)/textprop.o \
+ $(OUTDIR)/ui.o \
+ $(OUTDIR)/undo.o \
+ $(OUTDIR)/userfunc.o \
+ $(OUTDIR)/version.o \
+ $(OUTDIR)/vimrc.o \
+ $(OUTDIR)/window.o
+
+ifdef PERL
+OBJ += $(OUTDIR)/if_perl.o
+endif
+ifdef LUA
+OBJ += $(OUTDIR)/if_lua.o
+endif
+ifdef MZSCHEME
+OBJ += $(OUTDIR)/if_mzsch.o
+MZSCHEME_INCL = if_mzsch.h
+ifeq (yes,$(MZSCHEME_GENERATE_BASE))
+CFLAGS += -DINCLUDE_MZSCHEME_BASE
+MZ_EXTRA_DEP += mzscheme_base.c
+endif
+ifeq (yes,$(MZSCHEME_PRECISE_GC))
+CFLAGS += -DMZ_PRECISE_GC
+endif
+endif
+ifdef PYTHON
+OBJ += $(OUTDIR)/if_python.o
+endif
+ifdef PYTHON3
+OBJ += $(OUTDIR)/if_python3.o
+endif
+ifdef RUBY
+OBJ += $(OUTDIR)/if_ruby.o
+endif
+ifdef TCL
+OBJ += $(OUTDIR)/if_tcl.o
+endif
+ifeq ($(CSCOPE),yes)
+OBJ += $(OUTDIR)/if_cscope.o
+endif
+
+ifeq ($(NETBEANS),yes)
+ifneq ($(CHANNEL),yes)
+# Cannot use Netbeans without CHANNEL
+NETBEANS=no
+else
+ifneq (yes, $(GUI))
+# Cannot use Netbeans without GUI.
+NETBEANS=no
+else
+OBJ += $(OUTDIR)/netbeans.o
+endif
+endif
+endif
+
+ifeq ($(CHANNEL),yes)
+OBJ += $(OUTDIR)/channel.o
+LIB += -lwsock32
+endif
+
+ifeq ($(DIRECTX),yes)
+# Only allow DIRECTX for a GUI build.
+ifeq (yes, $(GUI))
+OBJ += $(OUTDIR)/gui_dwrite.o
+LIB += -ld2d1 -ldwrite
+USE_STDCPLUS = yes
+endif
+endif
+ifneq ($(XPM),no)
+# Only allow XPM for a GUI build.
+ifeq (yes, $(GUI))
+OBJ += $(OUTDIR)/xpm_w32.o
+# You'll need libXpm.a from http://gnuwin32.sf.net
+LIB += -L$(XPM)/lib -lXpm
+endif
+endif
+
+ifeq ($(TERMINAL),yes)
+OBJ += $(OUTDIR)/terminal.o \
+ $(OUTDIR)/encoding.o \
+ $(OUTDIR)/keyboard.o \
+ $(OUTDIR)/mouse.o \
+ $(OUTDIR)/parser.o \
+ $(OUTDIR)/pen.o \
+ $(OUTDIR)/termscreen.o \
+ $(OUTDIR)/state.o \
+ $(OUTDIR)/unicode.o \
+ $(OUTDIR)/vterm.o
+endif
+
+# Include xdiff
+OBJ += $(OUTDIR)/xdiffi.o \
+ $(OUTDIR)/xemit.o \
+ $(OUTDIR)/xprepare.o \
+ $(OUTDIR)/xutils.o \
+ $(OUTDIR)/xhistogram.o \
+ $(OUTDIR)/xpatience.o
+
+XDIFF_DEPS = \
+ xdiff/xdiff.h \
+ xdiff/xdiffi.h \
+ xdiff/xemit.h \
+ xdiff/xinclude.h \
+ xdiff/xmacros.h \
+ xdiff/xprepare.h \
+ xdiff/xtypes.h \
+ xdiff/xutils.h
+
+ifdef MZSCHEME
+MZSCHEME_SUFFIX = Z
+endif
+
+ifeq ($(GUI),yes)
+TARGET := gvim$(DEBUG_SUFFIX).exe
+DEFINES += $(DEF_GUI)
+OBJ += $(GUIOBJ)
+LFLAGS += -mwindows
+OUTDIR = gobj$(DEBUG_SUFFIX)$(MZSCHEME_SUFFIX)$(ARCH)
+else
+OBJ += $(CUIOBJ)
+TARGET := vim$(DEBUG_SUFFIX).exe
+OUTDIR = obj$(DEBUG_SUFFIX)$(MZSCHEME_SUFFIX)$(ARCH)
+endif
+
+ifdef GETTEXT
+ifneq (yes, $(GETTEXT))
+CFLAGS += -I$(GETTEXTINCLUDE)
+ifndef STATIC_GETTEXT
+LIB += -L$(GETTEXTLIB) -l$(INTLLIB)
+ifeq (USE_SAFE_GETTEXT_DLL, $(DYNAMIC_GETTEXT))
+OBJ+=$(SAFE_GETTEXT_DLL_OBJ)
+endif
+else
+LIB += -L$(GETTEXTLIB) -lintl
+endif
+endif
+endif
+
+ifdef PERL
+ifeq (no, $(DYNAMIC_PERL))
+LIB += -L$(PERLLIBS) -lperl$(PERL_VER)
+endif
+endif
+
+ifdef TCL
+LIB += -L$(TCL)/lib
+ifeq (yes, $(DYNAMIC_TCL))
+LIB += -ltclstub$(TCL_VER)
+else
+LIB += -ltcl$(TCL_VER)
+endif
+endif
+
+ifeq (yes, $(OLE))
+LIB += -loleaut32
+OBJ += $(OUTDIR)/if_ole.o
+USE_STDCPLUS = yes
+endif
+
+ifeq (yes, $(IME))
+DEFINES += -DFEAT_MBYTE_IME
+ifeq (yes, $(DYNAMIC_IME))
+DEFINES += -DDYNAMIC_IME
+else
+LIB += -limm32
+endif
+endif
+
+ifdef ICONV
+ifneq (yes, $(ICONV))
+LIB += -L$(ICONV)
+CFLAGS += -I$(ICONV)
+endif
+DEFINES+=-DDYNAMIC_ICONV
+endif
+
+ifeq (yes, $(USE_STDCPLUS))
+LINK = $(CXX)
+ifeq (yes, $(STATIC_STDCPLUS))
+#LIB += -static-libstdc++ -static-libgcc
+LIB += -Wl,-Bstatic -lstdc++ -Wl,-Bdynamic
+endif
+else
+LINK = $(CC)
+endif
+
+ifeq (yes, $(STATIC_WINPTHREAD))
+ifeq (yes, $(HAS_GCC_EH))
+LIB += -lgcc_eh
+endif
+LIB += -Wl,-Bstatic -lwinpthread -Wl,-Bdynamic
+endif
+
+ifeq (yes, $(MAP))
+LFLAGS += -Wl,-Map=$(TARGET).map
+endif
+
+all: $(TARGET) vimrun.exe xxd/xxd.exe tee/tee.exe install.exe uninstal.exe GvimExt/gvimext.dll
+
+vimrun.exe: vimrun.c
+ $(CC) $(CFLAGS) -o vimrun.exe vimrun.c $(LIB)
+
+install.exe: dosinst.c
+ $(CC) $(CFLAGS) -o install.exe dosinst.c $(LIB) -lole32 -luuid
+
+uninstal.exe: uninstal.c
+ $(CC) $(CFLAGS) -o uninstal.exe uninstal.c $(LIB)
+
+$(TARGET): $(OUTDIR) $(OBJ)
+ $(LINK) $(CFLAGS) $(LFLAGS) -o $@ $(OBJ) $(LIB) -lole32 -luuid $(LUA_LIB) $(MZSCHEME_LIBDIR) $(MZSCHEME_LIB) $(PYTHONLIB) $(PYTHON3LIB) $(RUBYLIB)
+
+upx: exes
+ upx gvim.exe
+ upx vim.exe
+
+mpress: exes
+ mpress gvim.exe
+ mpress vim.exe
+
+xxd/xxd.exe: xxd/xxd.c
+ $(MAKE) -C xxd -f Make_ming.mak CC='$(CC)'
+
+tee/tee.exe: tee/tee.c
+ $(MAKE) -C tee CC='$(CC)'
+
+GvimExt/gvimext.dll: GvimExt/gvimext.cpp GvimExt/gvimext.rc GvimExt/gvimext.h
+ $(MAKE) -C GvimExt -f Make_ming.mak CROSS=$(CROSS) CROSS_COMPILE=$(CROSS_COMPILE) CXX='$(CXX)' STATIC_STDCPLUS=$(STATIC_STDCPLUS)
+
+tags: notags
+ $(CTAGS) $(TAGS_FILES)
+
+notags:
+ -$(DEL) tags
+
+clean:
+ -$(DEL) $(OUTDIR)$(DIRSLASH)*.o
+ -$(DEL) $(OUTDIR)$(DIRSLASH)*.res
+ -rmdir $(OUTDIR)
+ -$(DEL) $(TARGET) vimrun.exe install.exe uninstal.exe
+ -$(DEL) pathdef.c
+ifdef PERL
+ -$(DEL) if_perl.c
+ -$(DEL) auto$(DIRSLASH)if_perl.c
+endif
+ifdef MZSCHEME
+ -$(DEL) mzscheme_base.c
+endif
+ $(MAKE) -C GvimExt -f Make_ming.mak clean
+ $(MAKE) -C xxd -f Make_ming.mak clean
+ $(MAKE) -C tee clean
+
+###########################################################################
+INCL = vim.h alloc.h arabic.h ascii.h ex_cmds.h farsi.h feature.h globals.h \
+ keymap.h macros.h option.h os_dos.h os_win32.h proto.h regexp.h \
+ spell.h structs.h term.h beval.h $(NBDEBUG_INCL)
+GUI_INCL = gui.h
+CUI_INCL = iscygpty.h
+
+$(OUTDIR)/if_python.o: if_python.c if_py_both.h $(INCL)
+ $(CC) -c $(CFLAGS) $(PYTHONINC) $(PYTHON_HOME_DEF) $< -o $@
+
+$(OUTDIR)/if_python3.o: if_python3.c if_py_both.h $(INCL)
+ $(CC) -c $(CFLAGS) $(PYTHON3INC) $(PYTHON3_HOME_DEF) $< -o $@
+
+$(OUTDIR)/%.o : %.c $(INCL)
+ $(CC) -c $(CFLAGS) $< -o $@
+
+$(OUTDIR)/vimrc.o: vim.rc version.h gui_w32_rc.h
+ $(WINDRES) $(WINDRES_FLAGS) $(DEFINES) \
+ --input-format=rc --output-format=coff -i vim.rc -o $@
+
+$(OUTDIR):
+ $(MKDIR) $(OUTDIR)
+
+$(OUTDIR)/gui_dwrite.o: gui_dwrite.cpp $(INCL) gui_dwrite.h
+ $(CC) -c $(CFLAGS) $(CXXFLAGS) gui_dwrite.cpp -o $(OUTDIR)/gui_dwrite.o
+
+$(OUTDIR)/gui.o: gui.c $(INCL) $(GUI_INCL)
+ $(CC) -c $(CFLAGS) gui.c -o $(OUTDIR)/gui.o
+
+$(OUTDIR)/beval.o: beval.c $(INCL) $(GUI_INCL)
+ $(CC) -c $(CFLAGS) beval.c -o $(OUTDIR)/beval.o
+
+$(OUTDIR)/gui_beval.o: gui_beval.c $(INCL) $(GUI_INCL)
+ $(CC) -c $(CFLAGS) gui_beval.c -o $(OUTDIR)/gui_beval.o
+
+$(OUTDIR)/gui_w32.o: gui_w32.c $(INCL) $(GUI_INCL)
+ $(CC) -c $(CFLAGS) gui_w32.c -o $(OUTDIR)/gui_w32.o
+
+$(OUTDIR)/if_cscope.o: if_cscope.c $(INCL) if_cscope.h
+ $(CC) -c $(CFLAGS) if_cscope.c -o $(OUTDIR)/if_cscope.o
+
+$(OUTDIR)/if_mzsch.o: if_mzsch.c $(INCL) $(MZSCHEME_INCL) $(MZ_EXTRA_DEP)
+ $(CC) -c $(CFLAGS) if_mzsch.c -o $(OUTDIR)/if_mzsch.o
+
+mzscheme_base.c:
+ $(MZSCHEME)/mzc --c-mods mzscheme_base.c ++lib scheme/base
+
+# Remove -D__IID_DEFINED__ for newer versions of the w32api
+$(OUTDIR)/if_ole.o: if_ole.cpp $(INCL) if_ole.h
+ $(CC) $(CFLAGS) $(CXXFLAGS) -c -o $(OUTDIR)/if_ole.o if_ole.cpp
+
+auto/if_perl.c: if_perl.xs typemap
+ $(XSUBPP) -prototypes -typemap \
+ $(PERLTYPEMAP) if_perl.xs -output $@
+
+$(OUTDIR)/if_perl.o: auto/if_perl.c $(INCL)
+ $(CC) -c $(CFLAGS) auto/if_perl.c -o $(OUTDIR)/if_perl.o
+
+
+$(OUTDIR)/if_ruby.o: if_ruby.c $(INCL)
+ifeq (16, $(RUBY))
+ $(CC) $(CFLAGS) -U_WIN32 -c -o $(OUTDIR)/if_ruby.o if_ruby.c
+endif
+
+$(OUTDIR)/iscygpty.o: iscygpty.c $(CUI_INCL)
+ $(CC) -c $(CFLAGS) iscygpty.c -o $(OUTDIR)/iscygpty.o -U_WIN32_WINNT -D_WIN32_WINNT=0x0600 -DUSE_DYNFILEID -DENABLE_STUB_IMPL
+
+$(OUTDIR)/main.o: main.c $(INCL) $(CUI_INCL)
+ $(CC) -c $(CFLAGS) main.c -o $(OUTDIR)/main.o
+
+$(OUTDIR)/netbeans.o: netbeans.c $(INCL) $(NBDEBUG_INCL) $(NBDEBUG_SRC)
+ $(CC) -c $(CFLAGS) netbeans.c -o $(OUTDIR)/netbeans.o
+
+$(OUTDIR)/os_win32.o: os_win32.c $(INCL) $(MZSCHEME_INCL)
+ $(CC) -c $(CFLAGS) os_win32.c -o $(OUTDIR)/os_win32.o
+
+$(OUTDIR)/regexp.o: regexp.c regexp_nfa.c $(INCL)
+ $(CC) -c $(CFLAGS) regexp.c -o $(OUTDIR)/regexp.o
+
+$(OUTDIR)/terminal.o: terminal.c $(INCL) $(TERM_DEPS)
+ $(CC) -c $(CFLAGS) terminal.c -o $(OUTDIR)/terminal.o
+
+$(OUTDIR)/textprop.o: textprop.c $(INCL)
+ $(CC) -c $(CFLAGS) textprop.c -o $(OUTDIR)/textprop.o
+
+
+CCCTERM = $(CC) -c $(CFLAGS) -Ilibvterm/include -DINLINE="" \
+ -DVSNPRINTF=vim_vsnprintf \
+ -DIS_COMBINING_FUNCTION=utf_iscomposing_uint \
+ -DWCWIDTH_FUNCTION=utf_uint2cells
+
+$(OUTDIR)/encoding.o: libvterm/src/encoding.c $(TERM_DEPS)
+ $(CCCTERM) libvterm/src/encoding.c -o $@
+
+$(OUTDIR)/keyboard.o: libvterm/src/keyboard.c $(TERM_DEPS)
+ $(CCCTERM) libvterm/src/keyboard.c -o $@
+
+$(OUTDIR)/mouse.o: libvterm/src/mouse.c $(TERM_DEPS)
+ $(CCCTERM) libvterm/src/mouse.c -o $@
+
+$(OUTDIR)/parser.o: libvterm/src/parser.c $(TERM_DEPS)
+ $(CCCTERM) libvterm/src/parser.c -o $@
+
+$(OUTDIR)/pen.o: libvterm/src/pen.c $(TERM_DEPS)
+ $(CCCTERM) libvterm/src/pen.c -o $@
+
+$(OUTDIR)/termscreen.o: libvterm/src/termscreen.c $(TERM_DEPS)
+ $(CCCTERM) libvterm/src/termscreen.c -o $@
+
+$(OUTDIR)/state.o: libvterm/src/state.c $(TERM_DEPS)
+ $(CCCTERM) libvterm/src/state.c -o $@
+
+$(OUTDIR)/unicode.o: libvterm/src/unicode.c $(TERM_DEPS)
+ $(CCCTERM) libvterm/src/unicode.c -o $@
+
+$(OUTDIR)/vterm.o: libvterm/src/vterm.c $(TERM_DEPS)
+ $(CCCTERM) libvterm/src/vterm.c -o $@
+
+$(OUTDIR)/xdiffi.o: xdiff/xdiffi.c $(XDIFF_DEPS)
+ $(CC) -c $(CFLAGS) xdiff/xdiffi.c -o $(OUTDIR)/xdiffi.o
+
+$(OUTDIR)/xemit.o: xdiff/xemit.c $(XDIFF_DEPS)
+ $(CC) -c $(CFLAGS) xdiff/xemit.c -o $(OUTDIR)/xemit.o
+
+$(OUTDIR)/xprepare.o: xdiff/xprepare.c $(XDIFF_DEPS)
+ $(CC) -c $(CFLAGS) xdiff/xprepare.c -o $(OUTDIR)/xprepare.o
+
+$(OUTDIR)/xutils.o: xdiff/xutils.c $(XDIFF_DEPS)
+ $(CC) -c $(CFLAGS) xdiff/xutils.c -o $(OUTDIR)/xutils.o
+
+$(OUTDIR)/xhistogram.o: xdiff/xhistogram.c $(XDIFF_DEPS)
+ $(CC) -c $(CFLAGS) xdiff/xhistogram.c -o $(OUTDIR)/xhistogram.o
+
+$(OUTDIR)/xpatience.o: xdiff/xpatience.c $(XDIFF_DEPS)
+ $(CC) -c $(CFLAGS) xdiff/xpatience.c -o $(OUTDIR)/xpatience.o
+
+pathdef.c: $(INCL)
+ifneq (sh.exe, $(SHELL))
+ @echo creating pathdef.c
+ @echo '/* pathdef.c */' > pathdef.c
+ @echo '#include "vim.h"' >> pathdef.c
+ @echo 'char_u *default_vim_dir = (char_u *)"$(VIMRCLOC)";' >> pathdef.c
+ @echo 'char_u *default_vimruntime_dir = (char_u *)"$(VIMRUNTIMEDIR)";' >> pathdef.c
+ @echo 'char_u *all_cflags = (char_u *)"$(CC) $(CFLAGS)";' >> pathdef.c
+ @echo 'char_u *all_lflags = (char_u *)"$(LINK) $(CFLAGS) $(LFLAGS) -o $(TARGET) $(LIB) -lole32 -luuid $(LUA_LIB) $(MZSCHEME_LIBDIR) $(MZSCHEME_LIB) $(PYTHONLIB) $(PYTHON3LIB) $(RUBYLIB)";' >> pathdef.c
+ @echo 'char_u *compiled_user = (char_u *)"$(USERNAME)";' >> pathdef.c
+ @echo 'char_u *compiled_sys = (char_u *)"$(USERDOMAIN)";' >> pathdef.c
+else
+ @echo creating pathdef.c
+ @echo /* pathdef.c */ > pathdef.c
+ @echo #include "vim.h" >> pathdef.c
+ @echo char_u *default_vim_dir = (char_u *)"$(VIMRCLOC)"; >> pathdef.c
+ @echo char_u *default_vimruntime_dir = (char_u *)"$(VIMRUNTIMEDIR)"; >> pathdef.c
+ @echo char_u *all_cflags = (char_u *)"$(CC) $(CFLAGS)"; >> pathdef.c
+ @echo char_u *all_lflags = (char_u *)"$(CC) $(CFLAGS) $(LFLAGS) -o $(TARGET) $(LIB) -lole32 -luuid $(LUA_LIB) $(MZSCHEME_LIBDIR) $(MZSCHEME_LIB) $(PYTHONLIB) $(PYTHON3LIB) $(RUBYLIB)"; >> pathdef.c
+ @echo char_u *compiled_user = (char_u *)"$(USERNAME)"; >> pathdef.c
+ @echo char_u *compiled_sys = (char_u *)"$(USERDOMAIN)"; >> pathdef.c
+endif
+
+# vim: set noet sw=8 ts=8 sts=0 wm=0 tw=0:
diff --git a/src/Make_dice.mak b/src/Make_dice.mak
new file mode 100644
index 0000000..57aed47
--- /dev/null
+++ b/src/Make_dice.mak
@@ -0,0 +1,285 @@
+#
+# Makefile for VIM, using DICE 3
+#
+
+#>>>>> choose options:
+### See feature.h for a list of optionals.
+### Any other defines can be included here.
+DEFINES = -DHAVE_TGETENT -DUP_BC_PC_EXTERN -DOSPEED_EXTERN
+
+#>>>>> if HAVE_TGETENT is defined o/termlib.o has to be used
+TERMLIB = o/termlib.o
+#TERMLIB =
+
+#>>>>> end of choices
+###########################################################################
+
+CFLAGS = -c -DAMIGA -Iproto $(DEFINES)
+
+SYMS = vim.syms
+PRE = -H${SYMS}=vim.h
+LIBS = -la
+CC = dcc
+LD = dcc
+
+.c.o:
+ ${CC} ${PRE} ${CFLAGS} $< -o $@
+
+SRC = \
+ arabic.c \
+ autocmd.c \
+ blowfish.c \
+ buffer.c \
+ charset.c \
+ crypt.c \
+ crypt_zip.c \
+ dict.c \
+ diff.c \
+ digraph.c \
+ edit.c \
+ eval.c \
+ evalfunc.c \
+ ex_cmds.c \
+ ex_cmds2.c \
+ ex_docmd.c \
+ ex_eval.c \
+ ex_getln.c \
+ farsi.c \
+ fileio.c \
+ fold.c \
+ getchar.c \
+ hardcopy.c \
+ hashtab.c \
+ indent.c \
+ json.c \
+ list.c \
+ main.c \
+ mark.c \
+ memfile.c \
+ memline.c \
+ menu.c \
+ message.c \
+ misc1.c \
+ misc2.c \
+ move.c \
+ mbyte.c \
+ normal.c \
+ ops.c \
+ option.c \
+ os_amiga.c \
+ popupmnu.c \
+ quickfix.c \
+ regexp.c \
+ screen.c \
+ search.c \
+ sha256.c \
+ sign.c \
+ spell.c \
+ spellfile.c \
+ syntax.c \
+ tag.c \
+ term.c \
+ ui.c \
+ undo.c \
+ userfunc.c \
+ window.c \
+ version.c
+
+OBJ = o/arabic.o \
+ o/autocmd.o \
+ o/blowfish.o \
+ o/buffer.o \
+ o/charset.o \
+ o/crypt.o \
+ o/crypt_zip.o \
+ o/dict.o \
+ o/diff.o \
+ o/digraph.o \
+ o/edit.o \
+ o/eval.o \
+ o/evalfunc.o \
+ o/ex_cmds.o \
+ o/ex_cmds2.o \
+ o/ex_docmd.o \
+ o/ex_eval.o \
+ o/ex_getln.o \
+ o/farsi.o \
+ o/fileio.o \
+ o/fold.o \
+ o/getchar.o \
+ o/hardcopy.o \
+ o/hashtab.o \
+ o/indent.o \
+ o/json.o \
+ o/list.o \
+ o/main.o \
+ o/mark.o \
+ o/memfile.o \
+ o/memline.o \
+ o/menu.o \
+ o/message.o \
+ o/misc1.o \
+ o/misc2.o \
+ o/move.o \
+ o/mbyte.o \
+ o/normal.o \
+ o/ops.o \
+ o/option.o \
+ o/os_amiga.o \
+ o/popupmnu.o \
+ o/quickfix.o \
+ o/regexp.o \
+ o/screen.o \
+ o/search.o \
+ o/sha256.o \
+ o/sign.o \
+ o/spell.o \
+ o/spellfile.o \
+ o/syntax.o \
+ o/tag.o \
+ o/term.o \
+ o/ui.o \
+ o/undo.o \
+ o/userfunc.o \
+ o/window.o \
+ $(TERMLIB)
+
+Vim: $(OBJ) version.c version.h
+ ${CC} $(CFLAGS) version.c -o o/version.o
+ ${LD} -o Vim $(OBJ) o/version.o $(LIBS)
+
+debug: $(OBJ) version.c version.h
+ ${CC} $(CFLAGS) version.c -o o/version.o
+ ${LD} -s -o Vim $(OBJ) o/version.o $(LIBS)
+
+tags:
+ csh -c ctags $(SRC) *.h
+
+clean:
+ delete o/*.o Vim $(SYMS)
+
+$(SYMS) : vim.h globals.h keymap.h macros.h ascii.h term.h os_amiga.h structs.h
+ delete $(SYMS)
+
+###########################################################################
+
+o/arabic.o: arabic.c $(SYMS)
+
+o/autocmd.o: autocmd.c $(SYMS)
+
+o/blowfish.o: blowfish.c $(SYMS)
+
+o/buffer.o: buffer.c $(SYMS)
+
+o/charset.o: charset.c $(SYMS)
+
+o/crypt.o: crypt.c $(SYMS)
+
+o/crypt_zip.o: crypt_zip.c $(SYMS)
+
+o/dict.o: dict.c $(SYMS)
+
+o/diff.o: diff.c $(SYMS)
+
+o/digraph.o: digraph.c $(SYMS)
+
+o/edit.o: edit.c $(SYMS)
+
+o/eval.o: eval.c $(SYMS)
+
+o/evalfunc.o: evalfunc.c $(SYMS)
+
+o/ex_cmds.o: ex_cmds.c $(SYMS)
+
+o/ex_cmds2.o: ex_cmds2.c $(SYMS)
+
+o/ex_docmd.o: ex_docmd.c $(SYMS) ex_cmds.h
+
+o/ex_eval.o: ex_eval.c $(SYMS) ex_cmds.h
+
+o/ex_getln.o: ex_getln.c $(SYMS)
+
+o/farsi.o: farsi.c $(SYMS)
+
+o/fileio.o: fileio.c $(SYMS)
+
+o/fold.o: fold.c $(SYMS)
+
+o/getchar.o: getchar.c $(SYMS)
+
+o/hardcopy.o: hardcopy.c $(SYMS)
+
+o/hashtab.o: hashtab.c $(SYMS)
+
+o/indent.o: indent.c $(SYMS)
+
+o/json.o: json.c $(SYMS)
+
+o/list.o: list.c $(SYMS)
+
+o/main.o: main.c $(SYMS)
+
+o/mark.o: mark.c $(SYMS)
+
+o/memfile.o: memfile.c $(SYMS)
+
+o/memline.o: memline.c $(SYMS)
+
+o/menu.o: menu.c $(SYMS)
+
+o/message.o: message.c $(SYMS)
+
+o/misc1.o: misc1.c $(SYMS)
+
+o/misc2.o: misc2.c $(SYMS)
+
+o/move.o: move.c $(SYMS)
+
+o/mbyte.o: mbyte.c $(SYMS)
+
+o/normal.o: normal.c $(SYMS)
+
+o/ops.o: ops.c $(SYMS)
+
+o/option.o: option.c $(SYMS)
+# Because of a bug in DC1 2.06.40, initialisation of unions does not
+# work correctly. dc1-21 is DC1 2.06.21 which does work.
+# rename dc1-21 dc1
+ ${CC} ${CFLAGS} option.c -o o/option.o
+# rename dc1 dc1-21
+
+o/os_amiga.o: os_amiga.c $(SYMS) os_amiga.h
+
+o/popupmnu.o: popupmnu.c $(SYMS)
+
+o/quickfix.o: quickfix.c $(SYMS)
+
+o/regexp.o: regexp.c $(SYMS) regexp.h
+
+o/screen.o: screen.c $(SYMS)
+
+o/search.o: search.c $(SYMS) regexp.h
+
+o/sha256.o: sha256.c $(SYMS)
+
+o/sign.o: sign.c $(SYMS)
+
+o/spell.o: spell.c $(SYMS) spell.h
+
+o/spellfile.o: spellfile.c $(SYMS) spell.h
+
+o/syntax.o: syntax.c $(SYMS)
+
+o/tag.o: tag.c $(SYMS)
+
+o/term.o: term.c $(SYMS) term.h
+
+o/termlib.o: termlib.c $(SYMS)
+
+o/ui.o: ui.c $(SYMS)
+
+o/undo.o: undo.c $(SYMS)
+
+o/userfunc.o: userfunc.c $(SYMS)
+
+o/window.o: window.c $(SYMS)
diff --git a/src/Make_dvc.mak b/src/Make_dvc.mak
new file mode 100644
index 0000000..46377f0
--- /dev/null
+++ b/src/Make_dvc.mak
@@ -0,0 +1,105 @@
+# Microsoft Developer Studio Generated NMAKE File, Format Version 4.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+!IF "$(CFG)" == ""
+CFG=Vim - Win32 IDE for Make_mvc.mak
+!MESSAGE No configuration specified. Defaulting to Vim - Win32 IDE for\
+ Make_mvc.mak.
+!ENDIF
+
+!IF "$(CFG)" != "Vim - Win32 IDE for Make_mvc.mak"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE on this makefile
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "Make_dvc.mak" CFG="Vim - Win32 IDE for Make_mvc.mak"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "Vim - Win32 IDE for Make_mvc.mak" (based on\
+ "Win32 (x86) Console Application")
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+################################################################################
+# Begin Project
+# PROP Target_Last_Scanned "Vim - Win32 IDE for Make_mvc.mak"
+CPP=cl.exe
+RSC=rc.exe
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir ""
+# PROP Intermediate_Dir ""
+# PROP Target_Dir ""
+OUTDIR=.
+INTDIR=.
+
+ALL : "$(OUTDIR)\vimrun.exe"
+
+CLEAN :
+ -@erase ".\vimrun.exe"
+ -@erase ".\vimrun.obj"
+
+# ADD CPP /nologo /c
+# ADD BASE RSC /l 0x809
+# ADD RSC /l 0x809 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BSC32 /nologo
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/Make_dvc.bsc"
+BSC32_SBRS=
+LINK32=link.exe
+# ADD BASE LINK32 /machine:IX86
+# ADD LINK32 /nologo /pdb:none /machine:IX86 /out:"vimrun.exe"
+LINK32_FLAGS=/nologo /pdb:none /machine:IX86 /out:"$(OUTDIR)/vimrun.exe"
+LINK32_OBJS= \
+ "$(INTDIR)/vimrun.obj"
+
+"$(OUTDIR)\vimrun.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+CPP_PROJ=/nologo /ML /c
+
+.c.obj:
+ $(CPP) $(CPP_PROJ) $<
+
+.cpp.obj:
+ $(CPP) $(CPP_PROJ) $<
+
+.cxx.obj:
+ $(CPP) $(CPP_PROJ) $<
+
+.c.sbr:
+ $(CPP) $(CPP_PROJ) $<
+
+.cpp.sbr:
+ $(CPP) $(CPP_PROJ) $<
+
+.cxx.sbr:
+ $(CPP) $(CPP_PROJ) $<
+
+################################################################################
+# Begin Target
+
+# Name "Vim - Win32 IDE for Make_mvc.mak"
+################################################################################
+# Begin Source File
+
+SOURCE=.\vimrun.c
+
+"$(INTDIR)\vimrun.obj" : $(SOURCE) "$(INTDIR)"
+
+
+# End Source File
+# End Target
+# End Project
+################################################################################
diff --git a/src/Make_ivc.mak b/src/Make_ivc.mak
new file mode 100644
index 0000000..96d6a47
--- /dev/null
+++ b/src/Make_ivc.mak
@@ -0,0 +1,763 @@
+# Microsoft Developer Studio Generated NMAKE File, Format Version 4.00
+# ** DO NOT EDIT **
+#
+# Make_ivc.mak Makefile to build vim in both IDE and nmake.
+# This file can be imported as a workspace into Visual Studio. It must be in
+# DOS fileformat then!
+#
+# It is worth making the file read-only as the VC4 IDE will try to overwrite
+# it with a HUGELY expanded clone of itself.
+#
+# The following points are worth noting:
+# 1) Comments here are ignored by VC[456].0 IDEs
+# 2) # ADD LINK32 /pdb:.\Dbg/vimd.pdb is written so rather than
+# # ADD LINK32 /pdb:".\Dbg/vimd.pdb" to avoid VC4 -> VC5 conversion failure
+# 3) It is good to delete .pdb file before linking to cope with switch among
+# VC[456] as IDE clean action does not remove that file and link clashes
+# with it. The following works in VC5 but not in VC4 which does not support
+# pre-link actions. The nmake action does such deletions.
+# Begin Special Build Tool
+PreLink_Cmds=@if exist .\oleDbg\gvimd.pdb del .\oleDbg\gvimd.pdb
+# End Special Build Tool
+# 4) I was unable to make !IFDEF OLE, etc. work in the VC4 IDE.
+# I was aiming for 4 configurations with sub-configurations selected by
+# environment variables.
+# 5) Optimisation is not supported by disabled versions of VC. This results in
+# messages for Release builds like:
+# Command line warning D4025 : overriding '/O2' with '/Od'
+# 6) nmake 1.62 and later support batch compilation. I was unable to use this
+# in a manner acceptable to earlier IDEs.
+#
+# History
+#
+# When Who What
+# 2001-07-06 W.Briscoe Original derived from Make_[go]vc.mak with less noise
+# 2001-07-08 W.Briscoe Further noise reduction; consistent .map and .pdb logic
+# Added install.exe rule, etc.; Removed unused libraries.
+# 2001-08-09 W.Briscoe Restored VC4.0-required trailing space in !MESSAGE afore
+# Enhanced if_ole.idl rule to use /out argument.
+# Default rules now relative to . to reduce IDE/nmake difs
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+!IF "$(CFG)" == ""
+CFG=Vim - Win32 Release gvim OLE
+!MESSAGE No configuration specified. Defaulting to Vim - Win32 Release gvim OLE.
+!ENDIF
+
+!IF "$(CFG)" != "Vim - Win32 Release gvim OLE"\
+ && "$(CFG)" != "Vim - Win32 Debug gvim OLE"\
+ && "$(CFG)" != "Vim - Win32 Release gvim"\
+ && "$(CFG)" != "Vim - Win32 Debug gvim"\
+ && "$(CFG)" != "Vim - Win32 Release vim"\
+ && "$(CFG)" != "Vim - Win32 Debug vim"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE on this makefile
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "Make_ivc.mak" CFG="Vim - Win32 Debug vim"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "Vim - Win32 Release gvim OLE" (based on "Win32 (x86) Console Application")
+!MESSAGE "Vim - Win32 Debug gvim OLE" (based on "Win32 (x86) Console Application")
+!MESSAGE "Vim - Win32 Release gvim" (based on "Win32 (x86) Console Application")
+!MESSAGE "Vim - Win32 Debug gvim" (based on "Win32 (x86) Console Application")
+!MESSAGE "Vim - Win32 Release vim" (based on "Win32 (x86) Console Application")
+!MESSAGE "Vim - Win32 Debug vim" (based on "Win32 (x86) Console Application")
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+DEL_TREE = rmdir /s /q
+!ELSE
+NULL=nul
+DEL_TREE = deltree /y
+!ENDIF
+
+# Begin Project
+# PROP Target_Last_Scanned "Vim - Win32 Debug vim"
+# PROP Use_MFC 0
+
+RSC=rc.exe
+CPP=cl.exe
+LINK32=link.exe
+
+CPP_PROJ= /nologo /MT /W3 /GX /I ".\proto" /D "WIN32" /c
+# ADD CPP /nologo /MT /W3 /GX /I ".\proto" /D "WIN32" /c
+
+LINK32_FLAGS= oldnames.lib kernel32.lib user32.lib gdi32.lib version.lib comdlg32.lib comctl32.lib advapi32.lib shell32.lib ole32.lib netapi32.lib uuid.lib /nologo /machine:I386 /nodefaultlib
+# ADD LINK32 oldnames.lib kernel32.lib user32.lib gdi32.lib version.lib comdlg32.lib comctl32.lib advapi32.lib shell32.lib ole32.lib uuid.lib /nologo /machine:I386 /nodefaultlib
+# SUBTRACT LINK32 /incremental:yes
+
+RSC_PROJ= /l 0x409 /d "FEAT_GUI_W32"
+# ADD RSC /l 0x409 /d "FEAT_GUI_W32"
+
+!IF "$(CFG)" == "Vim - Win32 Release gvim OLE"
+
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir .\oleRel
+# PROP Intermediate_Dir .\oleRel
+
+INTDIR=.\oleRel
+VIM=gvim
+EXTRAS="$(INTDIR)/if_ole.obj" "$(INTDIR)/vim.res" "$(INTDIR)/gui.obj" "$(INTDIR)/gui_w32.obj" "$(INTDIR)/gui_beval.obj" "$(INTDIR)/os_w32exe.obj"
+
+CPP_PROJ=$(CPP_PROJ) /Zi /O2 /D "NDEBUG" /D "FEAT_GUI_W32" /D "DYNAMIC_GETTEXT" /D "FEAT_OLE" /Fd.\oleRel/ /Fo.\oleRel/
+# ADD CPP /Zi /O2 /D "NDEBUG" /D "FEAT_GUI_W32" /D "DYNAMIC_GETTEXT" /D "FEAT_OLE" /Fd.\oleRel/ /Fo.\oleRel/
+
+RSC_PROJ=$(RSC_PROJ) /I ".\oleRel" /d "NDEBUG" /d "FEAT_OLE" /fo.\oleRel\vim.res
+# ADD RSC /I ".\oleRel" /d "NDEBUG" /d "FEAT_OLE" /fo.\oleRel\vim.res
+
+LINK32_FLAGS=$(LINK32_FLAGS) /pdb:.\oleRel/gvim.pdb -debug:full -debugtype:cv,fixup /map:.\oleDbg\gvim.map libc.lib oleaut32.lib /subsystem:windows /out:.\gvim.exe
+# ADD LINK32 /pdb:.\oleRel/gvim.pdb -debug:full -debugtype:cv,fixup /map:.\oleDbg\gvim.map libc.lib oleaut32.lib /subsystem:windows /out:.\gvim.exe
+
+!ELSEIF "$(CFG)" == "Vim - Win32 Debug gvim OLE"
+
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir .\oleDbg
+# PROP Intermediate_Dir .\oleDbg
+
+INTDIR=.\oleDbg
+VIM=gvimd
+EXTRAS="$(INTDIR)/if_ole.obj" "$(INTDIR)/vim.res" "$(INTDIR)/gui.obj" "$(INTDIR)/gui_w32.obj" "$(INTDIR)/gui_beval.obj" "$(INTDIR)/os_w32exe.obj"
+
+CPP_PROJ=$(CPP_PROJ) /Zi /Od /D "_DEBUG" /D "FEAT_GUI_W32" /D "DYNAMIC_GETTEXT" /D "FEAT_OLE" /Fd.\oleDbg/ /Fo.\oleDbg/
+# ADD CPP /Zi /Od /D "_DEBUG" /D "FEAT_GUI_W32" /D "DYNAMIC_GETTEXT" /D "FEAT_OLE" /Fd.\oleDbg/ /Fo.\oleDbg/
+
+RSC_PROJ=$(RSC_PROJ) /I .\oleDbg /d "_DEBUG" /d "FEAT_OLE" /fo.\oleDbg\vim.res
+# ADD RSC /I .\oleDbg /d "_DEBUG" /d "FEAT_OLE" /fo.\oleDbg\vim.res
+
+LINK32_FLAGS=$(LINK32_FLAGS) libcd.lib oleaut32.lib /subsystem:windows /debug /profile /pdb:.\oleDbg/gvimd.pdb -debug:full -debugtype:cv,fixup /map:.\oleDbg\gvimd.map /out:.\gvimd.exe
+# ADD LINK32 libcd.lib oleaut32.lib /subsystem:windows /debug /profile /pdb:.\oleDbg/gvimd.pdb -debug:full -debugtype:cv,fixup /map:.\oleDbg\gvimd.map /out:.\gvimd.exe
+
+
+!ELSEIF "$(CFG)" == "Vim - Win32 Release gvim"
+
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir .\gRel
+# PROP Intermediate_Dir .\gRel
+
+INTDIR=.\gRel
+VIM=gvim
+EXTRAS="$(INTDIR)/vim.res" "$(INTDIR)/gui.obj" "$(INTDIR)/gui_w32.obj" "$(INTDIR)/gui_beval.obj" "$(INTDIR)/os_w32exe.obj"
+
+CPP_PROJ=$(CPP_PROJ) /Zi /O2 /D "NDEBUG" /D "FEAT_GUI_W32" /Fd.\gRel/ /Fo.\gRel/
+# ADD CPP /Zi /O2 /D "NDEBUG" /D "FEAT_GUI_W32" /Fd.\gRel/ /Fo.\gRel/
+
+RSC_PROJ=$(RSC_PROJ) /d "NDEBUG" /fo.\gRel\vim.res
+# ADD RSC /d "NDEBUG" /fo.\gRel\vim.res
+
+LINK32_FLAGS=$(LINK32_FLAGS) /pdb:.\gRel/gvim.pdb -debug:full -debugtype:cv,fixup /map:.\oleDbg\gvim.map libc.lib /subsystem:windows /out:.\gvim.exe
+# ADD LINK32 /pdb:.\gRel/gvim.pdb -debug:full -debugtype:cv,fixup /map:.\oleDbg\gvim.map libc.lib /subsystem:windows /out:.\gvim.exe
+
+!ELSEIF "$(CFG)" == "Vim - Win32 Debug gvim"
+
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir .\gDbg
+# PROP Intermediate_Dir .\gDbg
+
+INTDIR=.\gDbg
+VIM=gvimd
+EXTRAS="$(INTDIR)/vim.res" "$(INTDIR)/gui.obj" "$(INTDIR)/gui_w32.obj" "$(INTDIR)/gui_beval.obj" "$(INTDIR)/os_w32exe.obj"
+
+CPP_PROJ=$(CPP_PROJ) /Zi /Od /D "_DEBUG" /D "FEAT_GUI_W32" /Fd.\gDbg/ /Fo.\gDbg/
+# ADD CPP /Zi /Od /D "_DEBUG" /D "FEAT_GUI_W32" /Fd.\gDbg/ /Fo.\gDbg/
+
+RSC_PROJ=$(RSC_PROJ) /d "_DEBUG" /fo.\gDbg\vim.res
+# ADD RSC /d "_DEBUG" /fo.\gDbg\vim.res
+
+LINK32_FLAGS=$(LINK32_FLAGS) libcd.lib /subsystem:windows /debug /profile /pdb:.\gDbg/gvimd.pdb -debug:full -debugtype:cv,fixup /map:.\gDbg\gvimd.map /out:.\gvimd.exe
+# ADD LINK32 libcd.lib /subsystem:windows /debug /profile /pdb:.\gDbg/gvimd.pdb -debug:full -debugtype:cv,fixup /map:.\gDbg\gvimd.map /out:.\gvimd.exe
+
+!ELSEIF "$(CFG)" == "Vim - Win32 Release vim"
+
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir .\Rel
+# PROP Intermediate_Dir .\Rel
+
+INTDIR=.\Rel
+VIM=vim
+EXTRAS=
+
+CPP_PROJ=$(CPP_PROJ) /Zi /O2 /D "NDEBUG" /Fd.\Rel/ /Fo.\Rel/
+# ADD CPP /Zi /O2 /D "NDEBUG" /Fd.\Rel/ /Fo.\Rel/
+
+LINK32_FLAGS=$(LINK32_FLAGS) /pdb:.\Rel/vim.pdb -debug:full -debugtype:cv,fixup /map:.\oleDbg\vim.map libc.lib /subsystem:console /out:.\vim.exe
+# ADD LINK32 /pdb:.\Rel/vim.pdb -debug:full -debugtype:cv,fixup /map:.\oleDbg\vim.map libc.lib /subsystem:console /out:.\vim.exe
+
+!ELSEIF "$(CFG)" == "Vim - Win32 Debug vim"
+
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir .\Dbg
+# PROP Intermediate_Dir .\Dbg
+
+INTDIR=.\Dbg
+VIM=vimd
+EXTRAS=
+
+CPP_PROJ=$(CPP_PROJ) /Zi /Od /D "_DEBUG" /Fd.\Dbg/ /Fo.\Dbg/
+# ADD CPP /Zi /Od /D "_DEBUG" /Fd.\Dbg/ /Fo.\Dbg/
+
+LINK32_FLAGS=$(LINK32_FLAGS) libcd.lib /subsystem:console /debug /profile /pdb:.\Dbg/vimd.pdb -debug:full -debugtype:cv,fixup /map:.\Dbg/vimd.map /out:.\vimd.exe
+# ADD LINK32 libcd.lib /subsystem:console /debug /profile /pdb:.\Dbg/vimd.pdb -debug:full -debugtype:cv,fixup /map:.\Dbg/vimd.map /out:.\vimd.exe
+
+!ENDIF
+
+ALL : .\$(VIM).exe vimrun.exe install.exe uninstal.exe xxd/xxd.exe GvimExt/gvimext.dll
+
+LINK32_OBJS= \
+ $(EXTRAS) \
+ "$(INTDIR)/arabic.obj" \
+ "$(INTDIR)/autocmd.obj" \
+ "$(INTDIR)/blowfish.obj" \
+ "$(INTDIR)/buffer.obj" \
+ "$(INTDIR)/charset.obj" \
+ "$(INTDIR)/crypt.obj" \
+ "$(INTDIR)/crypt_zip.obj" \
+ "$(INTDIR)/dict.obj" \
+ "$(INTDIR)/diff.obj" \
+ "$(INTDIR)/digraph.obj" \
+ "$(INTDIR)/edit.obj" \
+ "$(INTDIR)/eval.obj" \
+ "$(INTDIR)/evalfunc.obj" \
+ "$(INTDIR)/ex_cmds.obj" \
+ "$(INTDIR)/ex_cmds2.obj" \
+ "$(INTDIR)/ex_docmd.obj" \
+ "$(INTDIR)/ex_eval.obj" \
+ "$(INTDIR)/ex_getln.obj" \
+ "$(INTDIR)/farsi.obj" \
+ "$(INTDIR)/fileio.obj" \
+ "$(INTDIR)/fold.obj" \
+ "$(INTDIR)/getchar.obj" \
+ "$(INTDIR)/hardcopy.obj" \
+ "$(INTDIR)/hashtab.obj" \
+ "$(INTDIR)/indent.obj" \
+ "$(INTDIR)/json.obj" \
+ "$(INTDIR)/list.obj" \
+ "$(INTDIR)/main.obj" \
+ "$(INTDIR)/mark.obj" \
+ "$(INTDIR)/mbyte.obj" \
+ "$(INTDIR)/memfile.obj" \
+ "$(INTDIR)/memline.obj" \
+ "$(INTDIR)/menu.obj" \
+ "$(INTDIR)/message.obj" \
+ "$(INTDIR)/misc1.obj" \
+ "$(INTDIR)/misc2.obj" \
+ "$(INTDIR)/move.obj" \
+ "$(INTDIR)/normal.obj" \
+ "$(INTDIR)/ops.obj" \
+ "$(INTDIR)/option.obj" \
+ "$(INTDIR)/os_mswin.obj" \
+ "$(INTDIR)/winclip.obj" \
+ "$(INTDIR)/os_win32.obj" \
+ "$(INTDIR)/popupmnu.obj" \
+ "$(INTDIR)/quickfix.obj" \
+ "$(INTDIR)/regexp.obj" \
+ "$(INTDIR)/screen.obj" \
+ "$(INTDIR)/search.obj" \
+ "$(INTDIR)/sha256.obj" \
+ "$(INTDIR)/sign.obj" \
+ "$(INTDIR)/spell.obj" \
+ "$(INTDIR)/spellfile.obj" \
+ "$(INTDIR)/syntax.obj" \
+ "$(INTDIR)/tag.obj" \
+ "$(INTDIR)/term.obj" \
+ "$(INTDIR)/ui.obj" \
+ "$(INTDIR)/undo.obj" \
+ "$(INTDIR)/userfunc.obj" \
+ "$(INTDIR)/version.obj" \
+ "$(INTDIR)/window.obj"
+
+".\$(VIM).exe" : "$(INTDIR)" $(EXTRAS) $(LINK32_OBJS)
+ @if exist $(INTDIR)\$(VIM).pdb del $(INTDIR)\$(VIM).pdb
+ $(LINK32) $(LINK32_FLAGS) $(LINK32_OBJS)
+
+"$(INTDIR)" :
+ if not exist "$(INTDIR)/$(NULL)" mkdir "$(INTDIR)"
+
+CLEAN :
+ -@if exist "$(INTDIR)/$(NULL)" $(DEL_TREE) "$(INTDIR)"
+ -@if exist $(VIM).exe erase $(VIM).exe
+ -@if exist $(VIM).ilk erase $(VIM).ilk
+ -@if exist $(VIM).map erase $(VIM).map
+ -@if exist $(VIM).pdb erase $(VIM).pdb
+ -@if exist DLLDATA.C erase DLLDATA.C
+ -@if exist Make_ivc.bak attrib -r Make_ivc.bak
+ -@if exist Make_ivc.bak erase Make_ivc.bak
+ -@if exist Make_ivc.dsp erase Make_ivc.dsp
+ -@if exist Make_ivc.dsw erase Make_ivc.dsw
+ -@if exist Make_ivc.mdp erase Make_ivc.mdp
+ -@if exist Make_ivc.ncb erase Make_ivc.ncb
+ -@if exist Make_ivc.opt erase Make_ivc.opt
+ -@if exist Make_ivc.plg erase Make_ivc.plg
+ -@if exist dosinst.obj erase dosinst.obj
+ -@if exist install.exe erase install.exe
+ -@if exist uninstal.exe erase uninstal.exe
+ -@if exist uninstal.obj erase uninstal.obj
+ -@if exist vimrun.exe erase vimrun.exe
+ -@if exist vimrun.obj erase vimrun.obj
+
+
+install.exe: dosinst.c
+ $(CPP) /Fe$@ /nologo /W3 -DNDEBUG -DWIN32 dosinst.c kernel32.lib shell32.lib user32.lib ole32.lib advapi32.lib uuid.lib
+
+uninstal.exe: uninstal.c
+ $(CPP) /nologo /W3 -DNDEBUG -DWIN32 uninstal.c shell32.lib advapi32.lib
+
+vimrun.exe: vimrun.c
+ $(CPP) /nologo /W3 -DNDEBUG vimrun.c
+
+xxd/xxd.exe: xxd/xxd.c
+ cd xxd
+ $(MAKE) /NOLOGO -f Make_mvc.mak
+ cd ..
+
+GvimExt/gvimext.dll: GvimExt/gvimext.cpp GvimExt/gvimext.rc GvimExt/gvimext.h
+ cd GvimExt
+ $(MAKE) /NOLOGO -f Makefile
+ cd ..
+
+{.}.c{$(INTDIR)/}.obj:
+ $(CPP) $(CPP_PROJ) $<
+
+{.}.cpp{$(INTDIR)/}.obj:
+ $(CPP) $(CPP_PROJ) /I $(INTDIR) $<
+
+{.}.rc{$(INTDIR)/}.res:
+ $(RSC) $(RSC_PROJ) $<
+
+# Begin Target
+
+# Name "Vim - Win32 Release gvim OLE"
+# Name "Vim - Win32 Debug gvim OLE"
+# Name "Vim - Win32 Release gvim"
+# Name "Vim - Win32 Debug gvim"
+# Name "Vim - Win32 Release vim"
+# Name "Vim - Win32 Debug vim"
+
+# Begin Source File
+
+SOURCE=.\arabic.c
+# End Source File
+# Begin Source File
+#
+SOURCE=.\autocmd.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\blowfish.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\buffer.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\charset.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\crypt.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\crypt_zip.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\dict.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\diff.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\digraph.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\edit.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\eval.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\evalfunc.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ex_cmds.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ex_cmds2.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ex_docmd.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ex_eval.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ex_getln.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\farsi.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\fileio.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\fold.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\getchar.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\hardcopy.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\hashtab.c
+# End Source File
+# Begin Source File
+#
+SOURCE=.\indent.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\gui.c
+
+!IF "$(CFG)" == "Vim - Win32 Release vim"
+
+# PROP Exclude_From_Build 1
+
+!ELSEIF "$(CFG)" == "Vim - Win32 Debug vim"
+
+# PROP Exclude_From_Build 1
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\gui_w32.c
+
+!IF "$(CFG)" == "Vim - Win32 Release vim"
+
+# PROP Exclude_From_Build 1
+
+!ELSEIF "$(CFG)" == "Vim - Win32 Debug vim"
+
+# PROP Exclude_From_Build 1
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\gui_beval.c
+
+!IF "$(CFG)" == "Vim - Win32 Release vim"
+
+# PROP Exclude_From_Build 1
+
+!ELSEIF "$(CFG)" == "Vim - Win32 Debug vim"
+
+# PROP Exclude_From_Build 1
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\os_w32exe.c
+
+!IF "$(CFG)" == "Vim - Win32 Release vim"
+
+# PROP Exclude_From_Build 1
+
+!ELSEIF "$(CFG)" == "Vim - Win32 Debug vim"
+
+# PROP Exclude_From_Build 1
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\if_ole.cpp
+
+!IF "$(CFG)" == "Vim - Win32 Release gvim OLE"
+
+# PROP Ignore_Default_Tool 1
+# Begin Custom Build
+
+"$(INTDIR)\if_ole.obj" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\if_ole.h"
+ cl.exe /nologo /MT /W3 /GX /I ".\proto" /D "WIN32" /c /Zi /O2 /D "NDEBUG" /D "FEAT_GUI_W32" /D "FEAT_OLE" /Fd.\oleRel/ /Fo.\oleRel/ /I ".\oleRel" .\if_ole.cpp
+ @rem This is the default rule with /I "$(IntDir)" added
+
+# End Custom Build
+
+!ELSEIF "$(CFG)" == "Vim - Win32 Debug gvim OLE"
+
+# PROP Ignore_Default_Tool 1
+# Begin Custom Build
+
+"$(INTDIR)\if_ole.obj" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\if_ole.h"
+ cl.exe /nologo /MT /W3 /GX /I ".\proto" /D "WIN32" /c /Zi /Od /D "_DEBUG" /D "FEAT_GUI_W32" /D "FEAT_OLE" /Fd.\oleDbg/ /Fo.\oleDbg/ /I ".\oleDbg" .\if_ole.cpp
+ @rem This is the default rule with /I "$(IntDir)" added
+
+# End Custom Build
+
+!ELSEIF "$(CFG)" == "Vim - Win32 Release gvim"
+
+# PROP Exclude_From_Build 1
+
+!ELSEIF "$(CFG)" == "Vim - Win32 Debug gvim"
+
+# PROP Exclude_From_Build 1
+
+!ELSEIF "$(CFG)" == "Vim - Win32 Release vim"
+
+# PROP Exclude_From_Build 1
+
+!ELSEIF "$(CFG)" == "Vim - Win32 Debug vim"
+
+# PROP Exclude_From_Build 1
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\if_ole.idl
+
+!IF "$(CFG)" == "Vim - Win32 Release gvim OLE"
+
+# PROP Ignore_Default_Tool 1
+# Begin Custom Build
+
+"$(INTDIR)\if_ole.h" : $(SOURCE) "$(INTDIR)"
+ if exist .\if_ole.h del .\if_ole.h
+ midl /out .\oleRel /iid iid_ole.c /tlb vim.tlb /proxy nul /header if_ole.h .\if_ole.idl
+
+# End Custom Build
+
+!ELSEIF "$(CFG)" == "Vim - Win32 Debug gvim OLE"
+
+# PROP Ignore_Default_Tool 1
+# Begin Custom Build
+
+"$(INTDIR)\if_ole.h" : $(SOURCE) "$(INTDIR)"
+ if exist .\if_ole.h del .\if_ole.h
+ midl /out .\oleDbg /iid iid_ole.c /tlb vim.tlb /proxy nul /header if_ole.h .\if_ole.idl
+
+# End Custom Build
+
+!ELSEIF "$(CFG)" == "Vim - Win32 Release gvim"
+
+# PROP Exclude_From_Build 1
+
+!ELSEIF "$(CFG)" == "Vim - Win32 Debug gvim"
+
+# PROP Exclude_From_Build 1
+
+!ELSEIF "$(CFG)" == "Vim - Win32 Release vim"
+
+# PROP Exclude_From_Build 1
+
+!ELSEIF "$(CFG)" == "Vim - Win32 Debug vim"
+
+# PROP Exclude_From_Build 1
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\json.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\list.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\main.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mark.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mbyte.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\memfile.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\memline.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\menu.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\message.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\misc1.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\misc2.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\move.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\normal.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ops.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\option.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\os_mswin.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\winclip.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\os_win32.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\popupmnu.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\quickfix.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\regexp.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\screen.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\search.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\sha256.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\sign.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\spell.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\spellfile.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\syntax.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tag.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\term.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ui.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\undo.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\userfunc.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\version.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\vim.rc
+
+!IF "$(CFG)" == "Vim - Win32 Release gvim OLE"
+
+"$(INTDIR)\vim.res" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\if_ole.h"
+
+!ELSEIF "$(CFG)" == "Vim - Win32 Debug gvim OLE"
+
+"$(INTDIR)\vim.res" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\if_ole.h"
+
+!ELSEIF "$(CFG)" == "Vim - Win32 Release gvim"
+
+"$(INTDIR)\vim.res" : $(SOURCE) "$(INTDIR)"
+
+!ELSEIF "$(CFG)" == "Vim - Win32 Debug gvim"
+
+"$(INTDIR)\vim.res" : $(SOURCE) "$(INTDIR)"
+
+!ELSEIF "$(CFG)" == "Vim - Win32 Release vim"
+
+# PROP Exclude_From_Build 1
+
+!ELSEIF "$(CFG)" == "Vim - Win32 Debug vim"
+
+# PROP Exclude_From_Build 1
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\window.c
+# End Source File
+# End Target
+# End Project
diff --git a/src/Make_manx.mak b/src/Make_manx.mak
new file mode 100644
index 0000000..a44ad65
--- /dev/null
+++ b/src/Make_manx.mak
@@ -0,0 +1,438 @@
+#
+# Makefile for VIM on the Amiga, using Aztec/Manx C 5.0 or later
+#
+# NOTE: THIS IS OLD AND PROBABLY NO LONGER WORKS.
+#
+# Note: Not all dependencies are included. This was done to avoid having
+# to compile everything when a global variable or function is added.
+# Careful when changing a global struct or variable!
+#
+
+#>>>>> choose options:
+
+### See feature.h for a list of optionals.
+### Any other defines can be included here.
+DEFINES =
+
+#>>>>> if HAVE_TGETENT is defined obj/termlib.o has to be used
+#TERMLIB = obj/termlib.o
+TERMLIB =
+
+#>>>>> choose between debugging (-bs) or optimizing (-so)
+OPTIONS = -so
+#OPTIONS = -bs
+
+#>>>>> end of choices
+###########################################################################
+
+CFLAGS = $(OPTIONS) -wapruq -ps -qf -Iproto $(DEFINES) -DAMIGA
+
+LIBS = -lc16
+SYMS = vim.syms
+CC = cc
+LN = ln
+LNFLAGS = +q
+SHELL = csh
+REN = $(SHELL) -c mv -f
+DEL = $(SHELL) -c rm -f
+
+SRC = arabic.c \
+ autocmd.c \
+ blowfish.c \
+ buffer.c \
+ charset.c \
+ crypt.c \
+ crypt_zip.c \
+ dict.c \
+ diff.c \
+ digraph.c \
+ edit.c \
+ eval.c \
+ evalfunc.c \
+ ex_cmds.c \
+ ex_cmds2.c \
+ ex_docmd.c \
+ ex_eval.c \
+ ex_getln.c \
+ farsi.c \
+ fileio.c \
+ fold.c \
+ getchar.c \
+ hardcopy.c \
+ hashtab.c \
+ indent.c \
+ json.c \
+ list.c \
+ main.c \
+ mark.c \
+ memfile.c \
+ memline.c \
+ menu.c \
+ message.c \
+ misc1.c \
+ misc2.c \
+ move.c \
+ mbyte.c \
+ normal.c \
+ ops.c \
+ option.c \
+ os_amiga.c \
+ popupmnu.c \
+ quickfix.c \
+ regexp.c \
+ screen.c \
+ search.c \
+ sha256.c \
+ sign.c \
+ spell.c \
+ spellfile.c \
+ syntax.c \
+ tag.c \
+ term.c \
+ ui.c \
+ undo.c \
+ userfunc.c \
+ window.c \
+ version.c
+
+INCL = vim.h feature.h keymap.h macros.h ascii.h term.h structs.h os_amiga.h
+
+OBJ = obj/arabic.o \
+ obj/autocmd.o \
+ obj/blowfish.o \
+ obj/buffer.o \
+ obj/charset.o \
+ obj/crypt.o \
+ obj/crypt_zip.o \
+ obj/dict.o \
+ obj/diff.o \
+ obj/digraph.o \
+ obj/edit.o \
+ obj/eval.o \
+ obj/evalfunc.o \
+ obj/ex_cmds.o \
+ obj/ex_cmds2.o \
+ obj/ex_docmd.o \
+ obj/ex_eval.o \
+ obj/ex_getln.o \
+ obj/farsi.o \
+ obj/fileio.o \
+ obj/fold.o \
+ obj/getchar.o \
+ obj/hardcopy.o \
+ obj/hashtab.o \
+ obj/indent.o \
+ obj/json.o \
+ obj/list.o \
+ obj/main.o \
+ obj/mark.o \
+ obj/memfile.o \
+ obj/memline.o \
+ obj/menu.o \
+ obj/message.o \
+ obj/misc1.o \
+ obj/misc2.o \
+ obj/move.o \
+ obj/mbyte.o \
+ obj/normal.o \
+ obj/ops.o \
+ obj/option.o \
+ obj/os_amiga.o \
+ obj/popupmnu.o \
+ obj/quickfix.o \
+ obj/regexp.o \
+ obj/screen.o \
+ obj/search.o \
+ obj/sha256.o \
+ obj/sign.o \
+ obj/spell.o \
+ obj/spellfile.o \
+ obj/syntax.o \
+ obj/tag.o \
+ obj/term.o \
+ obj/ui.o \
+ obj/undo.o \
+ obj/userfunc.o \
+ obj/window.o \
+ $(TERMLIB)
+
+PRO = proto/arabic.pro \
+ proto/autocmd.pro \
+ proto/blowfish.pro \
+ proto/buffer.pro \
+ proto/charset.pro \
+ proto/crypt.pro \
+ proto/crypt_zip.pro \
+ proto/dict.pro \
+ proto/diff.pro \
+ proto/digraph.pro \
+ proto/edit.pro \
+ proto/eval.pro \
+ proto/evalfunc.pro \
+ proto/ex_cmds.pro \
+ proto/ex_cmds2.pro \
+ proto/ex_docmd.pro \
+ proto/ex_eval.pro \
+ proto/ex_getln.pro \
+ proto/farsi.pro \
+ proto/fileio.pro \
+ proto/fold.pro \
+ proto/getchar.pro \
+ proto/hardcopy.pro \
+ proto/hashtab.pro \
+ proto/indent.pro \
+ proto/json.pro \
+ proto/list.pro \
+ proto/main.pro \
+ proto/mark.pro \
+ proto/memfile.pro \
+ proto/memline.pro \
+ proto/menu.pro \
+ proto/message.pro \
+ proto/misc1.pro \
+ proto/misc2.pro \
+ proto/move.pro \
+ proto/mbyte.pro \
+ proto/normal.pro \
+ proto/ops.pro \
+ proto/option.pro \
+ proto/os_amiga.pro \
+ proto/popupmnu.pro \
+ proto/quickfix.pro \
+ proto/regexp.pro \
+ proto/screen.pro \
+ proto/search.pro \
+ proto/sha256.pro \
+ proto/sign.pro \
+ proto/spell.pro \
+ proto/spellfile.pro \
+ proto/syntax.pro \
+ proto/tag.pro \
+ proto/term.pro \
+ proto/termlib.pro \
+ proto/ui.pro \
+ proto/undo.pro \
+ proto/userfunc.pro \
+ proto/window.pro
+
+all: Vim xxd/Xxd
+
+Vim: obj $(OBJ) version.c version.h
+ $(CC) $(CFLAGS) version.c -o obj/version.o
+ $(LN) $(LNFLAGS) -m -o Vim $(OBJ) obj/version.o $(LIBS)
+
+debug: obj $(OBJ) version.c version.h
+ $(CC) $(CFLAGS) version.c -o obj/version.o
+ $(LN) $(LNFLAGS) -m -g -o Vim $(OBJ) obj/version.o $(LIBS)
+
+xxd/Xxd: xxd/xxd.c
+ $(SHELL) -c cd xxd; make -f Make_amiga.mak; cd ..
+
+# Making prototypes with Manx has been removed, because it caused too many
+# problems.
+#proto: $(SYMS) $(PRO)
+
+obj:
+ makedir obj
+
+tags: $(SRC) $(INCL)
+ $(SHELL) -c ctags $(SRC) *.h
+
+# can't use delete here, too many file names
+clean:
+ $(DEL) $(OBJ) obj/version.o \
+ obj/termlib.o Vim $(SYMS) xxd/Xxd
+
+test:
+ $(SHELL) -c cd testdir; make -f Make_amiga.mak; cd ..
+
+$(SYMS): $(INCL) $(PRO)
+ $(CC) $(CFLAGS) -ho$(SYMS) vim.h
+
+###########################################################################
+
+# Unfortunately, Manx's make doesn't understand a .c.o rule, so each
+# compilation command has to be given explicitly.
+
+CCSYM = $(CC) $(CFLAGS) -hi$(SYMS) -o
+CCNOSYM = $(CC) $(CFLAGS) -o
+
+$(OBJ): $(SYMS)
+
+obj/arabic.o: arabic.c
+ $(CCSYM) $@ arabic.c
+
+obj/autocmd.o: autocmd.c
+ $(CCSYM) $@ autocmd.c
+
+obj/blowfish.o: blowfish.c
+ $(CCSYM) $@ blowfish.c
+
+obj/buffer.o: buffer.c
+ $(CCSYM) $@ buffer.c
+
+obj/charset.o: charset.c
+ $(CCSYM) $@ charset.c
+
+obj/crypt.o: crypt.c
+ $(CCSYM) $@ crypt.c
+
+obj/crypt_zip.o: crypt_zip.c
+ $(CCSYM) $@ crypt_zip.c
+
+obj/dict.o: dict.c
+ $(CCSYM) $@ dict.c
+
+obj/diff.o: diff.c
+ $(CCSYM) $@ diff.c
+
+obj/digraph.o: digraph.c
+ $(CCSYM) $@ digraph.c
+
+obj/edit.o: edit.c
+ $(CCSYM) $@ edit.c
+
+obj/eval.o: eval.c
+ $(CCSYM) $@ eval.c
+
+obj/evalfunc.o: evalfunc.c
+ $(CCSYM) $@ evalfunc.c
+
+obj/ex_cmds.o: ex_cmds.c
+ $(CCSYM) $@ ex_cmds.c
+
+obj/ex_cmds2.o: ex_cmds2.c
+ $(CCSYM) $@ ex_cmds2.c
+
+# Don't use $(SYMS) here, because ex_docmd.c defines DO_DECLARE_EXCMD
+obj/ex_docmd.o: ex_docmd.c ex_cmds.h
+ $(CCNOSYM) $@ ex_docmd.c
+
+obj/ex_eval.o: ex_eval.c ex_cmds.h
+ $(CCSYM) $@ ex_eval.c
+
+obj/ex_getln.o: ex_getln.c
+ $(CCSYM) $@ ex_getln.c
+
+obj/farsi.o: farsi.c
+ $(CCSYM) $@ farsi.c
+
+obj/fileio.o: fileio.c
+ $(CCSYM) $@ fileio.c
+
+obj/fold.o: fold.c
+ $(CCSYM) $@ fold.c
+
+obj/getchar.o: getchar.c
+ $(CCSYM) $@ getchar.c
+
+obj/hardcopy.o: hardcopy.c
+ $(CCSYM) $@ hardcopy.c
+
+obj/hashtab.o: hashtab.c
+ $(CCSYM) $@ hashtab.c
+
+obj/indent.o: indent.c
+ $(CCSYM) $@ indent.c
+
+obj/json.o: json.c
+ $(CCSYM) $@ json.c
+
+obj/list.o: list.c
+ $(CCSYM) $@ list.c
+
+# Don't use $(SYMS) here, because main.c defines EXTERN
+obj/main.o: main.c option.h globals.h
+ $(CCNOSYM) $@ main.c
+
+obj/mark.o: mark.c
+ $(CCSYM) $@ mark.c
+
+obj/memfile.o: memfile.c
+ $(CCSYM) $@ memfile.c
+
+obj/memline.o: memline.c
+ $(CCSYM) $@ memline.c
+
+obj/menu.o: menu.c
+ $(CCSYM) $@ menu.c
+
+# Don't use $(SYMS) here, because message.c defines MESSAGE_FILE
+obj/message.o: message.c
+ $(CCNOSYM) $@ message.c
+
+obj/misc1.o: misc1.c
+ $(CCSYM) $@ misc1.c
+
+obj/misc2.o: misc2.c
+ $(CCSYM) $@ misc2.c
+
+obj/move.o: move.c
+ $(CCSYM) $@ move.c
+
+obj/mbyte.o: mbyte.c
+ $(CCSYM) $@ mbyte.c
+
+obj/normal.o: normal.c
+ $(CCSYM) $@ normal.c
+
+obj/ops.o: ops.c
+ $(CCSYM) $@ ops.c
+
+# Don't use $(SYMS) here, because option.h defines variables here
+obj/option.o: option.c
+ $(CCNOSYM) $@ option.c
+
+obj/os_amiga.o: os_amiga.c
+ $(CCSYM) $@ os_amiga.c
+
+obj/popupmnu.o: popupmnu.c
+ $(CCSYM) $@ popupmnu.c
+
+obj/quickfix.o: quickfix.c
+ $(CCSYM) $@ quickfix.c
+
+obj/regexp.o: regexp.c
+ $(CCSYM) $@ regexp.c
+
+obj/screen.o: screen.c
+ $(CCSYM) $@ screen.c
+
+obj/search.o: search.c
+ $(CCSYM) $@ search.c
+
+obj/sha256.o: sha256.c
+ $(CCSYM) $@ sha256.c
+
+obj/sign.o: sign.c
+ $(CCSYM) $@ sign.c
+
+obj/spell.o: spell.c
+ $(CCSYM) $@ spell.c
+
+obj/spellfile.o: spellfile.c
+ $(CCSYM) $@ spellfile.c
+
+obj/syntax.o: syntax.c
+ $(CCSYM) $@ syntax.c
+
+obj/tag.o: tag.c
+ $(CCSYM) $@ tag.c
+
+obj/term.o: term.c term.h
+ $(CCSYM) $@ term.c
+
+obj/termlib.o: termlib.c
+ $(CCSYM) $@ termlib.c
+
+obj/ui.o: ui.c
+ $(CCSYM) $@ ui.c
+
+obj/undo.o: undo.c
+ $(CCSYM) $@ undo.c
+
+obj/userfunc.o: userfunc.c
+ $(CCSYM) $@ userfunc.c
+
+obj/window.o: window.c
+ $(CCSYM) $@ window.c
diff --git a/src/Make_ming.mak b/src/Make_ming.mak
new file mode 100644
index 0000000..e9e20f6
--- /dev/null
+++ b/src/Make_ming.mak
@@ -0,0 +1,51 @@
+#
+# Makefile for VIM on Win32, using MinGW
+#
+# Also read INSTALLpc.txt!
+#
+# The old Make_ming.mak (maintained by Ron Aaron et al.) was merged into
+# Make_cyg_ming.mak.
+# This file contains MinGW specific settings. Common settings are contained
+# in Make_cyg_ming.mak.
+#
+# Last updated by Ken Takata.
+# Last Change: 2014 Oct 21
+
+
+# uncomment 'PERL' if you want a perl-enabled version
+#PERL=c:/perl
+
+# uncomment 'LUA' if you want a Lua-enabled version
+#LUA=c:/lua
+
+# uncomment 'MZSCHEME' if you want a MzScheme-enabled version
+#MZSCHEME=d:/plt
+
+# uncomment 'PYTHON' if you want a python-enabled version
+# Put the path to the python distro here. If cross compiling from Linux, you
+# will also need to convert the header files to unix instead of dos format:
+# for fil in *.h ; do vim -e -c 'set ff=unix|w|q' $fil
+# and also, you will need to make a mingw32 'libpython20.a' to link with:
+# cd $PYTHON/libs
+# pexports python20.dll > python20.def
+# dlltool -d python20.def -l libpython20.a
+# on my Linux box, I put the Python stuff here:
+#PYTHON=/home/ron/ActivePython-2.0.0-202/src/Core
+# on my NT box, it's here:
+#PYTHON=c:/python20
+
+# uncomment 'PYTHON3' if you want a python3-enabled version
+#PYTHON3=c:/python31
+
+# uncomment 'TCL' if you want a Tcl-enabled version
+#TCL=c:/tcl
+
+# uncomment 'RUBY' if you want a Ruby-enabled version
+#RUBY=c:/ruby
+
+
+# Do not change this.
+UNDER_CYGWIN = no
+include Make_cyg_ming.mak
+
+# vim: set noet sw=8 ts=8 sts=0 wm=0 tw=0:
diff --git a/src/Make_mint.mak b/src/Make_mint.mak
new file mode 100644
index 0000000..97a2e4b
--- /dev/null
+++ b/src/Make_mint.mak
@@ -0,0 +1,56 @@
+#
+# Makefile for Vim on MiNT vim:ts=8:sw=8:tw=78
+#
+# This is a wrapper around the Unix Makefile. It is configured to accompany
+# the MiNT distribution of Vim.
+#
+# See "Makefile" for instructions how to run "make".
+#
+# BUT: Always run: "make -f Make_mint.mak config",
+# and then: "make -f Make_mint.mak"!
+# Otherwise the postprocessing won't get done.
+#
+
+### This Makefile has been successfully tested on these systems.
+### Check the (*) column for remarks, listed below.
+### Later code changes may cause small problems, otherwise Vim is supposed to
+### compile and run without problems.
+
+#system: configurations: version (*) tested by:
+#------------- ------------------------ ------- - ----------
+#MiNT 1.12.5 gcc gcc-2.6.1 3.29 Jens Felderhoff
+#MiNT 1.12.6 gcc gcc-2.6.1 -GUI 4.6b Jens Felderhoff
+#MiNT 1.12.6 gcc gcc-2.6.1 -GUI 4.6 Jens Felderhoff
+
+# set this to the pathname prefix of your symbol link editor, i.e. if it is
+# /usr/local/bin/sym-ld set:
+#
+SYMLDPREFIX = /usr/local/bin/sym-
+#SYMLDPREFIX = /gnu/bin/sym-
+
+POSTPROCESS = fixstk 20k $(VIMTARGET)
+DBGPOSTPROCESS = fixstk 20k $(DBGTARGET)
+DBGLDFLAGS = -B$(SYMLDPREFIX)
+DBGTARGET = $(VIMTARGET).sym
+
+
+# Default target is making the executable and then do the post processing
+all: $(VIMTARGET) $(TOOLS)
+ $(POSTPROCESS)
+
+debug: $(DBGTARGET)
+ $(DBGPOSTPROCESS)
+
+#################### include the Unix Makefile ###############
+
+include Makefile
+
+
+### (M) MiNT with gcc 2.6.1 and gdb 3.5
+CC = gcc -mint
+CFLAGS = -g -O -Iproto
+
+$(DBGTARGET): $(OBJ) version.c version.h
+ $(CC) -c $(ALL_CFLAGS) version.c
+ $(CC) $(LDFLAGS) $(DBGLDFLAGS) -o $(DBGTARGET) -g $(OBJ) \
+ version.o $(ALL_LIBS)
diff --git a/src/Make_morph.mak b/src/Make_morph.mak
new file mode 100644
index 0000000..6bcae1a
--- /dev/null
+++ b/src/Make_morph.mak
@@ -0,0 +1,95 @@
+#
+# Makefile for VIM, using MorphOS SDK (gcc 2.95.3)
+#
+
+CFLAGS = -c \
+ -pipe \
+ -O2 \
+ -Wall \
+ \
+ -DNO_ARP \
+ -DUSE_TMPNAM \
+ \
+ -I proto \
+ \
+ -noixemul
+
+PRG = Vim
+LIBS = -noixemul -s
+CC = gcc
+LD = gcc
+OBJDUMP = objdump
+RM = rm
+
+.c.o:
+ ${CC} ${CFLAGS} $< -o $@
+
+SRC = arabic.c \
+ autocmd.c \
+ blowfish.c \
+ buffer.c \
+ charset.c \
+ crypt.c \
+ crypt_zip.c \
+ dict.c \
+ diff.c \
+ digraph.c \
+ edit.c \
+ eval.c \
+ evalfunc.c \
+ ex_cmds.c \
+ ex_cmds2.c \
+ ex_docmd.c \
+ ex_eval.c \
+ ex_getln.c \
+ farsi.c \
+ fileio.c \
+ fold.c \
+ getchar.c \
+ hardcopy.c \
+ hashtab.c \
+ indent.c \
+ json.c \
+ list.c \
+ main.c \
+ mark.c \
+ mbyte.c \
+ memfile.c \
+ memline.c \
+ menu.c \
+ message.c \
+ misc1.c \
+ misc2.c \
+ move.c \
+ normal.c \
+ ops.c \
+ option.c \
+ os_amiga.c \
+ popupmnu.c \
+ quickfix.c \
+ regexp.c \
+ screen.c \
+ search.c \
+ sha256.c \
+ sign.c \
+ spell.c \
+ spellfile.c \
+ syntax.c \
+ tag.c \
+ term.c \
+ ui.c \
+ undo.c \
+ userfunc.c \
+ version.c \
+ window.c \
+
+OBJ = $(SRC:.c=.o)
+
+$(PRG): $(OBJ)
+ ${LD} -o $(PRG) $(OBJ) $(LIBS)
+
+dump: $(PRG)
+ $(OBJDUMP) --reloc --disassemble-all $(PRG) > $(PRG).s
+
+clean:
+ $(RM) -fv $(OBJ) $(PRG) $(PRG).s
diff --git a/src/Make_mvc.mak b/src/Make_mvc.mak
new file mode 100644
index 0000000..52deb54
--- /dev/null
+++ b/src/Make_mvc.mak
@@ -0,0 +1,1701 @@
+# Makefile for Vim on Win32 (Windows XP/2003/Vista/7/8/10) and Win64,
+# using the Microsoft Visual C++ compilers. Known to work with VC5, VC6 (VS98),
+# VC7.0 (VS2002), VC7.1 (VS2003), VC8 (VS2005), VC9 (VS2008), VC10 (VS2010),
+# VC11 (VS2012), VC12 (VS2013), VC14 (VS2015) and VC15 (VS2017)
+#
+# To build using other Windows compilers, see INSTALLpc.txt
+#
+# This makefile can build the console, GUI, OLE-enable, Perl-enabled and
+# Python-enabled versions of Vim for Win32 platforms.
+#
+# The basic command line to build Vim is:
+#
+# nmake -f Make_mvc.mak
+#
+# This will build the console version of Vim with no additional interfaces.
+# To add features, define any of the following:
+#
+# For MSVC 11, if you want to include Win32.mak, you need to specify
+# where the file is, e.g.:
+# SDK_INCLUDE_DIR="C:\Program Files\Microsoft SDKs\Windows\v7.1\Include"
+#
+# !!!! After changing features do "nmake clean" first !!!!
+#
+# Feature Set: FEATURES=[TINY, SMALL, NORMAL, BIG, HUGE] (default is HUGE)
+#
+# GUI interface: GUI=yes (default is no)
+#
+# GUI with DirectWrite (DirectX): DIRECTX=yes
+# (default is yes if GUI=yes, requires GUI=yes)
+#
+# Color emoji support: COLOR_EMOJI=yes
+# (default is yes if DIRECTX=yes, requires WinSDK 8.1 or later.)
+#
+# OLE interface: OLE=yes (usually with GUI=yes)
+#
+# IME support: IME=yes (requires GUI=yes)
+# DYNAMIC_IME=[yes or no] (to load the imm32.dll dynamically, default
+# is yes)
+# Global IME support: GIME=yes (requires GUI=yes)
+#
+# Terminal support: TERMINAL=yes (default is yes)
+#
+# Lua interface:
+# LUA=[Path to Lua directory]
+# DYNAMIC_LUA=yes (to load the Lua DLL dynamically)
+# LUA_VER=[Lua version] (default is 53)
+#
+# MzScheme interface:
+# MZSCHEME=[Path to MzScheme directory]
+# DYNAMIC_MZSCHEME=yes (to load the MzScheme DLLs dynamically)
+# MZSCHEME_VER=[MzScheme version] (default is 3m_a0solc (6.6))
+# Used for the DLL file name. E.g.:
+# C:\Program Files (x86)\Racket\lib\libracket3m_XXXXXX.dll
+# MZSCHEME_DEBUG=no
+#
+# Perl interface:
+# PERL=[Path to Perl directory]
+# DYNAMIC_PERL=yes (to load the Perl DLL dynamically)
+# PERL_VER=[Perl version, in the form 55 (5.005), 56 (5.6.x),
+# 510 (5.10.x), etc]
+# (default is 524)
+#
+# Python interface:
+# PYTHON=[Path to Python directory]
+# DYNAMIC_PYTHON=yes (to load the Python DLL dynamically)
+# PYTHON_VER=[Python version, eg 22, 23, ..., 27] (default is 27)
+#
+# Python3 interface:
+# PYTHON3=[Path to Python3 directory]
+# DYNAMIC_PYTHON3=yes (to load the Python3 DLL dynamically)
+# PYTHON3_VER=[Python3 version, eg 30, 31] (default is 36)
+#
+# Ruby interface:
+# RUBY=[Path to Ruby directory]
+# DYNAMIC_RUBY=yes (to load the Ruby DLL dynamically)
+# RUBY_VER=[Ruby version, eg 19, 22] (default is 22)
+# RUBY_API_VER_LONG=[Ruby API version, eg 1.8, 1.9.1, 2.2.0]
+# (default is 2.2.0)
+# You must set RUBY_API_VER_LONG when change RUBY_VER.
+# Note: If you use Ruby 1.9.3, set as follows:
+# RUBY_VER=19
+# RUBY_API_VER_LONG=1.9.1 (not 1.9.3, because the API version is 1.9.1.)
+#
+# Tcl interface:
+# TCL=[Path to Tcl directory]
+# DYNAMIC_TCL=yes (to load the Tcl DLL dynamically)
+# TCL_VER=[Tcl version, e.g. 80, 83] (default is 86)
+# TCL_VER_LONG=[Tcl version, eg 8.3] (default is 8.6)
+# You must set TCL_VER_LONG when you set TCL_VER.
+# TCL_DLL=[Tcl dll name, e.g. tcl86.dll] (default is tcl86.dll)
+#
+# Cscope support: CSCOPE=yes
+#
+# Iconv library support (always dynamically loaded):
+# ICONV=[yes or no] (default is yes)
+#
+# Intl library support (always dynamically loaded):
+# GETTEXT=[yes or no] (default is yes)
+# See http://sourceforge.net/projects/gettext/
+#
+# PostScript printing: POSTSCRIPT=yes (default is no)
+#
+# Netbeans Support: NETBEANS=[yes or no] (default is yes if GUI is yes)
+# Requires CHANNEL.
+#
+# Netbeans Debugging Support: NBDEBUG=[yes or no] (should be no, yes
+# doesn't work)
+#
+# Inter process communication: CHANNEL=[yes or no] (default is yes if GUI
+# is yes)
+#
+# XPM Image Support: XPM=[path to XPM directory]
+# Default is "xpm", using the files included in the distribution.
+# Use "no" to disable this feature.
+#
+# Optimization: OPTIMIZE=[SPACE, SPEED, MAXSPEED] (default is MAXSPEED)
+#
+# Processor Version: CPUNR=[any, i586, i686, sse, sse2, avx, avx2] (default is
+# any)
+# avx is available on Visual C++ 2010 and after.
+# avx2 is available on Visual C++ 2013 Update 2 and after.
+#
+# Version Support: WINVER=[0x0501, 0x0502, 0x0600, 0x0601, 0x0602,
+# 0x0603, 0x0A00] (default is 0x0501)
+# Supported versions depends on your target SDK, check SDKDDKVer.h
+# See https://docs.microsoft.com/en-us/cpp/porting/modifying-winver-and-win32-winnt
+#
+# Debug version: DEBUG=yes
+# Mapfile: MAP=[no, yes or lines] (default is yes)
+# no: Don't write a mapfile.
+# yes: Write a normal mapfile.
+# lines: Write a mapfile with line numbers (only for VC6 and later)
+#
+# Static Code Analysis: ANALYZE=yes (works with VS2012 or later)
+#
+# You can combine any of these interfaces
+#
+# Example: To build the non-debug, GUI version with Perl interface:
+# nmake -f Make_mvc.mak GUI=yes PERL=C:\Perl
+#
+# DEBUG with Make_mvc.mak and Make_dvc.mak:
+# This makefile gives a fineness of control which is not supported in
+# Visual C++ configuration files. Therefore, debugging requires a bit of
+# extra work.
+# Make_dvc.mak is a Visual C++ project to access that support. It may be
+# badly out of date for the Visual C++ you are using...
+# To use Make_dvc.mak:
+# 1) Build Vim with Make_mvc.mak.
+# Use a "DEBUG=yes" argument to build Vim with debug support.
+# E.g. the following builds gvimd.exe:
+# nmake -f Make_mvc.mak debug=yes gui=yes
+# 2) Use MS Devstudio and set it up to allow that file to be debugged:
+# i) Pass Make_dvc.mak to the IDE.
+# Use the "open workspace" menu entry to load Make_dvc.mak.
+# Alternatively, from the command line:
+# msdev /nologo Make_dvc.mak
+# Note: Make_dvc.mak is in VC4.0 format. Later VC versions see
+# this and offer to convert it to their own format. Accept that.
+# It creates a file called Make_dvc.dsw which can then be used
+# for further operations. E.g.
+# msdev /nologo Make_dvc.dsw
+# ii) Set the built executable for debugging:
+# a) Alt+F7/Debug takes you to the Debug dialog.
+# b) Fill "Executable for debug session". e.g. gvimd.exe
+# c) Fill "Program arguments". e.g. -R dosinst.c
+# d) Complete the dialog
+# 3) You can now debug the executable you built with Make_mvc.mak
+#
+# Note: Make_dvc.mak builds vimrun.exe, because it must build something
+# to be a valid makefile..
+
+### See feature.h for a list of optionals.
+# If you want to build some optional features without modifying the source,
+# you can set DEFINES on the command line, e.g.,
+# nmake -f Make_mvc.mvc "DEFINES=-DEMACS_TAGS"
+
+# Build on Windows NT/XP
+
+TARGETOS = WINNT
+
+!ifndef DIRECTX
+DIRECTX = $(GUI)
+!endif
+
+# Select one of eight object code directories, depends on GUI, OLE, DEBUG and
+# interfaces.
+# If you change something else, do "make clean" first!
+!if "$(GUI)" == "yes"
+OBJDIR = .\ObjG
+!else
+OBJDIR = .\ObjC
+!endif
+!if "$(DIRECTX)" == "yes"
+OBJDIR = $(OBJDIR)X
+!endif
+!if "$(OLE)" == "yes"
+OBJDIR = $(OBJDIR)O
+!endif
+!ifdef LUA
+OBJDIR = $(OBJDIR)U
+!endif
+!ifdef PERL
+OBJDIR = $(OBJDIR)L
+!endif
+!ifdef PYTHON
+OBJDIR = $(OBJDIR)Y
+!endif
+!ifdef PYTHON3
+OBJDIR = $(OBJDIR)H
+!endif
+!ifdef TCL
+OBJDIR = $(OBJDIR)T
+!endif
+!ifdef RUBY
+OBJDIR = $(OBJDIR)R
+!endif
+!ifdef MZSCHEME
+OBJDIR = $(OBJDIR)Z
+!endif
+!if "$(DEBUG)" == "yes"
+OBJDIR = $(OBJDIR)d
+!endif
+
+# If you include Win32.mak, it requires that CPU be set appropriately.
+# To cross-compile for Win64, set CPU=AMD64 or CPU=IA64.
+
+!ifdef PROCESSOR_ARCHITECTURE
+# We're on Windows NT or using VC 6+
+! ifdef CPU
+ASSEMBLY_ARCHITECTURE=$(CPU)
+# Using I386 for $ASSEMBLY_ARCHITECTURE doesn't work for VC7.
+! if "$(CPU)" == "I386"
+CPU = i386
+! endif
+! else # !CPU
+CPU = i386
+! if !defined(PLATFORM) && defined(TARGET_CPU)
+PLATFORM = $(TARGET_CPU)
+! endif
+! ifdef PLATFORM
+! if ("$(PLATFORM)" == "x64") || ("$(PLATFORM)" == "X64")
+CPU = AMD64
+! elseif ("$(PLATFORM)" != "x86") && ("$(PLATFORM)" != "X86")
+! error *** ERROR Unknown target platform "$(PLATFORM)". Make aborted.
+! endif
+! endif # !PLATFORM
+! endif
+!else # !PROCESSOR_ARCHITECTURE
+# We're on Windows 95
+CPU = i386
+!endif # !PROCESSOR_ARCHITECTURE
+ASSEMBLY_ARCHITECTURE=$(CPU)
+OBJDIR = $(OBJDIR)$(CPU)
+
+# Build a retail version by default
+
+!if "$(DEBUG)" != "yes"
+NODEBUG = 1
+!else
+!undef NODEBUG
+MAKEFLAGS_GVIMEXT = DEBUG=yes
+!endif
+
+
+# Get all sorts of useful, standard macros from the Platform SDK,
+# if SDK_INCLUDE_DIR is set or USE_WIN32MAK is set to "yes".
+
+!ifdef SDK_INCLUDE_DIR
+!include $(SDK_INCLUDE_DIR)\Win32.mak
+!elseif "$(USE_WIN32MAK)"=="yes"
+!include <Win32.mak>
+!else
+link = link
+!endif
+
+
+# Check VC version.
+!if [echo MSVCVER=_MSC_VER> msvcver.c && $(CC) /EP msvcver.c > msvcver.~ 2> nul]
+!message *** ERROR
+!message Cannot run Visual C to determine its version. Make sure cl.exe is in your PATH.
+!message This can usually be done by running "vcvarsall.bat", located in the bin directory where Visual Studio was installed.
+!error Make aborted.
+!else
+!include msvcver.~
+!if [del msvcver.c msvcver.~]
+!endif
+!endif
+
+!if $(MSVCVER) < 1900
+MSVC_MAJOR = ($(MSVCVER) / 100 - 6)
+MSVCRT_VER = ($(MSVCVER) / 10 - 60)
+# Visual C++ 2017 needs special handling
+# it has an _MSC_VER of 1910->14.1, but is actually v15 with runtime v140
+# TODO: what's the maximum value?
+!elseif $(MSVCVER) >= 1910
+MSVC_MAJOR = 15
+MSVCRT_VER = 140
+!else
+MSVC_MAJOR = ($(MSVCVER) / 100 - 5)
+MSVCRT_VER = ($(MSVCVER) / 10 - 50)
+!endif
+
+# Calculate MSVC_FULL for Visual C++ 8 and up.
+!if $(MSVC_MAJOR) >= 8
+! if [echo MSVC_FULL=_MSC_FULL_VER> msvcfullver.c && $(CC) /EP msvcfullver.c > msvcfullver.~ 2> nul]
+! message *** ERROR
+! message Cannot run Visual C to determine its version. Make sure cl.exe is in your PATH.
+! message This can usually be done by running "vcvarsall.bat", located in the bin directory where Visual Studio was installed.
+! error Make aborted.
+! else
+! include msvcfullver.~
+! if [del msvcfullver.c msvcfullver.~]
+! endif
+! endif
+!endif
+
+
+# Calculate MSVCRT_VER
+!if [(set /a MSVCRT_VER="$(MSVCRT_VER)" > nul) && set MSVCRT_VER > msvcrtver.~] == 0
+!include msvcrtver.~
+!if [del msvcrtver.~]
+!endif
+!endif
+
+# Base name of the msvcrXX.dll
+!if $(MSVCRT_VER) <= 60
+MSVCRT_NAME = msvcrt
+!elseif $(MSVCRT_VER) <= 130
+MSVCRT_NAME = msvcr$(MSVCRT_VER)
+!else
+MSVCRT_NAME = vcruntime$(MSVCRT_VER)
+!endif
+
+!if $(MSVC_MAJOR) == 6
+CPU = ix86
+!endif
+
+
+# Flag to turn on Win64 compatibility warnings for VC7.x and VC8.
+WP64CHECK = /Wp64
+
+# Use multiprocess build
+USE_MP = yes
+
+#>>>>> path of the compiler and linker; name of include and lib directories
+# PATH = c:\msvc20\bin;$(PATH)
+# INCLUDE = c:\msvc20\include
+# LIB = c:\msvc20\lib
+
+!if "$(FEATURES)"==""
+FEATURES = HUGE
+!endif
+
+!ifndef CTAGS
+# this assumes ctags is Exuberant ctags
+CTAGS = ctags -I INIT+ --fields=+S
+!endif
+
+!ifndef CSCOPE
+CSCOPE = yes
+!endif
+
+!if "$(CSCOPE)" == "yes"
+# CSCOPE - Include support for Cscope
+CSCOPE_INCL = if_cscope.h
+CSCOPE_OBJ = $(OBJDIR)/if_cscope.obj
+CSCOPE_DEFS = -DFEAT_CSCOPE
+!endif
+
+!ifndef TERMINAL
+!if "$(FEATURES)"=="HUGE"
+TERMINAL = yes
+!else
+TERMINAL = no
+!endif
+!endif
+
+!if "$(TERMINAL)" == "yes"
+TERM_OBJ = \
+ $(OBJDIR)/terminal.obj \
+ $(OBJDIR)/encoding.obj \
+ $(OBJDIR)/keyboard.obj \
+ $(OBJDIR)/mouse.obj \
+ $(OBJDIR)/parser.obj \
+ $(OBJDIR)/pen.obj \
+ $(OBJDIR)/termscreen.obj \
+ $(OBJDIR)/state.obj \
+ $(OBJDIR)/unicode.obj \
+ $(OBJDIR)/vterm.obj
+TERM_DEFS = -DFEAT_TERMINAL
+TERM_DEPS = \
+ libvterm/include/vterm.h \
+ libvterm/include/vterm_keycodes.h \
+ libvterm/src/rect.h \
+ libvterm/src/utf8.h \
+ libvterm/src/vterm_internal.h
+!endif
+
+!ifndef NETBEANS
+NETBEANS = $(GUI)
+!endif
+
+!ifndef CHANNEL
+!if "$(FEATURES)"=="HUGE"
+CHANNEL = yes
+!else
+CHANNEL = $(GUI)
+!endif
+!endif
+
+# GUI sepcific features.
+!if "$(GUI)" == "yes"
+# Only allow NETBEANS for a GUI build and CHANNEL.
+!if "$(NETBEANS)" == "yes" && "$(CHANNEL)" == "yes"
+# NETBEANS - Include support for Netbeans integration
+NETBEANS_PRO = proto/netbeans.pro
+NETBEANS_OBJ = $(OBJDIR)/netbeans.obj
+NETBEANS_DEFS = -DFEAT_NETBEANS_INTG
+
+!if "$(NBDEBUG)" == "yes"
+NBDEBUG_DEFS = -DNBDEBUG
+NBDEBUG_INCL = nbdebug.h
+NBDEBUG_SRC = nbdebug.c
+!endif
+NETBEANS_LIB = WSock32.lib
+!endif
+
+# DirectWrite (DirectX)
+!if "$(DIRECTX)" == "yes"
+DIRECTX_DEFS = -DFEAT_DIRECTX -DDYNAMIC_DIRECTX
+!if "$(COLOR_EMOJI)" != "no"
+DIRECTX_DEFS = $(DIRECTX_DEFS) -DFEAT_DIRECTX_COLOR_EMOJI
+!endif
+DIRECTX_INCL = gui_dwrite.h
+DIRECTX_OBJ = $(OUTDIR)\gui_dwrite.obj
+!endif
+
+# Only allow XPM for a GUI build.
+!ifndef XPM
+!ifndef USE_MSVCRT
+# Both XPM and USE_MSVCRT are not set, use the included xpm files, depending
+# on the architecture.
+!if "$(CPU)" == "AMD64"
+XPM = xpm\x64
+!elseif "$(CPU)" == "i386"
+XPM = xpm\x86
+!else
+XPM = no
+!endif
+!else # USE_MSVCRT
+XPM = no
+!endif # USE_MSVCRT
+!endif # XPM
+!if "$(XPM)" != "no"
+# XPM - Include support for XPM signs
+# See the xpm directory for more information.
+XPM_OBJ = $(OBJDIR)/xpm_w32.obj
+XPM_DEFS = -DFEAT_XPM_W32
+!if $(MSVC_MAJOR) >= 14
+# VC14 cannot use a library built by VC12 or eariler, because VC14 uses
+# Universal CRT.
+XPM_LIB = $(XPM)\lib-vc14\libXpm.lib
+!else
+XPM_LIB = $(XPM)\lib\libXpm.lib
+!endif
+XPM_INC = -I $(XPM)\include -I $(XPM)\..\include
+!endif
+!endif
+
+!if "$(CHANNEL)" == "yes"
+CHANNEL_PRO = proto/channel.pro
+CHANNEL_OBJ = $(OBJDIR)/channel.obj
+CHANNEL_DEFS = -DFEAT_JOB_CHANNEL
+
+NETBEANS_LIB = WSock32.lib
+!endif
+
+# Set which version of the CRT to use
+!if defined(USE_MSVCRT)
+# CVARS = $(cvarsdll)
+# !elseif defined(MULTITHREADED)
+# CVARS = $(cvarsmt)
+!else
+# CVARS = $(cvars)
+# CVARS = $(cvarsmt)
+!endif
+
+# need advapi32.lib for GetUserName()
+# need shell32.lib for ExtractIcon()
+# need netapi32.lib for NetUserEnum()
+# gdi32.lib and comdlg32.lib for printing support
+# ole32.lib and uuid.lib are needed for FEAT_SHORTCUT
+CON_LIB = oldnames.lib kernel32.lib advapi32.lib shell32.lib gdi32.lib \
+ comdlg32.lib ole32.lib netapi32.lib uuid.lib /machine:$(CPU)
+!if "$(DELAYLOAD)" == "yes"
+CON_LIB = $(CON_LIB) /DELAYLOAD:comdlg32.dll /DELAYLOAD:ole32.dll DelayImp.lib
+!endif
+
+### Set the default $(WINVER) to make it work with VC++7.0 (VS.NET)
+!ifndef WINVER
+WINVER = 0x0501
+!endif
+
+# If you have a fixed directory for $VIM or $VIMRUNTIME, other than the normal
+# default, use these lines.
+#VIMRCLOC = somewhere
+#VIMRUNTIMEDIR = somewhere
+
+CFLAGS = -c /W3 /nologo $(CVARS) -I. -Iproto -DHAVE_PATHDEF -DWIN32 \
+ $(CSCOPE_DEFS) $(TERM_DEFS) $(NETBEANS_DEFS) $(CHANNEL_DEFS) \
+ $(NBDEBUG_DEFS) $(XPM_DEFS) \
+ $(DEFINES) -DWINVER=$(WINVER) -D_WIN32_WINNT=$(WINVER)
+
+#>>>>> end of choices
+###########################################################################
+
+DEL_TREE = rmdir /s /q
+
+INTDIR=$(OBJDIR)
+OUTDIR=$(OBJDIR)
+
+### Validate CPUNR
+!ifndef CPUNR
+# default to untargeted code
+CPUNR = any
+!elseif "$(CPUNR)" == "i386" || "$(CPUNR)" == "i486"
+# alias i386 and i486 to i586
+! message *** WARNING CPUNR=$(CPUNR) is not a valid target architecture.
+! message Windows XP is the minimum target OS, with a minimum target
+! message architecture of i586.
+! message Retargeting to i586
+CPUNR = i586
+!elseif "$(CPUNR)" == "pentium4"
+# alias pentium4 to sse2
+! message *** WARNING CPUNR=pentium4 is deprecated in favour of sse2.
+! message Retargeting to sse2.
+CPUNR = sse2
+!elseif "$(CPUNR)" != "any" && "$(CPUNR)" != "i586" && "$(CPUNR)" != "i686" && "$(CPUNR)" != "sse" && "$(CPUNR)" != "sse2" && "$(CPUNR)" != "avx" && "$(CPUNR)" != "avx2"
+! error *** ERROR Unknown target architecture "$(CPUNR)". Make aborted.
+!endif
+
+# Convert processor ID to MVC-compatible number
+!if $(MSVC_MAJOR) < 8
+! if "$(CPUNR)" == "i586"
+CPUARG = /G5
+! elseif "$(CPUNR)" == "i686"
+CPUARG = /G6
+! elseif "$(CPUNR)" == "sse"
+CPUARG = /G6 /arch:SSE
+! elseif "$(CPUNR)" == "sse2"
+CPUARG = /G7 /arch:SSE2
+! elseif "$(CPUNR)" == "avx" || "$(CPUNR)" == "avx2"
+! message AVX/AVX2 Instruction Sets are not supported by Visual C++ v$(MSVC_MAJOR)
+! message Falling back to SSE2
+CPUARG = /G7 /arch:SSE2
+! elseif "$(CPUNR)" == "any"
+CPUARG =
+! endif
+!else
+# IA32/SSE/SSE2 are only supported on x86
+! if "$(ASSEMBLY_ARCHITECTURE)" == "i386" && ("$(CPUNR)" == "i586" || "$(CPUNR)" == "i686" || "$(CPUNR)" == "any")
+# VC<11 generates fp87 code by default
+! if $(MSVC_MAJOR) < 11
+CPUARG =
+# VC>=11 needs explicit insturctions to generate fp87 code
+! else
+CPUARG = /arch:IA32
+! endif
+! elseif "$(ASSEMBLY_ARCHITECTURE)" == "i386" && "$(CPUNR)" == "sse"
+CPUARG = /arch:SSE
+! elseif "$(ASSEMBLY_ARCHITECTURE)" == "i386" && "$(CPUNR)" == "sse2"
+CPUARG = /arch:SSE2
+! elseif "$(CPUNR)" == "avx"
+# AVX is only supported by VC 10 and up
+! if $(MSVC_MAJOR) < 10
+! message AVX Instruction Set is not supported by Visual C++ v$(MSVC_MAJOR)
+! if "$(ASSEMBLY_ARCHITECTURE)" == "i386"
+! message Falling back to SSE2
+CPUARG = /arch:SSE2
+! else
+CPUARG =
+! endif
+! else
+CPUARG = /arch:AVX
+! endif
+! elseif "$(CPUNR)" == "avx2"
+# AVX is only supported by VC 10 and up
+! if $(MSVC_MAJOR) < 10
+! message AVX2 Instruction Set is not supported by Visual C++ v$(MSVC_MAJOR)
+! if "$(ASSEMBLY_ARCHITECTURE)" == "i386"
+! message Falling back to SSE2
+CPUARG = /arch:SSE2
+! else
+CPUARG =
+! endif
+# AVX2 is only supported by VC 12U2 and up
+# 180030501 is the full version number for Visual Studio 2013/VC 12 Update 2
+! elseif $(MSVC_FULL) < 180030501
+! message AVX2 Instruction Set is not supported by Visual C++ v$(MSVC_MAJOR)-$(MSVC_FULL)
+! message Falling back to AVX
+CPUARG = /arch:AVX
+! else
+CPUARG = /arch:AVX2
+! endif
+! endif
+!endif
+
+# Pass CPUARG to GvimExt, to avoid using version-dependent defaults
+MAKEFLAGS_GVIMEXT = $(MAKEFLAGS_GVIMEXT) CPUARG="$(CPUARG)"
+
+
+LIBC =
+DEBUGINFO = /Zi
+
+# Don't use /nodefaultlib on MSVC 14
+!if $(MSVC_MAJOR) >= 14
+NODEFAULTLIB =
+!else
+NODEFAULTLIB = /nodefaultlib
+!endif
+
+# Use multiprocess build on MSVC 10
+!if "$(USE_MP)"=="yes"
+!if $(MSVC_MAJOR) >= 10
+CFLAGS = $(CFLAGS) /MP
+!endif
+!endif
+
+
+!ifdef NODEBUG
+VIM = vim
+!if "$(OPTIMIZE)" == "SPACE"
+OPTFLAG = /O1
+!elseif "$(OPTIMIZE)" == "SPEED"
+OPTFLAG = /O2
+!else # MAXSPEED
+OPTFLAG = /Ox
+!endif
+
+!if $(MSVC_MAJOR) >= 8
+# Use link time code generation if not worried about size
+!if "$(OPTIMIZE)" != "SPACE"
+OPTFLAG = $(OPTFLAG) /GL
+!endif
+!endif
+
+# (/Wp64 is deprecated in VC9 and generates an obnoxious warning.)
+!if ($(MSVC_MAJOR) == 7) || ($(MSVC_MAJOR) == 8)
+CFLAGS=$(CFLAGS) $(WP64CHECK)
+!endif
+
+# VC10 or later has stdint.h.
+!if $(MSVC_MAJOR) >= 10
+CFLAGS = $(CFLAGS) -DHAVE_STDINT_H
+!endif
+
+# Static code analysis generally available starting with VS2012 (VC11) or
+# Windows SDK 7.1 (VC10)
+!if ("$(ANALYZE)" == "yes") && ($(MSVC_MAJOR) >= 10)
+CFLAGS=$(CFLAGS) /analyze
+!endif
+
+CFLAGS = $(CFLAGS) $(OPTFLAG) -DNDEBUG $(CPUARG)
+RCFLAGS = $(rcflags) $(rcvars) -DNDEBUG
+! ifdef USE_MSVCRT
+CFLAGS = $(CFLAGS) /MD
+LIBC = msvcrt.lib
+! else
+LIBC = libcmt.lib
+CFLAGS = $(CFLAGS) /Zl /MT
+! endif
+!else # DEBUG
+VIM = vimd
+! if ("$(CPU)" == "i386") || ("$(CPU)" == "ix86")
+DEBUGINFO = /ZI
+! endif
+CFLAGS = $(CFLAGS) -D_DEBUG -DDEBUG /Od
+RCFLAGS = $(rcflags) $(rcvars) -D_DEBUG -DDEBUG
+# The /fixed:no is needed for Quantify. Assume not 4.? as unsupported in VC4.0.
+! if $(MSVC_MAJOR) == 4
+LIBC =
+! else
+LIBC = /fixed:no
+! endif
+! ifdef USE_MSVCRT
+CFLAGS = $(CFLAGS) /MDd
+LIBC = $(LIBC) msvcrtd.lib
+! else
+LIBC = $(LIBC) libcmtd.lib
+CFLAGS = $(CFLAGS) /Zl /MTd
+! endif
+!endif # DEBUG
+
+!include Make_all.mak
+!include testdir\Make_all.mak
+
+INCL = vim.h alloc.h arabic.h ascii.h ex_cmds.h farsi.h feature.h globals.h \
+ keymap.h macros.h option.h os_dos.h os_win32.h proto.h regexp.h \
+ spell.h structs.h term.h beval.h $(NBDEBUG_INCL)
+
+OBJ = \
+ $(OUTDIR)\arabic.obj \
+ $(OUTDIR)\autocmd.obj \
+ $(OUTDIR)\beval.obj \
+ $(OUTDIR)\blob.obj \
+ $(OUTDIR)\blowfish.obj \
+ $(OUTDIR)\buffer.obj \
+ $(OUTDIR)\charset.obj \
+ $(OUTDIR)\crypt.obj \
+ $(OUTDIR)\crypt_zip.obj \
+ $(OUTDIR)\dict.obj \
+ $(OUTDIR)\diff.obj \
+ $(OUTDIR)\digraph.obj \
+ $(OUTDIR)\edit.obj \
+ $(OUTDIR)\eval.obj \
+ $(OUTDIR)\evalfunc.obj \
+ $(OUTDIR)\ex_cmds.obj \
+ $(OUTDIR)\ex_cmds2.obj \
+ $(OUTDIR)\ex_docmd.obj \
+ $(OUTDIR)\ex_eval.obj \
+ $(OUTDIR)\ex_getln.obj \
+ $(OUTDIR)\farsi.obj \
+ $(OUTDIR)\fileio.obj \
+ $(OUTDIR)\fold.obj \
+ $(OUTDIR)\getchar.obj \
+ $(OUTDIR)\hardcopy.obj \
+ $(OUTDIR)\hashtab.obj \
+ $(OUTDIR)\indent.obj \
+ $(OUTDIR)\json.obj \
+ $(OUTDIR)\list.obj \
+ $(OUTDIR)\main.obj \
+ $(OUTDIR)\mark.obj \
+ $(OUTDIR)\mbyte.obj \
+ $(OUTDIR)\memfile.obj \
+ $(OUTDIR)\memline.obj \
+ $(OUTDIR)\menu.obj \
+ $(OUTDIR)\message.obj \
+ $(OUTDIR)\misc1.obj \
+ $(OUTDIR)\misc2.obj \
+ $(OUTDIR)\move.obj \
+ $(OUTDIR)\normal.obj \
+ $(OUTDIR)\ops.obj \
+ $(OUTDIR)\option.obj \
+ $(OUTDIR)\os_mswin.obj \
+ $(OUTDIR)\winclip.obj \
+ $(OUTDIR)\os_win32.obj \
+ $(OUTDIR)\pathdef.obj \
+ $(OUTDIR)\popupmnu.obj \
+ $(OUTDIR)\quickfix.obj \
+ $(OUTDIR)\regexp.obj \
+ $(OUTDIR)\screen.obj \
+ $(OUTDIR)\search.obj \
+ $(OUTDIR)\sha256.obj \
+ $(OUTDIR)\sign.obj \
+ $(OUTDIR)\spell.obj \
+ $(OUTDIR)\spellfile.obj \
+ $(OUTDIR)\syntax.obj \
+ $(OUTDIR)\tag.obj \
+ $(OUTDIR)\term.obj \
+ $(OUTDIR)\textprop.obj \
+ $(OUTDIR)\ui.obj \
+ $(OUTDIR)\undo.obj \
+ $(OUTDIR)\userfunc.obj \
+ $(OUTDIR)\window.obj \
+ $(OUTDIR)\vim.res
+
+!if "$(OLE)" == "yes"
+CFLAGS = $(CFLAGS) -DFEAT_OLE
+RCFLAGS = $(RCFLAGS) -DFEAT_OLE
+OLE_OBJ = $(OUTDIR)\if_ole.obj
+OLE_IDL = if_ole.idl
+OLE_LIB = oleaut32.lib
+!endif
+
+!if "$(IME)" == "yes"
+CFLAGS = $(CFLAGS) -DFEAT_MBYTE_IME
+!ifndef DYNAMIC_IME
+DYNAMIC_IME = yes
+!endif
+!if "$(DYNAMIC_IME)" == "yes"
+CFLAGS = $(CFLAGS) -DDYNAMIC_IME
+!else
+IME_LIB = imm32.lib
+!endif
+!endif
+
+!if "$(GIME)" == "yes"
+CFLAGS = $(CFLAGS) -DGLOBAL_IME
+OBJ = $(OBJ) $(OUTDIR)\dimm_i.obj $(OUTDIR)\glbl_ime.obj
+!endif
+
+!if "$(GUI)" == "yes"
+SUBSYSTEM = windows
+CFLAGS = $(CFLAGS) -DFEAT_GUI_W32
+RCFLAGS = $(RCFLAGS) -DFEAT_GUI_W32
+VIM = g$(VIM)
+GUI_INCL = \
+ gui.h
+GUI_OBJ = \
+ $(OUTDIR)\gui.obj \
+ $(OUTDIR)\gui_beval.obj \
+ $(OUTDIR)\gui_w32.obj \
+ $(OUTDIR)\os_w32exe.obj
+GUI_LIB = \
+ gdi32.lib version.lib $(IME_LIB) \
+ winspool.lib comctl32.lib advapi32.lib shell32.lib netapi32.lib \
+ /machine:$(CPU)
+!else
+SUBSYSTEM = console
+CUI_INCL = iscygpty.h
+CUI_OBJ = $(OUTDIR)\iscygpty.obj
+!endif
+SUBSYSTEM_TOOLS = console
+
+XDIFF_OBJ = $(OBJDIR)/xdiffi.obj \
+ $(OBJDIR)/xemit.obj \
+ $(OBJDIR)/xprepare.obj \
+ $(OBJDIR)/xutils.obj \
+ $(OBJDIR)/xhistogram.obj \
+ $(OBJDIR)/xpatience.obj
+
+XDIFF_DEPS = \
+ xdiff/xdiff.h \
+ xdiff/xdiffi.h \
+ xdiff/xemit.h \
+ xdiff/xinclude.h \
+ xdiff/xmacros.h \
+ xdiff/xprepare.h \
+ xdiff/xtypes.h \
+ xdiff/xutils.h
+
+
+!if "$(SUBSYSTEM_VER)" != ""
+SUBSYSTEM = $(SUBSYSTEM),$(SUBSYSTEM_VER)
+SUBSYSTEM_TOOLS = $(SUBSYSTEM_TOOLS),$(SUBSYSTEM_VER)
+# Pass SUBSYSTEM_VER to GvimExt and other tools
+MAKEFLAGS_GVIMEXT = $(MAKEFLAGS_GVIMEXT) SUBSYSTEM_VER=$(SUBSYSTEM_VER)
+MAKEFLAGS_TOOLS = $(MAKEFLAGS_TOOLS) SUBSYSTEM_VER=$(SUBSYSTEM_VER)
+!endif
+
+!if "$(GUI)" == "yes" && "$(DIRECTX)" == "yes"
+CFLAGS = $(CFLAGS) $(DIRECTX_DEFS)
+GUI_INCL = $(GUI_INCL) $(DIRECTX_INCL)
+GUI_OBJ = $(GUI_OBJ) $(DIRECTX_OBJ)
+!endif
+
+# iconv.dll library (dynamically loaded)
+!ifndef ICONV
+ICONV = yes
+!endif
+!if "$(ICONV)" == "yes"
+CFLAGS = $(CFLAGS) -DDYNAMIC_ICONV
+!endif
+
+# libintl.dll library
+!ifndef GETTEXT
+GETTEXT = yes
+!endif
+!if "$(GETTEXT)" == "yes"
+CFLAGS = $(CFLAGS) -DDYNAMIC_GETTEXT
+!endif
+
+# TCL interface
+!ifdef TCL
+!ifndef TCL_VER
+TCL_VER = 86
+TCL_VER_LONG = 8.6
+!endif
+!message Tcl requested (version $(TCL_VER)) - root dir is "$(TCL)"
+!if "$(DYNAMIC_TCL)" == "yes"
+!message Tcl DLL will be loaded dynamically
+!ifndef TCL_DLL
+TCL_DLL = tcl$(TCL_VER).dll
+!endif
+CFLAGS = $(CFLAGS) -DFEAT_TCL -DDYNAMIC_TCL -DDYNAMIC_TCL_DLL=\"$(TCL_DLL)\" \
+ -DDYNAMIC_TCL_VER=\"$(TCL_VER_LONG)\"
+TCL_OBJ = $(OUTDIR)\if_tcl.obj
+TCL_INC = /I "$(TCL)\Include" /I "$(TCL)"
+TCL_LIB = "$(TCL)\lib\tclstub$(TCL_VER).lib"
+!else
+CFLAGS = $(CFLAGS) -DFEAT_TCL
+TCL_OBJ = $(OUTDIR)\if_tcl.obj
+TCL_INC = /I "$(TCL)\Include" /I "$(TCL)"
+TCL_LIB = $(TCL)\lib\tcl$(TCL_VER)vc.lib
+!endif
+!endif
+
+# Lua interface
+!ifdef LUA
+!ifndef LUA_VER
+LUA_VER = 53
+!endif
+!message Lua requested (version $(LUA_VER)) - root dir is "$(LUA)"
+!if "$(DYNAMIC_LUA)" == "yes"
+!message Lua DLL will be loaded dynamically
+!endif
+CFLAGS = $(CFLAGS) -DFEAT_LUA
+LUA_OBJ = $(OUTDIR)\if_lua.obj
+LUA_INC = /I "$(LUA)\include" /I "$(LUA)"
+!if "$(DYNAMIC_LUA)" == "yes"
+CFLAGS = $(CFLAGS) -DDYNAMIC_LUA \
+ -DDYNAMIC_LUA_DLL=\"lua$(LUA_VER).dll\"
+LUA_LIB = /nodefaultlib:lua$(LUA_VER).lib
+!else
+LUA_LIB = "$(LUA)\lib\lua$(LUA_VER).lib"
+!endif
+!endif
+
+!ifdef PYTHON
+!ifdef PYTHON3
+DYNAMIC_PYTHON=yes
+DYNAMIC_PYTHON3=yes
+!endif
+!endif
+
+# PYTHON interface
+!ifdef PYTHON
+!ifndef PYTHON_VER
+PYTHON_VER = 27
+!endif
+!message Python requested (version $(PYTHON_VER)) - root dir is "$(PYTHON)"
+!if "$(DYNAMIC_PYTHON)" == "yes"
+!message Python DLL will be loaded dynamically
+!endif
+CFLAGS = $(CFLAGS) -DFEAT_PYTHON
+PYTHON_OBJ = $(OUTDIR)\if_python.obj
+PYTHON_INC = /I "$(PYTHON)\Include" /I "$(PYTHON)\PC"
+!if "$(DYNAMIC_PYTHON)" == "yes"
+CFLAGS = $(CFLAGS) -DDYNAMIC_PYTHON \
+ -DDYNAMIC_PYTHON_DLL=\"python$(PYTHON_VER).dll\"
+PYTHON_LIB = /nodefaultlib:python$(PYTHON_VER).lib
+!else
+PYTHON_LIB = $(PYTHON)\libs\python$(PYTHON_VER).lib
+!endif
+!endif
+
+# PYTHON3 interface
+!ifdef PYTHON3
+!ifndef PYTHON3_VER
+PYTHON3_VER = 36
+!endif
+!message Python3 requested (version $(PYTHON3_VER)) - root dir is "$(PYTHON3)"
+!if "$(DYNAMIC_PYTHON3)" == "yes"
+!message Python3 DLL will be loaded dynamically
+!endif
+CFLAGS = $(CFLAGS) -DFEAT_PYTHON3
+PYTHON3_OBJ = $(OUTDIR)\if_python3.obj
+PYTHON3_INC = /I "$(PYTHON3)\Include" /I "$(PYTHON3)\PC"
+!if "$(DYNAMIC_PYTHON3)" == "yes"
+CFLAGS = $(CFLAGS) -DDYNAMIC_PYTHON3 \
+ -DDYNAMIC_PYTHON3_DLL=\"python$(PYTHON3_VER).dll\"
+PYTHON3_LIB = /nodefaultlib:python$(PYTHON3_VER).lib
+!else
+PYTHON3_LIB = $(PYTHON3)\libs\python$(PYTHON3_VER).lib
+!endif
+!endif
+
+# MzScheme interface
+!ifdef MZSCHEME
+!message MzScheme requested - root dir is "$(MZSCHEME)"
+!ifndef MZSCHEME_VER
+MZSCHEME_VER = 3m_a0solc
+!endif
+!ifndef MZSCHEME_COLLECTS
+MZSCHEME_COLLECTS=$(MZSCHEME)\collects
+!endif
+CFLAGS = $(CFLAGS) -DFEAT_MZSCHEME -I "$(MZSCHEME)\include"
+!if EXIST("$(MZSCHEME)\lib\msvc\libmzsch$(MZSCHEME_VER).lib")
+MZSCHEME_MAIN_LIB=mzsch
+!else
+MZSCHEME_MAIN_LIB=racket
+!endif
+!if (EXIST("$(MZSCHEME)\lib\lib$(MZSCHEME_MAIN_LIB)$(MZSCHEME_VER).dll") \
+ && !EXIST("$(MZSCHEME)\lib\libmzgc$(MZSCHEME_VER).dll")) \
+ || (EXIST("$(MZSCHEME)\lib\msvc\lib$(MZSCHEME_MAIN_LIB)$(MZSCHEME_VER).lib") \
+ && !EXIST("$(MZSCHEME)\lib\msvc\libmzgc$(MZSCHEME_VER).lib"))
+!message Building with Precise GC
+MZSCHEME_PRECISE_GC = yes
+CFLAGS = $(CFLAGS) -DMZ_PRECISE_GC
+!endif
+!if "$(DYNAMIC_MZSCHEME)" == "yes"
+!message MzScheme DLLs will be loaded dynamically
+CFLAGS = $(CFLAGS) -DDYNAMIC_MZSCHEME
+!if "$(MZSCHEME_PRECISE_GC)" == "yes"
+# Precise GC does not use separate dll
+CFLAGS = $(CFLAGS) \
+ -DDYNAMIC_MZSCH_DLL=\"lib$(MZSCHEME_MAIN_LIB)$(MZSCHEME_VER).dll\" \
+ -DDYNAMIC_MZGC_DLL=\"lib$(MZSCHEME_MAIN_LIB)$(MZSCHEME_VER).dll\"
+!else
+CFLAGS = $(CFLAGS) \
+ -DDYNAMIC_MZSCH_DLL=\"lib$(MZSCHEME_MAIN_LIB)$(MZSCHEME_VER).dll\" \
+ -DDYNAMIC_MZGC_DLL=\"libmzgc$(MZSCHEME_VER).dll\"
+!endif
+!else
+!if "$(MZSCHEME_DEBUG)" == "yes"
+CFLAGS = $(CFLAGS) -DMZSCHEME_FORCE_GC
+!endif
+!if "$(MZSCHEME_PRECISE_GC)" == "yes"
+# Precise GC does not use separate dll
+!if EXIST("$(MZSCHEME)\lib\lib$(MZSCHEME_MAIN_LIB)$(MZSCHEME_VER).def")
+# create .lib from .def
+MZSCHEME_LIB = lib$(MZSCHEME_MAIN_LIB)$(MZSCHEME_VER).lib
+MZSCHEME_EXTRA_DEP = lib$(MZSCHEME_MAIN_LIB)$(MZSCHEME_VER).lib
+!else
+MZSCHEME_LIB = "$(MZSCHEME)\lib\msvc\lib$(MZSCHEME_MAIN_LIB)$(MZSCHEME_VER).lib"
+!endif
+!else
+MZSCHEME_LIB = "$(MZSCHEME)\lib\msvc\libmzgc$(MZSCHEME_VER).lib" \
+ "$(MZSCHEME)\lib\msvc\lib$(MZSCHEME_MAIN_LIB)$(MZSCHEME_VER).lib"
+!endif
+!endif
+MZSCHEME_OBJ = $(OUTDIR)\if_mzsch.obj
+# increase stack size
+MZSCHEME_LIB = $(MZSCHEME_LIB) /STACK:8388608
+MZSCHEME_INCL = if_mzsch.h
+!endif
+
+# Perl interface
+!ifdef PERL
+!ifndef PERL_VER
+PERL_VER = 524
+!endif
+!message Perl requested (version $(PERL_VER)) - root dir is "$(PERL)"
+!if "$(DYNAMIC_PERL)" == "yes"
+!if $(PERL_VER) >= 56
+!message Perl DLL will be loaded dynamically
+!else
+!message Dynamic loading is not supported for Perl versions earlier than 5.6.0
+!message Reverting to static loading...
+!undef DYNAMIC_PERL
+!endif
+!endif
+
+# Is Perl installed in architecture-specific directories?
+!if exist($(PERL)\Bin\MSWin32-x86)
+PERL_ARCH = \MSWin32-x86
+!endif
+
+PERL_INCDIR = $(PERL)\Lib$(PERL_ARCH)\Core
+
+# Version-dependent stuff
+!if $(PERL_VER) == 55
+PERL_LIB = $(PERL_INCDIR)\perl.lib
+!else
+PERL_DLL = perl$(PERL_VER).dll
+!if exist($(PERL_INCDIR)\perl$(PERL_VER).lib)
+PERL_LIB = $(PERL_INCDIR)\perl$(PERL_VER).lib
+!else
+# For ActivePerl 5.18 and later
+PERL_LIB = $(PERL_INCDIR)\libperl$(PERL_VER).a
+!endif
+!endif
+
+CFLAGS = $(CFLAGS) -DFEAT_PERL -DPERL_IMPLICIT_CONTEXT -DPERL_IMPLICIT_SYS
+
+# Do we want to load Perl dynamically?
+!if "$(DYNAMIC_PERL)" == "yes"
+CFLAGS = $(CFLAGS) -DDYNAMIC_PERL -DDYNAMIC_PERL_DLL=\"$(PERL_DLL)\"
+!undef PERL_LIB
+!endif
+
+PERL_EXE = $(PERL)\Bin$(PERL_ARCH)\perl
+PERL_INC = /I $(PERL_INCDIR)
+!if $(MSVC_MAJOR) <= 11
+# ActivePerl 5.20+ requires stdbool.h but VC2012 or earlier doesn't have it.
+# Use a stub stdbool.h.
+PERL_INC = $(PERL_INC) /I if_perl_msvc
+!endif
+PERL_OBJ = $(OUTDIR)\if_perl.obj $(OUTDIR)\if_perlsfio.obj
+XSUBPP = $(PERL)\lib\ExtUtils\xsubpp
+!if exist($(XSUBPP))
+XSUBPP = $(PERL_EXE) $(XSUBPP)
+!else
+XSUBPP = xsubpp
+!endif
+XSUBPP_TYPEMAP = $(PERL)\lib\ExtUtils\typemap
+
+!endif
+
+#
+# Support Ruby interface
+#
+!ifdef RUBY
+# Set default value
+!ifndef RUBY_VER
+RUBY_VER = 22
+!endif
+!ifndef RUBY_VER_LONG
+RUBY_VER_LONG = 2.2.0
+!endif
+!ifndef RUBY_API_VER_LONG
+RUBY_API_VER_LONG = $(RUBY_VER_LONG)
+!endif
+!ifndef RUBY_API_VER
+RUBY_API_VER = $(RUBY_API_VER_LONG:.=)
+!endif
+
+!if $(RUBY_VER) >= 18
+
+!ifndef RUBY_PLATFORM
+!if "$(CPU)" == "i386"
+RUBY_PLATFORM = i386-mswin32
+!else # CPU
+RUBY_PLATFORM = x64-mswin64
+!endif # CPU
+!if $(MSVCRT_VER) >= 70 && $(RUBY_VER) > 19
+RUBY_PLATFORM = $(RUBY_PLATFORM)_$(MSVCRT_VER)
+!endif # MSVCRT_VER
+!endif # RUBY_PLATFORM
+
+!ifndef RUBY_INSTALL_NAME
+!ifndef RUBY_MSVCRT_NAME
+# Base name of msvcrXX.dll which is used by ruby's dll.
+RUBY_MSVCRT_NAME = $(MSVCRT_NAME)
+!endif # RUBY_MSVCRT_NAME
+!if "$(CPU)" == "i386"
+RUBY_INSTALL_NAME = $(RUBY_MSVCRT_NAME)-ruby$(RUBY_API_VER)
+!else # CPU
+RUBY_INSTALL_NAME = x64-$(RUBY_MSVCRT_NAME)-ruby$(RUBY_API_VER)
+!endif # CPU
+!endif # RUBY_INSTALL_NAME
+
+!else # $(RUBY_VER) >= 18
+
+!ifndef RUBY_PLATFORM
+RUBY_PLATFORM = i586-mswin32
+!endif
+!ifndef RUBY_INSTALL_NAME
+RUBY_INSTALL_NAME = mswin32-ruby$(RUBY_API_VER)
+!endif
+
+!endif # $(RUBY_VER) >= 18
+
+!message Ruby requested (version $(RUBY_VER)) - root dir is "$(RUBY)"
+CFLAGS = $(CFLAGS) -DFEAT_RUBY
+RUBY_OBJ = $(OUTDIR)\if_ruby.obj
+!if $(RUBY_VER) >= 19
+RUBY_INC = /I "$(RUBY)\include\ruby-$(RUBY_API_VER_LONG)" /I "$(RUBY)\include\ruby-$(RUBY_API_VER_LONG)\$(RUBY_PLATFORM)"
+!else
+RUBY_INC = /I "$(RUBY)\lib\ruby\$(RUBY_API_VER_LONG)\$(RUBY_PLATFORM)"
+!endif
+RUBY_LIB = $(RUBY)\lib\$(RUBY_INSTALL_NAME).lib
+# Do we want to load Ruby dynamically?
+!if "$(DYNAMIC_RUBY)" == "yes"
+!message Ruby DLL will be loaded dynamically
+CFLAGS = $(CFLAGS) -DDYNAMIC_RUBY -DDYNAMIC_RUBY_VER=$(RUBY_VER) \
+ -DDYNAMIC_RUBY_DLL=\"$(RUBY_INSTALL_NAME).dll\"
+!undef RUBY_LIB
+!endif
+!endif # RUBY
+
+#
+# Support PostScript printing
+#
+!if "$(POSTSCRIPT)" == "yes"
+CFLAGS = $(CFLAGS) -DMSWINPS
+!endif # POSTSCRIPT
+
+#
+# FEATURES: TINY, SMALL, NORMAL, BIG or HUGE
+#
+CFLAGS = $(CFLAGS) -DFEAT_$(FEATURES)
+
+#
+# Always generate the .pdb file, so that we get debug symbols that can be used
+# on a crash (doesn't add overhead to the executable).
+# Generate edit-and-continue debug info when no optimization - allows to
+# debug more conveniently (able to look at variables which are in registers)
+#
+CFLAGS = $(CFLAGS) /Fd$(OUTDIR)/ $(DEBUGINFO)
+LINK_PDB = /PDB:$(VIM).pdb -debug
+
+#
+# End extra feature include
+#
+!message
+
+# CFLAGS with /Fo$(OUTDIR)/
+CFLAGS_OUTDIR=$(CFLAGS) /Fo$(OUTDIR)/
+
+# Add /opt:ref to remove unreferenced functions and data even when /DEBUG is
+# added.
+conflags = /nologo /subsystem:$(SUBSYSTEM) /opt:ref
+
+PATHDEF_SRC = $(OUTDIR)\pathdef.c
+
+!IF "$(MAP)" == "yes"
+# "/map" is for debugging
+conflags = $(conflags) /map
+!ELSEIF "$(MAP)" == "lines"
+# "/mapinfo:lines" is for debugging, only works for VC6 and later
+conflags = $(conflags) /map /mapinfo:lines
+!ENDIF
+
+LINKARGS1 = $(linkdebug) $(conflags)
+LINKARGS2 = $(CON_LIB) $(GUI_LIB) $(NODEFAULTLIB) $(LIBC) $(OLE_LIB) user32.lib \
+ $(LUA_LIB) $(MZSCHEME_LIB) $(PERL_LIB) $(PYTHON_LIB) $(PYTHON3_LIB) $(RUBY_LIB) \
+ $(TCL_LIB) $(NETBEANS_LIB) $(XPM_LIB) $(LINK_PDB)
+
+# Report link time code generation progress if used.
+!ifdef NODEBUG
+!if $(MSVC_MAJOR) >= 8
+!if "$(OPTIMIZE)" != "SPACE"
+LINKARGS1 = $(LINKARGS1) /LTCG:STATUS
+!endif
+!endif
+!endif
+
+!if $(MSVC_MAJOR) >= 11 && "$(CPU)" == "AMD64" && "$(GUI)" == "yes"
+# This option is required for VC2012 or later so that 64-bit gvim can
+# accept D&D from 32-bit applications. NOTE: This disables 64-bit ASLR,
+# therefore the security level becomes as same as VC2010.
+LINKARGS1 = $(LINKARGS1) /HIGHENTROPYVA:NO
+!endif
+
+all: $(VIM).exe \
+ vimrun.exe \
+ install.exe \
+ uninstal.exe \
+ xxd/xxd.exe \
+ tee/tee.exe \
+ GvimExt/gvimext.dll
+
+$(VIM).exe: $(OUTDIR) $(OBJ) $(XDIFF_OBJ) $(GUI_OBJ) $(CUI_OBJ) $(OLE_OBJ) $(OLE_IDL) $(MZSCHEME_OBJ) \
+ $(LUA_OBJ) $(PERL_OBJ) $(PYTHON_OBJ) $(PYTHON3_OBJ) $(RUBY_OBJ) $(TCL_OBJ) \
+ $(CSCOPE_OBJ) $(TERM_OBJ) $(NETBEANS_OBJ) $(CHANNEL_OBJ) $(XPM_OBJ) \
+ version.c version.h
+ $(CC) $(CFLAGS_OUTDIR) version.c
+ $(link) $(LINKARGS1) -out:$(VIM).exe $(OBJ) $(XDIFF_OBJ) $(GUI_OBJ) $(CUI_OBJ) $(OLE_OBJ) \
+ $(LUA_OBJ) $(MZSCHEME_OBJ) $(PERL_OBJ) $(PYTHON_OBJ) $(PYTHON3_OBJ) $(RUBY_OBJ) \
+ $(TCL_OBJ) $(CSCOPE_OBJ) $(TERM_OBJ) $(NETBEANS_OBJ) $(CHANNEL_OBJ) \
+ $(XPM_OBJ) $(OUTDIR)\version.obj $(LINKARGS2)
+ if exist $(VIM).exe.manifest mt.exe -nologo -manifest $(VIM).exe.manifest -updateresource:$(VIM).exe;1
+
+$(VIM): $(VIM).exe
+
+$(OUTDIR):
+ if not exist $(OUTDIR)/nul mkdir $(OUTDIR)
+
+install.exe: dosinst.c
+ $(CC) /nologo -DNDEBUG -DWIN32 dosinst.c kernel32.lib shell32.lib \
+ user32.lib ole32.lib advapi32.lib uuid.lib \
+ -link -subsystem:$(SUBSYSTEM_TOOLS)
+ - if exist install.exe del install.exe
+ ren dosinst.exe install.exe
+
+uninstal.exe: uninstal.c
+ $(CC) /nologo -DNDEBUG -DWIN32 uninstal.c shell32.lib advapi32.lib \
+ -link -subsystem:$(SUBSYSTEM_TOOLS)
+
+vimrun.exe: vimrun.c
+ $(CC) /nologo -DNDEBUG vimrun.c -link -subsystem:$(SUBSYSTEM_TOOLS)
+
+xxd/xxd.exe: xxd/xxd.c
+ cd xxd
+ $(MAKE) /NOLOGO -f Make_mvc.mak $(MAKEFLAGS_TOOLS)
+ cd ..
+
+tee/tee.exe: tee/tee.c
+ cd tee
+ $(MAKE) /NOLOGO -f Make_mvc.mak $(MAKEFLAGS_TOOLS)
+ cd ..
+
+GvimExt/gvimext.dll: GvimExt/gvimext.cpp GvimExt/gvimext.rc GvimExt/gvimext.h
+ cd GvimExt
+ $(MAKE) /NOLOGO -f Makefile $(MAKEFLAGS_GVIMEXT)
+ cd ..
+
+
+tags: notags
+ $(CTAGS) $(TAGS_FILES)
+
+notags:
+ - if exist tags del tags
+
+clean:
+ - if exist $(OUTDIR)/nul $(DEL_TREE) $(OUTDIR)
+ - if exist *.obj del *.obj
+ - if exist $(VIM).exe del $(VIM).exe
+ - if exist $(VIM).ilk del $(VIM).ilk
+ - if exist $(VIM).pdb del $(VIM).pdb
+ - if exist $(VIM).map del $(VIM).map
+ - if exist $(VIM).ncb del $(VIM).ncb
+ - if exist vimrun.exe del vimrun.exe
+ - if exist install.exe del install.exe
+ - if exist uninstal.exe del uninstal.exe
+ - if exist if_perl.c del if_perl.c
+ - if exist auto\if_perl.c del auto\if_perl.c
+ - if exist dimm.h del dimm.h
+ - if exist dimm_i.c del dimm_i.c
+ - if exist dimm.tlb del dimm.tlb
+ - if exist dosinst.exe del dosinst.exe
+ cd xxd
+ $(MAKE) /NOLOGO -f Make_mvc.mak clean
+ cd ..
+ cd tee
+ $(MAKE) /NOLOGO -f Make_mvc.mak clean
+ cd ..
+ cd GvimExt
+ $(MAKE) /NOLOGO -f Makefile clean
+ cd ..
+ - if exist testdir\*.out del testdir\*.out
+
+test:
+ cd testdir
+ $(MAKE) /NOLOGO -f Make_dos.mak win32
+ cd ..
+
+testgvim:
+ cd testdir
+ $(MAKE) /NOLOGO -f Make_dos.mak VIMPROG=..\gvim win32
+ cd ..
+
+testclean:
+ cd testdir
+ $(MAKE) /NOLOGO -f Make_dos.mak clean
+ cd ..
+
+$(NEW_TESTS):
+ cd testdir
+ - if exist $@.res del $@.res
+ $(MAKE) /NOLOGO -f Make_dos.mak nolog
+ $(MAKE) /NOLOGO -f Make_dos.mak $@.res
+ $(MAKE) /NOLOGO -f Make_dos.mak report
+ type messages
+ cd ..
+
+###########################################################################
+
+# Create a default rule for transforming .c files to .obj files in $(OUTDIR)
+# Batch compilation is supported by nmake 1.62 (part of VS 5.0) and later)
+!IF "$(_NMAKE_VER)" == ""
+.c{$(OUTDIR)/}.obj:
+!ELSE
+.c{$(OUTDIR)/}.obj::
+!ENDIF
+ $(CC) $(CFLAGS_OUTDIR) $<
+
+# Create a default rule for transforming .cpp files to .obj files in $(OUTDIR)
+# Batch compilation is supported by nmake 1.62 (part of VS 5.0) and later)
+!IF "$(_NMAKE_VER)" == ""
+.cpp{$(OUTDIR)/}.obj:
+!ELSE
+.cpp{$(OUTDIR)/}.obj::
+!ENDIF
+ $(CC) $(CFLAGS_OUTDIR) $<
+
+$(OUTDIR)/arabic.obj: $(OUTDIR) arabic.c $(INCL)
+
+$(OUTDIR)/autocmd.obj: $(OUTDIR) autocmd.c $(INCL)
+
+$(OUTDIR)/beval.obj: $(OUTDIR) beval.c $(INCL)
+
+$(OUTDIR)/blob.obj: $(OUTDIR) blob.c $(INCL)
+
+$(OUTDIR)/blowfish.obj: $(OUTDIR) blowfish.c $(INCL)
+
+$(OUTDIR)/buffer.obj: $(OUTDIR) buffer.c $(INCL)
+
+$(OUTDIR)/charset.obj: $(OUTDIR) charset.c $(INCL)
+
+$(OUTDIR)/crypt.obj: $(OUTDIR) crypt.c $(INCL)
+
+$(OUTDIR)/crypt_zip.obj: $(OUTDIR) crypt_zip.c $(INCL)
+
+$(OUTDIR)/dict.obj: $(OUTDIR) dict.c $(INCL)
+
+$(OUTDIR)/diff.obj: $(OUTDIR) diff.c $(INCL)
+
+$(OUTDIR)/xdiffi.obj: $(OUTDIR) xdiff/xdiffi.c $(XDIFF_DEPS)
+ $(CC) $(CFLAGS_OUTDIR) xdiff/xdiffi.c
+
+$(OUTDIR)/xemit.obj: $(OUTDIR) xdiff/xemit.c $(XDIFF_DEPS)
+ $(CC) $(CFLAGS_OUTDIR) xdiff/xemit.c
+
+$(OUTDIR)/xprepare.obj: $(OUTDIR) xdiff/xprepare.c $(XDIFF_DEPS)
+ $(CC) $(CFLAGS_OUTDIR) xdiff/xprepare.c
+
+$(OUTDIR)/xutils.obj: $(OUTDIR) xdiff/xutils.c $(XDIFF_DEPS)
+ $(CC) $(CFLAGS_OUTDIR) xdiff/xutils.c
+
+$(OUTDIR)/xhistogram.obj: $(OUTDIR) xdiff/xhistogram.c $(XDIFF_DEPS)
+ $(CC) $(CFLAGS_OUTDIR) xdiff/xhistogram.c
+
+$(OUTDIR)/xpatience.obj: $(OUTDIR) xdiff/xpatience.c $(XDIFF_DEPS)
+ $(CC) $(CFLAGS_OUTDIR) xdiff/xpatience.c
+
+$(OUTDIR)/digraph.obj: $(OUTDIR) digraph.c $(INCL)
+
+$(OUTDIR)/edit.obj: $(OUTDIR) edit.c $(INCL)
+
+$(OUTDIR)/eval.obj: $(OUTDIR) eval.c $(INCL)
+
+$(OUTDIR)/evalfunc.obj: $(OUTDIR) evalfunc.c $(INCL)
+
+$(OUTDIR)/ex_cmds.obj: $(OUTDIR) ex_cmds.c $(INCL)
+
+$(OUTDIR)/ex_cmds2.obj: $(OUTDIR) ex_cmds2.c $(INCL)
+
+$(OUTDIR)/ex_docmd.obj: $(OUTDIR) ex_docmd.c $(INCL)
+
+$(OUTDIR)/ex_eval.obj: $(OUTDIR) ex_eval.c $(INCL)
+
+$(OUTDIR)/ex_getln.obj: $(OUTDIR) ex_getln.c $(INCL)
+
+$(OUTDIR)/farsi.obj: $(OUTDIR) farsi.c $(INCL)
+
+$(OUTDIR)/fileio.obj: $(OUTDIR) fileio.c $(INCL)
+
+$(OUTDIR)/fold.obj: $(OUTDIR) fold.c $(INCL)
+
+$(OUTDIR)/getchar.obj: $(OUTDIR) getchar.c $(INCL)
+
+$(OUTDIR)/hardcopy.obj: $(OUTDIR) hardcopy.c $(INCL)
+
+$(OUTDIR)/hashtab.obj: $(OUTDIR) hashtab.c $(INCL)
+
+$(OUTDIR)/indent.obj: $(OUTDIR) indent.c $(INCL)
+
+$(OUTDIR)/gui.obj: $(OUTDIR) gui.c $(INCL) $(GUI_INCL)
+
+$(OUTDIR)/gui_beval.obj: $(OUTDIR) gui_beval.c $(INCL) $(GUI_INCL)
+
+$(OUTDIR)/gui_w32.obj: $(OUTDIR) gui_w32.c $(INCL) $(GUI_INCL)
+
+$(OUTDIR)/gui_dwrite.obj: $(OUTDIR) gui_dwrite.cpp $(INCL) $(GUI_INCL)
+
+$(OUTDIR)/if_cscope.obj: $(OUTDIR) if_cscope.c $(INCL) if_cscope.h
+
+$(OUTDIR)/if_lua.obj: $(OUTDIR) if_lua.c $(INCL)
+ $(CC) $(CFLAGS_OUTDIR) $(LUA_INC) if_lua.c
+
+auto/if_perl.c : if_perl.xs typemap
+ $(XSUBPP) -prototypes -typemap $(XSUBPP_TYPEMAP) \
+ -typemap typemap if_perl.xs -output $@
+
+$(OUTDIR)/if_perl.obj: $(OUTDIR) auto/if_perl.c $(INCL)
+ $(CC) $(CFLAGS_OUTDIR) $(PERL_INC) auto/if_perl.c
+
+$(OUTDIR)/if_perlsfio.obj: $(OUTDIR) if_perlsfio.c $(INCL)
+ $(CC) $(CFLAGS_OUTDIR) $(PERL_INC) if_perlsfio.c
+
+$(OUTDIR)/if_mzsch.obj: $(OUTDIR) if_mzsch.c $(MZSCHEME_INCL) $(INCL) $(MZSCHEME_EXTRA_DEP)
+ $(CC) $(CFLAGS_OUTDIR) if_mzsch.c \
+ -DMZSCHEME_COLLECTS="\"$(MZSCHEME_COLLECTS:\=\\)\""
+
+lib$(MZSCHEME_MAIN_LIB)$(MZSCHEME_VER).lib:
+ lib /DEF:"$(MZSCHEME)\lib\lib$(MZSCHEME_MAIN_LIB)$(MZSCHEME_VER).def"
+
+$(OUTDIR)/if_python.obj: $(OUTDIR) if_python.c if_py_both.h $(INCL)
+ $(CC) $(CFLAGS_OUTDIR) $(PYTHON_INC) if_python.c
+
+$(OUTDIR)/if_python3.obj: $(OUTDIR) if_python3.c if_py_both.h $(INCL)
+ $(CC) $(CFLAGS_OUTDIR) $(PYTHON3_INC) if_python3.c
+
+$(OUTDIR)/if_ole.obj: $(OUTDIR) if_ole.cpp $(INCL) if_ole.h
+
+$(OUTDIR)/if_ruby.obj: $(OUTDIR) if_ruby.c $(INCL)
+ $(CC) $(CFLAGS_OUTDIR) $(RUBY_INC) if_ruby.c
+
+$(OUTDIR)/if_tcl.obj: $(OUTDIR) if_tcl.c $(INCL)
+ $(CC) $(CFLAGS_OUTDIR) $(TCL_INC) if_tcl.c
+
+$(OUTDIR)/iscygpty.obj: $(OUTDIR) iscygpty.c $(CUI_INCL)
+ $(CC) $(CFLAGS_OUTDIR) iscygpty.c -D_WIN32_WINNT=0x0600 -DUSE_DYNFILEID -DENABLE_STUB_IMPL
+
+$(OUTDIR)/json.obj: $(OUTDIR) json.c $(INCL)
+
+$(OUTDIR)/list.obj: $(OUTDIR) list.c $(INCL)
+
+$(OUTDIR)/main.obj: $(OUTDIR) main.c $(INCL) $(CUI_INCL)
+
+$(OUTDIR)/mark.obj: $(OUTDIR) mark.c $(INCL)
+
+$(OUTDIR)/memfile.obj: $(OUTDIR) memfile.c $(INCL)
+
+$(OUTDIR)/memline.obj: $(OUTDIR) memline.c $(INCL)
+
+$(OUTDIR)/menu.obj: $(OUTDIR) menu.c $(INCL)
+
+$(OUTDIR)/message.obj: $(OUTDIR) message.c $(INCL)
+
+$(OUTDIR)/misc1.obj: $(OUTDIR) misc1.c $(INCL)
+
+$(OUTDIR)/misc2.obj: $(OUTDIR) misc2.c $(INCL)
+
+$(OUTDIR)/move.obj: $(OUTDIR) move.c $(INCL)
+
+$(OUTDIR)/mbyte.obj: $(OUTDIR) mbyte.c $(INCL)
+
+$(OUTDIR)/netbeans.obj: $(OUTDIR) netbeans.c $(NBDEBUG_SRC) $(INCL)
+
+$(OUTDIR)/channel.obj: $(OUTDIR) channel.c $(INCL)
+
+$(OUTDIR)/normal.obj: $(OUTDIR) normal.c $(INCL)
+
+$(OUTDIR)/option.obj: $(OUTDIR) option.c $(INCL)
+
+$(OUTDIR)/ops.obj: $(OUTDIR) ops.c $(INCL)
+
+$(OUTDIR)/os_mswin.obj: $(OUTDIR) os_mswin.c $(INCL)
+
+$(OUTDIR)/terminal.obj: $(OUTDIR) terminal.c $(INCL) $(TERM_DEPS)
+
+$(OUTDIR)/winclip.obj: $(OUTDIR) winclip.c $(INCL)
+
+$(OUTDIR)/os_win32.obj: $(OUTDIR) os_win32.c $(INCL) $(MZSCHEME_INCL)
+
+$(OUTDIR)/os_w32exe.obj: $(OUTDIR) os_w32exe.c $(INCL)
+
+$(OUTDIR)/pathdef.obj: $(OUTDIR) $(PATHDEF_SRC) $(INCL)
+ $(CC) $(CFLAGS_OUTDIR) $(PATHDEF_SRC)
+
+$(OUTDIR)/popupmnu.obj: $(OUTDIR) popupmnu.c $(INCL)
+
+$(OUTDIR)/quickfix.obj: $(OUTDIR) quickfix.c $(INCL)
+
+$(OUTDIR)/regexp.obj: $(OUTDIR) regexp.c regexp_nfa.c $(INCL)
+
+$(OUTDIR)/screen.obj: $(OUTDIR) screen.c $(INCL)
+
+$(OUTDIR)/search.obj: $(OUTDIR) search.c $(INCL)
+
+$(OUTDIR)/sha256.obj: $(OUTDIR) sha256.c $(INCL)
+
+$(OUTDIR)/sign.obj: $(OUTDIR) sign.c $(INCL)
+
+$(OUTDIR)/spell.obj: $(OUTDIR) spell.c $(INCL)
+
+$(OUTDIR)/spellfile.obj: $(OUTDIR) spellfile.c $(INCL)
+
+$(OUTDIR)/syntax.obj: $(OUTDIR) syntax.c $(INCL)
+
+$(OUTDIR)/tag.obj: $(OUTDIR) tag.c $(INCL)
+
+$(OUTDIR)/term.obj: $(OUTDIR) term.c $(INCL)
+
+$(OUTDIR)/textprop.obj: $(OUTDIR) textprop.c $(INCL)
+
+$(OUTDIR)/ui.obj: $(OUTDIR) ui.c $(INCL)
+
+$(OUTDIR)/undo.obj: $(OUTDIR) undo.c $(INCL)
+
+$(OUTDIR)/userfunc.obj: $(OUTDIR) userfunc.c $(INCL)
+
+$(OUTDIR)/window.obj: $(OUTDIR) window.c $(INCL)
+
+$(OUTDIR)/xpm_w32.obj: $(OUTDIR) xpm_w32.c
+ $(CC) $(CFLAGS_OUTDIR) $(XPM_INC) xpm_w32.c
+
+$(OUTDIR)/vim.res: $(OUTDIR) vim.rc gvim.exe.mnf version.h tools.bmp \
+ tearoff.bmp vim.ico vim_error.ico \
+ vim_alert.ico vim_info.ico vim_quest.ico
+ $(RC) /nologo /l 0x409 /Fo$(OUTDIR)/vim.res $(RCFLAGS) vim.rc
+
+iid_ole.c if_ole.h vim.tlb: if_ole.idl
+ midl /nologo /error none /proxy nul /iid iid_ole.c /tlb vim.tlb \
+ /header if_ole.h if_ole.idl
+
+dimm.h dimm_i.c: dimm.idl
+ midl /nologo /error none /proxy nul dimm.idl
+
+$(OUTDIR)/dimm_i.obj: $(OUTDIR) dimm_i.c $(INCL)
+
+$(OUTDIR)/glbl_ime.obj: $(OUTDIR) glbl_ime.cpp dimm.h $(INCL)
+
+
+CCCTERM = $(CC) $(CFLAGS) -Ilibvterm/include -DINLINE="" \
+ -DVSNPRINTF=vim_vsnprintf \
+ -DIS_COMBINING_FUNCTION=utf_iscomposing_uint \
+ -DWCWIDTH_FUNCTION=utf_uint2cells \
+ -D_CRT_SECURE_NO_WARNINGS
+
+$(OUTDIR)/encoding.obj: $(OUTDIR) libvterm/src/encoding.c $(TERM_DEPS)
+ $(CCCTERM) -Fo$@ libvterm/src/encoding.c
+
+$(OUTDIR)/keyboard.obj: $(OUTDIR) libvterm/src/keyboard.c $(TERM_DEPS)
+ $(CCCTERM) -Fo$@ libvterm/src/keyboard.c
+
+$(OUTDIR)/mouse.obj: $(OUTDIR) libvterm/src/mouse.c $(TERM_DEPS)
+ $(CCCTERM) -Fo$@ libvterm/src/mouse.c
+
+$(OUTDIR)/parser.obj: $(OUTDIR) libvterm/src/parser.c $(TERM_DEPS)
+ $(CCCTERM) -Fo$@ libvterm/src/parser.c
+
+$(OUTDIR)/pen.obj: $(OUTDIR) libvterm/src/pen.c $(TERM_DEPS)
+ $(CCCTERM) -Fo$@ libvterm/src/pen.c
+
+$(OUTDIR)/termscreen.obj: $(OUTDIR) libvterm/src/termscreen.c $(TERM_DEPS)
+ $(CCCTERM) -Fo$@ libvterm/src/termscreen.c
+
+$(OUTDIR)/state.obj: $(OUTDIR) libvterm/src/state.c $(TERM_DEPS)
+ $(CCCTERM) -Fo$@ libvterm/src/state.c
+
+$(OUTDIR)/unicode.obj: $(OUTDIR) libvterm/src/unicode.c $(TERM_DEPS)
+ $(CCCTERM) -Fo$@ libvterm/src/unicode.c
+
+$(OUTDIR)/vterm.obj: $(OUTDIR) libvterm/src/vterm.c $(TERM_DEPS)
+ $(CCCTERM) -Fo$@ libvterm/src/vterm.c
+
+
+# $CFLAGS may contain backslashes and double quotes, escape them both.
+E0_CFLAGS = $(CFLAGS:\=\\)
+E_CFLAGS = $(E0_CFLAGS:"=\")
+# ") stop the string
+# $LINKARGS2 may contain backslashes and double quotes, escape them both.
+E0_LINKARGS2 = $(LINKARGS2:\=\\)
+E_LINKARGS2 = $(E0_LINKARGS2:"=\")
+# ") stop the string
+
+$(PATHDEF_SRC): auto
+ @echo creating $(PATHDEF_SRC)
+ @echo /* pathdef.c */ > $(PATHDEF_SRC)
+ @echo #include "vim.h" >> $(PATHDEF_SRC)
+ @echo char_u *default_vim_dir = (char_u *)"$(VIMRCLOC:\=\\)"; >> $(PATHDEF_SRC)
+ @echo char_u *default_vimruntime_dir = (char_u *)"$(VIMRUNTIMEDIR:\=\\)"; >> $(PATHDEF_SRC)
+ @echo char_u *all_cflags = (char_u *)"$(CC:\=\\) $(E_CFLAGS)"; >> $(PATHDEF_SRC)
+ @echo char_u *all_lflags = (char_u *)"$(link:\=\\) $(LINKARGS1:\=\\) $(E_LINKARGS2)"; >> $(PATHDEF_SRC)
+ @echo char_u *compiled_user = (char_u *)"$(USERNAME)"; >> $(PATHDEF_SRC)
+ @echo char_u *compiled_sys = (char_u *)"$(USERDOMAIN)"; >> $(PATHDEF_SRC)
+
+auto:
+ if not exist auto/nul mkdir auto
+
+# End Custom Build
+proto.h: \
+ proto/arabic.pro \
+ proto/autocmd.pro \
+ proto/blob.pro \
+ proto/blowfish.pro \
+ proto/buffer.pro \
+ proto/charset.pro \
+ proto/crypt.pro \
+ proto/crypt_zip.pro \
+ proto/dict.pro \
+ proto/diff.pro \
+ proto/digraph.pro \
+ proto/edit.pro \
+ proto/eval.pro \
+ proto/evalfunc.pro \
+ proto/ex_cmds.pro \
+ proto/ex_cmds2.pro \
+ proto/ex_docmd.pro \
+ proto/ex_eval.pro \
+ proto/ex_getln.pro \
+ proto/farsi.pro \
+ proto/fileio.pro \
+ proto/getchar.pro \
+ proto/hardcopy.pro \
+ proto/hashtab.pro \
+ proto/indent.pro \
+ proto/json.pro \
+ proto/list.pro \
+ proto/main.pro \
+ proto/mark.pro \
+ proto/memfile.pro \
+ proto/memline.pro \
+ proto/menu.pro \
+ proto/message.pro \
+ proto/misc1.pro \
+ proto/misc2.pro \
+ proto/move.pro \
+ proto/mbyte.pro \
+ proto/normal.pro \
+ proto/ops.pro \
+ proto/option.pro \
+ proto/os_mswin.pro \
+ proto/winclip.pro \
+ proto/os_win32.pro \
+ proto/popupmnu.pro \
+ proto/quickfix.pro \
+ proto/regexp.pro \
+ proto/screen.pro \
+ proto/search.pro \
+ proto/sha256.pro \
+ proto/sign.pro \
+ proto/spell.pro \
+ proto/spellfile.pro \
+ proto/syntax.pro \
+ proto/tag.pro \
+ proto/term.pro \
+ proto/textprop.pro \
+ proto/ui.pro \
+ proto/undo.pro \
+ proto/userfunc.pro \
+ proto/window.pro \
+ $(NETBEANS_PRO) \
+ $(CHANNEL_PRO)
+
+.SUFFIXES: .cod .i
+
+# Generate foo.cod (mixed source and assembly listing) from foo.c via "nmake
+# foo.cod"
+.c.cod:
+ $(CC) $(CFLAGS) /FAcs $<
+
+# Generate foo.i (preprocessor listing) from foo.c via "nmake foo.i"
+.c.i:
+ $(CC) $(CFLAGS) /P /C $<
+
+# vim: set noet sw=8 ts=8 sts=0 wm=0 tw=0:
diff --git a/src/Make_sas.mak b/src/Make_sas.mak
new file mode 100644
index 0000000..e7faf56
--- /dev/null
+++ b/src/Make_sas.mak
@@ -0,0 +1,440 @@
+# vim: set ft=make :
+# Makefile for VIM on the Amiga, using SAS/Lattice C 6.0 to 6.58
+#
+# Do NOT use the peephole optimizer with a version before 6.56!
+# It messes up all kinds of things:
+# For 6.0 and 6.1, expand_env() will not work correctly.
+# For 6.2 and 6.3 the call to free_line in u_freeentry is wrong.
+# The "read.me" file for version 6.56 includes a remark about a fix for the
+# peephole optimizer. Everything before 6.56 will probably fail.
+#
+# You should use Manx Aztec C whenever possible, because it has been tested.
+#
+# The prototypes from Manx and SAS are incompatible. If the prototypes
+# were generated by Manx, first do "touch *.c; make proto" before "make".
+# The prototypes generated on Unix work for both.
+#
+# Note: Not all dependencies are included. This was done to avoid having
+# to compile everything when a global variable or function is added.
+
+#>>>>> choose options:
+
+### See feature.h for a list of optionals.
+### Any other defines can be included here.
+
+# NO_ARP Don't include ARP functions
+# SASC=658 Sas/C version number
+# NEWSASC fixes a bug in the syntax highlighting?
+DEFINES = DEF=NO_ARP DEF=NEWSASC DEF="SASC=658"
+
+#>>>>> if HAVE_TGETENT is defined termlib.o has to be used
+#TERMLIB = termlib.o
+TERMLIB =
+
+#>>>>> choose NODEBUG for normal compiling, the other for debugging and
+# profiling
+# don't switch on debugging when generating proto files, it crashes the
+# compiler.
+DBG = NODEBUG
+#DBG = DBG=SF
+
+#>>>>> choose NOOPTPEEP for 6.0 to 6.3, NOOPT for debugging
+# with version 6.56 and later you can probably use OPT
+OPTIMIZE = OPT
+#OPTIMIZE = NOOPTPEEP
+#OPTIMIZE = NOOPT
+
+# for 6.58 you can use the line below, but be warned it takes a loooonnnggg time
+#OPTIMIZE=OPT OPTIMIZERSCHEDULER OPTIMIZERTIME NoOPTIMIZERALIAS \
+ OptimizerComplexity=10 OptimizerDepth=10 OptimizerRecurDepth=10 \
+ OptimizerInLocal OPTPEEP
+
+#generate code for your processor - 68060 will work for 040's as well.
+CPU=68000
+#CPU=68020
+#CPU=68030
+#CPU=68040
+#CPU=68060
+
+#Error reporting - rexx or console
+ERROR = ERRORCONSOLE ERRORSOURCE ERRORHIGHLIGHT
+#ERROR = ERRORREXX ERRORCONSOLE ERRORSOURCE ERRORHIGHLIGHT
+
+#memory types, if you have fast use it :->,
+# ANY = will work on all machines
+# FAST = this is the best option, for speed
+#MEMORYTYPE=FAST
+MEMORYTYPE=ANY
+
+#MEMSIZE - this is for compile time only for speed of compilation
+#MEMSIZE=HUGE
+MEMSIZE=LARGE
+#MEMSIZE=SMALL
+
+#>>>>> end of choices
+###########################################################################
+
+CC = sc
+GST = vim.gst
+COPTS = SINT SCODE SDATA
+SHELL = csh
+DEL = $(SHELL) -c rm -f
+
+# ignore error messages for uninitialized variables, they are mostly not correct
+CFLAGS = NOLINK $(DBG) CPU=$(CPU) NOSTACKCHECK DEF=AMIGA CODE=FAR idir=proto ignore=317
+CFLAGS2 = $(OPTIMIZE) $(ERROR) GSTIMMEDIATE GST=$(GST)
+CFLAGS3 = $(COPTS) STRINGMERGE MEMSIZE=$(MEMSIZE)
+CFLAGS4 = $(DEFINES) DATAMEMORY=$(MEMORYTYPE)
+
+PROPT = DEF=PROTO GPROTO GPPARM MAXIMUMERRORS=999 GENPROTOSTATICS GENPROTOPARAMETERS
+
+SRC = \
+ arabic.c \
+ autocmd.c \
+ blowfish.c \
+ buffer.c \
+ charset.c \
+ crypt.c \
+ crypt_zip.c \
+ dict.c \
+ diff.c \
+ digraph.c \
+ edit.c \
+ eval.c \
+ evalfunc.c \
+ ex_cmds.c \
+ ex_cmds2.c \
+ ex_docmd.c \
+ ex_eval.c \
+ ex_getln.c \
+ farsi.c \
+ fileio.c \
+ fold.c \
+ getchar.c \
+ hardcopy.c \
+ hashtab.c \
+ indent.c \
+ json.c \
+ list.c \
+ main.c \
+ mark.c \
+ memfile.c \
+ memline.c \
+ menu.c \
+ message.c \
+ misc1.c \
+ misc2.c \
+ move.c \
+ mbyte.c \
+ normal.c \
+ ops.c \
+ option.c \
+ os_amiga.c \
+ popupmnu.c \
+ quickfix.c \
+ regexp.c \
+ screen.c \
+ search.c \
+ sha256.c \
+ sign.c \
+ spell.c \
+ spellfile.c \
+ syntax.c \
+ tag.c \
+ term.c \
+ ui.c \
+ undo.c \
+ userfunc.c \
+ window.c \
+ version.c
+
+OBJ = \
+ arabic.o \
+ autocmd.o \
+ blowfish.o \
+ buffer.o \
+ charset.o \
+ crypt.o \
+ crypt_zip.o \
+ dict.o \
+ diff.o \
+ digraph.o \
+ edit.o \
+ eval.o \
+ evalfunc.o \
+ ex_cmds.o \
+ ex_cmds2.o \
+ ex_docmd.o \
+ ex_eval.o \
+ ex_getln.o \
+ farsi.o \
+ fileio.o \
+ fold.o \
+ getchar.o \
+ hardcopy.o \
+ hashtab.o \
+ indent.o \
+ json.o \
+ list.o \
+ main.o \
+ mark.o \
+ memfile.o \
+ memline.o \
+ menu.o \
+ message.o \
+ misc1.o \
+ misc2.o \
+ move.o \
+ mbyte.o \
+ normal.o \
+ ops.o \
+ option.o \
+ os_amiga.o \
+ popupmnu.o \
+ quickfix.o \
+ regexp.o \
+ screen.o \
+ search.o \
+ sha256.o \
+ sign.o \
+ spell.o \
+ spellfile.o \
+ syntax.o \
+ tag.o \
+ term.o \
+ ui.o \
+ undo.o \
+ userfunc.o \
+ window.o \
+ $(TERMLIB)
+
+PRO = \
+ proto/arabic.pro \
+ proto/autocmd.pro \
+ proto/blowfish.pro \
+ proto/buffer.pro \
+ proto/charset.pro \
+ proto/crypt.pro \
+ proto/crypt_zip.pro \
+ proto/dict.pro \
+ proto/diff.pro \
+ proto/digraph.pro \
+ proto/edit.pro \
+ proto/eval.pro \
+ proto/evalfunc.pro \
+ proto/ex_cmds.pro \
+ proto/ex_cmds2.pro \
+ proto/ex_docmd.pro \
+ proto/ex_eval.pro \
+ proto/ex_getln.pro \
+ proto/farsi.pro \
+ proto/fileio.pro \
+ proto/fold.pro \
+ proto/getchar.pro \
+ proto/hardcopy.pro \
+ proto/hashtab.pro \
+ proto/indent.pro \
+ proto/json.pro \
+ proto/list.pro \
+ proto/main.pro \
+ proto/mark.pro \
+ proto/memfile.pro \
+ proto/memline.pro \
+ proto/menu.pro \
+ proto/message.pro \
+ proto/misc1.pro \
+ proto/misc2.pro \
+ proto/move.pro \
+ proto/mbyte.pro \
+ proto/normal.pro \
+ proto/ops.pro \
+ proto/option.pro \
+ proto/os_amiga.pro \
+ proto/popupmnu.pro \
+ proto/quickfix.pro \
+ proto/regexp.pro \
+ proto/screen.pro \
+ proto/search.pro \
+ proto/sha256.pro \
+ proto/sign.pro \
+ proto/spell.pro \
+ proto/spellfile.pro \
+ proto/syntax.pro \
+ proto/tag.pro \
+ proto/term.pro \
+ proto/termlib.pro \
+ proto/ui.pro \
+ proto/undo.pro \
+ proto/userfunc.pro \
+ proto/window.pro
+
+all: proto Vim
+
+Vim: scoptions $(OBJ) version.c version.h
+ $(CC) $(CFLAGS) version.c
+ $(CC) LINK $(COPTS) $(OBJ) version.o $(DBG) PNAME=Vim
+
+debug: scoptions $(OBJ) version.c version.h
+ $(CC) $(CFLAGS) version.c
+ $(CC) LINK $(COPTS) $(OBJ) version.o $(DBG) PNAME=Vim
+
+proto: $(GST) $(PRO)
+
+tags:
+ spat ctags $(SRC) *.h
+# csh -c ctags $(SRC) *.h
+
+# can't use delete here, too many file names
+clean:
+ $(DEL) *.o Vim $(GST)
+
+# generate GlobalSymbolTable, which speeds up the compile time.
+#
+# A preprocessing stage is used to work around a bug in the GST generator, in
+# that it does not handle nested makefiles properly in this stage.
+# Ignore error message for not producing any code (105).
+$(GST): scoptions vim.h keymap.h macros.h ascii.h term.h structs.h
+ $(CC) $(CFLAGS) PREPROCESSORONLY vim.h objectname pre.h
+ $(CC) MGST=$(GST) pre.h ignore=105
+ $(DEL) pre.h
+
+# generate an options file, because SAS/C smake can't handle the amiga command
+# line can handle the lengths that this makefile will impose on the shell.
+# (Manx's make can do this).
+scoptions: Make_sas.mak
+ @echo "Generating - $@ ..."
+ @echo $(CFLAGS) > scoptions
+ @echo $(CFLAGS1) >> scoptions
+ @echo $(CFLAGS2) >> scoptions
+ @echo $(CFLAGS3) >> scoptions
+ @echo $(CFLAGS4) >> scoptions
+ @echo $(COPTS) >>scoptions
+ @echo done
+
+###########################################################################
+
+$(OBJ): $(GST) vim.h
+$(PRO): $(GST) vim.h
+
+.c.o:
+ $(CC) $(CFLAGS) $*.c
+
+.c.pro:
+ $(CC) $(CFLAGS) GPFILE=proto/$*.pro $(PROPT) $*.c
+
+# dependencies
+arabic.o: arabic.c
+proto/arabic.pro: arabic.c
+autocmd.o: autocmd.c
+proto/autocmd.pro: autocmd.c
+blowfish.o: blowfish.c
+proto/blowfish.pro: blowfish.c
+buffer.o: buffer.c
+proto/buffer.pro: buffer.c
+charset.o: charset.c
+proto/charset.pro: charset.c
+crypt.o: crypt.c
+proto/crypt.pro: crypt.c
+crypt_zip.o: crypt_zip.c
+proto/crypt_zip.pro: crypt_zip.c
+dict.o: dict.c
+proto/dict.pro: dict.c
+diff.o: diff.c
+proto/diff.pro: diff.c
+digraph.o: digraph.c
+proto/digraph.pro: digraph.c
+edit.o: edit.c
+proto/edit.pro: edit.c
+eval.o: eval.c
+proto/eval.pro: eval.c
+evalfunc.o: evalfunc.c
+proto/evalfunc.pro: evalfunc.c
+ex_cmds.o: ex_cmds.c
+proto/ex_cmds.pro: ex_cmds.c
+ex_cmds2.o: ex_cmds2.c
+proto/ex_cmds2.pro: ex_cmds2.c
+ex_docmd.o: ex_docmd.c ex_cmds.h
+proto/ex_docmd.pro: ex_docmd.c ex_cmds.h
+ex_eval.o: ex_eval.c ex_cmds.h
+proto/ex_eval.pro: ex_eval.c ex_cmds.h
+ex_getln.o: ex_getln.c
+proto/ex_getln.pro: ex_getln.c
+farsi.o: farsi.c
+proto/farsi.pro: farsi.c
+fileio.o: fileio.c
+proto/fileio.pro: fileio.c
+fold.o: fold.c
+proto/fold.pro: fold.c
+getchar.o: getchar.c
+proto/getchar.pro: getchar.c
+hardcopy.o: hardcopy.c
+proto/hardcopy.pro: hardcopy.c
+hashtab.o: hashtab.c
+proto/hashtab.pro: hashtab.c
+indent.o: indent.c
+proto/indent.pro: indent.c
+json.o: json.c
+proto/json.pro: json.c
+list.o: list.c
+proto/list.pro: list.c
+main.o: main.c
+proto/main.pro: main.c
+mark.o: mark.c
+proto/mark.pro: mark.c
+memfile.o: memfile.c
+proto/memfile.pro: memfile.c
+memline.o: memline.c
+proto/memline.pro: memline.c
+menu.o: menu.c
+proto/menu.pro: menu.c
+message.o: message.c
+proto/message.pro: message.c
+misc1.o: misc1.c
+proto/misc1.pro: misc1.c
+misc2.o: misc2.c
+proto/misc2.pro: misc2.c
+move.o: move.c
+proto/move.pro: move.c
+mbyte.o: mbyte.c
+proto/mbyte.pro: mbyte.c
+normal.o: normal.c
+proto/normal.pro: normal.c
+ops.o: ops.c
+proto/ops.pro: ops.c
+option.o: option.c
+proto/option.pro: option.c
+os_amiga.o: os_amiga.c
+proto/os_amiga.pro: os_amiga.c
+popupmnu.o: popupmnu.c
+proto/popupmnu.pro: popupmnu.c
+quickfix.o: quickfix.c
+proto/quickfix.pro: quickfix.c
+regexp.o: regexp.c
+proto/regexp.pro: regexp.c
+screen.o: screen.c
+proto/screen.pro: screen.c
+search.o: search.c
+proto/search.pro: search.c
+sha256.o: sha256.c
+proto/sha256.pro: sha256.c
+sign.o: sign.c
+proto/sign.pro: sign.c
+spell.o: spell.c
+proto/spell.pro: spell.c
+spellfile.o: spellfile.c
+proto/spellfile.pro: spellfile.c
+syntax.o: syntax.c
+proto/syntax.pro: syntax.c
+tag.o: tag.c
+proto/tag.pro: tag.c
+term.o: term.c
+proto/term.pro: term.c
+termlib.o: termlib.c
+proto/termlib.pro: termlib.c
+ui.o: ui.c
+proto/ui.pro: ui.c
+undo.o: undo.c
+proto/undo.pro: undo.c
+userfunc.o: userfunc.c
+proto/userfunc.pro: userfunc.c
+window.o: window.c
diff --git a/src/Make_vms.mms b/src/Make_vms.mms
new file mode 100644
index 0000000..1a21d15
--- /dev/null
+++ b/src/Make_vms.mms
@@ -0,0 +1,858 @@
+#
+# Makefile for Vim on OpenVMS
+#
+# Maintainer: Zoltan Arpadffy <arpadffy@polarhome.com>
+# Last change: 2019 Jan 18
+#
+# This has script been tested on VMS 6.2 to 8.2 on DEC Alpha, VAX and IA64
+# with MMS and MMK
+#
+# The following could be built:
+# vim.exe: standard (terminal, GUI/Motif, GUI/GTK)
+# dvim.exe: debug
+#
+# Edit the lines in the Configuration section below for fine tuning.
+#
+# To build: mms/descrip=Make_vms.mms /ignore=warning
+# To clean up: mms/descrip=Make_vms.mms clean
+#
+# Hints and detailed description could be found in INSTALLVMS.TXT file.
+#
+######################################################################
+# Configuration section.
+######################################################################
+
+# Compiler selection.
+# Comment out if you use the VAXC compiler
+DECC = YES
+
+# Build model selection
+# TINY - Almost no features enabled, not even multiple windows
+# SMALL - Few features enabled, as basic as possible
+# NORMAL - A default selection of features enabled
+# BIG - Many features enabled, as rich as possible. (default)
+# HUGE - All possible features enabled.
+# Please select one of these alternatives above.
+MODEL = HUGE
+
+# GUI or terminal mode executable.
+# Comment out if you want just the character terminal mode only.
+# GUI with Motif
+GUI = YES
+
+# GUI with GTK
+# If you have GTK installed you might want to enable this option.
+# NOTE: you will need to properly define GTK_DIR below
+# NOTE: since Vim 7.3 GTK 2+ is used that is not ported to VMS,
+# therefore this option should not be used
+# GTK = YES
+
+# GUI/Motif with XPM
+# If you have XPM installed you might want to build Motif version with toolbar
+# XPM = YES
+
+# Comment out if you want the compiler version with :ver command.
+# NOTE: This part can make some complications if you're using some
+# predefined symbols/flags for your compiler. If does, just leave behind
+# the comment variable CCVER.
+CCVER = YES
+
+# Uncomment if want a debug version. Resulting executable is DVIM.EXE
+# Development purpose only! Normally, it should not be defined. !!!
+# DEBUG = YES
+
+# Languages support for Perl, Python, TCL etc.
+# If you don't need it really, leave them behind the comment.
+# You will need related libraries, include files etc.
+# VIM_TCL = YES
+# VIM_PERL = YES
+# VIM_PYTHON = YES
+# VIM_RUBY = YES
+
+# X Input Method. For entering special languages like chinese and
+# Japanese. Please define just one: VIM_XIM or VIM_HANGULIN
+# If you don't need it really, leave it behind the comment.
+# VIM_XIM = YES
+
+# Internal Hangul input method. GUI only.
+# If you don't need it really, leave it behind the comment.
+# VIM_HANGULIN = YES
+
+# Allow any white space to separate the fields in a tags file
+# When not defined, only a TAB is allowed.
+# VIM_TAG_ANYWHITE = YES
+
+# Allow FEATURE_MZSCHEME
+# VIM_MZSCHEME = YES
+
+# Use ICONV
+# VIM_ICONV = YES
+
+######################################################################
+# Directory, library and include files configuration section.
+# Normally you need not to change anything below. !
+# These may need to be defined if things are not in standard locations
+#
+# You can find some explanation in INSTALLVMS.TXT
+######################################################################
+
+# Compiler setup
+
+.IFDEF MMSVAX
+.IFDEF DECC # VAX with DECC
+CC_DEF = cc # /decc # some versions require /decc switch but when it is not required /ver might fail
+PREFIX = /prefix=all
+OPTIMIZE= /noopt # do not optimize on VAX. The compiler has hard time with crypto functions
+.ELSE # VAX with VAXC
+CC_DEF = cc
+PREFIX =
+OPTIMIZE= /noopt
+CCVER =
+.ENDIF
+.ELSE # AXP and IA64 with DECC
+CC_DEF = cc
+PREFIX = /prefix=all
+OPTIMIZE= /opt
+.ENDIF
+
+
+LD_DEF = link
+C_INC = [.proto]
+
+.IFDEF DEBUG
+DEBUG_DEF = ,"DEBUG"
+TARGET = dvim.exe
+CFLAGS = /debug/noopt$(PREFIX)
+LDFLAGS = /debug
+.ELSE
+TARGET = vim.exe
+CFLAGS = $(OPTIMIZE)$(PREFIX)
+LDFLAGS =
+.ENDIF
+
+# Predefined VIM directories
+# Please, use $VIM and $VIMRUNTIME logicals instead
+VIMLOC = ""
+VIMRUN = ""
+
+CONFIG_H = os_vms_conf.h
+
+# GTK or XPM but not both
+.IFDEF GTK
+.IFDEF GUI
+.ELSE
+GUI = YES
+.ENDIF
+.IFDEF XPM
+XPM = ""
+.ENDIF
+.ENDIF
+
+.IFDEF XPM
+.IFDEF GUI
+.ELSE
+GUI = YES
+.ENDIF
+.IFDEF GTK
+GTK = ""
+.ENDIF
+.ENDIF
+
+.IFDEF GUI
+# X/Motif/GTK executable (also works in terminal mode )
+
+.IFDEF GTK
+# NOTE: you need to set up your GTK_DIR (GTK root directory), because it is
+# unique on every system - logicals are not accepted
+# please note: directory should end with . in order to /trans=conc work
+# This value for GTK_DIR is an example.
+GTK_DIR = DKA0:[WORK.GTK1210.]
+DEFS = "HAVE_CONFIG_H","FEAT_GUI_GTK"
+LIBS = ,OS_VMS_GTK.OPT/OPT
+GUI_FLAG = /name=(as_is,short)/float=ieee/ieee=denorm
+GUI_SRC = gui.c gui_gtk.c gui_gtk_f.c gui_gtk_x11.c gui_beval.c pty.c
+GUI_OBJ = gui.obj gui_gtk.obj gui_gtk_f.obj gui_gtk_x11.obj gui_beval.obj pty.obj
+GUI_INC = ,"/gtk_root/gtk","/gtk_root/glib"
+# GUI_INC_VER is used just for :ver information
+# this string should escape from C and DCL in the same time
+GUI_INC_VER= ,\""/gtk_root/gtk\"",\""/gtk_root/glib\""
+.ELSE
+MOTIF = YES
+.IFDEF XPM
+DEFS = "HAVE_CONFIG_H","FEAT_GUI_MOTIF","HAVE_XPM"
+XPM_INC = ,[.xpm.include]
+.ELSE
+DEFS = "HAVE_CONFIG_H","FEAT_GUI_MOTIF"
+XPM_INC =
+.ENDIF
+LIBS = ,OS_VMS_MOTIF.OPT/OPT
+GUI_FLAG =
+GUI_SRC = gui.c gui_motif.c gui_x11.c gui_beval.c gui_xmdlg.c gui_xmebw.c
+GUI_OBJ = gui.obj gui_motif.obj gui_x11.obj gui_beval.obj gui_xmdlg.obj gui_xmebw.obj
+GUI_INC =
+.ENDIF
+
+# You need to define these variables if you do not have DECW files
+# at standard location
+GUI_INC_DIR = ,decw$include:
+# GUI_LIB_DIR = ,sys$library:
+
+.ELSE
+# Character terminal only executable
+DEFS = "HAVE_CONFIG_H"
+LIBS =
+.ENDIF
+
+.IFDEF VIM_PERL
+# Perl related setup.
+PERL = perl
+PERL_DEF = ,"FEAT_PERL"
+PERL_SRC = if_perlsfio.c if_perl.xs
+PERL_OBJ = if_perlsfio.obj if_perl.obj
+PERL_LIB = ,OS_VMS_PERL.OPT/OPT
+PERL_INC = ,dka0:[perlbuild.perl.lib.vms_axp.5_6_1.core]
+.ENDIF
+
+.IFDEF VIM_PYTHON
+# Python related setup.
+PYTHON_DEF = ,"FEAT_PYTHON"
+PYTHON_SRC = if_python.c
+PYTHON_OBJ = if_python.obj
+PYTHON_LIB = ,OS_VMS_PYTHON.OPT/OPT
+PYTHON_INC = ,PYTHON_INCLUDE
+.ENDIF
+
+.IFDEF VIM_TCL
+# TCL related setup.
+TCL_DEF = ,"FEAT_TCL"
+TCL_SRC = if_tcl.c
+TCL_OBJ = if_tcl.obj
+TCL_LIB = ,OS_VMS_TCL.OPT/OPT
+TCL_INC = ,dka0:[tcl80.generic]
+.ENDIF
+
+.IFDEF VIM_RUBY
+# RUBY related setup.
+RUBY_DEF = ,"FEAT_RUBY"
+RUBY_SRC = if_ruby.c
+RUBY_OBJ = if_ruby.obj
+RUBY_LIB = ,OS_VMS_RUBY.OPT/OPT
+RUBY_INC =
+.ENDIF
+
+.IFDEF VIM_XIM
+# XIM related setup.
+.IFDEF GUI
+XIM_DEF = ,"FEAT_XIM"
+.ENDIF
+.ENDIF
+
+.IFDEF VIM_HANGULIN
+# HANGULIN related setup.
+.IFDEF GUI
+HANGULIN_DEF = ,"FEAT_HANGULIN"
+HANGULIN_SRC = hangulin.c
+HANGULIN_OBJ = hangulin.obj
+.ENDIF
+.ENDIF
+
+.IFDEF VIM_TAG_ANYWHITE
+# TAG_ANYWHITE related setup.
+TAG_DEF = ,"FEAT_TAG_ANYWHITE"
+.ENDIF
+
+.IFDEF VIM_MZSCHEME
+# MZSCHEME related setup
+MZSCH_DEF = ,"FEAT_MZSCHEME"
+MZSCH_SRC = if_mzsch.c
+MZSCH_OBJ = if_mzsch.obj
+.ENDIF
+
+.IFDEF VIM_ICONV
+# ICONV related setup
+ICONV_DEF = ,"USE_ICONV"
+.ENDIF
+
+# XDIFF related setup.
+XDIFF_SRC = xdiffi.c,xemit.c,xprepare.c,xutils.c,xhistogram.c,xpatience.c
+XDIFF_OBJ = xdiffi.obj,xemit.obj,xprepare.obj,xutils.obj,xhistogram.obj,xpatience.obj
+XDIFF_INC = ,[.xdiff]
+
+######################################################################
+# End of configuration section.
+# Please, do not change anything below without programming experience.
+######################################################################
+
+MODEL_DEF = "FEAT_$(MODEL)",
+
+# These go into pathdef.c
+VIMUSER = "''F$EDIT(F$GETJPI(" ","USERNAME"),"TRIM")'"
+VIMHOST = "''F$TRNLNM("SYS$NODE")'''F$TRNLNM("UCX$INET_HOST")'.''F$TRNLNM("UCX$INET_DOMAIN")'"
+
+.SUFFIXES : .obj .c
+
+ALL_CFLAGS = /def=($(MODEL_DEF)$(DEFS)$(DEBUG_DEF)$(PERL_DEF)$(PYTHON_DEF) -
+ $(TCL_DEF)$(RUBY_DEF)$(XIM_DEF)$(HANGULIN_DEF)$(TAG_DEF)$(MZSCH_DEF) -
+ $(ICONV_DEF)) -
+ $(CFLAGS)$(GUI_FLAG) -
+ /include=($(C_INC)$(GUI_INC_DIR)$(GUI_INC)$(PERL_INC)$(PYTHON_INC) -
+ $(TCL_INC)$(XDIFF_INC)$(XPM_INC))
+
+# CFLAGS displayed in :ver information
+# It is specially formated for correct display of unix like includes
+# as $(GUI_INC) - replaced with $(GUI_INC_VER)
+# Otherwise should not be any other difference.
+ALL_CFLAGS_VER = /def=($(MODEL_DEF)$(DEFS)$(DEBUG_DEF)$(PERL_DEF)$(PYTHON_DEF) -
+ $(TCL_DEF)$(RUBY_DEF)$(XIM_DEF)$(HANGULIN_DEF)$(TAG_DEF)$(MZSCH_DEF) -
+ $(ICONV_DEF)) -
+ $(CFLAGS)$(GUI_FLAG) -
+ /include=($(C_INC)$(GUI_INC_DIR)$(GUI_INC_VER)$(PERL_INC)$(PYTHON_INC) -
+ $(TCL_INC)$(XDIFF_INC)$(XPM_INC))
+
+ALL_LIBS = $(LIBS) $(GUI_LIB_DIR) $(GUI_LIB) \
+ $(PERL_LIB) $(PYTHON_LIB) $(TCL_LIB) $(RUBY_LIB)
+
+SRC = arabic.c autocmd.c beval.c blob.c blowfish.c buffer.c charset.c crypt.c crypt_zip.c dict.c diff.c digraph.c edit.c eval.c \
+ evalfunc.c ex_cmds.c ex_cmds2.c ex_docmd.c ex_eval.c ex_getln.c if_cscope.c if_xcmdsrv.c farsi.c fileio.c fold.c \
+ getchar.c hardcopy.c hashtab.c indent.c json.c list.c main.c mark.c menu.c mbyte.c memfile.c memline.c message.c misc1.c \
+ misc2.c move.c normal.c ops.c option.c popupmnu.c quickfix.c regexp.c search.c sha256.c sign.c \
+ spell.c spellfile.c syntax.c tag.c term.c termlib.c textprop.c ui.c undo.c userfunc.c version.c screen.c \
+ window.c os_unix.c os_vms.c pathdef.c \
+ $(GUI_SRC) $(PERL_SRC) $(PYTHON_SRC) $(TCL_SRC) \
+ $(RUBY_SRC) $(HANGULIN_SRC) $(MZSCH_SRC) $(XDIFF_SRC)
+
+OBJ = arabic.obj autocmd.obj beval.obj blob.obj blowfish.obj buffer.obj charset.obj crypt.obj crypt_zip.obj dict.obj diff.obj digraph.obj \
+ edit.obj eval.obj evalfunc.obj ex_cmds.obj ex_cmds2.obj ex_docmd.obj ex_eval.obj ex_getln.obj if_cscope.obj \
+ if_xcmdsrv.obj farsi.obj fileio.obj fold.obj getchar.obj hardcopy.obj hashtab.obj indent.obj json.obj list.obj main.obj mark.obj \
+ menu.obj memfile.obj memline.obj message.obj misc1.obj misc2.obj \
+ move.obj mbyte.obj normal.obj ops.obj option.obj popupmnu.obj quickfix.obj \
+ regexp.obj search.obj sha256.obj sign.obj spell.obj spellfile.obj syntax.obj tag.obj term.obj termlib.obj textprop.obj \
+ ui.obj undo.obj userfunc.obj screen.obj version.obj window.obj os_unix.obj \
+ os_vms.obj pathdef.obj if_mzsch.obj\
+ $(GUI_OBJ) $(PERL_OBJ) $(PYTHON_OBJ) $(TCL_OBJ) \
+ $(RUBY_OBJ) $(HANGULIN_OBJ) $(MZSCH_OBJ) $(XDIFF_OBJ)
+
+# Default target is making the executable
+all : [.auto]config.h mmk_compat motif_env gtk_env perl_env python_env tcl_env ruby_env $(TARGET)
+ ! $@
+
+[.auto]config.h : $(CONFIG_H)
+ copy/nolog $(CONFIG_H) [.auto]config.h
+
+mmk_compat :
+ -@ open/write pd pathdef.c
+ -@ write pd "/* Empty file to satisfy MMK depend. */"
+ -@ write pd "/* It will be overwritten later on... */"
+ -@ close pd
+clean :
+ -@ if "''F$SEARCH("*.exe")'" .NES. "" then delete/noconfirm/nolog *.exe;*
+ -@ if "''F$SEARCH("*.obj")'" .NES. "" then delete/noconfirm/nolog *.obj;*
+ -@ if "''F$SEARCH("[.auto]config.h")'" .NES. "" then delete/noconfirm/nolog [.auto]config.h;*
+ -@ if "''F$SEARCH("pathdef.c")'" .NES. "" then delete/noconfirm/nolog pathdef.c;*
+ -@ if "''F$SEARCH("if_perl.c")'" .NES. "" then delete/noconfirm/nolog if_perl.c;*
+ -@ if "''F$SEARCH("*.opt")'" .NES. "" then delete/noconfirm/nolog *.opt;*
+
+# Link the target
+$(TARGET) : $(OBJ)
+ $(LD_DEF) $(LDFLAGS) /exe=$(TARGET) $+ $(ALL_LIBS)
+
+.c.obj :
+ $(CC_DEF) $(ALL_CFLAGS) $<
+
+pathdef.c : check_ccver $(CONFIG_H)
+ -@ write sys$output "creating PATHDEF.C file."
+ -@ open/write pd pathdef.c
+ -@ write pd "/* pathdef.c -- DO NOT EDIT! */"
+ -@ write pd "/* This file is automatically created by MAKE_VMS.MMS"
+ -@ write pd " * Change the file MAKE_VMS.MMS Only. */"
+ -@ write pd "typedef unsigned char char_u;"
+ -@ write pd "char_u *default_vim_dir = (char_u *)"$(VIMLOC)";"
+ -@ write pd "char_u *default_vimruntime_dir = (char_u *)"$(VIMRUN)";"
+ -@ write pd "char_u *all_cflags = (char_u *)""$(CC_DEF)$(ALL_CFLAGS_VER)"";"
+ -@ write pd "char_u *all_lflags = (char_u *)""$(LD_DEF)$(LDFLAGS) /exe=$(TARGET) *.OBJ $(ALL_LIBS)"";"
+ -@ write pd "char_u *compiler_version = (char_u *) ""''CC_VER'"";"
+ -@ write pd "char_u *compiled_user = (char_u *) "$(VIMUSER)";"
+ -@ write pd "char_u *compiled_sys = (char_u *) "$(VIMHOST)";"
+ -@ write pd "char_u *compiled_arch = (char_u *) ""$(MMSARCH_NAME)"";"
+ -@ close pd
+
+if_perl.c : if_perl.xs
+ -@ $(PERL) PERL_ROOT:[LIB.ExtUtils]xsubpp -prototypes -typemap -
+ PERL_ROOT:[LIB.ExtUtils]typemap if_perl.xs >> $@
+
+make_vms.mms :
+ -@ write sys$output "The name of the makefile MUST be <MAKE_VMS.MMS> !!!"
+
+.IFDEF CCVER
+# This part can make some complications if you're using some predefined
+# symbols/flags for your compiler. If does, just comment out CCVER variable
+check_ccver :
+ -@ define sys$output cc_ver.tmp
+ -@ $(CC_DEF)/version
+ -@ deassign sys$output
+ -@ open/read file cc_ver.tmp
+ -@ read file CC_VER
+ -@ close file
+ -@ delete/noconfirm/nolog cc_ver.tmp.*
+.ELSE
+check_ccver :
+ -@ !
+.ENDIF
+
+.IFDEF MOTIF
+motif_env :
+.IFDEF XPM
+ -@ write sys$output "using DECW/Motif/XPM environment."
+.ELSE
+ -@ write sys$output "using DECW/Motif environment."
+.ENDIF
+ -@ write sys$output "creating OS_VMS_MOTIF.OPT file."
+ -@ open/write opt_file OS_VMS_MOTIF.OPT
+ -@ write opt_file "sys$share:decw$xmlibshr12.exe/share,-"
+ -@ write opt_file "sys$share:decw$xtlibshrr5.exe/share,-"
+ -@ write opt_file "sys$share:decw$xlibshr.exe/share"
+ -@ close opt_file
+.ELSE
+motif_env :
+ -@ !
+.ENDIF
+
+
+.IFDEF GTK
+gtk_env :
+ -@ write sys$output "using GTK environment:"
+ -@ define/nolog gtk_root /trans=conc $(GTK_DIR)
+ -@ show logical gtk_root
+ -@ write sys$output " include path: "$(GUI_INC)""
+ -@ write sys$output "creating OS_VMS_GTK.OPT file."
+ -@ open/write opt_file OS_VMS_GTK.OPT
+ -@ write opt_file "gtk_root:[glib]libglib.exe /share,-"
+ -@ write opt_file "gtk_root:[glib.gmodule]libgmodule.exe /share,-"
+ -@ write opt_file "gtk_root:[gtk.gdk]libgdk.exe /share,-"
+ -@ write opt_file "gtk_root:[gtk.gtk]libgtk.exe /share,-"
+ -@ write opt_file "sys$share:decw$xmlibshr12.exe/share,-"
+ -@ write opt_file "sys$share:decw$xtlibshrr5.exe/share,-"
+ -@ write opt_file "sys$share:decw$xlibshr.exe/share"
+ -@ close opt_file
+.ELSE
+gtk_env :
+ -@ !
+.ENDIF
+
+.IFDEF VIM_PERL
+perl_env :
+ -@ write sys$output "using PERL environment:"
+ -@ show logical PERLSHR
+ -@ write sys$output " include path: ""$(PERL_INC)"""
+ -@ show symbol perl
+ -@ open/write pd if_perl.c
+ -@ write pd "/* Empty file to satisfy MMK depend. */"
+ -@ write pd "/* It will be overwritten later on... */"
+ -@ close pd
+ -@ write sys$output "creating OS_VMS_PERL.OPT file."
+ -@ open/write opt_file OS_VMS_PERL.OPT
+ -@ write opt_file "PERLSHR /share"
+ -@ close opt_file
+.ELSE
+perl_env :
+ -@ !
+.ENDIF
+
+.IFDEF VIM_PYTHON
+python_env :
+ -@ write sys$output "using PYTHON environment:"
+ -@ show logical PYTHON_INCLUDE
+ -@ show logical PYTHON_OLB
+ -@ write sys$output "creating OS_VMS_PYTHON.OPT file."
+ -@ open/write opt_file OS_VMS_PYTHON.OPT
+ -@ write opt_file "PYTHON_OLB:PYTHON.OLB /share"
+ -@ close opt_file
+.ELSE
+python_env :
+ -@ !
+.ENDIF
+
+.IFDEF VIM_TCL
+tcl_env :
+ -@ write sys$output "using TCL environment:"
+ -@ show logical TCLSHR
+ -@ write sys$output " include path: ""$(TCL_INC)"""
+ -@ write sys$output "creating OS_VMS_TCL.OPT file."
+ -@ open/write opt_file OS_VMS_TCL.OPT
+ -@ write opt_file "TCLSHR /share"
+ -@ close opt_file
+.ELSE
+tcl_env :
+ -@ !
+.ENDIF
+
+.IFDEF VIM_RUBY
+ruby_env :
+ -@ write sys$output "using RUBY environment:"
+ -@ write sys$output " include path: ""$(RUBY_INC)"""
+ -@ write sys$output "creating OS_VMS_RUBY.OPT file."
+ -@ open/write opt_file OS_VMS_RUBY.OPT
+ -@ write opt_file "RUBYSHR /share"
+ -@ close opt_file
+.ELSE
+ruby_env :
+ -@ !
+.ENDIF
+
+arabic.obj : arabic.c vim.h
+autocmd.obj : autocmd.c vim.h [.auto]config.h feature.h os_unix.h
+blowfish.obj : blowfish.c vim.h [.auto]config.h feature.h os_unix.h
+blob.obj : blob.c vim.h [.auto]config.h feature.h os_unix.h
+buffer.obj : buffer.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h \
+ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
+ globals.h farsi.h arabic.h version.h
+charset.obj : charset.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h \
+ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
+ globals.h farsi.h arabic.h
+crypt.obj : crypt.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h option.h structs.h regexp.h gui.h \
+ beval.h [.proto]gui_beval.pro alloc.h ex_cmds.h spell.h proto.h \
+ globals.h farsi.h arabic.h
+crypt_zip.obj : crypt_zip.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h option.h structs.h \
+ regexp.h gui.h beval.h [.proto]gui_beval.pro alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+dict.obj : dict.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h option.h structs.h regexp.h gui.h \
+ beval.h [.proto]gui_beval.pro alloc.h ex_cmds.h spell.h proto.h \
+ globals.h farsi.h arabic.h
+diff.obj : diff.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
+ [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h farsi.h \
+ arabic.h
+digraph.obj : digraph.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h \
+ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
+ globals.h farsi.h arabic.h
+edit.obj : edit.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
+ [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h farsi.h \
+ arabic.h
+eval.obj : eval.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
+ [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h farsi.h \
+ arabic.h version.h
+evalfunc.obj : evalfunc.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h option.h structs.h \
+ regexp.h gui.h beval.h [.proto]gui_beval.pro alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h version.h
+ex_cmds.obj : ex_cmds.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h \
+ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
+ globals.h farsi.h arabic.h version.h
+ex_cmds2.obj : ex_cmds2.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h \
+ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
+ globals.h farsi.h arabic.h version.h
+ex_docmd.obj : ex_docmd.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h \
+ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
+ globals.h farsi.h arabic.h
+ex_eval.obj : ex_eval.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h \
+ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
+ globals.h farsi.h arabic.h
+ex_getln.obj : ex_getln.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h \
+ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
+ globals.h farsi.h arabic.h
+farsi.obj : farsi.c vim.h
+fileio.obj : fileio.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h \
+ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
+ globals.h farsi.h arabic.h
+fold.obj : fold.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
+ [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h farsi.h \
+ arabic.h
+getchar.obj : getchar.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h \
+ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
+ globals.h farsi.h arabic.h
+hardcopy.obj : hardcopy.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h \
+ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
+ globals.h farsi.h arabic.h
+hashtab.obj : hashtab.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h \
+ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
+ globals.h farsi.h arabic.h
+if_cscope.obj : if_cscope.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h \
+ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
+ globals.h farsi.h arabic.h if_cscope.h
+if_xcmdsrv.obj : if_xcmdsrv.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h \
+ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
+ globals.h farsi.h arabic.h version.h
+if_mzsch.obj : if_mzsch.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h option.h structs.h \
+ regexp.h gui.h beval.h [.proto]gui_beval.pro ex_cmds.h proto.h \
+ globals.h farsi.h arabic.h if_mzsch.h
+indent.obj : indent.c vim.h [.auto]config.h feature.h os_unix.h
+json.obj : json.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
+ [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h farsi.h \
+ arabic.h version.h
+list.obj : list.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h option.h structs.h regexp.h gui.h \
+ beval.h [.proto]gui_beval.pro alloc.h ex_cmds.h spell.h proto.h \
+ globals.h farsi.h arabic.h
+main.obj : main.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
+ [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h farsi.h \
+ arabic.h farsi.c arabic.c
+mark.obj : mark.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
+ [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h farsi.h \
+ arabic.h
+memfile.obj : memfile.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h \
+ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
+ globals.h farsi.h arabic.h
+memline.obj : memline.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h \
+ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
+ globals.h farsi.h arabic.h
+menu.obj : menu.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
+ [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h farsi.h \
+ arabic.h
+message.obj : message.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h \
+ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
+ globals.h farsi.h arabic.h
+misc1.obj : misc1.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
+ [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h farsi.h \
+ arabic.h version.h
+misc2.obj : misc2.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
+ [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h farsi.h \
+ arabic.h
+move.obj : move.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
+ [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h farsi.h \
+ arabic.h
+mbyte.obj : mbyte.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
+ [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h farsi.h \
+ arabic.h
+normal.obj : normal.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h \
+ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
+ globals.h farsi.h arabic.h
+ops.obj : ops.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
+ [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h farsi.h \
+ arabic.h
+option.obj : option.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h \
+ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
+ globals.h farsi.h arabic.h
+os_unix.obj : os_unix.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h \
+ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
+ globals.h farsi.h arabic.h os_unixx.h
+os_vms.obj : os_vms.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h \
+ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
+ globals.h farsi.h arabic.h os_unixx.h
+pathdef.obj : pathdef.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h \
+ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
+ globals.h farsi.h arabic.h
+popupmnu.obj : popupmnu.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h \
+ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
+ globals.h farsi.h arabic.h
+quickfix.obj : quickfix.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h \
+ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
+ globals.h farsi.h arabic.h
+regexp.obj : regexp.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h \
+ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
+ globals.h farsi.h arabic.h
+screen.obj : screen.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h \
+ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
+ globals.h farsi.h arabic.h
+search.obj : search.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h \
+ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
+ globals.h farsi.h arabic.h
+sha256.obj : sha256.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h option.h structs.h regexp.h gui.h \
+ beval.h [.proto]gui_beval.pro alloc.h ex_cmds.h spell.h proto.h \
+ globals.h farsi.h arabic.h
+sign.obj : sign.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h option.h structs.h regexp.h gui.h \
+ beval.h [.proto]gui_beval.pro alloc.h ex_cmds.h spell.h proto.h \
+ globals.h farsi.h arabic.h
+spell.obj : spell.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h \
+ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
+ globals.h farsi.h arabic.h
+spellfile.obj : spellfile.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h option.h structs.h \
+ regexp.h gui.h beval.h [.proto]gui_beval.pro alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+syntax.obj : syntax.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h \
+ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
+ globals.h farsi.h arabic.h
+tag.obj : tag.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
+ [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h farsi.h \
+ arabic.h
+term.obj : term.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
+ [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h farsi.h \
+ arabic.h
+termlib.obj : termlib.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
+ [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h farsi.h \
+ arabic.h
+textprop.obj : textprop.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
+ [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h farsi.h \
+ arabic.h
+ui.obj : ui.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
+ [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h farsi.h \
+ arabic.h
+undo.obj : undo.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
+ [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h farsi.h \
+ arabic.h
+userfunc.obj : userfunc.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h option.h structs.h \
+ regexp.h gui.h beval.h [.proto]gui_beval.pro alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+version.obj : version.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h \
+ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
+ globals.h farsi.h arabic.h version.h
+window.obj : window.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h \
+ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
+ globals.h farsi.h arabic.h
+gui.obj : gui.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
+ [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h farsi.h \
+ arabic.h
+gui_gtk.obj : gui_gtk.c gui_gtk_f.h vim.h [.auto]config.h feature.h \
+ os_unix.h ascii.h keymap.h term.h macros.h structs.h \
+ regexp.h gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h \
+ proto.h globals.h farsi.h arabic.h [-.pixmaps]stock_icons.h
+gui_gtk_f.obj : gui_gtk_f.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h \
+ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
+ globals.h farsi.h arabic.h gui_gtk_f.h
+gui_motif.obj : gui_motif.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h \
+ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
+ globals.h farsi.h arabic.h [-.pixmaps]alert.xpm [-.pixmaps]error.xpm \
+ [-.pixmaps]generic.xpm [-.pixmaps]info.xpm [-.pixmaps]quest.xpm
+gui_athena.obj : gui_athena.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h \
+ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
+ globals.h farsi.h arabic.h gui_at_sb.h
+gui_gtk_x11.obj : gui_gtk_x11.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h \
+ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
+ globals.h farsi.h arabic.h gui_gtk_f.h [-.runtime]vim32x32.xpm \
+ [-.runtime]vim16x16.xpm [-.runtime]vim48x48.xpm
+gui_x11.obj : gui_x11.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h \
+ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
+ globals.h farsi.h arabic.h [-.runtime]vim32x32.xpm \
+ [-.runtime]vim16x16.xpm [-.runtime]vim48x48.xpm [-.pixmaps]tb_new.xpm \
+ [-.pixmaps]tb_open.xpm [-.pixmaps]tb_close.xpm [-.pixmaps]tb_save.xpm \
+ [-.pixmaps]tb_print.xpm [-.pixmaps]tb_cut.xpm [-.pixmaps]tb_copy.xpm \
+ [-.pixmaps]tb_paste.xpm [-.pixmaps]tb_find.xpm \
+ [-.pixmaps]tb_find_next.xpm [-.pixmaps]tb_find_prev.xpm \
+ [-.pixmaps]tb_find_help.xpm [-.pixmaps]tb_exit.xpm \
+ [-.pixmaps]tb_undo.xpm [-.pixmaps]tb_redo.xpm [-.pixmaps]tb_help.xpm \
+ [-.pixmaps]tb_macro.xpm [-.pixmaps]tb_make.xpm \
+ [-.pixmaps]tb_save_all.xpm [-.pixmaps]tb_jump.xpm \
+ [-.pixmaps]tb_ctags.xpm [-.pixmaps]tb_load_session.xpm \
+ [-.pixmaps]tb_save_session.xpm [-.pixmaps]tb_new_session.xpm \
+ [-.pixmaps]tb_blank.xpm [-.pixmaps]tb_maximize.xpm \
+ [-.pixmaps]tb_split.xpm [-.pixmaps]tb_minimize.xpm \
+ [-.pixmaps]tb_shell.xpm [-.pixmaps]tb_replace.xpm \
+ [-.pixmaps]tb_vsplit.xpm [-.pixmaps]tb_maxwidth.xpm \
+ [-.pixmaps]tb_minwidth.xpm
+gui_at_sb.obj : gui_at_sb.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h \
+ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
+ globals.h farsi.h arabic.h gui_at_sb.h
+gui_at_fs.obj : gui_at_fs.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h \
+ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
+ globals.h farsi.h arabic.h gui_at_sb.h
+pty.obj : pty.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
+ [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h farsi.h \
+ arabic.h
+hangulin.obj : hangulin.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h \
+ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
+ globals.h farsi.h arabic.h
+if_perl.obj : [.auto]if_perl.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h \
+ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
+ globals.h farsi.h arabic.h
+if_perlsfio.obj : if_perlsfio.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h \
+ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
+ globals.h farsi.h arabic.h
+if_python.obj : if_python.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h \
+ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
+ globals.h farsi.h arabic.h
+if_tcl.obj : if_tcl.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h \
+ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
+ globals.h farsi.h arabic.h
+if_ruby.obj : if_ruby.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h \
+ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
+ globals.h farsi.h arabic.h version.h
+beval.obj : beval.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h \
+ gui.h beval.h option.h ex_cmds.h proto.h \
+ globals.h farsi.h arabic.h
+gui_beval.obj : gui_beval.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h \
+ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
+ globals.h farsi.h arabic.h
+workshop.obj : workshop.c [.auto]config.h integration.h vim.h feature.h \
+ os_unix.h ascii.h keymap.h term.h macros.h structs.h \
+ regexp.h gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h \
+ proto.h globals.h farsi.h arabic.h version.h workshop.h
+wsdebug.obj : wsdebug.c
+integration.obj : integration.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h \
+ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
+ globals.h farsi.h arabic.h integration.h
+netbeans.obj : netbeans.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h \
+ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
+ globals.h farsi.h arabic.h version.h
+gui_xmdlg.obj : gui_xmdlg.c [.auto]config.h vim.h feature.h os_unix.h
+gui_xmebw.obj : gui_xmebw.c [.auto]config.h vim.h feature.h os_unix.h
+xdiffi.obj : [.xdiff]xdiffi.c [.xdiff]xinclude.h [.auto]config.h vim.h feature.h os_unix.h
+xemit.obj : [.xdiff]xemit.c [.xdiff]xinclude.h [.auto]config.h vim.h feature.h os_unix.h
+xprepare.obj : [.xdiff]xprepare.c [.xdiff]xinclude.h [.auto]config.h vim.h feature.h os_unix.h
+xutils.obj : [.xdiff]xutils.c [.xdiff]xinclude.h [.auto]config.h vim.h feature.h os_unix.h
+xhistogram.obj : [.xdiff]xhistogram.c [.xdiff]xinclude.h [.auto]config.h vim.h feature.h os_unix.h
+xpatience.obj : [.xdiff]xpatience.c [.xdiff]xinclude.h [.auto]config.h vim.h feature.h os_unix.h
diff --git a/src/Makefile b/src/Makefile
new file mode 100644
index 0000000..8b83e95
--- /dev/null
+++ b/src/Makefile
@@ -0,0 +1,3871 @@
+# Makefile for Vim on Unix and Unix-like systems vim:ts=8:sw=8:tw=78
+#
+# This Makefile is loosely based on the GNU Makefile conventions found in
+# standards.info.
+#
+# Compiling Vim, summary:
+#
+# 3. make
+# 5. make install
+#
+# Compiling Vim, details:
+#
+# Edit this file for adjusting to your system. You should not need to edit any
+# other file for machine specific things!
+# The name of this file MUST be Makefile (note the uppercase 'M').
+#
+# 1. Edit this Makefile {{{1
+# The defaults for Vim should work on most machines, but you may want to
+# uncomment some lines or make other changes below to tune it to your
+# system, compiler or preferences. Uncommenting means that the '#' in
+# the first column of a line is removed.
+# - If you want a version of Vim that is small and starts up quickly,
+# you might want to disable the GUI, X11, Perl, Python and Tcl.
+# - Uncomment the line with --disable-gui if you have Motif, GTK and/or
+# Athena but don't want to make gvim (the GUI version of Vim with nice
+# menus and scrollbars, but makes Vim bigger and startup slower).
+# - Uncomment --disable-darwin if on Mac OS X but you want to compile a
+# Unix version.
+# - Uncomment the line "CONF_OPT_X = --without-x" if you have X11 but
+# want to disable using X11 libraries. This speeds up starting Vim,
+# but the window title will not be set and the X11 selection can not
+# be used.
+# - Uncomment the line "CONF_OPT_XSMP = --disable-xsmp" if you have the
+# X11 Session Management Protocol (XSMP) library (libSM) but do not
+# want to use it.
+# This can speedup Vim startup but Vim loses the ability to catch the
+# user logging out from session-managers like GNOME and work
+# could be lost.
+# - Uncomment one or more of these lines to include an interface;
+# each makes Vim quite a bit bigger:
+# --enable-luainterp for Lua interpreter
+# --enable-mzschemeinterp for MzScheme interpreter
+# --enable-perlinterp for Perl interpreter
+# --enable-python3interp for Python3 interpreter
+# --enable-pythoninterp for Python interpreter
+# --enable-rubyinterp for Ruby interpreter
+# --enable-tclinterp for Tcl interpreter
+# --enable-cscope for Cscope interface
+# - Uncomment one of the lines with --with-features= to enable a set of
+# features (but not the interfaces just mentioned).
+# - Uncomment the line with --disable-acl to disable ACL support even
+# though your system supports it.
+# - Uncomment the line with --disable-gpm to disable gpm support
+# even though you have gpm libraries and includes.
+# - Uncomment the line with --disable-sysmouse to disable sysmouse
+# support even though you have /dev/sysmouse and includes.
+# - Uncomment one of the lines with CFLAGS and/or CC if you have
+# something very special or want to tune the optimizer.
+# - Search for the name of your system to see if it needs anything
+# special.
+# - A few versions of make use '.include "file"' instead of 'include
+# file'. Adjust the include line below if yours does.
+#
+# 2. Edit feature.h {{{1
+# Only if you do not agree with the default compile features, e.g.:
+# - you want Vim to be as vi compatible as it can be
+# - you want to use Emacs tags files
+# - you want right-to-left editing (Hebrew)
+# - you want 'langmap' support (Greek)
+# - you want to remove features to make Vim smaller
+#
+# 3. "make" {{{1
+# Will first run ./configure with the options in this file. Then it will
+# start make again on this Makefile to do the compiling. You can also do
+# this in two steps with:
+# make config
+# make
+# The configuration phase creates/overwrites auto/config.h and
+# auto/config.mk.
+# The configure script is created with "make autoconf". It can detect
+# different features of your system and act accordingly. However, it is
+# not correct for all systems. Check this:
+# - If you have X windows, but configure could not find it or reported
+# another include/library directory then you wanted to use, you have
+# to set CONF_OPT_X below. You might also check the installation of
+# xmkmf.
+# - If you have --enable-gui=motif and have Motif on your system, but
+# configure reports "checking for location of gui... <not found>", you
+# have to set GUI_INC_LOC and GUI_LIB_LOC below.
+# If you changed something, do this to run configure again:
+# make reconfig
+#
+# - If you do not trust the automatic configuration code, then inspect
+# auto/config.h and auto/config.mk, before starting the actual build
+# phase. If possible edit this Makefile, rather than auto/config.mk --
+# especially look at the definition of VIMLOC below. Note that the
+# configure phase overwrites auto/config.mk and auto/config.h again.
+# - If you get error messages, find out what is wrong and try to correct
+# it in this Makefile. You may need to do "make reconfig" when you
+# change anything that configure uses (e.g. switching from an old C
+# compiler to an ANSI C compiler). Only when auto/configure does
+# something wrong you may need to change one of the other files. If
+# you find a clean way to fix the problem, consider sending a note to
+# the author of autoconf (bug-gnu-utils@prep.ai.mit.edu) or Vim
+# (Bram@vim.org). Don't bother to do that when you made a hack
+# solution for a non-standard system.
+#
+# 4. "make test" {{{1
+# This is optional. This will run Vim scripts on a number of test
+# files, and compare the produced output with the expected output.
+# If all is well, you will get the "ALL DONE" message in the end. If a
+# test fails you get "TEST FAILURE". See below (search for "/^test").
+#
+# 5. "make install" {{{1
+# If the new Vim seems to be working OK you can install it and the
+# documentation in the appropriate location. The default is
+# "/usr/local". Change "prefix" below to change the location.
+# "auto/pathdef.c" will be compiled again after changing this to make
+# the executable know where the help files are located.
+# Note that any existing executable is removed or overwritten. If you
+# want to keep it you will have to make a backup copy first.
+# The runtime files are in a different directory for each version. You
+# might want to delete an older version.
+# If you don't want to install everything, there are other targets:
+# make installvim only installs Vim, not the tools
+# make installvimbin only installs the Vim executable
+# make installruntime installs most of the runtime files
+# make installrtbase only installs the Vim help and
+# runtime files
+# make installlinks only installs the Vim binary links
+# make installmanlinks only installs the Vim manpage links
+# make installmacros only installs the Vim macros
+# make installpack only installs the packages
+# make installtutorbin only installs the Vim tutor program
+# make installtutor only installs the Vim tutor files
+# make installspell only installs the spell files
+# make installtools only installs xxd
+# If you install Vim, not to install for real but to prepare a package
+# or RPM, set DESTDIR to the root of the tree.
+#
+# 6. Use Vim until a new version comes out. {{{1
+#
+# 7. "make uninstall_runtime" {{{1
+# Will remove the runtime files for the current version. This is safe
+# to use while another version is being used, only version-specific
+# files will be deleted.
+# To remove the runtime files of another version:
+# make uninstall_runtime VIMRTDIR=/vim54
+# If you want to delete all installed files, use:
+# make uninstall
+# Note that this will delete files that have the same name for any
+# version, thus you might need to do a "make install" soon after this.
+# Be careful not to remove a version of Vim that is still being used!
+# To find out which files and directories will be deleted, use:
+# make -n uninstall
+# }}}
+#
+### This Makefile has been successfully tested on many systems. {{{
+### Only the ones that require special options are mentioned here.
+### Check the (*) column for remarks, listed below.
+### Later code changes may cause small problems, otherwise Vim is supposed to
+### compile and run without problems.
+
+#system: configurations: version (*) tested by:
+#------------- ------------------------ ------- - ----------
+#AIX 3.2.5 cc (not gcc) - 4.5 (M) Will Fiveash
+#AIX 4 cc +X11 -GUI 3.27 (4) Axel Kielhorn
+#AIX 4.1.4 cc +X11 +GUI 4.5 (5) Nico Bakker
+#AIX 4.2.1 cc 5.2k (C) Will Fiveash
+#AIX 4.3.3.12 xic 3.6.6 5.6 (5) David R. Favor
+#A/UX 3.1.1 gcc +X11 4.0 (6) Jim Jagielski
+#BeOS PR mwcc DR3 5.0n (T) Olaf Seibert
+#BSDI 2.1 (x86) shlicc2 gcc-2.6.3 -X11 X11R6 4.5 (1) Jos Backus
+#BSD/OS 3.0 (x86) gcc gcc-2.7.2.1 -X11 X11R6 4.6c (1) Jos Backus
+#CX/UX 6.2 cc +X11 +GUI_Mofif 5.4 (V) Kipp E. Howard
+#DG/UX 5.4* gcc 2.5.8 GUI 5.0e (H) Jonas Schlein
+#DG/UX 5.4R4.20 gcc 2.7.2 GUI 5.0s (H) Rocky Olive
+#HP-UX (most) c89 cc 5.1 (2) Bram Moolenaar
+#HP-UX_9.04 cc +X11 +Motif 5.0 (2) Carton Lao
+#Irix 6.3 (O2) cc ? 4.5 (L) Edouard Poor
+#Irix 6.4 cc ? 5.0m (S) Rick Sayre
+#Irix 6.5 cc ? 6.0 (S) David Harrison
+#Irix 64 bit 4.5 (K) Jon Wright
+#Linux 2.0 gcc-2.7.2 Infomagic Motif 4.3 (3) Ronald Rietman
+#Linux 2.0.31 gcc +X11 +GUI Athena 5.0w (U) Darren Hiebert
+#LynxOS 3.0.1 2.9-gnupro-98r2 +X11 +GUI Athena 5.7.1(O) Lorenz Hahn
+#LynxOS 3.1.0 2.9-gnupro-98r2 +X11 +GUI Athena 5.7.1(O) Lorenz Hahn
+#NEC UP4800 UNIX_SV 4.2MP cc +X11R6 Motif,Athena4.6b (Q) Lennart Schultz
+#NetBSD 1.0A gcc-2.4.5 -X11 -GUI 3.21 (X) Juergen Weigert
+#QNX 4.2 wcc386-10.6 -X11 4.2 (D) G.F. Desrochers
+#QNX 4.23 Watcom -X11 4.2 (F) John Oleynick
+#SCO Unix v3.2.5 cc +X11 Motif 3.27 (C) M. Kuperblum
+#SCO Open Server 5 gcc 2.7.2.3 +X11 +GUI Motif 5.3 (A) Glauber Ribeiro
+#SINIX-N 5.43 RM400 R4000 cc +X11 +GUI 5.0l (I) Martin Furter
+#SINIX-Z 5.42 i386 gcc 2.7.2.3 +X11 +GUI Motif 5.1 (I) Joachim Fehn
+#SINIX-Y 5.43 RM600 R4000 gcc 2.7.2.3 +X11 +GUI Motif 5.1 (I) Joachim Fehn
+#Reliant/SINIX 5.44 cc +X11 +GUI 5.5a (I) B. Pruemmer
+#SNI Targon31 TOS 4.1.11 gcc-2.4.5 +X11 -GUI 4.6c (B) Paul Slootman
+#Solaris 2.4 (Sparc) cc +X11 +GUI 3.29 (9) Glauber
+#Solaris 2.4/2.5 clcc +X11 -GUI openwin 3.20 (7) Robert Colon
+#Solaris 2.5 (sun4m) cc (SC4.0) +X11R6 +GUI (CDE) 4.6b (E) Andrew Large
+#Solaris 2.5 cc +X11 +GUI Athena 4.2 (9) Sonia Heimann
+#Solaris 2.5 gcc 2.5.6 +X11 Motif 5.0m (R) Ant. Colombo
+#Solaris 2.6 gcc 2.8.1 ncurses 5.3 (G) Larry W. Virden
+#Solaris with -lthread 5.5 (W) K. Nagano
+#Solaris gcc (b) Riccardo
+#SunOS 4.1.x +X11 -GUI 5.1b (J) Bram Moolenaar
+#SunOS 4.1.3_U1 (sun4c) gcc +X11 +GUI Athena 5.0w (J) Darren Hiebert
+#SUPER-UX 6.2 (NEC SX-4) cc +X11R6 Motif,Athena4.6b (P) Lennart Schultz
+#Tandem/NSK (c) Matthew Woehlke
+#Unisys 6035 cc +X11 Motif 5.3 (8) Glauber Ribeiro
+#ESIX V4.2 cc +X11 6.0 (a) Reinhard Wobst
+#Mac OS X 10.[23] gcc Carbon 6.2 (x) Bram Moolenaar
+# }}}
+
+# (*) Remarks: {{{
+#
+# (1) Uncomment line below for shlicc2
+# (2) HPUX with compile problems or wrong digraphs, uncomment line below
+# (3) Infomagic Motif needs GUI_LIB_LOC and GUI_INC_LOC set, see below.
+# And add "-lXpm" to MOTIF_LIBS2.
+# (4) For cc the optimizer must be disabled (use CFLAGS= after running
+# configure) (symptom: ":set termcap" output looks weird).
+# (5) Compiler may need extra argument, see below.
+# (6) See below for a few lines to uncomment
+# (7) See below for lines which enable the use of clcc
+# (8) Needs some EXTRA_LIBS, search for Unisys below
+# (9) Needs an extra compiler flag to compile gui_at_sb.c, see below.
+# (A) May need EXTRA_LIBS, see below
+# (B) Can't compile GUI because there is no waitpid()... Disable GUI below.
+# (C) Force the use of curses instead of termcap, see below.
+# (D) Uncomment lines below for QNX
+# (E) You might want to use termlib instead of termcap, see below.
+# (F) See below for instructions.
+# (G) Using ncurses version 4.2 has reported to cause a crash. Use the
+# Sun curses library instead.
+# (H) See line for EXTRA_LIBS below.
+# (I) SINIX-N 5.42 and 5.43 need some EXTRA_LIBS. Also for Reliant-Unix.
+# (J) If you get undefined symbols, see below for a solution.
+# (K) See lines to uncomment below for machines with 64 bit pointers.
+# (L) For Silicon Graphics O2 workstations remove "-lnsl" from auto/config.mk
+# (M) gcc version cygnus-2.0.1 does NOT work (symptom: "dl" deletes two
+# characters instead of one).
+# (N) SCO with decmouse.
+# (O) LynxOS needs EXTRA_LIBS, see below.
+# (P) For SuperUX 6.2 on NEC SX-4 see a few lines below to uncomment.
+# (Q) For UNIXSVR 4.2MP on NEC UP4800 see below for lines to uncomment.
+# (R) For Solaris 2.5 (or 2.5.1) with gcc > 2.5.6, uncomment line below.
+# (S) For Irix 6.x with MipsPro compiler, use -OPT:Olimit. See line below.
+# (T) See ../doc/os_beos.txt.
+# (U) Must uncomment CONF_OPT_PYTHON option below to disable Python
+# detection, since the configure script runs into an error when it
+# detects Python (probably because of the bash shell).
+# (V) See lines to uncomment below.
+# (X) Need to use the .include "auto/config.mk" line below
+# (Y) See line with c89 below
+# (Z) See lines with cc or c89 below
+# (a) See line with EXTRA_LIBS below.
+# (b) When using gcc with the Solaris linker, make sure you don't use GNU
+# strip, otherwise the binary may not run: "Cannot find ELF".
+# (c) Add -lfloss to EXTRA_LIBS, see below.
+# (x) When you get warnings for precompiled header files, run
+# "sudo fixPrecomps". Also see CONF_OPT_DARWIN below.
+# }}}
+
+
+#DO NOT CHANGE the next line, we need it for configure to find the compiler
+#instead of using the default from the "make" program.
+#Use a line further down to change the value for CC.
+CC=
+
+# Change and use these defines if configure cannot find your Motif stuff.
+# Unfortunately there is no "standard" location for Motif. {{{
+# These defines can contain a single directory (recommended) or a list of
+# directories (for when you are working with several systems). The LAST
+# directory that exists is used.
+# When changed, run "make reconfig" next!
+#GUI_INC_LOC = -I/usr/include/Motif2.0 -I/usr/include/Motif1.2
+#GUI_LIB_LOC = -L/usr/lib/Motif2.0 -L/usr/lib/Motif1.2
+### Use these two lines for Infomagic Motif (3)
+#GUI_INC_LOC = -I/usr/X11R6/include
+#GUI_LIB_LOC = -L/usr/X11R6/lib
+# }}}
+
+# Defaults used when auto/config.mk does not exist.
+srcdir = .
+VIMNAME = vim
+EXNAME = ex
+VIEWNAME = view
+
+######################## auto/config.mk ######################## {{{1
+# At this position auto/config.mk is included. When starting from the
+# toplevel Makefile it is almost empty. After running auto/configure it
+# contains settings that have been discovered for your system. Settings below
+# this include override settings in auto/config.mk!
+
+# Note: If make fails because auto/config.mk does not exist (it is not
+# included in the repository), do:
+# cp config.mk.dist auto/config.mk
+
+# (X) How to include auto/config.mk depends on the version of "make" you have,
+# if the current choice doesn't work, try the other one.
+
+include auto/config.mk
+#.include "auto/config.mk"
+CClink = $(CC)
+
+#}}}
+
+# Include the configuration choices first, so we can override everything
+# below. As shipped, this file contains a target that causes to run
+# configure. Once configure was run, this file contains a list of
+# make variables with predefined values instead. Thus any second invocation
+# of make, will build Vim.
+
+# CONFIGURE - configure arguments {{{1
+# You can give a lot of options to configure.
+# Change this to your desire and do 'make config' afterwards
+
+# examples you can uncomment:
+#CONF_ARGS1 = --exec-prefix=/usr
+#CONF_ARGS2 = --with-vim-name=vim8 --with-ex-name=ex8 --with-view-name=view8
+#CONF_ARGS3 = --with-global-runtime=/etc/vim,/usr/share/vim
+#CONF_ARGS4 = --with-local-dir=/usr/share
+#CONF_ARGS5 = --without-local-dir
+
+# Use this one if you distribute a modified version of Vim.
+#CONF_ARGS6 = --with-modified-by="John Doe"
+
+# GUI - For creating Vim with GUI (gvim) (B)
+# Uncomment this line when you don't want to get the GUI version, although you
+# have GTK, Motif and/or Athena. Also use --without-x if you don't want X11
+# at all.
+#CONF_OPT_GUI = --disable-gui
+
+# Uncomment one of these lines if you have that GUI but don't want to use it.
+# The automatic check will use another one that can be found.
+# Gnome is disabled by default, because it may cause trouble.
+#
+# When both GTK+ 2 and GTK+ 3 are possible then GTK+ 2 will be selected.
+# To use GTK+ 3 instead use --enable-gui=gtk3 (see below).
+#CONF_OPT_GUI = --disable-gtk2-check
+#CONF_OPT_GUI = --enable-gnome-check
+#CONF_OPT_GUI = --disable-gtk3-check
+#CONF_OPT_GUI = --disable-motif-check
+#CONF_OPT_GUI = --disable-athena-check
+#CONF_OPT_GUI = --disable-nextaw-check
+
+# Uncomment one of these lines to select a specific GUI to use.
+# When using "yes" or nothing, configure will use the first one found: GTK+,
+# Motif or Athena.
+#
+# GTK versions that are known not to work 100% are rejected.
+# Use "--disable-gtktest" to accept them anyway.
+# For GTK 1 use Vim 7.2.
+#
+# GNOME means GTK with Gnome support. If using GTK and --enable-gnome-check
+# is used then GNOME will automatically be used if it is found. If you have
+# GNOME, but do not want to use it (e.g., want a GTK-only version), then use
+# --enable-gui=gtk or leave out --enable-gnome-check.
+#
+# GNOME makes sense only for GTK+ 2. Avoid use of --enable-gnome-check with
+# GTK+ 3 build, as the functionality of GNOME is already incooperated into
+# GTK+ 3.
+#
+# If the selected GUI isn't found, the GUI is disabled automatically
+#CONF_OPT_GUI = --enable-gui=gtk2
+#CONF_OPT_GUI = --enable-gui=gtk2 --disable-gtktest
+#CONF_OPT_GUI = --enable-gui=gnome2
+#CONF_OPT_GUI = --enable-gui=gnome2 --disable-gtktest
+#CONF_OPT_GUI = --enable-gui=gtk3
+#CONF_OPT_GUI = --enable-gui=gtk3 --disable-gtktest
+#CONF_OPT_GUI = --enable-gui=motif
+#CONF_OPT_GUI = --enable-gui=motif --with-motif-lib="-static -lXm -shared"
+#CONF_OPT_GUI = --enable-gui=athena
+#CONF_OPT_GUI = --enable-gui=nextaw
+
+# Carbon GUI for Mac OS X
+#CONF_OPT_GUI = --enable-gui=carbon
+
+# Uncomment this line to run an individual test with gvim.
+#GUI_TESTARG = GUI_FLAG=-g
+
+# DARWIN - detecting Mac OS X
+# Uncomment this line when you want to compile a Unix version of Vim on
+# Darwin. None of the Mac specific options or files will be used.
+#CONF_OPT_DARWIN = --disable-darwin
+
+# Select the architecture supported. Default is to build for the current
+# platform. Use "both" for a universal binary. That probably doesn't work
+# when including Perl, Python, etc.
+#CONF_OPT_DARWIN = --with-mac-arch=i386
+#CONF_OPT_DARWIN = --with-mac-arch=ppc
+#CONF_OPT_DARWIN = --with-mac-arch=both
+
+# Uncomment the next line to fail if one of the requested language interfaces
+# cannot be configured. Without this Vim will be build anyway, without
+# the failing interfaces.
+#CONF_OPT_FAIL = --enable-fail-if-missing
+
+# LUA
+# Uncomment one of these when you want to include the Lua interface.
+# First one is for static linking, second one for dynamic loading.
+# Use --with-luajit if you want to use LuaJIT instead of Lua.
+# Set PATH environment variable to find lua or luajit executable.
+# This requires at least "normal" features, "tiny" and "small" don't work.
+#CONF_OPT_LUA = --enable-luainterp
+#CONF_OPT_LUA = --enable-luainterp=dynamic
+#CONF_OPT_LUA = --enable-luainterp --with-luajit
+#CONF_OPT_LUA = --enable-luainterp=dynamic --with-luajit
+# Lua installation dir (when not set uses $LUA_PREFIX or defaults to /usr)
+#CONF_OPT_LUA_PREFIX = --with-lua-prefix=/usr/local
+
+# MZSCHEME
+# Uncomment this when you want to include the MzScheme interface.
+# NOTE: does not work well together with valgrind.
+#CONF_OPT_MZSCHEME = --enable-mzschemeinterp
+# PLT/mrscheme/drscheme Home dir; the PLTHOME environment variable also works
+#CONF_OPT_PLTHOME = --with-plthome=/usr/local/plt
+#CONF_OPT_PLTHOME = --with-plthome=/usr/local/drscheme
+#CONF_OPT_PLTHOME = --with-plthome=/home/me/mz
+
+# PERL
+# Uncomment one of these when you want to include the Perl interface.
+# First one is for static linking, second one for dynamic loading.
+# The Perl option sometimes causes problems, because it adds extra flags
+#
+# to the command line. If you see strange flags during compilation, check in
+# auto/config.mk where they come from. If it's PERL_CFLAGS, try commenting
+# the next line.
+# When you get an error for a missing "perl.exp" file, try creating an empty
+# one: "touch perl.exp".
+# This requires at least "normal" features, "tiny" and "small" don't work.
+#CONF_OPT_PERL = --enable-perlinterp
+#CONF_OPT_PERL = --enable-perlinterp=dynamic
+
+# PYTHON
+# Uncomment lines here when you want to include the Python interface.
+# This requires at least "normal" features, "tiny" and "small" don't work.
+# NOTE: This may cause threading to be enabled, which has side effects (such
+# as using different libraries and debugging becomes more difficult).
+# For Python3 support make a symbolic link in /usr/local/bin:
+# ln -s python3 python3.1
+# If both python2.x and python3.x are enabled then the linking will be via
+# dlopen(), dlsym(), dlclose(), i.e. pythonX.Y.so must be available
+# However, this may still cause problems, such as "import termios" failing.
+# Build two separate versions of Vim in that case.
+#CONF_OPT_PYTHON = --enable-pythoninterp
+#CONF_OPT_PYTHON = --enable-pythoninterp --with-python-command=python2.7
+#CONF_OPT_PYTHON = --enable-pythoninterp=dynamic
+#CONF_OPT_PYTHON3 = --enable-python3interp
+#CONF_OPT_PYTHON3 = --enable-python3interp --with-python3-command=python3.6
+#CONF_OPT_PYTHON3 = --enable-python3interp=dynamic
+
+# RUBY
+# Uncomment this when you want to include the Ruby interface.
+# First one for static linking, second one for loading when used.
+# Note: you need the development package (e.g., ruby1.9.1-dev on Ubuntu).
+# This requires at least "normal" features, "tiny" and "small" don't work.
+#CONF_OPT_RUBY = --enable-rubyinterp
+#CONF_OPT_RUBY = --enable-rubyinterp=dynamic
+#CONF_OPT_RUBY = --enable-rubyinterp --with-ruby-command=ruby1.9.1
+
+# TCL
+# Uncomment this when you want to include the Tcl interface.
+# First one is for static linking, second one for dynamic loading.
+#CONF_OPT_TCL = --enable-tclinterp
+#CONF_OPT_TCL = --enable-tclinterp=dynamic
+#CONF_OPT_TCL = --enable-tclinterp --with-tclsh=tclsh8.4
+
+# CSCOPE
+# Uncomment this when you want to include the Cscope interface.
+#CONF_OPT_CSCOPE = --enable-cscope
+
+# NETBEANS - NetBeans interface. Only works with Motif, GTK, and gnome.
+# Motif version must have XPM libraries (see |netbeans-xpm|).
+# Uncomment this when you do not want the netbeans interface.
+#CONF_OPT_NETBEANS = --disable-netbeans
+
+# CHANNEL - inter process communication. Same conditions as NetBeans.
+# Uncomment this when you do not want inter process communication.
+#CONF_OPT_CHANNEL = --disable-channel
+
+# TERMINAL - Terminal emulator support, :terminal command. Requires the
+# channel feature. The default is enable for when using "huge" features.
+# Uncomment the first line when you want terminal emulator support for
+# not-huge builds. Uncomment the second line when you don't want terminal
+# emulator support in the huge build.
+#CONF_OPT_TERMINAL = --enable-terminal
+#CONF_OPT_TERMINAL = --disable-terminal
+
+# MULTIBYTE - To edit multi-byte characters.
+# This is now always enabled.
+
+# When building with at least "big" features, right-left, Arabic and Farsi
+# features are enabled. Use this to disable them.
+#CONF_OPT_MULTIBYTE = --disable-rightleft --disable-farsi --disable-arabic
+
+# NLS - National Language Support
+# Uncomment this when you do not want to support translated messages, even
+# though configure can find support for it.
+#CONF_OPT_NLS = --disable-nls
+
+# XIM - X Input Method. Special character input support for X11 (Chinese,
+# Japanese, special symbols, etc). Also needed for dead-key support.
+# When omitted it's automatically enabled for the X-windows GUI.
+# HANGUL - Input Hangul (Korean) language using internal routines.
+# Uncomment one of these when you want to input a multibyte language.
+#CONF_OPT_INPUT = --enable-xim
+#CONF_OPT_INPUT = --disable-xim
+#CONF_OPT_INPUT = --enable-hangulinput
+
+# FONTSET - X fontset support for output of languages with many characters.
+# Uncomment this when you want to output a multibyte language.
+#CONF_OPT_OUTPUT = --enable-fontset
+
+# ACL - Uncomment this when you do not want to include ACL support, even
+# though your system does support it. E.g., when it's buggy.
+#CONF_OPT_ACL = --disable-acl
+
+# gpm - For mouse support on Linux console via gpm
+# Uncomment this when you do not want to include gpm support, even
+# though you have gpm libraries and includes.
+#CONF_OPT_GPM = --disable-gpm
+
+# sysmouse - For mouse support on FreeBSD and DragonFly console via sysmouse
+# Uncomment this when you do not want do include sysmouse support, even
+# though you have /dev/sysmouse and includes.
+#CONF_OPT_SYSMOUSE = --disable-sysmouse
+
+# FEATURES - For creating Vim with more or less features
+# Uncomment one of these lines when you want to include few to many features.
+# The default is "huge" for most systems.
+#CONF_OPT_FEAT = --with-features=tiny
+#CONF_OPT_FEAT = --with-features=small
+#CONF_OPT_FEAT = --with-features=normal
+#CONF_OPT_FEAT = --with-features=big
+#CONF_OPT_FEAT = --with-features=huge
+
+# COMPILED BY - For including a specific e-mail address for ":version".
+#CONF_OPT_COMPBY = "--with-compiledby=John Doe <JohnDoe@yahoo.com>"
+
+# X WINDOWS DISABLE - For creating a plain Vim without any X11 related fancies
+# (otherwise Vim configure will try to include xterm titlebar access)
+# Also disable the GUI above, otherwise it will be included anyway.
+# When both GUI and X11 have been disabled this may save about 15% of the
+# code and make Vim startup quicker.
+#CONF_OPT_X = --without-x
+
+# X WINDOWS DIRECTORY - specify X directories
+# If configure can't find you X stuff, or if you have multiple X11 derivatives
+# installed, you may wish to specify which one to use.
+# Select nothing to let configure choose.
+# This here selects openwin (as found on sun).
+#XROOT = /usr/openwin
+#CONF_OPT_X = --x-include=$(XROOT)/include --x-libraries=$(XROOT)/lib
+
+# X11 Session Management Protocol support
+# Vim will try to use XSMP to catch the user logging out if there are unsaved
+# files. Uncomment this line to disable that (it prevents vim trying to open
+# communications with the session manager).
+#CONF_OPT_XSMP = --disable-xsmp
+
+# You may wish to include xsmp but use exclude xsmp-interact if the logout
+# XSMP functionality does not work well with your session-manager (at time of
+# writing, this would be early GNOME-1 gnome-session: it 'freezes' other
+# applications after Vim has cancelled a logout (until Vim quits). This
+# *might* be the Vim code, but is more likely a bug in early GNOME-1.
+# This disables the dialog that asks you if you want to save files or not.
+#CONF_OPT_XSMP = --disable-xsmp-interact
+
+# If you want to always automatically add a servername, also in the terminal.
+#CONF_OPT_AUTOSERVE = --enable-autoservername
+
+# COMPILER - Name of the compiler {{{1
+# The default from configure will mostly be fine, no need to change this, just
+# an example. If a compiler is defined here, configure will use it rather than
+# probing for one. It is dangerous to change this after configure was run.
+# Make will use your choice then -- but beware: Many things may change with
+# another compiler. It is wise to run 'make reconfig' to start all over
+# again.
+#CC = cc
+#CC = gcc
+#CC = clang
+
+# COMPILER FLAGS - change as you please. Either before running {{{1
+# configure or afterwards. For examples see below.
+# When using -g with some older versions of Linux you might get a
+# statically linked executable.
+# When not defined, configure will try to use -O2 -g for gcc and -O for cc.
+#CFLAGS = -g
+#CFLAGS = -O
+
+# Optimization limits - depends on the compiler. Automatic check in configure
+# doesn't work very well, because many compilers only give a warning for
+# unrecognized arguments.
+#CFLAGS = -O -OPT:Olimit=2600
+#CFLAGS = -O -Olimit 2000
+#CFLAGS = -O -FOlimit,2000
+
+# Often used for GCC: mixed optimizing, lot of optimizing, debugging
+#CFLAGS = -g -O2 -fno-strength-reduce -Wall -Wshadow -Wmissing-prototypes
+#CFLAGS = -g -O2 -fno-strength-reduce -Wall -Wmissing-prototypes
+#CFLAGS = -g -Wall -Wmissing-prototypes
+#CFLAGS = -O6 -fno-strength-reduce -Wall -Wshadow -Wmissing-prototypes
+#CFLAGS = -g -DDEBUG -Wall -Wshadow -Wmissing-prototypes
+#CFLAGS = -g -O2 '-DSTARTUPTIME="vimstartup"' -fno-strength-reduce -Wall -Wmissing-prototypes
+
+# Use this with GCC to check for mistakes, unused arguments, etc.
+# Note: If you use -Wextra and get warnings in GTK code about function
+# parameters, you can add -Wno-cast-function-type
+#CFLAGS = -g -Wall -Wextra -Wshadow -Wmissing-prototypes -Wunreachable-code -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1
+# Add -Wpedantic to find // comments and other C99 constructs.
+# Better disable Perl and Python to avoid a lot of warnings.
+#CFLAGS = -g -Wall -Wextra -Wshadow -Wmissing-prototypes -Wpedantic -Wunreachable-code -Wunused-result -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1
+#CFLAGS = -g -O2 -Wall -Wextra -Wshadow -Wmissing-prototypes -Wpedantic -Wunreachable-code -Wunused-result -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1
+#PYTHON_CFLAGS_EXTRA = -Wno-missing-field-initializers
+#MZSCHEME_CFLAGS_EXTRA = -Wno-unreachable-code -Wno-unused-parameter
+
+# EFENCE - Electric-Fence malloc debugging: catches memory accesses beyond
+# allocated memory (and makes every malloc()/free() very slow).
+# Electric Fence is free (search ftp sites).
+# You may want to set the EF_PROTECT_BELOW environment variable to check the
+# other side of allocated memory.
+# On FreeBSD you might need to enlarge the number of mmaps allowed. Do this
+# as root: sysctl -w vm.max_proc_mmap=30000
+#EXTRA_LIBS = /usr/local/lib/libefence.a
+
+# Autoconf binary.
+AUTOCONF = autoconf
+
+# PURIFY - remove the # to use the "purify" program (hoi Nia++!)
+#PURIFY = purify
+
+# VALGRIND - remove the # to use valgrind for memory leaks and access errors.
+# Used for the unittest targets.
+# VALGRIND = valgrind --tool=memcheck --leak-check=yes --num-callers=25 --log-file=valgrind.$@
+
+# NBDEBUG - debugging the netbeans interface.
+#EXTRA_DEFS = -DNBDEBUG
+
+# }}}
+
+# LINT - for running lint
+# For standard Unix lint
+LINT = lint
+LINT_OPTIONS = -beprxzF
+# For splint
+# It doesn't work well, crashes on include files and non-ascii characters.
+#LINT = splint
+#LINT_OPTIONS = +unixlib -weak -macrovarprefixexclude -showfunc -linelen 9999
+
+# PROFILING - Uncomment the next two lines to do profiling with gcc and gprof.
+# Might not work with GUI or Perl.
+# After running Vim see the profile result with: gprof vim gmon.out | vim -
+# Need to recompile everything after changing this: "make clean" "make".
+#PROFILE_CFLAGS = -pg -g -DWE_ARE_PROFILING
+#PROFILE_LIBS = -pg
+
+# GCC 5 and later need the -no-pie argument.
+#PROFILE_LIBS = -pg -no-pie
+
+# For unknown reasons adding "-lc" fixes a linking problem with some versions
+# of GCC. That's probably a bug in the "-pg" implementation.
+#PROFILE_LIBS = -pg -lc
+
+
+# TEST COVERAGE - Uncomment the two lines below the explanation to get code
+# coverage information. (provided by Yegappan Lakshmanan)
+# 1. make clean, run configure and build Vim as usual.
+# 2. Generate the baseline code coverage information:
+# $ lcov -c -i -b . -d objects -o objects/coverage_base.info
+# 3. Run "make test" to run the unit tests. The code coverage information will
+# be generated in the src/objects directory.
+# 4. Generate the code coverage information from the tests:
+# $ lcov -c -b . -d objects/ -o objects/coverage_test.info
+# 5. Combine the baseline and test code coverage data:
+# $ lcov -a objects/coverage_base.info -a objects/coverage_test.info -o objects/coverage_total.info
+# 6. Process the test coverage data and generate a report in html:
+# $ genhtml objects/coverage_total.info -o objects
+# 7. Open the objects/index.html file in a web browser to view the coverage
+# information.
+#
+# PROFILE_CFLAGS=-g -O0 -fprofile-arcs -ftest-coverage
+# LDFLAGS=--coverage
+
+
+# Uncomment one of the next two lines to compile Vim with the
+# address sanitizer or with the undefined sanitizer. Works with gcc and
+# clang. May make Vim twice as slow. Errors reported on stderr.
+# More at: https://code.google.com/p/address-sanitizer/
+#SANITIZER_CFLAGS = -g -O0 -fsanitize=address -fno-omit-frame-pointer
+#SANITIZER_CFLAGS = -g -O0 -fsanitize=undefined -fno-omit-frame-pointer
+SANITIZER_LIBS = $(SANITIZER_CFLAGS)
+
+# MEMORY LEAK DETECTION
+# Requires installing the ccmalloc library.
+# Configuration is in the .ccmalloc or ~/.ccmalloc file.
+# Doesn't work very well, since memory linked to from global variables
+# (in libraries) is also marked as leaked memory.
+#LEAK_CFLAGS = -DEXITFREE
+#LEAK_LIBS = -lccmalloc
+
+# Uncomment this line to have Vim call abort() when an internal error is
+# detected. Useful when using a tool to find errors.
+#ABORT_CLFAGS = -DABORT_ON_INTERNAL_ERROR
+
+#####################################################
+### Specific systems, check if yours is listed! ### {{{
+#####################################################
+
+### Uncomment things here only if the values chosen by configure are wrong.
+### It's better to adjust configure.ac and "make autoconf", if you can!
+### Then send the required changes to configure.ac to the bugs list.
+
+### (1) BSD/OS 2.0.1, 2.1 or 3.0 using shared libraries
+###
+#CC = shlicc2
+#CFLAGS = -O2 -g -m486 -Wall -Wshadow -Wmissing-prototypes -fno-builtin
+
+### (2) HP-UX with a non-ANSI cc, use the c89 ANSI compiler
+### The first probably works on all systems
+### The second should work a bit better on newer systems
+### The third should work a bit better on HPUX 11.11
+### Information provided by: Richard Allen <ra@rhi.hi.is>
+#CC = c89 -D_HPUX_SOURCE
+#CC = c89 -O +Onolimit +ESlit -D_HPUX_SOURCE
+#CC = c89 -O +Onolimit +ESlit +e -D_HPUX_SOURCE
+
+### (2) For HP-UX: Enable the use of a different set of digraphs. Use this
+### when the default (ISO) digraphs look completely wrong.
+### After changing this do "touch digraph.c; make".
+#EXTRA_DEFS = -DHPUX_DIGRAPHS
+
+### (2) For HP-UX: 9.04 cpp default macro definition table of 128000 bytes
+### is too small to compile many routines. It produces too much defining
+### and no space errors.
+### Uncomment the following to specify a larger macro definition table.
+#CFLAGS = -Wp,-H256000
+
+### (2) For HP-UX 10.20 using the HP cc, with X11R6 and Motif 1.2, with
+### libraries in /usr/lib instead of /lib (avoiding transition links).
+### Information provided by: David Green
+#XROOT = /usr
+#CONF_OPT_X = --x-include=$(XROOT)/include/X11R6 --x-libraries=$(XROOT)/lib/X11R6
+#GUI_INC_LOC = -I/usr/include/Motif1.2
+#GUI_LIB_LOC = -L/usr/lib/Motif1.2_R6
+
+### (5) AIX 4.1.4 with cc
+#CFLAGS = -O -qmaxmem=8192
+
+### AIX with c89 (Walter Briscoe)
+#CC = c89
+#CPPFLAGS = -D_ALL_SOURCE
+
+### AIX 4.3.3.12 with xic 3.6.6 (David R. Favor)
+# needed to avoid a problem where strings.h gets included
+#CFLAGS = -qsrcmsg -O2 -qmaxmem=8192 -D__STR31__
+
+### (W) Solaris with multi-threaded libraries (-lthread):
+### If suspending doesn't work properly, try using this line:
+#EXTRA_DEFS = -D_REENTRANT
+
+### (7) Solaris 2.4/2.5 with Centerline compiler
+#CC = clcc
+#X_LIBS_DIR = -L/usr/openwin/lib -R/usr/openwin/lib
+#CFLAGS = -O
+
+### (9) Solaris 2.x with cc (SunPro), using Athena.
+### Only required for compiling gui_at_sb.c.
+### Symptom: "identifier redeclared: vim_XawScrollbarSetThumb"
+### Use one of the lines (either Full ANSI or no ANSI at all)
+#CFLAGS = $(CFLAGS) -Xc
+#CFLAGS = $(CFLAGS) -Xs
+
+### Solaris 2.3 with X11 and specific cc
+#CC=/opt/SUNWspro/bin/cc -O -Xa -v -R/usr/openwin/lib
+
+### Solaris with /usr/ucb/cc (it is rejected by autoconf as "cc")
+#CC = /usr/ucb/cc
+#EXTRA_LIBS = -R/usr/ucblib
+
+### Solaris with Forte Developer and NetBeans.
+# The Xpm library is available from http://koala.ilog.fr/ftp/pub/xpm.
+#CC = cc
+#XPM_DIR = /usr/local/xpm/xpm-3.4k-solaris
+#XPM_LIB = -L$(XPM_DIR)/lib -R$(XPM_DIR)/lib -lXpm
+#XPM_IPATH = -I$(XPM_DIR)/include
+#EXTRA_LIBS = $(XPM_LIB)
+#EXTRA_IPATHS = $(XPM_IPATH)
+#EXTRA_DEFS = -xCC -DHAVE_X11_XPM_H
+
+### (R) for Solaris 2.5 (or 2.5.1) with gcc > 2.5.6 you might need this:
+#LDFLAGS = -lw -ldl -lXmu
+#GUI_LIB_LOC = -L/usr/local/lib
+
+### (8) Unisys 6035 (Glauber Ribeiro)
+#EXTRA_LIBS = -lnsl -lsocket -lgen
+
+### When builtin functions cause problems with gcc (for Sun 4.1.x)
+#CFLAGS = -O2 -Wall -traditional -Wno-implicit
+
+### Apollo DOMAIN (with SYSTYPE = bsd4.3) (TESTED for version 3.0)
+#EXTRA_DEFS = -DDOMAIN
+#CFLAGS= -O -A systype,bsd4.3
+
+### Coherent 4.2.10 on Intel 386 platform
+#EXTRA_DEFS = -Dvoid=int
+#EXTRA_LIBS = -lterm -lsocket
+
+### SCO 3.2, with different library name for terminfo
+#EXTRA_LIBS = -ltinfo
+
+### UTS2 for Amdahl UTS 2.1.x
+#EXTRA_DEFS = -DUTS2
+#EXTRA_LIBS = -lsocket
+
+### UTS4 for Amdahl UTS 4.x
+#EXTRA_DEFS = -DUTS4 -Xa
+
+### USL for Unix Systems Laboratories (SYSV 4.2)
+#EXTRA_DEFS = -DUSL
+
+### (6) A/UX 3.1.1 with gcc (Jim Jagielski)
+#CC= gcc -D_POSIX_SOURCE
+#CFLAGS= -O2
+#EXTRA_LIBS = -lposix -lbsd -ltermcap -lX11
+
+### (A) Some versions of SCO Open Server 5 (Jan Christiaan van Winkel)
+### Also use the CONF_TERM_LIB below!
+#EXTRA_LIBS = -lgen
+
+### (D) QNX (by G.F. Desrochers)
+#CFLAGS = -g -O -mf -4
+
+### (F) QNX (by John Oleynick)
+# 1. If you don't have an X server: Comment out CONF_OPT_GUI and uncomment
+# CONF_OPT_X = --without-x.
+# 2. make config
+# 3. edit auto/config.mk and remove -ldir and -ltermcap from LIBS. It doesn't
+# have -ldir (does config find it somewhere?) and -ltermcap has at
+# least one problem so I use termlib.o instead. The problem with
+# termcap is that it segfaults if you call it with the name of
+# a non-existent terminal type.
+# 4. edit auto/config.h and add #define USE_TMPNAM
+# 5. add termlib.o to OBJ
+# 6. make
+
+### (H) for Data general DG/UX 5.4.2 and 5.4R3.10 (Jonas J. Schlein)
+#EXTRA_LIBS = -lgen
+
+### (I) SINIX-N 5.42 or 5.43 RM400 R4000 (also SINIX-Y and SINIX-Z)
+#EXTRA_LIBS = -lgen -lnsl
+### For SINIX-Y this is needed for the right prototype of gettimeofday()
+#EXTRA_DEFS = -D_XPG_IV
+
+### (I) Reliant-Unix (aka SINIX) 5.44 with standard cc
+# Use both "-F O3" lines for optimization or the "-g" line for debugging
+#EXTRA_LIBS = -lgen -lsocket -lnsl -lSM -lICE
+#CFLAGS = -F O3 -DSINIXN
+#LDFLAGS = -F O3
+#CFLAGS = -g -DSINIXN
+
+### (P) SCO 3.2.42, with different termcap names for some useful keys DJB
+#EXTRA_DEFS = -DSCOKEYS -DNETTERM_MOUSE -DDEC_MOUSE -DXTERM_MOUSE -DHAVE_GETTIMEOFDAY
+#EXTRA_LIBS = -lsocket -ltermcap -lmalloc -lc_s
+
+### (P) SuperUX 6.2 on NEC SX-4 (Lennart Schultz)
+#GUI_INC_LOC = -I/usr/include
+#GUI_LIB_LOC = -L/usr/lib
+#EXTRA_LIBS = -lgen
+
+### (Q) UNIXSVR 4.2MP on NEC UP4800 (Lennart Schultz)
+#GUI_INC_LOC = -I/usr/necccs/include
+#GUI_LIB_LOC = -L/usr/necccs/lib/X11R6
+#XROOT = /usr/necccs
+#CONF_OPT_X = --x-include=$(XROOT)/include --x-libraries=$(XROOT)/lib/X11R6
+#EXTRA_LIBS = -lsocket -lgen
+
+### Irix 4.0 & 5.2 (Silicon Graphics Machines, __sgi will be defined)
+# Not needed for Irix 5.3, Ives Aerts reported
+#EXTRA_LIBS = -lmalloc -lc_s
+# Irix 4.0, when regexp and regcmp cannot be found when linking:
+#EXTRA_LIBS = -lmalloc -lc_s -lPW
+
+### (S) Irix 6.x (MipsPro compiler): Uses different Olimit flag:
+# Note: This newer option style is used with the MipsPro compilers ONLY if
+# you are compiling an "n32" or "64" ABI binary (use either a -n32
+# flag or a -64 flag for CFLAGS). If you explicitly use a -o32 flag,
+# then the CFLAGS option format will be the typical style (i.e.
+# -Olimit 3000).
+#CFLAGS = -OPT:Olimit=3000 -O
+
+### (S) Irix 6.5 with MipsPro C compiler. Try this as a test to see new
+# compiler features! Beware, the optimization is EXTREMELY thorough
+# and takes quite a long time.
+# Note: See the note above. Here, the -mips3 option automatically
+# enables either the "n32" or "64" ABI, depending on what machine you
+# are compiling on (n32 is explicitly enabled here, just to make sure).
+#CFLAGS = -OPT:Olimit=3500 -O -n32 -mips3 -IPA:aggr_cprop=ON -INLINE:dfe=ON:list=ON:must=screen_char,out_char,ui_write,out_flush
+#LDFLAGS= -OPT:Olimit=3500 -O -n32 -mips3 -IPA:aggr_cprop=ON -INLINE:dfe=ON:list=ON:must=screen_char,out_char,ui_write,out_flush
+
+### (K) for SGI Irix machines with 64 bit pointers ("uname -s" says IRIX64)
+### Suggested by Jon Wright <jon@gate.sinica.edu.tw>.
+### Tested on R8000 IRIX6.1 Power Indigo2.
+### Check /etc/compiler.defaults for your compiler settings.
+# either (for 64 bit pointers) uncomment the following line
+#GUI_LIB_LOC = -L/usr/lib64
+# then
+# 1) make config
+# 2) edit auto/config.mk and delete the -lelf entry in the LIBS line
+# 3) make
+#
+# or (for 32bit pointers) uncomment the following line
+#EXTRA_DEFS = -n32
+#GUI_LIB_LOC = -L/usr/lib32
+# then
+# 1) make config
+# 2) edit auto/config.mk, add -n32 to LDFLAGS
+# 3) make
+#
+#Alternatively: use -o32 instead of -n32.
+###
+
+### (C) On SCO Unix v3.2.5 (and probably other versions) the termcap library,
+### which is found by configure, doesn't work correctly. Symptom is the
+### error message "Termcap entry too long". Uncomment the next line.
+### On AIX 4.2.1 (and other versions probably), libtermcap is reported
+### not to display properly.
+### after changing this, you need to do "make reconfig".
+#CONF_TERM_LIB = --with-tlib=curses
+
+### (E) If you want to use termlib library instead of the automatically found
+### one. After changing this, you need to do "make reconfig".
+#CONF_TERM_LIB = --with-tlib=termlib
+
+### (a) ESIX V4.2 (Reinhard Wobst)
+#EXTRA_LIBS = -lnsl -lsocket -lgen -lXIM -lXmu -lXext
+
+### (c) Tandem/NSK (Matthew Woehlke)
+#EXTRA_LIBS = -lfloss
+
+### If you want to use ncurses library instead of the automatically found one
+### after changing this, you need to do "make reconfig".
+#CONF_TERM_LIB = --with-tlib=ncurses
+
+### For GCC on MS-Windows, the ".exe" suffix will be added.
+#EXEEXT = .exe
+#LNKEXT = .exe
+
+### (O) For LynxOS 2.5.0, tested on PC.
+#EXTRA_LIBS = -lXext -lSM -lICE -lbsd
+### For LynxOS 3.0.1, tested on PPC
+#EXTRA_LIBS= -lXext -lSM -lICE -lnetinet -lXmu -liberty -lX11
+### For LynxOS 3.1.0, tested on PC
+#EXTRA_LIBS= -lXext -lSM -lICE -lnetinet -lXmu
+
+
+### (V) For CX/UX 6.2 (on Harris/Concurrent NightHawk 4800, 5800). Remove
+### -Qtarget if only in a 5800 environment. (Kipp E. Howard)
+#CFLAGS = -O -Qtarget=m88110compat
+#EXTRA_LIBS = -lgen
+
+# The value of QUOTESED comes from auto/config.mk.
+# Uncomment the next line to use the default value.
+# QUOTESED = sed -e 's/[\\"]/\\&/g' -e 's/\\"/"/' -e 's/\\";$$/";/'
+
+##################### end of system specific lines ################### }}}
+
+### Names of the programs and targets {{{1
+VIMTARGET = $(VIMNAME)$(EXEEXT)
+EXTARGET = $(EXNAME)$(LNKEXT)
+VIEWTARGET = $(VIEWNAME)$(LNKEXT)
+GVIMNAME = g$(VIMNAME)
+GVIMTARGET = $(GVIMNAME)$(LNKEXT)
+GVIEWNAME = g$(VIEWNAME)
+GVIEWTARGET = $(GVIEWNAME)$(LNKEXT)
+RVIMNAME = r$(VIMNAME)
+RVIMTARGET = $(RVIMNAME)$(LNKEXT)
+RVIEWNAME = r$(VIEWNAME)
+RVIEWTARGET = $(RVIEWNAME)$(LNKEXT)
+RGVIMNAME = r$(GVIMNAME)
+RGVIMTARGET = $(RGVIMNAME)$(LNKEXT)
+RGVIEWNAME = r$(GVIEWNAME)
+RGVIEWTARGET = $(RGVIEWNAME)$(LNKEXT)
+VIMDIFFNAME = $(VIMNAME)diff
+GVIMDIFFNAME = g$(VIMDIFFNAME)
+VIMDIFFTARGET = $(VIMDIFFNAME)$(LNKEXT)
+GVIMDIFFTARGET = $(GVIMDIFFNAME)$(LNKEXT)
+EVIMNAME = e$(VIMNAME)
+EVIMTARGET = $(EVIMNAME)$(LNKEXT)
+EVIEWNAME = e$(VIEWNAME)
+EVIEWTARGET = $(EVIEWNAME)$(LNKEXT)
+
+### Names of the tools that are also made {{{1
+TOOLS = xxd/xxd$(EXEEXT)
+
+### Installation directories. The defaults come from configure. {{{1
+#
+### prefix the top directory for the data (default "/usr/local")
+#
+# Uncomment the next line to install Vim in your home directory.
+#prefix = $(HOME)
+
+### exec_prefix is the top directory for the executable (default $(prefix))
+#
+# Uncomment the next line to install the Vim executable in "/usr/machine/bin"
+#exec_prefix = /usr/machine
+
+### BINDIR dir for the executable (default "$(exec_prefix)/bin")
+### MANDIR dir for the manual pages (default "$(prefix)/man")
+### DATADIR dir for the other files (default "$(prefix)/lib" or
+# "$(prefix)/share")
+# They may be different when using different architectures for the
+# executable and a common directory for the other files.
+#
+# Uncomment the next line to install Vim in "/usr/bin"
+#BINDIR = /usr/bin
+# Uncomment the next line to install Vim manuals in "/usr/share/man/man1"
+#MANDIR = /usr/share/man
+# Uncomment the next line to install Vim help files in "/usr/share/vim"
+#DATADIR = /usr/share
+
+### DESTDIR root of the installation tree. This is prepended to the other
+# directories. This directory must exist.
+#DESTDIR = ~/pkg/vim
+
+### Directory of the man pages
+MAN1DIR = /man1
+
+### Vim version (adjusted by a script)
+VIMMAJOR = 8
+VIMMINOR = 1
+
+### Location of Vim files (should not need to be changed, and {{{1
+### some things might not work when they are changed!)
+VIMDIR = /vim
+VIMRTDIR = /vim$(VIMMAJOR)$(VIMMINOR)
+HELPSUBDIR = /doc
+COLSUBDIR = /colors
+SYNSUBDIR = /syntax
+INDSUBDIR = /indent
+AUTOSUBDIR = /autoload
+PLUGSUBDIR = /plugin
+FTPLUGSUBDIR = /ftplugin
+LANGSUBDIR = /lang
+COMPSUBDIR = /compiler
+KMAPSUBDIR = /keymap
+MACROSUBDIR = /macros
+PACKSUBDIR = /pack
+TOOLSSUBDIR = /tools
+TUTORSUBDIR = /tutor
+SPELLSUBDIR = /spell
+PRINTSUBDIR = /print
+PODIR = po
+
+### VIMLOC common root of the Vim files (all versions)
+### VIMRTLOC common root of the runtime Vim files (this version)
+### VIMRCLOC compiled-in location for global [g]vimrc files (all versions)
+### VIMRUNTIMEDIR compiled-in location for runtime files (optional)
+### HELPSUBLOC location for help files
+### COLSUBLOC location for colorscheme files
+### SYNSUBLOC location for syntax files
+### INDSUBLOC location for indent files
+### AUTOSUBLOC location for standard autoload files
+### PLUGSUBLOC location for standard plugin files
+### FTPLUGSUBLOC location for ftplugin files
+### LANGSUBLOC location for language files
+### COMPSUBLOC location for compiler files
+### KMAPSUBLOC location for keymap files
+### MACROSUBLOC location for macro files
+### PACKSUBLOC location for packages
+### TOOLSSUBLOC location for tools files
+### TUTORSUBLOC location for tutor files
+### SPELLSUBLOC location for spell files
+### PRINTSUBLOC location for PostScript files (prolog, latin1, ..)
+### SCRIPTLOC location for script files (menu.vim, bugreport.vim, ..)
+### You can override these if you want to install them somewhere else.
+### Edit feature.h for compile-time settings.
+VIMLOC = $(DATADIR)$(VIMDIR)
+VIMRTLOC = $(DATADIR)$(VIMDIR)$(VIMRTDIR)
+VIMRCLOC = $(VIMLOC)
+HELPSUBLOC = $(VIMRTLOC)$(HELPSUBDIR)
+COLSUBLOC = $(VIMRTLOC)$(COLSUBDIR)
+SYNSUBLOC = $(VIMRTLOC)$(SYNSUBDIR)
+INDSUBLOC = $(VIMRTLOC)$(INDSUBDIR)
+AUTOSUBLOC = $(VIMRTLOC)$(AUTOSUBDIR)
+PLUGSUBLOC = $(VIMRTLOC)$(PLUGSUBDIR)
+FTPLUGSUBLOC = $(VIMRTLOC)$(FTPLUGSUBDIR)
+LANGSUBLOC = $(VIMRTLOC)$(LANGSUBDIR)
+COMPSUBLOC = $(VIMRTLOC)$(COMPSUBDIR)
+KMAPSUBLOC = $(VIMRTLOC)$(KMAPSUBDIR)
+MACROSUBLOC = $(VIMRTLOC)$(MACROSUBDIR)
+PACKSUBLOC = $(VIMRTLOC)$(PACKSUBDIR)
+TOOLSSUBLOC = $(VIMRTLOC)$(TOOLSSUBDIR)
+TUTORSUBLOC = $(VIMRTLOC)$(TUTORSUBDIR)
+SPELLSUBLOC = $(VIMRTLOC)$(SPELLSUBDIR)
+PRINTSUBLOC = $(VIMRTLOC)$(PRINTSUBDIR)
+SCRIPTLOC = $(VIMRTLOC)
+
+### Only set VIMRUNTIMEDIR when VIMRTLOC is set to a different location and
+### the runtime directory is not below it.
+#VIMRUNTIMEDIR = $(VIMRTLOC)
+
+### Name of the defaults/evim/mswin file target.
+VIM_DEFAULTS_FILE = $(DESTDIR)$(SCRIPTLOC)/defaults.vim
+EVIM_FILE = $(DESTDIR)$(SCRIPTLOC)/evim.vim
+MSWIN_FILE = $(DESTDIR)$(SCRIPTLOC)/mswin.vim
+
+### Name of the menu file target.
+SYS_MENU_FILE = $(DESTDIR)$(SCRIPTLOC)/menu.vim
+SYS_SYNMENU_FILE = $(DESTDIR)$(SCRIPTLOC)/synmenu.vim
+SYS_DELMENU_FILE = $(DESTDIR)$(SCRIPTLOC)/delmenu.vim
+
+### Name of the bugreport file target.
+SYS_BUGR_FILE = $(DESTDIR)$(SCRIPTLOC)/bugreport.vim
+
+### Name of the rgb.txt file target.
+SYS_RGB_FILE = $(DESTDIR)$(SCRIPTLOC)/rgb.txt
+
+### Name of the file type detection file target.
+SYS_FILETYPE_FILE = $(DESTDIR)$(SCRIPTLOC)/filetype.vim
+
+### Name of the file type detection file target.
+SYS_FTOFF_FILE = $(DESTDIR)$(SCRIPTLOC)/ftoff.vim
+
+### Name of the file type detection script file target.
+SYS_SCRIPTS_FILE = $(DESTDIR)$(SCRIPTLOC)/scripts.vim
+
+### Name of the ftplugin-on file target.
+SYS_FTPLUGIN_FILE = $(DESTDIR)$(SCRIPTLOC)/ftplugin.vim
+
+### Name of the ftplugin-off file target.
+SYS_FTPLUGOF_FILE = $(DESTDIR)$(SCRIPTLOC)/ftplugof.vim
+
+### Name of the indent-on file target.
+SYS_INDENT_FILE = $(DESTDIR)$(SCRIPTLOC)/indent.vim
+
+### Name of the indent-off file target.
+SYS_INDOFF_FILE = $(DESTDIR)$(SCRIPTLOC)/indoff.vim
+
+### Name of the option window script file target.
+SYS_OPTWIN_FILE = $(DESTDIR)$(SCRIPTLOC)/optwin.vim
+
+# Program to install the program in the target directory. Could also be "mv".
+INSTALL_PROG = cp
+
+# Program to install the data in the target directory. Cannot be "mv"!
+INSTALL_DATA = cp
+INSTALL_DATA_R = cp -r
+
+### Program to run on installed binary. Use the second one to disable strip.
+#STRIP = strip
+#STRIP = /bin/true
+
+### Permissions for binaries {{{1
+BINMOD = 755
+
+### Permissions for man page
+MANMOD = 644
+
+### Permissions for help files
+HELPMOD = 644
+
+### Permissions for Perl and shell scripts
+SCRIPTMOD = 755
+
+### Permission for Vim script files (menu.vim, bugreport.vim, ..)
+VIMSCRIPTMOD = 644
+
+### Permissions for all directories that are created
+DIRMOD = 755
+
+### Permissions for all other files that are created
+FILEMOD = 644
+
+# Where to copy the man and help files from
+HELPSOURCE = ../runtime/doc
+
+# Where to copy the script files from (menu, bugreport)
+SCRIPTSOURCE = ../runtime
+
+# Where to copy the colorscheme files from
+COLSOURCE = ../runtime/colors
+
+# Where to copy the syntax files from
+SYNSOURCE = ../runtime/syntax
+
+# Where to copy the indent files from
+INDSOURCE = ../runtime/indent
+
+# Where to copy the standard plugin files from
+AUTOSOURCE = ../runtime/autoload
+
+# Where to copy the standard plugin files from
+PLUGSOURCE = ../runtime/plugin
+
+# Where to copy the ftplugin files from
+FTPLUGSOURCE = ../runtime/ftplugin
+
+# Where to copy the macro files from
+MACROSOURCE = ../runtime/macros
+
+# Where to copy the package files from
+PACKSOURCE = ../runtime/pack
+
+# Where to copy the tools files from
+TOOLSSOURCE = ../runtime/tools
+
+# Where to copy the tutor files from
+TUTORSOURCE = ../runtime/tutor
+
+# Where to copy the spell files from
+SPELLSOURCE = ../runtime/spell
+
+# Where to look for language specific files
+LANGSOURCE = ../runtime/lang
+
+# Where to look for compiler files
+COMPSOURCE = ../runtime/compiler
+
+# Where to look for keymap files
+KMAPSOURCE = ../runtime/keymap
+
+# Where to look for print resource files
+PRINTSOURCE = ../runtime/print
+
+# If you are using Linux, you might want to use this to make vim the
+# default vi editor, it will create a link from vi to Vim when doing
+# "make install". An existing file will be overwritten!
+# When not using it, some make programs can't handle an undefined $(LINKIT).
+#LINKIT = ln -f -s $(DEST_BIN)/$(VIMTARGET) $(DESTDIR)/usr/bin/vi
+LINKIT = @echo >/dev/null
+
+###
+### GRAPHICAL USER INTERFACE (GUI). {{{1
+### 'configure --enable-gui' can enable one of these for you if you did set
+### a corresponding CONF_OPT_GUI above and have X11.
+### Override configures choice by uncommenting all the following lines.
+### As they are, the GUI is disabled. Replace "NONE" with "ATHENA" or "MOTIF"
+### for enabling the Athena or Motif GUI.
+#GUI_SRC = $(NONE_SRC)
+#GUI_OBJ = $(NONE_OBJ)
+#GUI_DEFS = $(NONE_DEFS)
+#GUI_IPATH = $(NONE_IPATH)
+#GUI_LIBS_DIR = $(NONE_LIBS_DIR)
+#GUI_LIBS1 = $(NONE_LIBS1)
+#GUI_LIBS2 = $(NONE_LIBS2)
+#GUI_INSTALL = $(NONE_INSTALL)
+#GUI_TARGETS = $(NONE_TARGETS)
+#GUI_MAN_TARGETS= $(NONE_MAN_TARGETS)
+#GUI_TESTTARGET = $(NONE_TESTTARGET)
+#GUI_BUNDLE = $(NONE_BUNDLE)
+
+# Without a GUI install the normal way.
+NONE_INSTALL = install_normal
+
+### GTK GUI
+GTK_SRC = gui.c gui_gtk.c gui_gtk_x11.c gui_gtk_f.c \
+ gui_beval.c $(GRESOURCE_SRC)
+GTK_OBJ = objects/gui.o objects/gui_gtk.o objects/gui_gtk_x11.o \
+ objects/gui_gtk_f.o \
+ objects/gui_beval.o $(GRESOURCE_OBJ)
+GTK_DEFS = -DFEAT_GUI_GTK $(NARROW_PROTO)
+GTK_IPATH = $(GUI_INC_LOC)
+GTK_LIBS_DIR = $(GUI_LIB_LOC)
+GTK_LIBS1 =
+GTK_LIBS2 = $(GTK_LIBNAME)
+GTK_INSTALL = install_normal install_gui_extra
+GTK_TARGETS = installglinks
+GTK_MAN_TARGETS = yes
+GTK_TESTTARGET = gui
+GTK_BUNDLE =
+
+### Motif GUI
+MOTIF_SRC = gui.c gui_motif.c gui_x11.c gui_beval.c \
+ gui_xmdlg.c gui_xmebw.c
+MOTIF_OBJ = objects/gui.o objects/gui_motif.o objects/gui_x11.o \
+ objects/gui_beval.o \
+ objects/gui_xmdlg.o objects/gui_xmebw.o
+MOTIF_DEFS = -DFEAT_GUI_MOTIF $(NARROW_PROTO)
+MOTIF_IPATH = $(GUI_INC_LOC)
+MOTIF_LIBS_DIR = $(GUI_LIB_LOC)
+MOTIF_LIBS1 =
+MOTIF_LIBS2 = $(MOTIF_LIBNAME) -lXt
+MOTIF_INSTALL = install_normal install_gui_extra
+MOTIF_TARGETS = installglinks
+MOTIF_MAN_TARGETS = yes
+MOTIF_TESTTARGET = gui
+MOTIF_BUNDLE =
+
+### Athena GUI
+### Use Xaw3d to make the menus look a little bit nicer
+#XAW_LIB = -lXaw3d
+XAW_LIB = -lXaw
+
+### When using Xaw3d, uncomment/comment the following lines to also get the
+### scrollbars from Xaw3d.
+#ATHENA_SRC = gui.c gui_athena.c gui_x11.c gui_beval.c gui_at_fs.c
+#ATHENA_OBJ = objects/gui.o objects/gui_athena.o objects/gui_x11.o \
+# objects/gui_beval.o objects/gui_at_fs.o
+#ATHENA_DEFS = -DFEAT_GUI_ATHENA $(NARROW_PROTO) \
+# -Dvim_scrollbarWidgetClass=scrollbarWidgetClass \
+# -Dvim_XawScrollbarSetThumb=XawScrollbarSetThumb
+ATHENA_SRC = gui.c gui_athena.c gui_x11.c gui_beval.c \
+ gui_at_sb.c gui_at_fs.c
+ATHENA_OBJ = objects/gui.o objects/gui_athena.o objects/gui_x11.o \
+ objects/gui_beval.o \
+ objects/gui_at_sb.o objects/gui_at_fs.o
+ATHENA_DEFS = -DFEAT_GUI_ATHENA $(NARROW_PROTO)
+
+ATHENA_IPATH = $(GUI_INC_LOC)
+ATHENA_LIBS_DIR = $(GUI_LIB_LOC)
+ATHENA_LIBS1 = $(XAW_LIB)
+ATHENA_LIBS2 = -lXt
+ATHENA_INSTALL = install_normal install_gui_extra
+ATHENA_TARGETS = installglinks
+ATHENA_MAN_TARGETS = yes
+ATHENA_TESTTARGET = gui
+ATHENA_BUNDLE =
+
+### neXtaw GUI
+NEXTAW_LIB = -lneXtaw
+
+NEXTAW_SRC = gui.c gui_athena.c gui_x11.c gui_beval.c gui_at_fs.c
+NEXTAW_OBJ = objects/gui.o objects/gui_athena.o objects/gui_x11.o \
+ objects/gui_beval.o objects/gui_at_fs.o
+NEXTAW_DEFS = -DFEAT_GUI_ATHENA -DFEAT_GUI_NEXTAW $(NARROW_PROTO)
+
+NEXTAW_IPATH = $(GUI_INC_LOC)
+NEXTAW_LIBS_DIR = $(GUI_LIB_LOC)
+NEXTAW_LIBS1 = $(NEXTAW_LIB)
+NEXTAW_LIBS2 = -lXt
+NEXTAW_INSTALL = install_normal install_gui_extra
+NEXTAW_TARGETS = installglinks
+NEXTAW_MAN_TARGETS = yes
+NEXTAW_TESTTARGET = gui
+NEXTAW_BUNDLE =
+
+### (J) Sun OpenWindows 3.2 (SunOS 4.1.x) or earlier that produce these ld
+# errors: ld: Undefined symbol
+# _get_wmShellWidgetClass
+# _get_applicationShellWidgetClass
+# then you need to get patches 100512-02 and 100573-03 from Sun. In the
+# meantime, uncomment the following GUI_X_LIBS definition as a workaround:
+#GUI_X_LIBS = -Bstatic -lXmu -Bdynamic -lXext
+# If you also get cos, sin etc. as undefined symbols, try uncommenting this
+# too:
+#EXTRA_LIBS = /usr/openwin/lib/libXmu.sa -lm
+
+# PHOTON GUI
+PHOTONGUI_SRC = gui.c gui_photon.c
+PHOTONGUI_OBJ = objects/gui.o objects/gui_photon.o
+PHOTONGUI_DEFS = -DFEAT_GUI_PHOTON
+PHOTONGUI_IPATH =
+PHOTONGUI_LIBS_DIR =
+PHOTONGUI_LIBS1 = -lph -lphexlib
+PHOTONGUI_LIBS2 =
+PHOTONGUI_INSTALL = install_normal install_gui_extra
+PHOTONGUI_TARGETS = installglinks
+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)
+
+# All GUI files
+ALL_GUI_SRC = gui.c gui_gtk.c gui_gtk_f.c gui_motif.c gui_xmdlg.c gui_xmebw.c gui_athena.c gui_gtk_x11.c gui_x11.c gui_at_sb.c gui_at_fs.c
+ALL_GUI_PRO = gui.pro gui_gtk.pro gui_motif.pro gui_xmdlg.pro gui_athena.pro gui_gtk_x11.pro gui_x11.pro gui_w32.pro gui_photon.pro
+
+# }}}
+
+TERM_DEPS = \
+ libvterm/include/vterm.h \
+ libvterm/include/vterm_keycodes.h \
+ libvterm/src/rect.h \
+ libvterm/src/utf8.h \
+ libvterm/src/vterm_internal.h
+
+TERM_SRC = libvterm/src/*.c
+
+XDIFF_SRC = \
+ xdiff/xdiffi.c \
+ xdiff/xemit.c \
+ xdiff/xprepare.c \
+ xdiff/xutils.c \
+ xdiff/xhistogram.c \
+ xdiff/xpatience.c \
+
+XDIFF_OBJS = \
+ objects/xdiffi.o \
+ objects/xemit.o \
+ objects/xprepare.o \
+ objects/xutils.o \
+ objects/xhistogram.o \
+ objects/xpatience.o \
+
+XDIFF_INCL = \
+ xdiff/xdiff.h \
+ xdiff/xdiffi.h \
+ xdiff/xemit.h \
+ xdiff/xinclude.h \
+ xdiff/xmacros.h \
+ xdiff/xprepare.h \
+ xdiff/xtypes.h \
+ xdiff/xutils.h \
+
+### Command to create dependencies based on #include "..."
+### prototype headers are ignored due to -DPROTO, system
+### headers #include <...> are ignored if we use the -MM option, as
+### e.g. provided by gcc-cpp.
+### Include FEAT_GUI to get dependency on gui.h
+### Need to change "-I /<path>" to "-isystem /<path>" for GCC 3.x.
+CPP_DEPEND = $(CC) -I$(srcdir) -M$(CPP_MM) \
+ `echo "$(DEPEND_CFLAGS)" $(DEPEND_CFLAGS_FILTER)`
+
+# flags for cproto
+# This is for cproto 3 patchlevel 8 or below
+# __inline, __attribute__ and __extension__ are not recognized by cproto
+# G_IMPLEMENT_INLINES is to avoid functions defined in glib/gutils.h.
+#NO_ATTR = -D__inline= -D__inline__= -DG_IMPLEMENT_INLINES \
+# -D"__attribute__\\(x\\)=" -D"__asm__\\(x\\)=" \
+# -D__extension__= -D__restrict="" \
+# -D__gnuc_va_list=char -D__builtin_va_list=char
+
+#
+# This is for cproto 3 patchlevel 9 or above (currently 4.6, 4.7g)
+# __inline and __attribute__ are now recognized by cproto
+# -D"foo()=" is not supported by all compilers so do not use it
+NO_ATTR=
+#
+# Use this for cproto 3 patchlevel 6 or below (use "cproto -V" to check):
+# PROTO_FLAGS = -f4 -d -E"$(CPP)" $(NO_ATTR)
+#
+# Use this for cproto 3 patchlevel 7 or above (use "cproto -V" to check):
+PROTO_FLAGS = -d -E"$(CPP)" $(NO_ATTR)
+
+
+################################################
+## no changes required below this line ##
+################################################
+
+SHELL = /bin/sh
+
+# We would normally use "mkdir -p" but it doesn't work properly everywhere.
+# Using AC_PROG_MKDIR_P in configure.ac has a problem with the "auto"
+# directory. Always use the install-sh script, it's slower but reliable.
+MKDIR_P = $(SHELL) install-sh -c -d
+
+.SUFFIXES:
+.SUFFIXES: .c .o .pro
+
+VTERM_CFLAGS = -Ilibvterm/include
+
+PRE_DEFS = -Iproto $(DEFS) $(GUI_DEFS) $(GUI_IPATH) $(CPPFLAGS) $(EXTRA_IPATHS)
+POST_DEFS = $(X_CFLAGS) $(MZSCHEME_CFLAGS) $(EXTRA_DEFS)
+
+ALL_CFLAGS = $(PRE_DEFS) $(CFLAGS) $(PROFILE_CFLAGS) $(SANITIZER_CFLAGS) $(LEAK_CFLAGS) $(ABORT_CLFAGS) $(POST_DEFS)
+
+# Exclude $CFLAGS for osdef.sh, for Mac 10.4 some flags don't work together
+# with "-E".
+OSDEF_CFLAGS = $(PRE_DEFS) $(POST_DEFS)
+
+LINT_CFLAGS = -DLINT -I. $(PRE_DEFS) $(POST_DEFS) \
+ $(RUBY_CFLAGS) $(LUA_CFLAGS) $(PERL_CFLAGS) $(PYTHON_CFLAGS) \
+ $(PYTHON3_CFLAGS) $(TCL_CFLAGS) $(VTERM_CFLAGS) \
+ -Dinline= -D__extension__= -Dalloca=alloca
+
+LINT_EXTRA = -DHANGUL_INPUT -D"__attribute__(x)="
+
+DEPEND_CFLAGS = -DPROTO -DDEPEND -DFEAT_GUI $(LINT_CFLAGS)
+
+# Note: MZSCHEME_LIBS must come before LIBS, because LIBS adds -lm which is
+# needed by racket.
+ALL_LIB_DIRS = $(GUI_LIBS_DIR) $(X_LIBS_DIR)
+ALL_LIBS = \
+ $(GUI_LIBS1) \
+ $(GUI_X_LIBS) \
+ $(GUI_LIBS2) \
+ $(X_PRE_LIBS) \
+ $(X_LIBS) \
+ $(X_EXTRA_LIBS) \
+ $(MZSCHEME_LIBS) \
+ $(LIBS) \
+ $(EXTRA_LIBS) \
+ $(LUA_LIBS) \
+ $(PERL_LIBS) \
+ $(PYTHON_LIBS) \
+ $(PYTHON3_LIBS) \
+ $(TCL_LIBS) \
+ $(RUBY_LIBS) \
+ $(PROFILE_LIBS) \
+ $(SANITIZER_LIBS) \
+ $(LEAK_LIBS)
+
+# abbreviations
+DEST_BIN = $(DESTDIR)$(BINDIR)
+DEST_VIM = $(DESTDIR)$(VIMLOC)
+DEST_RT = $(DESTDIR)$(VIMRTLOC)
+DEST_HELP = $(DESTDIR)$(HELPSUBLOC)
+DEST_COL = $(DESTDIR)$(COLSUBLOC)
+DEST_SYN = $(DESTDIR)$(SYNSUBLOC)
+DEST_IND = $(DESTDIR)$(INDSUBLOC)
+DEST_AUTO = $(DESTDIR)$(AUTOSUBLOC)
+DEST_PLUG = $(DESTDIR)$(PLUGSUBLOC)
+DEST_FTP = $(DESTDIR)$(FTPLUGSUBLOC)
+DEST_LANG = $(DESTDIR)$(LANGSUBLOC)
+DEST_COMP = $(DESTDIR)$(COMPSUBLOC)
+DEST_KMAP = $(DESTDIR)$(KMAPSUBLOC)
+DEST_MACRO = $(DESTDIR)$(MACROSUBLOC)
+DEST_PACK = $(DESTDIR)$(PACKSUBLOC)
+DEST_TOOLS = $(DESTDIR)$(TOOLSSUBLOC)
+DEST_TUTOR = $(DESTDIR)$(TUTORSUBLOC)
+DEST_SPELL = $(DESTDIR)$(SPELLSUBLOC)
+DEST_SCRIPT = $(DESTDIR)$(SCRIPTLOC)
+DEST_PRINT = $(DESTDIR)$(PRINTSUBLOC)
+DEST_MAN_TOP = $(DESTDIR)$(MANDIR)
+
+# We assume that the ".../man/xx/man1/" directory is for latin1 manual pages.
+# Some systems use UTF-8, but these should find the ".../man/xx.UTF-8/man1/"
+# directory first.
+# FreeBSD uses ".../man/xx.ISO8859-1/man1" for latin1, use that one too.
+DEST_MAN = $(DEST_MAN_TOP)$(MAN1DIR)
+DEST_MAN_DA = $(DEST_MAN_TOP)/da$(MAN1DIR)
+DEST_MAN_DA_I = $(DEST_MAN_TOP)/da.ISO8859-1$(MAN1DIR)
+DEST_MAN_DA_U = $(DEST_MAN_TOP)/da.UTF-8$(MAN1DIR)
+DEST_MAN_DE = $(DEST_MAN_TOP)/de$(MAN1DIR)
+DEST_MAN_DE_I = $(DEST_MAN_TOP)/de.ISO8859-1$(MAN1DIR)
+DEST_MAN_DE_U = $(DEST_MAN_TOP)/de.UTF-8$(MAN1DIR)
+DEST_MAN_FR = $(DEST_MAN_TOP)/fr$(MAN1DIR)
+DEST_MAN_FR_I = $(DEST_MAN_TOP)/fr.ISO8859-1$(MAN1DIR)
+DEST_MAN_FR_U = $(DEST_MAN_TOP)/fr.UTF-8$(MAN1DIR)
+DEST_MAN_IT = $(DEST_MAN_TOP)/it$(MAN1DIR)
+DEST_MAN_IT_I = $(DEST_MAN_TOP)/it.ISO8859-1$(MAN1DIR)
+DEST_MAN_IT_U = $(DEST_MAN_TOP)/it.UTF-8$(MAN1DIR)
+DEST_MAN_JA_U = $(DEST_MAN_TOP)/ja$(MAN1DIR)
+DEST_MAN_PL = $(DEST_MAN_TOP)/pl$(MAN1DIR)
+DEST_MAN_PL_I = $(DEST_MAN_TOP)/pl.ISO8859-2$(MAN1DIR)
+DEST_MAN_PL_U = $(DEST_MAN_TOP)/pl.UTF-8$(MAN1DIR)
+DEST_MAN_RU = $(DEST_MAN_TOP)/ru.KOI8-R$(MAN1DIR)
+DEST_MAN_RU_U = $(DEST_MAN_TOP)/ru.UTF-8$(MAN1DIR)
+
+# stuff common to all systems
+include Make_all.mak
+
+# get the list of tests
+include testdir/Make_all.mak
+
+# BASIC_SRC: files that are always used
+# GUI_SRC: extra GUI files for current configuration
+# ALL_GUI_SRC: all GUI files for Unix
+#
+# SRC: files used for current configuration
+# ALL_SRC: source files used for make depend and make lint
+
+BASIC_SRC = \
+ arabic.c \
+ autocmd.c \
+ beval.c \
+ blob.c \
+ blowfish.c \
+ buffer.c \
+ charset.c \
+ crypt.c \
+ crypt_zip.c \
+ dict.c \
+ diff.c \
+ digraph.c \
+ edit.c \
+ eval.c \
+ evalfunc.c \
+ ex_cmds.c \
+ ex_cmds2.c \
+ ex_docmd.c \
+ ex_eval.c \
+ ex_getln.c \
+ farsi.c \
+ fileio.c \
+ fold.c \
+ getchar.c \
+ hardcopy.c \
+ hashtab.c \
+ if_cscope.c \
+ if_xcmdsrv.c \
+ indent.c \
+ json.c \
+ list.c \
+ main.c \
+ mark.c \
+ memfile.c \
+ memline.c \
+ menu.c \
+ message.c \
+ misc1.c \
+ misc2.c \
+ move.c \
+ mbyte.c \
+ normal.c \
+ ops.c \
+ option.c \
+ os_unix.c \
+ auto/pathdef.c \
+ popupmnu.c \
+ pty.c \
+ quickfix.c \
+ regexp.c \
+ screen.c \
+ search.c \
+ sha256.c \
+ sign.c \
+ spell.c \
+ spellfile.c \
+ syntax.c \
+ tag.c \
+ term.c \
+ terminal.c \
+ textprop.c \
+ ui.c \
+ undo.c \
+ userfunc.c \
+ version.c \
+ window.c \
+ $(OS_EXTRA_SRC)
+
+SRC = $(BASIC_SRC) \
+ $(GUI_SRC) \
+ $(TERM_SRC) \
+ $(XDIFF_SRC) \
+ $(HANGULIN_SRC) \
+ $(LUA_SRC) \
+ $(MZSCHEME_SRC) \
+ $(PERL_SRC) \
+ $(PYTHON_SRC) $(PYTHON3_SRC) \
+ $(TCL_SRC) \
+ $(RUBY_SRC)
+
+EXTRA_SRC = hangulin.c if_lua.c if_mzsch.c auto/if_perl.c if_perlsfio.c \
+ if_python.c if_python3.c if_tcl.c if_ruby.c \
+ gui_beval.c netbeans.c channel.c \
+ $(GRESOURCE_SRC)
+
+# Unittest files
+JSON_TEST_SRC = json_test.c
+JSON_TEST_TARGET = json_test$(EXEEXT)
+KWORD_TEST_SRC = kword_test.c
+KWORD_TEST_TARGET = kword_test$(EXEEXT)
+MEMFILE_TEST_SRC = memfile_test.c
+MEMFILE_TEST_TARGET = memfile_test$(EXEEXT)
+MESSAGE_TEST_SRC = message_test.c
+MESSAGE_TEST_TARGET = message_test$(EXEEXT)
+
+UNITTEST_SRC = $(JSON_TEST_SRC) $(KWORD_TEST_SRC) $(MEMFILE_TEST_SRC) $(MESSAGE_TEST_SRC)
+UNITTEST_TARGETS = $(JSON_TEST_TARGET) $(KWORD_TEST_TARGET) $(MEMFILE_TEST_TARGET) $(MESSAGE_TEST_TARGET)
+RUN_UNITTESTS = run_json_test run_kword_test run_memfile_test run_message_test
+
+# All sources, also the ones that are not configured
+ALL_SRC = $(BASIC_SRC) $(ALL_GUI_SRC) $(UNITTEST_SRC) \
+ $(EXTRA_SRC) $(TERM_SRC) $(XDIFF_SRC)
+
+# Which files to check with lint. Select one of these three lines. ALL_SRC
+# checks more, but may not work well for checking a GUI that wasn't configured.
+# The perl sources also don't work well with lint.
+LINT_SRC = $(BASIC_SRC) $(GUI_SRC) $(HANGULIN_SRC) \
+ $(PYTHON_SRC) $(PYTHON3_SRC) $(TCL_SRC) \
+ $(NETBEANS_SRC) $(CHANNEL_SRC) $(TERM_SRC)
+#LINT_SRC = $(SRC)
+#LINT_SRC = $(ALL_SRC)
+#LINT_SRC = $(BASIC_SRC)
+
+OBJ_COMMON = \
+ objects/arabic.o \
+ objects/autocmd.o \
+ objects/beval.o \
+ objects/buffer.o \
+ objects/blob.o \
+ objects/blowfish.o \
+ objects/crypt.o \
+ objects/crypt_zip.o \
+ objects/dict.o \
+ objects/diff.o \
+ objects/digraph.o \
+ objects/edit.o \
+ objects/eval.o \
+ objects/evalfunc.o \
+ objects/ex_cmds.o \
+ objects/ex_cmds2.o \
+ objects/ex_docmd.o \
+ objects/ex_eval.o \
+ objects/ex_getln.o \
+ objects/farsi.o \
+ objects/fileio.o \
+ objects/fold.o \
+ objects/getchar.o \
+ objects/hardcopy.o \
+ objects/hashtab.o \
+ $(HANGULIN_OBJ) \
+ objects/if_cscope.o \
+ objects/if_xcmdsrv.o \
+ objects/indent.o \
+ objects/list.o \
+ objects/mark.o \
+ objects/memline.o \
+ objects/menu.o \
+ objects/misc1.o \
+ objects/misc2.o \
+ objects/move.o \
+ objects/mbyte.o \
+ objects/normal.o \
+ objects/ops.o \
+ objects/option.o \
+ objects/os_unix.o \
+ objects/pathdef.o \
+ objects/popupmnu.o \
+ objects/pty.o \
+ objects/quickfix.o \
+ objects/regexp.o \
+ objects/screen.o \
+ objects/search.o \
+ objects/sha256.o \
+ objects/sign.o \
+ objects/spell.o \
+ objects/spellfile.o \
+ objects/syntax.o \
+ objects/tag.o \
+ objects/term.o \
+ objects/terminal.o \
+ objects/textprop.o \
+ objects/ui.o \
+ objects/undo.o \
+ objects/userfunc.o \
+ objects/version.o \
+ objects/window.o \
+ $(GUI_OBJ) \
+ $(TERM_OBJ) \
+ $(LUA_OBJ) \
+ $(MZSCHEME_OBJ) \
+ $(PERL_OBJ) \
+ $(PYTHON_OBJ) \
+ $(PYTHON3_OBJ) \
+ $(TCL_OBJ) \
+ $(RUBY_OBJ) \
+ $(OS_EXTRA_OBJ) \
+ $(NETBEANS_OBJ) \
+ $(CHANNEL_OBJ) \
+ $(XDIFF_OBJS)
+
+# The files included by tests are not in OBJ_COMMON.
+OBJ_MAIN = \
+ objects/charset.o \
+ objects/json.o \
+ objects/main.o \
+ objects/memfile.o \
+ objects/message.o
+
+OBJ = $(OBJ_COMMON) $(OBJ_MAIN)
+
+OBJ_JSON_TEST = \
+ objects/charset.o \
+ objects/memfile.o \
+ objects/message.o \
+ objects/json_test.o
+
+JSON_TEST_OBJ = $(OBJ_COMMON) $(OBJ_JSON_TEST)
+
+OBJ_KWORD_TEST = \
+ objects/json.o \
+ objects/memfile.o \
+ objects/message.o \
+ objects/kword_test.o
+
+KWORD_TEST_OBJ = $(OBJ_COMMON) $(OBJ_KWORD_TEST)
+
+OBJ_MEMFILE_TEST = \
+ objects/charset.o \
+ objects/json.o \
+ objects/message.o \
+ objects/memfile_test.o
+
+MEMFILE_TEST_OBJ = $(OBJ_COMMON) $(OBJ_MEMFILE_TEST)
+
+OBJ_MESSAGE_TEST = \
+ objects/charset.o \
+ objects/json.o \
+ objects/memfile.o \
+ objects/message_test.o
+
+MESSAGE_TEST_OBJ = $(OBJ_COMMON) $(OBJ_MESSAGE_TEST)
+
+ALL_OBJ = $(OBJ_COMMON) \
+ $(OBJ_MAIN) \
+ $(OBJ_JSON_TEST) \
+ $(OBJ_KWORD_TEST) \
+ $(OBJ_MEMFILE_TEST) \
+ $(OBJ_MESSAGE_TEST)
+
+
+PRO_AUTO = \
+ arabic.pro \
+ autocmd.pro \
+ blowfish.pro \
+ buffer.pro \
+ charset.pro \
+ crypt.pro \
+ crypt_zip.pro \
+ dict.pro \
+ diff.pro \
+ digraph.pro \
+ edit.pro \
+ eval.pro \
+ evalfunc.pro \
+ ex_cmds.pro \
+ ex_cmds2.pro \
+ ex_docmd.pro \
+ ex_eval.pro \
+ ex_getln.pro \
+ farsi.pro \
+ fileio.pro \
+ fold.pro \
+ getchar.pro \
+ hardcopy.pro \
+ hashtab.pro \
+ hangulin.pro \
+ if_cscope.pro \
+ if_lua.pro \
+ if_mzsch.pro \
+ if_python.pro \
+ if_python3.pro \
+ if_ruby.pro \
+ if_xcmdsrv.pro \
+ indent.pro \
+ json.pro \
+ list.pro \
+ main.pro \
+ mark.pro \
+ mbyte.pro \
+ memfile.pro \
+ memline.pro \
+ menu.pro \
+ message.pro \
+ misc1.pro \
+ misc2.pro \
+ move.pro \
+ normal.pro \
+ ops.pro \
+ option.pro \
+ os_mac_conv.pro \
+ os_unix.pro \
+ popupmnu.pro \
+ pty.pro \
+ quickfix.pro \
+ regexp.pro \
+ screen.pro \
+ search.pro \
+ sha256.pro \
+ sign.pro \
+ spell.pro \
+ spellfile.pro \
+ syntax.pro \
+ tag.pro \
+ term.pro \
+ terminal.pro \
+ termlib.pro \
+ textprop.pro \
+ ui.pro \
+ undo.pro \
+ userfunc.pro \
+ version.pro \
+ window.pro \
+ beval.pro \
+ gui_beval.pro \
+ netbeans.pro \
+ channel.pro \
+ $(ALL_GUI_PRO) \
+ $(TCL_PRO)
+
+# Resources used for the Mac are in one directory.
+RSRC_DIR = os_mac_rsrc
+
+PRO_MANUAL = os_amiga.pro os_win32.pro \
+ os_mswin.pro winclip.pro os_beos.pro os_vms.pro $(PERL_PRO)
+
+# Default target is making the executable and tools
+all: $(VIMTARGET) $(TOOLS) languages $(GUI_BUNDLE)
+
+tools: $(TOOLS)
+
+# Run configure with all the setting from above.
+#
+# Note: auto/config.h doesn't depend on configure, because running configure
+# doesn't always update auto/config.h. The timestamp isn't changed if the
+# file contents didn't change (to avoid recompiling everything). Including a
+# dependency on auto/config.h would cause running configure each time when
+# auto/config.h isn't updated. The dependency on auto/config.mk should make
+# sure configure is run when it's needed.
+#
+# Remove the config.cache every time, once in a while it causes problems that
+# are very hard to figure out.
+#
+config auto/config.mk: auto/configure config.mk.in config.h.in
+ -rm -f auto/config.cache
+ if test "X$(MAKECMDGOALS)" != "Xclean" \
+ -a "X$(MAKECMDGOALS)" != "Xdistclean" \
+ -a "X$(MAKECMDGOALS)" != "Xautoconf" \
+ -a "X$(MAKECMDGOALS)" != "Xreconfig"; then \
+ GUI_INC_LOC="$(GUI_INC_LOC)" GUI_LIB_LOC="$(GUI_LIB_LOC)" \
+ CC="$(CC)" CPPFLAGS="$(CPPFLAGS)" CFLAGS="$(CFLAGS)" \
+ LDFLAGS="$(LDFLAGS)" $(CONF_SHELL) srcdir="$(srcdir)" \
+ ./configure $(CONF_OPT_GUI) $(CONF_OPT_X) $(CONF_OPT_XSMP) \
+ $(CONF_OPT_AUTOSERVE) $(CONF_OPT_DARWIN) $(CONF_OPT_FAIL) \
+ $(CONF_OPT_PERL) $(CONF_OPT_PYTHON) $(CONF_OPT_PYTHON3) \
+ $(CONF_OPT_TCL) $(CONF_OPT_RUBY) $(CONF_OPT_NLS) \
+ $(CONF_OPT_CSCOPE) $(CONF_OPT_MULTIBYTE) $(CONF_OPT_INPUT) \
+ $(CONF_OPT_OUTPUT) $(CONF_OPT_GPM) \
+ $(CONF_OPT_FEAT) $(CONF_TERM_LIB) \
+ $(CONF_OPT_COMPBY) $(CONF_OPT_ACL) $(CONF_OPT_NETBEANS) \
+ $(CONF_OPT_CHANNEL) $(CONF_OPT_TERMINAL) \
+ $(CONF_ARGS) $(CONF_ARGS1) $(CONF_ARGS2) $(CONF_ARGS3) \
+ $(CONF_ARGS4) $(CONF_ARGS5) $(CONF_ARGS6) \
+ $(CONF_OPT_MZSCHEME) $(CONF_OPT_PLTHOME) \
+ $(CONF_OPT_LUA) $(CONF_OPT_LUA_PREFIX) \
+ $(CONF_OPT_SYSMOUSE); \
+ fi
+
+# Use "make reconfig" to rerun configure without cached values.
+# When config.h changes, most things will be recompiled automatically.
+# Invoke $(MAKE) to run config with the empty auto/config.mk.
+# Invoke $(MAKE) to build all with the filled auto/config.mk.
+reconfig: scratch clean
+ $(MAKE) -f Makefile config
+ $(MAKE) -f Makefile all
+
+# Run autoconf to produce auto/configure.
+# Note:
+# - DO NOT RUN autoconf MANUALLY! It will overwrite ./configure instead of
+# producing auto/configure.
+# - autoconf is not run automatically, because a patch usually changes both
+# configure.ac and auto/configure but can't update the timestamps. People
+# who do not have (the correct version of) autoconf would run into trouble.
+#
+# Two tricks are required to make autoconf put its output in the "auto" dir:
+# - Temporarily move the ./configure script to ./configure.save. Don't
+# overwrite it, it's probably the result of an aborted autoconf.
+# - Use sed to change ./config.log to auto/config.log in the configure script.
+# Autoconf 2.5x (2.59 at least) produces a few more files that we need to take
+# care of:
+# - configure.lineno: has the line numbers replaced with $LINENO. That
+# improves patches a LOT, thus use it instead (until someone says it doesn't
+# work on some system).
+# - autom4te.cache directory is created and not cleaned up. Delete it.
+# - Uses ">config.log" instead of "./config.log".
+autoconf:
+ if test ! -f configure.save; then mv configure configure.save; fi
+ $(AUTOCONF)
+ sed -e 's+>config.log+>auto/config.log+' -e 's+\./config.log+auto/config.log+' configure > auto/configure
+ chmod 755 auto/configure
+ mv -f configure.save configure
+ -rm -rf autom4te.cache
+ -rm -f auto/config.status auto/config.cache
+
+# Run vim script to generate the Ex command lookup table.
+# This only needs to be run when a command name has been added or changed.
+# If this fails because you don't have Vim yet, first build and install Vim
+# without changes.
+cmdidxs: ex_cmds.h
+ vim -u NONE -i NONE -X -S create_cmdidxs.vim
+
+
+# The normal command to compile a .c file to its .o file.
+# Without or with ALL_CFLAGS.
+CCC_NF = $(CC) -c -I$(srcdir)
+CCC = $(CCC_NF) $(ALL_CFLAGS)
+
+
+# Link the target for normal use or debugging.
+# A shell script is used to try linking without unnecessary libraries.
+$(VIMTARGET): auto/config.mk objects $(OBJ) version.c version.h
+ $(CCC) version.c -o objects/version.o
+ @LINK="$(PURIFY) $(SHRPENV) $(CClink) $(ALL_LIB_DIRS) $(LDFLAGS) \
+ -o $(VIMTARGET) $(OBJ) $(ALL_LIBS)" \
+ MAKE="$(MAKE)" LINK_AS_NEEDED=$(LINK_AS_NEEDED) \
+ sh $(srcdir)/link.sh
+
+xxd/xxd$(EXEEXT): xxd/xxd.c
+ cd xxd; CC="$(CC)" CFLAGS="$(CPPFLAGS) $(CFLAGS)" LDFLAGS="$(LDFLAGS)" \
+ $(MAKE) -f Makefile
+
+# Build the language specific files if they were unpacked.
+# Generate the converted .mo files separately, it's no problem if this fails.
+languages:
+ @if test -n "$(MAKEMO)" -a -f $(PODIR)/Makefile; then \
+ cd $(PODIR); \
+ CC="$(CC)" $(MAKE) prefix=$(DESTDIR)$(prefix); \
+ fi
+ -@if test -n "$(MAKEMO)" -a -f $(PODIR)/Makefile; then \
+ cd $(PODIR); \
+ CC="$(CC)" $(MAKE) prefix=$(DESTDIR)$(prefix) converted; \
+ fi
+
+# Update the *.po files for changes in the sources. Only run manually.
+update-po:
+ cd $(PODIR); CC="$(CC)" $(MAKE) prefix=$(DESTDIR)$(prefix) update-po
+
+# Generate function prototypes. This is not needed to compile vim, but if
+# you want to use it, cproto is out there on the net somewhere -- Webb
+#
+# When generating os_amiga.pro and os_win32.pro there will be a
+# few include files that can not be found, that's OK.
+
+proto: $(PRO_AUTO) $(PRO_MANUAL)
+
+# Filter out arguments that cproto doesn't support.
+# Don't pass "-pthread", "-fwrapv" and similar arguments to cproto, it sees
+# them as a list of individual flags.
+# The -E"gcc -E" argument must be separate to avoid problems with shell
+# quoting.
+# Strip -O2, it may cause cproto to write stderr to the file "2".
+CPROTO = cproto $(PROTO_FLAGS) -DPROTO \
+ `echo '$(LINT_CFLAGS)' | sed -e 's/ -[a-z-]\+//g' -e 's/ -O[^ ]\+//g'`
+
+### Would be nice if this would work for "normal" make.
+### Currently it only works for (Free)BSD make.
+#$(PRO_AUTO): $$(*F).c
+# $(CPROTO) -DFEAT_GUI $(*F).c > $@
+
+# Always define FEAT_GUI. This may generate a few warnings if it's also
+# defined in auto/config.h, you can ignore that.
+.c.pro:
+ $(CPROTO) -DFEAT_GUI $< > proto/$@
+ echo "/* vim: set ft=c : */" >> proto/$@
+
+os_amiga.pro: os_amiga.c
+ $(CPROTO) -DAMIGA -UHAVE_CONFIG_H -DBPTR=char* $< > proto/$@
+ echo "/* vim: set ft=c : */" >> proto/$@
+
+os_win32.pro: os_win32.c
+ $(CPROTO) -DWIN32 -UHAVE_CONFIG_H $< > proto/$@
+ echo "/* vim: set ft=c : */" >> proto/$@
+
+os_mswin.pro: os_mswin.c
+ $(CPROTO) -DWIN32 -UHAVE_CONFIG_H $< > proto/$@
+ echo "/* vim: set ft=c : */" >> proto/$@
+
+winclip.pro: winclip.c
+ $(CPROTO) -DWIN32 -UHAVE_CONFIG_H $< > proto/$@
+ echo "/* vim: set ft=c : */" >> proto/$@
+
+os_beos.pro: os_beos.c
+ $(CPROTO) -D__BEOS__ -UHAVE_CONFIG_H $< > proto/$@
+ echo "/* vim: set ft=c : */" >> proto/$@
+
+os_vms.pro: os_vms.c
+# must use os_vms_conf.h for auto/config.h
+ mv auto/config.h auto/config.h.save
+ cp os_vms_conf.h auto/config.h
+ $(CPROTO) -DVMS -UFEAT_GUI_ATHENA -UFEAT_GUI_NEXTAW -UFEAT_GUI_MOTIF -UFEAT_GUI_GTK $< > proto/$@
+ echo "/* vim: set ft=c : */" >> proto/$@
+ rm auto/config.h
+ mv auto/config.h.save auto/config.h
+
+# if_perl.pro is special: Use the generated if_perl.c for input and remove
+# prototypes for local functions.
+if_perl.pro: auto/if_perl.c
+ $(CPROTO) -DFEAT_GUI auto/if_perl.c | sed "/_VI/d" > proto/$@
+
+gui_gtk_gresources.pro: auto/gui_gtk_gresources.c
+ $(CPROTO) -DFEAT_GUI $< > proto/$@
+ echo "/* vim: set ft=c : */" >> proto/$@
+
+notags:
+ -rm -f tags
+
+# Note: tags is made for the currently configured version, can't include both
+# Motif and Athena GUI
+# You can ignore error messages for missing files.
+tags TAGS: notags
+ $(TAGPRG) $(TAGS_FILES)
+
+# Make a highlight file for types. Requires Exuberant ctags and awk
+types: types.vim
+types.vim: $(TAGS_FILES)
+ ctags --c-kinds=gstu -o- $(TAGS_FILES) |\
+ awk 'BEGIN{printf("syntax keyword Type\t")}\
+ {printf("%s ", $$1)}END{print ""}' > $@
+ echo "syn keyword Constant OK FAIL TRUE FALSE MAYBE" >> $@
+
+# TESTING
+#
+# Execute the test scripts and the unittests.
+test check: scripttests unittests test_libvterm
+
+# Execute the test scripts. Run these after compiling Vim, before installing.
+# This doesn't depend on $(VIMTARGET), because that won't work when configure
+# wasn't run yet. Restart make to build it instead.
+#
+# 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".
+#
+scripttests:
+ $(MAKE) -f Makefile $(VIMTARGET)
+ if test -n "$(MAKEMO)" -a -f $(PODIR)/Makefile; then \
+ cd $(PODIR); $(MAKE) -f Makefile check VIM=../$(VIMTARGET); \
+ fi
+ -if test $(VIMTARGET) != vim -a ! -r vim; then \
+ ln -s $(VIMTARGET) vim; \
+ fi
+ cd testdir; $(MAKE) -f Makefile $(GUI_TESTTARGET) VIMPROG=../$(VIMTARGET) $(GUI_TESTARG) SCRIPTSOURCE=../$(SCRIPTSOURCE)
+
+# Run the tests with the GUI. Assumes vim/gvim was already built
+testgui:
+ cd testdir; $(MAKE) -f Makefile $(GUI_TESTTARGET) VIMPROG=../$(VIMTARGET) GUI_FLAG=-g $(GUI_TESTARG) SCRIPTSOURCE=../$(SCRIPTSOURCE)
+
+benchmark:
+ cd testdir; $(MAKE) -f Makefile benchmark VIMPROG=../$(VIMTARGET) SCRIPTSOURCE=../$(SCRIPTSOURCE)
+
+unittesttargets:
+ $(MAKE) -f Makefile $(UNITTEST_TARGETS)
+
+# Swap these lines to run individual tests with gvim instead of vim.
+VIMTESTTARGET = $(VIMTARGET)
+# VIMTESTTARGET = $(GVIMTARGET)
+
+# Execute the unittests one by one.
+unittest unittests: $(RUN_UNITTESTS)
+
+run_json_test: $(JSON_TEST_TARGET)
+ $(VALGRIND) ./$(JSON_TEST_TARGET) || exit 1; echo $* passed;
+
+run_kword_test: $(KWORD_TEST_TARGET)
+ $(VALGRIND) ./$(KWORD_TEST_TARGET) || exit 1; echo $* passed;
+
+run_memfile_test: $(MEMFILE_TEST_TARGET)
+ $(VALGRIND) ./$(MEMFILE_TEST_TARGET) || exit 1; echo $* passed;
+
+run_message_test: $(MESSAGE_TEST_TARGET)
+ $(VALGRIND) ./$(MESSAGE_TEST_TARGET) || exit 1; echo $* passed;
+
+# Run the libvterm tests.
+# This currently doesn't work on Mac, only run on Linux for now.
+test_libvterm:
+ @if test `uname` = "Linux"; then \
+ cd libvterm; $(MAKE) -f Makefile test \
+ CC="$(CC)" CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)"; \
+ fi
+
+# Run individual OLD style test.
+# These do not depend on the executable, compile it when needed.
+test1 \
+ test_eval \
+ test3 test11 test14 test17 \
+ test29 test30 test37 test39 \
+ test42 test44 test48 test49 \
+ test52 test59 \
+ test64 test69 \
+ test70 test72 \
+ test86 test87 test88 \
+ test94 test95 test99 test108:
+ cd testdir; rm -f $@.out; $(MAKE) -f Makefile $@.out VIMPROG=../$(VIMTESTTARGET) $(GUI_TESTARG) SCRIPTSOURCE=../$(SCRIPTSOURCE)
+
+# Run individual NEW style test.
+# These do not depend on the executable, compile it when needed.
+$(NEW_TESTS):
+ cd testdir; $(MAKE) $@ VIMPROG=../$(VIMTESTTARGET) $(GUI_TESTARG) SCRIPTSOURCE=../$(SCRIPTSOURCE)
+
+newtests:
+ cd testdir; rm -f $@.res test.log messages; $(MAKE) -f Makefile newtestssilent VIMPROG=../$(VIMTESTTARGET) $(GUI_TESTARG) SCRIPTSOURCE=../$(SCRIPTSOURCE)
+ @if test -f testdir/test.log; then \
+ cat testdir/test.log; \
+ fi
+ cat testdir/messages
+
+testclean:
+ cd testdir; $(MAKE) -f Makefile clean
+ if test -d $(PODIR); then \
+ cd $(PODIR); $(MAKE) checkclean; \
+ fi
+
+# Unittests
+# It's build just like Vim to satisfy all dependencies.
+$(JSON_TEST_TARGET): auto/config.mk objects $(JSON_TEST_OBJ)
+ $(CCC) version.c -o objects/version.o
+ @LINK="$(PURIFY) $(SHRPENV) $(CClink) $(ALL_LIB_DIRS) $(LDFLAGS) \
+ -o $(JSON_TEST_TARGET) $(JSON_TEST_OBJ) $(ALL_LIBS)" \
+ MAKE="$(MAKE)" LINK_AS_NEEDED=$(LINK_AS_NEEDED) \
+ sh $(srcdir)/link.sh
+
+$(KWORD_TEST_TARGET): auto/config.mk objects $(KWORD_TEST_OBJ)
+ $(CCC) version.c -o objects/version.o
+ @LINK="$(PURIFY) $(SHRPENV) $(CClink) $(ALL_LIB_DIRS) $(LDFLAGS) \
+ -o $(KWORD_TEST_TARGET) $(KWORD_TEST_OBJ) $(ALL_LIBS)" \
+ MAKE="$(MAKE)" LINK_AS_NEEDED=$(LINK_AS_NEEDED) \
+ sh $(srcdir)/link.sh
+
+$(MEMFILE_TEST_TARGET): auto/config.mk objects $(MEMFILE_TEST_OBJ)
+ $(CCC) version.c -o objects/version.o
+ @LINK="$(PURIFY) $(SHRPENV) $(CClink) $(ALL_LIB_DIRS) $(LDFLAGS) \
+ -o $(MEMFILE_TEST_TARGET) $(MEMFILE_TEST_OBJ) $(ALL_LIBS)" \
+ MAKE="$(MAKE)" LINK_AS_NEEDED=$(LINK_AS_NEEDED) \
+ sh $(srcdir)/link.sh
+
+$(MESSAGE_TEST_TARGET): auto/config.mk objects $(MESSAGE_TEST_OBJ)
+ $(CCC) version.c -o objects/version.o
+ @LINK="$(PURIFY) $(SHRPENV) $(CClink) $(ALL_LIB_DIRS) $(LDFLAGS) \
+ -o $(MESSAGE_TEST_TARGET) $(MESSAGE_TEST_OBJ) $(ALL_LIBS)" \
+ MAKE="$(MAKE)" LINK_AS_NEEDED=$(LINK_AS_NEEDED) \
+ sh $(srcdir)/link.sh
+
+# install targets
+
+install: $(GUI_INSTALL)
+
+install_normal: installvim installtools $(INSTALL_LANGS) install-icons
+
+install_gui_extra: installgtutorbin
+
+installvim: installvimbin installtutorbin \
+ installruntime installlinks installmanlinks
+
+#
+# Avoid overwriting an existing executable, somebody might be running it and
+# overwriting it could cause it to crash. Deleting it is OK, it won't be
+# really deleted until all running processes for it have exited. It is
+# renamed first, in case the deleting doesn't work.
+#
+# If you want to keep an older version, rename it before running "make
+# install".
+#
+installvimbin: $(VIMTARGET) $(DESTDIR)$(exec_prefix) $(DEST_BIN)
+ -if test -f $(DEST_BIN)/$(VIMTARGET); then \
+ mv -f $(DEST_BIN)/$(VIMTARGET) $(DEST_BIN)/$(VIMNAME).rm; \
+ rm -f $(DEST_BIN)/$(VIMNAME).rm; \
+ fi
+ $(INSTALL_PROG) $(VIMTARGET) $(DEST_BIN)
+ $(STRIP) $(DEST_BIN)/$(VIMTARGET)
+ chmod $(BINMOD) $(DEST_BIN)/$(VIMTARGET)
+# may create a link to the new executable from /usr/bin/vi
+ -$(LINKIT)
+
+# Long list of arguments for the shell script that installs the manual pages
+# for one language.
+INSTALLMANARGS = $(VIMLOC) $(SCRIPTLOC) $(VIMRCLOC) $(HELPSOURCE) $(MANMOD) \
+ $(VIMNAME) $(VIMDIFFNAME) $(EVIMNAME)
+
+# Install most of the runtime files
+installruntime: installrtbase installmacros installpack installtutor installspell
+
+# install the help files; first adjust the contents for the final location
+installrtbase: $(HELPSOURCE)/vim.1 $(DEST_VIM) $(DEST_RT) \
+ $(DEST_HELP) $(DEST_PRINT) $(DEST_COL) $(DEST_SYN) $(DEST_IND) \
+ $(DEST_FTP) $(DEST_AUTO) $(DEST_AUTO)/dist $(DEST_AUTO)/xml \
+ $(DEST_PLUG) $(DEST_TUTOR) $(DEST_SPELL) $(DEST_COMP)
+ -$(SHELL) ./installman.sh install $(DEST_MAN) "" $(INSTALLMANARGS)
+# Generate the help tags with ":helptags" to handle all languages.
+# Move the distributed tags file aside and restore it, to avoid it being
+# different from the repository.
+ cd $(HELPSOURCE); if test -z "$(CROSS_COMPILING)" -a -f tags; then \
+ mv -f tags tags.dist; fi
+ @echo generating help tags
+ -@cd $(HELPSOURCE); if test -z "$(CROSS_COMPILING)"; then \
+ $(MAKE) VIMEXE=$(DEST_BIN)/$(VIMTARGET) vimtags; fi
+ cd $(HELPSOURCE); \
+ files=`ls *.txt tags`; \
+ files="$$files `ls *.??x tags-?? 2>/dev/null || true`"; \
+ $(INSTALL_DATA) $$files $(DEST_HELP); \
+ cd $(DEST_HELP); \
+ chmod $(HELPMOD) $$files
+ $(INSTALL_DATA) $(HELPSOURCE)/*.pl $(DEST_HELP)
+ chmod $(SCRIPTMOD) $(DEST_HELP)/*.pl
+ cd $(HELPSOURCE); if test -f tags.dist; then mv -f tags.dist tags; fi
+# install the menu files
+ $(INSTALL_DATA) $(SCRIPTSOURCE)/menu.vim $(SYS_MENU_FILE)
+ chmod $(VIMSCRIPTMOD) $(SYS_MENU_FILE)
+ $(INSTALL_DATA) $(SCRIPTSOURCE)/synmenu.vim $(SYS_SYNMENU_FILE)
+ chmod $(VIMSCRIPTMOD) $(SYS_SYNMENU_FILE)
+ $(INSTALL_DATA) $(SCRIPTSOURCE)/delmenu.vim $(SYS_DELMENU_FILE)
+ chmod $(VIMSCRIPTMOD) $(SYS_DELMENU_FILE)
+# install the defaults/evim/mswin file
+ $(INSTALL_DATA) $(SCRIPTSOURCE)/defaults.vim $(VIM_DEFAULTS_FILE)
+ chmod $(VIMSCRIPTMOD) $(VIM_DEFAULTS_FILE)
+ $(INSTALL_DATA) $(SCRIPTSOURCE)/evim.vim $(EVIM_FILE)
+ chmod $(VIMSCRIPTMOD) $(EVIM_FILE)
+ $(INSTALL_DATA) $(SCRIPTSOURCE)/mswin.vim $(MSWIN_FILE)
+ chmod $(VIMSCRIPTMOD) $(MSWIN_FILE)
+# install the rgb.txt file
+ $(INSTALL_DATA) $(SCRIPTSOURCE)/rgb.txt $(SYS_RGB_FILE)
+ chmod $(VIMSCRIPTMOD) $(SYS_RGB_FILE)
+# install the bugreport file
+ $(INSTALL_DATA) $(SCRIPTSOURCE)/bugreport.vim $(SYS_BUGR_FILE)
+ chmod $(VIMSCRIPTMOD) $(SYS_BUGR_FILE)
+# install the example vimrc files
+ $(INSTALL_DATA) $(SCRIPTSOURCE)/vimrc_example.vim $(DEST_SCRIPT)
+ chmod $(VIMSCRIPTMOD) $(DEST_SCRIPT)/vimrc_example.vim
+ $(INSTALL_DATA) $(SCRIPTSOURCE)/gvimrc_example.vim $(DEST_SCRIPT)
+ chmod $(VIMSCRIPTMOD) $(DEST_SCRIPT)/gvimrc_example.vim
+# install the file type detection files
+ $(INSTALL_DATA) $(SCRIPTSOURCE)/filetype.vim $(SYS_FILETYPE_FILE)
+ chmod $(VIMSCRIPTMOD) $(SYS_FILETYPE_FILE)
+ $(INSTALL_DATA) $(SCRIPTSOURCE)/ftoff.vim $(SYS_FTOFF_FILE)
+ chmod $(VIMSCRIPTMOD) $(SYS_FTOFF_FILE)
+ $(INSTALL_DATA) $(SCRIPTSOURCE)/scripts.vim $(SYS_SCRIPTS_FILE)
+ chmod $(VIMSCRIPTMOD) $(SYS_SCRIPTS_FILE)
+ $(INSTALL_DATA) $(SCRIPTSOURCE)/ftplugin.vim $(SYS_FTPLUGIN_FILE)
+ chmod $(VIMSCRIPTMOD) $(SYS_FTPLUGIN_FILE)
+ $(INSTALL_DATA) $(SCRIPTSOURCE)/ftplugof.vim $(SYS_FTPLUGOF_FILE)
+ chmod $(VIMSCRIPTMOD) $(SYS_FTPLUGOF_FILE)
+ $(INSTALL_DATA) $(SCRIPTSOURCE)/indent.vim $(SYS_INDENT_FILE)
+ chmod $(VIMSCRIPTMOD) $(SYS_INDENT_FILE)
+ $(INSTALL_DATA) $(SCRIPTSOURCE)/indoff.vim $(SYS_INDOFF_FILE)
+ chmod $(VIMSCRIPTMOD) $(SYS_INDOFF_FILE)
+ $(INSTALL_DATA) $(SCRIPTSOURCE)/optwin.vim $(SYS_OPTWIN_FILE)
+ chmod $(VIMSCRIPTMOD) $(SYS_OPTWIN_FILE)
+# install the print resource files
+ cd $(PRINTSOURCE); $(INSTALL_DATA) *.ps $(DEST_PRINT)
+ cd $(DEST_PRINT); chmod $(FILEMOD) *.ps
+# install the colorscheme files
+ cd $(COLSOURCE); $(INSTALL_DATA_R) *.vim tools README.txt $(DEST_COL)
+ cd $(DEST_COL); chmod $(DIRMOD) tools
+ cd $(DEST_COL); chmod $(HELPMOD) *.vim README.txt tools/*.vim
+# install the syntax files
+ cd $(SYNSOURCE); $(INSTALL_DATA) *.vim README.txt $(DEST_SYN)
+ cd $(DEST_SYN); chmod $(HELPMOD) *.vim README.txt
+# install the indent files
+ cd $(INDSOURCE); $(INSTALL_DATA) *.vim README.txt $(DEST_IND)
+ cd $(DEST_IND); chmod $(HELPMOD) *.vim README.txt
+# install the standard autoload files
+ cd $(AUTOSOURCE); $(INSTALL_DATA) *.vim README.txt $(DEST_AUTO)
+ cd $(DEST_AUTO); chmod $(HELPMOD) *.vim README.txt
+ cd $(AUTOSOURCE)/dist; $(INSTALL_DATA) *.vim $(DEST_AUTO)/dist
+ cd $(DEST_AUTO)/dist; chmod $(HELPMOD) *.vim
+ cd $(AUTOSOURCE)/xml; $(INSTALL_DATA) *.vim $(DEST_AUTO)/xml
+ cd $(DEST_AUTO)/xml; chmod $(HELPMOD) *.vim
+# install the standard plugin files
+ cd $(PLUGSOURCE); $(INSTALL_DATA) *.vim README.txt $(DEST_PLUG)
+ cd $(DEST_PLUG); chmod $(HELPMOD) *.vim README.txt
+# install the ftplugin files
+ cd $(FTPLUGSOURCE); $(INSTALL_DATA) *.vim README.txt logtalk.dict $(DEST_FTP)
+ cd $(DEST_FTP); chmod $(HELPMOD) *.vim README.txt
+# install the compiler files
+ cd $(COMPSOURCE); $(INSTALL_DATA) *.vim README.txt $(DEST_COMP)
+ cd $(DEST_COMP); chmod $(HELPMOD) *.vim README.txt
+
+installmacros: $(DEST_VIM) $(DEST_RT) $(DEST_MACRO)
+ $(INSTALL_DATA_R) $(MACROSOURCE)/* $(DEST_MACRO)
+ chmod $(DIRMOD) `find $(DEST_MACRO) -type d -print`
+ chmod $(FILEMOD) `find $(DEST_MACRO) -type f -print`
+ chmod $(SCRIPTMOD) $(DEST_MACRO)/less.sh
+# When using CVS some CVS directories might have been copied.
+# Also delete AAPDIR and *.info files.
+ cvs=`find $(DEST_MACRO) \( -name CVS -o -name AAPDIR -o -name "*.info" \) -print`; \
+ if test -n "$$cvs"; then \
+ rm -rf $$cvs; \
+ fi
+
+installpack: $(DEST_VIM) $(DEST_RT) $(DEST_PACK)
+ $(INSTALL_DATA_R) $(PACKSOURCE)/* $(DEST_PACK)
+ chmod $(DIRMOD) `find $(DEST_PACK) -type d -print`
+ chmod $(FILEMOD) `find $(DEST_PACK) -type f -print`
+
+# install the tutor files
+installtutorbin: $(DEST_VIM)
+ $(INSTALL_DATA) vimtutor $(DEST_BIN)/$(VIMNAME)tutor
+ chmod $(SCRIPTMOD) $(DEST_BIN)/$(VIMNAME)tutor
+
+installgtutorbin: $(DEST_VIM)
+ $(INSTALL_DATA) gvimtutor $(DEST_BIN)/$(GVIMNAME)tutor
+ chmod $(SCRIPTMOD) $(DEST_BIN)/$(GVIMNAME)tutor
+
+installtutor: $(DEST_RT) $(DEST_TUTOR)
+ -$(INSTALL_DATA) $(TUTORSOURCE)/README* $(TUTORSOURCE)/tutor* $(DEST_TUTOR)
+ -rm -f $(DEST_TUTOR)/*.info
+ chmod $(HELPMOD) $(DEST_TUTOR)/*
+
+# Install the spell files, if they exist. This assumes at least the English
+# spell file is there.
+installspell: $(DEST_VIM) $(DEST_RT) $(DEST_SPELL)
+ if test -f $(SPELLSOURCE)/en.latin1.spl; then \
+ $(INSTALL_DATA) $(SPELLSOURCE)/*.spl $(SPELLSOURCE)/*.sug $(SPELLSOURCE)/*.vim $(DEST_SPELL); \
+ chmod $(HELPMOD) $(DEST_SPELL)/*.spl $(DEST_SPELL)/*.sug $(DEST_SPELL)/*.vim; \
+ fi
+
+# install helper program xxd
+installtools: $(TOOLS) $(DESTDIR)$(exec_prefix) $(DEST_BIN) \
+ $(TOOLSSOURCE) $(DEST_VIM) $(DEST_RT) $(DEST_TOOLS) \
+ $(INSTALL_TOOL_LANGS)
+ if test -f $(DEST_BIN)/xxd$(EXEEXT); then \
+ mv -f $(DEST_BIN)/xxd$(EXEEXT) $(DEST_BIN)/xxd.rm; \
+ rm -f $(DEST_BIN)/xxd.rm; \
+ fi
+ $(INSTALL_PROG) xxd/xxd$(EXEEXT) $(DEST_BIN)
+ $(STRIP) $(DEST_BIN)/xxd$(EXEEXT)
+ chmod $(BINMOD) $(DEST_BIN)/xxd$(EXEEXT)
+ -$(SHELL) ./installman.sh xxd $(DEST_MAN) "" $(INSTALLMANARGS)
+
+# install the runtime tools
+ $(INSTALL_DATA_R) $(TOOLSSOURCE)/* $(DEST_TOOLS)
+# When using CVS some CVS directories might have been copied.
+ cvs=`find $(DEST_TOOLS) \( -name CVS -o -name AAPDIR \) -print`; \
+ if test -n "$$cvs"; then \
+ rm -rf $$cvs; \
+ fi
+ -chmod $(FILEMOD) $(DEST_TOOLS)/*
+# replace the path in some tools
+ perlpath=`./which.sh perl` && sed -e "s+/usr/bin/perl+$$perlpath+" $(TOOLSSOURCE)/efm_perl.pl >$(DEST_TOOLS)/efm_perl.pl
+ awkpath=`./which.sh nawk` && sed -e "s+/usr/bin/nawk+$$awkpath+" $(TOOLSSOURCE)/mve.awk >$(DEST_TOOLS)/mve.awk; if test -z "$$awkpath"; then \
+ awkpath=`./which.sh gawk` && sed -e "s+/usr/bin/nawk+$$awkpath+" $(TOOLSSOURCE)/mve.awk >$(DEST_TOOLS)/mve.awk; if test -z "$$awkpath"; then \
+ awkpath=`./which.sh awk` && sed -e "s+/usr/bin/nawk+$$awkpath+" $(TOOLSSOURCE)/mve.awk >$(DEST_TOOLS)/mve.awk; fi; fi
+ -chmod $(SCRIPTMOD) `grep -l "^#!" $(DEST_TOOLS)/*`
+
+# install the language specific files for tools, if they were unpacked
+install-tool-languages:
+ -$(SHELL) ./installman.sh xxd $(DEST_MAN_DA) "-da" $(INSTALLMANARGS)
+ -$(SHELL) ./installman.sh xxd $(DEST_MAN_DA_I) "-da" $(INSTALLMANARGS)
+ -$(SHELL) ./installman.sh xxd $(DEST_MAN_DA_U) "-da.UTF-8" $(INSTALLMANARGS)
+ -$(SHELL) ./installman.sh xxd $(DEST_MAN_DE) "-de" $(INSTALLMANARGS)
+ -$(SHELL) ./installman.sh xxd $(DEST_MAN_DE_I) "-de" $(INSTALLMANARGS)
+ -$(SHELL) ./installman.sh xxd $(DEST_MAN_DE_U) "-de.UTF-8" $(INSTALLMANARGS)
+ -$(SHELL) ./installman.sh xxd $(DEST_MAN_FR) "-fr" $(INSTALLMANARGS)
+ -$(SHELL) ./installman.sh xxd $(DEST_MAN_FR_I) "-fr" $(INSTALLMANARGS)
+ -$(SHELL) ./installman.sh xxd $(DEST_MAN_FR_U) "-fr.UTF-8" $(INSTALLMANARGS)
+ -$(SHELL) ./installman.sh xxd $(DEST_MAN_IT) "-it" $(INSTALLMANARGS)
+ -$(SHELL) ./installman.sh xxd $(DEST_MAN_IT_I) "-it" $(INSTALLMANARGS)
+ -$(SHELL) ./installman.sh xxd $(DEST_MAN_IT_U) "-it.UTF-8" $(INSTALLMANARGS)
+ -$(SHELL) ./installman.sh xxd $(DEST_MAN_JA_U) "-ja.UTF-8" $(INSTALLMANARGS)
+ -$(SHELL) ./installman.sh xxd $(DEST_MAN_PL) "-pl" $(INSTALLMANARGS)
+ -$(SHELL) ./installman.sh xxd $(DEST_MAN_PL_I) "-pl" $(INSTALLMANARGS)
+ -$(SHELL) ./installman.sh xxd $(DEST_MAN_PL_U) "-pl.UTF-8" $(INSTALLMANARGS)
+ -$(SHELL) ./installman.sh xxd $(DEST_MAN_RU) "-ru" $(INSTALLMANARGS)
+ -$(SHELL) ./installman.sh xxd $(DEST_MAN_RU_U) "-ru.UTF-8" $(INSTALLMANARGS)
+
+# install the language specific files, if they were unpacked
+install-languages: languages $(DEST_LANG) $(DEST_KMAP)
+ -$(SHELL) ./installman.sh install $(DEST_MAN_DA) "-da" $(INSTALLMANARGS)
+ -$(SHELL) ./installman.sh install $(DEST_MAN_DA_I) "-da" $(INSTALLMANARGS)
+ -$(SHELL) ./installman.sh install $(DEST_MAN_DA_U) "-da.UTF-8" $(INSTALLMANARGS)
+ -$(SHELL) ./installman.sh install $(DEST_MAN_DE) "-de" $(INSTALLMANARGS)
+ -$(SHELL) ./installman.sh install $(DEST_MAN_DE_I) "-de" $(INSTALLMANARGS)
+ -$(SHELL) ./installman.sh install $(DEST_MAN_DE_U) "-de.UTF-8" $(INSTALLMANARGS)
+ -$(SHELL) ./installman.sh install $(DEST_MAN_FR) "-fr" $(INSTALLMANARGS)
+ -$(SHELL) ./installman.sh install $(DEST_MAN_FR_I) "-fr" $(INSTALLMANARGS)
+ -$(SHELL) ./installman.sh install $(DEST_MAN_FR_U) "-fr.UTF-8" $(INSTALLMANARGS)
+ -$(SHELL) ./installman.sh install $(DEST_MAN_IT) "-it" $(INSTALLMANARGS)
+ -$(SHELL) ./installman.sh install $(DEST_MAN_IT_I) "-it" $(INSTALLMANARGS)
+ -$(SHELL) ./installman.sh install $(DEST_MAN_IT_U) "-it.UTF-8" $(INSTALLMANARGS)
+ -$(SHELL) ./installman.sh install $(DEST_MAN_JA_U) "-ja.UTF-8" $(INSTALLMANARGS)
+ -$(SHELL) ./installman.sh install $(DEST_MAN_PL) "-pl" $(INSTALLMANARGS)
+ -$(SHELL) ./installman.sh install $(DEST_MAN_PL_I) "-pl" $(INSTALLMANARGS)
+ -$(SHELL) ./installman.sh install $(DEST_MAN_PL_U) "-pl.UTF-8" $(INSTALLMANARGS)
+ -$(SHELL) ./installman.sh install $(DEST_MAN_RU) "-ru" $(INSTALLMANARGS)
+ -$(SHELL) ./installman.sh install $(DEST_MAN_RU_U) "-ru.UTF-8" $(INSTALLMANARGS)
+ -$(SHELL) ./installml.sh install "$(GUI_MAN_TARGETS)" \
+ $(DEST_MAN_DA) $(INSTALLMLARGS)
+ -$(SHELL) ./installml.sh install "$(GUI_MAN_TARGETS)" \
+ $(DEST_MAN_DA_I) $(INSTALLMLARGS)
+ -$(SHELL) ./installml.sh install "$(GUI_MAN_TARGETS)" \
+ $(DEST_MAN_DA_U) $(INSTALLMLARGS)
+ -$(SHELL) ./installml.sh install "$(GUI_MAN_TARGETS)" \
+ $(DEST_MAN_DE) $(INSTALLMLARGS)
+ -$(SHELL) ./installml.sh install "$(GUI_MAN_TARGETS)" \
+ $(DEST_MAN_DE_I) $(INSTALLMLARGS)
+ -$(SHELL) ./installml.sh install "$(GUI_MAN_TARGETS)" \
+ $(DEST_MAN_DE_U) $(INSTALLMLARGS)
+ -$(SHELL) ./installml.sh install "$(GUI_MAN_TARGETS)" \
+ $(DEST_MAN_FR) $(INSTALLMLARGS)
+ -$(SHELL) ./installml.sh install "$(GUI_MAN_TARGETS)" \
+ $(DEST_MAN_FR_I) $(INSTALLMLARGS)
+ -$(SHELL) ./installml.sh install "$(GUI_MAN_TARGETS)" \
+ $(DEST_MAN_FR_U) $(INSTALLMLARGS)
+ -$(SHELL) ./installml.sh install "$(GUI_MAN_TARGETS)" \
+ $(DEST_MAN_IT) $(INSTALLMLARGS)
+ -$(SHELL) ./installml.sh install "$(GUI_MAN_TARGETS)" \
+ $(DEST_MAN_IT_I) $(INSTALLMLARGS)
+ -$(SHELL) ./installml.sh install "$(GUI_MAN_TARGETS)" \
+ $(DEST_MAN_IT_U) $(INSTALLMLARGS)
+ -$(SHELL) ./installml.sh install "$(GUI_MAN_TARGETS)" \
+ $(DEST_MAN_JA_U) $(INSTALLMLARGS)
+ -$(SHELL) ./installml.sh install "$(GUI_MAN_TARGETS)" \
+ $(DEST_MAN_PL) $(INSTALLMLARGS)
+ -$(SHELL) ./installml.sh install "$(GUI_MAN_TARGETS)" \
+ $(DEST_MAN_PL_I) $(INSTALLMLARGS)
+ -$(SHELL) ./installml.sh install "$(GUI_MAN_TARGETS)" \
+ $(DEST_MAN_PL_U) $(INSTALLMLARGS)
+ -$(SHELL) ./installml.sh install "$(GUI_MAN_TARGETS)" \
+ $(DEST_MAN_RU) $(INSTALLMLARGS)
+ -$(SHELL) ./installml.sh install "$(GUI_MAN_TARGETS)" \
+ $(DEST_MAN_RU_U) $(INSTALLMLARGS)
+ if test -n "$(MAKEMO)" -a -f $(PODIR)/Makefile; then \
+ cd $(PODIR); $(MAKE) prefix=$(DESTDIR)$(prefix) LOCALEDIR=$(DEST_LANG) \
+ INSTALL_DATA=$(INSTALL_DATA) FILEMOD=$(FILEMOD) install; \
+ fi
+ if test -d $(LANGSOURCE); then \
+ $(INSTALL_DATA) $(LANGSOURCE)/README.txt $(LANGSOURCE)/*.vim $(DEST_LANG); \
+ chmod $(FILEMOD) $(DEST_LANG)/README.txt $(DEST_LANG)/*.vim; \
+ fi
+ if test -d $(KMAPSOURCE); then \
+ $(INSTALL_DATA) $(KMAPSOURCE)/README.txt $(KMAPSOURCE)/*.vim $(DEST_KMAP); \
+ chmod $(FILEMOD) $(DEST_KMAP)/README.txt $(DEST_KMAP)/*.vim; \
+ fi
+
+# Install the icons for KDE, if the directory exists and the icon doesn't.
+# Always when $(DESTDIR) is not empty.
+ICON48PATH = $(DESTDIR)$(DATADIR)/icons/hicolor/48x48/apps
+ICON32PATH = $(DESTDIR)$(DATADIR)/icons/locolor/32x32/apps
+ICON16PATH = $(DESTDIR)$(DATADIR)/icons/locolor/16x16/apps
+ICONTHEMEPATH = $(DATADIR)/icons/hicolor
+DESKTOPPATH = $(DESTDIR)$(DATADIR)/applications
+KDEPATH = $(HOME)/.kde/share/icons
+install-icons:
+ if test -n "$(DESTDIR)"; then \
+ $(MKDIR_P) $(ICON48PATH) $(ICON32PATH) \
+ $(ICON16PATH) $(DESKTOPPATH); \
+ fi
+
+ if test -d $(ICON48PATH) -a -w $(ICON48PATH) \
+ -a ! -f $(ICON48PATH)/gvim.png; then \
+ $(INSTALL_DATA) $(SCRIPTSOURCE)/vim48x48.png $(ICON48PATH)/gvim.png; \
+ if test -z "$(DESTDIR)" -a -x "$(GTK_UPDATE_ICON_CACHE)" \
+ -a -w $(ICONTHEMEPATH) \
+ -a -f $(ICONTHEMEPATH)/index.theme; then \
+ $(GTK_UPDATE_ICON_CACHE) -q $(ICONTHEMEPATH); \
+ fi \
+ fi
+ if test -d $(ICON32PATH) -a -w $(ICON32PATH) \
+ -a ! -f $(ICON32PATH)/gvim.png; then \
+ $(INSTALL_DATA) $(SCRIPTSOURCE)/vim32x32.png $(ICON32PATH)/gvim.png; \
+ fi
+ if test -d $(ICON16PATH) -a -w $(ICON16PATH) \
+ -a ! -f $(ICON16PATH)/gvim.png; then \
+ $(INSTALL_DATA) $(SCRIPTSOURCE)/vim16x16.png $(ICON16PATH)/gvim.png; \
+ fi
+ if test -d $(DESKTOPPATH) -a -w $(DESKTOPPATH); then \
+ $(INSTALL_DATA) $(SCRIPTSOURCE)/vim.desktop \
+ $(SCRIPTSOURCE)/gvim.desktop \
+ $(DESKTOPPATH); \
+ if test -z "$(DESTDIR)" -a -x "$(UPDATE_DESKTOP_DATABASE)"; then \
+ $(UPDATE_DESKTOP_DATABASE) -q $(DESKTOPPATH); \
+ fi \
+ fi
+
+$(HELPSOURCE)/vim.1 $(MACROSOURCE) $(TOOLSSOURCE):
+ @echo Runtime files not found.
+ @echo You need to unpack the runtime archive before running "make install".
+ test -f error
+
+$(DESTDIR)$(exec_prefix) $(DEST_BIN) \
+ $(DEST_VIM) $(DEST_RT) $(DEST_HELP) \
+ $(DEST_PRINT) $(DEST_COL) $(DEST_SYN) $(DEST_IND) $(DEST_FTP) \
+ $(DEST_LANG) $(DEST_KMAP) $(DEST_COMP) $(DEST_MACRO) \
+ $(DEST_PACK) $(DEST_TOOLS) $(DEST_TUTOR) $(DEST_SPELL) \
+ $(DEST_AUTO) $(DEST_AUTO)/dist $(DEST_AUTO)/xml $(DEST_PLUG):
+ $(MKDIR_P) $@
+ -chmod $(DIRMOD) $@
+
+# create links from various names to vim. This is only done when the links
+# (or executables with the same name) don't exist yet.
+installlinks: $(GUI_TARGETS) \
+ $(DEST_BIN)/$(EXTARGET) \
+ $(DEST_BIN)/$(VIEWTARGET) \
+ $(DEST_BIN)/$(RVIMTARGET) \
+ $(DEST_BIN)/$(RVIEWTARGET) \
+ $(INSTALLVIMDIFF)
+
+installglinks: $(DEST_BIN)/$(GVIMTARGET) \
+ $(DEST_BIN)/$(GVIEWTARGET) \
+ $(DEST_BIN)/$(RGVIMTARGET) \
+ $(DEST_BIN)/$(RGVIEWTARGET) \
+ $(DEST_BIN)/$(EVIMTARGET) \
+ $(DEST_BIN)/$(EVIEWTARGET) \
+ $(INSTALLGVIMDIFF)
+
+installvimdiff: $(DEST_BIN)/$(VIMDIFFTARGET)
+installgvimdiff: $(DEST_BIN)/$(GVIMDIFFTARGET)
+
+$(DEST_BIN)/$(EXTARGET):
+ cd $(DEST_BIN); ln -s $(VIMTARGET) $(EXTARGET)
+
+$(DEST_BIN)/$(VIEWTARGET):
+ cd $(DEST_BIN); ln -s $(VIMTARGET) $(VIEWTARGET)
+
+$(DEST_BIN)/$(GVIMTARGET):
+ cd $(DEST_BIN); ln -s $(VIMTARGET) $(GVIMTARGET)
+
+$(DEST_BIN)/$(GVIEWTARGET):
+ cd $(DEST_BIN); ln -s $(VIMTARGET) $(GVIEWTARGET)
+
+$(DEST_BIN)/$(RVIMTARGET):
+ cd $(DEST_BIN); ln -s $(VIMTARGET) $(RVIMTARGET)
+
+$(DEST_BIN)/$(RVIEWTARGET):
+ cd $(DEST_BIN); ln -s $(VIMTARGET) $(RVIEWTARGET)
+
+$(DEST_BIN)/$(RGVIMTARGET):
+ cd $(DEST_BIN); ln -s $(VIMTARGET) $(RGVIMTARGET)
+
+$(DEST_BIN)/$(RGVIEWTARGET):
+ cd $(DEST_BIN); ln -s $(VIMTARGET) $(RGVIEWTARGET)
+
+$(DEST_BIN)/$(VIMDIFFTARGET):
+ cd $(DEST_BIN); ln -s $(VIMTARGET) $(VIMDIFFTARGET)
+
+$(DEST_BIN)/$(GVIMDIFFTARGET):
+ cd $(DEST_BIN); ln -s $(VIMTARGET) $(GVIMDIFFTARGET)
+
+$(DEST_BIN)/$(EVIMTARGET):
+ cd $(DEST_BIN); ln -s $(VIMTARGET) $(EVIMTARGET)
+
+$(DEST_BIN)/$(EVIEWTARGET):
+ cd $(DEST_BIN); ln -s $(VIMTARGET) $(EVIEWTARGET)
+
+# Create links for the manual pages with various names to vim. This is only
+# done when the links (or manpages with the same name) don't exist yet.
+
+INSTALLMLARGS = $(VIMNAME) $(VIMDIFFNAME) $(EVIMNAME) \
+ $(EXNAME) $(VIEWNAME) $(RVIMNAME) $(RVIEWNAME) \
+ $(GVIMNAME) $(GVIEWNAME) $(RGVIMNAME) $(RGVIEWNAME) \
+ $(GVIMDIFFNAME) $(EVIEWNAME)
+
+installmanlinks:
+ -$(SHELL) ./installml.sh install "$(GUI_MAN_TARGETS)" \
+ $(DEST_MAN) $(INSTALLMLARGS)
+
+uninstall: uninstall_runtime
+ -rm -f $(DEST_BIN)/$(VIMTARGET)
+ -rm -f $(DEST_BIN)/vimtutor
+ -rm -f $(DEST_BIN)/gvimtutor
+ -rm -f $(DEST_BIN)/$(EXTARGET) $(DEST_BIN)/$(VIEWTARGET)
+ -rm -f $(DEST_BIN)/$(GVIMTARGET) $(DEST_BIN)/$(GVIEWTARGET)
+ -rm -f $(DEST_BIN)/$(RVIMTARGET) $(DEST_BIN)/$(RVIEWTARGET)
+ -rm -f $(DEST_BIN)/$(RGVIMTARGET) $(DEST_BIN)/$(RGVIEWTARGET)
+ -rm -f $(DEST_BIN)/$(VIMDIFFTARGET) $(DEST_BIN)/$(GVIMDIFFTARGET)
+ -rm -f $(DEST_BIN)/$(EVIMTARGET) $(DEST_BIN)/$(EVIEWTARGET)
+ -rm -f $(DEST_BIN)/xxd$(EXEEXT)
+
+# Note: the "rmdir" will fail if any files were added after "make install"
+uninstall_runtime:
+ -$(SHELL) ./installman.sh uninstall $(DEST_MAN) "" $(INSTALLMANARGS)
+ -$(SHELL) ./installman.sh uninstall $(DEST_MAN_DA) "" $(INSTALLMANARGS)
+ -$(SHELL) ./installman.sh uninstall $(DEST_MAN_DA_I) "" $(INSTALLMANARGS)
+ -$(SHELL) ./installman.sh uninstall $(DEST_MAN_DA_U) "" $(INSTALLMANARGS)
+ -$(SHELL) ./installman.sh uninstall $(DEST_MAN_DE) "" $(INSTALLMANARGS)
+ -$(SHELL) ./installman.sh uninstall $(DEST_MAN_DE_I) "" $(INSTALLMANARGS)
+ -$(SHELL) ./installman.sh uninstall $(DEST_MAN_DE_U) "" $(INSTALLMANARGS)
+ -$(SHELL) ./installman.sh uninstall $(DEST_MAN_FR) "" $(INSTALLMANARGS)
+ -$(SHELL) ./installman.sh uninstall $(DEST_MAN_FR_I) "" $(INSTALLMANARGS)
+ -$(SHELL) ./installman.sh uninstall $(DEST_MAN_FR_U) "" $(INSTALLMANARGS)
+ -$(SHELL) ./installman.sh uninstall $(DEST_MAN_IT) "" $(INSTALLMANARGS)
+ -$(SHELL) ./installman.sh uninstall $(DEST_MAN_IT_I) "" $(INSTALLMANARGS)
+ -$(SHELL) ./installman.sh uninstall $(DEST_MAN_IT_U) "" $(INSTALLMANARGS)
+ -$(SHELL) ./installman.sh uninstall $(DEST_MAN_JA_U) "" $(INSTALLMANARGS)
+ -$(SHELL) ./installman.sh uninstall $(DEST_MAN_PL) "" $(INSTALLMANARGS)
+ -$(SHELL) ./installman.sh uninstall $(DEST_MAN_PL_I) "" $(INSTALLMANARGS)
+ -$(SHELL) ./installman.sh uninstall $(DEST_MAN_PL_U) "" $(INSTALLMANARGS)
+ -$(SHELL) ./installman.sh uninstall $(DEST_MAN_RU) "" $(INSTALLMANARGS)
+ -$(SHELL) ./installman.sh uninstall $(DEST_MAN_RU_U) "" $(INSTALLMANARGS)
+ -$(SHELL) ./installml.sh uninstall "$(GUI_MAN_TARGETS)" \
+ $(DEST_MAN) $(INSTALLMLARGS)
+ -$(SHELL) ./installml.sh uninstall "$(GUI_MAN_TARGETS)" \
+ $(DEST_MAN_DA) $(INSTALLMLARGS)
+ -$(SHELL) ./installml.sh uninstall "$(GUI_MAN_TARGETS)" \
+ $(DEST_MAN_DA_I) $(INSTALLMLARGS)
+ -$(SHELL) ./installml.sh uninstall "$(GUI_MAN_TARGETS)" \
+ $(DEST_MAN_DA_U) $(INSTALLMLARGS)
+ -$(SHELL) ./installml.sh uninstall "$(GUI_MAN_TARGETS)" \
+ $(DEST_MAN_DE) $(INSTALLMLARGS)
+ -$(SHELL) ./installml.sh uninstall "$(GUI_MAN_TARGETS)" \
+ $(DEST_MAN_DE_I) $(INSTALLMLARGS)
+ -$(SHELL) ./installml.sh uninstall "$(GUI_MAN_TARGETS)" \
+ $(DEST_MAN_DE_U) $(INSTALLMLARGS)
+ -$(SHELL) ./installml.sh uninstall "$(GUI_MAN_TARGETS)" \
+ $(DEST_MAN_FR) $(INSTALLMLARGS)
+ -$(SHELL) ./installml.sh uninstall "$(GUI_MAN_TARGETS)" \
+ $(DEST_MAN_FR_I) $(INSTALLMLARGS)
+ -$(SHELL) ./installml.sh uninstall "$(GUI_MAN_TARGETS)" \
+ $(DEST_MAN_FR_U) $(INSTALLMLARGS)
+ -$(SHELL) ./installml.sh uninstall "$(GUI_MAN_TARGETS)" \
+ $(DEST_MAN_IT) $(INSTALLMLARGS)
+ -$(SHELL) ./installml.sh uninstall "$(GUI_MAN_TARGETS)" \
+ $(DEST_MAN_IT_I) $(INSTALLMLARGS)
+ -$(SHELL) ./installml.sh uninstall "$(GUI_MAN_TARGETS)" \
+ $(DEST_MAN_IT_U) $(INSTALLMLARGS)
+ -$(SHELL) ./installml.sh uninstall "$(GUI_MAN_TARGETS)" \
+ $(DEST_MAN_JA_U) $(INSTALLMLARGS)
+ -$(SHELL) ./installml.sh uninstall "$(GUI_MAN_TARGETS)" \
+ $(DEST_MAN_PL) $(INSTALLMLARGS)
+ -$(SHELL) ./installml.sh uninstall "$(GUI_MAN_TARGETS)" \
+ $(DEST_MAN_PL_I) $(INSTALLMLARGS)
+ -$(SHELL) ./installml.sh uninstall "$(GUI_MAN_TARGETS)" \
+ $(DEST_MAN_PL_U) $(INSTALLMLARGS)
+ -$(SHELL) ./installml.sh uninstall "$(GUI_MAN_TARGETS)" \
+ $(DEST_MAN_RU) $(INSTALLMLARGS)
+ -$(SHELL) ./installml.sh uninstall "$(GUI_MAN_TARGETS)" \
+ $(DEST_MAN_RU_U) $(INSTALLMLARGS)
+ -rm -f $(DEST_MAN)/xxd.1
+ -rm -f $(DEST_MAN_DA)/xxd.1 $(DEST_MAN_DA_I)/xxd.1 $(DEST_MAN_DA_U)/xxd.1
+ -rm -f $(DEST_MAN_DE)/xxd.1 $(DEST_MAN_DE_I)/xxd.1 $(DEST_MAN_DE_U)/xxd.1
+ -rm -f $(DEST_MAN_FR)/xxd.1 $(DEST_MAN_FR_I)/xxd.1 $(DEST_MAN_FR_U)/xxd.1
+ -rm -f $(DEST_MAN_IT)/xxd.1 $(DEST_MAN_IT_I)/xxd.1 $(DEST_MAN_IT_U)/xxd.1
+ -rm -f $(DEST_MAN_JA_U)/xxd.1
+ -rm -f $(DEST_MAN_PL)/xxd.1 $(DEST_MAN_PL_I)/xxd.1 $(DEST_MAN_PL_U)/xxd.1
+ -rm -f $(DEST_MAN_RU)/xxd.1 $(DEST_MAN_RU_U)/xxd.1
+ -rm -f $(DEST_HELP)/*.txt $(DEST_HELP)/tags $(DEST_HELP)/*.pl
+ -rm -f $(DEST_HELP)/*.??x $(DEST_HELP)/tags-??
+ -rm -f $(SYS_RGB_FILE)
+ -rm -f $(SYS_MENU_FILE) $(SYS_SYNMENU_FILE) $(SYS_DELMENU_FILE)
+ -rm -f $(SYS_BUGR_FILE) $(VIM_DEFAULTS_FILE) $(EVIM_FILE) $(MSWIN_FILE)
+ -rm -f $(DEST_SCRIPT)/gvimrc_example.vim $(DEST_SCRIPT)/vimrc_example.vim
+ -rm -f $(SYS_FILETYPE_FILE) $(SYS_FTOFF_FILE) $(SYS_SCRIPTS_FILE)
+ -rm -f $(SYS_INDOFF_FILE) $(SYS_INDENT_FILE)
+ -rm -f $(SYS_FTPLUGOF_FILE) $(SYS_FTPLUGIN_FILE)
+ -rm -f $(SYS_OPTWIN_FILE)
+ -rm -f $(DEST_COL)/*.vim $(DEST_COL)/README.txt
+ -rm -rf $(DEST_COL)/tools
+ -rm -f $(DEST_SYN)/*.vim $(DEST_SYN)/README.txt
+ -rm -f $(DEST_IND)/*.vim $(DEST_IND)/README.txt
+ -rm -rf $(DEST_MACRO)
+ -rm -rf $(DEST_PACK)
+ -rm -rf $(DEST_TUTOR)
+ -rm -rf $(DEST_SPELL)
+ -rm -rf $(DEST_TOOLS)
+ -rm -rf $(DEST_LANG)
+ -rm -rf $(DEST_KMAP)
+ -rm -rf $(DEST_COMP)
+ -rm -f $(DEST_PRINT)/*.ps
+ -rmdir $(DEST_HELP) $(DEST_PRINT) $(DEST_COL) $(DEST_SYN) $(DEST_IND)
+ -rm -rf $(DEST_FTP)/*.vim $(DEST_FTP)/README.txt $(DEST_FTP)/logtalk.dict
+ -rm -f $(DEST_AUTO)/*.vim $(DEST_AUTO)/README.txt
+ -rm -f $(DEST_AUTO)/dist/*.vim $(DEST_AUTO)/xml/*.vim
+ -rm -f $(DEST_PLUG)/*.vim $(DEST_PLUG)/README.txt
+ -rmdir $(DEST_FTP) $(DEST_AUTO)/dist $(DEST_AUTO)/xml $(DEST_AUTO)
+ -rmdir $(DEST_PLUG) $(DEST_RT)
+# This will fail when other Vim versions are installed, no worries.
+ -rmdir $(DEST_VIM)
+
+# Clean up all the files that have been produced, except configure's.
+# We support common typing mistakes for Juergen! :-)
+clean celan: testclean
+ -rm -f *.o core $(VIMTARGET).core $(VIMTARGET) vim xxd/*.o
+ -rm -rf objects
+ -rm -f $(TOOLS) auto/osdef.h auto/pathdef.c auto/if_perl.c auto/gui_gtk_gresources.c auto/gui_gtk_gresources.h
+ -rm -f conftest* *~ auto/link.sed
+ -rm -f testdir/opt_test.vim
+ -rm -f $(UNITTEST_TARGETS)
+ -rm -f runtime pixmaps
+ -rm -rf $(APPDIR)
+ -rm -rf mzscheme_base.c
+ if test -d $(PODIR); then \
+ cd $(PODIR); $(MAKE) prefix=$(DESTDIR)$(prefix) clean; \
+ fi
+
+# Make a shadow directory for compilation on another system or with different
+# features.
+SHADOWDIR = shadow
+
+shadow: runtime pixmaps
+ $(MKDIR_P) $(SHADOWDIR)
+ cd $(SHADOWDIR); ln -s ../*.[chm] ../*.in ../*.sh ../*.xs ../*.xbm ../gui_gtk_res.xml ../toolcheck ../proto ../libvterm ../vimtutor ../gvimtutor ../install-sh ../Make_all.mak .
+ mkdir $(SHADOWDIR)/auto
+ cd $(SHADOWDIR)/auto; ln -s ../../auto/configure .
+ $(MKDIR_P) $(SHADOWDIR)/po
+ cd $(SHADOWDIR)/po; ln -s ../../po/*.po ../../po/*.mak ../../po/*.vim ../../po/Makefile .
+ cd $(SHADOWDIR); rm -f auto/link.sed
+ cp Makefile configure $(SHADOWDIR)
+ rm -f $(SHADOWDIR)/auto/config.mk $(SHADOWDIR)/config.mk.dist
+ cp config.mk.dist $(SHADOWDIR)/auto/config.mk
+ cp config.mk.dist $(SHADOWDIR)
+ $(MKDIR_P) $(SHADOWDIR)/xxd
+ cd $(SHADOWDIR)/xxd; ln -s ../../xxd/*.[ch] ../../xxd/Make* .
+ $(MKDIR_P) $(SHADOWDIR)/xdiff
+ cd $(SHADOWDIR)/xdiff; ln -s ../../xdiff/*.[ch] .
+ if test -d $(RSRC_DIR); then \
+ cd $(SHADOWDIR); \
+ ln -s ../infplist.xml .; \
+ ln -s ../$(RSRC_DIR) ../os_mac.rsr.hqx ../dehqx.py .; \
+ fi
+ $(MKDIR_P) $(SHADOWDIR)/testdir
+ cd $(SHADOWDIR)/testdir; ln -s ../../testdir/Makefile \
+ ../../testdir/Make_all.mak \
+ ../../testdir/README.txt \
+ ../../testdir/*.in \
+ ../../testdir/*.vim \
+ ../../testdir/*.py \
+ ../../testdir/python* \
+ ../../testdir/pyxfile \
+ ../../testdir/sautest \
+ ../../testdir/samples \
+ ../../testdir/dumps \
+ ../../testdir/test83-tags? \
+ ../../testdir/*.ok .
+
+# Link needed for doing "make install" in a shadow directory.
+runtime:
+ -ln -s ../runtime .
+
+# Link needed for doing "make" using GTK in a shadow directory.
+pixmaps:
+ -ln -s ../pixmaps .
+
+# Update the synmenu.vim file with the latest Syntax menu.
+# This is only needed when runtime/makemenu.vim was changed.
+menu: ./vim ../runtime/makemenu.vim
+ ./vim -u ../runtime/makemenu.vim
+
+# Start configure from scratch
+scrub scratch:
+ -rm -f auto/config.status auto/config.cache config.log auto/config.log
+ -rm -f auto/config.h auto/link.log auto/link.sed auto/config.mk
+ touch auto/config.h
+ cp config.mk.dist auto/config.mk
+
+distclean: clean scratch
+ -rm -f tags
+
+dist: distclean
+ @echo
+ @echo Making the distribution has to be done in the top directory
+
+mdepend:
+ -@rm -f Makefile~
+ cp Makefile Makefile~
+ sed -e '/\#\#\# Dependencies/q' < Makefile > tmp_make
+ @for i in $(ALL_SRC) ; do \
+ echo "$$i" ; \
+ echo `echo "$$i" | sed -e 's/[^ ]*\.c$$/objects\/\1.o/'`": $$i" `\
+ $(CPP) $$i |\
+ grep '^# .*"\./.*\.h"' |\
+ sort -t'"' -u +1 -2 |\
+ sed -e 's/.*"\.\/\(.*\)".*/\1/'\
+ ` >> tmp_make ; \
+ done
+ mv tmp_make Makefile
+
+depend:
+ -@rm -f Makefile~
+ cp Makefile Makefile~
+ sed -e '/\#\#\# Dependencies/q' < Makefile > tmp_make
+ -for i in $(ALL_SRC); do echo $$i; \
+ $(CPP_DEPEND) $$i | \
+ sed -e 's+^\([^ ]*\.o\)+objects/\1+' -e 's+xdiff/\.\./++g' >> tmp_make; done
+ mv tmp_make Makefile
+
+# Run lint. Clean up the *.ln files that are sometimes left behind.
+lint:
+ $(LINT) $(LINT_OPTIONS) $(LINT_CFLAGS) $(LINT_EXTRA) $(LINT_SRC)
+ -rm -f *.ln
+
+# Check dosinst.c with lint.
+lintinstall:
+ $(LINT) $(LINT_OPTIONS) -DWIN32 -DUNIX_LINT dosinst.c
+ -rm -f dosinst.ln
+
+###########################################################################
+
+.c.o:
+ $(CCC) $<
+
+auto/if_perl.c: if_perl.xs
+ $(PERL) -e 'unless ( $$] >= 5.005 ) { for (qw(na defgv errgv)) { print "#define PL_$$_ $$_\n" }}' > $@
+ $(PERL) $(PERL_XSUBPP) -prototypes -typemap \
+ $(PERLLIB)/ExtUtils/typemap if_perl.xs >> $@
+
+auto/osdef.h: auto/config.h osdef.sh osdef1.h.in osdef2.h.in
+ CC="$(CC) $(OSDEF_CFLAGS)" srcdir=$(srcdir) sh $(srcdir)/osdef.sh
+
+auto/pathdef.c: Makefile auto/config.mk
+ -@echo creating $@
+ -@echo '/* pathdef.c */' > $@
+ -@echo '/* This file is automatically created by Makefile' >> $@
+ -@echo ' * DO NOT EDIT! Change Makefile only. */' >> $@
+ -@echo '#include "vim.h"' >> $@
+ -@echo 'char_u *default_vim_dir = (char_u *)"$(VIMRCLOC)";' | $(QUOTESED) >> $@
+ -@echo 'char_u *default_vimruntime_dir = (char_u *)"$(VIMRUNTIMEDIR)";' | $(QUOTESED) >> $@
+ -@echo 'char_u *all_cflags = (char_u *)"$(CC) -c -I$(srcdir) $(ALL_CFLAGS)";' | $(QUOTESED) >> $@
+ -@echo 'char_u *all_lflags = (char_u *)"$(CC) $(ALL_LIB_DIRS) $(LDFLAGS) -o $(VIMTARGET) $(ALL_LIBS) ";' | $(QUOTESED) >> $@
+ -@echo 'char_u *compiled_user = (char_u *)"' | tr -d $(NL) >> $@
+ -@if test -n "$(COMPILEDBY)"; then \
+ echo "$(COMPILEDBY)" | tr -d $(NL) >> $@; \
+ else ((logname) 2>/dev/null || whoami) | tr -d $(NL) >> $@; fi
+ -@echo '";' >> $@
+ -@echo 'char_u *compiled_sys = (char_u *)"' | tr -d $(NL) >> $@
+ -@if test -z "$(COMPILEDBY)"; then hostname | tr -d $(NL) >> $@; fi
+ -@echo '";' >> $@
+ -@sh $(srcdir)/pathdef.sh
+
+GUI_GTK_RES_INPUTS = \
+ ../pixmaps/stock_vim_build_tags.png \
+ ../pixmaps/stock_vim_find_help.png \
+ ../pixmaps/stock_vim_save_all.png \
+ ../pixmaps/stock_vim_session_load.png \
+ ../pixmaps/stock_vim_session_new.png \
+ ../pixmaps/stock_vim_session_save.png \
+ ../pixmaps/stock_vim_shell.png \
+ ../pixmaps/stock_vim_window_maximize.png \
+ ../pixmaps/stock_vim_window_maximize_width.png \
+ ../pixmaps/stock_vim_window_minimize.png \
+ ../pixmaps/stock_vim_window_minimize_width.png \
+ ../pixmaps/stock_vim_window_split.png \
+ ../pixmaps/stock_vim_window_split_vertical.png
+
+auto/gui_gtk_gresources.c: gui_gtk_res.xml $(GUI_GTK_RES_INPUTS)
+ $(GLIB_COMPILE_RESOURCES) --target=$@ --sourcedir=../pixmaps --generate --c-name=gui_gtk --manual-register gui_gtk_res.xml
+auto/gui_gtk_gresources.h: gui_gtk_res.xml $(GUI_GTK_RES_INPUTS)
+ if test -z "$(GLIB_COMPILE_RESOURCES)"; then touch $@; else \
+ $(GLIB_COMPILE_RESOURCES) --target=$@ --sourcedir=../pixmaps --generate --c-name=gui_gtk --manual-register gui_gtk_res.xml; \
+ fi
+
+# All the object files are put in the "objects" directory. Since not all make
+# commands understand putting object files in another directory, it must be
+# specified for each file separately.
+
+objects: objects/.dirstamp
+
+objects/.dirstamp:
+ $(MKDIR_P) objects
+ touch objects/.dirstamp
+
+# All object files depend on the objects directory, so that parallel make
+# works. Can't depend on the directory itself, its timestamp changes all the
+# time.
+$(ALL_OBJ): objects/.dirstamp
+
+objects/arabic.o: arabic.c
+ $(CCC) -o $@ arabic.c
+
+objects/autocmd.o: autocmd.c
+ $(CCC) -o $@ autocmd.c
+
+objects/blob.o: blob.c
+ $(CCC) -o $@ blob.c
+
+objects/blowfish.o: blowfish.c
+ $(CCC) -o $@ blowfish.c
+
+objects/buffer.o: buffer.c
+ $(CCC) -o $@ buffer.c
+
+objects/charset.o: charset.c
+ $(CCC) -o $@ charset.c
+
+objects/crypt.o: crypt.c
+ $(CCC) -o $@ crypt.c
+
+objects/crypt_zip.o: crypt_zip.c
+ $(CCC) -o $@ crypt_zip.c
+
+objects/dict.o: dict.c
+ $(CCC) -o $@ dict.c
+
+objects/diff.o: diff.c $(XDIFF_INCL)
+ $(CCC) -o $@ diff.c
+
+objects/digraph.o: digraph.c
+ $(CCC) -o $@ digraph.c
+
+objects/edit.o: edit.c
+ $(CCC) -o $@ edit.c
+
+objects/eval.o: eval.c
+ $(CCC) -o $@ eval.c
+
+objects/evalfunc.o: evalfunc.c
+ $(CCC) -o $@ evalfunc.c
+
+objects/ex_cmds.o: ex_cmds.c
+ $(CCC) -o $@ ex_cmds.c
+
+objects/ex_cmds2.o: ex_cmds2.c
+ $(CCC) -o $@ ex_cmds2.c
+
+objects/ex_docmd.o: ex_docmd.c
+ $(CCC) -o $@ ex_docmd.c
+
+objects/ex_eval.o: ex_eval.c
+ $(CCC) -o $@ ex_eval.c
+
+objects/ex_getln.o: ex_getln.c
+ $(CCC) -o $@ ex_getln.c
+
+objects/farsi.o: farsi.c
+ $(CCC) -o $@ farsi.c
+
+objects/fileio.o: fileio.c
+ $(CCC) -o $@ fileio.c
+
+objects/fold.o: fold.c
+ $(CCC) -o $@ fold.c
+
+objects/getchar.o: getchar.c
+ $(CCC) -o $@ getchar.c
+
+objects/hardcopy.o: hardcopy.c
+ $(CCC) -o $@ hardcopy.c
+
+objects/hashtab.o: hashtab.c
+ $(CCC) -o $@ hashtab.c
+
+objects/gui.o: gui.c
+ $(CCC) -o $@ gui.c
+
+objects/gui_at_fs.o: gui_at_fs.c
+ $(CCC) -o $@ gui_at_fs.c
+
+objects/gui_at_sb.o: gui_at_sb.c
+ $(CCC) -o $@ gui_at_sb.c
+
+objects/gui_athena.o: gui_athena.c
+ $(CCC) -o $@ gui_athena.c
+
+objects/beval.o: beval.c
+ $(CCC) -o $@ beval.c
+
+objects/gui_beval.o: gui_beval.c
+ $(CCC) -o $@ gui_beval.c
+
+objects/gui_gtk.o: gui_gtk.c
+ $(CCC) -o $@ gui_gtk.c
+
+objects/gui_gtk_f.o: gui_gtk_f.c
+ $(CCC) -o $@ gui_gtk_f.c
+
+objects/gui_gtk_gresources.o: auto/gui_gtk_gresources.c
+ $(CCC_NF) $(PERL_CFLAGS) $(ALL_CFLAGS) -o $@ auto/gui_gtk_gresources.c
+
+objects/gui_gtk_x11.o: gui_gtk_x11.c
+ $(CCC) -o $@ gui_gtk_x11.c
+
+objects/gui_motif.o: gui_motif.c
+ $(CCC) -o $@ gui_motif.c
+
+objects/gui_xmdlg.o: gui_xmdlg.c
+ $(CCC) -o $@ gui_xmdlg.c
+
+objects/gui_xmebw.o: gui_xmebw.c
+ $(CCC) -o $@ gui_xmebw.c
+
+objects/gui_x11.o: gui_x11.c
+ $(CCC) -o $@ gui_x11.c
+
+objects/gui_photon.o: gui_photon.c
+ $(CCC) -o $@ gui_photon.c
+
+objects/gui_mac.o: gui_mac.c
+ $(CCC) -o $@ gui_mac.c
+
+objects/hangulin.o: hangulin.c
+ $(CCC) -o $@ hangulin.c
+
+objects/if_cscope.o: if_cscope.c
+ $(CCC) -o $@ if_cscope.c
+
+objects/if_xcmdsrv.o: if_xcmdsrv.c
+ $(CCC) -o $@ if_xcmdsrv.c
+
+objects/if_lua.o: if_lua.c
+ $(CCC_NF) $(LUA_CFLAGS) $(ALL_CFLAGS) -o $@ if_lua.c
+
+objects/if_mzsch.o: if_mzsch.c $(MZSCHEME_EXTRA)
+ $(CCC) -o $@ $(MZSCHEME_CFLAGS_EXTRA) if_mzsch.c
+
+mzscheme_base.c:
+ $(MZSCHEME_MZC) --c-mods mzscheme_base.c ++lib scheme/base
+
+objects/if_perl.o: auto/if_perl.c
+ $(CCC_NF) $(PERL_CFLAGS) $(ALL_CFLAGS) -o $@ auto/if_perl.c
+
+objects/if_perlsfio.o: if_perlsfio.c
+ $(CCC_NF) $(PERL_CFLAGS) $(ALL_CFLAGS) -o $@ if_perlsfio.c
+
+objects/if_python.o: if_python.c if_py_both.h
+ $(CCC_NF) $(PYTHON_CFLAGS) $(PYTHON_CFLAGS_EXTRA) $(ALL_CFLAGS) -o $@ if_python.c
+
+objects/if_python3.o: if_python3.c if_py_both.h
+ $(CCC_NF) $(PYTHON3_CFLAGS) $(PYTHON3_CFLAGS_EXTRA) $(ALL_CFLAGS) -o $@ if_python3.c
+
+objects/if_ruby.o: if_ruby.c
+ $(CCC_NF) $(RUBY_CFLAGS) $(ALL_CFLAGS) -o $@ if_ruby.c
+
+objects/if_tcl.o: if_tcl.c
+ $(CCC_NF) $(TCL_CFLAGS) $(ALL_CFLAGS) -o $@ if_tcl.c
+
+objects/indent.o: indent.c
+ $(CCC) -o $@ indent.c
+
+objects/json.o: json.c
+ $(CCC) -o $@ json.c
+
+objects/json_test.o: json_test.c
+ $(CCC) -o $@ json_test.c
+
+objects/kword_test.o: kword_test.c
+ $(CCC) -o $@ kword_test.c
+
+objects/list.o: list.c
+ $(CCC) -o $@ list.c
+
+objects/main.o: main.c
+ $(CCC) -o $@ main.c
+
+objects/mark.o: mark.c
+ $(CCC) -o $@ mark.c
+
+objects/memfile.o: memfile.c
+ $(CCC) -o $@ memfile.c
+
+objects/memfile_test.o: memfile_test.c
+ $(CCC) -o $@ memfile_test.c
+
+objects/memline.o: memline.c
+ $(CCC) -o $@ memline.c
+
+objects/menu.o: menu.c
+ $(CCC) -o $@ menu.c
+
+objects/message.o: message.c
+ $(CCC) -o $@ message.c
+
+objects/message_test.o: message_test.c
+ $(CCC) -o $@ message_test.c
+
+objects/misc1.o: misc1.c
+ $(CCC) -o $@ misc1.c
+
+objects/misc2.o: misc2.c
+ $(CCC) -o $@ misc2.c
+
+objects/move.o: move.c
+ $(CCC) -o $@ move.c
+
+objects/mbyte.o: mbyte.c
+ $(CCC) -o $@ mbyte.c
+
+objects/normal.o: normal.c
+ $(CCC) -o $@ normal.c
+
+objects/ops.o: ops.c
+ $(CCC) -o $@ ops.c
+
+objects/option.o: option.c
+ $(CCC_NF) $(LUA_CFLAGS) $(PERL_CFLAGS) $(PYTHON_CFLAGS) $(PYTHON3_CFLAGS) $(RUBY_CFLAGS) $(TCL_CFLAGS) $(ALL_CFLAGS) -o $@ option.c
+
+objects/os_beos.o: os_beos.c
+ $(CCC) -o $@ os_beos.c
+
+objects/os_qnx.o: os_qnx.c
+ $(CCC) -o $@ os_qnx.c
+
+objects/os_macosx.o: os_macosx.m
+ $(CCC) -o $@ os_macosx.m
+
+objects/os_mac_conv.o: os_mac_conv.c
+ $(CCC) -o $@ os_mac_conv.c
+
+objects/os_unix.o: os_unix.c
+ $(CCC) -o $@ os_unix.c
+
+objects/os_mswin.o: os_mswin.c
+ $(CCC) -o $@ os_mswin.c
+
+objects/winclip.o: winclip.c
+ $(CCC) -o $@ winclip.c
+
+objects/pathdef.o: auto/pathdef.c
+ $(CCC) -o $@ auto/pathdef.c
+
+objects/popupmnu.o: popupmnu.c
+ $(CCC) -o $@ popupmnu.c
+
+objects/pty.o: pty.c
+ $(CCC) -o $@ pty.c
+
+objects/quickfix.o: quickfix.c
+ $(CCC) -o $@ quickfix.c
+
+objects/regexp.o: regexp.c regexp_nfa.c
+ $(CCC) -o $@ regexp.c
+
+objects/screen.o: screen.c
+ $(CCC) -o $@ screen.c
+
+objects/search.o: search.c
+ $(CCC) -o $@ search.c
+
+objects/sha256.o: sha256.c
+ $(CCC) -o $@ sha256.c
+
+objects/sign.o: sign.c
+ $(CCC) -o $@ sign.c
+
+objects/spell.o: spell.c
+ $(CCC) -o $@ spell.c
+
+objects/spellfile.o: spellfile.c
+ $(CCC) -o $@ spellfile.c
+
+objects/syntax.o: syntax.c
+ $(CCC) -o $@ syntax.c
+
+objects/tag.o: tag.c
+ $(CCC) -o $@ tag.c
+
+objects/term.o: term.c
+ $(CCC) -o $@ term.c
+
+objects/terminal.o: terminal.c $(TERM_DEPS)
+ $(CCC) -o $@ terminal.c
+
+objects/textprop.o: textprop.c
+ $(CCC) -o $@ textprop.c
+
+objects/ui.o: ui.c
+ $(CCC) -o $@ ui.c
+
+objects/undo.o: undo.c
+ $(CCC) -o $@ undo.c
+
+objects/userfunc.o: userfunc.c
+ $(CCC) -o $@ userfunc.c
+
+objects/window.o: window.c
+ $(CCC) -o $@ window.c
+
+objects/netbeans.o: netbeans.c
+ $(CCC) -o $@ netbeans.c
+
+objects/channel.o: channel.c
+ $(CCC) -o $@ channel.c
+
+Makefile:
+ @echo The name of the makefile MUST be "Makefile" (with capital M)!!!!
+
+CCCTERM = $(CCC_NF) $(VTERM_CFLAGS) $(ALL_CFLAGS) -DINLINE="" \
+ -DVSNPRINTF=vim_vsnprintf \
+ -DIS_COMBINING_FUNCTION=utf_iscomposing_uint \
+ -DWCWIDTH_FUNCTION=utf_uint2cells
+
+objects/encoding.o: libvterm/src/encoding.c $(TERM_DEPS)
+ $(CCCTERM) -o $@ libvterm/src/encoding.c
+
+objects/keyboard.o: libvterm/src/keyboard.c $(TERM_DEPS)
+ $(CCCTERM) -o $@ libvterm/src/keyboard.c
+
+objects/mouse.o: libvterm/src/mouse.c $(TERM_DEPS)
+ $(CCCTERM) -o $@ libvterm/src/mouse.c
+
+objects/parser.o: libvterm/src/parser.c $(TERM_DEPS)
+ $(CCCTERM) -o $@ libvterm/src/parser.c
+
+objects/pen.o: libvterm/src/pen.c $(TERM_DEPS)
+ $(CCCTERM) -o $@ libvterm/src/pen.c
+
+objects/termscreen.o: libvterm/src/termscreen.c $(TERM_DEPS)
+ $(CCCTERM) -o $@ libvterm/src/termscreen.c
+
+objects/state.o: libvterm/src/state.c $(TERM_DEPS)
+ $(CCCTERM) -o $@ libvterm/src/state.c
+
+objects/unicode.o: libvterm/src/unicode.c $(TERM_DEPS)
+ $(CCCTERM) -o $@ libvterm/src/unicode.c
+
+objects/vterm.o: libvterm/src/vterm.c $(TERM_DEPS)
+ $(CCCTERM) -o $@ libvterm/src/vterm.c
+
+CCCDIFF = $(CCC_NF) $(ALL_CFLAGS)
+
+objects/xdiffi.o: xdiff/xdiffi.c $(XDIFF_INCL)
+ $(CCCDIFF) -o $@ xdiff/xdiffi.c
+
+objects/xprepare.o: xdiff/xprepare.c $(XDIFF_INCL)
+ $(CCCDIFF) -o $@ xdiff/xprepare.c
+
+objects/xutils.o: xdiff/xutils.c $(XDIFF_INCL)
+ $(CCCDIFF) -o $@ xdiff/xutils.c
+
+objects/xemit.o: xdiff/xemit.c $(XDIFF_INCL)
+ $(CCCDIFF) -o $@ xdiff/xemit.c
+
+objects/xhistogram.o: xdiff/xhistogram.c $(XDIFF_INCL)
+ $(CCCDIFF) -o $@ xdiff/xhistogram.c
+
+objects/xpatience.o: xdiff/xpatience.c $(XDIFF_INCL)
+ $(CCCDIFF) -o $@ xdiff/xpatience.c
+
+
+###############################################################################
+### MacOS X installation
+###
+### This installs a runnable Vim.app in $(prefix)
+
+REZ = /Developer/Tools/Rez
+RESDIR = $(APPDIR)/Contents/Resources
+VERSION = $(VIMMAJOR).$(VIMMINOR)
+
+### Common flags
+M4FLAGSX = $(M4FLAGS) -DAPP_EXE=$(VIMNAME) -DAPP_NAME=$(VIMNAME) \
+ -DAPP_VER=$(VERSION)
+
+install_macosx: gui_bundle
+# Remove the link to the runtime dir, don't want to copy all of that.
+ -rm $(RESDIR)/vim/runtime
+ $(INSTALL_DATA_R) $(APPDIR) $(DESTDIR)$(prefix)
+# Generate the help tags file now, it won't work with "make installruntime".
+ -@srcdir=`pwd`; cd $(HELPSOURCE); $(MAKE) VIMEXE=$$srcdir/$(VIMTARGET) vimtags
+# Install the runtime files. Recursive!
+ $(MKDIR_P) $(DESTDIR)$(prefix)/$(RESDIR)/vim/runtime
+ srcdir=`pwd`; $(MAKE) -f Makefile installruntime \
+ VIMEXE=$$srcdir/$(VIMTARGET) \
+ prefix=$(DESTDIR)$(prefix)/$(RESDIR)$(VIMDIR) \
+ exec_prefix=$(DESTDIR)$(prefix)/$(APPDIR)/Contents \
+ BINDIR=$(DESTDIR)$(prefix)/$(APPDIR)/Contents/MacOS \
+ VIMLOC=$(DESTDIR)$(prefix)/$(RESDIR)$(VIMDIR) \
+ VIMRTLOC=$(DESTDIR)$(prefix)/$(RESDIR)$(VIMDIR)/runtime
+# Put the link back.
+ ln -s `pwd`/../runtime $(RESDIR)/vim
+# Copy rgb.txt, Mac doesn't always have X11
+ $(INSTALL_DATA) $(SCRIPTSOURCE)/rgb.txt $(DESTDIR)$(prefix)/$(RESDIR)/vim/runtime
+# TODO: Create the vimtutor and/or gvimtutor application.
+
+gui_bundle: $(RESDIR) bundle-dir bundle-executable bundle-info bundle-resource \
+ bundle-language
+
+$(RESDIR):
+ $(MKDIR_P) $@
+
+bundle-dir: $(APPDIR)/Contents $(VIMTARGET)
+# Make a link to the runtime directory, so that we can try out the executable
+# without installing it.
+ $(MKDIR_P) $(RESDIR)/vim
+ -ln -s `pwd`/../runtime $(RESDIR)/vim
+
+bundle-executable: $(VIMTARGET)
+ $(MKDIR_P) $(APPDIR)/Contents/MacOS
+ cp $(VIMTARGET) $(APPDIR)/Contents/MacOS/$(VIMTARGET)
+
+bundle-info: bundle-dir
+ @echo "Creating PkgInfo"
+ @echo -n "APPLVIM!" > $(APPDIR)/Contents/PkgInfo
+ @echo "Creating Info.plist"
+ m4 $(M4FLAGSX) infplist.xml > $(APPDIR)/Contents/Info.plist
+
+bundle-resource: bundle-dir bundle-rsrc
+ cp -f $(RSRC_DIR)/*.icns $(RESDIR)
+
+### Classic resources
+# Resource fork (in the form of a .rsrc file) for Classic Vim (Mac OS 9)
+# This file is also required for OS X Vim.
+bundle-rsrc: os_mac.rsr.hqx
+ @echo "Creating resource fork"
+ python dehqx.py $<
+ rm -f gui_mac.rsrc
+ mv gui_mac.rsrc.rsrcfork $(RESDIR)/$(VIMNAME).rsrc
+
+# po/Make_osx.pl says something about generating a Mac message file
+# for Ukrainian. Would somebody using Mac OS X in Ukrainian
+# *really* be upset that Carbon Vim was not localised in
+# Ukrainian?
+#
+#bundle-language: bundle-dir po/Make_osx.pl
+# cd po && perl Make_osx.pl --outdir ../$(RESDIR) $(MULTILANG)
+bundle-language: bundle-dir
+
+$(APPDIR)/Contents:
+ $(MKDIR_P) $(APPDIR)/Contents/MacOS
+ $(MKDIR_P) $(RESDIR)/English.lproj
+
+
+###############################################################################
+### (automatically generated by 'make depend')
+### Dependencies:
+objects/arabic.o: arabic.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/autocmd.o: autocmd.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/beval.o: beval.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/blob.o: blob.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/blowfish.o: blowfish.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/buffer.o: buffer.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h version.h
+objects/charset.o: charset.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/crypt.o: crypt.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/crypt_zip.o: crypt_zip.c vim.h protodef.h auto/config.h feature.h \
+ os_unix.h auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/dict.o: dict.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/diff.o: diff.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h xdiff/xdiff.h vim.h
+objects/digraph.o: digraph.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/edit.o: edit.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/eval.o: eval.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h version.h
+objects/evalfunc.o: evalfunc.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h version.h
+objects/ex_cmds.o: ex_cmds.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h version.h
+objects/ex_cmds2.o: ex_cmds2.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h version.h
+objects/ex_docmd.o: ex_docmd.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h ex_cmdidxs.h
+objects/ex_eval.o: ex_eval.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/ex_getln.o: ex_getln.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/farsi.o: farsi.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/fileio.o: fileio.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/fold.o: fold.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/getchar.o: getchar.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/hardcopy.o: hardcopy.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h version.h
+objects/hashtab.o: hashtab.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/if_cscope.o: if_cscope.c vim.h protodef.h auto/config.h feature.h \
+ os_unix.h auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h if_cscope.h
+objects/if_xcmdsrv.o: if_xcmdsrv.c vim.h protodef.h auto/config.h feature.h \
+ os_unix.h auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h version.h
+objects/indent.o: indent.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/json.o: json.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/list.o: list.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/main.o: main.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/mark.o: mark.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/memfile.o: memfile.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/memline.o: memline.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/menu.o: menu.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/message.o: message.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/misc1.o: misc1.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h version.h
+objects/misc2.o: misc2.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/move.o: move.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/mbyte.o: mbyte.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/normal.o: normal.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/ops.o: ops.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/option.o: option.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/os_unix.o: os_unix.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h os_unixx.h
+objects/pathdef.o: auto/pathdef.c vim.h protodef.h auto/config.h feature.h \
+ os_unix.h auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/popupmnu.o: popupmnu.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/pty.o: pty.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/quickfix.o: quickfix.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/regexp.o: regexp.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h regexp_nfa.c
+objects/screen.o: screen.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/search.o: search.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/sha256.o: sha256.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/sign.o: sign.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/spell.o: spell.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/spellfile.o: spellfile.c vim.h protodef.h auto/config.h feature.h \
+ os_unix.h auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/syntax.o: syntax.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/tag.o: tag.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/term.o: term.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h libvterm/include/vterm.h \
+ libvterm/include/vterm_keycodes.h
+objects/terminal.o: terminal.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h libvterm/include/vterm.h \
+ libvterm/include/vterm_keycodes.h
+objects/textprop.o: textprop.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/ui.o: ui.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/undo.o: undo.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/userfunc.o: userfunc.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/version.o: version.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h version.h
+objects/window.o: window.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/gui.o: gui.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/gui_gtk.o: gui_gtk.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h gui_gtk_f.h
+objects/gui_gtk_f.o: gui_gtk_f.c vim.h protodef.h auto/config.h feature.h \
+ os_unix.h auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h gui_gtk_f.h
+objects/gui_motif.o: gui_motif.c vim.h protodef.h auto/config.h feature.h \
+ os_unix.h auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h gui_xmebw.h ../pixmaps/alert.xpm \
+ ../pixmaps/error.xpm ../pixmaps/generic.xpm ../pixmaps/info.xpm \
+ ../pixmaps/quest.xpm gui_x11_pm.h ../pixmaps/tb_new.xpm \
+ ../pixmaps/tb_open.xpm ../pixmaps/tb_close.xpm ../pixmaps/tb_save.xpm \
+ ../pixmaps/tb_print.xpm ../pixmaps/tb_cut.xpm ../pixmaps/tb_copy.xpm \
+ ../pixmaps/tb_paste.xpm ../pixmaps/tb_find.xpm \
+ ../pixmaps/tb_find_next.xpm ../pixmaps/tb_find_prev.xpm \
+ ../pixmaps/tb_find_help.xpm ../pixmaps/tb_exit.xpm \
+ ../pixmaps/tb_undo.xpm ../pixmaps/tb_redo.xpm ../pixmaps/tb_help.xpm \
+ ../pixmaps/tb_macro.xpm ../pixmaps/tb_make.xpm \
+ ../pixmaps/tb_save_all.xpm ../pixmaps/tb_jump.xpm \
+ ../pixmaps/tb_ctags.xpm ../pixmaps/tb_load_session.xpm \
+ ../pixmaps/tb_save_session.xpm ../pixmaps/tb_new_session.xpm \
+ ../pixmaps/tb_blank.xpm ../pixmaps/tb_maximize.xpm \
+ ../pixmaps/tb_split.xpm ../pixmaps/tb_minimize.xpm \
+ ../pixmaps/tb_shell.xpm ../pixmaps/tb_replace.xpm \
+ ../pixmaps/tb_vsplit.xpm ../pixmaps/tb_maxwidth.xpm \
+ ../pixmaps/tb_minwidth.xpm
+objects/gui_xmdlg.o: gui_xmdlg.c vim.h protodef.h auto/config.h feature.h \
+ os_unix.h auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/gui_xmebw.o: gui_xmebw.c vim.h protodef.h auto/config.h feature.h \
+ os_unix.h auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h gui_xmebwp.h gui_xmebw.h
+objects/gui_athena.o: gui_athena.c vim.h protodef.h auto/config.h feature.h \
+ os_unix.h auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h gui_at_sb.h gui_x11_pm.h \
+ ../pixmaps/tb_new.xpm ../pixmaps/tb_open.xpm ../pixmaps/tb_close.xpm \
+ ../pixmaps/tb_save.xpm ../pixmaps/tb_print.xpm ../pixmaps/tb_cut.xpm \
+ ../pixmaps/tb_copy.xpm ../pixmaps/tb_paste.xpm ../pixmaps/tb_find.xpm \
+ ../pixmaps/tb_find_next.xpm ../pixmaps/tb_find_prev.xpm \
+ ../pixmaps/tb_find_help.xpm ../pixmaps/tb_exit.xpm \
+ ../pixmaps/tb_undo.xpm ../pixmaps/tb_redo.xpm ../pixmaps/tb_help.xpm \
+ ../pixmaps/tb_macro.xpm ../pixmaps/tb_make.xpm \
+ ../pixmaps/tb_save_all.xpm ../pixmaps/tb_jump.xpm \
+ ../pixmaps/tb_ctags.xpm ../pixmaps/tb_load_session.xpm \
+ ../pixmaps/tb_save_session.xpm ../pixmaps/tb_new_session.xpm \
+ ../pixmaps/tb_blank.xpm ../pixmaps/tb_maximize.xpm \
+ ../pixmaps/tb_split.xpm ../pixmaps/tb_minimize.xpm \
+ ../pixmaps/tb_shell.xpm ../pixmaps/tb_replace.xpm \
+ ../pixmaps/tb_vsplit.xpm ../pixmaps/tb_maxwidth.xpm \
+ ../pixmaps/tb_minwidth.xpm
+objects/gui_gtk_x11.o: gui_gtk_x11.c vim.h protodef.h auto/config.h feature.h \
+ os_unix.h auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h auto/gui_gtk_gresources.h gui_gtk_f.h \
+ ../runtime/vim32x32.xpm ../runtime/vim16x16.xpm ../runtime/vim48x48.xpm
+objects/gui_x11.o: gui_x11.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h ../runtime/vim32x32.xpm \
+ ../runtime/vim16x16.xpm ../runtime/vim48x48.xpm
+objects/gui_at_sb.o: gui_at_sb.c vim.h protodef.h auto/config.h feature.h \
+ os_unix.h auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h gui_at_sb.h
+objects/gui_at_fs.o: gui_at_fs.c vim.h protodef.h auto/config.h feature.h \
+ os_unix.h auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h gui_at_sb.h
+objects/json_test.o: json_test.c main.c vim.h protodef.h auto/config.h feature.h \
+ os_unix.h auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h json.c
+objects/kword_test.o: kword_test.c main.c vim.h protodef.h auto/config.h \
+ feature.h os_unix.h auto/osdef.h ascii.h keymap.h term.h macros.h \
+ option.h beval.h proto/gui_beval.pro structs.h regexp.h gui.h alloc.h \
+ ex_cmds.h spell.h proto.h globals.h farsi.h arabic.h charset.c
+objects/memfile_test.o: memfile_test.c main.c vim.h protodef.h auto/config.h \
+ feature.h os_unix.h auto/osdef.h ascii.h keymap.h term.h macros.h \
+ option.h beval.h proto/gui_beval.pro structs.h regexp.h gui.h alloc.h \
+ ex_cmds.h spell.h proto.h globals.h farsi.h arabic.h memfile.c
+objects/message_test.o: message_test.c main.c vim.h protodef.h auto/config.h \
+ feature.h os_unix.h auto/osdef.h ascii.h keymap.h term.h macros.h \
+ option.h beval.h proto/gui_beval.pro structs.h regexp.h gui.h alloc.h \
+ ex_cmds.h spell.h proto.h globals.h farsi.h arabic.h message.c
+objects/hangulin.o: hangulin.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/if_lua.o: if_lua.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/if_mzsch.o: if_mzsch.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h if_mzsch.h
+objects/if_perl.o: auto/if_perl.c vim.h protodef.h auto/config.h feature.h \
+ os_unix.h auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/if_perlsfio.o: if_perlsfio.c vim.h protodef.h auto/config.h feature.h \
+ os_unix.h auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/if_python.o: if_python.c vim.h protodef.h auto/config.h feature.h \
+ os_unix.h auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h if_py_both.h
+objects/if_python3.o: if_python3.c vim.h protodef.h auto/config.h feature.h \
+ os_unix.h auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h if_py_both.h
+objects/if_tcl.o: if_tcl.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/if_ruby.o: if_ruby.c protodef.h auto/config.h vim.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h version.h
+objects/gui_beval.o: gui_beval.c vim.h protodef.h auto/config.h feature.h \
+ os_unix.h auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/netbeans.o: netbeans.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h version.h
+objects/channel.o: channel.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h farsi.h arabic.h
+objects/gui_gtk_gresources.o: auto/gui_gtk_gresources.c
+objects/encoding.o: libvterm/src/encoding.c libvterm/src/vterm_internal.h \
+ libvterm/include/vterm.h libvterm/include/vterm_keycodes.h \
+ libvterm/src/encoding/DECdrawing.inc libvterm/src/encoding/uk.inc
+objects/keyboard.o: libvterm/src/keyboard.c libvterm/src/vterm_internal.h \
+ libvterm/include/vterm.h libvterm/include/vterm_keycodes.h \
+ libvterm/src/utf8.h
+objects/mouse.o: libvterm/src/mouse.c libvterm/src/vterm_internal.h \
+ libvterm/include/vterm.h libvterm/include/vterm_keycodes.h \
+ libvterm/src/utf8.h
+objects/parser.o: libvterm/src/parser.c libvterm/src/vterm_internal.h \
+ libvterm/include/vterm.h libvterm/include/vterm_keycodes.h
+objects/pen.o: libvterm/src/pen.c libvterm/src/vterm_internal.h \
+ libvterm/include/vterm.h libvterm/include/vterm_keycodes.h
+objects/state.o: libvterm/src/state.c libvterm/src/vterm_internal.h \
+ libvterm/include/vterm.h libvterm/include/vterm_keycodes.h
+objects/termscreen.o: libvterm/src/termscreen.c libvterm/src/vterm_internal.h \
+ libvterm/include/vterm.h libvterm/include/vterm_keycodes.h \
+ libvterm/src/rect.h libvterm/src/utf8.h
+objects/unicode.o: libvterm/src/unicode.c libvterm/src/vterm_internal.h \
+ libvterm/include/vterm.h libvterm/include/vterm_keycodes.h
+objects/vterm.o: libvterm/src/vterm.c libvterm/src/vterm_internal.h \
+ libvterm/include/vterm.h libvterm/include/vterm_keycodes.h \
+ libvterm/src/utf8.h
+objects/xdiffi.o: xdiff/xdiffi.c xdiff/xinclude.h auto/config.h \
+ xdiff/xmacros.h xdiff/xdiff.h vim.h protodef.h \
+ auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h \
+ macros.h option.h beval.h proto/gui_beval.pro \
+ structs.h regexp.h gui.h alloc.h \
+ ex_cmds.h spell.h proto.h globals.h \
+ farsi.h arabic.h xdiff/xtypes.h xdiff/xutils.h \
+ xdiff/xprepare.h xdiff/xdiffi.h xdiff/xemit.h
+objects/xemit.o: xdiff/xemit.c xdiff/xinclude.h auto/config.h \
+ xdiff/xmacros.h xdiff/xdiff.h vim.h protodef.h \
+ auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h \
+ macros.h option.h beval.h proto/gui_beval.pro \
+ structs.h regexp.h gui.h alloc.h \
+ ex_cmds.h spell.h proto.h globals.h \
+ farsi.h arabic.h xdiff/xtypes.h xdiff/xutils.h \
+ xdiff/xprepare.h xdiff/xdiffi.h xdiff/xemit.h
+objects/xprepare.o: xdiff/xprepare.c xdiff/xinclude.h auto/config.h \
+ xdiff/xmacros.h xdiff/xdiff.h vim.h protodef.h \
+ auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h \
+ macros.h option.h beval.h proto/gui_beval.pro \
+ structs.h regexp.h gui.h alloc.h \
+ ex_cmds.h spell.h proto.h globals.h \
+ farsi.h arabic.h xdiff/xtypes.h xdiff/xutils.h \
+ xdiff/xprepare.h xdiff/xdiffi.h xdiff/xemit.h
+objects/xutils.o: xdiff/xutils.c xdiff/xinclude.h auto/config.h \
+ xdiff/xmacros.h xdiff/xdiff.h vim.h protodef.h \
+ auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h \
+ macros.h option.h beval.h proto/gui_beval.pro \
+ structs.h regexp.h gui.h alloc.h \
+ ex_cmds.h spell.h proto.h globals.h \
+ farsi.h arabic.h xdiff/xtypes.h xdiff/xutils.h \
+ xdiff/xprepare.h xdiff/xdiffi.h xdiff/xemit.h
+objects/xhistogram.o: xdiff/xhistogram.c xdiff/xinclude.h auto/config.h \
+ xdiff/xmacros.h xdiff/xdiff.h vim.h protodef.h \
+ auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h \
+ macros.h option.h beval.h proto/gui_beval.pro \
+ structs.h regexp.h gui.h alloc.h \
+ ex_cmds.h spell.h proto.h globals.h \
+ farsi.h arabic.h xdiff/xtypes.h xdiff/xutils.h \
+ xdiff/xprepare.h xdiff/xdiffi.h xdiff/xemit.h
+objects/xpatience.o: xdiff/xpatience.c xdiff/xinclude.h auto/config.h \
+ xdiff/xmacros.h xdiff/xdiff.h vim.h protodef.h \
+ auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h \
+ macros.h option.h beval.h proto/gui_beval.pro \
+ structs.h regexp.h gui.h alloc.h \
+ ex_cmds.h spell.h proto.h globals.h \
+ farsi.h arabic.h xdiff/xtypes.h xdiff/xutils.h \
+ xdiff/xprepare.h xdiff/xdiffi.h xdiff/xemit.h
diff --git a/src/README.txt b/src/README.txt
new file mode 100644
index 0000000..e1dc36f
--- /dev/null
+++ b/src/README.txt
@@ -0,0 +1,160 @@
+README for the Vim source code
+
+Here are a few hints for finding your way around the source code. This
+doesn't make it less complex than it is, but it gets you started.
+
+You might also want to read ":help development".
+
+
+JUMPING AROUND
+
+First of all, use ":make tags" to generate a tags file, so that you can jump
+around in the source code.
+
+To jump to a function or variable definition, move the cursor on the name and
+use the CTRL-] command. Use CTRL-T or CTRL-O to jump back.
+
+To jump to a file, move the cursor on its name and use the "gf" command.
+
+Most code can be found in a file with an obvious name (incomplete list):
+ autocmd.c autocommands
+ buffer.c manipulating buffers (loaded files)
+ diff.c diff mode (vimdiff)
+ eval.c expression evaluation
+ fileio.c reading and writing files
+ fold.c folding
+ getchar.c getting characters and key mapping
+ mark.c marks
+ mbyte.c multi-byte character handling
+ memfile.c storing lines for buffers in a swapfile
+ memline.c storing lines for buffers in memory
+ menu.c menus
+ message.c (error) messages
+ ops.c handling operators ("d", "y", "p")
+ option.c options
+ quickfix.c quickfix commands (":make", ":cn")
+ regexp.c pattern matching
+ screen.c updating the windows
+ search.c pattern searching
+ sign.c signs
+ spell.c spell checking
+ syntax.c syntax and other highlighting
+ tag.c tags
+ term.c terminal handling, termcap codes
+ undo.c undo and redo
+ window.c handling split windows
+
+
+DEBUGGING
+
+If you have a reasonable recent version of gdb, you can use the :Termdebug
+command to debug Vim. See ":help :Termdebug".
+
+When something is time critical or stepping through code is a hassle, use the
+channel logging to create a time-stamped log file. Add lines to the code like
+this:
+ ch_log(NULL, "Value is now %02x", value);
+After compiling and starting Vim, do:
+ :call ch_logfile('debuglog', 'w')
+And edit "debuglog" to see what happens. The channel functions already have
+ch_log() calls, thus you always see that in the log.
+
+
+IMPORTANT VARIABLES
+
+The current mode is stored in "State". The values it can have are NORMAL,
+INSERT, CMDLINE, and a few others.
+
+The current window is "curwin". The current buffer is "curbuf". These point
+to structures with the cursor position in the window, option values, the file
+name, etc. These are defined in structs.h.
+
+All the global variables are declared in globals.h.
+
+
+THE MAIN LOOP
+
+This is conveniently called main_loop(). It updates a few things and then
+calls normal_cmd() to process a command. This returns when the command is
+finished.
+
+The basic idea is that Vim waits for the user to type a character and
+processes it until another character is needed. Thus there are several places
+where Vim waits for a character to be typed. The vgetc() function is used for
+this. It also handles mapping.
+
+Updating the screen is mostly postponed until a command or a sequence of
+commands has finished. The work is done by update_screen(), which calls
+win_update() for every window, which calls win_line() for every line.
+See the start of screen.c for more explanations.
+
+
+COMMAND-LINE MODE
+
+When typing a ":", normal_cmd() will call getcmdline() to obtain a line with
+an Ex command. getcmdline() contains a loop that will handle each typed
+character. It returns when hitting <CR> or <Esc> or some other character that
+ends the command line mode.
+
+
+EX COMMANDS
+
+Ex commands are handled by the function do_cmdline(). It does the generic
+parsing of the ":" command line and calls do_one_cmd() for each separate
+command. It also takes care of while loops.
+
+do_one_cmd() parses the range and generic arguments and puts them in the
+exarg_t and passes it to the function that handles the command.
+
+The ":" commands are listed in ex_cmds.h. The third entry of each item is the
+name of the function that handles the command. The last entry are the flags
+that are used for the command.
+
+
+NORMAL MODE COMMANDS
+
+The Normal mode commands are handled by the normal_cmd() function. It also
+handles the optional count and an extra character for some commands. These
+are passed in a cmdarg_t to the function that handles the command.
+
+There is a table nv_cmds in normal.c which lists the first character of every
+command. The second entry of each item is the name of the function that
+handles the command.
+
+
+INSERT MODE COMMANDS
+
+When doing an "i" or "a" command, normal_cmd() will call the edit() function.
+It contains a loop that waits for the next character and handles it. It
+returns when leaving Insert mode.
+
+
+OPTIONS
+
+There is a list with all option names in option.c, called options[].
+
+
+THE GUI
+
+Most of the GUI code is implemented like it was a clever terminal. Typing a
+character, moving a scrollbar, clicking the mouse, etc. are all translated
+into events which are written in the input buffer. These are read by the
+main code, just like reading from a terminal. The code for this is scattered
+through gui.c. For example: gui_send_mouse_event() for a mouse click and
+gui_menu_cb() for a menu action. Key hits are handled by the system-specific
+GUI code, which calls add_to_input_buf() to send the key code.
+
+Updating the GUI window is done by writing codes in the output buffer, just
+like writing to a terminal. When the buffer gets full or is flushed,
+gui_write() will parse the codes and draw the appropriate items. Finally the
+system-specific GUI code will be called to do the work.
+
+
+DEBUGGING THE GUI
+
+Remember to prevent that gvim forks and the debugger thinks Vim has exited,
+add the "-f" argument. In gdb: "run -f -g".
+
+When stepping through display updating code, the focus event is triggered
+when going from the debugger to Vim and back. To avoid this, recompile with
+some code in gui_focus_change() disabled.
diff --git a/src/VisVim/Commands.cpp b/src/VisVim/Commands.cpp
new file mode 100644
index 0000000..569fbb8
--- /dev/null
+++ b/src/VisVim/Commands.cpp
@@ -0,0 +1,710 @@
+#include "stdafx.h"
+#include <comdef.h> // For _bstr_t
+#include "VisVim.h"
+#include "Commands.h"
+#include "OleAut.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+
+#endif
+
+
+// Change directory before opening file?
+#define CD_SOURCE 0 // Cd to source path
+#define CD_SOURCE_PARENT 1 // Cd to parent directory of source path
+#define CD_NONE 2 // No cd
+
+
+static BOOL g_bEnableVim = TRUE; // Vim enabled
+static BOOL g_bDevStudioEditor = FALSE; // Open file in Dev Studio editor simultaneously
+static BOOL g_bNewTabs = FALSE;
+static int g_ChangeDir = CD_NONE; // CD after file open?
+
+static void VimSetEnableState(BOOL bEnableState);
+static BOOL VimOpenFile(BSTR& FileName, long LineNr);
+static DISPID VimGetDispatchId(COleAutomationControl& VimOle, char* Method);
+static void VimErrDiag(COleAutomationControl& VimOle);
+static void VimChangeDir(COleAutomationControl& VimOle, DISPID DispatchId, BSTR& FileName);
+static void DebugMsg(char* Msg, char* Arg = NULL);
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CCommands
+
+CCommands::CCommands()
+{
+ // m_pApplication == NULL; M$ Code generation bug!!!
+ m_pApplication = NULL;
+ m_pApplicationEventsObj = NULL;
+ m_pDebuggerEventsObj = NULL;
+}
+
+CCommands::~CCommands()
+{
+ ASSERT(m_pApplication != NULL);
+ if (m_pApplication)
+ {
+ m_pApplication->Release();
+ m_pApplication = NULL;
+ }
+}
+
+void CCommands::SetApplicationObject(IApplication * pApplication)
+{
+ // This function assumes pApplication has already been AddRef'd
+ // for us, which CDSAddIn did in it's QueryInterface call
+ // just before it called us.
+ m_pApplication = pApplication;
+ if (! m_pApplication)
+ return;
+
+ // Create Application event handlers
+ XApplicationEventsObj::CreateInstance(&m_pApplicationEventsObj);
+ if (! m_pApplicationEventsObj)
+ {
+ ReportInternalError("XApplicationEventsObj::CreateInstance");
+ return;
+ }
+ m_pApplicationEventsObj->AddRef();
+ m_pApplicationEventsObj->Connect(m_pApplication);
+ m_pApplicationEventsObj->m_pCommands = this;
+
+#ifdef NEVER
+ // Create Debugger event handler
+ CComPtr < IDispatch > pDebugger;
+ if (SUCCEEDED(m_pApplication->get_Debugger(&pDebugger))
+ && pDebugger != NULL)
+ {
+ XDebuggerEventsObj::CreateInstance(&m_pDebuggerEventsObj);
+ m_pDebuggerEventsObj->AddRef();
+ m_pDebuggerEventsObj->Connect(pDebugger);
+ m_pDebuggerEventsObj->m_pCommands = this;
+ }
+#endif
+
+ // Get settings from registry HKEY_CURRENT_USER\Software\Vim\VisVim
+ HKEY hAppKey = GetAppKey("Vim");
+ if (hAppKey)
+ {
+ HKEY hSectionKey = GetSectionKey(hAppKey, "VisVim");
+ if (hSectionKey)
+ {
+ g_bEnableVim = GetRegistryInt(hSectionKey, "EnableVim",
+ g_bEnableVim);
+ g_bDevStudioEditor = GetRegistryInt(hSectionKey,
+ "DevStudioEditor", g_bDevStudioEditor);
+ g_bNewTabs = GetRegistryInt(hSectionKey, "NewTabs",
+ g_bNewTabs);
+ g_ChangeDir = GetRegistryInt(hSectionKey, "ChangeDir",
+ g_ChangeDir);
+ RegCloseKey(hSectionKey);
+ }
+ RegCloseKey(hAppKey);
+ }
+}
+
+void CCommands::UnadviseFromEvents()
+{
+ ASSERT(m_pApplicationEventsObj != NULL);
+ if (m_pApplicationEventsObj)
+ {
+ m_pApplicationEventsObj->Disconnect(m_pApplication);
+ m_pApplicationEventsObj->Release();
+ m_pApplicationEventsObj = NULL;
+ }
+
+#ifdef NEVER
+ if (m_pDebuggerEventsObj)
+ {
+ // Since we were able to connect to the Debugger events, we
+ // should be able to access the Debugger object again to
+ // unadvise from its events (thus the VERIFY_OK below--see
+ // stdafx.h).
+ CComPtr < IDispatch > pDebugger;
+ VERIFY_OK(m_pApplication->get_Debugger(&pDebugger));
+ ASSERT(pDebugger != NULL);
+ m_pDebuggerEventsObj->Disconnect(pDebugger);
+ m_pDebuggerEventsObj->Release();
+ m_pDebuggerEventsObj = NULL;
+ }
+#endif
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Event handlers
+
+// Application events
+
+HRESULT CCommands::XApplicationEvents::BeforeBuildStart()
+{
+ AFX_MANAGE_STATE(AfxGetStaticModuleState());
+ return S_OK;
+}
+
+HRESULT CCommands::XApplicationEvents::BuildFinish(long nNumErrors, long nNumWarnings)
+{
+ AFX_MANAGE_STATE(AfxGetStaticModuleState());
+ return S_OK;
+}
+
+HRESULT CCommands::XApplicationEvents::BeforeApplicationShutDown()
+{
+ AFX_MANAGE_STATE(AfxGetStaticModuleState());
+ return S_OK;
+}
+
+// The open document event handle is the place where the real interface work
+// is done.
+// Vim gets called from here.
+//
+HRESULT CCommands::XApplicationEvents::DocumentOpen(IDispatch * theDocument)
+{
+ AFX_MANAGE_STATE(AfxGetStaticModuleState());
+
+ if (! g_bEnableVim)
+ // Vim not enabled or empty command line entered
+ return S_OK;
+
+ // First get the current file name and line number
+
+ // Get the document object
+ CComQIPtr < ITextDocument, &IID_ITextDocument > pDoc(theDocument);
+ if (! pDoc)
+ return S_OK;
+
+ BSTR FileName;
+ long LineNr = -1;
+
+ // Get the document name
+ if (FAILED(pDoc->get_FullName(&FileName)))
+ return S_OK;
+
+ LPDISPATCH pDispSel;
+
+ // Get a selection object dispatch pointer
+ if (SUCCEEDED(pDoc->get_Selection(&pDispSel)))
+ {
+ // Get the selection object
+ CComQIPtr < ITextSelection, &IID_ITextSelection > pSel(pDispSel);
+
+ if (pSel)
+ // Get the selection line number
+ pSel->get_CurrentLine(&LineNr);
+
+ pDispSel->Release();
+ }
+
+ // Open the file in Vim and position to the current line
+ if (VimOpenFile(FileName, LineNr))
+ {
+ if (! g_bDevStudioEditor)
+ {
+ // Close the document in developer studio
+ CComVariant vSaveChanges = dsSaveChangesPrompt;
+ DsSaveStatus Saved;
+
+ pDoc->Close(vSaveChanges, &Saved);
+ }
+ }
+
+ // We're done here
+ SysFreeString(FileName);
+ return S_OK;
+}
+
+HRESULT CCommands::XApplicationEvents::BeforeDocumentClose(IDispatch * theDocument)
+{
+ AFX_MANAGE_STATE(AfxGetStaticModuleState());
+ return S_OK;
+}
+
+HRESULT CCommands::XApplicationEvents::DocumentSave(IDispatch * theDocument)
+{
+ AFX_MANAGE_STATE(AfxGetStaticModuleState());
+ return S_OK;
+}
+
+HRESULT CCommands::XApplicationEvents::NewDocument(IDispatch * theDocument)
+{
+ AFX_MANAGE_STATE(AfxGetStaticModuleState());
+
+ if (! g_bEnableVim)
+ // Vim not enabled or empty command line entered
+ return S_OK;
+
+ // First get the current file name and line number
+
+ CComQIPtr < ITextDocument, &IID_ITextDocument > pDoc(theDocument);
+ if (! pDoc)
+ return S_OK;
+
+ BSTR FileName;
+ HRESULT hr;
+
+ hr = pDoc->get_FullName(&FileName);
+ if (FAILED(hr))
+ return S_OK;
+
+ // Open the file in Vim and position to the current line
+ if (VimOpenFile(FileName, 0))
+ {
+ if (! g_bDevStudioEditor)
+ {
+ // Close the document in developer studio
+ CComVariant vSaveChanges = dsSaveChangesPrompt;
+ DsSaveStatus Saved;
+
+ pDoc->Close(vSaveChanges, &Saved);
+ }
+ }
+
+ SysFreeString(FileName);
+ return S_OK;
+}
+
+HRESULT CCommands::XApplicationEvents::WindowActivate(IDispatch * theWindow)
+{
+ AFX_MANAGE_STATE(AfxGetStaticModuleState());
+ return S_OK;
+}
+
+HRESULT CCommands::XApplicationEvents::WindowDeactivate(IDispatch * theWindow)
+{
+ AFX_MANAGE_STATE(AfxGetStaticModuleState());
+ return S_OK;
+}
+
+HRESULT CCommands::XApplicationEvents::WorkspaceOpen()
+{
+ AFX_MANAGE_STATE(AfxGetStaticModuleState());
+ return S_OK;
+}
+
+HRESULT CCommands::XApplicationEvents::WorkspaceClose()
+{
+ AFX_MANAGE_STATE(AfxGetStaticModuleState());
+ return S_OK;
+}
+
+HRESULT CCommands::XApplicationEvents::NewWorkspace()
+{
+ AFX_MANAGE_STATE(AfxGetStaticModuleState());
+ return S_OK;
+}
+
+// Debugger event
+
+HRESULT CCommands::XDebuggerEvents::BreakpointHit(IDispatch * pBreakpoint)
+{
+ AFX_MANAGE_STATE(AfxGetStaticModuleState());
+ return S_OK;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+// VisVim dialog
+
+class CMainDialog : public CDialog
+{
+ public:
+ CMainDialog(CWnd * pParent = NULL); // Standard constructor
+
+ //{{AFX_DATA(CMainDialog)
+ enum { IDD = IDD_ADDINMAIN };
+ int m_ChangeDir;
+ BOOL m_bDevStudioEditor;
+ BOOL m_bNewTabs;
+ //}}AFX_DATA
+
+ //{{AFX_VIRTUAL(CMainDialog)
+ protected:
+ virtual void DoDataExchange(CDataExchange * pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+
+ protected:
+ //{{AFX_MSG(CMainDialog)
+ afx_msg void OnEnable();
+ afx_msg void OnDisable();
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+};
+
+CMainDialog::CMainDialog(CWnd * pParent /* =NULL */ )
+ : CDialog(CMainDialog::IDD, pParent)
+{
+ //{{AFX_DATA_INIT(CMainDialog)
+ m_ChangeDir = -1;
+ m_bDevStudioEditor = FALSE;
+ m_bNewTabs = FALSE;
+ //}}AFX_DATA_INIT
+}
+
+void CMainDialog::DoDataExchange(CDataExchange * pDX)
+{
+ CDialog::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CMainDialog)
+ DDX_Radio(pDX, IDC_CD_SOURCE_PATH, m_ChangeDir);
+ DDX_Check(pDX, IDC_DEVSTUDIO_EDITOR, m_bDevStudioEditor);
+ DDX_Check(pDX, IDC_NEW_TABS, m_bNewTabs);
+ //}}AFX_DATA_MAP
+}
+
+BEGIN_MESSAGE_MAP(CMainDialog, CDialog)
+ //{{AFX_MSG_MAP(CMainDialog)
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CCommands methods
+
+STDMETHODIMP CCommands::VisVimDialog()
+{
+ AFX_MANAGE_STATE(AfxGetStaticModuleState());
+
+ // Use m_pApplication to access the Developer Studio Application
+ // object,
+ // and VERIFY_OK to see error strings in DEBUG builds of your add-in
+ // (see stdafx.h)
+
+ VERIFY_OK(m_pApplication->EnableModeless(VARIANT_FALSE));
+
+ CMainDialog Dlg;
+
+ Dlg.m_bDevStudioEditor = g_bDevStudioEditor;
+ Dlg.m_bNewTabs = g_bNewTabs;
+ Dlg.m_ChangeDir = g_ChangeDir;
+ if (Dlg.DoModal() == IDOK)
+ {
+ g_bDevStudioEditor = Dlg.m_bDevStudioEditor;
+ g_bNewTabs = Dlg.m_bNewTabs;
+ g_ChangeDir = Dlg.m_ChangeDir;
+
+ // Save settings to registry HKEY_CURRENT_USER\Software\Vim\VisVim
+ HKEY hAppKey = GetAppKey("Vim");
+ if (hAppKey)
+ {
+ HKEY hSectionKey = GetSectionKey(hAppKey, "VisVim");
+ if (hSectionKey)
+ {
+ WriteRegistryInt(hSectionKey, "DevStudioEditor",
+ g_bDevStudioEditor);
+ WriteRegistryInt(hSectionKey, "NewTabs",
+ g_bNewTabs);
+ WriteRegistryInt(hSectionKey, "ChangeDir", g_ChangeDir);
+ RegCloseKey(hSectionKey);
+ }
+ RegCloseKey(hAppKey);
+ }
+ }
+
+ VERIFY_OK(m_pApplication->EnableModeless(VARIANT_TRUE));
+ return S_OK;
+}
+
+STDMETHODIMP CCommands::VisVimEnable()
+{
+ AFX_MANAGE_STATE(AfxGetStaticModuleState());
+ VimSetEnableState(true);
+ return S_OK;
+}
+
+STDMETHODIMP CCommands::VisVimDisable()
+{
+ AFX_MANAGE_STATE(AfxGetStaticModuleState());
+ VimSetEnableState(false);
+ return S_OK;
+}
+
+STDMETHODIMP CCommands::VisVimToggle()
+{
+ AFX_MANAGE_STATE(AfxGetStaticModuleState());
+ VimSetEnableState(! g_bEnableVim);
+ return S_OK;
+}
+
+STDMETHODIMP CCommands::VisVimLoad()
+{
+ AFX_MANAGE_STATE(AfxGetStaticModuleState());
+
+ // Use m_pApplication to access the Developer Studio Application object,
+ // and VERIFY_OK to see error strings in DEBUG builds of your add-in
+ // (see stdafx.h)
+
+ CComBSTR bStr;
+ // Define dispatch pointers for document and selection objects
+ CComPtr < IDispatch > pDispDoc, pDispSel;
+
+ // Get a document object dispatch pointer
+ VERIFY_OK(m_pApplication->get_ActiveDocument(&pDispDoc));
+ if (! pDispDoc)
+ return S_OK;
+
+ BSTR FileName;
+ long LineNr = -1;
+
+ // Get the document object
+ CComQIPtr < ITextDocument, &IID_ITextDocument > pDoc(pDispDoc);
+
+ if (! pDoc)
+ return S_OK;
+
+ // Get the document name
+ if (FAILED(pDoc->get_FullName(&FileName)))
+ return S_OK;
+
+ // Get a selection object dispatch pointer
+ if (SUCCEEDED(pDoc->get_Selection(&pDispSel)))
+ {
+ // Get the selection object
+ CComQIPtr < ITextSelection, &IID_ITextSelection > pSel(pDispSel);
+
+ if (pSel)
+ // Get the selection line number
+ pSel->get_CurrentLine(&LineNr);
+ }
+
+ // Open the file in Vim
+ VimOpenFile(FileName, LineNr);
+
+ SysFreeString(FileName);
+ return S_OK;
+}
+
+
+//
+// Here we do the actual processing and communication with Vim
+//
+
+// Set the enable state and save to registry
+//
+static void VimSetEnableState(BOOL bEnableState)
+{
+ g_bEnableVim = bEnableState;
+ HKEY hAppKey = GetAppKey("Vim");
+ if (hAppKey)
+ {
+ HKEY hSectionKey = GetSectionKey(hAppKey, "VisVim");
+ if (hSectionKey)
+ WriteRegistryInt(hSectionKey, "EnableVim", g_bEnableVim);
+ RegCloseKey(hAppKey);
+ }
+}
+
+// Open the file 'FileName' in Vim and goto line 'LineNr'
+// 'FileName' is expected to contain an absolute DOS path including the drive
+// letter.
+// 'LineNr' must contain a valid line number or 0, e. g. for a new file
+//
+static BOOL VimOpenFile(BSTR& FileName, long LineNr)
+{
+
+ // OLE automation object for com. with Vim
+ // When the object goes out of scope, it's destructor destroys the OLE
+ // connection;
+ // This is important to avoid blocking the object
+ // (in this memory corruption would be likely when terminating Vim
+ // while still running DevStudio).
+ // So keep this object local!
+ COleAutomationControl VimOle;
+
+ // :cd D:/Src2/VisVim/
+ //
+ // Get a dispatch id for the SendKeys method of Vim;
+ // enables connection to Vim if necessary
+ DISPID DispatchId;
+ DispatchId = VimGetDispatchId(VimOle, "SendKeys");
+ if (! DispatchId)
+ // OLE error, can't obtain dispatch id
+ goto OleError;
+
+ OLECHAR Buf[MAX_OLE_STR];
+ char FileNameTmp[MAX_OLE_STR];
+ char VimCmd[MAX_OLE_STR];
+ char *s, *p;
+
+ // Prepend CTRL-\ CTRL-N to exit insert mode
+ VimCmd[0] = 0x1c;
+ VimCmd[1] = 0x0e;
+ VimCmd[2] = 0;
+
+#ifdef SINGLE_WINDOW
+ // Update the current file in Vim if it has been modified.
+ // Disabled, because it could write the file when you don't want to.
+ sprintf(VimCmd + 2, ":up\n");
+#endif
+ if (! VimOle.Method(DispatchId, "s", TO_OLE_STR_BUF(VimCmd, Buf)))
+ goto OleError;
+
+ // Change Vim working directory to where the file is if desired
+ if (g_ChangeDir != CD_NONE)
+ VimChangeDir(VimOle, DispatchId, FileName);
+
+ // Make Vim open the file.
+ // In the filename convert all \ to /, put a \ before a space.
+ if (g_bNewTabs)
+ {
+ sprintf(VimCmd, ":tab drop ");
+ s = VimCmd + 10;
+ }
+ else
+ {
+ sprintf(VimCmd, ":drop ");
+ s = VimCmd + 6;
+ }
+ sprintf(FileNameTmp, "%S", (char *)FileName);
+ for (p = FileNameTmp; *p != '\0' && s < VimCmd + MAX_OLE_STR - 4; ++p)
+ if (*p == '\\')
+ *s++ = '/';
+ else
+ {
+ if (*p == ' ')
+ *s++ = '\\';
+ *s++ = *p;
+ }
+ *s++ = '\n';
+ *s = '\0';
+
+ if (! VimOle.Method(DispatchId, "s", TO_OLE_STR_BUF(VimCmd, Buf)))
+ goto OleError;
+
+ if (LineNr > 0)
+ {
+ // Goto line
+ sprintf(VimCmd, ":%ld\n", LineNr);
+ if (! VimOle.Method(DispatchId, "s", TO_OLE_STR_BUF(VimCmd, Buf)))
+ goto OleError;
+ }
+
+ // Make Vim come to the foreground
+ if (! VimOle.Method("SetForeground"))
+ VimOle.ErrDiag();
+
+ // We're done
+ return true;
+
+ OleError:
+ // There was an OLE error
+ // Check if it's the "unknown class string" error
+ VimErrDiag(VimOle);
+ return false;
+}
+
+// Return the dispatch id for the Vim method 'Method'
+// Create the Vim OLE object if necessary
+// Returns a valid dispatch id or null on error
+//
+static DISPID VimGetDispatchId(COleAutomationControl& VimOle, char* Method)
+{
+ // Initialize Vim OLE connection if not already done
+ if (! VimOle.IsCreated())
+ {
+ if (! VimOle.CreateObject("Vim.Application"))
+ return NULL;
+ }
+
+ // Get the dispatch id for the SendKeys method.
+ // By doing this, we are checking if Vim is still there...
+ DISPID DispatchId = VimOle.GetDispatchId("SendKeys");
+ if (! DispatchId)
+ {
+ // We can't get a dispatch id.
+ // This means that probably Vim has been terminated.
+ // Don't issue an error message here, instead
+ // destroy the OLE object and try to connect once more
+ //
+ // In fact, this should never happen, because the OLE aut. object
+ // should not be kept long enough to allow the user to terminate Vim
+ // to avoid memory corruption (why the heck is there no system garbage
+ // collection for those damned OLE memory chunks???).
+ VimOle.DeleteObject();
+ if (! VimOle.CreateObject("Vim.Application"))
+ // If this create fails, it's time for an error msg
+ return NULL;
+
+ if (! (DispatchId = VimOle.GetDispatchId("SendKeys")))
+ // There is something wrong...
+ return NULL;
+ }
+
+ return DispatchId;
+}
+
+// Output an error message for an OLE error
+// Check on the classstring error, which probably means Vim wasn't registered.
+//
+static void VimErrDiag(COleAutomationControl& VimOle)
+{
+ SCODE sc = GetScode(VimOle.GetResult());
+ if (sc == CO_E_CLASSSTRING)
+ {
+ char Buf[256];
+ sprintf(Buf, "There is no registered OLE automation server named "
+ "\"Vim.Application\".\n"
+ "Use the OLE-enabled version of Vim with VisVim and "
+ "make sure to register Vim by running \"vim -register\".");
+ MessageBox(NULL, Buf, "OLE Error", MB_OK);
+ }
+ else
+ VimOle.ErrDiag();
+}
+
+// Change directory to the directory the file 'FileName' is in or it's parent
+// directory according to the setting of the global 'g_ChangeDir':
+// 'FileName' is expected to contain an absolute DOS path including the drive
+// letter.
+// CD_NONE
+// CD_SOURCE_PATH
+// CD_SOURCE_PARENT
+//
+static void VimChangeDir(COleAutomationControl& VimOle, DISPID DispatchId, BSTR& FileName)
+{
+ // Do a :cd first
+
+ // Get the path name of the file ("dir/")
+ CString StrFileName = FileName;
+ char Drive[_MAX_DRIVE];
+ char Dir[_MAX_DIR];
+ char DirUnix[_MAX_DIR * 2];
+ char *s, *t;
+
+ _splitpath(StrFileName, Drive, Dir, NULL, NULL);
+
+ // Convert to Unix path name format, escape spaces.
+ t = DirUnix;
+ for (s = Dir; *s; ++s)
+ if (*s == '\\')
+ *t++ = '/';
+ else
+ {
+ if (*s == ' ')
+ *t++ = '\\';
+ *t++ = *s;
+ }
+ *t = '\0';
+
+
+ // Construct the cd command; append /.. if cd to parent
+ // directory and not in root directory
+ OLECHAR Buf[MAX_OLE_STR];
+ char VimCmd[MAX_OLE_STR];
+
+ sprintf(VimCmd, ":cd %s%s%s\n", Drive, DirUnix,
+ g_ChangeDir == CD_SOURCE_PARENT && DirUnix[1] ? ".." : "");
+ VimOle.Method(DispatchId, "s", TO_OLE_STR_BUF(VimCmd, Buf));
+}
+
+#ifdef _DEBUG
+// Print out a debug message
+//
+static void DebugMsg(char* Msg, char* Arg)
+{
+ char Buf[400];
+ sprintf(Buf, Msg, Arg);
+ AfxMessageBox(Buf);
+}
+#endif
diff --git a/src/VisVim/Commands.h b/src/VisVim/Commands.h
new file mode 100644
index 0000000..e47c81a
--- /dev/null
+++ b/src/VisVim/Commands.h
@@ -0,0 +1,127 @@
+// Commands.h : header file
+//
+
+#if !defined(AFX_COMMANDS_H__AC726717_2977_11D1_B2F3_006008040780__INCLUDED_)
+#define AFX_COMMANDS_H__AC726717_2977_11D1_B2F3_006008040780__INCLUDED_
+
+#include "vsvtypes.h"
+
+class CCommands :
+ public CComDualImpl < ICommands,
+ &IID_ICommands,
+ &LIBID_VisVim >,
+ public CComObjectRoot,
+ public CComCoClass < CCommands,
+ &CLSID_Commands >
+{
+ protected:
+ IApplication * m_pApplication;
+
+ public:
+ CCommands ();
+ ~CCommands ();
+ void SetApplicationObject (IApplication * m_pApplication);
+ IApplication *GetApplicationObject ()
+ {
+ return m_pApplication;
+ }
+ void UnadviseFromEvents ();
+
+ BEGIN_COM_MAP (CCommands)
+ COM_INTERFACE_ENTRY (IDispatch)
+ COM_INTERFACE_ENTRY (ICommands)
+ END_COM_MAP ()
+ DECLARE_NOT_AGGREGATABLE (CCommands)
+
+ protected:
+ // This class template is used as the base class for the Application
+ // event handler object and the Debugger event handler object,
+ // which are declared below.
+ template < class IEvents,
+ const IID * piidEvents,
+ const GUID * plibid,
+ class XEvents,
+ const CLSID * pClsidEvents >
+ class XEventHandler :
+ public CComDualImpl < IEvents,
+ piidEvents,
+ plibid >,
+ public CComObjectRoot,
+ public CComCoClass < XEvents,
+ pClsidEvents >
+ {
+ public:
+ BEGIN_COM_MAP (XEvents)
+ COM_INTERFACE_ENTRY (IDispatch)
+ COM_INTERFACE_ENTRY_IID (*piidEvents, IEvents)
+ END_COM_MAP ()
+ DECLARE_NOT_AGGREGATABLE (XEvents)
+ void Connect (IUnknown * pUnk)
+ {
+ VERIFY (SUCCEEDED (AtlAdvise (pUnk, this, *piidEvents,
+ &m_dwAdvise)));
+ }
+ void Disconnect (IUnknown * pUnk)
+ {
+ AtlUnadvise (pUnk, *piidEvents, m_dwAdvise);
+ }
+
+ CCommands *m_pCommands;
+
+ protected:
+ DWORD m_dwAdvise;
+ };
+
+ // This object handles events fired by the Application object
+ class XApplicationEvents : public XEventHandler < IApplicationEvents,
+ &IID_IApplicationEvents,
+ &LIBID_VisVim,
+ XApplicationEvents,
+ &CLSID_ApplicationEvents >
+ {
+ public:
+ // IApplicationEvents methods
+ STDMETHOD (BeforeBuildStart) (THIS);
+ STDMETHOD (BuildFinish) (THIS_ long nNumErrors, long nNumWarnings);
+ STDMETHOD (BeforeApplicationShutDown) (THIS);
+ STDMETHOD (DocumentOpen) (THIS_ IDispatch * theDocument);
+ STDMETHOD (BeforeDocumentClose) (THIS_ IDispatch * theDocument);
+ STDMETHOD (DocumentSave) (THIS_ IDispatch * theDocument);
+ STDMETHOD (NewDocument) (THIS_ IDispatch * theDocument);
+ STDMETHOD (WindowActivate) (THIS_ IDispatch * theWindow);
+ STDMETHOD (WindowDeactivate) (THIS_ IDispatch * theWindow);
+ STDMETHOD (WorkspaceOpen) (THIS);
+ STDMETHOD (WorkspaceClose) (THIS);
+ STDMETHOD (NewWorkspace) (THIS);
+ };
+ typedef CComObject < XApplicationEvents > XApplicationEventsObj;
+ XApplicationEventsObj *m_pApplicationEventsObj;
+
+ // This object handles events fired by the Application object
+ class XDebuggerEvents : public XEventHandler < IDebuggerEvents,
+ &IID_IDebuggerEvents,
+ &LIBID_VisVim,
+ XDebuggerEvents,
+ &CLSID_DebuggerEvents >
+ {
+ public:
+ // IDebuggerEvents method
+ STDMETHOD (BreakpointHit) (THIS_ IDispatch * pBreakpoint);
+ };
+ typedef CComObject < XDebuggerEvents > XDebuggerEventsObj;
+ XDebuggerEventsObj *m_pDebuggerEventsObj;
+
+ public:
+ // ICommands methods
+ STDMETHOD (VisVimDialog) (THIS);
+ STDMETHOD (VisVimEnable) (THIS);
+ STDMETHOD (VisVimDisable) (THIS);
+ STDMETHOD (VisVimToggle) (THIS);
+ STDMETHOD (VisVimLoad) (THIS);
+};
+
+typedef CComObject < CCommands > CCommandsObj;
+
+//{{AFX_INSERT_LOCATION}}
+
+#endif // !defined(AFX_COMMANDS_H__AC726717_2977_11D1_B2F3_006008040780__INCLUDED)
diff --git a/src/VisVim/DSAddIn.cpp b/src/VisVim/DSAddIn.cpp
new file mode 100644
index 0000000..b16361b
--- /dev/null
+++ b/src/VisVim/DSAddIn.cpp
@@ -0,0 +1,160 @@
+#include "stdafx.h"
+#include "VisVim.h"
+#include "DSAddIn.h"
+#include "Commands.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+
+#endif
+
+// This is called when the user first loads the add-in, and on start-up
+// of each subsequent Developer Studio session
+STDMETHODIMP CDSAddIn::OnConnection (IApplication * pApp, VARIANT_BOOL bFirstTime,
+ long dwCookie, VARIANT_BOOL * OnConnection)
+{
+ AFX_MANAGE_STATE (AfxGetStaticModuleState ());
+ *OnConnection = VARIANT_FALSE;
+
+ // Store info passed to us
+ IApplication *pApplication = NULL;
+ HRESULT hr;
+
+ hr = pApp->QueryInterface (IID_IApplication, (void **) &pApplication);
+ if (FAILED (hr))
+ {
+ ReportLastError (hr);
+ return E_UNEXPECTED;
+ }
+ if (pApplication == NULL)
+ {
+ ReportInternalError ("IApplication::QueryInterface");
+ return E_UNEXPECTED;
+ }
+
+ m_dwCookie = dwCookie;
+
+ // Create command dispatch, send info back to DevStudio
+ CCommandsObj::CreateInstance (&m_pCommands);
+ if (! m_pCommands)
+ {
+ ReportInternalError ("CCommandsObj::CreateInstance");
+ return E_UNEXPECTED;
+ }
+ m_pCommands->AddRef ();
+
+ // The QueryInterface above AddRef'd the Application object. It will
+ // be Release'd in CCommand's destructor.
+ m_pCommands->SetApplicationObject (pApplication);
+
+ hr = pApplication->SetAddInInfo ((long) AfxGetInstanceHandle (),
+ (LPDISPATCH) m_pCommands, IDR_TOOLBAR_MEDIUM, IDR_TOOLBAR_LARGE,
+ m_dwCookie);
+ if (FAILED (hr))
+ {
+ ReportLastError (hr);
+ return E_UNEXPECTED;
+ }
+
+ // Inform DevStudio of the commands we implement
+ if (! AddCommand (pApplication, "VisVimDialog", "VisVimDialogCmd",
+ IDS_CMD_DIALOG, 0, bFirstTime))
+ return E_UNEXPECTED;
+ if (! AddCommand (pApplication, "VisVimEnable", "VisVimEnableCmd",
+ IDS_CMD_ENABLE, 1, bFirstTime))
+ return E_UNEXPECTED;
+ if (! AddCommand (pApplication, "VisVimDisable", "VisVimDisableCmd",
+ IDS_CMD_DISABLE, 2, bFirstTime))
+ return E_UNEXPECTED;
+ if (! AddCommand (pApplication, "VisVimToggle", "VisVimToggleCmd",
+ IDS_CMD_TOGGLE, 3, bFirstTime))
+ return E_UNEXPECTED;
+ if (! AddCommand (pApplication, "VisVimLoad", "VisVimLoadCmd",
+ IDS_CMD_LOAD, 4, bFirstTime))
+ return E_UNEXPECTED;
+
+ *OnConnection = VARIANT_TRUE;
+ return S_OK;
+}
+
+// This is called on shut-down, and also when the user unloads the add-in
+STDMETHODIMP CDSAddIn::OnDisconnection (VARIANT_BOOL bLastTime)
+{
+ AFX_MANAGE_STATE (AfxGetStaticModuleState ());
+
+ m_pCommands->UnadviseFromEvents ();
+ m_pCommands->Release ();
+ m_pCommands = NULL;
+
+ return S_OK;
+}
+
+// Add a command to DevStudio
+// Creates a toolbar button for the command also.
+// 'MethodName' is the name of the method specified in the .odl file
+// 'StrResId' the resource id of the descriptive string
+// 'GlyphIndex' the image index into the command buttons bitmap
+// Return true on success
+//
+bool CDSAddIn::AddCommand (IApplication* pApp, char* MethodName, char* CmdName,
+ UINT StrResId, UINT GlyphIndex, VARIANT_BOOL bFirstTime)
+{
+ CString CmdString;
+ CString CmdText;
+
+ CmdText.LoadString (StrResId);
+ CmdString = CmdName;
+ CmdString += CmdText;
+
+ CComBSTR bszCmdString (CmdString);
+ CComBSTR bszMethod (MethodName);
+ CComBSTR bszCmdName (CmdName);
+
+ // (see stdafx.h for the definition of VERIFY_OK)
+
+ VARIANT_BOOL bRet;
+ VERIFY_OK (pApp->AddCommand (bszCmdString, bszMethod, GlyphIndex,
+ m_dwCookie, &bRet));
+ if (bRet == VARIANT_FALSE)
+ {
+ // AddCommand failed because a command with this name already exists.
+ ReportInternalError ("IApplication::AddCommand");
+ return FALSE;
+ }
+
+ // Add toolbar buttons only if this is the first time the add-in
+ // is being loaded. Toolbar buttons are automatically remembered
+ // by Developer Studio from session to session, so we should only
+ // add the toolbar buttons once.
+ if (bFirstTime == VARIANT_TRUE)
+ VERIFY_OK (pApp->AddCommandBarButton (dsGlyph, bszCmdName, m_dwCookie));
+
+ return TRUE;
+}
+
+void ReportLastError (HRESULT Err)
+{
+ char *Buf = NULL;
+ char Msg[512];
+
+ FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
+ NULL, Err,
+ MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
+ Buf, 400, NULL);
+ sprintf (Msg, "Unexpected error (Error code: %lx)\n%s", Err, Buf);
+
+ ::MessageBox (NULL, Msg, "VisVim", MB_OK | MB_ICONSTOP);
+ if (Buf)
+ LocalFree (Buf);
+}
+
+void ReportInternalError (char* Fct)
+{
+ char Msg[512];
+
+ sprintf (Msg, "Unexpected error\n%s failed", Fct);
+ ::MessageBox (NULL, Msg, "VisVim", MB_OK | MB_ICONSTOP);
+}
+
diff --git a/src/VisVim/DSAddIn.h b/src/VisVim/DSAddIn.h
new file mode 100644
index 0000000..7282872
--- /dev/null
+++ b/src/VisVim/DSAddIn.h
@@ -0,0 +1,53 @@
+// DSAddIn.h : header file
+//
+
+#if !defined(AFX_DSADDIN_H__AC726715_2977_11D1_B2F3_006008040780__INCLUDED_)
+#define AFX_DSADDIN_H__AC726715_2977_11D1_B2F3_006008040780__INCLUDED_
+
+#include "commands.h"
+
+// {4F9E01C0-406B-11d2-8006-00001C405077}
+DEFINE_GUID (CLSID_DSAddIn,
+ 0x4f9e01c0, 0x406b, 0x11d2, 0x80, 0x6, 0x0, 0x0, 0x1c, 0x40, 0x50, 0x77);
+
+/////////////////////////////////////////////////////////////////////////////
+// CDSAddIn
+
+class CDSAddIn :
+ public IDSAddIn,
+ public CComObjectRoot,
+ public CComCoClass < CDSAddIn,
+ &CLSID_DSAddIn >
+{
+ public:
+ DECLARE_REGISTRY (CDSAddIn, "VisVim.DSAddIn.1",
+ "VisVim Developer Studio Add-in", IDS_VISVIM_LONGNAME,
+ THREADFLAGS_BOTH)
+
+ CDSAddIn ()
+ {
+ }
+
+ BEGIN_COM_MAP (CDSAddIn)
+ COM_INTERFACE_ENTRY (IDSAddIn)
+ END_COM_MAP ()
+ DECLARE_NOT_AGGREGATABLE (CDSAddIn)
+
+ // IDSAddIns
+ public:
+ STDMETHOD (OnConnection) (THIS_ IApplication * pApp, VARIANT_BOOL bFirstTime,
+ long dwCookie, VARIANT_BOOL * OnConnection);
+ STDMETHOD (OnDisconnection) (THIS_ VARIANT_BOOL bLastTime);
+
+ protected:
+ bool AddCommand (IApplication* pApp, char* MethodName, char* CmdName,
+ UINT StrResId, UINT GlyphIndex, VARIANT_BOOL bFirstTime);
+
+ protected:
+ CCommandsObj * m_pCommands;
+ DWORD m_dwCookie;
+};
+
+//{{AFX_INSERT_LOCATION}}
+
+#endif // !defined(AFX_DSADDIN_H__AC726715_2977_11D1_B2F3_006008040780__INCLUDED)
diff --git a/src/VisVim/OleAut.cpp b/src/VisVim/OleAut.cpp
new file mode 100644
index 0000000..6902df9
--- /dev/null
+++ b/src/VisVim/OleAut.cpp
@@ -0,0 +1,781 @@
+//
+// Class for creating OLE automation controllers.
+//
+// CreateObject() creates an automation object
+// Invoke() will call a property or method of the automation object.
+// GetProperty() returns a property
+// SetProperty() changes a property
+// Method() invokes a method
+//
+// For example, the following VB code will control Microsoft Word:
+//
+// Private Sub Form_Load()
+// Dim wb As Object
+// Set wb = CreateObject("Word.Basic")
+// wb.AppShow
+// wb.FileNewDefault
+// wb.Insert "This is a test"
+// wb.FileSaveAs "c:\sample.doc)"
+// End Sub
+//
+// A C++ automation controller that does the same can be written as follows:
+// the helper functions:
+//
+// Void FormLoad ()
+// {
+// COleAutomationControl Aut;
+// Aut.CreateObject("Word.Basic");
+// Aut.Method ("AppShow");
+// Aut.Method ("FileNewDefault");
+// Aut.Method ("Insert", "s", (LPOLESTR) OLESTR ("This is a test"));
+// Aut.Method ("FileSaveAs", "s", OLESTR ("c:\\sample.doc"));
+// }
+//
+//
+
+#include "stdafx.h"
+#include <stdarg.h>
+#include "oleaut.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+
+static bool CountArgsInFormat (LPCTSTR Format, UINT* nArgs);
+static LPCTSTR GetNextVarType (LPCTSTR Format, VARTYPE* pVarType);
+
+
+COleAutomationControl::COleAutomationControl ()
+{
+ m_pDispatch = NULL;
+ m_hResult = NOERROR;
+ m_nErrArg = 0;
+ VariantInit (&m_VariantResult);
+}
+
+COleAutomationControl::~COleAutomationControl ()
+{
+ DeleteObject ();
+}
+
+void COleAutomationControl::DeleteObject ()
+{
+ if (m_pDispatch)
+ {
+ m_pDispatch->Release ();
+ m_pDispatch = NULL;
+ }
+}
+
+// Creates an instance of the Automation object and
+// obtains it's IDispatch interface.
+//
+// Parameters:
+// ProgId ProgID of Automation object
+//
+bool COleAutomationControl::CreateObject (char* ProgId)
+{
+ CLSID ClsId; // CLSID of automation object
+ LPUNKNOWN pUnknown = NULL; // IUnknown of automation object
+
+ // Retrieve CLSID from the progID that the user specified
+ LPOLESTR OleProgId = TO_OLE_STR (ProgId);
+ m_hResult = CLSIDFromProgID (OleProgId, &ClsId);
+ if (FAILED (m_hResult))
+ goto error;
+
+ // Create an instance of the automation object and ask for the
+ // IDispatch interface
+ m_hResult = CoCreateInstance (ClsId, NULL, CLSCTX_SERVER,
+ IID_IUnknown, (void**) &pUnknown);
+ if (FAILED (m_hResult))
+ goto error;
+
+ m_hResult = pUnknown->QueryInterface (IID_IDispatch, (void**) &m_pDispatch);
+ if (FAILED (m_hResult))
+ goto error;
+
+ pUnknown->Release ();
+ return true;
+
+error:
+ if (pUnknown)
+ pUnknown->Release ();
+ if (m_pDispatch)
+ m_pDispatch->Release ();
+ return false;
+}
+
+// Return the dispatch id of a named service
+// This id can be used in subsequent calls to GetProperty (), SetProperty () and
+// Method (). This is the preferred method when performance is important.
+//
+DISPID COleAutomationControl::GetDispatchId (char* Name)
+{
+ DISPID DispatchId;
+
+ ASSERT (m_pDispatch);
+
+ // Get DISPID of property/method
+ LPOLESTR OleName = TO_OLE_STR (Name);
+ m_hResult = m_pDispatch->GetIDsOfNames (IID_NULL, &OleName, 1,
+ LOCALE_USER_DEFAULT, &DispatchId);
+ if (FAILED (m_hResult))
+ return NULL;
+ return DispatchId;
+}
+
+// The following functions use these parameters:
+//
+// Parameters:
+//
+// Name Name of property or method.
+//
+// Format Format string that describes the variable list of parameters that
+// follows. The format string can contain the following characters.
+// & = mark the following format character as VT_BYREF
+// B = VT_BOOL
+// i = VT_I2
+// I = VT_I4
+// r = VT_R2
+// R = VT_R4
+// c = VT_CY
+// s = VT_BSTR (string pointer can be passed,
+// BSTR will be allocated by this function).
+// e = VT_ERROR
+// d = VT_DATE
+// v = VT_VARIANT. Use this to pass data types that are not described
+// in the format string. (For example SafeArrays).
+// D = VT_DISPATCH
+// U = VT_UNKNOWN
+//
+// ... Arguments of the property or method.
+// Arguments are described by Format.
+//
+
+bool COleAutomationControl::GetProperty (char* Name)
+{
+ return Invoke (DISPATCH_PROPERTYGET, Name, NULL, NULL);
+}
+
+bool COleAutomationControl::GetProperty (DISPID DispatchId)
+{
+ return Invoke (DISPATCH_PROPERTYGET, DispatchId, NULL, NULL);
+}
+
+bool COleAutomationControl::PutProperty (char* Name, LPCTSTR Format, ...)
+{
+ va_list ArgList;
+
+ va_start (ArgList, Format);
+ bool bRet = Invoke (DISPATCH_PROPERTYPUT, Name, Format, ArgList);
+ va_end (ArgList);
+ return bRet;
+}
+
+bool COleAutomationControl::PutProperty (DISPID DispatchId, LPCTSTR Format, ...)
+{
+ va_list ArgList;
+
+ va_start (ArgList, Format);
+ bool bRet = Invoke (DISPATCH_PROPERTYPUT, DispatchId, Format, ArgList);
+ va_end (ArgList);
+ return bRet;
+}
+
+bool COleAutomationControl::Method (char* Name, LPCTSTR Format, ...)
+{
+ va_list ArgList;
+
+ va_start (ArgList, Format);
+ bool bRet = Invoke (DISPATCH_METHOD, Name, Format, ArgList);
+ va_end (ArgList);
+ return bRet;
+}
+
+bool COleAutomationControl::Method (DISPID DispatchId, LPCTSTR Format, ...)
+{
+ va_list ArgList;
+
+ va_start (ArgList, Format);
+ bool bRet = Invoke (DISPATCH_METHOD, DispatchId, Format, ArgList);
+ va_end (ArgList);
+ return bRet;
+}
+
+bool COleAutomationControl::Invoke (WORD Flags, char* Name,
+ LPCTSTR Format, va_list ArgList)
+{
+ DISPID DispatchId = GetDispatchId (Name);
+ if (! DispatchId)
+ return false;
+ return Invoke (Flags, DispatchId, Format, ArgList);
+}
+
+bool COleAutomationControl::Invoke (WORD Flags, DISPID DispatchId,
+ LPCTSTR Format, va_list ArgList)
+{
+ UINT ArgCount = 0;
+ VARIANTARG* ArgVector = NULL;
+
+ ASSERT (m_pDispatch);
+
+ DISPPARAMS DispatchParams;
+ memset (&DispatchParams, 0, sizeof (DispatchParams));
+
+ // Determine number of arguments
+ if (Format)
+ CountArgsInFormat (Format, &ArgCount);
+
+ // Property puts have a named argument that represents the value that
+ // the property is being assigned.
+ DISPID DispIdNamed = DISPID_PROPERTYPUT;
+ if (Flags & DISPATCH_PROPERTYPUT)
+ {
+ if (ArgCount == 0)
+ {
+ m_hResult = ResultFromScode (E_INVALIDARG);
+ return false;
+ }
+ DispatchParams.cNamedArgs = 1;
+ DispatchParams.rgdispidNamedArgs = &DispIdNamed;
+ }
+
+ if (ArgCount)
+ {
+ // Allocate memory for all VARIANTARG parameters
+ ArgVector = (VARIANTARG*) CoTaskMemAlloc (
+ ArgCount * sizeof (VARIANTARG));
+ if (! ArgVector)
+ {
+ m_hResult = ResultFromScode (E_OUTOFMEMORY);
+ return false;
+ }
+ memset (ArgVector, 0, sizeof (VARIANTARG) * ArgCount);
+
+ // Get ready to walk vararg list
+ LPCTSTR s = Format;
+
+ VARIANTARG *p = ArgVector + ArgCount - 1; // Params go in opposite order
+
+ for (;;)
+ {
+ VariantInit (p);
+ if (! (s = GetNextVarType (s, &p->vt)))
+ break;
+
+ if (p < ArgVector)
+ {
+ m_hResult = ResultFromScode (E_INVALIDARG);
+ goto Cleanup;
+ }
+ switch (p->vt)
+ {
+ case VT_I2:
+ V_I2 (p) = va_arg (ArgList, short);
+ break;
+ case VT_I4:
+ V_I4 (p) = va_arg (ArgList, long);
+ break;
+ case VT_R4:
+ V_R4 (p) = va_arg (ArgList, float);
+ break;
+ case VT_DATE:
+ case VT_R8:
+ V_R8 (p) = va_arg (ArgList, double);
+ break;
+ case VT_CY:
+ V_CY (p) = va_arg (ArgList, CY);
+ break;
+ case VT_BSTR:
+ V_BSTR (p) = SysAllocString (va_arg (ArgList,
+ OLECHAR*));
+ if (! p->bstrVal)
+ {
+ m_hResult = ResultFromScode (E_OUTOFMEMORY);
+ p->vt = VT_EMPTY;
+ goto Cleanup;
+ }
+ break;
+ case VT_DISPATCH:
+ V_DISPATCH (p) = va_arg (ArgList, LPDISPATCH);
+ break;
+ case VT_ERROR:
+ V_ERROR (p) = va_arg (ArgList, SCODE);
+ break;
+ case VT_BOOL:
+ V_BOOL (p) = va_arg (ArgList, BOOL) ? -1 : 0;
+ break;
+ case VT_VARIANT:
+ *p = va_arg (ArgList, VARIANTARG);
+ break;
+ case VT_UNKNOWN:
+ V_UNKNOWN (p) = va_arg (ArgList, LPUNKNOWN);
+ break;
+
+ case VT_I2 | VT_BYREF:
+ V_I2REF (p) = va_arg (ArgList, short*);
+ break;
+ case VT_I4 | VT_BYREF:
+ V_I4REF (p) = va_arg (ArgList, long*);
+ break;
+ case VT_R4 | VT_BYREF:
+ V_R4REF (p) = va_arg (ArgList, float*);
+ break;
+ case VT_R8 | VT_BYREF:
+ V_R8REF (p) = va_arg (ArgList, double*);
+ break;
+ case VT_DATE | VT_BYREF:
+ V_DATEREF (p) = va_arg (ArgList, DATE*);
+ break;
+ case VT_CY | VT_BYREF:
+ V_CYREF (p) = va_arg (ArgList, CY*);
+ break;
+ case VT_BSTR | VT_BYREF:
+ V_BSTRREF (p) = va_arg (ArgList, BSTR*);
+ break;
+ case VT_DISPATCH | VT_BYREF:
+ V_DISPATCHREF (p) = va_arg (ArgList, LPDISPATCH*);
+ break;
+ case VT_ERROR | VT_BYREF:
+ V_ERRORREF (p) = va_arg (ArgList, SCODE*);
+ break;
+ case VT_BOOL | VT_BYREF:
+ {
+ BOOL* pBool = va_arg (ArgList, BOOL*);
+
+ *pBool = 0;
+ V_BOOLREF (p) = (VARIANT_BOOL*) pBool;
+ }
+ break;
+ case VT_VARIANT | VT_BYREF:
+ V_VARIANTREF (p) = va_arg (ArgList, VARIANTARG*);
+ break;
+ case VT_UNKNOWN | VT_BYREF:
+ V_UNKNOWNREF (p) = va_arg (ArgList, LPUNKNOWN*);
+ break;
+
+ default:
+ {
+ m_hResult = ResultFromScode (E_INVALIDARG);
+ goto Cleanup;
+ }
+ break;
+ }
+
+ --p; // Get ready to fill next argument
+ }
+ }
+
+ DispatchParams.cArgs = ArgCount;
+ DispatchParams.rgvarg = ArgVector;
+
+ // Initialize return variant, in case caller forgot. Caller can pass
+ // NULL if return value is not expected.
+ VariantInit (&m_VariantResult);
+
+ // Make the call
+ m_hResult = m_pDispatch->Invoke (DispatchId, IID_NULL, LOCALE_USER_DEFAULT,
+ Flags, &DispatchParams, &m_VariantResult,
+ &m_ExceptionInfo, &m_nErrArg);
+
+ Cleanup:
+ // Cleanup any arguments that need cleanup
+ if (ArgCount)
+ {
+ VARIANTARG* p = ArgVector;
+
+ while (ArgCount--)
+ {
+ switch (p->vt)
+ {
+ case VT_BSTR:
+ VariantClear (p);
+ break;
+ }
+ ++p;
+ }
+ CoTaskMemFree (ArgVector);
+ }
+
+ return FAILED (m_hResult) ? false : true;
+}
+
+#define CASE_SCODE(sc) \
+ case sc: \
+ lstrcpy((char*)ErrName, (char*)#sc); \
+ break;
+
+void COleAutomationControl::ErrDiag ()
+{
+ char ErrName[200];
+
+ SCODE sc = GetScode (m_hResult);
+ switch (sc)
+ {
+ // SCODE's defined in SCODE.H
+ CASE_SCODE (S_OK)
+ CASE_SCODE (S_FALSE)
+ CASE_SCODE (E_UNEXPECTED)
+ CASE_SCODE (E_OUTOFMEMORY)
+ CASE_SCODE (E_INVALIDARG)
+ CASE_SCODE (E_NOINTERFACE)
+ CASE_SCODE (E_POINTER)
+ CASE_SCODE (E_HANDLE)
+ CASE_SCODE (E_ABORT)
+ CASE_SCODE (E_FAIL)
+ CASE_SCODE (E_ACCESSDENIED)
+
+ // SCODE's defined in OLE2.H
+ CASE_SCODE (OLE_E_OLEVERB)
+ CASE_SCODE (OLE_E_ADVF)
+ CASE_SCODE (OLE_E_ENUM_NOMORE)
+ CASE_SCODE (OLE_E_ADVISENOTSUPPORTED)
+ CASE_SCODE (OLE_E_NOCONNECTION)
+ CASE_SCODE (OLE_E_NOTRUNNING)
+ CASE_SCODE (OLE_E_NOCACHE)
+ CASE_SCODE (OLE_E_BLANK)
+ CASE_SCODE (OLE_E_CLASSDIFF)
+ CASE_SCODE (OLE_E_CANT_GETMONIKER)
+ CASE_SCODE (OLE_E_CANT_BINDTOSOURCE)
+ CASE_SCODE (OLE_E_STATIC)
+ CASE_SCODE (OLE_E_PROMPTSAVECANCELLED)
+ CASE_SCODE (OLE_E_INVALIDRECT)
+ CASE_SCODE (OLE_E_WRONGCOMPOBJ)
+ CASE_SCODE (OLE_E_INVALIDHWND)
+ CASE_SCODE (OLE_E_NOT_INPLACEACTIVE)
+ CASE_SCODE (OLE_E_CANTCONVERT)
+ CASE_SCODE (OLE_E_NOSTORAGE)
+
+ CASE_SCODE (DV_E_FORMATETC)
+ CASE_SCODE (DV_E_DVTARGETDEVICE)
+ CASE_SCODE (DV_E_STGMEDIUM)
+ CASE_SCODE (DV_E_STATDATA)
+ CASE_SCODE (DV_E_LINDEX)
+ CASE_SCODE (DV_E_TYMED)
+ CASE_SCODE (DV_E_CLIPFORMAT)
+ CASE_SCODE (DV_E_DVASPECT)
+ CASE_SCODE (DV_E_DVTARGETDEVICE_SIZE)
+ CASE_SCODE (DV_E_NOIVIEWOBJECT)
+
+ CASE_SCODE (OLE_S_USEREG)
+ CASE_SCODE (OLE_S_STATIC)
+ CASE_SCODE (OLE_S_MAC_CLIPFORMAT)
+
+ CASE_SCODE (CONVERT10_E_OLESTREAM_GET)
+ CASE_SCODE (CONVERT10_E_OLESTREAM_PUT)
+ CASE_SCODE (CONVERT10_E_OLESTREAM_FMT)
+ CASE_SCODE (CONVERT10_E_OLESTREAM_BITMAP_TO_DIB)
+ CASE_SCODE (CONVERT10_E_STG_FMT)
+ CASE_SCODE (CONVERT10_E_STG_NO_STD_STREAM)
+ CASE_SCODE (CONVERT10_E_STG_DIB_TO_BITMAP)
+ CASE_SCODE (CONVERT10_S_NO_PRESENTATION)
+
+ CASE_SCODE (CLIPBRD_E_CANT_OPEN)
+ CASE_SCODE (CLIPBRD_E_CANT_EMPTY)
+ CASE_SCODE (CLIPBRD_E_CANT_SET)
+ CASE_SCODE (CLIPBRD_E_BAD_DATA)
+ CASE_SCODE (CLIPBRD_E_CANT_CLOSE)
+
+ CASE_SCODE (DRAGDROP_E_NOTREGISTERED)
+ CASE_SCODE (DRAGDROP_E_ALREADYREGISTERED)
+ CASE_SCODE (DRAGDROP_E_INVALIDHWND)
+ CASE_SCODE (DRAGDROP_S_DROP)
+ CASE_SCODE (DRAGDROP_S_CANCEL)
+ CASE_SCODE (DRAGDROP_S_USEDEFAULTCURSORS)
+
+ CASE_SCODE (OLEOBJ_E_NOVERBS)
+ CASE_SCODE (OLEOBJ_E_INVALIDVERB)
+ CASE_SCODE (OLEOBJ_S_INVALIDVERB)
+ CASE_SCODE (OLEOBJ_S_CANNOT_DOVERB_NOW)
+ CASE_SCODE (OLEOBJ_S_INVALIDHWND)
+ CASE_SCODE (INPLACE_E_NOTUNDOABLE)
+ CASE_SCODE (INPLACE_E_NOTOOLSPACE)
+ CASE_SCODE (INPLACE_S_TRUNCATED)
+
+ // SCODE's defined in COMPOBJ.H
+ CASE_SCODE (CO_E_NOTINITIALIZED)
+ CASE_SCODE (CO_E_ALREADYINITIALIZED)
+ CASE_SCODE (CO_E_CANTDETERMINECLASS)
+ CASE_SCODE (CO_E_CLASSSTRING)
+ CASE_SCODE (CO_E_IIDSTRING)
+ CASE_SCODE (CO_E_APPNOTFOUND)
+ CASE_SCODE (CO_E_APPSINGLEUSE)
+ CASE_SCODE (CO_E_ERRORINAPP)
+ CASE_SCODE (CO_E_DLLNOTFOUND)
+ CASE_SCODE (CO_E_ERRORINDLL)
+ CASE_SCODE (CO_E_WRONGOSFORAPP)
+ CASE_SCODE (CO_E_OBJNOTREG)
+ CASE_SCODE (CO_E_OBJISREG)
+ CASE_SCODE (CO_E_OBJNOTCONNECTED)
+ CASE_SCODE (CO_E_APPDIDNTREG)
+ CASE_SCODE (CLASS_E_NOAGGREGATION)
+ CASE_SCODE (CLASS_E_CLASSNOTAVAILABLE)
+ CASE_SCODE (REGDB_E_READREGDB)
+ CASE_SCODE (REGDB_E_WRITEREGDB)
+ CASE_SCODE (REGDB_E_KEYMISSING)
+ CASE_SCODE (REGDB_E_INVALIDVALUE)
+ CASE_SCODE (REGDB_E_CLASSNOTREG)
+ CASE_SCODE (REGDB_E_IIDNOTREG)
+ CASE_SCODE (RPC_E_CALL_REJECTED)
+ CASE_SCODE (RPC_E_CALL_CANCELED)
+ CASE_SCODE (RPC_E_CANTPOST_INSENDCALL)
+ CASE_SCODE (RPC_E_CANTCALLOUT_INASYNCCALL)
+ CASE_SCODE (RPC_E_CANTCALLOUT_INEXTERNALCALL)
+ CASE_SCODE (RPC_E_CONNECTION_TERMINATED)
+ CASE_SCODE (RPC_E_SERVER_DIED)
+ CASE_SCODE (RPC_E_CLIENT_DIED)
+ CASE_SCODE (RPC_E_INVALID_DATAPACKET)
+ CASE_SCODE (RPC_E_CANTTRANSMIT_CALL)
+ CASE_SCODE (RPC_E_CLIENT_CANTMARSHAL_DATA)
+ CASE_SCODE (RPC_E_CLIENT_CANTUNMARSHAL_DATA)
+ CASE_SCODE (RPC_E_SERVER_CANTMARSHAL_DATA)
+ CASE_SCODE (RPC_E_SERVER_CANTUNMARSHAL_DATA)
+ CASE_SCODE (RPC_E_INVALID_DATA)
+ CASE_SCODE (RPC_E_INVALID_PARAMETER)
+ CASE_SCODE (RPC_E_CANTCALLOUT_AGAIN)
+ CASE_SCODE (RPC_E_UNEXPECTED)
+
+ // SCODE's defined in DVOBJ.H
+ CASE_SCODE (DATA_S_SAMEFORMATETC)
+ CASE_SCODE (VIEW_E_DRAW)
+ CASE_SCODE (VIEW_S_ALREADY_FROZEN)
+ CASE_SCODE (CACHE_E_NOCACHE_UPDATED)
+ CASE_SCODE (CACHE_S_FORMATETC_NOTSUPPORTED)
+ CASE_SCODE (CACHE_S_SAMECACHE)
+ CASE_SCODE (CACHE_S_SOMECACHES_NOTUPDATED)
+
+ // SCODE's defined in STORAGE.H
+ CASE_SCODE (STG_E_INVALIDFUNCTION)
+ CASE_SCODE (STG_E_FILENOTFOUND)
+ CASE_SCODE (STG_E_PATHNOTFOUND)
+ CASE_SCODE (STG_E_TOOMANYOPENFILES)
+ CASE_SCODE (STG_E_ACCESSDENIED)
+ CASE_SCODE (STG_E_INVALIDHANDLE)
+ CASE_SCODE (STG_E_INSUFFICIENTMEMORY)
+ CASE_SCODE (STG_E_INVALIDPOINTER)
+ CASE_SCODE (STG_E_NOMOREFILES)
+ CASE_SCODE (STG_E_DISKISWRITEPROTECTED)
+ CASE_SCODE (STG_E_SEEKERROR)
+ CASE_SCODE (STG_E_WRITEFAULT)
+ CASE_SCODE (STG_E_READFAULT)
+ CASE_SCODE (STG_E_SHAREVIOLATION)
+ CASE_SCODE (STG_E_LOCKVIOLATION)
+ CASE_SCODE (STG_E_FILEALREADYEXISTS)
+ CASE_SCODE (STG_E_INVALIDPARAMETER)
+ CASE_SCODE (STG_E_MEDIUMFULL)
+ CASE_SCODE (STG_E_ABNORMALAPIEXIT)
+ CASE_SCODE (STG_E_INVALIDHEADER)
+ CASE_SCODE (STG_E_INVALIDNAME)
+ CASE_SCODE (STG_E_UNKNOWN)
+ CASE_SCODE (STG_E_UNIMPLEMENTEDFUNCTION)
+ CASE_SCODE (STG_E_INVALIDFLAG)
+ CASE_SCODE (STG_E_INUSE)
+ CASE_SCODE (STG_E_NOTCURRENT)
+ CASE_SCODE (STG_E_REVERTED)
+ CASE_SCODE (STG_E_CANTSAVE)
+ CASE_SCODE (STG_E_OLDFORMAT)
+ CASE_SCODE (STG_E_OLDDLL)
+ CASE_SCODE (STG_E_SHAREREQUIRED)
+ CASE_SCODE (STG_E_NOTFILEBASEDSTORAGE)
+ CASE_SCODE (STG_E_EXTANTMARSHALLINGS)
+ CASE_SCODE (STG_S_CONVERTED)
+
+ // SCODE's defined in STORAGE.H
+ CASE_SCODE (MK_E_CONNECTMANUALLY)
+ CASE_SCODE (MK_E_EXCEEDEDDEADLINE)
+ CASE_SCODE (MK_E_NEEDGENERIC)
+ CASE_SCODE (MK_E_UNAVAILABLE)
+ CASE_SCODE (MK_E_SYNTAX)
+ CASE_SCODE (MK_E_NOOBJECT)
+ CASE_SCODE (MK_E_INVALIDEXTENSION)
+ CASE_SCODE (MK_E_INTERMEDIATEINTERFACENOTSUPPORTED)
+ CASE_SCODE (MK_E_NOTBINDABLE)
+ CASE_SCODE (MK_E_NOTBOUND)
+ CASE_SCODE (MK_E_CANTOPENFILE)
+ CASE_SCODE (MK_E_MUSTBOTHERUSER)
+ CASE_SCODE (MK_E_NOINVERSE)
+ CASE_SCODE (MK_E_NOSTORAGE)
+ CASE_SCODE (MK_E_NOPREFIX)
+ CASE_SCODE (MK_S_REDUCED_TO_SELF)
+ CASE_SCODE (MK_S_ME)
+ CASE_SCODE (MK_S_HIM)
+ CASE_SCODE (MK_S_US)
+ CASE_SCODE (MK_S_MONIKERALREADYREGISTERED)
+
+ // SCODE's defined in DISPATCH.H
+ CASE_SCODE (DISP_E_UNKNOWNINTERFACE)
+ CASE_SCODE (DISP_E_MEMBERNOTFOUND)
+ CASE_SCODE (DISP_E_PARAMNOTFOUND)
+ CASE_SCODE (DISP_E_TYPEMISMATCH)
+ CASE_SCODE (DISP_E_UNKNOWNNAME)
+ CASE_SCODE (DISP_E_NONAMEDARGS)
+ CASE_SCODE (DISP_E_BADVARTYPE)
+ CASE_SCODE (DISP_E_EXCEPTION)
+ CASE_SCODE (DISP_E_OVERFLOW)
+ CASE_SCODE (DISP_E_BADINDEX)
+ CASE_SCODE (DISP_E_UNKNOWNLCID)
+ CASE_SCODE (DISP_E_ARRAYISLOCKED)
+ CASE_SCODE (DISP_E_BADPARAMCOUNT)
+ CASE_SCODE (DISP_E_PARAMNOTOPTIONAL)
+ CASE_SCODE (DISP_E_BADCALLEE)
+ CASE_SCODE (DISP_E_NOTACOLLECTION)
+
+ CASE_SCODE (TYPE_E_BUFFERTOOSMALL)
+ CASE_SCODE (TYPE_E_INVDATAREAD)
+ CASE_SCODE (TYPE_E_UNSUPFORMAT)
+ CASE_SCODE (TYPE_E_REGISTRYACCESS)
+ CASE_SCODE (TYPE_E_LIBNOTREGISTERED)
+ CASE_SCODE (TYPE_E_UNDEFINEDTYPE)
+ CASE_SCODE (TYPE_E_QUALIFIEDNAMEDISALLOWED)
+ CASE_SCODE (TYPE_E_INVALIDSTATE)
+ CASE_SCODE (TYPE_E_WRONGTYPEKIND)
+ CASE_SCODE (TYPE_E_ELEMENTNOTFOUND)
+ CASE_SCODE (TYPE_E_AMBIGUOUSNAME)
+ CASE_SCODE (TYPE_E_NAMECONFLICT)
+ CASE_SCODE (TYPE_E_UNKNOWNLCID)
+ CASE_SCODE (TYPE_E_DLLFUNCTIONNOTFOUND)
+ CASE_SCODE (TYPE_E_BADMODULEKIND)
+ CASE_SCODE (TYPE_E_SIZETOOBIG)
+ CASE_SCODE (TYPE_E_DUPLICATEID)
+ CASE_SCODE (TYPE_E_TYPEMISMATCH)
+ CASE_SCODE (TYPE_E_OUTOFBOUNDS)
+ CASE_SCODE (TYPE_E_IOERROR)
+ CASE_SCODE (TYPE_E_CANTCREATETMPFILE)
+ CASE_SCODE (TYPE_E_CANTLOADLIBRARY)
+ CASE_SCODE (TYPE_E_INCONSISTENTPROPFUNCS)
+ CASE_SCODE (TYPE_E_CIRCULARTYPE)
+
+ default:
+ lstrcpy (ErrName, "UNKNOWN SCODE");
+ }
+
+ char Buf[256];
+ sprintf (Buf, "An OLE error occurred:\r\nCode = %s\r\nResult = %lx.",
+ (char*) ErrName, m_hResult);
+ MessageBox (NULL, Buf, "OLE Error", MB_OK);
+}
+
+
+static bool CountArgsInFormat (LPCTSTR Format, UINT* pArgCount)
+{
+ *pArgCount = 0;
+
+ if (! Format)
+ return true;
+
+ while (*Format)
+ {
+ if (*Format == '&')
+ Format++;
+
+ switch (*Format)
+ {
+ case 'b':
+ case 'i':
+ case 'I':
+ case 'r':
+ case 'R':
+ case 'c':
+ case 's':
+ case 'e':
+ case 'd':
+ case 'v':
+ case 'D':
+ case 'U':
+ ++ (*pArgCount);
+ Format++;
+ break;
+ case '\0':
+ default:
+ return false;
+ }
+ }
+ return true;
+}
+
+static LPCTSTR GetNextVarType (LPCTSTR Format, VARTYPE* pVarType)
+{
+ *pVarType = 0;
+ if (*Format == '&')
+ {
+ *pVarType = VT_BYREF;
+ Format++;
+ if (!*Format)
+ return NULL;
+ }
+ switch (*Format)
+ {
+ case 'b':
+ *pVarType |= VT_BOOL;
+ break;
+ case 'i':
+ *pVarType |= VT_I2;
+ break;
+ case 'I':
+ *pVarType |= VT_I4;
+ break;
+ case 'r':
+ *pVarType |= VT_R4;
+ break;
+ case 'R':
+ *pVarType |= VT_R8;
+ break;
+ case 'c':
+ *pVarType |= VT_CY;
+ break;
+ case 's':
+ *pVarType |= VT_BSTR;
+ break;
+ case 'e':
+ *pVarType |= VT_ERROR;
+ break;
+ case 'd':
+ *pVarType |= VT_DATE;
+ break;
+ case 'v':
+ *pVarType |= VT_VARIANT;
+ break;
+ case 'U':
+ *pVarType |= VT_UNKNOWN;
+ break;
+ case 'D':
+ *pVarType |= VT_DISPATCH;
+ break;
+ case '\0':
+ return NULL; // End of Format string
+ default:
+ return NULL;
+ }
+ return ++Format;
+}
+
+#ifndef UNICODE
+char* ConvertToAnsi (OLECHAR* sUnicode)
+{
+ static char BufAscii[MAX_OLE_STR];
+ return ConvertToAnsiBuf (sUnicode, BufAscii);
+}
+
+char* ConvertToAnsiBuf (OLECHAR* sUnicode, char* BufAscii)
+{
+ WideCharToMultiByte (CP_ACP, 0, sUnicode, -1, BufAscii, MAX_OLE_STR, NULL, NULL);
+ return BufAscii;
+}
+
+OLECHAR* ConvertToUnicode (char* sAscii)
+{
+ static OLECHAR BufUnicode[MAX_OLE_STR];
+ return ConvertToUnicodeBuf (sAscii, BufUnicode);
+}
+
+OLECHAR* ConvertToUnicodeBuf (char* sAscii, OLECHAR* BufUnicode)
+{
+ MultiByteToWideChar (CP_ACP, 0, sAscii, -1, BufUnicode, MAX_OLE_STR);
+ return BufUnicode;
+}
+#endif
+
diff --git a/src/VisVim/OleAut.h b/src/VisVim/OleAut.h
new file mode 100644
index 0000000..37de807
--- /dev/null
+++ b/src/VisVim/OleAut.h
@@ -0,0 +1,73 @@
+#ifndef __OLEAUT_H__
+#define __OLEAUT_H__
+
+class COleAutomationControl : public CObject
+{
+ public:
+ COleAutomationControl ();
+ ~COleAutomationControl ();
+ bool CreateObject (char* ProgId);
+ DISPID GetDispatchId (char* Name);
+ bool GetProperty (char* Name);
+ bool GetProperty (DISPID DispatchId);
+ bool PutProperty (char* Name, LPCTSTR Format, ...);
+ bool PutProperty (DISPID DispatchId, LPCTSTR Format, ...);
+ bool Method (char* Name, LPCTSTR Format = NULL, ...);
+ bool Method (DISPID DispatchId, LPCTSTR Format = NULL, ...);
+ void DeleteObject ();
+ void ErrDiag ();
+ bool IsCreated ()
+ {
+ return m_pDispatch ? true : false;
+ }
+ bool IsAlive ();
+ HRESULT GetResult ()
+ {
+ return m_hResult;
+ }
+ UINT GetErrArgNr ()
+ {
+ return m_nErrArg;
+ }
+ EXCEPINFO* GetExceptionInfo ()
+ {
+ return &m_ExceptionInfo;
+ }
+ LPVARIANT GetResultVariant ()
+ {
+ return &m_VariantResult;
+ }
+
+ protected:
+ bool Invoke (WORD Flags, char* Name, LPCTSTR Format, va_list ArgList);
+ bool Invoke (WORD Flags, DISPID DispatchId, LPCTSTR Format, va_list ArgList);
+
+ protected:
+ IDispatch* m_pDispatch;
+ HRESULT m_hResult;
+ UINT m_nErrArg;
+ EXCEPINFO m_ExceptionInfo;
+ VARIANTARG m_VariantResult;
+};
+
+#ifdef UNICODE
+ #define FROM_OLE_STRING(str) str
+ #define FROM_OLE_STRING_BUF(str,buf) str
+ #define TO_OLE_STR(str) str
+ #define TO_OLE_STR_BUF(str,buf) str
+ #define MAX_OLE_STR 1
+#else
+ #define FROM_OLE_STR(str) ConvertToAnsi(str)
+ #define FROM_OLE_STR_BUF(str,buf) ConvertToAnsiBuf(str,buf)
+ char* ConvertToAnsi (OLECHAR* sUnicode);
+ char* ConvertToAnsiBuf (OLECHAR* sUnicode, char* Buf);
+ #define TO_OLE_STR(str) ConvertToUnicode(str)
+ #define TO_OLE_STR_BUF(str,buf) ConvertToUnicodeBuf(str,buf)
+ OLECHAR* ConvertToUnicode (char* sAscii);
+ OLECHAR* ConvertToUnicodeBuf (char* sAscii, OLECHAR* Buf);
+ // Maximum length of string that can be converted between Ansi & Unicode
+ #define MAX_OLE_STR 500
+#endif
+
+
+#endif // __OLEAUT_H__
diff --git a/src/VisVim/README_VisVim.txt b/src/VisVim/README_VisVim.txt
new file mode 100644
index 0000000..25b0fbd
--- /dev/null
+++ b/src/VisVim/README_VisVim.txt
@@ -0,0 +1,326 @@
+===============================
+Visual Studio - Vim Integration
+===============================
+
+Copyright (C) 1997 Heiko Erhardt
+
+VisVim is a Visual Studio Add-In that allows Vim to be integrated
+as the default text editor. It will be used instead of the Visual
+Studio built-in editor when you double-click on a file or press F4
+after compiling (it will go to the proper line in the Vim buffer).
+The file can be loaded exclusively by Vim or additionally to the
+builtin Visual Studio editor (this option can be set in the VisVim
+configuration dialog inside Visual Studio).
+Vim does not replace the Visual Studio editor, it still runs in its
+own window.
+
+VisVim is based upon VisEmacs by Christopher Payne
+(Copyright (C) Christopher Payne 1997).
+
+Author: Heiko Erhardt <heiko.erhardt@gmx.net>
+Based upon: VisEmacs by Christopher Payne <payneca@sagian.com>
+Version: 1.0
+Created: 23 Oct 1997
+Date: 23 Oct 1997
+
+VisVim was originally GNU GPL licensed, as stated below. On March 21 2012
+Heiko Erhardt declared this work to be relicensed under the Vim license, as
+stated in ../../runtime/doc/uganda.txt (or ":help uganda" in Vim).
+
+VisVim is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+VisVim is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+
+Requirements
+------------
+
+VisVim works with the *OLE-enabled* version of Vim version 5.0 and higher
+only!!! You must download the extra archive containing the OLE-enabled
+executable from your Vim download site. When building your own Vim
+executable, use the if_ole_vc.mak makefile (Vim 5.1 and higher).
+VisVim needs DevStudio 5.0 or higher. It does not work with DevStudio 4.2.
+
+
+Installation
+------------
+
+1) Close running instances of DevStudio.
+
+2) Copy VisVim.dll into a convenient directory like \vim,
+ \vim\lib, or \vim\addin
+
+3) Register the DLL using regsvr32.exe ... (Skip this on Windows 95/98)
+ Example:
+ > cd \vim\addin
+ > regsvr32 VisVim.dll
+ On NT, you should do this from an administrator account.
+ Before installing a new version of VisVim you should unregister
+ the old one using
+ > regsvr32 -unregister VisVim.dll
+ The batch files register.bat and unregister.bat can do that for you.
+
+3a) If you didn't do this yet: Register the OLE gvim:
+ > gvim -register
+
+4) Start Visual Studio and go to:
+ Tools
+ Customize...
+ Add-Ins and Macro Files
+
+5) Click on Browse, and point Visual Studio to your VisVim.dll file.
+
+6) Click the checkbox to indicate that you want to use the Add-In, and
+ Close the Customize dialog box.
+
+7) You should notice the VisVim Toolbar with the Vim Icon.
+ Click the first item of the toolbar to get to the options dialog.
+
+
+Compiling VisVim
+----------------
+
+Two Options:
+
+1) Load the VisVim.mak file as a Workspace in Visual Studio and compile
+
+2) Use the MSVC command line compiler:
+ vcvars32
+ nmake -f VisVim.mak
+
+
+Using VisVim
+------------
+
+The VisVim DLL exposes several functions to the user. These functions are
+accessible using the toolbar or by assigning hotkeys to them (see below).
+The following functions are visible on the toolbar (from left to right):
+
+1. VisVim settings dialog
+ The settings you adjust here will be saved in the registry and
+ will be reloaded on program startup.
+
+2. Enable Vim
+ Enables Vim as Visual Studio editor. Control will be switched to Vim when:
+ - Clicking a file in the file view
+ - Clicking a compiler error message line
+ - Using the 'File-Open' Dialog
+ - Showing the current source line when encountering a debugger breakpoint.
+ - Using File-New
+
+3. Disable Vim
+ The internal Visual Studio editor will be used to edit files.
+
+4. Toggle enable state
+ Toggles the enable state of VisVim. Use this function if you want to have
+ one button only to activate/deactivate Vim.
+
+5. Load current file in Vim
+ Loads the file shown in the internal editor into Vim. Use this function if
+ you want the internal editor to stay active and just edit one file in Vim.
+ This command works always whether Vim is enabled as default editor or not.
+
+You cannot use DevStudio's debugger commands from inside Vim, so you should
+disable Vim before running the debugger.
+
+You can customize the Vim toolbar itself or add the Vim buttons to other
+toolbars.
+To have fast access to the VisVim options dialog I suggest to create keyboard
+shortcuts:
+
+1) Choose
+ Tools
+ Customize...
+ Keyboard
+2) Choose Category:AddIns and Commands:VisVim.
+3) Choose 'Main' as editor, enter each hotkey and press the Assign button.
+ I suggest:
+ VisVimDialogCmd Alt+Shift+V
+ VisVimEnableCmd Alt+Shift+E
+ VisVimDisableCmd Alt+Shift+D
+ VisVimToggleCmd Alt+Shift+T
+ VisVimLoadCmd Alt+Shift+G
+4) Close the dialog
+
+Now a typical debugging example:
+
+Using "Alt+Shift+d" you turn off Vim before starting the debugger.
+After hitting the breakpoint you single step through your application
+using the internal source code editor and examine variables.
+When you stumble across the line with the null pointer
+assignment, just press "Alt+Shift+g", and correct the error in Vim.
+Save the file, press Alt+Tab to return to DevStudio and press F7 to compile.
+That's it.
+
+
+Troubleshooting
+---------------
+
+1. When opening a file in DevStudio the file is opened in the DevStudio
+ editor and immediately vanishes. No Vim shows up.
+ Cause: Probably you don't have the OLE-enabled Vim or you didn't
+ register it.
+ Explanation: VisVim is notified by DevStudio if an 'open document' event
+ occurs. It then closes the document in the internal editor
+ and tries to start Vim. If Vim isn't properly OLE-registered,
+ this won't work.
+ Workaround: Download and install the OLE-enable version of Vim and
+ execute "gvim -register".
+
+2. Sometimes when clicking on a file, the file won't be opened by Vim but
+ instead the Visual Studio editor comes up.
+ Cause: The file was already loaded by the DevStudio editor.
+ Explanation: VisVim works by hooks exposed by Visual Studio.
+ Most of the functionality works from the OpenDocument hook.
+ If a document is already loaded in the Visual Studio editor,
+ no 'open document' event will be generated when clicking the
+ file in the file list.
+ Workaround: Close the document in Visual Studio first.
+
+3. I can't get VisVim to work. Either the Vim toolbar does not appear at all
+ or weird crashes happen.
+ Cause: The Visual Studio installation is messed up.
+ Explanation: I can't give you one. Ask M$.
+ Workaround: Reinstall DevStudio (I know this is brute, but in some cases
+ it helped). There was one case where the service pack 1 had
+ to be installed, too.
+
+4. If an instance of Vim is already running, VisVim will use that instance
+ and not start a new one.
+ Cause: This is proper OLE behaviour
+ Explanation: Some call it a bug, some a feature. That's just the way OLE
+ works.
+
+5. When being in insert mode in Vim and selecting a file in Visual Studio,
+ the Vim command :e ... is inserted as text instead of being executed.
+ Cause: You probably know...
+ Explanation: The Vim OLE automation interface interprets the VisVim
+ commands as if they were typed in by the user.
+ So if you're in insert mode Vim considers it to be text.
+ I decided against sending an ESC before the command because
+ it may cause a beep or at least a screen flash when noeb is
+ set.
+ Workaround: Get used to press ESC before switching to DevStudio.
+
+6. I'm tired of VisVim but I can't get rid of it. I can't delete it in
+ Tools-Customize-Add-Ins.
+ Cause: You can't delete an item you once added to the add-ins
+ list box.
+ Explanation: M$ just didn't put a 'delete' button in the dialog box.
+ Unfortunately there is no DEL key accellerator as well...
+ Workaround: You can't kill it, but you can knock it out:
+ 1. Uncheck the check box in front of 'Vim Developer Studio
+ Add-in'.
+ 2. Close Visual Studio.
+ 3. Delete VisVim.dll or move it somewhere it can't be found.
+ 4. Run Visual Studio.
+ 5. Tools -> Customize ->Add-ins and Macro-Files.
+ 6. A message appears:
+ ".../VisVim.dll" "This add-in no longer exists. It will
+ no longer be displayed."
+ That's it!
+
+
+Change history
+--------------
+
+1.0a to 1.0
+-----------
+
+- All settings in the VisVim dialog are remembered between DevStudio sessions
+ by keeping them in the registry (HKEY_CURRENT_USER\Software\Vim\VisVim).
+- Added an option to do a :cd before opening the file (having a file opened
+ by clicking it but finding out to be still in C:\Windows\system when trying to
+ open another file by ":e" can be annoying). Change directory can be
+ done to the source file's directory or it's parent directory.
+- Added some explanations to the error message for the CO_E_CLASSSTRING error
+ ("Use OLE Vim and make sure to register...").
+
+1.0 to 1.1a
+-----------
+
+- The VisVim toolbar button now shows the new Vim icon instead of the old one.
+- Made some changes to the documentation, added the troubleshooting chapter
+ and ToDo list.
+- File-New-* now invokes Vim instead of the builtin editor if enabled.
+
+1.1 to 1.1b
+-----------
+
+- Extended the VisVim toolbar to have multiple buttons instead of one.
+- Moved the enable/disable commands from the settings dialog to the toolbar.
+- Added the toggle enable/disable command
+- Added the 'load current file' command.
+
+1.1b to 1.2
+-----------
+
+No new features, just some fine tuning:
+
+- Changed the GUID of the VisVim OLE interface to avoid conflicts with a
+ version of VisEmacs or VisVile on the same computer (Guy Gascoigne)
+- Fixed a bug caused by a bug in the Developer Studio add-in code generator
+ (Clark Morgan)
+- Fixed a memory leak (Clark Morgan)
+- Added an option in the VisVim dialog to prepend ESC before the first command
+ that is sent to Vim. This will avoid inserting the command as text when Vim
+ is still in insert mode.
+- An :update command is sent to Vim before any other command to update the
+ current file if it is modified, or else the following :cd or :e command will fail.
+
+1.2 to 1.3a
+-----------
+
+- Fixed a bug caused by a missing EnableModeless() function call in VimLoad().
+ This seems to reduce VisVim crashing DevStudio on some systems (it
+ occasionally still seems to happen, but it's more stable now).
+ (Vince Negri)
+- Added support for the new CTRL-\ CTRL-N command of Vim 5.4a.
+ This prevents Vim from beeping when a VisVim command is executed and Vim is
+ not in insert mode.
+
+
+ToDo List
+---------
+
+P1 is highest priority, P10 lowest
+
+P9 Switching to DevStudio using ALT-TAB may get annoying. Would be nice to
+ have the option to map ActivateApplication("Visual Studio") in Vim.
+ Vim DLLs would solve that problem.
+
+P8 Execute :tag command in Vim for word under cursor in DevStudio
+
+P7 Controlling the Visual Studio Debugger from inside Vim
+ See message above. Also a 'Debug' highlight group and a
+ command to highlight a certain line would be necessary.
+
+P6 Provide an option to open the current file in VisVim in
+ Visual Studio editor
+ Same as above message. A kind of two way OLE automation would have to be
+ established between VisVim and Vim. Also a 'Debug' highlight group and a
+ command to highlight a certain line would be necessary.
+
+
+Known Problems
+--------------
+
+- Occasional memory corruptions in DevStudio may appear on some systems.
+ Reinstalling DevStudio helped in some cases.
+ The cause of these crashes is unclear; there is no way to debug this.
+ Recompiling VisVim with DevStudio SP3 didn't help.
+ I assume it's a problem deep inside the DevStudio add-in OLE interfaces.
+ This will hopefully be fixed with DevStudio 6.
+
+
+Have fun!
+
+Heiko Erhardt
+heiko.erhardt@gmx.net
+
diff --git a/src/VisVim/Reg.cpp b/src/VisVim/Reg.cpp
new file mode 100644
index 0000000..b4378e5
--- /dev/null
+++ b/src/VisVim/Reg.cpp
@@ -0,0 +1,56 @@
+#include "stdafx.h"
+
+// Returns key for HKEY_CURRENT_USER\"Software"\Company\AppName
+// creating it if it doesn't exist
+// responsibility of the caller to call RegCloseKey() on the returned HKEY
+//
+HKEY GetAppKey (char* AppName)
+{
+ HKEY hAppKey = NULL;
+ HKEY hSoftKey = NULL;
+ if (RegOpenKeyEx (HKEY_CURRENT_USER, "Software", 0, KEY_WRITE | KEY_READ,
+ &hSoftKey) == ERROR_SUCCESS)
+ {
+ DWORD Dummy;
+ RegCreateKeyEx (hSoftKey, AppName, 0, REG_NONE,
+ REG_OPTION_NON_VOLATILE, KEY_WRITE | KEY_READ, NULL,
+ &hAppKey, &Dummy);
+ }
+ if (hSoftKey)
+ RegCloseKey (hSoftKey);
+
+ return hAppKey;
+}
+
+// Returns key for
+// HKEY_CURRENT_USER\"Software"\RegistryKey\AppName\Section
+// creating it if it doesn't exist.
+// responsibility of the caller to call RegCloseKey () on the returned HKEY
+//
+HKEY GetSectionKey (HKEY hAppKey, LPCTSTR Section)
+{
+ HKEY hSectionKey = NULL;
+ DWORD Dummy;
+ RegCreateKeyEx (hAppKey, Section, 0, REG_NONE,
+ REG_OPTION_NON_VOLATILE, KEY_WRITE|KEY_READ, NULL,
+ &hSectionKey, &Dummy);
+ return hSectionKey;
+}
+
+int GetRegistryInt (HKEY hSectionKey, LPCTSTR Entry, int Default)
+{
+ DWORD Value;
+ DWORD Type;
+ DWORD Count = sizeof (DWORD);
+ if (RegQueryValueEx (hSectionKey, (LPTSTR) Entry, NULL, &Type,
+ (LPBYTE) &Value, &Count) == ERROR_SUCCESS)
+ return Value;
+ return Default;
+}
+
+bool WriteRegistryInt (HKEY hSectionKey, char* Entry, int nValue)
+{
+ return RegSetValueEx (hSectionKey, Entry, NULL, REG_DWORD,
+ (LPBYTE) &nValue, sizeof (nValue)) == ERROR_SUCCESS;
+}
+
diff --git a/src/VisVim/Register.bat b/src/VisVim/Register.bat
new file mode 100644
index 0000000..baef50b
--- /dev/null
+++ b/src/VisVim/Register.bat
@@ -0,0 +1 @@
+regsvr32.exe visvim.dll
diff --git a/src/VisVim/Res/ToolbarL.bmp b/src/VisVim/Res/ToolbarL.bmp
new file mode 100644
index 0000000..e11c66f
--- /dev/null
+++ b/src/VisVim/Res/ToolbarL.bmp
Binary files differ
diff --git a/src/VisVim/Res/ToolbarM.bmp b/src/VisVim/Res/ToolbarM.bmp
new file mode 100644
index 0000000..22e15f4
--- /dev/null
+++ b/src/VisVim/Res/ToolbarM.bmp
Binary files differ
diff --git a/src/VisVim/Resource.h b/src/VisVim/Resource.h
new file mode 100644
index 0000000..1070091
--- /dev/null
+++ b/src/VisVim/Resource.h
@@ -0,0 +1,30 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by VisVim.rc
+//
+#define IDS_VISVIM_LONGNAME 1
+#define IDS_VISVIM_DESCRIPTION 2
+#define IDS_CMD_DIALOG 3
+#define IDS_CMD_ENABLE 4
+#define IDS_CMD_DISABLE 5
+#define IDS_CMD_TOGGLE 6
+#define IDS_CMD_LOAD 7
+#define IDR_TOOLBAR_MEDIUM 128
+#define IDR_TOOLBAR_LARGE 129
+#define IDD_ADDINMAIN 130
+#define IDC_DEVSTUDIO_EDITOR 1000
+#define IDC_CD_SOURCE_PATH 1001
+#define IDC_CD_SOURCE_PARENT 1002
+#define IDC_CD_NONE 1003
+#define IDC_NEW_TABS 1004
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 131
+#define _APS_NEXT_COMMAND_VALUE 32771
+#define _APS_NEXT_CONTROL_VALUE 1004
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/src/VisVim/StdAfx.cpp b/src/VisVim/StdAfx.cpp
new file mode 100644
index 0000000..f4f6eb5
--- /dev/null
+++ b/src/VisVim/StdAfx.cpp
@@ -0,0 +1,6 @@
+// Stdafx.cpp : source file that includes just the standard includes
+// VisEmacs.pch will be the pre-compiled header
+// stdafx.obj will contain the pre-compiled type information
+
+#include "stdafx.h"
+#include "atlimpl.cpp"
diff --git a/src/VisVim/StdAfx.h b/src/VisVim/StdAfx.h
new file mode 100644
index 0000000..10bfdc0
--- /dev/null
+++ b/src/VisVim/StdAfx.h
@@ -0,0 +1,73 @@
+// Stdafx.h : include file for standard system include files,
+// or project specific include files that are used frequently, but
+// are changed infrequently
+//
+
+#if !defined(AFX_STDAFX_H__AC72670E_2977_11D1_B2F3_006008040780__INCLUDED_)
+#define AFX_STDAFX_H__AC72670E_2977_11D1_B2F3_006008040780__INCLUDED_
+
+#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers
+
+#include <afxwin.h> // MFC core and standard components
+#include <afxdisp.h>
+
+#include <atlbase.h>
+//You may derive a class from CComModule and use it if you want to override
+//something, but do not change the name of _Module
+extern CComModule _Module;
+
+#include <atlcom.h>
+
+// Developer Studio Object Model
+#include <ObjModel\addauto.h>
+#include <ObjModel\appdefs.h>
+#include <ObjModel\appauto.h>
+#include <ObjModel\blddefs.h>
+#include <ObjModel\bldauto.h>
+#include <ObjModel\textdefs.h>
+#include <ObjModel\textauto.h>
+#include <ObjModel\dbgdefs.h>
+#include <ObjModel\dbgauto.h>
+
+/////////////////////////////////////////////////////////////////////////////
+// Debugging support
+
+// Use VERIFY_OK around all calls to the Developer Studio objects which
+// you expect to return S_OK.
+// In DEBUG builds of your add-in, VERIFY_OK displays an ASSERT dialog box
+// if the expression returns an HRESULT other than S_OK. If the HRESULT
+// is a success code, the ASSERT box will display that HRESULT. If it
+// is a failure code, the ASSERT box will display that HRESULT plus the
+// error description string provided by the object which raised the error.
+// In RETAIL builds of your add-in, VERIFY_OK just evaluates the expression
+// and ignores the returned HRESULT.
+
+#ifdef _DEBUG
+
+void GetLastErrorDescription (CComBSTR & bstr); // Defined in VisVim.cpp
+#define VERIFY_OK(f) \
+ { \
+ HRESULT hr = (f); \
+ if (hr != S_OK) \
+ { \
+ if (FAILED(hr)) \
+ { \
+ CComBSTR bstr; \
+ GetLastErrorDescription(bstr); \
+ _RPTF2(_CRT_ASSERT, "Object call returned %lx\n\n%S", hr, (BSTR) bstr); \
+ } \
+ else \
+ _RPTF1(_CRT_ASSERT, "Object call returned %lx", hr); \
+ } \
+ }
+
+#else //_DEBUG
+
+#define VERIFY_OK(f) (f);
+
+#endif //_DEBUG
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_STDAFX_H__AC72670E_2977_11D1_B2F3_006008040780__INCLUDED)
diff --git a/src/VisVim/UnRegist.bat b/src/VisVim/UnRegist.bat
new file mode 100644
index 0000000..9ea105d
--- /dev/null
+++ b/src/VisVim/UnRegist.bat
@@ -0,0 +1 @@
+regsvr32.exe -unregister visvim.dll
diff --git a/src/VisVim/VisVim.cpp b/src/VisVim/VisVim.cpp
new file mode 100644
index 0000000..222925a
--- /dev/null
+++ b/src/VisVim/VisVim.cpp
@@ -0,0 +1,152 @@
+// VisVim.cpp : Defines the initialization routines for the DLL.
+//
+
+#include "stdafx.h"
+#include <initguid.h>
+#include "VisVim.h"
+#include "DSAddIn.h"
+#include "Commands.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+
+#endif
+
+CComModule _Module;
+
+BEGIN_OBJECT_MAP (ObjectMap)
+OBJECT_ENTRY (CLSID_DSAddIn, CDSAddIn)
+END_OBJECT_MAP ()
+
+class CVisVimApp : public CWinApp
+{
+ public:
+ CVisVimApp ();
+
+ //{{AFX_VIRTUAL(CVisVimApp)
+ public:
+ virtual BOOL InitInstance ();
+ virtual int ExitInstance ();
+ //}}AFX_VIRTUAL
+
+ //{{AFX_MSG(CVisVimApp)
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP ()
+};
+
+BEGIN_MESSAGE_MAP (CVisVimApp, CWinApp)
+//{{AFX_MSG_MAP(CVisVimApp)
+//}}AFX_MSG_MAP
+END_MESSAGE_MAP ()
+
+// The one and only CVisVimApp object
+CVisVimApp theApp;
+
+CVisVimApp::CVisVimApp ()
+{
+}
+
+BOOL CVisVimApp::InitInstance ()
+{
+ _Module.Init (ObjectMap, m_hInstance);
+ return CWinApp::InitInstance ();
+}
+
+int CVisVimApp::ExitInstance ()
+{
+ _Module.Term ();
+ return CWinApp::ExitInstance ();
+}
+
+// Special entry points required for inproc servers
+//
+
+STDAPI DllGetClassObject (REFCLSID rclsid, REFIID riid, LPVOID * ppv)
+{
+ AFX_MANAGE_STATE (AfxGetStaticModuleState ());
+ return _Module.GetClassObject (rclsid, riid, ppv);
+}
+
+STDAPI DllCanUnloadNow (void)
+{
+ AFX_MANAGE_STATE (AfxGetStaticModuleState ());
+ return (AfxDllCanUnloadNow () == S_OK && _Module.GetLockCount () == 0)
+ ? S_OK : S_FALSE;
+}
+
+// By exporting DllRegisterServer, you can use regsvr32.exe
+//
+STDAPI DllRegisterServer (void)
+{
+ AFX_MANAGE_STATE (AfxGetStaticModuleState ());
+ HRESULT hRes;
+
+ // Registers object, typelib and all interfaces in typelib
+ hRes = _Module.RegisterServer (TRUE);
+ if (FAILED (hRes))
+ // Hack: When this fails we might be a normal user, while the
+ // admin already registered the module. Returning S_OK then
+ // makes it work. When the module was never registered it
+ // will soon fail in another way.
+ // old code: return hRes;
+ return S_OK;
+
+ _ATL_OBJMAP_ENTRY *pEntry = _Module.m_pObjMap;
+ CRegKey key;
+ LONG lRes = key.Open (HKEY_CLASSES_ROOT, _T ("CLSID"));
+
+ if (lRes == ERROR_SUCCESS)
+ {
+ USES_CONVERSION;
+ LPOLESTR lpOleStr;
+
+ StringFromCLSID (*pEntry->pclsid, &lpOleStr);
+ LPTSTR lpsz = OLE2T (lpOleStr);
+
+ lRes = key.Open (key, lpsz);
+ if (lRes == ERROR_SUCCESS)
+ {
+ CString strDescription;
+
+ strDescription.LoadString (IDS_VISVIM_DESCRIPTION);
+ key.SetKeyValue (_T ("Description"), strDescription);
+ }
+ CoTaskMemFree (lpOleStr);
+ }
+
+ if (lRes != ERROR_SUCCESS)
+ hRes = HRESULT_FROM_WIN32 (lRes);
+
+ return hRes;
+
+}
+
+// DllUnregisterServer - Removes entries from the system registry
+//
+STDAPI DllUnregisterServer (void)
+{
+ AFX_MANAGE_STATE (AfxGetStaticModuleState ());
+
+ HRESULT hRes = S_OK;
+ _Module.UnregisterServer ();
+ return hRes;
+}
+
+
+// Debugging support
+
+// GetLastErrorDescription is used in the implementation of the VERIFY_OK
+// macro, defined in stdafx.h.
+
+#ifdef _DEBUG
+
+void GetLastErrorDescription (CComBSTR & bstr)
+{
+ CComPtr < IErrorInfo > pErrorInfo;
+ if (GetErrorInfo (0, &pErrorInfo) == S_OK)
+ pErrorInfo->GetDescription (&bstr);
+}
+
+#endif //_DEBUG
diff --git a/src/VisVim/VisVim.def b/src/VisVim/VisVim.def
new file mode 100644
index 0000000..023d478
--- /dev/null
+++ b/src/VisVim/VisVim.def
@@ -0,0 +1,11 @@
+; VisVim.def : Declares the module parameters for the DLL.
+
+LIBRARY "VISVIM"
+DESCRIPTION 'VISVIM Windows Dynamic Link Library'
+
+EXPORTS
+ ; Explicit exports can go here
+ DllCanUnloadNow PRIVATE
+ DllGetClassObject PRIVATE
+ DllRegisterServer PRIVATE
+ DllUnregisterServer PRIVATE
diff --git a/src/VisVim/VisVim.dll b/src/VisVim/VisVim.dll
new file mode 100644
index 0000000..017b417
--- /dev/null
+++ b/src/VisVim/VisVim.dll
Binary files differ
diff --git a/src/VisVim/VisVim.h b/src/VisVim/VisVim.h
new file mode 100644
index 0000000..7759778
--- /dev/null
+++ b/src/VisVim/VisVim.h
@@ -0,0 +1,33 @@
+// VisVIM.h : main header file for the VisVim DLL
+//
+
+#if !defined(AFX_VISVIM_H__AC72670B_2977_11D1_B2F3_006008040780__INCLUDED_)
+#define AFX_VISVIM_H__AC72670B_2977_11D1_B2F3_006008040780__INCLUDED_
+
+#ifndef __AFXWIN_H__
+#error include 'stdafx.h' before including this file for PCH
+#endif
+
+#include "resource.h" // Main symbols
+
+#include <ObjModel\addguid.h>
+#include <ObjModel\appguid.h>
+#include <ObjModel\bldguid.h>
+#include <ObjModel\textguid.h>
+#include <ObjModel\dbgguid.h>
+
+//
+// Prototypes
+//
+
+HKEY GetAppKey (char* AppName);
+HKEY GetSectionKey (HKEY hAppKey, LPCTSTR Section);
+int GetRegistryInt (HKEY hSectionKey, LPCTSTR Entry, int Default);
+bool WriteRegistryInt (HKEY hSectionKey, char* Entry, int nValue);
+void ReportLastError (HRESULT Err);
+void ReportInternalError (char* Fct);
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_VISVIM_H__AC72670B_2977_11D1_B2F3_006008040780__INCLUDED)
diff --git a/src/VisVim/VisVim.mak b/src/VisVim/VisVim.mak
new file mode 100644
index 0000000..30a9cf4
--- /dev/null
+++ b/src/VisVim/VisVim.mak
@@ -0,0 +1,205 @@
+# Microsoft Developer Studio Generated NMAKE File, Format Version 4.00
+# ** DO NOT EDIT **
+#
+# When Who What
+# 1999-08-01 Anon Original VisVim.dsp
+# 2001-08-08 W.Briscoe Back-ported to a condensed VC4 Makefile
+# Reduced inter-dependency of Release and Debug builds.
+#
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+!IF "$(CFG)" == ""
+CFG=VisVim - Win32 Release
+!MESSAGE No configuration specified. Defaulting to VisVim - Win32 Release.
+!ENDIF
+
+!IF "$(CFG)" != "VisVim - Win32 Release" && "$(CFG)" != "VisVim - Win32 Debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE on this makefile
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "VisVim.mak" CFG="VisVim - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "VisVim - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "VisVim - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+DEL_TREE = rmdir /s /q
+!ELSE
+NULL=nul
+DEL_TREE = deltree /y
+!ENDIF
+# Begin Project
+# PROP Target_Last_Scanned "VisVim - Win32 Release"
+# PROP Use_MFC 2
+CPP=cl.exe
+RSC=rc.exe
+LINK32=link.exe
+
+!IF "$(CFG)" == "VisVim - Win32 Release"
+
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir ".\Release"
+# PROP Intermediate_Dir ".\Release"
+# PROP Target_Dir ""
+OUTDIR=.\Release
+INTDIR=.\Release
+CPP_OBJS=.\Release/
+
+# ADD CPP /MD /O2 /D "NDEBUG" /I.\Release
+CPP_PROJ= /MD /O2 /D "NDEBUG" /I.\Release
+# ADD RSC /d "NDEBUG
+RSC_PROJ= /d "NDEBUG"
+# ADD LINK32 /pdb:none
+LINK32_FLAGS=/pdb:none
+
+!ELSEIF "$(CFG)" == "VisVim - Win32 Debug"
+
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir ".\Debug"
+# PROP Intermediate_Dir ".\Debug"
+# PROP Target_Dir ""
+OUTDIR=.\Debug
+INTDIR=.\Debug
+CPP_OBJS=.\Debug/
+
+# ADD CPP /MDd /Gm /Zi /Od /D "_DEBUG" /I.\Debug
+CPP_PROJ= /MDd /Gm /Zi /Od /D "_DEBUG" /I.\Debug /Fd"$(INTDIR)/"
+MTL_PROJ= /D "_DEBUG"
+# ADD RSC /d "_DEBUG
+RSC_PROJ= /d "_DEBUG"
+# ADD LINK32 /debug /pdbtype:sept /pdb:".\Debug/VisVim.pdb"
+LINK32_FLAGS=/debug /pdbtype:sept /pdb:"$(OUTDIR)/VisVim.pdb"
+
+!ENDIF
+
+# ADD CPP /nologo /W3 /GX /D "WIN32" /D "_WINDOWS" /D "_WINDLL" /D "_AFXDLL" /D "_USRDLL" /c
+CPP_PROJ=$(CPP_PROJ) /nologo /W3 /GX /D "WIN32" /D "_WINDOWS" /D "_WINDLL" /D "_AFXDLL" /D "_USRDLL" /c /Fo"$(INTDIR)/"
+# ADD RSC /l 0x409 /d "_AFXDLL"
+RSC_PROJ=$(RSC_PROJ) /l 0x409 /d "_AFXDLL" /fo"$(INTDIR)/VisVim.res"
+# ADD LINK32 /nologo /subsystem:windows /dll /machine:I386 /incremental:no
+LINK32_FLAGS=$(LINK32_FLAGS) /nologo /subsystem:windows /dll /machine:I386\
+ /incremental:no /def:".\VisVim.def"\
+ /out:"$(OUTDIR)/VisVim.dll" /implib:"$(OUTDIR)/VisVim.lib"
+
+ALL : "$(OUTDIR)\VisVim.dll"
+
+CLEAN :
+ -@if exist "$(INTDIR)/$(NULL)" $(DEL_TREE) "$(INTDIR)"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+LINK32_OBJS= \
+ "$(INTDIR)/VisVim.res" \
+ "$(INTDIR)/VisVim.obj" \
+ "$(INTDIR)/StdAfx.obj" \
+ "$(INTDIR)/Reg.obj" \
+ "$(INTDIR)/DSAddIn.obj" \
+ "$(INTDIR)/OleAut.obj" \
+ "$(INTDIR)/Commands.obj"
+
+"$(OUTDIR)\VisVim.dll" : "$(OUTDIR)" ".\VisVim.def" $(LINK32_OBJS)
+ $(LINK32) $(LINK32_FLAGS) $(LINK32_OBJS)
+
+{.}.c{$(CPP_OBJS)}.obj:
+ $(CPP) $(CPP_PROJ) $<
+
+{.}.cpp{$(CPP_OBJS)}.obj:
+ $(CPP) $(CPP_PROJ) $<
+
+# Begin Target
+
+# Name "VisVim - Win32 Release"
+# Name "VisVim - Win32 Debug"
+
+# Begin Source File
+
+SOURCE=.\VisVim.cpp
+
+"$(INTDIR)\VisVim.obj" : $(SOURCE) "$(INTDIR)"
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\VisVim.def
+# End Source File
+# Begin Source File
+
+SOURCE=.\VisVim.odl
+
+!IF "$(CFG)" == "VisVim - Win32 Release"
+
+# PROP Ignore_Default_Tool 1
+# Begin Custom Build
+
+"$(INTDIR)\VisVim.tlb" : $(SOURCE) "$(INTDIR)"
+ midl /nologo /mktyplib203 /win32 /tlb VisVim.tlb /h VSVTypes.h .\VisVim.odl /out .\Release /D "NDEBUG"
+
+# End Custom Build
+
+!ELSEIF "$(CFG)" == "VisVim - Win32 Debug"
+
+# PROP Ignore_Default_Tool 1
+# Begin Custom Build
+
+"$(INTDIR)\VisVim.tlb" : $(SOURCE) "$(INTDIR)"
+ midl /nologo /mktyplib203 /win32 /tlb VisVim.tlb /h VSVTypes.h .\VisVim.odl /out .\Debug /D "_DEBUG"
+
+# End Custom Build
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\StdAfx.cpp
+
+"$(INTDIR)\StdAfx.obj" : $(SOURCE) "$(INTDIR)"
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\VisVim.rc
+
+"$(INTDIR)\VisVim.res" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\VisVim.tlb"
+ $(RSC) $(RSC_PROJ) /i "$(INTDIR)" $(SOURCE)
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\Reg.cpp
+
+"$(INTDIR)\Reg.obj" : $(SOURCE) "$(INTDIR)"
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\DSAddIn.cpp
+
+"$(INTDIR)\DSAddIn.obj" : $(SOURCE) "$(INTDIR)"
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\OleAut.cpp
+
+"$(INTDIR)\OleAut.obj" : $(SOURCE) "$(INTDIR)"
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\Commands.cpp
+
+"$(INTDIR)\Commands.obj" : $(SOURCE) "$(INTDIR)"
+
+# End Source File
+# End Target
+# End Project
diff --git a/src/VisVim/VisVim.odl b/src/VisVim/VisVim.odl
new file mode 100644
index 0000000..0491b8f
--- /dev/null
+++ b/src/VisVim/VisVim.odl
@@ -0,0 +1,61 @@
+// VisVim.odl : type library source for VisVim.dll
+
+// This file will be processed by the Make Type Library (mktyplib) tool to
+// produce the type library (VisVim.tlb).
+
+[ uuid(AC726707-2977-11D1-B2F3-006008040780), version(1.0),
+ helpstring ("VisVim Developer Studio Add-in") ]
+library VisVim
+{
+ importlib("stdole32.tlb");
+ importlib("devshl.dll");
+ importlib("ide\devdbg.pkg");
+
+
+ // Dual interface for CCommands
+ //
+ // All commands that your add-in adds to DevStudio
+ // must appear in this interface. You may use the
+ // ClassView to add methods to this interface, which
+ // will cause stub implementations of those methods to
+ // appear in your CCommands class.
+
+ [ uuid(AC726703-2977-11D1-B2F3-006008040780),
+ oleautomation,
+ dual
+ ]
+
+ interface ICommands : IDispatch
+ {
+ // methods
+ [id(1)]
+ HRESULT VisVimDialog();
+ HRESULT VisVimEnable();
+ HRESULT VisVimDisable();
+ HRESULT VisVimToggle();
+ HRESULT VisVimLoad();
+ };
+
+ // Class information for CCommands
+
+ [ uuid(AC726704-2977-11D1-B2F3-006008040780) ]
+ coclass Commands
+ {
+ [default] interface ICommands;
+ };
+
+ [ hidden, uuid(AC726705-2977-11D1-B2F3-006008040780) ]
+ coclass ApplicationEvents
+ {
+ [default] interface IApplicationEvents;
+ }
+
+ [ hidden, uuid(AC726706-2977-11D1-B2F3-006008040780) ]
+ coclass DebuggerEvents
+ {
+ [default] interface IDebuggerEvents;
+ }
+
+ //{{AFX_APPEND_ODL}}
+ //}}AFX_APPEND_ODL}}
+};
diff --git a/src/VisVim/VisVim.rc b/src/VisVim/VisVim.rc
new file mode 100644
index 0000000..cf74b29
--- /dev/null
+++ b/src/VisVim/VisVim.rc
@@ -0,0 +1,202 @@
+//Microsoft Developer Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// Englisch (USA) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#define _AFX_NO_SPLITTER_RESOURCES\r\n"
+ "#define _AFX_NO_OLE_RESOURCES\r\n"
+ "#define _AFX_NO_TRACKER_RESOURCES\r\n"
+ "#define _AFX_NO_PROPERTY_RESOURCES\r\n"
+ "\r\n"
+ "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n"
+ "#ifdef _WIN32\r\n"
+ "LANGUAGE 9, 1\r\n"
+ "#pragma code_page(1252)\r\n"
+ "#endif\r\n"
+ "#include ""afxres.rc"" // Standard components\r\n"
+ "#endif\r\n"
+ "1 TYPELIB ""VisVim.tlb""\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Bitmap
+//
+
+IDR_TOOLBAR_MEDIUM BITMAP MOVEABLE PURE "res\\ToolbarM.bmp"
+IDR_TOOLBAR_LARGE BITMAP MOVEABLE PURE "res\\ToolbarL.bmp"
+
+#ifndef _MAC
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,1,0,1
+ PRODUCTVERSION 1,1,0,1
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "CompanyName", "\0"
+ VALUE "FileDescription", "VisVim DLL\0"
+ VALUE "FileVersion", "1, 1, 0, 1\0"
+ VALUE "InternalName", "VisVim\0"
+ VALUE "LegalCopyright", "Copyright (C) 1998\0"
+ VALUE "OriginalFilename", "VisVim.DLL\0"
+ VALUE "ProductName", "VisVim Dynamic Link Library\0"
+ VALUE "ProductVersion", "1, 1, 0, 1\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
+
+#endif // !_MAC
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_ADDINMAIN DIALOG DISCARDABLE 0, 0, 178, 124
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Vim Add-In 1.4"
+FONT 8, "MS Sans Serif"
+BEGIN
+ CONTROL "&Open file in DevStudio editor simultaneously",
+ IDC_DEVSTUDIO_EDITOR,"Button",BS_AUTOCHECKBOX | WS_GROUP |
+ WS_TABSTOP,7,7,153,10
+ CONTROL "Open files in new tabs",
+ IDC_NEW_TABS,"Button",BS_AUTOCHECKBOX | WS_GROUP |
+ WS_TABSTOP,7,21,153,10
+ GROUPBOX "Current directory",IDC_STATIC,7,35,164,58,WS_GROUP
+ CONTROL "Set to &source file path",IDC_CD_SOURCE_PATH,"Button",
+ BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,17,49,85,10
+ CONTROL "Set to &parent directory of source file path",
+ IDC_CD_SOURCE_PARENT,"Button",BS_AUTORADIOBUTTON,17,63,
+ 143,10
+ CONTROL "Do &not change",IDC_CD_NONE,"Button",BS_AUTORADIOBUTTON,
+ 17,78,63,10
+ DEFPUSHBUTTON "&Ok",IDOK,7,102,74,14,WS_GROUP
+ PUSHBUTTON "&Cancel",IDCANCEL,97,102,74,14,WS_GROUP
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO DISCARDABLE
+BEGIN
+ IDD_ADDINMAIN, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 171
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 117
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ IDS_VISVIM_LONGNAME "Vim Developer Studio Add-In"
+ IDS_VISVIM_DESCRIPTION "Allows integration of Vim as the text editor in Developer Studio."
+ IDS_CMD_DIALOG "\nVim Add-In Dialog\nDisplays the options dialog box of the Vim Add-In\nVim Add-In Dialog"
+ IDS_CMD_ENABLE "\nEnable Vim Add-In\nEnables Vim as Visual Studio editor\nEnable Vim Add-In"
+ IDS_CMD_DISABLE "\nDisable Vim Add-In\nDisables Vim as Visual Studio editor\nDisable Vim Add-In"
+ IDS_CMD_TOGGLE "\nToggle Vim Add-In State\nToggles the enable state of the Vim Add-In\nToggle Vim Add-In State"
+ IDS_CMD_LOAD "\nVim Add-In Load Document\nLoads the current document in Vim\nVim Add-In Load Document"
+END
+
+#endif // Englisch (USA) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+#define _AFX_NO_SPLITTER_RESOURCES
+#define _AFX_NO_OLE_RESOURCES
+#define _AFX_NO_TRACKER_RESOURCES
+#define _AFX_NO_PROPERTY_RESOURCES
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE 9, 1
+#pragma code_page(1252)
+#endif
+#include "afxres.rc" // Standard components
+#endif
+1 TYPELIB "VisVim.tlb"
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/src/VisVim/VsReadMe.txt b/src/VisVim/VsReadMe.txt
new file mode 100644
index 0000000..f480c6b
--- /dev/null
+++ b/src/VisVim/VsReadMe.txt
@@ -0,0 +1,91 @@
+========================================================================
+ DEVELOPER STUDIO ADD-IN : VisVim
+========================================================================
+
+
+The Add-in Wizard has created this VisVim DLL for you. This DLL not only
+demonstrates the basics of creating a Developer Studio add-in, but it is also
+a starting point for writing your own add-in.
+
+An add-in mainly does two things.
+ (1) It adds commands to Developer Studio, which can then be tied
+ to keystrokes or toolbar buttons by the user or programmatically
+ by the add-in.
+ (2) It responds to events fired by Developer Studio.
+In both cases, the add-in code has access to the full Developer Studio
+Automation Object Model, and may manipulate those objects to affect the
+behavior of Developer Studio.
+
+This file contains a summary of what you will find in each of the files that
+make up your VisVim DLL.
+
+
+VisVim.h
+ This is the main header file for the DLL. It declares the
+ CVisVimApp class.
+
+VisVim.cpp
+ This is the main DLL source file. It contains the class CVisVimApp.
+ It also contains the OLE entry points required of inproc servers.
+
+VisVim.odl
+ This file contains the Object Description Language source code for the
+ type library of your DLL.
+
+VisVim.rc
+ This is a listing of all of the Microsoft Windows resources that the
+ program uses. It includes the sample toolbar bitmap that is stored
+ in the RES subdirectory. This file can be directly edited in Microsoft
+ Developer Studio.
+
+res\VisVim.rc2
+ This file contains resources that are not edited by Microsoft
+ Developer Studio. You should place all resources not
+ editable by the resource editor in this file.
+
+VisVim.def
+ This file contains information about the DLL that must be
+ provided to run with Microsoft Windows. It defines parameters
+ such as the name and description of the DLL. It also exports
+ functions from the DLL.
+
+VisVim.clw
+ This file contains information used by ClassWizard to edit existing
+ classes or add new classes. ClassWizard also uses this file to store
+ information needed to create and edit message maps and dialog data
+ maps and to create prototype member functions.
+
+/////////////////////////////////////////////////////////////////////////////
+Add-in-specific files:
+
+DSAddIn.cpp, DSAddIn.h
+ These files contain the CDSAddIn class, which implements the
+ IDSAddIn interface. This interface contains handlers
+ for connecting and disconnecting the add-in.
+
+Commands.cpp, Commands.h
+ These files contain the CCommands class, which implements your
+ command dispatch interface. This interface contains one method
+ for each command you add to Developer Studio.
+ These files also contain stub implementations of handlers for all events
+ fired by the Developer Studio Application object.
+
+OleAut.cpp
+ These files contain a general OLE automation class used to communicate
+ with vim.
+
+Reg.cpp
+ These files contain functions to access the registry.
+
+
+/////////////////////////////////////////////////////////////////////////////
+Other standard files:
+
+StdAfx.h, StdAfx.cpp
+ These files are used to build a precompiled header (PCH) file
+ named VisVim.pch and a precompiled types file named StdAfx.obj.
+
+Resource.h
+ This is the standard header file, which defines new resource IDs.
+ Microsoft Developer Studio reads and updates this file.
+
diff --git a/src/alloc.h b/src/alloc.h
new file mode 100644
index 0000000..8babde3
--- /dev/null
+++ b/src/alloc.h
@@ -0,0 +1,33 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * Do ":help uganda" in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ */
+
+/*
+ * alloc.h: enumeration of alloc IDs.
+ * Each entry must be on exactly one line, GetAllocId() depends on that.
+ */
+typedef enum {
+ aid_none = 0,
+ aid_qf_dirname_start,
+ aid_qf_dirname_now,
+ aid_qf_namebuf,
+ aid_qf_module,
+ aid_qf_errmsg,
+ aid_qf_pattern,
+ aid_tagstack_items,
+ aid_tagstack_from,
+ aid_tagstack_details,
+ aid_sign_getdefined,
+ aid_sign_getplaced,
+ aid_sign_define_by_name,
+ aid_sign_getlist,
+ aid_sign_getplaced_dict,
+ aid_sign_getplaced_list,
+ aid_insert_sign,
+ aid_sign_getinfo,
+ aid_last
+} alloc_id_T;
diff --git a/src/arabic.c b/src/arabic.c
new file mode 100644
index 0000000..6c15221
--- /dev/null
+++ b/src/arabic.c
@@ -0,0 +1,715 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * arabic.c: functions for Arabic language
+ *
+ * Author: Nadim Shaikli & Isam Bayazidi
+ */
+
+#include "vim.h"
+
+#if defined(FEAT_ARABIC) || defined(PROTO)
+
+static int A_firstc_laa(int c1, int c);
+static int A_is_harakat(int c);
+static int A_is_iso(int c);
+static int A_is_formb(int c);
+static int A_is_ok(int c);
+static int A_is_valid(int c);
+static int A_is_special(int c);
+
+
+/*
+ * Returns True if c is an ISO-8859-6 shaped ARABIC letter (user entered)
+ */
+ static int
+A_is_a(int cur_c)
+{
+ switch (cur_c)
+ {
+ case a_HAMZA:
+ case a_ALEF_MADDA:
+ case a_ALEF_HAMZA_ABOVE:
+ case a_WAW_HAMZA:
+ case a_ALEF_HAMZA_BELOW:
+ case a_YEH_HAMZA:
+ case a_ALEF:
+ case a_BEH:
+ case a_TEH_MARBUTA:
+ case a_TEH:
+ case a_THEH:
+ case a_JEEM:
+ case a_HAH:
+ case a_KHAH:
+ case a_DAL:
+ case a_THAL:
+ case a_REH:
+ case a_ZAIN:
+ case a_SEEN:
+ case a_SHEEN:
+ case a_SAD:
+ case a_DAD:
+ case a_TAH:
+ case a_ZAH:
+ case a_AIN:
+ case a_GHAIN:
+ case a_TATWEEL:
+ case a_FEH:
+ case a_QAF:
+ case a_KAF:
+ case a_LAM:
+ case a_MEEM:
+ case a_NOON:
+ case a_HEH:
+ case a_WAW:
+ case a_ALEF_MAKSURA:
+ case a_YEH:
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+/*
+ * Returns True if c is an Isolated Form-B ARABIC letter
+ */
+ static int
+A_is_s(int cur_c)
+{
+ switch (cur_c)
+ {
+ case a_s_HAMZA:
+ case a_s_ALEF_MADDA:
+ case a_s_ALEF_HAMZA_ABOVE:
+ case a_s_WAW_HAMZA:
+ case a_s_ALEF_HAMZA_BELOW:
+ case a_s_YEH_HAMZA:
+ case a_s_ALEF:
+ case a_s_BEH:
+ case a_s_TEH_MARBUTA:
+ case a_s_TEH:
+ case a_s_THEH:
+ case a_s_JEEM:
+ case a_s_HAH:
+ case a_s_KHAH:
+ case a_s_DAL:
+ case a_s_THAL:
+ case a_s_REH:
+ case a_s_ZAIN:
+ case a_s_SEEN:
+ case a_s_SHEEN:
+ case a_s_SAD:
+ case a_s_DAD:
+ case a_s_TAH:
+ case a_s_ZAH:
+ case a_s_AIN:
+ case a_s_GHAIN:
+ case a_s_FEH:
+ case a_s_QAF:
+ case a_s_KAF:
+ case a_s_LAM:
+ case a_s_MEEM:
+ case a_s_NOON:
+ case a_s_HEH:
+ case a_s_WAW:
+ case a_s_ALEF_MAKSURA:
+ case a_s_YEH:
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+/*
+ * Returns True if c is a Final shape of an ARABIC letter
+ */
+ static int
+A_is_f(int cur_c)
+{
+ switch (cur_c)
+ {
+ case a_f_ALEF_MADDA:
+ case a_f_ALEF_HAMZA_ABOVE:
+ case a_f_WAW_HAMZA:
+ case a_f_ALEF_HAMZA_BELOW:
+ case a_f_YEH_HAMZA:
+ case a_f_ALEF:
+ case a_f_BEH:
+ case a_f_TEH_MARBUTA:
+ case a_f_TEH:
+ case a_f_THEH:
+ case a_f_JEEM:
+ case a_f_HAH:
+ case a_f_KHAH:
+ case a_f_DAL:
+ case a_f_THAL:
+ case a_f_REH:
+ case a_f_ZAIN:
+ case a_f_SEEN:
+ case a_f_SHEEN:
+ case a_f_SAD:
+ case a_f_DAD:
+ case a_f_TAH:
+ case a_f_ZAH:
+ case a_f_AIN:
+ case a_f_GHAIN:
+ case a_f_FEH:
+ case a_f_QAF:
+ case a_f_KAF:
+ case a_f_LAM:
+ case a_f_MEEM:
+ case a_f_NOON:
+ case a_f_HEH:
+ case a_f_WAW:
+ case a_f_ALEF_MAKSURA:
+ case a_f_YEH:
+ case a_f_LAM_ALEF_MADDA_ABOVE:
+ case a_f_LAM_ALEF_HAMZA_ABOVE:
+ case a_f_LAM_ALEF_HAMZA_BELOW:
+ case a_f_LAM_ALEF:
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+/*
+ * Change shape - from ISO-8859-6/Isolated to Form-B Isolated
+ */
+ static int
+chg_c_a2s(int cur_c)
+{
+ switch (cur_c)
+ {
+ case a_HAMZA: return a_s_HAMZA;
+ case a_ALEF_MADDA: return a_s_ALEF_MADDA;
+ case a_ALEF_HAMZA_ABOVE: return a_s_ALEF_HAMZA_ABOVE;
+ case a_WAW_HAMZA: return a_s_WAW_HAMZA;
+ case a_ALEF_HAMZA_BELOW: return a_s_ALEF_HAMZA_BELOW;
+ case a_YEH_HAMZA: return a_s_YEH_HAMZA;
+ case a_ALEF: return a_s_ALEF;
+ case a_TEH_MARBUTA: return a_s_TEH_MARBUTA;
+ case a_DAL: return a_s_DAL;
+ case a_THAL: return a_s_THAL;
+ case a_REH: return a_s_REH;
+ case a_ZAIN: return a_s_ZAIN;
+ case a_TATWEEL: return cur_c; /* exceptions */
+ case a_WAW: return a_s_WAW;
+ case a_ALEF_MAKSURA: return a_s_ALEF_MAKSURA;
+ case a_BEH: return a_s_BEH;
+ case a_TEH: return a_s_TEH;
+ case a_THEH: return a_s_THEH;
+ case a_JEEM: return a_s_JEEM;
+ case a_HAH: return a_s_HAH;
+ case a_KHAH: return a_s_KHAH;
+ case a_SEEN: return a_s_SEEN;
+ case a_SHEEN: return a_s_SHEEN;
+ case a_SAD: return a_s_SAD;
+ case a_DAD: return a_s_DAD;
+ case a_TAH: return a_s_TAH;
+ case a_ZAH: return a_s_ZAH;
+ case a_AIN: return a_s_AIN;
+ case a_GHAIN: return a_s_GHAIN;
+ case a_FEH: return a_s_FEH;
+ case a_QAF: return a_s_QAF;
+ case a_KAF: return a_s_KAF;
+ case a_LAM: return a_s_LAM;
+ case a_MEEM: return a_s_MEEM;
+ case a_NOON: return a_s_NOON;
+ case a_HEH: return a_s_HEH;
+ case a_YEH: return a_s_YEH;
+ }
+ return 0;
+}
+
+
+/*
+ * Change shape - from ISO-8859-6/Isolated to Initial
+ */
+ static int
+chg_c_a2i(int cur_c)
+{
+ switch (cur_c)
+ {
+ case a_YEH_HAMZA: return a_i_YEH_HAMZA;
+ case a_HAMZA: /* exceptions */
+ return a_s_HAMZA;
+ case a_ALEF_MADDA: /* exceptions */
+ return a_s_ALEF_MADDA;
+ case a_ALEF_HAMZA_ABOVE: /* exceptions */
+ return a_s_ALEF_HAMZA_ABOVE;
+ case a_WAW_HAMZA: /* exceptions */
+ return a_s_WAW_HAMZA;
+ case a_ALEF_HAMZA_BELOW: /* exceptions */
+ return a_s_ALEF_HAMZA_BELOW;
+ case a_ALEF: /* exceptions */
+ return a_s_ALEF;
+ case a_TEH_MARBUTA: /* exceptions */
+ return a_s_TEH_MARBUTA;
+ case a_DAL: /* exceptions */
+ return a_s_DAL;
+ case a_THAL: /* exceptions */
+ return a_s_THAL;
+ case a_REH: /* exceptions */
+ return a_s_REH;
+ case a_ZAIN: /* exceptions */
+ return a_s_ZAIN;
+ case a_TATWEEL: /* exceptions */
+ return cur_c;
+ case a_WAW: /* exceptions */
+ return a_s_WAW;
+ case a_ALEF_MAKSURA: /* exceptions */
+ return a_s_ALEF_MAKSURA;
+ case a_BEH: return a_i_BEH;
+ case a_TEH: return a_i_TEH;
+ case a_THEH: return a_i_THEH;
+ case a_JEEM: return a_i_JEEM;
+ case a_HAH: return a_i_HAH;
+ case a_KHAH: return a_i_KHAH;
+ case a_SEEN: return a_i_SEEN;
+ case a_SHEEN: return a_i_SHEEN;
+ case a_SAD: return a_i_SAD;
+ case a_DAD: return a_i_DAD;
+ case a_TAH: return a_i_TAH;
+ case a_ZAH: return a_i_ZAH;
+ case a_AIN: return a_i_AIN;
+ case a_GHAIN: return a_i_GHAIN;
+ case a_FEH: return a_i_FEH;
+ case a_QAF: return a_i_QAF;
+ case a_KAF: return a_i_KAF;
+ case a_LAM: return a_i_LAM;
+ case a_MEEM: return a_i_MEEM;
+ case a_NOON: return a_i_NOON;
+ case a_HEH: return a_i_HEH;
+ case a_YEH: return a_i_YEH;
+ }
+ return 0;
+}
+
+
+/*
+ * Change shape - from ISO-8859-6/Isolated to Medial
+ */
+ static int
+chg_c_a2m(int cur_c)
+{
+ switch (cur_c)
+ {
+ case a_HAMZA: return a_s_HAMZA; /* exception */
+ case a_ALEF_MADDA: return a_f_ALEF_MADDA; /* exception */
+ case a_ALEF_HAMZA_ABOVE: return a_f_ALEF_HAMZA_ABOVE; /* exception */
+ case a_WAW_HAMZA: return a_f_WAW_HAMZA; /* exception */
+ case a_ALEF_HAMZA_BELOW: return a_f_ALEF_HAMZA_BELOW; /* exception */
+ case a_YEH_HAMZA: return a_m_YEH_HAMZA;
+ case a_ALEF: return a_f_ALEF; /* exception */
+ case a_BEH: return a_m_BEH;
+ case a_TEH_MARBUTA: return a_f_TEH_MARBUTA; /* exception */
+ case a_TEH: return a_m_TEH;
+ case a_THEH: return a_m_THEH;
+ case a_JEEM: return a_m_JEEM;
+ case a_HAH: return a_m_HAH;
+ case a_KHAH: return a_m_KHAH;
+ case a_DAL: return a_f_DAL; /* exception */
+ case a_THAL: return a_f_THAL; /* exception */
+ case a_REH: return a_f_REH; /* exception */
+ case a_ZAIN: return a_f_ZAIN; /* exception */
+ case a_SEEN: return a_m_SEEN;
+ case a_SHEEN: return a_m_SHEEN;
+ case a_SAD: return a_m_SAD;
+ case a_DAD: return a_m_DAD;
+ case a_TAH: return a_m_TAH;
+ case a_ZAH: return a_m_ZAH;
+ case a_AIN: return a_m_AIN;
+ case a_GHAIN: return a_m_GHAIN;
+ case a_TATWEEL: return cur_c; /* exception */
+ case a_FEH: return a_m_FEH;
+ case a_QAF: return a_m_QAF;
+ case a_KAF: return a_m_KAF;
+ case a_LAM: return a_m_LAM;
+ case a_MEEM: return a_m_MEEM;
+ case a_NOON: return a_m_NOON;
+ case a_HEH: return a_m_HEH;
+ case a_WAW: return a_f_WAW; /* exception */
+ case a_ALEF_MAKSURA: return a_f_ALEF_MAKSURA; /* exception */
+ case a_YEH: return a_m_YEH;
+ }
+ return 0;
+}
+
+
+/*
+ * Change shape - from ISO-8859-6/Isolated to final
+ */
+ static int
+chg_c_a2f(int cur_c)
+{
+ /* NOTE: these encodings need to be accounted for
+ * a_f_ALEF_MADDA;
+ * a_f_ALEF_HAMZA_ABOVE;
+ * a_f_ALEF_HAMZA_BELOW;
+ * a_f_LAM_ALEF_MADDA_ABOVE;
+ * a_f_LAM_ALEF_HAMZA_ABOVE;
+ * a_f_LAM_ALEF_HAMZA_BELOW;
+ */
+ switch (cur_c)
+ {
+ case a_HAMZA: return a_s_HAMZA; /* exception */
+ case a_ALEF_MADDA: return a_f_ALEF_MADDA;
+ case a_ALEF_HAMZA_ABOVE: return a_f_ALEF_HAMZA_ABOVE;
+ case a_WAW_HAMZA: return a_f_WAW_HAMZA;
+ case a_ALEF_HAMZA_BELOW: return a_f_ALEF_HAMZA_BELOW;
+ case a_YEH_HAMZA: return a_f_YEH_HAMZA;
+ case a_ALEF: return a_f_ALEF;
+ case a_BEH: return a_f_BEH;
+ case a_TEH_MARBUTA: return a_f_TEH_MARBUTA;
+ case a_TEH: return a_f_TEH;
+ case a_THEH: return a_f_THEH;
+ case a_JEEM: return a_f_JEEM;
+ case a_HAH: return a_f_HAH;
+ case a_KHAH: return a_f_KHAH;
+ case a_DAL: return a_f_DAL;
+ case a_THAL: return a_f_THAL;
+ case a_REH: return a_f_REH;
+ case a_ZAIN: return a_f_ZAIN;
+ case a_SEEN: return a_f_SEEN;
+ case a_SHEEN: return a_f_SHEEN;
+ case a_SAD: return a_f_SAD;
+ case a_DAD: return a_f_DAD;
+ case a_TAH: return a_f_TAH;
+ case a_ZAH: return a_f_ZAH;
+ case a_AIN: return a_f_AIN;
+ case a_GHAIN: return a_f_GHAIN;
+ case a_TATWEEL: return cur_c; /* exception */
+ case a_FEH: return a_f_FEH;
+ case a_QAF: return a_f_QAF;
+ case a_KAF: return a_f_KAF;
+ case a_LAM: return a_f_LAM;
+ case a_MEEM: return a_f_MEEM;
+ case a_NOON: return a_f_NOON;
+ case a_HEH: return a_f_HEH;
+ case a_WAW: return a_f_WAW;
+ case a_ALEF_MAKSURA: return a_f_ALEF_MAKSURA;
+ case a_YEH: return a_f_YEH;
+ }
+ return 0;
+}
+
+
+/*
+ * Change shape - from Initial to Medial
+ * This code is unreachable, because for the relevant characters ARABIC_CHAR()
+ * is FALSE;
+ */
+#if 0
+ static int
+chg_c_i2m(int cur_c)
+{
+ switch (cur_c)
+ {
+ case a_i_YEH_HAMZA: return a_m_YEH_HAMZA;
+ case a_i_BEH: return a_m_BEH;
+ case a_i_TEH: return a_m_TEH;
+ case a_i_THEH: return a_m_THEH;
+ case a_i_JEEM: return a_m_JEEM;
+ case a_i_HAH: return a_m_HAH;
+ case a_i_KHAH: return a_m_KHAH;
+ case a_i_SEEN: return a_m_SEEN;
+ case a_i_SHEEN: return a_m_SHEEN;
+ case a_i_SAD: return a_m_SAD;
+ case a_i_DAD: return a_m_DAD;
+ case a_i_TAH: return a_m_TAH;
+ case a_i_ZAH: return a_m_ZAH;
+ case a_i_AIN: return a_m_AIN;
+ case a_i_GHAIN: return a_m_GHAIN;
+ case a_i_FEH: return a_m_FEH;
+ case a_i_QAF: return a_m_QAF;
+ case a_i_KAF: return a_m_KAF;
+ case a_i_LAM: return a_m_LAM;
+ case a_i_MEEM: return a_m_MEEM;
+ case a_i_NOON: return a_m_NOON;
+ case a_i_HEH: return a_m_HEH;
+ case a_i_YEH: return a_m_YEH;
+ }
+ return 0;
+}
+#endif
+
+
+/*
+ * Change shape - from Final to Medial
+ */
+ static int
+chg_c_f2m(int cur_c)
+{
+ switch (cur_c)
+ {
+ /* NOTE: these encodings are multi-positional, no ?
+ * case a_f_ALEF_MADDA:
+ * case a_f_ALEF_HAMZA_ABOVE:
+ * case a_f_ALEF_HAMZA_BELOW:
+ */
+ case a_f_YEH_HAMZA: return a_m_YEH_HAMZA;
+ case a_f_WAW_HAMZA: /* exceptions */
+ case a_f_ALEF:
+ case a_f_TEH_MARBUTA:
+ case a_f_DAL:
+ case a_f_THAL:
+ case a_f_REH:
+ case a_f_ZAIN:
+ case a_f_WAW:
+ case a_f_ALEF_MAKSURA:
+ return cur_c;
+ case a_f_BEH: return a_m_BEH;
+ case a_f_TEH: return a_m_TEH;
+ case a_f_THEH: return a_m_THEH;
+ case a_f_JEEM: return a_m_JEEM;
+ case a_f_HAH: return a_m_HAH;
+ case a_f_KHAH: return a_m_KHAH;
+ case a_f_SEEN: return a_m_SEEN;
+ case a_f_SHEEN: return a_m_SHEEN;
+ case a_f_SAD: return a_m_SAD;
+ case a_f_DAD: return a_m_DAD;
+ case a_f_TAH: return a_m_TAH;
+ case a_f_ZAH: return a_m_ZAH;
+ case a_f_AIN: return a_m_AIN;
+ case a_f_GHAIN: return a_m_GHAIN;
+ case a_f_FEH: return a_m_FEH;
+ case a_f_QAF: return a_m_QAF;
+ case a_f_KAF: return a_m_KAF;
+ case a_f_LAM: return a_m_LAM;
+ case a_f_MEEM: return a_m_MEEM;
+ case a_f_NOON: return a_m_NOON;
+ case a_f_HEH: return a_m_HEH;
+ case a_f_YEH: return a_m_YEH;
+
+ /* NOTE: these encodings are multi-positional, no ?
+ * case a_f_LAM_ALEF_MADDA_ABOVE:
+ * case a_f_LAM_ALEF_HAMZA_ABOVE:
+ * case a_f_LAM_ALEF_HAMZA_BELOW:
+ * case a_f_LAM_ALEF:
+ */
+ }
+ return 0;
+}
+
+
+/*
+ * Change shape - from Combination (2 char) to an Isolated
+ */
+ static int
+chg_c_laa2i(int hid_c)
+{
+ switch (hid_c)
+ {
+ case a_ALEF_MADDA: return a_s_LAM_ALEF_MADDA_ABOVE;
+ case a_ALEF_HAMZA_ABOVE: return a_s_LAM_ALEF_HAMZA_ABOVE;
+ case a_ALEF_HAMZA_BELOW: return a_s_LAM_ALEF_HAMZA_BELOW;
+ case a_ALEF: return a_s_LAM_ALEF;
+ }
+ return 0;
+}
+
+
+/*
+ * Change shape - from Combination-Isolated to Final
+ */
+ static int
+chg_c_laa2f(int hid_c)
+{
+ switch (hid_c)
+ {
+ case a_ALEF_MADDA: return a_f_LAM_ALEF_MADDA_ABOVE;
+ case a_ALEF_HAMZA_ABOVE: return a_f_LAM_ALEF_HAMZA_ABOVE;
+ case a_ALEF_HAMZA_BELOW: return a_f_LAM_ALEF_HAMZA_BELOW;
+ case a_ALEF: return a_f_LAM_ALEF;
+ }
+ return 0;
+}
+
+/*
+ * Do "half-shaping" on character "c". Return zero if no shaping.
+ */
+ static int
+half_shape(int c)
+{
+ if (A_is_a(c))
+ return chg_c_a2i(c);
+ if (A_is_valid(c) && A_is_f(c))
+ return chg_c_f2m(c);
+ return 0;
+}
+
+/*
+ * Do Arabic shaping on character "c". Returns the shaped character.
+ * out: "ccp" points to the first byte of the character to be shaped.
+ * in/out: "c1p" points to the first composing char for "c".
+ * in: "prev_c" is the previous character (not shaped)
+ * in: "prev_c1" is the first composing char for the previous char
+ * (not shaped)
+ * in: "next_c" is the next character (not shaped).
+ */
+ int
+arabic_shape(
+ int c,
+ int *ccp,
+ int *c1p,
+ int prev_c,
+ int prev_c1,
+ int next_c)
+{
+ int curr_c;
+ int shape_c;
+ int curr_laa;
+ int prev_laa;
+
+ /* Deal only with Arabic character, pass back all others */
+ if (!A_is_ok(c))
+ return c;
+
+ /* half-shape current and previous character */
+ shape_c = half_shape(prev_c);
+
+ /* Save away current character */
+ curr_c = c;
+
+ curr_laa = A_firstc_laa(c, *c1p);
+ prev_laa = A_firstc_laa(prev_c, prev_c1);
+
+ if (curr_laa)
+ {
+ if (A_is_valid(prev_c) && !A_is_f(shape_c)
+ && !A_is_s(shape_c) && !prev_laa)
+ curr_c = chg_c_laa2f(curr_laa);
+ else
+ curr_c = chg_c_laa2i(curr_laa);
+
+ /* Remove the composing character */
+ *c1p = 0;
+ }
+ else if (!A_is_valid(prev_c) && A_is_valid(next_c))
+ curr_c = chg_c_a2i(c);
+ else if (!shape_c || A_is_f(shape_c) || A_is_s(shape_c) || prev_laa)
+ curr_c = A_is_valid(next_c) ? chg_c_a2i(c) : chg_c_a2s(c);
+ else if (A_is_valid(next_c))
+#if 0
+ curr_c = A_is_iso(c) ? chg_c_a2m(c) : chg_c_i2m(c);
+#else
+ curr_c = A_is_iso(c) ? chg_c_a2m(c) : 0;
+#endif
+ else if (A_is_valid(prev_c))
+ curr_c = chg_c_a2f(c);
+ else
+ curr_c = chg_c_a2s(c);
+
+ /* Sanity check -- curr_c should, in the future, never be 0.
+ * We should, in the future, insert a fatal error here. */
+ if (curr_c == NUL)
+ curr_c = c;
+
+ if (curr_c != c && ccp != NULL)
+ {
+ char_u buf[MB_MAXBYTES + 1];
+
+ /* Update the first byte of the character. */
+ (*mb_char2bytes)(curr_c, buf);
+ *ccp = buf[0];
+ }
+
+ /* Return the shaped character */
+ return curr_c;
+}
+
+
+/*
+ * A_firstc_laa returns first character of LAA combination if it exists
+ */
+ static int
+A_firstc_laa(
+ int c, /* base character */
+ int c1) /* first composing character */
+{
+ if (c1 != NUL && c == a_LAM && !A_is_harakat(c1))
+ return c1;
+ return 0;
+}
+
+
+/*
+ * A_is_harakat returns TRUE if 'c' is an Arabic Harakat character
+ * (harakat/tanween)
+ */
+ static int
+A_is_harakat(int c)
+{
+ return (c >= a_FATHATAN && c <= a_SUKUN);
+}
+
+
+/*
+ * A_is_iso returns TRUE if 'c' is an Arabic ISO-8859-6 character
+ * (alphabet/number/punctuation)
+ */
+ static int
+A_is_iso(int c)
+{
+ return ((c >= a_HAMZA && c <= a_GHAIN)
+ || (c >= a_TATWEEL && c <= a_HAMZA_BELOW)
+ || c == a_MINI_ALEF);
+}
+
+
+/*
+ * A_is_formb returns TRUE if 'c' is an Arabic 10646-1 FormB character
+ * (alphabet/number/punctuation)
+ */
+ static int
+A_is_formb(int c)
+{
+ return ((c >= a_s_FATHATAN && c <= a_s_DAMMATAN)
+ || c == a_s_KASRATAN
+ || (c >= a_s_FATHA && c <= a_f_LAM_ALEF)
+ || c == a_BYTE_ORDER_MARK);
+}
+
+
+/*
+ * A_is_ok returns TRUE if 'c' is an Arabic 10646 (8859-6 or Form-B)
+ */
+ static int
+A_is_ok(int c)
+{
+ return (A_is_iso(c) || A_is_formb(c));
+}
+
+
+/*
+ * A_is_valid returns TRUE if 'c' is an Arabic 10646 (8859-6 or Form-B)
+ * with some exceptions/exclusions
+ */
+ static int
+A_is_valid(int c)
+{
+ return (A_is_ok(c) && !A_is_special(c));
+}
+
+
+/*
+ * A_is_special returns TRUE if 'c' is not a special Arabic character.
+ * Specials don't adhere to most of the rules.
+ */
+ static int
+A_is_special(int c)
+{
+ return (c == a_HAMZA || c == a_s_HAMZA);
+}
+
+#endif /* FEAT_ARABIC */
diff --git a/src/arabic.h b/src/arabic.h
new file mode 100644
index 0000000..cb5cbd1
--- /dev/null
+++ b/src/arabic.h
@@ -0,0 +1,258 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * Do ":help uganda" in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ */
+
+/*
+ * Arabic characters are categorized into following types:
+ *
+ * Isolated - iso-8859-6 form char denoted with a_*
+ * Initial - unicode form-B start char denoted with a_i_*
+ * Medial - unicode form-B middle char denoted with a_m_*
+ * Final - unicode form-B final char denoted with a_f_*
+ * Stand-Alone - unicode form-B isolated char denoted with a_s_* (NOT USED)
+ *
+ * --
+ *
+ * Author: Nadim Shaikli & Isam Bayazidi
+ * - (based on Unicode)
+ *
+ */
+
+/*
+ * Arabic ISO-10646-1 character set definition
+ */
+
+/*
+ * Arabic ISO-8859-6 (subset of 10646; 0600 - 06FF)
+ */
+#define a_COMMA 0x060C
+#define a_SEMICOLON 0x061B
+#define a_QUESTION 0x061F
+#define a_HAMZA 0x0621
+#define a_ALEF_MADDA 0x0622
+#define a_ALEF_HAMZA_ABOVE 0x0623
+#define a_WAW_HAMZA 0x0624
+#define a_ALEF_HAMZA_BELOW 0x0625
+#define a_YEH_HAMZA 0x0626
+#define a_ALEF 0x0627
+#define a_BEH 0x0628
+#define a_TEH_MARBUTA 0x0629
+#define a_TEH 0x062a
+#define a_THEH 0x062b
+#define a_JEEM 0x062c
+#define a_HAH 0x062d
+#define a_KHAH 0x062e
+#define a_DAL 0x062f
+#define a_THAL 0x0630
+#define a_REH 0x0631
+#define a_ZAIN 0x0632
+#define a_SEEN 0x0633
+#define a_SHEEN 0x0634
+#define a_SAD 0x0635
+#define a_DAD 0x0636
+#define a_TAH 0x0637
+#define a_ZAH 0x0638
+#define a_AIN 0x0639
+#define a_GHAIN 0x063a
+#define a_TATWEEL 0x0640
+#define a_FEH 0x0641
+#define a_QAF 0x0642
+#define a_KAF 0x0643
+#define a_LAM 0x0644
+#define a_MEEM 0x0645
+#define a_NOON 0x0646
+#define a_HEH 0x0647
+#define a_WAW 0x0648
+#define a_ALEF_MAKSURA 0x0649
+#define a_YEH 0x064a
+
+#define a_FATHATAN 0x064b
+#define a_DAMMATAN 0x064c
+#define a_KASRATAN 0x064d
+#define a_FATHA 0x064e
+#define a_DAMMA 0x064f
+#define a_KASRA 0x0650
+#define a_SHADDA 0x0651
+#define a_SUKUN 0x0652
+
+#define a_MADDA_ABOVE 0x0653
+#define a_HAMZA_ABOVE 0x0654
+#define a_HAMZA_BELOW 0x0655
+
+#define a_ZERO 0x0660
+#define a_ONE 0x0661
+#define a_TWO 0x0662
+#define a_THREE 0x0663
+#define a_FOUR 0x0664
+#define a_FIVE 0x0665
+#define a_SIX 0x0666
+#define a_SEVEN 0x0667
+#define a_EIGHT 0x0668
+#define a_NINE 0x0669
+#define a_PERCENT 0x066a
+#define a_DECIMAL 0x066b
+#define a_THOUSANDS 0x066c
+#define a_STAR 0x066d
+#define a_MINI_ALEF 0x0670
+/* Rest of 8859-6 does not relate to Arabic */
+
+/*
+ * Arabic Presentation Form-B (subset of 10646; FE70 - FEFF)
+ *
+ * s -> isolated
+ * i -> initial
+ * m -> medial
+ * f -> final
+ *
+ */
+#define a_s_FATHATAN 0xfe70
+#define a_m_TATWEEL_FATHATAN 0xfe71
+#define a_s_DAMMATAN 0xfe72
+
+#define a_s_KASRATAN 0xfe74
+
+#define a_s_FATHA 0xfe76
+#define a_m_FATHA 0xfe77
+#define a_s_DAMMA 0xfe78
+#define a_m_DAMMA 0xfe79
+#define a_s_KASRA 0xfe7a
+#define a_m_KASRA 0xfe7b
+#define a_s_SHADDA 0xfe7c
+#define a_m_SHADDA 0xfe7d
+#define a_s_SUKUN 0xfe7e
+#define a_m_SUKUN 0xfe7f
+
+#define a_s_HAMZA 0xfe80
+#define a_s_ALEF_MADDA 0xfe81
+#define a_f_ALEF_MADDA 0xfe82
+#define a_s_ALEF_HAMZA_ABOVE 0xfe83
+#define a_f_ALEF_HAMZA_ABOVE 0xfe84
+#define a_s_WAW_HAMZA 0xfe85
+#define a_f_WAW_HAMZA 0xfe86
+#define a_s_ALEF_HAMZA_BELOW 0xfe87
+#define a_f_ALEF_HAMZA_BELOW 0xfe88
+#define a_s_YEH_HAMZA 0xfe89
+#define a_f_YEH_HAMZA 0xfe8a
+#define a_i_YEH_HAMZA 0xfe8b
+#define a_m_YEH_HAMZA 0xfe8c
+#define a_s_ALEF 0xfe8d
+#define a_f_ALEF 0xfe8e
+#define a_s_BEH 0xfe8f
+#define a_f_BEH 0xfe90
+#define a_i_BEH 0xfe91
+#define a_m_BEH 0xfe92
+#define a_s_TEH_MARBUTA 0xfe93
+#define a_f_TEH_MARBUTA 0xfe94
+#define a_s_TEH 0xfe95
+#define a_f_TEH 0xfe96
+#define a_i_TEH 0xfe97
+#define a_m_TEH 0xfe98
+#define a_s_THEH 0xfe99
+#define a_f_THEH 0xfe9a
+#define a_i_THEH 0xfe9b
+#define a_m_THEH 0xfe9c
+#define a_s_JEEM 0xfe9d
+#define a_f_JEEM 0xfe9e
+#define a_i_JEEM 0xfe9f
+#define a_m_JEEM 0xfea0
+#define a_s_HAH 0xfea1
+#define a_f_HAH 0xfea2
+#define a_i_HAH 0xfea3
+#define a_m_HAH 0xfea4
+#define a_s_KHAH 0xfea5
+#define a_f_KHAH 0xfea6
+#define a_i_KHAH 0xfea7
+#define a_m_KHAH 0xfea8
+#define a_s_DAL 0xfea9
+#define a_f_DAL 0xfeaa
+#define a_s_THAL 0xfeab
+#define a_f_THAL 0xfeac
+#define a_s_REH 0xfead
+#define a_f_REH 0xfeae
+#define a_s_ZAIN 0xfeaf
+#define a_f_ZAIN 0xfeb0
+#define a_s_SEEN 0xfeb1
+#define a_f_SEEN 0xfeb2
+#define a_i_SEEN 0xfeb3
+#define a_m_SEEN 0xfeb4
+#define a_s_SHEEN 0xfeb5
+#define a_f_SHEEN 0xfeb6
+#define a_i_SHEEN 0xfeb7
+#define a_m_SHEEN 0xfeb8
+#define a_s_SAD 0xfeb9
+#define a_f_SAD 0xfeba
+#define a_i_SAD 0xfebb
+#define a_m_SAD 0xfebc
+#define a_s_DAD 0xfebd
+#define a_f_DAD 0xfebe
+#define a_i_DAD 0xfebf
+#define a_m_DAD 0xfec0
+#define a_s_TAH 0xfec1
+#define a_f_TAH 0xfec2
+#define a_i_TAH 0xfec3
+#define a_m_TAH 0xfec4
+#define a_s_ZAH 0xfec5
+#define a_f_ZAH 0xfec6
+#define a_i_ZAH 0xfec7
+#define a_m_ZAH 0xfec8
+#define a_s_AIN 0xfec9
+#define a_f_AIN 0xfeca
+#define a_i_AIN 0xfecb
+#define a_m_AIN 0xfecc
+#define a_s_GHAIN 0xfecd
+#define a_f_GHAIN 0xfece
+#define a_i_GHAIN 0xfecf
+#define a_m_GHAIN 0xfed0
+#define a_s_FEH 0xfed1
+#define a_f_FEH 0xfed2
+#define a_i_FEH 0xfed3
+#define a_m_FEH 0xfed4
+#define a_s_QAF 0xfed5
+#define a_f_QAF 0xfed6
+#define a_i_QAF 0xfed7
+#define a_m_QAF 0xfed8
+#define a_s_KAF 0xfed9
+#define a_f_KAF 0xfeda
+#define a_i_KAF 0xfedb
+#define a_m_KAF 0xfedc
+#define a_s_LAM 0xfedd
+#define a_f_LAM 0xfede
+#define a_i_LAM 0xfedf
+#define a_m_LAM 0xfee0
+#define a_s_MEEM 0xfee1
+#define a_f_MEEM 0xfee2
+#define a_i_MEEM 0xfee3
+#define a_m_MEEM 0xfee4
+#define a_s_NOON 0xfee5
+#define a_f_NOON 0xfee6
+#define a_i_NOON 0xfee7
+#define a_m_NOON 0xfee8
+#define a_s_HEH 0xfee9
+#define a_f_HEH 0xfeea
+#define a_i_HEH 0xfeeb
+#define a_m_HEH 0xfeec
+#define a_s_WAW 0xfeed
+#define a_f_WAW 0xfeee
+#define a_s_ALEF_MAKSURA 0xfeef
+#define a_f_ALEF_MAKSURA 0xfef0
+#define a_s_YEH 0xfef1
+#define a_f_YEH 0xfef2
+#define a_i_YEH 0xfef3
+#define a_m_YEH 0xfef4
+#define a_s_LAM_ALEF_MADDA_ABOVE 0xfef5
+#define a_f_LAM_ALEF_MADDA_ABOVE 0xfef6
+#define a_s_LAM_ALEF_HAMZA_ABOVE 0xfef7
+#define a_f_LAM_ALEF_HAMZA_ABOVE 0xfef8
+#define a_s_LAM_ALEF_HAMZA_BELOW 0xfef9
+#define a_f_LAM_ALEF_HAMZA_BELOW 0xfefa
+#define a_s_LAM_ALEF 0xfefb
+#define a_f_LAM_ALEF 0xfefc
+
+#define a_BYTE_ORDER_MARK 0xfeff
+
+/* Range of Arabic characters that might be shaped. */
+#define ARABIC_CHAR(c) ((c) >= a_HAMZA && (c) <= a_MINI_ALEF)
diff --git a/src/ascii.h b/src/ascii.h
new file mode 100644
index 0000000..769e1a0
--- /dev/null
+++ b/src/ascii.h
@@ -0,0 +1,186 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * Do ":help uganda" in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ */
+
+/*
+ * Definitions of various common control characters.
+ * For EBCDIC we have to use different values.
+ */
+
+#ifndef EBCDIC
+
+/* IF_EB(ASCII_constant, EBCDIC_constant) */
+#define IF_EB(a, b) a
+
+#define CharOrd(x) ((x) < 'a' ? (x) - 'A' : (x) - 'a')
+#define CharOrdLow(x) ((x) - 'a')
+#define CharOrdUp(x) ((x) - 'A')
+#define ROT13(c, a) (((((c) - (a)) + 13) % 26) + (a))
+
+#define NUL '\000'
+#define BELL '\007'
+#define BS '\010'
+#define TAB '\011'
+#define NL '\012'
+#define NL_STR (char_u *)"\012"
+#define FF '\014'
+#define CAR '\015' /* CR is used by Mac OS X */
+#define ESC '\033'
+#define ESC_STR (char_u *)"\033"
+#define ESC_STR_nc "\033"
+#define DEL 0x7f
+#define DEL_STR (char_u *)"\177"
+
+#define POUND 0xA3
+
+#define Ctrl_chr(x) (TOUPPER_ASC(x) ^ 0x40) /* '?' -> DEL, '@' -> ^@, etc. */
+#define Meta(x) ((x) | 0x80)
+
+#define CTRL_F_STR "\006"
+#define CTRL_H_STR "\010"
+#define CTRL_V_STR "\026"
+
+#define Ctrl_AT 0 /* @ */
+#define Ctrl_A 1
+#define Ctrl_B 2
+#define Ctrl_C 3
+#define Ctrl_D 4
+#define Ctrl_E 5
+#define Ctrl_F 6
+#define Ctrl_G 7
+#define Ctrl_H 8
+#define Ctrl_I 9
+#define Ctrl_J 10
+#define Ctrl_K 11
+#define Ctrl_L 12
+#define Ctrl_M 13
+#define Ctrl_N 14
+#define Ctrl_O 15
+#define Ctrl_P 16
+#define Ctrl_Q 17
+#define Ctrl_R 18
+#define Ctrl_S 19
+#define Ctrl_T 20
+#define Ctrl_U 21
+#define Ctrl_V 22
+#define Ctrl_W 23
+#define Ctrl_X 24
+#define Ctrl_Y 25
+#define Ctrl_Z 26
+ /* CTRL- [ Left Square Bracket == ESC*/
+#define Ctrl_BSL 28 /* \ BackSLash */
+#define Ctrl_RSB 29 /* ] Right Square Bracket */
+#define Ctrl_HAT 30 /* ^ */
+#define Ctrl__ 31
+
+#else
+
+/* EBCDIC */
+
+/* IF_EB(ASCII_constant, EBCDIC_constant) */
+#define IF_EB(a, b) b
+
+/*
+ * Finding the position in the alphabet is not straightforward in EBCDIC.
+ * There are gaps in the code table.
+ * 'a' + 1 == 'b', but: 'i' + 7 == 'j' and 'r' + 8 == 's'
+ */
+#define CharOrd__(c) ((c) < ('j' - 'a') ? (c) : ((c) < ('s' - 'a') ? (c) - 7 : (c) - 7 - 8))
+#define CharOrdLow(x) (CharOrd__((x) - 'a'))
+#define CharOrdUp(x) (CharOrd__((x) - 'A'))
+#define CharOrd(x) (isupper(x) ? CharOrdUp(x) : CharOrdLow(x))
+
+#define EBCDIC_CHAR_ADD_(x) ((x) < 0?'a':(x)>25?'z':"abcdefghijklmnopqrstuvwxyz"[x])
+#define EBCDIC_CHAR_ADD(c,s) (isupper(c) ? toupper(EBCDIC_CHAR_ADD_(CharOrdUp(c)+(s))) : EBCDIC_CHAR_ADD_(CharOrdLow(c)+(s)))
+
+#define R13_(c) ("abcdefghijklmnopqrstuvwxyz"[((c) + 13) % 26])
+#define ROT13(c, a) (isupper(c) ? toupper(R13_(CharOrdUp(c))) : R13_(CharOrdLow(c)))
+
+#define NUL '\000'
+#define BELL '\x2f'
+#define BS '\x16'
+#define TAB '\x05'
+#define NL '\x15'
+#define NL_STR (char_u *)"\x15"
+#define FF '\x0C'
+#define CAR '\x0D'
+#define ESC '\x27'
+#define ESC_STR (char_u *)"\x27"
+#define ESC_STR_nc "\x27"
+#define DEL 0x07
+#define DEL_STR (char_u *)"\007"
+
+#define POUND 0xB1
+
+#define CTRL_F_STR "\056"
+#define CTRL_H_STR "\026"
+#define CTRL_V_STR "\062"
+
+#define Ctrl_AT 0x00 /* @ */
+#define Ctrl_A 0x01
+#define Ctrl_B 0x02
+#define Ctrl_C 0x03
+#define Ctrl_D 0x37
+#define Ctrl_E 0x2D
+#define Ctrl_F 0x2E
+#define Ctrl_G 0x2F
+#define Ctrl_H 0x16
+#define Ctrl_I 0x05
+#define Ctrl_J 0x15
+#define Ctrl_K 0x0B
+#define Ctrl_L 0x0C
+#define Ctrl_M 0x0D
+#define Ctrl_N 0x0E
+#define Ctrl_O 0x0F
+#define Ctrl_P 0x10
+#define Ctrl_Q 0x11
+#define Ctrl_R 0x12
+#define Ctrl_S 0x13
+#define Ctrl_T 0x3C
+#define Ctrl_U 0x3D
+#define Ctrl_V 0x32
+#define Ctrl_W 0x26
+#define Ctrl_X 0x18
+#define Ctrl_Y 0x19
+#define Ctrl_Z 0x3F
+ /* CTRL- [ Left Square Bracket == ESC*/
+#define Ctrl_RSB 0x1D /* ] Right Square Bracket */
+#define Ctrl_BSL 0x1C /* \ BackSLash */
+#define Ctrl_HAT 0x1E /* ^ */
+#define Ctrl__ 0x1F
+
+#define Ctrl_chr(x) (CtrlTable[(x)])
+extern char CtrlTable[];
+
+#define CtrlChar(x) ((x < ' ') ? CtrlCharTable[(x)] : 0)
+extern char CtrlCharTable[];
+
+#define MetaChar(x) ((x < ' ') ? MetaCharTable[(x)] : 0)
+extern char MetaCharTable[];
+
+#endif /* defined EBCDIC */
+
+/* TODO: EBCDIC Code page dependent (here 1047) */
+#define CSI 0x9b /* Control Sequence Introducer */
+#define CSI_STR "\233"
+#define DCS 0x90 /* Device Control String */
+#define OSC 0x9d /* Operating System Command */
+#define STERM 0x9c /* String Terminator */
+
+/*
+ * Character that separates dir names in a path.
+ * For MS-DOS, WIN32 and OS/2 we use a backslash. A slash mostly works
+ * fine, but there are places where it doesn't (e.g. in a command name).
+ * For Acorn we use a dot.
+ */
+#ifdef BACKSLASH_IN_FILENAME
+# define PATHSEP psepc
+# define PATHSEPSTR pseps
+#else
+# define PATHSEP '/'
+# define PATHSEPSTR "/"
+#endif
diff --git a/src/auto/configure b/src/auto/configure
new file mode 100755
index 0000000..8052ceb
--- /dev/null
+++ b/src/auto/configure
@@ -0,0 +1,16142 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.69.
+#
+#
+# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
+#
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# Use a proper internal environment variable to ensure we don't fall
+ # into an infinite loop, continuously re-executing ourselves.
+ if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
+ _as_can_reexec=no; export _as_can_reexec;
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+as_fn_exit 255
+ fi
+ # We don't want this to propagate to other subprocesses.
+ { _as_can_reexec=; unset _as_can_reexec;}
+if test "x$CONFIG_SHELL" = x; then
+ as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '\${1+\"\$@\"}'='\"\$@\"'
+ setopt NO_GLOB_SUBST
+else
+ case \`(set -o) 2>/dev/null\` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+"
+ as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+ exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1
+test -x / || exit 1"
+ as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+ as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+ eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+ test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
+test \$(( 1 + 1 )) = 2 || exit 1"
+ if (eval "$as_required") 2>/dev/null; then :
+ as_have_required=yes
+else
+ as_have_required=no
+fi
+ if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ as_found=:
+ case $as_dir in #(
+ /*)
+ for as_base in sh bash ksh sh5; do
+ # Try only shells that exist, to save several forks.
+ as_shell=$as_dir/$as_base
+ if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ CONFIG_SHELL=$as_shell as_have_required=yes
+ if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ break 2
+fi
+fi
+ done;;
+ esac
+ as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+ CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+ if test "x$CONFIG_SHELL" != x; then :
+ export CONFIG_SHELL
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+exit 255
+fi
+
+ if test x$as_have_required = xno; then :
+ $as_echo "$0: This script requires a shell more modern than all"
+ $as_echo "$0: the shells that I found on your system."
+ if test x${ZSH_VERSION+set} = xset ; then
+ $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+ $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+ else
+ $as_echo "$0: Please tell bug-autoconf@gnu.org about your system,
+$0: including any error possibly output before this
+$0: message. Then install a modern shell, or manually run
+$0: the script under such a shell if you do have one."
+ fi
+ exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+ as_lineno_1=$LINENO as_lineno_1a=$LINENO
+ as_lineno_2=$LINENO as_lineno_2a=$LINENO
+ eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+ test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+ # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-)
+ sed -n '
+ p
+ /[$]LINENO/=
+ ' <$as_myself |
+ sed '
+ s/[$]LINENO.*/&-/
+ t lineno
+ b
+ :lineno
+ N
+ :loop
+ s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+ t loop
+ s/-\n.*//
+ ' >$as_me.lineno &&
+ chmod +x "$as_me.lineno" ||
+ { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+ # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
+ # already done that, so ensure we don't try to do so again and fall
+ # in an infinite loop. This has already happened in practice.
+ _as_can_reexec=no; export _as_can_reexec
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensitive to this).
+ . "./$as_me.lineno"
+ # Exit status is that of the last command.
+ exit
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+
+# Identity of this package.
+PACKAGE_NAME=
+PACKAGE_TARNAME=
+PACKAGE_VERSION=
+PACKAGE_STRING=
+PACKAGE_BUGREPORT=
+PACKAGE_URL=
+
+ac_unique_file="vim.h"
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_STRING_H
+# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
+# include <memory.h>
+# endif
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+LINK_AS_NEEDED
+DEPEND_CFLAGS_FILTER
+MAKEMO
+MSGFMT
+INSTALL_TOOL_LANGS
+INSTALL_LANGS
+TAGPRG
+HANGULIN_OBJ
+HANGULIN_SRC
+GUI_X_LIBS
+GUITYPE
+GUI_LIB_LOC
+GUI_INC_LOC
+NARROW_PROTO
+MOTIF_LIBNAME
+GRESOURCE_OBJ
+GRESOURCE_SRC
+UPDATE_DESKTOP_DATABASE
+GTK_UPDATE_ICON_CACHE
+GLIB_COMPILE_RESOURCES
+GNOME_INCLUDEDIR
+GNOME_LIBDIR
+GNOME_LIBS
+GTK_LIBNAME
+GTK_LIBS
+GTK_CFLAGS
+PKG_CONFIG
+X_LIB
+X_EXTRA_LIBS
+X_LIBS
+X_PRE_LIBS
+X_CFLAGS
+XMKMF
+xmkmfpath
+TERM_OBJ
+TERM_SRC
+CHANNEL_OBJ
+CHANNEL_SRC
+NETBEANS_OBJ
+NETBEANS_SRC
+RUBY_LIBS
+RUBY_CFLAGS
+RUBY_PRO
+RUBY_OBJ
+RUBY_SRC
+vi_cv_path_ruby
+TCL_LIBS
+TCL_CFLAGS
+TCL_PRO
+TCL_OBJ
+TCL_SRC
+vi_cv_path_tcl
+PYTHON3_OBJ
+PYTHON3_SRC
+PYTHON3_CFLAGS
+PYTHON3_LIBS
+vi_cv_path_python3
+PYTHON_OBJ
+PYTHON_SRC
+PYTHON_CFLAGS
+PYTHON_LIBS
+vi_cv_path_python
+PERL_LIBS
+PERL_CFLAGS
+PERL_PRO
+PERL_OBJ
+PERL_SRC
+shrpenv
+vi_cv_perl_xsubpp
+vi_cv_perllib
+vi_cv_path_perl
+MZSCHEME_MZC
+MZSCHEME_EXTRA
+MZSCHEME_CFLAGS
+MZSCHEME_LIBS
+MZSCHEME_PRO
+MZSCHEME_OBJ
+MZSCHEME_SRC
+vi_cv_path_mzscheme
+LUA_CFLAGS
+LUA_LIBS
+LUA_PRO
+LUA_OBJ
+LUA_SRC
+vi_cv_path_plain_lua
+vi_cv_path_luajit
+vi_cv_path_lua
+compiledby
+dogvimdiff
+dovimdiff
+QUOTESED
+line_break
+VIEWNAME
+EXNAME
+VIMNAME
+OS_EXTRA_OBJ
+OS_EXTRA_SRC
+XCODE_SELECT
+CPP_MM
+CROSS_COMPILING
+STRIP
+AWK
+FGREP
+EGREP
+GREP
+CPP
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+SET_MAKE
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+runstatedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_URL
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+enable_fail_if_missing
+enable_darwin
+with_mac_arch
+with_developer_dir
+with_local_dir
+with_vim_name
+with_ex_name
+with_view_name
+with_global_runtime
+with_modified_by
+enable_smack
+enable_selinux
+with_features
+with_compiledby
+enable_xsmp
+enable_xsmp_interact
+enable_luainterp
+with_lua_prefix
+with_luajit
+enable_mzschemeinterp
+with_plthome
+enable_perlinterp
+enable_pythoninterp
+with_python_command
+with_python_config_dir
+enable_python3interp
+with_python3_command
+with_python3_config_dir
+enable_tclinterp
+with_tclsh
+enable_rubyinterp
+with_ruby_command
+enable_cscope
+enable_netbeans
+enable_channel
+enable_terminal
+enable_autoservername
+enable_multibyte
+enable_rightleft
+enable_arabic
+enable_farsi
+enable_hangulinput
+enable_xim
+enable_fontset
+with_x
+enable_gui
+enable_gtk2_check
+enable_gnome_check
+enable_gtk3_check
+enable_motif_check
+enable_athena_check
+enable_nextaw_check
+enable_carbon_check
+enable_gtktest
+with_gnome_includes
+with_gnome_libs
+with_gnome
+enable_icon_cache_update
+enable_desktop_database_update
+with_motif_lib
+with_tlib
+enable_largefile
+enable_acl
+enable_gpm
+enable_sysmouse
+enable_nls
+'
+ ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+CPP
+XMKMF'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval $ac_prev=\$ac_option
+ ac_prev=
+ continue
+ fi
+
+ case $ac_option in
+ *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+ *=) ac_optarg= ;;
+ *) ac_optarg=yes ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_dashdash$ac_option in
+ --)
+ ac_dashdash=yes ;;
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=*)
+ datadir=$ac_optarg ;;
+
+ -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+ | --dataroo | --dataro | --datar)
+ ac_prev=datarootdir ;;
+ -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+ datarootdir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=no ;;
+
+ -docdir | --docdir | --docdi | --doc | --do)
+ ac_prev=docdir ;;
+ -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+ docdir=$ac_optarg ;;
+
+ -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+ ac_prev=dvidir ;;
+ -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+ dvidir=$ac_optarg ;;
+
+ -enable-* | --enable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=\$ac_optarg ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+ ac_prev=htmldir ;;
+ -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+ | --ht=*)
+ htmldir=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localedir | --localedir | --localedi | --localed | --locale)
+ ac_prev=localedir ;;
+ -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+ localedir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst | --locals)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+ ac_prev=pdfdir ;;
+ -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+ pdfdir=$ac_optarg ;;
+
+ -psdir | --psdir | --psdi | --psd | --ps)
+ ac_prev=psdir ;;
+ -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+ psdir=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -runstatedir | --runstatedir | --runstatedi | --runstated \
+ | --runstate | --runstat | --runsta | --runst | --runs \
+ | --run | --ru | --r)
+ ac_prev=runstatedir ;;
+ -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+ | --run=* | --ru=* | --r=*)
+ runstatedir=$ac_optarg ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=\$ac_optarg ;;
+
+ -without-* | --without-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=no ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ case $ac_envvar in #(
+ '' | [0-9]* | *[!_$as_cr_alnum]* )
+ as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+ esac
+ eval $ac_envvar=\$ac_optarg
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+ case $enable_option_checking in
+ no) ;;
+ fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+ *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+ esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
+ datadir sysconfdir sharedstatedir localstatedir includedir \
+ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+ libdir localedir mandir runstatedir
+do
+ eval ac_val=\$$ac_var
+ # Remove trailing slashes.
+ case $ac_val in
+ */ )
+ ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+ eval $ac_var=\$ac_val;;
+ esac
+ # Be sure to have absolute directory names.
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) continue;;
+ NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+ esac
+ as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+ as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+ as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then the parent directory.
+ ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_myself" : 'X\(//\)[^/]' \| \
+ X"$as_myself" : 'X\(//\)$' \| \
+ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r "$srcdir/$ac_unique_file"; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+ test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+ as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+ cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+ pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+ srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+ eval ac_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_env_${ac_var}_value=\$${ac_var}
+ eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking ...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
+ --datadir=DIR read-only architecture-independent data [DATAROOTDIR]
+ --infodir=DIR info documentation [DATAROOTDIR/info]
+ --localedir=DIR locale-dependent data [DATAROOTDIR/locale]
+ --mandir=DIR man documentation [DATAROOTDIR/man]
+ --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE]
+ --htmldir=DIR html documentation [DOCDIR]
+ --dvidir=DIR dvi documentation [DOCDIR]
+ --pdfdir=DIR pdf documentation [DOCDIR]
+ --psdir=DIR ps documentation [DOCDIR]
+_ACEOF
+
+ cat <<\_ACEOF
+
+X features:
+ --x-includes=DIR X include files are in DIR
+ --x-libraries=DIR X library files are in DIR
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+ cat <<\_ACEOF
+
+Optional Features:
+ --disable-option-checking ignore unrecognized --enable/--with options
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --enable-fail-if-missing Fail if dependencies on additional features
+ specified on the command line are missing.
+ --disable-darwin Disable Darwin (Mac OS X) support.
+ --disable-smack Do not check for Smack support.
+ --disable-selinux Do not check for SELinux support.
+ --disable-xsmp Disable XSMP session management
+ --disable-xsmp-interact Disable XSMP interaction
+ --enable-luainterp=OPTS Include Lua interpreter. default=no OPTS=no/yes/dynamic
+ --enable-mzschemeinterp Include MzScheme interpreter.
+ --enable-perlinterp=OPTS Include Perl interpreter. default=no OPTS=no/yes/dynamic
+ --enable-pythoninterp=OPTS Include Python interpreter. default=no OPTS=no/yes/dynamic
+ --enable-python3interp=OPTS Include Python3 interpreter. default=no OPTS=no/yes/dynamic
+ --enable-tclinterp=OPTS Include Tcl interpreter. default=no OPTS=no/yes/dynamic
+ --enable-rubyinterp=OPTS Include Ruby interpreter. default=no OPTS=no/yes/dynamic
+ --enable-cscope Include cscope interface.
+ --disable-netbeans Disable NetBeans integration support.
+ --disable-channel Disable process communication support.
+ --enable-terminal Enable terminal emulation support.
+ --enable-autoservername Automatically define servername at vim startup.
+ --enable-multibyte Include multibyte editing support.
+ --disable-rightleft Do not include Right-to-Left language support.
+ --disable-arabic Do not include Arabic language support.
+ --disable-farsi Do not include Farsi language support.
+ --enable-hangulinput Include Hangul input support.
+ --enable-xim Include XIM input support.
+ --enable-fontset Include X fontset output support.
+ --enable-gui=OPTS X11 GUI. default=auto OPTS=auto/no/gtk2/gnome2/gtk3/motif/athena/neXtaw/photon/carbon
+ --enable-gtk2-check If auto-select GUI, check for GTK+ 2 default=yes
+ --enable-gnome-check If GTK GUI, check for GNOME default=no
+ --enable-gtk3-check If auto-select GUI, check for GTK+ 3 default=yes
+ --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
+ --disable-gtktest Do not try to compile and run a test GTK program
+ --disable-icon-cache-update update disabled
+ --disable-desktop-database-update update disabled
+ --disable-largefile omit support for large files
+ --disable-acl No check for ACL support.
+ --disable-gpm Don't use gpm (Linux mouse daemon).
+ --disable-sysmouse Don't use sysmouse (mouse in *BSD console).
+ --disable-nls Don't support NLS (gettext()).
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --with-mac-arch=ARCH current, intel, ppc or both
+ --with-developer-dir=PATH use PATH as location for Xcode developer tools
+ --with-local-dir=PATH search PATH instead of /usr/local for local libraries.
+ --without-local-dir do not search /usr/local for local libraries.
+ --with-vim-name=NAME what to call the Vim executable
+ --with-ex-name=NAME what to call the Ex executable
+ --with-view-name=NAME what to call the View executable
+ --with-global-runtime=DIR global runtime directory in 'runtimepath', comma-separated for multiple directories
+ --with-modified-by=NAME name of who modified a release version
+ --with-features=TYPE tiny, small, normal, big or huge (default: huge)
+ --with-compiledby=NAME name to show in :version message
+ --with-lua-prefix=PFX Prefix where Lua is installed.
+ --with-luajit Link with LuaJIT instead of Lua.
+ --with-plthome=PLTHOME Use PLTHOME.
+ --with-python-command=NAME name of the Python 2 command (default: python2 or python)
+ --with-python-config-dir=PATH Python's config directory (deprecated)
+ --with-python3-command=NAME name of the Python 3 command (default: python3 or python)
+ --with-python3-config-dir=PATH Python's config directory (deprecated)
+ --with-tclsh=PATH which tclsh to use (default: tclsh8.0)
+ --with-ruby-command=RUBY name of the Ruby command (default: ruby)
+ --with-x use the X Window System
+ --with-gnome-includes=DIR Specify location of GNOME headers
+ --with-gnome-libs=DIR Specify location of GNOME libs
+ --with-gnome Specify prefix for GNOME files
+ --with-motif-lib=STRING Library for Motif
+ --with-tlib=library terminal library to be used
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ LIBS libraries to pass to the linker, e.g. -l<library>
+ CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+ you have headers in a nonstandard directory <include dir>
+ CPP C preprocessor
+ XMKMF Path to xmkmf, Makefile generator for X Window System
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to the package provider.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d "$ac_dir" ||
+ { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+ continue
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+ cd "$ac_dir" || { ac_status=$?; continue; }
+ # Check for guested configure.
+ if test -f "$ac_srcdir/configure.gnu"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+ elif test -f "$ac_srcdir/configure"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure" --help=recursive
+ else
+ $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi || ac_status=$?
+ cd "$ac_pwd" || { ac_status=$?; break; }
+ done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+ cat <<\_ACEOF
+configure
+generated by GNU Autoconf 2.69
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext
+ if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_cpp LINENO
+# ----------------------
+# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_cpp ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if { { ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } > conftest.i && {
+ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_cpp
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext conftest$ac_exeext
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ test -x conftest$ac_exeext
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+ # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+ # interfere with the next link command; also delete a directory that is
+ # left behind by Apple's compiler. We do this before executing the actions.
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+
+# ac_fn_c_try_run LINENO
+# ----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes
+# that executables *can* be run.
+ac_fn_c_try_run ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && { ac_try='./conftest$ac_exeext'
+ { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: program exited with status $ac_status" >&5
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=$ac_status
+fi
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_run
+
+# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists, giving a warning if it cannot be compiled using
+# the include files in INCLUDES and setting the cache variable VAR
+# accordingly.
+ac_fn_c_check_header_mongrel ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if eval \${$3+:} false; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+ # Is the header compilable?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
+$as_echo_n "checking $2 usability... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_header_compiler=yes
+else
+ ac_header_compiler=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
+$as_echo_n "checking $2 presence... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <$2>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ ac_header_preproc=yes
+else
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #((
+ yes:no: )
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+ ;;
+ no:yes:* )
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+ ;;
+esac
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ eval "$3=\$ac_header_compiler"
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_mongrel
+
+# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists and can be compiled using the include files in
+# INCLUDES, setting the cache variable VAR accordingly.
+ac_fn_c_check_header_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ eval "$3=yes"
+else
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_compile
+
+# ac_fn_c_check_func LINENO FUNC VAR
+# ----------------------------------
+# Tests whether FUNC exists, setting the cache variable VAR accordingly
+ac_fn_c_check_func ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $2 innocuous_$2
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $2 (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $2
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $2 ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined __stub_$2 || defined __stub___$2
+choke me
+#endif
+
+int
+main ()
+{
+return $2 ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ eval "$3=yes"
+else
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_func
+
+# ac_fn_c_check_type LINENO TYPE VAR INCLUDES
+# -------------------------------------------
+# Tests whether TYPE exists after having included INCLUDES, setting cache
+# variable VAR accordingly.
+ac_fn_c_check_type ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ eval "$3=no"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+int
+main ()
+{
+if (sizeof ($2))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+int
+main ()
+{
+if (sizeof (($2)))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+ eval "$3=yes"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_type
+
+# ac_fn_c_find_uintX_t LINENO BITS VAR
+# ------------------------------------
+# Finds an unsigned integer type with width BITS, setting cache variable VAR
+# accordingly.
+ac_fn_c_find_uintX_t ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uint$2_t" >&5
+$as_echo_n "checking for uint$2_t... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ eval "$3=no"
+ # Order is important - never check a type that is potentially smaller
+ # than half of the expected target width.
+ for ac_type in uint$2_t 'unsigned int' 'unsigned long int' \
+ 'unsigned long long int' 'unsigned short int' 'unsigned char'; do
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !((($ac_type) -1 >> ($2 / 2 - 1)) >> ($2 / 2 - 1) == 3)];
+test_array [0] = 0;
+return test_array [0];
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ case $ac_type in #(
+ uint$2_t) :
+ eval "$3=yes" ;; #(
+ *) :
+ eval "$3=\$ac_type" ;;
+esac
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ if eval test \"x\$"$3"\" = x"no"; then :
+
+else
+ break
+fi
+ done
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_find_uintX_t
+
+# ac_fn_c_compute_int LINENO EXPR VAR INCLUDES
+# --------------------------------------------
+# Tries to find the compile-time value of EXPR in a program that includes
+# INCLUDES, setting VAR accordingly. Returns whether the value could be
+# computed
+ac_fn_c_compute_int ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if test "$cross_compiling" = yes; then
+ # Depending upon the size, compute the lo and hi bounds.
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+int
+main ()
+{
+static int test_array [1 - 2 * !(($2) >= 0)];
+test_array [0] = 0;
+return test_array [0];
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_lo=0 ac_mid=0
+ while :; do
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+int
+main ()
+{
+static int test_array [1 - 2 * !(($2) <= $ac_mid)];
+test_array [0] = 0;
+return test_array [0];
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_hi=$ac_mid; break
+else
+ as_fn_arith $ac_mid + 1 && ac_lo=$as_val
+ if test $ac_lo -le $ac_mid; then
+ ac_lo= ac_hi=
+ break
+ fi
+ as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+int
+main ()
+{
+static int test_array [1 - 2 * !(($2) < 0)];
+test_array [0] = 0;
+return test_array [0];
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_hi=-1 ac_mid=-1
+ while :; do
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+int
+main ()
+{
+static int test_array [1 - 2 * !(($2) >= $ac_mid)];
+test_array [0] = 0;
+return test_array [0];
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_lo=$ac_mid; break
+else
+ as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val
+ if test $ac_mid -le $ac_hi; then
+ ac_lo= ac_hi=
+ break
+ fi
+ as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+else
+ ac_lo= ac_hi=
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+ as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+int
+main ()
+{
+static int test_array [1 - 2 * !(($2) <= $ac_mid)];
+test_array [0] = 0;
+return test_array [0];
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_hi=$ac_mid
+else
+ as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in #((
+?*) eval "$3=\$ac_lo"; ac_retval=0 ;;
+'') ac_retval=1 ;;
+esac
+ else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+static long int longval () { return $2; }
+static unsigned long int ulongval () { return $2; }
+#include <stdio.h>
+#include <stdlib.h>
+int
+main ()
+{
+
+ FILE *f = fopen ("conftest.val", "w");
+ if (! f)
+ return 1;
+ if (($2) < 0)
+ {
+ long int i = longval ();
+ if (i != ($2))
+ return 1;
+ fprintf (f, "%ld", i);
+ }
+ else
+ {
+ unsigned long int i = ulongval ();
+ if (i != ($2))
+ return 1;
+ fprintf (f, "%lu", i);
+ }
+ /* Do not output a trailing newline, as this causes \r\n confusion
+ on some platforms. */
+ return ferror (f) || fclose (f) != 0;
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ echo >>conftest.val; read $3 <conftest.val; ac_retval=0
+else
+ ac_retval=1
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+rm -f conftest.val
+
+ fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_compute_int
+cat >auto/config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>auto/config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ $as_echo "PATH: $as_dir"
+ done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 2)
+ as_fn_append ac_configure_args1 " '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ as_fn_append ac_configure_args " '$ac_arg'"
+ ;;
+ esac
+ done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ $as_echo "$as_me: caught signal $ac_signal"
+ $as_echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+ # We do not want a PATH search for config.site.
+ case $CONFIG_SITE in #((
+ -*) ac_site_file1=./$CONFIG_SITE;;
+ */*) ac_site_file1=$CONFIG_SITE;;
+ *) ac_site_file1=./$CONFIG_SITE;;
+ esac
+elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+else
+ ac_site_file1=$ac_default_prefix/share/config.site
+ ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+ test "x$ac_site_file" = xNONE && continue
+ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file" \
+ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special files
+ # actually), so we avoid doing that. DJGPP emulates it as a regular file.
+ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+ac_config_headers="$ac_config_headers auto/config.h:config.h.in"
+
+
+$as_echo "#define UNIX 1" >>confdefs.h
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; }
+set x ${MAKE-make}
+ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
+if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat >conftest.make <<\_ACEOF
+SHELL = /bin/sh
+all:
+ @echo '@@@%%%=$(MAKE)=@@@%%%'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering ...", which would confuse us.
+case `${MAKE-make} -f conftest.make 2>/dev/null` in
+ *@@@%%%=?*=@@@%%%*)
+ eval ac_cv_prog_make_${ac_make}_set=yes;;
+ *)
+ eval ac_cv_prog_make_${ac_make}_set=no;;
+esac
+rm -f conftest.make
+fi
+if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ SET_MAKE=
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ fi
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl.exe
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl.exe
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_CC" && break
+done
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+ { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ sed '10a\
+... rest of stderr output deleted ...
+ 10q' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ fi
+ rm -f conftest.er1 conftest.err
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+done
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+ esac
+done
+rm -f $ac_rmfiles
+
+if { { ac_try="$ac_link_default"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link_default") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile. We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+ ;;
+ [ab].out )
+ # We found the default executable, but exeext='' is most
+ # certainly right.
+ break;;
+ *.* )
+ if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+ then :; else
+ ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ fi
+ # We set ac_cv_exeext here because the later test for it is not
+ # safe: cross compilers may not add the suffix if given an `-o'
+ # argument, so we may need to know it at that point already.
+ # Even if this section looks crufty: it has the advantage of
+ # actually working.
+ break;;
+ * )
+ break;;
+ esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+ ac_file=''
+fi
+if test -z "$ac_file"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "C compiler cannot create executables
+See \`config.log' for more details" "$LINENO" 5; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+ac_exeext=$ac_cv_exeext
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdio.h>
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+ { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ if { ac_try='./conftest$ac_cv_exeext'
+ { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if ${ac_cv_objext+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ for ac_file in conftest.o conftest.obj conftest.*; do
+ test -f "$ac_file" || continue;
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if ${ac_cv_c_compiler_gnu+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_compiler_gnu=yes
+else
+ ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if ${ac_cv_prog_cc_g+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_save_c_werror_flag=$ac_c_werror_flag
+ ac_c_werror_flag=yes
+ ac_cv_prog_cc_g=no
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+else
+ CFLAGS=""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+ ac_c_werror_flag=$ac_save_c_werror_flag
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+struct stat;
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
+ function prototypes and stuff, but not '\xHH' hex character constants.
+ These don't provoke an error unfortunately, instead are silently treated
+ as 'x'. The following induces an error, until -std is added to get
+ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
+ array size at least. It's necessary to write '\x00'==0 to get something
+ that's true only with -std. */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+ inside strings and character constants. */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+ test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+ x)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+ xno)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+ *)
+ CC="$CC $ac_cv_prog_cc_c89"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C99" >&5
+$as_echo_n "checking for $CC option to accept ISO C99... " >&6; }
+if ${ac_cv_prog_cc_c99+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_prog_cc_c99=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include <stdio.h>
+
+// Check varargs macros. These examples are taken from C99 6.10.3.5.
+#define debug(...) fprintf (stderr, __VA_ARGS__)
+#define showlist(...) puts (#__VA_ARGS__)
+#define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__))
+static void
+test_varargs_macros (void)
+{
+ int x = 1234;
+ int y = 5678;
+ debug ("Flag");
+ debug ("X = %d\n", x);
+ showlist (The first, second, and third items.);
+ report (x>y, "x is %d but y is %d", x, y);
+}
+
+// Check long long types.
+#define BIG64 18446744073709551615ull
+#define BIG32 4294967295ul
+#define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0)
+#if !BIG_OK
+ your preprocessor is broken;
+#endif
+#if BIG_OK
+#else
+ your preprocessor is broken;
+#endif
+static long long int bignum = -9223372036854775807LL;
+static unsigned long long int ubignum = BIG64;
+
+struct incomplete_array
+{
+ int datasize;
+ double data[];
+};
+
+struct named_init {
+ int number;
+ const wchar_t *name;
+ double average;
+};
+
+typedef const char *ccp;
+
+static inline int
+test_restrict (ccp restrict text)
+{
+ // See if C++-style comments work.
+ // Iterate through items via the restricted pointer.
+ // Also check for declarations in for loops.
+ for (unsigned int i = 0; *(text+i) != '\0'; ++i)
+ continue;
+ return 0;
+}
+
+// Check varargs and va_copy.
+static void
+test_varargs (const char *format, ...)
+{
+ va_list args;
+ va_start (args, format);
+ va_list args_copy;
+ va_copy (args_copy, args);
+
+ const char *str;
+ int number;
+ float fnumber;
+
+ while (*format)
+ {
+ switch (*format++)
+ {
+ case 's': // string
+ str = va_arg (args_copy, const char *);
+ break;
+ case 'd': // int
+ number = va_arg (args_copy, int);
+ break;
+ case 'f': // float
+ fnumber = va_arg (args_copy, double);
+ break;
+ default:
+ break;
+ }
+ }
+ va_end (args_copy);
+ va_end (args);
+}
+
+int
+main ()
+{
+
+ // Check bool.
+ _Bool success = false;
+
+ // Check restrict.
+ if (test_restrict ("String literal") == 0)
+ success = true;
+ char *restrict newvar = "Another string";
+
+ // Check varargs.
+ test_varargs ("s, d' f .", "string", 65, 34.234);
+ test_varargs_macros ();
+
+ // Check flexible array members.
+ struct incomplete_array *ia =
+ malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10));
+ ia->datasize = 10;
+ for (int i = 0; i < ia->datasize; ++i)
+ ia->data[i] = i * 1.234;
+
+ // Check named initializers.
+ struct named_init ni = {
+ .number = 34,
+ .name = L"Test wide string",
+ .average = 543.34343,
+ };
+
+ ni.number = 58;
+
+ int dynamic_array[ni.number];
+ dynamic_array[ni.number - 1] = 543;
+
+ // work around unused variable warnings
+ return (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == 'x'
+ || dynamic_array[ni.number - 1] != 543);
+
+ ;
+ return 0;
+}
+_ACEOF
+for ac_arg in '' -std=gnu99 -std=c99 -c99 -AC99 -D_STDC_C99= -qlanglvl=extc99
+do
+ CC="$ac_save_CC $ac_arg"
+ if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_c99=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+ test "x$ac_cv_prog_cc_c99" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c99" in
+ x)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+ xno)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+ *)
+ CC="$CC $ac_cv_prog_cc_c99"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5
+$as_echo "$ac_cv_prog_cc_c99" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c99" != xno; then :
+
+fi
+
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
+$as_echo_n "checking how to run the C preprocessor... " >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+ if ${ac_cv_prog_CPP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ # Double quotes because CPP needs to be expanded
+ for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+ do
+ ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+ break
+fi
+
+ done
+ ac_cv_prog_CPP=$CPP
+
+fi
+ CPP=$ac_cv_prog_CPP
+else
+ ac_cv_prog_CPP=$CPP
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
+$as_echo "$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
+$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
+if ${ac_cv_path_GREP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$GREP"; then
+ ac_path_GREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in grep ggrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+ as_fn_executable_p "$ac_path_GREP" || continue
+# Check for GNU ac_path_GREP and select it if it is found.
+ # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'GREP' >> "conftest.nl"
+ "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_GREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_GREP="$ac_path_GREP"
+ ac_path_GREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_GREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_GREP"; then
+ as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_GREP=$GREP
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
+$as_echo "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
+$as_echo_n "checking for egrep... " >&6; }
+if ${ac_cv_path_EGREP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+ then ac_cv_path_EGREP="$GREP -E"
+ else
+ if test -z "$EGREP"; then
+ ac_path_EGREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in egrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+ as_fn_executable_p "$ac_path_EGREP" || continue
+# Check for GNU ac_path_EGREP and select it if it is found.
+ # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'EGREP' >> "conftest.nl"
+ "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_EGREP="$ac_path_EGREP"
+ ac_path_EGREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_EGREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_EGREP"; then
+ as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_EGREP=$EGREP
+fi
+
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
+$as_echo "$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "" >/dev/null 2>&1; then :
+
+fi
+rm -f conftest*
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5
+$as_echo_n "checking for fgrep... " >&6; }
+if ${ac_cv_path_FGREP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1
+ then ac_cv_path_FGREP="$GREP -F"
+ else
+ if test -z "$FGREP"; then
+ ac_path_FGREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in fgrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext"
+ as_fn_executable_p "$ac_path_FGREP" || continue
+# Check for GNU ac_path_FGREP and select it if it is found.
+ # Check for GNU $ac_path_FGREP
+case `"$ac_path_FGREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'FGREP' >> "conftest.nl"
+ "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_FGREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_FGREP="$ac_path_FGREP"
+ ac_path_FGREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_FGREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_FGREP"; then
+ as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_FGREP=$FGREP
+fi
+
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5
+$as_echo "$ac_cv_path_FGREP" >&6; }
+ FGREP="$ac_cv_path_FGREP"
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing strerror" >&5
+$as_echo_n "checking for library containing strerror... " >&6; }
+if ${ac_cv_search_strerror+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char strerror ();
+int
+main ()
+{
+return strerror ();
+ ;
+ return 0;
+}
+_ACEOF
+for ac_lib in '' cposix; do
+ if test -z "$ac_lib"; then
+ ac_res="none required"
+ else
+ ac_res=-l$ac_lib
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ fi
+ if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_search_strerror=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext
+ if ${ac_cv_search_strerror+:} false; then :
+ break
+fi
+done
+if ${ac_cv_search_strerror+:} false; then :
+
+else
+ ac_cv_search_strerror=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_strerror" >&5
+$as_echo "$ac_cv_search_strerror" >&6; }
+ac_res=$ac_cv_search_strerror
+if test "$ac_res" != no; then :
+ test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+fi
+ for ac_prog in gawk mawk nawk awk
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_AWK+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$AWK"; then
+ ac_cv_prog_AWK="$AWK" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_AWK="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+AWK=$ac_cv_prog_AWK
+if test -n "$AWK"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5
+$as_echo "$AWK" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$AWK" && break
+done
+
+# Extract the first word of "strip", so it can be a program name with args.
+set dummy strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_STRIP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$STRIP"; then
+ ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_STRIP="strip"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ test -z "$ac_cv_prog_STRIP" && ac_cv_prog_STRIP=":"
+fi
+fi
+STRIP=$ac_cv_prog_STRIP
+if test -n "$STRIP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5
+$as_echo "$STRIP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
+$as_echo_n "checking for ANSI C header files... " >&6; }
+if ${ac_cv_header_stdc+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_header_stdc=yes
+else
+ ac_cv_header_stdc=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "memchr" >/dev/null 2>&1; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "free" >/dev/null 2>&1; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+ if test "$cross_compiling" = yes; then :
+ :
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ctype.h>
+#include <stdlib.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+ (('a' <= (c) && (c) <= 'i') \
+ || ('j' <= (c) && (c) <= 'r') \
+ || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 256; i++)
+ if (XOR (islower (i), ISLOWER (i))
+ || toupper (i) != TOUPPER (i))
+ return 2;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
+$as_echo "$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+
+$as_echo "#define STDC_HEADERS 1" >>confdefs.h
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sys/wait.h that is POSIX.1 compatible" >&5
+$as_echo_n "checking for sys/wait.h that is POSIX.1 compatible... " >&6; }
+if ${ac_cv_header_sys_wait_h+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <sys/wait.h>
+#ifndef WEXITSTATUS
+# define WEXITSTATUS(stat_val) ((unsigned int) (stat_val) >> 8)
+#endif
+#ifndef WIFEXITED
+# define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
+#endif
+
+int
+main ()
+{
+ int s;
+ wait (&s);
+ s = WIFEXITED (s) ? WEXITSTATUS (s) : 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_header_sys_wait_h=yes
+else
+ ac_cv_header_sys_wait_h=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_sys_wait_h" >&5
+$as_echo "$ac_cv_header_sys_wait_h" >&6; }
+if test $ac_cv_header_sys_wait_h = yes; then
+
+$as_echo "#define HAVE_SYS_WAIT_H 1" >>confdefs.h
+
+fi
+
+
+if test x"$ac_cv_prog_cc_c99" != xno; then
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for unsigned long long int" >&5
+$as_echo_n "checking for unsigned long long int... " >&6; }
+if ${ac_cv_type_unsigned_long_long_int+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_type_unsigned_long_long_int=yes
+ if test "x${ac_cv_prog_cc_c99-no}" = xno; then
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ /* For now, do not test the preprocessor; as of 2007 there are too many
+ implementations with broken preprocessors. Perhaps this can
+ be revisited in 2012. In the meantime, code should not expect
+ #if to work with literals wider than 32 bits. */
+ /* Test literals. */
+ long long int ll = 9223372036854775807ll;
+ long long int nll = -9223372036854775807LL;
+ unsigned long long int ull = 18446744073709551615ULL;
+ /* Test constant expressions. */
+ typedef int a[((-9223372036854775807LL < 0 && 0 < 9223372036854775807ll)
+ ? 1 : -1)];
+ typedef int b[(18446744073709551615ULL <= (unsigned long long int) -1
+ ? 1 : -1)];
+ int i = 63;
+int
+main ()
+{
+/* Test availability of runtime routines for shift and division. */
+ long long int llmax = 9223372036854775807ll;
+ unsigned long long int ullmax = 18446744073709551615ull;
+ return ((ll << 63) | (ll >> 63) | (ll < i) | (ll > i)
+ | (llmax / ll) | (llmax % ll)
+ | (ull << 63) | (ull >> 63) | (ull << i) | (ull >> i)
+ | (ullmax / ull) | (ullmax % ull));
+ ;
+ return 0;
+}
+
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+else
+ ac_cv_type_unsigned_long_long_int=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_unsigned_long_long_int" >&5
+$as_echo "$ac_cv_type_unsigned_long_long_int" >&6; }
+ if test $ac_cv_type_unsigned_long_long_int = yes; then
+
+$as_echo "#define HAVE_UNSIGNED_LONG_LONG_INT 1" >>confdefs.h
+
+ fi
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for long long int" >&5
+$as_echo_n "checking for long long int... " >&6; }
+if ${ac_cv_type_long_long_int+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_type_long_long_int=yes
+ if test "x${ac_cv_prog_cc_c99-no}" = xno; then
+ ac_cv_type_long_long_int=$ac_cv_type_unsigned_long_long_int
+ if test $ac_cv_type_long_long_int = yes; then
+ if test "$cross_compiling" = yes; then :
+ :
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <limits.h>
+ #ifndef LLONG_MAX
+ # define HALF \
+ (1LL << (sizeof (long long int) * CHAR_BIT - 2))
+ # define LLONG_MAX (HALF - 1 + HALF)
+ #endif
+int
+main ()
+{
+long long int n = 1;
+ int i;
+ for (i = 0; ; i++)
+ {
+ long long int m = n << i;
+ if (m >> i != n)
+ return 1;
+ if (LLONG_MAX / 2 < m)
+ break;
+ }
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+else
+ ac_cv_type_long_long_int=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+ fi
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_long_long_int" >&5
+$as_echo "$ac_cv_type_long_long_int" >&6; }
+ if test $ac_cv_type_long_long_int = yes; then
+
+$as_echo "#define HAVE_LONG_LONG_INT 1" >>confdefs.h
+
+ fi
+
+ if test "$ac_cv_type_long_long_int" = no; then
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "Compiler does not support long long int
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the compiler supports trailing commas" >&5
+$as_echo_n "checking if the compiler supports trailing commas... " >&6; }
+ trailing_commas=no
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ enum {
+ one,
+ };
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }; trailing_commas=yes
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ if test "$trailing_commas" = no; then
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "Compiler does not support trailing comma in enum
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the compiler supports C++ comments" >&5
+$as_echo_n "checking if the compiler supports C++ comments... " >&6; }
+ slash_comments=no
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+// C++ comments?
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }; slash_comments=yes
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ if test "$slash_comments" = no; then
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "Compiler does not support C++ comments
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --enable-fail-if-missing argument" >&5
+$as_echo_n "checking --enable-fail-if-missing argument... " >&6; }
+# Check whether --enable-fail_if_missing was given.
+if test "${enable_fail_if_missing+set}" = set; then :
+ enableval=$enable_fail_if_missing; fail_if_missing="yes"
+else
+ fail_if_missing="no"
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $fail_if_missing" >&5
+$as_echo "$fail_if_missing" >&6; }
+
+with_x_arg="$with_x"
+
+if test -z "$CFLAGS"; then
+ CFLAGS="-O"
+ test "$GCC" = yes && CFLAGS="-O2 -fno-strength-reduce -Wall"
+fi
+if test "$GCC" = yes; then
+ gccversion=`$CC -dumpversion`
+ if test "x$gccversion" = "x"; then
+ gccversion=`$CC --version | sed -e '2,$d' -e 's/darwin.//' -e 's/^[^0-9]*\([0-9]\.[0-9.]*\).*$/\1/g'`
+ fi
+ if test "$gccversion" = "3.0.1" -o "$gccversion" = "3.0.2" -o "$gccversion" = "4.0.1"; then
+ echo 'GCC [34].0.[12] has a bug in the optimizer, disabling "-O#"'
+ CFLAGS=`echo "$CFLAGS" | sed 's/-O[23456789]/-O/'`
+ else
+ if test "$gccversion" = "3.1" -o "$gccversion" = "3.2" -o "$gccversion" = "3.2.1" && `echo "$CFLAGS" | grep -v fno-strength-reduce >/dev/null`; then
+ echo 'GCC 3.1 and 3.2 have a bug in the optimizer, adding "-fno-strength-reduce"'
+ CFLAGS="$CFLAGS -fno-strength-reduce"
+ fi
+ fi
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for clang version" >&5
+$as_echo_n "checking for clang version... " >&6; }
+CLANG_VERSION_STRING=`$CC --version 2>/dev/null | sed -n -e 's/^.*clang[^0-9]*\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\).*$/\1/p'`
+if test x"$CLANG_VERSION_STRING" != x"" ; then
+ CLANG_MAJOR=`echo "$CLANG_VERSION_STRING" | sed -n -e 's/\([0-9][0-9]*\)\.[0-9][0-9]*\.[0-9][0-9]*/\1/p'`
+ CLANG_MINOR=`echo "$CLANG_VERSION_STRING" | sed -n -e 's/[0-9][0-9]*\.\([0-9][0-9]*\)\.[0-9][0-9]*/\1/p'`
+ CLANG_REVISION=`echo "$CLANG_VERSION_STRING" | sed -n -e 's/[0-9][0-9]*\.[0-9][0-9]*\.\([0-9][0-9]*\)/\1/p'`
+ CLANG_VERSION=`expr $CLANG_MAJOR '*' 1000000 '+' $CLANG_MINOR '*' 1000 '+' $CLANG_REVISION`
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CLANG_VERSION" >&5
+$as_echo "$CLANG_VERSION" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if clang supports -fno-strength-reduce" >&5
+$as_echo_n "checking if clang supports -fno-strength-reduce... " >&6; }
+ if test "$CLANG_VERSION" -ge 500002075 ; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ CFLAGS=`echo "$CFLAGS" | sed -e 's/-fno-strength-reduce/ /'`
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: N/A" >&5
+$as_echo "N/A" >&6; }
+fi
+
+CROSS_COMPILING=
+if test "$cross_compiling" = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: cannot compile a simple program; if not cross compiling check CC and CFLAGS" >&5
+$as_echo "cannot compile a simple program; if not cross compiling check CC and CFLAGS" >&6; }
+ CROSS_COMPILING=1
+fi
+
+
+test "$GCC" = yes && CPP_MM=M;
+
+if test -f ./toolcheck; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for buggy tools..." >&5
+$as_echo "$as_me: checking for buggy tools..." >&6;}
+ sh ./toolcheck 1>&6
+fi
+
+OS_EXTRA_SRC=""; OS_EXTRA_OBJ=""
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BeOS" >&5
+$as_echo_n "checking for BeOS... " >&6; }
+case `uname` in
+ BeOS) OS_EXTRA_SRC=os_beos.c; OS_EXTRA_OBJ=objects/os_beos.o
+ BEOS=yes; { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; };;
+ *) BEOS=no; { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; };;
+esac
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for QNX" >&5
+$as_echo_n "checking for QNX... " >&6; }
+case `uname` in
+ QNX) OS_EXTRA_SRC=os_qnx.c; OS_EXTRA_OBJ=objects/os_qnx.o
+ test -z "$with_x" && with_x=no
+ QNX=yes; { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; };;
+ *) QNX=no; { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; };;
+esac
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for Darwin (Mac OS X)" >&5
+$as_echo_n "checking for Darwin (Mac OS X)... " >&6; }
+if test "`(uname) 2>/dev/null`" = Darwin; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ MACOS_X=yes
+ CPPFLAGS="$CPPFLAGS -DMACOS_X"
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking --disable-darwin argument" >&5
+$as_echo_n "checking --disable-darwin argument... " >&6; }
+ # Check whether --enable-darwin was given.
+if test "${enable_darwin+set}" = set; then :
+ enableval=$enable_darwin;
+else
+ enable_darwin="yes"
+fi
+
+ if test "$enable_darwin" = "yes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if Darwin files are there" >&5
+$as_echo_n "checking if Darwin files are there... " >&6; }
+ if test -f os_macosx.m; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, Darwin support disabled" >&5
+$as_echo "no, Darwin support disabled" >&6; }
+ enable_darwin=no
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes, Darwin support excluded" >&5
+$as_echo "yes, Darwin support excluded" >&6; }
+ fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking --with-mac-arch argument" >&5
+$as_echo_n "checking --with-mac-arch argument... " >&6; }
+
+# Check whether --with-mac-arch was given.
+if test "${with_mac_arch+set}" = set; then :
+ withval=$with_mac_arch; MACARCH="$withval"; { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MACARCH" >&5
+$as_echo "$MACARCH" >&6; }
+else
+ MACARCH="current"; { $as_echo "$as_me:${as_lineno-$LINENO}: result: defaulting to $MACARCH" >&5
+$as_echo "defaulting to $MACARCH" >&6; }
+fi
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking --with-developer-dir argument" >&5
+$as_echo_n "checking --with-developer-dir argument... " >&6; }
+
+# Check whether --with-developer-dir was given.
+if test "${with_developer_dir+set}" = set; then :
+ withval=$with_developer_dir; DEVELOPER_DIR="$withval"; { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DEVELOPER_DIR" >&5
+$as_echo "$DEVELOPER_DIR" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: not present" >&5
+$as_echo "not present" >&6; }
+fi
+
+
+ if test "x$DEVELOPER_DIR" = "x"; then
+ # Extract the first word of "xcode-select", so it can be a program name with args.
+set dummy xcode-select; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_XCODE_SELECT+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $XCODE_SELECT in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_XCODE_SELECT="$XCODE_SELECT" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_XCODE_SELECT="$as_dir/$ac_word$ac_exec_ext"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+fi
+XCODE_SELECT=$ac_cv_path_XCODE_SELECT
+if test -n "$XCODE_SELECT"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $XCODE_SELECT" >&5
+$as_echo "$XCODE_SELECT" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ if test "x$XCODE_SELECT" != "x"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for developer dir using xcode-select" >&5
+$as_echo_n "checking for developer dir using xcode-select... " >&6; }
+ DEVELOPER_DIR=`$XCODE_SELECT -print-path`
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DEVELOPER_DIR" >&5
+$as_echo "$DEVELOPER_DIR" >&6; }
+ else
+ DEVELOPER_DIR=/Developer
+ fi
+ fi
+
+ if test "x$MACARCH" = "xboth"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 10.4 universal SDK" >&5
+$as_echo_n "checking for 10.4 universal SDK... " >&6; }
+ save_cppflags="$CPPFLAGS"
+ save_cflags="$CFLAGS"
+ save_ldflags="$LDFLAGS"
+ CFLAGS="$CFLAGS -isysroot $DEVELOPER_DIR/SDKs/MacOSX10.4u.sdk -arch i386 -arch ppc"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5
+$as_echo "found" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5
+$as_echo "not found" >&6; }
+ CFLAGS="$save_cflags"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if Intel architecture is supported" >&5
+$as_echo_n "checking if Intel architecture is supported... " >&6; }
+ CPPFLAGS="$CPPFLAGS -arch i386"
+ LDFLAGS="$save_ldflags -arch i386"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }; MACARCH="intel"
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ MACARCH="ppc"
+ CPPFLAGS="$save_cppflags -arch ppc"
+ LDFLAGS="$save_ldflags -arch ppc"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ elif test "x$MACARCH" = "xintel"; then
+ CPPFLAGS="$CPPFLAGS -arch intel"
+ LDFLAGS="$LDFLAGS -arch intel"
+ elif test "x$MACARCH" = "xppc"; then
+ CPPFLAGS="$CPPFLAGS -arch ppc"
+ LDFLAGS="$LDFLAGS -arch ppc"
+ fi
+
+ if test "$enable_darwin" = "yes"; then
+ MACOS_X_DARWIN=yes
+ OS_EXTRA_SRC="os_macosx.m os_mac_conv.c";
+ 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.
+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 :
+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
+"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+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
+
+
+ if test "x$CARBON" = "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
+ fi
+
+ if test "$MACARCH" = "intel" -o "$MACARCH" = "both"; then
+ CFLAGS=`echo "$CFLAGS" | sed 's/-O[23456789]/-Oz/'`
+ fi
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+for ac_header in AvailabilityMacros.h
+do :
+ ac_fn_c_check_header_mongrel "$LINENO" "AvailabilityMacros.h" "ac_cv_header_AvailabilityMacros_h" "$ac_includes_default"
+if test "x$ac_cv_header_AvailabilityMacros_h" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_AVAILABILITYMACROS_H 1
+_ACEOF
+
+fi
+
+done
+
+
+
+
+
+if test "$cross_compiling" = no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking --with-local-dir argument" >&5
+$as_echo_n "checking --with-local-dir argument... " >&6; }
+ have_local_include=''
+ have_local_lib=''
+
+# Check whether --with-local-dir was given.
+if test "${with_local_dir+set}" = set; then :
+ withval=$with_local_dir;
+ local_dir="$withval"
+ case "$withval" in
+ */*) ;;
+ no)
+ # avoid adding local dir to LDFLAGS and CPPFLAGS
+ have_local_include=yes
+ have_local_lib=yes
+ ;;
+ *) as_fn_error $? "must pass path argument to --with-local-dir" "$LINENO" 5 ;;
+ esac
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $local_dir" >&5
+$as_echo "$local_dir" >&6; }
+
+else
+
+ local_dir=/usr/local
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: Defaulting to $local_dir" >&5
+$as_echo "Defaulting to $local_dir" >&6; }
+
+fi
+
+ if test "$GCC" = yes -a "$local_dir" != no; then
+ echo 'void f(){}' > conftest.c
+ have_local_include=`${CC-cc} -c -v conftest.c 2>&1 | grep "${local_dir}/include"`
+ have_local_lib=`${CC-cc} -c -v conftest.c 2>&1 | grep "${local_dir}/lib"`
+ rm -f conftest.c conftest.o
+ fi
+ if test -z "$have_local_lib" -a -d "${local_dir}/lib"; then
+ tt=`echo "$LDFLAGS" | sed -e "s+-L${local_dir}/lib ++g" -e "s+-L${local_dir}/lib$++g"`
+ if test "$tt" = "$LDFLAGS"; then
+ LDFLAGS="$LDFLAGS -L${local_dir}/lib"
+ fi
+ fi
+ if test -z "$have_local_include" -a -d "${local_dir}/include"; then
+ tt=`echo "$CPPFLAGS" | sed -e "s+-I${local_dir}/include ++g" -e "s+-I${local_dir}/include$++g"`
+ if test "$tt" = "$CPPFLAGS"; then
+ CPPFLAGS="$CPPFLAGS -I${local_dir}/include"
+ fi
+ fi
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --with-vim-name argument" >&5
+$as_echo_n "checking --with-vim-name argument... " >&6; }
+
+# Check whether --with-vim-name was given.
+if test "${with_vim_name+set}" = set; then :
+ withval=$with_vim_name; VIMNAME="$withval"; { $as_echo "$as_me:${as_lineno-$LINENO}: result: $VIMNAME" >&5
+$as_echo "$VIMNAME" >&6; }
+else
+ VIMNAME="vim"; { $as_echo "$as_me:${as_lineno-$LINENO}: result: Defaulting to $VIMNAME" >&5
+$as_echo "Defaulting to $VIMNAME" >&6; }
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --with-ex-name argument" >&5
+$as_echo_n "checking --with-ex-name argument... " >&6; }
+
+# Check whether --with-ex-name was given.
+if test "${with_ex_name+set}" = set; then :
+ withval=$with_ex_name; EXNAME="$withval"; { $as_echo "$as_me:${as_lineno-$LINENO}: result: $EXNAME" >&5
+$as_echo "$EXNAME" >&6; }
+else
+ EXNAME="ex"; { $as_echo "$as_me:${as_lineno-$LINENO}: result: Defaulting to ex" >&5
+$as_echo "Defaulting to ex" >&6; }
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --with-view-name argument" >&5
+$as_echo_n "checking --with-view-name argument... " >&6; }
+
+# Check whether --with-view-name was given.
+if test "${with_view_name+set}" = set; then :
+ withval=$with_view_name; VIEWNAME="$withval"; { $as_echo "$as_me:${as_lineno-$LINENO}: result: $VIEWNAME" >&5
+$as_echo "$VIEWNAME" >&6; }
+else
+ VIEWNAME="view"; { $as_echo "$as_me:${as_lineno-$LINENO}: result: Defaulting to view" >&5
+$as_echo "Defaulting to view" >&6; }
+fi
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --with-global-runtime argument" >&5
+$as_echo_n "checking --with-global-runtime argument... " >&6; }
+
+# Check whether --with-global-runtime was given.
+if test "${with_global_runtime+set}" = set; then :
+ withval=$with_global_runtime; RUNTIME_GLOBAL="$withval"; { $as_echo "$as_me:${as_lineno-$LINENO}: result: $withval" >&5
+$as_echo "$withval" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+if test "X$RUNTIME_GLOBAL" != "X"; then
+ RUNTIME_GLOBAL_AFTER=$(printf -- "$RUNTIME_GLOBAL\\n" | $AWK -F, 'BEGIN { comma=0 } { for (i = NF; i > 0; i--) { if (comma) { printf ",%s/after", $i } else { printf "%s/after", $i; comma=1 } } } END { printf "\n" }')
+ cat >>confdefs.h <<_ACEOF
+#define RUNTIME_GLOBAL "$RUNTIME_GLOBAL"
+_ACEOF
+
+ cat >>confdefs.h <<_ACEOF
+#define RUNTIME_GLOBAL_AFTER "$RUNTIME_GLOBAL_AFTER"
+_ACEOF
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --with-modified-by argument" >&5
+$as_echo_n "checking --with-modified-by argument... " >&6; }
+
+# Check whether --with-modified-by was given.
+if test "${with_modified_by+set}" = set; then :
+ withval=$with_modified_by; { $as_echo "$as_me:${as_lineno-$LINENO}: result: $withval" >&5
+$as_echo "$withval" >&6; }; cat >>confdefs.h <<_ACEOF
+#define MODIFIED_BY "$withval"
+_ACEOF
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if character set is EBCDIC" >&5
+$as_echo_n "checking if character set is EBCDIC... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+ /* TryCompile function for CharSet.
+ Treat any failure as ASCII for compatibility with existing art.
+ Use compile-time rather than run-time tests for cross-compiler
+ tolerance. */
+#if '0'!=240
+make an error "Character set is not EBCDIC"
+#endif
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ # TryCompile action if true
+cf_cv_ebcdic=yes
+else
+ # TryCompile action if false
+cf_cv_ebcdic=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+# end of TryCompile ])
+# end of CacheVal CvEbcdic
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cf_cv_ebcdic" >&5
+$as_echo "$cf_cv_ebcdic" >&6; }
+case "$cf_cv_ebcdic" in #(vi
+ yes) $as_echo "#define EBCDIC 1" >>confdefs.h
+
+ line_break='"\\n"'
+ ;;
+ *) line_break='"\\012"';;
+esac
+
+
+if test "$cf_cv_ebcdic" = "yes"; then
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for z/OS Unix" >&5
+$as_echo_n "checking for z/OS Unix... " >&6; }
+case `uname` in
+ OS/390) zOSUnix="yes";
+ if test "$CC" = "cc"; then
+ ccm="$_CC_CCMODE"
+ ccn="CC"
+ else
+ if test "$CC" = "c89"; then
+ ccm="$_CC_C89MODE"
+ ccn="C89"
+ else
+ ccm=1
+ fi
+ fi
+ if test "$ccm" != "1"; then
+ echo ""
+ echo "------------------------------------------"
+ echo " On z/OS Unix, the environment variable"
+ echo " _CC_${ccn}MODE must be set to \"1\"!"
+ echo " Do:"
+ echo " export _CC_${ccn}MODE=1"
+ echo " and then call configure again."
+ echo "------------------------------------------"
+ exit 1
+ fi
+ # Set CFLAGS for configure process.
+ # This will be reset later for config.mk.
+ # Use haltonmsg to force error for missing H files.
+ CFLAGS="$CFLAGS -D_ALL_SOURCE -Wc,float(ieee),haltonmsg(3296)";
+ LDFLAGS="$LDFLAGS -Wl,EDIT=NO"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ ;;
+ *) zOSUnix="no";
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ ;;
+esac
+fi
+
+if test "$zOSUnix" = "yes"; then
+ QUOTESED="sed -e 's/[\\\\\"]/\\\\\\\\&/g' -e 's/\\\\\\\\\"/\"/' -e 's/\\\\\\\\\";\$\$/\";/'"
+else
+ QUOTESED="sed -e 's/[\\\\\"]/\\\\&/g' -e 's/\\\\\"/\"/' -e 's/\\\\\";\$\$/\";/'"
+fi
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --disable-smack argument" >&5
+$as_echo_n "checking --disable-smack argument... " >&6; }
+# Check whether --enable-smack was given.
+if test "${enable_smack+set}" = set; then :
+ enableval=$enable_smack;
+else
+ enable_smack="yes"
+fi
+
+if test "$enable_smack" = "yes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ ac_fn_c_check_header_mongrel "$LINENO" "linux/xattr.h" "ac_cv_header_linux_xattr_h" "$ac_includes_default"
+if test "x$ac_cv_header_linux_xattr_h" = xyes; then :
+ true
+else
+ enable_smack="no"
+fi
+
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+if test "$enable_smack" = "yes"; then
+ ac_fn_c_check_header_mongrel "$LINENO" "attr/xattr.h" "ac_cv_header_attr_xattr_h" "$ac_includes_default"
+if test "x$ac_cv_header_attr_xattr_h" = xyes; then :
+ true
+else
+ enable_smack="no"
+fi
+
+
+fi
+if test "$enable_smack" = "yes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for XATTR_NAME_SMACKEXEC in linux/xattr.h" >&5
+$as_echo_n "checking for XATTR_NAME_SMACKEXEC in linux/xattr.h... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <linux/xattr.h>
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "XATTR_NAME_SMACKEXEC" >/dev/null 2>&1; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }; enable_smack="no"
+fi
+rm -f conftest*
+
+fi
+if test "$enable_smack" = "yes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for setxattr in -lattr" >&5
+$as_echo_n "checking for setxattr in -lattr... " >&6; }
+if ${ac_cv_lib_attr_setxattr+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lattr $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char setxattr ();
+int
+main ()
+{
+return setxattr ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_attr_setxattr=yes
+else
+ ac_cv_lib_attr_setxattr=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_attr_setxattr" >&5
+$as_echo "$ac_cv_lib_attr_setxattr" >&6; }
+if test "x$ac_cv_lib_attr_setxattr" = xyes; then :
+ LIBS="$LIBS -lattr"
+ found_smack="yes"
+ $as_echo "#define HAVE_SMACK 1" >>confdefs.h
+
+fi
+
+fi
+
+if test "x$found_smack" = "x"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking --disable-selinux argument" >&5
+$as_echo_n "checking --disable-selinux argument... " >&6; }
+ # Check whether --enable-selinux was given.
+if test "${enable_selinux+set}" = set; then :
+ enableval=$enable_selinux;
+else
+ enable_selinux="yes"
+fi
+
+ if test "$enable_selinux" = "yes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for is_selinux_enabled in -lselinux" >&5
+$as_echo_n "checking for is_selinux_enabled in -lselinux... " >&6; }
+if ${ac_cv_lib_selinux_is_selinux_enabled+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lselinux $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char is_selinux_enabled ();
+int
+main ()
+{
+return is_selinux_enabled ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_selinux_is_selinux_enabled=yes
+else
+ ac_cv_lib_selinux_is_selinux_enabled=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_selinux_is_selinux_enabled" >&5
+$as_echo "$ac_cv_lib_selinux_is_selinux_enabled" >&6; }
+if test "x$ac_cv_lib_selinux_is_selinux_enabled" = xyes; then :
+ ac_fn_c_check_header_mongrel "$LINENO" "selinux/selinux.h" "ac_cv_header_selinux_selinux_h" "$ac_includes_default"
+if test "x$ac_cv_header_selinux_selinux_h" = xyes; then :
+ LIBS="$LIBS -lselinux"
+ $as_echo "#define HAVE_SELINUX 1" >>confdefs.h
+
+fi
+
+
+fi
+
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ fi
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --with-features argument" >&5
+$as_echo_n "checking --with-features argument... " >&6; }
+
+# Check whether --with-features was given.
+if test "${with_features+set}" = set; then :
+ withval=$with_features; features="$withval"; { $as_echo "$as_me:${as_lineno-$LINENO}: result: $features" >&5
+$as_echo "$features" >&6; }
+else
+ features="huge"; { $as_echo "$as_me:${as_lineno-$LINENO}: result: Defaulting to huge" >&5
+$as_echo "Defaulting to huge" >&6; }
+fi
+
+
+dovimdiff=""
+dogvimdiff=""
+case "$features" in
+ tiny) $as_echo "#define FEAT_TINY 1" >>confdefs.h
+ ;;
+ small) $as_echo "#define FEAT_SMALL 1" >>confdefs.h
+ ;;
+ normal) $as_echo "#define FEAT_NORMAL 1" >>confdefs.h
+ dovimdiff="installvimdiff";
+ dogvimdiff="installgvimdiff" ;;
+ big) $as_echo "#define FEAT_BIG 1" >>confdefs.h
+ dovimdiff="installvimdiff";
+ dogvimdiff="installgvimdiff" ;;
+ huge) $as_echo "#define FEAT_HUGE 1" >>confdefs.h
+ dovimdiff="installvimdiff";
+ dogvimdiff="installgvimdiff" ;;
+ *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: Sorry, $features is not supported" >&5
+$as_echo "Sorry, $features is not supported" >&6; } ;;
+esac
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --with-compiledby argument" >&5
+$as_echo_n "checking --with-compiledby argument... " >&6; }
+
+# Check whether --with-compiledby was given.
+if test "${with_compiledby+set}" = set; then :
+ withval=$with_compiledby; compiledby="$withval"; { $as_echo "$as_me:${as_lineno-$LINENO}: result: $withval" >&5
+$as_echo "$withval" >&6; }
+else
+ compiledby=""; { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --disable-xsmp argument" >&5
+$as_echo_n "checking --disable-xsmp argument... " >&6; }
+# Check whether --enable-xsmp was given.
+if test "${enable_xsmp+set}" = set; then :
+ enableval=$enable_xsmp;
+else
+ enable_xsmp="yes"
+fi
+
+
+if test "$enable_xsmp" = "yes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking --disable-xsmp-interact argument" >&5
+$as_echo_n "checking --disable-xsmp-interact argument... " >&6; }
+ # Check whether --enable-xsmp-interact was given.
+if test "${enable_xsmp_interact+set}" = set; then :
+ enableval=$enable_xsmp_interact;
+else
+ enable_xsmp_interact="yes"
+fi
+
+ if test "$enable_xsmp_interact" = "yes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ $as_echo "#define USE_XSMP_INTERACT 1" >>confdefs.h
+
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --enable-luainterp argument" >&5
+$as_echo_n "checking --enable-luainterp argument... " >&6; }
+# Check whether --enable-luainterp was given.
+if test "${enable_luainterp+set}" = set; then :
+ enableval=$enable_luainterp;
+else
+ enable_luainterp="no"
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_luainterp" >&5
+$as_echo "$enable_luainterp" >&6; }
+
+if test "$enable_luainterp" = "yes" -o "$enable_luainterp" = "dynamic"; then
+ if test "x$features" = "xtiny" -o "x$features" = "xsmall"; then
+ as_fn_error $? "cannot use Lua with tiny or small features" "$LINENO" 5
+ fi
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking --with-lua-prefix argument" >&5
+$as_echo_n "checking --with-lua-prefix argument... " >&6; }
+
+# Check whether --with-lua_prefix was given.
+if test "${with_lua_prefix+set}" = set; then :
+ withval=$with_lua_prefix; with_lua_prefix="$withval"; { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_lua_prefix" >&5
+$as_echo "$with_lua_prefix" >&6; }
+else
+ with_lua_prefix="";{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ if test "X$with_lua_prefix" != "X"; then
+ vi_cv_path_lua_pfx="$with_lua_prefix"
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking LUA_PREFIX environment var" >&5
+$as_echo_n "checking LUA_PREFIX environment var... " >&6; }
+ if test "X$LUA_PREFIX" != "X"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: \"$LUA_PREFIX\"" >&5
+$as_echo "\"$LUA_PREFIX\"" >&6; }
+ vi_cv_path_lua_pfx="$LUA_PREFIX"
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: not set, default to /usr" >&5
+$as_echo "not set, default to /usr" >&6; }
+ vi_cv_path_lua_pfx="/usr"
+ fi
+ fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking --with-luajit" >&5
+$as_echo_n "checking --with-luajit... " >&6; }
+
+# Check whether --with-luajit was given.
+if test "${with_luajit+set}" = set; then :
+ withval=$with_luajit; vi_cv_with_luajit="$withval"
+else
+ vi_cv_with_luajit="no"
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_with_luajit" >&5
+$as_echo "$vi_cv_with_luajit" >&6; }
+
+ LUA_INC=
+ if test "X$vi_cv_path_lua_pfx" != "X"; then
+ if test "x$vi_cv_with_luajit" != "xno"; then
+ # Extract the first word of "luajit", so it can be a program name with args.
+set dummy luajit; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_vi_cv_path_luajit+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $vi_cv_path_luajit in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_vi_cv_path_luajit="$vi_cv_path_luajit" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_vi_cv_path_luajit="$as_dir/$ac_word$ac_exec_ext"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+fi
+vi_cv_path_luajit=$ac_cv_path_vi_cv_path_luajit
+if test -n "$vi_cv_path_luajit"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_path_luajit" >&5
+$as_echo "$vi_cv_path_luajit" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ if test "X$vi_cv_path_luajit" != "X"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking LuaJIT version" >&5
+$as_echo_n "checking LuaJIT version... " >&6; }
+if ${vi_cv_version_luajit+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ vi_cv_version_luajit=`${vi_cv_path_luajit} -v 2>&1 | sed 's/LuaJIT \([0-9.]*\)\.[0-9]\(-[a-z0-9]*\)* .*/\1/'`
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_version_luajit" >&5
+$as_echo "$vi_cv_version_luajit" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking Lua version of LuaJIT" >&5
+$as_echo_n "checking Lua version of LuaJIT... " >&6; }
+if ${vi_cv_version_lua_luajit+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ vi_cv_version_lua_luajit=`${vi_cv_path_luajit} -e "print(_VERSION)" | sed 's/.* //'`
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_version_lua_luajit" >&5
+$as_echo "$vi_cv_version_lua_luajit" >&6; }
+ vi_cv_path_lua="$vi_cv_path_luajit"
+ vi_cv_version_lua="$vi_cv_version_lua_luajit"
+ fi
+ else
+ # Extract the first word of "lua", so it can be a program name with args.
+set dummy lua; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_vi_cv_path_plain_lua+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $vi_cv_path_plain_lua in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_vi_cv_path_plain_lua="$vi_cv_path_plain_lua" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_vi_cv_path_plain_lua="$as_dir/$ac_word$ac_exec_ext"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+fi
+vi_cv_path_plain_lua=$ac_cv_path_vi_cv_path_plain_lua
+if test -n "$vi_cv_path_plain_lua"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_path_plain_lua" >&5
+$as_echo "$vi_cv_path_plain_lua" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ if test "X$vi_cv_path_plain_lua" != "X"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking Lua version" >&5
+$as_echo_n "checking Lua version... " >&6; }
+if ${vi_cv_version_plain_lua+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ vi_cv_version_plain_lua=`${vi_cv_path_plain_lua} -e "print(_VERSION)" | sed 's/.* //'`
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_version_plain_lua" >&5
+$as_echo "$vi_cv_version_plain_lua" >&6; }
+ fi
+ vi_cv_path_lua="$vi_cv_path_plain_lua"
+ vi_cv_version_lua="$vi_cv_version_plain_lua"
+ fi
+ if test "x$vi_cv_with_luajit" != "xno" && test "X$vi_cv_version_luajit" != "X"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if lua.h can be found in $vi_cv_path_lua_pfx/include/luajit-$vi_cv_version_luajit" >&5
+$as_echo_n "checking if lua.h can be found in $vi_cv_path_lua_pfx/include/luajit-$vi_cv_version_luajit... " >&6; }
+ if test -f "$vi_cv_path_lua_pfx/include/luajit-$vi_cv_version_luajit/lua.h"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ LUA_INC=/luajit-$vi_cv_version_luajit
+ fi
+ fi
+ if test "X$LUA_INC" = "X"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if lua.h can be found in $vi_cv_path_lua_pfx/include" >&5
+$as_echo_n "checking if lua.h can be found in $vi_cv_path_lua_pfx/include... " >&6; }
+ if test -f "$vi_cv_path_lua_pfx/include/lua.h"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if lua.h can be found in $vi_cv_path_lua_pfx/include/lua$vi_cv_version_lua" >&5
+$as_echo_n "checking if lua.h can be found in $vi_cv_path_lua_pfx/include/lua$vi_cv_version_lua... " >&6; }
+ if test -f "$vi_cv_path_lua_pfx/include/lua$vi_cv_version_lua/lua.h"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ LUA_INC=/lua$vi_cv_version_lua
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ vi_cv_path_lua_pfx=
+ fi
+ fi
+ fi
+ fi
+
+ if test "X$vi_cv_path_lua_pfx" != "X"; then
+ if test "x$vi_cv_with_luajit" != "xno"; then
+ multiarch=`dpkg-architecture -qDEB_HOST_MULTIARCH 2> /dev/null`
+ if test "X$multiarch" != "X"; then
+ lib_multiarch="lib/${multiarch}"
+ else
+ lib_multiarch="lib"
+ fi
+ if test "X$vi_cv_version_lua" = "X"; then
+ LUA_LIBS="-L${vi_cv_path_lua_pfx}/${lib_multiarch} -lluajit"
+ else
+ LUA_LIBS="-L${vi_cv_path_lua_pfx}/${lib_multiarch} -lluajit-$vi_cv_version_lua"
+ fi
+ else
+ if test "X$LUA_INC" != "X"; then
+ LUA_LIBS="-L${vi_cv_path_lua_pfx}/lib -llua$vi_cv_version_lua"
+ else
+ LUA_LIBS="-L${vi_cv_path_lua_pfx}/lib -llua"
+ fi
+ fi
+ if test "$enable_luainterp" = "dynamic"; then
+ lua_ok="yes"
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if link with ${LUA_LIBS} is sane" >&5
+$as_echo_n "checking if link with ${LUA_LIBS} is sane... " >&6; }
+ libs_save=$LIBS
+ LIBS="$LIBS $LUA_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }; lua_ok="yes"
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }; lua_ok="no"; LUA_LIBS=""
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LIBS=$libs_save
+ fi
+ if test "x$lua_ok" = "xyes"; then
+ LUA_CFLAGS="-I${vi_cv_path_lua_pfx}/include${LUA_INC}"
+ LUA_SRC="if_lua.c"
+ LUA_OBJ="objects/if_lua.o"
+ LUA_PRO="if_lua.pro"
+ $as_echo "#define FEAT_LUA 1" >>confdefs.h
+
+ fi
+ if test "$enable_luainterp" = "dynamic"; then
+ if test "x$vi_cv_with_luajit" != "xno"; then
+ luajit="jit"
+ fi
+ if test -f "${vi_cv_path_lua_pfx}/bin/cyglua-${vi_cv_version_lua}.dll"; then
+ vi_cv_dll_name_lua="cyglua-${vi_cv_version_lua}.dll"
+ else
+ if test "x$MACOS_X" = "xyes"; then
+ ext="dylib"
+ indexes=""
+ else
+ ext="so"
+ indexes=".0 .1 .2 .3 .4 .5 .6 .7 .8 .9"
+ multiarch=`dpkg-architecture -qDEB_HOST_MULTIARCH 2> /dev/null`
+ if test "X$multiarch" != "X"; then
+ lib_multiarch="lib/${multiarch}"
+ fi
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if liblua${luajit}*.${ext}* can be found in $vi_cv_path_lua_pfx" >&5
+$as_echo_n "checking if liblua${luajit}*.${ext}* can be found in $vi_cv_path_lua_pfx... " >&6; }
+ for subdir in "${lib_multiarch}" lib64 lib; do
+ if test -z "$subdir"; then
+ continue
+ fi
+ for sover in "${vi_cv_version_lua}.${ext}" "-${vi_cv_version_lua}.${ext}" \
+ ".${vi_cv_version_lua}.${ext}" ".${ext}.${vi_cv_version_lua}"; do
+ for i in $indexes ""; do
+ if test -f "${vi_cv_path_lua_pfx}/${subdir}/liblua${luajit}${sover}$i"; then
+ sover2="$i"
+ break 3
+ fi
+ done
+ done
+ sover=""
+ done
+ if test "X$sover" = "X"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ lua_ok="no"
+ vi_cv_dll_name_lua="liblua${luajit}.${ext}"
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ lua_ok="yes"
+ vi_cv_dll_name_lua="liblua${luajit}${sover}$sover2"
+ fi
+ fi
+ $as_echo "#define DYNAMIC_LUA 1" >>confdefs.h
+
+ LUA_LIBS=""
+ LUA_CFLAGS="-DDYNAMIC_LUA_DLL=\\\"${vi_cv_dll_name_lua}\\\" $LUA_CFLAGS"
+ fi
+ if test "X$LUA_CFLAGS$LUA_LIBS" != "X" && \
+ test "x$MACOS_X" = "xyes" && test "x$vi_cv_with_luajit" != "xno" && \
+ test "`(uname -m) 2>/dev/null`" = "x86_64"; then
+ LUA_LIBS="-pagezero_size 10000 -image_base 100000000 $LUA_LIBS"
+ fi
+ fi
+ if test "$fail_if_missing" = "yes" -a "$lua_ok" != "yes"; then
+ as_fn_error $? "could not configure lua" "$LINENO" 5
+ fi
+
+
+
+
+
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --enable-mzschemeinterp argument" >&5
+$as_echo_n "checking --enable-mzschemeinterp argument... " >&6; }
+# Check whether --enable-mzschemeinterp was given.
+if test "${enable_mzschemeinterp+set}" = set; then :
+ enableval=$enable_mzschemeinterp;
+else
+ enable_mzschemeinterp="no"
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_mzschemeinterp" >&5
+$as_echo "$enable_mzschemeinterp" >&6; }
+
+if test "$enable_mzschemeinterp" = "yes"; then
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking --with-plthome argument" >&5
+$as_echo_n "checking --with-plthome argument... " >&6; }
+
+# Check whether --with-plthome was given.
+if test "${with_plthome+set}" = set; then :
+ withval=$with_plthome; with_plthome="$withval"; { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_plthome" >&5
+$as_echo "$with_plthome" >&6; }
+else
+ with_plthome="";{ $as_echo "$as_me:${as_lineno-$LINENO}: result: \"no\"" >&5
+$as_echo "\"no\"" >&6; }
+fi
+
+
+ if test "X$with_plthome" != "X"; then
+ vi_cv_path_mzscheme_pfx="$with_plthome"
+ vi_cv_path_mzscheme="${vi_cv_path_mzscheme_pfx}/bin/mzscheme"
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking PLTHOME environment var" >&5
+$as_echo_n "checking PLTHOME environment var... " >&6; }
+ if test "X$PLTHOME" != "X"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: \"$PLTHOME\"" >&5
+$as_echo "\"$PLTHOME\"" >&6; }
+ vi_cv_path_mzscheme_pfx="$PLTHOME"
+ vi_cv_path_mzscheme="${vi_cv_path_mzscheme_pfx}/bin/mzscheme"
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: not set" >&5
+$as_echo "not set" >&6; }
+ # Extract the first word of "mzscheme", so it can be a program name with args.
+set dummy mzscheme; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_vi_cv_path_mzscheme+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $vi_cv_path_mzscheme in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_vi_cv_path_mzscheme="$vi_cv_path_mzscheme" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_vi_cv_path_mzscheme="$as_dir/$ac_word$ac_exec_ext"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+fi
+vi_cv_path_mzscheme=$ac_cv_path_vi_cv_path_mzscheme
+if test -n "$vi_cv_path_mzscheme"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_path_mzscheme" >&5
+$as_echo "$vi_cv_path_mzscheme" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+ if test "X$vi_cv_path_mzscheme" != "X"; then
+ lsout=`ls -l $vi_cv_path_mzscheme`
+ if echo "$lsout" | grep -e '->' >/dev/null 2>/dev/null; then
+ vi_cv_path_mzscheme=`echo "$lsout" | sed 's/.*-> \(.*\)/\1/'`
+ fi
+ fi
+
+ if test "X$vi_cv_path_mzscheme" != "X"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking MzScheme install prefix" >&5
+$as_echo_n "checking MzScheme install prefix... " >&6; }
+if ${vi_cv_path_mzscheme_pfx+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ echo "(display (simplify-path \
+ (build-path (call-with-values \
+ (lambda () (split-path (find-system-path (quote exec-file)))) \
+ (lambda (base name must-be-dir?) base)) (quote up))))" > mzdirs.scm
+ vi_cv_path_mzscheme_pfx=`${vi_cv_path_mzscheme} -r mzdirs.scm | \
+ sed -e 's+/$++'`
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_path_mzscheme_pfx" >&5
+$as_echo "$vi_cv_path_mzscheme_pfx" >&6; }
+ rm -f mzdirs.scm
+ fi
+ fi
+ fi
+
+ if test "X$vi_cv_path_mzscheme_pfx" != "X"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for racket include directory" >&5
+$as_echo_n "checking for racket include directory... " >&6; }
+ SCHEME_INC=`${vi_cv_path_mzscheme} -e '(require setup/dirs)(let ((p (find-include-dir))) (when (path? p) (display p)))'`
+ if test "X$SCHEME_INC" != "X"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${SCHEME_INC}" >&5
+$as_echo "${SCHEME_INC}" >&6; }
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5
+$as_echo "not found" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if scheme.h can be found in $vi_cv_path_mzscheme_pfx/include" >&5
+$as_echo_n "checking if scheme.h can be found in $vi_cv_path_mzscheme_pfx/include... " >&6; }
+ if test -f "$vi_cv_path_mzscheme_pfx/include/scheme.h"; then
+ SCHEME_INC=${vi_cv_path_mzscheme_pfx}/include
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if scheme.h can be found in $vi_cv_path_mzscheme_pfx/include/plt" >&5
+$as_echo_n "checking if scheme.h can be found in $vi_cv_path_mzscheme_pfx/include/plt... " >&6; }
+ if test -f "$vi_cv_path_mzscheme_pfx/include/plt/scheme.h"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ SCHEME_INC=${vi_cv_path_mzscheme_pfx}/include/plt
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if scheme.h can be found in $vi_cv_path_mzscheme_pfx/include/racket" >&5
+$as_echo_n "checking if scheme.h can be found in $vi_cv_path_mzscheme_pfx/include/racket... " >&6; }
+ if test -f "$vi_cv_path_mzscheme_pfx/include/racket/scheme.h"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ SCHEME_INC=${vi_cv_path_mzscheme_pfx}/include/racket
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if scheme.h can be found in /usr/include/plt/" >&5
+$as_echo_n "checking if scheme.h can be found in /usr/include/plt/... " >&6; }
+ if test -f /usr/include/plt/scheme.h; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ SCHEME_INC=/usr/include/plt
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if scheme.h can be found in /usr/include/racket/" >&5
+$as_echo_n "checking if scheme.h can be found in /usr/include/racket/... " >&6; }
+ if test -f /usr/include/racket/scheme.h; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ SCHEME_INC=/usr/include/racket
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ vi_cv_path_mzscheme_pfx=
+ fi
+ fi
+ fi
+ fi
+ fi
+ fi
+ fi
+
+ if test "X$vi_cv_path_mzscheme_pfx" != "X"; then
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for racket lib directory" >&5
+$as_echo_n "checking for racket lib directory... " >&6; }
+ SCHEME_LIB=`${vi_cv_path_mzscheme} -e '(require setup/dirs)(let ((p (find-lib-dir))) (when (path? p) (display p)))'`
+ if test "X$SCHEME_LIB" != "X"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${SCHEME_LIB}" >&5
+$as_echo "${SCHEME_LIB}" >&6; }
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5
+$as_echo "not found" >&6; }
+ fi
+
+ for path in "${vi_cv_path_mzscheme_pfx}/lib" "${SCHEME_LIB}"; do
+ if test "X$path" != "X"; then
+ if test "x$MACOS_X" = "xyes"; then
+ MZSCHEME_LIBS="-framework Racket"
+ MZSCHEME_CFLAGS="-DMZ_PRECISE_GC"
+ elif test -f "${path}/libmzscheme3m.a"; then
+ MZSCHEME_LIBS="${path}/libmzscheme3m.a"
+ MZSCHEME_CFLAGS="-DMZ_PRECISE_GC"
+ elif test -f "${path}/libracket3m.a"; then
+ MZSCHEME_LIBS="${path}/libracket3m.a"
+ MZSCHEME_CFLAGS="-DMZ_PRECISE_GC"
+ elif test -f "${path}/libracket.a"; then
+ MZSCHEME_LIBS="${path}/libracket.a ${path}/libmzgc.a"
+ elif test -f "${path}/libmzscheme.a"; then
+ MZSCHEME_LIBS="${path}/libmzscheme.a ${path}/libmzgc.a"
+ else
+ if test -f "${path}/libmzscheme3m.so"; then
+ MZSCHEME_LIBS="-L${path} -lmzscheme3m"
+ MZSCHEME_CFLAGS="-DMZ_PRECISE_GC"
+ elif test -f "${path}/libracket3m.so"; then
+ MZSCHEME_LIBS="-L${path} -lracket3m"
+ MZSCHEME_CFLAGS="-DMZ_PRECISE_GC"
+ elif test -f "${path}/libracket.so"; then
+ MZSCHEME_LIBS="-L${path} -lracket -lmzgc"
+ else
+ if test "$path" != "$SCHEME_LIB"; then
+ continue
+ fi
+ MZSCHEME_LIBS="-L${path} -lmzscheme -lmzgc"
+ fi
+ if test "$GCC" = yes; then
+ MZSCHEME_LIBS="${MZSCHEME_LIBS} -Wl,-rpath -Wl,${path}"
+ elif test "`(uname) 2>/dev/null`" = SunOS &&
+ uname -r | grep '^5' >/dev/null; then
+ MZSCHEME_LIBS="${MZSCHEME_LIBS} -R ${path}"
+ fi
+ fi
+ fi
+ if test "X$MZSCHEME_LIBS" != "X"; then
+ break
+ fi
+ done
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if racket requires -pthread" >&5
+$as_echo_n "checking if racket requires -pthread... " >&6; }
+ if test "X$SCHEME_LIB" != "X" && $FGREP -e -pthread "$SCHEME_LIB/buildinfo" >/dev/null ; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ MZSCHEME_LIBS="${MZSCHEME_LIBS} -pthread"
+ MZSCHEME_CFLAGS="${MZSCHEME_CFLAGS} -pthread"
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for racket config directory" >&5
+$as_echo_n "checking for racket config directory... " >&6; }
+ SCHEME_CONFIGDIR=`${vi_cv_path_mzscheme} -e '(require setup/dirs)(let ((p (find-config-dir))) (when (path? p) (display p)))'`
+ if test "X$SCHEME_CONFIGDIR" != "X"; then
+ MZSCHEME_CFLAGS="${MZSCHEME_CFLAGS} -DMZSCHEME_CONFIGDIR='\"${SCHEME_CONFIGDIR}\"'"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${SCHEME_CONFIGDIR}" >&5
+$as_echo "${SCHEME_CONFIGDIR}" >&6; }
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5
+$as_echo "not found" >&6; }
+ fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for racket collects directory" >&5
+$as_echo_n "checking for racket collects directory... " >&6; }
+ SCHEME_COLLECTS=`${vi_cv_path_mzscheme} -e '(require setup/dirs)(let ((p (find-collects-dir))) (when (path? p) (let-values (((base _1 _2) (split-path p))) (display base))))'`
+ if test "X$SCHEME_COLLECTS" = "X"; then
+ if test -d "$vi_cv_path_mzscheme_pfx/lib/plt/collects"; then
+ SCHEME_COLLECTS=$vi_cv_path_mzscheme_pfx/lib/plt/
+ else
+ if test -d "$vi_cv_path_mzscheme_pfx/lib/racket/collects"; then
+ SCHEME_COLLECTS=$vi_cv_path_mzscheme_pfx/lib/racket/
+ else
+ if test -d "$vi_cv_path_mzscheme_pfx/share/racket/collects"; then
+ SCHEME_COLLECTS=$vi_cv_path_mzscheme_pfx/share/racket/
+ else
+ if test -d "$vi_cv_path_mzscheme_pfx/collects"; then
+ SCHEME_COLLECTS=$vi_cv_path_mzscheme_pfx/
+ fi
+ fi
+ fi
+ fi
+ fi
+ if test "X$SCHEME_COLLECTS" != "X" ; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${SCHEME_COLLECTS}" >&5
+$as_echo "${SCHEME_COLLECTS}" >&6; }
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5
+$as_echo "not found" >&6; }
+ fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mzscheme_base.c" >&5
+$as_echo_n "checking for mzscheme_base.c... " >&6; }
+ if test -f "${SCHEME_COLLECTS}collects/scheme/base.ss" ; then
+ MZSCHEME_EXTRA="mzscheme_base.c"
+ MZSCHEME_MZC="${vi_cv_path_mzscheme_pfx}/bin/mzc"
+ MZSCHEME_MOD="++lib scheme/base"
+ else
+ if test -f "${SCHEME_COLLECTS}collects/scheme/base.rkt" ; then
+ MZSCHEME_EXTRA="mzscheme_base.c"
+ MZSCHEME_MZC="${vi_cv_path_mzscheme_pfx}/bin/mzc"
+ MZSCHEME_MOD="++lib scheme/base"
+ else
+ if test -f "${SCHEME_COLLECTS}collects/racket/base.rkt" ; then
+ MZSCHEME_EXTRA="mzscheme_base.c"
+ MZSCHEME_MZC="${vi_cv_path_mzscheme_pfx}/bin/raco ctool"
+ MZSCHEME_MOD=""
+ fi
+ fi
+ fi
+ if test "X$MZSCHEME_EXTRA" != "X" ; then
+ MZSCHEME_CFLAGS="${MZSCHEME_CFLAGS} -DINCLUDE_MZSCHEME_BASE"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: needed" >&5
+$as_echo "needed" >&6; }
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: not needed" >&5
+$as_echo "not needed" >&6; }
+ fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ffi_type_void in -lffi" >&5
+$as_echo_n "checking for ffi_type_void in -lffi... " >&6; }
+if ${ac_cv_lib_ffi_ffi_type_void+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lffi $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char ffi_type_void ();
+int
+main ()
+{
+return ffi_type_void ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_ffi_ffi_type_void=yes
+else
+ ac_cv_lib_ffi_ffi_type_void=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ffi_ffi_type_void" >&5
+$as_echo "$ac_cv_lib_ffi_ffi_type_void" >&6; }
+if test "x$ac_cv_lib_ffi_ffi_type_void" = xyes; then :
+ MZSCHEME_LIBS="$MZSCHEME_LIBS -lffi"
+fi
+
+
+ MZSCHEME_CFLAGS="${MZSCHEME_CFLAGS} -I${SCHEME_INC} \
+ -DMZSCHEME_COLLECTS='\"${SCHEME_COLLECTS}collects\"'"
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if compile and link flags for MzScheme are sane" >&5
+$as_echo_n "checking if compile and link flags for MzScheme are sane... " >&6; }
+ cflags_save=$CFLAGS
+ libs_save=$LIBS
+ CFLAGS="$CFLAGS $MZSCHEME_CFLAGS"
+ LIBS="$LIBS $MZSCHEME_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }; mzs_ok=yes
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no: MZSCHEME DISABLED" >&5
+$as_echo "no: MZSCHEME DISABLED" >&6; }; mzs_ok=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ CFLAGS=$cflags_save
+ LIBS=$libs_save
+ if test $mzs_ok = yes; then
+ MZSCHEME_SRC="if_mzsch.c"
+ MZSCHEME_OBJ="objects/if_mzsch.o"
+ MZSCHEME_PRO="if_mzsch.pro"
+ $as_echo "#define FEAT_MZSCHEME 1" >>confdefs.h
+
+ else
+ MZSCHEME_CFLAGS=
+ MZSCHEME_LIBS=
+ MZSCHEME_EXTRA=
+ MZSCHEME_MZC=
+ fi
+ fi
+
+
+
+
+
+
+
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --enable-perlinterp argument" >&5
+$as_echo_n "checking --enable-perlinterp argument... " >&6; }
+# Check whether --enable-perlinterp was given.
+if test "${enable_perlinterp+set}" = set; then :
+ enableval=$enable_perlinterp;
+else
+ enable_perlinterp="no"
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_perlinterp" >&5
+$as_echo "$enable_perlinterp" >&6; }
+if test "$enable_perlinterp" = "yes" -o "$enable_perlinterp" = "dynamic"; then
+ if test "x$features" = "xtiny" -o "x$features" = "xsmall"; then
+ as_fn_error $? "cannot use Perl with tiny or small features" "$LINENO" 5
+ fi
+
+ # Extract the first word of "perl", so it can be a program name with args.
+set dummy perl; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_vi_cv_path_perl+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $vi_cv_path_perl in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_vi_cv_path_perl="$vi_cv_path_perl" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_vi_cv_path_perl="$as_dir/$ac_word$ac_exec_ext"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+fi
+vi_cv_path_perl=$ac_cv_path_vi_cv_path_perl
+if test -n "$vi_cv_path_perl"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_path_perl" >&5
+$as_echo "$vi_cv_path_perl" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ if test "X$vi_cv_path_perl" != "X"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking Perl version" >&5
+$as_echo_n "checking Perl version... " >&6; }
+ if $vi_cv_path_perl -e 'require 5.003_01' >/dev/null 2>/dev/null; then
+ eval `$vi_cv_path_perl -V:usethreads`
+ eval `$vi_cv_path_perl -V:libperl`
+ if test "X$usethreads" = "XUNKNOWN" -o "X$usethreads" = "Xundef"; then
+ badthreads=no
+ else
+ if $vi_cv_path_perl -e 'require 5.6.0' >/dev/null 2>/dev/null; then
+ eval `$vi_cv_path_perl -V:use5005threads`
+ if test "X$use5005threads" = "XUNKNOWN" -o "X$use5005threads" = "Xundef"; then
+ badthreads=no
+ else
+ badthreads=yes
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: >>> Perl > 5.6 with 5.5 threads cannot be used <<<" >&5
+$as_echo ">>> Perl > 5.6 with 5.5 threads cannot be used <<<" >&6; }
+ fi
+ else
+ badthreads=yes
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: >>> Perl 5.5 with threads cannot be used <<<" >&5
+$as_echo ">>> Perl 5.5 with threads cannot be used <<<" >&6; }
+ fi
+ fi
+ if test $badthreads = no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: OK" >&5
+$as_echo "OK" >&6; }
+ eval `$vi_cv_path_perl -V:shrpenv`
+ if test "X$shrpenv" = "XUNKNOWN"; then # pre 5.003_04
+ shrpenv=""
+ fi
+ vi_cv_perllib=`$vi_cv_path_perl -MConfig -e 'print $Config{privlibexp}'`
+
+ vi_cv_perl_extutils=unknown_perl_extutils_path
+ for extutils_rel_path in ExtUtils vendor_perl/ExtUtils; do
+ xsubpp_path="$vi_cv_perllib/$extutils_rel_path/xsubpp"
+ if test -f "$xsubpp_path"; then
+ vi_cv_perl_xsubpp="$xsubpp_path"
+ fi
+ done
+
+ perlcppflags=`$vi_cv_path_perl -Mlib=$srcdir -MExtUtils::Embed \
+ -e 'ccflags;perl_inc;print"\n"' | sed -e 's/-fno[^ ]*//' \
+ -e 's/-fdebug-prefix-map[^ ]*//g' \
+ -e 's/-pipe //' \
+ -e 's/-W[^ ]*//g' \
+ -e 's/-D_FORTIFY_SOURCE=.//g'`
+ perllibs=`cd $srcdir; $vi_cv_path_perl -MExtUtils::Embed -e 'ldopts' | \
+ sed -e '/Warning/d' -e '/Note (probably harmless)/d' \
+ -e 's/-bE:perl.exp//' -e 's/-lc //'`
+ perlldflags=`cd $srcdir; $vi_cv_path_perl -MExtUtils::Embed \
+ -e 'ccdlflags' | sed -e 's/-bE:perl.exp//'`
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if compile and link flags for Perl are sane" >&5
+$as_echo_n "checking if compile and link flags for Perl are sane... " >&6; }
+ cflags_save=$CFLAGS
+ libs_save=$LIBS
+ ldflags_save=$LDFLAGS
+ CFLAGS="$CFLAGS $perlcppflags"
+ LIBS="$LIBS $perllibs"
+ perlldflags=`echo "$perlldflags" | sed -e 's/^ *//g'`
+ LDFLAGS="$perlldflags $LDFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }; perl_ok=yes
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no: PERL DISABLED" >&5
+$as_echo "no: PERL DISABLED" >&6; }; perl_ok=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ CFLAGS=$cflags_save
+ LIBS=$libs_save
+ LDFLAGS=$ldflags_save
+ if test $perl_ok = yes; then
+ if test "X$perlcppflags" != "X"; then
+ PERL_CFLAGS=$perlcppflags
+ fi
+ if test "X$perlldflags" != "X"; then
+ if test "X`echo \"$LDFLAGS\" | $FGREP -e \"$perlldflags\"`" = "X"; then
+ LDFLAGS="$perlldflags $LDFLAGS"
+ fi
+ fi
+ PERL_LIBS=$perllibs
+ PERL_SRC="auto/if_perl.c if_perlsfio.c"
+ PERL_OBJ="objects/if_perl.o objects/if_perlsfio.o"
+ PERL_PRO="if_perl.pro if_perlsfio.pro"
+ $as_echo "#define FEAT_PERL 1" >>confdefs.h
+
+ fi
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: >>> too old; need Perl version 5.003_01 or later <<<" >&5
+$as_echo ">>> too old; need Perl version 5.003_01 or later <<<" >&6; }
+ fi
+ fi
+
+ if test "x$MACOS_X" = "xyes"; then
+ dir=/System/Library/Perl
+ darwindir=$dir/darwin
+ if test -d $darwindir; then
+ PERL=/usr/bin/perl
+ else
+ dir=/System/Library/Perl/5.8.1
+ darwindir=$dir/darwin-thread-multi-2level
+ if test -d $darwindir; then
+ PERL=/usr/bin/perl
+ fi
+ fi
+ if test -n "$PERL"; then
+ PERL_DIR="$dir"
+ PERL_CFLAGS="-DFEAT_PERL -I$darwindir/CORE"
+ PERL_OBJ="objects/if_perl.o objects/if_perlsfio.o $darwindir/auto/DynaLoader/DynaLoader.a"
+ PERL_LIBS="-L$darwindir/CORE -lperl"
+ fi
+ PERL_LIBS=`echo "$PERL_LIBS" | sed -e 's/-arch\ ppc//' -e 's/-arch\ i386//' -e 's/-arch\ x86_64//'`
+ PERL_CFLAGS=`echo "$PERL_CFLAGS" | sed -e 's/-arch\ ppc//' -e 's/-arch\ i386//' -e 's/-arch\ x86_64//'`
+ fi
+ if test "$enable_perlinterp" = "dynamic"; then
+ if test "$perl_ok" = "yes" -a "X$libperl" != "X"; then
+ $as_echo "#define DYNAMIC_PERL 1" >>confdefs.h
+
+ PERL_CFLAGS="-DDYNAMIC_PERL_DLL=\\\"$libperl\\\" $PERL_CFLAGS"
+ fi
+ fi
+
+ if test "$fail_if_missing" = "yes" -a "$perl_ok" != "yes"; then
+ as_fn_error $? "could not configure perl" "$LINENO" 5
+ fi
+fi
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --enable-pythoninterp argument" >&5
+$as_echo_n "checking --enable-pythoninterp argument... " >&6; }
+# Check whether --enable-pythoninterp was given.
+if test "${enable_pythoninterp+set}" = set; then :
+ enableval=$enable_pythoninterp;
+else
+ enable_pythoninterp="no"
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_pythoninterp" >&5
+$as_echo "$enable_pythoninterp" >&6; }
+if test "$enable_pythoninterp" = "yes" -o "$enable_pythoninterp" = "dynamic"; then
+ if test "x$features" = "xtiny" -o "x$features" = "xsmall"; then
+ as_fn_error $? "cannot use Python with tiny or small features" "$LINENO" 5
+ fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking --with-python-command argument" >&5
+$as_echo_n "checking --with-python-command argument... " >&6; }
+
+
+# Check whether --with-python-command was given.
+if test "${with_python_command+set}" = set; then :
+ withval=$with_python_command; vi_cv_path_python="$withval"; { $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_path_python" >&5
+$as_echo "$vi_cv_path_python" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ if test "X$vi_cv_path_python" = "X"; then
+ for ac_prog in python2 python
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_vi_cv_path_python+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $vi_cv_path_python in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_vi_cv_path_python="$vi_cv_path_python" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_vi_cv_path_python="$as_dir/$ac_word$ac_exec_ext"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+fi
+vi_cv_path_python=$ac_cv_path_vi_cv_path_python
+if test -n "$vi_cv_path_python"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_path_python" >&5
+$as_echo "$vi_cv_path_python" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$vi_cv_path_python" && break
+done
+
+ fi
+ if test "X$vi_cv_path_python" != "X"; then
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking Python version" >&5
+$as_echo_n "checking Python version... " >&6; }
+if ${vi_cv_var_python_version+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ vi_cv_var_python_version=`
+ ${vi_cv_path_python} -c 'import sys; print sys.version[:3]'`
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_var_python_version" >&5
+$as_echo "$vi_cv_var_python_version" >&6; }
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking Python is 2.3 or better" >&5
+$as_echo_n "checking Python is 2.3 or better... " >&6; }
+ if ${vi_cv_path_python} -c \
+ "import sys; sys.exit(${vi_cv_var_python_version} < 2.3)"
+ then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yep" >&5
+$as_echo "yep" >&6; }
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking Python's install prefix" >&5
+$as_echo_n "checking Python's install prefix... " >&6; }
+if ${vi_cv_path_python_pfx+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ vi_cv_path_python_pfx=`
+ ${vi_cv_path_python} -c \
+ "import sys; print sys.prefix"`
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_path_python_pfx" >&5
+$as_echo "$vi_cv_path_python_pfx" >&6; }
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking Python's execution prefix" >&5
+$as_echo_n "checking Python's execution prefix... " >&6; }
+if ${vi_cv_path_python_epfx+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ vi_cv_path_python_epfx=`
+ ${vi_cv_path_python} -c \
+ "import sys; print sys.exec_prefix"`
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_path_python_epfx" >&5
+$as_echo "$vi_cv_path_python_epfx" >&6; }
+
+
+ if ${vi_cv_path_pythonpath+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ vi_cv_path_pythonpath=`
+ unset PYTHONPATH;
+ ${vi_cv_path_python} -c \
+ "import sys, string; print string.join(sys.path,':')"`
+fi
+
+
+
+
+# Check whether --with-python-config-dir was given.
+if test "${with_python_config_dir+set}" = set; then :
+ withval=$with_python_config_dir; vi_cv_path_python_conf="${withval}"; have_python_config_dir=1
+fi
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking Python's configuration directory" >&5
+$as_echo_n "checking Python's configuration directory... " >&6; }
+if ${vi_cv_path_python_conf+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ vi_cv_path_python_conf=
+ d=`${vi_cv_path_python} -c "import distutils.sysconfig; print distutils.sysconfig.get_config_var('LIBPL')"`
+ if test -d "$d" && test -f "$d/config.c"; then
+ vi_cv_path_python_conf="$d"
+ else
+ for path in "${vi_cv_path_python_pfx}" "${vi_cv_path_python_epfx}"; do
+ for subdir in lib64 lib share; do
+ d="${path}/${subdir}/python${vi_cv_var_python_version}/config"
+ if test -d "$d" && test -f "$d/config.c"; then
+ vi_cv_path_python_conf="$d"
+ fi
+ done
+ done
+ fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_path_python_conf" >&5
+$as_echo "$vi_cv_path_python_conf" >&6; }
+
+ PYTHON_CONFDIR="${vi_cv_path_python_conf}"
+
+ if test "X$PYTHON_CONFDIR" = "X"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: can't find it!" >&5
+$as_echo "can't find it!" >&6; }
+ else
+
+ if ${vi_cv_path_python_plibs+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ pwd=`pwd`
+ tmp_mkf="$pwd/config-PyMake$$"
+ cat -- "${PYTHON_CONFDIR}/Makefile" - <<'eof' >"${tmp_mkf}"
+__:
+ @echo "python_BASEMODLIBS='$(BASEMODLIBS)'"
+ @echo "python_LIBS='$(LIBS)'"
+ @echo "python_SYSLIBS='$(SYSLIBS)'"
+ @echo "python_LINKFORSHARED='$(LINKFORSHARED)'"
+ @echo "python_DLLLIBRARY='$(DLLLIBRARY)'"
+ @echo "python_INSTSONAME='$(INSTSONAME)'"
+ @echo "python_PYTHONFRAMEWORK='$(PYTHONFRAMEWORK)'"
+ @echo "python_PYTHONFRAMEWORKPREFIX='$(PYTHONFRAMEWORKPREFIX)'"
+ @echo "python_PYTHONFRAMEWORKINSTALLDIR='$(PYTHONFRAMEWORKINSTALLDIR)'"
+eof
+ eval "`cd ${PYTHON_CONFDIR} && make -f "${tmp_mkf}" __ | sed '/ directory /d'`"
+ rm -f -- "${tmp_mkf}"
+ if test "x$MACOS_X" = "xyes" && test -n "${python_PYTHONFRAMEWORK}" && ${vi_cv_path_python} -c \
+ "import sys; sys.exit(${vi_cv_var_python_version} < 2.3)"; then
+ vi_cv_path_python_plibs="-framework Python"
+ if test "x${vi_cv_path_python}" != "x/usr/bin/python" && test -n "${python_PYTHONFRAMEWORKPREFIX}"; then
+ vi_cv_path_python_plibs="-F${python_PYTHONFRAMEWORKPREFIX} -framework Python"
+ fi
+ else
+ vi_cv_path_python_plibs="-L${PYTHON_CONFDIR} -lpython${vi_cv_var_python_version}"
+ if test -n "${python_LINKFORSHARED}" && test -n "${python_PYTHONFRAMEWORKPREFIX}"; then
+ python_link_symbol=`echo ${python_LINKFORSHARED} | sed 's/\([^ \t][^ \t]*[ \t][ \t]*[^ \t][^ \t]*\)[ \t].*/\1/'`
+ python_link_path=`echo ${python_LINKFORSHARED} | sed 's/\([^ \t][^ \t]*[ \t][ \t]*[^ \t][^ \t]*\)[ \t][ \t]*\(.*\)/\2/'`
+ if test -n "${python_link_path}" && ! test -x "${python_link_path}"; then
+ python_link_path="${python_PYTHONFRAMEWORKPREFIX}/${python_link_path}"
+ if test -n "${python_link_path}" && ! test -x "${python_link_path}"; then
+ python_link_path="${python_PYTHONFRAMEWORKINSTALLDIR}/Versions/${vi_cv_var_python_version}/${python_PYTHONFRAMEWORK}"
+ fi
+ python_LINKFORSHARED="${python_link_symbol} ${python_link_path}"
+ fi
+ fi
+ vi_cv_path_python_plibs="${vi_cv_path_python_plibs} ${python_BASEMODLIBS} ${python_LIBS} ${python_SYSLIBS} ${python_LINKFORSHARED}"
+ vi_cv_path_python_plibs=`echo $vi_cv_path_python_plibs | sed s/-ltermcap//`
+ fi
+
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking Python's dll name" >&5
+$as_echo_n "checking Python's dll name... " >&6; }
+if ${vi_cv_dll_name_python+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ if test "X$python_DLLLIBRARY" != "X"; then
+ vi_cv_dll_name_python="$python_DLLLIBRARY"
+ else
+ vi_cv_dll_name_python="$python_INSTSONAME"
+ fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_dll_name_python" >&5
+$as_echo "$vi_cv_dll_name_python" >&6; }
+
+ PYTHON_LIBS="${vi_cv_path_python_plibs}"
+ if test "${vi_cv_path_python_pfx}" = "${vi_cv_path_python_epfx}"; then
+ PYTHON_CFLAGS="-I${vi_cv_path_python_pfx}/include/python${vi_cv_var_python_version}"
+ else
+ PYTHON_CFLAGS="-I${vi_cv_path_python_pfx}/include/python${vi_cv_var_python_version} -I${vi_cv_path_python_epfx}/include/python${vi_cv_var_python_version}"
+ fi
+ if test "X$have_python_config_dir" = "X1" -a "$enable_pythoninterp" = "dynamic"; then
+ PYTHON_CFLAGS="${PYTHON_CFLAGS} -DPYTHON_HOME='\"${vi_cv_path_python_pfx}\"'"
+
+ fi
+ PYTHON_SRC="if_python.c"
+ PYTHON_OBJ="objects/if_python.o"
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if -pthread should be used" >&5
+$as_echo_n "checking if -pthread should be used... " >&6; }
+ threadsafe_flag=
+ thread_lib=
+ if test "`(uname) 2>/dev/null`" != Darwin; then
+ test "$GCC" = yes && threadsafe_flag="-pthread"
+ if test "`(uname) 2>/dev/null`" = FreeBSD; then
+ threadsafe_flag="-D_THREAD_SAFE"
+ thread_lib="-pthread"
+ fi
+ if test "`(uname) 2>/dev/null`" = SunOS; then
+ threadsafe_flag="-pthreads"
+ fi
+ fi
+ libs_save_old=$LIBS
+ if test -n "$threadsafe_flag"; then
+ cflags_save=$CFLAGS
+ CFLAGS="$CFLAGS $threadsafe_flag"
+ LIBS="$LIBS $thread_lib"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }; PYTHON_CFLAGS="$PYTHON_CFLAGS $threadsafe_flag"
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }; LIBS=$libs_save_old
+
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ CFLAGS=$cflags_save
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if compile and link flags for Python are sane" >&5
+$as_echo_n "checking if compile and link flags for Python are sane... " >&6; }
+ cflags_save=$CFLAGS
+ libs_save=$LIBS
+ CFLAGS="$CFLAGS $PYTHON_CFLAGS"
+ LIBS="$LIBS $PYTHON_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }; python_ok=yes
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no: PYTHON DISABLED" >&5
+$as_echo "no: PYTHON DISABLED" >&6; }; python_ok=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ CFLAGS=$cflags_save
+ LIBS=$libs_save
+ if test $python_ok = yes; then
+ $as_echo "#define FEAT_PYTHON 1" >>confdefs.h
+
+ else
+ LIBS=$libs_save_old
+ PYTHON_SRC=
+ PYTHON_OBJ=
+ PYTHON_LIBS=
+ PYTHON_CFLAGS=
+ fi
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: too old" >&5
+$as_echo "too old" >&6; }
+ fi
+ fi
+
+ if test "$fail_if_missing" = "yes" -a "$python_ok" != "yes"; then
+ as_fn_error $? "could not configure python" "$LINENO" 5
+ fi
+fi
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --enable-python3interp argument" >&5
+$as_echo_n "checking --enable-python3interp argument... " >&6; }
+# Check whether --enable-python3interp was given.
+if test "${enable_python3interp+set}" = set; then :
+ enableval=$enable_python3interp;
+else
+ enable_python3interp="no"
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_python3interp" >&5
+$as_echo "$enable_python3interp" >&6; }
+if test "$enable_python3interp" = "yes" -o "$enable_python3interp" = "dynamic"; then
+ if test "x$features" = "xtiny" -o "x$features" = "xsmall"; then
+ as_fn_error $? "cannot use Python with tiny or small features" "$LINENO" 5
+ fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking --with-python3-command argument" >&5
+$as_echo_n "checking --with-python3-command argument... " >&6; }
+
+
+# Check whether --with-python3-command was given.
+if test "${with_python3_command+set}" = set; then :
+ withval=$with_python3_command; vi_cv_path_python3="$withval"; { $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_path_python3" >&5
+$as_echo "$vi_cv_path_python3" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ if test "X$vi_cv_path_python3" = "X"; then
+ for ac_prog in python3 python
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_vi_cv_path_python3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $vi_cv_path_python3 in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_vi_cv_path_python3="$vi_cv_path_python3" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_vi_cv_path_python3="$as_dir/$ac_word$ac_exec_ext"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+fi
+vi_cv_path_python3=$ac_cv_path_vi_cv_path_python3
+if test -n "$vi_cv_path_python3"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_path_python3" >&5
+$as_echo "$vi_cv_path_python3" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$vi_cv_path_python3" && break
+done
+
+ fi
+ if test "X$vi_cv_path_python3" != "X"; then
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking Python version" >&5
+$as_echo_n "checking Python version... " >&6; }
+if ${vi_cv_var_python3_version+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ vi_cv_var_python3_version=`
+ ${vi_cv_path_python3} -c 'import sys; print(sys.version[:3])'`
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_var_python3_version" >&5
+$as_echo "$vi_cv_var_python3_version" >&6; }
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking Python is 3.0 or better" >&5
+$as_echo_n "checking Python is 3.0 or better... " >&6; }
+ if ${vi_cv_path_python3} -c \
+ "import sys; sys.exit(${vi_cv_var_python3_version} < 3.0)"
+ then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yep" >&5
+$as_echo "yep" >&6; }
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking Python's abiflags" >&5
+$as_echo_n "checking Python's abiflags... " >&6; }
+if ${vi_cv_var_python3_abiflags+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ vi_cv_var_python3_abiflags=
+ if ${vi_cv_path_python3} -c \
+ "import sys; sys.exit(${vi_cv_var_python3_version} < 3.2)"
+ then
+ vi_cv_var_python3_abiflags=`${vi_cv_path_python3} -c \
+ "import sys; print(sys.abiflags)"`
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_var_python3_abiflags" >&5
+$as_echo "$vi_cv_var_python3_abiflags" >&6; }
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking Python's install prefix" >&5
+$as_echo_n "checking Python's install prefix... " >&6; }
+if ${vi_cv_path_python3_pfx+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ vi_cv_path_python3_pfx=`
+ ${vi_cv_path_python3} -c \
+ "import sys; print(sys.prefix)"`
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_path_python3_pfx" >&5
+$as_echo "$vi_cv_path_python3_pfx" >&6; }
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking Python's execution prefix" >&5
+$as_echo_n "checking Python's execution prefix... " >&6; }
+if ${vi_cv_path_python3_epfx+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ vi_cv_path_python3_epfx=`
+ ${vi_cv_path_python3} -c \
+ "import sys; print(sys.exec_prefix)"`
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_path_python3_epfx" >&5
+$as_echo "$vi_cv_path_python3_epfx" >&6; }
+
+
+ if ${vi_cv_path_python3path+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ vi_cv_path_python3path=`
+ unset PYTHONPATH;
+ ${vi_cv_path_python3} -c \
+ "import sys, string; print(':'.join(sys.path))"`
+fi
+
+
+
+
+# Check whether --with-python3-config-dir was given.
+if test "${with_python3_config_dir+set}" = set; then :
+ withval=$with_python3_config_dir; vi_cv_path_python3_conf="${withval}"; have_python3_config_dir=1
+fi
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking Python's configuration directory" >&5
+$as_echo_n "checking Python's configuration directory... " >&6; }
+if ${vi_cv_path_python3_conf+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ vi_cv_path_python3_conf=
+ config_dir="config-${vi_cv_var_python3_version}${vi_cv_var_python3_abiflags}"
+ d=`${vi_cv_path_python3} -c "import distutils.sysconfig; print(distutils.sysconfig.get_config_var('LIBPL'))"`
+ if test -d "$d" && test -f "$d/config.c"; then
+ vi_cv_path_python3_conf="$d"
+ else
+ for path in "${vi_cv_path_python3_pfx}" "${vi_cv_path_python3_epfx}"; do
+ for subdir in lib64 lib share; do
+ d="${path}/${subdir}/python${vi_cv_var_python3_version}/${config_dir}"
+ if test -d "$d" && test -f "$d/config.c"; then
+ vi_cv_path_python3_conf="$d"
+ fi
+ done
+ done
+ fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_path_python3_conf" >&5
+$as_echo "$vi_cv_path_python3_conf" >&6; }
+
+ PYTHON3_CONFDIR="${vi_cv_path_python3_conf}"
+
+ if test "X$PYTHON3_CONFDIR" = "X"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: can't find it!" >&5
+$as_echo "can't find it!" >&6; }
+ else
+
+ if ${vi_cv_path_python3_plibs+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ pwd=`pwd`
+ tmp_mkf="$pwd/config-PyMake$$"
+ cat -- "${PYTHON3_CONFDIR}/Makefile" - <<'eof' >"${tmp_mkf}"
+__:
+ @echo "python3_BASEMODLIBS='$(BASEMODLIBS)'"
+ @echo "python3_LIBS='$(LIBS)'"
+ @echo "python3_SYSLIBS='$(SYSLIBS)'"
+ @echo "python3_DLLLIBRARY='$(DLLLIBRARY)'"
+ @echo "python3_INSTSONAME='$(INSTSONAME)'"
+eof
+ eval "`cd ${PYTHON3_CONFDIR} && make -f "${tmp_mkf}" __ | sed '/ directory /d'`"
+ rm -f -- "${tmp_mkf}"
+ vi_cv_path_python3_plibs="-L${PYTHON3_CONFDIR} -lpython${vi_cv_var_python3_version}${vi_cv_var_python3_abiflags}"
+ vi_cv_path_python3_plibs="${vi_cv_path_python3_plibs} ${python3_BASEMODLIBS} ${python3_LIBS} ${python3_SYSLIBS}"
+ vi_cv_path_python3_plibs=`echo $vi_cv_path_python3_plibs | sed s/-ltermcap//`
+ vi_cv_path_python3_plibs=`echo $vi_cv_path_python3_plibs | sed s/-lffi//`
+
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking Python3's dll name" >&5
+$as_echo_n "checking Python3's dll name... " >&6; }
+if ${vi_cv_dll_name_python3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ if test "X$python3_DLLLIBRARY" != "X"; then
+ vi_cv_dll_name_python3="$python3_DLLLIBRARY"
+ else
+ vi_cv_dll_name_python3="$python3_INSTSONAME"
+ fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_dll_name_python3" >&5
+$as_echo "$vi_cv_dll_name_python3" >&6; }
+
+ PYTHON3_LIBS="${vi_cv_path_python3_plibs}"
+ if test "${vi_cv_path_python3_pfx}" = "${vi_cv_path_python3_epfx}"; then
+ PYTHON3_CFLAGS="-I${vi_cv_path_python3_pfx}/include/python${vi_cv_var_python3_version}${vi_cv_var_python3_abiflags}"
+ else
+ PYTHON3_CFLAGS="-I${vi_cv_path_python3_pfx}/include/python${vi_cv_var_python3_version}${vi_cv_var_python3_abiflags} -I${vi_cv_path_python3_epfx}/include/python${vi_cv_var_python3_version}${vi_cv_var_python3_abiflags}"
+ fi
+ if test "X$have_python3_config_dir" = "X1" -a "$enable_python3interp" = "dynamic"; then
+ PYTHON3_CFLAGS="${PYTHON3_CFLAGS} -DPYTHON3_HOME='L\"${vi_cv_path_python3_pfx}\"'"
+ fi
+ PYTHON3_SRC="if_python3.c"
+ PYTHON3_OBJ="objects/if_python3.o"
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if -pthread should be used" >&5
+$as_echo_n "checking if -pthread should be used... " >&6; }
+ threadsafe_flag=
+ thread_lib=
+ if test "`(uname) 2>/dev/null`" != Darwin; then
+ test "$GCC" = yes && threadsafe_flag="-pthread"
+ if test "`(uname) 2>/dev/null`" = FreeBSD; then
+ threadsafe_flag="-D_THREAD_SAFE"
+ thread_lib="-pthread"
+ fi
+ if test "`(uname) 2>/dev/null`" = SunOS; then
+ threadsafe_flag="-pthreads"
+ fi
+ fi
+ libs_save_old=$LIBS
+ if test -n "$threadsafe_flag"; then
+ cflags_save=$CFLAGS
+ CFLAGS="$CFLAGS $threadsafe_flag"
+ LIBS="$LIBS $thread_lib"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }; PYTHON3_CFLAGS="$PYTHON3_CFLAGS $threadsafe_flag"
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }; LIBS=$libs_save_old
+
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ CFLAGS=$cflags_save
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if compile and link flags for Python 3 are sane" >&5
+$as_echo_n "checking if compile and link flags for Python 3 are sane... " >&6; }
+ cflags_save=$CFLAGS
+ libs_save=$LIBS
+ CFLAGS="$CFLAGS $PYTHON3_CFLAGS"
+ LIBS="$LIBS $PYTHON3_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }; python3_ok=yes
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no: PYTHON3 DISABLED" >&5
+$as_echo "no: PYTHON3 DISABLED" >&6; }; python3_ok=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ CFLAGS=$cflags_save
+ LIBS=$libs_save
+ if test "$python3_ok" = yes; then
+ $as_echo "#define FEAT_PYTHON3 1" >>confdefs.h
+
+ else
+ LIBS=$libs_save_old
+ PYTHON3_SRC=
+ PYTHON3_OBJ=
+ PYTHON3_LIBS=
+ PYTHON3_CFLAGS=
+ fi
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: too old" >&5
+$as_echo "too old" >&6; }
+ fi
+ fi
+ if test "$fail_if_missing" = "yes" -a "$python3_ok" != "yes"; then
+ as_fn_error $? "could not configure python3" "$LINENO" 5
+ fi
+fi
+
+
+
+
+
+
+if test "$python_ok" = yes && test "$python3_ok" = yes; then
+ $as_echo "#define DYNAMIC_PYTHON 1" >>confdefs.h
+
+ $as_echo "#define DYNAMIC_PYTHON3 1" >>confdefs.h
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we can do without RTLD_GLOBAL for Python" >&5
+$as_echo_n "checking whether we can do without RTLD_GLOBAL for Python... " >&6; }
+ cflags_save=$CFLAGS
+ CFLAGS="$CFLAGS $PYTHON_CFLAGS"
+ libs_save=$LIBS
+ LIBS="-ldl $LIBS"
+ if test "$cross_compiling" = yes; then :
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run test program while cross compiling
+See \`config.log' for more details" "$LINENO" 5; }
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <dlfcn.h>
+ /* If this program fails, then RTLD_GLOBAL is needed.
+ * RTLD_GLOBAL will be used and then it is not possible to
+ * have both python versions enabled in the same vim instance.
+ * Only the first python version used will be switched on.
+ */
+
+ int no_rtl_global_needed_for(char *python_instsoname, char *prefix)
+ {
+ int needed = 0;
+ void* pylib = dlopen(python_instsoname, RTLD_LAZY|RTLD_LOCAL);
+ if (pylib != 0)
+ {
+ void (*pfx)(char *home) = dlsym(pylib, "Py_SetPythonHome");
+ void (*init)(void) = dlsym(pylib, "Py_Initialize");
+ int (*simple)(char*) = dlsym(pylib, "PyRun_SimpleString");
+ void (*final)(void) = dlsym(pylib, "Py_Finalize");
+ (*pfx)(prefix);
+ (*init)();
+ needed = (*simple)("import termios") == -1;
+ (*final)();
+ dlclose(pylib);
+ }
+ return !needed;
+ }
+
+ int main(int argc, char** argv)
+ {
+ int not_needed = 0;
+ if (no_rtl_global_needed_for("${vi_cv_dll_name_python}", "${vi_cv_path_python_pfx}"))
+ not_needed = 1;
+ return !not_needed;
+ }
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; };$as_echo "#define PY_NO_RTLD_GLOBAL 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+
+ CFLAGS=$cflags_save
+ LIBS=$libs_save
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we can do without RTLD_GLOBAL for Python3" >&5
+$as_echo_n "checking whether we can do without RTLD_GLOBAL for Python3... " >&6; }
+ cflags_save=$CFLAGS
+ CFLAGS="$CFLAGS $PYTHON3_CFLAGS"
+ libs_save=$LIBS
+ LIBS="-ldl $LIBS"
+ if test "$cross_compiling" = yes; then :
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run test program while cross compiling
+See \`config.log' for more details" "$LINENO" 5; }
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <dlfcn.h>
+ #include <wchar.h>
+ /* If this program fails, then RTLD_GLOBAL is needed.
+ * RTLD_GLOBAL will be used and then it is not possible to
+ * have both python versions enabled in the same vim instance.
+ * Only the first python version used will be switched on.
+ */
+
+ int no_rtl_global_needed_for(char *python_instsoname, wchar_t *prefix)
+ {
+ int needed = 0;
+ void* pylib = dlopen(python_instsoname, RTLD_LAZY|RTLD_LOCAL);
+ if (pylib != 0)
+ {
+ void (*pfx)(wchar_t *home) = dlsym(pylib, "Py_SetPythonHome");
+ void (*init)(void) = dlsym(pylib, "Py_Initialize");
+ int (*simple)(char*) = dlsym(pylib, "PyRun_SimpleString");
+ void (*final)(void) = dlsym(pylib, "Py_Finalize");
+ (*pfx)(prefix);
+ (*init)();
+ needed = (*simple)("import termios") == -1;
+ (*final)();
+ dlclose(pylib);
+ }
+ return !needed;
+ }
+
+ int main(int argc, char** argv)
+ {
+ int not_needed = 0;
+ if (no_rtl_global_needed_for("${vi_cv_dll_name_python3}", L"${vi_cv_path_python3_pfx}"))
+ not_needed = 1;
+ return !not_needed;
+ }
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; };$as_echo "#define PY3_NO_RTLD_GLOBAL 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+
+ CFLAGS=$cflags_save
+ LIBS=$libs_save
+
+ PYTHON_SRC="if_python.c"
+ PYTHON_OBJ="objects/if_python.o"
+ PYTHON_CFLAGS="$PYTHON_CFLAGS -DDYNAMIC_PYTHON_DLL=\\\"${vi_cv_dll_name_python}\\\""
+ PYTHON_LIBS=
+ PYTHON3_SRC="if_python3.c"
+ PYTHON3_OBJ="objects/if_python3.o"
+ PYTHON3_CFLAGS="$PYTHON3_CFLAGS -DDYNAMIC_PYTHON3_DLL=\\\"${vi_cv_dll_name_python3}\\\""
+ PYTHON3_LIBS=
+elif test "$python_ok" = yes && test "$enable_pythoninterp" = "dynamic"; then
+ $as_echo "#define DYNAMIC_PYTHON 1" >>confdefs.h
+
+ PYTHON_SRC="if_python.c"
+ PYTHON_OBJ="objects/if_python.o"
+ PYTHON_CFLAGS="$PYTHON_CFLAGS -DDYNAMIC_PYTHON_DLL=\\\"${vi_cv_dll_name_python}\\\""
+ PYTHON_LIBS=
+elif test "$python_ok" = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if -fPIE can be added for Python" >&5
+$as_echo_n "checking if -fPIE can be added for Python... " >&6; }
+ cflags_save=$CFLAGS
+ libs_save=$LIBS
+ CFLAGS="$CFLAGS $PYTHON_CFLAGS -fPIE"
+ LIBS="$LIBS $PYTHON_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }; fpie_ok=yes
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }; fpie_ok=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ CFLAGS=$cflags_save
+ LIBS=$libs_save
+ if test $fpie_ok = yes; then
+ PYTHON_CFLAGS="$PYTHON_CFLAGS -fPIE"
+ fi
+elif test "$python3_ok" = yes && test "$enable_python3interp" = "dynamic"; then
+ $as_echo "#define DYNAMIC_PYTHON3 1" >>confdefs.h
+
+ PYTHON3_SRC="if_python3.c"
+ PYTHON3_OBJ="objects/if_python3.o"
+ PYTHON3_CFLAGS="$PYTHON3_CFLAGS -DDYNAMIC_PYTHON3_DLL=\\\"${vi_cv_dll_name_python3}\\\""
+ PYTHON3_LIBS=
+elif test "$python3_ok" = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if -fPIE can be added for Python3" >&5
+$as_echo_n "checking if -fPIE can be added for Python3... " >&6; }
+ cflags_save=$CFLAGS
+ libs_save=$LIBS
+ CFLAGS="$CFLAGS $PYTHON3_CFLAGS -fPIE"
+ LIBS="$LIBS $PYTHON3_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }; fpie_ok=yes
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }; fpie_ok=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ CFLAGS=$cflags_save
+ LIBS=$libs_save
+ if test $fpie_ok = yes; then
+ PYTHON3_CFLAGS="$PYTHON3_CFLAGS -fPIE"
+ fi
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --enable-tclinterp argument" >&5
+$as_echo_n "checking --enable-tclinterp argument... " >&6; }
+# Check whether --enable-tclinterp was given.
+if test "${enable_tclinterp+set}" = set; then :
+ enableval=$enable_tclinterp;
+else
+ enable_tclinterp="no"
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_tclinterp" >&5
+$as_echo "$enable_tclinterp" >&6; }
+
+if test "$enable_tclinterp" = "yes" -o "$enable_tclinterp" = "dynamic"; then
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking --with-tclsh argument" >&5
+$as_echo_n "checking --with-tclsh argument... " >&6; }
+
+# Check whether --with-tclsh was given.
+if test "${with_tclsh+set}" = set; then :
+ withval=$with_tclsh; tclsh_name="$withval"; { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tclsh_name" >&5
+$as_echo "$tclsh_name" >&6; }
+else
+ tclsh_name="tclsh8.5"; { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ # Extract the first word of "$tclsh_name", so it can be a program name with args.
+set dummy $tclsh_name; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_vi_cv_path_tcl+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $vi_cv_path_tcl in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_vi_cv_path_tcl="$vi_cv_path_tcl" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_vi_cv_path_tcl="$as_dir/$ac_word$ac_exec_ext"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+fi
+vi_cv_path_tcl=$ac_cv_path_vi_cv_path_tcl
+if test -n "$vi_cv_path_tcl"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_path_tcl" >&5
+$as_echo "$vi_cv_path_tcl" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+
+ if test "X$vi_cv_path_tcl" = "X" -a $tclsh_name = "tclsh8.5"; then
+ tclsh_name="tclsh8.4"
+ # Extract the first word of "$tclsh_name", so it can be a program name with args.
+set dummy $tclsh_name; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_vi_cv_path_tcl+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $vi_cv_path_tcl in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_vi_cv_path_tcl="$vi_cv_path_tcl" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_vi_cv_path_tcl="$as_dir/$ac_word$ac_exec_ext"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+fi
+vi_cv_path_tcl=$ac_cv_path_vi_cv_path_tcl
+if test -n "$vi_cv_path_tcl"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_path_tcl" >&5
+$as_echo "$vi_cv_path_tcl" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ fi
+ if test "X$vi_cv_path_tcl" = "X" -a $tclsh_name = "tclsh8.4"; then
+ tclsh_name="tclsh8.2"
+ # Extract the first word of "$tclsh_name", so it can be a program name with args.
+set dummy $tclsh_name; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_vi_cv_path_tcl+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $vi_cv_path_tcl in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_vi_cv_path_tcl="$vi_cv_path_tcl" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_vi_cv_path_tcl="$as_dir/$ac_word$ac_exec_ext"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+fi
+vi_cv_path_tcl=$ac_cv_path_vi_cv_path_tcl
+if test -n "$vi_cv_path_tcl"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_path_tcl" >&5
+$as_echo "$vi_cv_path_tcl" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ fi
+ if test "X$vi_cv_path_tcl" = "X" -a $tclsh_name = "tclsh8.2"; then
+ tclsh_name="tclsh8.0"
+ # Extract the first word of "$tclsh_name", so it can be a program name with args.
+set dummy $tclsh_name; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_vi_cv_path_tcl+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $vi_cv_path_tcl in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_vi_cv_path_tcl="$vi_cv_path_tcl" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_vi_cv_path_tcl="$as_dir/$ac_word$ac_exec_ext"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+fi
+vi_cv_path_tcl=$ac_cv_path_vi_cv_path_tcl
+if test -n "$vi_cv_path_tcl"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_path_tcl" >&5
+$as_echo "$vi_cv_path_tcl" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ fi
+ if test "X$vi_cv_path_tcl" = "X"; then
+ tclsh_name="tclsh"
+ # Extract the first word of "$tclsh_name", so it can be a program name with args.
+set dummy $tclsh_name; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_vi_cv_path_tcl+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $vi_cv_path_tcl in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_vi_cv_path_tcl="$vi_cv_path_tcl" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_vi_cv_path_tcl="$as_dir/$ac_word$ac_exec_ext"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+fi
+vi_cv_path_tcl=$ac_cv_path_vi_cv_path_tcl
+if test -n "$vi_cv_path_tcl"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_path_tcl" >&5
+$as_echo "$vi_cv_path_tcl" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ fi
+ if test "X$vi_cv_path_tcl" != "X"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking Tcl version" >&5
+$as_echo_n "checking Tcl version... " >&6; }
+ if echo 'exit [expr [info tclversion] < 8.0]' | "$vi_cv_path_tcl" - ; then
+ tclver=`echo 'puts [info tclversion]' | $vi_cv_path_tcl -`
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tclver - OK" >&5
+$as_echo "$tclver - OK" >&6; };
+ tclloc=`echo 'set l [info library];set i [string last lib $l];incr i -2;puts [string range $l 0 $i]' | $vi_cv_path_tcl -`
+ tcldll=`echo 'puts libtcl[info tclversion][info sharedlibextension]' | $vi_cv_path_tcl -`
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for location of Tcl include" >&5
+$as_echo_n "checking for location of Tcl include... " >&6; }
+ if test "x$MACOS_X" != "xyes"; then
+ tclinc="$tclloc/include $tclloc/include/tcl $tclloc/include/tcl$tclver /usr/local/include /usr/local/include/tcl$tclver /usr/include /usr/include/tcl$tclver"
+ else
+ tclinc="/System/Library/Frameworks/Tcl.framework/Headers"
+ fi
+ TCL_INC=
+ for try in $tclinc; do
+ if test -f "$try/tcl.h"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $try/tcl.h" >&5
+$as_echo "$try/tcl.h" >&6; }
+ TCL_INC=$try
+ break
+ fi
+ done
+ if test -z "$TCL_INC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: <not found>" >&5
+$as_echo "<not found>" >&6; }
+ SKIP_TCL=YES
+ fi
+ if test -z "$SKIP_TCL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for location of tclConfig.sh script" >&5
+$as_echo_n "checking for location of tclConfig.sh script... " >&6; }
+ if test "x$MACOS_X" != "xyes"; then
+ tclcnf=`echo $tclinc | sed s/include/lib/g`
+ tclcnf="$tclcnf `echo $tclinc | sed s/include/lib64/g`"
+ else
+ tclcnf="/System/Library/Frameworks/Tcl.framework"
+ fi
+ for try in $tclcnf; do
+ if test -f "$try/tclConfig.sh"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $try/tclConfig.sh" >&5
+$as_echo "$try/tclConfig.sh" >&6; }
+ . "$try/tclConfig.sh"
+ if test "$enable_tclinterp" = "dynamic"; then
+ TCL_LIBS=`eval echo "$TCL_STUB_LIB_SPEC $TCL_LIBS"`
+ else
+ TCL_LIBS=`eval echo "$TCL_LIB_SPEC $TCL_LIBS"`
+ fi
+ TCL_DEFS=`echo $TCL_DEFS | sed -e 's/\\\\ /\\\\X/g' | tr ' ' '\012' | sed -e '/^[^-]/d' -e '/^-[^D]/d' -e '/-D[^_]/d' -e 's/-D_/ -D_/' | tr '\012' ' ' | sed -e 's/\\\\X/\\\\ /g'`
+ break
+ fi
+ done
+ if test -z "$TCL_LIBS"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: <not found>" >&5
+$as_echo "<not found>" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Tcl library by myself" >&5
+$as_echo_n "checking for Tcl library by myself... " >&6; }
+ tcllib=`echo $tclinc | sed s/include/lib/g`
+ tcllib="$tcllib `echo $tclinc | sed s/include/lib64/g`"
+ for ext in .so .a ; do
+ for ver in "" $tclver ; do
+ for try in $tcllib ; do
+ trylib=tcl$ver$ext
+ if test -f "$try/lib$trylib" ; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $try/lib$trylib" >&5
+$as_echo "$try/lib$trylib" >&6; }
+ TCL_LIBS="-L\"$try\" -ltcl$ver -ldl -lm"
+ if test "`(uname) 2>/dev/null`" = SunOS &&
+ uname -r | grep '^5' >/dev/null; then
+ TCL_LIBS="$TCL_LIBS -R $try"
+ fi
+ break 3
+ fi
+ done
+ done
+ done
+ if test -z "$TCL_LIBS"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: <not found>" >&5
+$as_echo "<not found>" >&6; }
+ SKIP_TCL=YES
+ fi
+ fi
+ if test -z "$SKIP_TCL"; then
+ $as_echo "#define FEAT_TCL 1" >>confdefs.h
+
+ TCL_SRC=if_tcl.c
+ TCL_OBJ=objects/if_tcl.o
+ TCL_PRO=if_tcl.pro
+ TCL_CFLAGS="-I$TCL_INC $TCL_DEFS"
+ fi
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: too old; need Tcl version 8.0 or later" >&5
+$as_echo "too old; need Tcl version 8.0 or later" >&6; }
+ fi
+ fi
+ if test "$enable_tclinterp" = "dynamic"; then
+ if test "X$TCL_SRC" != "X" -a "X$tcldll" != "X"; then
+ $as_echo "#define DYNAMIC_TCL 1" >>confdefs.h
+
+ TCL_CFLAGS="-DDYNAMIC_TCL_DLL=\\\"$tcldll\\\" -DDYNAMIC_TCL_VER=\\\"$tclver\\\" $TCL_CFLAGS"
+ fi
+ fi
+ if test "$fail_if_missing" = "yes" -a -z "$TCL_SRC"; then
+ as_fn_error $? "could not configure Tcl" "$LINENO" 5
+ fi
+fi
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --enable-rubyinterp argument" >&5
+$as_echo_n "checking --enable-rubyinterp argument... " >&6; }
+# Check whether --enable-rubyinterp was given.
+if test "${enable_rubyinterp+set}" = set; then :
+ enableval=$enable_rubyinterp;
+else
+ enable_rubyinterp="no"
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_rubyinterp" >&5
+$as_echo "$enable_rubyinterp" >&6; }
+if test "$enable_rubyinterp" = "yes" -o "$enable_rubyinterp" = "dynamic"; then
+ if test "x$features" = "xtiny" -o "x$features" = "xsmall"; then
+ as_fn_error $? "cannot use Ruby with tiny or small features" "$LINENO" 5
+ fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking --with-ruby-command argument" >&5
+$as_echo_n "checking --with-ruby-command argument... " >&6; }
+
+
+# Check whether --with-ruby-command was given.
+if test "${with_ruby_command+set}" = set; then :
+ withval=$with_ruby_command; RUBY_CMD="$withval"; vi_cv_path_ruby="$withval"; { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RUBY_CMD" >&5
+$as_echo "$RUBY_CMD" >&6; }
+else
+ RUBY_CMD="ruby"; { $as_echo "$as_me:${as_lineno-$LINENO}: result: defaulting to $RUBY_CMD" >&5
+$as_echo "defaulting to $RUBY_CMD" >&6; }
+fi
+
+ # Extract the first word of "$RUBY_CMD", so it can be a program name with args.
+set dummy $RUBY_CMD; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_vi_cv_path_ruby+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $vi_cv_path_ruby in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_vi_cv_path_ruby="$vi_cv_path_ruby" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_vi_cv_path_ruby="$as_dir/$ac_word$ac_exec_ext"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+fi
+vi_cv_path_ruby=$ac_cv_path_vi_cv_path_ruby
+if test -n "$vi_cv_path_ruby"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_path_ruby" >&5
+$as_echo "$vi_cv_path_ruby" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ if test "X$vi_cv_path_ruby" != "X"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking Ruby version" >&5
+$as_echo_n "checking Ruby version... " >&6; }
+ if $vi_cv_path_ruby -e '(VERSION rescue RUBY_VERSION) >= "1.6.0" or exit 1' >/dev/null 2>/dev/null; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: OK" >&5
+$as_echo "OK" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking Ruby rbconfig" >&5
+$as_echo_n "checking Ruby rbconfig... " >&6; }
+ ruby_rbconfig="RbConfig"
+ if ! $vi_cv_path_ruby -r rbconfig -e 'RbConfig' >/dev/null 2>/dev/null; then
+ ruby_rbconfig="Config"
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ruby_rbconfig" >&5
+$as_echo "$ruby_rbconfig" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking Ruby header files" >&5
+$as_echo_n "checking Ruby header files... " >&6; }
+ rubyhdrdir=`$vi_cv_path_ruby -r mkmf -e "print $ruby_rbconfig::CONFIG['rubyhdrdir'] || $ruby_rbconfig::CONFIG['archdir'] || \\$hdrdir" 2>/dev/null`
+ if test "X$rubyhdrdir" != "X"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $rubyhdrdir" >&5
+$as_echo "$rubyhdrdir" >&6; }
+ RUBY_CFLAGS="-I$rubyhdrdir"
+ rubyarchdir=`$vi_cv_path_ruby -r rbconfig -e "print ($ruby_rbconfig::CONFIG.has_key? 'rubyarchhdrdir') ? $ruby_rbconfig::CONFIG['rubyarchhdrdir'] : '$rubyhdrdir/'+$ruby_rbconfig::CONFIG['arch']"`
+ if test -d "$rubyarchdir"; then
+ RUBY_CFLAGS="$RUBY_CFLAGS -I$rubyarchdir"
+ fi
+ rubyversion=`$vi_cv_path_ruby -r rbconfig -e "print $ruby_rbconfig::CONFIG['ruby_version'].gsub(/\./, '')[0,2]"`
+ if test "X$rubyversion" = "X"; then
+ rubyversion=`$vi_cv_path_ruby -e "print ((VERSION rescue RUBY_VERSION)).gsub(/\./, '')[0,2]"`
+ fi
+ RUBY_CFLAGS="$RUBY_CFLAGS -DRUBY_VERSION=$rubyversion"
+ rubylibs=`$vi_cv_path_ruby -r rbconfig -e "print $ruby_rbconfig::CONFIG['LIBS']"`
+ if test "X$rubylibs" != "X"; then
+ RUBY_LIBS="$rubylibs"
+ fi
+ librubyarg=`$vi_cv_path_ruby -r rbconfig -e "print $ruby_rbconfig.expand($ruby_rbconfig::CONFIG['LIBRUBYARG'])"`
+ librubya=`$vi_cv_path_ruby -r rbconfig -e "print $ruby_rbconfig.expand($ruby_rbconfig::CONFIG['LIBRUBY_A'])"`
+ rubylibdir=`$vi_cv_path_ruby -r rbconfig -e "print $ruby_rbconfig.expand($ruby_rbconfig::CONFIG['libdir'])"`
+ if test -f "$rubylibdir/$librubya"; then
+ librubyarg="$librubyarg"
+ RUBY_LIBS="$RUBY_LIBS -L$rubylibdir"
+ elif test "$librubyarg" = "libruby.a"; then
+ librubyarg="-lruby"
+ RUBY_LIBS="$RUBY_LIBS -L$rubylibdir"
+ fi
+
+ if test "X$librubyarg" != "X"; then
+ RUBY_LIBS="$librubyarg $RUBY_LIBS"
+ fi
+ rubyldflags=`$vi_cv_path_ruby -r rbconfig -e "print $ruby_rbconfig::CONFIG['LDFLAGS']"`
+ if test "X$rubyldflags" != "X"; then
+ rubyldflags=`echo "$rubyldflags" | sed -e 's/-arch\ ppc//' -e 's/-arch\ i386//' -e 's/-arch\ x86_64//'`
+ if test "X$rubyldflags" != "X"; then
+ if test "X`echo \"$LDFLAGS\" | $FGREP -e \"$rubyldflags\"`" = "X"; then
+ LDFLAGS="$rubyldflags $LDFLAGS"
+ fi
+ fi
+ fi
+ RUBY_SRC="if_ruby.c"
+ RUBY_OBJ="objects/if_ruby.o"
+ RUBY_PRO="if_ruby.pro"
+ $as_echo "#define FEAT_RUBY 1" >>confdefs.h
+
+ if test "$enable_rubyinterp" = "dynamic"; then
+ libruby_soname=`$vi_cv_path_ruby -r rbconfig -e "puts $ruby_rbconfig::CONFIG['LIBRUBY_ALIASES'].split[0]"`
+ if test -z "$libruby_soname"; then
+ libruby_soname=`$vi_cv_path_ruby -r rbconfig -e "puts $ruby_rbconfig::CONFIG['LIBRUBY_SO']"`
+ fi
+ $as_echo "#define DYNAMIC_RUBY 1" >>confdefs.h
+
+ RUBY_CFLAGS="-DDYNAMIC_RUBY_DLL=\\\"$libruby_soname\\\" -DDYNAMIC_RUBY_VER=$rubyversion $RUBY_CFLAGS"
+ RUBY_LIBS=
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found; disabling Ruby" >&5
+$as_echo "not found; disabling Ruby" >&6; }
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: too old; need Ruby version 1.6.0 or later" >&5
+$as_echo "too old; need Ruby version 1.6.0 or later" >&6; }
+ fi
+ fi
+
+ if test "$fail_if_missing" = "yes" -a -z "$RUBY_OBJ"; then
+ as_fn_error $? "could not configure Ruby" "$LINENO" 5
+ fi
+fi
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --enable-cscope argument" >&5
+$as_echo_n "checking --enable-cscope argument... " >&6; }
+# Check whether --enable-cscope was given.
+if test "${enable_cscope+set}" = set; then :
+ enableval=$enable_cscope;
+else
+ enable_cscope="no"
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_cscope" >&5
+$as_echo "$enable_cscope" >&6; }
+if test "$enable_cscope" = "yes"; then
+ $as_echo "#define FEAT_CSCOPE 1" >>confdefs.h
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --disable-netbeans argument" >&5
+$as_echo_n "checking --disable-netbeans argument... " >&6; }
+# Check whether --enable-netbeans was given.
+if test "${enable_netbeans+set}" = set; then :
+ enableval=$enable_netbeans;
+else
+ enable_netbeans="yes"
+fi
+
+if test "$enable_netbeans" = "yes"; then
+ if test "x$features" = "xtiny" -o "x$features" = "xsmall"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: cannot use NetBeans with tiny or small features" >&5
+$as_echo "cannot use NetBeans with tiny or small features" >&6; }
+ enable_netbeans="no"
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --disable-channel argument" >&5
+$as_echo_n "checking --disable-channel argument... " >&6; }
+# Check whether --enable-channel was given.
+if test "${enable_channel+set}" = set; then :
+ enableval=$enable_channel;
+else
+ enable_channel="yes"
+fi
+
+if test "$enable_channel" = "yes"; then
+ if test "x$features" = "xtiny" -o "x$features" = "xsmall"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: cannot use channels with tiny or small features" >&5
+$as_echo "cannot use channels with tiny or small features" >&6; }
+ enable_channel="no"
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ fi
+else
+ if test "$enable_netbeans" = "yes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes, netbeans also disabled" >&5
+$as_echo "yes, netbeans also disabled" >&6; }
+ enable_netbeans="no"
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ fi
+fi
+
+if test "$enable_channel" = "yes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for socket in -lsocket" >&5
+$as_echo_n "checking for socket in -lsocket... " >&6; }
+if ${ac_cv_lib_socket_socket+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsocket $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char socket ();
+int
+main ()
+{
+return socket ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_socket_socket=yes
+else
+ ac_cv_lib_socket_socket=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_socket" >&5
+$as_echo "$ac_cv_lib_socket_socket" >&6; }
+if test "x$ac_cv_lib_socket_socket" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBSOCKET 1
+_ACEOF
+
+ LIBS="-lsocket $LIBS"
+
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lnsl" >&5
+$as_echo_n "checking for gethostbyname in -lnsl... " >&6; }
+if ${ac_cv_lib_nsl_gethostbyname+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lnsl $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char gethostbyname ();
+int
+main ()
+{
+return gethostbyname ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_nsl_gethostbyname=yes
+else
+ ac_cv_lib_nsl_gethostbyname=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_gethostbyname" >&5
+$as_echo "$ac_cv_lib_nsl_gethostbyname" >&6; }
+if test "x$ac_cv_lib_nsl_gethostbyname" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBNSL 1
+_ACEOF
+
+ LIBS="-lnsl $LIBS"
+
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiling with process communication is possible" >&5
+$as_echo_n "checking whether compiling with process communication is possible... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+ /* Check bitfields */
+ struct nbbuf {
+ unsigned int initDone:1;
+ unsigned short signmaplen;
+ };
+
+int
+main ()
+{
+
+ /* Check creating a socket. */
+ struct sockaddr_in server;
+ (void)socket(AF_INET, SOCK_STREAM, 0);
+ (void)htons(100);
+ (void)gethostbyname("microsoft.com");
+ if (errno == ECONNREFUSED)
+ (void)connect(1, (struct sockaddr *)&server, sizeof(server));
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }; enable_netbeans="no"; enable_channel="no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+if test "$enable_netbeans" = "yes"; then
+ $as_echo "#define FEAT_NETBEANS_INTG 1" >>confdefs.h
+
+ NETBEANS_SRC="netbeans.c"
+
+ NETBEANS_OBJ="objects/netbeans.o"
+
+fi
+if test "$enable_channel" = "yes"; then
+ $as_echo "#define FEAT_JOB_CHANNEL 1" >>confdefs.h
+
+ CHANNEL_SRC="channel.c"
+
+ CHANNEL_OBJ="objects/channel.o"
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --enable-terminal argument" >&5
+$as_echo_n "checking --enable-terminal argument... " >&6; }
+# Check whether --enable-terminal was given.
+if test "${enable_terminal+set}" = set; then :
+ enableval=$enable_terminal;
+else
+ enable_terminal="auto"
+fi
+
+if test "$enable_terminal" = "yes" || test "$enable_terminal" = "auto" -a "x$features" = "xhuge" ; then
+ if test "x$features" = "xtiny" -o "x$features" = "xsmall"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: cannot use terminal emulator with tiny or small features" >&5
+$as_echo "cannot use terminal emulator with tiny or small features" >&6; }
+ enable_terminal="no"
+ else
+ if test "$enable_terminal" = "auto"; then
+ enable_terminal="yes"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: defaulting to yes" >&5
+$as_echo "defaulting to yes" >&6; }
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ fi
+ fi
+else
+ if test "$enable_terminal" = "auto"; then
+ enable_terminal="no"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: defaulting to no" >&5
+$as_echo "defaulting to no" >&6; }
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ fi
+fi
+if test "$enable_terminal" = "yes" -a "$enable_channel" = "yes"; then
+ $as_echo "#define FEAT_TERMINAL 1" >>confdefs.h
+
+ TERM_SRC="libvterm/src/encoding.c libvterm/src/keyboard.c libvterm/src/mouse.c libvterm/src/parser.c libvterm/src/pen.c libvterm/src/termscreen.c libvterm/src/state.c libvterm/src/unicode.c libvterm/src/vterm.c"
+
+ TERM_OBJ="objects/encoding.o objects/keyboard.o objects/mouse.o objects/parser.o objects/pen.o objects/termscreen.o objects/state.o objects/unicode.o objects/vterm.o"
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --enable-autoservername argument" >&5
+$as_echo_n "checking --enable-autoservername argument... " >&6; }
+# Check whether --enable-autoservername was given.
+if test "${enable_autoservername+set}" = set; then :
+ enableval=$enable_autoservername;
+else
+ enable_autoservername="no"
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_autoservername" >&5
+$as_echo "$enable_autoservername" >&6; }
+if test "$enable_autoservername" = "yes"; then
+ $as_echo "#define FEAT_AUTOSERVERNAME 1" >>confdefs.h
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --enable-multibyte argument" >&5
+$as_echo_n "checking --enable-multibyte argument... " >&6; }
+# Check whether --enable-multibyte was given.
+if test "${enable_multibyte+set}" = set; then :
+ enableval=$enable_multibyte;
+else
+ enable_multibyte="yes"
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_multibyte" >&5
+$as_echo "$enable_multibyte" >&6; }
+if test "$enable_multibyte" != "yes"; then
+ as_fn_error $? "The multi-byte feature can no longer be disabled. If you have
+ a problem with this, discuss on the Vim mailing list." "$LINENO" 5
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --disable-rightleft argument" >&5
+$as_echo_n "checking --disable-rightleft argument... " >&6; }
+# Check whether --enable-rightleft was given.
+if test "${enable_rightleft+set}" = set; then :
+ enableval=$enable_rightleft;
+else
+ enable_rightleft="yes"
+fi
+
+if test "$enable_rightleft" = "yes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ $as_echo "#define DISABLE_RIGHTLEFT 1" >>confdefs.h
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --disable-arabic argument" >&5
+$as_echo_n "checking --disable-arabic argument... " >&6; }
+# Check whether --enable-arabic was given.
+if test "${enable_arabic+set}" = set; then :
+ enableval=$enable_arabic;
+else
+ enable_arabic="yes"
+fi
+
+if test "$enable_arabic" = "yes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ $as_echo "#define DISABLE_ARABIC 1" >>confdefs.h
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --disable-farsi argument" >&5
+$as_echo_n "checking --disable-farsi argument... " >&6; }
+# Check whether --enable-farsi was given.
+if test "${enable_farsi+set}" = set; then :
+ enableval=$enable_farsi;
+else
+ enable_farsi="yes"
+fi
+
+if test "$enable_farsi" = "yes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ $as_echo "#define DISABLE_FARSI 1" >>confdefs.h
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --enable-hangulinput argument" >&5
+$as_echo_n "checking --enable-hangulinput argument... " >&6; }
+# Check whether --enable-hangulinput was given.
+if test "${enable_hangulinput+set}" = set; then :
+ enableval=$enable_hangulinput;
+else
+ enable_hangulinput="no"
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_hangulinput" >&5
+$as_echo "$enable_hangulinput" >&6; }
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --enable-xim argument" >&5
+$as_echo_n "checking --enable-xim argument... " >&6; }
+# Check whether --enable-xim was given.
+if test "${enable_xim+set}" = set; then :
+ enableval=$enable_xim; { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_xim" >&5
+$as_echo "$enable_xim" >&6; }
+else
+ enable_xim="auto"; { $as_echo "$as_me:${as_lineno-$LINENO}: result: defaulting to auto" >&5
+$as_echo "defaulting to auto" >&6; }
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --enable-fontset argument" >&5
+$as_echo_n "checking --enable-fontset argument... " >&6; }
+# Check whether --enable-fontset was given.
+if test "${enable_fontset+set}" = set; then :
+ enableval=$enable_fontset;
+else
+ enable_fontset="no"
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_fontset" >&5
+$as_echo "$enable_fontset" >&6; }
+
+test -z "$with_x" && with_x=yes
+test "${enable_gui-yes}" != no -a "x$MACOS_X" != "xyes" -a "x$QNX" != "xyes" && with_x=yes
+if test "$with_x" = no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: defaulting to: don't HAVE_X11" >&5
+$as_echo "defaulting to: don't HAVE_X11" >&6; }
+else
+
+ # Extract the first word of "xmkmf", so it can be a program name with args.
+set dummy xmkmf; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_xmkmfpath+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $xmkmfpath in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_xmkmfpath="$xmkmfpath" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_xmkmfpath="$as_dir/$ac_word$ac_exec_ext"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+fi
+xmkmfpath=$ac_cv_path_xmkmfpath
+if test -n "$xmkmfpath"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $xmkmfpath" >&5
+$as_echo "$xmkmfpath" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for X" >&5
+$as_echo_n "checking for X... " >&6; }
+
+
+# Check whether --with-x was given.
+if test "${with_x+set}" = set; then :
+ withval=$with_x;
+fi
+
+# $have_x is `yes', `no', `disabled', or empty when we do not yet know.
+if test "x$with_x" = xno; then
+ # The user explicitly disabled X.
+ have_x=disabled
+else
+ case $x_includes,$x_libraries in #(
+ *\'*) as_fn_error $? "cannot use X directory names containing '" "$LINENO" 5;; #(
+ *,NONE | NONE,*) if ${ac_cv_have_x+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ # One or both of the vars are not set, and there is no cached value.
+ac_x_includes=no ac_x_libraries=no
+rm -f -r conftest.dir
+if mkdir conftest.dir; then
+ cd conftest.dir
+ cat >Imakefile <<'_ACEOF'
+incroot:
+ @echo incroot='${INCROOT}'
+usrlibdir:
+ @echo usrlibdir='${USRLIBDIR}'
+libdir:
+ @echo libdir='${LIBDIR}'
+_ACEOF
+ if (export CC; ${XMKMF-xmkmf}) >/dev/null 2>/dev/null && test -f Makefile; then
+ # GNU make sometimes prints "make[1]: Entering ...", which would confuse us.
+ for ac_var in incroot usrlibdir libdir; do
+ eval "ac_im_$ac_var=\`\${MAKE-make} $ac_var 2>/dev/null | sed -n 's/^$ac_var=//p'\`"
+ done
+ # Open Windows xmkmf reportedly sets LIBDIR instead of USRLIBDIR.
+ for ac_extension in a so sl dylib la dll; do
+ if test ! -f "$ac_im_usrlibdir/libX11.$ac_extension" &&
+ test -f "$ac_im_libdir/libX11.$ac_extension"; then
+ ac_im_usrlibdir=$ac_im_libdir; break
+ fi
+ done
+ # Screen out bogus values from the imake configuration. They are
+ # bogus both because they are the default anyway, and because
+ # using them would break gcc on systems where it needs fixed includes.
+ case $ac_im_incroot in
+ /usr/include) ac_x_includes= ;;
+ *) test -f "$ac_im_incroot/X11/Xos.h" && ac_x_includes=$ac_im_incroot;;
+ esac
+ case $ac_im_usrlibdir in
+ /usr/lib | /usr/lib64 | /lib | /lib64) ;;
+ *) test -d "$ac_im_usrlibdir" && ac_x_libraries=$ac_im_usrlibdir ;;
+ esac
+ fi
+ cd ..
+ rm -f -r conftest.dir
+fi
+
+# Standard set of common directories for X headers.
+# Check X11 before X11Rn because it is often a symlink to the current release.
+ac_x_header_dirs='
+/usr/X11/include
+/usr/X11R7/include
+/usr/X11R6/include
+/usr/X11R5/include
+/usr/X11R4/include
+
+/usr/include/X11
+/usr/include/X11R7
+/usr/include/X11R6
+/usr/include/X11R5
+/usr/include/X11R4
+
+/usr/local/X11/include
+/usr/local/X11R7/include
+/usr/local/X11R6/include
+/usr/local/X11R5/include
+/usr/local/X11R4/include
+
+/usr/local/include/X11
+/usr/local/include/X11R7
+/usr/local/include/X11R6
+/usr/local/include/X11R5
+/usr/local/include/X11R4
+
+/usr/X386/include
+/usr/x386/include
+/usr/XFree86/include/X11
+
+/usr/include
+/usr/local/include
+/usr/unsupported/include
+/usr/athena/include
+/usr/local/x11r5/include
+/usr/lpp/Xamples/include
+
+/usr/openwin/include
+/usr/openwin/share/include'
+
+if test "$ac_x_includes" = no; then
+ # Guess where to find include files, by looking for Xlib.h.
+ # First, try using that file with no special directory specified.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <X11/Xlib.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ # We can compile using X headers with no special include directory.
+ac_x_includes=
+else
+ for ac_dir in $ac_x_header_dirs; do
+ if test -r "$ac_dir/X11/Xlib.h"; then
+ ac_x_includes=$ac_dir
+ break
+ fi
+done
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+fi # $ac_x_includes = no
+
+if test "$ac_x_libraries" = no; then
+ # Check for the libraries.
+ # See if we find them without any special options.
+ # Don't add to $LIBS permanently.
+ ac_save_LIBS=$LIBS
+ LIBS="-lX11 $LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <X11/Xlib.h>
+int
+main ()
+{
+XrmInitialize ()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ LIBS=$ac_save_LIBS
+# We can link X programs with no special library path.
+ac_x_libraries=
+else
+ LIBS=$ac_save_LIBS
+for ac_dir in `$as_echo "$ac_x_includes $ac_x_header_dirs" | sed s/include/lib/g`
+do
+ # Don't even attempt the hair of trying to link an X program!
+ for ac_extension in a so sl dylib la dll; do
+ if test -r "$ac_dir/libX11.$ac_extension"; then
+ ac_x_libraries=$ac_dir
+ break 2
+ fi
+ done
+done
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi # $ac_x_libraries = no
+
+case $ac_x_includes,$ac_x_libraries in #(
+ no,* | *,no | *\'*)
+ # Didn't find X, or a directory has "'" in its name.
+ ac_cv_have_x="have_x=no";; #(
+ *)
+ # Record where we found X for the cache.
+ ac_cv_have_x="have_x=yes\
+ ac_x_includes='$ac_x_includes'\
+ ac_x_libraries='$ac_x_libraries'"
+esac
+fi
+;; #(
+ *) have_x=yes;;
+ esac
+ eval "$ac_cv_have_x"
+fi # $with_x != no
+
+if test "$have_x" != yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_x" >&5
+$as_echo "$have_x" >&6; }
+ no_x=yes
+else
+ # If each of the values was on the command line, it overrides each guess.
+ test "x$x_includes" = xNONE && x_includes=$ac_x_includes
+ test "x$x_libraries" = xNONE && x_libraries=$ac_x_libraries
+ # Update the cache value to reflect the command line values.
+ ac_cv_have_x="have_x=yes\
+ ac_x_includes='$x_includes'\
+ ac_x_libraries='$x_libraries'"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: libraries $x_libraries, headers $x_includes" >&5
+$as_echo "libraries $x_libraries, headers $x_includes" >&6; }
+fi
+
+if test "$no_x" = yes; then
+ # Not all programs may use this symbol, but it does not hurt to define it.
+
+$as_echo "#define X_DISPLAY_MISSING 1" >>confdefs.h
+
+ X_CFLAGS= X_PRE_LIBS= X_LIBS= X_EXTRA_LIBS=
+else
+ if test -n "$x_includes"; then
+ X_CFLAGS="$X_CFLAGS -I$x_includes"
+ fi
+
+ # It would also be nice to do this for all -L options, not just this one.
+ if test -n "$x_libraries"; then
+ X_LIBS="$X_LIBS -L$x_libraries"
+ # For Solaris; some versions of Sun CC require a space after -R and
+ # others require no space. Words are not sufficient . . . .
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -R must be followed by a space" >&5
+$as_echo_n "checking whether -R must be followed by a space... " >&6; }
+ ac_xsave_LIBS=$LIBS; LIBS="$LIBS -R$x_libraries"
+ ac_xsave_c_werror_flag=$ac_c_werror_flag
+ ac_c_werror_flag=yes
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ X_LIBS="$X_LIBS -R$x_libraries"
+else
+ LIBS="$ac_xsave_LIBS -R $x_libraries"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ X_LIBS="$X_LIBS -R $x_libraries"
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: neither works" >&5
+$as_echo "neither works" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ ac_c_werror_flag=$ac_xsave_c_werror_flag
+ LIBS=$ac_xsave_LIBS
+ fi
+
+ # Check for system-dependent libraries X programs must link with.
+ # Do this before checking for the system-independent R6 libraries
+ # (-lICE), since we may need -lsocket or whatever for X linking.
+
+ if test "$ISC" = yes; then
+ X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl_s -linet"
+ else
+ # Martyn Johnson says this is needed for Ultrix, if the X
+ # libraries were built with DECnet support. And Karl Berry says
+ # the Alpha needs dnet_stub (dnet does not exist).
+ ac_xsave_LIBS="$LIBS"; LIBS="$LIBS $X_LIBS -lX11"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char XOpenDisplay ();
+int
+main ()
+{
+return XOpenDisplay ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dnet_ntoa in -ldnet" >&5
+$as_echo_n "checking for dnet_ntoa in -ldnet... " >&6; }
+if ${ac_cv_lib_dnet_dnet_ntoa+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldnet $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dnet_ntoa ();
+int
+main ()
+{
+return dnet_ntoa ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_dnet_dnet_ntoa=yes
+else
+ ac_cv_lib_dnet_dnet_ntoa=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dnet_dnet_ntoa" >&5
+$as_echo "$ac_cv_lib_dnet_dnet_ntoa" >&6; }
+if test "x$ac_cv_lib_dnet_dnet_ntoa" = xyes; then :
+ X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet"
+fi
+
+ if test $ac_cv_lib_dnet_dnet_ntoa = no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dnet_ntoa in -ldnet_stub" >&5
+$as_echo_n "checking for dnet_ntoa in -ldnet_stub... " >&6; }
+if ${ac_cv_lib_dnet_stub_dnet_ntoa+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldnet_stub $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dnet_ntoa ();
+int
+main ()
+{
+return dnet_ntoa ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_dnet_stub_dnet_ntoa=yes
+else
+ ac_cv_lib_dnet_stub_dnet_ntoa=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dnet_stub_dnet_ntoa" >&5
+$as_echo "$ac_cv_lib_dnet_stub_dnet_ntoa" >&6; }
+if test "x$ac_cv_lib_dnet_stub_dnet_ntoa" = xyes; then :
+ X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet_stub"
+fi
+
+ fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LIBS="$ac_xsave_LIBS"
+
+ # msh@cis.ufl.edu says -lnsl (and -lsocket) are needed for his 386/AT,
+ # to get the SysV transport functions.
+ # Chad R. Larson says the Pyramis MIS-ES running DC/OSx (SVR4)
+ # needs -lnsl.
+ # The nsl library prevents programs from opening the X display
+ # on Irix 5.2, according to T.E. Dickey.
+ # The functions gethostbyname, getservbyname, and inet_addr are
+ # in -lbsd on LynxOS 3.0.1/i386, according to Lars Hecking.
+ ac_fn_c_check_func "$LINENO" "gethostbyname" "ac_cv_func_gethostbyname"
+if test "x$ac_cv_func_gethostbyname" = xyes; then :
+
+fi
+
+ if test $ac_cv_func_gethostbyname = no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lnsl" >&5
+$as_echo_n "checking for gethostbyname in -lnsl... " >&6; }
+if ${ac_cv_lib_nsl_gethostbyname+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lnsl $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char gethostbyname ();
+int
+main ()
+{
+return gethostbyname ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_nsl_gethostbyname=yes
+else
+ ac_cv_lib_nsl_gethostbyname=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_gethostbyname" >&5
+$as_echo "$ac_cv_lib_nsl_gethostbyname" >&6; }
+if test "x$ac_cv_lib_nsl_gethostbyname" = xyes; then :
+ X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl"
+fi
+
+ if test $ac_cv_lib_nsl_gethostbyname = no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lbsd" >&5
+$as_echo_n "checking for gethostbyname in -lbsd... " >&6; }
+if ${ac_cv_lib_bsd_gethostbyname+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lbsd $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char gethostbyname ();
+int
+main ()
+{
+return gethostbyname ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_bsd_gethostbyname=yes
+else
+ ac_cv_lib_bsd_gethostbyname=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_gethostbyname" >&5
+$as_echo "$ac_cv_lib_bsd_gethostbyname" >&6; }
+if test "x$ac_cv_lib_bsd_gethostbyname" = xyes; then :
+ X_EXTRA_LIBS="$X_EXTRA_LIBS -lbsd"
+fi
+
+ fi
+ fi
+
+ # lieder@skyler.mavd.honeywell.com says without -lsocket,
+ # socket/setsockopt and other routines are undefined under SCO ODT
+ # 2.0. But -lsocket is broken on IRIX 5.2 (and is not necessary
+ # on later versions), says Simon Leinen: it contains gethostby*
+ # variants that don't use the name server (or something). -lsocket
+ # must be given before -lnsl if both are needed. We assume that
+ # if connect needs -lnsl, so does gethostbyname.
+ ac_fn_c_check_func "$LINENO" "connect" "ac_cv_func_connect"
+if test "x$ac_cv_func_connect" = xyes; then :
+
+fi
+
+ if test $ac_cv_func_connect = no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for connect in -lsocket" >&5
+$as_echo_n "checking for connect in -lsocket... " >&6; }
+if ${ac_cv_lib_socket_connect+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsocket $X_EXTRA_LIBS $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char connect ();
+int
+main ()
+{
+return connect ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_socket_connect=yes
+else
+ ac_cv_lib_socket_connect=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_connect" >&5
+$as_echo "$ac_cv_lib_socket_connect" >&6; }
+if test "x$ac_cv_lib_socket_connect" = xyes; then :
+ X_EXTRA_LIBS="-lsocket $X_EXTRA_LIBS"
+fi
+
+ fi
+
+ # Guillermo Gomez says -lposix is necessary on A/UX.
+ ac_fn_c_check_func "$LINENO" "remove" "ac_cv_func_remove"
+if test "x$ac_cv_func_remove" = xyes; then :
+
+fi
+
+ if test $ac_cv_func_remove = no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for remove in -lposix" >&5
+$as_echo_n "checking for remove in -lposix... " >&6; }
+if ${ac_cv_lib_posix_remove+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lposix $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char remove ();
+int
+main ()
+{
+return remove ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_posix_remove=yes
+else
+ ac_cv_lib_posix_remove=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_posix_remove" >&5
+$as_echo "$ac_cv_lib_posix_remove" >&6; }
+if test "x$ac_cv_lib_posix_remove" = xyes; then :
+ X_EXTRA_LIBS="$X_EXTRA_LIBS -lposix"
+fi
+
+ fi
+
+ # BSDI BSD/OS 2.1 needs -lipc for XOpenDisplay.
+ ac_fn_c_check_func "$LINENO" "shmat" "ac_cv_func_shmat"
+if test "x$ac_cv_func_shmat" = xyes; then :
+
+fi
+
+ if test $ac_cv_func_shmat = no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shmat in -lipc" >&5
+$as_echo_n "checking for shmat in -lipc... " >&6; }
+if ${ac_cv_lib_ipc_shmat+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lipc $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char shmat ();
+int
+main ()
+{
+return shmat ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_ipc_shmat=yes
+else
+ ac_cv_lib_ipc_shmat=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ipc_shmat" >&5
+$as_echo "$ac_cv_lib_ipc_shmat" >&6; }
+if test "x$ac_cv_lib_ipc_shmat" = xyes; then :
+ X_EXTRA_LIBS="$X_EXTRA_LIBS -lipc"
+fi
+
+ fi
+ fi
+
+ # Check for libraries that X11R6 Xt/Xaw programs need.
+ ac_save_LDFLAGS=$LDFLAGS
+ test -n "$x_libraries" && LDFLAGS="$LDFLAGS -L$x_libraries"
+ # SM needs ICE to (dynamically) link under SunOS 4.x (so we have to
+ # check for ICE first), but we must link in the order -lSM -lICE or
+ # we get undefined symbols. So assume we have SM if we have ICE.
+ # These have to be linked with before -lX11, unlike the other
+ # libraries we check for below, so use a different variable.
+ # John Interrante, Karl Berry
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for IceConnectionNumber in -lICE" >&5
+$as_echo_n "checking for IceConnectionNumber in -lICE... " >&6; }
+if ${ac_cv_lib_ICE_IceConnectionNumber+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lICE $X_EXTRA_LIBS $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char IceConnectionNumber ();
+int
+main ()
+{
+return IceConnectionNumber ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_ICE_IceConnectionNumber=yes
+else
+ ac_cv_lib_ICE_IceConnectionNumber=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ICE_IceConnectionNumber" >&5
+$as_echo "$ac_cv_lib_ICE_IceConnectionNumber" >&6; }
+if test "x$ac_cv_lib_ICE_IceConnectionNumber" = xyes; then :
+ X_PRE_LIBS="$X_PRE_LIBS -lSM -lICE"
+fi
+
+ LDFLAGS=$ac_save_LDFLAGS
+
+fi
+
+
+ if test "$zOSUnix" = "yes"; then
+ CFLAGS="$CFLAGS -W c,dll"
+ LDFLAGS="$LDFLAGS -W l,dll"
+ X_EXTRA_LIBS="$X_EXTRA_LIBS -lSM -lICE -lXmu"
+ fi
+
+
+ if test -d "$x_includes" && test ! -d "$x_libraries"; then
+ x_libraries=`echo "$x_includes" | sed s/include/lib/`
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: Corrected X libraries to $x_libraries" >&5
+$as_echo "Corrected X libraries to $x_libraries" >&6; }
+ X_LIBS="$X_LIBS -L$x_libraries"
+ if test "`(uname) 2>/dev/null`" = SunOS &&
+ uname -r | grep '^5' >/dev/null; then
+ X_LIBS="$X_LIBS -R $x_libraries"
+ fi
+ fi
+
+ if test -d "$x_libraries" && test ! -d "$x_includes"; then
+ x_includes=`echo "$x_libraries" | sed s/lib/include/`
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: Corrected X includes to $x_includes" >&5
+$as_echo "Corrected X includes to $x_includes" >&6; }
+ X_CFLAGS="$X_CFLAGS -I$x_includes"
+ fi
+
+ X_CFLAGS="`echo $X_CFLAGS\ | sed 's%-I/usr/include %%'`"
+ X_LIBS="`echo $X_LIBS\ | sed 's%-L/usr/lib %%'`"
+ X_LIBS="`echo $X_LIBS\ | sed -e 's%-R/usr/lib %%' -e 's%-R /usr/lib %%'`"
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if X11 header files can be found" >&5
+$as_echo_n "checking if X11 header files can be found... " >&6; }
+ cflags_save=$CFLAGS
+ CFLAGS="$CFLAGS $X_CFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <X11/Xlib.h>
+#include <X11/Intrinsic.h>
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }; no_x=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ CFLAGS=$cflags_save
+
+ if test "${no_x-no}" = yes; then
+ with_x=no
+ else
+ $as_echo "#define HAVE_X11 1" >>confdefs.h
+
+ X_LIB="-lXt -lX11";
+
+
+ ac_save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="-L$x_libraries $LDFLAGS"
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _XdmcpAuthDoIt in -lXdmcp" >&5
+$as_echo_n "checking for _XdmcpAuthDoIt in -lXdmcp... " >&6; }
+if ${ac_cv_lib_Xdmcp__XdmcpAuthDoIt+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lXdmcp -lXt $X_PRE_LIBS -lX11 $X_EXTRA_LIBS -lXdmcp $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char _XdmcpAuthDoIt ();
+int
+main ()
+{
+return _XdmcpAuthDoIt ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_Xdmcp__XdmcpAuthDoIt=yes
+else
+ ac_cv_lib_Xdmcp__XdmcpAuthDoIt=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_Xdmcp__XdmcpAuthDoIt" >&5
+$as_echo "$ac_cv_lib_Xdmcp__XdmcpAuthDoIt" >&6; }
+if test "x$ac_cv_lib_Xdmcp__XdmcpAuthDoIt" = xyes; then :
+ X_EXTRA_LIBS="$X_EXTRA_LIBS -lXdmcp"
+fi
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for IceOpenConnection in -lICE" >&5
+$as_echo_n "checking for IceOpenConnection in -lICE... " >&6; }
+if ${ac_cv_lib_ICE_IceOpenConnection+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lICE $X_EXTRA_LIBS $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char IceOpenConnection ();
+int
+main ()
+{
+return IceOpenConnection ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_ICE_IceOpenConnection=yes
+else
+ ac_cv_lib_ICE_IceOpenConnection=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ICE_IceOpenConnection" >&5
+$as_echo "$ac_cv_lib_ICE_IceOpenConnection" >&6; }
+if test "x$ac_cv_lib_ICE_IceOpenConnection" = xyes; then :
+ X_EXTRA_LIBS="$X_EXTRA_LIBS -lSM -lICE"
+fi
+
+
+ LDFLAGS="$X_LIBS $ac_save_LDFLAGS"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for XpmCreatePixmapFromData in -lXpm" >&5
+$as_echo_n "checking for XpmCreatePixmapFromData in -lXpm... " >&6; }
+if ${ac_cv_lib_Xpm_XpmCreatePixmapFromData+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lXpm -lXt $X_PRE_LIBS -lXpm -lX11 $X_EXTRA_LIBS $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char XpmCreatePixmapFromData ();
+int
+main ()
+{
+return XpmCreatePixmapFromData ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_Xpm_XpmCreatePixmapFromData=yes
+else
+ ac_cv_lib_Xpm_XpmCreatePixmapFromData=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_Xpm_XpmCreatePixmapFromData" >&5
+$as_echo "$ac_cv_lib_Xpm_XpmCreatePixmapFromData" >&6; }
+if test "x$ac_cv_lib_Xpm_XpmCreatePixmapFromData" = xyes; then :
+ X_PRE_LIBS="$X_PRE_LIBS -lXpm"
+fi
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if X11 header files implicitly declare return values" >&5
+$as_echo_n "checking if X11 header files implicitly declare return values... " >&6; }
+ cflags_save=$CFLAGS
+ if test "$GCC" = yes; then
+ CFLAGS="$CFLAGS $X_CFLAGS -Werror"
+ else
+ CFLAGS="$CFLAGS $X_CFLAGS"
+ fi
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <X11/Xlib.h>
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+else
+ CFLAGS="$CFLAGS -Wno-implicit-int"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <X11/Xlib.h>
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }; cflags_save="$cflags_save -Wno-implicit-int"
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: test failed" >&5
+$as_echo "test failed" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ CFLAGS=$cflags_save
+
+ LDFLAGS="$ac_save_LDFLAGS"
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of wchar_t is 2 bytes" >&5
+$as_echo_n "checking size of wchar_t is 2 bytes... " >&6; }
+ if ${ac_cv_small_wchar_t+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "$cross_compiling" = yes; then :
+ as_fn_error $? "failed to compile test program" "$LINENO" 5
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <X11/Xlib.h>
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#endif
+ main()
+ {
+ if (sizeof(wchar_t) <= 2)
+ exit(1);
+ exit(0);
+ }
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ ac_cv_small_wchar_t="no"
+else
+ ac_cv_small_wchar_t="yes"
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_small_wchar_t" >&5
+$as_echo "$ac_cv_small_wchar_t" >&6; }
+ if test "x$ac_cv_small_wchar_t" = "xyes" ; then
+ $as_echo "#define SMALL_WCHAR_T 1" >>confdefs.h
+
+ fi
+
+ fi
+fi
+
+if test "x$with_x" = xno -a "x$with_x_arg" = xyes; then
+ as_fn_error $? "could not configure X" "$LINENO" 5
+fi
+
+test "x$with_x" = xno -a "x$MACOS_X" != "xyes" -a "x$QNX" != "xyes" && enable_gui=no
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --enable-gui argument" >&5
+$as_echo_n "checking --enable-gui argument... " >&6; }
+# Check whether --enable-gui was given.
+if test "${enable_gui+set}" = set; then :
+ enableval=$enable_gui;
+else
+ enable_gui="auto"
+fi
+
+
+enable_gui_canon=`echo "_$enable_gui" | \
+ sed 's/[ _+-]//g;y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'`
+
+SKIP_GTK2=YES
+SKIP_GTK3=YES
+SKIP_GNOME=YES
+SKIP_MOTIF=YES
+SKIP_ATHENA=YES
+SKIP_NEXTAW=YES
+SKIP_PHOTON=YES
+SKIP_CARBON=YES
+GUITYPE=NONE
+
+if test "x$QNX" = "xyes" -a "x$with_x" = "xno" ; then
+ SKIP_PHOTON=
+ 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_PHOTON=YES ;;
+ yes|""|auto) { $as_echo "$as_me:${as_lineno-$LINENO}: result: automatic GUI support" >&5
+$as_echo "automatic GUI support" >&6; }
+ gui_auto=yes ;;
+ photon) { $as_echo "$as_me:${as_lineno-$LINENO}: result: Photon GUI support" >&5
+$as_echo "Photon 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_PHOTON=YES ;;
+ esac
+
+elif test "x$MACOS_X" = "xyes" -a "x$with_x" = "xno" ; then
+ SKIP_CARBON=
+ 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 ;;
+ yes|"") { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes - automatic GUI support" >&5
+$as_echo "yes - automatic GUI support" >&6; }
+ gui_auto=yes ;;
+ auto) { $as_echo "$as_me:${as_lineno-$LINENO}: result: auto - Carbon GUI is outdated - disable GUI support" >&5
+$as_echo "auto - Carbon GUI is outdated - disable GUI support" >&6; }
+ SKIP_CARBON=YES ;;
+ carbon) { $as_echo "$as_me:${as_lineno-$LINENO}: result: Carbon GUI support" >&5
+$as_echo "Carbon 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 ;;
+ esac
+
+else
+
+ case "$enable_gui_canon" in
+ no|none) { $as_echo "$as_me:${as_lineno-$LINENO}: result: no GUI support" >&5
+$as_echo "no GUI support" >&6; } ;;
+ 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_GTK2=
+ SKIP_GNOME=
+ SKIP_MOTIF=
+ SKIP_ATHENA=
+ SKIP_NEXTAW=
+ SKIP_CARBON=;;
+ 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=;;
+ gnome2) { $as_echo "$as_me:${as_lineno-$LINENO}: result: GNOME 2.x GUI support" >&5
+$as_echo "GNOME 2.x GUI support" >&6; }
+ SKIP_GNOME=
+ SKIP_GTK2=;;
+ gtk3) { $as_echo "$as_me:${as_lineno-$LINENO}: result: GTK+ 3.x GUI support" >&5
+$as_echo "GTK+ 3.x GUI support" >&6; }
+ SKIP_GTK3=;;
+ motif) { $as_echo "$as_me:${as_lineno-$LINENO}: result: Motif GUI support" >&5
+$as_echo "Motif GUI support" >&6; }
+ SKIP_MOTIF=;;
+ athena) { $as_echo "$as_me:${as_lineno-$LINENO}: result: Athena GUI support" >&5
+$as_echo "Athena GUI support" >&6; }
+ SKIP_ATHENA=;;
+ nextaw) { $as_echo "$as_me:${as_lineno-$LINENO}: result: neXtaw GUI support" >&5
+$as_echo "neXtaw GUI support" >&6; }
+ SKIP_NEXTAW=;;
+ *) { $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; } ;;
+ esac
+
+fi
+
+if test "x$SKIP_GTK2" != "xYES" -a "$enable_gui_canon" != "gtk2" \
+ -a "$enable_gui_canon" != "gnome2"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether or not to look for GTK+ 2" >&5
+$as_echo_n "checking whether or not to look for GTK+ 2... " >&6; }
+ # Check whether --enable-gtk2-check was given.
+if test "${enable_gtk2_check+set}" = set; then :
+ enableval=$enable_gtk2_check;
+else
+ enable_gtk2_check="yes"
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_gtk2_check" >&5
+$as_echo "$enable_gtk2_check" >&6; }
+ if test "x$enable_gtk2_check" = "xno"; then
+ SKIP_GTK2=YES
+ SKIP_GNOME=YES
+ fi
+fi
+
+if test "x$SKIP_GNOME" != "xYES" -a "$enable_gui_canon" != "gnome2"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether or not to look for GNOME" >&5
+$as_echo_n "checking whether or not to look for GNOME... " >&6; }
+ # Check whether --enable-gnome-check was given.
+if test "${enable_gnome_check+set}" = set; then :
+ enableval=$enable_gnome_check;
+else
+ enable_gnome_check="no"
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_gnome_check" >&5
+$as_echo "$enable_gnome_check" >&6; }
+ if test "x$enable_gnome_check" = "xno"; then
+ SKIP_GNOME=YES
+ fi
+fi
+
+if test "x$SKIP_GTK3" != "xYES" -a "$enable_gui_canon" != "gtk3"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether or not to look for GTK+ 3" >&5
+$as_echo_n "checking whether or not to look for GTK+ 3... " >&6; }
+ # Check whether --enable-gtk3-check was given.
+if test "${enable_gtk3_check+set}" = set; then :
+ enableval=$enable_gtk3_check;
+else
+ enable_gtk3_check="yes"
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_gtk3_check" >&5
+$as_echo "$enable_gtk3_check" >&6; }
+ if test "x$enable_gtk3_check" = "xno"; then
+ SKIP_GTK3=YES
+ fi
+fi
+
+if test "x$SKIP_MOTIF" != "xYES" -a "$enable_gui_canon" != "motif"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether or not to look for Motif" >&5
+$as_echo_n "checking whether or not to look for Motif... " >&6; }
+ # Check whether --enable-motif-check was given.
+if test "${enable_motif_check+set}" = set; then :
+ enableval=$enable_motif_check;
+else
+ enable_motif_check="yes"
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_motif_check" >&5
+$as_echo "$enable_motif_check" >&6; }
+ if test "x$enable_motif_check" = "xno"; then
+ SKIP_MOTIF=YES
+ fi
+fi
+
+if test "x$SKIP_ATHENA" != "xYES" -a "$enable_gui_canon" != "athena"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether or not to look for Athena" >&5
+$as_echo_n "checking whether or not to look for Athena... " >&6; }
+ # Check whether --enable-athena-check was given.
+if test "${enable_athena_check+set}" = set; then :
+ enableval=$enable_athena_check;
+else
+ enable_athena_check="yes"
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_athena_check" >&5
+$as_echo "$enable_athena_check" >&6; }
+ if test "x$enable_athena_check" = "xno"; then
+ SKIP_ATHENA=YES
+ fi
+fi
+
+if test "x$SKIP_NEXTAW" != "xYES" -a "$enable_gui_canon" != "nextaw"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether or not to look for neXtaw" >&5
+$as_echo_n "checking whether or not to look for neXtaw... " >&6; }
+ # Check whether --enable-nextaw-check was given.
+if test "${enable_nextaw_check+set}" = set; then :
+ enableval=$enable_nextaw_check;
+else
+ enable_nextaw_check="yes"
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_nextaw_check" >&5
+$as_echo "$enable_nextaw_check" >&6; };
+ if test "x$enable_nextaw_check" = "xno"; then
+ SKIP_NEXTAW=YES
+ 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$MACOS_X" = "xyes" -a -z "$SKIP_CARBON" -a "x$CARBON" = "xyes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Carbon GUI" >&5
+$as_echo_n "checking for Carbon GUI... " >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; };
+ GUITYPE=CARBONGUI
+ if test "$VIMNAME" = "vim"; then
+ VIMNAME=Vim
+ fi
+
+ if test "x$MACARCH" = "xboth"; then
+ CPPFLAGS="$CPPFLAGS -I$DEVELOPER_DIR/SDKs/MacOSX10.4u.sdk/Developer/Headers/FlatCarbon"
+ else
+ CPPFLAGS="$CPPFLAGS -I$DEVELOPER_DIR/Headers/FlatCarbon"
+ fi
+
+ if test x$prefix = xNONE; then
+ prefix=/Applications
+ fi
+
+ datadir='${prefix}/Vim.app/Contents/Resources'
+
+ SKIP_GTK2=YES;
+ SKIP_GNOME=YES;
+ SKIP_MOTIF=YES;
+ SKIP_ATHENA=YES;
+ SKIP_NEXTAW=YES;
+ SKIP_PHOTON=YES;
+ SKIP_CARBON=YES
+fi
+
+
+
+
+
+
+
+
+if test -z "$SKIP_GTK2"; then
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking --disable-gtktest argument" >&5
+$as_echo_n "checking --disable-gtktest argument... " >&6; }
+ # Check whether --enable-gtktest was given.
+if test "${enable_gtktest+set}" = set; then :
+ enableval=$enable_gtktest;
+else
+ enable_gtktest=yes
+fi
+
+ if test "x$enable_gtktest" = "xyes" ; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: gtk test enabled" >&5
+$as_echo "gtk test enabled" >&6; }
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: gtk test disabled" >&5
+$as_echo "gtk test disabled" >&6; }
+ fi
+
+ if test "X$PKG_CONFIG" = "X"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
+set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_PKG_CONFIG+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $PKG_CONFIG in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+fi
+PKG_CONFIG=$ac_cv_path_PKG_CONFIG
+if test -n "$PKG_CONFIG"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5
+$as_echo "$PKG_CONFIG" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_path_PKG_CONFIG"; then
+ ac_pt_PKG_CONFIG=$PKG_CONFIG
+ # Extract the first word of "pkg-config", so it can be a program name with args.
+set dummy pkg-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $ac_pt_PKG_CONFIG in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+fi
+ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG
+if test -n "$ac_pt_PKG_CONFIG"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5
+$as_echo "$ac_pt_PKG_CONFIG" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_pt_PKG_CONFIG" = x; then
+ PKG_CONFIG="no"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ PKG_CONFIG=$ac_pt_PKG_CONFIG
+ fi
+else
+ PKG_CONFIG="$ac_cv_path_PKG_CONFIG"
+fi
+
+ fi
+
+ if test "x$PKG_CONFIG" != "xno"; then
+
+ if test "X$GTK_CONFIG" != "Xno" -o "X$PKG_CONFIG" != "Xno"; then
+ {
+ no_gtk=""
+ if (test "X$SKIP_GTK2" != "XYES" -a "X$PKG_CONFIG" != "Xno") \
+ && $PKG_CONFIG --exists gtk+-2.0; then
+ {
+ min_gtk_version=2.2.0
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GTK - version >= $min_gtk_version" >&5
+$as_echo_n "checking for GTK - version >= $min_gtk_version... " >&6; }
+ GTK_CFLAGS=`$PKG_CONFIG --cflags gtk+-2.0`
+ GTK_LIBDIR=`$PKG_CONFIG --libs-only-L gtk+-2.0`
+ GTK_LIBS=`$PKG_CONFIG --libs gtk+-2.0`
+ gtk_major_version=`$PKG_CONFIG --modversion gtk+-2.0 | \
+ sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\1/'`
+ gtk_minor_version=`$PKG_CONFIG --modversion gtk+-2.0 | \
+ sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\2/'`
+ gtk_micro_version=`$PKG_CONFIG --modversion gtk+-2.0 | \
+ sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\3/'`
+ }
+ elif (test "X$SKIP_GTK3" != "XYES" -a "X$PKG_CONFIG" != "Xno") \
+ && $PKG_CONFIG --exists gtk+-3.0; then
+ {
+ min_gtk_version=2.2.0
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GTK - version >= $min_gtk_version" >&5
+$as_echo_n "checking for GTK - version >= $min_gtk_version... " >&6; }
+
+ GTK_CFLAGS=`$PKG_CONFIG --cflags gtk+-3.0`
+ GTK_LIBDIR=`$PKG_CONFIG --libs-only-L gtk+-3.0`
+ GTK_LIBS=`$PKG_CONFIG --libs gtk+-3.0`
+ gtk_major_version=`$PKG_CONFIG --modversion gtk+-3.0 | \
+ sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\1/'`
+ gtk_minor_version=`$PKG_CONFIG --modversion gtk+-3.0 | \
+ sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\2/'`
+ gtk_micro_version=`$PKG_CONFIG --modversion gtk+-3.0 | \
+ sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\3/'`
+ }
+ else
+ no_gtk=yes
+ fi
+
+ if test "x$enable_gtktest" = "xyes" -a "x$no_gtk" = "x"; then
+ {
+ ac_save_CFLAGS="$CFLAGS"
+ ac_save_LIBS="$LIBS"
+ CFLAGS="$CFLAGS $GTK_CFLAGS"
+ LIBS="$LIBS $GTK_LIBS"
+
+ rm -f conf.gtktest
+ if test "$cross_compiling" = yes; then :
+ echo $ac_n "cross compiling; assumed OK... $ac_c"
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <gtk/gtk.h>
+#include <stdio.h>
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#endif
+
+int
+main ()
+{
+int major, minor, micro;
+char *tmp_version;
+
+system ("touch conf.gtktest");
+
+/* HP/UX 9 (%@#!) writes to sscanf strings */
+tmp_version = g_strdup("$min_gtk_version");
+if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, &micro) != 3) {
+ printf("%s, bad version string\n", "$min_gtk_version");
+ exit(1);
+ }
+
+if ((gtk_major_version > major) ||
+ ((gtk_major_version == major) && (gtk_minor_version > minor)) ||
+ ((gtk_major_version == major) && (gtk_minor_version == minor) &&
+ (gtk_micro_version >= micro)))
+{
+ return 0;
+}
+return 1;
+}
+
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+else
+ no_gtk=yes
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+ CFLAGS="$ac_save_CFLAGS"
+ LIBS="$ac_save_LIBS"
+ }
+ fi
+ if test "x$no_gtk" = x ; then
+ if test "x$enable_gtktest" = "xyes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes; found version $gtk_major_version.$gtk_minor_version.$gtk_micro_version" >&5
+$as_echo "yes; found version $gtk_major_version.$gtk_minor_version.$gtk_micro_version" >&6; }
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: found version $gtk_major_version.$gtk_minor_version.$gtk_micro_version" >&5
+$as_echo "found version $gtk_major_version.$gtk_minor_version.$gtk_micro_version" >&6; }
+ fi
+ GUI_LIB_LOC="$GTK_LIBDIR"
+ GTK_LIBNAME="$GTK_LIBS"
+ GUI_INC_LOC="$GTK_CFLAGS"
+ else
+ {
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ GTK_CFLAGS=""
+ GTK_LIBS=""
+ :
+ if test "$fail_if_missing" = "yes" -a "X$gui_auto" != "Xyes"; then
+ as_fn_error $? "could not configure GTK" "$LINENO" 5
+ fi
+ }
+ fi
+ }
+ else
+ GTK_CFLAGS=""
+ GTK_LIBS=""
+ :
+ fi
+
+
+ rm -f conf.gtktest
+
+ if test "x$GTK_CFLAGS" != "x"; then
+ SKIP_GTK3=YES
+ SKIP_ATHENA=YES
+ SKIP_NEXTAW=YES
+ SKIP_MOTIF=YES
+ GUITYPE=GTK
+
+ fi
+ fi
+ if test "x$GUITYPE" = "xGTK"; then
+ if test -z "$SKIP_GNOME"; then
+ {
+
+
+
+
+
+
+# Check whether --with-gnome-includes was given.
+if test "${with_gnome_includes+set}" = set; then :
+ withval=$with_gnome_includes; CFLAGS="$CFLAGS -I$withval"
+
+fi
+
+
+
+# Check whether --with-gnome-libs was given.
+if test "${with_gnome_libs+set}" = set; then :
+ withval=$with_gnome_libs; LDFLAGS="$LDFLAGS -L$withval" gnome_prefix=$withval
+
+fi
+
+
+
+# Check whether --with-gnome was given.
+if test "${with_gnome+set}" = set; then :
+ withval=$with_gnome; if test x$withval = xyes; then
+ want_gnome=yes
+ have_gnome=yes
+ else
+ if test "x$withval" = xno; then
+ want_gnome=no
+ else
+ want_gnome=yes
+ LDFLAGS="$LDFLAGS -L$withval/lib"
+ CFLAGS="$CFLAGS -I$withval/include"
+ gnome_prefix=$withval/lib
+ fi
+ fi
+else
+ want_gnome=yes
+fi
+
+
+ if test "x$want_gnome" = xyes; then
+ {
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libgnomeui-2.0" >&5
+$as_echo_n "checking for libgnomeui-2.0... " >&6; }
+ if $PKG_CONFIG --exists libgnomeui-2.0; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ GNOME_LIBS=`$PKG_CONFIG --libs-only-l libgnomeui-2.0`
+ GNOME_LIBDIR=`$PKG_CONFIG --libs-only-L libgnomeui-2.0`
+ GNOME_INCLUDEDIR=`$PKG_CONFIG --cflags libgnomeui-2.0`
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for FreeBSD" >&5
+$as_echo_n "checking for FreeBSD... " >&6; }
+ if test "`(uname) 2>/dev/null`" = FreeBSD; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ GNOME_INCLUDEDIR="$GNOME_INCLUDEDIR -D_THREAD_SAFE"
+ GNOME_LIBS="$GNOME_LIBS -pthread"
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ fi
+ have_gnome=yes
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5
+$as_echo "not found" >&6; }
+ if test "x" = xfail; then
+ as_fn_error $? "Could not find libgnomeui-2.0 via pkg-config" "$LINENO" 5
+ fi
+ fi
+ }
+ fi
+
+ if test "x$have_gnome" = xyes ; then
+ $as_echo "#define FEAT_GUI_GNOME 1" >>confdefs.h
+
+ GUI_INC_LOC="$GUI_INC_LOC $GNOME_INCLUDEDIR"
+ GTK_LIBNAME="$GTK_LIBNAME $GNOME_LIBDIR $GNOME_LIBS"
+ fi
+ }
+ fi
+ fi
+fi
+
+
+if test -z "$SKIP_GTK3"; then
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking --disable-gtktest argument" >&5
+$as_echo_n "checking --disable-gtktest argument... " >&6; }
+ # Check whether --enable-gtktest was given.
+if test "${enable_gtktest+set}" = set; then :
+ enableval=$enable_gtktest;
+else
+ enable_gtktest=yes
+fi
+
+ if test "x$enable_gtktest" = "xyes" ; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: gtk test enabled" >&5
+$as_echo "gtk test enabled" >&6; }
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: gtk test disabled" >&5
+$as_echo "gtk test disabled" >&6; }
+ fi
+
+ if test "X$PKG_CONFIG" = "X"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
+set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_PKG_CONFIG+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $PKG_CONFIG in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+fi
+PKG_CONFIG=$ac_cv_path_PKG_CONFIG
+if test -n "$PKG_CONFIG"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5
+$as_echo "$PKG_CONFIG" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_path_PKG_CONFIG"; then
+ ac_pt_PKG_CONFIG=$PKG_CONFIG
+ # Extract the first word of "pkg-config", so it can be a program name with args.
+set dummy pkg-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $ac_pt_PKG_CONFIG in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+fi
+ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG
+if test -n "$ac_pt_PKG_CONFIG"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5
+$as_echo "$ac_pt_PKG_CONFIG" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_pt_PKG_CONFIG" = x; then
+ PKG_CONFIG="no"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ PKG_CONFIG=$ac_pt_PKG_CONFIG
+ fi
+else
+ PKG_CONFIG="$ac_cv_path_PKG_CONFIG"
+fi
+
+ fi
+
+ if test "x$PKG_CONFIG" != "xno"; then
+
+ if test "X$GTK_CONFIG" != "Xno" -o "X$PKG_CONFIG" != "Xno"; then
+ {
+ no_gtk=""
+ if (test "X$SKIP_GTK2" != "XYES" -a "X$PKG_CONFIG" != "Xno") \
+ && $PKG_CONFIG --exists gtk+-2.0; then
+ {
+ min_gtk_version=3.0.0
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GTK - version >= $min_gtk_version" >&5
+$as_echo_n "checking for GTK - version >= $min_gtk_version... " >&6; }
+ GTK_CFLAGS=`$PKG_CONFIG --cflags gtk+-2.0`
+ GTK_LIBDIR=`$PKG_CONFIG --libs-only-L gtk+-2.0`
+ GTK_LIBS=`$PKG_CONFIG --libs gtk+-2.0`
+ gtk_major_version=`$PKG_CONFIG --modversion gtk+-2.0 | \
+ sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\1/'`
+ gtk_minor_version=`$PKG_CONFIG --modversion gtk+-2.0 | \
+ sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\2/'`
+ gtk_micro_version=`$PKG_CONFIG --modversion gtk+-2.0 | \
+ sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\3/'`
+ }
+ elif (test "X$SKIP_GTK3" != "XYES" -a "X$PKG_CONFIG" != "Xno") \
+ && $PKG_CONFIG --exists gtk+-3.0; then
+ {
+ min_gtk_version=3.0.0
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GTK - version >= $min_gtk_version" >&5
+$as_echo_n "checking for GTK - version >= $min_gtk_version... " >&6; }
+
+ GTK_CFLAGS=`$PKG_CONFIG --cflags gtk+-3.0`
+ GTK_LIBDIR=`$PKG_CONFIG --libs-only-L gtk+-3.0`
+ GTK_LIBS=`$PKG_CONFIG --libs gtk+-3.0`
+ gtk_major_version=`$PKG_CONFIG --modversion gtk+-3.0 | \
+ sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\1/'`
+ gtk_minor_version=`$PKG_CONFIG --modversion gtk+-3.0 | \
+ sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\2/'`
+ gtk_micro_version=`$PKG_CONFIG --modversion gtk+-3.0 | \
+ sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\3/'`
+ }
+ else
+ no_gtk=yes
+ fi
+
+ if test "x$enable_gtktest" = "xyes" -a "x$no_gtk" = "x"; then
+ {
+ ac_save_CFLAGS="$CFLAGS"
+ ac_save_LIBS="$LIBS"
+ CFLAGS="$CFLAGS $GTK_CFLAGS"
+ LIBS="$LIBS $GTK_LIBS"
+
+ rm -f conf.gtktest
+ if test "$cross_compiling" = yes; then :
+ echo $ac_n "cross compiling; assumed OK... $ac_c"
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <gtk/gtk.h>
+#include <stdio.h>
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#endif
+
+int
+main ()
+{
+int major, minor, micro;
+char *tmp_version;
+
+system ("touch conf.gtktest");
+
+/* HP/UX 9 (%@#!) writes to sscanf strings */
+tmp_version = g_strdup("$min_gtk_version");
+if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, &micro) != 3) {
+ printf("%s, bad version string\n", "$min_gtk_version");
+ exit(1);
+ }
+
+if ((gtk_major_version > major) ||
+ ((gtk_major_version == major) && (gtk_minor_version > minor)) ||
+ ((gtk_major_version == major) && (gtk_minor_version == minor) &&
+ (gtk_micro_version >= micro)))
+{
+ return 0;
+}
+return 1;
+}
+
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+else
+ no_gtk=yes
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+ CFLAGS="$ac_save_CFLAGS"
+ LIBS="$ac_save_LIBS"
+ }
+ fi
+ if test "x$no_gtk" = x ; then
+ if test "x$enable_gtktest" = "xyes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes; found version $gtk_major_version.$gtk_minor_version.$gtk_micro_version" >&5
+$as_echo "yes; found version $gtk_major_version.$gtk_minor_version.$gtk_micro_version" >&6; }
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: found version $gtk_major_version.$gtk_minor_version.$gtk_micro_version" >&5
+$as_echo "found version $gtk_major_version.$gtk_minor_version.$gtk_micro_version" >&6; }
+ fi
+ GUI_LIB_LOC="$GTK_LIBDIR"
+ GTK_LIBNAME="$GTK_LIBS"
+ GUI_INC_LOC="$GTK_CFLAGS"
+ else
+ {
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ GTK_CFLAGS=""
+ GTK_LIBS=""
+ :
+ if test "$fail_if_missing" = "yes" -a "X$gui_auto" != "Xyes"; then
+ as_fn_error $? "could not configure GTK" "$LINENO" 5
+ fi
+ }
+ fi
+ }
+ else
+ GTK_CFLAGS=""
+ GTK_LIBS=""
+ :
+ fi
+
+
+ rm -f conf.gtktest
+
+ if test "x$GTK_CFLAGS" != "x"; then
+ SKIP_GTK2=YES
+ SKIP_GNOME=YES
+ SKIP_ATHENA=YES
+ SKIP_NEXTAW=YES
+ SKIP_MOTIF=YES
+ GUITYPE=GTK
+
+ $as_echo "#define USE_GTK3 1" >>confdefs.h
+
+ fi
+ fi
+fi
+
+if test "x$GUITYPE" = "xGTK"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking version of Gdk-Pixbuf" >&5
+$as_echo_n "checking version of Gdk-Pixbuf... " >&6; }
+ gdk_pixbuf_version=`$PKG_CONFIG --modversion gdk-pixbuf-2.0`
+ if test "x$gdk_pixbuf_version" != x ; then
+ gdk_pixbuf_version_minor=`echo $gdk_pixbuf_version | \
+ sed -e 's/[0-9][0-9]*\.\([0-9][0-9]*\)\.[0-9][0-9]*/\1/'`
+ if test "x$gdk_pixbuf_version_minor" != x -a \
+ $gdk_pixbuf_version_minor -ge 31 ; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: OK." >&5
+$as_echo "OK." >&6; }
+ # Extract the first word of "glib-compile-resources", so it can be a program name with args.
+set dummy glib-compile-resources; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_GLIB_COMPILE_RESOURCES+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $GLIB_COMPILE_RESOURCES in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_GLIB_COMPILE_RESOURCES="$GLIB_COMPILE_RESOURCES" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_GLIB_COMPILE_RESOURCES="$as_dir/$ac_word$ac_exec_ext"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ test -z "$ac_cv_path_GLIB_COMPILE_RESOURCES" && ac_cv_path_GLIB_COMPILE_RESOURCES="no"
+ ;;
+esac
+fi
+GLIB_COMPILE_RESOURCES=$ac_cv_path_GLIB_COMPILE_RESOURCES
+if test -n "$GLIB_COMPILE_RESOURCES"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GLIB_COMPILE_RESOURCES" >&5
+$as_echo "$GLIB_COMPILE_RESOURCES" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking glib-compile-resources" >&5
+$as_echo_n "checking glib-compile-resources... " >&6; }
+ if test "x$GLIB_COMPILE_RESOURCES" = xno ; then
+ GLIB_COMPILE_RESOURCES=""
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: cannot be found in PATH." >&5
+$as_echo "cannot be found in PATH." >&6; }
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: usable." >&5
+$as_echo "usable." >&6; }
+ $as_echo "#define USE_GRESOURCE 1" >>confdefs.h
+
+ GRESOURCE_SRC="auto/gui_gtk_gresources.c"
+ GRESOURCE_OBJ="objects/gui_gtk_gresources.o"
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: not usable." >&5
+$as_echo "not usable." >&6; }
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: cannot obtain from pkg_config." >&5
+$as_echo "cannot obtain from pkg_config." >&6; }
+ fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking --disable-icon-cache-update argument" >&5
+$as_echo_n "checking --disable-icon-cache-update argument... " >&6; }
+ # Check whether --enable-icon_cache_update was given.
+if test "${enable_icon_cache_update+set}" = set; then :
+ enableval=$enable_icon_cache_update;
+else
+ enable_icon_cache_update="yes"
+fi
+
+ if test "$enable_icon_cache_update" = "yes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: not set" >&5
+$as_echo "not set" >&6; }
+ # Extract the first word of "gtk-update-icon-cache", so it can be a program name with args.
+set dummy gtk-update-icon-cache; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_GTK_UPDATE_ICON_CACHE+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $GTK_UPDATE_ICON_CACHE in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_GTK_UPDATE_ICON_CACHE="$GTK_UPDATE_ICON_CACHE" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_GTK_UPDATE_ICON_CACHE="$as_dir/$ac_word$ac_exec_ext"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ test -z "$ac_cv_path_GTK_UPDATE_ICON_CACHE" && ac_cv_path_GTK_UPDATE_ICON_CACHE="no"
+ ;;
+esac
+fi
+GTK_UPDATE_ICON_CACHE=$ac_cv_path_GTK_UPDATE_ICON_CACHE
+if test -n "$GTK_UPDATE_ICON_CACHE"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GTK_UPDATE_ICON_CACHE" >&5
+$as_echo "$GTK_UPDATE_ICON_CACHE" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ if test "x$GTK_UPDATE_ICON_CACHE" = "xno" ; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found in PATH." >&5
+$as_echo "not found in PATH." >&6; }
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: update disabled" >&5
+$as_echo "update disabled" >&6; }
+ fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking --disable-desktop-database-update argument" >&5
+$as_echo_n "checking --disable-desktop-database-update argument... " >&6; }
+ # Check whether --enable-desktop_database_update was given.
+if test "${enable_desktop_database_update+set}" = set; then :
+ enableval=$enable_desktop_database_update;
+else
+ enable_desktop_database_update="yes"
+fi
+
+ if test "$enable_desktop_database_update" = "yes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: not set" >&5
+$as_echo "not set" >&6; }
+ # Extract the first word of "update-desktop-database", so it can be a program name with args.
+set dummy update-desktop-database; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_UPDATE_DESKTOP_DATABASE+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $UPDATE_DESKTOP_DATABASE in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_UPDATE_DESKTOP_DATABASE="$UPDATE_DESKTOP_DATABASE" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_UPDATE_DESKTOP_DATABASE="$as_dir/$ac_word$ac_exec_ext"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ test -z "$ac_cv_path_UPDATE_DESKTOP_DATABASE" && ac_cv_path_UPDATE_DESKTOP_DATABASE="no"
+ ;;
+esac
+fi
+UPDATE_DESKTOP_DATABASE=$ac_cv_path_UPDATE_DESKTOP_DATABASE
+if test -n "$UPDATE_DESKTOP_DATABASE"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $UPDATE_DESKTOP_DATABASE" >&5
+$as_echo "$UPDATE_DESKTOP_DATABASE" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ if test "x$UPDATE_DESKTOP_DATABASE" = "xno" ; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found in PATH." >&5
+$as_echo "not found in PATH." >&6; }
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: update disabled" >&5
+$as_echo "update disabled" >&6; }
+ fi
+fi
+
+
+
+
+
+
+
+if test -z "$SKIP_MOTIF"; then
+ gui_XXX="/usr/XXX/Motif* /usr/Motif*/XXX /usr/XXX /usr/shlib /usr/X11*/XXX /usr/XXX/X11* /usr/dt/XXX /local/Motif*/XXX /local/XXX/Motif* /usr/local/Motif*/XXX /usr/local/XXX/Motif* /usr/local/XXX /usr/local/X11*/XXX /usr/local/LessTif/Motif*/XXX $MOTIFHOME/XXX"
+ GUI_INC_LOC="`echo $GUI_INC_LOC|sed 's%-I%%g'`"
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for location of Motif GUI includes" >&5
+$as_echo_n "checking for location of Motif GUI includes... " >&6; }
+ gui_includes="`echo $x_includes|sed 's%/^/^/*$%%'` `echo "$gui_XXX" | sed s/XXX/include/g` $GUI_INC_LOC"
+ GUI_INC_LOC=
+ for try in $gui_includes; do
+ if test -f "$try/Xm/Xm.h"; then
+ GUI_INC_LOC=$try
+ fi
+ done
+ if test -n "$GUI_INC_LOC"; then
+ if test "$GUI_INC_LOC" = /usr/include; then
+ GUI_INC_LOC=
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: in default path" >&5
+$as_echo "in default path" >&6; }
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GUI_INC_LOC" >&5
+$as_echo "$GUI_INC_LOC" >&6; }
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: <not found>" >&5
+$as_echo "<not found>" >&6; }
+ SKIP_MOTIF=YES
+ fi
+fi
+
+
+if test -z "$SKIP_MOTIF"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking --with-motif-lib argument" >&5
+$as_echo_n "checking --with-motif-lib argument... " >&6; }
+
+# Check whether --with-motif-lib was given.
+if test "${with_motif_lib+set}" = set; then :
+ withval=$with_motif_lib; MOTIF_LIBNAME="${withval}"
+fi
+
+
+ if test -n "$MOTIF_LIBNAME"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MOTIF_LIBNAME" >&5
+$as_echo "$MOTIF_LIBNAME" >&6; }
+ GUI_LIB_LOC=
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+ GUI_LIB_LOC="`echo $GUI_LIB_LOC|sed 's%-L%%g'`"
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for location of Motif GUI libs" >&5
+$as_echo_n "checking for location of Motif GUI libs... " >&6; }
+ gui_libs="`echo $x_libraries|sed 's%/^/^/*$%%'` `echo "$gui_XXX" | sed s/XXX/lib/g` /usr/lib/i386-linux-gnu /usr/lib/x86_64-linux-gnu `echo "$GUI_INC_LOC" | sed s/include/lib/` $GUI_LIB_LOC"
+ GUI_LIB_LOC=
+ for try in $gui_libs; do
+ for libtry in "$try"/libXm.a "$try"/libXm.so* "$try"/libXm.sl "$try"/libXm.dylib; do
+ if test -f "$libtry"; then
+ GUI_LIB_LOC=$try
+ fi
+ done
+ done
+ if test -n "$GUI_LIB_LOC"; then
+ if test "$GUI_LIB_LOC" = /usr/lib \
+ -o "$GUI_LIB_LOC" = /usr/lib/i386-linux-gnu \
+ -o "$GUI_LIB_LOC" = /usr/lib/x86_64-linux-gnu; then
+ GUI_LIB_LOC=
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: in default path" >&5
+$as_echo "in default path" >&6; }
+ else
+ if test -n "$GUI_LIB_LOC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GUI_LIB_LOC" >&5
+$as_echo "$GUI_LIB_LOC" >&6; }
+ if test "`(uname) 2>/dev/null`" = SunOS &&
+ uname -r | grep '^5' >/dev/null; then
+ GUI_LIB_LOC="$GUI_LIB_LOC -R $GUI_LIB_LOC"
+ fi
+ fi
+ fi
+ MOTIF_LIBNAME=-lXm
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: <not found>" >&5
+$as_echo "<not found>" >&6; }
+ SKIP_MOTIF=YES
+ fi
+ fi
+fi
+
+if test -z "$SKIP_MOTIF"; then
+ SKIP_ATHENA=YES
+ SKIP_NEXTAW=YES
+ GUITYPE=MOTIF
+
+fi
+
+
+GUI_X_LIBS=
+
+if test -z "$SKIP_ATHENA"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if Athena header files can be found" >&5
+$as_echo_n "checking if Athena header files can be found... " >&6; }
+ cflags_save=$CFLAGS
+ CFLAGS="$CFLAGS $X_CFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <X11/Intrinsic.h>
+#include <X11/Xaw/Paned.h>
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }; SKIP_ATHENA=YES
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ CFLAGS=$cflags_save
+fi
+
+if test -z "$SKIP_ATHENA"; then
+ GUITYPE=ATHENA
+fi
+
+if test -z "$SKIP_NEXTAW"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if neXtaw header files can be found" >&5
+$as_echo_n "checking if neXtaw header files can be found... " >&6; }
+ cflags_save=$CFLAGS
+ CFLAGS="$CFLAGS $X_CFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <X11/Intrinsic.h>
+#include <X11/neXtaw/Paned.h>
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }; SKIP_NEXTAW=YES
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ CFLAGS=$cflags_save
+fi
+
+if test -z "$SKIP_NEXTAW"; then
+ GUITYPE=NEXTAW
+fi
+
+if test -z "$SKIP_ATHENA" -o -z "$SKIP_NEXTAW" -o -z "$SKIP_MOTIF"; then
+ if test -n "$GUI_INC_LOC"; then
+ GUI_INC_LOC=-I"`echo $GUI_INC_LOC|sed 's%-I%%'`"
+ fi
+ if test -n "$GUI_LIB_LOC"; then
+ GUI_LIB_LOC=-L"`echo $GUI_LIB_LOC|sed 's%-L%%'`"
+ fi
+
+ ldflags_save=$LDFLAGS
+ LDFLAGS="$X_LIBS $LDFLAGS"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for XShapeQueryExtension in -lXext" >&5
+$as_echo_n "checking for XShapeQueryExtension in -lXext... " >&6; }
+if ${ac_cv_lib_Xext_XShapeQueryExtension+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lXext -lXt $X_PRE_LIBS -lX11 $X_EXTRA_LIBS $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char XShapeQueryExtension ();
+int
+main ()
+{
+return XShapeQueryExtension ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_Xext_XShapeQueryExtension=yes
+else
+ ac_cv_lib_Xext_XShapeQueryExtension=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_Xext_XShapeQueryExtension" >&5
+$as_echo "$ac_cv_lib_Xext_XShapeQueryExtension" >&6; }
+if test "x$ac_cv_lib_Xext_XShapeQueryExtension" = xyes; then :
+ GUI_X_LIBS="-lXext"
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for wslen in -lw" >&5
+$as_echo_n "checking for wslen in -lw... " >&6; }
+if ${ac_cv_lib_w_wslen+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lw $GUI_X_LIBS -lXt $X_PRE_LIBS -lX11 $X_EXTRA_LIBS $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char wslen ();
+int
+main ()
+{
+return wslen ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_w_wslen=yes
+else
+ ac_cv_lib_w_wslen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_w_wslen" >&5
+$as_echo "$ac_cv_lib_w_wslen" >&6; }
+if test "x$ac_cv_lib_w_wslen" = xyes; then :
+ X_EXTRA_LIBS="$X_EXTRA_LIBS -lw"
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlsym in -ldl" >&5
+$as_echo_n "checking for dlsym in -ldl... " >&6; }
+if ${ac_cv_lib_dl_dlsym+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl $GUI_X_LIBS -lXt $X_PRE_LIBS -lX11 $X_EXTRA_LIBS $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlsym ();
+int
+main ()
+{
+return dlsym ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_dl_dlsym=yes
+else
+ ac_cv_lib_dl_dlsym=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlsym" >&5
+$as_echo "$ac_cv_lib_dl_dlsym" >&6; }
+if test "x$ac_cv_lib_dl_dlsym" = xyes; then :
+ X_EXTRA_LIBS="$X_EXTRA_LIBS -ldl"
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for XmuCreateStippledPixmap in -lXmu" >&5
+$as_echo_n "checking for XmuCreateStippledPixmap in -lXmu... " >&6; }
+if ${ac_cv_lib_Xmu_XmuCreateStippledPixmap+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lXmu $GUI_X_LIBS -lXt $X_PRE_LIBS -lX11 $X_EXTRA_LIBS $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char XmuCreateStippledPixmap ();
+int
+main ()
+{
+return XmuCreateStippledPixmap ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_Xmu_XmuCreateStippledPixmap=yes
+else
+ ac_cv_lib_Xmu_XmuCreateStippledPixmap=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_Xmu_XmuCreateStippledPixmap" >&5
+$as_echo "$ac_cv_lib_Xmu_XmuCreateStippledPixmap" >&6; }
+if test "x$ac_cv_lib_Xmu_XmuCreateStippledPixmap" = xyes; then :
+ GUI_X_LIBS="-lXmu $GUI_X_LIBS"
+fi
+
+ if test -z "$SKIP_MOTIF"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for XpEndJob in -lXp" >&5
+$as_echo_n "checking for XpEndJob in -lXp... " >&6; }
+if ${ac_cv_lib_Xp_XpEndJob+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lXp $GUI_X_LIBS -lXm -lXt $X_PRE_LIBS -lX11 $X_EXTRA_LIBS $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char XpEndJob ();
+int
+main ()
+{
+return XpEndJob ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_Xp_XpEndJob=yes
+else
+ ac_cv_lib_Xp_XpEndJob=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_Xp_XpEndJob" >&5
+$as_echo "$ac_cv_lib_Xp_XpEndJob" >&6; }
+if test "x$ac_cv_lib_Xp_XpEndJob" = xyes; then :
+ GUI_X_LIBS="-lXp $GUI_X_LIBS"
+fi
+
+ fi
+ LDFLAGS=$ldflags_save
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for extra X11 defines" >&5
+$as_echo_n "checking for extra X11 defines... " >&6; }
+ NARROW_PROTO=
+ rm -fr conftestdir
+ if mkdir conftestdir; then
+ cd conftestdir
+ cat > Imakefile <<'EOF'
+acfindx:
+ @echo 'NARROW_PROTO="${PROTO_DEFINES}"'
+EOF
+ if (xmkmf) >/dev/null 2>/dev/null && test -f Makefile; then
+ eval `${MAKE-make} acfindx 2>/dev/null | grep -v make`
+ fi
+ cd ..
+ rm -fr conftestdir
+ fi
+ if test -z "$NARROW_PROTO"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NARROW_PROTO" >&5
+$as_echo "$NARROW_PROTO" >&6; }
+ fi
+
+fi
+
+if test "$enable_xsmp" = "yes"; then
+ cppflags_save=$CPPFLAGS
+ CPPFLAGS="$CPPFLAGS $X_CFLAGS"
+ for ac_header in X11/SM/SMlib.h
+do :
+ ac_fn_c_check_header_mongrel "$LINENO" "X11/SM/SMlib.h" "ac_cv_header_X11_SM_SMlib_h" "$ac_includes_default"
+if test "x$ac_cv_header_X11_SM_SMlib_h" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_X11_SM_SMLIB_H 1
+_ACEOF
+
+fi
+
+done
+
+ CPPFLAGS=$cppflags_save
+fi
+
+
+if test -z "$SKIP_ATHENA" -o -z "$SKIP_NEXTAW" -o -z "$SKIP_MOTIF" -o -z "$SKIP_GTK2" -o -z "$SKIP_GTK3"; then
+ cppflags_save=$CPPFLAGS
+ CPPFLAGS="$CPPFLAGS $X_CFLAGS"
+ for ac_header in X11/xpm.h X11/Sunkeysym.h
+do :
+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+ if test ! "$enable_xim" = "no"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for XIMText in X11/Xlib.h" >&5
+$as_echo_n "checking for XIMText in X11/Xlib.h... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <X11/Xlib.h>
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "XIMText" >/dev/null 2>&1; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no; xim has been disabled" >&5
+$as_echo "no; xim has been disabled" >&6; }; enable_xim="no"
+fi
+rm -f conftest*
+
+ fi
+ CPPFLAGS=$cppflags_save
+
+ if test "$enable_xim" = "auto" -a "$enable_hangulinput" != "yes" \
+ -a "x$GUITYPE" != "xNONE" ; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: X GUI selected; xim has been enabled" >&5
+$as_echo "X GUI selected; xim has been enabled" >&6; }
+ enable_xim="yes"
+ fi
+fi
+
+if test -z "$SKIP_ATHENA" -o -z "$SKIP_NEXTAW" -o -z "$SKIP_MOTIF"; then
+ cppflags_save=$CPPFLAGS
+ CPPFLAGS="$CPPFLAGS $X_CFLAGS"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for X11/Xmu/Editres.h" >&5
+$as_echo_n "checking for X11/Xmu/Editres.h... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <X11/Intrinsic.h>
+#include <X11/Xmu/Editres.h>
+int
+main ()
+{
+int i; i = 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ $as_echo "#define HAVE_X11_XMU_EDITRES_H 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ CPPFLAGS=$cppflags_save
+fi
+
+if test -z "$SKIP_MOTIF"; then
+ cppflags_save=$CPPFLAGS
+ CPPFLAGS="$CPPFLAGS $X_CFLAGS"
+ if test "$zOSUnix" = "yes"; then
+ xmheader="Xm/Xm.h"
+ else
+ xmheader="Xm/Xm.h Xm/XpmP.h Xm/JoinSideT.h Xm/TraitP.h Xm/Manager.h
+ Xm/UnhighlightT.h Xm/Notebook.h"
+ fi
+ for ac_header in $xmheader
+do :
+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+ if test "x$ac_cv_header_Xm_XpmP_h" = "xyes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for XpmAttributes_21 in Xm/XpmP.h" >&5
+$as_echo_n "checking for XpmAttributes_21 in Xm/XpmP.h... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <Xm/XpmP.h>
+int
+main ()
+{
+XpmAttributes_21 attr;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }; $as_echo "#define XPMATTRIBUTES_TYPE XpmAttributes_21" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }; $as_echo "#define XPMATTRIBUTES_TYPE XpmAttributes" >>confdefs.h
+
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ else
+ $as_echo "#define XPMATTRIBUTES_TYPE XpmAttributes" >>confdefs.h
+
+ fi
+ CPPFLAGS=$cppflags_save
+fi
+
+if test "x$GUITYPE" = "xNONE" -a "$enable_xim" = "yes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no GUI selected; xim has been disabled" >&5
+$as_echo "no GUI selected; xim has been disabled" >&6; }
+ enable_xim="no"
+fi
+if test "x$GUITYPE" = "xNONE" -a "$enable_fontset" = "yes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no GUI selected; fontset has been disabled" >&5
+$as_echo "no GUI selected; fontset has been disabled" >&6; }
+ enable_fontset="no"
+fi
+if test "x$GUITYPE:$enable_fontset" = "xGTK:yes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: GTK+ 2 GUI selected; fontset has been disabled" >&5
+$as_echo "GTK+ 2 GUI selected; fontset has been disabled" >&6; }
+ enable_fontset="no"
+fi
+
+if test -z "$SKIP_PHOTON"; then
+ GUITYPE=PHOTONGUI
+fi
+
+
+
+
+
+
+if test "$enable_workshop" = "yes" -a -n "$SKIP_MOTIF"; then
+ as_fn_error $? "cannot use workshop without Motif" "$LINENO" 5
+fi
+
+if test "$enable_xim" = "yes"; then
+ $as_echo "#define FEAT_XIM 1" >>confdefs.h
+
+fi
+if test "$enable_fontset" = "yes"; then
+ $as_echo "#define FEAT_XFONTSET 1" >>confdefs.h
+
+fi
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for /proc link to executable" >&5
+$as_echo_n "checking for /proc link to executable... " >&6; }
+if test -L "/proc/self/exe"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: /proc/self/exe" >&5
+$as_echo "/proc/self/exe" >&6; }
+ $as_echo "#define PROC_EXE_LINK \"/proc/self/exe\"" >>confdefs.h
+
+elif test -L "/proc/self/path/a.out"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: /proc/self/path/a.out" >&5
+$as_echo "/proc/self/path/a.out" >&6; }
+ $as_echo "#define PROC_EXE_LINK \"/proc/self/path/a.out\"" >>confdefs.h
+
+elif test -L "/proc/curproc/file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: /proc/curproc/file" >&5
+$as_echo "/proc/curproc/file" >&6; }
+ $as_echo "#define PROC_EXE_LINK \"/proc/curproc/file\"" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for CYGWIN or MSYS environment" >&5
+$as_echo_n "checking for CYGWIN or MSYS environment... " >&6; }
+case `uname` in
+ CYGWIN*|MSYS*) CYGWIN=yes; { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for CYGWIN clipboard support" >&5
+$as_echo_n "checking for CYGWIN clipboard support... " >&6; }
+ if test "x$with_x" = "xno" ; then
+ OS_EXTRA_SRC=winclip.c; OS_EXTRA_OBJ=objects/winclip.o
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ $as_echo "#define FEAT_CYGWIN_WIN32_CLIPBOARD 1" >>confdefs.h
+
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no - using X11" >&5
+$as_echo "no - using X11" >&6; }
+ fi ;;
+
+ *) CYGWIN=no; { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; };;
+esac
+
+if test "$enable_hangulinput" = "yes"; then
+ if test "x$GUITYPE" = "xNONE"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no GUI selected; hangul input has been disabled" >&5
+$as_echo "no GUI selected; hangul input has been disabled" >&6; }
+ enable_hangulinput=no
+ else
+ $as_echo "#define FEAT_HANGULIN 1" >>confdefs.h
+
+ HANGULIN_SRC=hangulin.c
+
+ HANGULIN_OBJ=objects/hangulin.o
+
+ fi
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether toupper is broken" >&5
+$as_echo_n "checking whether toupper is broken... " >&6; }
+if ${vim_cv_toupper_broken+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ if test "$cross_compiling" = yes; then :
+
+ as_fn_error $? "cross-compiling: please set 'vim_cv_toupper_broken'" "$LINENO" 5
+
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include "confdefs.h"
+#include <ctype.h>
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#endif
+main() { exit(toupper('A') == 'A' && tolower('z') == 'z'); }
+
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+ vim_cv_toupper_broken=yes
+
+else
+
+ vim_cv_toupper_broken=no
+
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vim_cv_toupper_broken" >&5
+$as_echo "$vim_cv_toupper_broken" >&6; }
+
+if test "x$vim_cv_toupper_broken" = "xyes" ; then
+ $as_echo "#define BROKEN_TOUPPER 1" >>confdefs.h
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether __DATE__ and __TIME__ work" >&5
+$as_echo_n "checking whether __DATE__ and __TIME__ work... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdio.h>
+int
+main ()
+{
+printf("(" __DATE__ " " __TIME__ ")");
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }; $as_echo "#define HAVE_DATE_TIME 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether __attribute__((unused)) is allowed" >&5
+$as_echo_n "checking whether __attribute__((unused)) is allowed... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdio.h>
+int
+main ()
+{
+int x __attribute__((unused));
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }; $as_echo "#define HAVE_ATTRIBUTE_UNUSED 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+ac_fn_c_check_header_mongrel "$LINENO" "elf.h" "ac_cv_header_elf_h" "$ac_includes_default"
+if test "x$ac_cv_header_elf_h" = xyes; then :
+ HAS_ELF=1
+fi
+
+
+if test "$HAS_ELF" = 1; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lelf" >&5
+$as_echo_n "checking for main in -lelf... " >&6; }
+if ${ac_cv_lib_elf_main+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lelf $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+
+int
+main ()
+{
+return main ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_elf_main=yes
+else
+ ac_cv_lib_elf_main=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_elf_main" >&5
+$as_echo "$ac_cv_lib_elf_main" >&6; }
+if test "x$ac_cv_lib_elf_main" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBELF 1
+_ACEOF
+
+ LIBS="-lelf $LIBS"
+
+fi
+
+fi
+
+ac_header_dirent=no
+for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do
+ as_ac_Header=`$as_echo "ac_cv_header_dirent_$ac_hdr" | $as_tr_sh`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_hdr that defines DIR" >&5
+$as_echo_n "checking for $ac_hdr that defines DIR... " >&6; }
+if eval \${$as_ac_Header+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <$ac_hdr>
+
+int
+main ()
+{
+if ((DIR *) 0)
+return 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ eval "$as_ac_Header=yes"
+else
+ eval "$as_ac_Header=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$as_ac_Header
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_hdr" | $as_tr_cpp` 1
+_ACEOF
+
+ac_header_dirent=$ac_hdr; break
+fi
+
+done
+# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix.
+if test $ac_header_dirent = dirent.h; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5
+$as_echo_n "checking for library containing opendir... " >&6; }
+if ${ac_cv_search_opendir+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char opendir ();
+int
+main ()
+{
+return opendir ();
+ ;
+ return 0;
+}
+_ACEOF
+for ac_lib in '' dir; do
+ if test -z "$ac_lib"; then
+ ac_res="none required"
+ else
+ ac_res=-l$ac_lib
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ fi
+ if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_search_opendir=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext
+ if ${ac_cv_search_opendir+:} false; then :
+ break
+fi
+done
+if ${ac_cv_search_opendir+:} false; then :
+
+else
+ ac_cv_search_opendir=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5
+$as_echo "$ac_cv_search_opendir" >&6; }
+ac_res=$ac_cv_search_opendir
+if test "$ac_res" != no; then :
+ test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+fi
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5
+$as_echo_n "checking for library containing opendir... " >&6; }
+if ${ac_cv_search_opendir+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char opendir ();
+int
+main ()
+{
+return opendir ();
+ ;
+ return 0;
+}
+_ACEOF
+for ac_lib in '' x; do
+ if test -z "$ac_lib"; then
+ ac_res="none required"
+ else
+ ac_res=-l$ac_lib
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ fi
+ if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_search_opendir=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext
+ if ${ac_cv_search_opendir+:} false; then :
+ break
+fi
+done
+if ${ac_cv_search_opendir+:} false; then :
+
+else
+ ac_cv_search_opendir=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5
+$as_echo "$ac_cv_search_opendir" >&6; }
+ac_res=$ac_cv_search_opendir
+if test "$ac_res" != no; then :
+ test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+fi
+
+fi
+
+
+if test $ac_cv_header_sys_wait_h = no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sys/wait.h that defines union wait" >&5
+$as_echo_n "checking for sys/wait.h that defines union wait... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/wait.h>
+int
+main ()
+{
+union wait xx, yy; xx = yy
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ $as_echo "#define HAVE_SYS_WAIT_H 1" >>confdefs.h
+
+ $as_echo "#define HAVE_UNION_WAIT 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+for ac_header in stdint.h stdlib.h string.h \
+ sys/select.h sys/utsname.h termcap.h fcntl.h \
+ sgtty.h sys/ioctl.h sys/time.h sys/types.h \
+ termio.h iconv.h inttypes.h langinfo.h math.h \
+ unistd.h stropts.h errno.h sys/resource.h \
+ sys/systeminfo.h locale.h sys/stream.h termios.h \
+ libc.h sys/statfs.h poll.h sys/poll.h pwd.h \
+ utime.h sys/param.h sys/ptms.h libintl.h libgen.h \
+ util/debug.h util/msg18n.h frame.h sys/acl.h \
+ sys/access.h sys/sysinfo.h wchar.h wctype.h
+do :
+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in sys/ptem.h
+do :
+ ac_fn_c_check_header_compile "$LINENO" "sys/ptem.h" "ac_cv_header_sys_ptem_h" "#if defined HAVE_SYS_STREAM_H
+# include <sys/stream.h>
+#endif
+"
+if test "x$ac_cv_header_sys_ptem_h" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_SYS_PTEM_H 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in sys/sysctl.h
+do :
+ ac_fn_c_check_header_compile "$LINENO" "sys/sysctl.h" "ac_cv_header_sys_sysctl_h" "#if defined HAVE_SYS_PARAM_H
+# include <sys/param.h>
+#endif
+"
+if test "x$ac_cv_header_sys_sysctl_h" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_SYS_SYSCTL_H 1
+_ACEOF
+
+fi
+
+done
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_np.h" >&5
+$as_echo_n "checking for pthread_np.h... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <pthread.h>
+#include <pthread_np.h>
+int
+main ()
+{
+int i; i = 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ $as_echo "#define HAVE_PTHREAD_NP_H 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+for ac_header in strings.h
+do :
+ ac_fn_c_check_header_mongrel "$LINENO" "strings.h" "ac_cv_header_strings_h" "$ac_includes_default"
+if test "x$ac_cv_header_strings_h" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_STRINGS_H 1
+_ACEOF
+
+fi
+
+done
+
+if test "x$MACOS_X" = "xyes"; then
+ $as_echo "#define NO_STRINGS_WITH_STRING_H 1" >>confdefs.h
+
+else
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if strings.h can be included after string.h" >&5
+$as_echo_n "checking if strings.h can be included after string.h... " >&6; }
+cppflags_save=$CPPFLAGS
+CPPFLAGS="$CPPFLAGS $X_CFLAGS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#if defined(_AIX) && !defined(_AIX51) && !defined(_NO_PROTO)
+# define _NO_PROTO /* like in os_unix.h, causes conflict for AIX (Winn) */
+ /* but don't do it on AIX 5.1 (Uribarri) */
+#endif
+#ifdef HAVE_XM_XM_H
+# include <Xm/Xm.h> /* This breaks it for HP-UX 11 (Squassabia) */
+#endif
+#ifdef HAVE_STRING_H
+# include <string.h>
+#endif
+#if defined(HAVE_STRINGS_H)
+# include <strings.h>
+#endif
+
+int
+main ()
+{
+int i; i = 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+ $as_echo "#define NO_STRINGS_WITH_STRING_H 1" >>confdefs.h
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+CPPFLAGS=$cppflags_save
+fi
+
+if test $ac_cv_c_compiler_gnu = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC needs -traditional" >&5
+$as_echo_n "checking whether $CC needs -traditional... " >&6; }
+if ${ac_cv_prog_gcc_traditional+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_pattern="Autoconf.*'x'"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sgtty.h>
+Autoconf TIOCGETP
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "$ac_pattern" >/dev/null 2>&1; then :
+ ac_cv_prog_gcc_traditional=yes
+else
+ ac_cv_prog_gcc_traditional=no
+fi
+rm -f conftest*
+
+
+ if test $ac_cv_prog_gcc_traditional = no; then
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <termio.h>
+Autoconf TCGETA
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "$ac_pattern" >/dev/null 2>&1; then :
+ ac_cv_prog_gcc_traditional=yes
+fi
+rm -f conftest*
+
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_gcc_traditional" >&5
+$as_echo "$ac_cv_prog_gcc_traditional" >&6; }
+ if test $ac_cv_prog_gcc_traditional = yes; then
+ CC="$CC -traditional"
+ fi
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5
+$as_echo_n "checking for an ANSI C-conforming const... " >&6; }
+if ${ac_cv_c_const+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+#ifndef __cplusplus
+ /* Ultrix mips cc rejects this sort of thing. */
+ typedef int charset[2];
+ const charset cs = { 0, 0 };
+ /* SunOS 4.1.1 cc rejects this. */
+ char const *const *pcpcc;
+ char **ppc;
+ /* NEC SVR4.0.2 mips cc rejects this. */
+ struct point {int x, y;};
+ static struct point const zero = {0,0};
+ /* AIX XL C 1.02.0.0 rejects this.
+ It does not let you subtract one const X* pointer from another in
+ an arm of an if-expression whose if-part is not a constant
+ expression */
+ const char *g = "string";
+ pcpcc = &g + (g ? g-g : 0);
+ /* HPUX 7.0 cc rejects these. */
+ ++pcpcc;
+ ppc = (char**) pcpcc;
+ pcpcc = (char const *const *) ppc;
+ { /* SCO 3.2v4 cc rejects this sort of thing. */
+ char tx;
+ char *t = &tx;
+ char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+ *t++ = 0;
+ if (s) return 0;
+ }
+ { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */
+ int x[] = {25, 17};
+ const int *foo = &x[0];
+ ++foo;
+ }
+ { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+ typedef const int *iptr;
+ iptr p = 0;
+ ++p;
+ }
+ { /* AIX XL C 1.02.0.0 rejects this sort of thing, saying
+ "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+ struct s { int j; const int *ap[3]; } bx;
+ struct s *b = &bx; b->j = 5;
+ }
+ { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+ const int foo = 10;
+ if (!foo) return 0;
+ }
+ return !cs[0] && !zero.x;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_c_const=yes
+else
+ ac_cv_c_const=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5
+$as_echo "$ac_cv_c_const" >&6; }
+if test $ac_cv_c_const = no; then
+
+$as_echo "#define const /**/" >>confdefs.h
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working volatile" >&5
+$as_echo_n "checking for working volatile... " >&6; }
+if ${ac_cv_c_volatile+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+volatile int x;
+int * volatile y = (int *) 0;
+return !x && !y;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_c_volatile=yes
+else
+ ac_cv_c_volatile=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_volatile" >&5
+$as_echo "$ac_cv_c_volatile" >&6; }
+if test $ac_cv_c_volatile = no; then
+
+$as_echo "#define volatile /**/" >>confdefs.h
+
+fi
+
+ac_fn_c_check_type "$LINENO" "mode_t" "ac_cv_type_mode_t" "$ac_includes_default"
+if test "x$ac_cv_type_mode_t" = xyes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define mode_t int
+_ACEOF
+
+fi
+
+ac_fn_c_check_type "$LINENO" "off_t" "ac_cv_type_off_t" "$ac_includes_default"
+if test "x$ac_cv_type_off_t" = xyes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define off_t long int
+_ACEOF
+
+fi
+
+ac_fn_c_check_type "$LINENO" "pid_t" "ac_cv_type_pid_t" "$ac_includes_default"
+if test "x$ac_cv_type_pid_t" = xyes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define pid_t int
+_ACEOF
+
+fi
+
+ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default"
+if test "x$ac_cv_type_size_t" = xyes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define size_t unsigned int
+_ACEOF
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for uid_t in sys/types.h" >&5
+$as_echo_n "checking for uid_t in sys/types.h... " >&6; }
+if ${ac_cv_type_uid_t+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "uid_t" >/dev/null 2>&1; then :
+ ac_cv_type_uid_t=yes
+else
+ ac_cv_type_uid_t=no
+fi
+rm -f conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uid_t" >&5
+$as_echo "$ac_cv_type_uid_t" >&6; }
+if test $ac_cv_type_uid_t = no; then
+
+$as_echo "#define uid_t int" >>confdefs.h
+
+
+$as_echo "#define gid_t int" >>confdefs.h
+
+fi
+
+ac_fn_c_find_uintX_t "$LINENO" "32" "ac_cv_c_uint32_t"
+case $ac_cv_c_uint32_t in #(
+ no|yes) ;; #(
+ *)
+
+$as_echo "#define _UINT32_T 1" >>confdefs.h
+
+
+cat >>confdefs.h <<_ACEOF
+#define uint32_t $ac_cv_c_uint32_t
+_ACEOF
+;;
+ esac
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether time.h and sys/time.h may both be included" >&5
+$as_echo_n "checking whether time.h and sys/time.h may both be included... " >&6; }
+if ${ac_cv_header_time+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+
+int
+main ()
+{
+if ((struct tm *) 0)
+return 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_header_time=yes
+else
+ ac_cv_header_time=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_time" >&5
+$as_echo "$ac_cv_header_time" >&6; }
+if test $ac_cv_header_time = yes; then
+
+$as_echo "#define TIME_WITH_SYS_TIME 1" >>confdefs.h
+
+fi
+
+ac_fn_c_check_type "$LINENO" "ino_t" "ac_cv_type_ino_t" "$ac_includes_default"
+if test "x$ac_cv_type_ino_t" = xyes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define ino_t long
+_ACEOF
+
+fi
+
+ac_fn_c_check_type "$LINENO" "dev_t" "ac_cv_type_dev_t" "$ac_includes_default"
+if test "x$ac_cv_type_dev_t" = xyes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define dev_t unsigned
+_ACEOF
+
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5
+$as_echo_n "checking whether byte ordering is bigendian... " >&6; }
+if ${ac_cv_c_bigendian+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_c_bigendian=unknown
+ # See if we're dealing with a universal compiler.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifndef __APPLE_CC__
+ not a universal capable compiler
+ #endif
+ typedef int dummy;
+
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ # Check for potential -arch flags. It is not universal unless
+ # there are at least two -arch flags with different values.
+ ac_arch=
+ ac_prev=
+ for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do
+ if test -n "$ac_prev"; then
+ case $ac_word in
+ i?86 | x86_64 | ppc | ppc64)
+ if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then
+ ac_arch=$ac_word
+ else
+ ac_cv_c_bigendian=universal
+ break
+ fi
+ ;;
+ esac
+ ac_prev=
+ elif test "x$ac_word" = "x-arch"; then
+ ac_prev=arch
+ fi
+ done
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ if test $ac_cv_c_bigendian = unknown; then
+ # See if sys/param.h defines the BYTE_ORDER macro.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+ #include <sys/param.h>
+
+int
+main ()
+{
+#if ! (defined BYTE_ORDER && defined BIG_ENDIAN \
+ && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \
+ && LITTLE_ENDIAN)
+ bogus endian macros
+ #endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ # It does; now see whether it defined to BIG_ENDIAN or not.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+ #include <sys/param.h>
+
+int
+main ()
+{
+#if BYTE_ORDER != BIG_ENDIAN
+ not big endian
+ #endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_c_bigendian=yes
+else
+ ac_cv_c_bigendian=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ fi
+ if test $ac_cv_c_bigendian = unknown; then
+ # See if <limits.h> defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris).
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <limits.h>
+
+int
+main ()
+{
+#if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN)
+ bogus endian macros
+ #endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ # It does; now see whether it defined to _BIG_ENDIAN or not.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <limits.h>
+
+int
+main ()
+{
+#ifndef _BIG_ENDIAN
+ not big endian
+ #endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_c_bigendian=yes
+else
+ ac_cv_c_bigendian=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ fi
+ if test $ac_cv_c_bigendian = unknown; then
+ # Compile a test program.
+ if test "$cross_compiling" = yes; then :
+ # Try to guess by grepping values from an object file.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+short int ascii_mm[] =
+ { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 };
+ short int ascii_ii[] =
+ { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 };
+ int use_ascii (int i) {
+ return ascii_mm[i] + ascii_ii[i];
+ }
+ short int ebcdic_ii[] =
+ { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 };
+ short int ebcdic_mm[] =
+ { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 };
+ int use_ebcdic (int i) {
+ return ebcdic_mm[i] + ebcdic_ii[i];
+ }
+ extern int foo;
+
+int
+main ()
+{
+return use_ascii (foo) == use_ebcdic (foo);
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then
+ ac_cv_c_bigendian=yes
+ fi
+ if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then
+ if test "$ac_cv_c_bigendian" = unknown; then
+ ac_cv_c_bigendian=no
+ else
+ # finding both strings is unlikely to happen, but who knows?
+ ac_cv_c_bigendian=unknown
+ fi
+ fi
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+
+ /* Are we little or big endian? From Harbison&Steele. */
+ union
+ {
+ long int l;
+ char c[sizeof (long int)];
+ } u;
+ u.l = 1;
+ return u.c[sizeof (long int) - 1] == 1;
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ ac_cv_c_bigendian=no
+else
+ ac_cv_c_bigendian=yes
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5
+$as_echo "$ac_cv_c_bigendian" >&6; }
+ case $ac_cv_c_bigendian in #(
+ yes)
+ $as_echo "#define WORDS_BIGENDIAN 1" >>confdefs.h
+;; #(
+ no)
+ ;; #(
+ universal)
+
+$as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h
+
+ ;; #(
+ *)
+ as_fn_error $? "unknown endianness
+ presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;;
+ esac
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5
+$as_echo_n "checking for inline... " >&6; }
+if ${ac_cv_c_inline+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_c_inline=no
+for ac_kw in inline __inline__ __inline; do
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifndef __cplusplus
+typedef int foo_t;
+static $ac_kw foo_t static_foo () {return 0; }
+$ac_kw foo_t foo () {return 0; }
+#endif
+
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_c_inline=$ac_kw
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ test "$ac_cv_c_inline" != no && break
+done
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5
+$as_echo "$ac_cv_c_inline" >&6; }
+
+case $ac_cv_c_inline in
+ inline | yes) ;;
+ *)
+ case $ac_cv_c_inline in
+ no) ac_val=;;
+ *) ac_val=$ac_cv_c_inline;;
+ esac
+ cat >>confdefs.h <<_ACEOF
+#ifndef __cplusplus
+#define inline $ac_val
+#endif
+_ACEOF
+ ;;
+esac
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for rlim_t" >&5
+$as_echo_n "checking for rlim_t... " >&6; }
+if eval "test \"`echo '$''{'ac_cv_type_rlim_t'+set}'`\" = set"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: (cached) $ac_cv_type_rlim_t" >&5
+$as_echo "(cached) $ac_cv_type_rlim_t" >&6; }
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <sys/types.h>
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#endif
+#ifdef HAVE_SYS_RESOURCE_H
+# include <sys/resource.h>
+#endif
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "(^|[^a-zA-Z_0-9])rlim_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then :
+ ac_cv_type_rlim_t=yes
+else
+ ac_cv_type_rlim_t=no
+fi
+rm -f conftest*
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_rlim_t" >&5
+$as_echo "$ac_cv_type_rlim_t" >&6; }
+fi
+if test $ac_cv_type_rlim_t = no; then
+ cat >> confdefs.h <<\EOF
+#define rlim_t unsigned long
+EOF
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for stack_t" >&5
+$as_echo_n "checking for stack_t... " >&6; }
+if eval "test \"`echo '$''{'ac_cv_type_stack_t'+set}'`\" = set"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: (cached) $ac_cv_type_stack_t" >&5
+$as_echo "(cached) $ac_cv_type_stack_t" >&6; }
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <sys/types.h>
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#endif
+#include <signal.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "stack_t" >/dev/null 2>&1; then :
+ ac_cv_type_stack_t=yes
+else
+ ac_cv_type_stack_t=no
+fi
+rm -f conftest*
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_stack_t" >&5
+$as_echo "$ac_cv_type_stack_t" >&6; }
+fi
+if test $ac_cv_type_stack_t = no; then
+ cat >> confdefs.h <<\EOF
+#define stack_t struct sigaltstack
+EOF
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stack_t has an ss_base field" >&5
+$as_echo_n "checking whether stack_t has an ss_base field... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <sys/types.h>
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#endif
+#include <signal.h>
+#include "confdefs.h"
+
+int
+main ()
+{
+stack_t sigstk; sigstk.ss_base = 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }; $as_echo "#define HAVE_SS_BASE 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+olibs="$LIBS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --with-tlib argument" >&5
+$as_echo_n "checking --with-tlib argument... " >&6; }
+
+# Check whether --with-tlib was given.
+if test "${with_tlib+set}" = set; then :
+ withval=$with_tlib;
+fi
+
+if test -n "$with_tlib"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_tlib" >&5
+$as_echo "$with_tlib" >&6; }
+ LIBS="$LIBS -l$with_tlib"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for linking with $with_tlib library" >&5
+$as_echo_n "checking for linking with $with_tlib library... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: OK" >&5
+$as_echo "OK" >&6; }
+else
+ as_fn_error $? "FAILED" "$LINENO" 5
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ olibs="$LIBS"
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: empty: automatic terminal library selection" >&5
+$as_echo "empty: automatic terminal library selection" >&6; }
+ case "`uname -s 2>/dev/null`" in
+ OSF1|SCO_SV) tlibs="tinfo ncurses curses termlib termcap";;
+ *) tlibs="tinfo ncurses termlib termcap curses";;
+ esac
+ for libname in $tlibs; do
+ as_ac_Lib=`$as_echo "ac_cv_lib_${libname}''_tgetent" | $as_tr_sh`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for tgetent in -l${libname}" >&5
+$as_echo_n "checking for tgetent in -l${libname}... " >&6; }
+if eval \${$as_ac_Lib+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-l${libname} $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char tgetent ();
+int
+main ()
+{
+return tgetent ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ eval "$as_ac_Lib=yes"
+else
+ eval "$as_ac_Lib=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+eval ac_res=\$$as_ac_Lib
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_LIB${libname}" | $as_tr_cpp` 1
+_ACEOF
+
+ LIBS="-l${libname} $LIBS"
+
+fi
+
+ if test "x$olibs" != "x$LIBS"; then
+ if test "$cross_compiling" = yes; then :
+ res="FAIL"
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#ifdef HAVE_TERMCAP_H
+# include <termcap.h>
+#endif
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#endif
+main() {char *s; s=(char *)tgoto("%p1%d", 0, 1); exit(0); }
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ res="OK"
+else
+ res="FAIL"
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+ if test "$res" = "OK"; then
+ break
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $libname library is not usable" >&5
+$as_echo "$libname library is not usable" >&6; }
+ LIBS="$olibs"
+ fi
+ done
+ if test "x$olibs" = "x$LIBS"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no terminal library found" >&5
+$as_echo "no terminal library found" >&6; }
+ fi
+fi
+
+if test "x$olibs" = "x$LIBS"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tgetent()" >&5
+$as_echo_n "checking for tgetent()... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+char s[10000]; int res = tgetent(s, "thisterminaldoesnotexist");
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+ as_fn_error $? "NOT FOUND!
+ You need to install a terminal library; for example ncurses.
+ Or specify the name of the library with --with-tlib." "$LINENO" 5
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we talk terminfo" >&5
+$as_echo_n "checking whether we talk terminfo... " >&6; }
+if ${vim_cv_terminfo+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ if test "$cross_compiling" = yes; then :
+
+ as_fn_error $? "cross-compiling: please set 'vim_cv_terminfo'" "$LINENO" 5
+
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include "confdefs.h"
+#ifdef HAVE_TERMCAP_H
+# include <termcap.h>
+#endif
+#ifdef HAVE_STRING_H
+# include <string.h>
+#endif
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#endif
+main()
+{char *s; s=(char *)tgoto("%p1%d", 0, 1); exit(!strcmp(s==0 ? "" : s, "1")); }
+
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+ vim_cv_terminfo=no
+
+else
+
+ vim_cv_terminfo=yes
+
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vim_cv_terminfo" >&5
+$as_echo "$vim_cv_terminfo" >&6; }
+
+if test "x$vim_cv_terminfo" = "xyes" ; then
+ $as_echo "#define TERMINFO 1" >>confdefs.h
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking what tgetent() returns for an unknown terminal" >&5
+$as_echo_n "checking what tgetent() returns for an unknown terminal... " >&6; }
+if ${vim_cv_tgetent+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ if test "$cross_compiling" = yes; then :
+
+ as_fn_error $? "failed to compile test program." "$LINENO" 5
+
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include "confdefs.h"
+#ifdef HAVE_TERMCAP_H
+# include <termcap.h>
+#endif
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#endif
+main()
+{char s[10000]; int res = tgetent(s, "thisterminaldoesnotexist"); exit(res != 0); }
+
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+ vim_cv_tgetent=zero
+
+else
+
+ vim_cv_tgetent=non-zero
+
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vim_cv_tgetent" >&5
+$as_echo "$vim_cv_tgetent" >&6; }
+
+if test "x$vim_cv_tgetent" = "xzero" ; then
+ $as_echo "#define TGETENT_ZERO_ERR 0" >>confdefs.h
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether termcap.h contains ospeed" >&5
+$as_echo_n "checking whether termcap.h contains ospeed... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#ifdef HAVE_TERMCAP_H
+# include <termcap.h>
+#endif
+
+int
+main ()
+{
+ospeed = 20000
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }; $as_echo "#define HAVE_OSPEED 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ospeed can be extern" >&5
+$as_echo_n "checking whether ospeed can be extern... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#ifdef HAVE_TERMCAP_H
+# include <termcap.h>
+#endif
+extern short ospeed;
+
+int
+main ()
+{
+ospeed = 20000
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }; $as_echo "#define OSPEED_EXTERN 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether termcap.h contains UP, BC and PC" >&5
+$as_echo_n "checking whether termcap.h contains UP, BC and PC... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#ifdef HAVE_TERMCAP_H
+# include <termcap.h>
+#endif
+
+int
+main ()
+{
+if (UP == 0 && BC == 0) PC = 1
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }; $as_echo "#define HAVE_UP_BC_PC 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether UP, BC and PC can be extern" >&5
+$as_echo_n "checking whether UP, BC and PC can be extern... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#ifdef HAVE_TERMCAP_H
+# include <termcap.h>
+#endif
+extern char *UP, *BC, PC;
+
+int
+main ()
+{
+if (UP == 0 && BC == 0) PC = 1
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }; $as_echo "#define UP_BC_PC_EXTERN 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether tputs() uses outfuntype" >&5
+$as_echo_n "checking whether tputs() uses outfuntype... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#ifdef HAVE_TERMCAP_H
+# include <termcap.h>
+#endif
+
+int
+main ()
+{
+extern int xx(); tputs("test", 1, (outfuntype)xx)
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }; $as_echo "#define HAVE_OUTFUNTYPE 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether sys/select.h and sys/time.h may both be included" >&5
+$as_echo_n "checking whether sys/select.h and sys/time.h may both be included... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/select.h>
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ $as_echo "#define SYS_SELECT_WITH_SYS_TIME 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for /dev/ptc" >&5
+$as_echo_n "checking for /dev/ptc... " >&6; }
+if test -r /dev/ptc; then
+ $as_echo "#define HAVE_DEV_PTC 1" >>confdefs.h
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for SVR4 ptys" >&5
+$as_echo_n "checking for SVR4 ptys... " >&6; }
+if test -c /dev/ptmx ; then
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+ptsname(0);grantpt(0);unlockpt(0);
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }; $as_echo "#define HAVE_SVR4_PTYS 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ptyranges" >&5
+$as_echo_n "checking for ptyranges... " >&6; }
+if test -d /dev/ptym ; then
+ pdir='/dev/ptym'
+else
+ pdir='/dev'
+fi
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef M_UNIX
+ yes;
+#endif
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "yes" >/dev/null 2>&1; then :
+ ptys=`echo /dev/ptyp??`
+else
+ ptys=`echo $pdir/pty??`
+fi
+rm -f conftest*
+
+if test "$ptys" != "$pdir/pty??" ; then
+ p0=`echo $ptys | tr ' ' '\012' | sed -e 's/^.*\(.\).$/\1/g' | sort -u | tr -d '\012'`
+ p1=`echo $ptys | tr ' ' '\012' | sed -e 's/^.*\(.\)$/\1/g' | sort -u | tr -d '\012'`
+ cat >>confdefs.h <<_ACEOF
+#define PTYRANGE0 "$p0"
+_ACEOF
+
+ cat >>confdefs.h <<_ACEOF
+#define PTYRANGE1 "$p1"
+_ACEOF
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $p0 / $p1" >&5
+$as_echo "$p0 / $p1" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: don't know" >&5
+$as_echo "don't know" >&6; }
+fi
+
+rm -f conftest_grp
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking default tty permissions/group" >&5
+$as_echo_n "checking default tty permissions/group... " >&6; }
+if ${vim_cv_tty_group+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ if test "$cross_compiling" = yes; then :
+
+ as_fn_error $? "cross-compiling: please set 'vim_cv_tty_group' and 'vim_cv_tty_mode'" "$LINENO" 5
+
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <sys/stat.h>
+#include <stdio.h>
+main()
+{
+ struct stat sb;
+ char *x,*ttyname();
+ int om, m;
+ FILE *fp;
+
+ if (!(x = ttyname(0))) exit(1);
+ if (stat(x, &sb)) exit(1);
+ om = sb.st_mode;
+ if (om & 002) exit(0);
+ m = system("mesg y");
+ if (m == -1 || m == 127) exit(1);
+ if (stat(x, &sb)) exit(1);
+ m = sb.st_mode;
+ if (chmod(x, om)) exit(1);
+ if (m & 002) exit(0);
+ if (sb.st_gid == getgid()) exit(1);
+ if (!(fp=fopen("conftest_grp", "w")))
+ exit(1);
+ fprintf(fp, "%d\n", sb.st_gid);
+ fclose(fp);
+ exit(0);
+}
+
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+ if test -f conftest_grp; then
+ vim_cv_tty_group=`cat conftest_grp`
+ if test "x$vim_cv_tty_mode" = "x" ; then
+ vim_cv_tty_mode=0620
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: pty mode: $vim_cv_tty_mode, group: $vim_cv_tty_group" >&5
+$as_echo "pty mode: $vim_cv_tty_mode, group: $vim_cv_tty_group" >&6; }
+ else
+ vim_cv_tty_group=world
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: ptys are world accessible" >&5
+$as_echo "ptys are world accessible" >&6; }
+ fi
+
+else
+
+ vim_cv_tty_group=world
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: can't determine - assume ptys are world accessible" >&5
+$as_echo "can't determine - assume ptys are world accessible" >&6; }
+
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vim_cv_tty_group" >&5
+$as_echo "$vim_cv_tty_group" >&6; }
+rm -f conftest_grp
+
+if test "x$vim_cv_tty_group" != "xworld" ; then
+ cat >>confdefs.h <<_ACEOF
+#define PTYGROUP $vim_cv_tty_group
+_ACEOF
+
+ if test "x$vim_cv_tty_mode" = "x" ; then
+ as_fn_error $? "It seems you're cross compiling and have 'vim_cv_tty_group' set, please also set the environment variable 'vim_cv_tty_mode' to the correct mode (probably 0620)" "$LINENO" 5
+ else
+ $as_echo "#define PTYMODE 0620" >>confdefs.h
+
+ fi
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking return type of signal handlers" >&5
+$as_echo_n "checking return type of signal handlers... " >&6; }
+if ${ac_cv_type_signal+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <signal.h>
+
+int
+main ()
+{
+return *(signal (0, 0)) (0) == 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_type_signal=int
+else
+ ac_cv_type_signal=void
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_signal" >&5
+$as_echo "$ac_cv_type_signal" >&6; }
+
+cat >>confdefs.h <<_ACEOF
+#define RETSIGTYPE $ac_cv_type_signal
+_ACEOF
+
+
+
+if test $ac_cv_type_signal = void; then
+ $as_echo "#define SIGRETURN return" >>confdefs.h
+
+else
+ $as_echo "#define SIGRETURN return 0" >>confdefs.h
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for struct sigcontext" >&5
+$as_echo_n "checking for struct sigcontext... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <signal.h>
+test_sig()
+{
+ struct sigcontext *scont;
+ scont = (struct sigcontext *)0;
+ return 1;
+}
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ $as_echo "#define HAVE_SIGCONTEXT 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking getcwd implementation is broken" >&5
+$as_echo_n "checking getcwd implementation is broken... " >&6; }
+if ${vim_cv_getcwd_broken+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ if test "$cross_compiling" = yes; then :
+
+ as_fn_error $? "cross-compiling: please set 'vim_cv_getcwd_broken'" "$LINENO" 5
+
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include "confdefs.h"
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+char *dagger[] = { "IFS=pwd", 0 };
+main()
+{
+ char buffer[500];
+ extern char **environ;
+ environ = dagger;
+ return getcwd(buffer, 500) ? 0 : 1;
+}
+
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+ vim_cv_getcwd_broken=no
+
+else
+
+ vim_cv_getcwd_broken=yes
+
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vim_cv_getcwd_broken" >&5
+$as_echo "$vim_cv_getcwd_broken" >&6; }
+
+if test "x$vim_cv_getcwd_broken" = "xyes" ; then
+ $as_echo "#define BAD_GETCWD 1" >>confdefs.h
+
+fi
+
+for ac_func in fchdir fchown fchmod fsync getcwd getpseudotty \
+ getpwent getpwnam getpwuid getrlimit gettimeofday getwd lstat \
+ memset mkdtemp nanosleep opendir putenv qsort readlink select setenv \
+ getpgid setpgid setsid sigaltstack sigstack sigset sigsetjmp sigaction \
+ sigprocmask sigvec strcasecmp strerror strftime stricmp strncasecmp \
+ strnicmp strpbrk strtol tgetent towlower towupper iswupper \
+ usleep utime utimes mblen ftruncate unsetenv
+do :
+ as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+for ac_header in sys/select.h sys/socket.h
+do :
+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking types of arguments for select" >&5
+$as_echo_n "checking types of arguments for select... " >&6; }
+if ${ac_cv_func_select_args+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ for ac_arg234 in 'fd_set *' 'int *' 'void *'; do
+ for ac_arg1 in 'int' 'size_t' 'unsigned long int' 'unsigned int'; do
+ for ac_arg5 in 'struct timeval *' 'const struct timeval *'; do
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$ac_includes_default
+#ifdef HAVE_SYS_SELECT_H
+# include <sys/select.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+# include <sys/socket.h>
+#endif
+
+int
+main ()
+{
+extern int select ($ac_arg1,
+ $ac_arg234, $ac_arg234, $ac_arg234,
+ $ac_arg5);
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_func_select_args="$ac_arg1,$ac_arg234,$ac_arg5"; break 3
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+ done
+done
+# Provide a safe default value.
+: "${ac_cv_func_select_args=int,int *,struct timeval *}"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_select_args" >&5
+$as_echo "$ac_cv_func_select_args" >&6; }
+ac_save_IFS=$IFS; IFS=','
+set dummy `echo "$ac_cv_func_select_args" | sed 's/\*/\*/g'`
+IFS=$ac_save_IFS
+shift
+
+cat >>confdefs.h <<_ACEOF
+#define SELECT_TYPE_ARG1 $1
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define SELECT_TYPE_ARG234 ($2)
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define SELECT_TYPE_ARG5 ($3)
+_ACEOF
+
+rm -f conftest*
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGEFILE_SOURCE value needed for large files" >&5
+$as_echo_n "checking for _LARGEFILE_SOURCE value needed for large files... " >&6; }
+if ${ac_cv_sys_largefile_source+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ while :; do
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h> /* for off_t */
+ #include <stdio.h>
+int
+main ()
+{
+int (*fp) (FILE *, off_t, int) = fseeko;
+ return fseeko (stdin, 0, 0) && fp (stdin, 0, 0);
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_sys_largefile_source=no; break
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#define _LARGEFILE_SOURCE 1
+#include <sys/types.h> /* for off_t */
+ #include <stdio.h>
+int
+main ()
+{
+int (*fp) (FILE *, off_t, int) = fseeko;
+ return fseeko (stdin, 0, 0) && fp (stdin, 0, 0);
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_sys_largefile_source=1; break
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ ac_cv_sys_largefile_source=unknown
+ break
+done
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_source" >&5
+$as_echo "$ac_cv_sys_largefile_source" >&6; }
+case $ac_cv_sys_largefile_source in #(
+ no | unknown) ;;
+ *)
+cat >>confdefs.h <<_ACEOF
+#define _LARGEFILE_SOURCE $ac_cv_sys_largefile_source
+_ACEOF
+;;
+esac
+rm -rf conftest*
+
+# We used to try defining _XOPEN_SOURCE=500 too, to work around a bug
+# in glibc 2.1.3, but that breaks too many other things.
+# If you want fseeko and ftello with glibc, upgrade to a fixed glibc.
+if test $ac_cv_sys_largefile_source != unknown; then
+
+$as_echo "#define HAVE_FSEEKO 1" >>confdefs.h
+
+fi
+
+
+# Check whether --enable-largefile was given.
+if test "${enable_largefile+set}" = set; then :
+ enableval=$enable_largefile;
+fi
+
+if test "$enable_largefile" != no; then
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5
+$as_echo_n "checking for special C compiler options needed for large files... " >&6; }
+if ${ac_cv_sys_largefile_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_sys_largefile_CC=no
+ if test "$GCC" != yes; then
+ ac_save_CC=$CC
+ while :; do
+ # IRIX 6.2 and later do not support large files by default,
+ # so use the C compiler's -n32 option if that helps.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+ We can't simply define LARGE_OFF_T to be 9223372036854775807,
+ since some C++ compilers masquerading as C compilers
+ incorrectly reject 9223372036854775807. */
+#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
+ int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+ && LARGE_OFF_T % 2147483647 == 1)
+ ? 1 : -1];
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ if ac_fn_c_try_compile "$LINENO"; then :
+ break
+fi
+rm -f core conftest.err conftest.$ac_objext
+ CC="$CC -n32"
+ if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_sys_largefile_CC=' -n32'; break
+fi
+rm -f core conftest.err conftest.$ac_objext
+ break
+ done
+ CC=$ac_save_CC
+ rm -f conftest.$ac_ext
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5
+$as_echo "$ac_cv_sys_largefile_CC" >&6; }
+ if test "$ac_cv_sys_largefile_CC" != no; then
+ CC=$CC$ac_cv_sys_largefile_CC
+ fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5
+$as_echo_n "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; }
+if ${ac_cv_sys_file_offset_bits+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ while :; do
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+ We can't simply define LARGE_OFF_T to be 9223372036854775807,
+ since some C++ compilers masquerading as C compilers
+ incorrectly reject 9223372036854775807. */
+#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
+ int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+ && LARGE_OFF_T % 2147483647 == 1)
+ ? 1 : -1];
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_sys_file_offset_bits=no; break
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#define _FILE_OFFSET_BITS 64
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+ We can't simply define LARGE_OFF_T to be 9223372036854775807,
+ since some C++ compilers masquerading as C compilers
+ incorrectly reject 9223372036854775807. */
+#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
+ int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+ && LARGE_OFF_T % 2147483647 == 1)
+ ? 1 : -1];
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_sys_file_offset_bits=64; break
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_cv_sys_file_offset_bits=unknown
+ break
+done
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5
+$as_echo "$ac_cv_sys_file_offset_bits" >&6; }
+case $ac_cv_sys_file_offset_bits in #(
+ no | unknown) ;;
+ *)
+cat >>confdefs.h <<_ACEOF
+#define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits
+_ACEOF
+;;
+esac
+rm -rf conftest*
+ if test $ac_cv_sys_file_offset_bits = unknown; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5
+$as_echo_n "checking for _LARGE_FILES value needed for large files... " >&6; }
+if ${ac_cv_sys_large_files+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ while :; do
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+ We can't simply define LARGE_OFF_T to be 9223372036854775807,
+ since some C++ compilers masquerading as C compilers
+ incorrectly reject 9223372036854775807. */
+#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
+ int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+ && LARGE_OFF_T % 2147483647 == 1)
+ ? 1 : -1];
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_sys_large_files=no; break
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#define _LARGE_FILES 1
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+ We can't simply define LARGE_OFF_T to be 9223372036854775807,
+ since some C++ compilers masquerading as C compilers
+ incorrectly reject 9223372036854775807. */
+#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
+ int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+ && LARGE_OFF_T % 2147483647 == 1)
+ ? 1 : -1];
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_sys_large_files=1; break
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_cv_sys_large_files=unknown
+ break
+done
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5
+$as_echo "$ac_cv_sys_large_files" >&6; }
+case $ac_cv_sys_large_files in #(
+ no | unknown) ;;
+ *)
+cat >>confdefs.h <<_ACEOF
+#define _LARGE_FILES $ac_cv_sys_large_files
+_ACEOF
+;;
+esac
+rm -rf conftest*
+ fi
+
+
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for st_blksize" >&5
+$as_echo_n "checking for st_blksize... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <sys/stat.h>
+int
+main ()
+{
+ struct stat st;
+ int n;
+
+ stat("/", &st);
+ n = (int)st.st_blksize;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }; $as_echo "#define HAVE_ST_BLKSIZE 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stat() ignores a trailing slash" >&5
+$as_echo_n "checking whether stat() ignores a trailing slash... " >&6; }
+if ${vim_cv_stat_ignores_slash+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ if test "$cross_compiling" = yes; then :
+
+ as_fn_error $? "cross-compiling: please set 'vim_cv_stat_ignores_slash'" "$LINENO" 5
+
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include "confdefs.h"
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+main() {struct stat st; exit(stat("configure/", &st) != 0); }
+
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+ vim_cv_stat_ignores_slash=yes
+
+else
+
+ vim_cv_stat_ignores_slash=no
+
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vim_cv_stat_ignores_slash" >&5
+$as_echo "$vim_cv_stat_ignores_slash" >&6; }
+
+if test "x$vim_cv_stat_ignores_slash" = "xyes" ; then
+ $as_echo "#define STAT_IGNORES_SLASH 1" >>confdefs.h
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for iconv_open()" >&5
+$as_echo_n "checking for iconv_open()... " >&6; }
+save_LIBS="$LIBS"
+LIBS="$LIBS -liconv"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#ifdef HAVE_ICONV_H
+# include <iconv.h>
+#endif
+
+int
+main ()
+{
+iconv_open("fr", "to");
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes; with -liconv" >&5
+$as_echo "yes; with -liconv" >&6; }; $as_echo "#define HAVE_ICONV 1" >>confdefs.h
+
+else
+ LIBS="$save_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#ifdef HAVE_ICONV_H
+# include <iconv.h>
+#endif
+
+int
+main ()
+{
+iconv_open("fr", "to");
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }; $as_echo "#define HAVE_ICONV 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for nl_langinfo(CODESET)" >&5
+$as_echo_n "checking for nl_langinfo(CODESET)... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#ifdef HAVE_LANGINFO_H
+# include <langinfo.h>
+#endif
+
+int
+main ()
+{
+char *cs = nl_langinfo(CODESET);
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }; $as_echo "#define HAVE_NL_LANGINFO_CODESET 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for strtod in -lm" >&5
+$as_echo_n "checking for strtod in -lm... " >&6; }
+if ${ac_cv_lib_m_strtod+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lm $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char strtod ();
+int
+main ()
+{
+return strtod ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_m_strtod=yes
+else
+ ac_cv_lib_m_strtod=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_strtod" >&5
+$as_echo "$ac_cv_lib_m_strtod" >&6; }
+if test "x$ac_cv_lib_m_strtod" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBM 1
+_ACEOF
+
+ LIBS="-lm $LIBS"
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for strtod() and other floating point functions" >&5
+$as_echo_n "checking for strtod() and other floating point functions... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#ifdef HAVE_MATH_H
+# include <math.h>
+#endif
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#endif
+
+int
+main ()
+{
+char *s; double d;
+ d = strtod("1.1", &s);
+ d = fabs(1.11);
+ d = ceil(1.11);
+ d = floor(1.11);
+ d = log10(1.11);
+ d = pow(1.11, 2.22);
+ d = sqrt(1.11);
+ d = sin(1.11);
+ d = cos(1.11);
+ d = atan(1.11);
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }; $as_echo "#define HAVE_FLOAT_FUNCS 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for isinf()" >&5
+$as_echo_n "checking for isinf()... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#ifdef HAVE_MATH_H
+# include <math.h>
+#endif
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#endif
+
+int
+main ()
+{
+int r = isinf(1.11);
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }; $as_echo "#define HAVE_ISINF 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for isnan()" >&5
+$as_echo_n "checking for isnan()... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#ifdef HAVE_MATH_H
+# include <math.h>
+#endif
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#endif
+
+int
+main ()
+{
+int r = isnan(1.11);
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }; $as_echo "#define HAVE_ISNAN 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --disable-acl argument" >&5
+$as_echo_n "checking --disable-acl argument... " >&6; }
+# Check whether --enable-acl was given.
+if test "${enable_acl+set}" = set; then :
+ enableval=$enable_acl;
+else
+ enable_acl="yes"
+fi
+
+if test "$enable_acl" = "yes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for acl_get_file in -lposix1e" >&5
+$as_echo_n "checking for acl_get_file in -lposix1e... " >&6; }
+if ${ac_cv_lib_posix1e_acl_get_file+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lposix1e $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char acl_get_file ();
+int
+main ()
+{
+return acl_get_file ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_posix1e_acl_get_file=yes
+else
+ ac_cv_lib_posix1e_acl_get_file=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_posix1e_acl_get_file" >&5
+$as_echo "$ac_cv_lib_posix1e_acl_get_file" >&6; }
+if test "x$ac_cv_lib_posix1e_acl_get_file" = xyes; then :
+ LIBS="$LIBS -lposix1e"
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for acl_get_file in -lacl" >&5
+$as_echo_n "checking for acl_get_file in -lacl... " >&6; }
+if ${ac_cv_lib_acl_acl_get_file+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lacl $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char acl_get_file ();
+int
+main ()
+{
+return acl_get_file ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_acl_acl_get_file=yes
+else
+ ac_cv_lib_acl_acl_get_file=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_acl_acl_get_file" >&5
+$as_echo "$ac_cv_lib_acl_acl_get_file" >&6; }
+if test "x$ac_cv_lib_acl_acl_get_file" = xyes; then :
+ LIBS="$LIBS -lacl"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgetxattr in -lattr" >&5
+$as_echo_n "checking for fgetxattr in -lattr... " >&6; }
+if ${ac_cv_lib_attr_fgetxattr+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lattr $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char fgetxattr ();
+int
+main ()
+{
+return fgetxattr ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_attr_fgetxattr=yes
+else
+ ac_cv_lib_attr_fgetxattr=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_attr_fgetxattr" >&5
+$as_echo "$ac_cv_lib_attr_fgetxattr" >&6; }
+if test "x$ac_cv_lib_attr_fgetxattr" = xyes; then :
+ LIBS="$LIBS -lattr"
+fi
+
+fi
+
+fi
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for POSIX ACL support" >&5
+$as_echo_n "checking for POSIX ACL support... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <sys/types.h>
+#ifdef HAVE_SYS_ACL_H
+# include <sys/acl.h>
+#endif
+acl_t acl;
+int
+main ()
+{
+acl = acl_get_file("foo", ACL_TYPE_ACCESS);
+ acl_set_file("foo", ACL_TYPE_ACCESS, acl);
+ acl_free(acl);
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }; $as_echo "#define HAVE_POSIX_ACL 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for acl_get in -lsec" >&5
+$as_echo_n "checking for acl_get in -lsec... " >&6; }
+if ${ac_cv_lib_sec_acl_get+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsec $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char acl_get ();
+int
+main ()
+{
+return acl_get ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_sec_acl_get=yes
+else
+ ac_cv_lib_sec_acl_get=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sec_acl_get" >&5
+$as_echo "$ac_cv_lib_sec_acl_get" >&6; }
+if test "x$ac_cv_lib_sec_acl_get" = xyes; then :
+ LIBS="$LIBS -lsec"; $as_echo "#define HAVE_SOLARIS_ZFS_ACL 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Solaris ACL support" >&5
+$as_echo_n "checking for Solaris ACL support... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#ifdef HAVE_SYS_ACL_H
+# include <sys/acl.h>
+#endif
+int
+main ()
+{
+acl("foo", GETACLCNT, 0, NULL);
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }; $as_echo "#define HAVE_SOLARIS_ACL 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for AIX ACL support" >&5
+$as_echo_n "checking for AIX ACL support... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#endif
+#ifdef HAVE_SYS_ACL_H
+# include <sys/acl.h>
+#endif
+#ifdef HAVE_SYS_ACCESS_H
+# include <sys/access.h>
+#endif
+#define _ALL_SOURCE
+
+#include <sys/stat.h>
+
+int aclsize;
+struct acl *aclent;
+int
+main ()
+{
+aclsize = sizeof(struct acl);
+ aclent = (void *)malloc(aclsize);
+ statacl("foo", STX_NORMAL, aclent, aclsize);
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }; $as_echo "#define HAVE_AIX_ACL 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+
+if test "x$GTK_CFLAGS" != "x"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pango_shape_full" >&5
+$as_echo_n "checking for pango_shape_full... " >&6; }
+ ac_save_CFLAGS="$CFLAGS"
+ ac_save_LIBS="$LIBS"
+ CFLAGS="$CFLAGS $GTK_CFLAGS"
+ LIBS="$LIBS $GTK_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <gtk/gtk.h>
+int
+main ()
+{
+ pango_shape_full(NULL, 0, NULL, 0, NULL, NULL);
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }; $as_echo "#define HAVE_PANGO_SHAPE_FULL 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ CFLAGS="$ac_save_CFLAGS"
+ LIBS="$ac_save_LIBS"
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --disable-gpm argument" >&5
+$as_echo_n "checking --disable-gpm argument... " >&6; }
+# Check whether --enable-gpm was given.
+if test "${enable_gpm+set}" = set; then :
+ enableval=$enable_gpm;
+else
+ enable_gpm="yes"
+fi
+
+
+if test "$enable_gpm" = "yes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gpm" >&5
+$as_echo_n "checking for gpm... " >&6; }
+if ${vi_cv_have_gpm+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ olibs="$LIBS" ; LIBS="-lgpm"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <gpm.h>
+ #include <linux/keyboard.h>
+int
+main ()
+{
+Gpm_GetLibVersion(NULL);
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ vi_cv_have_gpm=yes
+else
+ vi_cv_have_gpm=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LIBS="$olibs"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_have_gpm" >&5
+$as_echo "$vi_cv_have_gpm" >&6; }
+ if test $vi_cv_have_gpm = yes; then
+ LIBS="$LIBS -lgpm"
+ $as_echo "#define HAVE_GPM 1" >>confdefs.h
+
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --disable-sysmouse argument" >&5
+$as_echo_n "checking --disable-sysmouse argument... " >&6; }
+# Check whether --enable-sysmouse was given.
+if test "${enable_sysmouse+set}" = set; then :
+ enableval=$enable_sysmouse;
+else
+ enable_sysmouse="yes"
+fi
+
+
+if test "$enable_sysmouse" = "yes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysmouse" >&5
+$as_echo_n "checking for sysmouse... " >&6; }
+if ${vi_cv_have_sysmouse+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/consio.h>
+ #include <signal.h>
+ #include <sys/fbio.h>
+int
+main ()
+{
+struct mouse_info mouse;
+ mouse.operation = MOUSE_MODE;
+ mouse.operation = MOUSE_SHOW;
+ mouse.u.mode.mode = 0;
+ mouse.u.mode.signal = SIGUSR2;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ vi_cv_have_sysmouse=yes
+else
+ vi_cv_have_sysmouse=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_have_sysmouse" >&5
+$as_echo "$vi_cv_have_sysmouse" >&6; }
+ if test $vi_cv_have_sysmouse = yes; then
+ $as_echo "#define HAVE_SYSMOUSE 1" >>confdefs.h
+
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for FD_CLOEXEC" >&5
+$as_echo_n "checking for FD_CLOEXEC... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#if HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+int
+main ()
+{
+ int flag = FD_CLOEXEC;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }; $as_echo "#define HAVE_FD_CLOEXEC 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: not usable" >&5
+$as_echo "not usable" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for rename" >&5
+$as_echo_n "checking for rename... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdio.h>
+int
+main ()
+{
+rename("this", "that")
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }; $as_echo "#define HAVE_RENAME 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysctl" >&5
+$as_echo_n "checking for sysctl... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <sys/sysctl.h>
+int
+main ()
+{
+ int mib[2], r;
+ size_t len;
+
+ mib[0] = CTL_HW;
+ mib[1] = HW_USERMEM;
+ len = sizeof(r);
+ (void)sysctl(mib, 2, &r, &len, (void *)0, (size_t)0);
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }; $as_echo "#define HAVE_SYSCTL 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: not usable" >&5
+$as_echo "not usable" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysinfo" >&5
+$as_echo_n "checking for sysinfo... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <sys/sysinfo.h>
+int
+main ()
+{
+ struct sysinfo sinfo;
+ int t;
+
+ (void)sysinfo(&sinfo);
+ t = sinfo.totalram;
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }; $as_echo "#define HAVE_SYSINFO 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: not usable" >&5
+$as_echo "not usable" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysinfo.mem_unit" >&5
+$as_echo_n "checking for sysinfo.mem_unit... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <sys/sysinfo.h>
+int
+main ()
+{
+ struct sysinfo sinfo;
+ sinfo.mem_unit = 1;
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }; $as_echo "#define HAVE_SYSINFO_MEM_UNIT 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysconf" >&5
+$as_echo_n "checking for sysconf... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <unistd.h>
+int
+main ()
+{
+ (void)sysconf(_SC_PAGESIZE);
+ (void)sysconf(_SC_PHYS_PAGES);
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }; $as_echo "#define HAVE_SYSCONF 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: not usable" >&5
+$as_echo "not usable" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of int" >&5
+$as_echo_n "checking size of int... " >&6; }
+if ${ac_cv_sizeof_int+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (int))" "ac_cv_sizeof_int" "$ac_includes_default"; then :
+
+else
+ if test "$ac_cv_type_int" = yes; then
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "cannot compute sizeof (int)
+See \`config.log' for more details" "$LINENO" 5; }
+ else
+ ac_cv_sizeof_int=0
+ fi
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_int" >&5
+$as_echo "$ac_cv_sizeof_int" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_INT $ac_cv_sizeof_int
+_ACEOF
+
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long" >&5
+$as_echo_n "checking size of long... " >&6; }
+if ${ac_cv_sizeof_long+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long))" "ac_cv_sizeof_long" "$ac_includes_default"; then :
+
+else
+ if test "$ac_cv_type_long" = yes; then
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "cannot compute sizeof (long)
+See \`config.log' for more details" "$LINENO" 5; }
+ else
+ ac_cv_sizeof_long=0
+ fi
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long" >&5
+$as_echo "$ac_cv_sizeof_long" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_LONG $ac_cv_sizeof_long
+_ACEOF
+
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of time_t" >&5
+$as_echo_n "checking size of time_t... " >&6; }
+if ${ac_cv_sizeof_time_t+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (time_t))" "ac_cv_sizeof_time_t" "$ac_includes_default"; then :
+
+else
+ if test "$ac_cv_type_time_t" = yes; then
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "cannot compute sizeof (time_t)
+See \`config.log' for more details" "$LINENO" 5; }
+ else
+ ac_cv_sizeof_time_t=0
+ fi
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_time_t" >&5
+$as_echo "$ac_cv_sizeof_time_t" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_TIME_T $ac_cv_sizeof_time_t
+_ACEOF
+
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of off_t" >&5
+$as_echo_n "checking size of off_t... " >&6; }
+if ${ac_cv_sizeof_off_t+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (off_t))" "ac_cv_sizeof_off_t" "$ac_includes_default"; then :
+
+else
+ if test "$ac_cv_type_off_t" = yes; then
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "cannot compute sizeof (off_t)
+See \`config.log' for more details" "$LINENO" 5; }
+ else
+ ac_cv_sizeof_off_t=0
+ fi
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_off_t" >&5
+$as_echo "$ac_cv_sizeof_off_t" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_OFF_T $ac_cv_sizeof_off_t
+_ACEOF
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define VIM_SIZEOF_INT $ac_cv_sizeof_int
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define VIM_SIZEOF_LONG $ac_cv_sizeof_long
+_ACEOF
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking uint32_t is 32 bits" >&5
+$as_echo_n "checking uint32_t is 32 bits... " >&6; }
+if test "$cross_compiling" = yes; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cannot check uint32_t when cross-compiling." >&5
+$as_echo "$as_me: WARNING: cannot check uint32_t when cross-compiling." >&2;}
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+main() {
+ uint32_t nr1 = (uint32_t)-1;
+ uint32_t nr2 = (uint32_t)0xffffffffUL;
+ if (sizeof(uint32_t) != 4 || nr1 != 0xffffffffUL || nr2 + 1 != 0) exit(1);
+ exit(0);
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5
+$as_echo "ok" >&6; }
+else
+ as_fn_error $? "WRONG! uint32_t not defined correctly." "$LINENO" 5
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+
+
+bcopy_test_prog='
+#include "confdefs.h"
+#ifdef HAVE_STRING_H
+# include <string.h>
+#endif
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#endif
+main() {
+ char buf[10];
+ strcpy(buf, "abcdefghi");
+ mch_memmove(buf, buf + 2, 3);
+ if (strncmp(buf, "ababcf", 6))
+ exit(1);
+ strcpy(buf, "abcdefghi");
+ mch_memmove(buf + 2, buf, 3);
+ if (strncmp(buf, "cdedef", 6))
+ exit(1);
+ exit(0); /* libc version works properly. */
+}'
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether memmove handles overlaps" >&5
+$as_echo_n "checking whether memmove handles overlaps... " >&6; }
+if ${vim_cv_memmove_handles_overlap+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ if test "$cross_compiling" = yes; then :
+
+ as_fn_error $? "cross-compiling: please set 'vim_cv_memmove_handles_overlap'" "$LINENO" 5
+
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#define mch_memmove(s,d,l) memmove(d,s,l) $bcopy_test_prog
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+ vim_cv_memmove_handles_overlap=yes
+
+else
+
+ vim_cv_memmove_handles_overlap=no
+
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vim_cv_memmove_handles_overlap" >&5
+$as_echo "$vim_cv_memmove_handles_overlap" >&6; }
+
+if test "x$vim_cv_memmove_handles_overlap" = "xyes" ; then
+ $as_echo "#define USEMEMMOVE 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether bcopy handles overlaps" >&5
+$as_echo_n "checking whether bcopy handles overlaps... " >&6; }
+if ${vim_cv_bcopy_handles_overlap+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ if test "$cross_compiling" = yes; then :
+
+ as_fn_error $? "cross-compiling: please set 'vim_cv_bcopy_handles_overlap'" "$LINENO" 5
+
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#define mch_bcopy(s,d,l) bcopy(d,s,l) $bcopy_test_prog
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+ vim_cv_bcopy_handles_overlap=yes
+
+else
+
+ vim_cv_bcopy_handles_overlap=no
+
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vim_cv_bcopy_handles_overlap" >&5
+$as_echo "$vim_cv_bcopy_handles_overlap" >&6; }
+
+ if test "x$vim_cv_bcopy_handles_overlap" = "xyes" ; then
+ $as_echo "#define USEBCOPY 1" >>confdefs.h
+
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether memcpy handles overlaps" >&5
+$as_echo_n "checking whether memcpy handles overlaps... " >&6; }
+if ${vim_cv_memcpy_handles_overlap+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ if test "$cross_compiling" = yes; then :
+
+ as_fn_error $? "cross-compiling: please set 'vim_cv_memcpy_handles_overlap'" "$LINENO" 5
+
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#define mch_memcpy(s,d,l) memcpy(d,s,l) $bcopy_test_prog
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+ vim_cv_memcpy_handles_overlap=yes
+
+else
+
+ vim_cv_memcpy_handles_overlap=no
+
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vim_cv_memcpy_handles_overlap" >&5
+$as_echo "$vim_cv_memcpy_handles_overlap" >&6; }
+
+ if test "x$vim_cv_memcpy_handles_overlap" = "xyes" ; then
+ $as_echo "#define USEMEMCPY 1" >>confdefs.h
+
+ fi
+ fi
+fi
+
+
+if test "x$with_x" = "xyes"; then
+ cflags_save=$CFLAGS
+ libs_save=$LIBS
+ LIBS="$LIBS $X_LIBS $GUI_LIB_LOC $GUI_X_LIBS $X_PRE_LIBS $X_LIB $X_EXTRA_LIBS"
+ CFLAGS="$CFLAGS $X_CFLAGS"
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether X_LOCALE needed" >&5
+$as_echo_n "checking whether X_LOCALE needed... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <X11/Xlocale.h>
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char _Xsetlocale ();
+int
+main ()
+{
+return _Xsetlocale ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ $as_echo "#define X_LOCALE 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether Xutf8SetWMProperties() can be used" >&5
+$as_echo_n "checking whether Xutf8SetWMProperties() can be used... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char Xutf8SetWMProperties ();
+int
+main ()
+{
+return Xutf8SetWMProperties ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ $as_echo "#define HAVE_XUTF8SETWMPROPERTIES 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+
+ CFLAGS=$cflags_save
+ LIBS=$libs_save
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for _xpg4_setrunelocale in -lxpg4" >&5
+$as_echo_n "checking for _xpg4_setrunelocale in -lxpg4... " >&6; }
+if ${ac_cv_lib_xpg4__xpg4_setrunelocale+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lxpg4 $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char _xpg4_setrunelocale ();
+int
+main ()
+{
+return _xpg4_setrunelocale ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_xpg4__xpg4_setrunelocale=yes
+else
+ ac_cv_lib_xpg4__xpg4_setrunelocale=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_xpg4__xpg4_setrunelocale" >&5
+$as_echo "$ac_cv_lib_xpg4__xpg4_setrunelocale" >&6; }
+if test "x$ac_cv_lib_xpg4__xpg4_setrunelocale" = xyes; then :
+ LIBS="$LIBS -lxpg4"
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to create tags" >&5
+$as_echo_n "checking how to create tags... " >&6; }
+test -f tags && mv tags tags.save
+if (eval ctags --version /dev/null | grep Exuberant) < /dev/null 1>&5 2>&1; then
+ TAGPRG="ctags -I INIT+ --fields=+S"
+elif (eval exctags --version /dev/null | grep Exuberant) < /dev/null 1>&5 2>&1; then
+ TAGPRG="exctags -I INIT+ --fields=+S"
+elif (eval exuberant-ctags --version /dev/null | grep Exuberant) < /dev/null 1>&5 2>&1; then
+ TAGPRG="exuberant-ctags -I INIT+ --fields=+S"
+else
+ TAGPRG="ctags"
+ (eval etags /dev/null) < /dev/null 1>&5 2>&1 && TAGPRG="etags"
+ (eval etags -c /dev/null) < /dev/null 1>&5 2>&1 && TAGPRG="etags -c"
+ (eval ctags /dev/null) < /dev/null 1>&5 2>&1 && TAGPRG="ctags"
+ (eval ctags -t /dev/null) < /dev/null 1>&5 2>&1 && TAGPRG="ctags -t"
+ (eval ctags -ts /dev/null) < /dev/null 1>&5 2>&1 && TAGPRG="ctags -ts"
+ (eval ctags -tvs /dev/null) < /dev/null 1>&5 2>&1 && TAGPRG="ctags -tvs"
+ (eval ctags -i+m /dev/null) < /dev/null 1>&5 2>&1 && TAGPRG="ctags -i+m"
+fi
+test -f tags.save && mv tags.save tags
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $TAGPRG" >&5
+$as_echo "$TAGPRG" >&6; }
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run man with a section nr" >&5
+$as_echo_n "checking how to run man with a section nr... " >&6; }
+MANDEF="man"
+(eval MANPAGER=cat PAGER=cat man -s 2 read) < /dev/null > /dev/null 2>&5 && MANDEF="man -s"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MANDEF" >&5
+$as_echo "$MANDEF" >&6; }
+if test "$MANDEF" = "man -s"; then
+ $as_echo "#define USEMAN_S 1" >>confdefs.h
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --disable-nls argument" >&5
+$as_echo_n "checking --disable-nls argument... " >&6; }
+# Check whether --enable-nls was given.
+if test "${enable_nls+set}" = set; then :
+ enableval=$enable_nls;
+else
+ enable_nls="yes"
+fi
+
+
+if test "$enable_nls" = "yes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+ INSTALL_LANGS=install-languages
+
+ INSTALL_TOOL_LANGS=install-tool-languages
+
+
+ # Extract the first word of "msgfmt", so it can be a program name with args.
+set dummy msgfmt; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_MSGFMT+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$MSGFMT"; then
+ ac_cv_prog_MSGFMT="$MSGFMT" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_MSGFMT="msgfmt"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+MSGFMT=$ac_cv_prog_MSGFMT
+if test -n "$MSGFMT"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MSGFMT" >&5
+$as_echo "$MSGFMT" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for NLS" >&5
+$as_echo_n "checking for NLS... " >&6; }
+ if test -f po/Makefile; then
+ have_gettext="no"
+ if test -n "$MSGFMT"; then
+ olibs=$LIBS
+ LIBS=""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <libintl.h>
+int
+main ()
+{
+gettext("Test");
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: gettext() works" >&5
+$as_echo "gettext() works" >&6; }; have_gettext="yes"; LIBS=$olibs
+else
+ LIBS="-lintl"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <libintl.h>
+int
+main ()
+{
+gettext("Test");
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: gettext() works with -lintl" >&5
+$as_echo "gettext() works with -lintl" >&6; }; have_gettext="yes";
+ LIBS="$olibs -lintl"
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: gettext() doesn't work" >&5
+$as_echo "gettext() doesn't work" >&6; };
+ LIBS=$olibs
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: msgfmt not found - disabled" >&5
+$as_echo "msgfmt not found - disabled" >&6; };
+ fi
+ if test $have_gettext = "yes" -a "x$features" != "xtiny" -a "x$features" != "xsmall"; then
+ $as_echo "#define HAVE_GETTEXT 1" >>confdefs.h
+
+ MAKEMO=yes
+
+ for ac_func in bind_textdomain_codeset
+do :
+ ac_fn_c_check_func "$LINENO" "bind_textdomain_codeset" "ac_cv_func_bind_textdomain_codeset"
+if test "x$ac_cv_func_bind_textdomain_codeset" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_BIND_TEXTDOMAIN_CODESET 1
+_ACEOF
+
+fi
+done
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _nl_msg_cat_cntr" >&5
+$as_echo_n "checking for _nl_msg_cat_cntr... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <libintl.h>
+ extern int _nl_msg_cat_cntr;
+int
+main ()
+{
+++_nl_msg_cat_cntr;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }; $as_echo "#define HAVE_NL_MSG_CAT_CNTR 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no \"po/Makefile\" - disabled" >&5
+$as_echo "no \"po/Makefile\" - disabled" >&6; };
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+
+ac_fn_c_check_header_mongrel "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default"
+if test "x$ac_cv_header_dlfcn_h" = xyes; then :
+ DLL=dlfcn.h
+else
+ ac_fn_c_check_header_mongrel "$LINENO" "dl.h" "ac_cv_header_dl_h" "$ac_includes_default"
+if test "x$ac_cv_header_dl_h" = xyes; then :
+ DLL=dl.h
+fi
+
+
+fi
+
+
+if test x${DLL} = xdlfcn.h; then
+
+$as_echo "#define HAVE_DLFCN_H 1" >>confdefs.h
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen()" >&5
+$as_echo_n "checking for dlopen()... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ extern void* dlopen();
+ dlopen();
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; };
+
+$as_echo "#define HAVE_DLOPEN 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; };
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen() in -ldl" >&5
+$as_echo_n "checking for dlopen() in -ldl... " >&6; }
+ olibs=$LIBS
+ LIBS="$LIBS -ldl"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ extern void* dlopen();
+ dlopen();
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; };
+
+$as_echo "#define HAVE_DLOPEN 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; };
+ LIBS=$olibs
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlsym()" >&5
+$as_echo_n "checking for dlsym()... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ extern void* dlsym();
+ dlsym();
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; };
+
+$as_echo "#define HAVE_DLSYM 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; };
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlsym() in -ldl" >&5
+$as_echo_n "checking for dlsym() in -ldl... " >&6; }
+ olibs=$LIBS
+ LIBS="$LIBS -ldl"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ extern void* dlsym();
+ dlsym();
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; };
+
+$as_echo "#define HAVE_DLSYM 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; };
+ LIBS=$olibs
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+elif test x${DLL} = xdl.h; then
+
+$as_echo "#define HAVE_DL_H 1" >>confdefs.h
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load()" >&5
+$as_echo_n "checking for shl_load()... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ extern void* shl_load();
+ shl_load();
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; };
+
+$as_echo "#define HAVE_SHL_LOAD 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; };
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load() in -ldld" >&5
+$as_echo_n "checking for shl_load() in -ldld... " >&6; }
+ olibs=$LIBS
+ LIBS="$LIBS -ldld"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ extern void* shl_load();
+ shl_load();
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; };
+
+$as_echo "#define HAVE_SHL_LOAD 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; };
+ LIBS=$olibs
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+for ac_header in setjmp.h
+do :
+ ac_fn_c_check_header_mongrel "$LINENO" "setjmp.h" "ac_cv_header_setjmp_h" "$ac_includes_default"
+if test "x$ac_cv_header_setjmp_h" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_SETJMP_H 1
+_ACEOF
+
+fi
+
+done
+
+
+if test "x$MACOS_X" = "xyes" -a -n "$PERL"; then
+ if echo $LIBS | grep -e '-ldl' >/dev/null; then
+ LIBS=`echo $LIBS | sed s/-ldl//`
+ PERL_LIBS="$PERL_LIBS -ldl"
+ fi
+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 "$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++'`
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes, we need CoreServices" >&5
+$as_echo "yes, we need CoreServices" >&6; }
+ LIBS="$LIBS -framework CoreServices"
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes, we need AppKit" >&5
+$as_echo "yes, we need AppKit" >&6; }
+ LIBS="$LIBS -framework AppKit"
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ fi
+fi
+if test "x$MACARCH" = "xboth" && test "x$GUITYPE" = "xCARBONGUI"; then
+ LDFLAGS="$LDFLAGS -isysroot $DEVELOPER_DIR/SDKs/MacOSX10.4u.sdk -arch i386 -arch ppc"
+fi
+
+DEPEND_CFLAGS_FILTER=
+if test "$GCC" = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GCC 3 or later" >&5
+$as_echo_n "checking for GCC 3 or later... " >&6; }
+ gccmajor=`echo "$gccversion" | sed -e 's/^\([1-9]\)\..*$/\1/g'`
+ if test "$gccmajor" -gt "2"; then
+ DEPEND_CFLAGS_FILTER="| sed 's+-I */+-isystem /+g'"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we need -D_FORTIFY_SOURCE=1" >&5
+$as_echo_n "checking whether we need -D_FORTIFY_SOURCE=1... " >&6; }
+ if test "$gccmajor" -gt "3"; then
+ CFLAGS=`echo "$CFLAGS" | sed -e 's/ *-Wp,-D_FORTIFY_SOURCE=.//g' -e 's/ *-D_FORTIFY_SOURCE=.//g' -e 's/ *-U_FORTIFY_SOURCE//g' -e 's/$/ -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1/'`
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ fi
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we need to force -D_FILE_OFFSET_BITS=64" >&5
+$as_echo_n "checking whether we need to force -D_FILE_OFFSET_BITS=64... " >&6; }
+if echo "$CFLAGS $LUA_CFLAGS $MZSCHEME_CFLAGS $PERL_CFLAGS $PYTHON_CFLAGS $PYTHON3_CFLAGS $TCL_CFLAGS $RUBY_CFLAGS $GTK_CFLAGS" | grep -q D_FILE_OFFSET_BITS 2>/dev/null; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ $as_echo "#define _FILE_OFFSET_BITS 64" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking linker --as-needed support" >&5
+$as_echo_n "checking linker --as-needed support... " >&6; }
+LINK_AS_NEEDED=
+# Check if linker supports --as-needed and --no-as-needed options
+if $CC -Wl,--help 2>/dev/null | grep as-needed > /dev/null; then
+ LDFLAGS=`echo "$LDFLAGS" | sed -e 's/ *-Wl,--as-needed//g' | sed -e 's/$/ -Wl,--as-needed/'`
+ LINK_AS_NEEDED=yes
+fi
+if test "$LINK_AS_NEEDED" = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+# IBM z/OS reset CFLAGS for config.mk
+if test "$zOSUnix" = "yes"; then
+ CFLAGS="-D_ALL_SOURCE -Wc,float\(ieee\),dll"
+fi
+
+ac_config_files="$ac_config_files auto/config.mk:config.mk.in"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+ for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+
+ (set) 2>&1 |
+ case $as_nl`(ac_space=' '; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ # `set' does not quote correctly, so add quotes: double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \.
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;; #(
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+) |
+ sed '
+ /^ac_cv_env_/b end
+ t clear
+ :clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+ if test -w "$cache_file"; then
+ if test "x$cache_file" != "x/dev/null"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+ if test ! -f "$cache_file" || test -h "$cache_file"; then
+ cat confcache >"$cache_file"
+ else
+ case $cache_file in #(
+ */* | ?:*)
+ mv -f confcache "$cache_file"$$ &&
+ mv -f "$cache_file"$$ "$cache_file" ;; #(
+ *)
+ mv -f confcache "$cache_file" ;;
+ esac
+ fi
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+ --header=FILE[:TEMPLATE]
+ instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+AWK='$AWK'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ as_fn_append CONFIG_HEADERS " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h)
+ # Conflict between --help and --header
+ as_fn_error $? "ambiguous option: \`$1'
+Try \`$0 --help' for more information.";;
+ --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>auto/config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "auto/config.h") CONFIG_HEADERS="$CONFIG_HEADERS auto/config.h:config.h.in" ;;
+ "auto/config.mk") CONFIG_FILES="$CONFIG_FILES auto/config.mk:config.mk.in" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+ test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ line = $ 0
+ nfields = split(line, field, "@")
+ substed = 0
+ len = length(field[1])
+ for (i = 2; i < nfields; i++) {
+ key = field[i]
+ keylen = length(key)
+ if (S_is_set[key]) {
+ value = S[key]
+ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+ len += length(value) + length(field[++i])
+ substed = 1
+ } else
+ len += 1 + keylen
+ }
+
+ print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+ cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
+h
+s///
+s/^/:/
+s/[ ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[ ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[ ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+# Set up the scripts for CONFIG_HEADERS section.
+# No need to generate them if there are no CONFIG_HEADERS.
+# This happens for instance with `./config.status Makefile'.
+if test -n "$CONFIG_HEADERS"; then
+cat >"$ac_tmp/defines.awk" <<\_ACAWK ||
+BEGIN {
+_ACEOF
+
+# Transform confdefs.h into an awk script `defines.awk', embedded as
+# here-document in config.status, that substitutes the proper values into
+# config.h.in to produce config.h.
+
+# Create a delimiter string that does not exist in confdefs.h, to ease
+# handling of long lines.
+ac_delim='%!_!# '
+for ac_last_try in false false :; do
+ ac_tt=`sed -n "/$ac_delim/p" confdefs.h`
+ if test -z "$ac_tt"; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+
+# For the awk script, D is an array of macro values keyed by name,
+# likewise P contains macro parameters if any. Preserve backslash
+# newline sequences.
+
+ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*
+sed -n '
+s/.\{148\}/&'"$ac_delim"'/g
+t rset
+:rset
+s/^[ ]*#[ ]*define[ ][ ]*/ /
+t def
+d
+:def
+s/\\$//
+t bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3"/p
+s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p
+d
+:bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3\\\\\\n"\\/p
+t cont
+s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p
+t cont
+d
+:cont
+n
+s/.\{148\}/&'"$ac_delim"'/g
+t clear
+:clear
+s/\\$//
+t bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/"/p
+d
+:bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p
+b cont
+' <confdefs.h | sed '
+s/'"$ac_delim"'/"\\\
+"/g' >>$CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ for (key in D) D_is_set[key] = 1
+ FS = ""
+}
+/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ {
+ line = \$ 0
+ split(line, arg, " ")
+ if (arg[1] == "#") {
+ defundef = arg[2]
+ mac1 = arg[3]
+ } else {
+ defundef = substr(arg[1], 2)
+ mac1 = arg[2]
+ }
+ split(mac1, mac2, "(") #)
+ macro = mac2[1]
+ prefix = substr(line, 1, index(line, defundef) - 1)
+ if (D_is_set[macro]) {
+ # Preserve the white space surrounding the "#".
+ print prefix "define", macro P[macro] D[macro]
+ next
+ } else {
+ # Replace #undef with comments. This is necessary, for example,
+ # in the case of _POSIX_SOURCE, which is predefined and required
+ # on some systems where configure will not decide to define it.
+ if (defundef == "undef") {
+ print "/*", prefix defundef, macro, "*/"
+ next
+ }
+ }
+}
+{ print }
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ as_fn_error $? "could not setup config headers machinery" "$LINENO" 5
+fi # test -n "$CONFIG_HEADERS"
+
+
+eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS "
+shift
+for ac_tag
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+ ac_save_IFS=$IFS
+ IFS=:
+ set x $ac_tag
+ IFS=$ac_save_IFS
+ shift
+ ac_file=$1
+ shift
+
+ case $ac_mode in
+ :L) ac_source=$1;;
+ :[FH])
+ ac_file_inputs=
+ for ac_f
+ do
+ case $ac_f in
+ -) ac_f="$ac_tmp/stdin";;
+ *) # Look for the file first in the build tree, then in the source tree
+ # (if the path is not absolute). The absolute path cannot be DOS-style,
+ # because $ac_f cannot contain `:'.
+ test -f "$ac_f" ||
+ case $ac_f in
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ esac
+ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ as_fn_append ac_file_inputs " '$ac_f'"
+ done
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ configure_input='Generated from '`
+ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ `' by configure.'
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+ fi
+ # Neutralize special characters interpreted by sed in replacement strings.
+ case $configure_input in #(
+ *\&* | *\|* | *\\* )
+ ac_sed_conf_input=`$as_echo "$configure_input" |
+ sed 's/[\\\\&|]/\\\\&/g'`;; #(
+ *) ac_sed_conf_input=$configure_input;;
+ esac
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$ac_tmp/stdin" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+ esac
+ ;;
+ esac
+
+ ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir="$ac_dir"; as_fn_mkdir_p
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ case $ac_mode in
+ :F)
+ #
+ # CONFIG_FILE
+ #
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ ac_datarootdir_hack='
+ s&@datadir@&$datadir&g
+ s&@docdir@&$docdir&g
+ s&@infodir@&$infodir&g
+ s&@localedir@&$localedir&g
+ s&@mandir@&$mandir&g
+ s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
+ "$ac_tmp/out"`; test -z "$ac_out"; } &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&2;}
+
+ rm -f "$ac_tmp/stdin"
+ case $ac_file in
+ -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+ *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+ esac \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+ :H)
+ #
+ # CONFIG_HEADER
+ #
+ if test x"$ac_file" != x-; then
+ {
+ $as_echo "/* $configure_input */" \
+ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs"
+ } >"$ac_tmp/config.h" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
+$as_echo "$as_me: $ac_file is unchanged" >&6;}
+ else
+ rm -f "$ac_file"
+ mv "$ac_tmp/config.h" "$ac_file" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ fi
+ else
+ $as_echo "/* $configure_input */" \
+ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \
+ || as_fn_error $? "could not create -" "$LINENO" 5
+ fi
+ ;;
+
+
+ esac
+
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+ as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>auto/config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
+
diff --git a/src/autocmd.c b/src/autocmd.c
new file mode 100644
index 0000000..55650b4
--- /dev/null
+++ b/src/autocmd.c
@@ -0,0 +1,2579 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * autocmd.c: Autocommand related functions
+ */
+
+#include "vim.h"
+
+/*
+ * The autocommands are stored in a list for each event.
+ * Autocommands for the same pattern, that are consecutive, are joined
+ * together, to avoid having to match the pattern too often.
+ * The result is an array of Autopat lists, which point to AutoCmd lists:
+ *
+ * last_autopat[0] -----------------------------+
+ * V
+ * first_autopat[0] --> Autopat.next --> Autopat.next --> NULL
+ * Autopat.cmds Autopat.cmds
+ * | |
+ * V V
+ * AutoCmd.next AutoCmd.next
+ * | |
+ * V V
+ * AutoCmd.next NULL
+ * |
+ * V
+ * NULL
+ *
+ * last_autopat[1] --------+
+ * V
+ * first_autopat[1] --> Autopat.next --> NULL
+ * Autopat.cmds
+ * |
+ * V
+ * AutoCmd.next
+ * |
+ * V
+ * NULL
+ * etc.
+ *
+ * The order of AutoCmds is important, this is the order in which they were
+ * defined and will have to be executed.
+ */
+typedef struct AutoCmd
+{
+ char_u *cmd; // The command to be executed (NULL
+ // when command has been removed).
+ char nested; // If autocommands nest here.
+ char last; // last command in list
+#ifdef FEAT_EVAL
+ sctx_T script_ctx; // script context where defined
+#endif
+ struct AutoCmd *next; // next AutoCmd in list
+} AutoCmd;
+
+typedef struct AutoPat
+{
+ struct AutoPat *next; // Next AutoPat in AutoPat list; MUST
+ // be the first entry.
+ char_u *pat; // pattern as typed (NULL when pattern
+ // has been removed)
+ regprog_T *reg_prog; // compiled regprog for pattern
+ AutoCmd *cmds; // list of commands to do
+ int group; // group ID
+ int patlen; // strlen() of pat
+ int buflocal_nr; // !=0 for buffer-local AutoPat
+ char allow_dirs; // Pattern may match whole path
+ char last; // last pattern for apply_autocmds()
+} AutoPat;
+
+static struct event_name
+{
+ char *name; // event name
+ event_T event; // event number
+} event_names[] =
+{
+ {"BufAdd", EVENT_BUFADD},
+ {"BufCreate", EVENT_BUFADD},
+ {"BufDelete", EVENT_BUFDELETE},
+ {"BufEnter", EVENT_BUFENTER},
+ {"BufFilePost", EVENT_BUFFILEPOST},
+ {"BufFilePre", EVENT_BUFFILEPRE},
+ {"BufHidden", EVENT_BUFHIDDEN},
+ {"BufLeave", EVENT_BUFLEAVE},
+ {"BufNew", EVENT_BUFNEW},
+ {"BufNewFile", EVENT_BUFNEWFILE},
+ {"BufRead", EVENT_BUFREADPOST},
+ {"BufReadCmd", EVENT_BUFREADCMD},
+ {"BufReadPost", EVENT_BUFREADPOST},
+ {"BufReadPre", EVENT_BUFREADPRE},
+ {"BufUnload", EVENT_BUFUNLOAD},
+ {"BufWinEnter", EVENT_BUFWINENTER},
+ {"BufWinLeave", EVENT_BUFWINLEAVE},
+ {"BufWipeout", EVENT_BUFWIPEOUT},
+ {"BufWrite", EVENT_BUFWRITEPRE},
+ {"BufWritePost", EVENT_BUFWRITEPOST},
+ {"BufWritePre", EVENT_BUFWRITEPRE},
+ {"BufWriteCmd", EVENT_BUFWRITECMD},
+ {"CmdlineChanged", EVENT_CMDLINECHANGED},
+ {"CmdlineEnter", EVENT_CMDLINEENTER},
+ {"CmdlineLeave", EVENT_CMDLINELEAVE},
+ {"CmdwinEnter", EVENT_CMDWINENTER},
+ {"CmdwinLeave", EVENT_CMDWINLEAVE},
+ {"CmdUndefined", EVENT_CMDUNDEFINED},
+ {"ColorScheme", EVENT_COLORSCHEME},
+ {"ColorSchemePre", EVENT_COLORSCHEMEPRE},
+ {"CompleteDone", EVENT_COMPLETEDONE},
+ {"CursorHold", EVENT_CURSORHOLD},
+ {"CursorHoldI", EVENT_CURSORHOLDI},
+ {"CursorMoved", EVENT_CURSORMOVED},
+ {"CursorMovedI", EVENT_CURSORMOVEDI},
+ {"DiffUpdated", EVENT_DIFFUPDATED},
+ {"DirChanged", EVENT_DIRCHANGED},
+ {"EncodingChanged", EVENT_ENCODINGCHANGED},
+ {"ExitPre", EVENT_EXITPRE},
+ {"FileEncoding", EVENT_ENCODINGCHANGED},
+ {"FileAppendPost", EVENT_FILEAPPENDPOST},
+ {"FileAppendPre", EVENT_FILEAPPENDPRE},
+ {"FileAppendCmd", EVENT_FILEAPPENDCMD},
+ {"FileChangedShell",EVENT_FILECHANGEDSHELL},
+ {"FileChangedShellPost",EVENT_FILECHANGEDSHELLPOST},
+ {"FileChangedRO", EVENT_FILECHANGEDRO},
+ {"FileReadPost", EVENT_FILEREADPOST},
+ {"FileReadPre", EVENT_FILEREADPRE},
+ {"FileReadCmd", EVENT_FILEREADCMD},
+ {"FileType", EVENT_FILETYPE},
+ {"FileWritePost", EVENT_FILEWRITEPOST},
+ {"FileWritePre", EVENT_FILEWRITEPRE},
+ {"FileWriteCmd", EVENT_FILEWRITECMD},
+ {"FilterReadPost", EVENT_FILTERREADPOST},
+ {"FilterReadPre", EVENT_FILTERREADPRE},
+ {"FilterWritePost", EVENT_FILTERWRITEPOST},
+ {"FilterWritePre", EVENT_FILTERWRITEPRE},
+ {"FocusGained", EVENT_FOCUSGAINED},
+ {"FocusLost", EVENT_FOCUSLOST},
+ {"FuncUndefined", EVENT_FUNCUNDEFINED},
+ {"GUIEnter", EVENT_GUIENTER},
+ {"GUIFailed", EVENT_GUIFAILED},
+ {"InsertChange", EVENT_INSERTCHANGE},
+ {"InsertEnter", EVENT_INSERTENTER},
+ {"InsertLeave", EVENT_INSERTLEAVE},
+ {"InsertCharPre", EVENT_INSERTCHARPRE},
+ {"MenuPopup", EVENT_MENUPOPUP},
+ {"OptionSet", EVENT_OPTIONSET},
+ {"QuickFixCmdPost", EVENT_QUICKFIXCMDPOST},
+ {"QuickFixCmdPre", EVENT_QUICKFIXCMDPRE},
+ {"QuitPre", EVENT_QUITPRE},
+ {"RemoteReply", EVENT_REMOTEREPLY},
+ {"SessionLoadPost", EVENT_SESSIONLOADPOST},
+ {"ShellCmdPost", EVENT_SHELLCMDPOST},
+ {"ShellFilterPost", EVENT_SHELLFILTERPOST},
+ {"SourceCmd", EVENT_SOURCECMD},
+ {"SourcePre", EVENT_SOURCEPRE},
+ {"SourcePost", EVENT_SOURCEPOST},
+ {"SpellFileMissing",EVENT_SPELLFILEMISSING},
+ {"StdinReadPost", EVENT_STDINREADPOST},
+ {"StdinReadPre", EVENT_STDINREADPRE},
+ {"SwapExists", EVENT_SWAPEXISTS},
+ {"Syntax", EVENT_SYNTAX},
+ {"TabNew", EVENT_TABNEW},
+ {"TabClosed", EVENT_TABCLOSED},
+ {"TabEnter", EVENT_TABENTER},
+ {"TabLeave", EVENT_TABLEAVE},
+ {"TermChanged", EVENT_TERMCHANGED},
+ {"TerminalOpen", EVENT_TERMINALOPEN},
+ {"TermResponse", EVENT_TERMRESPONSE},
+ {"TextChanged", EVENT_TEXTCHANGED},
+ {"TextChangedI", EVENT_TEXTCHANGEDI},
+ {"TextChangedP", EVENT_TEXTCHANGEDP},
+ {"User", EVENT_USER},
+ {"VimEnter", EVENT_VIMENTER},
+ {"VimLeave", EVENT_VIMLEAVE},
+ {"VimLeavePre", EVENT_VIMLEAVEPRE},
+ {"WinNew", EVENT_WINNEW},
+ {"WinEnter", EVENT_WINENTER},
+ {"WinLeave", EVENT_WINLEAVE},
+ {"VimResized", EVENT_VIMRESIZED},
+ {"TextYankPost", EVENT_TEXTYANKPOST},
+ {NULL, (event_T)0}
+};
+
+static AutoPat *first_autopat[NUM_EVENTS] =
+{
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+static AutoPat *last_autopat[NUM_EVENTS] =
+{
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+#define AUGROUP_DEFAULT -1 // default autocmd group
+#define AUGROUP_ERROR -2 // erroneous autocmd group
+#define AUGROUP_ALL -3 // all autocmd groups
+
+/*
+ * struct used to keep status while executing autocommands for an event.
+ */
+typedef struct AutoPatCmd
+{
+ AutoPat *curpat; // next AutoPat to examine
+ AutoCmd *nextcmd; // next AutoCmd to execute
+ int group; // group being used
+ char_u *fname; // fname to match with
+ char_u *sfname; // sfname to match with
+ char_u *tail; // tail of fname
+ event_T event; // current event
+ int arg_bufnr; // Initially equal to <abuf>, set to zero when
+ // buf is deleted.
+ struct AutoPatCmd *next; // chain of active apc-s for auto-invalidation
+} AutoPatCmd;
+
+static AutoPatCmd *active_apc_list = NULL; /* stack of active autocommands */
+
+/*
+ * augroups stores a list of autocmd group names.
+ */
+static garray_T augroups = {0, 0, sizeof(char_u *), 10, NULL};
+#define AUGROUP_NAME(i) (((char_u **)augroups.ga_data)[i])
+/* use get_deleted_augroup() to get this */
+static char_u *deleted_augroup = NULL;
+
+/*
+ * Set by the apply_autocmds_group function if the given event is equal to
+ * EVENT_FILETYPE. Used by the readfile function in order to determine if
+ * EVENT_BUFREADPOST triggered the EVENT_FILETYPE.
+ *
+ * Relying on this value requires one to reset it prior calling
+ * apply_autocmds_group.
+ */
+int au_did_filetype INIT(= FALSE);
+
+/*
+ * The ID of the current group. Group 0 is the default one.
+ */
+static int current_augroup = AUGROUP_DEFAULT;
+
+static int au_need_clean = FALSE; /* need to delete marked patterns */
+
+static char_u *event_nr2name(event_T event);
+static int au_get_grouparg(char_u **argp);
+static int do_autocmd_event(event_T event, char_u *pat, int nested, char_u *cmd, int forceit, int group);
+static int apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io, int force, int group, buf_T *buf, exarg_T *eap);
+static void auto_next_pat(AutoPatCmd *apc, int stop_at_last);
+static int au_find_group(char_u *name);
+
+static event_T last_event;
+static int last_group;
+static int autocmd_blocked = 0; /* block all autocmds */
+
+ static char_u *
+get_deleted_augroup(void)
+{
+ if (deleted_augroup == NULL)
+ deleted_augroup = (char_u *)_("--Deleted--");
+ return deleted_augroup;
+}
+
+/*
+ * Show the autocommands for one AutoPat.
+ */
+ static void
+show_autocmd(AutoPat *ap, event_T event)
+{
+ AutoCmd *ac;
+
+ // Check for "got_int" (here and at various places below), which is set
+ // when "q" has been hit for the "--more--" prompt
+ if (got_int)
+ return;
+ if (ap->pat == NULL) // pattern has been removed
+ return;
+
+ msg_putchar('\n');
+ if (got_int)
+ return;
+ if (event != last_event || ap->group != last_group)
+ {
+ if (ap->group != AUGROUP_DEFAULT)
+ {
+ if (AUGROUP_NAME(ap->group) == NULL)
+ msg_puts_attr((char *)get_deleted_augroup(), HL_ATTR(HLF_E));
+ else
+ msg_puts_attr((char *)AUGROUP_NAME(ap->group), HL_ATTR(HLF_T));
+ msg_puts(" ");
+ }
+ msg_puts_attr((char *)event_nr2name(event), HL_ATTR(HLF_T));
+ last_event = event;
+ last_group = ap->group;
+ msg_putchar('\n');
+ if (got_int)
+ return;
+ }
+ msg_col = 4;
+ msg_outtrans(ap->pat);
+
+ for (ac = ap->cmds; ac != NULL; ac = ac->next)
+ {
+ if (ac->cmd != NULL) // skip removed commands
+ {
+ if (msg_col >= 14)
+ msg_putchar('\n');
+ msg_col = 14;
+ if (got_int)
+ return;
+ msg_outtrans(ac->cmd);
+#ifdef FEAT_EVAL
+ if (p_verbose > 0)
+ last_set_msg(ac->script_ctx);
+#endif
+ if (got_int)
+ return;
+ if (ac->next != NULL)
+ {
+ msg_putchar('\n');
+ if (got_int)
+ return;
+ }
+ }
+ }
+}
+
+/*
+ * Mark an autocommand pattern for deletion.
+ */
+ static void
+au_remove_pat(AutoPat *ap)
+{
+ VIM_CLEAR(ap->pat);
+ ap->buflocal_nr = -1;
+ au_need_clean = TRUE;
+}
+
+/*
+ * Mark all commands for a pattern for deletion.
+ */
+ static void
+au_remove_cmds(AutoPat *ap)
+{
+ AutoCmd *ac;
+
+ for (ac = ap->cmds; ac != NULL; ac = ac->next)
+ VIM_CLEAR(ac->cmd);
+ au_need_clean = TRUE;
+}
+
+/*
+ * Cleanup autocommands and patterns that have been deleted.
+ * This is only done when not executing autocommands.
+ */
+ static void
+au_cleanup(void)
+{
+ AutoPat *ap, **prev_ap;
+ AutoCmd *ac, **prev_ac;
+ event_T event;
+
+ if (autocmd_busy || !au_need_clean)
+ return;
+
+ // loop over all events
+ for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
+ event = (event_T)((int)event + 1))
+ {
+ // loop over all autocommand patterns
+ prev_ap = &(first_autopat[(int)event]);
+ for (ap = *prev_ap; ap != NULL; ap = *prev_ap)
+ {
+ // loop over all commands for this pattern
+ prev_ac = &(ap->cmds);
+ for (ac = *prev_ac; ac != NULL; ac = *prev_ac)
+ {
+ // remove the command if the pattern is to be deleted or when
+ // the command has been marked for deletion
+ if (ap->pat == NULL || ac->cmd == NULL)
+ {
+ *prev_ac = ac->next;
+ vim_free(ac->cmd);
+ vim_free(ac);
+ }
+ else
+ prev_ac = &(ac->next);
+ }
+
+ // remove the pattern if it has been marked for deletion
+ if (ap->pat == NULL)
+ {
+ if (ap->next == NULL)
+ {
+ if (prev_ap == &(first_autopat[(int)event]))
+ last_autopat[(int)event] = NULL;
+ else
+ // this depends on the "next" field being the first in
+ // the struct
+ last_autopat[(int)event] = (AutoPat *)prev_ap;
+ }
+ *prev_ap = ap->next;
+ vim_regfree(ap->reg_prog);
+ vim_free(ap);
+ }
+ else
+ prev_ap = &(ap->next);
+ }
+ }
+
+ au_need_clean = FALSE;
+}
+
+/*
+ * Called when buffer is freed, to remove/invalidate related buffer-local
+ * autocmds.
+ */
+ void
+aubuflocal_remove(buf_T *buf)
+{
+ AutoPat *ap;
+ event_T event;
+ AutoPatCmd *apc;
+
+ // invalidate currently executing autocommands
+ for (apc = active_apc_list; apc; apc = apc->next)
+ if (buf->b_fnum == apc->arg_bufnr)
+ apc->arg_bufnr = 0;
+
+ // invalidate buflocals looping through events
+ for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
+ event = (event_T)((int)event + 1))
+ // loop over all autocommand patterns
+ for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next)
+ if (ap->buflocal_nr == buf->b_fnum)
+ {
+ au_remove_pat(ap);
+ if (p_verbose >= 6)
+ {
+ verbose_enter();
+ smsg(_("auto-removing autocommand: %s <buffer=%d>"),
+ event_nr2name(event), buf->b_fnum);
+ verbose_leave();
+ }
+ }
+ au_cleanup();
+}
+
+/*
+ * Add an autocmd group name.
+ * Return its ID. Returns AUGROUP_ERROR (< 0) for error.
+ */
+ static int
+au_new_group(char_u *name)
+{
+ int i;
+
+ i = au_find_group(name);
+ if (i == AUGROUP_ERROR) // the group doesn't exist yet, add it
+ {
+ // First try using a free entry.
+ for (i = 0; i < augroups.ga_len; ++i)
+ if (AUGROUP_NAME(i) == NULL)
+ break;
+ if (i == augroups.ga_len && ga_grow(&augroups, 1) == FAIL)
+ return AUGROUP_ERROR;
+
+ AUGROUP_NAME(i) = vim_strsave(name);
+ if (AUGROUP_NAME(i) == NULL)
+ return AUGROUP_ERROR;
+ if (i == augroups.ga_len)
+ ++augroups.ga_len;
+ }
+
+ return i;
+}
+
+ static void
+au_del_group(char_u *name)
+{
+ int i;
+
+ i = au_find_group(name);
+ if (i == AUGROUP_ERROR) // the group doesn't exist
+ semsg(_("E367: No such group: \"%s\""), name);
+ else if (i == current_augroup)
+ emsg(_("E936: Cannot delete the current group"));
+ else
+ {
+ event_T event;
+ AutoPat *ap;
+ int in_use = FALSE;
+
+ for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
+ event = (event_T)((int)event + 1))
+ {
+ for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next)
+ if (ap->group == i && ap->pat != NULL)
+ {
+ give_warning((char_u *)_("W19: Deleting augroup that is still in use"), TRUE);
+ in_use = TRUE;
+ event = NUM_EVENTS;
+ break;
+ }
+ }
+ vim_free(AUGROUP_NAME(i));
+ if (in_use)
+ {
+ AUGROUP_NAME(i) = get_deleted_augroup();
+ }
+ else
+ AUGROUP_NAME(i) = NULL;
+ }
+}
+
+/*
+ * Find the ID of an autocmd group name.
+ * Return its ID. Returns AUGROUP_ERROR (< 0) for error.
+ */
+ static int
+au_find_group(char_u *name)
+{
+ int i;
+
+ for (i = 0; i < augroups.ga_len; ++i)
+ if (AUGROUP_NAME(i) != NULL && AUGROUP_NAME(i) != get_deleted_augroup()
+ && STRCMP(AUGROUP_NAME(i), name) == 0)
+ return i;
+ return AUGROUP_ERROR;
+}
+
+/*
+ * Return TRUE if augroup "name" exists.
+ */
+ int
+au_has_group(char_u *name)
+{
+ return au_find_group(name) != AUGROUP_ERROR;
+}
+
+/*
+ * ":augroup {name}".
+ */
+ void
+do_augroup(char_u *arg, int del_group)
+{
+ int i;
+
+ if (del_group)
+ {
+ if (*arg == NUL)
+ emsg(_(e_argreq));
+ else
+ au_del_group(arg);
+ }
+ else if (STRICMP(arg, "end") == 0) // ":aug end": back to group 0
+ current_augroup = AUGROUP_DEFAULT;
+ else if (*arg) // ":aug xxx": switch to group xxx
+ {
+ i = au_new_group(arg);
+ if (i != AUGROUP_ERROR)
+ current_augroup = i;
+ }
+ else // ":aug": list the group names
+ {
+ msg_start();
+ for (i = 0; i < augroups.ga_len; ++i)
+ {
+ if (AUGROUP_NAME(i) != NULL)
+ {
+ msg_puts((char *)AUGROUP_NAME(i));
+ msg_puts(" ");
+ }
+ }
+ msg_clr_eos();
+ msg_end();
+ }
+}
+
+#if defined(EXITFREE) || defined(PROTO)
+ void
+free_all_autocmds(void)
+{
+ int i;
+ char_u *s;
+
+ for (current_augroup = -1; current_augroup < augroups.ga_len;
+ ++current_augroup)
+ do_autocmd((char_u *)"", TRUE);
+
+ for (i = 0; i < augroups.ga_len; ++i)
+ {
+ s = ((char_u **)(augroups.ga_data))[i];
+ if (s != get_deleted_augroup())
+ vim_free(s);
+ }
+ ga_clear(&augroups);
+}
+#endif
+
+/*
+ * Return the event number for event name "start".
+ * Return NUM_EVENTS if the event name was not found.
+ * Return a pointer to the next event name in "end".
+ */
+ static event_T
+event_name2nr(char_u *start, char_u **end)
+{
+ char_u *p;
+ int i;
+ int len;
+
+ // the event name ends with end of line, '|', a blank or a comma
+ for (p = start; *p && !VIM_ISWHITE(*p) && *p != ',' && *p != '|'; ++p)
+ ;
+ for (i = 0; event_names[i].name != NULL; ++i)
+ {
+ len = (int)STRLEN(event_names[i].name);
+ if (len == p - start && STRNICMP(event_names[i].name, start, len) == 0)
+ break;
+ }
+ if (*p == ',')
+ ++p;
+ *end = p;
+ if (event_names[i].name == NULL)
+ return NUM_EVENTS;
+ return event_names[i].event;
+}
+
+/*
+ * Return the name for event "event".
+ */
+ static char_u *
+event_nr2name(event_T event)
+{
+ int i;
+
+ for (i = 0; event_names[i].name != NULL; ++i)
+ if (event_names[i].event == event)
+ return (char_u *)event_names[i].name;
+ return (char_u *)"Unknown";
+}
+
+/*
+ * Scan over the events. "*" stands for all events.
+ */
+ static char_u *
+find_end_event(
+ char_u *arg,
+ int have_group) // TRUE when group name was found
+{
+ char_u *pat;
+ char_u *p;
+
+ if (*arg == '*')
+ {
+ if (arg[1] && !VIM_ISWHITE(arg[1]))
+ {
+ semsg(_("E215: Illegal character after *: %s"), arg);
+ return NULL;
+ }
+ pat = arg + 1;
+ }
+ else
+ {
+ for (pat = arg; *pat && *pat != '|' && !VIM_ISWHITE(*pat); pat = p)
+ {
+ if ((int)event_name2nr(pat, &p) >= (int)NUM_EVENTS)
+ {
+ if (have_group)
+ semsg(_("E216: No such event: %s"), pat);
+ else
+ semsg(_("E216: No such group or event: %s"), pat);
+ return NULL;
+ }
+ }
+ }
+ return pat;
+}
+
+/*
+ * Return TRUE if "event" is included in 'eventignore'.
+ */
+ static int
+event_ignored(event_T event)
+{
+ char_u *p = p_ei;
+
+ while (*p != NUL)
+ {
+ if (STRNICMP(p, "all", 3) == 0 && (p[3] == NUL || p[3] == ','))
+ return TRUE;
+ if (event_name2nr(p, &p) == event)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/*
+ * Return OK when the contents of p_ei is valid, FAIL otherwise.
+ */
+ int
+check_ei(void)
+{
+ char_u *p = p_ei;
+
+ while (*p)
+ {
+ if (STRNICMP(p, "all", 3) == 0 && (p[3] == NUL || p[3] == ','))
+ {
+ p += 3;
+ if (*p == ',')
+ ++p;
+ }
+ else if (event_name2nr(p, &p) == NUM_EVENTS)
+ return FAIL;
+ }
+
+ return OK;
+}
+
+# if defined(FEAT_SYN_HL) || defined(PROTO)
+
+/*
+ * Add "what" to 'eventignore' to skip loading syntax highlighting for every
+ * buffer loaded into the window. "what" must start with a comma.
+ * Returns the old value of 'eventignore' in allocated memory.
+ */
+ char_u *
+au_event_disable(char *what)
+{
+ char_u *new_ei;
+ char_u *save_ei;
+
+ save_ei = vim_strsave(p_ei);
+ if (save_ei != NULL)
+ {
+ new_ei = vim_strnsave(p_ei, (int)(STRLEN(p_ei) + STRLEN(what)));
+ if (new_ei != NULL)
+ {
+ if (*what == ',' && *p_ei == NUL)
+ STRCPY(new_ei, what + 1);
+ else
+ STRCAT(new_ei, what);
+ set_string_option_direct((char_u *)"ei", -1, new_ei,
+ OPT_FREE, SID_NONE);
+ vim_free(new_ei);
+ }
+ }
+ return save_ei;
+}
+
+ void
+au_event_restore(char_u *old_ei)
+{
+ if (old_ei != NULL)
+ {
+ set_string_option_direct((char_u *)"ei", -1, old_ei,
+ OPT_FREE, SID_NONE);
+ vim_free(old_ei);
+ }
+}
+# endif /* FEAT_SYN_HL */
+
+/*
+ * do_autocmd() -- implements the :autocmd command. Can be used in the
+ * following ways:
+ *
+ * :autocmd <event> <pat> <cmd> Add <cmd> to the list of commands that
+ * will be automatically executed for <event>
+ * when editing a file matching <pat>, in
+ * the current group.
+ * :autocmd <event> <pat> Show the autocommands associated with
+ * <event> and <pat>.
+ * :autocmd <event> Show the autocommands associated with
+ * <event>.
+ * :autocmd Show all autocommands.
+ * :autocmd! <event> <pat> <cmd> Remove all autocommands associated with
+ * <event> and <pat>, and add the command
+ * <cmd>, for the current group.
+ * :autocmd! <event> <pat> Remove all autocommands associated with
+ * <event> and <pat> for the current group.
+ * :autocmd! <event> Remove all autocommands associated with
+ * <event> for the current group.
+ * :autocmd! Remove ALL autocommands for the current
+ * group.
+ *
+ * Multiple events and patterns may be given separated by commas. Here are
+ * some examples:
+ * :autocmd bufread,bufenter *.c,*.h set tw=0 smartindent noic
+ * :autocmd bufleave * set tw=79 nosmartindent ic infercase
+ *
+ * :autocmd * *.c show all autocommands for *.c files.
+ *
+ * Mostly a {group} argument can optionally appear before <event>.
+ */
+ void
+do_autocmd(char_u *arg_in, int forceit)
+{
+ char_u *arg = arg_in;
+ char_u *pat;
+ char_u *envpat = NULL;
+ char_u *cmd;
+ event_T event;
+ int need_free = FALSE;
+ int nested = FALSE;
+ int group;
+
+ if (*arg == '|')
+ {
+ arg = (char_u *)"";
+ group = AUGROUP_ALL; // no argument, use all groups
+ }
+ else
+ {
+ /*
+ * Check for a legal group name. If not, use AUGROUP_ALL.
+ */
+ group = au_get_grouparg(&arg);
+ if (arg == NULL) // out of memory
+ return;
+ }
+
+ /*
+ * Scan over the events.
+ * If we find an illegal name, return here, don't do anything.
+ */
+ pat = find_end_event(arg, group != AUGROUP_ALL);
+ if (pat == NULL)
+ return;
+
+ pat = skipwhite(pat);
+ if (*pat == '|')
+ {
+ pat = (char_u *)"";
+ cmd = (char_u *)"";
+ }
+ else
+ {
+ /*
+ * Scan over the pattern. Put a NUL at the end.
+ */
+ cmd = pat;
+ while (*cmd && (!VIM_ISWHITE(*cmd) || cmd[-1] == '\\'))
+ cmd++;
+ if (*cmd)
+ *cmd++ = NUL;
+
+ // Expand environment variables in the pattern. Set 'shellslash', we
+ // want forward slashes here.
+ if (vim_strchr(pat, '$') != NULL || vim_strchr(pat, '~') != NULL)
+ {
+#ifdef BACKSLASH_IN_FILENAME
+ int p_ssl_save = p_ssl;
+
+ p_ssl = TRUE;
+#endif
+ envpat = expand_env_save(pat);
+#ifdef BACKSLASH_IN_FILENAME
+ p_ssl = p_ssl_save;
+#endif
+ if (envpat != NULL)
+ pat = envpat;
+ }
+
+ /*
+ * Check for "nested" flag.
+ */
+ cmd = skipwhite(cmd);
+ if (*cmd != NUL && STRNCMP(cmd, "nested", 6) == 0
+ && VIM_ISWHITE(cmd[6]))
+ {
+ nested = TRUE;
+ cmd = skipwhite(cmd + 6);
+ }
+
+ /*
+ * Find the start of the commands.
+ * Expand <sfile> in it.
+ */
+ if (*cmd != NUL)
+ {
+ cmd = expand_sfile(cmd);
+ if (cmd == NULL) // some error
+ return;
+ need_free = TRUE;
+ }
+ }
+
+ /*
+ * Print header when showing autocommands.
+ */
+ if (!forceit && *cmd == NUL)
+ // Highlight title
+ msg_puts_title(_("\n--- Autocommands ---"));
+
+ /*
+ * Loop over the events.
+ */
+ last_event = (event_T)-1; // for listing the event name
+ last_group = AUGROUP_ERROR; // for listing the group name
+ if (*arg == '*' || *arg == NUL || *arg == '|')
+ {
+ for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
+ event = (event_T)((int)event + 1))
+ if (do_autocmd_event(event, pat,
+ nested, cmd, forceit, group) == FAIL)
+ break;
+ }
+ else
+ {
+ while (*arg && *arg != '|' && !VIM_ISWHITE(*arg))
+ if (do_autocmd_event(event_name2nr(arg, &arg), pat,
+ nested, cmd, forceit, group) == FAIL)
+ break;
+ }
+
+ if (need_free)
+ vim_free(cmd);
+ vim_free(envpat);
+}
+
+/*
+ * Find the group ID in a ":autocmd" or ":doautocmd" argument.
+ * The "argp" argument is advanced to the following argument.
+ *
+ * Returns the group ID, AUGROUP_ERROR for error (out of memory).
+ */
+ static int
+au_get_grouparg(char_u **argp)
+{
+ char_u *group_name;
+ char_u *p;
+ char_u *arg = *argp;
+ int group = AUGROUP_ALL;
+
+ for (p = arg; *p && !VIM_ISWHITE(*p) && *p != '|'; ++p)
+ ;
+ if (p > arg)
+ {
+ group_name = vim_strnsave(arg, (int)(p - arg));
+ if (group_name == NULL) // out of memory
+ return AUGROUP_ERROR;
+ group = au_find_group(group_name);
+ if (group == AUGROUP_ERROR)
+ group = AUGROUP_ALL; // no match, use all groups
+ else
+ *argp = skipwhite(p); // match, skip over group name
+ vim_free(group_name);
+ }
+ return group;
+}
+
+/*
+ * do_autocmd() for one event.
+ * If *pat == NUL do for all patterns.
+ * If *cmd == NUL show entries.
+ * If forceit == TRUE delete entries.
+ * If group is not AUGROUP_ALL, only use this group.
+ */
+ static int
+do_autocmd_event(
+ event_T event,
+ char_u *pat,
+ int nested,
+ char_u *cmd,
+ int forceit,
+ int group)
+{
+ AutoPat *ap;
+ AutoPat **prev_ap;
+ AutoCmd *ac;
+ AutoCmd **prev_ac;
+ int brace_level;
+ char_u *endpat;
+ int findgroup;
+ int allgroups;
+ int patlen;
+ int is_buflocal;
+ int buflocal_nr;
+ char_u buflocal_pat[25]; /* for "<buffer=X>" */
+
+ if (group == AUGROUP_ALL)
+ findgroup = current_augroup;
+ else
+ findgroup = group;
+ allgroups = (group == AUGROUP_ALL && !forceit && *cmd == NUL);
+
+ /*
+ * Show or delete all patterns for an event.
+ */
+ if (*pat == NUL)
+ {
+ for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next)
+ {
+ if (forceit) // delete the AutoPat, if it's in the current group
+ {
+ if (ap->group == findgroup)
+ au_remove_pat(ap);
+ }
+ else if (group == AUGROUP_ALL || ap->group == group)
+ show_autocmd(ap, event);
+ }
+ }
+
+ /*
+ * Loop through all the specified patterns.
+ */
+ for ( ; *pat; pat = (*endpat == ',' ? endpat + 1 : endpat))
+ {
+ /*
+ * Find end of the pattern.
+ * Watch out for a comma in braces, like "*.\{obj,o\}".
+ */
+ brace_level = 0;
+ for (endpat = pat; *endpat && (*endpat != ',' || brace_level
+ || (endpat > pat && endpat[-1] == '\\')); ++endpat)
+ {
+ if (*endpat == '{')
+ brace_level++;
+ else if (*endpat == '}')
+ brace_level--;
+ }
+ if (pat == endpat) // ignore single comma
+ continue;
+ patlen = (int)(endpat - pat);
+
+ /*
+ * detect special <buflocal[=X]> buffer-local patterns
+ */
+ is_buflocal = FALSE;
+ buflocal_nr = 0;
+
+ if (patlen >= 8 && STRNCMP(pat, "<buffer", 7) == 0
+ && pat[patlen - 1] == '>')
+ {
+ // "<buffer...>": Error will be printed only for addition.
+ // printing and removing will proceed silently.
+ is_buflocal = TRUE;
+ if (patlen == 8)
+ // "<buffer>"
+ buflocal_nr = curbuf->b_fnum;
+ else if (patlen > 9 && pat[7] == '=')
+ {
+ if (patlen == 13 && STRNICMP(pat, "<buffer=abuf>", 13) == 0)
+ // "<buffer=abuf>"
+ buflocal_nr = autocmd_bufnr;
+ else if (skipdigits(pat + 8) == pat + patlen - 1)
+ // "<buffer=123>"
+ buflocal_nr = atoi((char *)pat + 8);
+ }
+ }
+
+ if (is_buflocal)
+ {
+ // normalize pat into standard "<buffer>#N" form
+ sprintf((char *)buflocal_pat, "<buffer=%d>", buflocal_nr);
+ pat = buflocal_pat; // can modify pat and patlen
+ patlen = (int)STRLEN(buflocal_pat); // but not endpat
+ }
+
+ /*
+ * Find AutoPat entries with this pattern. When adding a command it
+ * always goes at or after the last one, so start at the end.
+ */
+ if (!forceit && *cmd != NUL && last_autopat[(int)event] != NULL)
+ prev_ap = &last_autopat[(int)event];
+ else
+ prev_ap = &first_autopat[(int)event];
+ while ((ap = *prev_ap) != NULL)
+ {
+ if (ap->pat != NULL)
+ {
+ /* Accept a pattern when:
+ * - a group was specified and it's that group, or a group was
+ * not specified and it's the current group, or a group was
+ * not specified and we are listing
+ * - the length of the pattern matches
+ * - the pattern matches.
+ * For <buffer[=X]>, this condition works because we normalize
+ * all buffer-local patterns.
+ */
+ if ((allgroups || ap->group == findgroup)
+ && ap->patlen == patlen
+ && STRNCMP(pat, ap->pat, patlen) == 0)
+ {
+ /*
+ * Remove existing autocommands.
+ * If adding any new autocmd's for this AutoPat, don't
+ * delete the pattern from the autopat list, append to
+ * this list.
+ */
+ if (forceit)
+ {
+ if (*cmd != NUL && ap->next == NULL)
+ {
+ au_remove_cmds(ap);
+ break;
+ }
+ au_remove_pat(ap);
+ }
+
+ /*
+ * Show autocmd's for this autopat, or buflocals <buffer=X>
+ */
+ else if (*cmd == NUL)
+ show_autocmd(ap, event);
+
+ /*
+ * Add autocmd to this autopat, if it's the last one.
+ */
+ else if (ap->next == NULL)
+ break;
+ }
+ }
+ prev_ap = &ap->next;
+ }
+
+ /*
+ * Add a new command.
+ */
+ if (*cmd != NUL)
+ {
+ /*
+ * If the pattern we want to add a command to does appear at the
+ * end of the list (or not is not in the list at all), add the
+ * pattern at the end of the list.
+ */
+ if (ap == NULL)
+ {
+ /* refuse to add buffer-local ap if buffer number is invalid */
+ if (is_buflocal && (buflocal_nr == 0
+ || buflist_findnr(buflocal_nr) == NULL))
+ {
+ semsg(_("E680: <buffer=%d>: invalid buffer number "),
+ buflocal_nr);
+ return FAIL;
+ }
+
+ ap = (AutoPat *)alloc((unsigned)sizeof(AutoPat));
+ if (ap == NULL)
+ return FAIL;
+ ap->pat = vim_strnsave(pat, patlen);
+ ap->patlen = patlen;
+ if (ap->pat == NULL)
+ {
+ vim_free(ap);
+ return FAIL;
+ }
+
+ if (is_buflocal)
+ {
+ ap->buflocal_nr = buflocal_nr;
+ ap->reg_prog = NULL;
+ }
+ else
+ {
+ char_u *reg_pat;
+
+ ap->buflocal_nr = 0;
+ reg_pat = file_pat_to_reg_pat(pat, endpat,
+ &ap->allow_dirs, TRUE);
+ if (reg_pat != NULL)
+ ap->reg_prog = vim_regcomp(reg_pat, RE_MAGIC);
+ vim_free(reg_pat);
+ if (reg_pat == NULL || ap->reg_prog == NULL)
+ {
+ vim_free(ap->pat);
+ vim_free(ap);
+ return FAIL;
+ }
+ }
+ ap->cmds = NULL;
+ *prev_ap = ap;
+ last_autopat[(int)event] = ap;
+ ap->next = NULL;
+ if (group == AUGROUP_ALL)
+ ap->group = current_augroup;
+ else
+ ap->group = group;
+ }
+
+ /*
+ * Add the autocmd at the end of the AutoCmd list.
+ */
+ prev_ac = &(ap->cmds);
+ while ((ac = *prev_ac) != NULL)
+ prev_ac = &ac->next;
+ ac = (AutoCmd *)alloc((unsigned)sizeof(AutoCmd));
+ if (ac == NULL)
+ return FAIL;
+ ac->cmd = vim_strsave(cmd);
+#ifdef FEAT_EVAL
+ ac->script_ctx = current_sctx;
+ ac->script_ctx.sc_lnum += sourcing_lnum;
+#endif
+ if (ac->cmd == NULL)
+ {
+ vim_free(ac);
+ return FAIL;
+ }
+ ac->next = NULL;
+ *prev_ac = ac;
+ ac->nested = nested;
+ }
+ }
+
+ au_cleanup(); // may really delete removed patterns/commands now
+ return OK;
+}
+
+/*
+ * Implementation of ":doautocmd [group] event [fname]".
+ * Return OK for success, FAIL for failure;
+ */
+ int
+do_doautocmd(
+ char_u *arg,
+ int do_msg, // give message for no matching autocmds?
+ int *did_something)
+{
+ char_u *fname;
+ int nothing_done = TRUE;
+ int group;
+
+ if (did_something != NULL)
+ *did_something = FALSE;
+
+ /*
+ * Check for a legal group name. If not, use AUGROUP_ALL.
+ */
+ group = au_get_grouparg(&arg);
+ if (arg == NULL) // out of memory
+ return FAIL;
+
+ if (*arg == '*')
+ {
+ emsg(_("E217: Can't execute autocommands for ALL events"));
+ return FAIL;
+ }
+
+ /*
+ * Scan over the events.
+ * If we find an illegal name, return here, don't do anything.
+ */
+ fname = find_end_event(arg, group != AUGROUP_ALL);
+ if (fname == NULL)
+ return FAIL;
+
+ fname = skipwhite(fname);
+
+ /*
+ * Loop over the events.
+ */
+ while (*arg && !ends_excmd(*arg) && !VIM_ISWHITE(*arg))
+ if (apply_autocmds_group(event_name2nr(arg, &arg),
+ fname, NULL, TRUE, group, curbuf, NULL))
+ nothing_done = FALSE;
+
+ if (nothing_done && do_msg)
+ msg(_("No matching autocommands"));
+ if (did_something != NULL)
+ *did_something = !nothing_done;
+
+#ifdef FEAT_EVAL
+ return aborting() ? FAIL : OK;
+#else
+ return OK;
+#endif
+}
+
+/*
+ * ":doautoall": execute autocommands for each loaded buffer.
+ */
+ void
+ex_doautoall(exarg_T *eap)
+{
+ int retval;
+ aco_save_T aco;
+ buf_T *buf;
+ bufref_T bufref;
+ char_u *arg = eap->arg;
+ int call_do_modelines = check_nomodeline(&arg);
+ int did_aucmd;
+
+ /*
+ * This is a bit tricky: For some commands curwin->w_buffer needs to be
+ * equal to curbuf, but for some buffers there may not be a window.
+ * So we change the buffer for the current window for a moment. This
+ * gives problems when the autocommands make changes to the list of
+ * buffers or windows...
+ */
+ FOR_ALL_BUFFERS(buf)
+ {
+ if (buf->b_ml.ml_mfp != NULL)
+ {
+ // find a window for this buffer and save some values
+ aucmd_prepbuf(&aco, buf);
+ set_bufref(&bufref, buf);
+
+ // execute the autocommands for this buffer
+ retval = do_doautocmd(arg, FALSE, &did_aucmd);
+
+ if (call_do_modelines && did_aucmd)
+ {
+ // Execute the modeline settings, but don't set window-local
+ // options if we are using the current window for another
+ // buffer.
+ do_modelines(curwin == aucmd_win ? OPT_NOWIN : 0);
+ }
+
+ // restore the current window
+ aucmd_restbuf(&aco);
+
+ // stop if there is some error or buffer was deleted
+ if (retval == FAIL || !bufref_valid(&bufref))
+ break;
+ }
+ }
+
+ check_cursor(); // just in case lines got deleted
+}
+
+/*
+ * Check *argp for <nomodeline>. When it is present return FALSE, otherwise
+ * return TRUE and advance *argp to after it.
+ * Thus return TRUE when do_modelines() should be called.
+ */
+ int
+check_nomodeline(char_u **argp)
+{
+ if (STRNCMP(*argp, "<nomodeline>", 12) == 0)
+ {
+ *argp = skipwhite(*argp + 12);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*
+ * Prepare for executing autocommands for (hidden) buffer "buf".
+ * Search for a visible window containing the current buffer. If there isn't
+ * one then use "aucmd_win".
+ * Set "curbuf" and "curwin" to match "buf".
+ */
+ void
+aucmd_prepbuf(
+ aco_save_T *aco, // structure to save values in
+ buf_T *buf) // new curbuf
+{
+ win_T *win;
+ int save_ea;
+#ifdef FEAT_AUTOCHDIR
+ int save_acd;
+#endif
+
+ // Find a window that is for the new buffer
+ if (buf == curbuf) // be quick when buf is curbuf
+ win = curwin;
+ else
+ FOR_ALL_WINDOWS(win)
+ if (win->w_buffer == buf)
+ break;
+
+ // Allocate "aucmd_win" when needed. If this fails (out of memory) fall
+ // back to using the current window.
+ if (win == NULL && aucmd_win == NULL)
+ {
+ win_alloc_aucmd_win();
+ if (aucmd_win == NULL)
+ win = curwin;
+ }
+ if (win == NULL && aucmd_win_used)
+ // Strange recursive autocommand, fall back to using the current
+ // window. Expect a few side effects...
+ win = curwin;
+
+ aco->save_curwin = curwin;
+ aco->save_curbuf = curbuf;
+ aco->save_prevwin = prevwin;
+ if (win != NULL)
+ {
+ // There is a window for "buf" in the current tab page, make it the
+ // curwin. This is preferred, it has the least side effects (esp. if
+ // "buf" is curbuf).
+ aco->use_aucmd_win = FALSE;
+ curwin = win;
+ }
+ else
+ {
+ // There is no window for "buf", use "aucmd_win". To minimize the side
+ // effects, insert it in the current tab page.
+ // Anything related to a window (e.g., setting folds) may have
+ // unexpected results.
+ aco->use_aucmd_win = TRUE;
+ aucmd_win_used = TRUE;
+ aucmd_win->w_buffer = buf;
+#if defined(FEAT_SYN_HL) || defined(FEAT_SPELL)
+ aucmd_win->w_s = &buf->b_s;
+#endif
+ ++buf->b_nwindows;
+ win_init_empty(aucmd_win); // set cursor and topline to safe values
+
+ // Make sure w_localdir and globaldir are NULL to avoid a chdir() in
+ // win_enter_ext().
+ VIM_CLEAR(aucmd_win->w_localdir);
+ aco->globaldir = globaldir;
+ globaldir = NULL;
+
+
+ // Split the current window, put the aucmd_win in the upper half.
+ // We don't want the BufEnter or WinEnter autocommands.
+ block_autocmds();
+ make_snapshot(SNAP_AUCMD_IDX);
+ save_ea = p_ea;
+ p_ea = FALSE;
+
+#ifdef FEAT_AUTOCHDIR
+ // Prevent chdir() call in win_enter_ext(), through do_autochdir().
+ save_acd = p_acd;
+ p_acd = FALSE;
+#endif
+
+ (void)win_split_ins(0, WSP_TOP, aucmd_win, 0);
+ (void)win_comp_pos(); // recompute window positions
+ p_ea = save_ea;
+#ifdef FEAT_AUTOCHDIR
+ p_acd = save_acd;
+#endif
+ unblock_autocmds();
+ curwin = aucmd_win;
+ }
+ curbuf = buf;
+ aco->new_curwin = curwin;
+ set_bufref(&aco->new_curbuf, curbuf);
+}
+
+/*
+ * Cleanup after executing autocommands for a (hidden) buffer.
+ * Restore the window as it was (if possible).
+ */
+ void
+aucmd_restbuf(
+ aco_save_T *aco) // structure holding saved values
+{
+ int dummy;
+
+ if (aco->use_aucmd_win)
+ {
+ --curbuf->b_nwindows;
+ // Find "aucmd_win", it can't be closed, but it may be in another tab
+ // page. Do not trigger autocommands here.
+ block_autocmds();
+ if (curwin != aucmd_win)
+ {
+ tabpage_T *tp;
+ win_T *wp;
+
+ FOR_ALL_TAB_WINDOWS(tp, wp)
+ {
+ if (wp == aucmd_win)
+ {
+ if (tp != curtab)
+ goto_tabpage_tp(tp, TRUE, TRUE);
+ win_goto(aucmd_win);
+ goto win_found;
+ }
+ }
+ }
+win_found:
+
+ // Remove the window and frame from the tree of frames.
+ (void)winframe_remove(curwin, &dummy, NULL);
+ win_remove(curwin, NULL);
+ aucmd_win_used = FALSE;
+ last_status(FALSE); // may need to remove last status line
+
+ if (!valid_tabpage_win(curtab))
+ // no valid window in current tabpage
+ close_tabpage(curtab);
+
+ restore_snapshot(SNAP_AUCMD_IDX, FALSE);
+ (void)win_comp_pos(); // recompute window positions
+ unblock_autocmds();
+
+ if (win_valid(aco->save_curwin))
+ curwin = aco->save_curwin;
+ else
+ // Hmm, original window disappeared. Just use the first one.
+ curwin = firstwin;
+ if (win_valid(aco->save_prevwin))
+ prevwin = aco->save_prevwin;
+#ifdef FEAT_EVAL
+ vars_clear(&aucmd_win->w_vars->dv_hashtab); // free all w: variables
+ hash_init(&aucmd_win->w_vars->dv_hashtab); // re-use the hashtab
+#endif
+ curbuf = curwin->w_buffer;
+
+ vim_free(globaldir);
+ globaldir = aco->globaldir;
+
+ // the buffer contents may have changed
+ check_cursor();
+ if (curwin->w_topline > curbuf->b_ml.ml_line_count)
+ {
+ curwin->w_topline = curbuf->b_ml.ml_line_count;
+#ifdef FEAT_DIFF
+ curwin->w_topfill = 0;
+#endif
+ }
+#if defined(FEAT_GUI)
+ // Hide the scrollbars from the aucmd_win and update.
+ gui_mch_enable_scrollbar(&aucmd_win->w_scrollbars[SBAR_LEFT], FALSE);
+ gui_mch_enable_scrollbar(&aucmd_win->w_scrollbars[SBAR_RIGHT], FALSE);
+ gui_may_update_scrollbars();
+#endif
+ }
+ else
+ {
+ // restore curwin
+ if (win_valid(aco->save_curwin))
+ {
+ // Restore the buffer which was previously edited by curwin, if
+ // it was changed, we are still the same window and the buffer is
+ // valid.
+ if (curwin == aco->new_curwin
+ && curbuf != aco->new_curbuf.br_buf
+ && bufref_valid(&aco->new_curbuf)
+ && aco->new_curbuf.br_buf->b_ml.ml_mfp != NULL)
+ {
+# if defined(FEAT_SYN_HL) || defined(FEAT_SPELL)
+ if (curwin->w_s == &curbuf->b_s)
+ curwin->w_s = &aco->new_curbuf.br_buf->b_s;
+# endif
+ --curbuf->b_nwindows;
+ curbuf = aco->new_curbuf.br_buf;
+ curwin->w_buffer = curbuf;
+ ++curbuf->b_nwindows;
+ }
+
+ curwin = aco->save_curwin;
+ curbuf = curwin->w_buffer;
+ if (win_valid(aco->save_prevwin))
+ prevwin = aco->save_prevwin;
+ // In case the autocommand move the cursor to a position that that
+ // not exist in curbuf.
+ check_cursor();
+ }
+ }
+}
+
+static int autocmd_nested = FALSE;
+
+/*
+ * Execute autocommands for "event" and file name "fname".
+ * Return TRUE if some commands were executed.
+ */
+ int
+apply_autocmds(
+ event_T event,
+ char_u *fname, // NULL or empty means use actual file name
+ char_u *fname_io, // fname to use for <afile> on cmdline
+ int force, // when TRUE, ignore autocmd_busy
+ buf_T *buf) // buffer for <abuf>
+{
+ return apply_autocmds_group(event, fname, fname_io, force,
+ AUGROUP_ALL, buf, NULL);
+}
+
+/*
+ * Like apply_autocmds(), but with extra "eap" argument. This takes care of
+ * setting v:filearg.
+ */
+ int
+apply_autocmds_exarg(
+ event_T event,
+ char_u *fname,
+ char_u *fname_io,
+ int force,
+ buf_T *buf,
+ exarg_T *eap)
+{
+ return apply_autocmds_group(event, fname, fname_io, force,
+ AUGROUP_ALL, buf, eap);
+}
+
+/*
+ * Like apply_autocmds(), but handles the caller's retval. If the script
+ * processing is being aborted or if retval is FAIL when inside a try
+ * conditional, no autocommands are executed. If otherwise the autocommands
+ * cause the script to be aborted, retval is set to FAIL.
+ */
+ int
+apply_autocmds_retval(
+ event_T event,
+ char_u *fname, // NULL or empty means use actual file name
+ char_u *fname_io, // fname to use for <afile> on cmdline
+ int force, // when TRUE, ignore autocmd_busy
+ buf_T *buf, // buffer for <abuf>
+ int *retval) // pointer to caller's retval
+{
+ int did_cmd;
+
+#ifdef FEAT_EVAL
+ if (should_abort(*retval))
+ return FALSE;
+#endif
+
+ did_cmd = apply_autocmds_group(event, fname, fname_io, force,
+ AUGROUP_ALL, buf, NULL);
+ if (did_cmd
+#ifdef FEAT_EVAL
+ && aborting()
+#endif
+ )
+ *retval = FAIL;
+ return did_cmd;
+}
+
+/*
+ * Return TRUE when there is a CursorHold autocommand defined.
+ */
+ int
+has_cursorhold(void)
+{
+ return (first_autopat[(int)(get_real_state() == NORMAL_BUSY
+ ? EVENT_CURSORHOLD : EVENT_CURSORHOLDI)] != NULL);
+}
+
+/*
+ * Return TRUE if the CursorHold event can be triggered.
+ */
+ int
+trigger_cursorhold(void)
+{
+ int state;
+
+ if (!did_cursorhold
+ && has_cursorhold()
+ && reg_recording == 0
+ && typebuf.tb_len == 0
+#ifdef FEAT_INS_EXPAND
+ && !ins_compl_active()
+#endif
+ )
+ {
+ state = get_real_state();
+ if (state == NORMAL_BUSY || (state & INSERT) != 0)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * Return TRUE when there is a CursorMoved autocommand defined.
+ */
+ int
+has_cursormoved(void)
+{
+ return (first_autopat[(int)EVENT_CURSORMOVED] != NULL);
+}
+
+#if defined(FEAT_CONCEAL) || defined(PROTO)
+/*
+ * Return TRUE when there is a CursorMovedI autocommand defined.
+ */
+ int
+has_cursormovedI(void)
+{
+ return (first_autopat[(int)EVENT_CURSORMOVEDI] != NULL);
+}
+#endif
+
+/*
+ * Return TRUE when there is a TextChanged autocommand defined.
+ */
+ int
+has_textchanged(void)
+{
+ return (first_autopat[(int)EVENT_TEXTCHANGED] != NULL);
+}
+
+/*
+ * Return TRUE when there is a TextChangedI autocommand defined.
+ */
+ int
+has_textchangedI(void)
+{
+ return (first_autopat[(int)EVENT_TEXTCHANGEDI] != NULL);
+}
+
+#if defined(FEAT_INS_EXPAND) || defined(PROTO)
+/*
+ * Return TRUE when there is a TextChangedP autocommand defined.
+ */
+ int
+has_textchangedP(void)
+{
+ return (first_autopat[(int)EVENT_TEXTCHANGEDP] != NULL);
+}
+#endif
+
+/*
+ * Return TRUE when there is an InsertCharPre autocommand defined.
+ */
+ int
+has_insertcharpre(void)
+{
+ return (first_autopat[(int)EVENT_INSERTCHARPRE] != NULL);
+}
+
+/*
+ * Return TRUE when there is an CmdUndefined autocommand defined.
+ */
+ int
+has_cmdundefined(void)
+{
+ return (first_autopat[(int)EVENT_CMDUNDEFINED] != NULL);
+}
+
+/*
+ * Return TRUE when there is an FuncUndefined autocommand defined.
+ */
+ int
+has_funcundefined(void)
+{
+ return (first_autopat[(int)EVENT_FUNCUNDEFINED] != NULL);
+}
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * Return TRUE when there is a TextYankPost autocommand defined.
+ */
+ int
+has_textyankpost(void)
+{
+ return (first_autopat[(int)EVENT_TEXTYANKPOST] != NULL);
+}
+#endif
+
+/*
+ * Execute autocommands for "event" and file name "fname".
+ * Return TRUE if some commands were executed.
+ */
+ static int
+apply_autocmds_group(
+ event_T event,
+ char_u *fname, // NULL or empty means use actual file name
+ char_u *fname_io, // fname to use for <afile> on cmdline, NULL means
+ // use fname
+ int force, // when TRUE, ignore autocmd_busy
+ int group, // group ID, or AUGROUP_ALL
+ buf_T *buf, // buffer for <abuf>
+ exarg_T *eap UNUSED) // command arguments
+{
+ char_u *sfname = NULL; // short file name
+ char_u *tail;
+ int save_changed;
+ buf_T *old_curbuf;
+ int retval = FALSE;
+ char_u *save_sourcing_name;
+ linenr_T save_sourcing_lnum;
+ char_u *save_autocmd_fname;
+ int save_autocmd_fname_full;
+ int save_autocmd_bufnr;
+ char_u *save_autocmd_match;
+ int save_autocmd_busy;
+ int save_autocmd_nested;
+ static int nesting = 0;
+ AutoPatCmd patcmd;
+ AutoPat *ap;
+#ifdef FEAT_EVAL
+ sctx_T save_current_sctx;
+ funccal_entry_T funccal_entry;
+ char_u *save_cmdarg;
+ long save_cmdbang;
+#endif
+ static int filechangeshell_busy = FALSE;
+#ifdef FEAT_PROFILE
+ proftime_T wait_time;
+#endif
+ int did_save_redobuff = FALSE;
+ save_redo_T save_redo;
+ int save_KeyTyped = KeyTyped;
+
+ /*
+ * Quickly return if there are no autocommands for this event or
+ * autocommands are blocked.
+ */
+ if (event == NUM_EVENTS || first_autopat[(int)event] == NULL
+ || autocmd_blocked > 0)
+ goto BYPASS_AU;
+
+ /*
+ * When autocommands are busy, new autocommands are only executed when
+ * explicitly enabled with the "nested" flag.
+ */
+ if (autocmd_busy && !(force || autocmd_nested))
+ goto BYPASS_AU;
+
+#ifdef FEAT_EVAL
+ /*
+ * Quickly return when immediately aborting on error, or when an interrupt
+ * occurred or an exception was thrown but not caught.
+ */
+ if (aborting())
+ goto BYPASS_AU;
+#endif
+
+ /*
+ * FileChangedShell never nests, because it can create an endless loop.
+ */
+ if (filechangeshell_busy && (event == EVENT_FILECHANGEDSHELL
+ || event == EVENT_FILECHANGEDSHELLPOST))
+ goto BYPASS_AU;
+
+ /*
+ * Ignore events in 'eventignore'.
+ */
+ if (event_ignored(event))
+ goto BYPASS_AU;
+
+ /*
+ * Allow nesting of autocommands, but restrict the depth, because it's
+ * possible to create an endless loop.
+ */
+ if (nesting == 10)
+ {
+ emsg(_("E218: autocommand nesting too deep"));
+ goto BYPASS_AU;
+ }
+
+ /*
+ * Check if these autocommands are disabled. Used when doing ":all" or
+ * ":ball".
+ */
+ if ( (autocmd_no_enter
+ && (event == EVENT_WINENTER || event == EVENT_BUFENTER))
+ || (autocmd_no_leave
+ && (event == EVENT_WINLEAVE || event == EVENT_BUFLEAVE)))
+ goto BYPASS_AU;
+
+ /*
+ * Save the autocmd_* variables and info about the current buffer.
+ */
+ save_autocmd_fname = autocmd_fname;
+ save_autocmd_fname_full = autocmd_fname_full;
+ save_autocmd_bufnr = autocmd_bufnr;
+ save_autocmd_match = autocmd_match;
+ save_autocmd_busy = autocmd_busy;
+ save_autocmd_nested = autocmd_nested;
+ save_changed = curbuf->b_changed;
+ old_curbuf = curbuf;
+
+ /*
+ * Set the file name to be used for <afile>.
+ * Make a copy to avoid that changing a buffer name or directory makes it
+ * invalid.
+ */
+ if (fname_io == NULL)
+ {
+ if (event == EVENT_COLORSCHEME || event == EVENT_COLORSCHEMEPRE
+ || event == EVENT_OPTIONSET)
+ autocmd_fname = NULL;
+ else if (fname != NULL && !ends_excmd(*fname))
+ autocmd_fname = fname;
+ else if (buf != NULL)
+ autocmd_fname = buf->b_ffname;
+ else
+ autocmd_fname = NULL;
+ }
+ else
+ autocmd_fname = fname_io;
+ if (autocmd_fname != NULL)
+ autocmd_fname = vim_strsave(autocmd_fname);
+ autocmd_fname_full = FALSE; // call FullName_save() later
+
+ /*
+ * Set the buffer number to be used for <abuf>.
+ */
+ if (buf == NULL)
+ autocmd_bufnr = 0;
+ else
+ autocmd_bufnr = buf->b_fnum;
+
+ /*
+ * When the file name is NULL or empty, use the file name of buffer "buf".
+ * Always use the full path of the file name to match with, in case
+ * "allow_dirs" is set.
+ */
+ if (fname == NULL || *fname == NUL)
+ {
+ if (buf == NULL)
+ fname = NULL;
+ else
+ {
+#ifdef FEAT_SYN_HL
+ if (event == EVENT_SYNTAX)
+ fname = buf->b_p_syn;
+ else
+#endif
+ if (event == EVENT_FILETYPE)
+ fname = buf->b_p_ft;
+ else
+ {
+ if (buf->b_sfname != NULL)
+ sfname = vim_strsave(buf->b_sfname);
+ fname = buf->b_ffname;
+ }
+ }
+ if (fname == NULL)
+ fname = (char_u *)"";
+ fname = vim_strsave(fname); // make a copy, so we can change it
+ }
+ else
+ {
+ sfname = vim_strsave(fname);
+ // Don't try expanding FileType, Syntax, FuncUndefined, WindowID,
+ // ColorScheme, QuickFixCmd* or DirChanged
+ if (event == EVENT_FILETYPE
+ || event == EVENT_SYNTAX
+ || event == EVENT_CMDLINECHANGED
+ || event == EVENT_CMDLINEENTER
+ || event == EVENT_CMDLINELEAVE
+ || event == EVENT_CMDWINENTER
+ || event == EVENT_CMDWINLEAVE
+ || event == EVENT_CMDUNDEFINED
+ || event == EVENT_FUNCUNDEFINED
+ || event == EVENT_REMOTEREPLY
+ || event == EVENT_SPELLFILEMISSING
+ || event == EVENT_QUICKFIXCMDPRE
+ || event == EVENT_COLORSCHEME
+ || event == EVENT_COLORSCHEMEPRE
+ || event == EVENT_OPTIONSET
+ || event == EVENT_QUICKFIXCMDPOST
+ || event == EVENT_DIRCHANGED)
+ {
+ fname = vim_strsave(fname);
+ autocmd_fname_full = TRUE; // don't expand it later
+ }
+ else
+ fname = FullName_save(fname, FALSE);
+ }
+ if (fname == NULL) // out of memory
+ {
+ vim_free(sfname);
+ retval = FALSE;
+ goto BYPASS_AU;
+ }
+
+#ifdef BACKSLASH_IN_FILENAME
+ /*
+ * Replace all backslashes with forward slashes. This makes the
+ * autocommand patterns portable between Unix and MS-DOS.
+ */
+ if (sfname != NULL)
+ forward_slash(sfname);
+ forward_slash(fname);
+#endif
+
+#ifdef VMS
+ // remove version for correct match
+ if (sfname != NULL)
+ vms_remove_version(sfname);
+ vms_remove_version(fname);
+#endif
+
+ /*
+ * Set the name to be used for <amatch>.
+ */
+ autocmd_match = fname;
+
+
+ // Don't redraw while doing autocommands.
+ ++RedrawingDisabled;
+ save_sourcing_name = sourcing_name;
+ sourcing_name = NULL; // don't free this one
+ save_sourcing_lnum = sourcing_lnum;
+ sourcing_lnum = 0; // no line number here
+
+#ifdef FEAT_EVAL
+ save_current_sctx = current_sctx;
+
+# ifdef FEAT_PROFILE
+ if (do_profiling == PROF_YES)
+ prof_child_enter(&wait_time); // doesn't count for the caller itself
+# endif
+
+ // Don't use local function variables, if called from a function.
+ save_funccal(&funccal_entry);
+#endif
+
+ /*
+ * When starting to execute autocommands, save the search patterns.
+ */
+ if (!autocmd_busy)
+ {
+ save_search_patterns();
+#ifdef FEAT_INS_EXPAND
+ if (!ins_compl_active())
+#endif
+ {
+ saveRedobuff(&save_redo);
+ did_save_redobuff = TRUE;
+ }
+ did_filetype = keep_filetype;
+ }
+
+ /*
+ * Note that we are applying autocmds. Some commands need to know.
+ */
+ autocmd_busy = TRUE;
+ filechangeshell_busy = (event == EVENT_FILECHANGEDSHELL);
+ ++nesting; // see matching decrement below
+
+ // Remember that FileType was triggered. Used for did_filetype().
+ if (event == EVENT_FILETYPE)
+ did_filetype = TRUE;
+
+ tail = gettail(fname);
+
+ // Find first autocommand that matches
+ patcmd.curpat = first_autopat[(int)event];
+ patcmd.nextcmd = NULL;
+ patcmd.group = group;
+ patcmd.fname = fname;
+ patcmd.sfname = sfname;
+ patcmd.tail = tail;
+ patcmd.event = event;
+ patcmd.arg_bufnr = autocmd_bufnr;
+ patcmd.next = NULL;
+ auto_next_pat(&patcmd, FALSE);
+
+ // found one, start executing the autocommands
+ if (patcmd.curpat != NULL)
+ {
+ // add to active_apc_list
+ patcmd.next = active_apc_list;
+ active_apc_list = &patcmd;
+
+#ifdef FEAT_EVAL
+ // set v:cmdarg (only when there is a matching pattern)
+ save_cmdbang = (long)get_vim_var_nr(VV_CMDBANG);
+ if (eap != NULL)
+ {
+ save_cmdarg = set_cmdarg(eap, NULL);
+ set_vim_var_nr(VV_CMDBANG, (long)eap->forceit);
+ }
+ else
+ save_cmdarg = NULL; // avoid gcc warning
+#endif
+ retval = TRUE;
+ // mark the last pattern, to avoid an endless loop when more patterns
+ // are added when executing autocommands
+ for (ap = patcmd.curpat; ap->next != NULL; ap = ap->next)
+ ap->last = FALSE;
+ ap->last = TRUE;
+ check_lnums(TRUE); // make sure cursor and topline are valid
+ do_cmdline(NULL, getnextac, (void *)&patcmd,
+ DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT);
+#ifdef FEAT_EVAL
+ if (eap != NULL)
+ {
+ (void)set_cmdarg(NULL, save_cmdarg);
+ set_vim_var_nr(VV_CMDBANG, save_cmdbang);
+ }
+#endif
+ // delete from active_apc_list
+ if (active_apc_list == &patcmd) // just in case
+ active_apc_list = patcmd.next;
+ }
+
+ --RedrawingDisabled;
+ autocmd_busy = save_autocmd_busy;
+ filechangeshell_busy = FALSE;
+ autocmd_nested = save_autocmd_nested;
+ vim_free(sourcing_name);
+ sourcing_name = save_sourcing_name;
+ sourcing_lnum = save_sourcing_lnum;
+ vim_free(autocmd_fname);
+ autocmd_fname = save_autocmd_fname;
+ autocmd_fname_full = save_autocmd_fname_full;
+ autocmd_bufnr = save_autocmd_bufnr;
+ autocmd_match = save_autocmd_match;
+#ifdef FEAT_EVAL
+ current_sctx = save_current_sctx;
+ restore_funccal();
+# ifdef FEAT_PROFILE
+ if (do_profiling == PROF_YES)
+ prof_child_exit(&wait_time);
+# endif
+#endif
+ KeyTyped = save_KeyTyped;
+ vim_free(fname);
+ vim_free(sfname);
+ --nesting; // see matching increment above
+
+ /*
+ * When stopping to execute autocommands, restore the search patterns and
+ * the redo buffer. Free any buffers in the au_pending_free_buf list and
+ * free any windows in the au_pending_free_win list.
+ */
+ if (!autocmd_busy)
+ {
+ restore_search_patterns();
+ if (did_save_redobuff)
+ restoreRedobuff(&save_redo);
+ did_filetype = FALSE;
+ while (au_pending_free_buf != NULL)
+ {
+ buf_T *b = au_pending_free_buf->b_next;
+ vim_free(au_pending_free_buf);
+ au_pending_free_buf = b;
+ }
+ while (au_pending_free_win != NULL)
+ {
+ win_T *w = au_pending_free_win->w_next;
+ vim_free(au_pending_free_win);
+ au_pending_free_win = w;
+ }
+ }
+
+ /*
+ * Some events don't set or reset the Changed flag.
+ * Check if still in the same buffer!
+ */
+ if (curbuf == old_curbuf
+ && (event == EVENT_BUFREADPOST
+ || event == EVENT_BUFWRITEPOST
+ || event == EVENT_FILEAPPENDPOST
+ || event == EVENT_VIMLEAVE
+ || event == EVENT_VIMLEAVEPRE))
+ {
+#ifdef FEAT_TITLE
+ if (curbuf->b_changed != save_changed)
+ need_maketitle = TRUE;
+#endif
+ curbuf->b_changed = save_changed;
+ }
+
+ au_cleanup(); // may really delete removed patterns/commands now
+
+BYPASS_AU:
+ // When wiping out a buffer make sure all its buffer-local autocommands
+ // are deleted.
+ if (event == EVENT_BUFWIPEOUT && buf != NULL)
+ aubuflocal_remove(buf);
+
+ if (retval == OK && event == EVENT_FILETYPE)
+ au_did_filetype = TRUE;
+
+ return retval;
+}
+
+# ifdef FEAT_EVAL
+static char_u *old_termresponse = NULL;
+# endif
+
+/*
+ * Block triggering autocommands until unblock_autocmd() is called.
+ * Can be used recursively, so long as it's symmetric.
+ */
+ void
+block_autocmds(void)
+{
+# ifdef FEAT_EVAL
+ // Remember the value of v:termresponse.
+ if (autocmd_blocked == 0)
+ old_termresponse = get_vim_var_str(VV_TERMRESPONSE);
+# endif
+ ++autocmd_blocked;
+}
+
+ void
+unblock_autocmds(void)
+{
+ --autocmd_blocked;
+
+# ifdef FEAT_EVAL
+ // When v:termresponse was set while autocommands were blocked, trigger
+ // the autocommands now. Esp. useful when executing a shell command
+ // during startup (vimdiff).
+ if (autocmd_blocked == 0
+ && get_vim_var_str(VV_TERMRESPONSE) != old_termresponse)
+ apply_autocmds(EVENT_TERMRESPONSE, NULL, NULL, FALSE, curbuf);
+# endif
+}
+
+#if defined(FEAT_EVAL) && (defined(FEAT_XIM) || defined(IME_WITHOUT_XIM)) \
+ || defined(PROTO)
+ int
+is_autocmd_blocked(void)
+{
+ return autocmd_blocked != 0;
+}
+#endif
+
+/*
+ * Find next autocommand pattern that matches.
+ */
+ static void
+auto_next_pat(
+ AutoPatCmd *apc,
+ int stop_at_last) // stop when 'last' flag is set
+{
+ AutoPat *ap;
+ AutoCmd *cp;
+ char_u *name;
+ char *s;
+
+ VIM_CLEAR(sourcing_name);
+
+ for (ap = apc->curpat; ap != NULL && !got_int; ap = ap->next)
+ {
+ apc->curpat = NULL;
+
+ // Only use a pattern when it has not been removed, has commands and
+ // the group matches. For buffer-local autocommands only check the
+ // buffer number.
+ if (ap->pat != NULL && ap->cmds != NULL
+ && (apc->group == AUGROUP_ALL || apc->group == ap->group))
+ {
+ // execution-condition
+ if (ap->buflocal_nr == 0
+ ? (match_file_pat(NULL, &ap->reg_prog, apc->fname,
+ apc->sfname, apc->tail, ap->allow_dirs))
+ : ap->buflocal_nr == apc->arg_bufnr)
+ {
+ name = event_nr2name(apc->event);
+ s = _("%s Autocommands for \"%s\"");
+ sourcing_name = alloc((unsigned)(STRLEN(s)
+ + STRLEN(name) + ap->patlen + 1));
+ if (sourcing_name != NULL)
+ {
+ sprintf((char *)sourcing_name, s,
+ (char *)name, (char *)ap->pat);
+ if (p_verbose >= 8)
+ {
+ verbose_enter();
+ smsg(_("Executing %s"), sourcing_name);
+ verbose_leave();
+ }
+ }
+
+ apc->curpat = ap;
+ apc->nextcmd = ap->cmds;
+ // mark last command
+ for (cp = ap->cmds; cp->next != NULL; cp = cp->next)
+ cp->last = FALSE;
+ cp->last = TRUE;
+ }
+ line_breakcheck();
+ if (apc->curpat != NULL) // found a match
+ break;
+ }
+ if (stop_at_last && ap->last)
+ break;
+ }
+}
+
+/*
+ * Get next autocommand command.
+ * Called by do_cmdline() to get the next line for ":if".
+ * Returns allocated string, or NULL for end of autocommands.
+ */
+ char_u *
+getnextac(int c UNUSED, void *cookie, int indent UNUSED)
+{
+ AutoPatCmd *acp = (AutoPatCmd *)cookie;
+ char_u *retval;
+ AutoCmd *ac;
+
+ // Can be called again after returning the last line.
+ if (acp->curpat == NULL)
+ return NULL;
+
+ // repeat until we find an autocommand to execute
+ for (;;)
+ {
+ // skip removed commands
+ while (acp->nextcmd != NULL && acp->nextcmd->cmd == NULL)
+ if (acp->nextcmd->last)
+ acp->nextcmd = NULL;
+ else
+ acp->nextcmd = acp->nextcmd->next;
+
+ if (acp->nextcmd != NULL)
+ break;
+
+ // at end of commands, find next pattern that matches
+ if (acp->curpat->last)
+ acp->curpat = NULL;
+ else
+ acp->curpat = acp->curpat->next;
+ if (acp->curpat != NULL)
+ auto_next_pat(acp, TRUE);
+ if (acp->curpat == NULL)
+ return NULL;
+ }
+
+ ac = acp->nextcmd;
+
+ if (p_verbose >= 9)
+ {
+ verbose_enter_scroll();
+ smsg(_("autocommand %s"), ac->cmd);
+ msg_puts("\n"); // don't overwrite this either
+ verbose_leave_scroll();
+ }
+ retval = vim_strsave(ac->cmd);
+ autocmd_nested = ac->nested;
+#ifdef FEAT_EVAL
+ current_sctx = ac->script_ctx;
+#endif
+ if (ac->last)
+ acp->nextcmd = NULL;
+ else
+ acp->nextcmd = ac->next;
+ return retval;
+}
+
+/*
+ * Return TRUE if there is a matching autocommand for "fname".
+ * To account for buffer-local autocommands, function needs to know
+ * in which buffer the file will be opened.
+ */
+ int
+has_autocmd(event_T event, char_u *sfname, buf_T *buf)
+{
+ AutoPat *ap;
+ char_u *fname;
+ char_u *tail = gettail(sfname);
+ int retval = FALSE;
+
+ fname = FullName_save(sfname, FALSE);
+ if (fname == NULL)
+ return FALSE;
+
+#ifdef BACKSLASH_IN_FILENAME
+ /*
+ * Replace all backslashes with forward slashes. This makes the
+ * autocommand patterns portable between Unix and MS-DOS.
+ */
+ sfname = vim_strsave(sfname);
+ if (sfname != NULL)
+ forward_slash(sfname);
+ forward_slash(fname);
+#endif
+
+ for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next)
+ if (ap->pat != NULL && ap->cmds != NULL
+ && (ap->buflocal_nr == 0
+ ? match_file_pat(NULL, &ap->reg_prog,
+ fname, sfname, tail, ap->allow_dirs)
+ : buf != NULL && ap->buflocal_nr == buf->b_fnum
+ ))
+ {
+ retval = TRUE;
+ break;
+ }
+
+ vim_free(fname);
+#ifdef BACKSLASH_IN_FILENAME
+ vim_free(sfname);
+#endif
+
+ return retval;
+}
+
+#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
+/*
+ * Function given to ExpandGeneric() to obtain the list of autocommand group
+ * names.
+ */
+ char_u *
+get_augroup_name(expand_T *xp UNUSED, int idx)
+{
+ if (idx == augroups.ga_len) // add "END" add the end
+ return (char_u *)"END";
+ if (idx >= augroups.ga_len) // end of list
+ return NULL;
+ if (AUGROUP_NAME(idx) == NULL || AUGROUP_NAME(idx) == get_deleted_augroup())
+ // skip deleted entries
+ return (char_u *)"";
+ return AUGROUP_NAME(idx); // return a name
+}
+
+static int include_groups = FALSE;
+
+ char_u *
+set_context_in_autocmd(
+ expand_T *xp,
+ char_u *arg,
+ int doautocmd) // TRUE for :doauto*, FALSE for :autocmd
+{
+ char_u *p;
+ int group;
+
+ // check for a group name, skip it if present
+ include_groups = FALSE;
+ p = arg;
+ group = au_get_grouparg(&arg);
+ if (group == AUGROUP_ERROR)
+ return NULL;
+ // If there only is a group name that's what we expand.
+ if (*arg == NUL && group != AUGROUP_ALL && !VIM_ISWHITE(arg[-1]))
+ {
+ arg = p;
+ group = AUGROUP_ALL;
+ }
+
+ // skip over event name
+ for (p = arg; *p != NUL && !VIM_ISWHITE(*p); ++p)
+ if (*p == ',')
+ arg = p + 1;
+ if (*p == NUL)
+ {
+ if (group == AUGROUP_ALL)
+ include_groups = TRUE;
+ xp->xp_context = EXPAND_EVENTS; // expand event name
+ xp->xp_pattern = arg;
+ return NULL;
+ }
+
+ // skip over pattern
+ arg = skipwhite(p);
+ while (*arg && (!VIM_ISWHITE(*arg) || arg[-1] == '\\'))
+ arg++;
+ if (*arg)
+ return arg; // expand (next) command
+
+ if (doautocmd)
+ xp->xp_context = EXPAND_FILES; // expand file names
+ else
+ xp->xp_context = EXPAND_NOTHING; // pattern is not expanded
+ return NULL;
+}
+
+/*
+ * Function given to ExpandGeneric() to obtain the list of event names.
+ */
+ char_u *
+get_event_name(expand_T *xp UNUSED, int idx)
+{
+ if (idx < augroups.ga_len) // First list group names, if wanted
+ {
+ if (!include_groups || AUGROUP_NAME(idx) == NULL
+ || AUGROUP_NAME(idx) == get_deleted_augroup())
+ return (char_u *)""; // skip deleted entries
+ return AUGROUP_NAME(idx); // return a name
+ }
+ return (char_u *)event_names[idx - augroups.ga_len].name;
+}
+
+#endif // FEAT_CMDL_COMPL
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * Return TRUE if autocmd is supported.
+ */
+ int
+autocmd_supported(char_u *name)
+{
+ char_u *p;
+
+ return (event_name2nr(name, &p) != NUM_EVENTS);
+}
+
+/*
+ * Return TRUE if an autocommand is defined for a group, event and
+ * pattern: The group can be omitted to accept any group. "event" and "pattern"
+ * can be NULL to accept any event and pattern. "pattern" can be NULL to accept
+ * any pattern. Buffer-local patterns <buffer> or <buffer=N> are accepted.
+ * Used for:
+ * exists("#Group") or
+ * exists("#Group#Event") or
+ * exists("#Group#Event#pat") or
+ * exists("#Event") or
+ * exists("#Event#pat")
+ */
+ int
+au_exists(char_u *arg)
+{
+ char_u *arg_save;
+ char_u *pattern = NULL;
+ char_u *event_name;
+ char_u *p;
+ event_T event;
+ AutoPat *ap;
+ buf_T *buflocal_buf = NULL;
+ int group;
+ int retval = FALSE;
+
+ // Make a copy so that we can change the '#' chars to a NUL.
+ arg_save = vim_strsave(arg);
+ if (arg_save == NULL)
+ return FALSE;
+ p = vim_strchr(arg_save, '#');
+ if (p != NULL)
+ *p++ = NUL;
+
+ // First, look for an autocmd group name
+ group = au_find_group(arg_save);
+ if (group == AUGROUP_ERROR)
+ {
+ // Didn't match a group name, assume the first argument is an event.
+ group = AUGROUP_ALL;
+ event_name = arg_save;
+ }
+ else
+ {
+ if (p == NULL)
+ {
+ // "Group": group name is present and it's recognized
+ retval = TRUE;
+ goto theend;
+ }
+
+ // Must be "Group#Event" or "Group#Event#pat".
+ event_name = p;
+ p = vim_strchr(event_name, '#');
+ if (p != NULL)
+ *p++ = NUL; // "Group#Event#pat"
+ }
+
+ pattern = p; // "pattern" is NULL when there is no pattern
+
+ // find the index (enum) for the event name
+ event = event_name2nr(event_name, &p);
+
+ // return FALSE if the event name is not recognized
+ if (event == NUM_EVENTS)
+ goto theend;
+
+ // Find the first autocommand for this event.
+ // If there isn't any, return FALSE;
+ // If there is one and no pattern given, return TRUE;
+ ap = first_autopat[(int)event];
+ if (ap == NULL)
+ goto theend;
+
+ // if pattern is "<buffer>", special handling is needed which uses curbuf
+ // for pattern "<buffer=N>, fnamecmp() will work fine
+ if (pattern != NULL && STRICMP(pattern, "<buffer>") == 0)
+ buflocal_buf = curbuf;
+
+ // Check if there is an autocommand with the given pattern.
+ for ( ; ap != NULL; ap = ap->next)
+ // only use a pattern when it has not been removed and has commands.
+ // For buffer-local autocommands, fnamecmp() works fine.
+ if (ap->pat != NULL && ap->cmds != NULL
+ && (group == AUGROUP_ALL || ap->group == group)
+ && (pattern == NULL
+ || (buflocal_buf == NULL
+ ? fnamecmp(ap->pat, pattern) == 0
+ : ap->buflocal_nr == buflocal_buf->b_fnum)))
+ {
+ retval = TRUE;
+ break;
+ }
+
+theend:
+ vim_free(arg_save);
+ return retval;
+}
+#endif
diff --git a/src/beval.c b/src/beval.c
new file mode 100644
index 0000000..c5fa220
--- /dev/null
+++ b/src/beval.c
@@ -0,0 +1,281 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ * Visual Workshop integration by Gordon Prieur
+ *
+ * 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.
+ */
+
+#include "vim.h"
+
+#if defined(FEAT_BEVAL) || defined(PROTO)
+
+/*
+ * Get the text and position to be evaluated for "beval".
+ * If "getword" is true the returned text is not the whole line but the
+ * relevant word in allocated memory.
+ * Returns OK or FAIL.
+ */
+ int
+get_beval_info(
+ BalloonEval *beval,
+ int getword,
+ win_T **winp,
+ linenr_T *lnump,
+ char_u **textp,
+ int *colp)
+{
+ win_T *wp;
+ int row, col;
+ char_u *lbuf;
+ linenr_T lnum;
+
+ *textp = NULL;
+# ifdef FEAT_BEVAL_TERM
+# ifdef FEAT_GUI
+ if (!gui.in_use)
+# endif
+ {
+ row = mouse_row;
+ col = mouse_col;
+ }
+# endif
+# ifdef FEAT_GUI
+ if (gui.in_use)
+ {
+ row = Y_2_ROW(beval->y);
+ col = X_2_COL(beval->x);
+ }
+#endif
+ wp = mouse_find_win(&row, &col);
+ if (wp != NULL && row >= 0 && row < wp->w_height && col < wp->w_width)
+ {
+ /* Found a window and the cursor is in the text. Now find the line
+ * number. */
+ if (!mouse_comp_pos(wp, &row, &col, &lnum))
+ {
+ /* Not past end of the file. */
+ lbuf = ml_get_buf(wp->w_buffer, lnum, FALSE);
+ if (col <= win_linetabsize(wp, lbuf, (colnr_T)MAXCOL))
+ {
+ /* Not past end of line. */
+ if (getword)
+ {
+ /* For Netbeans we get the relevant part of the line
+ * instead of the whole line. */
+ int len;
+ pos_T *spos = NULL, *epos = NULL;
+
+ if (VIsual_active)
+ {
+ if (LT_POS(VIsual, curwin->w_cursor))
+ {
+ spos = &VIsual;
+ epos = &curwin->w_cursor;
+ }
+ else
+ {
+ spos = &curwin->w_cursor;
+ epos = &VIsual;
+ }
+ }
+
+ col = vcol2col(wp, lnum, col);
+
+ if (VIsual_active
+ && wp->w_buffer == curwin->w_buffer
+ && (lnum == spos->lnum
+ ? col >= (int)spos->col
+ : lnum > spos->lnum)
+ && (lnum == epos->lnum
+ ? col <= (int)epos->col
+ : lnum < epos->lnum))
+ {
+ /* Visual mode and pointing to the line with the
+ * Visual selection: return selected text, with a
+ * maximum of one line. */
+ if (spos->lnum != epos->lnum || spos->col == epos->col)
+ return FAIL;
+
+ lbuf = ml_get_buf(curwin->w_buffer, VIsual.lnum, FALSE);
+ len = epos->col - spos->col;
+ if (*p_sel != 'e')
+ len += MB_PTR2LEN(lbuf + epos->col);
+ lbuf = vim_strnsave(lbuf + spos->col, len);
+ lnum = spos->lnum;
+ col = spos->col;
+ }
+ else
+ {
+ /* Find the word under the cursor. */
+ ++emsg_off;
+ len = find_ident_at_pos(wp, lnum, (colnr_T)col, &lbuf,
+ FIND_IDENT + FIND_STRING + FIND_EVAL);
+ --emsg_off;
+ if (len == 0)
+ return FAIL;
+ lbuf = vim_strnsave(lbuf, len);
+ }
+ }
+
+ *winp = wp;
+ *lnump = lnum;
+ *textp = lbuf;
+ *colp = col;
+#ifdef FEAT_VARTABS
+ vim_free(beval->vts);
+ beval->vts = tabstop_copy(wp->w_buffer->b_p_vts_array);
+#endif
+ beval->ts = wp->w_buffer->b_p_ts;
+ return OK;
+ }
+ }
+ }
+
+ return FAIL;
+}
+
+/*
+ * Show a balloon with "mesg" or "list".
+ */
+ void
+post_balloon(BalloonEval *beval UNUSED, char_u *mesg, list_T *list UNUSED)
+{
+# ifdef FEAT_BEVAL_TERM
+# ifdef FEAT_GUI
+ if (!gui.in_use)
+# endif
+ ui_post_balloon(mesg, list);
+# endif
+# ifdef FEAT_BEVAL_GUI
+ if (gui.in_use)
+ /* GUI can't handle a list */
+ gui_mch_post_balloon(beval, mesg);
+# endif
+}
+
+/*
+ * Returns TRUE if the balloon eval has been enabled:
+ * 'ballooneval' for the GUI and 'balloonevalterm' for the terminal.
+ * Also checks if the screen isn't scrolled up.
+ */
+ int
+can_use_beval(void)
+{
+ return (0
+#ifdef FEAT_BEVAL_GUI
+ || (gui.in_use && p_beval)
+#endif
+#ifdef FEAT_BEVAL_TERM
+ || (
+# ifdef FEAT_GUI
+ !gui.in_use &&
+# endif
+ p_bevalterm)
+#endif
+ ) && msg_scrolled == 0;
+}
+
+/*
+ * Common code, invoked when the mouse is resting for a moment.
+ */
+ void
+general_beval_cb(BalloonEval *beval, int state UNUSED)
+{
+#ifdef FEAT_EVAL
+ win_T *wp;
+ int col;
+ int use_sandbox;
+ linenr_T lnum;
+ char_u *text;
+ static char_u *result = NULL;
+ long winnr = 0;
+ char_u *bexpr;
+ buf_T *save_curbuf;
+ size_t len;
+ win_T *cw;
+#endif
+ static int recursive = FALSE;
+
+ /* Don't do anything when 'ballooneval' is off, messages scrolled the
+ * windows up or we have no beval area. */
+ if (!can_use_beval() || beval == NULL)
+ return;
+
+ /* Don't do this recursively. Happens when the expression evaluation
+ * takes a long time and invokes something that checks for CTRL-C typed. */
+ if (recursive)
+ return;
+ recursive = TRUE;
+
+#ifdef FEAT_EVAL
+ if (get_beval_info(beval, TRUE, &wp, &lnum, &text, &col) == OK)
+ {
+ bexpr = (*wp->w_buffer->b_p_bexpr == NUL) ? p_bexpr
+ : wp->w_buffer->b_p_bexpr;
+ if (*bexpr != NUL)
+ {
+ /* Convert window pointer to number. */
+ for (cw = firstwin; cw != wp; cw = cw->w_next)
+ ++winnr;
+
+ set_vim_var_nr(VV_BEVAL_BUFNR, (long)wp->w_buffer->b_fnum);
+ set_vim_var_nr(VV_BEVAL_WINNR, winnr);
+ set_vim_var_nr(VV_BEVAL_WINID, wp->w_id);
+ set_vim_var_nr(VV_BEVAL_LNUM, (long)lnum);
+ set_vim_var_nr(VV_BEVAL_COL, (long)(col + 1));
+ set_vim_var_string(VV_BEVAL_TEXT, text, -1);
+ vim_free(text);
+
+ /*
+ * Temporarily change the curbuf, so that we can determine whether
+ * the buffer-local balloonexpr option was set insecurely.
+ */
+ save_curbuf = curbuf;
+ curbuf = wp->w_buffer;
+ use_sandbox = was_set_insecurely((char_u *)"balloonexpr",
+ *curbuf->b_p_bexpr == NUL ? 0 : OPT_LOCAL);
+ curbuf = save_curbuf;
+ if (use_sandbox)
+ ++sandbox;
+ ++textlock;
+
+ vim_free(result);
+ result = eval_to_string(bexpr, NULL, TRUE);
+
+ /* Remove one trailing newline, it is added when the result was a
+ * list and it's hardly ever useful. If the user really wants a
+ * trailing newline he can add two and one remains. */
+ if (result != NULL)
+ {
+ len = STRLEN(result);
+ if (len > 0 && result[len - 1] == NL)
+ result[len - 1] = NUL;
+ }
+
+ if (use_sandbox)
+ --sandbox;
+ --textlock;
+
+ set_vim_var_string(VV_BEVAL_TEXT, NULL, -1);
+ if (result != NULL && result[0] != NUL)
+ {
+ post_balloon(beval, result, NULL);
+ recursive = FALSE;
+ return;
+ }
+ }
+ }
+#endif
+#ifdef FEAT_NETBEANS_INTG
+ if (bevalServers & BEVAL_NETBEANS)
+ netbeans_beval_cb(beval, state);
+#endif
+
+ recursive = FALSE;
+}
+
+#endif
+
diff --git a/src/beval.h b/src/beval.h
new file mode 100644
index 0000000..21900c5
--- /dev/null
+++ b/src/beval.h
@@ -0,0 +1,91 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ * Visual Workshop integration by Gordon Prieur
+ *
+ * Do ":help uganda" in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ */
+
+#if !defined(BEVAL__H) && (defined(FEAT_BEVAL) || defined(PROTO))
+#define BEVAL__H
+
+#ifdef FEAT_GUI_GTK
+# ifdef USE_GTK3
+# include <gtk/gtk.h>
+# else
+# include <gtk/gtkwidget.h>
+# endif
+#else
+# if defined(FEAT_GUI_X11)
+# include <X11/Intrinsic.h>
+# endif
+#endif
+
+typedef enum
+{
+ ShS_NEUTRAL, /* nothing showing or pending */
+ ShS_PENDING, /* data requested from debugger */
+ ShS_UPDATE_PENDING, /* switching information displayed */
+ ShS_SHOWING /* the balloon is being displayed */
+} BeState;
+
+typedef struct BalloonEvalStruct
+{
+#ifdef FEAT_BEVAL_GUI
+# ifdef FEAT_GUI_GTK
+ GtkWidget *target; /* widget we are monitoring */
+ GtkWidget *balloonShell;
+ GtkWidget *balloonLabel;
+ unsigned int timerID; /* timer for run */
+ BeState showState; /* tells us whats currently going on */
+ int x;
+ int y;
+ unsigned int state; /* Button/Modifier key state */
+# else
+# if !defined(FEAT_GUI_W32)
+ Widget target; /* widget we are monitoring */
+ Widget balloonShell;
+ Widget balloonLabel;
+ XtIntervalId timerID; /* timer for run */
+ BeState showState; /* tells us whats currently going on */
+ XtAppContext appContext; /* used in event handler */
+ Position x;
+ Position y;
+ Position x_root;
+ Position y_root;
+ int state; /* Button/Modifier key state */
+# else
+ HWND target;
+ HWND balloon;
+ int x;
+ int y;
+ BeState showState; /* tells us whats currently going on */
+# endif
+# endif
+# if !defined(FEAT_GUI_GTK) && !defined(FEAT_GUI_W32)
+ Dimension screen_width; /* screen width in pixels */
+ Dimension screen_height; /* screen height in pixels */
+# endif
+ void (*msgCB)(struct BalloonEvalStruct *, int);
+ void *clientData; /* For callback */
+#endif
+
+ int ts; // tabstop setting for this buffer
+#ifdef FEAT_VARTABS
+ int *vts; // vartabstop setting for this buffer
+#endif
+ char_u *msg;
+#ifdef FEAT_GUI_W32
+ void *tofree;
+#endif
+} BalloonEval;
+
+#define EVAL_OFFSET_X 15 /* displacement of beval topleft corner from pointer */
+#define EVAL_OFFSET_Y 10
+
+#ifdef FEAT_BEVAL_GUI
+# include "gui_beval.pro"
+#endif
+
+#endif /* BEVAL__H and FEAT_BEVAL_GUI */
diff --git a/src/bigvim.bat b/src/bigvim.bat
new file mode 100644
index 0000000..e82eabd
--- /dev/null
+++ b/src/bigvim.bat
@@ -0,0 +1,5 @@
+:: command to build big Vim with OLE, Lua, Perl, Python, Racket, Ruby and Tcl
+SET VCDIR="C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin\"
+SET TOOLDIR=E:\
+%VCDIR%nmake -f Make_mvc.mak GUI=yes OLE=yes LUA=%TOOLDIR%lua53 DYNAMIC_LUA=yes LUA_VER=53 PERL=%TOOLDIR%perl524 DYNAMIC_PERL=yes PERL_VER=524 PYTHON=%TOOLDIR%python27 DYNAMIC_PYTHON=yes PYTHON_VER=27 PYTHON3=%TOOLDIR%python36 DYNAMIC_PYTHON3=yes PYTHON3_VER=36 MZSCHEME=%TOOLDIR%Racket DYNAMIC_MZSCHEME=yes MZSCHEME_VER=3m_a36fs8 RUBY=%TOOLDIR%ruby24 DYNAMIC_RUBY=yes RUBY_VER=24 RUBY_API_VER_LONG=2.4.0 RUBY_MSVCRT_NAME=msvcrt TCL=%TOOLDIR%ActiveTcl TCL_VER=86 TCL_VER_LONG=8.6 DYNAMIC_TCL=yes TCL_DLL=tcl86t.dll %1 IME=yes CSCOPE=yes DIRECTX=yes
+
diff --git a/src/bigvim64.bat b/src/bigvim64.bat
new file mode 100644
index 0000000..8d5fba0
--- /dev/null
+++ b/src/bigvim64.bat
@@ -0,0 +1,7 @@
+:: command to build big Vim 64 bit with OLE, Perl and Python.
+:: First run: %VCDIR%\vcvarsall.bat x86_amd64
+:: Ruby and Tcl are excluded, doesn't seem to work.
+SET VCDIR="C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\"
+SET TOOLDIR=E:\
+%VCDIR%\bin\nmake -f Make_mvc.mak CPU=AMD64 GUI=yes OLE=yes PERL=E:\perl524 DYNAMIC_PERL=yes PERL_VER=524 PYTHON=%TOOLDIR%python27 DYNAMIC_PYTHON=yes PYTHON_VER=27 PYTHON3=%TOOLDIR%python35 DYNAMIC_PYTHON3=yes PYTHON3_VER=35 %1 IME=yes CSCOPE=yes
+
diff --git a/src/blob.c b/src/blob.c
new file mode 100644
index 0000000..9dc7926
--- /dev/null
+++ b/src/blob.c
@@ -0,0 +1,258 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * blob.c: Blob support by Yasuhiro Matsumoto
+ */
+
+#include "vim.h"
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+
+/*
+ * Allocate an empty blob.
+ * Caller should take care of the reference count.
+ */
+ blob_T *
+blob_alloc(void)
+{
+ blob_T *blob = (blob_T *)alloc_clear(sizeof(blob_T));
+
+ if (blob != NULL)
+ ga_init2(&blob->bv_ga, 1, 100);
+ return blob;
+}
+
+/*
+ * Allocate an empty blob for a return value, with reference count set.
+ * Returns OK or FAIL.
+ */
+ int
+rettv_blob_alloc(typval_T *rettv)
+{
+ blob_T *b = blob_alloc();
+
+ if (b == NULL)
+ return FAIL;
+
+ rettv_blob_set(rettv, b);
+ return OK;
+}
+
+/*
+ * Set a blob as the return value.
+ */
+ void
+rettv_blob_set(typval_T *rettv, blob_T *b)
+{
+ rettv->v_type = VAR_BLOB;
+ rettv->vval.v_blob = b;
+ if (b != NULL)
+ ++b->bv_refcount;
+}
+
+ int
+blob_copy(typval_T *from, typval_T *to)
+{
+ int ret = OK;
+
+ to->v_type = VAR_BLOB;
+ if (from->vval.v_blob == NULL)
+ to->vval.v_blob = NULL;
+ else if (rettv_blob_alloc(to) == FAIL)
+ ret = FAIL;
+ else
+ {
+ int len = from->vval.v_blob->bv_ga.ga_len;
+
+ if (len > 0)
+ {
+ to->vval.v_blob->bv_ga.ga_data =
+ vim_memsave(from->vval.v_blob->bv_ga.ga_data, len);
+ if (to->vval.v_blob->bv_ga.ga_data == NULL)
+ len = 0;
+ }
+ to->vval.v_blob->bv_ga.ga_len = len;
+ }
+ return ret;
+}
+
+ void
+blob_free(blob_T *b)
+{
+ ga_clear(&b->bv_ga);
+ vim_free(b);
+}
+
+/*
+ * Unreference a blob: decrement the reference count and free it when it
+ * becomes zero.
+ */
+ void
+blob_unref(blob_T *b)
+{
+ if (b != NULL && --b->bv_refcount <= 0)
+ blob_free(b);
+}
+
+/*
+ * Get the length of data.
+ */
+ long
+blob_len(blob_T *b)
+{
+ if (b == NULL)
+ return 0L;
+ return b->bv_ga.ga_len;
+}
+
+/*
+ * Get byte "idx" in blob "b".
+ * Caller must check that "idx" is valid.
+ */
+ int
+blob_get(blob_T *b, int idx)
+{
+ return ((char_u*)b->bv_ga.ga_data)[idx];
+}
+
+/*
+ * Store one byte "c" in blob "b" at "idx".
+ * Caller must make sure that "idx" is valid.
+ */
+ void
+blob_set(blob_T *b, int idx, char_u c)
+{
+ ((char_u*)b->bv_ga.ga_data)[idx] = c;
+}
+
+/*
+ * Return TRUE when two blobs have exactly the same values.
+ */
+ int
+blob_equal(
+ blob_T *b1,
+ blob_T *b2)
+{
+ int i;
+ int len1 = blob_len(b1);
+ int len2 = blob_len(b2);
+
+ // empty and NULL are considered the same
+ if (len1 == 0 && len2 == 0)
+ return TRUE;
+ if (b1 == b2)
+ return TRUE;
+ if (len1 != len2)
+ return FALSE;
+
+ for (i = 0; i < b1->bv_ga.ga_len; i++)
+ if (blob_get(b1, i) != blob_get(b2, i)) return FALSE;
+ return TRUE;
+}
+
+/*
+ * Read "blob" from file "fd".
+ * Return OK or FAIL.
+ */
+ int
+read_blob(FILE *fd, blob_T *blob)
+{
+ struct stat st;
+
+ if (fstat(fileno(fd), &st) < 0)
+ return FAIL;
+ if (ga_grow(&blob->bv_ga, st.st_size) == FAIL)
+ return FAIL;
+ blob->bv_ga.ga_len = st.st_size;
+ if (fread(blob->bv_ga.ga_data, 1, blob->bv_ga.ga_len, fd)
+ < (size_t)blob->bv_ga.ga_len)
+ return FAIL;
+ return OK;
+}
+
+/*
+ * Write "blob" to file "fd".
+ * Return OK or FAIL.
+ */
+ int
+write_blob(FILE *fd, blob_T *blob)
+{
+ if (fwrite(blob->bv_ga.ga_data, 1, blob->bv_ga.ga_len, fd)
+ < (size_t)blob->bv_ga.ga_len)
+ {
+ emsg(_(e_write));
+ return FAIL;
+ }
+ return OK;
+}
+
+/*
+ * Convert a blob to a readable form: "0z00112233.44556677.8899"
+ */
+ char_u *
+blob2string(blob_T *blob, char_u **tofree, char_u *numbuf)
+{
+ int i;
+ garray_T ga;
+
+ if (blob == NULL)
+ {
+ *tofree = NULL;
+ return (char_u *)"0z";
+ }
+
+ // Store bytes in the growarray.
+ ga_init2(&ga, 1, 4000);
+ ga_concat(&ga, (char_u *)"0z");
+ for (i = 0; i < blob_len(blob); i++)
+ {
+ if (i > 0 && (i & 3) == 0)
+ ga_concat(&ga, (char_u *)".");
+ vim_snprintf((char *)numbuf, NUMBUFLEN, "%02X", (int)blob_get(blob, i));
+ ga_concat(&ga, numbuf);
+ }
+ *tofree = ga.ga_data;
+ return *tofree;
+}
+
+/*
+ * Convert a string variable, in the format of blob2string(), to a blob.
+ * Return NULL when conversion failed.
+ */
+ blob_T *
+string2blob(char_u *str)
+{
+ blob_T *blob = blob_alloc();
+ char_u *s = str;
+
+ if (s[0] != '0' || (s[1] != 'z' && s[1] != 'Z'))
+ goto failed;
+ s += 2;
+ while (vim_isxdigit(*s))
+ {
+ if (!vim_isxdigit(s[1]))
+ goto failed;
+ ga_append(&blob->bv_ga, (hex2nr(s[0]) << 4) + hex2nr(s[1]));
+ s += 2;
+ if (*s == '.' && vim_isxdigit(s[1]))
+ ++s;
+ }
+ if (*skipwhite(s) != NUL)
+ goto failed; // text after final digit
+
+ ++blob->bv_refcount;
+ return blob;
+
+failed:
+ blob_free(blob);
+ return NULL;
+}
+
+#endif /* defined(FEAT_EVAL) */
diff --git a/src/blowfish.c b/src/blowfish.c
new file mode 100644
index 0000000..8ca0e28
--- /dev/null
+++ b/src/blowfish.c
@@ -0,0 +1,683 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ *
+ * Blowfish encryption for Vim; in Blowfish cipher feedback mode.
+ * Contributed by Mohsin Ahmed, http://www.cs.albany.edu/~mosh
+ * Based on http://www.schneier.com/blowfish.html by Bruce Schneier.
+ *
+ * There are two variants:
+ * - The old one "blowfish" has a flaw which makes it much easier to crack the
+ * key. To see this, make a text file with one line of 1000 "x" characters
+ * and write it encrypted. Use "xxd" to inspect the bytes in the file. You
+ * will see that a block of 8 bytes repeats 8 times.
+ * - The new one "blowfish2" is better. It uses an 8 byte CFB to avoid the
+ * repeats.
+ */
+
+#include "vim.h"
+
+#if defined(FEAT_CRYPT) || defined(PROTO)
+
+#define ARRAY_LENGTH(A) (sizeof(A)/sizeof(A[0]))
+
+#define BF_BLOCK 8
+#define BF_BLOCK_MASK 7
+#define BF_MAX_CFB_LEN (8 * BF_BLOCK)
+
+typedef union {
+ UINT32_T ul[2];
+ char_u uc[8];
+} block8;
+
+#if defined(WIN3264)
+ /* MS-Windows is always little endian */
+#else
+# ifdef HAVE_CONFIG_H
+ /* in configure.ac AC_C_BIGENDIAN() defines WORDS_BIGENDIAN when needed */
+# else
+ error!
+ Please change this code to define WORDS_BIGENDIAN for big-endian machines.
+# endif
+#endif
+
+/* The state of encryption, referenced by cryptstate_T. */
+typedef struct {
+ UINT32_T pax[18]; /* P-array */
+ UINT32_T sbx[4][256]; /* S-boxes */
+ int randbyte_offset;
+ int update_offset;
+ char_u cfb_buffer[BF_MAX_CFB_LEN]; /* up to 64 bytes used */
+ int cfb_len; /* size of cfb_buffer actually used */
+} bf_state_T;
+
+
+/* Blowfish code */
+static UINT32_T pax_init[18] = {
+ 0x243f6a88u, 0x85a308d3u, 0x13198a2eu,
+ 0x03707344u, 0xa4093822u, 0x299f31d0u,
+ 0x082efa98u, 0xec4e6c89u, 0x452821e6u,
+ 0x38d01377u, 0xbe5466cfu, 0x34e90c6cu,
+ 0xc0ac29b7u, 0xc97c50ddu, 0x3f84d5b5u,
+ 0xb5470917u, 0x9216d5d9u, 0x8979fb1bu
+};
+
+static UINT32_T sbx_init[4][256] = {
+ {0xd1310ba6u, 0x98dfb5acu, 0x2ffd72dbu, 0xd01adfb7u,
+ 0xb8e1afedu, 0x6a267e96u, 0xba7c9045u, 0xf12c7f99u,
+ 0x24a19947u, 0xb3916cf7u, 0x0801f2e2u, 0x858efc16u,
+ 0x636920d8u, 0x71574e69u, 0xa458fea3u, 0xf4933d7eu,
+ 0x0d95748fu, 0x728eb658u, 0x718bcd58u, 0x82154aeeu,
+ 0x7b54a41du, 0xc25a59b5u, 0x9c30d539u, 0x2af26013u,
+ 0xc5d1b023u, 0x286085f0u, 0xca417918u, 0xb8db38efu,
+ 0x8e79dcb0u, 0x603a180eu, 0x6c9e0e8bu, 0xb01e8a3eu,
+ 0xd71577c1u, 0xbd314b27u, 0x78af2fdau, 0x55605c60u,
+ 0xe65525f3u, 0xaa55ab94u, 0x57489862u, 0x63e81440u,
+ 0x55ca396au, 0x2aab10b6u, 0xb4cc5c34u, 0x1141e8ceu,
+ 0xa15486afu, 0x7c72e993u, 0xb3ee1411u, 0x636fbc2au,
+ 0x2ba9c55du, 0x741831f6u, 0xce5c3e16u, 0x9b87931eu,
+ 0xafd6ba33u, 0x6c24cf5cu, 0x7a325381u, 0x28958677u,
+ 0x3b8f4898u, 0x6b4bb9afu, 0xc4bfe81bu, 0x66282193u,
+ 0x61d809ccu, 0xfb21a991u, 0x487cac60u, 0x5dec8032u,
+ 0xef845d5du, 0xe98575b1u, 0xdc262302u, 0xeb651b88u,
+ 0x23893e81u, 0xd396acc5u, 0x0f6d6ff3u, 0x83f44239u,
+ 0x2e0b4482u, 0xa4842004u, 0x69c8f04au, 0x9e1f9b5eu,
+ 0x21c66842u, 0xf6e96c9au, 0x670c9c61u, 0xabd388f0u,
+ 0x6a51a0d2u, 0xd8542f68u, 0x960fa728u, 0xab5133a3u,
+ 0x6eef0b6cu, 0x137a3be4u, 0xba3bf050u, 0x7efb2a98u,
+ 0xa1f1651du, 0x39af0176u, 0x66ca593eu, 0x82430e88u,
+ 0x8cee8619u, 0x456f9fb4u, 0x7d84a5c3u, 0x3b8b5ebeu,
+ 0xe06f75d8u, 0x85c12073u, 0x401a449fu, 0x56c16aa6u,
+ 0x4ed3aa62u, 0x363f7706u, 0x1bfedf72u, 0x429b023du,
+ 0x37d0d724u, 0xd00a1248u, 0xdb0fead3u, 0x49f1c09bu,
+ 0x075372c9u, 0x80991b7bu, 0x25d479d8u, 0xf6e8def7u,
+ 0xe3fe501au, 0xb6794c3bu, 0x976ce0bdu, 0x04c006bau,
+ 0xc1a94fb6u, 0x409f60c4u, 0x5e5c9ec2u, 0x196a2463u,
+ 0x68fb6fafu, 0x3e6c53b5u, 0x1339b2ebu, 0x3b52ec6fu,
+ 0x6dfc511fu, 0x9b30952cu, 0xcc814544u, 0xaf5ebd09u,
+ 0xbee3d004u, 0xde334afdu, 0x660f2807u, 0x192e4bb3u,
+ 0xc0cba857u, 0x45c8740fu, 0xd20b5f39u, 0xb9d3fbdbu,
+ 0x5579c0bdu, 0x1a60320au, 0xd6a100c6u, 0x402c7279u,
+ 0x679f25feu, 0xfb1fa3ccu, 0x8ea5e9f8u, 0xdb3222f8u,
+ 0x3c7516dfu, 0xfd616b15u, 0x2f501ec8u, 0xad0552abu,
+ 0x323db5fau, 0xfd238760u, 0x53317b48u, 0x3e00df82u,
+ 0x9e5c57bbu, 0xca6f8ca0u, 0x1a87562eu, 0xdf1769dbu,
+ 0xd542a8f6u, 0x287effc3u, 0xac6732c6u, 0x8c4f5573u,
+ 0x695b27b0u, 0xbbca58c8u, 0xe1ffa35du, 0xb8f011a0u,
+ 0x10fa3d98u, 0xfd2183b8u, 0x4afcb56cu, 0x2dd1d35bu,
+ 0x9a53e479u, 0xb6f84565u, 0xd28e49bcu, 0x4bfb9790u,
+ 0xe1ddf2dau, 0xa4cb7e33u, 0x62fb1341u, 0xcee4c6e8u,
+ 0xef20cadau, 0x36774c01u, 0xd07e9efeu, 0x2bf11fb4u,
+ 0x95dbda4du, 0xae909198u, 0xeaad8e71u, 0x6b93d5a0u,
+ 0xd08ed1d0u, 0xafc725e0u, 0x8e3c5b2fu, 0x8e7594b7u,
+ 0x8ff6e2fbu, 0xf2122b64u, 0x8888b812u, 0x900df01cu,
+ 0x4fad5ea0u, 0x688fc31cu, 0xd1cff191u, 0xb3a8c1adu,
+ 0x2f2f2218u, 0xbe0e1777u, 0xea752dfeu, 0x8b021fa1u,
+ 0xe5a0cc0fu, 0xb56f74e8u, 0x18acf3d6u, 0xce89e299u,
+ 0xb4a84fe0u, 0xfd13e0b7u, 0x7cc43b81u, 0xd2ada8d9u,
+ 0x165fa266u, 0x80957705u, 0x93cc7314u, 0x211a1477u,
+ 0xe6ad2065u, 0x77b5fa86u, 0xc75442f5u, 0xfb9d35cfu,
+ 0xebcdaf0cu, 0x7b3e89a0u, 0xd6411bd3u, 0xae1e7e49u,
+ 0x00250e2du, 0x2071b35eu, 0x226800bbu, 0x57b8e0afu,
+ 0x2464369bu, 0xf009b91eu, 0x5563911du, 0x59dfa6aau,
+ 0x78c14389u, 0xd95a537fu, 0x207d5ba2u, 0x02e5b9c5u,
+ 0x83260376u, 0x6295cfa9u, 0x11c81968u, 0x4e734a41u,
+ 0xb3472dcau, 0x7b14a94au, 0x1b510052u, 0x9a532915u,
+ 0xd60f573fu, 0xbc9bc6e4u, 0x2b60a476u, 0x81e67400u,
+ 0x08ba6fb5u, 0x571be91fu, 0xf296ec6bu, 0x2a0dd915u,
+ 0xb6636521u, 0xe7b9f9b6u, 0xff34052eu, 0xc5855664u,
+ 0x53b02d5du, 0xa99f8fa1u, 0x08ba4799u, 0x6e85076au},
+ {0x4b7a70e9u, 0xb5b32944u, 0xdb75092eu, 0xc4192623u,
+ 0xad6ea6b0u, 0x49a7df7du, 0x9cee60b8u, 0x8fedb266u,
+ 0xecaa8c71u, 0x699a17ffu, 0x5664526cu, 0xc2b19ee1u,
+ 0x193602a5u, 0x75094c29u, 0xa0591340u, 0xe4183a3eu,
+ 0x3f54989au, 0x5b429d65u, 0x6b8fe4d6u, 0x99f73fd6u,
+ 0xa1d29c07u, 0xefe830f5u, 0x4d2d38e6u, 0xf0255dc1u,
+ 0x4cdd2086u, 0x8470eb26u, 0x6382e9c6u, 0x021ecc5eu,
+ 0x09686b3fu, 0x3ebaefc9u, 0x3c971814u, 0x6b6a70a1u,
+ 0x687f3584u, 0x52a0e286u, 0xb79c5305u, 0xaa500737u,
+ 0x3e07841cu, 0x7fdeae5cu, 0x8e7d44ecu, 0x5716f2b8u,
+ 0xb03ada37u, 0xf0500c0du, 0xf01c1f04u, 0x0200b3ffu,
+ 0xae0cf51au, 0x3cb574b2u, 0x25837a58u, 0xdc0921bdu,
+ 0xd19113f9u, 0x7ca92ff6u, 0x94324773u, 0x22f54701u,
+ 0x3ae5e581u, 0x37c2dadcu, 0xc8b57634u, 0x9af3dda7u,
+ 0xa9446146u, 0x0fd0030eu, 0xecc8c73eu, 0xa4751e41u,
+ 0xe238cd99u, 0x3bea0e2fu, 0x3280bba1u, 0x183eb331u,
+ 0x4e548b38u, 0x4f6db908u, 0x6f420d03u, 0xf60a04bfu,
+ 0x2cb81290u, 0x24977c79u, 0x5679b072u, 0xbcaf89afu,
+ 0xde9a771fu, 0xd9930810u, 0xb38bae12u, 0xdccf3f2eu,
+ 0x5512721fu, 0x2e6b7124u, 0x501adde6u, 0x9f84cd87u,
+ 0x7a584718u, 0x7408da17u, 0xbc9f9abcu, 0xe94b7d8cu,
+ 0xec7aec3au, 0xdb851dfau, 0x63094366u, 0xc464c3d2u,
+ 0xef1c1847u, 0x3215d908u, 0xdd433b37u, 0x24c2ba16u,
+ 0x12a14d43u, 0x2a65c451u, 0x50940002u, 0x133ae4ddu,
+ 0x71dff89eu, 0x10314e55u, 0x81ac77d6u, 0x5f11199bu,
+ 0x043556f1u, 0xd7a3c76bu, 0x3c11183bu, 0x5924a509u,
+ 0xf28fe6edu, 0x97f1fbfau, 0x9ebabf2cu, 0x1e153c6eu,
+ 0x86e34570u, 0xeae96fb1u, 0x860e5e0au, 0x5a3e2ab3u,
+ 0x771fe71cu, 0x4e3d06fau, 0x2965dcb9u, 0x99e71d0fu,
+ 0x803e89d6u, 0x5266c825u, 0x2e4cc978u, 0x9c10b36au,
+ 0xc6150ebau, 0x94e2ea78u, 0xa5fc3c53u, 0x1e0a2df4u,
+ 0xf2f74ea7u, 0x361d2b3du, 0x1939260fu, 0x19c27960u,
+ 0x5223a708u, 0xf71312b6u, 0xebadfe6eu, 0xeac31f66u,
+ 0xe3bc4595u, 0xa67bc883u, 0xb17f37d1u, 0x018cff28u,
+ 0xc332ddefu, 0xbe6c5aa5u, 0x65582185u, 0x68ab9802u,
+ 0xeecea50fu, 0xdb2f953bu, 0x2aef7dadu, 0x5b6e2f84u,
+ 0x1521b628u, 0x29076170u, 0xecdd4775u, 0x619f1510u,
+ 0x13cca830u, 0xeb61bd96u, 0x0334fe1eu, 0xaa0363cfu,
+ 0xb5735c90u, 0x4c70a239u, 0xd59e9e0bu, 0xcbaade14u,
+ 0xeecc86bcu, 0x60622ca7u, 0x9cab5cabu, 0xb2f3846eu,
+ 0x648b1eafu, 0x19bdf0cau, 0xa02369b9u, 0x655abb50u,
+ 0x40685a32u, 0x3c2ab4b3u, 0x319ee9d5u, 0xc021b8f7u,
+ 0x9b540b19u, 0x875fa099u, 0x95f7997eu, 0x623d7da8u,
+ 0xf837889au, 0x97e32d77u, 0x11ed935fu, 0x16681281u,
+ 0x0e358829u, 0xc7e61fd6u, 0x96dedfa1u, 0x7858ba99u,
+ 0x57f584a5u, 0x1b227263u, 0x9b83c3ffu, 0x1ac24696u,
+ 0xcdb30aebu, 0x532e3054u, 0x8fd948e4u, 0x6dbc3128u,
+ 0x58ebf2efu, 0x34c6ffeau, 0xfe28ed61u, 0xee7c3c73u,
+ 0x5d4a14d9u, 0xe864b7e3u, 0x42105d14u, 0x203e13e0u,
+ 0x45eee2b6u, 0xa3aaabeau, 0xdb6c4f15u, 0xfacb4fd0u,
+ 0xc742f442u, 0xef6abbb5u, 0x654f3b1du, 0x41cd2105u,
+ 0xd81e799eu, 0x86854dc7u, 0xe44b476au, 0x3d816250u,
+ 0xcf62a1f2u, 0x5b8d2646u, 0xfc8883a0u, 0xc1c7b6a3u,
+ 0x7f1524c3u, 0x69cb7492u, 0x47848a0bu, 0x5692b285u,
+ 0x095bbf00u, 0xad19489du, 0x1462b174u, 0x23820e00u,
+ 0x58428d2au, 0x0c55f5eau, 0x1dadf43eu, 0x233f7061u,
+ 0x3372f092u, 0x8d937e41u, 0xd65fecf1u, 0x6c223bdbu,
+ 0x7cde3759u, 0xcbee7460u, 0x4085f2a7u, 0xce77326eu,
+ 0xa6078084u, 0x19f8509eu, 0xe8efd855u, 0x61d99735u,
+ 0xa969a7aau, 0xc50c06c2u, 0x5a04abfcu, 0x800bcadcu,
+ 0x9e447a2eu, 0xc3453484u, 0xfdd56705u, 0x0e1e9ec9u,
+ 0xdb73dbd3u, 0x105588cdu, 0x675fda79u, 0xe3674340u,
+ 0xc5c43465u, 0x713e38d8u, 0x3d28f89eu, 0xf16dff20u,
+ 0x153e21e7u, 0x8fb03d4au, 0xe6e39f2bu, 0xdb83adf7u},
+ {0xe93d5a68u, 0x948140f7u, 0xf64c261cu, 0x94692934u,
+ 0x411520f7u, 0x7602d4f7u, 0xbcf46b2eu, 0xd4a20068u,
+ 0xd4082471u, 0x3320f46au, 0x43b7d4b7u, 0x500061afu,
+ 0x1e39f62eu, 0x97244546u, 0x14214f74u, 0xbf8b8840u,
+ 0x4d95fc1du, 0x96b591afu, 0x70f4ddd3u, 0x66a02f45u,
+ 0xbfbc09ecu, 0x03bd9785u, 0x7fac6dd0u, 0x31cb8504u,
+ 0x96eb27b3u, 0x55fd3941u, 0xda2547e6u, 0xabca0a9au,
+ 0x28507825u, 0x530429f4u, 0x0a2c86dau, 0xe9b66dfbu,
+ 0x68dc1462u, 0xd7486900u, 0x680ec0a4u, 0x27a18deeu,
+ 0x4f3ffea2u, 0xe887ad8cu, 0xb58ce006u, 0x7af4d6b6u,
+ 0xaace1e7cu, 0xd3375fecu, 0xce78a399u, 0x406b2a42u,
+ 0x20fe9e35u, 0xd9f385b9u, 0xee39d7abu, 0x3b124e8bu,
+ 0x1dc9faf7u, 0x4b6d1856u, 0x26a36631u, 0xeae397b2u,
+ 0x3a6efa74u, 0xdd5b4332u, 0x6841e7f7u, 0xca7820fbu,
+ 0xfb0af54eu, 0xd8feb397u, 0x454056acu, 0xba489527u,
+ 0x55533a3au, 0x20838d87u, 0xfe6ba9b7u, 0xd096954bu,
+ 0x55a867bcu, 0xa1159a58u, 0xcca92963u, 0x99e1db33u,
+ 0xa62a4a56u, 0x3f3125f9u, 0x5ef47e1cu, 0x9029317cu,
+ 0xfdf8e802u, 0x04272f70u, 0x80bb155cu, 0x05282ce3u,
+ 0x95c11548u, 0xe4c66d22u, 0x48c1133fu, 0xc70f86dcu,
+ 0x07f9c9eeu, 0x41041f0fu, 0x404779a4u, 0x5d886e17u,
+ 0x325f51ebu, 0xd59bc0d1u, 0xf2bcc18fu, 0x41113564u,
+ 0x257b7834u, 0x602a9c60u, 0xdff8e8a3u, 0x1f636c1bu,
+ 0x0e12b4c2u, 0x02e1329eu, 0xaf664fd1u, 0xcad18115u,
+ 0x6b2395e0u, 0x333e92e1u, 0x3b240b62u, 0xeebeb922u,
+ 0x85b2a20eu, 0xe6ba0d99u, 0xde720c8cu, 0x2da2f728u,
+ 0xd0127845u, 0x95b794fdu, 0x647d0862u, 0xe7ccf5f0u,
+ 0x5449a36fu, 0x877d48fau, 0xc39dfd27u, 0xf33e8d1eu,
+ 0x0a476341u, 0x992eff74u, 0x3a6f6eabu, 0xf4f8fd37u,
+ 0xa812dc60u, 0xa1ebddf8u, 0x991be14cu, 0xdb6e6b0du,
+ 0xc67b5510u, 0x6d672c37u, 0x2765d43bu, 0xdcd0e804u,
+ 0xf1290dc7u, 0xcc00ffa3u, 0xb5390f92u, 0x690fed0bu,
+ 0x667b9ffbu, 0xcedb7d9cu, 0xa091cf0bu, 0xd9155ea3u,
+ 0xbb132f88u, 0x515bad24u, 0x7b9479bfu, 0x763bd6ebu,
+ 0x37392eb3u, 0xcc115979u, 0x8026e297u, 0xf42e312du,
+ 0x6842ada7u, 0xc66a2b3bu, 0x12754cccu, 0x782ef11cu,
+ 0x6a124237u, 0xb79251e7u, 0x06a1bbe6u, 0x4bfb6350u,
+ 0x1a6b1018u, 0x11caedfau, 0x3d25bdd8u, 0xe2e1c3c9u,
+ 0x44421659u, 0x0a121386u, 0xd90cec6eu, 0xd5abea2au,
+ 0x64af674eu, 0xda86a85fu, 0xbebfe988u, 0x64e4c3feu,
+ 0x9dbc8057u, 0xf0f7c086u, 0x60787bf8u, 0x6003604du,
+ 0xd1fd8346u, 0xf6381fb0u, 0x7745ae04u, 0xd736fcccu,
+ 0x83426b33u, 0xf01eab71u, 0xb0804187u, 0x3c005e5fu,
+ 0x77a057beu, 0xbde8ae24u, 0x55464299u, 0xbf582e61u,
+ 0x4e58f48fu, 0xf2ddfda2u, 0xf474ef38u, 0x8789bdc2u,
+ 0x5366f9c3u, 0xc8b38e74u, 0xb475f255u, 0x46fcd9b9u,
+ 0x7aeb2661u, 0x8b1ddf84u, 0x846a0e79u, 0x915f95e2u,
+ 0x466e598eu, 0x20b45770u, 0x8cd55591u, 0xc902de4cu,
+ 0xb90bace1u, 0xbb8205d0u, 0x11a86248u, 0x7574a99eu,
+ 0xb77f19b6u, 0xe0a9dc09u, 0x662d09a1u, 0xc4324633u,
+ 0xe85a1f02u, 0x09f0be8cu, 0x4a99a025u, 0x1d6efe10u,
+ 0x1ab93d1du, 0x0ba5a4dfu, 0xa186f20fu, 0x2868f169u,
+ 0xdcb7da83u, 0x573906feu, 0xa1e2ce9bu, 0x4fcd7f52u,
+ 0x50115e01u, 0xa70683fau, 0xa002b5c4u, 0x0de6d027u,
+ 0x9af88c27u, 0x773f8641u, 0xc3604c06u, 0x61a806b5u,
+ 0xf0177a28u, 0xc0f586e0u, 0x006058aau, 0x30dc7d62u,
+ 0x11e69ed7u, 0x2338ea63u, 0x53c2dd94u, 0xc2c21634u,
+ 0xbbcbee56u, 0x90bcb6deu, 0xebfc7da1u, 0xce591d76u,
+ 0x6f05e409u, 0x4b7c0188u, 0x39720a3du, 0x7c927c24u,
+ 0x86e3725fu, 0x724d9db9u, 0x1ac15bb4u, 0xd39eb8fcu,
+ 0xed545578u, 0x08fca5b5u, 0xd83d7cd3u, 0x4dad0fc4u,
+ 0x1e50ef5eu, 0xb161e6f8u, 0xa28514d9u, 0x6c51133cu,
+ 0x6fd5c7e7u, 0x56e14ec4u, 0x362abfceu, 0xddc6c837u,
+ 0xd79a3234u, 0x92638212u, 0x670efa8eu, 0x406000e0u},
+ {0x3a39ce37u, 0xd3faf5cfu, 0xabc27737u, 0x5ac52d1bu,
+ 0x5cb0679eu, 0x4fa33742u, 0xd3822740u, 0x99bc9bbeu,
+ 0xd5118e9du, 0xbf0f7315u, 0xd62d1c7eu, 0xc700c47bu,
+ 0xb78c1b6bu, 0x21a19045u, 0xb26eb1beu, 0x6a366eb4u,
+ 0x5748ab2fu, 0xbc946e79u, 0xc6a376d2u, 0x6549c2c8u,
+ 0x530ff8eeu, 0x468dde7du, 0xd5730a1du, 0x4cd04dc6u,
+ 0x2939bbdbu, 0xa9ba4650u, 0xac9526e8u, 0xbe5ee304u,
+ 0xa1fad5f0u, 0x6a2d519au, 0x63ef8ce2u, 0x9a86ee22u,
+ 0xc089c2b8u, 0x43242ef6u, 0xa51e03aau, 0x9cf2d0a4u,
+ 0x83c061bau, 0x9be96a4du, 0x8fe51550u, 0xba645bd6u,
+ 0x2826a2f9u, 0xa73a3ae1u, 0x4ba99586u, 0xef5562e9u,
+ 0xc72fefd3u, 0xf752f7dau, 0x3f046f69u, 0x77fa0a59u,
+ 0x80e4a915u, 0x87b08601u, 0x9b09e6adu, 0x3b3ee593u,
+ 0xe990fd5au, 0x9e34d797u, 0x2cf0b7d9u, 0x022b8b51u,
+ 0x96d5ac3au, 0x017da67du, 0xd1cf3ed6u, 0x7c7d2d28u,
+ 0x1f9f25cfu, 0xadf2b89bu, 0x5ad6b472u, 0x5a88f54cu,
+ 0xe029ac71u, 0xe019a5e6u, 0x47b0acfdu, 0xed93fa9bu,
+ 0xe8d3c48du, 0x283b57ccu, 0xf8d56629u, 0x79132e28u,
+ 0x785f0191u, 0xed756055u, 0xf7960e44u, 0xe3d35e8cu,
+ 0x15056dd4u, 0x88f46dbau, 0x03a16125u, 0x0564f0bdu,
+ 0xc3eb9e15u, 0x3c9057a2u, 0x97271aecu, 0xa93a072au,
+ 0x1b3f6d9bu, 0x1e6321f5u, 0xf59c66fbu, 0x26dcf319u,
+ 0x7533d928u, 0xb155fdf5u, 0x03563482u, 0x8aba3cbbu,
+ 0x28517711u, 0xc20ad9f8u, 0xabcc5167u, 0xccad925fu,
+ 0x4de81751u, 0x3830dc8eu, 0x379d5862u, 0x9320f991u,
+ 0xea7a90c2u, 0xfb3e7bceu, 0x5121ce64u, 0x774fbe32u,
+ 0xa8b6e37eu, 0xc3293d46u, 0x48de5369u, 0x6413e680u,
+ 0xa2ae0810u, 0xdd6db224u, 0x69852dfdu, 0x09072166u,
+ 0xb39a460au, 0x6445c0ddu, 0x586cdecfu, 0x1c20c8aeu,
+ 0x5bbef7ddu, 0x1b588d40u, 0xccd2017fu, 0x6bb4e3bbu,
+ 0xdda26a7eu, 0x3a59ff45u, 0x3e350a44u, 0xbcb4cdd5u,
+ 0x72eacea8u, 0xfa6484bbu, 0x8d6612aeu, 0xbf3c6f47u,
+ 0xd29be463u, 0x542f5d9eu, 0xaec2771bu, 0xf64e6370u,
+ 0x740e0d8du, 0xe75b1357u, 0xf8721671u, 0xaf537d5du,
+ 0x4040cb08u, 0x4eb4e2ccu, 0x34d2466au, 0x0115af84u,
+ 0xe1b00428u, 0x95983a1du, 0x06b89fb4u, 0xce6ea048u,
+ 0x6f3f3b82u, 0x3520ab82u, 0x011a1d4bu, 0x277227f8u,
+ 0x611560b1u, 0xe7933fdcu, 0xbb3a792bu, 0x344525bdu,
+ 0xa08839e1u, 0x51ce794bu, 0x2f32c9b7u, 0xa01fbac9u,
+ 0xe01cc87eu, 0xbcc7d1f6u, 0xcf0111c3u, 0xa1e8aac7u,
+ 0x1a908749u, 0xd44fbd9au, 0xd0dadecbu, 0xd50ada38u,
+ 0x0339c32au, 0xc6913667u, 0x8df9317cu, 0xe0b12b4fu,
+ 0xf79e59b7u, 0x43f5bb3au, 0xf2d519ffu, 0x27d9459cu,
+ 0xbf97222cu, 0x15e6fc2au, 0x0f91fc71u, 0x9b941525u,
+ 0xfae59361u, 0xceb69cebu, 0xc2a86459u, 0x12baa8d1u,
+ 0xb6c1075eu, 0xe3056a0cu, 0x10d25065u, 0xcb03a442u,
+ 0xe0ec6e0eu, 0x1698db3bu, 0x4c98a0beu, 0x3278e964u,
+ 0x9f1f9532u, 0xe0d392dfu, 0xd3a0342bu, 0x8971f21eu,
+ 0x1b0a7441u, 0x4ba3348cu, 0xc5be7120u, 0xc37632d8u,
+ 0xdf359f8du, 0x9b992f2eu, 0xe60b6f47u, 0x0fe3f11du,
+ 0xe54cda54u, 0x1edad891u, 0xce6279cfu, 0xcd3e7e6fu,
+ 0x1618b166u, 0xfd2c1d05u, 0x848fd2c5u, 0xf6fb2299u,
+ 0xf523f357u, 0xa6327623u, 0x93a83531u, 0x56cccd02u,
+ 0xacf08162u, 0x5a75ebb5u, 0x6e163697u, 0x88d273ccu,
+ 0xde966292u, 0x81b949d0u, 0x4c50901bu, 0x71c65614u,
+ 0xe6c6c7bdu, 0x327a140au, 0x45e1d006u, 0xc3f27b9au,
+ 0xc9aa53fdu, 0x62a80f00u, 0xbb25bfe2u, 0x35bdd2f6u,
+ 0x71126905u, 0xb2040222u, 0xb6cbcf7cu, 0xcd769c2bu,
+ 0x53113ec0u, 0x1640e3d3u, 0x38abbd60u, 0x2547adf0u,
+ 0xba38209cu, 0xf746ce76u, 0x77afa1c5u, 0x20756060u,
+ 0x85cbfe4eu, 0x8ae88dd8u, 0x7aaaf9b0u, 0x4cf9aa7eu,
+ 0x1948c25cu, 0x02fb8a8cu, 0x01c36ae4u, 0xd6ebe1f9u,
+ 0x90d4f869u, 0xa65cdea0u, 0x3f09252du, 0xc208e69fu,
+ 0xb74e6132u, 0xce77e25bu, 0x578fdfe3u, 0x3ac372e6u
+ }
+};
+
+#define F1(i) \
+ xl ^= bfs->pax[i]; \
+ xr ^= ((bfs->sbx[0][xl >> 24] + \
+ bfs->sbx[1][(xl & 0xFF0000) >> 16]) ^ \
+ bfs->sbx[2][(xl & 0xFF00) >> 8]) + \
+ bfs->sbx[3][xl & 0xFF];
+
+#define F2(i) \
+ xr ^= bfs->pax[i]; \
+ xl ^= ((bfs->sbx[0][xr >> 24] + \
+ bfs->sbx[1][(xr & 0xFF0000) >> 16]) ^ \
+ bfs->sbx[2][(xr & 0xFF00) >> 8]) + \
+ bfs->sbx[3][xr & 0xFF];
+
+ static void
+bf_e_block(
+ bf_state_T *bfs,
+ UINT32_T *p_xl,
+ UINT32_T *p_xr)
+{
+ UINT32_T temp;
+ UINT32_T xl = *p_xl;
+ UINT32_T xr = *p_xr;
+
+ F1(0) F2(1)
+ F1(2) F2(3)
+ F1(4) F2(5)
+ F1(6) F2(7)
+ F1(8) F2(9)
+ F1(10) F2(11)
+ F1(12) F2(13)
+ F1(14) F2(15)
+ xl ^= bfs->pax[16];
+ xr ^= bfs->pax[17];
+ temp = xl;
+ xl = xr;
+ xr = temp;
+ *p_xl = xl;
+ *p_xr = xr;
+}
+
+
+#ifdef WORDS_BIGENDIAN
+# define htonl2(x) \
+ x = ((((x) & 0xffL) << 24) | (((x) & 0xff00L) << 8) | \
+ (((x) & 0xff0000L) >> 8) | (((x) & 0xff000000L) >> 24))
+#else
+# define htonl2(x)
+#endif
+
+ static void
+bf_e_cblock(
+ bf_state_T *bfs,
+ char_u *block)
+{
+ block8 bk;
+
+ memcpy(bk.uc, block, 8);
+ htonl2(bk.ul[0]);
+ htonl2(bk.ul[1]);
+ bf_e_block(bfs, &bk.ul[0], &bk.ul[1]);
+ htonl2(bk.ul[0]);
+ htonl2(bk.ul[1]);
+ memcpy(block, bk.uc, 8);
+}
+
+/*
+ * Initialize the crypt method using "password" as the encryption key and
+ * "salt[salt_len]" as the salt.
+ */
+ static void
+bf_key_init(
+ bf_state_T *bfs,
+ char_u *password,
+ char_u *salt,
+ int salt_len)
+{
+ int i, j, keypos = 0;
+ unsigned u;
+ UINT32_T val, data_l, data_r;
+ char_u *key;
+ int keylen;
+
+ /* Process the key 1001 times.
+ * See http://en.wikipedia.org/wiki/Key_strengthening. */
+ key = sha256_key(password, salt, salt_len);
+ for (i = 0; i < 1000; i++)
+ key = sha256_key(key, salt, salt_len);
+
+ /* Convert the key from 64 hex chars to 32 binary chars. */
+ keylen = (int)STRLEN(key) / 2;
+ if (keylen == 0)
+ {
+ iemsg(_("E831: bf_key_init() called with empty password"));
+ return;
+ }
+ for (i = 0; i < keylen; i++)
+ {
+ sscanf((char *)&key[i * 2], "%2x", &u);
+ key[i] = u;
+ }
+
+ /* Use "key" to initialize the P-array ("pax") and S-boxes ("sbx") of
+ * Blowfish. */
+ mch_memmove(bfs->sbx, sbx_init, 4 * 4 * 256);
+
+ for (i = 0; i < 18; ++i)
+ {
+ val = 0;
+ for (j = 0; j < 4; ++j)
+ val = (val << 8) | key[keypos++ % keylen];
+ bfs->pax[i] = pax_init[i] ^ val;
+ }
+
+ data_l = data_r = 0;
+ for (i = 0; i < 18; i += 2)
+ {
+ bf_e_block(bfs, &data_l, &data_r);
+ bfs->pax[i + 0] = data_l;
+ bfs->pax[i + 1] = data_r;
+ }
+
+ for (i = 0; i < 4; ++i)
+ {
+ for (j = 0; j < 256; j += 2)
+ {
+ bf_e_block(bfs, &data_l, &data_r);
+ bfs->sbx[i][j + 0] = data_l;
+ bfs->sbx[i][j + 1] = data_r;
+ }
+ }
+}
+
+/*
+ * Blowfish self-test for corrupted tables or instructions.
+ */
+ static int
+bf_check_tables(
+ UINT32_T pax[18],
+ UINT32_T sbx[4][256],
+ UINT32_T val)
+{
+ int i, j;
+ UINT32_T c = 0;
+
+ for (i = 0; i < 18; i++)
+ c ^= pax[i];
+ for (i = 0; i < 4; i++)
+ for (j = 0; j < 256; j++)
+ c ^= sbx[i][j];
+ return c == val;
+}
+
+typedef struct {
+ char_u password[64];
+ char_u salt[9];
+ char_u plaintxt[9];
+ char_u cryptxt[9];
+ char_u badcryptxt[9]; /* cryptxt when big/little endian is wrong */
+ UINT32_T keysum;
+} struct_bf_test_data;
+
+/*
+ * Assert bf(password, plaintxt) is cryptxt.
+ * Assert csum(pax sbx(password)) is keysum.
+ */
+static struct_bf_test_data bf_test_data[] = {
+ {
+ "password",
+ "salt",
+ "plaintxt",
+ "\xad\x3d\xfa\x7f\xe8\xea\x40\xf6", /* cryptxt */
+ "\x72\x50\x3b\x38\x10\x60\x22\xa7", /* badcryptxt */
+ 0x56701b5du /* keysum */
+ },
+};
+
+/*
+ * Return FAIL when there is something wrong with blowfish encryption.
+ */
+ static int
+bf_self_test(void)
+{
+ int i, bn;
+ int err = 0;
+ block8 bk;
+ UINT32_T ui = 0xffffffffUL;
+ bf_state_T state;
+
+ vim_memset(&state, 0, sizeof(bf_state_T));
+ state.cfb_len = BF_MAX_CFB_LEN;
+
+ /* We can't simply use sizeof(UINT32_T), it would generate a compiler
+ * warning. */
+ if (ui != 0xffffffffUL || ui + 1 != 0) {
+ err++;
+ emsg(_("E820: sizeof(uint32_t) != 4"));
+ }
+
+ if (!bf_check_tables(pax_init, sbx_init, 0x6ffa520a))
+ err++;
+
+ bn = ARRAY_LENGTH(bf_test_data);
+ for (i = 0; i < bn; i++)
+ {
+ bf_key_init(&state, (char_u *)(bf_test_data[i].password),
+ bf_test_data[i].salt,
+ (int)STRLEN(bf_test_data[i].salt));
+ if (!bf_check_tables(state.pax, state.sbx, bf_test_data[i].keysum))
+ err++;
+
+ /* Don't modify bf_test_data[i].plaintxt, self test is idempotent. */
+ memcpy(bk.uc, bf_test_data[i].plaintxt, 8);
+ bf_e_cblock(&state, bk.uc);
+ if (memcmp(bk.uc, bf_test_data[i].cryptxt, 8) != 0)
+ {
+ if (err == 0 && memcmp(bk.uc, bf_test_data[i].badcryptxt, 8) == 0)
+ emsg(_("E817: Blowfish big/little endian use wrong"));
+ err++;
+ }
+ }
+
+ return err > 0 ? FAIL : OK;
+}
+
+/*
+ * CFB: Cipher Feedback Mode.
+ */
+
+/*
+ * Initialize with seed "seed[seed_len]".
+ */
+ static void
+bf_cfb_init(
+ bf_state_T *bfs,
+ char_u *seed,
+ int seed_len)
+{
+ int i, mi;
+
+ bfs->randbyte_offset = bfs->update_offset = 0;
+ vim_memset(bfs->cfb_buffer, 0, bfs->cfb_len);
+ if (seed_len > 0)
+ {
+ mi = seed_len > bfs->cfb_len ? seed_len : bfs->cfb_len;
+ for (i = 0; i < mi; i++)
+ bfs->cfb_buffer[i % bfs->cfb_len] ^= seed[i % seed_len];
+ }
+}
+
+#define BF_CFB_UPDATE(bfs, c) { \
+ bfs->cfb_buffer[bfs->update_offset] ^= (char_u)c; \
+ if (++bfs->update_offset == bfs->cfb_len) \
+ bfs->update_offset = 0; \
+}
+
+#define BF_RANBYTE(bfs, t) { \
+ if ((bfs->randbyte_offset & BF_BLOCK_MASK) == 0) \
+ bf_e_cblock(bfs, &(bfs->cfb_buffer[bfs->randbyte_offset])); \
+ t = bfs->cfb_buffer[bfs->randbyte_offset]; \
+ if (++bfs->randbyte_offset == bfs->cfb_len) \
+ bfs->randbyte_offset = 0; \
+}
+
+/*
+ * Encrypt "from[len]" into "to[len]".
+ * "from" and "to" can be equal to encrypt in place.
+ */
+ void
+crypt_blowfish_encode(
+ cryptstate_T *state,
+ char_u *from,
+ size_t len,
+ char_u *to)
+{
+ bf_state_T *bfs = state->method_state;
+ size_t i;
+ int ztemp, t;
+
+ for (i = 0; i < len; ++i)
+ {
+ ztemp = from[i];
+ BF_RANBYTE(bfs, t);
+ BF_CFB_UPDATE(bfs, ztemp);
+ to[i] = t ^ ztemp;
+ }
+}
+
+/*
+ * Decrypt "from[len]" into "to[len]".
+ */
+ void
+crypt_blowfish_decode(
+ cryptstate_T *state,
+ char_u *from,
+ size_t len,
+ char_u *to)
+{
+ bf_state_T *bfs = state->method_state;
+ size_t i;
+ int t;
+
+ for (i = 0; i < len; ++i)
+ {
+ BF_RANBYTE(bfs, t);
+ to[i] = from[i] ^ t;
+ BF_CFB_UPDATE(bfs, to[i]);
+ }
+}
+
+ void
+crypt_blowfish_init(
+ cryptstate_T *state,
+ char_u* key,
+ char_u* salt,
+ int salt_len,
+ char_u* seed,
+ int seed_len)
+{
+ bf_state_T *bfs = (bf_state_T *)alloc_clear(sizeof(bf_state_T));
+
+ state->method_state = bfs;
+
+ /* "blowfish" uses a 64 byte buffer, causing it to repeat 8 byte groups 8
+ * times. "blowfish2" uses a 8 byte buffer to avoid repeating. */
+ bfs->cfb_len = state->method_nr == CRYPT_M_BF ? BF_MAX_CFB_LEN : BF_BLOCK;
+
+ if (blowfish_self_test() == FAIL)
+ return;
+
+ bf_key_init(bfs, key, salt, salt_len);
+ bf_cfb_init(bfs, seed, seed_len);
+}
+
+/*
+ * Run a test to check if the encryption works as expected.
+ * Give an error and return FAIL when not.
+ */
+ int
+blowfish_self_test(void)
+{
+ if (sha256_self_test() == FAIL)
+ {
+ emsg(_("E818: sha256 test failed"));
+ return FAIL;
+ }
+ if (bf_self_test() == FAIL)
+ {
+ emsg(_("E819: Blowfish test failed"));
+ return FAIL;
+ }
+ return OK;
+}
+
+#endif /* FEAT_CRYPT */
diff --git a/src/buffer.c b/src/buffer.c
new file mode 100644
index 0000000..98d505f
--- /dev/null
+++ b/src/buffer.c
@@ -0,0 +1,5948 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * buffer.c: functions for dealing with the buffer structure
+ */
+
+/*
+ * The buffer list is a double linked list of all buffers.
+ * Each buffer can be in one of these states:
+ * never loaded: BF_NEVERLOADED is set, only the file name is valid
+ * not loaded: b_ml.ml_mfp == NULL, no memfile allocated
+ * hidden: b_nwindows == 0, loaded but not displayed in a window
+ * normal: loaded and displayed in a window
+ *
+ * Instead of storing file names all over the place, each file name is
+ * stored in the buffer list. It can be referenced by a number.
+ *
+ * The current implementation remembers all file names ever used.
+ */
+
+#include "vim.h"
+
+static char_u *buflist_match(regmatch_T *rmp, buf_T *buf, int ignore_case);
+static char_u *fname_match(regmatch_T *rmp, char_u *name, int ignore_case);
+static void buflist_setfpos(buf_T *buf, win_T *win, linenr_T lnum, colnr_T col, int copy_options);
+#ifdef UNIX
+static buf_T *buflist_findname_stat(char_u *ffname, stat_T *st);
+static int otherfile_buf(buf_T *buf, char_u *ffname, stat_T *stp);
+static int buf_same_ino(buf_T *buf, stat_T *stp);
+#else
+static int otherfile_buf(buf_T *buf, char_u *ffname);
+#endif
+#ifdef FEAT_TITLE
+static int value_changed(char_u *str, char_u **last);
+#endif
+static int append_arg_number(win_T *wp, char_u *buf, int buflen, int add_file);
+static void free_buffer(buf_T *);
+static void free_buffer_stuff(buf_T *buf, int free_options);
+static void clear_wininfo(buf_T *buf);
+
+#ifdef UNIX
+# define dev_T dev_t
+#else
+# define dev_T unsigned
+#endif
+
+#if defined(FEAT_QUICKFIX)
+static char *msg_loclist = N_("[Location List]");
+static char *msg_qflist = N_("[Quickfix List]");
+#endif
+static char *e_auabort = N_("E855: Autocommands caused command to abort");
+
+/* Number of times free_buffer() was called. */
+static int buf_free_count = 0;
+
+/* Read data from buffer for retrying. */
+ static int
+read_buffer(
+ int read_stdin, /* read file from stdin, otherwise fifo */
+ exarg_T *eap, /* for forced 'ff' and 'fenc' or NULL */
+ int flags) /* extra flags for readfile() */
+{
+ int retval = OK;
+ linenr_T line_count;
+
+ /*
+ * Read from the buffer which the text is already filled in and append at
+ * the end. This makes it possible to retry when 'fileformat' or
+ * 'fileencoding' was guessed wrong.
+ */
+ line_count = curbuf->b_ml.ml_line_count;
+ retval = readfile(
+ read_stdin ? NULL : curbuf->b_ffname,
+ read_stdin ? NULL : curbuf->b_fname,
+ (linenr_T)line_count, (linenr_T)0, (linenr_T)MAXLNUM, eap,
+ flags | READ_BUFFER);
+ if (retval == OK)
+ {
+ /* Delete the binary lines. */
+ while (--line_count >= 0)
+ ml_delete((linenr_T)1, FALSE);
+ }
+ else
+ {
+ /* Delete the converted lines. */
+ while (curbuf->b_ml.ml_line_count > line_count)
+ ml_delete(line_count, FALSE);
+ }
+ /* Put the cursor on the first line. */
+ curwin->w_cursor.lnum = 1;
+ curwin->w_cursor.col = 0;
+
+ if (read_stdin)
+ {
+ /* Set or reset 'modified' before executing autocommands, so that
+ * it can be changed there. */
+ if (!readonlymode && !BUFEMPTY())
+ changed();
+ else if (retval == OK)
+ unchanged(curbuf, FALSE);
+
+ if (retval == OK)
+ {
+#ifdef FEAT_EVAL
+ apply_autocmds_retval(EVENT_STDINREADPOST, NULL, NULL, FALSE,
+ curbuf, &retval);
+#else
+ apply_autocmds(EVENT_STDINREADPOST, NULL, NULL, FALSE, curbuf);
+#endif
+ }
+ }
+ return retval;
+}
+
+/*
+ * Open current buffer, that is: open the memfile and read the file into
+ * memory.
+ * Return FAIL for failure, OK otherwise.
+ */
+ int
+open_buffer(
+ int read_stdin, /* read file from stdin */
+ exarg_T *eap, /* for forced 'ff' and 'fenc' or NULL */
+ int flags) /* extra flags for readfile() */
+{
+ int retval = OK;
+ bufref_T old_curbuf;
+#ifdef FEAT_SYN_HL
+ long old_tw = curbuf->b_p_tw;
+#endif
+ int read_fifo = FALSE;
+
+ /*
+ * The 'readonly' flag is only set when BF_NEVERLOADED is being reset.
+ * When re-entering the same buffer, it should not change, because the
+ * user may have reset the flag by hand.
+ */
+ if (readonlymode && curbuf->b_ffname != NULL
+ && (curbuf->b_flags & BF_NEVERLOADED))
+ curbuf->b_p_ro = TRUE;
+
+ if (ml_open(curbuf) == FAIL)
+ {
+ /*
+ * There MUST be a memfile, otherwise we can't do anything
+ * If we can't create one for the current buffer, take another buffer
+ */
+ close_buffer(NULL, curbuf, 0, FALSE);
+ FOR_ALL_BUFFERS(curbuf)
+ if (curbuf->b_ml.ml_mfp != NULL)
+ break;
+ /*
+ * if there is no memfile at all, exit
+ * This is OK, since there are no changes to lose.
+ */
+ if (curbuf == NULL)
+ {
+ emsg(_("E82: Cannot allocate any buffer, exiting..."));
+ getout(2);
+ }
+ emsg(_("E83: Cannot allocate buffer, using other one..."));
+ enter_buffer(curbuf);
+#ifdef FEAT_SYN_HL
+ if (old_tw != curbuf->b_p_tw)
+ check_colorcolumn(curwin);
+#endif
+ return FAIL;
+ }
+
+ /* The autocommands in readfile() may change the buffer, but only AFTER
+ * reading the file. */
+ set_bufref(&old_curbuf, curbuf);
+ modified_was_set = FALSE;
+
+ /* mark cursor position as being invalid */
+ curwin->w_valid = 0;
+
+ if (curbuf->b_ffname != NULL
+#ifdef FEAT_NETBEANS_INTG
+ && netbeansReadFile
+#endif
+ )
+ {
+ int old_msg_silent = msg_silent;
+#ifdef UNIX
+ int save_bin = curbuf->b_p_bin;
+ int perm;
+#endif
+#ifdef FEAT_NETBEANS_INTG
+ int oldFire = netbeansFireChanges;
+
+ netbeansFireChanges = 0;
+#endif
+#ifdef UNIX
+ perm = mch_getperm(curbuf->b_ffname);
+ if (perm >= 0 && (S_ISFIFO(perm)
+ || S_ISSOCK(perm)
+# ifdef OPEN_CHR_FILES
+ || (S_ISCHR(perm) && is_dev_fd_file(curbuf->b_ffname))
+# endif
+ ))
+ read_fifo = TRUE;
+ if (read_fifo)
+ curbuf->b_p_bin = TRUE;
+#endif
+ if (shortmess(SHM_FILEINFO))
+ msg_silent = 1;
+ retval = readfile(curbuf->b_ffname, curbuf->b_fname,
+ (linenr_T)0, (linenr_T)0, (linenr_T)MAXLNUM, eap,
+ flags | READ_NEW | (read_fifo ? READ_FIFO : 0));
+#ifdef UNIX
+ if (read_fifo)
+ {
+ curbuf->b_p_bin = save_bin;
+ if (retval == OK)
+ retval = read_buffer(FALSE, eap, flags);
+ }
+#endif
+ msg_silent = old_msg_silent;
+#ifdef FEAT_NETBEANS_INTG
+ netbeansFireChanges = oldFire;
+#endif
+ /* Help buffer is filtered. */
+ if (bt_help(curbuf))
+ fix_help_buffer();
+ }
+ else if (read_stdin)
+ {
+ int save_bin = curbuf->b_p_bin;
+
+ /*
+ * First read the text in binary mode into the buffer.
+ * Then read from that same buffer and append at the end. This makes
+ * it possible to retry when 'fileformat' or 'fileencoding' was
+ * guessed wrong.
+ */
+ curbuf->b_p_bin = TRUE;
+ retval = readfile(NULL, NULL, (linenr_T)0,
+ (linenr_T)0, (linenr_T)MAXLNUM, NULL,
+ flags | (READ_NEW + READ_STDIN));
+ curbuf->b_p_bin = save_bin;
+ if (retval == OK)
+ retval = read_buffer(TRUE, eap, flags);
+ }
+
+ /* if first time loading this buffer, init b_chartab[] */
+ if (curbuf->b_flags & BF_NEVERLOADED)
+ {
+ (void)buf_init_chartab(curbuf, FALSE);
+#ifdef FEAT_CINDENT
+ parse_cino(curbuf);
+#endif
+ }
+
+ /*
+ * Set/reset the Changed flag first, autocmds may change the buffer.
+ * Apply the automatic commands, before processing the modelines.
+ * So the modelines have priority over autocommands.
+ */
+ /* When reading stdin, the buffer contents always needs writing, so set
+ * the changed flag. Unless in readonly mode: "ls | gview -".
+ * When interrupted and 'cpoptions' contains 'i' set changed flag. */
+ if ((got_int && vim_strchr(p_cpo, CPO_INTMOD) != NULL)
+ || modified_was_set /* ":set modified" used in autocmd */
+#ifdef FEAT_EVAL
+ || (aborting() && vim_strchr(p_cpo, CPO_INTMOD) != NULL)
+#endif
+ )
+ changed();
+ else if (retval == OK && !read_stdin && !read_fifo)
+ unchanged(curbuf, FALSE);
+ save_file_ff(curbuf); /* keep this fileformat */
+
+ /* Set last_changedtick to avoid triggering a TextChanged autocommand right
+ * after it was added. */
+ curbuf->b_last_changedtick = CHANGEDTICK(curbuf);
+#ifdef FEAT_INS_EXPAND
+ curbuf->b_last_changedtick_pum = CHANGEDTICK(curbuf);
+#endif
+
+ /* require "!" to overwrite the file, because it wasn't read completely */
+#ifdef FEAT_EVAL
+ if (aborting())
+#else
+ if (got_int)
+#endif
+ curbuf->b_flags |= BF_READERR;
+
+#ifdef FEAT_FOLDING
+ /* Need to update automatic folding. Do this before the autocommands,
+ * they may use the fold info. */
+ foldUpdateAll(curwin);
+#endif
+
+ /* need to set w_topline, unless some autocommand already did that. */
+ if (!(curwin->w_valid & VALID_TOPLINE))
+ {
+ curwin->w_topline = 1;
+#ifdef FEAT_DIFF
+ curwin->w_topfill = 0;
+#endif
+ }
+#ifdef FEAT_EVAL
+ apply_autocmds_retval(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf, &retval);
+#else
+ apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf);
+#endif
+
+ if (retval == OK)
+ {
+ /*
+ * The autocommands may have changed the current buffer. Apply the
+ * modelines to the correct buffer, if it still exists and is loaded.
+ */
+ if (bufref_valid(&old_curbuf) && old_curbuf.br_buf->b_ml.ml_mfp != NULL)
+ {
+ aco_save_T aco;
+
+ /* Go to the buffer that was opened. */
+ aucmd_prepbuf(&aco, old_curbuf.br_buf);
+ do_modelines(0);
+ curbuf->b_flags &= ~(BF_CHECK_RO | BF_NEVERLOADED);
+
+#ifdef FEAT_EVAL
+ apply_autocmds_retval(EVENT_BUFWINENTER, NULL, NULL, FALSE, curbuf,
+ &retval);
+#else
+ apply_autocmds(EVENT_BUFWINENTER, NULL, NULL, FALSE, curbuf);
+#endif
+
+ /* restore curwin/curbuf and a few other things */
+ aucmd_restbuf(&aco);
+ }
+ }
+
+ return retval;
+}
+
+/*
+ * Store "buf" in "bufref" and set the free count.
+ */
+ void
+set_bufref(bufref_T *bufref, buf_T *buf)
+{
+ bufref->br_buf = buf;
+ bufref->br_fnum = buf == NULL ? 0 : buf->b_fnum;
+ bufref->br_buf_free_count = buf_free_count;
+}
+
+/*
+ * Return TRUE if "bufref->br_buf" points to the same buffer as when
+ * set_bufref() was called and it is a valid buffer.
+ * Only goes through the buffer list if buf_free_count changed.
+ * Also checks if b_fnum is still the same, a :bwipe followed by :new might get
+ * the same allocated memory, but it's a different buffer.
+ */
+ int
+bufref_valid(bufref_T *bufref)
+{
+ return bufref->br_buf_free_count == buf_free_count
+ ? TRUE : buf_valid(bufref->br_buf)
+ && bufref->br_fnum == bufref->br_buf->b_fnum;
+}
+
+/*
+ * Return TRUE if "buf" points to a valid buffer (in the buffer list).
+ * This can be slow if there are many buffers, prefer using bufref_valid().
+ */
+ int
+buf_valid(buf_T *buf)
+{
+ buf_T *bp;
+
+ /* Assume that we more often have a recent buffer, start with the last
+ * one. */
+ for (bp = lastbuf; bp != NULL; bp = bp->b_prev)
+ if (bp == buf)
+ return TRUE;
+ return FALSE;
+}
+
+/*
+ * A hash table used to quickly lookup a buffer by its number.
+ */
+static hashtab_T buf_hashtab;
+
+ static void
+buf_hashtab_add(buf_T *buf)
+{
+ sprintf((char *)buf->b_key, "%x", buf->b_fnum);
+ if (hash_add(&buf_hashtab, buf->b_key) == FAIL)
+ emsg(_("E931: Buffer cannot be registered"));
+}
+
+ static void
+buf_hashtab_remove(buf_T *buf)
+{
+ hashitem_T *hi = hash_find(&buf_hashtab, buf->b_key);
+
+ if (!HASHITEM_EMPTY(hi))
+ hash_remove(&buf_hashtab, hi);
+}
+
+/*
+ * Return TRUE when buffer "buf" can be unloaded.
+ * Give an error message and return FALSE when the buffer is locked or the
+ * screen is being redrawn and the buffer is in a window.
+ */
+ static int
+can_unload_buffer(buf_T *buf)
+{
+ int can_unload = !buf->b_locked;
+
+ if (can_unload && updating_screen)
+ {
+ win_T *wp;
+
+ FOR_ALL_WINDOWS(wp)
+ if (wp->w_buffer == buf)
+ {
+ can_unload = FALSE;
+ break;
+ }
+ }
+ if (!can_unload)
+ emsg(_("E937: Attempt to delete a buffer that is in use"));
+ return can_unload;
+}
+
+/*
+ * Close the link to a buffer.
+ * "action" is used when there is no longer a window for the buffer.
+ * It can be:
+ * 0 buffer becomes hidden
+ * DOBUF_UNLOAD buffer is unloaded
+ * DOBUF_DELETE buffer is unloaded and removed from buffer list
+ * DOBUF_WIPE buffer is unloaded and really deleted
+ * When doing all but the first one on the current buffer, the caller should
+ * get a new buffer very soon!
+ *
+ * The 'bufhidden' option can force freeing and deleting.
+ *
+ * When "abort_if_last" is TRUE then do not close the buffer if autocommands
+ * cause there to be only one window with this buffer. e.g. when ":quit" is
+ * supposed to close the window but autocommands close all other windows.
+ */
+ void
+close_buffer(
+ win_T *win, /* if not NULL, set b_last_cursor */
+ buf_T *buf,
+ int action,
+ int abort_if_last UNUSED)
+{
+ int is_curbuf;
+ int nwindows;
+ bufref_T bufref;
+ int is_curwin = (curwin != NULL && curwin->w_buffer == buf);
+ win_T *the_curwin = curwin;
+ tabpage_T *the_curtab = curtab;
+ int unload_buf = (action != 0);
+ int del_buf = (action == DOBUF_DEL || action == DOBUF_WIPE);
+ int wipe_buf = (action == DOBUF_WIPE);
+
+ /*
+ * Force unloading or deleting when 'bufhidden' says so.
+ * The caller must take care of NOT deleting/freeing when 'bufhidden' is
+ * "hide" (otherwise we could never free or delete a buffer).
+ */
+ if (buf->b_p_bh[0] == 'd') /* 'bufhidden' == "delete" */
+ {
+ del_buf = TRUE;
+ unload_buf = TRUE;
+ }
+ else if (buf->b_p_bh[0] == 'w') /* 'bufhidden' == "wipe" */
+ {
+ del_buf = TRUE;
+ unload_buf = TRUE;
+ wipe_buf = TRUE;
+ }
+ else if (buf->b_p_bh[0] == 'u') /* 'bufhidden' == "unload" */
+ unload_buf = TRUE;
+
+#ifdef FEAT_TERMINAL
+ if (bt_terminal(buf) && (buf->b_nwindows == 1 || del_buf))
+ {
+ if (term_job_running(buf->b_term))
+ {
+ if (wipe_buf || unload_buf)
+ {
+ if (!can_unload_buffer(buf))
+ return;
+
+ /* Wiping out or unloading a terminal buffer kills the job. */
+ free_terminal(buf);
+ }
+ else
+ {
+ /* The job keeps running, hide the buffer. */
+ del_buf = FALSE;
+ unload_buf = FALSE;
+ }
+ }
+ else
+ {
+ /* A terminal buffer is wiped out if the job has finished. */
+ del_buf = TRUE;
+ unload_buf = TRUE;
+ wipe_buf = TRUE;
+ }
+ }
+#endif
+
+ /* Disallow deleting the buffer when it is locked (already being closed or
+ * halfway a command that relies on it). Unloading is allowed. */
+ if ((del_buf || wipe_buf) && !can_unload_buffer(buf))
+ return;
+
+ /* check no autocommands closed the window */
+ if (win != NULL && win_valid_any_tab(win))
+ {
+ /* Set b_last_cursor when closing the last window for the buffer.
+ * Remember the last cursor position and window options of the buffer.
+ * This used to be only for the current window, but then options like
+ * 'foldmethod' may be lost with a ":only" command. */
+ if (buf->b_nwindows == 1)
+ set_last_cursor(win);
+ buflist_setfpos(buf, win,
+ win->w_cursor.lnum == 1 ? 0 : win->w_cursor.lnum,
+ win->w_cursor.col, TRUE);
+ }
+
+ set_bufref(&bufref, buf);
+
+ /* When the buffer is no longer in a window, trigger BufWinLeave */
+ if (buf->b_nwindows == 1)
+ {
+ ++buf->b_locked;
+ if (apply_autocmds(EVENT_BUFWINLEAVE, buf->b_fname, buf->b_fname,
+ FALSE, buf)
+ && !bufref_valid(&bufref))
+ {
+ /* Autocommands deleted the buffer. */
+aucmd_abort:
+ emsg(_(e_auabort));
+ return;
+ }
+ --buf->b_locked;
+ if (abort_if_last && one_window())
+ /* Autocommands made this the only window. */
+ goto aucmd_abort;
+
+ /* When the buffer becomes hidden, but is not unloaded, trigger
+ * BufHidden */
+ if (!unload_buf)
+ {
+ ++buf->b_locked;
+ if (apply_autocmds(EVENT_BUFHIDDEN, buf->b_fname, buf->b_fname,
+ FALSE, buf)
+ && !bufref_valid(&bufref))
+ /* Autocommands deleted the buffer. */
+ goto aucmd_abort;
+ --buf->b_locked;
+ if (abort_if_last && one_window())
+ /* Autocommands made this the only window. */
+ goto aucmd_abort;
+ }
+#ifdef FEAT_EVAL
+ if (aborting()) /* autocmds may abort script processing */
+ return;
+#endif
+ }
+
+ /* If the buffer was in curwin and the window has changed, go back to that
+ * window, if it still exists. This avoids that ":edit x" triggering a
+ * "tabnext" BufUnload autocmd leaves a window behind without a buffer. */
+ if (is_curwin && curwin != the_curwin && win_valid_any_tab(the_curwin))
+ {
+ block_autocmds();
+ goto_tabpage_win(the_curtab, the_curwin);
+ unblock_autocmds();
+ }
+
+ nwindows = buf->b_nwindows;
+
+ /* decrease the link count from windows (unless not in any window) */
+ if (buf->b_nwindows > 0)
+ --buf->b_nwindows;
+
+#ifdef FEAT_DIFF
+ if (diffopt_hiddenoff() && !unload_buf && buf->b_nwindows == 0)
+ diff_buf_delete(buf); /* Clear 'diff' for hidden buffer. */
+#endif
+
+ /* Return when a window is displaying the buffer or when it's not
+ * unloaded. */
+ if (buf->b_nwindows > 0 || !unload_buf)
+ return;
+
+ /* Always remove the buffer when there is no file name. */
+ if (buf->b_ffname == NULL)
+ del_buf = TRUE;
+
+ /* When closing the current buffer stop Visual mode before freeing
+ * anything. */
+ if (buf == curbuf && VIsual_active
+#if defined(EXITFREE)
+ && !entered_free_all_mem
+#endif
+ )
+ end_visual_mode();
+
+ /*
+ * Free all things allocated for this buffer.
+ * Also calls the "BufDelete" autocommands when del_buf is TRUE.
+ */
+ /* Remember if we are closing the current buffer. Restore the number of
+ * windows, so that autocommands in buf_freeall() don't get confused. */
+ is_curbuf = (buf == curbuf);
+ buf->b_nwindows = nwindows;
+
+ buf_freeall(buf, (del_buf ? BFA_DEL : 0) + (wipe_buf ? BFA_WIPE : 0));
+
+ /* Autocommands may have deleted the buffer. */
+ if (!bufref_valid(&bufref))
+ return;
+#ifdef FEAT_EVAL
+ if (aborting()) /* autocmds may abort script processing */
+ return;
+#endif
+
+ /*
+ * It's possible that autocommands change curbuf to the one being deleted.
+ * This might cause the previous curbuf to be deleted unexpectedly. But
+ * in some cases it's OK to delete the curbuf, because a new one is
+ * obtained anyway. Therefore only return if curbuf changed to the
+ * deleted buffer.
+ */
+ if (buf == curbuf && !is_curbuf)
+ return;
+
+ if (win_valid_any_tab(win) && win->w_buffer == buf)
+ win->w_buffer = NULL; /* make sure we don't use the buffer now */
+
+ /* Autocommands may have opened or closed windows for this buffer.
+ * Decrement the count for the close we do here. */
+ if (buf->b_nwindows > 0)
+ --buf->b_nwindows;
+
+ /*
+ * Remove the buffer from the list.
+ */
+ if (wipe_buf)
+ {
+ if (buf->b_sfname != buf->b_ffname)
+ VIM_CLEAR(buf->b_sfname);
+ else
+ buf->b_sfname = NULL;
+ VIM_CLEAR(buf->b_ffname);
+ if (buf->b_prev == NULL)
+ firstbuf = buf->b_next;
+ else
+ buf->b_prev->b_next = buf->b_next;
+ if (buf->b_next == NULL)
+ lastbuf = buf->b_prev;
+ else
+ buf->b_next->b_prev = buf->b_prev;
+ free_buffer(buf);
+ }
+ else
+ {
+ if (del_buf)
+ {
+ /* Free all internal variables and reset option values, to make
+ * ":bdel" compatible with Vim 5.7. */
+ free_buffer_stuff(buf, TRUE);
+
+ /* Make it look like a new buffer. */
+ buf->b_flags = BF_CHECK_RO | BF_NEVERLOADED;
+
+ /* Init the options when loaded again. */
+ buf->b_p_initialized = FALSE;
+ }
+ buf_clear_file(buf);
+ if (del_buf)
+ buf->b_p_bl = FALSE;
+ }
+}
+
+/*
+ * Make buffer not contain a file.
+ */
+ void
+buf_clear_file(buf_T *buf)
+{
+ buf->b_ml.ml_line_count = 1;
+ unchanged(buf, TRUE);
+ buf->b_shortname = FALSE;
+ buf->b_p_eol = TRUE;
+ buf->b_start_eol = TRUE;
+ buf->b_p_bomb = FALSE;
+ buf->b_start_bomb = FALSE;
+ buf->b_ml.ml_mfp = NULL;
+ buf->b_ml.ml_flags = ML_EMPTY; /* empty buffer */
+#ifdef FEAT_NETBEANS_INTG
+ netbeans_deleted_all_lines(buf);
+#endif
+}
+
+/*
+ * buf_freeall() - free all things allocated for a buffer that are related to
+ * the file. Careful: get here with "curwin" NULL when exiting.
+ * flags:
+ * BFA_DEL buffer is going to be deleted
+ * BFA_WIPE buffer is going to be wiped out
+ * BFA_KEEP_UNDO do not free undo information
+ */
+ void
+buf_freeall(buf_T *buf, int flags)
+{
+ int is_curbuf = (buf == curbuf);
+ bufref_T bufref;
+ int is_curwin = (curwin != NULL && curwin->w_buffer == buf);
+ win_T *the_curwin = curwin;
+ tabpage_T *the_curtab = curtab;
+
+ /* Make sure the buffer isn't closed by autocommands. */
+ ++buf->b_locked;
+ set_bufref(&bufref, buf);
+ if (buf->b_ml.ml_mfp != NULL)
+ {
+ if (apply_autocmds(EVENT_BUFUNLOAD, buf->b_fname, buf->b_fname,
+ FALSE, buf)
+ && !bufref_valid(&bufref))
+ /* autocommands deleted the buffer */
+ return;
+ }
+ if ((flags & BFA_DEL) && buf->b_p_bl)
+ {
+ if (apply_autocmds(EVENT_BUFDELETE, buf->b_fname, buf->b_fname,
+ FALSE, buf)
+ && !bufref_valid(&bufref))
+ /* autocommands deleted the buffer */
+ return;
+ }
+ if (flags & BFA_WIPE)
+ {
+ if (apply_autocmds(EVENT_BUFWIPEOUT, buf->b_fname, buf->b_fname,
+ FALSE, buf)
+ && !bufref_valid(&bufref))
+ /* autocommands deleted the buffer */
+ return;
+ }
+ --buf->b_locked;
+
+ /* If the buffer was in curwin and the window has changed, go back to that
+ * window, if it still exists. This avoids that ":edit x" triggering a
+ * "tabnext" BufUnload autocmd leaves a window behind without a buffer. */
+ if (is_curwin && curwin != the_curwin && win_valid_any_tab(the_curwin))
+ {
+ block_autocmds();
+ goto_tabpage_win(the_curtab, the_curwin);
+ unblock_autocmds();
+ }
+
+#ifdef FEAT_EVAL
+ if (aborting()) /* autocmds may abort script processing */
+ return;
+#endif
+
+ /*
+ * It's possible that autocommands change curbuf to the one being deleted.
+ * This might cause curbuf to be deleted unexpectedly. But in some cases
+ * it's OK to delete the curbuf, because a new one is obtained anyway.
+ * Therefore only return if curbuf changed to the deleted buffer.
+ */
+ if (buf == curbuf && !is_curbuf)
+ return;
+#ifdef FEAT_DIFF
+ diff_buf_delete(buf); /* Can't use 'diff' for unloaded buffer. */
+#endif
+#ifdef FEAT_SYN_HL
+ /* Remove any ownsyntax, unless exiting. */
+ if (curwin != NULL && curwin->w_buffer == buf)
+ reset_synblock(curwin);
+#endif
+
+#ifdef FEAT_FOLDING
+ /* No folds in an empty buffer. */
+ {
+ win_T *win;
+ tabpage_T *tp;
+
+ FOR_ALL_TAB_WINDOWS(tp, win)
+ if (win->w_buffer == buf)
+ clearFolding(win);
+ }
+#endif
+
+#ifdef FEAT_TCL
+ tcl_buffer_free(buf);
+#endif
+ ml_close(buf, TRUE); /* close and delete the memline/memfile */
+ buf->b_ml.ml_line_count = 0; /* no lines in buffer */
+ if ((flags & BFA_KEEP_UNDO) == 0)
+ {
+ u_blockfree(buf); /* free the memory allocated for undo */
+ u_clearall(buf); /* reset all undo information */
+ }
+#ifdef FEAT_SYN_HL
+ syntax_clear(&buf->b_s); /* reset syntax info */
+#endif
+#ifdef FEAT_TEXT_PROP
+ clear_buf_prop_types(buf);
+#endif
+ buf->b_flags &= ~BF_READERR; /* a read error is no longer relevant */
+}
+
+/*
+ * Free a buffer structure and the things it contains related to the buffer
+ * itself (not the file, that must have been done already).
+ */
+ static void
+free_buffer(buf_T *buf)
+{
+ ++buf_free_count;
+ free_buffer_stuff(buf, TRUE);
+#ifdef FEAT_EVAL
+ /* b:changedtick uses an item in buf_T, remove it now */
+ dictitem_remove(buf->b_vars, (dictitem_T *)&buf->b_ct_di);
+ unref_var_dict(buf->b_vars);
+#endif
+#ifdef FEAT_LUA
+ lua_buffer_free(buf);
+#endif
+#ifdef FEAT_MZSCHEME
+ mzscheme_buffer_free(buf);
+#endif
+#ifdef FEAT_PERL
+ perl_buf_free(buf);
+#endif
+#ifdef FEAT_PYTHON
+ python_buffer_free(buf);
+#endif
+#ifdef FEAT_PYTHON3
+ python3_buffer_free(buf);
+#endif
+#ifdef FEAT_RUBY
+ ruby_buffer_free(buf);
+#endif
+#ifdef FEAT_JOB_CHANNEL
+ channel_buffer_free(buf);
+#endif
+#ifdef FEAT_TERMINAL
+ free_terminal(buf);
+#endif
+#ifdef FEAT_JOB_CHANNEL
+ vim_free(buf->b_prompt_text);
+ free_callback(buf->b_prompt_callback, buf->b_prompt_partial);
+#endif
+
+ buf_hashtab_remove(buf);
+
+ aubuflocal_remove(buf);
+
+ if (autocmd_busy)
+ {
+ /* Do not free the buffer structure while autocommands are executing,
+ * it's still needed. Free it when autocmd_busy is reset. */
+ buf->b_next = au_pending_free_buf;
+ au_pending_free_buf = buf;
+ }
+ else
+ vim_free(buf);
+}
+
+/*
+ * Initializes b:changedtick.
+ */
+ static void
+init_changedtick(buf_T *buf)
+{
+ dictitem_T *di = (dictitem_T *)&buf->b_ct_di;
+
+ di->di_flags = DI_FLAGS_FIX | DI_FLAGS_RO;
+ di->di_tv.v_type = VAR_NUMBER;
+ di->di_tv.v_lock = VAR_FIXED;
+ di->di_tv.vval.v_number = 0;
+
+#ifdef FEAT_EVAL
+ STRCPY(buf->b_ct_di.di_key, "changedtick");
+ (void)dict_add(buf->b_vars, di);
+#endif
+}
+
+/*
+ * Free stuff in the buffer for ":bdel" and when wiping out the buffer.
+ */
+ static void
+free_buffer_stuff(
+ buf_T *buf,
+ int free_options) /* free options as well */
+{
+ if (free_options)
+ {
+ clear_wininfo(buf); /* including window-local options */
+ free_buf_options(buf, TRUE);
+#ifdef FEAT_SPELL
+ ga_clear(&buf->b_s.b_langp);
+#endif
+ }
+#ifdef FEAT_EVAL
+ {
+ varnumber_T tick = CHANGEDTICK(buf);
+
+ vars_clear(&buf->b_vars->dv_hashtab); /* free all buffer variables */
+ hash_init(&buf->b_vars->dv_hashtab);
+ init_changedtick(buf);
+ CHANGEDTICK(buf) = tick;
+ }
+#endif
+#ifdef FEAT_USR_CMDS
+ uc_clear(&buf->b_ucmds); /* clear local user commands */
+#endif
+#ifdef FEAT_SIGNS
+ buf_delete_signs(buf, (char_u *)"*"); // delete any signs */
+#endif
+#ifdef FEAT_NETBEANS_INTG
+ netbeans_file_killed(buf);
+#endif
+#ifdef FEAT_LOCALMAP
+ map_clear_int(buf, MAP_ALL_MODES, TRUE, FALSE); /* clear local mappings */
+ map_clear_int(buf, MAP_ALL_MODES, TRUE, TRUE); /* clear local abbrevs */
+#endif
+ VIM_CLEAR(buf->b_start_fenc);
+}
+
+/*
+ * Free the b_wininfo list for buffer "buf".
+ */
+ static void
+clear_wininfo(buf_T *buf)
+{
+ wininfo_T *wip;
+
+ while (buf->b_wininfo != NULL)
+ {
+ wip = buf->b_wininfo;
+ buf->b_wininfo = wip->wi_next;
+ if (wip->wi_optset)
+ {
+ clear_winopt(&wip->wi_opt);
+#ifdef FEAT_FOLDING
+ deleteFoldRecurse(&wip->wi_folds);
+#endif
+ }
+ vim_free(wip);
+ }
+}
+
+/*
+ * Go to another buffer. Handles the result of the ATTENTION dialog.
+ */
+ void
+goto_buffer(
+ exarg_T *eap,
+ int start,
+ int dir,
+ int count)
+{
+#if defined(HAS_SWAP_EXISTS_ACTION)
+ bufref_T old_curbuf;
+
+ set_bufref(&old_curbuf, curbuf);
+
+ swap_exists_action = SEA_DIALOG;
+#endif
+ (void)do_buffer(*eap->cmd == 's' ? DOBUF_SPLIT : DOBUF_GOTO,
+ start, dir, count, eap->forceit);
+#if defined(HAS_SWAP_EXISTS_ACTION)
+ if (swap_exists_action == SEA_QUIT && *eap->cmd == 's')
+ {
+# if defined(FEAT_EVAL)
+ cleanup_T cs;
+
+ /* Reset the error/interrupt/exception state here so that
+ * aborting() returns FALSE when closing a window. */
+ enter_cleanup(&cs);
+# endif
+
+ /* Quitting means closing the split window, nothing else. */
+ win_close(curwin, TRUE);
+ swap_exists_action = SEA_NONE;
+ swap_exists_did_quit = TRUE;
+
+# if defined(FEAT_EVAL)
+ /* Restore the error/interrupt/exception state if not discarded by a
+ * new aborting error, interrupt, or uncaught exception. */
+ leave_cleanup(&cs);
+# endif
+ }
+ else
+ handle_swap_exists(&old_curbuf);
+#endif
+}
+
+#if defined(HAS_SWAP_EXISTS_ACTION) || defined(PROTO)
+/*
+ * Handle the situation of swap_exists_action being set.
+ * It is allowed for "old_curbuf" to be NULL or invalid.
+ */
+ void
+handle_swap_exists(bufref_T *old_curbuf)
+{
+# if defined(FEAT_EVAL)
+ cleanup_T cs;
+# endif
+# ifdef FEAT_SYN_HL
+ long old_tw = curbuf->b_p_tw;
+# endif
+ buf_T *buf;
+
+ if (swap_exists_action == SEA_QUIT)
+ {
+# if defined(FEAT_EVAL)
+ /* Reset the error/interrupt/exception state here so that
+ * aborting() returns FALSE when closing a buffer. */
+ enter_cleanup(&cs);
+# endif
+
+ /* User selected Quit at ATTENTION prompt. Go back to previous
+ * buffer. If that buffer is gone or the same as the current one,
+ * open a new, empty buffer. */
+ swap_exists_action = SEA_NONE; /* don't want it again */
+ swap_exists_did_quit = TRUE;
+ close_buffer(curwin, curbuf, DOBUF_UNLOAD, FALSE);
+ if (old_curbuf == NULL || !bufref_valid(old_curbuf)
+ || old_curbuf->br_buf == curbuf)
+ buf = buflist_new(NULL, NULL, 1L, BLN_CURBUF | BLN_LISTED);
+ else
+ buf = old_curbuf->br_buf;
+ if (buf != NULL)
+ {
+ int old_msg_silent = msg_silent;
+
+ if (shortmess(SHM_FILEINFO))
+ msg_silent = 1; // prevent fileinfo message
+ enter_buffer(buf);
+ // restore msg_silent, so that the command line will be shown
+ msg_silent = old_msg_silent;
+
+# ifdef FEAT_SYN_HL
+ if (old_tw != curbuf->b_p_tw)
+ check_colorcolumn(curwin);
+# endif
+ }
+ /* If "old_curbuf" is NULL we are in big trouble here... */
+
+# if defined(FEAT_EVAL)
+ /* Restore the error/interrupt/exception state if not discarded by a
+ * new aborting error, interrupt, or uncaught exception. */
+ leave_cleanup(&cs);
+# endif
+ }
+ else if (swap_exists_action == SEA_RECOVER)
+ {
+# if defined(FEAT_EVAL)
+ /* Reset the error/interrupt/exception state here so that
+ * aborting() returns FALSE when closing a buffer. */
+ enter_cleanup(&cs);
+# endif
+
+ /* User selected Recover at ATTENTION prompt. */
+ msg_scroll = TRUE;
+ ml_recover();
+ msg_puts("\n"); /* don't overwrite the last message */
+ cmdline_row = msg_row;
+ do_modelines(0);
+
+# if defined(FEAT_EVAL)
+ /* Restore the error/interrupt/exception state if not discarded by a
+ * new aborting error, interrupt, or uncaught exception. */
+ leave_cleanup(&cs);
+# endif
+ }
+ swap_exists_action = SEA_NONE;
+}
+#endif
+
+/*
+ * do_bufdel() - delete or unload buffer(s)
+ *
+ * addr_count == 0: ":bdel" - delete current buffer
+ * addr_count == 1: ":N bdel" or ":bdel N [N ..]" - first delete
+ * buffer "end_bnr", then any other arguments.
+ * addr_count == 2: ":N,N bdel" - delete buffers in range
+ *
+ * command can be DOBUF_UNLOAD (":bunload"), DOBUF_WIPE (":bwipeout") or
+ * DOBUF_DEL (":bdel")
+ *
+ * Returns error message or NULL
+ */
+ char *
+do_bufdel(
+ int command,
+ char_u *arg, /* pointer to extra arguments */
+ int addr_count,
+ int start_bnr, /* first buffer number in a range */
+ int end_bnr, /* buffer nr or last buffer nr in a range */
+ int forceit)
+{
+ int do_current = 0; /* delete current buffer? */
+ int deleted = 0; /* number of buffers deleted */
+ char *errormsg = NULL; /* return value */
+ int bnr; /* buffer number */
+ char_u *p;
+
+ if (addr_count == 0)
+ {
+ (void)do_buffer(command, DOBUF_CURRENT, FORWARD, 0, forceit);
+ }
+ else
+ {
+ if (addr_count == 2)
+ {
+ if (*arg) /* both range and argument is not allowed */
+ return _(e_trailing);
+ bnr = start_bnr;
+ }
+ else /* addr_count == 1 */
+ bnr = end_bnr;
+
+ for ( ;!got_int; ui_breakcheck())
+ {
+ /*
+ * delete the current buffer last, otherwise when the
+ * current buffer is deleted, the next buffer becomes
+ * the current one and will be loaded, which may then
+ * also be deleted, etc.
+ */
+ if (bnr == curbuf->b_fnum)
+ do_current = bnr;
+ else if (do_buffer(command, DOBUF_FIRST, FORWARD, (int)bnr,
+ forceit) == OK)
+ ++deleted;
+
+ /*
+ * find next buffer number to delete/unload
+ */
+ if (addr_count == 2)
+ {
+ if (++bnr > end_bnr)
+ break;
+ }
+ else /* addr_count == 1 */
+ {
+ arg = skipwhite(arg);
+ if (*arg == NUL)
+ break;
+ if (!VIM_ISDIGIT(*arg))
+ {
+ p = skiptowhite_esc(arg);
+ bnr = buflist_findpat(arg, p, command == DOBUF_WIPE,
+ FALSE, FALSE);
+ if (bnr < 0) /* failed */
+ break;
+ arg = p;
+ }
+ else
+ bnr = getdigits(&arg);
+ }
+ }
+ if (!got_int && do_current && do_buffer(command, DOBUF_FIRST,
+ FORWARD, do_current, forceit) == OK)
+ ++deleted;
+
+ if (deleted == 0)
+ {
+ if (command == DOBUF_UNLOAD)
+ STRCPY(IObuff, _("E515: No buffers were unloaded"));
+ else if (command == DOBUF_DEL)
+ STRCPY(IObuff, _("E516: No buffers were deleted"));
+ else
+ STRCPY(IObuff, _("E517: No buffers were wiped out"));
+ errormsg = (char *)IObuff;
+ }
+ else if (deleted >= p_report)
+ {
+ if (command == DOBUF_UNLOAD)
+ smsg(NGETTEXT("%d buffer unloaded",
+ "%d buffers unloaded", deleted), deleted);
+ else if (command == DOBUF_DEL)
+ smsg(NGETTEXT("%d buffer deleted",
+ "%d buffers deleted", deleted), deleted);
+ else
+ smsg(NGETTEXT("%d buffer wiped out",
+ "%d buffers wiped out", deleted), deleted);
+ }
+ }
+
+
+ return errormsg;
+}
+
+/*
+ * Make the current buffer empty.
+ * Used when it is wiped out and it's the last buffer.
+ */
+ static int
+empty_curbuf(
+ int close_others,
+ int forceit,
+ int action)
+{
+ int retval;
+ buf_T *buf = curbuf;
+ bufref_T bufref;
+
+ if (action == DOBUF_UNLOAD)
+ {
+ emsg(_("E90: Cannot unload last buffer"));
+ return FAIL;
+ }
+
+ set_bufref(&bufref, buf);
+ if (close_others)
+ /* Close any other windows on this buffer, then make it empty. */
+ close_windows(buf, TRUE);
+
+ setpcmark();
+ retval = do_ecmd(0, NULL, NULL, NULL, ECMD_ONE,
+ forceit ? ECMD_FORCEIT : 0, curwin);
+
+ /*
+ * do_ecmd() may create a new buffer, then we have to delete
+ * the old one. But do_ecmd() may have done that already, check
+ * if the buffer still exists.
+ */
+ if (buf != curbuf && bufref_valid(&bufref) && buf->b_nwindows == 0)
+ close_buffer(NULL, buf, action, FALSE);
+ if (!close_others)
+ need_fileinfo = FALSE;
+ return retval;
+}
+
+/*
+ * Implementation of the commands for the buffer list.
+ *
+ * action == DOBUF_GOTO go to specified buffer
+ * action == DOBUF_SPLIT split window and go to specified buffer
+ * action == DOBUF_UNLOAD unload specified buffer(s)
+ * action == DOBUF_DEL delete specified buffer(s) from buffer list
+ * action == DOBUF_WIPE delete specified buffer(s) really
+ *
+ * start == DOBUF_CURRENT go to "count" buffer from current buffer
+ * start == DOBUF_FIRST go to "count" buffer from first buffer
+ * start == DOBUF_LAST go to "count" buffer from last buffer
+ * start == DOBUF_MOD go to "count" modified buffer from current buffer
+ *
+ * Return FAIL or OK.
+ */
+ int
+do_buffer(
+ int action,
+ int start,
+ int dir, /* FORWARD or BACKWARD */
+ int count, /* buffer number or number of buffers */
+ int forceit) /* TRUE for :...! */
+{
+ buf_T *buf;
+ buf_T *bp;
+ int unload = (action == DOBUF_UNLOAD || action == DOBUF_DEL
+ || action == DOBUF_WIPE);
+
+ switch (start)
+ {
+ case DOBUF_FIRST: buf = firstbuf; break;
+ case DOBUF_LAST: buf = lastbuf; break;
+ default: buf = curbuf; break;
+ }
+ if (start == DOBUF_MOD) /* find next modified buffer */
+ {
+ while (count-- > 0)
+ {
+ do
+ {
+ buf = buf->b_next;
+ if (buf == NULL)
+ buf = firstbuf;
+ }
+ while (buf != curbuf && !bufIsChanged(buf));
+ }
+ if (!bufIsChanged(buf))
+ {
+ emsg(_("E84: No modified buffer found"));
+ return FAIL;
+ }
+ }
+ else if (start == DOBUF_FIRST && count) /* find specified buffer number */
+ {
+ while (buf != NULL && buf->b_fnum != count)
+ buf = buf->b_next;
+ }
+ else
+ {
+ bp = NULL;
+ while (count > 0 || (!unload && !buf->b_p_bl && bp != buf))
+ {
+ /* remember the buffer where we start, we come back there when all
+ * buffers are unlisted. */
+ if (bp == NULL)
+ bp = buf;
+ if (dir == FORWARD)
+ {
+ buf = buf->b_next;
+ if (buf == NULL)
+ buf = firstbuf;
+ }
+ else
+ {
+ buf = buf->b_prev;
+ if (buf == NULL)
+ buf = lastbuf;
+ }
+ /* don't count unlisted buffers */
+ if (unload || buf->b_p_bl)
+ {
+ --count;
+ bp = NULL; /* use this buffer as new starting point */
+ }
+ if (bp == buf)
+ {
+ /* back where we started, didn't find anything. */
+ emsg(_("E85: There is no listed buffer"));
+ return FAIL;
+ }
+ }
+ }
+
+ if (buf == NULL) /* could not find it */
+ {
+ if (start == DOBUF_FIRST)
+ {
+ /* don't warn when deleting */
+ if (!unload)
+ semsg(_(e_nobufnr), count);
+ }
+ else if (dir == FORWARD)
+ emsg(_("E87: Cannot go beyond last buffer"));
+ else
+ emsg(_("E88: Cannot go before first buffer"));
+ return FAIL;
+ }
+
+#ifdef FEAT_GUI
+ need_mouse_correct = TRUE;
+#endif
+
+ /*
+ * delete buffer buf from memory and/or the list
+ */
+ if (unload)
+ {
+ int forward;
+ bufref_T bufref;
+
+ if (!can_unload_buffer(buf))
+ return FAIL;
+
+ set_bufref(&bufref, buf);
+
+ /* When unloading or deleting a buffer that's already unloaded and
+ * unlisted: fail silently. */
+ if (action != DOBUF_WIPE && buf->b_ml.ml_mfp == NULL && !buf->b_p_bl)
+ return FAIL;
+
+ if (!forceit && bufIsChanged(buf))
+ {
+#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
+ if ((p_confirm || cmdmod.confirm) && p_write)
+ {
+ dialog_changed(buf, FALSE);
+ if (!bufref_valid(&bufref))
+ /* Autocommand deleted buffer, oops! It's not changed
+ * now. */
+ return FAIL;
+ /* If it's still changed fail silently, the dialog already
+ * mentioned why it fails. */
+ if (bufIsChanged(buf))
+ return FAIL;
+ }
+ else
+#endif
+ {
+ semsg(_("E89: No write since last change for buffer %d (add ! to override)"),
+ buf->b_fnum);
+ return FAIL;
+ }
+ }
+
+ /* When closing the current buffer stop Visual mode. */
+ if (buf == curbuf && VIsual_active)
+ end_visual_mode();
+
+ /*
+ * If deleting the last (listed) buffer, make it empty.
+ * The last (listed) buffer cannot be unloaded.
+ */
+ FOR_ALL_BUFFERS(bp)
+ if (bp->b_p_bl && bp != buf)
+ break;
+ if (bp == NULL && buf == curbuf)
+ return empty_curbuf(TRUE, forceit, action);
+
+ /*
+ * If the deleted buffer is the current one, close the current window
+ * (unless it's the only window). Repeat this so long as we end up in
+ * a window with this buffer.
+ */
+ while (buf == curbuf
+ && !(curwin->w_closing || curwin->w_buffer->b_locked > 0)
+ && (!ONE_WINDOW || first_tabpage->tp_next != NULL))
+ {
+ if (win_close(curwin, FALSE) == FAIL)
+ break;
+ }
+
+ /*
+ * If the buffer to be deleted is not the current one, delete it here.
+ */
+ if (buf != curbuf)
+ {
+ close_windows(buf, FALSE);
+ if (buf != curbuf && bufref_valid(&bufref) && buf->b_nwindows <= 0)
+ close_buffer(NULL, buf, action, FALSE);
+ return OK;
+ }
+
+ /*
+ * Deleting the current buffer: Need to find another buffer to go to.
+ * There should be another, otherwise it would have been handled
+ * above. However, autocommands may have deleted all buffers.
+ * First use au_new_curbuf.br_buf, if it is valid.
+ * Then prefer the buffer we most recently visited.
+ * Else try to find one that is loaded, after the current buffer,
+ * then before the current buffer.
+ * Finally use any buffer.
+ */
+ buf = NULL; /* selected buffer */
+ bp = NULL; /* used when no loaded buffer found */
+ if (au_new_curbuf.br_buf != NULL && bufref_valid(&au_new_curbuf))
+ buf = au_new_curbuf.br_buf;
+#ifdef FEAT_JUMPLIST
+ else if (curwin->w_jumplistlen > 0)
+ {
+ int jumpidx;
+
+ jumpidx = curwin->w_jumplistidx - 1;
+ if (jumpidx < 0)
+ jumpidx = curwin->w_jumplistlen - 1;
+
+ forward = jumpidx;
+ while (jumpidx != curwin->w_jumplistidx)
+ {
+ buf = buflist_findnr(curwin->w_jumplist[jumpidx].fmark.fnum);
+ if (buf != NULL)
+ {
+ if (buf == curbuf || !buf->b_p_bl)
+ buf = NULL; /* skip current and unlisted bufs */
+ else if (buf->b_ml.ml_mfp == NULL)
+ {
+ /* skip unloaded buf, but may keep it for later */
+ if (bp == NULL)
+ bp = buf;
+ buf = NULL;
+ }
+ }
+ if (buf != NULL) /* found a valid buffer: stop searching */
+ break;
+ /* advance to older entry in jump list */
+ if (!jumpidx && curwin->w_jumplistidx == curwin->w_jumplistlen)
+ break;
+ if (--jumpidx < 0)
+ jumpidx = curwin->w_jumplistlen - 1;
+ if (jumpidx == forward) /* List exhausted for sure */
+ break;
+ }
+ }
+#endif
+
+ if (buf == NULL) /* No previous buffer, Try 2'nd approach */
+ {
+ forward = TRUE;
+ buf = curbuf->b_next;
+ for (;;)
+ {
+ if (buf == NULL)
+ {
+ if (!forward) /* tried both directions */
+ break;
+ buf = curbuf->b_prev;
+ forward = FALSE;
+ continue;
+ }
+ /* in non-help buffer, try to skip help buffers, and vv */
+ if (buf->b_help == curbuf->b_help && buf->b_p_bl)
+ {
+ if (buf->b_ml.ml_mfp != NULL) /* found loaded buffer */
+ break;
+ if (bp == NULL) /* remember unloaded buf for later */
+ bp = buf;
+ }
+ if (forward)
+ buf = buf->b_next;
+ else
+ buf = buf->b_prev;
+ }
+ }
+ if (buf == NULL) /* No loaded buffer, use unloaded one */
+ buf = bp;
+ if (buf == NULL) /* No loaded buffer, find listed one */
+ {
+ FOR_ALL_BUFFERS(buf)
+ if (buf->b_p_bl && buf != curbuf)
+ break;
+ }
+ if (buf == NULL) /* Still no buffer, just take one */
+ {
+ if (curbuf->b_next != NULL)
+ buf = curbuf->b_next;
+ else
+ buf = curbuf->b_prev;
+ }
+ }
+
+ if (buf == NULL)
+ {
+ /* Autocommands must have wiped out all other buffers. Only option
+ * now is to make the current buffer empty. */
+ return empty_curbuf(FALSE, forceit, action);
+ }
+
+ /*
+ * make buf current buffer
+ */
+ if (action == DOBUF_SPLIT) /* split window first */
+ {
+ /* If 'switchbuf' contains "useopen": jump to first window containing
+ * "buf" if one exists */
+ if ((swb_flags & SWB_USEOPEN) && buf_jump_open_win(buf))
+ return OK;
+ /* If 'switchbuf' contains "usetab": jump to first window in any tab
+ * page containing "buf" if one exists */
+ if ((swb_flags & SWB_USETAB) && buf_jump_open_tab(buf))
+ return OK;
+ if (win_split(0, 0) == FAIL)
+ return FAIL;
+ }
+
+ /* go to current buffer - nothing to do */
+ if (buf == curbuf)
+ return OK;
+
+ /*
+ * Check if the current buffer may be abandoned.
+ */
+ if (action == DOBUF_GOTO && !can_abandon(curbuf, forceit))
+ {
+#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
+ if ((p_confirm || cmdmod.confirm) && p_write)
+ {
+ bufref_T bufref;
+
+ set_bufref(&bufref, buf);
+ dialog_changed(curbuf, FALSE);
+ if (!bufref_valid(&bufref))
+ /* Autocommand deleted buffer, oops! */
+ return FAIL;
+ }
+ if (bufIsChanged(curbuf))
+#endif
+ {
+ no_write_message();
+ return FAIL;
+ }
+ }
+
+ /* Go to the other buffer. */
+ set_curbuf(buf, action);
+
+ if (action == DOBUF_SPLIT)
+ {
+ RESET_BINDING(curwin); /* reset 'scrollbind' and 'cursorbind' */
+ }
+
+#if defined(FEAT_EVAL)
+ if (aborting()) /* autocmds may abort script processing */
+ return FAIL;
+#endif
+
+ return OK;
+}
+
+/*
+ * Set current buffer to "buf". Executes autocommands and closes current
+ * buffer. "action" tells how to close the current buffer:
+ * DOBUF_GOTO free or hide it
+ * DOBUF_SPLIT nothing
+ * DOBUF_UNLOAD unload it
+ * DOBUF_DEL delete it
+ * DOBUF_WIPE wipe it out
+ */
+ void
+set_curbuf(buf_T *buf, int action)
+{
+ buf_T *prevbuf;
+ int unload = (action == DOBUF_UNLOAD || action == DOBUF_DEL
+ || action == DOBUF_WIPE);
+#ifdef FEAT_SYN_HL
+ long old_tw = curbuf->b_p_tw;
+#endif
+ bufref_T newbufref;
+ bufref_T prevbufref;
+
+ setpcmark();
+ if (!cmdmod.keepalt)
+ curwin->w_alt_fnum = curbuf->b_fnum; /* remember alternate file */
+ buflist_altfpos(curwin); /* remember curpos */
+
+ /* Don't restart Select mode after switching to another buffer. */
+ VIsual_reselect = FALSE;
+
+ /* close_windows() or apply_autocmds() may change curbuf and wipe out "buf"
+ */
+ prevbuf = curbuf;
+ set_bufref(&prevbufref, prevbuf);
+ set_bufref(&newbufref, buf);
+
+ /* Autocommands may delete the curren buffer and/or the buffer we wan to go
+ * to. In those cases don't close the buffer. */
+ if (!apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, FALSE, curbuf)
+ || (bufref_valid(&prevbufref)
+ && bufref_valid(&newbufref)
+#ifdef FEAT_EVAL
+ && !aborting()
+#endif
+ ))
+ {
+#ifdef FEAT_SYN_HL
+ if (prevbuf == curwin->w_buffer)
+ reset_synblock(curwin);
+#endif
+ if (unload)
+ close_windows(prevbuf, FALSE);
+#if defined(FEAT_EVAL)
+ if (bufref_valid(&prevbufref) && !aborting())
+#else
+ if (bufref_valid(&prevbufref))
+#endif
+ {
+ win_T *previouswin = curwin;
+ if (prevbuf == curbuf)
+ u_sync(FALSE);
+ close_buffer(prevbuf == curwin->w_buffer ? curwin : NULL, prevbuf,
+ unload ? action : (action == DOBUF_GOTO
+ && !buf_hide(prevbuf)
+ && !bufIsChanged(prevbuf)) ? DOBUF_UNLOAD : 0, FALSE);
+ if (curwin != previouswin && win_valid(previouswin))
+ /* autocommands changed curwin, Grr! */
+ curwin = previouswin;
+ }
+ }
+ /* An autocommand may have deleted "buf", already entered it (e.g., when
+ * it did ":bunload") or aborted the script processing.
+ * If curwin->w_buffer is null, enter_buffer() will make it valid again */
+ if ((buf_valid(buf) && buf != curbuf
+#ifdef FEAT_EVAL
+ && !aborting()
+#endif
+ ) || curwin->w_buffer == NULL)
+ {
+ enter_buffer(buf);
+#ifdef FEAT_SYN_HL
+ if (old_tw != curbuf->b_p_tw)
+ check_colorcolumn(curwin);
+#endif
+ }
+}
+
+/*
+ * Enter a new current buffer.
+ * Old curbuf must have been abandoned already! This also means "curbuf" may
+ * be pointing to freed memory.
+ */
+ void
+enter_buffer(buf_T *buf)
+{
+ /* Copy buffer and window local option values. Not for a help buffer. */
+ buf_copy_options(buf, BCO_ENTER | BCO_NOHELP);
+ if (!buf->b_help)
+ get_winopts(buf);
+#ifdef FEAT_FOLDING
+ else
+ /* Remove all folds in the window. */
+ clearFolding(curwin);
+ foldUpdateAll(curwin); /* update folds (later). */
+#endif
+
+ /* Get the buffer in the current window. */
+ curwin->w_buffer = buf;
+ curbuf = buf;
+ ++curbuf->b_nwindows;
+
+#ifdef FEAT_DIFF
+ if (curwin->w_p_diff)
+ diff_buf_add(curbuf);
+#endif
+
+#ifdef FEAT_SYN_HL
+ curwin->w_s = &(curbuf->b_s);
+#endif
+
+ /* Cursor on first line by default. */
+ curwin->w_cursor.lnum = 1;
+ curwin->w_cursor.col = 0;
+ curwin->w_cursor.coladd = 0;
+ curwin->w_set_curswant = TRUE;
+ curwin->w_topline_was_set = FALSE;
+
+ /* mark cursor position as being invalid */
+ curwin->w_valid = 0;
+
+ buflist_setfpos(curbuf, curwin, curbuf->b_last_cursor.lnum,
+ curbuf->b_last_cursor.col, TRUE);
+
+ /* Make sure the buffer is loaded. */
+ if (curbuf->b_ml.ml_mfp == NULL) /* need to load the file */
+ {
+ /* If there is no filetype, allow for detecting one. Esp. useful for
+ * ":ball" used in a autocommand. If there already is a filetype we
+ * might prefer to keep it. */
+ if (*curbuf->b_p_ft == NUL)
+ did_filetype = FALSE;
+
+ open_buffer(FALSE, NULL, 0);
+ }
+ else
+ {
+ if (!msg_silent)
+ need_fileinfo = TRUE; /* display file info after redraw */
+ (void)buf_check_timestamp(curbuf, FALSE); /* check if file changed */
+ curwin->w_topline = 1;
+#ifdef FEAT_DIFF
+ curwin->w_topfill = 0;
+#endif
+ apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf);
+ apply_autocmds(EVENT_BUFWINENTER, NULL, NULL, FALSE, curbuf);
+ }
+
+ /* If autocommands did not change the cursor position, restore cursor lnum
+ * and possibly cursor col. */
+ if (curwin->w_cursor.lnum == 1 && inindent(0))
+ buflist_getfpos();
+
+ check_arg_idx(curwin); /* check for valid arg_idx */
+#ifdef FEAT_TITLE
+ maketitle();
+#endif
+ /* when autocmds didn't change it */
+ if (curwin->w_topline == 1 && !curwin->w_topline_was_set)
+ scroll_cursor_halfway(FALSE); /* redisplay at correct position */
+
+#ifdef FEAT_NETBEANS_INTG
+ /* Send fileOpened event because we've changed buffers. */
+ netbeans_file_activated(curbuf);
+#endif
+
+ /* Change directories when the 'acd' option is set. */
+ DO_AUTOCHDIR;
+
+#ifdef FEAT_KEYMAP
+ if (curbuf->b_kmap_state & KEYMAP_INIT)
+ (void)keymap_init();
+#endif
+#ifdef FEAT_SPELL
+ /* May need to set the spell language. Can only do this after the buffer
+ * has been properly setup. */
+ if (!curbuf->b_help && curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
+ (void)did_set_spelllang(curwin);
+#endif
+#ifdef FEAT_VIMINFO
+ curbuf->b_last_used = vim_time();
+#endif
+
+ redraw_later(NOT_VALID);
+}
+
+#if defined(FEAT_AUTOCHDIR) || defined(PROTO)
+/*
+ * Change to the directory of the current buffer.
+ * Don't do this while still starting up.
+ */
+ void
+do_autochdir(void)
+{
+ if ((starting == 0 || test_autochdir)
+ && curbuf->b_ffname != NULL
+ && vim_chdirfile(curbuf->b_ffname, "auto") == OK)
+ shorten_fnames(TRUE);
+}
+#endif
+
+ void
+no_write_message(void)
+{
+#ifdef FEAT_TERMINAL
+ if (term_job_running(curbuf->b_term))
+ emsg(_("E948: Job still running (add ! to end the job)"));
+ else
+#endif
+ emsg(_("E37: No write since last change (add ! to override)"));
+}
+
+ void
+no_write_message_nobang(buf_T *buf UNUSED)
+{
+#ifdef FEAT_TERMINAL
+ if (term_job_running(buf->b_term))
+ emsg(_("E948: Job still running"));
+ else
+#endif
+ emsg(_("E37: No write since last change"));
+}
+
+/*
+ * functions for dealing with the buffer list
+ */
+
+static int top_file_num = 1; /* highest file number */
+
+/*
+ * Return TRUE if the current buffer is empty, unnamed, unmodified and used in
+ * only one window. That means it can be re-used.
+ */
+ int
+curbuf_reusable(void)
+{
+ return (curbuf != NULL
+ && curbuf->b_ffname == NULL
+ && curbuf->b_nwindows <= 1
+ && (curbuf->b_ml.ml_mfp == NULL || BUFEMPTY())
+ && !curbufIsChanged());
+}
+
+/*
+ * Add a file name to the buffer list. Return a pointer to the buffer.
+ * If the same file name already exists return a pointer to that buffer.
+ * If it does not exist, or if fname == NULL, a new entry is created.
+ * If (flags & BLN_CURBUF) is TRUE, may use current buffer.
+ * If (flags & BLN_LISTED) is TRUE, add new buffer to buffer list.
+ * If (flags & BLN_DUMMY) is TRUE, don't count it as a real buffer.
+ * If (flags & BLN_NEW) is TRUE, don't use an existing buffer.
+ * If (flags & BLN_NOOPT) is TRUE, don't copy options from the current buffer
+ * if the buffer already exists.
+ * This is the ONLY way to create a new buffer.
+ */
+ buf_T *
+buflist_new(
+ char_u *ffname_arg, // full path of fname or relative
+ char_u *sfname_arg, // short fname or NULL
+ linenr_T lnum, // preferred cursor line
+ int flags) // BLN_ defines
+{
+ char_u *ffname = ffname_arg;
+ char_u *sfname = sfname_arg;
+ buf_T *buf;
+#ifdef UNIX
+ stat_T st;
+#endif
+
+ if (top_file_num == 1)
+ hash_init(&buf_hashtab);
+
+ fname_expand(curbuf, &ffname, &sfname); // will allocate ffname
+
+ /*
+ * If file name already exists in the list, update the entry.
+ */
+#ifdef UNIX
+ /* On Unix we can use inode numbers when the file exists. Works better
+ * for hard links. */
+ if (sfname == NULL || mch_stat((char *)sfname, &st) < 0)
+ st.st_dev = (dev_T)-1;
+#endif
+ if (ffname != NULL && !(flags & (BLN_DUMMY | BLN_NEW)) && (buf =
+#ifdef UNIX
+ buflist_findname_stat(ffname, &st)
+#else
+ buflist_findname(ffname)
+#endif
+ ) != NULL)
+ {
+ vim_free(ffname);
+ if (lnum != 0)
+ buflist_setfpos(buf, curwin, lnum, (colnr_T)0, FALSE);
+
+ if ((flags & BLN_NOOPT) == 0)
+ /* copy the options now, if 'cpo' doesn't have 's' and not done
+ * already */
+ buf_copy_options(buf, 0);
+
+ if ((flags & BLN_LISTED) && !buf->b_p_bl)
+ {
+ bufref_T bufref;
+
+ buf->b_p_bl = TRUE;
+ set_bufref(&bufref, buf);
+ if (!(flags & BLN_DUMMY))
+ {
+ if (apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, buf)
+ && !bufref_valid(&bufref))
+ return NULL;
+ }
+ }
+ return buf;
+ }
+
+ /*
+ * If the current buffer has no name and no contents, use the current
+ * buffer. Otherwise: Need to allocate a new buffer structure.
+ *
+ * This is the ONLY place where a new buffer structure is allocated!
+ * (A spell file buffer is allocated in spell.c, but that's not a normal
+ * buffer.)
+ */
+ buf = NULL;
+ if ((flags & BLN_CURBUF) && curbuf_reusable())
+ {
+ buf = curbuf;
+ /* It's like this buffer is deleted. Watch out for autocommands that
+ * change curbuf! If that happens, allocate a new buffer anyway. */
+ if (curbuf->b_p_bl)
+ apply_autocmds(EVENT_BUFDELETE, NULL, NULL, FALSE, curbuf);
+ if (buf == curbuf)
+ apply_autocmds(EVENT_BUFWIPEOUT, NULL, NULL, FALSE, curbuf);
+#ifdef FEAT_EVAL
+ if (aborting()) /* autocmds may abort script processing */
+ return NULL;
+#endif
+ if (buf == curbuf)
+ {
+ /* Make sure 'bufhidden' and 'buftype' are empty */
+ clear_string_option(&buf->b_p_bh);
+ clear_string_option(&buf->b_p_bt);
+ }
+ }
+ if (buf != curbuf || curbuf == NULL)
+ {
+ buf = (buf_T *)alloc_clear((unsigned)sizeof(buf_T));
+ if (buf == NULL)
+ {
+ vim_free(ffname);
+ return NULL;
+ }
+#ifdef FEAT_EVAL
+ /* init b: variables */
+ buf->b_vars = dict_alloc();
+ if (buf->b_vars == NULL)
+ {
+ vim_free(ffname);
+ vim_free(buf);
+ return NULL;
+ }
+ init_var_dict(buf->b_vars, &buf->b_bufvar, VAR_SCOPE);
+#endif
+ init_changedtick(buf);
+ }
+
+ if (ffname != NULL)
+ {
+ buf->b_ffname = ffname;
+ buf->b_sfname = vim_strsave(sfname);
+ }
+
+ clear_wininfo(buf);
+ buf->b_wininfo = (wininfo_T *)alloc_clear((unsigned)sizeof(wininfo_T));
+
+ if ((ffname != NULL && (buf->b_ffname == NULL || buf->b_sfname == NULL))
+ || buf->b_wininfo == NULL)
+ {
+ if (buf->b_sfname != buf->b_ffname)
+ VIM_CLEAR(buf->b_sfname);
+ else
+ buf->b_sfname = NULL;
+ VIM_CLEAR(buf->b_ffname);
+ if (buf != curbuf)
+ free_buffer(buf);
+ return NULL;
+ }
+
+ if (buf == curbuf)
+ {
+ /* free all things allocated for this buffer */
+ buf_freeall(buf, 0);
+ if (buf != curbuf) /* autocommands deleted the buffer! */
+ return NULL;
+#if defined(FEAT_EVAL)
+ if (aborting()) /* autocmds may abort script processing */
+ return NULL;
+#endif
+ free_buffer_stuff(buf, FALSE); /* delete local variables et al. */
+
+ /* Init the options. */
+ buf->b_p_initialized = FALSE;
+ buf_copy_options(buf, BCO_ENTER);
+
+#ifdef FEAT_KEYMAP
+ /* need to reload lmaps and set b:keymap_name */
+ curbuf->b_kmap_state |= KEYMAP_INIT;
+#endif
+ }
+ else
+ {
+ /*
+ * put new buffer at the end of the buffer list
+ */
+ buf->b_next = NULL;
+ if (firstbuf == NULL) /* buffer list is empty */
+ {
+ buf->b_prev = NULL;
+ firstbuf = buf;
+ }
+ else /* append new buffer at end of list */
+ {
+ lastbuf->b_next = buf;
+ buf->b_prev = lastbuf;
+ }
+ lastbuf = buf;
+
+ buf->b_fnum = top_file_num++;
+ if (top_file_num < 0) /* wrap around (may cause duplicates) */
+ {
+ emsg(_("W14: Warning: List of file names overflow"));
+ if (emsg_silent == 0)
+ {
+ out_flush();
+ ui_delay(3000L, TRUE); /* make sure it is noticed */
+ }
+ top_file_num = 1;
+ }
+ buf_hashtab_add(buf);
+
+ /*
+ * Always copy the options from the current buffer.
+ */
+ buf_copy_options(buf, BCO_ALWAYS);
+ }
+
+ buf->b_wininfo->wi_fpos.lnum = lnum;
+ buf->b_wininfo->wi_win = curwin;
+
+#ifdef FEAT_SYN_HL
+ hash_init(&buf->b_s.b_keywtab);
+ hash_init(&buf->b_s.b_keywtab_ic);
+#endif
+
+ buf->b_fname = buf->b_sfname;
+#ifdef UNIX
+ if (st.st_dev == (dev_T)-1)
+ buf->b_dev_valid = FALSE;
+ else
+ {
+ buf->b_dev_valid = TRUE;
+ buf->b_dev = st.st_dev;
+ buf->b_ino = st.st_ino;
+ }
+#endif
+ buf->b_u_synced = TRUE;
+ buf->b_flags = BF_CHECK_RO | BF_NEVERLOADED;
+ if (flags & BLN_DUMMY)
+ buf->b_flags |= BF_DUMMY;
+ buf_clear_file(buf);
+ clrallmarks(buf); /* clear marks */
+ fmarks_check_names(buf); /* check file marks for this file */
+ buf->b_p_bl = (flags & BLN_LISTED) ? TRUE : FALSE; /* init 'buflisted' */
+ if (!(flags & BLN_DUMMY))
+ {
+ bufref_T bufref;
+
+ /* Tricky: these autocommands may change the buffer list. They could
+ * also split the window with re-using the one empty buffer. This may
+ * result in unexpectedly losing the empty buffer. */
+ set_bufref(&bufref, buf);
+ if (apply_autocmds(EVENT_BUFNEW, NULL, NULL, FALSE, buf)
+ && !bufref_valid(&bufref))
+ return NULL;
+ if (flags & BLN_LISTED)
+ {
+ if (apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, buf)
+ && !bufref_valid(&bufref))
+ return NULL;
+ }
+#ifdef FEAT_EVAL
+ if (aborting()) /* autocmds may abort script processing */
+ return NULL;
+#endif
+ }
+
+ return buf;
+}
+
+/*
+ * Free the memory for the options of a buffer.
+ * If "free_p_ff" is TRUE also free 'fileformat', 'buftype' and
+ * 'fileencoding'.
+ */
+ void
+free_buf_options(
+ buf_T *buf,
+ int free_p_ff)
+{
+ if (free_p_ff)
+ {
+ clear_string_option(&buf->b_p_fenc);
+ clear_string_option(&buf->b_p_ff);
+ clear_string_option(&buf->b_p_bh);
+ clear_string_option(&buf->b_p_bt);
+ }
+#ifdef FEAT_FIND_ID
+ clear_string_option(&buf->b_p_def);
+ clear_string_option(&buf->b_p_inc);
+# ifdef FEAT_EVAL
+ clear_string_option(&buf->b_p_inex);
+# endif
+#endif
+#if defined(FEAT_CINDENT) && defined(FEAT_EVAL)
+ clear_string_option(&buf->b_p_inde);
+ clear_string_option(&buf->b_p_indk);
+#endif
+#if defined(FEAT_BEVAL) && defined(FEAT_EVAL)
+ clear_string_option(&buf->b_p_bexpr);
+#endif
+#if defined(FEAT_CRYPT)
+ clear_string_option(&buf->b_p_cm);
+#endif
+ clear_string_option(&buf->b_p_fp);
+#if defined(FEAT_EVAL)
+ clear_string_option(&buf->b_p_fex);
+#endif
+#ifdef FEAT_CRYPT
+ clear_string_option(&buf->b_p_key);
+#endif
+ clear_string_option(&buf->b_p_kp);
+ clear_string_option(&buf->b_p_mps);
+ clear_string_option(&buf->b_p_fo);
+ clear_string_option(&buf->b_p_flp);
+ clear_string_option(&buf->b_p_isk);
+#ifdef FEAT_VARTABS
+ clear_string_option(&buf->b_p_vsts);
+ if (buf->b_p_vsts_nopaste)
+ vim_free(buf->b_p_vsts_nopaste);
+ buf->b_p_vsts_nopaste = NULL;
+ if (buf->b_p_vsts_array)
+ vim_free(buf->b_p_vsts_array);
+ buf->b_p_vsts_array = NULL;
+ clear_string_option(&buf->b_p_vts);
+ if (buf->b_p_vts_array)
+ vim_free(buf->b_p_vts_array);
+ buf->b_p_vts_array = NULL;
+#endif
+#ifdef FEAT_KEYMAP
+ clear_string_option(&buf->b_p_keymap);
+ keymap_clear(&buf->b_kmap_ga);
+ ga_clear(&buf->b_kmap_ga);
+#endif
+#ifdef FEAT_COMMENTS
+ clear_string_option(&buf->b_p_com);
+#endif
+#ifdef FEAT_FOLDING
+ clear_string_option(&buf->b_p_cms);
+#endif
+ clear_string_option(&buf->b_p_nf);
+#ifdef FEAT_SYN_HL
+ clear_string_option(&buf->b_p_syn);
+ clear_string_option(&buf->b_s.b_syn_isk);
+#endif
+#ifdef FEAT_SPELL
+ clear_string_option(&buf->b_s.b_p_spc);
+ clear_string_option(&buf->b_s.b_p_spf);
+ vim_regfree(buf->b_s.b_cap_prog);
+ buf->b_s.b_cap_prog = NULL;
+ clear_string_option(&buf->b_s.b_p_spl);
+#endif
+#ifdef FEAT_SEARCHPATH
+ clear_string_option(&buf->b_p_sua);
+#endif
+ clear_string_option(&buf->b_p_ft);
+#ifdef FEAT_CINDENT
+ clear_string_option(&buf->b_p_cink);
+ clear_string_option(&buf->b_p_cino);
+#endif
+#if defined(FEAT_CINDENT) || defined(FEAT_SMARTINDENT)
+ clear_string_option(&buf->b_p_cinw);
+#endif
+#ifdef FEAT_INS_EXPAND
+ clear_string_option(&buf->b_p_cpt);
+#endif
+#ifdef FEAT_COMPL_FUNC
+ clear_string_option(&buf->b_p_cfu);
+ clear_string_option(&buf->b_p_ofu);
+#endif
+#ifdef FEAT_QUICKFIX
+ clear_string_option(&buf->b_p_gp);
+ clear_string_option(&buf->b_p_mp);
+ clear_string_option(&buf->b_p_efm);
+#endif
+ clear_string_option(&buf->b_p_ep);
+ clear_string_option(&buf->b_p_path);
+ clear_string_option(&buf->b_p_tags);
+ clear_string_option(&buf->b_p_tc);
+#ifdef FEAT_INS_EXPAND
+ clear_string_option(&buf->b_p_dict);
+ clear_string_option(&buf->b_p_tsr);
+#endif
+#ifdef FEAT_TEXTOBJ
+ clear_string_option(&buf->b_p_qe);
+#endif
+ buf->b_p_ar = -1;
+ buf->b_p_ul = NO_LOCAL_UNDOLEVEL;
+#ifdef FEAT_LISP
+ clear_string_option(&buf->b_p_lw);
+#endif
+ clear_string_option(&buf->b_p_bkc);
+ clear_string_option(&buf->b_p_menc);
+}
+
+/*
+ * Get alternate file "n".
+ * Set linenr to "lnum" or altfpos.lnum if "lnum" == 0.
+ * Also set cursor column to altfpos.col if 'startofline' is not set.
+ * if (options & GETF_SETMARK) call setpcmark()
+ * if (options & GETF_ALT) we are jumping to an alternate file.
+ * if (options & GETF_SWITCH) respect 'switchbuf' settings when jumping
+ *
+ * Return FAIL for failure, OK for success.
+ */
+ int
+buflist_getfile(
+ int n,
+ linenr_T lnum,
+ int options,
+ int forceit)
+{
+ buf_T *buf;
+ win_T *wp = NULL;
+ pos_T *fpos;
+ colnr_T col;
+
+ buf = buflist_findnr(n);
+ if (buf == NULL)
+ {
+ if ((options & GETF_ALT) && n == 0)
+ emsg(_(e_noalt));
+ else
+ semsg(_("E92: Buffer %d not found"), n);
+ return FAIL;
+ }
+
+ /* if alternate file is the current buffer, nothing to do */
+ if (buf == curbuf)
+ return OK;
+
+ if (text_locked())
+ {
+ text_locked_msg();
+ return FAIL;
+ }
+ if (curbuf_locked())
+ return FAIL;
+
+ /* altfpos may be changed by getfile(), get it now */
+ if (lnum == 0)
+ {
+ fpos = buflist_findfpos(buf);
+ lnum = fpos->lnum;
+ col = fpos->col;
+ }
+ else
+ col = 0;
+
+ if (options & GETF_SWITCH)
+ {
+ /* If 'switchbuf' contains "useopen": jump to first window containing
+ * "buf" if one exists */
+ if (swb_flags & SWB_USEOPEN)
+ wp = buf_jump_open_win(buf);
+
+ /* If 'switchbuf' contains "usetab": jump to first window in any tab
+ * page containing "buf" if one exists */
+ if (wp == NULL && (swb_flags & SWB_USETAB))
+ wp = buf_jump_open_tab(buf);
+
+ /* If 'switchbuf' contains "split", "vsplit" or "newtab" and the
+ * current buffer isn't empty: open new tab or window */
+ if (wp == NULL && (swb_flags & (SWB_VSPLIT | SWB_SPLIT | SWB_NEWTAB))
+ && !BUFEMPTY())
+ {
+ if (swb_flags & SWB_NEWTAB)
+ tabpage_new();
+ else if (win_split(0, (swb_flags & SWB_VSPLIT) ? WSP_VERT : 0)
+ == FAIL)
+ return FAIL;
+ RESET_BINDING(curwin);
+ }
+ }
+
+ ++RedrawingDisabled;
+ if (GETFILE_SUCCESS(getfile(buf->b_fnum, NULL, NULL,
+ (options & GETF_SETMARK), lnum, forceit)))
+ {
+ --RedrawingDisabled;
+
+ /* cursor is at to BOL and w_cursor.lnum is checked due to getfile() */
+ if (!p_sol && col != 0)
+ {
+ curwin->w_cursor.col = col;
+ check_cursor_col();
+ curwin->w_cursor.coladd = 0;
+ curwin->w_set_curswant = TRUE;
+ }
+ return OK;
+ }
+ --RedrawingDisabled;
+ return FAIL;
+}
+
+/*
+ * go to the last know line number for the current buffer
+ */
+ void
+buflist_getfpos(void)
+{
+ pos_T *fpos;
+
+ fpos = buflist_findfpos(curbuf);
+
+ curwin->w_cursor.lnum = fpos->lnum;
+ check_cursor_lnum();
+
+ if (p_sol)
+ curwin->w_cursor.col = 0;
+ else
+ {
+ curwin->w_cursor.col = fpos->col;
+ check_cursor_col();
+ curwin->w_cursor.coladd = 0;
+ curwin->w_set_curswant = TRUE;
+ }
+}
+
+#if defined(FEAT_QUICKFIX) || defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * Find file in buffer list by name (it has to be for the current window).
+ * Returns NULL if not found.
+ */
+ buf_T *
+buflist_findname_exp(char_u *fname)
+{
+ char_u *ffname;
+ buf_T *buf = NULL;
+
+ /* First make the name into a full path name */
+ ffname = FullName_save(fname,
+#ifdef UNIX
+ TRUE /* force expansion, get rid of symbolic links */
+#else
+ FALSE
+#endif
+ );
+ if (ffname != NULL)
+ {
+ buf = buflist_findname(ffname);
+ vim_free(ffname);
+ }
+ return buf;
+}
+#endif
+
+/*
+ * Find file in buffer list by name (it has to be for the current window).
+ * "ffname" must have a full path.
+ * Skips dummy buffers.
+ * Returns NULL if not found.
+ */
+ buf_T *
+buflist_findname(char_u *ffname)
+{
+#ifdef UNIX
+ stat_T st;
+
+ if (mch_stat((char *)ffname, &st) < 0)
+ st.st_dev = (dev_T)-1;
+ return buflist_findname_stat(ffname, &st);
+}
+
+/*
+ * Same as buflist_findname(), but pass the stat structure to avoid getting it
+ * twice for the same file.
+ * Returns NULL if not found.
+ */
+ static buf_T *
+buflist_findname_stat(
+ char_u *ffname,
+ stat_T *stp)
+{
+#endif
+ buf_T *buf;
+
+ /* Start at the last buffer, expect to find a match sooner. */
+ for (buf = lastbuf; buf != NULL; buf = buf->b_prev)
+ if ((buf->b_flags & BF_DUMMY) == 0 && !otherfile_buf(buf, ffname
+#ifdef UNIX
+ , stp
+#endif
+ ))
+ return buf;
+ return NULL;
+}
+
+/*
+ * Find file in buffer list by a regexp pattern.
+ * Return fnum of the found buffer.
+ * Return < 0 for error.
+ */
+ int
+buflist_findpat(
+ char_u *pattern,
+ char_u *pattern_end, /* pointer to first char after pattern */
+ int unlisted, /* find unlisted buffers */
+ int diffmode UNUSED, /* find diff-mode buffers only */
+ int curtab_only) /* find buffers in current tab only */
+{
+ buf_T *buf;
+ int match = -1;
+ int find_listed;
+ char_u *pat;
+ char_u *patend;
+ int attempt;
+ char_u *p;
+ int toggledollar;
+
+ if (pattern_end == pattern + 1 && (*pattern == '%' || *pattern == '#'))
+ {
+ if (*pattern == '%')
+ match = curbuf->b_fnum;
+ else
+ match = curwin->w_alt_fnum;
+#ifdef FEAT_DIFF
+ if (diffmode && !diff_mode_buf(buflist_findnr(match)))
+ match = -1;
+#endif
+ }
+
+ /*
+ * Try four ways of matching a listed buffer:
+ * attempt == 0: without '^' or '$' (at any position)
+ * attempt == 1: with '^' at start (only at position 0)
+ * attempt == 2: with '$' at end (only match at end)
+ * attempt == 3: with '^' at start and '$' at end (only full match)
+ * Repeat this for finding an unlisted buffer if there was no matching
+ * listed buffer.
+ */
+ else
+ {
+ pat = file_pat_to_reg_pat(pattern, pattern_end, NULL, FALSE);
+ if (pat == NULL)
+ return -1;
+ patend = pat + STRLEN(pat) - 1;
+ toggledollar = (patend > pat && *patend == '$');
+
+ /* First try finding a listed buffer. If not found and "unlisted"
+ * is TRUE, try finding an unlisted buffer. */
+ find_listed = TRUE;
+ for (;;)
+ {
+ for (attempt = 0; attempt <= 3; ++attempt)
+ {
+ regmatch_T regmatch;
+
+ /* may add '^' and '$' */
+ if (toggledollar)
+ *patend = (attempt < 2) ? NUL : '$'; /* add/remove '$' */
+ p = pat;
+ if (*p == '^' && !(attempt & 1)) /* add/remove '^' */
+ ++p;
+ regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
+ if (regmatch.regprog == NULL)
+ {
+ vim_free(pat);
+ return -1;
+ }
+
+ for (buf = lastbuf; buf != NULL; buf = buf->b_prev)
+ if (buf->b_p_bl == find_listed
+#ifdef FEAT_DIFF
+ && (!diffmode || diff_mode_buf(buf))
+#endif
+ && buflist_match(&regmatch, buf, FALSE) != NULL)
+ {
+ if (curtab_only)
+ {
+ /* Ignore the match if the buffer is not open in
+ * the current tab. */
+ win_T *wp;
+
+ FOR_ALL_WINDOWS(wp)
+ if (wp->w_buffer == buf)
+ break;
+ if (wp == NULL)
+ continue;
+ }
+ if (match >= 0) /* already found a match */
+ {
+ match = -2;
+ break;
+ }
+ match = buf->b_fnum; /* remember first match */
+ }
+
+ vim_regfree(regmatch.regprog);
+ if (match >= 0) /* found one match */
+ break;
+ }
+
+ /* Only search for unlisted buffers if there was no match with
+ * a listed buffer. */
+ if (!unlisted || !find_listed || match != -1)
+ break;
+ find_listed = FALSE;
+ }
+
+ vim_free(pat);
+ }
+
+ if (match == -2)
+ semsg(_("E93: More than one match for %s"), pattern);
+ else if (match < 0)
+ semsg(_("E94: No matching buffer for %s"), pattern);
+ return match;
+}
+
+#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
+
+/*
+ * Find all buffer names that match.
+ * For command line expansion of ":buf" and ":sbuf".
+ * Return OK if matches found, FAIL otherwise.
+ */
+ int
+ExpandBufnames(
+ char_u *pat,
+ int *num_file,
+ char_u ***file,
+ int options)
+{
+ int count = 0;
+ buf_T *buf;
+ int round;
+ char_u *p;
+ int attempt;
+ char_u *patc;
+
+ *num_file = 0; /* return values in case of FAIL */
+ *file = NULL;
+
+ /* Make a copy of "pat" and change "^" to "\(^\|[\/]\)". */
+ if (*pat == '^')
+ {
+ patc = alloc((unsigned)STRLEN(pat) + 11);
+ if (patc == NULL)
+ return FAIL;
+ STRCPY(patc, "\\(^\\|[\\/]\\)");
+ STRCPY(patc + 11, pat + 1);
+ }
+ else
+ patc = pat;
+
+ /*
+ * attempt == 0: try match with '\<', match at start of word
+ * attempt == 1: try match without '\<', match anywhere
+ */
+ for (attempt = 0; attempt <= 1; ++attempt)
+ {
+ regmatch_T regmatch;
+
+ if (attempt > 0 && patc == pat)
+ break; /* there was no anchor, no need to try again */
+ regmatch.regprog = vim_regcomp(patc + attempt * 11, RE_MAGIC);
+ if (regmatch.regprog == NULL)
+ {
+ if (patc != pat)
+ vim_free(patc);
+ return FAIL;
+ }
+
+ /*
+ * round == 1: Count the matches.
+ * round == 2: Build the array to keep the matches.
+ */
+ for (round = 1; round <= 2; ++round)
+ {
+ count = 0;
+ FOR_ALL_BUFFERS(buf)
+ {
+ if (!buf->b_p_bl) /* skip unlisted buffers */
+ continue;
+ p = buflist_match(&regmatch, buf, p_wic);
+ if (p != NULL)
+ {
+ if (round == 1)
+ ++count;
+ else
+ {
+ if (options & WILD_HOME_REPLACE)
+ p = home_replace_save(buf, p);
+ else
+ p = vim_strsave(p);
+ (*file)[count++] = p;
+ }
+ }
+ }
+ if (count == 0) /* no match found, break here */
+ break;
+ if (round == 1)
+ {
+ *file = (char_u **)alloc((unsigned)(count * sizeof(char_u *)));
+ if (*file == NULL)
+ {
+ vim_regfree(regmatch.regprog);
+ if (patc != pat)
+ vim_free(patc);
+ return FAIL;
+ }
+ }
+ }
+ vim_regfree(regmatch.regprog);
+ if (count) /* match(es) found, break here */
+ break;
+ }
+
+ if (patc != pat)
+ vim_free(patc);
+
+ *num_file = count;
+ return (count == 0 ? FAIL : OK);
+}
+
+#endif /* FEAT_CMDL_COMPL */
+
+/*
+ * Check for a match on the file name for buffer "buf" with regprog "prog".
+ */
+ static char_u *
+buflist_match(
+ regmatch_T *rmp,
+ buf_T *buf,
+ int ignore_case) /* when TRUE ignore case, when FALSE use 'fic' */
+{
+ char_u *match;
+
+ /* First try the short file name, then the long file name. */
+ match = fname_match(rmp, buf->b_sfname, ignore_case);
+ if (match == NULL)
+ match = fname_match(rmp, buf->b_ffname, ignore_case);
+
+ return match;
+}
+
+/*
+ * Try matching the regexp in "prog" with file name "name".
+ * Return "name" when there is a match, NULL when not.
+ */
+ static char_u *
+fname_match(
+ regmatch_T *rmp,
+ char_u *name,
+ int ignore_case) /* when TRUE ignore case, when FALSE use 'fic' */
+{
+ char_u *match = NULL;
+ char_u *p;
+
+ if (name != NULL)
+ {
+ /* Ignore case when 'fileignorecase' or the argument is set. */
+ rmp->rm_ic = p_fic || ignore_case;
+ if (vim_regexec(rmp, name, (colnr_T)0))
+ match = name;
+ else
+ {
+ /* Replace $(HOME) with '~' and try matching again. */
+ p = home_replace_save(NULL, name);
+ if (p != NULL && vim_regexec(rmp, p, (colnr_T)0))
+ match = name;
+ vim_free(p);
+ }
+ }
+
+ return match;
+}
+
+/*
+ * Find a file in the buffer list by buffer number.
+ */
+ buf_T *
+buflist_findnr(int nr)
+{
+ char_u key[VIM_SIZEOF_INT * 2 + 1];
+ hashitem_T *hi;
+
+ if (nr == 0)
+ nr = curwin->w_alt_fnum;
+ sprintf((char *)key, "%x", nr);
+ hi = hash_find(&buf_hashtab, key);
+
+ if (!HASHITEM_EMPTY(hi))
+ return (buf_T *)(hi->hi_key
+ - ((unsigned)(curbuf->b_key - (char_u *)curbuf)));
+ return NULL;
+}
+
+/*
+ * Get name of file 'n' in the buffer list.
+ * When the file has no name an empty string is returned.
+ * home_replace() is used to shorten the file name (used for marks).
+ * Returns a pointer to allocated memory, of NULL when failed.
+ */
+ char_u *
+buflist_nr2name(
+ int n,
+ int fullname,
+ int helptail) /* for help buffers return tail only */
+{
+ buf_T *buf;
+
+ buf = buflist_findnr(n);
+ if (buf == NULL)
+ return NULL;
+ return home_replace_save(helptail ? buf : NULL,
+ fullname ? buf->b_ffname : buf->b_fname);
+}
+
+/*
+ * Set the "lnum" and "col" for the buffer "buf" and the current window.
+ * When "copy_options" is TRUE save the local window option values.
+ * When "lnum" is 0 only do the options.
+ */
+ static void
+buflist_setfpos(
+ buf_T *buf,
+ win_T *win,
+ linenr_T lnum,
+ colnr_T col,
+ int copy_options)
+{
+ wininfo_T *wip;
+
+ for (wip = buf->b_wininfo; wip != NULL; wip = wip->wi_next)
+ if (wip->wi_win == win)
+ break;
+ if (wip == NULL)
+ {
+ /* allocate a new entry */
+ wip = (wininfo_T *)alloc_clear((unsigned)sizeof(wininfo_T));
+ if (wip == NULL)
+ return;
+ wip->wi_win = win;
+ if (lnum == 0) /* set lnum even when it's 0 */
+ lnum = 1;
+ }
+ else
+ {
+ /* remove the entry from the list */
+ if (wip->wi_prev)
+ wip->wi_prev->wi_next = wip->wi_next;
+ else
+ buf->b_wininfo = wip->wi_next;
+ if (wip->wi_next)
+ wip->wi_next->wi_prev = wip->wi_prev;
+ if (copy_options && wip->wi_optset)
+ {
+ clear_winopt(&wip->wi_opt);
+#ifdef FEAT_FOLDING
+ deleteFoldRecurse(&wip->wi_folds);
+#endif
+ }
+ }
+ if (lnum != 0)
+ {
+ wip->wi_fpos.lnum = lnum;
+ wip->wi_fpos.col = col;
+ }
+ if (copy_options)
+ {
+ /* Save the window-specific option values. */
+ copy_winopt(&win->w_onebuf_opt, &wip->wi_opt);
+#ifdef FEAT_FOLDING
+ wip->wi_fold_manual = win->w_fold_manual;
+ cloneFoldGrowArray(&win->w_folds, &wip->wi_folds);
+#endif
+ wip->wi_optset = TRUE;
+ }
+
+ /* insert the entry in front of the list */
+ wip->wi_next = buf->b_wininfo;
+ buf->b_wininfo = wip;
+ wip->wi_prev = NULL;
+ if (wip->wi_next)
+ wip->wi_next->wi_prev = wip;
+
+ return;
+}
+
+#ifdef FEAT_DIFF
+/*
+ * Return TRUE when "wip" has 'diff' set and the diff is only for another tab
+ * page. That's because a diff is local to a tab page.
+ */
+ static int
+wininfo_other_tab_diff(wininfo_T *wip)
+{
+ win_T *wp;
+
+ if (wip->wi_opt.wo_diff)
+ {
+ FOR_ALL_WINDOWS(wp)
+ /* return FALSE when it's a window in the current tab page, thus
+ * the buffer was in diff mode here */
+ if (wip->wi_win == wp)
+ return FALSE;
+ return TRUE;
+ }
+ return FALSE;
+}
+#endif
+
+/*
+ * Find info for the current window in buffer "buf".
+ * If not found, return the info for the most recently used window.
+ * When "skip_diff_buffer" is TRUE avoid windows with 'diff' set that is in
+ * another tab page.
+ * Returns NULL when there isn't any info.
+ */
+ static wininfo_T *
+find_wininfo(
+ buf_T *buf,
+ int skip_diff_buffer UNUSED)
+{
+ wininfo_T *wip;
+
+ for (wip = buf->b_wininfo; wip != NULL; wip = wip->wi_next)
+ if (wip->wi_win == curwin
+#ifdef FEAT_DIFF
+ && (!skip_diff_buffer || !wininfo_other_tab_diff(wip))
+#endif
+ )
+ break;
+
+ /* If no wininfo for curwin, use the first in the list (that doesn't have
+ * 'diff' set and is in another tab page). */
+ if (wip == NULL)
+ {
+#ifdef FEAT_DIFF
+ if (skip_diff_buffer)
+ {
+ for (wip = buf->b_wininfo; wip != NULL; wip = wip->wi_next)
+ if (!wininfo_other_tab_diff(wip))
+ break;
+ }
+ else
+#endif
+ wip = buf->b_wininfo;
+ }
+ return wip;
+}
+
+/*
+ * Reset the local window options to the values last used in this window.
+ * If the buffer wasn't used in this window before, use the values from
+ * the most recently used window. If the values were never set, use the
+ * global values for the window.
+ */
+ void
+get_winopts(buf_T *buf)
+{
+ wininfo_T *wip;
+
+ clear_winopt(&curwin->w_onebuf_opt);
+#ifdef FEAT_FOLDING
+ clearFolding(curwin);
+#endif
+
+ wip = find_wininfo(buf, TRUE);
+ if (wip != NULL && wip->wi_win != NULL
+ && wip->wi_win != curwin && wip->wi_win->w_buffer == buf)
+ {
+ /* The buffer is currently displayed in the window: use the actual
+ * option values instead of the saved (possibly outdated) values. */
+ win_T *wp = wip->wi_win;
+
+ copy_winopt(&wp->w_onebuf_opt, &curwin->w_onebuf_opt);
+#ifdef FEAT_FOLDING
+ curwin->w_fold_manual = wp->w_fold_manual;
+ curwin->w_foldinvalid = TRUE;
+ cloneFoldGrowArray(&wp->w_folds, &curwin->w_folds);
+#endif
+ }
+ else if (wip != NULL && wip->wi_optset)
+ {
+ /* the buffer was displayed in the current window earlier */
+ copy_winopt(&wip->wi_opt, &curwin->w_onebuf_opt);
+#ifdef FEAT_FOLDING
+ curwin->w_fold_manual = wip->wi_fold_manual;
+ curwin->w_foldinvalid = TRUE;
+ cloneFoldGrowArray(&wip->wi_folds, &curwin->w_folds);
+#endif
+ }
+ else
+ copy_winopt(&curwin->w_allbuf_opt, &curwin->w_onebuf_opt);
+
+#ifdef FEAT_FOLDING
+ /* Set 'foldlevel' to 'foldlevelstart' if it's not negative. */
+ if (p_fdls >= 0)
+ curwin->w_p_fdl = p_fdls;
+#endif
+#ifdef FEAT_SYN_HL
+ check_colorcolumn(curwin);
+#endif
+}
+
+/*
+ * Find the position (lnum and col) for the buffer 'buf' for the current
+ * window.
+ * Returns a pointer to no_position if no position is found.
+ */
+ pos_T *
+buflist_findfpos(buf_T *buf)
+{
+ wininfo_T *wip;
+ static pos_T no_position = {1, 0, 0};
+
+ wip = find_wininfo(buf, FALSE);
+ if (wip != NULL)
+ return &(wip->wi_fpos);
+ else
+ return &no_position;
+}
+
+/*
+ * Find the lnum for the buffer 'buf' for the current window.
+ */
+ linenr_T
+buflist_findlnum(buf_T *buf)
+{
+ return buflist_findfpos(buf)->lnum;
+}
+
+/*
+ * List all known file names (for :files and :buffers command).
+ */
+ void
+buflist_list(exarg_T *eap)
+{
+ buf_T *buf;
+ int len;
+ int i;
+ int ro_char;
+ int changed_char;
+#ifdef FEAT_TERMINAL
+ int job_running;
+ int job_none_open;
+#endif
+
+ for (buf = firstbuf; buf != NULL && !got_int; buf = buf->b_next)
+ {
+#ifdef FEAT_TERMINAL
+ job_running = term_job_running(buf->b_term);
+ job_none_open = job_running && term_none_open(buf->b_term);
+#endif
+ /* skip unlisted buffers, unless ! was used */
+ if ((!buf->b_p_bl && !eap->forceit && !vim_strchr(eap->arg, 'u'))
+ || (vim_strchr(eap->arg, 'u') && buf->b_p_bl)
+ || (vim_strchr(eap->arg, '+')
+ && ((buf->b_flags & BF_READERR) || !bufIsChanged(buf)))
+ || (vim_strchr(eap->arg, 'a')
+ && (buf->b_ml.ml_mfp == NULL || buf->b_nwindows == 0))
+ || (vim_strchr(eap->arg, 'h')
+ && (buf->b_ml.ml_mfp == NULL || buf->b_nwindows != 0))
+#ifdef FEAT_TERMINAL
+ || (vim_strchr(eap->arg, 'R')
+ && (!job_running || (job_running && job_none_open)))
+ || (vim_strchr(eap->arg, '?')
+ && (!job_running || (job_running && !job_none_open)))
+ || (vim_strchr(eap->arg, 'F')
+ && (job_running || buf->b_term == NULL))
+#endif
+ || (vim_strchr(eap->arg, '-') && buf->b_p_ma)
+ || (vim_strchr(eap->arg, '=') && !buf->b_p_ro)
+ || (vim_strchr(eap->arg, 'x') && !(buf->b_flags & BF_READERR))
+ || (vim_strchr(eap->arg, '%') && buf != curbuf)
+ || (vim_strchr(eap->arg, '#')
+ && (buf == curbuf || curwin->w_alt_fnum != buf->b_fnum)))
+ continue;
+ if (buf_spname(buf) != NULL)
+ vim_strncpy(NameBuff, buf_spname(buf), MAXPATHL - 1);
+ else
+ home_replace(buf, buf->b_fname, NameBuff, MAXPATHL, TRUE);
+ if (message_filtered(NameBuff))
+ continue;
+
+ changed_char = (buf->b_flags & BF_READERR) ? 'x'
+ : (bufIsChanged(buf) ? '+' : ' ');
+#ifdef FEAT_TERMINAL
+ if (term_job_running(buf->b_term))
+ {
+ if (term_none_open(buf->b_term))
+ ro_char = '?';
+ else
+ ro_char = 'R';
+ changed_char = ' '; /* bufIsChanged() returns TRUE to avoid
+ * closing, but it's not actually changed. */
+ }
+ else if (buf->b_term != NULL)
+ ro_char = 'F';
+ else
+#endif
+ ro_char = !buf->b_p_ma ? '-' : (buf->b_p_ro ? '=' : ' ');
+
+ msg_putchar('\n');
+ len = vim_snprintf((char *)IObuff, IOSIZE - 20, "%3d%c%c%c%c%c \"%s\"",
+ buf->b_fnum,
+ buf->b_p_bl ? ' ' : 'u',
+ buf == curbuf ? '%' :
+ (curwin->w_alt_fnum == buf->b_fnum ? '#' : ' '),
+ buf->b_ml.ml_mfp == NULL ? ' ' :
+ (buf->b_nwindows == 0 ? 'h' : 'a'),
+ ro_char,
+ changed_char,
+ NameBuff);
+ if (len > IOSIZE - 20)
+ len = IOSIZE - 20;
+
+ /* put "line 999" in column 40 or after the file name */
+ i = 40 - vim_strsize(IObuff);
+ do
+ {
+ IObuff[len++] = ' ';
+ } while (--i > 0 && len < IOSIZE - 18);
+ vim_snprintf((char *)IObuff + len, (size_t)(IOSIZE - len),
+ _("line %ld"), buf == curbuf ? curwin->w_cursor.lnum
+ : (long)buflist_findlnum(buf));
+ msg_outtrans(IObuff);
+ out_flush(); /* output one line at a time */
+ ui_breakcheck();
+ }
+}
+
+/*
+ * Get file name and line number for file 'fnum'.
+ * Used by DoOneCmd() for translating '%' and '#'.
+ * Used by insert_reg() and cmdline_paste() for '#' register.
+ * Return FAIL if not found, OK for success.
+ */
+ int
+buflist_name_nr(
+ int fnum,
+ char_u **fname,
+ linenr_T *lnum)
+{
+ buf_T *buf;
+
+ buf = buflist_findnr(fnum);
+ if (buf == NULL || buf->b_fname == NULL)
+ return FAIL;
+
+ *fname = buf->b_fname;
+ *lnum = buflist_findlnum(buf);
+
+ return OK;
+}
+
+/*
+ * Set the file name for "buf"' to "ffname_arg", short file name to
+ * "sfname_arg".
+ * The file name with the full path is also remembered, for when :cd is used.
+ * Returns FAIL for failure (file name already in use by other buffer)
+ * OK otherwise.
+ */
+ int
+setfname(
+ buf_T *buf,
+ char_u *ffname_arg,
+ char_u *sfname_arg,
+ int message) /* give message when buffer already exists */
+{
+ char_u *ffname = ffname_arg;
+ char_u *sfname = sfname_arg;
+ buf_T *obuf = NULL;
+#ifdef UNIX
+ stat_T st;
+#endif
+
+ if (ffname == NULL || *ffname == NUL)
+ {
+ /* Removing the name. */
+ if (buf->b_sfname != buf->b_ffname)
+ VIM_CLEAR(buf->b_sfname);
+ else
+ buf->b_sfname = NULL;
+ VIM_CLEAR(buf->b_ffname);
+#ifdef UNIX
+ st.st_dev = (dev_T)-1;
+#endif
+ }
+ else
+ {
+ fname_expand(buf, &ffname, &sfname); /* will allocate ffname */
+ if (ffname == NULL) /* out of memory */
+ return FAIL;
+
+ /*
+ * if the file name is already used in another buffer:
+ * - if the buffer is loaded, fail
+ * - if the buffer is not loaded, delete it from the list
+ */
+#ifdef UNIX
+ if (mch_stat((char *)ffname, &st) < 0)
+ st.st_dev = (dev_T)-1;
+#endif
+ if (!(buf->b_flags & BF_DUMMY))
+#ifdef UNIX
+ obuf = buflist_findname_stat(ffname, &st);
+#else
+ obuf = buflist_findname(ffname);
+#endif
+ if (obuf != NULL && obuf != buf)
+ {
+ if (obuf->b_ml.ml_mfp != NULL) /* it's loaded, fail */
+ {
+ if (message)
+ emsg(_("E95: Buffer with this name already exists"));
+ vim_free(ffname);
+ return FAIL;
+ }
+ /* delete from the list */
+ close_buffer(NULL, obuf, DOBUF_WIPE, FALSE);
+ }
+ sfname = vim_strsave(sfname);
+ if (ffname == NULL || sfname == NULL)
+ {
+ vim_free(sfname);
+ vim_free(ffname);
+ return FAIL;
+ }
+#ifdef USE_FNAME_CASE
+# ifdef USE_LONG_FNAME
+ if (USE_LONG_FNAME)
+# endif
+ fname_case(sfname, 0); /* set correct case for short file name */
+#endif
+ if (buf->b_sfname != buf->b_ffname)
+ vim_free(buf->b_sfname);
+ vim_free(buf->b_ffname);
+ buf->b_ffname = ffname;
+ buf->b_sfname = sfname;
+ }
+ buf->b_fname = buf->b_sfname;
+#ifdef UNIX
+ if (st.st_dev == (dev_T)-1)
+ buf->b_dev_valid = FALSE;
+ else
+ {
+ buf->b_dev_valid = TRUE;
+ buf->b_dev = st.st_dev;
+ buf->b_ino = st.st_ino;
+ }
+#endif
+
+ buf->b_shortname = FALSE;
+
+ buf_name_changed(buf);
+ return OK;
+}
+
+/*
+ * Crude way of changing the name of a buffer. Use with care!
+ * The name should be relative to the current directory.
+ */
+ void
+buf_set_name(int fnum, char_u *name)
+{
+ buf_T *buf;
+
+ buf = buflist_findnr(fnum);
+ if (buf != NULL)
+ {
+ if (buf->b_sfname != buf->b_ffname)
+ vim_free(buf->b_sfname);
+ vim_free(buf->b_ffname);
+ buf->b_ffname = vim_strsave(name);
+ buf->b_sfname = NULL;
+ /* Allocate ffname and expand into full path. Also resolves .lnk
+ * files on Win32. */
+ fname_expand(buf, &buf->b_ffname, &buf->b_sfname);
+ buf->b_fname = buf->b_sfname;
+ }
+}
+
+/*
+ * Take care of what needs to be done when the name of buffer "buf" has
+ * changed.
+ */
+ void
+buf_name_changed(buf_T *buf)
+{
+ /*
+ * If the file name changed, also change the name of the swapfile
+ */
+ if (buf->b_ml.ml_mfp != NULL)
+ ml_setname(buf);
+
+ if (curwin->w_buffer == buf)
+ check_arg_idx(curwin); /* check file name for arg list */
+#ifdef FEAT_TITLE
+ maketitle(); /* set window title */
+#endif
+ status_redraw_all(); /* status lines need to be redrawn */
+ fmarks_check_names(buf); /* check named file marks */
+ ml_timestamp(buf); /* reset timestamp */
+}
+
+/*
+ * set alternate file name for current window
+ *
+ * Used by do_one_cmd(), do_write() and do_ecmd().
+ * Return the buffer.
+ */
+ buf_T *
+setaltfname(
+ char_u *ffname,
+ char_u *sfname,
+ linenr_T lnum)
+{
+ buf_T *buf;
+
+ /* Create a buffer. 'buflisted' is not set if it's a new buffer */
+ buf = buflist_new(ffname, sfname, lnum, 0);
+ if (buf != NULL && !cmdmod.keepalt)
+ curwin->w_alt_fnum = buf->b_fnum;
+ return buf;
+}
+
+/*
+ * Get alternate file name for current window.
+ * Return NULL if there isn't any, and give error message if requested.
+ */
+ char_u *
+getaltfname(
+ int errmsg) /* give error message */
+{
+ char_u *fname;
+ linenr_T dummy;
+
+ if (buflist_name_nr(0, &fname, &dummy) == FAIL)
+ {
+ if (errmsg)
+ emsg(_(e_noalt));
+ return NULL;
+ }
+ return fname;
+}
+
+/*
+ * Add a file name to the buflist and return its number.
+ * Uses same flags as buflist_new(), except BLN_DUMMY.
+ *
+ * used by qf_init(), main() and doarglist()
+ */
+ int
+buflist_add(char_u *fname, int flags)
+{
+ buf_T *buf;
+
+ buf = buflist_new(fname, NULL, (linenr_T)0, flags);
+ if (buf != NULL)
+ return buf->b_fnum;
+ return 0;
+}
+
+#if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
+/*
+ * Adjust slashes in file names. Called after 'shellslash' was set.
+ */
+ void
+buflist_slash_adjust(void)
+{
+ buf_T *bp;
+
+ FOR_ALL_BUFFERS(bp)
+ {
+ if (bp->b_ffname != NULL)
+ slash_adjust(bp->b_ffname);
+ if (bp->b_sfname != NULL)
+ slash_adjust(bp->b_sfname);
+ }
+}
+#endif
+
+/*
+ * Set alternate cursor position for the current buffer and window "win".
+ * Also save the local window option values.
+ */
+ void
+buflist_altfpos(win_T *win)
+{
+ buflist_setfpos(curbuf, win, win->w_cursor.lnum, win->w_cursor.col, TRUE);
+}
+
+/*
+ * Return TRUE if 'ffname' is not the same file as current file.
+ * Fname must have a full path (expanded by mch_FullName()).
+ */
+ int
+otherfile(char_u *ffname)
+{
+ return otherfile_buf(curbuf, ffname
+#ifdef UNIX
+ , NULL
+#endif
+ );
+}
+
+ static int
+otherfile_buf(
+ buf_T *buf,
+ char_u *ffname
+#ifdef UNIX
+ , stat_T *stp
+#endif
+ )
+{
+ /* no name is different */
+ if (ffname == NULL || *ffname == NUL || buf->b_ffname == NULL)
+ return TRUE;
+ if (fnamecmp(ffname, buf->b_ffname) == 0)
+ return FALSE;
+#ifdef UNIX
+ {
+ stat_T st;
+
+ /* If no stat_T given, get it now */
+ if (stp == NULL)
+ {
+ if (!buf->b_dev_valid || mch_stat((char *)ffname, &st) < 0)
+ st.st_dev = (dev_T)-1;
+ stp = &st;
+ }
+ /* Use dev/ino to check if the files are the same, even when the names
+ * are different (possible with links). Still need to compare the
+ * name above, for when the file doesn't exist yet.
+ * Problem: The dev/ino changes when a file is deleted (and created
+ * again) and remains the same when renamed/moved. We don't want to
+ * mch_stat() each buffer each time, that would be too slow. Get the
+ * dev/ino again when they appear to match, but not when they appear
+ * to be different: Could skip a buffer when it's actually the same
+ * file. */
+ if (buf_same_ino(buf, stp))
+ {
+ buf_setino(buf);
+ if (buf_same_ino(buf, stp))
+ return FALSE;
+ }
+ }
+#endif
+ return TRUE;
+}
+
+#if defined(UNIX) || defined(PROTO)
+/*
+ * Set inode and device number for a buffer.
+ * Must always be called when b_fname is changed!.
+ */
+ void
+buf_setino(buf_T *buf)
+{
+ stat_T st;
+
+ if (buf->b_fname != NULL && mch_stat((char *)buf->b_fname, &st) >= 0)
+ {
+ buf->b_dev_valid = TRUE;
+ buf->b_dev = st.st_dev;
+ buf->b_ino = st.st_ino;
+ }
+ else
+ buf->b_dev_valid = FALSE;
+}
+
+/*
+ * Return TRUE if dev/ino in buffer "buf" matches with "stp".
+ */
+ static int
+buf_same_ino(
+ buf_T *buf,
+ stat_T *stp)
+{
+ return (buf->b_dev_valid
+ && stp->st_dev == buf->b_dev
+ && stp->st_ino == buf->b_ino);
+}
+#endif
+
+/*
+ * Print info about the current buffer.
+ */
+ void
+fileinfo(
+ int fullname, /* when non-zero print full path */
+ int shorthelp,
+ int dont_truncate)
+{
+ char_u *name;
+ int n;
+ char *p;
+ char *buffer;
+ size_t len;
+
+ buffer = (char *)alloc(IOSIZE);
+ if (buffer == NULL)
+ return;
+
+ if (fullname > 1) /* 2 CTRL-G: include buffer number */
+ {
+ vim_snprintf(buffer, IOSIZE, "buf %d: ", curbuf->b_fnum);
+ p = buffer + STRLEN(buffer);
+ }
+ else
+ p = buffer;
+
+ *p++ = '"';
+ if (buf_spname(curbuf) != NULL)
+ vim_strncpy((char_u *)p, buf_spname(curbuf), IOSIZE - (p - buffer) - 1);
+ else
+ {
+ if (!fullname && curbuf->b_fname != NULL)
+ name = curbuf->b_fname;
+ else
+ name = curbuf->b_ffname;
+ home_replace(shorthelp ? curbuf : NULL, name, (char_u *)p,
+ (int)(IOSIZE - (p - buffer)), TRUE);
+ }
+
+ vim_snprintf_add(buffer, IOSIZE, "\"%s%s%s%s%s%s",
+ curbufIsChanged() ? (shortmess(SHM_MOD)
+ ? " [+]" : _(" [Modified]")) : " ",
+ (curbuf->b_flags & BF_NOTEDITED)
+#ifdef FEAT_QUICKFIX
+ && !bt_dontwrite(curbuf)
+#endif
+ ? _("[Not edited]") : "",
+ (curbuf->b_flags & BF_NEW)
+#ifdef FEAT_QUICKFIX
+ && !bt_dontwrite(curbuf)
+#endif
+ ? _("[New file]") : "",
+ (curbuf->b_flags & BF_READERR) ? _("[Read errors]") : "",
+ curbuf->b_p_ro ? (shortmess(SHM_RO) ? _("[RO]")
+ : _("[readonly]")) : "",
+ (curbufIsChanged() || (curbuf->b_flags & BF_WRITE_MASK)
+ || curbuf->b_p_ro) ?
+ " " : "");
+ /* With 32 bit longs and more than 21,474,836 lines multiplying by 100
+ * causes an overflow, thus for large numbers divide instead. */
+ if (curwin->w_cursor.lnum > 1000000L)
+ n = (int)(((long)curwin->w_cursor.lnum) /
+ ((long)curbuf->b_ml.ml_line_count / 100L));
+ else
+ n = (int)(((long)curwin->w_cursor.lnum * 100L) /
+ (long)curbuf->b_ml.ml_line_count);
+ if (curbuf->b_ml.ml_flags & ML_EMPTY)
+ vim_snprintf_add(buffer, IOSIZE, "%s", _(no_lines_msg));
+#ifdef FEAT_CMDL_INFO
+ else if (p_ru)
+ /* Current line and column are already on the screen -- webb */
+ vim_snprintf_add(buffer, IOSIZE,
+ NGETTEXT("%ld line --%d%%--", "%ld lines --%d%%--",
+ curbuf->b_ml.ml_line_count),
+ (long)curbuf->b_ml.ml_line_count, n);
+#endif
+ else
+ {
+ vim_snprintf_add(buffer, IOSIZE,
+ _("line %ld of %ld --%d%%-- col "),
+ (long)curwin->w_cursor.lnum,
+ (long)curbuf->b_ml.ml_line_count,
+ n);
+ validate_virtcol();
+ len = STRLEN(buffer);
+ col_print((char_u *)buffer + len, IOSIZE - len,
+ (int)curwin->w_cursor.col + 1, (int)curwin->w_virtcol + 1);
+ }
+
+ (void)append_arg_number(curwin, (char_u *)buffer, IOSIZE,
+ !shortmess(SHM_FILE));
+
+ if (dont_truncate)
+ {
+ /* Temporarily set msg_scroll to avoid the message being truncated.
+ * First call msg_start() to get the message in the right place. */
+ msg_start();
+ n = msg_scroll;
+ msg_scroll = TRUE;
+ msg(buffer);
+ msg_scroll = n;
+ }
+ else
+ {
+ p = (char *)msg_trunc_attr(buffer, FALSE, 0);
+ if (restart_edit != 0 || (msg_scrolled && !need_wait_return))
+ /* Need to repeat the message after redrawing when:
+ * - When restart_edit is set (otherwise there will be a delay
+ * before redrawing).
+ * - When the screen was scrolled but there is no wait-return
+ * prompt. */
+ set_keep_msg((char_u *)p, 0);
+ }
+
+ vim_free(buffer);
+}
+
+ void
+col_print(
+ char_u *buf,
+ size_t buflen,
+ int col,
+ int vcol)
+{
+ if (col == vcol)
+ vim_snprintf((char *)buf, buflen, "%d", col);
+ else
+ vim_snprintf((char *)buf, buflen, "%d-%d", col, vcol);
+}
+
+#if defined(FEAT_TITLE) || defined(PROTO)
+static char_u *lasttitle = NULL;
+static char_u *lasticon = NULL;
+
+/*
+ * Put the file name in the title bar and icon of the window.
+ */
+ void
+maketitle(void)
+{
+ char_u *p;
+ char_u *title_str = NULL;
+ char_u *icon_str = NULL;
+ int maxlen = 0;
+ int len;
+ int mustset;
+ char_u buf[IOSIZE];
+ int off;
+
+ if (!redrawing())
+ {
+ /* Postpone updating the title when 'lazyredraw' is set. */
+ need_maketitle = TRUE;
+ return;
+ }
+
+ need_maketitle = FALSE;
+ if (!p_title && !p_icon && lasttitle == NULL && lasticon == NULL)
+ return; // nothing to do
+
+ if (p_title)
+ {
+ if (p_titlelen > 0)
+ {
+ maxlen = p_titlelen * Columns / 100;
+ if (maxlen < 10)
+ maxlen = 10;
+ }
+
+ title_str = buf;
+ if (*p_titlestring != NUL)
+ {
+#ifdef FEAT_STL_OPT
+ if (stl_syntax & STL_IN_TITLE)
+ {
+ int use_sandbox = FALSE;
+ int save_called_emsg = called_emsg;
+
+# ifdef FEAT_EVAL
+ use_sandbox = was_set_insecurely((char_u *)"titlestring", 0);
+# endif
+ called_emsg = FALSE;
+ build_stl_str_hl(curwin, title_str, sizeof(buf),
+ p_titlestring, use_sandbox,
+ 0, maxlen, NULL, NULL);
+ if (called_emsg)
+ set_string_option_direct((char_u *)"titlestring", -1,
+ (char_u *)"", OPT_FREE, SID_ERROR);
+ called_emsg |= save_called_emsg;
+ }
+ else
+#endif
+ title_str = p_titlestring;
+ }
+ else
+ {
+ /* format: "fname + (path) (1 of 2) - VIM" */
+
+#define SPACE_FOR_FNAME (IOSIZE - 100)
+#define SPACE_FOR_DIR (IOSIZE - 20)
+#define SPACE_FOR_ARGNR (IOSIZE - 10) /* at least room for " - VIM" */
+ if (curbuf->b_fname == NULL)
+ vim_strncpy(buf, (char_u *)_("[No Name]"), SPACE_FOR_FNAME);
+#ifdef FEAT_TERMINAL
+ else if (curbuf->b_term != NULL)
+ {
+ vim_strncpy(buf, term_get_status_text(curbuf->b_term),
+ SPACE_FOR_FNAME);
+ }
+#endif
+ else
+ {
+ p = transstr(gettail(curbuf->b_fname));
+ vim_strncpy(buf, p, SPACE_FOR_FNAME);
+ vim_free(p);
+ }
+
+#ifdef FEAT_TERMINAL
+ if (curbuf->b_term == NULL)
+#endif
+ switch (bufIsChanged(curbuf)
+ + (curbuf->b_p_ro * 2)
+ + (!curbuf->b_p_ma * 4))
+ {
+ case 1: STRCAT(buf, " +"); break;
+ case 2: STRCAT(buf, " ="); break;
+ case 3: STRCAT(buf, " =+"); break;
+ case 4:
+ case 6: STRCAT(buf, " -"); break;
+ case 5:
+ case 7: STRCAT(buf, " -+"); break;
+ }
+
+ if (curbuf->b_fname != NULL
+#ifdef FEAT_TERMINAL
+ && curbuf->b_term == NULL
+#endif
+ )
+ {
+ /* Get path of file, replace home dir with ~ */
+ off = (int)STRLEN(buf);
+ buf[off++] = ' ';
+ buf[off++] = '(';
+ home_replace(curbuf, curbuf->b_ffname,
+ buf + off, SPACE_FOR_DIR - off, TRUE);
+#ifdef BACKSLASH_IN_FILENAME
+ /* avoid "c:/name" to be reduced to "c" */
+ if (isalpha(buf[off]) && buf[off + 1] == ':')
+ off += 2;
+#endif
+ /* remove the file name */
+ p = gettail_sep(buf + off);
+ if (p == buf + off)
+ {
+ /* must be a help buffer */
+ vim_strncpy(buf + off, (char_u *)_("help"),
+ (size_t)(SPACE_FOR_DIR - off - 1));
+ }
+ else
+ *p = NUL;
+
+ /* Translate unprintable chars and concatenate. Keep some
+ * room for the server name. When there is no room (very long
+ * file name) use (...). */
+ if (off < SPACE_FOR_DIR)
+ {
+ p = transstr(buf + off);
+ vim_strncpy(buf + off, p, (size_t)(SPACE_FOR_DIR - off));
+ vim_free(p);
+ }
+ else
+ {
+ vim_strncpy(buf + off, (char_u *)"...",
+ (size_t)(SPACE_FOR_ARGNR - off));
+ }
+ STRCAT(buf, ")");
+ }
+
+ append_arg_number(curwin, buf, SPACE_FOR_ARGNR, FALSE);
+
+#if defined(FEAT_CLIENTSERVER)
+ if (serverName != NULL)
+ {
+ STRCAT(buf, " - ");
+ vim_strcat(buf, serverName, IOSIZE);
+ }
+ else
+#endif
+ STRCAT(buf, " - VIM");
+
+ if (maxlen > 0)
+ {
+ /* make it shorter by removing a bit in the middle */
+ if (vim_strsize(buf) > maxlen)
+ trunc_string(buf, buf, maxlen, IOSIZE);
+ }
+ }
+ }
+ mustset = value_changed(title_str, &lasttitle);
+
+ if (p_icon)
+ {
+ icon_str = buf;
+ if (*p_iconstring != NUL)
+ {
+#ifdef FEAT_STL_OPT
+ if (stl_syntax & STL_IN_ICON)
+ {
+ int use_sandbox = FALSE;
+ int save_called_emsg = called_emsg;
+
+# ifdef FEAT_EVAL
+ use_sandbox = was_set_insecurely((char_u *)"iconstring", 0);
+# endif
+ called_emsg = FALSE;
+ build_stl_str_hl(curwin, icon_str, sizeof(buf),
+ p_iconstring, use_sandbox,
+ 0, 0, NULL, NULL);
+ if (called_emsg)
+ set_string_option_direct((char_u *)"iconstring", -1,
+ (char_u *)"", OPT_FREE, SID_ERROR);
+ called_emsg |= save_called_emsg;
+ }
+ else
+#endif
+ icon_str = p_iconstring;
+ }
+ else
+ {
+ if (buf_spname(curbuf) != NULL)
+ p = buf_spname(curbuf);
+ else /* use file name only in icon */
+ p = gettail(curbuf->b_ffname);
+ *icon_str = NUL;
+ /* Truncate name at 100 bytes. */
+ len = (int)STRLEN(p);
+ if (len > 100)
+ {
+ len -= 100;
+ if (has_mbyte)
+ len += (*mb_tail_off)(p, p + len) + 1;
+ p += len;
+ }
+ STRCPY(icon_str, p);
+ trans_characters(icon_str, IOSIZE);
+ }
+ }
+
+ mustset |= value_changed(icon_str, &lasticon);
+
+ if (mustset)
+ resettitle();
+}
+
+/*
+ * Used for title and icon: Check if "str" differs from "*last". Set "*last"
+ * from "str" if it does.
+ * Return TRUE if resettitle() is to be called.
+ */
+ static int
+value_changed(char_u *str, char_u **last)
+{
+ if ((str == NULL) != (*last == NULL)
+ || (str != NULL && *last != NULL && STRCMP(str, *last) != 0))
+ {
+ vim_free(*last);
+ if (str == NULL)
+ {
+ *last = NULL;
+ mch_restore_title(
+ last == &lasttitle ? SAVE_RESTORE_TITLE : SAVE_RESTORE_ICON);
+ }
+ else
+ {
+ *last = vim_strsave(str);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/*
+ * Put current window title back (used after calling a shell)
+ */
+ void
+resettitle(void)
+{
+ mch_settitle(lasttitle, lasticon);
+}
+
+# if defined(EXITFREE) || defined(PROTO)
+ void
+free_titles(void)
+{
+ vim_free(lasttitle);
+ vim_free(lasticon);
+}
+# endif
+
+#endif /* FEAT_TITLE */
+
+#if defined(FEAT_STL_OPT) || defined(FEAT_GUI_TABLINE) || defined(PROTO)
+/*
+ * Build a string from the status line items in "fmt".
+ * Return length of string in screen cells.
+ *
+ * Normally works for window "wp", except when working for 'tabline' then it
+ * is "curwin".
+ *
+ * Items are drawn interspersed with the text that surrounds it
+ * Specials: %-<wid>(xxx%) => group, %= => middle marker, %< => truncation
+ * Item: %-<minwid>.<maxwid><itemch> All but <itemch> are optional
+ *
+ * If maxwidth is not zero, the string will be filled at any middle marker
+ * or truncated if too long, fillchar is used for all whitespace.
+ */
+ int
+build_stl_str_hl(
+ win_T *wp,
+ char_u *out, /* buffer to write into != NameBuff */
+ size_t outlen, /* length of out[] */
+ char_u *fmt,
+ int use_sandbox UNUSED, /* "fmt" was set insecurely, use sandbox */
+ int fillchar,
+ int maxwidth,
+ struct stl_hlrec *hltab, /* return: HL attributes (can be NULL) */
+ struct stl_hlrec *tabtab) /* return: tab page nrs (can be NULL) */
+{
+ linenr_T lnum;
+ size_t len;
+ char_u *p;
+ char_u *s;
+ char_u *t;
+ int byteval;
+#ifdef FEAT_EVAL
+ win_T *save_curwin;
+ buf_T *save_curbuf;
+#endif
+ int empty_line;
+ colnr_T virtcol;
+ long l;
+ long n;
+ int prevchar_isflag;
+ int prevchar_isitem;
+ int itemisflag;
+ int fillable;
+ char_u *str;
+ long num;
+ int width;
+ int itemcnt;
+ int curitem;
+ int group_end_userhl;
+ int group_start_userhl;
+ int groupitem[STL_MAX_ITEM];
+ int groupdepth;
+ struct stl_item
+ {
+ char_u *start;
+ int minwid;
+ int maxwid;
+ enum
+ {
+ Normal,
+ Empty,
+ Group,
+ Middle,
+ Highlight,
+ TabPage,
+ Trunc
+ } type;
+ } item[STL_MAX_ITEM];
+ int minwid;
+ int maxwid;
+ int zeropad;
+ char_u base;
+ char_u opt;
+#define TMPLEN 70
+ char_u tmp[TMPLEN];
+ char_u *usefmt = fmt;
+ struct stl_hlrec *sp;
+ int save_must_redraw = must_redraw;
+ int save_redr_type = curwin->w_redr_type;
+
+#ifdef FEAT_EVAL
+ /*
+ * When the format starts with "%!" then evaluate it as an expression and
+ * use the result as the actual format string.
+ */
+ if (fmt[0] == '%' && fmt[1] == '!')
+ {
+ usefmt = eval_to_string_safe(fmt + 2, NULL, use_sandbox);
+ if (usefmt == NULL)
+ usefmt = fmt;
+ }
+#endif
+
+ if (fillchar == 0)
+ fillchar = ' ';
+ /* Can't handle a multi-byte fill character yet. */
+ else if (mb_char2len(fillchar) > 1)
+ fillchar = '-';
+
+ // The cursor in windows other than the current one isn't always
+ // up-to-date, esp. because of autocommands and timers.
+ lnum = wp->w_cursor.lnum;
+ if (lnum > wp->w_buffer->b_ml.ml_line_count)
+ {
+ lnum = wp->w_buffer->b_ml.ml_line_count;
+ wp->w_cursor.lnum = lnum;
+ }
+
+ // Get line & check if empty (cursorpos will show "0-1"). Note that
+ // p will become invalid when getting another buffer line.
+ p = ml_get_buf(wp->w_buffer, lnum, FALSE);
+ empty_line = (*p == NUL);
+
+ // Get the byte value now, in case we need it below. This is more efficient
+ // than making a copy of the line.
+ len = STRLEN(p);
+ if (wp->w_cursor.col > (colnr_T)len)
+ {
+ // Line may have changed since checking the cursor column, or the lnum
+ // was adjusted above.
+ wp->w_cursor.col = (colnr_T)len;
+ wp->w_cursor.coladd = 0;
+ byteval = 0;
+ }
+ else
+ byteval = (*mb_ptr2char)(p + wp->w_cursor.col);
+
+ groupdepth = 0;
+ p = out;
+ curitem = 0;
+ prevchar_isflag = TRUE;
+ prevchar_isitem = FALSE;
+ for (s = usefmt; *s; )
+ {
+ if (curitem == STL_MAX_ITEM)
+ {
+ /* There are too many items. Add the error code to the statusline
+ * to give the user a hint about what went wrong. */
+ if (p + 6 < out + outlen)
+ {
+ mch_memmove(p, " E541", (size_t)5);
+ p += 5;
+ }
+ break;
+ }
+
+ if (*s != NUL && *s != '%')
+ prevchar_isflag = prevchar_isitem = FALSE;
+
+ /*
+ * Handle up to the next '%' or the end.
+ */
+ while (*s != NUL && *s != '%' && p + 1 < out + outlen)
+ *p++ = *s++;
+ if (*s == NUL || p + 1 >= out + outlen)
+ break;
+
+ /*
+ * Handle one '%' item.
+ */
+ s++;
+ if (*s == NUL) /* ignore trailing % */
+ break;
+ if (*s == '%')
+ {
+ if (p + 1 >= out + outlen)
+ break;
+ *p++ = *s++;
+ prevchar_isflag = prevchar_isitem = FALSE;
+ continue;
+ }
+ if (*s == STL_MIDDLEMARK)
+ {
+ s++;
+ if (groupdepth > 0)
+ continue;
+ item[curitem].type = Middle;
+ item[curitem++].start = p;
+ continue;
+ }
+ if (*s == STL_TRUNCMARK)
+ {
+ s++;
+ item[curitem].type = Trunc;
+ item[curitem++].start = p;
+ continue;
+ }
+ if (*s == ')')
+ {
+ s++;
+ if (groupdepth < 1)
+ continue;
+ groupdepth--;
+
+ t = item[groupitem[groupdepth]].start;
+ *p = NUL;
+ l = vim_strsize(t);
+ if (curitem > groupitem[groupdepth] + 1
+ && item[groupitem[groupdepth]].minwid == 0)
+ {
+ /* remove group if all items are empty and highlight group
+ * doesn't change */
+ group_start_userhl = group_end_userhl = 0;
+ for (n = groupitem[groupdepth] - 1; n >= 0; n--)
+ {
+ if (item[n].type == Highlight)
+ {
+ group_start_userhl = group_end_userhl = item[n].minwid;
+ break;
+ }
+ }
+ for (n = groupitem[groupdepth] + 1; n < curitem; n++)
+ {
+ if (item[n].type == Normal)
+ break;
+ if (item[n].type == Highlight)
+ group_end_userhl = item[n].minwid;
+ }
+ if (n == curitem && group_start_userhl == group_end_userhl)
+ {
+ p = t;
+ l = 0;
+ }
+ }
+ if (l > item[groupitem[groupdepth]].maxwid)
+ {
+ /* truncate, remove n bytes of text at the start */
+ if (has_mbyte)
+ {
+ /* Find the first character that should be included. */
+ n = 0;
+ while (l >= item[groupitem[groupdepth]].maxwid)
+ {
+ l -= ptr2cells(t + n);
+ n += (*mb_ptr2len)(t + n);
+ }
+ }
+ else
+ n = (long)(p - t) - item[groupitem[groupdepth]].maxwid + 1;
+
+ *t = '<';
+ mch_memmove(t + 1, t + n, (size_t)(p - (t + n)));
+ p = p - n + 1;
+
+ // Fill up space left over by half a double-wide char.
+ while (++l < item[groupitem[groupdepth]].minwid)
+ *p++ = fillchar;
+
+ /* correct the start of the items for the truncation */
+ for (l = groupitem[groupdepth] + 1; l < curitem; l++)
+ {
+ item[l].start -= n;
+ if (item[l].start < t)
+ item[l].start = t;
+ }
+ }
+ else if (abs(item[groupitem[groupdepth]].minwid) > l)
+ {
+ /* fill */
+ n = item[groupitem[groupdepth]].minwid;
+ if (n < 0)
+ {
+ /* fill by appending characters */
+ n = 0 - n;
+ while (l++ < n && p + 1 < out + outlen)
+ *p++ = fillchar;
+ }
+ else
+ {
+ /* fill by inserting characters */
+ mch_memmove(t + n - l, t, (size_t)(p - t));
+ l = n - l;
+ if (p + l >= out + outlen)
+ l = (long)((out + outlen) - p - 1);
+ p += l;
+ for (n = groupitem[groupdepth] + 1; n < curitem; n++)
+ item[n].start += l;
+ for ( ; l > 0; l--)
+ *t++ = fillchar;
+ }
+ }
+ continue;
+ }
+ minwid = 0;
+ maxwid = 9999;
+ zeropad = FALSE;
+ l = 1;
+ if (*s == '0')
+ {
+ s++;
+ zeropad = TRUE;
+ }
+ if (*s == '-')
+ {
+ s++;
+ l = -1;
+ }
+ if (VIM_ISDIGIT(*s))
+ {
+ minwid = (int)getdigits(&s);
+ if (minwid < 0) /* overflow */
+ minwid = 0;
+ }
+ if (*s == STL_USER_HL)
+ {
+ item[curitem].type = Highlight;
+ item[curitem].start = p;
+ item[curitem].minwid = minwid > 9 ? 1 : minwid;
+ s++;
+ curitem++;
+ continue;
+ }
+ if (*s == STL_TABPAGENR || *s == STL_TABCLOSENR)
+ {
+ if (*s == STL_TABCLOSENR)
+ {
+ if (minwid == 0)
+ {
+ /* %X ends the close label, go back to the previously
+ * define tab label nr. */
+ for (n = curitem - 1; n >= 0; --n)
+ if (item[n].type == TabPage && item[n].minwid >= 0)
+ {
+ minwid = item[n].minwid;
+ break;
+ }
+ }
+ else
+ /* close nrs are stored as negative values */
+ minwid = - minwid;
+ }
+ item[curitem].type = TabPage;
+ item[curitem].start = p;
+ item[curitem].minwid = minwid;
+ s++;
+ curitem++;
+ continue;
+ }
+ if (*s == '.')
+ {
+ s++;
+ if (VIM_ISDIGIT(*s))
+ {
+ maxwid = (int)getdigits(&s);
+ if (maxwid <= 0) /* overflow */
+ maxwid = 50;
+ }
+ }
+ minwid = (minwid > 50 ? 50 : minwid) * l;
+ if (*s == '(')
+ {
+ groupitem[groupdepth++] = curitem;
+ item[curitem].type = Group;
+ item[curitem].start = p;
+ item[curitem].minwid = minwid;
+ item[curitem].maxwid = maxwid;
+ s++;
+ curitem++;
+ continue;
+ }
+ if (vim_strchr(STL_ALL, *s) == NULL)
+ {
+ s++;
+ continue;
+ }
+ opt = *s++;
+
+ /* OK - now for the real work */
+ base = 'D';
+ itemisflag = FALSE;
+ fillable = TRUE;
+ num = -1;
+ str = NULL;
+ switch (opt)
+ {
+ case STL_FILEPATH:
+ case STL_FULLPATH:
+ case STL_FILENAME:
+ fillable = FALSE; /* don't change ' ' to fillchar */
+ if (buf_spname(wp->w_buffer) != NULL)
+ vim_strncpy(NameBuff, buf_spname(wp->w_buffer), MAXPATHL - 1);
+ else
+ {
+ t = (opt == STL_FULLPATH) ? wp->w_buffer->b_ffname
+ : wp->w_buffer->b_fname;
+ home_replace(wp->w_buffer, t, NameBuff, MAXPATHL, TRUE);
+ }
+ trans_characters(NameBuff, MAXPATHL);
+ if (opt != STL_FILENAME)
+ str = NameBuff;
+ else
+ str = gettail(NameBuff);
+ break;
+
+ case STL_VIM_EXPR: /* '{' */
+ itemisflag = TRUE;
+ t = p;
+ while (*s != '}' && *s != NUL && p + 1 < out + outlen)
+ *p++ = *s++;
+ if (*s != '}') /* missing '}' or out of space */
+ break;
+ s++;
+ *p = 0;
+ p = t;
+
+#ifdef FEAT_EVAL
+ vim_snprintf((char *)tmp, sizeof(tmp), "%d", curbuf->b_fnum);
+ set_internal_string_var((char_u *)"g:actual_curbuf", tmp);
+
+ save_curbuf = curbuf;
+ save_curwin = curwin;
+ curwin = wp;
+ curbuf = wp->w_buffer;
+
+ str = eval_to_string_safe(p, &t, use_sandbox);
+
+ curwin = save_curwin;
+ curbuf = save_curbuf;
+ do_unlet((char_u *)"g:actual_curbuf", TRUE);
+
+ if (str != NULL && *str != 0)
+ {
+ if (*skipdigits(str) == NUL)
+ {
+ num = atoi((char *)str);
+ VIM_CLEAR(str);
+ itemisflag = FALSE;
+ }
+ }
+#endif
+ break;
+
+ case STL_LINE:
+ num = (wp->w_buffer->b_ml.ml_flags & ML_EMPTY)
+ ? 0L : (long)(wp->w_cursor.lnum);
+ break;
+
+ case STL_NUMLINES:
+ num = wp->w_buffer->b_ml.ml_line_count;
+ break;
+
+ case STL_COLUMN:
+ num = !(State & INSERT) && empty_line
+ ? 0 : (int)wp->w_cursor.col + 1;
+ break;
+
+ case STL_VIRTCOL:
+ case STL_VIRTCOL_ALT:
+ /* In list mode virtcol needs to be recomputed */
+ virtcol = wp->w_virtcol;
+ if (wp->w_p_list && lcs_tab1 == NUL)
+ {
+ wp->w_p_list = FALSE;
+ getvcol(wp, &wp->w_cursor, NULL, &virtcol, NULL);
+ wp->w_p_list = TRUE;
+ }
+ ++virtcol;
+ /* Don't display %V if it's the same as %c. */
+ if (opt == STL_VIRTCOL_ALT
+ && (virtcol == (colnr_T)(!(State & INSERT) && empty_line
+ ? 0 : (int)wp->w_cursor.col + 1)))
+ break;
+ num = (long)virtcol;
+ break;
+
+ case STL_PERCENTAGE:
+ num = (int)(((long)wp->w_cursor.lnum * 100L) /
+ (long)wp->w_buffer->b_ml.ml_line_count);
+ break;
+
+ case STL_ALTPERCENT:
+ str = tmp;
+ get_rel_pos(wp, str, TMPLEN);
+ break;
+
+ case STL_ARGLISTSTAT:
+ fillable = FALSE;
+ tmp[0] = 0;
+ if (append_arg_number(wp, tmp, (int)sizeof(tmp), FALSE))
+ str = tmp;
+ break;
+
+ case STL_KEYMAP:
+ fillable = FALSE;
+ if (get_keymap_str(wp, (char_u *)"<%s>", tmp, TMPLEN))
+ str = tmp;
+ break;
+ case STL_PAGENUM:
+#if defined(FEAT_PRINTER) || defined(FEAT_GUI_TABLINE)
+ num = printer_page_num;
+#else
+ num = 0;
+#endif
+ break;
+
+ case STL_BUFNO:
+ num = wp->w_buffer->b_fnum;
+ break;
+
+ case STL_OFFSET_X:
+ base = 'X';
+ /* FALLTHROUGH */
+ case STL_OFFSET:
+#ifdef FEAT_BYTEOFF
+ l = ml_find_line_or_offset(wp->w_buffer, wp->w_cursor.lnum, NULL);
+ num = (wp->w_buffer->b_ml.ml_flags & ML_EMPTY) || l < 0 ?
+ 0L : l + 1 + (!(State & INSERT) && empty_line ?
+ 0 : (int)wp->w_cursor.col);
+#endif
+ break;
+
+ case STL_BYTEVAL_X:
+ base = 'X';
+ /* FALLTHROUGH */
+ case STL_BYTEVAL:
+ num = byteval;
+ if (num == NL)
+ num = 0;
+ else if (num == CAR && get_fileformat(wp->w_buffer) == EOL_MAC)
+ num = NL;
+ break;
+
+ case STL_ROFLAG:
+ case STL_ROFLAG_ALT:
+ itemisflag = TRUE;
+ if (wp->w_buffer->b_p_ro)
+ str = (char_u *)((opt == STL_ROFLAG_ALT) ? ",RO" : _("[RO]"));
+ break;
+
+ case STL_HELPFLAG:
+ case STL_HELPFLAG_ALT:
+ itemisflag = TRUE;
+ if (wp->w_buffer->b_help)
+ str = (char_u *)((opt == STL_HELPFLAG_ALT) ? ",HLP"
+ : _("[Help]"));
+ break;
+
+ case STL_FILETYPE:
+ if (*wp->w_buffer->b_p_ft != NUL
+ && STRLEN(wp->w_buffer->b_p_ft) < TMPLEN - 3)
+ {
+ vim_snprintf((char *)tmp, sizeof(tmp), "[%s]",
+ wp->w_buffer->b_p_ft);
+ str = tmp;
+ }
+ break;
+
+ case STL_FILETYPE_ALT:
+ itemisflag = TRUE;
+ if (*wp->w_buffer->b_p_ft != NUL
+ && STRLEN(wp->w_buffer->b_p_ft) < TMPLEN - 2)
+ {
+ vim_snprintf((char *)tmp, sizeof(tmp), ",%s",
+ wp->w_buffer->b_p_ft);
+ for (t = tmp; *t != 0; t++)
+ *t = TOUPPER_LOC(*t);
+ str = tmp;
+ }
+ break;
+
+#if defined(FEAT_QUICKFIX)
+ case STL_PREVIEWFLAG:
+ case STL_PREVIEWFLAG_ALT:
+ itemisflag = TRUE;
+ if (wp->w_p_pvw)
+ str = (char_u *)((opt == STL_PREVIEWFLAG_ALT) ? ",PRV"
+ : _("[Preview]"));
+ break;
+
+ case STL_QUICKFIX:
+ if (bt_quickfix(wp->w_buffer))
+ str = (char_u *)(wp->w_llist_ref
+ ? _(msg_loclist)
+ : _(msg_qflist));
+ break;
+#endif
+
+ case STL_MODIFIED:
+ case STL_MODIFIED_ALT:
+ itemisflag = TRUE;
+ switch ((opt == STL_MODIFIED_ALT)
+ + bufIsChanged(wp->w_buffer) * 2
+ + (!wp->w_buffer->b_p_ma) * 4)
+ {
+ case 2: str = (char_u *)"[+]"; break;
+ case 3: str = (char_u *)",+"; break;
+ case 4: str = (char_u *)"[-]"; break;
+ case 5: str = (char_u *)",-"; break;
+ case 6: str = (char_u *)"[+-]"; break;
+ case 7: str = (char_u *)",+-"; break;
+ }
+ break;
+
+ case STL_HIGHLIGHT:
+ t = s;
+ while (*s != '#' && *s != NUL)
+ ++s;
+ if (*s == '#')
+ {
+ item[curitem].type = Highlight;
+ item[curitem].start = p;
+ item[curitem].minwid = -syn_namen2id(t, (int)(s - t));
+ curitem++;
+ }
+ if (*s != NUL)
+ ++s;
+ continue;
+ }
+
+ item[curitem].start = p;
+ item[curitem].type = Normal;
+ if (str != NULL && *str)
+ {
+ t = str;
+ if (itemisflag)
+ {
+ if ((t[0] && t[1])
+ && ((!prevchar_isitem && *t == ',')
+ || (prevchar_isflag && *t == ' ')))
+ t++;
+ prevchar_isflag = TRUE;
+ }
+ l = vim_strsize(t);
+ if (l > 0)
+ prevchar_isitem = TRUE;
+ if (l > maxwid)
+ {
+ while (l >= maxwid)
+ if (has_mbyte)
+ {
+ l -= ptr2cells(t);
+ t += (*mb_ptr2len)(t);
+ }
+ else
+ l -= byte2cells(*t++);
+ if (p + 1 >= out + outlen)
+ break;
+ *p++ = '<';
+ }
+ if (minwid > 0)
+ {
+ for (; l < minwid && p + 1 < out + outlen; l++)
+ {
+ /* Don't put a "-" in front of a digit. */
+ if (l + 1 == minwid && fillchar == '-' && VIM_ISDIGIT(*t))
+ *p++ = ' ';
+ else
+ *p++ = fillchar;
+ }
+ minwid = 0;
+ }
+ else
+ minwid *= -1;
+ while (*t && p + 1 < out + outlen)
+ {
+ *p++ = *t++;
+ /* Change a space by fillchar, unless fillchar is '-' and a
+ * digit follows. */
+ if (fillable && p[-1] == ' '
+ && (!VIM_ISDIGIT(*t) || fillchar != '-'))
+ p[-1] = fillchar;
+ }
+ for (; l < minwid && p + 1 < out + outlen; l++)
+ *p++ = fillchar;
+ }
+ else if (num >= 0)
+ {
+ int nbase = (base == 'D' ? 10 : (base == 'O' ? 8 : 16));
+ char_u nstr[20];
+
+ if (p + 20 >= out + outlen)
+ break; /* not sufficient space */
+ prevchar_isitem = TRUE;
+ t = nstr;
+ if (opt == STL_VIRTCOL_ALT)
+ {
+ *t++ = '-';
+ minwid--;
+ }
+ *t++ = '%';
+ if (zeropad)
+ *t++ = '0';
+ *t++ = '*';
+ *t++ = nbase == 16 ? base : (char_u)(nbase == 8 ? 'o' : 'd');
+ *t = 0;
+
+ for (n = num, l = 1; n >= nbase; n /= nbase)
+ l++;
+ if (opt == STL_VIRTCOL_ALT)
+ l++;
+ if (l > maxwid)
+ {
+ l += 2;
+ n = l - maxwid;
+ while (l-- > maxwid)
+ num /= nbase;
+ *t++ = '>';
+ *t++ = '%';
+ *t = t[-3];
+ *++t = 0;
+ vim_snprintf((char *)p, outlen - (p - out), (char *)nstr,
+ 0, num, n);
+ }
+ else
+ vim_snprintf((char *)p, outlen - (p - out), (char *)nstr,
+ minwid, num);
+ p += STRLEN(p);
+ }
+ else
+ item[curitem].type = Empty;
+
+ if (opt == STL_VIM_EXPR)
+ vim_free(str);
+
+ if (num >= 0 || (!itemisflag && str && *str))
+ prevchar_isflag = FALSE; /* Item not NULL, but not a flag */
+ curitem++;
+ }
+ *p = NUL;
+ itemcnt = curitem;
+
+#ifdef FEAT_EVAL
+ if (usefmt != fmt)
+ vim_free(usefmt);
+#endif
+
+ width = vim_strsize(out);
+ if (maxwidth > 0 && width > maxwidth)
+ {
+ /* Result is too long, must truncate somewhere. */
+ l = 0;
+ if (itemcnt == 0)
+ s = out;
+ else
+ {
+ for ( ; l < itemcnt; l++)
+ if (item[l].type == Trunc)
+ {
+ /* Truncate at %< item. */
+ s = item[l].start;
+ break;
+ }
+ if (l == itemcnt)
+ {
+ /* No %< item, truncate first item. */
+ s = item[0].start;
+ l = 0;
+ }
+ }
+
+ if (width - vim_strsize(s) >= maxwidth)
+ {
+ /* Truncation mark is beyond max length */
+ if (has_mbyte)
+ {
+ s = out;
+ width = 0;
+ for (;;)
+ {
+ width += ptr2cells(s);
+ if (width >= maxwidth)
+ break;
+ s += (*mb_ptr2len)(s);
+ }
+ /* Fill up for half a double-wide character. */
+ while (++width < maxwidth)
+ *s++ = fillchar;
+ }
+ else
+ s = out + maxwidth - 1;
+ for (l = 0; l < itemcnt; l++)
+ if (item[l].start > s)
+ break;
+ itemcnt = l;
+ *s++ = '>';
+ *s = 0;
+ }
+ else
+ {
+ if (has_mbyte)
+ {
+ n = 0;
+ while (width >= maxwidth)
+ {
+ width -= ptr2cells(s + n);
+ n += (*mb_ptr2len)(s + n);
+ }
+ }
+ else
+ n = width - maxwidth + 1;
+ p = s + n;
+ STRMOVE(s + 1, p);
+ *s = '<';
+
+ /* Fill up for half a double-wide character. */
+ while (++width < maxwidth)
+ {
+ s = s + STRLEN(s);
+ *s++ = fillchar;
+ *s = NUL;
+ }
+
+ --n; /* count the '<' */
+ for (; l < itemcnt; l++)
+ {
+ if (item[l].start - n >= s)
+ item[l].start -= n;
+ else
+ item[l].start = s;
+ }
+ }
+ width = maxwidth;
+ }
+ else if (width < maxwidth && STRLEN(out) + maxwidth - width + 1 < outlen)
+ {
+ /* Apply STL_MIDDLE if any */
+ for (l = 0; l < itemcnt; l++)
+ if (item[l].type == Middle)
+ break;
+ if (l < itemcnt)
+ {
+ p = item[l].start + maxwidth - width;
+ STRMOVE(p, item[l].start);
+ for (s = item[l].start; s < p; s++)
+ *s = fillchar;
+ for (l++; l < itemcnt; l++)
+ item[l].start += maxwidth - width;
+ width = maxwidth;
+ }
+ }
+
+ /* Store the info about highlighting. */
+ if (hltab != NULL)
+ {
+ sp = hltab;
+ for (l = 0; l < itemcnt; l++)
+ {
+ if (item[l].type == Highlight)
+ {
+ sp->start = item[l].start;
+ sp->userhl = item[l].minwid;
+ sp++;
+ }
+ }
+ sp->start = NULL;
+ sp->userhl = 0;
+ }
+
+ /* Store the info about tab pages labels. */
+ if (tabtab != NULL)
+ {
+ sp = tabtab;
+ for (l = 0; l < itemcnt; l++)
+ {
+ if (item[l].type == TabPage)
+ {
+ sp->start = item[l].start;
+ sp->userhl = item[l].minwid;
+ sp++;
+ }
+ }
+ sp->start = NULL;
+ sp->userhl = 0;
+ }
+
+ /* When inside update_screen we do not want redrawing a stausline, ruler,
+ * title, etc. to trigger another redraw, it may cause an endless loop. */
+ if (updating_screen)
+ {
+ must_redraw = save_must_redraw;
+ curwin->w_redr_type = save_redr_type;
+ }
+
+ return width;
+}
+#endif /* FEAT_STL_OPT */
+
+#if defined(FEAT_STL_OPT) || defined(FEAT_CMDL_INFO) \
+ || defined(FEAT_GUI_TABLINE) || defined(PROTO)
+/*
+ * Get relative cursor position in window into "buf[buflen]", in the form 99%,
+ * using "Top", "Bot" or "All" when appropriate.
+ */
+ void
+get_rel_pos(
+ win_T *wp,
+ char_u *buf,
+ int buflen)
+{
+ long above; /* number of lines above window */
+ long below; /* number of lines below window */
+
+ if (buflen < 3) /* need at least 3 chars for writing */
+ return;
+ above = wp->w_topline - 1;
+#ifdef FEAT_DIFF
+ above += diff_check_fill(wp, wp->w_topline) - wp->w_topfill;
+ if (wp->w_topline == 1 && wp->w_topfill >= 1)
+ above = 0; /* All buffer lines are displayed and there is an
+ * indication of filler lines, that can be considered
+ * seeing all lines. */
+#endif
+ below = wp->w_buffer->b_ml.ml_line_count - wp->w_botline + 1;
+ if (below <= 0)
+ vim_strncpy(buf, (char_u *)(above == 0 ? _("All") : _("Bot")),
+ (size_t)(buflen - 1));
+ else if (above <= 0)
+ vim_strncpy(buf, (char_u *)_("Top"), (size_t)(buflen - 1));
+ else
+ vim_snprintf((char *)buf, (size_t)buflen, "%2d%%", above > 1000000L
+ ? (int)(above / ((above + below) / 100L))
+ : (int)(above * 100L / (above + below)));
+}
+#endif
+
+/*
+ * Append (file 2 of 8) to "buf[buflen]", if editing more than one file.
+ * Return TRUE if it was appended.
+ */
+ static int
+append_arg_number(
+ win_T *wp,
+ char_u *buf,
+ int buflen,
+ int add_file) /* Add "file" before the arg number */
+{
+ char_u *p;
+
+ if (ARGCOUNT <= 1) /* nothing to do */
+ return FALSE;
+
+ p = buf + STRLEN(buf); /* go to the end of the buffer */
+ if (p - buf + 35 >= buflen) /* getting too long */
+ return FALSE;
+ *p++ = ' ';
+ *p++ = '(';
+ if (add_file)
+ {
+ STRCPY(p, "file ");
+ p += 5;
+ }
+ vim_snprintf((char *)p, (size_t)(buflen - (p - buf)),
+ wp->w_arg_idx_invalid ? "(%d) of %d)"
+ : "%d of %d)", wp->w_arg_idx + 1, ARGCOUNT);
+ return TRUE;
+}
+
+/*
+ * If fname is not a full path, make it a full path.
+ * Returns pointer to allocated memory (NULL for failure).
+ */
+ char_u *
+fix_fname(char_u *fname)
+{
+ /*
+ * Force expanding the path always for Unix, because symbolic links may
+ * mess up the full path name, even though it starts with a '/'.
+ * Also expand when there is ".." in the file name, try to remove it,
+ * because "c:/src/../README" is equal to "c:/README".
+ * Similarly "c:/src//file" is equal to "c:/src/file".
+ * For MS-Windows also expand names like "longna~1" to "longname".
+ */
+#ifdef UNIX
+ return FullName_save(fname, TRUE);
+#else
+ if (!vim_isAbsName(fname)
+ || strstr((char *)fname, "..") != NULL
+ || strstr((char *)fname, "//") != NULL
+# ifdef BACKSLASH_IN_FILENAME
+ || strstr((char *)fname, "\\\\") != NULL
+# endif
+# if defined(MSWIN)
+ || vim_strchr(fname, '~') != NULL
+# endif
+ )
+ return FullName_save(fname, FALSE);
+
+ fname = vim_strsave(fname);
+
+# ifdef USE_FNAME_CASE
+# ifdef USE_LONG_FNAME
+ if (USE_LONG_FNAME)
+# endif
+ {
+ if (fname != NULL)
+ fname_case(fname, 0); /* set correct case for file name */
+ }
+# endif
+
+ return fname;
+#endif
+}
+
+/*
+ * Make "*ffname" a full file name, set "*sfname" to "*ffname" if not NULL.
+ * "*ffname" becomes a pointer to allocated memory (or NULL).
+ * When resolving a link both "*sfname" and "*ffname" will point to the same
+ * allocated memory.
+ * The "*ffname" and "*sfname" pointer values on call will not be freed.
+ * Note that the resulting "*ffname" pointer should be considered not allocaed.
+ */
+ void
+fname_expand(
+ buf_T *buf UNUSED,
+ char_u **ffname,
+ char_u **sfname)
+{
+ if (*ffname == NULL) // no file name given, nothing to do
+ return;
+ if (*sfname == NULL) // no short file name given, use ffname
+ *sfname = *ffname;
+ *ffname = fix_fname(*ffname); // expand to full path
+
+#ifdef FEAT_SHORTCUT
+ if (!buf->b_p_bin)
+ {
+ char_u *rfname;
+
+ // If the file name is a shortcut file, use the file it links to.
+ rfname = mch_resolve_shortcut(*ffname);
+ if (rfname != NULL)
+ {
+ vim_free(*ffname);
+ *ffname = rfname;
+ *sfname = rfname;
+ }
+ }
+#endif
+}
+
+/*
+ * Get the file name for an argument list entry.
+ */
+ char_u *
+alist_name(aentry_T *aep)
+{
+ buf_T *bp;
+
+ /* Use the name from the associated buffer if it exists. */
+ bp = buflist_findnr(aep->ae_fnum);
+ if (bp == NULL || bp->b_fname == NULL)
+ return aep->ae_fname;
+ return bp->b_fname;
+}
+
+/*
+ * do_arg_all(): Open up to 'count' windows, one for each argument.
+ */
+ void
+do_arg_all(
+ int count,
+ int forceit, /* hide buffers in current windows */
+ int keep_tabs) /* keep current tabs, for ":tab drop file" */
+{
+ int i;
+ win_T *wp, *wpnext;
+ char_u *opened; /* Array of weight for which args are open:
+ * 0: not opened
+ * 1: opened in other tab
+ * 2: opened in curtab
+ * 3: opened in curtab and curwin
+ */
+ int opened_len; /* length of opened[] */
+ int use_firstwin = FALSE; /* use first window for arglist */
+ int split_ret = OK;
+ int p_ea_save;
+ alist_T *alist; /* argument list to be used */
+ buf_T *buf;
+ tabpage_T *tpnext;
+ int had_tab = cmdmod.tab;
+ win_T *old_curwin, *last_curwin;
+ tabpage_T *old_curtab, *last_curtab;
+ win_T *new_curwin = NULL;
+ tabpage_T *new_curtab = NULL;
+
+ if (ARGCOUNT <= 0)
+ {
+ /* Don't give an error message. We don't want it when the ":all"
+ * command is in the .vimrc. */
+ return;
+ }
+ setpcmark();
+
+ opened_len = ARGCOUNT;
+ opened = alloc_clear((unsigned)opened_len);
+ if (opened == NULL)
+ return;
+
+ /* Autocommands may do anything to the argument list. Make sure it's not
+ * freed while we are working here by "locking" it. We still have to
+ * watch out for its size to be changed. */
+ alist = curwin->w_alist;
+ ++alist->al_refcount;
+
+ old_curwin = curwin;
+ old_curtab = curtab;
+
+# ifdef FEAT_GUI
+ need_mouse_correct = TRUE;
+# endif
+
+ /*
+ * Try closing all windows that are not in the argument list.
+ * Also close windows that are not full width;
+ * When 'hidden' or "forceit" set the buffer becomes hidden.
+ * Windows that have a changed buffer and can't be hidden won't be closed.
+ * When the ":tab" modifier was used do this for all tab pages.
+ */
+ if (had_tab > 0)
+ goto_tabpage_tp(first_tabpage, TRUE, TRUE);
+ for (;;)
+ {
+ tpnext = curtab->tp_next;
+ for (wp = firstwin; wp != NULL; wp = wpnext)
+ {
+ wpnext = wp->w_next;
+ buf = wp->w_buffer;
+ if (buf->b_ffname == NULL
+ || (!keep_tabs && (buf->b_nwindows > 1
+ || wp->w_width != Columns)))
+ i = opened_len;
+ else
+ {
+ /* check if the buffer in this window is in the arglist */
+ for (i = 0; i < opened_len; ++i)
+ {
+ if (i < alist->al_ga.ga_len
+ && (AARGLIST(alist)[i].ae_fnum == buf->b_fnum
+ || fullpathcmp(alist_name(&AARGLIST(alist)[i]),
+ buf->b_ffname, TRUE) & FPC_SAME))
+ {
+ int weight = 1;
+
+ if (old_curtab == curtab)
+ {
+ ++weight;
+ if (old_curwin == wp)
+ ++weight;
+ }
+
+ if (weight > (int)opened[i])
+ {
+ opened[i] = (char_u)weight;
+ if (i == 0)
+ {
+ if (new_curwin != NULL)
+ new_curwin->w_arg_idx = opened_len;
+ new_curwin = wp;
+ new_curtab = curtab;
+ }
+ }
+ else if (keep_tabs)
+ i = opened_len;
+
+ if (wp->w_alist != alist)
+ {
+ /* Use the current argument list for all windows
+ * containing a file from it. */
+ alist_unlink(wp->w_alist);
+ wp->w_alist = alist;
+ ++wp->w_alist->al_refcount;
+ }
+ break;
+ }
+ }
+ }
+ wp->w_arg_idx = i;
+
+ if (i == opened_len && !keep_tabs)/* close this window */
+ {
+ if (buf_hide(buf) || forceit || buf->b_nwindows > 1
+ || !bufIsChanged(buf))
+ {
+ /* If the buffer was changed, and we would like to hide it,
+ * try autowriting. */
+ if (!buf_hide(buf) && buf->b_nwindows <= 1
+ && bufIsChanged(buf))
+ {
+ bufref_T bufref;
+
+ set_bufref(&bufref, buf);
+
+ (void)autowrite(buf, FALSE);
+
+ /* check if autocommands removed the window */
+ if (!win_valid(wp) || !bufref_valid(&bufref))
+ {
+ wpnext = firstwin; /* start all over... */
+ continue;
+ }
+ }
+ /* don't close last window */
+ if (ONE_WINDOW
+ && (first_tabpage->tp_next == NULL || !had_tab))
+ use_firstwin = TRUE;
+ else
+ {
+ win_close(wp, !buf_hide(buf) && !bufIsChanged(buf));
+
+ /* check if autocommands removed the next window */
+ if (!win_valid(wpnext))
+ wpnext = firstwin; /* start all over... */
+ }
+ }
+ }
+ }
+
+ /* Without the ":tab" modifier only do the current tab page. */
+ if (had_tab == 0 || tpnext == NULL)
+ break;
+
+ /* check if autocommands removed the next tab page */
+ if (!valid_tabpage(tpnext))
+ tpnext = first_tabpage; /* start all over...*/
+
+ goto_tabpage_tp(tpnext, TRUE, TRUE);
+ }
+
+ /*
+ * Open a window for files in the argument list that don't have one.
+ * ARGCOUNT may change while doing this, because of autocommands.
+ */
+ if (count > opened_len || count <= 0)
+ count = opened_len;
+
+ /* Don't execute Win/Buf Enter/Leave autocommands here. */
+ ++autocmd_no_enter;
+ ++autocmd_no_leave;
+ last_curwin = curwin;
+ last_curtab = curtab;
+ win_enter(lastwin, FALSE);
+ /* ":drop all" should re-use an empty window to avoid "--remote-tab"
+ * leaving an empty tab page when executed locally. */
+ if (keep_tabs && BUFEMPTY() && curbuf->b_nwindows == 1
+ && curbuf->b_ffname == NULL && !curbuf->b_changed)
+ use_firstwin = TRUE;
+
+ for (i = 0; i < count && i < opened_len && !got_int; ++i)
+ {
+ if (alist == &global_alist && i == global_alist.al_ga.ga_len - 1)
+ arg_had_last = TRUE;
+ if (opened[i] > 0)
+ {
+ /* Move the already present window to below the current window */
+ if (curwin->w_arg_idx != i)
+ {
+ for (wpnext = firstwin; wpnext != NULL; wpnext = wpnext->w_next)
+ {
+ if (wpnext->w_arg_idx == i)
+ {
+ if (keep_tabs)
+ {
+ new_curwin = wpnext;
+ new_curtab = curtab;
+ }
+ else
+ win_move_after(wpnext, curwin);
+ break;
+ }
+ }
+ }
+ }
+ else if (split_ret == OK)
+ {
+ if (!use_firstwin) /* split current window */
+ {
+ p_ea_save = p_ea;
+ p_ea = TRUE; /* use space from all windows */
+ split_ret = win_split(0, WSP_ROOM | WSP_BELOW);
+ p_ea = p_ea_save;
+ if (split_ret == FAIL)
+ continue;
+ }
+ else /* first window: do autocmd for leaving this buffer */
+ --autocmd_no_leave;
+
+ /*
+ * edit file "i"
+ */
+ curwin->w_arg_idx = i;
+ if (i == 0)
+ {
+ new_curwin = curwin;
+ new_curtab = curtab;
+ }
+ (void)do_ecmd(0, alist_name(&AARGLIST(alist)[i]), NULL, NULL,
+ ECMD_ONE,
+ ((buf_hide(curwin->w_buffer)
+ || bufIsChanged(curwin->w_buffer)) ? ECMD_HIDE : 0)
+ + ECMD_OLDBUF, curwin);
+ if (use_firstwin)
+ ++autocmd_no_leave;
+ use_firstwin = FALSE;
+ }
+ ui_breakcheck();
+
+ /* When ":tab" was used open a new tab for a new window repeatedly. */
+ if (had_tab > 0 && tabpage_index(NULL) <= p_tpm)
+ cmdmod.tab = 9999;
+ }
+
+ /* Remove the "lock" on the argument list. */
+ alist_unlink(alist);
+
+ --autocmd_no_enter;
+
+ /* restore last referenced tabpage's curwin */
+ if (last_curtab != new_curtab)
+ {
+ if (valid_tabpage(last_curtab))
+ goto_tabpage_tp(last_curtab, TRUE, TRUE);
+ if (win_valid(last_curwin))
+ win_enter(last_curwin, FALSE);
+ }
+ /* to window with first arg */
+ if (valid_tabpage(new_curtab))
+ goto_tabpage_tp(new_curtab, TRUE, TRUE);
+ if (win_valid(new_curwin))
+ win_enter(new_curwin, FALSE);
+
+ --autocmd_no_leave;
+ vim_free(opened);
+}
+
+/*
+ * Open a window for a number of buffers.
+ */
+ void
+ex_buffer_all(exarg_T *eap)
+{
+ buf_T *buf;
+ win_T *wp, *wpnext;
+ int split_ret = OK;
+ int p_ea_save;
+ int open_wins = 0;
+ int r;
+ int count; /* Maximum number of windows to open. */
+ int all; /* When TRUE also load inactive buffers. */
+ int had_tab = cmdmod.tab;
+ tabpage_T *tpnext;
+
+ if (eap->addr_count == 0) /* make as many windows as possible */
+ count = 9999;
+ else
+ count = eap->line2; /* make as many windows as specified */
+ if (eap->cmdidx == CMD_unhide || eap->cmdidx == CMD_sunhide)
+ all = FALSE;
+ else
+ all = TRUE;
+
+ setpcmark();
+
+#ifdef FEAT_GUI
+ need_mouse_correct = TRUE;
+#endif
+
+ /*
+ * Close superfluous windows (two windows for the same buffer).
+ * Also close windows that are not full-width.
+ */
+ if (had_tab > 0)
+ goto_tabpage_tp(first_tabpage, TRUE, TRUE);
+ for (;;)
+ {
+ tpnext = curtab->tp_next;
+ for (wp = firstwin; wp != NULL; wp = wpnext)
+ {
+ wpnext = wp->w_next;
+ if ((wp->w_buffer->b_nwindows > 1
+ || ((cmdmod.split & WSP_VERT)
+ ? wp->w_height + wp->w_status_height < Rows - p_ch
+ - tabline_height()
+ : wp->w_width != Columns)
+ || (had_tab > 0 && wp != firstwin)) && !ONE_WINDOW
+ && !(wp->w_closing || wp->w_buffer->b_locked > 0))
+ {
+ win_close(wp, FALSE);
+ wpnext = firstwin; /* just in case an autocommand does
+ something strange with windows */
+ tpnext = first_tabpage; /* start all over... */
+ open_wins = 0;
+ }
+ else
+ ++open_wins;
+ }
+
+ /* Without the ":tab" modifier only do the current tab page. */
+ if (had_tab == 0 || tpnext == NULL)
+ break;
+ goto_tabpage_tp(tpnext, TRUE, TRUE);
+ }
+
+ /*
+ * Go through the buffer list. When a buffer doesn't have a window yet,
+ * open one. Otherwise move the window to the right position.
+ * Watch out for autocommands that delete buffers or windows!
+ */
+ /* Don't execute Win/Buf Enter/Leave autocommands here. */
+ ++autocmd_no_enter;
+ win_enter(lastwin, FALSE);
+ ++autocmd_no_leave;
+ for (buf = firstbuf; buf != NULL && open_wins < count; buf = buf->b_next)
+ {
+ /* Check if this buffer needs a window */
+ if ((!all && buf->b_ml.ml_mfp == NULL) || !buf->b_p_bl)
+ continue;
+
+ if (had_tab != 0)
+ {
+ /* With the ":tab" modifier don't move the window. */
+ if (buf->b_nwindows > 0)
+ wp = lastwin; /* buffer has a window, skip it */
+ else
+ wp = NULL;
+ }
+ else
+ {
+ /* Check if this buffer already has a window */
+ FOR_ALL_WINDOWS(wp)
+ if (wp->w_buffer == buf)
+ break;
+ /* If the buffer already has a window, move it */
+ if (wp != NULL)
+ win_move_after(wp, curwin);
+ }
+
+ if (wp == NULL && split_ret == OK)
+ {
+ bufref_T bufref;
+
+ set_bufref(&bufref, buf);
+
+ /* Split the window and put the buffer in it */
+ p_ea_save = p_ea;
+ p_ea = TRUE; /* use space from all windows */
+ split_ret = win_split(0, WSP_ROOM | WSP_BELOW);
+ ++open_wins;
+ p_ea = p_ea_save;
+ if (split_ret == FAIL)
+ continue;
+
+ /* Open the buffer in this window. */
+#if defined(HAS_SWAP_EXISTS_ACTION)
+ swap_exists_action = SEA_DIALOG;
+#endif
+ set_curbuf(buf, DOBUF_GOTO);
+ if (!bufref_valid(&bufref))
+ {
+ /* autocommands deleted the buffer!!! */
+#if defined(HAS_SWAP_EXISTS_ACTION)
+ swap_exists_action = SEA_NONE;
+#endif
+ break;
+ }
+#if defined(HAS_SWAP_EXISTS_ACTION)
+ if (swap_exists_action == SEA_QUIT)
+ {
+# if defined(FEAT_EVAL)
+ cleanup_T cs;
+
+ /* Reset the error/interrupt/exception state here so that
+ * aborting() returns FALSE when closing a window. */
+ enter_cleanup(&cs);
+# endif
+
+ /* User selected Quit at ATTENTION prompt; close this window. */
+ win_close(curwin, TRUE);
+ --open_wins;
+ swap_exists_action = SEA_NONE;
+ swap_exists_did_quit = TRUE;
+
+# if defined(FEAT_EVAL)
+ /* Restore the error/interrupt/exception state if not
+ * discarded by a new aborting error, interrupt, or uncaught
+ * exception. */
+ leave_cleanup(&cs);
+# endif
+ }
+ else
+ handle_swap_exists(NULL);
+#endif
+ }
+
+ ui_breakcheck();
+ if (got_int)
+ {
+ (void)vgetc(); /* only break the file loading, not the rest */
+ break;
+ }
+#ifdef FEAT_EVAL
+ /* Autocommands deleted the buffer or aborted script processing!!! */
+ if (aborting())
+ break;
+#endif
+ /* When ":tab" was used open a new tab for a new window repeatedly. */
+ if (had_tab > 0 && tabpage_index(NULL) <= p_tpm)
+ cmdmod.tab = 9999;
+ }
+ --autocmd_no_enter;
+ win_enter(firstwin, FALSE); /* back to first window */
+ --autocmd_no_leave;
+
+ /*
+ * Close superfluous windows.
+ */
+ for (wp = lastwin; open_wins > count; )
+ {
+ r = (buf_hide(wp->w_buffer) || !bufIsChanged(wp->w_buffer)
+ || autowrite(wp->w_buffer, FALSE) == OK);
+ if (!win_valid(wp))
+ {
+ /* BufWrite Autocommands made the window invalid, start over */
+ wp = lastwin;
+ }
+ else if (r)
+ {
+ win_close(wp, !buf_hide(wp->w_buffer));
+ --open_wins;
+ wp = lastwin;
+ }
+ else
+ {
+ wp = wp->w_prev;
+ if (wp == NULL)
+ break;
+ }
+ }
+}
+
+
+static int chk_modeline(linenr_T, int);
+
+/*
+ * do_modelines() - process mode lines for the current file
+ *
+ * "flags" can be:
+ * OPT_WINONLY only set options local to window
+ * OPT_NOWIN don't set options local to window
+ *
+ * Returns immediately if the "ml" option isn't set.
+ */
+ void
+do_modelines(int flags)
+{
+ linenr_T lnum;
+ int nmlines;
+ static int entered = 0;
+
+ if (!curbuf->b_p_ml || (nmlines = (int)p_mls) == 0)
+ return;
+
+ /* Disallow recursive entry here. Can happen when executing a modeline
+ * triggers an autocommand, which reloads modelines with a ":do". */
+ if (entered)
+ return;
+
+ ++entered;
+ for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count && lnum <= nmlines;
+ ++lnum)
+ if (chk_modeline(lnum, flags) == FAIL)
+ nmlines = 0;
+
+ for (lnum = curbuf->b_ml.ml_line_count; lnum > 0 && lnum > nmlines
+ && lnum > curbuf->b_ml.ml_line_count - nmlines; --lnum)
+ if (chk_modeline(lnum, flags) == FAIL)
+ nmlines = 0;
+ --entered;
+}
+
+#include "version.h" /* for version number */
+
+/*
+ * chk_modeline() - check a single line for a mode string
+ * Return FAIL if an error encountered.
+ */
+ static int
+chk_modeline(
+ linenr_T lnum,
+ int flags) /* Same as for do_modelines(). */
+{
+ char_u *s;
+ char_u *e;
+ char_u *linecopy; /* local copy of any modeline found */
+ int prev;
+ int vers;
+ int end;
+ int retval = OK;
+ char_u *save_sourcing_name;
+ linenr_T save_sourcing_lnum;
+#ifdef FEAT_EVAL
+ sctx_T save_current_sctx;
+#endif
+
+ prev = -1;
+ for (s = ml_get(lnum); *s != NUL; ++s)
+ {
+ if (prev == -1 || vim_isspace(prev))
+ {
+ if ((prev != -1 && STRNCMP(s, "ex:", (size_t)3) == 0)
+ || STRNCMP(s, "vi:", (size_t)3) == 0)
+ break;
+ /* Accept both "vim" and "Vim". */
+ if ((s[0] == 'v' || s[0] == 'V') && s[1] == 'i' && s[2] == 'm')
+ {
+ if (s[3] == '<' || s[3] == '=' || s[3] == '>')
+ e = s + 4;
+ else
+ e = s + 3;
+ vers = getdigits(&e);
+ if (*e == ':'
+ && (s[0] != 'V'
+ || STRNCMP(skipwhite(e + 1), "set", 3) == 0)
+ && (s[3] == ':'
+ || (VIM_VERSION_100 >= vers && isdigit(s[3]))
+ || (VIM_VERSION_100 < vers && s[3] == '<')
+ || (VIM_VERSION_100 > vers && s[3] == '>')
+ || (VIM_VERSION_100 == vers && s[3] == '=')))
+ break;
+ }
+ }
+ prev = *s;
+ }
+
+ if (*s)
+ {
+ do /* skip over "ex:", "vi:" or "vim:" */
+ ++s;
+ while (s[-1] != ':');
+
+ s = linecopy = vim_strsave(s); /* copy the line, it will change */
+ if (linecopy == NULL)
+ return FAIL;
+
+ save_sourcing_lnum = sourcing_lnum;
+ save_sourcing_name = sourcing_name;
+ sourcing_lnum = lnum; /* prepare for emsg() */
+ sourcing_name = (char_u *)"modelines";
+
+ end = FALSE;
+ while (end == FALSE)
+ {
+ s = skipwhite(s);
+ if (*s == NUL)
+ break;
+
+ /*
+ * Find end of set command: ':' or end of line.
+ * Skip over "\:", replacing it with ":".
+ */
+ for (e = s; *e != ':' && *e != NUL; ++e)
+ if (e[0] == '\\' && e[1] == ':')
+ STRMOVE(e, e + 1);
+ if (*e == NUL)
+ end = TRUE;
+
+ /*
+ * If there is a "set" command, require a terminating ':' and
+ * ignore the stuff after the ':'.
+ * "vi:set opt opt opt: foo" -- foo not interpreted
+ * "vi:opt opt opt: foo" -- foo interpreted
+ * Accept "se" for compatibility with Elvis.
+ */
+ if (STRNCMP(s, "set ", (size_t)4) == 0
+ || STRNCMP(s, "se ", (size_t)3) == 0)
+ {
+ if (*e != ':') /* no terminating ':'? */
+ break;
+ end = TRUE;
+ s = vim_strchr(s, ' ') + 1;
+ }
+ *e = NUL; /* truncate the set command */
+
+ if (*s != NUL) /* skip over an empty "::" */
+ {
+ int secure_save = secure;
+#ifdef FEAT_EVAL
+ save_current_sctx = current_sctx;
+ current_sctx.sc_sid = SID_MODELINE;
+ current_sctx.sc_seq = 0;
+ current_sctx.sc_lnum = 0;
+#endif
+ // Make sure no risky things are executed as a side effect.
+ ++secure;
+
+ retval = do_set(s, OPT_MODELINE | OPT_LOCAL | flags);
+
+ secure = secure_save;
+#ifdef FEAT_EVAL
+ current_sctx = save_current_sctx;
+#endif
+ if (retval == FAIL) /* stop if error found */
+ break;
+ }
+ s = e + 1; /* advance to next part */
+ }
+
+ sourcing_lnum = save_sourcing_lnum;
+ sourcing_name = save_sourcing_name;
+
+ vim_free(linecopy);
+ }
+ return retval;
+}
+
+#if defined(FEAT_VIMINFO) || defined(PROTO)
+ int
+read_viminfo_bufferlist(
+ vir_T *virp,
+ int writing)
+{
+ char_u *tab;
+ linenr_T lnum;
+ colnr_T col;
+ buf_T *buf;
+ char_u *sfname;
+ char_u *xline;
+
+ /* Handle long line and escaped characters. */
+ xline = viminfo_readstring(virp, 1, FALSE);
+
+ /* don't read in if there are files on the command-line or if writing: */
+ if (xline != NULL && !writing && ARGCOUNT == 0
+ && find_viminfo_parameter('%') != NULL)
+ {
+ /* Format is: <fname> Tab <lnum> Tab <col>.
+ * Watch out for a Tab in the file name, work from the end. */
+ lnum = 0;
+ col = 0;
+ tab = vim_strrchr(xline, '\t');
+ if (tab != NULL)
+ {
+ *tab++ = '\0';
+ col = (colnr_T)atoi((char *)tab);
+ tab = vim_strrchr(xline, '\t');
+ if (tab != NULL)
+ {
+ *tab++ = '\0';
+ lnum = atol((char *)tab);
+ }
+ }
+
+ /* Expand "~/" in the file name at "line + 1" to a full path.
+ * Then try shortening it by comparing with the current directory */
+ expand_env(xline, NameBuff, MAXPATHL);
+ sfname = shorten_fname1(NameBuff);
+
+ buf = buflist_new(NameBuff, sfname, (linenr_T)0, BLN_LISTED);
+ if (buf != NULL) /* just in case... */
+ {
+ buf->b_last_cursor.lnum = lnum;
+ buf->b_last_cursor.col = col;
+ buflist_setfpos(buf, curwin, lnum, col, FALSE);
+ }
+ }
+ vim_free(xline);
+
+ return viminfo_readline(virp);
+}
+
+ void
+write_viminfo_bufferlist(FILE *fp)
+{
+ buf_T *buf;
+ win_T *win;
+ tabpage_T *tp;
+ char_u *line;
+ int max_buffers;
+
+ if (find_viminfo_parameter('%') == NULL)
+ return;
+
+ /* Without a number -1 is returned: do all buffers. */
+ max_buffers = get_viminfo_parameter('%');
+
+ /* Allocate room for the file name, lnum and col. */
+#define LINE_BUF_LEN (MAXPATHL + 40)
+ line = alloc(LINE_BUF_LEN);
+ if (line == NULL)
+ return;
+
+ FOR_ALL_TAB_WINDOWS(tp, win)
+ set_last_cursor(win);
+
+ fputs(_("\n# Buffer list:\n"), fp);
+ FOR_ALL_BUFFERS(buf)
+ {
+ if (buf->b_fname == NULL
+ || !buf->b_p_bl
+#ifdef FEAT_QUICKFIX
+ || bt_quickfix(buf)
+#endif
+#ifdef FEAT_TERMINAL
+ || bt_terminal(buf)
+#endif
+ || removable(buf->b_ffname))
+ continue;
+
+ if (max_buffers-- == 0)
+ break;
+ putc('%', fp);
+ home_replace(NULL, buf->b_ffname, line, MAXPATHL, TRUE);
+ vim_snprintf_add((char *)line, LINE_BUF_LEN, "\t%ld\t%d",
+ (long)buf->b_last_cursor.lnum,
+ buf->b_last_cursor.col);
+ viminfo_writestring(fp, line);
+ }
+ vim_free(line);
+}
+#endif
+
+/*
+ * Return TRUE if "buf" is a normal buffer, 'buftype' is empty.
+ */
+ int
+bt_normal(buf_T *buf)
+{
+ return buf != NULL && buf->b_p_bt[0] == NUL;
+}
+
+#if defined(FEAT_QUICKFIX) || defined(PROTO)
+/*
+ * Return TRUE if "buf" is the quickfix buffer.
+ */
+ int
+bt_quickfix(buf_T *buf)
+{
+ return buf != NULL && buf->b_p_bt[0] == 'q';
+}
+#endif
+
+#if defined(FEAT_TERMINAL) || defined(PROTO)
+/*
+ * Return TRUE if "buf" is a terminal buffer.
+ */
+ int
+bt_terminal(buf_T *buf)
+{
+ return buf != NULL && buf->b_p_bt[0] == 't';
+}
+#endif
+
+/*
+ * Return TRUE if "buf" is a help buffer.
+ */
+ int
+bt_help(buf_T *buf)
+{
+ return buf != NULL && buf->b_help;
+}
+
+/*
+ * Return TRUE if "buf" is a prompt buffer.
+ */
+ int
+bt_prompt(buf_T *buf)
+{
+ return buf != NULL && buf->b_p_bt[0] == 'p';
+}
+
+/*
+ * Return TRUE if "buf" is a "nofile", "acwrite", "terminal" or "prompt"
+ * buffer. This means the buffer name is not a file name.
+ */
+ int
+bt_nofile(buf_T *buf)
+{
+ return buf != NULL && ((buf->b_p_bt[0] == 'n' && buf->b_p_bt[2] == 'f')
+ || buf->b_p_bt[0] == 'a'
+ || buf->b_p_bt[0] == 't'
+ || buf->b_p_bt[0] == 'p');
+}
+
+/*
+ * Return TRUE if "buf" is a "nowrite", "nofile", "terminal" or "prompt"
+ * buffer.
+ */
+ int
+bt_dontwrite(buf_T *buf)
+{
+ return buf != NULL && (buf->b_p_bt[0] == 'n'
+ || buf->b_p_bt[0] == 't'
+ || buf->b_p_bt[0] == 'p');
+}
+
+#if defined(FEAT_QUICKFIX) || defined(PROTO)
+ int
+bt_dontwrite_msg(buf_T *buf)
+{
+ if (bt_dontwrite(buf))
+ {
+ emsg(_("E382: Cannot write, 'buftype' option is set"));
+ return TRUE;
+ }
+ return FALSE;
+}
+#endif
+
+/*
+ * Return TRUE if the buffer should be hidden, according to 'hidden', ":hide"
+ * and 'bufhidden'.
+ */
+ int
+buf_hide(buf_T *buf)
+{
+ /* 'bufhidden' overrules 'hidden' and ":hide", check it first */
+ switch (buf->b_p_bh[0])
+ {
+ case 'u': /* "unload" */
+ case 'w': /* "wipe" */
+ case 'd': return FALSE; /* "delete" */
+ case 'h': return TRUE; /* "hide" */
+ }
+ return (p_hid || cmdmod.hide);
+}
+
+/*
+ * Return special buffer name.
+ * Returns NULL when the buffer has a normal file name.
+ */
+ char_u *
+buf_spname(buf_T *buf)
+{
+#if defined(FEAT_QUICKFIX)
+ if (bt_quickfix(buf))
+ {
+ win_T *win;
+ tabpage_T *tp;
+
+ /*
+ * For location list window, w_llist_ref points to the location list.
+ * For quickfix window, w_llist_ref is NULL.
+ */
+ if (find_win_for_buf(buf, &win, &tp) == OK && win->w_llist_ref != NULL)
+ return (char_u *)_(msg_loclist);
+ else
+ return (char_u *)_(msg_qflist);
+ }
+#endif
+
+ /* There is no _file_ when 'buftype' is "nofile", b_sfname
+ * contains the name as specified by the user. */
+ if (bt_nofile(buf))
+ {
+#ifdef FEAT_TERMINAL
+ if (buf->b_term != NULL)
+ return term_get_status_text(buf->b_term);
+#endif
+ if (buf->b_fname != NULL)
+ return buf->b_fname;
+#ifdef FEAT_JOB_CHANNEL
+ if (bt_prompt(buf))
+ return (char_u *)_("[Prompt]");
+#endif
+ return (char_u *)_("[Scratch]");
+ }
+
+ if (buf->b_fname == NULL)
+ return (char_u *)_("[No Name]");
+ return NULL;
+}
+
+#if defined(FEAT_JOB_CHANNEL) \
+ || defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) \
+ || defined(PROTO)
+# define SWITCH_TO_WIN
+
+/*
+ * Find a window that contains "buf" and switch to it.
+ * If there is no such window, use the current window and change "curbuf".
+ * Caller must initialize save_curbuf to NULL.
+ * restore_win_for_buf() MUST be called later!
+ */
+ void
+switch_to_win_for_buf(
+ buf_T *buf,
+ win_T **save_curwinp,
+ tabpage_T **save_curtabp,
+ bufref_T *save_curbuf)
+{
+ win_T *wp;
+ tabpage_T *tp;
+
+ if (find_win_for_buf(buf, &wp, &tp) == FAIL)
+ switch_buffer(save_curbuf, buf);
+ else if (switch_win(save_curwinp, save_curtabp, wp, tp, TRUE) == FAIL)
+ {
+ restore_win(*save_curwinp, *save_curtabp, TRUE);
+ switch_buffer(save_curbuf, buf);
+ }
+}
+
+ void
+restore_win_for_buf(
+ win_T *save_curwin,
+ tabpage_T *save_curtab,
+ bufref_T *save_curbuf)
+{
+ if (save_curbuf->br_buf == NULL)
+ restore_win(save_curwin, save_curtab, TRUE);
+ else
+ restore_buffer(save_curbuf);
+}
+#endif
+
+#if defined(FEAT_QUICKFIX) || defined(SWITCH_TO_WIN) || defined(PROTO)
+/*
+ * Find a window for buffer "buf".
+ * If found OK is returned and "wp" and "tp" are set to the window and tabpage.
+ * If not found FAIL is returned.
+ */
+ int
+find_win_for_buf(
+ buf_T *buf,
+ win_T **wp,
+ tabpage_T **tp)
+{
+ FOR_ALL_TAB_WINDOWS(*tp, *wp)
+ if ((*wp)->w_buffer == buf)
+ goto win_found;
+ return FAIL;
+win_found:
+ return OK;
+}
+#endif
+
+/*
+ * Set 'buflisted' for curbuf to "on" and trigger autocommands if it changed.
+ */
+ void
+set_buflisted(int on)
+{
+ if (on != curbuf->b_p_bl)
+ {
+ curbuf->b_p_bl = on;
+ if (on)
+ apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, curbuf);
+ else
+ apply_autocmds(EVENT_BUFDELETE, NULL, NULL, FALSE, curbuf);
+ }
+}
+
+/*
+ * Read the file for "buf" again and check if the contents changed.
+ * Return TRUE if it changed or this could not be checked.
+ */
+ int
+buf_contents_changed(buf_T *buf)
+{
+ buf_T *newbuf;
+ int differ = TRUE;
+ linenr_T lnum;
+ aco_save_T aco;
+ exarg_T ea;
+
+ /* Allocate a buffer without putting it in the buffer list. */
+ newbuf = buflist_new(NULL, NULL, (linenr_T)1, BLN_DUMMY);
+ if (newbuf == NULL)
+ return TRUE;
+
+ /* Force the 'fileencoding' and 'fileformat' to be equal. */
+ if (prep_exarg(&ea, buf) == FAIL)
+ {
+ wipe_buffer(newbuf, FALSE);
+ return TRUE;
+ }
+
+ /* set curwin/curbuf to buf and save a few things */
+ aucmd_prepbuf(&aco, newbuf);
+
+ if (ml_open(curbuf) == OK
+ && readfile(buf->b_ffname, buf->b_fname,
+ (linenr_T)0, (linenr_T)0, (linenr_T)MAXLNUM,
+ &ea, READ_NEW | READ_DUMMY) == OK)
+ {
+ /* compare the two files line by line */
+ if (buf->b_ml.ml_line_count == curbuf->b_ml.ml_line_count)
+ {
+ differ = FALSE;
+ for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count; ++lnum)
+ if (STRCMP(ml_get_buf(buf, lnum, FALSE), ml_get(lnum)) != 0)
+ {
+ differ = TRUE;
+ break;
+ }
+ }
+ }
+ vim_free(ea.cmd);
+
+ /* restore curwin/curbuf and a few other things */
+ aucmd_restbuf(&aco);
+
+ if (curbuf != newbuf) /* safety check */
+ wipe_buffer(newbuf, FALSE);
+
+ return differ;
+}
+
+/*
+ * Wipe out a buffer and decrement the last buffer number if it was used for
+ * this buffer. Call this to wipe out a temp buffer that does not contain any
+ * marks.
+ */
+ void
+wipe_buffer(
+ buf_T *buf,
+ int aucmd UNUSED) /* When TRUE trigger autocommands. */
+{
+ if (buf->b_fnum == top_file_num - 1)
+ --top_file_num;
+
+ if (!aucmd) /* Don't trigger BufDelete autocommands here. */
+ block_autocmds();
+
+ close_buffer(NULL, buf, DOBUF_WIPE, FALSE);
+
+ if (!aucmd)
+ unblock_autocmds();
+}
diff --git a/src/channel.c b/src/channel.c
new file mode 100644
index 0000000..484d013
--- /dev/null
+++ b/src/channel.c
@@ -0,0 +1,6100 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * Do ":help uganda" in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ */
+
+/*
+ * Implements communication through a socket or any file handle.
+ */
+
+#include "vim.h"
+
+#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
+
+/* TRUE when netbeans is running with a GUI. */
+#ifdef FEAT_GUI
+# define CH_HAS_GUI (gui.in_use || gui.starting)
+#endif
+
+/* Note: when making changes here also adjust configure.ac. */
+#ifdef WIN32
+/* WinSock API is separated from C API, thus we can't use read(), write(),
+ * errno... */
+# define SOCK_ERRNO errno = WSAGetLastError()
+# undef ECONNREFUSED
+# define ECONNREFUSED WSAECONNREFUSED
+# undef EWOULDBLOCK
+# define EWOULDBLOCK WSAEWOULDBLOCK
+# undef EINPROGRESS
+# define EINPROGRESS WSAEINPROGRESS
+# ifdef EINTR
+# undef EINTR
+# endif
+# define EINTR WSAEINTR
+# define sock_write(sd, buf, len) send((SOCKET)sd, buf, len, 0)
+# define sock_read(sd, buf, len) recv((SOCKET)sd, buf, len, 0)
+# define sock_close(sd) closesocket((SOCKET)sd)
+#else
+# include <netdb.h>
+# include <netinet/in.h>
+
+# include <sys/socket.h>
+# ifdef HAVE_LIBGEN_H
+# include <libgen.h>
+# endif
+# define SOCK_ERRNO
+# define sock_write(sd, buf, len) write(sd, buf, len)
+# define sock_read(sd, buf, len) read(sd, buf, len)
+# define sock_close(sd) close(sd)
+# define fd_read(fd, buf, len) read(fd, buf, len)
+# define fd_write(sd, buf, len) write(sd, buf, len)
+# define fd_close(sd) close(sd)
+#endif
+
+static void channel_read(channel_T *channel, ch_part_T part, char *func);
+
+/* Whether a redraw is needed for appending a line to a buffer. */
+static int channel_need_redraw = FALSE;
+
+/* Whether we are inside channel_parse_messages() or another situation where it
+ * is safe to invoke callbacks. */
+static int safe_to_invoke_callback = 0;
+
+static char *part_names[] = {"sock", "out", "err", "in"};
+
+#ifdef WIN32
+ static int
+fd_read(sock_T fd, char *buf, size_t len)
+{
+ HANDLE h = (HANDLE)fd;
+ DWORD nread;
+
+ if (!ReadFile(h, buf, (DWORD)len, &nread, NULL))
+ return -1;
+ return (int)nread;
+}
+
+ static int
+fd_write(sock_T fd, char *buf, size_t len)
+{
+ size_t todo = len;
+ HANDLE h = (HANDLE)fd;
+ DWORD nwrite, size, done = 0;
+ OVERLAPPED ov;
+
+ while (todo > 0)
+ {
+ if (todo > MAX_NAMED_PIPE_SIZE)
+ size = MAX_NAMED_PIPE_SIZE;
+ else
+ size = (DWORD)todo;
+ // If the pipe overflows while the job does not read the data, WriteFile
+ // will block forever. This abandons the write.
+ memset(&ov, 0, sizeof(ov));
+ if (!WriteFile(h, buf + done, size, &nwrite, &ov))
+ {
+ DWORD err = GetLastError();
+
+ if (err != ERROR_IO_PENDING)
+ return -1;
+ if (!GetOverlappedResult(h, &ov, &nwrite, FALSE))
+ return -1;
+ FlushFileBuffers(h);
+ }
+ todo -= nwrite;
+ done += nwrite;
+ }
+ return (int)done;
+}
+
+ static void
+fd_close(sock_T fd)
+{
+ HANDLE h = (HANDLE)fd;
+
+ CloseHandle(h);
+}
+#endif
+
+/* Log file opened with ch_logfile(). */
+static FILE *log_fd = NULL;
+#ifdef FEAT_RELTIME
+static proftime_T log_start;
+#endif
+
+ void
+ch_logfile(char_u *fname, char_u *opt)
+{
+ FILE *file = NULL;
+
+ if (log_fd != NULL)
+ fclose(log_fd);
+
+ if (*fname != NUL)
+ {
+ file = fopen((char *)fname, *opt == 'w' ? "w" : "a");
+ if (file == NULL)
+ {
+ semsg(_(e_notopen), fname);
+ return;
+ }
+ }
+ log_fd = file;
+
+ if (log_fd != NULL)
+ {
+ fprintf(log_fd, "==== start log session ====\n");
+#ifdef FEAT_RELTIME
+ profile_start(&log_start);
+#endif
+ }
+}
+
+ int
+ch_log_active(void)
+{
+ return log_fd != NULL;
+}
+
+ static void
+ch_log_lead(const char *what, channel_T *ch, ch_part_T part)
+{
+ if (log_fd != NULL)
+ {
+#ifdef FEAT_RELTIME
+ proftime_T log_now;
+
+ profile_start(&log_now);
+ profile_sub(&log_now, &log_start);
+ fprintf(log_fd, "%s ", profile_msg(&log_now));
+#endif
+ if (ch != NULL)
+ {
+ if (part < PART_COUNT)
+ fprintf(log_fd, "%son %d(%s): ",
+ what, ch->ch_id, part_names[part]);
+ else
+ fprintf(log_fd, "%son %d: ", what, ch->ch_id);
+ }
+ else
+ fprintf(log_fd, "%s: ", what);
+ }
+}
+
+static int did_log_msg = TRUE;
+
+#ifndef PROTO /* prototype is in vim.h */
+ void
+ch_log(channel_T *ch, const char *fmt, ...)
+{
+ if (log_fd != NULL)
+ {
+ va_list ap;
+
+ ch_log_lead("", ch, PART_COUNT);
+ va_start(ap, fmt);
+ vfprintf(log_fd, fmt, ap);
+ va_end(ap);
+ fputc('\n', log_fd);
+ fflush(log_fd);
+ did_log_msg = TRUE;
+ }
+}
+#endif
+
+ static void
+ch_error(channel_T *ch, const char *fmt, ...)
+#ifdef USE_PRINTF_FORMAT_ATTRIBUTE
+ __attribute__((format(printf, 2, 3)))
+#endif
+ ;
+
+ static void
+ch_error(channel_T *ch, const char *fmt, ...)
+{
+ if (log_fd != NULL)
+ {
+ va_list ap;
+
+ ch_log_lead("ERR ", ch, PART_COUNT);
+ va_start(ap, fmt);
+ vfprintf(log_fd, fmt, ap);
+ va_end(ap);
+ fputc('\n', log_fd);
+ fflush(log_fd);
+ did_log_msg = TRUE;
+ }
+}
+
+#ifdef _WIN32
+# undef PERROR
+# define PERROR(msg) (void)semsg("%s: %s", msg, strerror_win32(errno))
+
+ static char *
+strerror_win32(int eno)
+{
+ static LPVOID msgbuf = NULL;
+ char_u *ptr;
+
+ if (msgbuf)
+ {
+ LocalFree(msgbuf);
+ msgbuf = NULL;
+ }
+ FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ eno,
+ MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
+ (LPTSTR) &msgbuf,
+ 0,
+ NULL);
+ if (msgbuf != NULL)
+ /* chomp \r or \n */
+ for (ptr = (char_u *)msgbuf; *ptr; ptr++)
+ switch (*ptr)
+ {
+ case '\r':
+ STRMOVE(ptr, ptr + 1);
+ ptr--;
+ break;
+ case '\n':
+ if (*(ptr + 1) == '\0')
+ *ptr = '\0';
+ else
+ *ptr = ' ';
+ break;
+ }
+ return msgbuf;
+}
+#endif
+
+/*
+ * The list of all allocated channels.
+ */
+static channel_T *first_channel = NULL;
+static int next_ch_id = 0;
+
+/*
+ * Allocate a new channel. The refcount is set to 1.
+ * The channel isn't actually used until it is opened.
+ * Returns NULL if out of memory.
+ */
+ channel_T *
+add_channel(void)
+{
+ ch_part_T part;
+ channel_T *channel = (channel_T *)alloc_clear((int)sizeof(channel_T));
+
+ if (channel == NULL)
+ return NULL;
+
+ channel->ch_id = next_ch_id++;
+ ch_log(channel, "Created channel");
+
+ for (part = PART_SOCK; part < PART_COUNT; ++part)
+ {
+ channel->ch_part[part].ch_fd = INVALID_FD;
+#ifdef FEAT_GUI_X11
+ channel->ch_part[part].ch_inputHandler = (XtInputId)NULL;
+#endif
+#ifdef FEAT_GUI_GTK
+ channel->ch_part[part].ch_inputHandler = 0;
+#endif
+ channel->ch_part[part].ch_timeout = 2000;
+ }
+
+ if (first_channel != NULL)
+ {
+ first_channel->ch_prev = channel;
+ channel->ch_next = first_channel;
+ }
+ first_channel = channel;
+
+ channel->ch_refcount = 1;
+ return channel;
+}
+
+ int
+has_any_channel(void)
+{
+ return first_channel != NULL;
+}
+
+/*
+ * Called when the refcount of a channel is zero.
+ * Return TRUE if "channel" has a callback and the associated job wasn't
+ * killed.
+ */
+ static int
+channel_still_useful(channel_T *channel)
+{
+ int has_sock_msg;
+ int has_out_msg;
+ int has_err_msg;
+
+ /* If the job was killed the channel is not expected to work anymore. */
+ if (channel->ch_job_killed && channel->ch_job == NULL)
+ return FALSE;
+
+ /* If there is a close callback it may still need to be invoked. */
+ if (channel->ch_close_cb != NULL)
+ return TRUE;
+
+ /* If reading from or a buffer it's still useful. */
+ if (channel->ch_part[PART_IN].ch_bufref.br_buf != NULL)
+ return TRUE;
+
+ /* If there is no callback then nobody can get readahead. If the fd is
+ * closed and there is no readahead then the callback won't be called. */
+ has_sock_msg = channel->ch_part[PART_SOCK].ch_fd != INVALID_FD
+ || channel->ch_part[PART_SOCK].ch_head.rq_next != NULL
+ || channel->ch_part[PART_SOCK].ch_json_head.jq_next != NULL;
+ has_out_msg = channel->ch_part[PART_OUT].ch_fd != INVALID_FD
+ || channel->ch_part[PART_OUT].ch_head.rq_next != NULL
+ || channel->ch_part[PART_OUT].ch_json_head.jq_next != NULL;
+ has_err_msg = channel->ch_part[PART_ERR].ch_fd != INVALID_FD
+ || channel->ch_part[PART_ERR].ch_head.rq_next != NULL
+ || channel->ch_part[PART_ERR].ch_json_head.jq_next != NULL;
+ return (channel->ch_callback != NULL && (has_sock_msg
+ || has_out_msg || has_err_msg))
+ || ((channel->ch_part[PART_OUT].ch_callback != NULL
+ || channel->ch_part[PART_OUT].ch_bufref.br_buf != NULL)
+ && has_out_msg)
+ || ((channel->ch_part[PART_ERR].ch_callback != NULL
+ || channel->ch_part[PART_ERR].ch_bufref.br_buf != NULL)
+ && has_err_msg);
+}
+
+/*
+ * Return TRUE if "channel" is closeable (i.e. all readable fds are closed).
+ */
+ static int
+channel_can_close(channel_T *channel)
+{
+ return channel->ch_to_be_closed == 0;
+}
+
+/*
+ * Close a channel and free all its resources.
+ */
+ static void
+channel_free_contents(channel_T *channel)
+{
+ channel_close(channel, TRUE);
+ channel_clear(channel);
+ ch_log(channel, "Freeing channel");
+}
+
+ static void
+channel_free_channel(channel_T *channel)
+{
+ if (channel->ch_next != NULL)
+ channel->ch_next->ch_prev = channel->ch_prev;
+ if (channel->ch_prev == NULL)
+ first_channel = channel->ch_next;
+ else
+ channel->ch_prev->ch_next = channel->ch_next;
+ vim_free(channel);
+}
+
+ static void
+channel_free(channel_T *channel)
+{
+ if (!in_free_unref_items)
+ {
+ if (safe_to_invoke_callback == 0)
+ channel->ch_to_be_freed = TRUE;
+ else
+ {
+ channel_free_contents(channel);
+ channel_free_channel(channel);
+ }
+ }
+}
+
+/*
+ * Close a channel and free all its resources if there is no further action
+ * possible, there is no callback to be invoked or the associated job was
+ * killed.
+ * Return TRUE if the channel was freed.
+ */
+ static int
+channel_may_free(channel_T *channel)
+{
+ if (!channel_still_useful(channel))
+ {
+ channel_free(channel);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * Decrement the reference count on "channel" and maybe free it when it goes
+ * down to zero. Don't free it if there is a pending action.
+ * Returns TRUE when the channel is no longer referenced.
+ */
+ int
+channel_unref(channel_T *channel)
+{
+ if (channel != NULL && --channel->ch_refcount <= 0)
+ return channel_may_free(channel);
+ return FALSE;
+}
+
+ int
+free_unused_channels_contents(int copyID, int mask)
+{
+ int did_free = FALSE;
+ channel_T *ch;
+
+ /* This is invoked from the garbage collector, which only runs at a safe
+ * point. */
+ ++safe_to_invoke_callback;
+
+ for (ch = first_channel; ch != NULL; ch = ch->ch_next)
+ if (!channel_still_useful(ch)
+ && (ch->ch_copyID & mask) != (copyID & mask))
+ {
+ /* Free the channel and ordinary items it contains, but don't
+ * recurse into Lists, Dictionaries etc. */
+ channel_free_contents(ch);
+ did_free = TRUE;
+ }
+
+ --safe_to_invoke_callback;
+ return did_free;
+}
+
+ void
+free_unused_channels(int copyID, int mask)
+{
+ channel_T *ch;
+ channel_T *ch_next;
+
+ for (ch = first_channel; ch != NULL; ch = ch_next)
+ {
+ ch_next = ch->ch_next;
+ if (!channel_still_useful(ch)
+ && (ch->ch_copyID & mask) != (copyID & mask))
+ {
+ /* Free the channel struct itself. */
+ channel_free_channel(ch);
+ }
+ }
+}
+
+#if defined(FEAT_GUI) || defined(PROTO)
+
+#if defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK)
+ static void
+channel_read_fd(int fd)
+{
+ channel_T *channel;
+ ch_part_T part;
+
+ channel = channel_fd2channel(fd, &part);
+ if (channel == NULL)
+ ch_error(NULL, "Channel for fd %d not found", fd);
+ else
+ channel_read(channel, part, "channel_read_fd");
+}
+#endif
+
+/*
+ * Read a command from netbeans.
+ */
+#ifdef FEAT_GUI_X11
+ static void
+messageFromServerX11(XtPointer clientData,
+ int *unused1 UNUSED,
+ XtInputId *unused2 UNUSED)
+{
+ channel_read_fd((int)(long)clientData);
+}
+#endif
+
+#ifdef FEAT_GUI_GTK
+# if GTK_CHECK_VERSION(3,0,0)
+ static gboolean
+messageFromServerGtk3(GIOChannel *unused1 UNUSED,
+ GIOCondition unused2 UNUSED,
+ gpointer clientData)
+{
+ channel_read_fd(GPOINTER_TO_INT(clientData));
+ return TRUE; /* Return FALSE instead in case the event source is to
+ * be removed after this function returns. */
+}
+# else
+ static void
+messageFromServerGtk2(gpointer clientData,
+ gint unused1 UNUSED,
+ GdkInputCondition unused2 UNUSED)
+{
+ channel_read_fd((int)(long)clientData);
+}
+# endif
+#endif
+
+ static void
+channel_gui_register_one(channel_T *channel, ch_part_T part)
+{
+ if (!CH_HAS_GUI)
+ return;
+
+ /* gets stuck in handling events for a not connected channel */
+ if (channel->ch_keep_open)
+ return;
+
+# ifdef FEAT_GUI_X11
+ /* Tell notifier we are interested in being called when there is input on
+ * the editor connection socket. */
+ if (channel->ch_part[part].ch_inputHandler == (XtInputId)NULL)
+ {
+ ch_log(channel, "Registering part %s with fd %d",
+ part_names[part], channel->ch_part[part].ch_fd);
+
+ channel->ch_part[part].ch_inputHandler = XtAppAddInput(
+ (XtAppContext)app_context,
+ channel->ch_part[part].ch_fd,
+ (XtPointer)(XtInputReadMask + XtInputExceptMask),
+ messageFromServerX11,
+ (XtPointer)(long)channel->ch_part[part].ch_fd);
+ }
+# else
+# ifdef FEAT_GUI_GTK
+ /* Tell gdk we are interested in being called when there is input on the
+ * editor connection socket. */
+ if (channel->ch_part[part].ch_inputHandler == 0)
+ {
+ ch_log(channel, "Registering part %s with fd %d",
+ part_names[part], channel->ch_part[part].ch_fd);
+# if GTK_CHECK_VERSION(3,0,0)
+ GIOChannel *chnnl = g_io_channel_unix_new(
+ (gint)channel->ch_part[part].ch_fd);
+
+ channel->ch_part[part].ch_inputHandler = g_io_add_watch(
+ chnnl,
+ G_IO_IN|G_IO_HUP|G_IO_ERR|G_IO_PRI,
+ messageFromServerGtk3,
+ GINT_TO_POINTER(channel->ch_part[part].ch_fd));
+
+ g_io_channel_unref(chnnl);
+# else
+ channel->ch_part[part].ch_inputHandler = gdk_input_add(
+ (gint)channel->ch_part[part].ch_fd,
+ (GdkInputCondition)
+ ((int)GDK_INPUT_READ + (int)GDK_INPUT_EXCEPTION),
+ messageFromServerGtk2,
+ (gpointer)(long)channel->ch_part[part].ch_fd);
+# endif
+ }
+# endif
+# endif
+}
+
+ static void
+channel_gui_register(channel_T *channel)
+{
+ if (channel->CH_SOCK_FD != INVALID_FD)
+ channel_gui_register_one(channel, PART_SOCK);
+ if (channel->CH_OUT_FD != INVALID_FD
+ && channel->CH_OUT_FD != channel->CH_SOCK_FD)
+ channel_gui_register_one(channel, PART_OUT);
+ if (channel->CH_ERR_FD != INVALID_FD
+ && channel->CH_ERR_FD != channel->CH_SOCK_FD
+ && channel->CH_ERR_FD != channel->CH_OUT_FD)
+ channel_gui_register_one(channel, PART_ERR);
+}
+
+/*
+ * Register any of our file descriptors with the GUI event handling system.
+ * Called when the GUI has started.
+ */
+ void
+channel_gui_register_all(void)
+{
+ channel_T *channel;
+
+ for (channel = first_channel; channel != NULL; channel = channel->ch_next)
+ channel_gui_register(channel);
+}
+
+ static void
+channel_gui_unregister_one(channel_T *channel, ch_part_T part)
+{
+# ifdef FEAT_GUI_X11
+ if (channel->ch_part[part].ch_inputHandler != (XtInputId)NULL)
+ {
+ ch_log(channel, "Unregistering part %s", part_names[part]);
+ XtRemoveInput(channel->ch_part[part].ch_inputHandler);
+ channel->ch_part[part].ch_inputHandler = (XtInputId)NULL;
+ }
+# else
+# ifdef FEAT_GUI_GTK
+ if (channel->ch_part[part].ch_inputHandler != 0)
+ {
+ ch_log(channel, "Unregistering part %s", part_names[part]);
+# if GTK_CHECK_VERSION(3,0,0)
+ g_source_remove(channel->ch_part[part].ch_inputHandler);
+# else
+ gdk_input_remove(channel->ch_part[part].ch_inputHandler);
+# endif
+ channel->ch_part[part].ch_inputHandler = 0;
+ }
+# endif
+# endif
+}
+
+ static void
+channel_gui_unregister(channel_T *channel)
+{
+ ch_part_T part;
+
+ for (part = PART_SOCK; part < PART_IN; ++part)
+ channel_gui_unregister_one(channel, part);
+}
+
+#endif
+
+static char *e_cannot_connect = N_("E902: Cannot connect to port");
+
+/*
+ * Open a socket channel to "hostname":"port".
+ * "waittime" is the time in msec to wait for the connection.
+ * When negative wait forever.
+ * Returns the channel for success.
+ * Returns NULL for failure.
+ */
+ channel_T *
+channel_open(
+ char *hostname,
+ int port_in,
+ int waittime,
+ void (*nb_close_cb)(void))
+{
+ int sd = -1;
+ struct sockaddr_in server;
+ struct hostent *host;
+#ifdef WIN32
+ u_short port = port_in;
+ u_long val = 1;
+#else
+ int port = port_in;
+#endif
+ channel_T *channel;
+ int ret;
+
+#ifdef WIN32
+ channel_init_winsock();
+#endif
+
+ channel = add_channel();
+ if (channel == NULL)
+ {
+ ch_error(NULL, "Cannot allocate channel.");
+ return NULL;
+ }
+
+ /* Get the server internet address and put into addr structure */
+ /* fill in the socket address structure and connect to server */
+ vim_memset((char *)&server, 0, sizeof(server));
+ server.sin_family = AF_INET;
+ server.sin_port = htons(port);
+ if ((host = gethostbyname(hostname)) == NULL)
+ {
+ ch_error(channel, "in gethostbyname() in channel_open()");
+ PERROR(_("E901: gethostbyname() in channel_open()"));
+ channel_free(channel);
+ return NULL;
+ }
+ {
+ char *p;
+
+ /* When using host->h_addr_list[0] directly ubsan warns for it to not
+ * be aligned. First copy the pointer to avoid that. */
+ memcpy(&p, &host->h_addr_list[0], sizeof(p));
+ memcpy((char *)&server.sin_addr, p, host->h_length);
+ }
+
+ /* On Mac and Solaris a zero timeout almost never works. At least wait
+ * one millisecond. Let's do it for all systems, because we don't know why
+ * this is needed. */
+ if (waittime == 0)
+ waittime = 1;
+
+ /*
+ * For Unix we need to call connect() again after connect() failed.
+ * On Win32 one time is sufficient.
+ */
+ while (TRUE)
+ {
+ long elapsed_msec = 0;
+ int waitnow;
+
+ if (sd >= 0)
+ sock_close(sd);
+ sd = socket(AF_INET, SOCK_STREAM, 0);
+ if (sd == -1)
+ {
+ ch_error(channel, "in socket() in channel_open().");
+ PERROR(_("E898: socket() in channel_open()"));
+ channel_free(channel);
+ return NULL;
+ }
+
+ if (waittime >= 0)
+ {
+ /* Make connect() non-blocking. */
+ if (
+#ifdef _WIN32
+ ioctlsocket(sd, FIONBIO, &val) < 0
+#else
+ fcntl(sd, F_SETFL, O_NONBLOCK) < 0
+#endif
+ )
+ {
+ SOCK_ERRNO;
+ ch_error(channel,
+ "channel_open: Connect failed with errno %d", errno);
+ sock_close(sd);
+ channel_free(channel);
+ return NULL;
+ }
+ }
+
+ /* Try connecting to the server. */
+ ch_log(channel, "Connecting to %s port %d", hostname, port);
+ ret = connect(sd, (struct sockaddr *)&server, sizeof(server));
+
+ if (ret == 0)
+ /* The connection could be established. */
+ break;
+
+ SOCK_ERRNO;
+ if (waittime < 0 || (errno != EWOULDBLOCK
+ && errno != ECONNREFUSED
+#ifdef EINPROGRESS
+ && errno != EINPROGRESS
+#endif
+ ))
+ {
+ ch_error(channel,
+ "channel_open: Connect failed with errno %d", errno);
+ PERROR(_(e_cannot_connect));
+ sock_close(sd);
+ channel_free(channel);
+ return NULL;
+ }
+
+ /* Limit the waittime to 50 msec. If it doesn't work within this
+ * time we close the socket and try creating it again. */
+ waitnow = waittime > 50 ? 50 : waittime;
+
+ /* If connect() didn't finish then try using select() to wait for the
+ * connection to be made. For Win32 always use select() to wait. */
+#ifndef WIN32
+ if (errno != ECONNREFUSED)
+#endif
+ {
+ struct timeval tv;
+ fd_set rfds;
+ fd_set wfds;
+#ifndef WIN32
+ int so_error = 0;
+ socklen_t so_error_len = sizeof(so_error);
+ struct timeval start_tv;
+ struct timeval end_tv;
+#endif
+ FD_ZERO(&rfds);
+ FD_SET(sd, &rfds);
+ FD_ZERO(&wfds);
+ FD_SET(sd, &wfds);
+
+ tv.tv_sec = waitnow / 1000;
+ tv.tv_usec = (waitnow % 1000) * 1000;
+#ifndef WIN32
+ gettimeofday(&start_tv, NULL);
+#endif
+ ch_log(channel,
+ "Waiting for connection (waiting %d msec)...", waitnow);
+ ret = select((int)sd + 1, &rfds, &wfds, NULL, &tv);
+
+ if (ret < 0)
+ {
+ SOCK_ERRNO;
+ ch_error(channel,
+ "channel_open: Connect failed with errno %d", errno);
+ PERROR(_(e_cannot_connect));
+ sock_close(sd);
+ channel_free(channel);
+ return NULL;
+ }
+
+#ifdef WIN32
+ /* On Win32: select() is expected to work and wait for up to
+ * "waitnow" msec for the socket to be open. */
+ if (FD_ISSET(sd, &wfds))
+ break;
+ elapsed_msec = waitnow;
+ if (waittime > 1 && elapsed_msec < waittime)
+ {
+ waittime -= elapsed_msec;
+ continue;
+ }
+#else
+ /* On Linux-like systems: See socket(7) for the behavior
+ * After putting the socket in non-blocking mode, connect() will
+ * return EINPROGRESS, select() will not wait (as if writing is
+ * possible), need to use getsockopt() to check if the socket is
+ * actually able to connect.
+ * We detect a failure to connect when either read and write fds
+ * are set. Use getsockopt() to find out what kind of failure. */
+ if (FD_ISSET(sd, &rfds) || FD_ISSET(sd, &wfds))
+ {
+ ret = getsockopt(sd,
+ SOL_SOCKET, SO_ERROR, &so_error, &so_error_len);
+ if (ret < 0 || (so_error != 0
+ && so_error != EWOULDBLOCK
+ && so_error != ECONNREFUSED
+# ifdef EINPROGRESS
+ && so_error != EINPROGRESS
+# endif
+ ))
+ {
+ ch_error(channel,
+ "channel_open: Connect failed with errno %d",
+ so_error);
+ PERROR(_(e_cannot_connect));
+ sock_close(sd);
+ channel_free(channel);
+ return NULL;
+ }
+ }
+
+ if (FD_ISSET(sd, &wfds) && so_error == 0)
+ /* Did not detect an error, connection is established. */
+ break;
+
+ gettimeofday(&end_tv, NULL);
+ elapsed_msec = (end_tv.tv_sec - start_tv.tv_sec) * 1000
+ + (end_tv.tv_usec - start_tv.tv_usec) / 1000;
+#endif
+ }
+
+#ifndef WIN32
+ if (waittime > 1 && elapsed_msec < waittime)
+ {
+ /* The port isn't ready but we also didn't get an error.
+ * This happens when the server didn't open the socket
+ * yet. Select() may return early, wait until the remaining
+ * "waitnow" and try again. */
+ waitnow -= elapsed_msec;
+ waittime -= elapsed_msec;
+ if (waitnow > 0)
+ {
+ mch_delay((long)waitnow, TRUE);
+ ui_breakcheck();
+ waittime -= waitnow;
+ }
+ if (!got_int)
+ {
+ if (waittime <= 0)
+ /* give it one more try */
+ waittime = 1;
+ continue;
+ }
+ /* we were interrupted, behave as if timed out */
+ }
+#endif
+
+ /* We timed out. */
+ ch_error(channel, "Connection timed out");
+ sock_close(sd);
+ channel_free(channel);
+ return NULL;
+ }
+
+ ch_log(channel, "Connection made");
+
+ if (waittime >= 0)
+ {
+#ifdef _WIN32
+ val = 0;
+ ioctlsocket(sd, FIONBIO, &val);
+#else
+ (void)fcntl(sd, F_SETFL, 0);
+#endif
+ }
+
+ channel->CH_SOCK_FD = (sock_T)sd;
+ channel->ch_nb_close_cb = nb_close_cb;
+ channel->ch_hostname = (char *)vim_strsave((char_u *)hostname);
+ channel->ch_port = port_in;
+ channel->ch_to_be_closed |= (1U << PART_SOCK);
+
+#ifdef FEAT_GUI
+ channel_gui_register_one(channel, PART_SOCK);
+#endif
+
+ return channel;
+}
+
+/*
+ * Implements ch_open().
+ */
+ channel_T *
+channel_open_func(typval_T *argvars)
+{
+ char_u *address;
+ char_u *p;
+ char *rest;
+ int port;
+ jobopt_T opt;
+ channel_T *channel = NULL;
+
+ address = tv_get_string(&argvars[0]);
+ if (argvars[1].v_type != VAR_UNKNOWN
+ && (argvars[1].v_type != VAR_DICT || argvars[1].vval.v_dict == NULL))
+ {
+ emsg(_(e_invarg));
+ return NULL;
+ }
+
+ /* parse address */
+ p = vim_strchr(address, ':');
+ if (p == NULL)
+ {
+ semsg(_(e_invarg2), address);
+ return NULL;
+ }
+ *p++ = NUL;
+ port = strtol((char *)p, &rest, 10);
+ if (*address == NUL || port <= 0 || *rest != NUL)
+ {
+ p[-1] = ':';
+ semsg(_(e_invarg2), address);
+ return NULL;
+ }
+
+ /* parse options */
+ clear_job_options(&opt);
+ opt.jo_mode = MODE_JSON;
+ opt.jo_timeout = 2000;
+ if (get_job_options(&argvars[1], &opt,
+ JO_MODE_ALL + JO_CB_ALL + JO_WAITTIME + JO_TIMEOUT_ALL, 0) == FAIL)
+ goto theend;
+ if (opt.jo_timeout < 0)
+ {
+ emsg(_(e_invarg));
+ goto theend;
+ }
+
+ channel = channel_open((char *)address, port, opt.jo_waittime, NULL);
+ if (channel != NULL)
+ {
+ opt.jo_set = JO_ALL;
+ channel_set_options(channel, &opt);
+ }
+theend:
+ free_job_options(&opt);
+ return channel;
+}
+
+ static void
+ch_close_part(channel_T *channel, ch_part_T part)
+{
+ sock_T *fd = &channel->ch_part[part].ch_fd;
+
+ if (*fd != INVALID_FD)
+ {
+ if (part == PART_SOCK)
+ sock_close(*fd);
+ else
+ {
+ /* When using a pty the same FD is set on multiple parts, only
+ * close it when the last reference is closed. */
+ if ((part == PART_IN || channel->CH_IN_FD != *fd)
+ && (part == PART_OUT || channel->CH_OUT_FD != *fd)
+ && (part == PART_ERR || channel->CH_ERR_FD != *fd))
+ {
+#ifdef WIN32
+ if (channel->ch_named_pipe)
+ DisconnectNamedPipe((HANDLE)fd);
+#endif
+ fd_close(*fd);
+ }
+ }
+ *fd = INVALID_FD;
+
+ /* channel is closed, may want to end the job if it was the last */
+ channel->ch_to_be_closed &= ~(1U << part);
+ }
+}
+
+ void
+channel_set_pipes(channel_T *channel, sock_T in, sock_T out, sock_T err)
+{
+ if (in != INVALID_FD)
+ {
+ ch_close_part(channel, PART_IN);
+ channel->CH_IN_FD = in;
+# if defined(UNIX)
+ /* Do not end the job when all output channels are closed, wait until
+ * the job ended. */
+ if (mch_isatty(in))
+ channel->ch_to_be_closed |= (1U << PART_IN);
+# endif
+ }
+ if (out != INVALID_FD)
+ {
+# if defined(FEAT_GUI)
+ channel_gui_unregister_one(channel, PART_OUT);
+# endif
+ ch_close_part(channel, PART_OUT);
+ channel->CH_OUT_FD = out;
+ channel->ch_to_be_closed |= (1U << PART_OUT);
+# if defined(FEAT_GUI)
+ channel_gui_register_one(channel, PART_OUT);
+# endif
+ }
+ if (err != INVALID_FD)
+ {
+# if defined(FEAT_GUI)
+ channel_gui_unregister_one(channel, PART_ERR);
+# endif
+ ch_close_part(channel, PART_ERR);
+ channel->CH_ERR_FD = err;
+ channel->ch_to_be_closed |= (1U << PART_ERR);
+# if defined(FEAT_GUI)
+ channel_gui_register_one(channel, PART_ERR);
+# endif
+ }
+}
+
+/*
+ * Sets the job the channel is associated with and associated options.
+ * This does not keep a refcount, when the job is freed ch_job is cleared.
+ */
+ void
+channel_set_job(channel_T *channel, job_T *job, jobopt_T *options)
+{
+ channel->ch_job = job;
+
+ channel_set_options(channel, options);
+
+ if (job->jv_in_buf != NULL)
+ {
+ chanpart_T *in_part = &channel->ch_part[PART_IN];
+
+ set_bufref(&in_part->ch_bufref, job->jv_in_buf);
+ ch_log(channel, "reading from buffer '%s'",
+ (char *)in_part->ch_bufref.br_buf->b_ffname);
+ if (options->jo_set & JO_IN_TOP)
+ {
+ if (options->jo_in_top == 0 && !(options->jo_set & JO_IN_BOT))
+ {
+ /* Special mode: send last-but-one line when appending a line
+ * to the buffer. */
+ in_part->ch_bufref.br_buf->b_write_to_channel = TRUE;
+ in_part->ch_buf_append = TRUE;
+ in_part->ch_buf_top =
+ in_part->ch_bufref.br_buf->b_ml.ml_line_count + 1;
+ }
+ else
+ in_part->ch_buf_top = options->jo_in_top;
+ }
+ else
+ in_part->ch_buf_top = 1;
+ if (options->jo_set & JO_IN_BOT)
+ in_part->ch_buf_bot = options->jo_in_bot;
+ else
+ in_part->ch_buf_bot = in_part->ch_bufref.br_buf->b_ml.ml_line_count;
+ }
+}
+
+/*
+ * Prepare buffer "buf" for writing channel output to.
+ */
+ static void
+prepare_buffer(buf_T *buf)
+{
+ buf_T *save_curbuf = curbuf;
+
+ buf_copy_options(buf, BCO_ENTER);
+ curbuf = buf;
+#ifdef FEAT_QUICKFIX
+ set_option_value((char_u *)"bt", 0L, (char_u *)"nofile", OPT_LOCAL);
+ set_option_value((char_u *)"bh", 0L, (char_u *)"hide", OPT_LOCAL);
+#endif
+ if (curbuf->b_ml.ml_mfp == NULL)
+ ml_open(curbuf);
+ curbuf = save_curbuf;
+}
+
+/*
+ * Find a buffer matching "name" or create a new one.
+ * Returns NULL if there is something very wrong (error already reported).
+ */
+ static buf_T *
+find_buffer(char_u *name, int err, int msg)
+{
+ buf_T *buf = NULL;
+ buf_T *save_curbuf = curbuf;
+
+ if (name != NULL && *name != NUL)
+ {
+ buf = buflist_findname(name);
+ if (buf == NULL)
+ buf = buflist_findname_exp(name);
+ }
+ if (buf == NULL)
+ {
+ buf = buflist_new(name == NULL || *name == NUL ? NULL : name,
+ NULL, (linenr_T)0, BLN_LISTED | BLN_NEW);
+ if (buf == NULL)
+ return NULL;
+ prepare_buffer(buf);
+
+ curbuf = buf;
+ if (msg)
+ ml_replace(1, (char_u *)(err ? "Reading from channel error..."
+ : "Reading from channel output..."), TRUE);
+ changed_bytes(1, 0);
+ curbuf = save_curbuf;
+ }
+
+ return buf;
+}
+
+ static void
+set_callback(
+ char_u **cbp,
+ partial_T **pp,
+ char_u *callback,
+ partial_T *partial)
+{
+ free_callback(*cbp, *pp);
+ if (callback != NULL && *callback != NUL)
+ {
+ if (partial != NULL)
+ *cbp = partial_name(partial);
+ else
+ {
+ *cbp = vim_strsave(callback);
+ func_ref(*cbp);
+ }
+ }
+ else
+ *cbp = NULL;
+ *pp = partial;
+ if (partial != NULL)
+ ++partial->pt_refcount;
+}
+
+/*
+ * Set various properties from an "opt" argument.
+ */
+ void
+channel_set_options(channel_T *channel, jobopt_T *opt)
+{
+ ch_part_T part;
+
+ if (opt->jo_set & JO_MODE)
+ for (part = PART_SOCK; part < PART_COUNT; ++part)
+ channel->ch_part[part].ch_mode = opt->jo_mode;
+ if (opt->jo_set & JO_IN_MODE)
+ channel->ch_part[PART_IN].ch_mode = opt->jo_in_mode;
+ if (opt->jo_set & JO_OUT_MODE)
+ channel->ch_part[PART_OUT].ch_mode = opt->jo_out_mode;
+ if (opt->jo_set & JO_ERR_MODE)
+ channel->ch_part[PART_ERR].ch_mode = opt->jo_err_mode;
+ channel->ch_nonblock = opt->jo_noblock;
+
+ if (opt->jo_set & JO_TIMEOUT)
+ for (part = PART_SOCK; part < PART_COUNT; ++part)
+ channel->ch_part[part].ch_timeout = opt->jo_timeout;
+ if (opt->jo_set & JO_OUT_TIMEOUT)
+ channel->ch_part[PART_OUT].ch_timeout = opt->jo_out_timeout;
+ if (opt->jo_set & JO_ERR_TIMEOUT)
+ channel->ch_part[PART_ERR].ch_timeout = opt->jo_err_timeout;
+ if (opt->jo_set & JO_BLOCK_WRITE)
+ channel->ch_part[PART_IN].ch_block_write = 1;
+
+ if (opt->jo_set & JO_CALLBACK)
+ set_callback(&channel->ch_callback, &channel->ch_partial,
+ opt->jo_callback, opt->jo_partial);
+ if (opt->jo_set & JO_OUT_CALLBACK)
+ set_callback(&channel->ch_part[PART_OUT].ch_callback,
+ &channel->ch_part[PART_OUT].ch_partial,
+ opt->jo_out_cb, opt->jo_out_partial);
+ if (opt->jo_set & JO_ERR_CALLBACK)
+ set_callback(&channel->ch_part[PART_ERR].ch_callback,
+ &channel->ch_part[PART_ERR].ch_partial,
+ opt->jo_err_cb, opt->jo_err_partial);
+ if (opt->jo_set & JO_CLOSE_CALLBACK)
+ set_callback(&channel->ch_close_cb, &channel->ch_close_partial,
+ opt->jo_close_cb, opt->jo_close_partial);
+ channel->ch_drop_never = opt->jo_drop_never;
+
+ if ((opt->jo_set & JO_OUT_IO) && opt->jo_io[PART_OUT] == JIO_BUFFER)
+ {
+ buf_T *buf;
+
+ /* writing output to a buffer. Default mode is NL. */
+ if (!(opt->jo_set & JO_OUT_MODE))
+ channel->ch_part[PART_OUT].ch_mode = MODE_NL;
+ if (opt->jo_set & JO_OUT_BUF)
+ {
+ buf = buflist_findnr(opt->jo_io_buf[PART_OUT]);
+ if (buf == NULL)
+ semsg(_(e_nobufnr), (long)opt->jo_io_buf[PART_OUT]);
+ }
+ else
+ {
+ int msg = TRUE;
+
+ if (opt->jo_set2 & JO2_OUT_MSG)
+ msg = opt->jo_message[PART_OUT];
+ buf = find_buffer(opt->jo_io_name[PART_OUT], FALSE, msg);
+ }
+ if (buf != NULL)
+ {
+ if (opt->jo_set & JO_OUT_MODIFIABLE)
+ channel->ch_part[PART_OUT].ch_nomodifiable =
+ !opt->jo_modifiable[PART_OUT];
+
+ if (!buf->b_p_ma && !channel->ch_part[PART_OUT].ch_nomodifiable)
+ {
+ emsg(_(e_modifiable));
+ }
+ else
+ {
+ ch_log(channel, "writing out to buffer '%s'",
+ (char *)buf->b_ffname);
+ set_bufref(&channel->ch_part[PART_OUT].ch_bufref, buf);
+ // if the buffer was deleted or unloaded resurrect it
+ if (buf->b_ml.ml_mfp == NULL)
+ prepare_buffer(buf);
+ }
+ }
+ }
+
+ if ((opt->jo_set & JO_ERR_IO) && (opt->jo_io[PART_ERR] == JIO_BUFFER
+ || (opt->jo_io[PART_ERR] == JIO_OUT && (opt->jo_set & JO_OUT_IO)
+ && opt->jo_io[PART_OUT] == JIO_BUFFER)))
+ {
+ buf_T *buf;
+
+ /* writing err to a buffer. Default mode is NL. */
+ if (!(opt->jo_set & JO_ERR_MODE))
+ channel->ch_part[PART_ERR].ch_mode = MODE_NL;
+ if (opt->jo_io[PART_ERR] == JIO_OUT)
+ buf = channel->ch_part[PART_OUT].ch_bufref.br_buf;
+ else if (opt->jo_set & JO_ERR_BUF)
+ {
+ buf = buflist_findnr(opt->jo_io_buf[PART_ERR]);
+ if (buf == NULL)
+ semsg(_(e_nobufnr), (long)opt->jo_io_buf[PART_ERR]);
+ }
+ else
+ {
+ int msg = TRUE;
+
+ if (opt->jo_set2 & JO2_ERR_MSG)
+ msg = opt->jo_message[PART_ERR];
+ buf = find_buffer(opt->jo_io_name[PART_ERR], TRUE, msg);
+ }
+ if (buf != NULL)
+ {
+ if (opt->jo_set & JO_ERR_MODIFIABLE)
+ channel->ch_part[PART_ERR].ch_nomodifiable =
+ !opt->jo_modifiable[PART_ERR];
+ if (!buf->b_p_ma && !channel->ch_part[PART_ERR].ch_nomodifiable)
+ {
+ emsg(_(e_modifiable));
+ }
+ else
+ {
+ ch_log(channel, "writing err to buffer '%s'",
+ (char *)buf->b_ffname);
+ set_bufref(&channel->ch_part[PART_ERR].ch_bufref, buf);
+ // if the buffer was deleted or unloaded resurrect it
+ if (buf->b_ml.ml_mfp == NULL)
+ prepare_buffer(buf);
+ }
+ }
+ }
+
+ channel->ch_part[PART_OUT].ch_io = opt->jo_io[PART_OUT];
+ channel->ch_part[PART_ERR].ch_io = opt->jo_io[PART_ERR];
+ channel->ch_part[PART_IN].ch_io = opt->jo_io[PART_IN];
+}
+
+/*
+ * Set the callback for "channel"/"part" for the response with "id".
+ */
+ void
+channel_set_req_callback(
+ channel_T *channel,
+ ch_part_T part,
+ char_u *callback,
+ partial_T *partial,
+ int id)
+{
+ cbq_T *head = &channel->ch_part[part].ch_cb_head;
+ cbq_T *item = (cbq_T *)alloc((int)sizeof(cbq_T));
+
+ if (item != NULL)
+ {
+ item->cq_partial = partial;
+ if (partial != NULL)
+ {
+ ++partial->pt_refcount;
+ item->cq_callback = callback;
+ }
+ else
+ {
+ item->cq_callback = vim_strsave(callback);
+ func_ref(item->cq_callback);
+ }
+ item->cq_seq_nr = id;
+ item->cq_prev = head->cq_prev;
+ head->cq_prev = item;
+ item->cq_next = NULL;
+ if (item->cq_prev == NULL)
+ head->cq_next = item;
+ else
+ item->cq_prev->cq_next = item;
+ }
+}
+
+ static void
+write_buf_line(buf_T *buf, linenr_T lnum, channel_T *channel)
+{
+ char_u *line = ml_get_buf(buf, lnum, FALSE);
+ int len = (int)STRLEN(line);
+ char_u *p;
+ int i;
+
+ /* Need to make a copy to be able to append a NL. */
+ if ((p = alloc(len + 2)) == NULL)
+ return;
+ memcpy((char *)p, (char *)line, len);
+
+ if (channel->ch_write_text_mode)
+ p[len] = CAR;
+ else
+ {
+ for (i = 0; i < len; ++i)
+ if (p[i] == NL)
+ p[i] = NUL;
+
+ p[len] = NL;
+ }
+ p[len + 1] = NUL;
+ channel_send(channel, PART_IN, p, len + 1, "write_buf_line");
+ vim_free(p);
+}
+
+/*
+ * Return TRUE if "channel" can be written to.
+ * Returns FALSE if the input is closed or the write would block.
+ */
+ static int
+can_write_buf_line(channel_T *channel)
+{
+ chanpart_T *in_part = &channel->ch_part[PART_IN];
+
+ if (in_part->ch_fd == INVALID_FD)
+ return FALSE; /* pipe was closed */
+
+ /* for testing: block every other attempt to write */
+ if (in_part->ch_block_write == 1)
+ in_part->ch_block_write = -1;
+ else if (in_part->ch_block_write == -1)
+ in_part->ch_block_write = 1;
+
+ /* TODO: Win32 implementation, probably using WaitForMultipleObjects() */
+#ifndef WIN32
+ {
+# if defined(HAVE_SELECT)
+ struct timeval tval;
+ fd_set wfds;
+ int ret;
+
+ FD_ZERO(&wfds);
+ FD_SET((int)in_part->ch_fd, &wfds);
+ tval.tv_sec = 0;
+ tval.tv_usec = 0;
+ for (;;)
+ {
+ ret = select((int)in_part->ch_fd + 1, NULL, &wfds, NULL, &tval);
+# ifdef EINTR
+ SOCK_ERRNO;
+ if (ret == -1 && errno == EINTR)
+ continue;
+# endif
+ if (ret <= 0 || in_part->ch_block_write == 1)
+ {
+ if (ret > 0)
+ ch_log(channel, "FAKED Input not ready for writing");
+ else
+ ch_log(channel, "Input not ready for writing");
+ return FALSE;
+ }
+ break;
+ }
+# else
+ struct pollfd fds;
+
+ fds.fd = in_part->ch_fd;
+ fds.events = POLLOUT;
+ if (poll(&fds, 1, 0) <= 0)
+ {
+ ch_log(channel, "Input not ready for writing");
+ return FALSE;
+ }
+ if (in_part->ch_block_write == 1)
+ {
+ ch_log(channel, "FAKED Input not ready for writing");
+ return FALSE;
+ }
+# endif
+ }
+#endif
+ return TRUE;
+}
+
+/*
+ * Write any buffer lines to the input channel.
+ */
+ static void
+channel_write_in(channel_T *channel)
+{
+ chanpart_T *in_part = &channel->ch_part[PART_IN];
+ linenr_T lnum;
+ buf_T *buf = in_part->ch_bufref.br_buf;
+ int written = 0;
+
+ if (buf == NULL || in_part->ch_buf_append)
+ return; /* no buffer or using appending */
+ if (!bufref_valid(&in_part->ch_bufref) || buf->b_ml.ml_mfp == NULL)
+ {
+ /* buffer was wiped out or unloaded */
+ ch_log(channel, "input buffer has been wiped out");
+ in_part->ch_bufref.br_buf = NULL;
+ return;
+ }
+
+ for (lnum = in_part->ch_buf_top; lnum <= in_part->ch_buf_bot
+ && lnum <= buf->b_ml.ml_line_count; ++lnum)
+ {
+ if (!can_write_buf_line(channel))
+ break;
+ write_buf_line(buf, lnum, channel);
+ ++written;
+ }
+
+ if (written == 1)
+ ch_log(channel, "written line %d to channel", (int)lnum - 1);
+ else if (written > 1)
+ ch_log(channel, "written %d lines to channel", written);
+
+ in_part->ch_buf_top = lnum;
+ if (lnum > buf->b_ml.ml_line_count || lnum > in_part->ch_buf_bot)
+ {
+#if defined(FEAT_TERMINAL)
+ /* Send CTRL-D or "eof_chars" to close stdin on MS-Windows. */
+ if (channel->ch_job != NULL)
+ term_send_eof(channel);
+#endif
+
+ /* Writing is done, no longer need the buffer. */
+ in_part->ch_bufref.br_buf = NULL;
+ ch_log(channel, "Finished writing all lines to channel");
+
+ /* Close the pipe/socket, so that the other side gets EOF. */
+ ch_close_part(channel, PART_IN);
+ }
+ else
+ ch_log(channel, "Still %ld more lines to write",
+ (long)(buf->b_ml.ml_line_count - lnum + 1));
+}
+
+/*
+ * Handle buffer "buf" being freed, remove it from any channels.
+ */
+ void
+channel_buffer_free(buf_T *buf)
+{
+ channel_T *channel;
+ ch_part_T part;
+
+ for (channel = first_channel; channel != NULL; channel = channel->ch_next)
+ for (part = PART_SOCK; part < PART_COUNT; ++part)
+ {
+ chanpart_T *ch_part = &channel->ch_part[part];
+
+ if (ch_part->ch_bufref.br_buf == buf)
+ {
+ ch_log(channel, "%s buffer has been wiped out",
+ part_names[part]);
+ ch_part->ch_bufref.br_buf = NULL;
+ }
+ }
+}
+
+/*
+ * Write any lines waiting to be written to "channel".
+ */
+ static void
+channel_write_input(channel_T *channel)
+{
+ chanpart_T *in_part = &channel->ch_part[PART_IN];
+
+ if (in_part->ch_writeque.wq_next != NULL)
+ channel_send(channel, PART_IN, (char_u *)"", 0, "channel_write_input");
+ else if (in_part->ch_bufref.br_buf != NULL)
+ {
+ if (in_part->ch_buf_append)
+ channel_write_new_lines(in_part->ch_bufref.br_buf);
+ else
+ channel_write_in(channel);
+ }
+}
+
+/*
+ * Write any lines waiting to be written to a channel.
+ */
+ void
+channel_write_any_lines(void)
+{
+ channel_T *channel;
+
+ for (channel = first_channel; channel != NULL; channel = channel->ch_next)
+ channel_write_input(channel);
+}
+
+/*
+ * Write appended lines above the last one in "buf" to the channel.
+ */
+ void
+channel_write_new_lines(buf_T *buf)
+{
+ channel_T *channel;
+ int found_one = FALSE;
+
+ /* There could be more than one channel for the buffer, loop over all of
+ * them. */
+ for (channel = first_channel; channel != NULL; channel = channel->ch_next)
+ {
+ chanpart_T *in_part = &channel->ch_part[PART_IN];
+ linenr_T lnum;
+ int written = 0;
+
+ if (in_part->ch_bufref.br_buf == buf && in_part->ch_buf_append)
+ {
+ if (in_part->ch_fd == INVALID_FD)
+ continue; /* pipe was closed */
+ found_one = TRUE;
+ for (lnum = in_part->ch_buf_bot; lnum < buf->b_ml.ml_line_count;
+ ++lnum)
+ {
+ if (!can_write_buf_line(channel))
+ break;
+ write_buf_line(buf, lnum, channel);
+ ++written;
+ }
+
+ if (written == 1)
+ ch_log(channel, "written line %d to channel", (int)lnum - 1);
+ else if (written > 1)
+ ch_log(channel, "written %d lines to channel", written);
+ if (lnum < buf->b_ml.ml_line_count)
+ ch_log(channel, "Still %ld more lines to write",
+ (long)(buf->b_ml.ml_line_count - lnum));
+
+ in_part->ch_buf_bot = lnum;
+ }
+ }
+ if (!found_one)
+ buf->b_write_to_channel = FALSE;
+}
+
+/*
+ * Invoke the "callback" on channel "channel".
+ * This does not redraw but sets channel_need_redraw;
+ */
+ static void
+invoke_callback(channel_T *channel, char_u *callback, partial_T *partial,
+ typval_T *argv)
+{
+ typval_T rettv;
+ int dummy;
+
+ if (safe_to_invoke_callback == 0)
+ iemsg("INTERNAL: Invoking callback when it is not safe");
+
+ argv[0].v_type = VAR_CHANNEL;
+ argv[0].vval.v_channel = channel;
+
+ call_func(callback, (int)STRLEN(callback), &rettv, 2, argv, NULL,
+ 0L, 0L, &dummy, TRUE, partial, NULL);
+ clear_tv(&rettv);
+ channel_need_redraw = TRUE;
+}
+
+/*
+ * Return the first node from "channel"/"part" without removing it.
+ * Returns NULL if there is nothing.
+ */
+ readq_T *
+channel_peek(channel_T *channel, ch_part_T part)
+{
+ readq_T *head = &channel->ch_part[part].ch_head;
+
+ return head->rq_next;
+}
+
+/*
+ * Return a pointer to the first NL in "node".
+ * Skips over NUL characters.
+ * Returns NULL if there is no NL.
+ */
+ char_u *
+channel_first_nl(readq_T *node)
+{
+ char_u *buffer = node->rq_buffer;
+ long_u i;
+
+ for (i = 0; i < node->rq_buflen; ++i)
+ if (buffer[i] == NL)
+ return buffer + i;
+ return NULL;
+}
+
+/*
+ * Return the first buffer from channel "channel"/"part" and remove it.
+ * The caller must free it.
+ * Returns NULL if there is nothing.
+ */
+ char_u *
+channel_get(channel_T *channel, ch_part_T part, int *outlen)
+{
+ readq_T *head = &channel->ch_part[part].ch_head;
+ readq_T *node = head->rq_next;
+ char_u *p;
+
+ if (node == NULL)
+ return NULL;
+ if (outlen != NULL)
+ *outlen += node->rq_buflen;
+ /* dispose of the node but keep the buffer */
+ p = node->rq_buffer;
+ head->rq_next = node->rq_next;
+ if (node->rq_next == NULL)
+ head->rq_prev = NULL;
+ else
+ node->rq_next->rq_prev = NULL;
+ vim_free(node);
+ return p;
+}
+
+/*
+ * Returns the whole buffer contents concatenated for "channel"/"part".
+ * Replaces NUL bytes with NL.
+ */
+ static char_u *
+channel_get_all(channel_T *channel, ch_part_T part, int *outlen)
+{
+ readq_T *head = &channel->ch_part[part].ch_head;
+ readq_T *node = head->rq_next;
+ long_u len = 0;
+ char_u *res;
+ char_u *p;
+
+ // Concatenate everything into one buffer.
+ for (node = head->rq_next; node != NULL; node = node->rq_next)
+ len += node->rq_buflen;
+ res = lalloc(len + 1, TRUE);
+ if (res == NULL)
+ return NULL;
+ p = res;
+ for (node = head->rq_next; node != NULL; node = node->rq_next)
+ {
+ mch_memmove(p, node->rq_buffer, node->rq_buflen);
+ p += node->rq_buflen;
+ }
+ *p = NUL;
+
+ // Free all buffers
+ do
+ {
+ p = channel_get(channel, part, NULL);
+ vim_free(p);
+ } while (p != NULL);
+
+ if (outlen != NULL)
+ {
+ // Returning the length, keep NUL characters.
+ *outlen += len;
+ return res;
+ }
+
+ // Turn all NUL into NL, so that the result can be used as a string.
+ p = res;
+ while (p < res + len)
+ {
+ if (*p == NUL)
+ *p = NL;
+#ifdef WIN32
+ else if (*p == 0x1b)
+ {
+ // crush the escape sequence OSC 0/1/2: ESC ]0;
+ if (p + 3 < res + len
+ && p[1] == ']'
+ && (p[2] == '0' || p[2] == '1' || p[2] == '2')
+ && p[3] == ';')
+ {
+ // '\a' becomes a NL
+ while (p < res + (len - 1) && *p != '\a')
+ ++p;
+ // BEL is zero width characters, suppress display mistake
+ // ConPTY (after 10.0.18317) requires advance checking
+ if (p[-1] == NUL)
+ p[-1] = 0x07;
+ }
+ }
+#endif
+ ++p;
+ }
+
+ return res;
+}
+
+/*
+ * Consume "len" bytes from the head of "node".
+ * Caller must check these bytes are available.
+ */
+ void
+channel_consume(channel_T *channel, ch_part_T part, int len)
+{
+ readq_T *head = &channel->ch_part[part].ch_head;
+ readq_T *node = head->rq_next;
+ char_u *buf = node->rq_buffer;
+
+ mch_memmove(buf, buf + len, node->rq_buflen - len);
+ node->rq_buflen -= len;
+}
+
+/*
+ * Collapses the first and second buffer for "channel"/"part".
+ * Returns FAIL if that is not possible.
+ * When "want_nl" is TRUE collapse more buffers until a NL is found.
+ */
+ int
+channel_collapse(channel_T *channel, ch_part_T part, int want_nl)
+{
+ readq_T *head = &channel->ch_part[part].ch_head;
+ readq_T *node = head->rq_next;
+ readq_T *last_node;
+ readq_T *n;
+ char_u *newbuf;
+ char_u *p;
+ long_u len;
+
+ if (node == NULL || node->rq_next == NULL)
+ return FAIL;
+
+ last_node = node->rq_next;
+ len = node->rq_buflen + last_node->rq_buflen + 1;
+ if (want_nl)
+ while (last_node->rq_next != NULL
+ && channel_first_nl(last_node) == NULL)
+ {
+ last_node = last_node->rq_next;
+ len += last_node->rq_buflen;
+ }
+
+ p = newbuf = alloc(len);
+ if (newbuf == NULL)
+ return FAIL; /* out of memory */
+ mch_memmove(p, node->rq_buffer, node->rq_buflen);
+ p += node->rq_buflen;
+ vim_free(node->rq_buffer);
+ node->rq_buffer = newbuf;
+ for (n = node; n != last_node; )
+ {
+ n = n->rq_next;
+ mch_memmove(p, n->rq_buffer, n->rq_buflen);
+ p += n->rq_buflen;
+ vim_free(n->rq_buffer);
+ }
+ node->rq_buflen = (long_u)(p - newbuf);
+
+ /* dispose of the collapsed nodes and their buffers */
+ for (n = node->rq_next; n != last_node; )
+ {
+ n = n->rq_next;
+ vim_free(n->rq_prev);
+ }
+ node->rq_next = last_node->rq_next;
+ if (last_node->rq_next == NULL)
+ head->rq_prev = node;
+ else
+ last_node->rq_next->rq_prev = node;
+ vim_free(last_node);
+ return OK;
+}
+
+/*
+ * Store "buf[len]" on "channel"/"part".
+ * When "prepend" is TRUE put in front, otherwise append at the end.
+ * Returns OK or FAIL.
+ */
+ static int
+channel_save(channel_T *channel, ch_part_T part, char_u *buf, int len,
+ int prepend, char *lead)
+{
+ readq_T *node;
+ readq_T *head = &channel->ch_part[part].ch_head;
+ char_u *p;
+ int i;
+
+ node = (readq_T *)alloc(sizeof(readq_T));
+ if (node == NULL)
+ return FAIL; /* out of memory */
+ /* A NUL is added at the end, because netbeans code expects that.
+ * Otherwise a NUL may appear inside the text. */
+ node->rq_buffer = alloc(len + 1);
+ if (node->rq_buffer == NULL)
+ {
+ vim_free(node);
+ return FAIL; /* out of memory */
+ }
+
+ if (channel->ch_part[part].ch_mode == MODE_NL)
+ {
+ /* Drop any CR before a NL. */
+ p = node->rq_buffer;
+ for (i = 0; i < len; ++i)
+ if (buf[i] != CAR || i + 1 >= len || buf[i + 1] != NL)
+ *p++ = buf[i];
+ *p = NUL;
+ node->rq_buflen = (long_u)(p - node->rq_buffer);
+ }
+ else
+ {
+ mch_memmove(node->rq_buffer, buf, len);
+ node->rq_buffer[len] = NUL;
+ node->rq_buflen = (long_u)len;
+ }
+
+ if (prepend)
+ {
+ /* preend node to the head of the queue */
+ node->rq_next = head->rq_next;
+ node->rq_prev = NULL;
+ if (head->rq_next == NULL)
+ head->rq_prev = node;
+ else
+ head->rq_next->rq_prev = node;
+ head->rq_next = node;
+ }
+ else
+ {
+ /* append node to the tail of the queue */
+ node->rq_next = NULL;
+ node->rq_prev = head->rq_prev;
+ if (head->rq_prev == NULL)
+ head->rq_next = node;
+ else
+ head->rq_prev->rq_next = node;
+ head->rq_prev = node;
+ }
+
+ if (ch_log_active() && lead != NULL)
+ {
+ ch_log_lead(lead, channel, part);
+ fprintf(log_fd, "'");
+ vim_ignored = (int)fwrite(buf, len, 1, log_fd);
+ fprintf(log_fd, "'\n");
+ }
+ return OK;
+}
+
+/*
+ * Try to fill the buffer of "reader".
+ * Returns FALSE when nothing was added.
+ */
+ static int
+channel_fill(js_read_T *reader)
+{
+ channel_T *channel = (channel_T *)reader->js_cookie;
+ ch_part_T part = reader->js_cookie_arg;
+ char_u *next = channel_get(channel, part, NULL);
+ int keeplen;
+ int addlen;
+ char_u *p;
+
+ if (next == NULL)
+ return FALSE;
+
+ keeplen = reader->js_end - reader->js_buf;
+ if (keeplen > 0)
+ {
+ /* Prepend unused text. */
+ addlen = (int)STRLEN(next);
+ p = alloc(keeplen + addlen + 1);
+ if (p == NULL)
+ {
+ vim_free(next);
+ return FALSE;
+ }
+ mch_memmove(p, reader->js_buf, keeplen);
+ mch_memmove(p + keeplen, next, addlen + 1);
+ vim_free(next);
+ next = p;
+ }
+
+ vim_free(reader->js_buf);
+ reader->js_buf = next;
+ return TRUE;
+}
+
+/*
+ * Use the read buffer of "channel"/"part" and parse a JSON message that is
+ * complete. The messages are added to the queue.
+ * Return TRUE if there is more to read.
+ */
+ static int
+channel_parse_json(channel_T *channel, ch_part_T part)
+{
+ js_read_T reader;
+ typval_T listtv;
+ jsonq_T *item;
+ chanpart_T *chanpart = &channel->ch_part[part];
+ jsonq_T *head = &chanpart->ch_json_head;
+ int status;
+ int ret;
+
+ if (channel_peek(channel, part) == NULL)
+ return FALSE;
+
+ reader.js_buf = channel_get(channel, part, NULL);
+ reader.js_used = 0;
+ reader.js_fill = channel_fill;
+ reader.js_cookie = channel;
+ reader.js_cookie_arg = part;
+
+ /* When a message is incomplete we wait for a short while for more to
+ * arrive. After the delay drop the input, otherwise a truncated string
+ * or list will make us hang.
+ * Do not generate error messages, they will be written in a channel log. */
+ ++emsg_silent;
+ status = json_decode(&reader, &listtv,
+ chanpart->ch_mode == MODE_JS ? JSON_JS : 0);
+ --emsg_silent;
+ if (status == OK)
+ {
+ /* Only accept the response when it is a list with at least two
+ * items. */
+ if (listtv.v_type != VAR_LIST || listtv.vval.v_list->lv_len < 2)
+ {
+ if (listtv.v_type != VAR_LIST)
+ ch_error(channel, "Did not receive a list, discarding");
+ else
+ ch_error(channel, "Expected list with two items, got %d",
+ listtv.vval.v_list->lv_len);
+ clear_tv(&listtv);
+ }
+ else
+ {
+ item = (jsonq_T *)alloc((unsigned)sizeof(jsonq_T));
+ if (item == NULL)
+ clear_tv(&listtv);
+ else
+ {
+ item->jq_no_callback = FALSE;
+ item->jq_value = alloc_tv();
+ if (item->jq_value == NULL)
+ {
+ vim_free(item);
+ clear_tv(&listtv);
+ }
+ else
+ {
+ *item->jq_value = listtv;
+ item->jq_prev = head->jq_prev;
+ head->jq_prev = item;
+ item->jq_next = NULL;
+ if (item->jq_prev == NULL)
+ head->jq_next = item;
+ else
+ item->jq_prev->jq_next = item;
+ }
+ }
+ }
+ }
+
+ if (status == OK)
+ chanpart->ch_wait_len = 0;
+ else if (status == MAYBE)
+ {
+ size_t buflen = STRLEN(reader.js_buf);
+
+ if (chanpart->ch_wait_len < buflen)
+ {
+ /* First time encountering incomplete message or after receiving
+ * more (but still incomplete): set a deadline of 100 msec. */
+ ch_log(channel,
+ "Incomplete message (%d bytes) - wait 100 msec for more",
+ (int)buflen);
+ reader.js_used = 0;
+ chanpart->ch_wait_len = buflen;
+#ifdef WIN32
+ chanpart->ch_deadline = GetTickCount() + 100L;
+#else
+ gettimeofday(&chanpart->ch_deadline, NULL);
+ chanpart->ch_deadline.tv_usec += 100 * 1000;
+ if (chanpart->ch_deadline.tv_usec > 1000 * 1000)
+ {
+ chanpart->ch_deadline.tv_usec -= 1000 * 1000;
+ ++chanpart->ch_deadline.tv_sec;
+ }
+#endif
+ }
+ else
+ {
+ int timeout;
+#ifdef WIN32
+ timeout = GetTickCount() > chanpart->ch_deadline;
+#else
+ {
+ struct timeval now_tv;
+
+ gettimeofday(&now_tv, NULL);
+ timeout = now_tv.tv_sec > chanpart->ch_deadline.tv_sec
+ || (now_tv.tv_sec == chanpart->ch_deadline.tv_sec
+ && now_tv.tv_usec > chanpart->ch_deadline.tv_usec);
+ }
+#endif
+ if (timeout)
+ {
+ status = FAIL;
+ chanpart->ch_wait_len = 0;
+ ch_log(channel, "timed out");
+ }
+ else
+ {
+ reader.js_used = 0;
+ ch_log(channel, "still waiting on incomplete message");
+ }
+ }
+ }
+
+ if (status == FAIL)
+ {
+ ch_error(channel, "Decoding failed - discarding input");
+ ret = FALSE;
+ chanpart->ch_wait_len = 0;
+ }
+ else if (reader.js_buf[reader.js_used] != NUL)
+ {
+ /* Put the unread part back into the channel. */
+ channel_save(channel, part, reader.js_buf + reader.js_used,
+ (int)(reader.js_end - reader.js_buf) - reader.js_used,
+ TRUE, NULL);
+ ret = status == MAYBE ? FALSE: TRUE;
+ }
+ else
+ ret = FALSE;
+
+ vim_free(reader.js_buf);
+ return ret;
+}
+
+/*
+ * Remove "node" from the queue that it is in. Does not free it.
+ */
+ static void
+remove_cb_node(cbq_T *head, cbq_T *node)
+{
+ if (node->cq_prev == NULL)
+ head->cq_next = node->cq_next;
+ else
+ node->cq_prev->cq_next = node->cq_next;
+ if (node->cq_next == NULL)
+ head->cq_prev = node->cq_prev;
+ else
+ node->cq_next->cq_prev = node->cq_prev;
+}
+
+/*
+ * Remove "node" from the queue that it is in and free it.
+ * Caller should have freed or used node->jq_value.
+ */
+ static void
+remove_json_node(jsonq_T *head, jsonq_T *node)
+{
+ if (node->jq_prev == NULL)
+ head->jq_next = node->jq_next;
+ else
+ node->jq_prev->jq_next = node->jq_next;
+ if (node->jq_next == NULL)
+ head->jq_prev = node->jq_prev;
+ else
+ node->jq_next->jq_prev = node->jq_prev;
+ vim_free(node);
+}
+
+/*
+ * Get a message from the JSON queue for channel "channel".
+ * When "id" is positive it must match the first number in the list.
+ * When "id" is zero or negative jut get the first message. But not the one
+ * with id ch_block_id.
+ * When "without_callback" is TRUE also get messages that were pushed back.
+ * Return OK when found and return the value in "rettv".
+ * Return FAIL otherwise.
+ */
+ static int
+channel_get_json(
+ channel_T *channel,
+ ch_part_T part,
+ int id,
+ int without_callback,
+ typval_T **rettv)
+{
+ jsonq_T *head = &channel->ch_part[part].ch_json_head;
+ jsonq_T *item = head->jq_next;
+
+ while (item != NULL)
+ {
+ list_T *l = item->jq_value->vval.v_list;
+ typval_T *tv = &l->lv_first->li_tv;
+
+ if ((without_callback || !item->jq_no_callback)
+ && ((id > 0 && tv->v_type == VAR_NUMBER && tv->vval.v_number == id)
+ || (id <= 0 && (tv->v_type != VAR_NUMBER
+ || tv->vval.v_number == 0
+ || tv->vval.v_number != channel->ch_part[part].ch_block_id))))
+ {
+ *rettv = item->jq_value;
+ if (tv->v_type == VAR_NUMBER)
+ ch_log(channel, "Getting JSON message %ld",
+ (long)tv->vval.v_number);
+ remove_json_node(head, item);
+ return OK;
+ }
+ item = item->jq_next;
+ }
+ return FAIL;
+}
+
+/*
+ * Put back "rettv" into the JSON queue, there was no callback for it.
+ * Takes over the values in "rettv".
+ */
+ static void
+channel_push_json(channel_T *channel, ch_part_T part, typval_T *rettv)
+{
+ jsonq_T *head = &channel->ch_part[part].ch_json_head;
+ jsonq_T *item = head->jq_next;
+ jsonq_T *newitem;
+
+ if (head->jq_prev != NULL && head->jq_prev->jq_no_callback)
+ /* last item was pushed back, append to the end */
+ item = NULL;
+ else while (item != NULL && item->jq_no_callback)
+ /* append after the last item that was pushed back */
+ item = item->jq_next;
+
+ newitem = (jsonq_T *)alloc((unsigned)sizeof(jsonq_T));
+ if (newitem == NULL)
+ clear_tv(rettv);
+ else
+ {
+ newitem->jq_value = alloc_tv();
+ if (newitem->jq_value == NULL)
+ {
+ vim_free(newitem);
+ clear_tv(rettv);
+ }
+ else
+ {
+ newitem->jq_no_callback = FALSE;
+ *newitem->jq_value = *rettv;
+ if (item == NULL)
+ {
+ /* append to the end */
+ newitem->jq_prev = head->jq_prev;
+ head->jq_prev = newitem;
+ newitem->jq_next = NULL;
+ if (newitem->jq_prev == NULL)
+ head->jq_next = newitem;
+ else
+ newitem->jq_prev->jq_next = newitem;
+ }
+ else
+ {
+ /* append after "item" */
+ newitem->jq_prev = item;
+ newitem->jq_next = item->jq_next;
+ item->jq_next = newitem;
+ if (newitem->jq_next == NULL)
+ head->jq_prev = newitem;
+ else
+ newitem->jq_next->jq_prev = newitem;
+ }
+ }
+ }
+}
+
+#define CH_JSON_MAX_ARGS 4
+
+/*
+ * Execute a command received over "channel"/"part"
+ * "argv[0]" is the command string.
+ * "argv[1]" etc. have further arguments, type is VAR_UNKNOWN if missing.
+ */
+ static void
+channel_exe_cmd(channel_T *channel, ch_part_T part, typval_T *argv)
+{
+ char_u *cmd = argv[0].vval.v_string;
+ char_u *arg;
+ int options = channel->ch_part[part].ch_mode == MODE_JS ? JSON_JS : 0;
+
+ if (argv[1].v_type != VAR_STRING)
+ {
+ ch_error(channel, "received command with non-string argument");
+ if (p_verbose > 2)
+ emsg(_("E903: received command with non-string argument"));
+ return;
+ }
+ arg = argv[1].vval.v_string;
+ if (arg == NULL)
+ arg = (char_u *)"";
+
+ if (STRCMP(cmd, "ex") == 0)
+ {
+ int save_called_emsg = called_emsg;
+
+ called_emsg = FALSE;
+ ch_log(channel, "Executing ex command '%s'", (char *)arg);
+ ++emsg_silent;
+ do_cmdline_cmd(arg);
+ --emsg_silent;
+ if (called_emsg)
+ ch_log(channel, "Ex command error: '%s'",
+ (char *)get_vim_var_str(VV_ERRMSG));
+ called_emsg = save_called_emsg;
+ }
+ else if (STRCMP(cmd, "normal") == 0)
+ {
+ exarg_T ea;
+
+ ch_log(channel, "Executing normal command '%s'", (char *)arg);
+ ea.arg = arg;
+ ea.addr_count = 0;
+ ea.forceit = TRUE; /* no mapping */
+ ex_normal(&ea);
+ }
+ else if (STRCMP(cmd, "redraw") == 0)
+ {
+ exarg_T ea;
+
+ ch_log(channel, "redraw");
+ ea.forceit = *arg != NUL;
+ ex_redraw(&ea);
+ showruler(FALSE);
+ setcursor();
+ out_flush_cursor(TRUE, FALSE);
+ }
+ else if (STRCMP(cmd, "expr") == 0 || STRCMP(cmd, "call") == 0)
+ {
+ int is_call = cmd[0] == 'c';
+ int id_idx = is_call ? 3 : 2;
+
+ if (argv[id_idx].v_type != VAR_UNKNOWN
+ && argv[id_idx].v_type != VAR_NUMBER)
+ {
+ ch_error(channel, "last argument for expr/call must be a number");
+ if (p_verbose > 2)
+ emsg(_("E904: last argument for expr/call must be a number"));
+ }
+ else if (is_call && argv[2].v_type != VAR_LIST)
+ {
+ ch_error(channel, "third argument for call must be a list");
+ if (p_verbose > 2)
+ emsg(_("E904: third argument for call must be a list"));
+ }
+ else
+ {
+ typval_T *tv = NULL;
+ typval_T res_tv;
+ typval_T err_tv;
+ char_u *json = NULL;
+
+ /* Don't pollute the display with errors. */
+ ++emsg_skip;
+ if (!is_call)
+ {
+ ch_log(channel, "Evaluating expression '%s'", (char *)arg);
+ tv = eval_expr(arg, NULL);
+ }
+ else
+ {
+ ch_log(channel, "Calling '%s'", (char *)arg);
+ if (func_call(arg, &argv[2], NULL, NULL, &res_tv) == OK)
+ tv = &res_tv;
+ }
+
+ if (argv[id_idx].v_type == VAR_NUMBER)
+ {
+ int id = argv[id_idx].vval.v_number;
+
+ if (tv != NULL)
+ json = json_encode_nr_expr(id, tv, options | JSON_NL);
+ if (tv == NULL || (json != NULL && *json == NUL))
+ {
+ /* If evaluation failed or the result can't be encoded
+ * then return the string "ERROR". */
+ vim_free(json);
+ err_tv.v_type = VAR_STRING;
+ err_tv.vval.v_string = (char_u *)"ERROR";
+ json = json_encode_nr_expr(id, &err_tv, options | JSON_NL);
+ }
+ if (json != NULL)
+ {
+ channel_send(channel,
+ part == PART_SOCK ? PART_SOCK : PART_IN,
+ json, (int)STRLEN(json), (char *)cmd);
+ vim_free(json);
+ }
+ }
+ --emsg_skip;
+ if (tv == &res_tv)
+ clear_tv(tv);
+ else
+ free_tv(tv);
+ }
+ }
+ else if (p_verbose > 2)
+ {
+ ch_error(channel, "Received unknown command: %s", (char *)cmd);
+ semsg(_("E905: received unknown command: %s"), cmd);
+ }
+}
+
+/*
+ * Invoke the callback at "cbhead".
+ * Does not redraw but sets channel_need_redraw.
+ */
+ static void
+invoke_one_time_callback(
+ channel_T *channel,
+ cbq_T *cbhead,
+ cbq_T *item,
+ typval_T *argv)
+{
+ ch_log(channel, "Invoking one-time callback %s",
+ (char *)item->cq_callback);
+ /* Remove the item from the list first, if the callback
+ * invokes ch_close() the list will be cleared. */
+ remove_cb_node(cbhead, item);
+ invoke_callback(channel, item->cq_callback, item->cq_partial, argv);
+ free_callback(item->cq_callback, item->cq_partial);
+ vim_free(item);
+}
+
+ static void
+append_to_buffer(buf_T *buffer, char_u *msg, channel_T *channel, ch_part_T part)
+{
+ bufref_T save_curbuf = {NULL, 0, 0};
+ win_T *save_curwin = NULL;
+ tabpage_T *save_curtab = NULL;
+ linenr_T lnum = buffer->b_ml.ml_line_count;
+ int save_write_to = buffer->b_write_to_channel;
+ chanpart_T *ch_part = &channel->ch_part[part];
+ int save_p_ma = buffer->b_p_ma;
+ int empty = (buffer->b_ml.ml_flags & ML_EMPTY) ? 1 : 0;
+
+ if (!buffer->b_p_ma && !ch_part->ch_nomodifiable)
+ {
+ if (!ch_part->ch_nomod_error)
+ {
+ ch_error(channel, "Buffer is not modifiable, cannot append");
+ ch_part->ch_nomod_error = TRUE;
+ }
+ return;
+ }
+
+ /* If the buffer is also used as input insert above the last
+ * line. Don't write these lines. */
+ if (save_write_to)
+ {
+ --lnum;
+ buffer->b_write_to_channel = FALSE;
+ }
+
+ /* Append to the buffer */
+ ch_log(channel, "appending line %d to buffer", (int)lnum + 1 - empty);
+
+ buffer->b_p_ma = TRUE;
+
+ /* Save curbuf/curwin/curtab and make "buffer" the current buffer. */
+ switch_to_win_for_buf(buffer, &save_curwin, &save_curtab, &save_curbuf);
+
+ u_sync(TRUE);
+ /* ignore undo failure, undo is not very useful here */
+ vim_ignored = u_save(lnum - empty, lnum + 1);
+
+ if (empty)
+ {
+ /* The buffer is empty, replace the first (dummy) line. */
+ ml_replace(lnum, msg, TRUE);
+ lnum = 0;
+ }
+ else
+ ml_append(lnum, msg, 0, FALSE);
+ appended_lines_mark(lnum, 1L);
+
+ /* Restore curbuf/curwin/curtab */
+ restore_win_for_buf(save_curwin, save_curtab, &save_curbuf);
+
+ if (ch_part->ch_nomodifiable)
+ buffer->b_p_ma = FALSE;
+ else
+ buffer->b_p_ma = save_p_ma;
+
+ if (buffer->b_nwindows > 0)
+ {
+ win_T *wp;
+
+ FOR_ALL_WINDOWS(wp)
+ {
+ if (wp->w_buffer == buffer
+ && (save_write_to
+ ? wp->w_cursor.lnum == lnum + 1
+ : (wp->w_cursor.lnum == lnum
+ && wp->w_cursor.col == 0)))
+ {
+ ++wp->w_cursor.lnum;
+ save_curwin = curwin;
+ curwin = wp;
+ curbuf = curwin->w_buffer;
+ scroll_cursor_bot(0, FALSE);
+ curwin = save_curwin;
+ curbuf = curwin->w_buffer;
+ }
+ }
+ redraw_buf_and_status_later(buffer, VALID);
+ channel_need_redraw = TRUE;
+ }
+
+ if (save_write_to)
+ {
+ channel_T *ch;
+
+ /* Find channels reading from this buffer and adjust their
+ * next-to-read line number. */
+ buffer->b_write_to_channel = TRUE;
+ for (ch = first_channel; ch != NULL; ch = ch->ch_next)
+ {
+ chanpart_T *in_part = &ch->ch_part[PART_IN];
+
+ if (in_part->ch_bufref.br_buf == buffer)
+ in_part->ch_buf_bot = buffer->b_ml.ml_line_count;
+ }
+ }
+}
+
+ static void
+drop_messages(channel_T *channel, ch_part_T part)
+{
+ char_u *msg;
+
+ while ((msg = channel_get(channel, part, NULL)) != NULL)
+ {
+ ch_log(channel, "Dropping message '%s'", (char *)msg);
+ vim_free(msg);
+ }
+}
+
+/*
+ * Invoke a callback for "channel"/"part" if needed.
+ * This does not redraw but sets channel_need_redraw when redraw is needed.
+ * Return TRUE when a message was handled, there might be another one.
+ */
+ static int
+may_invoke_callback(channel_T *channel, ch_part_T part)
+{
+ char_u *msg = NULL;
+ typval_T *listtv = NULL;
+ typval_T argv[CH_JSON_MAX_ARGS];
+ int seq_nr = -1;
+ chanpart_T *ch_part = &channel->ch_part[part];
+ ch_mode_T ch_mode = ch_part->ch_mode;
+ cbq_T *cbhead = &ch_part->ch_cb_head;
+ cbq_T *cbitem;
+ char_u *callback = NULL;
+ partial_T *partial = NULL;
+ buf_T *buffer = NULL;
+ char_u *p;
+
+ if (channel->ch_nb_close_cb != NULL)
+ /* this channel is handled elsewhere (netbeans) */
+ return FALSE;
+
+ /* Use a message-specific callback, part callback or channel callback */
+ for (cbitem = cbhead->cq_next; cbitem != NULL; cbitem = cbitem->cq_next)
+ if (cbitem->cq_seq_nr == 0)
+ break;
+ if (cbitem != NULL)
+ {
+ callback = cbitem->cq_callback;
+ partial = cbitem->cq_partial;
+ }
+ else if (ch_part->ch_callback != NULL)
+ {
+ callback = ch_part->ch_callback;
+ partial = ch_part->ch_partial;
+ }
+ else
+ {
+ callback = channel->ch_callback;
+ partial = channel->ch_partial;
+ }
+
+ buffer = ch_part->ch_bufref.br_buf;
+ if (buffer != NULL && (!bufref_valid(&ch_part->ch_bufref)
+ || buffer->b_ml.ml_mfp == NULL))
+ {
+ /* buffer was wiped out or unloaded */
+ ch_log(channel, "%s buffer has been wiped out", part_names[part]);
+ ch_part->ch_bufref.br_buf = NULL;
+ buffer = NULL;
+ }
+
+ if (ch_mode == MODE_JSON || ch_mode == MODE_JS)
+ {
+ listitem_T *item;
+ int argc = 0;
+
+ /* Get any json message in the queue. */
+ if (channel_get_json(channel, part, -1, FALSE, &listtv) == FAIL)
+ {
+ /* Parse readahead, return when there is still no message. */
+ channel_parse_json(channel, part);
+ if (channel_get_json(channel, part, -1, FALSE, &listtv) == FAIL)
+ return FALSE;
+ }
+
+ for (item = listtv->vval.v_list->lv_first;
+ item != NULL && argc < CH_JSON_MAX_ARGS;
+ item = item->li_next)
+ argv[argc++] = item->li_tv;
+ while (argc < CH_JSON_MAX_ARGS)
+ argv[argc++].v_type = VAR_UNKNOWN;
+
+ if (argv[0].v_type == VAR_STRING)
+ {
+ /* ["cmd", arg] or ["cmd", arg, arg] or ["cmd", arg, arg, arg] */
+ channel_exe_cmd(channel, part, argv);
+ free_tv(listtv);
+ return TRUE;
+ }
+
+ if (argv[0].v_type != VAR_NUMBER)
+ {
+ ch_error(channel,
+ "Dropping message with invalid sequence number type");
+ free_tv(listtv);
+ return FALSE;
+ }
+ seq_nr = argv[0].vval.v_number;
+ }
+ else if (channel_peek(channel, part) == NULL)
+ {
+ /* nothing to read on RAW or NL channel */
+ return FALSE;
+ }
+ else
+ {
+ /* If there is no callback or buffer drop the message. */
+ if (callback == NULL && buffer == NULL)
+ {
+ /* If there is a close callback it may use ch_read() to get the
+ * messages. */
+ if (channel->ch_close_cb == NULL && !channel->ch_drop_never)
+ drop_messages(channel, part);
+ return FALSE;
+ }
+
+ if (ch_mode == MODE_NL)
+ {
+ char_u *nl = NULL;
+ char_u *buf;
+ readq_T *node;
+
+ /* See if we have a message ending in NL in the first buffer. If
+ * not try to concatenate the first and the second buffer. */
+ while (TRUE)
+ {
+ node = channel_peek(channel, part);
+ nl = channel_first_nl(node);
+ if (nl != NULL)
+ break;
+ if (channel_collapse(channel, part, TRUE) == FAIL)
+ {
+ if (ch_part->ch_fd == INVALID_FD && node->rq_buflen > 0)
+ break;
+ return FALSE; /* incomplete message */
+ }
+ }
+ buf = node->rq_buffer;
+
+ if (nl == NULL)
+ {
+ /* Flush remaining message that is missing a NL. */
+ char_u *new_buf;
+
+ new_buf = vim_realloc(buf, node->rq_buflen + 1);
+ if (new_buf == NULL)
+ /* This might fail over and over again, should the message
+ * be dropped? */
+ return FALSE;
+ buf = new_buf;
+ node->rq_buffer = buf;
+ nl = buf + node->rq_buflen++;
+ *nl = NUL;
+ }
+
+ /* Convert NUL to NL, the internal representation. */
+ for (p = buf; p < nl && p < buf + node->rq_buflen; ++p)
+ if (*p == NUL)
+ *p = NL;
+
+ if (nl + 1 == buf + node->rq_buflen)
+ {
+ /* get the whole buffer, drop the NL */
+ msg = channel_get(channel, part, NULL);
+ *nl = NUL;
+ }
+ else
+ {
+ /* Copy the message into allocated memory (excluding the NL)
+ * and remove it from the buffer (including the NL). */
+ msg = vim_strnsave(buf, (int)(nl - buf));
+ channel_consume(channel, part, (int)(nl - buf) + 1);
+ }
+ }
+ else
+ {
+ /* For a raw channel we don't know where the message ends, just
+ * get everything we have.
+ * Convert NUL to NL, the internal representation. */
+ msg = channel_get_all(channel, part, NULL);
+ }
+
+ if (msg == NULL)
+ return FALSE; /* out of memory (and avoids Coverity warning) */
+
+ argv[1].v_type = VAR_STRING;
+ argv[1].vval.v_string = msg;
+ }
+
+ if (seq_nr > 0)
+ {
+ int done = FALSE;
+
+ /* JSON or JS mode: invoke the one-time callback with the matching nr */
+ for (cbitem = cbhead->cq_next; cbitem != NULL; cbitem = cbitem->cq_next)
+ if (cbitem->cq_seq_nr == seq_nr)
+ {
+ invoke_one_time_callback(channel, cbhead, cbitem, argv);
+ done = TRUE;
+ break;
+ }
+ if (!done)
+ {
+ if (channel->ch_drop_never)
+ {
+ /* message must be read with ch_read() */
+ channel_push_json(channel, part, listtv);
+ listtv = NULL;
+ }
+ else
+ ch_log(channel, "Dropping message %d without callback",
+ seq_nr);
+ }
+ }
+ else if (callback != NULL || buffer != NULL)
+ {
+ if (buffer != NULL)
+ {
+ if (msg == NULL)
+ /* JSON or JS mode: re-encode the message. */
+ msg = json_encode(listtv, ch_mode);
+ if (msg != NULL)
+ {
+#ifdef FEAT_TERMINAL
+ if (buffer->b_term != NULL)
+ write_to_term(buffer, msg, channel);
+ else
+#endif
+ append_to_buffer(buffer, msg, channel, part);
+ }
+ }
+
+ if (callback != NULL)
+ {
+ if (cbitem != NULL)
+ invoke_one_time_callback(channel, cbhead, cbitem, argv);
+ else
+ {
+ /* invoke the channel callback */
+ ch_log(channel, "Invoking channel callback %s",
+ (char *)callback);
+ invoke_callback(channel, callback, partial, argv);
+ }
+ }
+ }
+ else
+ ch_log(channel, "Dropping message %d", seq_nr);
+
+ if (listtv != NULL)
+ free_tv(listtv);
+ vim_free(msg);
+
+ return TRUE;
+}
+
+#if defined(FEAT_NETBEANS_INTG) || defined(PROTO)
+/*
+ * Return TRUE when channel "channel" is open for writing to.
+ * Also returns FALSE or invalid "channel".
+ */
+ int
+channel_can_write_to(channel_T *channel)
+{
+ return channel != NULL && (channel->CH_SOCK_FD != INVALID_FD
+ || channel->CH_IN_FD != INVALID_FD);
+}
+#endif
+
+/*
+ * Return TRUE when channel "channel" is open for reading or writing.
+ * Also returns FALSE for invalid "channel".
+ */
+ int
+channel_is_open(channel_T *channel)
+{
+ return channel != NULL && (channel->CH_SOCK_FD != INVALID_FD
+ || channel->CH_IN_FD != INVALID_FD
+ || channel->CH_OUT_FD != INVALID_FD
+ || channel->CH_ERR_FD != INVALID_FD);
+}
+
+/*
+ * Return TRUE if "channel" has JSON or other typeahead.
+ */
+ int
+channel_has_readahead(channel_T *channel, ch_part_T part)
+{
+ ch_mode_T ch_mode = channel->ch_part[part].ch_mode;
+
+ if (ch_mode == MODE_JSON || ch_mode == MODE_JS)
+ {
+ jsonq_T *head = &channel->ch_part[part].ch_json_head;
+ jsonq_T *item = head->jq_next;
+
+ return item != NULL;
+ }
+ return channel_peek(channel, part) != NULL;
+}
+
+/*
+ * Return a string indicating the status of the channel.
+ * If "req_part" is not negative check that part.
+ */
+ char *
+channel_status(channel_T *channel, int req_part)
+{
+ ch_part_T part;
+ int has_readahead = FALSE;
+
+ if (channel == NULL)
+ return "fail";
+ if (req_part == PART_OUT)
+ {
+ if (channel->CH_OUT_FD != INVALID_FD)
+ return "open";
+ if (channel_has_readahead(channel, PART_OUT))
+ has_readahead = TRUE;
+ }
+ else if (req_part == PART_ERR)
+ {
+ if (channel->CH_ERR_FD != INVALID_FD)
+ return "open";
+ if (channel_has_readahead(channel, PART_ERR))
+ has_readahead = TRUE;
+ }
+ else
+ {
+ if (channel_is_open(channel))
+ return "open";
+ for (part = PART_SOCK; part < PART_IN; ++part)
+ if (channel_has_readahead(channel, part))
+ {
+ has_readahead = TRUE;
+ break;
+ }
+ }
+
+ if (has_readahead)
+ return "buffered";
+ return "closed";
+}
+
+ static void
+channel_part_info(channel_T *channel, dict_T *dict, char *name, ch_part_T part)
+{
+ chanpart_T *chanpart = &channel->ch_part[part];
+ char namebuf[20]; /* longest is "sock_timeout" */
+ size_t tail;
+ char *status;
+ char *s = "";
+
+ vim_strncpy((char_u *)namebuf, (char_u *)name, 4);
+ STRCAT(namebuf, "_");
+ tail = STRLEN(namebuf);
+
+ STRCPY(namebuf + tail, "status");
+ if (chanpart->ch_fd != INVALID_FD)
+ status = "open";
+ else if (channel_has_readahead(channel, part))
+ status = "buffered";
+ else
+ status = "closed";
+ dict_add_string(dict, namebuf, (char_u *)status);
+
+ STRCPY(namebuf + tail, "mode");
+ switch (chanpart->ch_mode)
+ {
+ case MODE_NL: s = "NL"; break;
+ case MODE_RAW: s = "RAW"; break;
+ case MODE_JSON: s = "JSON"; break;
+ case MODE_JS: s = "JS"; break;
+ }
+ dict_add_string(dict, namebuf, (char_u *)s);
+
+ STRCPY(namebuf + tail, "io");
+ if (part == PART_SOCK)
+ s = "socket";
+ else switch (chanpart->ch_io)
+ {
+ case JIO_NULL: s = "null"; break;
+ case JIO_PIPE: s = "pipe"; break;
+ case JIO_FILE: s = "file"; break;
+ case JIO_BUFFER: s = "buffer"; break;
+ case JIO_OUT: s = "out"; break;
+ }
+ dict_add_string(dict, namebuf, (char_u *)s);
+
+ STRCPY(namebuf + tail, "timeout");
+ dict_add_number(dict, namebuf, chanpart->ch_timeout);
+}
+
+ void
+channel_info(channel_T *channel, dict_T *dict)
+{
+ dict_add_number(dict, "id", channel->ch_id);
+ dict_add_string(dict, "status", (char_u *)channel_status(channel, -1));
+
+ if (channel->ch_hostname != NULL)
+ {
+ dict_add_string(dict, "hostname", (char_u *)channel->ch_hostname);
+ dict_add_number(dict, "port", channel->ch_port);
+ channel_part_info(channel, dict, "sock", PART_SOCK);
+ }
+ else
+ {
+ channel_part_info(channel, dict, "out", PART_OUT);
+ channel_part_info(channel, dict, "err", PART_ERR);
+ channel_part_info(channel, dict, "in", PART_IN);
+ }
+}
+
+/*
+ * Close channel "channel".
+ * Trigger the close callback if "invoke_close_cb" is TRUE.
+ * Does not clear the buffers.
+ */
+ void
+channel_close(channel_T *channel, int invoke_close_cb)
+{
+ ch_log(channel, "Closing channel");
+
+#ifdef FEAT_GUI
+ channel_gui_unregister(channel);
+#endif
+
+ ch_close_part(channel, PART_SOCK);
+ ch_close_part(channel, PART_IN);
+ ch_close_part(channel, PART_OUT);
+ ch_close_part(channel, PART_ERR);
+
+ if (invoke_close_cb)
+ {
+ ch_part_T part;
+
+ /* Invoke callbacks and flush buffers before the close callback. */
+ if (channel->ch_close_cb != NULL)
+ ch_log(channel,
+ "Invoking callbacks and flushing buffers before closing");
+ for (part = PART_SOCK; part < PART_IN; ++part)
+ {
+ if (channel->ch_close_cb != NULL
+ || channel->ch_part[part].ch_bufref.br_buf != NULL)
+ {
+ /* Increment the refcount to avoid the channel being freed
+ * halfway. */
+ ++channel->ch_refcount;
+ if (channel->ch_close_cb == NULL)
+ ch_log(channel, "flushing %s buffers before closing",
+ part_names[part]);
+ while (may_invoke_callback(channel, part))
+ ;
+ --channel->ch_refcount;
+ }
+ }
+
+ if (channel->ch_close_cb != NULL)
+ {
+ typval_T argv[1];
+ typval_T rettv;
+ int dummy;
+
+ /* Increment the refcount to avoid the channel being freed
+ * halfway. */
+ ++channel->ch_refcount;
+ ch_log(channel, "Invoking close callback %s",
+ (char *)channel->ch_close_cb);
+ argv[0].v_type = VAR_CHANNEL;
+ argv[0].vval.v_channel = channel;
+ call_func(channel->ch_close_cb, (int)STRLEN(channel->ch_close_cb),
+ &rettv, 1, argv, NULL, 0L, 0L, &dummy, TRUE,
+ channel->ch_close_partial, NULL);
+ clear_tv(&rettv);
+ channel_need_redraw = TRUE;
+
+ /* the callback is only called once */
+ free_callback(channel->ch_close_cb, channel->ch_close_partial);
+ channel->ch_close_cb = NULL;
+ channel->ch_close_partial = NULL;
+
+ if (channel_need_redraw)
+ {
+ channel_need_redraw = FALSE;
+ redraw_after_callback(TRUE);
+ }
+
+ if (!channel->ch_drop_never)
+ /* any remaining messages are useless now */
+ for (part = PART_SOCK; part < PART_IN; ++part)
+ drop_messages(channel, part);
+
+ --channel->ch_refcount;
+ }
+ }
+
+ channel->ch_nb_close_cb = NULL;
+
+#ifdef FEAT_TERMINAL
+ term_channel_closed(channel);
+#endif
+}
+
+/*
+ * Close the "in" part channel "channel".
+ */
+ void
+channel_close_in(channel_T *channel)
+{
+ ch_close_part(channel, PART_IN);
+}
+
+ static void
+remove_from_writeque(writeq_T *wq, writeq_T *entry)
+{
+ ga_clear(&entry->wq_ga);
+ wq->wq_next = entry->wq_next;
+ if (wq->wq_next == NULL)
+ wq->wq_prev = NULL;
+ else
+ wq->wq_next->wq_prev = NULL;
+ vim_free(entry);
+}
+
+/*
+ * Clear the read buffer on "channel"/"part".
+ */
+ static void
+channel_clear_one(channel_T *channel, ch_part_T part)
+{
+ chanpart_T *ch_part = &channel->ch_part[part];
+ jsonq_T *json_head = &ch_part->ch_json_head;
+ cbq_T *cb_head = &ch_part->ch_cb_head;
+
+ while (channel_peek(channel, part) != NULL)
+ vim_free(channel_get(channel, part, NULL));
+
+ while (cb_head->cq_next != NULL)
+ {
+ cbq_T *node = cb_head->cq_next;
+
+ remove_cb_node(cb_head, node);
+ free_callback(node->cq_callback, node->cq_partial);
+ vim_free(node);
+ }
+
+ while (json_head->jq_next != NULL)
+ {
+ free_tv(json_head->jq_next->jq_value);
+ remove_json_node(json_head, json_head->jq_next);
+ }
+
+ free_callback(ch_part->ch_callback, ch_part->ch_partial);
+ ch_part->ch_callback = NULL;
+ ch_part->ch_partial = NULL;
+
+ while (ch_part->ch_writeque.wq_next != NULL)
+ remove_from_writeque(&ch_part->ch_writeque,
+ ch_part->ch_writeque.wq_next);
+}
+
+/*
+ * Clear all the read buffers on "channel".
+ */
+ void
+channel_clear(channel_T *channel)
+{
+ ch_log(channel, "Clearing channel");
+ VIM_CLEAR(channel->ch_hostname);
+ channel_clear_one(channel, PART_SOCK);
+ channel_clear_one(channel, PART_OUT);
+ channel_clear_one(channel, PART_ERR);
+ channel_clear_one(channel, PART_IN);
+ free_callback(channel->ch_callback, channel->ch_partial);
+ channel->ch_callback = NULL;
+ channel->ch_partial = NULL;
+ free_callback(channel->ch_close_cb, channel->ch_close_partial);
+ channel->ch_close_cb = NULL;
+ channel->ch_close_partial = NULL;
+}
+
+#if defined(EXITFREE) || defined(PROTO)
+ void
+channel_free_all(void)
+{
+ channel_T *channel;
+
+ ch_log(NULL, "channel_free_all()");
+ for (channel = first_channel; channel != NULL; channel = channel->ch_next)
+ channel_clear(channel);
+}
+#endif
+
+
+/* Sent when the netbeans channel is found closed when reading. */
+#define DETACH_MSG_RAW "DETACH\n"
+
+/* Buffer size for reading incoming messages. */
+#define MAXMSGSIZE 4096
+
+#if defined(HAVE_SELECT)
+/*
+ * Add write fds where we are waiting for writing to be possible.
+ */
+ static int
+channel_fill_wfds(int maxfd_arg, fd_set *wfds)
+{
+ int maxfd = maxfd_arg;
+ channel_T *ch;
+
+ for (ch = first_channel; ch != NULL; ch = ch->ch_next)
+ {
+ chanpart_T *in_part = &ch->ch_part[PART_IN];
+
+ if (in_part->ch_fd != INVALID_FD
+ && (in_part->ch_bufref.br_buf != NULL
+ || in_part->ch_writeque.wq_next != NULL))
+ {
+ FD_SET((int)in_part->ch_fd, wfds);
+ if ((int)in_part->ch_fd >= maxfd)
+ maxfd = (int)in_part->ch_fd + 1;
+ }
+ }
+ return maxfd;
+}
+#else
+/*
+ * Add write fds where we are waiting for writing to be possible.
+ */
+ static int
+channel_fill_poll_write(int nfd_in, struct pollfd *fds)
+{
+ int nfd = nfd_in;
+ channel_T *ch;
+
+ for (ch = first_channel; ch != NULL; ch = ch->ch_next)
+ {
+ chanpart_T *in_part = &ch->ch_part[PART_IN];
+
+ if (in_part->ch_fd != INVALID_FD
+ && (in_part->ch_bufref.br_buf != NULL
+ || in_part->ch_writeque.wq_next != NULL))
+ {
+ in_part->ch_poll_idx = nfd;
+ fds[nfd].fd = in_part->ch_fd;
+ fds[nfd].events = POLLOUT;
+ ++nfd;
+ }
+ else
+ in_part->ch_poll_idx = -1;
+ }
+ return nfd;
+}
+#endif
+
+typedef enum {
+ CW_READY,
+ CW_NOT_READY,
+ CW_ERROR
+} channel_wait_result;
+
+/*
+ * Check for reading from "fd" with "timeout" msec.
+ * Return CW_READY when there is something to read.
+ * Return CW_NOT_READY when there is nothing to read.
+ * Return CW_ERROR when there is an error.
+ */
+ static channel_wait_result
+channel_wait(channel_T *channel, sock_T fd, int timeout)
+{
+ if (timeout > 0)
+ ch_log(channel, "Waiting for up to %d msec", timeout);
+
+# ifdef WIN32
+ if (fd != channel->CH_SOCK_FD)
+ {
+ DWORD nread;
+ int sleep_time;
+ DWORD deadline = GetTickCount() + timeout;
+ int delay = 1;
+
+ /* reading from a pipe, not a socket */
+ while (TRUE)
+ {
+ int r = PeekNamedPipe((HANDLE)fd, NULL, 0, NULL, &nread, NULL);
+
+ if (r && nread > 0)
+ return CW_READY;
+
+ if (channel->ch_named_pipe)
+ {
+ DisconnectNamedPipe((HANDLE)fd);
+ ConnectNamedPipe((HANDLE)fd, NULL);
+ }
+ else if (r == 0)
+ return CW_ERROR;
+
+ /* perhaps write some buffer lines */
+ channel_write_any_lines();
+
+ sleep_time = deadline - GetTickCount();
+ if (sleep_time <= 0)
+ break;
+ /* Wait for a little while. Very short at first, up to 10 msec
+ * after looping a few times. */
+ if (sleep_time > delay)
+ sleep_time = delay;
+ Sleep(sleep_time);
+ delay = delay * 2;
+ if (delay > 10)
+ delay = 10;
+ }
+ }
+ else
+#endif
+ {
+#if defined(HAVE_SELECT)
+ struct timeval tval;
+ fd_set rfds;
+ fd_set wfds;
+ int ret;
+ int maxfd;
+
+ tval.tv_sec = timeout / 1000;
+ tval.tv_usec = (timeout % 1000) * 1000;
+ for (;;)
+ {
+ FD_ZERO(&rfds);
+ FD_SET((int)fd, &rfds);
+
+ /* Write lines to a pipe when a pipe can be written to. Need to
+ * set this every time, some buffers may be done. */
+ maxfd = (int)fd + 1;
+ FD_ZERO(&wfds);
+ maxfd = channel_fill_wfds(maxfd, &wfds);
+
+ ret = select(maxfd, &rfds, &wfds, NULL, &tval);
+# ifdef EINTR
+ SOCK_ERRNO;
+ if (ret == -1 && errno == EINTR)
+ continue;
+# endif
+ if (ret > 0)
+ {
+ if (FD_ISSET(fd, &rfds))
+ return CW_READY;
+ channel_write_any_lines();
+ continue;
+ }
+ break;
+ }
+#else
+ for (;;)
+ {
+ struct pollfd fds[MAX_OPEN_CHANNELS + 1];
+ int nfd = 1;
+
+ fds[0].fd = fd;
+ fds[0].events = POLLIN;
+ nfd = channel_fill_poll_write(nfd, fds);
+ if (poll(fds, nfd, timeout) > 0)
+ {
+ if (fds[0].revents & POLLIN)
+ return CW_READY;
+ channel_write_any_lines();
+ continue;
+ }
+ break;
+ }
+#endif
+ }
+ return CW_NOT_READY;
+}
+
+ static void
+ch_close_part_on_error(
+ channel_T *channel, ch_part_T part, int is_err, char *func)
+{
+ char msg[] = "%s(): Read %s from ch_part[%d], closing";
+
+ if (is_err)
+ /* Do not call emsg(), most likely the other end just exited. */
+ ch_error(channel, msg, func, "error", part);
+ else
+ ch_log(channel, msg, func, "EOF", part);
+
+ /* Queue a "DETACH" netbeans message in the command queue in order to
+ * terminate the netbeans session later. Do not end the session here
+ * directly as we may be running in the context of a call to
+ * netbeans_parse_messages():
+ * netbeans_parse_messages
+ * -> autocmd triggered while processing the netbeans cmd
+ * -> ui_breakcheck
+ * -> gui event loop or select loop
+ * -> channel_read()
+ * Only send "DETACH" for a netbeans channel.
+ */
+ if (channel->ch_nb_close_cb != NULL)
+ channel_save(channel, PART_SOCK, (char_u *)DETACH_MSG_RAW,
+ (int)STRLEN(DETACH_MSG_RAW), FALSE, "PUT ");
+
+ /* When reading is not possible close this part of the channel. Don't
+ * close the channel yet, there may be something to read on another part.
+ * When stdout and stderr use the same FD we get the error only on one of
+ * them, also close the other. */
+ if (part == PART_OUT || part == PART_ERR)
+ {
+ ch_part_T other = part == PART_OUT ? PART_ERR : PART_OUT;
+
+ if (channel->ch_part[part].ch_fd == channel->ch_part[other].ch_fd)
+ ch_close_part(channel, other);
+ }
+ ch_close_part(channel, part);
+
+#ifdef FEAT_GUI
+ /* Stop listening to GUI events right away. */
+ channel_gui_unregister_one(channel, part);
+#endif
+}
+
+ static void
+channel_close_now(channel_T *channel)
+{
+ ch_log(channel, "Closing channel because all readable fds are closed");
+ if (channel->ch_nb_close_cb != NULL)
+ (*channel->ch_nb_close_cb)();
+ channel_close(channel, TRUE);
+}
+
+/*
+ * Read from channel "channel" for as long as there is something to read.
+ * "part" is PART_SOCK, PART_OUT or PART_ERR.
+ * The data is put in the read queue. No callbacks are invoked here.
+ */
+ static void
+channel_read(channel_T *channel, ch_part_T part, char *func)
+{
+ static char_u *buf = NULL;
+ int len = 0;
+ int readlen = 0;
+ sock_T fd;
+ int use_socket = FALSE;
+
+ fd = channel->ch_part[part].ch_fd;
+ if (fd == INVALID_FD)
+ {
+ ch_error(channel, "channel_read() called while %s part is closed",
+ part_names[part]);
+ return;
+ }
+ use_socket = fd == channel->CH_SOCK_FD;
+
+ /* Allocate a buffer to read into. */
+ if (buf == NULL)
+ {
+ buf = alloc(MAXMSGSIZE);
+ if (buf == NULL)
+ return; /* out of memory! */
+ }
+
+ /* Keep on reading for as long as there is something to read.
+ * Use select() or poll() to avoid blocking on a message that is exactly
+ * MAXMSGSIZE long. */
+ for (;;)
+ {
+ if (channel_wait(channel, fd, 0) != CW_READY)
+ break;
+ if (use_socket)
+ len = sock_read(fd, (char *)buf, MAXMSGSIZE);
+ else
+ len = fd_read(fd, (char *)buf, MAXMSGSIZE);
+ if (len <= 0)
+ break; /* error or nothing more to read */
+
+ /* Store the read message in the queue. */
+ channel_save(channel, part, buf, len, FALSE, "RECV ");
+ readlen += len;
+ if (len < MAXMSGSIZE)
+ break; /* did read everything that's available */
+ }
+
+ /* Reading a disconnection (readlen == 0), or an error. */
+ if (readlen <= 0)
+ {
+ if (!channel->ch_keep_open)
+ ch_close_part_on_error(channel, part, (len < 0), func);
+ }
+#if defined(CH_HAS_GUI) && defined(FEAT_GUI_GTK)
+ else if (CH_HAS_GUI && gtk_main_level() > 0)
+ /* signal the main loop that there is something to read */
+ gtk_main_quit();
+#endif
+}
+
+/*
+ * Read from RAW or NL "channel"/"part". Blocks until there is something to
+ * read or the timeout expires.
+ * When "raw" is TRUE don't block waiting on a NL.
+ * Returns what was read in allocated memory.
+ * Returns NULL in case of error or timeout.
+ */
+ static char_u *
+channel_read_block(
+ channel_T *channel, ch_part_T part, int timeout, int raw, int *outlen)
+{
+ char_u *buf;
+ char_u *msg;
+ ch_mode_T mode = channel->ch_part[part].ch_mode;
+ sock_T fd = channel->ch_part[part].ch_fd;
+ char_u *nl;
+ readq_T *node;
+
+ ch_log(channel, "Blocking %s read, timeout: %d msec",
+ mode == MODE_RAW ? "RAW" : "NL", timeout);
+
+ while (TRUE)
+ {
+ node = channel_peek(channel, part);
+ if (node != NULL)
+ {
+ if (mode == MODE_RAW || (mode == MODE_NL
+ && channel_first_nl(node) != NULL))
+ /* got a complete message */
+ break;
+ if (channel_collapse(channel, part, mode == MODE_NL) == OK)
+ continue;
+ /* If not blocking or nothing more is coming then return what we
+ * have. */
+ if (raw || fd == INVALID_FD)
+ break;
+ }
+
+ /* Wait for up to the channel timeout. */
+ if (fd == INVALID_FD)
+ return NULL;
+ if (channel_wait(channel, fd, timeout) != CW_READY)
+ {
+ ch_log(channel, "Timed out");
+ return NULL;
+ }
+ channel_read(channel, part, "channel_read_block");
+ }
+
+ /* We have a complete message now. */
+ if (mode == MODE_RAW || outlen != NULL)
+ {
+ msg = channel_get_all(channel, part, outlen);
+ }
+ else
+ {
+ char_u *p;
+
+ buf = node->rq_buffer;
+ nl = channel_first_nl(node);
+
+ /* Convert NUL to NL, the internal representation. */
+ for (p = buf; (nl == NULL || p < nl) && p < buf + node->rq_buflen; ++p)
+ if (*p == NUL)
+ *p = NL;
+
+ if (nl == NULL)
+ {
+ /* must be a closed channel with missing NL */
+ msg = channel_get(channel, part, NULL);
+ }
+ else if (nl + 1 == buf + node->rq_buflen)
+ {
+ /* get the whole buffer */
+ msg = channel_get(channel, part, NULL);
+ *nl = NUL;
+ }
+ else
+ {
+ /* Copy the message into allocated memory and remove it from the
+ * buffer. */
+ msg = vim_strnsave(buf, (int)(nl - buf));
+ channel_consume(channel, part, (int)(nl - buf) + 1);
+ }
+ }
+ if (ch_log_active())
+ ch_log(channel, "Returning %d bytes", (int)STRLEN(msg));
+ return msg;
+}
+
+/*
+ * Read one JSON message with ID "id" from "channel"/"part" and store the
+ * result in "rettv".
+ * When "id" is -1 accept any message;
+ * Blocks until the message is received or the timeout is reached.
+ */
+ static int
+channel_read_json_block(
+ channel_T *channel,
+ ch_part_T part,
+ int timeout_arg,
+ int id,
+ typval_T **rettv)
+{
+ int more;
+ sock_T fd;
+ int timeout;
+ chanpart_T *chanpart = &channel->ch_part[part];
+
+ ch_log(channel, "Reading JSON");
+ if (id != -1)
+ chanpart->ch_block_id = id;
+ for (;;)
+ {
+ more = channel_parse_json(channel, part);
+
+ /* search for message "id" */
+ if (channel_get_json(channel, part, id, TRUE, rettv) == OK)
+ {
+ chanpart->ch_block_id = 0;
+ return OK;
+ }
+
+ if (!more)
+ {
+ /* Handle any other messages in the queue. If done some more
+ * messages may have arrived. */
+ if (channel_parse_messages())
+ continue;
+
+ /* Wait for up to the timeout. If there was an incomplete message
+ * use the deadline for that. */
+ timeout = timeout_arg;
+ if (chanpart->ch_wait_len > 0)
+ {
+#ifdef WIN32
+ timeout = chanpart->ch_deadline - GetTickCount() + 1;
+#else
+ {
+ struct timeval now_tv;
+
+ gettimeofday(&now_tv, NULL);
+ timeout = (chanpart->ch_deadline.tv_sec
+ - now_tv.tv_sec) * 1000
+ + (chanpart->ch_deadline.tv_usec
+ - now_tv.tv_usec) / 1000
+ + 1;
+ }
+#endif
+ if (timeout < 0)
+ {
+ /* Something went wrong, channel_parse_json() didn't
+ * discard message. Cancel waiting. */
+ chanpart->ch_wait_len = 0;
+ timeout = timeout_arg;
+ }
+ else if (timeout > timeout_arg)
+ timeout = timeout_arg;
+ }
+ fd = chanpart->ch_fd;
+ if (fd == INVALID_FD
+ || channel_wait(channel, fd, timeout) != CW_READY)
+ {
+ if (timeout == timeout_arg)
+ {
+ if (fd != INVALID_FD)
+ ch_log(channel, "Timed out");
+ break;
+ }
+ }
+ else
+ channel_read(channel, part, "channel_read_json_block");
+ }
+ }
+ chanpart->ch_block_id = 0;
+ return FAIL;
+}
+
+/*
+ * Common for ch_read() and ch_readraw().
+ */
+ void
+common_channel_read(typval_T *argvars, typval_T *rettv, int raw, int blob)
+{
+ channel_T *channel;
+ ch_part_T part = PART_COUNT;
+ jobopt_T opt;
+ int mode;
+ int timeout;
+ int id = -1;
+ typval_T *listtv = NULL;
+
+ /* return an empty string by default */
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+
+ clear_job_options(&opt);
+ if (get_job_options(&argvars[1], &opt, JO_TIMEOUT + JO_PART + JO_ID, 0)
+ == FAIL)
+ goto theend;
+
+ if (opt.jo_set & JO_PART)
+ part = opt.jo_part;
+ channel = get_channel_arg(&argvars[0], TRUE, TRUE, part);
+ if (channel != NULL)
+ {
+ if (part == PART_COUNT)
+ part = channel_part_read(channel);
+ mode = channel_get_mode(channel, part);
+ timeout = channel_get_timeout(channel, part);
+ if (opt.jo_set & JO_TIMEOUT)
+ timeout = opt.jo_timeout;
+
+ if (blob)
+ {
+ int outlen = 0;
+ char_u *p = channel_read_block(channel, part,
+ timeout, TRUE, &outlen);
+ if (p != NULL)
+ {
+ blob_T *b = blob_alloc();
+
+ if (b != NULL)
+ {
+ b->bv_ga.ga_len = outlen;
+ if (ga_grow(&b->bv_ga, outlen) == FAIL)
+ blob_free(b);
+ else
+ {
+ memcpy(b->bv_ga.ga_data, p, outlen);
+ rettv_blob_set(rettv, b);
+ }
+ }
+ vim_free(p);
+ }
+ }
+ else if (raw || mode == MODE_RAW || mode == MODE_NL)
+ rettv->vval.v_string = channel_read_block(channel, part,
+ timeout, raw, NULL);
+ else
+ {
+ if (opt.jo_set & JO_ID)
+ id = opt.jo_id;
+ channel_read_json_block(channel, part, timeout, id, &listtv);
+ if (listtv != NULL)
+ {
+ *rettv = *listtv;
+ vim_free(listtv);
+ }
+ else
+ {
+ rettv->v_type = VAR_SPECIAL;
+ rettv->vval.v_number = VVAL_NONE;
+ }
+ }
+ }
+
+theend:
+ free_job_options(&opt);
+}
+
+# if defined(WIN32) || defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK) \
+ || defined(PROTO)
+/*
+ * Lookup the channel from the socket. Set "partp" to the fd index.
+ * Returns NULL when the socket isn't found.
+ */
+ channel_T *
+channel_fd2channel(sock_T fd, ch_part_T *partp)
+{
+ channel_T *channel;
+ ch_part_T part;
+
+ if (fd != INVALID_FD)
+ for (channel = first_channel; channel != NULL;
+ channel = channel->ch_next)
+ {
+ for (part = PART_SOCK; part < PART_IN; ++part)
+ if (channel->ch_part[part].ch_fd == fd)
+ {
+ *partp = part;
+ return channel;
+ }
+ }
+ return NULL;
+}
+# endif
+
+# if defined(WIN32) || defined(FEAT_GUI) || defined(PROTO)
+/*
+ * Check the channels for anything that is ready to be read.
+ * The data is put in the read queue.
+ * if "only_keep_open" is TRUE only check channels where ch_keep_open is set.
+ */
+ void
+channel_handle_events(int only_keep_open)
+{
+ channel_T *channel;
+ ch_part_T part;
+ sock_T fd;
+
+ for (channel = first_channel; channel != NULL; channel = channel->ch_next)
+ {
+ if (only_keep_open && !channel->ch_keep_open)
+ continue;
+
+ /* check the socket and pipes */
+ for (part = PART_SOCK; part < PART_IN; ++part)
+ {
+ fd = channel->ch_part[part].ch_fd;
+ if (fd != INVALID_FD)
+ {
+ int r = channel_wait(channel, fd, 0);
+
+ if (r == CW_READY)
+ channel_read(channel, part, "channel_handle_events");
+ else if (r == CW_ERROR)
+ ch_close_part_on_error(channel, part, TRUE,
+ "channel_handle_events");
+ }
+ }
+ }
+}
+# endif
+
+# if defined(FEAT_GUI) || defined(PROTO)
+/*
+ * Return TRUE when there is any channel with a keep_open flag.
+ */
+ int
+channel_any_keep_open()
+{
+ channel_T *channel;
+
+ for (channel = first_channel; channel != NULL; channel = channel->ch_next)
+ if (channel->ch_keep_open)
+ return TRUE;
+ return FALSE;
+}
+# endif
+
+/*
+ * Set "channel"/"part" to non-blocking.
+ * Only works for sockets and pipes.
+ */
+ void
+channel_set_nonblock(channel_T *channel, ch_part_T part)
+{
+ chanpart_T *ch_part = &channel->ch_part[part];
+ int fd = ch_part->ch_fd;
+
+ if (fd != INVALID_FD)
+ {
+#ifdef _WIN32
+ u_long val = 1;
+
+ ioctlsocket(fd, FIONBIO, &val);
+#else
+ (void)fcntl(fd, F_SETFL, O_NONBLOCK);
+#endif
+ ch_part->ch_nonblocking = TRUE;
+ }
+}
+
+/*
+ * Write "buf" (NUL terminated string) to "channel"/"part".
+ * When "fun" is not NULL an error message might be given.
+ * Return FAIL or OK.
+ */
+ int
+channel_send(
+ channel_T *channel,
+ ch_part_T part,
+ char_u *buf_arg,
+ int len_arg,
+ char *fun)
+{
+ int res;
+ sock_T fd;
+ chanpart_T *ch_part = &channel->ch_part[part];
+ int did_use_queue = FALSE;
+
+ fd = ch_part->ch_fd;
+ if (fd == INVALID_FD)
+ {
+ if (!channel->ch_error && fun != NULL)
+ {
+ ch_error(channel, "%s(): write while not connected", fun);
+ semsg(_("E630: %s(): write while not connected"), fun);
+ }
+ channel->ch_error = TRUE;
+ return FAIL;
+ }
+
+ if (channel->ch_nonblock && !ch_part->ch_nonblocking)
+ channel_set_nonblock(channel, part);
+
+ if (ch_log_active())
+ {
+ ch_log_lead("SEND ", channel, part);
+ fprintf(log_fd, "'");
+ vim_ignored = (int)fwrite(buf_arg, len_arg, 1, log_fd);
+ fprintf(log_fd, "'\n");
+ fflush(log_fd);
+ did_log_msg = TRUE;
+ }
+
+ for (;;)
+ {
+ writeq_T *wq = &ch_part->ch_writeque;
+ char_u *buf;
+ int len;
+
+ if (wq->wq_next != NULL)
+ {
+ /* first write what was queued */
+ buf = wq->wq_next->wq_ga.ga_data;
+ len = wq->wq_next->wq_ga.ga_len;
+ did_use_queue = TRUE;
+ }
+ else
+ {
+ if (len_arg == 0)
+ /* nothing to write, called from channel_select_check() */
+ return OK;
+ buf = buf_arg;
+ len = len_arg;
+ }
+
+ if (part == PART_SOCK)
+ res = sock_write(fd, (char *)buf, len);
+ else
+ {
+ res = fd_write(fd, (char *)buf, len);
+#ifdef WIN32
+ if (channel->ch_named_pipe && res < 0)
+ {
+ DisconnectNamedPipe((HANDLE)fd);
+ ConnectNamedPipe((HANDLE)fd, NULL);
+ }
+#endif
+ }
+ if (res < 0 && (errno == EWOULDBLOCK
+#ifdef EAGAIN
+ || errno == EAGAIN
+#endif
+ ))
+ res = 0; /* nothing got written */
+
+ if (res >= 0 && ch_part->ch_nonblocking)
+ {
+ writeq_T *entry = wq->wq_next;
+
+ if (did_use_queue)
+ ch_log(channel, "Sent %d bytes now", res);
+ if (res == len)
+ {
+ /* Wrote all the buf[len] bytes. */
+ if (entry != NULL)
+ {
+ /* Remove the entry from the write queue. */
+ remove_from_writeque(wq, entry);
+ continue;
+ }
+ if (did_use_queue)
+ ch_log(channel, "Write queue empty");
+ }
+ else
+ {
+ /* Wrote only buf[res] bytes, can't write more now. */
+ if (entry != NULL)
+ {
+ if (res > 0)
+ {
+ /* Remove the bytes that were written. */
+ mch_memmove(entry->wq_ga.ga_data,
+ (char *)entry->wq_ga.ga_data + res,
+ len - res);
+ entry->wq_ga.ga_len -= res;
+ }
+ buf = buf_arg;
+ len = len_arg;
+ }
+ else
+ {
+ buf += res;
+ len -= res;
+ }
+ ch_log(channel, "Adding %d bytes to the write queue", len);
+
+ /* Append the not written bytes of the argument to the write
+ * buffer. Limit entries to 4000 bytes. */
+ if (wq->wq_prev != NULL
+ && wq->wq_prev->wq_ga.ga_len + len < 4000)
+ {
+ writeq_T *last = wq->wq_prev;
+
+ /* append to the last entry */
+ if (ga_grow(&last->wq_ga, len) == OK)
+ {
+ mch_memmove((char *)last->wq_ga.ga_data
+ + last->wq_ga.ga_len,
+ buf, len);
+ last->wq_ga.ga_len += len;
+ }
+ }
+ else
+ {
+ writeq_T *last = (writeq_T *)alloc((int)sizeof(writeq_T));
+
+ if (last != NULL)
+ {
+ last->wq_prev = wq->wq_prev;
+ last->wq_next = NULL;
+ if (wq->wq_prev == NULL)
+ wq->wq_next = last;
+ else
+ wq->wq_prev->wq_next = last;
+ wq->wq_prev = last;
+ ga_init2(&last->wq_ga, 1, 1000);
+ if (ga_grow(&last->wq_ga, len) == OK)
+ {
+ mch_memmove(last->wq_ga.ga_data, buf, len);
+ last->wq_ga.ga_len = len;
+ }
+ }
+ }
+ }
+ }
+ else if (res != len)
+ {
+ if (!channel->ch_error && fun != NULL)
+ {
+ ch_error(channel, "%s(): write failed", fun);
+ semsg(_("E631: %s(): write failed"), fun);
+ }
+ channel->ch_error = TRUE;
+ return FAIL;
+ }
+
+ channel->ch_error = FALSE;
+ return OK;
+ }
+}
+
+/*
+ * Common for "ch_sendexpr()" and "ch_sendraw()".
+ * Returns the channel if the caller should read the response.
+ * Sets "part_read" to the read fd.
+ * Otherwise returns NULL.
+ */
+ static channel_T *
+send_common(
+ typval_T *argvars,
+ char_u *text,
+ int len,
+ int id,
+ int eval,
+ jobopt_T *opt,
+ char *fun,
+ ch_part_T *part_read)
+{
+ channel_T *channel;
+ ch_part_T part_send;
+
+ clear_job_options(opt);
+ channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
+ if (channel == NULL)
+ return NULL;
+ part_send = channel_part_send(channel);
+ *part_read = channel_part_read(channel);
+
+ if (get_job_options(&argvars[2], opt, JO_CALLBACK + JO_TIMEOUT, 0) == FAIL)
+ return NULL;
+
+ /* Set the callback. An empty callback means no callback and not reading
+ * the response. With "ch_evalexpr()" and "ch_evalraw()" a callback is not
+ * allowed. */
+ if (opt->jo_callback != NULL && *opt->jo_callback != NUL)
+ {
+ if (eval)
+ {
+ semsg(_("E917: Cannot use a callback with %s()"), fun);
+ return NULL;
+ }
+ channel_set_req_callback(channel, *part_read,
+ opt->jo_callback, opt->jo_partial, id);
+ }
+
+ if (channel_send(channel, part_send, text, len, fun) == OK
+ && opt->jo_callback == NULL)
+ return channel;
+ return NULL;
+}
+
+/*
+ * common for "ch_evalexpr()" and "ch_sendexpr()"
+ */
+ void
+ch_expr_common(typval_T *argvars, typval_T *rettv, int eval)
+{
+ char_u *text;
+ typval_T *listtv;
+ channel_T *channel;
+ int id;
+ ch_mode_T ch_mode;
+ ch_part_T part_send;
+ ch_part_T part_read;
+ jobopt_T opt;
+ int timeout;
+
+ /* return an empty string by default */
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+
+ channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
+ if (channel == NULL)
+ return;
+ part_send = channel_part_send(channel);
+
+ ch_mode = channel_get_mode(channel, part_send);
+ if (ch_mode == MODE_RAW || ch_mode == MODE_NL)
+ {
+ emsg(_("E912: cannot use ch_evalexpr()/ch_sendexpr() with a raw or nl channel"));
+ return;
+ }
+
+ id = ++channel->ch_last_msg_id;
+ text = json_encode_nr_expr(id, &argvars[1],
+ (ch_mode == MODE_JS ? JSON_JS : 0) | JSON_NL);
+ if (text == NULL)
+ return;
+
+ channel = send_common(argvars, text, (int)STRLEN(text), id, eval, &opt,
+ eval ? "ch_evalexpr" : "ch_sendexpr", &part_read);
+ vim_free(text);
+ if (channel != NULL && eval)
+ {
+ if (opt.jo_set & JO_TIMEOUT)
+ timeout = opt.jo_timeout;
+ else
+ timeout = channel_get_timeout(channel, part_read);
+ if (channel_read_json_block(channel, part_read, timeout, id, &listtv)
+ == OK)
+ {
+ list_T *list = listtv->vval.v_list;
+
+ /* Move the item from the list and then change the type to
+ * avoid the value being freed. */
+ *rettv = list->lv_last->li_tv;
+ list->lv_last->li_tv.v_type = VAR_NUMBER;
+ free_tv(listtv);
+ }
+ }
+ free_job_options(&opt);
+}
+
+/*
+ * common for "ch_evalraw()" and "ch_sendraw()"
+ */
+ void
+ch_raw_common(typval_T *argvars, typval_T *rettv, int eval)
+{
+ char_u buf[NUMBUFLEN];
+ char_u *text;
+ int len;
+ channel_T *channel;
+ ch_part_T part_read;
+ jobopt_T opt;
+ int timeout;
+
+ /* return an empty string by default */
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+
+ if (argvars[1].v_type == VAR_BLOB)
+ {
+ text = argvars[1].vval.v_blob->bv_ga.ga_data;
+ len = argvars[1].vval.v_blob->bv_ga.ga_len;
+ }
+ else
+ {
+ text = tv_get_string_buf(&argvars[1], buf);
+ len = (int)STRLEN(text);
+ }
+ channel = send_common(argvars, text, len, 0, eval, &opt,
+ eval ? "ch_evalraw" : "ch_sendraw", &part_read);
+ if (channel != NULL && eval)
+ {
+ if (opt.jo_set & JO_TIMEOUT)
+ timeout = opt.jo_timeout;
+ else
+ timeout = channel_get_timeout(channel, part_read);
+ rettv->vval.v_string = channel_read_block(channel, part_read,
+ timeout, TRUE, NULL);
+ }
+ free_job_options(&opt);
+}
+
+# define KEEP_OPEN_TIME 20 /* msec */
+
+# if (defined(UNIX) && !defined(HAVE_SELECT)) || defined(PROTO)
+/*
+ * Add open channels to the poll struct.
+ * Return the adjusted struct index.
+ * The type of "fds" is hidden to avoid problems with the function proto.
+ */
+ int
+channel_poll_setup(int nfd_in, void *fds_in, int *towait)
+{
+ int nfd = nfd_in;
+ channel_T *channel;
+ struct pollfd *fds = fds_in;
+ ch_part_T part;
+
+ for (channel = first_channel; channel != NULL; channel = channel->ch_next)
+ {
+ for (part = PART_SOCK; part < PART_IN; ++part)
+ {
+ chanpart_T *ch_part = &channel->ch_part[part];
+
+ if (ch_part->ch_fd != INVALID_FD)
+ {
+ if (channel->ch_keep_open)
+ {
+ /* For unknown reason poll() returns immediately for a
+ * keep-open channel. Instead of adding it to the fds add
+ * a short timeout and check, like polling. */
+ if (*towait < 0 || *towait > KEEP_OPEN_TIME)
+ *towait = KEEP_OPEN_TIME;
+ }
+ else
+ {
+ ch_part->ch_poll_idx = nfd;
+ fds[nfd].fd = ch_part->ch_fd;
+ fds[nfd].events = POLLIN;
+ nfd++;
+ }
+ }
+ else
+ channel->ch_part[part].ch_poll_idx = -1;
+ }
+ }
+
+ nfd = channel_fill_poll_write(nfd, fds);
+
+ return nfd;
+}
+
+/*
+ * The type of "fds" is hidden to avoid problems with the function proto.
+ */
+ int
+channel_poll_check(int ret_in, void *fds_in)
+{
+ int ret = ret_in;
+ channel_T *channel;
+ struct pollfd *fds = fds_in;
+ ch_part_T part;
+ int idx;
+ chanpart_T *in_part;
+
+ for (channel = first_channel; channel != NULL; channel = channel->ch_next)
+ {
+ for (part = PART_SOCK; part < PART_IN; ++part)
+ {
+ idx = channel->ch_part[part].ch_poll_idx;
+
+ if (ret > 0 && idx != -1 && (fds[idx].revents & POLLIN))
+ {
+ channel_read(channel, part, "channel_poll_check");
+ --ret;
+ }
+ else if (channel->ch_part[part].ch_fd != INVALID_FD
+ && channel->ch_keep_open)
+ {
+ /* polling a keep-open channel */
+ channel_read(channel, part, "channel_poll_check_keep_open");
+ }
+ }
+
+ in_part = &channel->ch_part[PART_IN];
+ idx = in_part->ch_poll_idx;
+ if (ret > 0 && idx != -1 && (fds[idx].revents & POLLOUT))
+ {
+ channel_write_input(channel);
+ --ret;
+ }
+ }
+
+ return ret;
+}
+# endif /* UNIX && !HAVE_SELECT */
+
+# if (!defined(WIN32) && defined(HAVE_SELECT)) || defined(PROTO)
+
+/*
+ * The "fd_set" type is hidden to avoid problems with the function proto.
+ */
+ int
+channel_select_setup(
+ int maxfd_in,
+ void *rfds_in,
+ void *wfds_in,
+ struct timeval *tv,
+ struct timeval **tvp)
+{
+ int maxfd = maxfd_in;
+ channel_T *channel;
+ fd_set *rfds = rfds_in;
+ fd_set *wfds = wfds_in;
+ ch_part_T part;
+
+ for (channel = first_channel; channel != NULL; channel = channel->ch_next)
+ {
+ for (part = PART_SOCK; part < PART_IN; ++part)
+ {
+ sock_T fd = channel->ch_part[part].ch_fd;
+
+ if (fd != INVALID_FD)
+ {
+ if (channel->ch_keep_open)
+ {
+ /* For unknown reason select() returns immediately for a
+ * keep-open channel. Instead of adding it to the rfds add
+ * a short timeout and check, like polling. */
+ if (*tvp == NULL || tv->tv_sec > 0
+ || tv->tv_usec > KEEP_OPEN_TIME * 1000)
+ {
+ *tvp = tv;
+ tv->tv_sec = 0;
+ tv->tv_usec = KEEP_OPEN_TIME * 1000;
+ }
+ }
+ else
+ {
+ FD_SET((int)fd, rfds);
+ if (maxfd < (int)fd)
+ maxfd = (int)fd;
+ }
+ }
+ }
+ }
+
+ maxfd = channel_fill_wfds(maxfd, wfds);
+
+ return maxfd;
+}
+
+/*
+ * The "fd_set" type is hidden to avoid problems with the function proto.
+ */
+ int
+channel_select_check(int ret_in, void *rfds_in, void *wfds_in)
+{
+ int ret = ret_in;
+ channel_T *channel;
+ fd_set *rfds = rfds_in;
+ fd_set *wfds = wfds_in;
+ ch_part_T part;
+ chanpart_T *in_part;
+
+ for (channel = first_channel; channel != NULL; channel = channel->ch_next)
+ {
+ for (part = PART_SOCK; part < PART_IN; ++part)
+ {
+ sock_T fd = channel->ch_part[part].ch_fd;
+
+ if (ret > 0 && fd != INVALID_FD && FD_ISSET(fd, rfds))
+ {
+ channel_read(channel, part, "channel_select_check");
+ FD_CLR(fd, rfds);
+ --ret;
+ }
+ else if (fd != INVALID_FD && channel->ch_keep_open)
+ {
+ /* polling a keep-open channel */
+ channel_read(channel, part, "channel_select_check_keep_open");
+ }
+ }
+
+ in_part = &channel->ch_part[PART_IN];
+ if (ret > 0 && in_part->ch_fd != INVALID_FD
+ && FD_ISSET(in_part->ch_fd, wfds))
+ {
+ /* Clear the flag first, ch_fd may change in channel_write_input(). */
+ FD_CLR(in_part->ch_fd, wfds);
+ channel_write_input(channel);
+ --ret;
+ }
+ }
+
+ return ret;
+}
+# endif /* !WIN32 && HAVE_SELECT */
+
+/*
+ * Execute queued up commands.
+ * Invoked from the main loop when it's safe to execute received commands.
+ * Return TRUE when something was done.
+ */
+ int
+channel_parse_messages(void)
+{
+ channel_T *channel = first_channel;
+ int ret = FALSE;
+ int r;
+ ch_part_T part = PART_SOCK;
+#ifdef ELAPSED_FUNC
+ elapsed_T start_tv;
+
+ ELAPSED_INIT(start_tv);
+#endif
+
+ ++safe_to_invoke_callback;
+
+ /* Only do this message when another message was given, otherwise we get
+ * lots of them. */
+ if (did_log_msg)
+ {
+ ch_log(NULL, "looking for messages on channels");
+ did_log_msg = FALSE;
+ }
+ while (channel != NULL)
+ {
+ if (channel_can_close(channel))
+ {
+ channel->ch_to_be_closed = (1U << PART_COUNT);
+ channel_close_now(channel);
+ /* channel may have been freed, start over */
+ channel = first_channel;
+ continue;
+ }
+ if (channel->ch_to_be_freed || channel->ch_killing)
+ {
+ channel_free(channel);
+ /* channel has been freed, start over */
+ channel = first_channel;
+ continue;
+ }
+ if (channel->ch_refcount == 0 && !channel_still_useful(channel))
+ {
+ /* channel is no longer useful, free it */
+ channel_free(channel);
+ channel = first_channel;
+ part = PART_SOCK;
+ continue;
+ }
+ if (channel->ch_part[part].ch_fd != INVALID_FD
+ || channel_has_readahead(channel, part))
+ {
+ /* Increase the refcount, in case the handler causes the channel
+ * to be unreferenced or closed. */
+ ++channel->ch_refcount;
+ r = may_invoke_callback(channel, part);
+ if (r == OK)
+ ret = TRUE;
+ if (channel_unref(channel) || (r == OK
+#ifdef ELAPSED_FUNC
+ /* Limit the time we loop here to 100 msec, otherwise
+ * Vim becomes unresponsive when the callback takes
+ * more than a bit of time. */
+ && ELAPSED_FUNC(start_tv) < 100L
+#endif
+ ))
+ {
+ /* channel was freed or something was done, start over */
+ channel = first_channel;
+ part = PART_SOCK;
+ continue;
+ }
+ }
+ if (part < PART_ERR)
+ ++part;
+ else
+ {
+ channel = channel->ch_next;
+ part = PART_SOCK;
+ }
+ }
+
+ if (channel_need_redraw)
+ {
+ channel_need_redraw = FALSE;
+ redraw_after_callback(TRUE);
+ }
+
+ --safe_to_invoke_callback;
+
+ return ret;
+}
+
+/*
+ * Return TRUE if any channel has readahead. That means we should not block on
+ * waiting for input.
+ */
+ int
+channel_any_readahead(void)
+{
+ channel_T *channel = first_channel;
+ ch_part_T part = PART_SOCK;
+
+ while (channel != NULL)
+ {
+ if (channel_has_readahead(channel, part))
+ return TRUE;
+ if (part < PART_ERR)
+ ++part;
+ else
+ {
+ channel = channel->ch_next;
+ part = PART_SOCK;
+ }
+ }
+ return FALSE;
+}
+
+/*
+ * Mark references to lists used in channels.
+ */
+ int
+set_ref_in_channel(int copyID)
+{
+ int abort = FALSE;
+ channel_T *channel;
+ typval_T tv;
+
+ for (channel = first_channel; channel != NULL; channel = channel->ch_next)
+ if (channel_still_useful(channel))
+ {
+ tv.v_type = VAR_CHANNEL;
+ tv.vval.v_channel = channel;
+ abort = abort || set_ref_in_item(&tv, copyID, NULL, NULL);
+ }
+ return abort;
+}
+
+/*
+ * Return the "part" to write to for "channel".
+ */
+ ch_part_T
+channel_part_send(channel_T *channel)
+{
+ if (channel->CH_SOCK_FD == INVALID_FD)
+ return PART_IN;
+ return PART_SOCK;
+}
+
+/*
+ * Return the default "part" to read from for "channel".
+ */
+ ch_part_T
+channel_part_read(channel_T *channel)
+{
+ if (channel->CH_SOCK_FD == INVALID_FD)
+ return PART_OUT;
+ return PART_SOCK;
+}
+
+/*
+ * Return the mode of "channel"/"part"
+ * If "channel" is invalid returns MODE_JSON.
+ */
+ ch_mode_T
+channel_get_mode(channel_T *channel, ch_part_T part)
+{
+ if (channel == NULL)
+ return MODE_JSON;
+ return channel->ch_part[part].ch_mode;
+}
+
+/*
+ * Return the timeout of "channel"/"part"
+ */
+ int
+channel_get_timeout(channel_T *channel, ch_part_T part)
+{
+ return channel->ch_part[part].ch_timeout;
+}
+
+ static int
+handle_mode(typval_T *item, jobopt_T *opt, ch_mode_T *modep, int jo)
+{
+ char_u *val = tv_get_string(item);
+
+ opt->jo_set |= jo;
+ if (STRCMP(val, "nl") == 0)
+ *modep = MODE_NL;
+ else if (STRCMP(val, "raw") == 0)
+ *modep = MODE_RAW;
+ else if (STRCMP(val, "js") == 0)
+ *modep = MODE_JS;
+ else if (STRCMP(val, "json") == 0)
+ *modep = MODE_JSON;
+ else
+ {
+ semsg(_(e_invarg2), val);
+ return FAIL;
+ }
+ return OK;
+}
+
+ static int
+handle_io(typval_T *item, ch_part_T part, jobopt_T *opt)
+{
+ char_u *val = tv_get_string(item);
+
+ opt->jo_set |= JO_OUT_IO << (part - PART_OUT);
+ if (STRCMP(val, "null") == 0)
+ opt->jo_io[part] = JIO_NULL;
+ else if (STRCMP(val, "pipe") == 0)
+ opt->jo_io[part] = JIO_PIPE;
+ else if (STRCMP(val, "file") == 0)
+ opt->jo_io[part] = JIO_FILE;
+ else if (STRCMP(val, "buffer") == 0)
+ opt->jo_io[part] = JIO_BUFFER;
+ else if (STRCMP(val, "out") == 0 && part == PART_ERR)
+ opt->jo_io[part] = JIO_OUT;
+ else
+ {
+ semsg(_(e_invarg2), val);
+ return FAIL;
+ }
+ return OK;
+}
+
+/*
+ * Clear a jobopt_T before using it.
+ */
+ void
+clear_job_options(jobopt_T *opt)
+{
+ vim_memset(opt, 0, sizeof(jobopt_T));
+}
+
+/*
+ * Free any members of a jobopt_T.
+ */
+ void
+free_job_options(jobopt_T *opt)
+{
+ if (opt->jo_partial != NULL)
+ partial_unref(opt->jo_partial);
+ else if (opt->jo_callback != NULL)
+ func_unref(opt->jo_callback);
+ if (opt->jo_out_partial != NULL)
+ partial_unref(opt->jo_out_partial);
+ else if (opt->jo_out_cb != NULL)
+ func_unref(opt->jo_out_cb);
+ if (opt->jo_err_partial != NULL)
+ partial_unref(opt->jo_err_partial);
+ else if (opt->jo_err_cb != NULL)
+ func_unref(opt->jo_err_cb);
+ if (opt->jo_close_partial != NULL)
+ partial_unref(opt->jo_close_partial);
+ else if (opt->jo_close_cb != NULL)
+ func_unref(opt->jo_close_cb);
+ if (opt->jo_exit_partial != NULL)
+ partial_unref(opt->jo_exit_partial);
+ else if (opt->jo_exit_cb != NULL)
+ func_unref(opt->jo_exit_cb);
+ if (opt->jo_env != NULL)
+ dict_unref(opt->jo_env);
+}
+
+/*
+ * Get the PART_ number from the first character of an option name.
+ */
+ static int
+part_from_char(int c)
+{
+ return c == 'i' ? PART_IN : c == 'o' ? PART_OUT: PART_ERR;
+}
+
+/*
+ * Get the option entries from the dict in "tv", parse them and put the result
+ * in "opt".
+ * Only accept JO_ options in "supported" and JO2_ options in "supported2".
+ * If an option value is invalid return FAIL.
+ */
+ int
+get_job_options(typval_T *tv, jobopt_T *opt, int supported, int supported2)
+{
+ typval_T *item;
+ char_u *val;
+ dict_T *dict;
+ int todo;
+ hashitem_T *hi;
+ ch_part_T part;
+
+ if (tv->v_type == VAR_UNKNOWN)
+ return OK;
+ if (tv->v_type != VAR_DICT)
+ {
+ emsg(_(e_dictreq));
+ return FAIL;
+ }
+ dict = tv->vval.v_dict;
+ if (dict == NULL)
+ return OK;
+
+ todo = (int)dict->dv_hashtab.ht_used;
+ for (hi = dict->dv_hashtab.ht_array; todo > 0; ++hi)
+ if (!HASHITEM_EMPTY(hi))
+ {
+ item = &dict_lookup(hi)->di_tv;
+
+ if (STRCMP(hi->hi_key, "mode") == 0)
+ {
+ if (!(supported & JO_MODE))
+ break;
+ if (handle_mode(item, opt, &opt->jo_mode, JO_MODE) == FAIL)
+ return FAIL;
+ }
+ else if (STRCMP(hi->hi_key, "in_mode") == 0)
+ {
+ if (!(supported & JO_IN_MODE))
+ break;
+ if (handle_mode(item, opt, &opt->jo_in_mode, JO_IN_MODE)
+ == FAIL)
+ return FAIL;
+ }
+ else if (STRCMP(hi->hi_key, "out_mode") == 0)
+ {
+ if (!(supported & JO_OUT_MODE))
+ break;
+ if (handle_mode(item, opt, &opt->jo_out_mode, JO_OUT_MODE)
+ == FAIL)
+ return FAIL;
+ }
+ else if (STRCMP(hi->hi_key, "err_mode") == 0)
+ {
+ if (!(supported & JO_ERR_MODE))
+ break;
+ if (handle_mode(item, opt, &opt->jo_err_mode, JO_ERR_MODE)
+ == FAIL)
+ return FAIL;
+ }
+ else if (STRCMP(hi->hi_key, "noblock") == 0)
+ {
+ if (!(supported & JO_MODE))
+ break;
+ opt->jo_noblock = tv_get_number(item);
+ }
+ else if (STRCMP(hi->hi_key, "in_io") == 0
+ || STRCMP(hi->hi_key, "out_io") == 0
+ || STRCMP(hi->hi_key, "err_io") == 0)
+ {
+ if (!(supported & JO_OUT_IO))
+ break;
+ if (handle_io(item, part_from_char(*hi->hi_key), opt) == FAIL)
+ return FAIL;
+ }
+ else if (STRCMP(hi->hi_key, "in_name") == 0
+ || STRCMP(hi->hi_key, "out_name") == 0
+ || STRCMP(hi->hi_key, "err_name") == 0)
+ {
+ part = part_from_char(*hi->hi_key);
+
+ if (!(supported & JO_OUT_IO))
+ break;
+ opt->jo_set |= JO_OUT_NAME << (part - PART_OUT);
+ opt->jo_io_name[part] =
+ tv_get_string_buf_chk(item, opt->jo_io_name_buf[part]);
+ }
+ else if (STRCMP(hi->hi_key, "pty") == 0)
+ {
+ if (!(supported & JO_MODE))
+ break;
+ opt->jo_pty = tv_get_number(item);
+ }
+ else if (STRCMP(hi->hi_key, "in_buf") == 0
+ || STRCMP(hi->hi_key, "out_buf") == 0
+ || STRCMP(hi->hi_key, "err_buf") == 0)
+ {
+ part = part_from_char(*hi->hi_key);
+
+ if (!(supported & JO_OUT_IO))
+ break;
+ opt->jo_set |= JO_OUT_BUF << (part - PART_OUT);
+ opt->jo_io_buf[part] = tv_get_number(item);
+ if (opt->jo_io_buf[part] <= 0)
+ {
+ semsg(_(e_invargNval), hi->hi_key, tv_get_string(item));
+ return FAIL;
+ }
+ if (buflist_findnr(opt->jo_io_buf[part]) == NULL)
+ {
+ semsg(_(e_nobufnr), (long)opt->jo_io_buf[part]);
+ return FAIL;
+ }
+ }
+ else if (STRCMP(hi->hi_key, "out_modifiable") == 0
+ || STRCMP(hi->hi_key, "err_modifiable") == 0)
+ {
+ part = part_from_char(*hi->hi_key);
+
+ if (!(supported & JO_OUT_IO))
+ break;
+ opt->jo_set |= JO_OUT_MODIFIABLE << (part - PART_OUT);
+ opt->jo_modifiable[part] = tv_get_number(item);
+ }
+ else if (STRCMP(hi->hi_key, "out_msg") == 0
+ || STRCMP(hi->hi_key, "err_msg") == 0)
+ {
+ part = part_from_char(*hi->hi_key);
+
+ if (!(supported & JO_OUT_IO))
+ break;
+ opt->jo_set2 |= JO2_OUT_MSG << (part - PART_OUT);
+ opt->jo_message[part] = tv_get_number(item);
+ }
+ else if (STRCMP(hi->hi_key, "in_top") == 0
+ || STRCMP(hi->hi_key, "in_bot") == 0)
+ {
+ linenr_T *lp;
+
+ if (!(supported & JO_OUT_IO))
+ break;
+ if (hi->hi_key[3] == 't')
+ {
+ lp = &opt->jo_in_top;
+ opt->jo_set |= JO_IN_TOP;
+ }
+ else
+ {
+ lp = &opt->jo_in_bot;
+ opt->jo_set |= JO_IN_BOT;
+ }
+ *lp = tv_get_number(item);
+ if (*lp < 0)
+ {
+ semsg(_(e_invargNval), hi->hi_key, tv_get_string(item));
+ return FAIL;
+ }
+ }
+ else if (STRCMP(hi->hi_key, "channel") == 0)
+ {
+ if (!(supported & JO_OUT_IO))
+ break;
+ opt->jo_set |= JO_CHANNEL;
+ if (item->v_type != VAR_CHANNEL)
+ {
+ semsg(_(e_invargval), "channel");
+ return FAIL;
+ }
+ opt->jo_channel = item->vval.v_channel;
+ }
+ else if (STRCMP(hi->hi_key, "callback") == 0)
+ {
+ if (!(supported & JO_CALLBACK))
+ break;
+ opt->jo_set |= JO_CALLBACK;
+ opt->jo_callback = get_callback(item, &opt->jo_partial);
+ if (opt->jo_callback == NULL)
+ {
+ semsg(_(e_invargval), "callback");
+ return FAIL;
+ }
+ }
+ else if (STRCMP(hi->hi_key, "out_cb") == 0)
+ {
+ if (!(supported & JO_OUT_CALLBACK))
+ break;
+ opt->jo_set |= JO_OUT_CALLBACK;
+ opt->jo_out_cb = get_callback(item, &opt->jo_out_partial);
+ if (opt->jo_out_cb == NULL)
+ {
+ semsg(_(e_invargval), "out_cb");
+ return FAIL;
+ }
+ }
+ else if (STRCMP(hi->hi_key, "err_cb") == 0)
+ {
+ if (!(supported & JO_ERR_CALLBACK))
+ break;
+ opt->jo_set |= JO_ERR_CALLBACK;
+ opt->jo_err_cb = get_callback(item, &opt->jo_err_partial);
+ if (opt->jo_err_cb == NULL)
+ {
+ semsg(_(e_invargval), "err_cb");
+ return FAIL;
+ }
+ }
+ else if (STRCMP(hi->hi_key, "close_cb") == 0)
+ {
+ if (!(supported & JO_CLOSE_CALLBACK))
+ break;
+ opt->jo_set |= JO_CLOSE_CALLBACK;
+ opt->jo_close_cb = get_callback(item, &opt->jo_close_partial);
+ if (opt->jo_close_cb == NULL)
+ {
+ semsg(_(e_invargval), "close_cb");
+ return FAIL;
+ }
+ }
+ else if (STRCMP(hi->hi_key, "drop") == 0)
+ {
+ int never = FALSE;
+ val = tv_get_string(item);
+
+ if (STRCMP(val, "never") == 0)
+ never = TRUE;
+ else if (STRCMP(val, "auto") != 0)
+ {
+ semsg(_(e_invargNval), "drop", val);
+ return FAIL;
+ }
+ opt->jo_drop_never = never;
+ }
+ else if (STRCMP(hi->hi_key, "exit_cb") == 0)
+ {
+ if (!(supported & JO_EXIT_CB))
+ break;
+ opt->jo_set |= JO_EXIT_CB;
+ opt->jo_exit_cb = get_callback(item, &opt->jo_exit_partial);
+ if (opt->jo_exit_cb == NULL)
+ {
+ semsg(_(e_invargval), "exit_cb");
+ return FAIL;
+ }
+ }
+#ifdef FEAT_TERMINAL
+ else if (STRCMP(hi->hi_key, "term_name") == 0)
+ {
+ if (!(supported2 & JO2_TERM_NAME))
+ break;
+ opt->jo_set2 |= JO2_TERM_NAME;
+ opt->jo_term_name = tv_get_string_chk(item);
+ if (opt->jo_term_name == NULL)
+ {
+ semsg(_(e_invargval), "term_name");
+ return FAIL;
+ }
+ }
+ else if (STRCMP(hi->hi_key, "term_finish") == 0)
+ {
+ if (!(supported2 & JO2_TERM_FINISH))
+ break;
+ val = tv_get_string(item);
+ if (STRCMP(val, "open") != 0 && STRCMP(val, "close") != 0)
+ {
+ semsg(_(e_invargNval), "term_finish", val);
+ return FAIL;
+ }
+ opt->jo_set2 |= JO2_TERM_FINISH;
+ opt->jo_term_finish = *val;
+ }
+ else if (STRCMP(hi->hi_key, "term_opencmd") == 0)
+ {
+ char_u *p;
+
+ if (!(supported2 & JO2_TERM_OPENCMD))
+ break;
+ opt->jo_set2 |= JO2_TERM_OPENCMD;
+ p = opt->jo_term_opencmd = tv_get_string_chk(item);
+ if (p != NULL)
+ {
+ /* Must have %d and no other %. */
+ p = vim_strchr(p, '%');
+ if (p != NULL && (p[1] != 'd'
+ || vim_strchr(p + 2, '%') != NULL))
+ p = NULL;
+ }
+ if (p == NULL)
+ {
+ semsg(_(e_invargval), "term_opencmd");
+ return FAIL;
+ }
+ }
+ else if (STRCMP(hi->hi_key, "eof_chars") == 0)
+ {
+ char_u *p;
+
+ if (!(supported2 & JO2_EOF_CHARS))
+ break;
+ opt->jo_set2 |= JO2_EOF_CHARS;
+ p = opt->jo_eof_chars = tv_get_string_chk(item);
+ if (p == NULL)
+ {
+ semsg(_(e_invargval), "eof_chars");
+ return FAIL;
+ }
+ }
+ else if (STRCMP(hi->hi_key, "term_rows") == 0)
+ {
+ if (!(supported2 & JO2_TERM_ROWS))
+ break;
+ opt->jo_set2 |= JO2_TERM_ROWS;
+ opt->jo_term_rows = tv_get_number(item);
+ }
+ else if (STRCMP(hi->hi_key, "term_cols") == 0)
+ {
+ if (!(supported2 & JO2_TERM_COLS))
+ break;
+ opt->jo_set2 |= JO2_TERM_COLS;
+ opt->jo_term_cols = tv_get_number(item);
+ }
+ else if (STRCMP(hi->hi_key, "vertical") == 0)
+ {
+ if (!(supported2 & JO2_VERTICAL))
+ break;
+ opt->jo_set2 |= JO2_VERTICAL;
+ opt->jo_vertical = tv_get_number(item);
+ }
+ else if (STRCMP(hi->hi_key, "curwin") == 0)
+ {
+ if (!(supported2 & JO2_CURWIN))
+ break;
+ opt->jo_set2 |= JO2_CURWIN;
+ opt->jo_curwin = tv_get_number(item);
+ }
+ else if (STRCMP(hi->hi_key, "hidden") == 0)
+ {
+ if (!(supported2 & JO2_HIDDEN))
+ break;
+ opt->jo_set2 |= JO2_HIDDEN;
+ opt->jo_hidden = tv_get_number(item);
+ }
+ else if (STRCMP(hi->hi_key, "norestore") == 0)
+ {
+ if (!(supported2 & JO2_NORESTORE))
+ break;
+ opt->jo_set2 |= JO2_NORESTORE;
+ opt->jo_term_norestore = tv_get_number(item);
+ }
+ else if (STRCMP(hi->hi_key, "term_kill") == 0)
+ {
+ if (!(supported2 & JO2_TERM_KILL))
+ break;
+ opt->jo_set2 |= JO2_TERM_KILL;
+ opt->jo_term_kill = tv_get_string_chk(item);
+ }
+ else if (STRCMP(hi->hi_key, "term_mode") == 0)
+ {
+ char_u *p;
+
+ if (!(supported2 & JO2_TERM_MODE))
+ break;
+ opt->jo_set2 |= JO2_TERM_MODE;
+ p = tv_get_string_chk(item);
+ if (p == NULL)
+ {
+ semsg(_(e_invargval), "term_mode");
+ return FAIL;
+ }
+ // Allow empty string, "winpty", "conpty".
+ if (!(*p == NUL || STRCMP(p, "winpty") == 0
+ || STRCMP(p, "conpty") == 0))
+ {
+ semsg(_(e_invargval), "term_mode");
+ return FAIL;
+ }
+ opt->jo_term_mode = p[0];
+ }
+# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
+ else if (STRCMP(hi->hi_key, "ansi_colors") == 0)
+ {
+ int n = 0;
+ listitem_T *li;
+ long_u rgb[16];
+
+ if (!(supported2 & JO2_ANSI_COLORS))
+ break;
+
+ if (item == NULL || item->v_type != VAR_LIST
+ || item->vval.v_list == NULL)
+ {
+ semsg(_(e_invargval), "ansi_colors");
+ return FAIL;
+ }
+
+ li = item->vval.v_list->lv_first;
+ for (; li != NULL && n < 16; li = li->li_next, n++)
+ {
+ char_u *color_name;
+ guicolor_T guicolor;
+
+ color_name = tv_get_string_chk(&li->li_tv);
+ if (color_name == NULL)
+ return FAIL;
+
+ guicolor = GUI_GET_COLOR(color_name);
+ if (guicolor == INVALCOLOR)
+ return FAIL;
+
+ rgb[n] = GUI_MCH_GET_RGB(guicolor);
+ }
+
+ if (n != 16 || li != NULL)
+ {
+ semsg(_(e_invargval), "ansi_colors");
+ return FAIL;
+ }
+
+ opt->jo_set2 |= JO2_ANSI_COLORS;
+ memcpy(opt->jo_ansi_colors, rgb, sizeof(rgb));
+ }
+# endif
+#endif
+ else if (STRCMP(hi->hi_key, "env") == 0)
+ {
+ if (!(supported2 & JO2_ENV))
+ break;
+ if (item->v_type != VAR_DICT)
+ {
+ semsg(_(e_invargval), "env");
+ return FAIL;
+ }
+ opt->jo_set2 |= JO2_ENV;
+ opt->jo_env = item->vval.v_dict;
+ if (opt->jo_env != NULL)
+ ++opt->jo_env->dv_refcount;
+ }
+ else if (STRCMP(hi->hi_key, "cwd") == 0)
+ {
+ if (!(supported2 & JO2_CWD))
+ break;
+ opt->jo_cwd = tv_get_string_buf_chk(item, opt->jo_cwd_buf);
+ if (opt->jo_cwd == NULL || !mch_isdir(opt->jo_cwd)
+#ifndef WIN32 // Win32 directories don't have the concept of "executable"
+ || mch_access((char *)opt->jo_cwd, X_OK) != 0
+#endif
+ )
+ {
+ semsg(_(e_invargval), "cwd");
+ return FAIL;
+ }
+ opt->jo_set2 |= JO2_CWD;
+ }
+ else if (STRCMP(hi->hi_key, "waittime") == 0)
+ {
+ if (!(supported & JO_WAITTIME))
+ break;
+ opt->jo_set |= JO_WAITTIME;
+ opt->jo_waittime = tv_get_number(item);
+ }
+ else if (STRCMP(hi->hi_key, "timeout") == 0)
+ {
+ if (!(supported & JO_TIMEOUT))
+ break;
+ opt->jo_set |= JO_TIMEOUT;
+ opt->jo_timeout = tv_get_number(item);
+ }
+ else if (STRCMP(hi->hi_key, "out_timeout") == 0)
+ {
+ if (!(supported & JO_OUT_TIMEOUT))
+ break;
+ opt->jo_set |= JO_OUT_TIMEOUT;
+ opt->jo_out_timeout = tv_get_number(item);
+ }
+ else if (STRCMP(hi->hi_key, "err_timeout") == 0)
+ {
+ if (!(supported & JO_ERR_TIMEOUT))
+ break;
+ opt->jo_set |= JO_ERR_TIMEOUT;
+ opt->jo_err_timeout = tv_get_number(item);
+ }
+ else if (STRCMP(hi->hi_key, "part") == 0)
+ {
+ if (!(supported & JO_PART))
+ break;
+ opt->jo_set |= JO_PART;
+ val = tv_get_string(item);
+ if (STRCMP(val, "err") == 0)
+ opt->jo_part = PART_ERR;
+ else if (STRCMP(val, "out") == 0)
+ opt->jo_part = PART_OUT;
+ else
+ {
+ semsg(_(e_invargNval), "part", val);
+ return FAIL;
+ }
+ }
+ else if (STRCMP(hi->hi_key, "id") == 0)
+ {
+ if (!(supported & JO_ID))
+ break;
+ opt->jo_set |= JO_ID;
+ opt->jo_id = tv_get_number(item);
+ }
+ else if (STRCMP(hi->hi_key, "stoponexit") == 0)
+ {
+ if (!(supported & JO_STOPONEXIT))
+ break;
+ opt->jo_set |= JO_STOPONEXIT;
+ opt->jo_stoponexit = tv_get_string_buf_chk(item,
+ opt->jo_soe_buf);
+ if (opt->jo_stoponexit == NULL)
+ {
+ semsg(_(e_invargval), "stoponexit");
+ return FAIL;
+ }
+ }
+ else if (STRCMP(hi->hi_key, "block_write") == 0)
+ {
+ if (!(supported & JO_BLOCK_WRITE))
+ break;
+ opt->jo_set |= JO_BLOCK_WRITE;
+ opt->jo_block_write = tv_get_number(item);
+ }
+ else
+ break;
+ --todo;
+ }
+ if (todo > 0)
+ {
+ semsg(_(e_invarg2), hi->hi_key);
+ return FAIL;
+ }
+
+ return OK;
+}
+
+/*
+ * Get the channel from the argument.
+ * Returns NULL if the handle is invalid.
+ * When "check_open" is TRUE check that the channel can be used.
+ * When "reading" is TRUE "check_open" considers typeahead useful.
+ * "part" is used to check typeahead, when PART_COUNT use the default part.
+ */
+ channel_T *
+get_channel_arg(typval_T *tv, int check_open, int reading, ch_part_T part)
+{
+ channel_T *channel = NULL;
+ int has_readahead = FALSE;
+
+ if (tv->v_type == VAR_JOB)
+ {
+ if (tv->vval.v_job != NULL)
+ channel = tv->vval.v_job->jv_channel;
+ }
+ else if (tv->v_type == VAR_CHANNEL)
+ {
+ channel = tv->vval.v_channel;
+ }
+ else
+ {
+ semsg(_(e_invarg2), tv_get_string(tv));
+ return NULL;
+ }
+ if (channel != NULL && reading)
+ has_readahead = channel_has_readahead(channel,
+ part != PART_COUNT ? part : channel_part_read(channel));
+
+ if (check_open && (channel == NULL || (!channel_is_open(channel)
+ && !(reading && has_readahead))))
+ {
+ emsg(_("E906: not an open channel"));
+ return NULL;
+ }
+ return channel;
+}
+
+static job_T *first_job = NULL;
+
+ static void
+job_free_contents(job_T *job)
+{
+ int i;
+
+ ch_log(job->jv_channel, "Freeing job");
+ if (job->jv_channel != NULL)
+ {
+ /* The link from the channel to the job doesn't count as a reference,
+ * thus don't decrement the refcount of the job. The reference from
+ * the job to the channel does count the reference, decrement it and
+ * NULL the reference. We don't set ch_job_killed, unreferencing the
+ * job doesn't mean it stops running. */
+ job->jv_channel->ch_job = NULL;
+ channel_unref(job->jv_channel);
+ }
+ mch_clear_job(job);
+
+ vim_free(job->jv_tty_in);
+ vim_free(job->jv_tty_out);
+ vim_free(job->jv_stoponexit);
+#ifdef UNIX
+ vim_free(job->jv_termsig);
+#endif
+ free_callback(job->jv_exit_cb, job->jv_exit_partial);
+ if (job->jv_argv != NULL)
+ {
+ for (i = 0; job->jv_argv[i] != NULL; i++)
+ vim_free(job->jv_argv[i]);
+ vim_free(job->jv_argv);
+ }
+}
+
+/*
+ * Remove "job" from the list of jobs.
+ */
+ static void
+job_unlink(job_T *job)
+{
+ if (job->jv_next != NULL)
+ job->jv_next->jv_prev = job->jv_prev;
+ if (job->jv_prev == NULL)
+ first_job = job->jv_next;
+ else
+ job->jv_prev->jv_next = job->jv_next;
+}
+
+ static void
+job_free_job(job_T *job)
+{
+ job_unlink(job);
+ vim_free(job);
+}
+
+ static void
+job_free(job_T *job)
+{
+ if (!in_free_unref_items)
+ {
+ job_free_contents(job);
+ job_free_job(job);
+ }
+}
+
+job_T *jobs_to_free = NULL;
+
+/*
+ * Put "job" in a list to be freed later, when it's no longer referenced.
+ */
+ static void
+job_free_later(job_T *job)
+{
+ job_unlink(job);
+ job->jv_next = jobs_to_free;
+ jobs_to_free = job;
+}
+
+ static void
+free_jobs_to_free_later(void)
+{
+ job_T *job;
+
+ while (jobs_to_free != NULL)
+ {
+ job = jobs_to_free;
+ jobs_to_free = job->jv_next;
+ job_free_contents(job);
+ vim_free(job);
+ }
+}
+
+#if defined(EXITFREE) || defined(PROTO)
+ void
+job_free_all(void)
+{
+ while (first_job != NULL)
+ job_free(first_job);
+ free_jobs_to_free_later();
+
+# ifdef FEAT_TERMINAL
+ free_unused_terminals();
+# endif
+}
+#endif
+
+/*
+ * Return TRUE if we need to check if the process of "job" has ended.
+ */
+ static int
+job_need_end_check(job_T *job)
+{
+ return job->jv_status == JOB_STARTED
+ && (job->jv_stoponexit != NULL || job->jv_exit_cb != NULL);
+}
+
+/*
+ * Return TRUE if the channel of "job" is still useful.
+ */
+ static int
+job_channel_still_useful(job_T *job)
+{
+ return job->jv_channel != NULL && channel_still_useful(job->jv_channel);
+}
+
+/*
+ * Return TRUE if the channel of "job" is closeable.
+ */
+ static int
+job_channel_can_close(job_T *job)
+{
+ return job->jv_channel != NULL && channel_can_close(job->jv_channel);
+}
+
+/*
+ * Return TRUE if the job should not be freed yet. Do not free the job when
+ * it has not ended yet and there is a "stoponexit" flag, an exit callback
+ * or when the associated channel will do something with the job output.
+ */
+ static int
+job_still_useful(job_T *job)
+{
+ return job_need_end_check(job) || job_channel_still_useful(job);
+}
+
+#if defined(GUI_MAY_FORK) || defined(PROTO)
+/*
+ * Return TRUE when there is any running job that we care about.
+ */
+ int
+job_any_running()
+{
+ job_T *job;
+
+ for (job = first_job; job != NULL; job = job->jv_next)
+ if (job_still_useful(job))
+ {
+ ch_log(NULL, "GUI not forking because a job is running");
+ return TRUE;
+ }
+ return FALSE;
+}
+#endif
+
+#if !defined(USE_ARGV) || defined(PROTO)
+/*
+ * Escape one argument for an external command.
+ * Returns the escaped string in allocated memory. NULL when out of memory.
+ */
+ static char_u *
+win32_escape_arg(char_u *arg)
+{
+ int slen, dlen;
+ int escaping = 0;
+ int i;
+ char_u *s, *d;
+ char_u *escaped_arg;
+ int has_spaces = FALSE;
+
+ /* First count the number of extra bytes required. */
+ slen = (int)STRLEN(arg);
+ dlen = slen;
+ for (s = arg; *s != NUL; MB_PTR_ADV(s))
+ {
+ if (*s == '"' || *s == '\\')
+ ++dlen;
+ if (*s == ' ' || *s == '\t')
+ has_spaces = TRUE;
+ }
+
+ if (has_spaces)
+ dlen += 2;
+
+ if (dlen == slen)
+ return vim_strsave(arg);
+
+ /* Allocate memory for the result and fill it. */
+ escaped_arg = alloc(dlen + 1);
+ if (escaped_arg == NULL)
+ return NULL;
+ memset(escaped_arg, 0, dlen+1);
+
+ d = escaped_arg;
+
+ if (has_spaces)
+ *d++ = '"';
+
+ for (s = arg; *s != NUL;)
+ {
+ switch (*s)
+ {
+ case '"':
+ for (i = 0; i < escaping; i++)
+ *d++ = '\\';
+ escaping = 0;
+ *d++ = '\\';
+ *d++ = *s++;
+ break;
+ case '\\':
+ escaping++;
+ *d++ = *s++;
+ break;
+ default:
+ escaping = 0;
+ MB_COPY_CHAR(s, d);
+ break;
+ }
+ }
+
+ /* add terminating quote and finish with a NUL */
+ if (has_spaces)
+ {
+ for (i = 0; i < escaping; i++)
+ *d++ = '\\';
+ *d++ = '"';
+ }
+ *d = NUL;
+
+ return escaped_arg;
+}
+
+/*
+ * Build a command line from a list, taking care of escaping.
+ * The result is put in gap->ga_data.
+ * Returns FAIL when out of memory.
+ */
+ int
+win32_build_cmd(list_T *l, garray_T *gap)
+{
+ listitem_T *li;
+ char_u *s;
+
+ for (li = l->lv_first; li != NULL; li = li->li_next)
+ {
+ s = tv_get_string_chk(&li->li_tv);
+ if (s == NULL)
+ return FAIL;
+ s = win32_escape_arg(s);
+ if (s == NULL)
+ return FAIL;
+ ga_concat(gap, s);
+ vim_free(s);
+ if (li->li_next != NULL)
+ ga_append(gap, ' ');
+ }
+ return OK;
+}
+#endif
+
+/*
+ * NOTE: Must call job_cleanup() only once right after the status of "job"
+ * changed to JOB_ENDED (i.e. after job_status() returned "dead" first or
+ * mch_detect_ended_job() returned non-NULL).
+ * If the job is no longer used it will be removed from the list of jobs, and
+ * deleted a bit later.
+ */
+ void
+job_cleanup(job_T *job)
+{
+ if (job->jv_status != JOB_ENDED)
+ return;
+
+ /* Ready to cleanup the job. */
+ job->jv_status = JOB_FINISHED;
+
+ /* When only channel-in is kept open, close explicitly. */
+ if (job->jv_channel != NULL)
+ ch_close_part(job->jv_channel, PART_IN);
+
+ if (job->jv_exit_cb != NULL)
+ {
+ typval_T argv[3];
+ typval_T rettv;
+ int dummy;
+
+ /* Invoke the exit callback. Make sure the refcount is > 0. */
+ ch_log(job->jv_channel, "Invoking exit callback %s", job->jv_exit_cb);
+ ++job->jv_refcount;
+ argv[0].v_type = VAR_JOB;
+ argv[0].vval.v_job = job;
+ argv[1].v_type = VAR_NUMBER;
+ argv[1].vval.v_number = job->jv_exitval;
+ call_func(job->jv_exit_cb, (int)STRLEN(job->jv_exit_cb),
+ &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE,
+ job->jv_exit_partial, NULL);
+ clear_tv(&rettv);
+ --job->jv_refcount;
+ channel_need_redraw = TRUE;
+ }
+
+ if (job->jv_channel != NULL
+ && job->jv_channel->ch_anonymous_pipe && !job->jv_channel->ch_killing)
+ {
+ ++safe_to_invoke_callback;
+ channel_free_contents(job->jv_channel);
+ job->jv_channel->ch_job = NULL;
+ job->jv_channel = NULL;
+ --safe_to_invoke_callback;
+ }
+
+ // Do not free the job in case the close callback of the associated channel
+ // isn't invoked yet and may get information by job_info().
+ if (job->jv_refcount == 0 && !job_channel_still_useful(job))
+ // The job was already unreferenced and the associated channel was
+ // detached, now that it ended it can be freed. However, a caller might
+ // still use it, thus free it a bit later.
+ job_free_later(job);
+}
+
+/*
+ * Mark references in jobs that are still useful.
+ */
+ int
+set_ref_in_job(int copyID)
+{
+ int abort = FALSE;
+ job_T *job;
+ typval_T tv;
+
+ for (job = first_job; job != NULL; job = job->jv_next)
+ if (job_still_useful(job))
+ {
+ tv.v_type = VAR_JOB;
+ tv.vval.v_job = job;
+ abort = abort || set_ref_in_item(&tv, copyID, NULL, NULL);
+ }
+ return abort;
+}
+
+/*
+ * Dereference "job". Note that after this "job" may have been freed.
+ */
+ void
+job_unref(job_T *job)
+{
+ if (job != NULL && --job->jv_refcount <= 0)
+ {
+ /* Do not free the job if there is a channel where the close callback
+ * may get the job info. */
+ if (!job_channel_still_useful(job))
+ {
+ /* Do not free the job when it has not ended yet and there is a
+ * "stoponexit" flag or an exit callback. */
+ if (!job_need_end_check(job))
+ {
+ job_free(job);
+ }
+ else if (job->jv_channel != NULL)
+ {
+ /* Do remove the link to the channel, otherwise it hangs
+ * around until Vim exits. See job_free() for refcount. */
+ ch_log(job->jv_channel, "detaching channel from job");
+ job->jv_channel->ch_job = NULL;
+ channel_unref(job->jv_channel);
+ job->jv_channel = NULL;
+ }
+ }
+ }
+}
+
+ int
+free_unused_jobs_contents(int copyID, int mask)
+{
+ int did_free = FALSE;
+ job_T *job;
+
+ for (job = first_job; job != NULL; job = job->jv_next)
+ if ((job->jv_copyID & mask) != (copyID & mask)
+ && !job_still_useful(job))
+ {
+ /* Free the channel and ordinary items it contains, but don't
+ * recurse into Lists, Dictionaries etc. */
+ job_free_contents(job);
+ did_free = TRUE;
+ }
+ return did_free;
+}
+
+ void
+free_unused_jobs(int copyID, int mask)
+{
+ job_T *job;
+ job_T *job_next;
+
+ for (job = first_job; job != NULL; job = job_next)
+ {
+ job_next = job->jv_next;
+ if ((job->jv_copyID & mask) != (copyID & mask)
+ && !job_still_useful(job))
+ {
+ /* Free the job struct itself. */
+ job_free_job(job);
+ }
+ }
+}
+
+/*
+ * Allocate a job. Sets the refcount to one and sets options default.
+ */
+ job_T *
+job_alloc(void)
+{
+ job_T *job;
+
+ job = (job_T *)alloc_clear(sizeof(job_T));
+ if (job != NULL)
+ {
+ job->jv_refcount = 1;
+ job->jv_stoponexit = vim_strsave((char_u *)"term");
+
+ if (first_job != NULL)
+ {
+ first_job->jv_prev = job;
+ job->jv_next = first_job;
+ }
+ first_job = job;
+ }
+ return job;
+}
+
+ void
+job_set_options(job_T *job, jobopt_T *opt)
+{
+ if (opt->jo_set & JO_STOPONEXIT)
+ {
+ vim_free(job->jv_stoponexit);
+ if (opt->jo_stoponexit == NULL || *opt->jo_stoponexit == NUL)
+ job->jv_stoponexit = NULL;
+ else
+ job->jv_stoponexit = vim_strsave(opt->jo_stoponexit);
+ }
+ if (opt->jo_set & JO_EXIT_CB)
+ {
+ free_callback(job->jv_exit_cb, job->jv_exit_partial);
+ if (opt->jo_exit_cb == NULL || *opt->jo_exit_cb == NUL)
+ {
+ job->jv_exit_cb = NULL;
+ job->jv_exit_partial = NULL;
+ }
+ else
+ {
+ job->jv_exit_partial = opt->jo_exit_partial;
+ if (job->jv_exit_partial != NULL)
+ {
+ job->jv_exit_cb = opt->jo_exit_cb;
+ ++job->jv_exit_partial->pt_refcount;
+ }
+ else
+ {
+ job->jv_exit_cb = vim_strsave(opt->jo_exit_cb);
+ func_ref(job->jv_exit_cb);
+ }
+ }
+ }
+}
+
+/*
+ * Called when Vim is exiting: kill all jobs that have the "stoponexit" flag.
+ */
+ void
+job_stop_on_exit(void)
+{
+ job_T *job;
+
+ for (job = first_job; job != NULL; job = job->jv_next)
+ if (job->jv_status == JOB_STARTED && job->jv_stoponexit != NULL)
+ mch_signal_job(job, job->jv_stoponexit);
+}
+
+/*
+ * Return TRUE when there is any job that has an exit callback and might exit,
+ * which means job_check_ended() should be called more often.
+ */
+ int
+has_pending_job(void)
+{
+ job_T *job;
+
+ for (job = first_job; job != NULL; job = job->jv_next)
+ /* Only should check if the channel has been closed, if the channel is
+ * open the job won't exit. */
+ if ((job->jv_status == JOB_STARTED && !job_channel_still_useful(job))
+ || (job->jv_status == JOB_FINISHED
+ && job_channel_can_close(job)))
+ return TRUE;
+ return FALSE;
+}
+
+#define MAX_CHECK_ENDED 8
+
+/*
+ * Called once in a while: check if any jobs that seem useful have ended.
+ * Returns TRUE if a job did end.
+ */
+ int
+job_check_ended(void)
+{
+ int i;
+ int did_end = FALSE;
+
+ // be quick if there are no jobs to check
+ if (first_job == NULL)
+ return did_end;
+
+ for (i = 0; i < MAX_CHECK_ENDED; ++i)
+ {
+ // NOTE: mch_detect_ended_job() must only return a job of which the
+ // status was just set to JOB_ENDED.
+ job_T *job = mch_detect_ended_job(first_job);
+
+ if (job == NULL)
+ break;
+ did_end = TRUE;
+ job_cleanup(job); // may add "job" to jobs_to_free
+ }
+
+ // Actually free jobs that were cleaned up.
+ free_jobs_to_free_later();
+
+ if (channel_need_redraw)
+ {
+ channel_need_redraw = FALSE;
+ redraw_after_callback(TRUE);
+ }
+ return did_end;
+}
+
+/*
+ * Create a job and return it. Implements job_start().
+ * "argv_arg" is only for Unix.
+ * When "argv_arg" is NULL then "argvars" is used.
+ * The returned job has a refcount of one.
+ * Returns NULL when out of memory.
+ */
+ job_T *
+job_start(
+ typval_T *argvars,
+ char **argv_arg,
+ jobopt_T *opt_arg,
+ int is_terminal UNUSED)
+{
+ job_T *job;
+ char_u *cmd = NULL;
+ char **argv = NULL;
+ int argc = 0;
+#if defined(UNIX)
+# define USE_ARGV
+ int i;
+#else
+ garray_T ga;
+#endif
+ jobopt_T opt;
+ ch_part_T part;
+
+ job = job_alloc();
+ if (job == NULL)
+ return NULL;
+
+ job->jv_status = JOB_FAILED;
+#ifndef USE_ARGV
+ ga_init2(&ga, (int)sizeof(char*), 20);
+#endif
+
+ if (opt_arg != NULL)
+ opt = *opt_arg;
+ else
+ {
+ /* Default mode is NL. */
+ clear_job_options(&opt);
+ opt.jo_mode = MODE_NL;
+ if (get_job_options(&argvars[1], &opt,
+ JO_MODE_ALL + JO_CB_ALL + JO_TIMEOUT_ALL + JO_STOPONEXIT
+ + JO_EXIT_CB + JO_OUT_IO + JO_BLOCK_WRITE,
+ JO2_ENV + JO2_CWD) == FAIL)
+ goto theend;
+ }
+
+ /* Check that when io is "file" that there is a file name. */
+ for (part = PART_OUT; part < PART_COUNT; ++part)
+ if ((opt.jo_set & (JO_OUT_IO << (part - PART_OUT)))
+ && opt.jo_io[part] == JIO_FILE
+ && (!(opt.jo_set & (JO_OUT_NAME << (part - PART_OUT)))
+ || *opt.jo_io_name[part] == NUL))
+ {
+ emsg(_("E920: _io file requires _name to be set"));
+ goto theend;
+ }
+
+ if ((opt.jo_set & JO_IN_IO) && opt.jo_io[PART_IN] == JIO_BUFFER)
+ {
+ buf_T *buf = NULL;
+
+ /* check that we can find the buffer before starting the job */
+ if (opt.jo_set & JO_IN_BUF)
+ {
+ buf = buflist_findnr(opt.jo_io_buf[PART_IN]);
+ if (buf == NULL)
+ semsg(_(e_nobufnr), (long)opt.jo_io_buf[PART_IN]);
+ }
+ else if (!(opt.jo_set & JO_IN_NAME))
+ {
+ emsg(_("E915: in_io buffer requires in_buf or in_name to be set"));
+ }
+ else
+ buf = buflist_find_by_name(opt.jo_io_name[PART_IN], FALSE);
+ if (buf == NULL)
+ goto theend;
+ if (buf->b_ml.ml_mfp == NULL)
+ {
+ char_u numbuf[NUMBUFLEN];
+ char_u *s;
+
+ if (opt.jo_set & JO_IN_BUF)
+ {
+ sprintf((char *)numbuf, "%d", opt.jo_io_buf[PART_IN]);
+ s = numbuf;
+ }
+ else
+ s = opt.jo_io_name[PART_IN];
+ semsg(_("E918: buffer must be loaded: %s"), s);
+ goto theend;
+ }
+ job->jv_in_buf = buf;
+ }
+
+ job_set_options(job, &opt);
+
+#ifdef USE_ARGV
+ if (argv_arg != NULL)
+ {
+ /* Make a copy of argv_arg for job->jv_argv. */
+ for (i = 0; argv_arg[i] != NULL; i++)
+ argc++;
+ argv = (char **)alloc(sizeof(char *) * (argc + 1));
+ if (argv == NULL)
+ goto theend;
+ for (i = 0; i < argc; i++)
+ argv[i] = (char *)vim_strsave((char_u *)argv_arg[i]);
+ argv[argc] = NULL;
+ }
+ else
+#endif
+ if (argvars[0].v_type == VAR_STRING)
+ {
+ /* Command is a string. */
+ cmd = argvars[0].vval.v_string;
+ if (cmd == NULL || *cmd == NUL)
+ {
+ emsg(_(e_invarg));
+ goto theend;
+ }
+
+ if (build_argv_from_string(cmd, &argv, &argc) == FAIL)
+ goto theend;
+ }
+ else if (argvars[0].v_type != VAR_LIST
+ || argvars[0].vval.v_list == NULL
+ || argvars[0].vval.v_list->lv_len < 1)
+ {
+ emsg(_(e_invarg));
+ goto theend;
+ }
+ else
+ {
+ list_T *l = argvars[0].vval.v_list;
+
+ if (build_argv_from_list(l, &argv, &argc) == FAIL)
+ goto theend;
+#ifndef USE_ARGV
+ if (win32_build_cmd(l, &ga) == FAIL)
+ goto theend;
+ cmd = ga.ga_data;
+#endif
+ }
+
+ /* Save the command used to start the job. */
+ job->jv_argv = argv;
+
+#ifdef USE_ARGV
+ if (ch_log_active())
+ {
+ garray_T ga;
+
+ ga_init2(&ga, (int)sizeof(char), 200);
+ for (i = 0; i < argc; ++i)
+ {
+ if (i > 0)
+ ga_concat(&ga, (char_u *)" ");
+ ga_concat(&ga, (char_u *)argv[i]);
+ }
+ ch_log(NULL, "Starting job: %s", (char *)ga.ga_data);
+ ga_clear(&ga);
+ }
+ mch_job_start(argv, job, &opt, is_terminal);
+#else
+ ch_log(NULL, "Starting job: %s", (char *)cmd);
+ mch_job_start((char *)cmd, job, &opt);
+#endif
+
+ /* If the channel is reading from a buffer, write lines now. */
+ if (job->jv_channel != NULL)
+ channel_write_in(job->jv_channel);
+
+theend:
+#ifndef USE_ARGV
+ vim_free(ga.ga_data);
+#endif
+ if (argv != job->jv_argv)
+ vim_free(argv);
+ free_job_options(&opt);
+ return job;
+}
+
+/*
+ * Get the status of "job" and invoke the exit callback when needed.
+ * The returned string is not allocated.
+ */
+ char *
+job_status(job_T *job)
+{
+ char *result;
+
+ if (job->jv_status >= JOB_ENDED)
+ /* No need to check, dead is dead. */
+ result = "dead";
+ else if (job->jv_status == JOB_FAILED)
+ result = "fail";
+ else
+ {
+ result = mch_job_status(job);
+ if (job->jv_status == JOB_ENDED)
+ job_cleanup(job);
+ }
+ return result;
+}
+
+/*
+ * Implementation of job_info().
+ */
+ void
+job_info(job_T *job, dict_T *dict)
+{
+ dictitem_T *item;
+ varnumber_T nr;
+ list_T *l;
+ int i;
+
+ dict_add_string(dict, "status", (char_u *)job_status(job));
+
+ item = dictitem_alloc((char_u *)"channel");
+ if (item == NULL)
+ return;
+ item->di_tv.v_type = VAR_CHANNEL;
+ item->di_tv.vval.v_channel = job->jv_channel;
+ if (job->jv_channel != NULL)
+ ++job->jv_channel->ch_refcount;
+ if (dict_add(dict, item) == FAIL)
+ dictitem_free(item);
+
+#ifdef UNIX
+ nr = job->jv_pid;
+#else
+ nr = job->jv_proc_info.dwProcessId;
+#endif
+ dict_add_number(dict, "process", nr);
+ dict_add_string(dict, "tty_in", job->jv_tty_in);
+ dict_add_string(dict, "tty_out", job->jv_tty_out);
+
+ dict_add_number(dict, "exitval", job->jv_exitval);
+ dict_add_string(dict, "exit_cb", job->jv_exit_cb);
+ dict_add_string(dict, "stoponexit", job->jv_stoponexit);
+#ifdef UNIX
+ dict_add_string(dict, "termsig", job->jv_termsig);
+#endif
+
+ l = list_alloc();
+ if (l != NULL)
+ {
+ dict_add_list(dict, "cmd", l);
+ if (job->jv_argv != NULL)
+ for (i = 0; job->jv_argv[i] != NULL; i++)
+ list_append_string(l, (char_u *)job->jv_argv[i], -1);
+ }
+}
+
+/*
+ * Implementation of job_info() to return info for all jobs.
+ */
+ void
+job_info_all(list_T *l)
+{
+ job_T *job;
+ typval_T tv;
+
+ for (job = first_job; job != NULL; job = job->jv_next)
+ {
+ tv.v_type = VAR_JOB;
+ tv.vval.v_job = job;
+
+ if (list_append_tv(l, &tv) != OK)
+ return;
+ }
+}
+
+/*
+ * Send a signal to "job". Implements job_stop().
+ * When "type" is not NULL use this for the type.
+ * Otherwise use argvars[1] for the type.
+ */
+ int
+job_stop(job_T *job, typval_T *argvars, char *type)
+{
+ char_u *arg;
+
+ if (type != NULL)
+ arg = (char_u *)type;
+ else if (argvars[1].v_type == VAR_UNKNOWN)
+ arg = (char_u *)"";
+ else
+ {
+ arg = tv_get_string_chk(&argvars[1]);
+ if (arg == NULL)
+ {
+ emsg(_(e_invarg));
+ return 0;
+ }
+ }
+ if (job->jv_status == JOB_FAILED)
+ {
+ ch_log(job->jv_channel, "Job failed to start, job_stop() skipped");
+ return 0;
+ }
+ if (job->jv_status == JOB_ENDED)
+ {
+ ch_log(job->jv_channel, "Job has already ended, job_stop() skipped");
+ return 0;
+ }
+ ch_log(job->jv_channel, "Stopping job with '%s'", (char *)arg);
+ if (mch_signal_job(job, arg) == FAIL)
+ return 0;
+
+ /* Assume that only "kill" will kill the job. */
+ if (job->jv_channel != NULL && STRCMP(arg, "kill") == 0)
+ job->jv_channel->ch_job_killed = TRUE;
+
+ /* We don't try freeing the job, obviously the caller still has a
+ * reference to it. */
+ return 1;
+}
+
+ void
+invoke_prompt_callback(void)
+{
+ typval_T rettv;
+ int dummy;
+ typval_T argv[2];
+ char_u *text;
+ char_u *prompt;
+ linenr_T lnum = curbuf->b_ml.ml_line_count;
+
+ // Add a new line for the prompt before invoking the callback, so that
+ // text can always be inserted above the last line.
+ ml_append(lnum, (char_u *)"", 0, FALSE);
+ curwin->w_cursor.lnum = lnum + 1;
+ curwin->w_cursor.col = 0;
+
+ if (curbuf->b_prompt_callback == NULL || *curbuf->b_prompt_callback == NUL)
+ return;
+ text = ml_get(lnum);
+ prompt = prompt_text();
+ if (STRLEN(text) >= STRLEN(prompt))
+ text += STRLEN(prompt);
+ argv[0].v_type = VAR_STRING;
+ argv[0].vval.v_string = vim_strsave(text);
+ argv[1].v_type = VAR_UNKNOWN;
+
+ call_func(curbuf->b_prompt_callback,
+ (int)STRLEN(curbuf->b_prompt_callback),
+ &rettv, 1, argv, NULL, 0L, 0L, &dummy, TRUE,
+ curbuf->b_prompt_partial, NULL);
+ clear_tv(&argv[0]);
+ clear_tv(&rettv);
+}
+
+/*
+ * Return TRUE when the interrupt callback was invoked.
+ */
+ int
+invoke_prompt_interrupt(void)
+{
+ typval_T rettv;
+ int dummy;
+ typval_T argv[1];
+
+ if (curbuf->b_prompt_interrupt == NULL
+ || *curbuf->b_prompt_interrupt == NUL)
+ return FALSE;
+ argv[0].v_type = VAR_UNKNOWN;
+
+ got_int = FALSE; // don't skip executing commands
+ call_func(curbuf->b_prompt_interrupt,
+ (int)STRLEN(curbuf->b_prompt_interrupt),
+ &rettv, 0, argv, NULL, 0L, 0L, &dummy, TRUE,
+ curbuf->b_prompt_int_partial, NULL);
+ clear_tv(&rettv);
+ return TRUE;
+}
+
+#endif /* FEAT_JOB_CHANNEL */
diff --git a/src/charset.c b/src/charset.c
new file mode 100644
index 0000000..5b091ec
--- /dev/null
+++ b/src/charset.c
@@ -0,0 +1,2093 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+#include "vim.h"
+
+#if defined(HAVE_WCHAR_H)
+# include <wchar.h> /* for towupper() and towlower() */
+#endif
+static int win_nolbr_chartabsize(win_T *wp, char_u *s, colnr_T col, int *headp);
+
+static unsigned nr2hex(unsigned c);
+
+static int chartab_initialized = FALSE;
+
+/* b_chartab[] is an array of 32 bytes, each bit representing one of the
+ * characters 0-255. */
+#define SET_CHARTAB(buf, c) (buf)->b_chartab[(unsigned)(c) >> 3] |= (1 << ((c) & 0x7))
+#define RESET_CHARTAB(buf, c) (buf)->b_chartab[(unsigned)(c) >> 3] &= ~(1 << ((c) & 0x7))
+#define GET_CHARTAB(buf, c) ((buf)->b_chartab[(unsigned)(c) >> 3] & (1 << ((c) & 0x7)))
+
+/* table used below, see init_chartab() for an explanation */
+static char_u g_chartab[256];
+
+/*
+ * Flags for g_chartab[].
+ */
+#define CT_CELL_MASK 0x07 /* mask: nr of display cells (1, 2 or 4) */
+#define CT_PRINT_CHAR 0x10 /* flag: set for printable chars */
+#define CT_ID_CHAR 0x20 /* flag: set for ID chars */
+#define CT_FNAME_CHAR 0x40 /* flag: set for file name chars */
+
+/*
+ * Fill g_chartab[]. Also fills curbuf->b_chartab[] with flags for keyword
+ * characters for current buffer.
+ *
+ * Depends on the option settings 'iskeyword', 'isident', 'isfname',
+ * 'isprint' and 'encoding'.
+ *
+ * The index in g_chartab[] depends on 'encoding':
+ * - For non-multi-byte index with the byte (same as the character).
+ * - For DBCS index with the first byte.
+ * - For UTF-8 index with the character (when first byte is up to 0x80 it is
+ * the same as the character, if the first byte is 0x80 and above it depends
+ * on further bytes).
+ *
+ * The contents of g_chartab[]:
+ * - The lower two bits, masked by CT_CELL_MASK, give the number of display
+ * cells the character occupies (1 or 2). Not valid for UTF-8 above 0x80.
+ * - CT_PRINT_CHAR bit is set when the character is printable (no need to
+ * translate the character before displaying it). Note that only DBCS
+ * characters can have 2 display cells and still be printable.
+ * - CT_FNAME_CHAR bit is set when the character can be in a file name.
+ * - CT_ID_CHAR bit is set when the character can be in an identifier.
+ *
+ * Return FAIL if 'iskeyword', 'isident', 'isfname' or 'isprint' option has an
+ * error, OK otherwise.
+ */
+ int
+init_chartab(void)
+{
+ return buf_init_chartab(curbuf, TRUE);
+}
+
+ int
+buf_init_chartab(
+ buf_T *buf,
+ int global) /* FALSE: only set buf->b_chartab[] */
+{
+ int c;
+ int c2;
+ char_u *p;
+ int i;
+ int tilde;
+ int do_isalpha;
+
+ if (global)
+ {
+ /*
+ * Set the default size for printable characters:
+ * From <Space> to '~' is 1 (printable), others are 2 (not printable).
+ * This also inits all 'isident' and 'isfname' flags to FALSE.
+ *
+ * EBCDIC: all chars below ' ' are not printable, all others are
+ * printable.
+ */
+ c = 0;
+ while (c < ' ')
+ g_chartab[c++] = (dy_flags & DY_UHEX) ? 4 : 2;
+#ifdef EBCDIC
+ while (c < 255)
+#else
+ while (c <= '~')
+#endif
+ g_chartab[c++] = 1 + CT_PRINT_CHAR;
+#ifdef FEAT_FKMAP
+ if (p_altkeymap)
+ {
+ while (c < YE)
+ g_chartab[c++] = 1 + CT_PRINT_CHAR;
+ }
+#endif
+ while (c < 256)
+ {
+ /* UTF-8: bytes 0xa0 - 0xff are printable (latin1) */
+ if (enc_utf8 && c >= 0xa0)
+ g_chartab[c++] = CT_PRINT_CHAR + 1;
+ /* euc-jp characters starting with 0x8e are single width */
+ else if (enc_dbcs == DBCS_JPNU && c == 0x8e)
+ g_chartab[c++] = CT_PRINT_CHAR + 1;
+ /* other double-byte chars can be printable AND double-width */
+ else if (enc_dbcs != 0 && MB_BYTE2LEN(c) == 2)
+ g_chartab[c++] = CT_PRINT_CHAR + 2;
+ else
+ /* the rest is unprintable by default */
+ g_chartab[c++] = (dy_flags & DY_UHEX) ? 4 : 2;
+ }
+
+ /* Assume that every multi-byte char is a filename character. */
+ for (c = 1; c < 256; ++c)
+ if ((enc_dbcs != 0 && MB_BYTE2LEN(c) > 1)
+ || (enc_dbcs == DBCS_JPNU && c == 0x8e)
+ || (enc_utf8 && c >= 0xa0))
+ g_chartab[c] |= CT_FNAME_CHAR;
+ }
+
+ /*
+ * Init word char flags all to FALSE
+ */
+ vim_memset(buf->b_chartab, 0, (size_t)32);
+ if (enc_dbcs != 0)
+ for (c = 0; c < 256; ++c)
+ {
+ /* double-byte characters are probably word characters */
+ if (MB_BYTE2LEN(c) == 2)
+ SET_CHARTAB(buf, c);
+ }
+
+#ifdef FEAT_LISP
+ /*
+ * In lisp mode the '-' character is included in keywords.
+ */
+ if (buf->b_p_lisp)
+ SET_CHARTAB(buf, '-');
+#endif
+
+ /* Walk through the 'isident', 'iskeyword', 'isfname' and 'isprint'
+ * options Each option is a list of characters, character numbers or
+ * ranges, separated by commas, e.g.: "200-210,x,#-178,-"
+ */
+ for (i = global ? 0 : 3; i <= 3; ++i)
+ {
+ if (i == 0)
+ p = p_isi; /* first round: 'isident' */
+ else if (i == 1)
+ p = p_isp; /* second round: 'isprint' */
+ else if (i == 2)
+ p = p_isf; /* third round: 'isfname' */
+ else /* i == 3 */
+ p = buf->b_p_isk; /* fourth round: 'iskeyword' */
+
+ while (*p)
+ {
+ tilde = FALSE;
+ do_isalpha = FALSE;
+ if (*p == '^' && p[1] != NUL)
+ {
+ tilde = TRUE;
+ ++p;
+ }
+ if (VIM_ISDIGIT(*p))
+ c = getdigits(&p);
+ else
+ if (has_mbyte)
+ c = mb_ptr2char_adv(&p);
+ else
+ c = *p++;
+ c2 = -1;
+ if (*p == '-' && p[1] != NUL)
+ {
+ ++p;
+ if (VIM_ISDIGIT(*p))
+ c2 = getdigits(&p);
+ else
+ if (has_mbyte)
+ c2 = mb_ptr2char_adv(&p);
+ else
+ c2 = *p++;
+ }
+ if (c <= 0 || c >= 256 || (c2 < c && c2 != -1) || c2 >= 256
+ || !(*p == NUL || *p == ','))
+ return FAIL;
+
+ if (c2 == -1) /* not a range */
+ {
+ /*
+ * A single '@' (not "@-@"):
+ * Decide on letters being ID/printable/keyword chars with
+ * standard function isalpha(). This takes care of locale for
+ * single-byte characters).
+ */
+ if (c == '@')
+ {
+ do_isalpha = TRUE;
+ c = 1;
+ c2 = 255;
+ }
+ else
+ c2 = c;
+ }
+ while (c <= c2)
+ {
+ /* Use the MB_ functions here, because isalpha() doesn't
+ * work properly when 'encoding' is "latin1" and the locale is
+ * "C". */
+ if (!do_isalpha || MB_ISLOWER(c) || MB_ISUPPER(c)
+#ifdef FEAT_FKMAP
+ || (p_altkeymap && (F_isalpha(c) || F_isdigit(c)))
+#endif
+ )
+ {
+ if (i == 0) /* (re)set ID flag */
+ {
+ if (tilde)
+ g_chartab[c] &= ~CT_ID_CHAR;
+ else
+ g_chartab[c] |= CT_ID_CHAR;
+ }
+ else if (i == 1) /* (re)set printable */
+ {
+ if ((c < ' '
+#ifndef EBCDIC
+ || c > '~'
+#endif
+#ifdef FEAT_FKMAP
+ || (p_altkeymap
+ && (F_isalpha(c) || F_isdigit(c)))
+#endif
+ // For double-byte we keep the cell width, so
+ // that we can detect it from the first byte.
+ ) && !(enc_dbcs && MB_BYTE2LEN(c) == 2))
+ {
+ if (tilde)
+ {
+ g_chartab[c] = (g_chartab[c] & ~CT_CELL_MASK)
+ + ((dy_flags & DY_UHEX) ? 4 : 2);
+ g_chartab[c] &= ~CT_PRINT_CHAR;
+ }
+ else
+ {
+ g_chartab[c] = (g_chartab[c] & ~CT_CELL_MASK) + 1;
+ g_chartab[c] |= CT_PRINT_CHAR;
+ }
+ }
+ }
+ else if (i == 2) /* (re)set fname flag */
+ {
+ if (tilde)
+ g_chartab[c] &= ~CT_FNAME_CHAR;
+ else
+ g_chartab[c] |= CT_FNAME_CHAR;
+ }
+ else /* i == 3 */ /* (re)set keyword flag */
+ {
+ if (tilde)
+ RESET_CHARTAB(buf, c);
+ else
+ SET_CHARTAB(buf, c);
+ }
+ }
+ ++c;
+ }
+
+ c = *p;
+ p = skip_to_option_part(p);
+ if (c == ',' && *p == NUL)
+ /* Trailing comma is not allowed. */
+ return FAIL;
+ }
+ }
+ chartab_initialized = TRUE;
+ return OK;
+}
+
+/*
+ * Translate any special characters in buf[bufsize] in-place.
+ * The result is a string with only printable characters, but if there is not
+ * enough room, not all characters will be translated.
+ */
+ void
+trans_characters(
+ char_u *buf,
+ int bufsize)
+{
+ int len; /* length of string needing translation */
+ int room; /* room in buffer after string */
+ char_u *trs; /* translated character */
+ int trs_len; /* length of trs[] */
+
+ len = (int)STRLEN(buf);
+ room = bufsize - len;
+ while (*buf != 0)
+ {
+ /* Assume a multi-byte character doesn't need translation. */
+ if (has_mbyte && (trs_len = (*mb_ptr2len)(buf)) > 1)
+ len -= trs_len;
+ else
+ {
+ trs = transchar_byte(*buf);
+ trs_len = (int)STRLEN(trs);
+ if (trs_len > 1)
+ {
+ room -= trs_len - 1;
+ if (room <= 0)
+ return;
+ mch_memmove(buf + trs_len, buf + 1, (size_t)len);
+ }
+ mch_memmove(buf, trs, (size_t)trs_len);
+ --len;
+ }
+ buf += trs_len;
+ }
+}
+
+#if defined(FEAT_EVAL) || defined(FEAT_TITLE) || defined(FEAT_INS_EXPAND) \
+ || defined(PROTO)
+/*
+ * Translate a string into allocated memory, replacing special chars with
+ * printable chars. Returns NULL when out of memory.
+ */
+ char_u *
+transstr(char_u *s)
+{
+ char_u *res;
+ char_u *p;
+ int l, len, c;
+ char_u hexbuf[11];
+
+ if (has_mbyte)
+ {
+ /* Compute the length of the result, taking account of unprintable
+ * multi-byte characters. */
+ len = 0;
+ p = s;
+ while (*p != NUL)
+ {
+ if ((l = (*mb_ptr2len)(p)) > 1)
+ {
+ c = (*mb_ptr2char)(p);
+ p += l;
+ if (vim_isprintc(c))
+ len += l;
+ else
+ {
+ transchar_hex(hexbuf, c);
+ len += (int)STRLEN(hexbuf);
+ }
+ }
+ else
+ {
+ l = byte2cells(*p++);
+ if (l > 0)
+ len += l;
+ else
+ len += 4; /* illegal byte sequence */
+ }
+ }
+ res = alloc((unsigned)(len + 1));
+ }
+ else
+ res = alloc((unsigned)(vim_strsize(s) + 1));
+ if (res != NULL)
+ {
+ *res = NUL;
+ p = s;
+ while (*p != NUL)
+ {
+ if (has_mbyte && (l = (*mb_ptr2len)(p)) > 1)
+ {
+ c = (*mb_ptr2char)(p);
+ if (vim_isprintc(c))
+ STRNCAT(res, p, l); /* append printable multi-byte char */
+ else
+ transchar_hex(res + STRLEN(res), c);
+ p += l;
+ }
+ else
+ STRCAT(res, transchar_byte(*p++));
+ }
+ }
+ return res;
+}
+#endif
+
+#if defined(FEAT_SYN_HL) || defined(FEAT_INS_EXPAND) || defined(PROTO)
+/*
+ * Convert the string "str[orglen]" to do ignore-case comparing. Uses the
+ * current locale.
+ * When "buf" is NULL returns an allocated string (NULL for out-of-memory).
+ * Otherwise puts the result in "buf[buflen]".
+ */
+ char_u *
+str_foldcase(
+ char_u *str,
+ int orglen,
+ char_u *buf,
+ int buflen)
+{
+ garray_T ga;
+ int i;
+ int len = orglen;
+
+#define GA_CHAR(i) ((char_u *)ga.ga_data)[i]
+#define GA_PTR(i) ((char_u *)ga.ga_data + i)
+#define STR_CHAR(i) (buf == NULL ? GA_CHAR(i) : buf[i])
+#define STR_PTR(i) (buf == NULL ? GA_PTR(i) : buf + i)
+
+ /* Copy "str" into "buf" or allocated memory, unmodified. */
+ if (buf == NULL)
+ {
+ ga_init2(&ga, 1, 10);
+ if (ga_grow(&ga, len + 1) == FAIL)
+ return NULL;
+ mch_memmove(ga.ga_data, str, (size_t)len);
+ ga.ga_len = len;
+ }
+ else
+ {
+ if (len >= buflen) /* Ugly! */
+ len = buflen - 1;
+ mch_memmove(buf, str, (size_t)len);
+ }
+ if (buf == NULL)
+ GA_CHAR(len) = NUL;
+ else
+ buf[len] = NUL;
+
+ /* Make each character lower case. */
+ i = 0;
+ while (STR_CHAR(i) != NUL)
+ {
+ if (enc_utf8 || (has_mbyte && MB_BYTE2LEN(STR_CHAR(i)) > 1))
+ {
+ if (enc_utf8)
+ {
+ int c = utf_ptr2char(STR_PTR(i));
+ int olen = utf_ptr2len(STR_PTR(i));
+ int lc = utf_tolower(c);
+
+ /* Only replace the character when it is not an invalid
+ * sequence (ASCII character or more than one byte) and
+ * utf_tolower() doesn't return the original character. */
+ if ((c < 0x80 || olen > 1) && c != lc)
+ {
+ int nlen = utf_char2len(lc);
+
+ /* If the byte length changes need to shift the following
+ * characters forward or backward. */
+ if (olen != nlen)
+ {
+ if (nlen > olen)
+ {
+ if (buf == NULL
+ ? ga_grow(&ga, nlen - olen + 1) == FAIL
+ : len + nlen - olen >= buflen)
+ {
+ /* out of memory, keep old char */
+ lc = c;
+ nlen = olen;
+ }
+ }
+ if (olen != nlen)
+ {
+ if (buf == NULL)
+ {
+ STRMOVE(GA_PTR(i) + nlen, GA_PTR(i) + olen);
+ ga.ga_len += nlen - olen;
+ }
+ else
+ {
+ STRMOVE(buf + i + nlen, buf + i + olen);
+ len += nlen - olen;
+ }
+ }
+ }
+ (void)utf_char2bytes(lc, STR_PTR(i));
+ }
+ }
+ /* skip to next multi-byte char */
+ i += (*mb_ptr2len)(STR_PTR(i));
+ }
+ else
+ {
+ if (buf == NULL)
+ GA_CHAR(i) = TOLOWER_LOC(GA_CHAR(i));
+ else
+ buf[i] = TOLOWER_LOC(buf[i]);
+ ++i;
+ }
+ }
+
+ if (buf == NULL)
+ return (char_u *)ga.ga_data;
+ return buf;
+}
+#endif
+
+/*
+ * Catch 22: g_chartab[] can't be initialized before the options are
+ * initialized, and initializing options may cause transchar() to be called!
+ * When chartab_initialized == FALSE don't use g_chartab[].
+ * Does NOT work for multi-byte characters, c must be <= 255.
+ * Also doesn't work for the first byte of a multi-byte, "c" must be a
+ * character!
+ */
+static char_u transchar_buf[7];
+
+ char_u *
+transchar(int c)
+{
+ int i;
+
+ i = 0;
+ if (IS_SPECIAL(c)) /* special key code, display as ~@ char */
+ {
+ transchar_buf[0] = '~';
+ transchar_buf[1] = '@';
+ i = 2;
+ c = K_SECOND(c);
+ }
+
+ if ((!chartab_initialized && (
+#ifdef EBCDIC
+ (c >= 64 && c < 255)
+#else
+ (c >= ' ' && c <= '~')
+#endif
+#ifdef FEAT_FKMAP
+ || (p_altkeymap && F_ischar(c))
+#endif
+ )) || (c < 256 && vim_isprintc_strict(c)))
+ {
+ /* printable character */
+ transchar_buf[i] = c;
+ transchar_buf[i + 1] = NUL;
+ }
+ else
+ transchar_nonprint(transchar_buf + i, c);
+ return transchar_buf;
+}
+
+/*
+ * Like transchar(), but called with a byte instead of a character. Checks
+ * for an illegal UTF-8 byte.
+ */
+ char_u *
+transchar_byte(int c)
+{
+ if (enc_utf8 && c >= 0x80)
+ {
+ transchar_nonprint(transchar_buf, c);
+ return transchar_buf;
+ }
+ return transchar(c);
+}
+
+/*
+ * Convert non-printable character to two or more printable characters in
+ * "buf[]". "buf" needs to be able to hold five bytes.
+ * Does NOT work for multi-byte characters, c must be <= 255.
+ */
+ void
+transchar_nonprint(char_u *buf, int c)
+{
+ if (c == NL)
+ c = NUL; /* we use newline in place of a NUL */
+ else if (c == CAR && get_fileformat(curbuf) == EOL_MAC)
+ c = NL; /* we use CR in place of NL in this case */
+
+ if (dy_flags & DY_UHEX) /* 'display' has "uhex" */
+ transchar_hex(buf, c);
+
+#ifdef EBCDIC
+ /* For EBCDIC only the characters 0-63 and 255 are not printable */
+ else if (CtrlChar(c) != 0 || c == DEL)
+#else
+ else if (c <= 0x7f) /* 0x00 - 0x1f and 0x7f */
+#endif
+ {
+ buf[0] = '^';
+#ifdef EBCDIC
+ if (c == DEL)
+ buf[1] = '?'; /* DEL displayed as ^? */
+ else
+ buf[1] = CtrlChar(c);
+#else
+ buf[1] = c ^ 0x40; /* DEL displayed as ^? */
+#endif
+
+ buf[2] = NUL;
+ }
+ else if (enc_utf8 && c >= 0x80)
+ {
+ transchar_hex(buf, c);
+ }
+#ifndef EBCDIC
+ else if (c >= ' ' + 0x80 && c <= '~' + 0x80) /* 0xa0 - 0xfe */
+ {
+ buf[0] = '|';
+ buf[1] = c - 0x80;
+ buf[2] = NUL;
+ }
+#else
+ else if (c < 64)
+ {
+ buf[0] = '~';
+ buf[1] = MetaChar(c);
+ buf[2] = NUL;
+ }
+#endif
+ else /* 0x80 - 0x9f and 0xff */
+ {
+ /*
+ * TODO: EBCDIC I don't know what to do with this chars, so I display
+ * them as '~?' for now
+ */
+ buf[0] = '~';
+#ifdef EBCDIC
+ buf[1] = '?'; /* 0xff displayed as ~? */
+#else
+ buf[1] = (c - 0x80) ^ 0x40; /* 0xff displayed as ~? */
+#endif
+ buf[2] = NUL;
+ }
+}
+
+ void
+transchar_hex(char_u *buf, int c)
+{
+ int i = 0;
+
+ buf[0] = '<';
+ if (c > 255)
+ {
+ buf[++i] = nr2hex((unsigned)c >> 12);
+ buf[++i] = nr2hex((unsigned)c >> 8);
+ }
+ buf[++i] = nr2hex((unsigned)c >> 4);
+ buf[++i] = nr2hex((unsigned)c);
+ buf[++i] = '>';
+ buf[++i] = NUL;
+}
+
+/*
+ * Convert the lower 4 bits of byte "c" to its hex character.
+ * Lower case letters are used to avoid the confusion of <F1> being 0xf1 or
+ * function key 1.
+ */
+ static unsigned
+nr2hex(unsigned c)
+{
+ if ((c & 0xf) <= 9)
+ return (c & 0xf) + '0';
+ return (c & 0xf) - 10 + 'a';
+}
+
+/*
+ * Return number of display cells occupied by byte "b".
+ * Caller must make sure 0 <= b <= 255.
+ * For multi-byte mode "b" must be the first byte of a character.
+ * A TAB is counted as two cells: "^I".
+ * For UTF-8 mode this will return 0 for bytes >= 0x80, because the number of
+ * cells depends on further bytes.
+ */
+ int
+byte2cells(int b)
+{
+ if (enc_utf8 && b >= 0x80)
+ return 0;
+ return (g_chartab[b] & CT_CELL_MASK);
+}
+
+/*
+ * Return number of display cells occupied by character "c".
+ * "c" can be a special key (negative number) in which case 3 or 4 is returned.
+ * A TAB is counted as two cells: "^I" or four: "<09>".
+ */
+ int
+char2cells(int c)
+{
+ if (IS_SPECIAL(c))
+ return char2cells(K_SECOND(c)) + 2;
+ if (c >= 0x80)
+ {
+ /* UTF-8: above 0x80 need to check the value */
+ if (enc_utf8)
+ return utf_char2cells(c);
+ /* DBCS: double-byte means double-width, except for euc-jp with first
+ * byte 0x8e */
+ if (enc_dbcs != 0 && c >= 0x100)
+ {
+ if (enc_dbcs == DBCS_JPNU && ((unsigned)c >> 8) == 0x8e)
+ return 1;
+ return 2;
+ }
+ }
+ return (g_chartab[c & 0xff] & CT_CELL_MASK);
+}
+
+/*
+ * Return number of display cells occupied by character at "*p".
+ * A TAB is counted as two cells: "^I" or four: "<09>".
+ */
+ int
+ptr2cells(char_u *p)
+{
+ /* For UTF-8 we need to look at more bytes if the first byte is >= 0x80. */
+ if (enc_utf8 && *p >= 0x80)
+ return utf_ptr2cells(p);
+ /* For DBCS we can tell the cell count from the first byte. */
+ return (g_chartab[*p] & CT_CELL_MASK);
+}
+
+/*
+ * Return the number of character cells string "s" will take on the screen,
+ * counting TABs as two characters: "^I".
+ */
+ int
+vim_strsize(char_u *s)
+{
+ return vim_strnsize(s, (int)MAXCOL);
+}
+
+/*
+ * Return the number of character cells string "s[len]" will take on the
+ * screen, counting TABs as two characters: "^I".
+ */
+ int
+vim_strnsize(char_u *s, int len)
+{
+ int size = 0;
+
+ while (*s != NUL && --len >= 0)
+ if (has_mbyte)
+ {
+ int l = (*mb_ptr2len)(s);
+
+ size += ptr2cells(s);
+ s += l;
+ len -= l - 1;
+ }
+ else
+ size += byte2cells(*s++);
+
+ return size;
+}
+
+/*
+ * Return the number of characters 'c' will take on the screen, taking
+ * into account the size of a tab.
+ * Use a define to make it fast, this is used very often!!!
+ * Also see getvcol() below.
+ */
+
+#ifdef FEAT_VARTABS
+# define RET_WIN_BUF_CHARTABSIZE(wp, buf, p, col) \
+ if (*(p) == TAB && (!(wp)->w_p_list || lcs_tab1)) \
+ { \
+ return tabstop_padding(col, (buf)->b_p_ts, (buf)->b_p_vts_array); \
+ } \
+ else \
+ return ptr2cells(p);
+#else
+# define RET_WIN_BUF_CHARTABSIZE(wp, buf, p, col) \
+ if (*(p) == TAB && (!(wp)->w_p_list || lcs_tab1)) \
+ { \
+ int ts; \
+ ts = (buf)->b_p_ts; \
+ return (int)(ts - (col % ts)); \
+ } \
+ else \
+ return ptr2cells(p);
+#endif
+
+ int
+chartabsize(char_u *p, colnr_T col)
+{
+ RET_WIN_BUF_CHARTABSIZE(curwin, curbuf, p, col)
+}
+
+#ifdef FEAT_LINEBREAK
+ static int
+win_chartabsize(win_T *wp, char_u *p, colnr_T col)
+{
+ RET_WIN_BUF_CHARTABSIZE(wp, wp->w_buffer, p, col)
+}
+#endif
+
+/*
+ * Return the number of characters the string 's' will take on the screen,
+ * taking into account the size of a tab.
+ */
+ int
+linetabsize(char_u *s)
+{
+ return linetabsize_col(0, s);
+}
+
+/*
+ * Like linetabsize(), but starting at column "startcol".
+ */
+ int
+linetabsize_col(int startcol, char_u *s)
+{
+ colnr_T col = startcol;
+ char_u *line = s; /* pointer to start of line, for breakindent */
+
+ while (*s != NUL)
+ col += lbr_chartabsize_adv(line, &s, col);
+ return (int)col;
+}
+
+/*
+ * Like linetabsize(), but for a given window instead of the current one.
+ */
+ int
+win_linetabsize(win_T *wp, char_u *line, colnr_T len)
+{
+ colnr_T col = 0;
+ char_u *s;
+
+ for (s = line; *s != NUL && (len == MAXCOL || s < line + len);
+ MB_PTR_ADV(s))
+ col += win_lbr_chartabsize(wp, line, s, col, NULL);
+ return (int)col;
+}
+
+/*
+ * Return TRUE if 'c' is a normal identifier character:
+ * Letters and characters from the 'isident' option.
+ */
+ int
+vim_isIDc(int c)
+{
+ return (c > 0 && c < 0x100 && (g_chartab[c] & CT_ID_CHAR));
+}
+
+/*
+ * return TRUE if 'c' is a keyword character: Letters and characters from
+ * 'iskeyword' option for the current buffer.
+ * For multi-byte characters mb_get_class() is used (builtin rules).
+ */
+ int
+vim_iswordc(int c)
+{
+ return vim_iswordc_buf(c, curbuf);
+}
+
+ int
+vim_iswordc_buf(int c, buf_T *buf)
+{
+ if (c >= 0x100)
+ {
+ if (enc_dbcs != 0)
+ return dbcs_class((unsigned)c >> 8, (unsigned)(c & 0xff)) >= 2;
+ if (enc_utf8)
+ return utf_class_buf(c, buf) >= 2;
+ return FALSE;
+ }
+ return (c > 0 && GET_CHARTAB(buf, c) != 0);
+}
+
+/*
+ * Just like vim_iswordc() but uses a pointer to the (multi-byte) character.
+ */
+ int
+vim_iswordp(char_u *p)
+{
+ return vim_iswordp_buf(p, curbuf);
+}
+
+ int
+vim_iswordp_buf(char_u *p, buf_T *buf)
+{
+ int c = *p;
+
+ if (has_mbyte && MB_BYTE2LEN(c) > 1)
+ c = (*mb_ptr2char)(p);
+ return vim_iswordc_buf(c, buf);
+}
+
+/*
+ * return TRUE if 'c' is a valid file-name character
+ * Assume characters above 0x100 are valid (multi-byte).
+ */
+ int
+vim_isfilec(int c)
+{
+ return (c >= 0x100 || (c > 0 && (g_chartab[c] & CT_FNAME_CHAR)));
+}
+
+/*
+ * return TRUE if 'c' is a valid file-name character or a wildcard character
+ * Assume characters above 0x100 are valid (multi-byte).
+ * Explicitly interpret ']' as a wildcard character as mch_has_wildcard("]")
+ * returns false.
+ */
+ int
+vim_isfilec_or_wc(int c)
+{
+ char_u buf[2];
+
+ buf[0] = (char_u)c;
+ buf[1] = NUL;
+ return vim_isfilec(c) || c == ']' || mch_has_wildcard(buf);
+}
+
+/*
+ * Return TRUE if 'c' is a printable character.
+ * Assume characters above 0x100 are printable (multi-byte), except for
+ * Unicode.
+ */
+ int
+vim_isprintc(int c)
+{
+ if (enc_utf8 && c >= 0x100)
+ return utf_printable(c);
+ return (c >= 0x100 || (c > 0 && (g_chartab[c] & CT_PRINT_CHAR)));
+}
+
+/*
+ * Strict version of vim_isprintc(c), don't return TRUE if "c" is the head
+ * byte of a double-byte character.
+ */
+ int
+vim_isprintc_strict(int c)
+{
+ if (enc_dbcs != 0 && c < 0x100 && MB_BYTE2LEN(c) > 1)
+ return FALSE;
+ if (enc_utf8 && c >= 0x100)
+ return utf_printable(c);
+ return (c >= 0x100 || (c > 0 && (g_chartab[c] & CT_PRINT_CHAR)));
+}
+
+/*
+ * like chartabsize(), but also check for line breaks on the screen
+ */
+ int
+lbr_chartabsize(
+ char_u *line UNUSED, /* start of the line */
+ unsigned char *s,
+ colnr_T col)
+{
+#ifdef FEAT_LINEBREAK
+ if (!curwin->w_p_lbr && *p_sbr == NUL && !curwin->w_p_bri)
+ {
+#endif
+ if (curwin->w_p_wrap)
+ return win_nolbr_chartabsize(curwin, s, col, NULL);
+ RET_WIN_BUF_CHARTABSIZE(curwin, curbuf, s, col)
+#ifdef FEAT_LINEBREAK
+ }
+ return win_lbr_chartabsize(curwin, line == NULL ? s : line, s, col, NULL);
+#endif
+}
+
+/*
+ * Call lbr_chartabsize() and advance the pointer.
+ */
+ int
+lbr_chartabsize_adv(
+ char_u *line, /* start of the line */
+ char_u **s,
+ colnr_T col)
+{
+ int retval;
+
+ retval = lbr_chartabsize(line, *s, col);
+ MB_PTR_ADV(*s);
+ return retval;
+}
+
+/*
+ * This function is used very often, keep it fast!!!!
+ *
+ * If "headp" not NULL, set *headp to the size of what we for 'showbreak'
+ * string at start of line. Warning: *headp is only set if it's a non-zero
+ * value, init to 0 before calling.
+ */
+ int
+win_lbr_chartabsize(
+ win_T *wp,
+ char_u *line UNUSED, /* start of the line */
+ char_u *s,
+ colnr_T col,
+ int *headp UNUSED)
+{
+#ifdef FEAT_LINEBREAK
+ int c;
+ int size;
+ colnr_T col2;
+ colnr_T col_adj = 0; /* col + screen size of tab */
+ colnr_T colmax;
+ int added;
+ int mb_added = 0;
+ int numberextra;
+ char_u *ps;
+ int tab_corr = (*s == TAB);
+ int n;
+
+ /*
+ * No 'linebreak', 'showbreak' and 'breakindent': return quickly.
+ */
+ if (!wp->w_p_lbr && !wp->w_p_bri && *p_sbr == NUL)
+#endif
+ {
+ if (wp->w_p_wrap)
+ return win_nolbr_chartabsize(wp, s, col, headp);
+ RET_WIN_BUF_CHARTABSIZE(wp, wp->w_buffer, s, col)
+ }
+
+#ifdef FEAT_LINEBREAK
+ /*
+ * First get normal size, without 'linebreak'
+ */
+ size = win_chartabsize(wp, s, col);
+ c = *s;
+ if (tab_corr)
+ col_adj = size - 1;
+
+ /*
+ * If 'linebreak' set check at a blank before a non-blank if the line
+ * needs a break here
+ */
+ if (wp->w_p_lbr
+ && VIM_ISBREAK(c)
+ && !VIM_ISBREAK((int)s[1])
+ && wp->w_p_wrap
+ && wp->w_width != 0)
+ {
+ /*
+ * Count all characters from first non-blank after a blank up to next
+ * non-blank after a blank.
+ */
+ numberextra = win_col_off(wp);
+ col2 = col;
+ colmax = (colnr_T)(wp->w_width - numberextra - col_adj);
+ if (col >= colmax)
+ {
+ colmax += col_adj;
+ n = colmax + win_col_off2(wp);
+ if (n > 0)
+ colmax += (((col - colmax) / n) + 1) * n - col_adj;
+ }
+
+ for (;;)
+ {
+ ps = s;
+ MB_PTR_ADV(s);
+ c = *s;
+ if (!(c != NUL
+ && (VIM_ISBREAK(c)
+ || (!VIM_ISBREAK(c)
+ && (col2 == col || !VIM_ISBREAK((int)*ps))))))
+ break;
+
+ col2 += win_chartabsize(wp, s, col2);
+ if (col2 >= colmax) /* doesn't fit */
+ {
+ size = colmax - col + col_adj;
+ tab_corr = FALSE;
+ break;
+ }
+ }
+ }
+ else if (has_mbyte && size == 2 && MB_BYTE2LEN(*s) > 1
+ && wp->w_p_wrap && in_win_border(wp, col))
+ {
+ ++size; /* Count the ">" in the last column. */
+ mb_added = 1;
+ }
+
+ /*
+ * May have to add something for 'breakindent' and/or 'showbreak'
+ * string at start of line.
+ * Set *headp to the size of what we add.
+ */
+ added = 0;
+ if ((*p_sbr != NUL || wp->w_p_bri) && wp->w_p_wrap && col != 0)
+ {
+ colnr_T sbrlen = 0;
+ int numberwidth = win_col_off(wp);
+
+ numberextra = numberwidth;
+ col += numberextra + mb_added;
+ if (col >= (colnr_T)wp->w_width)
+ {
+ col -= wp->w_width;
+ numberextra = wp->w_width - (numberextra - win_col_off2(wp));
+ if (col >= numberextra && numberextra > 0)
+ col %= numberextra;
+ if (*p_sbr != NUL)
+ {
+ sbrlen = (colnr_T)MB_CHARLEN(p_sbr);
+ if (col >= sbrlen)
+ col -= sbrlen;
+ }
+ if (col >= numberextra && numberextra > 0)
+ col = col % numberextra;
+ else if (col > 0 && numberextra > 0)
+ col += numberwidth - win_col_off2(wp);
+
+ numberwidth -= win_col_off2(wp);
+ }
+ if (col == 0 || col + size + sbrlen > (colnr_T)wp->w_width)
+ {
+ added = 0;
+ if (*p_sbr != NUL)
+ {
+ if (size + sbrlen + numberwidth > (colnr_T)wp->w_width)
+ {
+ /* calculate effective window width */
+ int width = (colnr_T)wp->w_width - sbrlen - numberwidth;
+ int prev_width = col ? ((colnr_T)wp->w_width - (sbrlen + col)) : 0;
+ if (width == 0)
+ width = (colnr_T)wp->w_width;
+ added += ((size - prev_width) / width) * vim_strsize(p_sbr);
+ if ((size - prev_width) % width)
+ /* wrapped, add another length of 'sbr' */
+ added += vim_strsize(p_sbr);
+ }
+ else
+ added += vim_strsize(p_sbr);
+ }
+ if (wp->w_p_bri)
+ added += get_breakindent_win(wp, line);
+
+ size += added;
+ if (col != 0)
+ added = 0;
+ }
+ }
+ if (headp != NULL)
+ *headp = added + mb_added;
+ return size;
+#endif
+}
+
+/*
+ * Like win_lbr_chartabsize(), except that we know 'linebreak' is off and
+ * 'wrap' is on. This means we need to check for a double-byte character that
+ * doesn't fit at the end of the screen line.
+ */
+ static int
+win_nolbr_chartabsize(
+ win_T *wp,
+ char_u *s,
+ colnr_T col,
+ int *headp)
+{
+ int n;
+
+ if (*s == TAB && (!wp->w_p_list || lcs_tab1))
+ {
+# ifdef FEAT_VARTABS
+ return tabstop_padding(col, wp->w_buffer->b_p_ts,
+ wp->w_buffer->b_p_vts_array);
+# else
+ n = wp->w_buffer->b_p_ts;
+ return (int)(n - (col % n));
+# endif
+ }
+ n = ptr2cells(s);
+ /* Add one cell for a double-width character in the last column of the
+ * window, displayed with a ">". */
+ if (n == 2 && MB_BYTE2LEN(*s) > 1 && in_win_border(wp, col))
+ {
+ if (headp != NULL)
+ *headp = 1;
+ return 3;
+ }
+ return n;
+}
+
+/*
+ * Return TRUE if virtual column "vcol" is in the rightmost column of window
+ * "wp".
+ */
+ int
+in_win_border(win_T *wp, colnr_T vcol)
+{
+ int width1; /* width of first line (after line number) */
+ int width2; /* width of further lines */
+
+ if (wp->w_width == 0) /* there is no border */
+ return FALSE;
+ width1 = wp->w_width - win_col_off(wp);
+ if ((int)vcol < width1 - 1)
+ return FALSE;
+ if ((int)vcol == width1 - 1)
+ return TRUE;
+ width2 = width1 + win_col_off2(wp);
+ if (width2 <= 0)
+ return FALSE;
+ return ((vcol - width1) % width2 == width2 - 1);
+}
+
+/*
+ * Get virtual column number of pos.
+ * start: on the first position of this character (TAB, ctrl)
+ * cursor: where the cursor is on this character (first char, except for TAB)
+ * end: on the last position of this character (TAB, ctrl)
+ *
+ * This is used very often, keep it fast!
+ */
+ void
+getvcol(
+ win_T *wp,
+ pos_T *pos,
+ colnr_T *start,
+ colnr_T *cursor,
+ colnr_T *end)
+{
+ colnr_T vcol;
+ char_u *ptr; /* points to current char */
+ char_u *posptr; /* points to char at pos->col */
+ char_u *line; /* start of the line */
+ int incr;
+ int head;
+#ifdef FEAT_VARTABS
+ int *vts = wp->w_buffer->b_p_vts_array;
+#endif
+ int ts = wp->w_buffer->b_p_ts;
+ int c;
+
+ vcol = 0;
+ line = ptr = ml_get_buf(wp->w_buffer, pos->lnum, FALSE);
+ if (pos->col == MAXCOL)
+ posptr = NULL; /* continue until the NUL */
+ else
+ {
+ /* Special check for an empty line, which can happen on exit, when
+ * ml_get_buf() always returns an empty string. */
+ if (*ptr == NUL)
+ pos->col = 0;
+ posptr = ptr + pos->col;
+ if (has_mbyte)
+ /* always start on the first byte */
+ posptr -= (*mb_head_off)(line, posptr);
+ }
+
+ /*
+ * This function is used very often, do some speed optimizations.
+ * When 'list', 'linebreak', 'showbreak' and 'breakindent' are not set
+ * use a simple loop.
+ * Also use this when 'list' is set but tabs take their normal size.
+ */
+ if ((!wp->w_p_list || lcs_tab1 != NUL)
+#ifdef FEAT_LINEBREAK
+ && !wp->w_p_lbr && *p_sbr == NUL && !wp->w_p_bri
+#endif
+ )
+ {
+ for (;;)
+ {
+ head = 0;
+ c = *ptr;
+ /* make sure we don't go past the end of the line */
+ if (c == NUL)
+ {
+ incr = 1; /* NUL at end of line only takes one column */
+ break;
+ }
+ /* A tab gets expanded, depending on the current column */
+ if (c == TAB)
+#ifdef FEAT_VARTABS
+ incr = tabstop_padding(vcol, ts, vts);
+#else
+ incr = ts - (vcol % ts);
+#endif
+ else
+ {
+ if (has_mbyte)
+ {
+ /* For utf-8, if the byte is >= 0x80, need to look at
+ * further bytes to find the cell width. */
+ if (enc_utf8 && c >= 0x80)
+ incr = utf_ptr2cells(ptr);
+ else
+ incr = g_chartab[c] & CT_CELL_MASK;
+
+ /* If a double-cell char doesn't fit at the end of a line
+ * it wraps to the next line, it's like this char is three
+ * cells wide. */
+ if (incr == 2 && wp->w_p_wrap && MB_BYTE2LEN(*ptr) > 1
+ && in_win_border(wp, vcol))
+ {
+ ++incr;
+ head = 1;
+ }
+ }
+ else
+ incr = g_chartab[c] & CT_CELL_MASK;
+ }
+
+ if (posptr != NULL && ptr >= posptr) /* character at pos->col */
+ break;
+
+ vcol += incr;
+ MB_PTR_ADV(ptr);
+ }
+ }
+ else
+ {
+ for (;;)
+ {
+ /* A tab gets expanded, depending on the current column */
+ head = 0;
+ incr = win_lbr_chartabsize(wp, line, ptr, vcol, &head);
+ /* make sure we don't go past the end of the line */
+ if (*ptr == NUL)
+ {
+ incr = 1; /* NUL at end of line only takes one column */
+ break;
+ }
+
+ if (posptr != NULL && ptr >= posptr) /* character at pos->col */
+ break;
+
+ vcol += incr;
+ MB_PTR_ADV(ptr);
+ }
+ }
+ if (start != NULL)
+ *start = vcol + head;
+ if (end != NULL)
+ *end = vcol + incr - 1;
+ if (cursor != NULL)
+ {
+ if (*ptr == TAB
+ && (State & NORMAL)
+ && !wp->w_p_list
+ && !virtual_active()
+ && !(VIsual_active
+ && (*p_sel == 'e' || LTOREQ_POS(*pos, VIsual)))
+ )
+ *cursor = vcol + incr - 1; /* cursor at end */
+ else
+ *cursor = vcol + head; /* cursor at start */
+ }
+}
+
+/*
+ * Get virtual cursor column in the current window, pretending 'list' is off.
+ */
+ colnr_T
+getvcol_nolist(pos_T *posp)
+{
+ int list_save = curwin->w_p_list;
+ colnr_T vcol;
+
+ curwin->w_p_list = FALSE;
+ if (posp->coladd)
+ getvvcol(curwin, posp, NULL, &vcol, NULL);
+ else
+ getvcol(curwin, posp, NULL, &vcol, NULL);
+ curwin->w_p_list = list_save;
+ return vcol;
+}
+
+/*
+ * Get virtual column in virtual mode.
+ */
+ void
+getvvcol(
+ win_T *wp,
+ pos_T *pos,
+ colnr_T *start,
+ colnr_T *cursor,
+ colnr_T *end)
+{
+ colnr_T col;
+ colnr_T coladd;
+ colnr_T endadd;
+ char_u *ptr;
+
+ if (virtual_active())
+ {
+ /* For virtual mode, only want one value */
+ getvcol(wp, pos, &col, NULL, NULL);
+
+ coladd = pos->coladd;
+ endadd = 0;
+ /* Cannot put the cursor on part of a wide character. */
+ ptr = ml_get_buf(wp->w_buffer, pos->lnum, FALSE);
+ if (pos->col < (colnr_T)STRLEN(ptr))
+ {
+ int c = (*mb_ptr2char)(ptr + pos->col);
+
+ if (c != TAB && vim_isprintc(c))
+ {
+ endadd = (colnr_T)(char2cells(c) - 1);
+ if (coladd > endadd) /* past end of line */
+ endadd = 0;
+ else
+ coladd = 0;
+ }
+ }
+ col += coladd;
+ if (start != NULL)
+ *start = col;
+ if (cursor != NULL)
+ *cursor = col;
+ if (end != NULL)
+ *end = col + endadd;
+ }
+ else
+ getvcol(wp, pos, start, cursor, end);
+}
+
+/*
+ * Get the leftmost and rightmost virtual column of pos1 and pos2.
+ * Used for Visual block mode.
+ */
+ void
+getvcols(
+ win_T *wp,
+ pos_T *pos1,
+ pos_T *pos2,
+ colnr_T *left,
+ colnr_T *right)
+{
+ colnr_T from1, from2, to1, to2;
+
+ if (LT_POSP(pos1, pos2))
+ {
+ getvvcol(wp, pos1, &from1, NULL, &to1);
+ getvvcol(wp, pos2, &from2, NULL, &to2);
+ }
+ else
+ {
+ getvvcol(wp, pos2, &from1, NULL, &to1);
+ getvvcol(wp, pos1, &from2, NULL, &to2);
+ }
+ if (from2 < from1)
+ *left = from2;
+ else
+ *left = from1;
+ if (to2 > to1)
+ {
+ if (*p_sel == 'e' && from2 - 1 >= to1)
+ *right = from2 - 1;
+ else
+ *right = to2;
+ }
+ else
+ *right = to1;
+}
+
+/*
+ * skipwhite: skip over ' ' and '\t'.
+ */
+ char_u *
+skipwhite(char_u *q)
+{
+ char_u *p = q;
+
+ while (VIM_ISWHITE(*p)) /* skip to next non-white */
+ ++p;
+ return p;
+}
+
+/*
+ * getwhitecols: return the number of whitespace
+ * columns (bytes) at the start of a given line
+ */
+ int
+getwhitecols_curline()
+{
+ return getwhitecols(ml_get_curline());
+}
+
+ int
+getwhitecols(char_u *p)
+{
+ return skipwhite(p) - p;
+}
+
+/*
+ * skip over digits
+ */
+ char_u *
+skipdigits(char_u *q)
+{
+ char_u *p = q;
+
+ while (VIM_ISDIGIT(*p)) /* skip to next non-digit */
+ ++p;
+ return p;
+}
+
+#if defined(FEAT_SYN_HL) || defined(FEAT_SPELL) || defined(PROTO)
+/*
+ * skip over binary digits
+ */
+ char_u *
+skipbin(char_u *q)
+{
+ char_u *p = q;
+
+ while (vim_isbdigit(*p)) /* skip to next non-digit */
+ ++p;
+ return p;
+}
+
+/*
+ * skip over digits and hex characters
+ */
+ char_u *
+skiphex(char_u *q)
+{
+ char_u *p = q;
+
+ while (vim_isxdigit(*p)) /* skip to next non-digit */
+ ++p;
+ return p;
+}
+#endif
+
+/*
+ * skip to bin digit (or NUL after the string)
+ */
+ char_u *
+skiptobin(char_u *q)
+{
+ char_u *p = q;
+
+ while (*p != NUL && !vim_isbdigit(*p)) /* skip to next digit */
+ ++p;
+ return p;
+}
+
+/*
+ * skip to digit (or NUL after the string)
+ */
+ char_u *
+skiptodigit(char_u *q)
+{
+ char_u *p = q;
+
+ while (*p != NUL && !VIM_ISDIGIT(*p)) /* skip to next digit */
+ ++p;
+ return p;
+}
+
+/*
+ * skip to hex character (or NUL after the string)
+ */
+ char_u *
+skiptohex(char_u *q)
+{
+ char_u *p = q;
+
+ while (*p != NUL && !vim_isxdigit(*p)) /* skip to next digit */
+ ++p;
+ return p;
+}
+
+/*
+ * Variant of isdigit() that can handle characters > 0x100.
+ * We don't use isdigit() here, because on some systems it also considers
+ * superscript 1 to be a digit.
+ * Use the VIM_ISDIGIT() macro for simple arguments.
+ */
+ int
+vim_isdigit(int c)
+{
+ return (c >= '0' && c <= '9');
+}
+
+/*
+ * Variant of isxdigit() that can handle characters > 0x100.
+ * We don't use isxdigit() here, because on some systems it also considers
+ * superscript 1 to be a digit.
+ */
+ int
+vim_isxdigit(int c)
+{
+ return (c >= '0' && c <= '9')
+ || (c >= 'a' && c <= 'f')
+ || (c >= 'A' && c <= 'F');
+}
+
+/*
+ * Corollary of vim_isdigit and vim_isxdigit() that can handle
+ * characters > 0x100.
+ */
+ int
+vim_isbdigit(int c)
+{
+ return (c == '0' || c == '1');
+}
+
+/*
+ * Vim's own character class functions. These exist because many library
+ * islower()/toupper() etc. do not work properly: they crash when used with
+ * invalid values or can't handle latin1 when the locale is C.
+ * Speed is most important here.
+ */
+#define LATIN1LOWER 'l'
+#define LATIN1UPPER 'U'
+
+static char_u latin1flags[257] = " UUUUUUUUUUUUUUUUUUUUUUUUUU llllllllllllllllllllllllll UUUUUUUUUUUUUUUUUUUUUUU UUUUUUUllllllllllllllllllllllll llllllll";
+static char_u latin1upper[257] = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`ABCDEFGHIJKLMNOPQRSTUVWXYZ{|}~\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xf7\xd8\xd9\xda\xdb\xdc\xdd\xde\xff";
+static char_u latin1lower[257] = " !\"#$%&'()*+,-./0123456789:;<=>?@abcdefghijklmnopqrstuvwxyz[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xd7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff";
+
+ int
+vim_islower(int c)
+{
+ if (c <= '@')
+ return FALSE;
+ if (c >= 0x80)
+ {
+ if (enc_utf8)
+ return utf_islower(c);
+ if (c >= 0x100)
+ {
+#ifdef HAVE_ISWLOWER
+ if (has_mbyte)
+ return iswlower(c);
+#endif
+ /* islower() can't handle these chars and may crash */
+ return FALSE;
+ }
+ if (enc_latin1like)
+ return (latin1flags[c] & LATIN1LOWER) == LATIN1LOWER;
+ }
+ return islower(c);
+}
+
+ int
+vim_isupper(int c)
+{
+ if (c <= '@')
+ return FALSE;
+ if (c >= 0x80)
+ {
+ if (enc_utf8)
+ return utf_isupper(c);
+ if (c >= 0x100)
+ {
+#ifdef HAVE_ISWUPPER
+ if (has_mbyte)
+ return iswupper(c);
+#endif
+ /* islower() can't handle these chars and may crash */
+ return FALSE;
+ }
+ if (enc_latin1like)
+ return (latin1flags[c] & LATIN1UPPER) == LATIN1UPPER;
+ }
+ return isupper(c);
+}
+
+ int
+vim_toupper(int c)
+{
+ if (c <= '@')
+ return c;
+ if (c >= 0x80 || !(cmp_flags & CMP_KEEPASCII))
+ {
+ if (enc_utf8)
+ return utf_toupper(c);
+ if (c >= 0x100)
+ {
+#ifdef HAVE_TOWUPPER
+ if (has_mbyte)
+ return towupper(c);
+#endif
+ /* toupper() can't handle these chars and may crash */
+ return c;
+ }
+ if (enc_latin1like)
+ return latin1upper[c];
+ }
+ if (c < 0x80 && (cmp_flags & CMP_KEEPASCII))
+ return TOUPPER_ASC(c);
+ return TOUPPER_LOC(c);
+}
+
+ int
+vim_tolower(int c)
+{
+ if (c <= '@')
+ return c;
+ if (c >= 0x80 || !(cmp_flags & CMP_KEEPASCII))
+ {
+ if (enc_utf8)
+ return utf_tolower(c);
+ if (c >= 0x100)
+ {
+#ifdef HAVE_TOWLOWER
+ if (has_mbyte)
+ return towlower(c);
+#endif
+ /* tolower() can't handle these chars and may crash */
+ return c;
+ }
+ if (enc_latin1like)
+ return latin1lower[c];
+ }
+ if (c < 0x80 && (cmp_flags & CMP_KEEPASCII))
+ return TOLOWER_ASC(c);
+ return TOLOWER_LOC(c);
+}
+
+/*
+ * skiptowhite: skip over text until ' ' or '\t' or NUL.
+ */
+ char_u *
+skiptowhite(char_u *p)
+{
+ while (*p != ' ' && *p != '\t' && *p != NUL)
+ ++p;
+ return p;
+}
+
+/*
+ * skiptowhite_esc: Like skiptowhite(), but also skip escaped chars
+ */
+ char_u *
+skiptowhite_esc(char_u *p)
+{
+ while (*p != ' ' && *p != '\t' && *p != NUL)
+ {
+ if ((*p == '\\' || *p == Ctrl_V) && *(p + 1) != NUL)
+ ++p;
+ ++p;
+ }
+ return p;
+}
+
+/*
+ * Getdigits: Get a number from a string and skip over it.
+ * Note: the argument is a pointer to a char_u pointer!
+ */
+ long
+getdigits(char_u **pp)
+{
+ char_u *p;
+ long retval;
+
+ p = *pp;
+ retval = atol((char *)p);
+ if (*p == '-') /* skip negative sign */
+ ++p;
+ p = skipdigits(p); /* skip to next non-digit */
+ *pp = p;
+ return retval;
+}
+
+/*
+ * Return TRUE if "lbuf" is empty or only contains blanks.
+ */
+ int
+vim_isblankline(char_u *lbuf)
+{
+ char_u *p;
+
+ p = skipwhite(lbuf);
+ return (*p == NUL || *p == '\r' || *p == '\n');
+}
+
+/*
+ * Convert a string into a long and/or unsigned long, taking care of
+ * hexadecimal, octal, and binary numbers. Accepts a '-' sign.
+ * If "prep" is not NULL, returns a flag to indicate the type of the number:
+ * 0 decimal
+ * '0' octal
+ * 'B' bin
+ * 'b' bin
+ * 'X' hex
+ * 'x' hex
+ * If "len" is not NULL, the length of the number in characters is returned.
+ * If "nptr" is not NULL, the signed result is returned in it.
+ * If "unptr" is not NULL, the unsigned result is returned in it.
+ * If "what" contains STR2NR_BIN recognize binary numbers
+ * If "what" contains STR2NR_OCT recognize octal numbers
+ * If "what" contains STR2NR_HEX recognize hex numbers
+ * If "what" contains STR2NR_FORCE always assume bin/oct/hex.
+ * If maxlen > 0, check at a maximum maxlen chars.
+ */
+ void
+vim_str2nr(
+ char_u *start,
+ int *prep, /* return: type of number 0 = decimal, 'x'
+ or 'X' is hex, '0' = octal, 'b' or 'B'
+ is bin */
+ int *len, /* return: detected length of number */
+ int what, /* what numbers to recognize */
+ varnumber_T *nptr, /* return: signed result */
+ uvarnumber_T *unptr, /* return: unsigned result */
+ int maxlen) /* max length of string to check */
+{
+ char_u *ptr = start;
+ int pre = 0; /* default is decimal */
+ int negative = FALSE;
+ uvarnumber_T un = 0;
+ int n;
+
+ if (ptr[0] == '-')
+ {
+ negative = TRUE;
+ ++ptr;
+ }
+
+ /* Recognize hex, octal, and bin. */
+ if (ptr[0] == '0' && ptr[1] != '8' && ptr[1] != '9'
+ && (maxlen == 0 || maxlen > 1))
+ {
+ pre = ptr[1];
+ if ((what & STR2NR_HEX)
+ && (pre == 'X' || pre == 'x') && vim_isxdigit(ptr[2])
+ && (maxlen == 0 || maxlen > 2))
+ /* hexadecimal */
+ ptr += 2;
+ else if ((what & STR2NR_BIN)
+ && (pre == 'B' || pre == 'b') && vim_isbdigit(ptr[2])
+ && (maxlen == 0 || maxlen > 2))
+ /* binary */
+ ptr += 2;
+ else
+ {
+ /* decimal or octal, default is decimal */
+ pre = 0;
+ if (what & STR2NR_OCT)
+ {
+ /* Don't interpret "0", "08" or "0129" as octal. */
+ for (n = 1; n != maxlen && VIM_ISDIGIT(ptr[n]); ++n)
+ {
+ if (ptr[n] > '7')
+ {
+ pre = 0; /* can't be octal */
+ break;
+ }
+ pre = '0'; /* assume octal */
+ }
+ }
+ }
+ }
+
+ /*
+ * Do the string-to-numeric conversion "manually" to avoid sscanf quirks.
+ */
+ n = 1;
+ if (pre == 'B' || pre == 'b' || what == STR2NR_BIN + STR2NR_FORCE)
+ {
+ /* bin */
+ if (pre != 0)
+ n += 2; /* skip over "0b" */
+ while ('0' <= *ptr && *ptr <= '1')
+ {
+ /* avoid ubsan error for overflow */
+ if (un <= UVARNUM_MAX / 2)
+ un = 2 * un + (uvarnumber_T)(*ptr - '0');
+ else
+ un = UVARNUM_MAX;
+ ++ptr;
+ if (n++ == maxlen)
+ break;
+ }
+ }
+ else if (pre == '0' || what == STR2NR_OCT + STR2NR_FORCE)
+ {
+ /* octal */
+ while ('0' <= *ptr && *ptr <= '7')
+ {
+ /* avoid ubsan error for overflow */
+ if (un <= UVARNUM_MAX / 8)
+ un = 8 * un + (uvarnumber_T)(*ptr - '0');
+ else
+ un = UVARNUM_MAX;
+ ++ptr;
+ if (n++ == maxlen)
+ break;
+ }
+ }
+ else if (pre != 0 || what == STR2NR_HEX + STR2NR_FORCE)
+ {
+ /* hex */
+ if (pre != 0)
+ n += 2; /* skip over "0x" */
+ while (vim_isxdigit(*ptr))
+ {
+ /* avoid ubsan error for overflow */
+ if (un <= UVARNUM_MAX / 16)
+ un = 16 * un + (uvarnumber_T)hex2nr(*ptr);
+ else
+ un = UVARNUM_MAX;
+ ++ptr;
+ if (n++ == maxlen)
+ break;
+ }
+ }
+ else
+ {
+ /* decimal */
+ while (VIM_ISDIGIT(*ptr))
+ {
+ uvarnumber_T digit = (uvarnumber_T)(*ptr - '0');
+
+ /* avoid ubsan error for overflow */
+ if (un < UVARNUM_MAX / 10
+ || (un == UVARNUM_MAX / 10 && digit <= UVARNUM_MAX % 10))
+ un = 10 * un + digit;
+ else
+ un = UVARNUM_MAX;
+ ++ptr;
+ if (n++ == maxlen)
+ break;
+ }
+ }
+
+ if (prep != NULL)
+ *prep = pre;
+ if (len != NULL)
+ *len = (int)(ptr - start);
+ if (nptr != NULL)
+ {
+ if (negative) /* account for leading '-' for decimal numbers */
+ {
+ /* avoid ubsan error for overflow */
+ if (un > VARNUM_MAX)
+ *nptr = VARNUM_MIN;
+ else
+ *nptr = -(varnumber_T)un;
+ }
+ else
+ {
+ if (un > VARNUM_MAX)
+ un = VARNUM_MAX;
+ *nptr = (varnumber_T)un;
+ }
+ }
+ if (unptr != NULL)
+ *unptr = un;
+}
+
+/*
+ * Return the value of a single hex character.
+ * Only valid when the argument is '0' - '9', 'A' - 'F' or 'a' - 'f'.
+ */
+ int
+hex2nr(int c)
+{
+ if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ if (c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+ return c - '0';
+}
+
+#if defined(FEAT_TERMRESPONSE) || defined(FEAT_GUI_GTK) || defined(PROTO)
+/*
+ * Convert two hex characters to a byte.
+ * Return -1 if one of the characters is not hex.
+ */
+ int
+hexhex2nr(char_u *p)
+{
+ if (!vim_isxdigit(p[0]) || !vim_isxdigit(p[1]))
+ return -1;
+ return (hex2nr(p[0]) << 4) + hex2nr(p[1]);
+}
+#endif
+
+/*
+ * Return TRUE if "str" starts with a backslash that should be removed.
+ * For MS-DOS, WIN32 and OS/2 this is only done when the character after the
+ * backslash is not a normal file name character.
+ * '$' is a valid file name character, we don't remove the backslash before
+ * it. This means it is not possible to use an environment variable after a
+ * backslash. "C:\$VIM\doc" is taken literally, only "$VIM\doc" works.
+ * Although "\ name" is valid, the backslash in "Program\ files" must be
+ * removed. Assume a file name doesn't start with a space.
+ * For multi-byte names, never remove a backslash before a non-ascii
+ * character, assume that all multi-byte characters are valid file name
+ * characters.
+ */
+ int
+rem_backslash(char_u *str)
+{
+#ifdef BACKSLASH_IN_FILENAME
+ return (str[0] == '\\'
+ && str[1] < 0x80
+ && (str[1] == ' '
+ || (str[1] != NUL
+ && str[1] != '*'
+ && str[1] != '?'
+ && !vim_isfilec(str[1]))));
+#else
+ return (str[0] == '\\' && str[1] != NUL);
+#endif
+}
+
+/*
+ * Halve the number of backslashes in a file name argument.
+ * For MS-DOS we only do this if the character after the backslash
+ * is not a normal file character.
+ */
+ void
+backslash_halve(char_u *p)
+{
+ for ( ; *p; ++p)
+ if (rem_backslash(p))
+ STRMOVE(p, p + 1);
+}
+
+/*
+ * backslash_halve() plus save the result in allocated memory.
+ */
+ char_u *
+backslash_halve_save(char_u *p)
+{
+ char_u *res;
+
+ res = vim_strsave(p);
+ if (res == NULL)
+ return p;
+ backslash_halve(res);
+ return res;
+}
+
+#if (defined(EBCDIC) && defined(FEAT_POSTSCRIPT)) || defined(PROTO)
+/*
+ * Table for EBCDIC to ASCII conversion unashamedly taken from xxd.c!
+ * The first 64 entries have been added to map control characters defined in
+ * ascii.h
+ */
+static char_u ebcdic2ascii_tab[256] =
+{
+ 0000, 0001, 0002, 0003, 0004, 0011, 0006, 0177,
+ 0010, 0011, 0012, 0013, 0014, 0015, 0016, 0017,
+ 0020, 0021, 0022, 0023, 0024, 0012, 0010, 0027,
+ 0030, 0031, 0032, 0033, 0033, 0035, 0036, 0037,
+ 0040, 0041, 0042, 0043, 0044, 0045, 0046, 0047,
+ 0050, 0051, 0052, 0053, 0054, 0055, 0056, 0057,
+ 0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067,
+ 0070, 0071, 0072, 0073, 0074, 0075, 0076, 0077,
+ 0040, 0240, 0241, 0242, 0243, 0244, 0245, 0246,
+ 0247, 0250, 0325, 0056, 0074, 0050, 0053, 0174,
+ 0046, 0251, 0252, 0253, 0254, 0255, 0256, 0257,
+ 0260, 0261, 0041, 0044, 0052, 0051, 0073, 0176,
+ 0055, 0057, 0262, 0263, 0264, 0265, 0266, 0267,
+ 0270, 0271, 0313, 0054, 0045, 0137, 0076, 0077,
+ 0272, 0273, 0274, 0275, 0276, 0277, 0300, 0301,
+ 0302, 0140, 0072, 0043, 0100, 0047, 0075, 0042,
+ 0303, 0141, 0142, 0143, 0144, 0145, 0146, 0147,
+ 0150, 0151, 0304, 0305, 0306, 0307, 0310, 0311,
+ 0312, 0152, 0153, 0154, 0155, 0156, 0157, 0160,
+ 0161, 0162, 0136, 0314, 0315, 0316, 0317, 0320,
+ 0321, 0345, 0163, 0164, 0165, 0166, 0167, 0170,
+ 0171, 0172, 0322, 0323, 0324, 0133, 0326, 0327,
+ 0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,
+ 0340, 0341, 0342, 0343, 0344, 0135, 0346, 0347,
+ 0173, 0101, 0102, 0103, 0104, 0105, 0106, 0107,
+ 0110, 0111, 0350, 0351, 0352, 0353, 0354, 0355,
+ 0175, 0112, 0113, 0114, 0115, 0116, 0117, 0120,
+ 0121, 0122, 0356, 0357, 0360, 0361, 0362, 0363,
+ 0134, 0237, 0123, 0124, 0125, 0126, 0127, 0130,
+ 0131, 0132, 0364, 0365, 0366, 0367, 0370, 0371,
+ 0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067,
+ 0070, 0071, 0372, 0373, 0374, 0375, 0376, 0377
+};
+
+/*
+ * Convert a buffer worth of characters from EBCDIC to ASCII. Only useful if
+ * wanting 7-bit ASCII characters out the other end.
+ */
+ void
+ebcdic2ascii(char_u *buffer, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++)
+ buffer[i] = ebcdic2ascii_tab[buffer[i]];
+}
+#endif
diff --git a/src/config.h.in b/src/config.h.in
new file mode 100644
index 0000000..d1aaf70
--- /dev/null
+++ b/src/config.h.in
@@ -0,0 +1,491 @@
+/*
+ * config.h.in. Originally generated automatically from configure.ac by
+ * autoheader and manually changed after that.
+ */
+
+/* Define if we have EBCDIC code */
+#undef EBCDIC
+
+/* Define unless no X support found */
+#undef HAVE_X11
+
+/* Define when terminfo support found */
+#undef TERMINFO
+
+/* Define when termcap.h contains ospeed */
+#undef HAVE_OSPEED
+
+/* Define when ospeed can be extern */
+#undef OSPEED_EXTERN
+
+/* Define when termcap.h contains UP, BC and PC */
+#undef HAVE_UP_BC_PC
+
+/* Define when UP, BC and PC can be extern */
+#undef UP_BC_PC_EXTERN
+
+/* Define when termcap.h defines outfuntype */
+#undef HAVE_OUTFUNTYPE
+
+/* Define when __DATE__ " " __TIME__ can be used */
+#undef HAVE_DATE_TIME
+
+/* Define when __attribute__((unused)) can be used */
+#undef HAVE_ATTRIBUTE_UNUSED
+
+/* defined always when using configure */
+#undef UNIX
+
+/* Defined to the size of an int */
+#undef VIM_SIZEOF_INT
+
+/* Defined to the size of a long */
+#undef VIM_SIZEOF_LONG
+
+/* Defined to the size of off_t */
+#undef SIZEOF_OFF_T
+
+/* Defined to the size of time_t */
+#undef SIZEOF_TIME_T
+
+/* Define when wchar_t is only 2 bytes. */
+#undef SMALL_WCHAR_T
+
+/*
+ * If we cannot trust one of the following from the libraries, we use our
+ * own safe but probably slower vim_memmove().
+ */
+#undef USEBCOPY
+#undef USEMEMMOVE
+#undef USEMEMCPY
+
+/* Define when "man -s 2" is to be used */
+#undef USEMAN_S
+
+/* Define to empty if the keyword does not work. */
+#undef const
+
+/* Define to empty if the keyword does not work. */
+#undef volatile
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef mode_t
+
+/* Define to `long' if <sys/types.h> doesn't define. */
+#undef off_t
+
+/* Define to `long' if <sys/types.h> doesn't define. */
+#undef pid_t
+
+/* Define to `unsigned' if <sys/types.h> doesn't define. */
+#undef size_t
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef uid_t
+
+/* Define to `unsigned int' or other type that is 32 bit. */
+#undef uint32_t
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef gid_t
+
+/* Define to `long' if <sys/types.h> doesn't define. */
+#undef ino_t
+
+/* Define to `unsigned' if <sys/types.h> doesn't define. */
+#undef dev_t
+
+/* Define on big-endian machines */
+#undef WORDS_BIGENDIAN
+
+/* Define to `unsigned long' if <sys/types.h> doesn't define. */
+#undef rlim_t
+
+/* Define to `struct sigaltstack' if <signal.h> doesn't define. */
+#undef stack_t
+
+/* Define if stack_t has the ss_base field. */
+#undef HAVE_SS_BASE
+
+/* Define if you can safely include both <sys/time.h> and <time.h>. */
+#undef TIME_WITH_SYS_TIME
+
+/* Define if you can safely include both <sys/time.h> and <sys/select.h>. */
+#undef SYS_SELECT_WITH_SYS_TIME
+
+/* Define to a typecast for select() arguments 2, 3 and 4. */
+#undef SELECT_TYPE_ARG234
+
+/* Define if you have /dev/ptc */
+#undef HAVE_DEV_PTC
+
+/* Define if you have Sys4 ptys */
+#undef HAVE_SVR4_PTYS
+
+/* Define to range of pty names to try */
+#undef PTYRANGE0
+#undef PTYRANGE1
+
+/* Define mode for pty */
+#undef PTYMODE
+
+/* Define group for pty */
+#undef PTYGROUP
+
+/* Define as the return type of signal handlers (int or void). */
+#undef RETSIGTYPE
+
+/* Define as the command at the end of signal handlers ("" or "return 0;"). */
+#undef SIGRETURN
+
+/* Define if struct sigcontext is present */
+#undef HAVE_SIGCONTEXT
+
+/* Define if touuper/tolower only work on lower/upercase characters */
+#undef BROKEN_TOUPPER
+
+/* Define if stat() ignores a trailing slash */
+#undef STAT_IGNORES_SLASH
+
+/* Define if tgetstr() has a second argument that is (char *) */
+#undef TGETSTR_CHAR_P
+
+/* Define if tgetent() returns zero for an error */
+#undef TGETENT_ZERO_ERR
+
+/* Define if the getcwd() function should not be used. */
+#undef BAD_GETCWD
+
+/* Define if you the function: */
+#undef HAVE_FCHDIR
+#undef HAVE_FCHOWN
+#undef HAVE_FCHMOD
+#undef HAVE_FLOAT_FUNCS
+#undef HAVE_FSEEKO
+#undef HAVE_FSYNC
+#undef HAVE_FTRUNCATE
+#undef HAVE_GETCWD
+#undef HAVE_GETPGID
+#undef HAVE_GETPSEUDOTTY
+#undef HAVE_GETPWENT
+#undef HAVE_GETPWNAM
+#undef HAVE_GETPWUID
+#undef HAVE_GETRLIMIT
+#undef HAVE_GETTIMEOFDAY
+#undef HAVE_GETWD
+#undef HAVE_ICONV
+#undef HAVE_LSTAT
+#undef HAVE_MEMSET
+#undef HAVE_MKDTEMP
+#undef HAVE_NANOSLEEP
+#undef HAVE_NL_LANGINFO_CODESET
+#undef HAVE_OPENDIR
+#undef HAVE_PUTENV
+#undef HAVE_QSORT
+#undef HAVE_READLINK
+#undef HAVE_RENAME
+#undef HAVE_SELECT
+#undef HAVE_SELINUX
+#undef HAVE_SETENV
+#undef HAVE_SETPGID
+#undef HAVE_SETSID
+#undef HAVE_SIGACTION
+#undef HAVE_SIGALTSTACK
+#undef HAVE_SIGSET
+#undef HAVE_SIGSETJMP
+#undef HAVE_SIGSTACK
+#undef HAVE_SIGPROCMASK
+#undef HAVE_SIGVEC
+#undef HAVE_SMACK
+#undef HAVE_STRCASECMP
+#undef HAVE_STRERROR
+#undef HAVE_STRFTIME
+#undef HAVE_STRICMP
+#undef HAVE_STRNCASECMP
+#undef HAVE_STRNICMP
+#undef HAVE_STRPBRK
+#undef HAVE_STRTOL
+#undef HAVE_ST_BLKSIZE
+#undef HAVE_SYSCONF
+#undef HAVE_SYSCTL
+#undef HAVE_SYSINFO
+#undef HAVE_SYSINFO_MEM_UNIT
+#undef HAVE_TGETENT
+#undef HAVE_TOWLOWER
+#undef HAVE_TOWUPPER
+#undef HAVE_ISWUPPER
+#undef HAVE_UNSETENV
+#undef HAVE_USLEEP
+#undef HAVE_UTIME
+#undef HAVE_BIND_TEXTDOMAIN_CODESET
+#undef HAVE_MBLEN
+
+/* Define, if needed, for accessing large files. */
+#undef _LARGE_FILES
+#undef _FILE_OFFSET_BITS
+#undef _LARGEFILE_SOURCE
+
+/* Define if you do not have utime(), but do have the utimes() function. */
+#undef HAVE_UTIMES
+
+/* Define if you have the header file: */
+#undef HAVE_DIRENT_H
+#undef HAVE_ERRNO_H
+#undef HAVE_FCNTL_H
+#undef HAVE_FRAME_H
+#undef HAVE_ICONV_H
+#undef HAVE_INTTYPES_H
+#undef HAVE_LANGINFO_H
+#undef HAVE_LIBC_H
+#undef HAVE_LIBGEN_H
+#undef HAVE_LIBINTL_H
+#undef HAVE_LOCALE_H
+#undef HAVE_MATH_H
+#undef HAVE_NDIR_H
+#undef HAVE_POLL_H
+#undef HAVE_PTHREAD_NP_H
+#undef HAVE_PWD_H
+#undef HAVE_SETJMP_H
+#undef HAVE_SGTTY_H
+#undef HAVE_STDINT_H
+#undef HAVE_STRINGS_H
+#undef HAVE_STROPTS_H
+#undef HAVE_SYS_ACCESS_H
+#undef HAVE_SYS_ACL_H
+#undef HAVE_SYS_DIR_H
+#undef HAVE_SYS_IOCTL_H
+#undef HAVE_SYS_NDIR_H
+#undef HAVE_SYS_PARAM_H
+#undef HAVE_SYS_POLL_H
+#undef HAVE_SYS_PTEM_H
+#undef HAVE_SYS_PTMS_H
+#undef HAVE_SYS_RESOURCE_H
+#undef HAVE_SYS_SELECT_H
+#undef HAVE_SYS_STATFS_H
+#undef HAVE_SYS_STREAM_H
+#undef HAVE_SYS_SYSCTL_H
+#undef HAVE_SYS_SYSINFO_H
+#undef HAVE_SYS_SYSTEMINFO_H
+#undef HAVE_SYS_TIME_H
+#undef HAVE_SYS_TYPES_H
+#undef HAVE_SYS_UTSNAME_H
+#undef HAVE_TERMCAP_H
+#undef HAVE_TERMIOS_H
+#undef HAVE_TERMIO_H
+#undef HAVE_WCHAR_H
+#undef HAVE_WCTYPE_H
+#undef HAVE_UNISTD_H
+#undef HAVE_UTIL_DEBUG_H
+#undef HAVE_UTIL_MSGI18N_H
+#undef HAVE_UTIME_H
+#undef HAVE_X11_SUNKEYSYM_H
+#undef HAVE_XM_XM_H
+#undef HAVE_XM_XPMP_H
+#undef HAVE_XM_TRAITP_H
+#undef HAVE_XM_MANAGER_H
+#undef HAVE_XM_UNHIGHLIGHTT_H
+#undef HAVE_XM_JOINSIDET_H
+#undef HAVE_XM_NOTEBOOK_H
+#undef HAVE_X11_XPM_H
+#undef HAVE_X11_XMU_EDITRES_H
+#undef HAVE_X11_SM_SMLIB_H
+
+/* Define to the type of the XpmAttributes type. */
+#undef XPMATTRIBUTES_TYPE
+
+/* Define if you have <sys/wait.h> that is POSIX.1 compatible. */
+#undef HAVE_SYS_WAIT_H
+
+/* Define if you have a <sys/wait.h> that is not POSIX.1 compatible. */
+#undef HAVE_UNION_WAIT
+
+/* This is currently unused in vim: */
+/* Define if you have the ANSI C header files. */
+/* #undef STDC_HEADERS */
+
+/* instead, we check a few STDC things ourselves */
+#undef HAVE_STDLIB_H
+#undef HAVE_STRING_H
+
+/* Define if strings.h cannot be included when strings.h already is */
+#undef NO_STRINGS_WITH_STRING_H
+
+/* Define if you want tiny features. */
+#undef FEAT_TINY
+
+/* Define if you want small features. */
+#undef FEAT_SMALL
+
+/* Define if you want normal features. */
+#undef FEAT_NORMAL
+
+/* Define if you want big features. */
+#undef FEAT_BIG
+
+/* Define if you want huge features. */
+#undef FEAT_HUGE
+
+/* Define if you want to include the Lua interpreter. */
+#undef FEAT_LUA
+
+/* Define for linking via dlopen() or LoadLibrary() */
+#undef DYNAMIC_LUA
+
+/* Define if you want to include the MzScheme interpreter. */
+#undef FEAT_MZSCHEME
+
+/* Define if you want to include the Perl interpreter. */
+#undef FEAT_PERL
+
+/* Define for linking via dlopen() or LoadLibrary() */
+#undef DYNAMIC_PERL
+
+/* Define if you want to include the Python interpreter. */
+#undef FEAT_PYTHON
+
+/* Define if you want to include the Python3 interpreter. */
+#undef FEAT_PYTHON3
+
+/* Define for linking via dlopen() or LoadLibrary() */
+#undef DYNAMIC_PYTHON
+
+/* Define for linking via dlopen() or LoadLibrary() */
+#undef DYNAMIC_PYTHON3
+
+/* Define if dynamic python does not require RTLD_GLOBAL */
+#undef PY_NO_RTLD_GLOBAL
+
+/* Define if dynamic python3 does not require RTLD_GLOBAL */
+#undef PY3_NO_RTLD_GLOBAL
+
+/* Define if you want to include the Ruby interpreter. */
+#undef FEAT_RUBY
+
+/* Define for linking via dlopen() or LoadLibrary() */
+#undef DYNAMIC_RUBY
+
+/* Define if you want to include the Tcl interpreter. */
+#undef FEAT_TCL
+
+/* Define for linking via dlopen() or LoadLibrary() */
+#undef DYNAMIC_TCL
+
+/* Define if you want to add support for ACL */
+#undef HAVE_POSIX_ACL
+#undef HAVE_SOLARIS_ZFS_ACL
+#undef HAVE_SOLARIS_ACL
+#undef HAVE_AIX_ACL
+
+/* Define if pango_shape_full() is available. */
+#undef HAVE_PANGO_SHAPE_FULL
+
+/* Define if you want to add support of GPM (Linux console mouse daemon) */
+#undef HAVE_GPM
+
+/* Define if you want to add support of sysmouse (*BSD console mouse) */
+#undef HAVE_SYSMOUSE
+
+/* Define if you want to include the Cscope interface. */
+#undef FEAT_CSCOPE
+
+/* Define if you don't want to include right-left support. */
+#undef DISABLE_RIGHTLEFT
+
+/* Define if you don't want to include Farsi support. */
+#undef DISABLE_FARSI
+
+/* Define if you don't want to include Arabic support. */
+#undef DISABLE_ARABIC
+
+/* Define if you want to always define a server name at vim startup. */
+#undef FEAT_AUTOSERVERNAME
+
+/* Define if you want to include fontset support. */
+#undef FEAT_XFONTSET
+
+/* Define if you want to include XIM support. */
+#undef FEAT_XIM
+
+/* Define if you want to include Hangul input support. */
+#undef FEAT_HANGULIN
+
+/* Define if you use GTK and want GNOME support. */
+#undef FEAT_GUI_GNOME
+
+/* Define if you use KDE and want KDE Toolbar support. */
+#undef FEAT_KDETOOLBAR
+
+/* Define if your X has own locale library */
+#undef X_LOCALE
+
+/* Define if we have dlfcn.h. */
+#undef HAVE_DLFCN_H
+
+/* Define if there is a working gettext(). */
+#undef HAVE_GETTEXT
+
+/* Define if _nl_msg_cat_cntr is present. */
+#undef HAVE_NL_MSG_CAT_CNTR
+
+/* Define if we have dlopen() */
+#undef HAVE_DLOPEN
+
+/* Define if we have dlsym() */
+#undef HAVE_DLSYM
+
+/* Define if we have dl.h. */
+#undef HAVE_DL_H
+
+/* Define if we have shl_load() */
+#undef HAVE_SHL_LOAD
+
+/* Define if you want to include NetBeans integration. */
+#undef FEAT_NETBEANS_INTG
+
+/* Define if you want to include process communication. */
+#undef FEAT_JOB_CHANNEL
+
+/* Define if you want to include terminal emulator support. */
+#undef FEAT_TERMINAL
+
+// Define default global runtime path.
+#undef RUNTIME_GLOBAL
+
+// Define default global runtime after path.
+#undef RUNTIME_GLOBAL_AFTER
+
+/* Define name of who modified a released Vim */
+#undef MODIFIED_BY
+
+/* Define if you want XSMP interaction as well as vanilla swapfile safety */
+#undef USE_XSMP_INTERACT
+
+/* Define if fcntl()'s F_SETFD command knows about FD_CLOEXEC */
+#undef HAVE_FD_CLOEXEC
+
+/* Define if /proc/self/exe or similar can be read */
+#undef PROC_EXE_LINK
+
+/* Define if you want Cygwin to use the WIN32 clipboard, not compatible with X11*/
+#undef FEAT_CYGWIN_WIN32_CLIPBOARD
+
+/* Define if we have AvailabilityMacros.h on Mac OS X */
+#undef HAVE_AVAILABILITYMACROS_H
+
+/* Define if Xutf8SetWMProperties() is in an X library. */
+#undef HAVE_XUTF8SETWMPROPERTIES
+
+/* Define if GResource is used to load icons */
+#undef USE_GRESOURCE
+
+/* Define if GTK+ GUI is to be linked against GTK+ 3 */
+#undef USE_GTK3
+
+/* Define if we have isinf() */
+#undef HAVE_ISINF
+
+/* Define if we have isnan() */
+#undef HAVE_ISNAN
+
+/* Define to inline symbol or empty */
+#undef inline
diff --git a/src/config.mk.dist b/src/config.mk.dist
new file mode 100644
index 0000000..8a584c2
--- /dev/null
+++ b/src/config.mk.dist
@@ -0,0 +1,5 @@
+the first target to make vim is: reconfig
+srcdir = .
+VIMNAME = vim
+EXNAME = ex
+VIEWNAME = view
diff --git a/src/config.mk.in b/src/config.mk.in
new file mode 100644
index 0000000..b5d1ebd
--- /dev/null
+++ b/src/config.mk.in
@@ -0,0 +1,175 @@
+#
+# config.mk.in -- autoconf template for Vim on Unix vim:ts=8:sw=8:
+#
+# DO NOT EDIT config.mk!! It will be overwritten by configure.
+# Edit Makefile and run "make" or run ./configure with other arguments.
+#
+# Configure does not edit the makefile directly. This method is not the
+# standard use of GNU autoconf, but it has two advantages:
+# a) The user can override every choice made by configure.
+# b) Modifications to the makefile are not lost when configure is run.
+#
+# I hope this is worth being nonstandard. jw.
+
+@SET_MAKE@
+
+VIMNAME = @VIMNAME@
+EXNAME = @EXNAME@
+VIEWNAME = @VIEWNAME@
+
+CC = @CC@
+DEFS = @DEFS@
+CFLAGS = @CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+srcdir = @srcdir@
+VPATH = @srcdir@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+TAGPRG = @TAGPRG@
+
+CPP = @CPP@
+CPP_MM = @CPP_MM@
+DEPEND_CFLAGS_FILTER = @DEPEND_CFLAGS_FILTER@
+LINK_AS_NEEDED = @LINK_AS_NEEDED@
+X_CFLAGS = @X_CFLAGS@
+X_LIBS_DIR = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIB@
+
+LUA_LIBS = @LUA_LIBS@
+LUA_SRC = @LUA_SRC@
+LUA_OBJ = @LUA_OBJ@
+LUA_CFLAGS = @LUA_CFLAGS@
+LUA_PRO = @LUA_PRO@
+
+MZSCHEME_LIBS = @MZSCHEME_LIBS@
+MZSCHEME_SRC = @MZSCHEME_SRC@
+MZSCHEME_OBJ = @MZSCHEME_OBJ@
+MZSCHEME_CFLAGS = @MZSCHEME_CFLAGS@
+MZSCHEME_PRO = @MZSCHEME_PRO@
+MZSCHEME_EXTRA = @MZSCHEME_EXTRA@
+MZSCHEME_MZC = @MZSCHEME_MZC@
+
+PERL = @vi_cv_path_perl@
+PERLLIB = @vi_cv_perllib@
+PERL_XSUBPP = @vi_cv_perl_xsubpp@
+PERL_LIBS = @PERL_LIBS@
+SHRPENV = @shrpenv@
+PERL_SRC = @PERL_SRC@
+PERL_OBJ = @PERL_OBJ@
+PERL_PRO = @PERL_PRO@
+PERL_CFLAGS = @PERL_CFLAGS@
+
+PYTHON_SRC = @PYTHON_SRC@
+PYTHON_OBJ = @PYTHON_OBJ@
+PYTHON_CFLAGS = @PYTHON_CFLAGS@
+PYTHON_LIBS = @PYTHON_LIBS@
+
+PYTHON3_SRC = @PYTHON3_SRC@
+PYTHON3_OBJ = @PYTHON3_OBJ@
+PYTHON3_CFLAGS = @PYTHON3_CFLAGS@
+PYTHON3_LIBS = @PYTHON3_LIBS@
+
+TCL = @vi_cv_path_tcl@
+TCL_SRC = @TCL_SRC@
+TCL_OBJ = @TCL_OBJ@
+TCL_PRO = @TCL_PRO@
+TCL_CFLAGS = @TCL_CFLAGS@
+TCL_LIBS = @TCL_LIBS@
+
+HANGULIN_SRC = @HANGULIN_SRC@
+HANGULIN_OBJ = @HANGULIN_OBJ@
+
+NETBEANS_SRC = @NETBEANS_SRC@
+NETBEANS_OBJ = @NETBEANS_OBJ@
+CHANNEL_SRC = @CHANNEL_SRC@
+CHANNEL_OBJ = @CHANNEL_OBJ@
+TERM_SRC = @TERM_SRC@
+TERM_OBJ = @TERM_OBJ@
+
+RUBY = @vi_cv_path_ruby@
+RUBY_SRC = @RUBY_SRC@
+RUBY_OBJ = @RUBY_OBJ@
+RUBY_PRO = @RUBY_PRO@
+RUBY_CFLAGS = @RUBY_CFLAGS@
+RUBY_LIBS = @RUBY_LIBS@
+
+AWK = @AWK@
+
+STRIP = @STRIP@
+
+EXEEXT = @EXEEXT@
+CROSS_COMPILING = @CROSS_COMPILING@
+
+COMPILEDBY = @compiledby@
+
+INSTALLVIMDIFF = @dovimdiff@
+INSTALLGVIMDIFF = @dogvimdiff@
+INSTALL_LANGS = @INSTALL_LANGS@
+INSTALL_TOOL_LANGS = @INSTALL_TOOL_LANGS@
+
+### sed command to fix quotes while creating pathdef.c
+QUOTESED = @QUOTESED@
+
+### Line break character as octal number for "tr"
+NL = @line_break@
+
+### Top directory for everything
+prefix = @prefix@
+
+### Top directory for the binary
+exec_prefix = @exec_prefix@
+
+### Prefix for location of data files
+BINDIR = @bindir@
+
+### For autoconf 2.60 and later (avoid a warning)
+datarootdir = @datarootdir@
+
+### Prefix for location of data files
+DATADIR = @datadir@
+
+### Prefix for location of man pages
+MANDIR = @mandir@
+
+### Do we have a GUI
+GUI_INC_LOC = @GUI_INC_LOC@
+GUI_LIB_LOC = @GUI_LIB_LOC@
+GUI_SRC = $(@GUITYPE@_SRC)
+GUI_OBJ = $(@GUITYPE@_OBJ)
+GUI_DEFS = $(@GUITYPE@_DEFS)
+GUI_IPATH = $(@GUITYPE@_IPATH)
+GUI_LIBS_DIR = $(@GUITYPE@_LIBS_DIR)
+GUI_LIBS1 = $(@GUITYPE@_LIBS1)
+GUI_LIBS2 = $(@GUITYPE@_LIBS2)
+GUI_INSTALL = $(@GUITYPE@_INSTALL)
+GUI_TARGETS = $(@GUITYPE@_TARGETS)
+GUI_MAN_TARGETS = $(@GUITYPE@_MAN_TARGETS)
+GUI_TESTTARGET = $(@GUITYPE@_TESTTARGET)
+GUI_TESTARG = $(@GUITYPE@_TESTARG)
+GUI_BUNDLE = $(@GUITYPE@_BUNDLE)
+NARROW_PROTO = @NARROW_PROTO@
+GUI_X_LIBS = @GUI_X_LIBS@
+MOTIF_LIBNAME = @MOTIF_LIBNAME@
+GTK_LIBNAME = @GTK_LIBNAME@
+
+GLIB_COMPILE_RESOURCES = @GLIB_COMPILE_RESOURCES@
+GRESOURCE_SRC = @GRESOURCE_SRC@
+GRESOURCE_OBJ = @GRESOURCE_OBJ@
+
+GTK_UPDATE_ICON_CACHE = @GTK_UPDATE_ICON_CACHE@
+UPDATE_DESKTOP_DATABASE = @UPDATE_DESKTOP_DATABASE@
+
+### Any OS dependent extra source and object file
+OS_EXTRA_SRC = @OS_EXTRA_SRC@
+OS_EXTRA_OBJ = @OS_EXTRA_OBJ@
+
+### If the *.po files are to be translated to *.mo files.
+MAKEMO = @MAKEMO@
+
+MSGFMT = @MSGFMT@
+
+# Make sure that "make first" will run "make all" once configure has done its
+# work. This is needed when using the Makefile in the top directory.
+first: all
diff --git a/src/configure b/src/configure
new file mode 100755
index 0000000..d8595a5
--- /dev/null
+++ b/src/configure
@@ -0,0 +1,10 @@
+#! /bin/sh
+# run the automatically generated configure script
+CONFIG_STATUS=auto/config.status \
+ auto/configure "$@" --srcdir="${srcdir:-.}" --cache-file=auto/config.cache
+result=$?
+
+# Stupid autoconf 2.5x causes this file to be left behind.
+if test -f configure.lineno; then rm -f configure.lineno; fi
+
+exit $result
diff --git a/src/configure.ac b/src/configure.ac
new file mode 100644
index 0000000..2b7725b
--- /dev/null
+++ b/src/configure.ac
@@ -0,0 +1,4486 @@
+dnl configure.ac: autoconf script for Vim
+
+dnl Process this file with autoconf 2.12 or 2.13 to produce "configure".
+dnl Should also work with autoconf 2.54 and later.
+
+AC_INIT(vim.h)
+AC_CONFIG_HEADER(auto/config.h:config.h.in)
+
+dnl Being able to run configure means the system is Unix (compatible).
+AC_DEFINE(UNIX)
+AC_PROG_MAKE_SET
+
+dnl Checks for programs.
+AC_PROG_CC_C99 dnl required by almost everything
+AC_PROG_CPP dnl required by header file checks
+AC_PROGRAM_EGREP dnl required by AC_EGREP_CPP
+AC_PROG_FGREP dnl finds working grep -F
+AC_ISC_POSIX dnl required by AC_C_CROSS
+AC_PROG_AWK dnl required for "make html" in ../doc
+
+dnl Don't strip if we don't have it
+AC_CHECK_PROG(STRIP, strip, strip, :)
+
+dnl Check for extension of executables
+AC_EXEEXT
+
+dnl Check for standard headers. We don't use this in Vim but other stuff
+dnl in autoconf needs it, where it uses STDC_HEADERS.
+AC_HEADER_STDC
+AC_HEADER_SYS_WAIT
+
+dnl Check that the C99 features that Vim uses are supported:
+if test x"$ac_cv_prog_cc_c99" != xno; then
+ dnl If the compiler doesn't explicitly support C99, then check
+ dnl for the specific features Vim uses
+
+ AC_TYPE_LONG_LONG_INT
+ if test "$ac_cv_type_long_long_int" = no; then
+ AC_MSG_FAILURE([Compiler does not support long long int])
+ fi
+
+ AC_MSG_CHECKING([if the compiler supports trailing commas])
+ trailing_commas=no
+ AC_TRY_COMPILE([], [
+ enum {
+ one,
+ };],
+ [AC_MSG_RESULT(yes); trailing_commas=yes],
+ [AC_MSG_RESULT(no)])
+ if test "$trailing_commas" = no; then
+ AC_MSG_FAILURE([Compiler does not support trailing comma in enum])
+ fi
+
+ AC_MSG_CHECKING([if the compiler supports C++ comments])
+ slash_comments=no
+ AC_TRY_COMPILE([],
+ [// C++ comments?],
+ [AC_MSG_RESULT(yes); slash_comments=yes],
+ [AC_MSG_RESULT(no)])
+ if test "$slash_comments" = no; then
+ AC_MSG_FAILURE([Compiler does not support C++ comments])
+ fi
+fi
+
+dnl Check for the flag that fails if stuff are missing.
+
+AC_MSG_CHECKING(--enable-fail-if-missing argument)
+AC_ARG_ENABLE(fail_if_missing,
+ [ --enable-fail-if-missing Fail if dependencies on additional features
+ specified on the command line are missing.],
+ [fail_if_missing="yes"],
+ [fail_if_missing="no"])
+AC_MSG_RESULT($fail_if_missing)
+
+dnl Keep original value to check later.
+with_x_arg="$with_x"
+
+dnl Set default value for CFLAGS if none is defined or it's empty
+if test -z "$CFLAGS"; then
+ CFLAGS="-O"
+ test "$GCC" = yes && CFLAGS="-O2 -fno-strength-reduce -Wall"
+fi
+if test "$GCC" = yes; then
+ dnl method that should work for nearly all versions
+ gccversion=`$CC -dumpversion`
+ if test "x$gccversion" = "x"; then
+ dnl old method; fall-back for when -dumpversion doesn't work
+ gccversion=`$CC --version | sed -e '2,$d' -e 's/darwin.//' -e 's/^[[^0-9]]*\([[0-9]]\.[[0-9.]]*\).*$/\1/g'`
+ fi
+ dnl version 4.0.1 was reported to cause trouble on Macintosh by Marcin Dalecki
+ if test "$gccversion" = "3.0.1" -o "$gccversion" = "3.0.2" -o "$gccversion" = "4.0.1"; then
+ echo 'GCC [[34]].0.[[12]] has a bug in the optimizer, disabling "-O#"'
+ CFLAGS=`echo "$CFLAGS" | sed 's/-O[[23456789]]/-O/'`
+ else
+ if test "$gccversion" = "3.1" -o "$gccversion" = "3.2" -o "$gccversion" = "3.2.1" && `echo "$CFLAGS" | grep -v fno-strength-reduce >/dev/null`; then
+ echo 'GCC 3.1 and 3.2 have a bug in the optimizer, adding "-fno-strength-reduce"'
+ CFLAGS="$CFLAGS -fno-strength-reduce"
+ fi
+ fi
+fi
+
+dnl clang-500.2.75 or around has abandoned -f[no-]strength-reduce and issues a
+dnl warning when that flag is passed to. Accordingly, adjust CFLAGS based on
+dnl the version number of the clang in use.
+dnl Note that this does not work to get the version of clang 3.1 or 3.2.
+AC_MSG_CHECKING(for clang version)
+CLANG_VERSION_STRING=`$CC --version 2>/dev/null | sed -n -e 's/^.*clang[[^0-9]]*\([[0-9]][[0-9]]*\.[[0-9]][[0-9]]*\.[[0-9]][[0-9]]*\).*$/\1/p'`
+if test x"$CLANG_VERSION_STRING" != x"" ; then
+ CLANG_MAJOR=`echo "$CLANG_VERSION_STRING" | sed -n -e 's/\([[0-9]][[0-9]]*\)\.[[0-9]][[0-9]]*\.[[0-9]][[0-9]]*/\1/p'`
+ CLANG_MINOR=`echo "$CLANG_VERSION_STRING" | sed -n -e 's/[[0-9]][[0-9]]*\.\([[0-9]][[0-9]]*\)\.[[0-9]][[0-9]]*/\1/p'`
+ CLANG_REVISION=`echo "$CLANG_VERSION_STRING" | sed -n -e 's/[[0-9]][[0-9]]*\.[[0-9]][[0-9]]*\.\([[0-9]][[0-9]]*\)/\1/p'`
+ CLANG_VERSION=`expr $CLANG_MAJOR '*' 1000000 '+' $CLANG_MINOR '*' 1000 '+' $CLANG_REVISION`
+ AC_MSG_RESULT($CLANG_VERSION)
+ dnl If you find the same issue with versions earlier than 500.2.75,
+ dnl change the constant 500002075 below appropriately. To get the
+ dnl integer corresponding to a version number, refer to the
+ dnl definition of CLANG_VERSION above.
+ AC_MSG_CHECKING(if clang supports -fno-strength-reduce)
+ if test "$CLANG_VERSION" -ge 500002075 ; then
+ AC_MSG_RESULT(no)
+ CFLAGS=`echo "$CFLAGS" | sed -e 's/-fno-strength-reduce/ /'`
+ else
+ AC_MSG_RESULT(yes)
+ fi
+else
+ AC_MSG_RESULT(N/A)
+fi
+
+dnl If configure thinks we are cross compiling, there might be something
+dnl wrong with the CC or CFLAGS settings, give a useful warning message
+CROSS_COMPILING=
+if test "$cross_compiling" = yes; then
+ AC_MSG_RESULT([cannot compile a simple program; if not cross compiling check CC and CFLAGS])
+ CROSS_COMPILING=1
+fi
+AC_SUBST(CROSS_COMPILING)
+
+dnl gcc-cpp has the wonderful -MM option to produce nicer dependencies.
+dnl But gcc 3.1 changed the meaning! See near the end.
+test "$GCC" = yes && CPP_MM=M; AC_SUBST(CPP_MM)
+
+if test -f ./toolcheck; then
+ AC_CHECKING(for buggy tools)
+ sh ./toolcheck 1>&AC_FD_MSG
+fi
+
+OS_EXTRA_SRC=""; OS_EXTRA_OBJ=""
+
+dnl Check for BeOS, which needs an extra source file
+AC_MSG_CHECKING(for BeOS)
+case `uname` in
+ BeOS) OS_EXTRA_SRC=os_beos.c; OS_EXTRA_OBJ=objects/os_beos.o
+ BEOS=yes; AC_MSG_RESULT(yes);;
+ *) BEOS=no; AC_MSG_RESULT(no);;
+esac
+
+dnl If QNX is found, assume we don't want to use Xphoton
+dnl unless it was specifically asked for (--with-x)
+AC_MSG_CHECKING(for QNX)
+case `uname` in
+ QNX) OS_EXTRA_SRC=os_qnx.c; OS_EXTRA_OBJ=objects/os_qnx.o
+ test -z "$with_x" && with_x=no
+ QNX=yes; AC_MSG_RESULT(yes);;
+ *) QNX=no; AC_MSG_RESULT(no);;
+esac
+
+dnl Check for Darwin and MacOS X
+dnl We do a check for MacOS X in the very beginning because there
+dnl are a lot of other things we need to change besides GUI stuff
+AC_MSG_CHECKING([for Darwin (Mac OS X)])
+if test "`(uname) 2>/dev/null`" = Darwin; then
+ AC_MSG_RESULT(yes)
+ MACOS_X=yes
+ CPPFLAGS="$CPPFLAGS -DMACOS_X"
+
+ AC_MSG_CHECKING(--disable-darwin argument)
+ AC_ARG_ENABLE(darwin,
+ [ --disable-darwin Disable Darwin (Mac OS X) support.],
+ , [enable_darwin="yes"])
+ if test "$enable_darwin" = "yes"; then
+ AC_MSG_RESULT(no)
+ AC_MSG_CHECKING(if Darwin files are there)
+ if test -f os_macosx.m; then
+ AC_MSG_RESULT(yes)
+ else
+ AC_MSG_RESULT([no, Darwin support disabled])
+ enable_darwin=no
+ fi
+ else
+ AC_MSG_RESULT([yes, Darwin support excluded])
+ fi
+
+ AC_MSG_CHECKING(--with-mac-arch argument)
+ AC_ARG_WITH(mac-arch, [ --with-mac-arch=ARCH current, intel, ppc or both],
+ MACARCH="$withval"; AC_MSG_RESULT($MACARCH),
+ MACARCH="current"; AC_MSG_RESULT(defaulting to $MACARCH))
+
+ AC_MSG_CHECKING(--with-developer-dir argument)
+ AC_ARG_WITH(developer-dir, [ --with-developer-dir=PATH use PATH as location for Xcode developer tools],
+ DEVELOPER_DIR="$withval"; AC_MSG_RESULT($DEVELOPER_DIR),
+ AC_MSG_RESULT(not present))
+
+ if test "x$DEVELOPER_DIR" = "x"; then
+ AC_PATH_PROG(XCODE_SELECT, xcode-select)
+ if test "x$XCODE_SELECT" != "x"; then
+ AC_MSG_CHECKING(for developer dir using xcode-select)
+ DEVELOPER_DIR=`$XCODE_SELECT -print-path`
+ AC_MSG_RESULT([$DEVELOPER_DIR])
+ else
+ DEVELOPER_DIR=/Developer
+ fi
+ fi
+
+ if test "x$MACARCH" = "xboth"; then
+ AC_MSG_CHECKING(for 10.4 universal SDK)
+ dnl There is a terrible inconsistency (but we appear to get away with it):
+ dnl $CFLAGS uses the 10.4u SDK library for the headers, while $CPPFLAGS
+ dnl doesn't, because "gcc -E" doesn't grok it. That means the configure
+ dnl tests using the preprocessor are actually done with the wrong header
+ dnl files. $LDFLAGS is set at the end, because configure uses it together
+ dnl with $CFLAGS and we can only have one -sysroot argument.
+ save_cppflags="$CPPFLAGS"
+ save_cflags="$CFLAGS"
+ save_ldflags="$LDFLAGS"
+ CFLAGS="$CFLAGS -isysroot $DEVELOPER_DIR/SDKs/MacOSX10.4u.sdk -arch i386 -arch ppc"
+ AC_TRY_LINK([ ], [ ],
+ AC_MSG_RESULT(found, will make universal binary),
+
+ AC_MSG_RESULT(not found)
+ CFLAGS="$save_cflags"
+ AC_MSG_CHECKING(if Intel architecture is supported)
+ CPPFLAGS="$CPPFLAGS -arch i386"
+ LDFLAGS="$save_ldflags -arch i386"
+ AC_TRY_LINK([ ], [ ],
+ AC_MSG_RESULT(yes); MACARCH="intel",
+ AC_MSG_RESULT(no, using PowerPC)
+ MACARCH="ppc"
+ CPPFLAGS="$save_cppflags -arch ppc"
+ LDFLAGS="$save_ldflags -arch ppc"))
+ elif test "x$MACARCH" = "xintel"; then
+ CPPFLAGS="$CPPFLAGS -arch intel"
+ LDFLAGS="$LDFLAGS -arch intel"
+ elif test "x$MACARCH" = "xppc"; then
+ CPPFLAGS="$CPPFLAGS -arch ppc"
+ LDFLAGS="$LDFLAGS -arch ppc"
+ fi
+
+ if test "$enable_darwin" = "yes"; then
+ MACOS_X_DARWIN=yes
+ OS_EXTRA_SRC="os_macosx.m os_mac_conv.c";
+ OS_EXTRA_OBJ="objects/os_macosx.o objects/os_mac_conv.o"
+ dnl TODO: use -arch i386 on Intel machines
+ dnl Removed -no-cpp-precomp, only for very old compilers.
+ CPPFLAGS="$CPPFLAGS -DMACOS_X_DARWIN"
+
+ dnl If Carbon is found, assume we don't want X11
+ dnl 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)
+ if test "x$CARBON" = "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
+ fi
+
+ dnl Avoid a bug with -O2 with gcc 4.0.1. Symptom: malloc() reports double
+ dnl free. This happens in expand_filename(), because the optimizer swaps
+ dnl two blocks of code, both using "repl", that can't be swapped.
+ if test "$MACARCH" = "intel" -o "$MACARCH" = "both"; then
+ CFLAGS=`echo "$CFLAGS" | sed 's/-O[[23456789]]/-Oz/'`
+ fi
+
+else
+ AC_MSG_RESULT(no)
+fi
+
+dnl Mac OS X 10.9+ no longer include AvailabilityMacros.h in Carbon
+dnl so we need to include it to have access to version macros.
+AC_CHECK_HEADERS(AvailabilityMacros.h)
+
+AC_SUBST(OS_EXTRA_SRC)
+AC_SUBST(OS_EXTRA_OBJ)
+
+dnl Add /usr/local/lib to $LDFLAGS and /usr/local/include to CFLAGS.
+dnl Only when the directory exists and it wasn't there yet.
+dnl For gcc don't do this when it is already in the default search path.
+dnl Skip all of this when cross-compiling.
+if test "$cross_compiling" = no; then
+ AC_MSG_CHECKING(--with-local-dir argument)
+ have_local_include=''
+ have_local_lib=''
+ AC_ARG_WITH([local-dir], [ --with-local-dir=PATH search PATH instead of /usr/local for local libraries.
+ --without-local-dir do not search /usr/local for local libraries.], [
+ local_dir="$withval"
+ case "$withval" in
+ */*) ;;
+ no)
+ # avoid adding local dir to LDFLAGS and CPPFLAGS
+ have_local_include=yes
+ have_local_lib=yes
+ ;;
+ *) AC_MSG_ERROR(must pass path argument to --with-local-dir) ;;
+ esac
+ AC_MSG_RESULT($local_dir)
+ ], [
+ local_dir=/usr/local
+ AC_MSG_RESULT(Defaulting to $local_dir)
+ ])
+ if test "$GCC" = yes -a "$local_dir" != no; then
+ echo 'void f(){}' > conftest.c
+ dnl Removed -no-cpp-precomp, only needed for OS X 10.2 (Ben Fowler)
+ have_local_include=`${CC-cc} -c -v conftest.c 2>&1 | grep "${local_dir}/include"`
+ have_local_lib=`${CC-cc} -c -v conftest.c 2>&1 | grep "${local_dir}/lib"`
+ rm -f conftest.c conftest.o
+ fi
+ if test -z "$have_local_lib" -a -d "${local_dir}/lib"; then
+ tt=`echo "$LDFLAGS" | sed -e "s+-L${local_dir}/lib ++g" -e "s+-L${local_dir}/lib$++g"`
+ if test "$tt" = "$LDFLAGS"; then
+ LDFLAGS="$LDFLAGS -L${local_dir}/lib"
+ fi
+ fi
+ if test -z "$have_local_include" -a -d "${local_dir}/include"; then
+ tt=`echo "$CPPFLAGS" | sed -e "s+-I${local_dir}/include ++g" -e "s+-I${local_dir}/include$++g"`
+ if test "$tt" = "$CPPFLAGS"; then
+ CPPFLAGS="$CPPFLAGS -I${local_dir}/include"
+ fi
+ fi
+fi
+
+AC_MSG_CHECKING(--with-vim-name argument)
+AC_ARG_WITH(vim-name, [ --with-vim-name=NAME what to call the Vim executable],
+ VIMNAME="$withval"; AC_MSG_RESULT($VIMNAME),
+ VIMNAME="vim"; AC_MSG_RESULT(Defaulting to $VIMNAME))
+AC_SUBST(VIMNAME)
+AC_MSG_CHECKING(--with-ex-name argument)
+AC_ARG_WITH(ex-name, [ --with-ex-name=NAME what to call the Ex executable],
+ EXNAME="$withval"; AC_MSG_RESULT($EXNAME),
+ EXNAME="ex"; AC_MSG_RESULT(Defaulting to ex))
+AC_SUBST(EXNAME)
+AC_MSG_CHECKING(--with-view-name argument)
+AC_ARG_WITH(view-name, [ --with-view-name=NAME what to call the View executable],
+ VIEWNAME="$withval"; AC_MSG_RESULT($VIEWNAME),
+ VIEWNAME="view"; AC_MSG_RESULT(Defaulting to view))
+AC_SUBST(VIEWNAME)
+
+AC_MSG_CHECKING(--with-global-runtime argument)
+AC_ARG_WITH(global-runtime, [ --with-global-runtime=DIR global runtime directory in 'runtimepath', comma-separated for multiple directories],
+ RUNTIME_GLOBAL="$withval"; AC_MSG_RESULT($withval),
+ AC_MSG_RESULT(no))
+
+if test "X$RUNTIME_GLOBAL" != "X"; then
+ RUNTIME_GLOBAL_AFTER=$(printf -- "$RUNTIME_GLOBAL\\n" | $AWK -F, 'BEGIN { comma=0 } { for (i = NF; i > 0; i--) { if (comma) { printf ",%s/after", $i } else { printf "%s/after", $i; comma=1 } } } END { printf "\n" }')
+ AC_DEFINE_UNQUOTED(RUNTIME_GLOBAL, "$RUNTIME_GLOBAL")
+ AC_DEFINE_UNQUOTED(RUNTIME_GLOBAL_AFTER, "$RUNTIME_GLOBAL_AFTER")
+fi
+
+AC_MSG_CHECKING(--with-modified-by argument)
+AC_ARG_WITH(modified-by, [ --with-modified-by=NAME name of who modified a release version],
+ AC_MSG_RESULT($withval); AC_DEFINE_UNQUOTED(MODIFIED_BY, "$withval"),
+ AC_MSG_RESULT(no))
+
+dnl Check for EBCDIC stolen from the LYNX port to z/OS Unix
+AC_MSG_CHECKING(if character set is EBCDIC)
+AC_TRY_COMPILE([ ],
+[ /* TryCompile function for CharSet.
+ Treat any failure as ASCII for compatibility with existing art.
+ Use compile-time rather than run-time tests for cross-compiler
+ tolerance. */
+#if '0'!=240
+make an error "Character set is not EBCDIC"
+#endif ],
+[ # TryCompile action if true
+cf_cv_ebcdic=yes ],
+[ # TryCompile action if false
+cf_cv_ebcdic=no])
+# end of TryCompile ])
+# end of CacheVal CvEbcdic
+AC_MSG_RESULT($cf_cv_ebcdic)
+case "$cf_cv_ebcdic" in #(vi
+ yes) AC_DEFINE(EBCDIC)
+ line_break='"\\n"'
+ ;;
+ *) line_break='"\\012"';;
+esac
+AC_SUBST(line_break)
+
+if test "$cf_cv_ebcdic" = "yes"; then
+dnl If we have EBCDIC we most likely have z/OS Unix, let's test it!
+AC_MSG_CHECKING(for z/OS Unix)
+case `uname` in
+ OS/390) zOSUnix="yes";
+ dnl If using cc the environment variable _CC_CCMODE must be
+ dnl set to "1", so that some compiler extensions are enabled.
+ dnl If using c89 the environment variable is named _CC_C89MODE.
+ dnl Note: compile with c89 never tested.
+ if test "$CC" = "cc"; then
+ ccm="$_CC_CCMODE"
+ ccn="CC"
+ else
+ if test "$CC" = "c89"; then
+ ccm="$_CC_C89MODE"
+ ccn="C89"
+ else
+ ccm=1
+ fi
+ fi
+ if test "$ccm" != "1"; then
+ echo ""
+ echo "------------------------------------------"
+ echo " On z/OS Unix, the environment variable"
+ echo " _CC_${ccn}MODE must be set to \"1\"!"
+ echo " Do:"
+ echo " export _CC_${ccn}MODE=1"
+ echo " and then call configure again."
+ echo "------------------------------------------"
+ exit 1
+ fi
+ # Set CFLAGS for configure process.
+ # This will be reset later for config.mk.
+ # Use haltonmsg to force error for missing H files.
+ CFLAGS="$CFLAGS -D_ALL_SOURCE -Wc,float(ieee),haltonmsg(3296)";
+ LDFLAGS="$LDFLAGS -Wl,EDIT=NO"
+ AC_MSG_RESULT(yes)
+ ;;
+ *) zOSUnix="no";
+ AC_MSG_RESULT(no)
+ ;;
+esac
+fi
+
+dnl Set QUOTESED. Needs additional backslashes on zOS
+if test "$zOSUnix" = "yes"; then
+ QUOTESED="sed -e 's/[[\\\\\"]]/\\\\\\\\&/g' -e 's/\\\\\\\\\"/\"/' -e 's/\\\\\\\\\";\$\$/\";/'"
+else
+ QUOTESED="sed -e 's/[[\\\\\"]]/\\\\&/g' -e 's/\\\\\"/\"/' -e 's/\\\\\";\$\$/\";/'"
+fi
+AC_SUBST(QUOTESED)
+
+
+dnl Link with -lsmack for Smack stuff; if not found
+AC_MSG_CHECKING(--disable-smack argument)
+AC_ARG_ENABLE(smack,
+ [ --disable-smack Do not check for Smack support.],
+ , enable_smack="yes")
+if test "$enable_smack" = "yes"; then
+ AC_MSG_RESULT(no)
+ AC_CHECK_HEADER([linux/xattr.h], true, enable_smack="no")
+else
+ AC_MSG_RESULT(yes)
+fi
+if test "$enable_smack" = "yes"; then
+ AC_CHECK_HEADER([attr/xattr.h], true, enable_smack="no")
+fi
+if test "$enable_smack" = "yes"; then
+ AC_MSG_CHECKING(for XATTR_NAME_SMACKEXEC in linux/xattr.h)
+ AC_EGREP_CPP(XATTR_NAME_SMACKEXEC, [#include <linux/xattr.h>],
+ AC_MSG_RESULT(yes),
+ AC_MSG_RESULT(no); enable_smack="no")
+fi
+if test "$enable_smack" = "yes"; then
+ AC_CHECK_LIB(attr, setxattr,
+ [LIBS="$LIBS -lattr"
+ found_smack="yes"
+ AC_DEFINE(HAVE_SMACK)])
+fi
+
+dnl When smack was found don't search for SELinux
+if test "x$found_smack" = "x"; then
+ dnl Link with -lselinux for SELinux stuff; if not found
+ AC_MSG_CHECKING(--disable-selinux argument)
+ AC_ARG_ENABLE(selinux,
+ [ --disable-selinux Do not check for SELinux support.],
+ , enable_selinux="yes")
+ if test "$enable_selinux" = "yes"; then
+ AC_MSG_RESULT(no)
+ AC_CHECK_LIB(selinux, is_selinux_enabled,
+ [AC_CHECK_HEADER(selinux/selinux.h,
+ [LIBS="$LIBS -lselinux"
+ AC_DEFINE(HAVE_SELINUX)])])
+ else
+ AC_MSG_RESULT(yes)
+ fi
+fi
+
+dnl Check user requested features.
+
+AC_MSG_CHECKING(--with-features argument)
+AC_ARG_WITH(features, [ --with-features=TYPE tiny, small, normal, big or huge (default: huge)],
+ features="$withval"; AC_MSG_RESULT($features),
+ features="huge"; AC_MSG_RESULT(Defaulting to huge))
+
+dovimdiff=""
+dogvimdiff=""
+case "$features" in
+ tiny) AC_DEFINE(FEAT_TINY) ;;
+ small) AC_DEFINE(FEAT_SMALL) ;;
+ normal) AC_DEFINE(FEAT_NORMAL) dovimdiff="installvimdiff";
+ dogvimdiff="installgvimdiff" ;;
+ big) AC_DEFINE(FEAT_BIG) dovimdiff="installvimdiff";
+ dogvimdiff="installgvimdiff" ;;
+ huge) AC_DEFINE(FEAT_HUGE) dovimdiff="installvimdiff";
+ dogvimdiff="installgvimdiff" ;;
+ *) AC_MSG_RESULT([Sorry, $features is not supported]) ;;
+esac
+
+AC_SUBST(dovimdiff)
+AC_SUBST(dogvimdiff)
+
+AC_MSG_CHECKING(--with-compiledby argument)
+AC_ARG_WITH(compiledby, [ --with-compiledby=NAME name to show in :version message],
+ compiledby="$withval"; AC_MSG_RESULT($withval),
+ compiledby=""; AC_MSG_RESULT(no))
+AC_SUBST(compiledby)
+
+AC_MSG_CHECKING(--disable-xsmp argument)
+AC_ARG_ENABLE(xsmp,
+ [ --disable-xsmp Disable XSMP session management],
+ , enable_xsmp="yes")
+
+if test "$enable_xsmp" = "yes"; then
+ AC_MSG_RESULT(no)
+ AC_MSG_CHECKING(--disable-xsmp-interact argument)
+ AC_ARG_ENABLE(xsmp-interact,
+ [ --disable-xsmp-interact Disable XSMP interaction],
+ , enable_xsmp_interact="yes")
+ if test "$enable_xsmp_interact" = "yes"; then
+ AC_MSG_RESULT(no)
+ AC_DEFINE(USE_XSMP_INTERACT)
+ else
+ AC_MSG_RESULT(yes)
+ fi
+else
+ AC_MSG_RESULT(yes)
+fi
+
+dnl Check for Lua feature.
+AC_MSG_CHECKING(--enable-luainterp argument)
+AC_ARG_ENABLE(luainterp,
+ [ --enable-luainterp[=OPTS] Include Lua interpreter. [default=no] [OPTS=no/yes/dynamic]], ,
+ [enable_luainterp="no"])
+AC_MSG_RESULT($enable_luainterp)
+
+if test "$enable_luainterp" = "yes" -o "$enable_luainterp" = "dynamic"; then
+ if test "x$features" = "xtiny" -o "x$features" = "xsmall"; then
+ AC_MSG_ERROR([cannot use Lua with tiny or small features])
+ fi
+
+ dnl -- find the lua executable
+ AC_SUBST(vi_cv_path_lua)
+
+ AC_MSG_CHECKING(--with-lua-prefix argument)
+ AC_ARG_WITH(lua_prefix,
+ [ --with-lua-prefix=PFX Prefix where Lua is installed.],
+ with_lua_prefix="$withval"; AC_MSG_RESULT($with_lua_prefix),
+ with_lua_prefix="";AC_MSG_RESULT(no))
+
+ if test "X$with_lua_prefix" != "X"; then
+ vi_cv_path_lua_pfx="$with_lua_prefix"
+ else
+ AC_MSG_CHECKING(LUA_PREFIX environment var)
+ if test "X$LUA_PREFIX" != "X"; then
+ AC_MSG_RESULT("$LUA_PREFIX")
+ vi_cv_path_lua_pfx="$LUA_PREFIX"
+ else
+ AC_MSG_RESULT([not set, default to /usr])
+ vi_cv_path_lua_pfx="/usr"
+ fi
+ fi
+
+ AC_MSG_CHECKING(--with-luajit)
+ AC_ARG_WITH(luajit,
+ [ --with-luajit Link with LuaJIT instead of Lua.],
+ [vi_cv_with_luajit="$withval"],
+ [vi_cv_with_luajit="no"])
+ AC_MSG_RESULT($vi_cv_with_luajit)
+
+ LUA_INC=
+ if test "X$vi_cv_path_lua_pfx" != "X"; then
+ if test "x$vi_cv_with_luajit" != "xno"; then
+ dnl -- try to find LuaJIT executable
+ AC_PATH_PROG(vi_cv_path_luajit, luajit)
+ if test "X$vi_cv_path_luajit" != "X"; then
+ dnl -- find LuaJIT version
+ AC_CACHE_CHECK(LuaJIT version, vi_cv_version_luajit,
+ [ vi_cv_version_luajit=`${vi_cv_path_luajit} -v 2>&1 | sed 's/LuaJIT \([[0-9.]]*\)\.[[0-9]]\(-[[a-z0-9]]*\)* .*/\1/'` ])
+ AC_CACHE_CHECK(Lua version of LuaJIT, vi_cv_version_lua_luajit,
+ [ vi_cv_version_lua_luajit=`${vi_cv_path_luajit} -e "print(_VERSION)" | sed 's/.* //'` ])
+ vi_cv_path_lua="$vi_cv_path_luajit"
+ vi_cv_version_lua="$vi_cv_version_lua_luajit"
+ fi
+ else
+ dnl -- try to find Lua executable
+ AC_PATH_PROG(vi_cv_path_plain_lua, lua)
+ if test "X$vi_cv_path_plain_lua" != "X"; then
+ dnl -- find Lua version
+ AC_CACHE_CHECK(Lua version, vi_cv_version_plain_lua,
+ [ vi_cv_version_plain_lua=`${vi_cv_path_plain_lua} -e "print(_VERSION)" | sed 's/.* //'` ])
+ fi
+ vi_cv_path_lua="$vi_cv_path_plain_lua"
+ vi_cv_version_lua="$vi_cv_version_plain_lua"
+ fi
+ if test "x$vi_cv_with_luajit" != "xno" && test "X$vi_cv_version_luajit" != "X"; then
+ AC_MSG_CHECKING(if lua.h can be found in $vi_cv_path_lua_pfx/include/luajit-$vi_cv_version_luajit)
+ if test -f "$vi_cv_path_lua_pfx/include/luajit-$vi_cv_version_luajit/lua.h"; then
+ AC_MSG_RESULT(yes)
+ LUA_INC=/luajit-$vi_cv_version_luajit
+ fi
+ fi
+ if test "X$LUA_INC" = "X"; then
+ AC_MSG_CHECKING(if lua.h can be found in $vi_cv_path_lua_pfx/include)
+ if test -f "$vi_cv_path_lua_pfx/include/lua.h"; then
+ AC_MSG_RESULT(yes)
+ else
+ AC_MSG_RESULT(no)
+ AC_MSG_CHECKING(if lua.h can be found in $vi_cv_path_lua_pfx/include/lua$vi_cv_version_lua)
+ if test -f "$vi_cv_path_lua_pfx/include/lua$vi_cv_version_lua/lua.h"; then
+ AC_MSG_RESULT(yes)
+ LUA_INC=/lua$vi_cv_version_lua
+ else
+ AC_MSG_RESULT(no)
+ vi_cv_path_lua_pfx=
+ fi
+ fi
+ fi
+ fi
+
+ if test "X$vi_cv_path_lua_pfx" != "X"; then
+ if test "x$vi_cv_with_luajit" != "xno"; then
+ multiarch=`dpkg-architecture -qDEB_HOST_MULTIARCH 2> /dev/null`
+ if test "X$multiarch" != "X"; then
+ lib_multiarch="lib/${multiarch}"
+ else
+ lib_multiarch="lib"
+ fi
+ if test "X$vi_cv_version_lua" = "X"; then
+ LUA_LIBS="-L${vi_cv_path_lua_pfx}/${lib_multiarch} -lluajit"
+ else
+ LUA_LIBS="-L${vi_cv_path_lua_pfx}/${lib_multiarch} -lluajit-$vi_cv_version_lua"
+ fi
+ else
+ if test "X$LUA_INC" != "X"; then
+ dnl Test alternate location using version
+ LUA_LIBS="-L${vi_cv_path_lua_pfx}/lib -llua$vi_cv_version_lua"
+ else
+ LUA_LIBS="-L${vi_cv_path_lua_pfx}/lib -llua"
+ fi
+ fi
+ if test "$enable_luainterp" = "dynamic"; then
+ lua_ok="yes"
+ else
+ AC_MSG_CHECKING([if link with ${LUA_LIBS} is sane])
+ libs_save=$LIBS
+ LIBS="$LIBS $LUA_LIBS"
+ AC_TRY_LINK(,[ ],
+ AC_MSG_RESULT(yes); lua_ok="yes",
+ AC_MSG_RESULT(no); lua_ok="no"; LUA_LIBS="")
+ LIBS=$libs_save
+ fi
+ if test "x$lua_ok" = "xyes"; then
+ LUA_CFLAGS="-I${vi_cv_path_lua_pfx}/include${LUA_INC}"
+ LUA_SRC="if_lua.c"
+ LUA_OBJ="objects/if_lua.o"
+ LUA_PRO="if_lua.pro"
+ AC_DEFINE(FEAT_LUA)
+ fi
+ if test "$enable_luainterp" = "dynamic"; then
+ if test "x$vi_cv_with_luajit" != "xno"; then
+ luajit="jit"
+ fi
+ if test -f "${vi_cv_path_lua_pfx}/bin/cyglua-${vi_cv_version_lua}.dll"; then
+ vi_cv_dll_name_lua="cyglua-${vi_cv_version_lua}.dll"
+ else
+ if test "x$MACOS_X" = "xyes"; then
+ ext="dylib"
+ indexes=""
+ else
+ ext="so"
+ indexes=".0 .1 .2 .3 .4 .5 .6 .7 .8 .9"
+ multiarch=`dpkg-architecture -qDEB_HOST_MULTIARCH 2> /dev/null`
+ if test "X$multiarch" != "X"; then
+ lib_multiarch="lib/${multiarch}"
+ fi
+ fi
+ dnl Determine the sover for the current version, but fallback to
+ dnl liblua${vi_cv_version_lua}.so if no sover-versioned file is found.
+ AC_MSG_CHECKING(if liblua${luajit}*.${ext}* can be found in $vi_cv_path_lua_pfx)
+ for subdir in "${lib_multiarch}" lib64 lib; do
+ if test -z "$subdir"; then
+ continue
+ fi
+ for sover in "${vi_cv_version_lua}.${ext}" "-${vi_cv_version_lua}.${ext}" \
+ ".${vi_cv_version_lua}.${ext}" ".${ext}.${vi_cv_version_lua}"; do
+ for i in $indexes ""; do
+ if test -f "${vi_cv_path_lua_pfx}/${subdir}/liblua${luajit}${sover}$i"; then
+ sover2="$i"
+ break 3
+ fi
+ done
+ done
+ sover=""
+ done
+ if test "X$sover" = "X"; then
+ AC_MSG_RESULT(no)
+ lua_ok="no"
+ vi_cv_dll_name_lua="liblua${luajit}.${ext}"
+ else
+ AC_MSG_RESULT(yes)
+ lua_ok="yes"
+ vi_cv_dll_name_lua="liblua${luajit}${sover}$sover2"
+ fi
+ fi
+ AC_DEFINE(DYNAMIC_LUA)
+ LUA_LIBS=""
+ LUA_CFLAGS="-DDYNAMIC_LUA_DLL=\\\"${vi_cv_dll_name_lua}\\\" $LUA_CFLAGS"
+ fi
+ if test "X$LUA_CFLAGS$LUA_LIBS" != "X" && \
+ test "x$MACOS_X" = "xyes" && test "x$vi_cv_with_luajit" != "xno" && \
+ test "`(uname -m) 2>/dev/null`" = "x86_64"; then
+ dnl OSX/x64 requires these flags. See http://luajit.org/install.html
+ LUA_LIBS="-pagezero_size 10000 -image_base 100000000 $LUA_LIBS"
+ fi
+ fi
+ if test "$fail_if_missing" = "yes" -a "$lua_ok" != "yes"; then
+ AC_MSG_ERROR([could not configure lua])
+ fi
+ AC_SUBST(LUA_SRC)
+ AC_SUBST(LUA_OBJ)
+ AC_SUBST(LUA_PRO)
+ AC_SUBST(LUA_LIBS)
+ AC_SUBST(LUA_CFLAGS)
+fi
+
+
+dnl Check for MzScheme feature.
+AC_MSG_CHECKING(--enable-mzschemeinterp argument)
+AC_ARG_ENABLE(mzschemeinterp,
+ [ --enable-mzschemeinterp Include MzScheme interpreter.], ,
+ [enable_mzschemeinterp="no"])
+AC_MSG_RESULT($enable_mzschemeinterp)
+
+if test "$enable_mzschemeinterp" = "yes"; then
+ dnl -- find the mzscheme executable
+ AC_SUBST(vi_cv_path_mzscheme)
+
+ AC_MSG_CHECKING(--with-plthome argument)
+ AC_ARG_WITH(plthome,
+ [ --with-plthome=PLTHOME Use PLTHOME.],
+ with_plthome="$withval"; AC_MSG_RESULT($with_plthome),
+ with_plthome="";AC_MSG_RESULT("no"))
+
+ if test "X$with_plthome" != "X"; then
+ vi_cv_path_mzscheme_pfx="$with_plthome"
+ vi_cv_path_mzscheme="${vi_cv_path_mzscheme_pfx}/bin/mzscheme"
+ else
+ AC_MSG_CHECKING(PLTHOME environment var)
+ if test "X$PLTHOME" != "X"; then
+ AC_MSG_RESULT("$PLTHOME")
+ vi_cv_path_mzscheme_pfx="$PLTHOME"
+ vi_cv_path_mzscheme="${vi_cv_path_mzscheme_pfx}/bin/mzscheme"
+ else
+ AC_MSG_RESULT(not set)
+ dnl -- try to find MzScheme executable
+ AC_PATH_PROG(vi_cv_path_mzscheme, mzscheme)
+
+ dnl resolve symbolic link, the executable is often elsewhere and there
+ dnl are no links for the include files.
+ if test "X$vi_cv_path_mzscheme" != "X"; then
+ lsout=`ls -l $vi_cv_path_mzscheme`
+ if echo "$lsout" | grep -e '->' >/dev/null 2>/dev/null; then
+ vi_cv_path_mzscheme=`echo "$lsout" | sed 's/.*-> \(.*\)/\1/'`
+ fi
+ fi
+
+ if test "X$vi_cv_path_mzscheme" != "X"; then
+ dnl -- find where MzScheme thinks it was installed
+ AC_CACHE_CHECK(MzScheme install prefix,vi_cv_path_mzscheme_pfx,
+ dnl different versions of MzScheme differ in command line processing
+ dnl use universal approach
+ echo "(display (simplify-path \
+ (build-path (call-with-values \
+ (lambda () (split-path (find-system-path (quote exec-file)))) \
+ (lambda (base name must-be-dir?) base)) (quote up))))" > mzdirs.scm
+ dnl Remove a trailing slash
+ [ vi_cv_path_mzscheme_pfx=`${vi_cv_path_mzscheme} -r mzdirs.scm | \
+ sed -e 's+/$++'` ])
+ rm -f mzdirs.scm
+ fi
+ fi
+ fi
+
+ if test "X$vi_cv_path_mzscheme_pfx" != "X"; then
+ AC_MSG_CHECKING(for racket include directory)
+ SCHEME_INC=`${vi_cv_path_mzscheme} -e '(require setup/dirs)(let ((p (find-include-dir))) (when (path? p) (display p)))'`
+ if test "X$SCHEME_INC" != "X"; then
+ AC_MSG_RESULT(${SCHEME_INC})
+ else
+ AC_MSG_RESULT(not found)
+ AC_MSG_CHECKING(if scheme.h can be found in $vi_cv_path_mzscheme_pfx/include)
+ if test -f "$vi_cv_path_mzscheme_pfx/include/scheme.h"; then
+ SCHEME_INC=${vi_cv_path_mzscheme_pfx}/include
+ AC_MSG_RESULT(yes)
+ else
+ AC_MSG_RESULT(no)
+ AC_MSG_CHECKING(if scheme.h can be found in $vi_cv_path_mzscheme_pfx/include/plt)
+ if test -f "$vi_cv_path_mzscheme_pfx/include/plt/scheme.h"; then
+ AC_MSG_RESULT(yes)
+ SCHEME_INC=${vi_cv_path_mzscheme_pfx}/include/plt
+ else
+ AC_MSG_RESULT(no)
+ AC_MSG_CHECKING(if scheme.h can be found in $vi_cv_path_mzscheme_pfx/include/racket)
+ if test -f "$vi_cv_path_mzscheme_pfx/include/racket/scheme.h"; then
+ AC_MSG_RESULT(yes)
+ SCHEME_INC=${vi_cv_path_mzscheme_pfx}/include/racket
+ else
+ AC_MSG_RESULT(no)
+ AC_MSG_CHECKING(if scheme.h can be found in /usr/include/plt/)
+ if test -f /usr/include/plt/scheme.h; then
+ AC_MSG_RESULT(yes)
+ SCHEME_INC=/usr/include/plt
+ else
+ AC_MSG_RESULT(no)
+ AC_MSG_CHECKING(if scheme.h can be found in /usr/include/racket/)
+ if test -f /usr/include/racket/scheme.h; then
+ AC_MSG_RESULT(yes)
+ SCHEME_INC=/usr/include/racket
+ else
+ AC_MSG_RESULT(no)
+ vi_cv_path_mzscheme_pfx=
+ fi
+ fi
+ fi
+ fi
+ fi
+ fi
+ fi
+
+ if test "X$vi_cv_path_mzscheme_pfx" != "X"; then
+
+ AC_MSG_CHECKING(for racket lib directory)
+ SCHEME_LIB=`${vi_cv_path_mzscheme} -e '(require setup/dirs)(let ((p (find-lib-dir))) (when (path? p) (display p)))'`
+ if test "X$SCHEME_LIB" != "X"; then
+ AC_MSG_RESULT(${SCHEME_LIB})
+ else
+ AC_MSG_RESULT(not found)
+ fi
+
+ for path in "${vi_cv_path_mzscheme_pfx}/lib" "${SCHEME_LIB}"; do
+ if test "X$path" != "X"; then
+ if test "x$MACOS_X" = "xyes"; then
+ MZSCHEME_LIBS="-framework Racket"
+ MZSCHEME_CFLAGS="-DMZ_PRECISE_GC"
+ elif test -f "${path}/libmzscheme3m.a"; then
+ MZSCHEME_LIBS="${path}/libmzscheme3m.a"
+ MZSCHEME_CFLAGS="-DMZ_PRECISE_GC"
+ elif test -f "${path}/libracket3m.a"; then
+ MZSCHEME_LIBS="${path}/libracket3m.a"
+ MZSCHEME_CFLAGS="-DMZ_PRECISE_GC"
+ elif test -f "${path}/libracket.a"; then
+ MZSCHEME_LIBS="${path}/libracket.a ${path}/libmzgc.a"
+ elif test -f "${path}/libmzscheme.a"; then
+ MZSCHEME_LIBS="${path}/libmzscheme.a ${path}/libmzgc.a"
+ else
+ dnl Using shared objects
+ if test -f "${path}/libmzscheme3m.so"; then
+ MZSCHEME_LIBS="-L${path} -lmzscheme3m"
+ MZSCHEME_CFLAGS="-DMZ_PRECISE_GC"
+ elif test -f "${path}/libracket3m.so"; then
+ MZSCHEME_LIBS="-L${path} -lracket3m"
+ MZSCHEME_CFLAGS="-DMZ_PRECISE_GC"
+ elif test -f "${path}/libracket.so"; then
+ MZSCHEME_LIBS="-L${path} -lracket -lmzgc"
+ else
+ dnl try next until last
+ if test "$path" != "$SCHEME_LIB"; then
+ continue
+ fi
+ MZSCHEME_LIBS="-L${path} -lmzscheme -lmzgc"
+ fi
+ if test "$GCC" = yes; then
+ dnl Make Vim remember the path to the library. For when it's not in
+ dnl $LD_LIBRARY_PATH.
+ MZSCHEME_LIBS="${MZSCHEME_LIBS} -Wl,-rpath -Wl,${path}"
+ elif test "`(uname) 2>/dev/null`" = SunOS &&
+ uname -r | grep '^5' >/dev/null; then
+ MZSCHEME_LIBS="${MZSCHEME_LIBS} -R ${path}"
+ fi
+ fi
+ fi
+ if test "X$MZSCHEME_LIBS" != "X"; then
+ break
+ fi
+ done
+
+ AC_MSG_CHECKING([if racket requires -pthread])
+ if test "X$SCHEME_LIB" != "X" && $FGREP -e -pthread "$SCHEME_LIB/buildinfo" >/dev/null ; then
+ AC_MSG_RESULT(yes)
+ MZSCHEME_LIBS="${MZSCHEME_LIBS} -pthread"
+ MZSCHEME_CFLAGS="${MZSCHEME_CFLAGS} -pthread"
+ else
+ AC_MSG_RESULT(no)
+ fi
+
+ AC_MSG_CHECKING(for racket config directory)
+ SCHEME_CONFIGDIR=`${vi_cv_path_mzscheme} -e '(require setup/dirs)(let ((p (find-config-dir))) (when (path? p) (display p)))'`
+ if test "X$SCHEME_CONFIGDIR" != "X"; then
+ MZSCHEME_CFLAGS="${MZSCHEME_CFLAGS} -DMZSCHEME_CONFIGDIR='\"${SCHEME_CONFIGDIR}\"'"
+ AC_MSG_RESULT(${SCHEME_CONFIGDIR})
+ else
+ AC_MSG_RESULT(not found)
+ fi
+
+ AC_MSG_CHECKING(for racket collects directory)
+ SCHEME_COLLECTS=`${vi_cv_path_mzscheme} -e '(require setup/dirs)(let ((p (find-collects-dir))) (when (path? p) (let-values (((base _1 _2) (split-path p))) (display base))))'`
+ if test "X$SCHEME_COLLECTS" = "X"; then
+ if test -d "$vi_cv_path_mzscheme_pfx/lib/plt/collects"; then
+ SCHEME_COLLECTS=$vi_cv_path_mzscheme_pfx/lib/plt/
+ else
+ if test -d "$vi_cv_path_mzscheme_pfx/lib/racket/collects"; then
+ SCHEME_COLLECTS=$vi_cv_path_mzscheme_pfx/lib/racket/
+ else
+ if test -d "$vi_cv_path_mzscheme_pfx/share/racket/collects"; then
+ SCHEME_COLLECTS=$vi_cv_path_mzscheme_pfx/share/racket/
+ else
+ if test -d "$vi_cv_path_mzscheme_pfx/collects"; then
+ SCHEME_COLLECTS=$vi_cv_path_mzscheme_pfx/
+ fi
+ fi
+ fi
+ fi
+ fi
+ if test "X$SCHEME_COLLECTS" != "X" ; then
+ AC_MSG_RESULT(${SCHEME_COLLECTS})
+ else
+ AC_MSG_RESULT(not found)
+ fi
+
+ AC_MSG_CHECKING(for mzscheme_base.c)
+ if test -f "${SCHEME_COLLECTS}collects/scheme/base.ss" ; then
+ MZSCHEME_EXTRA="mzscheme_base.c"
+ MZSCHEME_MZC="${vi_cv_path_mzscheme_pfx}/bin/mzc"
+ MZSCHEME_MOD="++lib scheme/base"
+ else
+ if test -f "${SCHEME_COLLECTS}collects/scheme/base.rkt" ; then
+ MZSCHEME_EXTRA="mzscheme_base.c"
+ MZSCHEME_MZC="${vi_cv_path_mzscheme_pfx}/bin/mzc"
+ MZSCHEME_MOD="++lib scheme/base"
+ else
+ if test -f "${SCHEME_COLLECTS}collects/racket/base.rkt" ; then
+ MZSCHEME_EXTRA="mzscheme_base.c"
+ MZSCHEME_MZC="${vi_cv_path_mzscheme_pfx}/bin/raco ctool"
+ MZSCHEME_MOD=""
+ fi
+ fi
+ fi
+ if test "X$MZSCHEME_EXTRA" != "X" ; then
+ dnl need to generate bytecode for MzScheme base
+ MZSCHEME_CFLAGS="${MZSCHEME_CFLAGS} -DINCLUDE_MZSCHEME_BASE"
+ AC_MSG_RESULT(needed)
+ else
+ AC_MSG_RESULT(not needed)
+ fi
+
+ dnl On Ubuntu this fixes "undefined reference to symbol 'ffi_type_void'".
+ AC_CHECK_LIB(ffi, ffi_type_void, [MZSCHEME_LIBS="$MZSCHEME_LIBS -lffi"])
+
+ MZSCHEME_CFLAGS="${MZSCHEME_CFLAGS} -I${SCHEME_INC} \
+ -DMZSCHEME_COLLECTS='\"${SCHEME_COLLECTS}collects\"'"
+
+ dnl Test that we can compile a simple program with these CFLAGS and LIBS.
+ AC_MSG_CHECKING([if compile and link flags for MzScheme are sane])
+ cflags_save=$CFLAGS
+ libs_save=$LIBS
+ CFLAGS="$CFLAGS $MZSCHEME_CFLAGS"
+ LIBS="$LIBS $MZSCHEME_LIBS"
+ AC_TRY_LINK(,[ ],
+ AC_MSG_RESULT(yes); mzs_ok=yes,
+ AC_MSG_RESULT(no: MZSCHEME DISABLED); mzs_ok=no)
+ CFLAGS=$cflags_save
+ LIBS=$libs_save
+ if test $mzs_ok = yes; then
+ MZSCHEME_SRC="if_mzsch.c"
+ MZSCHEME_OBJ="objects/if_mzsch.o"
+ MZSCHEME_PRO="if_mzsch.pro"
+ AC_DEFINE(FEAT_MZSCHEME)
+ else
+ MZSCHEME_CFLAGS=
+ MZSCHEME_LIBS=
+ MZSCHEME_EXTRA=
+ MZSCHEME_MZC=
+ fi
+ fi
+ AC_SUBST(MZSCHEME_SRC)
+ AC_SUBST(MZSCHEME_OBJ)
+ AC_SUBST(MZSCHEME_PRO)
+ AC_SUBST(MZSCHEME_LIBS)
+ AC_SUBST(MZSCHEME_CFLAGS)
+ AC_SUBST(MZSCHEME_EXTRA)
+ AC_SUBST(MZSCHEME_MZC)
+fi
+
+
+AC_MSG_CHECKING(--enable-perlinterp argument)
+AC_ARG_ENABLE(perlinterp,
+ [ --enable-perlinterp[=OPTS] Include Perl interpreter. [default=no] [OPTS=no/yes/dynamic]], ,
+ [enable_perlinterp="no"])
+AC_MSG_RESULT($enable_perlinterp)
+if test "$enable_perlinterp" = "yes" -o "$enable_perlinterp" = "dynamic"; then
+ if test "x$features" = "xtiny" -o "x$features" = "xsmall"; then
+ AC_MSG_ERROR([cannot use Perl with tiny or small features])
+ fi
+ AC_SUBST(vi_cv_path_perl)
+ AC_PATH_PROG(vi_cv_path_perl, perl)
+ if test "X$vi_cv_path_perl" != "X"; then
+ AC_MSG_CHECKING(Perl version)
+ if $vi_cv_path_perl -e 'require 5.003_01' >/dev/null 2>/dev/null; then
+ eval `$vi_cv_path_perl -V:usethreads`
+ eval `$vi_cv_path_perl -V:libperl`
+ if test "X$usethreads" = "XUNKNOWN" -o "X$usethreads" = "Xundef"; then
+ badthreads=no
+ else
+ if $vi_cv_path_perl -e 'require 5.6.0' >/dev/null 2>/dev/null; then
+ eval `$vi_cv_path_perl -V:use5005threads`
+ if test "X$use5005threads" = "XUNKNOWN" -o "X$use5005threads" = "Xundef"; then
+ badthreads=no
+ else
+ badthreads=yes
+ AC_MSG_RESULT(>>> Perl > 5.6 with 5.5 threads cannot be used <<<)
+ fi
+ else
+ badthreads=yes
+ AC_MSG_RESULT(>>> Perl 5.5 with threads cannot be used <<<)
+ fi
+ fi
+ if test $badthreads = no; then
+ AC_MSG_RESULT(OK)
+ eval `$vi_cv_path_perl -V:shrpenv`
+ if test "X$shrpenv" = "XUNKNOWN"; then # pre 5.003_04
+ shrpenv=""
+ fi
+ vi_cv_perllib=`$vi_cv_path_perl -MConfig -e 'print $Config{privlibexp}'`
+ AC_SUBST(vi_cv_perllib)
+ vi_cv_perl_extutils=unknown_perl_extutils_path
+ for extutils_rel_path in ExtUtils vendor_perl/ExtUtils; do
+ xsubpp_path="$vi_cv_perllib/$extutils_rel_path/xsubpp"
+ if test -f "$xsubpp_path"; then
+ vi_cv_perl_xsubpp="$xsubpp_path"
+ fi
+ done
+ AC_SUBST(vi_cv_perl_xsubpp)
+ dnl Remove "-fno-something", it breaks using cproto.
+ dnl Remove "-fdebug-prefix-map", it isn't supported by clang.
+ dnl Remove "FORTIFY_SOURCE", it will be defined twice.
+ dnl remove -pipe and -Wxxx, it confuses cproto
+ perlcppflags=`$vi_cv_path_perl -Mlib=$srcdir -MExtUtils::Embed \
+ -e 'ccflags;perl_inc;print"\n"' | sed -e 's/-fno[[^ ]]*//' \
+ -e 's/-fdebug-prefix-map[[^ ]]*//g' \
+ -e 's/-pipe //' \
+ -e 's/-W[[^ ]]*//g' \
+ -e 's/-D_FORTIFY_SOURCE=.//g'`
+ dnl Remove "-lc", it breaks on FreeBSD when using "-pthread".
+ perllibs=`cd $srcdir; $vi_cv_path_perl -MExtUtils::Embed -e 'ldopts' | \
+ sed -e '/Warning/d' -e '/Note (probably harmless)/d' \
+ -e 's/-bE:perl.exp//' -e 's/-lc //'`
+ dnl Don't add perl lib to $LIBS: if it's not in LD_LIBRARY_PATH
+ dnl a test in configure may fail because of that.
+ perlldflags=`cd $srcdir; $vi_cv_path_perl -MExtUtils::Embed \
+ -e 'ccdlflags' | sed -e 's/-bE:perl.exp//'`
+
+ dnl check that compiling a simple program still works with the flags
+ dnl added for Perl.
+ AC_MSG_CHECKING([if compile and link flags for Perl are sane])
+ cflags_save=$CFLAGS
+ libs_save=$LIBS
+ ldflags_save=$LDFLAGS
+ CFLAGS="$CFLAGS $perlcppflags"
+ LIBS="$LIBS $perllibs"
+ perlldflags=`echo "$perlldflags" | sed -e 's/^ *//g'`
+ LDFLAGS="$perlldflags $LDFLAGS"
+ AC_TRY_LINK(,[ ],
+ AC_MSG_RESULT(yes); perl_ok=yes,
+ AC_MSG_RESULT(no: PERL DISABLED); perl_ok=no)
+ CFLAGS=$cflags_save
+ LIBS=$libs_save
+ LDFLAGS=$ldflags_save
+ if test $perl_ok = yes; then
+ if test "X$perlcppflags" != "X"; then
+ PERL_CFLAGS=$perlcppflags
+ fi
+ if test "X$perlldflags" != "X"; then
+ if test "X`echo \"$LDFLAGS\" | $FGREP -e \"$perlldflags\"`" = "X"; then
+ LDFLAGS="$perlldflags $LDFLAGS"
+ fi
+ fi
+ PERL_LIBS=$perllibs
+ PERL_SRC="auto/if_perl.c if_perlsfio.c"
+ PERL_OBJ="objects/if_perl.o objects/if_perlsfio.o"
+ PERL_PRO="if_perl.pro if_perlsfio.pro"
+ AC_DEFINE(FEAT_PERL)
+ fi
+ fi
+ else
+ AC_MSG_RESULT(>>> too old; need Perl version 5.003_01 or later <<<)
+ fi
+ fi
+
+ if test "x$MACOS_X" = "xyes"; then
+ dnl Mac OS X 10.2 or later
+ dir=/System/Library/Perl
+ darwindir=$dir/darwin
+ if test -d $darwindir; then
+ PERL=/usr/bin/perl
+ else
+ dnl Mac OS X 10.3
+ dir=/System/Library/Perl/5.8.1
+ darwindir=$dir/darwin-thread-multi-2level
+ if test -d $darwindir; then
+ PERL=/usr/bin/perl
+ fi
+ fi
+ if test -n "$PERL"; then
+ PERL_DIR="$dir"
+ PERL_CFLAGS="-DFEAT_PERL -I$darwindir/CORE"
+ PERL_OBJ="objects/if_perl.o objects/if_perlsfio.o $darwindir/auto/DynaLoader/DynaLoader.a"
+ PERL_LIBS="-L$darwindir/CORE -lperl"
+ fi
+ dnl Perl on Mac OS X 10.5 adds "-arch" flags but these should only
+ dnl be included if requested by passing --with-mac-arch to
+ dnl configure, so strip these flags first (if present)
+ PERL_LIBS=`echo "$PERL_LIBS" | sed -e 's/-arch\ ppc//' -e 's/-arch\ i386//' -e 's/-arch\ x86_64//'`
+ PERL_CFLAGS=`echo "$PERL_CFLAGS" | sed -e 's/-arch\ ppc//' -e 's/-arch\ i386//' -e 's/-arch\ x86_64//'`
+ fi
+ if test "$enable_perlinterp" = "dynamic"; then
+ if test "$perl_ok" = "yes" -a "X$libperl" != "X"; then
+ AC_DEFINE(DYNAMIC_PERL)
+ PERL_CFLAGS="-DDYNAMIC_PERL_DLL=\\\"$libperl\\\" $PERL_CFLAGS"
+ fi
+ fi
+
+ if test "$fail_if_missing" = "yes" -a "$perl_ok" != "yes"; then
+ AC_MSG_ERROR([could not configure perl])
+ fi
+fi
+AC_SUBST(shrpenv)
+AC_SUBST(PERL_SRC)
+AC_SUBST(PERL_OBJ)
+AC_SUBST(PERL_PRO)
+AC_SUBST(PERL_CFLAGS)
+AC_SUBST(PERL_LIBS)
+
+AC_MSG_CHECKING(--enable-pythoninterp argument)
+AC_ARG_ENABLE(pythoninterp,
+ [ --enable-pythoninterp[=OPTS] Include Python interpreter. [default=no] [OPTS=no/yes/dynamic]], ,
+ [enable_pythoninterp="no"])
+AC_MSG_RESULT($enable_pythoninterp)
+if test "$enable_pythoninterp" = "yes" -o "$enable_pythoninterp" = "dynamic"; then
+ if test "x$features" = "xtiny" -o "x$features" = "xsmall"; then
+ AC_MSG_ERROR([cannot use Python with tiny or small features])
+ fi
+
+ dnl -- find the python executable
+ AC_MSG_CHECKING(--with-python-command argument)
+ AC_SUBST(vi_cv_path_python)
+ AC_ARG_WITH(python-command, [ --with-python-command=NAME name of the Python 2 command (default: python2 or python)],
+ vi_cv_path_python="$withval"; AC_MSG_RESULT($vi_cv_path_python),
+ AC_MSG_RESULT(no))
+
+ if test "X$vi_cv_path_python" = "X"; then
+ AC_PATH_PROGS(vi_cv_path_python, python2 python)
+ fi
+ if test "X$vi_cv_path_python" != "X"; then
+
+ dnl -- get its version number
+ AC_CACHE_CHECK(Python version,vi_cv_var_python_version,
+ [[vi_cv_var_python_version=`
+ ${vi_cv_path_python} -c 'import sys; print sys.version[:3]'`
+ ]])
+
+ dnl -- it must be at least version 2.3
+ AC_MSG_CHECKING(Python is 2.3 or better)
+ if ${vi_cv_path_python} -c \
+ "import sys; sys.exit(${vi_cv_var_python_version} < 2.3)"
+ then
+ AC_MSG_RESULT(yep)
+
+ dnl -- find where python thinks it was installed
+ AC_CACHE_CHECK(Python's install prefix,vi_cv_path_python_pfx,
+ [ vi_cv_path_python_pfx=`
+ ${vi_cv_path_python} -c \
+ "import sys; print sys.prefix"` ])
+
+ dnl -- and where it thinks it runs
+ AC_CACHE_CHECK(Python's execution prefix,vi_cv_path_python_epfx,
+ [ vi_cv_path_python_epfx=`
+ ${vi_cv_path_python} -c \
+ "import sys; print sys.exec_prefix"` ])
+
+ dnl -- python's internal library path
+
+ AC_CACHE_VAL(vi_cv_path_pythonpath,
+ [ vi_cv_path_pythonpath=`
+ unset PYTHONPATH;
+ ${vi_cv_path_python} -c \
+ "import sys, string; print string.join(sys.path,':')"` ])
+
+ dnl -- where the Python implementation library archives are
+
+ AC_ARG_WITH(python-config-dir,
+ [ --with-python-config-dir=PATH Python's config directory (deprecated)],
+ [ vi_cv_path_python_conf="${withval}"; have_python_config_dir=1 ] )
+
+ AC_CACHE_CHECK(Python's configuration directory,vi_cv_path_python_conf,
+ [
+ vi_cv_path_python_conf=
+ d=`${vi_cv_path_python} -c "import distutils.sysconfig; print distutils.sysconfig.get_config_var('LIBPL')"`
+ if test -d "$d" && test -f "$d/config.c"; then
+ vi_cv_path_python_conf="$d"
+ else
+ for path in "${vi_cv_path_python_pfx}" "${vi_cv_path_python_epfx}"; do
+ for subdir in lib64 lib share; do
+ d="${path}/${subdir}/python${vi_cv_var_python_version}/config"
+ if test -d "$d" && test -f "$d/config.c"; then
+ vi_cv_path_python_conf="$d"
+ fi
+ done
+ done
+ fi
+ ])
+
+ PYTHON_CONFDIR="${vi_cv_path_python_conf}"
+
+ if test "X$PYTHON_CONFDIR" = "X"; then
+ AC_MSG_RESULT([can't find it!])
+ else
+
+ dnl -- we need to examine Python's config/Makefile too
+ dnl see what the interpreter is built from
+ AC_CACHE_VAL(vi_cv_path_python_plibs,
+ [
+ pwd=`pwd`
+ tmp_mkf="$pwd/config-PyMake$$"
+ cat -- "${PYTHON_CONFDIR}/Makefile" - <<'eof' >"${tmp_mkf}"
+__:
+ @echo "python_BASEMODLIBS='$(BASEMODLIBS)'"
+ @echo "python_LIBS='$(LIBS)'"
+ @echo "python_SYSLIBS='$(SYSLIBS)'"
+ @echo "python_LINKFORSHARED='$(LINKFORSHARED)'"
+ @echo "python_DLLLIBRARY='$(DLLLIBRARY)'"
+ @echo "python_INSTSONAME='$(INSTSONAME)'"
+ @echo "python_PYTHONFRAMEWORK='$(PYTHONFRAMEWORK)'"
+ @echo "python_PYTHONFRAMEWORKPREFIX='$(PYTHONFRAMEWORKPREFIX)'"
+ @echo "python_PYTHONFRAMEWORKINSTALLDIR='$(PYTHONFRAMEWORKINSTALLDIR)'"
+eof
+ dnl -- delete the lines from make about Entering/Leaving directory
+ eval "`cd ${PYTHON_CONFDIR} && make -f "${tmp_mkf}" __ | sed '/ directory /d'`"
+ rm -f -- "${tmp_mkf}"
+ if test "x$MACOS_X" = "xyes" && test -n "${python_PYTHONFRAMEWORK}" && ${vi_cv_path_python} -c \
+ "import sys; sys.exit(${vi_cv_var_python_version} < 2.3)"; then
+ vi_cv_path_python_plibs="-framework Python"
+ if test "x${vi_cv_path_python}" != "x/usr/bin/python" && test -n "${python_PYTHONFRAMEWORKPREFIX}"; then
+ vi_cv_path_python_plibs="-F${python_PYTHONFRAMEWORKPREFIX} -framework Python"
+ fi
+ else
+ vi_cv_path_python_plibs="-L${PYTHON_CONFDIR} -lpython${vi_cv_var_python_version}"
+ dnl -- Check if the path contained in python_LINKFORSHARED is
+ dnl usable for vim build. If not, make and try other
+ dnl candidates.
+ if test -n "${python_LINKFORSHARED}" && test -n "${python_PYTHONFRAMEWORKPREFIX}"; then
+ python_link_symbol=`echo ${python_LINKFORSHARED} | sed 's/\([[^ \t]][[^ \t]]*[[ \t]][[ \t]]*[[^ \t]][[^ \t]]*\)[[ \t]].*/\1/'`
+ python_link_path=`echo ${python_LINKFORSHARED} | sed 's/\([[^ \t]][[^ \t]]*[[ \t]][[ \t]]*[[^ \t]][[^ \t]]*\)[[ \t]][[ \t]]*\(.*\)/\2/'`
+ if test -n "${python_link_path}" && ! test -x "${python_link_path}"; then
+ dnl -- The path looks relative. Guess the absolute one using
+ dnl the prefix and try that.
+ python_link_path="${python_PYTHONFRAMEWORKPREFIX}/${python_link_path}"
+ if test -n "${python_link_path}" && ! test -x "${python_link_path}"; then
+ dnl -- A last resort.
+ python_link_path="${python_PYTHONFRAMEWORKINSTALLDIR}/Versions/${vi_cv_var_python_version}/${python_PYTHONFRAMEWORK}"
+ dnl -- No check is done. The last word is left to the
+ dnl "sanity" test on link flags that follows shortly.
+ fi
+ python_LINKFORSHARED="${python_link_symbol} ${python_link_path}"
+ fi
+ fi
+ vi_cv_path_python_plibs="${vi_cv_path_python_plibs} ${python_BASEMODLIBS} ${python_LIBS} ${python_SYSLIBS} ${python_LINKFORSHARED}"
+ dnl remove -ltermcap, it can conflict with an earlier -lncurses
+ vi_cv_path_python_plibs=`echo $vi_cv_path_python_plibs | sed s/-ltermcap//`
+ fi
+ ])
+ AC_CACHE_CHECK(Python's dll name,vi_cv_dll_name_python,
+ [
+ if test "X$python_DLLLIBRARY" != "X"; then
+ vi_cv_dll_name_python="$python_DLLLIBRARY"
+ else
+ vi_cv_dll_name_python="$python_INSTSONAME"
+ fi
+ ])
+
+ PYTHON_LIBS="${vi_cv_path_python_plibs}"
+ if test "${vi_cv_path_python_pfx}" = "${vi_cv_path_python_epfx}"; then
+ PYTHON_CFLAGS="-I${vi_cv_path_python_pfx}/include/python${vi_cv_var_python_version}"
+ else
+ PYTHON_CFLAGS="-I${vi_cv_path_python_pfx}/include/python${vi_cv_var_python_version} -I${vi_cv_path_python_epfx}/include/python${vi_cv_var_python_version}"
+ fi
+ if test "X$have_python_config_dir" = "X1" -a "$enable_pythoninterp" = "dynamic"; then
+ dnl Define PYTHON_HOME if --with-python-config-dir was used
+ PYTHON_CFLAGS="${PYTHON_CFLAGS} -DPYTHON_HOME='\"${vi_cv_path_python_pfx}\"'"
+
+ fi
+ PYTHON_SRC="if_python.c"
+ PYTHON_OBJ="objects/if_python.o"
+
+ dnl On FreeBSD linking with "-pthread" is required to use threads.
+ dnl _THREAD_SAFE must be used for compiling then.
+ dnl The "-pthread" is added to $LIBS, so that the following check for
+ dnl sigaltstack() will look in libc_r (it's there in libc!).
+ dnl Otherwise, when using GCC, try adding -pthread to $CFLAGS. GCC
+ dnl will then define target-specific defines, e.g., -D_REENTRANT.
+ dnl Don't do this for Mac OSX, -pthread will generate a warning.
+ AC_MSG_CHECKING([if -pthread should be used])
+ threadsafe_flag=
+ thread_lib=
+ dnl if test "x$MACOS_X" != "xyes"; then
+ if test "`(uname) 2>/dev/null`" != Darwin; then
+ test "$GCC" = yes && threadsafe_flag="-pthread"
+ if test "`(uname) 2>/dev/null`" = FreeBSD; then
+ threadsafe_flag="-D_THREAD_SAFE"
+ thread_lib="-pthread"
+ fi
+ if test "`(uname) 2>/dev/null`" = SunOS; then
+ threadsafe_flag="-pthreads"
+ fi
+ fi
+ libs_save_old=$LIBS
+ if test -n "$threadsafe_flag"; then
+ cflags_save=$CFLAGS
+ CFLAGS="$CFLAGS $threadsafe_flag"
+ LIBS="$LIBS $thread_lib"
+ AC_TRY_LINK(,[ ],
+ AC_MSG_RESULT(yes); PYTHON_CFLAGS="$PYTHON_CFLAGS $threadsafe_flag",
+ AC_MSG_RESULT(no); LIBS=$libs_save_old
+ )
+ CFLAGS=$cflags_save
+ else
+ AC_MSG_RESULT(no)
+ fi
+
+ dnl Check that compiling a simple program still works with the flags
+ dnl added for Python.
+ AC_MSG_CHECKING([if compile and link flags for Python are sane])
+ cflags_save=$CFLAGS
+ libs_save=$LIBS
+ CFLAGS="$CFLAGS $PYTHON_CFLAGS"
+ LIBS="$LIBS $PYTHON_LIBS"
+ AC_TRY_LINK(,[ ],
+ AC_MSG_RESULT(yes); python_ok=yes,
+ AC_MSG_RESULT(no: PYTHON DISABLED); python_ok=no)
+ CFLAGS=$cflags_save
+ LIBS=$libs_save
+ if test $python_ok = yes; then
+ AC_DEFINE(FEAT_PYTHON)
+ else
+ LIBS=$libs_save_old
+ PYTHON_SRC=
+ PYTHON_OBJ=
+ PYTHON_LIBS=
+ PYTHON_CFLAGS=
+ fi
+ fi
+ else
+ AC_MSG_RESULT(too old)
+ fi
+ fi
+
+ if test "$fail_if_missing" = "yes" -a "$python_ok" != "yes"; then
+ AC_MSG_ERROR([could not configure python])
+ fi
+fi
+
+AC_SUBST(PYTHON_LIBS)
+AC_SUBST(PYTHON_CFLAGS)
+AC_SUBST(PYTHON_SRC)
+AC_SUBST(PYTHON_OBJ)
+
+
+AC_MSG_CHECKING(--enable-python3interp argument)
+AC_ARG_ENABLE(python3interp,
+ [ --enable-python3interp[=OPTS] Include Python3 interpreter. [default=no] [OPTS=no/yes/dynamic]], ,
+ [enable_python3interp="no"])
+AC_MSG_RESULT($enable_python3interp)
+if test "$enable_python3interp" = "yes" -o "$enable_python3interp" = "dynamic"; then
+ if test "x$features" = "xtiny" -o "x$features" = "xsmall"; then
+ AC_MSG_ERROR([cannot use Python with tiny or small features])
+ fi
+
+ dnl -- find the python3 executable
+ AC_MSG_CHECKING(--with-python3-command argument)
+ AC_SUBST(vi_cv_path_python3)
+ AC_ARG_WITH(python3-command, [ --with-python3-command=NAME name of the Python 3 command (default: python3 or python)],
+ vi_cv_path_python3="$withval"; AC_MSG_RESULT($vi_cv_path_python3),
+ AC_MSG_RESULT(no))
+
+ if test "X$vi_cv_path_python3" = "X"; then
+ AC_PATH_PROGS(vi_cv_path_python3, python3 python)
+ fi
+ if test "X$vi_cv_path_python3" != "X"; then
+
+ dnl -- get its version number
+ AC_CACHE_CHECK(Python version,vi_cv_var_python3_version,
+ [[vi_cv_var_python3_version=`
+ ${vi_cv_path_python3} -c 'import sys; print(sys.version[:3])'`
+ ]])
+
+ dnl -- it must be at least version 3
+ AC_MSG_CHECKING(Python is 3.0 or better)
+ if ${vi_cv_path_python3} -c \
+ "import sys; sys.exit(${vi_cv_var_python3_version} < 3.0)"
+ then
+ AC_MSG_RESULT(yep)
+
+ dnl -- get abiflags for python 3.2 or higher (PEP 3149)
+ AC_CACHE_CHECK(Python's abiflags,vi_cv_var_python3_abiflags,
+ [
+ vi_cv_var_python3_abiflags=
+ if ${vi_cv_path_python3} -c \
+ "import sys; sys.exit(${vi_cv_var_python3_version} < 3.2)"
+ then
+ vi_cv_var_python3_abiflags=`${vi_cv_path_python3} -c \
+ "import sys; print(sys.abiflags)"`
+ fi ])
+
+ dnl -- find where python3 thinks it was installed
+ AC_CACHE_CHECK(Python's install prefix,vi_cv_path_python3_pfx,
+ [ vi_cv_path_python3_pfx=`
+ ${vi_cv_path_python3} -c \
+ "import sys; print(sys.prefix)"` ])
+
+ dnl -- and where it thinks it runs
+ AC_CACHE_CHECK(Python's execution prefix,vi_cv_path_python3_epfx,
+ [ vi_cv_path_python3_epfx=`
+ ${vi_cv_path_python3} -c \
+ "import sys; print(sys.exec_prefix)"` ])
+
+ dnl -- python3's internal library path
+
+ AC_CACHE_VAL(vi_cv_path_python3path,
+ [ vi_cv_path_python3path=`
+ unset PYTHONPATH;
+ ${vi_cv_path_python3} -c \
+ "import sys, string; print(':'.join(sys.path))"` ])
+
+ dnl -- where the Python implementation library archives are
+
+ AC_ARG_WITH(python3-config-dir,
+ [ --with-python3-config-dir=PATH Python's config directory (deprecated)],
+ [ vi_cv_path_python3_conf="${withval}"; have_python3_config_dir=1 ] )
+
+ AC_CACHE_CHECK(Python's configuration directory,vi_cv_path_python3_conf,
+ [
+ vi_cv_path_python3_conf=
+ config_dir="config-${vi_cv_var_python3_version}${vi_cv_var_python3_abiflags}"
+ d=`${vi_cv_path_python3} -c "import distutils.sysconfig; print(distutils.sysconfig.get_config_var('LIBPL'))"`
+ if test -d "$d" && test -f "$d/config.c"; then
+ vi_cv_path_python3_conf="$d"
+ else
+ for path in "${vi_cv_path_python3_pfx}" "${vi_cv_path_python3_epfx}"; do
+ for subdir in lib64 lib share; do
+ d="${path}/${subdir}/python${vi_cv_var_python3_version}/${config_dir}"
+ if test -d "$d" && test -f "$d/config.c"; then
+ vi_cv_path_python3_conf="$d"
+ fi
+ done
+ done
+ fi
+ ])
+
+ PYTHON3_CONFDIR="${vi_cv_path_python3_conf}"
+
+ if test "X$PYTHON3_CONFDIR" = "X"; then
+ AC_MSG_RESULT([can't find it!])
+ else
+
+ dnl -- we need to examine Python's config/Makefile too
+ dnl see what the interpreter is built from
+ AC_CACHE_VAL(vi_cv_path_python3_plibs,
+ [
+ pwd=`pwd`
+ tmp_mkf="$pwd/config-PyMake$$"
+ cat -- "${PYTHON3_CONFDIR}/Makefile" - <<'eof' >"${tmp_mkf}"
+__:
+ @echo "python3_BASEMODLIBS='$(BASEMODLIBS)'"
+ @echo "python3_LIBS='$(LIBS)'"
+ @echo "python3_SYSLIBS='$(SYSLIBS)'"
+ @echo "python3_DLLLIBRARY='$(DLLLIBRARY)'"
+ @echo "python3_INSTSONAME='$(INSTSONAME)'"
+eof
+ dnl -- delete the lines from make about Entering/Leaving directory
+ eval "`cd ${PYTHON3_CONFDIR} && make -f "${tmp_mkf}" __ | sed '/ directory /d'`"
+ rm -f -- "${tmp_mkf}"
+ vi_cv_path_python3_plibs="-L${PYTHON3_CONFDIR} -lpython${vi_cv_var_python3_version}${vi_cv_var_python3_abiflags}"
+ vi_cv_path_python3_plibs="${vi_cv_path_python3_plibs} ${python3_BASEMODLIBS} ${python3_LIBS} ${python3_SYSLIBS}"
+ dnl remove -ltermcap, it can conflict with an earlier -lncurses
+ vi_cv_path_python3_plibs=`echo $vi_cv_path_python3_plibs | sed s/-ltermcap//`
+ vi_cv_path_python3_plibs=`echo $vi_cv_path_python3_plibs | sed s/-lffi//`
+ ])
+ AC_CACHE_CHECK(Python3's dll name,vi_cv_dll_name_python3,
+ [
+ if test "X$python3_DLLLIBRARY" != "X"; then
+ vi_cv_dll_name_python3="$python3_DLLLIBRARY"
+ else
+ vi_cv_dll_name_python3="$python3_INSTSONAME"
+ fi
+ ])
+
+ PYTHON3_LIBS="${vi_cv_path_python3_plibs}"
+ if test "${vi_cv_path_python3_pfx}" = "${vi_cv_path_python3_epfx}"; then
+ PYTHON3_CFLAGS="-I${vi_cv_path_python3_pfx}/include/python${vi_cv_var_python3_version}${vi_cv_var_python3_abiflags}"
+ else
+ PYTHON3_CFLAGS="-I${vi_cv_path_python3_pfx}/include/python${vi_cv_var_python3_version}${vi_cv_var_python3_abiflags} -I${vi_cv_path_python3_epfx}/include/python${vi_cv_var_python3_version}${vi_cv_var_python3_abiflags}"
+ fi
+ if test "X$have_python3_config_dir" = "X1" -a "$enable_python3interp" = "dynamic"; then
+ dnl Define PYTHON3_HOME if --with-python-config-dir was used
+ PYTHON3_CFLAGS="${PYTHON3_CFLAGS} -DPYTHON3_HOME='L\"${vi_cv_path_python3_pfx}\"'"
+ fi
+ PYTHON3_SRC="if_python3.c"
+ PYTHON3_OBJ="objects/if_python3.o"
+
+ dnl On FreeBSD linking with "-pthread" is required to use threads.
+ dnl _THREAD_SAFE must be used for compiling then.
+ dnl The "-pthread" is added to $LIBS, so that the following check for
+ dnl sigaltstack() will look in libc_r (it's there in libc!).
+ dnl Otherwise, when using GCC, try adding -pthread to $CFLAGS. GCC
+ dnl will then define target-specific defines, e.g., -D_REENTRANT.
+ dnl Don't do this for Mac OSX, -pthread will generate a warning.
+ AC_MSG_CHECKING([if -pthread should be used])
+ threadsafe_flag=
+ thread_lib=
+ dnl if test "x$MACOS_X" != "xyes"; then
+ if test "`(uname) 2>/dev/null`" != Darwin; then
+ test "$GCC" = yes && threadsafe_flag="-pthread"
+ if test "`(uname) 2>/dev/null`" = FreeBSD; then
+ threadsafe_flag="-D_THREAD_SAFE"
+ thread_lib="-pthread"
+ fi
+ if test "`(uname) 2>/dev/null`" = SunOS; then
+ threadsafe_flag="-pthreads"
+ fi
+ fi
+ libs_save_old=$LIBS
+ if test -n "$threadsafe_flag"; then
+ cflags_save=$CFLAGS
+ CFLAGS="$CFLAGS $threadsafe_flag"
+ LIBS="$LIBS $thread_lib"
+ AC_TRY_LINK(,[ ],
+ AC_MSG_RESULT(yes); PYTHON3_CFLAGS="$PYTHON3_CFLAGS $threadsafe_flag",
+ AC_MSG_RESULT(no); LIBS=$libs_save_old
+ )
+ CFLAGS=$cflags_save
+ else
+ AC_MSG_RESULT(no)
+ fi
+
+ dnl check that compiling a simple program still works with the flags
+ dnl added for Python.
+ AC_MSG_CHECKING([if compile and link flags for Python 3 are sane])
+ cflags_save=$CFLAGS
+ libs_save=$LIBS
+ CFLAGS="$CFLAGS $PYTHON3_CFLAGS"
+ LIBS="$LIBS $PYTHON3_LIBS"
+ AC_TRY_LINK(,[ ],
+ AC_MSG_RESULT(yes); python3_ok=yes,
+ AC_MSG_RESULT(no: PYTHON3 DISABLED); python3_ok=no)
+ CFLAGS=$cflags_save
+ LIBS=$libs_save
+ if test "$python3_ok" = yes; then
+ AC_DEFINE(FEAT_PYTHON3)
+ else
+ LIBS=$libs_save_old
+ PYTHON3_SRC=
+ PYTHON3_OBJ=
+ PYTHON3_LIBS=
+ PYTHON3_CFLAGS=
+ fi
+ fi
+ else
+ AC_MSG_RESULT(too old)
+ fi
+ fi
+ if test "$fail_if_missing" = "yes" -a "$python3_ok" != "yes"; then
+ AC_MSG_ERROR([could not configure python3])
+ fi
+fi
+
+AC_SUBST(PYTHON3_LIBS)
+AC_SUBST(PYTHON3_CFLAGS)
+AC_SUBST(PYTHON3_SRC)
+AC_SUBST(PYTHON3_OBJ)
+
+dnl if python2.x and python3.x are enabled one can only link in code
+dnl with dlopen(), dlsym(), dlclose()
+if test "$python_ok" = yes && test "$python3_ok" = yes; then
+ AC_DEFINE(DYNAMIC_PYTHON)
+ AC_DEFINE(DYNAMIC_PYTHON3)
+ AC_MSG_CHECKING(whether we can do without RTLD_GLOBAL for Python)
+ cflags_save=$CFLAGS
+ CFLAGS="$CFLAGS $PYTHON_CFLAGS"
+ libs_save=$LIBS
+ dnl -ldl must go first to make this work on Archlinux (Roland Puntaier)
+ LIBS="-ldl $LIBS"
+ AC_RUN_IFELSE([AC_LANG_SOURCE([
+ #include <dlfcn.h>
+ /* If this program fails, then RTLD_GLOBAL is needed.
+ * RTLD_GLOBAL will be used and then it is not possible to
+ * have both python versions enabled in the same vim instance.
+ * Only the first python version used will be switched on.
+ */
+
+ int no_rtl_global_needed_for(char *python_instsoname, char *prefix)
+ {
+ int needed = 0;
+ void* pylib = dlopen(python_instsoname, RTLD_LAZY|RTLD_LOCAL);
+ if (pylib != 0)
+ {
+ void (*pfx)(char *home) = dlsym(pylib, "Py_SetPythonHome");
+ void (*init)(void) = dlsym(pylib, "Py_Initialize");
+ int (*simple)(char*) = dlsym(pylib, "PyRun_SimpleString");
+ void (*final)(void) = dlsym(pylib, "Py_Finalize");
+ (*pfx)(prefix);
+ (*init)();
+ needed = (*simple)("import termios") == -1;
+ (*final)();
+ dlclose(pylib);
+ }
+ return !needed;
+ }
+
+ int main(int argc, char** argv)
+ {
+ int not_needed = 0;
+ if (no_rtl_global_needed_for("${vi_cv_dll_name_python}", "${vi_cv_path_python_pfx}"))
+ not_needed = 1;
+ return !not_needed;
+ }])],
+ [AC_MSG_RESULT(yes);AC_DEFINE(PY_NO_RTLD_GLOBAL)], [AC_MSG_RESULT(no)])
+
+ CFLAGS=$cflags_save
+ LIBS=$libs_save
+
+ AC_MSG_CHECKING(whether we can do without RTLD_GLOBAL for Python3)
+ cflags_save=$CFLAGS
+ CFLAGS="$CFLAGS $PYTHON3_CFLAGS"
+ libs_save=$LIBS
+ dnl -ldl must go first to make this work on Archlinux (Roland Puntaier)
+ LIBS="-ldl $LIBS"
+ AC_RUN_IFELSE([AC_LANG_SOURCE([
+ #include <dlfcn.h>
+ #include <wchar.h>
+ /* If this program fails, then RTLD_GLOBAL is needed.
+ * RTLD_GLOBAL will be used and then it is not possible to
+ * have both python versions enabled in the same vim instance.
+ * Only the first python version used will be switched on.
+ */
+
+ int no_rtl_global_needed_for(char *python_instsoname, wchar_t *prefix)
+ {
+ int needed = 0;
+ void* pylib = dlopen(python_instsoname, RTLD_LAZY|RTLD_LOCAL);
+ if (pylib != 0)
+ {
+ void (*pfx)(wchar_t *home) = dlsym(pylib, "Py_SetPythonHome");
+ void (*init)(void) = dlsym(pylib, "Py_Initialize");
+ int (*simple)(char*) = dlsym(pylib, "PyRun_SimpleString");
+ void (*final)(void) = dlsym(pylib, "Py_Finalize");
+ (*pfx)(prefix);
+ (*init)();
+ needed = (*simple)("import termios") == -1;
+ (*final)();
+ dlclose(pylib);
+ }
+ return !needed;
+ }
+
+ int main(int argc, char** argv)
+ {
+ int not_needed = 0;
+ if (no_rtl_global_needed_for("${vi_cv_dll_name_python3}", L"${vi_cv_path_python3_pfx}"))
+ not_needed = 1;
+ return !not_needed;
+ }])],
+ [AC_MSG_RESULT(yes);AC_DEFINE(PY3_NO_RTLD_GLOBAL)], [AC_MSG_RESULT(no)])
+
+ CFLAGS=$cflags_save
+ LIBS=$libs_save
+
+ PYTHON_SRC="if_python.c"
+ PYTHON_OBJ="objects/if_python.o"
+ PYTHON_CFLAGS="$PYTHON_CFLAGS -DDYNAMIC_PYTHON_DLL=\\\"${vi_cv_dll_name_python}\\\""
+ PYTHON_LIBS=
+ PYTHON3_SRC="if_python3.c"
+ PYTHON3_OBJ="objects/if_python3.o"
+ PYTHON3_CFLAGS="$PYTHON3_CFLAGS -DDYNAMIC_PYTHON3_DLL=\\\"${vi_cv_dll_name_python3}\\\""
+ PYTHON3_LIBS=
+elif test "$python_ok" = yes && test "$enable_pythoninterp" = "dynamic"; then
+ AC_DEFINE(DYNAMIC_PYTHON)
+ PYTHON_SRC="if_python.c"
+ PYTHON_OBJ="objects/if_python.o"
+ PYTHON_CFLAGS="$PYTHON_CFLAGS -DDYNAMIC_PYTHON_DLL=\\\"${vi_cv_dll_name_python}\\\""
+ PYTHON_LIBS=
+elif test "$python_ok" = yes; then
+ dnl Check that adding -fPIE works. It may be needed when using a static
+ dnl Python library.
+ AC_MSG_CHECKING([if -fPIE can be added for Python])
+ cflags_save=$CFLAGS
+ libs_save=$LIBS
+ CFLAGS="$CFLAGS $PYTHON_CFLAGS -fPIE"
+ LIBS="$LIBS $PYTHON_LIBS"
+ AC_TRY_LINK(,[ ],
+ AC_MSG_RESULT(yes); fpie_ok=yes,
+ AC_MSG_RESULT(no); fpie_ok=no)
+ CFLAGS=$cflags_save
+ LIBS=$libs_save
+ if test $fpie_ok = yes; then
+ PYTHON_CFLAGS="$PYTHON_CFLAGS -fPIE"
+ fi
+elif test "$python3_ok" = yes && test "$enable_python3interp" = "dynamic"; then
+ AC_DEFINE(DYNAMIC_PYTHON3)
+ PYTHON3_SRC="if_python3.c"
+ PYTHON3_OBJ="objects/if_python3.o"
+ PYTHON3_CFLAGS="$PYTHON3_CFLAGS -DDYNAMIC_PYTHON3_DLL=\\\"${vi_cv_dll_name_python3}\\\""
+ PYTHON3_LIBS=
+elif test "$python3_ok" = yes; then
+ dnl Check that adding -fPIE works. It may be needed when using a static
+ dnl Python library.
+ AC_MSG_CHECKING([if -fPIE can be added for Python3])
+ cflags_save=$CFLAGS
+ libs_save=$LIBS
+ CFLAGS="$CFLAGS $PYTHON3_CFLAGS -fPIE"
+ LIBS="$LIBS $PYTHON3_LIBS"
+ AC_TRY_LINK(,[ ],
+ AC_MSG_RESULT(yes); fpie_ok=yes,
+ AC_MSG_RESULT(no); fpie_ok=no)
+ CFLAGS=$cflags_save
+ LIBS=$libs_save
+ if test $fpie_ok = yes; then
+ PYTHON3_CFLAGS="$PYTHON3_CFLAGS -fPIE"
+ fi
+fi
+
+AC_MSG_CHECKING(--enable-tclinterp argument)
+AC_ARG_ENABLE(tclinterp,
+ [ --enable-tclinterp[=OPTS] Include Tcl interpreter. [default=no] [OPTS=no/yes/dynamic]], ,
+ [enable_tclinterp="no"])
+AC_MSG_RESULT($enable_tclinterp)
+
+if test "$enable_tclinterp" = "yes" -o "$enable_tclinterp" = "dynamic"; then
+
+ dnl on FreeBSD tclsh is a silly script, look for tclsh8.[5420]
+ AC_MSG_CHECKING(--with-tclsh argument)
+ AC_ARG_WITH(tclsh, [ --with-tclsh=PATH which tclsh to use (default: tclsh8.0)],
+ tclsh_name="$withval"; AC_MSG_RESULT($tclsh_name),
+ tclsh_name="tclsh8.5"; AC_MSG_RESULT(no))
+ AC_PATH_PROG(vi_cv_path_tcl, $tclsh_name)
+ AC_SUBST(vi_cv_path_tcl)
+
+ dnl when no specific version specified, also try 8.4, 8.2 and 8.0
+ if test "X$vi_cv_path_tcl" = "X" -a $tclsh_name = "tclsh8.5"; then
+ tclsh_name="tclsh8.4"
+ AC_PATH_PROG(vi_cv_path_tcl, $tclsh_name)
+ fi
+ if test "X$vi_cv_path_tcl" = "X" -a $tclsh_name = "tclsh8.4"; then
+ tclsh_name="tclsh8.2"
+ AC_PATH_PROG(vi_cv_path_tcl, $tclsh_name)
+ fi
+ if test "X$vi_cv_path_tcl" = "X" -a $tclsh_name = "tclsh8.2"; then
+ tclsh_name="tclsh8.0"
+ AC_PATH_PROG(vi_cv_path_tcl, $tclsh_name)
+ fi
+ dnl still didn't find it, try without version number
+ if test "X$vi_cv_path_tcl" = "X"; then
+ tclsh_name="tclsh"
+ AC_PATH_PROG(vi_cv_path_tcl, $tclsh_name)
+ fi
+ if test "X$vi_cv_path_tcl" != "X"; then
+ AC_MSG_CHECKING(Tcl version)
+ if echo 'exit [[expr [info tclversion] < 8.0]]' | "$vi_cv_path_tcl" - ; then
+ tclver=`echo 'puts [[info tclversion]]' | $vi_cv_path_tcl -`
+ AC_MSG_RESULT($tclver - OK);
+ tclloc=`echo 'set l [[info library]];set i [[string last lib $l]];incr i -2;puts [[string range $l 0 $i]]' | $vi_cv_path_tcl -`
+ tcldll=`echo 'puts libtcl[[info tclversion]][[info sharedlibextension]]' | $vi_cv_path_tcl -`
+
+ AC_MSG_CHECKING(for location of Tcl include)
+ if test "x$MACOS_X" != "xyes"; then
+ tclinc="$tclloc/include $tclloc/include/tcl $tclloc/include/tcl$tclver /usr/local/include /usr/local/include/tcl$tclver /usr/include /usr/include/tcl$tclver"
+ else
+ dnl For Mac OS X 10.3, use the OS-provided framework location
+ tclinc="/System/Library/Frameworks/Tcl.framework/Headers"
+ fi
+ TCL_INC=
+ for try in $tclinc; do
+ if test -f "$try/tcl.h"; then
+ AC_MSG_RESULT($try/tcl.h)
+ TCL_INC=$try
+ break
+ fi
+ done
+ if test -z "$TCL_INC"; then
+ AC_MSG_RESULT(<not found>)
+ SKIP_TCL=YES
+ fi
+ if test -z "$SKIP_TCL"; then
+ AC_MSG_CHECKING(for location of tclConfig.sh script)
+ if test "x$MACOS_X" != "xyes"; then
+ tclcnf=`echo $tclinc | sed s/include/lib/g`
+ tclcnf="$tclcnf `echo $tclinc | sed s/include/lib64/g`"
+ else
+ dnl For Mac OS X 10.3, use the OS-provided framework location
+ tclcnf="/System/Library/Frameworks/Tcl.framework"
+ fi
+ for try in $tclcnf; do
+ if test -f "$try/tclConfig.sh"; then
+ AC_MSG_RESULT($try/tclConfig.sh)
+ . "$try/tclConfig.sh"
+ dnl use eval, because tcl 8.2 includes ${TCL_DBGX}
+ if test "$enable_tclinterp" = "dynamic"; then
+ TCL_LIBS=`eval echo "$TCL_STUB_LIB_SPEC $TCL_LIBS"`
+ else
+ TCL_LIBS=`eval echo "$TCL_LIB_SPEC $TCL_LIBS"`
+ fi
+ dnl Use $TCL_DEFS for -D_THREAD_SAFE et al. But only use the
+ dnl "-D_ABC" items. Watch out for -DFOO=long\ long.
+ TCL_DEFS=`echo $TCL_DEFS | sed -e 's/\\\\ /\\\\X/g' | tr ' ' '\012' | sed -e '/^[[^-]]/d' -e '/^-[[^D]]/d' -e '/-D[[^_]]/d' -e 's/-D_/ -D_/' | tr '\012' ' ' | sed -e 's/\\\\X/\\\\ /g'`
+ break
+ fi
+ done
+ if test -z "$TCL_LIBS"; then
+ AC_MSG_RESULT(<not found>)
+ AC_MSG_CHECKING(for Tcl library by myself)
+ tcllib=`echo $tclinc | sed s/include/lib/g`
+ tcllib="$tcllib `echo $tclinc | sed s/include/lib64/g`"
+ for ext in .so .a ; do
+ for ver in "" $tclver ; do
+ for try in $tcllib ; do
+ trylib=tcl$ver$ext
+ if test -f "$try/lib$trylib" ; then
+ AC_MSG_RESULT($try/lib$trylib)
+ TCL_LIBS="-L\"$try\" -ltcl$ver -ldl -lm"
+ if test "`(uname) 2>/dev/null`" = SunOS &&
+ uname -r | grep '^5' >/dev/null; then
+ TCL_LIBS="$TCL_LIBS -R $try"
+ fi
+ break 3
+ fi
+ done
+ done
+ done
+ if test -z "$TCL_LIBS"; then
+ AC_MSG_RESULT(<not found>)
+ SKIP_TCL=YES
+ fi
+ fi
+ if test -z "$SKIP_TCL"; then
+ AC_DEFINE(FEAT_TCL)
+ TCL_SRC=if_tcl.c
+ TCL_OBJ=objects/if_tcl.o
+ TCL_PRO=if_tcl.pro
+ TCL_CFLAGS="-I$TCL_INC $TCL_DEFS"
+ fi
+ fi
+ else
+ AC_MSG_RESULT(too old; need Tcl version 8.0 or later)
+ fi
+ fi
+ if test "$enable_tclinterp" = "dynamic"; then
+ if test "X$TCL_SRC" != "X" -a "X$tcldll" != "X"; then
+ AC_DEFINE(DYNAMIC_TCL)
+ TCL_CFLAGS="-DDYNAMIC_TCL_DLL=\\\"$tcldll\\\" -DDYNAMIC_TCL_VER=\\\"$tclver\\\" $TCL_CFLAGS"
+ fi
+ fi
+ if test "$fail_if_missing" = "yes" -a -z "$TCL_SRC"; then
+ AC_MSG_ERROR([could not configure Tcl])
+ fi
+fi
+AC_SUBST(TCL_SRC)
+AC_SUBST(TCL_OBJ)
+AC_SUBST(TCL_PRO)
+AC_SUBST(TCL_CFLAGS)
+AC_SUBST(TCL_LIBS)
+
+AC_MSG_CHECKING(--enable-rubyinterp argument)
+AC_ARG_ENABLE(rubyinterp,
+ [ --enable-rubyinterp[=OPTS] Include Ruby interpreter. [default=no] [OPTS=no/yes/dynamic]], ,
+ [enable_rubyinterp="no"])
+AC_MSG_RESULT($enable_rubyinterp)
+if test "$enable_rubyinterp" = "yes" -o "$enable_rubyinterp" = "dynamic"; then
+ if test "x$features" = "xtiny" -o "x$features" = "xsmall"; then
+ AC_MSG_ERROR([cannot use Ruby with tiny or small features])
+ fi
+
+ AC_MSG_CHECKING(--with-ruby-command argument)
+ AC_SUBST(vi_cv_path_ruby)
+ AC_ARG_WITH(ruby-command, [ --with-ruby-command=RUBY name of the Ruby command (default: ruby)],
+ RUBY_CMD="$withval"; vi_cv_path_ruby="$withval"; AC_MSG_RESULT($RUBY_CMD),
+ RUBY_CMD="ruby"; AC_MSG_RESULT(defaulting to $RUBY_CMD))
+ AC_PATH_PROG(vi_cv_path_ruby, $RUBY_CMD)
+ if test "X$vi_cv_path_ruby" != "X"; then
+ AC_MSG_CHECKING(Ruby version)
+ if $vi_cv_path_ruby -e '(VERSION rescue RUBY_VERSION) >= "1.6.0" or exit 1' >/dev/null 2>/dev/null; then
+ AC_MSG_RESULT(OK)
+ AC_MSG_CHECKING(Ruby rbconfig)
+ ruby_rbconfig="RbConfig"
+ if ! $vi_cv_path_ruby -r rbconfig -e 'RbConfig' >/dev/null 2>/dev/null; then
+ ruby_rbconfig="Config"
+ fi
+ AC_MSG_RESULT($ruby_rbconfig)
+ AC_MSG_CHECKING(Ruby header files)
+ rubyhdrdir=`$vi_cv_path_ruby -r mkmf -e "print $ruby_rbconfig::CONFIG[['rubyhdrdir']] || $ruby_rbconfig::CONFIG[['archdir']] || \\$hdrdir" 2>/dev/null`
+ if test "X$rubyhdrdir" != "X"; then
+ AC_MSG_RESULT($rubyhdrdir)
+ RUBY_CFLAGS="-I$rubyhdrdir"
+ rubyarchdir=`$vi_cv_path_ruby -r rbconfig -e "print ($ruby_rbconfig::CONFIG.has_key? 'rubyarchhdrdir') ? $ruby_rbconfig::CONFIG[['rubyarchhdrdir']] : '$rubyhdrdir/'+$ruby_rbconfig::CONFIG[['arch']]"`
+ if test -d "$rubyarchdir"; then
+ RUBY_CFLAGS="$RUBY_CFLAGS -I$rubyarchdir"
+ fi
+ rubyversion=`$vi_cv_path_ruby -r rbconfig -e "print $ruby_rbconfig::CONFIG[['ruby_version']].gsub(/\./, '')[[0,2]]"`
+ if test "X$rubyversion" = "X"; then
+ rubyversion=`$vi_cv_path_ruby -e "print ((VERSION rescue RUBY_VERSION)).gsub(/\./, '')[[0,2]]"`
+ fi
+ RUBY_CFLAGS="$RUBY_CFLAGS -DRUBY_VERSION=$rubyversion"
+ rubylibs=`$vi_cv_path_ruby -r rbconfig -e "print $ruby_rbconfig::CONFIG[['LIBS']]"`
+ if test "X$rubylibs" != "X"; then
+ RUBY_LIBS="$rubylibs"
+ fi
+ librubyarg=`$vi_cv_path_ruby -r rbconfig -e "print $ruby_rbconfig.expand($ruby_rbconfig::CONFIG[['LIBRUBYARG']])"`
+ librubya=`$vi_cv_path_ruby -r rbconfig -e "print $ruby_rbconfig.expand($ruby_rbconfig::CONFIG[['LIBRUBY_A']])"`
+ rubylibdir=`$vi_cv_path_ruby -r rbconfig -e "print $ruby_rbconfig.expand($ruby_rbconfig::CONFIG[['libdir']])"`
+ if test -f "$rubylibdir/$librubya"; then
+ librubyarg="$librubyarg"
+ RUBY_LIBS="$RUBY_LIBS -L$rubylibdir"
+ elif test "$librubyarg" = "libruby.a"; then
+ dnl required on Mac OS 10.3 where libruby.a doesn't exist
+ librubyarg="-lruby"
+ RUBY_LIBS="$RUBY_LIBS -L$rubylibdir"
+ fi
+
+ if test "X$librubyarg" != "X"; then
+ RUBY_LIBS="$librubyarg $RUBY_LIBS"
+ fi
+ rubyldflags=`$vi_cv_path_ruby -r rbconfig -e "print $ruby_rbconfig::CONFIG[['LDFLAGS']]"`
+ if test "X$rubyldflags" != "X"; then
+ dnl Ruby on Mac OS X 10.5 adds "-arch" flags but these should only
+ dnl be included if requested by passing --with-mac-arch to
+ dnl configure, so strip these flags first (if present)
+ rubyldflags=`echo "$rubyldflags" | sed -e 's/-arch\ ppc//' -e 's/-arch\ i386//' -e 's/-arch\ x86_64//'`
+ if test "X$rubyldflags" != "X"; then
+ if test "X`echo \"$LDFLAGS\" | $FGREP -e \"$rubyldflags\"`" = "X"; then
+ LDFLAGS="$rubyldflags $LDFLAGS"
+ fi
+ fi
+ fi
+ RUBY_SRC="if_ruby.c"
+ RUBY_OBJ="objects/if_ruby.o"
+ RUBY_PRO="if_ruby.pro"
+ AC_DEFINE(FEAT_RUBY)
+ if test "$enable_rubyinterp" = "dynamic"; then
+ libruby_soname=`$vi_cv_path_ruby -r rbconfig -e "puts $ruby_rbconfig::CONFIG[['LIBRUBY_ALIASES']].split[[0]]"`
+ if test -z "$libruby_soname"; then
+ libruby_soname=`$vi_cv_path_ruby -r rbconfig -e "puts $ruby_rbconfig::CONFIG[['LIBRUBY_SO']]"`
+ fi
+ AC_DEFINE(DYNAMIC_RUBY)
+ RUBY_CFLAGS="-DDYNAMIC_RUBY_DLL=\\\"$libruby_soname\\\" -DDYNAMIC_RUBY_VER=$rubyversion $RUBY_CFLAGS"
+ RUBY_LIBS=
+ fi
+ else
+ AC_MSG_RESULT(not found; disabling Ruby)
+ fi
+ else
+ AC_MSG_RESULT(too old; need Ruby version 1.6.0 or later)
+ fi
+ fi
+
+ if test "$fail_if_missing" = "yes" -a -z "$RUBY_OBJ"; then
+ AC_MSG_ERROR([could not configure Ruby])
+ fi
+fi
+AC_SUBST(RUBY_SRC)
+AC_SUBST(RUBY_OBJ)
+AC_SUBST(RUBY_PRO)
+AC_SUBST(RUBY_CFLAGS)
+AC_SUBST(RUBY_LIBS)
+
+AC_MSG_CHECKING(--enable-cscope argument)
+AC_ARG_ENABLE(cscope,
+ [ --enable-cscope Include cscope interface.], ,
+ [enable_cscope="no"])
+AC_MSG_RESULT($enable_cscope)
+if test "$enable_cscope" = "yes"; then
+ AC_DEFINE(FEAT_CSCOPE)
+fi
+
+AC_MSG_CHECKING(--disable-netbeans argument)
+AC_ARG_ENABLE(netbeans,
+ [ --disable-netbeans Disable NetBeans integration support.],
+ , [enable_netbeans="yes"])
+if test "$enable_netbeans" = "yes"; then
+ if test "x$features" = "xtiny" -o "x$features" = "xsmall"; then
+ AC_MSG_RESULT([cannot use NetBeans with tiny or small features])
+ enable_netbeans="no"
+ else
+ AC_MSG_RESULT(no)
+ fi
+else
+ AC_MSG_RESULT(yes)
+fi
+
+AC_MSG_CHECKING(--disable-channel argument)
+AC_ARG_ENABLE(channel,
+ [ --disable-channel Disable process communication support.],
+ , [enable_channel="yes"])
+if test "$enable_channel" = "yes"; then
+ if test "x$features" = "xtiny" -o "x$features" = "xsmall"; then
+ AC_MSG_RESULT([cannot use channels with tiny or small features])
+ enable_channel="no"
+ else
+ AC_MSG_RESULT(no)
+ fi
+else
+ if test "$enable_netbeans" = "yes"; then
+ AC_MSG_RESULT([yes, netbeans also disabled])
+ enable_netbeans="no"
+ else
+ AC_MSG_RESULT(yes)
+ fi
+fi
+
+if test "$enable_channel" = "yes"; then
+ dnl On Solaris we need the socket and nsl library.
+ AC_CHECK_LIB(socket, socket)
+ AC_CHECK_LIB(nsl, gethostbyname)
+ AC_MSG_CHECKING(whether compiling with process communication is possible)
+ AC_TRY_LINK([
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+ /* Check bitfields */
+ struct nbbuf {
+ unsigned int initDone:1;
+ unsigned short signmaplen;
+ };
+ ], [
+ /* Check creating a socket. */
+ struct sockaddr_in server;
+ (void)socket(AF_INET, SOCK_STREAM, 0);
+ (void)htons(100);
+ (void)gethostbyname("microsoft.com");
+ if (errno == ECONNREFUSED)
+ (void)connect(1, (struct sockaddr *)&server, sizeof(server));
+ ],
+ AC_MSG_RESULT(yes),
+ AC_MSG_RESULT(no); enable_netbeans="no"; enable_channel="no")
+fi
+if test "$enable_netbeans" = "yes"; then
+ AC_DEFINE(FEAT_NETBEANS_INTG)
+ NETBEANS_SRC="netbeans.c"
+ AC_SUBST(NETBEANS_SRC)
+ NETBEANS_OBJ="objects/netbeans.o"
+ AC_SUBST(NETBEANS_OBJ)
+fi
+if test "$enable_channel" = "yes"; then
+ AC_DEFINE(FEAT_JOB_CHANNEL)
+ CHANNEL_SRC="channel.c"
+ AC_SUBST(CHANNEL_SRC)
+ CHANNEL_OBJ="objects/channel.o"
+ AC_SUBST(CHANNEL_OBJ)
+fi
+
+AC_MSG_CHECKING(--enable-terminal argument)
+AC_ARG_ENABLE(terminal,
+ [ --enable-terminal Enable terminal emulation support.],
+ , [enable_terminal="auto"])
+if test "$enable_terminal" = "yes" || test "$enable_terminal" = "auto" -a "x$features" = "xhuge" ; then
+ if test "x$features" = "xtiny" -o "x$features" = "xsmall"; then
+ AC_MSG_RESULT([cannot use terminal emulator with tiny or small features])
+ enable_terminal="no"
+ else
+ if test "$enable_terminal" = "auto"; then
+ enable_terminal="yes"
+ AC_MSG_RESULT(defaulting to yes)
+ else
+ AC_MSG_RESULT(yes)
+ fi
+ fi
+else
+ if test "$enable_terminal" = "auto"; then
+ enable_terminal="no"
+ AC_MSG_RESULT(defaulting to no)
+ else
+ AC_MSG_RESULT(no)
+ fi
+fi
+if test "$enable_terminal" = "yes" -a "$enable_channel" = "yes"; then
+ AC_DEFINE(FEAT_TERMINAL)
+ TERM_SRC="libvterm/src/encoding.c libvterm/src/keyboard.c libvterm/src/mouse.c libvterm/src/parser.c libvterm/src/pen.c libvterm/src/termscreen.c libvterm/src/state.c libvterm/src/unicode.c libvterm/src/vterm.c"
+ AC_SUBST(TERM_SRC)
+ TERM_OBJ="objects/encoding.o objects/keyboard.o objects/mouse.o objects/parser.o objects/pen.o objects/termscreen.o objects/state.o objects/unicode.o objects/vterm.o"
+ AC_SUBST(TERM_OBJ)
+fi
+
+AC_MSG_CHECKING(--enable-autoservername argument)
+AC_ARG_ENABLE(autoservername,
+ [ --enable-autoservername Automatically define servername at vim startup.], ,
+ [enable_autoservername="no"])
+AC_MSG_RESULT($enable_autoservername)
+if test "$enable_autoservername" = "yes"; then
+ AC_DEFINE(FEAT_AUTOSERVERNAME)
+fi
+
+AC_MSG_CHECKING(--enable-multibyte argument)
+AC_ARG_ENABLE(multibyte,
+ [ --enable-multibyte Include multibyte editing support.], ,
+ [enable_multibyte="yes"])
+AC_MSG_RESULT($enable_multibyte)
+if test "$enable_multibyte" != "yes"; then
+ AC_MSG_ERROR([The multi-byte feature can no longer be disabled. If you have
+ a problem with this, discuss on the Vim mailing list.])
+fi
+
+dnl Right-to-Left language support for Vim will be included with big features,
+dnl unless ENABLE_RIGHTLEFT is undefined.
+AC_MSG_CHECKING(--disable-rightleft argument)
+AC_ARG_ENABLE(rightleft,
+ [ --disable-rightleft Do not include Right-to-Left language support.],
+ , [enable_rightleft="yes"])
+if test "$enable_rightleft" = "yes"; then
+ AC_MSG_RESULT(no)
+else
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(DISABLE_RIGHTLEFT)
+fi
+
+dnl Arabic language support for Vim will be included with big features,
+dnl unless ENABLE_ARABIC is undefined.
+AC_MSG_CHECKING(--disable-arabic argument)
+AC_ARG_ENABLE(arabic,
+ [ --disable-arabic Do not include Arabic language support.],
+ , [enable_arabic="yes"])
+if test "$enable_arabic" = "yes"; then
+ AC_MSG_RESULT(no)
+else
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(DISABLE_ARABIC)
+fi
+
+dnl Farsi language support for vim will be included with big features,
+dnl unless ENABLE_FARSI is undefined.
+AC_MSG_CHECKING(--disable-farsi argument)
+AC_ARG_ENABLE(farsi,
+ [ --disable-farsi Do not include Farsi language support.],
+ , [enable_farsi="yes"])
+if test "$enable_farsi" = "yes"; then
+ AC_MSG_RESULT(no)
+else
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(DISABLE_FARSI)
+fi
+
+AC_MSG_CHECKING(--enable-hangulinput argument)
+AC_ARG_ENABLE(hangulinput,
+ [ --enable-hangulinput Include Hangul input support.], ,
+ [enable_hangulinput="no"])
+AC_MSG_RESULT($enable_hangulinput)
+
+AC_MSG_CHECKING(--enable-xim argument)
+AC_ARG_ENABLE(xim,
+ [ --enable-xim Include XIM input support.],
+ AC_MSG_RESULT($enable_xim),
+ [enable_xim="auto"; AC_MSG_RESULT(defaulting to auto)])
+
+AC_MSG_CHECKING(--enable-fontset argument)
+AC_ARG_ENABLE(fontset,
+ [ --enable-fontset Include X fontset output support.], ,
+ [enable_fontset="no"])
+AC_MSG_RESULT($enable_fontset)
+dnl defining FEAT_XFONTSET is delayed, so that it can be disabled for no GUI
+
+test -z "$with_x" && with_x=yes
+test "${enable_gui-yes}" != no -a "x$MACOS_X" != "xyes" -a "x$QNX" != "xyes" && with_x=yes
+if test "$with_x" = no; then
+ AC_MSG_RESULT(defaulting to: don't HAVE_X11)
+else
+ dnl Do this check early, so that its failure can override user requests.
+
+ AC_PATH_PROG(xmkmfpath, xmkmf)
+
+ AC_PATH_XTRA
+
+ dnl On z/OS Unix the X libraries are DLLs. To use them the code must
+ dnl be compiled with a special option.
+ dnl Also add SM, ICE and Xmu to X_EXTRA_LIBS.
+ if test "$zOSUnix" = "yes"; then
+ CFLAGS="$CFLAGS -W c,dll"
+ LDFLAGS="$LDFLAGS -W l,dll"
+ X_EXTRA_LIBS="$X_EXTRA_LIBS -lSM -lICE -lXmu"
+ fi
+
+ dnl On my HPUX system the X include dir is found, but the lib dir not.
+ dnl This is a desparate try to fix this.
+
+ if test -d "$x_includes" && test ! -d "$x_libraries"; then
+ x_libraries=`echo "$x_includes" | sed s/include/lib/`
+ AC_MSG_RESULT(Corrected X libraries to $x_libraries)
+ X_LIBS="$X_LIBS -L$x_libraries"
+ if test "`(uname) 2>/dev/null`" = SunOS &&
+ uname -r | grep '^5' >/dev/null; then
+ X_LIBS="$X_LIBS -R $x_libraries"
+ fi
+ fi
+
+ if test -d "$x_libraries" && test ! -d "$x_includes"; then
+ x_includes=`echo "$x_libraries" | sed s/lib/include/`
+ AC_MSG_RESULT(Corrected X includes to $x_includes)
+ X_CFLAGS="$X_CFLAGS -I$x_includes"
+ fi
+
+ dnl Remove "-I/usr/include " from X_CFLAGS, should not be needed.
+ X_CFLAGS="`echo $X_CFLAGS\ | sed 's%-I/usr/include %%'`"
+ dnl Remove "-L/usr/lib " from X_LIBS, should not be needed.
+ X_LIBS="`echo $X_LIBS\ | sed 's%-L/usr/lib %%'`"
+ dnl Same for "-R/usr/lib ".
+ X_LIBS="`echo $X_LIBS\ | sed -e 's%-R/usr/lib %%' -e 's%-R /usr/lib %%'`"
+
+
+ dnl Check if the X11 header files are correctly installed. On some systems
+ dnl Xlib.h includes files that don't exist. On some systems X11/Intrinsic.h
+ dnl is missing.
+ AC_MSG_CHECKING(if X11 header files can be found)
+ cflags_save=$CFLAGS
+ CFLAGS="$CFLAGS $X_CFLAGS"
+ AC_TRY_COMPILE([#include <X11/Xlib.h>
+#include <X11/Intrinsic.h>], ,
+ AC_MSG_RESULT(yes),
+ AC_MSG_RESULT(no); no_x=yes)
+ CFLAGS=$cflags_save
+
+ if test "${no_x-no}" = yes; then
+ with_x=no
+ else
+ AC_DEFINE(HAVE_X11)
+ X_LIB="-lXt -lX11";
+ AC_SUBST(X_LIB)
+
+ ac_save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="-L$x_libraries $LDFLAGS"
+
+ dnl Check for -lXdmcp (needed on SunOS 4.1.4)
+ dnl For HP-UX 10.20 it must be before -lSM -lICE
+ AC_CHECK_LIB(Xdmcp, _XdmcpAuthDoIt, [X_EXTRA_LIBS="$X_EXTRA_LIBS -lXdmcp"],,
+ [-lXt $X_PRE_LIBS -lX11 $X_EXTRA_LIBS -lXdmcp])
+
+ dnl Some systems need -lnsl -lsocket when testing for ICE.
+ dnl The check above doesn't do this, try here (again). Also needed to get
+ dnl them after Xdmcp. link.sh will remove them when not needed.
+ dnl Check for other function than above to avoid the cached value
+ AC_CHECK_LIB(ICE, IceOpenConnection,
+ [X_EXTRA_LIBS="$X_EXTRA_LIBS -lSM -lICE"],, [$X_EXTRA_LIBS])
+
+ dnl Check for -lXpm (needed for some versions of Motif)
+ LDFLAGS="$X_LIBS $ac_save_LDFLAGS"
+ AC_CHECK_LIB(Xpm, XpmCreatePixmapFromData, [X_PRE_LIBS="$X_PRE_LIBS -lXpm"],,
+ [-lXt $X_PRE_LIBS -lXpm -lX11 $X_EXTRA_LIBS])
+
+ dnl Check that the X11 header files don't use implicit declarations
+ AC_MSG_CHECKING(if X11 header files implicitly declare return values)
+ cflags_save=$CFLAGS
+ dnl -Werror is GCC only, others like Solaris Studio might not like it
+ if test "$GCC" = yes; then
+ CFLAGS="$CFLAGS $X_CFLAGS -Werror"
+ else
+ CFLAGS="$CFLAGS $X_CFLAGS"
+ fi
+ AC_TRY_COMPILE([#include <X11/Xlib.h>], ,
+ AC_MSG_RESULT(no),
+ CFLAGS="$CFLAGS -Wno-implicit-int"
+ AC_TRY_COMPILE([#include <X11/Xlib.h>], ,
+ AC_MSG_RESULT(yes); cflags_save="$cflags_save -Wno-implicit-int",
+ AC_MSG_RESULT(test failed)
+ )
+ )
+ CFLAGS=$cflags_save
+
+ LDFLAGS="$ac_save_LDFLAGS"
+
+ AC_MSG_CHECKING(size of wchar_t is 2 bytes)
+ AC_CACHE_VAL(ac_cv_small_wchar_t,
+ [AC_TRY_RUN([
+#include <X11/Xlib.h>
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#endif
+ main()
+ {
+ if (sizeof(wchar_t) <= 2)
+ exit(1);
+ exit(0);
+ }],
+ ac_cv_small_wchar_t="no",
+ ac_cv_small_wchar_t="yes",
+ AC_MSG_ERROR(failed to compile test program))])
+ AC_MSG_RESULT($ac_cv_small_wchar_t)
+ if test "x$ac_cv_small_wchar_t" = "xyes" ; then
+ AC_DEFINE(SMALL_WCHAR_T)
+ fi
+
+ fi
+fi
+
+dnl Check if --with-x was given but it doesn't work.
+if test "x$with_x" = xno -a "x$with_x_arg" = xyes; then
+ AC_MSG_ERROR([could not configure X])
+fi
+
+test "x$with_x" = xno -a "x$MACOS_X" != "xyes" -a "x$QNX" != "xyes" && enable_gui=no
+
+AC_MSG_CHECKING(--enable-gui argument)
+AC_ARG_ENABLE(gui,
+ [ --enable-gui[=OPTS] X11 GUI. [default=auto] [OPTS=auto/no/gtk2/gnome2/gtk3/motif/athena/neXtaw/photon/carbon]], , enable_gui="auto")
+
+dnl Canonicalize the --enable-gui= argument so that it can be easily compared.
+dnl Do not use character classes for portability with old tools.
+enable_gui_canon=`echo "_$enable_gui" | \
+ sed 's/[[ _+-]]//g;y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'`
+
+dnl Skip everything by default.
+SKIP_GTK2=YES
+SKIP_GTK3=YES
+SKIP_GNOME=YES
+SKIP_MOTIF=YES
+SKIP_ATHENA=YES
+SKIP_NEXTAW=YES
+SKIP_PHOTON=YES
+SKIP_CARBON=YES
+GUITYPE=NONE
+
+if test "x$QNX" = "xyes" -a "x$with_x" = "xno" ; then
+ SKIP_PHOTON=
+ case "$enable_gui_canon" in
+ no) AC_MSG_RESULT(no GUI support)
+ SKIP_PHOTON=YES ;;
+ yes|""|auto) AC_MSG_RESULT(automatic GUI support)
+ gui_auto=yes ;;
+ photon) AC_MSG_RESULT(Photon GUI support) ;;
+ *) AC_MSG_RESULT([Sorry, $enable_gui GUI is not supported])
+ SKIP_PHOTON=YES ;;
+ esac
+
+elif test "x$MACOS_X" = "xyes" -a "x$with_x" = "xno" ; then
+ SKIP_CARBON=
+ case "$enable_gui_canon" in
+ no) AC_MSG_RESULT(no GUI support)
+ SKIP_CARBON=YES ;;
+ yes|"") AC_MSG_RESULT(yes - automatic GUI support)
+ gui_auto=yes ;;
+ auto) AC_MSG_RESULT(auto - Carbon GUI is outdated - disable GUI support)
+ SKIP_CARBON=YES ;;
+ carbon) AC_MSG_RESULT(Carbon GUI support) ;;
+ *) AC_MSG_RESULT([Sorry, $enable_gui GUI is not supported])
+ SKIP_CARBON=YES ;;
+ esac
+
+else
+
+ case "$enable_gui_canon" in
+ no|none) AC_MSG_RESULT(no GUI support) ;;
+ yes|""|auto) AC_MSG_RESULT(yes/auto - automatic GUI support)
+ gui_auto=yes
+ SKIP_GTK2=
+ SKIP_GNOME=
+ SKIP_MOTIF=
+ SKIP_ATHENA=
+ SKIP_NEXTAW=
+ SKIP_CARBON=;;
+ gtk2) AC_MSG_RESULT(GTK+ 2.x GUI support)
+ SKIP_GTK2=;;
+ gnome2) AC_MSG_RESULT(GNOME 2.x GUI support)
+ SKIP_GNOME=
+ SKIP_GTK2=;;
+ gtk3) AC_MSG_RESULT(GTK+ 3.x GUI support)
+ SKIP_GTK3=;;
+ motif) AC_MSG_RESULT(Motif GUI support)
+ SKIP_MOTIF=;;
+ athena) AC_MSG_RESULT(Athena GUI support)
+ SKIP_ATHENA=;;
+ nextaw) AC_MSG_RESULT(neXtaw GUI support)
+ SKIP_NEXTAW=;;
+ *) AC_MSG_RESULT([Sorry, $enable_gui GUI is not supported]) ;;
+ esac
+
+fi
+
+if test "x$SKIP_GTK2" != "xYES" -a "$enable_gui_canon" != "gtk2" \
+ -a "$enable_gui_canon" != "gnome2"; then
+ AC_MSG_CHECKING(whether or not to look for GTK+ 2)
+ AC_ARG_ENABLE(gtk2-check,
+ [ --enable-gtk2-check If auto-select GUI, check for GTK+ 2 [default=yes]],
+ , enable_gtk2_check="yes")
+ AC_MSG_RESULT($enable_gtk2_check)
+ if test "x$enable_gtk2_check" = "xno"; then
+ SKIP_GTK2=YES
+ SKIP_GNOME=YES
+ fi
+fi
+
+if test "x$SKIP_GNOME" != "xYES" -a "$enable_gui_canon" != "gnome2"; then
+ AC_MSG_CHECKING(whether or not to look for GNOME)
+ AC_ARG_ENABLE(gnome-check,
+ [ --enable-gnome-check If GTK GUI, check for GNOME [default=no]],
+ , enable_gnome_check="no")
+ AC_MSG_RESULT($enable_gnome_check)
+ if test "x$enable_gnome_check" = "xno"; then
+ SKIP_GNOME=YES
+ fi
+fi
+
+if test "x$SKIP_GTK3" != "xYES" -a "$enable_gui_canon" != "gtk3"; then
+ AC_MSG_CHECKING(whether or not to look for GTK+ 3)
+ AC_ARG_ENABLE(gtk3-check,
+ [ --enable-gtk3-check If auto-select GUI, check for GTK+ 3 [default=yes]],
+ , enable_gtk3_check="yes")
+ AC_MSG_RESULT($enable_gtk3_check)
+ if test "x$enable_gtk3_check" = "xno"; then
+ SKIP_GTK3=YES
+ fi
+fi
+
+if test "x$SKIP_MOTIF" != "xYES" -a "$enable_gui_canon" != "motif"; then
+ AC_MSG_CHECKING(whether or not to look for Motif)
+ AC_ARG_ENABLE(motif-check,
+ [ --enable-motif-check If auto-select GUI, check for Motif [default=yes]],
+ , enable_motif_check="yes")
+ AC_MSG_RESULT($enable_motif_check)
+ if test "x$enable_motif_check" = "xno"; then
+ SKIP_MOTIF=YES
+ fi
+fi
+
+if test "x$SKIP_ATHENA" != "xYES" -a "$enable_gui_canon" != "athena"; then
+ AC_MSG_CHECKING(whether or not to look for Athena)
+ AC_ARG_ENABLE(athena-check,
+ [ --enable-athena-check If auto-select GUI, check for Athena [default=yes]],
+ , enable_athena_check="yes")
+ AC_MSG_RESULT($enable_athena_check)
+ if test "x$enable_athena_check" = "xno"; then
+ SKIP_ATHENA=YES
+ fi
+fi
+
+if test "x$SKIP_NEXTAW" != "xYES" -a "$enable_gui_canon" != "nextaw"; then
+ AC_MSG_CHECKING(whether or not to look for neXtaw)
+ AC_ARG_ENABLE(nextaw-check,
+ [ --enable-nextaw-check If auto-select GUI, check for neXtaw [default=yes]],
+ , enable_nextaw_check="yes")
+ AC_MSG_RESULT($enable_nextaw_check);
+ if test "x$enable_nextaw_check" = "xno"; then
+ SKIP_NEXTAW=YES
+ 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$MACOS_X" = "xyes" -a -z "$SKIP_CARBON" -a "x$CARBON" = "xyes"; then
+ AC_MSG_CHECKING(for Carbon GUI)
+ dnl already did the check, just give the message
+ AC_MSG_RESULT(yes);
+ GUITYPE=CARBONGUI
+ if test "$VIMNAME" = "vim"; then
+ VIMNAME=Vim
+ fi
+
+ if test "x$MACARCH" = "xboth"; then
+ CPPFLAGS="$CPPFLAGS -I$DEVELOPER_DIR/SDKs/MacOSX10.4u.sdk/Developer/Headers/FlatCarbon"
+ else
+ CPPFLAGS="$CPPFLAGS -I$DEVELOPER_DIR/Headers/FlatCarbon"
+ fi
+
+ dnl Default install directory is not /usr/local
+ if test x$prefix = xNONE; then
+ prefix=/Applications
+ fi
+
+ dnl Sorry for the hard coded default
+ datadir='${prefix}/Vim.app/Contents/Resources'
+
+ dnl skip everything else
+ SKIP_GTK2=YES;
+ SKIP_GNOME=YES;
+ SKIP_MOTIF=YES;
+ SKIP_ATHENA=YES;
+ SKIP_NEXTAW=YES;
+ SKIP_PHOTON=YES;
+ SKIP_CARBON=YES
+fi
+
+dnl define an autoconf function to check for a specified version of GTK, and
+dnl try to compile/link a GTK program.
+dnl
+dnl AM_PATH_GTK([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]])
+dnl Test for GTK, and define GTK_CFLAGS, GTK_LIBDIR and GTK_LIBS
+dnl
+AC_DEFUN(AM_PATH_GTK,
+[
+ if test "X$GTK_CONFIG" != "Xno" -o "X$PKG_CONFIG" != "Xno"; then
+ {
+ no_gtk=""
+ if (test "X$SKIP_GTK2" != "XYES" -a "X$PKG_CONFIG" != "Xno") \
+ && $PKG_CONFIG --exists gtk+-2.0; then
+ {
+ min_gtk_version=ifelse([$1], ,2.2.0,$1)
+ AC_MSG_CHECKING(for GTK - version >= $min_gtk_version)
+ dnl We should be using PKG_CHECK_MODULES() instead of this hack.
+ dnl But I guess the dependency on pkgconfig.m4 is not wanted or
+ dnl something like that.
+ GTK_CFLAGS=`$PKG_CONFIG --cflags gtk+-2.0`
+ GTK_LIBDIR=`$PKG_CONFIG --libs-only-L gtk+-2.0`
+ GTK_LIBS=`$PKG_CONFIG --libs gtk+-2.0`
+ gtk_major_version=`$PKG_CONFIG --modversion gtk+-2.0 | \
+ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\1/'`
+ gtk_minor_version=`$PKG_CONFIG --modversion gtk+-2.0 | \
+ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\2/'`
+ gtk_micro_version=`$PKG_CONFIG --modversion gtk+-2.0 | \
+ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\3/'`
+ }
+ elif (test "X$SKIP_GTK3" != "XYES" -a "X$PKG_CONFIG" != "Xno") \
+ && $PKG_CONFIG --exists gtk+-3.0; then
+ {
+ min_gtk_version=ifelse([$1], ,3.0.0,$1)
+ AC_MSG_CHECKING(for GTK - version >= $min_gtk_version)
+
+ GTK_CFLAGS=`$PKG_CONFIG --cflags gtk+-3.0`
+ GTK_LIBDIR=`$PKG_CONFIG --libs-only-L gtk+-3.0`
+ GTK_LIBS=`$PKG_CONFIG --libs gtk+-3.0`
+ gtk_major_version=`$PKG_CONFIG --modversion gtk+-3.0 | \
+ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\1/'`
+ gtk_minor_version=`$PKG_CONFIG --modversion gtk+-3.0 | \
+ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\2/'`
+ gtk_micro_version=`$PKG_CONFIG --modversion gtk+-3.0 | \
+ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\3/'`
+ }
+ else
+ no_gtk=yes
+ fi
+
+ if test "x$enable_gtktest" = "xyes" -a "x$no_gtk" = "x"; then
+ {
+ ac_save_CFLAGS="$CFLAGS"
+ ac_save_LIBS="$LIBS"
+ CFLAGS="$CFLAGS $GTK_CFLAGS"
+ LIBS="$LIBS $GTK_LIBS"
+
+ dnl
+ dnl Now check if the installed GTK is sufficiently new.
+ dnl
+ rm -f conf.gtktest
+ AC_TRY_RUN([
+#include <gtk/gtk.h>
+#include <stdio.h>
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#endif
+
+int
+main ()
+{
+int major, minor, micro;
+char *tmp_version;
+
+system ("touch conf.gtktest");
+
+/* HP/UX 9 (%@#!) writes to sscanf strings */
+tmp_version = g_strdup("$min_gtk_version");
+if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, &micro) != 3) {
+ printf("%s, bad version string\n", "$min_gtk_version");
+ exit(1);
+ }
+
+if ((gtk_major_version > major) ||
+ ((gtk_major_version == major) && (gtk_minor_version > minor)) ||
+ ((gtk_major_version == major) && (gtk_minor_version == minor) &&
+ (gtk_micro_version >= micro)))
+{
+ return 0;
+}
+return 1;
+}
+],, no_gtk=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
+ CFLAGS="$ac_save_CFLAGS"
+ LIBS="$ac_save_LIBS"
+ }
+ fi
+ if test "x$no_gtk" = x ; then
+ if test "x$enable_gtktest" = "xyes"; then
+ AC_MSG_RESULT(yes; found version $gtk_major_version.$gtk_minor_version.$gtk_micro_version)
+ else
+ AC_MSG_RESULT(found version $gtk_major_version.$gtk_minor_version.$gtk_micro_version)
+ fi
+ ifelse([$2], , :, [$2])
+ else
+ {
+ AC_MSG_RESULT(no)
+ GTK_CFLAGS=""
+ GTK_LIBS=""
+ ifelse([$3], , :, [$3])
+ if test "$fail_if_missing" = "yes" -a "X$gui_auto" != "Xyes"; then
+ AC_MSG_ERROR([could not configure GTK])
+ fi
+ }
+ fi
+ }
+ else
+ GTK_CFLAGS=""
+ GTK_LIBS=""
+ ifelse([$3], , :, [$3])
+ fi
+ AC_SUBST(GTK_CFLAGS)
+ AC_SUBST(GTK_LIBS)
+ rm -f conf.gtktest
+])
+
+dnl ---------------------------------------------------------------------------
+dnl gnome
+dnl ---------------------------------------------------------------------------
+AC_DEFUN([GNOME_INIT_HOOK],
+[
+ AC_SUBST(GNOME_LIBS)
+ AC_SUBST(GNOME_LIBDIR)
+ AC_SUBST(GNOME_INCLUDEDIR)
+
+ AC_ARG_WITH(gnome-includes,
+ [ --with-gnome-includes=DIR Specify location of GNOME headers],
+ [CFLAGS="$CFLAGS -I$withval"]
+ )
+
+ AC_ARG_WITH(gnome-libs,
+ [ --with-gnome-libs=DIR Specify location of GNOME libs],
+ [LDFLAGS="$LDFLAGS -L$withval" gnome_prefix=$withval]
+ )
+
+ AC_ARG_WITH(gnome,
+ [ --with-gnome Specify prefix for GNOME files],
+ if test x$withval = xyes; then
+ want_gnome=yes
+ ifelse([$1], [], :, [$1])
+ else
+ if test "x$withval" = xno; then
+ want_gnome=no
+ else
+ want_gnome=yes
+ LDFLAGS="$LDFLAGS -L$withval/lib"
+ CFLAGS="$CFLAGS -I$withval/include"
+ gnome_prefix=$withval/lib
+ fi
+ fi,
+ want_gnome=yes)
+
+ if test "x$want_gnome" = xyes; then
+ {
+ AC_MSG_CHECKING(for libgnomeui-2.0)
+ if $PKG_CONFIG --exists libgnomeui-2.0; then
+ AC_MSG_RESULT(yes)
+ GNOME_LIBS=`$PKG_CONFIG --libs-only-l libgnomeui-2.0`
+ GNOME_LIBDIR=`$PKG_CONFIG --libs-only-L libgnomeui-2.0`
+ GNOME_INCLUDEDIR=`$PKG_CONFIG --cflags libgnomeui-2.0`
+
+ dnl On FreeBSD we need -pthread but pkg-config doesn't include it.
+ dnl This might not be the right way but it works for me...
+ AC_MSG_CHECKING(for FreeBSD)
+ if test "`(uname) 2>/dev/null`" = FreeBSD; then
+ AC_MSG_RESULT(yes, adding -pthread)
+ GNOME_INCLUDEDIR="$GNOME_INCLUDEDIR -D_THREAD_SAFE"
+ GNOME_LIBS="$GNOME_LIBS -pthread"
+ else
+ AC_MSG_RESULT(no)
+ fi
+ $1
+ else
+ AC_MSG_RESULT(not found)
+ if test "x$2" = xfail; then
+ AC_MSG_ERROR(Could not find libgnomeui-2.0 via pkg-config)
+ fi
+ fi
+ }
+ fi
+])
+
+AC_DEFUN([GNOME_INIT],[
+ GNOME_INIT_HOOK([],fail)
+])
+
+
+dnl ---------------------------------------------------------------------------
+dnl Check for GTK2. If it fails, then continue on for Motif as before...
+dnl ---------------------------------------------------------------------------
+if test -z "$SKIP_GTK2"; then
+
+ AC_MSG_CHECKING(--disable-gtktest argument)
+ AC_ARG_ENABLE(gtktest, [ --disable-gtktest Do not try to compile and run a test GTK program],
+ , enable_gtktest=yes)
+ if test "x$enable_gtktest" = "xyes" ; then
+ AC_MSG_RESULT(gtk test enabled)
+ else
+ AC_MSG_RESULT(gtk test disabled)
+ fi
+
+ if test "X$PKG_CONFIG" = "X"; then
+ AC_PATH_TOOL(PKG_CONFIG, pkg-config, no)
+ fi
+
+ if test "x$PKG_CONFIG" != "xno"; then
+ dnl First try finding version 2.2.0 or later. The 2.0.x series has
+ dnl problems (bold fonts, --remote doesn't work).
+ AM_PATH_GTK(2.2.0,
+ [GUI_LIB_LOC="$GTK_LIBDIR"
+ GTK_LIBNAME="$GTK_LIBS"
+ GUI_INC_LOC="$GTK_CFLAGS"], )
+ if test "x$GTK_CFLAGS" != "x"; then
+ SKIP_GTK3=YES
+ SKIP_ATHENA=YES
+ SKIP_NEXTAW=YES
+ SKIP_MOTIF=YES
+ GUITYPE=GTK
+ AC_SUBST(GTK_LIBNAME)
+ fi
+ fi
+ if test "x$GUITYPE" = "xGTK"; then
+ dnl
+ dnl if GTK exists, then check for GNOME.
+ dnl
+ if test -z "$SKIP_GNOME"; then
+ {
+ GNOME_INIT_HOOK([have_gnome=yes])
+ if test "x$have_gnome" = xyes ; then
+ AC_DEFINE(FEAT_GUI_GNOME)
+ GUI_INC_LOC="$GUI_INC_LOC $GNOME_INCLUDEDIR"
+ GTK_LIBNAME="$GTK_LIBNAME $GNOME_LIBDIR $GNOME_LIBS"
+ fi
+ }
+ fi
+ fi
+fi
+
+
+dnl ---------------------------------------------------------------------------
+dnl Check for GTK3.
+dnl ---------------------------------------------------------------------------
+if test -z "$SKIP_GTK3"; then
+
+ AC_MSG_CHECKING(--disable-gtktest argument)
+ AC_ARG_ENABLE(gtktest, [ --disable-gtktest Do not try to compile and run a test GTK program],
+ , enable_gtktest=yes)
+ if test "x$enable_gtktest" = "xyes" ; then
+ AC_MSG_RESULT(gtk test enabled)
+ else
+ AC_MSG_RESULT(gtk test disabled)
+ fi
+
+ if test "X$PKG_CONFIG" = "X"; then
+ AC_PATH_TOOL(PKG_CONFIG, pkg-config, no)
+ fi
+
+ if test "x$PKG_CONFIG" != "xno"; then
+ AM_PATH_GTK(3.0.0,
+ [GUI_LIB_LOC="$GTK_LIBDIR"
+ GTK_LIBNAME="$GTK_LIBS"
+ GUI_INC_LOC="$GTK_CFLAGS"], )
+ if test "x$GTK_CFLAGS" != "x"; then
+ SKIP_GTK2=YES
+ SKIP_GNOME=YES
+ SKIP_ATHENA=YES
+ SKIP_NEXTAW=YES
+ SKIP_MOTIF=YES
+ GUITYPE=GTK
+ AC_SUBST(GTK_LIBNAME)
+ AC_DEFINE(USE_GTK3)
+ fi
+ fi
+fi
+
+dnl Check the version of Gdk-Pixbuf. If the version is 2.31 or later and
+dnl glib-compile-resources is found in PATH, use GResource.
+if test "x$GUITYPE" = "xGTK"; then
+ AC_MSG_CHECKING([version of Gdk-Pixbuf])
+ gdk_pixbuf_version=`$PKG_CONFIG --modversion gdk-pixbuf-2.0`
+ if test "x$gdk_pixbuf_version" != x ; then
+ gdk_pixbuf_version_minor=`echo $gdk_pixbuf_version | \
+ sed -e 's/[[0-9]][[0-9]]*\.\([[0-9]][[0-9]]*\)\.[[0-9]][[0-9]]*/\1/'`
+ if test "x$gdk_pixbuf_version_minor" != x -a \
+ $gdk_pixbuf_version_minor -ge 31 ; then
+ AC_MSG_RESULT([OK.])
+ AC_PATH_PROG(GLIB_COMPILE_RESOURCES,[glib-compile-resources],no)
+ AC_MSG_CHECKING([glib-compile-resources])
+ if test "x$GLIB_COMPILE_RESOURCES" = xno ; then
+ GLIB_COMPILE_RESOURCES=""
+ AC_MSG_RESULT([cannot be found in PATH.])
+ else
+ AC_MSG_RESULT([usable.])
+ AC_DEFINE(USE_GRESOURCE)
+ GRESOURCE_SRC="auto/gui_gtk_gresources.c"
+ GRESOURCE_OBJ="objects/gui_gtk_gresources.o"
+ fi
+ else
+ AC_MSG_RESULT([not usable.])
+ fi
+ else
+ AC_MSG_RESULT([cannot obtain from pkg_config.])
+ fi
+
+ AC_MSG_CHECKING([--disable-icon-cache-update argument])
+ AC_ARG_ENABLE(icon_cache_update,
+ [ --disable-icon-cache-update update disabled],
+ [],
+ [enable_icon_cache_update="yes"])
+ if test "$enable_icon_cache_update" = "yes"; then
+ AC_MSG_RESULT([not set])
+ AC_PATH_PROG(GTK_UPDATE_ICON_CACHE,[gtk-update-icon-cache],no)
+ if test "x$GTK_UPDATE_ICON_CACHE" = "xno" ; then
+ AC_MSG_RESULT([not found in PATH.])
+ fi
+ else
+ AC_MSG_RESULT([update disabled])
+ fi
+
+ AC_MSG_CHECKING([--disable-desktop-database-update argument])
+ AC_ARG_ENABLE(desktop_database_update,
+ [ --disable-desktop-database-update update disabled],
+ [],
+ [enable_desktop_database_update="yes"])
+ if test "$enable_desktop_database_update" = "yes"; then
+ AC_MSG_RESULT([not set])
+ AC_PATH_PROG(UPDATE_DESKTOP_DATABASE,[update-desktop-database],no)
+ if test "x$UPDATE_DESKTOP_DATABASE" = "xno" ; then
+ AC_MSG_RESULT([not found in PATH.])
+ fi
+ else
+ AC_MSG_RESULT([update disabled])
+ fi
+fi
+AC_SUBST(GLIB_COMPILE_RESOURCES)
+AC_SUBST(GRESOURCE_SRC)
+AC_SUBST(GRESOURCE_OBJ)
+AC_SUBST(GTK_UPDATE_ICON_CACHE)
+AC_SUBST(UPDATE_DESKTOP_DATABASE)
+
+dnl Check for Motif include files location.
+dnl The LAST one found is used, this makes the highest version to be used,
+dnl e.g. when Motif1.2 and Motif2.0 are both present.
+
+if test -z "$SKIP_MOTIF"; then
+ gui_XXX="/usr/XXX/Motif* /usr/Motif*/XXX /usr/XXX /usr/shlib /usr/X11*/XXX /usr/XXX/X11* /usr/dt/XXX /local/Motif*/XXX /local/XXX/Motif* /usr/local/Motif*/XXX /usr/local/XXX/Motif* /usr/local/XXX /usr/local/X11*/XXX /usr/local/LessTif/Motif*/XXX $MOTIFHOME/XXX"
+ dnl Remove "-I" from before $GUI_INC_LOC if it's there
+ GUI_INC_LOC="`echo $GUI_INC_LOC|sed 's%-I%%g'`"
+
+ AC_MSG_CHECKING(for location of Motif GUI includes)
+ gui_includes="`echo $x_includes|sed 's%/[^/][^/]*$%%'` `echo "$gui_XXX" | sed s/XXX/include/g` $GUI_INC_LOC"
+ GUI_INC_LOC=
+ for try in $gui_includes; do
+ if test -f "$try/Xm/Xm.h"; then
+ GUI_INC_LOC=$try
+ fi
+ done
+ if test -n "$GUI_INC_LOC"; then
+ if test "$GUI_INC_LOC" = /usr/include; then
+ GUI_INC_LOC=
+ AC_MSG_RESULT(in default path)
+ else
+ AC_MSG_RESULT($GUI_INC_LOC)
+ fi
+ else
+ AC_MSG_RESULT(<not found>)
+ SKIP_MOTIF=YES
+ fi
+fi
+
+dnl Check for Motif library files location. In the same order as the include
+dnl files, to avoid a mixup if several versions are present
+
+if test -z "$SKIP_MOTIF"; then
+ AC_MSG_CHECKING(--with-motif-lib argument)
+ AC_ARG_WITH(motif-lib,
+ [ --with-motif-lib=STRING Library for Motif ],
+ [ MOTIF_LIBNAME="${withval}" ] )
+
+ if test -n "$MOTIF_LIBNAME"; then
+ AC_MSG_RESULT($MOTIF_LIBNAME)
+ GUI_LIB_LOC=
+ else
+ AC_MSG_RESULT(no)
+
+ dnl Remove "-L" from before $GUI_LIB_LOC if it's there
+ GUI_LIB_LOC="`echo $GUI_LIB_LOC|sed 's%-L%%g'`"
+
+ dnl Ubuntu has libXm.so in /usr/lib/i386-linux-gnu and elsewhere. The
+ dnl linker will figure out which one to use, we only check if one exists.
+ AC_MSG_CHECKING(for location of Motif GUI libs)
+ gui_libs="`echo $x_libraries|sed 's%/[^/][^/]*$%%'` `echo "$gui_XXX" | sed s/XXX/lib/g` /usr/lib/i386-linux-gnu /usr/lib/x86_64-linux-gnu `echo "$GUI_INC_LOC" | sed s/include/lib/` $GUI_LIB_LOC"
+ GUI_LIB_LOC=
+ for try in $gui_libs; do
+ for libtry in "$try"/libXm.a "$try"/libXm.so* "$try"/libXm.sl "$try"/libXm.dylib; do
+ if test -f "$libtry"; then
+ GUI_LIB_LOC=$try
+ fi
+ done
+ done
+ if test -n "$GUI_LIB_LOC"; then
+ dnl Remove /usr/lib, it causes trouble on some systems
+ if test "$GUI_LIB_LOC" = /usr/lib \
+ -o "$GUI_LIB_LOC" = /usr/lib/i386-linux-gnu \
+ -o "$GUI_LIB_LOC" = /usr/lib/x86_64-linux-gnu; then
+ GUI_LIB_LOC=
+ AC_MSG_RESULT(in default path)
+ else
+ if test -n "$GUI_LIB_LOC"; then
+ AC_MSG_RESULT($GUI_LIB_LOC)
+ if test "`(uname) 2>/dev/null`" = SunOS &&
+ uname -r | grep '^5' >/dev/null; then
+ GUI_LIB_LOC="$GUI_LIB_LOC -R $GUI_LIB_LOC"
+ fi
+ fi
+ fi
+ MOTIF_LIBNAME=-lXm
+ else
+ AC_MSG_RESULT(<not found>)
+ SKIP_MOTIF=YES
+ fi
+ fi
+fi
+
+if test -z "$SKIP_MOTIF"; then
+ SKIP_ATHENA=YES
+ SKIP_NEXTAW=YES
+ GUITYPE=MOTIF
+ AC_SUBST(MOTIF_LIBNAME)
+fi
+
+dnl Check if the Athena files can be found
+
+GUI_X_LIBS=
+
+if test -z "$SKIP_ATHENA"; then
+ AC_MSG_CHECKING(if Athena header files can be found)
+ cflags_save=$CFLAGS
+ CFLAGS="$CFLAGS $X_CFLAGS"
+ AC_TRY_COMPILE([
+#include <X11/Intrinsic.h>
+#include <X11/Xaw/Paned.h>], ,
+ AC_MSG_RESULT(yes),
+ AC_MSG_RESULT(no); SKIP_ATHENA=YES )
+ CFLAGS=$cflags_save
+fi
+
+if test -z "$SKIP_ATHENA"; then
+ GUITYPE=ATHENA
+fi
+
+if test -z "$SKIP_NEXTAW"; then
+ AC_MSG_CHECKING(if neXtaw header files can be found)
+ cflags_save=$CFLAGS
+ CFLAGS="$CFLAGS $X_CFLAGS"
+ AC_TRY_COMPILE([
+#include <X11/Intrinsic.h>
+#include <X11/neXtaw/Paned.h>], ,
+ AC_MSG_RESULT(yes),
+ AC_MSG_RESULT(no); SKIP_NEXTAW=YES )
+ CFLAGS=$cflags_save
+fi
+
+if test -z "$SKIP_NEXTAW"; then
+ GUITYPE=NEXTAW
+fi
+
+if test -z "$SKIP_ATHENA" -o -z "$SKIP_NEXTAW" -o -z "$SKIP_MOTIF"; then
+ dnl Prepend -I and -L to $GUI_INC_LOC and $GUI_LIB_LOC if not empty
+ dnl Avoid adding it when it twice
+ if test -n "$GUI_INC_LOC"; then
+ GUI_INC_LOC=-I"`echo $GUI_INC_LOC|sed 's%-I%%'`"
+ fi
+ if test -n "$GUI_LIB_LOC"; then
+ GUI_LIB_LOC=-L"`echo $GUI_LIB_LOC|sed 's%-L%%'`"
+ fi
+
+ dnl Check for -lXext and then for -lXmu
+ ldflags_save=$LDFLAGS
+ LDFLAGS="$X_LIBS $LDFLAGS"
+ AC_CHECK_LIB(Xext, XShapeQueryExtension, [GUI_X_LIBS="-lXext"],,
+ [-lXt $X_PRE_LIBS -lX11 $X_EXTRA_LIBS])
+ dnl For Solaris we need -lw and -ldl before linking with -lXmu works.
+ AC_CHECK_LIB(w, wslen, [X_EXTRA_LIBS="$X_EXTRA_LIBS -lw"],,
+ [$GUI_X_LIBS -lXt $X_PRE_LIBS -lX11 $X_EXTRA_LIBS])
+ AC_CHECK_LIB(dl, dlsym, [X_EXTRA_LIBS="$X_EXTRA_LIBS -ldl"],,
+ [$GUI_X_LIBS -lXt $X_PRE_LIBS -lX11 $X_EXTRA_LIBS])
+ AC_CHECK_LIB(Xmu, XmuCreateStippledPixmap, [GUI_X_LIBS="-lXmu $GUI_X_LIBS"],,
+ [$GUI_X_LIBS -lXt $X_PRE_LIBS -lX11 $X_EXTRA_LIBS])
+ if test -z "$SKIP_MOTIF"; then
+ AC_CHECK_LIB(Xp, XpEndJob, [GUI_X_LIBS="-lXp $GUI_X_LIBS"],,
+ [$GUI_X_LIBS -lXm -lXt $X_PRE_LIBS -lX11 $X_EXTRA_LIBS])
+ fi
+ LDFLAGS=$ldflags_save
+
+ dnl Execute xmkmf to figure out if -DNARROWPROTO is needed.
+ AC_MSG_CHECKING(for extra X11 defines)
+ NARROW_PROTO=
+ rm -fr conftestdir
+ if mkdir conftestdir; then
+ cd conftestdir
+ cat > Imakefile <<'EOF'
+acfindx:
+ @echo 'NARROW_PROTO="${PROTO_DEFINES}"'
+EOF
+ if (xmkmf) >/dev/null 2>/dev/null && test -f Makefile; then
+ eval `${MAKE-make} acfindx 2>/dev/null | grep -v make`
+ fi
+ cd ..
+ rm -fr conftestdir
+ fi
+ if test -z "$NARROW_PROTO"; then
+ AC_MSG_RESULT(no)
+ else
+ AC_MSG_RESULT($NARROW_PROTO)
+ fi
+ AC_SUBST(NARROW_PROTO)
+fi
+
+dnl Look for XSMP support - but don't necessarily restrict it to X11 GUIs
+dnl use the X11 include path
+if test "$enable_xsmp" = "yes"; then
+ cppflags_save=$CPPFLAGS
+ CPPFLAGS="$CPPFLAGS $X_CFLAGS"
+ AC_CHECK_HEADERS(X11/SM/SMlib.h)
+ CPPFLAGS=$cppflags_save
+fi
+
+
+if test -z "$SKIP_ATHENA" -o -z "$SKIP_NEXTAW" -o -z "$SKIP_MOTIF" -o -z "$SKIP_GTK2" -o -z "$SKIP_GTK3"; then
+ dnl Check for X11/xpm.h and X11/Sunkeysym.h with the GUI include path
+ cppflags_save=$CPPFLAGS
+ CPPFLAGS="$CPPFLAGS $X_CFLAGS"
+ AC_CHECK_HEADERS(X11/xpm.h X11/Sunkeysym.h)
+
+ dnl automatically disable XIM when XIMtext isn't in X11/Xlib.h
+ if test ! "$enable_xim" = "no"; then
+ AC_MSG_CHECKING(for XIMText in X11/Xlib.h)
+ AC_EGREP_CPP(XIMText, [#include <X11/Xlib.h>],
+ AC_MSG_RESULT(yes),
+ AC_MSG_RESULT(no; xim has been disabled); enable_xim="no")
+ fi
+ CPPFLAGS=$cppflags_save
+
+ dnl automatically enable XIM when hangul input isn't enabled
+ if test "$enable_xim" = "auto" -a "$enable_hangulinput" != "yes" \
+ -a "x$GUITYPE" != "xNONE" ; then
+ AC_MSG_RESULT(X GUI selected; xim has been enabled)
+ enable_xim="yes"
+ fi
+fi
+
+if test -z "$SKIP_ATHENA" -o -z "$SKIP_NEXTAW" -o -z "$SKIP_MOTIF"; then
+ cppflags_save=$CPPFLAGS
+ CPPFLAGS="$CPPFLAGS $X_CFLAGS"
+dnl Xmu/Editres.h may exist but can only be used after including Intrinsic.h
+ AC_MSG_CHECKING([for X11/Xmu/Editres.h])
+ AC_TRY_COMPILE([
+#include <X11/Intrinsic.h>
+#include <X11/Xmu/Editres.h>],
+ [int i; i = 0;],
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_X11_XMU_EDITRES_H),
+ AC_MSG_RESULT(no))
+ CPPFLAGS=$cppflags_save
+fi
+
+dnl Only use the Xm directory when compiling Motif, don't use it for Athena
+if test -z "$SKIP_MOTIF"; then
+ cppflags_save=$CPPFLAGS
+ CPPFLAGS="$CPPFLAGS $X_CFLAGS"
+ if test "$zOSUnix" = "yes"; then
+ xmheader="Xm/Xm.h"
+ else
+ xmheader="Xm/Xm.h Xm/XpmP.h Xm/JoinSideT.h Xm/TraitP.h Xm/Manager.h
+ Xm/UnhighlightT.h Xm/Notebook.h"
+ fi
+ AC_CHECK_HEADERS($xmheader)
+
+ if test "x$ac_cv_header_Xm_XpmP_h" = "xyes"; then
+ dnl Solaris uses XpmAttributes_21, very annoying.
+ AC_MSG_CHECKING([for XpmAttributes_21 in Xm/XpmP.h])
+ AC_TRY_COMPILE([#include <Xm/XpmP.h>], [XpmAttributes_21 attr;],
+ AC_MSG_RESULT(yes); AC_DEFINE(XPMATTRIBUTES_TYPE, XpmAttributes_21),
+ AC_MSG_RESULT(no); AC_DEFINE(XPMATTRIBUTES_TYPE, XpmAttributes)
+ )
+ else
+ AC_DEFINE(XPMATTRIBUTES_TYPE, XpmAttributes)
+ fi
+ CPPFLAGS=$cppflags_save
+fi
+
+if test "x$GUITYPE" = "xNONE" -a "$enable_xim" = "yes"; then
+ AC_MSG_RESULT(no GUI selected; xim has been disabled)
+ enable_xim="no"
+fi
+if test "x$GUITYPE" = "xNONE" -a "$enable_fontset" = "yes"; then
+ AC_MSG_RESULT(no GUI selected; fontset has been disabled)
+ enable_fontset="no"
+fi
+if test "x$GUITYPE:$enable_fontset" = "xGTK:yes"; then
+ AC_MSG_RESULT(GTK+ 2 GUI selected; fontset has been disabled)
+ enable_fontset="no"
+fi
+
+if test -z "$SKIP_PHOTON"; then
+ GUITYPE=PHOTONGUI
+fi
+
+AC_SUBST(GUI_INC_LOC)
+AC_SUBST(GUI_LIB_LOC)
+AC_SUBST(GUITYPE)
+AC_SUBST(GUI_X_LIBS)
+
+if test "$enable_workshop" = "yes" -a -n "$SKIP_MOTIF"; then
+ AC_MSG_ERROR([cannot use workshop without Motif])
+fi
+
+dnl defining FEAT_XIM and FEAT_XFONTSET is delayed, so that they can be disabled
+if test "$enable_xim" = "yes"; then
+ AC_DEFINE(FEAT_XIM)
+fi
+if test "$enable_fontset" = "yes"; then
+ AC_DEFINE(FEAT_XFONTSET)
+fi
+
+
+dnl ---------------------------------------------------------------------------
+dnl end of GUI-checking
+dnl ---------------------------------------------------------------------------
+
+AC_MSG_CHECKING([for /proc link to executable])
+if test -L "/proc/self/exe"; then
+ dnl Linux
+ AC_MSG_RESULT([/proc/self/exe])
+ AC_DEFINE(PROC_EXE_LINK, "/proc/self/exe")
+elif test -L "/proc/self/path/a.out"; then
+ dnl Solaris
+ AC_MSG_RESULT([/proc/self/path/a.out])
+ AC_DEFINE(PROC_EXE_LINK, "/proc/self/path/a.out")
+elif test -L "/proc/curproc/file"; then
+ dnl FreeBSD
+ AC_MSG_RESULT([/proc/curproc/file])
+ AC_DEFINE(PROC_EXE_LINK, "/proc/curproc/file")
+else
+ AC_MSG_RESULT(no)
+fi
+
+dnl Check for Cygwin, which needs an extra source file if not using X11
+AC_MSG_CHECKING(for CYGWIN or MSYS environment)
+case `uname` in
+ CYGWIN*|MSYS*) CYGWIN=yes; AC_MSG_RESULT(yes)
+ AC_MSG_CHECKING(for CYGWIN clipboard support)
+ if test "x$with_x" = "xno" ; then
+ OS_EXTRA_SRC=winclip.c; OS_EXTRA_OBJ=objects/winclip.o
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(FEAT_CYGWIN_WIN32_CLIPBOARD)
+ else
+ AC_MSG_RESULT(no - using X11)
+ fi ;;
+
+ *) CYGWIN=no; AC_MSG_RESULT(no);;
+esac
+
+dnl Only really enable hangul input when GUI and XFONTSET are available
+if test "$enable_hangulinput" = "yes"; then
+ if test "x$GUITYPE" = "xNONE"; then
+ AC_MSG_RESULT(no GUI selected; hangul input has been disabled)
+ enable_hangulinput=no
+ else
+ AC_DEFINE(FEAT_HANGULIN)
+ HANGULIN_SRC=hangulin.c
+ AC_SUBST(HANGULIN_SRC)
+ HANGULIN_OBJ=objects/hangulin.o
+ AC_SUBST(HANGULIN_OBJ)
+ fi
+fi
+
+dnl Checks for libraries and include files.
+
+AC_CACHE_CHECK([whether toupper is broken], [vim_cv_toupper_broken],
+ [
+ AC_RUN_IFELSE([AC_LANG_SOURCE([[
+#include "confdefs.h"
+#include <ctype.h>
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#endif
+main() { exit(toupper('A') == 'A' && tolower('z') == 'z'); }
+ ]])],[
+ vim_cv_toupper_broken=yes
+ ],[
+ vim_cv_toupper_broken=no
+ ],[
+ AC_MSG_ERROR(cross-compiling: please set 'vim_cv_toupper_broken')
+ ])])
+
+if test "x$vim_cv_toupper_broken" = "xyes" ; then
+ AC_DEFINE(BROKEN_TOUPPER)
+fi
+
+AC_MSG_CHECKING(whether __DATE__ and __TIME__ work)
+AC_TRY_COMPILE([#include <stdio.h>], [printf("(" __DATE__ " " __TIME__ ")");],
+ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_DATE_TIME),
+ AC_MSG_RESULT(no))
+
+AC_MSG_CHECKING(whether __attribute__((unused)) is allowed)
+AC_TRY_COMPILE([#include <stdio.h>], [int x __attribute__((unused));],
+ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_ATTRIBUTE_UNUSED),
+ AC_MSG_RESULT(no))
+
+dnl Checks for header files.
+AC_CHECK_HEADER(elf.h, HAS_ELF=1)
+dnl AC_CHECK_HEADER(dwarf.h, SVR4=1)
+if test "$HAS_ELF" = 1; then
+ AC_CHECK_LIB(elf, main)
+fi
+
+AC_HEADER_DIRENT
+
+dnl If sys/wait.h is not found it might still exist but not be POSIX
+dnl compliant. In that case we define HAVE_UNION_WAIT (for NeXT)
+if test $ac_cv_header_sys_wait_h = no; then
+ AC_MSG_CHECKING([for sys/wait.h that defines union wait])
+ AC_TRY_COMPILE([#include <sys/wait.h>],
+ [union wait xx, yy; xx = yy],
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_SYS_WAIT_H)
+ AC_DEFINE(HAVE_UNION_WAIT),
+ AC_MSG_RESULT(no))
+fi
+
+AC_CHECK_HEADERS(stdint.h stdlib.h string.h \
+ sys/select.h sys/utsname.h termcap.h fcntl.h \
+ sgtty.h sys/ioctl.h sys/time.h sys/types.h \
+ termio.h iconv.h inttypes.h langinfo.h math.h \
+ unistd.h stropts.h errno.h sys/resource.h \
+ sys/systeminfo.h locale.h sys/stream.h termios.h \
+ libc.h sys/statfs.h poll.h sys/poll.h pwd.h \
+ utime.h sys/param.h sys/ptms.h libintl.h libgen.h \
+ util/debug.h util/msg18n.h frame.h sys/acl.h \
+ sys/access.h sys/sysinfo.h wchar.h wctype.h)
+
+dnl sys/ptem.h depends on sys/stream.h on Solaris
+AC_CHECK_HEADERS(sys/ptem.h, [], [],
+[#if defined HAVE_SYS_STREAM_H
+# include <sys/stream.h>
+#endif])
+
+dnl sys/sysctl.h depends on sys/param.h on OpenBSD
+AC_CHECK_HEADERS(sys/sysctl.h, [], [],
+[#if defined HAVE_SYS_PARAM_H
+# include <sys/param.h>
+#endif])
+
+
+dnl pthread_np.h may exist but can only be used after including pthread.h
+AC_MSG_CHECKING([for pthread_np.h])
+AC_TRY_COMPILE([
+#include <pthread.h>
+#include <pthread_np.h>],
+ [int i; i = 0;],
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_PTHREAD_NP_H),
+ AC_MSG_RESULT(no))
+
+AC_CHECK_HEADERS(strings.h)
+if test "x$MACOS_X" = "xyes"; then
+ dnl The strings.h file on OS/X contains a warning and nothing useful.
+ AC_DEFINE(NO_STRINGS_WITH_STRING_H)
+else
+
+dnl Check if strings.h and string.h can both be included when defined.
+AC_MSG_CHECKING([if strings.h can be included after string.h])
+cppflags_save=$CPPFLAGS
+CPPFLAGS="$CPPFLAGS $X_CFLAGS"
+AC_TRY_COMPILE([
+#if defined(_AIX) && !defined(_AIX51) && !defined(_NO_PROTO)
+# define _NO_PROTO /* like in os_unix.h, causes conflict for AIX (Winn) */
+ /* but don't do it on AIX 5.1 (Uribarri) */
+#endif
+#ifdef HAVE_XM_XM_H
+# include <Xm/Xm.h> /* This breaks it for HP-UX 11 (Squassabia) */
+#endif
+#ifdef HAVE_STRING_H
+# include <string.h>
+#endif
+#if defined(HAVE_STRINGS_H)
+# include <strings.h>
+#endif
+ ], [int i; i = 0;],
+ AC_MSG_RESULT(yes),
+ AC_DEFINE(NO_STRINGS_WITH_STRING_H)
+ AC_MSG_RESULT(no))
+CPPFLAGS=$cppflags_save
+fi
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_PROG_GCC_TRADITIONAL
+AC_C_CONST
+AC_C_VOLATILE
+AC_TYPE_MODE_T
+AC_TYPE_OFF_T
+AC_TYPE_PID_T
+AC_TYPE_SIZE_T
+AC_TYPE_UID_T
+AC_TYPE_UINT32_T
+
+AC_HEADER_TIME
+AC_CHECK_TYPE(ino_t, long)
+AC_CHECK_TYPE(dev_t, unsigned)
+AC_C_BIGENDIAN(,,,)
+AC_C_INLINE
+
+AC_MSG_CHECKING(for rlim_t)
+if eval "test \"`echo '$''{'ac_cv_type_rlim_t'+set}'`\" = set"; then
+ AC_MSG_RESULT([(cached) $ac_cv_type_rlim_t])
+else
+ AC_EGREP_CPP(dnl
+changequote(<<,>>)dnl
+<<(^|[^a-zA-Z_0-9])rlim_t[^a-zA-Z_0-9]>>dnl
+changequote([,]),
+ [
+#include <sys/types.h>
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#endif
+#ifdef HAVE_SYS_RESOURCE_H
+# include <sys/resource.h>
+#endif
+ ], ac_cv_type_rlim_t=yes, ac_cv_type_rlim_t=no)
+ AC_MSG_RESULT($ac_cv_type_rlim_t)
+fi
+if test $ac_cv_type_rlim_t = no; then
+ cat >> confdefs.h <<\EOF
+#define rlim_t unsigned long
+EOF
+fi
+
+AC_MSG_CHECKING(for stack_t)
+if eval "test \"`echo '$''{'ac_cv_type_stack_t'+set}'`\" = set"; then
+ AC_MSG_RESULT([(cached) $ac_cv_type_stack_t])
+else
+ AC_EGREP_CPP(stack_t,
+ [
+#include <sys/types.h>
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#endif
+#include <signal.h>
+ ], ac_cv_type_stack_t=yes, ac_cv_type_stack_t=no)
+ AC_MSG_RESULT($ac_cv_type_stack_t)
+fi
+if test $ac_cv_type_stack_t = no; then
+ cat >> confdefs.h <<\EOF
+#define stack_t struct sigaltstack
+EOF
+fi
+
+dnl BSDI uses ss_base while others use ss_sp for the stack pointer.
+AC_MSG_CHECKING(whether stack_t has an ss_base field)
+AC_TRY_COMPILE([
+#include <sys/types.h>
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#endif
+#include <signal.h>
+#include "confdefs.h"
+ ], [stack_t sigstk; sigstk.ss_base = 0; ],
+ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_SS_BASE),
+ AC_MSG_RESULT(no))
+
+olibs="$LIBS"
+AC_MSG_CHECKING(--with-tlib argument)
+AC_ARG_WITH(tlib, [ --with-tlib=library terminal library to be used ],)
+if test -n "$with_tlib"; then
+ AC_MSG_RESULT($with_tlib)
+ LIBS="$LIBS -l$with_tlib"
+ AC_MSG_CHECKING(for linking with $with_tlib library)
+ AC_TRY_LINK([], [], AC_MSG_RESULT(OK), AC_MSG_ERROR(FAILED))
+ dnl Need to check for tgetent() below.
+ olibs="$LIBS"
+else
+ AC_MSG_RESULT([empty: automatic terminal library selection])
+ dnl On HP-UX 10.10 termcap or termlib should be used instead of
+ dnl curses, because curses is much slower.
+ dnl Newer versions of ncurses are preferred over anything, except
+ dnl when tinfo has been split off, it contains all we need.
+ dnl Older versions of ncurses have bugs, get a new one!
+ dnl Digital Unix (OSF1) should use curses (Ronald Schild).
+ dnl On SCO Openserver should prefer termlib (Roger Cornelius).
+ case "`uname -s 2>/dev/null`" in
+ OSF1|SCO_SV) tlibs="tinfo ncurses curses termlib termcap";;
+ *) tlibs="tinfo ncurses termlib termcap curses";;
+ esac
+ for libname in $tlibs; do
+ AC_CHECK_LIB(${libname}, tgetent,,)
+ if test "x$olibs" != "x$LIBS"; then
+ dnl It's possible that a library is found but it doesn't work
+ dnl e.g., shared library that cannot be found
+ dnl compile and run a test program to be sure
+ AC_TRY_RUN([
+#ifdef HAVE_TERMCAP_H
+# include <termcap.h>
+#endif
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#endif
+main() {char *s; s=(char *)tgoto("%p1%d", 0, 1); exit(0); }],
+ res="OK", res="FAIL", res="FAIL")
+ if test "$res" = "OK"; then
+ break
+ fi
+ AC_MSG_RESULT($libname library is not usable)
+ LIBS="$olibs"
+ fi
+ done
+ if test "x$olibs" = "x$LIBS"; then
+ AC_MSG_RESULT(no terminal library found)
+ fi
+fi
+
+if test "x$olibs" = "x$LIBS"; then
+ AC_MSG_CHECKING([for tgetent()])
+ AC_TRY_LINK([],
+ [char s[10000]; int res = tgetent(s, "thisterminaldoesnotexist");],
+ AC_MSG_RESULT(yes),
+ AC_MSG_ERROR([NOT FOUND!
+ You need to install a terminal library; for example ncurses.
+ Or specify the name of the library with --with-tlib.]))
+fi
+
+AC_CACHE_CHECK([whether we talk terminfo], [vim_cv_terminfo],
+ [
+ AC_RUN_IFELSE([AC_LANG_SOURCE([[
+#include "confdefs.h"
+#ifdef HAVE_TERMCAP_H
+# include <termcap.h>
+#endif
+#ifdef HAVE_STRING_H
+# include <string.h>
+#endif
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#endif
+main()
+{char *s; s=(char *)tgoto("%p1%d", 0, 1); exit(!strcmp(s==0 ? "" : s, "1")); }
+ ]])],[
+ vim_cv_terminfo=no
+ ],[
+ vim_cv_terminfo=yes
+ ],[
+ AC_MSG_ERROR(cross-compiling: please set 'vim_cv_terminfo')
+ ])
+ ])
+
+if test "x$vim_cv_terminfo" = "xyes" ; then
+ AC_DEFINE(TERMINFO)
+fi
+
+AC_CACHE_CHECK([what tgetent() returns for an unknown terminal], [vim_cv_tgetent],
+ [
+ AC_RUN_IFELSE([AC_LANG_SOURCE([[
+#include "confdefs.h"
+#ifdef HAVE_TERMCAP_H
+# include <termcap.h>
+#endif
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#endif
+main()
+{char s[10000]; int res = tgetent(s, "thisterminaldoesnotexist"); exit(res != 0); }
+ ]])],[
+ vim_cv_tgetent=zero
+ ],[
+ vim_cv_tgetent=non-zero
+ ],[
+ AC_MSG_ERROR(failed to compile test program.)
+ ])
+ ])
+
+if test "x$vim_cv_tgetent" = "xzero" ; then
+ AC_DEFINE(TGETENT_ZERO_ERR, 0)
+fi
+
+AC_MSG_CHECKING(whether termcap.h contains ospeed)
+AC_TRY_LINK([
+#ifdef HAVE_TERMCAP_H
+# include <termcap.h>
+#endif
+ ], [ospeed = 20000],
+ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_OSPEED),
+ [AC_MSG_RESULT(no)
+ AC_MSG_CHECKING(whether ospeed can be extern)
+ AC_TRY_LINK([
+#ifdef HAVE_TERMCAP_H
+# include <termcap.h>
+#endif
+extern short ospeed;
+ ], [ospeed = 20000],
+ AC_MSG_RESULT(yes); AC_DEFINE(OSPEED_EXTERN),
+ AC_MSG_RESULT(no))]
+ )
+
+AC_MSG_CHECKING([whether termcap.h contains UP, BC and PC])
+AC_TRY_LINK([
+#ifdef HAVE_TERMCAP_H
+# include <termcap.h>
+#endif
+ ], [if (UP == 0 && BC == 0) PC = 1],
+ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_UP_BC_PC),
+ [AC_MSG_RESULT(no)
+ AC_MSG_CHECKING([whether UP, BC and PC can be extern])
+ AC_TRY_LINK([
+#ifdef HAVE_TERMCAP_H
+# include <termcap.h>
+#endif
+extern char *UP, *BC, PC;
+ ], [if (UP == 0 && BC == 0) PC = 1],
+ AC_MSG_RESULT(yes); AC_DEFINE(UP_BC_PC_EXTERN),
+ AC_MSG_RESULT(no))]
+ )
+
+AC_MSG_CHECKING(whether tputs() uses outfuntype)
+AC_TRY_COMPILE([
+#ifdef HAVE_TERMCAP_H
+# include <termcap.h>
+#endif
+ ], [extern int xx(); tputs("test", 1, (outfuntype)xx)],
+ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_OUTFUNTYPE),
+ AC_MSG_RESULT(no))
+
+dnl On some SCO machines sys/select redefines struct timeval
+AC_MSG_CHECKING([whether sys/select.h and sys/time.h may both be included])
+AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/select.h>], ,
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(SYS_SELECT_WITH_SYS_TIME),
+ AC_MSG_RESULT(no))
+
+dnl AC_DECL_SYS_SIGLIST
+
+dnl Checks for pty.c (copied from screen) ==========================
+AC_MSG_CHECKING(for /dev/ptc)
+if test -r /dev/ptc; then
+ AC_DEFINE(HAVE_DEV_PTC)
+ AC_MSG_RESULT(yes)
+else
+ AC_MSG_RESULT(no)
+fi
+
+AC_MSG_CHECKING(for SVR4 ptys)
+if test -c /dev/ptmx ; then
+ AC_TRY_LINK([], [ptsname(0);grantpt(0);unlockpt(0);],
+ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_SVR4_PTYS),
+ AC_MSG_RESULT(no))
+else
+ AC_MSG_RESULT(no)
+fi
+
+AC_MSG_CHECKING(for ptyranges)
+if test -d /dev/ptym ; then
+ pdir='/dev/ptym'
+else
+ pdir='/dev'
+fi
+dnl SCO uses ptyp%d
+AC_EGREP_CPP(yes,
+[#ifdef M_UNIX
+ yes;
+#endif
+ ], ptys=`echo /dev/ptyp??`, ptys=`echo $pdir/pty??`)
+dnl if test -c /dev/ptyp19; then
+dnl ptys=`echo /dev/ptyp??`
+dnl else
+dnl ptys=`echo $pdir/pty??`
+dnl fi
+if test "$ptys" != "$pdir/pty??" ; then
+ p0=`echo $ptys | tr ' ' '\012' | sed -e 's/^.*\(.\).$/\1/g' | sort -u | tr -d '\012'`
+ p1=`echo $ptys | tr ' ' '\012' | sed -e 's/^.*\(.\)$/\1/g' | sort -u | tr -d '\012'`
+ AC_DEFINE_UNQUOTED(PTYRANGE0,"$p0")
+ AC_DEFINE_UNQUOTED(PTYRANGE1,"$p1")
+ AC_MSG_RESULT([$p0 / $p1])
+else
+ AC_MSG_RESULT([don't know])
+fi
+
+dnl **** pty mode/group handling ****
+dnl
+dnl support provided by Luke Mewburn <lm@rmit.edu.au>, 931222
+rm -f conftest_grp
+AC_CACHE_CHECK([default tty permissions/group], [vim_cv_tty_group],
+ [
+ AC_RUN_IFELSE([AC_LANG_SOURCE([[
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <sys/stat.h>
+#include <stdio.h>
+main()
+{
+ struct stat sb;
+ char *x,*ttyname();
+ int om, m;
+ FILE *fp;
+
+ if (!(x = ttyname(0))) exit(1);
+ if (stat(x, &sb)) exit(1);
+ om = sb.st_mode;
+ if (om & 002) exit(0);
+ m = system("mesg y");
+ if (m == -1 || m == 127) exit(1);
+ if (stat(x, &sb)) exit(1);
+ m = sb.st_mode;
+ if (chmod(x, om)) exit(1);
+ if (m & 002) exit(0);
+ if (sb.st_gid == getgid()) exit(1);
+ if (!(fp=fopen("conftest_grp", "w")))
+ exit(1);
+ fprintf(fp, "%d\n", sb.st_gid);
+ fclose(fp);
+ exit(0);
+}
+ ]])],[
+ if test -f conftest_grp; then
+ vim_cv_tty_group=`cat conftest_grp`
+ if test "x$vim_cv_tty_mode" = "x" ; then
+ vim_cv_tty_mode=0620
+ fi
+ AC_MSG_RESULT([pty mode: $vim_cv_tty_mode, group: $vim_cv_tty_group])
+ else
+ vim_cv_tty_group=world
+ AC_MSG_RESULT([ptys are world accessible])
+ fi
+ ],[
+ vim_cv_tty_group=world
+ AC_MSG_RESULT([can't determine - assume ptys are world accessible])
+ ],[
+ AC_MSG_ERROR(cross-compiling: please set 'vim_cv_tty_group' and 'vim_cv_tty_mode')
+ ])
+ ])
+rm -f conftest_grp
+
+if test "x$vim_cv_tty_group" != "xworld" ; then
+ AC_DEFINE_UNQUOTED(PTYGROUP,$vim_cv_tty_group)
+ if test "x$vim_cv_tty_mode" = "x" ; then
+ AC_MSG_ERROR([It seems you're cross compiling and have 'vim_cv_tty_group' set, please also set the environment variable 'vim_cv_tty_mode' to the correct mode (probably 0620)])
+ else
+ AC_DEFINE(PTYMODE, 0620)
+ fi
+fi
+
+dnl Checks for library functions. ===================================
+
+AC_TYPE_SIGNAL
+
+dnl find out what to use at the end of a signal function
+if test $ac_cv_type_signal = void; then
+ AC_DEFINE(SIGRETURN, [return])
+else
+ AC_DEFINE(SIGRETURN, [return 0])
+fi
+
+dnl check if struct sigcontext is defined (used for SGI only)
+AC_MSG_CHECKING(for struct sigcontext)
+AC_TRY_COMPILE([
+#include <signal.h>
+test_sig()
+{
+ struct sigcontext *scont;
+ scont = (struct sigcontext *)0;
+ return 1;
+} ], ,
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_SIGCONTEXT),
+ AC_MSG_RESULT(no))
+
+dnl tricky stuff: try to find out if getcwd() is implemented with
+dnl system("sh -c pwd")
+AC_CACHE_CHECK([getcwd implementation is broken], [vim_cv_getcwd_broken],
+ [
+ AC_RUN_IFELSE([AC_LANG_SOURCE([[
+#include "confdefs.h"
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+char *dagger[] = { "IFS=pwd", 0 };
+main()
+{
+ char buffer[500];
+ extern char **environ;
+ environ = dagger;
+ return getcwd(buffer, 500) ? 0 : 1;
+}
+ ]])],[
+ vim_cv_getcwd_broken=no
+ ],[
+ vim_cv_getcwd_broken=yes
+ ],[
+ AC_MSG_ERROR(cross-compiling: please set 'vim_cv_getcwd_broken')
+ ])
+ ])
+
+if test "x$vim_cv_getcwd_broken" = "xyes" ; then
+ AC_DEFINE(BAD_GETCWD)
+fi
+
+dnl Check for functions in one big call, to reduce the size of configure.
+dnl Can only be used for functions that do not require any include.
+AC_CHECK_FUNCS(fchdir fchown fchmod fsync getcwd getpseudotty \
+ getpwent getpwnam getpwuid getrlimit gettimeofday getwd lstat \
+ memset mkdtemp nanosleep opendir putenv qsort readlink select setenv \
+ getpgid setpgid setsid sigaltstack sigstack sigset sigsetjmp sigaction \
+ sigprocmask sigvec strcasecmp strerror strftime stricmp strncasecmp \
+ strnicmp strpbrk strtol tgetent towlower towupper iswupper \
+ usleep utime utimes mblen ftruncate unsetenv)
+AC_FUNC_SELECT_ARGTYPES
+AC_FUNC_FSEEKO
+
+dnl define _LARGE_FILES, _FILE_OFFSET_BITS and _LARGEFILE_SOURCE when
+dnl appropriate, so that off_t is 64 bits when needed.
+AC_SYS_LARGEFILE
+
+dnl fstatfs() can take 2 to 4 arguments, try to use st_blksize if possible
+AC_MSG_CHECKING(for st_blksize)
+AC_TRY_COMPILE(
+[#include <sys/types.h>
+#include <sys/stat.h>],
+[ struct stat st;
+ int n;
+
+ stat("/", &st);
+ n = (int)st.st_blksize;],
+ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_ST_BLKSIZE),
+ AC_MSG_RESULT(no))
+
+AC_CACHE_CHECK([whether stat() ignores a trailing slash], [vim_cv_stat_ignores_slash],
+ [
+ AC_RUN_IFELSE([AC_LANG_SOURCE([[
+#include "confdefs.h"
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+main() {struct stat st; exit(stat("configure/", &st) != 0); }
+ ]])],[
+ vim_cv_stat_ignores_slash=yes
+ ],[
+ vim_cv_stat_ignores_slash=no
+ ],[
+ AC_MSG_ERROR(cross-compiling: please set 'vim_cv_stat_ignores_slash')
+ ])
+ ])
+
+if test "x$vim_cv_stat_ignores_slash" = "xyes" ; then
+ AC_DEFINE(STAT_IGNORES_SLASH)
+fi
+
+dnl Link with iconv for charset translation, if not found without library.
+dnl check for iconv() requires including iconv.h
+dnl Add "-liconv" when possible; Solaris has iconv but use GNU iconv when it
+dnl has been installed.
+AC_MSG_CHECKING(for iconv_open())
+save_LIBS="$LIBS"
+LIBS="$LIBS -liconv"
+AC_TRY_LINK([
+#ifdef HAVE_ICONV_H
+# include <iconv.h>
+#endif
+ ], [iconv_open("fr", "to");],
+ AC_MSG_RESULT(yes; with -liconv); AC_DEFINE(HAVE_ICONV),
+ LIBS="$save_LIBS"
+ AC_TRY_LINK([
+#ifdef HAVE_ICONV_H
+# include <iconv.h>
+#endif
+ ], [iconv_open("fr", "to");],
+ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_ICONV),
+ AC_MSG_RESULT(no)))
+
+
+AC_MSG_CHECKING(for nl_langinfo(CODESET))
+AC_TRY_LINK([
+#ifdef HAVE_LANGINFO_H
+# include <langinfo.h>
+#endif
+], [char *cs = nl_langinfo(CODESET);],
+ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_NL_LANGINFO_CODESET),
+ AC_MSG_RESULT(no))
+
+dnl Need various functions for floating point support. Only enable
+dnl floating point when they are all present.
+AC_CHECK_LIB(m, strtod)
+AC_MSG_CHECKING([for strtod() and other floating point functions])
+AC_TRY_LINK([
+#ifdef HAVE_MATH_H
+# include <math.h>
+#endif
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#endif
+], [char *s; double d;
+ d = strtod("1.1", &s);
+ d = fabs(1.11);
+ d = ceil(1.11);
+ d = floor(1.11);
+ d = log10(1.11);
+ d = pow(1.11, 2.22);
+ d = sqrt(1.11);
+ d = sin(1.11);
+ d = cos(1.11);
+ d = atan(1.11);
+ ],
+ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_FLOAT_FUNCS),
+ AC_MSG_RESULT(no))
+
+dnl isinf() and isnan() need to include header files and may need -lm.
+AC_MSG_CHECKING([for isinf()])
+AC_TRY_LINK([
+#ifdef HAVE_MATH_H
+# include <math.h>
+#endif
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#endif
+], [int r = isinf(1.11); ],
+ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_ISINF),
+ AC_MSG_RESULT(no))
+
+AC_MSG_CHECKING([for isnan()])
+AC_TRY_LINK([
+#ifdef HAVE_MATH_H
+# include <math.h>
+#endif
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#endif
+], [int r = isnan(1.11); ],
+ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_ISNAN),
+ AC_MSG_RESULT(no))
+
+dnl Link with -lposix1e for ACL stuff; if not found, try -lacl for SGI
+dnl when -lacl works, also try to use -lattr (required for Debian).
+dnl On Solaris, use the acl_get/set functions in libsec, if present.
+AC_MSG_CHECKING(--disable-acl argument)
+AC_ARG_ENABLE(acl,
+ [ --disable-acl No check for ACL support.],
+ , [enable_acl="yes"])
+if test "$enable_acl" = "yes"; then
+ AC_MSG_RESULT(no)
+ AC_CHECK_LIB(posix1e, acl_get_file, [LIBS="$LIBS -lposix1e"],
+ AC_CHECK_LIB(acl, acl_get_file, [LIBS="$LIBS -lacl"
+ AC_CHECK_LIB(attr, fgetxattr, LIBS="$LIBS -lattr",,)],,),)
+
+ AC_MSG_CHECKING(for POSIX ACL support)
+ AC_TRY_LINK([
+#include <sys/types.h>
+#ifdef HAVE_SYS_ACL_H
+# include <sys/acl.h>
+#endif
+acl_t acl;], [acl = acl_get_file("foo", ACL_TYPE_ACCESS);
+ acl_set_file("foo", ACL_TYPE_ACCESS, acl);
+ acl_free(acl);],
+ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_POSIX_ACL),
+ AC_MSG_RESULT(no))
+
+ AC_CHECK_LIB(sec, acl_get, [LIBS="$LIBS -lsec"; AC_DEFINE(HAVE_SOLARIS_ZFS_ACL)],
+ AC_MSG_CHECKING(for Solaris ACL support)
+ AC_TRY_LINK([
+#ifdef HAVE_SYS_ACL_H
+# include <sys/acl.h>
+#endif], [acl("foo", GETACLCNT, 0, NULL);
+ ],
+ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_SOLARIS_ACL),
+ AC_MSG_RESULT(no)))
+
+ AC_MSG_CHECKING(for AIX ACL support)
+ AC_TRY_LINK([
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#endif
+#ifdef HAVE_SYS_ACL_H
+# include <sys/acl.h>
+#endif
+#ifdef HAVE_SYS_ACCESS_H
+# include <sys/access.h>
+#endif
+#define _ALL_SOURCE
+
+#include <sys/stat.h>
+
+int aclsize;
+struct acl *aclent;], [aclsize = sizeof(struct acl);
+ aclent = (void *)malloc(aclsize);
+ statacl("foo", STX_NORMAL, aclent, aclsize);
+ ],
+ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_AIX_ACL),
+ AC_MSG_RESULT(no))
+else
+ AC_MSG_RESULT(yes)
+fi
+
+if test "x$GTK_CFLAGS" != "x"; then
+ dnl pango_shape_full() is new, fall back to pango_shape().
+ AC_MSG_CHECKING(for pango_shape_full)
+ ac_save_CFLAGS="$CFLAGS"
+ ac_save_LIBS="$LIBS"
+ CFLAGS="$CFLAGS $GTK_CFLAGS"
+ LIBS="$LIBS $GTK_LIBS"
+ AC_TRY_LINK(
+ [#include <gtk/gtk.h>],
+ [ pango_shape_full(NULL, 0, NULL, 0, NULL, NULL); ],
+ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_PANGO_SHAPE_FULL),
+ AC_MSG_RESULT(no))
+ CFLAGS="$ac_save_CFLAGS"
+ LIBS="$ac_save_LIBS"
+fi
+
+AC_MSG_CHECKING(--disable-gpm argument)
+AC_ARG_ENABLE(gpm,
+ [ --disable-gpm Don't use gpm (Linux mouse daemon).], ,
+ [enable_gpm="yes"])
+
+if test "$enable_gpm" = "yes"; then
+ AC_MSG_RESULT(no)
+ dnl Checking if gpm support can be compiled
+ AC_CACHE_CHECK([for gpm], vi_cv_have_gpm,
+ [olibs="$LIBS" ; LIBS="-lgpm"]
+ AC_TRY_LINK(
+ [#include <gpm.h>
+ #include <linux/keyboard.h>],
+ [Gpm_GetLibVersion(NULL);],
+ dnl Configure defines HAVE_GPM, if it is defined feature.h defines
+ dnl FEAT_MOUSE_GPM if mouse support is included
+ [vi_cv_have_gpm=yes],
+ [vi_cv_have_gpm=no])
+ [LIBS="$olibs"]
+ )
+ if test $vi_cv_have_gpm = yes; then
+ LIBS="$LIBS -lgpm"
+ AC_DEFINE(HAVE_GPM)
+ fi
+else
+ AC_MSG_RESULT(yes)
+fi
+
+AC_MSG_CHECKING(--disable-sysmouse argument)
+AC_ARG_ENABLE(sysmouse,
+ [ --disable-sysmouse Don't use sysmouse (mouse in *BSD console).], ,
+ [enable_sysmouse="yes"])
+
+if test "$enable_sysmouse" = "yes"; then
+ AC_MSG_RESULT(no)
+ dnl Checking if sysmouse support can be compiled
+ dnl Configure defines HAVE_SYSMOUSE, if it is defined feature.h
+ dnl defines FEAT_SYSMOUSE if mouse support is included
+ AC_CACHE_CHECK([for sysmouse], vi_cv_have_sysmouse,
+ AC_TRY_LINK(
+ [#include <sys/consio.h>
+ #include <signal.h>
+ #include <sys/fbio.h>],
+ [struct mouse_info mouse;
+ mouse.operation = MOUSE_MODE;
+ mouse.operation = MOUSE_SHOW;
+ mouse.u.mode.mode = 0;
+ mouse.u.mode.signal = SIGUSR2;],
+ [vi_cv_have_sysmouse=yes],
+ [vi_cv_have_sysmouse=no])
+ )
+ if test $vi_cv_have_sysmouse = yes; then
+ AC_DEFINE(HAVE_SYSMOUSE)
+ fi
+else
+ AC_MSG_RESULT(yes)
+fi
+
+dnl make sure the FD_CLOEXEC flag for fcntl()'s F_SETFD command is known
+AC_MSG_CHECKING(for FD_CLOEXEC)
+AC_TRY_COMPILE(
+[#if HAVE_FCNTL_H
+# include <fcntl.h>
+#endif],
+[ int flag = FD_CLOEXEC;],
+ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_FD_CLOEXEC),
+ AC_MSG_RESULT(not usable))
+
+dnl rename needs to be checked separately to work on Nextstep with cc
+AC_MSG_CHECKING(for rename)
+AC_TRY_LINK([#include <stdio.h>], [rename("this", "that")],
+ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_RENAME),
+ AC_MSG_RESULT(no))
+
+dnl sysctl() may exist but not the arguments we use
+AC_MSG_CHECKING(for sysctl)
+AC_TRY_COMPILE(
+[#include <sys/types.h>
+#include <sys/sysctl.h>],
+[ int mib[2], r;
+ size_t len;
+
+ mib[0] = CTL_HW;
+ mib[1] = HW_USERMEM;
+ len = sizeof(r);
+ (void)sysctl(mib, 2, &r, &len, (void *)0, (size_t)0);
+ ],
+ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_SYSCTL),
+ AC_MSG_RESULT(not usable))
+
+dnl sysinfo() may exist but not be Linux compatible
+AC_MSG_CHECKING(for sysinfo)
+AC_TRY_COMPILE(
+[#include <sys/types.h>
+#include <sys/sysinfo.h>],
+[ struct sysinfo sinfo;
+ int t;
+
+ (void)sysinfo(&sinfo);
+ t = sinfo.totalram;
+ ],
+ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_SYSINFO),
+ AC_MSG_RESULT(not usable))
+
+dnl struct sysinfo may have the mem_unit field or not
+AC_MSG_CHECKING(for sysinfo.mem_unit)
+AC_TRY_COMPILE(
+[#include <sys/types.h>
+#include <sys/sysinfo.h>],
+[ struct sysinfo sinfo;
+ sinfo.mem_unit = 1;
+ ],
+ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_SYSINFO_MEM_UNIT),
+ AC_MSG_RESULT(no))
+
+dnl sysconf() may exist but not support what we want to use
+AC_MSG_CHECKING(for sysconf)
+AC_TRY_COMPILE(
+[#include <unistd.h>],
+[ (void)sysconf(_SC_PAGESIZE);
+ (void)sysconf(_SC_PHYS_PAGES);
+ ],
+ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_SYSCONF),
+ AC_MSG_RESULT(not usable))
+
+AC_CHECK_SIZEOF([int])
+AC_CHECK_SIZEOF([long])
+AC_CHECK_SIZEOF([time_t])
+AC_CHECK_SIZEOF([off_t])
+
+dnl Use different names to avoid clashing with other header files.
+AC_DEFINE_UNQUOTED(VIM_SIZEOF_INT, [$ac_cv_sizeof_int])
+AC_DEFINE_UNQUOTED(VIM_SIZEOF_LONG, [$ac_cv_sizeof_long])
+
+dnl Make sure that uint32_t is really 32 bits unsigned.
+AC_MSG_CHECKING([uint32_t is 32 bits])
+AC_TRY_RUN([
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+main() {
+ uint32_t nr1 = (uint32_t)-1;
+ uint32_t nr2 = (uint32_t)0xffffffffUL;
+ if (sizeof(uint32_t) != 4 || nr1 != 0xffffffffUL || nr2 + 1 != 0) exit(1);
+ exit(0);
+}],
+AC_MSG_RESULT(ok),
+AC_MSG_ERROR([WRONG! uint32_t not defined correctly.]),
+AC_MSG_WARN([cannot check uint32_t when cross-compiling.]))
+
+dnl Check for memmove() before bcopy(), makes memmove() be used when both are
+dnl present, fixes problem with incompatibility between Solaris 2.4 and 2.5.
+
+[bcopy_test_prog='
+#include "confdefs.h"
+#ifdef HAVE_STRING_H
+# include <string.h>
+#endif
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#endif
+main() {
+ char buf[10];
+ strcpy(buf, "abcdefghi");
+ mch_memmove(buf, buf + 2, 3);
+ if (strncmp(buf, "ababcf", 6))
+ exit(1);
+ strcpy(buf, "abcdefghi");
+ mch_memmove(buf + 2, buf, 3);
+ if (strncmp(buf, "cdedef", 6))
+ exit(1);
+ exit(0); /* libc version works properly. */
+}']
+
+AC_CACHE_CHECK([whether memmove handles overlaps],[vim_cv_memmove_handles_overlap],
+ [
+ AC_RUN_IFELSE([AC_LANG_SOURCE([[#define mch_memmove(s,d,l) memmove(d,s,l) $bcopy_test_prog]])],
+ [
+ vim_cv_memmove_handles_overlap=yes
+ ],[
+ vim_cv_memmove_handles_overlap=no
+ ],[
+ AC_MSG_ERROR(cross-compiling: please set 'vim_cv_memmove_handles_overlap')
+ ])
+ ])
+
+if test "x$vim_cv_memmove_handles_overlap" = "xyes" ; then
+ AC_DEFINE(USEMEMMOVE)
+else
+ AC_CACHE_CHECK([whether bcopy handles overlaps],[vim_cv_bcopy_handles_overlap],
+ [
+ AC_RUN_IFELSE([AC_LANG_SOURCE([[#define mch_bcopy(s,d,l) bcopy(d,s,l) $bcopy_test_prog]])],
+ [
+ vim_cv_bcopy_handles_overlap=yes
+ ],[
+ vim_cv_bcopy_handles_overlap=no
+ ],[
+ AC_MSG_ERROR(cross-compiling: please set 'vim_cv_bcopy_handles_overlap')
+ ])
+ ])
+
+ if test "x$vim_cv_bcopy_handles_overlap" = "xyes" ; then
+ AC_DEFINE(USEBCOPY)
+ else
+ AC_CACHE_CHECK([whether memcpy handles overlaps],[vim_cv_memcpy_handles_overlap],
+ [
+ AC_RUN_IFELSE([AC_LANG_SOURCE([[#define mch_memcpy(s,d,l) memcpy(d,s,l) $bcopy_test_prog]])],
+ [
+ vim_cv_memcpy_handles_overlap=yes
+ ],[
+ vim_cv_memcpy_handles_overlap=no
+ ],[
+ AC_MSG_ERROR(cross-compiling: please set 'vim_cv_memcpy_handles_overlap')
+ ])
+ ])
+
+ if test "x$vim_cv_memcpy_handles_overlap" = "xyes" ; then
+ AC_DEFINE(USEMEMCPY)
+ fi
+ fi
+fi
+
+
+dnl Check for multibyte locale functions
+dnl Find out if _Xsetlocale() is supported by libX11.
+dnl Check if X_LOCALE should be defined.
+if test "x$with_x" = "xyes"; then
+ cflags_save=$CFLAGS
+ libs_save=$LIBS
+ LIBS="$LIBS $X_LIBS $GUI_LIB_LOC $GUI_X_LIBS $X_PRE_LIBS $X_LIB $X_EXTRA_LIBS"
+ CFLAGS="$CFLAGS $X_CFLAGS"
+
+ AC_MSG_CHECKING(whether X_LOCALE needed)
+ AC_TRY_COMPILE([#include <X11/Xlocale.h>],,
+ AC_TRY_LINK_FUNC([_Xsetlocale], [AC_MSG_RESULT(yes)
+ AC_DEFINE(X_LOCALE)], AC_MSG_RESULT(no)),
+ AC_MSG_RESULT(no))
+
+ AC_MSG_CHECKING(whether Xutf8SetWMProperties() can be used)
+ AC_TRY_LINK_FUNC([Xutf8SetWMProperties], [AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_XUTF8SETWMPROPERTIES)], AC_MSG_RESULT(no))
+
+ CFLAGS=$cflags_save
+ LIBS=$libs_save
+fi
+
+dnl Link with xpg4, it is said to make Korean locale working
+AC_CHECK_LIB(xpg4, _xpg4_setrunelocale, [LIBS="$LIBS -lxpg4"],,)
+
+dnl Check how we can run ctags. Default to "ctags" when nothing works.
+dnl Use --version to detect Exuberant ctags (preferred)
+dnl Add --fields=+S to get function signatures for omni completion.
+dnl -t for typedefs (many ctags have this)
+dnl -s for static functions (Elvis ctags only?)
+dnl -v for variables. Dangerous, most ctags take this for 'vgrind style'.
+dnl -i+m to test for older Exuberant ctags
+AC_MSG_CHECKING(how to create tags)
+test -f tags && mv tags tags.save
+if (eval ctags --version /dev/null | grep Exuberant) < /dev/null 1>&AC_FD_CC 2>&1; then
+ TAGPRG="ctags -I INIT+ --fields=+S"
+elif (eval exctags --version /dev/null | grep Exuberant) < /dev/null 1>&AC_FD_CC 2>&1; then
+ TAGPRG="exctags -I INIT+ --fields=+S"
+elif (eval exuberant-ctags --version /dev/null | grep Exuberant) < /dev/null 1>&AC_FD_CC 2>&1; then
+ TAGPRG="exuberant-ctags -I INIT+ --fields=+S"
+else
+ TAGPRG="ctags"
+ (eval etags /dev/null) < /dev/null 1>&AC_FD_CC 2>&1 && TAGPRG="etags"
+ (eval etags -c /dev/null) < /dev/null 1>&AC_FD_CC 2>&1 && TAGPRG="etags -c"
+ (eval ctags /dev/null) < /dev/null 1>&AC_FD_CC 2>&1 && TAGPRG="ctags"
+ (eval ctags -t /dev/null) < /dev/null 1>&AC_FD_CC 2>&1 && TAGPRG="ctags -t"
+ (eval ctags -ts /dev/null) < /dev/null 1>&AC_FD_CC 2>&1 && TAGPRG="ctags -ts"
+ (eval ctags -tvs /dev/null) < /dev/null 1>&AC_FD_CC 2>&1 && TAGPRG="ctags -tvs"
+ (eval ctags -i+m /dev/null) < /dev/null 1>&AC_FD_CC 2>&1 && TAGPRG="ctags -i+m"
+fi
+test -f tags.save && mv tags.save tags
+AC_MSG_RESULT($TAGPRG) AC_SUBST(TAGPRG)
+
+dnl Check how we can run man with a section number
+AC_MSG_CHECKING(how to run man with a section nr)
+MANDEF="man"
+(eval MANPAGER=cat PAGER=cat man -s 2 read) < /dev/null > /dev/null 2>&AC_FD_CC && MANDEF="man -s"
+AC_MSG_RESULT($MANDEF)
+if test "$MANDEF" = "man -s"; then
+ AC_DEFINE(USEMAN_S)
+fi
+
+dnl Check if gettext() is working and if it needs -lintl
+dnl We take care to base this on an empty LIBS: on some systems libelf would be
+dnl in LIBS and implicitly take along libintl. The final LIBS would then not
+dnl contain libintl, and the link step would fail due to -Wl,--as-needed.
+AC_MSG_CHECKING(--disable-nls argument)
+AC_ARG_ENABLE(nls,
+ [ --disable-nls Don't support NLS (gettext()).], ,
+ [enable_nls="yes"])
+
+if test "$enable_nls" = "yes"; then
+ AC_MSG_RESULT(no)
+
+ INSTALL_LANGS=install-languages
+ AC_SUBST(INSTALL_LANGS)
+ INSTALL_TOOL_LANGS=install-tool-languages
+ AC_SUBST(INSTALL_TOOL_LANGS)
+
+ AC_CHECK_PROG(MSGFMT, msgfmt, msgfmt, )
+ AC_MSG_CHECKING([for NLS])
+ if test -f po/Makefile; then
+ have_gettext="no"
+ if test -n "$MSGFMT"; then
+ olibs=$LIBS
+ LIBS=""
+ AC_TRY_LINK(
+ [#include <libintl.h>],
+ [gettext("Test");],
+ AC_MSG_RESULT([gettext() works]); have_gettext="yes"; LIBS=$olibs,
+ LIBS="-lintl"
+ AC_TRY_LINK(
+ [#include <libintl.h>],
+ [gettext("Test");],
+ AC_MSG_RESULT([gettext() works with -lintl]); have_gettext="yes";
+ LIBS="$olibs -lintl",
+ AC_MSG_RESULT([gettext() doesn't work]);
+ LIBS=$olibs))
+ else
+ AC_MSG_RESULT([msgfmt not found - disabled]);
+ fi
+ if test $have_gettext = "yes" -a "x$features" != "xtiny" -a "x$features" != "xsmall"; then
+ AC_DEFINE(HAVE_GETTEXT)
+ MAKEMO=yes
+ AC_SUBST(MAKEMO)
+ dnl this was added in GNU gettext 0.10.36
+ AC_CHECK_FUNCS(bind_textdomain_codeset)
+ dnl _nl_msg_cat_cntr is required for GNU gettext
+ AC_MSG_CHECKING([for _nl_msg_cat_cntr])
+ AC_TRY_LINK(
+ [#include <libintl.h>
+ extern int _nl_msg_cat_cntr;],
+ [++_nl_msg_cat_cntr;],
+ AC_MSG_RESULT([yes]); AC_DEFINE(HAVE_NL_MSG_CAT_CNTR),
+ AC_MSG_RESULT([no]))
+ fi
+ else
+ AC_MSG_RESULT([no "po/Makefile" - disabled]);
+ fi
+else
+ AC_MSG_RESULT(yes)
+fi
+
+dnl Check for dynamic linking loader
+AC_CHECK_HEADER(dlfcn.h, DLL=dlfcn.h, [AC_CHECK_HEADER(dl.h, DLL=dl.h)])
+if test x${DLL} = xdlfcn.h; then
+ AC_DEFINE(HAVE_DLFCN_H, 1, [ Define if we have dlfcn.h. ])
+ AC_MSG_CHECKING([for dlopen()])
+ AC_TRY_LINK(,[
+ extern void* dlopen();
+ dlopen();
+ ],
+ AC_MSG_RESULT(yes);
+ AC_DEFINE(HAVE_DLOPEN, 1, [ Define if we have dlopen() ]),
+ AC_MSG_RESULT(no);
+ AC_MSG_CHECKING([for dlopen() in -ldl])
+ olibs=$LIBS
+ LIBS="$LIBS -ldl"
+ AC_TRY_LINK(,[
+ extern void* dlopen();
+ dlopen();
+ ],
+ AC_MSG_RESULT(yes);
+ AC_DEFINE(HAVE_DLOPEN, 1, [ Define if we have dlopen() ]),
+ AC_MSG_RESULT(no);
+ LIBS=$olibs))
+ dnl ReliantUNIX has dlopen() in libc but everything else in libdl
+ dnl ick :-)
+ AC_MSG_CHECKING([for dlsym()])
+ AC_TRY_LINK(,[
+ extern void* dlsym();
+ dlsym();
+ ],
+ AC_MSG_RESULT(yes);
+ AC_DEFINE(HAVE_DLSYM, 1, [ Define if we have dlsym() ]),
+ AC_MSG_RESULT(no);
+ AC_MSG_CHECKING([for dlsym() in -ldl])
+ olibs=$LIBS
+ LIBS="$LIBS -ldl"
+ AC_TRY_LINK(,[
+ extern void* dlsym();
+ dlsym();
+ ],
+ AC_MSG_RESULT(yes);
+ AC_DEFINE(HAVE_DLSYM, 1, [ Define if we have dlsym() ]),
+ AC_MSG_RESULT(no);
+ LIBS=$olibs))
+elif test x${DLL} = xdl.h; then
+ AC_DEFINE(HAVE_DL_H, 1, [ Define if we have dl.h. ])
+ AC_MSG_CHECKING([for shl_load()])
+ AC_TRY_LINK(,[
+ extern void* shl_load();
+ shl_load();
+ ],
+ AC_MSG_RESULT(yes);
+ AC_DEFINE(HAVE_SHL_LOAD, 1, [ Define if we have shl_load() ]),
+ AC_MSG_RESULT(no);
+ AC_MSG_CHECKING([for shl_load() in -ldld])
+ olibs=$LIBS
+ LIBS="$LIBS -ldld"
+ AC_TRY_LINK(,[
+ extern void* shl_load();
+ shl_load();
+ ],
+ AC_MSG_RESULT(yes);
+ AC_DEFINE(HAVE_SHL_LOAD, 1, [ Define if we have shl_load() ]),
+ AC_MSG_RESULT(no);
+ LIBS=$olibs))
+fi
+AC_CHECK_HEADERS(setjmp.h)
+
+if test "x$MACOS_X" = "xyes" -a -n "$PERL"; then
+ dnl -ldl must come after DynaLoader.a
+ if echo $LIBS | grep -e '-ldl' >/dev/null; then
+ LIBS=`echo $LIBS | sed s/-ldl//`
+ PERL_LIBS="$PERL_LIBS -ldl"
+ fi
+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 "$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++'`
+ OS_EXTRA_OBJ=`echo "$OS_EXTRA_OBJ" | sed -e 's+objects/os_macosx.o++'`
+ AC_MSG_RESULT([yes, we need CoreServices])
+ LIBS="$LIBS -framework CoreServices"
+ else
+ AC_MSG_RESULT([yes, we need AppKit])
+ LIBS="$LIBS -framework AppKit"
+ fi
+ else
+ AC_MSG_RESULT([no])
+ fi
+fi
+if test "x$MACARCH" = "xboth" && test "x$GUITYPE" = "xCARBONGUI"; then
+ LDFLAGS="$LDFLAGS -isysroot $DEVELOPER_DIR/SDKs/MacOSX10.4u.sdk -arch i386 -arch ppc"
+fi
+
+dnl gcc 3.1 changed the meaning of -MM. The only solution appears to be to
+dnl use "-isystem" instead of "-I" for all non-Vim include dirs.
+dnl But only when making dependencies, cproto and lint don't take "-isystem".
+dnl Mac gcc returns "powerpc-apple-darwin8-gcc-4.0.1 (GCC)...", need to allow
+dnl the number before the version number.
+DEPEND_CFLAGS_FILTER=
+if test "$GCC" = yes; then
+ AC_MSG_CHECKING(for GCC 3 or later)
+ gccmajor=`echo "$gccversion" | sed -e 's/^\([[1-9]]\)\..*$/\1/g'`
+ if test "$gccmajor" -gt "2"; then
+ DEPEND_CFLAGS_FILTER="| sed 's+-I */+-isystem /+g'"
+ AC_MSG_RESULT(yes)
+ else
+ AC_MSG_RESULT(no)
+ fi
+ dnl -D_FORTIFY_SOURCE=2 crashes Vim on strcpy(buf, "000") when buf is
+ dnl declared as char x[1] but actually longer. Introduced in gcc 4.0.
+ dnl Also remove duplicate _FORTIFY_SOURCE arguments.
+ dnl And undefine it first to avoid a warning.
+ AC_MSG_CHECKING(whether we need -D_FORTIFY_SOURCE=1)
+ if test "$gccmajor" -gt "3"; then
+ CFLAGS=`echo "$CFLAGS" | sed -e 's/ *-Wp,-D_FORTIFY_SOURCE=.//g' -e 's/ *-D_FORTIFY_SOURCE=.//g' -e 's/ *-U_FORTIFY_SOURCE//g' -e 's/$/ -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1/'`
+ AC_MSG_RESULT(yes)
+ else
+ AC_MSG_RESULT(no)
+ fi
+fi
+AC_SUBST(DEPEND_CFLAGS_FILTER)
+
+dnl On some systems AC_SYS_LARGEFILE determines that -D_FILE_OFFSET_BITS=64
+dnl isn't required, but the CFLAGS for some of the libraries we're using
+dnl include the define. Since the define changes the size of some datatypes
+dnl (e.g. ino_t and off_t), all of Vim's modules must be compiled with a
+dnl consistent value. It's therefore safest to force the use of the define
+dnl if it's present in any of the *_CFLAGS variables.
+AC_MSG_CHECKING(whether we need to force -D_FILE_OFFSET_BITS=64)
+if echo "$CFLAGS $LUA_CFLAGS $MZSCHEME_CFLAGS $PERL_CFLAGS $PYTHON_CFLAGS $PYTHON3_CFLAGS $TCL_CFLAGS $RUBY_CFLAGS $GTK_CFLAGS" | grep -q D_FILE_OFFSET_BITS 2>/dev/null; then
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(_FILE_OFFSET_BITS, 64)
+else
+ AC_MSG_RESULT(no)
+fi
+
+dnl link.sh tries to avoid overlinking in a hackish way.
+dnl At least GNU ld supports --as-needed which provides the same functionality
+dnl at linker level. Let's use it.
+AC_MSG_CHECKING(linker --as-needed support)
+LINK_AS_NEEDED=
+# Check if linker supports --as-needed and --no-as-needed options
+if $CC -Wl,--help 2>/dev/null | grep as-needed > /dev/null; then
+ LDFLAGS=`echo "$LDFLAGS" | sed -e 's/ *-Wl,--as-needed//g' | sed -e 's/$/ -Wl,--as-needed/'`
+ LINK_AS_NEEDED=yes
+fi
+if test "$LINK_AS_NEEDED" = yes; then
+ AC_MSG_RESULT(yes)
+else
+ AC_MSG_RESULT(no)
+fi
+AC_SUBST(LINK_AS_NEEDED)
+
+# IBM z/OS reset CFLAGS for config.mk
+if test "$zOSUnix" = "yes"; then
+ CFLAGS="-D_ALL_SOURCE -Wc,float\(ieee\),dll"
+fi
+
+dnl write output files
+AC_OUTPUT(auto/config.mk:config.mk.in)
+
+dnl vim: set sw=2 tw=78 fo+=l:
diff --git a/src/create_cmdidxs.vim b/src/create_cmdidxs.vim
new file mode 100644
index 0000000..c306ccb
--- /dev/null
+++ b/src/create_cmdidxs.vim
@@ -0,0 +1,81 @@
+" This script generates the tables cmdidxs1[] and cmdidxs2[][] which,
+" given a Ex command, determine the first value to probe to find
+" a matching command in cmdnames[] based on the first character
+" and the first 2 characters of the command.
+" This is used to speed up lookup in cmdnames[].
+"
+" Script should be run every time new Ex commands are added in Vim,
+" from the src/vim directory, since it reads commands from "ex_cmds.h".
+
+let cmds = []
+let skipped_cmds = 0
+
+for line in readfile('ex_cmds.h')
+ if line =~ '^EX(CMD_'
+ let m = matchlist(line, '^EX(CMD_\S*,\s*"\([a-z][^"]*\)"')
+ if len(m) >= 2
+ let cmds += [ m[1] ]
+ else
+ let skipped_cmds += 1
+ endif
+ endif
+endfor
+
+let cmdidxs1 = {}
+let cmdidxs2 = {}
+
+for i in range(len(cmds) - 1, 0, -1)
+ let cmd = cmds[i]
+ let c1 = cmd[0] " First character of command
+ let c2 = cmd[1] " Second character of command (if any)
+
+ let cmdidxs1{c1} = i
+ if c2 >= 'a' && c2 <= 'z'
+ let cmdidxs2{c1}{c2} = i
+ endif
+endfor
+
+let output = [ '/* Automatically generated code by create_cmdidxs.vim' ]
+let output += [ ' *' ]
+let output += [ ' * Table giving the index of the first command in cmdnames[] to lookup' ]
+let output += [ ' * based on the first letter of a command.' ]
+let output += [ ' */' ]
+let output += [ 'static const unsigned short cmdidxs1[26] =' ]
+let output += [ '{' ]
+
+let a_to_z = map(range(char2nr('a'), char2nr('z')), 'nr2char(v:val)')
+for c1 in a_to_z
+ let line = ' /* ' . c1 . ' */ ' . cmdidxs1{c1} . ((c1 == 'z') ? '' : ',')
+ let output += [ line ]
+endfor
+let output += [ '};' ]
+let output += [ '' ]
+let output += [ '/*' ]
+let output += [ ' * Table giving the index of the first command in cmdnames[] to lookup' ]
+let output += [ ' * based on the first 2 letters of a command.' ]
+let output += [ ' * Values in cmdidxs2[c1][c2] are relative to cmdidxs1[c1] so that they' ]
+let output += [ ' * fit in a byte.' ]
+let output += [ ' */' ]
+let output += [ 'static const unsigned char cmdidxs2[26][26] =' ]
+let output += [ '{ /* a b c d e f g h i j k l m n o p q r s t u v w x y z */' ]
+
+for c1 in a_to_z
+ let line = ' /* ' . c1 . ' */ {'
+ for c2 in a_to_z
+ if exists('cmdidxs2{c1}{c2}')
+ let line .= printf('%3d', cmdidxs2{c1}{c2} - cmdidxs1{c1})
+ else
+ let line .= ' 0'
+ endif
+ let line .= (c2 == 'z') ? '' : ','
+ endfor
+ let line .= ' }' . ((c1 == 'z') ? '' : ',')
+ let output += [ line ]
+endfor
+
+let output += [ '};' ]
+let output += [ '' ]
+let output += [ 'static const int command_count = ' . (len(cmds) + skipped_cmds) . ';' ]
+
+call writefile(output, "ex_cmdidxs.h")
+quit
diff --git a/src/crypt.c b/src/crypt.c
new file mode 100644
index 0000000..47617e9
--- /dev/null
+++ b/src/crypt.c
@@ -0,0 +1,605 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * crypt.c: Generic encryption support.
+ */
+#include "vim.h"
+
+#if defined(FEAT_CRYPT) || defined(PROTO)
+/*
+ * Optional encryption support.
+ * Mohsin Ahmed, mosh@sasi.com, 1998-09-24
+ * Based on zip/crypt sources.
+ * Refactored by David Leadbeater, 2014.
+ *
+ * NOTE FOR USA: Since 2000 exporting this code from the USA is allowed to
+ * most countries. There are a few exceptions, but that still should not be a
+ * problem since this code was originally created in Europe and India.
+ *
+ * Blowfish addition originally made by Mohsin Ahmed,
+ * http://www.cs.albany.edu/~mosh 2010-03-14
+ * Based on blowfish by Bruce Schneier (http://www.schneier.com/blowfish.html)
+ * and sha256 by Christophe Devine.
+ */
+
+typedef struct {
+ char *name; /* encryption name as used in 'cryptmethod' */
+ char *magic; /* magic bytes stored in file header */
+ int salt_len; /* length of salt, or 0 when not using salt */
+ int seed_len; /* length of seed, or 0 when not using salt */
+#ifdef CRYPT_NOT_INPLACE
+ int works_inplace; /* encryption/decryption can be done in-place */
+#endif
+ int whole_undofile; /* whole undo file is encrypted */
+
+ /* Optional function pointer for a self-test. */
+ int (* self_test_fn)();
+
+ /* Function pointer for initializing encryption/decription. */
+ void (* init_fn)(cryptstate_T *state, char_u *key,
+ char_u *salt, int salt_len, char_u *seed, int seed_len);
+
+ /* Function pointers for encoding/decoding from one buffer into another.
+ * Optional, however, these or the _buffer ones should be configured. */
+ void (*encode_fn)(cryptstate_T *state, char_u *from, size_t len,
+ char_u *to);
+ void (*decode_fn)(cryptstate_T *state, char_u *from, size_t len,
+ char_u *to);
+
+ /* Function pointers for encoding and decoding, can buffer data if needed.
+ * Optional (however, these or the above should be configured). */
+ long (*encode_buffer_fn)(cryptstate_T *state, char_u *from, size_t len,
+ char_u **newptr);
+ long (*decode_buffer_fn)(cryptstate_T *state, char_u *from, size_t len,
+ char_u **newptr);
+
+ /* Function pointers for in-place encoding and decoding, used for
+ * crypt_*_inplace(). "from" and "to" arguments will be equal.
+ * These may be the same as decode_fn and encode_fn above, however an
+ * algorithm may implement them in a way that is not interchangeable with
+ * the crypt_(en|de)code() interface (for example because it wishes to add
+ * padding to files).
+ * This method is used for swap and undo files which have a rigid format.
+ */
+ void (*encode_inplace_fn)(cryptstate_T *state, char_u *p1, size_t len,
+ char_u *p2);
+ void (*decode_inplace_fn)(cryptstate_T *state, char_u *p1, size_t len,
+ char_u *p2);
+} cryptmethod_T;
+
+/* index is method_nr of cryptstate_T, CRYPT_M_* */
+static cryptmethod_T cryptmethods[CRYPT_M_COUNT] = {
+ /* PK_Zip; very weak */
+ {
+ "zip",
+ "VimCrypt~01!",
+ 0,
+ 0,
+#ifdef CRYPT_NOT_INPLACE
+ TRUE,
+#endif
+ FALSE,
+ NULL,
+ crypt_zip_init,
+ crypt_zip_encode, crypt_zip_decode,
+ NULL, NULL,
+ crypt_zip_encode, crypt_zip_decode,
+ },
+
+ /* Blowfish/CFB + SHA-256 custom key derivation; implementation issues. */
+ {
+ "blowfish",
+ "VimCrypt~02!",
+ 8,
+ 8,
+#ifdef CRYPT_NOT_INPLACE
+ TRUE,
+#endif
+ FALSE,
+ blowfish_self_test,
+ crypt_blowfish_init,
+ crypt_blowfish_encode, crypt_blowfish_decode,
+ NULL, NULL,
+ crypt_blowfish_encode, crypt_blowfish_decode,
+ },
+
+ /* Blowfish/CFB + SHA-256 custom key derivation; fixed. */
+ {
+ "blowfish2",
+ "VimCrypt~03!",
+ 8,
+ 8,
+#ifdef CRYPT_NOT_INPLACE
+ TRUE,
+#endif
+ TRUE,
+ blowfish_self_test,
+ crypt_blowfish_init,
+ crypt_blowfish_encode, crypt_blowfish_decode,
+ NULL, NULL,
+ crypt_blowfish_encode, crypt_blowfish_decode,
+ },
+
+ /* NOTE: when adding a new method, use some random bytes for the magic key,
+ * to avoid that a text file is recognized as encrypted. */
+};
+
+#define CRYPT_MAGIC_LEN 12 /* cannot change */
+static char crypt_magic_head[] = "VimCrypt~";
+
+/*
+ * Return int value for crypt method name.
+ * 0 for "zip", the old method. Also for any non-valid value.
+ * 1 for "blowfish".
+ * 2 for "blowfish2".
+ */
+ int
+crypt_method_nr_from_name(char_u *name)
+{
+ int i;
+
+ for (i = 0; i < CRYPT_M_COUNT; ++i)
+ if (STRCMP(name, cryptmethods[i].name) == 0)
+ return i;
+ return 0;
+}
+
+/*
+ * Get the crypt method used for a file from "ptr[len]", the magic text at the
+ * start of the file.
+ * Returns -1 when no encryption used.
+ */
+ int
+crypt_method_nr_from_magic(char *ptr, int len)
+{
+ int i;
+
+ if (len < CRYPT_MAGIC_LEN)
+ return -1;
+
+ for (i = 0; i < CRYPT_M_COUNT; i++)
+ if (memcmp(ptr, cryptmethods[i].magic, CRYPT_MAGIC_LEN) == 0)
+ return i;
+
+ i = (int)STRLEN(crypt_magic_head);
+ if (len >= i && memcmp(ptr, crypt_magic_head, i) == 0)
+ emsg(_("E821: File is encrypted with unknown method"));
+
+ return -1;
+}
+
+#ifdef CRYPT_NOT_INPLACE
+/*
+ * Return TRUE if the crypt method for "method_nr" can be done in-place.
+ */
+ int
+crypt_works_inplace(cryptstate_T *state)
+{
+ return cryptmethods[state->method_nr].works_inplace;
+}
+#endif
+
+/*
+ * Get the crypt method for buffer "buf" as a number.
+ */
+ int
+crypt_get_method_nr(buf_T *buf)
+{
+ return crypt_method_nr_from_name(*buf->b_p_cm == NUL ? p_cm : buf->b_p_cm);
+}
+
+/*
+ * Return TRUE when the buffer uses an encryption method that encrypts the
+ * whole undo file, not only the text.
+ */
+ int
+crypt_whole_undofile(int method_nr)
+{
+ return cryptmethods[method_nr].whole_undofile;
+}
+
+/*
+ * Get crypt method specifc length of the file header in bytes.
+ */
+ int
+crypt_get_header_len(int method_nr)
+{
+ return CRYPT_MAGIC_LEN
+ + cryptmethods[method_nr].salt_len
+ + cryptmethods[method_nr].seed_len;
+}
+
+/*
+ * Set the crypt method for buffer "buf" to "method_nr" using the int value as
+ * returned by crypt_method_nr_from_name().
+ */
+ void
+crypt_set_cm_option(buf_T *buf, int method_nr)
+{
+ free_string_option(buf->b_p_cm);
+ buf->b_p_cm = vim_strsave((char_u *)cryptmethods[method_nr].name);
+}
+
+/*
+ * If the crypt method for the current buffer has a self-test, run it and
+ * return OK/FAIL.
+ */
+ int
+crypt_self_test(void)
+{
+ int method_nr = crypt_get_method_nr(curbuf);
+
+ if (cryptmethods[method_nr].self_test_fn == NULL)
+ return OK;
+ return cryptmethods[method_nr].self_test_fn();
+}
+
+/*
+ * Allocate a crypt state and initialize it.
+ */
+ cryptstate_T *
+crypt_create(
+ int method_nr,
+ char_u *key,
+ char_u *salt,
+ int salt_len,
+ char_u *seed,
+ int seed_len)
+{
+ cryptstate_T *state = (cryptstate_T *)alloc((int)sizeof(cryptstate_T));
+
+ state->method_nr = method_nr;
+ cryptmethods[method_nr].init_fn(state, key, salt, salt_len, seed, seed_len);
+ return state;
+}
+
+/*
+ * Allocate a crypt state from a file header and initialize it.
+ * Assumes that header contains at least the number of bytes that
+ * crypt_get_header_len() returns for "method_nr".
+ */
+ cryptstate_T *
+crypt_create_from_header(
+ int method_nr,
+ char_u *key,
+ char_u *header)
+{
+ char_u *salt = NULL;
+ char_u *seed = NULL;
+ int salt_len = cryptmethods[method_nr].salt_len;
+ int seed_len = cryptmethods[method_nr].seed_len;
+
+ if (salt_len > 0)
+ salt = header + CRYPT_MAGIC_LEN;
+ if (seed_len > 0)
+ seed = header + CRYPT_MAGIC_LEN + salt_len;
+
+ return crypt_create(method_nr, key, salt, salt_len, seed, seed_len);
+}
+
+/*
+ * Read the crypt method specific header data from "fp".
+ * Return an allocated cryptstate_T or NULL on error.
+ */
+ cryptstate_T *
+crypt_create_from_file(FILE *fp, char_u *key)
+{
+ int method_nr;
+ int header_len;
+ char magic_buffer[CRYPT_MAGIC_LEN];
+ char_u *buffer;
+ cryptstate_T *state;
+
+ if (fread(magic_buffer, CRYPT_MAGIC_LEN, 1, fp) != 1)
+ return NULL;
+ method_nr = crypt_method_nr_from_magic(magic_buffer, CRYPT_MAGIC_LEN);
+ if (method_nr < 0)
+ return NULL;
+
+ header_len = crypt_get_header_len(method_nr);
+ if ((buffer = alloc(header_len)) == NULL)
+ return NULL;
+ mch_memmove(buffer, magic_buffer, CRYPT_MAGIC_LEN);
+ if (header_len > CRYPT_MAGIC_LEN
+ && fread(buffer + CRYPT_MAGIC_LEN,
+ header_len - CRYPT_MAGIC_LEN, 1, fp) != 1)
+ {
+ vim_free(buffer);
+ return NULL;
+ }
+
+ state = crypt_create_from_header(method_nr, key, buffer);
+ vim_free(buffer);
+ return state;
+}
+
+/*
+ * Allocate a cryptstate_T for writing and initialize it with "key".
+ * Allocates and fills in the header and stores it in "header", setting
+ * "header_len". The header may include salt and seed, depending on
+ * cryptmethod. Caller must free header.
+ * Returns the state or NULL on failure.
+ */
+ cryptstate_T *
+crypt_create_for_writing(
+ int method_nr,
+ char_u *key,
+ char_u **header,
+ int *header_len)
+{
+ int len = crypt_get_header_len(method_nr);
+ char_u *salt = NULL;
+ char_u *seed = NULL;
+ int salt_len = cryptmethods[method_nr].salt_len;
+ int seed_len = cryptmethods[method_nr].seed_len;
+ cryptstate_T *state;
+
+ *header_len = len;
+ *header = alloc(len);
+ if (*header == NULL)
+ return NULL;
+
+ mch_memmove(*header, cryptmethods[method_nr].magic, CRYPT_MAGIC_LEN);
+ if (salt_len > 0 || seed_len > 0)
+ {
+ if (salt_len > 0)
+ salt = *header + CRYPT_MAGIC_LEN;
+ if (seed_len > 0)
+ seed = *header + CRYPT_MAGIC_LEN + salt_len;
+
+ /* TODO: Should this be crypt method specific? (Probably not worth
+ * it). sha2_seed is pretty bad for large amounts of entropy, so make
+ * that into something which is suitable for anything. */
+ sha2_seed(salt, salt_len, seed, seed_len);
+ }
+
+ state = crypt_create(method_nr, key, salt, salt_len, seed, seed_len);
+ if (state == NULL)
+ VIM_CLEAR(*header);
+ return state;
+}
+
+/*
+ * Free the crypt state.
+ */
+ void
+crypt_free_state(cryptstate_T *state)
+{
+ vim_free(state->method_state);
+ vim_free(state);
+}
+
+#ifdef CRYPT_NOT_INPLACE
+/*
+ * Encode "from[len]" and store the result in a newly allocated buffer, which
+ * is stored in "newptr".
+ * Return number of bytes in "newptr", 0 for need more or -1 on error.
+ */
+ long
+crypt_encode_alloc(
+ cryptstate_T *state,
+ char_u *from,
+ size_t len,
+ char_u **newptr)
+{
+ cryptmethod_T *method = &cryptmethods[state->method_nr];
+
+ if (method->encode_buffer_fn != NULL)
+ /* Has buffer function, pass through. */
+ return method->encode_buffer_fn(state, from, len, newptr);
+ if (len == 0)
+ /* Not buffering, just return EOF. */
+ return (long)len;
+
+ *newptr = alloc((long)len);
+ if (*newptr == NULL)
+ return -1;
+ method->encode_fn(state, from, len, *newptr);
+ return (long)len;
+}
+
+/*
+ * Decrypt "ptr[len]" and store the result in a newly allocated buffer, which
+ * is stored in "newptr".
+ * Return number of bytes in "newptr", 0 for need more or -1 on error.
+ */
+ long
+crypt_decode_alloc(
+ cryptstate_T *state,
+ char_u *ptr,
+ long len,
+ char_u **newptr)
+{
+ cryptmethod_T *method = &cryptmethods[state->method_nr];
+
+ if (method->decode_buffer_fn != NULL)
+ /* Has buffer function, pass through. */
+ return method->decode_buffer_fn(state, ptr, len, newptr);
+
+ if (len == 0)
+ /* Not buffering, just return EOF. */
+ return len;
+
+ *newptr = alloc(len);
+ if (*newptr == NULL)
+ return -1;
+ method->decode_fn(state, ptr, len, *newptr);
+ return len;
+}
+#endif
+
+/*
+ * Encrypting "from[len]" into "to[len]".
+ */
+ void
+crypt_encode(
+ cryptstate_T *state,
+ char_u *from,
+ size_t len,
+ char_u *to)
+{
+ cryptmethods[state->method_nr].encode_fn(state, from, len, to);
+}
+
+#if 0 // unused
+/*
+ * decrypting "from[len]" into "to[len]".
+ */
+ void
+crypt_decode(
+ cryptstate_T *state,
+ char_u *from,
+ size_t len,
+ char_u *to)
+{
+ cryptmethods[state->method_nr].decode_fn(state, from, len, to);
+}
+#endif
+
+/*
+ * Simple inplace encryption, modifies "buf[len]" in place.
+ */
+ void
+crypt_encode_inplace(
+ cryptstate_T *state,
+ char_u *buf,
+ size_t len)
+{
+ cryptmethods[state->method_nr].encode_inplace_fn(state, buf, len, buf);
+}
+
+/*
+ * Simple inplace decryption, modifies "buf[len]" in place.
+ */
+ void
+crypt_decode_inplace(
+ cryptstate_T *state,
+ char_u *buf,
+ size_t len)
+{
+ cryptmethods[state->method_nr].decode_inplace_fn(state, buf, len, buf);
+}
+
+/*
+ * Free an allocated crypt key. Clear the text to make sure it doesn't stay
+ * in memory anywhere.
+ */
+ void
+crypt_free_key(char_u *key)
+{
+ char_u *p;
+
+ if (key != NULL)
+ {
+ for (p = key; *p != NUL; ++p)
+ *p = 0;
+ vim_free(key);
+ }
+}
+
+/*
+ * Check the crypt method and give a warning if it's outdated.
+ */
+ void
+crypt_check_method(int method)
+{
+ if (method < CRYPT_M_BF2)
+ {
+ msg_scroll = TRUE;
+ msg(_("Warning: Using a weak encryption method; see :help 'cm'"));
+ }
+}
+
+ void
+crypt_check_current_method(void)
+{
+ crypt_check_method(crypt_get_method_nr(curbuf));
+}
+
+/*
+ * Ask the user for a crypt key.
+ * When "store" is TRUE, the new key is stored in the 'key' option, and the
+ * 'key' option value is returned: Don't free it.
+ * When "store" is FALSE, the typed key is returned in allocated memory.
+ * Returns NULL on failure.
+ */
+ char_u *
+crypt_get_key(
+ int store,
+ int twice) /* Ask for the key twice. */
+{
+ char_u *p1, *p2 = NULL;
+ int round;
+
+ for (round = 0; ; ++round)
+ {
+ cmdline_star = TRUE;
+ cmdline_row = msg_row;
+ p1 = getcmdline_prompt(NUL, round == 0
+ ? (char_u *)_("Enter encryption key: ")
+ : (char_u *)_("Enter same key again: "), 0, EXPAND_NOTHING,
+ NULL);
+ cmdline_star = FALSE;
+
+ if (p1 == NULL)
+ break;
+
+ if (round == twice)
+ {
+ if (p2 != NULL && STRCMP(p1, p2) != 0)
+ {
+ msg(_("Keys don't match!"));
+ crypt_free_key(p1);
+ crypt_free_key(p2);
+ p2 = NULL;
+ round = -1; /* do it again */
+ continue;
+ }
+
+ if (store)
+ {
+ set_option_value((char_u *)"key", 0L, p1, OPT_LOCAL);
+ crypt_free_key(p1);
+ p1 = curbuf->b_p_key;
+ }
+ break;
+ }
+ p2 = p1;
+ }
+
+ /* since the user typed this, no need to wait for return */
+ if (msg_didout)
+ msg_putchar('\n');
+ need_wait_return = FALSE;
+ msg_didout = FALSE;
+
+ crypt_free_key(p2);
+ return p1;
+}
+
+
+/*
+ * Append a message to IObuff for the encryption/decryption method being used.
+ */
+ void
+crypt_append_msg(
+ buf_T *buf)
+{
+ if (crypt_get_method_nr(buf) == 0)
+ STRCAT(IObuff, _("[crypted]"));
+ else
+ {
+ STRCAT(IObuff, "[");
+ STRCAT(IObuff, *buf->b_p_cm == NUL ? p_cm : buf->b_p_cm);
+ STRCAT(IObuff, "]");
+ }
+}
+
+#endif /* FEAT_CRYPT */
diff --git a/src/crypt_zip.c b/src/crypt_zip.c
new file mode 100644
index 0000000..ed17d95
--- /dev/null
+++ b/src/crypt_zip.c
@@ -0,0 +1,152 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * crypt_zip.c: Zip encryption support.
+ */
+#include "vim.h"
+
+#if defined(FEAT_CRYPT) || defined(PROTO)
+/*
+ * Optional encryption support.
+ * Mohsin Ahmed, mosh@sasi.com, 98-09-24
+ * Based on zip/crypt sources.
+ *
+ * NOTE FOR USA: Since 2000 exporting this code from the USA is allowed to
+ * most countries. There are a few exceptions, but that still should not be a
+ * problem since this code was originally created in Europe and India.
+ */
+
+/* Need a type that should be 32 bits. 64 also works but wastes space. */
+typedef unsigned int u32_T; /* int is at least 32 bits */
+
+/* The state of encryption, referenced by cryptstate_T. */
+typedef struct {
+ u32_T keys[3];
+} zip_state_T;
+
+
+static u32_T crc_32_table[256];
+
+/*
+ * Fill the CRC table, if not done already.
+ */
+ static void
+make_crc_tab(void)
+{
+ u32_T s, t, v;
+ static int done = FALSE;
+
+ if (done)
+ return;
+ for (t = 0; t < 256; t++)
+ {
+ v = t;
+ for (s = 0; s < 8; s++)
+ v = (v >> 1) ^ ((v & 1) * (u32_T)0xedb88320L);
+ crc_32_table[t] = v;
+ }
+ done = TRUE;
+}
+
+#define CRC32(c, b) (crc_32_table[((int)(c) ^ (b)) & 0xff] ^ ((c) >> 8))
+
+/*
+ * Return the next byte in the pseudo-random sequence.
+ */
+#define DECRYPT_BYTE_ZIP(keys, t) { \
+ short_u temp = (short_u)keys[2] | 2; \
+ t = (int)(((unsigned)(temp * (temp ^ 1U)) >> 8) & 0xff); \
+}
+
+/*
+ * Update the encryption keys with the next byte of plain text.
+ */
+#define UPDATE_KEYS_ZIP(keys, c) { \
+ keys[0] = CRC32(keys[0], (c)); \
+ keys[1] += keys[0] & 0xff; \
+ keys[1] = keys[1] * 134775813L + 1; \
+ keys[2] = CRC32(keys[2], (int)(keys[1] >> 24)); \
+}
+
+/*
+ * Initialize for encryption/decryption.
+ */
+ void
+crypt_zip_init(
+ cryptstate_T *state,
+ char_u *key,
+ char_u *salt UNUSED,
+ int salt_len UNUSED,
+ char_u *seed UNUSED,
+ int seed_len UNUSED)
+{
+ char_u *p;
+ zip_state_T *zs;
+
+ zs = (zip_state_T *)alloc(sizeof(zip_state_T));
+ state->method_state = zs;
+
+ make_crc_tab();
+ zs->keys[0] = 305419896L;
+ zs->keys[1] = 591751049L;
+ zs->keys[2] = 878082192L;
+ for (p = key; *p != NUL; ++p)
+ {
+ UPDATE_KEYS_ZIP(zs->keys, (int)*p);
+ }
+}
+
+/*
+ * Encrypt "from[len]" into "to[len]".
+ * "from" and "to" can be equal to encrypt in place.
+ */
+ void
+crypt_zip_encode(
+ cryptstate_T *state,
+ char_u *from,
+ size_t len,
+ char_u *to)
+{
+ zip_state_T *zs = state->method_state;
+ size_t i;
+ int ztemp, t;
+
+ for (i = 0; i < len; ++i)
+ {
+ ztemp = from[i];
+ DECRYPT_BYTE_ZIP(zs->keys, t);
+ UPDATE_KEYS_ZIP(zs->keys, ztemp);
+ to[i] = t ^ ztemp;
+ }
+}
+
+/*
+ * Decrypt "from[len]" into "to[len]".
+ */
+ void
+crypt_zip_decode(
+ cryptstate_T *state,
+ char_u *from,
+ size_t len,
+ char_u *to)
+{
+ zip_state_T *zs = state->method_state;
+ size_t i;
+ short_u temp;
+
+ for (i = 0; i < len; ++i)
+ {
+ temp = (short_u)zs->keys[2] | 2;
+ temp = (int)(((unsigned)(temp * (temp ^ 1U)) >> 8) & 0xff);
+ UPDATE_KEYS_ZIP(zs->keys, to[i] = from[i] ^ temp);
+ }
+}
+
+#endif /* FEAT_CRYPT */
diff --git a/src/dehqx.py b/src/dehqx.py
new file mode 100644
index 0000000..00e8f9f
--- /dev/null
+++ b/src/dehqx.py
@@ -0,0 +1,45 @@
+# Python script to get both the data and resource fork from a BinHex encoded
+# file.
+# Author: MURAOKA Taro <koron.kaoriya@gmail.com>
+# Last Change: 2018 Mar 27
+#
+# Copyright (C) 2003,12 MURAOKA Taro <koron.kaoriya@gmail.com>
+# THIS FILE IS DISTRIBUTED UNDER THE VIM LICENSE.
+
+import sys
+import binhex
+
+input = sys.argv[1]
+conv = binhex.HexBin(input)
+info = conv.FInfo
+out = conv.FName
+out_data = out
+out_rsrc = out + '.rsrcfork'
+
+# This uses the print statement on Python 2, print function on Python 3.
+#print('out_rsrc=' + out_rsrc)
+print('In file: ' + input)
+
+outfile = open(out_data, 'wb')
+print(' Out data fork: ' + out_data)
+while 1:
+ d = conv.read(128000)
+ if not d: break
+ outfile.write(d)
+outfile.close()
+conv.close_data()
+
+d = conv.read_rsrc(128000)
+if d:
+ print(' Out rsrc fork: ' + out_rsrc)
+ outfile = open(out_rsrc, 'wb')
+ outfile.write(d)
+ while 1:
+ d = conv.read_rsrc(128000)
+ if not d: break
+ outfile.write(d)
+ outfile.close()
+
+conv.close()
+
+# vim:set ts=8 sts=4 sw=4 et:
diff --git a/src/dict.c b/src/dict.c
new file mode 100644
index 0000000..91c6e55
--- /dev/null
+++ b/src/dict.c
@@ -0,0 +1,920 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * dict.c: Dictionary support
+ */
+
+#include "vim.h"
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+
+/* List head for garbage collection. Although there can be a reference loop
+ * from partial to dict to partial, we don't need to keep track of the partial,
+ * since it will get freed when the dict is unused and gets freed. */
+static dict_T *first_dict = NULL; /* list of all dicts */
+
+/*
+ * Allocate an empty header for a dictionary.
+ */
+ dict_T *
+dict_alloc(void)
+{
+ dict_T *d;
+
+ d = (dict_T *)alloc(sizeof(dict_T));
+ if (d != NULL)
+ {
+ /* Add the dict to the list of dicts for garbage collection. */
+ if (first_dict != NULL)
+ first_dict->dv_used_prev = d;
+ d->dv_used_next = first_dict;
+ d->dv_used_prev = NULL;
+ first_dict = d;
+
+ hash_init(&d->dv_hashtab);
+ d->dv_lock = 0;
+ d->dv_scope = 0;
+ d->dv_refcount = 0;
+ d->dv_copyID = 0;
+ }
+ return d;
+}
+
+/*
+ * dict_alloc() with an ID for alloc_fail().
+ */
+ dict_T *
+dict_alloc_id(alloc_id_T id UNUSED)
+{
+#ifdef FEAT_EVAL
+ if (alloc_fail_id == id && alloc_does_fail((long_u)sizeof(list_T)))
+ return NULL;
+#endif
+ return (dict_alloc());
+}
+
+ dict_T *
+dict_alloc_lock(int lock)
+{
+ dict_T *d = dict_alloc();
+
+ if (d != NULL)
+ d->dv_lock = lock;
+ return d;
+}
+
+/*
+ * Allocate an empty dict for a return value.
+ * Returns OK or FAIL.
+ */
+ int
+rettv_dict_alloc(typval_T *rettv)
+{
+ dict_T *d = dict_alloc_lock(0);
+
+ if (d == NULL)
+ return FAIL;
+
+ rettv_dict_set(rettv, d);
+ return OK;
+}
+
+/*
+ * Set a dictionary as the return value
+ */
+ void
+rettv_dict_set(typval_T *rettv, dict_T *d)
+{
+ rettv->v_type = VAR_DICT;
+ rettv->vval.v_dict = d;
+ if (d != NULL)
+ ++d->dv_refcount;
+}
+
+/*
+ * Free a Dictionary, including all non-container items it contains.
+ * Ignores the reference count.
+ */
+ void
+dict_free_contents(dict_T *d)
+{
+ int todo;
+ hashitem_T *hi;
+ dictitem_T *di;
+
+ /* Lock the hashtab, we don't want it to resize while freeing items. */
+ hash_lock(&d->dv_hashtab);
+ todo = (int)d->dv_hashtab.ht_used;
+ for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
+ {
+ if (!HASHITEM_EMPTY(hi))
+ {
+ /* Remove the item before deleting it, just in case there is
+ * something recursive causing trouble. */
+ di = HI2DI(hi);
+ hash_remove(&d->dv_hashtab, hi);
+ dictitem_free(di);
+ --todo;
+ }
+ }
+
+ /* The hashtab is still locked, it has to be re-initialized anyway */
+ hash_clear(&d->dv_hashtab);
+}
+
+ static void
+dict_free_dict(dict_T *d)
+{
+ /* Remove the dict from the list of dicts for garbage collection. */
+ if (d->dv_used_prev == NULL)
+ first_dict = d->dv_used_next;
+ else
+ d->dv_used_prev->dv_used_next = d->dv_used_next;
+ if (d->dv_used_next != NULL)
+ d->dv_used_next->dv_used_prev = d->dv_used_prev;
+ vim_free(d);
+}
+
+ static void
+dict_free(dict_T *d)
+{
+ if (!in_free_unref_items)
+ {
+ dict_free_contents(d);
+ dict_free_dict(d);
+ }
+}
+
+/*
+ * Unreference a Dictionary: decrement the reference count and free it when it
+ * becomes zero.
+ */
+ void
+dict_unref(dict_T *d)
+{
+ if (d != NULL && --d->dv_refcount <= 0)
+ dict_free(d);
+}
+
+/*
+ * Go through the list of dicts and free items without the copyID.
+ * Returns TRUE if something was freed.
+ */
+ int
+dict_free_nonref(int copyID)
+{
+ dict_T *dd;
+ int did_free = FALSE;
+
+ for (dd = first_dict; dd != NULL; dd = dd->dv_used_next)
+ if ((dd->dv_copyID & COPYID_MASK) != (copyID & COPYID_MASK))
+ {
+ /* Free the Dictionary and ordinary items it contains, but don't
+ * recurse into Lists and Dictionaries, they will be in the list
+ * of dicts or list of lists. */
+ dict_free_contents(dd);
+ did_free = TRUE;
+ }
+ return did_free;
+}
+
+ void
+dict_free_items(int copyID)
+{
+ dict_T *dd, *dd_next;
+
+ for (dd = first_dict; dd != NULL; dd = dd_next)
+ {
+ dd_next = dd->dv_used_next;
+ if ((dd->dv_copyID & COPYID_MASK) != (copyID & COPYID_MASK))
+ dict_free_dict(dd);
+ }
+}
+
+/*
+ * Allocate a Dictionary item.
+ * The "key" is copied to the new item.
+ * Note that the type and value of the item "di_tv" still needs to be
+ * initialized!
+ * Returns NULL when out of memory.
+ */
+ dictitem_T *
+dictitem_alloc(char_u *key)
+{
+ dictitem_T *di;
+
+ di = (dictitem_T *)alloc((unsigned)(sizeof(dictitem_T) + STRLEN(key)));
+ if (di != NULL)
+ {
+ STRCPY(di->di_key, key);
+ di->di_flags = DI_FLAGS_ALLOC;
+ di->di_tv.v_lock = 0;
+ }
+ return di;
+}
+
+/*
+ * Make a copy of a Dictionary item.
+ */
+ static dictitem_T *
+dictitem_copy(dictitem_T *org)
+{
+ dictitem_T *di;
+
+ di = (dictitem_T *)alloc((unsigned)(sizeof(dictitem_T)
+ + STRLEN(org->di_key)));
+ if (di != NULL)
+ {
+ STRCPY(di->di_key, org->di_key);
+ di->di_flags = DI_FLAGS_ALLOC;
+ copy_tv(&org->di_tv, &di->di_tv);
+ }
+ return di;
+}
+
+/*
+ * Remove item "item" from Dictionary "dict" and free it.
+ */
+ void
+dictitem_remove(dict_T *dict, dictitem_T *item)
+{
+ hashitem_T *hi;
+
+ hi = hash_find(&dict->dv_hashtab, item->di_key);
+ if (HASHITEM_EMPTY(hi))
+ internal_error("dictitem_remove()");
+ else
+ hash_remove(&dict->dv_hashtab, hi);
+ dictitem_free(item);
+}
+
+/*
+ * Free a dict item. Also clears the value.
+ */
+ void
+dictitem_free(dictitem_T *item)
+{
+ clear_tv(&item->di_tv);
+ if (item->di_flags & DI_FLAGS_ALLOC)
+ vim_free(item);
+}
+
+/*
+ * Make a copy of dict "d". Shallow if "deep" is FALSE.
+ * The refcount of the new dict is set to 1.
+ * See item_copy() for "copyID".
+ * Returns NULL when out of memory.
+ */
+ dict_T *
+dict_copy(dict_T *orig, int deep, int copyID)
+{
+ dict_T *copy;
+ dictitem_T *di;
+ int todo;
+ hashitem_T *hi;
+
+ if (orig == NULL)
+ return NULL;
+
+ copy = dict_alloc();
+ if (copy != NULL)
+ {
+ if (copyID != 0)
+ {
+ orig->dv_copyID = copyID;
+ orig->dv_copydict = copy;
+ }
+ todo = (int)orig->dv_hashtab.ht_used;
+ for (hi = orig->dv_hashtab.ht_array; todo > 0 && !got_int; ++hi)
+ {
+ if (!HASHITEM_EMPTY(hi))
+ {
+ --todo;
+
+ di = dictitem_alloc(hi->hi_key);
+ if (di == NULL)
+ break;
+ if (deep)
+ {
+ if (item_copy(&HI2DI(hi)->di_tv, &di->di_tv, deep,
+ copyID) == FAIL)
+ {
+ vim_free(di);
+ break;
+ }
+ }
+ else
+ copy_tv(&HI2DI(hi)->di_tv, &di->di_tv);
+ if (dict_add(copy, di) == FAIL)
+ {
+ dictitem_free(di);
+ break;
+ }
+ }
+ }
+
+ ++copy->dv_refcount;
+ if (todo > 0)
+ {
+ dict_unref(copy);
+ copy = NULL;
+ }
+ }
+
+ return copy;
+}
+
+/*
+ * Add item "item" to Dictionary "d".
+ * Returns FAIL when out of memory and when key already exists.
+ */
+ int
+dict_add(dict_T *d, dictitem_T *item)
+{
+ return hash_add(&d->dv_hashtab, item->di_key);
+}
+
+/*
+ * Add a number entry to dictionary "d".
+ * Returns FAIL when out of memory and when key already exists.
+ */
+ int
+dict_add_number(dict_T *d, char *key, varnumber_T nr)
+{
+ dictitem_T *item;
+
+ item = dictitem_alloc((char_u *)key);
+ if (item == NULL)
+ return FAIL;
+ item->di_tv.v_type = VAR_NUMBER;
+ item->di_tv.vval.v_number = nr;
+ if (dict_add(d, item) == FAIL)
+ {
+ dictitem_free(item);
+ return FAIL;
+ }
+ return OK;
+}
+
+/*
+ * Add a string entry to dictionary "d".
+ * Returns FAIL when out of memory and when key already exists.
+ */
+ int
+dict_add_string(dict_T *d, char *key, char_u *str)
+{
+ return dict_add_string_len(d, key, str, -1);
+}
+
+/*
+ * Add a string entry to dictionary "d".
+ * "str" will be copied to allocated memory.
+ * When "len" is -1 use the whole string, otherwise only this many bytes.
+ * Returns FAIL when out of memory and when key already exists.
+ */
+ int
+dict_add_string_len(dict_T *d, char *key, char_u *str, int len)
+{
+ dictitem_T *item;
+ char_u *val = NULL;
+
+ item = dictitem_alloc((char_u *)key);
+ if (item == NULL)
+ return FAIL;
+ item->di_tv.v_type = VAR_STRING;
+ if (str != NULL)
+ {
+ if (len == -1)
+ val = vim_strsave(str);
+ else
+ val = vim_strnsave(str, len);
+ }
+ item->di_tv.vval.v_string = val;
+ if (dict_add(d, item) == FAIL)
+ {
+ dictitem_free(item);
+ return FAIL;
+ }
+ return OK;
+}
+
+/*
+ * Add a list entry to dictionary "d".
+ * Returns FAIL when out of memory and when key already exists.
+ */
+ int
+dict_add_list(dict_T *d, char *key, list_T *list)
+{
+ dictitem_T *item;
+
+ item = dictitem_alloc((char_u *)key);
+ if (item == NULL)
+ return FAIL;
+ item->di_tv.v_type = VAR_LIST;
+ item->di_tv.vval.v_list = list;
+ ++list->lv_refcount;
+ if (dict_add(d, item) == FAIL)
+ {
+ dictitem_free(item);
+ return FAIL;
+ }
+ return OK;
+}
+
+/*
+ * Add a dict entry to dictionary "d".
+ * Returns FAIL when out of memory and when key already exists.
+ */
+ int
+dict_add_dict(dict_T *d, char *key, dict_T *dict)
+{
+ dictitem_T *item;
+
+ item = dictitem_alloc((char_u *)key);
+ if (item == NULL)
+ return FAIL;
+ item->di_tv.v_type = VAR_DICT;
+ item->di_tv.vval.v_dict = dict;
+ ++dict->dv_refcount;
+ if (dict_add(d, item) == FAIL)
+ {
+ dictitem_free(item);
+ return FAIL;
+ }
+ return OK;
+}
+
+/*
+ * Get the number of items in a Dictionary.
+ */
+ long
+dict_len(dict_T *d)
+{
+ if (d == NULL)
+ return 0L;
+ return (long)d->dv_hashtab.ht_used;
+}
+
+/*
+ * Find item "key[len]" in Dictionary "d".
+ * If "len" is negative use strlen(key).
+ * Returns NULL when not found.
+ */
+ dictitem_T *
+dict_find(dict_T *d, char_u *key, int len)
+{
+#define AKEYLEN 200
+ char_u buf[AKEYLEN];
+ char_u *akey;
+ char_u *tofree = NULL;
+ hashitem_T *hi;
+
+ if (d == NULL)
+ return NULL;
+ if (len < 0)
+ akey = key;
+ else if (len >= AKEYLEN)
+ {
+ tofree = akey = vim_strnsave(key, len);
+ if (akey == NULL)
+ return NULL;
+ }
+ else
+ {
+ /* Avoid a malloc/free by using buf[]. */
+ vim_strncpy(buf, key, len);
+ akey = buf;
+ }
+
+ hi = hash_find(&d->dv_hashtab, akey);
+ vim_free(tofree);
+ if (HASHITEM_EMPTY(hi))
+ return NULL;
+ return HI2DI(hi);
+}
+
+/*
+ * Get a string item from a dictionary.
+ * When "save" is TRUE allocate memory for it.
+ * When FALSE a shared buffer is used, can only be used once!
+ * Returns NULL if the entry doesn't exist or out of memory.
+ */
+ char_u *
+dict_get_string(dict_T *d, char_u *key, int save)
+{
+ dictitem_T *di;
+ char_u *s;
+
+ di = dict_find(d, key, -1);
+ if (di == NULL)
+ return NULL;
+ s = tv_get_string(&di->di_tv);
+ if (save && s != NULL)
+ s = vim_strsave(s);
+ return s;
+}
+
+/*
+ * Get a number item from a dictionary.
+ * Returns 0 if the entry doesn't exist.
+ */
+ varnumber_T
+dict_get_number(dict_T *d, char_u *key)
+{
+ dictitem_T *di;
+
+ di = dict_find(d, key, -1);
+ if (di == NULL)
+ return 0;
+ return tv_get_number(&di->di_tv);
+}
+
+/*
+ * Return an allocated string with the string representation of a Dictionary.
+ * May return NULL.
+ */
+ char_u *
+dict2string(typval_T *tv, int copyID, int restore_copyID)
+{
+ garray_T ga;
+ int first = TRUE;
+ char_u *tofree;
+ char_u numbuf[NUMBUFLEN];
+ hashitem_T *hi;
+ char_u *s;
+ dict_T *d;
+ int todo;
+
+ if ((d = tv->vval.v_dict) == NULL)
+ return NULL;
+ ga_init2(&ga, (int)sizeof(char), 80);
+ ga_append(&ga, '{');
+
+ todo = (int)d->dv_hashtab.ht_used;
+ for (hi = d->dv_hashtab.ht_array; todo > 0 && !got_int; ++hi)
+ {
+ if (!HASHITEM_EMPTY(hi))
+ {
+ --todo;
+
+ if (first)
+ first = FALSE;
+ else
+ ga_concat(&ga, (char_u *)", ");
+
+ tofree = string_quote(hi->hi_key, FALSE);
+ if (tofree != NULL)
+ {
+ ga_concat(&ga, tofree);
+ vim_free(tofree);
+ }
+ ga_concat(&ga, (char_u *)": ");
+ s = echo_string_core(&HI2DI(hi)->di_tv, &tofree, numbuf, copyID,
+ FALSE, restore_copyID, TRUE);
+ if (s != NULL)
+ ga_concat(&ga, s);
+ vim_free(tofree);
+ if (s == NULL || did_echo_string_emsg)
+ break;
+ line_breakcheck();
+
+ }
+ }
+ if (todo > 0)
+ {
+ vim_free(ga.ga_data);
+ return NULL;
+ }
+
+ ga_append(&ga, '}');
+ ga_append(&ga, NUL);
+ return (char_u *)ga.ga_data;
+}
+
+/*
+ * Allocate a variable for a Dictionary and fill it from "*arg".
+ * Return OK or FAIL. Returns NOTDONE for {expr}.
+ */
+ int
+dict_get_tv(char_u **arg, typval_T *rettv, int evaluate)
+{
+ dict_T *d = NULL;
+ typval_T tvkey;
+ typval_T tv;
+ char_u *key = NULL;
+ dictitem_T *item;
+ char_u *start = skipwhite(*arg + 1);
+ char_u buf[NUMBUFLEN];
+
+ /*
+ * First check if it's not a curly-braces thing: {expr}.
+ * Must do this without evaluating, otherwise a function may be called
+ * twice. Unfortunately this means we need to call eval1() twice for the
+ * first item.
+ * But {} is an empty Dictionary.
+ */
+ if (*start != '}')
+ {
+ if (eval1(&start, &tv, FALSE) == FAIL) /* recursive! */
+ return FAIL;
+ if (*start == '}')
+ return NOTDONE;
+ }
+
+ if (evaluate)
+ {
+ d = dict_alloc();
+ if (d == NULL)
+ return FAIL;
+ }
+ tvkey.v_type = VAR_UNKNOWN;
+ tv.v_type = VAR_UNKNOWN;
+
+ *arg = skipwhite(*arg + 1);
+ while (**arg != '}' && **arg != NUL)
+ {
+ if (eval1(arg, &tvkey, evaluate) == FAIL) /* recursive! */
+ goto failret;
+ if (**arg != ':')
+ {
+ semsg(_("E720: Missing colon in Dictionary: %s"), *arg);
+ clear_tv(&tvkey);
+ goto failret;
+ }
+ if (evaluate)
+ {
+ key = tv_get_string_buf_chk(&tvkey, buf);
+ if (key == NULL)
+ {
+ /* "key" is NULL when tv_get_string_buf_chk() gave an errmsg */
+ clear_tv(&tvkey);
+ goto failret;
+ }
+ }
+
+ *arg = skipwhite(*arg + 1);
+ if (eval1(arg, &tv, evaluate) == FAIL) /* recursive! */
+ {
+ if (evaluate)
+ clear_tv(&tvkey);
+ goto failret;
+ }
+ if (evaluate)
+ {
+ item = dict_find(d, key, -1);
+ if (item != NULL)
+ {
+ semsg(_("E721: Duplicate key in Dictionary: \"%s\""), key);
+ clear_tv(&tvkey);
+ clear_tv(&tv);
+ goto failret;
+ }
+ item = dictitem_alloc(key);
+ clear_tv(&tvkey);
+ if (item != NULL)
+ {
+ item->di_tv = tv;
+ item->di_tv.v_lock = 0;
+ if (dict_add(d, item) == FAIL)
+ dictitem_free(item);
+ }
+ }
+
+ if (**arg == '}')
+ break;
+ if (**arg != ',')
+ {
+ semsg(_("E722: Missing comma in Dictionary: %s"), *arg);
+ goto failret;
+ }
+ *arg = skipwhite(*arg + 1);
+ }
+
+ if (**arg != '}')
+ {
+ semsg(_("E723: Missing end of Dictionary '}': %s"), *arg);
+failret:
+ if (evaluate)
+ dict_free(d);
+ return FAIL;
+ }
+
+ *arg = skipwhite(*arg + 1);
+ if (evaluate)
+ rettv_dict_set(rettv, d);
+
+ return OK;
+}
+
+/*
+ * Go over all entries in "d2" and add them to "d1".
+ * When "action" is "error" then a duplicate key is an error.
+ * When "action" is "force" then a duplicate key is overwritten.
+ * Otherwise duplicate keys are ignored ("action" is "keep").
+ */
+ void
+dict_extend(dict_T *d1, dict_T *d2, char_u *action)
+{
+ dictitem_T *di1;
+ hashitem_T *hi2;
+ int todo;
+ char_u *arg_errmsg = (char_u *)N_("extend() argument");
+
+ todo = (int)d2->dv_hashtab.ht_used;
+ for (hi2 = d2->dv_hashtab.ht_array; todo > 0; ++hi2)
+ {
+ if (!HASHITEM_EMPTY(hi2))
+ {
+ --todo;
+ di1 = dict_find(d1, hi2->hi_key, -1);
+ if (d1->dv_scope != 0)
+ {
+ /* Disallow replacing a builtin function in l: and g:.
+ * Check the key to be valid when adding to any scope. */
+ if (d1->dv_scope == VAR_DEF_SCOPE
+ && HI2DI(hi2)->di_tv.v_type == VAR_FUNC
+ && var_check_func_name(hi2->hi_key, di1 == NULL))
+ break;
+ if (!valid_varname(hi2->hi_key))
+ break;
+ }
+ if (di1 == NULL)
+ {
+ di1 = dictitem_copy(HI2DI(hi2));
+ if (di1 != NULL && dict_add(d1, di1) == FAIL)
+ dictitem_free(di1);
+ }
+ else if (*action == 'e')
+ {
+ semsg(_("E737: Key already exists: %s"), hi2->hi_key);
+ break;
+ }
+ else if (*action == 'f' && HI2DI(hi2) != di1)
+ {
+ if (tv_check_lock(di1->di_tv.v_lock, arg_errmsg, TRUE)
+ || var_check_ro(di1->di_flags, arg_errmsg, TRUE))
+ break;
+ clear_tv(&di1->di_tv);
+ copy_tv(&HI2DI(hi2)->di_tv, &di1->di_tv);
+ }
+ }
+ }
+}
+
+/*
+ * Return the dictitem that an entry in a hashtable points to.
+ */
+ dictitem_T *
+dict_lookup(hashitem_T *hi)
+{
+ return HI2DI(hi);
+}
+
+/*
+ * Return TRUE when two dictionaries have exactly the same key/values.
+ */
+ int
+dict_equal(
+ dict_T *d1,
+ dict_T *d2,
+ int ic, /* ignore case for strings */
+ int recursive) /* TRUE when used recursively */
+{
+ hashitem_T *hi;
+ dictitem_T *item2;
+ int todo;
+
+ if (d1 == NULL && d2 == NULL)
+ return TRUE;
+ if (d1 == NULL || d2 == NULL)
+ return FALSE;
+ if (d1 == d2)
+ return TRUE;
+ if (dict_len(d1) != dict_len(d2))
+ return FALSE;
+
+ todo = (int)d1->dv_hashtab.ht_used;
+ for (hi = d1->dv_hashtab.ht_array; todo > 0; ++hi)
+ {
+ if (!HASHITEM_EMPTY(hi))
+ {
+ item2 = dict_find(d2, hi->hi_key, -1);
+ if (item2 == NULL)
+ return FALSE;
+ if (!tv_equal(&HI2DI(hi)->di_tv, &item2->di_tv, ic, recursive))
+ return FALSE;
+ --todo;
+ }
+ }
+ return TRUE;
+}
+
+/*
+ * Turn a dict into a list:
+ * "what" == 0: list of keys
+ * "what" == 1: list of values
+ * "what" == 2: list of items
+ */
+ void
+dict_list(typval_T *argvars, typval_T *rettv, int what)
+{
+ list_T *l2;
+ dictitem_T *di;
+ hashitem_T *hi;
+ listitem_T *li;
+ listitem_T *li2;
+ dict_T *d;
+ int todo;
+
+ if (argvars[0].v_type != VAR_DICT)
+ {
+ emsg(_(e_dictreq));
+ return;
+ }
+ if ((d = argvars[0].vval.v_dict) == NULL)
+ return;
+
+ if (rettv_list_alloc(rettv) == FAIL)
+ return;
+
+ todo = (int)d->dv_hashtab.ht_used;
+ for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
+ {
+ if (!HASHITEM_EMPTY(hi))
+ {
+ --todo;
+ di = HI2DI(hi);
+
+ li = listitem_alloc();
+ if (li == NULL)
+ break;
+ list_append(rettv->vval.v_list, li);
+
+ if (what == 0)
+ {
+ /* keys() */
+ li->li_tv.v_type = VAR_STRING;
+ li->li_tv.v_lock = 0;
+ li->li_tv.vval.v_string = vim_strsave(di->di_key);
+ }
+ else if (what == 1)
+ {
+ /* values() */
+ copy_tv(&di->di_tv, &li->li_tv);
+ }
+ else
+ {
+ /* items() */
+ l2 = list_alloc();
+ li->li_tv.v_type = VAR_LIST;
+ li->li_tv.v_lock = 0;
+ li->li_tv.vval.v_list = l2;
+ if (l2 == NULL)
+ break;
+ ++l2->lv_refcount;
+
+ li2 = listitem_alloc();
+ if (li2 == NULL)
+ break;
+ list_append(l2, li2);
+ li2->li_tv.v_type = VAR_STRING;
+ li2->li_tv.v_lock = 0;
+ li2->li_tv.vval.v_string = vim_strsave(di->di_key);
+
+ li2 = listitem_alloc();
+ if (li2 == NULL)
+ break;
+ list_append(l2, li2);
+ copy_tv(&di->di_tv, &li2->li_tv);
+ }
+ }
+ }
+}
+
+/*
+ * Make each item in the dict readonly (not the value of the item).
+ */
+ void
+dict_set_items_ro(dict_T *di)
+{
+ int todo = (int)di->dv_hashtab.ht_used;
+ hashitem_T *hi;
+
+ /* Set readonly */
+ for (hi = di->dv_hashtab.ht_array; todo > 0 ; ++hi)
+ {
+ if (HASHITEM_EMPTY(hi))
+ continue;
+ --todo;
+ HI2DI(hi)->di_flags |= DI_FLAGS_RO | DI_FLAGS_FIX;
+ }
+}
+
+#endif /* defined(FEAT_EVAL) */
diff --git a/src/diff.c b/src/diff.c
new file mode 100644
index 0000000..d368f96
--- /dev/null
+++ b/src/diff.c
@@ -0,0 +1,3221 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * diff.c: code for diff'ing two, three or four buffers.
+ *
+ * There are three ways to diff:
+ * - Shell out to an external diff program, using files.
+ * - Use the compiled-in xdiff library.
+ * - Let 'diffexpr' do the work, using files.
+ */
+
+#include "vim.h"
+#include "xdiff/xdiff.h"
+
+#if defined(FEAT_DIFF) || defined(PROTO)
+
+static int diff_busy = FALSE; // using diff structs, don't change them
+static int diff_need_update = FALSE; // ex_diffupdate needs to be called
+
+/* flags obtained from the 'diffopt' option */
+#define DIFF_FILLER 0x001 // display filler lines
+#define DIFF_IBLANK 0x002 // ignore empty lines
+#define DIFF_ICASE 0x004 // ignore case
+#define DIFF_IWHITE 0x008 // ignore change in white space
+#define DIFF_IWHITEALL 0x010 // ignore all white space changes
+#define DIFF_IWHITEEOL 0x020 // ignore change in white space at EOL
+#define DIFF_HORIZONTAL 0x040 // horizontal splits
+#define DIFF_VERTICAL 0x080 // vertical splits
+#define DIFF_HIDDEN_OFF 0x100 // diffoff when hidden
+#define DIFF_INTERNAL 0x200 // use internal xdiff algorithm
+#define ALL_WHITE_DIFF (DIFF_IWHITE | DIFF_IWHITEALL | DIFF_IWHITEEOL)
+static int diff_flags = DIFF_INTERNAL | DIFF_FILLER;
+
+static long diff_algorithm = 0;
+
+#define LBUFLEN 50 /* length of line in diff file */
+
+static int diff_a_works = MAYBE; /* TRUE when "diff -a" works, FALSE when it
+ doesn't work, MAYBE when not checked yet */
+#if defined(MSWIN)
+static int diff_bin_works = MAYBE; /* TRUE when "diff --binary" works, FALSE
+ when it doesn't work, MAYBE when not
+ checked yet */
+#endif
+
+// used for diff input
+typedef struct {
+ char_u *din_fname; // used for external diff
+ mmfile_t din_mmfile; // used for internal diff
+} diffin_T;
+
+// used for diff result
+typedef struct {
+ char_u *dout_fname; // used for external diff
+ garray_T dout_ga; // used for internal diff
+} diffout_T;
+
+// two diff inputs and one result
+typedef struct {
+ diffin_T dio_orig; // original file input
+ diffin_T dio_new; // new file input
+ diffout_T dio_diff; // diff result
+ int dio_internal; // using internal diff
+} diffio_T;
+
+static int diff_buf_idx(buf_T *buf);
+static int diff_buf_idx_tp(buf_T *buf, tabpage_T *tp);
+static void diff_mark_adjust_tp(tabpage_T *tp, int idx, linenr_T line1, linenr_T line2, long amount, long amount_after);
+static void diff_check_unchanged(tabpage_T *tp, diff_T *dp);
+static int diff_check_sanity(tabpage_T *tp, diff_T *dp);
+static void diff_redraw(int dofold);
+static int check_external_diff(diffio_T *diffio);
+static int diff_file(diffio_T *diffio);
+static int diff_equal_entry(diff_T *dp, int idx1, int idx2);
+static int diff_cmp(char_u *s1, char_u *s2);
+#ifdef FEAT_FOLDING
+static void diff_fold_update(diff_T *dp, int skip_idx);
+#endif
+static void diff_read(int idx_orig, int idx_new, diffout_T *fname);
+static void diff_copy_entry(diff_T *dprev, diff_T *dp, int idx_orig, int idx_new);
+static diff_T *diff_alloc_new(tabpage_T *tp, diff_T *dprev, diff_T *dp);
+static int parse_diff_ed(char_u *line, linenr_T *lnum_orig, long *count_orig, linenr_T *lnum_new, long *count_new);
+static int parse_diff_unified(char_u *line, linenr_T *lnum_orig, long *count_orig, linenr_T *lnum_new, long *count_new);
+static int xdiff_out(void *priv, mmbuffer_t *mb, int nbuf);
+
+#ifndef USE_CR
+# define tag_fgets vim_fgets
+#endif
+
+/*
+ * Called when deleting or unloading a buffer: No longer make a diff with it.
+ */
+ void
+diff_buf_delete(buf_T *buf)
+{
+ int i;
+ tabpage_T *tp;
+
+ FOR_ALL_TABPAGES(tp)
+ {
+ i = diff_buf_idx_tp(buf, tp);
+ if (i != DB_COUNT)
+ {
+ tp->tp_diffbuf[i] = NULL;
+ tp->tp_diff_invalid = TRUE;
+ if (tp == curtab)
+ diff_redraw(TRUE);
+ }
+ }
+}
+
+/*
+ * Check if the current buffer should be added to or removed from the list of
+ * diff buffers.
+ */
+ void
+diff_buf_adjust(win_T *win)
+{
+ win_T *wp;
+ int i;
+
+ if (!win->w_p_diff)
+ {
+ /* When there is no window showing a diff for this buffer, remove
+ * it from the diffs. */
+ FOR_ALL_WINDOWS(wp)
+ if (wp->w_buffer == win->w_buffer && wp->w_p_diff)
+ break;
+ if (wp == NULL)
+ {
+ i = diff_buf_idx(win->w_buffer);
+ if (i != DB_COUNT)
+ {
+ curtab->tp_diffbuf[i] = NULL;
+ curtab->tp_diff_invalid = TRUE;
+ diff_redraw(TRUE);
+ }
+ }
+ }
+ else
+ diff_buf_add(win->w_buffer);
+}
+
+/*
+ * Add a buffer to make diffs for.
+ * Call this when a new buffer is being edited in the current window where
+ * 'diff' is set.
+ * Marks the current buffer as being part of the diff and requiring updating.
+ * This must be done before any autocmd, because a command may use info
+ * about the screen contents.
+ */
+ void
+diff_buf_add(buf_T *buf)
+{
+ int i;
+
+ if (diff_buf_idx(buf) != DB_COUNT)
+ return; /* It's already there. */
+
+ for (i = 0; i < DB_COUNT; ++i)
+ if (curtab->tp_diffbuf[i] == NULL)
+ {
+ curtab->tp_diffbuf[i] = buf;
+ curtab->tp_diff_invalid = TRUE;
+ diff_redraw(TRUE);
+ return;
+ }
+
+ semsg(_("E96: Cannot diff more than %d buffers"), DB_COUNT);
+}
+
+/*
+ * Remove all buffers to make diffs for.
+ */
+ static void
+diff_buf_clear(void)
+{
+ int i;
+
+ for (i = 0; i < DB_COUNT; ++i)
+ if (curtab->tp_diffbuf[i] != NULL)
+ {
+ curtab->tp_diffbuf[i] = NULL;
+ curtab->tp_diff_invalid = TRUE;
+ diff_redraw(TRUE);
+ }
+}
+
+/*
+ * Find buffer "buf" in the list of diff buffers for the current tab page.
+ * Return its index or DB_COUNT if not found.
+ */
+ static int
+diff_buf_idx(buf_T *buf)
+{
+ int idx;
+
+ for (idx = 0; idx < DB_COUNT; ++idx)
+ if (curtab->tp_diffbuf[idx] == buf)
+ break;
+ return idx;
+}
+
+/*
+ * Find buffer "buf" in the list of diff buffers for tab page "tp".
+ * Return its index or DB_COUNT if not found.
+ */
+ static int
+diff_buf_idx_tp(buf_T *buf, tabpage_T *tp)
+{
+ int idx;
+
+ for (idx = 0; idx < DB_COUNT; ++idx)
+ if (tp->tp_diffbuf[idx] == buf)
+ break;
+ return idx;
+}
+
+/*
+ * Mark the diff info involving buffer "buf" as invalid, it will be updated
+ * when info is requested.
+ */
+ void
+diff_invalidate(buf_T *buf)
+{
+ tabpage_T *tp;
+ int i;
+
+ FOR_ALL_TABPAGES(tp)
+ {
+ i = diff_buf_idx_tp(buf, tp);
+ if (i != DB_COUNT)
+ {
+ tp->tp_diff_invalid = TRUE;
+ if (tp == curtab)
+ diff_redraw(TRUE);
+ }
+ }
+}
+
+/*
+ * Called by mark_adjust(): update line numbers in "curbuf".
+ */
+ void
+diff_mark_adjust(
+ linenr_T line1,
+ linenr_T line2,
+ long amount,
+ long amount_after)
+{
+ int idx;
+ tabpage_T *tp;
+
+ /* Handle all tab pages that use the current buffer in a diff. */
+ FOR_ALL_TABPAGES(tp)
+ {
+ idx = diff_buf_idx_tp(curbuf, tp);
+ if (idx != DB_COUNT)
+ diff_mark_adjust_tp(tp, idx, line1, line2, amount, amount_after);
+ }
+}
+
+/*
+ * Update line numbers in tab page "tp" for "curbuf" with index "idx".
+ * This attempts to update the changes as much as possible:
+ * When inserting/deleting lines outside of existing change blocks, create a
+ * new change block and update the line numbers in following blocks.
+ * When inserting/deleting lines in existing change blocks, update them.
+ */
+ static void
+diff_mark_adjust_tp(
+ tabpage_T *tp,
+ int idx,
+ linenr_T line1,
+ linenr_T line2,
+ long amount,
+ long amount_after)
+{
+ diff_T *dp;
+ diff_T *dprev;
+ diff_T *dnext;
+ int i;
+ int inserted, deleted;
+ int n, off;
+ linenr_T last;
+ linenr_T lnum_deleted = line1; /* lnum of remaining deletion */
+ int check_unchanged;
+
+ if (diff_internal())
+ {
+ // Will update diffs before redrawing. Set _invalid to update the
+ // diffs themselves, set _update to also update folds properly just
+ // before redrawing.
+ // Do update marks here, it is needed for :%diffput.
+ tp->tp_diff_invalid = TRUE;
+ tp->tp_diff_update = TRUE;
+ }
+
+ if (line2 == MAXLNUM)
+ {
+ /* mark_adjust(99, MAXLNUM, 9, 0): insert lines */
+ inserted = amount;
+ deleted = 0;
+ }
+ else if (amount_after > 0)
+ {
+ /* mark_adjust(99, 98, MAXLNUM, 9): a change that inserts lines*/
+ inserted = amount_after;
+ deleted = 0;
+ }
+ else
+ {
+ /* mark_adjust(98, 99, MAXLNUM, -2): delete lines */
+ inserted = 0;
+ deleted = -amount_after;
+ }
+
+ dprev = NULL;
+ dp = tp->tp_first_diff;
+ for (;;)
+ {
+ /* If the change is after the previous diff block and before the next
+ * diff block, thus not touching an existing change, create a new diff
+ * block. Don't do this when ex_diffgetput() is busy. */
+ if ((dp == NULL || dp->df_lnum[idx] - 1 > line2
+ || (line2 == MAXLNUM && dp->df_lnum[idx] > line1))
+ && (dprev == NULL
+ || dprev->df_lnum[idx] + dprev->df_count[idx] < line1)
+ && !diff_busy)
+ {
+ dnext = diff_alloc_new(tp, dprev, dp);
+ if (dnext == NULL)
+ return;
+
+ dnext->df_lnum[idx] = line1;
+ dnext->df_count[idx] = inserted;
+ for (i = 0; i < DB_COUNT; ++i)
+ if (tp->tp_diffbuf[i] != NULL && i != idx)
+ {
+ if (dprev == NULL)
+ dnext->df_lnum[i] = line1;
+ else
+ dnext->df_lnum[i] = line1
+ + (dprev->df_lnum[i] + dprev->df_count[i])
+ - (dprev->df_lnum[idx] + dprev->df_count[idx]);
+ dnext->df_count[i] = deleted;
+ }
+ }
+
+ /* if at end of the list, quit */
+ if (dp == NULL)
+ break;
+
+ /*
+ * Check for these situations:
+ * 1 2 3
+ * 1 2 3
+ * line1 2 3 4 5
+ * 2 3 4 5
+ * 2 3 4 5
+ * line2 2 3 4 5
+ * 3 5 6
+ * 3 5 6
+ */
+ /* compute last line of this change */
+ last = dp->df_lnum[idx] + dp->df_count[idx] - 1;
+
+ /* 1. change completely above line1: nothing to do */
+ if (last >= line1 - 1)
+ {
+ /* 6. change below line2: only adjust for amount_after; also when
+ * "deleted" became zero when deleted all lines between two diffs */
+ if (dp->df_lnum[idx] - (deleted + inserted != 0) > line2)
+ {
+ if (amount_after == 0)
+ break; /* nothing left to change */
+ dp->df_lnum[idx] += amount_after;
+ }
+ else
+ {
+ check_unchanged = FALSE;
+
+ /* 2. 3. 4. 5.: inserted/deleted lines touching this diff. */
+ if (deleted > 0)
+ {
+ if (dp->df_lnum[idx] >= line1)
+ {
+ off = dp->df_lnum[idx] - lnum_deleted;
+ if (last <= line2)
+ {
+ /* 4. delete all lines of diff */
+ if (dp->df_next != NULL
+ && dp->df_next->df_lnum[idx] - 1 <= line2)
+ {
+ /* delete continues in next diff, only do
+ * lines until that one */
+ n = dp->df_next->df_lnum[idx] - lnum_deleted;
+ deleted -= n;
+ n -= dp->df_count[idx];
+ lnum_deleted = dp->df_next->df_lnum[idx];
+ }
+ else
+ n = deleted - dp->df_count[idx];
+ dp->df_count[idx] = 0;
+ }
+ else
+ {
+ /* 5. delete lines at or just before top of diff */
+ n = off;
+ dp->df_count[idx] -= line2 - dp->df_lnum[idx] + 1;
+ check_unchanged = TRUE;
+ }
+ dp->df_lnum[idx] = line1;
+ }
+ else
+ {
+ off = 0;
+ if (last < line2)
+ {
+ /* 2. delete at end of of diff */
+ dp->df_count[idx] -= last - lnum_deleted + 1;
+ if (dp->df_next != NULL
+ && dp->df_next->df_lnum[idx] - 1 <= line2)
+ {
+ /* delete continues in next diff, only do
+ * lines until that one */
+ n = dp->df_next->df_lnum[idx] - 1 - last;
+ deleted -= dp->df_next->df_lnum[idx]
+ - lnum_deleted;
+ lnum_deleted = dp->df_next->df_lnum[idx];
+ }
+ else
+ n = line2 - last;
+ check_unchanged = TRUE;
+ }
+ else
+ {
+ /* 3. delete lines inside the diff */
+ n = 0;
+ dp->df_count[idx] -= deleted;
+ }
+ }
+
+ for (i = 0; i < DB_COUNT; ++i)
+ if (tp->tp_diffbuf[i] != NULL && i != idx)
+ {
+ dp->df_lnum[i] -= off;
+ dp->df_count[i] += n;
+ }
+ }
+ else
+ {
+ if (dp->df_lnum[idx] <= line1)
+ {
+ /* inserted lines somewhere in this diff */
+ dp->df_count[idx] += inserted;
+ check_unchanged = TRUE;
+ }
+ else
+ /* inserted lines somewhere above this diff */
+ dp->df_lnum[idx] += inserted;
+ }
+
+ if (check_unchanged)
+ /* Check if inserted lines are equal, may reduce the
+ * size of the diff. TODO: also check for equal lines
+ * in the middle and perhaps split the block. */
+ diff_check_unchanged(tp, dp);
+ }
+ }
+
+ /* check if this block touches the previous one, may merge them. */
+ if (dprev != NULL && dprev->df_lnum[idx] + dprev->df_count[idx]
+ == dp->df_lnum[idx])
+ {
+ for (i = 0; i < DB_COUNT; ++i)
+ if (tp->tp_diffbuf[i] != NULL)
+ dprev->df_count[i] += dp->df_count[i];
+ dprev->df_next = dp->df_next;
+ vim_free(dp);
+ dp = dprev->df_next;
+ }
+ else
+ {
+ /* Advance to next entry. */
+ dprev = dp;
+ dp = dp->df_next;
+ }
+ }
+
+ dprev = NULL;
+ dp = tp->tp_first_diff;
+ while (dp != NULL)
+ {
+ /* All counts are zero, remove this entry. */
+ for (i = 0; i < DB_COUNT; ++i)
+ if (tp->tp_diffbuf[i] != NULL && dp->df_count[i] != 0)
+ break;
+ if (i == DB_COUNT)
+ {
+ dnext = dp->df_next;
+ vim_free(dp);
+ dp = dnext;
+ if (dprev == NULL)
+ tp->tp_first_diff = dnext;
+ else
+ dprev->df_next = dnext;
+ }
+ else
+ {
+ /* Advance to next entry. */
+ dprev = dp;
+ dp = dp->df_next;
+ }
+
+ }
+
+ if (tp == curtab)
+ {
+ diff_redraw(TRUE);
+
+ /* Need to recompute the scroll binding, may remove or add filler
+ * lines (e.g., when adding lines above w_topline). But it's slow when
+ * making many changes, postpone until redrawing. */
+ diff_need_scrollbind = TRUE;
+ }
+}
+
+/*
+ * Allocate a new diff block and link it between "dprev" and "dp".
+ */
+ static diff_T *
+diff_alloc_new(tabpage_T *tp, diff_T *dprev, diff_T *dp)
+{
+ diff_T *dnew;
+
+ dnew = (diff_T *)alloc((unsigned)sizeof(diff_T));
+ if (dnew != NULL)
+ {
+ dnew->df_next = dp;
+ if (dprev == NULL)
+ tp->tp_first_diff = dnew;
+ else
+ dprev->df_next = dnew;
+ }
+ return dnew;
+}
+
+/*
+ * Check if the diff block "dp" can be made smaller for lines at the start and
+ * end that are equal. Called after inserting lines.
+ * This may result in a change where all buffers have zero lines, the caller
+ * must take care of removing it.
+ */
+ static void
+diff_check_unchanged(tabpage_T *tp, diff_T *dp)
+{
+ int i_org;
+ int i_new;
+ int off_org, off_new;
+ char_u *line_org;
+ int dir = FORWARD;
+
+ /* Find the first buffers, use it as the original, compare the other
+ * buffer lines against this one. */
+ for (i_org = 0; i_org < DB_COUNT; ++i_org)
+ if (tp->tp_diffbuf[i_org] != NULL)
+ break;
+ if (i_org == DB_COUNT) /* safety check */
+ return;
+
+ if (diff_check_sanity(tp, dp) == FAIL)
+ return;
+
+ /* First check lines at the top, then at the bottom. */
+ off_org = 0;
+ off_new = 0;
+ for (;;)
+ {
+ /* Repeat until a line is found which is different or the number of
+ * lines has become zero. */
+ while (dp->df_count[i_org] > 0)
+ {
+ /* Copy the line, the next ml_get() will invalidate it. */
+ if (dir == BACKWARD)
+ off_org = dp->df_count[i_org] - 1;
+ line_org = vim_strsave(ml_get_buf(tp->tp_diffbuf[i_org],
+ dp->df_lnum[i_org] + off_org, FALSE));
+ if (line_org == NULL)
+ return;
+ for (i_new = i_org + 1; i_new < DB_COUNT; ++i_new)
+ {
+ if (tp->tp_diffbuf[i_new] == NULL)
+ continue;
+ if (dir == BACKWARD)
+ off_new = dp->df_count[i_new] - 1;
+ /* if other buffer doesn't have this line, it was inserted */
+ if (off_new < 0 || off_new >= dp->df_count[i_new])
+ break;
+ if (diff_cmp(line_org, ml_get_buf(tp->tp_diffbuf[i_new],
+ dp->df_lnum[i_new] + off_new, FALSE)) != 0)
+ break;
+ }
+ vim_free(line_org);
+
+ /* Stop when a line isn't equal in all diff buffers. */
+ if (i_new != DB_COUNT)
+ break;
+
+ /* Line matched in all buffers, remove it from the diff. */
+ for (i_new = i_org; i_new < DB_COUNT; ++i_new)
+ if (tp->tp_diffbuf[i_new] != NULL)
+ {
+ if (dir == FORWARD)
+ ++dp->df_lnum[i_new];
+ --dp->df_count[i_new];
+ }
+ }
+ if (dir == BACKWARD)
+ break;
+ dir = BACKWARD;
+ }
+}
+
+/*
+ * Check if a diff block doesn't contain invalid line numbers.
+ * This can happen when the diff program returns invalid results.
+ */
+ static int
+diff_check_sanity(tabpage_T *tp, diff_T *dp)
+{
+ int i;
+
+ for (i = 0; i < DB_COUNT; ++i)
+ if (tp->tp_diffbuf[i] != NULL)
+ if (dp->df_lnum[i] + dp->df_count[i] - 1
+ > tp->tp_diffbuf[i]->b_ml.ml_line_count)
+ return FAIL;
+ return OK;
+}
+
+/*
+ * Mark all diff buffers in the current tab page for redraw.
+ */
+ static void
+diff_redraw(
+ int dofold) // also recompute the folds
+{
+ win_T *wp;
+ int n;
+
+ FOR_ALL_WINDOWS(wp)
+ if (wp->w_p_diff)
+ {
+ redraw_win_later(wp, SOME_VALID);
+#ifdef FEAT_FOLDING
+ if (dofold && foldmethodIsDiff(wp))
+ foldUpdateAll(wp);
+#endif
+ /* A change may have made filler lines invalid, need to take care
+ * of that for other windows. */
+ n = diff_check(wp, wp->w_topline);
+ if ((wp != curwin && wp->w_topfill > 0) || n > 0)
+ {
+ if (wp->w_topfill > n)
+ wp->w_topfill = (n < 0 ? 0 : n);
+ else if (n > 0 && n > wp->w_topfill)
+ wp->w_topfill = n;
+ check_topfill(wp, FALSE);
+ }
+ }
+}
+
+ static void
+clear_diffin(diffin_T *din)
+{
+ if (din->din_fname == NULL)
+ {
+ vim_free(din->din_mmfile.ptr);
+ din->din_mmfile.ptr = NULL;
+ }
+ else
+ mch_remove(din->din_fname);
+}
+
+ static void
+clear_diffout(diffout_T *dout)
+{
+ if (dout->dout_fname == NULL)
+ ga_clear_strings(&dout->dout_ga);
+ else
+ mch_remove(dout->dout_fname);
+}
+
+/*
+ * Write buffer "buf" to a memory buffer.
+ * Return FAIL for failure.
+ */
+ static int
+diff_write_buffer(buf_T *buf, diffin_T *din)
+{
+ linenr_T lnum;
+ char_u *s;
+ long len = 0;
+ char_u *ptr;
+
+ // xdiff requires one big block of memory with all the text.
+ for (lnum = 1; lnum <= buf->b_ml.ml_line_count; ++lnum)
+ len += (long)STRLEN(ml_get_buf(buf, lnum, FALSE)) + 1;
+ ptr = lalloc(len, TRUE);
+ if (ptr == NULL)
+ {
+ // Allocating memory failed. This can happen, because we try to read
+ // the whole buffer text into memory. Set the failed flag, the diff
+ // will be retried with external diff. The flag is never reset.
+ buf->b_diff_failed = TRUE;
+ if (p_verbose > 0)
+ {
+ verbose_enter();
+ smsg(_("Not enough memory to use internal diff for buffer \"%s\""),
+ buf->b_fname);
+ verbose_leave();
+ }
+ return FAIL;
+ }
+ din->din_mmfile.ptr = (char *)ptr;
+ din->din_mmfile.size = len;
+
+ len = 0;
+ for (lnum = 1; lnum <= buf->b_ml.ml_line_count; ++lnum)
+ {
+ for (s = ml_get_buf(buf, lnum, FALSE); *s != NUL; )
+ {
+ if (diff_flags & DIFF_ICASE)
+ {
+ int c;
+ int orig_len;
+ char_u cbuf[MB_MAXBYTES + 1];
+
+ // xdiff doesn't support ignoring case, fold-case the text.
+ c = PTR2CHAR(s);
+ c = enc_utf8 ? utf_fold(c) : MB_TOLOWER(c);
+ orig_len = MB_PTR2LEN(s);
+ if (mb_char2bytes(c, cbuf) != orig_len)
+ // TODO: handle byte length difference
+ mch_memmove(ptr + len, s, orig_len);
+ else
+ mch_memmove(ptr + len, cbuf, orig_len);
+
+ s += orig_len;
+ len += orig_len;
+ }
+ else
+ ptr[len++] = *s++;
+ }
+ ptr[len++] = NL;
+ }
+ return OK;
+}
+
+/*
+ * Write buffer "buf" to file or memory buffer.
+ * Return FAIL for failure.
+ */
+ static int
+diff_write(buf_T *buf, diffin_T *din)
+{
+ int r;
+ char_u *save_ff;
+
+ if (din->din_fname == NULL)
+ return diff_write_buffer(buf, din);
+
+ // Always use 'fileformat' set to "unix".
+ save_ff = buf->b_p_ff;
+ buf->b_p_ff = vim_strsave((char_u *)FF_UNIX);
+ r = buf_write(buf, din->din_fname, NULL,
+ (linenr_T)1, buf->b_ml.ml_line_count,
+ NULL, FALSE, FALSE, FALSE, TRUE);
+ free_string_option(buf->b_p_ff);
+ buf->b_p_ff = save_ff;
+ return r;
+}
+
+/*
+ * Update the diffs for all buffers involved.
+ */
+ static void
+diff_try_update(
+ diffio_T *dio,
+ int idx_orig,
+ exarg_T *eap) // "eap" can be NULL
+{
+ buf_T *buf;
+ int idx_new;
+
+ if (dio->dio_internal)
+ {
+ ga_init2(&dio->dio_diff.dout_ga, sizeof(char *), 1000);
+ }
+ else
+ {
+ // We need three temp file names.
+ dio->dio_orig.din_fname = vim_tempname('o', TRUE);
+ dio->dio_new.din_fname = vim_tempname('n', TRUE);
+ dio->dio_diff.dout_fname = vim_tempname('d', TRUE);
+ if (dio->dio_orig.din_fname == NULL
+ || dio->dio_new.din_fname == NULL
+ || dio->dio_diff.dout_fname == NULL)
+ goto theend;
+ }
+
+ // Check external diff is actually working.
+ if (!dio->dio_internal && check_external_diff(dio) == FAIL)
+ goto theend;
+
+ // :diffupdate!
+ if (eap != NULL && eap->forceit)
+ for (idx_new = idx_orig; idx_new < DB_COUNT; ++idx_new)
+ {
+ buf = curtab->tp_diffbuf[idx_new];
+ if (buf_valid(buf))
+ buf_check_timestamp(buf, FALSE);
+ }
+
+ // Write the first buffer to a tempfile or mmfile_t.
+ buf = curtab->tp_diffbuf[idx_orig];
+ if (diff_write(buf, &dio->dio_orig) == FAIL)
+ goto theend;
+
+ // Make a difference between the first buffer and every other.
+ for (idx_new = idx_orig + 1; idx_new < DB_COUNT; ++idx_new)
+ {
+ buf = curtab->tp_diffbuf[idx_new];
+ if (buf == NULL || buf->b_ml.ml_mfp == NULL)
+ continue; // skip buffer that isn't loaded
+
+ // Write the other buffer and diff with the first one.
+ if (diff_write(buf, &dio->dio_new) == FAIL)
+ continue;
+ if (diff_file(dio) == FAIL)
+ continue;
+
+ // Read the diff output and add each entry to the diff list.
+ diff_read(idx_orig, idx_new, &dio->dio_diff);
+
+ clear_diffin(&dio->dio_new);
+ clear_diffout(&dio->dio_diff);
+ }
+ clear_diffin(&dio->dio_orig);
+
+theend:
+ vim_free(dio->dio_orig.din_fname);
+ vim_free(dio->dio_new.din_fname);
+ vim_free(dio->dio_diff.dout_fname);
+}
+
+/*
+ * Return TRUE if the options are set to use the internal diff library.
+ * Note that if the internal diff failed for one of the buffers, the external
+ * diff will be used anyway.
+ */
+ int
+diff_internal(void)
+{
+ return (diff_flags & DIFF_INTERNAL) != 0 && *p_dex == NUL;
+}
+
+/*
+ * Return TRUE if the internal diff failed for one of the diff buffers.
+ */
+ static int
+diff_internal_failed(void)
+{
+ int idx;
+
+ // Only need to do something when there is another buffer.
+ for (idx = 0; idx < DB_COUNT; ++idx)
+ if (curtab->tp_diffbuf[idx] != NULL
+ && curtab->tp_diffbuf[idx]->b_diff_failed)
+ return TRUE;
+ return FALSE;
+}
+
+/*
+ * Completely update the diffs for the buffers involved.
+ * When using the external "diff" command the buffers are written to a file,
+ * also for unmodified buffers (the file could have been produced by
+ * autocommands, e.g. the netrw plugin).
+ */
+ void
+ex_diffupdate(exarg_T *eap) // "eap" can be NULL
+{
+ int idx_orig;
+ int idx_new;
+ diffio_T diffio;
+ int had_diffs = curtab->tp_first_diff != NULL;
+
+ if (diff_busy)
+ {
+ diff_need_update = TRUE;
+ return;
+ }
+
+ // Delete all diffblocks.
+ diff_clear(curtab);
+ curtab->tp_diff_invalid = FALSE;
+
+ // Use the first buffer as the original text.
+ for (idx_orig = 0; idx_orig < DB_COUNT; ++idx_orig)
+ if (curtab->tp_diffbuf[idx_orig] != NULL)
+ break;
+ if (idx_orig == DB_COUNT)
+ goto theend;
+
+ // Only need to do something when there is another buffer.
+ for (idx_new = idx_orig + 1; idx_new < DB_COUNT; ++idx_new)
+ if (curtab->tp_diffbuf[idx_new] != NULL)
+ break;
+ if (idx_new == DB_COUNT)
+ goto theend;
+
+ // Only use the internal method if it did not fail for one of the buffers.
+ vim_memset(&diffio, 0, sizeof(diffio));
+ diffio.dio_internal = diff_internal() && !diff_internal_failed();
+
+ diff_try_update(&diffio, idx_orig, eap);
+ if (diffio.dio_internal && diff_internal_failed())
+ {
+ // Internal diff failed, use external diff instead.
+ vim_memset(&diffio, 0, sizeof(diffio));
+ diff_try_update(&diffio, idx_orig, eap);
+ }
+
+ // force updating cursor position on screen
+ curwin->w_valid_cursor.lnum = 0;
+
+theend:
+ // A redraw is needed if there were diffs and they were cleared, or there
+ // are diffs now, which means they got updated.
+ if (had_diffs || curtab->tp_first_diff != NULL)
+ {
+ diff_redraw(TRUE);
+ apply_autocmds(EVENT_DIFFUPDATED, NULL, NULL, FALSE, curbuf);
+ }
+}
+
+/*
+ * Do a quick test if "diff" really works. Otherwise it looks like there
+ * are no differences. Can't use the return value, it's non-zero when
+ * there are differences.
+ */
+ static int
+check_external_diff(diffio_T *diffio)
+{
+ FILE *fd;
+ int ok;
+ int io_error = FALSE;
+
+ // May try twice, first with "-a" and then without.
+ for (;;)
+ {
+ ok = FALSE;
+ fd = mch_fopen((char *)diffio->dio_orig.din_fname, "w");
+ if (fd == NULL)
+ io_error = TRUE;
+ else
+ {
+ if (fwrite("line1\n", (size_t)6, (size_t)1, fd) != 1)
+ io_error = TRUE;
+ fclose(fd);
+ fd = mch_fopen((char *)diffio->dio_new.din_fname, "w");
+ if (fd == NULL)
+ io_error = TRUE;
+ else
+ {
+ if (fwrite("line2\n", (size_t)6, (size_t)1, fd) != 1)
+ io_error = TRUE;
+ fclose(fd);
+ fd = NULL;
+ if (diff_file(diffio) == OK)
+ fd = mch_fopen((char *)diffio->dio_diff.dout_fname, "r");
+ if (fd == NULL)
+ io_error = TRUE;
+ else
+ {
+ char_u linebuf[LBUFLEN];
+
+ for (;;)
+ {
+ /* There must be a line that contains "1c1". */
+ if (tag_fgets(linebuf, LBUFLEN, fd))
+ break;
+ if (STRNCMP(linebuf, "1c1", 3) == 0)
+ ok = TRUE;
+ }
+ fclose(fd);
+ }
+ mch_remove(diffio->dio_diff.dout_fname);
+ mch_remove(diffio->dio_new.din_fname);
+ }
+ mch_remove(diffio->dio_orig.din_fname);
+ }
+
+#ifdef FEAT_EVAL
+ /* When using 'diffexpr' break here. */
+ if (*p_dex != NUL)
+ break;
+#endif
+
+#if defined(MSWIN)
+ /* If the "-a" argument works, also check if "--binary" works. */
+ if (ok && diff_a_works == MAYBE && diff_bin_works == MAYBE)
+ {
+ diff_a_works = TRUE;
+ diff_bin_works = TRUE;
+ continue;
+ }
+ if (!ok && diff_a_works == TRUE && diff_bin_works == TRUE)
+ {
+ /* Tried --binary, but it failed. "-a" works though. */
+ diff_bin_works = FALSE;
+ ok = TRUE;
+ }
+#endif
+
+ /* If we checked if "-a" works already, break here. */
+ if (diff_a_works != MAYBE)
+ break;
+ diff_a_works = ok;
+
+ /* If "-a" works break here, otherwise retry without "-a". */
+ if (ok)
+ break;
+ }
+ if (!ok)
+ {
+ if (io_error)
+ emsg(_("E810: Cannot read or write temp files"));
+ emsg(_("E97: Cannot create diffs"));
+ diff_a_works = MAYBE;
+#if defined(MSWIN)
+ diff_bin_works = MAYBE;
+#endif
+ return FAIL;
+ }
+ return OK;
+}
+
+/*
+ * Invoke the xdiff function.
+ */
+ static int
+diff_file_internal(diffio_T *diffio)
+{
+ xpparam_t param;
+ xdemitconf_t emit_cfg;
+ xdemitcb_t emit_cb;
+
+ vim_memset(&param, 0, sizeof(param));
+ vim_memset(&emit_cfg, 0, sizeof(emit_cfg));
+ vim_memset(&emit_cb, 0, sizeof(emit_cb));
+
+ param.flags = diff_algorithm;
+
+ if (diff_flags & DIFF_IWHITE)
+ param.flags |= XDF_IGNORE_WHITESPACE_CHANGE;
+ if (diff_flags & DIFF_IWHITEALL)
+ param.flags |= XDF_IGNORE_WHITESPACE;
+ if (diff_flags & DIFF_IWHITEEOL)
+ param.flags |= XDF_IGNORE_WHITESPACE_AT_EOL;
+ if (diff_flags & DIFF_IBLANK)
+ param.flags |= XDF_IGNORE_BLANK_LINES;
+
+ emit_cfg.ctxlen = 0; // don't need any diff_context here
+ emit_cb.priv = &diffio->dio_diff;
+ emit_cb.outf = xdiff_out;
+ if (xdl_diff(&diffio->dio_orig.din_mmfile,
+ &diffio->dio_new.din_mmfile,
+ &param, &emit_cfg, &emit_cb) < 0)
+ {
+ emsg(_("E960: Problem creating the internal diff"));
+ return FAIL;
+ }
+ return OK;
+}
+
+/*
+ * Make a diff between files "tmp_orig" and "tmp_new", results in "tmp_diff".
+ * return OK or FAIL;
+ */
+ static int
+diff_file(diffio_T *dio)
+{
+ char_u *cmd;
+ size_t len;
+ char_u *tmp_orig = dio->dio_orig.din_fname;
+ char_u *tmp_new = dio->dio_new.din_fname;
+ char_u *tmp_diff = dio->dio_diff.dout_fname;
+
+#ifdef FEAT_EVAL
+ if (*p_dex != NUL)
+ {
+ // Use 'diffexpr' to generate the diff file.
+ eval_diff(tmp_orig, tmp_new, tmp_diff);
+ return OK;
+ }
+ else
+#endif
+ // Use xdiff for generating the diff.
+ if (dio->dio_internal)
+ {
+ return diff_file_internal(dio);
+ }
+ else
+ {
+ len = STRLEN(tmp_orig) + STRLEN(tmp_new)
+ + STRLEN(tmp_diff) + STRLEN(p_srr) + 27;
+ cmd = alloc((unsigned)len);
+ if (cmd == NULL)
+ return FAIL;
+
+ // We don't want $DIFF_OPTIONS to get in the way.
+ if (getenv("DIFF_OPTIONS"))
+ vim_setenv((char_u *)"DIFF_OPTIONS", (char_u *)"");
+
+ // Build the diff command and execute it. Always use -a, binary
+ // differences are of no use. Ignore errors, diff returns
+ // non-zero when differences have been found.
+ vim_snprintf((char *)cmd, len, "diff %s%s%s%s%s%s%s%s %s",
+ diff_a_works == FALSE ? "" : "-a ",
+#if defined(MSWIN)
+ diff_bin_works == TRUE ? "--binary " : "",
+#else
+ "",
+#endif
+ (diff_flags & DIFF_IWHITE) ? "-b " : "",
+ (diff_flags & DIFF_IWHITEALL) ? "-w " : "",
+ (diff_flags & DIFF_IWHITEEOL) ? "-Z " : "",
+ (diff_flags & DIFF_IBLANK) ? "-B " : "",
+ (diff_flags & DIFF_ICASE) ? "-i " : "",
+ tmp_orig, tmp_new);
+ append_redir(cmd, (int)len, p_srr, tmp_diff);
+ block_autocmds(); // avoid ShellCmdPost stuff
+ (void)call_shell(cmd, SHELL_FILTER|SHELL_SILENT|SHELL_DOOUT);
+ unblock_autocmds();
+ vim_free(cmd);
+ return OK;
+ }
+}
+
+/*
+ * Create a new version of a file from the current buffer and a diff file.
+ * The buffer is written to a file, also for unmodified buffers (the file
+ * could have been produced by autocommands, e.g. the netrw plugin).
+ */
+ void
+ex_diffpatch(exarg_T *eap)
+{
+ char_u *tmp_orig; /* name of original temp file */
+ char_u *tmp_new; /* name of patched temp file */
+ char_u *buf = NULL;
+ size_t buflen;
+ win_T *old_curwin = curwin;
+ char_u *newname = NULL; /* name of patched file buffer */
+#ifdef UNIX
+ char_u dirbuf[MAXPATHL];
+ char_u *fullname = NULL;
+#endif
+#ifdef FEAT_BROWSE
+ char_u *browseFile = NULL;
+ int browse_flag = cmdmod.browse;
+#endif
+ stat_T st;
+ char_u *esc_name = NULL;
+
+#ifdef FEAT_BROWSE
+ if (cmdmod.browse)
+ {
+ browseFile = do_browse(0, (char_u *)_("Patch file"),
+ eap->arg, NULL, NULL,
+ (char_u *)_(BROWSE_FILTER_ALL_FILES), NULL);
+ if (browseFile == NULL)
+ return; /* operation cancelled */
+ eap->arg = browseFile;
+ cmdmod.browse = FALSE; /* don't let do_ecmd() browse again */
+ }
+#endif
+
+ /* We need two temp file names. */
+ tmp_orig = vim_tempname('o', FALSE);
+ tmp_new = vim_tempname('n', FALSE);
+ if (tmp_orig == NULL || tmp_new == NULL)
+ goto theend;
+
+ /* Write the current buffer to "tmp_orig". */
+ if (buf_write(curbuf, tmp_orig, NULL,
+ (linenr_T)1, curbuf->b_ml.ml_line_count,
+ NULL, FALSE, FALSE, FALSE, TRUE) == FAIL)
+ goto theend;
+
+#ifdef UNIX
+ /* Get the absolute path of the patchfile, changing directory below. */
+ fullname = FullName_save(eap->arg, FALSE);
+#endif
+ esc_name = vim_strsave_shellescape(
+# ifdef UNIX
+ fullname != NULL ? fullname :
+# endif
+ eap->arg, TRUE, TRUE);
+ if (esc_name == NULL)
+ goto theend;
+ buflen = STRLEN(tmp_orig) + STRLEN(esc_name) + STRLEN(tmp_new) + 16;
+ buf = alloc((unsigned)buflen);
+ if (buf == NULL)
+ goto theend;
+
+#ifdef UNIX
+ /* Temporarily chdir to /tmp, to avoid patching files in the current
+ * directory when the patch file contains more than one patch. When we
+ * have our own temp dir use that instead, it will be cleaned up when we
+ * exit (any .rej files created). Don't change directory if we can't
+ * return to the current. */
+ if (mch_dirname(dirbuf, MAXPATHL) != OK || mch_chdir((char *)dirbuf) != 0)
+ dirbuf[0] = NUL;
+ else
+ {
+# ifdef TEMPDIRNAMES
+ if (vim_tempdir != NULL)
+ vim_ignored = mch_chdir((char *)vim_tempdir);
+ else
+# endif
+ vim_ignored = mch_chdir("/tmp");
+ shorten_fnames(TRUE);
+ }
+#endif
+
+#ifdef FEAT_EVAL
+ if (*p_pex != NUL)
+ /* Use 'patchexpr' to generate the new file. */
+ eval_patch(tmp_orig,
+# ifdef UNIX
+ fullname != NULL ? fullname :
+# endif
+ eap->arg, tmp_new);
+ else
+#endif
+ {
+ /* Build the patch command and execute it. Ignore errors. Switch to
+ * cooked mode to allow the user to respond to prompts. */
+ vim_snprintf((char *)buf, buflen, "patch -o %s %s < %s",
+ tmp_new, tmp_orig, esc_name);
+ block_autocmds(); /* Avoid ShellCmdPost stuff */
+ (void)call_shell(buf, SHELL_FILTER | SHELL_COOKED);
+ unblock_autocmds();
+ }
+
+#ifdef UNIX
+ if (dirbuf[0] != NUL)
+ {
+ if (mch_chdir((char *)dirbuf) != 0)
+ emsg(_(e_prev_dir));
+ shorten_fnames(TRUE);
+ }
+#endif
+
+ /* patch probably has written over the screen */
+ redraw_later(CLEAR);
+
+ /* Delete any .orig or .rej file created. */
+ STRCPY(buf, tmp_new);
+ STRCAT(buf, ".orig");
+ mch_remove(buf);
+ STRCPY(buf, tmp_new);
+ STRCAT(buf, ".rej");
+ mch_remove(buf);
+
+ /* Only continue if the output file was created. */
+ if (mch_stat((char *)tmp_new, &st) < 0 || st.st_size == 0)
+ emsg(_("E816: Cannot read patch output"));
+ else
+ {
+ if (curbuf->b_fname != NULL)
+ {
+ newname = vim_strnsave(curbuf->b_fname,
+ (int)(STRLEN(curbuf->b_fname) + 4));
+ if (newname != NULL)
+ STRCAT(newname, ".new");
+ }
+
+#ifdef FEAT_GUI
+ need_mouse_correct = TRUE;
+#endif
+ /* don't use a new tab page, each tab page has its own diffs */
+ cmdmod.tab = 0;
+
+ if (win_split(0, (diff_flags & DIFF_VERTICAL) ? WSP_VERT : 0) != FAIL)
+ {
+ /* Pretend it was a ":split fname" command */
+ eap->cmdidx = CMD_split;
+ eap->arg = tmp_new;
+ do_exedit(eap, old_curwin);
+
+ /* check that split worked and editing tmp_new */
+ if (curwin != old_curwin && win_valid(old_curwin))
+ {
+ /* Set 'diff', 'scrollbind' on and 'wrap' off. */
+ diff_win_options(curwin, TRUE);
+ diff_win_options(old_curwin, TRUE);
+
+ if (newname != NULL)
+ {
+ /* do a ":file filename.new" on the patched buffer */
+ eap->arg = newname;
+ ex_file(eap);
+
+ /* Do filetype detection with the new name. */
+ if (au_has_group((char_u *)"filetypedetect"))
+ do_cmdline_cmd((char_u *)":doau filetypedetect BufRead");
+ }
+ }
+ }
+ }
+
+theend:
+ if (tmp_orig != NULL)
+ mch_remove(tmp_orig);
+ vim_free(tmp_orig);
+ if (tmp_new != NULL)
+ mch_remove(tmp_new);
+ vim_free(tmp_new);
+ vim_free(newname);
+ vim_free(buf);
+#ifdef UNIX
+ vim_free(fullname);
+#endif
+ vim_free(esc_name);
+#ifdef FEAT_BROWSE
+ vim_free(browseFile);
+ cmdmod.browse = browse_flag;
+#endif
+}
+
+/*
+ * Split the window and edit another file, setting options to show the diffs.
+ */
+ void
+ex_diffsplit(exarg_T *eap)
+{
+ win_T *old_curwin = curwin;
+ bufref_T old_curbuf;
+
+ set_bufref(&old_curbuf, curbuf);
+#ifdef FEAT_GUI
+ need_mouse_correct = TRUE;
+#endif
+ /* Need to compute w_fraction when no redraw happened yet. */
+ validate_cursor();
+ set_fraction(curwin);
+
+ /* don't use a new tab page, each tab page has its own diffs */
+ cmdmod.tab = 0;
+
+ if (win_split(0, (diff_flags & DIFF_VERTICAL) ? WSP_VERT : 0) != FAIL)
+ {
+ /* Pretend it was a ":split fname" command */
+ eap->cmdidx = CMD_split;
+ curwin->w_p_diff = TRUE;
+ do_exedit(eap, old_curwin);
+
+ if (curwin != old_curwin) /* split must have worked */
+ {
+ /* Set 'diff', 'scrollbind' on and 'wrap' off. */
+ diff_win_options(curwin, TRUE);
+ if (win_valid(old_curwin))
+ {
+ diff_win_options(old_curwin, TRUE);
+
+ if (bufref_valid(&old_curbuf))
+ /* Move the cursor position to that of the old window. */
+ curwin->w_cursor.lnum = diff_get_corresponding_line(
+ old_curbuf.br_buf, old_curwin->w_cursor.lnum);
+ }
+ /* Now that lines are folded scroll to show the cursor at the same
+ * relative position. */
+ scroll_to_fraction(curwin, curwin->w_height);
+ }
+ }
+}
+
+/*
+ * Set options to show diffs for the current window.
+ */
+ void
+ex_diffthis(exarg_T *eap UNUSED)
+{
+ /* Set 'diff', 'scrollbind' on and 'wrap' off. */
+ diff_win_options(curwin, TRUE);
+}
+
+ static void
+set_diff_option(win_T *wp, int value)
+{
+ win_T *old_curwin = curwin;
+
+ curwin = wp;
+ curbuf = curwin->w_buffer;
+ ++curbuf_lock;
+ set_option_value((char_u *)"diff", (long)value, NULL, OPT_LOCAL);
+ --curbuf_lock;
+ curwin = old_curwin;
+ curbuf = curwin->w_buffer;
+}
+
+/*
+ * Set options in window "wp" for diff mode.
+ */
+ void
+diff_win_options(
+ win_T *wp,
+ int addbuf) /* Add buffer to diff. */
+{
+# ifdef FEAT_FOLDING
+ win_T *old_curwin = curwin;
+
+ /* close the manually opened folds */
+ curwin = wp;
+ newFoldLevel();
+ curwin = old_curwin;
+# endif
+
+ /* Use 'scrollbind' and 'cursorbind' when available */
+ if (!wp->w_p_diff)
+ wp->w_p_scb_save = wp->w_p_scb;
+ wp->w_p_scb = TRUE;
+ if (!wp->w_p_diff)
+ wp->w_p_crb_save = wp->w_p_crb;
+ wp->w_p_crb = TRUE;
+ if (!wp->w_p_diff)
+ wp->w_p_wrap_save = wp->w_p_wrap;
+ wp->w_p_wrap = FALSE;
+# ifdef FEAT_FOLDING
+ curwin = wp;
+ curbuf = curwin->w_buffer;
+ if (!wp->w_p_diff)
+ {
+ if (wp->w_p_diff_saved)
+ free_string_option(wp->w_p_fdm_save);
+ wp->w_p_fdm_save = vim_strsave(wp->w_p_fdm);
+ }
+ set_string_option_direct((char_u *)"fdm", -1, (char_u *)"diff",
+ OPT_LOCAL|OPT_FREE, 0);
+ curwin = old_curwin;
+ curbuf = curwin->w_buffer;
+ if (!wp->w_p_diff)
+ {
+ wp->w_p_fdc_save = wp->w_p_fdc;
+ wp->w_p_fen_save = wp->w_p_fen;
+ wp->w_p_fdl_save = wp->w_p_fdl;
+ }
+ wp->w_p_fdc = diff_foldcolumn;
+ wp->w_p_fen = TRUE;
+ wp->w_p_fdl = 0;
+ foldUpdateAll(wp);
+ /* make sure topline is not halfway a fold */
+ changed_window_setting_win(wp);
+# endif
+ if (vim_strchr(p_sbo, 'h') == NULL)
+ do_cmdline_cmd((char_u *)"set sbo+=hor");
+ /* Save the current values, to be restored in ex_diffoff(). */
+ wp->w_p_diff_saved = TRUE;
+
+ set_diff_option(wp, TRUE);
+
+ if (addbuf)
+ diff_buf_add(wp->w_buffer);
+ redraw_win_later(wp, NOT_VALID);
+}
+
+/*
+ * Set options not to show diffs. For the current window or all windows.
+ * Only in the current tab page.
+ */
+ void
+ex_diffoff(exarg_T *eap)
+{
+ win_T *wp;
+ int diffwin = FALSE;
+
+ FOR_ALL_WINDOWS(wp)
+ {
+ if (eap->forceit ? wp->w_p_diff : wp == curwin)
+ {
+ /* Set 'diff' off. If option values were saved in
+ * diff_win_options(), restore the ones whose settings seem to have
+ * been left over from diff mode. */
+ set_diff_option(wp, FALSE);
+
+ if (wp->w_p_diff_saved)
+ {
+
+ if (wp->w_p_scb)
+ wp->w_p_scb = wp->w_p_scb_save;
+ if (wp->w_p_crb)
+ wp->w_p_crb = wp->w_p_crb_save;
+ if (!wp->w_p_wrap)
+ wp->w_p_wrap = wp->w_p_wrap_save;
+#ifdef FEAT_FOLDING
+ free_string_option(wp->w_p_fdm);
+ wp->w_p_fdm = vim_strsave(
+ *wp->w_p_fdm_save ? wp->w_p_fdm_save : (char_u*)"manual");
+
+ if (wp->w_p_fdc == diff_foldcolumn)
+ wp->w_p_fdc = wp->w_p_fdc_save;
+ if (wp->w_p_fdl == 0)
+ wp->w_p_fdl = wp->w_p_fdl_save;
+
+ /* Only restore 'foldenable' when 'foldmethod' is not
+ * "manual", otherwise we continue to show the diff folds. */
+ if (wp->w_p_fen)
+ wp->w_p_fen = foldmethodIsManual(wp) ? FALSE
+ : wp->w_p_fen_save;
+
+ foldUpdateAll(wp);
+#endif
+ }
+ /* remove filler lines */
+ wp->w_topfill = 0;
+
+ /* make sure topline is not halfway a fold and cursor is
+ * invalidated */
+ changed_window_setting_win(wp);
+
+ /* Note: 'sbo' is not restored, it's a global option. */
+ diff_buf_adjust(wp);
+ }
+ diffwin |= wp->w_p_diff;
+ }
+
+ /* Also remove hidden buffers from the list. */
+ if (eap->forceit)
+ diff_buf_clear();
+
+ /* Remove "hor" from from 'scrollopt' if there are no diff windows left. */
+ if (!diffwin && vim_strchr(p_sbo, 'h') != NULL)
+ do_cmdline_cmd((char_u *)"set sbo-=hor");
+}
+
+/*
+ * Read the diff output and add each entry to the diff list.
+ */
+ static void
+diff_read(
+ int idx_orig, // idx of original file
+ int idx_new, // idx of new file
+ diffout_T *dout) // diff output
+{
+ FILE *fd = NULL;
+ int line_idx = 0;
+ diff_T *dprev = NULL;
+ diff_T *dp = curtab->tp_first_diff;
+ diff_T *dn, *dpl;
+ char_u linebuf[LBUFLEN]; /* only need to hold the diff line */
+ char_u *line;
+ long off;
+ int i;
+ linenr_T lnum_orig, lnum_new;
+ long count_orig, count_new;
+ int notset = TRUE; /* block "*dp" not set yet */
+ enum {
+ DIFF_ED,
+ DIFF_UNIFIED,
+ DIFF_NONE
+ } diffstyle = DIFF_NONE;
+
+ if (dout->dout_fname == NULL)
+ {
+ diffstyle = DIFF_UNIFIED;
+ }
+ else
+ {
+ fd = mch_fopen((char *)dout->dout_fname, "r");
+ if (fd == NULL)
+ {
+ emsg(_("E98: Cannot read diff output"));
+ return;
+ }
+ }
+
+ for (;;)
+ {
+ if (fd == NULL)
+ {
+ if (line_idx >= dout->dout_ga.ga_len)
+ break; // did last line
+ line = ((char_u **)dout->dout_ga.ga_data)[line_idx++];
+ }
+ else
+ {
+ if (tag_fgets(linebuf, LBUFLEN, fd))
+ break; // end of file
+ line = linebuf;
+ }
+
+ if (diffstyle == DIFF_NONE)
+ {
+ // Determine diff style.
+ // ed like diff looks like this:
+ // {first}[,{last}]c{first}[,{last}]
+ // {first}a{first}[,{last}]
+ // {first}[,{last}]d{first}
+ //
+ // unified diff looks like this:
+ // --- file1 2018-03-20 13:23:35.783153140 +0100
+ // +++ file2 2018-03-20 13:23:41.183156066 +0100
+ // @@ -1,3 +1,5 @@
+ if (isdigit(*line))
+ diffstyle = DIFF_ED;
+ else if ((STRNCMP(line, "@@ ", 3) == 0))
+ diffstyle = DIFF_UNIFIED;
+ else if ((STRNCMP(line, "--- ", 4) == 0)
+ && (tag_fgets(linebuf, LBUFLEN, fd) == 0)
+ && (STRNCMP(line, "+++ ", 4) == 0)
+ && (tag_fgets(linebuf, LBUFLEN, fd) == 0)
+ && (STRNCMP(line, "@@ ", 3) == 0))
+ diffstyle = DIFF_UNIFIED;
+ else
+ // Format not recognized yet, skip over this line. Cygwin diff
+ // may put a warning at the start of the file.
+ continue;
+ }
+
+ if (diffstyle == DIFF_ED)
+ {
+ if (!isdigit(*line))
+ continue; // not the start of a diff block
+ if (parse_diff_ed(line, &lnum_orig, &count_orig,
+ &lnum_new, &count_new) == FAIL)
+ continue;
+ }
+ else if (diffstyle == DIFF_UNIFIED)
+ {
+ if (STRNCMP(line, "@@ ", 3) != 0)
+ continue; // not the start of a diff block
+ if (parse_diff_unified(line, &lnum_orig, &count_orig,
+ &lnum_new, &count_new) == FAIL)
+ continue;
+ }
+ else
+ {
+ emsg(_("E959: Invalid diff format."));
+ break;
+ }
+
+ // Go over blocks before the change, for which orig and new are equal.
+ // Copy blocks from orig to new.
+ while (dp != NULL
+ && lnum_orig > dp->df_lnum[idx_orig] + dp->df_count[idx_orig])
+ {
+ if (notset)
+ diff_copy_entry(dprev, dp, idx_orig, idx_new);
+ dprev = dp;
+ dp = dp->df_next;
+ notset = TRUE;
+ }
+
+ if (dp != NULL
+ && lnum_orig <= dp->df_lnum[idx_orig] + dp->df_count[idx_orig]
+ && lnum_orig + count_orig >= dp->df_lnum[idx_orig])
+ {
+ // New block overlaps with existing block(s).
+ // First find last block that overlaps.
+ for (dpl = dp; dpl->df_next != NULL; dpl = dpl->df_next)
+ if (lnum_orig + count_orig < dpl->df_next->df_lnum[idx_orig])
+ break;
+
+ // If the newly found block starts before the old one, set the
+ // start back a number of lines.
+ off = dp->df_lnum[idx_orig] - lnum_orig;
+ if (off > 0)
+ {
+ for (i = idx_orig; i < idx_new; ++i)
+ if (curtab->tp_diffbuf[i] != NULL)
+ dp->df_lnum[i] -= off;
+ dp->df_lnum[idx_new] = lnum_new;
+ dp->df_count[idx_new] = count_new;
+ }
+ else if (notset)
+ {
+ // new block inside existing one, adjust new block
+ dp->df_lnum[idx_new] = lnum_new + off;
+ dp->df_count[idx_new] = count_new - off;
+ }
+ else
+ // second overlap of new block with existing block
+ dp->df_count[idx_new] += count_new - count_orig
+ + dpl->df_lnum[idx_orig] + dpl->df_count[idx_orig]
+ - (dp->df_lnum[idx_orig] + dp->df_count[idx_orig]);
+
+ // Adjust the size of the block to include all the lines to the
+ // end of the existing block or the new diff, whatever ends last.
+ off = (lnum_orig + count_orig)
+ - (dpl->df_lnum[idx_orig] + dpl->df_count[idx_orig]);
+ if (off < 0)
+ {
+ // new change ends in existing block, adjust the end if not
+ // done already
+ if (notset)
+ dp->df_count[idx_new] += -off;
+ off = 0;
+ }
+ for (i = idx_orig; i < idx_new; ++i)
+ if (curtab->tp_diffbuf[i] != NULL)
+ dp->df_count[i] = dpl->df_lnum[i] + dpl->df_count[i]
+ - dp->df_lnum[i] + off;
+
+ // Delete the diff blocks that have been merged into one.
+ dn = dp->df_next;
+ dp->df_next = dpl->df_next;
+ while (dn != dp->df_next)
+ {
+ dpl = dn->df_next;
+ vim_free(dn);
+ dn = dpl;
+ }
+ }
+ else
+ {
+ // Allocate a new diffblock.
+ dp = diff_alloc_new(curtab, dprev, dp);
+ if (dp == NULL)
+ goto done;
+
+ dp->df_lnum[idx_orig] = lnum_orig;
+ dp->df_count[idx_orig] = count_orig;
+ dp->df_lnum[idx_new] = lnum_new;
+ dp->df_count[idx_new] = count_new;
+
+ // Set values for other buffers, these must be equal to the
+ // original buffer, otherwise there would have been a change
+ // already.
+ for (i = idx_orig + 1; i < idx_new; ++i)
+ if (curtab->tp_diffbuf[i] != NULL)
+ diff_copy_entry(dprev, dp, idx_orig, i);
+ }
+ notset = FALSE; // "*dp" has been set
+ }
+
+ // for remaining diff blocks orig and new are equal
+ while (dp != NULL)
+ {
+ if (notset)
+ diff_copy_entry(dprev, dp, idx_orig, idx_new);
+ dprev = dp;
+ dp = dp->df_next;
+ notset = TRUE;
+ }
+
+done:
+ if (fd != NULL)
+ fclose(fd);
+}
+
+/*
+ * Copy an entry at "dp" from "idx_orig" to "idx_new".
+ */
+ static void
+diff_copy_entry(
+ diff_T *dprev,
+ diff_T *dp,
+ int idx_orig,
+ int idx_new)
+{
+ long off;
+
+ if (dprev == NULL)
+ off = 0;
+ else
+ off = (dprev->df_lnum[idx_orig] + dprev->df_count[idx_orig])
+ - (dprev->df_lnum[idx_new] + dprev->df_count[idx_new]);
+ dp->df_lnum[idx_new] = dp->df_lnum[idx_orig] - off;
+ dp->df_count[idx_new] = dp->df_count[idx_orig];
+}
+
+/*
+ * Clear the list of diffblocks for tab page "tp".
+ */
+ void
+diff_clear(tabpage_T *tp)
+{
+ diff_T *p, *next_p;
+
+ for (p = tp->tp_first_diff; p != NULL; p = next_p)
+ {
+ next_p = p->df_next;
+ vim_free(p);
+ }
+ tp->tp_first_diff = NULL;
+}
+
+/*
+ * Check diff status for line "lnum" in buffer "buf":
+ * Returns 0 for nothing special
+ * Returns -1 for a line that should be highlighted as changed.
+ * Returns -2 for a line that should be highlighted as added/deleted.
+ * Returns > 0 for inserting that many filler lines above it (never happens
+ * when 'diffopt' doesn't contain "filler").
+ * This should only be used for windows where 'diff' is set.
+ */
+ int
+diff_check(win_T *wp, linenr_T lnum)
+{
+ int idx; /* index in tp_diffbuf[] for this buffer */
+ diff_T *dp;
+ int maxcount;
+ int i;
+ buf_T *buf = wp->w_buffer;
+ int cmp;
+
+ if (curtab->tp_diff_invalid)
+ ex_diffupdate(NULL); /* update after a big change */
+
+ if (curtab->tp_first_diff == NULL || !wp->w_p_diff) /* no diffs at all */
+ return 0;
+
+ /* safety check: "lnum" must be a buffer line */
+ if (lnum < 1 || lnum > buf->b_ml.ml_line_count + 1)
+ return 0;
+
+ idx = diff_buf_idx(buf);
+ if (idx == DB_COUNT)
+ return 0; /* no diffs for buffer "buf" */
+
+#ifdef FEAT_FOLDING
+ /* A closed fold never has filler lines. */
+ if (hasFoldingWin(wp, lnum, NULL, NULL, TRUE, NULL))
+ return 0;
+#endif
+
+ /* search for a change that includes "lnum" in the list of diffblocks. */
+ for (dp = curtab->tp_first_diff; dp != NULL; dp = dp->df_next)
+ if (lnum <= dp->df_lnum[idx] + dp->df_count[idx])
+ break;
+ if (dp == NULL || lnum < dp->df_lnum[idx])
+ return 0;
+
+ if (lnum < dp->df_lnum[idx] + dp->df_count[idx])
+ {
+ int zero = FALSE;
+
+ /* Changed or inserted line. If the other buffers have a count of
+ * zero, the lines were inserted. If the other buffers have the same
+ * count, check if the lines are identical. */
+ cmp = FALSE;
+ for (i = 0; i < DB_COUNT; ++i)
+ if (i != idx && curtab->tp_diffbuf[i] != NULL)
+ {
+ if (dp->df_count[i] == 0)
+ zero = TRUE;
+ else
+ {
+ if (dp->df_count[i] != dp->df_count[idx])
+ return -1; /* nr of lines changed. */
+ cmp = TRUE;
+ }
+ }
+ if (cmp)
+ {
+ /* Compare all lines. If they are equal the lines were inserted
+ * in some buffers, deleted in others, but not changed. */
+ for (i = 0; i < DB_COUNT; ++i)
+ if (i != idx && curtab->tp_diffbuf[i] != NULL
+ && dp->df_count[i] != 0)
+ if (!diff_equal_entry(dp, idx, i))
+ return -1;
+ }
+ /* If there is no buffer with zero lines then there is no difference
+ * any longer. Happens when making a change (or undo) that removes
+ * the difference. Can't remove the entry here, we might be halfway
+ * updating the window. Just report the text as unchanged. Other
+ * windows might still show the change though. */
+ if (zero == FALSE)
+ return 0;
+ return -2;
+ }
+
+ /* If 'diffopt' doesn't contain "filler", return 0. */
+ if (!(diff_flags & DIFF_FILLER))
+ return 0;
+
+ /* Insert filler lines above the line just below the change. Will return
+ * 0 when this buf had the max count. */
+ maxcount = 0;
+ for (i = 0; i < DB_COUNT; ++i)
+ if (curtab->tp_diffbuf[i] != NULL && dp->df_count[i] > maxcount)
+ maxcount = dp->df_count[i];
+ return maxcount - dp->df_count[idx];
+}
+
+/*
+ * Compare two entries in diff "*dp" and return TRUE if they are equal.
+ */
+ static int
+diff_equal_entry(diff_T *dp, int idx1, int idx2)
+{
+ int i;
+ char_u *line;
+ int cmp;
+
+ if (dp->df_count[idx1] != dp->df_count[idx2])
+ return FALSE;
+ if (diff_check_sanity(curtab, dp) == FAIL)
+ return FALSE;
+ for (i = 0; i < dp->df_count[idx1]; ++i)
+ {
+ line = vim_strsave(ml_get_buf(curtab->tp_diffbuf[idx1],
+ dp->df_lnum[idx1] + i, FALSE));
+ if (line == NULL)
+ return FALSE;
+ cmp = diff_cmp(line, ml_get_buf(curtab->tp_diffbuf[idx2],
+ dp->df_lnum[idx2] + i, FALSE));
+ vim_free(line);
+ if (cmp != 0)
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*
+ * Compare the characters at "p1" and "p2". If they are equal (possibly
+ * ignoring case) return TRUE and set "len" to the number of bytes.
+ */
+ static int
+diff_equal_char(char_u *p1, char_u *p2, int *len)
+{
+ int l = (*mb_ptr2len)(p1);
+
+ if (l != (*mb_ptr2len)(p2))
+ return FALSE;
+ if (l > 1)
+ {
+ if (STRNCMP(p1, p2, l) != 0
+ && (!enc_utf8
+ || !(diff_flags & DIFF_ICASE)
+ || utf_fold(utf_ptr2char(p1))
+ != utf_fold(utf_ptr2char(p2))))
+ return FALSE;
+ *len = l;
+ }
+ else
+ {
+ if ((*p1 != *p2)
+ && (!(diff_flags & DIFF_ICASE)
+ || TOLOWER_LOC(*p1) != TOLOWER_LOC(*p2)))
+ return FALSE;
+ *len = 1;
+ }
+ return TRUE;
+}
+
+/*
+ * Compare strings "s1" and "s2" according to 'diffopt'.
+ * Return non-zero when they are different.
+ */
+ static int
+diff_cmp(char_u *s1, char_u *s2)
+{
+ char_u *p1, *p2;
+ int l;
+
+ if ((diff_flags & DIFF_IBLANK)
+ && (*skipwhite(s1) == NUL || *skipwhite(s2) == NUL))
+ return 0;
+
+ if ((diff_flags & (DIFF_ICASE | ALL_WHITE_DIFF)) == 0)
+ return STRCMP(s1, s2);
+ if ((diff_flags & DIFF_ICASE) && !(diff_flags & ALL_WHITE_DIFF))
+ return MB_STRICMP(s1, s2);
+
+ p1 = s1;
+ p2 = s2;
+
+ // Ignore white space changes and possibly ignore case.
+ while (*p1 != NUL && *p2 != NUL)
+ {
+ if (((diff_flags & DIFF_IWHITE)
+ && VIM_ISWHITE(*p1) && VIM_ISWHITE(*p2))
+ || ((diff_flags & DIFF_IWHITEALL)
+ && (VIM_ISWHITE(*p1) || VIM_ISWHITE(*p2))))
+ {
+ p1 = skipwhite(p1);
+ p2 = skipwhite(p2);
+ }
+ else
+ {
+ if (!diff_equal_char(p1, p2, &l))
+ break;
+ p1 += l;
+ p2 += l;
+ }
+ }
+
+ // Ignore trailing white space.
+ p1 = skipwhite(p1);
+ p2 = skipwhite(p2);
+ if (*p1 != NUL || *p2 != NUL)
+ return 1;
+ return 0;
+}
+
+/*
+ * Return the number of filler lines above "lnum".
+ */
+ int
+diff_check_fill(win_T *wp, linenr_T lnum)
+{
+ int n;
+
+ /* be quick when there are no filler lines */
+ if (!(diff_flags & DIFF_FILLER))
+ return 0;
+ n = diff_check(wp, lnum);
+ if (n <= 0)
+ return 0;
+ return n;
+}
+
+/*
+ * Set the topline of "towin" to match the position in "fromwin", so that they
+ * show the same diff'ed lines.
+ */
+ void
+diff_set_topline(win_T *fromwin, win_T *towin)
+{
+ buf_T *frombuf = fromwin->w_buffer;
+ linenr_T lnum = fromwin->w_topline;
+ int fromidx;
+ int toidx;
+ diff_T *dp;
+ int max_count;
+ int i;
+
+ fromidx = diff_buf_idx(frombuf);
+ if (fromidx == DB_COUNT)
+ return; /* safety check */
+
+ if (curtab->tp_diff_invalid)
+ ex_diffupdate(NULL); /* update after a big change */
+
+ towin->w_topfill = 0;
+
+ /* search for a change that includes "lnum" in the list of diffblocks. */
+ for (dp = curtab->tp_first_diff; dp != NULL; dp = dp->df_next)
+ if (lnum <= dp->df_lnum[fromidx] + dp->df_count[fromidx])
+ break;
+ if (dp == NULL)
+ {
+ /* After last change, compute topline relative to end of file; no
+ * filler lines. */
+ towin->w_topline = towin->w_buffer->b_ml.ml_line_count
+ - (frombuf->b_ml.ml_line_count - lnum);
+ }
+ else
+ {
+ /* Find index for "towin". */
+ toidx = diff_buf_idx(towin->w_buffer);
+ if (toidx == DB_COUNT)
+ return; /* safety check */
+
+ towin->w_topline = lnum + (dp->df_lnum[toidx] - dp->df_lnum[fromidx]);
+ if (lnum >= dp->df_lnum[fromidx])
+ {
+ /* Inside a change: compute filler lines. With three or more
+ * buffers we need to know the largest count. */
+ max_count = 0;
+ for (i = 0; i < DB_COUNT; ++i)
+ if (curtab->tp_diffbuf[i] != NULL
+ && max_count < dp->df_count[i])
+ max_count = dp->df_count[i];
+
+ if (dp->df_count[toidx] == dp->df_count[fromidx])
+ {
+ /* same number of lines: use same filler count */
+ towin->w_topfill = fromwin->w_topfill;
+ }
+ else if (dp->df_count[toidx] > dp->df_count[fromidx])
+ {
+ if (lnum == dp->df_lnum[fromidx] + dp->df_count[fromidx])
+ {
+ /* more lines in towin and fromwin doesn't show diff
+ * lines, only filler lines */
+ if (max_count - fromwin->w_topfill >= dp->df_count[toidx])
+ {
+ /* towin also only shows filler lines */
+ towin->w_topline = dp->df_lnum[toidx]
+ + dp->df_count[toidx];
+ towin->w_topfill = fromwin->w_topfill;
+ }
+ else
+ /* towin still has some diff lines to show */
+ towin->w_topline = dp->df_lnum[toidx]
+ + max_count - fromwin->w_topfill;
+ }
+ }
+ else if (towin->w_topline >= dp->df_lnum[toidx]
+ + dp->df_count[toidx])
+ {
+ /* less lines in towin and no diff lines to show: compute
+ * filler lines */
+ towin->w_topline = dp->df_lnum[toidx] + dp->df_count[toidx];
+ if (diff_flags & DIFF_FILLER)
+ {
+ if (lnum == dp->df_lnum[fromidx] + dp->df_count[fromidx])
+ /* fromwin is also out of diff lines */
+ towin->w_topfill = fromwin->w_topfill;
+ else
+ /* fromwin has some diff lines */
+ towin->w_topfill = dp->df_lnum[fromidx]
+ + max_count - lnum;
+ }
+ }
+ }
+ }
+
+ /* safety check (if diff info gets outdated strange things may happen) */
+ towin->w_botfill = FALSE;
+ if (towin->w_topline > towin->w_buffer->b_ml.ml_line_count)
+ {
+ towin->w_topline = towin->w_buffer->b_ml.ml_line_count;
+ towin->w_botfill = TRUE;
+ }
+ if (towin->w_topline < 1)
+ {
+ towin->w_topline = 1;
+ towin->w_topfill = 0;
+ }
+
+ /* When w_topline changes need to recompute w_botline and cursor position */
+ invalidate_botline_win(towin);
+ changed_line_abv_curs_win(towin);
+
+ check_topfill(towin, FALSE);
+#ifdef FEAT_FOLDING
+ (void)hasFoldingWin(towin, towin->w_topline, &towin->w_topline,
+ NULL, TRUE, NULL);
+#endif
+}
+
+/*
+ * This is called when 'diffopt' is changed.
+ */
+ int
+diffopt_changed(void)
+{
+ char_u *p;
+ int diff_context_new = 6;
+ int diff_flags_new = 0;
+ int diff_foldcolumn_new = 2;
+ long diff_algorithm_new = 0;
+ long diff_indent_heuristic = 0;
+ tabpage_T *tp;
+
+ p = p_dip;
+ while (*p != NUL)
+ {
+ if (STRNCMP(p, "filler", 6) == 0)
+ {
+ p += 6;
+ diff_flags_new |= DIFF_FILLER;
+ }
+ else if (STRNCMP(p, "context:", 8) == 0 && VIM_ISDIGIT(p[8]))
+ {
+ p += 8;
+ diff_context_new = getdigits(&p);
+ }
+ else if (STRNCMP(p, "iblank", 6) == 0)
+ {
+ p += 6;
+ diff_flags_new |= DIFF_IBLANK;
+ }
+ else if (STRNCMP(p, "icase", 5) == 0)
+ {
+ p += 5;
+ diff_flags_new |= DIFF_ICASE;
+ }
+ else if (STRNCMP(p, "iwhiteall", 9) == 0)
+ {
+ p += 9;
+ diff_flags_new |= DIFF_IWHITEALL;
+ }
+ else if (STRNCMP(p, "iwhiteeol", 9) == 0)
+ {
+ p += 9;
+ diff_flags_new |= DIFF_IWHITEEOL;
+ }
+ else if (STRNCMP(p, "iwhite", 6) == 0)
+ {
+ p += 6;
+ diff_flags_new |= DIFF_IWHITE;
+ }
+ else if (STRNCMP(p, "horizontal", 10) == 0)
+ {
+ p += 10;
+ diff_flags_new |= DIFF_HORIZONTAL;
+ }
+ else if (STRNCMP(p, "vertical", 8) == 0)
+ {
+ p += 8;
+ diff_flags_new |= DIFF_VERTICAL;
+ }
+ else if (STRNCMP(p, "foldcolumn:", 11) == 0 && VIM_ISDIGIT(p[11]))
+ {
+ p += 11;
+ diff_foldcolumn_new = getdigits(&p);
+ }
+ else if (STRNCMP(p, "hiddenoff", 9) == 0)
+ {
+ p += 9;
+ diff_flags_new |= DIFF_HIDDEN_OFF;
+ }
+ else if (STRNCMP(p, "indent-heuristic", 16) == 0)
+ {
+ p += 16;
+ diff_indent_heuristic = XDF_INDENT_HEURISTIC;
+ }
+ else if (STRNCMP(p, "internal", 8) == 0)
+ {
+ p += 8;
+ diff_flags_new |= DIFF_INTERNAL;
+ }
+ else if (STRNCMP(p, "algorithm:", 10) == 0)
+ {
+ p += 10;
+ if (STRNCMP(p, "myers", 5) == 0)
+ {
+ p += 5;
+ diff_algorithm_new = 0;
+ }
+ else if (STRNCMP(p, "minimal", 7) == 0)
+ {
+ p += 7;
+ diff_algorithm_new = XDF_NEED_MINIMAL;
+ }
+ else if (STRNCMP(p, "patience", 8) == 0)
+ {
+ p += 8;
+ diff_algorithm_new = XDF_PATIENCE_DIFF;
+ }
+ else if (STRNCMP(p, "histogram", 9) == 0)
+ {
+ p += 9;
+ diff_algorithm_new = XDF_HISTOGRAM_DIFF;
+ }
+ else
+ return FAIL;
+ }
+
+ if (*p != ',' && *p != NUL)
+ return FAIL;
+ if (*p == ',')
+ ++p;
+ }
+
+ diff_algorithm_new |= diff_indent_heuristic;
+
+ /* Can't have both "horizontal" and "vertical". */
+ if ((diff_flags_new & DIFF_HORIZONTAL) && (diff_flags_new & DIFF_VERTICAL))
+ return FAIL;
+
+ // If flags were added or removed, or the algorithm was changed, need to
+ // update the diff.
+ if (diff_flags != diff_flags_new || diff_algorithm != diff_algorithm_new)
+ FOR_ALL_TABPAGES(tp)
+ tp->tp_diff_invalid = TRUE;
+
+ diff_flags = diff_flags_new;
+ diff_context = diff_context_new;
+ diff_foldcolumn = diff_foldcolumn_new;
+ diff_algorithm = diff_algorithm_new;
+
+ diff_redraw(TRUE);
+
+ /* recompute the scroll binding with the new option value, may
+ * remove or add filler lines */
+ check_scrollbind((linenr_T)0, 0L);
+
+ return OK;
+}
+
+/*
+ * Return TRUE if 'diffopt' contains "horizontal".
+ */
+ int
+diffopt_horizontal(void)
+{
+ return (diff_flags & DIFF_HORIZONTAL) != 0;
+}
+
+/*
+ * Return TRUE if 'diffopt' contains "hiddenoff".
+ */
+ int
+diffopt_hiddenoff(void)
+{
+ return (diff_flags & DIFF_HIDDEN_OFF) != 0;
+}
+
+/*
+ * Find the difference within a changed line.
+ * Returns TRUE if the line was added, no other buffer has it.
+ */
+ int
+diff_find_change(
+ win_T *wp,
+ linenr_T lnum,
+ int *startp, /* first char of the change */
+ int *endp) /* last char of the change */
+{
+ char_u *line_org;
+ char_u *line_new;
+ int i;
+ int si_org, si_new;
+ int ei_org, ei_new;
+ diff_T *dp;
+ int idx;
+ int off;
+ int added = TRUE;
+ char_u *p1, *p2;
+ int l;
+
+ /* Make a copy of the line, the next ml_get() will invalidate it. */
+ line_org = vim_strsave(ml_get_buf(wp->w_buffer, lnum, FALSE));
+ if (line_org == NULL)
+ return FALSE;
+
+ idx = diff_buf_idx(wp->w_buffer);
+ if (idx == DB_COUNT) /* cannot happen */
+ {
+ vim_free(line_org);
+ return FALSE;
+ }
+
+ /* search for a change that includes "lnum" in the list of diffblocks. */
+ for (dp = curtab->tp_first_diff; dp != NULL; dp = dp->df_next)
+ if (lnum <= dp->df_lnum[idx] + dp->df_count[idx])
+ break;
+ if (dp == NULL || diff_check_sanity(curtab, dp) == FAIL)
+ {
+ vim_free(line_org);
+ return FALSE;
+ }
+
+ off = lnum - dp->df_lnum[idx];
+
+ for (i = 0; i < DB_COUNT; ++i)
+ if (curtab->tp_diffbuf[i] != NULL && i != idx)
+ {
+ /* Skip lines that are not in the other change (filler lines). */
+ if (off >= dp->df_count[i])
+ continue;
+ added = FALSE;
+ line_new = ml_get_buf(curtab->tp_diffbuf[i],
+ dp->df_lnum[i] + off, FALSE);
+
+ /* Search for start of difference */
+ si_org = si_new = 0;
+ while (line_org[si_org] != NUL)
+ {
+ if (((diff_flags & DIFF_IWHITE)
+ && VIM_ISWHITE(line_org[si_org])
+ && VIM_ISWHITE(line_new[si_new]))
+ || ((diff_flags & DIFF_IWHITEALL)
+ && (VIM_ISWHITE(line_org[si_org])
+ || VIM_ISWHITE(line_new[si_new]))))
+ {
+ si_org = (int)(skipwhite(line_org + si_org) - line_org);
+ si_new = (int)(skipwhite(line_new + si_new) - line_new);
+ }
+ else
+ {
+ if (!diff_equal_char(line_org + si_org, line_new + si_new,
+ &l))
+ break;
+ si_org += l;
+ si_new += l;
+ }
+ }
+ if (has_mbyte)
+ {
+ /* Move back to first byte of character in both lines (may
+ * have "nn^" in line_org and "n^ in line_new). */
+ si_org -= (*mb_head_off)(line_org, line_org + si_org);
+ si_new -= (*mb_head_off)(line_new, line_new + si_new);
+ }
+ if (*startp > si_org)
+ *startp = si_org;
+
+ /* Search for end of difference, if any. */
+ if (line_org[si_org] != NUL || line_new[si_new] != NUL)
+ {
+ ei_org = (int)STRLEN(line_org);
+ ei_new = (int)STRLEN(line_new);
+ while (ei_org >= *startp && ei_new >= si_new
+ && ei_org >= 0 && ei_new >= 0)
+ {
+ if (((diff_flags & DIFF_IWHITE)
+ && VIM_ISWHITE(line_org[ei_org])
+ && VIM_ISWHITE(line_new[ei_new]))
+ || ((diff_flags & DIFF_IWHITEALL)
+ && (VIM_ISWHITE(line_org[ei_org])
+ || VIM_ISWHITE(line_new[ei_new]))))
+ {
+ while (ei_org >= *startp
+ && VIM_ISWHITE(line_org[ei_org]))
+ --ei_org;
+ while (ei_new >= si_new
+ && VIM_ISWHITE(line_new[ei_new]))
+ --ei_new;
+ }
+ else
+ {
+ p1 = line_org + ei_org;
+ p2 = line_new + ei_new;
+ p1 -= (*mb_head_off)(line_org, p1);
+ p2 -= (*mb_head_off)(line_new, p2);
+ if (!diff_equal_char(p1, p2, &l))
+ break;
+ ei_org -= l;
+ ei_new -= l;
+ }
+ }
+ if (*endp < ei_org)
+ *endp = ei_org;
+ }
+ }
+
+ vim_free(line_org);
+ return added;
+}
+
+#if defined(FEAT_FOLDING) || defined(PROTO)
+/*
+ * Return TRUE if line "lnum" is not close to a diff block, this line should
+ * be in a fold.
+ * Return FALSE if there are no diff blocks at all in this window.
+ */
+ int
+diff_infold(win_T *wp, linenr_T lnum)
+{
+ int i;
+ int idx = -1;
+ int other = FALSE;
+ diff_T *dp;
+
+ /* Return if 'diff' isn't set. */
+ if (!wp->w_p_diff)
+ return FALSE;
+
+ for (i = 0; i < DB_COUNT; ++i)
+ {
+ if (curtab->tp_diffbuf[i] == wp->w_buffer)
+ idx = i;
+ else if (curtab->tp_diffbuf[i] != NULL)
+ other = TRUE;
+ }
+
+ /* return here if there are no diffs in the window */
+ if (idx == -1 || !other)
+ return FALSE;
+
+ if (curtab->tp_diff_invalid)
+ ex_diffupdate(NULL); /* update after a big change */
+
+ /* Return if there are no diff blocks. All lines will be folded. */
+ if (curtab->tp_first_diff == NULL)
+ return TRUE;
+
+ for (dp = curtab->tp_first_diff; dp != NULL; dp = dp->df_next)
+ {
+ /* If this change is below the line there can't be any further match. */
+ if (dp->df_lnum[idx] - diff_context > lnum)
+ break;
+ /* If this change ends before the line we have a match. */
+ if (dp->df_lnum[idx] + dp->df_count[idx] + diff_context > lnum)
+ return FALSE;
+ }
+ return TRUE;
+}
+#endif
+
+/*
+ * "dp" and "do" commands.
+ */
+ void
+nv_diffgetput(int put, long count)
+{
+ exarg_T ea;
+ char_u buf[30];
+
+#ifdef FEAT_JOB_CHANNEL
+ if (bt_prompt(curbuf))
+ {
+ vim_beep(BO_OPER);
+ return;
+ }
+#endif
+ if (count == 0)
+ ea.arg = (char_u *)"";
+ else
+ {
+ vim_snprintf((char *)buf, 30, "%ld", count);
+ ea.arg = buf;
+ }
+ if (put)
+ ea.cmdidx = CMD_diffput;
+ else
+ ea.cmdidx = CMD_diffget;
+ ea.addr_count = 0;
+ ea.line1 = curwin->w_cursor.lnum;
+ ea.line2 = curwin->w_cursor.lnum;
+ ex_diffgetput(&ea);
+}
+
+/*
+ * ":diffget"
+ * ":diffput"
+ */
+ void
+ex_diffgetput(exarg_T *eap)
+{
+ linenr_T lnum;
+ int count;
+ linenr_T off = 0;
+ diff_T *dp;
+ diff_T *dprev;
+ diff_T *dfree;
+ int idx_cur;
+ int idx_other;
+ int idx_from;
+ int idx_to;
+ int i;
+ int added;
+ char_u *p;
+ aco_save_T aco;
+ buf_T *buf;
+ int start_skip, end_skip;
+ int new_count;
+ int buf_empty;
+ int found_not_ma = FALSE;
+
+ /* Find the current buffer in the list of diff buffers. */
+ idx_cur = diff_buf_idx(curbuf);
+ if (idx_cur == DB_COUNT)
+ {
+ emsg(_("E99: Current buffer is not in diff mode"));
+ return;
+ }
+
+ if (*eap->arg == NUL)
+ {
+ /* No argument: Find the other buffer in the list of diff buffers. */
+ for (idx_other = 0; idx_other < DB_COUNT; ++idx_other)
+ if (curtab->tp_diffbuf[idx_other] != curbuf
+ && curtab->tp_diffbuf[idx_other] != NULL)
+ {
+ if (eap->cmdidx != CMD_diffput
+ || curtab->tp_diffbuf[idx_other]->b_p_ma)
+ break;
+ found_not_ma = TRUE;
+ }
+ if (idx_other == DB_COUNT)
+ {
+ if (found_not_ma)
+ emsg(_("E793: No other buffer in diff mode is modifiable"));
+ else
+ emsg(_("E100: No other buffer in diff mode"));
+ return;
+ }
+
+ /* Check that there isn't a third buffer in the list */
+ for (i = idx_other + 1; i < DB_COUNT; ++i)
+ if (curtab->tp_diffbuf[i] != curbuf
+ && curtab->tp_diffbuf[i] != NULL
+ && (eap->cmdidx != CMD_diffput || curtab->tp_diffbuf[i]->b_p_ma))
+ {
+ emsg(_("E101: More than two buffers in diff mode, don't know which one to use"));
+ return;
+ }
+ }
+ else
+ {
+ /* Buffer number or pattern given. Ignore trailing white space. */
+ p = eap->arg + STRLEN(eap->arg);
+ while (p > eap->arg && VIM_ISWHITE(p[-1]))
+ --p;
+ for (i = 0; vim_isdigit(eap->arg[i]) && eap->arg + i < p; ++i)
+ ;
+ if (eap->arg + i == p) /* digits only */
+ i = atol((char *)eap->arg);
+ else
+ {
+ i = buflist_findpat(eap->arg, p, FALSE, TRUE, FALSE);
+ if (i < 0)
+ return; /* error message already given */
+ }
+ buf = buflist_findnr(i);
+ if (buf == NULL)
+ {
+ semsg(_("E102: Can't find buffer \"%s\""), eap->arg);
+ return;
+ }
+ if (buf == curbuf)
+ return; /* nothing to do */
+ idx_other = diff_buf_idx(buf);
+ if (idx_other == DB_COUNT)
+ {
+ semsg(_("E103: Buffer \"%s\" is not in diff mode"), eap->arg);
+ return;
+ }
+ }
+
+ diff_busy = TRUE;
+
+ /* When no range given include the line above or below the cursor. */
+ if (eap->addr_count == 0)
+ {
+ /* Make it possible that ":diffget" on the last line gets line below
+ * the cursor line when there is no difference above the cursor. */
+ if (eap->cmdidx == CMD_diffget
+ && eap->line1 == curbuf->b_ml.ml_line_count
+ && diff_check(curwin, eap->line1) == 0
+ && (eap->line1 == 1 || diff_check(curwin, eap->line1 - 1) == 0))
+ ++eap->line2;
+ else if (eap->line1 > 0)
+ --eap->line1;
+ }
+
+ if (eap->cmdidx == CMD_diffget)
+ {
+ idx_from = idx_other;
+ idx_to = idx_cur;
+ }
+ else
+ {
+ idx_from = idx_cur;
+ idx_to = idx_other;
+ /* Need to make the other buffer the current buffer to be able to make
+ * changes in it. */
+ /* set curwin/curbuf to buf and save a few things */
+ aucmd_prepbuf(&aco, curtab->tp_diffbuf[idx_other]);
+ }
+
+ /* May give the warning for a changed buffer here, which can trigger the
+ * FileChangedRO autocommand, which may do nasty things and mess
+ * everything up. */
+ if (!curbuf->b_changed)
+ {
+ change_warning(0);
+ if (diff_buf_idx(curbuf) != idx_to)
+ {
+ emsg(_("E787: Buffer changed unexpectedly"));
+ goto theend;
+ }
+ }
+
+ dprev = NULL;
+ for (dp = curtab->tp_first_diff; dp != NULL; )
+ {
+ if (dp->df_lnum[idx_cur] > eap->line2 + off)
+ break; /* past the range that was specified */
+
+ dfree = NULL;
+ lnum = dp->df_lnum[idx_to];
+ count = dp->df_count[idx_to];
+ if (dp->df_lnum[idx_cur] + dp->df_count[idx_cur] > eap->line1 + off
+ && u_save(lnum - 1, lnum + count) != FAIL)
+ {
+ /* Inside the specified range and saving for undo worked. */
+ start_skip = 0;
+ end_skip = 0;
+ if (eap->addr_count > 0)
+ {
+ /* A range was specified: check if lines need to be skipped. */
+ start_skip = eap->line1 + off - dp->df_lnum[idx_cur];
+ if (start_skip > 0)
+ {
+ /* range starts below start of current diff block */
+ if (start_skip > count)
+ {
+ lnum += count;
+ count = 0;
+ }
+ else
+ {
+ count -= start_skip;
+ lnum += start_skip;
+ }
+ }
+ else
+ start_skip = 0;
+
+ end_skip = dp->df_lnum[idx_cur] + dp->df_count[idx_cur] - 1
+ - (eap->line2 + off);
+ if (end_skip > 0)
+ {
+ /* range ends above end of current/from diff block */
+ if (idx_cur == idx_from) /* :diffput */
+ {
+ i = dp->df_count[idx_cur] - start_skip - end_skip;
+ if (count > i)
+ count = i;
+ }
+ else /* :diffget */
+ {
+ count -= end_skip;
+ end_skip = dp->df_count[idx_from] - start_skip - count;
+ if (end_skip < 0)
+ end_skip = 0;
+ }
+ }
+ else
+ end_skip = 0;
+ }
+
+ buf_empty = BUFEMPTY();
+ added = 0;
+ for (i = 0; i < count; ++i)
+ {
+ /* remember deleting the last line of the buffer */
+ buf_empty = curbuf->b_ml.ml_line_count == 1;
+ ml_delete(lnum, FALSE);
+ --added;
+ }
+ for (i = 0; i < dp->df_count[idx_from] - start_skip - end_skip; ++i)
+ {
+ linenr_T nr;
+
+ nr = dp->df_lnum[idx_from] + start_skip + i;
+ if (nr > curtab->tp_diffbuf[idx_from]->b_ml.ml_line_count)
+ break;
+ p = vim_strsave(ml_get_buf(curtab->tp_diffbuf[idx_from],
+ nr, FALSE));
+ if (p != NULL)
+ {
+ ml_append(lnum + i - 1, p, 0, FALSE);
+ vim_free(p);
+ ++added;
+ if (buf_empty && curbuf->b_ml.ml_line_count == 2)
+ {
+ /* Added the first line into an empty buffer, need to
+ * delete the dummy empty line. */
+ buf_empty = FALSE;
+ ml_delete((linenr_T)2, FALSE);
+ }
+ }
+ }
+ new_count = dp->df_count[idx_to] + added;
+ dp->df_count[idx_to] = new_count;
+
+ if (start_skip == 0 && end_skip == 0)
+ {
+ /* Check if there are any other buffers and if the diff is
+ * equal in them. */
+ for (i = 0; i < DB_COUNT; ++i)
+ if (curtab->tp_diffbuf[i] != NULL && i != idx_from
+ && i != idx_to
+ && !diff_equal_entry(dp, idx_from, i))
+ break;
+ if (i == DB_COUNT)
+ {
+ /* delete the diff entry, the buffers are now equal here */
+ dfree = dp;
+ dp = dp->df_next;
+ if (dprev == NULL)
+ curtab->tp_first_diff = dp;
+ else
+ dprev->df_next = dp;
+ }
+ }
+
+ /* Adjust marks. This will change the following entries! */
+ if (added != 0)
+ {
+ mark_adjust(lnum, lnum + count - 1, (long)MAXLNUM, (long)added);
+ if (curwin->w_cursor.lnum >= lnum)
+ {
+ /* Adjust the cursor position if it's in/after the changed
+ * lines. */
+ if (curwin->w_cursor.lnum >= lnum + count)
+ curwin->w_cursor.lnum += added;
+ else if (added < 0)
+ curwin->w_cursor.lnum = lnum;
+ }
+ }
+ changed_lines(lnum, 0, lnum + count, (long)added);
+
+ if (dfree != NULL)
+ {
+ /* Diff is deleted, update folds in other windows. */
+#ifdef FEAT_FOLDING
+ diff_fold_update(dfree, idx_to);
+#endif
+ vim_free(dfree);
+ }
+ else
+ /* mark_adjust() may have changed the count in a wrong way */
+ dp->df_count[idx_to] = new_count;
+
+ /* When changing the current buffer, keep track of line numbers */
+ if (idx_cur == idx_to)
+ off += added;
+ }
+
+ /* If before the range or not deleted, go to next diff. */
+ if (dfree == NULL)
+ {
+ dprev = dp;
+ dp = dp->df_next;
+ }
+ }
+
+ /* restore curwin/curbuf and a few other things */
+ if (eap->cmdidx != CMD_diffget)
+ {
+ /* Syncing undo only works for the current buffer, but we change
+ * another buffer. Sync undo if the command was typed. This isn't
+ * 100% right when ":diffput" is used in a function or mapping. */
+ if (KeyTyped)
+ u_sync(FALSE);
+ aucmd_restbuf(&aco);
+ }
+
+theend:
+ diff_busy = FALSE;
+ if (diff_need_update)
+ ex_diffupdate(NULL);
+
+ // Check that the cursor is on a valid character and update its
+ // position. When there were filler lines the topline has become
+ // invalid.
+ check_cursor();
+ changed_line_abv_curs();
+
+ if (diff_need_update)
+ // redraw already done by ex_diffupdate()
+ diff_need_update = FALSE;
+ else
+ {
+ // Also need to redraw the other buffers.
+ diff_redraw(FALSE);
+ apply_autocmds(EVENT_DIFFUPDATED, NULL, NULL, FALSE, curbuf);
+ }
+}
+
+#ifdef FEAT_FOLDING
+/*
+ * Update folds for all diff buffers for entry "dp".
+ * Skip buffer with index "skip_idx".
+ * When there are no diffs, all folds are removed.
+ */
+ static void
+diff_fold_update(diff_T *dp, int skip_idx)
+{
+ int i;
+ win_T *wp;
+
+ FOR_ALL_WINDOWS(wp)
+ for (i = 0; i < DB_COUNT; ++i)
+ if (curtab->tp_diffbuf[i] == wp->w_buffer && i != skip_idx)
+ foldUpdate(wp, dp->df_lnum[i],
+ dp->df_lnum[i] + dp->df_count[i]);
+}
+#endif
+
+/*
+ * Return TRUE if buffer "buf" is in diff-mode.
+ */
+ int
+diff_mode_buf(buf_T *buf)
+{
+ tabpage_T *tp;
+
+ FOR_ALL_TABPAGES(tp)
+ if (diff_buf_idx_tp(buf, tp) != DB_COUNT)
+ return TRUE;
+ return FALSE;
+}
+
+/*
+ * Move "count" times in direction "dir" to the next diff block.
+ * Return FAIL if there isn't such a diff block.
+ */
+ int
+diff_move_to(int dir, long count)
+{
+ int idx;
+ linenr_T lnum = curwin->w_cursor.lnum;
+ diff_T *dp;
+
+ idx = diff_buf_idx(curbuf);
+ if (idx == DB_COUNT || curtab->tp_first_diff == NULL)
+ return FAIL;
+
+ if (curtab->tp_diff_invalid)
+ ex_diffupdate(NULL); /* update after a big change */
+
+ if (curtab->tp_first_diff == NULL) /* no diffs today */
+ return FAIL;
+
+ while (--count >= 0)
+ {
+ /* Check if already before first diff. */
+ if (dir == BACKWARD && lnum <= curtab->tp_first_diff->df_lnum[idx])
+ break;
+
+ for (dp = curtab->tp_first_diff; ; dp = dp->df_next)
+ {
+ if (dp == NULL)
+ break;
+ if ((dir == FORWARD && lnum < dp->df_lnum[idx])
+ || (dir == BACKWARD
+ && (dp->df_next == NULL
+ || lnum <= dp->df_next->df_lnum[idx])))
+ {
+ lnum = dp->df_lnum[idx];
+ break;
+ }
+ }
+ }
+
+ /* don't end up past the end of the file */
+ if (lnum > curbuf->b_ml.ml_line_count)
+ lnum = curbuf->b_ml.ml_line_count;
+
+ /* When the cursor didn't move at all we fail. */
+ if (lnum == curwin->w_cursor.lnum)
+ return FAIL;
+
+ setpcmark();
+ curwin->w_cursor.lnum = lnum;
+ curwin->w_cursor.col = 0;
+
+ return OK;
+}
+
+/*
+ * Return the line number in the current window that is closest to "lnum1" in
+ * "buf1" in diff mode.
+ */
+ static linenr_T
+diff_get_corresponding_line_int(
+ buf_T *buf1,
+ linenr_T lnum1)
+{
+ int idx1;
+ int idx2;
+ diff_T *dp;
+ int baseline = 0;
+
+ idx1 = diff_buf_idx(buf1);
+ idx2 = diff_buf_idx(curbuf);
+ if (idx1 == DB_COUNT || idx2 == DB_COUNT || curtab->tp_first_diff == NULL)
+ return lnum1;
+
+ if (curtab->tp_diff_invalid)
+ ex_diffupdate(NULL); /* update after a big change */
+
+ if (curtab->tp_first_diff == NULL) /* no diffs today */
+ return lnum1;
+
+ for (dp = curtab->tp_first_diff; dp != NULL; dp = dp->df_next)
+ {
+ if (dp->df_lnum[idx1] > lnum1)
+ return lnum1 - baseline;
+ if ((dp->df_lnum[idx1] + dp->df_count[idx1]) > lnum1)
+ {
+ /* Inside the diffblock */
+ baseline = lnum1 - dp->df_lnum[idx1];
+ if (baseline > dp->df_count[idx2])
+ baseline = dp->df_count[idx2];
+
+ return dp->df_lnum[idx2] + baseline;
+ }
+ if ( (dp->df_lnum[idx1] == lnum1)
+ && (dp->df_count[idx1] == 0)
+ && (dp->df_lnum[idx2] <= curwin->w_cursor.lnum)
+ && ((dp->df_lnum[idx2] + dp->df_count[idx2])
+ > curwin->w_cursor.lnum))
+ /*
+ * Special case: if the cursor is just after a zero-count
+ * block (i.e. all filler) and the target cursor is already
+ * inside the corresponding block, leave the target cursor
+ * unmoved. This makes repeated CTRL-W W operations work
+ * as expected.
+ */
+ return curwin->w_cursor.lnum;
+ baseline = (dp->df_lnum[idx1] + dp->df_count[idx1])
+ - (dp->df_lnum[idx2] + dp->df_count[idx2]);
+ }
+
+ /* If we get here then the cursor is after the last diff */
+ return lnum1 - baseline;
+}
+
+/*
+ * Return the line number in the current window that is closest to "lnum1" in
+ * "buf1" in diff mode. Checks the line number to be valid.
+ */
+ linenr_T
+diff_get_corresponding_line(buf_T *buf1, linenr_T lnum1)
+{
+ linenr_T lnum = diff_get_corresponding_line_int(buf1, lnum1);
+
+ /* don't end up past the end of the file */
+ if (lnum > curbuf->b_ml.ml_line_count)
+ return curbuf->b_ml.ml_line_count;
+ return lnum;
+}
+
+/*
+ * For line "lnum" in the current window find the equivalent lnum in window
+ * "wp", compensating for inserted/deleted lines.
+ */
+ linenr_T
+diff_lnum_win(linenr_T lnum, win_T *wp)
+{
+ diff_T *dp;
+ int idx;
+ int i;
+ linenr_T n;
+
+ idx = diff_buf_idx(curbuf);
+ if (idx == DB_COUNT) /* safety check */
+ return (linenr_T)0;
+
+ if (curtab->tp_diff_invalid)
+ ex_diffupdate(NULL); /* update after a big change */
+
+ /* search for a change that includes "lnum" in the list of diffblocks. */
+ for (dp = curtab->tp_first_diff; dp != NULL; dp = dp->df_next)
+ if (lnum <= dp->df_lnum[idx] + dp->df_count[idx])
+ break;
+
+ /* When after the last change, compute relative to the last line number. */
+ if (dp == NULL)
+ return wp->w_buffer->b_ml.ml_line_count
+ - (curbuf->b_ml.ml_line_count - lnum);
+
+ /* Find index for "wp". */
+ i = diff_buf_idx(wp->w_buffer);
+ if (i == DB_COUNT) /* safety check */
+ return (linenr_T)0;
+
+ n = lnum + (dp->df_lnum[i] - dp->df_lnum[idx]);
+ if (n > dp->df_lnum[i] + dp->df_count[i])
+ n = dp->df_lnum[i] + dp->df_count[i];
+ return n;
+}
+
+/*
+ * Handle an ED style diff line.
+ * Return FAIL if the line does not contain diff info.
+ */
+ static int
+parse_diff_ed(
+ char_u *line,
+ linenr_T *lnum_orig,
+ long *count_orig,
+ linenr_T *lnum_new,
+ long *count_new)
+{
+ char_u *p;
+ long f1, l1, f2, l2;
+ int difftype;
+
+ // The line must be one of three formats:
+ // change: {first}[,{last}]c{first}[,{last}]
+ // append: {first}a{first}[,{last}]
+ // delete: {first}[,{last}]d{first}
+ p = line;
+ f1 = getdigits(&p);
+ if (*p == ',')
+ {
+ ++p;
+ l1 = getdigits(&p);
+ }
+ else
+ l1 = f1;
+ if (*p != 'a' && *p != 'c' && *p != 'd')
+ return FAIL; // invalid diff format
+ difftype = *p++;
+ f2 = getdigits(&p);
+ if (*p == ',')
+ {
+ ++p;
+ l2 = getdigits(&p);
+ }
+ else
+ l2 = f2;
+ if (l1 < f1 || l2 < f2)
+ return FAIL;
+
+ if (difftype == 'a')
+ {
+ *lnum_orig = f1 + 1;
+ *count_orig = 0;
+ }
+ else
+ {
+ *lnum_orig = f1;
+ *count_orig = l1 - f1 + 1;
+ }
+ if (difftype == 'd')
+ {
+ *lnum_new = f2 + 1;
+ *count_new = 0;
+ }
+ else
+ {
+ *lnum_new = f2;
+ *count_new = l2 - f2 + 1;
+ }
+ return OK;
+}
+
+/*
+ * Parses unified diff with zero(!) context lines.
+ * Return FAIL if there is no diff information in "line".
+ */
+ static int
+parse_diff_unified(
+ char_u *line,
+ linenr_T *lnum_orig,
+ long *count_orig,
+ linenr_T *lnum_new,
+ long *count_new)
+{
+ char_u *p;
+ long oldline, oldcount, newline, newcount;
+
+ // Parse unified diff hunk header:
+ // @@ -oldline,oldcount +newline,newcount @@
+ p = line;
+ if (*p++ == '@' && *p++ == '@' && *p++ == ' ' && *p++ == '-')
+ {
+ oldline = getdigits(&p);
+ if (*p == ',')
+ {
+ ++p;
+ oldcount = getdigits(&p);
+ }
+ else
+ oldcount = 1;
+ if (*p++ == ' ' && *p++ == '+')
+ {
+ newline = getdigits(&p);
+ if (*p == ',')
+ {
+ ++p;
+ newcount = getdigits(&p);
+ }
+ else
+ newcount = 1;
+ }
+ else
+ return FAIL; // invalid diff format
+
+ if (oldcount == 0)
+ oldline += 1;
+ if (newcount == 0)
+ newline += 1;
+ if (newline == 0)
+ newline = 1;
+
+ *lnum_orig = oldline;
+ *count_orig = oldcount;
+ *lnum_new = newline;
+ *count_new = newcount;
+
+ return OK;
+ }
+
+ return FAIL;
+}
+
+/*
+ * Callback function for the xdl_diff() function.
+ * Stores the diff output in a grow array.
+ */
+ static int
+xdiff_out(void *priv, mmbuffer_t *mb, int nbuf)
+{
+ diffout_T *dout = (diffout_T *)priv;
+ char_u *p;
+
+ // The header line always comes by itself, text lines in at least two
+ // parts. We drop the text part.
+ if (nbuf > 1)
+ return 0;
+
+ // sanity check
+ if (STRNCMP(mb[0].ptr, "@@ ", 3) != 0)
+ return 0;
+
+ if (ga_grow(&dout->dout_ga, 1) == FAIL)
+ return -1;
+ p = vim_strnsave((char_u *)mb[0].ptr, mb[0].size);
+ if (p == NULL)
+ return -1;
+ ((char_u **)dout->dout_ga.ga_data)[dout->dout_ga.ga_len++] = p;
+ return 0;
+}
+
+#endif /* FEAT_DIFF */
diff --git a/src/digraph.c b/src/digraph.c
new file mode 100644
index 0000000..d936136
--- /dev/null
+++ b/src/digraph.c
@@ -0,0 +1,2472 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * digraph.c: code for digraphs
+ */
+
+#include "vim.h"
+
+#if defined(FEAT_DIGRAPHS) || defined(PROTO)
+
+typedef int result_T;
+
+typedef struct digraph
+{
+ char_u char1;
+ char_u char2;
+ result_T result;
+} digr_T;
+
+static void printdigraph(digr_T *dp, result_T *previous);
+
+/* digraphs added by the user */
+static garray_T user_digraphs = {0, 0, (int)sizeof(digr_T), 10, NULL};
+
+/*
+ * Note: Characters marked with XX are not included literally, because some
+ * compilers cannot handle them (Amiga SAS/C is the most picky one).
+ */
+static digr_T digraphdefault[] =
+
+#ifdef __MINT__
+ /*
+ * ATARI digraphs
+ */
+ {{'C', ',', 128}, /* ~@ XX */
+ {'u', '"', 129}, /* */
+ {'e', '\'', 130}, /* ‚ */
+ {'a', '^', 131}, /* ƒ */
+ {'a', '"', 132}, /* „ */
+ {'a', '`', 133}, /* … */
+ {'a', '@', 134}, /* † */
+ {'c', ',', 135}, /* ~G XX */
+ {'e', '^', 136}, /* ~H XX */
+ {'e', '"', 137}, /* ‰ */
+ {'e', '`', 138}, /* Š */
+ {'i', '"', 139}, /* ‹ */
+ {'i', '^', 140}, /* Œ */
+ {'i', '`', 141}, /* */
+ {'A', '"', 142}, /* Ž */
+ {'A', '@', 143}, /* */
+ {'E', '\'', 144}, /* */
+ {'a', 'e', 145}, /* ‘ */
+ {'A', 'E', 146}, /* ’ */
+ {'o', '^', 147}, /* “ */
+ {'o', '"', 148}, /* ” */
+ {'o', '`', 149}, /* • */
+ {'u', '^', 150}, /* – */
+ {'u', '`', 151}, /* — */
+ {'y', '"', 152}, /* ˜ */
+ {'O', '"', 153}, /* ™ */
+ {'U', '"', 154}, /* š */
+ {'c', '|', 155}, /* › */
+ {'$', '$', 156}, /* œ */
+ {'Y', '-', 157}, /* ~] XX */
+ {'s', 's', 158}, /* ž */
+ {'f', 'f', 159}, /* Ÿ */
+ {'a', '\'', 160}, /*   */
+ {'i', '\'', 161}, /* ¡ */
+ {'o', '\'', 162}, /* ¢ */
+ {'u', '\'', 163}, /* £ */
+ {'n', '~', 164}, /* ¤ */
+ {'N', '~', 165}, /* ¥ */
+ {'a', 'a', 166}, /* ¦ */
+ {'o', 'o', 167}, /* § */
+ {'~', '?', 168}, /* ¨ */
+ {'-', 'a', 169}, /* © */
+ {'a', '-', 170}, /* ª */
+ {'1', '2', 171}, /* « */
+ {'1', '4', 172}, /* ¬ */
+ {'~', '!', 173}, /* ­ */
+ {'<', '<', 174}, /* ® */
+ {'>', '>', 175}, /* ¯ */
+ {'j', 'u', 230}, /* æ */
+ {'o', '/', 237}, /* í */
+ {'+', '-', 241}, /* ñ */
+ {'>', '=', 242}, /* ò */
+ {'<', '=', 243}, /* ó */
+ {':', '-', 246}, /* ö */
+ {'~', '~', 247}, /* ÷ */
+ {'~', 'o', 248}, /* ø */
+ {'2', '2', 253}, /* ý */
+ {NUL, NUL, NUL}
+ };
+
+#else /* !__MINT__ */
+# ifdef HPUX_DIGRAPHS
+
+ /*
+ * different HPUX digraphs
+ */
+ {{'A', '`', 161}, /* ¡ */
+ {'A', '^', 162}, /* ¢ */
+ {'E', '`', 163}, /* £ */
+ {'E', '^', 164}, /* ¤ */
+ {'E', '"', 165}, /* ¥ */
+ {'I', '^', 166}, /* ¦ */
+ {'I', '"', 167}, /* § */
+ {'\'', '\'', 168}, /* ¨ */
+ {'`', '`', 169}, /* © */
+ {'^', '^', 170}, /* ª */
+ {'"', '"', 171}, /* « */
+ {'~', '~', 172}, /* ¬ */
+ {'U', '`', 173}, /* ­ */
+ {'U', '^', 174}, /* ® */
+ {'L', '=', 175}, /* ¯ */
+ {'~', '_', 176}, /* ° */
+ {'Y', '\'', 177}, /* ± */
+ {'y', '\'', 178}, /* ² */
+ {'~', 'o', 179}, /* ³ */
+ {'C', ',', 180}, /* ´ */
+ {'c', ',', 181}, /* µ */
+ {'N', '~', 182}, /* ¶ */
+ {'n', '~', 183}, /* · */
+ {'~', '!', 184}, /* ¸ */
+ {'~', '?', 185}, /* ¹ */
+ {'o', 'x', 186}, /* º */
+ {'L', '-', 187}, /* » */
+ {'Y', '=', 188}, /* ¼ */
+ {'p', 'p', 189}, /* ½ */
+ {'f', 'l', 190}, /* ¾ */
+ {'c', '|', 191}, /* ¿ */
+ {'a', '^', 192}, /* À */
+ {'e', '^', 193}, /* Á */
+ {'o', '^', 194}, /* Â */
+ {'u', '^', 195}, /* Ã */
+ {'a', '\'', 196}, /* Ä */
+ {'e', '\'', 197}, /* Å */
+ {'o', '\'', 198}, /* Æ */
+ {'u', '\'', 199}, /* Ç */
+ {'a', '`', 200}, /* È */
+ {'e', '`', 201}, /* É */
+ {'o', '`', 202}, /* Ê */
+ {'u', '`', 203}, /* Ë */
+ {'a', '"', 204}, /* Ì */
+ {'e', '"', 205}, /* Í */
+ {'o', '"', 206}, /* Î */
+ {'u', '"', 207}, /* Ï */
+ {'A', 'o', 208}, /* Ð */
+ {'i', '^', 209}, /* Ñ */
+ {'O', '/', 210}, /* Ò */
+ {'A', 'E', 211}, /* Ó */
+ {'a', 'o', 212}, /* Ô */
+ {'i', '\'', 213}, /* Õ */
+ {'o', '/', 214}, /* Ö */
+ {'a', 'e', 215}, /* × */
+ {'A', '"', 216}, /* Ø */
+ {'i', '`', 217}, /* Ù */
+ {'O', '"', 218}, /* Ú */
+ {'U', '"', 219}, /* Û */
+ {'E', '\'', 220}, /* Ü */
+ {'i', '"', 221}, /* Ý */
+ {'s', 's', 222}, /* Þ */
+ {'O', '^', 223}, /* ß */
+ {'A', '\'', 224}, /* à */
+ {'A', '~', 225}, /* á */
+ {'a', '~', 226}, /* â */
+ {'D', '-', 227}, /* ã */
+ {'d', '-', 228}, /* ä */
+ {'I', '\'', 229}, /* å */
+ {'I', '`', 230}, /* æ */
+ {'O', '\'', 231}, /* ç */
+ {'O', '`', 232}, /* è */
+ {'O', '~', 233}, /* é */
+ {'o', '~', 234}, /* ê */
+ {'S', '~', 235}, /* ë */
+ {'s', '~', 236}, /* ì */
+ {'U', '\'', 237}, /* í */
+ {'Y', '"', 238}, /* î */
+ {'y', '"', 239}, /* ï */
+ {'p', '-', 240}, /* ð */
+ {'p', '~', 241}, /* ñ */
+ {'~', '.', 242}, /* ò */
+ {'j', 'u', 243}, /* ó */
+ {'P', 'p', 244}, /* ô */
+ {'3', '4', 245}, /* õ */
+ {'-', '-', 246}, /* ö */
+ {'1', '4', 247}, /* ÷ */
+ {'1', '2', 248}, /* ø */
+ {'a', '_', 249}, /* ù */
+ {'o', '_', 250}, /* ú */
+ {'<', '<', 251}, /* û */
+ {'x', 'x', 252}, /* ü */
+ {'>', '>', 253}, /* ý */
+ {'+', '-', 254}, /* þ */
+ {'n', 'u', 255}, /* x XX */
+ {NUL, NUL, NUL}
+ };
+
+# else /* !HPUX_DIGRAPHS */
+
+# ifdef EBCDIC
+
+ /*
+ * EBCDIC - ISO digraphs
+ * TODO: EBCDIC Table is Code-Page 1047
+ */
+ {{'a', '^', 66}, /* â */
+ {'a', '"', 67}, /* ä */
+ {'a', '`', 68}, /* à */
+ {'a', '\'', 69}, /* á */
+ {'a', '~', 70}, /* ã */
+ {'a', '@', 71}, /* å */
+ {'a', 'a', 71}, /* å */
+ {'c', ',', 72}, /* ç */
+ {'n', '~', 73}, /* ñ */
+ {'c', '|', 74}, /* ¢ */
+ {'e', '\'', 81}, /* é */
+ {'e', '^', 82}, /* ê */
+ {'e', '"', 83}, /* ë */
+ {'e', '`', 84}, /* è */
+ {'i', '\'', 85}, /* í */
+ {'i', '^', 86}, /* î */
+ {'i', '"', 87}, /* ï */
+ {'i', '`', 88}, /* ì */
+ {'s', 's', 89}, /* ß */
+ {'A', '^', 98}, /* Â */
+ {'A', '"', 99}, /* Ä */
+ {'A', '`', 100}, /* À */
+ {'A', '\'', 101}, /* Á */
+ {'A', '~', 102}, /* Ã */
+ {'A', '@', 103}, /* Å */
+ {'A', 'A', 103}, /* Å */
+ {'C', ',', 104}, /* Ç */
+ {'N', '~', 105}, /* Ñ */
+ {'|', '|', 106}, /* ¦ */
+ {'o', '/', 112}, /* ø */
+ {'E', '\'', 113}, /* É */
+ {'E', '^', 114}, /* Ê */
+ {'E', '"', 115}, /* Ë */
+ {'E', '`', 116}, /* È */
+ {'I', '\'', 117}, /* Í */
+ {'I', '^', 118}, /* Î */
+ {'I', '"', 119}, /* Ï */
+ {'I', '`', 120}, /* Ì */
+ {'O', '/', 128}, /* 0/ XX */
+ {'<', '<', 138}, /* « */
+ {'>', '>', 139}, /* » */
+ {'d', '-', 140}, /* ð */
+ {'y', '\'', 141}, /* ý */
+ {'i', 'p', 142}, /* þ */
+ {'+', '-', 143}, /* ± */
+ {'~', 'o', 144}, /* ° */
+ {'a', '-', 154}, /* ª */
+ {'o', '-', 155}, /* º */
+ {'a', 'e', 156}, /* æ */
+ {',', ',', 157}, /* , XX */
+ {'A', 'E', 158}, /* Æ */
+ {'o', 'x', 159}, /* ¤ - currency symbol in ISO 8859-1 */
+ {'e', '=', 159}, /* ¤ - euro symbol in ISO 8859-15 */
+ {'E', 'u', 159}, /* ¤ - euro symbol in ISO 8859-15 */
+ {'j', 'u', 160}, /* µ */
+ {'y', '"', 167}, /* x XX */
+ {'~', '!', 170}, /* ¡ */
+ {'~', '?', 171}, /* ¿ */
+ {'D', '-', 172}, /* Ð */
+ {'I', 'p', 174}, /* Þ */
+ {'r', 'O', 175}, /* ® */
+ {'-', ',', 176}, /* ¬ */
+ {'$', '$', 177}, /* £ */
+ {'Y', '-', 178}, /* ¥ */
+ {'~', '.', 179}, /* · */
+ {'c', 'O', 180}, /* © */
+ {'p', 'a', 181}, /* § */
+ {'p', 'p', 182}, /* ¶ */
+ {'1', '4', 183}, /* ¼ */
+ {'1', '2', 184}, /* ½ */
+ {'3', '4', 185}, /* ¾ */
+ {'Y', '\'', 186}, /* Ý */
+ {'"', '"', 187}, /* ¨ */
+ {'-', '=', 188}, /* ¯ */
+ {'\'', '\'', 190}, /* ´ */
+ {'O', 'E', 191}, /* × - OE in ISO 8859-15 */
+ {'/', '\\', 191}, /* × - multiplication symbol in ISO 8859-1 */
+ {'-', '-', 202}, /* ­ */
+ {'o', '^', 203}, /* ô */
+ {'o', '"', 204}, /* ö */
+ {'o', '`', 205}, /* ò */
+ {'o', '\'', 206}, /* ó */
+ {'o', '~', 207}, /* õ */
+ {'1', '1', 218}, /* ¹ */
+ {'u', '^', 219}, /* û */
+ {'u', '"', 220}, /* ü */
+ {'u', '`', 221}, /* ù */
+ {'u', '\'', 222}, /* ú */
+ {':', '-', 225}, /* ÷ - division symbol in ISO 8859-1 */
+ {'o', 'e', 225}, /* ÷ - oe in ISO 8859-15 */
+ {'2', '2', 234}, /* ² */
+ {'O', '^', 235}, /* Ô */
+ {'O', '"', 236}, /* Ö */
+ {'O', '`', 237}, /* Ò */
+ {'O', '\'', 238}, /* Ó */
+ {'O', '~', 239}, /* Õ */
+ {'3', '3', 250}, /* ³ */
+ {'U', '^', 251}, /* Û */
+ {'U', '"', 252}, /* Ü */
+ {'U', '`', 253}, /* Ù */
+ {'U', '\'', 254}, /* Ú */
+ {NUL, NUL, NUL}
+ };
+
+# else
+# ifdef OLD_DIGRAPHS
+
+ /*
+ * digraphs compatible with Vim 5.x
+ */
+ {{'~', '!', 161}, /* ¡ */
+ {'c', '|', 162}, /* ¢ */
+ {'$', '$', 163}, /* £ */
+ {'o', 'x', 164}, /* ¤ - currency symbol in ISO 8859-1 */
+ {'e', '=', 164}, /* ¤ - euro symbol in ISO 8859-15 */
+ {'Y', '-', 165}, /* ¥ */
+ {'|', '|', 166}, /* ¦ */
+ {'p', 'a', 167}, /* § */
+ {'"', '"', 168}, /* ¨ */
+ {'c', 'O', 169}, /* © */
+ {'a', '-', 170}, /* ª */
+ {'<', '<', 171}, /* « */
+ {'-', ',', 172}, /* ¬ */
+ {'-', '-', 173}, /* ­ */
+ {'r', 'O', 174}, /* ® */
+ {'-', '=', 175}, /* ¯ */
+ {'~', 'o', 176}, /* ° */
+ {'+', '-', 177}, /* ± */
+ {'2', '2', 178}, /* ² */
+ {'3', '3', 179}, /* ³ */
+ {'\'', '\'', 180}, /* ´ */
+ {'j', 'u', 181}, /* µ */
+ {'p', 'p', 182}, /* ¶ */
+ {'~', '.', 183}, /* · */
+ {',', ',', 184}, /* ¸ */
+ {'1', '1', 185}, /* ¹ */
+ {'o', '-', 186}, /* º */
+ {'>', '>', 187}, /* » */
+ {'1', '4', 188}, /* ¼ */
+ {'1', '2', 189}, /* ½ */
+ {'3', '4', 190}, /* ¾ */
+ {'~', '?', 191}, /* ¿ */
+ {'A', '`', 192}, /* À */
+ {'A', '\'', 193}, /* Á */
+ {'A', '^', 194}, /* Â */
+ {'A', '~', 195}, /* Ã */
+ {'A', '"', 196}, /* Ä */
+ {'A', '@', 197}, /* Å */
+ {'A', 'A', 197}, /* Å */
+ {'A', 'E', 198}, /* Æ */
+ {'C', ',', 199}, /* Ç */
+ {'E', '`', 200}, /* È */
+ {'E', '\'', 201}, /* É */
+ {'E', '^', 202}, /* Ê */
+ {'E', '"', 203}, /* Ë */
+ {'I', '`', 204}, /* Ì */
+ {'I', '\'', 205}, /* Í */
+ {'I', '^', 206}, /* Î */
+ {'I', '"', 207}, /* Ï */
+ {'D', '-', 208}, /* Ð */
+ {'N', '~', 209}, /* Ñ */
+ {'O', '`', 210}, /* Ò */
+ {'O', '\'', 211}, /* Ó */
+ {'O', '^', 212}, /* Ô */
+ {'O', '~', 213}, /* Õ */
+ {'O', '"', 214}, /* Ö */
+ {'/', '\\', 215}, /* × - multiplication symbol in ISO 8859-1 */
+ {'O', 'E', 215}, /* × - OE in ISO 8859-15 */
+ {'O', '/', 216}, /* Ø */
+ {'U', '`', 217}, /* Ù */
+ {'U', '\'', 218}, /* Ú */
+ {'U', '^', 219}, /* Û */
+ {'U', '"', 220}, /* Ü */
+ {'Y', '\'', 221}, /* Ý */
+ {'I', 'p', 222}, /* Þ */
+ {'s', 's', 223}, /* ß */
+ {'a', '`', 224}, /* à */
+ {'a', '\'', 225}, /* á */
+ {'a', '^', 226}, /* â */
+ {'a', '~', 227}, /* ã */
+ {'a', '"', 228}, /* ä */
+ {'a', '@', 229}, /* å */
+ {'a', 'a', 229}, /* å */
+ {'a', 'e', 230}, /* æ */
+ {'c', ',', 231}, /* ç */
+ {'e', '`', 232}, /* è */
+ {'e', '\'', 233}, /* é */
+ {'e', '^', 234}, /* ê */
+ {'e', '"', 235}, /* ë */
+ {'i', '`', 236}, /* ì */
+ {'i', '\'', 237}, /* í */
+ {'i', '^', 238}, /* î */
+ {'i', '"', 239}, /* ï */
+ {'d', '-', 240}, /* ð */
+ {'n', '~', 241}, /* ñ */
+ {'o', '`', 242}, /* ò */
+ {'o', '\'', 243}, /* ó */
+ {'o', '^', 244}, /* ô */
+ {'o', '~', 245}, /* õ */
+ {'o', '"', 246}, /* ö */
+ {':', '-', 247}, /* ÷ - division symbol in ISO 8859-1 */
+ {'o', 'e', 247}, /* ÷ - oe in ISO 8859-15 */
+ {'o', '/', 248}, /* ø */
+ {'u', '`', 249}, /* ù */
+ {'u', '\'', 250}, /* ú */
+ {'u', '^', 251}, /* û */
+ {'u', '"', 252}, /* ü */
+ {'y', '\'', 253}, /* ý */
+ {'i', 'p', 254}, /* þ */
+ {'y', '"', 255}, /* x XX */
+ {NUL, NUL, NUL}
+ };
+# else /* OLD_DIGRAPHS */
+
+ /*
+ * digraphs for Unicode from RFC1345
+ * (also work for ISO-8859-1 aka latin1)
+ */
+ {
+ {'N', 'U', 0x0a}, /* LF for NUL */
+ {'S', 'H', 0x01},
+ {'S', 'X', 0x02},
+ {'E', 'X', 0x03},
+ {'E', 'T', 0x04},
+ {'E', 'Q', 0x05},
+ {'A', 'K', 0x06},
+ {'B', 'L', 0x07},
+ {'B', 'S', 0x08},
+ {'H', 'T', 0x09},
+ {'L', 'F', 0x0a},
+ {'V', 'T', 0x0b},
+ {'F', 'F', 0x0c},
+ {'C', 'R', 0x0d},
+ {'S', 'O', 0x0e},
+ {'S', 'I', 0x0f},
+ {'D', 'L', 0x10},
+ {'D', '1', 0x11},
+ {'D', '2', 0x12},
+ {'D', '3', 0x13},
+ {'D', '4', 0x14},
+ {'N', 'K', 0x15},
+ {'S', 'Y', 0x16},
+ {'E', 'B', 0x17},
+ {'C', 'N', 0x18},
+ {'E', 'M', 0x19},
+ {'S', 'B', 0x1a},
+ {'E', 'C', 0x1b},
+ {'F', 'S', 0x1c},
+ {'G', 'S', 0x1d},
+ {'R', 'S', 0x1e},
+ {'U', 'S', 0x1f},
+ {'S', 'P', 0x20},
+ {'N', 'b', 0x23},
+ {'D', 'O', 0x24},
+ {'A', 't', 0x40},
+ {'<', '(', 0x5b},
+ {'/', '/', 0x5c},
+ {')', '>', 0x5d},
+ {'\'', '>', 0x5e},
+ {'\'', '!', 0x60},
+ {'(', '!', 0x7b},
+ {'!', '!', 0x7c},
+ {'!', ')', 0x7d},
+ {'\'', '?', 0x7e},
+ {'D', 'T', 0x7f},
+ {'P', 'A', 0x80},
+ {'H', 'O', 0x81},
+ {'B', 'H', 0x82},
+ {'N', 'H', 0x83},
+ {'I', 'N', 0x84},
+ {'N', 'L', 0x85},
+ {'S', 'A', 0x86},
+ {'E', 'S', 0x87},
+ {'H', 'S', 0x88},
+ {'H', 'J', 0x89},
+ {'V', 'S', 0x8a},
+ {'P', 'D', 0x8b},
+ {'P', 'U', 0x8c},
+ {'R', 'I', 0x8d},
+ {'S', '2', 0x8e},
+ {'S', '3', 0x8f},
+ {'D', 'C', 0x90},
+ {'P', '1', 0x91},
+ {'P', '2', 0x92},
+ {'T', 'S', 0x93},
+ {'C', 'C', 0x94},
+ {'M', 'W', 0x95},
+ {'S', 'G', 0x96},
+ {'E', 'G', 0x97},
+ {'S', 'S', 0x98},
+ {'G', 'C', 0x99},
+ {'S', 'C', 0x9a},
+ {'C', 'I', 0x9b},
+ {'S', 'T', 0x9c},
+ {'O', 'C', 0x9d},
+ {'P', 'M', 0x9e},
+ {'A', 'C', 0x9f},
+ {'N', 'S', 0xa0},
+#define DG_START_LATIN 0xa1
+ {'!', 'I', 0xa1},
+ {'~', '!', 0xa1}, // ¡ Vim 5.x compatible
+ {'C', 't', 0xa2},
+ {'c', '|', 0xa2}, // ¢ Vim 5.x compatible
+ {'P', 'd', 0xa3},
+ {'$', '$', 0xa3}, // £ Vim 5.x compatible
+ {'C', 'u', 0xa4},
+ {'o', 'x', 0xa4}, // ¤ Vim 5.x compatible
+ {'Y', 'e', 0xa5},
+ {'Y', '-', 0xa5}, // ¥ Vim 5.x compatible
+ {'B', 'B', 0xa6},
+ {'|', '|', 0xa6}, // ¦ Vim 5.x compatible
+ {'S', 'E', 0xa7},
+ {'\'', ':', 0xa8},
+ {'C', 'o', 0xa9},
+ {'c', 'O', 0xa9}, // © Vim 5.x compatible
+ {'-', 'a', 0xaa},
+ {'<', '<', 0xab},
+ {'N', 'O', 0xac},
+ {'-', ',', 0xac}, // ¬ Vim 5.x compatible
+ {'-', '-', 0xad},
+ {'R', 'g', 0xae},
+ {'\'', 'm', 0xaf},
+ {'-', '=', 0xaf}, // ¯ Vim 5.x compatible
+ {'D', 'G', 0xb0},
+ {'~', 'o', 0xb0}, // ° Vim 5.x compatible
+ {'+', '-', 0xb1},
+ {'2', 'S', 0xb2},
+ {'2', '2', 0xb2}, // ² Vim 5.x compatible
+ {'3', 'S', 0xb3},
+ {'3', '3', 0xb3}, // ³ Vim 5.x compatible
+ {'\'', '\'', 0xb4},
+ {'M', 'y', 0xb5},
+ {'P', 'I', 0xb6},
+ {'p', 'p', 0xb6}, // ¶ Vim 5.x compatible
+ {'.', 'M', 0xb7},
+ {'~', '.', 0xb7}, // · Vim 5.x compatible
+ {'\'', ',', 0xb8},
+ {'1', 'S', 0xb9},
+ {'1', '1', 0xb9}, // ¹ Vim 5.x compatible
+ {'-', 'o', 0xba},
+ {'>', '>', 0xbb},
+ {'1', '4', 0xbc},
+ {'1', '2', 0xbd},
+ {'3', '4', 0xbe},
+ {'?', 'I', 0xbf},
+ {'~', '?', 0xbf}, // ¿ Vim 5.x compatible
+ {'A', '!', 0xc0},
+ {'A', '`', 0xc0}, // À Vim 5.x compatible
+ {'A', '\'', 0xc1},
+ {'A', '>', 0xc2},
+ {'A', '^', 0xc2}, // Â Vim 5.x compatible
+ {'A', '?', 0xc3},
+ {'A', '~', 0xc3}, // Ã Vim 5.x compatible
+ {'A', ':', 0xc4},
+ {'A', '"', 0xc4}, // Ä Vim 5.x compatible
+ {'A', 'A', 0xc5},
+ {'A', '@', 0xc5}, // Å Vim 5.x compatible
+ {'A', 'E', 0xc6},
+ {'C', ',', 0xc7},
+ {'E', '!', 0xc8},
+ {'E', '`', 0xc8}, // È Vim 5.x compatible
+ {'E', '\'', 0xc9},
+ {'E', '>', 0xca},
+ {'E', '^', 0xca}, // Ê Vim 5.x compatible
+ {'E', ':', 0xcb},
+ {'E', '"', 0xcb}, // Ë Vim 5.x compatible
+ {'I', '!', 0xcc},
+ {'I', '`', 0xcc}, // Ì Vim 5.x compatible
+ {'I', '\'', 0xcd},
+ {'I', '>', 0xce},
+ {'I', '^', 0xce}, // Î Vim 5.x compatible
+ {'I', ':', 0xcf},
+ {'I', '"', 0xcf}, // Ï Vim 5.x compatible
+ {'D', '-', 0xd0},
+ {'N', '?', 0xd1},
+ {'N', '~', 0xd1}, // Ñ Vim 5.x compatible
+ {'O', '!', 0xd2},
+ {'O', '`', 0xd2}, // Ò Vim 5.x compatible
+ {'O', '\'', 0xd3},
+ {'O', '>', 0xd4},
+ {'O', '^', 0xd4}, // Ô Vim 5.x compatible
+ {'O', '?', 0xd5},
+ {'O', '~', 0xd5}, // Õ Vim 5.x compatible
+ {'O', ':', 0xd6},
+ {'*', 'X', 0xd7},
+ {'/', '\\', 0xd7}, // × Vim 5.x compatible
+ {'O', '/', 0xd8},
+ {'U', '!', 0xd9},
+ {'U', '`', 0xd9}, // Ù Vim 5.x compatible
+ {'U', '\'', 0xda},
+ {'U', '>', 0xdb},
+ {'U', '^', 0xdb}, // Û Vim 5.x compatible
+ {'U', ':', 0xdc},
+ {'Y', '\'', 0xdd},
+ {'T', 'H', 0xde},
+ {'I', 'p', 0xde}, // Þ Vim 5.x compatible
+ {'s', 's', 0xdf},
+ {'a', '!', 0xe0},
+ {'a', '`', 0xe0}, // à Vim 5.x compatible
+ {'a', '\'', 0xe1},
+ {'a', '>', 0xe2},
+ {'a', '^', 0xe2}, // â Vim 5.x compatible
+ {'a', '?', 0xe3},
+ {'a', '~', 0xe3}, // ã Vim 5.x compatible
+ {'a', ':', 0xe4},
+ {'a', '"', 0xe4}, // ä Vim 5.x compatible
+ {'a', 'a', 0xe5},
+ {'a', '@', 0xe5}, // å Vim 5.x compatible
+ {'a', 'e', 0xe6},
+ {'c', ',', 0xe7},
+ {'e', '!', 0xe8},
+ {'e', '`', 0xe8}, // è Vim 5.x compatible
+ {'e', '\'', 0xe9},
+ {'e', '>', 0xea},
+ {'e', '^', 0xea}, // ê Vim 5.x compatible
+ {'e', ':', 0xeb},
+ {'e', '"', 0xeb}, // ë Vim 5.x compatible
+ {'i', '!', 0xec},
+ {'i', '`', 0xec}, // ì Vim 5.x compatible
+ {'i', '\'', 0xed},
+ {'i', '>', 0xee},
+ {'i', '^', 0xee}, // î Vim 5.x compatible
+ {'i', ':', 0xef},
+ {'d', '-', 0xf0},
+ {'n', '?', 0xf1},
+ {'n', '~', 0xf1}, // ñ Vim 5.x compatible
+ {'o', '!', 0xf2},
+ {'o', '`', 0xf2}, // ò Vim 5.x compatible
+ {'o', '\'', 0xf3},
+ {'o', '>', 0xf4},
+ {'o', '^', 0xf4}, // ô Vim 5.x compatible
+ {'o', '?', 0xf5},
+ {'o', '~', 0xf5}, // õ Vim 5.x compatible
+ {'o', ':', 0xf6},
+ {'-', ':', 0xf7},
+ {'o', '/', 0xf8},
+ {'u', '!', 0xf9},
+ {'u', '`', 0xf9}, // ù Vim 5.x compatible
+ {'u', '\'', 0xfa},
+ {'u', '>', 0xfb},
+ {'u', '^', 0xfb}, // û Vim 5.x compatible
+ {'u', ':', 0xfc},
+ {'y', '\'', 0xfd},
+ {'t', 'h', 0xfe},
+ {'y', ':', 0xff},
+ {'y', '"', 0xff}, // x XX Vim 5.x compatible
+
+# define USE_UNICODE_DIGRAPHS
+
+ {'A', '-', 0x0100},
+ {'a', '-', 0x0101},
+ {'A', '(', 0x0102},
+ {'a', '(', 0x0103},
+ {'A', ';', 0x0104},
+ {'a', ';', 0x0105},
+ {'C', '\'', 0x0106},
+ {'c', '\'', 0x0107},
+ {'C', '>', 0x0108},
+ {'c', '>', 0x0109},
+ {'C', '.', 0x010a},
+ {'c', '.', 0x010b},
+ {'C', '<', 0x010c},
+ {'c', '<', 0x010d},
+ {'D', '<', 0x010e},
+ {'d', '<', 0x010f},
+ {'D', '/', 0x0110},
+ {'d', '/', 0x0111},
+ {'E', '-', 0x0112},
+ {'e', '-', 0x0113},
+ {'E', '(', 0x0114},
+ {'e', '(', 0x0115},
+ {'E', '.', 0x0116},
+ {'e', '.', 0x0117},
+ {'E', ';', 0x0118},
+ {'e', ';', 0x0119},
+ {'E', '<', 0x011a},
+ {'e', '<', 0x011b},
+ {'G', '>', 0x011c},
+ {'g', '>', 0x011d},
+ {'G', '(', 0x011e},
+ {'g', '(', 0x011f},
+ {'G', '.', 0x0120},
+ {'g', '.', 0x0121},
+ {'G', ',', 0x0122},
+ {'g', ',', 0x0123},
+ {'H', '>', 0x0124},
+ {'h', '>', 0x0125},
+ {'H', '/', 0x0126},
+ {'h', '/', 0x0127},
+ {'I', '?', 0x0128},
+ {'i', '?', 0x0129},
+ {'I', '-', 0x012a},
+ {'i', '-', 0x012b},
+ {'I', '(', 0x012c},
+ {'i', '(', 0x012d},
+ {'I', ';', 0x012e},
+ {'i', ';', 0x012f},
+ {'I', '.', 0x0130},
+ {'i', '.', 0x0131},
+ {'I', 'J', 0x0132},
+ {'i', 'j', 0x0133},
+ {'J', '>', 0x0134},
+ {'j', '>', 0x0135},
+ {'K', ',', 0x0136},
+ {'k', ',', 0x0137},
+ {'k', 'k', 0x0138},
+ {'L', '\'', 0x0139},
+ {'l', '\'', 0x013a},
+ {'L', ',', 0x013b},
+ {'l', ',', 0x013c},
+ {'L', '<', 0x013d},
+ {'l', '<', 0x013e},
+ {'L', '.', 0x013f},
+ {'l', '.', 0x0140},
+ {'L', '/', 0x0141},
+ {'l', '/', 0x0142},
+ {'N', '\'', 0x0143},
+ {'n', '\'', 0x0144},
+ {'N', ',', 0x0145},
+ {'n', ',', 0x0146},
+ {'N', '<', 0x0147},
+ {'n', '<', 0x0148},
+ {'\'', 'n', 0x0149},
+ {'N', 'G', 0x014a},
+ {'n', 'g', 0x014b},
+ {'O', '-', 0x014c},
+ {'o', '-', 0x014d},
+ {'O', '(', 0x014e},
+ {'o', '(', 0x014f},
+ {'O', '"', 0x0150},
+ {'o', '"', 0x0151},
+ {'O', 'E', 0x0152},
+ {'o', 'e', 0x0153},
+ {'R', '\'', 0x0154},
+ {'r', '\'', 0x0155},
+ {'R', ',', 0x0156},
+ {'r', ',', 0x0157},
+ {'R', '<', 0x0158},
+ {'r', '<', 0x0159},
+ {'S', '\'', 0x015a},
+ {'s', '\'', 0x015b},
+ {'S', '>', 0x015c},
+ {'s', '>', 0x015d},
+ {'S', ',', 0x015e},
+ {'s', ',', 0x015f},
+ {'S', '<', 0x0160},
+ {'s', '<', 0x0161},
+ {'T', ',', 0x0162},
+ {'t', ',', 0x0163},
+ {'T', '<', 0x0164},
+ {'t', '<', 0x0165},
+ {'T', '/', 0x0166},
+ {'t', '/', 0x0167},
+ {'U', '?', 0x0168},
+ {'u', '?', 0x0169},
+ {'U', '-', 0x016a},
+ {'u', '-', 0x016b},
+ {'U', '(', 0x016c},
+ {'u', '(', 0x016d},
+ {'U', '0', 0x016e},
+ {'u', '0', 0x016f},
+ {'U', '"', 0x0170},
+ {'u', '"', 0x0171},
+ {'U', ';', 0x0172},
+ {'u', ';', 0x0173},
+ {'W', '>', 0x0174},
+ {'w', '>', 0x0175},
+ {'Y', '>', 0x0176},
+ {'y', '>', 0x0177},
+ {'Y', ':', 0x0178},
+ {'Z', '\'', 0x0179},
+ {'z', '\'', 0x017a},
+ {'Z', '.', 0x017b},
+ {'z', '.', 0x017c},
+ {'Z', '<', 0x017d},
+ {'z', '<', 0x017e},
+ {'O', '9', 0x01a0},
+ {'o', '9', 0x01a1},
+ {'O', 'I', 0x01a2},
+ {'o', 'i', 0x01a3},
+ {'y', 'r', 0x01a6},
+ {'U', '9', 0x01af},
+ {'u', '9', 0x01b0},
+ {'Z', '/', 0x01b5},
+ {'z', '/', 0x01b6},
+ {'E', 'D', 0x01b7},
+ {'A', '<', 0x01cd},
+ {'a', '<', 0x01ce},
+ {'I', '<', 0x01cf},
+ {'i', '<', 0x01d0},
+ {'O', '<', 0x01d1},
+ {'o', '<', 0x01d2},
+ {'U', '<', 0x01d3},
+ {'u', '<', 0x01d4},
+ {'A', '1', 0x01de},
+ {'a', '1', 0x01df},
+ {'A', '7', 0x01e0},
+ {'a', '7', 0x01e1},
+ {'A', '3', 0x01e2},
+ {'a', '3', 0x01e3},
+ {'G', '/', 0x01e4},
+ {'g', '/', 0x01e5},
+ {'G', '<', 0x01e6},
+ {'g', '<', 0x01e7},
+ {'K', '<', 0x01e8},
+ {'k', '<', 0x01e9},
+ {'O', ';', 0x01ea},
+ {'o', ';', 0x01eb},
+ {'O', '1', 0x01ec},
+ {'o', '1', 0x01ed},
+ {'E', 'Z', 0x01ee},
+ {'e', 'z', 0x01ef},
+ {'j', '<', 0x01f0},
+ {'G', '\'', 0x01f4},
+ {'g', '\'', 0x01f5},
+ {';', 'S', 0x02bf},
+ {'\'', '<', 0x02c7},
+ {'\'', '(', 0x02d8},
+ {'\'', '.', 0x02d9},
+ {'\'', '0', 0x02da},
+ {'\'', ';', 0x02db},
+ {'\'', '"', 0x02dd},
+#define DG_START_GREEK 0x0386
+ {'A', '%', 0x0386},
+ {'E', '%', 0x0388},
+ {'Y', '%', 0x0389},
+ {'I', '%', 0x038a},
+ {'O', '%', 0x038c},
+ {'U', '%', 0x038e},
+ {'W', '%', 0x038f},
+ {'i', '3', 0x0390},
+ {'A', '*', 0x0391},
+ {'B', '*', 0x0392},
+ {'G', '*', 0x0393},
+ {'D', '*', 0x0394},
+ {'E', '*', 0x0395},
+ {'Z', '*', 0x0396},
+ {'Y', '*', 0x0397},
+ {'H', '*', 0x0398},
+ {'I', '*', 0x0399},
+ {'K', '*', 0x039a},
+ {'L', '*', 0x039b},
+ {'M', '*', 0x039c},
+ {'N', '*', 0x039d},
+ {'C', '*', 0x039e},
+ {'O', '*', 0x039f},
+ {'P', '*', 0x03a0},
+ {'R', '*', 0x03a1},
+ {'S', '*', 0x03a3},
+ {'T', '*', 0x03a4},
+ {'U', '*', 0x03a5},
+ {'F', '*', 0x03a6},
+ {'X', '*', 0x03a7},
+ {'Q', '*', 0x03a8},
+ {'W', '*', 0x03a9},
+ {'J', '*', 0x03aa},
+ {'V', '*', 0x03ab},
+ {'a', '%', 0x03ac},
+ {'e', '%', 0x03ad},
+ {'y', '%', 0x03ae},
+ {'i', '%', 0x03af},
+ {'u', '3', 0x03b0},
+ {'a', '*', 0x03b1},
+ {'b', '*', 0x03b2},
+ {'g', '*', 0x03b3},
+ {'d', '*', 0x03b4},
+ {'e', '*', 0x03b5},
+ {'z', '*', 0x03b6},
+ {'y', '*', 0x03b7},
+ {'h', '*', 0x03b8},
+ {'i', '*', 0x03b9},
+ {'k', '*', 0x03ba},
+ {'l', '*', 0x03bb},
+ {'m', '*', 0x03bc},
+ {'n', '*', 0x03bd},
+ {'c', '*', 0x03be},
+ {'o', '*', 0x03bf},
+ {'p', '*', 0x03c0},
+ {'r', '*', 0x03c1},
+ {'*', 's', 0x03c2},
+ {'s', '*', 0x03c3},
+ {'t', '*', 0x03c4},
+ {'u', '*', 0x03c5},
+ {'f', '*', 0x03c6},
+ {'x', '*', 0x03c7},
+ {'q', '*', 0x03c8},
+ {'w', '*', 0x03c9},
+ {'j', '*', 0x03ca},
+ {'v', '*', 0x03cb},
+ {'o', '%', 0x03cc},
+ {'u', '%', 0x03cd},
+ {'w', '%', 0x03ce},
+ {'\'', 'G', 0x03d8},
+ {',', 'G', 0x03d9},
+ {'T', '3', 0x03da},
+ {'t', '3', 0x03db},
+ {'M', '3', 0x03dc},
+ {'m', '3', 0x03dd},
+ {'K', '3', 0x03de},
+ {'k', '3', 0x03df},
+ {'P', '3', 0x03e0},
+ {'p', '3', 0x03e1},
+ {'\'', '%', 0x03f4},
+ {'j', '3', 0x03f5},
+#define DG_START_CYRILLIC 0x0401
+ {'I', 'O', 0x0401},
+ {'D', '%', 0x0402},
+ {'G', '%', 0x0403},
+ {'I', 'E', 0x0404},
+ {'D', 'S', 0x0405},
+ {'I', 'I', 0x0406},
+ {'Y', 'I', 0x0407},
+ {'J', '%', 0x0408},
+ {'L', 'J', 0x0409},
+ {'N', 'J', 0x040a},
+ {'T', 's', 0x040b},
+ {'K', 'J', 0x040c},
+ {'V', '%', 0x040e},
+ {'D', 'Z', 0x040f},
+ {'A', '=', 0x0410},
+ {'B', '=', 0x0411},
+ {'V', '=', 0x0412},
+ {'G', '=', 0x0413},
+ {'D', '=', 0x0414},
+ {'E', '=', 0x0415},
+ {'Z', '%', 0x0416},
+ {'Z', '=', 0x0417},
+ {'I', '=', 0x0418},
+ {'J', '=', 0x0419},
+ {'K', '=', 0x041a},
+ {'L', '=', 0x041b},
+ {'M', '=', 0x041c},
+ {'N', '=', 0x041d},
+ {'O', '=', 0x041e},
+ {'P', '=', 0x041f},
+ {'R', '=', 0x0420},
+ {'S', '=', 0x0421},
+ {'T', '=', 0x0422},
+ {'U', '=', 0x0423},
+ {'F', '=', 0x0424},
+ {'H', '=', 0x0425},
+ {'C', '=', 0x0426},
+ {'C', '%', 0x0427},
+ {'S', '%', 0x0428},
+ {'S', 'c', 0x0429},
+ {'=', '"', 0x042a},
+ {'Y', '=', 0x042b},
+ {'%', '"', 0x042c},
+ {'J', 'E', 0x042d},
+ {'J', 'U', 0x042e},
+ {'J', 'A', 0x042f},
+ {'a', '=', 0x0430},
+ {'b', '=', 0x0431},
+ {'v', '=', 0x0432},
+ {'g', '=', 0x0433},
+ {'d', '=', 0x0434},
+ {'e', '=', 0x0435},
+ {'z', '%', 0x0436},
+ {'z', '=', 0x0437},
+ {'i', '=', 0x0438},
+ {'j', '=', 0x0439},
+ {'k', '=', 0x043a},
+ {'l', '=', 0x043b},
+ {'m', '=', 0x043c},
+ {'n', '=', 0x043d},
+ {'o', '=', 0x043e},
+ {'p', '=', 0x043f},
+ {'r', '=', 0x0440},
+ {'s', '=', 0x0441},
+ {'t', '=', 0x0442},
+ {'u', '=', 0x0443},
+ {'f', '=', 0x0444},
+ {'h', '=', 0x0445},
+ {'c', '=', 0x0446},
+ {'c', '%', 0x0447},
+ {'s', '%', 0x0448},
+ {'s', 'c', 0x0449},
+ {'=', '\'', 0x044a},
+ {'y', '=', 0x044b},
+ {'%', '\'', 0x044c},
+ {'j', 'e', 0x044d},
+ {'j', 'u', 0x044e},
+ {'j', 'a', 0x044f},
+ {'i', 'o', 0x0451},
+ {'d', '%', 0x0452},
+ {'g', '%', 0x0453},
+ {'i', 'e', 0x0454},
+ {'d', 's', 0x0455},
+ {'i', 'i', 0x0456},
+ {'y', 'i', 0x0457},
+ {'j', '%', 0x0458},
+ {'l', 'j', 0x0459},
+ {'n', 'j', 0x045a},
+ {'t', 's', 0x045b},
+ {'k', 'j', 0x045c},
+ {'v', '%', 0x045e},
+ {'d', 'z', 0x045f},
+ {'Y', '3', 0x0462},
+ {'y', '3', 0x0463},
+ {'O', '3', 0x046a},
+ {'o', '3', 0x046b},
+ {'F', '3', 0x0472},
+ {'f', '3', 0x0473},
+ {'V', '3', 0x0474},
+ {'v', '3', 0x0475},
+ {'C', '3', 0x0480},
+ {'c', '3', 0x0481},
+ {'G', '3', 0x0490},
+ {'g', '3', 0x0491},
+#define DG_START_HEBREW 0x05d0
+ {'A', '+', 0x05d0},
+ {'B', '+', 0x05d1},
+ {'G', '+', 0x05d2},
+ {'D', '+', 0x05d3},
+ {'H', '+', 0x05d4},
+ {'W', '+', 0x05d5},
+ {'Z', '+', 0x05d6},
+ {'X', '+', 0x05d7},
+ {'T', 'j', 0x05d8},
+ {'J', '+', 0x05d9},
+ {'K', '%', 0x05da},
+ {'K', '+', 0x05db},
+ {'L', '+', 0x05dc},
+ {'M', '%', 0x05dd},
+ {'M', '+', 0x05de},
+ {'N', '%', 0x05df},
+ {'N', '+', 0x05e0},
+ {'S', '+', 0x05e1},
+ {'E', '+', 0x05e2},
+ {'P', '%', 0x05e3},
+ {'P', '+', 0x05e4},
+ {'Z', 'j', 0x05e5},
+ {'Z', 'J', 0x05e6},
+ {'Q', '+', 0x05e7},
+ {'R', '+', 0x05e8},
+ {'S', 'h', 0x05e9},
+ {'T', '+', 0x05ea},
+#define DG_START_ARABIC 0x060c
+ {',', '+', 0x060c},
+ {';', '+', 0x061b},
+ {'?', '+', 0x061f},
+ {'H', '\'', 0x0621},
+ {'a', 'M', 0x0622},
+ {'a', 'H', 0x0623},
+ {'w', 'H', 0x0624},
+ {'a', 'h', 0x0625},
+ {'y', 'H', 0x0626},
+ {'a', '+', 0x0627},
+ {'b', '+', 0x0628},
+ {'t', 'm', 0x0629},
+ {'t', '+', 0x062a},
+ {'t', 'k', 0x062b},
+ {'g', '+', 0x062c},
+ {'h', 'k', 0x062d},
+ {'x', '+', 0x062e},
+ {'d', '+', 0x062f},
+ {'d', 'k', 0x0630},
+ {'r', '+', 0x0631},
+ {'z', '+', 0x0632},
+ {'s', '+', 0x0633},
+ {'s', 'n', 0x0634},
+ {'c', '+', 0x0635},
+ {'d', 'd', 0x0636},
+ {'t', 'j', 0x0637},
+ {'z', 'H', 0x0638},
+ {'e', '+', 0x0639},
+ {'i', '+', 0x063a},
+ {'+', '+', 0x0640},
+ {'f', '+', 0x0641},
+ {'q', '+', 0x0642},
+ {'k', '+', 0x0643},
+ {'l', '+', 0x0644},
+ {'m', '+', 0x0645},
+ {'n', '+', 0x0646},
+ {'h', '+', 0x0647},
+ {'w', '+', 0x0648},
+ {'j', '+', 0x0649},
+ {'y', '+', 0x064a},
+ {':', '+', 0x064b},
+ {'"', '+', 0x064c},
+ {'=', '+', 0x064d},
+ {'/', '+', 0x064e},
+ {'\'', '+', 0x064f},
+ {'1', '+', 0x0650},
+ {'3', '+', 0x0651},
+ {'0', '+', 0x0652},
+ {'a', 'S', 0x0670},
+ {'p', '+', 0x067e},
+ {'v', '+', 0x06a4},
+ {'g', 'f', 0x06af},
+ {'0', 'a', 0x06f0},
+ {'1', 'a', 0x06f1},
+ {'2', 'a', 0x06f2},
+ {'3', 'a', 0x06f3},
+ {'4', 'a', 0x06f4},
+ {'5', 'a', 0x06f5},
+ {'6', 'a', 0x06f6},
+ {'7', 'a', 0x06f7},
+ {'8', 'a', 0x06f8},
+ {'9', 'a', 0x06f9},
+#define DG_START_LATIN_EXTENDED 0x1e02
+ {'B', '.', 0x1e02},
+ {'b', '.', 0x1e03},
+ {'B', '_', 0x1e06},
+ {'b', '_', 0x1e07},
+ {'D', '.', 0x1e0a},
+ {'d', '.', 0x1e0b},
+ {'D', '_', 0x1e0e},
+ {'d', '_', 0x1e0f},
+ {'D', ',', 0x1e10},
+ {'d', ',', 0x1e11},
+ {'F', '.', 0x1e1e},
+ {'f', '.', 0x1e1f},
+ {'G', '-', 0x1e20},
+ {'g', '-', 0x1e21},
+ {'H', '.', 0x1e22},
+ {'h', '.', 0x1e23},
+ {'H', ':', 0x1e26},
+ {'h', ':', 0x1e27},
+ {'H', ',', 0x1e28},
+ {'h', ',', 0x1e29},
+ {'K', '\'', 0x1e30},
+ {'k', '\'', 0x1e31},
+ {'K', '_', 0x1e34},
+ {'k', '_', 0x1e35},
+ {'L', '_', 0x1e3a},
+ {'l', '_', 0x1e3b},
+ {'M', '\'', 0x1e3e},
+ {'m', '\'', 0x1e3f},
+ {'M', '.', 0x1e40},
+ {'m', '.', 0x1e41},
+ {'N', '.', 0x1e44},
+ {'n', '.', 0x1e45},
+ {'N', '_', 0x1e48},
+ {'n', '_', 0x1e49},
+ {'P', '\'', 0x1e54},
+ {'p', '\'', 0x1e55},
+ {'P', '.', 0x1e56},
+ {'p', '.', 0x1e57},
+ {'R', '.', 0x1e58},
+ {'r', '.', 0x1e59},
+ {'R', '_', 0x1e5e},
+ {'r', '_', 0x1e5f},
+ {'S', '.', 0x1e60},
+ {'s', '.', 0x1e61},
+ {'T', '.', 0x1e6a},
+ {'t', '.', 0x1e6b},
+ {'T', '_', 0x1e6e},
+ {'t', '_', 0x1e6f},
+ {'V', '?', 0x1e7c},
+ {'v', '?', 0x1e7d},
+ {'W', '!', 0x1e80},
+ {'W', '`', 0x1e80}, // extra alternative, easier to remember
+ {'w', '!', 0x1e81},
+ {'w', '`', 0x1e81}, // extra alternative, easier to remember
+ {'W', '\'', 0x1e82},
+ {'w', '\'', 0x1e83},
+ {'W', ':', 0x1e84},
+ {'w', ':', 0x1e85},
+ {'W', '.', 0x1e86},
+ {'w', '.', 0x1e87},
+ {'X', '.', 0x1e8a},
+ {'x', '.', 0x1e8b},
+ {'X', ':', 0x1e8c},
+ {'x', ':', 0x1e8d},
+ {'Y', '.', 0x1e8e},
+ {'y', '.', 0x1e8f},
+ {'Z', '>', 0x1e90},
+ {'z', '>', 0x1e91},
+ {'Z', '_', 0x1e94},
+ {'z', '_', 0x1e95},
+ {'h', '_', 0x1e96},
+ {'t', ':', 0x1e97},
+ {'w', '0', 0x1e98},
+ {'y', '0', 0x1e99},
+ {'A', '2', 0x1ea2},
+ {'a', '2', 0x1ea3},
+ {'E', '2', 0x1eba},
+ {'e', '2', 0x1ebb},
+ {'E', '?', 0x1ebc},
+ {'e', '?', 0x1ebd},
+ {'I', '2', 0x1ec8},
+ {'i', '2', 0x1ec9},
+ {'O', '2', 0x1ece},
+ {'o', '2', 0x1ecf},
+ {'U', '2', 0x1ee6},
+ {'u', '2', 0x1ee7},
+ {'Y', '!', 0x1ef2},
+ {'Y', '`', 0x1ef2}, // extra alternative, easier to remember
+ {'y', '!', 0x1ef3},
+ {'y', '`', 0x1ef3}, // extra alternative, easier to remember
+ {'Y', '2', 0x1ef6},
+ {'y', '2', 0x1ef7},
+ {'Y', '?', 0x1ef8},
+ {'y', '?', 0x1ef9},
+#define DG_START_GREEK_EXTENDED 0x1f00
+ {';', '\'', 0x1f00},
+ {',', '\'', 0x1f01},
+ {';', '!', 0x1f02},
+ {',', '!', 0x1f03},
+ {'?', ';', 0x1f04},
+ {'?', ',', 0x1f05},
+ {'!', ':', 0x1f06},
+ {'?', ':', 0x1f07},
+#define DG_START_PUNCTUATION 0x2002
+ {'1', 'N', 0x2002},
+ {'1', 'M', 0x2003},
+ {'3', 'M', 0x2004},
+ {'4', 'M', 0x2005},
+ {'6', 'M', 0x2006},
+ {'1', 'T', 0x2009},
+ {'1', 'H', 0x200a},
+ {'-', '1', 0x2010},
+ {'-', 'N', 0x2013},
+ {'-', 'M', 0x2014},
+ {'-', '3', 0x2015},
+ {'!', '2', 0x2016},
+ {'=', '2', 0x2017},
+ {'\'', '6', 0x2018},
+ {'\'', '9', 0x2019},
+ {'.', '9', 0x201a},
+ {'9', '\'', 0x201b},
+ {'"', '6', 0x201c},
+ {'"', '9', 0x201d},
+ {':', '9', 0x201e},
+ {'9', '"', 0x201f},
+ {'/', '-', 0x2020},
+ {'/', '=', 0x2021},
+ {'.', '.', 0x2025},
+ {',', '.', 0x2026},
+ {'%', '0', 0x2030},
+ {'1', '\'', 0x2032},
+ {'2', '\'', 0x2033},
+ {'3', '\'', 0x2034},
+ {'1', '"', 0x2035},
+ {'2', '"', 0x2036},
+ {'3', '"', 0x2037},
+ {'C', 'a', 0x2038},
+ {'<', '1', 0x2039},
+ {'>', '1', 0x203a},
+ {':', 'X', 0x203b},
+ {'\'', '-', 0x203e},
+ {'/', 'f', 0x2044},
+#define DG_START_SUB_SUPER 0x2070
+ {'0', 'S', 0x2070},
+ {'4', 'S', 0x2074},
+ {'5', 'S', 0x2075},
+ {'6', 'S', 0x2076},
+ {'7', 'S', 0x2077},
+ {'8', 'S', 0x2078},
+ {'9', 'S', 0x2079},
+ {'+', 'S', 0x207a},
+ {'-', 'S', 0x207b},
+ {'=', 'S', 0x207c},
+ {'(', 'S', 0x207d},
+ {')', 'S', 0x207e},
+ {'n', 'S', 0x207f},
+ {'0', 's', 0x2080},
+ {'1', 's', 0x2081},
+ {'2', 's', 0x2082},
+ {'3', 's', 0x2083},
+ {'4', 's', 0x2084},
+ {'5', 's', 0x2085},
+ {'6', 's', 0x2086},
+ {'7', 's', 0x2087},
+ {'8', 's', 0x2088},
+ {'9', 's', 0x2089},
+ {'+', 's', 0x208a},
+ {'-', 's', 0x208b},
+ {'=', 's', 0x208c},
+ {'(', 's', 0x208d},
+ {')', 's', 0x208e},
+#define DG_START_CURRENCY 0x20a4
+ {'L', 'i', 0x20a4},
+ {'P', 't', 0x20a7},
+ {'W', '=', 0x20a9},
+ {'=', 'e', 0x20ac}, /* euro */
+ {'E', 'u', 0x20ac}, /* euro */
+ {'=', 'R', 0x20bd}, /* rouble */
+ {'=', 'P', 0x20bd}, /* rouble */
+#define DG_START_OTHER1 0x2103
+ {'o', 'C', 0x2103},
+ {'c', 'o', 0x2105},
+ {'o', 'F', 0x2109},
+ {'N', '0', 0x2116},
+ {'P', 'O', 0x2117},
+ {'R', 'x', 0x211e},
+ {'S', 'M', 0x2120},
+ {'T', 'M', 0x2122},
+ {'O', 'm', 0x2126},
+ {'A', 'O', 0x212b},
+ {'1', '3', 0x2153},
+ {'2', '3', 0x2154},
+ {'1', '5', 0x2155},
+ {'2', '5', 0x2156},
+ {'3', '5', 0x2157},
+ {'4', '5', 0x2158},
+ {'1', '6', 0x2159},
+ {'5', '6', 0x215a},
+ {'1', '8', 0x215b},
+ {'3', '8', 0x215c},
+ {'5', '8', 0x215d},
+ {'7', '8', 0x215e},
+#define DG_START_ROMAN 0x2160
+ {'1', 'R', 0x2160},
+ {'2', 'R', 0x2161},
+ {'3', 'R', 0x2162},
+ {'4', 'R', 0x2163},
+ {'5', 'R', 0x2164},
+ {'6', 'R', 0x2165},
+ {'7', 'R', 0x2166},
+ {'8', 'R', 0x2167},
+ {'9', 'R', 0x2168},
+ {'a', 'R', 0x2169},
+ {'b', 'R', 0x216a},
+ {'c', 'R', 0x216b},
+ {'1', 'r', 0x2170},
+ {'2', 'r', 0x2171},
+ {'3', 'r', 0x2172},
+ {'4', 'r', 0x2173},
+ {'5', 'r', 0x2174},
+ {'6', 'r', 0x2175},
+ {'7', 'r', 0x2176},
+ {'8', 'r', 0x2177},
+ {'9', 'r', 0x2178},
+ {'a', 'r', 0x2179},
+ {'b', 'r', 0x217a},
+ {'c', 'r', 0x217b},
+#define DG_START_ARROWS 0x2190
+ {'<', '-', 0x2190},
+ {'-', '!', 0x2191},
+ {'-', '>', 0x2192},
+ {'-', 'v', 0x2193},
+ {'<', '>', 0x2194},
+ {'U', 'D', 0x2195},
+ {'<', '=', 0x21d0},
+ {'=', '>', 0x21d2},
+ {'=', '=', 0x21d4},
+#define DG_START_MATH 0x2200
+ {'F', 'A', 0x2200},
+ {'d', 'P', 0x2202},
+ {'T', 'E', 0x2203},
+ {'/', '0', 0x2205},
+ {'D', 'E', 0x2206},
+ {'N', 'B', 0x2207},
+ {'(', '-', 0x2208},
+ {'-', ')', 0x220b},
+ {'*', 'P', 0x220f},
+ {'+', 'Z', 0x2211},
+ {'-', '2', 0x2212},
+ {'-', '+', 0x2213},
+ {'*', '-', 0x2217},
+ {'O', 'b', 0x2218},
+ {'S', 'b', 0x2219},
+ {'R', 'T', 0x221a},
+ {'0', '(', 0x221d},
+ {'0', '0', 0x221e},
+ {'-', 'L', 0x221f},
+ {'-', 'V', 0x2220},
+ {'P', 'P', 0x2225},
+ {'A', 'N', 0x2227},
+ {'O', 'R', 0x2228},
+ {'(', 'U', 0x2229},
+ {')', 'U', 0x222a},
+ {'I', 'n', 0x222b},
+ {'D', 'I', 0x222c},
+ {'I', 'o', 0x222e},
+ {'.', ':', 0x2234},
+ {':', '.', 0x2235},
+ {':', 'R', 0x2236},
+ {':', ':', 0x2237},
+ {'?', '1', 0x223c},
+ {'C', 'G', 0x223e},
+ {'?', '-', 0x2243},
+ {'?', '=', 0x2245},
+ {'?', '2', 0x2248},
+ {'=', '?', 0x224c},
+ {'H', 'I', 0x2253},
+ {'!', '=', 0x2260},
+ {'=', '3', 0x2261},
+ {'=', '<', 0x2264},
+ {'>', '=', 0x2265},
+ {'<', '*', 0x226a},
+ {'*', '>', 0x226b},
+ {'!', '<', 0x226e},
+ {'!', '>', 0x226f},
+ {'(', 'C', 0x2282},
+ {')', 'C', 0x2283},
+ {'(', '_', 0x2286},
+ {')', '_', 0x2287},
+ {'0', '.', 0x2299},
+ {'0', '2', 0x229a},
+ {'-', 'T', 0x22a5},
+ {'.', 'P', 0x22c5},
+ {':', '3', 0x22ee},
+ {'.', '3', 0x22ef},
+#define DG_START_TECHNICAL 0x2302
+ {'E', 'h', 0x2302},
+ {'<', '7', 0x2308},
+ {'>', '7', 0x2309},
+ {'7', '<', 0x230a},
+ {'7', '>', 0x230b},
+ {'N', 'I', 0x2310},
+ {'(', 'A', 0x2312},
+ {'T', 'R', 0x2315},
+ {'I', 'u', 0x2320},
+ {'I', 'l', 0x2321},
+ {'<', '/', 0x2329},
+ {'/', '>', 0x232a},
+#define DG_START_OTHER2 0x2423
+ {'V', 's', 0x2423},
+ {'1', 'h', 0x2440},
+ {'3', 'h', 0x2441},
+ {'2', 'h', 0x2442},
+ {'4', 'h', 0x2443},
+ {'1', 'j', 0x2446},
+ {'2', 'j', 0x2447},
+ {'3', 'j', 0x2448},
+ {'4', 'j', 0x2449},
+ {'1', '.', 0x2488},
+ {'2', '.', 0x2489},
+ {'3', '.', 0x248a},
+ {'4', '.', 0x248b},
+ {'5', '.', 0x248c},
+ {'6', '.', 0x248d},
+ {'7', '.', 0x248e},
+ {'8', '.', 0x248f},
+ {'9', '.', 0x2490},
+#define DG_START_DRAWING 0x2500
+ {'h', 'h', 0x2500},
+ {'H', 'H', 0x2501},
+ {'v', 'v', 0x2502},
+ {'V', 'V', 0x2503},
+ {'3', '-', 0x2504},
+ {'3', '_', 0x2505},
+ {'3', '!', 0x2506},
+ {'3', '/', 0x2507},
+ {'4', '-', 0x2508},
+ {'4', '_', 0x2509},
+ {'4', '!', 0x250a},
+ {'4', '/', 0x250b},
+ {'d', 'r', 0x250c},
+ {'d', 'R', 0x250d},
+ {'D', 'r', 0x250e},
+ {'D', 'R', 0x250f},
+ {'d', 'l', 0x2510},
+ {'d', 'L', 0x2511},
+ {'D', 'l', 0x2512},
+ {'L', 'D', 0x2513},
+ {'u', 'r', 0x2514},
+ {'u', 'R', 0x2515},
+ {'U', 'r', 0x2516},
+ {'U', 'R', 0x2517},
+ {'u', 'l', 0x2518},
+ {'u', 'L', 0x2519},
+ {'U', 'l', 0x251a},
+ {'U', 'L', 0x251b},
+ {'v', 'r', 0x251c},
+ {'v', 'R', 0x251d},
+ {'V', 'r', 0x2520},
+ {'V', 'R', 0x2523},
+ {'v', 'l', 0x2524},
+ {'v', 'L', 0x2525},
+ {'V', 'l', 0x2528},
+ {'V', 'L', 0x252b},
+ {'d', 'h', 0x252c},
+ {'d', 'H', 0x252f},
+ {'D', 'h', 0x2530},
+ {'D', 'H', 0x2533},
+ {'u', 'h', 0x2534},
+ {'u', 'H', 0x2537},
+ {'U', 'h', 0x2538},
+ {'U', 'H', 0x253b},
+ {'v', 'h', 0x253c},
+ {'v', 'H', 0x253f},
+ {'V', 'h', 0x2542},
+ {'V', 'H', 0x254b},
+ {'F', 'D', 0x2571},
+ {'B', 'D', 0x2572},
+#define DG_START_BLOCK 0x2580
+ {'T', 'B', 0x2580},
+ {'L', 'B', 0x2584},
+ {'F', 'B', 0x2588},
+ {'l', 'B', 0x258c},
+ {'R', 'B', 0x2590},
+ {'.', 'S', 0x2591},
+ {':', 'S', 0x2592},
+ {'?', 'S', 0x2593},
+#define DG_START_SHAPES 0x25a0
+ {'f', 'S', 0x25a0},
+ {'O', 'S', 0x25a1},
+ {'R', 'O', 0x25a2},
+ {'R', 'r', 0x25a3},
+ {'R', 'F', 0x25a4},
+ {'R', 'Y', 0x25a5},
+ {'R', 'H', 0x25a6},
+ {'R', 'Z', 0x25a7},
+ {'R', 'K', 0x25a8},
+ {'R', 'X', 0x25a9},
+ {'s', 'B', 0x25aa},
+ {'S', 'R', 0x25ac},
+ {'O', 'r', 0x25ad},
+ {'U', 'T', 0x25b2},
+ {'u', 'T', 0x25b3},
+ {'P', 'R', 0x25b6},
+ {'T', 'r', 0x25b7},
+ {'D', 't', 0x25bc},
+ {'d', 'T', 0x25bd},
+ {'P', 'L', 0x25c0},
+ {'T', 'l', 0x25c1},
+ {'D', 'b', 0x25c6},
+ {'D', 'w', 0x25c7},
+ {'L', 'Z', 0x25ca},
+ {'0', 'm', 0x25cb},
+ {'0', 'o', 0x25ce},
+ {'0', 'M', 0x25cf},
+ {'0', 'L', 0x25d0},
+ {'0', 'R', 0x25d1},
+ {'S', 'n', 0x25d8},
+ {'I', 'c', 0x25d9},
+ {'F', 'd', 0x25e2},
+ {'B', 'd', 0x25e3},
+#define DG_START_SYMBOLS 0x2605
+ {'*', '2', 0x2605},
+ {'*', '1', 0x2606},
+ {'<', 'H', 0x261c},
+ {'>', 'H', 0x261e},
+ {'0', 'u', 0x263a},
+ {'0', 'U', 0x263b},
+ {'S', 'U', 0x263c},
+ {'F', 'm', 0x2640},
+ {'M', 'l', 0x2642},
+ {'c', 'S', 0x2660},
+ {'c', 'H', 0x2661},
+ {'c', 'D', 0x2662},
+ {'c', 'C', 0x2663},
+ {'M', 'd', 0x2669},
+ {'M', '8', 0x266a},
+ {'M', '2', 0x266b},
+ {'M', 'b', 0x266d},
+ {'M', 'x', 0x266e},
+ {'M', 'X', 0x266f},
+#define DG_START_DINGBATS 0x2713
+ {'O', 'K', 0x2713},
+ {'X', 'X', 0x2717},
+ {'-', 'X', 0x2720},
+#define DG_START_CJK_SYMBOLS 0x3000
+ {'I', 'S', 0x3000},
+ {',', '_', 0x3001},
+ {'.', '_', 0x3002},
+ {'+', '"', 0x3003},
+ {'+', '_', 0x3004},
+ {'*', '_', 0x3005},
+ {';', '_', 0x3006},
+ {'0', '_', 0x3007},
+ {'<', '+', 0x300a},
+ {'>', '+', 0x300b},
+ {'<', '\'', 0x300c},
+ {'>', '\'', 0x300d},
+ {'<', '"', 0x300e},
+ {'>', '"', 0x300f},
+ {'(', '"', 0x3010},
+ {')', '"', 0x3011},
+ {'=', 'T', 0x3012},
+ {'=', '_', 0x3013},
+ {'(', '\'', 0x3014},
+ {')', '\'', 0x3015},
+ {'(', 'I', 0x3016},
+ {')', 'I', 0x3017},
+ {'-', '?', 0x301c},
+#define DG_START_HIRAGANA 0x3041
+ {'A', '5', 0x3041},
+ {'a', '5', 0x3042},
+ {'I', '5', 0x3043},
+ {'i', '5', 0x3044},
+ {'U', '5', 0x3045},
+ {'u', '5', 0x3046},
+ {'E', '5', 0x3047},
+ {'e', '5', 0x3048},
+ {'O', '5', 0x3049},
+ {'o', '5', 0x304a},
+ {'k', 'a', 0x304b},
+ {'g', 'a', 0x304c},
+ {'k', 'i', 0x304d},
+ {'g', 'i', 0x304e},
+ {'k', 'u', 0x304f},
+ {'g', 'u', 0x3050},
+ {'k', 'e', 0x3051},
+ {'g', 'e', 0x3052},
+ {'k', 'o', 0x3053},
+ {'g', 'o', 0x3054},
+ {'s', 'a', 0x3055},
+ {'z', 'a', 0x3056},
+ {'s', 'i', 0x3057},
+ {'z', 'i', 0x3058},
+ {'s', 'u', 0x3059},
+ {'z', 'u', 0x305a},
+ {'s', 'e', 0x305b},
+ {'z', 'e', 0x305c},
+ {'s', 'o', 0x305d},
+ {'z', 'o', 0x305e},
+ {'t', 'a', 0x305f},
+ {'d', 'a', 0x3060},
+ {'t', 'i', 0x3061},
+ {'d', 'i', 0x3062},
+ {'t', 'U', 0x3063},
+ {'t', 'u', 0x3064},
+ {'d', 'u', 0x3065},
+ {'t', 'e', 0x3066},
+ {'d', 'e', 0x3067},
+ {'t', 'o', 0x3068},
+ {'d', 'o', 0x3069},
+ {'n', 'a', 0x306a},
+ {'n', 'i', 0x306b},
+ {'n', 'u', 0x306c},
+ {'n', 'e', 0x306d},
+ {'n', 'o', 0x306e},
+ {'h', 'a', 0x306f},
+ {'b', 'a', 0x3070},
+ {'p', 'a', 0x3071},
+ {'h', 'i', 0x3072},
+ {'b', 'i', 0x3073},
+ {'p', 'i', 0x3074},
+ {'h', 'u', 0x3075},
+ {'b', 'u', 0x3076},
+ {'p', 'u', 0x3077},
+ {'h', 'e', 0x3078},
+ {'b', 'e', 0x3079},
+ {'p', 'e', 0x307a},
+ {'h', 'o', 0x307b},
+ {'b', 'o', 0x307c},
+ {'p', 'o', 0x307d},
+ {'m', 'a', 0x307e},
+ {'m', 'i', 0x307f},
+ {'m', 'u', 0x3080},
+ {'m', 'e', 0x3081},
+ {'m', 'o', 0x3082},
+ {'y', 'A', 0x3083},
+ {'y', 'a', 0x3084},
+ {'y', 'U', 0x3085},
+ {'y', 'u', 0x3086},
+ {'y', 'O', 0x3087},
+ {'y', 'o', 0x3088},
+ {'r', 'a', 0x3089},
+ {'r', 'i', 0x308a},
+ {'r', 'u', 0x308b},
+ {'r', 'e', 0x308c},
+ {'r', 'o', 0x308d},
+ {'w', 'A', 0x308e},
+ {'w', 'a', 0x308f},
+ {'w', 'i', 0x3090},
+ {'w', 'e', 0x3091},
+ {'w', 'o', 0x3092},
+ {'n', '5', 0x3093},
+ {'v', 'u', 0x3094},
+ {'"', '5', 0x309b},
+ {'0', '5', 0x309c},
+ {'*', '5', 0x309d},
+ {'+', '5', 0x309e},
+#define DG_START_KATAKANA 0x30a1
+ {'a', '6', 0x30a1},
+ {'A', '6', 0x30a2},
+ {'i', '6', 0x30a3},
+ {'I', '6', 0x30a4},
+ {'u', '6', 0x30a5},
+ {'U', '6', 0x30a6},
+ {'e', '6', 0x30a7},
+ {'E', '6', 0x30a8},
+ {'o', '6', 0x30a9},
+ {'O', '6', 0x30aa},
+ {'K', 'a', 0x30ab},
+ {'G', 'a', 0x30ac},
+ {'K', 'i', 0x30ad},
+ {'G', 'i', 0x30ae},
+ {'K', 'u', 0x30af},
+ {'G', 'u', 0x30b0},
+ {'K', 'e', 0x30b1},
+ {'G', 'e', 0x30b2},
+ {'K', 'o', 0x30b3},
+ {'G', 'o', 0x30b4},
+ {'S', 'a', 0x30b5},
+ {'Z', 'a', 0x30b6},
+ {'S', 'i', 0x30b7},
+ {'Z', 'i', 0x30b8},
+ {'S', 'u', 0x30b9},
+ {'Z', 'u', 0x30ba},
+ {'S', 'e', 0x30bb},
+ {'Z', 'e', 0x30bc},
+ {'S', 'o', 0x30bd},
+ {'Z', 'o', 0x30be},
+ {'T', 'a', 0x30bf},
+ {'D', 'a', 0x30c0},
+ {'T', 'i', 0x30c1},
+ {'D', 'i', 0x30c2},
+ {'T', 'U', 0x30c3},
+ {'T', 'u', 0x30c4},
+ {'D', 'u', 0x30c5},
+ {'T', 'e', 0x30c6},
+ {'D', 'e', 0x30c7},
+ {'T', 'o', 0x30c8},
+ {'D', 'o', 0x30c9},
+ {'N', 'a', 0x30ca},
+ {'N', 'i', 0x30cb},
+ {'N', 'u', 0x30cc},
+ {'N', 'e', 0x30cd},
+ {'N', 'o', 0x30ce},
+ {'H', 'a', 0x30cf},
+ {'B', 'a', 0x30d0},
+ {'P', 'a', 0x30d1},
+ {'H', 'i', 0x30d2},
+ {'B', 'i', 0x30d3},
+ {'P', 'i', 0x30d4},
+ {'H', 'u', 0x30d5},
+ {'B', 'u', 0x30d6},
+ {'P', 'u', 0x30d7},
+ {'H', 'e', 0x30d8},
+ {'B', 'e', 0x30d9},
+ {'P', 'e', 0x30da},
+ {'H', 'o', 0x30db},
+ {'B', 'o', 0x30dc},
+ {'P', 'o', 0x30dd},
+ {'M', 'a', 0x30de},
+ {'M', 'i', 0x30df},
+ {'M', 'u', 0x30e0},
+ {'M', 'e', 0x30e1},
+ {'M', 'o', 0x30e2},
+ {'Y', 'A', 0x30e3},
+ {'Y', 'a', 0x30e4},
+ {'Y', 'U', 0x30e5},
+ {'Y', 'u', 0x30e6},
+ {'Y', 'O', 0x30e7},
+ {'Y', 'o', 0x30e8},
+ {'R', 'a', 0x30e9},
+ {'R', 'i', 0x30ea},
+ {'R', 'u', 0x30eb},
+ {'R', 'e', 0x30ec},
+ {'R', 'o', 0x30ed},
+ {'W', 'A', 0x30ee},
+ {'W', 'a', 0x30ef},
+ {'W', 'i', 0x30f0},
+ {'W', 'e', 0x30f1},
+ {'W', 'o', 0x30f2},
+ {'N', '6', 0x30f3},
+ {'V', 'u', 0x30f4},
+ {'K', 'A', 0x30f5},
+ {'K', 'E', 0x30f6},
+ {'V', 'a', 0x30f7},
+ {'V', 'i', 0x30f8},
+ {'V', 'e', 0x30f9},
+ {'V', 'o', 0x30fa},
+ {'.', '6', 0x30fb},
+ {'-', '6', 0x30fc},
+ {'*', '6', 0x30fd},
+ {'+', '6', 0x30fe},
+#define DG_START_BOPOMOFO 0x3105
+ {'b', '4', 0x3105},
+ {'p', '4', 0x3106},
+ {'m', '4', 0x3107},
+ {'f', '4', 0x3108},
+ {'d', '4', 0x3109},
+ {'t', '4', 0x310a},
+ {'n', '4', 0x310b},
+ {'l', '4', 0x310c},
+ {'g', '4', 0x310d},
+ {'k', '4', 0x310e},
+ {'h', '4', 0x310f},
+ {'j', '4', 0x3110},
+ {'q', '4', 0x3111},
+ {'x', '4', 0x3112},
+ {'z', 'h', 0x3113},
+ {'c', 'h', 0x3114},
+ {'s', 'h', 0x3115},
+ {'r', '4', 0x3116},
+ {'z', '4', 0x3117},
+ {'c', '4', 0x3118},
+ {'s', '4', 0x3119},
+ {'a', '4', 0x311a},
+ {'o', '4', 0x311b},
+ {'e', '4', 0x311c},
+ {'a', 'i', 0x311e},
+ {'e', 'i', 0x311f},
+ {'a', 'u', 0x3120},
+ {'o', 'u', 0x3121},
+ {'a', 'n', 0x3122},
+ {'e', 'n', 0x3123},
+ {'a', 'N', 0x3124},
+ {'e', 'N', 0x3125},
+ {'e', 'r', 0x3126},
+ {'i', '4', 0x3127},
+ {'u', '4', 0x3128},
+ {'i', 'u', 0x3129},
+ {'v', '4', 0x312a},
+ {'n', 'G', 0x312b},
+ {'g', 'n', 0x312c},
+#define DG_START_OTHER3 0x3220
+ {'1', 'c', 0x3220},
+ {'2', 'c', 0x3221},
+ {'3', 'c', 0x3222},
+ {'4', 'c', 0x3223},
+ {'5', 'c', 0x3224},
+ {'6', 'c', 0x3225},
+ {'7', 'c', 0x3226},
+ {'8', 'c', 0x3227},
+ {'9', 'c', 0x3228},
+ /* code points 0xe000 - 0xefff excluded, they have no assigned
+ * characters, only used in proposals. */
+ {'f', 'f', 0xfb00},
+ {'f', 'i', 0xfb01},
+ {'f', 'l', 0xfb02},
+ {'f', 't', 0xfb05},
+ {'s', 't', 0xfb06},
+
+ {NUL, NUL, NUL}
+ };
+
+# endif /* OLD_DIGRAPHS */
+# endif /* EBCDIC */
+# endif /* !HPUX_DIGRAPHS */
+#endif /* !__MINT__ */
+
+/*
+ * handle digraphs after typing a character
+ */
+ int
+do_digraph(int c)
+{
+ static int backspaced; /* character before K_BS */
+ static int lastchar; /* last typed character */
+
+ if (c == -1) /* init values */
+ {
+ backspaced = -1;
+ }
+ else if (p_dg)
+ {
+ if (backspaced >= 0)
+ c = getdigraph(backspaced, c, FALSE);
+ backspaced = -1;
+ if ((c == K_BS || c == Ctrl_H) && lastchar >= 0)
+ backspaced = lastchar;
+ }
+ lastchar = c;
+ return c;
+}
+
+/*
+ * Find a digraph for "val". If found return the string to display it.
+ * If not found return NULL.
+ */
+ char_u *
+get_digraph_for_char(int val_arg)
+{
+ int val = val_arg;
+ int i;
+ int use_defaults;
+ digr_T *dp;
+ static char_u r[3];
+
+#if defined(USE_UNICODE_DIGRAPHS)
+ if (!enc_utf8)
+ {
+ char_u buf[6], *to;
+ vimconv_T vc;
+
+ // convert the character from 'encoding' to Unicode
+ i = mb_char2bytes(val, buf);
+ vc.vc_type = CONV_NONE;
+ if (convert_setup(&vc, p_enc, (char_u *)"utf-8") == OK)
+ {
+ vc.vc_fail = TRUE;
+ to = string_convert(&vc, buf, &i);
+ if (to != NULL)
+ {
+ val = utf_ptr2char(to);
+ vim_free(to);
+ }
+ (void)convert_setup(&vc, NULL, NULL);
+ }
+ }
+#endif
+
+ for (use_defaults = 0; use_defaults <= 1; use_defaults++)
+ {
+ if (use_defaults == 0)
+ dp = (digr_T *)user_digraphs.ga_data;
+ else
+ dp = digraphdefault;
+ for (i = 0; use_defaults ? dp->char1 != NUL
+ : i < user_digraphs.ga_len; ++i)
+ {
+ if (dp->result == val)
+ {
+ r[0] = dp->char1;
+ r[1] = dp->char2;
+ r[2] = NUL;
+ return r;
+ }
+ ++dp;
+ }
+ }
+ return NULL;
+}
+
+/*
+ * Get a digraph. Used after typing CTRL-K on the command line or in normal
+ * mode.
+ * Returns composed character, or NUL when ESC was used.
+ */
+ int
+get_digraph(
+ int cmdline) /* TRUE when called from the cmdline */
+{
+ int c, cc;
+
+ ++no_mapping;
+ ++allow_keys;
+ c = plain_vgetc();
+ --no_mapping;
+ --allow_keys;
+ if (c != ESC) /* ESC cancels CTRL-K */
+ {
+ if (IS_SPECIAL(c)) /* insert special key code */
+ return c;
+ if (cmdline)
+ {
+ if (char2cells(c) == 1
+#if defined(FEAT_CRYPT) || defined(FEAT_EVAL)
+ && cmdline_star == 0
+#endif
+ )
+ putcmdline(c, TRUE);
+ }
+#ifdef FEAT_CMDL_INFO
+ else
+ add_to_showcmd(c);
+#endif
+ ++no_mapping;
+ ++allow_keys;
+ cc = plain_vgetc();
+ --no_mapping;
+ --allow_keys;
+ if (cc != ESC) /* ESC cancels CTRL-K */
+ return getdigraph(c, cc, TRUE);
+ }
+ return NUL;
+}
+
+/*
+ * Lookup the pair "char1", "char2" in the digraph tables.
+ * If no match, return "char2".
+ * If "meta_char" is TRUE and "char1" is a space, return "char2" | 0x80.
+ */
+ static int
+getexactdigraph(int char1, int char2, int meta_char)
+{
+ int i;
+ int retval = 0;
+ digr_T *dp;
+
+ if (IS_SPECIAL(char1) || IS_SPECIAL(char2))
+ return char2;
+
+ /*
+ * Search user digraphs first.
+ */
+ dp = (digr_T *)user_digraphs.ga_data;
+ for (i = 0; i < user_digraphs.ga_len; ++i)
+ {
+ if ((int)dp->char1 == char1 && (int)dp->char2 == char2)
+ {
+ retval = dp->result;
+ break;
+ }
+ ++dp;
+ }
+
+ /*
+ * Search default digraphs.
+ */
+ if (retval == 0)
+ {
+ dp = digraphdefault;
+ for (i = 0; dp->char1 != 0; ++i)
+ {
+ if ((int)dp->char1 == char1 && (int)dp->char2 == char2)
+ {
+ retval = dp->result;
+ break;
+ }
+ ++dp;
+ }
+ }
+#ifdef USE_UNICODE_DIGRAPHS
+ if (retval != 0 && !enc_utf8)
+ {
+ char_u buf[6], *to;
+ vimconv_T vc;
+
+ /*
+ * Convert the Unicode digraph to 'encoding'.
+ */
+ i = utf_char2bytes(retval, buf);
+ retval = 0;
+ vc.vc_type = CONV_NONE;
+ if (convert_setup(&vc, (char_u *)"utf-8", p_enc) == OK)
+ {
+ vc.vc_fail = TRUE;
+ to = string_convert(&vc, buf, &i);
+ if (to != NULL)
+ {
+ retval = (*mb_ptr2char)(to);
+ vim_free(to);
+ }
+ (void)convert_setup(&vc, NULL, NULL);
+ }
+ }
+#endif
+
+ /* Ignore multi-byte characters when not in multi-byte mode. */
+ if (!has_mbyte && retval > 0xff)
+ retval = 0;
+
+ if (retval == 0) /* digraph deleted or not found */
+ {
+ if (char1 == ' ' && meta_char) /* <space> <char> --> meta-char */
+ return (char2 | 0x80);
+ return char2;
+ }
+ return retval;
+}
+
+/*
+ * Get digraph.
+ * Allow for both char1-char2 and char2-char1
+ */
+ int
+getdigraph(int char1, int char2, int meta_char)
+{
+ int retval;
+
+ if (((retval = getexactdigraph(char1, char2, meta_char)) == char2)
+ && (char1 != char2)
+ && ((retval = getexactdigraph(char2, char1, meta_char)) == char1))
+ return char2;
+ return retval;
+}
+
+/*
+ * Add the digraphs in the argument to the digraph table.
+ * format: {c1}{c2} char {c1}{c2} char ...
+ */
+ void
+putdigraph(char_u *str)
+{
+ int char1, char2, n;
+ int i;
+ digr_T *dp;
+
+ while (*str != NUL)
+ {
+ str = skipwhite(str);
+ if (*str == NUL)
+ return;
+ char1 = *str++;
+ char2 = *str++;
+ if (char2 == 0)
+ {
+ emsg(_(e_invarg));
+ return;
+ }
+ if (char1 == ESC || char2 == ESC)
+ {
+ emsg(_("E104: Escape not allowed in digraph"));
+ return;
+ }
+ str = skipwhite(str);
+ if (!VIM_ISDIGIT(*str))
+ {
+ emsg(_(e_number_exp));
+ return;
+ }
+ n = getdigits(&str);
+
+ /* If the digraph already exists, replace the result. */
+ dp = (digr_T *)user_digraphs.ga_data;
+ for (i = 0; i < user_digraphs.ga_len; ++i)
+ {
+ if ((int)dp->char1 == char1 && (int)dp->char2 == char2)
+ {
+ dp->result = n;
+ break;
+ }
+ ++dp;
+ }
+
+ /* Add a new digraph to the table. */
+ if (i == user_digraphs.ga_len)
+ {
+ if (ga_grow(&user_digraphs, 1) == OK)
+ {
+ dp = (digr_T *)user_digraphs.ga_data + user_digraphs.ga_len;
+ dp->char1 = char1;
+ dp->char2 = char2;
+ dp->result = n;
+ ++user_digraphs.ga_len;
+ }
+ }
+ }
+}
+
+#if defined(USE_UNICODE_DIGRAPHS)
+ static void
+digraph_header(char *msg)
+{
+ if (msg_col > 0)
+ msg_putchar('\n');
+ msg_outtrans_attr((char_u *)msg, HL_ATTR(HLF_CM));
+ msg_putchar('\n');
+}
+#endif
+
+ void
+listdigraphs(int use_headers)
+{
+ int i;
+ digr_T *dp;
+ result_T previous = 0;
+
+ msg_putchar('\n');
+
+ dp = digraphdefault;
+ for (i = 0; dp->char1 != NUL && !got_int; ++i)
+ {
+#if defined(USE_UNICODE_DIGRAPHS)
+ digr_T tmp;
+
+ /* May need to convert the result to 'encoding'. */
+ tmp.char1 = dp->char1;
+ tmp.char2 = dp->char2;
+ tmp.result = getexactdigraph(tmp.char1, tmp.char2, FALSE);
+ if (tmp.result != 0 && tmp.result != tmp.char2
+ && (has_mbyte || tmp.result <= 255))
+ printdigraph(&tmp, use_headers ? &previous : NULL);
+#else
+
+ if (getexactdigraph(dp->char1, dp->char2, FALSE) == dp->result
+ && (has_mbyte || dp->result <= 255))
+ printdigraph(dp, use_headers ? &previous : NULL);
+#endif
+ ++dp;
+ ui_breakcheck();
+ }
+
+ dp = (digr_T *)user_digraphs.ga_data;
+ for (i = 0; i < user_digraphs.ga_len && !got_int; ++i)
+ {
+#if defined(USE_UNICODE_DIGRAPHS)
+ if (previous >= 0 && use_headers)
+ digraph_header(_("Custom"));
+ previous = -1;
+#endif
+ printdigraph(dp, NULL);
+ ui_breakcheck();
+ ++dp;
+ }
+ must_redraw = CLEAR; /* clear screen, because some digraphs may be
+ wrong, in which case we messed up ScreenLines */
+}
+
+struct dg_header_entry {
+ int dg_start;
+ char *dg_header;
+} header_table[] = {
+ {DG_START_LATIN, N_("Latin supplement")},
+ {DG_START_GREEK, N_("Greek and Coptic")},
+ {DG_START_CYRILLIC, N_("Cyrillic")},
+ {DG_START_HEBREW, N_("Hebrew")},
+ {DG_START_ARABIC, N_("Arabic")},
+ {DG_START_LATIN_EXTENDED, N_("Latin extended")},
+ {DG_START_GREEK_EXTENDED, N_("Greek extended")},
+ {DG_START_PUNCTUATION, N_("Punctuation")},
+ {DG_START_SUB_SUPER, N_("Super- and subscripts")},
+ {DG_START_CURRENCY, N_("Currency")},
+ {DG_START_OTHER1, N_("Other")},
+ {DG_START_ROMAN, N_("Roman numbers")},
+ {DG_START_ARROWS, N_("Arrows")},
+ {DG_START_MATH, N_("Mathematical operators")},
+ {DG_START_TECHNICAL, N_("Technical")},
+ {DG_START_OTHER2, N_("Other")},
+ {DG_START_DRAWING, N_("Box drawing")},
+ {DG_START_BLOCK, N_("Block elements")},
+ {DG_START_SHAPES, N_("Geometric shapes")},
+ {DG_START_SYMBOLS, N_("Symbols")},
+ {DG_START_DINGBATS, N_("Dingbats")},
+ {DG_START_CJK_SYMBOLS, N_("CJK symbols and punctuation")},
+ {DG_START_HIRAGANA, N_("Hiragana")},
+ {DG_START_KATAKANA, N_("Katakana")},
+ {DG_START_BOPOMOFO, N_("Bopomofo")},
+ {DG_START_OTHER3, N_("Other")},
+ {0xfffffff, NULL},
+};
+
+ static void
+printdigraph(digr_T *dp, result_T *previous)
+{
+ char_u buf[30];
+ char_u *p;
+
+ int list_width;
+
+ if ((dy_flags & DY_UHEX) || has_mbyte)
+ list_width = 13;
+ else
+ list_width = 11;
+
+ if (dp->result != 0)
+ {
+#if defined(USE_UNICODE_DIGRAPHS)
+ if (previous != NULL)
+ {
+ int i;
+
+ for (i = 0; header_table[i].dg_header != NULL; ++i)
+ if (*previous < header_table[i].dg_start
+ && dp->result >= header_table[i].dg_start
+ && dp->result < header_table[i + 1].dg_start)
+ {
+ digraph_header(_(header_table[i].dg_header));
+ break;
+ }
+ *previous = dp->result;
+ }
+#endif
+ if (msg_col > Columns - list_width)
+ msg_putchar('\n');
+ if (msg_col)
+ while (msg_col % list_width != 0)
+ msg_putchar(' ');
+
+ p = buf;
+ *p++ = dp->char1;
+ *p++ = dp->char2;
+ *p++ = ' ';
+ *p = NUL;
+ msg_outtrans(buf);
+ p = buf;
+ if (has_mbyte)
+ {
+ /* add a space to draw a composing char on */
+ if (enc_utf8 && utf_iscomposing(dp->result))
+ *p++ = ' ';
+ p += (*mb_char2bytes)(dp->result, p);
+ }
+ else
+ *p++ = (char_u)dp->result;
+ *p = NUL;
+ msg_outtrans_attr(buf, HL_ATTR(HLF_8));
+ p = buf;
+ if (char2cells(dp->result) == 1)
+ *p++ = ' ';
+ vim_snprintf((char *)p, sizeof(buf) - (p - buf), " %3d", dp->result);
+ msg_outtrans(buf);
+ }
+}
+
+#endif /* FEAT_DIGRAPHS */
+
+#if defined(FEAT_KEYMAP) || defined(PROTO)
+
+/* structure used for b_kmap_ga.ga_data */
+typedef struct
+{
+ char_u *from;
+ char_u *to;
+} kmap_T;
+
+#define KMAP_MAXLEN 20 /* maximum length of "from" or "to" */
+
+static void keymap_unload(void);
+
+/*
+ * Set up key mapping tables for the 'keymap' option.
+ * Returns NULL if OK, an error message for failure. This only needs to be
+ * used when setting the option, not later when the value has already been
+ * checked.
+ */
+ char *
+keymap_init(void)
+{
+ curbuf->b_kmap_state &= ~KEYMAP_INIT;
+
+ if (*curbuf->b_p_keymap == NUL)
+ {
+ /* Stop any active keymap and clear the table. Also remove
+ * b:keymap_name, as no keymap is active now. */
+ keymap_unload();
+ do_cmdline_cmd((char_u *)"unlet! b:keymap_name");
+ }
+ else
+ {
+ char_u *buf;
+ size_t buflen;
+
+ /* Source the keymap file. It will contain a ":loadkeymap" command
+ * which will call ex_loadkeymap() below. */
+ buflen = STRLEN(curbuf->b_p_keymap) + STRLEN(p_enc) + 14;
+ buf = alloc((unsigned)buflen);
+ if (buf == NULL)
+ return e_outofmem;
+
+ /* try finding "keymap/'keymap'_'encoding'.vim" in 'runtimepath' */
+ vim_snprintf((char *)buf, buflen, "keymap/%s_%s.vim",
+ curbuf->b_p_keymap, p_enc);
+ if (source_runtime(buf, 0) == FAIL)
+ {
+ /* try finding "keymap/'keymap'.vim" in 'runtimepath' */
+ vim_snprintf((char *)buf, buflen, "keymap/%s.vim",
+ curbuf->b_p_keymap);
+ if (source_runtime(buf, 0) == FAIL)
+ {
+ vim_free(buf);
+ return N_("E544: Keymap file not found");
+ }
+ }
+ vim_free(buf);
+ }
+
+ return NULL;
+}
+
+/*
+ * ":loadkeymap" command: load the following lines as the keymap.
+ */
+ void
+ex_loadkeymap(exarg_T *eap)
+{
+ char_u *line;
+ char_u *p;
+ char_u *s;
+ kmap_T *kp;
+#define KMAP_LLEN 200 /* max length of "to" and "from" together */
+ char_u buf[KMAP_LLEN + 11];
+ int i;
+ char_u *save_cpo = p_cpo;
+
+ if (!getline_equal(eap->getline, eap->cookie, getsourceline))
+ {
+ emsg(_("E105: Using :loadkeymap not in a sourced file"));
+ return;
+ }
+
+ /*
+ * Stop any active keymap and clear the table.
+ */
+ keymap_unload();
+
+ curbuf->b_kmap_state = 0;
+ ga_init2(&curbuf->b_kmap_ga, (int)sizeof(kmap_T), 20);
+
+ /* Set 'cpoptions' to "C" to avoid line continuation. */
+ p_cpo = (char_u *)"C";
+
+ /*
+ * Get each line of the sourced file, break at the end.
+ */
+ for (;;)
+ {
+ line = eap->getline(0, eap->cookie, 0);
+ if (line == NULL)
+ break;
+
+ p = skipwhite(line);
+ if (*p != '"' && *p != NUL && ga_grow(&curbuf->b_kmap_ga, 1) == OK)
+ {
+ kp = (kmap_T *)curbuf->b_kmap_ga.ga_data + curbuf->b_kmap_ga.ga_len;
+ s = skiptowhite(p);
+ kp->from = vim_strnsave(p, (int)(s - p));
+ p = skipwhite(s);
+ s = skiptowhite(p);
+ kp->to = vim_strnsave(p, (int)(s - p));
+
+ if (kp->from == NULL || kp->to == NULL
+ || STRLEN(kp->from) + STRLEN(kp->to) >= KMAP_LLEN
+ || *kp->from == NUL || *kp->to == NUL)
+ {
+ if (kp->to != NULL && *kp->to == NUL)
+ emsg(_("E791: Empty keymap entry"));
+ vim_free(kp->from);
+ vim_free(kp->to);
+ }
+ else
+ ++curbuf->b_kmap_ga.ga_len;
+ }
+ vim_free(line);
+ }
+
+ /*
+ * setup ":lnoremap" to map the keys
+ */
+ for (i = 0; i < curbuf->b_kmap_ga.ga_len; ++i)
+ {
+ vim_snprintf((char *)buf, sizeof(buf), "<buffer> %s %s",
+ ((kmap_T *)curbuf->b_kmap_ga.ga_data)[i].from,
+ ((kmap_T *)curbuf->b_kmap_ga.ga_data)[i].to);
+ (void)do_map(2, buf, LANGMAP, FALSE);
+ }
+
+ p_cpo = save_cpo;
+
+ curbuf->b_kmap_state |= KEYMAP_LOADED;
+ status_redraw_curbuf();
+}
+
+/*
+ * Stop using 'keymap'.
+ */
+ static void
+keymap_unload(void)
+{
+ char_u buf[KMAP_MAXLEN + 10];
+ int i;
+ char_u *save_cpo = p_cpo;
+ kmap_T *kp;
+
+ if (!(curbuf->b_kmap_state & KEYMAP_LOADED))
+ return;
+
+ /* Set 'cpoptions' to "C" to avoid line continuation. */
+ p_cpo = (char_u *)"C";
+
+ /* clear the ":lmap"s */
+ kp = (kmap_T *)curbuf->b_kmap_ga.ga_data;
+ for (i = 0; i < curbuf->b_kmap_ga.ga_len; ++i)
+ {
+ vim_snprintf((char *)buf, sizeof(buf), "<buffer> %s", kp[i].from);
+ (void)do_map(1, buf, LANGMAP, FALSE);
+ }
+ keymap_clear(&curbuf->b_kmap_ga);
+
+ p_cpo = save_cpo;
+
+ ga_clear(&curbuf->b_kmap_ga);
+ curbuf->b_kmap_state &= ~KEYMAP_LOADED;
+ status_redraw_curbuf();
+}
+
+ void
+keymap_clear(garray_T *kmap)
+{
+ int i;
+ kmap_T *kp = (kmap_T *)kmap->ga_data;
+
+ for (i = 0; i < kmap->ga_len; ++i)
+ {
+ vim_free(kp[i].from);
+ vim_free(kp[i].to);
+ }
+}
+#endif /* FEAT_KEYMAP */
diff --git a/src/dimm.idl b/src/dimm.idl
new file mode 100644
index 0000000..ac44965
--- /dev/null
+++ b/src/dimm.idl
@@ -0,0 +1,544 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992-2000.
+//
+// File: dimm.idl
+//
+// Contents: ActiveIMM interface definitions
+//
+//
+//--------------------------------------------------------------------------
+
+cpp_quote("//=--------------------------------------------------------------------------=")
+cpp_quote("// dimm.h")
+cpp_quote("//=--------------------------------------------------------------------------=")
+cpp_quote("// (C) Copyright 1995-1998 Microsoft Corporation. All Rights Reserved.")
+cpp_quote("//")
+cpp_quote("// THIS CODE AND INFORMATION IS PROVIDED \"AS IS\" WITHOUT WARRANTY OF")
+cpp_quote("// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO")
+cpp_quote("// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A")
+cpp_quote("// PARTICULAR PURPOSE.")
+cpp_quote("//=--------------------------------------------------------------------------=")
+cpp_quote("")
+cpp_quote("#pragma comment(lib,\"uuid.lib\")")
+cpp_quote("")
+cpp_quote("//--------------------------------------------------------------------------")
+cpp_quote("// IActiveIMM Interfaces.")
+cpp_quote("")
+
+/*
+Disable a warning about lack of polymorphic type support for the following reasons
+- the only reason to have library block in the file is to make midl accept coclass
+ statement and generate CLSID for CActiveIMM.
+- the generated dimm_i.c has the clsid and that file is used to have clsid available
+- the dimm.tlb is not used at all
+- on top of it, there is no plans to port the app using dimm.idl to 64b platform.
+*/
+/*
+ * midl_pragma is unsupported in midl version 3.01 shipped with VC5.0.
+ * It is supported in midl version 5.01 shipped with VC6.0
+ * I could not produce message 2395. Is this needed? W.Briscoe 2001-08-14
+ */
+#if (__midl >= 501)
+midl_pragma warning( disable: 2395) // polymorphic types not supported in the TLB
+#endif
+
+#ifndef DO_NO_IMPORTS
+import "unknwn.idl";
+#endif
+
+[
+ uuid(4955DD30-B159-11d0-8FCF-00AA006BCC59),
+ helpstring("ActiveIMM"),
+ lcid(0x0000),
+ version(0.1)
+]
+library ActiveIMM
+{
+ importlib("stdole2.tlb");
+
+ cpp_quote("#include <imm.h>")
+
+ cpp_quote("#if 0")
+
+ typedef WORD LANGID;
+
+ typedef struct
+ {
+ LPSTR lpReading;
+ LPSTR lpWord;
+ } REGISTERWORDA;
+
+ typedef struct
+ {
+ LPWSTR lpReading;
+ LPWSTR lpWord;
+ } REGISTERWORDW;
+
+ #define LF_FACESIZE 32
+
+ typedef struct
+ {
+ LONG lfHeight;
+ LONG lfWidth;
+ LONG lfEscapement;
+ LONG lfOrientation;
+ LONG lfWeight;
+ BYTE lfItalic;
+ BYTE lfUnderline;
+ BYTE lfStrikeOut;
+ BYTE lfCharSet;
+ BYTE lfOutPrecision;
+ BYTE lfClipPrecision;
+ BYTE lfQuality;
+ BYTE lfPitchAndFamily;
+ CHAR lfFaceName[LF_FACESIZE];
+ } LOGFONTA;
+
+ typedef struct
+ {
+ LONG lfHeight;
+ LONG lfWidth;
+ LONG lfEscapement;
+ LONG lfOrientation;
+ LONG lfWeight;
+ BYTE lfItalic;
+ BYTE lfUnderline;
+ BYTE lfStrikeOut;
+ BYTE lfCharSet;
+ BYTE lfOutPrecision;
+ BYTE lfClipPrecision;
+ BYTE lfQuality;
+ BYTE lfPitchAndFamily;
+ WCHAR lfFaceName[LF_FACESIZE];
+ } LOGFONTW;
+
+ typedef DWORD HIMC;
+ typedef DWORD HIMCC;
+
+ typedef struct
+ {
+ DWORD dwIndex;
+ DWORD dwStyle;
+ POINT ptCurrentPos;
+ RECT rcArea;
+ } CANDIDATEFORM;
+
+ typedef struct
+ {
+ DWORD dwStyle;
+ POINT ptCurrentPos;
+ RECT rcArea;
+ } COMPOSITIONFORM;
+
+ typedef struct
+ {
+ DWORD dwSize;
+ DWORD dwStyle;
+ DWORD dwCount;
+ DWORD dwSelection;
+ DWORD dwPageStart;
+ DWORD dwPageSize;
+ DWORD dwOffset[1];
+ } CANDIDATELIST;
+
+ #define STYLE_DESCRIPTION_SIZE 32
+
+ typedef struct
+ {
+ DWORD dwStyle;
+ CHAR szDescription[STYLE_DESCRIPTION_SIZE];
+ } STYLEBUFA;
+
+ typedef struct
+ {
+ DWORD dwStyle;
+ WCHAR szDescription[STYLE_DESCRIPTION_SIZE];
+ } STYLEBUFW;
+
+ typedef WORD ATOM;
+
+ cpp_quote("#endif")
+
+ cpp_quote("#if (WINVER < 0x040A)")
+
+ #define IMEMENUITEM_STRING_SIZE 80
+
+ typedef struct
+ {
+ UINT cbSize;
+ UINT fType;
+ UINT fState;
+ UINT wID;
+ HBITMAP hbmpChecked;
+ HBITMAP hbmpUnchecked;
+ DWORD dwItemData;
+ CHAR szString[IMEMENUITEM_STRING_SIZE];
+ HBITMAP hbmpItem;
+ } IMEMENUITEMINFOA;
+
+ typedef struct
+ {
+ UINT cbSize;
+ UINT fType;
+ UINT fState;
+ UINT wID;
+ HBITMAP hbmpChecked;
+ HBITMAP hbmpUnchecked;
+ DWORD dwItemData;
+ WCHAR szString[IMEMENUITEM_STRING_SIZE];
+ HBITMAP hbmpItem;
+ } IMEMENUITEMINFOW;
+
+ cpp_quote("#endif")
+
+ cpp_quote("#ifndef _DDKIMM_H_")
+
+ typedef struct
+ {
+ HWND hWnd;
+ BOOL fOpen;
+ POINT ptStatusWndPos;
+ POINT ptSoftKbdPos;
+ DWORD fdwConversion;
+ DWORD fdwSentence;
+ union
+ {
+ LOGFONTA A;
+ LOGFONTW W;
+ } lfFont;
+ COMPOSITIONFORM cfCompForm;
+ CANDIDATEFORM cfCandForm[4];
+ HIMCC hCompStr;
+ HIMCC hCandInfo;
+ HIMCC hGuideLine;
+ HIMCC hPrivate;
+ DWORD dwNumMsgBuf;
+ HIMCC hMsgBuf;
+ DWORD fdwInit;
+ DWORD dwReserve[3];
+ } INPUTCONTEXT;
+
+ typedef struct
+ {
+ DWORD dwPrivateDataSize;
+ DWORD fdwProperty;
+ DWORD fdwConversionCaps;
+ DWORD fdwSentenceCaps;
+ DWORD fdwUICaps;
+ DWORD fdwSCSCaps;
+ DWORD fdwSelectCaps;
+ } IMEINFO;
+
+ cpp_quote("#endif")
+
+ [
+ object,
+ uuid(08C03412-F96B-11d0-A475-00AA006BCC59),
+ pointer_default(unique)
+ ]
+ interface IEnumRegisterWordA : IUnknown
+ {
+ HRESULT Clone([out] IEnumRegisterWordA **ppEnum);
+ HRESULT Next([in] ULONG ulCount, [out] REGISTERWORDA *rgRegisterWord, [out] ULONG *pcFetched);
+ HRESULT Reset();
+ HRESULT Skip([in] ULONG ulCount);
+ };
+
+ [
+ object,
+ uuid(4955DD31-B159-11d0-8FCF-00AA006BCC59),
+ pointer_default(unique)
+ ]
+ interface IEnumRegisterWordW : IUnknown
+ {
+ HRESULT Clone([out] IEnumRegisterWordW **ppEnum);
+ HRESULT Next([in] ULONG ulCount, [out] REGISTERWORDW *rgRegisterWord, [out] ULONG *pcFetched);
+ HRESULT Reset();
+ HRESULT Skip([in] ULONG ulCount);
+ };
+
+
+ [
+ object,
+ uuid(09b5eab0-f997-11d1-93d4-0060b067b86e),
+ pointer_default(unique)
+ ]
+ interface IEnumInputContext : IUnknown
+ {
+ HRESULT Clone([out] IEnumInputContext **ppEnum);
+ HRESULT Next([in] ULONG ulCount, [out] HIMC *rgInputContext, [out] ULONG *pcFetched);
+ HRESULT Reset();
+ HRESULT Skip([in] ULONG ulCount);
+ };
+
+
+ [
+ object,
+ uuid(b3458082-bd00-11d1-939b-0060b067b86e),
+ pointer_default(unique)
+ ]
+ interface IActiveIMMRegistrar : IUnknown
+ {
+ HRESULT RegisterIME([in] REFCLSID rclsid, [in] LANGID lgid, [in] LPCWSTR pszIconFile, [in] LPCWSTR pszDesc);
+ HRESULT UnregisterIME([in] REFCLSID rclsid);
+ };
+
+ [
+ object,
+ uuid(b5cf2cfa-8aeb-11d1-9364-0060b067b86e),
+ pointer_default(unique)
+ ]
+ interface IActiveIMMMessagePumpOwner : IUnknown
+ {
+ HRESULT Start();
+ HRESULT End();
+ HRESULT OnTranslateMessage([in] const MSG *pMsg);
+ HRESULT Pause([out] DWORD *pdwCookie);
+ HRESULT Resume([in] DWORD dwCookie);
+ }
+
+ [
+ object,
+ uuid(08c0e040-62d1-11d1-9326-0060b067b86e),
+ pointer_default(unique)
+ ]
+ interface IActiveIMMApp : IUnknown
+ {
+ HRESULT AssociateContext([in] HWND hWnd, [in] HIMC hIME, [out] HIMC *phPrev);
+ HRESULT ConfigureIMEA([in] HKL hKL, [in] HWND hWnd, [in] DWORD dwMode, [in] REGISTERWORDA *pData);
+ HRESULT ConfigureIMEW([in] HKL hKL, [in] HWND hWnd, [in] DWORD dwMode, [in] REGISTERWORDW *pData);
+ HRESULT CreateContext([out] HIMC *phIMC);
+ HRESULT DestroyContext([in] HIMC hIME);
+ HRESULT EnumRegisterWordA([in] HKL hKL, [in] LPSTR szReading, [in] DWORD dwStyle, [in] LPSTR szRegister, [in] LPVOID pData, [out] IEnumRegisterWordA **pEnum);
+ HRESULT EnumRegisterWordW([in] HKL hKL, [in] LPWSTR szReading, [in] DWORD dwStyle, [in] LPWSTR szRegister, [in] LPVOID pData, [out] IEnumRegisterWordW **pEnum);
+ HRESULT EscapeA([in] HKL hKL, [in] HIMC hIMC, [in] UINT uEscape, [in, out] LPVOID pData, [out] LRESULT *plResult);
+ HRESULT EscapeW([in] HKL hKL, [in] HIMC hIMC, [in] UINT uEscape, [in, out] LPVOID pData, [out] LRESULT *plResult);
+ HRESULT GetCandidateListA([in] HIMC hIMC, [in] DWORD dwIndex, [in] UINT uBufLen, [out] CANDIDATELIST *pCandList, [out] UINT *puCopied);
+ HRESULT GetCandidateListW([in] HIMC hIMC, [in] DWORD dwIndex, [in] UINT uBufLen, [out] CANDIDATELIST *pCandList, [out] UINT *puCopied);
+ HRESULT GetCandidateListCountA([in] HIMC hIMC, [out] DWORD *pdwListSize, [out] DWORD *pdwBufLen);
+ HRESULT GetCandidateListCountW([in] HIMC hIMC, [out] DWORD *pdwListSize, [out] DWORD *pdwBufLen);
+ HRESULT GetCandidateWindow([in] HIMC hIMC, [in] DWORD dwIndex, [out] CANDIDATEFORM *pCandidate);
+ HRESULT GetCompositionFontA([in] HIMC hIMC, [out] LOGFONTA *plf);
+ HRESULT GetCompositionFontW([in] HIMC hIMC, [out] LOGFONTW *plf);
+ HRESULT GetCompositionStringA([in] HIMC hIMC, [in] DWORD dwIndex, [in] DWORD dwBufLen, [out] LONG *plCopied, [out] LPVOID pBuf);
+ HRESULT GetCompositionStringW([in] HIMC hIMC, [in] DWORD dwIndex, [in] DWORD dwBufLen, [out] LONG *plCopied, [out] LPVOID pBuf);
+ HRESULT GetCompositionWindow([in] HIMC hIMC, [out] COMPOSITIONFORM *pCompForm);
+ HRESULT GetContext([in] HWND hWnd, [out] HIMC *phIMC);
+ HRESULT GetConversionListA([in] HKL hKL, [in] HIMC hIMC, [in] LPSTR pSrc, [in] UINT uBufLen, [in] UINT uFlag, [out] CANDIDATELIST *pDst, [out] UINT *puCopied);
+ HRESULT GetConversionListW([in] HKL hKL, [in] HIMC hIMC, [in] LPWSTR pSrc, [in] UINT uBufLen, [in] UINT uFlag, [out] CANDIDATELIST *pDst, [out] UINT *puCopied);
+ HRESULT GetConversionStatus([in] HIMC hIMC, [out] DWORD *pfdwConversion, [out] DWORD *pfdwSentence);
+ HRESULT GetDefaultIMEWnd([in] HWND hWnd, [out] HWND *phDefWnd);
+ HRESULT GetDescriptionA([in] HKL hKL, [in] UINT uBufLen, [out] LPSTR szDescription, [out] UINT *puCopied);
+ HRESULT GetDescriptionW([in] HKL hKL, [in] UINT uBufLen, [out] LPWSTR szDescription, [out] UINT *puCopied);
+ HRESULT GetGuideLineA([in] HIMC hIMC, [in] DWORD dwIndex, [in] DWORD dwBufLen, [out] LPSTR pBuf, [out] DWORD *pdwResult);
+ HRESULT GetGuideLineW([in] HIMC hIMC, [in] DWORD dwIndex, [in] DWORD dwBufLen, [out] LPWSTR pBuf, [out] DWORD *pdwResult);
+ HRESULT GetIMEFileNameA([in] HKL hKL, [in] UINT uBufLen, [out] LPSTR szFileName, [out] UINT *puCopied);
+ HRESULT GetIMEFileNameW([in] HKL hKL, [in] UINT uBufLen, [out] LPWSTR szFileName, [out] UINT *puCopied);
+ HRESULT GetOpenStatus([in] HIMC hIMC);
+ HRESULT GetProperty([in] HKL hKL, [in] DWORD fdwIndex, [out] DWORD *pdwProperty);
+ HRESULT GetRegisterWordStyleA([in] HKL hKL, [in] UINT nItem, [out] STYLEBUFA *pStyleBuf, [out] UINT *puCopied);
+ HRESULT GetRegisterWordStyleW([in] HKL hKL, [in] UINT nItem, [out] STYLEBUFW *pStyleBuf, [out] UINT *puCopied);
+ HRESULT GetStatusWindowPos([in] HIMC hIMC, [out] POINT *pptPos);
+ HRESULT GetVirtualKey([in] HWND hWnd, [out] UINT *puVirtualKey);
+ HRESULT InstallIMEA([in] LPSTR szIMEFileName, [in] LPSTR szLayoutText, [out] HKL *phKL);
+ HRESULT InstallIMEW([in] LPWSTR szIMEFileName, [in] LPWSTR szLayoutText, [out] HKL *phKL);
+ HRESULT IsIME([in] HKL hKL);
+ HRESULT IsUIMessageA([in] HWND hWndIME, [in] UINT msg, [in] WPARAM wParam, [in] LPARAM lParam);
+ HRESULT IsUIMessageW([in] HWND hWndIME, [in] UINT msg, [in] WPARAM wParam, [in] LPARAM lParam);
+ HRESULT NotifyIME([in] HIMC hIMC, [in] DWORD dwAction, [in] DWORD dwIndex, [in] DWORD dwValue);
+ HRESULT RegisterWordA([in] HKL hKL, [in] LPSTR szReading, [in] DWORD dwStyle, [in] LPSTR szRegister);
+ HRESULT RegisterWordW([in] HKL hKL, [in] LPWSTR szReading, [in] DWORD dwStyle, [in] LPWSTR szRegister);
+ HRESULT ReleaseContext([in] HWND hWnd, [in] HIMC hIMC);
+ HRESULT SetCandidateWindow([in] HIMC hIMC, [in] CANDIDATEFORM *pCandidate);
+ HRESULT SetCompositionFontA([in] HIMC hIMC, [in] LOGFONTA *plf);
+ HRESULT SetCompositionFontW([in] HIMC hIMC, [in] LOGFONTW *plf);
+ HRESULT SetCompositionStringA([in] HIMC hIMC, [in] DWORD dwIndex, [in] LPVOID pComp, [in] DWORD dwCompLen, [in] LPVOID pRead, [in] DWORD dwReadLen);
+ HRESULT SetCompositionStringW([in] HIMC hIMC, [in] DWORD dwIndex, [in] LPVOID pComp, [in] DWORD dwCompLen, [in] LPVOID pRead, [in] DWORD dwReadLen);
+ HRESULT SetCompositionWindow([in] HIMC hIMC, [in] COMPOSITIONFORM *pCompForm);
+ HRESULT SetConversionStatus([in] HIMC hIMC, [in] DWORD fdwConversion, [in] DWORD fdwSentence);
+ HRESULT SetOpenStatus([in] HIMC hIMC, [in] BOOL fOpen);
+ HRESULT SetStatusWindowPos([in] HIMC hIMC, [in] POINT *pptPos);
+ HRESULT SimulateHotKey([in] HWND hWnd, [in] DWORD dwHotKeyID);
+ HRESULT UnregisterWordA([in] HKL hKL, [in] LPSTR szReading, [in] DWORD dwStyle, [in] LPSTR szUnregister);
+ HRESULT UnregisterWordW([in] HKL hKL, [in] LPWSTR szReading, [in] DWORD dwStyle, [in] LPWSTR szUnregister);
+
+ HRESULT Activate([in] BOOL fRestoreLayout);
+ HRESULT Deactivate();
+
+ HRESULT OnDefWindowProc([in] HWND hWnd, [in] UINT Msg, [in] WPARAM wParam, [in] LPARAM lParam, [out] LRESULT *plResult);
+
+ HRESULT FilterClientWindows([in] ATOM *aaClassList, [in] UINT uSize);
+
+ HRESULT GetCodePageA([in] HKL hKL, [out] UINT *uCodePage);
+ HRESULT GetLangId([in] HKL hKL, [out] LANGID *plid);
+
+ // win98/nt5 apis
+ HRESULT AssociateContextEx([in] HWND hWnd, [in] HIMC hIMC, [in] DWORD dwFlags);
+ HRESULT DisableIME([in] DWORD idThread);
+ HRESULT GetImeMenuItemsA([in] HIMC hIMC, [in] DWORD dwFlags, [in] DWORD dwType, [in] IMEMENUITEMINFOA *pImeParentMenu, [out] IMEMENUITEMINFOA *pImeMenu, [in] DWORD dwSize, [out] DWORD *pdwResult);
+ HRESULT GetImeMenuItemsW([in] HIMC hIMC, [in] DWORD dwFlags, [in] DWORD dwType, [in] IMEMENUITEMINFOW *pImeParentMenu, [out] IMEMENUITEMINFOW *pImeMenu, [in] DWORD dwSize, [out] DWORD *pdwResult);
+ HRESULT EnumInputContext([in] DWORD idThread, [out] IEnumInputContext **ppEnum);
+ };
+
+ [
+ object,
+ uuid(08C03411-F96B-11d0-A475-00AA006BCC59),
+ pointer_default(unique)
+ ]
+ interface IActiveIMMIME : IUnknown
+ {
+ HRESULT AssociateContext([in] HWND hWnd, [in] HIMC hIME, [out] HIMC *phPrev);
+ HRESULT ConfigureIMEA([in] HKL hKL, [in] HWND hWnd, [in] DWORD dwMode, [in] REGISTERWORDA *pData);
+ HRESULT ConfigureIMEW([in] HKL hKL, [in] HWND hWnd, [in] DWORD dwMode, [in] REGISTERWORDW *pData);
+ HRESULT CreateContext([out] HIMC *phIMC);
+ HRESULT DestroyContext([in] HIMC hIME);
+ HRESULT EnumRegisterWordA([in] HKL hKL, [in] LPSTR szReading, [in] DWORD dwStyle, [in] LPSTR szRegister, [in] LPVOID pData, [out] IEnumRegisterWordA **pEnum);
+ HRESULT EnumRegisterWordW([in] HKL hKL, [in] LPWSTR szReading, [in] DWORD dwStyle, [in] LPWSTR szRegister, [in] LPVOID pData, [out] IEnumRegisterWordW **pEnum);
+ HRESULT EscapeA([in] HKL hKL, [in] HIMC hIMC, [in] UINT uEscape, [in, out] LPVOID pData, [out] LRESULT *plResult);
+ HRESULT EscapeW([in] HKL hKL, [in] HIMC hIMC, [in] UINT uEscape, [in, out] LPVOID pData, [out] LRESULT *plResult);
+ HRESULT GetCandidateListA([in] HIMC hIMC, [in] DWORD dwIndex, [in] UINT uBufLen, [out] CANDIDATELIST *pCandList, [out] UINT *puCopied);
+ HRESULT GetCandidateListW([in] HIMC hIMC, [in] DWORD dwIndex, [in] UINT uBufLen, [out] CANDIDATELIST *pCandList, [out] UINT *puCopied);
+ HRESULT GetCandidateListCountA([in] HIMC hIMC, [out] DWORD *pdwListSize, [out] DWORD *pdwBufLen);
+ HRESULT GetCandidateListCountW([in] HIMC hIMC, [out] DWORD *pdwListSize, [out] DWORD *pdwBufLen);
+ HRESULT GetCandidateWindow([in] HIMC hIMC, [in] DWORD dwIndex, [out] CANDIDATEFORM *pCandidate);
+ HRESULT GetCompositionFontA([in] HIMC hIMC, [out] LOGFONTA *plf);
+ HRESULT GetCompositionFontW([in] HIMC hIMC, [out] LOGFONTW *plf);
+ HRESULT GetCompositionStringA([in] HIMC hIMC, [in] DWORD dwIndex, [in] DWORD dwBufLen, [out] LONG *plCopied, [out] LPVOID pBuf);
+ HRESULT GetCompositionStringW([in] HIMC hIMC, [in] DWORD dwIndex, [in] DWORD dwBufLen, [out] LONG *plCopied, [out] LPVOID pBuf);
+ HRESULT GetCompositionWindow([in] HIMC hIMC, [out] COMPOSITIONFORM *pCompForm);
+ HRESULT GetContext([in] HWND hWnd, [out] HIMC *phIMC);
+ HRESULT GetConversionListA([in] HKL hKL, [in] HIMC hIMC, [in] LPSTR pSrc, [in] UINT uBufLen, [in] UINT uFlag, [out] CANDIDATELIST *pDst, [out] UINT *puCopied);
+ HRESULT GetConversionListW([in] HKL hKL, [in] HIMC hIMC, [in] LPWSTR pSrc, [in] UINT uBufLen, [in] UINT uFlag, [out] CANDIDATELIST *pDst, [out] UINT *puCopied);
+ HRESULT GetConversionStatus([in] HIMC hIMC, [out] DWORD *pfdwConversion, [out] DWORD *pfdwSentence);
+ HRESULT GetDefaultIMEWnd([in] HWND hWnd, [out] HWND *phDefWnd);
+ HRESULT GetDescriptionA([in] HKL hKL, [in] UINT uBufLen, [out] LPSTR szDescription, [out] UINT *puCopied);
+ HRESULT GetDescriptionW([in] HKL hKL, [in] UINT uBufLen, [out] LPWSTR szDescription, [out] UINT *puCopied);
+ HRESULT GetGuideLineA([in] HIMC hIMC, [in] DWORD dwIndex, [in] DWORD dwBufLen, [out] LPSTR pBuf, [out] DWORD *pdwResult);
+ HRESULT GetGuideLineW([in] HIMC hIMC, [in] DWORD dwIndex, [in] DWORD dwBufLen, [out] LPWSTR pBuf, [out] DWORD *pdwResult);
+ HRESULT GetIMEFileNameA([in] HKL hKL, [in] UINT uBufLen, [out] LPSTR szFileName, [out] UINT *puCopied);
+ HRESULT GetIMEFileNameW([in] HKL hKL, [in] UINT uBufLen, [out] LPWSTR szFileName, [out] UINT *puCopied);
+ HRESULT GetOpenStatus([in] HIMC hIMC);
+ HRESULT GetProperty([in] HKL hKL, [in] DWORD fdwIndex, [out] DWORD *pdwProperty);
+ HRESULT GetRegisterWordStyleA([in] HKL hKL, [in] UINT nItem, [out] STYLEBUFA *pStyleBuf, [out] UINT *puCopied);
+ HRESULT GetRegisterWordStyleW([in] HKL hKL, [in] UINT nItem, [out] STYLEBUFW *pStyleBuf, [out] UINT *puCopied);
+ HRESULT GetStatusWindowPos([in] HIMC hIMC, [out] POINT *pptPos);
+ HRESULT GetVirtualKey([in] HWND hWnd, [out] UINT *puVirtualKey);
+ HRESULT InstallIMEA([in] LPSTR szIMEFileName, [in] LPSTR szLayoutText, [out] HKL *phKL);
+ HRESULT InstallIMEW([in] LPWSTR szIMEFileName, [in] LPWSTR szLayoutText, [out] HKL *phKL);
+ HRESULT IsIME([in] HKL hKL);
+ HRESULT IsUIMessageA([in] HWND hWndIME, [in] UINT msg, [in] WPARAM wParam, [in] LPARAM lParam);
+ HRESULT IsUIMessageW([in] HWND hWndIME, [in] UINT msg, [in] WPARAM wParam, [in] LPARAM lParam);
+ HRESULT NotifyIME([in] HIMC hIMC, [in] DWORD dwAction, [in] DWORD dwIndex, [in] DWORD dwValue);
+ HRESULT RegisterWordA([in] HKL hKL, [in] LPSTR szReading, [in] DWORD dwStyle, [in] LPSTR szRegister);
+ HRESULT RegisterWordW([in] HKL hKL, [in] LPWSTR szReading, [in] DWORD dwStyle, [in] LPWSTR szRegister);
+ HRESULT ReleaseContext([in] HWND hWnd, [in] HIMC hIMC);
+ HRESULT SetCandidateWindow([in] HIMC hIMC, [in] CANDIDATEFORM *pCandidate);
+ HRESULT SetCompositionFontA([in] HIMC hIMC, [in] LOGFONTA *plf);
+ HRESULT SetCompositionFontW([in] HIMC hIMC, [in] LOGFONTW *plf);
+ HRESULT SetCompositionStringA([in] HIMC hIMC, [in] DWORD dwIndex, [in] LPVOID pComp, [in] DWORD dwCompLen, [in] LPVOID pRead, [in] DWORD dwReadLen);
+ HRESULT SetCompositionStringW([in] HIMC hIMC, [in] DWORD dwIndex, [in] LPVOID pComp, [in] DWORD dwCompLen, [in] LPVOID pRead, [in] DWORD dwReadLen);
+ HRESULT SetCompositionWindow([in] HIMC hIMC, [in] COMPOSITIONFORM *pCompForm);
+ HRESULT SetConversionStatus([in] HIMC hIMC, [in] DWORD fdwConversion, [in] DWORD fdwSentence);
+ HRESULT SetOpenStatus([in] HIMC hIMC, [in] BOOL fOpen);
+ HRESULT SetStatusWindowPos([in] HIMC hIMC, [in] POINT *pptPos);
+ HRESULT SimulateHotKey([in] HWND hWnd, [in] DWORD dwHotKeyID);
+ HRESULT UnregisterWordA([in] HKL hKL, [in] LPSTR szReading, [in] DWORD dwStyle, [in] LPSTR szUnregister);
+ HRESULT UnregisterWordW([in] HKL hKL, [in] LPWSTR szReading, [in] DWORD dwStyle, [in] LPWSTR szUnregister);
+
+ // ime helper methods
+ HRESULT GenerateMessage([in] HIMC hIMC);
+
+ // HIMC and HIMCC management api's
+ HRESULT LockIMC([in] HIMC hIMC, [out] INPUTCONTEXT **ppIMC);
+ HRESULT UnlockIMC([in] HIMC hIMC);
+ HRESULT GetIMCLockCount([in] HIMC hIMC, [out] DWORD *pdwLockCount);
+ HRESULT CreateIMCC([in] DWORD dwSize, [out] HIMCC *phIMCC);
+ HRESULT DestroyIMCC([in] HIMCC hIMCC);
+ HRESULT LockIMCC([in] HIMCC hIMCC, [out] void **ppv);
+ HRESULT UnlockIMCC([in] HIMCC hIMCC);
+ HRESULT ReSizeIMCC([in] HIMCC hIMCC, [in] DWORD dwSize, [out] HIMCC *phIMCC);
+ HRESULT GetIMCCSize([in] HIMCC hIMCC, [out] DWORD *pdwSize);
+ HRESULT GetIMCCLockCount([in] HIMCC hIMCC, [out] DWORD *pdwLockCount);
+
+ // hot key manipulation api's
+ HRESULT GetHotKey([in] DWORD dwHotKeyID, [out] UINT *puModifiers, [out] UINT *puVKey, [out] HKL *phKL);
+ HRESULT SetHotKey([in] DWORD dwHotKeyID, [in] UINT uModifiers, [in] UINT uVKey, [in] HKL hKL);
+
+ // soft keyboard api's
+ HRESULT CreateSoftKeyboard([in] UINT uType, [in] HWND hOwner, [in] int x, [in] int y, [out] HWND *phSoftKbdWnd);
+ HRESULT DestroySoftKeyboard([in] HWND hSoftKbdWnd);
+ HRESULT ShowSoftKeyboard([in] HWND hSoftKbdWnd, [in] int nCmdShow);
+
+ HRESULT GetCodePageA([in] HKL hKL, [out] UINT *uCodePage);
+ HRESULT GetLangId([in] HKL hKL, [out] LANGID *plid);
+
+ HRESULT KeybdEvent([in] LANGID lgidIME, [in] BYTE bVk, [in] BYTE bScan, [in] DWORD dwFlags, [in] DWORD dwExtraInfo);
+
+ HRESULT LockModal();
+ HRESULT UnlockModal();
+
+ // win98/nt5 apis
+ HRESULT AssociateContextEx([in] HWND hWnd, [in] HIMC hIMC, [in] DWORD dwFlags);
+ HRESULT DisableIME([in] DWORD idThread);
+ HRESULT GetImeMenuItemsA([in] HIMC hIMC, [in] DWORD dwFlags, [in] DWORD dwType, [in] IMEMENUITEMINFOA *pImeParentMenu, [out] IMEMENUITEMINFOA *pImeMenu, [in] DWORD dwSize, [out] DWORD *pdwResult);
+ HRESULT GetImeMenuItemsW([in] HIMC hIMC, [in] DWORD dwFlags, [in] DWORD dwType, [in] IMEMENUITEMINFOW *pImeParentMenu, [out] IMEMENUITEMINFOW *pImeMenu, [in] DWORD dwSize, [out] DWORD *pdwResult);
+ HRESULT EnumInputContext([in] DWORD idThread, [out] IEnumInputContext **ppEnum);
+ HRESULT RequestMessageA([in] HIMC hIMC, [in] WPARAM wParam, [in] LPARAM lParam, [out] LRESULT *plResult);
+ HRESULT RequestMessageW([in] HIMC hIMC, [in] WPARAM wParam, [in] LPARAM lParam, [out] LRESULT *plResult);
+
+ HRESULT SendIMCA([in] HWND hWnd, [in] UINT uMsg, [in] WPARAM wParam, [in] LPARAM lParam, [out] LRESULT *plResult);
+ HRESULT SendIMCW([in] HWND hWnd, [in] UINT uMsg, [in] WPARAM wParam, [in] LPARAM lParam, [out] LRESULT *plResult);
+
+ HRESULT IsSleeping();
+ };
+
+ [
+ object,
+ uuid(6FE20962-D077-11d0-8FE7-00AA006BCC59),
+ pointer_default(unique)
+ ]
+ interface IActiveIME : IUnknown
+ {
+ HRESULT Inquire([in] DWORD dwSystemInfoFlags, [out] IMEINFO *pIMEInfo, [out] LPWSTR szWndClass, [out] DWORD *pdwPrivate);
+ HRESULT ConversionList([in] HIMC hIMC, [in] LPWSTR szSource, [in] UINT uFlag, [in] UINT uBufLen, [out] CANDIDATELIST *pDest, [out] UINT *puCopied);
+ HRESULT Configure([in] HKL hKL, [in] HWND hWnd, [in] DWORD dwMode, [in] REGISTERWORDW *pRegisterWord);
+ HRESULT Destroy([in] UINT uReserved);
+ HRESULT Escape([in] HIMC hIMC, [in] UINT uEscape, [in, out] void *pData, [out] LRESULT *plResult);
+ HRESULT SetActiveContext([in] HIMC hIMC, [in] BOOL fFlag);
+ HRESULT ProcessKey([in] HIMC hIMC, [in] UINT uVirKey, [in] DWORD lParam, [in] BYTE *pbKeyState);
+ HRESULT Notify([in] HIMC hIMC, [in] DWORD dwAction, [in] DWORD dwIndex, [in] DWORD dwValue);
+ HRESULT Select([in] HIMC hIMC, [in] BOOL fSelect);
+ HRESULT SetCompositionString([in] HIMC hIMC, [in] DWORD dwIndex, [in] void *pComp, [in] DWORD dwCompLen, [in] void *pRead, [in] DWORD dwReadLen);
+ HRESULT ToAsciiEx([in] UINT uVirKey, [in] UINT uScanCode, [in] BYTE *pbKeyState, [in] UINT fuState, [in] HIMC hIMC, [out] DWORD *pdwTransBuf, [out] UINT *puSize);
+ HRESULT RegisterWord([in] LPWSTR szReading, [in] DWORD dwStyle, [in] LPWSTR szString);
+ HRESULT UnregisterWord([in] LPWSTR szReading, [in] DWORD dwStyle, [in] LPWSTR szString);
+ HRESULT GetRegisterWordStyle([in] UINT nItem, [out] STYLEBUFW *pStyleBuf, [out] UINT *puBufSize);
+ HRESULT EnumRegisterWord([in] LPWSTR szReading, [in] DWORD dwStyle, [in] LPWSTR szRegister, [in] LPVOID pData, [out] IEnumRegisterWordW **ppEnum);
+ HRESULT GetCodePageA([out] UINT *uCodePage);
+ HRESULT GetLangId([out] LANGID *plid);
+ };
+
+ [
+ object,
+ uuid(e1c4bf0e-2d53-11d2-93e1-0060b067b86e),
+ pointer_default(unique)
+ ]
+ interface IActiveIME2 : IActiveIME
+ {
+ HRESULT Sleep();
+ HRESULT Unsleep([in] BOOL fDead);
+ };
+
+ [
+ uuid(4955DD33-B159-11d0-8FCF-00AA006BCC59),
+ ]
+ coclass CActiveIMM
+ {
+ [default] interface IActiveIMMApp;
+ interface IActiveIMMIME;
+ interface IActiveIMMRegistrar;
+ interface IActiveIMMMessagePumpOwner;
+ };
+}
diff --git a/src/dlldata.c b/src/dlldata.c
new file mode 100644
index 0000000..d03124c
--- /dev/null
+++ b/src/dlldata.c
@@ -0,0 +1,38 @@
+/*********************************************************
+ DllData file -- generated by MIDL compiler
+
+ DO NOT ALTER THIS FILE
+
+ This file is regenerated by MIDL on every IDL file compile.
+
+ To completely reconstruct this file, delete it and rerun MIDL
+ on all the IDL files in this DLL, specifying this file for the
+ /dlldata command line option
+
+*********************************************************/
+
+#define PROXY_DELEGATION
+
+#include <rpcproxy.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+EXTERN_PROXY_FILE( if_ole )
+
+
+PROXYFILE_LIST_START
+/* Start of list */
+ REFERENCE_PROXY_FILE( if_ole ),
+/* End of list */
+PROXYFILE_LIST_END
+
+
+DLLDATA_ROUTINES( aProxyFileList, GET_DLL_CLSID )
+
+#ifdef __cplusplus
+} /*extern "C" */
+#endif
+
+/* end of generated dlldata file */
diff --git a/src/dosinst.c b/src/dosinst.c
new file mode 100644
index 0000000..5b05598
--- /dev/null
+++ b/src/dosinst.c
@@ -0,0 +1,2845 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * dosinst.c: Install program for Vim on MS-DOS and MS-Windows
+ *
+ * Compile with Make_mvc.mak, Make_bc3.mak, Make_bc5.mak or Make_djg.mak.
+ */
+
+/*
+ * Include common code for dosinst.c and uninstal.c.
+ */
+#define DOSINST
+#include "dosinst.h"
+#include <io.h>
+
+#define GVIMEXT64_PATH "GvimExt64\\gvimext.dll"
+#define GVIMEXT32_PATH "GvimExt32\\gvimext.dll"
+
+/* Macro to do an error check I was typing over and over */
+#define CHECK_REG_ERROR(code) \
+ do { \
+ if (code != ERROR_SUCCESS) \
+ { \
+ printf("%ld error number: %ld\n", (long)__LINE__, (long)code); \
+ return 1; \
+ } \
+ } while (0)
+
+int has_vim = 0; /* installable vim.exe exists */
+int has_gvim = 0; /* installable gvim.exe exists */
+
+char oldvimrc[BUFSIZE]; /* name of existing vimrc file */
+char vimrc[BUFSIZE]; /* name of vimrc file to create */
+
+char *default_bat_dir = NULL; /* when not NULL, use this as the default
+ directory to write .bat files in */
+char *default_vim_dir = NULL; /* when not NULL, use this as the default
+ install dir for NSIS */
+
+/*
+ * Structure used for each choice the user can make.
+ */
+struct choice
+{
+ int active; /* non-zero when choice is active */
+ char *text; /* text displayed for this choice */
+ void (*changefunc)(int idx); /* function to change this choice */
+ int arg; /* argument for function */
+ void (*installfunc)(int idx); /* function to install this choice */
+};
+
+struct choice choices[30]; /* choices the user can make */
+int choice_count = 0; /* number of choices available */
+
+#define TABLE_SIZE(s) (int)(sizeof(s) / sizeof(*s))
+
+enum
+{
+ compat_vi = 1,
+ compat_vim,
+ compat_some_enhancements,
+ compat_all_enhancements
+};
+char *(compat_choices[]) =
+{
+ "\nChoose the default way to run Vim:",
+ "Vi compatible",
+ "Vim default",
+ "with some Vim enhancements",
+ "with syntax highlighting and other features switched on",
+};
+int compat_choice = (int)compat_all_enhancements;
+char *compat_text = "- run Vim %s";
+
+enum
+{
+ remap_no = 1,
+ remap_win
+};
+char *(remap_choices[]) =
+{
+ "\nChoose:",
+ "Do not remap keys for Windows behavior",
+ "Remap a few keys for Windows behavior (CTRL-V, CTRL-C, CTRL-F, etc)",
+};
+int remap_choice = (int)remap_no;
+char *remap_text = "- %s";
+
+enum
+{
+ mouse_xterm = 1,
+ mouse_mswin,
+ mouse_default
+};
+char *(mouse_choices[]) =
+{
+ "\nChoose the way how Vim uses the mouse:",
+ "right button extends selection (the Unix way)",
+ "right button has a popup menu, left button starts select mode (the Windows way)",
+ "right button has a popup menu, left button starts visual mode",
+};
+int mouse_choice = (int)mouse_default;
+char *mouse_text = "- The mouse %s";
+
+enum
+{
+ vimfiles_dir_none = 1,
+ vimfiles_dir_vim,
+ vimfiles_dir_home
+};
+static char *(vimfiles_dir_choices[]) =
+{
+ "\nCreate plugin directories:",
+ "No",
+ "In the VIM directory",
+ "In your HOME directory",
+};
+
+/* non-zero when selected to install the popup menu entry. */
+static int install_popup = 0;
+
+/* non-zero when selected to install the "Open with" entry. */
+static int install_openwith = 0;
+
+/* non-zero when need to add an uninstall entry in the registry */
+static int need_uninstall_entry = 0;
+
+/*
+ * Definitions of the directory name (under $VIM) of the vimfiles directory
+ * and its subdirectories:
+ */
+static char *(vimfiles_subdirs[]) =
+{
+ "colors",
+ "compiler",
+ "doc",
+ "ftdetect",
+ "ftplugin",
+ "indent",
+ "keymap",
+ "plugin",
+ "syntax",
+};
+
+/*
+ * Obtain a choice from a table.
+ * First entry is a question, others are choices.
+ */
+ static int
+get_choice(char **table, int entries)
+{
+ int answer;
+ int idx;
+ char dummy[100];
+
+ do
+ {
+ for (idx = 0; idx < entries; ++idx)
+ {
+ if (idx)
+ printf("%2d ", idx);
+ puts(table[idx]);
+ }
+ printf("Choice: ");
+ if (scanf("%d", &answer) != 1)
+ {
+ scanf("%99s", dummy);
+ answer = 0;
+ }
+ }
+ while (answer < 1 || answer >= entries);
+
+ return answer;
+}
+
+/*
+ * Check if the user unpacked the archives properly.
+ * Sets "runtimeidx".
+ */
+ static void
+check_unpack(void)
+{
+ char buf[BUFSIZE];
+ FILE *fd;
+ struct stat st;
+
+ /* check for presence of the correct version number in installdir[] */
+ runtimeidx = strlen(installdir) - strlen(VIM_VERSION_NODOT);
+ if (runtimeidx <= 0
+ || stricmp(installdir + runtimeidx, VIM_VERSION_NODOT) != 0
+ || (installdir[runtimeidx - 1] != '/'
+ && installdir[runtimeidx - 1] != '\\'))
+ {
+ printf("ERROR: Install program not in directory \"%s\"\n",
+ VIM_VERSION_NODOT);
+ printf("This program can only work when it is located in its original directory\n");
+ myexit(1);
+ }
+
+ /* check if filetype.vim is present, which means the runtime archive has
+ * been unpacked */
+ sprintf(buf, "%s\\filetype.vim", installdir);
+ if (stat(buf, &st) < 0)
+ {
+ printf("ERROR: Cannot find filetype.vim in \"%s\"\n", installdir);
+ printf("It looks like you did not unpack the runtime archive.\n");
+ printf("You must unpack the runtime archive \"vim%srt.zip\" before installing.\n",
+ VIM_VERSION_NODOT + 3);
+ myexit(1);
+ }
+
+ /* Check if vim.exe or gvim.exe is in the current directory. */
+ if ((fd = fopen("gvim.exe", "r")) != NULL)
+ {
+ fclose(fd);
+ has_gvim = 1;
+ }
+ if ((fd = fopen("vim.exe", "r")) != NULL)
+ {
+ fclose(fd);
+ has_vim = 1;
+ }
+ if (!has_gvim && !has_vim)
+ {
+ printf("ERROR: Cannot find any Vim executables in \"%s\"\n\n",
+ installdir);
+ myexit(1);
+ }
+}
+
+/*
+ * Compare paths "p[plen]" to "q[qlen]". Return 0 if they match.
+ * Ignores case and differences between '/' and '\'.
+ * "plen" and "qlen" can be negative, strlen() is used then.
+ */
+ static int
+pathcmp(char *p, int plen, char *q, int qlen)
+{
+ int i;
+
+ if (plen < 0)
+ plen = strlen(p);
+ if (qlen < 0)
+ qlen = strlen(q);
+ for (i = 0; ; ++i)
+ {
+ /* End of "p": check if "q" also ends or just has a slash. */
+ if (i == plen)
+ {
+ if (i == qlen) /* match */
+ return 0;
+ if (i == qlen - 1 && (q[i] == '\\' || q[i] == '/'))
+ return 0; /* match with trailing slash */
+ return 1; /* no match */
+ }
+
+ /* End of "q": check if "p" also ends or just has a slash. */
+ if (i == qlen)
+ {
+ if (i == plen) /* match */
+ return 0;
+ if (i == plen - 1 && (p[i] == '\\' || p[i] == '/'))
+ return 0; /* match with trailing slash */
+ return 1; /* no match */
+ }
+
+ if (!(mytoupper(p[i]) == mytoupper(q[i])
+ || ((p[i] == '/' || p[i] == '\\')
+ && (q[i] == '/' || q[i] == '\\'))))
+ return 1; /* no match */
+ }
+ /*NOTREACHED*/
+}
+
+/*
+ * If the executable "**destination" is in the install directory, find another
+ * one in $PATH.
+ * On input "**destination" is the path of an executable in allocated memory
+ * (or NULL).
+ * "*destination" is set to NULL or the location of the file.
+ */
+ static void
+findoldfile(char **destination)
+{
+ char *bp = *destination;
+ size_t indir_l = strlen(installdir);
+ char *cp = bp + indir_l;
+ char *tmpname;
+ char *farname;
+
+ /*
+ * No action needed if exe not found or not in this directory.
+ */
+ if (bp == NULL
+ || strnicmp(bp, installdir, indir_l) != 0
+ || strchr("/\\", *cp++) == NULL
+ || strchr(cp, '\\') != NULL
+ || strchr(cp, '/') != NULL)
+ return;
+
+ tmpname = alloc((int)strlen(cp) + 1);
+ strcpy(tmpname, cp);
+ tmpname[strlen(tmpname) - 1] = 'x'; /* .exe -> .exx */
+
+ if (access(tmpname, 0) == 0)
+ {
+ printf("\nERROR: %s and %s clash. Remove or rename %s.\n",
+ tmpname, cp, tmpname);
+ myexit(1);
+ }
+
+ if (rename(cp, tmpname) != 0)
+ {
+ printf("\nERROR: failed to rename %s to %s: %s\n",
+ cp, tmpname, strerror(0));
+ myexit(1);
+ }
+
+ farname = searchpath_save(cp);
+
+ if (rename(tmpname, cp) != 0)
+ {
+ printf("\nERROR: failed to rename %s back to %s: %s\n",
+ tmpname, cp, strerror(0));
+ myexit(1);
+ }
+
+ free(*destination);
+ free(tmpname);
+ *destination = farname;
+}
+
+/*
+ * Check if there is a vim.[exe|bat|, gvim.[exe|bat|, etc. in the path.
+ * When "check_bat_only" is TRUE, only find "default_bat_dir".
+ */
+ static void
+find_bat_exe(int check_bat_only)
+{
+ int i;
+
+ /* avoid looking in the "installdir" by chdir to system root */
+ mch_chdir(sysdrive);
+ mch_chdir("\\");
+
+ for (i = 1; i < TARGET_COUNT; ++i)
+ {
+ targets[i].oldbat = searchpath_save(targets[i].batname);
+ if (!check_bat_only)
+ targets[i].oldexe = searchpath_save(targets[i].exename);
+
+ if (default_bat_dir == NULL && targets[i].oldbat != NULL)
+ {
+ default_bat_dir = alloc(strlen(targets[i].oldbat) + 1);
+ strcpy(default_bat_dir, targets[i].oldbat);
+ remove_tail(default_bat_dir);
+ }
+ if (check_bat_only && targets[i].oldbat != NULL)
+ {
+ free(targets[i].oldbat);
+ targets[i].oldbat = NULL;
+ }
+ }
+
+ mch_chdir(installdir);
+}
+
+/*
+ * Get the value of $VIMRUNTIME or $VIM and write it in $TEMP/vimini.ini, so
+ * that NSIS can read it.
+ * When not set, use the directory of a previously installed Vim.
+ */
+ static void
+get_vim_env(void)
+{
+ char *vim;
+ char buf[BUFSIZE];
+ FILE *fd;
+ char fname[BUFSIZE];
+
+ /* First get $VIMRUNTIME. If it's set, remove the tail. */
+ vim = getenv("VIMRUNTIME");
+ if (vim != NULL && *vim != 0 && strlen(vim) < BUFSIZE)
+ {
+ strcpy(buf, vim);
+ remove_tail(buf);
+ vim = buf;
+ }
+ else
+ {
+ vim = getenv("VIM");
+ if (vim == NULL || *vim == 0)
+ {
+ /* Use the directory from an old uninstall entry. */
+ if (default_vim_dir != NULL)
+ vim = default_vim_dir;
+ else
+ /* Let NSIS know there is no default, it should use
+ * $PROGRAMFILES. */
+ vim = "";
+ }
+ }
+
+ /* NSIS also uses GetTempPath(), thus we should get the same directory
+ * name as where NSIS will look for vimini.ini. */
+ GetTempPath(BUFSIZE, fname);
+ add_pathsep(fname);
+ strcat(fname, "vimini.ini");
+
+ fd = fopen(fname, "w");
+ if (fd != NULL)
+ {
+ /* Make it look like an .ini file, so that NSIS can read it with a
+ * ReadINIStr command. */
+ fprintf(fd, "[vimini]\n");
+ fprintf(fd, "dir=\"%s\"\n", vim);
+ fclose(fd);
+ }
+ else
+ {
+ printf("Failed to open %s\n", fname);
+ sleep(2);
+ }
+}
+
+static int num_windows;
+
+/*
+ * Callback used for EnumWindows():
+ * Count the window if the title looks like it is for the uninstaller.
+ */
+/*ARGSUSED*/
+ static BOOL CALLBACK
+window_cb(HWND hwnd, LPARAM lparam)
+{
+ char title[256];
+
+ title[0] = 0;
+ GetWindowText(hwnd, title, 256);
+ if (strstr(title, "Vim ") != NULL && strstr(title, " Uninstall") != NULL)
+ ++num_windows;
+ return TRUE;
+}
+
+/*
+ * Run the uninstaller silently.
+ */
+ static int
+run_silent_uninstall(char *uninst_exe)
+{
+ char vimrt_dir[BUFSIZE];
+ char temp_uninst[BUFSIZE];
+ char temp_dir[MAX_PATH];
+ char buf[BUFSIZE * 2 + 10];
+ int i;
+ DWORD tick;
+
+ strcpy(vimrt_dir, uninst_exe);
+ remove_tail(vimrt_dir);
+
+ if (!GetTempPath(sizeof(temp_dir), temp_dir))
+ return FAIL;
+
+ /* Copy the uninstaller to a temporary exe. */
+ tick = GetTickCount();
+ for (i = 0; ; i++)
+ {
+ sprintf(temp_uninst, "%s\\vimun%04X.exe", temp_dir,
+ (unsigned int)((i + tick) & 0xFFFF));
+ if (CopyFile(uninst_exe, temp_uninst, TRUE))
+ break;
+ if (GetLastError() != ERROR_FILE_EXISTS)
+ return FAIL;
+ if (i == 65535)
+ return FAIL;
+ }
+
+ /* Run the copied uninstaller silently. */
+ if (strchr(temp_uninst, ' ') != NULL)
+ sprintf(buf, "\"%s\" /S _?=%s", temp_uninst, vimrt_dir);
+ else
+ sprintf(buf, "%s /S _?=%s", temp_uninst, vimrt_dir);
+ run_command(buf);
+
+ DeleteFile(temp_uninst);
+ return OK;
+}
+
+/*
+ * Check for already installed Vims.
+ * Return non-zero when found one.
+ */
+ static int
+uninstall_check(int skip_question)
+{
+ HKEY key_handle;
+ HKEY uninstall_key_handle;
+ char *uninstall_key = "software\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
+ char subkey_name_buff[BUFSIZE];
+ char temp_string_buffer[BUFSIZE];
+ DWORD local_bufsize = BUFSIZE;
+ FILETIME temp_pfiletime;
+ DWORD key_index;
+ char input;
+ long code;
+ DWORD value_type;
+ DWORD orig_num_keys;
+ DWORD new_num_keys;
+ DWORD allow_silent;
+ int foundone = 0;
+
+ code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, uninstall_key, 0,
+ KEY_WOW64_64KEY | KEY_READ, &key_handle);
+ CHECK_REG_ERROR(code);
+
+ for (key_index = 0;
+ RegEnumKeyEx(key_handle, key_index, subkey_name_buff, &local_bufsize,
+ NULL, NULL, NULL, &temp_pfiletime) != ERROR_NO_MORE_ITEMS;
+ key_index++)
+ {
+ local_bufsize = BUFSIZE;
+ if (strncmp("Vim", subkey_name_buff, 3) == 0)
+ {
+ /* Open the key named Vim* */
+ code = RegOpenKeyEx(key_handle, subkey_name_buff, 0,
+ KEY_WOW64_64KEY | KEY_READ, &uninstall_key_handle);
+ CHECK_REG_ERROR(code);
+
+ /* get the DisplayName out of it to show the user */
+ code = RegQueryValueEx(uninstall_key_handle, "displayname", 0,
+ &value_type, (LPBYTE)temp_string_buffer,
+ &local_bufsize);
+ local_bufsize = BUFSIZE;
+ CHECK_REG_ERROR(code);
+
+ allow_silent = 0;
+ if (skip_question)
+ {
+ DWORD varsize = sizeof(DWORD);
+
+ RegQueryValueEx(uninstall_key_handle, "AllowSilent", 0,
+ &value_type, (LPBYTE)&allow_silent,
+ &varsize);
+ }
+
+ foundone = 1;
+ printf("\n*********************************************************\n");
+ printf("Vim Install found what looks like an existing Vim version.\n");
+ printf("The name of the entry is:\n");
+ printf("\n \"%s\"\n\n", temp_string_buffer);
+
+ printf("Installing the new version will disable part of the existing version.\n");
+ printf("(The batch files used in a console and the \"Edit with Vim\" entry in\n");
+ printf("the popup menu will use the new version)\n");
+
+ if (skip_question)
+ printf("\nRunning uninstall program for \"%s\"\n", temp_string_buffer);
+ else
+ printf("\nDo you want to uninstall \"%s\" now?\n(y)es/(n)o) ", temp_string_buffer);
+ fflush(stdout);
+
+ /* get the UninstallString */
+ code = RegQueryValueEx(uninstall_key_handle, "uninstallstring", 0,
+ &value_type, (LPBYTE)temp_string_buffer, &local_bufsize);
+ local_bufsize = BUFSIZE;
+ CHECK_REG_ERROR(code);
+
+ /* Remember the directory, it is used as the default for NSIS. */
+ default_vim_dir = alloc(strlen(temp_string_buffer) + 1);
+ strcpy(default_vim_dir, temp_string_buffer);
+ remove_tail(default_vim_dir);
+ remove_tail(default_vim_dir);
+
+ input = 'n';
+ do
+ {
+ if (input != 'n')
+ printf("%c is an invalid reply. Please enter either 'y' or 'n'\n", input);
+
+ if (skip_question)
+ input = 'y';
+ else
+ {
+ rewind(stdin);
+ scanf("%c", &input);
+ }
+ switch (input)
+ {
+ case 'y':
+ case 'Y':
+ /* save the number of uninstall keys so we can know if
+ * it changed */
+ RegQueryInfoKey(key_handle, NULL, NULL, NULL,
+ &orig_num_keys, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL);
+
+ /* Find existing .bat files before deleting them. */
+ find_bat_exe(TRUE);
+
+ if (allow_silent)
+ {
+ if (run_silent_uninstall(temp_string_buffer)
+ == FAIL)
+ allow_silent = 0; /* Retry with non silent. */
+ }
+ if (!allow_silent)
+ {
+ /* Execute the uninstall program. Put it in double
+ * quotes if there is an embedded space. */
+ {
+ char buf[BUFSIZE];
+
+ if (strchr(temp_string_buffer, ' ') != NULL)
+ sprintf(buf, "\"%s\"", temp_string_buffer);
+ else
+ strcpy(buf, temp_string_buffer);
+ run_command(buf);
+ }
+
+ /* Count the number of windows with a title that match
+ * the installer, so that we can check when it's done.
+ * The uninstaller copies itself, executes the copy
+ * and exits, thus we can't wait for the process to
+ * finish. */
+ sleep(1); /* wait for uninstaller to start up */
+ num_windows = 0;
+ EnumWindows(window_cb, 0);
+ if (num_windows == 0)
+ {
+ /* Did not find the uninstaller, ask user to press
+ * Enter when done. Just in case. */
+ printf("Press Enter when the uninstaller is finished\n");
+ rewind(stdin);
+ (void)getchar();
+ }
+ else
+ {
+ printf("Waiting for the uninstaller to finish (press CTRL-C to abort).");
+ do
+ {
+ printf(".");
+ fflush(stdout);
+ sleep(1); /* wait for the uninstaller to finish */
+ num_windows = 0;
+ EnumWindows(window_cb, 0);
+ } while (num_windows > 0);
+ }
+ }
+ printf("\nDone!\n");
+
+ /* Check if an uninstall reg key was deleted.
+ * if it was, we want to decrement key_index.
+ * if we don't do this, we will skip the key
+ * immediately after any key that we delete. */
+ RegQueryInfoKey(key_handle, NULL, NULL, NULL,
+ &new_num_keys, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL);
+ if (new_num_keys < orig_num_keys)
+ key_index--;
+
+ input = 'y';
+ break;
+
+ case 'n':
+ case 'N':
+ /* Do not uninstall */
+ input = 'n';
+ break;
+
+ default: /* just drop through and redo the loop */
+ break;
+ }
+
+ } while (input != 'n' && input != 'y');
+
+ RegCloseKey(uninstall_key_handle);
+ }
+ }
+ RegCloseKey(key_handle);
+
+ return foundone;
+}
+
+/*
+ * Find out information about the system.
+ */
+ static void
+inspect_system(void)
+{
+ char *p;
+ char buf[BUFSIZE];
+ FILE *fd;
+ int i;
+ int foundone;
+
+ /* This may take a little while, let the user know what we're doing. */
+ printf("Inspecting system...\n");
+
+ /*
+ * If $VIM is set, check that it's pointing to our directory.
+ */
+ p = getenv("VIM");
+ if (p != NULL && pathcmp(p, -1, installdir, runtimeidx - 1) != 0)
+ {
+ printf("------------------------------------------------------\n");
+ printf("$VIM is set to \"%s\".\n", p);
+ printf("This is different from where this version of Vim is:\n");
+ strcpy(buf, installdir);
+ *(buf + runtimeidx - 1) = NUL;
+ printf("\"%s\"\n", buf);
+ printf("You must adjust or remove the setting of $VIM,\n");
+ if (interactive)
+ {
+ printf("to be able to use this install program.\n");
+ myexit(1);
+ }
+ printf("otherwise Vim WILL NOT WORK properly!\n");
+ printf("------------------------------------------------------\n");
+ }
+
+ /*
+ * If $VIMRUNTIME is set, check that it's pointing to our runtime directory.
+ */
+ p = getenv("VIMRUNTIME");
+ if (p != NULL && pathcmp(p, -1, installdir, -1) != 0)
+ {
+ printf("------------------------------------------------------\n");
+ printf("$VIMRUNTIME is set to \"%s\".\n", p);
+ printf("This is different from where this version of Vim is:\n");
+ printf("\"%s\"\n", installdir);
+ printf("You must adjust or remove the setting of $VIMRUNTIME,\n");
+ if (interactive)
+ {
+ printf("to be able to use this install program.\n");
+ myexit(1);
+ }
+ printf("otherwise Vim WILL NOT WORK properly!\n");
+ printf("------------------------------------------------------\n");
+ }
+
+ /*
+ * Check if there is a vim.[exe|bat|, gvim.[exe|bat|, etc. in the path.
+ */
+ find_bat_exe(FALSE);
+
+ /*
+ * A .exe in the install directory may be found anyway on Windows 2000.
+ * Check for this situation and find another executable if necessary.
+ * w.briscoe@ponl.com 2001-01-20
+ */
+ foundone = 0;
+ for (i = 1; i < TARGET_COUNT; ++i)
+ {
+ findoldfile(&(targets[i].oldexe));
+ if (targets[i].oldexe != NULL)
+ foundone = 1;
+ }
+
+ if (foundone)
+ {
+ printf("Warning: Found Vim executable(s) in your $PATH:\n");
+ for (i = 1; i < TARGET_COUNT; ++i)
+ if (targets[i].oldexe != NULL)
+ printf("%s\n", targets[i].oldexe);
+ printf("It will be used instead of the version you are installing.\n");
+ printf("Please delete or rename it, or adjust your $PATH setting.\n");
+ }
+
+ /*
+ * Check if there is an existing ../_vimrc or ../.vimrc file.
+ */
+ strcpy(oldvimrc, installdir);
+ strcpy(oldvimrc + runtimeidx, "_vimrc");
+ if ((fd = fopen(oldvimrc, "r")) == NULL)
+ {
+ strcpy(oldvimrc + runtimeidx, "vimrc~1"); /* short version of .vimrc */
+ if ((fd = fopen(oldvimrc, "r")) == NULL)
+ {
+ strcpy(oldvimrc + runtimeidx, ".vimrc");
+ fd = fopen(oldvimrc, "r");
+ }
+ }
+ if (fd != NULL)
+ fclose(fd);
+ else
+ *oldvimrc = NUL;
+}
+
+/*
+ * Add a dummy choice to avoid that the numbering changes depending on items
+ * in the environment. The user may type a number he remembered without
+ * looking.
+ */
+ static void
+add_dummy_choice(void)
+{
+ choices[choice_count].installfunc = NULL;
+ choices[choice_count].active = 0;
+ choices[choice_count].changefunc = NULL;
+ choices[choice_count].text = NULL;
+ choices[choice_count].arg = 0;
+ ++choice_count;
+}
+
+/***********************************************
+ * stuff for creating the batch files.
+ */
+
+/*
+ * Install the vim.bat, gvim.bat, etc. files.
+ */
+ static void
+install_bat_choice(int idx)
+{
+ char *batpath = targets[choices[idx].arg].batpath;
+ char *oldname = targets[choices[idx].arg].oldbat;
+ char *exename = targets[choices[idx].arg].exenamearg;
+ char *vimarg = targets[choices[idx].arg].exearg;
+ FILE *fd;
+
+ if (*batpath != NUL)
+ {
+ fd = fopen(batpath, "w");
+ if (fd == NULL)
+ printf("\nERROR: Cannot open \"%s\" for writing.\n", batpath);
+ else
+ {
+ need_uninstall_entry = 1;
+
+ fprintf(fd, "@echo off\n");
+ fprintf(fd, "rem -- Run Vim --\n");
+ fprintf(fd, "\n");
+ fprintf(fd, "setlocal\n");
+
+ /* Don't use double quotes for the "set" argument, also when it
+ * contains a space. The quotes would be included in the value
+ * for MSDOS and NT.
+ * The order of preference is:
+ * 1. $VIMRUNTIME/vim.exe (user preference)
+ * 2. $VIM/vim70/vim.exe (hard coded version)
+ * 3. installdir/vim.exe (hard coded install directory)
+ */
+ fprintf(fd, "set VIM_EXE_DIR=%s\n", installdir);
+ fprintf(fd, "if exist \"%%VIM%%\\%s\\%s\" set VIM_EXE_DIR=%%VIM%%\\%s\n",
+ VIM_VERSION_NODOT, exename, VIM_VERSION_NODOT);
+ fprintf(fd, "if exist \"%%VIMRUNTIME%%\\%s\" set VIM_EXE_DIR=%%VIMRUNTIME%%\n", exename);
+ fprintf(fd, "\n");
+
+ /* Give an error message when the executable could not be found. */
+ fprintf(fd, "if exist \"%%VIM_EXE_DIR%%\\%s\" goto havevim\n",
+ exename);
+ fprintf(fd, "echo \"%%VIM_EXE_DIR%%\\%s\" not found\n", exename);
+ fprintf(fd, "goto eof\n");
+ fprintf(fd, "\n");
+ fprintf(fd, ":havevim\n");
+
+ fprintf(fd, "rem collect the arguments in VIMARGS for Win95\n");
+ fprintf(fd, "set VIMARGS=\n");
+ if (*exename == 'g')
+ fprintf(fd, "set VIMNOFORK=\n");
+ fprintf(fd, ":loopstart\n");
+ fprintf(fd, "if .%%1==. goto loopend\n");
+ if (*exename == 'g')
+ {
+ fprintf(fd, "if NOT .%%1==.--nofork goto noforklongarg\n");
+ fprintf(fd, "set VIMNOFORK=1\n");
+ fprintf(fd, ":noforklongarg\n");
+ fprintf(fd, "if NOT .%%1==.-f goto noforkarg\n");
+ fprintf(fd, "set VIMNOFORK=1\n");
+ fprintf(fd, ":noforkarg\n");
+ }
+ fprintf(fd, "set VIMARGS=%%VIMARGS%% %%1\n");
+ fprintf(fd, "shift\n");
+ fprintf(fd, "goto loopstart\n");
+ fprintf(fd, ":loopend\n");
+ fprintf(fd, "\n");
+
+ fprintf(fd, "if .%%OS%%==.Windows_NT goto ntaction\n");
+ fprintf(fd, "\n");
+
+ /* For gvim.exe use "start" to avoid that the console window stays
+ * open. */
+ if (*exename == 'g')
+ {
+ fprintf(fd, "if .%%VIMNOFORK%%==.1 goto nofork\n");
+ fprintf(fd, "start ");
+ }
+
+ /* Always use quotes, $VIM or $VIMRUNTIME might have a space. */
+ fprintf(fd, "\"%%VIM_EXE_DIR%%\\%s\" %s %%VIMARGS%%\n",
+ exename, vimarg);
+ fprintf(fd, "goto eof\n");
+ fprintf(fd, "\n");
+
+ if (*exename == 'g')
+ {
+ fprintf(fd, ":nofork\n");
+ fprintf(fd, "start /w ");
+ /* Always use quotes, $VIM or $VIMRUNTIME might have a space. */
+ fprintf(fd, "\"%%VIM_EXE_DIR%%\\%s\" %s %%VIMARGS%%\n",
+ exename, vimarg);
+ fprintf(fd, "goto eof\n");
+ fprintf(fd, "\n");
+ }
+
+ fprintf(fd, ":ntaction\n");
+ fprintf(fd, "rem for WinNT we can use %%*\n");
+
+ /* For gvim.exe use "start /b" to avoid that the console window
+ * stays open. */
+ if (*exename == 'g')
+ {
+ fprintf(fd, "if .%%VIMNOFORK%%==.1 goto noforknt\n");
+ fprintf(fd, "start \"dummy\" /b ");
+ }
+
+ /* Always use quotes, $VIM or $VIMRUNTIME might have a space. */
+ fprintf(fd, "\"%%VIM_EXE_DIR%%\\%s\" %s %%*\n", exename, vimarg);
+ fprintf(fd, "goto eof\n");
+ fprintf(fd, "\n");
+
+ if (*exename == 'g')
+ {
+ fprintf(fd, ":noforknt\n");
+ fprintf(fd, "start \"dummy\" /b /wait ");
+ /* Always use quotes, $VIM or $VIMRUNTIME might have a space. */
+ fprintf(fd, "\"%%VIM_EXE_DIR%%\\%s\" %s %%*\n",
+ exename, vimarg);
+ }
+
+ fprintf(fd, "\n:eof\n");
+ fprintf(fd, "set VIMARGS=\n");
+ if (*exename == 'g')
+ fprintf(fd, "set VIMNOFORK=\n");
+
+ fclose(fd);
+ printf("%s has been %s\n", batpath,
+ oldname == NULL ? "created" : "overwritten");
+ }
+ }
+}
+
+/*
+ * Make the text string for choice "idx".
+ * The format "fmt" is must have one %s item, which "arg" is used for.
+ */
+ static void
+alloc_text(int idx, char *fmt, char *arg)
+{
+ if (choices[idx].text != NULL)
+ free(choices[idx].text);
+
+ choices[idx].text = alloc((int)(strlen(fmt) + strlen(arg)) - 1);
+ sprintf(choices[idx].text, fmt, arg);
+}
+
+/*
+ * Toggle the "Overwrite .../vim.bat" to "Don't overwrite".
+ */
+ static void
+toggle_bat_choice(int idx)
+{
+ char *batname = targets[choices[idx].arg].batpath;
+ char *oldname = targets[choices[idx].arg].oldbat;
+
+ if (*batname == NUL)
+ {
+ alloc_text(idx, " Overwrite %s", oldname);
+ strcpy(batname, oldname);
+ }
+ else
+ {
+ alloc_text(idx, " Do NOT overwrite %s", oldname);
+ *batname = NUL;
+ }
+}
+
+/*
+ * Do some work for a batch file entry: Append the batch file name to the path
+ * and set the text for the choice.
+ */
+ static void
+set_bat_text(int idx, char *batpath, char *name)
+{
+ strcat(batpath, name);
+
+ alloc_text(idx, " Create %s", batpath);
+}
+
+/*
+ * Select a directory to write the batch file line.
+ */
+ static void
+change_bat_choice(int idx)
+{
+ char *path;
+ char *batpath;
+ char *name;
+ int n;
+ char *s;
+ char *p;
+ int count;
+ char **names = NULL;
+ int i;
+ int target = choices[idx].arg;
+
+ name = targets[target].batname;
+ batpath = targets[target].batpath;
+
+ path = getenv("PATH");
+ if (path == NULL)
+ {
+ printf("\nERROR: The variable $PATH is not set\n");
+ return;
+ }
+
+ /*
+ * first round: count number of names in path;
+ * second round: save names to names[].
+ */
+ for (;;)
+ {
+ count = 1;
+ for (p = path; *p; )
+ {
+ s = strchr(p, ';');
+ if (s == NULL)
+ s = p + strlen(p);
+ if (names != NULL)
+ {
+ names[count] = alloc((int)(s - p) + 1);
+ strncpy(names[count], p, s - p);
+ names[count][s - p] = NUL;
+ }
+ ++count;
+ p = s;
+ if (*p != NUL)
+ ++p;
+ }
+ if (names != NULL)
+ break;
+ names = alloc((int)(count + 1) * sizeof(char *));
+ }
+ names[0] = alloc(50);
+ sprintf(names[0], "Select directory to create %s in:", name);
+ names[count] = alloc(50);
+ if (choices[idx].arg == 0)
+ sprintf(names[count], "Do not create any .bat file.");
+ else
+ sprintf(names[count], "Do not create a %s file.", name);
+ n = get_choice(names, count + 1);
+
+ if (n == count)
+ {
+ /* Selected last item, don't create bat file. */
+ *batpath = NUL;
+ if (choices[idx].arg != 0)
+ alloc_text(idx, " Do NOT create %s", name);
+ }
+ else
+ {
+ /* Selected one of the paths. For the first item only keep the path,
+ * for the others append the batch file name. */
+ strcpy(batpath, names[n]);
+ add_pathsep(batpath);
+ if (choices[idx].arg != 0)
+ set_bat_text(idx, batpath, name);
+ }
+
+ for (i = 0; i <= count; ++i)
+ free(names[i]);
+ free(names);
+}
+
+char *bat_text_yes = "Install .bat files to use Vim at the command line:";
+char *bat_text_no = "do NOT install .bat files to use Vim at the command line";
+
+ static void
+change_main_bat_choice(int idx)
+{
+ int i;
+
+ /* let the user select a default directory or NONE */
+ change_bat_choice(idx);
+
+ if (targets[0].batpath[0] != NUL)
+ choices[idx].text = bat_text_yes;
+ else
+ choices[idx].text = bat_text_no;
+
+ /* update the individual batch file selections */
+ for (i = 1; i < TARGET_COUNT; ++i)
+ {
+ /* Only make it active when the first item has a path and the vim.exe
+ * or gvim.exe exists (there is a changefunc then). */
+ if (targets[0].batpath[0] != NUL
+ && choices[idx + i].changefunc != NULL)
+ {
+ choices[idx + i].active = 1;
+ if (choices[idx + i].changefunc == change_bat_choice
+ && targets[i].batpath[0] != NUL)
+ {
+ strcpy(targets[i].batpath, targets[0].batpath);
+ set_bat_text(idx + i, targets[i].batpath, targets[i].batname);
+ }
+ }
+ else
+ choices[idx + i].active = 0;
+ }
+}
+
+/*
+ * Initialize a choice for creating a batch file.
+ */
+ static void
+init_bat_choice(int target)
+{
+ char *batpath = targets[target].batpath;
+ char *oldbat = targets[target].oldbat;
+ char *p;
+ int i;
+
+ choices[choice_count].arg = target;
+ choices[choice_count].installfunc = install_bat_choice;
+ choices[choice_count].active = 1;
+ choices[choice_count].text = NULL; /* will be set below */
+ if (oldbat != NULL)
+ {
+ /* A [g]vim.bat exists: Only choice is to overwrite it or not. */
+ choices[choice_count].changefunc = toggle_bat_choice;
+ *batpath = NUL;
+ toggle_bat_choice(choice_count);
+ }
+ else
+ {
+ if (default_bat_dir != NULL)
+ /* Prefer using the same path as an existing .bat file. */
+ strcpy(batpath, default_bat_dir);
+ else
+ {
+ /* No [g]vim.bat exists: Write it to a directory in $PATH. Use
+ * $WINDIR by default, if it's empty the first item in $PATH. */
+ p = getenv("WINDIR");
+ if (p != NULL && *p != NUL)
+ strcpy(batpath, p);
+ else
+ {
+ p = getenv("PATH");
+ if (p == NULL || *p == NUL) /* "cannot happen" */
+ strcpy(batpath, "C:/Windows");
+ else
+ {
+ i = 0;
+ while (*p != NUL && *p != ';')
+ batpath[i++] = *p++;
+ batpath[i] = NUL;
+ }
+ }
+ }
+ add_pathsep(batpath);
+ set_bat_text(choice_count, batpath, targets[target].batname);
+
+ choices[choice_count].changefunc = change_bat_choice;
+ }
+ ++choice_count;
+}
+
+/*
+ * Set up the choices for installing .bat files.
+ * For these items "arg" is the index in targets[].
+ */
+ static void
+init_bat_choices(void)
+{
+ int i;
+
+ /* The first item is used to switch installing batch files on/off and
+ * setting the default path. */
+ choices[choice_count].text = bat_text_yes;
+ choices[choice_count].changefunc = change_main_bat_choice;
+ choices[choice_count].installfunc = NULL;
+ choices[choice_count].active = 1;
+ choices[choice_count].arg = 0;
+ ++choice_count;
+
+ /* Add items for each batch file target. Only used when not disabled by
+ * the first item. When a .exe exists, don't offer to create a .bat. */
+ for (i = 1; i < TARGET_COUNT; ++i)
+ if (targets[i].oldexe == NULL
+ && (targets[i].exenamearg[0] == 'g' ? has_gvim : has_vim))
+ init_bat_choice(i);
+ else
+ add_dummy_choice();
+}
+
+/*
+ * Install the vimrc file.
+ */
+ static void
+install_vimrc(int idx)
+{
+ FILE *fd, *tfd;
+ char *fname;
+
+ /* If an old vimrc file exists, overwrite it.
+ * Otherwise create a new one. */
+ if (*oldvimrc != NUL)
+ fname = oldvimrc;
+ else
+ fname = vimrc;
+
+ fd = fopen(fname, "w");
+ if (fd == NULL)
+ {
+ printf("\nERROR: Cannot open \"%s\" for writing.\n", fname);
+ return;
+ }
+ switch (compat_choice)
+ {
+ case compat_vi:
+ fprintf(fd, "\" Vi compatible\n");
+ fprintf(fd, "set compatible\n");
+ break;
+ case compat_vim:
+ fprintf(fd, "\" Vim's default behavior\n");
+ fprintf(fd, "if &compatible\n");
+ fprintf(fd, " set nocompatible\n");
+ fprintf(fd, "endif\n");
+ break;
+ case compat_some_enhancements:
+ fprintf(fd, "\" Vim with some enhancements\n");
+ fprintf(fd, "source $VIMRUNTIME/defaults.vim\n");
+ break;
+ case compat_all_enhancements:
+ fprintf(fd, "\" Vim with all enhancements\n");
+ fprintf(fd, "source $VIMRUNTIME/vimrc_example.vim\n");
+ break;
+ }
+ switch (remap_choice)
+ {
+ case remap_no:
+ break;
+ case remap_win:
+ fprintf(fd, "\n");
+ fprintf(fd, "\" Remap a few keys for Windows behavior\n");
+ fprintf(fd, "source $VIMRUNTIME/mswin.vim\n");
+ break;
+ }
+ switch (mouse_choice)
+ {
+ case mouse_xterm:
+ fprintf(fd, "\n");
+ fprintf(fd, "\" Mouse behavior (the Unix way)\n");
+ fprintf(fd, "behave xterm\n");
+ break;
+ case mouse_mswin:
+ fprintf(fd, "\n");
+ fprintf(fd, "\" Mouse behavior (the Windows way)\n");
+ fprintf(fd, "behave mswin\n");
+ break;
+ case mouse_default:
+ break;
+ }
+ if ((tfd = fopen("diff.exe", "r")) != NULL)
+ {
+ /* Use the diff.exe that comes with the self-extracting gvim.exe. */
+ fclose(tfd);
+ fprintf(fd, "\n");
+ fprintf(fd, "\" Use the internal diff if available.\n");
+ fprintf(fd, "\" Otherwise use the special 'diffexpr' for Windows.\n");
+ fprintf(fd, "if &diffopt !~# 'internal'\n");
+ fprintf(fd, " set diffexpr=MyDiff()\n");
+ fprintf(fd, "endif\n");
+ fprintf(fd, "function MyDiff()\n");
+ fprintf(fd, " let opt = '-a --binary '\n");
+ fprintf(fd, " if &diffopt =~ 'icase' | let opt = opt . '-i ' | endif\n");
+ fprintf(fd, " if &diffopt =~ 'iwhite' | let opt = opt . '-b ' | endif\n");
+ /* Use quotes only when needed, they may cause trouble.
+ * Always escape "!". */
+ fprintf(fd, " let arg1 = v:fname_in\n");
+ fprintf(fd, " if arg1 =~ ' ' | let arg1 = '\"' . arg1 . '\"' | endif\n");
+ fprintf(fd, " let arg1 = substitute(arg1, '!', '\\!', 'g')\n");
+ fprintf(fd, " let arg2 = v:fname_new\n");
+ fprintf(fd, " if arg2 =~ ' ' | let arg2 = '\"' . arg2 . '\"' | endif\n");
+ fprintf(fd, " let arg2 = substitute(arg2, '!', '\\!', 'g')\n");
+ fprintf(fd, " let arg3 = v:fname_out\n");
+ fprintf(fd, " if arg3 =~ ' ' | let arg3 = '\"' . arg3 . '\"' | endif\n");
+ fprintf(fd, " let arg3 = substitute(arg3, '!', '\\!', 'g')\n");
+
+ /* If the path has a space: When using cmd.exe (Win NT/2000/XP) put
+ * quotes around the diff command and rely on the default value of
+ * shellxquote to solve the quoting problem for the whole command.
+ *
+ * Otherwise put a double quote just before the space and at the
+ * end of the command. Putting quotes around the whole thing
+ * doesn't work on Win 95/98/ME. This is mostly guessed! */
+ fprintf(fd, " if $VIMRUNTIME =~ ' '\n");
+ fprintf(fd, " if &sh =~ '\\<cmd'\n");
+ fprintf(fd, " if empty(&shellxquote)\n");
+ fprintf(fd, " let l:shxq_sav = ''\n");
+ fprintf(fd, " set shellxquote&\n");
+ fprintf(fd, " endif\n");
+ fprintf(fd, " let cmd = '\"' . $VIMRUNTIME . '\\diff\"'\n");
+ fprintf(fd, " else\n");
+ fprintf(fd, " let cmd = substitute($VIMRUNTIME, ' ', '\" ', '') . '\\diff\"'\n");
+ fprintf(fd, " endif\n");
+ fprintf(fd, " else\n");
+ fprintf(fd, " let cmd = $VIMRUNTIME . '\\diff'\n");
+ fprintf(fd, " endif\n");
+ fprintf(fd, " let cmd = substitute(cmd, '!', '\\!', 'g')\n");
+ fprintf(fd, " silent execute '!' . cmd . ' ' . opt . arg1 . ' ' . arg2 . ' > ' . arg3\n");
+ fprintf(fd, " if exists('l:shxq_sav')\n");
+ fprintf(fd, " let &shellxquote=l:shxq_sav\n");
+ fprintf(fd, " endif\n");
+ fprintf(fd, "endfunction\n");
+ fprintf(fd, "\n");
+ }
+ fclose(fd);
+ printf("%s has been written\n", fname);
+}
+
+ static void
+change_vimrc_choice(int idx)
+{
+ if (choices[idx].installfunc != NULL)
+ {
+ /* Switch to NOT change or create a vimrc file. */
+ if (*oldvimrc != NUL)
+ alloc_text(idx, "Do NOT change startup file %s", oldvimrc);
+ else
+ alloc_text(idx, "Do NOT create startup file %s", vimrc);
+ choices[idx].installfunc = NULL;
+ choices[idx + 1].active = 0;
+ choices[idx + 2].active = 0;
+ choices[idx + 3].active = 0;
+ }
+ else
+ {
+ /* Switch to change or create a vimrc file. */
+ if (*oldvimrc != NUL)
+ alloc_text(idx, "Overwrite startup file %s with:", oldvimrc);
+ else
+ alloc_text(idx, "Create startup file %s with:", vimrc);
+ choices[idx].installfunc = install_vimrc;
+ choices[idx + 1].active = 1;
+ choices[idx + 2].active = 1;
+ choices[idx + 3].active = 1;
+ }
+}
+
+/*
+ * Change the choice how to run Vim.
+ */
+ static void
+change_run_choice(int idx)
+{
+ compat_choice = get_choice(compat_choices, TABLE_SIZE(compat_choices));
+ alloc_text(idx, compat_text, compat_choices[compat_choice]);
+}
+
+/*
+ * Change the choice if keys are to be remapped.
+ */
+ static void
+change_remap_choice(int idx)
+{
+ remap_choice = get_choice(remap_choices, TABLE_SIZE(remap_choices));
+ alloc_text(idx, remap_text, remap_choices[remap_choice]);
+}
+
+/*
+ * Change the choice how to select text.
+ */
+ static void
+change_mouse_choice(int idx)
+{
+ mouse_choice = get_choice(mouse_choices, TABLE_SIZE(mouse_choices));
+ alloc_text(idx, mouse_text, mouse_choices[mouse_choice]);
+}
+
+ static void
+init_vimrc_choices(void)
+{
+ /* set path for a new _vimrc file (also when not used) */
+ strcpy(vimrc, installdir);
+ strcpy(vimrc + runtimeidx, "_vimrc");
+
+ /* Set opposite value and then toggle it by calling change_vimrc_choice() */
+ if (*oldvimrc == NUL)
+ choices[choice_count].installfunc = NULL;
+ else
+ choices[choice_count].installfunc = install_vimrc;
+ choices[choice_count].text = NULL;
+ change_vimrc_choice(choice_count);
+ choices[choice_count].changefunc = change_vimrc_choice;
+ choices[choice_count].active = 1;
+ ++choice_count;
+
+ /* default way to run Vim */
+ alloc_text(choice_count, compat_text, compat_choices[compat_choice]);
+ choices[choice_count].changefunc = change_run_choice;
+ choices[choice_count].installfunc = NULL;
+ choices[choice_count].active = (*oldvimrc == NUL);
+ ++choice_count;
+
+ /* Whether to remap keys */
+ alloc_text(choice_count, remap_text , remap_choices[remap_choice]);
+ choices[choice_count].changefunc = change_remap_choice;
+ choices[choice_count].installfunc = NULL;
+ choices[choice_count].active = (*oldvimrc == NUL);
+ ++choice_count;
+
+ /* default way to use the mouse */
+ alloc_text(choice_count, mouse_text, mouse_choices[mouse_choice]);
+ choices[choice_count].changefunc = change_mouse_choice;
+ choices[choice_count].installfunc = NULL;
+ choices[choice_count].active = (*oldvimrc == NUL);
+ ++choice_count;
+}
+
+ static LONG
+reg_create_key(
+ HKEY root,
+ const char *subkey,
+ PHKEY phKey,
+ DWORD flag)
+{
+ DWORD disp;
+
+ *phKey = NULL;
+ return RegCreateKeyEx(
+ root, subkey,
+ 0, NULL, REG_OPTION_NON_VOLATILE,
+ flag | KEY_WRITE,
+ NULL, phKey, &disp);
+}
+
+ static LONG
+reg_set_string_value(
+ HKEY hKey,
+ const char *value_name,
+ const char *data)
+{
+ return RegSetValueEx(hKey, value_name, 0, REG_SZ,
+ (LPBYTE)data, (DWORD)(1 + strlen(data)));
+}
+
+ static LONG
+reg_create_key_and_value(
+ HKEY hRootKey,
+ const char *subkey,
+ const char *value_name,
+ const char *data,
+ DWORD flag)
+{
+ HKEY hKey;
+ LONG lRet = reg_create_key(hRootKey, subkey, &hKey, flag);
+
+ if (ERROR_SUCCESS == lRet)
+ {
+ lRet = reg_set_string_value(hKey, value_name, data);
+ RegCloseKey(hKey);
+ }
+ return lRet;
+}
+
+ static LONG
+register_inproc_server(
+ HKEY hRootKey,
+ const char *clsid,
+ const char *extname,
+ const char *module,
+ const char *threading_model,
+ DWORD flag)
+{
+ CHAR subkey[BUFSIZE];
+ LONG lRet;
+
+ sprintf(subkey, "CLSID\\%s", clsid);
+ lRet = reg_create_key_and_value(hRootKey, subkey, NULL, extname, flag);
+ if (ERROR_SUCCESS == lRet)
+ {
+ sprintf(subkey, "CLSID\\%s\\InProcServer32", clsid);
+ lRet = reg_create_key_and_value(hRootKey, subkey, NULL, module, flag);
+ if (ERROR_SUCCESS == lRet)
+ {
+ lRet = reg_create_key_and_value(hRootKey, subkey,
+ "ThreadingModel", threading_model, flag);
+ }
+ }
+ return lRet;
+}
+
+ static LONG
+register_shellex(
+ HKEY hRootKey,
+ const char *clsid,
+ const char *name,
+ const char *exe_path,
+ DWORD flag)
+{
+ LONG lRet = reg_create_key_and_value(
+ hRootKey,
+ "*\\shellex\\ContextMenuHandlers\\gvim",
+ NULL,
+ clsid,
+ flag);
+
+ if (ERROR_SUCCESS == lRet)
+ {
+ lRet = reg_create_key_and_value(
+ HKEY_LOCAL_MACHINE,
+ "Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved",
+ clsid,
+ name,
+ flag);
+
+ if (ERROR_SUCCESS == lRet)
+ {
+ lRet = reg_create_key_and_value(
+ HKEY_LOCAL_MACHINE,
+ "Software\\Vim\\Gvim",
+ "path",
+ exe_path,
+ flag);
+ }
+ }
+ return lRet;
+}
+
+ static LONG
+register_openwith(
+ HKEY hRootKey,
+ const char *exe_path,
+ DWORD flag)
+{
+ char exe_cmd[BUFSIZE];
+ LONG lRet;
+
+ sprintf(exe_cmd, "\"%s\" \"%%1\"", exe_path);
+ lRet = reg_create_key_and_value(
+ hRootKey,
+ "Applications\\gvim.exe\\shell\\edit\\command",
+ NULL,
+ exe_cmd,
+ flag);
+
+ if (ERROR_SUCCESS == lRet)
+ {
+ int i;
+ static const char *openwith[] = {
+ ".htm\\OpenWithList\\gvim.exe",
+ ".vim\\OpenWithList\\gvim.exe",
+ "*\\OpenWithList\\gvim.exe",
+ };
+
+ for (i = 0; ERROR_SUCCESS == lRet
+ && i < sizeof(openwith) / sizeof(openwith[0]); i++)
+ {
+ lRet = reg_create_key_and_value(hRootKey, openwith[i], NULL, "", flag);
+ }
+ }
+
+ return lRet;
+}
+
+ static LONG
+register_uninstall(
+ HKEY hRootKey,
+ const char *appname,
+ const char *display_name,
+ const char *uninstall_string,
+ const char *display_icon,
+ const char *display_version,
+ const char *publisher)
+{
+ LONG lRet = reg_create_key_and_value(hRootKey, appname,
+ "DisplayName", display_name, KEY_WOW64_64KEY);
+
+ if (ERROR_SUCCESS == lRet)
+ lRet = reg_create_key_and_value(hRootKey, appname,
+ "UninstallString", uninstall_string, KEY_WOW64_64KEY);
+ if (ERROR_SUCCESS == lRet)
+ lRet = reg_create_key_and_value(hRootKey, appname,
+ "DisplayIcon", display_icon, KEY_WOW64_64KEY);
+ if (ERROR_SUCCESS == lRet)
+ lRet = reg_create_key_and_value(hRootKey, appname,
+ "DisplayVersion", display_version, KEY_WOW64_64KEY);
+ if (ERROR_SUCCESS == lRet)
+ lRet = reg_create_key_and_value(hRootKey, appname,
+ "Publisher", publisher, KEY_WOW64_64KEY);
+ return lRet;
+}
+
+/*
+ * Add some entries to the registry:
+ * - to add "Edit with Vim" to the context * menu
+ * - to add Vim to the "Open with..." list
+ * - to uninstall Vim
+ */
+/*ARGSUSED*/
+ static int
+install_registry(void)
+{
+ LONG lRet = ERROR_SUCCESS;
+ const char *vim_ext_ThreadingModel = "Apartment";
+ const char *vim_ext_name = "Vim Shell Extension";
+ const char *vim_ext_clsid = "{51EEE242-AD87-11d3-9C1E-0090278BBD99}";
+ char vim_exe_path[BUFSIZE];
+ char display_name[BUFSIZE];
+ char uninstall_string[BUFSIZE];
+ char icon_string[BUFSIZE];
+ int i;
+ int loop_count = is_64bit_os() ? 2 : 1;
+ DWORD flag;
+
+ sprintf(vim_exe_path, "%s\\gvim.exe", installdir);
+
+ if (install_popup)
+ {
+ char bufg[BUFSIZE];
+
+ printf("Creating \"Edit with Vim\" popup menu entry\n");
+
+ for (i = 0; i < loop_count; i++)
+ {
+ if (i == 0)
+ {
+ sprintf(bufg, "%s\\" GVIMEXT32_PATH, installdir);
+ flag = KEY_WOW64_32KEY;
+ }
+ else
+ {
+ sprintf(bufg, "%s\\" GVIMEXT64_PATH, installdir);
+ flag = KEY_WOW64_64KEY;
+ }
+
+ lRet = register_inproc_server(
+ HKEY_CLASSES_ROOT, vim_ext_clsid, vim_ext_name,
+ bufg, vim_ext_ThreadingModel, flag);
+ if (ERROR_SUCCESS != lRet)
+ return FAIL;
+ lRet = register_shellex(
+ HKEY_CLASSES_ROOT, vim_ext_clsid, vim_ext_name,
+ vim_exe_path, flag);
+ if (ERROR_SUCCESS != lRet)
+ return FAIL;
+ }
+ }
+
+ if (install_openwith)
+ {
+ printf("Creating \"Open with ...\" list entry\n");
+
+ for (i = 0; i < loop_count; i++)
+ {
+ if (i == 0)
+ flag = KEY_WOW64_32KEY;
+ else
+ flag = KEY_WOW64_64KEY;
+
+ lRet = register_openwith(HKEY_CLASSES_ROOT, vim_exe_path, flag);
+ if (ERROR_SUCCESS != lRet)
+ return FAIL;
+ }
+ }
+
+ printf("Creating an uninstall entry\n");
+ sprintf(display_name, "Vim " VIM_VERSION_SHORT
+#ifdef _WIN64
+ " (x64)"
+#endif
+ );
+
+ /* For the NSIS installer use the generated uninstaller. */
+ if (interactive)
+ sprintf(uninstall_string, "%s\\uninstal.exe", installdir);
+ else
+ sprintf(uninstall_string, "%s\\uninstall-gui.exe", installdir);
+
+ sprintf(icon_string, "%s\\gvim.exe,0", installdir);
+
+ lRet = register_uninstall(
+ HKEY_LOCAL_MACHINE,
+ "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Vim " VIM_VERSION_SHORT,
+ display_name,
+ uninstall_string,
+ icon_string,
+ VIM_VERSION_SHORT,
+ "Bram Moolenaar et al.");
+ if (ERROR_SUCCESS != lRet)
+ return FAIL;
+
+ return OK;
+}
+
+ static void
+change_popup_choice(int idx)
+{
+ if (install_popup == 0)
+ {
+ choices[idx].text = "Install an entry for Vim in the popup menu for the right\n mouse button so that you can edit any file with Vim";
+ install_popup = 1;
+ }
+ else
+ {
+ choices[idx].text = "Do NOT install an entry for Vim in the popup menu for the\n right mouse button to edit any file with Vim";
+ install_popup = 0;
+ }
+}
+
+/*
+ * Only add the choice for the popup menu entry when gvim.exe was found and
+ * both gvimext.dll and regedit.exe exist.
+ */
+ static void
+init_popup_choice(void)
+{
+ struct stat st;
+
+ if (has_gvim
+ && (stat(GVIMEXT32_PATH, &st) >= 0
+ || stat(GVIMEXT64_PATH, &st) >= 0))
+ {
+ choices[choice_count].changefunc = change_popup_choice;
+ choices[choice_count].installfunc = NULL;
+ choices[choice_count].active = 1;
+ change_popup_choice(choice_count); /* set the text */
+ ++choice_count;
+ }
+ else
+ add_dummy_choice();
+}
+
+ static void
+change_openwith_choice(int idx)
+{
+ if (install_openwith == 0)
+ {
+ choices[idx].text = "Add Vim to the \"Open With...\" list in the popup menu for the right\n mouse button so that you can edit any file with Vim";
+ install_openwith = 1;
+ }
+ else
+ {
+ choices[idx].text = "Do NOT add Vim to the \"Open With...\" list in the popup menu for the\n right mouse button to edit any file with Vim";
+ install_openwith = 0;
+ }
+}
+
+/*
+ * Only add the choice for the open-with menu entry when gvim.exe was found
+ * and regedit.exe exist.
+ */
+ static void
+init_openwith_choice(void)
+{
+ if (has_gvim)
+ {
+ choices[choice_count].changefunc = change_openwith_choice;
+ choices[choice_count].installfunc = NULL;
+ choices[choice_count].active = 1;
+ change_openwith_choice(choice_count); /* set the text */
+ ++choice_count;
+ }
+ else
+ add_dummy_choice();
+}
+
+/* create_shortcut
+ *
+ * Create a shell link.
+ *
+ * returns 0 on failure, non-zero on successful completion.
+ *
+ * NOTE: Currently untested with mingw.
+ */
+ int
+create_shortcut(
+ const char *shortcut_name,
+ const char *iconfile_path,
+ int iconindex,
+ const char *shortcut_target,
+ const char *shortcut_args,
+ const char *workingdir
+ )
+{
+ IShellLink *shelllink_ptr;
+ HRESULT hres;
+ IPersistFile *persistfile_ptr;
+
+ /* Initialize COM library */
+ hres = CoInitialize(NULL);
+ if (!SUCCEEDED(hres))
+ {
+ printf("Error: Could not open the COM library. Not creating shortcut.\n");
+ return FAIL;
+ }
+
+ /* Instantiate a COM object for the ShellLink, store a pointer to it
+ * in shelllink_ptr. */
+ hres = CoCreateInstance(&CLSID_ShellLink,
+ NULL,
+ CLSCTX_INPROC_SERVER,
+ &IID_IShellLink,
+ (void **) &shelllink_ptr);
+
+ if (SUCCEEDED(hres)) /* If the instantiation was successful... */
+ {
+ /* ...Then build a PersistFile interface for the ShellLink so we can
+ * save it as a file after we build it. */
+ hres = shelllink_ptr->lpVtbl->QueryInterface(shelllink_ptr,
+ &IID_IPersistFile, (void **) &persistfile_ptr);
+
+ if (SUCCEEDED(hres))
+ {
+ wchar_t wsz[BUFSIZE];
+
+ /* translate the (possibly) multibyte shortcut filename to windows
+ * Unicode so it can be used as a file name.
+ */
+ MultiByteToWideChar(CP_ACP, 0, shortcut_name, -1, wsz, BUFSIZE);
+
+ /* set the attributes */
+ shelllink_ptr->lpVtbl->SetPath(shelllink_ptr, shortcut_target);
+ shelllink_ptr->lpVtbl->SetWorkingDirectory(shelllink_ptr,
+ workingdir);
+ shelllink_ptr->lpVtbl->SetIconLocation(shelllink_ptr,
+ iconfile_path, iconindex);
+ shelllink_ptr->lpVtbl->SetArguments(shelllink_ptr, shortcut_args);
+
+ /* save the shortcut to a file and return the PersistFile object*/
+ persistfile_ptr->lpVtbl->Save(persistfile_ptr, wsz, 1);
+ persistfile_ptr->lpVtbl->Release(persistfile_ptr);
+ }
+ else
+ {
+ printf("QueryInterface Error\n");
+ return FAIL;
+ }
+
+ /* Return the ShellLink object */
+ shelllink_ptr->lpVtbl->Release(shelllink_ptr);
+ }
+ else
+ {
+ printf("CoCreateInstance Error - hres = %08x\n", (int)hres);
+ return FAIL;
+ }
+
+ return OK;
+}
+
+/*
+ * Build a path to where we will put a specified link.
+ *
+ * Return 0 on error, non-zero on success
+ */
+ int
+build_link_name(
+ char *link_path,
+ const char *link_name,
+ const char *shell_folder_name)
+{
+ char shell_folder_path[BUFSIZE];
+
+ if (get_shell_folder_path(shell_folder_path, shell_folder_name) == FAIL)
+ {
+ printf("An error occurred while attempting to find the path to %s.\n",
+ shell_folder_name);
+ return FAIL;
+ }
+
+ /* Make sure the directory exists (create Start Menu\Programs\Vim).
+ * Ignore errors if it already exists. */
+ vim_mkdir(shell_folder_path, 0755);
+
+ /* build the path to the shortcut and the path to gvim.exe */
+ sprintf(link_path, "%s\\%s.lnk", shell_folder_path, link_name);
+
+ return OK;
+}
+
+ static int
+build_shortcut(
+ const char *name, /* Name of the shortcut */
+ const char *exename, /* Name of the executable (e.g., vim.exe) */
+ const char *args,
+ const char *shell_folder,
+ const char *workingdir)
+{
+ char executable_path[BUFSIZE];
+ char link_name[BUFSIZE];
+
+ sprintf(executable_path, "%s\\%s", installdir, exename);
+
+ if (build_link_name(link_name, name, shell_folder) == FAIL)
+ {
+ printf("An error has occurred. A shortcut to %s will not be created %s.\n",
+ name,
+ *shell_folder == 'd' ? "on the desktop" : "in the Start menu");
+ return FAIL;
+ }
+
+ /* Create the shortcut: */
+ return create_shortcut(link_name, executable_path, 0,
+ executable_path, args, workingdir);
+}
+
+/*
+ * We used to use "homedir" as the working directory, but that is a bad choice
+ * on multi-user systems. However, not specifying a directory results in the
+ * current directory to be c:\Windows\system32 on Windows 7. Use environment
+ * variables instead.
+ */
+#define WORKDIR "%HOMEDRIVE%%HOMEPATH%"
+
+/*
+ * Create shortcut(s) in the Start Menu\Programs\Vim folder.
+ */
+ static void
+install_start_menu(int idx)
+{
+ need_uninstall_entry = 1;
+ printf("Creating start menu\n");
+ if (has_vim)
+ {
+ if (build_shortcut("Vim", "vim.exe", "",
+ VIM_STARTMENU, WORKDIR) == FAIL)
+ return;
+ if (build_shortcut("Vim Read-only", "vim.exe", "-R",
+ VIM_STARTMENU, WORKDIR) == FAIL)
+ return;
+ if (build_shortcut("Vim Diff", "vim.exe", "-d",
+ VIM_STARTMENU, WORKDIR) == FAIL)
+ return;
+ }
+ if (has_gvim)
+ {
+ if (build_shortcut("gVim", "gvim.exe", "",
+ VIM_STARTMENU, WORKDIR) == FAIL)
+ return;
+ if (build_shortcut("gVim Easy", "gvim.exe", "-y",
+ VIM_STARTMENU, WORKDIR) == FAIL)
+ return;
+ if (build_shortcut("gVim Read-only", "gvim.exe", "-R",
+ VIM_STARTMENU, WORKDIR) == FAIL)
+ return;
+ if (build_shortcut("gVim Diff", "gvim.exe", "-d",
+ VIM_STARTMENU, WORKDIR) == FAIL)
+ return;
+ }
+ if (build_shortcut("Uninstall",
+ interactive ? "uninstal.exe" : "uninstall-gui.exe", "",
+ VIM_STARTMENU, installdir) == FAIL)
+ return;
+ /* For Windows NT the working dir of the vimtutor.bat must be right,
+ * otherwise gvim.exe won't be found and using gvimbat doesn't work. */
+ if (build_shortcut("Vim tutor", "vimtutor.bat", "",
+ VIM_STARTMENU, installdir) == FAIL)
+ return;
+ if (build_shortcut("Help", has_gvim ? "gvim.exe" : "vim.exe", "-c h",
+ VIM_STARTMENU, WORKDIR) == FAIL)
+ return;
+ {
+ char shell_folder_path[BUFSIZE];
+
+ /* Creating the URL shortcut works a bit differently... */
+ if (get_shell_folder_path(shell_folder_path, VIM_STARTMENU) == FAIL)
+ {
+ printf("Finding the path of the Start menu failed\n");
+ return ;
+ }
+ add_pathsep(shell_folder_path);
+ strcat(shell_folder_path, "Vim Online.url");
+ if (!WritePrivateProfileString("InternetShortcut", "URL",
+ "https://www.vim.org/", shell_folder_path))
+ {
+ printf("Creating the Vim online URL failed\n");
+ return;
+ }
+ }
+}
+
+ static void
+toggle_startmenu_choice(int idx)
+{
+ if (choices[idx].installfunc == NULL)
+ {
+ choices[idx].installfunc = install_start_menu;
+ choices[idx].text = "Add Vim to the Start menu";
+ }
+ else
+ {
+ choices[idx].installfunc = NULL;
+ choices[idx].text = "Do NOT add Vim to the Start menu";
+ }
+}
+
+/*
+ * Function to actually create the shortcuts
+ *
+ * Currently I am supplying no working directory to the shortcut. This
+ * means that the initial working dir will be:
+ * - the location of the shortcut if no file is supplied
+ * - the location of the file being edited if a file is supplied (ie via
+ * drag and drop onto the shortcut).
+ */
+ void
+install_shortcut_gvim(int idx)
+{
+ /* Create shortcut(s) on the desktop */
+ if (choices[idx].arg)
+ {
+ (void)build_shortcut(icon_names[0], "gvim.exe",
+ "", "desktop", WORKDIR);
+ need_uninstall_entry = 1;
+ }
+}
+
+ void
+install_shortcut_evim(int idx)
+{
+ if (choices[idx].arg)
+ {
+ (void)build_shortcut(icon_names[1], "gvim.exe",
+ "-y", "desktop", WORKDIR);
+ need_uninstall_entry = 1;
+ }
+}
+
+ void
+install_shortcut_gview(int idx)
+{
+ if (choices[idx].arg)
+ {
+ (void)build_shortcut(icon_names[2], "gvim.exe",
+ "-R", "desktop", WORKDIR);
+ need_uninstall_entry = 1;
+ }
+}
+
+ void
+toggle_shortcut_choice(int idx)
+{
+ char *arg;
+
+ if (choices[idx].installfunc == install_shortcut_gvim)
+ arg = "gVim";
+ else if (choices[idx].installfunc == install_shortcut_evim)
+ arg = "gVim Easy";
+ else
+ arg = "gVim Read-only";
+ if (choices[idx].arg)
+ {
+ choices[idx].arg = 0;
+ alloc_text(idx, "Do NOT create a desktop icon for %s", arg);
+ }
+ else
+ {
+ choices[idx].arg = 1;
+ alloc_text(idx, "Create a desktop icon for %s", arg);
+ }
+}
+
+ static void
+init_startmenu_choice(void)
+{
+ /* Start menu */
+ choices[choice_count].changefunc = toggle_startmenu_choice;
+ choices[choice_count].installfunc = NULL;
+ choices[choice_count].active = 1;
+ toggle_startmenu_choice(choice_count); /* set the text */
+ ++choice_count;
+}
+
+/*
+ * Add the choice for the desktop shortcuts.
+ */
+ static void
+init_shortcut_choices(void)
+{
+ /* Shortcut to gvim */
+ choices[choice_count].text = NULL;
+ choices[choice_count].arg = 0;
+ choices[choice_count].active = has_gvim;
+ choices[choice_count].changefunc = toggle_shortcut_choice;
+ choices[choice_count].installfunc = install_shortcut_gvim;
+ toggle_shortcut_choice(choice_count);
+ ++choice_count;
+
+ /* Shortcut to evim */
+ choices[choice_count].text = NULL;
+ choices[choice_count].arg = 0;
+ choices[choice_count].active = has_gvim;
+ choices[choice_count].changefunc = toggle_shortcut_choice;
+ choices[choice_count].installfunc = install_shortcut_evim;
+ toggle_shortcut_choice(choice_count);
+ ++choice_count;
+
+ /* Shortcut to gview */
+ choices[choice_count].text = NULL;
+ choices[choice_count].arg = 0;
+ choices[choice_count].active = has_gvim;
+ choices[choice_count].changefunc = toggle_shortcut_choice;
+ choices[choice_count].installfunc = install_shortcut_gview;
+ toggle_shortcut_choice(choice_count);
+ ++choice_count;
+}
+
+/*
+ * Attempt to register OLE for Vim.
+ */
+ static void
+install_OLE_register(void)
+{
+ char register_command_string[BUFSIZE + 30];
+
+ printf("\n--- Attempting to register Vim with OLE ---\n");
+ printf("(There is no message whether this works or not.)\n");
+
+ sprintf(register_command_string, "\"%s\\gvim.exe\" -silent -register", installdir);
+ system(register_command_string);
+}
+
+/*
+ * Remove the last part of directory "path[]" to get its parent, and put the
+ * result in "to[]".
+ */
+ static void
+dir_remove_last(const char *path, char to[BUFSIZE])
+{
+ char c;
+ long last_char_to_copy;
+ long path_length = strlen(path);
+
+ /* skip the last character just in case it is a '\\' */
+ last_char_to_copy = path_length - 2;
+ c = path[last_char_to_copy];
+
+ while (c != '\\')
+ {
+ last_char_to_copy--;
+ c = path[last_char_to_copy];
+ }
+
+ strncpy(to, path, (size_t)last_char_to_copy);
+ to[last_char_to_copy] = NUL;
+}
+
+ static void
+set_directories_text(int idx)
+{
+ int vimfiles_dir_choice = choices[idx].arg;
+
+ if (vimfiles_dir_choice == (int)vimfiles_dir_none)
+ alloc_text(idx, "Do NOT create plugin directories%s", "");
+ else
+ alloc_text(idx, "Create plugin directories: %s",
+ vimfiles_dir_choices[vimfiles_dir_choice]);
+}
+
+/*
+ * To get the "real" home directory:
+ * - get value of $HOME
+ * - if not found, get value of $HOMEDRIVE$HOMEPATH
+ * - if not found, get value of $USERPROFILE
+ *
+ * This code is based on init_homedir() in misc1.c, keep in sync!
+ */
+static char *homedir = NULL;
+
+ void
+init_homedir(void)
+{
+ char *var;
+ char buf[MAX_PATH];
+
+ if (homedir != NULL)
+ {
+ free(homedir);
+ homedir = NULL;
+ }
+
+ var = getenv("HOME");
+
+ /*
+ * Typically, $HOME is not defined on Windows, unless the user has
+ * specifically defined it for Vim's sake. However, on Windows NT
+ * platforms, $HOMEDRIVE and $HOMEPATH are automatically defined for
+ * each user. Try constructing $HOME from these.
+ */
+ if (var == NULL || *var == NUL)
+ {
+ char *homedrive, *homepath;
+
+ homedrive = getenv("HOMEDRIVE");
+ homepath = getenv("HOMEPATH");
+ if (homepath == NULL || *homepath == NUL)
+ homepath = "\\";
+ if (homedrive != NULL
+ && strlen(homedrive) + strlen(homepath) < MAX_PATH)
+ {
+ sprintf(buf, "%s%s", homedrive, homepath);
+ if (buf[0] != NUL)
+ var = buf;
+ }
+ }
+
+ if (var == NULL)
+ var = getenv("USERPROFILE");
+
+ /*
+ * Weird but true: $HOME may contain an indirect reference to another
+ * variable, esp. "%USERPROFILE%". Happens when $USERPROFILE isn't set
+ * when $HOME is being set.
+ */
+ if (var != NULL && *var == '%')
+ {
+ char *p;
+ char *exp;
+
+ p = strchr(var + 1, '%');
+ if (p != NULL)
+ {
+ strncpy(buf, var + 1, p - (var + 1));
+ buf[p - (var + 1)] = NUL;
+ exp = getenv(buf);
+ if (exp != NULL && *exp != NUL
+ && strlen(exp) + strlen(p) < MAX_PATH)
+ {
+ _snprintf(buf, MAX_PATH, "%s%s", exp, p + 1);
+ buf[MAX_PATH - 1] = NUL;
+ var = buf;
+ }
+ }
+ }
+
+ if (var != NULL && *var == NUL) // empty is same as not set
+ var = NULL;
+
+ if (var == NULL)
+ homedir = NULL;
+ else
+ homedir = _strdup(var);
+}
+
+/*
+ * Change the directory that the vim plugin directories will be created in:
+ * $HOME, $VIM or nowhere.
+ */
+ static void
+change_directories_choice(int idx)
+{
+ int choice_count = TABLE_SIZE(vimfiles_dir_choices);
+
+ /* Don't offer the $HOME choice if $HOME isn't set. */
+ if (homedir == NULL)
+ --choice_count;
+ choices[idx].arg = get_choice(vimfiles_dir_choices, choice_count);
+ set_directories_text(idx);
+}
+
+/*
+ * Create the plugin directories...
+ */
+/*ARGSUSED*/
+ static void
+install_vimfilesdir(int idx)
+{
+ int i;
+ int vimfiles_dir_choice = choices[idx].arg;
+ char *p;
+ char vimdir_path[BUFSIZE];
+ char vimfiles_path[BUFSIZE];
+ char tmp_dirname[BUFSIZE];
+
+ /* switch on the location that the user wants the plugin directories
+ * built in */
+ switch (vimfiles_dir_choice)
+ {
+ case vimfiles_dir_vim:
+ {
+ /* Go to the %VIM% directory - check env first, then go one dir
+ * below installdir if there is no %VIM% environment variable.
+ * The accuracy of $VIM is checked in inspect_system(), so we
+ * can be sure it is ok to use here. */
+ p = getenv("VIM");
+ if (p == NULL) /* No $VIM in path */
+ dir_remove_last(installdir, vimdir_path);
+ else
+ strcpy(vimdir_path, p);
+ break;
+ }
+ case vimfiles_dir_home:
+ {
+ // Find the $HOME directory. Its existence was already checked.
+ p = homedir;
+ if (p == NULL)
+ {
+ printf("Internal error: $HOME is NULL\n");
+ p = "c:\\";
+ }
+ strcpy(vimdir_path, p);
+ break;
+ }
+ case vimfiles_dir_none:
+ {
+ // Do not create vim plugin directory.
+ return;
+ }
+ }
+
+ /* Now, just create the directory. If it already exists, it will fail
+ * silently. */
+ sprintf(vimfiles_path, "%s\\vimfiles", vimdir_path);
+ vim_mkdir(vimfiles_path, 0755);
+
+ printf("Creating the following directories in \"%s\":\n", vimfiles_path);
+ for (i = 0; i < TABLE_SIZE(vimfiles_subdirs); i++)
+ {
+ sprintf(tmp_dirname, "%s\\%s", vimfiles_path, vimfiles_subdirs[i]);
+ printf(" %s", vimfiles_subdirs[i]);
+ vim_mkdir(tmp_dirname, 0755);
+ }
+ printf("\n");
+}
+
+/*
+ * Add the creation of runtime files to the setup sequence.
+ */
+ static void
+init_directories_choice(void)
+{
+ struct stat st;
+ char tmp_dirname[BUFSIZE];
+ char *p;
+ int vimfiles_dir_choice;
+
+ choices[choice_count].text = alloc(150);
+ choices[choice_count].changefunc = change_directories_choice;
+ choices[choice_count].installfunc = install_vimfilesdir;
+ choices[choice_count].active = 1;
+
+ // Check if the "compiler" directory already exists. That's a good
+ // indication that the plugin directories were already created.
+ if (getenv("HOME") != NULL)
+ {
+ vimfiles_dir_choice = (int)vimfiles_dir_home;
+ sprintf(tmp_dirname, "%s\\vimfiles\\compiler", getenv("HOME"));
+ if (stat(tmp_dirname, &st) == 0)
+ vimfiles_dir_choice = (int)vimfiles_dir_none;
+ }
+ else
+ {
+ vimfiles_dir_choice = (int)vimfiles_dir_vim;
+ p = getenv("VIM");
+ if (p == NULL) // No $VIM in path, use the install dir.
+ dir_remove_last(installdir, tmp_dirname);
+ else
+ strcpy(tmp_dirname, p);
+ strcat(tmp_dirname, "\\vimfiles\\compiler");
+ if (stat(tmp_dirname, &st) == 0)
+ vimfiles_dir_choice = (int)vimfiles_dir_none;
+ }
+
+ choices[choice_count].arg = vimfiles_dir_choice;
+ set_directories_text(choice_count);
+ ++choice_count;
+}
+
+/*
+ * Setup the choices and the default values.
+ */
+ static void
+setup_choices(void)
+{
+ /* install the batch files */
+ init_bat_choices();
+
+ /* (over) write _vimrc file */
+ init_vimrc_choices();
+
+ /* Whether to add Vim to the popup menu */
+ init_popup_choice();
+
+ /* Whether to add Vim to the "Open With..." menu */
+ init_openwith_choice();
+
+ /* Whether to add Vim to the Start Menu. */
+ init_startmenu_choice();
+
+ /* Whether to add shortcuts to the Desktop. */
+ init_shortcut_choices();
+
+ /* Whether to create the runtime directories. */
+ init_directories_choice();
+}
+
+ static void
+print_cmd_line_help(void)
+{
+ printf("Vim installer non-interactive command line arguments:\n");
+ printf("\n");
+ printf("-create-batfiles [vim gvim evim view gview vimdiff gvimdiff]\n");
+ printf(" Create .bat files for Vim variants in the Windows directory.\n");
+ printf("-create-vimrc\n");
+ printf(" Create a default _vimrc file if one does not already exist.\n");
+ printf("-vimrc-remap [no|win]\n");
+ printf(" Remap keys when creating a default _vimrc file.\n");
+ printf("-vimrc-behave [unix|mswin|default]\n");
+ printf(" Set mouse behavior when creating a default _vimrc file.\n");
+ printf("-vimrc-compat [vi|vim|defaults|all]\n");
+ printf(" Set Vi compatibility when creating a default _vimrc file.\n");
+ printf("-install-popup\n");
+ printf(" Install the Edit-with-Vim context menu entry\n");
+ printf("-install-openwith\n");
+ printf(" Add Vim to the \"Open With...\" context menu list\n");
+ printf("-add-start-menu");
+ printf(" Add Vim to the start menu\n");
+ printf("-install-icons");
+ printf(" Create icons for gVim executables on the desktop\n");
+ printf("-create-directories [vim|home]\n");
+ printf(" Create runtime directories to drop plugins into; in the $VIM\n");
+ printf(" or $HOME directory\n");
+ printf("-register-OLE");
+ printf(" Ignored\n");
+ printf("\n");
+}
+
+/*
+ * Setup installation choices based on command line switches
+ */
+ static void
+command_line_setup_choices(int argc, char **argv)
+{
+ int i, j;
+
+ for (i = 1; i < argc; i++)
+ {
+ if (strcmp(argv[i], "-create-batfiles") == 0)
+ {
+ if (i + 1 == argc)
+ continue;
+ while (argv[i + 1][0] != '-' && i < argc)
+ {
+ i++;
+ for (j = 1; j < TARGET_COUNT; ++j)
+ if ((targets[j].exenamearg[0] == 'g' ? has_gvim : has_vim)
+ && strcmp(argv[i], targets[j].name) == 0)
+ {
+ init_bat_choice(j);
+ break;
+ }
+ if (j == TARGET_COUNT)
+ printf("%s is not a valid choice for -create-batfiles\n",
+ argv[i]);
+
+ if (i + 1 == argc)
+ break;
+ }
+ }
+ else if (strcmp(argv[i], "-create-vimrc") == 0)
+ {
+ /* Setup default vimrc choices. If there is already a _vimrc file,
+ * it will NOT be overwritten.
+ */
+ init_vimrc_choices();
+ }
+ else if (strcmp(argv[i], "-vimrc-remap") == 0)
+ {
+ if (i + 1 == argc)
+ break;
+ i++;
+ if (strcmp(argv[i], "no") == 0)
+ remap_choice = remap_no;
+ else if (strcmp(argv[i], "win") == 0)
+ remap_choice = remap_win;
+ }
+ else if (strcmp(argv[i], "-vimrc-behave") == 0)
+ {
+ if (i + 1 == argc)
+ break;
+ i++;
+ if (strcmp(argv[i], "unix") == 0)
+ mouse_choice = mouse_xterm;
+ else if (strcmp(argv[i], "mswin") == 0)
+ mouse_choice = mouse_mswin;
+ else if (strcmp(argv[i], "default") == 0)
+ mouse_choice = mouse_default;
+ }
+ else if (strcmp(argv[i], "-vimrc-compat") == 0)
+ {
+ if (i + 1 == argc)
+ break;
+ i++;
+ if (strcmp(argv[i], "vi") == 0)
+ compat_choice = compat_vi;
+ else if (strcmp(argv[i], "vim") == 0)
+ compat_choice = compat_vim;
+ else if (strcmp(argv[i], "defaults") == 0)
+ compat_choice = compat_some_enhancements;
+ else if (strcmp(argv[i], "all") == 0)
+ compat_choice = compat_all_enhancements;
+ }
+ else if (strcmp(argv[i], "-install-popup") == 0)
+ {
+ init_popup_choice();
+ }
+ else if (strcmp(argv[i], "-install-openwith") == 0)
+ {
+ init_openwith_choice();
+ }
+ else if (strcmp(argv[i], "-add-start-menu") == 0)
+ {
+ init_startmenu_choice();
+ }
+ else if (strcmp(argv[i], "-install-icons") == 0)
+ {
+ init_shortcut_choices();
+ }
+ else if (strcmp(argv[i], "-create-directories") == 0)
+ {
+ int vimfiles_dir_choice = (int)vimfiles_dir_none;
+
+ init_directories_choice();
+ if (argv[i + 1][0] != '-')
+ {
+ i++;
+ if (strcmp(argv[i], "vim") == 0)
+ vimfiles_dir_choice = (int)vimfiles_dir_vim;
+ else if (strcmp(argv[i], "home") == 0)
+ {
+ if (homedir == NULL) // No $HOME in environment
+ vimfiles_dir_choice = (int)vimfiles_dir_none;
+ else
+ vimfiles_dir_choice = (int)vimfiles_dir_home;
+ }
+ else
+ {
+ printf("Unknown argument for -create-directories: %s\n",
+ argv[i]);
+ print_cmd_line_help();
+ }
+ }
+ else /* No choice specified, default to vim directory */
+ vimfiles_dir_choice = (int)vimfiles_dir_vim;
+ choices[choice_count - 1].arg = vimfiles_dir_choice;
+ }
+ else if (strcmp(argv[i], "-register-OLE") == 0)
+ {
+ /* This is always done when gvim is found */
+ }
+ else /* Unknown switch */
+ {
+ printf("Got unknown argument argv[%d] = %s\n", i, argv[i]);
+ print_cmd_line_help();
+ }
+ }
+}
+
+
+/*
+ * Show a few screens full of helpful information.
+ */
+ static void
+show_help(void)
+{
+ static char *(items[]) =
+ {
+"Installing .bat files\n"
+"---------------------\n"
+"The vim.bat file is written in one of the directories in $PATH.\n"
+"This makes it possible to start Vim from the command line.\n"
+"If vim.exe can be found in $PATH, the choice for vim.bat will not be\n"
+"present. It is assumed you will use the existing vim.exe.\n"
+"If vim.bat can already be found in $PATH this is probably for an old\n"
+"version of Vim (but this is not checked!). You can overwrite it.\n"
+"If no vim.bat already exists, you can select one of the directories in\n"
+"$PATH for creating the batch file, or disable creating a vim.bat file.\n"
+"\n"
+"If you choose not to create the vim.bat file, Vim can still be executed\n"
+"in other ways, but not from the command line.\n"
+"\n"
+"The same applies to choices for gvim, evim, (g)view, and (g)vimdiff.\n"
+"The first item can be used to change the path for all of them.\n"
+,
+"Creating a _vimrc file\n"
+"----------------------\n"
+"The _vimrc file is used to set options for how Vim behaves.\n"
+"The install program can create a _vimrc file with a few basic choices.\n"
+"You can edit this file later to tune your preferences.\n"
+"If you already have a _vimrc or .vimrc file it can be overwritten.\n"
+"Don't do that if you have made changes to it.\n"
+,
+"Vim features\n"
+"------------\n"
+"(this choice is only available when creating a _vimrc file)\n"
+"1. Vim can run in Vi-compatible mode. Many nice Vim features are then\n"
+" disabled. Only choose Vi-compatible if you really need full Vi\n"
+" compatibility.\n"
+"2. Vim runs in not-Vi-compatible mode. Vim is still mostly Vi compatible,\n"
+" but adds nice features like multi-level undo.\n"
+"3. Running Vim with some enhancements is useful when you want some of\n"
+" the nice Vim features, but have a slow computer and want to keep it\n"
+" really fast.\n"
+"4. Syntax highlighting shows many files in color. Not only does this look\n"
+" nice, it also makes it easier to spot errors and you can work faster.\n"
+" The other features include editing compressed files.\n"
+,
+"Windows key mapping\n"
+"-------------------\n"
+"(this choice is only available when creating a _vimrc file)\n"
+"Under MS-Windows the CTRL-C key copies text to the clipboard and CTRL-V\n"
+"pastes text from the clipboard. There are a few more keys like these.\n"
+"Unfortunately, in Vim these keys normally have another meaning.\n"
+"1. Choose to have the keys like they normally are in Vim (useful if you\n"
+" also use Vim on other systems).\n"
+"2. Choose to have the keys work like they are used on MS-Windows (useful\n"
+" if you mostly work on MS-Windows).\n"
+,
+"Mouse use\n"
+"---------\n"
+"(this choice is only available when creating a _vimrc file)\n"
+"The right mouse button can be used in two ways:\n"
+"1. The Unix way is to extend an existing selection. The popup menu is\n"
+" not available.\n"
+"2. The MS-Windows way is to show a popup menu, which allows you to\n"
+" copy/paste text, undo/redo, etc. Extending the selection can still be\n"
+" done by keeping SHIFT pressed while using the left mouse button\n"
+,
+"Edit-with-Vim context menu entry\n"
+"--------------------------------\n"
+"(this choice is only available when gvim.exe and gvimext.dll are present)\n"
+"You can associate different file types with Vim, so that you can (double)\n"
+"click on a file to edit it with Vim. This means you have to individually\n"
+"select each file type.\n"
+"An alternative is the option offered here: Install an \"Edit with Vim\"\n"
+"entry in the popup menu for the right mouse button. This means you can\n"
+"edit any file with Vim.\n"
+,
+"\"Open With...\" context menu entry\n"
+"--------------------------------\n"
+"(this choice is only available when gvim.exe is present)\n"
+"This option adds Vim to the \"Open With...\" entry in the popup menu for\n"
+"the right mouse button. This also makes it possible to edit HTML files\n"
+"directly from Internet Explorer.\n"
+,
+"Add Vim to the Start menu\n"
+"-------------------------\n"
+"In Windows 95 and later, Vim can be added to the Start menu. This will\n"
+"create a submenu with an entry for vim, gvim, evim, vimdiff, etc..\n"
+,
+"Icons on the desktop\n"
+"--------------------\n"
+"(these choices are only available when installing gvim)\n"
+"In Windows 95 and later, shortcuts (icons) can be created on the Desktop.\n"
+,
+"Create plugin directories\n"
+"-------------------------\n"
+"Plugin directories allow extending Vim by dropping a file into a directory.\n"
+"This choice allows creating them in $HOME (if you have a home directory) or\n"
+"$VIM (used for everybody on the system).\n"
+,
+NULL
+ };
+ int i;
+ int c;
+
+ rewind(stdin);
+ printf("\n");
+ for (i = 0; items[i] != NULL; ++i)
+ {
+ puts(items[i]);
+ printf("Hit Enter to continue, b (back) or q (quit help): ");
+ c = getchar();
+ rewind(stdin);
+ if (c == 'b' || c == 'B')
+ {
+ if (i == 0)
+ --i;
+ else
+ i -= 2;
+ }
+ if (c == 'q' || c == 'Q')
+ break;
+ printf("\n");
+ }
+}
+
+/*
+ * Install the choices.
+ */
+ static void
+install(void)
+{
+ int i;
+
+ /* Install the selected choices. */
+ for (i = 0; i < choice_count; ++i)
+ if (choices[i].installfunc != NULL && choices[i].active)
+ (choices[i].installfunc)(i);
+
+ /* Add some entries to the registry, if needed. */
+ if (install_popup
+ || install_openwith
+ || (need_uninstall_entry && interactive)
+ || !interactive)
+ install_registry();
+
+ /* Register gvim with OLE. */
+ if (has_gvim)
+ install_OLE_register();
+}
+
+/*
+ * request_choice
+ */
+ static void
+request_choice(void)
+{
+ int i;
+
+ printf("\n\nInstall will do for you:\n");
+ for (i = 0; i < choice_count; ++i)
+ if (choices[i].active)
+ printf("%2d %s\n", i + 1, choices[i].text);
+ printf("To change an item, enter its number\n\n");
+ printf("Enter item number, h (help), d (do it) or q (quit): ");
+}
+
+ int
+main(int argc, char **argv)
+{
+ int i;
+ char buf[BUFSIZE];
+
+ /*
+ * Run interactively if there are no command line arguments.
+ */
+ if (argc > 1)
+ interactive = 0;
+ else
+ interactive = 1;
+
+ /* Initialize this program. */
+ do_inits(argv);
+ init_homedir();
+
+ if (argc > 1 && strcmp(argv[1], "-uninstall-check") == 0)
+ {
+ /* Only check for already installed Vims. Used by NSIS installer. */
+ i = uninstall_check(1);
+
+ /* Find the value of $VIM, because NSIS isn't able to do this by
+ * itself. */
+ get_vim_env();
+
+ /* When nothing found exit quietly. If something found wait for
+ * a little while, so that the user can read the messages. */
+ if (i && _isatty(1))
+ sleep(3);
+ exit(0);
+ }
+
+ printf("This program sets up the installation of Vim "
+ VIM_VERSION_MEDIUM "\n\n");
+
+ /* Check if the user unpacked the archives properly. */
+ check_unpack();
+
+ /* Check for already installed Vims. */
+ if (interactive)
+ uninstall_check(0);
+
+ /* Find out information about the system. */
+ inspect_system();
+
+ if (interactive)
+ {
+ /* Setup all the choices. */
+ setup_choices();
+
+ /* Let the user change choices and finally install (or quit). */
+ for (;;)
+ {
+ request_choice();
+ rewind(stdin);
+ if (scanf("%99s", buf) == 1)
+ {
+ if (isdigit(buf[0]))
+ {
+ /* Change a choice. */
+ i = atoi(buf);
+ if (i > 0 && i <= choice_count && choices[i - 1].active)
+ (choices[i - 1].changefunc)(i - 1);
+ else
+ printf("\nIllegal choice\n");
+ }
+ else if (buf[0] == 'h' || buf[0] == 'H')
+ {
+ /* Help */
+ show_help();
+ }
+ else if (buf[0] == 'd' || buf[0] == 'D')
+ {
+ /* Install! */
+ install();
+ printf("\nThat finishes the installation. Happy Vimming!\n");
+ break;
+ }
+ else if (buf[0] == 'q' || buf[0] == 'Q')
+ {
+ /* Quit */
+ printf("\nExiting without anything done\n");
+ break;
+ }
+ else
+ printf("\nIllegal choice\n");
+ }
+ }
+ printf("\n");
+ myexit(0);
+ }
+ else
+ {
+ /*
+ * Run non-interactive - setup according to the command line switches
+ */
+ command_line_setup_choices(argc, argv);
+ install();
+
+ /* Avoid that the user has to hit Enter, just wait a little bit to
+ * allow reading the messages. */
+ sleep(2);
+ }
+
+ return 0;
+}
diff --git a/src/dosinst.h b/src/dosinst.h
new file mode 100644
index 0000000..59de932
--- /dev/null
+++ b/src/dosinst.h
@@ -0,0 +1,531 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+/*
+ * dosinst.h: Common code for dosinst.c and uninstal.c
+ */
+
+/* Visual Studio 2005 has 'deprecated' many of the standard CRT functions */
+#if _MSC_VER >= 1400
+# define _CRT_SECURE_NO_DEPRECATE
+# define _CRT_NONSTDC_NO_DEPRECATE
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#ifndef UNIX_LINT
+# include "vimio.h"
+# include <ctype.h>
+
+# include <direct.h>
+
+# include <windows.h>
+# include <shlobj.h>
+#endif
+
+#ifdef UNIX_LINT
+/* Running lint on Unix: Some things are missing. */
+char *searchpath(char *name);
+#endif
+
+#if defined(UNIX_LINT)
+# include <unistd.h>
+# include <errno.h>
+#endif
+
+#include "version.h"
+
+#if defined(UNIX_LINT)
+# define vim_mkdir(x, y) mkdir((char *)(x), y)
+#else
+# ifndef __BORLANDC__
+# define vim_mkdir(x, y) _mkdir((char *)(x))
+# else
+# define vim_mkdir(x, y) mkdir((char *)(x))
+# endif
+#endif
+
+#define sleep(n) Sleep((n) * 1000)
+
+/* ---------------------------------------- */
+
+
+#define BUFSIZE 512 /* long enough to hold a file name path */
+#define NUL 0
+
+#define FAIL 0
+#define OK 1
+
+#ifndef FALSE
+# define FALSE 0
+#endif
+#ifndef TRUE
+# define TRUE 1
+#endif
+
+/*
+ * Modern way of creating registry entries, also works on 64 bit windows when
+ * compiled as a 32 bit program.
+ */
+# ifndef KEY_WOW64_64KEY
+# define KEY_WOW64_64KEY 0x0100
+# endif
+# ifndef KEY_WOW64_32KEY
+# define KEY_WOW64_32KEY 0x0200
+# endif
+
+#define VIM_STARTMENU "Programs\\Vim " VIM_VERSION_SHORT
+
+int interactive; /* non-zero when running interactively */
+
+/*
+ * Call malloc() and exit when out of memory.
+ */
+ static void *
+alloc(int len)
+{
+ char *s;
+
+ s = malloc(len);
+ if (s == NULL)
+ {
+ printf("ERROR: out of memory\n");
+ exit(1);
+ }
+ return (void *)s;
+}
+
+/*
+ * The toupper() in Bcc 5.5 doesn't work, use our own implementation.
+ */
+ static int
+mytoupper(int c)
+{
+ if (c >= 'a' && c <= 'z')
+ return c - 'a' + 'A';
+ return c;
+}
+
+ static void
+myexit(int n)
+{
+ if (!interactive)
+ {
+ /* Present a prompt, otherwise error messages can't be read. */
+ printf("Press Enter to continue\n");
+ rewind(stdin);
+ (void)getchar();
+ }
+ exit(n);
+}
+
+
+typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS)(HANDLE, PBOOL);
+/*
+ * Check if this is a 64-bit OS.
+ */
+ static BOOL
+is_64bit_os(void)
+{
+#ifdef _WIN64
+ return TRUE;
+#else
+ BOOL bIsWow64 = FALSE;
+ LPFN_ISWOW64PROCESS pIsWow64Process;
+
+ pIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(
+ GetModuleHandle("kernel32"), "IsWow64Process");
+ if (pIsWow64Process != NULL)
+ pIsWow64Process(GetCurrentProcess(), &bIsWow64);
+ return bIsWow64;
+#endif
+}
+
+#ifdef __BORLANDC__
+/* Borland defines its own searchpath() in dir.h */
+# include <dir.h>
+#else
+ static char *
+searchpath(char *name)
+{
+ static char widename[2 * BUFSIZE];
+ static char location[2 * BUFSIZE + 2];
+
+ /* There appears to be a bug in FindExecutableA() on Windows NT.
+ * Use FindExecutableW() instead... */
+ MultiByteToWideChar(CP_ACP, 0, (LPCTSTR)name, -1,
+ (LPWSTR)widename, BUFSIZE);
+ if (FindExecutableW((LPCWSTR)widename, (LPCWSTR)"",
+ (LPWSTR)location) > (HINSTANCE)32)
+ {
+ WideCharToMultiByte(CP_ACP, 0, (LPWSTR)location, -1,
+ (LPSTR)widename, 2 * BUFSIZE, NULL, NULL);
+ return widename;
+ }
+ return NULL;
+}
+#endif
+
+/*
+ * Call searchpath() and save the result in allocated memory, or return NULL.
+ */
+ static char *
+searchpath_save(char *name)
+{
+ char *p;
+ char *s;
+
+ p = searchpath(name);
+ if (p == NULL)
+ return NULL;
+ s = alloc(strlen(p) + 1);
+ strcpy(s, p);
+ return s;
+}
+
+
+#ifndef CSIDL_COMMON_PROGRAMS
+# define CSIDL_COMMON_PROGRAMS 0x0017
+#endif
+#ifndef CSIDL_COMMON_DESKTOPDIRECTORY
+# define CSIDL_COMMON_DESKTOPDIRECTORY 0x0019
+#endif
+
+/*
+ * Get the path to a requested Windows shell folder.
+ *
+ * Return FAIL on error, OK on success
+ */
+ int
+get_shell_folder_path(
+ char *shell_folder_path,
+ const char *shell_folder_name)
+{
+ /*
+ * The following code was successfully built with make_mvc.mak.
+ * The resulting executable worked on Windows 95, Millennium Edition, and
+ * 2000 Professional. But it was changed after testing...
+ */
+ LPITEMIDLIST pidl = 0; /* Pointer to an Item ID list allocated below */
+ LPMALLOC pMalloc; /* Pointer to an IMalloc interface */
+ int csidl;
+ int alt_csidl = -1;
+ static int desktop_csidl = -1;
+ static int programs_csidl = -1;
+ int *pcsidl;
+ int r;
+
+ if (strcmp(shell_folder_name, "desktop") == 0)
+ {
+ pcsidl = &desktop_csidl;
+ csidl = CSIDL_COMMON_DESKTOPDIRECTORY;
+ alt_csidl = CSIDL_DESKTOP;
+ }
+ else if (strncmp(shell_folder_name, "Programs", 8) == 0)
+ {
+ pcsidl = &programs_csidl;
+ csidl = CSIDL_COMMON_PROGRAMS;
+ alt_csidl = CSIDL_PROGRAMS;
+ }
+ else
+ {
+ printf("\nERROR (internal) unrecognised shell_folder_name: \"%s\"\n\n",
+ shell_folder_name);
+ return FAIL;
+ }
+
+ /* Did this stuff before, use the same ID again. */
+ if (*pcsidl >= 0)
+ {
+ csidl = *pcsidl;
+ alt_csidl = -1;
+ }
+
+retry:
+ /* Initialize pointer to IMalloc interface */
+ if (NOERROR != SHGetMalloc(&pMalloc))
+ {
+ printf("\nERROR getting interface for shell_folder_name: \"%s\"\n\n",
+ shell_folder_name);
+ return FAIL;
+ }
+
+ /* Get an ITEMIDLIST corresponding to the folder code */
+ if (NOERROR != SHGetSpecialFolderLocation(0, csidl, &pidl))
+ {
+ if (alt_csidl < 0 || NOERROR != SHGetSpecialFolderLocation(0,
+ alt_csidl, &pidl))
+ {
+ printf("\nERROR getting ITEMIDLIST for shell_folder_name: \"%s\"\n\n",
+ shell_folder_name);
+ return FAIL;
+ }
+ csidl = alt_csidl;
+ alt_csidl = -1;
+ }
+
+ /* Translate that ITEMIDLIST to a string */
+ r = SHGetPathFromIDList(pidl, shell_folder_path);
+
+ /* Free the data associated with pidl */
+ pMalloc->lpVtbl->Free(pMalloc, pidl);
+ /* Release the IMalloc interface */
+ pMalloc->lpVtbl->Release(pMalloc);
+
+ if (!r)
+ {
+ if (alt_csidl >= 0)
+ {
+ /* We probably get here for Windows 95: the "all users"
+ * desktop/start menu entry doesn't exist. */
+ csidl = alt_csidl;
+ alt_csidl = -1;
+ goto retry;
+ }
+ printf("\nERROR translating ITEMIDLIST for shell_folder_name: \"%s\"\n\n",
+ shell_folder_name);
+ return FAIL;
+ }
+
+ /* If there is an alternative: verify we can write in this directory.
+ * This should cause a retry when the "all users" directory exists but we
+ * are a normal user and can't write there. */
+ if (alt_csidl >= 0)
+ {
+ char tbuf[BUFSIZE];
+ FILE *fd;
+
+ strcpy(tbuf, shell_folder_path);
+ strcat(tbuf, "\\vim write test");
+ fd = fopen(tbuf, "w");
+ if (fd == NULL)
+ {
+ csidl = alt_csidl;
+ alt_csidl = -1;
+ goto retry;
+ }
+ fclose(fd);
+ unlink(tbuf);
+ }
+
+ /*
+ * Keep the found csidl for next time, so that we don't have to do the
+ * write test every time.
+ */
+ if (*pcsidl < 0)
+ *pcsidl = csidl;
+
+ if (strncmp(shell_folder_name, "Programs\\", 9) == 0)
+ strcat(shell_folder_path, shell_folder_name + 8);
+
+ return OK;
+}
+
+/*
+ * List of targets. The first one (index zero) is used for the default path
+ * for the batch files.
+ */
+#define TARGET_COUNT 9
+
+struct
+{
+ char *name; /* Vim exe name (without .exe) */
+ char *batname; /* batch file name */
+ char *lnkname; /* shortcut file name */
+ char *exename; /* exe file name */
+ char *exenamearg; /* exe file name when using exearg */
+ char *exearg; /* argument for vim.exe or gvim.exe */
+ char *oldbat; /* path to existing xxx.bat or NULL */
+ char *oldexe; /* path to existing xxx.exe or NULL */
+ char batpath[BUFSIZE]; /* path of batch file to create; not
+ created when it's empty */
+} targets[TARGET_COUNT] =
+{
+ {"all", "batch files"},
+ {"vim", "vim.bat", "Vim.lnk",
+ "vim.exe", "vim.exe", ""},
+ {"gvim", "gvim.bat", "gVim.lnk",
+ "gvim.exe", "gvim.exe", ""},
+ {"evim", "evim.bat", "gVim Easy.lnk",
+ "evim.exe", "gvim.exe", "-y"},
+ {"view", "view.bat", "Vim Read-only.lnk",
+ "view.exe", "vim.exe", "-R"},
+ {"gview", "gview.bat", "gVim Read-only.lnk",
+ "gview.exe", "gvim.exe", "-R"},
+ {"vimdiff", "vimdiff.bat", "Vim Diff.lnk",
+ "vimdiff.exe","vim.exe", "-d"},
+ {"gvimdiff","gvimdiff.bat", "gVim Diff.lnk",
+ "gvimdiff.exe","gvim.exe", "-d"},
+ {"vimtutor","vimtutor.bat", "Vim tutor.lnk",
+ "vimtutor.bat", "vimtutor.bat", ""},
+};
+
+#define ICON_COUNT 3
+char *(icon_names[ICON_COUNT]) =
+ {"gVim " VIM_VERSION_SHORT,
+ "gVim Easy " VIM_VERSION_SHORT,
+ "gVim Read only " VIM_VERSION_SHORT};
+char *(icon_link_names[ICON_COUNT]) =
+ {"gVim " VIM_VERSION_SHORT ".lnk",
+ "gVim Easy " VIM_VERSION_SHORT ".lnk",
+ "gVim Read only " VIM_VERSION_SHORT ".lnk"};
+
+/* This is only used for dosinst.c. */
+#if defined(DOSINST)
+/*
+ * Run an external command and wait for it to finish.
+ */
+ static void
+run_command(char *cmd)
+{
+ char *cmd_path;
+ char cmd_buf[BUFSIZE];
+ char *p;
+
+ /* On WinNT, 'start' is a shell built-in for cmd.exe rather than an
+ * executable (start.exe) like in Win9x. */
+ cmd_path = searchpath_save("cmd.exe");
+ if (cmd_path != NULL)
+ {
+ /* There is a cmd.exe, so this might be Windows NT. If it is,
+ * we need to call cmd.exe explicitly. If it is a later OS,
+ * calling cmd.exe won't hurt if it is present.
+ * Also, "start" on NT expects a window title argument.
+ */
+ /* Replace the slashes with backslashes. */
+ while ((p = strchr(cmd_path, '/')) != NULL)
+ *p = '\\';
+ sprintf(cmd_buf, "%s /c start \"vimcmd\" /wait %s", cmd_path, cmd);
+ free(cmd_path);
+ }
+ else
+ {
+ /* No cmd.exe, just make the call and let the system handle it. */
+ sprintf(cmd_buf, "start /w %s", cmd);
+ }
+ system(cmd_buf);
+}
+#endif
+
+/*
+ * Append a backslash to "name" if there isn't one yet.
+ */
+ void
+add_pathsep(char *name)
+{
+ int len = strlen(name);
+
+ if (len > 0 && name[len - 1] != '\\' && name[len - 1] != '/')
+ strcat(name, "\\");
+}
+
+/*
+ * The normal chdir() does not change the default drive. This one does.
+ */
+/*ARGSUSED*/
+ int
+change_drive(int drive)
+{
+ char temp[3] = "-:";
+ temp[0] = (char)(drive + 'A' - 1);
+ return !SetCurrentDirectory(temp);
+}
+
+/*
+ * Change directory to "path".
+ * Return 0 for success, -1 for failure.
+ */
+ int
+mch_chdir(char *path)
+{
+ if (path[0] == NUL) /* just checking... */
+ return 0;
+ if (path[1] == ':') /* has a drive name */
+ {
+ if (change_drive(mytoupper(path[0]) - 'A' + 1))
+ return -1; /* invalid drive name */
+ path += 2;
+ }
+ if (*path == NUL) /* drive name only */
+ return 0;
+ return chdir(path); /* let the normal chdir() do the rest */
+}
+
+/*
+ * Expand the executable name into a full path name.
+ */
+#if defined(__BORLANDC__)
+
+/* Only Borland C++ has this. */
+# define my_fullpath(b, n, l) _fullpath(b, n, l)
+
+#else
+ static char *
+my_fullpath(char *buf, char *fname, int len)
+{
+ /* Only GetModuleFileName() will get the long file name path.
+ * GetFullPathName() may still use the short (FAT) name. */
+ DWORD len_read = GetModuleFileName(NULL, buf, (size_t)len);
+
+ return (len_read > 0 && len_read < (DWORD)len) ? buf : NULL;
+}
+#endif
+
+/*
+ * Remove the tail from a file or directory name.
+ * Puts a NUL on the last '/' or '\'.
+ */
+ static void
+remove_tail(char *path)
+{
+ int i;
+
+ for (i = strlen(path) - 1; i > 0; --i)
+ if (path[i] == '/' || path[i] == '\\')
+ {
+ path[i] = NUL;
+ break;
+ }
+}
+
+
+char installdir[BUFSIZE]; /* top of the installation dir, where the
+ install.exe is located, E.g.:
+ "c:\vim\vim60" */
+int runtimeidx; /* index in installdir[] where "vim60" starts */
+char *sysdrive; /* system drive or "c:\" */
+
+/*
+ * Setup for using this program.
+ * Sets "installdir[]".
+ */
+ static void
+do_inits(char **argv)
+{
+ /* Find out the full path of our executable. */
+ if (my_fullpath(installdir, argv[0], BUFSIZE) == NULL)
+ {
+ printf("ERROR: Cannot get name of executable\n");
+ myexit(1);
+ }
+ /* remove the tail, the executable name "install.exe" */
+ remove_tail(installdir);
+
+ /* change to the installdir */
+ mch_chdir(installdir);
+
+ /* Find the system drive. Only used for searching the Vim executable, not
+ * very important. */
+ sysdrive = getenv("SYSTEMDRIVE");
+ if (sysdrive == NULL || *sysdrive == NUL)
+ sysdrive = "C:\\";
+}
diff --git a/src/edit.c b/src/edit.c
new file mode 100644
index 0000000..eac4803
--- /dev/null
+++ b/src/edit.c
@@ -0,0 +1,10296 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * edit.c: functions for Insert mode
+ */
+
+#include "vim.h"
+
+#ifdef FEAT_INS_EXPAND
+/*
+ * definitions used for CTRL-X submode
+ */
+# define CTRL_X_WANT_IDENT 0x100
+
+# define CTRL_X_NORMAL 0 /* CTRL-N CTRL-P completion, default */
+# define CTRL_X_NOT_DEFINED_YET 1
+# define CTRL_X_SCROLL 2
+# define CTRL_X_WHOLE_LINE 3
+# define CTRL_X_FILES 4
+# define CTRL_X_TAGS (5 + CTRL_X_WANT_IDENT)
+# define CTRL_X_PATH_PATTERNS (6 + CTRL_X_WANT_IDENT)
+# define CTRL_X_PATH_DEFINES (7 + CTRL_X_WANT_IDENT)
+# define CTRL_X_FINISHED 8
+# define CTRL_X_DICTIONARY (9 + CTRL_X_WANT_IDENT)
+# define CTRL_X_THESAURUS (10 + CTRL_X_WANT_IDENT)
+# define CTRL_X_CMDLINE 11
+# define CTRL_X_FUNCTION 12
+# define CTRL_X_OMNI 13
+# define CTRL_X_SPELL 14
+# define CTRL_X_LOCAL_MSG 15 /* only used in "ctrl_x_msgs" */
+# define CTRL_X_EVAL 16 /* for builtin function complete() */
+
+# define CTRL_X_MSG(i) ctrl_x_msgs[(i) & ~CTRL_X_WANT_IDENT]
+# define CTRL_X_MODE_LINE_OR_EVAL(m) ((m) == CTRL_X_WHOLE_LINE || (m) == CTRL_X_EVAL)
+
+/* Message for CTRL-X mode, index is ctrl_x_mode. */
+static char *ctrl_x_msgs[] =
+{
+ N_(" Keyword completion (^N^P)"), /* CTRL_X_NORMAL, ^P/^N compl. */
+ N_(" ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"),
+ NULL, /* CTRL_X_SCROLL: depends on state */
+ N_(" Whole line completion (^L^N^P)"),
+ N_(" File name completion (^F^N^P)"),
+ N_(" Tag completion (^]^N^P)"),
+ N_(" Path pattern completion (^N^P)"),
+ N_(" Definition completion (^D^N^P)"),
+ NULL, /* CTRL_X_FINISHED */
+ N_(" Dictionary completion (^K^N^P)"),
+ N_(" Thesaurus completion (^T^N^P)"),
+ N_(" Command-line completion (^V^N^P)"),
+ N_(" User defined completion (^U^N^P)"),
+ N_(" Omni completion (^O^N^P)"),
+ N_(" Spelling suggestion (s^N^P)"),
+ N_(" Keyword Local completion (^N^P)"),
+ NULL, /* CTRL_X_EVAL doesn't use msg. */
+};
+
+static char e_hitend[] = N_("Hit end of paragraph");
+# ifdef FEAT_COMPL_FUNC
+static char e_complwin[] = N_("E839: Completion function changed window");
+static char e_compldel[] = N_("E840: Completion function deleted text");
+# endif
+
+/*
+ * Structure used to store one match for insert completion.
+ */
+typedef struct compl_S compl_T;
+struct compl_S
+{
+ compl_T *cp_next;
+ compl_T *cp_prev;
+ char_u *cp_str; /* matched text */
+ char cp_icase; /* TRUE or FALSE: ignore case */
+ char_u *(cp_text[CPT_COUNT]); /* text for the menu */
+ char_u *cp_fname; /* file containing the match, allocated when
+ * cp_flags has FREE_FNAME */
+ int cp_flags; /* ORIGINAL_TEXT, CONT_S_IPOS or FREE_FNAME */
+ int cp_number; /* sequence number */
+};
+
+# define ORIGINAL_TEXT (1) /* the original text when the expansion begun */
+# define FREE_FNAME (2)
+
+/*
+ * All the current matches are stored in a list.
+ * "compl_first_match" points to the start of the list.
+ * "compl_curr_match" points to the currently selected entry.
+ * "compl_shown_match" is different from compl_curr_match during
+ * ins_compl_get_exp().
+ */
+static compl_T *compl_first_match = NULL;
+static compl_T *compl_curr_match = NULL;
+static compl_T *compl_shown_match = NULL;
+static compl_T *compl_old_match = NULL;
+
+/* After using a cursor key <Enter> selects a match in the popup menu,
+ * otherwise it inserts a line break. */
+static int compl_enter_selects = FALSE;
+
+/* When "compl_leader" is not NULL only matches that start with this string
+ * are used. */
+static char_u *compl_leader = NULL;
+
+static int compl_get_longest = FALSE; /* put longest common string
+ in compl_leader */
+
+static int compl_no_insert = FALSE; /* FALSE: select & insert
+ TRUE: noinsert */
+static int compl_no_select = FALSE; /* FALSE: select & insert
+ TRUE: noselect */
+
+static int compl_used_match; /* Selected one of the matches. When
+ FALSE the match was edited or using
+ the longest common string. */
+
+static int compl_was_interrupted = FALSE; /* didn't finish finding
+ completions. */
+
+static int compl_restarting = FALSE; /* don't insert match */
+
+/* When the first completion is done "compl_started" is set. When it's
+ * FALSE the word to be completed must be located. */
+static int compl_started = FALSE;
+
+/* Which Ctrl-X mode are we in? */
+static int ctrl_x_mode = CTRL_X_NORMAL;
+
+/* Set when doing something for completion that may call edit() recursively,
+ * which is not allowed. */
+static int compl_busy = FALSE;
+
+static int compl_matches = 0;
+static char_u *compl_pattern = NULL;
+static int compl_direction = FORWARD;
+static int compl_shows_dir = FORWARD;
+static int compl_pending = 0; /* > 1 for postponed CTRL-N */
+static pos_T compl_startpos;
+static colnr_T compl_col = 0; /* column where the text starts
+ * that is being completed */
+static char_u *compl_orig_text = NULL; /* text as it was before
+ * completion started */
+static int compl_cont_mode = 0;
+static expand_T compl_xp;
+
+static int compl_opt_refresh_always = FALSE;
+static int compl_opt_suppress_empty = FALSE;
+
+static void ins_ctrl_x(void);
+static int has_compl_option(int dict_opt);
+static int ins_compl_accept_char(int c);
+static int ins_compl_add(char_u *str, int len, int icase, char_u *fname, char_u **cptext, int cdir, int flags, int adup);
+static void ins_compl_longest_match(compl_T *match);
+static void ins_compl_del_pum(void);
+static int pum_wanted(void);
+static void ins_compl_files(int count, char_u **files, int thesaurus, int flags, regmatch_T *regmatch, char_u *buf, int *dir);
+static char_u *find_line_end(char_u *ptr);
+static void ins_compl_free(void);
+static void ins_compl_clear(void);
+static int ins_compl_bs(void);
+static int ins_compl_need_restart(void);
+static void ins_compl_new_leader(void);
+static void ins_compl_addleader(int c);
+static int ins_compl_len(void);
+static void ins_compl_restart(void);
+static void ins_compl_set_original_text(char_u *str);
+static void ins_compl_addfrommatch(void);
+static int ins_compl_prep(int c);
+static void ins_compl_fixRedoBufForLeader(char_u *ptr_arg);
+# if defined(FEAT_COMPL_FUNC) || defined(FEAT_EVAL)
+static void ins_compl_add_list(list_T *list);
+static void ins_compl_add_dict(dict_T *dict);
+# endif
+static void ins_compl_delete(void);
+static void ins_compl_insert(int in_compl_func);
+static int ins_compl_key2dir(int c);
+static int ins_compl_pum_key(int c);
+static int ins_compl_key2count(int c);
+static int ins_complete(int c, int enable_pum);
+static void show_pum(int prev_w_wrow, int prev_w_leftcol);
+static unsigned quote_meta(char_u *dest, char_u *str, int len);
+#endif /* FEAT_INS_EXPAND */
+
+#define BACKSPACE_CHAR 1
+#define BACKSPACE_WORD 2
+#define BACKSPACE_WORD_NOT_SPACE 3
+#define BACKSPACE_LINE 4
+
+static void ins_redraw(int ready);
+static void ins_ctrl_v(void);
+#ifdef FEAT_JOB_CHANNEL
+static void init_prompt(int cmdchar_todo);
+#endif
+static void undisplay_dollar(void);
+static void insert_special(int, int, int);
+static void internal_format(int textwidth, int second_indent, int flags, int format_only, int c);
+static void check_auto_format(int);
+static void redo_literal(int c);
+static void start_arrow(pos_T *end_insert_pos);
+static void start_arrow_common(pos_T *end_insert_pos, int change);
+#ifdef FEAT_SPELL
+static void check_spell_redraw(void);
+static void spell_back_to_badword(void);
+static int spell_bad_len = 0; /* length of located bad word */
+#endif
+static void stop_insert(pos_T *end_insert_pos, int esc, int nomove);
+static int echeck_abbr(int);
+static void replace_join(int off);
+static void mb_replace_pop_ins(int cc);
+static void replace_flush(void);
+static void replace_do_bs(int limit_col);
+static int del_char_after_col(int limit_col);
+static void ins_reg(void);
+static void ins_ctrl_g(void);
+static void ins_ctrl_hat(void);
+static int ins_esc(long *count, int cmdchar, int nomove);
+#ifdef FEAT_RIGHTLEFT
+static void ins_ctrl_(void);
+#endif
+static int ins_start_select(int c);
+static void ins_insert(int replaceState);
+static void ins_ctrl_o(void);
+static void ins_shift(int c, int lastc);
+static void ins_del(void);
+static int ins_bs(int c, int mode, int *inserted_space_p);
+#ifdef FEAT_MOUSE
+static void ins_mouse(int c);
+static void ins_mousescroll(int dir);
+#endif
+#if defined(FEAT_GUI_TABLINE) || defined(PROTO)
+static void ins_tabline(int c);
+#endif
+static void ins_left(int end_change);
+static void ins_home(int c);
+static void ins_end(int c);
+static void ins_s_left(void);
+static void ins_right(int end_change);
+static void ins_s_right(void);
+static void ins_up(int startcol);
+static void ins_pageup(void);
+static void ins_down(int startcol);
+static void ins_pagedown(void);
+#ifdef FEAT_DND
+static void ins_drop(void);
+#endif
+static int ins_tab(void);
+static int ins_eol(int c);
+#ifdef FEAT_DIGRAPHS
+static int ins_digraph(void);
+#endif
+static int ins_ctrl_ey(int tc);
+#ifdef FEAT_SMARTINDENT
+static void ins_try_si(int c);
+#endif
+#if defined(FEAT_EVAL)
+static char_u *do_insert_char_pre(int c);
+#endif
+static int ins_apply_autocmds(event_T event);
+
+static colnr_T Insstart_textlen; /* length of line when insert started */
+static colnr_T Insstart_blank_vcol; /* vcol for first inserted blank */
+static int update_Insstart_orig = TRUE; /* set Insstart_orig to Insstart */
+
+static char_u *last_insert = NULL; /* the text of the previous insert,
+ K_SPECIAL and CSI are escaped */
+static int last_insert_skip; /* nr of chars in front of previous insert */
+static int new_insert_skip; /* nr of chars in front of current insert */
+static int did_restart_edit; /* "restart_edit" when calling edit() */
+
+#ifdef FEAT_CINDENT
+static int can_cindent; /* may do cindenting on this line */
+#endif
+
+static int old_indent = 0; /* for ^^D command in insert mode */
+
+#ifdef FEAT_RIGHTLEFT
+static int revins_on; /* reverse insert mode on */
+static int revins_chars; /* how much to skip after edit */
+static int revins_legal; /* was the last char 'legal'? */
+static int revins_scol; /* start column of revins session */
+#endif
+
+static int ins_need_undo; /* call u_save() before inserting a
+ char. Set when edit() is called.
+ after that arrow_used is used. */
+
+static int did_add_space = FALSE; /* auto_format() added an extra space
+ under the cursor */
+static int dont_sync_undo = FALSE; /* CTRL-G U prevents syncing undo for
+ the next left/right cursor */
+
+/*
+ * edit(): Start inserting text.
+ *
+ * "cmdchar" can be:
+ * 'i' normal insert command
+ * 'a' normal append command
+ * K_PS bracketed paste
+ * 'R' replace command
+ * 'r' "r<CR>" command: insert one <CR>. Note: count can be > 1, for redo,
+ * but still only one <CR> is inserted. The <Esc> is not used for redo.
+ * 'g' "gI" command.
+ * 'V' "gR" command for Virtual Replace mode.
+ * 'v' "gr" command for single character Virtual Replace mode.
+ *
+ * This function is not called recursively. For CTRL-O commands, it returns
+ * and lets the caller handle the Normal-mode command.
+ *
+ * Return TRUE if a CTRL-O command caused the return (insert mode pending).
+ */
+ int
+edit(
+ int cmdchar,
+ int startln, /* if set, insert at start of line */
+ long count)
+{
+ int c = 0;
+ char_u *ptr;
+ int lastc = 0;
+ int mincol;
+ static linenr_T o_lnum = 0;
+ int i;
+ int did_backspace = TRUE; /* previous char was backspace */
+#ifdef FEAT_CINDENT
+ int line_is_white = FALSE; /* line is empty before insert */
+#endif
+ linenr_T old_topline = 0; /* topline before insertion */
+#ifdef FEAT_DIFF
+ int old_topfill = -1;
+#endif
+ int inserted_space = FALSE; /* just inserted a space */
+ int replaceState = REPLACE;
+ int nomove = FALSE; /* don't move cursor on return */
+#ifdef FEAT_JOB_CHANNEL
+ int cmdchar_todo = cmdchar;
+#endif
+
+ /* Remember whether editing was restarted after CTRL-O. */
+ did_restart_edit = restart_edit;
+
+ /* sleep before redrawing, needed for "CTRL-O :" that results in an
+ * error message */
+ check_for_delay(TRUE);
+
+ /* set Insstart_orig to Insstart */
+ update_Insstart_orig = TRUE;
+
+#ifdef HAVE_SANDBOX
+ /* Don't allow inserting in the sandbox. */
+ if (sandbox != 0)
+ {
+ emsg(_(e_sandbox));
+ return FALSE;
+ }
+#endif
+ /* Don't allow changes in the buffer while editing the cmdline. The
+ * caller of getcmdline() may get confused. */
+ if (textlock != 0)
+ {
+ emsg(_(e_secure));
+ return FALSE;
+ }
+
+#ifdef FEAT_INS_EXPAND
+ /* Don't allow recursive insert mode when busy with completion. */
+ if (compl_started || compl_busy || pum_visible())
+ {
+ emsg(_(e_secure));
+ return FALSE;
+ }
+ ins_compl_clear(); /* clear stuff for CTRL-X mode */
+#endif
+
+ /*
+ * Trigger InsertEnter autocommands. Do not do this for "r<CR>" or "grx".
+ */
+ if (cmdchar != 'r' && cmdchar != 'v')
+ {
+ pos_T save_cursor = curwin->w_cursor;
+
+#ifdef FEAT_EVAL
+ if (cmdchar == 'R')
+ ptr = (char_u *)"r";
+ else if (cmdchar == 'V')
+ ptr = (char_u *)"v";
+ else
+ ptr = (char_u *)"i";
+ set_vim_var_string(VV_INSERTMODE, ptr, 1);
+ set_vim_var_string(VV_CHAR, NULL, -1); /* clear v:char */
+#endif
+ ins_apply_autocmds(EVENT_INSERTENTER);
+
+ /* Make sure the cursor didn't move. Do call check_cursor_col() in
+ * case the text was modified. Since Insert mode was not started yet
+ * a call to check_cursor_col() may move the cursor, especially with
+ * the "A" command, thus set State to avoid that. Also check that the
+ * line number is still valid (lines may have been deleted).
+ * Do not restore if v:char was set to a non-empty string. */
+ if (!EQUAL_POS(curwin->w_cursor, save_cursor)
+#ifdef FEAT_EVAL
+ && *get_vim_var_str(VV_CHAR) == NUL
+#endif
+ && save_cursor.lnum <= curbuf->b_ml.ml_line_count)
+ {
+ int save_state = State;
+
+ curwin->w_cursor = save_cursor;
+ State = INSERT;
+ check_cursor_col();
+ State = save_state;
+ }
+ }
+
+#ifdef FEAT_CONCEAL
+ /* Check if the cursor line needs redrawing before changing State. If
+ * 'concealcursor' is "n" it needs to be redrawn without concealing. */
+ conceal_check_cursor_line();
+#endif
+
+#ifdef FEAT_MOUSE
+ /*
+ * When doing a paste with the middle mouse button, Insstart is set to
+ * where the paste started.
+ */
+ if (where_paste_started.lnum != 0)
+ Insstart = where_paste_started;
+ else
+#endif
+ {
+ Insstart = curwin->w_cursor;
+ if (startln)
+ Insstart.col = 0;
+ }
+ Insstart_textlen = (colnr_T)linetabsize(ml_get_curline());
+ Insstart_blank_vcol = MAXCOL;
+ if (!did_ai)
+ ai_col = 0;
+
+ if (cmdchar != NUL && restart_edit == 0)
+ {
+ ResetRedobuff();
+ AppendNumberToRedobuff(count);
+ if (cmdchar == 'V' || cmdchar == 'v')
+ {
+ /* "gR" or "gr" command */
+ AppendCharToRedobuff('g');
+ AppendCharToRedobuff((cmdchar == 'v') ? 'r' : 'R');
+ }
+ else
+ {
+ if (cmdchar == K_PS)
+ AppendCharToRedobuff('a');
+ else
+ AppendCharToRedobuff(cmdchar);
+ if (cmdchar == 'g') /* "gI" command */
+ AppendCharToRedobuff('I');
+ else if (cmdchar == 'r') /* "r<CR>" command */
+ count = 1; /* insert only one <CR> */
+ }
+ }
+
+ if (cmdchar == 'R')
+ {
+#ifdef FEAT_FKMAP
+ if (p_fkmap && p_ri)
+ {
+ beep_flush();
+ emsg(farsi_text_3); /* encoded in Farsi */
+ State = INSERT;
+ }
+ else
+#endif
+ State = REPLACE;
+ }
+ else if (cmdchar == 'V' || cmdchar == 'v')
+ {
+ State = VREPLACE;
+ replaceState = VREPLACE;
+ orig_line_count = curbuf->b_ml.ml_line_count;
+ vr_lines_changed = 1;
+ }
+ else
+ State = INSERT;
+
+ stop_insert_mode = FALSE;
+
+ /*
+ * Need to recompute the cursor position, it might move when the cursor is
+ * on a TAB or special character.
+ */
+ curs_columns(TRUE);
+
+ /*
+ * Enable langmap or IME, indicated by 'iminsert'.
+ * Note that IME may enabled/disabled without us noticing here, thus the
+ * 'iminsert' value may not reflect what is actually used. It is updated
+ * when hitting <Esc>.
+ */
+ if (curbuf->b_p_iminsert == B_IMODE_LMAP)
+ State |= LANGMAP;
+#ifdef HAVE_INPUT_METHOD
+ im_set_active(curbuf->b_p_iminsert == B_IMODE_IM);
+#endif
+
+#ifdef FEAT_MOUSE
+ setmouse();
+#endif
+#ifdef FEAT_CMDL_INFO
+ clear_showcmd();
+#endif
+#ifdef FEAT_RIGHTLEFT
+ /* there is no reverse replace mode */
+ revins_on = (State == INSERT && p_ri);
+ if (revins_on)
+ undisplay_dollar();
+ revins_chars = 0;
+ revins_legal = 0;
+ revins_scol = -1;
+#endif
+ if (!p_ek)
+ /* Disable bracketed paste mode, we won't recognize the escape
+ * sequences. */
+ out_str(T_BD);
+
+ /*
+ * Handle restarting Insert mode.
+ * Don't do this for "CTRL-O ." (repeat an insert): In that case we get
+ * here with something in the stuff buffer.
+ */
+ if (restart_edit != 0 && stuff_empty())
+ {
+#ifdef FEAT_MOUSE
+ /*
+ * After a paste we consider text typed to be part of the insert for
+ * the pasted text. You can backspace over the pasted text too.
+ */
+ if (where_paste_started.lnum)
+ arrow_used = FALSE;
+ else
+#endif
+ arrow_used = TRUE;
+ restart_edit = 0;
+
+ /*
+ * If the cursor was after the end-of-line before the CTRL-O and it is
+ * now at the end-of-line, put it after the end-of-line (this is not
+ * correct in very rare cases).
+ * Also do this if curswant is greater than the current virtual
+ * column. Eg after "^O$" or "^O80|".
+ */
+ validate_virtcol();
+ update_curswant();
+ if (((ins_at_eol && curwin->w_cursor.lnum == o_lnum)
+ || curwin->w_curswant > curwin->w_virtcol)
+ && *(ptr = ml_get_curline() + curwin->w_cursor.col) != NUL)
+ {
+ if (ptr[1] == NUL)
+ ++curwin->w_cursor.col;
+ else if (has_mbyte)
+ {
+ i = (*mb_ptr2len)(ptr);
+ if (ptr[i] == NUL)
+ curwin->w_cursor.col += i;
+ }
+ }
+ ins_at_eol = FALSE;
+ }
+ else
+ arrow_used = FALSE;
+
+ /* we are in insert mode now, don't need to start it anymore */
+ need_start_insertmode = FALSE;
+
+ /* Need to save the line for undo before inserting the first char. */
+ ins_need_undo = TRUE;
+
+#ifdef FEAT_MOUSE
+ where_paste_started.lnum = 0;
+#endif
+#ifdef FEAT_CINDENT
+ can_cindent = TRUE;
+#endif
+#ifdef FEAT_FOLDING
+ /* The cursor line is not in a closed fold, unless 'insertmode' is set or
+ * restarting. */
+ if (!p_im && did_restart_edit == 0)
+ foldOpenCursor();
+#endif
+
+ /*
+ * If 'showmode' is set, show the current (insert/replace/..) mode.
+ * A warning message for changing a readonly file is given here, before
+ * actually changing anything. It's put after the mode, if any.
+ */
+ i = 0;
+ if (p_smd && msg_silent == 0)
+ i = showmode();
+
+ if (!p_im && did_restart_edit == 0)
+ change_warning(i == 0 ? 0 : i + 1);
+
+#ifdef CURSOR_SHAPE
+ ui_cursor_shape(); /* may show different cursor shape */
+#endif
+#ifdef FEAT_DIGRAPHS
+ do_digraph(-1); /* clear digraphs */
+#endif
+
+ /*
+ * Get the current length of the redo buffer, those characters have to be
+ * skipped if we want to get to the inserted characters.
+ */
+ ptr = get_inserted();
+ if (ptr == NULL)
+ new_insert_skip = 0;
+ else
+ {
+ new_insert_skip = (int)STRLEN(ptr);
+ vim_free(ptr);
+ }
+
+ old_indent = 0;
+
+ /*
+ * Main loop in Insert mode: repeat until Insert mode is left.
+ */
+ for (;;)
+ {
+#ifdef FEAT_RIGHTLEFT
+ if (!revins_legal)
+ revins_scol = -1; /* reset on illegal motions */
+ else
+ revins_legal = 0;
+#endif
+ if (arrow_used) /* don't repeat insert when arrow key used */
+ count = 0;
+
+ if (update_Insstart_orig)
+ Insstart_orig = Insstart;
+
+ if (stop_insert_mode
+#ifdef FEAT_INS_EXPAND
+ && !pum_visible()
+#endif
+ )
+ {
+ /* ":stopinsert" used or 'insertmode' reset */
+ count = 0;
+ goto doESCkey;
+ }
+
+ /* set curwin->w_curswant for next K_DOWN or K_UP */
+ if (!arrow_used)
+ curwin->w_set_curswant = TRUE;
+
+ /* If there is no typeahead may check for timestamps (e.g., for when a
+ * menu invoked a shell command). */
+ if (stuff_empty())
+ {
+ did_check_timestamps = FALSE;
+ if (need_check_timestamps)
+ check_timestamps(FALSE);
+ }
+
+ /*
+ * When emsg() was called msg_scroll will have been set.
+ */
+ msg_scroll = FALSE;
+
+#ifdef FEAT_GUI
+ /* When 'mousefocus' is set a mouse movement may have taken us to
+ * another window. "need_mouse_correct" may then be set because of an
+ * autocommand. */
+ if (need_mouse_correct)
+ gui_mouse_correct();
+#endif
+
+#ifdef FEAT_FOLDING
+ /* Open fold at the cursor line, according to 'foldopen'. */
+ if (fdo_flags & FDO_INSERT)
+ foldOpenCursor();
+ /* Close folds where the cursor isn't, according to 'foldclose' */
+ if (!char_avail())
+ foldCheckClose();
+#endif
+
+#ifdef FEAT_JOB_CHANNEL
+ if (bt_prompt(curbuf))
+ {
+ init_prompt(cmdchar_todo);
+ cmdchar_todo = NUL;
+ }
+#endif
+
+ /*
+ * If we inserted a character at the last position of the last line in
+ * the window, scroll the window one line up. This avoids an extra
+ * redraw.
+ * This is detected when the cursor column is smaller after inserting
+ * something.
+ * Don't do this when the topline changed already, it has
+ * already been adjusted (by insertchar() calling open_line())).
+ */
+ if (curbuf->b_mod_set
+ && curwin->w_p_wrap
+ && !did_backspace
+ && curwin->w_topline == old_topline
+#ifdef FEAT_DIFF
+ && curwin->w_topfill == old_topfill
+#endif
+ )
+ {
+ mincol = curwin->w_wcol;
+ validate_cursor_col();
+
+ if (
+#ifdef FEAT_VARTABS
+ (int)curwin->w_wcol < mincol - tabstop_at(
+ get_nolist_virtcol(), curbuf->b_p_ts,
+ curbuf->b_p_vts_array)
+#else
+ (int)curwin->w_wcol < mincol - curbuf->b_p_ts
+#endif
+ && curwin->w_wrow == W_WINROW(curwin)
+ + curwin->w_height - 1 - get_scrolloff_value()
+ && (curwin->w_cursor.lnum != curwin->w_topline
+#ifdef FEAT_DIFF
+ || curwin->w_topfill > 0
+#endif
+ ))
+ {
+#ifdef FEAT_DIFF
+ if (curwin->w_topfill > 0)
+ --curwin->w_topfill;
+ else
+#endif
+#ifdef FEAT_FOLDING
+ if (hasFolding(curwin->w_topline, NULL, &old_topline))
+ set_topline(curwin, old_topline + 1);
+ else
+#endif
+ set_topline(curwin, curwin->w_topline + 1);
+ }
+ }
+
+ /* May need to adjust w_topline to show the cursor. */
+ update_topline();
+
+ did_backspace = FALSE;
+
+ validate_cursor(); /* may set must_redraw */
+
+ /*
+ * Redraw the display when no characters are waiting.
+ * Also shows mode, ruler and positions cursor.
+ */
+ ins_redraw(TRUE);
+
+ if (curwin->w_p_scb)
+ do_check_scrollbind(TRUE);
+
+ if (curwin->w_p_crb)
+ do_check_cursorbind();
+ update_curswant();
+ old_topline = curwin->w_topline;
+#ifdef FEAT_DIFF
+ old_topfill = curwin->w_topfill;
+#endif
+
+#ifdef USE_ON_FLY_SCROLL
+ dont_scroll = FALSE; /* allow scrolling here */
+#endif
+
+ /*
+ * Get a character for Insert mode. Ignore K_IGNORE and K_NOP.
+ */
+ if (c != K_CURSORHOLD)
+ lastc = c; /* remember the previous char for CTRL-D */
+
+ /* After using CTRL-G U the next cursor key will not break undo. */
+ if (dont_sync_undo == MAYBE)
+ dont_sync_undo = TRUE;
+ else
+ dont_sync_undo = FALSE;
+ if (cmdchar == K_PS)
+ /* Got here from normal mode when bracketed paste started. */
+ c = K_PS;
+ else
+ do
+ {
+ c = safe_vgetc();
+
+ if (stop_insert_mode)
+ {
+ // Insert mode ended, possibly from a callback.
+ count = 0;
+ nomove = TRUE;
+ goto doESCkey;
+ }
+ } while (c == K_IGNORE || c == K_NOP);
+
+ /* Don't want K_CURSORHOLD for the second key, e.g., after CTRL-V. */
+ did_cursorhold = TRUE;
+
+#ifdef FEAT_RIGHTLEFT
+ if (p_hkmap && KeyTyped)
+ c = hkmap(c); /* Hebrew mode mapping */
+#endif
+#ifdef FEAT_FKMAP
+ if (p_fkmap && KeyTyped)
+ c = fkmap(c); /* Farsi mode mapping */
+#endif
+
+#ifdef FEAT_INS_EXPAND
+ /*
+ * Special handling of keys while the popup menu is visible or wanted
+ * and the cursor is still in the completed word. Only when there is
+ * a match, skip this when no matches were found.
+ */
+ if (compl_started
+ && pum_wanted()
+ && curwin->w_cursor.col >= compl_col
+ && (compl_shown_match == NULL
+ || compl_shown_match != compl_shown_match->cp_next))
+ {
+ /* BS: Delete one character from "compl_leader". */
+ if ((c == K_BS || c == Ctrl_H)
+ && curwin->w_cursor.col > compl_col
+ && (c = ins_compl_bs()) == NUL)
+ continue;
+
+ /* When no match was selected or it was edited. */
+ if (!compl_used_match)
+ {
+ /* CTRL-L: Add one character from the current match to
+ * "compl_leader". Except when at the original match and
+ * there is nothing to add, CTRL-L works like CTRL-P then. */
+ if (c == Ctrl_L
+ && (!CTRL_X_MODE_LINE_OR_EVAL(ctrl_x_mode)
+ || (int)STRLEN(compl_shown_match->cp_str)
+ > curwin->w_cursor.col - compl_col))
+ {
+ ins_compl_addfrommatch();
+ continue;
+ }
+
+ /* A non-white character that fits in with the current
+ * completion: Add to "compl_leader". */
+ if (ins_compl_accept_char(c))
+ {
+#if defined(FEAT_EVAL)
+ /* Trigger InsertCharPre. */
+ char_u *str = do_insert_char_pre(c);
+ char_u *p;
+
+ if (str != NULL)
+ {
+ for (p = str; *p != NUL; MB_PTR_ADV(p))
+ ins_compl_addleader(PTR2CHAR(p));
+ vim_free(str);
+ }
+ else
+#endif
+ ins_compl_addleader(c);
+ continue;
+ }
+
+ /* Pressing CTRL-Y selects the current match. When
+ * compl_enter_selects is set the Enter key does the same. */
+ if ((c == Ctrl_Y || (compl_enter_selects
+ && (c == CAR || c == K_KENTER || c == NL)))
+ && stop_arrow() == OK)
+ {
+ ins_compl_delete();
+ ins_compl_insert(FALSE);
+ }
+ }
+ }
+
+ /* Prepare for or stop CTRL-X mode. This doesn't do completion, but
+ * it does fix up the text when finishing completion. */
+ compl_get_longest = FALSE;
+ if (ins_compl_prep(c))
+ continue;
+#endif
+
+ /* CTRL-\ CTRL-N goes to Normal mode,
+ * CTRL-\ CTRL-G goes to mode selected with 'insertmode',
+ * CTRL-\ CTRL-O is like CTRL-O but without moving the cursor. */
+ if (c == Ctrl_BSL)
+ {
+ /* may need to redraw when no more chars available now */
+ ins_redraw(FALSE);
+ ++no_mapping;
+ ++allow_keys;
+ c = plain_vgetc();
+ --no_mapping;
+ --allow_keys;
+ if (c != Ctrl_N && c != Ctrl_G && c != Ctrl_O)
+ {
+ /* it's something else */
+ vungetc(c);
+ c = Ctrl_BSL;
+ }
+ else if (c == Ctrl_G && p_im)
+ continue;
+ else
+ {
+ if (c == Ctrl_O)
+ {
+ ins_ctrl_o();
+ ins_at_eol = FALSE; /* cursor keeps its column */
+ nomove = TRUE;
+ }
+ count = 0;
+ goto doESCkey;
+ }
+ }
+
+#ifdef FEAT_DIGRAPHS
+ c = do_digraph(c);
+#endif
+
+#ifdef FEAT_INS_EXPAND
+ if ((c == Ctrl_V || c == Ctrl_Q) && ctrl_x_mode == CTRL_X_CMDLINE)
+ goto docomplete;
+#endif
+ if (c == Ctrl_V || c == Ctrl_Q)
+ {
+ ins_ctrl_v();
+ c = Ctrl_V; /* pretend CTRL-V is last typed character */
+ continue;
+ }
+
+#ifdef FEAT_CINDENT
+ if (cindent_on()
+# ifdef FEAT_INS_EXPAND
+ && ctrl_x_mode == 0
+# endif
+ )
+ {
+ /* A key name preceded by a bang means this key is not to be
+ * inserted. Skip ahead to the re-indenting below.
+ * A key name preceded by a star means that indenting has to be
+ * done before inserting the key. */
+ line_is_white = inindent(0);
+ if (in_cinkeys(c, '!', line_is_white))
+ goto force_cindent;
+ if (can_cindent && in_cinkeys(c, '*', line_is_white)
+ && stop_arrow() == OK)
+ do_c_expr_indent();
+ }
+#endif
+
+#ifdef FEAT_RIGHTLEFT
+ if (curwin->w_p_rl)
+ switch (c)
+ {
+ case K_LEFT: c = K_RIGHT; break;
+ case K_S_LEFT: c = K_S_RIGHT; break;
+ case K_C_LEFT: c = K_C_RIGHT; break;
+ case K_RIGHT: c = K_LEFT; break;
+ case K_S_RIGHT: c = K_S_LEFT; break;
+ case K_C_RIGHT: c = K_C_LEFT; break;
+ }
+#endif
+
+ /*
+ * If 'keymodel' contains "startsel", may start selection. If it
+ * does, a CTRL-O and c will be stuffed, we need to get these
+ * characters.
+ */
+ if (ins_start_select(c))
+ continue;
+
+ /*
+ * The big switch to handle a character in insert mode.
+ */
+ switch (c)
+ {
+ case ESC: /* End input mode */
+ if (echeck_abbr(ESC + ABBR_OFF))
+ break;
+ /* FALLTHROUGH */
+
+ case Ctrl_C: /* End input mode */
+#ifdef FEAT_CMDWIN
+ if (c == Ctrl_C && cmdwin_type != 0)
+ {
+ /* Close the cmdline window. */
+ cmdwin_result = K_IGNORE;
+ got_int = FALSE; /* don't stop executing autocommands et al. */
+ nomove = TRUE;
+ goto doESCkey;
+ }
+#endif
+#ifdef FEAT_JOB_CHANNEL
+ if (c == Ctrl_C && bt_prompt(curbuf))
+ {
+ if (invoke_prompt_interrupt())
+ {
+ if (!bt_prompt(curbuf))
+ // buffer changed to a non-prompt buffer, get out of
+ // Insert mode
+ goto doESCkey;
+ break;
+ }
+ }
+#endif
+
+#ifdef UNIX
+do_intr:
+#endif
+ /* when 'insertmode' set, and not halfway a mapping, don't leave
+ * Insert mode */
+ if (goto_im())
+ {
+ if (got_int)
+ {
+ (void)vgetc(); /* flush all buffers */
+ got_int = FALSE;
+ }
+ else
+ vim_beep(BO_IM);
+ break;
+ }
+doESCkey:
+ /*
+ * This is the ONLY return from edit()!
+ */
+ /* Always update o_lnum, so that a "CTRL-O ." that adds a line
+ * still puts the cursor back after the inserted text. */
+ if (ins_at_eol && gchar_cursor() == NUL)
+ o_lnum = curwin->w_cursor.lnum;
+
+ if (ins_esc(&count, cmdchar, nomove))
+ {
+ // When CTRL-C was typed got_int will be set, with the result
+ // that the autocommands won't be executed. When mapped got_int
+ // is not set, but let's keep the behavior the same.
+ if (cmdchar != 'r' && cmdchar != 'v' && c != Ctrl_C)
+ ins_apply_autocmds(EVENT_INSERTLEAVE);
+ did_cursorhold = FALSE;
+ return (c == Ctrl_O);
+ }
+ continue;
+
+ case Ctrl_Z: /* suspend when 'insertmode' set */
+ if (!p_im)
+ goto normalchar; /* insert CTRL-Z as normal char */
+ do_cmdline_cmd((char_u *)"stop");
+#ifdef CURSOR_SHAPE
+ ui_cursor_shape(); /* may need to update cursor shape */
+#endif
+ continue;
+
+ case Ctrl_O: /* execute one command */
+#ifdef FEAT_COMPL_FUNC
+ if (ctrl_x_mode == CTRL_X_OMNI)
+ goto docomplete;
+#endif
+ if (echeck_abbr(Ctrl_O + ABBR_OFF))
+ break;
+ ins_ctrl_o();
+
+ /* don't move the cursor left when 'virtualedit' has "onemore". */
+ if (ve_flags & VE_ONEMORE)
+ {
+ ins_at_eol = FALSE;
+ nomove = TRUE;
+ }
+ count = 0;
+ goto doESCkey;
+
+ case K_INS: /* toggle insert/replace mode */
+ case K_KINS:
+ ins_insert(replaceState);
+ break;
+
+ case K_SELECT: /* end of Select mode mapping - ignore */
+ break;
+
+ case K_HELP: /* Help key works like <ESC> <Help> */
+ case K_F1:
+ case K_XF1:
+ stuffcharReadbuff(K_HELP);
+ if (p_im)
+ need_start_insertmode = TRUE;
+ goto doESCkey;
+
+#ifdef FEAT_NETBEANS_INTG
+ case K_F21: /* NetBeans command */
+ ++no_mapping; /* don't map the next key hits */
+ i = plain_vgetc();
+ --no_mapping;
+ netbeans_keycommand(i);
+ break;
+#endif
+
+ case K_ZERO: /* Insert the previously inserted text. */
+ case NUL:
+ case Ctrl_A:
+ /* For ^@ the trailing ESC will end the insert, unless there is an
+ * error. */
+ if (stuff_inserted(NUL, 1L, (c == Ctrl_A)) == FAIL
+ && c != Ctrl_A && !p_im)
+ goto doESCkey; /* quit insert mode */
+ inserted_space = FALSE;
+ break;
+
+ case Ctrl_R: /* insert the contents of a register */
+ ins_reg();
+ auto_format(FALSE, TRUE);
+ inserted_space = FALSE;
+ break;
+
+ case Ctrl_G: /* commands starting with CTRL-G */
+ ins_ctrl_g();
+ break;
+
+ case Ctrl_HAT: /* switch input mode and/or langmap */
+ ins_ctrl_hat();
+ break;
+
+#ifdef FEAT_RIGHTLEFT
+ case Ctrl__: /* switch between languages */
+ if (!p_ari)
+ goto normalchar;
+ ins_ctrl_();
+ break;
+#endif
+
+ case Ctrl_D: /* Make indent one shiftwidth smaller. */
+#if defined(FEAT_INS_EXPAND) && defined(FEAT_FIND_ID)
+ if (ctrl_x_mode == CTRL_X_PATH_DEFINES)
+ goto docomplete;
+#endif
+ /* FALLTHROUGH */
+
+ case Ctrl_T: /* Make indent one shiftwidth greater. */
+# ifdef FEAT_INS_EXPAND
+ if (c == Ctrl_T && ctrl_x_mode == CTRL_X_THESAURUS)
+ {
+ if (has_compl_option(FALSE))
+ goto docomplete;
+ break;
+ }
+# endif
+ ins_shift(c, lastc);
+ auto_format(FALSE, TRUE);
+ inserted_space = FALSE;
+ break;
+
+ case K_DEL: /* delete character under the cursor */
+ case K_KDEL:
+ ins_del();
+ auto_format(FALSE, TRUE);
+ break;
+
+ case K_BS: /* delete character before the cursor */
+ case Ctrl_H:
+ did_backspace = ins_bs(c, BACKSPACE_CHAR, &inserted_space);
+ auto_format(FALSE, TRUE);
+ break;
+
+ case Ctrl_W: /* delete word before the cursor */
+#ifdef FEAT_JOB_CHANNEL
+ if (bt_prompt(curbuf) && (mod_mask & MOD_MASK_SHIFT) == 0)
+ {
+ // In a prompt window CTRL-W is used for window commands.
+ // Use Shift-CTRL-W to delete a word.
+ stuffcharReadbuff(Ctrl_W);
+ restart_edit = 'A';
+ nomove = TRUE;
+ count = 0;
+ goto doESCkey;
+ }
+#endif
+ did_backspace = ins_bs(c, BACKSPACE_WORD, &inserted_space);
+ auto_format(FALSE, TRUE);
+ break;
+
+ case Ctrl_U: /* delete all inserted text in current line */
+# ifdef FEAT_COMPL_FUNC
+ /* CTRL-X CTRL-U completes with 'completefunc'. */
+ if (ctrl_x_mode == CTRL_X_FUNCTION)
+ goto docomplete;
+# endif
+ did_backspace = ins_bs(c, BACKSPACE_LINE, &inserted_space);
+ auto_format(FALSE, TRUE);
+ inserted_space = FALSE;
+ break;
+
+#ifdef FEAT_MOUSE
+ case K_LEFTMOUSE: /* mouse keys */
+ case K_LEFTMOUSE_NM:
+ case K_LEFTDRAG:
+ case K_LEFTRELEASE:
+ case K_LEFTRELEASE_NM:
+ case K_MOUSEMOVE:
+ case K_MIDDLEMOUSE:
+ case K_MIDDLEDRAG:
+ case K_MIDDLERELEASE:
+ case K_RIGHTMOUSE:
+ case K_RIGHTDRAG:
+ case K_RIGHTRELEASE:
+ case K_X1MOUSE:
+ case K_X1DRAG:
+ case K_X1RELEASE:
+ case K_X2MOUSE:
+ case K_X2DRAG:
+ case K_X2RELEASE:
+ ins_mouse(c);
+ break;
+
+ case K_MOUSEDOWN: /* Default action for scroll wheel up: scroll up */
+ ins_mousescroll(MSCR_DOWN);
+ break;
+
+ case K_MOUSEUP: /* Default action for scroll wheel down: scroll down */
+ ins_mousescroll(MSCR_UP);
+ break;
+
+ case K_MOUSELEFT: /* Scroll wheel left */
+ ins_mousescroll(MSCR_LEFT);
+ break;
+
+ case K_MOUSERIGHT: /* Scroll wheel right */
+ ins_mousescroll(MSCR_RIGHT);
+ break;
+#endif
+ case K_PS:
+ bracketed_paste(PASTE_INSERT, FALSE, NULL);
+ if (cmdchar == K_PS)
+ /* invoked from normal mode, bail out */
+ goto doESCkey;
+ break;
+ case K_PE:
+ /* Got K_PE without K_PS, ignore. */
+ break;
+
+#ifdef FEAT_GUI_TABLINE
+ case K_TABLINE:
+ case K_TABMENU:
+ ins_tabline(c);
+ break;
+#endif
+
+ case K_IGNORE: /* Something mapped to nothing */
+ break;
+
+ case K_CURSORHOLD: /* Didn't type something for a while. */
+ ins_apply_autocmds(EVENT_CURSORHOLDI);
+ did_cursorhold = TRUE;
+ break;
+
+#ifdef FEAT_GUI_W32
+ /* On Win32 ignore <M-F4>, we get it when closing the window was
+ * cancelled. */
+ case K_F4:
+ if (mod_mask != MOD_MASK_ALT)
+ goto normalchar;
+ break;
+#endif
+
+#ifdef FEAT_GUI
+ case K_VER_SCROLLBAR:
+ ins_scroll();
+ break;
+
+ case K_HOR_SCROLLBAR:
+ ins_horscroll();
+ break;
+#endif
+
+ case K_HOME: /* <Home> */
+ case K_KHOME:
+ case K_S_HOME:
+ case K_C_HOME:
+ ins_home(c);
+ break;
+
+ case K_END: /* <End> */
+ case K_KEND:
+ case K_S_END:
+ case K_C_END:
+ ins_end(c);
+ break;
+
+ case K_LEFT: /* <Left> */
+ if (mod_mask & (MOD_MASK_SHIFT|MOD_MASK_CTRL))
+ ins_s_left();
+ else
+ ins_left(dont_sync_undo == FALSE);
+ break;
+
+ case K_S_LEFT: /* <S-Left> */
+ case K_C_LEFT:
+ ins_s_left();
+ break;
+
+ case K_RIGHT: /* <Right> */
+ if (mod_mask & (MOD_MASK_SHIFT|MOD_MASK_CTRL))
+ ins_s_right();
+ else
+ ins_right(dont_sync_undo == FALSE);
+ break;
+
+ case K_S_RIGHT: /* <S-Right> */
+ case K_C_RIGHT:
+ ins_s_right();
+ break;
+
+ case K_UP: /* <Up> */
+#ifdef FEAT_INS_EXPAND
+ if (pum_visible())
+ goto docomplete;
+#endif
+ if (mod_mask & MOD_MASK_SHIFT)
+ ins_pageup();
+ else
+ ins_up(FALSE);
+ break;
+
+ case K_S_UP: /* <S-Up> */
+ case K_PAGEUP:
+ case K_KPAGEUP:
+#ifdef FEAT_INS_EXPAND
+ if (pum_visible())
+ goto docomplete;
+#endif
+ ins_pageup();
+ break;
+
+ case K_DOWN: /* <Down> */
+#ifdef FEAT_INS_EXPAND
+ if (pum_visible())
+ goto docomplete;
+#endif
+ if (mod_mask & MOD_MASK_SHIFT)
+ ins_pagedown();
+ else
+ ins_down(FALSE);
+ break;
+
+ case K_S_DOWN: /* <S-Down> */
+ case K_PAGEDOWN:
+ case K_KPAGEDOWN:
+#ifdef FEAT_INS_EXPAND
+ if (pum_visible())
+ goto docomplete;
+#endif
+ ins_pagedown();
+ break;
+
+#ifdef FEAT_DND
+ case K_DROP: /* drag-n-drop event */
+ ins_drop();
+ break;
+#endif
+
+ case K_S_TAB: /* When not mapped, use like a normal TAB */
+ c = TAB;
+ /* FALLTHROUGH */
+
+ case TAB: /* TAB or Complete patterns along path */
+#if defined(FEAT_INS_EXPAND) && defined(FEAT_FIND_ID)
+ if (ctrl_x_mode == CTRL_X_PATH_PATTERNS)
+ goto docomplete;
+#endif
+ inserted_space = FALSE;
+ if (ins_tab())
+ goto normalchar; /* insert TAB as a normal char */
+ auto_format(FALSE, TRUE);
+ break;
+
+ case K_KENTER: /* <Enter> */
+ c = CAR;
+ /* FALLTHROUGH */
+ case CAR:
+ case NL:
+#if defined(FEAT_QUICKFIX)
+ /* In a quickfix window a <CR> jumps to the error under the
+ * cursor. */
+ if (bt_quickfix(curbuf) && c == CAR)
+ {
+ if (curwin->w_llist_ref == NULL) /* quickfix window */
+ do_cmdline_cmd((char_u *)".cc");
+ else /* location list window */
+ do_cmdline_cmd((char_u *)".ll");
+ break;
+ }
+#endif
+#ifdef FEAT_CMDWIN
+ if (cmdwin_type != 0)
+ {
+ /* Execute the command in the cmdline window. */
+ cmdwin_result = CAR;
+ goto doESCkey;
+ }
+#endif
+#ifdef FEAT_JOB_CHANNEL
+ if (bt_prompt(curbuf))
+ {
+ invoke_prompt_callback();
+ if (!bt_prompt(curbuf))
+ // buffer changed to a non-prompt buffer, get out of
+ // Insert mode
+ goto doESCkey;
+ break;
+ }
+#endif
+ if (ins_eol(c) == FAIL && !p_im)
+ goto doESCkey; /* out of memory */
+ auto_format(FALSE, FALSE);
+ inserted_space = FALSE;
+ break;
+
+#if defined(FEAT_DIGRAPHS) || defined(FEAT_INS_EXPAND)
+ case Ctrl_K: /* digraph or keyword completion */
+# ifdef FEAT_INS_EXPAND
+ if (ctrl_x_mode == CTRL_X_DICTIONARY)
+ {
+ if (has_compl_option(TRUE))
+ goto docomplete;
+ break;
+ }
+# endif
+# ifdef FEAT_DIGRAPHS
+ c = ins_digraph();
+ if (c == NUL)
+ break;
+# endif
+ goto normalchar;
+#endif
+
+#ifdef FEAT_INS_EXPAND
+ case Ctrl_X: /* Enter CTRL-X mode */
+ ins_ctrl_x();
+ break;
+
+ case Ctrl_RSB: /* Tag name completion after ^X */
+ if (ctrl_x_mode != CTRL_X_TAGS)
+ goto normalchar;
+ goto docomplete;
+
+ case Ctrl_F: /* File name completion after ^X */
+ if (ctrl_x_mode != CTRL_X_FILES)
+ goto normalchar;
+ goto docomplete;
+
+ case 's': /* Spelling completion after ^X */
+ case Ctrl_S:
+ if (ctrl_x_mode != CTRL_X_SPELL)
+ goto normalchar;
+ goto docomplete;
+#endif
+
+ case Ctrl_L: /* Whole line completion after ^X */
+#ifdef FEAT_INS_EXPAND
+ if (ctrl_x_mode != CTRL_X_WHOLE_LINE)
+#endif
+ {
+ /* CTRL-L with 'insertmode' set: Leave Insert mode */
+ if (p_im)
+ {
+ if (echeck_abbr(Ctrl_L + ABBR_OFF))
+ break;
+ goto doESCkey;
+ }
+ goto normalchar;
+ }
+#ifdef FEAT_INS_EXPAND
+ /* FALLTHROUGH */
+
+ case Ctrl_P: /* Do previous/next pattern completion */
+ case Ctrl_N:
+ /* if 'complete' is empty then plain ^P is no longer special,
+ * but it is under other ^X modes */
+ if (*curbuf->b_p_cpt == NUL
+ && (ctrl_x_mode == CTRL_X_NORMAL
+ || ctrl_x_mode == CTRL_X_WHOLE_LINE)
+ && !(compl_cont_status & CONT_LOCAL))
+ goto normalchar;
+
+docomplete:
+ compl_busy = TRUE;
+#ifdef FEAT_FOLDING
+ disable_fold_update++; /* don't redraw folds here */
+#endif
+ if (ins_complete(c, TRUE) == FAIL)
+ compl_cont_status = 0;
+#ifdef FEAT_FOLDING
+ disable_fold_update--;
+#endif
+ compl_busy = FALSE;
+ break;
+#endif /* FEAT_INS_EXPAND */
+
+ case Ctrl_Y: /* copy from previous line or scroll down */
+ case Ctrl_E: /* copy from next line or scroll up */
+ c = ins_ctrl_ey(c);
+ break;
+
+ default:
+#ifdef UNIX
+ if (c == intr_char) /* special interrupt char */
+ goto do_intr;
+#endif
+
+normalchar:
+ /*
+ * Insert a normal character.
+ */
+#if defined(FEAT_EVAL)
+ if (!p_paste)
+ {
+ /* Trigger InsertCharPre. */
+ char_u *str = do_insert_char_pre(c);
+ char_u *p;
+
+ if (str != NULL)
+ {
+ if (*str != NUL && stop_arrow() != FAIL)
+ {
+ /* Insert the new value of v:char literally. */
+ for (p = str; *p != NUL; MB_PTR_ADV(p))
+ {
+ c = PTR2CHAR(p);
+ if (c == CAR || c == K_KENTER || c == NL)
+ ins_eol(c);
+ else
+ ins_char(c);
+ }
+ AppendToRedobuffLit(str, -1);
+ }
+ vim_free(str);
+ c = NUL;
+ }
+
+ /* If the new value is already inserted or an empty string
+ * then don't insert any character. */
+ if (c == NUL)
+ break;
+ }
+#endif
+#ifdef FEAT_SMARTINDENT
+ /* Try to perform smart-indenting. */
+ ins_try_si(c);
+#endif
+
+ if (c == ' ')
+ {
+ inserted_space = TRUE;
+#ifdef FEAT_CINDENT
+ if (inindent(0))
+ can_cindent = FALSE;
+#endif
+ if (Insstart_blank_vcol == MAXCOL
+ && curwin->w_cursor.lnum == Insstart.lnum)
+ Insstart_blank_vcol = get_nolist_virtcol();
+ }
+
+ /* Insert a normal character and check for abbreviations on a
+ * special character. Let CTRL-] expand abbreviations without
+ * inserting it. */
+ if (vim_iswordc(c) || (!echeck_abbr(
+ // Add ABBR_OFF for characters above 0x100, this is
+ // what check_abbr() expects.
+ (has_mbyte && c >= 0x100) ? (c + ABBR_OFF) : c)
+ && c != Ctrl_RSB))
+ {
+ insert_special(c, FALSE, FALSE);
+#ifdef FEAT_RIGHTLEFT
+ revins_legal++;
+ revins_chars++;
+#endif
+ }
+
+ auto_format(FALSE, TRUE);
+
+#ifdef FEAT_FOLDING
+ /* When inserting a character the cursor line must never be in a
+ * closed fold. */
+ foldOpenCursor();
+#endif
+ break;
+ } /* end of switch (c) */
+
+ /* If typed something may trigger CursorHoldI again. */
+ if (c != K_CURSORHOLD
+#ifdef FEAT_COMPL_FUNC
+ /* but not in CTRL-X mode, a script can't restore the state */
+ && ctrl_x_mode == CTRL_X_NORMAL
+#endif
+ )
+ did_cursorhold = FALSE;
+
+ /* If the cursor was moved we didn't just insert a space */
+ if (arrow_used)
+ inserted_space = FALSE;
+
+#ifdef FEAT_CINDENT
+ if (can_cindent && cindent_on()
+# ifdef FEAT_INS_EXPAND
+ && ctrl_x_mode == CTRL_X_NORMAL
+# endif
+ )
+ {
+force_cindent:
+ /*
+ * Indent now if a key was typed that is in 'cinkeys'.
+ */
+ if (in_cinkeys(c, ' ', line_is_white))
+ {
+ if (stop_arrow() == OK)
+ /* re-indent the current line */
+ do_c_expr_indent();
+ }
+ }
+#endif /* FEAT_CINDENT */
+
+ } /* for (;;) */
+ /* NOTREACHED */
+}
+
+/*
+ * Redraw for Insert mode.
+ * This is postponed until getting the next character to make '$' in the 'cpo'
+ * option work correctly.
+ * Only redraw when there are no characters available. This speeds up
+ * inserting sequences of characters (e.g., for CTRL-R).
+ */
+ static void
+ins_redraw(
+ int ready UNUSED) /* not busy with something */
+{
+#ifdef FEAT_CONCEAL
+ linenr_T conceal_old_cursor_line = 0;
+ linenr_T conceal_new_cursor_line = 0;
+ int conceal_update_lines = FALSE;
+#endif
+
+ if (char_avail())
+ return;
+
+#if defined(FEAT_CONCEAL)
+ /* Trigger CursorMoved if the cursor moved. Not when the popup menu is
+ * visible, the command might delete it. */
+ if (ready && (has_cursormovedI()
+# if defined(FEAT_CONCEAL)
+ || curwin->w_p_cole > 0
+# endif
+ )
+ && !EQUAL_POS(last_cursormoved, curwin->w_cursor)
+# ifdef FEAT_INS_EXPAND
+ && !pum_visible()
+# endif
+ )
+ {
+# ifdef FEAT_SYN_HL
+ /* Need to update the screen first, to make sure syntax
+ * highlighting is correct after making a change (e.g., inserting
+ * a "(". The autocommand may also require a redraw, so it's done
+ * again below, unfortunately. */
+ if (syntax_present(curwin) && must_redraw)
+ update_screen(0);
+# endif
+ if (has_cursormovedI())
+ {
+ /* Make sure curswant is correct, an autocommand may call
+ * getcurpos(). */
+ update_curswant();
+ ins_apply_autocmds(EVENT_CURSORMOVEDI);
+ }
+# ifdef FEAT_CONCEAL
+ if (curwin->w_p_cole > 0)
+ {
+ conceal_old_cursor_line = last_cursormoved.lnum;
+ conceal_new_cursor_line = curwin->w_cursor.lnum;
+ conceal_update_lines = TRUE;
+ }
+# endif
+ last_cursormoved = curwin->w_cursor;
+ }
+#endif
+
+ /* Trigger TextChangedI if b_changedtick differs. */
+ if (ready && has_textchangedI()
+ && curbuf->b_last_changedtick != CHANGEDTICK(curbuf)
+#ifdef FEAT_INS_EXPAND
+ && !pum_visible()
+#endif
+ )
+ {
+ aco_save_T aco;
+ varnumber_T tick = CHANGEDTICK(curbuf);
+
+ // save and restore curwin and curbuf, in case the autocmd changes them
+ aucmd_prepbuf(&aco, curbuf);
+ apply_autocmds(EVENT_TEXTCHANGEDI, NULL, NULL, FALSE, curbuf);
+ aucmd_restbuf(&aco);
+ curbuf->b_last_changedtick = CHANGEDTICK(curbuf);
+ if (tick != CHANGEDTICK(curbuf)) // see ins_apply_autocmds()
+ u_save(curwin->w_cursor.lnum,
+ (linenr_T)(curwin->w_cursor.lnum + 1));
+ }
+
+#ifdef FEAT_INS_EXPAND
+ /* Trigger TextChangedP if b_changedtick differs. When the popupmenu closes
+ * TextChangedI will need to trigger for backwards compatibility, thus use
+ * different b_last_changedtick* variables. */
+ if (ready && has_textchangedP()
+ && curbuf->b_last_changedtick_pum != CHANGEDTICK(curbuf)
+ && pum_visible())
+ {
+ aco_save_T aco;
+ varnumber_T tick = CHANGEDTICK(curbuf);
+
+ // save and restore curwin and curbuf, in case the autocmd changes them
+ aucmd_prepbuf(&aco, curbuf);
+ apply_autocmds(EVENT_TEXTCHANGEDP, NULL, NULL, FALSE, curbuf);
+ aucmd_restbuf(&aco);
+ curbuf->b_last_changedtick_pum = CHANGEDTICK(curbuf);
+ if (tick != CHANGEDTICK(curbuf)) // see ins_apply_autocmds()
+ u_save(curwin->w_cursor.lnum,
+ (linenr_T)(curwin->w_cursor.lnum + 1));
+ }
+#endif
+
+#if defined(FEAT_CONCEAL)
+ if ((conceal_update_lines
+ && (conceal_old_cursor_line != conceal_new_cursor_line
+ || conceal_cursor_line(curwin)))
+ || need_cursor_line_redraw)
+ {
+ if (conceal_old_cursor_line != conceal_new_cursor_line)
+ redrawWinline(curwin, conceal_old_cursor_line);
+ redrawWinline(curwin, conceal_new_cursor_line == 0
+ ? curwin->w_cursor.lnum : conceal_new_cursor_line);
+ curwin->w_valid &= ~VALID_CROW;
+ need_cursor_line_redraw = FALSE;
+ }
+#endif
+ if (must_redraw)
+ update_screen(0);
+ else if (clear_cmdline || redraw_cmdline)
+ showmode(); /* clear cmdline and show mode */
+ showruler(FALSE);
+ setcursor();
+ emsg_on_display = FALSE; /* may remove error message now */
+}
+
+/*
+ * Handle a CTRL-V or CTRL-Q typed in Insert mode.
+ */
+ static void
+ins_ctrl_v(void)
+{
+ int c;
+ int did_putchar = FALSE;
+
+ /* may need to redraw when no more chars available now */
+ ins_redraw(FALSE);
+
+ if (redrawing() && !char_avail())
+ {
+ edit_putchar('^', TRUE);
+ did_putchar = TRUE;
+ }
+ AppendToRedobuff((char_u *)CTRL_V_STR); /* CTRL-V */
+
+#ifdef FEAT_CMDL_INFO
+ add_to_showcmd_c(Ctrl_V);
+#endif
+
+ c = get_literal();
+ if (did_putchar)
+ /* when the line fits in 'columns' the '^' is at the start of the next
+ * line and will not removed by the redraw */
+ edit_unputchar();
+#ifdef FEAT_CMDL_INFO
+ clear_showcmd();
+#endif
+ insert_special(c, FALSE, TRUE);
+#ifdef FEAT_RIGHTLEFT
+ revins_chars++;
+ revins_legal++;
+#endif
+}
+
+/*
+ * Put a character directly onto the screen. It's not stored in a buffer.
+ * Used while handling CTRL-K, CTRL-V, etc. in Insert mode.
+ */
+static int pc_status;
+#define PC_STATUS_UNSET 0 /* pc_bytes was not set */
+#define PC_STATUS_RIGHT 1 /* right halve of double-wide char */
+#define PC_STATUS_LEFT 2 /* left halve of double-wide char */
+#define PC_STATUS_SET 3 /* pc_bytes was filled */
+static char_u pc_bytes[MB_MAXBYTES + 1]; /* saved bytes */
+static int pc_attr;
+static int pc_row;
+static int pc_col;
+
+ void
+edit_putchar(int c, int highlight)
+{
+ int attr;
+
+ if (ScreenLines != NULL)
+ {
+ update_topline(); /* just in case w_topline isn't valid */
+ validate_cursor();
+ if (highlight)
+ attr = HL_ATTR(HLF_8);
+ else
+ attr = 0;
+ pc_row = W_WINROW(curwin) + curwin->w_wrow;
+ pc_col = curwin->w_wincol;
+ pc_status = PC_STATUS_UNSET;
+#ifdef FEAT_RIGHTLEFT
+ if (curwin->w_p_rl)
+ {
+ pc_col += curwin->w_width - 1 - curwin->w_wcol;
+ if (has_mbyte)
+ {
+ int fix_col = mb_fix_col(pc_col, pc_row);
+
+ if (fix_col != pc_col)
+ {
+ screen_putchar(' ', pc_row, fix_col, attr);
+ --curwin->w_wcol;
+ pc_status = PC_STATUS_RIGHT;
+ }
+ }
+ }
+ else
+#endif
+ {
+ pc_col += curwin->w_wcol;
+ if (mb_lefthalve(pc_row, pc_col))
+ pc_status = PC_STATUS_LEFT;
+ }
+
+ /* save the character to be able to put it back */
+ if (pc_status == PC_STATUS_UNSET)
+ {
+ screen_getbytes(pc_row, pc_col, pc_bytes, &pc_attr);
+ pc_status = PC_STATUS_SET;
+ }
+ screen_putchar(c, pc_row, pc_col, attr);
+ }
+}
+
+#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
+/*
+ * Return the effective prompt for the current buffer.
+ */
+ char_u *
+prompt_text(void)
+{
+ if (curbuf->b_prompt_text == NULL)
+ return (char_u *)"% ";
+ return curbuf->b_prompt_text;
+}
+
+/*
+ * Prepare for prompt mode: Make sure the last line has the prompt text.
+ * Move the cursor to this line.
+ */
+ static void
+init_prompt(int cmdchar_todo)
+{
+ char_u *prompt = prompt_text();
+ char_u *text;
+
+ curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
+ text = ml_get_curline();
+ if (STRNCMP(text, prompt, STRLEN(prompt)) != 0)
+ {
+ // prompt is missing, insert it or append a line with it
+ if (*text == NUL)
+ ml_replace(curbuf->b_ml.ml_line_count, prompt, TRUE);
+ else
+ ml_append(curbuf->b_ml.ml_line_count, prompt, 0, FALSE);
+ curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
+ coladvance((colnr_T)MAXCOL);
+ changed_bytes(curbuf->b_ml.ml_line_count, 0);
+ }
+
+ // Insert always starts after the prompt, allow editing text after it.
+ if (Insstart_orig.lnum != curwin->w_cursor.lnum
+ || Insstart_orig.col != (int)STRLEN(prompt))
+ {
+ Insstart.lnum = curwin->w_cursor.lnum;
+ Insstart.col = (int)STRLEN(prompt);
+ Insstart_orig = Insstart;
+ Insstart_textlen = Insstart.col;
+ Insstart_blank_vcol = MAXCOL;
+ arrow_used = FALSE;
+ }
+
+ if (cmdchar_todo == 'A')
+ coladvance((colnr_T)MAXCOL);
+ if (cmdchar_todo == 'I' || curwin->w_cursor.col <= (int)STRLEN(prompt))
+ curwin->w_cursor.col = (int)STRLEN(prompt);
+ /* Make sure the cursor is in a valid position. */
+ check_cursor();
+}
+
+/*
+ * Return TRUE if the cursor is in the editable position of the prompt line.
+ */
+ int
+prompt_curpos_editable()
+{
+ return curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count
+ && curwin->w_cursor.col >= (int)STRLEN(prompt_text());
+}
+#endif
+
+/*
+ * Undo the previous edit_putchar().
+ */
+ void
+edit_unputchar(void)
+{
+ if (pc_status != PC_STATUS_UNSET && pc_row >= msg_scrolled)
+ {
+ if (pc_status == PC_STATUS_RIGHT)
+ ++curwin->w_wcol;
+ if (pc_status == PC_STATUS_RIGHT || pc_status == PC_STATUS_LEFT)
+ redrawWinline(curwin, curwin->w_cursor.lnum);
+ else
+ screen_puts(pc_bytes, pc_row - msg_scrolled, pc_col, pc_attr);
+ }
+}
+
+/*
+ * Called when p_dollar is set: display a '$' at the end of the changed text
+ * Only works when cursor is in the line that changes.
+ */
+ void
+display_dollar(colnr_T col)
+{
+ colnr_T save_col;
+
+ if (!redrawing())
+ return;
+
+ cursor_off();
+ save_col = curwin->w_cursor.col;
+ curwin->w_cursor.col = col;
+ if (has_mbyte)
+ {
+ char_u *p;
+
+ /* If on the last byte of a multi-byte move to the first byte. */
+ p = ml_get_curline();
+ curwin->w_cursor.col -= (*mb_head_off)(p, p + col);
+ }
+ curs_columns(FALSE); /* recompute w_wrow and w_wcol */
+ if (curwin->w_wcol < curwin->w_width)
+ {
+ edit_putchar('$', FALSE);
+ dollar_vcol = curwin->w_virtcol;
+ }
+ curwin->w_cursor.col = save_col;
+}
+
+/*
+ * Call this function before moving the cursor from the normal insert position
+ * in insert mode.
+ */
+ static void
+undisplay_dollar(void)
+{
+ if (dollar_vcol >= 0)
+ {
+ dollar_vcol = -1;
+ redrawWinline(curwin, curwin->w_cursor.lnum);
+ }
+}
+
+/*
+ * Insert an indent (for <Tab> or CTRL-T) or delete an indent (for CTRL-D).
+ * Keep the cursor on the same character.
+ * type == INDENT_INC increase indent (for CTRL-T or <Tab>)
+ * type == INDENT_DEC decrease indent (for CTRL-D)
+ * type == INDENT_SET set indent to "amount"
+ * if round is TRUE, round the indent to 'shiftwidth' (only with _INC and _Dec).
+ */
+ void
+change_indent(
+ int type,
+ int amount,
+ int round,
+ int replaced, /* replaced character, put on replace stack */
+ int call_changed_bytes) /* call changed_bytes() */
+{
+ int vcol;
+ int last_vcol;
+ int insstart_less; /* reduction for Insstart.col */
+ int new_cursor_col;
+ int i;
+ char_u *ptr;
+ int save_p_list;
+ int start_col;
+ colnr_T vc;
+ colnr_T orig_col = 0; /* init for GCC */
+ char_u *new_line, *orig_line = NULL; /* init for GCC */
+
+ /* VREPLACE mode needs to know what the line was like before changing */
+ if (State & VREPLACE_FLAG)
+ {
+ orig_line = vim_strsave(ml_get_curline()); /* Deal with NULL below */
+ orig_col = curwin->w_cursor.col;
+ }
+
+ /* for the following tricks we don't want list mode */
+ save_p_list = curwin->w_p_list;
+ curwin->w_p_list = FALSE;
+ vc = getvcol_nolist(&curwin->w_cursor);
+ vcol = vc;
+
+ /*
+ * For Replace mode we need to fix the replace stack later, which is only
+ * possible when the cursor is in the indent. Remember the number of
+ * characters before the cursor if it's possible.
+ */
+ start_col = curwin->w_cursor.col;
+
+ /* determine offset from first non-blank */
+ new_cursor_col = curwin->w_cursor.col;
+ beginline(BL_WHITE);
+ new_cursor_col -= curwin->w_cursor.col;
+
+ insstart_less = curwin->w_cursor.col;
+
+ /*
+ * If the cursor is in the indent, compute how many screen columns the
+ * cursor is to the left of the first non-blank.
+ */
+ if (new_cursor_col < 0)
+ vcol = get_indent() - vcol;
+
+ if (new_cursor_col > 0) /* can't fix replace stack */
+ start_col = -1;
+
+ /*
+ * Set the new indent. The cursor will be put on the first non-blank.
+ */
+ if (type == INDENT_SET)
+ (void)set_indent(amount, call_changed_bytes ? SIN_CHANGED : 0);
+ else
+ {
+ int save_State = State;
+
+ /* Avoid being called recursively. */
+ if (State & VREPLACE_FLAG)
+ State = INSERT;
+ shift_line(type == INDENT_DEC, round, 1, call_changed_bytes);
+ State = save_State;
+ }
+ insstart_less -= curwin->w_cursor.col;
+
+ /*
+ * Try to put cursor on same character.
+ * If the cursor is at or after the first non-blank in the line,
+ * compute the cursor column relative to the column of the first
+ * non-blank character.
+ * If we are not in insert mode, leave the cursor on the first non-blank.
+ * If the cursor is before the first non-blank, position it relative
+ * to the first non-blank, counted in screen columns.
+ */
+ if (new_cursor_col >= 0)
+ {
+ /*
+ * When changing the indent while the cursor is touching it, reset
+ * Insstart_col to 0.
+ */
+ if (new_cursor_col == 0)
+ insstart_less = MAXCOL;
+ new_cursor_col += curwin->w_cursor.col;
+ }
+ else if (!(State & INSERT))
+ new_cursor_col = curwin->w_cursor.col;
+ else
+ {
+ /*
+ * Compute the screen column where the cursor should be.
+ */
+ vcol = get_indent() - vcol;
+ curwin->w_virtcol = (colnr_T)((vcol < 0) ? 0 : vcol);
+
+ /*
+ * Advance the cursor until we reach the right screen column.
+ */
+ vcol = last_vcol = 0;
+ new_cursor_col = -1;
+ ptr = ml_get_curline();
+ while (vcol <= (int)curwin->w_virtcol)
+ {
+ last_vcol = vcol;
+ if (has_mbyte && new_cursor_col >= 0)
+ new_cursor_col += (*mb_ptr2len)(ptr + new_cursor_col);
+ else
+ ++new_cursor_col;
+ vcol += lbr_chartabsize(ptr, ptr + new_cursor_col, (colnr_T)vcol);
+ }
+ vcol = last_vcol;
+
+ /*
+ * May need to insert spaces to be able to position the cursor on
+ * the right screen column.
+ */
+ if (vcol != (int)curwin->w_virtcol)
+ {
+ curwin->w_cursor.col = (colnr_T)new_cursor_col;
+ i = (int)curwin->w_virtcol - vcol;
+ ptr = alloc((unsigned)(i + 1));
+ if (ptr != NULL)
+ {
+ new_cursor_col += i;
+ ptr[i] = NUL;
+ while (--i >= 0)
+ ptr[i] = ' ';
+ ins_str(ptr);
+ vim_free(ptr);
+ }
+ }
+
+ /*
+ * When changing the indent while the cursor is in it, reset
+ * Insstart_col to 0.
+ */
+ insstart_less = MAXCOL;
+ }
+
+ curwin->w_p_list = save_p_list;
+
+ if (new_cursor_col <= 0)
+ curwin->w_cursor.col = 0;
+ else
+ curwin->w_cursor.col = (colnr_T)new_cursor_col;
+ curwin->w_set_curswant = TRUE;
+ changed_cline_bef_curs();
+
+ /*
+ * May have to adjust the start of the insert.
+ */
+ if (State & INSERT)
+ {
+ if (curwin->w_cursor.lnum == Insstart.lnum && Insstart.col != 0)
+ {
+ if ((int)Insstart.col <= insstart_less)
+ Insstart.col = 0;
+ else
+ Insstart.col -= insstart_less;
+ }
+ if ((int)ai_col <= insstart_less)
+ ai_col = 0;
+ else
+ ai_col -= insstart_less;
+ }
+
+ /*
+ * For REPLACE mode, may have to fix the replace stack, if it's possible.
+ * If the number of characters before the cursor decreased, need to pop a
+ * few characters from the replace stack.
+ * If the number of characters before the cursor increased, need to push a
+ * few NULs onto the replace stack.
+ */
+ if (REPLACE_NORMAL(State) && start_col >= 0)
+ {
+ while (start_col > (int)curwin->w_cursor.col)
+ {
+ replace_join(0); /* remove a NUL from the replace stack */
+ --start_col;
+ }
+ while (start_col < (int)curwin->w_cursor.col || replaced)
+ {
+ replace_push(NUL);
+ if (replaced)
+ {
+ replace_push(replaced);
+ replaced = NUL;
+ }
+ ++start_col;
+ }
+ }
+
+ /*
+ * For VREPLACE mode, we also have to fix the replace stack. In this case
+ * it is always possible because we backspace over the whole line and then
+ * put it back again the way we wanted it.
+ */
+ if (State & VREPLACE_FLAG)
+ {
+ /* If orig_line didn't allocate, just return. At least we did the job,
+ * even if you can't backspace. */
+ if (orig_line == NULL)
+ return;
+
+ /* Save new line */
+ new_line = vim_strsave(ml_get_curline());
+ if (new_line == NULL)
+ return;
+
+ /* We only put back the new line up to the cursor */
+ new_line[curwin->w_cursor.col] = NUL;
+
+ /* Put back original line */
+ ml_replace(curwin->w_cursor.lnum, orig_line, FALSE);
+ curwin->w_cursor.col = orig_col;
+
+ /* Backspace from cursor to start of line */
+ backspace_until_column(0);
+
+ /* Insert new stuff into line again */
+ ins_bytes(new_line);
+
+ vim_free(new_line);
+ }
+}
+
+/*
+ * Truncate the space at the end of a line. This is to be used only in an
+ * insert mode. It handles fixing the replace stack for REPLACE and VREPLACE
+ * modes.
+ */
+ void
+truncate_spaces(char_u *line)
+{
+ int i;
+
+ /* find start of trailing white space */
+ for (i = (int)STRLEN(line) - 1; i >= 0 && VIM_ISWHITE(line[i]); i--)
+ {
+ if (State & REPLACE_FLAG)
+ replace_join(0); /* remove a NUL from the replace stack */
+ }
+ line[i + 1] = NUL;
+}
+
+/*
+ * Backspace the cursor until the given column. Handles REPLACE and VREPLACE
+ * modes correctly. May also be used when not in insert mode at all.
+ * Will attempt not to go before "col" even when there is a composing
+ * character.
+ */
+ void
+backspace_until_column(int col)
+{
+ while ((int)curwin->w_cursor.col > col)
+ {
+ curwin->w_cursor.col--;
+ if (State & REPLACE_FLAG)
+ replace_do_bs(col);
+ else if (!del_char_after_col(col))
+ break;
+ }
+}
+
+/*
+ * Like del_char(), but make sure not to go before column "limit_col".
+ * Only matters when there are composing characters.
+ * Return TRUE when something was deleted.
+ */
+ static int
+del_char_after_col(int limit_col UNUSED)
+{
+ if (enc_utf8 && limit_col >= 0)
+ {
+ colnr_T ecol = curwin->w_cursor.col + 1;
+
+ /* Make sure the cursor is at the start of a character, but
+ * skip forward again when going too far back because of a
+ * composing character. */
+ mb_adjust_cursor();
+ while (curwin->w_cursor.col < (colnr_T)limit_col)
+ {
+ int l = utf_ptr2len(ml_get_cursor());
+
+ if (l == 0) /* end of line */
+ break;
+ curwin->w_cursor.col += l;
+ }
+ if (*ml_get_cursor() == NUL || curwin->w_cursor.col == ecol)
+ return FALSE;
+ del_bytes((long)((int)ecol - curwin->w_cursor.col), FALSE, TRUE);
+ }
+ else
+ (void)del_char(FALSE);
+ return TRUE;
+}
+
+#if defined(FEAT_INS_EXPAND) || defined(PROTO)
+/*
+ * CTRL-X pressed in Insert mode.
+ */
+ static void
+ins_ctrl_x(void)
+{
+ /* CTRL-X after CTRL-X CTRL-V doesn't do anything, so that CTRL-X
+ * CTRL-V works like CTRL-N */
+ if (ctrl_x_mode != CTRL_X_CMDLINE)
+ {
+ /* if the next ^X<> won't ADD nothing, then reset
+ * compl_cont_status */
+ if (compl_cont_status & CONT_N_ADDS)
+ compl_cont_status |= CONT_INTRPT;
+ else
+ compl_cont_status = 0;
+ /* We're not sure which CTRL-X mode it will be yet */
+ ctrl_x_mode = CTRL_X_NOT_DEFINED_YET;
+ edit_submode = (char_u *)_(CTRL_X_MSG(ctrl_x_mode));
+ edit_submode_pre = NULL;
+ showmode();
+ }
+}
+
+/*
+ * Whether other than default completion has been selected.
+ */
+ int
+ctrl_x_mode_not_default(void)
+{
+ return ctrl_x_mode != CTRL_X_NORMAL;
+}
+
+/*
+ * Whether CTRL-X was typed without a following character.
+ */
+ int
+ctrl_x_mode_not_defined_yet(void)
+{
+ return ctrl_x_mode == CTRL_X_NOT_DEFINED_YET;
+}
+
+/*
+ * Return TRUE if the 'dict' or 'tsr' option can be used.
+ */
+ static int
+has_compl_option(int dict_opt)
+{
+ if (dict_opt ? (*curbuf->b_p_dict == NUL && *p_dict == NUL
+# ifdef FEAT_SPELL
+ && !curwin->w_p_spell
+# endif
+ )
+ : (*curbuf->b_p_tsr == NUL && *p_tsr == NUL))
+ {
+ ctrl_x_mode = CTRL_X_NORMAL;
+ edit_submode = NULL;
+ msg_attr(dict_opt ? _("'dictionary' option is empty")
+ : _("'thesaurus' option is empty"),
+ HL_ATTR(HLF_E));
+ if (emsg_silent == 0)
+ {
+ vim_beep(BO_COMPL);
+ setcursor();
+ out_flush();
+#ifdef FEAT_EVAL
+ if (!get_vim_var_nr(VV_TESTING))
+#endif
+ ui_delay(2000L, FALSE);
+ }
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*
+ * Is the character 'c' a valid key to go to or keep us in CTRL-X mode?
+ * This depends on the current mode.
+ */
+ int
+vim_is_ctrl_x_key(int c)
+{
+ // Always allow ^R - let its results then be checked
+ if (c == Ctrl_R)
+ return TRUE;
+
+ /* Accept <PageUp> and <PageDown> if the popup menu is visible. */
+ if (ins_compl_pum_key(c))
+ return TRUE;
+
+ switch (ctrl_x_mode)
+ {
+ case 0: /* Not in any CTRL-X mode */
+ return (c == Ctrl_N || c == Ctrl_P || c == Ctrl_X);
+ case CTRL_X_NOT_DEFINED_YET:
+ return ( c == Ctrl_X || c == Ctrl_Y || c == Ctrl_E
+ || c == Ctrl_L || c == Ctrl_F || c == Ctrl_RSB
+ || c == Ctrl_I || c == Ctrl_D || c == Ctrl_P
+ || c == Ctrl_N || c == Ctrl_T || c == Ctrl_V
+ || c == Ctrl_Q || c == Ctrl_U || c == Ctrl_O
+ || c == Ctrl_S || c == Ctrl_K || c == 's');
+ case CTRL_X_SCROLL:
+ return (c == Ctrl_Y || c == Ctrl_E);
+ case CTRL_X_WHOLE_LINE:
+ return (c == Ctrl_L || c == Ctrl_P || c == Ctrl_N);
+ case CTRL_X_FILES:
+ return (c == Ctrl_F || c == Ctrl_P || c == Ctrl_N);
+ case CTRL_X_DICTIONARY:
+ return (c == Ctrl_K || c == Ctrl_P || c == Ctrl_N);
+ case CTRL_X_THESAURUS:
+ return (c == Ctrl_T || c == Ctrl_P || c == Ctrl_N);
+ case CTRL_X_TAGS:
+ return (c == Ctrl_RSB || c == Ctrl_P || c == Ctrl_N);
+#ifdef FEAT_FIND_ID
+ case CTRL_X_PATH_PATTERNS:
+ return (c == Ctrl_P || c == Ctrl_N);
+ case CTRL_X_PATH_DEFINES:
+ return (c == Ctrl_D || c == Ctrl_P || c == Ctrl_N);
+#endif
+ case CTRL_X_CMDLINE:
+ return (c == Ctrl_V || c == Ctrl_Q || c == Ctrl_P || c == Ctrl_N
+ || c == Ctrl_X);
+#ifdef FEAT_COMPL_FUNC
+ case CTRL_X_FUNCTION:
+ return (c == Ctrl_U || c == Ctrl_P || c == Ctrl_N);
+ case CTRL_X_OMNI:
+ return (c == Ctrl_O || c == Ctrl_P || c == Ctrl_N);
+#endif
+ case CTRL_X_SPELL:
+ return (c == Ctrl_S || c == Ctrl_P || c == Ctrl_N);
+ case CTRL_X_EVAL:
+ return (c == Ctrl_P || c == Ctrl_N);
+ }
+ internal_error("vim_is_ctrl_x_key()");
+ return FALSE;
+}
+
+/*
+ * Return TRUE when character "c" is part of the item currently being
+ * completed. Used to decide whether to abandon complete mode when the menu
+ * is visible.
+ */
+ static int
+ins_compl_accept_char(int c)
+{
+ if (ctrl_x_mode & CTRL_X_WANT_IDENT)
+ /* When expanding an identifier only accept identifier chars. */
+ return vim_isIDc(c);
+
+ switch (ctrl_x_mode)
+ {
+ case CTRL_X_FILES:
+ /* When expanding file name only accept file name chars. But not
+ * path separators, so that "proto/<Tab>" expands files in
+ * "proto", not "proto/" as a whole */
+ return vim_isfilec(c) && !vim_ispathsep(c);
+
+ case CTRL_X_CMDLINE:
+ case CTRL_X_OMNI:
+ /* Command line and Omni completion can work with just about any
+ * printable character, but do stop at white space. */
+ return vim_isprintc(c) && !VIM_ISWHITE(c);
+
+ case CTRL_X_WHOLE_LINE:
+ /* For while line completion a space can be part of the line. */
+ return vim_isprintc(c);
+ }
+ return vim_iswordc(c);
+}
+
+/*
+ * This is like ins_compl_add(), but if 'ic' and 'inf' are set, then the
+ * case of the originally typed text is used, and the case of the completed
+ * text is inferred, ie this tries to work out what case you probably wanted
+ * the rest of the word to be in -- webb
+ */
+ int
+ins_compl_add_infercase(
+ char_u *str,
+ int len,
+ int icase,
+ char_u *fname,
+ int dir,
+ int flags)
+{
+ char_u *p;
+ int i, c;
+ int actual_len; /* Take multi-byte characters */
+ int actual_compl_length; /* into account. */
+ int min_len;
+ int *wca; /* Wide character array. */
+ int has_lower = FALSE;
+ int was_letter = FALSE;
+
+ if (p_ic && curbuf->b_p_inf && len > 0)
+ {
+ /* Infer case of completed part. */
+
+ /* Find actual length of completion. */
+ if (has_mbyte)
+ {
+ p = str;
+ actual_len = 0;
+ while (*p != NUL)
+ {
+ MB_PTR_ADV(p);
+ ++actual_len;
+ }
+ }
+ else
+ actual_len = len;
+
+ /* Find actual length of original text. */
+ if (has_mbyte)
+ {
+ p = compl_orig_text;
+ actual_compl_length = 0;
+ while (*p != NUL)
+ {
+ MB_PTR_ADV(p);
+ ++actual_compl_length;
+ }
+ }
+ else
+ actual_compl_length = compl_length;
+
+ /* "actual_len" may be smaller than "actual_compl_length" when using
+ * thesaurus, only use the minimum when comparing. */
+ min_len = actual_len < actual_compl_length
+ ? actual_len : actual_compl_length;
+
+ /* Allocate wide character array for the completion and fill it. */
+ wca = (int *)alloc((unsigned)(actual_len * sizeof(int)));
+ if (wca != NULL)
+ {
+ p = str;
+ for (i = 0; i < actual_len; ++i)
+ if (has_mbyte)
+ wca[i] = mb_ptr2char_adv(&p);
+ else
+ wca[i] = *(p++);
+
+ /* Rule 1: Were any chars converted to lower? */
+ p = compl_orig_text;
+ for (i = 0; i < min_len; ++i)
+ {
+ if (has_mbyte)
+ c = mb_ptr2char_adv(&p);
+ else
+ c = *(p++);
+ if (MB_ISLOWER(c))
+ {
+ has_lower = TRUE;
+ if (MB_ISUPPER(wca[i]))
+ {
+ /* Rule 1 is satisfied. */
+ for (i = actual_compl_length; i < actual_len; ++i)
+ wca[i] = MB_TOLOWER(wca[i]);
+ break;
+ }
+ }
+ }
+
+ /*
+ * Rule 2: No lower case, 2nd consecutive letter converted to
+ * upper case.
+ */
+ if (!has_lower)
+ {
+ p = compl_orig_text;
+ for (i = 0; i < min_len; ++i)
+ {
+ if (has_mbyte)
+ c = mb_ptr2char_adv(&p);
+ else
+ c = *(p++);
+ if (was_letter && MB_ISUPPER(c) && MB_ISLOWER(wca[i]))
+ {
+ /* Rule 2 is satisfied. */
+ for (i = actual_compl_length; i < actual_len; ++i)
+ wca[i] = MB_TOUPPER(wca[i]);
+ break;
+ }
+ was_letter = MB_ISLOWER(c) || MB_ISUPPER(c);
+ }
+ }
+
+ /* Copy the original case of the part we typed. */
+ p = compl_orig_text;
+ for (i = 0; i < min_len; ++i)
+ {
+ if (has_mbyte)
+ c = mb_ptr2char_adv(&p);
+ else
+ c = *(p++);
+ if (MB_ISLOWER(c))
+ wca[i] = MB_TOLOWER(wca[i]);
+ else if (MB_ISUPPER(c))
+ wca[i] = MB_TOUPPER(wca[i]);
+ }
+
+ /*
+ * Generate encoding specific output from wide character array.
+ * Multi-byte characters can occupy up to five bytes more than
+ * ASCII characters, and we also need one byte for NUL, so stay
+ * six bytes away from the edge of IObuff.
+ */
+ p = IObuff;
+ i = 0;
+ while (i < actual_len && (p - IObuff + 6) < IOSIZE)
+ if (has_mbyte)
+ p += (*mb_char2bytes)(wca[i++], p);
+ else
+ *(p++) = wca[i++];
+ *p = NUL;
+
+ vim_free(wca);
+ }
+
+ return ins_compl_add(IObuff, len, icase, fname, NULL, dir,
+ flags, FALSE);
+ }
+ return ins_compl_add(str, len, icase, fname, NULL, dir, flags, FALSE);
+}
+
+/*
+ * Add a match to the list of matches.
+ * If the given string is already in the list of completions, then return
+ * NOTDONE, otherwise add it to the list and return OK. If there is an error,
+ * maybe because alloc() returns NULL, then FAIL is returned.
+ */
+ static int
+ins_compl_add(
+ char_u *str,
+ int len,
+ int icase,
+ char_u *fname,
+ char_u **cptext, /* extra text for popup menu or NULL */
+ int cdir,
+ int flags,
+ int adup) /* accept duplicate match */
+{
+ compl_T *match;
+ int dir = (cdir == 0 ? compl_direction : cdir);
+
+ ui_breakcheck();
+ if (got_int)
+ return FAIL;
+ if (len < 0)
+ len = (int)STRLEN(str);
+
+ /*
+ * If the same match is already present, don't add it.
+ */
+ if (compl_first_match != NULL && !adup)
+ {
+ match = compl_first_match;
+ do
+ {
+ if ( !(match->cp_flags & ORIGINAL_TEXT)
+ && STRNCMP(match->cp_str, str, len) == 0
+ && match->cp_str[len] == NUL)
+ return NOTDONE;
+ match = match->cp_next;
+ } while (match != NULL && match != compl_first_match);
+ }
+
+ /* Remove any popup menu before changing the list of matches. */
+ ins_compl_del_pum();
+
+ /*
+ * Allocate a new match structure.
+ * Copy the values to the new match structure.
+ */
+ match = (compl_T *)alloc_clear((unsigned)sizeof(compl_T));
+ if (match == NULL)
+ return FAIL;
+ match->cp_number = -1;
+ if (flags & ORIGINAL_TEXT)
+ match->cp_number = 0;
+ if ((match->cp_str = vim_strnsave(str, len)) == NULL)
+ {
+ vim_free(match);
+ return FAIL;
+ }
+ match->cp_icase = icase;
+
+ /* match-fname is:
+ * - compl_curr_match->cp_fname if it is a string equal to fname.
+ * - a copy of fname, FREE_FNAME is set to free later THE allocated mem.
+ * - NULL otherwise. --Acevedo */
+ if (fname != NULL
+ && compl_curr_match != NULL
+ && compl_curr_match->cp_fname != NULL
+ && STRCMP(fname, compl_curr_match->cp_fname) == 0)
+ match->cp_fname = compl_curr_match->cp_fname;
+ else if (fname != NULL)
+ {
+ match->cp_fname = vim_strsave(fname);
+ flags |= FREE_FNAME;
+ }
+ else
+ match->cp_fname = NULL;
+ match->cp_flags = flags;
+
+ if (cptext != NULL)
+ {
+ int i;
+
+ for (i = 0; i < CPT_COUNT; ++i)
+ if (cptext[i] != NULL && *cptext[i] != NUL)
+ match->cp_text[i] = vim_strsave(cptext[i]);
+ }
+
+ /*
+ * Link the new match structure in the list of matches.
+ */
+ if (compl_first_match == NULL)
+ match->cp_next = match->cp_prev = NULL;
+ else if (dir == FORWARD)
+ {
+ match->cp_next = compl_curr_match->cp_next;
+ match->cp_prev = compl_curr_match;
+ }
+ else /* BACKWARD */
+ {
+ match->cp_next = compl_curr_match;
+ match->cp_prev = compl_curr_match->cp_prev;
+ }
+ if (match->cp_next)
+ match->cp_next->cp_prev = match;
+ if (match->cp_prev)
+ match->cp_prev->cp_next = match;
+ else /* if there's nothing before, it is the first match */
+ compl_first_match = match;
+ compl_curr_match = match;
+
+ /*
+ * Find the longest common string if still doing that.
+ */
+ if (compl_get_longest && (flags & ORIGINAL_TEXT) == 0)
+ ins_compl_longest_match(match);
+
+ return OK;
+}
+
+/*
+ * Return TRUE if "str[len]" matches with match->cp_str, considering
+ * match->cp_icase.
+ */
+ static int
+ins_compl_equal(compl_T *match, char_u *str, int len)
+{
+ if (match->cp_icase)
+ return STRNICMP(match->cp_str, str, (size_t)len) == 0;
+ return STRNCMP(match->cp_str, str, (size_t)len) == 0;
+}
+
+/*
+ * Reduce the longest common string for match "match".
+ */
+ static void
+ins_compl_longest_match(compl_T *match)
+{
+ char_u *p, *s;
+ int c1, c2;
+ int had_match;
+
+ if (compl_leader == NULL)
+ {
+ /* First match, use it as a whole. */
+ compl_leader = vim_strsave(match->cp_str);
+ if (compl_leader != NULL)
+ {
+ had_match = (curwin->w_cursor.col > compl_col);
+ ins_compl_delete();
+ ins_bytes(compl_leader + ins_compl_len());
+ ins_redraw(FALSE);
+
+ /* When the match isn't there (to avoid matching itself) remove it
+ * again after redrawing. */
+ if (!had_match)
+ ins_compl_delete();
+ compl_used_match = FALSE;
+ }
+ }
+ else
+ {
+ /* Reduce the text if this match differs from compl_leader. */
+ p = compl_leader;
+ s = match->cp_str;
+ while (*p != NUL)
+ {
+ if (has_mbyte)
+ {
+ c1 = mb_ptr2char(p);
+ c2 = mb_ptr2char(s);
+ }
+ else
+ {
+ c1 = *p;
+ c2 = *s;
+ }
+ if (match->cp_icase ? (MB_TOLOWER(c1) != MB_TOLOWER(c2))
+ : (c1 != c2))
+ break;
+ if (has_mbyte)
+ {
+ MB_PTR_ADV(p);
+ MB_PTR_ADV(s);
+ }
+ else
+ {
+ ++p;
+ ++s;
+ }
+ }
+
+ if (*p != NUL)
+ {
+ /* Leader was shortened, need to change the inserted text. */
+ *p = NUL;
+ had_match = (curwin->w_cursor.col > compl_col);
+ ins_compl_delete();
+ ins_bytes(compl_leader + ins_compl_len());
+ ins_redraw(FALSE);
+
+ /* When the match isn't there (to avoid matching itself) remove it
+ * again after redrawing. */
+ if (!had_match)
+ ins_compl_delete();
+ }
+
+ compl_used_match = FALSE;
+ }
+}
+
+/*
+ * Add an array of matches to the list of matches.
+ * Frees matches[].
+ */
+ static void
+ins_compl_add_matches(
+ int num_matches,
+ char_u **matches,
+ int icase)
+{
+ int i;
+ int add_r = OK;
+ int dir = compl_direction;
+
+ for (i = 0; i < num_matches && add_r != FAIL; i++)
+ if ((add_r = ins_compl_add(matches[i], -1, icase,
+ NULL, NULL, dir, 0, FALSE)) == OK)
+ /* if dir was BACKWARD then honor it just once */
+ dir = FORWARD;
+ FreeWild(num_matches, matches);
+}
+
+/* Make the completion list cyclic.
+ * Return the number of matches (excluding the original).
+ */
+ static int
+ins_compl_make_cyclic(void)
+{
+ compl_T *match;
+ int count = 0;
+
+ if (compl_first_match != NULL)
+ {
+ /*
+ * Find the end of the list.
+ */
+ match = compl_first_match;
+ /* there's always an entry for the compl_orig_text, it doesn't count. */
+ while (match->cp_next != NULL && match->cp_next != compl_first_match)
+ {
+ match = match->cp_next;
+ ++count;
+ }
+ match->cp_next = compl_first_match;
+ compl_first_match->cp_prev = match;
+ }
+ return count;
+}
+
+/*
+ * Set variables that store noselect and noinsert behavior from the
+ * 'completeopt' value.
+ */
+ void
+completeopt_was_set(void)
+{
+ compl_no_insert = FALSE;
+ compl_no_select = FALSE;
+ if (strstr((char *)p_cot, "noselect") != NULL)
+ compl_no_select = TRUE;
+ if (strstr((char *)p_cot, "noinsert") != NULL)
+ compl_no_insert = TRUE;
+}
+
+/*
+ * Start completion for the complete() function.
+ * "startcol" is where the matched text starts (1 is first column).
+ * "list" is the list of matches.
+ */
+ void
+set_completion(colnr_T startcol, list_T *list)
+{
+ int save_w_wrow = curwin->w_wrow;
+ int save_w_leftcol = curwin->w_leftcol;
+
+ /* If already doing completions stop it. */
+ if (ctrl_x_mode != CTRL_X_NORMAL)
+ ins_compl_prep(' ');
+ ins_compl_clear();
+ ins_compl_free();
+
+ compl_direction = FORWARD;
+ if (startcol > curwin->w_cursor.col)
+ startcol = curwin->w_cursor.col;
+ compl_col = startcol;
+ compl_length = (int)curwin->w_cursor.col - (int)startcol;
+ /* compl_pattern doesn't need to be set */
+ compl_orig_text = vim_strnsave(ml_get_curline() + compl_col, compl_length);
+ if (compl_orig_text == NULL || ins_compl_add(compl_orig_text,
+ -1, p_ic, NULL, NULL, 0, ORIGINAL_TEXT, FALSE) != OK)
+ return;
+
+ ctrl_x_mode = CTRL_X_EVAL;
+
+ ins_compl_add_list(list);
+ compl_matches = ins_compl_make_cyclic();
+ compl_started = TRUE;
+ compl_used_match = TRUE;
+ compl_cont_status = 0;
+
+ compl_curr_match = compl_first_match;
+ if (compl_no_insert || compl_no_select)
+ {
+ ins_complete(K_DOWN, FALSE);
+ if (compl_no_select)
+ /* Down/Up has no real effect. */
+ ins_complete(K_UP, FALSE);
+ }
+ else
+ ins_complete(Ctrl_N, FALSE);
+ compl_enter_selects = compl_no_insert;
+
+ /* Lazily show the popup menu, unless we got interrupted. */
+ if (!compl_interrupted)
+ show_pum(save_w_wrow, save_w_leftcol);
+ out_flush();
+}
+
+
+/* "compl_match_array" points the currently displayed list of entries in the
+ * popup menu. It is NULL when there is no popup menu. */
+static pumitem_T *compl_match_array = NULL;
+static int compl_match_arraysize;
+
+/*
+ * Update the screen and when there is any scrolling remove the popup menu.
+ */
+ static void
+ins_compl_upd_pum(void)
+{
+ int h;
+
+ if (compl_match_array != NULL)
+ {
+ h = curwin->w_cline_height;
+ // Update the screen later, before drawing the popup menu over it.
+ pum_call_update_screen();
+ if (h != curwin->w_cline_height)
+ ins_compl_del_pum();
+ }
+}
+
+/*
+ * Remove any popup menu.
+ */
+ static void
+ins_compl_del_pum(void)
+{
+ if (compl_match_array != NULL)
+ {
+ pum_undisplay();
+ VIM_CLEAR(compl_match_array);
+ }
+}
+
+/*
+ * Return TRUE if the popup menu should be displayed.
+ */
+ static int
+pum_wanted(void)
+{
+ /* 'completeopt' must contain "menu" or "menuone" */
+ if (vim_strchr(p_cot, 'm') == NULL)
+ return FALSE;
+
+ /* The display looks bad on a B&W display. */
+ if (t_colors < 8
+#ifdef FEAT_GUI
+ && !gui.in_use
+#endif
+ )
+ return FALSE;
+ return TRUE;
+}
+
+/*
+ * Return TRUE if there are two or more matches to be shown in the popup menu.
+ * One if 'completopt' contains "menuone".
+ */
+ static int
+pum_enough_matches(void)
+{
+ compl_T *compl;
+ int i;
+
+ /* Don't display the popup menu if there are no matches or there is only
+ * one (ignoring the original text). */
+ compl = compl_first_match;
+ i = 0;
+ do
+ {
+ if (compl == NULL
+ || ((compl->cp_flags & ORIGINAL_TEXT) == 0 && ++i == 2))
+ break;
+ compl = compl->cp_next;
+ } while (compl != compl_first_match);
+
+ if (strstr((char *)p_cot, "menuone") != NULL)
+ return (i >= 1);
+ return (i >= 2);
+}
+
+/*
+ * Show the popup menu for the list of matches.
+ * Also adjusts "compl_shown_match" to an entry that is actually displayed.
+ */
+ void
+ins_compl_show_pum(void)
+{
+ compl_T *compl;
+ compl_T *shown_compl = NULL;
+ int did_find_shown_match = FALSE;
+ int shown_match_ok = FALSE;
+ int i;
+ int cur = -1;
+ colnr_T col;
+ int lead_len = 0;
+
+ if (!pum_wanted() || !pum_enough_matches())
+ return;
+
+#if defined(FEAT_EVAL)
+ /* Dirty hard-coded hack: remove any matchparen highlighting. */
+ do_cmdline_cmd((char_u *)"if exists('g:loaded_matchparen')|3match none|endif");
+#endif
+
+ // Update the screen later, before drawing the popup menu over it.
+ pum_call_update_screen();
+
+ if (compl_match_array == NULL)
+ {
+ /* Need to build the popup menu list. */
+ compl_match_arraysize = 0;
+ compl = compl_first_match;
+ if (compl_leader != NULL)
+ lead_len = (int)STRLEN(compl_leader);
+ do
+ {
+ if ((compl->cp_flags & ORIGINAL_TEXT) == 0
+ && (compl_leader == NULL
+ || ins_compl_equal(compl, compl_leader, lead_len)))
+ ++compl_match_arraysize;
+ compl = compl->cp_next;
+ } while (compl != NULL && compl != compl_first_match);
+ if (compl_match_arraysize == 0)
+ return;
+ compl_match_array = (pumitem_T *)alloc_clear(
+ (unsigned)(sizeof(pumitem_T)
+ * compl_match_arraysize));
+ if (compl_match_array != NULL)
+ {
+ /* If the current match is the original text don't find the first
+ * match after it, don't highlight anything. */
+ if (compl_shown_match->cp_flags & ORIGINAL_TEXT)
+ shown_match_ok = TRUE;
+
+ i = 0;
+ compl = compl_first_match;
+ do
+ {
+ if ((compl->cp_flags & ORIGINAL_TEXT) == 0
+ && (compl_leader == NULL
+ || ins_compl_equal(compl, compl_leader, lead_len)))
+ {
+ if (!shown_match_ok)
+ {
+ if (compl == compl_shown_match || did_find_shown_match)
+ {
+ /* This item is the shown match or this is the
+ * first displayed item after the shown match. */
+ compl_shown_match = compl;
+ did_find_shown_match = TRUE;
+ shown_match_ok = TRUE;
+ }
+ else
+ /* Remember this displayed match for when the
+ * shown match is just below it. */
+ shown_compl = compl;
+ cur = i;
+ }
+
+ if (compl->cp_text[CPT_ABBR] != NULL)
+ compl_match_array[i].pum_text =
+ compl->cp_text[CPT_ABBR];
+ else
+ compl_match_array[i].pum_text = compl->cp_str;
+ compl_match_array[i].pum_kind = compl->cp_text[CPT_KIND];
+ compl_match_array[i].pum_info = compl->cp_text[CPT_INFO];
+ if (compl->cp_text[CPT_MENU] != NULL)
+ compl_match_array[i++].pum_extra =
+ compl->cp_text[CPT_MENU];
+ else
+ compl_match_array[i++].pum_extra = compl->cp_fname;
+ }
+
+ if (compl == compl_shown_match)
+ {
+ did_find_shown_match = TRUE;
+
+ /* When the original text is the shown match don't set
+ * compl_shown_match. */
+ if (compl->cp_flags & ORIGINAL_TEXT)
+ shown_match_ok = TRUE;
+
+ if (!shown_match_ok && shown_compl != NULL)
+ {
+ /* The shown match isn't displayed, set it to the
+ * previously displayed match. */
+ compl_shown_match = shown_compl;
+ shown_match_ok = TRUE;
+ }
+ }
+ compl = compl->cp_next;
+ } while (compl != NULL && compl != compl_first_match);
+
+ if (!shown_match_ok) /* no displayed match at all */
+ cur = -1;
+ }
+ }
+ else
+ {
+ /* popup menu already exists, only need to find the current item.*/
+ for (i = 0; i < compl_match_arraysize; ++i)
+ if (compl_match_array[i].pum_text == compl_shown_match->cp_str
+ || compl_match_array[i].pum_text
+ == compl_shown_match->cp_text[CPT_ABBR])
+ {
+ cur = i;
+ break;
+ }
+ }
+
+ if (compl_match_array != NULL)
+ {
+ /* In Replace mode when a $ is displayed at the end of the line only
+ * part of the screen would be updated. We do need to redraw here. */
+ dollar_vcol = -1;
+
+ /* Compute the screen column of the start of the completed text.
+ * Use the cursor to get all wrapping and other settings right. */
+ col = curwin->w_cursor.col;
+ curwin->w_cursor.col = compl_col;
+ pum_display(compl_match_array, compl_match_arraysize, cur);
+ curwin->w_cursor.col = col;
+ }
+}
+
+#define DICT_FIRST (1) /* use just first element in "dict" */
+#define DICT_EXACT (2) /* "dict" is the exact name of a file */
+
+/*
+ * Add any identifiers that match the given pattern in the list of dictionary
+ * files "dict_start" to the list of completions.
+ */
+ static void
+ins_compl_dictionaries(
+ char_u *dict_start,
+ char_u *pat,
+ int flags, /* DICT_FIRST and/or DICT_EXACT */
+ int thesaurus) /* Thesaurus completion */
+{
+ char_u *dict = dict_start;
+ char_u *ptr;
+ char_u *buf;
+ regmatch_T regmatch;
+ char_u **files;
+ int count;
+ int save_p_scs;
+ int dir = compl_direction;
+
+ if (*dict == NUL)
+ {
+#ifdef FEAT_SPELL
+ /* When 'dictionary' is empty and spell checking is enabled use
+ * "spell". */
+ if (!thesaurus && curwin->w_p_spell)
+ dict = (char_u *)"spell";
+ else
+#endif
+ return;
+ }
+
+ buf = alloc(LSIZE);
+ if (buf == NULL)
+ return;
+ regmatch.regprog = NULL; /* so that we can goto theend */
+
+ /* If 'infercase' is set, don't use 'smartcase' here */
+ save_p_scs = p_scs;
+ if (curbuf->b_p_inf)
+ p_scs = FALSE;
+
+ /* When invoked to match whole lines for CTRL-X CTRL-L adjust the pattern
+ * to only match at the start of a line. Otherwise just match the
+ * pattern. Also need to double backslashes. */
+ if (CTRL_X_MODE_LINE_OR_EVAL(ctrl_x_mode))
+ {
+ char_u *pat_esc = vim_strsave_escaped(pat, (char_u *)"\\");
+ size_t len;
+
+ if (pat_esc == NULL)
+ goto theend;
+ len = STRLEN(pat_esc) + 10;
+ ptr = alloc((unsigned)len);
+ if (ptr == NULL)
+ {
+ vim_free(pat_esc);
+ goto theend;
+ }
+ vim_snprintf((char *)ptr, len, "^\\s*\\zs\\V%s", pat_esc);
+ regmatch.regprog = vim_regcomp(ptr, RE_MAGIC);
+ vim_free(pat_esc);
+ vim_free(ptr);
+ }
+ else
+ {
+ regmatch.regprog = vim_regcomp(pat, p_magic ? RE_MAGIC : 0);
+ if (regmatch.regprog == NULL)
+ goto theend;
+ }
+
+ /* ignore case depends on 'ignorecase', 'smartcase' and "pat" */
+ regmatch.rm_ic = ignorecase(pat);
+ while (*dict != NUL && !got_int && !compl_interrupted)
+ {
+ /* copy one dictionary file name into buf */
+ if (flags == DICT_EXACT)
+ {
+ count = 1;
+ files = &dict;
+ }
+ else
+ {
+ /* Expand wildcards in the dictionary name, but do not allow
+ * backticks (for security, the 'dict' option may have been set in
+ * a modeline). */
+ copy_option_part(&dict, buf, LSIZE, ",");
+# ifdef FEAT_SPELL
+ if (!thesaurus && STRCMP(buf, "spell") == 0)
+ count = -1;
+ else
+# endif
+ if (vim_strchr(buf, '`') != NULL
+ || expand_wildcards(1, &buf, &count, &files,
+ EW_FILE|EW_SILENT) != OK)
+ count = 0;
+ }
+
+# ifdef FEAT_SPELL
+ if (count == -1)
+ {
+ /* Complete from active spelling. Skip "\<" in the pattern, we
+ * don't use it as a RE. */
+ if (pat[0] == '\\' && pat[1] == '<')
+ ptr = pat + 2;
+ else
+ ptr = pat;
+ spell_dump_compl(ptr, regmatch.rm_ic, &dir, 0);
+ }
+ else
+# endif
+ if (count > 0) /* avoid warning for using "files" uninit */
+ {
+ ins_compl_files(count, files, thesaurus, flags,
+ &regmatch, buf, &dir);
+ if (flags != DICT_EXACT)
+ FreeWild(count, files);
+ }
+ if (flags != 0)
+ break;
+ }
+
+theend:
+ p_scs = save_p_scs;
+ vim_regfree(regmatch.regprog);
+ vim_free(buf);
+}
+
+ static void
+ins_compl_files(
+ int count,
+ char_u **files,
+ int thesaurus,
+ int flags,
+ regmatch_T *regmatch,
+ char_u *buf,
+ int *dir)
+{
+ char_u *ptr;
+ int i;
+ FILE *fp;
+ int add_r;
+
+ for (i = 0; i < count && !got_int && !compl_interrupted; i++)
+ {
+ fp = mch_fopen((char *)files[i], "r"); /* open dictionary file */
+ if (flags != DICT_EXACT)
+ {
+ vim_snprintf((char *)IObuff, IOSIZE,
+ _("Scanning dictionary: %s"), (char *)files[i]);
+ (void)msg_trunc_attr((char *)IObuff, TRUE, HL_ATTR(HLF_R));
+ }
+
+ if (fp != NULL)
+ {
+ /*
+ * Read dictionary file line by line.
+ * Check each line for a match.
+ */
+ while (!got_int && !compl_interrupted
+ && !vim_fgets(buf, LSIZE, fp))
+ {
+ ptr = buf;
+ while (vim_regexec(regmatch, buf, (colnr_T)(ptr - buf)))
+ {
+ ptr = regmatch->startp[0];
+ if (CTRL_X_MODE_LINE_OR_EVAL(ctrl_x_mode))
+ ptr = find_line_end(ptr);
+ else
+ ptr = find_word_end(ptr);
+ add_r = ins_compl_add_infercase(regmatch->startp[0],
+ (int)(ptr - regmatch->startp[0]),
+ p_ic, files[i], *dir, 0);
+ if (thesaurus)
+ {
+ char_u *wstart;
+
+ /*
+ * Add the other matches on the line
+ */
+ ptr = buf;
+ while (!got_int)
+ {
+ /* Find start of the next word. Skip white
+ * space and punctuation. */
+ ptr = find_word_start(ptr);
+ if (*ptr == NUL || *ptr == NL)
+ break;
+ wstart = ptr;
+
+ /* Find end of the word. */
+ if (has_mbyte)
+ /* Japanese words may have characters in
+ * different classes, only separate words
+ * with single-byte non-word characters. */
+ while (*ptr != NUL)
+ {
+ int l = (*mb_ptr2len)(ptr);
+
+ if (l < 2 && !vim_iswordc(*ptr))
+ break;
+ ptr += l;
+ }
+ else
+ ptr = find_word_end(ptr);
+
+ /* Add the word. Skip the regexp match. */
+ if (wstart != regmatch->startp[0])
+ add_r = ins_compl_add_infercase(wstart,
+ (int)(ptr - wstart),
+ p_ic, files[i], *dir, 0);
+ }
+ }
+ if (add_r == OK)
+ /* if dir was BACKWARD then honor it just once */
+ *dir = FORWARD;
+ else if (add_r == FAIL)
+ break;
+ /* avoid expensive call to vim_regexec() when at end
+ * of line */
+ if (*ptr == '\n' || got_int)
+ break;
+ }
+ line_breakcheck();
+ ins_compl_check_keys(50, FALSE);
+ }
+ fclose(fp);
+ }
+ }
+}
+
+/*
+ * Find the start of the next word.
+ * Returns a pointer to the first char of the word. Also stops at a NUL.
+ */
+ char_u *
+find_word_start(char_u *ptr)
+{
+ if (has_mbyte)
+ while (*ptr != NUL && *ptr != '\n' && mb_get_class(ptr) <= 1)
+ ptr += (*mb_ptr2len)(ptr);
+ else
+ while (*ptr != NUL && *ptr != '\n' && !vim_iswordc(*ptr))
+ ++ptr;
+ return ptr;
+}
+
+/*
+ * Find the end of the word. Assumes it starts inside a word.
+ * Returns a pointer to just after the word.
+ */
+ char_u *
+find_word_end(char_u *ptr)
+{
+ int start_class;
+
+ if (has_mbyte)
+ {
+ start_class = mb_get_class(ptr);
+ if (start_class > 1)
+ while (*ptr != NUL)
+ {
+ ptr += (*mb_ptr2len)(ptr);
+ if (mb_get_class(ptr) != start_class)
+ break;
+ }
+ }
+ else
+ while (vim_iswordc(*ptr))
+ ++ptr;
+ return ptr;
+}
+
+/*
+ * Find the end of the line, omitting CR and NL at the end.
+ * Returns a pointer to just after the line.
+ */
+ static char_u *
+find_line_end(char_u *ptr)
+{
+ char_u *s;
+
+ s = ptr + STRLEN(ptr);
+ while (s > ptr && (s[-1] == CAR || s[-1] == NL))
+ --s;
+ return s;
+}
+
+/*
+ * Free the list of completions
+ */
+ static void
+ins_compl_free(void)
+{
+ compl_T *match;
+ int i;
+
+ VIM_CLEAR(compl_pattern);
+ VIM_CLEAR(compl_leader);
+
+ if (compl_first_match == NULL)
+ return;
+
+ ins_compl_del_pum();
+ pum_clear();
+
+ compl_curr_match = compl_first_match;
+ do
+ {
+ match = compl_curr_match;
+ compl_curr_match = compl_curr_match->cp_next;
+ vim_free(match->cp_str);
+ /* several entries may use the same fname, free it just once. */
+ if (match->cp_flags & FREE_FNAME)
+ vim_free(match->cp_fname);
+ for (i = 0; i < CPT_COUNT; ++i)
+ vim_free(match->cp_text[i]);
+ vim_free(match);
+ } while (compl_curr_match != NULL && compl_curr_match != compl_first_match);
+ compl_first_match = compl_curr_match = NULL;
+ compl_shown_match = NULL;
+ compl_old_match = NULL;
+}
+
+ static void
+ins_compl_clear(void)
+{
+ compl_cont_status = 0;
+ compl_started = FALSE;
+ compl_matches = 0;
+ VIM_CLEAR(compl_pattern);
+ VIM_CLEAR(compl_leader);
+ edit_submode_extra = NULL;
+ VIM_CLEAR(compl_orig_text);
+ compl_enter_selects = FALSE;
+ /* clear v:completed_item */
+ set_vim_var_dict(VV_COMPLETED_ITEM, dict_alloc_lock(VAR_FIXED));
+}
+
+/*
+ * Return TRUE when Insert completion is active.
+ */
+ int
+ins_compl_active(void)
+{
+ return compl_started;
+}
+
+/*
+ * Delete one character before the cursor and show the subset of the matches
+ * that match the word that is now before the cursor.
+ * Returns the character to be used, NUL if the work is done and another char
+ * to be got from the user.
+ */
+ static int
+ins_compl_bs(void)
+{
+ char_u *line;
+ char_u *p;
+
+ line = ml_get_curline();
+ p = line + curwin->w_cursor.col;
+ MB_PTR_BACK(line, p);
+
+ /* Stop completion when the whole word was deleted. For Omni completion
+ * allow the word to be deleted, we won't match everything.
+ * Respect the 'backspace' option. */
+ if ((int)(p - line) - (int)compl_col < 0
+ || ((int)(p - line) - (int)compl_col == 0
+ && ctrl_x_mode != CTRL_X_OMNI) || ctrl_x_mode == CTRL_X_EVAL
+ || (!can_bs(BS_START) && (int)(p - line) - (int)compl_col
+ - compl_length < 0))
+ return K_BS;
+
+ /* Deleted more than what was used to find matches or didn't finish
+ * finding all matches: need to look for matches all over again. */
+ if (curwin->w_cursor.col <= compl_col + compl_length
+ || ins_compl_need_restart())
+ ins_compl_restart();
+
+ vim_free(compl_leader);
+ compl_leader = vim_strnsave(line + compl_col, (int)(p - line) - compl_col);
+ if (compl_leader != NULL)
+ {
+ ins_compl_new_leader();
+ if (compl_shown_match != NULL)
+ /* Make sure current match is not a hidden item. */
+ compl_curr_match = compl_shown_match;
+ return NUL;
+ }
+ return K_BS;
+}
+
+/*
+ * Return TRUE when we need to find matches again, ins_compl_restart() is to
+ * be called.
+ */
+ static int
+ins_compl_need_restart(void)
+{
+ /* Return TRUE if we didn't complete finding matches or when the
+ * 'completefunc' returned "always" in the "refresh" dictionary item. */
+ return compl_was_interrupted
+ || ((ctrl_x_mode == CTRL_X_FUNCTION || ctrl_x_mode == CTRL_X_OMNI)
+ && compl_opt_refresh_always);
+}
+
+/*
+ * Called after changing "compl_leader".
+ * Show the popup menu with a different set of matches.
+ * May also search for matches again if the previous search was interrupted.
+ */
+ static void
+ins_compl_new_leader(void)
+{
+ ins_compl_del_pum();
+ ins_compl_delete();
+ ins_bytes(compl_leader + ins_compl_len());
+ compl_used_match = FALSE;
+
+ if (compl_started)
+ ins_compl_set_original_text(compl_leader);
+ else
+ {
+#ifdef FEAT_SPELL
+ spell_bad_len = 0; /* need to redetect bad word */
+#endif
+ /*
+ * Matches were cleared, need to search for them now. Befor drawing
+ * the popup menu display the changed text before the cursor. Set
+ * "compl_restarting" to avoid that the first match is inserted.
+ */
+ pum_call_update_screen();
+#ifdef FEAT_GUI
+ if (gui.in_use)
+ {
+ /* Show the cursor after the match, not after the redrawn text. */
+ setcursor();
+ out_flush_cursor(FALSE, FALSE);
+ }
+#endif
+ compl_restarting = TRUE;
+ if (ins_complete(Ctrl_N, TRUE) == FAIL)
+ compl_cont_status = 0;
+ compl_restarting = FALSE;
+ }
+
+ compl_enter_selects = !compl_used_match;
+
+ /* Show the popup menu with a different set of matches. */
+ ins_compl_show_pum();
+
+ /* Don't let Enter select the original text when there is no popup menu. */
+ if (compl_match_array == NULL)
+ compl_enter_selects = FALSE;
+}
+
+/*
+ * Return the length of the completion, from the completion start column to
+ * the cursor column. Making sure it never goes below zero.
+ */
+ static int
+ins_compl_len(void)
+{
+ int off = (int)curwin->w_cursor.col - (int)compl_col;
+
+ if (off < 0)
+ return 0;
+ return off;
+}
+
+/*
+ * Append one character to the match leader. May reduce the number of
+ * matches.
+ */
+ static void
+ins_compl_addleader(int c)
+{
+ int cc;
+
+ if (stop_arrow() == FAIL)
+ return;
+ if (has_mbyte && (cc = (*mb_char2len)(c)) > 1)
+ {
+ char_u buf[MB_MAXBYTES + 1];
+
+ (*mb_char2bytes)(c, buf);
+ buf[cc] = NUL;
+ ins_char_bytes(buf, cc);
+ if (compl_opt_refresh_always)
+ AppendToRedobuff(buf);
+ }
+ else
+ {
+ ins_char(c);
+ if (compl_opt_refresh_always)
+ AppendCharToRedobuff(c);
+ }
+
+ /* If we didn't complete finding matches we must search again. */
+ if (ins_compl_need_restart())
+ ins_compl_restart();
+
+ /* When 'always' is set, don't reset compl_leader. While completing,
+ * cursor doesn't point original position, changing compl_leader would
+ * break redo. */
+ if (!compl_opt_refresh_always)
+ {
+ vim_free(compl_leader);
+ compl_leader = vim_strnsave(ml_get_curline() + compl_col,
+ (int)(curwin->w_cursor.col - compl_col));
+ if (compl_leader != NULL)
+ ins_compl_new_leader();
+ }
+}
+
+/*
+ * Setup for finding completions again without leaving CTRL-X mode. Used when
+ * BS or a key was typed while still searching for matches.
+ */
+ static void
+ins_compl_restart(void)
+{
+ ins_compl_free();
+ compl_started = FALSE;
+ compl_matches = 0;
+ compl_cont_status = 0;
+ compl_cont_mode = 0;
+}
+
+/*
+ * Set the first match, the original text.
+ */
+ static void
+ins_compl_set_original_text(char_u *str)
+{
+ char_u *p;
+
+ /* Replace the original text entry.
+ * The ORIGINAL_TEXT flag is either at the first item or might possibly be
+ * at the last item for backward completion */
+ if (compl_first_match->cp_flags & ORIGINAL_TEXT) /* safety check */
+ {
+ p = vim_strsave(str);
+ if (p != NULL)
+ {
+ vim_free(compl_first_match->cp_str);
+ compl_first_match->cp_str = p;
+ }
+ }
+ else if (compl_first_match->cp_prev != NULL
+ && (compl_first_match->cp_prev->cp_flags & ORIGINAL_TEXT))
+ {
+ p = vim_strsave(str);
+ if (p != NULL)
+ {
+ vim_free(compl_first_match->cp_prev->cp_str);
+ compl_first_match->cp_prev->cp_str = p;
+ }
+ }
+}
+
+/*
+ * Append one character to the match leader. May reduce the number of
+ * matches.
+ */
+ static void
+ins_compl_addfrommatch(void)
+{
+ char_u *p;
+ int len = (int)curwin->w_cursor.col - (int)compl_col;
+ int c;
+ compl_T *cp;
+
+ p = compl_shown_match->cp_str;
+ if ((int)STRLEN(p) <= len) /* the match is too short */
+ {
+ /* When still at the original match use the first entry that matches
+ * the leader. */
+ if (compl_shown_match->cp_flags & ORIGINAL_TEXT)
+ {
+ p = NULL;
+ for (cp = compl_shown_match->cp_next; cp != NULL
+ && cp != compl_first_match; cp = cp->cp_next)
+ {
+ if (compl_leader == NULL
+ || ins_compl_equal(cp, compl_leader,
+ (int)STRLEN(compl_leader)))
+ {
+ p = cp->cp_str;
+ break;
+ }
+ }
+ if (p == NULL || (int)STRLEN(p) <= len)
+ return;
+ }
+ else
+ return;
+ }
+ p += len;
+ c = PTR2CHAR(p);
+ ins_compl_addleader(c);
+}
+
+/*
+ * Prepare for Insert mode completion, or stop it.
+ * Called just after typing a character in Insert mode.
+ * Returns TRUE when the character is not to be inserted;
+ */
+ static int
+ins_compl_prep(int c)
+{
+ char_u *ptr;
+ int want_cindent;
+ int retval = FALSE;
+
+ /* Forget any previous 'special' messages if this is actually
+ * a ^X mode key - bar ^R, in which case we wait to see what it gives us.
+ */
+ if (c != Ctrl_R && vim_is_ctrl_x_key(c))
+ edit_submode_extra = NULL;
+
+ /* Ignore end of Select mode mapping and mouse scroll buttons. */
+ if (c == K_SELECT || c == K_MOUSEDOWN || c == K_MOUSEUP
+ || c == K_MOUSELEFT || c == K_MOUSERIGHT)
+ return retval;
+
+ /* Set "compl_get_longest" when finding the first matches. */
+ if (ctrl_x_mode == CTRL_X_NOT_DEFINED_YET
+ || (ctrl_x_mode == CTRL_X_NORMAL && !compl_started))
+ {
+ compl_get_longest = (strstr((char *)p_cot, "longest") != NULL);
+ compl_used_match = TRUE;
+
+ }
+
+ if (ctrl_x_mode == CTRL_X_NOT_DEFINED_YET)
+ {
+ /*
+ * We have just typed CTRL-X and aren't quite sure which CTRL-X mode
+ * it will be yet. Now we decide.
+ */
+ switch (c)
+ {
+ case Ctrl_E:
+ case Ctrl_Y:
+ ctrl_x_mode = CTRL_X_SCROLL;
+ if (!(State & REPLACE_FLAG))
+ edit_submode = (char_u *)_(" (insert) Scroll (^E/^Y)");
+ else
+ edit_submode = (char_u *)_(" (replace) Scroll (^E/^Y)");
+ edit_submode_pre = NULL;
+ showmode();
+ break;
+ case Ctrl_L:
+ ctrl_x_mode = CTRL_X_WHOLE_LINE;
+ break;
+ case Ctrl_F:
+ ctrl_x_mode = CTRL_X_FILES;
+ break;
+ case Ctrl_K:
+ ctrl_x_mode = CTRL_X_DICTIONARY;
+ break;
+ case Ctrl_R:
+ /* Simply allow ^R to happen without affecting ^X mode */
+ break;
+ case Ctrl_T:
+ ctrl_x_mode = CTRL_X_THESAURUS;
+ break;
+#ifdef FEAT_COMPL_FUNC
+ case Ctrl_U:
+ ctrl_x_mode = CTRL_X_FUNCTION;
+ break;
+ case Ctrl_O:
+ ctrl_x_mode = CTRL_X_OMNI;
+ break;
+#endif
+ case 's':
+ case Ctrl_S:
+ ctrl_x_mode = CTRL_X_SPELL;
+#ifdef FEAT_SPELL
+ ++emsg_off; /* Avoid getting the E756 error twice. */
+ spell_back_to_badword();
+ --emsg_off;
+#endif
+ break;
+ case Ctrl_RSB:
+ ctrl_x_mode = CTRL_X_TAGS;
+ break;
+#ifdef FEAT_FIND_ID
+ case Ctrl_I:
+ case K_S_TAB:
+ ctrl_x_mode = CTRL_X_PATH_PATTERNS;
+ break;
+ case Ctrl_D:
+ ctrl_x_mode = CTRL_X_PATH_DEFINES;
+ break;
+#endif
+ case Ctrl_V:
+ case Ctrl_Q:
+ ctrl_x_mode = CTRL_X_CMDLINE;
+ break;
+ case Ctrl_P:
+ case Ctrl_N:
+ /* ^X^P means LOCAL expansion if nothing interrupted (eg we
+ * just started ^X mode, or there were enough ^X's to cancel
+ * the previous mode, say ^X^F^X^X^P or ^P^X^X^X^P, see below)
+ * do normal expansion when interrupting a different mode (say
+ * ^X^F^X^P or ^P^X^X^P, see below)
+ * nothing changes if interrupting mode 0, (eg, the flag
+ * doesn't change when going to ADDING mode -- Acevedo */
+ if (!(compl_cont_status & CONT_INTRPT))
+ compl_cont_status |= CONT_LOCAL;
+ else if (compl_cont_mode != 0)
+ compl_cont_status &= ~CONT_LOCAL;
+ /* FALLTHROUGH */
+ default:
+ /* If we have typed at least 2 ^X's... for modes != 0, we set
+ * compl_cont_status = 0 (eg, as if we had just started ^X
+ * mode).
+ * For mode 0, we set "compl_cont_mode" to an impossible
+ * value, in both cases ^X^X can be used to restart the same
+ * mode (avoiding ADDING mode).
+ * Undocumented feature: In a mode != 0 ^X^P and ^X^X^P start
+ * 'complete' and local ^P expansions respectively.
+ * In mode 0 an extra ^X is needed since ^X^P goes to ADDING
+ * mode -- Acevedo */
+ if (c == Ctrl_X)
+ {
+ if (compl_cont_mode != 0)
+ compl_cont_status = 0;
+ else
+ compl_cont_mode = CTRL_X_NOT_DEFINED_YET;
+ }
+ ctrl_x_mode = CTRL_X_NORMAL;
+ edit_submode = NULL;
+ showmode();
+ break;
+ }
+ }
+ else if (ctrl_x_mode != CTRL_X_NORMAL)
+ {
+ /* We're already in CTRL-X mode, do we stay in it? */
+ if (!vim_is_ctrl_x_key(c))
+ {
+ if (ctrl_x_mode == CTRL_X_SCROLL)
+ ctrl_x_mode = CTRL_X_NORMAL;
+ else
+ ctrl_x_mode = CTRL_X_FINISHED;
+ edit_submode = NULL;
+ }
+ showmode();
+ }
+
+ if (compl_started || ctrl_x_mode == CTRL_X_FINISHED)
+ {
+ /* Show error message from attempted keyword completion (probably
+ * 'Pattern not found') until another key is hit, then go back to
+ * showing what mode we are in. */
+ showmode();
+ if ((ctrl_x_mode == CTRL_X_NORMAL && c != Ctrl_N && c != Ctrl_P
+ && c != Ctrl_R && !ins_compl_pum_key(c))
+ || ctrl_x_mode == CTRL_X_FINISHED)
+ {
+ /* Get here when we have finished typing a sequence of ^N and
+ * ^P or other completion characters in CTRL-X mode. Free up
+ * memory that was used, and make sure we can redo the insert. */
+ if (compl_curr_match != NULL || compl_leader != NULL || c == Ctrl_E)
+ {
+ /*
+ * If any of the original typed text has been changed, eg when
+ * ignorecase is set, we must add back-spaces to the redo
+ * buffer. We add as few as necessary to delete just the part
+ * of the original text that has changed.
+ * When using the longest match, edited the match or used
+ * CTRL-E then don't use the current match.
+ */
+ if (compl_curr_match != NULL && compl_used_match && c != Ctrl_E)
+ ptr = compl_curr_match->cp_str;
+ else
+ ptr = NULL;
+ ins_compl_fixRedoBufForLeader(ptr);
+ }
+
+#ifdef FEAT_CINDENT
+ want_cindent = (can_cindent && cindent_on());
+#endif
+ /*
+ * When completing whole lines: fix indent for 'cindent'.
+ * Otherwise, break line if it's too long.
+ */
+ if (compl_cont_mode == CTRL_X_WHOLE_LINE)
+ {
+#ifdef FEAT_CINDENT
+ /* re-indent the current line */
+ if (want_cindent)
+ {
+ do_c_expr_indent();
+ want_cindent = FALSE; /* don't do it again */
+ }
+#endif
+ }
+ else
+ {
+ int prev_col = curwin->w_cursor.col;
+
+ /* put the cursor on the last char, for 'tw' formatting */
+ if (prev_col > 0)
+ dec_cursor();
+ /* only format when something was inserted */
+ if (!arrow_used && !ins_need_undo && c != Ctrl_E)
+ insertchar(NUL, 0, -1);
+ if (prev_col > 0
+ && ml_get_curline()[curwin->w_cursor.col] != NUL)
+ inc_cursor();
+ }
+
+ /* If the popup menu is displayed pressing CTRL-Y means accepting
+ * the selection without inserting anything. When
+ * compl_enter_selects is set the Enter key does the same. */
+ if ((c == Ctrl_Y || (compl_enter_selects
+ && (c == CAR || c == K_KENTER || c == NL)))
+ && pum_visible())
+ retval = TRUE;
+
+ /* CTRL-E means completion is Ended, go back to the typed text.
+ * but only do this, if the Popup is still visible */
+ if (c == Ctrl_E)
+ {
+ ins_compl_delete();
+ if (compl_leader != NULL)
+ ins_bytes(compl_leader + ins_compl_len());
+ else if (compl_first_match != NULL)
+ ins_bytes(compl_orig_text + ins_compl_len());
+ retval = TRUE;
+ }
+
+ auto_format(FALSE, TRUE);
+
+ ins_compl_free();
+ compl_started = FALSE;
+ compl_matches = 0;
+ if (!shortmess(SHM_COMPLETIONMENU))
+ msg_clr_cmdline(); /* necessary for "noshowmode" */
+ ctrl_x_mode = CTRL_X_NORMAL;
+ compl_enter_selects = FALSE;
+ if (edit_submode != NULL)
+ {
+ edit_submode = NULL;
+ showmode();
+ }
+
+#ifdef FEAT_CMDWIN
+ if (c == Ctrl_C && cmdwin_type != 0)
+ /* Avoid the popup menu remains displayed when leaving the
+ * command line window. */
+ update_screen(0);
+#endif
+#ifdef FEAT_CINDENT
+ /*
+ * Indent now if a key was typed that is in 'cinkeys'.
+ */
+ if (want_cindent && in_cinkeys(KEY_COMPLETE, ' ', inindent(0)))
+ do_c_expr_indent();
+#endif
+ /* Trigger the CompleteDone event to give scripts a chance to act
+ * upon the completion. */
+ ins_apply_autocmds(EVENT_COMPLETEDONE);
+ }
+ }
+ else if (ctrl_x_mode == CTRL_X_LOCAL_MSG)
+ /* Trigger the CompleteDone event to give scripts a chance to act
+ * upon the (possibly failed) completion. */
+ ins_apply_autocmds(EVENT_COMPLETEDONE);
+
+ /* reset continue_* if we left expansion-mode, if we stay they'll be
+ * (re)set properly in ins_complete() */
+ if (!vim_is_ctrl_x_key(c))
+ {
+ compl_cont_status = 0;
+ compl_cont_mode = 0;
+ }
+
+ return retval;
+}
+
+/*
+ * Fix the redo buffer for the completion leader replacing some of the typed
+ * text. This inserts backspaces and appends the changed text.
+ * "ptr" is the known leader text or NUL.
+ */
+ static void
+ins_compl_fixRedoBufForLeader(char_u *ptr_arg)
+{
+ int len;
+ char_u *p;
+ char_u *ptr = ptr_arg;
+
+ if (ptr == NULL)
+ {
+ if (compl_leader != NULL)
+ ptr = compl_leader;
+ else
+ return; /* nothing to do */
+ }
+ if (compl_orig_text != NULL)
+ {
+ p = compl_orig_text;
+ for (len = 0; p[len] != NUL && p[len] == ptr[len]; ++len)
+ ;
+ if (len > 0)
+ len -= (*mb_head_off)(p, p + len);
+ for (p += len; *p != NUL; MB_PTR_ADV(p))
+ AppendCharToRedobuff(K_BS);
+ }
+ else
+ len = 0;
+ if (ptr != NULL)
+ AppendToRedobuffLit(ptr + len, -1);
+}
+
+/*
+ * Loops through the list of windows, loaded-buffers or non-loaded-buffers
+ * (depending on flag) starting from buf and looking for a non-scanned
+ * buffer (other than curbuf). curbuf is special, if it is called with
+ * buf=curbuf then it has to be the first call for a given flag/expansion.
+ *
+ * Returns the buffer to scan, if any, otherwise returns curbuf -- Acevedo
+ */
+ static buf_T *
+ins_compl_next_buf(buf_T *buf, int flag)
+{
+ static win_T *wp;
+
+ if (flag == 'w') /* just windows */
+ {
+ if (buf == curbuf) /* first call for this flag/expansion */
+ wp = curwin;
+ while ((wp = (wp->w_next != NULL ? wp->w_next : firstwin)) != curwin
+ && wp->w_buffer->b_scanned)
+ ;
+ buf = wp->w_buffer;
+ }
+ else
+ /* 'b' (just loaded buffers), 'u' (just non-loaded buffers) or 'U'
+ * (unlisted buffers)
+ * When completing whole lines skip unloaded buffers. */
+ while ((buf = (buf->b_next != NULL ? buf->b_next : firstbuf)) != curbuf
+ && ((flag == 'U'
+ ? buf->b_p_bl
+ : (!buf->b_p_bl
+ || (buf->b_ml.ml_mfp == NULL) != (flag == 'u')))
+ || buf->b_scanned))
+ ;
+ return buf;
+}
+
+#ifdef FEAT_COMPL_FUNC
+/*
+ * Execute user defined complete function 'completefunc' or 'omnifunc', and
+ * get matches in "matches".
+ */
+ static void
+expand_by_function(
+ int type, /* CTRL_X_OMNI or CTRL_X_FUNCTION */
+ char_u *base)
+{
+ list_T *matchlist = NULL;
+ dict_T *matchdict = NULL;
+ typval_T args[3];
+ char_u *funcname;
+ pos_T pos;
+ win_T *curwin_save;
+ buf_T *curbuf_save;
+ typval_T rettv;
+ int save_State = State;
+
+ funcname = (type == CTRL_X_FUNCTION) ? curbuf->b_p_cfu : curbuf->b_p_ofu;
+ if (*funcname == NUL)
+ return;
+
+ /* Call 'completefunc' to obtain the list of matches. */
+ args[0].v_type = VAR_NUMBER;
+ args[0].vval.v_number = 0;
+ args[1].v_type = VAR_STRING;
+ args[1].vval.v_string = base != NULL ? base : (char_u *)"";
+ args[2].v_type = VAR_UNKNOWN;
+
+ pos = curwin->w_cursor;
+ curwin_save = curwin;
+ curbuf_save = curbuf;
+
+ /* Call a function, which returns a list or dict. */
+ if (call_vim_function(funcname, 2, args, &rettv) == OK)
+ {
+ switch (rettv.v_type)
+ {
+ case VAR_LIST:
+ matchlist = rettv.vval.v_list;
+ break;
+ case VAR_DICT:
+ matchdict = rettv.vval.v_dict;
+ break;
+ case VAR_SPECIAL:
+ if (rettv.vval.v_number == VVAL_NONE)
+ compl_opt_suppress_empty = TRUE;
+ // FALLTHROUGH
+ default:
+ // TODO: Give error message?
+ clear_tv(&rettv);
+ break;
+ }
+ }
+
+ if (curwin_save != curwin || curbuf_save != curbuf)
+ {
+ emsg(_(e_complwin));
+ goto theend;
+ }
+ curwin->w_cursor = pos; /* restore the cursor position */
+ validate_cursor();
+ if (!EQUAL_POS(curwin->w_cursor, pos))
+ {
+ emsg(_(e_compldel));
+ goto theend;
+ }
+
+ if (matchlist != NULL)
+ ins_compl_add_list(matchlist);
+ else if (matchdict != NULL)
+ ins_compl_add_dict(matchdict);
+
+theend:
+ // Restore State, it might have been changed.
+ State = save_State;
+
+ if (matchdict != NULL)
+ dict_unref(matchdict);
+ if (matchlist != NULL)
+ list_unref(matchlist);
+}
+#endif /* FEAT_COMPL_FUNC */
+
+#if defined(FEAT_COMPL_FUNC) || defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * Add completions from a list.
+ */
+ static void
+ins_compl_add_list(list_T *list)
+{
+ listitem_T *li;
+ int dir = compl_direction;
+
+ /* Go through the List with matches and add each of them. */
+ for (li = list->lv_first; li != NULL; li = li->li_next)
+ {
+ if (ins_compl_add_tv(&li->li_tv, dir) == OK)
+ /* if dir was BACKWARD then honor it just once */
+ dir = FORWARD;
+ else if (did_emsg)
+ break;
+ }
+}
+
+/*
+ * Add completions from a dict.
+ */
+ static void
+ins_compl_add_dict(dict_T *dict)
+{
+ dictitem_T *di_refresh;
+ dictitem_T *di_words;
+
+ /* Check for optional "refresh" item. */
+ compl_opt_refresh_always = FALSE;
+ di_refresh = dict_find(dict, (char_u *)"refresh", 7);
+ if (di_refresh != NULL && di_refresh->di_tv.v_type == VAR_STRING)
+ {
+ char_u *v = di_refresh->di_tv.vval.v_string;
+
+ if (v != NULL && STRCMP(v, (char_u *)"always") == 0)
+ compl_opt_refresh_always = TRUE;
+ }
+
+ /* Add completions from a "words" list. */
+ di_words = dict_find(dict, (char_u *)"words", 5);
+ if (di_words != NULL && di_words->di_tv.v_type == VAR_LIST)
+ ins_compl_add_list(di_words->di_tv.vval.v_list);
+}
+
+/*
+ * Add a match to the list of matches from a typeval_T.
+ * If the given string is already in the list of completions, then return
+ * NOTDONE, otherwise add it to the list and return OK. If there is an error,
+ * maybe because alloc() returns NULL, then FAIL is returned.
+ */
+ int
+ins_compl_add_tv(typval_T *tv, int dir)
+{
+ char_u *word;
+ int icase = FALSE;
+ int adup = FALSE;
+ int aempty = FALSE;
+ char_u *(cptext[CPT_COUNT]);
+
+ if (tv->v_type == VAR_DICT && tv->vval.v_dict != NULL)
+ {
+ word = dict_get_string(tv->vval.v_dict, (char_u *)"word", FALSE);
+ cptext[CPT_ABBR] = dict_get_string(tv->vval.v_dict,
+ (char_u *)"abbr", FALSE);
+ cptext[CPT_MENU] = dict_get_string(tv->vval.v_dict,
+ (char_u *)"menu", FALSE);
+ cptext[CPT_KIND] = dict_get_string(tv->vval.v_dict,
+ (char_u *)"kind", FALSE);
+ cptext[CPT_INFO] = dict_get_string(tv->vval.v_dict,
+ (char_u *)"info", FALSE);
+ cptext[CPT_USER_DATA] = dict_get_string(tv->vval.v_dict,
+ (char_u *)"user_data", FALSE);
+ if (dict_get_string(tv->vval.v_dict, (char_u *)"icase", FALSE) != NULL)
+ icase = dict_get_number(tv->vval.v_dict, (char_u *)"icase");
+ if (dict_get_string(tv->vval.v_dict, (char_u *)"dup", FALSE) != NULL)
+ adup = dict_get_number(tv->vval.v_dict, (char_u *)"dup");
+ if (dict_get_string(tv->vval.v_dict, (char_u *)"empty", FALSE) != NULL)
+ aempty = dict_get_number(tv->vval.v_dict, (char_u *)"empty");
+ }
+ else
+ {
+ word = tv_get_string_chk(tv);
+ vim_memset(cptext, 0, sizeof(cptext));
+ }
+ if (word == NULL || (!aempty && *word == NUL))
+ return FAIL;
+ return ins_compl_add(word, -1, icase, NULL, cptext, dir, 0, adup);
+}
+#endif
+
+/*
+ * Get the next expansion(s), using "compl_pattern".
+ * The search starts at position "ini" in curbuf and in the direction
+ * compl_direction.
+ * When "compl_started" is FALSE start at that position, otherwise continue
+ * where we stopped searching before.
+ * This may return before finding all the matches.
+ * Return the total number of matches or -1 if still unknown -- Acevedo
+ */
+ static int
+ins_compl_get_exp(pos_T *ini)
+{
+ static pos_T first_match_pos;
+ static pos_T last_match_pos;
+ static char_u *e_cpt = (char_u *)""; /* curr. entry in 'complete' */
+ static int found_all = FALSE; /* Found all matches of a
+ certain type. */
+ static buf_T *ins_buf = NULL; /* buffer being scanned */
+
+ pos_T *pos;
+ char_u **matches;
+ int save_p_scs;
+ int save_p_ws;
+ int save_p_ic;
+ int i;
+ int num_matches;
+ int len;
+ int found_new_match;
+ int type = ctrl_x_mode;
+ char_u *ptr;
+ char_u *dict = NULL;
+ int dict_f = 0;
+ int set_match_pos;
+
+ if (!compl_started)
+ {
+ FOR_ALL_BUFFERS(ins_buf)
+ ins_buf->b_scanned = 0;
+ found_all = FALSE;
+ ins_buf = curbuf;
+ e_cpt = (compl_cont_status & CONT_LOCAL)
+ ? (char_u *)"." : curbuf->b_p_cpt;
+ last_match_pos = first_match_pos = *ini;
+ }
+ else if (ins_buf != curbuf && !buf_valid(ins_buf))
+ ins_buf = curbuf; // In case the buffer was wiped out.
+
+ compl_old_match = compl_curr_match; /* remember the last current match */
+ pos = (compl_direction == FORWARD) ? &last_match_pos : &first_match_pos;
+
+ /*
+ * For ^N/^P loop over all the flags/windows/buffers in 'complete'.
+ */
+ for (;;)
+ {
+ found_new_match = FAIL;
+ set_match_pos = FALSE;
+
+ /* For ^N/^P pick a new entry from e_cpt if compl_started is off,
+ * or if found_all says this entry is done. For ^X^L only use the
+ * entries from 'complete' that look in loaded buffers. */
+ if ((ctrl_x_mode == CTRL_X_NORMAL
+ || CTRL_X_MODE_LINE_OR_EVAL(ctrl_x_mode))
+ && (!compl_started || found_all))
+ {
+ found_all = FALSE;
+ while (*e_cpt == ',' || *e_cpt == ' ')
+ e_cpt++;
+ if (*e_cpt == '.' && !curbuf->b_scanned)
+ {
+ ins_buf = curbuf;
+ first_match_pos = *ini;
+ /* Move the cursor back one character so that ^N can match the
+ * word immediately after the cursor. */
+ if (ctrl_x_mode == CTRL_X_NORMAL && dec(&first_match_pos) < 0)
+ {
+ /* Move the cursor to after the last character in the
+ * buffer, so that word at start of buffer is found
+ * correctly. */
+ first_match_pos.lnum = ins_buf->b_ml.ml_line_count;
+ first_match_pos.col =
+ (colnr_T)STRLEN(ml_get(first_match_pos.lnum));
+ }
+ last_match_pos = first_match_pos;
+ type = 0;
+
+ /* Remember the first match so that the loop stops when we
+ * wrap and come back there a second time. */
+ set_match_pos = TRUE;
+ }
+ else if (vim_strchr((char_u *)"buwU", *e_cpt) != NULL
+ && (ins_buf = ins_compl_next_buf(ins_buf, *e_cpt)) != curbuf)
+ {
+ /* Scan a buffer, but not the current one. */
+ if (ins_buf->b_ml.ml_mfp != NULL) /* loaded buffer */
+ {
+ compl_started = TRUE;
+ first_match_pos.col = last_match_pos.col = 0;
+ first_match_pos.lnum = ins_buf->b_ml.ml_line_count + 1;
+ last_match_pos.lnum = 0;
+ type = 0;
+ }
+ else /* unloaded buffer, scan like dictionary */
+ {
+ found_all = TRUE;
+ if (ins_buf->b_fname == NULL)
+ continue;
+ type = CTRL_X_DICTIONARY;
+ dict = ins_buf->b_fname;
+ dict_f = DICT_EXACT;
+ }
+ vim_snprintf((char *)IObuff, IOSIZE, _("Scanning: %s"),
+ ins_buf->b_fname == NULL
+ ? buf_spname(ins_buf)
+ : ins_buf->b_sfname == NULL
+ ? ins_buf->b_fname
+ : ins_buf->b_sfname);
+ (void)msg_trunc_attr((char *)IObuff, TRUE, HL_ATTR(HLF_R));
+ }
+ else if (*e_cpt == NUL)
+ break;
+ else
+ {
+ if (CTRL_X_MODE_LINE_OR_EVAL(ctrl_x_mode))
+ type = -1;
+ else if (*e_cpt == 'k' || *e_cpt == 's')
+ {
+ if (*e_cpt == 'k')
+ type = CTRL_X_DICTIONARY;
+ else
+ type = CTRL_X_THESAURUS;
+ if (*++e_cpt != ',' && *e_cpt != NUL)
+ {
+ dict = e_cpt;
+ dict_f = DICT_FIRST;
+ }
+ }
+#ifdef FEAT_FIND_ID
+ else if (*e_cpt == 'i')
+ type = CTRL_X_PATH_PATTERNS;
+ else if (*e_cpt == 'd')
+ type = CTRL_X_PATH_DEFINES;
+#endif
+ else if (*e_cpt == ']' || *e_cpt == 't')
+ {
+ type = CTRL_X_TAGS;
+ vim_snprintf((char *)IObuff, IOSIZE, _("Scanning tags."));
+ (void)msg_trunc_attr((char *)IObuff, TRUE, HL_ATTR(HLF_R));
+ }
+ else
+ type = -1;
+
+ /* in any case e_cpt is advanced to the next entry */
+ (void)copy_option_part(&e_cpt, IObuff, IOSIZE, ",");
+
+ found_all = TRUE;
+ if (type == -1)
+ continue;
+ }
+ }
+
+ /* If complete() was called then compl_pattern has been reset. The
+ * following won't work then, bail out. */
+ if (compl_pattern == NULL)
+ break;
+
+ switch (type)
+ {
+ case -1:
+ break;
+#ifdef FEAT_FIND_ID
+ case CTRL_X_PATH_PATTERNS:
+ case CTRL_X_PATH_DEFINES:
+ find_pattern_in_path(compl_pattern, compl_direction,
+ (int)STRLEN(compl_pattern), FALSE, FALSE,
+ (type == CTRL_X_PATH_DEFINES
+ && !(compl_cont_status & CONT_SOL))
+ ? FIND_DEFINE : FIND_ANY, 1L, ACTION_EXPAND,
+ (linenr_T)1, (linenr_T)MAXLNUM);
+ break;
+#endif
+
+ case CTRL_X_DICTIONARY:
+ case CTRL_X_THESAURUS:
+ ins_compl_dictionaries(
+ dict != NULL ? dict
+ : (type == CTRL_X_THESAURUS
+ ? (*curbuf->b_p_tsr == NUL
+ ? p_tsr
+ : curbuf->b_p_tsr)
+ : (*curbuf->b_p_dict == NUL
+ ? p_dict
+ : curbuf->b_p_dict)),
+ compl_pattern,
+ dict != NULL ? dict_f
+ : 0, type == CTRL_X_THESAURUS);
+ dict = NULL;
+ break;
+
+ case CTRL_X_TAGS:
+ /* set p_ic according to p_ic, p_scs and pat for find_tags(). */
+ save_p_ic = p_ic;
+ p_ic = ignorecase(compl_pattern);
+
+ /* Find up to TAG_MANY matches. Avoids that an enormous number
+ * of matches is found when compl_pattern is empty */
+ if (find_tags(compl_pattern, &num_matches, &matches,
+ TAG_REGEXP | TAG_NAMES | TAG_NOIC | TAG_INS_COMP
+ | (ctrl_x_mode != CTRL_X_NORMAL ? TAG_VERBOSE : 0),
+ TAG_MANY, curbuf->b_ffname) == OK && num_matches > 0)
+ {
+ ins_compl_add_matches(num_matches, matches, p_ic);
+ }
+ p_ic = save_p_ic;
+ break;
+
+ case CTRL_X_FILES:
+ if (expand_wildcards(1, &compl_pattern, &num_matches, &matches,
+ EW_FILE|EW_DIR|EW_ADDSLASH|EW_SILENT) == OK)
+ {
+
+ /* May change home directory back to "~". */
+ tilde_replace(compl_pattern, num_matches, matches);
+ ins_compl_add_matches(num_matches, matches, p_fic || p_wic);
+ }
+ break;
+
+ case CTRL_X_CMDLINE:
+ if (expand_cmdline(&compl_xp, compl_pattern,
+ (int)STRLEN(compl_pattern),
+ &num_matches, &matches) == EXPAND_OK)
+ ins_compl_add_matches(num_matches, matches, FALSE);
+ break;
+
+#ifdef FEAT_COMPL_FUNC
+ case CTRL_X_FUNCTION:
+ case CTRL_X_OMNI:
+ expand_by_function(type, compl_pattern);
+ break;
+#endif
+
+ case CTRL_X_SPELL:
+#ifdef FEAT_SPELL
+ num_matches = expand_spelling(first_match_pos.lnum,
+ compl_pattern, &matches);
+ if (num_matches > 0)
+ ins_compl_add_matches(num_matches, matches, p_ic);
+#endif
+ break;
+
+ default: /* normal ^P/^N and ^X^L */
+ /*
+ * If 'infercase' is set, don't use 'smartcase' here
+ */
+ save_p_scs = p_scs;
+ if (ins_buf->b_p_inf)
+ p_scs = FALSE;
+
+ /* Buffers other than curbuf are scanned from the beginning or the
+ * end but never from the middle, thus setting nowrapscan in this
+ * buffers is a good idea, on the other hand, we always set
+ * wrapscan for curbuf to avoid missing matches -- Acevedo,Webb */
+ save_p_ws = p_ws;
+ if (ins_buf != curbuf)
+ p_ws = FALSE;
+ else if (*e_cpt == '.')
+ p_ws = TRUE;
+ for (;;)
+ {
+ int flags = 0;
+
+ ++msg_silent; /* Don't want messages for wrapscan. */
+
+ /* CTRL_X_MODE_LINE_OR_EVAL(ctrl_x_mode)
+ * || word-wise search that
+ * has added a word that was at the beginning of the line */
+ if (CTRL_X_MODE_LINE_OR_EVAL(ctrl_x_mode)
+ || (compl_cont_status & CONT_SOL))
+ found_new_match = search_for_exact_line(ins_buf, pos,
+ compl_direction, compl_pattern);
+ else
+ found_new_match = searchit(NULL, ins_buf, pos, NULL,
+ compl_direction,
+ compl_pattern, 1L, SEARCH_KEEP + SEARCH_NFMSG,
+ RE_LAST, (linenr_T)0, NULL, NULL);
+ --msg_silent;
+ if (!compl_started || set_match_pos)
+ {
+ /* set "compl_started" even on fail */
+ compl_started = TRUE;
+ first_match_pos = *pos;
+ last_match_pos = *pos;
+ set_match_pos = FALSE;
+ }
+ else if (first_match_pos.lnum == last_match_pos.lnum
+ && first_match_pos.col == last_match_pos.col)
+ found_new_match = FAIL;
+ if (found_new_match == FAIL)
+ {
+ if (ins_buf == curbuf)
+ found_all = TRUE;
+ break;
+ }
+
+ /* when ADDING, the text before the cursor matches, skip it */
+ if ( (compl_cont_status & CONT_ADDING) && ins_buf == curbuf
+ && ini->lnum == pos->lnum
+ && ini->col == pos->col)
+ continue;
+ ptr = ml_get_buf(ins_buf, pos->lnum, FALSE) + pos->col;
+ if (CTRL_X_MODE_LINE_OR_EVAL(ctrl_x_mode))
+ {
+ if (compl_cont_status & CONT_ADDING)
+ {
+ if (pos->lnum >= ins_buf->b_ml.ml_line_count)
+ continue;
+ ptr = ml_get_buf(ins_buf, pos->lnum + 1, FALSE);
+ if (!p_paste)
+ ptr = skipwhite(ptr);
+ }
+ len = (int)STRLEN(ptr);
+ }
+ else
+ {
+ char_u *tmp_ptr = ptr;
+
+ if (compl_cont_status & CONT_ADDING)
+ {
+ tmp_ptr += compl_length;
+ /* Skip if already inside a word. */
+ if (vim_iswordp(tmp_ptr))
+ continue;
+ /* Find start of next word. */
+ tmp_ptr = find_word_start(tmp_ptr);
+ }
+ /* Find end of this word. */
+ tmp_ptr = find_word_end(tmp_ptr);
+ len = (int)(tmp_ptr - ptr);
+
+ if ((compl_cont_status & CONT_ADDING)
+ && len == compl_length)
+ {
+ if (pos->lnum < ins_buf->b_ml.ml_line_count)
+ {
+ /* Try next line, if any. the new word will be
+ * "join" as if the normal command "J" was used.
+ * IOSIZE is always greater than
+ * compl_length, so the next STRNCPY always
+ * works -- Acevedo */
+ STRNCPY(IObuff, ptr, len);
+ ptr = ml_get_buf(ins_buf, pos->lnum + 1, FALSE);
+ tmp_ptr = ptr = skipwhite(ptr);
+ /* Find start of next word. */
+ tmp_ptr = find_word_start(tmp_ptr);
+ /* Find end of next word. */
+ tmp_ptr = find_word_end(tmp_ptr);
+ if (tmp_ptr > ptr)
+ {
+ if (*ptr != ')' && IObuff[len - 1] != TAB)
+ {
+ if (IObuff[len - 1] != ' ')
+ IObuff[len++] = ' ';
+ /* IObuf =~ "\k.* ", thus len >= 2 */
+ if (p_js
+ && (IObuff[len - 2] == '.'
+ || (vim_strchr(p_cpo, CPO_JOINSP)
+ == NULL
+ && (IObuff[len - 2] == '?'
+ || IObuff[len - 2] == '!'))))
+ IObuff[len++] = ' ';
+ }
+ /* copy as much as possible of the new word */
+ if (tmp_ptr - ptr >= IOSIZE - len)
+ tmp_ptr = ptr + IOSIZE - len - 1;
+ STRNCPY(IObuff + len, ptr, tmp_ptr - ptr);
+ len += (int)(tmp_ptr - ptr);
+ flags |= CONT_S_IPOS;
+ }
+ IObuff[len] = NUL;
+ ptr = IObuff;
+ }
+ if (len == compl_length)
+ continue;
+ }
+ }
+ if (ins_compl_add_infercase(ptr, len, p_ic,
+ ins_buf == curbuf ? NULL : ins_buf->b_sfname,
+ 0, flags) != NOTDONE)
+ {
+ found_new_match = OK;
+ break;
+ }
+ }
+ p_scs = save_p_scs;
+ p_ws = save_p_ws;
+ }
+
+ /* check if compl_curr_match has changed, (e.g. other type of
+ * expansion added something) */
+ if (type != 0 && compl_curr_match != compl_old_match)
+ found_new_match = OK;
+
+ /* break the loop for specialized modes (use 'complete' just for the
+ * generic ctrl_x_mode == CTRL_X_NORMAL) or when we've found a new
+ * match */
+ if ((ctrl_x_mode != CTRL_X_NORMAL
+ && !CTRL_X_MODE_LINE_OR_EVAL(ctrl_x_mode))
+ || found_new_match != FAIL)
+ {
+ if (got_int)
+ break;
+ /* Fill the popup menu as soon as possible. */
+ if (type != -1)
+ ins_compl_check_keys(0, FALSE);
+
+ if ((ctrl_x_mode != CTRL_X_NORMAL
+ && !CTRL_X_MODE_LINE_OR_EVAL(ctrl_x_mode))
+ || compl_interrupted)
+ break;
+ compl_started = TRUE;
+ }
+ else
+ {
+ /* Mark a buffer scanned when it has been scanned completely */
+ if (type == 0 || type == CTRL_X_PATH_PATTERNS)
+ ins_buf->b_scanned = TRUE;
+
+ compl_started = FALSE;
+ }
+ }
+ compl_started = TRUE;
+
+ if ((ctrl_x_mode == CTRL_X_NORMAL || CTRL_X_MODE_LINE_OR_EVAL(ctrl_x_mode))
+ && *e_cpt == NUL) /* Got to end of 'complete' */
+ found_new_match = FAIL;
+
+ i = -1; /* total of matches, unknown */
+ if (found_new_match == FAIL || (ctrl_x_mode != CTRL_X_NORMAL
+ && !CTRL_X_MODE_LINE_OR_EVAL(ctrl_x_mode)))
+ i = ins_compl_make_cyclic();
+
+ if (compl_old_match != NULL)
+ {
+ /* If several matches were added (FORWARD) or the search failed and has
+ * just been made cyclic then we have to move compl_curr_match to the
+ * next or previous entry (if any) -- Acevedo */
+ compl_curr_match = compl_direction == FORWARD ? compl_old_match->cp_next
+ : compl_old_match->cp_prev;
+ if (compl_curr_match == NULL)
+ compl_curr_match = compl_old_match;
+ }
+ return i;
+}
+
+/* Delete the old text being completed. */
+ static void
+ins_compl_delete(void)
+{
+ int col;
+
+ /*
+ * In insert mode: Delete the typed part.
+ * In replace mode: Put the old characters back, if any.
+ */
+ col = compl_col + (compl_cont_status & CONT_ADDING ? compl_length : 0);
+ if ((int)curwin->w_cursor.col > col)
+ {
+ if (stop_arrow() == FAIL)
+ return;
+ backspace_until_column(col);
+ }
+
+ /* TODO: is this sufficient for redrawing? Redrawing everything causes
+ * flicker, thus we can't do that. */
+ changed_cline_bef_curs();
+ /* clear v:completed_item */
+ set_vim_var_dict(VV_COMPLETED_ITEM, dict_alloc_lock(VAR_FIXED));
+}
+
+/*
+ * Insert the new text being completed.
+ * "in_compl_func" is TRUE when called from complete_check().
+ */
+ static void
+ins_compl_insert(int in_compl_func)
+{
+ dict_T *dict;
+
+ ins_bytes(compl_shown_match->cp_str + ins_compl_len());
+ if (compl_shown_match->cp_flags & ORIGINAL_TEXT)
+ compl_used_match = FALSE;
+ else
+ compl_used_match = TRUE;
+
+ /* Set completed item. */
+ /* { word, abbr, menu, kind, info } */
+ dict = dict_alloc_lock(VAR_FIXED);
+ if (dict != NULL)
+ {
+ dict_add_string(dict, "word", compl_shown_match->cp_str);
+ dict_add_string(dict, "abbr", compl_shown_match->cp_text[CPT_ABBR]);
+ dict_add_string(dict, "menu", compl_shown_match->cp_text[CPT_MENU]);
+ dict_add_string(dict, "kind", compl_shown_match->cp_text[CPT_KIND]);
+ dict_add_string(dict, "info", compl_shown_match->cp_text[CPT_INFO]);
+ dict_add_string(dict, "user_data",
+ compl_shown_match->cp_text[CPT_USER_DATA]);
+ }
+ set_vim_var_dict(VV_COMPLETED_ITEM, dict);
+ if (!in_compl_func)
+ compl_curr_match = compl_shown_match;
+}
+
+/*
+ * Fill in the next completion in the current direction.
+ * If "allow_get_expansion" is TRUE, then we may call ins_compl_get_exp() to
+ * get more completions. If it is FALSE, then we just do nothing when there
+ * are no more completions in a given direction. The latter case is used when
+ * we are still in the middle of finding completions, to allow browsing
+ * through the ones found so far.
+ * Return the total number of matches, or -1 if still unknown -- webb.
+ *
+ * compl_curr_match is currently being used by ins_compl_get_exp(), so we use
+ * compl_shown_match here.
+ *
+ * Note that this function may be called recursively once only. First with
+ * "allow_get_expansion" TRUE, which calls ins_compl_get_exp(), which in turn
+ * calls this function with "allow_get_expansion" FALSE.
+ */
+ static int
+ins_compl_next(
+ int allow_get_expansion,
+ int count, /* repeat completion this many times; should
+ be at least 1 */
+ int insert_match, /* Insert the newly selected match */
+ int in_compl_func) /* called from complete_check() */
+{
+ int num_matches = -1;
+ int todo = count;
+ compl_T *found_compl = NULL;
+ int found_end = FALSE;
+ int advance;
+ int started = compl_started;
+
+ /* When user complete function return -1 for findstart which is next
+ * time of 'always', compl_shown_match become NULL. */
+ if (compl_shown_match == NULL)
+ return -1;
+
+ if (compl_leader != NULL
+ && (compl_shown_match->cp_flags & ORIGINAL_TEXT) == 0)
+ {
+ /* Set "compl_shown_match" to the actually shown match, it may differ
+ * when "compl_leader" is used to omit some of the matches. */
+ while (!ins_compl_equal(compl_shown_match,
+ compl_leader, (int)STRLEN(compl_leader))
+ && compl_shown_match->cp_next != NULL
+ && compl_shown_match->cp_next != compl_first_match)
+ compl_shown_match = compl_shown_match->cp_next;
+
+ /* If we didn't find it searching forward, and compl_shows_dir is
+ * backward, find the last match. */
+ if (compl_shows_dir == BACKWARD
+ && !ins_compl_equal(compl_shown_match,
+ compl_leader, (int)STRLEN(compl_leader))
+ && (compl_shown_match->cp_next == NULL
+ || compl_shown_match->cp_next == compl_first_match))
+ {
+ while (!ins_compl_equal(compl_shown_match,
+ compl_leader, (int)STRLEN(compl_leader))
+ && compl_shown_match->cp_prev != NULL
+ && compl_shown_match->cp_prev != compl_first_match)
+ compl_shown_match = compl_shown_match->cp_prev;
+ }
+ }
+
+ if (allow_get_expansion && insert_match
+ && (!(compl_get_longest || compl_restarting) || compl_used_match))
+ /* Delete old text to be replaced */
+ ins_compl_delete();
+
+ /* When finding the longest common text we stick at the original text,
+ * don't let CTRL-N or CTRL-P move to the first match. */
+ advance = count != 1 || !allow_get_expansion || !compl_get_longest;
+
+ /* When restarting the search don't insert the first match either. */
+ if (compl_restarting)
+ {
+ advance = FALSE;
+ compl_restarting = FALSE;
+ }
+
+ /* Repeat this for when <PageUp> or <PageDown> is typed. But don't wrap
+ * around. */
+ while (--todo >= 0)
+ {
+ if (compl_shows_dir == FORWARD && compl_shown_match->cp_next != NULL)
+ {
+ compl_shown_match = compl_shown_match->cp_next;
+ found_end = (compl_first_match != NULL
+ && (compl_shown_match->cp_next == compl_first_match
+ || compl_shown_match == compl_first_match));
+ }
+ else if (compl_shows_dir == BACKWARD
+ && compl_shown_match->cp_prev != NULL)
+ {
+ found_end = (compl_shown_match == compl_first_match);
+ compl_shown_match = compl_shown_match->cp_prev;
+ found_end |= (compl_shown_match == compl_first_match);
+ }
+ else
+ {
+ if (!allow_get_expansion)
+ {
+ if (advance)
+ {
+ if (compl_shows_dir == BACKWARD)
+ compl_pending -= todo + 1;
+ else
+ compl_pending += todo + 1;
+ }
+ return -1;
+ }
+
+ if (!compl_no_select && advance)
+ {
+ if (compl_shows_dir == BACKWARD)
+ --compl_pending;
+ else
+ ++compl_pending;
+ }
+
+ /* Find matches. */
+ num_matches = ins_compl_get_exp(&compl_startpos);
+
+ /* handle any pending completions */
+ while (compl_pending != 0 && compl_direction == compl_shows_dir
+ && advance)
+ {
+ if (compl_pending > 0 && compl_shown_match->cp_next != NULL)
+ {
+ compl_shown_match = compl_shown_match->cp_next;
+ --compl_pending;
+ }
+ if (compl_pending < 0 && compl_shown_match->cp_prev != NULL)
+ {
+ compl_shown_match = compl_shown_match->cp_prev;
+ ++compl_pending;
+ }
+ else
+ break;
+ }
+ found_end = FALSE;
+ }
+ if ((compl_shown_match->cp_flags & ORIGINAL_TEXT) == 0
+ && compl_leader != NULL
+ && !ins_compl_equal(compl_shown_match,
+ compl_leader, (int)STRLEN(compl_leader)))
+ ++todo;
+ else
+ /* Remember a matching item. */
+ found_compl = compl_shown_match;
+
+ /* Stop at the end of the list when we found a usable match. */
+ if (found_end)
+ {
+ if (found_compl != NULL)
+ {
+ compl_shown_match = found_compl;
+ break;
+ }
+ todo = 1; /* use first usable match after wrapping around */
+ }
+ }
+
+ /* Insert the text of the new completion, or the compl_leader. */
+ if (compl_no_insert && !started)
+ {
+ ins_bytes(compl_orig_text + ins_compl_len());
+ compl_used_match = FALSE;
+ }
+ else if (insert_match)
+ {
+ if (!compl_get_longest || compl_used_match)
+ ins_compl_insert(in_compl_func);
+ else
+ ins_bytes(compl_leader + ins_compl_len());
+ }
+ else
+ compl_used_match = FALSE;
+
+ if (!allow_get_expansion)
+ {
+ /* may undisplay the popup menu first */
+ ins_compl_upd_pum();
+
+ // Redraw before showing the popup menu to show the user what was
+ // inserted.
+ pum_call_update_screen();
+
+ /* display the updated popup menu */
+ ins_compl_show_pum();
+#ifdef FEAT_GUI
+ if (gui.in_use)
+ {
+ /* Show the cursor after the match, not after the redrawn text. */
+ setcursor();
+ out_flush_cursor(FALSE, FALSE);
+ }
+#endif
+
+ /* Delete old text to be replaced, since we're still searching and
+ * don't want to match ourselves! */
+ ins_compl_delete();
+ }
+
+ /* Enter will select a match when the match wasn't inserted and the popup
+ * menu is visible. */
+ if (compl_no_insert && !started)
+ compl_enter_selects = TRUE;
+ else
+ compl_enter_selects = !insert_match && compl_match_array != NULL;
+
+ /*
+ * Show the file name for the match (if any)
+ * Truncate the file name to avoid a wait for return.
+ */
+ if (compl_shown_match->cp_fname != NULL)
+ {
+ char *lead = _("match in file");
+ int space = sc_col - vim_strsize((char_u *)lead) - 2;
+ char_u *s;
+ char_u *e;
+
+ if (space > 0)
+ {
+ /* We need the tail that fits. With double-byte encoding going
+ * back from the end is very slow, thus go from the start and keep
+ * the text that fits in "space" between "s" and "e". */
+ for (s = e = compl_shown_match->cp_fname; *e != NUL; MB_PTR_ADV(e))
+ {
+ space -= ptr2cells(e);
+ while (space < 0)
+ {
+ space += ptr2cells(s);
+ MB_PTR_ADV(s);
+ }
+ }
+ vim_snprintf((char *)IObuff, IOSIZE, "%s %s%s", lead,
+ s > compl_shown_match->cp_fname ? "<" : "", s);
+ msg((char *)IObuff);
+ redraw_cmdline = FALSE; /* don't overwrite! */
+ }
+ }
+
+ return num_matches;
+}
+
+/*
+ * Call this while finding completions, to check whether the user has hit a key
+ * that should change the currently displayed completion, or exit completion
+ * mode. Also, when compl_pending is not zero, show a completion as soon as
+ * possible. -- webb
+ * "frequency" specifies out of how many calls we actually check.
+ * "in_compl_func" is TRUE when called from complete_check(), don't set
+ * compl_curr_match.
+ */
+ void
+ins_compl_check_keys(int frequency, int in_compl_func)
+{
+ static int count = 0;
+ int c;
+
+ /* Don't check when reading keys from a script, :normal or feedkeys().
+ * That would break the test scripts. But do check for keys when called
+ * from complete_check(). */
+ if (!in_compl_func && (using_script() || ex_normal_busy))
+ return;
+
+ /* Only do this at regular intervals */
+ if (++count < frequency)
+ return;
+ count = 0;
+
+ /* Check for a typed key. Do use mappings, otherwise vim_is_ctrl_x_key()
+ * can't do its work correctly. */
+ c = vpeekc_any();
+ if (c != NUL)
+ {
+ if (vim_is_ctrl_x_key(c) && c != Ctrl_X && c != Ctrl_R)
+ {
+ c = safe_vgetc(); /* Eat the character */
+ compl_shows_dir = ins_compl_key2dir(c);
+ (void)ins_compl_next(FALSE, ins_compl_key2count(c),
+ c != K_UP && c != K_DOWN, in_compl_func);
+ }
+ else
+ {
+ /* Need to get the character to have KeyTyped set. We'll put it
+ * back with vungetc() below. But skip K_IGNORE. */
+ c = safe_vgetc();
+ if (c != K_IGNORE)
+ {
+ /* Don't interrupt completion when the character wasn't typed,
+ * e.g., when doing @q to replay keys. */
+ if (c != Ctrl_R && KeyTyped)
+ compl_interrupted = TRUE;
+
+ vungetc(c);
+ }
+ }
+ }
+ if (compl_pending != 0 && !got_int && !compl_no_insert)
+ {
+ int todo = compl_pending > 0 ? compl_pending : -compl_pending;
+
+ compl_pending = 0;
+ (void)ins_compl_next(FALSE, todo, TRUE, in_compl_func);
+ }
+}
+
+/*
+ * Decide the direction of Insert mode complete from the key typed.
+ * Returns BACKWARD or FORWARD.
+ */
+ static int
+ins_compl_key2dir(int c)
+{
+ if (c == Ctrl_P || c == Ctrl_L
+ || c == K_PAGEUP || c == K_KPAGEUP || c == K_S_UP || c == K_UP)
+ return BACKWARD;
+ return FORWARD;
+}
+
+/*
+ * Return TRUE for keys that are used for completion only when the popup menu
+ * is visible.
+ */
+ static int
+ins_compl_pum_key(int c)
+{
+ return pum_visible() && (c == K_PAGEUP || c == K_KPAGEUP || c == K_S_UP
+ || c == K_PAGEDOWN || c == K_KPAGEDOWN || c == K_S_DOWN
+ || c == K_UP || c == K_DOWN);
+}
+
+/*
+ * Decide the number of completions to move forward.
+ * Returns 1 for most keys, height of the popup menu for page-up/down keys.
+ */
+ static int
+ins_compl_key2count(int c)
+{
+ int h;
+
+ if (ins_compl_pum_key(c) && c != K_UP && c != K_DOWN)
+ {
+ h = pum_get_height();
+ if (h > 3)
+ h -= 2; /* keep some context */
+ return h;
+ }
+ return 1;
+}
+
+/*
+ * Return TRUE if completion with "c" should insert the match, FALSE if only
+ * to change the currently selected completion.
+ */
+ static int
+ins_compl_use_match(int c)
+{
+ switch (c)
+ {
+ case K_UP:
+ case K_DOWN:
+ case K_PAGEDOWN:
+ case K_KPAGEDOWN:
+ case K_S_DOWN:
+ case K_PAGEUP:
+ case K_KPAGEUP:
+ case K_S_UP:
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*
+ * Do Insert mode completion.
+ * Called when character "c" was typed, which has a meaning for completion.
+ * Returns OK if completion was done, FAIL if something failed (out of mem).
+ */
+ static int
+ins_complete(int c, int enable_pum)
+{
+ char_u *line;
+ int startcol = 0; /* column where searched text starts */
+ colnr_T curs_col; /* cursor column */
+ int n;
+ int save_w_wrow;
+ int save_w_leftcol;
+ int insert_match;
+ int save_did_ai = did_ai;
+
+ compl_direction = ins_compl_key2dir(c);
+ insert_match = ins_compl_use_match(c);
+
+ if (!compl_started)
+ {
+ /* First time we hit ^N or ^P (in a row, I mean) */
+
+ did_ai = FALSE;
+#ifdef FEAT_SMARTINDENT
+ did_si = FALSE;
+ can_si = FALSE;
+ can_si_back = FALSE;
+#endif
+ if (stop_arrow() == FAIL)
+ return FAIL;
+
+ line = ml_get(curwin->w_cursor.lnum);
+ curs_col = curwin->w_cursor.col;
+ compl_pending = 0;
+
+ /* If this same ctrl_x_mode has been interrupted use the text from
+ * "compl_startpos" to the cursor as a pattern to add a new word
+ * instead of expand the one before the cursor, in word-wise if
+ * "compl_startpos" is not in the same line as the cursor then fix it
+ * (the line has been split because it was longer than 'tw'). if SOL
+ * is set then skip the previous pattern, a word at the beginning of
+ * the line has been inserted, we'll look for that -- Acevedo. */
+ if ((compl_cont_status & CONT_INTRPT) == CONT_INTRPT
+ && compl_cont_mode == ctrl_x_mode)
+ {
+ /*
+ * it is a continued search
+ */
+ compl_cont_status &= ~CONT_INTRPT; /* remove INTRPT */
+ if (ctrl_x_mode == CTRL_X_NORMAL
+ || ctrl_x_mode == CTRL_X_PATH_PATTERNS
+ || ctrl_x_mode == CTRL_X_PATH_DEFINES)
+ {
+ if (compl_startpos.lnum != curwin->w_cursor.lnum)
+ {
+ /* line (probably) wrapped, set compl_startpos to the
+ * first non_blank in the line, if it is not a wordchar
+ * include it to get a better pattern, but then we don't
+ * want the "\\<" prefix, check it bellow */
+ compl_col = (colnr_T)getwhitecols(line);
+ compl_startpos.col = compl_col;
+ compl_startpos.lnum = curwin->w_cursor.lnum;
+ compl_cont_status &= ~CONT_SOL; /* clear SOL if present */
+ }
+ else
+ {
+ /* S_IPOS was set when we inserted a word that was at the
+ * beginning of the line, which means that we'll go to SOL
+ * mode but first we need to redefine compl_startpos */
+ if (compl_cont_status & CONT_S_IPOS)
+ {
+ compl_cont_status |= CONT_SOL;
+ compl_startpos.col = (colnr_T)(skipwhite(
+ line + compl_length
+ + compl_startpos.col) - line);
+ }
+ compl_col = compl_startpos.col;
+ }
+ compl_length = curwin->w_cursor.col - (int)compl_col;
+ /* IObuff is used to add a "word from the next line" would we
+ * have enough space? just being paranoid */
+#define MIN_SPACE 75
+ if (compl_length > (IOSIZE - MIN_SPACE))
+ {
+ compl_cont_status &= ~CONT_SOL;
+ compl_length = (IOSIZE - MIN_SPACE);
+ compl_col = curwin->w_cursor.col - compl_length;
+ }
+ compl_cont_status |= CONT_ADDING | CONT_N_ADDS;
+ if (compl_length < 1)
+ compl_cont_status &= CONT_LOCAL;
+ }
+ else if (CTRL_X_MODE_LINE_OR_EVAL(ctrl_x_mode))
+ compl_cont_status = CONT_ADDING | CONT_N_ADDS;
+ else
+ compl_cont_status = 0;
+ }
+ else
+ compl_cont_status &= CONT_LOCAL;
+
+ if (!(compl_cont_status & CONT_ADDING)) /* normal expansion */
+ {
+ compl_cont_mode = ctrl_x_mode;
+ if (ctrl_x_mode != CTRL_X_NORMAL)
+ /* Remove LOCAL if ctrl_x_mode != CTRL_X_NORMAL */
+ compl_cont_status = 0;
+ compl_cont_status |= CONT_N_ADDS;
+ compl_startpos = curwin->w_cursor;
+ startcol = (int)curs_col;
+ compl_col = 0;
+ }
+
+ /* Work out completion pattern and original text -- webb */
+ if (ctrl_x_mode == CTRL_X_NORMAL || (ctrl_x_mode & CTRL_X_WANT_IDENT))
+ {
+ if ((compl_cont_status & CONT_SOL)
+ || ctrl_x_mode == CTRL_X_PATH_DEFINES)
+ {
+ if (!(compl_cont_status & CONT_ADDING))
+ {
+ while (--startcol >= 0 && vim_isIDc(line[startcol]))
+ ;
+ compl_col += ++startcol;
+ compl_length = curs_col - startcol;
+ }
+ if (p_ic)
+ compl_pattern = str_foldcase(line + compl_col,
+ compl_length, NULL, 0);
+ else
+ compl_pattern = vim_strnsave(line + compl_col,
+ compl_length);
+ if (compl_pattern == NULL)
+ return FAIL;
+ }
+ else if (compl_cont_status & CONT_ADDING)
+ {
+ char_u *prefix = (char_u *)"\\<";
+
+ /* we need up to 2 extra chars for the prefix */
+ compl_pattern = alloc(quote_meta(NULL, line + compl_col,
+ compl_length) + 2);
+ if (compl_pattern == NULL)
+ return FAIL;
+ if (!vim_iswordp(line + compl_col)
+ || (compl_col > 0
+ && (vim_iswordp(mb_prevptr(line, line + compl_col)))))
+ prefix = (char_u *)"";
+ STRCPY((char *)compl_pattern, prefix);
+ (void)quote_meta(compl_pattern + STRLEN(prefix),
+ line + compl_col, compl_length);
+ }
+ else if (--startcol < 0
+ || !vim_iswordp(mb_prevptr(line, line + startcol + 1)))
+ {
+ /* Match any word of at least two chars */
+ compl_pattern = vim_strsave((char_u *)"\\<\\k\\k");
+ if (compl_pattern == NULL)
+ return FAIL;
+ compl_col += curs_col;
+ compl_length = 0;
+ }
+ else
+ {
+ /* Search the point of change class of multibyte character
+ * or not a word single byte character backward. */
+ if (has_mbyte)
+ {
+ int base_class;
+ int head_off;
+
+ startcol -= (*mb_head_off)(line, line + startcol);
+ base_class = mb_get_class(line + startcol);
+ while (--startcol >= 0)
+ {
+ head_off = (*mb_head_off)(line, line + startcol);
+ if (base_class != mb_get_class(line + startcol
+ - head_off))
+ break;
+ startcol -= head_off;
+ }
+ }
+ else
+ while (--startcol >= 0 && vim_iswordc(line[startcol]))
+ ;
+ compl_col += ++startcol;
+ compl_length = (int)curs_col - startcol;
+ if (compl_length == 1)
+ {
+ /* Only match word with at least two chars -- webb
+ * there's no need to call quote_meta,
+ * alloc(7) is enough -- Acevedo
+ */
+ compl_pattern = alloc(7);
+ if (compl_pattern == NULL)
+ return FAIL;
+ STRCPY((char *)compl_pattern, "\\<");
+ (void)quote_meta(compl_pattern + 2, line + compl_col, 1);
+ STRCAT((char *)compl_pattern, "\\k");
+ }
+ else
+ {
+ compl_pattern = alloc(quote_meta(NULL, line + compl_col,
+ compl_length) + 2);
+ if (compl_pattern == NULL)
+ return FAIL;
+ STRCPY((char *)compl_pattern, "\\<");
+ (void)quote_meta(compl_pattern + 2, line + compl_col,
+ compl_length);
+ }
+ }
+ }
+ else if (CTRL_X_MODE_LINE_OR_EVAL(ctrl_x_mode))
+ {
+ compl_col = (colnr_T)getwhitecols(line);
+ compl_length = (int)curs_col - (int)compl_col;
+ if (compl_length < 0) /* cursor in indent: empty pattern */
+ compl_length = 0;
+ if (p_ic)
+ compl_pattern = str_foldcase(line + compl_col, compl_length,
+ NULL, 0);
+ else
+ compl_pattern = vim_strnsave(line + compl_col, compl_length);
+ if (compl_pattern == NULL)
+ return FAIL;
+ }
+ else if (ctrl_x_mode == CTRL_X_FILES)
+ {
+ /* Go back to just before the first filename character. */
+ if (startcol > 0)
+ {
+ char_u *p = line + startcol;
+
+ MB_PTR_BACK(line, p);
+ while (p > line && vim_isfilec(PTR2CHAR(p)))
+ MB_PTR_BACK(line, p);
+ if (p == line && vim_isfilec(PTR2CHAR(p)))
+ startcol = 0;
+ else
+ startcol = (int)(p - line) + 1;
+ }
+
+ compl_col += startcol;
+ compl_length = (int)curs_col - startcol;
+ compl_pattern = addstar(line + compl_col, compl_length,
+ EXPAND_FILES);
+ if (compl_pattern == NULL)
+ return FAIL;
+ }
+ else if (ctrl_x_mode == CTRL_X_CMDLINE)
+ {
+ compl_pattern = vim_strnsave(line, curs_col);
+ if (compl_pattern == NULL)
+ return FAIL;
+ set_cmd_context(&compl_xp, compl_pattern,
+ (int)STRLEN(compl_pattern), curs_col, FALSE);
+ if (compl_xp.xp_context == EXPAND_UNSUCCESSFUL
+ || compl_xp.xp_context == EXPAND_NOTHING)
+ /* No completion possible, use an empty pattern to get a
+ * "pattern not found" message. */
+ compl_col = curs_col;
+ else
+ compl_col = (int)(compl_xp.xp_pattern - compl_pattern);
+ compl_length = curs_col - compl_col;
+ }
+ else if (ctrl_x_mode == CTRL_X_FUNCTION || ctrl_x_mode == CTRL_X_OMNI)
+ {
+#ifdef FEAT_COMPL_FUNC
+ /*
+ * Call user defined function 'completefunc' with "a:findstart"
+ * set to 1 to obtain the length of text to use for completion.
+ */
+ typval_T args[3];
+ int col;
+ char_u *funcname;
+ pos_T pos;
+ win_T *curwin_save;
+ buf_T *curbuf_save;
+ int save_State = State;
+
+ /* Call 'completefunc' or 'omnifunc' and get pattern length as a
+ * string */
+ funcname = ctrl_x_mode == CTRL_X_FUNCTION
+ ? curbuf->b_p_cfu : curbuf->b_p_ofu;
+ if (*funcname == NUL)
+ {
+ semsg(_(e_notset), ctrl_x_mode == CTRL_X_FUNCTION
+ ? "completefunc" : "omnifunc");
+ /* restore did_ai, so that adding comment leader works */
+ did_ai = save_did_ai;
+ return FAIL;
+ }
+
+ args[0].v_type = VAR_NUMBER;
+ args[0].vval.v_number = 1;
+ args[1].v_type = VAR_STRING;
+ args[1].vval.v_string = (char_u *)"";
+ args[2].v_type = VAR_UNKNOWN;
+ pos = curwin->w_cursor;
+ curwin_save = curwin;
+ curbuf_save = curbuf;
+ col = call_func_retnr(funcname, 2, args);
+
+ State = save_State;
+ if (curwin_save != curwin || curbuf_save != curbuf)
+ {
+ emsg(_(e_complwin));
+ return FAIL;
+ }
+ curwin->w_cursor = pos; /* restore the cursor position */
+ validate_cursor();
+ if (!EQUAL_POS(curwin->w_cursor, pos))
+ {
+ emsg(_(e_compldel));
+ return FAIL;
+ }
+
+ /* Return value -2 means the user complete function wants to
+ * cancel the complete without an error.
+ * Return value -3 does the same as -2 and leaves CTRL-X mode.*/
+ if (col == -2)
+ return FAIL;
+ if (col == -3)
+ {
+ ctrl_x_mode = CTRL_X_NORMAL;
+ edit_submode = NULL;
+ if (!shortmess(SHM_COMPLETIONMENU))
+ msg_clr_cmdline();
+ return FAIL;
+ }
+
+ /*
+ * Reset extended parameters of completion, when start new
+ * completion.
+ */
+ compl_opt_refresh_always = FALSE;
+ compl_opt_suppress_empty = FALSE;
+
+ if (col < 0)
+ col = curs_col;
+ compl_col = col;
+ if (compl_col > curs_col)
+ compl_col = curs_col;
+
+ /* Setup variables for completion. Need to obtain "line" again,
+ * it may have become invalid. */
+ line = ml_get(curwin->w_cursor.lnum);
+ compl_length = curs_col - compl_col;
+ compl_pattern = vim_strnsave(line + compl_col, compl_length);
+ if (compl_pattern == NULL)
+#endif
+ return FAIL;
+ }
+ else if (ctrl_x_mode == CTRL_X_SPELL)
+ {
+#ifdef FEAT_SPELL
+ if (spell_bad_len > 0)
+ compl_col = curs_col - spell_bad_len;
+ else
+ compl_col = spell_word_start(startcol);
+ if (compl_col >= (colnr_T)startcol)
+ {
+ compl_length = 0;
+ compl_col = curs_col;
+ }
+ else
+ {
+ spell_expand_check_cap(compl_col);
+ compl_length = (int)curs_col - compl_col;
+ }
+ /* Need to obtain "line" again, it may have become invalid. */
+ line = ml_get(curwin->w_cursor.lnum);
+ compl_pattern = vim_strnsave(line + compl_col, compl_length);
+ if (compl_pattern == NULL)
+#endif
+ return FAIL;
+ }
+ else
+ {
+ internal_error("ins_complete()");
+ return FAIL;
+ }
+
+ if (compl_cont_status & CONT_ADDING)
+ {
+ edit_submode_pre = (char_u *)_(" Adding");
+ if (CTRL_X_MODE_LINE_OR_EVAL(ctrl_x_mode))
+ {
+ /* Insert a new line, keep indentation but ignore 'comments' */
+#ifdef FEAT_COMMENTS
+ char_u *old = curbuf->b_p_com;
+
+ curbuf->b_p_com = (char_u *)"";
+#endif
+ compl_startpos.lnum = curwin->w_cursor.lnum;
+ compl_startpos.col = compl_col;
+ ins_eol('\r');
+#ifdef FEAT_COMMENTS
+ curbuf->b_p_com = old;
+#endif
+ compl_length = 0;
+ compl_col = curwin->w_cursor.col;
+ }
+ }
+ else
+ {
+ edit_submode_pre = NULL;
+ compl_startpos.col = compl_col;
+ }
+
+ if (compl_cont_status & CONT_LOCAL)
+ edit_submode = (char_u *)_(ctrl_x_msgs[CTRL_X_LOCAL_MSG]);
+ else
+ edit_submode = (char_u *)_(CTRL_X_MSG(ctrl_x_mode));
+
+ /* If any of the original typed text has been changed we need to fix
+ * the redo buffer. */
+ ins_compl_fixRedoBufForLeader(NULL);
+
+ /* Always add completion for the original text. */
+ vim_free(compl_orig_text);
+ compl_orig_text = vim_strnsave(line + compl_col, compl_length);
+ if (compl_orig_text == NULL || ins_compl_add(compl_orig_text,
+ -1, p_ic, NULL, NULL, 0, ORIGINAL_TEXT, FALSE) != OK)
+ {
+ VIM_CLEAR(compl_pattern);
+ VIM_CLEAR(compl_orig_text);
+ return FAIL;
+ }
+
+ /* showmode might reset the internal line pointers, so it must
+ * be called before line = ml_get(), or when this address is no
+ * longer needed. -- Acevedo.
+ */
+ edit_submode_extra = (char_u *)_("-- Searching...");
+ edit_submode_highl = HLF_COUNT;
+ showmode();
+ edit_submode_extra = NULL;
+ out_flush();
+ }
+ else if (insert_match && stop_arrow() == FAIL)
+ return FAIL;
+
+ compl_shown_match = compl_curr_match;
+ compl_shows_dir = compl_direction;
+
+ /*
+ * Find next match (and following matches).
+ */
+ save_w_wrow = curwin->w_wrow;
+ save_w_leftcol = curwin->w_leftcol;
+ n = ins_compl_next(TRUE, ins_compl_key2count(c), insert_match, FALSE);
+
+ /* may undisplay the popup menu */
+ ins_compl_upd_pum();
+
+ if (n > 1) /* all matches have been found */
+ compl_matches = n;
+ compl_curr_match = compl_shown_match;
+ compl_direction = compl_shows_dir;
+
+ /* Eat the ESC that vgetc() returns after a CTRL-C to avoid leaving Insert
+ * mode. */
+ if (got_int && !global_busy)
+ {
+ (void)vgetc();
+ got_int = FALSE;
+ }
+
+ /* we found no match if the list has only the "compl_orig_text"-entry */
+ if (compl_first_match == compl_first_match->cp_next)
+ {
+ edit_submode_extra = (compl_cont_status & CONT_ADDING)
+ && compl_length > 1
+ ? (char_u *)_(e_hitend) : (char_u *)_(e_patnotf);
+ edit_submode_highl = HLF_E;
+ /* remove N_ADDS flag, so next ^X<> won't try to go to ADDING mode,
+ * because we couldn't expand anything at first place, but if we used
+ * ^P, ^N, ^X^I or ^X^D we might want to add-expand a single-char-word
+ * (such as M in M'exico) if not tried already. -- Acevedo */
+ if ( compl_length > 1
+ || (compl_cont_status & CONT_ADDING)
+ || (ctrl_x_mode != CTRL_X_NORMAL
+ && ctrl_x_mode != CTRL_X_PATH_PATTERNS
+ && ctrl_x_mode != CTRL_X_PATH_DEFINES))
+ compl_cont_status &= ~CONT_N_ADDS;
+ }
+
+ if (compl_curr_match->cp_flags & CONT_S_IPOS)
+ compl_cont_status |= CONT_S_IPOS;
+ else
+ compl_cont_status &= ~CONT_S_IPOS;
+
+ if (edit_submode_extra == NULL)
+ {
+ if (compl_curr_match->cp_flags & ORIGINAL_TEXT)
+ {
+ edit_submode_extra = (char_u *)_("Back at original");
+ edit_submode_highl = HLF_W;
+ }
+ else if (compl_cont_status & CONT_S_IPOS)
+ {
+ edit_submode_extra = (char_u *)_("Word from other line");
+ edit_submode_highl = HLF_COUNT;
+ }
+ else if (compl_curr_match->cp_next == compl_curr_match->cp_prev)
+ {
+ edit_submode_extra = (char_u *)_("The only match");
+ edit_submode_highl = HLF_COUNT;
+ }
+ else
+ {
+ /* Update completion sequence number when needed. */
+ if (compl_curr_match->cp_number == -1)
+ {
+ int number = 0;
+ compl_T *match;
+
+ if (compl_direction == FORWARD)
+ {
+ /* search backwards for the first valid (!= -1) number.
+ * This should normally succeed already at the first loop
+ * cycle, so it's fast! */
+ for (match = compl_curr_match->cp_prev; match != NULL
+ && match != compl_first_match;
+ match = match->cp_prev)
+ if (match->cp_number != -1)
+ {
+ number = match->cp_number;
+ break;
+ }
+ if (match != NULL)
+ /* go up and assign all numbers which are not assigned
+ * yet */
+ for (match = match->cp_next;
+ match != NULL && match->cp_number == -1;
+ match = match->cp_next)
+ match->cp_number = ++number;
+ }
+ else /* BACKWARD */
+ {
+ /* search forwards (upwards) for the first valid (!= -1)
+ * number. This should normally succeed already at the
+ * first loop cycle, so it's fast! */
+ for (match = compl_curr_match->cp_next; match != NULL
+ && match != compl_first_match;
+ match = match->cp_next)
+ if (match->cp_number != -1)
+ {
+ number = match->cp_number;
+ break;
+ }
+ if (match != NULL)
+ /* go down and assign all numbers which are not
+ * assigned yet */
+ for (match = match->cp_prev; match
+ && match->cp_number == -1;
+ match = match->cp_prev)
+ match->cp_number = ++number;
+ }
+ }
+
+ /* The match should always have a sequence number now, this is
+ * just a safety check. */
+ if (compl_curr_match->cp_number != -1)
+ {
+ /* Space for 10 text chars. + 2x10-digit no.s = 31.
+ * Translations may need more than twice that. */
+ static char_u match_ref[81];
+
+ if (compl_matches > 0)
+ vim_snprintf((char *)match_ref, sizeof(match_ref),
+ _("match %d of %d"),
+ compl_curr_match->cp_number, compl_matches);
+ else
+ vim_snprintf((char *)match_ref, sizeof(match_ref),
+ _("match %d"),
+ compl_curr_match->cp_number);
+ edit_submode_extra = match_ref;
+ edit_submode_highl = HLF_R;
+ if (dollar_vcol >= 0)
+ curs_columns(FALSE);
+ }
+ }
+ }
+
+ // Show a message about what (completion) mode we're in.
+ if (!compl_opt_suppress_empty)
+ {
+ showmode();
+ if (!shortmess(SHM_COMPLETIONMENU))
+ {
+ if (edit_submode_extra != NULL)
+ {
+ if (!p_smd)
+ msg_attr((char *)edit_submode_extra,
+ edit_submode_highl < HLF_COUNT
+ ? HL_ATTR(edit_submode_highl) : 0);
+ }
+ else
+ msg_clr_cmdline(); // necessary for "noshowmode"
+ }
+ }
+
+ /* Show the popup menu, unless we got interrupted. */
+ if (enable_pum && !compl_interrupted)
+ show_pum(save_w_wrow, save_w_leftcol);
+
+ compl_was_interrupted = compl_interrupted;
+ compl_interrupted = FALSE;
+
+ return OK;
+}
+
+ static void
+show_pum(int prev_w_wrow, int prev_w_leftcol)
+{
+ /* RedrawingDisabled may be set when invoked through complete(). */
+ int n = RedrawingDisabled;
+
+ RedrawingDisabled = 0;
+
+ /* If the cursor moved or the display scrolled we need to remove the pum
+ * first. */
+ setcursor();
+ if (prev_w_wrow != curwin->w_wrow || prev_w_leftcol != curwin->w_leftcol)
+ ins_compl_del_pum();
+
+ ins_compl_show_pum();
+ setcursor();
+ RedrawingDisabled = n;
+}
+
+/*
+ * Looks in the first "len" chars. of "src" for search-metachars.
+ * If dest is not NULL the chars. are copied there quoting (with
+ * a backslash) the metachars, and dest would be NUL terminated.
+ * Returns the length (needed) of dest
+ */
+ static unsigned
+quote_meta(char_u *dest, char_u *src, int len)
+{
+ unsigned m = (unsigned)len + 1; /* one extra for the NUL */
+
+ for ( ; --len >= 0; src++)
+ {
+ switch (*src)
+ {
+ case '.':
+ case '*':
+ case '[':
+ if (ctrl_x_mode == CTRL_X_DICTIONARY
+ || ctrl_x_mode == CTRL_X_THESAURUS)
+ break;
+ /* FALLTHROUGH */
+ case '~':
+ if (!p_magic) /* quote these only if magic is set */
+ break;
+ /* FALLTHROUGH */
+ case '\\':
+ if (ctrl_x_mode == CTRL_X_DICTIONARY
+ || ctrl_x_mode == CTRL_X_THESAURUS)
+ break;
+ /* FALLTHROUGH */
+ case '^': /* currently it's not needed. */
+ case '$':
+ m++;
+ if (dest != NULL)
+ *dest++ = '\\';
+ break;
+ }
+ if (dest != NULL)
+ *dest++ = *src;
+ /* Copy remaining bytes of a multibyte character. */
+ if (has_mbyte)
+ {
+ int i, mb_len;
+
+ mb_len = (*mb_ptr2len)(src) - 1;
+ if (mb_len > 0 && len >= mb_len)
+ for (i = 0; i < mb_len; ++i)
+ {
+ --len;
+ ++src;
+ if (dest != NULL)
+ *dest++ = *src;
+ }
+ }
+ }
+ if (dest != NULL)
+ *dest = NUL;
+
+ return m;
+}
+#endif /* FEAT_INS_EXPAND */
+
+/*
+ * Next character is interpreted literally.
+ * A one, two or three digit decimal number is interpreted as its byte value.
+ * If one or two digits are entered, the next character is given to vungetc().
+ * For Unicode a character > 255 may be returned.
+ */
+ int
+get_literal(void)
+{
+ int cc;
+ int nc;
+ int i;
+ int hex = FALSE;
+ int octal = FALSE;
+ int unicode = 0;
+
+ if (got_int)
+ return Ctrl_C;
+
+#ifdef FEAT_GUI
+ /*
+ * In GUI there is no point inserting the internal code for a special key.
+ * It is more useful to insert the string "<KEY>" instead. This would
+ * probably be useful in a text window too, but it would not be
+ * vi-compatible (maybe there should be an option for it?) -- webb
+ */
+ if (gui.in_use)
+ ++allow_keys;
+#endif
+#ifdef USE_ON_FLY_SCROLL
+ dont_scroll = TRUE; /* disallow scrolling here */
+#endif
+ ++no_mapping; /* don't map the next key hits */
+ cc = 0;
+ i = 0;
+ for (;;)
+ {
+ nc = plain_vgetc();
+#ifdef FEAT_CMDL_INFO
+ if (!(State & CMDLINE) && MB_BYTE2LEN_CHECK(nc) == 1)
+ add_to_showcmd(nc);
+#endif
+ if (nc == 'x' || nc == 'X')
+ hex = TRUE;
+ else if (nc == 'o' || nc == 'O')
+ octal = TRUE;
+ else if (nc == 'u' || nc == 'U')
+ unicode = nc;
+ else
+ {
+ if (hex || unicode != 0)
+ {
+ if (!vim_isxdigit(nc))
+ break;
+ cc = cc * 16 + hex2nr(nc);
+ }
+ else if (octal)
+ {
+ if (nc < '0' || nc > '7')
+ break;
+ cc = cc * 8 + nc - '0';
+ }
+ else
+ {
+ if (!VIM_ISDIGIT(nc))
+ break;
+ cc = cc * 10 + nc - '0';
+ }
+
+ ++i;
+ }
+
+ if (cc > 255 && unicode == 0)
+ cc = 255; /* limit range to 0-255 */
+ nc = 0;
+
+ if (hex) /* hex: up to two chars */
+ {
+ if (i >= 2)
+ break;
+ }
+ else if (unicode) /* Unicode: up to four or eight chars */
+ {
+ if ((unicode == 'u' && i >= 4) || (unicode == 'U' && i >= 8))
+ break;
+ }
+ else if (i >= 3) /* decimal or octal: up to three chars */
+ break;
+ }
+ if (i == 0) /* no number entered */
+ {
+ if (nc == K_ZERO) /* NUL is stored as NL */
+ {
+ cc = '\n';
+ nc = 0;
+ }
+ else
+ {
+ cc = nc;
+ nc = 0;
+ }
+ }
+
+ if (cc == 0) /* NUL is stored as NL */
+ cc = '\n';
+ if (enc_dbcs && (cc & 0xff) == 0)
+ cc = '?'; /* don't accept an illegal DBCS char, the NUL in the
+ second byte will cause trouble! */
+
+ --no_mapping;
+#ifdef FEAT_GUI
+ if (gui.in_use)
+ --allow_keys;
+#endif
+ if (nc)
+ vungetc(nc);
+ got_int = FALSE; /* CTRL-C typed after CTRL-V is not an interrupt */
+ return cc;
+}
+
+/*
+ * Insert character, taking care of special keys and mod_mask
+ */
+ static void
+insert_special(
+ int c,
+ int allow_modmask,
+ int ctrlv) /* c was typed after CTRL-V */
+{
+ char_u *p;
+ int len;
+
+ /*
+ * Special function key, translate into "<Key>". Up to the last '>' is
+ * inserted with ins_str(), so as not to replace characters in replace
+ * mode.
+ * Only use mod_mask for special keys, to avoid things like <S-Space>,
+ * unless 'allow_modmask' is TRUE.
+ */
+#ifdef MACOS_X
+ /* Command-key never produces a normal key */
+ if (mod_mask & MOD_MASK_CMD)
+ allow_modmask = TRUE;
+#endif
+ if (IS_SPECIAL(c) || (mod_mask && allow_modmask))
+ {
+ p = get_special_key_name(c, mod_mask);
+ len = (int)STRLEN(p);
+ c = p[len - 1];
+ if (len > 2)
+ {
+ if (stop_arrow() == FAIL)
+ return;
+ p[len - 1] = NUL;
+ ins_str(p);
+ AppendToRedobuffLit(p, -1);
+ ctrlv = FALSE;
+ }
+ }
+ if (stop_arrow() == OK)
+ insertchar(c, ctrlv ? INSCHAR_CTRLV : 0, -1);
+}
+
+/*
+ * Special characters in this context are those that need processing other
+ * than the simple insertion that can be performed here. This includes ESC
+ * which terminates the insert, and CR/NL which need special processing to
+ * open up a new line. This routine tries to optimize insertions performed by
+ * the "redo", "undo" or "put" commands, so it needs to know when it should
+ * stop and defer processing to the "normal" mechanism.
+ * '0' and '^' are special, because they can be followed by CTRL-D.
+ */
+#ifdef EBCDIC
+# define ISSPECIAL(c) ((c) < ' ' || (c) == '0' || (c) == '^')
+#else
+# define ISSPECIAL(c) ((c) < ' ' || (c) >= DEL || (c) == '0' || (c) == '^')
+#endif
+
+#define WHITECHAR(cc) (VIM_ISWHITE(cc) && (!enc_utf8 || !utf_iscomposing(utf_ptr2char(ml_get_cursor() + 1))))
+
+/*
+ * "flags": INSCHAR_FORMAT - force formatting
+ * INSCHAR_CTRLV - char typed just after CTRL-V
+ * INSCHAR_NO_FEX - don't use 'formatexpr'
+ *
+ * NOTE: passes the flags value straight through to internal_format() which,
+ * beside INSCHAR_FORMAT (above), is also looking for these:
+ * INSCHAR_DO_COM - format comments
+ * INSCHAR_COM_LIST - format comments with num list or 2nd line indent
+ */
+ void
+insertchar(
+ int c, /* character to insert or NUL */
+ int flags, /* INSCHAR_FORMAT, etc. */
+ int second_indent) /* indent for second line if >= 0 */
+{
+ int textwidth;
+#ifdef FEAT_COMMENTS
+ char_u *p;
+#endif
+ int fo_ins_blank;
+ int force_format = flags & INSCHAR_FORMAT;
+
+ textwidth = comp_textwidth(force_format);
+ fo_ins_blank = has_format_option(FO_INS_BLANK);
+
+ /*
+ * Try to break the line in two or more pieces when:
+ * - Always do this if we have been called to do formatting only.
+ * - Always do this when 'formatoptions' has the 'a' flag and the line
+ * ends in white space.
+ * - Otherwise:
+ * - Don't do this if inserting a blank
+ * - Don't do this if an existing character is being replaced, unless
+ * we're in VREPLACE mode.
+ * - Do this if the cursor is not on the line where insert started
+ * or - 'formatoptions' doesn't have 'l' or the line was not too long
+ * before the insert.
+ * - 'formatoptions' doesn't have 'b' or a blank was inserted at or
+ * before 'textwidth'
+ */
+ if (textwidth > 0
+ && (force_format
+ || (!VIM_ISWHITE(c)
+ && !((State & REPLACE_FLAG)
+ && !(State & VREPLACE_FLAG)
+ && *ml_get_cursor() != NUL)
+ && (curwin->w_cursor.lnum != Insstart.lnum
+ || ((!has_format_option(FO_INS_LONG)
+ || Insstart_textlen <= (colnr_T)textwidth)
+ && (!fo_ins_blank
+ || Insstart_blank_vcol <= (colnr_T)textwidth
+ ))))))
+ {
+ /* Format with 'formatexpr' when it's set. Use internal formatting
+ * when 'formatexpr' isn't set or it returns non-zero. */
+#if defined(FEAT_EVAL)
+ int do_internal = TRUE;
+ colnr_T virtcol = get_nolist_virtcol()
+ + char2cells(c != NUL ? c : gchar_cursor());
+
+ if (*curbuf->b_p_fex != NUL && (flags & INSCHAR_NO_FEX) == 0
+ && (force_format || virtcol > (colnr_T)textwidth))
+ {
+ do_internal = (fex_format(curwin->w_cursor.lnum, 1L, c) != 0);
+ /* It may be required to save for undo again, e.g. when setline()
+ * was called. */
+ ins_need_undo = TRUE;
+ }
+ if (do_internal)
+#endif
+ internal_format(textwidth, second_indent, flags, c == NUL, c);
+ }
+
+ if (c == NUL) /* only formatting was wanted */
+ return;
+
+#ifdef FEAT_COMMENTS
+ /* Check whether this character should end a comment. */
+ if (did_ai && (int)c == end_comment_pending)
+ {
+ char_u *line;
+ char_u lead_end[COM_MAX_LEN]; /* end-comment string */
+ int middle_len, end_len;
+ int i;
+
+ /*
+ * Need to remove existing (middle) comment leader and insert end
+ * comment leader. First, check what comment leader we can find.
+ */
+ i = get_leader_len(line = ml_get_curline(), &p, FALSE, TRUE);
+ if (i > 0 && vim_strchr(p, COM_MIDDLE) != NULL) /* Just checking */
+ {
+ /* Skip middle-comment string */
+ while (*p && p[-1] != ':') /* find end of middle flags */
+ ++p;
+ middle_len = copy_option_part(&p, lead_end, COM_MAX_LEN, ",");
+ /* Don't count trailing white space for middle_len */
+ while (middle_len > 0 && VIM_ISWHITE(lead_end[middle_len - 1]))
+ --middle_len;
+
+ /* Find the end-comment string */
+ while (*p && p[-1] != ':') /* find end of end flags */
+ ++p;
+ end_len = copy_option_part(&p, lead_end, COM_MAX_LEN, ",");
+
+ /* Skip white space before the cursor */
+ i = curwin->w_cursor.col;
+ while (--i >= 0 && VIM_ISWHITE(line[i]))
+ ;
+ i++;
+
+ /* Skip to before the middle leader */
+ i -= middle_len;
+
+ /* Check some expected things before we go on */
+ if (i >= 0 && lead_end[end_len - 1] == end_comment_pending)
+ {
+ /* Backspace over all the stuff we want to replace */
+ backspace_until_column(i);
+
+ /*
+ * Insert the end-comment string, except for the last
+ * character, which will get inserted as normal later.
+ */
+ ins_bytes_len(lead_end, end_len - 1);
+ }
+ }
+ }
+ end_comment_pending = NUL;
+#endif
+
+ did_ai = FALSE;
+#ifdef FEAT_SMARTINDENT
+ did_si = FALSE;
+ can_si = FALSE;
+ can_si_back = FALSE;
+#endif
+
+ /*
+ * If there's any pending input, grab up to INPUT_BUFLEN at once.
+ * This speeds up normal text input considerably.
+ * Don't do this when 'cindent' or 'indentexpr' is set, because we might
+ * need to re-indent at a ':', or any other character (but not what
+ * 'paste' is set)..
+ * Don't do this when there an InsertCharPre autocommand is defined,
+ * because we need to fire the event for every character.
+ * Do the check for InsertCharPre before the call to vpeekc() because the
+ * InsertCharPre autocommand could change the input buffer.
+ */
+#ifdef USE_ON_FLY_SCROLL
+ dont_scroll = FALSE; /* allow scrolling here */
+#endif
+
+ if ( !ISSPECIAL(c)
+ && (!has_mbyte || (*mb_char2len)(c) == 1)
+ && !has_insertcharpre()
+ && vpeekc() != NUL
+ && !(State & REPLACE_FLAG)
+#ifdef FEAT_CINDENT
+ && !cindent_on()
+#endif
+#ifdef FEAT_RIGHTLEFT
+ && !p_ri
+#endif
+ )
+ {
+#define INPUT_BUFLEN 100
+ char_u buf[INPUT_BUFLEN + 1];
+ int i;
+ colnr_T virtcol = 0;
+
+ buf[0] = c;
+ i = 1;
+ if (textwidth > 0)
+ virtcol = get_nolist_virtcol();
+ /*
+ * Stop the string when:
+ * - no more chars available
+ * - finding a special character (command key)
+ * - buffer is full
+ * - running into the 'textwidth' boundary
+ * - need to check for abbreviation: A non-word char after a word-char
+ */
+ while ( (c = vpeekc()) != NUL
+ && !ISSPECIAL(c)
+ && (!has_mbyte || MB_BYTE2LEN_CHECK(c) == 1)
+ && i < INPUT_BUFLEN
+# ifdef FEAT_FKMAP
+ && !(p_fkmap && KeyTyped) /* Farsi mode mapping moves cursor */
+# endif
+ && (textwidth == 0
+ || (virtcol += byte2cells(buf[i - 1])) < (colnr_T)textwidth)
+ && !(!no_abbr && !vim_iswordc(c) && vim_iswordc(buf[i - 1])))
+ {
+#ifdef FEAT_RIGHTLEFT
+ c = vgetc();
+ if (p_hkmap && KeyTyped)
+ c = hkmap(c); /* Hebrew mode mapping */
+ buf[i++] = c;
+#else
+ buf[i++] = vgetc();
+#endif
+ }
+
+#ifdef FEAT_DIGRAPHS
+ do_digraph(-1); /* clear digraphs */
+ do_digraph(buf[i-1]); /* may be the start of a digraph */
+#endif
+ buf[i] = NUL;
+ ins_str(buf);
+ if (flags & INSCHAR_CTRLV)
+ {
+ redo_literal(*buf);
+ i = 1;
+ }
+ else
+ i = 0;
+ if (buf[i] != NUL)
+ AppendToRedobuffLit(buf + i, -1);
+ }
+ else
+ {
+ int cc;
+
+ if (has_mbyte && (cc = (*mb_char2len)(c)) > 1)
+ {
+ char_u buf[MB_MAXBYTES + 1];
+
+ (*mb_char2bytes)(c, buf);
+ buf[cc] = NUL;
+ ins_char_bytes(buf, cc);
+ AppendCharToRedobuff(c);
+ }
+ else
+ {
+ ins_char(c);
+ if (flags & INSCHAR_CTRLV)
+ redo_literal(c);
+ else
+ AppendCharToRedobuff(c);
+ }
+ }
+}
+
+/*
+ * Format text at the current insert position.
+ *
+ * If the INSCHAR_COM_LIST flag is present, then the value of second_indent
+ * will be the comment leader length sent to open_line().
+ */
+ static void
+internal_format(
+ int textwidth,
+ int second_indent,
+ int flags,
+ int format_only,
+ int c) /* character to be inserted (can be NUL) */
+{
+ int cc;
+ int save_char = NUL;
+ int haveto_redraw = FALSE;
+ int fo_ins_blank = has_format_option(FO_INS_BLANK);
+ int fo_multibyte = has_format_option(FO_MBYTE_BREAK);
+ int fo_white_par = has_format_option(FO_WHITE_PAR);
+ int first_line = TRUE;
+#ifdef FEAT_COMMENTS
+ colnr_T leader_len;
+ int no_leader = FALSE;
+ int do_comments = (flags & INSCHAR_DO_COM);
+#endif
+#ifdef FEAT_LINEBREAK
+ int has_lbr = curwin->w_p_lbr;
+
+ /* make sure win_lbr_chartabsize() counts correctly */
+ curwin->w_p_lbr = FALSE;
+#endif
+
+ /*
+ * When 'ai' is off we don't want a space under the cursor to be
+ * deleted. Replace it with an 'x' temporarily.
+ */
+ if (!curbuf->b_p_ai && !(State & VREPLACE_FLAG))
+ {
+ cc = gchar_cursor();
+ if (VIM_ISWHITE(cc))
+ {
+ save_char = cc;
+ pchar_cursor('x');
+ }
+ }
+
+ /*
+ * Repeat breaking lines, until the current line is not too long.
+ */
+ while (!got_int)
+ {
+ int startcol; /* Cursor column at entry */
+ int wantcol; /* column at textwidth border */
+ int foundcol; /* column for start of spaces */
+ int end_foundcol = 0; /* column for start of word */
+ colnr_T len;
+ colnr_T virtcol;
+ int orig_col = 0;
+ char_u *saved_text = NULL;
+ colnr_T col;
+ colnr_T end_col;
+ int wcc; // counter for whitespace chars
+
+ virtcol = get_nolist_virtcol()
+ + char2cells(c != NUL ? c : gchar_cursor());
+ if (virtcol <= (colnr_T)textwidth)
+ break;
+
+#ifdef FEAT_COMMENTS
+ if (no_leader)
+ do_comments = FALSE;
+ else if (!(flags & INSCHAR_FORMAT)
+ && has_format_option(FO_WRAP_COMS))
+ do_comments = TRUE;
+
+ /* Don't break until after the comment leader */
+ if (do_comments)
+ leader_len = get_leader_len(ml_get_curline(), NULL, FALSE, TRUE);
+ else
+ leader_len = 0;
+
+ /* If the line doesn't start with a comment leader, then don't
+ * start one in a following broken line. Avoids that a %word
+ * moved to the start of the next line causes all following lines
+ * to start with %. */
+ if (leader_len == 0)
+ no_leader = TRUE;
+#endif
+ if (!(flags & INSCHAR_FORMAT)
+#ifdef FEAT_COMMENTS
+ && leader_len == 0
+#endif
+ && !has_format_option(FO_WRAP))
+
+ break;
+ if ((startcol = curwin->w_cursor.col) == 0)
+ break;
+
+ /* find column of textwidth border */
+ coladvance((colnr_T)textwidth);
+ wantcol = curwin->w_cursor.col;
+
+ curwin->w_cursor.col = startcol;
+ foundcol = 0;
+
+ /*
+ * Find position to break at.
+ * Stop at first entered white when 'formatoptions' has 'v'
+ */
+ while ((!fo_ins_blank && !has_format_option(FO_INS_VI))
+ || (flags & INSCHAR_FORMAT)
+ || curwin->w_cursor.lnum != Insstart.lnum
+ || curwin->w_cursor.col >= Insstart.col)
+ {
+ if (curwin->w_cursor.col == startcol && c != NUL)
+ cc = c;
+ else
+ cc = gchar_cursor();
+ if (WHITECHAR(cc))
+ {
+ /* remember position of blank just before text */
+ end_col = curwin->w_cursor.col;
+
+ // find start of sequence of blanks
+ wcc = 0;
+ while (curwin->w_cursor.col > 0 && WHITECHAR(cc))
+ {
+ dec_cursor();
+ cc = gchar_cursor();
+
+ // Increment count of how many whitespace chars in this
+ // group; we only need to know if it's more than one.
+ if (wcc < 2)
+ wcc++;
+ }
+ if (curwin->w_cursor.col == 0 && WHITECHAR(cc))
+ break; /* only spaces in front of text */
+
+ // Don't break after a period when 'formatoptions' has 'p' and
+ // there are less than two spaces.
+ if (has_format_option(FO_PERIOD_ABBR) && cc == '.' && wcc < 2)
+ continue;
+
+#ifdef FEAT_COMMENTS
+ /* Don't break until after the comment leader */
+ if (curwin->w_cursor.col < leader_len)
+ break;
+#endif
+ if (has_format_option(FO_ONE_LETTER))
+ {
+ /* do not break after one-letter words */
+ if (curwin->w_cursor.col == 0)
+ break; /* one-letter word at begin */
+#ifdef FEAT_COMMENTS
+ /* do not break "#a b" when 'tw' is 2 */
+ if (curwin->w_cursor.col <= leader_len)
+ break;
+#endif
+ col = curwin->w_cursor.col;
+ dec_cursor();
+ cc = gchar_cursor();
+
+ if (WHITECHAR(cc))
+ continue; /* one-letter, continue */
+ curwin->w_cursor.col = col;
+ }
+
+ inc_cursor();
+
+ end_foundcol = end_col + 1;
+ foundcol = curwin->w_cursor.col;
+ if (curwin->w_cursor.col <= (colnr_T)wantcol)
+ break;
+ }
+ else if (cc >= 0x100 && fo_multibyte)
+ {
+ /* Break after or before a multi-byte character. */
+ if (curwin->w_cursor.col != startcol)
+ {
+#ifdef FEAT_COMMENTS
+ /* Don't break until after the comment leader */
+ if (curwin->w_cursor.col < leader_len)
+ break;
+#endif
+ col = curwin->w_cursor.col;
+ inc_cursor();
+ /* Don't change end_foundcol if already set. */
+ if (foundcol != curwin->w_cursor.col)
+ {
+ foundcol = curwin->w_cursor.col;
+ end_foundcol = foundcol;
+ if (curwin->w_cursor.col <= (colnr_T)wantcol)
+ break;
+ }
+ curwin->w_cursor.col = col;
+ }
+
+ if (curwin->w_cursor.col == 0)
+ break;
+
+ col = curwin->w_cursor.col;
+
+ dec_cursor();
+ cc = gchar_cursor();
+
+ if (WHITECHAR(cc))
+ continue; /* break with space */
+#ifdef FEAT_COMMENTS
+ /* Don't break until after the comment leader */
+ if (curwin->w_cursor.col < leader_len)
+ break;
+#endif
+
+ curwin->w_cursor.col = col;
+
+ foundcol = curwin->w_cursor.col;
+ end_foundcol = foundcol;
+ if (curwin->w_cursor.col <= (colnr_T)wantcol)
+ break;
+ }
+ if (curwin->w_cursor.col == 0)
+ break;
+ dec_cursor();
+ }
+
+ if (foundcol == 0) /* no spaces, cannot break line */
+ {
+ curwin->w_cursor.col = startcol;
+ break;
+ }
+
+ /* Going to break the line, remove any "$" now. */
+ undisplay_dollar();
+
+ /*
+ * Offset between cursor position and line break is used by replace
+ * stack functions. VREPLACE does not use this, and backspaces
+ * over the text instead.
+ */
+ if (State & VREPLACE_FLAG)
+ orig_col = startcol; /* Will start backspacing from here */
+ else
+ replace_offset = startcol - end_foundcol;
+
+ /*
+ * adjust startcol for spaces that will be deleted and
+ * characters that will remain on top line
+ */
+ curwin->w_cursor.col = foundcol;
+ while ((cc = gchar_cursor(), WHITECHAR(cc))
+ && (!fo_white_par || curwin->w_cursor.col < startcol))
+ inc_cursor();
+ startcol -= curwin->w_cursor.col;
+ if (startcol < 0)
+ startcol = 0;
+
+ if (State & VREPLACE_FLAG)
+ {
+ /*
+ * In VREPLACE mode, we will backspace over the text to be
+ * wrapped, so save a copy now to put on the next line.
+ */
+ saved_text = vim_strsave(ml_get_cursor());
+ curwin->w_cursor.col = orig_col;
+ if (saved_text == NULL)
+ break; /* Can't do it, out of memory */
+ saved_text[startcol] = NUL;
+
+ /* Backspace over characters that will move to the next line */
+ if (!fo_white_par)
+ backspace_until_column(foundcol);
+ }
+ else
+ {
+ /* put cursor after pos. to break line */
+ if (!fo_white_par)
+ curwin->w_cursor.col = foundcol;
+ }
+
+ /*
+ * Split the line just before the margin.
+ * Only insert/delete lines, but don't really redraw the window.
+ */
+ open_line(FORWARD, OPENLINE_DELSPACES + OPENLINE_MARKFIX
+ + (fo_white_par ? OPENLINE_KEEPTRAIL : 0)
+#ifdef FEAT_COMMENTS
+ + (do_comments ? OPENLINE_DO_COM : 0)
+ + ((flags & INSCHAR_COM_LIST) ? OPENLINE_COM_LIST : 0)
+#endif
+ , ((flags & INSCHAR_COM_LIST) ? second_indent : old_indent));
+ if (!(flags & INSCHAR_COM_LIST))
+ old_indent = 0;
+
+ replace_offset = 0;
+ if (first_line)
+ {
+ if (!(flags & INSCHAR_COM_LIST))
+ {
+ /*
+ * This section is for auto-wrap of numeric lists. When not
+ * in insert mode (i.e. format_lines()), the INSCHAR_COM_LIST
+ * flag will be set and open_line() will handle it (as seen
+ * above). The code here (and in get_number_indent()) will
+ * recognize comments if needed...
+ */
+ if (second_indent < 0 && has_format_option(FO_Q_NUMBER))
+ second_indent =
+ get_number_indent(curwin->w_cursor.lnum - 1);
+ if (second_indent >= 0)
+ {
+ if (State & VREPLACE_FLAG)
+ change_indent(INDENT_SET, second_indent,
+ FALSE, NUL, TRUE);
+ else
+#ifdef FEAT_COMMENTS
+ if (leader_len > 0 && second_indent - leader_len > 0)
+ {
+ int i;
+ int padding = second_indent - leader_len;
+
+ /* We started at the first_line of a numbered list
+ * that has a comment. the open_line() function has
+ * inserted the proper comment leader and positioned
+ * the cursor at the end of the split line. Now we
+ * add the additional whitespace needed after the
+ * comment leader for the numbered list. */
+ for (i = 0; i < padding; i++)
+ ins_str((char_u *)" ");
+ }
+ else
+ {
+#endif
+ (void)set_indent(second_indent, SIN_CHANGED);
+#ifdef FEAT_COMMENTS
+ }
+#endif
+ }
+ }
+ first_line = FALSE;
+ }
+
+ if (State & VREPLACE_FLAG)
+ {
+ /*
+ * In VREPLACE mode we have backspaced over the text to be
+ * moved, now we re-insert it into the new line.
+ */
+ ins_bytes(saved_text);
+ vim_free(saved_text);
+ }
+ else
+ {
+ /*
+ * Check if cursor is not past the NUL off the line, cindent
+ * may have added or removed indent.
+ */
+ curwin->w_cursor.col += startcol;
+ len = (colnr_T)STRLEN(ml_get_curline());
+ if (curwin->w_cursor.col > len)
+ curwin->w_cursor.col = len;
+ }
+
+ haveto_redraw = TRUE;
+#ifdef FEAT_CINDENT
+ can_cindent = TRUE;
+#endif
+ /* moved the cursor, don't autoindent or cindent now */
+ did_ai = FALSE;
+#ifdef FEAT_SMARTINDENT
+ did_si = FALSE;
+ can_si = FALSE;
+ can_si_back = FALSE;
+#endif
+ line_breakcheck();
+ }
+
+ if (save_char != NUL) /* put back space after cursor */
+ pchar_cursor(save_char);
+
+#ifdef FEAT_LINEBREAK
+ curwin->w_p_lbr = has_lbr;
+#endif
+ if (!format_only && haveto_redraw)
+ {
+ update_topline();
+ redraw_curbuf_later(VALID);
+ }
+}
+
+/*
+ * Called after inserting or deleting text: When 'formatoptions' includes the
+ * 'a' flag format from the current line until the end of the paragraph.
+ * Keep the cursor at the same position relative to the text.
+ * The caller must have saved the cursor line for undo, following ones will be
+ * saved here.
+ */
+ void
+auto_format(
+ int trailblank, /* when TRUE also format with trailing blank */
+ int prev_line) /* may start in previous line */
+{
+ pos_T pos;
+ colnr_T len;
+ char_u *old;
+ char_u *new, *pnew;
+ int wasatend;
+ int cc;
+
+ if (!has_format_option(FO_AUTO))
+ return;
+
+ pos = curwin->w_cursor;
+ old = ml_get_curline();
+
+ /* may remove added space */
+ check_auto_format(FALSE);
+
+ /* Don't format in Insert mode when the cursor is on a trailing blank, the
+ * user might insert normal text next. Also skip formatting when "1" is
+ * in 'formatoptions' and there is a single character before the cursor.
+ * Otherwise the line would be broken and when typing another non-white
+ * next they are not joined back together. */
+ wasatend = (pos.col == (colnr_T)STRLEN(old));
+ if (*old != NUL && !trailblank && wasatend)
+ {
+ dec_cursor();
+ cc = gchar_cursor();
+ if (!WHITECHAR(cc) && curwin->w_cursor.col > 0
+ && has_format_option(FO_ONE_LETTER))
+ dec_cursor();
+ cc = gchar_cursor();
+ if (WHITECHAR(cc))
+ {
+ curwin->w_cursor = pos;
+ return;
+ }
+ curwin->w_cursor = pos;
+ }
+
+#ifdef FEAT_COMMENTS
+ /* With the 'c' flag in 'formatoptions' and 't' missing: only format
+ * comments. */
+ if (has_format_option(FO_WRAP_COMS) && !has_format_option(FO_WRAP)
+ && get_leader_len(old, NULL, FALSE, TRUE) == 0)
+ return;
+#endif
+
+ /*
+ * May start formatting in a previous line, so that after "x" a word is
+ * moved to the previous line if it fits there now. Only when this is not
+ * the start of a paragraph.
+ */
+ if (prev_line && !paragraph_start(curwin->w_cursor.lnum))
+ {
+ --curwin->w_cursor.lnum;
+ if (u_save_cursor() == FAIL)
+ return;
+ }
+
+ /*
+ * Do the formatting and restore the cursor position. "saved_cursor" will
+ * be adjusted for the text formatting.
+ */
+ saved_cursor = pos;
+ format_lines((linenr_T)-1, FALSE);
+ curwin->w_cursor = saved_cursor;
+ saved_cursor.lnum = 0;
+
+ if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
+ {
+ /* "cannot happen" */
+ curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
+ coladvance((colnr_T)MAXCOL);
+ }
+ else
+ check_cursor_col();
+
+ /* Insert mode: If the cursor is now after the end of the line while it
+ * previously wasn't, the line was broken. Because of the rule above we
+ * need to add a space when 'w' is in 'formatoptions' to keep a paragraph
+ * formatted. */
+ if (!wasatend && has_format_option(FO_WHITE_PAR))
+ {
+ new = ml_get_curline();
+ len = (colnr_T)STRLEN(new);
+ if (curwin->w_cursor.col == len)
+ {
+ pnew = vim_strnsave(new, len + 2);
+ pnew[len] = ' ';
+ pnew[len + 1] = NUL;
+ ml_replace(curwin->w_cursor.lnum, pnew, FALSE);
+ /* remove the space later */
+ did_add_space = TRUE;
+ }
+ else
+ /* may remove added space */
+ check_auto_format(FALSE);
+ }
+
+ check_cursor();
+}
+
+/*
+ * When an extra space was added to continue a paragraph for auto-formatting,
+ * delete it now. The space must be under the cursor, just after the insert
+ * position.
+ */
+ static void
+check_auto_format(
+ int end_insert) /* TRUE when ending Insert mode */
+{
+ int c = ' ';
+ int cc;
+
+ if (did_add_space)
+ {
+ cc = gchar_cursor();
+ if (!WHITECHAR(cc))
+ /* Somehow the space was removed already. */
+ did_add_space = FALSE;
+ else
+ {
+ if (!end_insert)
+ {
+ inc_cursor();
+ c = gchar_cursor();
+ dec_cursor();
+ }
+ if (c != NUL)
+ {
+ /* The space is no longer at the end of the line, delete it. */
+ del_char(FALSE);
+ did_add_space = FALSE;
+ }
+ }
+ }
+}
+
+/*
+ * Find out textwidth to be used for formatting:
+ * if 'textwidth' option is set, use it
+ * else if 'wrapmargin' option is set, use curwin->w_width - 'wrapmargin'
+ * if invalid value, use 0.
+ * Set default to window width (maximum 79) for "gq" operator.
+ */
+ int
+comp_textwidth(
+ int ff) /* force formatting (for "gq" command) */
+{
+ int textwidth;
+
+ textwidth = curbuf->b_p_tw;
+ if (textwidth == 0 && curbuf->b_p_wm)
+ {
+ /* The width is the window width minus 'wrapmargin' minus all the
+ * things that add to the margin. */
+ textwidth = curwin->w_width - curbuf->b_p_wm;
+#ifdef FEAT_CMDWIN
+ if (cmdwin_type != 0)
+ textwidth -= 1;
+#endif
+#ifdef FEAT_FOLDING
+ textwidth -= curwin->w_p_fdc;
+#endif
+#ifdef FEAT_SIGNS
+ if (signcolumn_on(curwin))
+ textwidth -= 1;
+#endif
+ if (curwin->w_p_nu || curwin->w_p_rnu)
+ textwidth -= 8;
+ }
+ if (textwidth < 0)
+ textwidth = 0;
+ if (ff && textwidth == 0)
+ {
+ textwidth = curwin->w_width - 1;
+ if (textwidth > 79)
+ textwidth = 79;
+ }
+ return textwidth;
+}
+
+/*
+ * Put a character in the redo buffer, for when just after a CTRL-V.
+ */
+ static void
+redo_literal(int c)
+{
+ char_u buf[10];
+
+ /* Only digits need special treatment. Translate them into a string of
+ * three digits. */
+ if (VIM_ISDIGIT(c))
+ {
+ vim_snprintf((char *)buf, sizeof(buf), "%03d", c);
+ AppendToRedobuff(buf);
+ }
+ else
+ AppendCharToRedobuff(c);
+}
+
+/*
+ * start_arrow() is called when an arrow key is used in insert mode.
+ * For undo/redo it resembles hitting the <ESC> key.
+ */
+ static void
+start_arrow(
+ pos_T *end_insert_pos) /* can be NULL */
+{
+ start_arrow_common(end_insert_pos, TRUE);
+}
+
+/*
+ * Like start_arrow() but with end_change argument.
+ * Will prepare for redo of CTRL-G U if "end_change" is FALSE.
+ */
+ static void
+start_arrow_with_change(
+ pos_T *end_insert_pos, /* can be NULL */
+ int end_change) /* end undoable change */
+{
+ start_arrow_common(end_insert_pos, end_change);
+ if (!end_change)
+ {
+ AppendCharToRedobuff(Ctrl_G);
+ AppendCharToRedobuff('U');
+ }
+}
+
+ static void
+start_arrow_common(
+ pos_T *end_insert_pos, /* can be NULL */
+ int end_change) /* end undoable change */
+{
+ if (!arrow_used && end_change) /* something has been inserted */
+ {
+ AppendToRedobuff(ESC_STR);
+ stop_insert(end_insert_pos, FALSE, FALSE);
+ arrow_used = TRUE; /* this means we stopped the current insert */
+ }
+#ifdef FEAT_SPELL
+ check_spell_redraw();
+#endif
+}
+
+#ifdef FEAT_SPELL
+/*
+ * If we skipped highlighting word at cursor, do it now.
+ * It may be skipped again, thus reset spell_redraw_lnum first.
+ */
+ static void
+check_spell_redraw(void)
+{
+ if (spell_redraw_lnum != 0)
+ {
+ linenr_T lnum = spell_redraw_lnum;
+
+ spell_redraw_lnum = 0;
+ redrawWinline(curwin, lnum);
+ }
+}
+
+/*
+ * Called when starting CTRL_X_SPELL mode: Move backwards to a previous badly
+ * spelled word, if there is one.
+ */
+ static void
+spell_back_to_badword(void)
+{
+ pos_T tpos = curwin->w_cursor;
+
+ spell_bad_len = spell_move_to(curwin, BACKWARD, TRUE, TRUE, NULL);
+ if (curwin->w_cursor.col != tpos.col)
+ start_arrow(&tpos);
+}
+#endif
+
+/*
+ * stop_arrow() is called before a change is made in insert mode.
+ * If an arrow key has been used, start a new insertion.
+ * Returns FAIL if undo is impossible, shouldn't insert then.
+ */
+ int
+stop_arrow(void)
+{
+ if (arrow_used)
+ {
+ Insstart = curwin->w_cursor; /* new insertion starts here */
+ if (Insstart.col > Insstart_orig.col && !ins_need_undo)
+ /* Don't update the original insert position when moved to the
+ * right, except when nothing was inserted yet. */
+ update_Insstart_orig = FALSE;
+ Insstart_textlen = (colnr_T)linetabsize(ml_get_curline());
+
+ if (u_save_cursor() == OK)
+ {
+ arrow_used = FALSE;
+ ins_need_undo = FALSE;
+ }
+
+ ai_col = 0;
+ if (State & VREPLACE_FLAG)
+ {
+ orig_line_count = curbuf->b_ml.ml_line_count;
+ vr_lines_changed = 1;
+ }
+ ResetRedobuff();
+ AppendToRedobuff((char_u *)"1i"); /* pretend we start an insertion */
+ new_insert_skip = 2;
+ }
+ else if (ins_need_undo)
+ {
+ if (u_save_cursor() == OK)
+ ins_need_undo = FALSE;
+ }
+
+#ifdef FEAT_FOLDING
+ /* Always open fold at the cursor line when inserting something. */
+ foldOpenCursor();
+#endif
+
+ return (arrow_used || ins_need_undo ? FAIL : OK);
+}
+
+/*
+ * Do a few things to stop inserting.
+ * "end_insert_pos" is where insert ended. It is NULL when we already jumped
+ * to another window/buffer.
+ */
+ static void
+stop_insert(
+ pos_T *end_insert_pos,
+ int esc, /* called by ins_esc() */
+ int nomove) /* <c-\><c-o>, don't move cursor */
+{
+ int cc;
+ char_u *ptr;
+
+ stop_redo_ins();
+ replace_flush(); /* abandon replace stack */
+
+ /*
+ * Save the inserted text for later redo with ^@ and CTRL-A.
+ * Don't do it when "restart_edit" was set and nothing was inserted,
+ * otherwise CTRL-O w and then <Left> will clear "last_insert".
+ */
+ ptr = get_inserted();
+ if (did_restart_edit == 0 || (ptr != NULL
+ && (int)STRLEN(ptr) > new_insert_skip))
+ {
+ vim_free(last_insert);
+ last_insert = ptr;
+ last_insert_skip = new_insert_skip;
+ }
+ else
+ vim_free(ptr);
+
+ if (!arrow_used && end_insert_pos != NULL)
+ {
+ /* Auto-format now. It may seem strange to do this when stopping an
+ * insertion (or moving the cursor), but it's required when appending
+ * a line and having it end in a space. But only do it when something
+ * was actually inserted, otherwise undo won't work. */
+ if (!ins_need_undo && has_format_option(FO_AUTO))
+ {
+ pos_T tpos = curwin->w_cursor;
+
+ /* When the cursor is at the end of the line after a space the
+ * formatting will move it to the following word. Avoid that by
+ * moving the cursor onto the space. */
+ cc = 'x';
+ if (curwin->w_cursor.col > 0 && gchar_cursor() == NUL)
+ {
+ dec_cursor();
+ cc = gchar_cursor();
+ if (!VIM_ISWHITE(cc))
+ curwin->w_cursor = tpos;
+ }
+
+ auto_format(TRUE, FALSE);
+
+ if (VIM_ISWHITE(cc))
+ {
+ if (gchar_cursor() != NUL)
+ inc_cursor();
+ // If the cursor is still at the same character, also keep
+ // the "coladd".
+ if (gchar_cursor() == NUL
+ && curwin->w_cursor.lnum == tpos.lnum
+ && curwin->w_cursor.col == tpos.col)
+ curwin->w_cursor.coladd = tpos.coladd;
+ }
+ }
+
+ /* If a space was inserted for auto-formatting, remove it now. */
+ check_auto_format(TRUE);
+
+ /* If we just did an auto-indent, remove the white space from the end
+ * of the line, and put the cursor back.
+ * Do this when ESC was used or moving the cursor up/down.
+ * Check for the old position still being valid, just in case the text
+ * got changed unexpectedly. */
+ if (!nomove && did_ai && (esc || (vim_strchr(p_cpo, CPO_INDENT) == NULL
+ && curwin->w_cursor.lnum != end_insert_pos->lnum))
+ && end_insert_pos->lnum <= curbuf->b_ml.ml_line_count)
+ {
+ pos_T tpos = curwin->w_cursor;
+
+ curwin->w_cursor = *end_insert_pos;
+ check_cursor_col(); /* make sure it is not past the line */
+ for (;;)
+ {
+ if (gchar_cursor() == NUL && curwin->w_cursor.col > 0)
+ --curwin->w_cursor.col;
+ cc = gchar_cursor();
+ if (!VIM_ISWHITE(cc))
+ break;
+ if (del_char(TRUE) == FAIL)
+ break; /* should not happen */
+ }
+ if (curwin->w_cursor.lnum != tpos.lnum)
+ curwin->w_cursor = tpos;
+ else
+ {
+ /* reset tpos, could have been invalidated in the loop above */
+ tpos = curwin->w_cursor;
+ tpos.col++;
+ if (cc != NUL && gchar_pos(&tpos) == NUL)
+ ++curwin->w_cursor.col; /* put cursor back on the NUL */
+ }
+
+ /* <C-S-Right> may have started Visual mode, adjust the position for
+ * deleted characters. */
+ if (VIsual_active && VIsual.lnum == curwin->w_cursor.lnum)
+ {
+ int len = (int)STRLEN(ml_get_curline());
+
+ if (VIsual.col > len)
+ {
+ VIsual.col = len;
+ VIsual.coladd = 0;
+ }
+ }
+ }
+ }
+ did_ai = FALSE;
+#ifdef FEAT_SMARTINDENT
+ did_si = FALSE;
+ can_si = FALSE;
+ can_si_back = FALSE;
+#endif
+
+ /* Set '[ and '] to the inserted text. When end_insert_pos is NULL we are
+ * now in a different buffer. */
+ if (end_insert_pos != NULL)
+ {
+ curbuf->b_op_start = Insstart;
+ curbuf->b_op_start_orig = Insstart_orig;
+ curbuf->b_op_end = *end_insert_pos;
+ }
+}
+
+/*
+ * Set the last inserted text to a single character.
+ * Used for the replace command.
+ */
+ void
+set_last_insert(int c)
+{
+ char_u *s;
+
+ vim_free(last_insert);
+ last_insert = alloc(MB_MAXBYTES * 3 + 5);
+ if (last_insert != NULL)
+ {
+ s = last_insert;
+ /* Use the CTRL-V only when entering a special char */
+ if (c < ' ' || c == DEL)
+ *s++ = Ctrl_V;
+ s = add_char2buf(c, s);
+ *s++ = ESC;
+ *s++ = NUL;
+ last_insert_skip = 0;
+ }
+}
+
+#if defined(EXITFREE) || defined(PROTO)
+ void
+free_last_insert(void)
+{
+ VIM_CLEAR(last_insert);
+# ifdef FEAT_INS_EXPAND
+ VIM_CLEAR(compl_orig_text);
+# endif
+}
+#endif
+
+/*
+ * Add character "c" to buffer "s". Escape the special meaning of K_SPECIAL
+ * and CSI. Handle multi-byte characters.
+ * Returns a pointer to after the added bytes.
+ */
+ char_u *
+add_char2buf(int c, char_u *s)
+{
+ char_u temp[MB_MAXBYTES + 1];
+ int i;
+ int len;
+
+ len = (*mb_char2bytes)(c, temp);
+ for (i = 0; i < len; ++i)
+ {
+ c = temp[i];
+ /* Need to escape K_SPECIAL and CSI like in the typeahead buffer. */
+ if (c == K_SPECIAL)
+ {
+ *s++ = K_SPECIAL;
+ *s++ = KS_SPECIAL;
+ *s++ = KE_FILLER;
+ }
+#ifdef FEAT_GUI
+ else if (c == CSI)
+ {
+ *s++ = CSI;
+ *s++ = KS_EXTRA;
+ *s++ = (int)KE_CSI;
+ }
+#endif
+ else
+ *s++ = c;
+ }
+ return s;
+}
+
+/*
+ * move cursor to start of line
+ * if flags & BL_WHITE move to first non-white
+ * if flags & BL_SOL move to first non-white if startofline is set,
+ * otherwise keep "curswant" column
+ * if flags & BL_FIX don't leave the cursor on a NUL.
+ */
+ void
+beginline(int flags)
+{
+ if ((flags & BL_SOL) && !p_sol)
+ coladvance(curwin->w_curswant);
+ else
+ {
+ curwin->w_cursor.col = 0;
+ curwin->w_cursor.coladd = 0;
+
+ if (flags & (BL_WHITE | BL_SOL))
+ {
+ char_u *ptr;
+
+ for (ptr = ml_get_curline(); VIM_ISWHITE(*ptr)
+ && !((flags & BL_FIX) && ptr[1] == NUL); ++ptr)
+ ++curwin->w_cursor.col;
+ }
+ curwin->w_set_curswant = TRUE;
+ }
+}
+
+/*
+ * oneright oneleft cursor_down cursor_up
+ *
+ * Move one char {right,left,down,up}.
+ * Doesn't move onto the NUL past the end of the line, unless it is allowed.
+ * Return OK when successful, FAIL when we hit a line of file boundary.
+ */
+
+ int
+oneright(void)
+{
+ char_u *ptr;
+ int l;
+
+ if (virtual_active())
+ {
+ pos_T prevpos = curwin->w_cursor;
+
+ /* Adjust for multi-wide char (excluding TAB) */
+ ptr = ml_get_cursor();
+ coladvance(getviscol() + ((*ptr != TAB
+ && vim_isprintc((*mb_ptr2char)(ptr)))
+ ? ptr2cells(ptr) : 1));
+ curwin->w_set_curswant = TRUE;
+ /* Return OK if the cursor moved, FAIL otherwise (at window edge). */
+ return (prevpos.col != curwin->w_cursor.col
+ || prevpos.coladd != curwin->w_cursor.coladd) ? OK : FAIL;
+ }
+
+ ptr = ml_get_cursor();
+ if (*ptr == NUL)
+ return FAIL; /* already at the very end */
+
+ if (has_mbyte)
+ l = (*mb_ptr2len)(ptr);
+ else
+ l = 1;
+
+ /* move "l" bytes right, but don't end up on the NUL, unless 'virtualedit'
+ * contains "onemore". */
+ if (ptr[l] == NUL && (ve_flags & VE_ONEMORE) == 0)
+ return FAIL;
+ curwin->w_cursor.col += l;
+
+ curwin->w_set_curswant = TRUE;
+ return OK;
+}
+
+ int
+oneleft(void)
+{
+ if (virtual_active())
+ {
+#ifdef FEAT_LINEBREAK
+ int width;
+#endif
+ int v = getviscol();
+
+ if (v == 0)
+ return FAIL;
+
+#ifdef FEAT_LINEBREAK
+ /* We might get stuck on 'showbreak', skip over it. */
+ width = 1;
+ for (;;)
+ {
+ coladvance(v - width);
+ /* getviscol() is slow, skip it when 'showbreak' is empty,
+ * 'breakindent' is not set and there are no multi-byte
+ * characters */
+ if ((*p_sbr == NUL && !curwin->w_p_bri
+ && !has_mbyte) || getviscol() < v)
+ break;
+ ++width;
+ }
+#else
+ coladvance(v - 1);
+#endif
+
+ if (curwin->w_cursor.coladd == 1)
+ {
+ char_u *ptr;
+
+ /* Adjust for multi-wide char (not a TAB) */
+ ptr = ml_get_cursor();
+ if (*ptr != TAB && vim_isprintc((*mb_ptr2char)(ptr))
+ && ptr2cells(ptr) > 1)
+ curwin->w_cursor.coladd = 0;
+ }
+
+ curwin->w_set_curswant = TRUE;
+ return OK;
+ }
+
+ if (curwin->w_cursor.col == 0)
+ return FAIL;
+
+ curwin->w_set_curswant = TRUE;
+ --curwin->w_cursor.col;
+
+ /* if the character on the left of the current cursor is a multi-byte
+ * character, move to its first byte */
+ if (has_mbyte)
+ mb_adjust_cursor();
+ return OK;
+}
+
+ int
+cursor_up(
+ long n,
+ int upd_topline) /* When TRUE: update topline */
+{
+ linenr_T lnum;
+
+ if (n > 0)
+ {
+ lnum = curwin->w_cursor.lnum;
+ /* This fails if the cursor is already in the first line or the count
+ * is larger than the line number and '-' is in 'cpoptions' */
+ if (lnum <= 1 || (n >= lnum && vim_strchr(p_cpo, CPO_MINUS) != NULL))
+ return FAIL;
+ if (n >= lnum)
+ lnum = 1;
+ else
+#ifdef FEAT_FOLDING
+ if (hasAnyFolding(curwin))
+ {
+ /*
+ * Count each sequence of folded lines as one logical line.
+ */
+ /* go to the start of the current fold */
+ (void)hasFolding(lnum, &lnum, NULL);
+
+ while (n--)
+ {
+ /* move up one line */
+ --lnum;
+ if (lnum <= 1)
+ break;
+ /* If we entered a fold, move to the beginning, unless in
+ * Insert mode or when 'foldopen' contains "all": it will open
+ * in a moment. */
+ if (n > 0 || !((State & INSERT) || (fdo_flags & FDO_ALL)))
+ (void)hasFolding(lnum, &lnum, NULL);
+ }
+ if (lnum < 1)
+ lnum = 1;
+ }
+ else
+#endif
+ lnum -= n;
+ curwin->w_cursor.lnum = lnum;
+ }
+
+ /* try to advance to the column we want to be at */
+ coladvance(curwin->w_curswant);
+
+ if (upd_topline)
+ update_topline(); /* make sure curwin->w_topline is valid */
+
+ return OK;
+}
+
+/*
+ * Cursor down a number of logical lines.
+ */
+ int
+cursor_down(
+ long n,
+ int upd_topline) /* When TRUE: update topline */
+{
+ linenr_T lnum;
+
+ if (n > 0)
+ {
+ lnum = curwin->w_cursor.lnum;
+#ifdef FEAT_FOLDING
+ /* Move to last line of fold, will fail if it's the end-of-file. */
+ (void)hasFolding(lnum, NULL, &lnum);
+#endif
+ /* This fails if the cursor is already in the last line or would move
+ * beyond the last line and '-' is in 'cpoptions' */
+ if (lnum >= curbuf->b_ml.ml_line_count
+ || (lnum + n > curbuf->b_ml.ml_line_count
+ && vim_strchr(p_cpo, CPO_MINUS) != NULL))
+ return FAIL;
+ if (lnum + n >= curbuf->b_ml.ml_line_count)
+ lnum = curbuf->b_ml.ml_line_count;
+ else
+#ifdef FEAT_FOLDING
+ if (hasAnyFolding(curwin))
+ {
+ linenr_T last;
+
+ /* count each sequence of folded lines as one logical line */
+ while (n--)
+ {
+ if (hasFolding(lnum, NULL, &last))
+ lnum = last + 1;
+ else
+ ++lnum;
+ if (lnum >= curbuf->b_ml.ml_line_count)
+ break;
+ }
+ if (lnum > curbuf->b_ml.ml_line_count)
+ lnum = curbuf->b_ml.ml_line_count;
+ }
+ else
+#endif
+ lnum += n;
+ curwin->w_cursor.lnum = lnum;
+ }
+
+ /* try to advance to the column we want to be at */
+ coladvance(curwin->w_curswant);
+
+ if (upd_topline)
+ update_topline(); /* make sure curwin->w_topline is valid */
+
+ return OK;
+}
+
+/*
+ * Stuff the last inserted text in the read buffer.
+ * Last_insert actually is a copy of the redo buffer, so we
+ * first have to remove the command.
+ */
+ int
+stuff_inserted(
+ int c, /* Command character to be inserted */
+ long count, /* Repeat this many times */
+ int no_esc) /* Don't add an ESC at the end */
+{
+ char_u *esc_ptr;
+ char_u *ptr;
+ char_u *last_ptr;
+ char_u last = NUL;
+
+ ptr = get_last_insert();
+ if (ptr == NULL)
+ {
+ emsg(_(e_noinstext));
+ return FAIL;
+ }
+
+ /* may want to stuff the command character, to start Insert mode */
+ if (c != NUL)
+ stuffcharReadbuff(c);
+ if ((esc_ptr = (char_u *)vim_strrchr(ptr, ESC)) != NULL)
+ *esc_ptr = NUL; /* remove the ESC */
+
+ /* when the last char is either "0" or "^" it will be quoted if no ESC
+ * comes after it OR if it will inserted more than once and "ptr"
+ * starts with ^D. -- Acevedo
+ */
+ last_ptr = (esc_ptr ? esc_ptr : ptr + STRLEN(ptr)) - 1;
+ if (last_ptr >= ptr && (*last_ptr == '0' || *last_ptr == '^')
+ && (no_esc || (*ptr == Ctrl_D && count > 1)))
+ {
+ last = *last_ptr;
+ *last_ptr = NUL;
+ }
+
+ do
+ {
+ stuffReadbuff(ptr);
+ /* a trailing "0" is inserted as "<C-V>048", "^" as "<C-V>^" */
+ if (last)
+ stuffReadbuff((char_u *)(last == '0'
+ ? IF_EB("\026\060\064\070", CTRL_V_STR "xf0")
+ : IF_EB("\026^", CTRL_V_STR "^")));
+ }
+ while (--count > 0);
+
+ if (last)
+ *last_ptr = last;
+
+ if (esc_ptr != NULL)
+ *esc_ptr = ESC; /* put the ESC back */
+
+ /* may want to stuff a trailing ESC, to get out of Insert mode */
+ if (!no_esc)
+ stuffcharReadbuff(ESC);
+
+ return OK;
+}
+
+ char_u *
+get_last_insert(void)
+{
+ if (last_insert == NULL)
+ return NULL;
+ return last_insert + last_insert_skip;
+}
+
+/*
+ * Get last inserted string, and remove trailing <Esc>.
+ * Returns pointer to allocated memory (must be freed) or NULL.
+ */
+ char_u *
+get_last_insert_save(void)
+{
+ char_u *s;
+ int len;
+
+ if (last_insert == NULL)
+ return NULL;
+ s = vim_strsave(last_insert + last_insert_skip);
+ if (s != NULL)
+ {
+ len = (int)STRLEN(s);
+ if (len > 0 && s[len - 1] == ESC) /* remove trailing ESC */
+ s[len - 1] = NUL;
+ }
+ return s;
+}
+
+/*
+ * Check the word in front of the cursor for an abbreviation.
+ * Called when the non-id character "c" has been entered.
+ * When an abbreviation is recognized it is removed from the text and
+ * the replacement string is inserted in typebuf.tb_buf[], followed by "c".
+ */
+ static int
+echeck_abbr(int c)
+{
+ /* Don't check for abbreviation in paste mode, when disabled and just
+ * after moving around with cursor keys. */
+ if (p_paste || no_abbr || arrow_used)
+ return FALSE;
+
+ return check_abbr(c, ml_get_curline(), curwin->w_cursor.col,
+ curwin->w_cursor.lnum == Insstart.lnum ? Insstart.col : 0);
+}
+
+/*
+ * replace-stack functions
+ *
+ * When replacing characters, the replaced characters are remembered for each
+ * new character. This is used to re-insert the old text when backspacing.
+ *
+ * There is a NUL headed list of characters for each character that is
+ * currently in the file after the insertion point. When BS is used, one NUL
+ * headed list is put back for the deleted character.
+ *
+ * For a newline, there are two NUL headed lists. One contains the characters
+ * that the NL replaced. The extra one stores the characters after the cursor
+ * that were deleted (always white space).
+ *
+ * Replace_offset is normally 0, in which case replace_push will add a new
+ * character at the end of the stack. If replace_offset is not 0, that many
+ * characters will be left on the stack above the newly inserted character.
+ */
+
+static char_u *replace_stack = NULL;
+static long replace_stack_nr = 0; /* next entry in replace stack */
+static long replace_stack_len = 0; /* max. number of entries */
+
+ void
+replace_push(
+ int c) /* character that is replaced (NUL is none) */
+{
+ char_u *p;
+
+ if (replace_stack_nr < replace_offset) /* nothing to do */
+ return;
+ if (replace_stack_len <= replace_stack_nr)
+ {
+ replace_stack_len += 50;
+ p = lalloc(sizeof(char_u) * replace_stack_len, TRUE);
+ if (p == NULL) /* out of memory */
+ {
+ replace_stack_len -= 50;
+ return;
+ }
+ if (replace_stack != NULL)
+ {
+ mch_memmove(p, replace_stack,
+ (size_t)(replace_stack_nr * sizeof(char_u)));
+ vim_free(replace_stack);
+ }
+ replace_stack = p;
+ }
+ p = replace_stack + replace_stack_nr - replace_offset;
+ if (replace_offset)
+ mch_memmove(p + 1, p, (size_t)(replace_offset * sizeof(char_u)));
+ *p = c;
+ ++replace_stack_nr;
+}
+
+/*
+ * Push a character onto the replace stack. Handles a multi-byte character in
+ * reverse byte order, so that the first byte is popped off first.
+ * Return the number of bytes done (includes composing characters).
+ */
+ int
+replace_push_mb(char_u *p)
+{
+ int l = (*mb_ptr2len)(p);
+ int j;
+
+ for (j = l - 1; j >= 0; --j)
+ replace_push(p[j]);
+ return l;
+}
+
+/*
+ * Pop one item from the replace stack.
+ * return -1 if stack empty
+ * return replaced character or NUL otherwise
+ */
+ static int
+replace_pop(void)
+{
+ if (replace_stack_nr == 0)
+ return -1;
+ return (int)replace_stack[--replace_stack_nr];
+}
+
+/*
+ * Join the top two items on the replace stack. This removes to "off"'th NUL
+ * encountered.
+ */
+ static void
+replace_join(
+ int off) /* offset for which NUL to remove */
+{
+ int i;
+
+ for (i = replace_stack_nr; --i >= 0; )
+ if (replace_stack[i] == NUL && off-- <= 0)
+ {
+ --replace_stack_nr;
+ mch_memmove(replace_stack + i, replace_stack + i + 1,
+ (size_t)(replace_stack_nr - i));
+ return;
+ }
+}
+
+/*
+ * Pop bytes from the replace stack until a NUL is found, and insert them
+ * before the cursor. Can only be used in REPLACE or VREPLACE mode.
+ */
+ static void
+replace_pop_ins(void)
+{
+ int cc;
+ int oldState = State;
+
+ State = NORMAL; /* don't want REPLACE here */
+ while ((cc = replace_pop()) > 0)
+ {
+ mb_replace_pop_ins(cc);
+ dec_cursor();
+ }
+ State = oldState;
+}
+
+/*
+ * Insert bytes popped from the replace stack. "cc" is the first byte. If it
+ * indicates a multi-byte char, pop the other bytes too.
+ */
+ static void
+mb_replace_pop_ins(int cc)
+{
+ int n;
+ char_u buf[MB_MAXBYTES + 1];
+ int i;
+ int c;
+
+ if (has_mbyte && (n = MB_BYTE2LEN(cc)) > 1)
+ {
+ buf[0] = cc;
+ for (i = 1; i < n; ++i)
+ buf[i] = replace_pop();
+ ins_bytes_len(buf, n);
+ }
+ else
+ ins_char(cc);
+
+ if (enc_utf8)
+ /* Handle composing chars. */
+ for (;;)
+ {
+ c = replace_pop();
+ if (c == -1) /* stack empty */
+ break;
+ if ((n = MB_BYTE2LEN(c)) == 1)
+ {
+ /* Not a multi-byte char, put it back. */
+ replace_push(c);
+ break;
+ }
+ else
+ {
+ buf[0] = c;
+ for (i = 1; i < n; ++i)
+ buf[i] = replace_pop();
+ if (utf_iscomposing(utf_ptr2char(buf)))
+ ins_bytes_len(buf, n);
+ else
+ {
+ /* Not a composing char, put it back. */
+ for (i = n - 1; i >= 0; --i)
+ replace_push(buf[i]);
+ break;
+ }
+ }
+ }
+}
+
+/*
+ * make the replace stack empty
+ * (called when exiting replace mode)
+ */
+ static void
+replace_flush(void)
+{
+ VIM_CLEAR(replace_stack);
+ replace_stack_len = 0;
+ replace_stack_nr = 0;
+}
+
+/*
+ * Handle doing a BS for one character.
+ * cc < 0: replace stack empty, just move cursor
+ * cc == 0: character was inserted, delete it
+ * cc > 0: character was replaced, put cc (first byte of original char) back
+ * and check for more characters to be put back
+ * When "limit_col" is >= 0, don't delete before this column. Matters when
+ * using composing characters, use del_char_after_col() instead of del_char().
+ */
+ static void
+replace_do_bs(int limit_col)
+{
+ int cc;
+ int orig_len = 0;
+ int ins_len;
+ int orig_vcols = 0;
+ colnr_T start_vcol;
+ char_u *p;
+ int i;
+ int vcol;
+
+ cc = replace_pop();
+ if (cc > 0)
+ {
+#ifdef FEAT_TEXT_PROP
+ size_t len_before = 0; // init to shut up GCC
+
+ if (curbuf->b_has_textprop)
+ {
+ // Do not adjust text properties for individual delete and insert
+ // operations, do it afterwards on the resulting text.
+ len_before = STRLEN(ml_get_curline());
+ ++text_prop_frozen;
+ }
+#endif
+ if (State & VREPLACE_FLAG)
+ {
+ /* Get the number of screen cells used by the character we are
+ * going to delete. */
+ getvcol(curwin, &curwin->w_cursor, NULL, &start_vcol, NULL);
+ orig_vcols = chartabsize(ml_get_cursor(), start_vcol);
+ }
+ if (has_mbyte)
+ {
+ (void)del_char_after_col(limit_col);
+ if (State & VREPLACE_FLAG)
+ orig_len = (int)STRLEN(ml_get_cursor());
+ replace_push(cc);
+ }
+ else
+ {
+ pchar_cursor(cc);
+ if (State & VREPLACE_FLAG)
+ orig_len = (int)STRLEN(ml_get_cursor()) - 1;
+ }
+ replace_pop_ins();
+
+ if (State & VREPLACE_FLAG)
+ {
+ /* Get the number of screen cells used by the inserted characters */
+ p = ml_get_cursor();
+ ins_len = (int)STRLEN(p) - orig_len;
+ vcol = start_vcol;
+ for (i = 0; i < ins_len; ++i)
+ {
+ vcol += chartabsize(p + i, vcol);
+ i += (*mb_ptr2len)(p) - 1;
+ }
+ vcol -= start_vcol;
+
+ /* Delete spaces that were inserted after the cursor to keep the
+ * text aligned. */
+ curwin->w_cursor.col += ins_len;
+ while (vcol > orig_vcols && gchar_cursor() == ' ')
+ {
+ del_char(FALSE);
+ ++orig_vcols;
+ }
+ curwin->w_cursor.col -= ins_len;
+ }
+
+ // mark the buffer as changed and prepare for displaying
+ changed_bytes(curwin->w_cursor.lnum, curwin->w_cursor.col);
+
+#ifdef FEAT_TEXT_PROP
+ if (curbuf->b_has_textprop)
+ {
+ size_t len_now = STRLEN(ml_get_curline());
+
+ --text_prop_frozen;
+ adjust_prop_columns(curwin->w_cursor.lnum, curwin->w_cursor.col,
+ (int)(len_now - len_before));
+ }
+#endif
+ }
+ else if (cc == 0)
+ (void)del_char_after_col(limit_col);
+}
+
+#if defined(FEAT_RIGHTLEFT) || defined(PROTO)
+/*
+ * Map Hebrew keyboard when in hkmap mode.
+ */
+ int
+hkmap(int c)
+{
+ if (p_hkmapp) /* phonetic mapping, by Ilya Dogolazky */
+ {
+ enum {hALEF=0, BET, GIMEL, DALET, HEI, VAV, ZAIN, HET, TET, IUD,
+ KAFsofit, hKAF, LAMED, MEMsofit, MEM, NUNsofit, NUN, SAMEH, AIN,
+ PEIsofit, PEI, ZADIsofit, ZADI, KOF, RESH, hSHIN, TAV};
+ static char_u map[26] =
+ {(char_u)hALEF/*a*/, (char_u)BET /*b*/, (char_u)hKAF /*c*/,
+ (char_u)DALET/*d*/, (char_u)-1 /*e*/, (char_u)PEIsofit/*f*/,
+ (char_u)GIMEL/*g*/, (char_u)HEI /*h*/, (char_u)IUD /*i*/,
+ (char_u)HET /*j*/, (char_u)KOF /*k*/, (char_u)LAMED /*l*/,
+ (char_u)MEM /*m*/, (char_u)NUN /*n*/, (char_u)SAMEH /*o*/,
+ (char_u)PEI /*p*/, (char_u)-1 /*q*/, (char_u)RESH /*r*/,
+ (char_u)ZAIN /*s*/, (char_u)TAV /*t*/, (char_u)TET /*u*/,
+ (char_u)VAV /*v*/, (char_u)hSHIN/*w*/, (char_u)-1 /*x*/,
+ (char_u)AIN /*y*/, (char_u)ZADI /*z*/};
+
+ if (c == 'N' || c == 'M' || c == 'P' || c == 'C' || c == 'Z')
+ return (int)(map[CharOrd(c)] - 1 + p_aleph);
+ /* '-1'='sofit' */
+ else if (c == 'x')
+ return 'X';
+ else if (c == 'q')
+ return '\''; /* {geresh}={'} */
+ else if (c == 246)
+ return ' '; /* \"o --> ' ' for a german keyboard */
+ else if (c == 228)
+ return ' '; /* \"a --> ' ' -- / -- */
+ else if (c == 252)
+ return ' '; /* \"u --> ' ' -- / -- */
+#ifdef EBCDIC
+ else if (islower(c))
+#else
+ /* NOTE: islower() does not do the right thing for us on Linux so we
+ * do this the same was as 5.7 and previous, so it works correctly on
+ * all systems. Specifically, the e.g. Delete and Arrow keys are
+ * munged and won't work if e.g. searching for Hebrew text.
+ */
+ else if (c >= 'a' && c <= 'z')
+#endif
+ return (int)(map[CharOrdLow(c)] + p_aleph);
+ else
+ return c;
+ }
+ else
+ {
+ switch (c)
+ {
+ case '`': return ';';
+ case '/': return '.';
+ case '\'': return ',';
+ case 'q': return '/';
+ case 'w': return '\'';
+
+ /* Hebrew letters - set offset from 'a' */
+ case ',': c = '{'; break;
+ case '.': c = 'v'; break;
+ case ';': c = 't'; break;
+ default: {
+ static char str[] = "zqbcxlsjphmkwonu ydafe rig";
+
+#ifdef EBCDIC
+ /* see note about islower() above */
+ if (!islower(c))
+#else
+ if (c < 'a' || c > 'z')
+#endif
+ return c;
+ c = str[CharOrdLow(c)];
+ break;
+ }
+ }
+
+ return (int)(CharOrdLow(c) + p_aleph);
+ }
+}
+#endif
+
+ static void
+ins_reg(void)
+{
+ int need_redraw = FALSE;
+ int regname;
+ int literally = 0;
+ int vis_active = VIsual_active;
+
+ /*
+ * If we are going to wait for a character, show a '"'.
+ */
+ pc_status = PC_STATUS_UNSET;
+ if (redrawing() && !char_avail())
+ {
+ /* may need to redraw when no more chars available now */
+ ins_redraw(FALSE);
+
+ edit_putchar('"', TRUE);
+#ifdef FEAT_CMDL_INFO
+ add_to_showcmd_c(Ctrl_R);
+#endif
+ }
+
+#ifdef USE_ON_FLY_SCROLL
+ dont_scroll = TRUE; /* disallow scrolling here */
+#endif
+
+ /*
+ * Don't map the register name. This also prevents the mode message to be
+ * deleted when ESC is hit.
+ */
+ ++no_mapping;
+ regname = plain_vgetc();
+ LANGMAP_ADJUST(regname, TRUE);
+ if (regname == Ctrl_R || regname == Ctrl_O || regname == Ctrl_P)
+ {
+ /* Get a third key for literal register insertion */
+ literally = regname;
+#ifdef FEAT_CMDL_INFO
+ add_to_showcmd_c(literally);
+#endif
+ regname = plain_vgetc();
+ LANGMAP_ADJUST(regname, TRUE);
+ }
+ --no_mapping;
+
+#ifdef FEAT_EVAL
+ /* Don't call u_sync() while typing the expression or giving an error
+ * message for it. Only call it explicitly. */
+ ++no_u_sync;
+ if (regname == '=')
+ {
+ pos_T curpos = curwin->w_cursor;
+# ifdef HAVE_INPUT_METHOD
+ int im_on = im_get_status();
+# endif
+ /* Sync undo when evaluating the expression calls setline() or
+ * append(), so that it can be undone separately. */
+ u_sync_once = 2;
+
+ regname = get_expr_register();
+
+ // Cursor may be moved back a column.
+ curwin->w_cursor = curpos;
+ check_cursor();
+# ifdef HAVE_INPUT_METHOD
+ // Restore the Input Method.
+ if (im_on)
+ im_set_active(TRUE);
+# endif
+ }
+ if (regname == NUL || !valid_yank_reg(regname, FALSE))
+ {
+ vim_beep(BO_REG);
+ need_redraw = TRUE; /* remove the '"' */
+ }
+ else
+ {
+#endif
+ if (literally == Ctrl_O || literally == Ctrl_P)
+ {
+ /* Append the command to the redo buffer. */
+ AppendCharToRedobuff(Ctrl_R);
+ AppendCharToRedobuff(literally);
+ AppendCharToRedobuff(regname);
+
+ do_put(regname, BACKWARD, 1L,
+ (literally == Ctrl_P ? PUT_FIXINDENT : 0) | PUT_CURSEND);
+ }
+ else if (insert_reg(regname, literally) == FAIL)
+ {
+ vim_beep(BO_REG);
+ need_redraw = TRUE; /* remove the '"' */
+ }
+ else if (stop_insert_mode)
+ /* When the '=' register was used and a function was invoked that
+ * did ":stopinsert" then stuff_empty() returns FALSE but we won't
+ * insert anything, need to remove the '"' */
+ need_redraw = TRUE;
+
+#ifdef FEAT_EVAL
+ }
+ --no_u_sync;
+ if (u_sync_once == 1)
+ ins_need_undo = TRUE;
+ u_sync_once = 0;
+#endif
+#ifdef FEAT_CMDL_INFO
+ clear_showcmd();
+#endif
+
+ /* If the inserted register is empty, we need to remove the '"' */
+ if (need_redraw || stuff_empty())
+ edit_unputchar();
+
+ /* Disallow starting Visual mode here, would get a weird mode. */
+ if (!vis_active && VIsual_active)
+ end_visual_mode();
+}
+
+/*
+ * CTRL-G commands in Insert mode.
+ */
+ static void
+ins_ctrl_g(void)
+{
+ int c;
+
+#ifdef FEAT_INS_EXPAND
+ /* Right after CTRL-X the cursor will be after the ruler. */
+ setcursor();
+#endif
+
+ /*
+ * Don't map the second key. This also prevents the mode message to be
+ * deleted when ESC is hit.
+ */
+ ++no_mapping;
+ c = plain_vgetc();
+ --no_mapping;
+ switch (c)
+ {
+ /* CTRL-G k and CTRL-G <Up>: cursor up to Insstart.col */
+ case K_UP:
+ case Ctrl_K:
+ case 'k': ins_up(TRUE);
+ break;
+
+ /* CTRL-G j and CTRL-G <Down>: cursor down to Insstart.col */
+ case K_DOWN:
+ case Ctrl_J:
+ case 'j': ins_down(TRUE);
+ break;
+
+ /* CTRL-G u: start new undoable edit */
+ case 'u': u_sync(TRUE);
+ ins_need_undo = TRUE;
+
+ /* Need to reset Insstart, esp. because a BS that joins
+ * a line to the previous one must save for undo. */
+ update_Insstart_orig = FALSE;
+ Insstart = curwin->w_cursor;
+ break;
+
+ /* CTRL-G U: do not break undo with the next char */
+ case 'U':
+ /* Allow one left/right cursor movement with the next char,
+ * without breaking undo. */
+ dont_sync_undo = MAYBE;
+ break;
+
+ /* Unknown CTRL-G command, reserved for future expansion. */
+ default: vim_beep(BO_CTRLG);
+ }
+}
+
+/*
+ * CTRL-^ in Insert mode.
+ */
+ static void
+ins_ctrl_hat(void)
+{
+ if (map_to_exists_mode((char_u *)"", LANGMAP, FALSE))
+ {
+ /* ":lmap" mappings exists, Toggle use of ":lmap" mappings. */
+ if (State & LANGMAP)
+ {
+ curbuf->b_p_iminsert = B_IMODE_NONE;
+ State &= ~LANGMAP;
+ }
+ else
+ {
+ curbuf->b_p_iminsert = B_IMODE_LMAP;
+ State |= LANGMAP;
+#ifdef HAVE_INPUT_METHOD
+ im_set_active(FALSE);
+#endif
+ }
+ }
+#ifdef HAVE_INPUT_METHOD
+ else
+ {
+ /* There are no ":lmap" mappings, toggle IM */
+ if (im_get_status())
+ {
+ curbuf->b_p_iminsert = B_IMODE_NONE;
+ im_set_active(FALSE);
+ }
+ else
+ {
+ curbuf->b_p_iminsert = B_IMODE_IM;
+ State &= ~LANGMAP;
+ im_set_active(TRUE);
+ }
+ }
+#endif
+ set_iminsert_global();
+ showmode();
+#ifdef FEAT_GUI
+ /* may show different cursor shape or color */
+ if (gui.in_use)
+ gui_update_cursor(TRUE, FALSE);
+#endif
+#if defined(FEAT_KEYMAP)
+ /* Show/unshow value of 'keymap' in status lines. */
+ status_redraw_curbuf();
+#endif
+}
+
+/*
+ * Handle ESC in insert mode.
+ * Returns TRUE when leaving insert mode, FALSE when going to repeat the
+ * insert.
+ */
+ static int
+ins_esc(
+ long *count,
+ int cmdchar,
+ int nomove) /* don't move cursor */
+{
+ int temp;
+ static int disabled_redraw = FALSE;
+
+#ifdef FEAT_SPELL
+ check_spell_redraw();
+#endif
+#if defined(FEAT_HANGULIN)
+# if defined(ESC_CHG_TO_ENG_MODE)
+ hangul_input_state_set(0);
+# endif
+ if (composing_hangul)
+ {
+ push_raw_key(composing_hangul_buffer, 2);
+ composing_hangul = 0;
+ }
+#endif
+
+ temp = curwin->w_cursor.col;
+ if (disabled_redraw)
+ {
+ --RedrawingDisabled;
+ disabled_redraw = FALSE;
+ }
+ if (!arrow_used)
+ {
+ /*
+ * Don't append the ESC for "r<CR>" and "grx".
+ * When 'insertmode' is set only CTRL-L stops Insert mode. Needed for
+ * when "count" is non-zero.
+ */
+ if (cmdchar != 'r' && cmdchar != 'v')
+ AppendToRedobuff(p_im ? (char_u *)"\014" : ESC_STR);
+
+ /*
+ * Repeating insert may take a long time. Check for
+ * interrupt now and then.
+ */
+ if (*count > 0)
+ {
+ line_breakcheck();
+ if (got_int)
+ *count = 0;
+ }
+
+ if (--*count > 0) /* repeat what was typed */
+ {
+ /* Vi repeats the insert without replacing characters. */
+ if (vim_strchr(p_cpo, CPO_REPLCNT) != NULL)
+ State &= ~REPLACE_FLAG;
+
+ (void)start_redo_ins();
+ if (cmdchar == 'r' || cmdchar == 'v')
+ stuffRedoReadbuff(ESC_STR); /* no ESC in redo buffer */
+ ++RedrawingDisabled;
+ disabled_redraw = TRUE;
+ return FALSE; /* repeat the insert */
+ }
+ stop_insert(&curwin->w_cursor, TRUE, nomove);
+ undisplay_dollar();
+ }
+
+ /* When an autoindent was removed, curswant stays after the
+ * indent */
+ if (restart_edit == NUL && (colnr_T)temp == curwin->w_cursor.col)
+ curwin->w_set_curswant = TRUE;
+
+ /* Remember the last Insert position in the '^ mark. */
+ if (!cmdmod.keepjumps)
+ curbuf->b_last_insert = curwin->w_cursor;
+
+ /*
+ * The cursor should end up on the last inserted character.
+ * Don't do it for CTRL-O, unless past the end of the line.
+ */
+ if (!nomove
+ && (curwin->w_cursor.col != 0
+ || curwin->w_cursor.coladd > 0)
+ && (restart_edit == NUL
+ || (gchar_cursor() == NUL && !VIsual_active))
+#ifdef FEAT_RIGHTLEFT
+ && !revins_on
+#endif
+ )
+ {
+ if (curwin->w_cursor.coladd > 0 || ve_flags == VE_ALL)
+ {
+ oneleft();
+ if (restart_edit != NUL)
+ ++curwin->w_cursor.coladd;
+ }
+ else
+ {
+ --curwin->w_cursor.col;
+ /* Correct cursor for multi-byte character. */
+ if (has_mbyte)
+ mb_adjust_cursor();
+ }
+ }
+
+#ifdef HAVE_INPUT_METHOD
+ /* Disable IM to allow typing English directly for Normal mode commands.
+ * When ":lmap" is enabled don't change 'iminsert' (IM can be enabled as
+ * well). */
+ if (!(State & LANGMAP))
+ im_save_status(&curbuf->b_p_iminsert);
+ im_set_active(FALSE);
+#endif
+
+ State = NORMAL;
+ /* need to position cursor again (e.g. when on a TAB ) */
+ changed_cline_bef_curs();
+
+#ifdef FEAT_MOUSE
+ setmouse();
+#endif
+#ifdef CURSOR_SHAPE
+ ui_cursor_shape(); /* may show different cursor shape */
+#endif
+ if (!p_ek)
+ /* Re-enable bracketed paste mode. */
+ out_str(T_BE);
+
+ /*
+ * When recording or for CTRL-O, need to display the new mode.
+ * Otherwise remove the mode message.
+ */
+ if (reg_recording != 0 || restart_edit != NUL)
+ showmode();
+ else if (p_smd && !skip_showmode())
+ msg("");
+
+ return TRUE; /* exit Insert mode */
+}
+
+#ifdef FEAT_RIGHTLEFT
+/*
+ * Toggle language: hkmap and revins_on.
+ * Move to end of reverse inserted text.
+ */
+ static void
+ins_ctrl_(void)
+{
+ if (revins_on && revins_chars && revins_scol >= 0)
+ {
+ while (gchar_cursor() != NUL && revins_chars--)
+ ++curwin->w_cursor.col;
+ }
+ p_ri = !p_ri;
+ revins_on = (State == INSERT && p_ri);
+ if (revins_on)
+ {
+ revins_scol = curwin->w_cursor.col;
+ revins_legal++;
+ revins_chars = 0;
+ undisplay_dollar();
+ }
+ else
+ revins_scol = -1;
+#ifdef FEAT_FKMAP
+ if (p_altkeymap)
+ {
+ /*
+ * to be consistent also for redo command, using '.'
+ * set arrow_used to true and stop it - causing to redo
+ * characters entered in one mode (normal/reverse insert).
+ */
+ arrow_used = TRUE;
+ (void)stop_arrow();
+ p_fkmap = curwin->w_p_rl ^ p_ri;
+ if (p_fkmap && p_ri)
+ State = INSERT;
+ }
+ else
+#endif
+ p_hkmap = curwin->w_p_rl ^ p_ri; /* be consistent! */
+ showmode();
+}
+#endif
+
+/*
+ * If 'keymodel' contains "startsel", may start selection.
+ * Returns TRUE when a CTRL-O and other keys stuffed.
+ */
+ static int
+ins_start_select(int c)
+{
+ if (km_startsel)
+ switch (c)
+ {
+ case K_KHOME:
+ case K_KEND:
+ case K_PAGEUP:
+ case K_KPAGEUP:
+ case K_PAGEDOWN:
+ case K_KPAGEDOWN:
+# ifdef MACOS_X
+ case K_LEFT:
+ case K_RIGHT:
+ case K_UP:
+ case K_DOWN:
+ case K_END:
+ case K_HOME:
+# endif
+ if (!(mod_mask & MOD_MASK_SHIFT))
+ break;
+ /* FALLTHROUGH */
+ case K_S_LEFT:
+ case K_S_RIGHT:
+ case K_S_UP:
+ case K_S_DOWN:
+ case K_S_END:
+ case K_S_HOME:
+ /* Start selection right away, the cursor can move with
+ * CTRL-O when beyond the end of the line. */
+ start_selection();
+
+ /* Execute the key in (insert) Select mode. */
+ stuffcharReadbuff(Ctrl_O);
+ if (mod_mask)
+ {
+ char_u buf[4];
+
+ buf[0] = K_SPECIAL;
+ buf[1] = KS_MODIFIER;
+ buf[2] = mod_mask;
+ buf[3] = NUL;
+ stuffReadbuff(buf);
+ }
+ stuffcharReadbuff(c);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * <Insert> key in Insert mode: toggle insert/replace mode.
+ */
+ static void
+ins_insert(int replaceState)
+{
+#ifdef FEAT_FKMAP
+ if (p_fkmap && p_ri)
+ {
+ beep_flush();
+ emsg(farsi_text_3); /* encoded in Farsi */
+ return;
+ }
+#endif
+
+# ifdef FEAT_EVAL
+ set_vim_var_string(VV_INSERTMODE,
+ (char_u *)((State & REPLACE_FLAG) ? "i"
+ : replaceState == VREPLACE ? "v"
+ : "r"), 1);
+# endif
+ ins_apply_autocmds(EVENT_INSERTCHANGE);
+ if (State & REPLACE_FLAG)
+ State = INSERT | (State & LANGMAP);
+ else
+ State = replaceState | (State & LANGMAP);
+ AppendCharToRedobuff(K_INS);
+ showmode();
+#ifdef CURSOR_SHAPE
+ ui_cursor_shape(); /* may show different cursor shape */
+#endif
+}
+
+/*
+ * Pressed CTRL-O in Insert mode.
+ */
+ static void
+ins_ctrl_o(void)
+{
+ if (State & VREPLACE_FLAG)
+ restart_edit = 'V';
+ else
+ if (State & REPLACE_FLAG)
+ restart_edit = 'R';
+ else
+ restart_edit = 'I';
+ if (virtual_active())
+ ins_at_eol = FALSE; /* cursor always keeps its column */
+ else
+ ins_at_eol = (gchar_cursor() == NUL);
+}
+
+/*
+ * If the cursor is on an indent, ^T/^D insert/delete one
+ * shiftwidth. Otherwise ^T/^D behave like a "<<" or ">>".
+ * Always round the indent to 'shiftwidth', this is compatible
+ * with vi. But vi only supports ^T and ^D after an
+ * autoindent, we support it everywhere.
+ */
+ static void
+ins_shift(int c, int lastc)
+{
+ if (stop_arrow() == FAIL)
+ return;
+ AppendCharToRedobuff(c);
+
+ /*
+ * 0^D and ^^D: remove all indent.
+ */
+ if (c == Ctrl_D && (lastc == '0' || lastc == '^')
+ && curwin->w_cursor.col > 0)
+ {
+ --curwin->w_cursor.col;
+ (void)del_char(FALSE); /* delete the '^' or '0' */
+ /* In Replace mode, restore the characters that '^' or '0' replaced. */
+ if (State & REPLACE_FLAG)
+ replace_pop_ins();
+ if (lastc == '^')
+ old_indent = get_indent(); /* remember curr. indent */
+ change_indent(INDENT_SET, 0, TRUE, 0, TRUE);
+ }
+ else
+ change_indent(c == Ctrl_D ? INDENT_DEC : INDENT_INC, 0, TRUE, 0, TRUE);
+
+ if (did_ai && *skipwhite(ml_get_curline()) != NUL)
+ did_ai = FALSE;
+#ifdef FEAT_SMARTINDENT
+ did_si = FALSE;
+ can_si = FALSE;
+ can_si_back = FALSE;
+#endif
+#ifdef FEAT_CINDENT
+ can_cindent = FALSE; /* no cindenting after ^D or ^T */
+#endif
+}
+
+ static void
+ins_del(void)
+{
+ int temp;
+
+ if (stop_arrow() == FAIL)
+ return;
+ if (gchar_cursor() == NUL) /* delete newline */
+ {
+ temp = curwin->w_cursor.col;
+ if (!can_bs(BS_EOL) /* only if "eol" included */
+ || do_join(2, FALSE, TRUE, FALSE, FALSE) == FAIL)
+ vim_beep(BO_BS);
+ else
+ {
+ curwin->w_cursor.col = temp;
+ /* Adjust orig_line_count in case more lines have been deleted than
+ * have been added. That makes sure, that open_line() later
+ * can access all buffer lines correctly */
+ if (State & VREPLACE_FLAG &&
+ orig_line_count > curbuf->b_ml.ml_line_count)
+ orig_line_count = curbuf->b_ml.ml_line_count;
+ }
+ }
+ else if (del_char(FALSE) == FAIL) /* delete char under cursor */
+ vim_beep(BO_BS);
+ did_ai = FALSE;
+#ifdef FEAT_SMARTINDENT
+ did_si = FALSE;
+ can_si = FALSE;
+ can_si_back = FALSE;
+#endif
+ AppendCharToRedobuff(K_DEL);
+}
+
+/*
+ * Delete one character for ins_bs().
+ */
+ static void
+ins_bs_one(colnr_T *vcolp)
+{
+ dec_cursor();
+ getvcol(curwin, &curwin->w_cursor, vcolp, NULL, NULL);
+ if (State & REPLACE_FLAG)
+ {
+ /* Don't delete characters before the insert point when in
+ * Replace mode */
+ if (curwin->w_cursor.lnum != Insstart.lnum
+ || curwin->w_cursor.col >= Insstart.col)
+ replace_do_bs(-1);
+ }
+ else
+ (void)del_char(FALSE);
+}
+
+/*
+ * Handle Backspace, delete-word and delete-line in Insert mode.
+ * Return TRUE when backspace was actually used.
+ */
+ static int
+ins_bs(
+ int c,
+ int mode,
+ int *inserted_space_p)
+{
+ linenr_T lnum;
+ int cc;
+ int temp = 0; /* init for GCC */
+ colnr_T save_col;
+ colnr_T mincol;
+ int did_backspace = FALSE;
+ int in_indent;
+ int oldState;
+ int cpc[MAX_MCO]; /* composing characters */
+
+ /*
+ * can't delete anything in an empty file
+ * can't backup past first character in buffer
+ * can't backup past starting point unless 'backspace' > 1
+ * can backup to a previous line if 'backspace' == 0
+ */
+ if ( BUFEMPTY()
+ || (
+#ifdef FEAT_RIGHTLEFT
+ !revins_on &&
+#endif
+ ((curwin->w_cursor.lnum == 1 && curwin->w_cursor.col == 0)
+ || (!can_bs(BS_START)
+ && (arrow_used
+ || (curwin->w_cursor.lnum == Insstart_orig.lnum
+ && curwin->w_cursor.col <= Insstart_orig.col)))
+ || (!can_bs(BS_INDENT) && !arrow_used && ai_col > 0
+ && curwin->w_cursor.col <= ai_col)
+ || (!can_bs(BS_EOL) && curwin->w_cursor.col == 0))))
+ {
+ vim_beep(BO_BS);
+ return FALSE;
+ }
+
+ if (stop_arrow() == FAIL)
+ return FALSE;
+ in_indent = inindent(0);
+#ifdef FEAT_CINDENT
+ if (in_indent)
+ can_cindent = FALSE;
+#endif
+#ifdef FEAT_COMMENTS
+ end_comment_pending = NUL; /* After BS, don't auto-end comment */
+#endif
+#ifdef FEAT_RIGHTLEFT
+ if (revins_on) /* put cursor after last inserted char */
+ inc_cursor();
+#endif
+
+ /* Virtualedit:
+ * BACKSPACE_CHAR eats a virtual space
+ * BACKSPACE_WORD eats all coladd
+ * BACKSPACE_LINE eats all coladd and keeps going
+ */
+ if (curwin->w_cursor.coladd > 0)
+ {
+ if (mode == BACKSPACE_CHAR)
+ {
+ --curwin->w_cursor.coladd;
+ return TRUE;
+ }
+ if (mode == BACKSPACE_WORD)
+ {
+ curwin->w_cursor.coladd = 0;
+ return TRUE;
+ }
+ curwin->w_cursor.coladd = 0;
+ }
+
+ /*
+ * Delete newline!
+ */
+ if (curwin->w_cursor.col == 0)
+ {
+ lnum = Insstart.lnum;
+ if (curwin->w_cursor.lnum == lnum
+#ifdef FEAT_RIGHTLEFT
+ || revins_on
+#endif
+ )
+ {
+ if (u_save((linenr_T)(curwin->w_cursor.lnum - 2),
+ (linenr_T)(curwin->w_cursor.lnum + 1)) == FAIL)
+ return FALSE;
+ --Insstart.lnum;
+ Insstart.col = (colnr_T)STRLEN(ml_get(Insstart.lnum));
+ }
+ /*
+ * In replace mode:
+ * cc < 0: NL was inserted, delete it
+ * cc >= 0: NL was replaced, put original characters back
+ */
+ cc = -1;
+ if (State & REPLACE_FLAG)
+ cc = replace_pop(); /* returns -1 if NL was inserted */
+ /*
+ * In replace mode, in the line we started replacing, we only move the
+ * cursor.
+ */
+ if ((State & REPLACE_FLAG) && curwin->w_cursor.lnum <= lnum)
+ {
+ dec_cursor();
+ }
+ else
+ {
+ if (!(State & VREPLACE_FLAG)
+ || curwin->w_cursor.lnum > orig_line_count)
+ {
+ temp = gchar_cursor(); /* remember current char */
+ --curwin->w_cursor.lnum;
+
+ /* When "aw" is in 'formatoptions' we must delete the space at
+ * the end of the line, otherwise the line will be broken
+ * again when auto-formatting. */
+ if (has_format_option(FO_AUTO)
+ && has_format_option(FO_WHITE_PAR))
+ {
+ char_u *ptr = ml_get_buf(curbuf, curwin->w_cursor.lnum,
+ TRUE);
+ int len;
+
+ len = (int)STRLEN(ptr);
+ if (len > 0 && ptr[len - 1] == ' ')
+ ptr[len - 1] = NUL;
+ }
+
+ (void)do_join(2, FALSE, FALSE, FALSE, FALSE);
+ if (temp == NUL && gchar_cursor() != NUL)
+ inc_cursor();
+ }
+ else
+ dec_cursor();
+
+ /*
+ * In REPLACE mode we have to put back the text that was replaced
+ * by the NL. On the replace stack is first a NUL-terminated
+ * sequence of characters that were deleted and then the
+ * characters that NL replaced.
+ */
+ if (State & REPLACE_FLAG)
+ {
+ /*
+ * Do the next ins_char() in NORMAL state, to
+ * prevent ins_char() from replacing characters and
+ * avoiding showmatch().
+ */
+ oldState = State;
+ State = NORMAL;
+ /*
+ * restore characters (blanks) deleted after cursor
+ */
+ while (cc > 0)
+ {
+ save_col = curwin->w_cursor.col;
+ mb_replace_pop_ins(cc);
+ curwin->w_cursor.col = save_col;
+ cc = replace_pop();
+ }
+ /* restore the characters that NL replaced */
+ replace_pop_ins();
+ State = oldState;
+ }
+ }
+ did_ai = FALSE;
+ }
+ else
+ {
+ /*
+ * Delete character(s) before the cursor.
+ */
+#ifdef FEAT_RIGHTLEFT
+ if (revins_on) /* put cursor on last inserted char */
+ dec_cursor();
+#endif
+ mincol = 0;
+ /* keep indent */
+ if (mode == BACKSPACE_LINE
+ && (curbuf->b_p_ai
+#ifdef FEAT_CINDENT
+ || cindent_on()
+#endif
+ )
+#ifdef FEAT_RIGHTLEFT
+ && !revins_on
+#endif
+ )
+ {
+ save_col = curwin->w_cursor.col;
+ beginline(BL_WHITE);
+ if (curwin->w_cursor.col < save_col)
+ mincol = curwin->w_cursor.col;
+ curwin->w_cursor.col = save_col;
+ }
+
+ /*
+ * Handle deleting one 'shiftwidth' or 'softtabstop'.
+ */
+ if ( mode == BACKSPACE_CHAR
+ && ((p_sta && in_indent)
+ || ((get_sts_value() != 0
+#ifdef FEAT_VARTABS
+ || tabstop_count(curbuf->b_p_vsts_array)
+#endif
+ )
+ && curwin->w_cursor.col > 0
+ && (*(ml_get_cursor() - 1) == TAB
+ || (*(ml_get_cursor() - 1) == ' '
+ && (!*inserted_space_p
+ || arrow_used))))))
+ {
+ int ts;
+ colnr_T vcol;
+ colnr_T want_vcol;
+ colnr_T start_vcol;
+
+ *inserted_space_p = FALSE;
+ /* Compute the virtual column where we want to be. Since
+ * 'showbreak' may get in the way, need to get the last column of
+ * the previous character. */
+ getvcol(curwin, &curwin->w_cursor, &vcol, NULL, NULL);
+ start_vcol = vcol;
+ dec_cursor();
+ getvcol(curwin, &curwin->w_cursor, NULL, NULL, &want_vcol);
+ inc_cursor();
+#ifdef FEAT_VARTABS
+ if (p_sta && in_indent)
+ {
+ ts = (int)get_sw_value(curbuf);
+ want_vcol = (want_vcol / ts) * ts;
+ }
+ else
+ want_vcol = tabstop_start(want_vcol, get_sts_value(),
+ curbuf->b_p_vsts_array);
+#else
+ if (p_sta && in_indent)
+ ts = (int)get_sw_value(curbuf);
+ else
+ ts = (int)get_sts_value();
+ want_vcol = (want_vcol / ts) * ts;
+#endif
+
+ /* delete characters until we are at or before want_vcol */
+ while (vcol > want_vcol
+ && (cc = *(ml_get_cursor() - 1), VIM_ISWHITE(cc)))
+ ins_bs_one(&vcol);
+
+ /* insert extra spaces until we are at want_vcol */
+ while (vcol < want_vcol)
+ {
+ /* Remember the first char we inserted */
+ if (curwin->w_cursor.lnum == Insstart_orig.lnum
+ && curwin->w_cursor.col < Insstart_orig.col)
+ Insstart_orig.col = curwin->w_cursor.col;
+
+ if (State & VREPLACE_FLAG)
+ ins_char(' ');
+ else
+ {
+ ins_str((char_u *)" ");
+ if ((State & REPLACE_FLAG))
+ replace_push(NUL);
+ }
+ getvcol(curwin, &curwin->w_cursor, &vcol, NULL, NULL);
+ }
+
+ /* If we are now back where we started delete one character. Can
+ * happen when using 'sts' and 'linebreak'. */
+ if (vcol >= start_vcol)
+ ins_bs_one(&vcol);
+ }
+
+ /*
+ * Delete upto starting point, start of line or previous word.
+ */
+ else
+ {
+ int cclass = 0, prev_cclass = 0;
+
+ if (has_mbyte)
+ cclass = mb_get_class(ml_get_cursor());
+ do
+ {
+#ifdef FEAT_RIGHTLEFT
+ if (!revins_on) /* put cursor on char to be deleted */
+#endif
+ dec_cursor();
+
+ cc = gchar_cursor();
+ /* look multi-byte character class */
+ if (has_mbyte)
+ {
+ prev_cclass = cclass;
+ cclass = mb_get_class(ml_get_cursor());
+ }
+
+ /* start of word? */
+ if (mode == BACKSPACE_WORD && !vim_isspace(cc))
+ {
+ mode = BACKSPACE_WORD_NOT_SPACE;
+ temp = vim_iswordc(cc);
+ }
+ /* end of word? */
+ else if (mode == BACKSPACE_WORD_NOT_SPACE
+ && ((vim_isspace(cc) || vim_iswordc(cc) != temp)
+ || prev_cclass != cclass))
+ {
+#ifdef FEAT_RIGHTLEFT
+ if (!revins_on)
+#endif
+ inc_cursor();
+#ifdef FEAT_RIGHTLEFT
+ else if (State & REPLACE_FLAG)
+ dec_cursor();
+#endif
+ break;
+ }
+ if (State & REPLACE_FLAG)
+ replace_do_bs(-1);
+ else
+ {
+ if (enc_utf8 && p_deco)
+ (void)utfc_ptr2char(ml_get_cursor(), cpc);
+ (void)del_char(FALSE);
+ /*
+ * If there are combining characters and 'delcombine' is set
+ * move the cursor back. Don't back up before the base
+ * character.
+ */
+ if (enc_utf8 && p_deco && cpc[0] != NUL)
+ inc_cursor();
+#ifdef FEAT_RIGHTLEFT
+ if (revins_chars)
+ {
+ revins_chars--;
+ revins_legal++;
+ }
+ if (revins_on && gchar_cursor() == NUL)
+ break;
+#endif
+ }
+ /* Just a single backspace?: */
+ if (mode == BACKSPACE_CHAR)
+ break;
+ } while (
+#ifdef FEAT_RIGHTLEFT
+ revins_on ||
+#endif
+ (curwin->w_cursor.col > mincol
+ && (curwin->w_cursor.lnum != Insstart_orig.lnum
+ || curwin->w_cursor.col != Insstart_orig.col)));
+ }
+ did_backspace = TRUE;
+ }
+#ifdef FEAT_SMARTINDENT
+ did_si = FALSE;
+ can_si = FALSE;
+ can_si_back = FALSE;
+#endif
+ if (curwin->w_cursor.col <= 1)
+ did_ai = FALSE;
+ /*
+ * It's a little strange to put backspaces into the redo
+ * buffer, but it makes auto-indent a lot easier to deal
+ * with.
+ */
+ AppendCharToRedobuff(c);
+
+ /* If deleted before the insertion point, adjust it */
+ if (curwin->w_cursor.lnum == Insstart_orig.lnum
+ && curwin->w_cursor.col < Insstart_orig.col)
+ Insstart_orig.col = curwin->w_cursor.col;
+
+ /* vi behaviour: the cursor moves backward but the character that
+ * was there remains visible
+ * Vim behaviour: the cursor moves backward and the character that
+ * was there is erased from the screen.
+ * We can emulate the vi behaviour by pretending there is a dollar
+ * displayed even when there isn't.
+ * --pkv Sun Jan 19 01:56:40 EST 2003 */
+ if (vim_strchr(p_cpo, CPO_BACKSPACE) != NULL && dollar_vcol == -1)
+ dollar_vcol = curwin->w_virtcol;
+
+#ifdef FEAT_FOLDING
+ /* When deleting a char the cursor line must never be in a closed fold.
+ * E.g., when 'foldmethod' is indent and deleting the first non-white
+ * char before a Tab. */
+ if (did_backspace)
+ foldOpenCursor();
+#endif
+
+ return did_backspace;
+}
+
+#ifdef FEAT_MOUSE
+ static void
+ins_mouse(int c)
+{
+ pos_T tpos;
+ win_T *old_curwin = curwin;
+
+# ifdef FEAT_GUI
+ /* When GUI is active, also move/paste when 'mouse' is empty */
+ if (!gui.in_use)
+# endif
+ if (!mouse_has(MOUSE_INSERT))
+ return;
+
+ undisplay_dollar();
+ tpos = curwin->w_cursor;
+ if (do_mouse(NULL, c, BACKWARD, 1L, 0))
+ {
+ win_T *new_curwin = curwin;
+
+ if (curwin != old_curwin && win_valid(old_curwin))
+ {
+ /* Mouse took us to another window. We need to go back to the
+ * previous one to stop insert there properly. */
+ curwin = old_curwin;
+ curbuf = curwin->w_buffer;
+#ifdef FEAT_JOB_CHANNEL
+ if (bt_prompt(curbuf))
+ // Restart Insert mode when re-entering the prompt buffer.
+ curbuf->b_prompt_insert = 'A';
+#endif
+ }
+ start_arrow(curwin == old_curwin ? &tpos : NULL);
+ if (curwin != new_curwin && win_valid(new_curwin))
+ {
+ curwin = new_curwin;
+ curbuf = curwin->w_buffer;
+ }
+# ifdef FEAT_CINDENT
+ can_cindent = TRUE;
+# endif
+ }
+
+ /* redraw status lines (in case another window became active) */
+ redraw_statuslines();
+}
+
+ static void
+ins_mousescroll(int dir)
+{
+ pos_T tpos;
+ win_T *old_curwin = curwin, *wp;
+# ifdef FEAT_INS_EXPAND
+ int did_scroll = FALSE;
+# endif
+
+ tpos = curwin->w_cursor;
+
+ if (mouse_row >= 0 && mouse_col >= 0)
+ {
+ int row, col;
+
+ row = mouse_row;
+ col = mouse_col;
+
+ /* find the window at the pointer coordinates */
+ wp = mouse_find_win(&row, &col);
+ if (wp == NULL)
+ return;
+ curwin = wp;
+ curbuf = curwin->w_buffer;
+ }
+ if (curwin == old_curwin)
+ undisplay_dollar();
+
+# ifdef FEAT_INS_EXPAND
+ /* Don't scroll the window in which completion is being done. */
+ if (!pum_visible() || curwin != old_curwin)
+# endif
+ {
+ if (dir == MSCR_DOWN || dir == MSCR_UP)
+ {
+ if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL))
+ scroll_redraw(dir,
+ (long)(curwin->w_botline - curwin->w_topline));
+ else
+ scroll_redraw(dir, 3L);
+ }
+#ifdef FEAT_GUI
+ else
+ {
+ int val, step = 6;
+
+ if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL))
+ step = curwin->w_width;
+ val = curwin->w_leftcol + (dir == MSCR_RIGHT ? -step : step);
+ if (val < 0)
+ val = 0;
+ gui_do_horiz_scroll(val, TRUE);
+ }
+#endif
+# ifdef FEAT_INS_EXPAND
+ did_scroll = TRUE;
+# endif
+ }
+
+ curwin->w_redr_status = TRUE;
+
+ curwin = old_curwin;
+ curbuf = curwin->w_buffer;
+
+# ifdef FEAT_INS_EXPAND
+ /* The popup menu may overlay the window, need to redraw it.
+ * TODO: Would be more efficient to only redraw the windows that are
+ * overlapped by the popup menu. */
+ if (pum_visible() && did_scroll)
+ {
+ redraw_all_later(NOT_VALID);
+ ins_compl_show_pum();
+ }
+# endif
+
+ if (!EQUAL_POS(curwin->w_cursor, tpos))
+ {
+ start_arrow(&tpos);
+# ifdef FEAT_CINDENT
+ can_cindent = TRUE;
+# endif
+ }
+}
+#endif
+
+/*
+ * Handle receiving P_PS: start paste mode. Inserts the following text up to
+ * P_PE literally.
+ * When "drop" is TRUE then consume the text and drop it.
+ */
+ int
+bracketed_paste(paste_mode_T mode, int drop, garray_T *gap)
+{
+ int c;
+ char_u buf[NUMBUFLEN + MB_MAXBYTES];
+ int idx = 0;
+ char_u *end = find_termcode((char_u *)"PE");
+ int ret_char = -1;
+ int save_allow_keys = allow_keys;
+ int save_paste = p_paste;
+
+ /* If the end code is too long we can't detect it, read everything. */
+ if (STRLEN(end) >= NUMBUFLEN)
+ end = NULL;
+ ++no_mapping;
+ allow_keys = 0;
+ if (!p_paste)
+ // Also have the side effects of setting 'paste' to make it work much
+ // faster.
+ set_option_value((char_u *)"paste", TRUE, NULL, 0);
+
+ for (;;)
+ {
+ // When the end is not defined read everything there is.
+ if (end == NULL && vpeekc() == NUL)
+ break;
+ do
+ {
+ c = vgetc();
+ } while (c == K_IGNORE || c == K_VER_SCROLLBAR || c == K_HOR_SCROLLBAR);
+ if (c == NUL || got_int)
+ // When CTRL-C was encountered the typeahead will be flushed and we
+ // won't get the end sequence.
+ break;
+
+ if (has_mbyte)
+ idx += (*mb_char2bytes)(c, buf + idx);
+ else
+ buf[idx++] = c;
+ buf[idx] = NUL;
+ if (end != NULL && STRNCMP(buf, end, idx) == 0)
+ {
+ if (end[idx] == NUL)
+ break; /* Found the end of paste code. */
+ continue;
+ }
+ if (!drop)
+ {
+ switch (mode)
+ {
+ case PASTE_CMDLINE:
+ put_on_cmdline(buf, idx, TRUE);
+ break;
+
+ case PASTE_EX:
+ if (gap != NULL && ga_grow(gap, idx) == OK)
+ {
+ mch_memmove((char *)gap->ga_data + gap->ga_len,
+ buf, (size_t)idx);
+ gap->ga_len += idx;
+ }
+ break;
+
+ case PASTE_INSERT:
+ if (stop_arrow() == OK)
+ {
+ c = buf[0];
+ if (idx == 1 && (c == CAR || c == K_KENTER || c == NL))
+ ins_eol(c);
+ else
+ {
+ ins_char_bytes(buf, idx);
+ AppendToRedobuffLit(buf, idx);
+ }
+ }
+ break;
+
+ case PASTE_ONE_CHAR:
+ if (ret_char == -1)
+ {
+ if (has_mbyte)
+ ret_char = (*mb_ptr2char)(buf);
+ else
+ ret_char = buf[0];
+ }
+ break;
+ }
+ }
+ idx = 0;
+ }
+
+ --no_mapping;
+ allow_keys = save_allow_keys;
+ if (!save_paste)
+ set_option_value((char_u *)"paste", FALSE, NULL, 0);
+
+ return ret_char;
+}
+
+#if defined(FEAT_GUI_TABLINE) || defined(PROTO)
+ static void
+ins_tabline(int c)
+{
+ /* We will be leaving the current window, unless closing another tab. */
+ if (c != K_TABMENU || current_tabmenu != TABLINE_MENU_CLOSE
+ || (current_tab != 0 && current_tab != tabpage_index(curtab)))
+ {
+ undisplay_dollar();
+ start_arrow(&curwin->w_cursor);
+# ifdef FEAT_CINDENT
+ can_cindent = TRUE;
+# endif
+ }
+
+ if (c == K_TABLINE)
+ goto_tabpage(current_tab);
+ else
+ {
+ handle_tabmenu();
+ redraw_statuslines(); /* will redraw the tabline when needed */
+ }
+}
+#endif
+
+#if defined(FEAT_GUI) || defined(PROTO)
+ void
+ins_scroll(void)
+{
+ pos_T tpos;
+
+ undisplay_dollar();
+ tpos = curwin->w_cursor;
+ if (gui_do_scroll())
+ {
+ start_arrow(&tpos);
+# ifdef FEAT_CINDENT
+ can_cindent = TRUE;
+# endif
+ }
+}
+
+ void
+ins_horscroll(void)
+{
+ pos_T tpos;
+
+ undisplay_dollar();
+ tpos = curwin->w_cursor;
+ if (gui_do_horiz_scroll(scrollbar_value, FALSE))
+ {
+ start_arrow(&tpos);
+# ifdef FEAT_CINDENT
+ can_cindent = TRUE;
+# endif
+ }
+}
+#endif
+
+ static void
+ins_left(
+ int end_change) /* end undoable change */
+{
+ pos_T tpos;
+
+#ifdef FEAT_FOLDING
+ if ((fdo_flags & FDO_HOR) && KeyTyped)
+ foldOpenCursor();
+#endif
+ undisplay_dollar();
+ tpos = curwin->w_cursor;
+ if (oneleft() == OK)
+ {
+#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
+ /* Only call start_arrow() when not busy with preediting, it will
+ * break undo. K_LEFT is inserted in im_correct_cursor(). */
+ if (p_imst == IM_OVER_THE_SPOT || !im_is_preediting())
+#endif
+ {
+ start_arrow_with_change(&tpos, end_change);
+ if (!end_change)
+ AppendCharToRedobuff(K_LEFT);
+ }
+#ifdef FEAT_RIGHTLEFT
+ /* If exit reversed string, position is fixed */
+ if (revins_scol != -1 && (int)curwin->w_cursor.col >= revins_scol)
+ revins_legal++;
+ revins_chars++;
+#endif
+ }
+
+ /*
+ * if 'whichwrap' set for cursor in insert mode may go to
+ * previous line
+ */
+ else if (vim_strchr(p_ww, '[') != NULL && curwin->w_cursor.lnum > 1)
+ {
+ /* always break undo when moving upwards/downwards, else undo may break */
+ start_arrow(&tpos);
+ --(curwin->w_cursor.lnum);
+ coladvance((colnr_T)MAXCOL);
+ curwin->w_set_curswant = TRUE; /* so we stay at the end */
+ }
+ else
+ vim_beep(BO_CRSR);
+ dont_sync_undo = FALSE;
+}
+
+ static void
+ins_home(int c)
+{
+ pos_T tpos;
+
+#ifdef FEAT_FOLDING
+ if ((fdo_flags & FDO_HOR) && KeyTyped)
+ foldOpenCursor();
+#endif
+ undisplay_dollar();
+ tpos = curwin->w_cursor;
+ if (c == K_C_HOME)
+ curwin->w_cursor.lnum = 1;
+ curwin->w_cursor.col = 0;
+ curwin->w_cursor.coladd = 0;
+ curwin->w_curswant = 0;
+ start_arrow(&tpos);
+}
+
+ static void
+ins_end(int c)
+{
+ pos_T tpos;
+
+#ifdef FEAT_FOLDING
+ if ((fdo_flags & FDO_HOR) && KeyTyped)
+ foldOpenCursor();
+#endif
+ undisplay_dollar();
+ tpos = curwin->w_cursor;
+ if (c == K_C_END)
+ curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
+ coladvance((colnr_T)MAXCOL);
+ curwin->w_curswant = MAXCOL;
+
+ start_arrow(&tpos);
+}
+
+ static void
+ins_s_left(void)
+{
+#ifdef FEAT_FOLDING
+ if ((fdo_flags & FDO_HOR) && KeyTyped)
+ foldOpenCursor();
+#endif
+ undisplay_dollar();
+ if (curwin->w_cursor.lnum > 1 || curwin->w_cursor.col > 0)
+ {
+ start_arrow(&curwin->w_cursor);
+ (void)bck_word(1L, FALSE, FALSE);
+ curwin->w_set_curswant = TRUE;
+ }
+ else
+ vim_beep(BO_CRSR);
+}
+
+ static void
+ins_right(
+ int end_change) /* end undoable change */
+{
+#ifdef FEAT_FOLDING
+ if ((fdo_flags & FDO_HOR) && KeyTyped)
+ foldOpenCursor();
+#endif
+ undisplay_dollar();
+ if (gchar_cursor() != NUL || virtual_active())
+ {
+ start_arrow_with_change(&curwin->w_cursor, end_change);
+ if (!end_change)
+ AppendCharToRedobuff(K_RIGHT);
+ curwin->w_set_curswant = TRUE;
+ if (virtual_active())
+ oneright();
+ else
+ {
+ if (has_mbyte)
+ curwin->w_cursor.col += (*mb_ptr2len)(ml_get_cursor());
+ else
+ ++curwin->w_cursor.col;
+ }
+
+#ifdef FEAT_RIGHTLEFT
+ revins_legal++;
+ if (revins_chars)
+ revins_chars--;
+#endif
+ }
+ /* if 'whichwrap' set for cursor in insert mode, may move the
+ * cursor to the next line */
+ else if (vim_strchr(p_ww, ']') != NULL
+ && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
+ {
+ start_arrow(&curwin->w_cursor);
+ curwin->w_set_curswant = TRUE;
+ ++curwin->w_cursor.lnum;
+ curwin->w_cursor.col = 0;
+ }
+ else
+ vim_beep(BO_CRSR);
+ dont_sync_undo = FALSE;
+}
+
+ static void
+ins_s_right(void)
+{
+#ifdef FEAT_FOLDING
+ if ((fdo_flags & FDO_HOR) && KeyTyped)
+ foldOpenCursor();
+#endif
+ undisplay_dollar();
+ if (curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count
+ || gchar_cursor() != NUL)
+ {
+ start_arrow(&curwin->w_cursor);
+ (void)fwd_word(1L, FALSE, 0);
+ curwin->w_set_curswant = TRUE;
+ }
+ else
+ vim_beep(BO_CRSR);
+}
+
+ static void
+ins_up(
+ int startcol) /* when TRUE move to Insstart.col */
+{
+ pos_T tpos;
+ linenr_T old_topline = curwin->w_topline;
+#ifdef FEAT_DIFF
+ int old_topfill = curwin->w_topfill;
+#endif
+
+ undisplay_dollar();
+ tpos = curwin->w_cursor;
+ if (cursor_up(1L, TRUE) == OK)
+ {
+ if (startcol)
+ coladvance(getvcol_nolist(&Insstart));
+ if (old_topline != curwin->w_topline
+#ifdef FEAT_DIFF
+ || old_topfill != curwin->w_topfill
+#endif
+ )
+ redraw_later(VALID);
+ start_arrow(&tpos);
+#ifdef FEAT_CINDENT
+ can_cindent = TRUE;
+#endif
+ }
+ else
+ vim_beep(BO_CRSR);
+}
+
+ static void
+ins_pageup(void)
+{
+ pos_T tpos;
+
+ undisplay_dollar();
+
+ if (mod_mask & MOD_MASK_CTRL)
+ {
+ /* <C-PageUp>: tab page back */
+ if (first_tabpage->tp_next != NULL)
+ {
+ start_arrow(&curwin->w_cursor);
+ goto_tabpage(-1);
+ }
+ return;
+ }
+
+ tpos = curwin->w_cursor;
+ if (onepage(BACKWARD, 1L) == OK)
+ {
+ start_arrow(&tpos);
+#ifdef FEAT_CINDENT
+ can_cindent = TRUE;
+#endif
+ }
+ else
+ vim_beep(BO_CRSR);
+}
+
+ static void
+ins_down(
+ int startcol) /* when TRUE move to Insstart.col */
+{
+ pos_T tpos;
+ linenr_T old_topline = curwin->w_topline;
+#ifdef FEAT_DIFF
+ int old_topfill = curwin->w_topfill;
+#endif
+
+ undisplay_dollar();
+ tpos = curwin->w_cursor;
+ if (cursor_down(1L, TRUE) == OK)
+ {
+ if (startcol)
+ coladvance(getvcol_nolist(&Insstart));
+ if (old_topline != curwin->w_topline
+#ifdef FEAT_DIFF
+ || old_topfill != curwin->w_topfill
+#endif
+ )
+ redraw_later(VALID);
+ start_arrow(&tpos);
+#ifdef FEAT_CINDENT
+ can_cindent = TRUE;
+#endif
+ }
+ else
+ vim_beep(BO_CRSR);
+}
+
+ static void
+ins_pagedown(void)
+{
+ pos_T tpos;
+
+ undisplay_dollar();
+
+ if (mod_mask & MOD_MASK_CTRL)
+ {
+ /* <C-PageDown>: tab page forward */
+ if (first_tabpage->tp_next != NULL)
+ {
+ start_arrow(&curwin->w_cursor);
+ goto_tabpage(0);
+ }
+ return;
+ }
+
+ tpos = curwin->w_cursor;
+ if (onepage(FORWARD, 1L) == OK)
+ {
+ start_arrow(&tpos);
+#ifdef FEAT_CINDENT
+ can_cindent = TRUE;
+#endif
+ }
+ else
+ vim_beep(BO_CRSR);
+}
+
+#ifdef FEAT_DND
+ static void
+ins_drop(void)
+{
+ do_put('~', BACKWARD, 1L, PUT_CURSEND);
+}
+#endif
+
+/*
+ * Handle TAB in Insert or Replace mode.
+ * Return TRUE when the TAB needs to be inserted like a normal character.
+ */
+ static int
+ins_tab(void)
+{
+ int ind;
+ int i;
+ int temp;
+
+ if (Insstart_blank_vcol == MAXCOL && curwin->w_cursor.lnum == Insstart.lnum)
+ Insstart_blank_vcol = get_nolist_virtcol();
+ if (echeck_abbr(TAB + ABBR_OFF))
+ return FALSE;
+
+ ind = inindent(0);
+#ifdef FEAT_CINDENT
+ if (ind)
+ can_cindent = FALSE;
+#endif
+
+ /*
+ * When nothing special, insert TAB like a normal character.
+ */
+ if (!curbuf->b_p_et
+#ifdef FEAT_VARTABS
+ && !(p_sta && ind
+ /* These five lines mean 'tabstop' != 'shiftwidth' */
+ && ((tabstop_count(curbuf->b_p_vts_array) > 1)
+ || (tabstop_count(curbuf->b_p_vts_array) == 1
+ && tabstop_first(curbuf->b_p_vts_array)
+ != get_sw_value(curbuf))
+ || (tabstop_count(curbuf->b_p_vts_array) == 0
+ && curbuf->b_p_ts != get_sw_value(curbuf))))
+ && tabstop_count(curbuf->b_p_vsts_array) == 0
+#else
+ && !(p_sta && ind && curbuf->b_p_ts != get_sw_value(curbuf))
+#endif
+ && get_sts_value() == 0)
+ return TRUE;
+
+ if (stop_arrow() == FAIL)
+ return TRUE;
+
+ did_ai = FALSE;
+#ifdef FEAT_SMARTINDENT
+ did_si = FALSE;
+ can_si = FALSE;
+ can_si_back = FALSE;
+#endif
+ AppendToRedobuff((char_u *)"\t");
+
+#ifdef FEAT_VARTABS
+ if (p_sta && ind) /* insert tab in indent, use 'shiftwidth' */
+ {
+ temp = (int)get_sw_value(curbuf);
+ temp -= get_nolist_virtcol() % temp;
+ }
+ else if (tabstop_count(curbuf->b_p_vsts_array) > 0 || curbuf->b_p_sts != 0)
+ /* use 'softtabstop' when set */
+ temp = tabstop_padding(get_nolist_virtcol(), get_sts_value(),
+ curbuf->b_p_vsts_array);
+ else /* otherwise use 'tabstop' */
+ temp = tabstop_padding(get_nolist_virtcol(), curbuf->b_p_ts,
+ curbuf->b_p_vts_array);
+#else
+ if (p_sta && ind) /* insert tab in indent, use 'shiftwidth' */
+ temp = (int)get_sw_value(curbuf);
+ else if (curbuf->b_p_sts != 0) /* use 'softtabstop' when set */
+ temp = (int)get_sts_value();
+ else /* otherwise use 'tabstop' */
+ temp = (int)curbuf->b_p_ts;
+ temp -= get_nolist_virtcol() % temp;
+#endif
+
+ /*
+ * Insert the first space with ins_char(). It will delete one char in
+ * replace mode. Insert the rest with ins_str(); it will not delete any
+ * chars. For VREPLACE mode, we use ins_char() for all characters.
+ */
+ ins_char(' ');
+ while (--temp > 0)
+ {
+ if (State & VREPLACE_FLAG)
+ ins_char(' ');
+ else
+ {
+ ins_str((char_u *)" ");
+ if (State & REPLACE_FLAG) /* no char replaced */
+ replace_push(NUL);
+ }
+ }
+
+ /*
+ * When 'expandtab' not set: Replace spaces by TABs where possible.
+ */
+#ifdef FEAT_VARTABS
+ if (!curbuf->b_p_et && (tabstop_count(curbuf->b_p_vsts_array) > 0
+ || get_sts_value() > 0
+ || (p_sta && ind)))
+#else
+ if (!curbuf->b_p_et && (get_sts_value() || (p_sta && ind)))
+#endif
+ {
+ char_u *ptr;
+ char_u *saved_line = NULL; /* init for GCC */
+ pos_T pos;
+ pos_T fpos;
+ pos_T *cursor;
+ colnr_T want_vcol, vcol;
+ int change_col = -1;
+ int save_list = curwin->w_p_list;
+
+ /*
+ * Get the current line. For VREPLACE mode, don't make real changes
+ * yet, just work on a copy of the line.
+ */
+ if (State & VREPLACE_FLAG)
+ {
+ pos = curwin->w_cursor;
+ cursor = &pos;
+ saved_line = vim_strsave(ml_get_curline());
+ if (saved_line == NULL)
+ return FALSE;
+ ptr = saved_line + pos.col;
+ }
+ else
+ {
+ ptr = ml_get_cursor();
+ cursor = &curwin->w_cursor;
+ }
+
+ /* When 'L' is not in 'cpoptions' a tab always takes up 'ts' spaces. */
+ if (vim_strchr(p_cpo, CPO_LISTWM) == NULL)
+ curwin->w_p_list = FALSE;
+
+ /* Find first white before the cursor */
+ fpos = curwin->w_cursor;
+ while (fpos.col > 0 && VIM_ISWHITE(ptr[-1]))
+ {
+ --fpos.col;
+ --ptr;
+ }
+
+ /* In Replace mode, don't change characters before the insert point. */
+ if ((State & REPLACE_FLAG)
+ && fpos.lnum == Insstart.lnum
+ && fpos.col < Insstart.col)
+ {
+ ptr += Insstart.col - fpos.col;
+ fpos.col = Insstart.col;
+ }
+
+ /* compute virtual column numbers of first white and cursor */
+ getvcol(curwin, &fpos, &vcol, NULL, NULL);
+ getvcol(curwin, cursor, &want_vcol, NULL, NULL);
+
+ /* Use as many TABs as possible. Beware of 'breakindent', 'showbreak'
+ * and 'linebreak' adding extra virtual columns. */
+ while (VIM_ISWHITE(*ptr))
+ {
+ i = lbr_chartabsize(NULL, (char_u *)"\t", vcol);
+ if (vcol + i > want_vcol)
+ break;
+ if (*ptr != TAB)
+ {
+ *ptr = TAB;
+ if (change_col < 0)
+ {
+ change_col = fpos.col; /* Column of first change */
+ /* May have to adjust Insstart */
+ if (fpos.lnum == Insstart.lnum && fpos.col < Insstart.col)
+ Insstart.col = fpos.col;
+ }
+ }
+ ++fpos.col;
+ ++ptr;
+ vcol += i;
+ }
+
+ if (change_col >= 0)
+ {
+ int repl_off = 0;
+ char_u *line = ptr;
+
+ /* Skip over the spaces we need. */
+ while (vcol < want_vcol && *ptr == ' ')
+ {
+ vcol += lbr_chartabsize(line, ptr, vcol);
+ ++ptr;
+ ++repl_off;
+ }
+ if (vcol > want_vcol)
+ {
+ /* Must have a char with 'showbreak' just before it. */
+ --ptr;
+ --repl_off;
+ }
+ fpos.col += repl_off;
+
+ /* Delete following spaces. */
+ i = cursor->col - fpos.col;
+ if (i > 0)
+ {
+ STRMOVE(ptr, ptr + i);
+ /* correct replace stack. */
+ if ((State & REPLACE_FLAG) && !(State & VREPLACE_FLAG))
+ for (temp = i; --temp >= 0; )
+ replace_join(repl_off);
+#ifdef FEAT_TEXT_PROP
+ curbuf->b_ml.ml_line_len -= i;
+#endif
+ }
+#ifdef FEAT_NETBEANS_INTG
+ if (netbeans_active())
+ {
+ netbeans_removed(curbuf, fpos.lnum, cursor->col, (long)(i + 1));
+ netbeans_inserted(curbuf, fpos.lnum, cursor->col,
+ (char_u *)"\t", 1);
+ }
+#endif
+ cursor->col -= i;
+
+ /*
+ * In VREPLACE mode, we haven't changed anything yet. Do it now by
+ * backspacing over the changed spacing and then inserting the new
+ * spacing.
+ */
+ if (State & VREPLACE_FLAG)
+ {
+ /* Backspace from real cursor to change_col */
+ backspace_until_column(change_col);
+
+ /* Insert each char in saved_line from changed_col to
+ * ptr-cursor */
+ ins_bytes_len(saved_line + change_col,
+ cursor->col - change_col);
+ }
+ }
+
+ if (State & VREPLACE_FLAG)
+ vim_free(saved_line);
+ curwin->w_p_list = save_list;
+ }
+
+ return FALSE;
+}
+
+/*
+ * Handle CR or NL in insert mode.
+ * Return FAIL when out of memory or can't undo.
+ */
+ static int
+ins_eol(int c)
+{
+ int i;
+
+ if (echeck_abbr(c + ABBR_OFF))
+ return OK;
+ if (stop_arrow() == FAIL)
+ return FAIL;
+ undisplay_dollar();
+
+ /*
+ * Strange Vi behaviour: In Replace mode, typing a NL will not delete the
+ * character under the cursor. Only push a NUL on the replace stack,
+ * nothing to put back when the NL is deleted.
+ */
+ if ((State & REPLACE_FLAG) && !(State & VREPLACE_FLAG))
+ replace_push(NUL);
+
+ /*
+ * In VREPLACE mode, a NL replaces the rest of the line, and starts
+ * replacing the next line, so we push all of the characters left on the
+ * line onto the replace stack. This is not done here though, it is done
+ * in open_line().
+ */
+
+ /* Put cursor on NUL if on the last char and coladd is 1 (happens after
+ * CTRL-O). */
+ if (virtual_active() && curwin->w_cursor.coladd > 0)
+ coladvance(getviscol());
+
+#ifdef FEAT_RIGHTLEFT
+# ifdef FEAT_FKMAP
+ if (p_altkeymap && p_fkmap)
+ fkmap(NL);
+# endif
+ /* NL in reverse insert will always start in the end of
+ * current line. */
+ if (revins_on)
+ curwin->w_cursor.col += (colnr_T)STRLEN(ml_get_cursor());
+#endif
+
+ AppendToRedobuff(NL_STR);
+ i = open_line(FORWARD,
+#ifdef FEAT_COMMENTS
+ has_format_option(FO_RET_COMS) ? OPENLINE_DO_COM :
+#endif
+ 0, old_indent);
+ old_indent = 0;
+#ifdef FEAT_CINDENT
+ can_cindent = TRUE;
+#endif
+#ifdef FEAT_FOLDING
+ /* When inserting a line the cursor line must never be in a closed fold. */
+ foldOpenCursor();
+#endif
+
+ return i;
+}
+
+#ifdef FEAT_DIGRAPHS
+/*
+ * Handle digraph in insert mode.
+ * Returns character still to be inserted, or NUL when nothing remaining to be
+ * done.
+ */
+ static int
+ins_digraph(void)
+{
+ int c;
+ int cc;
+ int did_putchar = FALSE;
+
+ pc_status = PC_STATUS_UNSET;
+ if (redrawing() && !char_avail())
+ {
+ /* may need to redraw when no more chars available now */
+ ins_redraw(FALSE);
+
+ edit_putchar('?', TRUE);
+ did_putchar = TRUE;
+#ifdef FEAT_CMDL_INFO
+ add_to_showcmd_c(Ctrl_K);
+#endif
+ }
+
+#ifdef USE_ON_FLY_SCROLL
+ dont_scroll = TRUE; /* disallow scrolling here */
+#endif
+
+ /* don't map the digraph chars. This also prevents the
+ * mode message to be deleted when ESC is hit */
+ ++no_mapping;
+ ++allow_keys;
+ c = plain_vgetc();
+ --no_mapping;
+ --allow_keys;
+ if (did_putchar)
+ /* when the line fits in 'columns' the '?' is at the start of the next
+ * line and will not be removed by the redraw */
+ edit_unputchar();
+
+ if (IS_SPECIAL(c) || mod_mask) /* special key */
+ {
+#ifdef FEAT_CMDL_INFO
+ clear_showcmd();
+#endif
+ insert_special(c, TRUE, FALSE);
+ return NUL;
+ }
+ if (c != ESC)
+ {
+ did_putchar = FALSE;
+ if (redrawing() && !char_avail())
+ {
+ /* may need to redraw when no more chars available now */
+ ins_redraw(FALSE);
+
+ if (char2cells(c) == 1)
+ {
+ ins_redraw(FALSE);
+ edit_putchar(c, TRUE);
+ did_putchar = TRUE;
+ }
+#ifdef FEAT_CMDL_INFO
+ add_to_showcmd_c(c);
+#endif
+ }
+ ++no_mapping;
+ ++allow_keys;
+ cc = plain_vgetc();
+ --no_mapping;
+ --allow_keys;
+ if (did_putchar)
+ /* when the line fits in 'columns' the '?' is at the start of the
+ * next line and will not be removed by a redraw */
+ edit_unputchar();
+ if (cc != ESC)
+ {
+ AppendToRedobuff((char_u *)CTRL_V_STR);
+ c = getdigraph(c, cc, TRUE);
+#ifdef FEAT_CMDL_INFO
+ clear_showcmd();
+#endif
+ return c;
+ }
+ }
+#ifdef FEAT_CMDL_INFO
+ clear_showcmd();
+#endif
+ return NUL;
+}
+#endif
+
+/*
+ * Handle CTRL-E and CTRL-Y in Insert mode: copy char from other line.
+ * Returns the char to be inserted, or NUL if none found.
+ */
+ int
+ins_copychar(linenr_T lnum)
+{
+ int c;
+ int temp;
+ char_u *ptr, *prev_ptr;
+ char_u *line;
+
+ if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
+ {
+ vim_beep(BO_COPY);
+ return NUL;
+ }
+
+ /* try to advance to the cursor column */
+ temp = 0;
+ line = ptr = ml_get(lnum);
+ prev_ptr = ptr;
+ validate_virtcol();
+ while ((colnr_T)temp < curwin->w_virtcol && *ptr != NUL)
+ {
+ prev_ptr = ptr;
+ temp += lbr_chartabsize_adv(line, &ptr, (colnr_T)temp);
+ }
+ if ((colnr_T)temp > curwin->w_virtcol)
+ ptr = prev_ptr;
+
+ c = (*mb_ptr2char)(ptr);
+ if (c == NUL)
+ vim_beep(BO_COPY);
+ return c;
+}
+
+/*
+ * CTRL-Y or CTRL-E typed in Insert mode.
+ */
+ static int
+ins_ctrl_ey(int tc)
+{
+ int c = tc;
+
+#ifdef FEAT_INS_EXPAND
+ if (ctrl_x_mode == CTRL_X_SCROLL)
+ {
+ if (c == Ctrl_Y)
+ scrolldown_clamp();
+ else
+ scrollup_clamp();
+ redraw_later(VALID);
+ }
+ else
+#endif
+ {
+ c = ins_copychar(curwin->w_cursor.lnum + (c == Ctrl_Y ? -1 : 1));
+ if (c != NUL)
+ {
+ long tw_save;
+
+ /* The character must be taken literally, insert like it
+ * was typed after a CTRL-V, and pretend 'textwidth'
+ * wasn't set. Digits, 'o' and 'x' are special after a
+ * CTRL-V, don't use it for these. */
+ if (c < 256 && !isalnum(c))
+ AppendToRedobuff((char_u *)CTRL_V_STR); /* CTRL-V */
+ tw_save = curbuf->b_p_tw;
+ curbuf->b_p_tw = -1;
+ insert_special(c, TRUE, FALSE);
+ curbuf->b_p_tw = tw_save;
+#ifdef FEAT_RIGHTLEFT
+ revins_chars++;
+ revins_legal++;
+#endif
+ c = Ctrl_V; /* pretend CTRL-V is last character */
+ auto_format(FALSE, TRUE);
+ }
+ }
+ return c;
+}
+
+#ifdef FEAT_SMARTINDENT
+/*
+ * Try to do some very smart auto-indenting.
+ * Used when inserting a "normal" character.
+ */
+ static void
+ins_try_si(int c)
+{
+ pos_T *pos, old_pos;
+ char_u *ptr;
+ int i;
+ int temp;
+
+ /*
+ * do some very smart indenting when entering '{' or '}'
+ */
+ if (((did_si || can_si_back) && c == '{') || (can_si && c == '}'))
+ {
+ /*
+ * for '}' set indent equal to indent of line containing matching '{'
+ */
+ if (c == '}' && (pos = findmatch(NULL, '{')) != NULL)
+ {
+ old_pos = curwin->w_cursor;
+ /*
+ * If the matching '{' has a ')' immediately before it (ignoring
+ * white-space), then line up with the start of the line
+ * containing the matching '(' if there is one. This handles the
+ * case where an "if (..\n..) {" statement continues over multiple
+ * lines -- webb
+ */
+ ptr = ml_get(pos->lnum);
+ i = pos->col;
+ if (i > 0) /* skip blanks before '{' */
+ while (--i > 0 && VIM_ISWHITE(ptr[i]))
+ ;
+ curwin->w_cursor.lnum = pos->lnum;
+ curwin->w_cursor.col = i;
+ if (ptr[i] == ')' && (pos = findmatch(NULL, '(')) != NULL)
+ curwin->w_cursor = *pos;
+ i = get_indent();
+ curwin->w_cursor = old_pos;
+ if (State & VREPLACE_FLAG)
+ change_indent(INDENT_SET, i, FALSE, NUL, TRUE);
+ else
+ (void)set_indent(i, SIN_CHANGED);
+ }
+ else if (curwin->w_cursor.col > 0)
+ {
+ /*
+ * when inserting '{' after "O" reduce indent, but not
+ * more than indent of previous line
+ */
+ temp = TRUE;
+ if (c == '{' && can_si_back && curwin->w_cursor.lnum > 1)
+ {
+ old_pos = curwin->w_cursor;
+ i = get_indent();
+ while (curwin->w_cursor.lnum > 1)
+ {
+ ptr = skipwhite(ml_get(--(curwin->w_cursor.lnum)));
+
+ /* ignore empty lines and lines starting with '#'. */
+ if (*ptr != '#' && *ptr != NUL)
+ break;
+ }
+ if (get_indent() >= i)
+ temp = FALSE;
+ curwin->w_cursor = old_pos;
+ }
+ if (temp)
+ shift_line(TRUE, FALSE, 1, TRUE);
+ }
+ }
+
+ /*
+ * set indent of '#' always to 0
+ */
+ if (curwin->w_cursor.col > 0 && can_si && c == '#')
+ {
+ /* remember current indent for next line */
+ old_indent = get_indent();
+ (void)set_indent(0, SIN_CHANGED);
+ }
+
+ /* Adjust ai_col, the char at this position can be deleted. */
+ if (ai_col > curwin->w_cursor.col)
+ ai_col = curwin->w_cursor.col;
+}
+#endif
+
+/*
+ * Get the value that w_virtcol would have when 'list' is off.
+ * Unless 'cpo' contains the 'L' flag.
+ */
+ colnr_T
+get_nolist_virtcol(void)
+{
+ // check validity of cursor in current buffer
+ if (curwin->w_buffer == NULL
+ || curwin->w_buffer->b_ml.ml_mfp == NULL
+ || curwin->w_cursor.lnum > curwin->w_buffer->b_ml.ml_line_count)
+ return 0;
+ if (curwin->w_p_list && vim_strchr(p_cpo, CPO_LISTWM) == NULL)
+ return getvcol_nolist(&curwin->w_cursor);
+ validate_virtcol();
+ return curwin->w_virtcol;
+}
+
+#if defined(FEAT_EVAL)
+/*
+ * Handle the InsertCharPre autocommand.
+ * "c" is the character that was typed.
+ * Return a pointer to allocated memory with the replacement string.
+ * Return NULL to continue inserting "c".
+ */
+ static char_u *
+do_insert_char_pre(int c)
+{
+ char_u *res;
+ char_u buf[MB_MAXBYTES + 1];
+ int save_State = State;
+
+ /* Return quickly when there is nothing to do. */
+ if (!has_insertcharpre())
+ return NULL;
+
+ if (has_mbyte)
+ buf[(*mb_char2bytes)(c, buf)] = NUL;
+ else
+ {
+ buf[0] = c;
+ buf[1] = NUL;
+ }
+
+ /* Lock the text to avoid weird things from happening. */
+ ++textlock;
+ set_vim_var_string(VV_CHAR, buf, -1); /* set v:char */
+
+ res = NULL;
+ if (ins_apply_autocmds(EVENT_INSERTCHARPRE))
+ {
+ /* Get the value of v:char. It may be empty or more than one
+ * character. Only use it when changed, otherwise continue with the
+ * original character to avoid breaking autoindent. */
+ if (STRCMP(buf, get_vim_var_str(VV_CHAR)) != 0)
+ res = vim_strsave(get_vim_var_str(VV_CHAR));
+ }
+
+ set_vim_var_string(VV_CHAR, NULL, -1); /* clear v:char */
+ --textlock;
+
+ // Restore the State, it may have been changed.
+ State = save_State;
+
+ return res;
+}
+#endif
+
+/*
+ * Trigger "event" and take care of fixing undo.
+ */
+ static int
+ins_apply_autocmds(event_T event)
+{
+ varnumber_T tick = CHANGEDTICK(curbuf);
+ int r;
+
+ r = apply_autocmds(event, NULL, NULL, FALSE, curbuf);
+
+ // If u_savesub() was called then we are not prepared to start
+ // a new line. Call u_save() with no contents to fix that.
+ if (tick != CHANGEDTICK(curbuf))
+ u_save(curwin->w_cursor.lnum, (linenr_T)(curwin->w_cursor.lnum + 1));
+
+ return r;
+}
diff --git a/src/eval.c b/src/eval.c
new file mode 100644
index 0000000..3f9db7d
--- /dev/null
+++ b/src/eval.c
@@ -0,0 +1,10837 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * eval.c: Expression evaluation.
+ */
+#define USING_FLOAT_STUFF
+
+#include "vim.h"
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+
+#ifdef VMS
+# include <float.h>
+#endif
+
+#define DICT_MAXNEST 100 /* maximum nesting of lists and dicts */
+
+static char *e_letunexp = N_("E18: Unexpected characters in :let");
+static char *e_undefvar = N_("E121: Undefined variable: %s");
+static char *e_missbrac = N_("E111: Missing ']'");
+static char *e_dictrange = N_("E719: Cannot use [:] with a Dictionary");
+static char *e_letwrong = N_("E734: Wrong variable type for %s=");
+static char *e_illvar = N_("E461: Illegal variable name: %s");
+#ifdef FEAT_FLOAT
+static char *e_float_as_string = N_("E806: using Float as a String");
+#endif
+
+#define NAMESPACE_CHAR (char_u *)"abglstvw"
+
+static dictitem_T globvars_var; /* variable used for g: */
+#define globvarht globvardict.dv_hashtab
+
+/*
+ * Old Vim variables such as "v:version" are also available without the "v:".
+ * Also in functions. We need a special hashtable for them.
+ */
+static hashtab_T compat_hashtab;
+
+/*
+ * When recursively copying lists and dicts we need to remember which ones we
+ * have done to avoid endless recursiveness. This unique ID is used for that.
+ * The last bit is used for previous_funccal, ignored when comparing.
+ */
+static int current_copyID = 0;
+
+/*
+ * Array to hold the hashtab with variables local to each sourced script.
+ * Each item holds a variable (nameless) that points to the dict_T.
+ */
+typedef struct
+{
+ dictitem_T sv_var;
+ dict_T sv_dict;
+} scriptvar_T;
+
+static garray_T ga_scripts = {0, 0, sizeof(scriptvar_T *), 4, NULL};
+#define SCRIPT_SV(id) (((scriptvar_T **)ga_scripts.ga_data)[(id) - 1])
+#define SCRIPT_VARS(id) (SCRIPT_SV(id)->sv_dict.dv_hashtab)
+
+static int echo_attr = 0; /* attributes used for ":echo" */
+
+/* The names of packages that once were loaded are remembered. */
+static garray_T ga_loaded = {0, 0, sizeof(char_u *), 4, NULL};
+
+/*
+ * Info used by a ":for" loop.
+ */
+typedef struct
+{
+ int fi_semicolon; /* TRUE if ending in '; var]' */
+ int fi_varcount; /* nr of variables in the list */
+ listwatch_T fi_lw; /* keep an eye on the item used. */
+ list_T *fi_list; /* list being used */
+ int fi_bi; /* index of blob */
+ blob_T *fi_blob; /* blob being used */
+} forinfo_T;
+
+
+/*
+ * Array to hold the value of v: variables.
+ * The value is in a dictitem, so that it can also be used in the v: scope.
+ * The reason to use this table anyway is for very quick access to the
+ * variables with the VV_ defines.
+ */
+
+/* values for vv_flags: */
+#define VV_COMPAT 1 /* compatible, also used without "v:" */
+#define VV_RO 2 /* read-only */
+#define VV_RO_SBX 4 /* read-only in the sandbox */
+
+#define VV_NAME(s, t) s, {{t, 0, {0}}, 0, {0}}
+
+static struct vimvar
+{
+ char *vv_name; /* name of variable, without v: */
+ dictitem16_T vv_di; /* value and name for key (max 16 chars!) */
+ char vv_flags; /* VV_COMPAT, VV_RO, VV_RO_SBX */
+} vimvars[VV_LEN] =
+{
+ /*
+ * The order here must match the VV_ defines in vim.h!
+ * Initializing a union does not work, leave tv.vval empty to get zero's.
+ */
+ {VV_NAME("count", VAR_NUMBER), VV_COMPAT+VV_RO},
+ {VV_NAME("count1", VAR_NUMBER), VV_RO},
+ {VV_NAME("prevcount", VAR_NUMBER), VV_RO},
+ {VV_NAME("errmsg", VAR_STRING), VV_COMPAT},
+ {VV_NAME("warningmsg", VAR_STRING), 0},
+ {VV_NAME("statusmsg", VAR_STRING), 0},
+ {VV_NAME("shell_error", VAR_NUMBER), VV_COMPAT+VV_RO},
+ {VV_NAME("this_session", VAR_STRING), VV_COMPAT},
+ {VV_NAME("version", VAR_NUMBER), VV_COMPAT+VV_RO},
+ {VV_NAME("lnum", VAR_NUMBER), VV_RO_SBX},
+ {VV_NAME("termresponse", VAR_STRING), VV_RO},
+ {VV_NAME("fname", VAR_STRING), VV_RO},
+ {VV_NAME("lang", VAR_STRING), VV_RO},
+ {VV_NAME("lc_time", VAR_STRING), VV_RO},
+ {VV_NAME("ctype", VAR_STRING), VV_RO},
+ {VV_NAME("charconvert_from", VAR_STRING), VV_RO},
+ {VV_NAME("charconvert_to", VAR_STRING), VV_RO},
+ {VV_NAME("fname_in", VAR_STRING), VV_RO},
+ {VV_NAME("fname_out", VAR_STRING), VV_RO},
+ {VV_NAME("fname_new", VAR_STRING), VV_RO},
+ {VV_NAME("fname_diff", VAR_STRING), VV_RO},
+ {VV_NAME("cmdarg", VAR_STRING), VV_RO},
+ {VV_NAME("foldstart", VAR_NUMBER), VV_RO_SBX},
+ {VV_NAME("foldend", VAR_NUMBER), VV_RO_SBX},
+ {VV_NAME("folddashes", VAR_STRING), VV_RO_SBX},
+ {VV_NAME("foldlevel", VAR_NUMBER), VV_RO_SBX},
+ {VV_NAME("progname", VAR_STRING), VV_RO},
+ {VV_NAME("servername", VAR_STRING), VV_RO},
+ {VV_NAME("dying", VAR_NUMBER), VV_RO},
+ {VV_NAME("exception", VAR_STRING), VV_RO},
+ {VV_NAME("throwpoint", VAR_STRING), VV_RO},
+ {VV_NAME("register", VAR_STRING), VV_RO},
+ {VV_NAME("cmdbang", VAR_NUMBER), VV_RO},
+ {VV_NAME("insertmode", VAR_STRING), VV_RO},
+ {VV_NAME("val", VAR_UNKNOWN), VV_RO},
+ {VV_NAME("key", VAR_UNKNOWN), VV_RO},
+ {VV_NAME("profiling", VAR_NUMBER), VV_RO},
+ {VV_NAME("fcs_reason", VAR_STRING), VV_RO},
+ {VV_NAME("fcs_choice", VAR_STRING), 0},
+ {VV_NAME("beval_bufnr", VAR_NUMBER), VV_RO},
+ {VV_NAME("beval_winnr", VAR_NUMBER), VV_RO},
+ {VV_NAME("beval_winid", VAR_NUMBER), VV_RO},
+ {VV_NAME("beval_lnum", VAR_NUMBER), VV_RO},
+ {VV_NAME("beval_col", VAR_NUMBER), VV_RO},
+ {VV_NAME("beval_text", VAR_STRING), VV_RO},
+ {VV_NAME("scrollstart", VAR_STRING), 0},
+ {VV_NAME("swapname", VAR_STRING), VV_RO},
+ {VV_NAME("swapchoice", VAR_STRING), 0},
+ {VV_NAME("swapcommand", VAR_STRING), VV_RO},
+ {VV_NAME("char", VAR_STRING), 0},
+ {VV_NAME("mouse_win", VAR_NUMBER), 0},
+ {VV_NAME("mouse_winid", VAR_NUMBER), 0},
+ {VV_NAME("mouse_lnum", VAR_NUMBER), 0},
+ {VV_NAME("mouse_col", VAR_NUMBER), 0},
+ {VV_NAME("operator", VAR_STRING), VV_RO},
+ {VV_NAME("searchforward", VAR_NUMBER), 0},
+ {VV_NAME("hlsearch", VAR_NUMBER), 0},
+ {VV_NAME("oldfiles", VAR_LIST), 0},
+ {VV_NAME("windowid", VAR_NUMBER), VV_RO},
+ {VV_NAME("progpath", VAR_STRING), VV_RO},
+ {VV_NAME("completed_item", VAR_DICT), VV_RO},
+ {VV_NAME("option_new", VAR_STRING), VV_RO},
+ {VV_NAME("option_old", VAR_STRING), VV_RO},
+ {VV_NAME("option_type", VAR_STRING), VV_RO},
+ {VV_NAME("errors", VAR_LIST), 0},
+ {VV_NAME("false", VAR_SPECIAL), VV_RO},
+ {VV_NAME("true", VAR_SPECIAL), VV_RO},
+ {VV_NAME("null", VAR_SPECIAL), VV_RO},
+ {VV_NAME("none", VAR_SPECIAL), VV_RO},
+ {VV_NAME("vim_did_enter", VAR_NUMBER), VV_RO},
+ {VV_NAME("testing", VAR_NUMBER), 0},
+ {VV_NAME("t_number", VAR_NUMBER), VV_RO},
+ {VV_NAME("t_string", VAR_NUMBER), VV_RO},
+ {VV_NAME("t_func", VAR_NUMBER), VV_RO},
+ {VV_NAME("t_list", VAR_NUMBER), VV_RO},
+ {VV_NAME("t_dict", VAR_NUMBER), VV_RO},
+ {VV_NAME("t_float", VAR_NUMBER), VV_RO},
+ {VV_NAME("t_bool", VAR_NUMBER), VV_RO},
+ {VV_NAME("t_none", VAR_NUMBER), VV_RO},
+ {VV_NAME("t_job", VAR_NUMBER), VV_RO},
+ {VV_NAME("t_channel", VAR_NUMBER), VV_RO},
+ {VV_NAME("t_blob", VAR_NUMBER), VV_RO},
+ {VV_NAME("termrfgresp", VAR_STRING), VV_RO},
+ {VV_NAME("termrbgresp", VAR_STRING), VV_RO},
+ {VV_NAME("termu7resp", VAR_STRING), VV_RO},
+ {VV_NAME("termstyleresp", VAR_STRING), VV_RO},
+ {VV_NAME("termblinkresp", VAR_STRING), VV_RO},
+ {VV_NAME("event", VAR_DICT), VV_RO},
+};
+
+/* shorthand */
+#define vv_type vv_di.di_tv.v_type
+#define vv_nr vv_di.di_tv.vval.v_number
+#define vv_float vv_di.di_tv.vval.v_float
+#define vv_str vv_di.di_tv.vval.v_string
+#define vv_list vv_di.di_tv.vval.v_list
+#define vv_dict vv_di.di_tv.vval.v_dict
+#define vv_blob vv_di.di_tv.vval.v_blob
+#define vv_tv vv_di.di_tv
+
+static dictitem_T vimvars_var; /* variable used for v: */
+#define vimvarht vimvardict.dv_hashtab
+
+static int ex_let_vars(char_u *arg, typval_T *tv, int copy, int semicolon, int var_count, char_u *nextchars);
+static char_u *skip_var_list(char_u *arg, int *var_count, int *semicolon);
+static char_u *skip_var_one(char_u *arg);
+static void list_glob_vars(int *first);
+static void list_buf_vars(int *first);
+static void list_win_vars(int *first);
+static void list_tab_vars(int *first);
+static void list_vim_vars(int *first);
+static void list_script_vars(int *first);
+static char_u *list_arg_vars(exarg_T *eap, char_u *arg, int *first);
+static char_u *ex_let_one(char_u *arg, typval_T *tv, int copy, char_u *endchars, char_u *op);
+static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv, int copy, char_u *op);
+static int tv_op(typval_T *tv1, typval_T *tv2, char_u *op);
+static void ex_unletlock(exarg_T *eap, char_u *argstart, int deep);
+static int do_unlet_var(lval_T *lp, char_u *name_end, int forceit);
+static int do_lock_var(lval_T *lp, char_u *name_end, int deep, int lock);
+static void item_lock(typval_T *tv, int deep, int lock);
+
+static int eval2(char_u **arg, typval_T *rettv, int evaluate);
+static int eval3(char_u **arg, typval_T *rettv, int evaluate);
+static int eval4(char_u **arg, typval_T *rettv, int evaluate);
+static int eval5(char_u **arg, typval_T *rettv, int evaluate);
+static int eval6(char_u **arg, typval_T *rettv, int evaluate, int want_string);
+static int eval7(char_u **arg, typval_T *rettv, int evaluate, int want_string);
+
+static int get_string_tv(char_u **arg, typval_T *rettv, int evaluate);
+static int get_lit_string_tv(char_u **arg, typval_T *rettv, int evaluate);
+static int free_unref_items(int copyID);
+static int get_env_tv(char_u **arg, typval_T *rettv, int evaluate);
+static int get_env_len(char_u **arg);
+static char_u * make_expanded_name(char_u *in_start, char_u *expr_start, char_u *expr_end, char_u *in_end);
+static void check_vars(char_u *name, int len);
+static typval_T *alloc_string_tv(char_u *string);
+static void delete_var(hashtab_T *ht, hashitem_T *hi);
+static void list_one_var(dictitem_T *v, char *prefix, int *first);
+static void list_one_var_a(char *prefix, char_u *name, int type, char_u *string, int *first);
+static char_u *find_option_end(char_u **arg, int *opt_flags);
+
+/* for VIM_VERSION_ defines */
+#include "version.h"
+
+
+#if defined(EBCDIC) || defined(PROTO)
+/*
+ * Compare struct fst by function name.
+ */
+ static int
+compare_func_name(const void *s1, const void *s2)
+{
+ struct fst *p1 = (struct fst *)s1;
+ struct fst *p2 = (struct fst *)s2;
+
+ return STRCMP(p1->f_name, p2->f_name);
+}
+
+/*
+ * Sort the function table by function name.
+ * The sorting of the table above is ASCII dependent.
+ * On machines using EBCDIC we have to sort it.
+ */
+ static void
+sortFunctions(void)
+{
+ int funcCnt = (int)(sizeof(functions) / sizeof(struct fst)) - 1;
+
+ qsort(functions, (size_t)funcCnt, sizeof(struct fst), compare_func_name);
+}
+#endif
+
+
+/*
+ * Initialize the global and v: variables.
+ */
+ void
+eval_init(void)
+{
+ int i;
+ struct vimvar *p;
+
+ init_var_dict(&globvardict, &globvars_var, VAR_DEF_SCOPE);
+ init_var_dict(&vimvardict, &vimvars_var, VAR_SCOPE);
+ vimvardict.dv_lock = VAR_FIXED;
+ hash_init(&compat_hashtab);
+ func_init();
+
+ for (i = 0; i < VV_LEN; ++i)
+ {
+ p = &vimvars[i];
+ if (STRLEN(p->vv_name) > 16)
+ {
+ iemsg("INTERNAL: name too long, increase size of dictitem16_T");
+ getout(1);
+ }
+ STRCPY(p->vv_di.di_key, p->vv_name);
+ if (p->vv_flags & VV_RO)
+ p->vv_di.di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
+ else if (p->vv_flags & VV_RO_SBX)
+ p->vv_di.di_flags = DI_FLAGS_RO_SBX | DI_FLAGS_FIX;
+ else
+ p->vv_di.di_flags = DI_FLAGS_FIX;
+
+ /* add to v: scope dict, unless the value is not always available */
+ if (p->vv_type != VAR_UNKNOWN)
+ hash_add(&vimvarht, p->vv_di.di_key);
+ if (p->vv_flags & VV_COMPAT)
+ /* add to compat scope dict */
+ hash_add(&compat_hashtab, p->vv_di.di_key);
+ }
+ vimvars[VV_VERSION].vv_nr = VIM_VERSION_100;
+
+ set_vim_var_nr(VV_SEARCHFORWARD, 1L);
+ set_vim_var_nr(VV_HLSEARCH, 1L);
+ set_vim_var_dict(VV_COMPLETED_ITEM, dict_alloc_lock(VAR_FIXED));
+ set_vim_var_list(VV_ERRORS, list_alloc());
+ set_vim_var_dict(VV_EVENT, dict_alloc_lock(VAR_FIXED));
+
+ set_vim_var_nr(VV_FALSE, VVAL_FALSE);
+ set_vim_var_nr(VV_TRUE, VVAL_TRUE);
+ set_vim_var_nr(VV_NONE, VVAL_NONE);
+ set_vim_var_nr(VV_NULL, VVAL_NULL);
+
+ set_vim_var_nr(VV_TYPE_NUMBER, VAR_TYPE_NUMBER);
+ set_vim_var_nr(VV_TYPE_STRING, VAR_TYPE_STRING);
+ set_vim_var_nr(VV_TYPE_FUNC, VAR_TYPE_FUNC);
+ set_vim_var_nr(VV_TYPE_LIST, VAR_TYPE_LIST);
+ set_vim_var_nr(VV_TYPE_DICT, VAR_TYPE_DICT);
+ set_vim_var_nr(VV_TYPE_FLOAT, VAR_TYPE_FLOAT);
+ set_vim_var_nr(VV_TYPE_BOOL, VAR_TYPE_BOOL);
+ set_vim_var_nr(VV_TYPE_NONE, VAR_TYPE_NONE);
+ set_vim_var_nr(VV_TYPE_JOB, VAR_TYPE_JOB);
+ set_vim_var_nr(VV_TYPE_CHANNEL, VAR_TYPE_CHANNEL);
+ set_vim_var_nr(VV_TYPE_BLOB, VAR_TYPE_BLOB);
+
+ set_reg_var(0); /* default for v:register is not 0 but '"' */
+
+#ifdef EBCDIC
+ /*
+ * Sort the function table, to enable binary search.
+ */
+ sortFunctions();
+#endif
+}
+
+#if defined(EXITFREE) || defined(PROTO)
+ void
+eval_clear(void)
+{
+ int i;
+ struct vimvar *p;
+
+ for (i = 0; i < VV_LEN; ++i)
+ {
+ p = &vimvars[i];
+ if (p->vv_di.di_tv.v_type == VAR_STRING)
+ VIM_CLEAR(p->vv_str);
+ else if (p->vv_di.di_tv.v_type == VAR_LIST)
+ {
+ list_unref(p->vv_list);
+ p->vv_list = NULL;
+ }
+ }
+ hash_clear(&vimvarht);
+ hash_init(&vimvarht); /* garbage_collect() will access it */
+ hash_clear(&compat_hashtab);
+
+ free_scriptnames();
+# if defined(FEAT_CMDL_COMPL)
+ free_locales();
+# endif
+
+ /* global variables */
+ vars_clear(&globvarht);
+
+ /* autoloaded script names */
+ ga_clear_strings(&ga_loaded);
+
+ /* Script-local variables. First clear all the variables and in a second
+ * loop free the scriptvar_T, because a variable in one script might hold
+ * a reference to the whole scope of another script. */
+ for (i = 1; i <= ga_scripts.ga_len; ++i)
+ vars_clear(&SCRIPT_VARS(i));
+ for (i = 1; i <= ga_scripts.ga_len; ++i)
+ vim_free(SCRIPT_SV(i));
+ ga_clear(&ga_scripts);
+
+ /* unreferenced lists and dicts */
+ (void)garbage_collect(FALSE);
+
+ /* functions */
+ free_all_functions();
+}
+#endif
+
+
+/*
+ * Set an internal variable to a string value. Creates the variable if it does
+ * not already exist.
+ */
+ void
+set_internal_string_var(char_u *name, char_u *value)
+{
+ char_u *val;
+ typval_T *tvp;
+
+ val = vim_strsave(value);
+ if (val != NULL)
+ {
+ tvp = alloc_string_tv(val);
+ if (tvp != NULL)
+ {
+ set_var(name, tvp, FALSE);
+ free_tv(tvp);
+ }
+ }
+}
+
+static lval_T *redir_lval = NULL;
+#define EVALCMD_BUSY (redir_lval == (lval_T *)&redir_lval)
+static garray_T redir_ga; /* only valid when redir_lval is not NULL */
+static char_u *redir_endp = NULL;
+static char_u *redir_varname = NULL;
+
+/*
+ * Start recording command output to a variable
+ * When "append" is TRUE append to an existing variable.
+ * Returns OK if successfully completed the setup. FAIL otherwise.
+ */
+ int
+var_redir_start(char_u *name, int append)
+{
+ int save_emsg;
+ int err;
+ typval_T tv;
+
+ /* Catch a bad name early. */
+ if (!eval_isnamec1(*name))
+ {
+ emsg(_(e_invarg));
+ return FAIL;
+ }
+
+ /* Make a copy of the name, it is used in redir_lval until redir ends. */
+ redir_varname = vim_strsave(name);
+ if (redir_varname == NULL)
+ return FAIL;
+
+ redir_lval = (lval_T *)alloc_clear((unsigned)sizeof(lval_T));
+ if (redir_lval == NULL)
+ {
+ var_redir_stop();
+ return FAIL;
+ }
+
+ /* The output is stored in growarray "redir_ga" until redirection ends. */
+ ga_init2(&redir_ga, (int)sizeof(char), 500);
+
+ /* Parse the variable name (can be a dict or list entry). */
+ redir_endp = get_lval(redir_varname, NULL, redir_lval, FALSE, FALSE, 0,
+ FNE_CHECK_START);
+ if (redir_endp == NULL || redir_lval->ll_name == NULL || *redir_endp != NUL)
+ {
+ clear_lval(redir_lval);
+ if (redir_endp != NULL && *redir_endp != NUL)
+ /* Trailing characters are present after the variable name */
+ emsg(_(e_trailing));
+ else
+ emsg(_(e_invarg));
+ redir_endp = NULL; /* don't store a value, only cleanup */
+ var_redir_stop();
+ return FAIL;
+ }
+
+ /* check if we can write to the variable: set it to or append an empty
+ * string */
+ save_emsg = did_emsg;
+ did_emsg = FALSE;
+ tv.v_type = VAR_STRING;
+ tv.vval.v_string = (char_u *)"";
+ if (append)
+ set_var_lval(redir_lval, redir_endp, &tv, TRUE, (char_u *)".");
+ else
+ set_var_lval(redir_lval, redir_endp, &tv, TRUE, (char_u *)"=");
+ clear_lval(redir_lval);
+ err = did_emsg;
+ did_emsg |= save_emsg;
+ if (err)
+ {
+ redir_endp = NULL; /* don't store a value, only cleanup */
+ var_redir_stop();
+ return FAIL;
+ }
+
+ return OK;
+}
+
+/*
+ * Append "value[value_len]" to the variable set by var_redir_start().
+ * The actual appending is postponed until redirection ends, because the value
+ * appended may in fact be the string we write to, changing it may cause freed
+ * memory to be used:
+ * :redir => foo
+ * :let foo
+ * :redir END
+ */
+ void
+var_redir_str(char_u *value, int value_len)
+{
+ int len;
+
+ if (redir_lval == NULL)
+ return;
+
+ if (value_len == -1)
+ len = (int)STRLEN(value); /* Append the entire string */
+ else
+ len = value_len; /* Append only "value_len" characters */
+
+ if (ga_grow(&redir_ga, len) == OK)
+ {
+ mch_memmove((char *)redir_ga.ga_data + redir_ga.ga_len, value, len);
+ redir_ga.ga_len += len;
+ }
+ else
+ var_redir_stop();
+}
+
+/*
+ * Stop redirecting command output to a variable.
+ * Frees the allocated memory.
+ */
+ void
+var_redir_stop(void)
+{
+ typval_T tv;
+
+ if (EVALCMD_BUSY)
+ {
+ redir_lval = NULL;
+ return;
+ }
+
+ if (redir_lval != NULL)
+ {
+ /* If there was no error: assign the text to the variable. */
+ if (redir_endp != NULL)
+ {
+ ga_append(&redir_ga, NUL); /* Append the trailing NUL. */
+ tv.v_type = VAR_STRING;
+ tv.vval.v_string = redir_ga.ga_data;
+ /* Call get_lval() again, if it's inside a Dict or List it may
+ * have changed. */
+ redir_endp = get_lval(redir_varname, NULL, redir_lval,
+ FALSE, FALSE, 0, FNE_CHECK_START);
+ if (redir_endp != NULL && redir_lval->ll_name != NULL)
+ set_var_lval(redir_lval, redir_endp, &tv, FALSE, (char_u *)".");
+ clear_lval(redir_lval);
+ }
+
+ /* free the collected output */
+ VIM_CLEAR(redir_ga.ga_data);
+
+ VIM_CLEAR(redir_lval);
+ }
+ VIM_CLEAR(redir_varname);
+}
+
+ int
+eval_charconvert(
+ char_u *enc_from,
+ char_u *enc_to,
+ char_u *fname_from,
+ char_u *fname_to)
+{
+ int err = FALSE;
+
+ set_vim_var_string(VV_CC_FROM, enc_from, -1);
+ set_vim_var_string(VV_CC_TO, enc_to, -1);
+ set_vim_var_string(VV_FNAME_IN, fname_from, -1);
+ set_vim_var_string(VV_FNAME_OUT, fname_to, -1);
+ if (eval_to_bool(p_ccv, &err, NULL, FALSE))
+ err = TRUE;
+ set_vim_var_string(VV_CC_FROM, NULL, -1);
+ set_vim_var_string(VV_CC_TO, NULL, -1);
+ set_vim_var_string(VV_FNAME_IN, NULL, -1);
+ set_vim_var_string(VV_FNAME_OUT, NULL, -1);
+
+ if (err)
+ return FAIL;
+ return OK;
+}
+
+# if defined(FEAT_POSTSCRIPT) || defined(PROTO)
+ int
+eval_printexpr(char_u *fname, char_u *args)
+{
+ int err = FALSE;
+
+ set_vim_var_string(VV_FNAME_IN, fname, -1);
+ set_vim_var_string(VV_CMDARG, args, -1);
+ if (eval_to_bool(p_pexpr, &err, NULL, FALSE))
+ err = TRUE;
+ set_vim_var_string(VV_FNAME_IN, NULL, -1);
+ set_vim_var_string(VV_CMDARG, NULL, -1);
+
+ if (err)
+ {
+ mch_remove(fname);
+ return FAIL;
+ }
+ return OK;
+}
+# endif
+
+# if defined(FEAT_DIFF) || defined(PROTO)
+ void
+eval_diff(
+ char_u *origfile,
+ char_u *newfile,
+ char_u *outfile)
+{
+ int err = FALSE;
+
+ set_vim_var_string(VV_FNAME_IN, origfile, -1);
+ set_vim_var_string(VV_FNAME_NEW, newfile, -1);
+ set_vim_var_string(VV_FNAME_OUT, outfile, -1);
+ (void)eval_to_bool(p_dex, &err, NULL, FALSE);
+ set_vim_var_string(VV_FNAME_IN, NULL, -1);
+ set_vim_var_string(VV_FNAME_NEW, NULL, -1);
+ set_vim_var_string(VV_FNAME_OUT, NULL, -1);
+}
+
+ void
+eval_patch(
+ char_u *origfile,
+ char_u *difffile,
+ char_u *outfile)
+{
+ int err;
+
+ set_vim_var_string(VV_FNAME_IN, origfile, -1);
+ set_vim_var_string(VV_FNAME_DIFF, difffile, -1);
+ set_vim_var_string(VV_FNAME_OUT, outfile, -1);
+ (void)eval_to_bool(p_pex, &err, NULL, FALSE);
+ set_vim_var_string(VV_FNAME_IN, NULL, -1);
+ set_vim_var_string(VV_FNAME_DIFF, NULL, -1);
+ set_vim_var_string(VV_FNAME_OUT, NULL, -1);
+}
+# endif
+
+/*
+ * Top level evaluation function, returning a boolean.
+ * Sets "error" to TRUE if there was an error.
+ * Return TRUE or FALSE.
+ */
+ int
+eval_to_bool(
+ char_u *arg,
+ int *error,
+ char_u **nextcmd,
+ int skip) /* only parse, don't execute */
+{
+ typval_T tv;
+ varnumber_T retval = FALSE;
+
+ if (skip)
+ ++emsg_skip;
+ if (eval0(arg, &tv, nextcmd, !skip) == FAIL)
+ *error = TRUE;
+ else
+ {
+ *error = FALSE;
+ if (!skip)
+ {
+ retval = (tv_get_number_chk(&tv, error) != 0);
+ clear_tv(&tv);
+ }
+ }
+ if (skip)
+ --emsg_skip;
+
+ return (int)retval;
+}
+
+/*
+ * Call eval1() and give an error message if not done at a lower level.
+ */
+ static int
+eval1_emsg(char_u **arg, typval_T *rettv, int evaluate)
+{
+ char_u *start = *arg;
+ int ret;
+ int did_emsg_before = did_emsg;
+ int called_emsg_before = called_emsg;
+
+ ret = eval1(arg, rettv, evaluate);
+ if (ret == FAIL)
+ {
+ // Report the invalid expression unless the expression evaluation has
+ // been cancelled due to an aborting error, an interrupt, or an
+ // exception, or we already gave a more specific error.
+ // Also check called_emsg for when using assert_fails().
+ if (!aborting() && did_emsg == did_emsg_before
+ && called_emsg == called_emsg_before)
+ semsg(_(e_invexpr2), start);
+ }
+ return ret;
+}
+
+ static int
+eval_expr_typval(typval_T *expr, typval_T *argv, int argc, typval_T *rettv)
+{
+ char_u *s;
+ int dummy;
+ char_u buf[NUMBUFLEN];
+
+ if (expr->v_type == VAR_FUNC)
+ {
+ s = expr->vval.v_string;
+ if (s == NULL || *s == NUL)
+ return FAIL;
+ if (call_func(s, (int)STRLEN(s), rettv, argc, argv, NULL,
+ 0L, 0L, &dummy, TRUE, NULL, NULL) == FAIL)
+ return FAIL;
+ }
+ else if (expr->v_type == VAR_PARTIAL)
+ {
+ partial_T *partial = expr->vval.v_partial;
+
+ s = partial_name(partial);
+ if (s == NULL || *s == NUL)
+ return FAIL;
+ if (call_func(s, (int)STRLEN(s), rettv, argc, argv, NULL,
+ 0L, 0L, &dummy, TRUE, partial, NULL) == FAIL)
+ return FAIL;
+ }
+ else
+ {
+ s = tv_get_string_buf_chk(expr, buf);
+ if (s == NULL)
+ return FAIL;
+ s = skipwhite(s);
+ if (eval1_emsg(&s, rettv, TRUE) == FAIL)
+ return FAIL;
+ if (*s != NUL) /* check for trailing chars after expr */
+ {
+ clear_tv(rettv);
+ semsg(_(e_invexpr2), s);
+ return FAIL;
+ }
+ }
+ return OK;
+}
+
+/*
+ * Like eval_to_bool() but using a typval_T instead of a string.
+ * Works for string, funcref and partial.
+ */
+ int
+eval_expr_to_bool(typval_T *expr, int *error)
+{
+ typval_T rettv;
+ int res;
+
+ if (eval_expr_typval(expr, NULL, 0, &rettv) == FAIL)
+ {
+ *error = TRUE;
+ return FALSE;
+ }
+ res = (tv_get_number_chk(&rettv, error) != 0);
+ clear_tv(&rettv);
+ return res;
+}
+
+/*
+ * Top level evaluation function, returning a string. If "skip" is TRUE,
+ * only parsing to "nextcmd" is done, without reporting errors. Return
+ * pointer to allocated memory, or NULL for failure or when "skip" is TRUE.
+ */
+ char_u *
+eval_to_string_skip(
+ char_u *arg,
+ char_u **nextcmd,
+ int skip) /* only parse, don't execute */
+{
+ typval_T tv;
+ char_u *retval;
+
+ if (skip)
+ ++emsg_skip;
+ if (eval0(arg, &tv, nextcmd, !skip) == FAIL || skip)
+ retval = NULL;
+ else
+ {
+ retval = vim_strsave(tv_get_string(&tv));
+ clear_tv(&tv);
+ }
+ if (skip)
+ --emsg_skip;
+
+ return retval;
+}
+
+/*
+ * Skip over an expression at "*pp".
+ * Return FAIL for an error, OK otherwise.
+ */
+ int
+skip_expr(char_u **pp)
+{
+ typval_T rettv;
+
+ *pp = skipwhite(*pp);
+ return eval1(pp, &rettv, FALSE);
+}
+
+/*
+ * Top level evaluation function, returning a string.
+ * When "convert" is TRUE convert a List into a sequence of lines and convert
+ * a Float to a String.
+ * Return pointer to allocated memory, or NULL for failure.
+ */
+ char_u *
+eval_to_string(
+ char_u *arg,
+ char_u **nextcmd,
+ int convert)
+{
+ typval_T tv;
+ char_u *retval;
+ garray_T ga;
+#ifdef FEAT_FLOAT
+ char_u numbuf[NUMBUFLEN];
+#endif
+
+ if (eval0(arg, &tv, nextcmd, TRUE) == FAIL)
+ retval = NULL;
+ else
+ {
+ if (convert && tv.v_type == VAR_LIST)
+ {
+ ga_init2(&ga, (int)sizeof(char), 80);
+ if (tv.vval.v_list != NULL)
+ {
+ list_join(&ga, tv.vval.v_list, (char_u *)"\n", TRUE, FALSE, 0);
+ if (tv.vval.v_list->lv_len > 0)
+ ga_append(&ga, NL);
+ }
+ ga_append(&ga, NUL);
+ retval = (char_u *)ga.ga_data;
+ }
+#ifdef FEAT_FLOAT
+ else if (convert && tv.v_type == VAR_FLOAT)
+ {
+ vim_snprintf((char *)numbuf, NUMBUFLEN, "%g", tv.vval.v_float);
+ retval = vim_strsave(numbuf);
+ }
+#endif
+ else
+ retval = vim_strsave(tv_get_string(&tv));
+ clear_tv(&tv);
+ }
+
+ return retval;
+}
+
+/*
+ * Call eval_to_string() without using current local variables and using
+ * textlock. When "use_sandbox" is TRUE use the sandbox.
+ */
+ char_u *
+eval_to_string_safe(
+ char_u *arg,
+ char_u **nextcmd,
+ int use_sandbox)
+{
+ char_u *retval;
+ funccal_entry_T funccal_entry;
+
+ save_funccal(&funccal_entry);
+ if (use_sandbox)
+ ++sandbox;
+ ++textlock;
+ retval = eval_to_string(arg, nextcmd, FALSE);
+ if (use_sandbox)
+ --sandbox;
+ --textlock;
+ restore_funccal();
+ return retval;
+}
+
+/*
+ * Top level evaluation function, returning a number.
+ * Evaluates "expr" silently.
+ * Returns -1 for an error.
+ */
+ varnumber_T
+eval_to_number(char_u *expr)
+{
+ typval_T rettv;
+ varnumber_T retval;
+ char_u *p = skipwhite(expr);
+
+ ++emsg_off;
+
+ if (eval1(&p, &rettv, TRUE) == FAIL)
+ retval = -1;
+ else
+ {
+ retval = tv_get_number_chk(&rettv, NULL);
+ clear_tv(&rettv);
+ }
+ --emsg_off;
+
+ return retval;
+}
+
+/*
+ * Prepare v: variable "idx" to be used.
+ * Save the current typeval in "save_tv".
+ * When not used yet add the variable to the v: hashtable.
+ */
+ static void
+prepare_vimvar(int idx, typval_T *save_tv)
+{
+ *save_tv = vimvars[idx].vv_tv;
+ if (vimvars[idx].vv_type == VAR_UNKNOWN)
+ hash_add(&vimvarht, vimvars[idx].vv_di.di_key);
+}
+
+/*
+ * Restore v: variable "idx" to typeval "save_tv".
+ * When no longer defined, remove the variable from the v: hashtable.
+ */
+ static void
+restore_vimvar(int idx, typval_T *save_tv)
+{
+ hashitem_T *hi;
+
+ vimvars[idx].vv_tv = *save_tv;
+ if (vimvars[idx].vv_type == VAR_UNKNOWN)
+ {
+ hi = hash_find(&vimvarht, vimvars[idx].vv_di.di_key);
+ if (HASHITEM_EMPTY(hi))
+ internal_error("restore_vimvar()");
+ else
+ hash_remove(&vimvarht, hi);
+ }
+}
+
+#if defined(FEAT_SPELL) || defined(PROTO)
+/*
+ * Evaluate an expression to a list with suggestions.
+ * For the "expr:" part of 'spellsuggest'.
+ * Returns NULL when there is an error.
+ */
+ list_T *
+eval_spell_expr(char_u *badword, char_u *expr)
+{
+ typval_T save_val;
+ typval_T rettv;
+ list_T *list = NULL;
+ char_u *p = skipwhite(expr);
+
+ /* Set "v:val" to the bad word. */
+ prepare_vimvar(VV_VAL, &save_val);
+ vimvars[VV_VAL].vv_type = VAR_STRING;
+ vimvars[VV_VAL].vv_str = badword;
+ if (p_verbose == 0)
+ ++emsg_off;
+
+ if (eval1(&p, &rettv, TRUE) == OK)
+ {
+ if (rettv.v_type != VAR_LIST)
+ clear_tv(&rettv);
+ else
+ list = rettv.vval.v_list;
+ }
+
+ if (p_verbose == 0)
+ --emsg_off;
+ restore_vimvar(VV_VAL, &save_val);
+
+ return list;
+}
+
+/*
+ * "list" is supposed to contain two items: a word and a number. Return the
+ * word in "pp" and the number as the return value.
+ * Return -1 if anything isn't right.
+ * Used to get the good word and score from the eval_spell_expr() result.
+ */
+ int
+get_spellword(list_T *list, char_u **pp)
+{
+ listitem_T *li;
+
+ li = list->lv_first;
+ if (li == NULL)
+ return -1;
+ *pp = tv_get_string(&li->li_tv);
+
+ li = li->li_next;
+ if (li == NULL)
+ return -1;
+ return (int)tv_get_number(&li->li_tv);
+}
+#endif
+
+/*
+ * Top level evaluation function.
+ * Returns an allocated typval_T with the result.
+ * Returns NULL when there is an error.
+ */
+ typval_T *
+eval_expr(char_u *arg, char_u **nextcmd)
+{
+ typval_T *tv;
+
+ tv = (typval_T *)alloc(sizeof(typval_T));
+ if (tv != NULL && eval0(arg, tv, nextcmd, TRUE) == FAIL)
+ VIM_CLEAR(tv);
+
+ return tv;
+}
+
+
+/*
+ * Call some Vim script function and return the result in "*rettv".
+ * Uses argv[0] to argv[argc - 1] for the function arguments. argv[argc]
+ * should have type VAR_UNKNOWN.
+ * Returns OK or FAIL.
+ */
+ int
+call_vim_function(
+ char_u *func,
+ int argc,
+ typval_T *argv,
+ typval_T *rettv)
+{
+ int doesrange;
+ int ret;
+
+ rettv->v_type = VAR_UNKNOWN; /* clear_tv() uses this */
+ ret = call_func(func, (int)STRLEN(func), rettv, argc, argv, NULL,
+ curwin->w_cursor.lnum, curwin->w_cursor.lnum,
+ &doesrange, TRUE, NULL, NULL);
+ if (ret == FAIL)
+ clear_tv(rettv);
+
+ return ret;
+}
+
+/*
+ * Call Vim script function "func" and return the result as a number.
+ * Returns -1 when calling the function fails.
+ * Uses argv[0] to argv[argc - 1] for the function arguments. argv[argc] should
+ * have type VAR_UNKNOWN.
+ */
+ varnumber_T
+call_func_retnr(
+ char_u *func,
+ int argc,
+ typval_T *argv)
+{
+ typval_T rettv;
+ varnumber_T retval;
+
+ if (call_vim_function(func, argc, argv, &rettv) == FAIL)
+ return -1;
+
+ retval = tv_get_number_chk(&rettv, NULL);
+ clear_tv(&rettv);
+ return retval;
+}
+
+#if (defined(FEAT_USR_CMDS) && defined(FEAT_CMDL_COMPL)) \
+ || defined(FEAT_COMPL_FUNC) || defined(PROTO)
+
+# if (defined(FEAT_USR_CMDS) && defined(FEAT_CMDL_COMPL)) || defined(PROTO)
+/*
+ * Call Vim script function "func" and return the result as a string.
+ * Returns NULL when calling the function fails.
+ * Uses argv[0] to argv[argc - 1] for the function arguments. argv[argc] should
+ * have type VAR_UNKNOWN.
+ */
+ void *
+call_func_retstr(
+ char_u *func,
+ int argc,
+ typval_T *argv)
+{
+ typval_T rettv;
+ char_u *retval;
+
+ if (call_vim_function(func, argc, argv, &rettv) == FAIL)
+ return NULL;
+
+ retval = vim_strsave(tv_get_string(&rettv));
+ clear_tv(&rettv);
+ return retval;
+}
+# endif
+
+/*
+ * Call Vim script function "func" and return the result as a List.
+ * Uses argv[0] to argv[argc - 1] for the function arguments. argv[argc] should
+ * have type VAR_UNKNOWN.
+ * Returns NULL when there is something wrong.
+ */
+ void *
+call_func_retlist(
+ char_u *func,
+ int argc,
+ typval_T *argv)
+{
+ typval_T rettv;
+
+ if (call_vim_function(func, argc, argv, &rettv) == FAIL)
+ return NULL;
+
+ if (rettv.v_type != VAR_LIST)
+ {
+ clear_tv(&rettv);
+ return NULL;
+ }
+
+ return rettv.vval.v_list;
+}
+#endif
+
+
+#ifdef FEAT_FOLDING
+/*
+ * Evaluate 'foldexpr'. Returns the foldlevel, and any character preceding
+ * it in "*cp". Doesn't give error messages.
+ */
+ int
+eval_foldexpr(char_u *arg, int *cp)
+{
+ typval_T tv;
+ varnumber_T retval;
+ char_u *s;
+ int use_sandbox = was_set_insecurely((char_u *)"foldexpr",
+ OPT_LOCAL);
+
+ ++emsg_off;
+ if (use_sandbox)
+ ++sandbox;
+ ++textlock;
+ *cp = NUL;
+ if (eval0(arg, &tv, NULL, TRUE) == FAIL)
+ retval = 0;
+ else
+ {
+ /* If the result is a number, just return the number. */
+ if (tv.v_type == VAR_NUMBER)
+ retval = tv.vval.v_number;
+ else if (tv.v_type != VAR_STRING || tv.vval.v_string == NULL)
+ retval = 0;
+ else
+ {
+ /* If the result is a string, check if there is a non-digit before
+ * the number. */
+ s = tv.vval.v_string;
+ if (!VIM_ISDIGIT(*s) && *s != '-')
+ *cp = *s++;
+ retval = atol((char *)s);
+ }
+ clear_tv(&tv);
+ }
+ --emsg_off;
+ if (use_sandbox)
+ --sandbox;
+ --textlock;
+
+ return (int)retval;
+}
+#endif
+
+/*
+ * ":let" list all variable values
+ * ":let var1 var2" list variable values
+ * ":let var = expr" assignment command.
+ * ":let var += expr" assignment command.
+ * ":let var -= expr" assignment command.
+ * ":let var .= expr" assignment command.
+ * ":let [var1, var2] = expr" unpack list.
+ */
+ void
+ex_let(exarg_T *eap)
+{
+ char_u *arg = eap->arg;
+ char_u *expr = NULL;
+ typval_T rettv;
+ int i;
+ int var_count = 0;
+ int semicolon = 0;
+ char_u op[2];
+ char_u *argend;
+ int first = TRUE;
+
+ argend = skip_var_list(arg, &var_count, &semicolon);
+ if (argend == NULL)
+ return;
+ if (argend > arg && argend[-1] == '.') /* for var.='str' */
+ --argend;
+ expr = skipwhite(argend);
+ if (*expr != '=' && !(vim_strchr((char_u *)"+-.", *expr) != NULL
+ && expr[1] == '='))
+ {
+ /*
+ * ":let" without "=": list variables
+ */
+ if (*arg == '[')
+ emsg(_(e_invarg));
+ else if (!ends_excmd(*arg))
+ /* ":let var1 var2" */
+ arg = list_arg_vars(eap, arg, &first);
+ else if (!eap->skip)
+ {
+ /* ":let" */
+ list_glob_vars(&first);
+ list_buf_vars(&first);
+ list_win_vars(&first);
+ list_tab_vars(&first);
+ list_script_vars(&first);
+ list_func_vars(&first);
+ list_vim_vars(&first);
+ }
+ eap->nextcmd = check_nextcmd(arg);
+ }
+ else
+ {
+ op[0] = '=';
+ op[1] = NUL;
+ if (*expr != '=')
+ {
+ if (vim_strchr((char_u *)"+-.", *expr) != NULL)
+ op[0] = *expr; /* +=, -= or .= */
+ expr = skipwhite(expr + 2);
+ }
+ else
+ expr = skipwhite(expr + 1);
+
+ if (eap->skip)
+ ++emsg_skip;
+ i = eval0(expr, &rettv, &eap->nextcmd, !eap->skip);
+ if (eap->skip)
+ {
+ if (i != FAIL)
+ clear_tv(&rettv);
+ --emsg_skip;
+ }
+ else if (i != FAIL)
+ {
+ (void)ex_let_vars(eap->arg, &rettv, FALSE, semicolon, var_count,
+ op);
+ clear_tv(&rettv);
+ }
+ }
+}
+
+/*
+ * Assign the typevalue "tv" to the variable or variables at "arg_start".
+ * Handles both "var" with any type and "[var, var; var]" with a list type.
+ * When "nextchars" is not NULL it points to a string with characters that
+ * must appear after the variable(s). Use "+", "-" or "." for add, subtract
+ * or concatenate.
+ * Returns OK or FAIL;
+ */
+ static int
+ex_let_vars(
+ char_u *arg_start,
+ typval_T *tv,
+ int copy, /* copy values from "tv", don't move */
+ int semicolon, /* from skip_var_list() */
+ int var_count, /* from skip_var_list() */
+ char_u *nextchars)
+{
+ char_u *arg = arg_start;
+ list_T *l;
+ int i;
+ listitem_T *item;
+ typval_T ltv;
+
+ if (*arg != '[')
+ {
+ /*
+ * ":let var = expr" or ":for var in list"
+ */
+ if (ex_let_one(arg, tv, copy, nextchars, nextchars) == NULL)
+ return FAIL;
+ return OK;
+ }
+
+ /*
+ * ":let [v1, v2] = list" or ":for [v1, v2] in listlist"
+ */
+ if (tv->v_type != VAR_LIST || (l = tv->vval.v_list) == NULL)
+ {
+ emsg(_(e_listreq));
+ return FAIL;
+ }
+
+ i = list_len(l);
+ if (semicolon == 0 && var_count < i)
+ {
+ emsg(_("E687: Less targets than List items"));
+ return FAIL;
+ }
+ if (var_count - semicolon > i)
+ {
+ emsg(_("E688: More targets than List items"));
+ return FAIL;
+ }
+
+ item = l->lv_first;
+ while (*arg != ']')
+ {
+ arg = skipwhite(arg + 1);
+ arg = ex_let_one(arg, &item->li_tv, TRUE, (char_u *)",;]", nextchars);
+ item = item->li_next;
+ if (arg == NULL)
+ return FAIL;
+
+ arg = skipwhite(arg);
+ if (*arg == ';')
+ {
+ /* Put the rest of the list (may be empty) in the var after ';'.
+ * Create a new list for this. */
+ l = list_alloc();
+ if (l == NULL)
+ return FAIL;
+ while (item != NULL)
+ {
+ list_append_tv(l, &item->li_tv);
+ item = item->li_next;
+ }
+
+ ltv.v_type = VAR_LIST;
+ ltv.v_lock = 0;
+ ltv.vval.v_list = l;
+ l->lv_refcount = 1;
+
+ arg = ex_let_one(skipwhite(arg + 1), &ltv, FALSE,
+ (char_u *)"]", nextchars);
+ clear_tv(&ltv);
+ if (arg == NULL)
+ return FAIL;
+ break;
+ }
+ else if (*arg != ',' && *arg != ']')
+ {
+ internal_error("ex_let_vars()");
+ return FAIL;
+ }
+ }
+
+ return OK;
+}
+
+/*
+ * Skip over assignable variable "var" or list of variables "[var, var]".
+ * Used for ":let varvar = expr" and ":for varvar in expr".
+ * For "[var, var]" increment "*var_count" for each variable.
+ * for "[var, var; var]" set "semicolon".
+ * Return NULL for an error.
+ */
+ static char_u *
+skip_var_list(
+ char_u *arg,
+ int *var_count,
+ int *semicolon)
+{
+ char_u *p, *s;
+
+ if (*arg == '[')
+ {
+ /* "[var, var]": find the matching ']'. */
+ p = arg;
+ for (;;)
+ {
+ p = skipwhite(p + 1); /* skip whites after '[', ';' or ',' */
+ s = skip_var_one(p);
+ if (s == p)
+ {
+ semsg(_(e_invarg2), p);
+ return NULL;
+ }
+ ++*var_count;
+
+ p = skipwhite(s);
+ if (*p == ']')
+ break;
+ else if (*p == ';')
+ {
+ if (*semicolon == 1)
+ {
+ emsg(_("Double ; in list of variables"));
+ return NULL;
+ }
+ *semicolon = 1;
+ }
+ else if (*p != ',')
+ {
+ semsg(_(e_invarg2), p);
+ return NULL;
+ }
+ }
+ return p + 1;
+ }
+ else
+ return skip_var_one(arg);
+}
+
+/*
+ * Skip one (assignable) variable name, including @r, $VAR, &option, d.key,
+ * l[idx].
+ */
+ static char_u *
+skip_var_one(char_u *arg)
+{
+ if (*arg == '@' && arg[1] != NUL)
+ return arg + 2;
+ return find_name_end(*arg == '$' || *arg == '&' ? arg + 1 : arg,
+ NULL, NULL, FNE_INCL_BR | FNE_CHECK_START);
+}
+
+/*
+ * List variables for hashtab "ht" with prefix "prefix".
+ * If "empty" is TRUE also list NULL strings as empty strings.
+ */
+ void
+list_hashtable_vars(
+ hashtab_T *ht,
+ char *prefix,
+ int empty,
+ int *first)
+{
+ hashitem_T *hi;
+ dictitem_T *di;
+ int todo;
+ char_u buf[IOSIZE];
+
+ todo = (int)ht->ht_used;
+ for (hi = ht->ht_array; todo > 0 && !got_int; ++hi)
+ {
+ if (!HASHITEM_EMPTY(hi))
+ {
+ --todo;
+ di = HI2DI(hi);
+
+ // apply :filter /pat/ to variable name
+ vim_strncpy((char_u *)buf, (char_u *)prefix, IOSIZE - 1);
+ vim_strcat((char_u *)buf, di->di_key, IOSIZE);
+ if (message_filtered(buf))
+ continue;
+
+ if (empty || di->di_tv.v_type != VAR_STRING
+ || di->di_tv.vval.v_string != NULL)
+ list_one_var(di, prefix, first);
+ }
+ }
+}
+
+/*
+ * List global variables.
+ */
+ static void
+list_glob_vars(int *first)
+{
+ list_hashtable_vars(&globvarht, "", TRUE, first);
+}
+
+/*
+ * List buffer variables.
+ */
+ static void
+list_buf_vars(int *first)
+{
+ list_hashtable_vars(&curbuf->b_vars->dv_hashtab, "b:", TRUE, first);
+}
+
+/*
+ * List window variables.
+ */
+ static void
+list_win_vars(int *first)
+{
+ list_hashtable_vars(&curwin->w_vars->dv_hashtab, "w:", TRUE, first);
+}
+
+/*
+ * List tab page variables.
+ */
+ static void
+list_tab_vars(int *first)
+{
+ list_hashtable_vars(&curtab->tp_vars->dv_hashtab, "t:", TRUE, first);
+}
+
+/*
+ * List Vim variables.
+ */
+ static void
+list_vim_vars(int *first)
+{
+ list_hashtable_vars(&vimvarht, "v:", FALSE, first);
+}
+
+/*
+ * List script-local variables, if there is a script.
+ */
+ static void
+list_script_vars(int *first)
+{
+ if (current_sctx.sc_sid > 0 && current_sctx.sc_sid <= ga_scripts.ga_len)
+ list_hashtable_vars(&SCRIPT_VARS(current_sctx.sc_sid),
+ "s:", FALSE, first);
+}
+
+/*
+ * List variables in "arg".
+ */
+ static char_u *
+list_arg_vars(exarg_T *eap, char_u *arg, int *first)
+{
+ int error = FALSE;
+ int len;
+ char_u *name;
+ char_u *name_start;
+ char_u *arg_subsc;
+ char_u *tofree;
+ typval_T tv;
+
+ while (!ends_excmd(*arg) && !got_int)
+ {
+ if (error || eap->skip)
+ {
+ arg = find_name_end(arg, NULL, NULL, FNE_INCL_BR | FNE_CHECK_START);
+ if (!VIM_ISWHITE(*arg) && !ends_excmd(*arg))
+ {
+ emsg_severe = TRUE;
+ emsg(_(e_trailing));
+ break;
+ }
+ }
+ else
+ {
+ /* get_name_len() takes care of expanding curly braces */
+ name_start = name = arg;
+ len = get_name_len(&arg, &tofree, TRUE, TRUE);
+ if (len <= 0)
+ {
+ /* This is mainly to keep test 49 working: when expanding
+ * curly braces fails overrule the exception error message. */
+ if (len < 0 && !aborting())
+ {
+ emsg_severe = TRUE;
+ semsg(_(e_invarg2), arg);
+ break;
+ }
+ error = TRUE;
+ }
+ else
+ {
+ if (tofree != NULL)
+ name = tofree;
+ if (get_var_tv(name, len, &tv, NULL, TRUE, FALSE) == FAIL)
+ error = TRUE;
+ else
+ {
+ /* handle d.key, l[idx], f(expr) */
+ arg_subsc = arg;
+ if (handle_subscript(&arg, &tv, TRUE, TRUE) == FAIL)
+ error = TRUE;
+ else
+ {
+ if (arg == arg_subsc && len == 2 && name[1] == ':')
+ {
+ switch (*name)
+ {
+ case 'g': list_glob_vars(first); break;
+ case 'b': list_buf_vars(first); break;
+ case 'w': list_win_vars(first); break;
+ case 't': list_tab_vars(first); break;
+ case 'v': list_vim_vars(first); break;
+ case 's': list_script_vars(first); break;
+ case 'l': list_func_vars(first); break;
+ default:
+ semsg(_("E738: Can't list variables for %s"), name);
+ }
+ }
+ else
+ {
+ char_u numbuf[NUMBUFLEN];
+ char_u *tf;
+ int c;
+ char_u *s;
+
+ s = echo_string(&tv, &tf, numbuf, 0);
+ c = *arg;
+ *arg = NUL;
+ list_one_var_a("",
+ arg == arg_subsc ? name : name_start,
+ tv.v_type,
+ s == NULL ? (char_u *)"" : s,
+ first);
+ *arg = c;
+ vim_free(tf);
+ }
+ clear_tv(&tv);
+ }
+ }
+ }
+
+ vim_free(tofree);
+ }
+
+ arg = skipwhite(arg);
+ }
+
+ return arg;
+}
+
+/*
+ * Set one item of ":let var = expr" or ":let [v1, v2] = list" to its value.
+ * Returns a pointer to the char just after the var name.
+ * Returns NULL if there is an error.
+ */
+ static char_u *
+ex_let_one(
+ char_u *arg, /* points to variable name */
+ typval_T *tv, /* value to assign to variable */
+ int copy, /* copy value from "tv" */
+ char_u *endchars, /* valid chars after variable name or NULL */
+ char_u *op) /* "+", "-", "." or NULL*/
+{
+ int c1;
+ char_u *name;
+ char_u *p;
+ char_u *arg_end = NULL;
+ int len;
+ int opt_flags;
+ char_u *tofree = NULL;
+
+ /*
+ * ":let $VAR = expr": Set environment variable.
+ */
+ if (*arg == '$')
+ {
+ /* Find the end of the name. */
+ ++arg;
+ name = arg;
+ len = get_env_len(&arg);
+ if (len == 0)
+ semsg(_(e_invarg2), name - 1);
+ else
+ {
+ if (op != NULL && (*op == '+' || *op == '-'))
+ semsg(_(e_letwrong), op);
+ else if (endchars != NULL
+ && vim_strchr(endchars, *skipwhite(arg)) == NULL)
+ emsg(_(e_letunexp));
+ else if (!check_secure())
+ {
+ c1 = name[len];
+ name[len] = NUL;
+ p = tv_get_string_chk(tv);
+ if (p != NULL && op != NULL && *op == '.')
+ {
+ int mustfree = FALSE;
+ char_u *s = vim_getenv(name, &mustfree);
+
+ if (s != NULL)
+ {
+ p = tofree = concat_str(s, p);
+ if (mustfree)
+ vim_free(s);
+ }
+ }
+ if (p != NULL)
+ {
+ vim_setenv(name, p);
+ if (STRICMP(name, "HOME") == 0)
+ init_homedir();
+ else if (didset_vim && STRICMP(name, "VIM") == 0)
+ didset_vim = FALSE;
+ else if (didset_vimruntime
+ && STRICMP(name, "VIMRUNTIME") == 0)
+ didset_vimruntime = FALSE;
+ arg_end = arg;
+ }
+ name[len] = c1;
+ vim_free(tofree);
+ }
+ }
+ }
+
+ /*
+ * ":let &option = expr": Set option value.
+ * ":let &l:option = expr": Set local option value.
+ * ":let &g:option = expr": Set global option value.
+ */
+ else if (*arg == '&')
+ {
+ /* Find the end of the name. */
+ p = find_option_end(&arg, &opt_flags);
+ if (p == NULL || (endchars != NULL
+ && vim_strchr(endchars, *skipwhite(p)) == NULL))
+ emsg(_(e_letunexp));
+ else
+ {
+ long n;
+ int opt_type;
+ long numval;
+ char_u *stringval = NULL;
+ char_u *s;
+
+ c1 = *p;
+ *p = NUL;
+
+ n = (long)tv_get_number(tv);
+ s = tv_get_string_chk(tv); /* != NULL if number or string */
+ if (s != NULL && op != NULL && *op != '=')
+ {
+ opt_type = get_option_value(arg, &numval,
+ &stringval, opt_flags);
+ if ((opt_type == 1 && *op == '.')
+ || (opt_type == 0 && *op != '.'))
+ {
+ semsg(_(e_letwrong), op);
+ s = NULL; /* don't set the value */
+ }
+ else
+ {
+ if (opt_type == 1) /* number */
+ {
+ if (*op == '+')
+ n = numval + n;
+ else
+ n = numval - n;
+ }
+ else if (opt_type == 0 && stringval != NULL) /* string */
+ {
+ s = concat_str(stringval, s);
+ vim_free(stringval);
+ stringval = s;
+ }
+ }
+ }
+ if (s != NULL)
+ {
+ set_option_value(arg, n, s, opt_flags);
+ arg_end = p;
+ }
+ *p = c1;
+ vim_free(stringval);
+ }
+ }
+
+ /*
+ * ":let @r = expr": Set register contents.
+ */
+ else if (*arg == '@')
+ {
+ ++arg;
+ if (op != NULL && (*op == '+' || *op == '-'))
+ semsg(_(e_letwrong), op);
+ else if (endchars != NULL
+ && vim_strchr(endchars, *skipwhite(arg + 1)) == NULL)
+ emsg(_(e_letunexp));
+ else
+ {
+ char_u *ptofree = NULL;
+ char_u *s;
+
+ p = tv_get_string_chk(tv);
+ if (p != NULL && op != NULL && *op == '.')
+ {
+ s = get_reg_contents(*arg == '@' ? '"' : *arg, GREG_EXPR_SRC);
+ if (s != NULL)
+ {
+ p = ptofree = concat_str(s, p);
+ vim_free(s);
+ }
+ }
+ if (p != NULL)
+ {
+ write_reg_contents(*arg == '@' ? '"' : *arg, p, -1, FALSE);
+ arg_end = arg + 1;
+ }
+ vim_free(ptofree);
+ }
+ }
+
+ /*
+ * ":let var = expr": Set internal variable.
+ * ":let {expr} = expr": Idem, name made with curly braces
+ */
+ else if (eval_isnamec1(*arg) || *arg == '{')
+ {
+ lval_T lv;
+
+ p = get_lval(arg, tv, &lv, FALSE, FALSE, 0, FNE_CHECK_START);
+ if (p != NULL && lv.ll_name != NULL)
+ {
+ if (endchars != NULL && vim_strchr(endchars, *skipwhite(p)) == NULL)
+ emsg(_(e_letunexp));
+ else
+ {
+ set_var_lval(&lv, p, tv, copy, op);
+ arg_end = p;
+ }
+ }
+ clear_lval(&lv);
+ }
+
+ else
+ semsg(_(e_invarg2), arg);
+
+ return arg_end;
+}
+
+/*
+ * Get an lval: variable, Dict item or List item that can be assigned a value
+ * to: "name", "na{me}", "name[expr]", "name[expr:expr]", "name[expr][expr]",
+ * "name.key", "name.key[expr]" etc.
+ * Indexing only works if "name" is an existing List or Dictionary.
+ * "name" points to the start of the name.
+ * If "rettv" is not NULL it points to the value to be assigned.
+ * "unlet" is TRUE for ":unlet": slightly different behavior when something is
+ * wrong; must end in space or cmd separator.
+ *
+ * flags:
+ * GLV_QUIET: do not give error messages
+ * GLV_READ_ONLY: will not change the variable
+ * GLV_NO_AUTOLOAD: do not use script autoloading
+ *
+ * Returns a pointer to just after the name, including indexes.
+ * When an evaluation error occurs "lp->ll_name" is NULL;
+ * Returns NULL for a parsing error. Still need to free items in "lp"!
+ */
+ char_u *
+get_lval(
+ char_u *name,
+ typval_T *rettv,
+ lval_T *lp,
+ int unlet,
+ int skip,
+ int flags, /* GLV_ values */
+ int fne_flags) /* flags for find_name_end() */
+{
+ char_u *p;
+ char_u *expr_start, *expr_end;
+ int cc;
+ dictitem_T *v;
+ typval_T var1;
+ typval_T var2;
+ int empty1 = FALSE;
+ listitem_T *ni;
+ char_u *key = NULL;
+ int len;
+ hashtab_T *ht;
+ int quiet = flags & GLV_QUIET;
+
+ /* Clear everything in "lp". */
+ vim_memset(lp, 0, sizeof(lval_T));
+
+ if (skip)
+ {
+ /* When skipping just find the end of the name. */
+ lp->ll_name = name;
+ return find_name_end(name, NULL, NULL, FNE_INCL_BR | fne_flags);
+ }
+
+ /* Find the end of the name. */
+ p = find_name_end(name, &expr_start, &expr_end, fne_flags);
+ if (expr_start != NULL)
+ {
+ /* Don't expand the name when we already know there is an error. */
+ if (unlet && !VIM_ISWHITE(*p) && !ends_excmd(*p)
+ && *p != '[' && *p != '.')
+ {
+ emsg(_(e_trailing));
+ return NULL;
+ }
+
+ lp->ll_exp_name = make_expanded_name(name, expr_start, expr_end, p);
+ if (lp->ll_exp_name == NULL)
+ {
+ /* Report an invalid expression in braces, unless the
+ * expression evaluation has been cancelled due to an
+ * aborting error, an interrupt, or an exception. */
+ if (!aborting() && !quiet)
+ {
+ emsg_severe = TRUE;
+ semsg(_(e_invarg2), name);
+ return NULL;
+ }
+ }
+ lp->ll_name = lp->ll_exp_name;
+ }
+ else
+ lp->ll_name = name;
+
+ /* Without [idx] or .key we are done. */
+ if ((*p != '[' && *p != '.') || lp->ll_name == NULL)
+ return p;
+
+ cc = *p;
+ *p = NUL;
+ /* Only pass &ht when we would write to the variable, it prevents autoload
+ * as well. */
+ v = find_var(lp->ll_name, (flags & GLV_READ_ONLY) ? NULL : &ht,
+ flags & GLV_NO_AUTOLOAD);
+ if (v == NULL && !quiet)
+ semsg(_(e_undefvar), lp->ll_name);
+ *p = cc;
+ if (v == NULL)
+ return NULL;
+
+ /*
+ * Loop until no more [idx] or .key is following.
+ */
+ lp->ll_tv = &v->di_tv;
+ var1.v_type = VAR_UNKNOWN;
+ var2.v_type = VAR_UNKNOWN;
+ while (*p == '[' || (*p == '.' && lp->ll_tv->v_type == VAR_DICT))
+ {
+ if (!(lp->ll_tv->v_type == VAR_LIST && lp->ll_tv->vval.v_list != NULL)
+ && !(lp->ll_tv->v_type == VAR_DICT
+ && lp->ll_tv->vval.v_dict != NULL)
+ && !(lp->ll_tv->v_type == VAR_BLOB
+ && lp->ll_tv->vval.v_blob != NULL))
+ {
+ if (!quiet)
+ emsg(_("E689: Can only index a List, Dictionary or Blob"));
+ return NULL;
+ }
+ if (lp->ll_range)
+ {
+ if (!quiet)
+ emsg(_("E708: [:] must come last"));
+ return NULL;
+ }
+
+ len = -1;
+ if (*p == '.')
+ {
+ key = p + 1;
+ for (len = 0; ASCII_ISALNUM(key[len]) || key[len] == '_'; ++len)
+ ;
+ if (len == 0)
+ {
+ if (!quiet)
+ emsg(_(e_emptykey));
+ return NULL;
+ }
+ p = key + len;
+ }
+ else
+ {
+ /* Get the index [expr] or the first index [expr: ]. */
+ p = skipwhite(p + 1);
+ if (*p == ':')
+ empty1 = TRUE;
+ else
+ {
+ empty1 = FALSE;
+ if (eval1(&p, &var1, TRUE) == FAIL) /* recursive! */
+ return NULL;
+ if (tv_get_string_chk(&var1) == NULL)
+ {
+ /* not a number or string */
+ clear_tv(&var1);
+ return NULL;
+ }
+ }
+
+ /* Optionally get the second index [ :expr]. */
+ if (*p == ':')
+ {
+ if (lp->ll_tv->v_type == VAR_DICT)
+ {
+ if (!quiet)
+ emsg(_(e_dictrange));
+ clear_tv(&var1);
+ return NULL;
+ }
+ if (rettv != NULL
+ && !(rettv->v_type == VAR_LIST
+ && rettv->vval.v_list != NULL)
+ && !(rettv->v_type == VAR_BLOB
+ && rettv->vval.v_blob != NULL))
+ {
+ if (!quiet)
+ emsg(_("E709: [:] requires a List or Blob value"));
+ clear_tv(&var1);
+ return NULL;
+ }
+ p = skipwhite(p + 1);
+ if (*p == ']')
+ lp->ll_empty2 = TRUE;
+ else
+ {
+ lp->ll_empty2 = FALSE;
+ if (eval1(&p, &var2, TRUE) == FAIL) /* recursive! */
+ {
+ clear_tv(&var1);
+ return NULL;
+ }
+ if (tv_get_string_chk(&var2) == NULL)
+ {
+ /* not a number or string */
+ clear_tv(&var1);
+ clear_tv(&var2);
+ return NULL;
+ }
+ }
+ lp->ll_range = TRUE;
+ }
+ else
+ lp->ll_range = FALSE;
+
+ if (*p != ']')
+ {
+ if (!quiet)
+ emsg(_(e_missbrac));
+ clear_tv(&var1);
+ clear_tv(&var2);
+ return NULL;
+ }
+
+ /* Skip to past ']'. */
+ ++p;
+ }
+
+ if (lp->ll_tv->v_type == VAR_DICT)
+ {
+ if (len == -1)
+ {
+ /* "[key]": get key from "var1" */
+ key = tv_get_string_chk(&var1); /* is number or string */
+ if (key == NULL)
+ {
+ clear_tv(&var1);
+ return NULL;
+ }
+ }
+ lp->ll_list = NULL;
+ lp->ll_dict = lp->ll_tv->vval.v_dict;
+ lp->ll_di = dict_find(lp->ll_dict, key, len);
+
+ /* When assigning to a scope dictionary check that a function and
+ * variable name is valid (only variable name unless it is l: or
+ * g: dictionary). Disallow overwriting a builtin function. */
+ if (rettv != NULL && lp->ll_dict->dv_scope != 0)
+ {
+ int prevval;
+ int wrong;
+
+ if (len != -1)
+ {
+ prevval = key[len];
+ key[len] = NUL;
+ }
+ else
+ prevval = 0; /* avoid compiler warning */
+ wrong = (lp->ll_dict->dv_scope == VAR_DEF_SCOPE
+ && rettv->v_type == VAR_FUNC
+ && var_check_func_name(key, lp->ll_di == NULL))
+ || !valid_varname(key);
+ if (len != -1)
+ key[len] = prevval;
+ if (wrong)
+ return NULL;
+ }
+
+ if (lp->ll_di == NULL)
+ {
+ /* Can't add "v:" variable. */
+ if (lp->ll_dict == &vimvardict)
+ {
+ semsg(_(e_illvar), name);
+ return NULL;
+ }
+
+ /* Key does not exist in dict: may need to add it. */
+ if (*p == '[' || *p == '.' || unlet)
+ {
+ if (!quiet)
+ semsg(_(e_dictkey), key);
+ clear_tv(&var1);
+ return NULL;
+ }
+ if (len == -1)
+ lp->ll_newkey = vim_strsave(key);
+ else
+ lp->ll_newkey = vim_strnsave(key, len);
+ clear_tv(&var1);
+ if (lp->ll_newkey == NULL)
+ p = NULL;
+ break;
+ }
+ /* existing variable, need to check if it can be changed */
+ else if ((flags & GLV_READ_ONLY) == 0
+ && var_check_ro(lp->ll_di->di_flags, name, FALSE))
+ {
+ clear_tv(&var1);
+ return NULL;
+ }
+
+ clear_tv(&var1);
+ lp->ll_tv = &lp->ll_di->di_tv;
+ }
+ else if (lp->ll_tv->v_type == VAR_BLOB)
+ {
+ long bloblen = blob_len(lp->ll_tv->vval.v_blob);
+
+ /*
+ * Get the number and item for the only or first index of the List.
+ */
+ if (empty1)
+ lp->ll_n1 = 0;
+ else
+ // is number or string
+ lp->ll_n1 = (long)tv_get_number(&var1);
+ clear_tv(&var1);
+
+ if (lp->ll_n1 < 0
+ || lp->ll_n1 > bloblen
+ || (lp->ll_range && lp->ll_n1 == bloblen))
+ {
+ if (!quiet)
+ semsg(_(e_blobidx), lp->ll_n1);
+ clear_tv(&var2);
+ return NULL;
+ }
+ if (lp->ll_range && !lp->ll_empty2)
+ {
+ lp->ll_n2 = (long)tv_get_number(&var2);
+ clear_tv(&var2);
+ if (lp->ll_n2 < 0
+ || lp->ll_n2 >= bloblen
+ || lp->ll_n2 < lp->ll_n1)
+ {
+ if (!quiet)
+ semsg(_(e_blobidx), lp->ll_n2);
+ return NULL;
+ }
+ }
+ lp->ll_blob = lp->ll_tv->vval.v_blob;
+ lp->ll_tv = NULL;
+ }
+ else
+ {
+ /*
+ * Get the number and item for the only or first index of the List.
+ */
+ if (empty1)
+ lp->ll_n1 = 0;
+ else
+ /* is number or string */
+ lp->ll_n1 = (long)tv_get_number(&var1);
+ clear_tv(&var1);
+
+ lp->ll_dict = NULL;
+ lp->ll_list = lp->ll_tv->vval.v_list;
+ lp->ll_li = list_find(lp->ll_list, lp->ll_n1);
+ if (lp->ll_li == NULL)
+ {
+ if (lp->ll_n1 < 0)
+ {
+ lp->ll_n1 = 0;
+ lp->ll_li = list_find(lp->ll_list, lp->ll_n1);
+ }
+ }
+ if (lp->ll_li == NULL)
+ {
+ clear_tv(&var2);
+ if (!quiet)
+ semsg(_(e_listidx), lp->ll_n1);
+ return NULL;
+ }
+
+ /*
+ * May need to find the item or absolute index for the second
+ * index of a range.
+ * When no index given: "lp->ll_empty2" is TRUE.
+ * Otherwise "lp->ll_n2" is set to the second index.
+ */
+ if (lp->ll_range && !lp->ll_empty2)
+ {
+ lp->ll_n2 = (long)tv_get_number(&var2);
+ /* is number or string */
+ clear_tv(&var2);
+ if (lp->ll_n2 < 0)
+ {
+ ni = list_find(lp->ll_list, lp->ll_n2);
+ if (ni == NULL)
+ {
+ if (!quiet)
+ semsg(_(e_listidx), lp->ll_n2);
+ return NULL;
+ }
+ lp->ll_n2 = list_idx_of_item(lp->ll_list, ni);
+ }
+
+ /* Check that lp->ll_n2 isn't before lp->ll_n1. */
+ if (lp->ll_n1 < 0)
+ lp->ll_n1 = list_idx_of_item(lp->ll_list, lp->ll_li);
+ if (lp->ll_n2 < lp->ll_n1)
+ {
+ if (!quiet)
+ semsg(_(e_listidx), lp->ll_n2);
+ return NULL;
+ }
+ }
+
+ lp->ll_tv = &lp->ll_li->li_tv;
+ }
+ }
+
+ clear_tv(&var1);
+ return p;
+}
+
+/*
+ * Clear lval "lp" that was filled by get_lval().
+ */
+ void
+clear_lval(lval_T *lp)
+{
+ vim_free(lp->ll_exp_name);
+ vim_free(lp->ll_newkey);
+}
+
+/*
+ * Set a variable that was parsed by get_lval() to "rettv".
+ * "endp" points to just after the parsed name.
+ * "op" is NULL, "+" for "+=", "-" for "-=", "." for ".=" or "=" for "=".
+ */
+ static void
+set_var_lval(
+ lval_T *lp,
+ char_u *endp,
+ typval_T *rettv,
+ int copy,
+ char_u *op)
+{
+ int cc;
+ listitem_T *ri;
+ dictitem_T *di;
+
+ if (lp->ll_tv == NULL)
+ {
+ cc = *endp;
+ *endp = NUL;
+ if (lp->ll_blob != NULL)
+ {
+ int error = FALSE, val;
+
+ if (op != NULL && *op != '=')
+ {
+ semsg(_(e_letwrong), op);
+ return;
+ }
+
+ if (lp->ll_range && rettv->v_type == VAR_BLOB)
+ {
+ int il, ir;
+
+ if (lp->ll_empty2)
+ lp->ll_n2 = blob_len(lp->ll_blob) - 1;
+
+ if (lp->ll_n2 - lp->ll_n1 + 1 != blob_len(rettv->vval.v_blob))
+ {
+ emsg(_("E972: Blob value does not have the right number of bytes"));
+ return;
+ }
+ if (lp->ll_empty2)
+ lp->ll_n2 = blob_len(lp->ll_blob);
+
+ ir = 0;
+ for (il = lp->ll_n1; il <= lp->ll_n2; il++)
+ blob_set(lp->ll_blob, il,
+ blob_get(rettv->vval.v_blob, ir++));
+ }
+ else
+ {
+ val = (int)tv_get_number_chk(rettv, &error);
+ if (!error)
+ {
+ garray_T *gap = &lp->ll_blob->bv_ga;
+
+ // Allow for appending a byte. Setting a byte beyond
+ // the end is an error otherwise.
+ if (lp->ll_n1 < gap->ga_len
+ || (lp->ll_n1 == gap->ga_len
+ && ga_grow(&lp->ll_blob->bv_ga, 1) == OK))
+ {
+ blob_set(lp->ll_blob, lp->ll_n1, val);
+ if (lp->ll_n1 == gap->ga_len)
+ ++gap->ga_len;
+ }
+ // error for invalid range was already given in get_lval()
+ }
+ }
+ }
+ else if (op != NULL && *op != '=')
+ {
+ typval_T tv;
+
+ /* handle +=, -= and .= */
+ di = NULL;
+ if (get_var_tv(lp->ll_name, (int)STRLEN(lp->ll_name),
+ &tv, &di, TRUE, FALSE) == OK)
+ {
+ if ((di == NULL
+ || (!var_check_ro(di->di_flags, lp->ll_name, FALSE)
+ && !tv_check_lock(di->di_tv.v_lock, lp->ll_name,
+ FALSE)))
+ && tv_op(&tv, rettv, op) == OK)
+ set_var(lp->ll_name, &tv, FALSE);
+ clear_tv(&tv);
+ }
+ }
+ else
+ set_var(lp->ll_name, rettv, copy);
+ *endp = cc;
+ }
+ else if (tv_check_lock(lp->ll_newkey == NULL
+ ? lp->ll_tv->v_lock
+ : lp->ll_tv->vval.v_dict->dv_lock, lp->ll_name, FALSE))
+ ;
+ else if (lp->ll_range)
+ {
+ listitem_T *ll_li = lp->ll_li;
+ int ll_n1 = lp->ll_n1;
+
+ /*
+ * Check whether any of the list items is locked
+ */
+ for (ri = rettv->vval.v_list->lv_first; ri != NULL && ll_li != NULL; )
+ {
+ if (tv_check_lock(ll_li->li_tv.v_lock, lp->ll_name, FALSE))
+ return;
+ ri = ri->li_next;
+ if (ri == NULL || (!lp->ll_empty2 && lp->ll_n2 == ll_n1))
+ break;
+ ll_li = ll_li->li_next;
+ ++ll_n1;
+ }
+
+ /*
+ * Assign the List values to the list items.
+ */
+ for (ri = rettv->vval.v_list->lv_first; ri != NULL; )
+ {
+ if (op != NULL && *op != '=')
+ tv_op(&lp->ll_li->li_tv, &ri->li_tv, op);
+ else
+ {
+ clear_tv(&lp->ll_li->li_tv);
+ copy_tv(&ri->li_tv, &lp->ll_li->li_tv);
+ }
+ ri = ri->li_next;
+ if (ri == NULL || (!lp->ll_empty2 && lp->ll_n2 == lp->ll_n1))
+ break;
+ if (lp->ll_li->li_next == NULL)
+ {
+ /* Need to add an empty item. */
+ if (list_append_number(lp->ll_list, 0) == FAIL)
+ {
+ ri = NULL;
+ break;
+ }
+ }
+ lp->ll_li = lp->ll_li->li_next;
+ ++lp->ll_n1;
+ }
+ if (ri != NULL)
+ emsg(_("E710: List value has more items than target"));
+ else if (lp->ll_empty2
+ ? (lp->ll_li != NULL && lp->ll_li->li_next != NULL)
+ : lp->ll_n1 != lp->ll_n2)
+ emsg(_("E711: List value has not enough items"));
+ }
+ else
+ {
+ /*
+ * Assign to a List or Dictionary item.
+ */
+ if (lp->ll_newkey != NULL)
+ {
+ if (op != NULL && *op != '=')
+ {
+ semsg(_(e_letwrong), op);
+ return;
+ }
+
+ /* Need to add an item to the Dictionary. */
+ di = dictitem_alloc(lp->ll_newkey);
+ if (di == NULL)
+ return;
+ if (dict_add(lp->ll_tv->vval.v_dict, di) == FAIL)
+ {
+ vim_free(di);
+ return;
+ }
+ lp->ll_tv = &di->di_tv;
+ }
+ else if (op != NULL && *op != '=')
+ {
+ tv_op(lp->ll_tv, rettv, op);
+ return;
+ }
+ else
+ clear_tv(lp->ll_tv);
+
+ /*
+ * Assign the value to the variable or list item.
+ */
+ if (copy)
+ copy_tv(rettv, lp->ll_tv);
+ else
+ {
+ *lp->ll_tv = *rettv;
+ lp->ll_tv->v_lock = 0;
+ init_tv(rettv);
+ }
+ }
+}
+
+/*
+ * Handle "tv1 += tv2", "tv1 -= tv2" and "tv1 .= tv2"
+ * Returns OK or FAIL.
+ */
+ static int
+tv_op(typval_T *tv1, typval_T *tv2, char_u *op)
+{
+ varnumber_T n;
+ char_u numbuf[NUMBUFLEN];
+ char_u *s;
+
+ /* Can't do anything with a Funcref, Dict, v:true on the right. */
+ if (tv2->v_type != VAR_FUNC && tv2->v_type != VAR_DICT
+ && tv2->v_type != VAR_SPECIAL)
+ {
+ switch (tv1->v_type)
+ {
+ case VAR_UNKNOWN:
+ case VAR_DICT:
+ case VAR_FUNC:
+ case VAR_PARTIAL:
+ case VAR_SPECIAL:
+ case VAR_JOB:
+ case VAR_CHANNEL:
+ break;
+
+ case VAR_BLOB:
+ if (*op != '+' || tv2->v_type != VAR_BLOB)
+ break;
+ // BLOB += BLOB
+ if (tv1->vval.v_blob != NULL && tv2->vval.v_blob != NULL)
+ {
+ blob_T *b1 = tv1->vval.v_blob;
+ blob_T *b2 = tv2->vval.v_blob;
+ int i, len = blob_len(b2);
+ for (i = 0; i < len; i++)
+ ga_append(&b1->bv_ga, blob_get(b2, i));
+ }
+ return OK;
+
+ case VAR_LIST:
+ if (*op != '+' || tv2->v_type != VAR_LIST)
+ break;
+ /* List += List */
+ if (tv1->vval.v_list != NULL && tv2->vval.v_list != NULL)
+ list_extend(tv1->vval.v_list, tv2->vval.v_list, NULL);
+ return OK;
+
+ case VAR_NUMBER:
+ case VAR_STRING:
+ if (tv2->v_type == VAR_LIST)
+ break;
+ if (*op == '+' || *op == '-')
+ {
+ /* nr += nr or nr -= nr*/
+ n = tv_get_number(tv1);
+#ifdef FEAT_FLOAT
+ if (tv2->v_type == VAR_FLOAT)
+ {
+ float_T f = n;
+
+ if (*op == '+')
+ f += tv2->vval.v_float;
+ else
+ f -= tv2->vval.v_float;
+ clear_tv(tv1);
+ tv1->v_type = VAR_FLOAT;
+ tv1->vval.v_float = f;
+ }
+ else
+#endif
+ {
+ if (*op == '+')
+ n += tv_get_number(tv2);
+ else
+ n -= tv_get_number(tv2);
+ clear_tv(tv1);
+ tv1->v_type = VAR_NUMBER;
+ tv1->vval.v_number = n;
+ }
+ }
+ else
+ {
+ if (tv2->v_type == VAR_FLOAT)
+ break;
+
+ /* str .= str */
+ s = tv_get_string(tv1);
+ s = concat_str(s, tv_get_string_buf(tv2, numbuf));
+ clear_tv(tv1);
+ tv1->v_type = VAR_STRING;
+ tv1->vval.v_string = s;
+ }
+ return OK;
+
+ case VAR_FLOAT:
+#ifdef FEAT_FLOAT
+ {
+ float_T f;
+
+ if (*op == '.' || (tv2->v_type != VAR_FLOAT
+ && tv2->v_type != VAR_NUMBER
+ && tv2->v_type != VAR_STRING))
+ break;
+ if (tv2->v_type == VAR_FLOAT)
+ f = tv2->vval.v_float;
+ else
+ f = tv_get_number(tv2);
+ if (*op == '+')
+ tv1->vval.v_float += f;
+ else
+ tv1->vval.v_float -= f;
+ }
+#endif
+ return OK;
+ }
+ }
+
+ semsg(_(e_letwrong), op);
+ return FAIL;
+}
+
+/*
+ * Evaluate the expression used in a ":for var in expr" command.
+ * "arg" points to "var".
+ * Set "*errp" to TRUE for an error, FALSE otherwise;
+ * Return a pointer that holds the info. Null when there is an error.
+ */
+ void *
+eval_for_line(
+ char_u *arg,
+ int *errp,
+ char_u **nextcmdp,
+ int skip)
+{
+ forinfo_T *fi;
+ char_u *expr;
+ typval_T tv;
+ list_T *l;
+
+ *errp = TRUE; /* default: there is an error */
+
+ fi = (forinfo_T *)alloc_clear(sizeof(forinfo_T));
+ if (fi == NULL)
+ return NULL;
+
+ expr = skip_var_list(arg, &fi->fi_varcount, &fi->fi_semicolon);
+ if (expr == NULL)
+ return fi;
+
+ expr = skipwhite(expr);
+ if (expr[0] != 'i' || expr[1] != 'n' || !VIM_ISWHITE(expr[2]))
+ {
+ emsg(_("E690: Missing \"in\" after :for"));
+ return fi;
+ }
+
+ if (skip)
+ ++emsg_skip;
+ if (eval0(skipwhite(expr + 2), &tv, nextcmdp, !skip) == OK)
+ {
+ *errp = FALSE;
+ if (!skip)
+ {
+ if (tv.v_type == VAR_LIST)
+ {
+ l = tv.vval.v_list;
+ if (l == NULL)
+ {
+ // a null list is like an empty list: do nothing
+ clear_tv(&tv);
+ }
+ else
+ {
+ // No need to increment the refcount, it's already set for
+ // the list being used in "tv".
+ fi->fi_list = l;
+ list_add_watch(l, &fi->fi_lw);
+ fi->fi_lw.lw_item = l->lv_first;
+ }
+ }
+ else if (tv.v_type == VAR_BLOB)
+ {
+ fi->fi_bi = 0;
+ if (tv.vval.v_blob != NULL)
+ {
+ typval_T btv;
+
+ // Make a copy, so that the iteration still works when the
+ // blob is changed.
+ blob_copy(&tv, &btv);
+ fi->fi_blob = btv.vval.v_blob;
+ }
+ clear_tv(&tv);
+ }
+ else
+ {
+ emsg(_(e_listreq));
+ clear_tv(&tv);
+ }
+ }
+ }
+ if (skip)
+ --emsg_skip;
+
+ return fi;
+}
+
+/*
+ * Use the first item in a ":for" list. Advance to the next.
+ * Assign the values to the variable (list). "arg" points to the first one.
+ * Return TRUE when a valid item was found, FALSE when at end of list or
+ * something wrong.
+ */
+ int
+next_for_item(void *fi_void, char_u *arg)
+{
+ forinfo_T *fi = (forinfo_T *)fi_void;
+ int result;
+ listitem_T *item;
+
+ if (fi->fi_blob != NULL)
+ {
+ typval_T tv;
+
+ if (fi->fi_bi >= blob_len(fi->fi_blob))
+ return FALSE;
+ tv.v_type = VAR_NUMBER;
+ tv.v_lock = VAR_FIXED;
+ tv.vval.v_number = blob_get(fi->fi_blob, fi->fi_bi);
+ ++fi->fi_bi;
+ return ex_let_vars(arg, &tv, TRUE,
+ fi->fi_semicolon, fi->fi_varcount, NULL) == OK;
+ }
+
+ item = fi->fi_lw.lw_item;
+ if (item == NULL)
+ result = FALSE;
+ else
+ {
+ fi->fi_lw.lw_item = item->li_next;
+ result = (ex_let_vars(arg, &item->li_tv, TRUE,
+ fi->fi_semicolon, fi->fi_varcount, NULL) == OK);
+ }
+ return result;
+}
+
+/*
+ * Free the structure used to store info used by ":for".
+ */
+ void
+free_for_info(void *fi_void)
+{
+ forinfo_T *fi = (forinfo_T *)fi_void;
+
+ if (fi != NULL && fi->fi_list != NULL)
+ {
+ list_rem_watch(fi->fi_list, &fi->fi_lw);
+ list_unref(fi->fi_list);
+ }
+ if (fi != NULL && fi->fi_blob != NULL)
+ blob_unref(fi->fi_blob);
+ vim_free(fi);
+}
+
+#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
+
+ void
+set_context_for_expression(
+ expand_T *xp,
+ char_u *arg,
+ cmdidx_T cmdidx)
+{
+ int got_eq = FALSE;
+ int c;
+ char_u *p;
+
+ if (cmdidx == CMD_let)
+ {
+ xp->xp_context = EXPAND_USER_VARS;
+ if (vim_strpbrk(arg, (char_u *)"\"'+-*/%.=!?~|&$([<>,#") == NULL)
+ {
+ /* ":let var1 var2 ...": find last space. */
+ for (p = arg + STRLEN(arg); p >= arg; )
+ {
+ xp->xp_pattern = p;
+ MB_PTR_BACK(arg, p);
+ if (VIM_ISWHITE(*p))
+ break;
+ }
+ return;
+ }
+ }
+ else
+ xp->xp_context = cmdidx == CMD_call ? EXPAND_FUNCTIONS
+ : EXPAND_EXPRESSION;
+ while ((xp->xp_pattern = vim_strpbrk(arg,
+ (char_u *)"\"'+-*/%.=!?~|&$([<>,#")) != NULL)
+ {
+ c = *xp->xp_pattern;
+ if (c == '&')
+ {
+ c = xp->xp_pattern[1];
+ if (c == '&')
+ {
+ ++xp->xp_pattern;
+ xp->xp_context = cmdidx != CMD_let || got_eq
+ ? EXPAND_EXPRESSION : EXPAND_NOTHING;
+ }
+ else if (c != ' ')
+ {
+ xp->xp_context = EXPAND_SETTINGS;
+ if ((c == 'l' || c == 'g') && xp->xp_pattern[2] == ':')
+ xp->xp_pattern += 2;
+
+ }
+ }
+ else if (c == '$')
+ {
+ /* environment variable */
+ xp->xp_context = EXPAND_ENV_VARS;
+ }
+ else if (c == '=')
+ {
+ got_eq = TRUE;
+ xp->xp_context = EXPAND_EXPRESSION;
+ }
+ else if (c == '#'
+ && xp->xp_context == EXPAND_EXPRESSION)
+ {
+ /* Autoload function/variable contains '#'. */
+ break;
+ }
+ else if ((c == '<' || c == '#')
+ && xp->xp_context == EXPAND_FUNCTIONS
+ && vim_strchr(xp->xp_pattern, '(') == NULL)
+ {
+ /* Function name can start with "<SNR>" and contain '#'. */
+ break;
+ }
+ else if (cmdidx != CMD_let || got_eq)
+ {
+ if (c == '"') /* string */
+ {
+ while ((c = *++xp->xp_pattern) != NUL && c != '"')
+ if (c == '\\' && xp->xp_pattern[1] != NUL)
+ ++xp->xp_pattern;
+ xp->xp_context = EXPAND_NOTHING;
+ }
+ else if (c == '\'') /* literal string */
+ {
+ /* Trick: '' is like stopping and starting a literal string. */
+ while ((c = *++xp->xp_pattern) != NUL && c != '\'')
+ /* skip */ ;
+ xp->xp_context = EXPAND_NOTHING;
+ }
+ else if (c == '|')
+ {
+ if (xp->xp_pattern[1] == '|')
+ {
+ ++xp->xp_pattern;
+ xp->xp_context = EXPAND_EXPRESSION;
+ }
+ else
+ xp->xp_context = EXPAND_COMMANDS;
+ }
+ else
+ xp->xp_context = EXPAND_EXPRESSION;
+ }
+ else
+ /* Doesn't look like something valid, expand as an expression
+ * anyway. */
+ xp->xp_context = EXPAND_EXPRESSION;
+ arg = xp->xp_pattern;
+ if (*arg != NUL)
+ while ((c = *++arg) != NUL && (c == ' ' || c == '\t'))
+ /* skip */ ;
+ }
+ xp->xp_pattern = arg;
+}
+
+#endif /* FEAT_CMDL_COMPL */
+
+/*
+ * ":unlet[!] var1 ... " command.
+ */
+ void
+ex_unlet(exarg_T *eap)
+{
+ ex_unletlock(eap, eap->arg, 0);
+}
+
+/*
+ * ":lockvar" and ":unlockvar" commands
+ */
+ void
+ex_lockvar(exarg_T *eap)
+{
+ char_u *arg = eap->arg;
+ int deep = 2;
+
+ if (eap->forceit)
+ deep = -1;
+ else if (vim_isdigit(*arg))
+ {
+ deep = getdigits(&arg);
+ arg = skipwhite(arg);
+ }
+
+ ex_unletlock(eap, arg, deep);
+}
+
+/*
+ * ":unlet", ":lockvar" and ":unlockvar" are quite similar.
+ */
+ static void
+ex_unletlock(
+ exarg_T *eap,
+ char_u *argstart,
+ int deep)
+{
+ char_u *arg = argstart;
+ char_u *name_end;
+ int error = FALSE;
+ lval_T lv;
+
+ do
+ {
+ if (*arg == '$')
+ {
+ char_u *name = ++arg;
+
+ if (get_env_len(&arg) == 0)
+ {
+ semsg(_(e_invarg2), name - 1);
+ return;
+ }
+ vim_unsetenv(name);
+ arg = skipwhite(arg);
+ continue;
+ }
+
+ /* Parse the name and find the end. */
+ name_end = get_lval(arg, NULL, &lv, TRUE, eap->skip || error, 0,
+ FNE_CHECK_START);
+ if (lv.ll_name == NULL)
+ error = TRUE; /* error but continue parsing */
+ if (name_end == NULL || (!VIM_ISWHITE(*name_end)
+ && !ends_excmd(*name_end)))
+ {
+ if (name_end != NULL)
+ {
+ emsg_severe = TRUE;
+ emsg(_(e_trailing));
+ }
+ if (!(eap->skip || error))
+ clear_lval(&lv);
+ break;
+ }
+
+ if (!error && !eap->skip)
+ {
+ if (eap->cmdidx == CMD_unlet)
+ {
+ if (do_unlet_var(&lv, name_end, eap->forceit) == FAIL)
+ error = TRUE;
+ }
+ else
+ {
+ if (do_lock_var(&lv, name_end, deep,
+ eap->cmdidx == CMD_lockvar) == FAIL)
+ error = TRUE;
+ }
+ }
+
+ if (!eap->skip)
+ clear_lval(&lv);
+
+ arg = skipwhite(name_end);
+ } while (!ends_excmd(*arg));
+
+ eap->nextcmd = check_nextcmd(arg);
+}
+
+ static int
+do_unlet_var(
+ lval_T *lp,
+ char_u *name_end,
+ int forceit)
+{
+ int ret = OK;
+ int cc;
+
+ if (lp->ll_tv == NULL)
+ {
+ cc = *name_end;
+ *name_end = NUL;
+
+ /* Normal name or expanded name. */
+ if (do_unlet(lp->ll_name, forceit) == FAIL)
+ ret = FAIL;
+ *name_end = cc;
+ }
+ else if ((lp->ll_list != NULL
+ && tv_check_lock(lp->ll_list->lv_lock, lp->ll_name, FALSE))
+ || (lp->ll_dict != NULL
+ && tv_check_lock(lp->ll_dict->dv_lock, lp->ll_name, FALSE)))
+ return FAIL;
+ else if (lp->ll_range)
+ {
+ listitem_T *li;
+ listitem_T *ll_li = lp->ll_li;
+ int ll_n1 = lp->ll_n1;
+
+ while (ll_li != NULL && (lp->ll_empty2 || lp->ll_n2 >= ll_n1))
+ {
+ li = ll_li->li_next;
+ if (tv_check_lock(ll_li->li_tv.v_lock, lp->ll_name, FALSE))
+ return FAIL;
+ ll_li = li;
+ ++ll_n1;
+ }
+
+ /* Delete a range of List items. */
+ while (lp->ll_li != NULL && (lp->ll_empty2 || lp->ll_n2 >= lp->ll_n1))
+ {
+ li = lp->ll_li->li_next;
+ listitem_remove(lp->ll_list, lp->ll_li);
+ lp->ll_li = li;
+ ++lp->ll_n1;
+ }
+ }
+ else
+ {
+ if (lp->ll_list != NULL)
+ /* unlet a List item. */
+ listitem_remove(lp->ll_list, lp->ll_li);
+ else
+ /* unlet a Dictionary item. */
+ dictitem_remove(lp->ll_dict, lp->ll_di);
+ }
+
+ return ret;
+}
+
+/*
+ * "unlet" a variable. Return OK if it existed, FAIL if not.
+ * When "forceit" is TRUE don't complain if the variable doesn't exist.
+ */
+ int
+do_unlet(char_u *name, int forceit)
+{
+ hashtab_T *ht;
+ hashitem_T *hi;
+ char_u *varname;
+ dict_T *d;
+ dictitem_T *di;
+
+ ht = find_var_ht(name, &varname);
+ if (ht != NULL && *varname != NUL)
+ {
+ d = get_current_funccal_dict(ht);
+ if (d == NULL)
+ {
+ if (ht == &globvarht)
+ d = &globvardict;
+ else if (ht == &compat_hashtab)
+ d = &vimvardict;
+ else
+ {
+ di = find_var_in_ht(ht, *name, (char_u *)"", FALSE);
+ d = di == NULL ? NULL : di->di_tv.vval.v_dict;
+ }
+ if (d == NULL)
+ {
+ internal_error("do_unlet()");
+ return FAIL;
+ }
+ }
+ hi = hash_find(ht, varname);
+ if (HASHITEM_EMPTY(hi))
+ hi = find_hi_in_scoped_ht(name, &ht);
+ if (hi != NULL && !HASHITEM_EMPTY(hi))
+ {
+ di = HI2DI(hi);
+ if (var_check_fixed(di->di_flags, name, FALSE)
+ || var_check_ro(di->di_flags, name, FALSE)
+ || tv_check_lock(d->dv_lock, name, FALSE))
+ return FAIL;
+
+ delete_var(ht, hi);
+ return OK;
+ }
+ }
+ if (forceit)
+ return OK;
+ semsg(_("E108: No such variable: \"%s\""), name);
+ return FAIL;
+}
+
+/*
+ * Lock or unlock variable indicated by "lp".
+ * "deep" is the levels to go (-1 for unlimited);
+ * "lock" is TRUE for ":lockvar", FALSE for ":unlockvar".
+ */
+ static int
+do_lock_var(
+ lval_T *lp,
+ char_u *name_end,
+ int deep,
+ int lock)
+{
+ int ret = OK;
+ int cc;
+ dictitem_T *di;
+
+ if (deep == 0) /* nothing to do */
+ return OK;
+
+ if (lp->ll_tv == NULL)
+ {
+ cc = *name_end;
+ *name_end = NUL;
+
+ /* Normal name or expanded name. */
+ di = find_var(lp->ll_name, NULL, TRUE);
+ if (di == NULL)
+ ret = FAIL;
+ else if ((di->di_flags & DI_FLAGS_FIX)
+ && di->di_tv.v_type != VAR_DICT
+ && di->di_tv.v_type != VAR_LIST)
+ /* For historic reasons this error is not given for a list or dict.
+ * E.g., the b: dict could be locked/unlocked. */
+ semsg(_("E940: Cannot lock or unlock variable %s"), lp->ll_name);
+ else
+ {
+ if (lock)
+ di->di_flags |= DI_FLAGS_LOCK;
+ else
+ di->di_flags &= ~DI_FLAGS_LOCK;
+ item_lock(&di->di_tv, deep, lock);
+ }
+ *name_end = cc;
+ }
+ else if (lp->ll_range)
+ {
+ listitem_T *li = lp->ll_li;
+
+ /* (un)lock a range of List items. */
+ while (li != NULL && (lp->ll_empty2 || lp->ll_n2 >= lp->ll_n1))
+ {
+ item_lock(&li->li_tv, deep, lock);
+ li = li->li_next;
+ ++lp->ll_n1;
+ }
+ }
+ else if (lp->ll_list != NULL)
+ /* (un)lock a List item. */
+ item_lock(&lp->ll_li->li_tv, deep, lock);
+ else
+ /* (un)lock a Dictionary item. */
+ item_lock(&lp->ll_di->di_tv, deep, lock);
+
+ return ret;
+}
+
+/*
+ * Lock or unlock an item. "deep" is nr of levels to go.
+ */
+ static void
+item_lock(typval_T *tv, int deep, int lock)
+{
+ static int recurse = 0;
+ list_T *l;
+ listitem_T *li;
+ dict_T *d;
+ blob_T *b;
+ hashitem_T *hi;
+ int todo;
+
+ if (recurse >= DICT_MAXNEST)
+ {
+ emsg(_("E743: variable nested too deep for (un)lock"));
+ return;
+ }
+ if (deep == 0)
+ return;
+ ++recurse;
+
+ /* lock/unlock the item itself */
+ if (lock)
+ tv->v_lock |= VAR_LOCKED;
+ else
+ tv->v_lock &= ~VAR_LOCKED;
+
+ switch (tv->v_type)
+ {
+ case VAR_UNKNOWN:
+ case VAR_NUMBER:
+ case VAR_STRING:
+ case VAR_FUNC:
+ case VAR_PARTIAL:
+ case VAR_FLOAT:
+ case VAR_SPECIAL:
+ case VAR_JOB:
+ case VAR_CHANNEL:
+ break;
+
+ case VAR_BLOB:
+ if ((b = tv->vval.v_blob) != NULL)
+ {
+ if (lock)
+ b->bv_lock |= VAR_LOCKED;
+ else
+ b->bv_lock &= ~VAR_LOCKED;
+ }
+ break;
+ case VAR_LIST:
+ if ((l = tv->vval.v_list) != NULL)
+ {
+ if (lock)
+ l->lv_lock |= VAR_LOCKED;
+ else
+ l->lv_lock &= ~VAR_LOCKED;
+ if (deep < 0 || deep > 1)
+ /* recursive: lock/unlock the items the List contains */
+ for (li = l->lv_first; li != NULL; li = li->li_next)
+ item_lock(&li->li_tv, deep - 1, lock);
+ }
+ break;
+ case VAR_DICT:
+ if ((d = tv->vval.v_dict) != NULL)
+ {
+ if (lock)
+ d->dv_lock |= VAR_LOCKED;
+ else
+ d->dv_lock &= ~VAR_LOCKED;
+ if (deep < 0 || deep > 1)
+ {
+ /* recursive: lock/unlock the items the List contains */
+ todo = (int)d->dv_hashtab.ht_used;
+ for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
+ {
+ if (!HASHITEM_EMPTY(hi))
+ {
+ --todo;
+ item_lock(&HI2DI(hi)->di_tv, deep - 1, lock);
+ }
+ }
+ }
+ }
+ }
+ --recurse;
+}
+
+#if (defined(FEAT_MENU) && defined(FEAT_MULTI_LANG)) || defined(PROTO)
+/*
+ * Delete all "menutrans_" variables.
+ */
+ void
+del_menutrans_vars(void)
+{
+ hashitem_T *hi;
+ int todo;
+
+ hash_lock(&globvarht);
+ todo = (int)globvarht.ht_used;
+ for (hi = globvarht.ht_array; todo > 0 && !got_int; ++hi)
+ {
+ if (!HASHITEM_EMPTY(hi))
+ {
+ --todo;
+ if (STRNCMP(HI2DI(hi)->di_key, "menutrans_", 10) == 0)
+ delete_var(&globvarht, hi);
+ }
+ }
+ hash_unlock(&globvarht);
+}
+#endif
+
+#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
+
+/*
+ * Local string buffer for the next two functions to store a variable name
+ * with its prefix. Allocated in cat_prefix_varname(), freed later in
+ * get_user_var_name().
+ */
+
+static char_u *varnamebuf = NULL;
+static int varnamebuflen = 0;
+
+/*
+ * Function to concatenate a prefix and a variable name.
+ */
+ static char_u *
+cat_prefix_varname(int prefix, char_u *name)
+{
+ int len;
+
+ len = (int)STRLEN(name) + 3;
+ if (len > varnamebuflen)
+ {
+ vim_free(varnamebuf);
+ len += 10; /* some additional space */
+ varnamebuf = alloc(len);
+ if (varnamebuf == NULL)
+ {
+ varnamebuflen = 0;
+ return NULL;
+ }
+ varnamebuflen = len;
+ }
+ *varnamebuf = prefix;
+ varnamebuf[1] = ':';
+ STRCPY(varnamebuf + 2, name);
+ return varnamebuf;
+}
+
+/*
+ * Function given to ExpandGeneric() to obtain the list of user defined
+ * (global/buffer/window/built-in) variable names.
+ */
+ char_u *
+get_user_var_name(expand_T *xp, int idx)
+{
+ static long_u gdone;
+ static long_u bdone;
+ static long_u wdone;
+ static long_u tdone;
+ static int vidx;
+ static hashitem_T *hi;
+ hashtab_T *ht;
+
+ if (idx == 0)
+ {
+ gdone = bdone = wdone = vidx = 0;
+ tdone = 0;
+ }
+
+ /* Global variables */
+ if (gdone < globvarht.ht_used)
+ {
+ if (gdone++ == 0)
+ hi = globvarht.ht_array;
+ else
+ ++hi;
+ while (HASHITEM_EMPTY(hi))
+ ++hi;
+ if (STRNCMP("g:", xp->xp_pattern, 2) == 0)
+ return cat_prefix_varname('g', hi->hi_key);
+ return hi->hi_key;
+ }
+
+ /* b: variables */
+ ht = &curbuf->b_vars->dv_hashtab;
+ if (bdone < ht->ht_used)
+ {
+ if (bdone++ == 0)
+ hi = ht->ht_array;
+ else
+ ++hi;
+ while (HASHITEM_EMPTY(hi))
+ ++hi;
+ return cat_prefix_varname('b', hi->hi_key);
+ }
+
+ /* w: variables */
+ ht = &curwin->w_vars->dv_hashtab;
+ if (wdone < ht->ht_used)
+ {
+ if (wdone++ == 0)
+ hi = ht->ht_array;
+ else
+ ++hi;
+ while (HASHITEM_EMPTY(hi))
+ ++hi;
+ return cat_prefix_varname('w', hi->hi_key);
+ }
+
+ /* t: variables */
+ ht = &curtab->tp_vars->dv_hashtab;
+ if (tdone < ht->ht_used)
+ {
+ if (tdone++ == 0)
+ hi = ht->ht_array;
+ else
+ ++hi;
+ while (HASHITEM_EMPTY(hi))
+ ++hi;
+ return cat_prefix_varname('t', hi->hi_key);
+ }
+
+ /* v: variables */
+ if (vidx < VV_LEN)
+ return cat_prefix_varname('v', (char_u *)vimvars[vidx++].vv_name);
+
+ VIM_CLEAR(varnamebuf);
+ varnamebuflen = 0;
+ return NULL;
+}
+
+#endif /* FEAT_CMDL_COMPL */
+
+/*
+ * Return TRUE if "pat" matches "text".
+ * Does not use 'cpo' and always uses 'magic'.
+ */
+ static int
+pattern_match(char_u *pat, char_u *text, int ic)
+{
+ int matches = FALSE;
+ char_u *save_cpo;
+ regmatch_T regmatch;
+
+ /* avoid 'l' flag in 'cpoptions' */
+ save_cpo = p_cpo;
+ p_cpo = (char_u *)"";
+ regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
+ if (regmatch.regprog != NULL)
+ {
+ regmatch.rm_ic = ic;
+ matches = vim_regexec_nl(&regmatch, text, (colnr_T)0);
+ vim_regfree(regmatch.regprog);
+ }
+ p_cpo = save_cpo;
+ return matches;
+}
+
+/*
+ * The "evaluate" argument: When FALSE, the argument is only parsed but not
+ * executed. The function may return OK, but the rettv will be of type
+ * VAR_UNKNOWN. The function still returns FAIL for a syntax error.
+ */
+
+/*
+ * Handle zero level expression.
+ * This calls eval1() and handles error message and nextcmd.
+ * Put the result in "rettv" when returning OK and "evaluate" is TRUE.
+ * Note: "rettv.v_lock" is not set.
+ * Return OK or FAIL.
+ */
+ int
+eval0(
+ char_u *arg,
+ typval_T *rettv,
+ char_u **nextcmd,
+ int evaluate)
+{
+ int ret;
+ char_u *p;
+ int did_emsg_before = did_emsg;
+ int called_emsg_before = called_emsg;
+
+ p = skipwhite(arg);
+ ret = eval1(&p, rettv, evaluate);
+ if (ret == FAIL || !ends_excmd(*p))
+ {
+ if (ret != FAIL)
+ clear_tv(rettv);
+ /*
+ * Report the invalid expression unless the expression evaluation has
+ * been cancelled due to an aborting error, an interrupt, or an
+ * exception, or we already gave a more specific error.
+ * Also check called_emsg for when using assert_fails().
+ */
+ if (!aborting() && did_emsg == did_emsg_before
+ && called_emsg == called_emsg_before)
+ semsg(_(e_invexpr2), arg);
+ ret = FAIL;
+ }
+ if (nextcmd != NULL)
+ *nextcmd = check_nextcmd(p);
+
+ return ret;
+}
+
+/*
+ * Handle top level expression:
+ * expr2 ? expr1 : expr1
+ *
+ * "arg" must point to the first non-white of the expression.
+ * "arg" is advanced to the next non-white after the recognized expression.
+ *
+ * Note: "rettv.v_lock" is not set.
+ *
+ * Return OK or FAIL.
+ */
+ int
+eval1(char_u **arg, typval_T *rettv, int evaluate)
+{
+ int result;
+ typval_T var2;
+
+ /*
+ * Get the first variable.
+ */
+ if (eval2(arg, rettv, evaluate) == FAIL)
+ return FAIL;
+
+ if ((*arg)[0] == '?')
+ {
+ result = FALSE;
+ if (evaluate)
+ {
+ int error = FALSE;
+
+ if (tv_get_number_chk(rettv, &error) != 0)
+ result = TRUE;
+ clear_tv(rettv);
+ if (error)
+ return FAIL;
+ }
+
+ /*
+ * Get the second variable.
+ */
+ *arg = skipwhite(*arg + 1);
+ if (eval1(arg, rettv, evaluate && result) == FAIL) /* recursive! */
+ return FAIL;
+
+ /*
+ * Check for the ":".
+ */
+ if ((*arg)[0] != ':')
+ {
+ emsg(_("E109: Missing ':' after '?'"));
+ if (evaluate && result)
+ clear_tv(rettv);
+ return FAIL;
+ }
+
+ /*
+ * Get the third variable.
+ */
+ *arg = skipwhite(*arg + 1);
+ if (eval1(arg, &var2, evaluate && !result) == FAIL) /* recursive! */
+ {
+ if (evaluate && result)
+ clear_tv(rettv);
+ return FAIL;
+ }
+ if (evaluate && !result)
+ *rettv = var2;
+ }
+
+ return OK;
+}
+
+/*
+ * Handle first level expression:
+ * expr2 || expr2 || expr2 logical OR
+ *
+ * "arg" must point to the first non-white of the expression.
+ * "arg" is advanced to the next non-white after the recognized expression.
+ *
+ * Return OK or FAIL.
+ */
+ static int
+eval2(char_u **arg, typval_T *rettv, int evaluate)
+{
+ typval_T var2;
+ long result;
+ int first;
+ int error = FALSE;
+
+ /*
+ * Get the first variable.
+ */
+ if (eval3(arg, rettv, evaluate) == FAIL)
+ return FAIL;
+
+ /*
+ * Repeat until there is no following "||".
+ */
+ first = TRUE;
+ result = FALSE;
+ while ((*arg)[0] == '|' && (*arg)[1] == '|')
+ {
+ if (evaluate && first)
+ {
+ if (tv_get_number_chk(rettv, &error) != 0)
+ result = TRUE;
+ clear_tv(rettv);
+ if (error)
+ return FAIL;
+ first = FALSE;
+ }
+
+ /*
+ * Get the second variable.
+ */
+ *arg = skipwhite(*arg + 2);
+ if (eval3(arg, &var2, evaluate && !result) == FAIL)
+ return FAIL;
+
+ /*
+ * Compute the result.
+ */
+ if (evaluate && !result)
+ {
+ if (tv_get_number_chk(&var2, &error) != 0)
+ result = TRUE;
+ clear_tv(&var2);
+ if (error)
+ return FAIL;
+ }
+ if (evaluate)
+ {
+ rettv->v_type = VAR_NUMBER;
+ rettv->vval.v_number = result;
+ }
+ }
+
+ return OK;
+}
+
+/*
+ * Handle second level expression:
+ * expr3 && expr3 && expr3 logical AND
+ *
+ * "arg" must point to the first non-white of the expression.
+ * "arg" is advanced to the next non-white after the recognized expression.
+ *
+ * Return OK or FAIL.
+ */
+ static int
+eval3(char_u **arg, typval_T *rettv, int evaluate)
+{
+ typval_T var2;
+ long result;
+ int first;
+ int error = FALSE;
+
+ /*
+ * Get the first variable.
+ */
+ if (eval4(arg, rettv, evaluate) == FAIL)
+ return FAIL;
+
+ /*
+ * Repeat until there is no following "&&".
+ */
+ first = TRUE;
+ result = TRUE;
+ while ((*arg)[0] == '&' && (*arg)[1] == '&')
+ {
+ if (evaluate && first)
+ {
+ if (tv_get_number_chk(rettv, &error) == 0)
+ result = FALSE;
+ clear_tv(rettv);
+ if (error)
+ return FAIL;
+ first = FALSE;
+ }
+
+ /*
+ * Get the second variable.
+ */
+ *arg = skipwhite(*arg + 2);
+ if (eval4(arg, &var2, evaluate && result) == FAIL)
+ return FAIL;
+
+ /*
+ * Compute the result.
+ */
+ if (evaluate && result)
+ {
+ if (tv_get_number_chk(&var2, &error) == 0)
+ result = FALSE;
+ clear_tv(&var2);
+ if (error)
+ return FAIL;
+ }
+ if (evaluate)
+ {
+ rettv->v_type = VAR_NUMBER;
+ rettv->vval.v_number = result;
+ }
+ }
+
+ return OK;
+}
+
+/*
+ * Handle third level expression:
+ * var1 == var2
+ * var1 =~ var2
+ * var1 != var2
+ * var1 !~ var2
+ * var1 > var2
+ * var1 >= var2
+ * var1 < var2
+ * var1 <= var2
+ * var1 is var2
+ * var1 isnot var2
+ *
+ * "arg" must point to the first non-white of the expression.
+ * "arg" is advanced to the next non-white after the recognized expression.
+ *
+ * Return OK or FAIL.
+ */
+ static int
+eval4(char_u **arg, typval_T *rettv, int evaluate)
+{
+ typval_T var2;
+ char_u *p;
+ int i;
+ exptype_T type = TYPE_UNKNOWN;
+ int type_is = FALSE; /* TRUE for "is" and "isnot" */
+ int len = 2;
+ int ic;
+
+ /*
+ * Get the first variable.
+ */
+ if (eval5(arg, rettv, evaluate) == FAIL)
+ return FAIL;
+
+ p = *arg;
+ switch (p[0])
+ {
+ case '=': if (p[1] == '=')
+ type = TYPE_EQUAL;
+ else if (p[1] == '~')
+ type = TYPE_MATCH;
+ break;
+ case '!': if (p[1] == '=')
+ type = TYPE_NEQUAL;
+ else if (p[1] == '~')
+ type = TYPE_NOMATCH;
+ break;
+ case '>': if (p[1] != '=')
+ {
+ type = TYPE_GREATER;
+ len = 1;
+ }
+ else
+ type = TYPE_GEQUAL;
+ break;
+ case '<': if (p[1] != '=')
+ {
+ type = TYPE_SMALLER;
+ len = 1;
+ }
+ else
+ type = TYPE_SEQUAL;
+ break;
+ case 'i': if (p[1] == 's')
+ {
+ if (p[2] == 'n' && p[3] == 'o' && p[4] == 't')
+ len = 5;
+ i = p[len];
+ if (!isalnum(i) && i != '_')
+ {
+ type = len == 2 ? TYPE_EQUAL : TYPE_NEQUAL;
+ type_is = TRUE;
+ }
+ }
+ break;
+ }
+
+ /*
+ * If there is a comparative operator, use it.
+ */
+ if (type != TYPE_UNKNOWN)
+ {
+ /* extra question mark appended: ignore case */
+ if (p[len] == '?')
+ {
+ ic = TRUE;
+ ++len;
+ }
+ /* extra '#' appended: match case */
+ else if (p[len] == '#')
+ {
+ ic = FALSE;
+ ++len;
+ }
+ /* nothing appended: use 'ignorecase' */
+ else
+ ic = p_ic;
+
+ /*
+ * Get the second variable.
+ */
+ *arg = skipwhite(p + len);
+ if (eval5(arg, &var2, evaluate) == FAIL)
+ {
+ clear_tv(rettv);
+ return FAIL;
+ }
+ if (evaluate)
+ {
+ int ret = typval_compare(rettv, &var2, type, type_is, ic);
+
+ clear_tv(&var2);
+ return ret;
+ }
+ }
+
+ return OK;
+}
+
+/*
+ * Handle fourth level expression:
+ * + number addition
+ * - number subtraction
+ * . string concatenation
+ *
+ * "arg" must point to the first non-white of the expression.
+ * "arg" is advanced to the next non-white after the recognized expression.
+ *
+ * Return OK or FAIL.
+ */
+ static int
+eval5(char_u **arg, typval_T *rettv, int evaluate)
+{
+ typval_T var2;
+ typval_T var3;
+ int op;
+ varnumber_T n1, n2;
+#ifdef FEAT_FLOAT
+ float_T f1 = 0, f2 = 0;
+#endif
+ char_u *s1, *s2;
+ char_u buf1[NUMBUFLEN], buf2[NUMBUFLEN];
+ char_u *p;
+
+ /*
+ * Get the first variable.
+ */
+ if (eval6(arg, rettv, evaluate, FALSE) == FAIL)
+ return FAIL;
+
+ /*
+ * Repeat computing, until no '+', '-' or '.' is following.
+ */
+ for (;;)
+ {
+ op = **arg;
+ if (op != '+' && op != '-' && op != '.')
+ break;
+
+ if ((op != '+' || (rettv->v_type != VAR_LIST
+ && rettv->v_type != VAR_BLOB))
+#ifdef FEAT_FLOAT
+ && (op == '.' || rettv->v_type != VAR_FLOAT)
+#endif
+ )
+ {
+ /* For "list + ...", an illegal use of the first operand as
+ * a number cannot be determined before evaluating the 2nd
+ * operand: if this is also a list, all is ok.
+ * For "something . ...", "something - ..." or "non-list + ...",
+ * we know that the first operand needs to be a string or number
+ * without evaluating the 2nd operand. So check before to avoid
+ * side effects after an error. */
+ if (evaluate && tv_get_string_chk(rettv) == NULL)
+ {
+ clear_tv(rettv);
+ return FAIL;
+ }
+ }
+
+ /*
+ * Get the second variable.
+ */
+ *arg = skipwhite(*arg + 1);
+ if (eval6(arg, &var2, evaluate, op == '.') == FAIL)
+ {
+ clear_tv(rettv);
+ return FAIL;
+ }
+
+ if (evaluate)
+ {
+ /*
+ * Compute the result.
+ */
+ if (op == '.')
+ {
+ s1 = tv_get_string_buf(rettv, buf1); /* already checked */
+ s2 = tv_get_string_buf_chk(&var2, buf2);
+ if (s2 == NULL) /* type error ? */
+ {
+ clear_tv(rettv);
+ clear_tv(&var2);
+ return FAIL;
+ }
+ p = concat_str(s1, s2);
+ clear_tv(rettv);
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = p;
+ }
+ else if (op == '+' && rettv->v_type == VAR_BLOB
+ && var2.v_type == VAR_BLOB)
+ {
+ blob_T *b1 = rettv->vval.v_blob;
+ blob_T *b2 = var2.vval.v_blob;
+ blob_T *b = blob_alloc();
+ int i;
+
+ if (b != NULL)
+ {
+ for (i = 0; i < blob_len(b1); i++)
+ ga_append(&b->bv_ga, blob_get(b1, i));
+ for (i = 0; i < blob_len(b2); i++)
+ ga_append(&b->bv_ga, blob_get(b2, i));
+
+ clear_tv(rettv);
+ rettv_blob_set(rettv, b);
+ }
+ }
+ else if (op == '+' && rettv->v_type == VAR_LIST
+ && var2.v_type == VAR_LIST)
+ {
+ /* concatenate Lists */
+ if (list_concat(rettv->vval.v_list, var2.vval.v_list,
+ &var3) == FAIL)
+ {
+ clear_tv(rettv);
+ clear_tv(&var2);
+ return FAIL;
+ }
+ clear_tv(rettv);
+ *rettv = var3;
+ }
+ else
+ {
+ int error = FALSE;
+
+#ifdef FEAT_FLOAT
+ if (rettv->v_type == VAR_FLOAT)
+ {
+ f1 = rettv->vval.v_float;
+ n1 = 0;
+ }
+ else
+#endif
+ {
+ n1 = tv_get_number_chk(rettv, &error);
+ if (error)
+ {
+ /* This can only happen for "list + non-list". For
+ * "non-list + ..." or "something - ...", we returned
+ * before evaluating the 2nd operand. */
+ clear_tv(rettv);
+ return FAIL;
+ }
+#ifdef FEAT_FLOAT
+ if (var2.v_type == VAR_FLOAT)
+ f1 = n1;
+#endif
+ }
+#ifdef FEAT_FLOAT
+ if (var2.v_type == VAR_FLOAT)
+ {
+ f2 = var2.vval.v_float;
+ n2 = 0;
+ }
+ else
+#endif
+ {
+ n2 = tv_get_number_chk(&var2, &error);
+ if (error)
+ {
+ clear_tv(rettv);
+ clear_tv(&var2);
+ return FAIL;
+ }
+#ifdef FEAT_FLOAT
+ if (rettv->v_type == VAR_FLOAT)
+ f2 = n2;
+#endif
+ }
+ clear_tv(rettv);
+
+#ifdef FEAT_FLOAT
+ /* If there is a float on either side the result is a float. */
+ if (rettv->v_type == VAR_FLOAT || var2.v_type == VAR_FLOAT)
+ {
+ if (op == '+')
+ f1 = f1 + f2;
+ else
+ f1 = f1 - f2;
+ rettv->v_type = VAR_FLOAT;
+ rettv->vval.v_float = f1;
+ }
+ else
+#endif
+ {
+ if (op == '+')
+ n1 = n1 + n2;
+ else
+ n1 = n1 - n2;
+ rettv->v_type = VAR_NUMBER;
+ rettv->vval.v_number = n1;
+ }
+ }
+ clear_tv(&var2);
+ }
+ }
+ return OK;
+}
+
+/*
+ * Handle fifth level expression:
+ * * number multiplication
+ * / number division
+ * % number modulo
+ *
+ * "arg" must point to the first non-white of the expression.
+ * "arg" is advanced to the next non-white after the recognized expression.
+ *
+ * Return OK or FAIL.
+ */
+ static int
+eval6(
+ char_u **arg,
+ typval_T *rettv,
+ int evaluate,
+ int want_string) /* after "." operator */
+{
+ typval_T var2;
+ int op;
+ varnumber_T n1, n2;
+#ifdef FEAT_FLOAT
+ int use_float = FALSE;
+ float_T f1 = 0, f2;
+#endif
+ int error = FALSE;
+
+ /*
+ * Get the first variable.
+ */
+ if (eval7(arg, rettv, evaluate, want_string) == FAIL)
+ return FAIL;
+
+ /*
+ * Repeat computing, until no '*', '/' or '%' is following.
+ */
+ for (;;)
+ {
+ op = **arg;
+ if (op != '*' && op != '/' && op != '%')
+ break;
+
+ if (evaluate)
+ {
+#ifdef FEAT_FLOAT
+ if (rettv->v_type == VAR_FLOAT)
+ {
+ f1 = rettv->vval.v_float;
+ use_float = TRUE;
+ n1 = 0;
+ }
+ else
+#endif
+ n1 = tv_get_number_chk(rettv, &error);
+ clear_tv(rettv);
+ if (error)
+ return FAIL;
+ }
+ else
+ n1 = 0;
+
+ /*
+ * Get the second variable.
+ */
+ *arg = skipwhite(*arg + 1);
+ if (eval7(arg, &var2, evaluate, FALSE) == FAIL)
+ return FAIL;
+
+ if (evaluate)
+ {
+#ifdef FEAT_FLOAT
+ if (var2.v_type == VAR_FLOAT)
+ {
+ if (!use_float)
+ {
+ f1 = n1;
+ use_float = TRUE;
+ }
+ f2 = var2.vval.v_float;
+ n2 = 0;
+ }
+ else
+#endif
+ {
+ n2 = tv_get_number_chk(&var2, &error);
+ clear_tv(&var2);
+ if (error)
+ return FAIL;
+#ifdef FEAT_FLOAT
+ if (use_float)
+ f2 = n2;
+#endif
+ }
+
+ /*
+ * Compute the result.
+ * When either side is a float the result is a float.
+ */
+#ifdef FEAT_FLOAT
+ if (use_float)
+ {
+ if (op == '*')
+ f1 = f1 * f2;
+ else if (op == '/')
+ {
+# ifdef VMS
+ /* VMS crashes on divide by zero, work around it */
+ if (f2 == 0.0)
+ {
+ if (f1 == 0)
+ f1 = -1 * __F_FLT_MAX - 1L; /* similar to NaN */
+ else if (f1 < 0)
+ f1 = -1 * __F_FLT_MAX;
+ else
+ f1 = __F_FLT_MAX;
+ }
+ else
+ f1 = f1 / f2;
+# else
+ /* We rely on the floating point library to handle divide
+ * by zero to result in "inf" and not a crash. */
+ f1 = f1 / f2;
+# endif
+ }
+ else
+ {
+ emsg(_("E804: Cannot use '%' with Float"));
+ return FAIL;
+ }
+ rettv->v_type = VAR_FLOAT;
+ rettv->vval.v_float = f1;
+ }
+ else
+#endif
+ {
+ if (op == '*')
+ n1 = n1 * n2;
+ else if (op == '/')
+ {
+ if (n2 == 0) /* give an error message? */
+ {
+ if (n1 == 0)
+ n1 = VARNUM_MIN; /* similar to NaN */
+ else if (n1 < 0)
+ n1 = -VARNUM_MAX;
+ else
+ n1 = VARNUM_MAX;
+ }
+ else
+ n1 = n1 / n2;
+ }
+ else
+ {
+ if (n2 == 0) /* give an error message? */
+ n1 = 0;
+ else
+ n1 = n1 % n2;
+ }
+ rettv->v_type = VAR_NUMBER;
+ rettv->vval.v_number = n1;
+ }
+ }
+ }
+
+ return OK;
+}
+
+/*
+ * Handle sixth level expression:
+ * number number constant
+ * 0zFFFFFFFF Blob constant
+ * "string" string constant
+ * 'string' literal string constant
+ * &option-name option value
+ * @r register contents
+ * identifier variable value
+ * function() function call
+ * $VAR environment variable
+ * (expression) nested expression
+ * [expr, expr] List
+ * {key: val, key: val} Dictionary
+ *
+ * Also handle:
+ * ! in front logical NOT
+ * - in front unary minus
+ * + in front unary plus (ignored)
+ * trailing [] subscript in String or List
+ * trailing .name entry in Dictionary
+ *
+ * "arg" must point to the first non-white of the expression.
+ * "arg" is advanced to the next non-white after the recognized expression.
+ *
+ * Return OK or FAIL.
+ */
+ static int
+eval7(
+ char_u **arg,
+ typval_T *rettv,
+ int evaluate,
+ int want_string UNUSED) /* after "." operator */
+{
+ varnumber_T n;
+ int len;
+ char_u *s;
+ char_u *start_leader, *end_leader;
+ int ret = OK;
+ char_u *alias;
+
+ /*
+ * Initialise variable so that clear_tv() can't mistake this for a
+ * string and free a string that isn't there.
+ */
+ rettv->v_type = VAR_UNKNOWN;
+
+ /*
+ * Skip '!', '-' and '+' characters. They are handled later.
+ */
+ start_leader = *arg;
+ while (**arg == '!' || **arg == '-' || **arg == '+')
+ *arg = skipwhite(*arg + 1);
+ end_leader = *arg;
+
+ switch (**arg)
+ {
+ /*
+ * Number constant.
+ */
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ {
+#ifdef FEAT_FLOAT
+ char_u *p = skipdigits(*arg + 1);
+ int get_float = FALSE;
+
+ /* We accept a float when the format matches
+ * "[0-9]\+\.[0-9]\+\([eE][+-]\?[0-9]\+\)\?". This is very
+ * strict to avoid backwards compatibility problems.
+ * Don't look for a float after the "." operator, so that
+ * ":let vers = 1.2.3" doesn't fail. */
+ if (!want_string && p[0] == '.' && vim_isdigit(p[1]))
+ {
+ get_float = TRUE;
+ p = skipdigits(p + 2);
+ if (*p == 'e' || *p == 'E')
+ {
+ ++p;
+ if (*p == '-' || *p == '+')
+ ++p;
+ if (!vim_isdigit(*p))
+ get_float = FALSE;
+ else
+ p = skipdigits(p + 1);
+ }
+ if (ASCII_ISALPHA(*p) || *p == '.')
+ get_float = FALSE;
+ }
+ if (get_float)
+ {
+ float_T f;
+
+ *arg += string2float(*arg, &f);
+ if (evaluate)
+ {
+ rettv->v_type = VAR_FLOAT;
+ rettv->vval.v_float = f;
+ }
+ }
+ else
+#endif
+ if (**arg == '0' && ((*arg)[1] == 'z' || (*arg)[1] == 'Z'))
+ {
+ char_u *bp;
+ blob_T *blob = NULL; // init for gcc
+
+ // Blob constant: 0z0123456789abcdef
+ if (evaluate)
+ blob = blob_alloc();
+ for (bp = *arg + 2; vim_isxdigit(bp[0]); bp += 2)
+ {
+ if (!vim_isxdigit(bp[1]))
+ {
+ if (blob != NULL)
+ {
+ emsg(_("E973: Blob literal should have an even number of hex characters"));
+ ga_clear(&blob->bv_ga);
+ VIM_CLEAR(blob);
+ }
+ ret = FAIL;
+ break;
+ }
+ if (blob != NULL)
+ ga_append(&blob->bv_ga,
+ (hex2nr(*bp) << 4) + hex2nr(*(bp+1)));
+ if (bp[2] == '.' && vim_isxdigit(bp[3]))
+ ++bp;
+ }
+ if (blob != NULL)
+ rettv_blob_set(rettv, blob);
+ *arg = bp;
+ }
+ else
+ {
+ // decimal, hex or octal number
+ vim_str2nr(*arg, NULL, &len, STR2NR_ALL, &n, NULL, 0);
+ *arg += len;
+ if (evaluate)
+ {
+ rettv->v_type = VAR_NUMBER;
+ rettv->vval.v_number = n;
+ }
+ }
+ break;
+ }
+
+ /*
+ * String constant: "string".
+ */
+ case '"': ret = get_string_tv(arg, rettv, evaluate);
+ break;
+
+ /*
+ * Literal string constant: 'str''ing'.
+ */
+ case '\'': ret = get_lit_string_tv(arg, rettv, evaluate);
+ break;
+
+ /*
+ * List: [expr, expr]
+ */
+ case '[': ret = get_list_tv(arg, rettv, evaluate);
+ break;
+
+ /*
+ * Lambda: {arg, arg -> expr}
+ * Dictionary: {key: val, key: val}
+ */
+ case '{': ret = get_lambda_tv(arg, rettv, evaluate);
+ if (ret == NOTDONE)
+ ret = dict_get_tv(arg, rettv, evaluate);
+ break;
+
+ /*
+ * Option value: &name
+ */
+ case '&': ret = get_option_tv(arg, rettv, evaluate);
+ break;
+
+ /*
+ * Environment variable: $VAR.
+ */
+ case '$': ret = get_env_tv(arg, rettv, evaluate);
+ break;
+
+ /*
+ * Register contents: @r.
+ */
+ case '@': ++*arg;
+ if (evaluate)
+ {
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = get_reg_contents(**arg,
+ GREG_EXPR_SRC);
+ }
+ if (**arg != NUL)
+ ++*arg;
+ break;
+
+ /*
+ * nested expression: (expression).
+ */
+ case '(': *arg = skipwhite(*arg + 1);
+ ret = eval1(arg, rettv, evaluate); /* recursive! */
+ if (**arg == ')')
+ ++*arg;
+ else if (ret == OK)
+ {
+ emsg(_("E110: Missing ')'"));
+ clear_tv(rettv);
+ ret = FAIL;
+ }
+ break;
+
+ default: ret = NOTDONE;
+ break;
+ }
+
+ if (ret == NOTDONE)
+ {
+ /*
+ * Must be a variable or function name.
+ * Can also be a curly-braces kind of name: {expr}.
+ */
+ s = *arg;
+ len = get_name_len(arg, &alias, evaluate, TRUE);
+ if (alias != NULL)
+ s = alias;
+
+ if (len <= 0)
+ ret = FAIL;
+ else
+ {
+ if (**arg == '(') /* recursive! */
+ {
+ partial_T *partial;
+
+ if (!evaluate)
+ check_vars(s, len);
+
+ /* If "s" is the name of a variable of type VAR_FUNC
+ * use its contents. */
+ s = deref_func_name(s, &len, &partial, !evaluate);
+
+ /* Need to make a copy, in case evaluating the arguments makes
+ * the name invalid. */
+ s = vim_strsave(s);
+ if (s == NULL)
+ ret = FAIL;
+ else
+ /* Invoke the function. */
+ ret = get_func_tv(s, len, rettv, arg,
+ curwin->w_cursor.lnum, curwin->w_cursor.lnum,
+ &len, evaluate, partial, NULL);
+ vim_free(s);
+
+ /* If evaluate is FALSE rettv->v_type was not set in
+ * get_func_tv, but it's needed in handle_subscript() to parse
+ * what follows. So set it here. */
+ if (rettv->v_type == VAR_UNKNOWN && !evaluate && **arg == '(')
+ {
+ rettv->vval.v_string = NULL;
+ rettv->v_type = VAR_FUNC;
+ }
+
+ /* Stop the expression evaluation when immediately
+ * aborting on error, or when an interrupt occurred or
+ * an exception was thrown but not caught. */
+ if (aborting())
+ {
+ if (ret == OK)
+ clear_tv(rettv);
+ ret = FAIL;
+ }
+ }
+ else if (evaluate)
+ ret = get_var_tv(s, len, rettv, NULL, TRUE, FALSE);
+ else
+ {
+ check_vars(s, len);
+ ret = OK;
+ }
+ }
+ vim_free(alias);
+ }
+
+ *arg = skipwhite(*arg);
+
+ /* Handle following '[', '(' and '.' for expr[expr], expr.name,
+ * expr(expr). */
+ if (ret == OK)
+ ret = handle_subscript(arg, rettv, evaluate, TRUE);
+
+ /*
+ * Apply logical NOT and unary '-', from right to left, ignore '+'.
+ */
+ if (ret == OK && evaluate && end_leader > start_leader)
+ {
+ int error = FALSE;
+ varnumber_T val = 0;
+#ifdef FEAT_FLOAT
+ float_T f = 0.0;
+
+ if (rettv->v_type == VAR_FLOAT)
+ f = rettv->vval.v_float;
+ else
+#endif
+ val = tv_get_number_chk(rettv, &error);
+ if (error)
+ {
+ clear_tv(rettv);
+ ret = FAIL;
+ }
+ else
+ {
+ while (end_leader > start_leader)
+ {
+ --end_leader;
+ if (*end_leader == '!')
+ {
+#ifdef FEAT_FLOAT
+ if (rettv->v_type == VAR_FLOAT)
+ f = !f;
+ else
+#endif
+ val = !val;
+ }
+ else if (*end_leader == '-')
+ {
+#ifdef FEAT_FLOAT
+ if (rettv->v_type == VAR_FLOAT)
+ f = -f;
+ else
+#endif
+ val = -val;
+ }
+ }
+#ifdef FEAT_FLOAT
+ if (rettv->v_type == VAR_FLOAT)
+ {
+ clear_tv(rettv);
+ rettv->vval.v_float = f;
+ }
+ else
+#endif
+ {
+ clear_tv(rettv);
+ rettv->v_type = VAR_NUMBER;
+ rettv->vval.v_number = val;
+ }
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * Evaluate an "[expr]" or "[expr:expr]" index. Also "dict.key".
+ * "*arg" points to the '[' or '.'.
+ * Returns FAIL or OK. "*arg" is advanced to after the ']'.
+ */
+ static int
+eval_index(
+ char_u **arg,
+ typval_T *rettv,
+ int evaluate,
+ int verbose) /* give error messages */
+{
+ int empty1 = FALSE, empty2 = FALSE;
+ typval_T var1, var2;
+ long i;
+ long n1, n2 = 0;
+ long len = -1;
+ int range = FALSE;
+ char_u *s;
+ char_u *key = NULL;
+
+ switch (rettv->v_type)
+ {
+ case VAR_FUNC:
+ case VAR_PARTIAL:
+ if (verbose)
+ emsg(_("E695: Cannot index a Funcref"));
+ return FAIL;
+ case VAR_FLOAT:
+#ifdef FEAT_FLOAT
+ if (verbose)
+ emsg(_(e_float_as_string));
+ return FAIL;
+#endif
+ case VAR_SPECIAL:
+ case VAR_JOB:
+ case VAR_CHANNEL:
+ if (verbose)
+ emsg(_("E909: Cannot index a special variable"));
+ return FAIL;
+ case VAR_UNKNOWN:
+ if (evaluate)
+ return FAIL;
+ /* FALLTHROUGH */
+
+ case VAR_STRING:
+ case VAR_NUMBER:
+ case VAR_LIST:
+ case VAR_DICT:
+ case VAR_BLOB:
+ break;
+ }
+
+ init_tv(&var1);
+ init_tv(&var2);
+ if (**arg == '.')
+ {
+ /*
+ * dict.name
+ */
+ key = *arg + 1;
+ for (len = 0; ASCII_ISALNUM(key[len]) || key[len] == '_'; ++len)
+ ;
+ if (len == 0)
+ return FAIL;
+ *arg = skipwhite(key + len);
+ }
+ else
+ {
+ /*
+ * something[idx]
+ *
+ * Get the (first) variable from inside the [].
+ */
+ *arg = skipwhite(*arg + 1);
+ if (**arg == ':')
+ empty1 = TRUE;
+ else if (eval1(arg, &var1, evaluate) == FAIL) /* recursive! */
+ return FAIL;
+ else if (evaluate && tv_get_string_chk(&var1) == NULL)
+ {
+ /* not a number or string */
+ clear_tv(&var1);
+ return FAIL;
+ }
+
+ /*
+ * Get the second variable from inside the [:].
+ */
+ if (**arg == ':')
+ {
+ range = TRUE;
+ *arg = skipwhite(*arg + 1);
+ if (**arg == ']')
+ empty2 = TRUE;
+ else if (eval1(arg, &var2, evaluate) == FAIL) /* recursive! */
+ {
+ if (!empty1)
+ clear_tv(&var1);
+ return FAIL;
+ }
+ else if (evaluate && tv_get_string_chk(&var2) == NULL)
+ {
+ /* not a number or string */
+ if (!empty1)
+ clear_tv(&var1);
+ clear_tv(&var2);
+ return FAIL;
+ }
+ }
+
+ /* Check for the ']'. */
+ if (**arg != ']')
+ {
+ if (verbose)
+ emsg(_(e_missbrac));
+ clear_tv(&var1);
+ if (range)
+ clear_tv(&var2);
+ return FAIL;
+ }
+ *arg = skipwhite(*arg + 1); /* skip the ']' */
+ }
+
+ if (evaluate)
+ {
+ n1 = 0;
+ if (!empty1 && rettv->v_type != VAR_DICT)
+ {
+ n1 = tv_get_number(&var1);
+ clear_tv(&var1);
+ }
+ if (range)
+ {
+ if (empty2)
+ n2 = -1;
+ else
+ {
+ n2 = tv_get_number(&var2);
+ clear_tv(&var2);
+ }
+ }
+
+ switch (rettv->v_type)
+ {
+ case VAR_UNKNOWN:
+ case VAR_FUNC:
+ case VAR_PARTIAL:
+ case VAR_FLOAT:
+ case VAR_SPECIAL:
+ case VAR_JOB:
+ case VAR_CHANNEL:
+ break; /* not evaluating, skipping over subscript */
+
+ case VAR_NUMBER:
+ case VAR_STRING:
+ s = tv_get_string(rettv);
+ len = (long)STRLEN(s);
+ if (range)
+ {
+ /* The resulting variable is a substring. If the indexes
+ * are out of range the result is empty. */
+ if (n1 < 0)
+ {
+ n1 = len + n1;
+ if (n1 < 0)
+ n1 = 0;
+ }
+ if (n2 < 0)
+ n2 = len + n2;
+ else if (n2 >= len)
+ n2 = len;
+ if (n1 >= len || n2 < 0 || n1 > n2)
+ s = NULL;
+ else
+ s = vim_strnsave(s + n1, (int)(n2 - n1 + 1));
+ }
+ else
+ {
+ /* The resulting variable is a string of a single
+ * character. If the index is too big or negative the
+ * result is empty. */
+ if (n1 >= len || n1 < 0)
+ s = NULL;
+ else
+ s = vim_strnsave(s + n1, 1);
+ }
+ clear_tv(rettv);
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = s;
+ break;
+
+ case VAR_BLOB:
+ len = blob_len(rettv->vval.v_blob);
+ if (range)
+ {
+ // The resulting variable is a sub-blob. If the indexes
+ // are out of range the result is empty.
+ if (n1 < 0)
+ {
+ n1 = len + n1;
+ if (n1 < 0)
+ n1 = 0;
+ }
+ if (n2 < 0)
+ n2 = len + n2;
+ else if (n2 >= len)
+ n2 = len - 1;
+ if (n1 >= len || n2 < 0 || n1 > n2)
+ {
+ clear_tv(rettv);
+ rettv->v_type = VAR_BLOB;
+ rettv->vval.v_blob = NULL;
+ }
+ else
+ {
+ blob_T *blob = blob_alloc();
+
+ if (blob != NULL)
+ {
+ if (ga_grow(&blob->bv_ga, n2 - n1 + 1) == FAIL)
+ {
+ blob_free(blob);
+ return FAIL;
+ }
+ blob->bv_ga.ga_len = n2 - n1 + 1;
+ for (i = n1; i <= n2; i++)
+ blob_set(blob, i - n1,
+ blob_get(rettv->vval.v_blob, i));
+
+ clear_tv(rettv);
+ rettv_blob_set(rettv, blob);
+ }
+ }
+ }
+ else
+ {
+ // The resulting variable is a byte value.
+ // If the index is too big or negative that is an error.
+ if (n1 < 0)
+ n1 = len + n1;
+ if (n1 < len && n1 >= 0)
+ {
+ int v = blob_get(rettv->vval.v_blob, n1);
+
+ clear_tv(rettv);
+ rettv->v_type = VAR_NUMBER;
+ rettv->vval.v_number = v;
+ }
+ else
+ semsg(_(e_blobidx), n1);
+ }
+ break;
+
+ case VAR_LIST:
+ len = list_len(rettv->vval.v_list);
+ if (n1 < 0)
+ n1 = len + n1;
+ if (!empty1 && (n1 < 0 || n1 >= len))
+ {
+ /* For a range we allow invalid values and return an empty
+ * list. A list index out of range is an error. */
+ if (!range)
+ {
+ if (verbose)
+ semsg(_(e_listidx), n1);
+ return FAIL;
+ }
+ n1 = len;
+ }
+ if (range)
+ {
+ list_T *l;
+ listitem_T *item;
+
+ if (n2 < 0)
+ n2 = len + n2;
+ else if (n2 >= len)
+ n2 = len - 1;
+ if (!empty2 && (n2 < 0 || n2 + 1 < n1))
+ n2 = -1;
+ l = list_alloc();
+ if (l == NULL)
+ return FAIL;
+ for (item = list_find(rettv->vval.v_list, n1);
+ n1 <= n2; ++n1)
+ {
+ if (list_append_tv(l, &item->li_tv) == FAIL)
+ {
+ list_free(l);
+ return FAIL;
+ }
+ item = item->li_next;
+ }
+ clear_tv(rettv);
+ rettv_list_set(rettv, l);
+ }
+ else
+ {
+ copy_tv(&list_find(rettv->vval.v_list, n1)->li_tv, &var1);
+ clear_tv(rettv);
+ *rettv = var1;
+ }
+ break;
+
+ case VAR_DICT:
+ if (range)
+ {
+ if (verbose)
+ emsg(_(e_dictrange));
+ if (len == -1)
+ clear_tv(&var1);
+ return FAIL;
+ }
+ {
+ dictitem_T *item;
+
+ if (len == -1)
+ {
+ key = tv_get_string_chk(&var1);
+ if (key == NULL)
+ {
+ clear_tv(&var1);
+ return FAIL;
+ }
+ }
+
+ item = dict_find(rettv->vval.v_dict, key, (int)len);
+
+ if (item == NULL && verbose)
+ semsg(_(e_dictkey), key);
+ if (len == -1)
+ clear_tv(&var1);
+ if (item == NULL)
+ return FAIL;
+
+ copy_tv(&item->di_tv, &var1);
+ clear_tv(rettv);
+ *rettv = var1;
+ }
+ break;
+ }
+ }
+
+ return OK;
+}
+
+/*
+ * Get an option value.
+ * "arg" points to the '&' or '+' before the option name.
+ * "arg" is advanced to character after the option name.
+ * Return OK or FAIL.
+ */
+ int
+get_option_tv(
+ char_u **arg,
+ typval_T *rettv, /* when NULL, only check if option exists */
+ int evaluate)
+{
+ char_u *option_end;
+ long numval;
+ char_u *stringval;
+ int opt_type;
+ int c;
+ int working = (**arg == '+'); /* has("+option") */
+ int ret = OK;
+ int opt_flags;
+
+ /*
+ * Isolate the option name and find its value.
+ */
+ option_end = find_option_end(arg, &opt_flags);
+ if (option_end == NULL)
+ {
+ if (rettv != NULL)
+ semsg(_("E112: Option name missing: %s"), *arg);
+ return FAIL;
+ }
+
+ if (!evaluate)
+ {
+ *arg = option_end;
+ return OK;
+ }
+
+ c = *option_end;
+ *option_end = NUL;
+ opt_type = get_option_value(*arg, &numval,
+ rettv == NULL ? NULL : &stringval, opt_flags);
+
+ if (opt_type == -3) /* invalid name */
+ {
+ if (rettv != NULL)
+ semsg(_("E113: Unknown option: %s"), *arg);
+ ret = FAIL;
+ }
+ else if (rettv != NULL)
+ {
+ if (opt_type == -2) /* hidden string option */
+ {
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+ }
+ else if (opt_type == -1) /* hidden number option */
+ {
+ rettv->v_type = VAR_NUMBER;
+ rettv->vval.v_number = 0;
+ }
+ else if (opt_type == 1) /* number option */
+ {
+ rettv->v_type = VAR_NUMBER;
+ rettv->vval.v_number = numval;
+ }
+ else /* string option */
+ {
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = stringval;
+ }
+ }
+ else if (working && (opt_type == -2 || opt_type == -1))
+ ret = FAIL;
+
+ *option_end = c; /* put back for error messages */
+ *arg = option_end;
+
+ return ret;
+}
+
+/*
+ * Allocate a variable for a string constant.
+ * Return OK or FAIL.
+ */
+ static int
+get_string_tv(char_u **arg, typval_T *rettv, int evaluate)
+{
+ char_u *p;
+ char_u *name;
+ int extra = 0;
+
+ /*
+ * Find the end of the string, skipping backslashed characters.
+ */
+ for (p = *arg + 1; *p != NUL && *p != '"'; MB_PTR_ADV(p))
+ {
+ if (*p == '\\' && p[1] != NUL)
+ {
+ ++p;
+ /* A "\<x>" form occupies at least 4 characters, and produces up
+ * to 6 characters: reserve space for 2 extra */
+ if (*p == '<')
+ extra += 2;
+ }
+ }
+
+ if (*p != '"')
+ {
+ semsg(_("E114: Missing quote: %s"), *arg);
+ return FAIL;
+ }
+
+ /* If only parsing, set *arg and return here */
+ if (!evaluate)
+ {
+ *arg = p + 1;
+ return OK;
+ }
+
+ /*
+ * Copy the string into allocated memory, handling backslashed
+ * characters.
+ */
+ name = alloc((unsigned)(p - *arg + extra));
+ if (name == NULL)
+ return FAIL;
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = name;
+
+ for (p = *arg + 1; *p != NUL && *p != '"'; )
+ {
+ if (*p == '\\')
+ {
+ switch (*++p)
+ {
+ case 'b': *name++ = BS; ++p; break;
+ case 'e': *name++ = ESC; ++p; break;
+ case 'f': *name++ = FF; ++p; break;
+ case 'n': *name++ = NL; ++p; break;
+ case 'r': *name++ = CAR; ++p; break;
+ case 't': *name++ = TAB; ++p; break;
+
+ case 'X': /* hex: "\x1", "\x12" */
+ case 'x':
+ case 'u': /* Unicode: "\u0023" */
+ case 'U':
+ if (vim_isxdigit(p[1]))
+ {
+ int n, nr;
+ int c = toupper(*p);
+
+ if (c == 'X')
+ n = 2;
+ else if (*p == 'u')
+ n = 4;
+ else
+ n = 8;
+ nr = 0;
+ while (--n >= 0 && vim_isxdigit(p[1]))
+ {
+ ++p;
+ nr = (nr << 4) + hex2nr(*p);
+ }
+ ++p;
+ /* For "\u" store the number according to
+ * 'encoding'. */
+ if (c != 'X')
+ name += (*mb_char2bytes)(nr, name);
+ else
+ *name++ = nr;
+ }
+ break;
+
+ /* octal: "\1", "\12", "\123" */
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7': *name = *p++ - '0';
+ if (*p >= '0' && *p <= '7')
+ {
+ *name = (*name << 3) + *p++ - '0';
+ if (*p >= '0' && *p <= '7')
+ *name = (*name << 3) + *p++ - '0';
+ }
+ ++name;
+ break;
+
+ /* Special key, e.g.: "\<C-W>" */
+ case '<': extra = trans_special(&p, name, TRUE, TRUE);
+ if (extra != 0)
+ {
+ name += extra;
+ break;
+ }
+ /* FALLTHROUGH */
+
+ default: MB_COPY_CHAR(p, name);
+ break;
+ }
+ }
+ else
+ MB_COPY_CHAR(p, name);
+
+ }
+ *name = NUL;
+ if (*p != NUL) /* just in case */
+ ++p;
+ *arg = p;
+
+ return OK;
+}
+
+/*
+ * Allocate a variable for a 'str''ing' constant.
+ * Return OK or FAIL.
+ */
+ static int
+get_lit_string_tv(char_u **arg, typval_T *rettv, int evaluate)
+{
+ char_u *p;
+ char_u *str;
+ int reduce = 0;
+
+ /*
+ * Find the end of the string, skipping ''.
+ */
+ for (p = *arg + 1; *p != NUL; MB_PTR_ADV(p))
+ {
+ if (*p == '\'')
+ {
+ if (p[1] != '\'')
+ break;
+ ++reduce;
+ ++p;
+ }
+ }
+
+ if (*p != '\'')
+ {
+ semsg(_("E115: Missing quote: %s"), *arg);
+ return FAIL;
+ }
+
+ /* If only parsing return after setting "*arg" */
+ if (!evaluate)
+ {
+ *arg = p + 1;
+ return OK;
+ }
+
+ /*
+ * Copy the string into allocated memory, handling '' to ' reduction.
+ */
+ str = alloc((unsigned)((p - *arg) - reduce));
+ if (str == NULL)
+ return FAIL;
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = str;
+
+ for (p = *arg + 1; *p != NUL; )
+ {
+ if (*p == '\'')
+ {
+ if (p[1] != '\'')
+ break;
+ ++p;
+ }
+ MB_COPY_CHAR(p, str);
+ }
+ *str = NUL;
+ *arg = p + 1;
+
+ return OK;
+}
+
+/*
+ * Return the function name of the partial.
+ */
+ char_u *
+partial_name(partial_T *pt)
+{
+ if (pt->pt_name != NULL)
+ return pt->pt_name;
+ return pt->pt_func->uf_name;
+}
+
+ static void
+partial_free(partial_T *pt)
+{
+ int i;
+
+ for (i = 0; i < pt->pt_argc; ++i)
+ clear_tv(&pt->pt_argv[i]);
+ vim_free(pt->pt_argv);
+ dict_unref(pt->pt_dict);
+ if (pt->pt_name != NULL)
+ {
+ func_unref(pt->pt_name);
+ vim_free(pt->pt_name);
+ }
+ else
+ func_ptr_unref(pt->pt_func);
+ vim_free(pt);
+}
+
+/*
+ * Unreference a closure: decrement the reference count and free it when it
+ * becomes zero.
+ */
+ void
+partial_unref(partial_T *pt)
+{
+ if (pt != NULL && --pt->pt_refcount <= 0)
+ partial_free(pt);
+}
+
+static int tv_equal_recurse_limit;
+
+ static int
+func_equal(
+ typval_T *tv1,
+ typval_T *tv2,
+ int ic) /* ignore case */
+{
+ char_u *s1, *s2;
+ dict_T *d1, *d2;
+ int a1, a2;
+ int i;
+
+ /* empty and NULL function name considered the same */
+ s1 = tv1->v_type == VAR_FUNC ? tv1->vval.v_string
+ : partial_name(tv1->vval.v_partial);
+ if (s1 != NULL && *s1 == NUL)
+ s1 = NULL;
+ s2 = tv2->v_type == VAR_FUNC ? tv2->vval.v_string
+ : partial_name(tv2->vval.v_partial);
+ if (s2 != NULL && *s2 == NUL)
+ s2 = NULL;
+ if (s1 == NULL || s2 == NULL)
+ {
+ if (s1 != s2)
+ return FALSE;
+ }
+ else if (STRCMP(s1, s2) != 0)
+ return FALSE;
+
+ /* empty dict and NULL dict is different */
+ d1 = tv1->v_type == VAR_FUNC ? NULL : tv1->vval.v_partial->pt_dict;
+ d2 = tv2->v_type == VAR_FUNC ? NULL : tv2->vval.v_partial->pt_dict;
+ if (d1 == NULL || d2 == NULL)
+ {
+ if (d1 != d2)
+ return FALSE;
+ }
+ else if (!dict_equal(d1, d2, ic, TRUE))
+ return FALSE;
+
+ /* empty list and no list considered the same */
+ a1 = tv1->v_type == VAR_FUNC ? 0 : tv1->vval.v_partial->pt_argc;
+ a2 = tv2->v_type == VAR_FUNC ? 0 : tv2->vval.v_partial->pt_argc;
+ if (a1 != a2)
+ return FALSE;
+ for (i = 0; i < a1; ++i)
+ if (!tv_equal(tv1->vval.v_partial->pt_argv + i,
+ tv2->vval.v_partial->pt_argv + i, ic, TRUE))
+ return FALSE;
+
+ return TRUE;
+}
+
+/*
+ * Return TRUE if "tv1" and "tv2" have the same value.
+ * Compares the items just like "==" would compare them, but strings and
+ * numbers are different. Floats and numbers are also different.
+ */
+ int
+tv_equal(
+ typval_T *tv1,
+ typval_T *tv2,
+ int ic, /* ignore case */
+ int recursive) /* TRUE when used recursively */
+{
+ char_u buf1[NUMBUFLEN], buf2[NUMBUFLEN];
+ char_u *s1, *s2;
+ static int recursive_cnt = 0; /* catch recursive loops */
+ int r;
+
+ /* Catch lists and dicts that have an endless loop by limiting
+ * recursiveness to a limit. We guess they are equal then.
+ * A fixed limit has the problem of still taking an awful long time.
+ * Reduce the limit every time running into it. That should work fine for
+ * deeply linked structures that are not recursively linked and catch
+ * recursiveness quickly. */
+ if (!recursive)
+ tv_equal_recurse_limit = 1000;
+ if (recursive_cnt >= tv_equal_recurse_limit)
+ {
+ --tv_equal_recurse_limit;
+ return TRUE;
+ }
+
+ /* For VAR_FUNC and VAR_PARTIAL compare the function name, bound dict and
+ * arguments. */
+ if ((tv1->v_type == VAR_FUNC
+ || (tv1->v_type == VAR_PARTIAL && tv1->vval.v_partial != NULL))
+ && (tv2->v_type == VAR_FUNC
+ || (tv2->v_type == VAR_PARTIAL && tv2->vval.v_partial != NULL)))
+ {
+ ++recursive_cnt;
+ r = func_equal(tv1, tv2, ic);
+ --recursive_cnt;
+ return r;
+ }
+
+ if (tv1->v_type != tv2->v_type)
+ return FALSE;
+
+ switch (tv1->v_type)
+ {
+ case VAR_LIST:
+ ++recursive_cnt;
+ r = list_equal(tv1->vval.v_list, tv2->vval.v_list, ic, TRUE);
+ --recursive_cnt;
+ return r;
+
+ case VAR_DICT:
+ ++recursive_cnt;
+ r = dict_equal(tv1->vval.v_dict, tv2->vval.v_dict, ic, TRUE);
+ --recursive_cnt;
+ return r;
+
+ case VAR_BLOB:
+ return blob_equal(tv1->vval.v_blob, tv2->vval.v_blob);
+
+ case VAR_NUMBER:
+ return tv1->vval.v_number == tv2->vval.v_number;
+
+ case VAR_STRING:
+ s1 = tv_get_string_buf(tv1, buf1);
+ s2 = tv_get_string_buf(tv2, buf2);
+ return ((ic ? MB_STRICMP(s1, s2) : STRCMP(s1, s2)) == 0);
+
+ case VAR_SPECIAL:
+ return tv1->vval.v_number == tv2->vval.v_number;
+
+ case VAR_FLOAT:
+#ifdef FEAT_FLOAT
+ return tv1->vval.v_float == tv2->vval.v_float;
+#endif
+ case VAR_JOB:
+#ifdef FEAT_JOB_CHANNEL
+ return tv1->vval.v_job == tv2->vval.v_job;
+#endif
+ case VAR_CHANNEL:
+#ifdef FEAT_JOB_CHANNEL
+ return tv1->vval.v_channel == tv2->vval.v_channel;
+#endif
+ case VAR_FUNC:
+ case VAR_PARTIAL:
+ case VAR_UNKNOWN:
+ break;
+ }
+
+ /* VAR_UNKNOWN can be the result of a invalid expression, let's say it
+ * does not equal anything, not even itself. */
+ return FALSE;
+}
+
+/*
+ * Return the next (unique) copy ID.
+ * Used for serializing nested structures.
+ */
+ int
+get_copyID(void)
+{
+ current_copyID += COPYID_INC;
+ return current_copyID;
+}
+
+/*
+ * Garbage collection for lists and dictionaries.
+ *
+ * We use reference counts to be able to free most items right away when they
+ * are no longer used. But for composite items it's possible that it becomes
+ * unused while the reference count is > 0: When there is a recursive
+ * reference. Example:
+ * :let l = [1, 2, 3]
+ * :let d = {9: l}
+ * :let l[1] = d
+ *
+ * Since this is quite unusual we handle this with garbage collection: every
+ * once in a while find out which lists and dicts are not referenced from any
+ * variable.
+ *
+ * Here is a good reference text about garbage collection (refers to Python
+ * but it applies to all reference-counting mechanisms):
+ * http://python.ca/nas/python/gc/
+ */
+
+/*
+ * Do garbage collection for lists and dicts.
+ * When "testing" is TRUE this is called from test_garbagecollect_now().
+ * Return TRUE if some memory was freed.
+ */
+ int
+garbage_collect(int testing)
+{
+ int copyID;
+ int abort = FALSE;
+ buf_T *buf;
+ win_T *wp;
+ int i;
+ int did_free = FALSE;
+ tabpage_T *tp;
+
+ if (!testing)
+ {
+ /* Only do this once. */
+ want_garbage_collect = FALSE;
+ may_garbage_collect = FALSE;
+ garbage_collect_at_exit = FALSE;
+ }
+
+ /* We advance by two because we add one for items referenced through
+ * previous_funccal. */
+ copyID = get_copyID();
+
+ /*
+ * 1. Go through all accessible variables and mark all lists and dicts
+ * with copyID.
+ */
+
+ /* Don't free variables in the previous_funccal list unless they are only
+ * referenced through previous_funccal. This must be first, because if
+ * the item is referenced elsewhere the funccal must not be freed. */
+ abort = abort || set_ref_in_previous_funccal(copyID);
+
+ /* script-local variables */
+ for (i = 1; i <= ga_scripts.ga_len; ++i)
+ abort = abort || set_ref_in_ht(&SCRIPT_VARS(i), copyID, NULL);
+
+ /* buffer-local variables */
+ FOR_ALL_BUFFERS(buf)
+ abort = abort || set_ref_in_item(&buf->b_bufvar.di_tv, copyID,
+ NULL, NULL);
+
+ /* window-local variables */
+ FOR_ALL_TAB_WINDOWS(tp, wp)
+ abort = abort || set_ref_in_item(&wp->w_winvar.di_tv, copyID,
+ NULL, NULL);
+ if (aucmd_win != NULL)
+ abort = abort || set_ref_in_item(&aucmd_win->w_winvar.di_tv, copyID,
+ NULL, NULL);
+
+ /* tabpage-local variables */
+ FOR_ALL_TABPAGES(tp)
+ abort = abort || set_ref_in_item(&tp->tp_winvar.di_tv, copyID,
+ NULL, NULL);
+ /* global variables */
+ abort = abort || set_ref_in_ht(&globvarht, copyID, NULL);
+
+ /* function-local variables */
+ abort = abort || set_ref_in_call_stack(copyID);
+
+ /* named functions (matters for closures) */
+ abort = abort || set_ref_in_functions(copyID);
+
+ /* function call arguments, if v:testing is set. */
+ abort = abort || set_ref_in_func_args(copyID);
+
+ /* v: vars */
+ abort = abort || set_ref_in_ht(&vimvarht, copyID, NULL);
+
+#ifdef FEAT_LUA
+ abort = abort || set_ref_in_lua(copyID);
+#endif
+
+#ifdef FEAT_PYTHON
+ abort = abort || set_ref_in_python(copyID);
+#endif
+
+#ifdef FEAT_PYTHON3
+ abort = abort || set_ref_in_python3(copyID);
+#endif
+
+#ifdef FEAT_JOB_CHANNEL
+ abort = abort || set_ref_in_channel(copyID);
+ abort = abort || set_ref_in_job(copyID);
+#endif
+#ifdef FEAT_NETBEANS_INTG
+ abort = abort || set_ref_in_nb_channel(copyID);
+#endif
+
+#ifdef FEAT_TIMERS
+ abort = abort || set_ref_in_timer(copyID);
+#endif
+
+#ifdef FEAT_QUICKFIX
+ abort = abort || set_ref_in_quickfix(copyID);
+#endif
+
+#ifdef FEAT_TERMINAL
+ abort = abort || set_ref_in_term(copyID);
+#endif
+
+ if (!abort)
+ {
+ /*
+ * 2. Free lists and dictionaries that are not referenced.
+ */
+ did_free = free_unref_items(copyID);
+
+ /*
+ * 3. Check if any funccal can be freed now.
+ * This may call us back recursively.
+ */
+ free_unref_funccal(copyID, testing);
+ }
+ else if (p_verbose > 0)
+ {
+ verb_msg(_("Not enough memory to set references, garbage collection aborted!"));
+ }
+
+ return did_free;
+}
+
+/*
+ * Free lists, dictionaries, channels and jobs that are no longer referenced.
+ */
+ static int
+free_unref_items(int copyID)
+{
+ int did_free = FALSE;
+
+ /* Let all "free" functions know that we are here. This means no
+ * dictionaries, lists, channels or jobs are to be freed, because we will
+ * do that here. */
+ in_free_unref_items = TRUE;
+
+ /*
+ * PASS 1: free the contents of the items. We don't free the items
+ * themselves yet, so that it is possible to decrement refcount counters
+ */
+
+ /* Go through the list of dicts and free items without the copyID. */
+ did_free |= dict_free_nonref(copyID);
+
+ /* Go through the list of lists and free items without the copyID. */
+ did_free |= list_free_nonref(copyID);
+
+#ifdef FEAT_JOB_CHANNEL
+ /* Go through the list of jobs and free items without the copyID. This
+ * must happen before doing channels, because jobs refer to channels, but
+ * the reference from the channel to the job isn't tracked. */
+ did_free |= free_unused_jobs_contents(copyID, COPYID_MASK);
+
+ /* Go through the list of channels and free items without the copyID. */
+ did_free |= free_unused_channels_contents(copyID, COPYID_MASK);
+#endif
+
+ /*
+ * PASS 2: free the items themselves.
+ */
+ dict_free_items(copyID);
+ list_free_items(copyID);
+
+#ifdef FEAT_JOB_CHANNEL
+ /* Go through the list of jobs and free items without the copyID. This
+ * must happen before doing channels, because jobs refer to channels, but
+ * the reference from the channel to the job isn't tracked. */
+ free_unused_jobs(copyID, COPYID_MASK);
+
+ /* Go through the list of channels and free items without the copyID. */
+ free_unused_channels(copyID, COPYID_MASK);
+#endif
+
+ in_free_unref_items = FALSE;
+
+ return did_free;
+}
+
+/*
+ * Mark all lists and dicts referenced through hashtab "ht" with "copyID".
+ * "list_stack" is used to add lists to be marked. Can be NULL.
+ *
+ * Returns TRUE if setting references failed somehow.
+ */
+ int
+set_ref_in_ht(hashtab_T *ht, int copyID, list_stack_T **list_stack)
+{
+ int todo;
+ int abort = FALSE;
+ hashitem_T *hi;
+ hashtab_T *cur_ht;
+ ht_stack_T *ht_stack = NULL;
+ ht_stack_T *tempitem;
+
+ cur_ht = ht;
+ for (;;)
+ {
+ if (!abort)
+ {
+ /* Mark each item in the hashtab. If the item contains a hashtab
+ * it is added to ht_stack, if it contains a list it is added to
+ * list_stack. */
+ todo = (int)cur_ht->ht_used;
+ for (hi = cur_ht->ht_array; todo > 0; ++hi)
+ if (!HASHITEM_EMPTY(hi))
+ {
+ --todo;
+ abort = abort || set_ref_in_item(&HI2DI(hi)->di_tv, copyID,
+ &ht_stack, list_stack);
+ }
+ }
+
+ if (ht_stack == NULL)
+ break;
+
+ /* take an item from the stack */
+ cur_ht = ht_stack->ht;
+ tempitem = ht_stack;
+ ht_stack = ht_stack->prev;
+ free(tempitem);
+ }
+
+ return abort;
+}
+
+/*
+ * Mark all lists and dicts referenced through list "l" with "copyID".
+ * "ht_stack" is used to add hashtabs to be marked. Can be NULL.
+ *
+ * Returns TRUE if setting references failed somehow.
+ */
+ int
+set_ref_in_list(list_T *l, int copyID, ht_stack_T **ht_stack)
+{
+ listitem_T *li;
+ int abort = FALSE;
+ list_T *cur_l;
+ list_stack_T *list_stack = NULL;
+ list_stack_T *tempitem;
+
+ cur_l = l;
+ for (;;)
+ {
+ if (!abort)
+ /* Mark each item in the list. If the item contains a hashtab
+ * it is added to ht_stack, if it contains a list it is added to
+ * list_stack. */
+ for (li = cur_l->lv_first; !abort && li != NULL; li = li->li_next)
+ abort = abort || set_ref_in_item(&li->li_tv, copyID,
+ ht_stack, &list_stack);
+ if (list_stack == NULL)
+ break;
+
+ /* take an item from the stack */
+ cur_l = list_stack->list;
+ tempitem = list_stack;
+ list_stack = list_stack->prev;
+ free(tempitem);
+ }
+
+ return abort;
+}
+
+/*
+ * Mark all lists and dicts referenced through typval "tv" with "copyID".
+ * "list_stack" is used to add lists to be marked. Can be NULL.
+ * "ht_stack" is used to add hashtabs to be marked. Can be NULL.
+ *
+ * Returns TRUE if setting references failed somehow.
+ */
+ int
+set_ref_in_item(
+ typval_T *tv,
+ int copyID,
+ ht_stack_T **ht_stack,
+ list_stack_T **list_stack)
+{
+ int abort = FALSE;
+
+ if (tv->v_type == VAR_DICT)
+ {
+ dict_T *dd = tv->vval.v_dict;
+
+ if (dd != NULL && dd->dv_copyID != copyID)
+ {
+ /* Didn't see this dict yet. */
+ dd->dv_copyID = copyID;
+ if (ht_stack == NULL)
+ {
+ abort = set_ref_in_ht(&dd->dv_hashtab, copyID, list_stack);
+ }
+ else
+ {
+ ht_stack_T *newitem = (ht_stack_T*)malloc(sizeof(ht_stack_T));
+ if (newitem == NULL)
+ abort = TRUE;
+ else
+ {
+ newitem->ht = &dd->dv_hashtab;
+ newitem->prev = *ht_stack;
+ *ht_stack = newitem;
+ }
+ }
+ }
+ }
+ else if (tv->v_type == VAR_LIST)
+ {
+ list_T *ll = tv->vval.v_list;
+
+ if (ll != NULL && ll->lv_copyID != copyID)
+ {
+ /* Didn't see this list yet. */
+ ll->lv_copyID = copyID;
+ if (list_stack == NULL)
+ {
+ abort = set_ref_in_list(ll, copyID, ht_stack);
+ }
+ else
+ {
+ list_stack_T *newitem = (list_stack_T*)malloc(
+ sizeof(list_stack_T));
+ if (newitem == NULL)
+ abort = TRUE;
+ else
+ {
+ newitem->list = ll;
+ newitem->prev = *list_stack;
+ *list_stack = newitem;
+ }
+ }
+ }
+ }
+ else if (tv->v_type == VAR_FUNC)
+ {
+ abort = set_ref_in_func(tv->vval.v_string, NULL, copyID);
+ }
+ else if (tv->v_type == VAR_PARTIAL)
+ {
+ partial_T *pt = tv->vval.v_partial;
+ int i;
+
+ /* A partial does not have a copyID, because it cannot contain itself.
+ */
+ if (pt != NULL)
+ {
+ abort = set_ref_in_func(pt->pt_name, pt->pt_func, copyID);
+
+ if (pt->pt_dict != NULL)
+ {
+ typval_T dtv;
+
+ dtv.v_type = VAR_DICT;
+ dtv.vval.v_dict = pt->pt_dict;
+ set_ref_in_item(&dtv, copyID, ht_stack, list_stack);
+ }
+
+ for (i = 0; i < pt->pt_argc; ++i)
+ abort = abort || set_ref_in_item(&pt->pt_argv[i], copyID,
+ ht_stack, list_stack);
+ }
+ }
+#ifdef FEAT_JOB_CHANNEL
+ else if (tv->v_type == VAR_JOB)
+ {
+ job_T *job = tv->vval.v_job;
+ typval_T dtv;
+
+ if (job != NULL && job->jv_copyID != copyID)
+ {
+ job->jv_copyID = copyID;
+ if (job->jv_channel != NULL)
+ {
+ dtv.v_type = VAR_CHANNEL;
+ dtv.vval.v_channel = job->jv_channel;
+ set_ref_in_item(&dtv, copyID, ht_stack, list_stack);
+ }
+ if (job->jv_exit_partial != NULL)
+ {
+ dtv.v_type = VAR_PARTIAL;
+ dtv.vval.v_partial = job->jv_exit_partial;
+ set_ref_in_item(&dtv, copyID, ht_stack, list_stack);
+ }
+ }
+ }
+ else if (tv->v_type == VAR_CHANNEL)
+ {
+ channel_T *ch =tv->vval.v_channel;
+ ch_part_T part;
+ typval_T dtv;
+ jsonq_T *jq;
+ cbq_T *cq;
+
+ if (ch != NULL && ch->ch_copyID != copyID)
+ {
+ ch->ch_copyID = copyID;
+ for (part = PART_SOCK; part < PART_COUNT; ++part)
+ {
+ for (jq = ch->ch_part[part].ch_json_head.jq_next; jq != NULL;
+ jq = jq->jq_next)
+ set_ref_in_item(jq->jq_value, copyID, ht_stack, list_stack);
+ for (cq = ch->ch_part[part].ch_cb_head.cq_next; cq != NULL;
+ cq = cq->cq_next)
+ if (cq->cq_partial != NULL)
+ {
+ dtv.v_type = VAR_PARTIAL;
+ dtv.vval.v_partial = cq->cq_partial;
+ set_ref_in_item(&dtv, copyID, ht_stack, list_stack);
+ }
+ if (ch->ch_part[part].ch_partial != NULL)
+ {
+ dtv.v_type = VAR_PARTIAL;
+ dtv.vval.v_partial = ch->ch_part[part].ch_partial;
+ set_ref_in_item(&dtv, copyID, ht_stack, list_stack);
+ }
+ }
+ if (ch->ch_partial != NULL)
+ {
+ dtv.v_type = VAR_PARTIAL;
+ dtv.vval.v_partial = ch->ch_partial;
+ set_ref_in_item(&dtv, copyID, ht_stack, list_stack);
+ }
+ if (ch->ch_close_partial != NULL)
+ {
+ dtv.v_type = VAR_PARTIAL;
+ dtv.vval.v_partial = ch->ch_close_partial;
+ set_ref_in_item(&dtv, copyID, ht_stack, list_stack);
+ }
+ }
+ }
+#endif
+ return abort;
+}
+
+ static char *
+get_var_special_name(int nr)
+{
+ switch (nr)
+ {
+ case VVAL_FALSE: return "v:false";
+ case VVAL_TRUE: return "v:true";
+ case VVAL_NONE: return "v:none";
+ case VVAL_NULL: return "v:null";
+ }
+ internal_error("get_var_special_name()");
+ return "42";
+}
+
+/*
+ * Return a string with the string representation of a variable.
+ * If the memory is allocated "tofree" is set to it, otherwise NULL.
+ * "numbuf" is used for a number.
+ * When "copyID" is not NULL replace recursive lists and dicts with "...".
+ * When both "echo_style" and "composite_val" are FALSE, put quotes around
+ * stings as "string()", otherwise does not put quotes around strings, as
+ * ":echo" displays values.
+ * When "restore_copyID" is FALSE, repeated items in dictionaries and lists
+ * are replaced with "...".
+ * May return NULL.
+ */
+ char_u *
+echo_string_core(
+ typval_T *tv,
+ char_u **tofree,
+ char_u *numbuf,
+ int copyID,
+ int echo_style,
+ int restore_copyID,
+ int composite_val)
+{
+ static int recurse = 0;
+ char_u *r = NULL;
+
+ if (recurse >= DICT_MAXNEST)
+ {
+ if (!did_echo_string_emsg)
+ {
+ /* Only give this message once for a recursive call to avoid
+ * flooding the user with errors. And stop iterating over lists
+ * and dicts. */
+ did_echo_string_emsg = TRUE;
+ emsg(_("E724: variable nested too deep for displaying"));
+ }
+ *tofree = NULL;
+ return (char_u *)"{E724}";
+ }
+ ++recurse;
+
+ switch (tv->v_type)
+ {
+ case VAR_STRING:
+ if (echo_style && !composite_val)
+ {
+ *tofree = NULL;
+ r = tv->vval.v_string;
+ if (r == NULL)
+ r = (char_u *)"";
+ }
+ else
+ {
+ *tofree = string_quote(tv->vval.v_string, FALSE);
+ r = *tofree;
+ }
+ break;
+
+ case VAR_FUNC:
+ if (echo_style)
+ {
+ *tofree = NULL;
+ r = tv->vval.v_string;
+ }
+ else
+ {
+ *tofree = string_quote(tv->vval.v_string, TRUE);
+ r = *tofree;
+ }
+ break;
+
+ case VAR_PARTIAL:
+ {
+ partial_T *pt = tv->vval.v_partial;
+ char_u *fname = string_quote(pt == NULL ? NULL
+ : partial_name(pt), FALSE);
+ garray_T ga;
+ int i;
+ char_u *tf;
+
+ ga_init2(&ga, 1, 100);
+ ga_concat(&ga, (char_u *)"function(");
+ if (fname != NULL)
+ {
+ ga_concat(&ga, fname);
+ vim_free(fname);
+ }
+ if (pt != NULL && pt->pt_argc > 0)
+ {
+ ga_concat(&ga, (char_u *)", [");
+ for (i = 0; i < pt->pt_argc; ++i)
+ {
+ if (i > 0)
+ ga_concat(&ga, (char_u *)", ");
+ ga_concat(&ga,
+ tv2string(&pt->pt_argv[i], &tf, numbuf, copyID));
+ vim_free(tf);
+ }
+ ga_concat(&ga, (char_u *)"]");
+ }
+ if (pt != NULL && pt->pt_dict != NULL)
+ {
+ typval_T dtv;
+
+ ga_concat(&ga, (char_u *)", ");
+ dtv.v_type = VAR_DICT;
+ dtv.vval.v_dict = pt->pt_dict;
+ ga_concat(&ga, tv2string(&dtv, &tf, numbuf, copyID));
+ vim_free(tf);
+ }
+ ga_concat(&ga, (char_u *)")");
+
+ *tofree = ga.ga_data;
+ r = *tofree;
+ break;
+ }
+
+ case VAR_BLOB:
+ r = blob2string(tv->vval.v_blob, tofree, numbuf);
+ break;
+
+ case VAR_LIST:
+ if (tv->vval.v_list == NULL)
+ {
+ *tofree = NULL;
+ r = NULL;
+ }
+ else if (copyID != 0 && tv->vval.v_list->lv_copyID == copyID
+ && tv->vval.v_list->lv_len > 0)
+ {
+ *tofree = NULL;
+ r = (char_u *)"[...]";
+ }
+ else
+ {
+ int old_copyID = tv->vval.v_list->lv_copyID;
+
+ tv->vval.v_list->lv_copyID = copyID;
+ *tofree = list2string(tv, copyID, restore_copyID);
+ if (restore_copyID)
+ tv->vval.v_list->lv_copyID = old_copyID;
+ r = *tofree;
+ }
+ break;
+
+ case VAR_DICT:
+ if (tv->vval.v_dict == NULL)
+ {
+ *tofree = NULL;
+ r = NULL;
+ }
+ else if (copyID != 0 && tv->vval.v_dict->dv_copyID == copyID
+ && tv->vval.v_dict->dv_hashtab.ht_used != 0)
+ {
+ *tofree = NULL;
+ r = (char_u *)"{...}";
+ }
+ else
+ {
+ int old_copyID = tv->vval.v_dict->dv_copyID;
+ tv->vval.v_dict->dv_copyID = copyID;
+ *tofree = dict2string(tv, copyID, restore_copyID);
+ if (restore_copyID)
+ tv->vval.v_dict->dv_copyID = old_copyID;
+ r = *tofree;
+ }
+ break;
+
+ case VAR_NUMBER:
+ case VAR_UNKNOWN:
+ *tofree = NULL;
+ r = tv_get_string_buf(tv, numbuf);
+ break;
+
+ case VAR_JOB:
+ case VAR_CHANNEL:
+ *tofree = NULL;
+ r = tv_get_string_buf(tv, numbuf);
+ if (composite_val)
+ {
+ *tofree = string_quote(r, FALSE);
+ r = *tofree;
+ }
+ break;
+
+ case VAR_FLOAT:
+#ifdef FEAT_FLOAT
+ *tofree = NULL;
+ vim_snprintf((char *)numbuf, NUMBUFLEN, "%g", tv->vval.v_float);
+ r = numbuf;
+ break;
+#endif
+
+ case VAR_SPECIAL:
+ *tofree = NULL;
+ r = (char_u *)get_var_special_name(tv->vval.v_number);
+ break;
+ }
+
+ if (--recurse == 0)
+ did_echo_string_emsg = FALSE;
+ return r;
+}
+
+/*
+ * Return a string with the string representation of a variable.
+ * If the memory is allocated "tofree" is set to it, otherwise NULL.
+ * "numbuf" is used for a number.
+ * Does not put quotes around strings, as ":echo" displays values.
+ * When "copyID" is not NULL replace recursive lists and dicts with "...".
+ * May return NULL.
+ */
+ char_u *
+echo_string(
+ typval_T *tv,
+ char_u **tofree,
+ char_u *numbuf,
+ int copyID)
+{
+ return echo_string_core(tv, tofree, numbuf, copyID, TRUE, FALSE, FALSE);
+}
+
+/*
+ * Return a string with the string representation of a variable.
+ * If the memory is allocated "tofree" is set to it, otherwise NULL.
+ * "numbuf" is used for a number.
+ * Puts quotes around strings, so that they can be parsed back by eval().
+ * May return NULL.
+ */
+ char_u *
+tv2string(
+ typval_T *tv,
+ char_u **tofree,
+ char_u *numbuf,
+ int copyID)
+{
+ return echo_string_core(tv, tofree, numbuf, copyID, FALSE, TRUE, FALSE);
+}
+
+/*
+ * Return string "str" in ' quotes, doubling ' characters.
+ * If "str" is NULL an empty string is assumed.
+ * If "function" is TRUE make it function('string').
+ */
+ char_u *
+string_quote(char_u *str, int function)
+{
+ unsigned len;
+ char_u *p, *r, *s;
+
+ len = (function ? 13 : 3);
+ if (str != NULL)
+ {
+ len += (unsigned)STRLEN(str);
+ for (p = str; *p != NUL; MB_PTR_ADV(p))
+ if (*p == '\'')
+ ++len;
+ }
+ s = r = alloc(len);
+ if (r != NULL)
+ {
+ if (function)
+ {
+ STRCPY(r, "function('");
+ r += 10;
+ }
+ else
+ *r++ = '\'';
+ if (str != NULL)
+ for (p = str; *p != NUL; )
+ {
+ if (*p == '\'')
+ *r++ = '\'';
+ MB_COPY_CHAR(p, r);
+ }
+ *r++ = '\'';
+ if (function)
+ *r++ = ')';
+ *r++ = NUL;
+ }
+ return s;
+}
+
+#if defined(FEAT_FLOAT) || defined(PROTO)
+/*
+ * Convert the string "text" to a floating point number.
+ * This uses strtod(). setlocale(LC_NUMERIC, "C") has been used to make sure
+ * this always uses a decimal point.
+ * Returns the length of the text that was consumed.
+ */
+ int
+string2float(
+ char_u *text,
+ float_T *value) /* result stored here */
+{
+ char *s = (char *)text;
+ float_T f;
+
+ /* MS-Windows does not deal with "inf" and "nan" properly. */
+ if (STRNICMP(text, "inf", 3) == 0)
+ {
+ *value = INFINITY;
+ return 3;
+ }
+ if (STRNICMP(text, "-inf", 3) == 0)
+ {
+ *value = -INFINITY;
+ return 4;
+ }
+ if (STRNICMP(text, "nan", 3) == 0)
+ {
+ *value = NAN;
+ return 3;
+ }
+ f = strtod(s, &s);
+ *value = f;
+ return (int)((char_u *)s - text);
+}
+#endif
+
+/*
+ * Get the value of an environment variable.
+ * "arg" is pointing to the '$'. It is advanced to after the name.
+ * If the environment variable was not set, silently assume it is empty.
+ * Return FAIL if the name is invalid.
+ */
+ static int
+get_env_tv(char_u **arg, typval_T *rettv, int evaluate)
+{
+ char_u *string = NULL;
+ int len;
+ int cc;
+ char_u *name;
+ int mustfree = FALSE;
+
+ ++*arg;
+ name = *arg;
+ len = get_env_len(arg);
+ if (evaluate)
+ {
+ if (len == 0)
+ return FAIL; /* invalid empty name */
+
+ cc = name[len];
+ name[len] = NUL;
+ /* first try vim_getenv(), fast for normal environment vars */
+ string = vim_getenv(name, &mustfree);
+ if (string != NULL && *string != NUL)
+ {
+ if (!mustfree)
+ string = vim_strsave(string);
+ }
+ else
+ {
+ if (mustfree)
+ vim_free(string);
+
+ /* next try expanding things like $VIM and ${HOME} */
+ string = expand_env_save(name - 1);
+ if (string != NULL && *string == '$')
+ VIM_CLEAR(string);
+ }
+ name[len] = cc;
+
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = string;
+ }
+
+ return OK;
+}
+
+
+
+/*
+ * Translate a String variable into a position.
+ * Returns NULL when there is an error.
+ */
+ pos_T *
+var2fpos(
+ typval_T *varp,
+ int dollar_lnum, /* TRUE when $ is last line */
+ int *fnum) /* set to fnum for '0, 'A, etc. */
+{
+ char_u *name;
+ static pos_T pos;
+ pos_T *pp;
+
+ /* Argument can be [lnum, col, coladd]. */
+ if (varp->v_type == VAR_LIST)
+ {
+ list_T *l;
+ int len;
+ int error = FALSE;
+ listitem_T *li;
+
+ l = varp->vval.v_list;
+ if (l == NULL)
+ return NULL;
+
+ /* Get the line number */
+ pos.lnum = list_find_nr(l, 0L, &error);
+ if (error || pos.lnum <= 0 || pos.lnum > curbuf->b_ml.ml_line_count)
+ return NULL; /* invalid line number */
+
+ /* Get the column number */
+ pos.col = list_find_nr(l, 1L, &error);
+ if (error)
+ return NULL;
+ len = (long)STRLEN(ml_get(pos.lnum));
+
+ /* We accept "$" for the column number: last column. */
+ li = list_find(l, 1L);
+ if (li != NULL && li->li_tv.v_type == VAR_STRING
+ && li->li_tv.vval.v_string != NULL
+ && STRCMP(li->li_tv.vval.v_string, "$") == 0)
+ pos.col = len + 1;
+
+ /* Accept a position up to the NUL after the line. */
+ if (pos.col == 0 || (int)pos.col > len + 1)
+ return NULL; /* invalid column number */
+ --pos.col;
+
+ /* Get the virtual offset. Defaults to zero. */
+ pos.coladd = list_find_nr(l, 2L, &error);
+ if (error)
+ pos.coladd = 0;
+
+ return &pos;
+ }
+
+ name = tv_get_string_chk(varp);
+ if (name == NULL)
+ return NULL;
+ if (name[0] == '.') /* cursor */
+ return &curwin->w_cursor;
+ if (name[0] == 'v' && name[1] == NUL) /* Visual start */
+ {
+ if (VIsual_active)
+ return &VIsual;
+ return &curwin->w_cursor;
+ }
+ if (name[0] == '\'') /* mark */
+ {
+ pp = getmark_buf_fnum(curbuf, name[1], FALSE, fnum);
+ if (pp == NULL || pp == (pos_T *)-1 || pp->lnum <= 0)
+ return NULL;
+ return pp;
+ }
+
+ pos.coladd = 0;
+
+ if (name[0] == 'w' && dollar_lnum)
+ {
+ pos.col = 0;
+ if (name[1] == '0') /* "w0": first visible line */
+ {
+ update_topline();
+ /* In silent Ex mode topline is zero, but that's not a valid line
+ * number; use one instead. */
+ pos.lnum = curwin->w_topline > 0 ? curwin->w_topline : 1;
+ return &pos;
+ }
+ else if (name[1] == '$') /* "w$": last visible line */
+ {
+ validate_botline();
+ /* In silent Ex mode botline is zero, return zero then. */
+ pos.lnum = curwin->w_botline > 0 ? curwin->w_botline - 1 : 0;
+ return &pos;
+ }
+ }
+ else if (name[0] == '$') /* last column or line */
+ {
+ if (dollar_lnum)
+ {
+ pos.lnum = curbuf->b_ml.ml_line_count;
+ pos.col = 0;
+ }
+ else
+ {
+ pos.lnum = curwin->w_cursor.lnum;
+ pos.col = (colnr_T)STRLEN(ml_get_curline());
+ }
+ return &pos;
+ }
+ return NULL;
+}
+
+/*
+ * Convert list in "arg" into a position and optional file number.
+ * When "fnump" is NULL there is no file number, only 3 items.
+ * Note that the column is passed on as-is, the caller may want to decrement
+ * it to use 1 for the first column.
+ * Return FAIL when conversion is not possible, doesn't check the position for
+ * validity.
+ */
+ int
+list2fpos(
+ typval_T *arg,
+ pos_T *posp,
+ int *fnump,
+ colnr_T *curswantp)
+{
+ list_T *l = arg->vval.v_list;
+ long i = 0;
+ long n;
+
+ /* List must be: [fnum, lnum, col, coladd, curswant], where "fnum" is only
+ * there when "fnump" isn't NULL; "coladd" and "curswant" are optional. */
+ if (arg->v_type != VAR_LIST
+ || l == NULL
+ || l->lv_len < (fnump == NULL ? 2 : 3)
+ || l->lv_len > (fnump == NULL ? 4 : 5))
+ return FAIL;
+
+ if (fnump != NULL)
+ {
+ n = list_find_nr(l, i++, NULL); /* fnum */
+ if (n < 0)
+ return FAIL;
+ if (n == 0)
+ n = curbuf->b_fnum; /* current buffer */
+ *fnump = n;
+ }
+
+ n = list_find_nr(l, i++, NULL); /* lnum */
+ if (n < 0)
+ return FAIL;
+ posp->lnum = n;
+
+ n = list_find_nr(l, i++, NULL); /* col */
+ if (n < 0)
+ return FAIL;
+ posp->col = n;
+
+ n = list_find_nr(l, i, NULL); /* off */
+ if (n < 0)
+ posp->coladd = 0;
+ else
+ posp->coladd = n;
+
+ if (curswantp != NULL)
+ *curswantp = list_find_nr(l, i + 1, NULL); /* curswant */
+
+ return OK;
+}
+
+/*
+ * Get the length of an environment variable name.
+ * Advance "arg" to the first character after the name.
+ * Return 0 for error.
+ */
+ static int
+get_env_len(char_u **arg)
+{
+ char_u *p;
+ int len;
+
+ for (p = *arg; vim_isIDc(*p); ++p)
+ ;
+ if (p == *arg) /* no name found */
+ return 0;
+
+ len = (int)(p - *arg);
+ *arg = p;
+ return len;
+}
+
+/*
+ * Get the length of the name of a function or internal variable.
+ * "arg" is advanced to the first non-white character after the name.
+ * Return 0 if something is wrong.
+ */
+ int
+get_id_len(char_u **arg)
+{
+ char_u *p;
+ int len;
+
+ /* Find the end of the name. */
+ for (p = *arg; eval_isnamec(*p); ++p)
+ {
+ if (*p == ':')
+ {
+ /* "s:" is start of "s:var", but "n:" is not and can be used in
+ * slice "[n:]". Also "xx:" is not a namespace. */
+ len = (int)(p - *arg);
+ if ((len == 1 && vim_strchr(NAMESPACE_CHAR, **arg) == NULL)
+ || len > 1)
+ break;
+ }
+ }
+ if (p == *arg) /* no name found */
+ return 0;
+
+ len = (int)(p - *arg);
+ *arg = skipwhite(p);
+
+ return len;
+}
+
+/*
+ * Get the length of the name of a variable or function.
+ * Only the name is recognized, does not handle ".key" or "[idx]".
+ * "arg" is advanced to the first non-white character after the name.
+ * Return -1 if curly braces expansion failed.
+ * Return 0 if something else is wrong.
+ * If the name contains 'magic' {}'s, expand them and return the
+ * expanded name in an allocated string via 'alias' - caller must free.
+ */
+ int
+get_name_len(
+ char_u **arg,
+ char_u **alias,
+ int evaluate,
+ int verbose)
+{
+ int len;
+ char_u *p;
+ char_u *expr_start;
+ char_u *expr_end;
+
+ *alias = NULL; /* default to no alias */
+
+ if ((*arg)[0] == K_SPECIAL && (*arg)[1] == KS_EXTRA
+ && (*arg)[2] == (int)KE_SNR)
+ {
+ /* hard coded <SNR>, already translated */
+ *arg += 3;
+ return get_id_len(arg) + 3;
+ }
+ len = eval_fname_script(*arg);
+ if (len > 0)
+ {
+ /* literal "<SID>", "s:" or "<SNR>" */
+ *arg += len;
+ }
+
+ /*
+ * Find the end of the name; check for {} construction.
+ */
+ p = find_name_end(*arg, &expr_start, &expr_end,
+ len > 0 ? 0 : FNE_CHECK_START);
+ if (expr_start != NULL)
+ {
+ char_u *temp_string;
+
+ if (!evaluate)
+ {
+ len += (int)(p - *arg);
+ *arg = skipwhite(p);
+ return len;
+ }
+
+ /*
+ * Include any <SID> etc in the expanded string:
+ * Thus the -len here.
+ */
+ temp_string = make_expanded_name(*arg - len, expr_start, expr_end, p);
+ if (temp_string == NULL)
+ return -1;
+ *alias = temp_string;
+ *arg = skipwhite(p);
+ return (int)STRLEN(temp_string);
+ }
+
+ len += get_id_len(arg);
+ // Only give an error when there is something, otherwise it will be
+ // reported at a higher level.
+ if (len == 0 && verbose && **arg != NUL)
+ semsg(_(e_invexpr2), *arg);
+
+ return len;
+}
+
+/*
+ * Find the end of a variable or function name, taking care of magic braces.
+ * If "expr_start" is not NULL then "expr_start" and "expr_end" are set to the
+ * start and end of the first magic braces item.
+ * "flags" can have FNE_INCL_BR and FNE_CHECK_START.
+ * Return a pointer to just after the name. Equal to "arg" if there is no
+ * valid name.
+ */
+ char_u *
+find_name_end(
+ char_u *arg,
+ char_u **expr_start,
+ char_u **expr_end,
+ int flags)
+{
+ int mb_nest = 0;
+ int br_nest = 0;
+ char_u *p;
+ int len;
+
+ if (expr_start != NULL)
+ {
+ *expr_start = NULL;
+ *expr_end = NULL;
+ }
+
+ /* Quick check for valid starting character. */
+ if ((flags & FNE_CHECK_START) && !eval_isnamec1(*arg) && *arg != '{')
+ return arg;
+
+ for (p = arg; *p != NUL
+ && (eval_isnamec(*p)
+ || *p == '{'
+ || ((flags & FNE_INCL_BR) && (*p == '[' || *p == '.'))
+ || mb_nest != 0
+ || br_nest != 0); MB_PTR_ADV(p))
+ {
+ if (*p == '\'')
+ {
+ /* skip over 'string' to avoid counting [ and ] inside it. */
+ for (p = p + 1; *p != NUL && *p != '\''; MB_PTR_ADV(p))
+ ;
+ if (*p == NUL)
+ break;
+ }
+ else if (*p == '"')
+ {
+ /* skip over "str\"ing" to avoid counting [ and ] inside it. */
+ for (p = p + 1; *p != NUL && *p != '"'; MB_PTR_ADV(p))
+ if (*p == '\\' && p[1] != NUL)
+ ++p;
+ if (*p == NUL)
+ break;
+ }
+ else if (br_nest == 0 && mb_nest == 0 && *p == ':')
+ {
+ /* "s:" is start of "s:var", but "n:" is not and can be used in
+ * slice "[n:]". Also "xx:" is not a namespace. But {ns}: is. */
+ len = (int)(p - arg);
+ if ((len == 1 && vim_strchr(NAMESPACE_CHAR, *arg) == NULL)
+ || (len > 1 && p[-1] != '}'))
+ break;
+ }
+
+ if (mb_nest == 0)
+ {
+ if (*p == '[')
+ ++br_nest;
+ else if (*p == ']')
+ --br_nest;
+ }
+
+ if (br_nest == 0)
+ {
+ if (*p == '{')
+ {
+ mb_nest++;
+ if (expr_start != NULL && *expr_start == NULL)
+ *expr_start = p;
+ }
+ else if (*p == '}')
+ {
+ mb_nest--;
+ if (expr_start != NULL && mb_nest == 0 && *expr_end == NULL)
+ *expr_end = p;
+ }
+ }
+ }
+
+ return p;
+}
+
+/*
+ * Expands out the 'magic' {}'s in a variable/function name.
+ * Note that this can call itself recursively, to deal with
+ * constructs like foo{bar}{baz}{bam}
+ * The four pointer arguments point to "foo{expre}ss{ion}bar"
+ * "in_start" ^
+ * "expr_start" ^
+ * "expr_end" ^
+ * "in_end" ^
+ *
+ * Returns a new allocated string, which the caller must free.
+ * Returns NULL for failure.
+ */
+ static char_u *
+make_expanded_name(
+ char_u *in_start,
+ char_u *expr_start,
+ char_u *expr_end,
+ char_u *in_end)
+{
+ char_u c1;
+ char_u *retval = NULL;
+ char_u *temp_result;
+ char_u *nextcmd = NULL;
+
+ if (expr_end == NULL || in_end == NULL)
+ return NULL;
+ *expr_start = NUL;
+ *expr_end = NUL;
+ c1 = *in_end;
+ *in_end = NUL;
+
+ temp_result = eval_to_string(expr_start + 1, &nextcmd, FALSE);
+ if (temp_result != NULL && nextcmd == NULL)
+ {
+ retval = alloc((unsigned)(STRLEN(temp_result) + (expr_start - in_start)
+ + (in_end - expr_end) + 1));
+ if (retval != NULL)
+ {
+ STRCPY(retval, in_start);
+ STRCAT(retval, temp_result);
+ STRCAT(retval, expr_end + 1);
+ }
+ }
+ vim_free(temp_result);
+
+ *in_end = c1; /* put char back for error messages */
+ *expr_start = '{';
+ *expr_end = '}';
+
+ if (retval != NULL)
+ {
+ temp_result = find_name_end(retval, &expr_start, &expr_end, 0);
+ if (expr_start != NULL)
+ {
+ /* Further expansion! */
+ temp_result = make_expanded_name(retval, expr_start,
+ expr_end, temp_result);
+ vim_free(retval);
+ retval = temp_result;
+ }
+ }
+
+ return retval;
+}
+
+/*
+ * Return TRUE if character "c" can be used in a variable or function name.
+ * Does not include '{' or '}' for magic braces.
+ */
+ int
+eval_isnamec(int c)
+{
+ return (ASCII_ISALNUM(c) || c == '_' || c == ':' || c == AUTOLOAD_CHAR);
+}
+
+/*
+ * Return TRUE if character "c" can be used as the first character in a
+ * variable or function name (excluding '{' and '}').
+ */
+ int
+eval_isnamec1(int c)
+{
+ return (ASCII_ISALPHA(c) || c == '_');
+}
+
+/*
+ * Set number v: variable to "val".
+ */
+ void
+set_vim_var_nr(int idx, varnumber_T val)
+{
+ vimvars[idx].vv_nr = val;
+}
+
+/*
+ * Get number v: variable value.
+ */
+ varnumber_T
+get_vim_var_nr(int idx)
+{
+ return vimvars[idx].vv_nr;
+}
+
+/*
+ * Get string v: variable value. Uses a static buffer, can only be used once.
+ * If the String variable has never been set, return an empty string.
+ * Never returns NULL;
+ */
+ char_u *
+get_vim_var_str(int idx)
+{
+ return tv_get_string(&vimvars[idx].vv_tv);
+}
+
+/*
+ * Get List v: variable value. Caller must take care of reference count when
+ * needed.
+ */
+ list_T *
+get_vim_var_list(int idx)
+{
+ return vimvars[idx].vv_list;
+}
+
+/*
+ * Get Dict v: variable value. Caller must take care of reference count when
+ * needed.
+ */
+ dict_T *
+get_vim_var_dict(int idx)
+{
+ return vimvars[idx].vv_dict;
+}
+
+/*
+ * Set v:char to character "c".
+ */
+ void
+set_vim_var_char(int c)
+{
+ char_u buf[MB_MAXBYTES + 1];
+
+ if (has_mbyte)
+ buf[(*mb_char2bytes)(c, buf)] = NUL;
+ else
+ {
+ buf[0] = c;
+ buf[1] = NUL;
+ }
+ set_vim_var_string(VV_CHAR, buf, -1);
+}
+
+/*
+ * Set v:count to "count" and v:count1 to "count1".
+ * When "set_prevcount" is TRUE first set v:prevcount from v:count.
+ */
+ void
+set_vcount(
+ long count,
+ long count1,
+ int set_prevcount)
+{
+ if (set_prevcount)
+ vimvars[VV_PREVCOUNT].vv_nr = vimvars[VV_COUNT].vv_nr;
+ vimvars[VV_COUNT].vv_nr = count;
+ vimvars[VV_COUNT1].vv_nr = count1;
+}
+
+/*
+ * Save variables that might be changed as a side effect. Used when executing
+ * a timer callback.
+ */
+ void
+save_vimvars(vimvars_save_T *vvsave)
+{
+ vvsave->vv_prevcount = vimvars[VV_PREVCOUNT].vv_nr;
+ vvsave->vv_count = vimvars[VV_COUNT].vv_nr;
+ vvsave->vv_count1 = vimvars[VV_COUNT1].vv_nr;
+}
+
+/*
+ * Restore variables saved by save_vimvars().
+ */
+ void
+restore_vimvars(vimvars_save_T *vvsave)
+{
+ vimvars[VV_PREVCOUNT].vv_nr = vvsave->vv_prevcount;
+ vimvars[VV_COUNT].vv_nr = vvsave->vv_count;
+ vimvars[VV_COUNT1].vv_nr = vvsave->vv_count1;
+}
+
+/*
+ * Set string v: variable to a copy of "val".
+ */
+ void
+set_vim_var_string(
+ int idx,
+ char_u *val,
+ int len) /* length of "val" to use or -1 (whole string) */
+{
+ clear_tv(&vimvars[idx].vv_di.di_tv);
+ vimvars[idx].vv_type = VAR_STRING;
+ if (val == NULL)
+ vimvars[idx].vv_str = NULL;
+ else if (len == -1)
+ vimvars[idx].vv_str = vim_strsave(val);
+ else
+ vimvars[idx].vv_str = vim_strnsave(val, len);
+}
+
+/*
+ * Set List v: variable to "val".
+ */
+ void
+set_vim_var_list(int idx, list_T *val)
+{
+ clear_tv(&vimvars[idx].vv_di.di_tv);
+ vimvars[idx].vv_type = VAR_LIST;
+ vimvars[idx].vv_list = val;
+ if (val != NULL)
+ ++val->lv_refcount;
+}
+
+/*
+ * Set Dictionary v: variable to "val".
+ */
+ void
+set_vim_var_dict(int idx, dict_T *val)
+{
+ clear_tv(&vimvars[idx].vv_di.di_tv);
+ vimvars[idx].vv_type = VAR_DICT;
+ vimvars[idx].vv_dict = val;
+ if (val != NULL)
+ {
+ ++val->dv_refcount;
+ dict_set_items_ro(val);
+ }
+}
+
+/*
+ * Set v:register if needed.
+ */
+ void
+set_reg_var(int c)
+{
+ char_u regname;
+
+ if (c == 0 || c == ' ')
+ regname = '"';
+ else
+ regname = c;
+ /* Avoid free/alloc when the value is already right. */
+ if (vimvars[VV_REG].vv_str == NULL || vimvars[VV_REG].vv_str[0] != c)
+ set_vim_var_string(VV_REG, &regname, 1);
+}
+
+/*
+ * Get or set v:exception. If "oldval" == NULL, return the current value.
+ * Otherwise, restore the value to "oldval" and return NULL.
+ * Must always be called in pairs to save and restore v:exception! Does not
+ * take care of memory allocations.
+ */
+ char_u *
+v_exception(char_u *oldval)
+{
+ if (oldval == NULL)
+ return vimvars[VV_EXCEPTION].vv_str;
+
+ vimvars[VV_EXCEPTION].vv_str = oldval;
+ return NULL;
+}
+
+/*
+ * Get or set v:throwpoint. If "oldval" == NULL, return the current value.
+ * Otherwise, restore the value to "oldval" and return NULL.
+ * Must always be called in pairs to save and restore v:throwpoint! Does not
+ * take care of memory allocations.
+ */
+ char_u *
+v_throwpoint(char_u *oldval)
+{
+ if (oldval == NULL)
+ return vimvars[VV_THROWPOINT].vv_str;
+
+ vimvars[VV_THROWPOINT].vv_str = oldval;
+ return NULL;
+}
+
+/*
+ * Set v:cmdarg.
+ * If "eap" != NULL, use "eap" to generate the value and return the old value.
+ * If "oldarg" != NULL, restore the value to "oldarg" and return NULL.
+ * Must always be called in pairs!
+ */
+ char_u *
+set_cmdarg(exarg_T *eap, char_u *oldarg)
+{
+ char_u *oldval;
+ char_u *newval;
+ unsigned len;
+
+ oldval = vimvars[VV_CMDARG].vv_str;
+ if (eap == NULL)
+ {
+ vim_free(oldval);
+ vimvars[VV_CMDARG].vv_str = oldarg;
+ return NULL;
+ }
+
+ if (eap->force_bin == FORCE_BIN)
+ len = 6;
+ else if (eap->force_bin == FORCE_NOBIN)
+ len = 8;
+ else
+ len = 0;
+
+ if (eap->read_edit)
+ len += 7;
+
+ if (eap->force_ff != 0)
+ len += 10; /* " ++ff=unix" */
+ if (eap->force_enc != 0)
+ len += (unsigned)STRLEN(eap->cmd + eap->force_enc) + 7;
+ if (eap->bad_char != 0)
+ len += 7 + 4; /* " ++bad=" + "keep" or "drop" */
+
+ newval = alloc(len + 1);
+ if (newval == NULL)
+ return NULL;
+
+ if (eap->force_bin == FORCE_BIN)
+ sprintf((char *)newval, " ++bin");
+ else if (eap->force_bin == FORCE_NOBIN)
+ sprintf((char *)newval, " ++nobin");
+ else
+ *newval = NUL;
+
+ if (eap->read_edit)
+ STRCAT(newval, " ++edit");
+
+ if (eap->force_ff != 0)
+ sprintf((char *)newval + STRLEN(newval), " ++ff=%s",
+ eap->force_ff == 'u' ? "unix"
+ : eap->force_ff == 'd' ? "dos"
+ : "mac");
+ if (eap->force_enc != 0)
+ sprintf((char *)newval + STRLEN(newval), " ++enc=%s",
+ eap->cmd + eap->force_enc);
+ if (eap->bad_char == BAD_KEEP)
+ STRCPY(newval + STRLEN(newval), " ++bad=keep");
+ else if (eap->bad_char == BAD_DROP)
+ STRCPY(newval + STRLEN(newval), " ++bad=drop");
+ else if (eap->bad_char != 0)
+ sprintf((char *)newval + STRLEN(newval), " ++bad=%c", eap->bad_char);
+ vimvars[VV_CMDARG].vv_str = newval;
+ return oldval;
+}
+
+/*
+ * Get the value of internal variable "name".
+ * Return OK or FAIL. If OK is returned "rettv" must be cleared.
+ */
+ int
+get_var_tv(
+ char_u *name,
+ int len, /* length of "name" */
+ typval_T *rettv, /* NULL when only checking existence */
+ dictitem_T **dip, /* non-NULL when typval's dict item is needed */
+ int verbose, /* may give error message */
+ int no_autoload) /* do not use script autoloading */
+{
+ int ret = OK;
+ typval_T *tv = NULL;
+ dictitem_T *v;
+ int cc;
+
+ /* truncate the name, so that we can use strcmp() */
+ cc = name[len];
+ name[len] = NUL;
+
+ /*
+ * Check for user-defined variables.
+ */
+ v = find_var(name, NULL, no_autoload);
+ if (v != NULL)
+ {
+ tv = &v->di_tv;
+ if (dip != NULL)
+ *dip = v;
+ }
+
+ if (tv == NULL)
+ {
+ if (rettv != NULL && verbose)
+ semsg(_(e_undefvar), name);
+ ret = FAIL;
+ }
+ else if (rettv != NULL)
+ copy_tv(tv, rettv);
+
+ name[len] = cc;
+
+ return ret;
+}
+
+/*
+ * Check if variable "name[len]" is a local variable or an argument.
+ * If so, "*eval_lavars_used" is set to TRUE.
+ */
+ static void
+check_vars(char_u *name, int len)
+{
+ int cc;
+ char_u *varname;
+ hashtab_T *ht;
+
+ if (eval_lavars_used == NULL)
+ return;
+
+ /* truncate the name, so that we can use strcmp() */
+ cc = name[len];
+ name[len] = NUL;
+
+ ht = find_var_ht(name, &varname);
+ if (ht == get_funccal_local_ht() || ht == get_funccal_args_ht())
+ {
+ if (find_var(name, NULL, TRUE) != NULL)
+ *eval_lavars_used = TRUE;
+ }
+
+ name[len] = cc;
+}
+
+/*
+ * Handle expr[expr], expr[expr:expr] subscript and .name lookup.
+ * Also handle function call with Funcref variable: func(expr)
+ * Can all be combined: dict.func(expr)[idx]['func'](expr)
+ */
+ int
+handle_subscript(
+ char_u **arg,
+ typval_T *rettv,
+ int evaluate, /* do more than finding the end */
+ int verbose) /* give error messages */
+{
+ int ret = OK;
+ dict_T *selfdict = NULL;
+ char_u *s;
+ int len;
+ typval_T functv;
+
+ while (ret == OK
+ && (**arg == '['
+ || (**arg == '.' && rettv->v_type == VAR_DICT)
+ || (**arg == '(' && (!evaluate || rettv->v_type == VAR_FUNC
+ || rettv->v_type == VAR_PARTIAL)))
+ && !VIM_ISWHITE(*(*arg - 1)))
+ {
+ if (**arg == '(')
+ {
+ partial_T *pt = NULL;
+
+ /* need to copy the funcref so that we can clear rettv */
+ if (evaluate)
+ {
+ functv = *rettv;
+ rettv->v_type = VAR_UNKNOWN;
+
+ /* Invoke the function. Recursive! */
+ if (functv.v_type == VAR_PARTIAL)
+ {
+ pt = functv.vval.v_partial;
+ s = partial_name(pt);
+ }
+ else
+ s = functv.vval.v_string;
+ }
+ else
+ s = (char_u *)"";
+ ret = get_func_tv(s, (int)STRLEN(s), rettv, arg,
+ curwin->w_cursor.lnum, curwin->w_cursor.lnum,
+ &len, evaluate, pt, selfdict);
+
+ /* Clear the funcref afterwards, so that deleting it while
+ * evaluating the arguments is possible (see test55). */
+ if (evaluate)
+ clear_tv(&functv);
+
+ /* Stop the expression evaluation when immediately aborting on
+ * error, or when an interrupt occurred or an exception was thrown
+ * but not caught. */
+ if (aborting())
+ {
+ if (ret == OK)
+ clear_tv(rettv);
+ ret = FAIL;
+ }
+ dict_unref(selfdict);
+ selfdict = NULL;
+ }
+ else /* **arg == '[' || **arg == '.' */
+ {
+ dict_unref(selfdict);
+ if (rettv->v_type == VAR_DICT)
+ {
+ selfdict = rettv->vval.v_dict;
+ if (selfdict != NULL)
+ ++selfdict->dv_refcount;
+ }
+ else
+ selfdict = NULL;
+ if (eval_index(arg, rettv, evaluate, verbose) == FAIL)
+ {
+ clear_tv(rettv);
+ ret = FAIL;
+ }
+ }
+ }
+
+ /* Turn "dict.Func" into a partial for "Func" bound to "dict".
+ * Don't do this when "Func" is already a partial that was bound
+ * explicitly (pt_auto is FALSE). */
+ if (selfdict != NULL
+ && (rettv->v_type == VAR_FUNC
+ || (rettv->v_type == VAR_PARTIAL
+ && (rettv->vval.v_partial->pt_auto
+ || rettv->vval.v_partial->pt_dict == NULL))))
+ selfdict = make_partial(selfdict, rettv);
+
+ dict_unref(selfdict);
+ return ret;
+}
+
+/*
+ * Allocate memory for a variable type-value, and make it empty (0 or NULL
+ * value).
+ */
+ typval_T *
+alloc_tv(void)
+{
+ return (typval_T *)alloc_clear((unsigned)sizeof(typval_T));
+}
+
+/*
+ * Allocate memory for a variable type-value, and assign a string to it.
+ * The string "s" must have been allocated, it is consumed.
+ * Return NULL for out of memory, the variable otherwise.
+ */
+ static typval_T *
+alloc_string_tv(char_u *s)
+{
+ typval_T *rettv;
+
+ rettv = alloc_tv();
+ if (rettv != NULL)
+ {
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = s;
+ }
+ else
+ vim_free(s);
+ return rettv;
+}
+
+/*
+ * Free the memory for a variable type-value.
+ */
+ void
+free_tv(typval_T *varp)
+{
+ if (varp != NULL)
+ {
+ switch (varp->v_type)
+ {
+ case VAR_FUNC:
+ func_unref(varp->vval.v_string);
+ /* FALLTHROUGH */
+ case VAR_STRING:
+ vim_free(varp->vval.v_string);
+ break;
+ case VAR_PARTIAL:
+ partial_unref(varp->vval.v_partial);
+ break;
+ case VAR_BLOB:
+ blob_unref(varp->vval.v_blob);
+ break;
+ case VAR_LIST:
+ list_unref(varp->vval.v_list);
+ break;
+ case VAR_DICT:
+ dict_unref(varp->vval.v_dict);
+ break;
+ case VAR_JOB:
+#ifdef FEAT_JOB_CHANNEL
+ job_unref(varp->vval.v_job);
+ break;
+#endif
+ case VAR_CHANNEL:
+#ifdef FEAT_JOB_CHANNEL
+ channel_unref(varp->vval.v_channel);
+ break;
+#endif
+ case VAR_NUMBER:
+ case VAR_FLOAT:
+ case VAR_UNKNOWN:
+ case VAR_SPECIAL:
+ break;
+ }
+ vim_free(varp);
+ }
+}
+
+/*
+ * Free the memory for a variable value and set the value to NULL or 0.
+ */
+ void
+clear_tv(typval_T *varp)
+{
+ if (varp != NULL)
+ {
+ switch (varp->v_type)
+ {
+ case VAR_FUNC:
+ func_unref(varp->vval.v_string);
+ /* FALLTHROUGH */
+ case VAR_STRING:
+ VIM_CLEAR(varp->vval.v_string);
+ break;
+ case VAR_PARTIAL:
+ partial_unref(varp->vval.v_partial);
+ varp->vval.v_partial = NULL;
+ break;
+ case VAR_BLOB:
+ blob_unref(varp->vval.v_blob);
+ varp->vval.v_blob = NULL;
+ break;
+ case VAR_LIST:
+ list_unref(varp->vval.v_list);
+ varp->vval.v_list = NULL;
+ break;
+ case VAR_DICT:
+ dict_unref(varp->vval.v_dict);
+ varp->vval.v_dict = NULL;
+ break;
+ case VAR_NUMBER:
+ case VAR_SPECIAL:
+ varp->vval.v_number = 0;
+ break;
+ case VAR_FLOAT:
+#ifdef FEAT_FLOAT
+ varp->vval.v_float = 0.0;
+ break;
+#endif
+ case VAR_JOB:
+#ifdef FEAT_JOB_CHANNEL
+ job_unref(varp->vval.v_job);
+ varp->vval.v_job = NULL;
+#endif
+ break;
+ case VAR_CHANNEL:
+#ifdef FEAT_JOB_CHANNEL
+ channel_unref(varp->vval.v_channel);
+ varp->vval.v_channel = NULL;
+#endif
+ case VAR_UNKNOWN:
+ break;
+ }
+ varp->v_lock = 0;
+ }
+}
+
+/*
+ * Set the value of a variable to NULL without freeing items.
+ */
+ void
+init_tv(typval_T *varp)
+{
+ if (varp != NULL)
+ vim_memset(varp, 0, sizeof(typval_T));
+}
+
+/*
+ * Get the number value of a variable.
+ * If it is a String variable, uses vim_str2nr().
+ * For incompatible types, return 0.
+ * tv_get_number_chk() is similar to tv_get_number(), but informs the
+ * caller of incompatible types: it sets *denote to TRUE if "denote"
+ * is not NULL or returns -1 otherwise.
+ */
+ varnumber_T
+tv_get_number(typval_T *varp)
+{
+ int error = FALSE;
+
+ return tv_get_number_chk(varp, &error); /* return 0L on error */
+}
+
+ varnumber_T
+tv_get_number_chk(typval_T *varp, int *denote)
+{
+ varnumber_T n = 0L;
+
+ switch (varp->v_type)
+ {
+ case VAR_NUMBER:
+ return varp->vval.v_number;
+ case VAR_FLOAT:
+#ifdef FEAT_FLOAT
+ emsg(_("E805: Using a Float as a Number"));
+ break;
+#endif
+ case VAR_FUNC:
+ case VAR_PARTIAL:
+ emsg(_("E703: Using a Funcref as a Number"));
+ break;
+ case VAR_STRING:
+ if (varp->vval.v_string != NULL)
+ vim_str2nr(varp->vval.v_string, NULL, NULL,
+ STR2NR_ALL, &n, NULL, 0);
+ return n;
+ case VAR_LIST:
+ emsg(_("E745: Using a List as a Number"));
+ break;
+ case VAR_DICT:
+ emsg(_("E728: Using a Dictionary as a Number"));
+ break;
+ case VAR_SPECIAL:
+ return varp->vval.v_number == VVAL_TRUE ? 1 : 0;
+ break;
+ case VAR_JOB:
+#ifdef FEAT_JOB_CHANNEL
+ emsg(_("E910: Using a Job as a Number"));
+ break;
+#endif
+ case VAR_CHANNEL:
+#ifdef FEAT_JOB_CHANNEL
+ emsg(_("E913: Using a Channel as a Number"));
+ break;
+#endif
+ case VAR_BLOB:
+ emsg(_("E974: Using a Blob as a Number"));
+ break;
+ case VAR_UNKNOWN:
+ internal_error("tv_get_number(UNKNOWN)");
+ break;
+ }
+ if (denote == NULL) /* useful for values that must be unsigned */
+ n = -1;
+ else
+ *denote = TRUE;
+ return n;
+}
+
+#ifdef FEAT_FLOAT
+ float_T
+tv_get_float(typval_T *varp)
+{
+ switch (varp->v_type)
+ {
+ case VAR_NUMBER:
+ return (float_T)(varp->vval.v_number);
+ case VAR_FLOAT:
+ return varp->vval.v_float;
+ case VAR_FUNC:
+ case VAR_PARTIAL:
+ emsg(_("E891: Using a Funcref as a Float"));
+ break;
+ case VAR_STRING:
+ emsg(_("E892: Using a String as a Float"));
+ break;
+ case VAR_LIST:
+ emsg(_("E893: Using a List as a Float"));
+ break;
+ case VAR_DICT:
+ emsg(_("E894: Using a Dictionary as a Float"));
+ break;
+ case VAR_SPECIAL:
+ emsg(_("E907: Using a special value as a Float"));
+ break;
+ case VAR_JOB:
+# ifdef FEAT_JOB_CHANNEL
+ emsg(_("E911: Using a Job as a Float"));
+ break;
+# endif
+ case VAR_CHANNEL:
+# ifdef FEAT_JOB_CHANNEL
+ emsg(_("E914: Using a Channel as a Float"));
+ break;
+# endif
+ case VAR_BLOB:
+ emsg(_("E975: Using a Blob as a Float"));
+ break;
+ case VAR_UNKNOWN:
+ internal_error("tv_get_float(UNKNOWN)");
+ break;
+ }
+ return 0;
+}
+#endif
+
+/*
+ * Get the string value of a variable.
+ * If it is a Number variable, the number is converted into a string.
+ * tv_get_string() uses a single, static buffer. YOU CAN ONLY USE IT ONCE!
+ * tv_get_string_buf() uses a given buffer.
+ * If the String variable has never been set, return an empty string.
+ * Never returns NULL;
+ * tv_get_string_chk() and tv_get_string_buf_chk() are similar, but return
+ * NULL on error.
+ */
+ char_u *
+tv_get_string(typval_T *varp)
+{
+ static char_u mybuf[NUMBUFLEN];
+
+ return tv_get_string_buf(varp, mybuf);
+}
+
+ char_u *
+tv_get_string_buf(typval_T *varp, char_u *buf)
+{
+ char_u *res = tv_get_string_buf_chk(varp, buf);
+
+ return res != NULL ? res : (char_u *)"";
+}
+
+/*
+ * Careful: This uses a single, static buffer. YOU CAN ONLY USE IT ONCE!
+ */
+ char_u *
+tv_get_string_chk(typval_T *varp)
+{
+ static char_u mybuf[NUMBUFLEN];
+
+ return tv_get_string_buf_chk(varp, mybuf);
+}
+
+ char_u *
+tv_get_string_buf_chk(typval_T *varp, char_u *buf)
+{
+ switch (varp->v_type)
+ {
+ case VAR_NUMBER:
+ vim_snprintf((char *)buf, NUMBUFLEN, "%lld",
+ (long_long_T)varp->vval.v_number);
+ return buf;
+ case VAR_FUNC:
+ case VAR_PARTIAL:
+ emsg(_("E729: using Funcref as a String"));
+ break;
+ case VAR_LIST:
+ emsg(_("E730: using List as a String"));
+ break;
+ case VAR_DICT:
+ emsg(_("E731: using Dictionary as a String"));
+ break;
+ case VAR_FLOAT:
+#ifdef FEAT_FLOAT
+ emsg(_(e_float_as_string));
+ break;
+#endif
+ case VAR_STRING:
+ if (varp->vval.v_string != NULL)
+ return varp->vval.v_string;
+ return (char_u *)"";
+ case VAR_SPECIAL:
+ STRCPY(buf, get_var_special_name(varp->vval.v_number));
+ return buf;
+ case VAR_BLOB:
+ emsg(_("E976: using Blob as a String"));
+ break;
+ case VAR_JOB:
+#ifdef FEAT_JOB_CHANNEL
+ {
+ job_T *job = varp->vval.v_job;
+ char *status;
+
+ if (job == NULL)
+ return (char_u *)"no process";
+ status = job->jv_status == JOB_FAILED ? "fail"
+ : job->jv_status >= JOB_ENDED ? "dead"
+ : "run";
+# ifdef UNIX
+ vim_snprintf((char *)buf, NUMBUFLEN,
+ "process %ld %s", (long)job->jv_pid, status);
+# elif defined(WIN32)
+ vim_snprintf((char *)buf, NUMBUFLEN,
+ "process %ld %s",
+ (long)job->jv_proc_info.dwProcessId,
+ status);
+# else
+ /* fall-back */
+ vim_snprintf((char *)buf, NUMBUFLEN, "process ? %s", status);
+# endif
+ return buf;
+ }
+#endif
+ break;
+ case VAR_CHANNEL:
+#ifdef FEAT_JOB_CHANNEL
+ {
+ channel_T *channel = varp->vval.v_channel;
+ char *status = channel_status(channel, -1);
+
+ if (channel == NULL)
+ vim_snprintf((char *)buf, NUMBUFLEN, "channel %s", status);
+ else
+ vim_snprintf((char *)buf, NUMBUFLEN,
+ "channel %d %s", channel->ch_id, status);
+ return buf;
+ }
+#endif
+ break;
+ case VAR_UNKNOWN:
+ emsg(_("E908: using an invalid value as a String"));
+ break;
+ }
+ return NULL;
+}
+
+/*
+ * Turn a typeval into a string. Similar to tv_get_string_buf() but uses
+ * string() on Dict, List, etc.
+ */
+ char_u *
+tv_stringify(typval_T *varp, char_u *buf)
+{
+ if (varp->v_type == VAR_LIST
+ || varp->v_type == VAR_DICT
+ || varp->v_type == VAR_FUNC
+ || varp->v_type == VAR_PARTIAL
+ || varp->v_type == VAR_FLOAT)
+ {
+ typval_T tmp;
+
+ f_string(varp, &tmp);
+ tv_get_string_buf(&tmp, buf);
+ clear_tv(varp);
+ *varp = tmp;
+ return tmp.vval.v_string;
+ }
+ return tv_get_string_buf(varp, buf);
+}
+
+/*
+ * Find variable "name" in the list of variables.
+ * Return a pointer to it if found, NULL if not found.
+ * Careful: "a:0" variables don't have a name.
+ * When "htp" is not NULL we are writing to the variable, set "htp" to the
+ * hashtab_T used.
+ */
+ dictitem_T *
+find_var(char_u *name, hashtab_T **htp, int no_autoload)
+{
+ char_u *varname;
+ hashtab_T *ht;
+ dictitem_T *ret = NULL;
+
+ ht = find_var_ht(name, &varname);
+ if (htp != NULL)
+ *htp = ht;
+ if (ht == NULL)
+ return NULL;
+ ret = find_var_in_ht(ht, *name, varname, no_autoload || htp != NULL);
+ if (ret != NULL)
+ return ret;
+
+ /* Search in parent scope for lambda */
+ return find_var_in_scoped_ht(name, no_autoload || htp != NULL);
+}
+
+/*
+ * Find variable "varname" in hashtab "ht" with name "htname".
+ * Returns NULL if not found.
+ */
+ dictitem_T *
+find_var_in_ht(
+ hashtab_T *ht,
+ int htname,
+ char_u *varname,
+ int no_autoload)
+{
+ hashitem_T *hi;
+
+ if (*varname == NUL)
+ {
+ /* Must be something like "s:", otherwise "ht" would be NULL. */
+ switch (htname)
+ {
+ case 's': return &SCRIPT_SV(current_sctx.sc_sid)->sv_var;
+ case 'g': return &globvars_var;
+ case 'v': return &vimvars_var;
+ case 'b': return &curbuf->b_bufvar;
+ case 'w': return &curwin->w_winvar;
+ case 't': return &curtab->tp_winvar;
+ case 'l': return get_funccal_local_var();
+ case 'a': return get_funccal_args_var();
+ }
+ return NULL;
+ }
+
+ hi = hash_find(ht, varname);
+ if (HASHITEM_EMPTY(hi))
+ {
+ /* For global variables we may try auto-loading the script. If it
+ * worked find the variable again. Don't auto-load a script if it was
+ * loaded already, otherwise it would be loaded every time when
+ * checking if a function name is a Funcref variable. */
+ if (ht == &globvarht && !no_autoload)
+ {
+ /* Note: script_autoload() may make "hi" invalid. It must either
+ * be obtained again or not used. */
+ if (!script_autoload(varname, FALSE) || aborting())
+ return NULL;
+ hi = hash_find(ht, varname);
+ }
+ if (HASHITEM_EMPTY(hi))
+ return NULL;
+ }
+ return HI2DI(hi);
+}
+
+/*
+ * Find the hashtab used for a variable name.
+ * Return NULL if the name is not valid.
+ * Set "varname" to the start of name without ':'.
+ */
+ hashtab_T *
+find_var_ht(char_u *name, char_u **varname)
+{
+ hashitem_T *hi;
+ hashtab_T *ht;
+
+ if (name[0] == NUL)
+ return NULL;
+ if (name[1] != ':')
+ {
+ /* The name must not start with a colon or #. */
+ if (name[0] == ':' || name[0] == AUTOLOAD_CHAR)
+ return NULL;
+ *varname = name;
+
+ /* "version" is "v:version" in all scopes */
+ hi = hash_find(&compat_hashtab, name);
+ if (!HASHITEM_EMPTY(hi))
+ return &compat_hashtab;
+
+ ht = get_funccal_local_ht();
+ if (ht == NULL)
+ return &globvarht; /* global variable */
+ return ht; /* local variable */
+ }
+ *varname = name + 2;
+ if (*name == 'g') /* global variable */
+ return &globvarht;
+ /* There must be no ':' or '#' in the rest of the name, unless g: is used
+ */
+ if (vim_strchr(name + 2, ':') != NULL
+ || vim_strchr(name + 2, AUTOLOAD_CHAR) != NULL)
+ return NULL;
+ if (*name == 'b') /* buffer variable */
+ return &curbuf->b_vars->dv_hashtab;
+ if (*name == 'w') /* window variable */
+ return &curwin->w_vars->dv_hashtab;
+ if (*name == 't') /* tab page variable */
+ return &curtab->tp_vars->dv_hashtab;
+ if (*name == 'v') /* v: variable */
+ return &vimvarht;
+ if (*name == 'a') /* a: function argument */
+ return get_funccal_args_ht();
+ if (*name == 'l') /* l: local function variable */
+ return get_funccal_local_ht();
+ if (*name == 's' /* script variable */
+ && current_sctx.sc_sid > 0 && current_sctx.sc_sid <= ga_scripts.ga_len)
+ return &SCRIPT_VARS(current_sctx.sc_sid);
+ return NULL;
+}
+
+/*
+ * Get the string value of a (global/local) variable.
+ * Note: see tv_get_string() for how long the pointer remains valid.
+ * Returns NULL when it doesn't exist.
+ */
+ char_u *
+get_var_value(char_u *name)
+{
+ dictitem_T *v;
+
+ v = find_var(name, NULL, FALSE);
+ if (v == NULL)
+ return NULL;
+ return tv_get_string(&v->di_tv);
+}
+
+/*
+ * Allocate a new hashtab for a sourced script. It will be used while
+ * sourcing this script and when executing functions defined in the script.
+ */
+ void
+new_script_vars(scid_T id)
+{
+ int i;
+ hashtab_T *ht;
+ scriptvar_T *sv;
+
+ if (ga_grow(&ga_scripts, (int)(id - ga_scripts.ga_len)) == OK)
+ {
+ /* Re-allocating ga_data means that an ht_array pointing to
+ * ht_smallarray becomes invalid. We can recognize this: ht_mask is
+ * at its init value. Also reset "v_dict", it's always the same. */
+ for (i = 1; i <= ga_scripts.ga_len; ++i)
+ {
+ ht = &SCRIPT_VARS(i);
+ if (ht->ht_mask == HT_INIT_SIZE - 1)
+ ht->ht_array = ht->ht_smallarray;
+ sv = SCRIPT_SV(i);
+ sv->sv_var.di_tv.vval.v_dict = &sv->sv_dict;
+ }
+
+ while (ga_scripts.ga_len < id)
+ {
+ sv = SCRIPT_SV(ga_scripts.ga_len + 1) =
+ (scriptvar_T *)alloc_clear(sizeof(scriptvar_T));
+ init_var_dict(&sv->sv_dict, &sv->sv_var, VAR_SCOPE);
+ ++ga_scripts.ga_len;
+ }
+ }
+}
+
+/*
+ * Initialize dictionary "dict" as a scope and set variable "dict_var" to
+ * point to it.
+ */
+ void
+init_var_dict(dict_T *dict, dictitem_T *dict_var, int scope)
+{
+ hash_init(&dict->dv_hashtab);
+ dict->dv_lock = 0;
+ dict->dv_scope = scope;
+ dict->dv_refcount = DO_NOT_FREE_CNT;
+ dict->dv_copyID = 0;
+ dict_var->di_tv.vval.v_dict = dict;
+ dict_var->di_tv.v_type = VAR_DICT;
+ dict_var->di_tv.v_lock = VAR_FIXED;
+ dict_var->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
+ dict_var->di_key[0] = NUL;
+}
+
+/*
+ * Unreference a dictionary initialized by init_var_dict().
+ */
+ void
+unref_var_dict(dict_T *dict)
+{
+ /* Now the dict needs to be freed if no one else is using it, go back to
+ * normal reference counting. */
+ dict->dv_refcount -= DO_NOT_FREE_CNT - 1;
+ dict_unref(dict);
+}
+
+/*
+ * Clean up a list of internal variables.
+ * Frees all allocated variables and the value they contain.
+ * Clears hashtab "ht", does not free it.
+ */
+ void
+vars_clear(hashtab_T *ht)
+{
+ vars_clear_ext(ht, TRUE);
+}
+
+/*
+ * Like vars_clear(), but only free the value if "free_val" is TRUE.
+ */
+ void
+vars_clear_ext(hashtab_T *ht, int free_val)
+{
+ int todo;
+ hashitem_T *hi;
+ dictitem_T *v;
+
+ hash_lock(ht);
+ todo = (int)ht->ht_used;
+ for (hi = ht->ht_array; todo > 0; ++hi)
+ {
+ if (!HASHITEM_EMPTY(hi))
+ {
+ --todo;
+
+ /* Free the variable. Don't remove it from the hashtab,
+ * ht_array might change then. hash_clear() takes care of it
+ * later. */
+ v = HI2DI(hi);
+ if (free_val)
+ clear_tv(&v->di_tv);
+ if (v->di_flags & DI_FLAGS_ALLOC)
+ vim_free(v);
+ }
+ }
+ hash_clear(ht);
+ ht->ht_used = 0;
+}
+
+/*
+ * Delete a variable from hashtab "ht" at item "hi".
+ * Clear the variable value and free the dictitem.
+ */
+ static void
+delete_var(hashtab_T *ht, hashitem_T *hi)
+{
+ dictitem_T *di = HI2DI(hi);
+
+ hash_remove(ht, hi);
+ clear_tv(&di->di_tv);
+ vim_free(di);
+}
+
+/*
+ * List the value of one internal variable.
+ */
+ static void
+list_one_var(dictitem_T *v, char *prefix, int *first)
+{
+ char_u *tofree;
+ char_u *s;
+ char_u numbuf[NUMBUFLEN];
+
+ s = echo_string(&v->di_tv, &tofree, numbuf, get_copyID());
+ list_one_var_a(prefix, v->di_key, v->di_tv.v_type,
+ s == NULL ? (char_u *)"" : s, first);
+ vim_free(tofree);
+}
+
+ static void
+list_one_var_a(
+ char *prefix,
+ char_u *name,
+ int type,
+ char_u *string,
+ int *first) /* when TRUE clear rest of screen and set to FALSE */
+{
+ /* don't use msg() or msg_attr() to avoid overwriting "v:statusmsg" */
+ msg_start();
+ msg_puts(prefix);
+ if (name != NULL) /* "a:" vars don't have a name stored */
+ msg_puts((char *)name);
+ msg_putchar(' ');
+ msg_advance(22);
+ if (type == VAR_NUMBER)
+ msg_putchar('#');
+ else if (type == VAR_FUNC || type == VAR_PARTIAL)
+ msg_putchar('*');
+ else if (type == VAR_LIST)
+ {
+ msg_putchar('[');
+ if (*string == '[')
+ ++string;
+ }
+ else if (type == VAR_DICT)
+ {
+ msg_putchar('{');
+ if (*string == '{')
+ ++string;
+ }
+ else
+ msg_putchar(' ');
+
+ msg_outtrans(string);
+
+ if (type == VAR_FUNC || type == VAR_PARTIAL)
+ msg_puts("()");
+ if (*first)
+ {
+ msg_clr_eos();
+ *first = FALSE;
+ }
+}
+
+/*
+ * Set variable "name" to value in "tv".
+ * If the variable already exists, the value is updated.
+ * Otherwise the variable is created.
+ */
+ void
+set_var(
+ char_u *name,
+ typval_T *tv,
+ int copy) /* make copy of value in "tv" */
+{
+ dictitem_T *v;
+ char_u *varname;
+ hashtab_T *ht;
+
+ ht = find_var_ht(name, &varname);
+ if (ht == NULL || *varname == NUL)
+ {
+ semsg(_(e_illvar), name);
+ return;
+ }
+ v = find_var_in_ht(ht, 0, varname, TRUE);
+
+ /* Search in parent scope which is possible to reference from lambda */
+ if (v == NULL)
+ v = find_var_in_scoped_ht(name, TRUE);
+
+ if ((tv->v_type == VAR_FUNC || tv->v_type == VAR_PARTIAL)
+ && var_check_func_name(name, v == NULL))
+ return;
+
+ if (v != NULL)
+ {
+ /* existing variable, need to clear the value */
+ if (var_check_ro(v->di_flags, name, FALSE)
+ || tv_check_lock(v->di_tv.v_lock, name, FALSE))
+ return;
+
+ /*
+ * Handle setting internal v: variables separately where needed to
+ * prevent changing the type.
+ */
+ if (ht == &vimvarht)
+ {
+ if (v->di_tv.v_type == VAR_STRING)
+ {
+ VIM_CLEAR(v->di_tv.vval.v_string);
+ if (copy || tv->v_type != VAR_STRING)
+ {
+ char_u *val = tv_get_string(tv);
+
+ // Careful: when assigning to v:errmsg and tv_get_string()
+ // causes an error message the variable will alrady be set.
+ if (v->di_tv.vval.v_string == NULL)
+ v->di_tv.vval.v_string = vim_strsave(val);
+ }
+ else
+ {
+ /* Take over the string to avoid an extra alloc/free. */
+ v->di_tv.vval.v_string = tv->vval.v_string;
+ tv->vval.v_string = NULL;
+ }
+ return;
+ }
+ else if (v->di_tv.v_type == VAR_NUMBER)
+ {
+ v->di_tv.vval.v_number = tv_get_number(tv);
+ if (STRCMP(varname, "searchforward") == 0)
+ set_search_direction(v->di_tv.vval.v_number ? '/' : '?');
+#ifdef FEAT_SEARCH_EXTRA
+ else if (STRCMP(varname, "hlsearch") == 0)
+ {
+ no_hlsearch = !v->di_tv.vval.v_number;
+ redraw_all_later(SOME_VALID);
+ }
+#endif
+ return;
+ }
+ else if (v->di_tv.v_type != tv->v_type)
+ {
+ semsg(_("E963: setting %s to value with wrong type"), name);
+ return;
+ }
+ }
+
+ clear_tv(&v->di_tv);
+ }
+ else /* add a new variable */
+ {
+ /* Can't add "v:" variable. */
+ if (ht == &vimvarht)
+ {
+ semsg(_(e_illvar), name);
+ return;
+ }
+
+ /* Make sure the variable name is valid. */
+ if (!valid_varname(varname))
+ return;
+
+ v = (dictitem_T *)alloc((unsigned)(sizeof(dictitem_T)
+ + STRLEN(varname)));
+ if (v == NULL)
+ return;
+ STRCPY(v->di_key, varname);
+ if (hash_add(ht, DI2HIKEY(v)) == FAIL)
+ {
+ vim_free(v);
+ return;
+ }
+ v->di_flags = DI_FLAGS_ALLOC;
+ }
+
+ if (copy || tv->v_type == VAR_NUMBER || tv->v_type == VAR_FLOAT)
+ copy_tv(tv, &v->di_tv);
+ else
+ {
+ v->di_tv = *tv;
+ v->di_tv.v_lock = 0;
+ init_tv(tv);
+ }
+}
+
+/*
+ * Return TRUE if di_flags "flags" indicates variable "name" is read-only.
+ * Also give an error message.
+ */
+ int
+var_check_ro(int flags, char_u *name, int use_gettext)
+{
+ if (flags & DI_FLAGS_RO)
+ {
+ semsg(_(e_readonlyvar), use_gettext ? (char_u *)_(name) : name);
+ return TRUE;
+ }
+ if ((flags & DI_FLAGS_RO_SBX) && sandbox)
+ {
+ semsg(_(e_readonlysbx), use_gettext ? (char_u *)_(name) : name);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * Return TRUE if di_flags "flags" indicates variable "name" is fixed.
+ * Also give an error message.
+ */
+ int
+var_check_fixed(int flags, char_u *name, int use_gettext)
+{
+ if (flags & DI_FLAGS_FIX)
+ {
+ semsg(_("E795: Cannot delete variable %s"),
+ use_gettext ? (char_u *)_(name) : name);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * Check if a funcref is assigned to a valid variable name.
+ * Return TRUE and give an error if not.
+ */
+ int
+var_check_func_name(
+ char_u *name, /* points to start of variable name */
+ int new_var) /* TRUE when creating the variable */
+{
+ /* Allow for w: b: s: and t:. */
+ if (!(vim_strchr((char_u *)"wbst", name[0]) != NULL && name[1] == ':')
+ && !ASCII_ISUPPER((name[0] != NUL && name[1] == ':')
+ ? name[2] : name[0]))
+ {
+ semsg(_("E704: Funcref variable name must start with a capital: %s"),
+ name);
+ return TRUE;
+ }
+ /* Don't allow hiding a function. When "v" is not NULL we might be
+ * assigning another function to the same var, the type is checked
+ * below. */
+ if (new_var && function_exists(name, FALSE))
+ {
+ semsg(_("E705: Variable name conflicts with existing function: %s"),
+ name);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * Check if a variable name is valid.
+ * Return FALSE and give an error if not.
+ */
+ int
+valid_varname(char_u *varname)
+{
+ char_u *p;
+
+ for (p = varname; *p != NUL; ++p)
+ if (!eval_isnamec1(*p) && (p == varname || !VIM_ISDIGIT(*p))
+ && *p != AUTOLOAD_CHAR)
+ {
+ semsg(_(e_illvar), varname);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*
+ * Return TRUE if typeval "tv" is set to be locked (immutable).
+ * Also give an error message, using "name" or _("name") when use_gettext is
+ * TRUE.
+ */
+ int
+tv_check_lock(int lock, char_u *name, int use_gettext)
+{
+ if (lock & VAR_LOCKED)
+ {
+ semsg(_("E741: Value is locked: %s"),
+ name == NULL ? (char_u *)_("Unknown")
+ : use_gettext ? (char_u *)_(name)
+ : name);
+ return TRUE;
+ }
+ if (lock & VAR_FIXED)
+ {
+ semsg(_("E742: Cannot change value of %s"),
+ name == NULL ? (char_u *)_("Unknown")
+ : use_gettext ? (char_u *)_(name)
+ : name);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * Copy the values from typval_T "from" to typval_T "to".
+ * When needed allocates string or increases reference count.
+ * Does not make a copy of a list, blob or dict but copies the reference!
+ * It is OK for "from" and "to" to point to the same item. This is used to
+ * make a copy later.
+ */
+ void
+copy_tv(typval_T *from, typval_T *to)
+{
+ to->v_type = from->v_type;
+ to->v_lock = 0;
+ switch (from->v_type)
+ {
+ case VAR_NUMBER:
+ case VAR_SPECIAL:
+ to->vval.v_number = from->vval.v_number;
+ break;
+ case VAR_FLOAT:
+#ifdef FEAT_FLOAT
+ to->vval.v_float = from->vval.v_float;
+ break;
+#endif
+ case VAR_JOB:
+#ifdef FEAT_JOB_CHANNEL
+ to->vval.v_job = from->vval.v_job;
+ if (to->vval.v_job != NULL)
+ ++to->vval.v_job->jv_refcount;
+ break;
+#endif
+ case VAR_CHANNEL:
+#ifdef FEAT_JOB_CHANNEL
+ to->vval.v_channel = from->vval.v_channel;
+ if (to->vval.v_channel != NULL)
+ ++to->vval.v_channel->ch_refcount;
+ break;
+#endif
+ case VAR_STRING:
+ case VAR_FUNC:
+ if (from->vval.v_string == NULL)
+ to->vval.v_string = NULL;
+ else
+ {
+ to->vval.v_string = vim_strsave(from->vval.v_string);
+ if (from->v_type == VAR_FUNC)
+ func_ref(to->vval.v_string);
+ }
+ break;
+ case VAR_PARTIAL:
+ if (from->vval.v_partial == NULL)
+ to->vval.v_partial = NULL;
+ else
+ {
+ to->vval.v_partial = from->vval.v_partial;
+ ++to->vval.v_partial->pt_refcount;
+ }
+ break;
+ case VAR_BLOB:
+ if (from->vval.v_blob == NULL)
+ to->vval.v_blob = NULL;
+ else
+ {
+ to->vval.v_blob = from->vval.v_blob;
+ ++to->vval.v_blob->bv_refcount;
+ }
+ break;
+ case VAR_LIST:
+ if (from->vval.v_list == NULL)
+ to->vval.v_list = NULL;
+ else
+ {
+ to->vval.v_list = from->vval.v_list;
+ ++to->vval.v_list->lv_refcount;
+ }
+ break;
+ case VAR_DICT:
+ if (from->vval.v_dict == NULL)
+ to->vval.v_dict = NULL;
+ else
+ {
+ to->vval.v_dict = from->vval.v_dict;
+ ++to->vval.v_dict->dv_refcount;
+ }
+ break;
+ case VAR_UNKNOWN:
+ internal_error("copy_tv(UNKNOWN)");
+ break;
+ }
+}
+
+/*
+ * Make a copy of an item.
+ * Lists and Dictionaries are also copied. A deep copy if "deep" is set.
+ * For deepcopy() "copyID" is zero for a full copy or the ID for when a
+ * reference to an already copied list/dict can be used.
+ * Returns FAIL or OK.
+ */
+ int
+item_copy(
+ typval_T *from,
+ typval_T *to,
+ int deep,
+ int copyID)
+{
+ static int recurse = 0;
+ int ret = OK;
+
+ if (recurse >= DICT_MAXNEST)
+ {
+ emsg(_("E698: variable nested too deep for making a copy"));
+ return FAIL;
+ }
+ ++recurse;
+
+ switch (from->v_type)
+ {
+ case VAR_NUMBER:
+ case VAR_FLOAT:
+ case VAR_STRING:
+ case VAR_FUNC:
+ case VAR_PARTIAL:
+ case VAR_SPECIAL:
+ case VAR_JOB:
+ case VAR_CHANNEL:
+ copy_tv(from, to);
+ break;
+ case VAR_LIST:
+ to->v_type = VAR_LIST;
+ to->v_lock = 0;
+ if (from->vval.v_list == NULL)
+ to->vval.v_list = NULL;
+ else if (copyID != 0 && from->vval.v_list->lv_copyID == copyID)
+ {
+ /* use the copy made earlier */
+ to->vval.v_list = from->vval.v_list->lv_copylist;
+ ++to->vval.v_list->lv_refcount;
+ }
+ else
+ to->vval.v_list = list_copy(from->vval.v_list, deep, copyID);
+ if (to->vval.v_list == NULL)
+ ret = FAIL;
+ break;
+ case VAR_BLOB:
+ ret = blob_copy(from, to);
+ break;
+ case VAR_DICT:
+ to->v_type = VAR_DICT;
+ to->v_lock = 0;
+ if (from->vval.v_dict == NULL)
+ to->vval.v_dict = NULL;
+ else if (copyID != 0 && from->vval.v_dict->dv_copyID == copyID)
+ {
+ /* use the copy made earlier */
+ to->vval.v_dict = from->vval.v_dict->dv_copydict;
+ ++to->vval.v_dict->dv_refcount;
+ }
+ else
+ to->vval.v_dict = dict_copy(from->vval.v_dict, deep, copyID);
+ if (to->vval.v_dict == NULL)
+ ret = FAIL;
+ break;
+ case VAR_UNKNOWN:
+ internal_error("item_copy(UNKNOWN)");
+ ret = FAIL;
+ }
+ --recurse;
+ return ret;
+}
+
+/*
+ * This function is used by f_input() and f_inputdialog() functions. The third
+ * argument to f_input() specifies the type of completion to use at the
+ * prompt. The third argument to f_inputdialog() specifies the value to return
+ * when the user cancels the prompt.
+ */
+ void
+get_user_input(
+ typval_T *argvars,
+ typval_T *rettv,
+ int inputdialog,
+ int secret)
+{
+ char_u *prompt = tv_get_string_chk(&argvars[0]);
+ char_u *p = NULL;
+ int c;
+ char_u buf[NUMBUFLEN];
+ int cmd_silent_save = cmd_silent;
+ char_u *defstr = (char_u *)"";
+ int xp_type = EXPAND_NOTHING;
+ char_u *xp_arg = NULL;
+
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+
+#ifdef NO_CONSOLE_INPUT
+ /* While starting up, there is no place to enter text. When running tests
+ * with --not-a-term we assume feedkeys() will be used. */
+ if (no_console_input() && !is_not_a_term())
+ return;
+#endif
+
+ cmd_silent = FALSE; /* Want to see the prompt. */
+ if (prompt != NULL)
+ {
+ /* Only the part of the message after the last NL is considered as
+ * prompt for the command line */
+ p = vim_strrchr(prompt, '\n');
+ if (p == NULL)
+ p = prompt;
+ else
+ {
+ ++p;
+ c = *p;
+ *p = NUL;
+ msg_start();
+ msg_clr_eos();
+ msg_puts_attr((char *)prompt, echo_attr);
+ msg_didout = FALSE;
+ msg_starthere();
+ *p = c;
+ }
+ cmdline_row = msg_row;
+
+ if (argvars[1].v_type != VAR_UNKNOWN)
+ {
+ defstr = tv_get_string_buf_chk(&argvars[1], buf);
+ if (defstr != NULL)
+ stuffReadbuffSpec(defstr);
+
+ if (!inputdialog && argvars[2].v_type != VAR_UNKNOWN)
+ {
+ char_u *xp_name;
+ int xp_namelen;
+ long argt;
+
+ /* input() with a third argument: completion */
+ rettv->vval.v_string = NULL;
+
+ xp_name = tv_get_string_buf_chk(&argvars[2], buf);
+ if (xp_name == NULL)
+ return;
+
+ xp_namelen = (int)STRLEN(xp_name);
+
+ if (parse_compl_arg(xp_name, xp_namelen, &xp_type, &argt,
+ &xp_arg) == FAIL)
+ return;
+ }
+ }
+
+ if (defstr != NULL)
+ {
+ int save_ex_normal_busy = ex_normal_busy;
+
+ ex_normal_busy = 0;
+ rettv->vval.v_string =
+ getcmdline_prompt(secret ? NUL : '@', p, echo_attr,
+ xp_type, xp_arg);
+ ex_normal_busy = save_ex_normal_busy;
+ }
+ if (inputdialog && rettv->vval.v_string == NULL
+ && argvars[1].v_type != VAR_UNKNOWN
+ && argvars[2].v_type != VAR_UNKNOWN)
+ rettv->vval.v_string = vim_strsave(tv_get_string_buf(
+ &argvars[2], buf));
+
+ vim_free(xp_arg);
+
+ /* since the user typed this, no need to wait for return */
+ need_wait_return = FALSE;
+ msg_didout = FALSE;
+ }
+ cmd_silent = cmd_silent_save;
+}
+
+/*
+ * ":echo expr1 ..." print each argument separated with a space, add a
+ * newline at the end.
+ * ":echon expr1 ..." print each argument plain.
+ */
+ void
+ex_echo(exarg_T *eap)
+{
+ char_u *arg = eap->arg;
+ typval_T rettv;
+ char_u *tofree;
+ char_u *p;
+ int needclr = TRUE;
+ int atstart = TRUE;
+ char_u numbuf[NUMBUFLEN];
+ int did_emsg_before = did_emsg;
+ int called_emsg_before = called_emsg;
+
+ if (eap->skip)
+ ++emsg_skip;
+ while (*arg != NUL && *arg != '|' && *arg != '\n' && !got_int)
+ {
+ /* If eval1() causes an error message the text from the command may
+ * still need to be cleared. E.g., "echo 22,44". */
+ need_clr_eos = needclr;
+
+ p = arg;
+ if (eval1(&arg, &rettv, !eap->skip) == FAIL)
+ {
+ /*
+ * Report the invalid expression unless the expression evaluation
+ * has been cancelled due to an aborting error, an interrupt, or an
+ * exception.
+ */
+ if (!aborting() && did_emsg == did_emsg_before
+ && called_emsg == called_emsg_before)
+ semsg(_(e_invexpr2), p);
+ need_clr_eos = FALSE;
+ break;
+ }
+ need_clr_eos = FALSE;
+
+ if (!eap->skip)
+ {
+ if (atstart)
+ {
+ atstart = FALSE;
+ /* Call msg_start() after eval1(), evaluating the expression
+ * may cause a message to appear. */
+ if (eap->cmdidx == CMD_echo)
+ {
+ /* Mark the saved text as finishing the line, so that what
+ * follows is displayed on a new line when scrolling back
+ * at the more prompt. */
+ msg_sb_eol();
+ msg_start();
+ }
+ }
+ else if (eap->cmdidx == CMD_echo)
+ msg_puts_attr(" ", echo_attr);
+ p = echo_string(&rettv, &tofree, numbuf, get_copyID());
+ if (p != NULL)
+ for ( ; *p != NUL && !got_int; ++p)
+ {
+ if (*p == '\n' || *p == '\r' || *p == TAB)
+ {
+ if (*p != TAB && needclr)
+ {
+ /* remove any text still there from the command */
+ msg_clr_eos();
+ needclr = FALSE;
+ }
+ msg_putchar_attr(*p, echo_attr);
+ }
+ else
+ {
+ if (has_mbyte)
+ {
+ int i = (*mb_ptr2len)(p);
+
+ (void)msg_outtrans_len_attr(p, i, echo_attr);
+ p += i - 1;
+ }
+ else
+ (void)msg_outtrans_len_attr(p, 1, echo_attr);
+ }
+ }
+ vim_free(tofree);
+ }
+ clear_tv(&rettv);
+ arg = skipwhite(arg);
+ }
+ eap->nextcmd = check_nextcmd(arg);
+
+ if (eap->skip)
+ --emsg_skip;
+ else
+ {
+ /* remove text that may still be there from the command */
+ if (needclr)
+ msg_clr_eos();
+ if (eap->cmdidx == CMD_echo)
+ msg_end();
+ }
+}
+
+/*
+ * ":echohl {name}".
+ */
+ void
+ex_echohl(exarg_T *eap)
+{
+ echo_attr = syn_name2attr(eap->arg);
+}
+
+/*
+ * ":execute expr1 ..." execute the result of an expression.
+ * ":echomsg expr1 ..." Print a message
+ * ":echoerr expr1 ..." Print an error
+ * Each gets spaces around each argument and a newline at the end for
+ * echo commands
+ */
+ void
+ex_execute(exarg_T *eap)
+{
+ char_u *arg = eap->arg;
+ typval_T rettv;
+ int ret = OK;
+ char_u *p;
+ garray_T ga;
+ int len;
+ int save_did_emsg = did_emsg;
+
+ ga_init2(&ga, 1, 80);
+
+ if (eap->skip)
+ ++emsg_skip;
+ while (*arg != NUL && *arg != '|' && *arg != '\n')
+ {
+ p = arg;
+ ret = eval1_emsg(&arg, &rettv, !eap->skip);
+ if (ret == FAIL)
+ break;
+
+ if (!eap->skip)
+ {
+ char_u buf[NUMBUFLEN];
+
+ if (eap->cmdidx == CMD_execute)
+ p = tv_get_string_buf(&rettv, buf);
+ else
+ p = tv_stringify(&rettv, buf);
+ len = (int)STRLEN(p);
+ if (ga_grow(&ga, len + 2) == FAIL)
+ {
+ clear_tv(&rettv);
+ ret = FAIL;
+ break;
+ }
+ if (ga.ga_len)
+ ((char_u *)(ga.ga_data))[ga.ga_len++] = ' ';
+ STRCPY((char_u *)(ga.ga_data) + ga.ga_len, p);
+ ga.ga_len += len;
+ }
+
+ clear_tv(&rettv);
+ arg = skipwhite(arg);
+ }
+
+ if (ret != FAIL && ga.ga_data != NULL)
+ {
+ if (eap->cmdidx == CMD_echomsg || eap->cmdidx == CMD_echoerr)
+ {
+ /* Mark the already saved text as finishing the line, so that what
+ * follows is displayed on a new line when scrolling back at the
+ * more prompt. */
+ msg_sb_eol();
+ }
+
+ if (eap->cmdidx == CMD_echomsg)
+ {
+ msg_attr(ga.ga_data, echo_attr);
+ out_flush();
+ }
+ else if (eap->cmdidx == CMD_echoerr)
+ {
+ /* We don't want to abort following commands, restore did_emsg. */
+ save_did_emsg = did_emsg;
+ emsg(ga.ga_data);
+ if (!force_abort)
+ did_emsg = save_did_emsg;
+ }
+ else if (eap->cmdidx == CMD_execute)
+ do_cmdline((char_u *)ga.ga_data,
+ eap->getline, eap->cookie, DOCMD_NOWAIT|DOCMD_VERBOSE);
+ }
+
+ ga_clear(&ga);
+
+ if (eap->skip)
+ --emsg_skip;
+
+ eap->nextcmd = check_nextcmd(arg);
+}
+
+/*
+ * Find window specified by "vp" in tabpage "tp".
+ */
+ win_T *
+find_win_by_nr(
+ typval_T *vp,
+ tabpage_T *tp) /* NULL for current tab page */
+{
+ win_T *wp;
+ int nr = (int)tv_get_number_chk(vp, NULL);
+
+ if (nr < 0)
+ return NULL;
+ if (nr == 0)
+ return curwin;
+
+ FOR_ALL_WINDOWS_IN_TAB(tp, wp)
+ {
+ if (nr >= LOWEST_WIN_ID)
+ {
+ if (wp->w_id == nr)
+ return wp;
+ }
+ else if (--nr <= 0)
+ break;
+ }
+ if (nr >= LOWEST_WIN_ID)
+ return NULL;
+ return wp;
+}
+
+/*
+ * Find a window: When using a Window ID in any tab page, when using a number
+ * in the current tab page.
+ */
+ win_T *
+find_win_by_nr_or_id(typval_T *vp)
+{
+ int nr = (int)tv_get_number_chk(vp, NULL);
+
+ if (nr >= LOWEST_WIN_ID)
+ return win_id2wp(vp);
+ return find_win_by_nr(vp, NULL);
+}
+
+/*
+ * Find window specified by "wvp" in tabpage "tvp".
+ */
+ win_T *
+find_tabwin(
+ typval_T *wvp, /* VAR_UNKNOWN for current window */
+ typval_T *tvp) /* VAR_UNKNOWN for current tab page */
+{
+ win_T *wp = NULL;
+ tabpage_T *tp = NULL;
+ long n;
+
+ if (wvp->v_type != VAR_UNKNOWN)
+ {
+ if (tvp->v_type != VAR_UNKNOWN)
+ {
+ n = (long)tv_get_number(tvp);
+ if (n >= 0)
+ tp = find_tabpage(n);
+ }
+ else
+ tp = curtab;
+
+ if (tp != NULL)
+ wp = find_win_by_nr(wvp, tp);
+ }
+ else
+ wp = curwin;
+
+ return wp;
+}
+
+/*
+ * getwinvar() and gettabwinvar()
+ */
+ void
+getwinvar(
+ typval_T *argvars,
+ typval_T *rettv,
+ int off) /* 1 for gettabwinvar() */
+{
+ win_T *win;
+ char_u *varname;
+ dictitem_T *v;
+ tabpage_T *tp = NULL;
+ int done = FALSE;
+ win_T *oldcurwin;
+ tabpage_T *oldtabpage;
+ int need_switch_win;
+
+ if (off == 1)
+ tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
+ else
+ tp = curtab;
+ win = find_win_by_nr(&argvars[off], tp);
+ varname = tv_get_string_chk(&argvars[off + 1]);
+ ++emsg_off;
+
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+
+ if (win != NULL && varname != NULL)
+ {
+ /* Set curwin to be our win, temporarily. Also set the tabpage,
+ * otherwise the window is not valid. Only do this when needed,
+ * autocommands get blocked. */
+ need_switch_win = !(tp == curtab && win == curwin);
+ if (!need_switch_win
+ || switch_win(&oldcurwin, &oldtabpage, win, tp, TRUE) == OK)
+ {
+ if (*varname == '&')
+ {
+ if (varname[1] == NUL)
+ {
+ /* get all window-local options in a dict */
+ dict_T *opts = get_winbuf_options(FALSE);
+
+ if (opts != NULL)
+ {
+ rettv_dict_set(rettv, opts);
+ done = TRUE;
+ }
+ }
+ else if (get_option_tv(&varname, rettv, 1) == OK)
+ /* window-local-option */
+ done = TRUE;
+ }
+ else
+ {
+ /* Look up the variable. */
+ /* Let getwinvar({nr}, "") return the "w:" dictionary. */
+ v = find_var_in_ht(&win->w_vars->dv_hashtab, 'w',
+ varname, FALSE);
+ if (v != NULL)
+ {
+ copy_tv(&v->di_tv, rettv);
+ done = TRUE;
+ }
+ }
+ }
+
+ if (need_switch_win)
+ /* restore previous notion of curwin */
+ restore_win(oldcurwin, oldtabpage, TRUE);
+ }
+
+ if (!done && argvars[off + 2].v_type != VAR_UNKNOWN)
+ /* use the default return value */
+ copy_tv(&argvars[off + 2], rettv);
+
+ --emsg_off;
+}
+
+/*
+ * "setwinvar()" and "settabwinvar()" functions
+ */
+ void
+setwinvar(typval_T *argvars, typval_T *rettv UNUSED, int off)
+{
+ win_T *win;
+ win_T *save_curwin;
+ tabpage_T *save_curtab;
+ int need_switch_win;
+ char_u *varname, *winvarname;
+ typval_T *varp;
+ char_u nbuf[NUMBUFLEN];
+ tabpage_T *tp = NULL;
+
+ if (check_restricted() || check_secure())
+ return;
+
+ if (off == 1)
+ tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
+ else
+ tp = curtab;
+ win = find_win_by_nr(&argvars[off], tp);
+ varname = tv_get_string_chk(&argvars[off + 1]);
+ varp = &argvars[off + 2];
+
+ if (win != NULL && varname != NULL && varp != NULL)
+ {
+ need_switch_win = !(tp == curtab && win == curwin);
+ if (!need_switch_win
+ || switch_win(&save_curwin, &save_curtab, win, tp, TRUE) == OK)
+ {
+ if (*varname == '&')
+ {
+ long numval;
+ char_u *strval;
+ int error = FALSE;
+
+ ++varname;
+ numval = (long)tv_get_number_chk(varp, &error);
+ strval = tv_get_string_buf_chk(varp, nbuf);
+ if (!error && strval != NULL)
+ set_option_value(varname, numval, strval, OPT_LOCAL);
+ }
+ else
+ {
+ winvarname = alloc((unsigned)STRLEN(varname) + 3);
+ if (winvarname != NULL)
+ {
+ STRCPY(winvarname, "w:");
+ STRCPY(winvarname + 2, varname);
+ set_var(winvarname, varp, TRUE);
+ vim_free(winvarname);
+ }
+ }
+ }
+ if (need_switch_win)
+ restore_win(save_curwin, save_curtab, TRUE);
+ }
+}
+
+/*
+ * Skip over the name of an option: "&option", "&g:option" or "&l:option".
+ * "arg" points to the "&" or '+' when called, to "option" when returning.
+ * Returns NULL when no option name found. Otherwise pointer to the char
+ * after the option name.
+ */
+ static char_u *
+find_option_end(char_u **arg, int *opt_flags)
+{
+ char_u *p = *arg;
+
+ ++p;
+ if (*p == 'g' && p[1] == ':')
+ {
+ *opt_flags = OPT_GLOBAL;
+ p += 2;
+ }
+ else if (*p == 'l' && p[1] == ':')
+ {
+ *opt_flags = OPT_LOCAL;
+ p += 2;
+ }
+ else
+ *opt_flags = 0;
+
+ if (!ASCII_ISALPHA(*p))
+ return NULL;
+ *arg = p;
+
+ if (p[0] == 't' && p[1] == '_' && p[2] != NUL && p[3] != NUL)
+ p += 4; /* termcap option */
+ else
+ while (ASCII_ISALPHA(*p))
+ ++p;
+ return p;
+}
+
+/*
+ * Return the autoload script name for a function or variable name.
+ * Returns NULL when out of memory.
+ */
+ char_u *
+autoload_name(char_u *name)
+{
+ char_u *p;
+ char_u *scriptname;
+
+ /* Get the script file name: replace '#' with '/', append ".vim". */
+ scriptname = alloc((unsigned)(STRLEN(name) + 14));
+ if (scriptname == NULL)
+ return FALSE;
+ STRCPY(scriptname, "autoload/");
+ STRCAT(scriptname, name);
+ *vim_strrchr(scriptname, AUTOLOAD_CHAR) = NUL;
+ STRCAT(scriptname, ".vim");
+ while ((p = vim_strchr(scriptname, AUTOLOAD_CHAR)) != NULL)
+ *p = '/';
+ return scriptname;
+}
+
+/*
+ * If "name" has a package name try autoloading the script for it.
+ * Return TRUE if a package was loaded.
+ */
+ int
+script_autoload(
+ char_u *name,
+ int reload) /* load script again when already loaded */
+{
+ char_u *p;
+ char_u *scriptname, *tofree;
+ int ret = FALSE;
+ int i;
+
+ /* If there is no '#' after name[0] there is no package name. */
+ p = vim_strchr(name, AUTOLOAD_CHAR);
+ if (p == NULL || p == name)
+ return FALSE;
+
+ tofree = scriptname = autoload_name(name);
+
+ /* Find the name in the list of previously loaded package names. Skip
+ * "autoload/", it's always the same. */
+ for (i = 0; i < ga_loaded.ga_len; ++i)
+ if (STRCMP(((char_u **)ga_loaded.ga_data)[i] + 9, scriptname + 9) == 0)
+ break;
+ if (!reload && i < ga_loaded.ga_len)
+ ret = FALSE; /* was loaded already */
+ else
+ {
+ /* Remember the name if it wasn't loaded already. */
+ if (i == ga_loaded.ga_len && ga_grow(&ga_loaded, 1) == OK)
+ {
+ ((char_u **)ga_loaded.ga_data)[ga_loaded.ga_len++] = scriptname;
+ tofree = NULL;
+ }
+
+ /* Try loading the package from $VIMRUNTIME/autoload/<name>.vim */
+ if (source_runtime(scriptname, 0) == OK)
+ ret = TRUE;
+ }
+
+ vim_free(tofree);
+ return ret;
+}
+
+#if defined(FEAT_VIMINFO) || defined(FEAT_SESSION)
+typedef enum
+{
+ VAR_FLAVOUR_DEFAULT, /* doesn't start with uppercase */
+ VAR_FLAVOUR_SESSION, /* starts with uppercase, some lower */
+ VAR_FLAVOUR_VIMINFO /* all uppercase */
+} var_flavour_T;
+
+ static var_flavour_T
+var_flavour(char_u *varname)
+{
+ char_u *p = varname;
+
+ if (ASCII_ISUPPER(*p))
+ {
+ while (*(++p))
+ if (ASCII_ISLOWER(*p))
+ return VAR_FLAVOUR_SESSION;
+ return VAR_FLAVOUR_VIMINFO;
+ }
+ else
+ return VAR_FLAVOUR_DEFAULT;
+}
+#endif
+
+#if defined(FEAT_VIMINFO) || defined(PROTO)
+/*
+ * Restore global vars that start with a capital from the viminfo file
+ */
+ int
+read_viminfo_varlist(vir_T *virp, int writing)
+{
+ char_u *tab;
+ int type = VAR_NUMBER;
+ typval_T tv;
+ funccal_entry_T funccal_entry;
+
+ if (!writing && (find_viminfo_parameter('!') != NULL))
+ {
+ tab = vim_strchr(virp->vir_line + 1, '\t');
+ if (tab != NULL)
+ {
+ *tab++ = '\0'; /* isolate the variable name */
+ switch (*tab)
+ {
+ case 'S': type = VAR_STRING; break;
+#ifdef FEAT_FLOAT
+ case 'F': type = VAR_FLOAT; break;
+#endif
+ case 'D': type = VAR_DICT; break;
+ case 'L': type = VAR_LIST; break;
+ case 'B': type = VAR_BLOB; break;
+ case 'X': type = VAR_SPECIAL; break;
+ }
+
+ tab = vim_strchr(tab, '\t');
+ if (tab != NULL)
+ {
+ tv.v_type = type;
+ if (type == VAR_STRING || type == VAR_DICT
+ || type == VAR_LIST || type == VAR_BLOB)
+ tv.vval.v_string = viminfo_readstring(virp,
+ (int)(tab - virp->vir_line + 1), TRUE);
+#ifdef FEAT_FLOAT
+ else if (type == VAR_FLOAT)
+ (void)string2float(tab + 1, &tv.vval.v_float);
+#endif
+ else
+ tv.vval.v_number = atol((char *)tab + 1);
+ if (type == VAR_DICT || type == VAR_LIST)
+ {
+ typval_T *etv = eval_expr(tv.vval.v_string, NULL);
+
+ if (etv == NULL)
+ /* Failed to parse back the dict or list, use it as a
+ * string. */
+ tv.v_type = VAR_STRING;
+ else
+ {
+ vim_free(tv.vval.v_string);
+ tv = *etv;
+ vim_free(etv);
+ }
+ }
+ else if (type == VAR_BLOB)
+ {
+ blob_T *blob = string2blob(tv.vval.v_string);
+
+ if (blob == NULL)
+ // Failed to parse back the blob, use it as a string.
+ tv.v_type = VAR_STRING;
+ else
+ {
+ vim_free(tv.vval.v_string);
+ tv.v_type = VAR_BLOB;
+ tv.vval.v_blob = blob;
+ }
+ }
+
+ /* when in a function use global variables */
+ save_funccal(&funccal_entry);
+ set_var(virp->vir_line + 1, &tv, FALSE);
+ restore_funccal();
+
+ if (tv.v_type == VAR_STRING)
+ vim_free(tv.vval.v_string);
+ else if (tv.v_type == VAR_DICT || tv.v_type == VAR_LIST ||
+ tv.v_type == VAR_BLOB)
+ clear_tv(&tv);
+ }
+ }
+ }
+
+ return viminfo_readline(virp);
+}
+
+/*
+ * Write global vars that start with a capital to the viminfo file
+ */
+ void
+write_viminfo_varlist(FILE *fp)
+{
+ hashitem_T *hi;
+ dictitem_T *this_var;
+ int todo;
+ char *s = "";
+ char_u *p;
+ char_u *tofree;
+ char_u numbuf[NUMBUFLEN];
+
+ if (find_viminfo_parameter('!') == NULL)
+ return;
+
+ fputs(_("\n# global variables:\n"), fp);
+
+ todo = (int)globvarht.ht_used;
+ for (hi = globvarht.ht_array; todo > 0; ++hi)
+ {
+ if (!HASHITEM_EMPTY(hi))
+ {
+ --todo;
+ this_var = HI2DI(hi);
+ if (var_flavour(this_var->di_key) == VAR_FLAVOUR_VIMINFO)
+ {
+ switch (this_var->di_tv.v_type)
+ {
+ case VAR_STRING: s = "STR"; break;
+ case VAR_NUMBER: s = "NUM"; break;
+ case VAR_FLOAT: s = "FLO"; break;
+ case VAR_DICT: s = "DIC"; break;
+ case VAR_LIST: s = "LIS"; break;
+ case VAR_BLOB: s = "BLO"; break;
+ case VAR_SPECIAL: s = "XPL"; break;
+
+ case VAR_UNKNOWN:
+ case VAR_FUNC:
+ case VAR_PARTIAL:
+ case VAR_JOB:
+ case VAR_CHANNEL:
+ continue;
+ }
+ fprintf(fp, "!%s\t%s\t", this_var->di_key, s);
+ if (this_var->di_tv.v_type == VAR_SPECIAL)
+ {
+ sprintf((char *)numbuf, "%ld",
+ (long)this_var->di_tv.vval.v_number);
+ p = numbuf;
+ tofree = NULL;
+ }
+ else
+ p = echo_string(&this_var->di_tv, &tofree, numbuf, 0);
+ if (p != NULL)
+ viminfo_writestring(fp, p);
+ vim_free(tofree);
+ }
+ }
+ }
+}
+#endif
+
+#if defined(FEAT_SESSION) || defined(PROTO)
+ int
+store_session_globals(FILE *fd)
+{
+ hashitem_T *hi;
+ dictitem_T *this_var;
+ int todo;
+ char_u *p, *t;
+
+ todo = (int)globvarht.ht_used;
+ for (hi = globvarht.ht_array; todo > 0; ++hi)
+ {
+ if (!HASHITEM_EMPTY(hi))
+ {
+ --todo;
+ this_var = HI2DI(hi);
+ if ((this_var->di_tv.v_type == VAR_NUMBER
+ || this_var->di_tv.v_type == VAR_STRING)
+ && var_flavour(this_var->di_key) == VAR_FLAVOUR_SESSION)
+ {
+ /* Escape special characters with a backslash. Turn a LF and
+ * CR into \n and \r. */
+ p = vim_strsave_escaped(tv_get_string(&this_var->di_tv),
+ (char_u *)"\\\"\n\r");
+ if (p == NULL) /* out of memory */
+ break;
+ for (t = p; *t != NUL; ++t)
+ if (*t == '\n')
+ *t = 'n';
+ else if (*t == '\r')
+ *t = 'r';
+ if ((fprintf(fd, "let %s = %c%s%c",
+ this_var->di_key,
+ (this_var->di_tv.v_type == VAR_STRING) ? '"'
+ : ' ',
+ p,
+ (this_var->di_tv.v_type == VAR_STRING) ? '"'
+ : ' ') < 0)
+ || put_eol(fd) == FAIL)
+ {
+ vim_free(p);
+ return FAIL;
+ }
+ vim_free(p);
+ }
+#ifdef FEAT_FLOAT
+ else if (this_var->di_tv.v_type == VAR_FLOAT
+ && var_flavour(this_var->di_key) == VAR_FLAVOUR_SESSION)
+ {
+ float_T f = this_var->di_tv.vval.v_float;
+ int sign = ' ';
+
+ if (f < 0)
+ {
+ f = -f;
+ sign = '-';
+ }
+ if ((fprintf(fd, "let %s = %c%f",
+ this_var->di_key, sign, f) < 0)
+ || put_eol(fd) == FAIL)
+ return FAIL;
+ }
+#endif
+ }
+ }
+ return OK;
+}
+#endif
+
+/*
+ * Display script name where an item was last set.
+ * Should only be invoked when 'verbose' is non-zero.
+ */
+ void
+last_set_msg(sctx_T script_ctx)
+{
+ char_u *p;
+
+ if (script_ctx.sc_sid != 0)
+ {
+ p = home_replace_save(NULL, get_scriptname(script_ctx.sc_sid));
+ if (p != NULL)
+ {
+ verbose_enter();
+ msg_puts(_("\n\tLast set from "));
+ msg_puts((char *)p);
+ if (script_ctx.sc_lnum > 0)
+ {
+ msg_puts(_(" line "));
+ msg_outnum((long)script_ctx.sc_lnum);
+ }
+ verbose_leave();
+ vim_free(p);
+ }
+ }
+}
+
+/* reset v:option_new, v:option_old and v:option_type */
+ void
+reset_v_option_vars(void)
+{
+ set_vim_var_string(VV_OPTION_NEW, NULL, -1);
+ set_vim_var_string(VV_OPTION_OLD, NULL, -1);
+ set_vim_var_string(VV_OPTION_TYPE, NULL, -1);
+}
+
+/*
+ * Prepare "gap" for an assert error and add the sourcing position.
+ */
+ void
+prepare_assert_error(garray_T *gap)
+{
+ char buf[NUMBUFLEN];
+
+ ga_init2(gap, 1, 100);
+ if (sourcing_name != NULL)
+ {
+ ga_concat(gap, sourcing_name);
+ if (sourcing_lnum > 0)
+ ga_concat(gap, (char_u *)" ");
+ }
+ if (sourcing_lnum > 0)
+ {
+ sprintf(buf, "line %ld", (long)sourcing_lnum);
+ ga_concat(gap, (char_u *)buf);
+ }
+ if (sourcing_name != NULL || sourcing_lnum > 0)
+ ga_concat(gap, (char_u *)": ");
+}
+
+/*
+ * Add an assert error to v:errors.
+ */
+ void
+assert_error(garray_T *gap)
+{
+ struct vimvar *vp = &vimvars[VV_ERRORS];
+
+ if (vp->vv_type != VAR_LIST || vimvars[VV_ERRORS].vv_list == NULL)
+ /* Make sure v:errors is a list. */
+ set_vim_var_list(VV_ERRORS, list_alloc());
+ list_append_string(vimvars[VV_ERRORS].vv_list, gap->ga_data, gap->ga_len);
+}
+
+ int
+assert_equal_common(typval_T *argvars, assert_type_T atype)
+{
+ garray_T ga;
+
+ if (tv_equal(&argvars[0], &argvars[1], FALSE, FALSE)
+ != (atype == ASSERT_EQUAL))
+ {
+ prepare_assert_error(&ga);
+ fill_assert_error(&ga, &argvars[2], NULL, &argvars[0], &argvars[1],
+ atype);
+ assert_error(&ga);
+ ga_clear(&ga);
+ return 1;
+ }
+ return 0;
+}
+
+ int
+assert_equalfile(typval_T *argvars)
+{
+ char_u buf1[NUMBUFLEN];
+ char_u buf2[NUMBUFLEN];
+ char_u *fname1 = tv_get_string_buf_chk(&argvars[0], buf1);
+ char_u *fname2 = tv_get_string_buf_chk(&argvars[1], buf2);
+ garray_T ga;
+ FILE *fd1;
+ FILE *fd2;
+
+ if (fname1 == NULL || fname2 == NULL)
+ return 0;
+
+ IObuff[0] = NUL;
+ fd1 = mch_fopen((char *)fname1, READBIN);
+ if (fd1 == NULL)
+ {
+ vim_snprintf((char *)IObuff, IOSIZE, (char *)e_notread, fname1);
+ }
+ else
+ {
+ fd2 = mch_fopen((char *)fname2, READBIN);
+ if (fd2 == NULL)
+ {
+ fclose(fd1);
+ vim_snprintf((char *)IObuff, IOSIZE, (char *)e_notread, fname2);
+ }
+ else
+ {
+ int c1, c2;
+ long count = 0;
+
+ for (;;)
+ {
+ c1 = fgetc(fd1);
+ c2 = fgetc(fd2);
+ if (c1 == EOF)
+ {
+ if (c2 != EOF)
+ STRCPY(IObuff, "first file is shorter");
+ break;
+ }
+ else if (c2 == EOF)
+ {
+ STRCPY(IObuff, "second file is shorter");
+ break;
+ }
+ else if (c1 != c2)
+ {
+ vim_snprintf((char *)IObuff, IOSIZE,
+ "difference at byte %ld", count);
+ break;
+ }
+ ++count;
+ }
+ fclose(fd1);
+ fclose(fd2);
+ }
+ }
+ if (IObuff[0] != NUL)
+ {
+ prepare_assert_error(&ga);
+ ga_concat(&ga, IObuff);
+ assert_error(&ga);
+ ga_clear(&ga);
+ return 1;
+ }
+ return 0;
+}
+
+ int
+assert_match_common(typval_T *argvars, assert_type_T atype)
+{
+ garray_T ga;
+ char_u buf1[NUMBUFLEN];
+ char_u buf2[NUMBUFLEN];
+ char_u *pat = tv_get_string_buf_chk(&argvars[0], buf1);
+ char_u *text = tv_get_string_buf_chk(&argvars[1], buf2);
+
+ if (pat == NULL || text == NULL)
+ emsg(_(e_invarg));
+ else if (pattern_match(pat, text, FALSE) != (atype == ASSERT_MATCH))
+ {
+ prepare_assert_error(&ga);
+ fill_assert_error(&ga, &argvars[2], NULL, &argvars[0], &argvars[1],
+ atype);
+ assert_error(&ga);
+ ga_clear(&ga);
+ return 1;
+ }
+ return 0;
+}
+
+ int
+assert_inrange(typval_T *argvars)
+{
+ garray_T ga;
+ int error = FALSE;
+ varnumber_T lower = tv_get_number_chk(&argvars[0], &error);
+ varnumber_T upper = tv_get_number_chk(&argvars[1], &error);
+ varnumber_T actual = tv_get_number_chk(&argvars[2], &error);
+ char_u *tofree;
+ char msg[200];
+ char_u numbuf[NUMBUFLEN];
+
+ if (error)
+ return 0;
+ if (actual < lower || actual > upper)
+ {
+ prepare_assert_error(&ga);
+ if (argvars[3].v_type != VAR_UNKNOWN)
+ {
+ ga_concat(&ga, tv2string(&argvars[3], &tofree, numbuf, 0));
+ vim_free(tofree);
+ }
+ else
+ {
+ vim_snprintf(msg, 200, "Expected range %ld - %ld, but got %ld",
+ (long)lower, (long)upper, (long)actual);
+ ga_concat(&ga, (char_u *)msg);
+ }
+ assert_error(&ga);
+ ga_clear(&ga);
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Common for assert_true() and assert_false().
+ * Return non-zero for failure.
+ */
+ int
+assert_bool(typval_T *argvars, int isTrue)
+{
+ int error = FALSE;
+ garray_T ga;
+
+ if (argvars[0].v_type == VAR_SPECIAL
+ && argvars[0].vval.v_number == (isTrue ? VVAL_TRUE : VVAL_FALSE))
+ return 0;
+ if (argvars[0].v_type != VAR_NUMBER
+ || (tv_get_number_chk(&argvars[0], &error) == 0) == isTrue
+ || error)
+ {
+ prepare_assert_error(&ga);
+ fill_assert_error(&ga, &argvars[1],
+ (char_u *)(isTrue ? "True" : "False"),
+ NULL, &argvars[0], ASSERT_OTHER);
+ assert_error(&ga);
+ ga_clear(&ga);
+ return 1;
+ }
+ return 0;
+}
+
+ int
+assert_report(typval_T *argvars)
+{
+ garray_T ga;
+
+ prepare_assert_error(&ga);
+ ga_concat(&ga, tv_get_string(&argvars[0]));
+ assert_error(&ga);
+ ga_clear(&ga);
+ return 1;
+}
+
+ int
+assert_exception(typval_T *argvars)
+{
+ garray_T ga;
+ char_u *error = tv_get_string_chk(&argvars[0]);
+
+ if (vimvars[VV_EXCEPTION].vv_str == NULL)
+ {
+ prepare_assert_error(&ga);
+ ga_concat(&ga, (char_u *)"v:exception is not set");
+ assert_error(&ga);
+ ga_clear(&ga);
+ return 1;
+ }
+ else if (error != NULL
+ && strstr((char *)vimvars[VV_EXCEPTION].vv_str, (char *)error) == NULL)
+ {
+ prepare_assert_error(&ga);
+ fill_assert_error(&ga, &argvars[1], NULL, &argvars[0],
+ &vimvars[VV_EXCEPTION].vv_tv, ASSERT_OTHER);
+ assert_error(&ga);
+ ga_clear(&ga);
+ return 1;
+ }
+ return 0;
+}
+
+ int
+assert_beeps(typval_T *argvars)
+{
+ char_u *cmd = tv_get_string_chk(&argvars[0]);
+ garray_T ga;
+ int ret = 0;
+
+ called_vim_beep = FALSE;
+ suppress_errthrow = TRUE;
+ emsg_silent = FALSE;
+ do_cmdline_cmd(cmd);
+ if (!called_vim_beep)
+ {
+ prepare_assert_error(&ga);
+ ga_concat(&ga, (char_u *)"command did not beep: ");
+ ga_concat(&ga, cmd);
+ assert_error(&ga);
+ ga_clear(&ga);
+ ret = 1;
+ }
+
+ suppress_errthrow = FALSE;
+ emsg_on_display = FALSE;
+ return ret;
+}
+
+ int
+assert_fails(typval_T *argvars)
+{
+ char_u *cmd = tv_get_string_chk(&argvars[0]);
+ garray_T ga;
+ int ret = 0;
+ char_u numbuf[NUMBUFLEN];
+ char_u *tofree;
+
+ called_emsg = FALSE;
+ suppress_errthrow = TRUE;
+ emsg_silent = TRUE;
+ do_cmdline_cmd(cmd);
+ if (!called_emsg)
+ {
+ prepare_assert_error(&ga);
+ ga_concat(&ga, (char_u *)"command did not fail: ");
+ if (argvars[1].v_type != VAR_UNKNOWN
+ && argvars[2].v_type != VAR_UNKNOWN)
+ {
+ ga_concat(&ga, echo_string(&argvars[2], &tofree, numbuf, 0));
+ vim_free(tofree);
+ }
+ else
+ ga_concat(&ga, cmd);
+ assert_error(&ga);
+ ga_clear(&ga);
+ ret = 1;
+ }
+ else if (argvars[1].v_type != VAR_UNKNOWN)
+ {
+ char_u buf[NUMBUFLEN];
+ char *error = (char *)tv_get_string_buf_chk(&argvars[1], buf);
+
+ if (error == NULL
+ || strstr((char *)vimvars[VV_ERRMSG].vv_str, error) == NULL)
+ {
+ prepare_assert_error(&ga);
+ fill_assert_error(&ga, &argvars[2], NULL, &argvars[1],
+ &vimvars[VV_ERRMSG].vv_tv, ASSERT_OTHER);
+ assert_error(&ga);
+ ga_clear(&ga);
+ ret = 1;
+ }
+ }
+
+ called_emsg = FALSE;
+ suppress_errthrow = FALSE;
+ emsg_silent = FALSE;
+ emsg_on_display = FALSE;
+ set_vim_var_string(VV_ERRMSG, NULL, 0);
+ return ret;
+}
+
+/*
+ * Append "p[clen]" to "gap", escaping unprintable characters.
+ * Changes NL to \n, CR to \r, etc.
+ */
+ static void
+ga_concat_esc(garray_T *gap, char_u *p, int clen)
+{
+ char_u buf[NUMBUFLEN];
+
+ if (clen > 1)
+ {
+ mch_memmove(buf, p, clen);
+ buf[clen] = NUL;
+ ga_concat(gap, buf);
+ }
+ else switch (*p)
+ {
+ case BS: ga_concat(gap, (char_u *)"\\b"); break;
+ case ESC: ga_concat(gap, (char_u *)"\\e"); break;
+ case FF: ga_concat(gap, (char_u *)"\\f"); break;
+ case NL: ga_concat(gap, (char_u *)"\\n"); break;
+ case TAB: ga_concat(gap, (char_u *)"\\t"); break;
+ case CAR: ga_concat(gap, (char_u *)"\\r"); break;
+ case '\\': ga_concat(gap, (char_u *)"\\\\"); break;
+ default:
+ if (*p < ' ')
+ {
+ vim_snprintf((char *)buf, NUMBUFLEN, "\\x%02x", *p);
+ ga_concat(gap, buf);
+ }
+ else
+ ga_append(gap, *p);
+ break;
+ }
+}
+
+/*
+ * Append "str" to "gap", escaping unprintable characters.
+ * Changes NL to \n, CR to \r, etc.
+ */
+ static void
+ga_concat_shorten_esc(garray_T *gap, char_u *str)
+{
+ char_u *p;
+ char_u *s;
+ int c;
+ int clen;
+ char_u buf[NUMBUFLEN];
+ int same_len;
+
+ if (str == NULL)
+ {
+ ga_concat(gap, (char_u *)"NULL");
+ return;
+ }
+
+ for (p = str; *p != NUL; ++p)
+ {
+ same_len = 1;
+ s = p;
+ c = mb_ptr2char_adv(&s);
+ clen = s - p;
+ while (*s != NUL && c == mb_ptr2char(s))
+ {
+ ++same_len;
+ s += clen;
+ }
+ if (same_len > 20)
+ {
+ ga_concat(gap, (char_u *)"\\[");
+ ga_concat_esc(gap, p, clen);
+ ga_concat(gap, (char_u *)" occurs ");
+ vim_snprintf((char *)buf, NUMBUFLEN, "%d", same_len);
+ ga_concat(gap, buf);
+ ga_concat(gap, (char_u *)" times]");
+ p = s - 1;
+ }
+ else
+ ga_concat_esc(gap, p, clen);
+ }
+}
+
+/*
+ * Fill "gap" with information about an assert error.
+ */
+ void
+fill_assert_error(
+ garray_T *gap,
+ typval_T *opt_msg_tv,
+ char_u *exp_str,
+ typval_T *exp_tv,
+ typval_T *got_tv,
+ assert_type_T atype)
+{
+ char_u numbuf[NUMBUFLEN];
+ char_u *tofree;
+
+ if (opt_msg_tv->v_type != VAR_UNKNOWN)
+ {
+ ga_concat(gap, echo_string(opt_msg_tv, &tofree, numbuf, 0));
+ vim_free(tofree);
+ ga_concat(gap, (char_u *)": ");
+ }
+
+ if (atype == ASSERT_MATCH || atype == ASSERT_NOTMATCH)
+ ga_concat(gap, (char_u *)"Pattern ");
+ else if (atype == ASSERT_NOTEQUAL)
+ ga_concat(gap, (char_u *)"Expected not equal to ");
+ else
+ ga_concat(gap, (char_u *)"Expected ");
+ if (exp_str == NULL)
+ {
+ ga_concat_shorten_esc(gap, tv2string(exp_tv, &tofree, numbuf, 0));
+ vim_free(tofree);
+ }
+ else
+ ga_concat_shorten_esc(gap, exp_str);
+ if (atype != ASSERT_NOTEQUAL)
+ {
+ if (atype == ASSERT_MATCH)
+ ga_concat(gap, (char_u *)" does not match ");
+ else if (atype == ASSERT_NOTMATCH)
+ ga_concat(gap, (char_u *)" does match ");
+ else
+ ga_concat(gap, (char_u *)" but got ");
+ ga_concat_shorten_esc(gap, tv2string(got_tv, &tofree, numbuf, 0));
+ vim_free(tofree);
+ }
+}
+
+/*
+ * Compare "typ1" and "typ2". Put the result in "typ1".
+ */
+ int
+typval_compare(
+ typval_T *typ1, /* first operand */
+ typval_T *typ2, /* second operand */
+ exptype_T type, /* operator */
+ int type_is, /* TRUE for "is" and "isnot" */
+ int ic) /* ignore case */
+{
+ int i;
+ varnumber_T n1, n2;
+ char_u *s1, *s2;
+ char_u buf1[NUMBUFLEN], buf2[NUMBUFLEN];
+
+ if (type_is && typ1->v_type != typ2->v_type)
+ {
+ /* For "is" a different type always means FALSE, for "notis"
+ * it means TRUE. */
+ n1 = (type == TYPE_NEQUAL);
+ }
+ else if (typ1->v_type == VAR_BLOB || typ2->v_type == VAR_BLOB)
+ {
+ if (type_is)
+ {
+ n1 = (typ1->v_type == typ2->v_type
+ && typ1->vval.v_blob == typ2->vval.v_blob);
+ if (type == TYPE_NEQUAL)
+ n1 = !n1;
+ }
+ else if (typ1->v_type != typ2->v_type
+ || (type != TYPE_EQUAL && type != TYPE_NEQUAL))
+ {
+ if (typ1->v_type != typ2->v_type)
+ emsg(_("E977: Can only compare Blob with Blob"));
+ else
+ emsg(_(e_invalblob));
+ clear_tv(typ1);
+ return FAIL;
+ }
+ else
+ {
+ // Compare two Blobs for being equal or unequal.
+ n1 = blob_equal(typ1->vval.v_blob, typ2->vval.v_blob);
+ if (type == TYPE_NEQUAL)
+ n1 = !n1;
+ }
+ }
+ else if (typ1->v_type == VAR_LIST || typ2->v_type == VAR_LIST)
+ {
+ if (type_is)
+ {
+ n1 = (typ1->v_type == typ2->v_type
+ && typ1->vval.v_list == typ2->vval.v_list);
+ if (type == TYPE_NEQUAL)
+ n1 = !n1;
+ }
+ else if (typ1->v_type != typ2->v_type
+ || (type != TYPE_EQUAL && type != TYPE_NEQUAL))
+ {
+ if (typ1->v_type != typ2->v_type)
+ emsg(_("E691: Can only compare List with List"));
+ else
+ emsg(_("E692: Invalid operation for List"));
+ clear_tv(typ1);
+ return FAIL;
+ }
+ else
+ {
+ /* Compare two Lists for being equal or unequal. */
+ n1 = list_equal(typ1->vval.v_list, typ2->vval.v_list,
+ ic, FALSE);
+ if (type == TYPE_NEQUAL)
+ n1 = !n1;
+ }
+ }
+
+ else if (typ1->v_type == VAR_DICT || typ2->v_type == VAR_DICT)
+ {
+ if (type_is)
+ {
+ n1 = (typ1->v_type == typ2->v_type
+ && typ1->vval.v_dict == typ2->vval.v_dict);
+ if (type == TYPE_NEQUAL)
+ n1 = !n1;
+ }
+ else if (typ1->v_type != typ2->v_type
+ || (type != TYPE_EQUAL && type != TYPE_NEQUAL))
+ {
+ if (typ1->v_type != typ2->v_type)
+ emsg(_("E735: Can only compare Dictionary with Dictionary"));
+ else
+ emsg(_("E736: Invalid operation for Dictionary"));
+ clear_tv(typ1);
+ return FAIL;
+ }
+ else
+ {
+ /* Compare two Dictionaries for being equal or unequal. */
+ n1 = dict_equal(typ1->vval.v_dict, typ2->vval.v_dict,
+ ic, FALSE);
+ if (type == TYPE_NEQUAL)
+ n1 = !n1;
+ }
+ }
+
+ else if (typ1->v_type == VAR_FUNC || typ2->v_type == VAR_FUNC
+ || typ1->v_type == VAR_PARTIAL || typ2->v_type == VAR_PARTIAL)
+ {
+ if (type != TYPE_EQUAL && type != TYPE_NEQUAL)
+ {
+ emsg(_("E694: Invalid operation for Funcrefs"));
+ clear_tv(typ1);
+ return FAIL;
+ }
+ if ((typ1->v_type == VAR_PARTIAL
+ && typ1->vval.v_partial == NULL)
+ || (typ2->v_type == VAR_PARTIAL
+ && typ2->vval.v_partial == NULL))
+ /* when a partial is NULL assume not equal */
+ n1 = FALSE;
+ else if (type_is)
+ {
+ if (typ1->v_type == VAR_FUNC && typ2->v_type == VAR_FUNC)
+ /* strings are considered the same if their value is
+ * the same */
+ n1 = tv_equal(typ1, typ2, ic, FALSE);
+ else if (typ1->v_type == VAR_PARTIAL
+ && typ2->v_type == VAR_PARTIAL)
+ n1 = (typ1->vval.v_partial == typ2->vval.v_partial);
+ else
+ n1 = FALSE;
+ }
+ else
+ n1 = tv_equal(typ1, typ2, ic, FALSE);
+ if (type == TYPE_NEQUAL)
+ n1 = !n1;
+ }
+
+#ifdef FEAT_FLOAT
+ /*
+ * If one of the two variables is a float, compare as a float.
+ * When using "=~" or "!~", always compare as string.
+ */
+ else if ((typ1->v_type == VAR_FLOAT || typ2->v_type == VAR_FLOAT)
+ && type != TYPE_MATCH && type != TYPE_NOMATCH)
+ {
+ float_T f1, f2;
+
+ if (typ1->v_type == VAR_FLOAT)
+ f1 = typ1->vval.v_float;
+ else
+ f1 = tv_get_number(typ1);
+ if (typ2->v_type == VAR_FLOAT)
+ f2 = typ2->vval.v_float;
+ else
+ f2 = tv_get_number(typ2);
+ n1 = FALSE;
+ switch (type)
+ {
+ case TYPE_EQUAL: n1 = (f1 == f2); break;
+ case TYPE_NEQUAL: n1 = (f1 != f2); break;
+ case TYPE_GREATER: n1 = (f1 > f2); break;
+ case TYPE_GEQUAL: n1 = (f1 >= f2); break;
+ case TYPE_SMALLER: n1 = (f1 < f2); break;
+ case TYPE_SEQUAL: n1 = (f1 <= f2); break;
+ case TYPE_UNKNOWN:
+ case TYPE_MATCH:
+ case TYPE_NOMATCH: break; /* avoid gcc warning */
+ }
+ }
+#endif
+
+ /*
+ * If one of the two variables is a number, compare as a number.
+ * When using "=~" or "!~", always compare as string.
+ */
+ else if ((typ1->v_type == VAR_NUMBER || typ2->v_type == VAR_NUMBER)
+ && type != TYPE_MATCH && type != TYPE_NOMATCH)
+ {
+ n1 = tv_get_number(typ1);
+ n2 = tv_get_number(typ2);
+ switch (type)
+ {
+ case TYPE_EQUAL: n1 = (n1 == n2); break;
+ case TYPE_NEQUAL: n1 = (n1 != n2); break;
+ case TYPE_GREATER: n1 = (n1 > n2); break;
+ case TYPE_GEQUAL: n1 = (n1 >= n2); break;
+ case TYPE_SMALLER: n1 = (n1 < n2); break;
+ case TYPE_SEQUAL: n1 = (n1 <= n2); break;
+ case TYPE_UNKNOWN:
+ case TYPE_MATCH:
+ case TYPE_NOMATCH: break; /* avoid gcc warning */
+ }
+ }
+ else
+ {
+ s1 = tv_get_string_buf(typ1, buf1);
+ s2 = tv_get_string_buf(typ2, buf2);
+ if (type != TYPE_MATCH && type != TYPE_NOMATCH)
+ i = ic ? MB_STRICMP(s1, s2) : STRCMP(s1, s2);
+ else
+ i = 0;
+ n1 = FALSE;
+ switch (type)
+ {
+ case TYPE_EQUAL: n1 = (i == 0); break;
+ case TYPE_NEQUAL: n1 = (i != 0); break;
+ case TYPE_GREATER: n1 = (i > 0); break;
+ case TYPE_GEQUAL: n1 = (i >= 0); break;
+ case TYPE_SMALLER: n1 = (i < 0); break;
+ case TYPE_SEQUAL: n1 = (i <= 0); break;
+
+ case TYPE_MATCH:
+ case TYPE_NOMATCH:
+ n1 = pattern_match(s2, s1, ic);
+ if (type == TYPE_NOMATCH)
+ n1 = !n1;
+ break;
+
+ case TYPE_UNKNOWN: break; /* avoid gcc warning */
+ }
+ }
+ clear_tv(typ1);
+ typ1->v_type = VAR_NUMBER;
+ typ1->vval.v_number = n1;
+
+ return OK;
+}
+
+ char_u *
+typval_tostring(typval_T *arg)
+{
+ char_u *tofree;
+ char_u numbuf[NUMBUFLEN];
+ char_u *ret = NULL;
+
+ if (arg == NULL)
+ return vim_strsave((char_u *)"(does not exist)");
+ ret = tv2string(arg, &tofree, numbuf, 0);
+ /* Make a copy if we have a value but it's not in allocated memory. */
+ if (ret != NULL && tofree == NULL)
+ ret = vim_strsave(ret);
+ return ret;
+}
+
+ int
+var_exists(char_u *var)
+{
+ char_u *name;
+ char_u *tofree;
+ typval_T tv;
+ int len = 0;
+ int n = FALSE;
+
+ /* get_name_len() takes care of expanding curly braces */
+ name = var;
+ len = get_name_len(&var, &tofree, TRUE, FALSE);
+ if (len > 0)
+ {
+ if (tofree != NULL)
+ name = tofree;
+ n = (get_var_tv(name, len, &tv, NULL, FALSE, TRUE) == OK);
+ if (n)
+ {
+ /* handle d.key, l[idx], f(expr) */
+ n = (handle_subscript(&var, &tv, TRUE, FALSE) == OK);
+ if (n)
+ clear_tv(&tv);
+ }
+ }
+ if (*var != NUL)
+ n = FALSE;
+
+ vim_free(tofree);
+ return n;
+}
+
+#endif /* FEAT_EVAL */
+
+
+#if defined(FEAT_MODIFY_FNAME) || defined(FEAT_EVAL) || defined(PROTO)
+
+#ifdef WIN3264
+/*
+ * Functions for ":8" filename modifier: get 8.3 version of a filename.
+ */
+
+/*
+ * Get the short path (8.3) for the filename in "fnamep".
+ * Only works for a valid file name.
+ * When the path gets longer "fnamep" is changed and the allocated buffer
+ * is put in "bufp".
+ * *fnamelen is the length of "fnamep" and set to 0 for a nonexistent path.
+ * Returns OK on success, FAIL on failure.
+ */
+ static int
+get_short_pathname(char_u **fnamep, char_u **bufp, int *fnamelen)
+{
+ int l, len;
+ char_u *newbuf;
+
+ len = *fnamelen;
+ l = GetShortPathName((LPSTR)*fnamep, (LPSTR)*fnamep, len);
+ if (l > len - 1)
+ {
+ /* If that doesn't work (not enough space), then save the string
+ * and try again with a new buffer big enough. */
+ newbuf = vim_strnsave(*fnamep, l);
+ if (newbuf == NULL)
+ return FAIL;
+
+ vim_free(*bufp);
+ *fnamep = *bufp = newbuf;
+
+ /* Really should always succeed, as the buffer is big enough. */
+ l = GetShortPathName((LPSTR)*fnamep, (LPSTR)*fnamep, l+1);
+ }
+
+ *fnamelen = l;
+ return OK;
+}
+
+/*
+ * Get the short path (8.3) for the filename in "fname". The converted
+ * path is returned in "bufp".
+ *
+ * Some of the directories specified in "fname" may not exist. This function
+ * will shorten the existing directories at the beginning of the path and then
+ * append the remaining non-existing path.
+ *
+ * fname - Pointer to the filename to shorten. On return, contains the
+ * pointer to the shortened pathname
+ * bufp - Pointer to an allocated buffer for the filename.
+ * fnamelen - Length of the filename pointed to by fname
+ *
+ * Returns OK on success (or nothing done) and FAIL on failure (out of memory).
+ */
+ static int
+shortpath_for_invalid_fname(
+ char_u **fname,
+ char_u **bufp,
+ int *fnamelen)
+{
+ char_u *short_fname, *save_fname, *pbuf_unused;
+ char_u *endp, *save_endp;
+ char_u ch;
+ int old_len, len;
+ int new_len, sfx_len;
+ int retval = OK;
+
+ /* Make a copy */
+ old_len = *fnamelen;
+ save_fname = vim_strnsave(*fname, old_len);
+ pbuf_unused = NULL;
+ short_fname = NULL;
+
+ endp = save_fname + old_len - 1; /* Find the end of the copy */
+ save_endp = endp;
+
+ /*
+ * Try shortening the supplied path till it succeeds by removing one
+ * directory at a time from the tail of the path.
+ */
+ len = 0;
+ for (;;)
+ {
+ /* go back one path-separator */
+ while (endp > save_fname && !after_pathsep(save_fname, endp + 1))
+ --endp;
+ if (endp <= save_fname)
+ break; /* processed the complete path */
+
+ /*
+ * Replace the path separator with a NUL and try to shorten the
+ * resulting path.
+ */
+ ch = *endp;
+ *endp = 0;
+ short_fname = save_fname;
+ len = (int)STRLEN(short_fname) + 1;
+ if (get_short_pathname(&short_fname, &pbuf_unused, &len) == FAIL)
+ {
+ retval = FAIL;
+ goto theend;
+ }
+ *endp = ch; /* preserve the string */
+
+ if (len > 0)
+ break; /* successfully shortened the path */
+
+ /* failed to shorten the path. Skip the path separator */
+ --endp;
+ }
+
+ if (len > 0)
+ {
+ /*
+ * Succeeded in shortening the path. Now concatenate the shortened
+ * path with the remaining path at the tail.
+ */
+
+ /* Compute the length of the new path. */
+ sfx_len = (int)(save_endp - endp) + 1;
+ new_len = len + sfx_len;
+
+ *fnamelen = new_len;
+ vim_free(*bufp);
+ if (new_len > old_len)
+ {
+ /* There is not enough space in the currently allocated string,
+ * copy it to a buffer big enough. */
+ *fname = *bufp = vim_strnsave(short_fname, new_len);
+ if (*fname == NULL)
+ {
+ retval = FAIL;
+ goto theend;
+ }
+ }
+ else
+ {
+ /* Transfer short_fname to the main buffer (it's big enough),
+ * unless get_short_pathname() did its work in-place. */
+ *fname = *bufp = save_fname;
+ if (short_fname != save_fname)
+ vim_strncpy(save_fname, short_fname, len);
+ save_fname = NULL;
+ }
+
+ /* concat the not-shortened part of the path */
+ vim_strncpy(*fname + len, endp, sfx_len);
+ (*fname)[new_len] = NUL;
+ }
+
+theend:
+ vim_free(pbuf_unused);
+ vim_free(save_fname);
+
+ return retval;
+}
+
+/*
+ * Get a pathname for a partial path.
+ * Returns OK for success, FAIL for failure.
+ */
+ static int
+shortpath_for_partial(
+ char_u **fnamep,
+ char_u **bufp,
+ int *fnamelen)
+{
+ int sepcount, len, tflen;
+ char_u *p;
+ char_u *pbuf, *tfname;
+ int hasTilde;
+
+ /* Count up the path separators from the RHS.. so we know which part
+ * of the path to return. */
+ sepcount = 0;
+ for (p = *fnamep; p < *fnamep + *fnamelen; MB_PTR_ADV(p))
+ if (vim_ispathsep(*p))
+ ++sepcount;
+
+ /* Need full path first (use expand_env() to remove a "~/") */
+ hasTilde = (**fnamep == '~');
+ if (hasTilde)
+ pbuf = tfname = expand_env_save(*fnamep);
+ else
+ pbuf = tfname = FullName_save(*fnamep, FALSE);
+
+ len = tflen = (int)STRLEN(tfname);
+
+ if (get_short_pathname(&tfname, &pbuf, &len) == FAIL)
+ return FAIL;
+
+ if (len == 0)
+ {
+ /* Don't have a valid filename, so shorten the rest of the
+ * path if we can. This CAN give us invalid 8.3 filenames, but
+ * there's not a lot of point in guessing what it might be.
+ */
+ len = tflen;
+ if (shortpath_for_invalid_fname(&tfname, &pbuf, &len) == FAIL)
+ return FAIL;
+ }
+
+ /* Count the paths backward to find the beginning of the desired string. */
+ for (p = tfname + len - 1; p >= tfname; --p)
+ {
+ if (has_mbyte)
+ p -= mb_head_off(tfname, p);
+ if (vim_ispathsep(*p))
+ {
+ if (sepcount == 0 || (hasTilde && sepcount == 1))
+ break;
+ else
+ sepcount --;
+ }
+ }
+ if (hasTilde)
+ {
+ --p;
+ if (p >= tfname)
+ *p = '~';
+ else
+ return FAIL;
+ }
+ else
+ ++p;
+
+ /* Copy in the string - p indexes into tfname - allocated at pbuf */
+ vim_free(*bufp);
+ *fnamelen = (int)STRLEN(p);
+ *bufp = pbuf;
+ *fnamep = p;
+
+ return OK;
+}
+#endif /* WIN3264 */
+
+/*
+ * Adjust a filename, according to a string of modifiers.
+ * *fnamep must be NUL terminated when called. When returning, the length is
+ * determined by *fnamelen.
+ * Returns VALID_ flags or -1 for failure.
+ * When there is an error, *fnamep is set to NULL.
+ */
+ int
+modify_fname(
+ char_u *src, // string with modifiers
+ int tilde_file, // "~" is a file name, not $HOME
+ int *usedlen, // characters after src that are used
+ char_u **fnamep, // file name so far
+ char_u **bufp, // buffer for allocated file name or NULL
+ int *fnamelen) // length of fnamep
+{
+ int valid = 0;
+ char_u *tail;
+ char_u *s, *p, *pbuf;
+ char_u dirname[MAXPATHL];
+ int c;
+ int has_fullname = 0;
+#ifdef WIN3264
+ char_u *fname_start = *fnamep;
+ int has_shortname = 0;
+#endif
+
+repeat:
+ /* ":p" - full path/file_name */
+ if (src[*usedlen] == ':' && src[*usedlen + 1] == 'p')
+ {
+ has_fullname = 1;
+
+ valid |= VALID_PATH;
+ *usedlen += 2;
+
+ /* Expand "~/path" for all systems and "~user/path" for Unix and VMS */
+ if ((*fnamep)[0] == '~'
+#if !defined(UNIX) && !(defined(VMS) && defined(USER_HOME))
+ && ((*fnamep)[1] == '/'
+# ifdef BACKSLASH_IN_FILENAME
+ || (*fnamep)[1] == '\\'
+# endif
+ || (*fnamep)[1] == NUL)
+#endif
+ && !(tilde_file && (*fnamep)[1] == NUL)
+ )
+ {
+ *fnamep = expand_env_save(*fnamep);
+ vim_free(*bufp); /* free any allocated file name */
+ *bufp = *fnamep;
+ if (*fnamep == NULL)
+ return -1;
+ }
+
+ /* When "/." or "/.." is used: force expansion to get rid of it. */
+ for (p = *fnamep; *p != NUL; MB_PTR_ADV(p))
+ {
+ if (vim_ispathsep(*p)
+ && p[1] == '.'
+ && (p[2] == NUL
+ || vim_ispathsep(p[2])
+ || (p[2] == '.'
+ && (p[3] == NUL || vim_ispathsep(p[3])))))
+ break;
+ }
+
+ /* FullName_save() is slow, don't use it when not needed. */
+ if (*p != NUL || !vim_isAbsName(*fnamep))
+ {
+ *fnamep = FullName_save(*fnamep, *p != NUL);
+ vim_free(*bufp); /* free any allocated file name */
+ *bufp = *fnamep;
+ if (*fnamep == NULL)
+ return -1;
+ }
+
+#ifdef WIN3264
+# if _WIN32_WINNT >= 0x0500
+ if (vim_strchr(*fnamep, '~') != NULL)
+ {
+ /* Expand 8.3 filename to full path. Needed to make sure the same
+ * file does not have two different names.
+ * Note: problem does not occur if _WIN32_WINNT < 0x0500. */
+ p = alloc(_MAX_PATH + 1);
+ if (p != NULL)
+ {
+ if (GetLongPathName((LPSTR)*fnamep, (LPSTR)p, _MAX_PATH))
+ {
+ vim_free(*bufp);
+ *bufp = *fnamep = p;
+ }
+ else
+ vim_free(p);
+ }
+ }
+# endif
+#endif
+ /* Append a path separator to a directory. */
+ if (mch_isdir(*fnamep))
+ {
+ /* Make room for one or two extra characters. */
+ *fnamep = vim_strnsave(*fnamep, (int)STRLEN(*fnamep) + 2);
+ vim_free(*bufp); /* free any allocated file name */
+ *bufp = *fnamep;
+ if (*fnamep == NULL)
+ return -1;
+ add_pathsep(*fnamep);
+ }
+ }
+
+ /* ":." - path relative to the current directory */
+ /* ":~" - path relative to the home directory */
+ /* ":8" - shortname path - postponed till after */
+ while (src[*usedlen] == ':'
+ && ((c = src[*usedlen + 1]) == '.' || c == '~' || c == '8'))
+ {
+ *usedlen += 2;
+ if (c == '8')
+ {
+#ifdef WIN3264
+ has_shortname = 1; /* Postpone this. */
+#endif
+ continue;
+ }
+ pbuf = NULL;
+ /* Need full path first (use expand_env() to remove a "~/") */
+ if (!has_fullname)
+ {
+ if (c == '.' && **fnamep == '~')
+ p = pbuf = expand_env_save(*fnamep);
+ else
+ p = pbuf = FullName_save(*fnamep, FALSE);
+ }
+ else
+ p = *fnamep;
+
+ has_fullname = 0;
+
+ if (p != NULL)
+ {
+ if (c == '.')
+ {
+ mch_dirname(dirname, MAXPATHL);
+ s = shorten_fname(p, dirname);
+ if (s != NULL)
+ {
+ *fnamep = s;
+ if (pbuf != NULL)
+ {
+ vim_free(*bufp); /* free any allocated file name */
+ *bufp = pbuf;
+ pbuf = NULL;
+ }
+ }
+ }
+ else
+ {
+ home_replace(NULL, p, dirname, MAXPATHL, TRUE);
+ /* Only replace it when it starts with '~' */
+ if (*dirname == '~')
+ {
+ s = vim_strsave(dirname);
+ if (s != NULL)
+ {
+ *fnamep = s;
+ vim_free(*bufp);
+ *bufp = s;
+ }
+ }
+ }
+ vim_free(pbuf);
+ }
+ }
+
+ tail = gettail(*fnamep);
+ *fnamelen = (int)STRLEN(*fnamep);
+
+ /* ":h" - head, remove "/file_name", can be repeated */
+ /* Don't remove the first "/" or "c:\" */
+ while (src[*usedlen] == ':' && src[*usedlen + 1] == 'h')
+ {
+ valid |= VALID_HEAD;
+ *usedlen += 2;
+ s = get_past_head(*fnamep);
+ while (tail > s && after_pathsep(s, tail))
+ MB_PTR_BACK(*fnamep, tail);
+ *fnamelen = (int)(tail - *fnamep);
+#ifdef VMS
+ if (*fnamelen > 0)
+ *fnamelen += 1; /* the path separator is part of the path */
+#endif
+ if (*fnamelen == 0)
+ {
+ /* Result is empty. Turn it into "." to make ":cd %:h" work. */
+ p = vim_strsave((char_u *)".");
+ if (p == NULL)
+ return -1;
+ vim_free(*bufp);
+ *bufp = *fnamep = tail = p;
+ *fnamelen = 1;
+ }
+ else
+ {
+ while (tail > s && !after_pathsep(s, tail))
+ MB_PTR_BACK(*fnamep, tail);
+ }
+ }
+
+ /* ":8" - shortname */
+ if (src[*usedlen] == ':' && src[*usedlen + 1] == '8')
+ {
+ *usedlen += 2;
+#ifdef WIN3264
+ has_shortname = 1;
+#endif
+ }
+
+#ifdef WIN3264
+ /*
+ * Handle ":8" after we have done 'heads' and before we do 'tails'.
+ */
+ if (has_shortname)
+ {
+ /* Copy the string if it is shortened by :h and when it wasn't copied
+ * yet, because we are going to change it in place. Avoids changing
+ * the buffer name for "%:8". */
+ if (*fnamelen < (int)STRLEN(*fnamep) || *fnamep == fname_start)
+ {
+ p = vim_strnsave(*fnamep, *fnamelen);
+ if (p == NULL)
+ return -1;
+ vim_free(*bufp);
+ *bufp = *fnamep = p;
+ }
+
+ /* Split into two implementations - makes it easier. First is where
+ * there isn't a full name already, second is where there is. */
+ if (!has_fullname && !vim_isAbsName(*fnamep))
+ {
+ if (shortpath_for_partial(fnamep, bufp, fnamelen) == FAIL)
+ return -1;
+ }
+ else
+ {
+ int l = *fnamelen;
+
+ /* Simple case, already have the full-name.
+ * Nearly always shorter, so try first time. */
+ if (get_short_pathname(fnamep, bufp, &l) == FAIL)
+ return -1;
+
+ if (l == 0)
+ {
+ /* Couldn't find the filename, search the paths. */
+ l = *fnamelen;
+ if (shortpath_for_invalid_fname(fnamep, bufp, &l) == FAIL)
+ return -1;
+ }
+ *fnamelen = l;
+ }
+ }
+#endif /* WIN3264 */
+
+ /* ":t" - tail, just the basename */
+ if (src[*usedlen] == ':' && src[*usedlen + 1] == 't')
+ {
+ *usedlen += 2;
+ *fnamelen -= (int)(tail - *fnamep);
+ *fnamep = tail;
+ }
+
+ /* ":e" - extension, can be repeated */
+ /* ":r" - root, without extension, can be repeated */
+ while (src[*usedlen] == ':'
+ && (src[*usedlen + 1] == 'e' || src[*usedlen + 1] == 'r'))
+ {
+ /* find a '.' in the tail:
+ * - for second :e: before the current fname
+ * - otherwise: The last '.'
+ */
+ if (src[*usedlen + 1] == 'e' && *fnamep > tail)
+ s = *fnamep - 2;
+ else
+ s = *fnamep + *fnamelen - 1;
+ for ( ; s > tail; --s)
+ if (s[0] == '.')
+ break;
+ if (src[*usedlen + 1] == 'e') /* :e */
+ {
+ if (s > tail)
+ {
+ *fnamelen += (int)(*fnamep - (s + 1));
+ *fnamep = s + 1;
+#ifdef VMS
+ /* cut version from the extension */
+ s = *fnamep + *fnamelen - 1;
+ for ( ; s > *fnamep; --s)
+ if (s[0] == ';')
+ break;
+ if (s > *fnamep)
+ *fnamelen = s - *fnamep;
+#endif
+ }
+ else if (*fnamep <= tail)
+ *fnamelen = 0;
+ }
+ else /* :r */
+ {
+ if (s > tail) /* remove one extension */
+ *fnamelen = (int)(s - *fnamep);
+ }
+ *usedlen += 2;
+ }
+
+ /* ":s?pat?foo?" - substitute */
+ /* ":gs?pat?foo?" - global substitute */
+ if (src[*usedlen] == ':'
+ && (src[*usedlen + 1] == 's'
+ || (src[*usedlen + 1] == 'g' && src[*usedlen + 2] == 's')))
+ {
+ char_u *str;
+ char_u *pat;
+ char_u *sub;
+ int sep;
+ char_u *flags;
+ int didit = FALSE;
+
+ flags = (char_u *)"";
+ s = src + *usedlen + 2;
+ if (src[*usedlen + 1] == 'g')
+ {
+ flags = (char_u *)"g";
+ ++s;
+ }
+
+ sep = *s++;
+ if (sep)
+ {
+ /* find end of pattern */
+ p = vim_strchr(s, sep);
+ if (p != NULL)
+ {
+ pat = vim_strnsave(s, (int)(p - s));
+ if (pat != NULL)
+ {
+ s = p + 1;
+ /* find end of substitution */
+ p = vim_strchr(s, sep);
+ if (p != NULL)
+ {
+ sub = vim_strnsave(s, (int)(p - s));
+ str = vim_strnsave(*fnamep, *fnamelen);
+ if (sub != NULL && str != NULL)
+ {
+ *usedlen = (int)(p + 1 - src);
+ s = do_string_sub(str, pat, sub, NULL, flags);
+ if (s != NULL)
+ {
+ *fnamep = s;
+ *fnamelen = (int)STRLEN(s);
+ vim_free(*bufp);
+ *bufp = s;
+ didit = TRUE;
+ }
+ }
+ vim_free(sub);
+ vim_free(str);
+ }
+ vim_free(pat);
+ }
+ }
+ /* after using ":s", repeat all the modifiers */
+ if (didit)
+ goto repeat;
+ }
+ }
+
+ if (src[*usedlen] == ':' && src[*usedlen + 1] == 'S')
+ {
+ /* vim_strsave_shellescape() needs a NUL terminated string. */
+ c = (*fnamep)[*fnamelen];
+ if (c != NUL)
+ (*fnamep)[*fnamelen] = NUL;
+ p = vim_strsave_shellescape(*fnamep, FALSE, FALSE);
+ if (c != NUL)
+ (*fnamep)[*fnamelen] = c;
+ if (p == NULL)
+ return -1;
+ vim_free(*bufp);
+ *bufp = *fnamep = p;
+ *fnamelen = (int)STRLEN(p);
+ *usedlen += 2;
+ }
+
+ return valid;
+}
+
+/*
+ * Perform a substitution on "str" with pattern "pat" and substitute "sub".
+ * When "sub" is NULL "expr" is used, must be a VAR_FUNC or VAR_PARTIAL.
+ * "flags" can be "g" to do a global substitute.
+ * Returns an allocated string, NULL for error.
+ */
+ char_u *
+do_string_sub(
+ char_u *str,
+ char_u *pat,
+ char_u *sub,
+ typval_T *expr,
+ char_u *flags)
+{
+ int sublen;
+ regmatch_T regmatch;
+ int i;
+ int do_all;
+ char_u *tail;
+ char_u *end;
+ garray_T ga;
+ char_u *ret;
+ char_u *save_cpo;
+ char_u *zero_width = NULL;
+
+ /* Make 'cpoptions' empty, so that the 'l' flag doesn't work here */
+ save_cpo = p_cpo;
+ p_cpo = empty_option;
+
+ ga_init2(&ga, 1, 200);
+
+ do_all = (flags[0] == 'g');
+
+ regmatch.rm_ic = p_ic;
+ regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
+ if (regmatch.regprog != NULL)
+ {
+ tail = str;
+ end = str + STRLEN(str);
+ while (vim_regexec_nl(&regmatch, str, (colnr_T)(tail - str)))
+ {
+ /* Skip empty match except for first match. */
+ if (regmatch.startp[0] == regmatch.endp[0])
+ {
+ if (zero_width == regmatch.startp[0])
+ {
+ /* avoid getting stuck on a match with an empty string */
+ i = MB_PTR2LEN(tail);
+ mch_memmove((char_u *)ga.ga_data + ga.ga_len, tail,
+ (size_t)i);
+ ga.ga_len += i;
+ tail += i;
+ continue;
+ }
+ zero_width = regmatch.startp[0];
+ }
+
+ /*
+ * Get some space for a temporary buffer to do the substitution
+ * into. It will contain:
+ * - The text up to where the match is.
+ * - The substituted text.
+ * - The text after the match.
+ */
+ sublen = vim_regsub(&regmatch, sub, expr, tail, FALSE, TRUE, FALSE);
+ if (ga_grow(&ga, (int)((end - tail) + sublen -
+ (regmatch.endp[0] - regmatch.startp[0]))) == FAIL)
+ {
+ ga_clear(&ga);
+ break;
+ }
+
+ /* copy the text up to where the match is */
+ i = (int)(regmatch.startp[0] - tail);
+ mch_memmove((char_u *)ga.ga_data + ga.ga_len, tail, (size_t)i);
+ /* add the substituted text */
+ (void)vim_regsub(&regmatch, sub, expr, (char_u *)ga.ga_data
+ + ga.ga_len + i, TRUE, TRUE, FALSE);
+ ga.ga_len += i + sublen - 1;
+ tail = regmatch.endp[0];
+ if (*tail == NUL)
+ break;
+ if (!do_all)
+ break;
+ }
+
+ if (ga.ga_data != NULL)
+ STRCPY((char *)ga.ga_data + ga.ga_len, tail);
+
+ vim_regfree(regmatch.regprog);
+ }
+
+ ret = vim_strsave(ga.ga_data == NULL ? str : (char_u *)ga.ga_data);
+ ga_clear(&ga);
+ if (p_cpo == empty_option)
+ p_cpo = save_cpo;
+ else
+ /* Darn, evaluating {sub} expression or {expr} changed the value. */
+ free_string_option(save_cpo);
+
+ return ret;
+}
+
+ static int
+filter_map_one(typval_T *tv, typval_T *expr, int map, int *remp)
+{
+ typval_T rettv;
+ typval_T argv[3];
+ int retval = FAIL;
+
+ copy_tv(tv, &vimvars[VV_VAL].vv_tv);
+ argv[0] = vimvars[VV_KEY].vv_tv;
+ argv[1] = vimvars[VV_VAL].vv_tv;
+ if (eval_expr_typval(expr, argv, 2, &rettv) == FAIL)
+ goto theend;
+ if (map)
+ {
+ /* map(): replace the list item value */
+ clear_tv(tv);
+ rettv.v_lock = 0;
+ *tv = rettv;
+ }
+ else
+ {
+ int error = FALSE;
+
+ /* filter(): when expr is zero remove the item */
+ *remp = (tv_get_number_chk(&rettv, &error) == 0);
+ clear_tv(&rettv);
+ /* On type error, nothing has been removed; return FAIL to stop the
+ * loop. The error message was given by tv_get_number_chk(). */
+ if (error)
+ goto theend;
+ }
+ retval = OK;
+theend:
+ clear_tv(&vimvars[VV_VAL].vv_tv);
+ return retval;
+}
+
+
+/*
+ * Implementation of map() and filter().
+ */
+ void
+filter_map(typval_T *argvars, typval_T *rettv, int map)
+{
+ typval_T *expr;
+ listitem_T *li, *nli;
+ list_T *l = NULL;
+ dictitem_T *di;
+ hashtab_T *ht;
+ hashitem_T *hi;
+ dict_T *d = NULL;
+ typval_T save_val;
+ typval_T save_key;
+ blob_T *b = NULL;
+ int rem;
+ int todo;
+ char_u *ermsg = (char_u *)(map ? "map()" : "filter()");
+ char_u *arg_errmsg = (char_u *)(map ? N_("map() argument")
+ : N_("filter() argument"));
+ int save_did_emsg;
+ int idx = 0;
+
+ if (argvars[0].v_type == VAR_BLOB)
+ {
+ if ((b = argvars[0].vval.v_blob) == NULL)
+ return;
+ }
+ else if (argvars[0].v_type == VAR_LIST)
+ {
+ if ((l = argvars[0].vval.v_list) == NULL
+ || (!map && tv_check_lock(l->lv_lock, arg_errmsg, TRUE)))
+ return;
+ }
+ else if (argvars[0].v_type == VAR_DICT)
+ {
+ if ((d = argvars[0].vval.v_dict) == NULL
+ || (!map && tv_check_lock(d->dv_lock, arg_errmsg, TRUE)))
+ return;
+ }
+ else
+ {
+ semsg(_(e_listdictarg), ermsg);
+ return;
+ }
+
+ expr = &argvars[1];
+ /* On type errors, the preceding call has already displayed an error
+ * message. Avoid a misleading error message for an empty string that
+ * was not passed as argument. */
+ if (expr->v_type != VAR_UNKNOWN)
+ {
+ prepare_vimvar(VV_VAL, &save_val);
+
+ /* We reset "did_emsg" to be able to detect whether an error
+ * occurred during evaluation of the expression. */
+ save_did_emsg = did_emsg;
+ did_emsg = FALSE;
+
+ prepare_vimvar(VV_KEY, &save_key);
+ if (argvars[0].v_type == VAR_DICT)
+ {
+ vimvars[VV_KEY].vv_type = VAR_STRING;
+
+ ht = &d->dv_hashtab;
+ hash_lock(ht);
+ todo = (int)ht->ht_used;
+ for (hi = ht->ht_array; todo > 0; ++hi)
+ {
+ if (!HASHITEM_EMPTY(hi))
+ {
+ int r;
+
+ --todo;
+ di = HI2DI(hi);
+ if (map &&
+ (tv_check_lock(di->di_tv.v_lock, arg_errmsg, TRUE)
+ || var_check_ro(di->di_flags, arg_errmsg, TRUE)))
+ break;
+ vimvars[VV_KEY].vv_str = vim_strsave(di->di_key);
+ r = filter_map_one(&di->di_tv, expr, map, &rem);
+ clear_tv(&vimvars[VV_KEY].vv_tv);
+ if (r == FAIL || did_emsg)
+ break;
+ if (!map && rem)
+ {
+ if (var_check_fixed(di->di_flags, arg_errmsg, TRUE)
+ || var_check_ro(di->di_flags, arg_errmsg, TRUE))
+ break;
+ dictitem_remove(d, di);
+ }
+ }
+ }
+ hash_unlock(ht);
+ }
+ else if (argvars[0].v_type == VAR_BLOB)
+ {
+ int i;
+ typval_T tv;
+
+ vimvars[VV_KEY].vv_type = VAR_NUMBER;
+ for (i = 0; i < b->bv_ga.ga_len; i++)
+ {
+ tv.v_type = VAR_NUMBER;
+ tv.vval.v_number = blob_get(b, i);
+ vimvars[VV_KEY].vv_nr = idx;
+ if (filter_map_one(&tv, expr, map, &rem) == FAIL || did_emsg)
+ break;
+ if (tv.v_type != VAR_NUMBER)
+ {
+ emsg(_(e_invalblob));
+ return;
+ }
+ tv.v_type = VAR_NUMBER;
+ blob_set(b, i, tv.vval.v_number);
+ if (!map && rem)
+ {
+ char_u *p = (char_u *)argvars[0].vval.v_blob->bv_ga.ga_data;
+
+ mch_memmove(p + idx, p + i + 1,
+ (size_t)b->bv_ga.ga_len - i - 1);
+ --b->bv_ga.ga_len;
+ --i;
+ }
+ }
+ }
+ else
+ {
+ // argvars[0].v_type == VAR_LIST
+ vimvars[VV_KEY].vv_type = VAR_NUMBER;
+
+ for (li = l->lv_first; li != NULL; li = nli)
+ {
+ if (map && tv_check_lock(li->li_tv.v_lock, arg_errmsg, TRUE))
+ break;
+ nli = li->li_next;
+ vimvars[VV_KEY].vv_nr = idx;
+ if (filter_map_one(&li->li_tv, expr, map, &rem) == FAIL
+ || did_emsg)
+ break;
+ if (!map && rem)
+ listitem_remove(l, li);
+ ++idx;
+ }
+ }
+
+ restore_vimvar(VV_KEY, &save_key);
+ restore_vimvar(VV_VAL, &save_val);
+
+ did_emsg |= save_did_emsg;
+ }
+
+ copy_tv(&argvars[0], rettv);
+}
+
+#endif /* defined(FEAT_MODIFY_FNAME) || defined(FEAT_EVAL) */
diff --git a/src/evalfunc.c b/src/evalfunc.c
new file mode 100644
index 0000000..fa7ed9b
--- /dev/null
+++ b/src/evalfunc.c
@@ -0,0 +1,14809 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * evalfunc.c: Builtin functions
+ */
+#define USING_FLOAT_STUFF
+
+#include "vim.h"
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+
+#ifdef AMIGA
+# include <time.h> /* for strftime() */
+#endif
+
+#ifdef VMS
+# include <float.h>
+#endif
+
+#ifdef MACOS_X
+# include <time.h> /* for time_t */
+#endif
+
+static char *e_listarg = N_("E686: Argument of %s must be a List");
+static char *e_listblobarg = N_("E899: Argument of %s must be a List or Blob");
+static char *e_stringreq = N_("E928: String required");
+
+#ifdef FEAT_FLOAT
+static void f_abs(typval_T *argvars, typval_T *rettv);
+static void f_acos(typval_T *argvars, typval_T *rettv);
+#endif
+static void f_add(typval_T *argvars, typval_T *rettv);
+static void f_and(typval_T *argvars, typval_T *rettv);
+static void f_append(typval_T *argvars, typval_T *rettv);
+static void f_appendbufline(typval_T *argvars, typval_T *rettv);
+static void f_argc(typval_T *argvars, typval_T *rettv);
+static void f_argidx(typval_T *argvars, typval_T *rettv);
+static void f_arglistid(typval_T *argvars, typval_T *rettv);
+static void f_argv(typval_T *argvars, typval_T *rettv);
+static void f_assert_beeps(typval_T *argvars, typval_T *rettv);
+static void f_assert_equal(typval_T *argvars, typval_T *rettv);
+static void f_assert_equalfile(typval_T *argvars, typval_T *rettv);
+static void f_assert_exception(typval_T *argvars, typval_T *rettv);
+static void f_assert_fails(typval_T *argvars, typval_T *rettv);
+static void f_assert_false(typval_T *argvars, typval_T *rettv);
+static void f_assert_inrange(typval_T *argvars, typval_T *rettv);
+static void f_assert_match(typval_T *argvars, typval_T *rettv);
+static void f_assert_notequal(typval_T *argvars, typval_T *rettv);
+static void f_assert_notmatch(typval_T *argvars, typval_T *rettv);
+static void f_assert_report(typval_T *argvars, typval_T *rettv);
+static void f_assert_true(typval_T *argvars, typval_T *rettv);
+#ifdef FEAT_FLOAT
+static void f_asin(typval_T *argvars, typval_T *rettv);
+static void f_atan(typval_T *argvars, typval_T *rettv);
+static void f_atan2(typval_T *argvars, typval_T *rettv);
+#endif
+#ifdef FEAT_BEVAL
+static void f_balloon_show(typval_T *argvars, typval_T *rettv);
+# if defined(FEAT_BEVAL_TERM)
+static void f_balloon_split(typval_T *argvars, typval_T *rettv);
+# endif
+#endif
+static void f_browse(typval_T *argvars, typval_T *rettv);
+static void f_browsedir(typval_T *argvars, typval_T *rettv);
+static void f_bufexists(typval_T *argvars, typval_T *rettv);
+static void f_buflisted(typval_T *argvars, typval_T *rettv);
+static void f_bufloaded(typval_T *argvars, typval_T *rettv);
+static void f_bufname(typval_T *argvars, typval_T *rettv);
+static void f_bufnr(typval_T *argvars, typval_T *rettv);
+static void f_bufwinid(typval_T *argvars, typval_T *rettv);
+static void f_bufwinnr(typval_T *argvars, typval_T *rettv);
+static void f_byte2line(typval_T *argvars, typval_T *rettv);
+static void byteidx(typval_T *argvars, typval_T *rettv, int comp);
+static void f_byteidx(typval_T *argvars, typval_T *rettv);
+static void f_byteidxcomp(typval_T *argvars, typval_T *rettv);
+static void f_call(typval_T *argvars, typval_T *rettv);
+#ifdef FEAT_FLOAT
+static void f_ceil(typval_T *argvars, typval_T *rettv);
+#endif
+#ifdef FEAT_JOB_CHANNEL
+static void f_ch_canread(typval_T *argvars, typval_T *rettv);
+static void f_ch_close(typval_T *argvars, typval_T *rettv);
+static void f_ch_close_in(typval_T *argvars, typval_T *rettv);
+static void f_ch_evalexpr(typval_T *argvars, typval_T *rettv);
+static void f_ch_evalraw(typval_T *argvars, typval_T *rettv);
+static void f_ch_getbufnr(typval_T *argvars, typval_T *rettv);
+static void f_ch_getjob(typval_T *argvars, typval_T *rettv);
+static void f_ch_info(typval_T *argvars, typval_T *rettv);
+static void f_ch_log(typval_T *argvars, typval_T *rettv);
+static void f_ch_logfile(typval_T *argvars, typval_T *rettv);
+static void f_ch_open(typval_T *argvars, typval_T *rettv);
+static void f_ch_read(typval_T *argvars, typval_T *rettv);
+static void f_ch_readblob(typval_T *argvars, typval_T *rettv);
+static void f_ch_readraw(typval_T *argvars, typval_T *rettv);
+static void f_ch_sendexpr(typval_T *argvars, typval_T *rettv);
+static void f_ch_sendraw(typval_T *argvars, typval_T *rettv);
+static void f_ch_setoptions(typval_T *argvars, typval_T *rettv);
+static void f_ch_status(typval_T *argvars, typval_T *rettv);
+#endif
+static void f_changenr(typval_T *argvars, typval_T *rettv);
+static void f_char2nr(typval_T *argvars, typval_T *rettv);
+static void f_cindent(typval_T *argvars, typval_T *rettv);
+static void f_clearmatches(typval_T *argvars, typval_T *rettv);
+static void f_col(typval_T *argvars, typval_T *rettv);
+#if defined(FEAT_INS_EXPAND)
+static void f_complete(typval_T *argvars, typval_T *rettv);
+static void f_complete_add(typval_T *argvars, typval_T *rettv);
+static void f_complete_check(typval_T *argvars, typval_T *rettv);
+#endif
+static void f_confirm(typval_T *argvars, typval_T *rettv);
+static void f_copy(typval_T *argvars, typval_T *rettv);
+#ifdef FEAT_FLOAT
+static void f_cos(typval_T *argvars, typval_T *rettv);
+static void f_cosh(typval_T *argvars, typval_T *rettv);
+#endif
+static void f_count(typval_T *argvars, typval_T *rettv);
+static void f_cscope_connection(typval_T *argvars, typval_T *rettv);
+static void f_cursor(typval_T *argsvars, typval_T *rettv);
+#ifdef WIN3264
+static void f_debugbreak(typval_T *argvars, typval_T *rettv);
+#endif
+static void f_deepcopy(typval_T *argvars, typval_T *rettv);
+static void f_delete(typval_T *argvars, typval_T *rettv);
+static void f_deletebufline(typval_T *argvars, typval_T *rettv);
+static void f_did_filetype(typval_T *argvars, typval_T *rettv);
+static void f_diff_filler(typval_T *argvars, typval_T *rettv);
+static void f_diff_hlID(typval_T *argvars, typval_T *rettv);
+static void f_empty(typval_T *argvars, typval_T *rettv);
+static void f_escape(typval_T *argvars, typval_T *rettv);
+static void f_eval(typval_T *argvars, typval_T *rettv);
+static void f_eventhandler(typval_T *argvars, typval_T *rettv);
+static void f_executable(typval_T *argvars, typval_T *rettv);
+static void f_execute(typval_T *argvars, typval_T *rettv);
+static void f_exepath(typval_T *argvars, typval_T *rettv);
+static void f_exists(typval_T *argvars, typval_T *rettv);
+#ifdef FEAT_FLOAT
+static void f_exp(typval_T *argvars, typval_T *rettv);
+#endif
+static void f_expand(typval_T *argvars, typval_T *rettv);
+static void f_extend(typval_T *argvars, typval_T *rettv);
+static void f_feedkeys(typval_T *argvars, typval_T *rettv);
+static void f_filereadable(typval_T *argvars, typval_T *rettv);
+static void f_filewritable(typval_T *argvars, typval_T *rettv);
+static void f_filter(typval_T *argvars, typval_T *rettv);
+static void f_finddir(typval_T *argvars, typval_T *rettv);
+static void f_findfile(typval_T *argvars, typval_T *rettv);
+#ifdef FEAT_FLOAT
+static void f_float2nr(typval_T *argvars, typval_T *rettv);
+static void f_floor(typval_T *argvars, typval_T *rettv);
+static void f_fmod(typval_T *argvars, typval_T *rettv);
+#endif
+static void f_fnameescape(typval_T *argvars, typval_T *rettv);
+static void f_fnamemodify(typval_T *argvars, typval_T *rettv);
+static void f_foldclosed(typval_T *argvars, typval_T *rettv);
+static void f_foldclosedend(typval_T *argvars, typval_T *rettv);
+static void f_foldlevel(typval_T *argvars, typval_T *rettv);
+static void f_foldtext(typval_T *argvars, typval_T *rettv);
+static void f_foldtextresult(typval_T *argvars, typval_T *rettv);
+static void f_foreground(typval_T *argvars, typval_T *rettv);
+static void f_funcref(typval_T *argvars, typval_T *rettv);
+static void f_function(typval_T *argvars, typval_T *rettv);
+static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
+static void f_get(typval_T *argvars, typval_T *rettv);
+static void f_getbufinfo(typval_T *argvars, typval_T *rettv);
+static void f_getbufline(typval_T *argvars, typval_T *rettv);
+static void f_getbufvar(typval_T *argvars, typval_T *rettv);
+static void f_getchangelist(typval_T *argvars, typval_T *rettv);
+static void f_getchar(typval_T *argvars, typval_T *rettv);
+static void f_getcharmod(typval_T *argvars, typval_T *rettv);
+static void f_getcharsearch(typval_T *argvars, typval_T *rettv);
+static void f_getcmdline(typval_T *argvars, typval_T *rettv);
+#if defined(FEAT_CMDL_COMPL)
+static void f_getcompletion(typval_T *argvars, typval_T *rettv);
+#endif
+static void f_getcmdpos(typval_T *argvars, typval_T *rettv);
+static void f_getcmdtype(typval_T *argvars, typval_T *rettv);
+static void f_getcmdwintype(typval_T *argvars, typval_T *rettv);
+static void f_getcwd(typval_T *argvars, typval_T *rettv);
+static void f_getfontname(typval_T *argvars, typval_T *rettv);
+static void f_getfperm(typval_T *argvars, typval_T *rettv);
+static void f_getfsize(typval_T *argvars, typval_T *rettv);
+static void f_getftime(typval_T *argvars, typval_T *rettv);
+static void f_getftype(typval_T *argvars, typval_T *rettv);
+static void f_getjumplist(typval_T *argvars, typval_T *rettv);
+static void f_getline(typval_T *argvars, typval_T *rettv);
+static void f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED);
+static void f_getmatches(typval_T *argvars, typval_T *rettv);
+static void f_getpid(typval_T *argvars, typval_T *rettv);
+static void f_getcurpos(typval_T *argvars, typval_T *rettv);
+static void f_getpos(typval_T *argvars, typval_T *rettv);
+static void f_getqflist(typval_T *argvars, typval_T *rettv);
+static void f_getreg(typval_T *argvars, typval_T *rettv);
+static void f_getregtype(typval_T *argvars, typval_T *rettv);
+static void f_gettabinfo(typval_T *argvars, typval_T *rettv);
+static void f_gettabvar(typval_T *argvars, typval_T *rettv);
+static void f_gettabwinvar(typval_T *argvars, typval_T *rettv);
+static void f_gettagstack(typval_T *argvars, typval_T *rettv);
+static void f_getwininfo(typval_T *argvars, typval_T *rettv);
+static void f_getwinpos(typval_T *argvars, typval_T *rettv);
+static void f_getwinposx(typval_T *argvars, typval_T *rettv);
+static void f_getwinposy(typval_T *argvars, typval_T *rettv);
+static void f_getwinvar(typval_T *argvars, typval_T *rettv);
+static void f_glob(typval_T *argvars, typval_T *rettv);
+static void f_globpath(typval_T *argvars, typval_T *rettv);
+static void f_glob2regpat(typval_T *argvars, typval_T *rettv);
+static void f_has(typval_T *argvars, typval_T *rettv);
+static void f_has_key(typval_T *argvars, typval_T *rettv);
+static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
+static void f_hasmapto(typval_T *argvars, typval_T *rettv);
+static void f_histadd(typval_T *argvars, typval_T *rettv);
+static void f_histdel(typval_T *argvars, typval_T *rettv);
+static void f_histget(typval_T *argvars, typval_T *rettv);
+static void f_histnr(typval_T *argvars, typval_T *rettv);
+static void f_hlID(typval_T *argvars, typval_T *rettv);
+static void f_hlexists(typval_T *argvars, typval_T *rettv);
+static void f_hostname(typval_T *argvars, typval_T *rettv);
+static void f_iconv(typval_T *argvars, typval_T *rettv);
+static void f_indent(typval_T *argvars, typval_T *rettv);
+static void f_index(typval_T *argvars, typval_T *rettv);
+static void f_input(typval_T *argvars, typval_T *rettv);
+static void f_inputdialog(typval_T *argvars, typval_T *rettv);
+static void f_inputlist(typval_T *argvars, typval_T *rettv);
+static void f_inputrestore(typval_T *argvars, typval_T *rettv);
+static void f_inputsave(typval_T *argvars, typval_T *rettv);
+static void f_inputsecret(typval_T *argvars, typval_T *rettv);
+static void f_insert(typval_T *argvars, typval_T *rettv);
+static void f_invert(typval_T *argvars, typval_T *rettv);
+static void f_isdirectory(typval_T *argvars, typval_T *rettv);
+static void f_islocked(typval_T *argvars, typval_T *rettv);
+#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
+static void f_isnan(typval_T *argvars, typval_T *rettv);
+#endif
+static void f_items(typval_T *argvars, typval_T *rettv);
+#ifdef FEAT_JOB_CHANNEL
+static void f_job_getchannel(typval_T *argvars, typval_T *rettv);
+static void f_job_info(typval_T *argvars, typval_T *rettv);
+static void f_job_setoptions(typval_T *argvars, typval_T *rettv);
+static void f_job_start(typval_T *argvars, typval_T *rettv);
+static void f_job_stop(typval_T *argvars, typval_T *rettv);
+static void f_job_status(typval_T *argvars, typval_T *rettv);
+#endif
+static void f_join(typval_T *argvars, typval_T *rettv);
+static void f_js_decode(typval_T *argvars, typval_T *rettv);
+static void f_js_encode(typval_T *argvars, typval_T *rettv);
+static void f_json_decode(typval_T *argvars, typval_T *rettv);
+static void f_json_encode(typval_T *argvars, typval_T *rettv);
+static void f_keys(typval_T *argvars, typval_T *rettv);
+static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
+static void f_len(typval_T *argvars, typval_T *rettv);
+static void f_libcall(typval_T *argvars, typval_T *rettv);
+static void f_libcallnr(typval_T *argvars, typval_T *rettv);
+static void f_line(typval_T *argvars, typval_T *rettv);
+static void f_line2byte(typval_T *argvars, typval_T *rettv);
+static void f_lispindent(typval_T *argvars, typval_T *rettv);
+static void f_localtime(typval_T *argvars, typval_T *rettv);
+#ifdef FEAT_FLOAT
+static void f_log(typval_T *argvars, typval_T *rettv);
+static void f_log10(typval_T *argvars, typval_T *rettv);
+#endif
+#ifdef FEAT_LUA
+static void f_luaeval(typval_T *argvars, typval_T *rettv);
+#endif
+static void f_map(typval_T *argvars, typval_T *rettv);
+static void f_maparg(typval_T *argvars, typval_T *rettv);
+static void f_mapcheck(typval_T *argvars, typval_T *rettv);
+static void f_match(typval_T *argvars, typval_T *rettv);
+static void f_matchadd(typval_T *argvars, typval_T *rettv);
+static void f_matchaddpos(typval_T *argvars, typval_T *rettv);
+static void f_matcharg(typval_T *argvars, typval_T *rettv);
+static void f_matchdelete(typval_T *argvars, typval_T *rettv);
+static void f_matchend(typval_T *argvars, typval_T *rettv);
+static void f_matchlist(typval_T *argvars, typval_T *rettv);
+static void f_matchstr(typval_T *argvars, typval_T *rettv);
+static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
+static void f_max(typval_T *argvars, typval_T *rettv);
+static void f_min(typval_T *argvars, typval_T *rettv);
+#ifdef vim_mkdir
+static void f_mkdir(typval_T *argvars, typval_T *rettv);
+#endif
+static void f_mode(typval_T *argvars, typval_T *rettv);
+#ifdef FEAT_MZSCHEME
+static void f_mzeval(typval_T *argvars, typval_T *rettv);
+#endif
+static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
+static void f_nr2char(typval_T *argvars, typval_T *rettv);
+static void f_or(typval_T *argvars, typval_T *rettv);
+static void f_pathshorten(typval_T *argvars, typval_T *rettv);
+#ifdef FEAT_PERL
+static void f_perleval(typval_T *argvars, typval_T *rettv);
+#endif
+#ifdef FEAT_FLOAT
+static void f_pow(typval_T *argvars, typval_T *rettv);
+#endif
+static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
+static void f_printf(typval_T *argvars, typval_T *rettv);
+#ifdef FEAT_JOB_CHANNEL
+static void f_prompt_setcallback(typval_T *argvars, typval_T *rettv);
+static void f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv);
+static void f_prompt_setprompt(typval_T *argvars, typval_T *rettv);
+#endif
+static void f_pumvisible(typval_T *argvars, typval_T *rettv);
+#ifdef FEAT_PYTHON3
+static void f_py3eval(typval_T *argvars, typval_T *rettv);
+#endif
+#ifdef FEAT_PYTHON
+static void f_pyeval(typval_T *argvars, typval_T *rettv);
+#endif
+#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
+static void f_pyxeval(typval_T *argvars, typval_T *rettv);
+#endif
+static void f_range(typval_T *argvars, typval_T *rettv);
+static void f_readfile(typval_T *argvars, typval_T *rettv);
+static void f_reg_executing(typval_T *argvars, typval_T *rettv);
+static void f_reg_recording(typval_T *argvars, typval_T *rettv);
+static void f_reltime(typval_T *argvars, typval_T *rettv);
+#ifdef FEAT_FLOAT
+static void f_reltimefloat(typval_T *argvars, typval_T *rettv);
+#endif
+static void f_reltimestr(typval_T *argvars, typval_T *rettv);
+static void f_remote_expr(typval_T *argvars, typval_T *rettv);
+static void f_remote_foreground(typval_T *argvars, typval_T *rettv);
+static void f_remote_peek(typval_T *argvars, typval_T *rettv);
+static void f_remote_read(typval_T *argvars, typval_T *rettv);
+static void f_remote_send(typval_T *argvars, typval_T *rettv);
+static void f_remote_startserver(typval_T *argvars, typval_T *rettv);
+static void f_remove(typval_T *argvars, typval_T *rettv);
+static void f_rename(typval_T *argvars, typval_T *rettv);
+static void f_repeat(typval_T *argvars, typval_T *rettv);
+static void f_resolve(typval_T *argvars, typval_T *rettv);
+static void f_reverse(typval_T *argvars, typval_T *rettv);
+#ifdef FEAT_FLOAT
+static void f_round(typval_T *argvars, typval_T *rettv);
+#endif
+static void f_screenattr(typval_T *argvars, typval_T *rettv);
+static void f_screenchar(typval_T *argvars, typval_T *rettv);
+static void f_screencol(typval_T *argvars, typval_T *rettv);
+static void f_screenrow(typval_T *argvars, typval_T *rettv);
+static void f_search(typval_T *argvars, typval_T *rettv);
+static void f_searchdecl(typval_T *argvars, typval_T *rettv);
+static void f_searchpair(typval_T *argvars, typval_T *rettv);
+static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
+static void f_searchpos(typval_T *argvars, typval_T *rettv);
+static void f_server2client(typval_T *argvars, typval_T *rettv);
+static void f_serverlist(typval_T *argvars, typval_T *rettv);
+static void f_setbufline(typval_T *argvars, typval_T *rettv);
+static void f_setbufvar(typval_T *argvars, typval_T *rettv);
+static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
+static void f_setcmdpos(typval_T *argvars, typval_T *rettv);
+static void f_setfperm(typval_T *argvars, typval_T *rettv);
+static void f_setline(typval_T *argvars, typval_T *rettv);
+static void f_setloclist(typval_T *argvars, typval_T *rettv);
+static void f_setmatches(typval_T *argvars, typval_T *rettv);
+static void f_setpos(typval_T *argvars, typval_T *rettv);
+static void f_setqflist(typval_T *argvars, typval_T *rettv);
+static void f_setreg(typval_T *argvars, typval_T *rettv);
+static void f_settabvar(typval_T *argvars, typval_T *rettv);
+static void f_settabwinvar(typval_T *argvars, typval_T *rettv);
+static void f_settagstack(typval_T *argvars, typval_T *rettv);
+static void f_setwinvar(typval_T *argvars, typval_T *rettv);
+#ifdef FEAT_CRYPT
+static void f_sha256(typval_T *argvars, typval_T *rettv);
+#endif /* FEAT_CRYPT */
+static void f_shellescape(typval_T *argvars, typval_T *rettv);
+static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
+#ifdef FEAT_SIGNS
+static void f_sign_define(typval_T *argvars, typval_T *rettv);
+static void f_sign_getdefined(typval_T *argvars, typval_T *rettv);
+static void f_sign_getplaced(typval_T *argvars, typval_T *rettv);
+static void f_sign_jump(typval_T *argvars, typval_T *rettv);
+static void f_sign_place(typval_T *argvars, typval_T *rettv);
+static void f_sign_undefine(typval_T *argvars, typval_T *rettv);
+static void f_sign_unplace(typval_T *argvars, typval_T *rettv);
+#endif
+static void f_simplify(typval_T *argvars, typval_T *rettv);
+#ifdef FEAT_FLOAT
+static void f_sin(typval_T *argvars, typval_T *rettv);
+static void f_sinh(typval_T *argvars, typval_T *rettv);
+#endif
+static void f_sort(typval_T *argvars, typval_T *rettv);
+static void f_soundfold(typval_T *argvars, typval_T *rettv);
+static void f_spellbadword(typval_T *argvars, typval_T *rettv);
+static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
+static void f_split(typval_T *argvars, typval_T *rettv);
+#ifdef FEAT_FLOAT
+static void f_sqrt(typval_T *argvars, typval_T *rettv);
+static void f_str2float(typval_T *argvars, typval_T *rettv);
+#endif
+static void f_str2nr(typval_T *argvars, typval_T *rettv);
+static void f_strchars(typval_T *argvars, typval_T *rettv);
+#ifdef HAVE_STRFTIME
+static void f_strftime(typval_T *argvars, typval_T *rettv);
+#endif
+static void f_strgetchar(typval_T *argvars, typval_T *rettv);
+static void f_stridx(typval_T *argvars, typval_T *rettv);
+static void f_strlen(typval_T *argvars, typval_T *rettv);
+static void f_strcharpart(typval_T *argvars, typval_T *rettv);
+static void f_strpart(typval_T *argvars, typval_T *rettv);
+static void f_strridx(typval_T *argvars, typval_T *rettv);
+static void f_strtrans(typval_T *argvars, typval_T *rettv);
+static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
+static void f_strwidth(typval_T *argvars, typval_T *rettv);
+static void f_submatch(typval_T *argvars, typval_T *rettv);
+static void f_substitute(typval_T *argvars, typval_T *rettv);
+static void f_swapinfo(typval_T *argvars, typval_T *rettv);
+static void f_swapname(typval_T *argvars, typval_T *rettv);
+static void f_synID(typval_T *argvars, typval_T *rettv);
+static void f_synIDattr(typval_T *argvars, typval_T *rettv);
+static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
+static void f_synstack(typval_T *argvars, typval_T *rettv);
+static void f_synconcealed(typval_T *argvars, typval_T *rettv);
+static void f_system(typval_T *argvars, typval_T *rettv);
+static void f_systemlist(typval_T *argvars, typval_T *rettv);
+static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
+static void f_tabpagenr(typval_T *argvars, typval_T *rettv);
+static void f_tabpagewinnr(typval_T *argvars, typval_T *rettv);
+static void f_taglist(typval_T *argvars, typval_T *rettv);
+static void f_tagfiles(typval_T *argvars, typval_T *rettv);
+static void f_tempname(typval_T *argvars, typval_T *rettv);
+static void f_test_alloc_fail(typval_T *argvars, typval_T *rettv);
+static void f_test_autochdir(typval_T *argvars, typval_T *rettv);
+static void f_test_feedinput(typval_T *argvars, typval_T *rettv);
+static void f_test_option_not_set(typval_T *argvars, typval_T *rettv);
+static void f_test_override(typval_T *argvars, typval_T *rettv);
+static void f_test_garbagecollect_now(typval_T *argvars, typval_T *rettv);
+static void f_test_ignore_error(typval_T *argvars, typval_T *rettv);
+static void f_test_null_blob(typval_T *argvars, typval_T *rettv);
+#ifdef FEAT_JOB_CHANNEL
+static void f_test_null_channel(typval_T *argvars, typval_T *rettv);
+#endif
+static void f_test_null_dict(typval_T *argvars, typval_T *rettv);
+#ifdef FEAT_JOB_CHANNEL
+static void f_test_null_job(typval_T *argvars, typval_T *rettv);
+#endif
+static void f_test_null_list(typval_T *argvars, typval_T *rettv);
+static void f_test_null_partial(typval_T *argvars, typval_T *rettv);
+static void f_test_null_string(typval_T *argvars, typval_T *rettv);
+#ifdef FEAT_GUI
+static void f_test_scrollbar(typval_T *argvars, typval_T *rettv);
+#endif
+static void f_test_settime(typval_T *argvars, typval_T *rettv);
+#ifdef FEAT_FLOAT
+static void f_tan(typval_T *argvars, typval_T *rettv);
+static void f_tanh(typval_T *argvars, typval_T *rettv);
+#endif
+#ifdef FEAT_TIMERS
+static void f_timer_info(typval_T *argvars, typval_T *rettv);
+static void f_timer_pause(typval_T *argvars, typval_T *rettv);
+static void f_timer_start(typval_T *argvars, typval_T *rettv);
+static void f_timer_stop(typval_T *argvars, typval_T *rettv);
+static void f_timer_stopall(typval_T *argvars, typval_T *rettv);
+#endif
+static void f_tolower(typval_T *argvars, typval_T *rettv);
+static void f_toupper(typval_T *argvars, typval_T *rettv);
+static void f_tr(typval_T *argvars, typval_T *rettv);
+static void f_trim(typval_T *argvars, typval_T *rettv);
+#ifdef FEAT_FLOAT
+static void f_trunc(typval_T *argvars, typval_T *rettv);
+#endif
+static void f_type(typval_T *argvars, typval_T *rettv);
+static void f_undofile(typval_T *argvars, typval_T *rettv);
+static void f_undotree(typval_T *argvars, typval_T *rettv);
+static void f_uniq(typval_T *argvars, typval_T *rettv);
+static void f_values(typval_T *argvars, typval_T *rettv);
+static void f_virtcol(typval_T *argvars, typval_T *rettv);
+static void f_visualmode(typval_T *argvars, typval_T *rettv);
+static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
+static void f_win_findbuf(typval_T *argvars, typval_T *rettv);
+static void f_win_getid(typval_T *argvars, typval_T *rettv);
+static void f_win_gotoid(typval_T *argvars, typval_T *rettv);
+static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv);
+static void f_win_id2win(typval_T *argvars, typval_T *rettv);
+static void f_win_screenpos(typval_T *argvars, typval_T *rettv);
+static void f_winbufnr(typval_T *argvars, typval_T *rettv);
+static void f_wincol(typval_T *argvars, typval_T *rettv);
+static void f_winheight(typval_T *argvars, typval_T *rettv);
+static void f_winlayout(typval_T *argvars, typval_T *rettv);
+static void f_winline(typval_T *argvars, typval_T *rettv);
+static void f_winnr(typval_T *argvars, typval_T *rettv);
+static void f_winrestcmd(typval_T *argvars, typval_T *rettv);
+static void f_winrestview(typval_T *argvars, typval_T *rettv);
+static void f_winsaveview(typval_T *argvars, typval_T *rettv);
+static void f_winwidth(typval_T *argvars, typval_T *rettv);
+static void f_writefile(typval_T *argvars, typval_T *rettv);
+static void f_wordcount(typval_T *argvars, typval_T *rettv);
+static void f_xor(typval_T *argvars, typval_T *rettv);
+
+/*
+ * Array with names and number of arguments of all internal functions
+ * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
+ */
+static struct fst
+{
+ char *f_name; /* function name */
+ char f_min_argc; /* minimal number of arguments */
+ char f_max_argc; /* maximal number of arguments */
+ void (*f_func)(typval_T *args, typval_T *rvar);
+ /* implementation of function */
+} functions[] =
+{
+#ifdef FEAT_FLOAT
+ {"abs", 1, 1, f_abs},
+ {"acos", 1, 1, f_acos}, /* WJMc */
+#endif
+ {"add", 2, 2, f_add},
+ {"and", 2, 2, f_and},
+ {"append", 2, 2, f_append},
+ {"appendbufline", 3, 3, f_appendbufline},
+ {"argc", 0, 1, f_argc},
+ {"argidx", 0, 0, f_argidx},
+ {"arglistid", 0, 2, f_arglistid},
+ {"argv", 0, 2, f_argv},
+#ifdef FEAT_FLOAT
+ {"asin", 1, 1, f_asin}, /* WJMc */
+#endif
+ {"assert_beeps", 1, 2, f_assert_beeps},
+ {"assert_equal", 2, 3, f_assert_equal},
+ {"assert_equalfile", 2, 2, f_assert_equalfile},
+ {"assert_exception", 1, 2, f_assert_exception},
+ {"assert_fails", 1, 3, f_assert_fails},
+ {"assert_false", 1, 2, f_assert_false},
+ {"assert_inrange", 3, 4, f_assert_inrange},
+ {"assert_match", 2, 3, f_assert_match},
+ {"assert_notequal", 2, 3, f_assert_notequal},
+ {"assert_notmatch", 2, 3, f_assert_notmatch},
+ {"assert_report", 1, 1, f_assert_report},
+ {"assert_true", 1, 2, f_assert_true},
+#ifdef FEAT_FLOAT
+ {"atan", 1, 1, f_atan},
+ {"atan2", 2, 2, f_atan2},
+#endif
+#ifdef FEAT_BEVAL
+ {"balloon_show", 1, 1, f_balloon_show},
+# if defined(FEAT_BEVAL_TERM)
+ {"balloon_split", 1, 1, f_balloon_split},
+# endif
+#endif
+ {"browse", 4, 4, f_browse},
+ {"browsedir", 2, 2, f_browsedir},
+ {"bufexists", 1, 1, f_bufexists},
+ {"buffer_exists", 1, 1, f_bufexists}, /* obsolete */
+ {"buffer_name", 1, 1, f_bufname}, /* obsolete */
+ {"buffer_number", 1, 1, f_bufnr}, /* obsolete */
+ {"buflisted", 1, 1, f_buflisted},
+ {"bufloaded", 1, 1, f_bufloaded},
+ {"bufname", 1, 1, f_bufname},
+ {"bufnr", 1, 2, f_bufnr},
+ {"bufwinid", 1, 1, f_bufwinid},
+ {"bufwinnr", 1, 1, f_bufwinnr},
+ {"byte2line", 1, 1, f_byte2line},
+ {"byteidx", 2, 2, f_byteidx},
+ {"byteidxcomp", 2, 2, f_byteidxcomp},
+ {"call", 2, 3, f_call},
+#ifdef FEAT_FLOAT
+ {"ceil", 1, 1, f_ceil},
+#endif
+#ifdef FEAT_JOB_CHANNEL
+ {"ch_canread", 1, 1, f_ch_canread},
+ {"ch_close", 1, 1, f_ch_close},
+ {"ch_close_in", 1, 1, f_ch_close_in},
+ {"ch_evalexpr", 2, 3, f_ch_evalexpr},
+ {"ch_evalraw", 2, 3, f_ch_evalraw},
+ {"ch_getbufnr", 2, 2, f_ch_getbufnr},
+ {"ch_getjob", 1, 1, f_ch_getjob},
+ {"ch_info", 1, 1, f_ch_info},
+ {"ch_log", 1, 2, f_ch_log},
+ {"ch_logfile", 1, 2, f_ch_logfile},
+ {"ch_open", 1, 2, f_ch_open},
+ {"ch_read", 1, 2, f_ch_read},
+ {"ch_readblob", 1, 2, f_ch_readblob},
+ {"ch_readraw", 1, 2, f_ch_readraw},
+ {"ch_sendexpr", 2, 3, f_ch_sendexpr},
+ {"ch_sendraw", 2, 3, f_ch_sendraw},
+ {"ch_setoptions", 2, 2, f_ch_setoptions},
+ {"ch_status", 1, 2, f_ch_status},
+#endif
+ {"changenr", 0, 0, f_changenr},
+ {"char2nr", 1, 2, f_char2nr},
+ {"cindent", 1, 1, f_cindent},
+ {"clearmatches", 0, 0, f_clearmatches},
+ {"col", 1, 1, f_col},
+#if defined(FEAT_INS_EXPAND)
+ {"complete", 2, 2, f_complete},
+ {"complete_add", 1, 1, f_complete_add},
+ {"complete_check", 0, 0, f_complete_check},
+#endif
+ {"confirm", 1, 4, f_confirm},
+ {"copy", 1, 1, f_copy},
+#ifdef FEAT_FLOAT
+ {"cos", 1, 1, f_cos},
+ {"cosh", 1, 1, f_cosh},
+#endif
+ {"count", 2, 4, f_count},
+ {"cscope_connection",0,3, f_cscope_connection},
+ {"cursor", 1, 3, f_cursor},
+#ifdef WIN3264
+ {"debugbreak", 1, 1, f_debugbreak},
+#endif
+ {"deepcopy", 1, 2, f_deepcopy},
+ {"delete", 1, 2, f_delete},
+ {"deletebufline", 2, 3, f_deletebufline},
+ {"did_filetype", 0, 0, f_did_filetype},
+ {"diff_filler", 1, 1, f_diff_filler},
+ {"diff_hlID", 2, 2, f_diff_hlID},
+ {"empty", 1, 1, f_empty},
+ {"escape", 2, 2, f_escape},
+ {"eval", 1, 1, f_eval},
+ {"eventhandler", 0, 0, f_eventhandler},
+ {"executable", 1, 1, f_executable},
+ {"execute", 1, 2, f_execute},
+ {"exepath", 1, 1, f_exepath},
+ {"exists", 1, 1, f_exists},
+#ifdef FEAT_FLOAT
+ {"exp", 1, 1, f_exp},
+#endif
+ {"expand", 1, 3, f_expand},
+ {"extend", 2, 3, f_extend},
+ {"feedkeys", 1, 2, f_feedkeys},
+ {"file_readable", 1, 1, f_filereadable}, /* obsolete */
+ {"filereadable", 1, 1, f_filereadable},
+ {"filewritable", 1, 1, f_filewritable},
+ {"filter", 2, 2, f_filter},
+ {"finddir", 1, 3, f_finddir},
+ {"findfile", 1, 3, f_findfile},
+#ifdef FEAT_FLOAT
+ {"float2nr", 1, 1, f_float2nr},
+ {"floor", 1, 1, f_floor},
+ {"fmod", 2, 2, f_fmod},
+#endif
+ {"fnameescape", 1, 1, f_fnameescape},
+ {"fnamemodify", 2, 2, f_fnamemodify},
+ {"foldclosed", 1, 1, f_foldclosed},
+ {"foldclosedend", 1, 1, f_foldclosedend},
+ {"foldlevel", 1, 1, f_foldlevel},
+ {"foldtext", 0, 0, f_foldtext},
+ {"foldtextresult", 1, 1, f_foldtextresult},
+ {"foreground", 0, 0, f_foreground},
+ {"funcref", 1, 3, f_funcref},
+ {"function", 1, 3, f_function},
+ {"garbagecollect", 0, 1, f_garbagecollect},
+ {"get", 2, 3, f_get},
+ {"getbufinfo", 0, 1, f_getbufinfo},
+ {"getbufline", 2, 3, f_getbufline},
+ {"getbufvar", 2, 3, f_getbufvar},
+ {"getchangelist", 1, 1, f_getchangelist},
+ {"getchar", 0, 1, f_getchar},
+ {"getcharmod", 0, 0, f_getcharmod},
+ {"getcharsearch", 0, 0, f_getcharsearch},
+ {"getcmdline", 0, 0, f_getcmdline},
+ {"getcmdpos", 0, 0, f_getcmdpos},
+ {"getcmdtype", 0, 0, f_getcmdtype},
+ {"getcmdwintype", 0, 0, f_getcmdwintype},
+#if defined(FEAT_CMDL_COMPL)
+ {"getcompletion", 2, 3, f_getcompletion},
+#endif
+ {"getcurpos", 0, 0, f_getcurpos},
+ {"getcwd", 0, 2, f_getcwd},
+ {"getfontname", 0, 1, f_getfontname},
+ {"getfperm", 1, 1, f_getfperm},
+ {"getfsize", 1, 1, f_getfsize},
+ {"getftime", 1, 1, f_getftime},
+ {"getftype", 1, 1, f_getftype},
+ {"getjumplist", 0, 2, f_getjumplist},
+ {"getline", 1, 2, f_getline},
+ {"getloclist", 1, 2, f_getloclist},
+ {"getmatches", 0, 0, f_getmatches},
+ {"getpid", 0, 0, f_getpid},
+ {"getpos", 1, 1, f_getpos},
+ {"getqflist", 0, 1, f_getqflist},
+ {"getreg", 0, 3, f_getreg},
+ {"getregtype", 0, 1, f_getregtype},
+ {"gettabinfo", 0, 1, f_gettabinfo},
+ {"gettabvar", 2, 3, f_gettabvar},
+ {"gettabwinvar", 3, 4, f_gettabwinvar},
+ {"gettagstack", 0, 1, f_gettagstack},
+ {"getwininfo", 0, 1, f_getwininfo},
+ {"getwinpos", 0, 1, f_getwinpos},
+ {"getwinposx", 0, 0, f_getwinposx},
+ {"getwinposy", 0, 0, f_getwinposy},
+ {"getwinvar", 2, 3, f_getwinvar},
+ {"glob", 1, 4, f_glob},
+ {"glob2regpat", 1, 1, f_glob2regpat},
+ {"globpath", 2, 5, f_globpath},
+ {"has", 1, 1, f_has},
+ {"has_key", 2, 2, f_has_key},
+ {"haslocaldir", 0, 2, f_haslocaldir},
+ {"hasmapto", 1, 3, f_hasmapto},
+ {"highlightID", 1, 1, f_hlID}, /* obsolete */
+ {"highlight_exists",1, 1, f_hlexists}, /* obsolete */
+ {"histadd", 2, 2, f_histadd},
+ {"histdel", 1, 2, f_histdel},
+ {"histget", 1, 2, f_histget},
+ {"histnr", 1, 1, f_histnr},
+ {"hlID", 1, 1, f_hlID},
+ {"hlexists", 1, 1, f_hlexists},
+ {"hostname", 0, 0, f_hostname},
+ {"iconv", 3, 3, f_iconv},
+ {"indent", 1, 1, f_indent},
+ {"index", 2, 4, f_index},
+ {"input", 1, 3, f_input},
+ {"inputdialog", 1, 3, f_inputdialog},
+ {"inputlist", 1, 1, f_inputlist},
+ {"inputrestore", 0, 0, f_inputrestore},
+ {"inputsave", 0, 0, f_inputsave},
+ {"inputsecret", 1, 2, f_inputsecret},
+ {"insert", 2, 3, f_insert},
+ {"invert", 1, 1, f_invert},
+ {"isdirectory", 1, 1, f_isdirectory},
+ {"islocked", 1, 1, f_islocked},
+#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
+ {"isnan", 1, 1, f_isnan},
+#endif
+ {"items", 1, 1, f_items},
+#ifdef FEAT_JOB_CHANNEL
+ {"job_getchannel", 1, 1, f_job_getchannel},
+ {"job_info", 0, 1, f_job_info},
+ {"job_setoptions", 2, 2, f_job_setoptions},
+ {"job_start", 1, 2, f_job_start},
+ {"job_status", 1, 1, f_job_status},
+ {"job_stop", 1, 2, f_job_stop},
+#endif
+ {"join", 1, 2, f_join},
+ {"js_decode", 1, 1, f_js_decode},
+ {"js_encode", 1, 1, f_js_encode},
+ {"json_decode", 1, 1, f_json_decode},
+ {"json_encode", 1, 1, f_json_encode},
+ {"keys", 1, 1, f_keys},
+ {"last_buffer_nr", 0, 0, f_last_buffer_nr},/* obsolete */
+ {"len", 1, 1, f_len},
+ {"libcall", 3, 3, f_libcall},
+ {"libcallnr", 3, 3, f_libcallnr},
+ {"line", 1, 1, f_line},
+ {"line2byte", 1, 1, f_line2byte},
+ {"lispindent", 1, 1, f_lispindent},
+ {"localtime", 0, 0, f_localtime},
+#ifdef FEAT_FLOAT
+ {"log", 1, 1, f_log},
+ {"log10", 1, 1, f_log10},
+#endif
+#ifdef FEAT_LUA
+ {"luaeval", 1, 2, f_luaeval},
+#endif
+ {"map", 2, 2, f_map},
+ {"maparg", 1, 4, f_maparg},
+ {"mapcheck", 1, 3, f_mapcheck},
+ {"match", 2, 4, f_match},
+ {"matchadd", 2, 5, f_matchadd},
+ {"matchaddpos", 2, 5, f_matchaddpos},
+ {"matcharg", 1, 1, f_matcharg},
+ {"matchdelete", 1, 1, f_matchdelete},
+ {"matchend", 2, 4, f_matchend},
+ {"matchlist", 2, 4, f_matchlist},
+ {"matchstr", 2, 4, f_matchstr},
+ {"matchstrpos", 2, 4, f_matchstrpos},
+ {"max", 1, 1, f_max},
+ {"min", 1, 1, f_min},
+#ifdef vim_mkdir
+ {"mkdir", 1, 3, f_mkdir},
+#endif
+ {"mode", 0, 1, f_mode},
+#ifdef FEAT_MZSCHEME
+ {"mzeval", 1, 1, f_mzeval},
+#endif
+ {"nextnonblank", 1, 1, f_nextnonblank},
+ {"nr2char", 1, 2, f_nr2char},
+ {"or", 2, 2, f_or},
+ {"pathshorten", 1, 1, f_pathshorten},
+#ifdef FEAT_PERL
+ {"perleval", 1, 1, f_perleval},
+#endif
+#ifdef FEAT_FLOAT
+ {"pow", 2, 2, f_pow},
+#endif
+ {"prevnonblank", 1, 1, f_prevnonblank},
+ {"printf", 1, 19, f_printf},
+#ifdef FEAT_JOB_CHANNEL
+ {"prompt_setcallback", 2, 2, f_prompt_setcallback},
+ {"prompt_setinterrupt", 2, 2, f_prompt_setinterrupt},
+ {"prompt_setprompt", 2, 2, f_prompt_setprompt},
+#endif
+#ifdef FEAT_TEXT_PROP
+ {"prop_add", 3, 3, f_prop_add},
+ {"prop_clear", 1, 3, f_prop_clear},
+ {"prop_list", 1, 2, f_prop_list},
+ {"prop_remove", 2, 3, f_prop_remove},
+ {"prop_type_add", 2, 2, f_prop_type_add},
+ {"prop_type_change", 2, 2, f_prop_type_change},
+ {"prop_type_delete", 1, 2, f_prop_type_delete},
+ {"prop_type_get", 1, 2, f_prop_type_get},
+ {"prop_type_list", 0, 1, f_prop_type_list},
+#endif
+ {"pumvisible", 0, 0, f_pumvisible},
+#ifdef FEAT_PYTHON3
+ {"py3eval", 1, 1, f_py3eval},
+#endif
+#ifdef FEAT_PYTHON
+ {"pyeval", 1, 1, f_pyeval},
+#endif
+#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
+ {"pyxeval", 1, 1, f_pyxeval},
+#endif
+ {"range", 1, 3, f_range},
+ {"readfile", 1, 3, f_readfile},
+ {"reg_executing", 0, 0, f_reg_executing},
+ {"reg_recording", 0, 0, f_reg_recording},
+ {"reltime", 0, 2, f_reltime},
+#ifdef FEAT_FLOAT
+ {"reltimefloat", 1, 1, f_reltimefloat},
+#endif
+ {"reltimestr", 1, 1, f_reltimestr},
+ {"remote_expr", 2, 4, f_remote_expr},
+ {"remote_foreground", 1, 1, f_remote_foreground},
+ {"remote_peek", 1, 2, f_remote_peek},
+ {"remote_read", 1, 2, f_remote_read},
+ {"remote_send", 2, 3, f_remote_send},
+ {"remote_startserver", 1, 1, f_remote_startserver},
+ {"remove", 2, 3, f_remove},
+ {"rename", 2, 2, f_rename},
+ {"repeat", 2, 2, f_repeat},
+ {"resolve", 1, 1, f_resolve},
+ {"reverse", 1, 1, f_reverse},
+#ifdef FEAT_FLOAT
+ {"round", 1, 1, f_round},
+#endif
+ {"screenattr", 2, 2, f_screenattr},
+ {"screenchar", 2, 2, f_screenchar},
+ {"screencol", 0, 0, f_screencol},
+ {"screenrow", 0, 0, f_screenrow},
+ {"search", 1, 4, f_search},
+ {"searchdecl", 1, 3, f_searchdecl},
+ {"searchpair", 3, 7, f_searchpair},
+ {"searchpairpos", 3, 7, f_searchpairpos},
+ {"searchpos", 1, 4, f_searchpos},
+ {"server2client", 2, 2, f_server2client},
+ {"serverlist", 0, 0, f_serverlist},
+ {"setbufline", 3, 3, f_setbufline},
+ {"setbufvar", 3, 3, f_setbufvar},
+ {"setcharsearch", 1, 1, f_setcharsearch},
+ {"setcmdpos", 1, 1, f_setcmdpos},
+ {"setfperm", 2, 2, f_setfperm},
+ {"setline", 2, 2, f_setline},
+ {"setloclist", 2, 4, f_setloclist},
+ {"setmatches", 1, 1, f_setmatches},
+ {"setpos", 2, 2, f_setpos},
+ {"setqflist", 1, 3, f_setqflist},
+ {"setreg", 2, 3, f_setreg},
+ {"settabvar", 3, 3, f_settabvar},
+ {"settabwinvar", 4, 4, f_settabwinvar},
+ {"settagstack", 2, 3, f_settagstack},
+ {"setwinvar", 3, 3, f_setwinvar},
+#ifdef FEAT_CRYPT
+ {"sha256", 1, 1, f_sha256},
+#endif
+ {"shellescape", 1, 2, f_shellescape},
+ {"shiftwidth", 0, 1, f_shiftwidth},
+#ifdef FEAT_SIGNS
+ {"sign_define", 1, 2, f_sign_define},
+ {"sign_getdefined", 0, 1, f_sign_getdefined},
+ {"sign_getplaced", 0, 2, f_sign_getplaced},
+ {"sign_jump", 3, 3, f_sign_jump},
+ {"sign_place", 4, 5, f_sign_place},
+ {"sign_undefine", 0, 1, f_sign_undefine},
+ {"sign_unplace", 1, 2, f_sign_unplace},
+#endif
+ {"simplify", 1, 1, f_simplify},
+#ifdef FEAT_FLOAT
+ {"sin", 1, 1, f_sin},
+ {"sinh", 1, 1, f_sinh},
+#endif
+ {"sort", 1, 3, f_sort},
+ {"soundfold", 1, 1, f_soundfold},
+ {"spellbadword", 0, 1, f_spellbadword},
+ {"spellsuggest", 1, 3, f_spellsuggest},
+ {"split", 1, 3, f_split},
+#ifdef FEAT_FLOAT
+ {"sqrt", 1, 1, f_sqrt},
+ {"str2float", 1, 1, f_str2float},
+#endif
+ {"str2nr", 1, 2, f_str2nr},
+ {"strcharpart", 2, 3, f_strcharpart},
+ {"strchars", 1, 2, f_strchars},
+ {"strdisplaywidth", 1, 2, f_strdisplaywidth},
+#ifdef HAVE_STRFTIME
+ {"strftime", 1, 2, f_strftime},
+#endif
+ {"strgetchar", 2, 2, f_strgetchar},
+ {"stridx", 2, 3, f_stridx},
+ {"string", 1, 1, f_string},
+ {"strlen", 1, 1, f_strlen},
+ {"strpart", 2, 3, f_strpart},
+ {"strridx", 2, 3, f_strridx},
+ {"strtrans", 1, 1, f_strtrans},
+ {"strwidth", 1, 1, f_strwidth},
+ {"submatch", 1, 2, f_submatch},
+ {"substitute", 4, 4, f_substitute},
+ {"swapinfo", 1, 1, f_swapinfo},
+ {"swapname", 1, 1, f_swapname},
+ {"synID", 3, 3, f_synID},
+ {"synIDattr", 2, 3, f_synIDattr},
+ {"synIDtrans", 1, 1, f_synIDtrans},
+ {"synconcealed", 2, 2, f_synconcealed},
+ {"synstack", 2, 2, f_synstack},
+ {"system", 1, 2, f_system},
+ {"systemlist", 1, 2, f_systemlist},
+ {"tabpagebuflist", 0, 1, f_tabpagebuflist},
+ {"tabpagenr", 0, 1, f_tabpagenr},
+ {"tabpagewinnr", 1, 2, f_tabpagewinnr},
+ {"tagfiles", 0, 0, f_tagfiles},
+ {"taglist", 1, 2, f_taglist},
+#ifdef FEAT_FLOAT
+ {"tan", 1, 1, f_tan},
+ {"tanh", 1, 1, f_tanh},
+#endif
+ {"tempname", 0, 0, f_tempname},
+#ifdef FEAT_TERMINAL
+ {"term_dumpdiff", 2, 3, f_term_dumpdiff},
+ {"term_dumpload", 1, 2, f_term_dumpload},
+ {"term_dumpwrite", 2, 3, f_term_dumpwrite},
+ {"term_getaltscreen", 1, 1, f_term_getaltscreen},
+# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
+ {"term_getansicolors", 1, 1, f_term_getansicolors},
+# endif
+ {"term_getattr", 2, 2, f_term_getattr},
+ {"term_getcursor", 1, 1, f_term_getcursor},
+ {"term_getjob", 1, 1, f_term_getjob},
+ {"term_getline", 2, 2, f_term_getline},
+ {"term_getscrolled", 1, 1, f_term_getscrolled},
+ {"term_getsize", 1, 1, f_term_getsize},
+ {"term_getstatus", 1, 1, f_term_getstatus},
+ {"term_gettitle", 1, 1, f_term_gettitle},
+ {"term_gettty", 1, 2, f_term_gettty},
+ {"term_list", 0, 0, f_term_list},
+ {"term_scrape", 2, 2, f_term_scrape},
+ {"term_sendkeys", 2, 2, f_term_sendkeys},
+# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
+ {"term_setansicolors", 2, 2, f_term_setansicolors},
+# endif
+ {"term_setkill", 2, 2, f_term_setkill},
+ {"term_setrestore", 2, 2, f_term_setrestore},
+ {"term_setsize", 3, 3, f_term_setsize},
+ {"term_start", 1, 2, f_term_start},
+ {"term_wait", 1, 2, f_term_wait},
+#endif
+ {"test_alloc_fail", 3, 3, f_test_alloc_fail},
+ {"test_autochdir", 0, 0, f_test_autochdir},
+ {"test_feedinput", 1, 1, f_test_feedinput},
+ {"test_garbagecollect_now", 0, 0, f_test_garbagecollect_now},
+ {"test_ignore_error", 1, 1, f_test_ignore_error},
+ {"test_null_blob", 0, 0, f_test_null_blob},
+#ifdef FEAT_JOB_CHANNEL
+ {"test_null_channel", 0, 0, f_test_null_channel},
+#endif
+ {"test_null_dict", 0, 0, f_test_null_dict},
+#ifdef FEAT_JOB_CHANNEL
+ {"test_null_job", 0, 0, f_test_null_job},
+#endif
+ {"test_null_list", 0, 0, f_test_null_list},
+ {"test_null_partial", 0, 0, f_test_null_partial},
+ {"test_null_string", 0, 0, f_test_null_string},
+ {"test_option_not_set", 1, 1, f_test_option_not_set},
+ {"test_override", 2, 2, f_test_override},
+#ifdef FEAT_GUI
+ {"test_scrollbar", 3, 3, f_test_scrollbar},
+#endif
+ {"test_settime", 1, 1, f_test_settime},
+#ifdef FEAT_TIMERS
+ {"timer_info", 0, 1, f_timer_info},
+ {"timer_pause", 2, 2, f_timer_pause},
+ {"timer_start", 2, 3, f_timer_start},
+ {"timer_stop", 1, 1, f_timer_stop},
+ {"timer_stopall", 0, 0, f_timer_stopall},
+#endif
+ {"tolower", 1, 1, f_tolower},
+ {"toupper", 1, 1, f_toupper},
+ {"tr", 3, 3, f_tr},
+ {"trim", 1, 2, f_trim},
+#ifdef FEAT_FLOAT
+ {"trunc", 1, 1, f_trunc},
+#endif
+ {"type", 1, 1, f_type},
+ {"undofile", 1, 1, f_undofile},
+ {"undotree", 0, 0, f_undotree},
+ {"uniq", 1, 3, f_uniq},
+ {"values", 1, 1, f_values},
+ {"virtcol", 1, 1, f_virtcol},
+ {"visualmode", 0, 1, f_visualmode},
+ {"wildmenumode", 0, 0, f_wildmenumode},
+ {"win_findbuf", 1, 1, f_win_findbuf},
+ {"win_getid", 0, 2, f_win_getid},
+ {"win_gotoid", 1, 1, f_win_gotoid},
+ {"win_id2tabwin", 1, 1, f_win_id2tabwin},
+ {"win_id2win", 1, 1, f_win_id2win},
+ {"win_screenpos", 1, 1, f_win_screenpos},
+ {"winbufnr", 1, 1, f_winbufnr},
+ {"wincol", 0, 0, f_wincol},
+ {"winheight", 1, 1, f_winheight},
+ {"winlayout", 0, 1, f_winlayout},
+ {"winline", 0, 0, f_winline},
+ {"winnr", 0, 1, f_winnr},
+ {"winrestcmd", 0, 0, f_winrestcmd},
+ {"winrestview", 1, 1, f_winrestview},
+ {"winsaveview", 0, 0, f_winsaveview},
+ {"winwidth", 1, 1, f_winwidth},
+ {"wordcount", 0, 0, f_wordcount},
+ {"writefile", 2, 3, f_writefile},
+ {"xor", 2, 2, f_xor},
+};
+
+#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
+
+/*
+ * Function given to ExpandGeneric() to obtain the list of internal
+ * or user defined function names.
+ */
+ char_u *
+get_function_name(expand_T *xp, int idx)
+{
+ static int intidx = -1;
+ char_u *name;
+
+ if (idx == 0)
+ intidx = -1;
+ if (intidx < 0)
+ {
+ name = get_user_func_name(xp, idx);
+ if (name != NULL)
+ return name;
+ }
+ if (++intidx < (int)(sizeof(functions) / sizeof(struct fst)))
+ {
+ STRCPY(IObuff, functions[intidx].f_name);
+ STRCAT(IObuff, "(");
+ if (functions[intidx].f_max_argc == 0)
+ STRCAT(IObuff, ")");
+ return IObuff;
+ }
+
+ return NULL;
+}
+
+/*
+ * Function given to ExpandGeneric() to obtain the list of internal or
+ * user defined variable or function names.
+ */
+ char_u *
+get_expr_name(expand_T *xp, int idx)
+{
+ static int intidx = -1;
+ char_u *name;
+
+ if (idx == 0)
+ intidx = -1;
+ if (intidx < 0)
+ {
+ name = get_function_name(xp, idx);
+ if (name != NULL)
+ return name;
+ }
+ return get_user_var_name(xp, ++intidx);
+}
+
+#endif /* FEAT_CMDL_COMPL */
+
+/*
+ * Find internal function in table above.
+ * Return index, or -1 if not found
+ */
+ int
+find_internal_func(
+ char_u *name) /* name of the function */
+{
+ int first = 0;
+ int last = (int)(sizeof(functions) / sizeof(struct fst)) - 1;
+ int cmp;
+ int x;
+
+ /*
+ * Find the function name in the table. Binary search.
+ */
+ while (first <= last)
+ {
+ x = first + ((unsigned)(last - first) >> 1);
+ cmp = STRCMP(name, functions[x].f_name);
+ if (cmp < 0)
+ last = x - 1;
+ else if (cmp > 0)
+ first = x + 1;
+ else
+ return x;
+ }
+ return -1;
+}
+
+ int
+call_internal_func(
+ char_u *name,
+ int argcount,
+ typval_T *argvars,
+ typval_T *rettv)
+{
+ int i;
+
+ i = find_internal_func(name);
+ if (i < 0)
+ return ERROR_UNKNOWN;
+ if (argcount < functions[i].f_min_argc)
+ return ERROR_TOOFEW;
+ if (argcount > functions[i].f_max_argc)
+ return ERROR_TOOMANY;
+ argvars[argcount].v_type = VAR_UNKNOWN;
+ functions[i].f_func(argvars, rettv);
+ return ERROR_NONE;
+}
+
+/*
+ * Return TRUE for a non-zero Number and a non-empty String.
+ */
+ static int
+non_zero_arg(typval_T *argvars)
+{
+ return ((argvars[0].v_type == VAR_NUMBER
+ && argvars[0].vval.v_number != 0)
+ || (argvars[0].v_type == VAR_SPECIAL
+ && argvars[0].vval.v_number == VVAL_TRUE)
+ || (argvars[0].v_type == VAR_STRING
+ && argvars[0].vval.v_string != NULL
+ && *argvars[0].vval.v_string != NUL));
+}
+
+/*
+ * Get the lnum from the first argument.
+ * Also accepts ".", "$", etc., but that only works for the current buffer.
+ * Returns -1 on error.
+ */
+ static linenr_T
+tv_get_lnum(typval_T *argvars)
+{
+ typval_T rettv;
+ linenr_T lnum;
+
+ lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
+ if (lnum == 0) /* no valid number, try using line() */
+ {
+ rettv.v_type = VAR_NUMBER;
+ f_line(argvars, &rettv);
+ lnum = (linenr_T)rettv.vval.v_number;
+ clear_tv(&rettv);
+ }
+ return lnum;
+}
+
+/*
+ * Get the lnum from the first argument.
+ * Also accepts "$", then "buf" is used.
+ * Returns 0 on error.
+ */
+ static linenr_T
+tv_get_lnum_buf(typval_T *argvars, buf_T *buf)
+{
+ if (argvars[0].v_type == VAR_STRING
+ && argvars[0].vval.v_string != NULL
+ && argvars[0].vval.v_string[0] == '$'
+ && buf != NULL)
+ return buf->b_ml.ml_line_count;
+ return (linenr_T)tv_get_number_chk(&argvars[0], NULL);
+}
+
+#ifdef FEAT_FLOAT
+/*
+ * Get the float value of "argvars[0]" into "f".
+ * Returns FAIL when the argument is not a Number or Float.
+ */
+ static int
+get_float_arg(typval_T *argvars, float_T *f)
+{
+ if (argvars[0].v_type == VAR_FLOAT)
+ {
+ *f = argvars[0].vval.v_float;
+ return OK;
+ }
+ if (argvars[0].v_type == VAR_NUMBER)
+ {
+ *f = (float_T)argvars[0].vval.v_number;
+ return OK;
+ }
+ emsg(_("E808: Number or Float required"));
+ return FAIL;
+}
+
+/*
+ * "abs(expr)" function
+ */
+ static void
+f_abs(typval_T *argvars, typval_T *rettv)
+{
+ if (argvars[0].v_type == VAR_FLOAT)
+ {
+ rettv->v_type = VAR_FLOAT;
+ rettv->vval.v_float = fabs(argvars[0].vval.v_float);
+ }
+ else
+ {
+ varnumber_T n;
+ int error = FALSE;
+
+ n = tv_get_number_chk(&argvars[0], &error);
+ if (error)
+ rettv->vval.v_number = -1;
+ else if (n > 0)
+ rettv->vval.v_number = n;
+ else
+ rettv->vval.v_number = -n;
+ }
+}
+
+/*
+ * "acos()" function
+ */
+ static void
+f_acos(typval_T *argvars, typval_T *rettv)
+{
+ float_T f = 0.0;
+
+ rettv->v_type = VAR_FLOAT;
+ if (get_float_arg(argvars, &f) == OK)
+ rettv->vval.v_float = acos(f);
+ else
+ rettv->vval.v_float = 0.0;
+}
+#endif
+
+/*
+ * "add(list, item)" function
+ */
+ static void
+f_add(typval_T *argvars, typval_T *rettv)
+{
+ list_T *l;
+ blob_T *b;
+
+ rettv->vval.v_number = 1; /* Default: Failed */
+ if (argvars[0].v_type == VAR_LIST)
+ {
+ if ((l = argvars[0].vval.v_list) != NULL
+ && !tv_check_lock(l->lv_lock,
+ (char_u *)N_("add() argument"), TRUE)
+ && list_append_tv(l, &argvars[1]) == OK)
+ copy_tv(&argvars[0], rettv);
+ }
+ else if (argvars[0].v_type == VAR_BLOB)
+ {
+ if ((b = argvars[0].vval.v_blob) != NULL
+ && !tv_check_lock(b->bv_lock,
+ (char_u *)N_("add() argument"), TRUE))
+ {
+ int error = FALSE;
+ varnumber_T n = tv_get_number_chk(&argvars[1], &error);
+
+ if (!error)
+ {
+ ga_append(&b->bv_ga, (int)n);
+ copy_tv(&argvars[0], rettv);
+ }
+ }
+ }
+ else
+ emsg(_(e_listblobreq));
+}
+
+/*
+ * "and(expr, expr)" function
+ */
+ static void
+f_and(typval_T *argvars, typval_T *rettv)
+{
+ rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
+ & tv_get_number_chk(&argvars[1], NULL);
+}
+
+/*
+ * If there is a window for "curbuf", make it the current window.
+ */
+ static void
+find_win_for_curbuf(void)
+{
+ wininfo_T *wip;
+
+ for (wip = curbuf->b_wininfo; wip != NULL; wip = wip->wi_next)
+ {
+ if (wip->wi_win != NULL)
+ {
+ curwin = wip->wi_win;
+ break;
+ }
+ }
+}
+
+/*
+ * Set line or list of lines in buffer "buf".
+ */
+ static void
+set_buffer_lines(
+ buf_T *buf,
+ linenr_T lnum_arg,
+ int append,
+ typval_T *lines,
+ typval_T *rettv)
+{
+ linenr_T lnum = lnum_arg + (append ? 1 : 0);
+ char_u *line = NULL;
+ list_T *l = NULL;
+ listitem_T *li = NULL;
+ long added = 0;
+ linenr_T append_lnum;
+ buf_T *curbuf_save = NULL;
+ win_T *curwin_save = NULL;
+ int is_curbuf = buf == curbuf;
+
+ /* When using the current buffer ml_mfp will be set if needed. Useful when
+ * setline() is used on startup. For other buffers the buffer must be
+ * loaded. */
+ if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1)
+ {
+ rettv->vval.v_number = 1; /* FAIL */
+ return;
+ }
+
+ if (!is_curbuf)
+ {
+ curbuf_save = curbuf;
+ curwin_save = curwin;
+ curbuf = buf;
+ find_win_for_curbuf();
+ }
+
+ if (append)
+ // appendbufline() uses the line number below which we insert
+ append_lnum = lnum - 1;
+ else
+ // setbufline() uses the line number above which we insert, we only
+ // append if it's below the last line
+ append_lnum = curbuf->b_ml.ml_line_count;
+
+ if (lines->v_type == VAR_LIST)
+ {
+ l = lines->vval.v_list;
+ li = l->lv_first;
+ }
+ else
+ line = tv_get_string_chk(lines);
+
+ /* default result is zero == OK */
+ for (;;)
+ {
+ if (l != NULL)
+ {
+ /* list argument, get next string */
+ if (li == NULL)
+ break;
+ line = tv_get_string_chk(&li->li_tv);
+ li = li->li_next;
+ }
+
+ rettv->vval.v_number = 1; /* FAIL */
+ if (line == NULL || lnum > curbuf->b_ml.ml_line_count + 1)
+ break;
+
+ /* When coming here from Insert mode, sync undo, so that this can be
+ * undone separately from what was previously inserted. */
+ if (u_sync_once == 2)
+ {
+ u_sync_once = 1; /* notify that u_sync() was called */
+ u_sync(TRUE);
+ }
+
+ if (!append && lnum <= curbuf->b_ml.ml_line_count)
+ {
+ // Existing line, replace it.
+ // Removes any existing text properties.
+ if (u_savesub(lnum) == OK && ml_replace_len(
+ lnum, line, (colnr_T)STRLEN(line) + 1, TRUE, TRUE) == OK)
+ {
+ changed_bytes(lnum, 0);
+ if (is_curbuf && lnum == curwin->w_cursor.lnum)
+ check_cursor_col();
+ rettv->vval.v_number = 0; /* OK */
+ }
+ }
+ else if (added > 0 || u_save(lnum - 1, lnum) == OK)
+ {
+ /* append the line */
+ ++added;
+ if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
+ rettv->vval.v_number = 0; /* OK */
+ }
+
+ if (l == NULL) /* only one string argument */
+ break;
+ ++lnum;
+ }
+
+ if (added > 0)
+ {
+ win_T *wp;
+ tabpage_T *tp;
+
+ appended_lines_mark(append_lnum, added);
+ FOR_ALL_TAB_WINDOWS(tp, wp)
+ if (wp->w_buffer == buf && wp->w_cursor.lnum > append_lnum)
+ wp->w_cursor.lnum += added;
+ check_cursor_col();
+
+#ifdef FEAT_JOB_CHANNEL
+ if (bt_prompt(curbuf) && (State & INSERT))
+ // show the line with the prompt
+ update_topline();
+#endif
+ }
+
+ if (!is_curbuf)
+ {
+ curbuf = curbuf_save;
+ curwin = curwin_save;
+ }
+}
+
+/*
+ * "append(lnum, string/list)" function
+ */
+ static void
+f_append(typval_T *argvars, typval_T *rettv)
+{
+ linenr_T lnum = tv_get_lnum(&argvars[0]);
+
+ set_buffer_lines(curbuf, lnum, TRUE, &argvars[1], rettv);
+}
+
+/*
+ * "appendbufline(buf, lnum, string/list)" function
+ */
+ static void
+f_appendbufline(typval_T *argvars, typval_T *rettv)
+{
+ linenr_T lnum;
+ buf_T *buf;
+
+ buf = tv_get_buf(&argvars[0], FALSE);
+ if (buf == NULL)
+ rettv->vval.v_number = 1; /* FAIL */
+ else
+ {
+ lnum = tv_get_lnum_buf(&argvars[1], buf);
+ set_buffer_lines(buf, lnum, TRUE, &argvars[2], rettv);
+ }
+}
+
+/*
+ * "argc([window id])" function
+ */
+ static void
+f_argc(typval_T *argvars, typval_T *rettv)
+{
+ win_T *wp;
+
+ if (argvars[0].v_type == VAR_UNKNOWN)
+ // use the current window
+ rettv->vval.v_number = ARGCOUNT;
+ else if (argvars[0].v_type == VAR_NUMBER
+ && tv_get_number(&argvars[0]) == -1)
+ // use the global argument list
+ rettv->vval.v_number = GARGCOUNT;
+ else
+ {
+ // use the argument list of the specified window
+ wp = find_win_by_nr_or_id(&argvars[0]);
+ if (wp != NULL)
+ rettv->vval.v_number = WARGCOUNT(wp);
+ else
+ rettv->vval.v_number = -1;
+ }
+}
+
+/*
+ * "argidx()" function
+ */
+ static void
+f_argidx(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ rettv->vval.v_number = curwin->w_arg_idx;
+}
+
+/*
+ * "arglistid()" function
+ */
+ static void
+f_arglistid(typval_T *argvars, typval_T *rettv)
+{
+ win_T *wp;
+
+ rettv->vval.v_number = -1;
+ wp = find_tabwin(&argvars[0], &argvars[1]);
+ if (wp != NULL)
+ rettv->vval.v_number = wp->w_alist->id;
+}
+
+/*
+ * Get the argument list for a given window
+ */
+ static void
+get_arglist_as_rettv(aentry_T *arglist, int argcount, typval_T *rettv)
+{
+ int idx;
+
+ if (rettv_list_alloc(rettv) == OK && arglist != NULL)
+ for (idx = 0; idx < argcount; ++idx)
+ list_append_string(rettv->vval.v_list,
+ alist_name(&arglist[idx]), -1);
+}
+
+/*
+ * "argv(nr)" function
+ */
+ static void
+f_argv(typval_T *argvars, typval_T *rettv)
+{
+ int idx;
+ aentry_T *arglist = NULL;
+ int argcount = -1;
+
+ if (argvars[0].v_type != VAR_UNKNOWN)
+ {
+ if (argvars[1].v_type == VAR_UNKNOWN)
+ {
+ arglist = ARGLIST;
+ argcount = ARGCOUNT;
+ }
+ else if (argvars[1].v_type == VAR_NUMBER
+ && tv_get_number(&argvars[1]) == -1)
+ {
+ arglist = GARGLIST;
+ argcount = GARGCOUNT;
+ }
+ else
+ {
+ win_T *wp = find_win_by_nr_or_id(&argvars[1]);
+
+ if (wp != NULL)
+ {
+ /* Use the argument list of the specified window */
+ arglist = WARGLIST(wp);
+ argcount = WARGCOUNT(wp);
+ }
+ }
+
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+ idx = tv_get_number_chk(&argvars[0], NULL);
+ if (arglist != NULL && idx >= 0 && idx < argcount)
+ rettv->vval.v_string = vim_strsave(alist_name(&arglist[idx]));
+ else if (idx == -1)
+ get_arglist_as_rettv(arglist, argcount, rettv);
+ }
+ else
+ get_arglist_as_rettv(ARGLIST, ARGCOUNT, rettv);
+}
+
+/*
+ * "assert_beeps(cmd [, error])" function
+ */
+ static void
+f_assert_beeps(typval_T *argvars, typval_T *rettv)
+{
+ rettv->vval.v_number = assert_beeps(argvars);
+}
+
+/*
+ * "assert_equal(expected, actual[, msg])" function
+ */
+ static void
+f_assert_equal(typval_T *argvars, typval_T *rettv)
+{
+ rettv->vval.v_number = assert_equal_common(argvars, ASSERT_EQUAL);
+}
+
+/*
+ * "assert_equalfile(fname-one, fname-two)" function
+ */
+ static void
+f_assert_equalfile(typval_T *argvars, typval_T *rettv)
+{
+ rettv->vval.v_number = assert_equalfile(argvars);
+}
+
+/*
+ * "assert_notequal(expected, actual[, msg])" function
+ */
+ static void
+f_assert_notequal(typval_T *argvars, typval_T *rettv)
+{
+ rettv->vval.v_number = assert_equal_common(argvars, ASSERT_NOTEQUAL);
+}
+
+/*
+ * "assert_exception(string[, msg])" function
+ */
+ static void
+f_assert_exception(typval_T *argvars, typval_T *rettv)
+{
+ rettv->vval.v_number = assert_exception(argvars);
+}
+
+/*
+ * "assert_fails(cmd [, error[, msg]])" function
+ */
+ static void
+f_assert_fails(typval_T *argvars, typval_T *rettv)
+{
+ rettv->vval.v_number = assert_fails(argvars);
+}
+
+/*
+ * "assert_false(actual[, msg])" function
+ */
+ static void
+f_assert_false(typval_T *argvars, typval_T *rettv)
+{
+ rettv->vval.v_number = assert_bool(argvars, FALSE);
+}
+
+/*
+ * "assert_inrange(lower, upper[, msg])" function
+ */
+ static void
+f_assert_inrange(typval_T *argvars, typval_T *rettv)
+{
+ rettv->vval.v_number = assert_inrange(argvars);
+}
+
+/*
+ * "assert_match(pattern, actual[, msg])" function
+ */
+ static void
+f_assert_match(typval_T *argvars, typval_T *rettv)
+{
+ rettv->vval.v_number = assert_match_common(argvars, ASSERT_MATCH);
+}
+
+/*
+ * "assert_notmatch(pattern, actual[, msg])" function
+ */
+ static void
+f_assert_notmatch(typval_T *argvars, typval_T *rettv)
+{
+ rettv->vval.v_number = assert_match_common(argvars, ASSERT_NOTMATCH);
+}
+
+/*
+ * "assert_report(msg)" function
+ */
+ static void
+f_assert_report(typval_T *argvars, typval_T *rettv)
+{
+ rettv->vval.v_number = assert_report(argvars);
+}
+
+/*
+ * "assert_true(actual[, msg])" function
+ */
+ static void
+f_assert_true(typval_T *argvars, typval_T *rettv)
+{
+ rettv->vval.v_number = assert_bool(argvars, TRUE);
+}
+
+#ifdef FEAT_FLOAT
+/*
+ * "asin()" function
+ */
+ static void
+f_asin(typval_T *argvars, typval_T *rettv)
+{
+ float_T f = 0.0;
+
+ rettv->v_type = VAR_FLOAT;
+ if (get_float_arg(argvars, &f) == OK)
+ rettv->vval.v_float = asin(f);
+ else
+ rettv->vval.v_float = 0.0;
+}
+
+/*
+ * "atan()" function
+ */
+ static void
+f_atan(typval_T *argvars, typval_T *rettv)
+{
+ float_T f = 0.0;
+
+ rettv->v_type = VAR_FLOAT;
+ if (get_float_arg(argvars, &f) == OK)
+ rettv->vval.v_float = atan(f);
+ else
+ rettv->vval.v_float = 0.0;
+}
+
+/*
+ * "atan2()" function
+ */
+ static void
+f_atan2(typval_T *argvars, typval_T *rettv)
+{
+ float_T fx = 0.0, fy = 0.0;
+
+ rettv->v_type = VAR_FLOAT;
+ if (get_float_arg(argvars, &fx) == OK
+ && get_float_arg(&argvars[1], &fy) == OK)
+ rettv->vval.v_float = atan2(fx, fy);
+ else
+ rettv->vval.v_float = 0.0;
+}
+#endif
+
+/*
+ * "balloon_show()" function
+ */
+#ifdef FEAT_BEVAL
+ static void
+f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
+{
+ if (balloonEval != NULL)
+ {
+ if (argvars[0].v_type == VAR_LIST
+# ifdef FEAT_GUI
+ && !gui.in_use
+# endif
+ )
+ post_balloon(balloonEval, NULL, argvars[0].vval.v_list);
+ else
+ post_balloon(balloonEval, tv_get_string_chk(&argvars[0]), NULL);
+ }
+}
+
+# if defined(FEAT_BEVAL_TERM)
+ static void
+f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
+{
+ if (rettv_list_alloc(rettv) == OK)
+ {
+ char_u *msg = tv_get_string_chk(&argvars[0]);
+
+ if (msg != NULL)
+ {
+ pumitem_T *array;
+ int size = split_message(msg, &array);
+ int i;
+
+ /* Skip the first and last item, they are always empty. */
+ for (i = 1; i < size - 1; ++i)
+ list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
+ while (size > 0)
+ vim_free(array[--size].pum_text);
+ vim_free(array);
+ }
+ }
+}
+# endif
+#endif
+
+/*
+ * "browse(save, title, initdir, default)" function
+ */
+ static void
+f_browse(typval_T *argvars UNUSED, typval_T *rettv)
+{
+#ifdef FEAT_BROWSE
+ int save;
+ char_u *title;
+ char_u *initdir;
+ char_u *defname;
+ char_u buf[NUMBUFLEN];
+ char_u buf2[NUMBUFLEN];
+ int error = FALSE;
+
+ save = (int)tv_get_number_chk(&argvars[0], &error);
+ title = tv_get_string_chk(&argvars[1]);
+ initdir = tv_get_string_buf_chk(&argvars[2], buf);
+ defname = tv_get_string_buf_chk(&argvars[3], buf2);
+
+ if (error || title == NULL || initdir == NULL || defname == NULL)
+ rettv->vval.v_string = NULL;
+ else
+ rettv->vval.v_string =
+ do_browse(save ? BROWSE_SAVE : 0,
+ title, defname, NULL, initdir, NULL, curbuf);
+#else
+ rettv->vval.v_string = NULL;
+#endif
+ rettv->v_type = VAR_STRING;
+}
+
+/*
+ * "browsedir(title, initdir)" function
+ */
+ static void
+f_browsedir(typval_T *argvars UNUSED, typval_T *rettv)
+{
+#ifdef FEAT_BROWSE
+ char_u *title;
+ char_u *initdir;
+ char_u buf[NUMBUFLEN];
+
+ title = tv_get_string_chk(&argvars[0]);
+ initdir = tv_get_string_buf_chk(&argvars[1], buf);
+
+ if (title == NULL || initdir == NULL)
+ rettv->vval.v_string = NULL;
+ else
+ rettv->vval.v_string = do_browse(BROWSE_DIR,
+ title, NULL, NULL, initdir, NULL, curbuf);
+#else
+ rettv->vval.v_string = NULL;
+#endif
+ rettv->v_type = VAR_STRING;
+}
+
+/*
+ * Find a buffer by number or exact name.
+ */
+ static buf_T *
+find_buffer(typval_T *avar)
+{
+ buf_T *buf = NULL;
+
+ if (avar->v_type == VAR_NUMBER)
+ buf = buflist_findnr((int)avar->vval.v_number);
+ else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL)
+ {
+ buf = buflist_findname_exp(avar->vval.v_string);
+ if (buf == NULL)
+ {
+ /* No full path name match, try a match with a URL or a "nofile"
+ * buffer, these don't use the full path. */
+ FOR_ALL_BUFFERS(buf)
+ if (buf->b_fname != NULL
+ && (path_with_url(buf->b_fname)
+#ifdef FEAT_QUICKFIX
+ || bt_nofile(buf)
+#endif
+ )
+ && STRCMP(buf->b_fname, avar->vval.v_string) == 0)
+ break;
+ }
+ }
+ return buf;
+}
+
+/*
+ * "bufexists(expr)" function
+ */
+ static void
+f_bufexists(typval_T *argvars, typval_T *rettv)
+{
+ rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
+}
+
+/*
+ * "buflisted(expr)" function
+ */
+ static void
+f_buflisted(typval_T *argvars, typval_T *rettv)
+{
+ buf_T *buf;
+
+ buf = find_buffer(&argvars[0]);
+ rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
+}
+
+/*
+ * "bufloaded(expr)" function
+ */
+ static void
+f_bufloaded(typval_T *argvars, typval_T *rettv)
+{
+ buf_T *buf;
+
+ buf = find_buffer(&argvars[0]);
+ rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
+}
+
+ buf_T *
+buflist_find_by_name(char_u *name, int curtab_only)
+{
+ int save_magic;
+ char_u *save_cpo;
+ buf_T *buf;
+
+ /* Ignore 'magic' and 'cpoptions' here to make scripts portable */
+ save_magic = p_magic;
+ p_magic = TRUE;
+ save_cpo = p_cpo;
+ p_cpo = (char_u *)"";
+
+ buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name),
+ TRUE, FALSE, curtab_only));
+
+ p_magic = save_magic;
+ p_cpo = save_cpo;
+ return buf;
+}
+
+/*
+ * Get buffer by number or pattern.
+ */
+ buf_T *
+tv_get_buf(typval_T *tv, int curtab_only)
+{
+ char_u *name = tv->vval.v_string;
+ buf_T *buf;
+
+ if (tv->v_type == VAR_NUMBER)
+ return buflist_findnr((int)tv->vval.v_number);
+ if (tv->v_type != VAR_STRING)
+ return NULL;
+ if (name == NULL || *name == NUL)
+ return curbuf;
+ if (name[0] == '$' && name[1] == NUL)
+ return lastbuf;
+
+ buf = buflist_find_by_name(name, curtab_only);
+
+ /* If not found, try expanding the name, like done for bufexists(). */
+ if (buf == NULL)
+ buf = find_buffer(tv);
+
+ return buf;
+}
+
+#ifdef FEAT_SIGNS
+/*
+ * Get the buffer from "arg" and give an error and return NULL if it is not
+ * valid.
+ */
+ static buf_T *
+get_buf_arg(typval_T *arg)
+{
+ buf_T *buf;
+
+ ++emsg_off;
+ buf = tv_get_buf(arg, FALSE);
+ --emsg_off;
+ if (buf == NULL)
+ semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
+ return buf;
+}
+#endif
+
+/*
+ * "bufname(expr)" function
+ */
+ static void
+f_bufname(typval_T *argvars, typval_T *rettv)
+{
+ buf_T *buf;
+
+ (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
+ ++emsg_off;
+ buf = tv_get_buf(&argvars[0], FALSE);
+ rettv->v_type = VAR_STRING;
+ if (buf != NULL && buf->b_fname != NULL)
+ rettv->vval.v_string = vim_strsave(buf->b_fname);
+ else
+ rettv->vval.v_string = NULL;
+ --emsg_off;
+}
+
+/*
+ * "bufnr(expr)" function
+ */
+ static void
+f_bufnr(typval_T *argvars, typval_T *rettv)
+{
+ buf_T *buf;
+ int error = FALSE;
+ char_u *name;
+
+ (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
+ ++emsg_off;
+ buf = tv_get_buf(&argvars[0], FALSE);
+ --emsg_off;
+
+ /* If the buffer isn't found and the second argument is not zero create a
+ * new buffer. */
+ if (buf == NULL
+ && argvars[1].v_type != VAR_UNKNOWN
+ && tv_get_number_chk(&argvars[1], &error) != 0
+ && !error
+ && (name = tv_get_string_chk(&argvars[0])) != NULL
+ && !error)
+ buf = buflist_new(name, NULL, (linenr_T)1, 0);
+
+ if (buf != NULL)
+ rettv->vval.v_number = buf->b_fnum;
+ else
+ rettv->vval.v_number = -1;
+}
+
+ static void
+buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr)
+{
+ win_T *wp;
+ int winnr = 0;
+ buf_T *buf;
+
+ (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
+ ++emsg_off;
+ buf = tv_get_buf(&argvars[0], TRUE);
+ FOR_ALL_WINDOWS(wp)
+ {
+ ++winnr;
+ if (wp->w_buffer == buf)
+ break;
+ }
+ rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1);
+ --emsg_off;
+}
+
+/*
+ * "bufwinid(nr)" function
+ */
+ static void
+f_bufwinid(typval_T *argvars, typval_T *rettv)
+{
+ buf_win_common(argvars, rettv, FALSE);
+}
+
+/*
+ * "bufwinnr(nr)" function
+ */
+ static void
+f_bufwinnr(typval_T *argvars, typval_T *rettv)
+{
+ buf_win_common(argvars, rettv, TRUE);
+}
+
+/*
+ * "byte2line(byte)" function
+ */
+ static void
+f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
+{
+#ifndef FEAT_BYTEOFF
+ rettv->vval.v_number = -1;
+#else
+ long boff = 0;
+
+ boff = tv_get_number(&argvars[0]) - 1; /* boff gets -1 on type error */
+ if (boff < 0)
+ rettv->vval.v_number = -1;
+ else
+ rettv->vval.v_number = ml_find_line_or_offset(curbuf,
+ (linenr_T)0, &boff);
+#endif
+}
+
+ static void
+byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
+{
+ char_u *t;
+ char_u *str;
+ varnumber_T idx;
+
+ str = tv_get_string_chk(&argvars[0]);
+ idx = tv_get_number_chk(&argvars[1], NULL);
+ rettv->vval.v_number = -1;
+ if (str == NULL || idx < 0)
+ return;
+
+ t = str;
+ for ( ; idx > 0; idx--)
+ {
+ if (*t == NUL) /* EOL reached */
+ return;
+ if (enc_utf8 && comp)
+ t += utf_ptr2len(t);
+ else
+ t += (*mb_ptr2len)(t);
+ }
+ rettv->vval.v_number = (varnumber_T)(t - str);
+}
+
+/*
+ * "byteidx()" function
+ */
+ static void
+f_byteidx(typval_T *argvars, typval_T *rettv)
+{
+ byteidx(argvars, rettv, FALSE);
+}
+
+/*
+ * "byteidxcomp()" function
+ */
+ static void
+f_byteidxcomp(typval_T *argvars, typval_T *rettv)
+{
+ byteidx(argvars, rettv, TRUE);
+}
+
+/*
+ * "call(func, arglist [, dict])" function
+ */
+ static void
+f_call(typval_T *argvars, typval_T *rettv)
+{
+ char_u *func;
+ partial_T *partial = NULL;
+ dict_T *selfdict = NULL;
+
+ if (argvars[1].v_type != VAR_LIST)
+ {
+ emsg(_(e_listreq));
+ return;
+ }
+ if (argvars[1].vval.v_list == NULL)
+ return;
+
+ if (argvars[0].v_type == VAR_FUNC)
+ func = argvars[0].vval.v_string;
+ else if (argvars[0].v_type == VAR_PARTIAL)
+ {
+ partial = argvars[0].vval.v_partial;
+ func = partial_name(partial);
+ }
+ else
+ func = tv_get_string(&argvars[0]);
+ if (*func == NUL)
+ return; /* type error or empty name */
+
+ if (argvars[2].v_type != VAR_UNKNOWN)
+ {
+ if (argvars[2].v_type != VAR_DICT)
+ {
+ emsg(_(e_dictreq));
+ return;
+ }
+ selfdict = argvars[2].vval.v_dict;
+ }
+
+ (void)func_call(func, &argvars[1], partial, selfdict, rettv);
+}
+
+#ifdef FEAT_FLOAT
+/*
+ * "ceil({float})" function
+ */
+ static void
+f_ceil(typval_T *argvars, typval_T *rettv)
+{
+ float_T f = 0.0;
+
+ rettv->v_type = VAR_FLOAT;
+ if (get_float_arg(argvars, &f) == OK)
+ rettv->vval.v_float = ceil(f);
+ else
+ rettv->vval.v_float = 0.0;
+}
+#endif
+
+#ifdef FEAT_JOB_CHANNEL
+/*
+ * "ch_canread()" function
+ */
+ static void
+f_ch_canread(typval_T *argvars, typval_T *rettv)
+{
+ channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
+
+ rettv->vval.v_number = 0;
+ if (channel != NULL)
+ rettv->vval.v_number = channel_has_readahead(channel, PART_SOCK)
+ || channel_has_readahead(channel, PART_OUT)
+ || channel_has_readahead(channel, PART_ERR);
+}
+
+/*
+ * "ch_close()" function
+ */
+ static void
+f_ch_close(typval_T *argvars, typval_T *rettv UNUSED)
+{
+ channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
+
+ if (channel != NULL)
+ {
+ channel_close(channel, FALSE);
+ channel_clear(channel);
+ }
+}
+
+/*
+ * "ch_close()" function
+ */
+ static void
+f_ch_close_in(typval_T *argvars, typval_T *rettv UNUSED)
+{
+ channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
+
+ if (channel != NULL)
+ channel_close_in(channel);
+}
+
+/*
+ * "ch_getbufnr()" function
+ */
+ static void
+f_ch_getbufnr(typval_T *argvars, typval_T *rettv)
+{
+ channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
+
+ rettv->vval.v_number = -1;
+ if (channel != NULL)
+ {
+ char_u *what = tv_get_string(&argvars[1]);
+ int part;
+
+ if (STRCMP(what, "err") == 0)
+ part = PART_ERR;
+ else if (STRCMP(what, "out") == 0)
+ part = PART_OUT;
+ else if (STRCMP(what, "in") == 0)
+ part = PART_IN;
+ else
+ part = PART_SOCK;
+ if (channel->ch_part[part].ch_bufref.br_buf != NULL)
+ rettv->vval.v_number =
+ channel->ch_part[part].ch_bufref.br_buf->b_fnum;
+ }
+}
+
+/*
+ * "ch_getjob()" function
+ */
+ static void
+f_ch_getjob(typval_T *argvars, typval_T *rettv)
+{
+ channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
+
+ if (channel != NULL)
+ {
+ rettv->v_type = VAR_JOB;
+ rettv->vval.v_job = channel->ch_job;
+ if (channel->ch_job != NULL)
+ ++channel->ch_job->jv_refcount;
+ }
+}
+
+/*
+ * "ch_info()" function
+ */
+ static void
+f_ch_info(typval_T *argvars, typval_T *rettv UNUSED)
+{
+ channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
+
+ if (channel != NULL && rettv_dict_alloc(rettv) != FAIL)
+ channel_info(channel, rettv->vval.v_dict);
+}
+
+/*
+ * "ch_log()" function
+ */
+ static void
+f_ch_log(typval_T *argvars, typval_T *rettv UNUSED)
+{
+ char_u *msg = tv_get_string(&argvars[0]);
+ channel_T *channel = NULL;
+
+ if (argvars[1].v_type != VAR_UNKNOWN)
+ channel = get_channel_arg(&argvars[1], FALSE, FALSE, 0);
+
+ ch_log(channel, "%s", msg);
+}
+
+/*
+ * "ch_logfile()" function
+ */
+ static void
+f_ch_logfile(typval_T *argvars, typval_T *rettv UNUSED)
+{
+ char_u *fname;
+ char_u *opt = (char_u *)"";
+ char_u buf[NUMBUFLEN];
+
+ /* Don't open a file in restricted mode. */
+ if (check_restricted() || check_secure())
+ return;
+ fname = tv_get_string(&argvars[0]);
+ if (argvars[1].v_type == VAR_STRING)
+ opt = tv_get_string_buf(&argvars[1], buf);
+ ch_logfile(fname, opt);
+}
+
+/*
+ * "ch_open()" function
+ */
+ static void
+f_ch_open(typval_T *argvars, typval_T *rettv)
+{
+ rettv->v_type = VAR_CHANNEL;
+ if (check_restricted() || check_secure())
+ return;
+ rettv->vval.v_channel = channel_open_func(argvars);
+}
+
+/*
+ * "ch_read()" function
+ */
+ static void
+f_ch_read(typval_T *argvars, typval_T *rettv)
+{
+ common_channel_read(argvars, rettv, FALSE, FALSE);
+}
+
+/*
+ * "ch_readblob()" function
+ */
+ static void
+f_ch_readblob(typval_T *argvars, typval_T *rettv)
+{
+ common_channel_read(argvars, rettv, TRUE, TRUE);
+}
+
+/*
+ * "ch_readraw()" function
+ */
+ static void
+f_ch_readraw(typval_T *argvars, typval_T *rettv)
+{
+ common_channel_read(argvars, rettv, TRUE, FALSE);
+}
+
+/*
+ * "ch_evalexpr()" function
+ */
+ static void
+f_ch_evalexpr(typval_T *argvars, typval_T *rettv)
+{
+ ch_expr_common(argvars, rettv, TRUE);
+}
+
+/*
+ * "ch_sendexpr()" function
+ */
+ static void
+f_ch_sendexpr(typval_T *argvars, typval_T *rettv)
+{
+ ch_expr_common(argvars, rettv, FALSE);
+}
+
+/*
+ * "ch_evalraw()" function
+ */
+ static void
+f_ch_evalraw(typval_T *argvars, typval_T *rettv)
+{
+ ch_raw_common(argvars, rettv, TRUE);
+}
+
+/*
+ * "ch_sendraw()" function
+ */
+ static void
+f_ch_sendraw(typval_T *argvars, typval_T *rettv)
+{
+ ch_raw_common(argvars, rettv, FALSE);
+}
+
+/*
+ * "ch_setoptions()" function
+ */
+ static void
+f_ch_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
+{
+ channel_T *channel;
+ jobopt_T opt;
+
+ channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
+ if (channel == NULL)
+ return;
+ clear_job_options(&opt);
+ if (get_job_options(&argvars[1], &opt,
+ JO_CB_ALL + JO_TIMEOUT_ALL + JO_MODE_ALL, 0) == OK)
+ channel_set_options(channel, &opt);
+ free_job_options(&opt);
+}
+
+/*
+ * "ch_status()" function
+ */
+ static void
+f_ch_status(typval_T *argvars, typval_T *rettv)
+{
+ channel_T *channel;
+ jobopt_T opt;
+ int part = -1;
+
+ /* return an empty string by default */
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+
+ channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
+
+ if (argvars[1].v_type != VAR_UNKNOWN)
+ {
+ clear_job_options(&opt);
+ if (get_job_options(&argvars[1], &opt, JO_PART, 0) == OK
+ && (opt.jo_set & JO_PART))
+ part = opt.jo_part;
+ }
+
+ rettv->vval.v_string = vim_strsave((char_u *)channel_status(channel, part));
+}
+#endif
+
+/*
+ * "changenr()" function
+ */
+ static void
+f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ rettv->vval.v_number = curbuf->b_u_seq_cur;
+}
+
+/*
+ * "char2nr(string)" function
+ */
+ static void
+f_char2nr(typval_T *argvars, typval_T *rettv)
+{
+ if (has_mbyte)
+ {
+ int utf8 = 0;
+
+ if (argvars[1].v_type != VAR_UNKNOWN)
+ utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
+
+ if (utf8)
+ rettv->vval.v_number = (*utf_ptr2char)(tv_get_string(&argvars[0]));
+ else
+ rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
+ }
+ else
+ rettv->vval.v_number = tv_get_string(&argvars[0])[0];
+}
+
+/*
+ * "cindent(lnum)" function
+ */
+ static void
+f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
+{
+#ifdef FEAT_CINDENT
+ pos_T pos;
+ linenr_T lnum;
+
+ pos = curwin->w_cursor;
+ lnum = tv_get_lnum(argvars);
+ if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
+ {
+ curwin->w_cursor.lnum = lnum;
+ rettv->vval.v_number = get_c_indent();
+ curwin->w_cursor = pos;
+ }
+ else
+#endif
+ rettv->vval.v_number = -1;
+}
+
+/*
+ * "clearmatches()" function
+ */
+ static void
+f_clearmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
+{
+#ifdef FEAT_SEARCH_EXTRA
+ clear_matches(curwin);
+#endif
+}
+
+/*
+ * "col(string)" function
+ */
+ static void
+f_col(typval_T *argvars, typval_T *rettv)
+{
+ colnr_T col = 0;
+ pos_T *fp;
+ int fnum = curbuf->b_fnum;
+
+ fp = var2fpos(&argvars[0], FALSE, &fnum);
+ if (fp != NULL && fnum == curbuf->b_fnum)
+ {
+ if (fp->col == MAXCOL)
+ {
+ /* '> can be MAXCOL, get the length of the line then */
+ if (fp->lnum <= curbuf->b_ml.ml_line_count)
+ col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
+ else
+ col = MAXCOL;
+ }
+ else
+ {
+ col = fp->col + 1;
+ /* col(".") when the cursor is on the NUL at the end of the line
+ * because of "coladd" can be seen as an extra column. */
+ if (virtual_active() && fp == &curwin->w_cursor)
+ {
+ char_u *p = ml_get_cursor();
+
+ if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
+ curwin->w_virtcol - curwin->w_cursor.coladd))
+ {
+ int l;
+
+ if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
+ col += l;
+ }
+ }
+ }
+ }
+ rettv->vval.v_number = col;
+}
+
+#if defined(FEAT_INS_EXPAND)
+/*
+ * "complete()" function
+ */
+ static void
+f_complete(typval_T *argvars, typval_T *rettv UNUSED)
+{
+ int startcol;
+
+ if ((State & INSERT) == 0)
+ {
+ emsg(_("E785: complete() can only be used in Insert mode"));
+ return;
+ }
+
+ /* Check for undo allowed here, because if something was already inserted
+ * the line was already saved for undo and this check isn't done. */
+ if (!undo_allowed())
+ return;
+
+ if (argvars[1].v_type != VAR_LIST || argvars[1].vval.v_list == NULL)
+ {
+ emsg(_(e_invarg));
+ return;
+ }
+
+ startcol = (int)tv_get_number_chk(&argvars[0], NULL);
+ if (startcol <= 0)
+ return;
+
+ set_completion(startcol - 1, argvars[1].vval.v_list);
+}
+
+/*
+ * "complete_add()" function
+ */
+ static void
+f_complete_add(typval_T *argvars, typval_T *rettv)
+{
+ rettv->vval.v_number = ins_compl_add_tv(&argvars[0], 0);
+}
+
+/*
+ * "complete_check()" function
+ */
+ static void
+f_complete_check(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ int saved = RedrawingDisabled;
+
+ RedrawingDisabled = 0;
+ ins_compl_check_keys(0, TRUE);
+ rettv->vval.v_number = compl_interrupted;
+ RedrawingDisabled = saved;
+}
+#endif
+
+/*
+ * "confirm(message, buttons[, default [, type]])" function
+ */
+ static void
+f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
+{
+#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
+ char_u *message;
+ char_u *buttons = NULL;
+ char_u buf[NUMBUFLEN];
+ char_u buf2[NUMBUFLEN];
+ int def = 1;
+ int type = VIM_GENERIC;
+ char_u *typestr;
+ int error = FALSE;
+
+ message = tv_get_string_chk(&argvars[0]);
+ if (message == NULL)
+ error = TRUE;
+ if (argvars[1].v_type != VAR_UNKNOWN)
+ {
+ buttons = tv_get_string_buf_chk(&argvars[1], buf);
+ if (buttons == NULL)
+ error = TRUE;
+ if (argvars[2].v_type != VAR_UNKNOWN)
+ {
+ def = (int)tv_get_number_chk(&argvars[2], &error);
+ if (argvars[3].v_type != VAR_UNKNOWN)
+ {
+ typestr = tv_get_string_buf_chk(&argvars[3], buf2);
+ if (typestr == NULL)
+ error = TRUE;
+ else
+ {
+ switch (TOUPPER_ASC(*typestr))
+ {
+ case 'E': type = VIM_ERROR; break;
+ case 'Q': type = VIM_QUESTION; break;
+ case 'I': type = VIM_INFO; break;
+ case 'W': type = VIM_WARNING; break;
+ case 'G': type = VIM_GENERIC; break;
+ }
+ }
+ }
+ }
+ }
+
+ if (buttons == NULL || *buttons == NUL)
+ buttons = (char_u *)_("&Ok");
+
+ if (!error)
+ rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
+ def, NULL, FALSE);
+#endif
+}
+
+/*
+ * "copy()" function
+ */
+ static void
+f_copy(typval_T *argvars, typval_T *rettv)
+{
+ item_copy(&argvars[0], rettv, FALSE, 0);
+}
+
+#ifdef FEAT_FLOAT
+/*
+ * "cos()" function
+ */
+ static void
+f_cos(typval_T *argvars, typval_T *rettv)
+{
+ float_T f = 0.0;
+
+ rettv->v_type = VAR_FLOAT;
+ if (get_float_arg(argvars, &f) == OK)
+ rettv->vval.v_float = cos(f);
+ else
+ rettv->vval.v_float = 0.0;
+}
+
+/*
+ * "cosh()" function
+ */
+ static void
+f_cosh(typval_T *argvars, typval_T *rettv)
+{
+ float_T f = 0.0;
+
+ rettv->v_type = VAR_FLOAT;
+ if (get_float_arg(argvars, &f) == OK)
+ rettv->vval.v_float = cosh(f);
+ else
+ rettv->vval.v_float = 0.0;
+}
+#endif
+
+/*
+ * "count()" function
+ */
+ static void
+f_count(typval_T *argvars, typval_T *rettv)
+{
+ long n = 0;
+ int ic = FALSE;
+ int error = FALSE;
+
+ if (argvars[2].v_type != VAR_UNKNOWN)
+ ic = (int)tv_get_number_chk(&argvars[2], &error);
+
+ if (argvars[0].v_type == VAR_STRING)
+ {
+ char_u *expr = tv_get_string_chk(&argvars[1]);
+ char_u *p = argvars[0].vval.v_string;
+ char_u *next;
+
+ if (!error && expr != NULL && *expr != NUL && p != NULL)
+ {
+ if (ic)
+ {
+ size_t len = STRLEN(expr);
+
+ while (*p != NUL)
+ {
+ if (MB_STRNICMP(p, expr, len) == 0)
+ {
+ ++n;
+ p += len;
+ }
+ else
+ MB_PTR_ADV(p);
+ }
+ }
+ else
+ while ((next = (char_u *)strstr((char *)p, (char *)expr))
+ != NULL)
+ {
+ ++n;
+ p = next + STRLEN(expr);
+ }
+ }
+
+ }
+ else if (argvars[0].v_type == VAR_LIST)
+ {
+ listitem_T *li;
+ list_T *l;
+ long idx;
+
+ if ((l = argvars[0].vval.v_list) != NULL)
+ {
+ li = l->lv_first;
+ if (argvars[2].v_type != VAR_UNKNOWN)
+ {
+ if (argvars[3].v_type != VAR_UNKNOWN)
+ {
+ idx = (long)tv_get_number_chk(&argvars[3], &error);
+ if (!error)
+ {
+ li = list_find(l, idx);
+ if (li == NULL)
+ semsg(_(e_listidx), idx);
+ }
+ }
+ if (error)
+ li = NULL;
+ }
+
+ for ( ; li != NULL; li = li->li_next)
+ if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE))
+ ++n;
+ }
+ }
+ else if (argvars[0].v_type == VAR_DICT)
+ {
+ int todo;
+ dict_T *d;
+ hashitem_T *hi;
+
+ if ((d = argvars[0].vval.v_dict) != NULL)
+ {
+ if (argvars[2].v_type != VAR_UNKNOWN)
+ {
+ if (argvars[3].v_type != VAR_UNKNOWN)
+ emsg(_(e_invarg));
+ }
+
+ todo = error ? 0 : (int)d->dv_hashtab.ht_used;
+ for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
+ {
+ if (!HASHITEM_EMPTY(hi))
+ {
+ --todo;
+ if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE))
+ ++n;
+ }
+ }
+ }
+ }
+ else
+ semsg(_(e_listdictarg), "count()");
+ rettv->vval.v_number = n;
+}
+
+/*
+ * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
+ *
+ * Checks the existence of a cscope connection.
+ */
+ static void
+f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
+{
+#ifdef FEAT_CSCOPE
+ int num = 0;
+ char_u *dbpath = NULL;
+ char_u *prepend = NULL;
+ char_u buf[NUMBUFLEN];
+
+ if (argvars[0].v_type != VAR_UNKNOWN
+ && argvars[1].v_type != VAR_UNKNOWN)
+ {
+ num = (int)tv_get_number(&argvars[0]);
+ dbpath = tv_get_string(&argvars[1]);
+ if (argvars[2].v_type != VAR_UNKNOWN)
+ prepend = tv_get_string_buf(&argvars[2], buf);
+ }
+
+ rettv->vval.v_number = cs_connection(num, dbpath, prepend);
+#endif
+}
+
+/*
+ * "cursor(lnum, col)" function, or
+ * "cursor(list)"
+ *
+ * Moves the cursor to the specified line and column.
+ * Returns 0 when the position could be set, -1 otherwise.
+ */
+ static void
+f_cursor(typval_T *argvars, typval_T *rettv)
+{
+ long line, col;
+ long coladd = 0;
+ int set_curswant = TRUE;
+
+ rettv->vval.v_number = -1;
+ if (argvars[1].v_type == VAR_UNKNOWN)
+ {
+ pos_T pos;
+ colnr_T curswant = -1;
+
+ if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
+ {
+ emsg(_(e_invarg));
+ return;
+ }
+ line = pos.lnum;
+ col = pos.col;
+ coladd = pos.coladd;
+ if (curswant >= 0)
+ {
+ curwin->w_curswant = curswant - 1;
+ set_curswant = FALSE;
+ }
+ }
+ else
+ {
+ line = tv_get_lnum(argvars);
+ col = (long)tv_get_number_chk(&argvars[1], NULL);
+ if (argvars[2].v_type != VAR_UNKNOWN)
+ coladd = (long)tv_get_number_chk(&argvars[2], NULL);
+ }
+ if (line < 0 || col < 0 || coladd < 0)
+ return; /* type error; errmsg already given */
+ if (line > 0)
+ curwin->w_cursor.lnum = line;
+ if (col > 0)
+ curwin->w_cursor.col = col - 1;
+ curwin->w_cursor.coladd = coladd;
+
+ /* Make sure the cursor is in a valid position. */
+ check_cursor();
+ /* Correct cursor for multi-byte character. */
+ if (has_mbyte)
+ mb_adjust_cursor();
+
+ curwin->w_set_curswant = set_curswant;
+ rettv->vval.v_number = 0;
+}
+
+#ifdef WIN3264
+/*
+ * "debugbreak()" function
+ */
+ static void
+f_debugbreak(typval_T *argvars, typval_T *rettv)
+{
+ int pid;
+
+ rettv->vval.v_number = FAIL;
+ pid = (int)tv_get_number(&argvars[0]);
+ if (pid == 0)
+ emsg(_(e_invarg));
+ else
+ {
+ HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
+
+ if (hProcess != NULL)
+ {
+ DebugBreakProcess(hProcess);
+ CloseHandle(hProcess);
+ rettv->vval.v_number = OK;
+ }
+ }
+}
+#endif
+
+/*
+ * "deepcopy()" function
+ */
+ static void
+f_deepcopy(typval_T *argvars, typval_T *rettv)
+{
+ int noref = 0;
+ int copyID;
+
+ if (argvars[1].v_type != VAR_UNKNOWN)
+ noref = (int)tv_get_number_chk(&argvars[1], NULL);
+ if (noref < 0 || noref > 1)
+ emsg(_(e_invarg));
+ else
+ {
+ copyID = get_copyID();
+ item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
+ }
+}
+
+/*
+ * "delete()" function
+ */
+ static void
+f_delete(typval_T *argvars, typval_T *rettv)
+{
+ char_u nbuf[NUMBUFLEN];
+ char_u *name;
+ char_u *flags;
+
+ rettv->vval.v_number = -1;
+ if (check_restricted() || check_secure())
+ return;
+
+ name = tv_get_string(&argvars[0]);
+ if (name == NULL || *name == NUL)
+ {
+ emsg(_(e_invarg));
+ return;
+ }
+
+ if (argvars[1].v_type != VAR_UNKNOWN)
+ flags = tv_get_string_buf(&argvars[1], nbuf);
+ else
+ flags = (char_u *)"";
+
+ if (*flags == NUL)
+ /* delete a file */
+ rettv->vval.v_number = mch_remove(name) == 0 ? 0 : -1;
+ else if (STRCMP(flags, "d") == 0)
+ /* delete an empty directory */
+ rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1;
+ else if (STRCMP(flags, "rf") == 0)
+ /* delete a directory recursively */
+ rettv->vval.v_number = delete_recursive(name);
+ else
+ semsg(_(e_invexpr2), flags);
+}
+
+/*
+ * "deletebufline()" function
+ */
+ static void
+f_deletebufline(typval_T *argvars, typval_T *rettv)
+{
+ buf_T *buf;
+ linenr_T first, last;
+ linenr_T lnum;
+ long count;
+ int is_curbuf;
+ buf_T *curbuf_save = NULL;
+ win_T *curwin_save = NULL;
+ tabpage_T *tp;
+ win_T *wp;
+
+ buf = tv_get_buf(&argvars[0], FALSE);
+ if (buf == NULL)
+ {
+ rettv->vval.v_number = 1; /* FAIL */
+ return;
+ }
+ is_curbuf = buf == curbuf;
+
+ first = tv_get_lnum_buf(&argvars[1], buf);
+ if (argvars[2].v_type != VAR_UNKNOWN)
+ last = tv_get_lnum_buf(&argvars[2], buf);
+ else
+ last = first;
+
+ if (buf->b_ml.ml_mfp == NULL || first < 1
+ || first > buf->b_ml.ml_line_count || last < first)
+ {
+ rettv->vval.v_number = 1; /* FAIL */
+ return;
+ }
+
+ if (!is_curbuf)
+ {
+ curbuf_save = curbuf;
+ curwin_save = curwin;
+ curbuf = buf;
+ find_win_for_curbuf();
+ }
+ if (last > curbuf->b_ml.ml_line_count)
+ last = curbuf->b_ml.ml_line_count;
+ count = last - first + 1;
+
+ // When coming here from Insert mode, sync undo, so that this can be
+ // undone separately from what was previously inserted.
+ if (u_sync_once == 2)
+ {
+ u_sync_once = 1; // notify that u_sync() was called
+ u_sync(TRUE);
+ }
+
+ if (u_save(first - 1, last + 1) == FAIL)
+ {
+ rettv->vval.v_number = 1; /* FAIL */
+ return;
+ }
+
+ for (lnum = first; lnum <= last; ++lnum)
+ ml_delete(first, TRUE);
+
+ FOR_ALL_TAB_WINDOWS(tp, wp)
+ if (wp->w_buffer == buf)
+ {
+ if (wp->w_cursor.lnum > last)
+ wp->w_cursor.lnum -= count;
+ else if (wp->w_cursor.lnum> first)
+ wp->w_cursor.lnum = first;
+ if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
+ wp->w_cursor.lnum = wp->w_buffer->b_ml.ml_line_count;
+ }
+ check_cursor_col();
+ deleted_lines_mark(first, count);
+
+ if (!is_curbuf)
+ {
+ curbuf = curbuf_save;
+ curwin = curwin_save;
+ }
+}
+
+/*
+ * "did_filetype()" function
+ */
+ static void
+f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
+{
+ rettv->vval.v_number = did_filetype;
+}
+
+/*
+ * "diff_filler()" function
+ */
+ static void
+f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
+{
+#ifdef FEAT_DIFF
+ rettv->vval.v_number = diff_check_fill(curwin, tv_get_lnum(argvars));
+#endif
+}
+
+/*
+ * "diff_hlID()" function
+ */
+ static void
+f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
+{
+#ifdef FEAT_DIFF
+ linenr_T lnum = tv_get_lnum(argvars);
+ static linenr_T prev_lnum = 0;
+ static varnumber_T changedtick = 0;
+ static int fnum = 0;
+ static int change_start = 0;
+ static int change_end = 0;
+ static hlf_T hlID = (hlf_T)0;
+ int filler_lines;
+ int col;
+
+ if (lnum < 0) /* ignore type error in {lnum} arg */
+ lnum = 0;
+ if (lnum != prev_lnum
+ || changedtick != CHANGEDTICK(curbuf)
+ || fnum != curbuf->b_fnum)
+ {
+ /* New line, buffer, change: need to get the values. */
+ filler_lines = diff_check(curwin, lnum);
+ if (filler_lines < 0)
+ {
+ if (filler_lines == -1)
+ {
+ change_start = MAXCOL;
+ change_end = -1;
+ if (diff_find_change(curwin, lnum, &change_start, &change_end))
+ hlID = HLF_ADD; /* added line */
+ else
+ hlID = HLF_CHD; /* changed line */
+ }
+ else
+ hlID = HLF_ADD; /* added line */
+ }
+ else
+ hlID = (hlf_T)0;
+ prev_lnum = lnum;
+ changedtick = CHANGEDTICK(curbuf);
+ fnum = curbuf->b_fnum;
+ }
+
+ if (hlID == HLF_CHD || hlID == HLF_TXD)
+ {
+ col = tv_get_number(&argvars[1]) - 1; /* ignore type error in {col} */
+ if (col >= change_start && col <= change_end)
+ hlID = HLF_TXD; /* changed text */
+ else
+ hlID = HLF_CHD; /* changed line */
+ }
+ rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID;
+#endif
+}
+
+/*
+ * "empty({expr})" function
+ */
+ static void
+f_empty(typval_T *argvars, typval_T *rettv)
+{
+ int n = FALSE;
+
+ switch (argvars[0].v_type)
+ {
+ case VAR_STRING:
+ case VAR_FUNC:
+ n = argvars[0].vval.v_string == NULL
+ || *argvars[0].vval.v_string == NUL;
+ break;
+ case VAR_PARTIAL:
+ n = FALSE;
+ break;
+ case VAR_NUMBER:
+ n = argvars[0].vval.v_number == 0;
+ break;
+ case VAR_FLOAT:
+#ifdef FEAT_FLOAT
+ n = argvars[0].vval.v_float == 0.0;
+ break;
+#endif
+ case VAR_LIST:
+ n = argvars[0].vval.v_list == NULL
+ || argvars[0].vval.v_list->lv_first == NULL;
+ break;
+ case VAR_DICT:
+ n = argvars[0].vval.v_dict == NULL
+ || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
+ break;
+ case VAR_SPECIAL:
+ n = argvars[0].vval.v_number != VVAL_TRUE;
+ break;
+
+ case VAR_BLOB:
+ n = argvars[0].vval.v_blob == NULL
+ || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
+ break;
+
+ case VAR_JOB:
+#ifdef FEAT_JOB_CHANNEL
+ n = argvars[0].vval.v_job == NULL
+ || argvars[0].vval.v_job->jv_status != JOB_STARTED;
+ break;
+#endif
+ case VAR_CHANNEL:
+#ifdef FEAT_JOB_CHANNEL
+ n = argvars[0].vval.v_channel == NULL
+ || !channel_is_open(argvars[0].vval.v_channel);
+ break;
+#endif
+ case VAR_UNKNOWN:
+ internal_error("f_empty(UNKNOWN)");
+ n = TRUE;
+ break;
+ }
+
+ rettv->vval.v_number = n;
+}
+
+/*
+ * "escape({string}, {chars})" function
+ */
+ static void
+f_escape(typval_T *argvars, typval_T *rettv)
+{
+ char_u buf[NUMBUFLEN];
+
+ rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
+ tv_get_string_buf(&argvars[1], buf));
+ rettv->v_type = VAR_STRING;
+}
+
+/*
+ * "eval()" function
+ */
+ static void
+f_eval(typval_T *argvars, typval_T *rettv)
+{
+ char_u *s, *p;
+
+ s = tv_get_string_chk(&argvars[0]);
+ if (s != NULL)
+ s = skipwhite(s);
+
+ p = s;
+ if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
+ {
+ if (p != NULL && !aborting())
+ semsg(_(e_invexpr2), p);
+ need_clr_eos = FALSE;
+ rettv->v_type = VAR_NUMBER;
+ rettv->vval.v_number = 0;
+ }
+ else if (*s != NUL)
+ emsg(_(e_trailing));
+}
+
+/*
+ * "eventhandler()" function
+ */
+ static void
+f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ rettv->vval.v_number = vgetc_busy;
+}
+
+/*
+ * "executable()" function
+ */
+ static void
+f_executable(typval_T *argvars, typval_T *rettv)
+{
+ char_u *name = tv_get_string(&argvars[0]);
+
+ /* Check in $PATH and also check directly if there is a directory name. */
+ rettv->vval.v_number = mch_can_exe(name, NULL, TRUE)
+ || (gettail(name) != name && mch_can_exe(name, NULL, FALSE));
+}
+
+static garray_T redir_execute_ga;
+
+/*
+ * Append "value[value_len]" to the execute() output.
+ */
+ void
+execute_redir_str(char_u *value, int value_len)
+{
+ int len;
+
+ if (value_len == -1)
+ len = (int)STRLEN(value); /* Append the entire string */
+ else
+ len = value_len; /* Append only "value_len" characters */
+ if (ga_grow(&redir_execute_ga, len) == OK)
+ {
+ mch_memmove((char *)redir_execute_ga.ga_data
+ + redir_execute_ga.ga_len, value, len);
+ redir_execute_ga.ga_len += len;
+ }
+}
+
+/*
+ * Get next line from a list.
+ * Called by do_cmdline() to get the next line.
+ * Returns allocated string, or NULL for end of function.
+ */
+
+ static char_u *
+get_list_line(
+ int c UNUSED,
+ void *cookie,
+ int indent UNUSED)
+{
+ listitem_T **p = (listitem_T **)cookie;
+ listitem_T *item = *p;
+ char_u buf[NUMBUFLEN];
+ char_u *s;
+
+ if (item == NULL)
+ return NULL;
+ s = tv_get_string_buf_chk(&item->li_tv, buf);
+ *p = item->li_next;
+ return s == NULL ? NULL : vim_strsave(s);
+}
+
+/*
+ * "execute()" function
+ */
+ static void
+f_execute(typval_T *argvars, typval_T *rettv)
+{
+ char_u *cmd = NULL;
+ list_T *list = NULL;
+ int save_msg_silent = msg_silent;
+ int save_emsg_silent = emsg_silent;
+ int save_emsg_noredir = emsg_noredir;
+ int save_redir_execute = redir_execute;
+ int save_redir_off = redir_off;
+ garray_T save_ga;
+ int save_msg_col = msg_col;
+ int echo_output = FALSE;
+
+ rettv->vval.v_string = NULL;
+ rettv->v_type = VAR_STRING;
+
+ if (argvars[0].v_type == VAR_LIST)
+ {
+ list = argvars[0].vval.v_list;
+ if (list == NULL || list->lv_first == NULL)
+ /* empty list, no commands, empty output */
+ return;
+ ++list->lv_refcount;
+ }
+ else
+ {
+ cmd = tv_get_string_chk(&argvars[0]);
+ if (cmd == NULL)
+ return;
+ }
+
+ if (argvars[1].v_type != VAR_UNKNOWN)
+ {
+ char_u buf[NUMBUFLEN];
+ char_u *s = tv_get_string_buf_chk(&argvars[1], buf);
+
+ if (s == NULL)
+ return;
+ if (*s == NUL)
+ echo_output = TRUE;
+ if (STRNCMP(s, "silent", 6) == 0)
+ ++msg_silent;
+ if (STRCMP(s, "silent!") == 0)
+ {
+ emsg_silent = TRUE;
+ emsg_noredir = TRUE;
+ }
+ }
+ else
+ ++msg_silent;
+
+ if (redir_execute)
+ save_ga = redir_execute_ga;
+ ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
+ redir_execute = TRUE;
+ redir_off = FALSE;
+ if (!echo_output)
+ msg_col = 0; // prevent leading spaces
+
+ if (cmd != NULL)
+ do_cmdline_cmd(cmd);
+ else
+ {
+ listitem_T *item = list->lv_first;
+
+ do_cmdline(NULL, get_list_line, (void *)&item,
+ DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
+ --list->lv_refcount;
+ }
+
+ /* Need to append a NUL to the result. */
+ if (ga_grow(&redir_execute_ga, 1) == OK)
+ {
+ ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
+ rettv->vval.v_string = redir_execute_ga.ga_data;
+ }
+ else
+ {
+ ga_clear(&redir_execute_ga);
+ rettv->vval.v_string = NULL;
+ }
+ msg_silent = save_msg_silent;
+ emsg_silent = save_emsg_silent;
+ emsg_noredir = save_emsg_noredir;
+
+ redir_execute = save_redir_execute;
+ if (redir_execute)
+ redir_execute_ga = save_ga;
+ redir_off = save_redir_off;
+
+ // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
+ if (echo_output)
+ // When not working silently: put it in column zero. A following
+ // "echon" will overwrite the message, unavoidably.
+ msg_col = 0;
+ else
+ // When working silently: Put it back where it was, since nothing
+ // should have been written.
+ msg_col = save_msg_col;
+}
+
+/*
+ * "exepath()" function
+ */
+ static void
+f_exepath(typval_T *argvars, typval_T *rettv)
+{
+ char_u *p = NULL;
+
+ (void)mch_can_exe(tv_get_string(&argvars[0]), &p, TRUE);
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = p;
+}
+
+/*
+ * "exists()" function
+ */
+ static void
+f_exists(typval_T *argvars, typval_T *rettv)
+{
+ char_u *p;
+ int n = FALSE;
+
+ p = tv_get_string(&argvars[0]);
+ if (*p == '$') /* environment variable */
+ {
+ /* first try "normal" environment variables (fast) */
+ if (mch_getenv(p + 1) != NULL)
+ n = TRUE;
+ else
+ {
+ /* try expanding things like $VIM and ${HOME} */
+ p = expand_env_save(p);
+ if (p != NULL && *p != '$')
+ n = TRUE;
+ vim_free(p);
+ }
+ }
+ else if (*p == '&' || *p == '+') /* option */
+ {
+ n = (get_option_tv(&p, NULL, TRUE) == OK);
+ if (*skipwhite(p) != NUL)
+ n = FALSE; /* trailing garbage */
+ }
+ else if (*p == '*') /* internal or user defined function */
+ {
+ n = function_exists(p + 1, FALSE);
+ }
+ else if (*p == ':')
+ {
+ n = cmd_exists(p + 1);
+ }
+ else if (*p == '#')
+ {
+ if (p[1] == '#')
+ n = autocmd_supported(p + 2);
+ else
+ n = au_exists(p + 1);
+ }
+ else /* internal variable */
+ {
+ n = var_exists(p);
+ }
+
+ rettv->vval.v_number = n;
+}
+
+#ifdef FEAT_FLOAT
+/*
+ * "exp()" function
+ */
+ static void
+f_exp(typval_T *argvars, typval_T *rettv)
+{
+ float_T f = 0.0;
+
+ rettv->v_type = VAR_FLOAT;
+ if (get_float_arg(argvars, &f) == OK)
+ rettv->vval.v_float = exp(f);
+ else
+ rettv->vval.v_float = 0.0;
+}
+#endif
+
+/*
+ * "expand()" function
+ */
+ static void
+f_expand(typval_T *argvars, typval_T *rettv)
+{
+ char_u *s;
+ int len;
+ char *errormsg;
+ int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
+ expand_T xpc;
+ int error = FALSE;
+ char_u *result;
+
+ rettv->v_type = VAR_STRING;
+ if (argvars[1].v_type != VAR_UNKNOWN
+ && argvars[2].v_type != VAR_UNKNOWN
+ && tv_get_number_chk(&argvars[2], &error)
+ && !error)
+ {
+ rettv_list_set(rettv, NULL);
+ }
+
+ s = tv_get_string(&argvars[0]);
+ if (*s == '%' || *s == '#' || *s == '<')
+ {
+ ++emsg_off;
+ result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
+ --emsg_off;
+ if (rettv->v_type == VAR_LIST)
+ {
+ if (rettv_list_alloc(rettv) != FAIL && result != NULL)
+ list_append_string(rettv->vval.v_list, result, -1);
+ else
+ vim_free(result);
+ }
+ else
+ rettv->vval.v_string = result;
+ }
+ else
+ {
+ /* When the optional second argument is non-zero, don't remove matches
+ * for 'wildignore' and don't put matches for 'suffixes' at the end. */
+ if (argvars[1].v_type != VAR_UNKNOWN
+ && tv_get_number_chk(&argvars[1], &error))
+ options |= WILD_KEEP_ALL;
+ if (!error)
+ {
+ ExpandInit(&xpc);
+ xpc.xp_context = EXPAND_FILES;
+ if (p_wic)
+ options += WILD_ICASE;
+ if (rettv->v_type == VAR_STRING)
+ rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
+ options, WILD_ALL);
+ else if (rettv_list_alloc(rettv) != FAIL)
+ {
+ int i;
+
+ ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
+ for (i = 0; i < xpc.xp_numfiles; i++)
+ list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
+ ExpandCleanup(&xpc);
+ }
+ }
+ else
+ rettv->vval.v_string = NULL;
+ }
+}
+
+/*
+ * "extend(list, list [, idx])" function
+ * "extend(dict, dict [, action])" function
+ */
+ static void
+f_extend(typval_T *argvars, typval_T *rettv)
+{
+ char_u *arg_errmsg = (char_u *)N_("extend() argument");
+
+ if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST)
+ {
+ list_T *l1, *l2;
+ listitem_T *item;
+ long before;
+ int error = FALSE;
+
+ l1 = argvars[0].vval.v_list;
+ l2 = argvars[1].vval.v_list;
+ if (l1 != NULL && !tv_check_lock(l1->lv_lock, arg_errmsg, TRUE)
+ && l2 != NULL)
+ {
+ if (argvars[2].v_type != VAR_UNKNOWN)
+ {
+ before = (long)tv_get_number_chk(&argvars[2], &error);
+ if (error)
+ return; /* type error; errmsg already given */
+
+ if (before == l1->lv_len)
+ item = NULL;
+ else
+ {
+ item = list_find(l1, before);
+ if (item == NULL)
+ {
+ semsg(_(e_listidx), before);
+ return;
+ }
+ }
+ }
+ else
+ item = NULL;
+ list_extend(l1, l2, item);
+
+ copy_tv(&argvars[0], rettv);
+ }
+ }
+ else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT)
+ {
+ dict_T *d1, *d2;
+ char_u *action;
+ int i;
+
+ d1 = argvars[0].vval.v_dict;
+ d2 = argvars[1].vval.v_dict;
+ if (d1 != NULL && !tv_check_lock(d1->dv_lock, arg_errmsg, TRUE)
+ && d2 != NULL)
+ {
+ /* Check the third argument. */
+ if (argvars[2].v_type != VAR_UNKNOWN)
+ {
+ static char *(av[]) = {"keep", "force", "error"};
+
+ action = tv_get_string_chk(&argvars[2]);
+ if (action == NULL)
+ return; /* type error; errmsg already given */
+ for (i = 0; i < 3; ++i)
+ if (STRCMP(action, av[i]) == 0)
+ break;
+ if (i == 3)
+ {
+ semsg(_(e_invarg2), action);
+ return;
+ }
+ }
+ else
+ action = (char_u *)"force";
+
+ dict_extend(d1, d2, action);
+
+ copy_tv(&argvars[0], rettv);
+ }
+ }
+ else
+ semsg(_(e_listdictarg), "extend()");
+}
+
+/*
+ * "feedkeys()" function
+ */
+ static void
+f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
+{
+ int remap = TRUE;
+ int insert = FALSE;
+ char_u *keys, *flags;
+ char_u nbuf[NUMBUFLEN];
+ int typed = FALSE;
+ int execute = FALSE;
+ int dangerous = FALSE;
+ int lowlevel = FALSE;
+ char_u *keys_esc;
+
+ /* This is not allowed in the sandbox. If the commands would still be
+ * executed in the sandbox it would be OK, but it probably happens later,
+ * when "sandbox" is no longer set. */
+ if (check_secure())
+ return;
+
+ keys = tv_get_string(&argvars[0]);
+
+ if (argvars[1].v_type != VAR_UNKNOWN)
+ {
+ flags = tv_get_string_buf(&argvars[1], nbuf);
+ for ( ; *flags != NUL; ++flags)
+ {
+ switch (*flags)
+ {
+ case 'n': remap = FALSE; break;
+ case 'm': remap = TRUE; break;
+ case 't': typed = TRUE; break;
+ case 'i': insert = TRUE; break;
+ case 'x': execute = TRUE; break;
+ case '!': dangerous = TRUE; break;
+ case 'L': lowlevel = TRUE; break;
+ }
+ }
+ }
+
+ if (*keys != NUL || execute)
+ {
+ /* Need to escape K_SPECIAL and CSI before putting the string in the
+ * typeahead buffer. */
+ keys_esc = vim_strsave_escape_csi(keys);
+ if (keys_esc != NULL)
+ {
+ if (lowlevel)
+ {
+#ifdef USE_INPUT_BUF
+ add_to_input_buf(keys, (int)STRLEN(keys));
+#else
+ emsg(_("E980: lowlevel input not supported"));
+#endif
+ }
+ else
+ {
+ ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
+ insert ? 0 : typebuf.tb_len, !typed, FALSE);
+ if (vgetc_busy
+#ifdef FEAT_TIMERS
+ || timer_busy
+#endif
+ )
+ typebuf_was_filled = TRUE;
+ }
+ vim_free(keys_esc);
+
+ if (execute)
+ {
+ int save_msg_scroll = msg_scroll;
+
+ /* Avoid a 1 second delay when the keys start Insert mode. */
+ msg_scroll = FALSE;
+
+ if (!dangerous)
+ ++ex_normal_busy;
+ exec_normal(TRUE, FALSE, TRUE);
+ if (!dangerous)
+ --ex_normal_busy;
+
+ msg_scroll |= save_msg_scroll;
+ }
+ }
+ }
+}
+
+/*
+ * "filereadable()" function
+ */
+ static void
+f_filereadable(typval_T *argvars, typval_T *rettv)
+{
+ int fd;
+ char_u *p;
+ int n;
+
+#ifndef O_NONBLOCK
+# define O_NONBLOCK 0
+#endif
+ p = tv_get_string(&argvars[0]);
+ if (*p && !mch_isdir(p) && (fd = mch_open((char *)p,
+ O_RDONLY | O_NONBLOCK, 0)) >= 0)
+ {
+ n = TRUE;
+ close(fd);
+ }
+ else
+ n = FALSE;
+
+ rettv->vval.v_number = n;
+}
+
+/*
+ * Return 0 for not writable, 1 for writable file, 2 for a dir which we have
+ * rights to write into.
+ */
+ static void
+f_filewritable(typval_T *argvars, typval_T *rettv)
+{
+ rettv->vval.v_number = filewritable(tv_get_string(&argvars[0]));
+}
+
+ static void
+findfilendir(
+ typval_T *argvars UNUSED,
+ typval_T *rettv,
+ int find_what UNUSED)
+{
+#ifdef FEAT_SEARCHPATH
+ char_u *fname;
+ char_u *fresult = NULL;
+ char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
+ char_u *p;
+ char_u pathbuf[NUMBUFLEN];
+ int count = 1;
+ int first = TRUE;
+ int error = FALSE;
+#endif
+
+ rettv->vval.v_string = NULL;
+ rettv->v_type = VAR_STRING;
+
+#ifdef FEAT_SEARCHPATH
+ fname = tv_get_string(&argvars[0]);
+
+ if (argvars[1].v_type != VAR_UNKNOWN)
+ {
+ p = tv_get_string_buf_chk(&argvars[1], pathbuf);
+ if (p == NULL)
+ error = TRUE;
+ else
+ {
+ if (*p != NUL)
+ path = p;
+
+ if (argvars[2].v_type != VAR_UNKNOWN)
+ count = (int)tv_get_number_chk(&argvars[2], &error);
+ }
+ }
+
+ if (count < 0 && rettv_list_alloc(rettv) == FAIL)
+ error = TRUE;
+
+ if (*fname != NUL && !error)
+ {
+ do
+ {
+ if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST)
+ vim_free(fresult);
+ fresult = find_file_in_path_option(first ? fname : NULL,
+ first ? (int)STRLEN(fname) : 0,
+ 0, first, path,
+ find_what,
+ curbuf->b_ffname,
+ find_what == FINDFILE_DIR
+ ? (char_u *)"" : curbuf->b_p_sua);
+ first = FALSE;
+
+ if (fresult != NULL && rettv->v_type == VAR_LIST)
+ list_append_string(rettv->vval.v_list, fresult, -1);
+
+ } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL);
+ }
+
+ if (rettv->v_type == VAR_STRING)
+ rettv->vval.v_string = fresult;
+#endif
+}
+
+/*
+ * "filter()" function
+ */
+ static void
+f_filter(typval_T *argvars, typval_T *rettv)
+{
+ filter_map(argvars, rettv, FALSE);
+}
+
+/*
+ * "finddir({fname}[, {path}[, {count}]])" function
+ */
+ static void
+f_finddir(typval_T *argvars, typval_T *rettv)
+{
+ findfilendir(argvars, rettv, FINDFILE_DIR);
+}
+
+/*
+ * "findfile({fname}[, {path}[, {count}]])" function
+ */
+ static void
+f_findfile(typval_T *argvars, typval_T *rettv)
+{
+ findfilendir(argvars, rettv, FINDFILE_FILE);
+}
+
+#ifdef FEAT_FLOAT
+/*
+ * "float2nr({float})" function
+ */
+ static void
+f_float2nr(typval_T *argvars, typval_T *rettv)
+{
+ float_T f = 0.0;
+
+ if (get_float_arg(argvars, &f) == OK)
+ {
+ if (f <= -VARNUM_MAX + DBL_EPSILON)
+ rettv->vval.v_number = -VARNUM_MAX;
+ else if (f >= VARNUM_MAX - DBL_EPSILON)
+ rettv->vval.v_number = VARNUM_MAX;
+ else
+ rettv->vval.v_number = (varnumber_T)f;
+ }
+}
+
+/*
+ * "floor({float})" function
+ */
+ static void
+f_floor(typval_T *argvars, typval_T *rettv)
+{
+ float_T f = 0.0;
+
+ rettv->v_type = VAR_FLOAT;
+ if (get_float_arg(argvars, &f) == OK)
+ rettv->vval.v_float = floor(f);
+ else
+ rettv->vval.v_float = 0.0;
+}
+
+/*
+ * "fmod()" function
+ */
+ static void
+f_fmod(typval_T *argvars, typval_T *rettv)
+{
+ float_T fx = 0.0, fy = 0.0;
+
+ rettv->v_type = VAR_FLOAT;
+ if (get_float_arg(argvars, &fx) == OK
+ && get_float_arg(&argvars[1], &fy) == OK)
+ rettv->vval.v_float = fmod(fx, fy);
+ else
+ rettv->vval.v_float = 0.0;
+}
+#endif
+
+/*
+ * "fnameescape({string})" function
+ */
+ static void
+f_fnameescape(typval_T *argvars, typval_T *rettv)
+{
+ rettv->vval.v_string = vim_strsave_fnameescape(
+ tv_get_string(&argvars[0]), FALSE);
+ rettv->v_type = VAR_STRING;
+}
+
+/*
+ * "fnamemodify({fname}, {mods})" function
+ */
+ static void
+f_fnamemodify(typval_T *argvars, typval_T *rettv)
+{
+ char_u *fname;
+ char_u *mods;
+ int usedlen = 0;
+ int len;
+ char_u *fbuf = NULL;
+ char_u buf[NUMBUFLEN];
+
+ fname = tv_get_string_chk(&argvars[0]);
+ mods = tv_get_string_buf_chk(&argvars[1], buf);
+ if (fname == NULL || mods == NULL)
+ fname = NULL;
+ else
+ {
+ len = (int)STRLEN(fname);
+ (void)modify_fname(mods, FALSE, &usedlen, &fname, &fbuf, &len);
+ }
+
+ rettv->v_type = VAR_STRING;
+ if (fname == NULL)
+ rettv->vval.v_string = NULL;
+ else
+ rettv->vval.v_string = vim_strnsave(fname, len);
+ vim_free(fbuf);
+}
+
+/*
+ * "foldclosed()" function
+ */
+ static void
+foldclosed_both(
+ typval_T *argvars UNUSED,
+ typval_T *rettv,
+ int end UNUSED)
+{
+#ifdef FEAT_FOLDING
+ linenr_T lnum;
+ linenr_T first, last;
+
+ lnum = tv_get_lnum(argvars);
+ if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
+ {
+ if (hasFoldingWin(curwin, lnum, &first, &last, FALSE, NULL))
+ {
+ if (end)
+ rettv->vval.v_number = (varnumber_T)last;
+ else
+ rettv->vval.v_number = (varnumber_T)first;
+ return;
+ }
+ }
+#endif
+ rettv->vval.v_number = -1;
+}
+
+/*
+ * "foldclosed()" function
+ */
+ static void
+f_foldclosed(typval_T *argvars, typval_T *rettv)
+{
+ foldclosed_both(argvars, rettv, FALSE);
+}
+
+/*
+ * "foldclosedend()" function
+ */
+ static void
+f_foldclosedend(typval_T *argvars, typval_T *rettv)
+{
+ foldclosed_both(argvars, rettv, TRUE);
+}
+
+/*
+ * "foldlevel()" function
+ */
+ static void
+f_foldlevel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
+{
+#ifdef FEAT_FOLDING
+ linenr_T lnum;
+
+ lnum = tv_get_lnum(argvars);
+ if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
+ rettv->vval.v_number = foldLevel(lnum);
+#endif
+}
+
+/*
+ * "foldtext()" function
+ */
+ static void
+f_foldtext(typval_T *argvars UNUSED, typval_T *rettv)
+{
+#ifdef FEAT_FOLDING
+ linenr_T foldstart;
+ linenr_T foldend;
+ char_u *dashes;
+ linenr_T lnum;
+ char_u *s;
+ char_u *r;
+ int len;
+ char *txt;
+ long count;
+#endif
+
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+#ifdef FEAT_FOLDING
+ foldstart = (linenr_T)get_vim_var_nr(VV_FOLDSTART);
+ foldend = (linenr_T)get_vim_var_nr(VV_FOLDEND);
+ dashes = get_vim_var_str(VV_FOLDDASHES);
+ if (foldstart > 0 && foldend <= curbuf->b_ml.ml_line_count
+ && dashes != NULL)
+ {
+ /* Find first non-empty line in the fold. */
+ for (lnum = foldstart; lnum < foldend; ++lnum)
+ if (!linewhite(lnum))
+ break;
+
+ /* Find interesting text in this line. */
+ s = skipwhite(ml_get(lnum));
+ /* skip C comment-start */
+ if (s[0] == '/' && (s[1] == '*' || s[1] == '/'))
+ {
+ s = skipwhite(s + 2);
+ if (*skipwhite(s) == NUL
+ && lnum + 1 < (linenr_T)get_vim_var_nr(VV_FOLDEND))
+ {
+ s = skipwhite(ml_get(lnum + 1));
+ if (*s == '*')
+ s = skipwhite(s + 1);
+ }
+ }
+ count = (long)(foldend - foldstart + 1);
+ txt = NGETTEXT("+-%s%3ld line: ", "+-%s%3ld lines: ", count);
+ r = alloc((unsigned)(STRLEN(txt)
+ + STRLEN(dashes) /* for %s */
+ + 20 /* for %3ld */
+ + STRLEN(s))); /* concatenated */
+ if (r != NULL)
+ {
+ sprintf((char *)r, txt, dashes, count);
+ len = (int)STRLEN(r);
+ STRCAT(r, s);
+ /* remove 'foldmarker' and 'commentstring' */
+ foldtext_cleanup(r + len);
+ rettv->vval.v_string = r;
+ }
+ }
+#endif
+}
+
+/*
+ * "foldtextresult(lnum)" function
+ */
+ static void
+f_foldtextresult(typval_T *argvars UNUSED, typval_T *rettv)
+{
+#ifdef FEAT_FOLDING
+ linenr_T lnum;
+ char_u *text;
+ char_u buf[FOLD_TEXT_LEN];
+ foldinfo_T foldinfo;
+ int fold_count;
+ static int entered = FALSE;
+#endif
+
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+#ifdef FEAT_FOLDING
+ if (entered)
+ return; /* reject recursive use */
+ entered = TRUE;
+
+ lnum = tv_get_lnum(argvars);
+ /* treat illegal types and illegal string values for {lnum} the same */
+ if (lnum < 0)
+ lnum = 0;
+ fold_count = foldedCount(curwin, lnum, &foldinfo);
+ if (fold_count > 0)
+ {
+ text = get_foldtext(curwin, lnum, lnum + fold_count - 1,
+ &foldinfo, buf);
+ if (text == buf)
+ text = vim_strsave(text);
+ rettv->vval.v_string = text;
+ }
+
+ entered = FALSE;
+#endif
+}
+
+/*
+ * "foreground()" function
+ */
+ static void
+f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
+{
+#ifdef FEAT_GUI
+ if (gui.in_use)
+ gui_mch_set_foreground();
+#else
+# ifdef WIN32
+ win32_set_foreground();
+# endif
+#endif
+}
+
+ static void
+common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
+{
+ char_u *s;
+ char_u *name;
+ int use_string = FALSE;
+ partial_T *arg_pt = NULL;
+ char_u *trans_name = NULL;
+
+ if (argvars[0].v_type == VAR_FUNC)
+ {
+ /* function(MyFunc, [arg], dict) */
+ s = argvars[0].vval.v_string;
+ }
+ else if (argvars[0].v_type == VAR_PARTIAL
+ && argvars[0].vval.v_partial != NULL)
+ {
+ /* function(dict.MyFunc, [arg]) */
+ arg_pt = argvars[0].vval.v_partial;
+ s = partial_name(arg_pt);
+ }
+ else
+ {
+ /* function('MyFunc', [arg], dict) */
+ s = tv_get_string(&argvars[0]);
+ use_string = TRUE;
+ }
+
+ if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
+ {
+ name = s;
+ trans_name = trans_function_name(&name, FALSE,
+ TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
+ if (*name != NUL)
+ s = NULL;
+ }
+
+ if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
+ || (is_funcref && trans_name == NULL))
+ semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
+ /* Don't check an autoload name for existence here. */
+ else if (trans_name != NULL && (is_funcref
+ ? find_func(trans_name) == NULL
+ : !translated_function_exists(trans_name)))
+ semsg(_("E700: Unknown function: %s"), s);
+ else
+ {
+ int dict_idx = 0;
+ int arg_idx = 0;
+ list_T *list = NULL;
+
+ if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
+ {
+ char sid_buf[25];
+ int off = *s == 's' ? 2 : 5;
+
+ /* Expand s: and <SID> into <SNR>nr_, so that the function can
+ * also be called from another script. Using trans_function_name()
+ * would also work, but some plugins depend on the name being
+ * printable text. */
+ sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
+ name = alloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1));
+ if (name != NULL)
+ {
+ STRCPY(name, sid_buf);
+ STRCAT(name, s + off);
+ }
+ }
+ else
+ name = vim_strsave(s);
+
+ if (argvars[1].v_type != VAR_UNKNOWN)
+ {
+ if (argvars[2].v_type != VAR_UNKNOWN)
+ {
+ /* function(name, [args], dict) */
+ arg_idx = 1;
+ dict_idx = 2;
+ }
+ else if (argvars[1].v_type == VAR_DICT)
+ /* function(name, dict) */
+ dict_idx = 1;
+ else
+ /* function(name, [args]) */
+ arg_idx = 1;
+ if (dict_idx > 0)
+ {
+ if (argvars[dict_idx].v_type != VAR_DICT)
+ {
+ emsg(_("E922: expected a dict"));
+ vim_free(name);
+ goto theend;
+ }
+ if (argvars[dict_idx].vval.v_dict == NULL)
+ dict_idx = 0;
+ }
+ if (arg_idx > 0)
+ {
+ if (argvars[arg_idx].v_type != VAR_LIST)
+ {
+ emsg(_("E923: Second argument of function() must be a list or a dict"));
+ vim_free(name);
+ goto theend;
+ }
+ list = argvars[arg_idx].vval.v_list;
+ if (list == NULL || list->lv_len == 0)
+ arg_idx = 0;
+ }
+ }
+ if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
+ {
+ partial_T *pt = (partial_T *)alloc_clear(sizeof(partial_T));
+
+ /* result is a VAR_PARTIAL */
+ if (pt == NULL)
+ vim_free(name);
+ else
+ {
+ if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
+ {
+ listitem_T *li;
+ int i = 0;
+ int arg_len = 0;
+ int lv_len = 0;
+
+ if (arg_pt != NULL)
+ arg_len = arg_pt->pt_argc;
+ if (list != NULL)
+ lv_len = list->lv_len;
+ pt->pt_argc = arg_len + lv_len;
+ pt->pt_argv = (typval_T *)alloc(
+ sizeof(typval_T) * pt->pt_argc);
+ if (pt->pt_argv == NULL)
+ {
+ vim_free(pt);
+ vim_free(name);
+ goto theend;
+ }
+ for (i = 0; i < arg_len; i++)
+ copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
+ if (lv_len > 0)
+ for (li = list->lv_first; li != NULL;
+ li = li->li_next)
+ copy_tv(&li->li_tv, &pt->pt_argv[i++]);
+ }
+
+ /* For "function(dict.func, [], dict)" and "func" is a partial
+ * use "dict". That is backwards compatible. */
+ if (dict_idx > 0)
+ {
+ /* The dict is bound explicitly, pt_auto is FALSE. */
+ pt->pt_dict = argvars[dict_idx].vval.v_dict;
+ ++pt->pt_dict->dv_refcount;
+ }
+ else if (arg_pt != NULL)
+ {
+ /* If the dict was bound automatically the result is also
+ * bound automatically. */
+ pt->pt_dict = arg_pt->pt_dict;
+ pt->pt_auto = arg_pt->pt_auto;
+ if (pt->pt_dict != NULL)
+ ++pt->pt_dict->dv_refcount;
+ }
+
+ pt->pt_refcount = 1;
+ if (arg_pt != NULL && arg_pt->pt_func != NULL)
+ {
+ pt->pt_func = arg_pt->pt_func;
+ func_ptr_ref(pt->pt_func);
+ vim_free(name);
+ }
+ else if (is_funcref)
+ {
+ pt->pt_func = find_func(trans_name);
+ func_ptr_ref(pt->pt_func);
+ vim_free(name);
+ }
+ else
+ {
+ pt->pt_name = name;
+ func_ref(name);
+ }
+ }
+ rettv->v_type = VAR_PARTIAL;
+ rettv->vval.v_partial = pt;
+ }
+ else
+ {
+ /* result is a VAR_FUNC */
+ rettv->v_type = VAR_FUNC;
+ rettv->vval.v_string = name;
+ func_ref(name);
+ }
+ }
+theend:
+ vim_free(trans_name);
+}
+
+/*
+ * "funcref()" function
+ */
+ static void
+f_funcref(typval_T *argvars, typval_T *rettv)
+{
+ common_function(argvars, rettv, TRUE);
+}
+
+/*
+ * "function()" function
+ */
+ static void
+f_function(typval_T *argvars, typval_T *rettv)
+{
+ common_function(argvars, rettv, FALSE);
+}
+
+/*
+ * "garbagecollect()" function
+ */
+ static void
+f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
+{
+ /* This is postponed until we are back at the toplevel, because we may be
+ * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
+ want_garbage_collect = TRUE;
+
+ if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
+ garbage_collect_at_exit = TRUE;
+}
+
+/*
+ * "get()" function
+ */
+ static void
+f_get(typval_T *argvars, typval_T *rettv)
+{
+ listitem_T *li;
+ list_T *l;
+ dictitem_T *di;
+ dict_T *d;
+ typval_T *tv = NULL;
+
+ if (argvars[0].v_type == VAR_BLOB)
+ {
+ int error = FALSE;
+ int idx = tv_get_number_chk(&argvars[1], &error);
+
+ if (!error)
+ {
+ rettv->v_type = VAR_NUMBER;
+ if (idx < 0)
+ idx = blob_len(argvars[0].vval.v_blob) + idx;
+ if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
+ rettv->vval.v_number = -1;
+ else
+ {
+ rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
+ tv = rettv;
+ }
+ }
+ }
+ else if (argvars[0].v_type == VAR_LIST)
+ {
+ if ((l = argvars[0].vval.v_list) != NULL)
+ {
+ int error = FALSE;
+
+ li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
+ if (!error && li != NULL)
+ tv = &li->li_tv;
+ }
+ }
+ else if (argvars[0].v_type == VAR_DICT)
+ {
+ if ((d = argvars[0].vval.v_dict) != NULL)
+ {
+ di = dict_find(d, tv_get_string(&argvars[1]), -1);
+ if (di != NULL)
+ tv = &di->di_tv;
+ }
+ }
+ else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
+ {
+ partial_T *pt;
+ partial_T fref_pt;
+
+ if (argvars[0].v_type == VAR_PARTIAL)
+ pt = argvars[0].vval.v_partial;
+ else
+ {
+ vim_memset(&fref_pt, 0, sizeof(fref_pt));
+ fref_pt.pt_name = argvars[0].vval.v_string;
+ pt = &fref_pt;
+ }
+
+ if (pt != NULL)
+ {
+ char_u *what = tv_get_string(&argvars[1]);
+ char_u *n;
+
+ if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
+ {
+ rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
+ n = partial_name(pt);
+ if (n == NULL)
+ rettv->vval.v_string = NULL;
+ else
+ {
+ rettv->vval.v_string = vim_strsave(n);
+ if (rettv->v_type == VAR_FUNC)
+ func_ref(rettv->vval.v_string);
+ }
+ }
+ else if (STRCMP(what, "dict") == 0)
+ rettv_dict_set(rettv, pt->pt_dict);
+ else if (STRCMP(what, "args") == 0)
+ {
+ rettv->v_type = VAR_LIST;
+ if (rettv_list_alloc(rettv) == OK)
+ {
+ int i;
+
+ for (i = 0; i < pt->pt_argc; ++i)
+ list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
+ }
+ }
+ else
+ semsg(_(e_invarg2), what);
+ return;
+ }
+ }
+ else
+ semsg(_(e_listdictblobarg), "get()");
+
+ if (tv == NULL)
+ {
+ if (argvars[2].v_type != VAR_UNKNOWN)
+ copy_tv(&argvars[2], rettv);
+ }
+ else
+ copy_tv(tv, rettv);
+}
+
+/*
+ * Returns buffer options, variables and other attributes in a dictionary.
+ */
+ static dict_T *
+get_buffer_info(buf_T *buf)
+{
+ dict_T *dict;
+ tabpage_T *tp;
+ win_T *wp;
+ list_T *windows;
+
+ dict = dict_alloc();
+ if (dict == NULL)
+ return NULL;
+
+ dict_add_number(dict, "bufnr", buf->b_fnum);
+ dict_add_string(dict, "name", buf->b_ffname);
+ dict_add_number(dict, "lnum", buf == curbuf ? curwin->w_cursor.lnum
+ : buflist_findlnum(buf));
+ dict_add_number(dict, "loaded", buf->b_ml.ml_mfp != NULL);
+ dict_add_number(dict, "listed", buf->b_p_bl);
+ dict_add_number(dict, "changed", bufIsChanged(buf));
+ dict_add_number(dict, "changedtick", CHANGEDTICK(buf));
+ dict_add_number(dict, "hidden",
+ buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0);
+
+ /* Get a reference to buffer variables */
+ dict_add_dict(dict, "variables", buf->b_vars);
+
+ /* List of windows displaying this buffer */
+ windows = list_alloc();
+ if (windows != NULL)
+ {
+ FOR_ALL_TAB_WINDOWS(tp, wp)
+ if (wp->w_buffer == buf)
+ list_append_number(windows, (varnumber_T)wp->w_id);
+ dict_add_list(dict, "windows", windows);
+ }
+
+#ifdef FEAT_SIGNS
+ if (buf->b_signlist != NULL)
+ {
+ /* List of signs placed in this buffer */
+ list_T *signs = list_alloc();
+ if (signs != NULL)
+ {
+ get_buffer_signs(buf, signs);
+ dict_add_list(dict, "signs", signs);
+ }
+ }
+#endif
+
+ return dict;
+}
+
+/*
+ * "getbufinfo()" function
+ */
+ static void
+f_getbufinfo(typval_T *argvars, typval_T *rettv)
+{
+ buf_T *buf = NULL;
+ buf_T *argbuf = NULL;
+ dict_T *d;
+ int filtered = FALSE;
+ int sel_buflisted = FALSE;
+ int sel_bufloaded = FALSE;
+ int sel_bufmodified = FALSE;
+
+ if (rettv_list_alloc(rettv) != OK)
+ return;
+
+ /* List of all the buffers or selected buffers */
+ if (argvars[0].v_type == VAR_DICT)
+ {
+ dict_T *sel_d = argvars[0].vval.v_dict;
+
+ if (sel_d != NULL)
+ {
+ dictitem_T *di;
+
+ filtered = TRUE;
+
+ di = dict_find(sel_d, (char_u *)"buflisted", -1);
+ if (di != NULL && tv_get_number(&di->di_tv))
+ sel_buflisted = TRUE;
+
+ di = dict_find(sel_d, (char_u *)"bufloaded", -1);
+ if (di != NULL && tv_get_number(&di->di_tv))
+ sel_bufloaded = TRUE;
+
+ di = dict_find(sel_d, (char_u *)"bufmodified", -1);
+ if (di != NULL && tv_get_number(&di->di_tv))
+ sel_bufmodified = TRUE;
+ }
+ }
+ else if (argvars[0].v_type != VAR_UNKNOWN)
+ {
+ /* Information about one buffer. Argument specifies the buffer */
+ (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
+ ++emsg_off;
+ argbuf = tv_get_buf(&argvars[0], FALSE);
+ --emsg_off;
+ if (argbuf == NULL)
+ return;
+ }
+
+ /* Return information about all the buffers or a specified buffer */
+ FOR_ALL_BUFFERS(buf)
+ {
+ if (argbuf != NULL && argbuf != buf)
+ continue;
+ if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
+ || (sel_buflisted && !buf->b_p_bl)
+ || (sel_bufmodified && !buf->b_changed)))
+ continue;
+
+ d = get_buffer_info(buf);
+ if (d != NULL)
+ list_append_dict(rettv->vval.v_list, d);
+ if (argbuf != NULL)
+ return;
+ }
+}
+
+/*
+ * Get line or list of lines from buffer "buf" into "rettv".
+ * Return a range (from start to end) of lines in rettv from the specified
+ * buffer.
+ * If 'retlist' is TRUE, then the lines are returned as a Vim List.
+ */
+ static void
+get_buffer_lines(
+ buf_T *buf,
+ linenr_T start,
+ linenr_T end,
+ int retlist,
+ typval_T *rettv)
+{
+ char_u *p;
+
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+ if (retlist && rettv_list_alloc(rettv) == FAIL)
+ return;
+
+ if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0)
+ return;
+
+ if (!retlist)
+ {
+ if (start >= 1 && start <= buf->b_ml.ml_line_count)
+ p = ml_get_buf(buf, start, FALSE);
+ else
+ p = (char_u *)"";
+ rettv->vval.v_string = vim_strsave(p);
+ }
+ else
+ {
+ if (end < start)
+ return;
+
+ if (start < 1)
+ start = 1;
+ if (end > buf->b_ml.ml_line_count)
+ end = buf->b_ml.ml_line_count;
+ while (start <= end)
+ if (list_append_string(rettv->vval.v_list,
+ ml_get_buf(buf, start++, FALSE), -1) == FAIL)
+ break;
+ }
+}
+
+/*
+ * "getbufline()" function
+ */
+ static void
+f_getbufline(typval_T *argvars, typval_T *rettv)
+{
+ linenr_T lnum;
+ linenr_T end;
+ buf_T *buf;
+
+ (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
+ ++emsg_off;
+ buf = tv_get_buf(&argvars[0], FALSE);
+ --emsg_off;
+
+ lnum = tv_get_lnum_buf(&argvars[1], buf);
+ if (argvars[2].v_type == VAR_UNKNOWN)
+ end = lnum;
+ else
+ end = tv_get_lnum_buf(&argvars[2], buf);
+
+ get_buffer_lines(buf, lnum, end, TRUE, rettv);
+}
+
+/*
+ * "getbufvar()" function
+ */
+ static void
+f_getbufvar(typval_T *argvars, typval_T *rettv)
+{
+ buf_T *buf;
+ buf_T *save_curbuf;
+ char_u *varname;
+ dictitem_T *v;
+ int done = FALSE;
+
+ (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
+ varname = tv_get_string_chk(&argvars[1]);
+ ++emsg_off;
+ buf = tv_get_buf(&argvars[0], FALSE);
+
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+
+ if (buf != NULL && varname != NULL)
+ {
+ /* set curbuf to be our buf, temporarily */
+ save_curbuf = curbuf;
+ curbuf = buf;
+
+ if (*varname == '&')
+ {
+ if (varname[1] == NUL)
+ {
+ /* get all buffer-local options in a dict */
+ dict_T *opts = get_winbuf_options(TRUE);
+
+ if (opts != NULL)
+ {
+ rettv_dict_set(rettv, opts);
+ done = TRUE;
+ }
+ }
+ else if (get_option_tv(&varname, rettv, TRUE) == OK)
+ /* buffer-local-option */
+ done = TRUE;
+ }
+ else
+ {
+ /* Look up the variable. */
+ /* Let getbufvar({nr}, "") return the "b:" dictionary. */
+ v = find_var_in_ht(&curbuf->b_vars->dv_hashtab,
+ 'b', varname, FALSE);
+ if (v != NULL)
+ {
+ copy_tv(&v->di_tv, rettv);
+ done = TRUE;
+ }
+ }
+
+ /* restore previous notion of curbuf */
+ curbuf = save_curbuf;
+ }
+
+ if (!done && argvars[2].v_type != VAR_UNKNOWN)
+ /* use the default value */
+ copy_tv(&argvars[2], rettv);
+
+ --emsg_off;
+}
+
+/*
+ * "getchangelist()" function
+ */
+ static void
+f_getchangelist(typval_T *argvars, typval_T *rettv)
+{
+#ifdef FEAT_JUMPLIST
+ buf_T *buf;
+ int i;
+ list_T *l;
+ dict_T *d;
+#endif
+
+ if (rettv_list_alloc(rettv) != OK)
+ return;
+
+#ifdef FEAT_JUMPLIST
+ (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
+ ++emsg_off;
+ buf = tv_get_buf(&argvars[0], FALSE);
+ --emsg_off;
+ if (buf == NULL)
+ return;
+
+ l = list_alloc();
+ if (l == NULL)
+ return;
+
+ if (list_append_list(rettv->vval.v_list, l) == FAIL)
+ return;
+ /*
+ * The current window change list index tracks only the position in the
+ * current buffer change list. For other buffers, use the change list
+ * length as the current index.
+ */
+ list_append_number(rettv->vval.v_list,
+ (varnumber_T)((buf == curwin->w_buffer)
+ ? curwin->w_changelistidx : buf->b_changelistlen));
+
+ for (i = 0; i < buf->b_changelistlen; ++i)
+ {
+ if (buf->b_changelist[i].lnum == 0)
+ continue;
+ if ((d = dict_alloc()) == NULL)
+ return;
+ if (list_append_dict(l, d) == FAIL)
+ return;
+ dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
+ dict_add_number(d, "col", (long)buf->b_changelist[i].col);
+ dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
+ }
+#endif
+}
+/*
+ * "getchar()" function
+ */
+ static void
+f_getchar(typval_T *argvars, typval_T *rettv)
+{
+ varnumber_T n;
+ int error = FALSE;
+
+#ifdef MESSAGE_QUEUE
+ // vpeekc() used to check for messages, but that caused problems, invoking
+ // a callback where it was not expected. Some plugins use getchar(1) in a
+ // loop to await a message, therefore make sure we check for messages here.
+ parse_queued_messages();
+#endif
+
+ /* Position the cursor. Needed after a message that ends in a space. */
+ windgoto(msg_row, msg_col);
+
+ ++no_mapping;
+ ++allow_keys;
+ for (;;)
+ {
+ if (argvars[0].v_type == VAR_UNKNOWN)
+ /* getchar(): blocking wait. */
+ n = plain_vgetc();
+ else if (tv_get_number_chk(&argvars[0], &error) == 1)
+ /* getchar(1): only check if char avail */
+ n = vpeekc_any();
+ else if (error || vpeekc_any() == NUL)
+ /* illegal argument or getchar(0) and no char avail: return zero */
+ n = 0;
+ else
+ /* getchar(0) and char avail: return char */
+ n = plain_vgetc();
+
+ if (n == K_IGNORE)
+ continue;
+ break;
+ }
+ --no_mapping;
+ --allow_keys;
+
+ set_vim_var_nr(VV_MOUSE_WIN, 0);
+ set_vim_var_nr(VV_MOUSE_WINID, 0);
+ set_vim_var_nr(VV_MOUSE_LNUM, 0);
+ set_vim_var_nr(VV_MOUSE_COL, 0);
+
+ rettv->vval.v_number = n;
+ if (IS_SPECIAL(n) || mod_mask != 0)
+ {
+ char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */
+ int i = 0;
+
+ /* Turn a special key into three bytes, plus modifier. */
+ if (mod_mask != 0)
+ {
+ temp[i++] = K_SPECIAL;
+ temp[i++] = KS_MODIFIER;
+ temp[i++] = mod_mask;
+ }
+ if (IS_SPECIAL(n))
+ {
+ temp[i++] = K_SPECIAL;
+ temp[i++] = K_SECOND(n);
+ temp[i++] = K_THIRD(n);
+ }
+ else if (has_mbyte)
+ i += (*mb_char2bytes)(n, temp + i);
+ else
+ temp[i++] = n;
+ temp[i++] = NUL;
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = vim_strsave(temp);
+
+#ifdef FEAT_MOUSE
+ if (is_mouse_key(n))
+ {
+ int row = mouse_row;
+ int col = mouse_col;
+ win_T *win;
+ linenr_T lnum;
+ win_T *wp;
+ int winnr = 1;
+
+ if (row >= 0 && col >= 0)
+ {
+ /* Find the window at the mouse coordinates and compute the
+ * text position. */
+ win = mouse_find_win(&row, &col);
+ if (win == NULL)
+ return;
+ (void)mouse_comp_pos(win, &row, &col, &lnum);
+ for (wp = firstwin; wp != win; wp = wp->w_next)
+ ++winnr;
+ set_vim_var_nr(VV_MOUSE_WIN, winnr);
+ set_vim_var_nr(VV_MOUSE_WINID, win->w_id);
+ set_vim_var_nr(VV_MOUSE_LNUM, lnum);
+ set_vim_var_nr(VV_MOUSE_COL, col + 1);
+ }
+ }
+#endif
+ }
+}
+
+/*
+ * "getcharmod()" function
+ */
+ static void
+f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ rettv->vval.v_number = mod_mask;
+}
+
+/*
+ * "getcharsearch()" function
+ */
+ static void
+f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ if (rettv_dict_alloc(rettv) != FAIL)
+ {
+ dict_T *dict = rettv->vval.v_dict;
+
+ dict_add_string(dict, "char", last_csearch());
+ dict_add_number(dict, "forward", last_csearch_forward());
+ dict_add_number(dict, "until", last_csearch_until());
+ }
+}
+
+/*
+ * "getcmdline()" function
+ */
+ static void
+f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = get_cmdline_str();
+}
+
+/*
+ * "getcmdpos()" function
+ */
+ static void
+f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ rettv->vval.v_number = get_cmdline_pos() + 1;
+}
+
+/*
+ * "getcmdtype()" function
+ */
+ static void
+f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = alloc(2);
+ if (rettv->vval.v_string != NULL)
+ {
+ rettv->vval.v_string[0] = get_cmdline_type();
+ rettv->vval.v_string[1] = NUL;
+ }
+}
+
+/*
+ * "getcmdwintype()" function
+ */
+ static void
+f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+#ifdef FEAT_CMDWIN
+ rettv->vval.v_string = alloc(2);
+ if (rettv->vval.v_string != NULL)
+ {
+ rettv->vval.v_string[0] = cmdwin_type;
+ rettv->vval.v_string[1] = NUL;
+ }
+#endif
+}
+
+#if defined(FEAT_CMDL_COMPL)
+/*
+ * "getcompletion()" function
+ */
+ static void
+f_getcompletion(typval_T *argvars, typval_T *rettv)
+{
+ char_u *pat;
+ expand_T xpc;
+ int filtered = FALSE;
+ int options = WILD_SILENT | WILD_USE_NL | WILD_ADD_SLASH
+ | WILD_NO_BEEP;
+
+ if (argvars[2].v_type != VAR_UNKNOWN)
+ filtered = tv_get_number_chk(&argvars[2], NULL);
+
+ if (p_wic)
+ options |= WILD_ICASE;
+
+ /* For filtered results, 'wildignore' is used */
+ if (!filtered)
+ options |= WILD_KEEP_ALL;
+
+ ExpandInit(&xpc);
+ xpc.xp_pattern = tv_get_string(&argvars[0]);
+ xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
+ xpc.xp_context = cmdcomplete_str_to_type(tv_get_string(&argvars[1]));
+ if (xpc.xp_context == EXPAND_NOTHING)
+ {
+ if (argvars[1].v_type == VAR_STRING)
+ semsg(_(e_invarg2), argvars[1].vval.v_string);
+ else
+ emsg(_(e_invarg));
+ return;
+ }
+
+# if defined(FEAT_MENU)
+ if (xpc.xp_context == EXPAND_MENUS)
+ {
+ set_context_in_menu_cmd(&xpc, (char_u *)"menu", xpc.xp_pattern, FALSE);
+ xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
+ }
+# endif
+#ifdef FEAT_CSCOPE
+ if (xpc.xp_context == EXPAND_CSCOPE)
+ {
+ set_context_in_cscope_cmd(&xpc, xpc.xp_pattern, CMD_cscope);
+ xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
+ }
+#endif
+#ifdef FEAT_SIGNS
+ if (xpc.xp_context == EXPAND_SIGN)
+ {
+ set_context_in_sign_cmd(&xpc, xpc.xp_pattern);
+ xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
+ }
+#endif
+
+ pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context);
+ if ((rettv_list_alloc(rettv) != FAIL) && (pat != NULL))
+ {
+ int i;
+
+ ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP);
+
+ for (i = 0; i < xpc.xp_numfiles; i++)
+ list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
+ }
+ vim_free(pat);
+ ExpandCleanup(&xpc);
+}
+#endif
+
+/*
+ * "getcwd()" function
+ */
+ static void
+f_getcwd(typval_T *argvars, typval_T *rettv)
+{
+ win_T *wp = NULL;
+ char_u *cwd;
+ int global = FALSE;
+
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+
+ if (argvars[0].v_type == VAR_NUMBER && argvars[0].vval.v_number == -1)
+ global = TRUE;
+ else
+ wp = find_tabwin(&argvars[0], &argvars[1]);
+
+ if (wp != NULL && wp->w_localdir != NULL)
+ rettv->vval.v_string = vim_strsave(wp->w_localdir);
+ else if (wp != NULL || global)
+ {
+ if (globaldir != NULL)
+ rettv->vval.v_string = vim_strsave(globaldir);
+ else
+ {
+ cwd = alloc(MAXPATHL);
+ if (cwd != NULL)
+ {
+ if (mch_dirname(cwd, MAXPATHL) != FAIL)
+ rettv->vval.v_string = vim_strsave(cwd);
+ vim_free(cwd);
+ }
+ }
+ }
+#ifdef BACKSLASH_IN_FILENAME
+ if (rettv->vval.v_string != NULL)
+ slash_adjust(rettv->vval.v_string);
+#endif
+}
+
+/*
+ * "getfontname()" function
+ */
+ static void
+f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+#ifdef FEAT_GUI
+ if (gui.in_use)
+ {
+ GuiFont font;
+ char_u *name = NULL;
+
+ if (argvars[0].v_type == VAR_UNKNOWN)
+ {
+ /* Get the "Normal" font. Either the name saved by
+ * hl_set_font_name() or from the font ID. */
+ font = gui.norm_font;
+ name = hl_get_font_name();
+ }
+ else
+ {
+ name = tv_get_string(&argvars[0]);
+ if (STRCMP(name, "*") == 0) /* don't use font dialog */
+ return;
+ font = gui_mch_get_font(name, FALSE);
+ if (font == NOFONT)
+ return; /* Invalid font name, return empty string. */
+ }
+ rettv->vval.v_string = gui_mch_get_fontname(font, name);
+ if (argvars[0].v_type != VAR_UNKNOWN)
+ gui_mch_free_font(font);
+ }
+#endif
+}
+
+/*
+ * "getfperm({fname})" function
+ */
+ static void
+f_getfperm(typval_T *argvars, typval_T *rettv)
+{
+ char_u *fname;
+ stat_T st;
+ char_u *perm = NULL;
+ char_u flags[] = "rwx";
+ int i;
+
+ fname = tv_get_string(&argvars[0]);
+
+ rettv->v_type = VAR_STRING;
+ if (mch_stat((char *)fname, &st) >= 0)
+ {
+ perm = vim_strsave((char_u *)"---------");
+ if (perm != NULL)
+ {
+ for (i = 0; i < 9; i++)
+ {
+ if (st.st_mode & (1 << (8 - i)))
+ perm[i] = flags[i % 3];
+ }
+ }
+ }
+ rettv->vval.v_string = perm;
+}
+
+/*
+ * "getfsize({fname})" function
+ */
+ static void
+f_getfsize(typval_T *argvars, typval_T *rettv)
+{
+ char_u *fname;
+ stat_T st;
+
+ fname = tv_get_string(&argvars[0]);
+
+ rettv->v_type = VAR_NUMBER;
+
+ if (mch_stat((char *)fname, &st) >= 0)
+ {
+ if (mch_isdir(fname))
+ rettv->vval.v_number = 0;
+ else
+ {
+ rettv->vval.v_number = (varnumber_T)st.st_size;
+
+ /* non-perfect check for overflow */
+ if ((off_T)rettv->vval.v_number != (off_T)st.st_size)
+ rettv->vval.v_number = -2;
+ }
+ }
+ else
+ rettv->vval.v_number = -1;
+}
+
+/*
+ * "getftime({fname})" function
+ */
+ static void
+f_getftime(typval_T *argvars, typval_T *rettv)
+{
+ char_u *fname;
+ stat_T st;
+
+ fname = tv_get_string(&argvars[0]);
+
+ if (mch_stat((char *)fname, &st) >= 0)
+ rettv->vval.v_number = (varnumber_T)st.st_mtime;
+ else
+ rettv->vval.v_number = -1;
+}
+
+/*
+ * "getftype({fname})" function
+ */
+ static void
+f_getftype(typval_T *argvars, typval_T *rettv)
+{
+ char_u *fname;
+ stat_T st;
+ char_u *type = NULL;
+ char *t;
+
+ fname = tv_get_string(&argvars[0]);
+
+ rettv->v_type = VAR_STRING;
+ if (mch_lstat((char *)fname, &st) >= 0)
+ {
+ if (S_ISREG(st.st_mode))
+ t = "file";
+ else if (S_ISDIR(st.st_mode))
+ t = "dir";
+ else if (S_ISLNK(st.st_mode))
+ t = "link";
+ else if (S_ISBLK(st.st_mode))
+ t = "bdev";
+ else if (S_ISCHR(st.st_mode))
+ t = "cdev";
+ else if (S_ISFIFO(st.st_mode))
+ t = "fifo";
+ else if (S_ISSOCK(st.st_mode))
+ t = "socket";
+ else
+ t = "other";
+ type = vim_strsave((char_u *)t);
+ }
+ rettv->vval.v_string = type;
+}
+
+/*
+ * "getjumplist()" function
+ */
+ static void
+f_getjumplist(typval_T *argvars, typval_T *rettv)
+{
+#ifdef FEAT_JUMPLIST
+ win_T *wp;
+ int i;
+ list_T *l;
+ dict_T *d;
+#endif
+
+ if (rettv_list_alloc(rettv) != OK)
+ return;
+
+#ifdef FEAT_JUMPLIST
+ wp = find_tabwin(&argvars[0], &argvars[1]);
+ if (wp == NULL)
+ return;
+
+ l = list_alloc();
+ if (l == NULL)
+ return;
+
+ if (list_append_list(rettv->vval.v_list, l) == FAIL)
+ return;
+ list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
+
+ cleanup_jumplist(wp, TRUE);
+
+ for (i = 0; i < wp->w_jumplistlen; ++i)
+ {
+ if (wp->w_jumplist[i].fmark.mark.lnum == 0)
+ continue;
+ if ((d = dict_alloc()) == NULL)
+ return;
+ if (list_append_dict(l, d) == FAIL)
+ return;
+ dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
+ dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
+ dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
+ dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
+ if (wp->w_jumplist[i].fname != NULL)
+ dict_add_string(d, "filename", wp->w_jumplist[i].fname);
+ }
+#endif
+}
+
+/*
+ * "getline(lnum, [end])" function
+ */
+ static void
+f_getline(typval_T *argvars, typval_T *rettv)
+{
+ linenr_T lnum;
+ linenr_T end;
+ int retlist;
+
+ lnum = tv_get_lnum(argvars);
+ if (argvars[1].v_type == VAR_UNKNOWN)
+ {
+ end = 0;
+ retlist = FALSE;
+ }
+ else
+ {
+ end = tv_get_lnum(&argvars[1]);
+ retlist = TRUE;
+ }
+
+ get_buffer_lines(curbuf, lnum, end, retlist, rettv);
+}
+
+#ifdef FEAT_QUICKFIX
+ static void
+get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
+{
+ if (what_arg->v_type == VAR_UNKNOWN)
+ {
+ if (rettv_list_alloc(rettv) == OK)
+ if (is_qf || wp != NULL)
+ (void)get_errorlist(NULL, wp, -1, rettv->vval.v_list);
+ }
+ else
+ {
+ if (rettv_dict_alloc(rettv) == OK)
+ if (is_qf || (wp != NULL))
+ {
+ if (what_arg->v_type == VAR_DICT)
+ {
+ dict_T *d = what_arg->vval.v_dict;
+
+ if (d != NULL)
+ qf_get_properties(wp, d, rettv->vval.v_dict);
+ }
+ else
+ emsg(_(e_dictreq));
+ }
+ }
+}
+#endif
+
+/*
+ * "getloclist()" function
+ */
+ static void
+f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
+{
+#ifdef FEAT_QUICKFIX
+ win_T *wp;
+
+ wp = find_win_by_nr_or_id(&argvars[0]);
+ get_qf_loc_list(FALSE, wp, &argvars[1], rettv);
+#endif
+}
+
+/*
+ * "getmatches()" function
+ */
+ static void
+f_getmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
+{
+#ifdef FEAT_SEARCH_EXTRA
+ dict_T *dict;
+ matchitem_T *cur = curwin->w_match_head;
+ int i;
+
+ if (rettv_list_alloc(rettv) == OK)
+ {
+ while (cur != NULL)
+ {
+ dict = dict_alloc();
+ if (dict == NULL)
+ return;
+ if (cur->match.regprog == NULL)
+ {
+ /* match added with matchaddpos() */
+ for (i = 0; i < MAXPOSMATCH; ++i)
+ {
+ llpos_T *llpos;
+ char buf[6];
+ list_T *l;
+
+ llpos = &cur->pos.pos[i];
+ if (llpos->lnum == 0)
+ break;
+ l = list_alloc();
+ if (l == NULL)
+ break;
+ list_append_number(l, (varnumber_T)llpos->lnum);
+ if (llpos->col > 0)
+ {
+ list_append_number(l, (varnumber_T)llpos->col);
+ list_append_number(l, (varnumber_T)llpos->len);
+ }
+ sprintf(buf, "pos%d", i + 1);
+ dict_add_list(dict, buf, l);
+ }
+ }
+ else
+ {
+ dict_add_string(dict, "pattern", cur->pattern);
+ }
+ dict_add_string(dict, "group", syn_id2name(cur->hlg_id));
+ dict_add_number(dict, "priority", (long)cur->priority);
+ dict_add_number(dict, "id", (long)cur->id);
+# if defined(FEAT_CONCEAL)
+ if (cur->conceal_char)
+ {
+ char_u buf[MB_MAXBYTES + 1];
+
+ buf[(*mb_char2bytes)((int)cur->conceal_char, buf)] = NUL;
+ dict_add_string(dict, "conceal", (char_u *)&buf);
+ }
+# endif
+ list_append_dict(rettv->vval.v_list, dict);
+ cur = cur->next;
+ }
+ }
+#endif
+}
+
+/*
+ * "getpid()" function
+ */
+ static void
+f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ rettv->vval.v_number = mch_get_pid();
+}
+
+ static void
+getpos_both(
+ typval_T *argvars,
+ typval_T *rettv,
+ int getcurpos)
+{
+ pos_T *fp;
+ list_T *l;
+ int fnum = -1;
+
+ if (rettv_list_alloc(rettv) == OK)
+ {
+ l = rettv->vval.v_list;
+ if (getcurpos)
+ fp = &curwin->w_cursor;
+ else
+ fp = var2fpos(&argvars[0], TRUE, &fnum);
+ if (fnum != -1)
+ list_append_number(l, (varnumber_T)fnum);
+ else
+ list_append_number(l, (varnumber_T)0);
+ list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
+ : (varnumber_T)0);
+ list_append_number(l, (fp != NULL)
+ ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
+ : (varnumber_T)0);
+ list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
+ (varnumber_T)0);
+ if (getcurpos)
+ {
+ update_curswant();
+ list_append_number(l, curwin->w_curswant == MAXCOL ?
+ (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
+ }
+ }
+ else
+ rettv->vval.v_number = FALSE;
+}
+
+/*
+ * "getcurpos()" function
+ */
+ static void
+f_getcurpos(typval_T *argvars, typval_T *rettv)
+{
+ getpos_both(argvars, rettv, TRUE);
+}
+
+/*
+ * "getpos(string)" function
+ */
+ static void
+f_getpos(typval_T *argvars, typval_T *rettv)
+{
+ getpos_both(argvars, rettv, FALSE);
+}
+
+/*
+ * "getqflist()" function
+ */
+ static void
+f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
+{
+#ifdef FEAT_QUICKFIX
+ get_qf_loc_list(TRUE, NULL, &argvars[0], rettv);
+#endif
+}
+
+/*
+ * "getreg()" function
+ */
+ static void
+f_getreg(typval_T *argvars, typval_T *rettv)
+{
+ char_u *strregname;
+ int regname;
+ int arg2 = FALSE;
+ int return_list = FALSE;
+ int error = FALSE;
+
+ if (argvars[0].v_type != VAR_UNKNOWN)
+ {
+ strregname = tv_get_string_chk(&argvars[0]);
+ error = strregname == NULL;
+ if (argvars[1].v_type != VAR_UNKNOWN)
+ {
+ arg2 = (int)tv_get_number_chk(&argvars[1], &error);
+ if (!error && argvars[2].v_type != VAR_UNKNOWN)
+ return_list = (int)tv_get_number_chk(&argvars[2], &error);
+ }
+ }
+ else
+ strregname = get_vim_var_str(VV_REG);
+
+ if (error)
+ return;
+
+ regname = (strregname == NULL ? '"' : *strregname);
+ if (regname == 0)
+ regname = '"';
+
+ if (return_list)
+ {
+ rettv->v_type = VAR_LIST;
+ rettv->vval.v_list = (list_T *)get_reg_contents(regname,
+ (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
+ if (rettv->vval.v_list == NULL)
+ (void)rettv_list_alloc(rettv);
+ else
+ ++rettv->vval.v_list->lv_refcount;
+ }
+ else
+ {
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = get_reg_contents(regname,
+ arg2 ? GREG_EXPR_SRC : 0);
+ }
+}
+
+/*
+ * "getregtype()" function
+ */
+ static void
+f_getregtype(typval_T *argvars, typval_T *rettv)
+{
+ char_u *strregname;
+ int regname;
+ char_u buf[NUMBUFLEN + 2];
+ long reglen = 0;
+
+ if (argvars[0].v_type != VAR_UNKNOWN)
+ {
+ strregname = tv_get_string_chk(&argvars[0]);
+ if (strregname == NULL) /* type error; errmsg already given */
+ {
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+ return;
+ }
+ }
+ else
+ /* Default to v:register */
+ strregname = get_vim_var_str(VV_REG);
+
+ regname = (strregname == NULL ? '"' : *strregname);
+ if (regname == 0)
+ regname = '"';
+
+ buf[0] = NUL;
+ buf[1] = NUL;
+ switch (get_reg_type(regname, &reglen))
+ {
+ case MLINE: buf[0] = 'V'; break;
+ case MCHAR: buf[0] = 'v'; break;
+ case MBLOCK:
+ buf[0] = Ctrl_V;
+ sprintf((char *)buf + 1, "%ld", reglen + 1);
+ break;
+ }
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = vim_strsave(buf);
+}
+
+/*
+ * Returns information (variables, options, etc.) about a tab page
+ * as a dictionary.
+ */
+ static dict_T *
+get_tabpage_info(tabpage_T *tp, int tp_idx)
+{
+ win_T *wp;
+ dict_T *dict;
+ list_T *l;
+
+ dict = dict_alloc();
+ if (dict == NULL)
+ return NULL;
+
+ dict_add_number(dict, "tabnr", tp_idx);
+
+ l = list_alloc();
+ if (l != NULL)
+ {
+ for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
+ wp; wp = wp->w_next)
+ list_append_number(l, (varnumber_T)wp->w_id);
+ dict_add_list(dict, "windows", l);
+ }
+
+ /* Make a reference to tabpage variables */
+ dict_add_dict(dict, "variables", tp->tp_vars);
+
+ return dict;
+}
+
+/*
+ * "gettabinfo()" function
+ */
+ static void
+f_gettabinfo(typval_T *argvars, typval_T *rettv)
+{
+ tabpage_T *tp, *tparg = NULL;
+ dict_T *d;
+ int tpnr = 0;
+
+ if (rettv_list_alloc(rettv) != OK)
+ return;
+
+ if (argvars[0].v_type != VAR_UNKNOWN)
+ {
+ /* Information about one tab page */
+ tparg = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
+ if (tparg == NULL)
+ return;
+ }
+
+ /* Get information about a specific tab page or all tab pages */
+ FOR_ALL_TABPAGES(tp)
+ {
+ tpnr++;
+ if (tparg != NULL && tp != tparg)
+ continue;
+ d = get_tabpage_info(tp, tpnr);
+ if (d != NULL)
+ list_append_dict(rettv->vval.v_list, d);
+ if (tparg != NULL)
+ return;
+ }
+}
+
+/*
+ * "gettabvar()" function
+ */
+ static void
+f_gettabvar(typval_T *argvars, typval_T *rettv)
+{
+ win_T *oldcurwin;
+ tabpage_T *tp, *oldtabpage;
+ dictitem_T *v;
+ char_u *varname;
+ int done = FALSE;
+
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+
+ varname = tv_get_string_chk(&argvars[1]);
+ tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
+ if (tp != NULL && varname != NULL)
+ {
+ /* Set tp to be our tabpage, temporarily. Also set the window to the
+ * first window in the tabpage, otherwise the window is not valid. */
+ if (switch_win(&oldcurwin, &oldtabpage,
+ tp == curtab || tp->tp_firstwin == NULL ? firstwin
+ : tp->tp_firstwin, tp, TRUE) == OK)
+ {
+ /* look up the variable */
+ /* Let gettabvar({nr}, "") return the "t:" dictionary. */
+ v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE);
+ if (v != NULL)
+ {
+ copy_tv(&v->di_tv, rettv);
+ done = TRUE;
+ }
+ }
+
+ /* restore previous notion of curwin */
+ restore_win(oldcurwin, oldtabpage, TRUE);
+ }
+
+ if (!done && argvars[2].v_type != VAR_UNKNOWN)
+ copy_tv(&argvars[2], rettv);
+}
+
+/*
+ * "gettabwinvar()" function
+ */
+ static void
+f_gettabwinvar(typval_T *argvars, typval_T *rettv)
+{
+ getwinvar(argvars, rettv, 1);
+}
+
+/*
+ * "gettagstack()" function
+ */
+ static void
+f_gettagstack(typval_T *argvars, typval_T *rettv)
+{
+ win_T *wp = curwin; // default is current window
+
+ if (rettv_dict_alloc(rettv) != OK)
+ return;
+
+ if (argvars[0].v_type != VAR_UNKNOWN)
+ {
+ wp = find_win_by_nr_or_id(&argvars[0]);
+ if (wp == NULL)
+ return;
+ }
+
+ get_tagstack(wp, rettv->vval.v_dict);
+}
+
+/*
+ * Returns information about a window as a dictionary.
+ */
+ static dict_T *
+get_win_info(win_T *wp, short tpnr, short winnr)
+{
+ dict_T *dict;
+
+ dict = dict_alloc();
+ if (dict == NULL)
+ return NULL;
+
+ dict_add_number(dict, "tabnr", tpnr);
+ dict_add_number(dict, "winnr", winnr);
+ dict_add_number(dict, "winid", wp->w_id);
+ dict_add_number(dict, "height", wp->w_height);
+ dict_add_number(dict, "winrow", wp->w_winrow + 1);
+#ifdef FEAT_MENU
+ dict_add_number(dict, "winbar", wp->w_winbar_height);
+#endif
+ dict_add_number(dict, "width", wp->w_width);
+ dict_add_number(dict, "wincol", wp->w_wincol + 1);
+ dict_add_number(dict, "bufnr", wp->w_buffer->b_fnum);
+
+#ifdef FEAT_TERMINAL
+ dict_add_number(dict, "terminal", bt_terminal(wp->w_buffer));
+#endif
+#ifdef FEAT_QUICKFIX
+ dict_add_number(dict, "quickfix", bt_quickfix(wp->w_buffer));
+ dict_add_number(dict, "loclist",
+ (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL));
+#endif
+
+ /* Add a reference to window variables */
+ dict_add_dict(dict, "variables", wp->w_vars);
+
+ return dict;
+}
+
+/*
+ * "getwininfo()" function
+ */
+ static void
+f_getwininfo(typval_T *argvars, typval_T *rettv)
+{
+ tabpage_T *tp;
+ win_T *wp = NULL, *wparg = NULL;
+ dict_T *d;
+ short tabnr = 0, winnr;
+
+ if (rettv_list_alloc(rettv) != OK)
+ return;
+
+ if (argvars[0].v_type != VAR_UNKNOWN)
+ {
+ wparg = win_id2wp(argvars);
+ if (wparg == NULL)
+ return;
+ }
+
+ /* Collect information about either all the windows across all the tab
+ * pages or one particular window.
+ */
+ FOR_ALL_TABPAGES(tp)
+ {
+ tabnr++;
+ winnr = 0;
+ FOR_ALL_WINDOWS_IN_TAB(tp, wp)
+ {
+ winnr++;
+ if (wparg != NULL && wp != wparg)
+ continue;
+ d = get_win_info(wp, tabnr, winnr);
+ if (d != NULL)
+ list_append_dict(rettv->vval.v_list, d);
+ if (wparg != NULL)
+ /* found information about a specific window */
+ return;
+ }
+ }
+}
+
+/*
+ * "win_findbuf()" function
+ */
+ static void
+f_win_findbuf(typval_T *argvars, typval_T *rettv)
+{
+ if (rettv_list_alloc(rettv) != FAIL)
+ win_findbuf(argvars, rettv->vval.v_list);
+}
+
+/*
+ * "win_getid()" function
+ */
+ static void
+f_win_getid(typval_T *argvars, typval_T *rettv)
+{
+ rettv->vval.v_number = win_getid(argvars);
+}
+
+/*
+ * "win_gotoid()" function
+ */
+ static void
+f_win_gotoid(typval_T *argvars, typval_T *rettv)
+{
+ rettv->vval.v_number = win_gotoid(argvars);
+}
+
+/*
+ * "win_id2tabwin()" function
+ */
+ static void
+f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
+{
+ if (rettv_list_alloc(rettv) != FAIL)
+ win_id2tabwin(argvars, rettv->vval.v_list);
+}
+
+/*
+ * "win_id2win()" function
+ */
+ static void
+f_win_id2win(typval_T *argvars, typval_T *rettv)
+{
+ rettv->vval.v_number = win_id2win(argvars);
+}
+
+/*
+ * "win_screenpos()" function
+ */
+ static void
+f_win_screenpos(typval_T *argvars, typval_T *rettv)
+{
+ win_T *wp;
+
+ if (rettv_list_alloc(rettv) == FAIL)
+ return;
+
+ wp = find_win_by_nr_or_id(&argvars[0]);
+ list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
+ list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
+}
+
+/*
+ * "getwinpos({timeout})" function
+ */
+ static void
+f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ int x = -1;
+ int y = -1;
+
+ if (rettv_list_alloc(rettv) == FAIL)
+ return;
+#ifdef FEAT_GUI
+ if (gui.in_use)
+ (void)gui_mch_get_winpos(&x, &y);
+# if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
+ else
+# endif
+#endif
+#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
+ {
+ varnumber_T timeout = 100;
+
+ if (argvars[0].v_type != VAR_UNKNOWN)
+ timeout = tv_get_number(&argvars[0]);
+ term_get_winpos(&x, &y, timeout);
+ }
+#endif
+ list_append_number(rettv->vval.v_list, (varnumber_T)x);
+ list_append_number(rettv->vval.v_list, (varnumber_T)y);
+}
+
+
+/*
+ * "getwinposx()" function
+ */
+ static void
+f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ rettv->vval.v_number = -1;
+#ifdef FEAT_GUI
+ if (gui.in_use)
+ {
+ int x, y;
+
+ if (gui_mch_get_winpos(&x, &y) == OK)
+ rettv->vval.v_number = x;
+ return;
+ }
+#endif
+#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
+ {
+ int x, y;
+
+ if (term_get_winpos(&x, &y, (varnumber_T)100) == OK)
+ rettv->vval.v_number = x;
+ }
+#endif
+}
+
+/*
+ * "getwinposy()" function
+ */
+ static void
+f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ rettv->vval.v_number = -1;
+#ifdef FEAT_GUI
+ if (gui.in_use)
+ {
+ int x, y;
+
+ if (gui_mch_get_winpos(&x, &y) == OK)
+ rettv->vval.v_number = y;
+ return;
+ }
+#endif
+#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
+ {
+ int x, y;
+
+ if (term_get_winpos(&x, &y, (varnumber_T)100) == OK)
+ rettv->vval.v_number = y;
+ }
+#endif
+}
+
+/*
+ * "getwinvar()" function
+ */
+ static void
+f_getwinvar(typval_T *argvars, typval_T *rettv)
+{
+ getwinvar(argvars, rettv, 0);
+}
+
+/*
+ * "glob()" function
+ */
+ static void
+f_glob(typval_T *argvars, typval_T *rettv)
+{
+ int options = WILD_SILENT|WILD_USE_NL;
+ expand_T xpc;
+ int error = FALSE;
+
+ /* When the optional second argument is non-zero, don't remove matches
+ * for 'wildignore' and don't put matches for 'suffixes' at the end. */
+ rettv->v_type = VAR_STRING;
+ if (argvars[1].v_type != VAR_UNKNOWN)
+ {
+ if (tv_get_number_chk(&argvars[1], &error))
+ options |= WILD_KEEP_ALL;
+ if (argvars[2].v_type != VAR_UNKNOWN)
+ {
+ if (tv_get_number_chk(&argvars[2], &error))
+ {
+ rettv_list_set(rettv, NULL);
+ }
+ if (argvars[3].v_type != VAR_UNKNOWN
+ && tv_get_number_chk(&argvars[3], &error))
+ options |= WILD_ALLLINKS;
+ }
+ }
+ if (!error)
+ {
+ ExpandInit(&xpc);
+ xpc.xp_context = EXPAND_FILES;
+ if (p_wic)
+ options += WILD_ICASE;
+ if (rettv->v_type == VAR_STRING)
+ rettv->vval.v_string = ExpandOne(&xpc, tv_get_string(&argvars[0]),
+ NULL, options, WILD_ALL);
+ else if (rettv_list_alloc(rettv) != FAIL)
+ {
+ int i;
+
+ ExpandOne(&xpc, tv_get_string(&argvars[0]),
+ NULL, options, WILD_ALL_KEEP);
+ for (i = 0; i < xpc.xp_numfiles; i++)
+ list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
+
+ ExpandCleanup(&xpc);
+ }
+ }
+ else
+ rettv->vval.v_string = NULL;
+}
+
+/*
+ * "globpath()" function
+ */
+ static void
+f_globpath(typval_T *argvars, typval_T *rettv)
+{
+ int flags = 0;
+ char_u buf1[NUMBUFLEN];
+ char_u *file = tv_get_string_buf_chk(&argvars[1], buf1);
+ int error = FALSE;
+ garray_T ga;
+ int i;
+
+ /* When the optional second argument is non-zero, don't remove matches
+ * for 'wildignore' and don't put matches for 'suffixes' at the end. */
+ rettv->v_type = VAR_STRING;
+ if (argvars[2].v_type != VAR_UNKNOWN)
+ {
+ if (tv_get_number_chk(&argvars[2], &error))
+ flags |= WILD_KEEP_ALL;
+ if (argvars[3].v_type != VAR_UNKNOWN)
+ {
+ if (tv_get_number_chk(&argvars[3], &error))
+ {
+ rettv_list_set(rettv, NULL);
+ }
+ if (argvars[4].v_type != VAR_UNKNOWN
+ && tv_get_number_chk(&argvars[4], &error))
+ flags |= WILD_ALLLINKS;
+ }
+ }
+ if (file != NULL && !error)
+ {
+ ga_init2(&ga, (int)sizeof(char_u *), 10);
+ globpath(tv_get_string(&argvars[0]), file, &ga, flags);
+ if (rettv->v_type == VAR_STRING)
+ rettv->vval.v_string = ga_concat_strings(&ga, "\n");
+ else if (rettv_list_alloc(rettv) != FAIL)
+ for (i = 0; i < ga.ga_len; ++i)
+ list_append_string(rettv->vval.v_list,
+ ((char_u **)(ga.ga_data))[i], -1);
+ ga_clear_strings(&ga);
+ }
+ else
+ rettv->vval.v_string = NULL;
+}
+
+/*
+ * "glob2regpat()" function
+ */
+ static void
+f_glob2regpat(typval_T *argvars, typval_T *rettv)
+{
+ char_u *pat = tv_get_string_chk(&argvars[0]);
+
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = (pat == NULL)
+ ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
+}
+
+/* for VIM_VERSION_ defines */
+#include "version.h"
+
+/*
+ * "has()" function
+ */
+ static void
+f_has(typval_T *argvars, typval_T *rettv)
+{
+ int i;
+ char_u *name;
+ int n = FALSE;
+ static char *(has_list[]) =
+ {
+#ifdef AMIGA
+ "amiga",
+# ifdef FEAT_ARP
+ "arp",
+# endif
+#endif
+#ifdef __BEOS__
+ "beos",
+#endif
+#if defined(BSD) && !defined(MACOS_X)
+ "bsd",
+#endif
+#ifdef hpux
+ "hpux",
+#endif
+#ifdef __linux__
+ "linux",
+#endif
+#ifdef MACOS_X
+ "mac", /* Mac OS X (and, once, Mac OS Classic) */
+ "osx", /* Mac OS X */
+# ifdef MACOS_X_DARWIN
+ "macunix", /* Mac OS X, with the darwin feature */
+ "osxdarwin", /* synonym for macunix */
+# endif
+#endif
+#ifdef __QNX__
+ "qnx",
+#endif
+#ifdef SUN_SYSTEM
+ "sun",
+#else
+ "moon",
+#endif
+#ifdef UNIX
+ "unix",
+#endif
+#ifdef VMS
+ "vms",
+#endif
+#ifdef WIN32
+ "win32",
+#endif
+#if defined(UNIX) && (defined(__CYGWIN32__) || defined(__CYGWIN__))
+ "win32unix",
+#endif
+#if defined(WIN64) || defined(_WIN64)
+ "win64",
+#endif
+#ifdef EBCDIC
+ "ebcdic",
+#endif
+#ifndef CASE_INSENSITIVE_FILENAME
+ "fname_case",
+#endif
+#ifdef HAVE_ACL
+ "acl",
+#endif
+#ifdef FEAT_ARABIC
+ "arabic",
+#endif
+ "autocmd",
+#ifdef FEAT_AUTOCHDIR
+ "autochdir",
+#endif
+#ifdef FEAT_AUTOSERVERNAME
+ "autoservername",
+#endif
+#ifdef FEAT_BEVAL_GUI
+ "balloon_eval",
+# ifndef FEAT_GUI_W32 /* other GUIs always have multiline balloons */
+ "balloon_multiline",
+# endif
+#endif
+#ifdef FEAT_BEVAL_TERM
+ "balloon_eval_term",
+#endif
+#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
+ "builtin_terms",
+# ifdef ALL_BUILTIN_TCAPS
+ "all_builtin_terms",
+# endif
+#endif
+#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
+ || defined(FEAT_GUI_W32) \
+ || defined(FEAT_GUI_MOTIF))
+ "browsefilter",
+#endif
+#ifdef FEAT_BYTEOFF
+ "byte_offset",
+#endif
+#ifdef FEAT_JOB_CHANNEL
+ "channel",
+#endif
+#ifdef FEAT_CINDENT
+ "cindent",
+#endif
+#ifdef FEAT_CLIENTSERVER
+ "clientserver",
+#endif
+#ifdef FEAT_CLIPBOARD
+ "clipboard",
+#endif
+#ifdef FEAT_CMDL_COMPL
+ "cmdline_compl",
+#endif
+#ifdef FEAT_CMDHIST
+ "cmdline_hist",
+#endif
+#ifdef FEAT_COMMENTS
+ "comments",
+#endif
+#ifdef FEAT_CONCEAL
+ "conceal",
+#endif
+#ifdef FEAT_CRYPT
+ "cryptv",
+ "crypt-blowfish",
+ "crypt-blowfish2",
+#endif
+#ifdef FEAT_CSCOPE
+ "cscope",
+#endif
+ "cursorbind",
+#ifdef CURSOR_SHAPE
+ "cursorshape",
+#endif
+#ifdef DEBUG
+ "debug",
+#endif
+#ifdef FEAT_CON_DIALOG
+ "dialog_con",
+#endif
+#ifdef FEAT_GUI_DIALOG
+ "dialog_gui",
+#endif
+#ifdef FEAT_DIFF
+ "diff",
+#endif
+#ifdef FEAT_DIGRAPHS
+ "digraphs",
+#endif
+#ifdef FEAT_DIRECTX
+ "directx",
+#endif
+#ifdef FEAT_DND
+ "dnd",
+#endif
+#ifdef FEAT_EMACS_TAGS
+ "emacs_tags",
+#endif
+ "eval", /* always present, of course! */
+ "ex_extra", /* graduated feature */
+#ifdef FEAT_SEARCH_EXTRA
+ "extra_search",
+#endif
+#ifdef FEAT_FKMAP
+ "farsi",
+#endif
+#ifdef FEAT_SEARCHPATH
+ "file_in_path",
+#endif
+#ifdef FEAT_FILTERPIPE
+ "filterpipe",
+#endif
+#ifdef FEAT_FIND_ID
+ "find_in_path",
+#endif
+#ifdef FEAT_FLOAT
+ "float",
+#endif
+#ifdef FEAT_FOLDING
+ "folding",
+#endif
+#ifdef FEAT_FOOTER
+ "footer",
+#endif
+#if !defined(USE_SYSTEM) && defined(UNIX)
+ "fork",
+#endif
+#ifdef FEAT_GETTEXT
+ "gettext",
+#endif
+#ifdef FEAT_GUI
+ "gui",
+#endif
+#ifdef FEAT_GUI_ATHENA
+# ifdef FEAT_GUI_NEXTAW
+ "gui_neXtaw",
+# else
+ "gui_athena",
+# endif
+#endif
+#ifdef FEAT_GUI_GTK
+ "gui_gtk",
+# ifdef USE_GTK3
+ "gui_gtk3",
+# else
+ "gui_gtk2",
+# endif
+#endif
+#ifdef FEAT_GUI_GNOME
+ "gui_gnome",
+#endif
+#ifdef FEAT_GUI_MAC
+ "gui_mac",
+#endif
+#ifdef FEAT_GUI_MOTIF
+ "gui_motif",
+#endif
+#ifdef FEAT_GUI_PHOTON
+ "gui_photon",
+#endif
+#ifdef FEAT_GUI_W32
+ "gui_win32",
+#endif
+#ifdef FEAT_HANGULIN
+ "hangul_input",
+#endif
+#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
+ "iconv",
+#endif
+#ifdef FEAT_INS_EXPAND
+ "insert_expand",
+#endif
+#ifdef FEAT_JOB_CHANNEL
+ "job",
+#endif
+#ifdef FEAT_JUMPLIST
+ "jumplist",
+#endif
+#ifdef FEAT_KEYMAP
+ "keymap",
+#endif
+ "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
+#ifdef FEAT_LANGMAP
+ "langmap",
+#endif
+#ifdef FEAT_LIBCALL
+ "libcall",
+#endif
+#ifdef FEAT_LINEBREAK
+ "linebreak",
+#endif
+#ifdef FEAT_LISP
+ "lispindent",
+#endif
+ "listcmds",
+#ifdef FEAT_LOCALMAP
+ "localmap",
+#endif
+#ifdef FEAT_LUA
+# ifndef DYNAMIC_LUA
+ "lua",
+# endif
+#endif
+#ifdef FEAT_MENU
+ "menu",
+#endif
+#ifdef FEAT_SESSION
+ "mksession",
+#endif
+#ifdef FEAT_MODIFY_FNAME
+ "modify_fname",
+#endif
+#ifdef FEAT_MOUSE
+ "mouse",
+#endif
+#ifdef FEAT_MOUSESHAPE
+ "mouseshape",
+#endif
+#if defined(UNIX) || defined(VMS)
+# ifdef FEAT_MOUSE_DEC
+ "mouse_dec",
+# endif
+# ifdef FEAT_MOUSE_GPM
+ "mouse_gpm",
+# endif
+# ifdef FEAT_MOUSE_JSB
+ "mouse_jsbterm",
+# endif
+# ifdef FEAT_MOUSE_NET
+ "mouse_netterm",
+# endif
+# ifdef FEAT_MOUSE_PTERM
+ "mouse_pterm",
+# endif
+# ifdef FEAT_MOUSE_SGR
+ "mouse_sgr",
+# endif
+# ifdef FEAT_SYSMOUSE
+ "mouse_sysmouse",
+# endif
+# ifdef FEAT_MOUSE_URXVT
+ "mouse_urxvt",
+# endif
+# ifdef FEAT_MOUSE_XTERM
+ "mouse_xterm",
+# endif
+#endif
+ "multi_byte",
+#ifdef FEAT_MBYTE_IME
+ "multi_byte_ime",
+#endif
+#ifdef FEAT_MULTI_LANG
+ "multi_lang",
+#endif
+#ifdef FEAT_MZSCHEME
+#ifndef DYNAMIC_MZSCHEME
+ "mzscheme",
+#endif
+#endif
+#ifdef FEAT_NUM64
+ "num64",
+#endif
+#ifdef FEAT_OLE
+ "ole",
+#endif
+#ifdef FEAT_EVAL
+ "packages",
+#endif
+#ifdef FEAT_PATH_EXTRA
+ "path_extra",
+#endif
+#ifdef FEAT_PERL
+#ifndef DYNAMIC_PERL
+ "perl",
+#endif
+#endif
+#ifdef FEAT_PERSISTENT_UNDO
+ "persistent_undo",
+#endif
+#if defined(FEAT_PYTHON)
+ "python_compiled",
+# if defined(DYNAMIC_PYTHON)
+ "python_dynamic",
+# else
+ "python",
+ "pythonx",
+# endif
+#endif
+#if defined(FEAT_PYTHON3)
+ "python3_compiled",
+# if defined(DYNAMIC_PYTHON3)
+ "python3_dynamic",
+# else
+ "python3",
+ "pythonx",
+# endif
+#endif
+#ifdef FEAT_POSTSCRIPT
+ "postscript",
+#endif
+#ifdef FEAT_PRINTER
+ "printer",
+#endif
+#ifdef FEAT_PROFILE
+ "profile",
+#endif
+#ifdef FEAT_RELTIME
+ "reltime",
+#endif
+#ifdef FEAT_QUICKFIX
+ "quickfix",
+#endif
+#ifdef FEAT_RIGHTLEFT
+ "rightleft",
+#endif
+#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
+ "ruby",
+#endif
+ "scrollbind",
+#ifdef FEAT_CMDL_INFO
+ "showcmd",
+ "cmdline_info",
+#endif
+#ifdef FEAT_SIGNS
+ "signs",
+#endif
+#ifdef FEAT_SMARTINDENT
+ "smartindent",
+#endif
+#ifdef STARTUPTIME
+ "startuptime",
+#endif
+#ifdef FEAT_STL_OPT
+ "statusline",
+#endif
+#ifdef FEAT_NETBEANS_INTG
+ "netbeans_intg",
+#endif
+#ifdef FEAT_SPELL
+ "spell",
+#endif
+#ifdef FEAT_SYN_HL
+ "syntax",
+#endif
+#if defined(USE_SYSTEM) || !defined(UNIX)
+ "system",
+#endif
+#ifdef FEAT_TAG_BINS
+ "tag_binary",
+#endif
+#ifdef FEAT_TAG_OLDSTATIC
+ "tag_old_static",
+#endif
+#ifdef FEAT_TAG_ANYWHITE
+ "tag_any_white",
+#endif
+#ifdef FEAT_TCL
+# ifndef DYNAMIC_TCL
+ "tcl",
+# endif
+#endif
+#ifdef FEAT_TERMGUICOLORS
+ "termguicolors",
+#endif
+#if defined(FEAT_TERMINAL) && !defined(WIN3264)
+ "terminal",
+#endif
+#ifdef TERMINFO
+ "terminfo",
+#endif
+#ifdef FEAT_TERMRESPONSE
+ "termresponse",
+#endif
+#ifdef FEAT_TEXTOBJ
+ "textobjects",
+#endif
+#ifdef FEAT_TEXT_PROP
+ "textprop",
+#endif
+#ifdef HAVE_TGETENT
+ "tgetent",
+#endif
+#ifdef FEAT_TIMERS
+ "timers",
+#endif
+#ifdef FEAT_TITLE
+ "title",
+#endif
+#ifdef FEAT_TOOLBAR
+ "toolbar",
+#endif
+#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
+ "unnamedplus",
+#endif
+#ifdef FEAT_USR_CMDS
+ "user-commands", /* was accidentally included in 5.4 */
+ "user_commands",
+#endif
+#ifdef FEAT_VARTABS
+ "vartabs",
+#endif
+#ifdef FEAT_VIMINFO
+ "viminfo",
+#endif
+ "vertsplit",
+ "virtualedit",
+ "visual",
+ "visualextra",
+ "vreplace",
+#ifdef FEAT_VTP
+ "vtp",
+#endif
+#ifdef FEAT_WILDIGN
+ "wildignore",
+#endif
+#ifdef FEAT_WILDMENU
+ "wildmenu",
+#endif
+ "windows",
+#ifdef FEAT_WAK
+ "winaltkeys",
+#endif
+#ifdef FEAT_WRITEBACKUP
+ "writebackup",
+#endif
+#ifdef FEAT_XIM
+ "xim",
+#endif
+#ifdef FEAT_XFONTSET
+ "xfontset",
+#endif
+#ifdef FEAT_XPM_W32
+ "xpm",
+ "xpm_w32", /* for backward compatibility */
+#else
+# if defined(HAVE_XPM)
+ "xpm",
+# endif
+#endif
+#ifdef USE_XSMP
+ "xsmp",
+#endif
+#ifdef USE_XSMP_INTERACT
+ "xsmp_interact",
+#endif
+#ifdef FEAT_XCLIPBOARD
+ "xterm_clipboard",
+#endif
+#ifdef FEAT_XTERM_SAVE
+ "xterm_save",
+#endif
+#if defined(UNIX) && defined(FEAT_X11)
+ "X11",
+#endif
+ NULL
+ };
+
+ name = tv_get_string(&argvars[0]);
+ for (i = 0; has_list[i] != NULL; ++i)
+ if (STRICMP(name, has_list[i]) == 0)
+ {
+ n = TRUE;
+ break;
+ }
+
+ if (n == FALSE)
+ {
+ if (STRNICMP(name, "patch", 5) == 0)
+ {
+ if (name[5] == '-'
+ && STRLEN(name) >= 11
+ && vim_isdigit(name[6])
+ && vim_isdigit(name[8])
+ && vim_isdigit(name[10]))
+ {
+ int major = atoi((char *)name + 6);
+ int minor = atoi((char *)name + 8);
+
+ /* Expect "patch-9.9.01234". */
+ n = (major < VIM_VERSION_MAJOR
+ || (major == VIM_VERSION_MAJOR
+ && (minor < VIM_VERSION_MINOR
+ || (minor == VIM_VERSION_MINOR
+ && has_patch(atoi((char *)name + 10))))));
+ }
+ else
+ n = has_patch(atoi((char *)name + 5));
+ }
+ else if (STRICMP(name, "vim_starting") == 0)
+ n = (starting != 0);
+ else if (STRICMP(name, "ttyin") == 0)
+ n = mch_input_isatty();
+ else if (STRICMP(name, "ttyout") == 0)
+ n = stdout_isatty;
+ else if (STRICMP(name, "multi_byte_encoding") == 0)
+ n = has_mbyte;
+#if defined(FEAT_BEVAL) && defined(FEAT_GUI_W32)
+ else if (STRICMP(name, "balloon_multiline") == 0)
+ n = multiline_balloon_available();
+#endif
+#ifdef DYNAMIC_TCL
+ else if (STRICMP(name, "tcl") == 0)
+ n = tcl_enabled(FALSE);
+#endif
+#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
+ else if (STRICMP(name, "iconv") == 0)
+ n = iconv_enabled(FALSE);
+#endif
+#ifdef DYNAMIC_LUA
+ else if (STRICMP(name, "lua") == 0)
+ n = lua_enabled(FALSE);
+#endif
+#ifdef DYNAMIC_MZSCHEME
+ else if (STRICMP(name, "mzscheme") == 0)
+ n = mzscheme_enabled(FALSE);
+#endif
+#ifdef DYNAMIC_RUBY
+ else if (STRICMP(name, "ruby") == 0)
+ n = ruby_enabled(FALSE);
+#endif
+#ifdef DYNAMIC_PYTHON
+ else if (STRICMP(name, "python") == 0)
+ n = python_enabled(FALSE);
+#endif
+#ifdef DYNAMIC_PYTHON3
+ else if (STRICMP(name, "python3") == 0)
+ n = python3_enabled(FALSE);
+#endif
+#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
+ else if (STRICMP(name, "pythonx") == 0)
+ {
+# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
+ if (p_pyx == 0)
+ n = python3_enabled(FALSE) || python_enabled(FALSE);
+ else if (p_pyx == 3)
+ n = python3_enabled(FALSE);
+ else if (p_pyx == 2)
+ n = python_enabled(FALSE);
+# elif defined(DYNAMIC_PYTHON)
+ n = python_enabled(FALSE);
+# elif defined(DYNAMIC_PYTHON3)
+ n = python3_enabled(FALSE);
+# endif
+ }
+#endif
+#ifdef DYNAMIC_PERL
+ else if (STRICMP(name, "perl") == 0)
+ n = perl_enabled(FALSE);
+#endif
+#ifdef FEAT_GUI
+ else if (STRICMP(name, "gui_running") == 0)
+ n = (gui.in_use || gui.starting);
+# ifdef FEAT_BROWSE
+ else if (STRICMP(name, "browse") == 0)
+ n = gui.in_use; /* gui_mch_browse() works when GUI is running */
+# endif
+#endif
+#ifdef FEAT_SYN_HL
+ else if (STRICMP(name, "syntax_items") == 0)
+ n = syntax_present(curwin);
+#endif
+#ifdef FEAT_VTP
+ else if (STRICMP(name, "vcon") == 0)
+ n = is_term_win32() && has_vtp_working();
+#endif
+#ifdef FEAT_NETBEANS_INTG
+ else if (STRICMP(name, "netbeans_enabled") == 0)
+ n = netbeans_active();
+#endif
+#if defined(FEAT_TERMINAL) && defined(WIN3264)
+ else if (STRICMP(name, "terminal") == 0)
+ n = terminal_enabled();
+#endif
+#if defined(FEAT_TERMINAL) && defined(WIN3264)
+ else if (STRICMP(name, "conpty") == 0)
+ n = use_conpty();
+#endif
+ }
+
+ rettv->vval.v_number = n;
+}
+
+/*
+ * "has_key()" function
+ */
+ static void
+f_has_key(typval_T *argvars, typval_T *rettv)
+{
+ if (argvars[0].v_type != VAR_DICT)
+ {
+ emsg(_(e_dictreq));
+ return;
+ }
+ if (argvars[0].vval.v_dict == NULL)
+ return;
+
+ rettv->vval.v_number = dict_find(argvars[0].vval.v_dict,
+ tv_get_string(&argvars[1]), -1) != NULL;
+}
+
+/*
+ * "haslocaldir()" function
+ */
+ static void
+f_haslocaldir(typval_T *argvars, typval_T *rettv)
+{
+ win_T *wp = NULL;
+
+ wp = find_tabwin(&argvars[0], &argvars[1]);
+ rettv->vval.v_number = (wp != NULL && wp->w_localdir != NULL);
+}
+
+/*
+ * "hasmapto()" function
+ */
+ static void
+f_hasmapto(typval_T *argvars, typval_T *rettv)
+{
+ char_u *name;
+ char_u *mode;
+ char_u buf[NUMBUFLEN];
+ int abbr = FALSE;
+
+ name = tv_get_string(&argvars[0]);
+ if (argvars[1].v_type == VAR_UNKNOWN)
+ mode = (char_u *)"nvo";
+ else
+ {
+ mode = tv_get_string_buf(&argvars[1], buf);
+ if (argvars[2].v_type != VAR_UNKNOWN)
+ abbr = (int)tv_get_number(&argvars[2]);
+ }
+
+ if (map_to_exists(name, mode, abbr))
+ rettv->vval.v_number = TRUE;
+ else
+ rettv->vval.v_number = FALSE;
+}
+
+/*
+ * "histadd()" function
+ */
+ static void
+f_histadd(typval_T *argvars UNUSED, typval_T *rettv)
+{
+#ifdef FEAT_CMDHIST
+ int histype;
+ char_u *str;
+ char_u buf[NUMBUFLEN];
+#endif
+
+ rettv->vval.v_number = FALSE;
+ if (check_restricted() || check_secure())
+ return;
+#ifdef FEAT_CMDHIST
+ str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
+ histype = str != NULL ? get_histtype(str) : -1;
+ if (histype >= 0)
+ {
+ str = tv_get_string_buf(&argvars[1], buf);
+ if (*str != NUL)
+ {
+ init_history();
+ add_to_history(histype, str, FALSE, NUL);
+ rettv->vval.v_number = TRUE;
+ return;
+ }
+ }
+#endif
+}
+
+/*
+ * "histdel()" function
+ */
+ static void
+f_histdel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
+{
+#ifdef FEAT_CMDHIST
+ int n;
+ char_u buf[NUMBUFLEN];
+ char_u *str;
+
+ str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
+ if (str == NULL)
+ n = 0;
+ else if (argvars[1].v_type == VAR_UNKNOWN)
+ /* only one argument: clear entire history */
+ n = clr_history(get_histtype(str));
+ else if (argvars[1].v_type == VAR_NUMBER)
+ /* index given: remove that entry */
+ n = del_history_idx(get_histtype(str),
+ (int)tv_get_number(&argvars[1]));
+ else
+ /* string given: remove all matching entries */
+ n = del_history_entry(get_histtype(str),
+ tv_get_string_buf(&argvars[1], buf));
+ rettv->vval.v_number = n;
+#endif
+}
+
+/*
+ * "histget()" function
+ */
+ static void
+f_histget(typval_T *argvars UNUSED, typval_T *rettv)
+{
+#ifdef FEAT_CMDHIST
+ int type;
+ int idx;
+ char_u *str;
+
+ str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
+ if (str == NULL)
+ rettv->vval.v_string = NULL;
+ else
+ {
+ type = get_histtype(str);
+ if (argvars[1].v_type == VAR_UNKNOWN)
+ idx = get_history_idx(type);
+ else
+ idx = (int)tv_get_number_chk(&argvars[1], NULL);
+ /* -1 on type error */
+ rettv->vval.v_string = vim_strsave(get_history_entry(type, idx));
+ }
+#else
+ rettv->vval.v_string = NULL;
+#endif
+ rettv->v_type = VAR_STRING;
+}
+
+/*
+ * "histnr()" function
+ */
+ static void
+f_histnr(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ int i;
+
+#ifdef FEAT_CMDHIST
+ char_u *history = tv_get_string_chk(&argvars[0]);
+
+ i = history == NULL ? HIST_CMD - 1 : get_histtype(history);
+ if (i >= HIST_CMD && i < HIST_COUNT)
+ i = get_history_idx(i);
+ else
+#endif
+ i = -1;
+ rettv->vval.v_number = i;
+}
+
+/*
+ * "highlightID(name)" function
+ */
+ static void
+f_hlID(typval_T *argvars, typval_T *rettv)
+{
+ rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
+}
+
+/*
+ * "highlight_exists()" function
+ */
+ static void
+f_hlexists(typval_T *argvars, typval_T *rettv)
+{
+ rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
+}
+
+/*
+ * "hostname()" function
+ */
+ static void
+f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ char_u hostname[256];
+
+ mch_get_host_name(hostname, 256);
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = vim_strsave(hostname);
+}
+
+/*
+ * iconv() function
+ */
+ static void
+f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ char_u buf1[NUMBUFLEN];
+ char_u buf2[NUMBUFLEN];
+ char_u *from, *to, *str;
+ vimconv_T vimconv;
+
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+
+ str = tv_get_string(&argvars[0]);
+ from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
+ to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
+ vimconv.vc_type = CONV_NONE;
+ convert_setup(&vimconv, from, to);
+
+ /* If the encodings are equal, no conversion needed. */
+ if (vimconv.vc_type == CONV_NONE)
+ rettv->vval.v_string = vim_strsave(str);
+ else
+ rettv->vval.v_string = string_convert(&vimconv, str, NULL);
+
+ convert_setup(&vimconv, NULL, NULL);
+ vim_free(from);
+ vim_free(to);
+}
+
+/*
+ * "indent()" function
+ */
+ static void
+f_indent(typval_T *argvars, typval_T *rettv)
+{
+ linenr_T lnum;
+
+ lnum = tv_get_lnum(argvars);
+ if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
+ rettv->vval.v_number = get_indent_lnum(lnum);
+ else
+ rettv->vval.v_number = -1;
+}
+
+/*
+ * "index()" function
+ */
+ static void
+f_index(typval_T *argvars, typval_T *rettv)
+{
+ list_T *l;
+ listitem_T *item;
+ blob_T *b;
+ long idx = 0;
+ int ic = FALSE;
+ int error = FALSE;
+
+ rettv->vval.v_number = -1;
+ if (argvars[0].v_type == VAR_BLOB)
+ {
+ typval_T tv;
+ int start = 0;
+
+ if (argvars[2].v_type != VAR_UNKNOWN)
+ {
+ start = tv_get_number_chk(&argvars[2], &error);
+ if (error)
+ return;
+ }
+ b = argvars[0].vval.v_blob;
+ if (b == NULL)
+ return;
+ if (start < 0)
+ {
+ start = blob_len(b) + start;
+ if (start < 0)
+ start = 0;
+ }
+
+ for (idx = start; idx < blob_len(b); ++idx)
+ {
+ tv.v_type = VAR_NUMBER;
+ tv.vval.v_number = blob_get(b, idx);
+ if (tv_equal(&tv, &argvars[1], ic, FALSE))
+ {
+ rettv->vval.v_number = idx;
+ return;
+ }
+ }
+ return;
+ }
+ else if (argvars[0].v_type != VAR_LIST)
+ {
+ emsg(_(e_listblobreq));
+ return;
+ }
+
+ l = argvars[0].vval.v_list;
+ if (l != NULL)
+ {
+ item = l->lv_first;
+ if (argvars[2].v_type != VAR_UNKNOWN)
+ {
+ /* Start at specified item. Use the cached index that list_find()
+ * sets, so that a negative number also works. */
+ item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
+ idx = l->lv_idx;
+ if (argvars[3].v_type != VAR_UNKNOWN)
+ ic = (int)tv_get_number_chk(&argvars[3], &error);
+ if (error)
+ item = NULL;
+ }
+
+ for ( ; item != NULL; item = item->li_next, ++idx)
+ if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
+ {
+ rettv->vval.v_number = idx;
+ break;
+ }
+ }
+}
+
+static int inputsecret_flag = 0;
+
+/*
+ * "input()" function
+ * Also handles inputsecret() when inputsecret is set.
+ */
+ static void
+f_input(typval_T *argvars, typval_T *rettv)
+{
+ get_user_input(argvars, rettv, FALSE, inputsecret_flag);
+}
+
+/*
+ * "inputdialog()" function
+ */
+ static void
+f_inputdialog(typval_T *argvars, typval_T *rettv)
+{
+#if defined(FEAT_GUI_TEXTDIALOG)
+ /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
+ if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
+ {
+ char_u *message;
+ char_u buf[NUMBUFLEN];
+ char_u *defstr = (char_u *)"";
+
+ message = tv_get_string_chk(&argvars[0]);
+ if (argvars[1].v_type != VAR_UNKNOWN
+ && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
+ vim_strncpy(IObuff, defstr, IOSIZE - 1);
+ else
+ IObuff[0] = NUL;
+ if (message != NULL && defstr != NULL
+ && do_dialog(VIM_QUESTION, NULL, message,
+ (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
+ rettv->vval.v_string = vim_strsave(IObuff);
+ else
+ {
+ if (message != NULL && defstr != NULL
+ && argvars[1].v_type != VAR_UNKNOWN
+ && argvars[2].v_type != VAR_UNKNOWN)
+ rettv->vval.v_string = vim_strsave(
+ tv_get_string_buf(&argvars[2], buf));
+ else
+ rettv->vval.v_string = NULL;
+ }
+ rettv->v_type = VAR_STRING;
+ }
+ else
+#endif
+ get_user_input(argvars, rettv, TRUE, inputsecret_flag);
+}
+
+/*
+ * "inputlist()" function
+ */
+ static void
+f_inputlist(typval_T *argvars, typval_T *rettv)
+{
+ listitem_T *li;
+ int selected;
+ int mouse_used;
+
+#ifdef NO_CONSOLE_INPUT
+ /* While starting up, there is no place to enter text. When running tests
+ * with --not-a-term we assume feedkeys() will be used. */
+ if (no_console_input() && !is_not_a_term())
+ return;
+#endif
+ if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
+ {
+ semsg(_(e_listarg), "inputlist()");
+ return;
+ }
+
+ msg_start();
+ msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
+ lines_left = Rows; /* avoid more prompt */
+ msg_scroll = TRUE;
+ msg_clr_eos();
+
+ for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
+ {
+ msg_puts((char *)tv_get_string(&li->li_tv));
+ msg_putchar('\n');
+ }
+
+ /* Ask for choice. */
+ selected = prompt_for_number(&mouse_used);
+ if (mouse_used)
+ selected -= lines_left;
+
+ rettv->vval.v_number = selected;
+}
+
+static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
+
+/*
+ * "inputrestore()" function
+ */
+ static void
+f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ if (ga_userinput.ga_len > 0)
+ {
+ --ga_userinput.ga_len;
+ restore_typeahead((tasave_T *)(ga_userinput.ga_data)
+ + ga_userinput.ga_len);
+ /* default return is zero == OK */
+ }
+ else if (p_verbose > 1)
+ {
+ verb_msg(_("called inputrestore() more often than inputsave()"));
+ rettv->vval.v_number = 1; /* Failed */
+ }
+}
+
+/*
+ * "inputsave()" function
+ */
+ static void
+f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ /* Add an entry to the stack of typeahead storage. */
+ if (ga_grow(&ga_userinput, 1) == OK)
+ {
+ save_typeahead((tasave_T *)(ga_userinput.ga_data)
+ + ga_userinput.ga_len);
+ ++ga_userinput.ga_len;
+ /* default return is zero == OK */
+ }
+ else
+ rettv->vval.v_number = 1; /* Failed */
+}
+
+/*
+ * "inputsecret()" function
+ */
+ static void
+f_inputsecret(typval_T *argvars, typval_T *rettv)
+{
+ ++cmdline_star;
+ ++inputsecret_flag;
+ f_input(argvars, rettv);
+ --cmdline_star;
+ --inputsecret_flag;
+}
+
+/*
+ * "insert()" function
+ */
+ static void
+f_insert(typval_T *argvars, typval_T *rettv)
+{
+ long before = 0;
+ listitem_T *item;
+ list_T *l;
+ int error = FALSE;
+
+ if (argvars[0].v_type == VAR_BLOB)
+ {
+ int val, len;
+ char_u *p;
+
+ len = blob_len(argvars[0].vval.v_blob);
+ if (argvars[2].v_type != VAR_UNKNOWN)
+ {
+ before = (long)tv_get_number_chk(&argvars[2], &error);
+ if (error)
+ return; // type error; errmsg already given
+ if (before < 0 || before > len)
+ {
+ semsg(_(e_invarg2), tv_get_string(&argvars[2]));
+ return;
+ }
+ }
+ val = tv_get_number_chk(&argvars[1], &error);
+ if (error)
+ return;
+ if (val < 0 || val > 255)
+ {
+ semsg(_(e_invarg2), tv_get_string(&argvars[1]));
+ return;
+ }
+
+ if (ga_grow(&argvars[0].vval.v_blob->bv_ga, 1) == FAIL)
+ return;
+ p = (char_u *)argvars[0].vval.v_blob->bv_ga.ga_data;
+ mch_memmove(p + before + 1, p + before, (size_t)len - before);
+ *(p + before) = val;
+ ++argvars[0].vval.v_blob->bv_ga.ga_len;
+
+ copy_tv(&argvars[0], rettv);
+ }
+ else if (argvars[0].v_type != VAR_LIST)
+ semsg(_(e_listblobarg), "insert()");
+ else if ((l = argvars[0].vval.v_list) != NULL && !tv_check_lock(l->lv_lock,
+ (char_u *)N_("insert() argument"), TRUE))
+ {
+ if (argvars[2].v_type != VAR_UNKNOWN)
+ before = (long)tv_get_number_chk(&argvars[2], &error);
+ if (error)
+ return; /* type error; errmsg already given */
+
+ if (before == l->lv_len)
+ item = NULL;
+ else
+ {
+ item = list_find(l, before);
+ if (item == NULL)
+ {
+ semsg(_(e_listidx), before);
+ l = NULL;
+ }
+ }
+ if (l != NULL)
+ {
+ list_insert_tv(l, &argvars[1], item);
+ copy_tv(&argvars[0], rettv);
+ }
+ }
+}
+
+/*
+ * "invert(expr)" function
+ */
+ static void
+f_invert(typval_T *argvars, typval_T *rettv)
+{
+ rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
+}
+
+/*
+ * "isdirectory()" function
+ */
+ static void
+f_isdirectory(typval_T *argvars, typval_T *rettv)
+{
+ rettv->vval.v_number = mch_isdir(tv_get_string(&argvars[0]));
+}
+
+/*
+ * Return TRUE if typeval "tv" is locked: Either that value is locked itself
+ * or it refers to a List or Dictionary that is locked.
+ */
+ static int
+tv_islocked(typval_T *tv)
+{
+ return (tv->v_lock & VAR_LOCKED)
+ || (tv->v_type == VAR_LIST
+ && tv->vval.v_list != NULL
+ && (tv->vval.v_list->lv_lock & VAR_LOCKED))
+ || (tv->v_type == VAR_DICT
+ && tv->vval.v_dict != NULL
+ && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
+}
+
+/*
+ * "islocked()" function
+ */
+ static void
+f_islocked(typval_T *argvars, typval_T *rettv)
+{
+ lval_T lv;
+ char_u *end;
+ dictitem_T *di;
+
+ rettv->vval.v_number = -1;
+ end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
+ GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
+ if (end != NULL && lv.ll_name != NULL)
+ {
+ if (*end != NUL)
+ emsg(_(e_trailing));
+ else
+ {
+ if (lv.ll_tv == NULL)
+ {
+ di = find_var(lv.ll_name, NULL, TRUE);
+ if (di != NULL)
+ {
+ /* Consider a variable locked when:
+ * 1. the variable itself is locked
+ * 2. the value of the variable is locked.
+ * 3. the List or Dict value is locked.
+ */
+ rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
+ || tv_islocked(&di->di_tv));
+ }
+ }
+ else if (lv.ll_range)
+ emsg(_("E786: Range not allowed"));
+ else if (lv.ll_newkey != NULL)
+ semsg(_(e_dictkey), lv.ll_newkey);
+ else if (lv.ll_list != NULL)
+ /* List item. */
+ rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
+ else
+ /* Dictionary item. */
+ rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
+ }
+ }
+
+ clear_lval(&lv);
+}
+
+#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
+/*
+ * "isnan()" function
+ */
+ static void
+f_isnan(typval_T *argvars, typval_T *rettv)
+{
+ rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
+ && isnan(argvars[0].vval.v_float);
+}
+#endif
+
+/*
+ * "items(dict)" function
+ */
+ static void
+f_items(typval_T *argvars, typval_T *rettv)
+{
+ dict_list(argvars, rettv, 2);
+}
+
+#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
+/*
+ * Get the job from the argument.
+ * Returns NULL if the job is invalid.
+ */
+ static job_T *
+get_job_arg(typval_T *tv)
+{
+ job_T *job;
+
+ if (tv->v_type != VAR_JOB)
+ {
+ semsg(_(e_invarg2), tv_get_string(tv));
+ return NULL;
+ }
+ job = tv->vval.v_job;
+
+ if (job == NULL)
+ emsg(_("E916: not a valid job"));
+ return job;
+}
+
+/*
+ * "job_getchannel()" function
+ */
+ static void
+f_job_getchannel(typval_T *argvars, typval_T *rettv)
+{
+ job_T *job = get_job_arg(&argvars[0]);
+
+ if (job != NULL)
+ {
+ rettv->v_type = VAR_CHANNEL;
+ rettv->vval.v_channel = job->jv_channel;
+ if (job->jv_channel != NULL)
+ ++job->jv_channel->ch_refcount;
+ }
+}
+
+/*
+ * "job_info()" function
+ */
+ static void
+f_job_info(typval_T *argvars, typval_T *rettv)
+{
+ if (argvars[0].v_type != VAR_UNKNOWN)
+ {
+ job_T *job = get_job_arg(&argvars[0]);
+
+ if (job != NULL && rettv_dict_alloc(rettv) != FAIL)
+ job_info(job, rettv->vval.v_dict);
+ }
+ else if (rettv_list_alloc(rettv) == OK)
+ job_info_all(rettv->vval.v_list);
+}
+
+/*
+ * "job_setoptions()" function
+ */
+ static void
+f_job_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
+{
+ job_T *job = get_job_arg(&argvars[0]);
+ jobopt_T opt;
+
+ if (job == NULL)
+ return;
+ clear_job_options(&opt);
+ if (get_job_options(&argvars[1], &opt, JO_STOPONEXIT + JO_EXIT_CB, 0) == OK)
+ job_set_options(job, &opt);
+ free_job_options(&opt);
+}
+
+/*
+ * "job_start()" function
+ */
+ static void
+f_job_start(typval_T *argvars, typval_T *rettv)
+{
+ rettv->v_type = VAR_JOB;
+ if (check_restricted() || check_secure())
+ return;
+ rettv->vval.v_job = job_start(argvars, NULL, NULL, FALSE);
+}
+
+/*
+ * "job_status()" function
+ */
+ static void
+f_job_status(typval_T *argvars, typval_T *rettv)
+{
+ job_T *job = get_job_arg(&argvars[0]);
+
+ if (job != NULL)
+ {
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = vim_strsave((char_u *)job_status(job));
+ }
+}
+
+/*
+ * "job_stop()" function
+ */
+ static void
+f_job_stop(typval_T *argvars, typval_T *rettv)
+{
+ job_T *job = get_job_arg(&argvars[0]);
+
+ if (job != NULL)
+ rettv->vval.v_number = job_stop(job, argvars, NULL);
+}
+#endif
+
+/*
+ * "join()" function
+ */
+ static void
+f_join(typval_T *argvars, typval_T *rettv)
+{
+ garray_T ga;
+ char_u *sep;
+
+ if (argvars[0].v_type != VAR_LIST)
+ {
+ emsg(_(e_listreq));
+ return;
+ }
+ if (argvars[0].vval.v_list == NULL)
+ return;
+ if (argvars[1].v_type == VAR_UNKNOWN)
+ sep = (char_u *)" ";
+ else
+ sep = tv_get_string_chk(&argvars[1]);
+
+ rettv->v_type = VAR_STRING;
+
+ if (sep != NULL)
+ {
+ ga_init2(&ga, (int)sizeof(char), 80);
+ list_join(&ga, argvars[0].vval.v_list, sep, TRUE, FALSE, 0);
+ ga_append(&ga, NUL);
+ rettv->vval.v_string = (char_u *)ga.ga_data;
+ }
+ else
+ rettv->vval.v_string = NULL;
+}
+
+/*
+ * "js_decode()" function
+ */
+ static void
+f_js_decode(typval_T *argvars, typval_T *rettv)
+{
+ js_read_T reader;
+
+ reader.js_buf = tv_get_string(&argvars[0]);
+ reader.js_fill = NULL;
+ reader.js_used = 0;
+ if (json_decode_all(&reader, rettv, JSON_JS) != OK)
+ emsg(_(e_invarg));
+}
+
+/*
+ * "js_encode()" function
+ */
+ static void
+f_js_encode(typval_T *argvars, typval_T *rettv)
+{
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = json_encode(&argvars[0], JSON_JS);
+}
+
+/*
+ * "json_decode()" function
+ */
+ static void
+f_json_decode(typval_T *argvars, typval_T *rettv)
+{
+ js_read_T reader;
+
+ reader.js_buf = tv_get_string(&argvars[0]);
+ reader.js_fill = NULL;
+ reader.js_used = 0;
+ json_decode_all(&reader, rettv, 0);
+}
+
+/*
+ * "json_encode()" function
+ */
+ static void
+f_json_encode(typval_T *argvars, typval_T *rettv)
+{
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = json_encode(&argvars[0], 0);
+}
+
+/*
+ * "keys()" function
+ */
+ static void
+f_keys(typval_T *argvars, typval_T *rettv)
+{
+ dict_list(argvars, rettv, 0);
+}
+
+/*
+ * "last_buffer_nr()" function.
+ */
+ static void
+f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ int n = 0;
+ buf_T *buf;
+
+ FOR_ALL_BUFFERS(buf)
+ if (n < buf->b_fnum)
+ n = buf->b_fnum;
+
+ rettv->vval.v_number = n;
+}
+
+/*
+ * "len()" function
+ */
+ static void
+f_len(typval_T *argvars, typval_T *rettv)
+{
+ switch (argvars[0].v_type)
+ {
+ case VAR_STRING:
+ case VAR_NUMBER:
+ rettv->vval.v_number = (varnumber_T)STRLEN(
+ tv_get_string(&argvars[0]));
+ break;
+ case VAR_BLOB:
+ rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
+ break;
+ case VAR_LIST:
+ rettv->vval.v_number = list_len(argvars[0].vval.v_list);
+ break;
+ case VAR_DICT:
+ rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
+ break;
+ case VAR_UNKNOWN:
+ case VAR_SPECIAL:
+ case VAR_FLOAT:
+ case VAR_FUNC:
+ case VAR_PARTIAL:
+ case VAR_JOB:
+ case VAR_CHANNEL:
+ emsg(_("E701: Invalid type for len()"));
+ break;
+ }
+}
+
+ static void
+libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
+{
+#ifdef FEAT_LIBCALL
+ char_u *string_in;
+ char_u **string_result;
+ int nr_result;
+#endif
+
+ rettv->v_type = type;
+ if (type != VAR_NUMBER)
+ rettv->vval.v_string = NULL;
+
+ if (check_restricted() || check_secure())
+ return;
+
+#ifdef FEAT_LIBCALL
+ /* The first two args must be strings, otherwise it's meaningless */
+ if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
+ {
+ string_in = NULL;
+ if (argvars[2].v_type == VAR_STRING)
+ string_in = argvars[2].vval.v_string;
+ if (type == VAR_NUMBER)
+ string_result = NULL;
+ else
+ string_result = &rettv->vval.v_string;
+ if (mch_libcall(argvars[0].vval.v_string,
+ argvars[1].vval.v_string,
+ string_in,
+ argvars[2].vval.v_number,
+ string_result,
+ &nr_result) == OK
+ && type == VAR_NUMBER)
+ rettv->vval.v_number = nr_result;
+ }
+#endif
+}
+
+/*
+ * "libcall()" function
+ */
+ static void
+f_libcall(typval_T *argvars, typval_T *rettv)
+{
+ libcall_common(argvars, rettv, VAR_STRING);
+}
+
+/*
+ * "libcallnr()" function
+ */
+ static void
+f_libcallnr(typval_T *argvars, typval_T *rettv)
+{
+ libcall_common(argvars, rettv, VAR_NUMBER);
+}
+
+/*
+ * "line(string)" function
+ */
+ static void
+f_line(typval_T *argvars, typval_T *rettv)
+{
+ linenr_T lnum = 0;
+ pos_T *fp;
+ int fnum;
+
+ fp = var2fpos(&argvars[0], TRUE, &fnum);
+ if (fp != NULL)
+ lnum = fp->lnum;
+ rettv->vval.v_number = lnum;
+}
+
+/*
+ * "line2byte(lnum)" function
+ */
+ static void
+f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
+{
+#ifndef FEAT_BYTEOFF
+ rettv->vval.v_number = -1;
+#else
+ linenr_T lnum;
+
+ lnum = tv_get_lnum(argvars);
+ if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
+ rettv->vval.v_number = -1;
+ else
+ rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
+ if (rettv->vval.v_number >= 0)
+ ++rettv->vval.v_number;
+#endif
+}
+
+/*
+ * "lispindent(lnum)" function
+ */
+ static void
+f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
+{
+#ifdef FEAT_LISP
+ pos_T pos;
+ linenr_T lnum;
+
+ pos = curwin->w_cursor;
+ lnum = tv_get_lnum(argvars);
+ if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
+ {
+ curwin->w_cursor.lnum = lnum;
+ rettv->vval.v_number = get_lisp_indent();
+ curwin->w_cursor = pos;
+ }
+ else
+#endif
+ rettv->vval.v_number = -1;
+}
+
+/*
+ * "localtime()" function
+ */
+ static void
+f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ rettv->vval.v_number = (varnumber_T)time(NULL);
+}
+
+ static void
+get_maparg(typval_T *argvars, typval_T *rettv, int exact)
+{
+ char_u *keys;
+ char_u *which;
+ char_u buf[NUMBUFLEN];
+ char_u *keys_buf = NULL;
+ char_u *rhs;
+ int mode;
+ int abbr = FALSE;
+ int get_dict = FALSE;
+ mapblock_T *mp;
+ int buffer_local;
+
+ /* return empty string for failure */
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+
+ keys = tv_get_string(&argvars[0]);
+ if (*keys == NUL)
+ return;
+
+ if (argvars[1].v_type != VAR_UNKNOWN)
+ {
+ which = tv_get_string_buf_chk(&argvars[1], buf);
+ if (argvars[2].v_type != VAR_UNKNOWN)
+ {
+ abbr = (int)tv_get_number(&argvars[2]);
+ if (argvars[3].v_type != VAR_UNKNOWN)
+ get_dict = (int)tv_get_number(&argvars[3]);
+ }
+ }
+ else
+ which = (char_u *)"";
+ if (which == NULL)
+ return;
+
+ mode = get_map_mode(&which, 0);
+
+ keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE);
+ rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local);
+ vim_free(keys_buf);
+
+ if (!get_dict)
+ {
+ /* Return a string. */
+ if (rhs != NULL)
+ {
+ if (*rhs == NUL)
+ rettv->vval.v_string = vim_strsave((char_u *)"<Nop>");
+ else
+ rettv->vval.v_string = str2special_save(rhs, FALSE);
+ }
+
+ }
+ else if (rettv_dict_alloc(rettv) != FAIL && rhs != NULL)
+ {
+ /* Return a dictionary. */
+ char_u *lhs = str2special_save(mp->m_keys, TRUE);
+ char_u *mapmode = map_mode_to_chars(mp->m_mode);
+ dict_T *dict = rettv->vval.v_dict;
+
+ dict_add_string(dict, "lhs", lhs);
+ dict_add_string(dict, "rhs", mp->m_orig_str);
+ dict_add_number(dict, "noremap", mp->m_noremap ? 1L : 0L);
+ dict_add_number(dict, "expr", mp->m_expr ? 1L : 0L);
+ dict_add_number(dict, "silent", mp->m_silent ? 1L : 0L);
+ dict_add_number(dict, "sid", (long)mp->m_script_ctx.sc_sid);
+ dict_add_number(dict, "lnum", (long)mp->m_script_ctx.sc_lnum);
+ dict_add_number(dict, "buffer", (long)buffer_local);
+ dict_add_number(dict, "nowait", mp->m_nowait ? 1L : 0L);
+ dict_add_string(dict, "mode", mapmode);
+
+ vim_free(lhs);
+ vim_free(mapmode);
+ }
+}
+
+#ifdef FEAT_FLOAT
+/*
+ * "log()" function
+ */
+ static void
+f_log(typval_T *argvars, typval_T *rettv)
+{
+ float_T f = 0.0;
+
+ rettv->v_type = VAR_FLOAT;
+ if (get_float_arg(argvars, &f) == OK)
+ rettv->vval.v_float = log(f);
+ else
+ rettv->vval.v_float = 0.0;
+}
+
+/*
+ * "log10()" function
+ */
+ static void
+f_log10(typval_T *argvars, typval_T *rettv)
+{
+ float_T f = 0.0;
+
+ rettv->v_type = VAR_FLOAT;
+ if (get_float_arg(argvars, &f) == OK)
+ rettv->vval.v_float = log10(f);
+ else
+ rettv->vval.v_float = 0.0;
+}
+#endif
+
+#ifdef FEAT_LUA
+/*
+ * "luaeval()" function
+ */
+ static void
+f_luaeval(typval_T *argvars, typval_T *rettv)
+{
+ char_u *str;
+ char_u buf[NUMBUFLEN];
+
+ str = tv_get_string_buf(&argvars[0], buf);
+ do_luaeval(str, argvars + 1, rettv);
+}
+#endif
+
+/*
+ * "map()" function
+ */
+ static void
+f_map(typval_T *argvars, typval_T *rettv)
+{
+ filter_map(argvars, rettv, TRUE);
+}
+
+/*
+ * "maparg()" function
+ */
+ static void
+f_maparg(typval_T *argvars, typval_T *rettv)
+{
+ get_maparg(argvars, rettv, TRUE);
+}
+
+/*
+ * "mapcheck()" function
+ */
+ static void
+f_mapcheck(typval_T *argvars, typval_T *rettv)
+{
+ get_maparg(argvars, rettv, FALSE);
+}
+
+typedef enum
+{
+ MATCH_END, /* matchend() */
+ MATCH_MATCH, /* match() */
+ MATCH_STR, /* matchstr() */
+ MATCH_LIST, /* matchlist() */
+ MATCH_POS /* matchstrpos() */
+} matchtype_T;
+
+ static void
+find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
+{
+ char_u *str = NULL;
+ long len = 0;
+ char_u *expr = NULL;
+ char_u *pat;
+ regmatch_T regmatch;
+ char_u patbuf[NUMBUFLEN];
+ char_u strbuf[NUMBUFLEN];
+ char_u *save_cpo;
+ long start = 0;
+ long nth = 1;
+ colnr_T startcol = 0;
+ int match = 0;
+ list_T *l = NULL;
+ listitem_T *li = NULL;
+ long idx = 0;
+ char_u *tofree = NULL;
+
+ /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
+ save_cpo = p_cpo;
+ p_cpo = (char_u *)"";
+
+ rettv->vval.v_number = -1;
+ if (type == MATCH_LIST || type == MATCH_POS)
+ {
+ /* type MATCH_LIST: return empty list when there are no matches.
+ * type MATCH_POS: return ["", -1, -1, -1] */
+ if (rettv_list_alloc(rettv) == FAIL)
+ goto theend;
+ if (type == MATCH_POS
+ && (list_append_string(rettv->vval.v_list,
+ (char_u *)"", 0) == FAIL
+ || list_append_number(rettv->vval.v_list,
+ (varnumber_T)-1) == FAIL
+ || list_append_number(rettv->vval.v_list,
+ (varnumber_T)-1) == FAIL
+ || list_append_number(rettv->vval.v_list,
+ (varnumber_T)-1) == FAIL))
+ {
+ list_free(rettv->vval.v_list);
+ rettv->vval.v_list = NULL;
+ goto theend;
+ }
+ }
+ else if (type == MATCH_STR)
+ {
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+ }
+
+ if (argvars[0].v_type == VAR_LIST)
+ {
+ if ((l = argvars[0].vval.v_list) == NULL)
+ goto theend;
+ li = l->lv_first;
+ }
+ else
+ {
+ expr = str = tv_get_string(&argvars[0]);
+ len = (long)STRLEN(str);
+ }
+
+ pat = tv_get_string_buf_chk(&argvars[1], patbuf);
+ if (pat == NULL)
+ goto theend;
+
+ if (argvars[2].v_type != VAR_UNKNOWN)
+ {
+ int error = FALSE;
+
+ start = (long)tv_get_number_chk(&argvars[2], &error);
+ if (error)
+ goto theend;
+ if (l != NULL)
+ {
+ li = list_find(l, start);
+ if (li == NULL)
+ goto theend;
+ idx = l->lv_idx; /* use the cached index */
+ }
+ else
+ {
+ if (start < 0)
+ start = 0;
+ if (start > len)
+ goto theend;
+ /* When "count" argument is there ignore matches before "start",
+ * otherwise skip part of the string. Differs when pattern is "^"
+ * or "\<". */
+ if (argvars[3].v_type != VAR_UNKNOWN)
+ startcol = start;
+ else
+ {
+ str += start;
+ len -= start;
+ }
+ }
+
+ if (argvars[3].v_type != VAR_UNKNOWN)
+ nth = (long)tv_get_number_chk(&argvars[3], &error);
+ if (error)
+ goto theend;
+ }
+
+ regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
+ if (regmatch.regprog != NULL)
+ {
+ regmatch.rm_ic = p_ic;
+
+ for (;;)
+ {
+ if (l != NULL)
+ {
+ if (li == NULL)
+ {
+ match = FALSE;
+ break;
+ }
+ vim_free(tofree);
+ expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
+ if (str == NULL)
+ break;
+ }
+
+ match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
+
+ if (match && --nth <= 0)
+ break;
+ if (l == NULL && !match)
+ break;
+
+ /* Advance to just after the match. */
+ if (l != NULL)
+ {
+ li = li->li_next;
+ ++idx;
+ }
+ else
+ {
+ startcol = (colnr_T)(regmatch.startp[0]
+ + (*mb_ptr2len)(regmatch.startp[0]) - str);
+ if (startcol > (colnr_T)len
+ || str + startcol <= regmatch.startp[0])
+ {
+ match = FALSE;
+ break;
+ }
+ }
+ }
+
+ if (match)
+ {
+ if (type == MATCH_POS)
+ {
+ listitem_T *li1 = rettv->vval.v_list->lv_first;
+ listitem_T *li2 = li1->li_next;
+ listitem_T *li3 = li2->li_next;
+ listitem_T *li4 = li3->li_next;
+
+ vim_free(li1->li_tv.vval.v_string);
+ li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
+ (int)(regmatch.endp[0] - regmatch.startp[0]));
+ li3->li_tv.vval.v_number =
+ (varnumber_T)(regmatch.startp[0] - expr);
+ li4->li_tv.vval.v_number =
+ (varnumber_T)(regmatch.endp[0] - expr);
+ if (l != NULL)
+ li2->li_tv.vval.v_number = (varnumber_T)idx;
+ }
+ else if (type == MATCH_LIST)
+ {
+ int i;
+
+ /* return list with matched string and submatches */
+ for (i = 0; i < NSUBEXP; ++i)
+ {
+ if (regmatch.endp[i] == NULL)
+ {
+ if (list_append_string(rettv->vval.v_list,
+ (char_u *)"", 0) == FAIL)
+ break;
+ }
+ else if (list_append_string(rettv->vval.v_list,
+ regmatch.startp[i],
+ (int)(regmatch.endp[i] - regmatch.startp[i]))
+ == FAIL)
+ break;
+ }
+ }
+ else if (type == MATCH_STR)
+ {
+ /* return matched string */
+ if (l != NULL)
+ copy_tv(&li->li_tv, rettv);
+ else
+ rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
+ (int)(regmatch.endp[0] - regmatch.startp[0]));
+ }
+ else if (l != NULL)
+ rettv->vval.v_number = idx;
+ else
+ {
+ if (type != MATCH_END)
+ rettv->vval.v_number =
+ (varnumber_T)(regmatch.startp[0] - str);
+ else
+ rettv->vval.v_number =
+ (varnumber_T)(regmatch.endp[0] - str);
+ rettv->vval.v_number += (varnumber_T)(str - expr);
+ }
+ }
+ vim_regfree(regmatch.regprog);
+ }
+
+theend:
+ if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
+ /* matchstrpos() without a list: drop the second item. */
+ listitem_remove(rettv->vval.v_list,
+ rettv->vval.v_list->lv_first->li_next);
+ vim_free(tofree);
+ p_cpo = save_cpo;
+}
+
+/*
+ * "match()" function
+ */
+ static void
+f_match(typval_T *argvars, typval_T *rettv)
+{
+ find_some_match(argvars, rettv, MATCH_MATCH);
+}
+
+#ifdef FEAT_SEARCH_EXTRA
+ static int
+matchadd_dict_arg(typval_T *tv, char_u **conceal_char, win_T **win)
+{
+ dictitem_T *di;
+
+ if (tv->v_type != VAR_DICT)
+ {
+ emsg(_(e_dictreq));
+ return FAIL;
+ }
+
+ if (dict_find(tv->vval.v_dict, (char_u *)"conceal", -1) != NULL)
+ *conceal_char = dict_get_string(tv->vval.v_dict,
+ (char_u *)"conceal", FALSE);
+
+ if ((di = dict_find(tv->vval.v_dict, (char_u *)"window", -1)) != NULL)
+ {
+ *win = find_win_by_nr_or_id(&di->di_tv);
+ if (*win == NULL)
+ {
+ emsg(_("E957: Invalid window number"));
+ return FAIL;
+ }
+ }
+
+ return OK;
+}
+#endif
+
+/*
+ * "matchadd()" function
+ */
+ static void
+f_matchadd(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
+{
+#ifdef FEAT_SEARCH_EXTRA
+ char_u buf[NUMBUFLEN];
+ char_u *grp = tv_get_string_buf_chk(&argvars[0], buf); /* group */
+ char_u *pat = tv_get_string_buf_chk(&argvars[1], buf); /* pattern */
+ int prio = 10; /* default priority */
+ int id = -1;
+ int error = FALSE;
+ char_u *conceal_char = NULL;
+ win_T *win = curwin;
+
+ rettv->vval.v_number = -1;
+
+ if (grp == NULL || pat == NULL)
+ return;
+ if (argvars[2].v_type != VAR_UNKNOWN)
+ {
+ prio = (int)tv_get_number_chk(&argvars[2], &error);
+ if (argvars[3].v_type != VAR_UNKNOWN)
+ {
+ id = (int)tv_get_number_chk(&argvars[3], &error);
+ if (argvars[4].v_type != VAR_UNKNOWN
+ && matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL)
+ return;
+ }
+ }
+ if (error == TRUE)
+ return;
+ if (id >= 1 && id <= 3)
+ {
+ semsg(_("E798: ID is reserved for \":match\": %d"), id);
+ return;
+ }
+
+ rettv->vval.v_number = match_add(win, grp, pat, prio, id, NULL,
+ conceal_char);
+#endif
+}
+
+/*
+ * "matchaddpos()" function
+ */
+ static void
+f_matchaddpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
+{
+#ifdef FEAT_SEARCH_EXTRA
+ char_u buf[NUMBUFLEN];
+ char_u *group;
+ int prio = 10;
+ int id = -1;
+ int error = FALSE;
+ list_T *l;
+ char_u *conceal_char = NULL;
+ win_T *win = curwin;
+
+ rettv->vval.v_number = -1;
+
+ group = tv_get_string_buf_chk(&argvars[0], buf);
+ if (group == NULL)
+ return;
+
+ if (argvars[1].v_type != VAR_LIST)
+ {
+ semsg(_(e_listarg), "matchaddpos()");
+ return;
+ }
+ l = argvars[1].vval.v_list;
+ if (l == NULL)
+ return;
+
+ if (argvars[2].v_type != VAR_UNKNOWN)
+ {
+ prio = (int)tv_get_number_chk(&argvars[2], &error);
+ if (argvars[3].v_type != VAR_UNKNOWN)
+ {
+ id = (int)tv_get_number_chk(&argvars[3], &error);
+
+ if (argvars[4].v_type != VAR_UNKNOWN
+ && matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL)
+ return;
+ }
+ }
+ if (error == TRUE)
+ return;
+
+ /* id == 3 is ok because matchaddpos() is supposed to substitute :3match */
+ if (id == 1 || id == 2)
+ {
+ semsg(_("E798: ID is reserved for \":match\": %d"), id);
+ return;
+ }
+
+ rettv->vval.v_number = match_add(win, group, NULL, prio, id, l,
+ conceal_char);
+#endif
+}
+
+/*
+ * "matcharg()" function
+ */
+ static void
+f_matcharg(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ if (rettv_list_alloc(rettv) == OK)
+ {
+#ifdef FEAT_SEARCH_EXTRA
+ int id = (int)tv_get_number(&argvars[0]);
+ matchitem_T *m;
+
+ if (id >= 1 && id <= 3)
+ {
+ if ((m = (matchitem_T *)get_match(curwin, id)) != NULL)
+ {
+ list_append_string(rettv->vval.v_list,
+ syn_id2name(m->hlg_id), -1);
+ list_append_string(rettv->vval.v_list, m->pattern, -1);
+ }
+ else
+ {
+ list_append_string(rettv->vval.v_list, NULL, -1);
+ list_append_string(rettv->vval.v_list, NULL, -1);
+ }
+ }
+#endif
+ }
+}
+
+/*
+ * "matchdelete()" function
+ */
+ static void
+f_matchdelete(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
+{
+#ifdef FEAT_SEARCH_EXTRA
+ rettv->vval.v_number = match_delete(curwin,
+ (int)tv_get_number(&argvars[0]), TRUE);
+#endif
+}
+
+/*
+ * "matchend()" function
+ */
+ static void
+f_matchend(typval_T *argvars, typval_T *rettv)
+{
+ find_some_match(argvars, rettv, MATCH_END);
+}
+
+/*
+ * "matchlist()" function
+ */
+ static void
+f_matchlist(typval_T *argvars, typval_T *rettv)
+{
+ find_some_match(argvars, rettv, MATCH_LIST);
+}
+
+/*
+ * "matchstr()" function
+ */
+ static void
+f_matchstr(typval_T *argvars, typval_T *rettv)
+{
+ find_some_match(argvars, rettv, MATCH_STR);
+}
+
+/*
+ * "matchstrpos()" function
+ */
+ static void
+f_matchstrpos(typval_T *argvars, typval_T *rettv)
+{
+ find_some_match(argvars, rettv, MATCH_POS);
+}
+
+ static void
+max_min(typval_T *argvars, typval_T *rettv, int domax)
+{
+ varnumber_T n = 0;
+ varnumber_T i;
+ int error = FALSE;
+
+ if (argvars[0].v_type == VAR_LIST)
+ {
+ list_T *l;
+ listitem_T *li;
+
+ l = argvars[0].vval.v_list;
+ if (l != NULL)
+ {
+ li = l->lv_first;
+ if (li != NULL)
+ {
+ n = tv_get_number_chk(&li->li_tv, &error);
+ for (;;)
+ {
+ li = li->li_next;
+ if (li == NULL)
+ break;
+ i = tv_get_number_chk(&li->li_tv, &error);
+ if (domax ? i > n : i < n)
+ n = i;
+ }
+ }
+ }
+ }
+ else if (argvars[0].v_type == VAR_DICT)
+ {
+ dict_T *d;
+ int first = TRUE;
+ hashitem_T *hi;
+ int todo;
+
+ d = argvars[0].vval.v_dict;
+ if (d != NULL)
+ {
+ todo = (int)d->dv_hashtab.ht_used;
+ for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
+ {
+ if (!HASHITEM_EMPTY(hi))
+ {
+ --todo;
+ i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
+ if (first)
+ {
+ n = i;
+ first = FALSE;
+ }
+ else if (domax ? i > n : i < n)
+ n = i;
+ }
+ }
+ }
+ }
+ else
+ semsg(_(e_listdictarg), domax ? "max()" : "min()");
+ rettv->vval.v_number = error ? 0 : n;
+}
+
+/*
+ * "max()" function
+ */
+ static void
+f_max(typval_T *argvars, typval_T *rettv)
+{
+ max_min(argvars, rettv, TRUE);
+}
+
+/*
+ * "min()" function
+ */
+ static void
+f_min(typval_T *argvars, typval_T *rettv)
+{
+ max_min(argvars, rettv, FALSE);
+}
+
+/*
+ * Create the directory in which "dir" is located, and higher levels when
+ * needed.
+ * Return OK or FAIL.
+ */
+ static int
+mkdir_recurse(char_u *dir, int prot)
+{
+ char_u *p;
+ char_u *updir;
+ int r = FAIL;
+
+ /* Get end of directory name in "dir".
+ * We're done when it's "/" or "c:/". */
+ p = gettail_sep(dir);
+ if (p <= get_past_head(dir))
+ return OK;
+
+ /* If the directory exists we're done. Otherwise: create it.*/
+ updir = vim_strnsave(dir, (int)(p - dir));
+ if (updir == NULL)
+ return FAIL;
+ if (mch_isdir(updir))
+ r = OK;
+ else if (mkdir_recurse(updir, prot) == OK)
+ r = vim_mkdir_emsg(updir, prot);
+ vim_free(updir);
+ return r;
+}
+
+#ifdef vim_mkdir
+/*
+ * "mkdir()" function
+ */
+ static void
+f_mkdir(typval_T *argvars, typval_T *rettv)
+{
+ char_u *dir;
+ char_u buf[NUMBUFLEN];
+ int prot = 0755;
+
+ rettv->vval.v_number = FAIL;
+ if (check_restricted() || check_secure())
+ return;
+
+ dir = tv_get_string_buf(&argvars[0], buf);
+ if (*dir == NUL)
+ return;
+
+ if (*gettail(dir) == NUL)
+ /* remove trailing slashes */
+ *gettail_sep(dir) = NUL;
+
+ if (argvars[1].v_type != VAR_UNKNOWN)
+ {
+ if (argvars[2].v_type != VAR_UNKNOWN)
+ {
+ prot = (int)tv_get_number_chk(&argvars[2], NULL);
+ if (prot == -1)
+ return;
+ }
+ if (STRCMP(tv_get_string(&argvars[1]), "p") == 0)
+ {
+ if (mch_isdir(dir))
+ {
+ /* With the "p" flag it's OK if the dir already exists. */
+ rettv->vval.v_number = OK;
+ return;
+ }
+ mkdir_recurse(dir, prot);
+ }
+ }
+ rettv->vval.v_number = vim_mkdir_emsg(dir, prot);
+}
+#endif
+
+/*
+ * "mode()" function
+ */
+ static void
+f_mode(typval_T *argvars, typval_T *rettv)
+{
+ char_u buf[4];
+
+ vim_memset(buf, 0, sizeof(buf));
+
+ if (time_for_testing == 93784)
+ {
+ /* Testing the two-character code. */
+ buf[0] = 'x';
+ buf[1] = '!';
+ }
+#ifdef FEAT_TERMINAL
+ else if (term_use_loop())
+ buf[0] = 't';
+#endif
+ else if (VIsual_active)
+ {
+ if (VIsual_select)
+ buf[0] = VIsual_mode + 's' - 'v';
+ else
+ buf[0] = VIsual_mode;
+ }
+ else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
+ || State == CONFIRM)
+ {
+ buf[0] = 'r';
+ if (State == ASKMORE)
+ buf[1] = 'm';
+ else if (State == CONFIRM)
+ buf[1] = '?';
+ }
+ else if (State == EXTERNCMD)
+ buf[0] = '!';
+ else if (State & INSERT)
+ {
+ if (State & VREPLACE_FLAG)
+ {
+ buf[0] = 'R';
+ buf[1] = 'v';
+ }
+ else
+ {
+ if (State & REPLACE_FLAG)
+ buf[0] = 'R';
+ else
+ buf[0] = 'i';
+#ifdef FEAT_INS_EXPAND
+ if (ins_compl_active())
+ buf[1] = 'c';
+ else if (ctrl_x_mode_not_defined_yet())
+ buf[1] = 'x';
+#endif
+ }
+ }
+ else if ((State & CMDLINE) || exmode_active)
+ {
+ buf[0] = 'c';
+ if (exmode_active == EXMODE_VIM)
+ buf[1] = 'v';
+ else if (exmode_active == EXMODE_NORMAL)
+ buf[1] = 'e';
+ }
+ else
+ {
+ buf[0] = 'n';
+ if (finish_op)
+ {
+ buf[1] = 'o';
+ // to be able to detect force-linewise/blockwise/characterwise operations
+ buf[2] = motion_force;
+ }
+ else if (restart_edit == 'I' || restart_edit == 'R'
+ || restart_edit == 'V')
+ {
+ buf[1] = 'i';
+ buf[2] = restart_edit;
+ }
+ }
+
+ /* Clear out the minor mode when the argument is not a non-zero number or
+ * non-empty string. */
+ if (!non_zero_arg(&argvars[0]))
+ buf[1] = NUL;
+
+ rettv->vval.v_string = vim_strsave(buf);
+ rettv->v_type = VAR_STRING;
+}
+
+#if defined(FEAT_MZSCHEME) || defined(PROTO)
+/*
+ * "mzeval()" function
+ */
+ static void
+f_mzeval(typval_T *argvars, typval_T *rettv)
+{
+ char_u *str;
+ char_u buf[NUMBUFLEN];
+
+ str = tv_get_string_buf(&argvars[0], buf);
+ do_mzeval(str, rettv);
+}
+
+ void
+mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
+{
+ typval_T argvars[3];
+
+ argvars[0].v_type = VAR_STRING;
+ argvars[0].vval.v_string = name;
+ copy_tv(args, &argvars[1]);
+ argvars[2].v_type = VAR_UNKNOWN;
+ f_call(argvars, rettv);
+ clear_tv(&argvars[1]);
+}
+#endif
+
+/*
+ * "nextnonblank()" function
+ */
+ static void
+f_nextnonblank(typval_T *argvars, typval_T *rettv)
+{
+ linenr_T lnum;
+
+ for (lnum = tv_get_lnum(argvars); ; ++lnum)
+ {
+ if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
+ {
+ lnum = 0;
+ break;
+ }
+ if (*skipwhite(ml_get(lnum)) != NUL)
+ break;
+ }
+ rettv->vval.v_number = lnum;
+}
+
+/*
+ * "nr2char()" function
+ */
+ static void
+f_nr2char(typval_T *argvars, typval_T *rettv)
+{
+ char_u buf[NUMBUFLEN];
+
+ if (has_mbyte)
+ {
+ int utf8 = 0;
+
+ if (argvars[1].v_type != VAR_UNKNOWN)
+ utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
+ if (utf8)
+ buf[(*utf_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
+ else
+ buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
+ }
+ else
+ {
+ buf[0] = (char_u)tv_get_number(&argvars[0]);
+ buf[1] = NUL;
+ }
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = vim_strsave(buf);
+}
+
+/*
+ * "or(expr, expr)" function
+ */
+ static void
+f_or(typval_T *argvars, typval_T *rettv)
+{
+ rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
+ | tv_get_number_chk(&argvars[1], NULL);
+}
+
+/*
+ * "pathshorten()" function
+ */
+ static void
+f_pathshorten(typval_T *argvars, typval_T *rettv)
+{
+ char_u *p;
+
+ rettv->v_type = VAR_STRING;
+ p = tv_get_string_chk(&argvars[0]);
+ if (p == NULL)
+ rettv->vval.v_string = NULL;
+ else
+ {
+ p = vim_strsave(p);
+ rettv->vval.v_string = p;
+ if (p != NULL)
+ shorten_dir(p);
+ }
+}
+
+#ifdef FEAT_PERL
+/*
+ * "perleval()" function
+ */
+ static void
+f_perleval(typval_T *argvars, typval_T *rettv)
+{
+ char_u *str;
+ char_u buf[NUMBUFLEN];
+
+ str = tv_get_string_buf(&argvars[0], buf);
+ do_perleval(str, rettv);
+}
+#endif
+
+#ifdef FEAT_FLOAT
+/*
+ * "pow()" function
+ */
+ static void
+f_pow(typval_T *argvars, typval_T *rettv)
+{
+ float_T fx = 0.0, fy = 0.0;
+
+ rettv->v_type = VAR_FLOAT;
+ if (get_float_arg(argvars, &fx) == OK
+ && get_float_arg(&argvars[1], &fy) == OK)
+ rettv->vval.v_float = pow(fx, fy);
+ else
+ rettv->vval.v_float = 0.0;
+}
+#endif
+
+/*
+ * "prevnonblank()" function
+ */
+ static void
+f_prevnonblank(typval_T *argvars, typval_T *rettv)
+{
+ linenr_T lnum;
+
+ lnum = tv_get_lnum(argvars);
+ if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
+ lnum = 0;
+ else
+ while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
+ --lnum;
+ rettv->vval.v_number = lnum;
+}
+
+/* This dummy va_list is here because:
+ * - passing a NULL pointer doesn't work when va_list isn't a pointer
+ * - locally in the function results in a "used before set" warning
+ * - using va_start() to initialize it gives "function with fixed args" error */
+static va_list ap;
+
+/*
+ * "printf()" function
+ */
+ static void
+f_printf(typval_T *argvars, typval_T *rettv)
+{
+ char_u buf[NUMBUFLEN];
+ int len;
+ char_u *s;
+ int saved_did_emsg = did_emsg;
+ char *fmt;
+
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+
+ /* Get the required length, allocate the buffer and do it for real. */
+ did_emsg = FALSE;
+ fmt = (char *)tv_get_string_buf(&argvars[0], buf);
+ len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
+ if (!did_emsg)
+ {
+ s = alloc(len + 1);
+ if (s != NULL)
+ {
+ rettv->vval.v_string = s;
+ (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
+ ap, argvars + 1);
+ }
+ }
+ did_emsg |= saved_did_emsg;
+}
+
+#ifdef FEAT_JOB_CHANNEL
+/*
+ * "prompt_setcallback({buffer}, {callback})" function
+ */
+ static void
+f_prompt_setcallback(typval_T *argvars, typval_T *rettv UNUSED)
+{
+ buf_T *buf;
+ char_u *callback;
+ partial_T *partial;
+
+ if (check_secure())
+ return;
+ buf = tv_get_buf(&argvars[0], FALSE);
+ if (buf == NULL)
+ return;
+
+ callback = get_callback(&argvars[1], &partial);
+ if (callback == NULL)
+ return;
+
+ free_callback(buf->b_prompt_callback, buf->b_prompt_partial);
+ if (partial == NULL)
+ buf->b_prompt_callback = vim_strsave(callback);
+ else
+ /* pointer into the partial */
+ buf->b_prompt_callback = callback;
+ buf->b_prompt_partial = partial;
+}
+
+/*
+ * "prompt_setinterrupt({buffer}, {callback})" function
+ */
+ static void
+f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv UNUSED)
+{
+ buf_T *buf;
+ char_u *callback;
+ partial_T *partial;
+
+ if (check_secure())
+ return;
+ buf = tv_get_buf(&argvars[0], FALSE);
+ if (buf == NULL)
+ return;
+
+ callback = get_callback(&argvars[1], &partial);
+ if (callback == NULL)
+ return;
+
+ free_callback(buf->b_prompt_interrupt, buf->b_prompt_int_partial);
+ if (partial == NULL)
+ buf->b_prompt_interrupt = vim_strsave(callback);
+ else
+ /* pointer into the partial */
+ buf->b_prompt_interrupt = callback;
+ buf->b_prompt_int_partial = partial;
+}
+
+/*
+ * "prompt_setprompt({buffer}, {text})" function
+ */
+ static void
+f_prompt_setprompt(typval_T *argvars, typval_T *rettv UNUSED)
+{
+ buf_T *buf;
+ char_u *text;
+
+ if (check_secure())
+ return;
+ buf = tv_get_buf(&argvars[0], FALSE);
+ if (buf == NULL)
+ return;
+
+ text = tv_get_string(&argvars[1]);
+ vim_free(buf->b_prompt_text);
+ buf->b_prompt_text = vim_strsave(text);
+}
+#endif
+
+/*
+ * "pumvisible()" function
+ */
+ static void
+f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
+{
+#ifdef FEAT_INS_EXPAND
+ if (pum_visible())
+ rettv->vval.v_number = 1;
+#endif
+}
+
+#ifdef FEAT_PYTHON3
+/*
+ * "py3eval()" function
+ */
+ static void
+f_py3eval(typval_T *argvars, typval_T *rettv)
+{
+ char_u *str;
+ char_u buf[NUMBUFLEN];
+
+ if (p_pyx == 0)
+ p_pyx = 3;
+
+ str = tv_get_string_buf(&argvars[0], buf);
+ do_py3eval(str, rettv);
+}
+#endif
+
+#ifdef FEAT_PYTHON
+/*
+ * "pyeval()" function
+ */
+ static void
+f_pyeval(typval_T *argvars, typval_T *rettv)
+{
+ char_u *str;
+ char_u buf[NUMBUFLEN];
+
+ if (p_pyx == 0)
+ p_pyx = 2;
+
+ str = tv_get_string_buf(&argvars[0], buf);
+ do_pyeval(str, rettv);
+}
+#endif
+
+#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
+/*
+ * "pyxeval()" function
+ */
+ static void
+f_pyxeval(typval_T *argvars, typval_T *rettv)
+{
+# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
+ init_pyxversion();
+ if (p_pyx == 2)
+ f_pyeval(argvars, rettv);
+ else
+ f_py3eval(argvars, rettv);
+# elif defined(FEAT_PYTHON)
+ f_pyeval(argvars, rettv);
+# elif defined(FEAT_PYTHON3)
+ f_py3eval(argvars, rettv);
+# endif
+}
+#endif
+
+/*
+ * "range()" function
+ */
+ static void
+f_range(typval_T *argvars, typval_T *rettv)
+{
+ varnumber_T start;
+ varnumber_T end;
+ varnumber_T stride = 1;
+ varnumber_T i;
+ int error = FALSE;
+
+ start = tv_get_number_chk(&argvars[0], &error);
+ if (argvars[1].v_type == VAR_UNKNOWN)
+ {
+ end = start - 1;
+ start = 0;
+ }
+ else
+ {
+ end = tv_get_number_chk(&argvars[1], &error);
+ if (argvars[2].v_type != VAR_UNKNOWN)
+ stride = tv_get_number_chk(&argvars[2], &error);
+ }
+
+ if (error)
+ return; /* type error; errmsg already given */
+ if (stride == 0)
+ emsg(_("E726: Stride is zero"));
+ else if (stride > 0 ? end + 1 < start : end - 1 > start)
+ emsg(_("E727: Start past end"));
+ else
+ {
+ if (rettv_list_alloc(rettv) == OK)
+ for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
+ if (list_append_number(rettv->vval.v_list,
+ (varnumber_T)i) == FAIL)
+ break;
+ }
+}
+
+/*
+ * "readfile()" function
+ */
+ static void
+f_readfile(typval_T *argvars, typval_T *rettv)
+{
+ int binary = FALSE;
+ int blob = FALSE;
+ int failed = FALSE;
+ char_u *fname;
+ FILE *fd;
+ char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */
+ int io_size = sizeof(buf);
+ int readlen; /* size of last fread() */
+ char_u *prev = NULL; /* previously read bytes, if any */
+ long prevlen = 0; /* length of data in prev */
+ long prevsize = 0; /* size of prev buffer */
+ long maxline = MAXLNUM;
+ long cnt = 0;
+ char_u *p; /* position in buf */
+ char_u *start; /* start of current line */
+
+ if (argvars[1].v_type != VAR_UNKNOWN)
+ {
+ if (STRCMP(tv_get_string(&argvars[1]), "b") == 0)
+ binary = TRUE;
+ if (STRCMP(tv_get_string(&argvars[1]), "B") == 0)
+ blob = TRUE;
+
+ if (argvars[2].v_type != VAR_UNKNOWN)
+ maxline = (long)tv_get_number(&argvars[2]);
+ }
+
+ if (blob)
+ {
+ if (rettv_blob_alloc(rettv) == FAIL)
+ return;
+ }
+ else
+ {
+ if (rettv_list_alloc(rettv) == FAIL)
+ return;
+ }
+
+ /* Always open the file in binary mode, library functions have a mind of
+ * their own about CR-LF conversion. */
+ fname = tv_get_string(&argvars[0]);
+ if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
+ {
+ semsg(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
+ return;
+ }
+
+ if (blob)
+ {
+ if (read_blob(fd, rettv->vval.v_blob) == FAIL)
+ {
+ emsg("cannot read file");
+ blob_free(rettv->vval.v_blob);
+ }
+ fclose(fd);
+ return;
+ }
+
+ while (cnt < maxline || maxline < 0)
+ {
+ readlen = (int)fread(buf, 1, io_size, fd);
+
+ /* This for loop processes what was read, but is also entered at end
+ * of file so that either:
+ * - an incomplete line gets written
+ * - a "binary" file gets an empty line at the end if it ends in a
+ * newline. */
+ for (p = buf, start = buf;
+ p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
+ ++p)
+ {
+ if (*p == '\n' || readlen <= 0)
+ {
+ listitem_T *li;
+ char_u *s = NULL;
+ long_u len = p - start;
+
+ /* Finished a line. Remove CRs before NL. */
+ if (readlen > 0 && !binary)
+ {
+ while (len > 0 && start[len - 1] == '\r')
+ --len;
+ /* removal may cross back to the "prev" string */
+ if (len == 0)
+ while (prevlen > 0 && prev[prevlen - 1] == '\r')
+ --prevlen;
+ }
+ if (prevlen == 0)
+ s = vim_strnsave(start, (int)len);
+ else
+ {
+ /* Change "prev" buffer to be the right size. This way
+ * the bytes are only copied once, and very long lines are
+ * allocated only once. */
+ if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
+ {
+ mch_memmove(s + prevlen, start, len);
+ s[prevlen + len] = NUL;
+ prev = NULL; /* the list will own the string */
+ prevlen = prevsize = 0;
+ }
+ }
+ if (s == NULL)
+ {
+ do_outofmem_msg((long_u) prevlen + len + 1);
+ failed = TRUE;
+ break;
+ }
+
+ if ((li = listitem_alloc()) == NULL)
+ {
+ vim_free(s);
+ failed = TRUE;
+ break;
+ }
+ li->li_tv.v_type = VAR_STRING;
+ li->li_tv.v_lock = 0;
+ li->li_tv.vval.v_string = s;
+ list_append(rettv->vval.v_list, li);
+
+ start = p + 1; /* step over newline */
+ if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
+ break;
+ }
+ else if (*p == NUL)
+ *p = '\n';
+ /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
+ * when finding the BF and check the previous two bytes. */
+ else if (*p == 0xbf && enc_utf8 && !binary)
+ {
+ /* Find the two bytes before the 0xbf. If p is at buf, or buf
+ * + 1, these may be in the "prev" string. */
+ char_u back1 = p >= buf + 1 ? p[-1]
+ : prevlen >= 1 ? prev[prevlen - 1] : NUL;
+ char_u back2 = p >= buf + 2 ? p[-2]
+ : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
+ : prevlen >= 2 ? prev[prevlen - 2] : NUL;
+
+ if (back2 == 0xef && back1 == 0xbb)
+ {
+ char_u *dest = p - 2;
+
+ /* Usually a BOM is at the beginning of a file, and so at
+ * the beginning of a line; then we can just step over it.
+ */
+ if (start == dest)
+ start = p + 1;
+ else
+ {
+ /* have to shuffle buf to close gap */
+ int adjust_prevlen = 0;
+
+ if (dest < buf)
+ {
+ adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */
+ dest = buf;
+ }
+ if (readlen > p - buf + 1)
+ mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
+ readlen -= 3 - adjust_prevlen;
+ prevlen -= adjust_prevlen;
+ p = dest - 1;
+ }
+ }
+ }
+ } /* for */
+
+ if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
+ break;
+ if (start < p)
+ {
+ /* There's part of a line in buf, store it in "prev". */
+ if (p - start + prevlen >= prevsize)
+ {
+ /* need bigger "prev" buffer */
+ char_u *newprev;
+
+ /* A common use case is ordinary text files and "prev" gets a
+ * fragment of a line, so the first allocation is made
+ * small, to avoid repeatedly 'allocing' large and
+ * 'reallocing' small. */
+ if (prevsize == 0)
+ prevsize = (long)(p - start);
+ else
+ {
+ long grow50pc = (prevsize * 3) / 2;
+ long growmin = (long)((p - start) * 2 + prevlen);
+ prevsize = grow50pc > growmin ? grow50pc : growmin;
+ }
+ newprev = prev == NULL ? alloc(prevsize)
+ : vim_realloc(prev, prevsize);
+ if (newprev == NULL)
+ {
+ do_outofmem_msg((long_u)prevsize);
+ failed = TRUE;
+ break;
+ }
+ prev = newprev;
+ }
+ /* Add the line part to end of "prev". */
+ mch_memmove(prev + prevlen, start, p - start);
+ prevlen += (long)(p - start);
+ }
+ } /* while */
+
+ /*
+ * For a negative line count use only the lines at the end of the file,
+ * free the rest.
+ */
+ if (!failed && maxline < 0)
+ while (cnt > -maxline)
+ {
+ listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
+ --cnt;
+ }
+
+ if (failed)
+ {
+ list_free(rettv->vval.v_list);
+ /* readfile doc says an empty list is returned on error */
+ rettv->vval.v_list = list_alloc();
+ }
+
+ vim_free(prev);
+ fclose(fd);
+}
+
+ static void
+return_register(int regname, typval_T *rettv)
+{
+ char_u buf[2] = {0, 0};
+
+ buf[0] = (char_u)regname;
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = vim_strsave(buf);
+}
+
+/*
+ * "reg_executing()" function
+ */
+ static void
+f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ return_register(reg_executing, rettv);
+}
+
+/*
+ * "reg_recording()" function
+ */
+ static void
+f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ return_register(reg_recording, rettv);
+}
+
+#if defined(FEAT_RELTIME)
+/*
+ * Convert a List to proftime_T.
+ * Return FAIL when there is something wrong.
+ */
+ static int
+list2proftime(typval_T *arg, proftime_T *tm)
+{
+ long n1, n2;
+ int error = FALSE;
+
+ if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
+ || arg->vval.v_list->lv_len != 2)
+ return FAIL;
+ n1 = list_find_nr(arg->vval.v_list, 0L, &error);
+ n2 = list_find_nr(arg->vval.v_list, 1L, &error);
+# ifdef WIN3264
+ tm->HighPart = n1;
+ tm->LowPart = n2;
+# else
+ tm->tv_sec = n1;
+ tm->tv_usec = n2;
+# endif
+ return error ? FAIL : OK;
+}
+#endif /* FEAT_RELTIME */
+
+/*
+ * "reltime()" function
+ */
+ static void
+f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
+{
+#ifdef FEAT_RELTIME
+ proftime_T res;
+ proftime_T start;
+
+ if (argvars[0].v_type == VAR_UNKNOWN)
+ {
+ /* No arguments: get current time. */
+ profile_start(&res);
+ }
+ else if (argvars[1].v_type == VAR_UNKNOWN)
+ {
+ if (list2proftime(&argvars[0], &res) == FAIL)
+ return;
+ profile_end(&res);
+ }
+ else
+ {
+ /* Two arguments: compute the difference. */
+ if (list2proftime(&argvars[0], &start) == FAIL
+ || list2proftime(&argvars[1], &res) == FAIL)
+ return;
+ profile_sub(&res, &start);
+ }
+
+ if (rettv_list_alloc(rettv) == OK)
+ {
+ long n1, n2;
+
+# ifdef WIN3264
+ n1 = res.HighPart;
+ n2 = res.LowPart;
+# else
+ n1 = res.tv_sec;
+ n2 = res.tv_usec;
+# endif
+ list_append_number(rettv->vval.v_list, (varnumber_T)n1);
+ list_append_number(rettv->vval.v_list, (varnumber_T)n2);
+ }
+#endif
+}
+
+#ifdef FEAT_FLOAT
+/*
+ * "reltimefloat()" function
+ */
+ static void
+f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
+{
+# ifdef FEAT_RELTIME
+ proftime_T tm;
+# endif
+
+ rettv->v_type = VAR_FLOAT;
+ rettv->vval.v_float = 0;
+# ifdef FEAT_RELTIME
+ if (list2proftime(&argvars[0], &tm) == OK)
+ rettv->vval.v_float = profile_float(&tm);
+# endif
+}
+#endif
+
+/*
+ * "reltimestr()" function
+ */
+ static void
+f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
+{
+#ifdef FEAT_RELTIME
+ proftime_T tm;
+#endif
+
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+#ifdef FEAT_RELTIME
+ if (list2proftime(&argvars[0], &tm) == OK)
+ rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
+#endif
+}
+
+#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
+ static void
+make_connection(void)
+{
+ if (X_DISPLAY == NULL
+# ifdef FEAT_GUI
+ && !gui.in_use
+# endif
+ )
+ {
+ x_force_connect = TRUE;
+ setup_term_clip();
+ x_force_connect = FALSE;
+ }
+}
+
+ static int
+check_connection(void)
+{
+ make_connection();
+ if (X_DISPLAY == NULL)
+ {
+ emsg(_("E240: No connection to the X server"));
+ return FAIL;
+ }
+ return OK;
+}
+#endif
+
+#ifdef FEAT_CLIENTSERVER
+ static void
+remote_common(typval_T *argvars, typval_T *rettv, int expr)
+{
+ char_u *server_name;
+ char_u *keys;
+ char_u *r = NULL;
+ char_u buf[NUMBUFLEN];
+ int timeout = 0;
+# ifdef WIN32
+ HWND w;
+# else
+ Window w;
+# endif
+
+ if (check_restricted() || check_secure())
+ return;
+
+# ifdef FEAT_X11
+ if (check_connection() == FAIL)
+ return;
+# endif
+ if (argvars[2].v_type != VAR_UNKNOWN
+ && argvars[3].v_type != VAR_UNKNOWN)
+ timeout = tv_get_number(&argvars[3]);
+
+ server_name = tv_get_string_chk(&argvars[0]);
+ if (server_name == NULL)
+ return; /* type error; errmsg already given */
+ keys = tv_get_string_buf(&argvars[1], buf);
+# ifdef WIN32
+ if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
+# else
+ if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
+ 0, TRUE) < 0)
+# endif
+ {
+ if (r != NULL)
+ {
+ emsg((char *)r); // sending worked but evaluation failed
+ vim_free(r);
+ }
+ else
+ semsg(_("E241: Unable to send to %s"), server_name);
+ return;
+ }
+
+ rettv->vval.v_string = r;
+
+ if (argvars[2].v_type != VAR_UNKNOWN)
+ {
+ dictitem_T v;
+ char_u str[30];
+ char_u *idvar;
+
+ idvar = tv_get_string_chk(&argvars[2]);
+ if (idvar != NULL && *idvar != NUL)
+ {
+ sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
+ v.di_tv.v_type = VAR_STRING;
+ v.di_tv.vval.v_string = vim_strsave(str);
+ set_var(idvar, &v.di_tv, FALSE);
+ vim_free(v.di_tv.vval.v_string);
+ }
+ }
+}
+#endif
+
+/*
+ * "remote_expr()" function
+ */
+ static void
+f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+#ifdef FEAT_CLIENTSERVER
+ remote_common(argvars, rettv, TRUE);
+#endif
+}
+
+/*
+ * "remote_foreground()" function
+ */
+ static void
+f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
+{
+#ifdef FEAT_CLIENTSERVER
+# ifdef WIN32
+ /* On Win32 it's done in this application. */
+ {
+ char_u *server_name = tv_get_string_chk(&argvars[0]);
+
+ if (server_name != NULL)
+ serverForeground(server_name);
+ }
+# else
+ /* Send a foreground() expression to the server. */
+ argvars[1].v_type = VAR_STRING;
+ argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
+ argvars[2].v_type = VAR_UNKNOWN;
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+ remote_common(argvars, rettv, TRUE);
+ vim_free(argvars[1].vval.v_string);
+# endif
+#endif
+}
+
+ static void
+f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
+{
+#ifdef FEAT_CLIENTSERVER
+ dictitem_T v;
+ char_u *s = NULL;
+# ifdef WIN32
+ long_u n = 0;
+# endif
+ char_u *serverid;
+
+ if (check_restricted() || check_secure())
+ {
+ rettv->vval.v_number = -1;
+ return;
+ }
+ serverid = tv_get_string_chk(&argvars[0]);
+ if (serverid == NULL)
+ {
+ rettv->vval.v_number = -1;
+ return; /* type error; errmsg already given */
+ }
+# ifdef WIN32
+ sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
+ if (n == 0)
+ rettv->vval.v_number = -1;
+ else
+ {
+ s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
+ rettv->vval.v_number = (s != NULL);
+ }
+# else
+ if (check_connection() == FAIL)
+ return;
+
+ rettv->vval.v_number = serverPeekReply(X_DISPLAY,
+ serverStrToWin(serverid), &s);
+# endif
+
+ if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
+ {
+ char_u *retvar;
+
+ v.di_tv.v_type = VAR_STRING;
+ v.di_tv.vval.v_string = vim_strsave(s);
+ retvar = tv_get_string_chk(&argvars[1]);
+ if (retvar != NULL)
+ set_var(retvar, &v.di_tv, FALSE);
+ vim_free(v.di_tv.vval.v_string);
+ }
+#else
+ rettv->vval.v_number = -1;
+#endif
+}
+
+ static void
+f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ char_u *r = NULL;
+
+#ifdef FEAT_CLIENTSERVER
+ char_u *serverid = tv_get_string_chk(&argvars[0]);
+
+ if (serverid != NULL && !check_restricted() && !check_secure())
+ {
+ int timeout = 0;
+# ifdef WIN32
+ /* The server's HWND is encoded in the 'id' parameter */
+ long_u n = 0;
+# endif
+
+ if (argvars[1].v_type != VAR_UNKNOWN)
+ timeout = tv_get_number(&argvars[1]);
+
+# ifdef WIN32
+ sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
+ if (n != 0)
+ r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
+ if (r == NULL)
+# else
+ if (check_connection() == FAIL
+ || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
+ &r, FALSE, timeout) < 0)
+# endif
+ emsg(_("E277: Unable to read a server reply"));
+ }
+#endif
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = r;
+}
+
+/*
+ * "remote_send()" function
+ */
+ static void
+f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+#ifdef FEAT_CLIENTSERVER
+ remote_common(argvars, rettv, FALSE);
+#endif
+}
+
+/*
+ * "remote_startserver()" function
+ */
+ static void
+f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
+{
+#ifdef FEAT_CLIENTSERVER
+ char_u *server = tv_get_string_chk(&argvars[0]);
+
+ if (server == NULL)
+ return; /* type error; errmsg already given */
+ if (serverName != NULL)
+ emsg(_("E941: already started a server"));
+ else
+ {
+# ifdef FEAT_X11
+ if (check_connection() == OK)
+ serverRegisterName(X_DISPLAY, server);
+# else
+ serverSetName(server);
+# endif
+ }
+#else
+ emsg(_("E942: +clientserver feature not available"));
+#endif
+}
+
+/*
+ * "remove()" function
+ */
+ static void
+f_remove(typval_T *argvars, typval_T *rettv)
+{
+ list_T *l;
+ listitem_T *item, *item2;
+ listitem_T *li;
+ long idx;
+ long end;
+ char_u *key;
+ dict_T *d;
+ dictitem_T *di;
+ char_u *arg_errmsg = (char_u *)N_("remove() argument");
+ int error = FALSE;
+
+ if (argvars[0].v_type == VAR_DICT)
+ {
+ if (argvars[2].v_type != VAR_UNKNOWN)
+ semsg(_(e_toomanyarg), "remove()");
+ else if ((d = argvars[0].vval.v_dict) != NULL
+ && !tv_check_lock(d->dv_lock, arg_errmsg, TRUE))
+ {
+ key = tv_get_string_chk(&argvars[1]);
+ if (key != NULL)
+ {
+ di = dict_find(d, key, -1);
+ if (di == NULL)
+ semsg(_(e_dictkey), key);
+ else if (!var_check_fixed(di->di_flags, arg_errmsg, TRUE)
+ && !var_check_ro(di->di_flags, arg_errmsg, TRUE))
+ {
+ *rettv = di->di_tv;
+ init_tv(&di->di_tv);
+ dictitem_remove(d, di);
+ }
+ }
+ }
+ }
+ else if (argvars[0].v_type == VAR_BLOB)
+ {
+ idx = (long)tv_get_number_chk(&argvars[1], &error);
+ if (!error)
+ {
+ blob_T *b = argvars[0].vval.v_blob;
+ int len = blob_len(b);
+ char_u *p;
+
+ if (idx < 0)
+ // count from the end
+ idx = len + idx;
+ if (idx < 0 || idx >= len)
+ {
+ semsg(_(e_blobidx), idx);
+ return;
+ }
+ if (argvars[2].v_type == VAR_UNKNOWN)
+ {
+ // Remove one item, return its value.
+ p = (char_u *)b->bv_ga.ga_data;
+ rettv->vval.v_number = (varnumber_T) *(p + idx);
+ mch_memmove(p + idx, p + idx + 1, (size_t)len - idx - 1);
+ --b->bv_ga.ga_len;
+ }
+ else
+ {
+ blob_T *blob;
+
+ // Remove range of items, return list with values.
+ end = (long)tv_get_number_chk(&argvars[2], &error);
+ if (error)
+ return;
+ if (end < 0)
+ // count from the end
+ end = len + end;
+ if (end >= len || idx > end)
+ {
+ semsg(_(e_blobidx), end);
+ return;
+ }
+ blob = blob_alloc();
+ if (blob == NULL)
+ return;
+ blob->bv_ga.ga_len = end - idx + 1;
+ if (ga_grow(&blob->bv_ga, end - idx + 1) == FAIL)
+ {
+ vim_free(blob);
+ return;
+ }
+ p = (char_u *)b->bv_ga.ga_data;
+ mch_memmove((char_u *)blob->bv_ga.ga_data, p + idx,
+ (size_t)(end - idx + 1));
+ ++blob->bv_refcount;
+ rettv->v_type = VAR_BLOB;
+ rettv->vval.v_blob = blob;
+
+ mch_memmove(p + idx, p + end + 1, (size_t)(len - end));
+ b->bv_ga.ga_len -= end - idx + 1;
+ }
+ }
+ }
+ else if (argvars[0].v_type != VAR_LIST)
+ semsg(_(e_listdictblobarg), "remove()");
+ else if ((l = argvars[0].vval.v_list) != NULL
+ && !tv_check_lock(l->lv_lock, arg_errmsg, TRUE))
+ {
+ idx = (long)tv_get_number_chk(&argvars[1], &error);
+ if (error)
+ ; // type error: do nothing, errmsg already given
+ else if ((item = list_find(l, idx)) == NULL)
+ semsg(_(e_listidx), idx);
+ else
+ {
+ if (argvars[2].v_type == VAR_UNKNOWN)
+ {
+ /* Remove one item, return its value. */
+ vimlist_remove(l, item, item);
+ *rettv = item->li_tv;
+ vim_free(item);
+ }
+ else
+ {
+ // Remove range of items, return list with values.
+ end = (long)tv_get_number_chk(&argvars[2], &error);
+ if (error)
+ ; // type error: do nothing
+ else if ((item2 = list_find(l, end)) == NULL)
+ semsg(_(e_listidx), end);
+ else
+ {
+ int cnt = 0;
+
+ for (li = item; li != NULL; li = li->li_next)
+ {
+ ++cnt;
+ if (li == item2)
+ break;
+ }
+ if (li == NULL) /* didn't find "item2" after "item" */
+ emsg(_(e_invrange));
+ else
+ {
+ vimlist_remove(l, item, item2);
+ if (rettv_list_alloc(rettv) == OK)
+ {
+ l = rettv->vval.v_list;
+ l->lv_first = item;
+ l->lv_last = item2;
+ item->li_prev = NULL;
+ item2->li_next = NULL;
+ l->lv_len = cnt;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+/*
+ * "rename({from}, {to})" function
+ */
+ static void
+f_rename(typval_T *argvars, typval_T *rettv)
+{
+ char_u buf[NUMBUFLEN];
+
+ if (check_restricted() || check_secure())
+ rettv->vval.v_number = -1;
+ else
+ rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
+ tv_get_string_buf(&argvars[1], buf));
+}
+
+/*
+ * "repeat()" function
+ */
+ static void
+f_repeat(typval_T *argvars, typval_T *rettv)
+{
+ char_u *p;
+ int n;
+ int slen;
+ int len;
+ char_u *r;
+ int i;
+
+ n = (int)tv_get_number(&argvars[1]);
+ if (argvars[0].v_type == VAR_LIST)
+ {
+ if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
+ while (n-- > 0)
+ if (list_extend(rettv->vval.v_list,
+ argvars[0].vval.v_list, NULL) == FAIL)
+ break;
+ }
+ else
+ {
+ p = tv_get_string(&argvars[0]);
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+
+ slen = (int)STRLEN(p);
+ len = slen * n;
+ if (len <= 0)
+ return;
+
+ r = alloc(len + 1);
+ if (r != NULL)
+ {
+ for (i = 0; i < n; i++)
+ mch_memmove(r + i * slen, p, (size_t)slen);
+ r[len] = NUL;
+ }
+
+ rettv->vval.v_string = r;
+ }
+}
+
+/*
+ * "resolve()" function
+ */
+ static void
+f_resolve(typval_T *argvars, typval_T *rettv)
+{
+ char_u *p;
+#ifdef HAVE_READLINK
+ char_u *buf = NULL;
+#endif
+
+ p = tv_get_string(&argvars[0]);
+#ifdef FEAT_SHORTCUT
+ {
+ char_u *v = NULL;
+
+ v = mch_resolve_shortcut(p);
+ if (v != NULL)
+ rettv->vval.v_string = v;
+ else
+ rettv->vval.v_string = vim_strsave(p);
+ }
+#else
+# ifdef HAVE_READLINK
+ {
+ char_u *cpy;
+ int len;
+ char_u *remain = NULL;
+ char_u *q;
+ int is_relative_to_current = FALSE;
+ int has_trailing_pathsep = FALSE;
+ int limit = 100;
+
+ p = vim_strsave(p);
+
+ if (p[0] == '.' && (vim_ispathsep(p[1])
+ || (p[1] == '.' && (vim_ispathsep(p[2])))))
+ is_relative_to_current = TRUE;
+
+ len = STRLEN(p);
+ if (len > 0 && after_pathsep(p, p + len))
+ {
+ has_trailing_pathsep = TRUE;
+ p[len - 1] = NUL; /* the trailing slash breaks readlink() */
+ }
+
+ q = getnextcomp(p);
+ if (*q != NUL)
+ {
+ /* Separate the first path component in "p", and keep the
+ * remainder (beginning with the path separator). */
+ remain = vim_strsave(q - 1);
+ q[-1] = NUL;
+ }
+
+ buf = alloc(MAXPATHL + 1);
+ if (buf == NULL)
+ goto fail;
+
+ for (;;)
+ {
+ for (;;)
+ {
+ len = readlink((char *)p, (char *)buf, MAXPATHL);
+ if (len <= 0)
+ break;
+ buf[len] = NUL;
+
+ if (limit-- == 0)
+ {
+ vim_free(p);
+ vim_free(remain);
+ emsg(_("E655: Too many symbolic links (cycle?)"));
+ rettv->vval.v_string = NULL;
+ goto fail;
+ }
+
+ /* Ensure that the result will have a trailing path separator
+ * if the argument has one. */
+ if (remain == NULL && has_trailing_pathsep)
+ add_pathsep(buf);
+
+ /* Separate the first path component in the link value and
+ * concatenate the remainders. */
+ q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
+ if (*q != NUL)
+ {
+ if (remain == NULL)
+ remain = vim_strsave(q - 1);
+ else
+ {
+ cpy = concat_str(q - 1, remain);
+ if (cpy != NULL)
+ {
+ vim_free(remain);
+ remain = cpy;
+ }
+ }
+ q[-1] = NUL;
+ }
+
+ q = gettail(p);
+ if (q > p && *q == NUL)
+ {
+ /* Ignore trailing path separator. */
+ q[-1] = NUL;
+ q = gettail(p);
+ }
+ if (q > p && !mch_isFullName(buf))
+ {
+ /* symlink is relative to directory of argument */
+ cpy = alloc((unsigned)(STRLEN(p) + STRLEN(buf) + 1));
+ if (cpy != NULL)
+ {
+ STRCPY(cpy, p);
+ STRCPY(gettail(cpy), buf);
+ vim_free(p);
+ p = cpy;
+ }
+ }
+ else
+ {
+ vim_free(p);
+ p = vim_strsave(buf);
+ }
+ }
+
+ if (remain == NULL)
+ break;
+
+ /* Append the first path component of "remain" to "p". */
+ q = getnextcomp(remain + 1);
+ len = q - remain - (*q != NUL);
+ cpy = vim_strnsave(p, STRLEN(p) + len);
+ if (cpy != NULL)
+ {
+ STRNCAT(cpy, remain, len);
+ vim_free(p);
+ p = cpy;
+ }
+ /* Shorten "remain". */
+ if (*q != NUL)
+ STRMOVE(remain, q - 1);
+ else
+ VIM_CLEAR(remain);
+ }
+
+ /* If the result is a relative path name, make it explicitly relative to
+ * the current directory if and only if the argument had this form. */
+ if (!vim_ispathsep(*p))
+ {
+ if (is_relative_to_current
+ && *p != NUL
+ && !(p[0] == '.'
+ && (p[1] == NUL
+ || vim_ispathsep(p[1])
+ || (p[1] == '.'
+ && (p[2] == NUL
+ || vim_ispathsep(p[2]))))))
+ {
+ /* Prepend "./". */
+ cpy = concat_str((char_u *)"./", p);
+ if (cpy != NULL)
+ {
+ vim_free(p);
+ p = cpy;
+ }
+ }
+ else if (!is_relative_to_current)
+ {
+ /* Strip leading "./". */
+ q = p;
+ while (q[0] == '.' && vim_ispathsep(q[1]))
+ q += 2;
+ if (q > p)
+ STRMOVE(p, p + 2);
+ }
+ }
+
+ /* Ensure that the result will have no trailing path separator
+ * if the argument had none. But keep "/" or "//". */
+ if (!has_trailing_pathsep)
+ {
+ q = p + STRLEN(p);
+ if (after_pathsep(p, q))
+ *gettail_sep(p) = NUL;
+ }
+
+ rettv->vval.v_string = p;
+ }
+# else
+ rettv->vval.v_string = vim_strsave(p);
+# endif
+#endif
+
+ simplify_filename(rettv->vval.v_string);
+
+#ifdef HAVE_READLINK
+fail:
+ vim_free(buf);
+#endif
+ rettv->v_type = VAR_STRING;
+}
+
+/*
+ * "reverse({list})" function
+ */
+ static void
+f_reverse(typval_T *argvars, typval_T *rettv)
+{
+ list_T *l;
+ listitem_T *li, *ni;
+
+ if (argvars[0].v_type == VAR_BLOB)
+ {
+ blob_T *b = argvars[0].vval.v_blob;
+ int i, len = blob_len(b);
+
+ for (i = 0; i < len / 2; i++)
+ {
+ int tmp = blob_get(b, i);
+
+ blob_set(b, i, blob_get(b, len - i - 1));
+ blob_set(b, len - i - 1, tmp);
+ }
+ rettv_blob_set(rettv, b);
+ return;
+ }
+
+ if (argvars[0].v_type != VAR_LIST)
+ semsg(_(e_listblobarg), "reverse()");
+ else if ((l = argvars[0].vval.v_list) != NULL
+ && !tv_check_lock(l->lv_lock,
+ (char_u *)N_("reverse() argument"), TRUE))
+ {
+ li = l->lv_last;
+ l->lv_first = l->lv_last = NULL;
+ l->lv_len = 0;
+ while (li != NULL)
+ {
+ ni = li->li_prev;
+ list_append(l, li);
+ li = ni;
+ }
+ rettv_list_set(rettv, l);
+ l->lv_idx = l->lv_len - l->lv_idx - 1;
+ }
+}
+
+#define SP_NOMOVE 0x01 /* don't move cursor */
+#define SP_REPEAT 0x02 /* repeat to find outer pair */
+#define SP_RETCOUNT 0x04 /* return matchcount */
+#define SP_SETPCMARK 0x08 /* set previous context mark */
+#define SP_START 0x10 /* accept match at start position */
+#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
+#define SP_END 0x40 /* leave cursor at end of match */
+#define SP_COLUMN 0x80 /* start at cursor column */
+
+/*
+ * Get flags for a search function.
+ * Possibly sets "p_ws".
+ * Returns BACKWARD, FORWARD or zero (for an error).
+ */
+ static int
+get_search_arg(typval_T *varp, int *flagsp)
+{
+ int dir = FORWARD;
+ char_u *flags;
+ char_u nbuf[NUMBUFLEN];
+ int mask;
+
+ if (varp->v_type != VAR_UNKNOWN)
+ {
+ flags = tv_get_string_buf_chk(varp, nbuf);
+ if (flags == NULL)
+ return 0; /* type error; errmsg already given */
+ while (*flags != NUL)
+ {
+ switch (*flags)
+ {
+ case 'b': dir = BACKWARD; break;
+ case 'w': p_ws = TRUE; break;
+ case 'W': p_ws = FALSE; break;
+ default: mask = 0;
+ if (flagsp != NULL)
+ switch (*flags)
+ {
+ case 'c': mask = SP_START; break;
+ case 'e': mask = SP_END; break;
+ case 'm': mask = SP_RETCOUNT; break;
+ case 'n': mask = SP_NOMOVE; break;
+ case 'p': mask = SP_SUBPAT; break;
+ case 'r': mask = SP_REPEAT; break;
+ case 's': mask = SP_SETPCMARK; break;
+ case 'z': mask = SP_COLUMN; break;
+ }
+ if (mask == 0)
+ {
+ semsg(_(e_invarg2), flags);
+ dir = 0;
+ }
+ else
+ *flagsp |= mask;
+ }
+ if (dir == 0)
+ break;
+ ++flags;
+ }
+ }
+ return dir;
+}
+
+/*
+ * Shared by search() and searchpos() functions.
+ */
+ static int
+search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
+{
+ int flags;
+ char_u *pat;
+ pos_T pos;
+ pos_T save_cursor;
+ int save_p_ws = p_ws;
+ int dir;
+ int retval = 0; /* default: FAIL */
+ long lnum_stop = 0;
+ proftime_T tm;
+#ifdef FEAT_RELTIME
+ long time_limit = 0;
+#endif
+ int options = SEARCH_KEEP;
+ int subpatnum;
+
+ pat = tv_get_string(&argvars[0]);
+ dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
+ if (dir == 0)
+ goto theend;
+ flags = *flagsp;
+ if (flags & SP_START)
+ options |= SEARCH_START;
+ if (flags & SP_END)
+ options |= SEARCH_END;
+ if (flags & SP_COLUMN)
+ options |= SEARCH_COL;
+
+ /* Optional arguments: line number to stop searching and timeout. */
+ if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
+ {
+ lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
+ if (lnum_stop < 0)
+ goto theend;
+#ifdef FEAT_RELTIME
+ if (argvars[3].v_type != VAR_UNKNOWN)
+ {
+ time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
+ if (time_limit < 0)
+ goto theend;
+ }
+#endif
+ }
+
+#ifdef FEAT_RELTIME
+ /* Set the time limit, if there is one. */
+ profile_setlimit(time_limit, &tm);
+#endif
+
+ /*
+ * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
+ * Check to make sure only those flags are set.
+ * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
+ * flags cannot be set. Check for that condition also.
+ */
+ if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
+ || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
+ {
+ semsg(_(e_invarg2), tv_get_string(&argvars[1]));
+ goto theend;
+ }
+
+ pos = save_cursor = curwin->w_cursor;
+ subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
+ options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
+ if (subpatnum != FAIL)
+ {
+ if (flags & SP_SUBPAT)
+ retval = subpatnum;
+ else
+ retval = pos.lnum;
+ if (flags & SP_SETPCMARK)
+ setpcmark();
+ curwin->w_cursor = pos;
+ if (match_pos != NULL)
+ {
+ /* Store the match cursor position */
+ match_pos->lnum = pos.lnum;
+ match_pos->col = pos.col + 1;
+ }
+ /* "/$" will put the cursor after the end of the line, may need to
+ * correct that here */
+ check_cursor();
+ }
+
+ /* If 'n' flag is used: restore cursor position. */
+ if (flags & SP_NOMOVE)
+ curwin->w_cursor = save_cursor;
+ else
+ curwin->w_set_curswant = TRUE;
+theend:
+ p_ws = save_p_ws;
+
+ return retval;
+}
+
+#ifdef FEAT_FLOAT
+
+/*
+ * round() is not in C90, use ceil() or floor() instead.
+ */
+ float_T
+vim_round(float_T f)
+{
+ return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
+}
+
+/*
+ * "round({float})" function
+ */
+ static void
+f_round(typval_T *argvars, typval_T *rettv)
+{
+ float_T f = 0.0;
+
+ rettv->v_type = VAR_FLOAT;
+ if (get_float_arg(argvars, &f) == OK)
+ rettv->vval.v_float = vim_round(f);
+ else
+ rettv->vval.v_float = 0.0;
+}
+#endif
+
+/*
+ * "screenattr()" function
+ */
+ static void
+f_screenattr(typval_T *argvars, typval_T *rettv)
+{
+ int row;
+ int col;
+ int c;
+
+ row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
+ col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
+ if (row < 0 || row >= screen_Rows
+ || col < 0 || col >= screen_Columns)
+ c = -1;
+ else
+ c = ScreenAttrs[LineOffset[row] + col];
+ rettv->vval.v_number = c;
+}
+
+/*
+ * "screenchar()" function
+ */
+ static void
+f_screenchar(typval_T *argvars, typval_T *rettv)
+{
+ int row;
+ int col;
+ int off;
+ int c;
+
+ row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
+ col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
+ if (row < 0 || row >= screen_Rows
+ || col < 0 || col >= screen_Columns)
+ c = -1;
+ else
+ {
+ off = LineOffset[row] + col;
+ if (enc_utf8 && ScreenLinesUC[off] != 0)
+ c = ScreenLinesUC[off];
+ else
+ c = ScreenLines[off];
+ }
+ rettv->vval.v_number = c;
+}
+
+/*
+ * "screencol()" function
+ *
+ * First column is 1 to be consistent with virtcol().
+ */
+ static void
+f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ rettv->vval.v_number = screen_screencol() + 1;
+}
+
+/*
+ * "screenrow()" function
+ */
+ static void
+f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ rettv->vval.v_number = screen_screenrow() + 1;
+}
+
+/*
+ * "search()" function
+ */
+ static void
+f_search(typval_T *argvars, typval_T *rettv)
+{
+ int flags = 0;
+
+ rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
+}
+
+/*
+ * "searchdecl()" function
+ */
+ static void
+f_searchdecl(typval_T *argvars, typval_T *rettv)
+{
+ int locally = 1;
+ int thisblock = 0;
+ int error = FALSE;
+ char_u *name;
+
+ rettv->vval.v_number = 1; /* default: FAIL */
+
+ name = tv_get_string_chk(&argvars[0]);
+ if (argvars[1].v_type != VAR_UNKNOWN)
+ {
+ locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
+ if (!error && argvars[2].v_type != VAR_UNKNOWN)
+ thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
+ }
+ if (!error && name != NULL)
+ rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
+ locally, thisblock, SEARCH_KEEP) == FAIL;
+}
+
+/*
+ * Used by searchpair() and searchpairpos()
+ */
+ static int
+searchpair_cmn(typval_T *argvars, pos_T *match_pos)
+{
+ char_u *spat, *mpat, *epat;
+ typval_T *skip;
+ int save_p_ws = p_ws;
+ int dir;
+ int flags = 0;
+ char_u nbuf1[NUMBUFLEN];
+ char_u nbuf2[NUMBUFLEN];
+ int retval = 0; /* default: FAIL */
+ long lnum_stop = 0;
+ long time_limit = 0;
+
+ /* Get the three pattern arguments: start, middle, end. Will result in an
+ * error if not a valid argument. */
+ spat = tv_get_string_chk(&argvars[0]);
+ mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
+ epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
+ if (spat == NULL || mpat == NULL || epat == NULL)
+ goto theend; /* type error */
+
+ /* Handle the optional fourth argument: flags */
+ dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
+ if (dir == 0)
+ goto theend;
+
+ /* Don't accept SP_END or SP_SUBPAT.
+ * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
+ */
+ if ((flags & (SP_END | SP_SUBPAT)) != 0
+ || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
+ {
+ semsg(_(e_invarg2), tv_get_string(&argvars[3]));
+ goto theend;
+ }
+
+ /* Using 'r' implies 'W', otherwise it doesn't work. */
+ if (flags & SP_REPEAT)
+ p_ws = FALSE;
+
+ /* Optional fifth argument: skip expression */
+ if (argvars[3].v_type == VAR_UNKNOWN
+ || argvars[4].v_type == VAR_UNKNOWN)
+ skip = NULL;
+ else
+ {
+ skip = &argvars[4];
+ if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
+ && skip->v_type != VAR_STRING)
+ {
+ /* Type error */
+ semsg(_(e_invarg2), tv_get_string(&argvars[4]));
+ goto theend;
+ }
+ if (argvars[5].v_type != VAR_UNKNOWN)
+ {
+ lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
+ if (lnum_stop < 0)
+ {
+ semsg(_(e_invarg2), tv_get_string(&argvars[5]));
+ goto theend;
+ }
+#ifdef FEAT_RELTIME
+ if (argvars[6].v_type != VAR_UNKNOWN)
+ {
+ time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
+ if (time_limit < 0)
+ {
+ semsg(_(e_invarg2), tv_get_string(&argvars[6]));
+ goto theend;
+ }
+ }
+#endif
+ }
+ }
+
+ retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
+ match_pos, lnum_stop, time_limit);
+
+theend:
+ p_ws = save_p_ws;
+
+ return retval;
+}
+
+/*
+ * "searchpair()" function
+ */
+ static void
+f_searchpair(typval_T *argvars, typval_T *rettv)
+{
+ rettv->vval.v_number = searchpair_cmn(argvars, NULL);
+}
+
+/*
+ * "searchpairpos()" function
+ */
+ static void
+f_searchpairpos(typval_T *argvars, typval_T *rettv)
+{
+ pos_T match_pos;
+ int lnum = 0;
+ int col = 0;
+
+ if (rettv_list_alloc(rettv) == FAIL)
+ return;
+
+ if (searchpair_cmn(argvars, &match_pos) > 0)
+ {
+ lnum = match_pos.lnum;
+ col = match_pos.col;
+ }
+
+ list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
+ list_append_number(rettv->vval.v_list, (varnumber_T)col);
+}
+
+/*
+ * Search for a start/middle/end thing.
+ * Used by searchpair(), see its documentation for the details.
+ * Returns 0 or -1 for no match,
+ */
+ long
+do_searchpair(
+ char_u *spat, /* start pattern */
+ char_u *mpat, /* middle pattern */
+ char_u *epat, /* end pattern */
+ int dir, /* BACKWARD or FORWARD */
+ typval_T *skip, /* skip expression */
+ int flags, /* SP_SETPCMARK and other SP_ values */
+ pos_T *match_pos,
+ linenr_T lnum_stop, /* stop at this line if not zero */
+ long time_limit UNUSED) /* stop after this many msec */
+{
+ char_u *save_cpo;
+ char_u *pat, *pat2 = NULL, *pat3 = NULL;
+ long retval = 0;
+ pos_T pos;
+ pos_T firstpos;
+ pos_T foundpos;
+ pos_T save_cursor;
+ pos_T save_pos;
+ int n;
+ int r;
+ int nest = 1;
+ int use_skip = FALSE;
+ int err;
+ int options = SEARCH_KEEP;
+ proftime_T tm;
+
+ /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
+ save_cpo = p_cpo;
+ p_cpo = empty_option;
+
+#ifdef FEAT_RELTIME
+ /* Set the time limit, if there is one. */
+ profile_setlimit(time_limit, &tm);
+#endif
+
+ /* Make two search patterns: start/end (pat2, for in nested pairs) and
+ * start/middle/end (pat3, for the top pair). */
+ pat2 = alloc((unsigned)(STRLEN(spat) + STRLEN(epat) + 17));
+ pat3 = alloc((unsigned)(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25));
+ if (pat2 == NULL || pat3 == NULL)
+ goto theend;
+ sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
+ if (*mpat == NUL)
+ STRCPY(pat3, pat2);
+ else
+ sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
+ spat, epat, mpat);
+ if (flags & SP_START)
+ options |= SEARCH_START;
+
+ if (skip != NULL)
+ {
+ /* Empty string means to not use the skip expression. */
+ if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
+ use_skip = skip->vval.v_string != NULL
+ && *skip->vval.v_string != NUL;
+ }
+
+ save_cursor = curwin->w_cursor;
+ pos = curwin->w_cursor;
+ CLEAR_POS(&firstpos);
+ CLEAR_POS(&foundpos);
+ pat = pat3;
+ for (;;)
+ {
+ n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
+ options, RE_SEARCH, lnum_stop, &tm, NULL);
+ if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
+ /* didn't find it or found the first match again: FAIL */
+ break;
+
+ if (firstpos.lnum == 0)
+ firstpos = pos;
+ if (EQUAL_POS(pos, foundpos))
+ {
+ /* Found the same position again. Can happen with a pattern that
+ * has "\zs" at the end and searching backwards. Advance one
+ * character and try again. */
+ if (dir == BACKWARD)
+ decl(&pos);
+ else
+ incl(&pos);
+ }
+ foundpos = pos;
+
+ /* clear the start flag to avoid getting stuck here */
+ options &= ~SEARCH_START;
+
+ /* If the skip pattern matches, ignore this match. */
+ if (use_skip)
+ {
+ save_pos = curwin->w_cursor;
+ curwin->w_cursor = pos;
+ err = FALSE;
+ r = eval_expr_to_bool(skip, &err);
+ curwin->w_cursor = save_pos;
+ if (err)
+ {
+ /* Evaluating {skip} caused an error, break here. */
+ curwin->w_cursor = save_cursor;
+ retval = -1;
+ break;
+ }
+ if (r)
+ continue;
+ }
+
+ if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
+ {
+ /* Found end when searching backwards or start when searching
+ * forward: nested pair. */
+ ++nest;
+ pat = pat2; /* nested, don't search for middle */
+ }
+ else
+ {
+ /* Found end when searching forward or start when searching
+ * backward: end of (nested) pair; or found middle in outer pair. */
+ if (--nest == 1)
+ pat = pat3; /* outer level, search for middle */
+ }
+
+ if (nest == 0)
+ {
+ /* Found the match: return matchcount or line number. */
+ if (flags & SP_RETCOUNT)
+ ++retval;
+ else
+ retval = pos.lnum;
+ if (flags & SP_SETPCMARK)
+ setpcmark();
+ curwin->w_cursor = pos;
+ if (!(flags & SP_REPEAT))
+ break;
+ nest = 1; /* search for next unmatched */
+ }
+ }
+
+ if (match_pos != NULL)
+ {
+ /* Store the match cursor position */
+ match_pos->lnum = curwin->w_cursor.lnum;
+ match_pos->col = curwin->w_cursor.col + 1;
+ }
+
+ /* If 'n' flag is used or search failed: restore cursor position. */
+ if ((flags & SP_NOMOVE) || retval == 0)
+ curwin->w_cursor = save_cursor;
+
+theend:
+ vim_free(pat2);
+ vim_free(pat3);
+ if (p_cpo == empty_option)
+ p_cpo = save_cpo;
+ else
+ /* Darn, evaluating the {skip} expression changed the value. */
+ free_string_option(save_cpo);
+
+ return retval;
+}
+
+/*
+ * "searchpos()" function
+ */
+ static void
+f_searchpos(typval_T *argvars, typval_T *rettv)
+{
+ pos_T match_pos;
+ int lnum = 0;
+ int col = 0;
+ int n;
+ int flags = 0;
+
+ if (rettv_list_alloc(rettv) == FAIL)
+ return;
+
+ n = search_cmn(argvars, &match_pos, &flags);
+ if (n > 0)
+ {
+ lnum = match_pos.lnum;
+ col = match_pos.col;
+ }
+
+ list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
+ list_append_number(rettv->vval.v_list, (varnumber_T)col);
+ if (flags & SP_SUBPAT)
+ list_append_number(rettv->vval.v_list, (varnumber_T)n);
+}
+
+ static void
+f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
+{
+#ifdef FEAT_CLIENTSERVER
+ char_u buf[NUMBUFLEN];
+ char_u *server = tv_get_string_chk(&argvars[0]);
+ char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
+
+ rettv->vval.v_number = -1;
+ if (server == NULL || reply == NULL)
+ return;
+ if (check_restricted() || check_secure())
+ return;
+# ifdef FEAT_X11
+ if (check_connection() == FAIL)
+ return;
+# endif
+
+ if (serverSendReply(server, reply) < 0)
+ {
+ emsg(_("E258: Unable to send to client"));
+ return;
+ }
+ rettv->vval.v_number = 0;
+#else
+ rettv->vval.v_number = -1;
+#endif
+}
+
+ static void
+f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ char_u *r = NULL;
+
+#ifdef FEAT_CLIENTSERVER
+# ifdef WIN32
+ r = serverGetVimNames();
+# else
+ make_connection();
+ if (X_DISPLAY != NULL)
+ r = serverGetVimNames(X_DISPLAY);
+# endif
+#endif
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = r;
+}
+
+/*
+ * "setbufline()" function
+ */
+ static void
+f_setbufline(typval_T *argvars, typval_T *rettv)
+{
+ linenr_T lnum;
+ buf_T *buf;
+
+ buf = tv_get_buf(&argvars[0], FALSE);
+ if (buf == NULL)
+ rettv->vval.v_number = 1; /* FAIL */
+ else
+ {
+ lnum = tv_get_lnum_buf(&argvars[1], buf);
+ set_buffer_lines(buf, lnum, FALSE, &argvars[2], rettv);
+ }
+}
+
+/*
+ * "setbufvar()" function
+ */
+ static void
+f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
+{
+ buf_T *buf;
+ char_u *varname, *bufvarname;
+ typval_T *varp;
+ char_u nbuf[NUMBUFLEN];
+
+ if (check_restricted() || check_secure())
+ return;
+ (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
+ varname = tv_get_string_chk(&argvars[1]);
+ buf = tv_get_buf(&argvars[0], FALSE);
+ varp = &argvars[2];
+
+ if (buf != NULL && varname != NULL && varp != NULL)
+ {
+ if (*varname == '&')
+ {
+ long numval;
+ char_u *strval;
+ int error = FALSE;
+ aco_save_T aco;
+
+ /* set curbuf to be our buf, temporarily */
+ aucmd_prepbuf(&aco, buf);
+
+ ++varname;
+ numval = (long)tv_get_number_chk(varp, &error);
+ strval = tv_get_string_buf_chk(varp, nbuf);
+ if (!error && strval != NULL)
+ set_option_value(varname, numval, strval, OPT_LOCAL);
+
+ /* reset notion of buffer */
+ aucmd_restbuf(&aco);
+ }
+ else
+ {
+ buf_T *save_curbuf = curbuf;
+
+ bufvarname = alloc((unsigned)STRLEN(varname) + 3);
+ if (bufvarname != NULL)
+ {
+ curbuf = buf;
+ STRCPY(bufvarname, "b:");
+ STRCPY(bufvarname + 2, varname);
+ set_var(bufvarname, varp, TRUE);
+ vim_free(bufvarname);
+ curbuf = save_curbuf;
+ }
+ }
+ }
+}
+
+ static void
+f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
+{
+ dict_T *d;
+ dictitem_T *di;
+ char_u *csearch;
+
+ if (argvars[0].v_type != VAR_DICT)
+ {
+ emsg(_(e_dictreq));
+ return;
+ }
+
+ if ((d = argvars[0].vval.v_dict) != NULL)
+ {
+ csearch = dict_get_string(d, (char_u *)"char", FALSE);
+ if (csearch != NULL)
+ {
+ if (enc_utf8)
+ {
+ int pcc[MAX_MCO];
+ int c = utfc_ptr2char(csearch, pcc);
+
+ set_last_csearch(c, csearch, utfc_ptr2len(csearch));
+ }
+ else
+ set_last_csearch(PTR2CHAR(csearch),
+ csearch, MB_PTR2LEN(csearch));
+ }
+
+ di = dict_find(d, (char_u *)"forward", -1);
+ if (di != NULL)
+ set_csearch_direction((int)tv_get_number(&di->di_tv)
+ ? FORWARD : BACKWARD);
+
+ di = dict_find(d, (char_u *)"until", -1);
+ if (di != NULL)
+ set_csearch_until(!!tv_get_number(&di->di_tv));
+ }
+}
+
+/*
+ * "setcmdpos()" function
+ */
+ static void
+f_setcmdpos(typval_T *argvars, typval_T *rettv)
+{
+ int pos = (int)tv_get_number(&argvars[0]) - 1;
+
+ if (pos >= 0)
+ rettv->vval.v_number = set_cmdline_pos(pos);
+}
+
+/*
+ * "setfperm({fname}, {mode})" function
+ */
+ static void
+f_setfperm(typval_T *argvars, typval_T *rettv)
+{
+ char_u *fname;
+ char_u modebuf[NUMBUFLEN];
+ char_u *mode_str;
+ int i;
+ int mask;
+ int mode = 0;
+
+ rettv->vval.v_number = 0;
+ fname = tv_get_string_chk(&argvars[0]);
+ if (fname == NULL)
+ return;
+ mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
+ if (mode_str == NULL)
+ return;
+ if (STRLEN(mode_str) != 9)
+ {
+ semsg(_(e_invarg2), mode_str);
+ return;
+ }
+
+ mask = 1;
+ for (i = 8; i >= 0; --i)
+ {
+ if (mode_str[i] != '-')
+ mode |= mask;
+ mask = mask << 1;
+ }
+ rettv->vval.v_number = mch_setperm(fname, mode) == OK;
+}
+
+/*
+ * "setline()" function
+ */
+ static void
+f_setline(typval_T *argvars, typval_T *rettv)
+{
+ linenr_T lnum = tv_get_lnum(&argvars[0]);
+
+ set_buffer_lines(curbuf, lnum, FALSE, &argvars[1], rettv);
+}
+
+/*
+ * Used by "setqflist()" and "setloclist()" functions
+ */
+ static void
+set_qf_ll_list(
+ win_T *wp UNUSED,
+ typval_T *list_arg UNUSED,
+ typval_T *action_arg UNUSED,
+ typval_T *what_arg UNUSED,
+ typval_T *rettv)
+{
+#ifdef FEAT_QUICKFIX
+ static char *e_invact = N_("E927: Invalid action: '%s'");
+ char_u *act;
+ int action = 0;
+ static int recursive = 0;
+#endif
+
+ rettv->vval.v_number = -1;
+
+#ifdef FEAT_QUICKFIX
+ if (list_arg->v_type != VAR_LIST)
+ emsg(_(e_listreq));
+ else if (recursive != 0)
+ emsg(_(e_au_recursive));
+ else
+ {
+ list_T *l = list_arg->vval.v_list;
+ dict_T *d = NULL;
+ int valid_dict = TRUE;
+
+ if (action_arg->v_type == VAR_STRING)
+ {
+ act = tv_get_string_chk(action_arg);
+ if (act == NULL)
+ return; /* type error; errmsg already given */
+ if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') &&
+ act[1] == NUL)
+ action = *act;
+ else
+ semsg(_(e_invact), act);
+ }
+ else if (action_arg->v_type == VAR_UNKNOWN)
+ action = ' ';
+ else
+ emsg(_(e_stringreq));
+
+ if (action_arg->v_type != VAR_UNKNOWN
+ && what_arg->v_type != VAR_UNKNOWN)
+ {
+ if (what_arg->v_type == VAR_DICT)
+ d = what_arg->vval.v_dict;
+ else
+ {
+ emsg(_(e_dictreq));
+ valid_dict = FALSE;
+ }
+ }
+
+ ++recursive;
+ if (l != NULL && action && valid_dict && set_errorlist(wp, l, action,
+ (char_u *)(wp == NULL ? ":setqflist()" : ":setloclist()"),
+ d) == OK)
+ rettv->vval.v_number = 0;
+ --recursive;
+ }
+#endif
+}
+
+/*
+ * "setloclist()" function
+ */
+ static void
+f_setloclist(typval_T *argvars, typval_T *rettv)
+{
+ win_T *win;
+
+ rettv->vval.v_number = -1;
+
+ win = find_win_by_nr_or_id(&argvars[0]);
+ if (win != NULL)
+ set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv);
+}
+
+/*
+ * "setmatches()" function
+ */
+ static void
+f_setmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
+{
+#ifdef FEAT_SEARCH_EXTRA
+ list_T *l;
+ listitem_T *li;
+ dict_T *d;
+ list_T *s = NULL;
+
+ rettv->vval.v_number = -1;
+ if (argvars[0].v_type != VAR_LIST)
+ {
+ emsg(_(e_listreq));
+ return;
+ }
+ if ((l = argvars[0].vval.v_list) != NULL)
+ {
+
+ /* To some extent make sure that we are dealing with a list from
+ * "getmatches()". */
+ li = l->lv_first;
+ while (li != NULL)
+ {
+ if (li->li_tv.v_type != VAR_DICT
+ || (d = li->li_tv.vval.v_dict) == NULL)
+ {
+ emsg(_(e_invarg));
+ return;
+ }
+ if (!(dict_find(d, (char_u *)"group", -1) != NULL
+ && (dict_find(d, (char_u *)"pattern", -1) != NULL
+ || dict_find(d, (char_u *)"pos1", -1) != NULL)
+ && dict_find(d, (char_u *)"priority", -1) != NULL
+ && dict_find(d, (char_u *)"id", -1) != NULL))
+ {
+ emsg(_(e_invarg));
+ return;
+ }
+ li = li->li_next;
+ }
+
+ clear_matches(curwin);
+ li = l->lv_first;
+ while (li != NULL)
+ {
+ int i = 0;
+ char_u buf[5];
+ dictitem_T *di;
+ char_u *group;
+ int priority;
+ int id;
+ char_u *conceal;
+
+ d = li->li_tv.vval.v_dict;
+ if (dict_find(d, (char_u *)"pattern", -1) == NULL)
+ {
+ if (s == NULL)
+ {
+ s = list_alloc();
+ if (s == NULL)
+ return;
+ }
+
+ /* match from matchaddpos() */
+ for (i = 1; i < 9; i++)
+ {
+ sprintf((char *)buf, (char *)"pos%d", i);
+ if ((di = dict_find(d, (char_u *)buf, -1)) != NULL)
+ {
+ if (di->di_tv.v_type != VAR_LIST)
+ return;
+
+ list_append_tv(s, &di->di_tv);
+ s->lv_refcount++;
+ }
+ else
+ break;
+ }
+ }
+
+ group = dict_get_string(d, (char_u *)"group", TRUE);
+ priority = (int)dict_get_number(d, (char_u *)"priority");
+ id = (int)dict_get_number(d, (char_u *)"id");
+ conceal = dict_find(d, (char_u *)"conceal", -1) != NULL
+ ? dict_get_string(d, (char_u *)"conceal", TRUE)
+ : NULL;
+ if (i == 0)
+ {
+ match_add(curwin, group,
+ dict_get_string(d, (char_u *)"pattern", FALSE),
+ priority, id, NULL, conceal);
+ }
+ else
+ {
+ match_add(curwin, group, NULL, priority, id, s, conceal);
+ list_unref(s);
+ s = NULL;
+ }
+ vim_free(group);
+ vim_free(conceal);
+
+ li = li->li_next;
+ }
+ rettv->vval.v_number = 0;
+ }
+#endif
+}
+
+/*
+ * "setpos()" function
+ */
+ static void
+f_setpos(typval_T *argvars, typval_T *rettv)
+{
+ pos_T pos;
+ int fnum;
+ char_u *name;
+ colnr_T curswant = -1;
+
+ rettv->vval.v_number = -1;
+ name = tv_get_string_chk(argvars);
+ if (name != NULL)
+ {
+ if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
+ {
+ if (--pos.col < 0)
+ pos.col = 0;
+ if (name[0] == '.' && name[1] == NUL)
+ {
+ /* set cursor; "fnum" is ignored */
+ curwin->w_cursor = pos;
+ if (curswant >= 0)
+ {
+ curwin->w_curswant = curswant - 1;
+ curwin->w_set_curswant = FALSE;
+ }
+ check_cursor();
+ rettv->vval.v_number = 0;
+ }
+ else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
+ {
+ /* set mark */
+ if (setmark_pos(name[1], &pos, fnum) == OK)
+ rettv->vval.v_number = 0;
+ }
+ else
+ emsg(_(e_invarg));
+ }
+ }
+}
+
+/*
+ * "setqflist()" function
+ */
+ static void
+f_setqflist(typval_T *argvars, typval_T *rettv)
+{
+ set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv);
+}
+
+/*
+ * "setreg()" function
+ */
+ static void
+f_setreg(typval_T *argvars, typval_T *rettv)
+{
+ int regname;
+ char_u *strregname;
+ char_u *stropt;
+ char_u *strval;
+ int append;
+ char_u yank_type;
+ long block_len;
+
+ block_len = -1;
+ yank_type = MAUTO;
+ append = FALSE;
+
+ strregname = tv_get_string_chk(argvars);
+ rettv->vval.v_number = 1; /* FAIL is default */
+
+ if (strregname == NULL)
+ return; /* type error; errmsg already given */
+ regname = *strregname;
+ if (regname == 0 || regname == '@')
+ regname = '"';
+
+ if (argvars[2].v_type != VAR_UNKNOWN)
+ {
+ stropt = tv_get_string_chk(&argvars[2]);
+ if (stropt == NULL)
+ return; /* type error */
+ for (; *stropt != NUL; ++stropt)
+ switch (*stropt)
+ {
+ case 'a': case 'A': /* append */
+ append = TRUE;
+ break;
+ case 'v': case 'c': /* character-wise selection */
+ yank_type = MCHAR;
+ break;
+ case 'V': case 'l': /* line-wise selection */
+ yank_type = MLINE;
+ break;
+ case 'b': case Ctrl_V: /* block-wise selection */
+ yank_type = MBLOCK;
+ if (VIM_ISDIGIT(stropt[1]))
+ {
+ ++stropt;
+ block_len = getdigits(&stropt) - 1;
+ --stropt;
+ }
+ break;
+ }
+ }
+
+ if (argvars[1].v_type == VAR_LIST)
+ {
+ char_u **lstval;
+ char_u **allocval;
+ char_u buf[NUMBUFLEN];
+ char_u **curval;
+ char_u **curallocval;
+ list_T *ll = argvars[1].vval.v_list;
+ listitem_T *li;
+ int len;
+
+ /* If the list is NULL handle like an empty list. */
+ len = ll == NULL ? 0 : ll->lv_len;
+
+ /* First half: use for pointers to result lines; second half: use for
+ * pointers to allocated copies. */
+ lstval = (char_u **)alloc(sizeof(char_u *) * ((len + 1) * 2));
+ if (lstval == NULL)
+ return;
+ curval = lstval;
+ allocval = lstval + len + 2;
+ curallocval = allocval;
+
+ for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
+ li = li->li_next)
+ {
+ strval = tv_get_string_buf_chk(&li->li_tv, buf);
+ if (strval == NULL)
+ goto free_lstval;
+ if (strval == buf)
+ {
+ /* Need to make a copy, next tv_get_string_buf_chk() will
+ * overwrite the string. */
+ strval = vim_strsave(buf);
+ if (strval == NULL)
+ goto free_lstval;
+ *curallocval++ = strval;
+ }
+ *curval++ = strval;
+ }
+ *curval++ = NULL;
+
+ write_reg_contents_lst(regname, lstval, -1,
+ append, yank_type, block_len);
+free_lstval:
+ while (curallocval > allocval)
+ vim_free(*--curallocval);
+ vim_free(lstval);
+ }
+ else
+ {
+ strval = tv_get_string_chk(&argvars[1]);
+ if (strval == NULL)
+ return;
+ write_reg_contents_ex(regname, strval, -1,
+ append, yank_type, block_len);
+ }
+ rettv->vval.v_number = 0;
+}
+
+/*
+ * "settabvar()" function
+ */
+ static void
+f_settabvar(typval_T *argvars, typval_T *rettv)
+{
+ tabpage_T *save_curtab;
+ tabpage_T *tp;
+ char_u *varname, *tabvarname;
+ typval_T *varp;
+
+ rettv->vval.v_number = 0;
+
+ if (check_restricted() || check_secure())
+ return;
+
+ tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
+ varname = tv_get_string_chk(&argvars[1]);
+ varp = &argvars[2];
+
+ if (varname != NULL && varp != NULL && tp != NULL)
+ {
+ save_curtab = curtab;
+ goto_tabpage_tp(tp, FALSE, FALSE);
+
+ tabvarname = alloc((unsigned)STRLEN(varname) + 3);
+ if (tabvarname != NULL)
+ {
+ STRCPY(tabvarname, "t:");
+ STRCPY(tabvarname + 2, varname);
+ set_var(tabvarname, varp, TRUE);
+ vim_free(tabvarname);
+ }
+
+ /* Restore current tabpage */
+ if (valid_tabpage(save_curtab))
+ goto_tabpage_tp(save_curtab, FALSE, FALSE);
+ }
+}
+
+/*
+ * "settabwinvar()" function
+ */
+ static void
+f_settabwinvar(typval_T *argvars, typval_T *rettv)
+{
+ setwinvar(argvars, rettv, 1);
+}
+
+/*
+ * "settagstack()" function
+ */
+ static void
+f_settagstack(typval_T *argvars, typval_T *rettv)
+{
+ static char *e_invact2 = N_("E962: Invalid action: '%s'");
+ win_T *wp;
+ dict_T *d;
+ int action = 'r';
+
+ rettv->vval.v_number = -1;
+
+ // first argument: window number or id
+ wp = find_win_by_nr_or_id(&argvars[0]);
+ if (wp == NULL)
+ return;
+
+ // second argument: dict with items to set in the tag stack
+ if (argvars[1].v_type != VAR_DICT)
+ {
+ emsg(_(e_dictreq));
+ return;
+ }
+ d = argvars[1].vval.v_dict;
+ if (d == NULL)
+ return;
+
+ // third argument: action - 'a' for append and 'r' for replace.
+ // default is to replace the stack.
+ if (argvars[2].v_type == VAR_UNKNOWN)
+ action = 'r';
+ else if (argvars[2].v_type == VAR_STRING)
+ {
+ char_u *actstr;
+ actstr = tv_get_string_chk(&argvars[2]);
+ if (actstr == NULL)
+ return;
+ if ((*actstr == 'r' || *actstr == 'a') && actstr[1] == NUL)
+ action = *actstr;
+ else
+ {
+ semsg(_(e_invact2), actstr);
+ return;
+ }
+ }
+ else
+ {
+ emsg(_(e_stringreq));
+ return;
+ }
+
+ if (set_tagstack(wp, d, action) == OK)
+ rettv->vval.v_number = 0;
+}
+
+/*
+ * "setwinvar()" function
+ */
+ static void
+f_setwinvar(typval_T *argvars, typval_T *rettv)
+{
+ setwinvar(argvars, rettv, 0);
+}
+
+#ifdef FEAT_CRYPT
+/*
+ * "sha256({string})" function
+ */
+ static void
+f_sha256(typval_T *argvars, typval_T *rettv)
+{
+ char_u *p;
+
+ p = tv_get_string(&argvars[0]);
+ rettv->vval.v_string = vim_strsave(
+ sha256_bytes(p, (int)STRLEN(p), NULL, 0));
+ rettv->v_type = VAR_STRING;
+}
+#endif /* FEAT_CRYPT */
+
+/*
+ * "shellescape({string})" function
+ */
+ static void
+f_shellescape(typval_T *argvars, typval_T *rettv)
+{
+ int do_special = non_zero_arg(&argvars[1]);
+
+ rettv->vval.v_string = vim_strsave_shellescape(
+ tv_get_string(&argvars[0]), do_special, do_special);
+ rettv->v_type = VAR_STRING;
+}
+
+/*
+ * shiftwidth() function
+ */
+ static void
+f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ rettv->vval.v_number = 0;
+
+ if (argvars[0].v_type != VAR_UNKNOWN)
+ {
+ long col;
+
+ col = (long)tv_get_number_chk(argvars, NULL);
+ if (col < 0)
+ return; // type error; errmsg already given
+#ifdef FEAT_VARTABS
+ rettv->vval.v_number = get_sw_value_col(curbuf, col);
+ return;
+#endif
+ }
+
+ rettv->vval.v_number = get_sw_value(curbuf);
+}
+
+#ifdef FEAT_SIGNS
+/*
+ * "sign_define()" function
+ */
+ static void
+f_sign_define(typval_T *argvars, typval_T *rettv)
+{
+ char_u *name;
+ dict_T *dict;
+ char_u *icon = NULL;
+ char_u *linehl = NULL;
+ char_u *text = NULL;
+ char_u *texthl = NULL;
+
+ rettv->vval.v_number = -1;
+
+ name = tv_get_string_chk(&argvars[0]);
+ if (name == NULL)
+ return;
+
+ if (argvars[1].v_type != VAR_UNKNOWN)
+ {
+ if (argvars[1].v_type != VAR_DICT)
+ {
+ emsg(_(e_dictreq));
+ return;
+ }
+
+ // sign attributes
+ dict = argvars[1].vval.v_dict;
+ if (dict_find(dict, (char_u *)"icon", -1) != NULL)
+ icon = dict_get_string(dict, (char_u *)"icon", TRUE);
+ if (dict_find(dict, (char_u *)"linehl", -1) != NULL)
+ linehl = dict_get_string(dict, (char_u *)"linehl", TRUE);
+ if (dict_find(dict, (char_u *)"text", -1) != NULL)
+ text = dict_get_string(dict, (char_u *)"text", TRUE);
+ if (dict_find(dict, (char_u *)"texthl", -1) != NULL)
+ texthl = dict_get_string(dict, (char_u *)"texthl", TRUE);
+ }
+
+ if (sign_define_by_name(name, icon, linehl, text, texthl) == OK)
+ rettv->vval.v_number = 0;
+
+ vim_free(icon);
+ vim_free(linehl);
+ vim_free(text);
+ vim_free(texthl);
+}
+
+/*
+ * "sign_getdefined()" function
+ */
+ static void
+f_sign_getdefined(typval_T *argvars, typval_T *rettv)
+{
+ char_u *name = NULL;
+
+ if (rettv_list_alloc_id(rettv, aid_sign_getdefined) != OK)
+ return;
+
+ if (argvars[0].v_type != VAR_UNKNOWN)
+ name = tv_get_string(&argvars[0]);
+
+ sign_getlist(name, rettv->vval.v_list);
+}
+
+/*
+ * "sign_getplaced()" function
+ */
+ static void
+f_sign_getplaced(typval_T *argvars, typval_T *rettv)
+{
+ buf_T *buf = NULL;
+ dict_T *dict;
+ dictitem_T *di;
+ linenr_T lnum = 0;
+ int sign_id = 0;
+ char_u *group = NULL;
+ int notanum = FALSE;
+
+ if (rettv_list_alloc_id(rettv, aid_sign_getplaced) != OK)
+ return;
+
+ if (argvars[0].v_type != VAR_UNKNOWN)
+ {
+ // get signs placed in the specified buffer
+ buf = get_buf_arg(&argvars[0]);
+ if (buf == NULL)
+ return;
+
+ if (argvars[1].v_type != VAR_UNKNOWN)
+ {
+ if (argvars[1].v_type != VAR_DICT ||
+ ((dict = argvars[1].vval.v_dict) == NULL))
+ {
+ emsg(_(e_dictreq));
+ return;
+ }
+ if ((di = dict_find(dict, (char_u *)"lnum", -1)) != NULL)
+ {
+ // get signs placed at this line
+ (void)tv_get_number_chk(&di->di_tv, &notanum);
+ if (notanum)
+ return;
+ lnum = tv_get_lnum(&di->di_tv);
+ }
+ if ((di = dict_find(dict, (char_u *)"id", -1)) != NULL)
+ {
+ // get sign placed with this identifier
+ sign_id = (int)tv_get_number_chk(&di->di_tv, &notanum);
+ if (notanum)
+ return;
+ }
+ if ((di = dict_find(dict, (char_u *)"group", -1)) != NULL)
+ {
+ group = tv_get_string_chk(&di->di_tv);
+ if (group == NULL)
+ return;
+ if (*group == '\0') // empty string means global group
+ group = NULL;
+ }
+ }
+ }
+
+ sign_get_placed(buf, lnum, sign_id, group, rettv->vval.v_list);
+}
+
+/*
+ * "sign_jump()" function
+ */
+ static void
+f_sign_jump(typval_T *argvars, typval_T *rettv)
+{
+ int sign_id;
+ char_u *sign_group = NULL;
+ buf_T *buf;
+ int notanum = FALSE;
+
+ rettv->vval.v_number = -1;
+
+ // Sign identifer
+ sign_id = (int)tv_get_number_chk(&argvars[0], &notanum);
+ if (notanum)
+ return;
+ if (sign_id <= 0)
+ {
+ emsg(_(e_invarg));
+ return;
+ }
+
+ // Sign group
+ sign_group = tv_get_string_chk(&argvars[1]);
+ if (sign_group == NULL)
+ return;
+ if (sign_group[0] == '\0')
+ sign_group = NULL; // global sign group
+ else
+ {
+ sign_group = vim_strsave(sign_group);
+ if (sign_group == NULL)
+ return;
+ }
+
+ // Buffer to place the sign
+ buf = get_buf_arg(&argvars[2]);
+ if (buf == NULL)
+ goto cleanup;
+
+ rettv->vval.v_number = sign_jump(sign_id, sign_group, buf);
+
+cleanup:
+ vim_free(sign_group);
+}
+
+/*
+ * "sign_place()" function
+ */
+ static void
+f_sign_place(typval_T *argvars, typval_T *rettv)
+{
+ int sign_id;
+ char_u *group = NULL;
+ char_u *sign_name;
+ buf_T *buf;
+ dict_T *dict;
+ dictitem_T *di;
+ linenr_T lnum = 0;
+ int prio = SIGN_DEF_PRIO;
+ int notanum = FALSE;
+
+ rettv->vval.v_number = -1;
+
+ // Sign identifer
+ sign_id = (int)tv_get_number_chk(&argvars[0], &notanum);
+ if (notanum)
+ return;
+ if (sign_id < 0)
+ {
+ emsg(_(e_invarg));
+ return;
+ }
+
+ // Sign group
+ group = tv_get_string_chk(&argvars[1]);
+ if (group == NULL)
+ return;
+ if (group[0] == '\0')
+ group = NULL; // global sign group
+ else
+ {
+ group = vim_strsave(group);
+ if (group == NULL)
+ return;
+ }
+
+ // Sign name
+ sign_name = tv_get_string_chk(&argvars[2]);
+ if (sign_name == NULL)
+ goto cleanup;
+
+ // Buffer to place the sign
+ buf = get_buf_arg(&argvars[3]);
+ if (buf == NULL)
+ goto cleanup;
+
+ if (argvars[4].v_type != VAR_UNKNOWN)
+ {
+ if (argvars[4].v_type != VAR_DICT ||
+ ((dict = argvars[4].vval.v_dict) == NULL))
+ {
+ emsg(_(e_dictreq));
+ goto cleanup;
+ }
+
+ // Line number where the sign is to be placed
+ if ((di = dict_find(dict, (char_u *)"lnum", -1)) != NULL)
+ {
+ (void)tv_get_number_chk(&di->di_tv, &notanum);
+ if (notanum)
+ goto cleanup;
+ lnum = tv_get_lnum(&di->di_tv);
+ }
+ if ((di = dict_find(dict, (char_u *)"priority", -1)) != NULL)
+ {
+ // Sign priority
+ prio = (int)tv_get_number_chk(&di->di_tv, &notanum);
+ if (notanum)
+ goto cleanup;
+ }
+ }
+
+ if (sign_place(&sign_id, group, sign_name, buf, lnum, prio) == OK)
+ rettv->vval.v_number = sign_id;
+
+cleanup:
+ vim_free(group);
+}
+
+/*
+ * "sign_undefine()" function
+ */
+ static void
+f_sign_undefine(typval_T *argvars, typval_T *rettv)
+{
+ char_u *name;
+
+ rettv->vval.v_number = -1;
+
+ if (argvars[0].v_type == VAR_UNKNOWN)
+ {
+ // Free all the signs
+ free_signs();
+ rettv->vval.v_number = 0;
+ }
+ else
+ {
+ // Free only the specified sign
+ name = tv_get_string_chk(&argvars[0]);
+ if (name == NULL)
+ return;
+
+ if (sign_undefine_by_name(name) == OK)
+ rettv->vval.v_number = 0;
+ }
+}
+
+/*
+ * "sign_unplace()" function
+ */
+ static void
+f_sign_unplace(typval_T *argvars, typval_T *rettv)
+{
+ dict_T *dict;
+ dictitem_T *di;
+ int sign_id = 0;
+ buf_T *buf = NULL;
+ char_u *group = NULL;
+
+ rettv->vval.v_number = -1;
+
+ if (argvars[0].v_type != VAR_STRING)
+ {
+ emsg(_(e_invarg));
+ return;
+ }
+
+ group = tv_get_string(&argvars[0]);
+ if (group[0] == '\0')
+ group = NULL; // global sign group
+ else
+ {
+ group = vim_strsave(group);
+ if (group == NULL)
+ return;
+ }
+
+ if (argvars[1].v_type != VAR_UNKNOWN)
+ {
+ if (argvars[1].v_type != VAR_DICT)
+ {
+ emsg(_(e_dictreq));
+ goto cleanup;
+ }
+ dict = argvars[1].vval.v_dict;
+
+ if ((di = dict_find(dict, (char_u *)"buffer", -1)) != NULL)
+ {
+ buf = get_buf_arg(&di->di_tv);
+ if (buf == NULL)
+ goto cleanup;
+ }
+ if (dict_find(dict, (char_u *)"id", -1) != NULL)
+ sign_id = dict_get_number(dict, (char_u *)"id");
+ }
+
+ if (buf == NULL)
+ {
+ // Delete the sign in all the buffers
+ FOR_ALL_BUFFERS(buf)
+ if (sign_unplace(sign_id, group, buf, 0) == OK)
+ rettv->vval.v_number = 0;
+ }
+ else
+ {
+ if (sign_unplace(sign_id, group, buf, 0) == OK)
+ rettv->vval.v_number = 0;
+ }
+
+cleanup:
+ vim_free(group);
+}
+#endif
+
+/*
+ * "simplify()" function
+ */
+ static void
+f_simplify(typval_T *argvars, typval_T *rettv)
+{
+ char_u *p;
+
+ p = tv_get_string(&argvars[0]);
+ rettv->vval.v_string = vim_strsave(p);
+ simplify_filename(rettv->vval.v_string); /* simplify in place */
+ rettv->v_type = VAR_STRING;
+}
+
+#ifdef FEAT_FLOAT
+/*
+ * "sin()" function
+ */
+ static void
+f_sin(typval_T *argvars, typval_T *rettv)
+{
+ float_T f = 0.0;
+
+ rettv->v_type = VAR_FLOAT;
+ if (get_float_arg(argvars, &f) == OK)
+ rettv->vval.v_float = sin(f);
+ else
+ rettv->vval.v_float = 0.0;
+}
+
+/*
+ * "sinh()" function
+ */
+ static void
+f_sinh(typval_T *argvars, typval_T *rettv)
+{
+ float_T f = 0.0;
+
+ rettv->v_type = VAR_FLOAT;
+ if (get_float_arg(argvars, &f) == OK)
+ rettv->vval.v_float = sinh(f);
+ else
+ rettv->vval.v_float = 0.0;
+}
+#endif
+
+static int
+#ifdef __BORLANDC__
+ _RTLENTRYF
+#endif
+ item_compare(const void *s1, const void *s2);
+static int
+#ifdef __BORLANDC__
+ _RTLENTRYF
+#endif
+ item_compare2(const void *s1, const void *s2);
+
+/* struct used in the array that's given to qsort() */
+typedef struct
+{
+ listitem_T *item;
+ int idx;
+} sortItem_T;
+
+/* struct storing information about current sort */
+typedef struct
+{
+ int item_compare_ic;
+ int item_compare_numeric;
+ int item_compare_numbers;
+#ifdef FEAT_FLOAT
+ int item_compare_float;
+#endif
+ char_u *item_compare_func;
+ partial_T *item_compare_partial;
+ dict_T *item_compare_selfdict;
+ int item_compare_func_err;
+ int item_compare_keep_zero;
+} sortinfo_T;
+static sortinfo_T *sortinfo = NULL;
+#define ITEM_COMPARE_FAIL 999
+
+/*
+ * Compare functions for f_sort() and f_uniq() below.
+ */
+ static int
+#ifdef __BORLANDC__
+_RTLENTRYF
+#endif
+item_compare(const void *s1, const void *s2)
+{
+ sortItem_T *si1, *si2;
+ typval_T *tv1, *tv2;
+ char_u *p1, *p2;
+ char_u *tofree1 = NULL, *tofree2 = NULL;
+ int res;
+ char_u numbuf1[NUMBUFLEN];
+ char_u numbuf2[NUMBUFLEN];
+
+ si1 = (sortItem_T *)s1;
+ si2 = (sortItem_T *)s2;
+ tv1 = &si1->item->li_tv;
+ tv2 = &si2->item->li_tv;
+
+ if (sortinfo->item_compare_numbers)
+ {
+ varnumber_T v1 = tv_get_number(tv1);
+ varnumber_T v2 = tv_get_number(tv2);
+
+ return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
+ }
+
+#ifdef FEAT_FLOAT
+ if (sortinfo->item_compare_float)
+ {
+ float_T v1 = tv_get_float(tv1);
+ float_T v2 = tv_get_float(tv2);
+
+ return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
+ }
+#endif
+
+ /* tv2string() puts quotes around a string and allocates memory. Don't do
+ * that for string variables. Use a single quote when comparing with a
+ * non-string to do what the docs promise. */
+ if (tv1->v_type == VAR_STRING)
+ {
+ if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric)
+ p1 = (char_u *)"'";
+ else
+ p1 = tv1->vval.v_string;
+ }
+ else
+ p1 = tv2string(tv1, &tofree1, numbuf1, 0);
+ if (tv2->v_type == VAR_STRING)
+ {
+ if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric)
+ p2 = (char_u *)"'";
+ else
+ p2 = tv2->vval.v_string;
+ }
+ else
+ p2 = tv2string(tv2, &tofree2, numbuf2, 0);
+ if (p1 == NULL)
+ p1 = (char_u *)"";
+ if (p2 == NULL)
+ p2 = (char_u *)"";
+ if (!sortinfo->item_compare_numeric)
+ {
+ if (sortinfo->item_compare_ic)
+ res = STRICMP(p1, p2);
+ else
+ res = STRCMP(p1, p2);
+ }
+ else
+ {
+ double n1, n2;
+ n1 = strtod((char *)p1, (char **)&p1);
+ n2 = strtod((char *)p2, (char **)&p2);
+ res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1;
+ }
+
+ /* When the result would be zero, compare the item indexes. Makes the
+ * sort stable. */
+ if (res == 0 && !sortinfo->item_compare_keep_zero)
+ res = si1->idx > si2->idx ? 1 : -1;
+
+ vim_free(tofree1);
+ vim_free(tofree2);
+ return res;
+}
+
+ static int
+#ifdef __BORLANDC__
+_RTLENTRYF
+#endif
+item_compare2(const void *s1, const void *s2)
+{
+ sortItem_T *si1, *si2;
+ int res;
+ typval_T rettv;
+ typval_T argv[3];
+ int dummy;
+ char_u *func_name;
+ partial_T *partial = sortinfo->item_compare_partial;
+
+ /* shortcut after failure in previous call; compare all items equal */
+ if (sortinfo->item_compare_func_err)
+ return 0;
+
+ si1 = (sortItem_T *)s1;
+ si2 = (sortItem_T *)s2;
+
+ if (partial == NULL)
+ func_name = sortinfo->item_compare_func;
+ else
+ func_name = partial_name(partial);
+
+ /* Copy the values. This is needed to be able to set v_lock to VAR_FIXED
+ * in the copy without changing the original list items. */
+ copy_tv(&si1->item->li_tv, &argv[0]);
+ copy_tv(&si2->item->li_tv, &argv[1]);
+
+ rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */
+ res = call_func(func_name, (int)STRLEN(func_name),
+ &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE,
+ partial, sortinfo->item_compare_selfdict);
+ clear_tv(&argv[0]);
+ clear_tv(&argv[1]);
+
+ if (res == FAIL)
+ res = ITEM_COMPARE_FAIL;
+ else
+ res = (int)tv_get_number_chk(&rettv, &sortinfo->item_compare_func_err);
+ if (sortinfo->item_compare_func_err)
+ res = ITEM_COMPARE_FAIL; /* return value has wrong type */
+ clear_tv(&rettv);
+
+ /* When the result would be zero, compare the pointers themselves. Makes
+ * the sort stable. */
+ if (res == 0 && !sortinfo->item_compare_keep_zero)
+ res = si1->idx > si2->idx ? 1 : -1;
+
+ return res;
+}
+
+/*
+ * "sort({list})" function
+ */
+ static void
+do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort)
+{
+ list_T *l;
+ listitem_T *li;
+ sortItem_T *ptrs;
+ sortinfo_T *old_sortinfo;
+ sortinfo_T info;
+ long len;
+ long i;
+
+ /* Pointer to current info struct used in compare function. Save and
+ * restore the current one for nested calls. */
+ old_sortinfo = sortinfo;
+ sortinfo = &info;
+
+ if (argvars[0].v_type != VAR_LIST)
+ semsg(_(e_listarg), sort ? "sort()" : "uniq()");
+ else
+ {
+ l = argvars[0].vval.v_list;
+ if (l == NULL || tv_check_lock(l->lv_lock,
+ (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")),
+ TRUE))
+ goto theend;
+ rettv_list_set(rettv, l);
+
+ len = list_len(l);
+ if (len <= 1)
+ goto theend; /* short list sorts pretty quickly */
+
+ info.item_compare_ic = FALSE;
+ info.item_compare_numeric = FALSE;
+ info.item_compare_numbers = FALSE;
+#ifdef FEAT_FLOAT
+ info.item_compare_float = FALSE;
+#endif
+ info.item_compare_func = NULL;
+ info.item_compare_partial = NULL;
+ info.item_compare_selfdict = NULL;
+ if (argvars[1].v_type != VAR_UNKNOWN)
+ {
+ /* optional second argument: {func} */
+ if (argvars[1].v_type == VAR_FUNC)
+ info.item_compare_func = argvars[1].vval.v_string;
+ else if (argvars[1].v_type == VAR_PARTIAL)
+ info.item_compare_partial = argvars[1].vval.v_partial;
+ else
+ {
+ int error = FALSE;
+
+ i = (long)tv_get_number_chk(&argvars[1], &error);
+ if (error)
+ goto theend; /* type error; errmsg already given */
+ if (i == 1)
+ info.item_compare_ic = TRUE;
+ else if (argvars[1].v_type != VAR_NUMBER)
+ info.item_compare_func = tv_get_string(&argvars[1]);
+ else if (i != 0)
+ {
+ emsg(_(e_invarg));
+ goto theend;
+ }
+ if (info.item_compare_func != NULL)
+ {
+ if (*info.item_compare_func == NUL)
+ {
+ /* empty string means default sort */
+ info.item_compare_func = NULL;
+ }
+ else if (STRCMP(info.item_compare_func, "n") == 0)
+ {
+ info.item_compare_func = NULL;
+ info.item_compare_numeric = TRUE;
+ }
+ else if (STRCMP(info.item_compare_func, "N") == 0)
+ {
+ info.item_compare_func = NULL;
+ info.item_compare_numbers = TRUE;
+ }
+#ifdef FEAT_FLOAT
+ else if (STRCMP(info.item_compare_func, "f") == 0)
+ {
+ info.item_compare_func = NULL;
+ info.item_compare_float = TRUE;
+ }
+#endif
+ else if (STRCMP(info.item_compare_func, "i") == 0)
+ {
+ info.item_compare_func = NULL;
+ info.item_compare_ic = TRUE;
+ }
+ }
+ }
+
+ if (argvars[2].v_type != VAR_UNKNOWN)
+ {
+ /* optional third argument: {dict} */
+ if (argvars[2].v_type != VAR_DICT)
+ {
+ emsg(_(e_dictreq));
+ goto theend;
+ }
+ info.item_compare_selfdict = argvars[2].vval.v_dict;
+ }
+ }
+
+ /* Make an array with each entry pointing to an item in the List. */
+ ptrs = (sortItem_T *)alloc((int)(len * sizeof(sortItem_T)));
+ if (ptrs == NULL)
+ goto theend;
+
+ i = 0;
+ if (sort)
+ {
+ /* sort(): ptrs will be the list to sort */
+ for (li = l->lv_first; li != NULL; li = li->li_next)
+ {
+ ptrs[i].item = li;
+ ptrs[i].idx = i;
+ ++i;
+ }
+
+ info.item_compare_func_err = FALSE;
+ info.item_compare_keep_zero = FALSE;
+ /* test the compare function */
+ if ((info.item_compare_func != NULL
+ || info.item_compare_partial != NULL)
+ && item_compare2((void *)&ptrs[0], (void *)&ptrs[1])
+ == ITEM_COMPARE_FAIL)
+ emsg(_("E702: Sort compare function failed"));
+ else
+ {
+ /* Sort the array with item pointers. */
+ qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T),
+ info.item_compare_func == NULL
+ && info.item_compare_partial == NULL
+ ? item_compare : item_compare2);
+
+ if (!info.item_compare_func_err)
+ {
+ /* Clear the List and append the items in sorted order. */
+ l->lv_first = l->lv_last = l->lv_idx_item = NULL;
+ l->lv_len = 0;
+ for (i = 0; i < len; ++i)
+ list_append(l, ptrs[i].item);
+ }
+ }
+ }
+ else
+ {
+ int (*item_compare_func_ptr)(const void *, const void *);
+
+ /* f_uniq(): ptrs will be a stack of items to remove */
+ info.item_compare_func_err = FALSE;
+ info.item_compare_keep_zero = TRUE;
+ item_compare_func_ptr = info.item_compare_func != NULL
+ || info.item_compare_partial != NULL
+ ? item_compare2 : item_compare;
+
+ for (li = l->lv_first; li != NULL && li->li_next != NULL;
+ li = li->li_next)
+ {
+ if (item_compare_func_ptr((void *)&li, (void *)&li->li_next)
+ == 0)
+ ptrs[i++].item = li;
+ if (info.item_compare_func_err)
+ {
+ emsg(_("E882: Uniq compare function failed"));
+ break;
+ }
+ }
+
+ if (!info.item_compare_func_err)
+ {
+ while (--i >= 0)
+ {
+ li = ptrs[i].item->li_next;
+ ptrs[i].item->li_next = li->li_next;
+ if (li->li_next != NULL)
+ li->li_next->li_prev = ptrs[i].item;
+ else
+ l->lv_last = ptrs[i].item;
+ list_fix_watch(l, li);
+ listitem_free(li);
+ l->lv_len--;
+ }
+ }
+ }
+
+ vim_free(ptrs);
+ }
+theend:
+ sortinfo = old_sortinfo;
+}
+
+/*
+ * "sort({list})" function
+ */
+ static void
+f_sort(typval_T *argvars, typval_T *rettv)
+{
+ do_sort_uniq(argvars, rettv, TRUE);
+}
+
+/*
+ * "uniq({list})" function
+ */
+ static void
+f_uniq(typval_T *argvars, typval_T *rettv)
+{
+ do_sort_uniq(argvars, rettv, FALSE);
+}
+
+/*
+ * "soundfold({word})" function
+ */
+ static void
+f_soundfold(typval_T *argvars, typval_T *rettv)
+{
+ char_u *s;
+
+ rettv->v_type = VAR_STRING;
+ s = tv_get_string(&argvars[0]);
+#ifdef FEAT_SPELL
+ rettv->vval.v_string = eval_soundfold(s);
+#else
+ rettv->vval.v_string = vim_strsave(s);
+#endif
+}
+
+/*
+ * "spellbadword()" function
+ */
+ static void
+f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ char_u *word = (char_u *)"";
+ hlf_T attr = HLF_COUNT;
+ int len = 0;
+
+ if (rettv_list_alloc(rettv) == FAIL)
+ return;
+
+#ifdef FEAT_SPELL
+ if (argvars[0].v_type == VAR_UNKNOWN)
+ {
+ /* Find the start and length of the badly spelled word. */
+ len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
+ if (len != 0)
+ {
+ word = ml_get_cursor();
+ curwin->w_set_curswant = TRUE;
+ }
+ }
+ else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
+ {
+ char_u *str = tv_get_string_chk(&argvars[0]);
+ int capcol = -1;
+
+ if (str != NULL)
+ {
+ /* Check the argument for spelling. */
+ while (*str != NUL)
+ {
+ len = spell_check(curwin, str, &attr, &capcol, FALSE);
+ if (attr != HLF_COUNT)
+ {
+ word = str;
+ break;
+ }
+ str += len;
+ capcol -= len;
+ }
+ }
+ }
+#endif
+
+ list_append_string(rettv->vval.v_list, word, len);
+ list_append_string(rettv->vval.v_list, (char_u *)(
+ attr == HLF_SPB ? "bad" :
+ attr == HLF_SPR ? "rare" :
+ attr == HLF_SPL ? "local" :
+ attr == HLF_SPC ? "caps" :
+ ""), -1);
+}
+
+/*
+ * "spellsuggest()" function
+ */
+ static void
+f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
+{
+#ifdef FEAT_SPELL
+ char_u *str;
+ int typeerr = FALSE;
+ int maxcount;
+ garray_T ga;
+ int i;
+ listitem_T *li;
+ int need_capital = FALSE;
+#endif
+
+ if (rettv_list_alloc(rettv) == FAIL)
+ return;
+
+#ifdef FEAT_SPELL
+ if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
+ {
+ str = tv_get_string(&argvars[0]);
+ if (argvars[1].v_type != VAR_UNKNOWN)
+ {
+ maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
+ if (maxcount <= 0)
+ return;
+ if (argvars[2].v_type != VAR_UNKNOWN)
+ {
+ need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
+ if (typeerr)
+ return;
+ }
+ }
+ else
+ maxcount = 25;
+
+ spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
+
+ for (i = 0; i < ga.ga_len; ++i)
+ {
+ str = ((char_u **)ga.ga_data)[i];
+
+ li = listitem_alloc();
+ if (li == NULL)
+ vim_free(str);
+ else
+ {
+ li->li_tv.v_type = VAR_STRING;
+ li->li_tv.v_lock = 0;
+ li->li_tv.vval.v_string = str;
+ list_append(rettv->vval.v_list, li);
+ }
+ }
+ ga_clear(&ga);
+ }
+#endif
+}
+
+ static void
+f_split(typval_T *argvars, typval_T *rettv)
+{
+ char_u *str;
+ char_u *end;
+ char_u *pat = NULL;
+ regmatch_T regmatch;
+ char_u patbuf[NUMBUFLEN];
+ char_u *save_cpo;
+ int match;
+ colnr_T col = 0;
+ int keepempty = FALSE;
+ int typeerr = FALSE;
+
+ /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
+ save_cpo = p_cpo;
+ p_cpo = (char_u *)"";
+
+ str = tv_get_string(&argvars[0]);
+ if (argvars[1].v_type != VAR_UNKNOWN)
+ {
+ pat = tv_get_string_buf_chk(&argvars[1], patbuf);
+ if (pat == NULL)
+ typeerr = TRUE;
+ if (argvars[2].v_type != VAR_UNKNOWN)
+ keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
+ }
+ if (pat == NULL || *pat == NUL)
+ pat = (char_u *)"[\\x01- ]\\+";
+
+ if (rettv_list_alloc(rettv) == FAIL)
+ return;
+ if (typeerr)
+ return;
+
+ regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
+ if (regmatch.regprog != NULL)
+ {
+ regmatch.rm_ic = FALSE;
+ while (*str != NUL || keepempty)
+ {
+ if (*str == NUL)
+ match = FALSE; /* empty item at the end */
+ else
+ match = vim_regexec_nl(&regmatch, str, col);
+ if (match)
+ end = regmatch.startp[0];
+ else
+ end = str + STRLEN(str);
+ if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
+ && *str != NUL && match && end < regmatch.endp[0]))
+ {
+ if (list_append_string(rettv->vval.v_list, str,
+ (int)(end - str)) == FAIL)
+ break;
+ }
+ if (!match)
+ break;
+ // Advance to just after the match.
+ if (regmatch.endp[0] > str)
+ col = 0;
+ else
+ // Don't get stuck at the same match.
+ col = (*mb_ptr2len)(regmatch.endp[0]);
+ str = regmatch.endp[0];
+ }
+
+ vim_regfree(regmatch.regprog);
+ }
+
+ p_cpo = save_cpo;
+}
+
+#ifdef FEAT_FLOAT
+/*
+ * "sqrt()" function
+ */
+ static void
+f_sqrt(typval_T *argvars, typval_T *rettv)
+{
+ float_T f = 0.0;
+
+ rettv->v_type = VAR_FLOAT;
+ if (get_float_arg(argvars, &f) == OK)
+ rettv->vval.v_float = sqrt(f);
+ else
+ rettv->vval.v_float = 0.0;
+}
+
+/*
+ * "str2float()" function
+ */
+ static void
+f_str2float(typval_T *argvars, typval_T *rettv)
+{
+ char_u *p = skipwhite(tv_get_string(&argvars[0]));
+ int isneg = (*p == '-');
+
+ if (*p == '+' || *p == '-')
+ p = skipwhite(p + 1);
+ (void)string2float(p, &rettv->vval.v_float);
+ if (isneg)
+ rettv->vval.v_float *= -1;
+ rettv->v_type = VAR_FLOAT;
+}
+#endif
+
+/*
+ * "str2nr()" function
+ */
+ static void
+f_str2nr(typval_T *argvars, typval_T *rettv)
+{
+ int base = 10;
+ char_u *p;
+ varnumber_T n;
+ int what;
+ int isneg;
+
+ if (argvars[1].v_type != VAR_UNKNOWN)
+ {
+ base = (int)tv_get_number(&argvars[1]);
+ if (base != 2 && base != 8 && base != 10 && base != 16)
+ {
+ emsg(_(e_invarg));
+ return;
+ }
+ }
+
+ p = skipwhite(tv_get_string(&argvars[0]));
+ isneg = (*p == '-');
+ if (*p == '+' || *p == '-')
+ p = skipwhite(p + 1);
+ switch (base)
+ {
+ case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
+ case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
+ case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
+ default: what = 0;
+ }
+ vim_str2nr(p, NULL, NULL, what, &n, NULL, 0);
+ if (isneg)
+ rettv->vval.v_number = -n;
+ else
+ rettv->vval.v_number = n;
+
+}
+
+#ifdef HAVE_STRFTIME
+/*
+ * "strftime({format}[, {time}])" function
+ */
+ static void
+f_strftime(typval_T *argvars, typval_T *rettv)
+{
+ char_u result_buf[256];
+ struct tm *curtime;
+ time_t seconds;
+ char_u *p;
+
+ rettv->v_type = VAR_STRING;
+
+ p = tv_get_string(&argvars[0]);
+ if (argvars[1].v_type == VAR_UNKNOWN)
+ seconds = time(NULL);
+ else
+ seconds = (time_t)tv_get_number(&argvars[1]);
+ curtime = localtime(&seconds);
+ /* MSVC returns NULL for an invalid value of seconds. */
+ if (curtime == NULL)
+ rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
+ else
+ {
+ vimconv_T conv;
+ char_u *enc;
+
+ conv.vc_type = CONV_NONE;
+ enc = enc_locale();
+ convert_setup(&conv, p_enc, enc);
+ if (conv.vc_type != CONV_NONE)
+ p = string_convert(&conv, p, NULL);
+ if (p != NULL)
+ (void)strftime((char *)result_buf, sizeof(result_buf),
+ (char *)p, curtime);
+ else
+ result_buf[0] = NUL;
+
+ if (conv.vc_type != CONV_NONE)
+ vim_free(p);
+ convert_setup(&conv, enc, p_enc);
+ if (conv.vc_type != CONV_NONE)
+ rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
+ else
+ rettv->vval.v_string = vim_strsave(result_buf);
+
+ /* Release conversion descriptors */
+ convert_setup(&conv, NULL, NULL);
+ vim_free(enc);
+ }
+}
+#endif
+
+/*
+ * "strgetchar()" function
+ */
+ static void
+f_strgetchar(typval_T *argvars, typval_T *rettv)
+{
+ char_u *str;
+ int len;
+ int error = FALSE;
+ int charidx;
+ int byteidx = 0;
+
+ rettv->vval.v_number = -1;
+ str = tv_get_string_chk(&argvars[0]);
+ if (str == NULL)
+ return;
+ len = (int)STRLEN(str);
+ charidx = (int)tv_get_number_chk(&argvars[1], &error);
+ if (error)
+ return;
+
+ while (charidx >= 0 && byteidx < len)
+ {
+ if (charidx == 0)
+ {
+ rettv->vval.v_number = mb_ptr2char(str + byteidx);
+ break;
+ }
+ --charidx;
+ byteidx += MB_CPTR2LEN(str + byteidx);
+ }
+}
+
+/*
+ * "stridx()" function
+ */
+ static void
+f_stridx(typval_T *argvars, typval_T *rettv)
+{
+ char_u buf[NUMBUFLEN];
+ char_u *needle;
+ char_u *haystack;
+ char_u *save_haystack;
+ char_u *pos;
+ int start_idx;
+
+ needle = tv_get_string_chk(&argvars[1]);
+ save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
+ rettv->vval.v_number = -1;
+ if (needle == NULL || haystack == NULL)
+ return; /* type error; errmsg already given */
+
+ if (argvars[2].v_type != VAR_UNKNOWN)
+ {
+ int error = FALSE;
+
+ start_idx = (int)tv_get_number_chk(&argvars[2], &error);
+ if (error || start_idx >= (int)STRLEN(haystack))
+ return;
+ if (start_idx >= 0)
+ haystack += start_idx;
+ }
+
+ pos = (char_u *)strstr((char *)haystack, (char *)needle);
+ if (pos != NULL)
+ rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
+}
+
+/*
+ * "string()" function
+ */
+ void
+f_string(typval_T *argvars, typval_T *rettv)
+{
+ char_u *tofree;
+ char_u numbuf[NUMBUFLEN];
+
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
+ get_copyID());
+ /* Make a copy if we have a value but it's not in allocated memory. */
+ if (rettv->vval.v_string != NULL && tofree == NULL)
+ rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
+}
+
+/*
+ * "strlen()" function
+ */
+ static void
+f_strlen(typval_T *argvars, typval_T *rettv)
+{
+ rettv->vval.v_number = (varnumber_T)(STRLEN(
+ tv_get_string(&argvars[0])));
+}
+
+/*
+ * "strchars()" function
+ */
+ static void
+f_strchars(typval_T *argvars, typval_T *rettv)
+{
+ char_u *s = tv_get_string(&argvars[0]);
+ int skipcc = 0;
+ varnumber_T len = 0;
+ int (*func_mb_ptr2char_adv)(char_u **pp);
+
+ if (argvars[1].v_type != VAR_UNKNOWN)
+ skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
+ if (skipcc < 0 || skipcc > 1)
+ emsg(_(e_invarg));
+ else
+ {
+ func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
+ while (*s != NUL)
+ {
+ func_mb_ptr2char_adv(&s);
+ ++len;
+ }
+ rettv->vval.v_number = len;
+ }
+}
+
+/*
+ * "strdisplaywidth()" function
+ */
+ static void
+f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
+{
+ char_u *s = tv_get_string(&argvars[0]);
+ int col = 0;
+
+ if (argvars[1].v_type != VAR_UNKNOWN)
+ col = (int)tv_get_number(&argvars[1]);
+
+ rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
+}
+
+/*
+ * "strwidth()" function
+ */
+ static void
+f_strwidth(typval_T *argvars, typval_T *rettv)
+{
+ char_u *s = tv_get_string(&argvars[0]);
+
+ rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
+}
+
+/*
+ * "strcharpart()" function
+ */
+ static void
+f_strcharpart(typval_T *argvars, typval_T *rettv)
+{
+ char_u *p;
+ int nchar;
+ int nbyte = 0;
+ int charlen;
+ int len = 0;
+ int slen;
+ int error = FALSE;
+
+ p = tv_get_string(&argvars[0]);
+ slen = (int)STRLEN(p);
+
+ nchar = (int)tv_get_number_chk(&argvars[1], &error);
+ if (!error)
+ {
+ if (nchar > 0)
+ while (nchar > 0 && nbyte < slen)
+ {
+ nbyte += MB_CPTR2LEN(p + nbyte);
+ --nchar;
+ }
+ else
+ nbyte = nchar;
+ if (argvars[2].v_type != VAR_UNKNOWN)
+ {
+ charlen = (int)tv_get_number(&argvars[2]);
+ while (charlen > 0 && nbyte + len < slen)
+ {
+ int off = nbyte + len;
+
+ if (off < 0)
+ len += 1;
+ else
+ len += MB_CPTR2LEN(p + off);
+ --charlen;
+ }
+ }
+ else
+ len = slen - nbyte; /* default: all bytes that are available. */
+ }
+
+ /*
+ * Only return the overlap between the specified part and the actual
+ * string.
+ */
+ if (nbyte < 0)
+ {
+ len += nbyte;
+ nbyte = 0;
+ }
+ else if (nbyte > slen)
+ nbyte = slen;
+ if (len < 0)
+ len = 0;
+ else if (nbyte + len > slen)
+ len = slen - nbyte;
+
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = vim_strnsave(p + nbyte, len);
+}
+
+/*
+ * "strpart()" function
+ */
+ static void
+f_strpart(typval_T *argvars, typval_T *rettv)
+{
+ char_u *p;
+ int n;
+ int len;
+ int slen;
+ int error = FALSE;
+
+ p = tv_get_string(&argvars[0]);
+ slen = (int)STRLEN(p);
+
+ n = (int)tv_get_number_chk(&argvars[1], &error);
+ if (error)
+ len = 0;
+ else if (argvars[2].v_type != VAR_UNKNOWN)
+ len = (int)tv_get_number(&argvars[2]);
+ else
+ len = slen - n; /* default len: all bytes that are available. */
+
+ /*
+ * Only return the overlap between the specified part and the actual
+ * string.
+ */
+ if (n < 0)
+ {
+ len += n;
+ n = 0;
+ }
+ else if (n > slen)
+ n = slen;
+ if (len < 0)
+ len = 0;
+ else if (n + len > slen)
+ len = slen - n;
+
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = vim_strnsave(p + n, len);
+}
+
+/*
+ * "strridx()" function
+ */
+ static void
+f_strridx(typval_T *argvars, typval_T *rettv)
+{
+ char_u buf[NUMBUFLEN];
+ char_u *needle;
+ char_u *haystack;
+ char_u *rest;
+ char_u *lastmatch = NULL;
+ int haystack_len, end_idx;
+
+ needle = tv_get_string_chk(&argvars[1]);
+ haystack = tv_get_string_buf_chk(&argvars[0], buf);
+
+ rettv->vval.v_number = -1;
+ if (needle == NULL || haystack == NULL)
+ return; /* type error; errmsg already given */
+
+ haystack_len = (int)STRLEN(haystack);
+ if (argvars[2].v_type != VAR_UNKNOWN)
+ {
+ /* Third argument: upper limit for index */
+ end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
+ if (end_idx < 0)
+ return; /* can never find a match */
+ }
+ else
+ end_idx = haystack_len;
+
+ if (*needle == NUL)
+ {
+ /* Empty string matches past the end. */
+ lastmatch = haystack + end_idx;
+ }
+ else
+ {
+ for (rest = haystack; *rest != '\0'; ++rest)
+ {
+ rest = (char_u *)strstr((char *)rest, (char *)needle);
+ if (rest == NULL || rest > haystack + end_idx)
+ break;
+ lastmatch = rest;
+ }
+ }
+
+ if (lastmatch == NULL)
+ rettv->vval.v_number = -1;
+ else
+ rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
+}
+
+/*
+ * "strtrans()" function
+ */
+ static void
+f_strtrans(typval_T *argvars, typval_T *rettv)
+{
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
+}
+
+/*
+ * "submatch()" function
+ */
+ static void
+f_submatch(typval_T *argvars, typval_T *rettv)
+{
+ int error = FALSE;
+ int no;
+ int retList = 0;
+
+ no = (int)tv_get_number_chk(&argvars[0], &error);
+ if (error)
+ return;
+ if (no < 0 || no >= NSUBEXP)
+ {
+ semsg(_("E935: invalid submatch number: %d"), no);
+ return;
+ }
+ if (argvars[1].v_type != VAR_UNKNOWN)
+ retList = (int)tv_get_number_chk(&argvars[1], &error);
+ if (error)
+ return;
+
+ if (retList == 0)
+ {
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = reg_submatch(no);
+ }
+ else
+ {
+ rettv->v_type = VAR_LIST;
+ rettv->vval.v_list = reg_submatch_list(no);
+ }
+}
+
+/*
+ * "substitute()" function
+ */
+ static void
+f_substitute(typval_T *argvars, typval_T *rettv)
+{
+ char_u patbuf[NUMBUFLEN];
+ char_u subbuf[NUMBUFLEN];
+ char_u flagsbuf[NUMBUFLEN];
+
+ char_u *str = tv_get_string_chk(&argvars[0]);
+ char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
+ char_u *sub = NULL;
+ typval_T *expr = NULL;
+ char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
+
+ if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
+ expr = &argvars[2];
+ else
+ sub = tv_get_string_buf_chk(&argvars[2], subbuf);
+
+ rettv->v_type = VAR_STRING;
+ if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
+ || flg == NULL)
+ rettv->vval.v_string = NULL;
+ else
+ rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
+}
+
+/*
+ * "swapinfo(swap_filename)" function
+ */
+ static void
+f_swapinfo(typval_T *argvars, typval_T *rettv)
+{
+ if (rettv_dict_alloc(rettv) == OK)
+ get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
+}
+
+/*
+ * "swapname(expr)" function
+ */
+ static void
+f_swapname(typval_T *argvars, typval_T *rettv)
+{
+ buf_T *buf;
+
+ rettv->v_type = VAR_STRING;
+ buf = tv_get_buf(&argvars[0], FALSE);
+ if (buf == NULL || buf->b_ml.ml_mfp == NULL
+ || buf->b_ml.ml_mfp->mf_fname == NULL)
+ rettv->vval.v_string = NULL;
+ else
+ rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
+}
+
+/*
+ * "synID(lnum, col, trans)" function
+ */
+ static void
+f_synID(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ int id = 0;
+#ifdef FEAT_SYN_HL
+ linenr_T lnum;
+ colnr_T col;
+ int trans;
+ int transerr = FALSE;
+
+ lnum = tv_get_lnum(argvars); /* -1 on type error */
+ col = (linenr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
+ trans = (int)tv_get_number_chk(&argvars[2], &transerr);
+
+ if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
+ && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
+ id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
+#endif
+
+ rettv->vval.v_number = id;
+}
+
+/*
+ * "synIDattr(id, what [, mode])" function
+ */
+ static void
+f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ char_u *p = NULL;
+#ifdef FEAT_SYN_HL
+ int id;
+ char_u *what;
+ char_u *mode;
+ char_u modebuf[NUMBUFLEN];
+ int modec;
+
+ id = (int)tv_get_number(&argvars[0]);
+ what = tv_get_string(&argvars[1]);
+ if (argvars[2].v_type != VAR_UNKNOWN)
+ {
+ mode = tv_get_string_buf(&argvars[2], modebuf);
+ modec = TOLOWER_ASC(mode[0]);
+ if (modec != 't' && modec != 'c' && modec != 'g')
+ modec = 0; /* replace invalid with current */
+ }
+ else
+ {
+#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
+ if (USE_24BIT)
+ modec = 'g';
+ else
+#endif
+ if (t_colors > 1)
+ modec = 'c';
+ else
+ modec = 't';
+ }
+
+ switch (TOLOWER_ASC(what[0]))
+ {
+ case 'b':
+ if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
+ p = highlight_color(id, what, modec);
+ else /* bold */
+ p = highlight_has_attr(id, HL_BOLD, modec);
+ break;
+
+ case 'f': /* fg[#] or font */
+ p = highlight_color(id, what, modec);
+ break;
+
+ case 'i':
+ if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
+ p = highlight_has_attr(id, HL_INVERSE, modec);
+ else /* italic */
+ p = highlight_has_attr(id, HL_ITALIC, modec);
+ break;
+
+ case 'n': /* name */
+ p = get_highlight_name_ext(NULL, id - 1, FALSE);
+ break;
+
+ case 'r': /* reverse */
+ p = highlight_has_attr(id, HL_INVERSE, modec);
+ break;
+
+ case 's':
+ if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
+ p = highlight_color(id, what, modec);
+ /* strikeout */
+ else if (TOLOWER_ASC(what[1]) == 't' &&
+ TOLOWER_ASC(what[2]) == 'r')
+ p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
+ else /* standout */
+ p = highlight_has_attr(id, HL_STANDOUT, modec);
+ break;
+
+ case 'u':
+ if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
+ /* underline */
+ p = highlight_has_attr(id, HL_UNDERLINE, modec);
+ else
+ /* undercurl */
+ p = highlight_has_attr(id, HL_UNDERCURL, modec);
+ break;
+ }
+
+ if (p != NULL)
+ p = vim_strsave(p);
+#endif
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = p;
+}
+
+/*
+ * "synIDtrans(id)" function
+ */
+ static void
+f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ int id;
+
+#ifdef FEAT_SYN_HL
+ id = (int)tv_get_number(&argvars[0]);
+
+ if (id > 0)
+ id = syn_get_final_id(id);
+ else
+#endif
+ id = 0;
+
+ rettv->vval.v_number = id;
+}
+
+/*
+ * "synconcealed(lnum, col)" function
+ */
+ static void
+f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
+{
+#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
+ linenr_T lnum;
+ colnr_T col;
+ int syntax_flags = 0;
+ int cchar;
+ int matchid = 0;
+ char_u str[NUMBUFLEN];
+#endif
+
+ rettv_list_set(rettv, NULL);
+
+#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
+ lnum = tv_get_lnum(argvars); /* -1 on type error */
+ col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
+
+ vim_memset(str, NUL, sizeof(str));
+
+ if (rettv_list_alloc(rettv) != FAIL)
+ {
+ if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
+ && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
+ && curwin->w_p_cole > 0)
+ {
+ (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
+ syntax_flags = get_syntax_info(&matchid);
+
+ /* get the conceal character */
+ if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
+ {
+ cchar = syn_get_sub_char();
+ if (cchar == NUL && curwin->w_p_cole == 1)
+ cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
+ if (cchar != NUL)
+ {
+ if (has_mbyte)
+ (*mb_char2bytes)(cchar, str);
+ else
+ str[0] = cchar;
+ }
+ }
+ }
+
+ list_append_number(rettv->vval.v_list,
+ (syntax_flags & HL_CONCEAL) != 0);
+ /* -1 to auto-determine strlen */
+ list_append_string(rettv->vval.v_list, str, -1);
+ list_append_number(rettv->vval.v_list, matchid);
+ }
+#endif
+}
+
+/*
+ * "synstack(lnum, col)" function
+ */
+ static void
+f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
+{
+#ifdef FEAT_SYN_HL
+ linenr_T lnum;
+ colnr_T col;
+ int i;
+ int id;
+#endif
+
+ rettv_list_set(rettv, NULL);
+
+#ifdef FEAT_SYN_HL
+ lnum = tv_get_lnum(argvars); /* -1 on type error */
+ col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
+
+ if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
+ && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
+ && rettv_list_alloc(rettv) != FAIL)
+ {
+ (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
+ for (i = 0; ; ++i)
+ {
+ id = syn_get_stack_item(i);
+ if (id < 0)
+ break;
+ if (list_append_number(rettv->vval.v_list, id) == FAIL)
+ break;
+ }
+ }
+#endif
+}
+
+ static void
+get_cmd_output_as_rettv(
+ typval_T *argvars,
+ typval_T *rettv,
+ int retlist)
+{
+ char_u *res = NULL;
+ char_u *p;
+ char_u *infile = NULL;
+ int err = FALSE;
+ FILE *fd;
+ list_T *list = NULL;
+ int flags = SHELL_SILENT;
+
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+ if (check_restricted() || check_secure())
+ goto errret;
+
+ if (argvars[1].v_type != VAR_UNKNOWN)
+ {
+ /*
+ * Write the text to a temp file, to be used for input of the shell
+ * command.
+ */
+ if ((infile = vim_tempname('i', TRUE)) == NULL)
+ {
+ emsg(_(e_notmp));
+ goto errret;
+ }
+
+ fd = mch_fopen((char *)infile, WRITEBIN);
+ if (fd == NULL)
+ {
+ semsg(_(e_notopen), infile);
+ goto errret;
+ }
+ if (argvars[1].v_type == VAR_NUMBER)
+ {
+ linenr_T lnum;
+ buf_T *buf;
+
+ buf = buflist_findnr(argvars[1].vval.v_number);
+ if (buf == NULL)
+ {
+ semsg(_(e_nobufnr), argvars[1].vval.v_number);
+ fclose(fd);
+ goto errret;
+ }
+
+ for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++)
+ {
+ for (p = ml_get_buf(buf, lnum, FALSE); *p != NUL; ++p)
+ if (putc(*p == '\n' ? NUL : *p, fd) == EOF)
+ {
+ err = TRUE;
+ break;
+ }
+ if (putc(NL, fd) == EOF)
+ {
+ err = TRUE;
+ break;
+ }
+ }
+ }
+ else if (argvars[1].v_type == VAR_LIST)
+ {
+ if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
+ err = TRUE;
+ }
+ else
+ {
+ size_t len;
+ char_u buf[NUMBUFLEN];
+
+ p = tv_get_string_buf_chk(&argvars[1], buf);
+ if (p == NULL)
+ {
+ fclose(fd);
+ goto errret; /* type error; errmsg already given */
+ }
+ len = STRLEN(p);
+ if (len > 0 && fwrite(p, len, 1, fd) != 1)
+ err = TRUE;
+ }
+ if (fclose(fd) != 0)
+ err = TRUE;
+ if (err)
+ {
+ emsg(_("E677: Error writing temp file"));
+ goto errret;
+ }
+ }
+
+ /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell
+ * echoes typeahead, that messes up the display. */
+ if (!msg_silent)
+ flags += SHELL_COOKED;
+
+ if (retlist)
+ {
+ int len;
+ listitem_T *li;
+ char_u *s = NULL;
+ char_u *start;
+ char_u *end;
+ int i;
+
+ res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, &len);
+ if (res == NULL)
+ goto errret;
+
+ list = list_alloc();
+ if (list == NULL)
+ goto errret;
+
+ for (i = 0; i < len; ++i)
+ {
+ start = res + i;
+ while (i < len && res[i] != NL)
+ ++i;
+ end = res + i;
+
+ s = alloc((unsigned)(end - start + 1));
+ if (s == NULL)
+ goto errret;
+
+ for (p = s; start < end; ++p, ++start)
+ *p = *start == NUL ? NL : *start;
+ *p = NUL;
+
+ li = listitem_alloc();
+ if (li == NULL)
+ {
+ vim_free(s);
+ goto errret;
+ }
+ li->li_tv.v_type = VAR_STRING;
+ li->li_tv.v_lock = 0;
+ li->li_tv.vval.v_string = s;
+ list_append(list, li);
+ }
+
+ rettv_list_set(rettv, list);
+ list = NULL;
+ }
+ else
+ {
+ res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, NULL);
+#ifdef USE_CR
+ /* translate <CR> into <NL> */
+ if (res != NULL)
+ {
+ char_u *s;
+
+ for (s = res; *s; ++s)
+ {
+ if (*s == CAR)
+ *s = NL;
+ }
+ }
+#else
+# ifdef USE_CRNL
+ /* translate <CR><NL> into <NL> */
+ if (res != NULL)
+ {
+ char_u *s, *d;
+
+ d = res;
+ for (s = res; *s; ++s)
+ {
+ if (s[0] == CAR && s[1] == NL)
+ ++s;
+ *d++ = *s;
+ }
+ *d = NUL;
+ }
+# endif
+#endif
+ rettv->vval.v_string = res;
+ res = NULL;
+ }
+
+errret:
+ if (infile != NULL)
+ {
+ mch_remove(infile);
+ vim_free(infile);
+ }
+ if (res != NULL)
+ vim_free(res);
+ if (list != NULL)
+ list_free(list);
+}
+
+/*
+ * "system()" function
+ */
+ static void
+f_system(typval_T *argvars, typval_T *rettv)
+{
+ get_cmd_output_as_rettv(argvars, rettv, FALSE);
+}
+
+/*
+ * "systemlist()" function
+ */
+ static void
+f_systemlist(typval_T *argvars, typval_T *rettv)
+{
+ get_cmd_output_as_rettv(argvars, rettv, TRUE);
+}
+
+/*
+ * "tabpagebuflist()" function
+ */
+ static void
+f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
+{
+ tabpage_T *tp;
+ win_T *wp = NULL;
+
+ if (argvars[0].v_type == VAR_UNKNOWN)
+ wp = firstwin;
+ else
+ {
+ tp = find_tabpage((int)tv_get_number(&argvars[0]));
+ if (tp != NULL)
+ wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
+ }
+ if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
+ {
+ for (; wp != NULL; wp = wp->w_next)
+ if (list_append_number(rettv->vval.v_list,
+ wp->w_buffer->b_fnum) == FAIL)
+ break;
+ }
+}
+
+/*
+ * "tabpagenr()" function
+ */
+ static void
+f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ int nr = 1;
+ char_u *arg;
+
+ if (argvars[0].v_type != VAR_UNKNOWN)
+ {
+ arg = tv_get_string_chk(&argvars[0]);
+ nr = 0;
+ if (arg != NULL)
+ {
+ if (STRCMP(arg, "$") == 0)
+ nr = tabpage_index(NULL) - 1;
+ else
+ semsg(_(e_invexpr2), arg);
+ }
+ }
+ else
+ nr = tabpage_index(curtab);
+ rettv->vval.v_number = nr;
+}
+
+
+/*
+ * Common code for tabpagewinnr() and winnr().
+ */
+ static int
+get_winnr(tabpage_T *tp, typval_T *argvar)
+{
+ win_T *twin;
+ int nr = 1;
+ win_T *wp;
+ char_u *arg;
+
+ twin = (tp == curtab) ? curwin : tp->tp_curwin;
+ if (argvar->v_type != VAR_UNKNOWN)
+ {
+ arg = tv_get_string_chk(argvar);
+ if (arg == NULL)
+ nr = 0; /* type error; errmsg already given */
+ else if (STRCMP(arg, "$") == 0)
+ twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
+ else if (STRCMP(arg, "#") == 0)
+ {
+ twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
+ if (twin == NULL)
+ nr = 0;
+ }
+ else
+ {
+ semsg(_(e_invexpr2), arg);
+ nr = 0;
+ }
+ }
+
+ if (nr > 0)
+ for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
+ wp != twin; wp = wp->w_next)
+ {
+ if (wp == NULL)
+ {
+ /* didn't find it in this tabpage */
+ nr = 0;
+ break;
+ }
+ ++nr;
+ }
+ return nr;
+}
+
+/*
+ * "tabpagewinnr()" function
+ */
+ static void
+f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ int nr = 1;
+ tabpage_T *tp;
+
+ tp = find_tabpage((int)tv_get_number(&argvars[0]));
+ if (tp == NULL)
+ nr = 0;
+ else
+ nr = get_winnr(tp, &argvars[1]);
+ rettv->vval.v_number = nr;
+}
+
+/*
+ * "tagfiles()" function
+ */
+ static void
+f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ char_u *fname;
+ tagname_T tn;
+ int first;
+
+ if (rettv_list_alloc(rettv) == FAIL)
+ return;
+ fname = alloc(MAXPATHL);
+ if (fname == NULL)
+ return;
+
+ for (first = TRUE; ; first = FALSE)
+ if (get_tagfname(&tn, first, fname) == FAIL
+ || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
+ break;
+ tagname_free(&tn);
+ vim_free(fname);
+}
+
+/*
+ * "taglist()" function
+ */
+ static void
+f_taglist(typval_T *argvars, typval_T *rettv)
+{
+ char_u *fname = NULL;
+ char_u *tag_pattern;
+
+ tag_pattern = tv_get_string(&argvars[0]);
+
+ rettv->vval.v_number = FALSE;
+ if (*tag_pattern == NUL)
+ return;
+
+ if (argvars[1].v_type != VAR_UNKNOWN)
+ fname = tv_get_string(&argvars[1]);
+ if (rettv_list_alloc(rettv) == OK)
+ (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
+}
+
+/*
+ * "tempname()" function
+ */
+ static void
+f_tempname(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ static int x = 'A';
+
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = vim_tempname(x, FALSE);
+
+ /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
+ * names. Skip 'I' and 'O', they are used for shell redirection. */
+ do
+ {
+ if (x == 'Z')
+ x = '0';
+ else if (x == '9')
+ x = 'A';
+ else
+ {
+#ifdef EBCDIC
+ if (x == 'I')
+ x = 'J';
+ else if (x == 'R')
+ x = 'S';
+ else
+#endif
+ ++x;
+ }
+ } while (x == 'I' || x == 'O');
+}
+
+#ifdef FEAT_FLOAT
+/*
+ * "tan()" function
+ */
+ static void
+f_tan(typval_T *argvars, typval_T *rettv)
+{
+ float_T f = 0.0;
+
+ rettv->v_type = VAR_FLOAT;
+ if (get_float_arg(argvars, &f) == OK)
+ rettv->vval.v_float = tan(f);
+ else
+ rettv->vval.v_float = 0.0;
+}
+
+/*
+ * "tanh()" function
+ */
+ static void
+f_tanh(typval_T *argvars, typval_T *rettv)
+{
+ float_T f = 0.0;
+
+ rettv->v_type = VAR_FLOAT;
+ if (get_float_arg(argvars, &f) == OK)
+ rettv->vval.v_float = tanh(f);
+ else
+ rettv->vval.v_float = 0.0;
+}
+#endif
+
+/*
+ * "test_alloc_fail(id, countdown, repeat)" function
+ */
+ static void
+f_test_alloc_fail(typval_T *argvars, typval_T *rettv UNUSED)
+{
+ if (argvars[0].v_type != VAR_NUMBER
+ || argvars[0].vval.v_number <= 0
+ || argvars[1].v_type != VAR_NUMBER
+ || argvars[1].vval.v_number < 0
+ || argvars[2].v_type != VAR_NUMBER)
+ emsg(_(e_invarg));
+ else
+ {
+ alloc_fail_id = argvars[0].vval.v_number;
+ if (alloc_fail_id >= aid_last)
+ emsg(_(e_invarg));
+ alloc_fail_countdown = argvars[1].vval.v_number;
+ alloc_fail_repeat = argvars[2].vval.v_number;
+ did_outofmem_msg = FALSE;
+ }
+}
+
+/*
+ * "test_autochdir()"
+ */
+ static void
+f_test_autochdir(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
+{
+#if defined(FEAT_AUTOCHDIR)
+ test_autochdir = TRUE;
+#endif
+}
+
+/*
+ * "test_feedinput()"
+ */
+ static void
+f_test_feedinput(typval_T *argvars, typval_T *rettv UNUSED)
+{
+#ifdef USE_INPUT_BUF
+ char_u *val = tv_get_string_chk(&argvars[0]);
+
+ if (val != NULL)
+ {
+ trash_input_buf();
+ add_to_input_buf_csi(val, (int)STRLEN(val));
+ }
+#endif
+}
+
+/*
+ * "test_option_not_set({name})" function
+ */
+ static void
+f_test_option_not_set(typval_T *argvars, typval_T *rettv UNUSED)
+{
+ char_u *name = (char_u *)"";
+
+ if (argvars[0].v_type != VAR_STRING)
+ emsg(_(e_invarg));
+ else
+ {
+ name = tv_get_string(&argvars[0]);
+ if (reset_option_was_set(name) == FAIL)
+ semsg(_(e_invarg2), name);
+ }
+}
+
+/*
+ * "test_override({name}, {val})" function
+ */
+ static void
+f_test_override(typval_T *argvars, typval_T *rettv UNUSED)
+{
+ char_u *name = (char_u *)"";
+ int val;
+ static int save_starting = -1;
+
+ if (argvars[0].v_type != VAR_STRING
+ || (argvars[1].v_type) != VAR_NUMBER)
+ emsg(_(e_invarg));
+ else
+ {
+ name = tv_get_string(&argvars[0]);
+ val = (int)tv_get_number(&argvars[1]);
+
+ if (STRCMP(name, (char_u *)"redraw") == 0)
+ disable_redraw_for_testing = val;
+ else if (STRCMP(name, (char_u *)"redraw_flag") == 0)
+ ignore_redraw_flag_for_testing = val;
+ else if (STRCMP(name, (char_u *)"char_avail") == 0)
+ disable_char_avail_for_testing = val;
+ else if (STRCMP(name, (char_u *)"starting") == 0)
+ {
+ if (val)
+ {
+ if (save_starting < 0)
+ save_starting = starting;
+ starting = 0;
+ }
+ else
+ {
+ starting = save_starting;
+ save_starting = -1;
+ }
+ }
+ else if (STRCMP(name, (char_u *)"nfa_fail") == 0)
+ nfa_fail_for_testing = val;
+ else if (STRCMP(name, (char_u *)"ALL") == 0)
+ {
+ disable_char_avail_for_testing = FALSE;
+ disable_redraw_for_testing = FALSE;
+ ignore_redraw_flag_for_testing = FALSE;
+ nfa_fail_for_testing = FALSE;
+ if (save_starting >= 0)
+ {
+ starting = save_starting;
+ save_starting = -1;
+ }
+ }
+ else
+ semsg(_(e_invarg2), name);
+ }
+}
+
+/*
+ * "test_garbagecollect_now()" function
+ */
+ static void
+f_test_garbagecollect_now(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
+{
+ /* This is dangerous, any Lists and Dicts used internally may be freed
+ * while still in use. */
+ garbage_collect(TRUE);
+}
+
+/*
+ * "test_ignore_error()" function
+ */
+ static void
+f_test_ignore_error(typval_T *argvars, typval_T *rettv UNUSED)
+{
+ ignore_error_for_testing(tv_get_string(&argvars[0]));
+}
+
+ static void
+f_test_null_blob(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ rettv->v_type = VAR_BLOB;
+ rettv->vval.v_blob = NULL;
+}
+
+#ifdef FEAT_JOB_CHANNEL
+ static void
+f_test_null_channel(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ rettv->v_type = VAR_CHANNEL;
+ rettv->vval.v_channel = NULL;
+}
+#endif
+
+ static void
+f_test_null_dict(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ rettv_dict_set(rettv, NULL);
+}
+
+#ifdef FEAT_JOB_CHANNEL
+ static void
+f_test_null_job(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ rettv->v_type = VAR_JOB;
+ rettv->vval.v_job = NULL;
+}
+#endif
+
+ static void
+f_test_null_list(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ rettv_list_set(rettv, NULL);
+}
+
+ static void
+f_test_null_partial(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ rettv->v_type = VAR_PARTIAL;
+ rettv->vval.v_partial = NULL;
+}
+
+ static void
+f_test_null_string(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+}
+
+#ifdef FEAT_GUI
+ static void
+f_test_scrollbar(typval_T *argvars, typval_T *rettv UNUSED)
+{
+ char_u *which;
+ long value;
+ int dragging;
+ scrollbar_T *sb = NULL;
+
+ if (argvars[0].v_type != VAR_STRING
+ || (argvars[1].v_type) != VAR_NUMBER
+ || (argvars[2].v_type) != VAR_NUMBER)
+ {
+ emsg(_(e_invarg));
+ return;
+ }
+ which = tv_get_string(&argvars[0]);
+ value = tv_get_number(&argvars[1]);
+ dragging = tv_get_number(&argvars[2]);
+
+ if (STRCMP(which, "left") == 0)
+ sb = &curwin->w_scrollbars[SBAR_LEFT];
+ else if (STRCMP(which, "right") == 0)
+ sb = &curwin->w_scrollbars[SBAR_RIGHT];
+ else if (STRCMP(which, "hor") == 0)
+ sb = &gui.bottom_sbar;
+ if (sb == NULL)
+ {
+ semsg(_(e_invarg2), which);
+ return;
+ }
+ gui_drag_scrollbar(sb, value, dragging);
+# ifndef USE_ON_FLY_SCROLL
+ // need to loop through normal_cmd() to handle the scroll events
+ exec_normal(FALSE, TRUE, FALSE);
+# endif
+}
+#endif
+
+ static void
+f_test_settime(typval_T *argvars, typval_T *rettv UNUSED)
+{
+ time_for_testing = (time_t)tv_get_number(&argvars[0]);
+}
+
+#if defined(FEAT_JOB_CHANNEL) || defined(FEAT_TIMERS) || defined(PROTO)
+/*
+ * Get a callback from "arg". It can be a Funcref or a function name.
+ * When "arg" is zero return an empty string.
+ * Return NULL for an invalid argument.
+ */
+ char_u *
+get_callback(typval_T *arg, partial_T **pp)
+{
+ if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
+ {
+ *pp = arg->vval.v_partial;
+ ++(*pp)->pt_refcount;
+ return partial_name(*pp);
+ }
+ *pp = NULL;
+ if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
+ {
+ func_ref(arg->vval.v_string);
+ return arg->vval.v_string;
+ }
+ if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
+ return (char_u *)"";
+ emsg(_("E921: Invalid callback argument"));
+ return NULL;
+}
+
+/*
+ * Unref/free "callback" and "partial" returned by get_callback().
+ */
+ void
+free_callback(char_u *callback, partial_T *partial)
+{
+ if (partial != NULL)
+ partial_unref(partial);
+ else if (callback != NULL)
+ {
+ func_unref(callback);
+ vim_free(callback);
+ }
+}
+#endif
+
+#ifdef FEAT_TIMERS
+/*
+ * "timer_info([timer])" function
+ */
+ static void
+f_timer_info(typval_T *argvars, typval_T *rettv)
+{
+ timer_T *timer = NULL;
+
+ if (rettv_list_alloc(rettv) != OK)
+ return;
+ if (argvars[0].v_type != VAR_UNKNOWN)
+ {
+ if (argvars[0].v_type != VAR_NUMBER)
+ emsg(_(e_number_exp));
+ else
+ {
+ timer = find_timer((int)tv_get_number(&argvars[0]));
+ if (timer != NULL)
+ add_timer_info(rettv, timer);
+ }
+ }
+ else
+ add_timer_info_all(rettv);
+}
+
+/*
+ * "timer_pause(timer, paused)" function
+ */
+ static void
+f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
+{
+ timer_T *timer = NULL;
+ int paused = (int)tv_get_number(&argvars[1]);
+
+ if (argvars[0].v_type != VAR_NUMBER)
+ emsg(_(e_number_exp));
+ else
+ {
+ timer = find_timer((int)tv_get_number(&argvars[0]));
+ if (timer != NULL)
+ timer->tr_paused = paused;
+ }
+}
+
+/*
+ * "timer_start(time, callback [, options])" function
+ */
+ static void
+f_timer_start(typval_T *argvars, typval_T *rettv)
+{
+ long msec = (long)tv_get_number(&argvars[0]);
+ timer_T *timer;
+ int repeat = 0;
+ char_u *callback;
+ dict_T *dict;
+ partial_T *partial;
+
+ rettv->vval.v_number = -1;
+ if (check_secure())
+ return;
+ if (argvars[2].v_type != VAR_UNKNOWN)
+ {
+ if (argvars[2].v_type != VAR_DICT
+ || (dict = argvars[2].vval.v_dict) == NULL)
+ {
+ semsg(_(e_invarg2), tv_get_string(&argvars[2]));
+ return;
+ }
+ if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
+ repeat = dict_get_number(dict, (char_u *)"repeat");
+ }
+
+ callback = get_callback(&argvars[1], &partial);
+ if (callback == NULL)
+ return;
+
+ timer = create_timer(msec, repeat);
+ if (timer == NULL)
+ free_callback(callback, partial);
+ else
+ {
+ if (partial == NULL)
+ timer->tr_callback = vim_strsave(callback);
+ else
+ /* pointer into the partial */
+ timer->tr_callback = callback;
+ timer->tr_partial = partial;
+ rettv->vval.v_number = (varnumber_T)timer->tr_id;
+ }
+}
+
+/*
+ * "timer_stop(timer)" function
+ */
+ static void
+f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
+{
+ timer_T *timer;
+
+ if (argvars[0].v_type != VAR_NUMBER)
+ {
+ emsg(_(e_number_exp));
+ return;
+ }
+ timer = find_timer((int)tv_get_number(&argvars[0]));
+ if (timer != NULL)
+ stop_timer(timer);
+}
+
+/*
+ * "timer_stopall()" function
+ */
+ static void
+f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
+{
+ stop_all_timers();
+}
+#endif
+
+/*
+ * "tolower(string)" function
+ */
+ static void
+f_tolower(typval_T *argvars, typval_T *rettv)
+{
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
+}
+
+/*
+ * "toupper(string)" function
+ */
+ static void
+f_toupper(typval_T *argvars, typval_T *rettv)
+{
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
+}
+
+/*
+ * "tr(string, fromstr, tostr)" function
+ */
+ static void
+f_tr(typval_T *argvars, typval_T *rettv)
+{
+ char_u *in_str;
+ char_u *fromstr;
+ char_u *tostr;
+ char_u *p;
+ int inlen;
+ int fromlen;
+ int tolen;
+ int idx;
+ char_u *cpstr;
+ int cplen;
+ int first = TRUE;
+ char_u buf[NUMBUFLEN];
+ char_u buf2[NUMBUFLEN];
+ garray_T ga;
+
+ in_str = tv_get_string(&argvars[0]);
+ fromstr = tv_get_string_buf_chk(&argvars[1], buf);
+ tostr = tv_get_string_buf_chk(&argvars[2], buf2);
+
+ /* Default return value: empty string. */
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+ if (fromstr == NULL || tostr == NULL)
+ return; /* type error; errmsg already given */
+ ga_init2(&ga, (int)sizeof(char), 80);
+
+ if (!has_mbyte)
+ /* not multi-byte: fromstr and tostr must be the same length */
+ if (STRLEN(fromstr) != STRLEN(tostr))
+ {
+error:
+ semsg(_(e_invarg2), fromstr);
+ ga_clear(&ga);
+ return;
+ }
+
+ /* fromstr and tostr have to contain the same number of chars */
+ while (*in_str != NUL)
+ {
+ if (has_mbyte)
+ {
+ inlen = (*mb_ptr2len)(in_str);
+ cpstr = in_str;
+ cplen = inlen;
+ idx = 0;
+ for (p = fromstr; *p != NUL; p += fromlen)
+ {
+ fromlen = (*mb_ptr2len)(p);
+ if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
+ {
+ for (p = tostr; *p != NUL; p += tolen)
+ {
+ tolen = (*mb_ptr2len)(p);
+ if (idx-- == 0)
+ {
+ cplen = tolen;
+ cpstr = p;
+ break;
+ }
+ }
+ if (*p == NUL) /* tostr is shorter than fromstr */
+ goto error;
+ break;
+ }
+ ++idx;
+ }
+
+ if (first && cpstr == in_str)
+ {
+ /* Check that fromstr and tostr have the same number of
+ * (multi-byte) characters. Done only once when a character
+ * of in_str doesn't appear in fromstr. */
+ first = FALSE;
+ for (p = tostr; *p != NUL; p += tolen)
+ {
+ tolen = (*mb_ptr2len)(p);
+ --idx;
+ }
+ if (idx != 0)
+ goto error;
+ }
+
+ (void)ga_grow(&ga, cplen);
+ mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
+ ga.ga_len += cplen;
+
+ in_str += inlen;
+ }
+ else
+ {
+ /* When not using multi-byte chars we can do it faster. */
+ p = vim_strchr(fromstr, *in_str);
+ if (p != NULL)
+ ga_append(&ga, tostr[p - fromstr]);
+ else
+ ga_append(&ga, *in_str);
+ ++in_str;
+ }
+ }
+
+ /* add a terminating NUL */
+ (void)ga_grow(&ga, 1);
+ ga_append(&ga, NUL);
+
+ rettv->vval.v_string = ga.ga_data;
+}
+
+/*
+ * "trim({expr})" function
+ */
+ static void
+f_trim(typval_T *argvars, typval_T *rettv)
+{
+ char_u buf1[NUMBUFLEN];
+ char_u buf2[NUMBUFLEN];
+ char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
+ char_u *mask = NULL;
+ char_u *tail;
+ char_u *prev;
+ char_u *p;
+ int c1;
+
+ rettv->v_type = VAR_STRING;
+ if (head == NULL)
+ {
+ rettv->vval.v_string = NULL;
+ return;
+ }
+
+ if (argvars[1].v_type == VAR_STRING)
+ mask = tv_get_string_buf_chk(&argvars[1], buf2);
+
+ while (*head != NUL)
+ {
+ c1 = PTR2CHAR(head);
+ if (mask == NULL)
+ {
+ if (c1 > ' ' && c1 != 0xa0)
+ break;
+ }
+ else
+ {
+ for (p = mask; *p != NUL; MB_PTR_ADV(p))
+ if (c1 == PTR2CHAR(p))
+ break;
+ if (*p == NUL)
+ break;
+ }
+ MB_PTR_ADV(head);
+ }
+
+ for (tail = head + STRLEN(head); tail > head; tail = prev)
+ {
+ prev = tail;
+ MB_PTR_BACK(head, prev);
+ c1 = PTR2CHAR(prev);
+ if (mask == NULL)
+ {
+ if (c1 > ' ' && c1 != 0xa0)
+ break;
+ }
+ else
+ {
+ for (p = mask; *p != NUL; MB_PTR_ADV(p))
+ if (c1 == PTR2CHAR(p))
+ break;
+ if (*p == NUL)
+ break;
+ }
+ }
+ rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
+}
+
+#ifdef FEAT_FLOAT
+/*
+ * "trunc({float})" function
+ */
+ static void
+f_trunc(typval_T *argvars, typval_T *rettv)
+{
+ float_T f = 0.0;
+
+ rettv->v_type = VAR_FLOAT;
+ if (get_float_arg(argvars, &f) == OK)
+ /* trunc() is not in C90, use floor() or ceil() instead. */
+ rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
+ else
+ rettv->vval.v_float = 0.0;
+}
+#endif
+
+/*
+ * "type(expr)" function
+ */
+ static void
+f_type(typval_T *argvars, typval_T *rettv)
+{
+ int n = -1;
+
+ switch (argvars[0].v_type)
+ {
+ case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
+ case VAR_STRING: n = VAR_TYPE_STRING; break;
+ case VAR_PARTIAL:
+ case VAR_FUNC: n = VAR_TYPE_FUNC; break;
+ case VAR_LIST: n = VAR_TYPE_LIST; break;
+ case VAR_DICT: n = VAR_TYPE_DICT; break;
+ case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
+ case VAR_SPECIAL:
+ if (argvars[0].vval.v_number == VVAL_FALSE
+ || argvars[0].vval.v_number == VVAL_TRUE)
+ n = VAR_TYPE_BOOL;
+ else
+ n = VAR_TYPE_NONE;
+ break;
+ case VAR_JOB: n = VAR_TYPE_JOB; break;
+ case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
+ case VAR_BLOB: n = VAR_TYPE_BLOB; break;
+ case VAR_UNKNOWN:
+ internal_error("f_type(UNKNOWN)");
+ n = -1;
+ break;
+ }
+ rettv->vval.v_number = n;
+}
+
+/*
+ * "undofile(name)" function
+ */
+ static void
+f_undofile(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ rettv->v_type = VAR_STRING;
+#ifdef FEAT_PERSISTENT_UNDO
+ {
+ char_u *fname = tv_get_string(&argvars[0]);
+
+ if (*fname == NUL)
+ {
+ /* If there is no file name there will be no undo file. */
+ rettv->vval.v_string = NULL;
+ }
+ else
+ {
+ char_u *ffname = FullName_save(fname, FALSE);
+
+ if (ffname != NULL)
+ rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE);
+ vim_free(ffname);
+ }
+ }
+#else
+ rettv->vval.v_string = NULL;
+#endif
+}
+
+/*
+ * "undotree()" function
+ */
+ static void
+f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ if (rettv_dict_alloc(rettv) == OK)
+ {
+ dict_T *dict = rettv->vval.v_dict;
+ list_T *list;
+
+ dict_add_number(dict, "synced", (long)curbuf->b_u_synced);
+ dict_add_number(dict, "seq_last", curbuf->b_u_seq_last);
+ dict_add_number(dict, "save_last", (long)curbuf->b_u_save_nr_last);
+ dict_add_number(dict, "seq_cur", curbuf->b_u_seq_cur);
+ dict_add_number(dict, "time_cur", (long)curbuf->b_u_time_cur);
+ dict_add_number(dict, "save_cur", (long)curbuf->b_u_save_nr_cur);
+
+ list = list_alloc();
+ if (list != NULL)
+ {
+ u_eval_tree(curbuf->b_u_oldhead, list);
+ dict_add_list(dict, "entries", list);
+ }
+ }
+}
+
+/*
+ * "values(dict)" function
+ */
+ static void
+f_values(typval_T *argvars, typval_T *rettv)
+{
+ dict_list(argvars, rettv, 1);
+}
+
+/*
+ * "virtcol(string)" function
+ */
+ static void
+f_virtcol(typval_T *argvars, typval_T *rettv)
+{
+ colnr_T vcol = 0;
+ pos_T *fp;
+ int fnum = curbuf->b_fnum;
+
+ fp = var2fpos(&argvars[0], FALSE, &fnum);
+ if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
+ && fnum == curbuf->b_fnum)
+ {
+ getvvcol(curwin, fp, NULL, NULL, &vcol);
+ ++vcol;
+ }
+
+ rettv->vval.v_number = vcol;
+}
+
+/*
+ * "visualmode()" function
+ */
+ static void
+f_visualmode(typval_T *argvars, typval_T *rettv)
+{
+ char_u str[2];
+
+ rettv->v_type = VAR_STRING;
+ str[0] = curbuf->b_visual_mode_eval;
+ str[1] = NUL;
+ rettv->vval.v_string = vim_strsave(str);
+
+ /* A non-zero number or non-empty string argument: reset mode. */
+ if (non_zero_arg(&argvars[0]))
+ curbuf->b_visual_mode_eval = NUL;
+}
+
+/*
+ * "wildmenumode()" function
+ */
+ static void
+f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
+{
+#ifdef FEAT_WILDMENU
+ if (wild_menu_showing)
+ rettv->vval.v_number = 1;
+#endif
+}
+
+/*
+ * "winbufnr(nr)" function
+ */
+ static void
+f_winbufnr(typval_T *argvars, typval_T *rettv)
+{
+ win_T *wp;
+
+ wp = find_win_by_nr_or_id(&argvars[0]);
+ if (wp == NULL)
+ rettv->vval.v_number = -1;
+ else
+ rettv->vval.v_number = wp->w_buffer->b_fnum;
+}
+
+/*
+ * "wincol()" function
+ */
+ static void
+f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ validate_cursor();
+ rettv->vval.v_number = curwin->w_wcol + 1;
+}
+
+/*
+ * "winheight(nr)" function
+ */
+ static void
+f_winheight(typval_T *argvars, typval_T *rettv)
+{
+ win_T *wp;
+
+ wp = find_win_by_nr_or_id(&argvars[0]);
+ if (wp == NULL)
+ rettv->vval.v_number = -1;
+ else
+ rettv->vval.v_number = wp->w_height;
+}
+
+/*
+ * "winlayout()" function
+ */
+ static void
+f_winlayout(typval_T *argvars, typval_T *rettv)
+{
+ tabpage_T *tp;
+
+ if (rettv_list_alloc(rettv) != OK)
+ return;
+
+ if (argvars[0].v_type == VAR_UNKNOWN)
+ tp = curtab;
+ else
+ {
+ tp = find_tabpage((int)tv_get_number(&argvars[0]));
+ if (tp == NULL)
+ return;
+ }
+
+ get_framelayout(tp->tp_topframe, rettv->vval.v_list, TRUE);
+}
+
+/*
+ * "winline()" function
+ */
+ static void
+f_winline(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ validate_cursor();
+ rettv->vval.v_number = curwin->w_wrow + 1;
+}
+
+/*
+ * "winnr()" function
+ */
+ static void
+f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ int nr = 1;
+
+ nr = get_winnr(curtab, &argvars[0]);
+ rettv->vval.v_number = nr;
+}
+
+/*
+ * "winrestcmd()" function
+ */
+ static void
+f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ win_T *wp;
+ int winnr = 1;
+ garray_T ga;
+ char_u buf[50];
+
+ ga_init2(&ga, (int)sizeof(char), 70);
+ FOR_ALL_WINDOWS(wp)
+ {
+ sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
+ ga_concat(&ga, buf);
+ sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
+ ga_concat(&ga, buf);
+ ++winnr;
+ }
+ ga_append(&ga, NUL);
+
+ rettv->vval.v_string = ga.ga_data;
+ rettv->v_type = VAR_STRING;
+}
+
+/*
+ * "winrestview()" function
+ */
+ static void
+f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
+{
+ dict_T *dict;
+
+ if (argvars[0].v_type != VAR_DICT
+ || (dict = argvars[0].vval.v_dict) == NULL)
+ emsg(_(e_invarg));
+ else
+ {
+ if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
+ curwin->w_cursor.lnum = (linenr_T)dict_get_number(dict, (char_u *)"lnum");
+ if (dict_find(dict, (char_u *)"col", -1) != NULL)
+ curwin->w_cursor.col = (colnr_T)dict_get_number(dict, (char_u *)"col");
+ if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
+ curwin->w_cursor.coladd = (colnr_T)dict_get_number(dict, (char_u *)"coladd");
+ if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
+ {
+ curwin->w_curswant = (colnr_T)dict_get_number(dict, (char_u *)"curswant");
+ curwin->w_set_curswant = FALSE;
+ }
+
+ if (dict_find(dict, (char_u *)"topline", -1) != NULL)
+ set_topline(curwin, (linenr_T)dict_get_number(dict, (char_u *)"topline"));
+#ifdef FEAT_DIFF
+ if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
+ curwin->w_topfill = (int)dict_get_number(dict, (char_u *)"topfill");
+#endif
+ if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
+ curwin->w_leftcol = (colnr_T)dict_get_number(dict, (char_u *)"leftcol");
+ if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
+ curwin->w_skipcol = (colnr_T)dict_get_number(dict, (char_u *)"skipcol");
+
+ check_cursor();
+ win_new_height(curwin, curwin->w_height);
+ win_new_width(curwin, curwin->w_width);
+ changed_window_setting();
+
+ if (curwin->w_topline <= 0)
+ curwin->w_topline = 1;
+ if (curwin->w_topline > curbuf->b_ml.ml_line_count)
+ curwin->w_topline = curbuf->b_ml.ml_line_count;
+#ifdef FEAT_DIFF
+ check_topfill(curwin, TRUE);
+#endif
+ }
+}
+
+/*
+ * "winsaveview()" function
+ */
+ static void
+f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ dict_T *dict;
+
+ if (rettv_dict_alloc(rettv) == FAIL)
+ return;
+ dict = rettv->vval.v_dict;
+
+ dict_add_number(dict, "lnum", (long)curwin->w_cursor.lnum);
+ dict_add_number(dict, "col", (long)curwin->w_cursor.col);
+ dict_add_number(dict, "coladd", (long)curwin->w_cursor.coladd);
+ update_curswant();
+ dict_add_number(dict, "curswant", (long)curwin->w_curswant);
+
+ dict_add_number(dict, "topline", (long)curwin->w_topline);
+#ifdef FEAT_DIFF
+ dict_add_number(dict, "topfill", (long)curwin->w_topfill);
+#endif
+ dict_add_number(dict, "leftcol", (long)curwin->w_leftcol);
+ dict_add_number(dict, "skipcol", (long)curwin->w_skipcol);
+}
+
+/*
+ * "winwidth(nr)" function
+ */
+ static void
+f_winwidth(typval_T *argvars, typval_T *rettv)
+{
+ win_T *wp;
+
+ wp = find_win_by_nr_or_id(&argvars[0]);
+ if (wp == NULL)
+ rettv->vval.v_number = -1;
+ else
+ rettv->vval.v_number = wp->w_width;
+}
+
+/*
+ * "wordcount()" function
+ */
+ static void
+f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ if (rettv_dict_alloc(rettv) == FAIL)
+ return;
+ cursor_pos_info(rettv->vval.v_dict);
+}
+
+/*
+ * "writefile()" function
+ */
+ static void
+f_writefile(typval_T *argvars, typval_T *rettv)
+{
+ int binary = FALSE;
+ int append = FALSE;
+#ifdef HAVE_FSYNC
+ int do_fsync = p_fs;
+#endif
+ char_u *fname;
+ FILE *fd;
+ int ret = 0;
+ listitem_T *li;
+ list_T *list = NULL;
+ blob_T *blob = NULL;
+
+ rettv->vval.v_number = -1;
+ if (check_restricted() || check_secure())
+ return;
+
+ if (argvars[0].v_type == VAR_LIST)
+ {
+ list = argvars[0].vval.v_list;
+ if (list == NULL)
+ return;
+ for (li = list->lv_first; li != NULL; li = li->li_next)
+ if (tv_get_string_chk(&li->li_tv) == NULL)
+ return;
+ }
+ else if (argvars[0].v_type == VAR_BLOB)
+ {
+ blob = argvars[0].vval.v_blob;
+ if (blob == NULL)
+ return;
+ }
+ else
+ {
+ semsg(_(e_invarg2), "writefile()");
+ return;
+ }
+
+ if (argvars[2].v_type != VAR_UNKNOWN)
+ {
+ char_u *arg2 = tv_get_string_chk(&argvars[2]);
+
+ if (arg2 == NULL)
+ return;
+ if (vim_strchr(arg2, 'b') != NULL)
+ binary = TRUE;
+ if (vim_strchr(arg2, 'a') != NULL)
+ append = TRUE;
+#ifdef HAVE_FSYNC
+ if (vim_strchr(arg2, 's') != NULL)
+ do_fsync = TRUE;
+ else if (vim_strchr(arg2, 'S') != NULL)
+ do_fsync = FALSE;
+#endif
+ }
+
+ fname = tv_get_string_chk(&argvars[1]);
+ if (fname == NULL)
+ return;
+
+ /* Always open the file in binary mode, library functions have a mind of
+ * their own about CR-LF conversion. */
+ if (*fname == NUL || (fd = mch_fopen((char *)fname,
+ append ? APPENDBIN : WRITEBIN)) == NULL)
+ {
+ semsg(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
+ ret = -1;
+ }
+ else if (blob)
+ {
+ if (write_blob(fd, blob) == FAIL)
+ ret = -1;
+#ifdef HAVE_FSYNC
+ else if (do_fsync)
+ // Ignore the error, the user wouldn't know what to do about it.
+ // May happen for a device.
+ vim_ignored = fsync(fileno(fd));
+#endif
+ fclose(fd);
+ }
+ else
+ {
+ if (write_list(fd, list, binary) == FAIL)
+ ret = -1;
+#ifdef HAVE_FSYNC
+ else if (do_fsync)
+ /* Ignore the error, the user wouldn't know what to do about it.
+ * May happen for a device. */
+ vim_ignored = fsync(fileno(fd));
+#endif
+ fclose(fd);
+ }
+
+ rettv->vval.v_number = ret;
+}
+
+/*
+ * "xor(expr, expr)" function
+ */
+ static void
+f_xor(typval_T *argvars, typval_T *rettv)
+{
+ rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
+ ^ tv_get_number_chk(&argvars[1], NULL);
+}
+
+#endif /* FEAT_EVAL */
diff --git a/src/ex_cmdidxs.h b/src/ex_cmdidxs.h
new file mode 100644
index 0000000..867047f
--- /dev/null
+++ b/src/ex_cmdidxs.h
@@ -0,0 +1,72 @@
+/* Automatically generated code by create_cmdidxs.vim
+ *
+ * Table giving the index of the first command in cmdnames[] to lookup
+ * based on the first letter of a command.
+ */
+static const unsigned short cmdidxs1[26] =
+{
+ /* a */ 0,
+ /* b */ 19,
+ /* c */ 42,
+ /* d */ 103,
+ /* e */ 125,
+ /* f */ 145,
+ /* g */ 161,
+ /* h */ 167,
+ /* i */ 176,
+ /* j */ 194,
+ /* k */ 196,
+ /* l */ 201,
+ /* m */ 259,
+ /* n */ 277,
+ /* o */ 297,
+ /* p */ 309,
+ /* q */ 348,
+ /* r */ 351,
+ /* s */ 371,
+ /* t */ 438,
+ /* u */ 481,
+ /* v */ 492,
+ /* w */ 510,
+ /* x */ 524,
+ /* y */ 533,
+ /* z */ 534
+};
+
+/*
+ * Table giving the index of the first command in cmdnames[] to lookup
+ * based on the first 2 letters of a command.
+ * Values in cmdidxs2[c1][c2] are relative to cmdidxs1[c1] so that they
+ * fit in a byte.
+ */
+static const unsigned char cmdidxs2[26][26] =
+{ /* a b c d e f g h i j k l m n o p q r s t u v w x y z */
+ /* a */ { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, 6, 0, 0, 0, 7, 15, 0, 16, 0, 0, 0, 0, 0 },
+ /* b */ { 2, 0, 0, 4, 5, 7, 0, 0, 0, 0, 0, 8, 9, 10, 11, 12, 0, 13, 0, 0, 0, 0, 22, 0, 0, 0 },
+ /* c */ { 3, 10, 12, 14, 16, 18, 21, 0, 0, 0, 0, 29, 33, 36, 42, 51, 53, 54, 55, 0, 57, 0, 60, 0, 0, 0 },
+ /* d */ { 0, 0, 0, 0, 0, 0, 0, 0, 6, 15, 0, 16, 0, 0, 17, 0, 0, 19, 20, 0, 0, 0, 0, 0, 0, 0 },
+ /* e */ { 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 7, 9, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0 },
+ /* f */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0 },
+ /* g */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 4, 5, 0, 0, 0, 0 },
+ /* h */ { 5, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* i */ { 1, 0, 0, 0, 0, 3, 0, 0, 0, 4, 0, 5, 6, 0, 0, 0, 0, 0, 13, 0, 15, 0, 0, 0, 0, 0 },
+ /* j */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 },
+ /* k */ { 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* l */ { 3, 9, 11, 15, 16, 20, 23, 28, 0, 0, 0, 30, 33, 36, 40, 46, 0, 48, 57, 49, 50, 54, 56, 0, 0, 0 },
+ /* m */ { 1, 0, 0, 0, 7, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16 },
+ /* n */ { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 8, 10, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0 },
+ /* o */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 5, 0, 0, 0, 0, 0, 0, 9, 0, 11, 0, 0, 0 },
+ /* p */ { 1, 0, 3, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 9, 0, 0, 16, 17, 26, 0, 27, 0, 28, 0 },
+ /* q */ { 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* r */ { 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 19, 0, 0, 0, 0 },
+ /* s */ { 2, 6, 15, 0, 18, 22, 0, 24, 25, 0, 0, 28, 30, 34, 38, 40, 0, 48, 0, 49, 0, 61, 62, 0, 63, 0 },
+ /* t */ { 2, 0, 19, 0, 22, 24, 0, 25, 0, 26, 0, 27, 31, 34, 36, 37, 0, 38, 40, 0, 41, 0, 0, 0, 0, 0 },
+ /* u */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* v */ { 0, 0, 0, 0, 1, 0, 0, 0, 4, 0, 0, 0, 9, 12, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 0, 0 },
+ /* w */ { 2, 0, 0, 0, 0, 0, 0, 3, 4, 0, 0, 0, 0, 8, 0, 9, 10, 0, 0, 0, 12, 13, 0, 0, 0, 0 },
+ /* x */ { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 5, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0 },
+ /* y */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* z */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+};
+
+static const int command_count = 547;
diff --git a/src/ex_cmds.c b/src/ex_cmds.c
new file mode 100644
index 0000000..a3974c1
--- /dev/null
+++ b/src/ex_cmds.c
@@ -0,0 +1,7754 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * ex_cmds.c: some functions for command line commands
+ */
+
+#include "vim.h"
+#include "version.h"
+
+#ifdef FEAT_FLOAT
+# include <float.h>
+#endif
+
+static int linelen(int *has_tab);
+static void do_filter(linenr_T line1, linenr_T line2, exarg_T *eap, char_u *cmd, int do_in, int do_out);
+#ifdef FEAT_VIMINFO
+static char_u *viminfo_filename(char_u *);
+static void do_viminfo(FILE *fp_in, FILE *fp_out, int flags);
+static int viminfo_encoding(vir_T *virp);
+static int read_viminfo_up_to_marks(vir_T *virp, int forceit, int writing);
+#endif
+
+static int check_readonly(int *forceit, buf_T *buf);
+static void delbuf_msg(char_u *name);
+static int
+#ifdef __BORLANDC__
+ _RTLENTRYF
+#endif
+ help_compare(const void *s1, const void *s2);
+static void prepare_help_buffer(void);
+
+/*
+ * ":ascii" and "ga".
+ */
+ void
+do_ascii(exarg_T *eap UNUSED)
+{
+ int c;
+ int cval;
+ char buf1[20];
+ char buf2[20];
+ char_u buf3[7];
+#ifdef FEAT_DIGRAPHS
+ char_u *dig;
+#endif
+ int cc[MAX_MCO];
+ int ci = 0;
+ int len;
+
+ if (enc_utf8)
+ c = utfc_ptr2char(ml_get_cursor(), cc);
+ else
+ c = gchar_cursor();
+ if (c == NUL)
+ {
+ msg("NUL");
+ return;
+ }
+
+ IObuff[0] = NUL;
+ if (!has_mbyte || (enc_dbcs != 0 && c < 0x100) || c < 0x80)
+ {
+ if (c == NL) /* NUL is stored as NL */
+ c = NUL;
+ if (c == CAR && get_fileformat(curbuf) == EOL_MAC)
+ cval = NL; /* NL is stored as CR */
+ else
+ cval = c;
+ if (vim_isprintc_strict(c) && (c < ' '
+#ifndef EBCDIC
+ || c > '~'
+#endif
+ ))
+ {
+ transchar_nonprint(buf3, c);
+ vim_snprintf(buf1, sizeof(buf1), " <%s>", (char *)buf3);
+ }
+ else
+ buf1[0] = NUL;
+#ifndef EBCDIC
+ if (c >= 0x80)
+ vim_snprintf(buf2, sizeof(buf2), " <M-%s>",
+ (char *)transchar(c & 0x7f));
+ else
+#endif
+ buf2[0] = NUL;
+#ifdef FEAT_DIGRAPHS
+ dig = get_digraph_for_char(cval);
+ if (dig != NULL)
+ vim_snprintf((char *)IObuff, IOSIZE,
+ _("<%s>%s%s %d, Hex %02x, Oct %03o, Digr %s"),
+ transchar(c), buf1, buf2, cval, cval, cval, dig);
+ else
+#endif
+ vim_snprintf((char *)IObuff, IOSIZE,
+ _("<%s>%s%s %d, Hex %02x, Octal %03o"),
+ transchar(c), buf1, buf2, cval, cval, cval);
+ if (enc_utf8)
+ c = cc[ci++];
+ else
+ c = 0;
+ }
+
+ /* Repeat for combining characters. */
+ while (has_mbyte && (c >= 0x100 || (enc_utf8 && c >= 0x80)))
+ {
+ len = (int)STRLEN(IObuff);
+ /* This assumes every multi-byte char is printable... */
+ if (len > 0)
+ IObuff[len++] = ' ';
+ IObuff[len++] = '<';
+ if (enc_utf8 && utf_iscomposing(c)
+# ifdef USE_GUI
+ && !gui.in_use
+# endif
+ )
+ IObuff[len++] = ' '; /* draw composing char on top of a space */
+ len += (*mb_char2bytes)(c, IObuff + len);
+#ifdef FEAT_DIGRAPHS
+ dig = get_digraph_for_char(c);
+ if (dig != NULL)
+ vim_snprintf((char *)IObuff + len, IOSIZE - len,
+ c < 0x10000 ? _("> %d, Hex %04x, Oct %o, Digr %s")
+ : _("> %d, Hex %08x, Oct %o, Digr %s"),
+ c, c, c, dig);
+ else
+#endif
+ vim_snprintf((char *)IObuff + len, IOSIZE - len,
+ c < 0x10000 ? _("> %d, Hex %04x, Octal %o")
+ : _("> %d, Hex %08x, Octal %o"),
+ c, c, c);
+ if (ci == MAX_MCO)
+ break;
+ if (enc_utf8)
+ c = cc[ci++];
+ else
+ c = 0;
+ }
+
+ msg((char *)IObuff);
+}
+
+/*
+ * ":left", ":center" and ":right": align text.
+ */
+ void
+ex_align(exarg_T *eap)
+{
+ pos_T save_curpos;
+ int len;
+ int indent = 0;
+ int new_indent;
+ int has_tab;
+ int width;
+
+#ifdef FEAT_RIGHTLEFT
+ if (curwin->w_p_rl)
+ {
+ /* switch left and right aligning */
+ if (eap->cmdidx == CMD_right)
+ eap->cmdidx = CMD_left;
+ else if (eap->cmdidx == CMD_left)
+ eap->cmdidx = CMD_right;
+ }
+#endif
+
+ width = atoi((char *)eap->arg);
+ save_curpos = curwin->w_cursor;
+ if (eap->cmdidx == CMD_left) /* width is used for new indent */
+ {
+ if (width >= 0)
+ indent = width;
+ }
+ else
+ {
+ /*
+ * if 'textwidth' set, use it
+ * else if 'wrapmargin' set, use it
+ * if invalid value, use 80
+ */
+ if (width <= 0)
+ width = curbuf->b_p_tw;
+ if (width == 0 && curbuf->b_p_wm > 0)
+ width = curwin->w_width - curbuf->b_p_wm;
+ if (width <= 0)
+ width = 80;
+ }
+
+ if (u_save((linenr_T)(eap->line1 - 1), (linenr_T)(eap->line2 + 1)) == FAIL)
+ return;
+
+ for (curwin->w_cursor.lnum = eap->line1;
+ curwin->w_cursor.lnum <= eap->line2; ++curwin->w_cursor.lnum)
+ {
+ if (eap->cmdidx == CMD_left) /* left align */
+ new_indent = indent;
+ else
+ {
+ has_tab = FALSE; /* avoid uninit warnings */
+ len = linelen(eap->cmdidx == CMD_right ? &has_tab
+ : NULL) - get_indent();
+
+ if (len <= 0) /* skip blank lines */
+ continue;
+
+ if (eap->cmdidx == CMD_center)
+ new_indent = (width - len) / 2;
+ else
+ {
+ new_indent = width - len; /* right align */
+
+ /*
+ * Make sure that embedded TABs don't make the text go too far
+ * to the right.
+ */
+ if (has_tab)
+ while (new_indent > 0)
+ {
+ (void)set_indent(new_indent, 0);
+ if (linelen(NULL) <= width)
+ {
+ /*
+ * Now try to move the line as much as possible to
+ * the right. Stop when it moves too far.
+ */
+ do
+ (void)set_indent(++new_indent, 0);
+ while (linelen(NULL) <= width);
+ --new_indent;
+ break;
+ }
+ --new_indent;
+ }
+ }
+ }
+ if (new_indent < 0)
+ new_indent = 0;
+ (void)set_indent(new_indent, 0); /* set indent */
+ }
+ changed_lines(eap->line1, 0, eap->line2 + 1, 0L);
+ curwin->w_cursor = save_curpos;
+ beginline(BL_WHITE | BL_FIX);
+}
+
+/*
+ * Get the length of the current line, excluding trailing white space.
+ */
+ static int
+linelen(int *has_tab)
+{
+ char_u *line;
+ char_u *first;
+ char_u *last;
+ int save;
+ int len;
+
+ /* find the first non-blank character */
+ line = ml_get_curline();
+ first = skipwhite(line);
+
+ /* find the character after the last non-blank character */
+ for (last = first + STRLEN(first);
+ last > first && VIM_ISWHITE(last[-1]); --last)
+ ;
+ save = *last;
+ *last = NUL;
+ len = linetabsize(line); /* get line length */
+ if (has_tab != NULL) /* check for embedded TAB */
+ *has_tab = (vim_strchr(first, TAB) != NULL);
+ *last = save;
+
+ return len;
+}
+
+/* Buffer for two lines used during sorting. They are allocated to
+ * contain the longest line being sorted. */
+static char_u *sortbuf1;
+static char_u *sortbuf2;
+
+static int sort_ic; /* ignore case */
+static int sort_nr; /* sort on number */
+static int sort_rx; /* sort on regex instead of skipping it */
+#ifdef FEAT_FLOAT
+static int sort_flt; /* sort on floating number */
+#endif
+
+static int sort_abort; /* flag to indicate if sorting has been interrupted */
+
+/* Struct to store info to be sorted. */
+typedef struct
+{
+ linenr_T lnum; /* line number */
+ union {
+ struct
+ {
+ varnumber_T start_col_nr; /* starting column number */
+ varnumber_T end_col_nr; /* ending column number */
+ } line;
+ varnumber_T value; /* value if sorting by integer */
+#ifdef FEAT_FLOAT
+ float_T value_flt; /* value if sorting by float */
+#endif
+ } st_u;
+} sorti_T;
+
+static int
+#ifdef __BORLANDC__
+_RTLENTRYF
+#endif
+sort_compare(const void *s1, const void *s2);
+
+ static int
+#ifdef __BORLANDC__
+_RTLENTRYF
+#endif
+sort_compare(const void *s1, const void *s2)
+{
+ sorti_T l1 = *(sorti_T *)s1;
+ sorti_T l2 = *(sorti_T *)s2;
+ int result = 0;
+
+ /* If the user interrupts, there's no way to stop qsort() immediately, but
+ * if we return 0 every time, qsort will assume it's done sorting and
+ * exit. */
+ if (sort_abort)
+ return 0;
+ fast_breakcheck();
+ if (got_int)
+ sort_abort = TRUE;
+
+ /* When sorting numbers "start_col_nr" is the number, not the column
+ * number. */
+ if (sort_nr)
+ result = l1.st_u.value == l2.st_u.value ? 0
+ : l1.st_u.value > l2.st_u.value ? 1 : -1;
+#ifdef FEAT_FLOAT
+ else if (sort_flt)
+ result = l1.st_u.value_flt == l2.st_u.value_flt ? 0
+ : l1.st_u.value_flt > l2.st_u.value_flt ? 1 : -1;
+#endif
+ else
+ {
+ /* We need to copy one line into "sortbuf1", because there is no
+ * guarantee that the first pointer becomes invalid when obtaining the
+ * second one. */
+ STRNCPY(sortbuf1, ml_get(l1.lnum) + l1.st_u.line.start_col_nr,
+ l1.st_u.line.end_col_nr - l1.st_u.line.start_col_nr + 1);
+ sortbuf1[l1.st_u.line.end_col_nr - l1.st_u.line.start_col_nr] = 0;
+ STRNCPY(sortbuf2, ml_get(l2.lnum) + l2.st_u.line.start_col_nr,
+ l2.st_u.line.end_col_nr - l2.st_u.line.start_col_nr + 1);
+ sortbuf2[l2.st_u.line.end_col_nr - l2.st_u.line.start_col_nr] = 0;
+
+ result = sort_ic ? STRICMP(sortbuf1, sortbuf2)
+ : STRCMP(sortbuf1, sortbuf2);
+ }
+
+ /* If two lines have the same value, preserve the original line order. */
+ if (result == 0)
+ return (int)(l1.lnum - l2.lnum);
+ return result;
+}
+
+/*
+ * ":sort".
+ */
+ void
+ex_sort(exarg_T *eap)
+{
+ regmatch_T regmatch;
+ int len;
+ linenr_T lnum;
+ long maxlen = 0;
+ sorti_T *nrs;
+ size_t count = (size_t)(eap->line2 - eap->line1 + 1);
+ size_t i;
+ char_u *p;
+ char_u *s;
+ char_u *s2;
+ char_u c; /* temporary character storage */
+ int unique = FALSE;
+ long deleted;
+ colnr_T start_col;
+ colnr_T end_col;
+ int sort_what = 0;
+ int format_found = 0;
+ int change_occurred = FALSE; // Buffer contents changed.
+
+ /* Sorting one line is really quick! */
+ if (count <= 1)
+ return;
+
+ if (u_save((linenr_T)(eap->line1 - 1), (linenr_T)(eap->line2 + 1)) == FAIL)
+ return;
+ sortbuf1 = NULL;
+ sortbuf2 = NULL;
+ regmatch.regprog = NULL;
+ nrs = (sorti_T *)lalloc((long_u)(count * sizeof(sorti_T)), TRUE);
+ if (nrs == NULL)
+ goto sortend;
+
+ sort_abort = sort_ic = sort_rx = sort_nr = 0;
+#ifdef FEAT_FLOAT
+ sort_flt = 0;
+#endif
+
+ for (p = eap->arg; *p != NUL; ++p)
+ {
+ if (VIM_ISWHITE(*p))
+ ;
+ else if (*p == 'i')
+ sort_ic = TRUE;
+ else if (*p == 'r')
+ sort_rx = TRUE;
+ else if (*p == 'n')
+ {
+ sort_nr = 1;
+ ++format_found;
+ }
+#ifdef FEAT_FLOAT
+ else if (*p == 'f')
+ {
+ sort_flt = 1;
+ ++format_found;
+ }
+#endif
+ else if (*p == 'b')
+ {
+ sort_what = STR2NR_BIN + STR2NR_FORCE;
+ ++format_found;
+ }
+ else if (*p == 'o')
+ {
+ sort_what = STR2NR_OCT + STR2NR_FORCE;
+ ++format_found;
+ }
+ else if (*p == 'x')
+ {
+ sort_what = STR2NR_HEX + STR2NR_FORCE;
+ ++format_found;
+ }
+ else if (*p == 'u')
+ unique = TRUE;
+ else if (*p == '"') /* comment start */
+ break;
+ else if (check_nextcmd(p) != NULL)
+ {
+ eap->nextcmd = check_nextcmd(p);
+ break;
+ }
+ else if (!ASCII_ISALPHA(*p) && regmatch.regprog == NULL)
+ {
+ s = skip_regexp(p + 1, *p, TRUE, NULL);
+ if (*s != *p)
+ {
+ emsg(_(e_invalpat));
+ goto sortend;
+ }
+ *s = NUL;
+ /* Use last search pattern if sort pattern is empty. */
+ if (s == p + 1)
+ {
+ if (last_search_pat() == NULL)
+ {
+ emsg(_(e_noprevre));
+ goto sortend;
+ }
+ regmatch.regprog = vim_regcomp(last_search_pat(), RE_MAGIC);
+ }
+ else
+ regmatch.regprog = vim_regcomp(p + 1, RE_MAGIC);
+ if (regmatch.regprog == NULL)
+ goto sortend;
+ p = s; /* continue after the regexp */
+ regmatch.rm_ic = p_ic;
+ }
+ else
+ {
+ semsg(_(e_invarg2), p);
+ goto sortend;
+ }
+ }
+
+ /* Can only have one of 'n', 'b', 'o' and 'x'. */
+ if (format_found > 1)
+ {
+ emsg(_(e_invarg));
+ goto sortend;
+ }
+
+ /* From here on "sort_nr" is used as a flag for any integer number
+ * sorting. */
+ sort_nr += sort_what;
+
+ /*
+ * Make an array with all line numbers. This avoids having to copy all
+ * the lines into allocated memory.
+ * When sorting on strings "start_col_nr" is the offset in the line, for
+ * numbers sorting it's the number to sort on. This means the pattern
+ * matching and number conversion only has to be done once per line.
+ * Also get the longest line length for allocating "sortbuf".
+ */
+ for (lnum = eap->line1; lnum <= eap->line2; ++lnum)
+ {
+ s = ml_get(lnum);
+ len = (int)STRLEN(s);
+ if (maxlen < len)
+ maxlen = len;
+
+ start_col = 0;
+ end_col = len;
+ if (regmatch.regprog != NULL && vim_regexec(&regmatch, s, 0))
+ {
+ if (sort_rx)
+ {
+ start_col = (colnr_T)(regmatch.startp[0] - s);
+ end_col = (colnr_T)(regmatch.endp[0] - s);
+ }
+ else
+ start_col = (colnr_T)(regmatch.endp[0] - s);
+ }
+ else
+ if (regmatch.regprog != NULL)
+ end_col = 0;
+
+ if (sort_nr
+#ifdef FEAT_FLOAT
+ || sort_flt
+#endif
+ )
+ {
+ /* Make sure vim_str2nr doesn't read any digits past the end
+ * of the match, by temporarily terminating the string there */
+ s2 = s + end_col;
+ c = *s2;
+ *s2 = NUL;
+ /* Sorting on number: Store the number itself. */
+ p = s + start_col;
+ if (sort_nr)
+ {
+ if (sort_what & STR2NR_HEX)
+ s = skiptohex(p);
+ else if (sort_what & STR2NR_BIN)
+ s = skiptobin(p);
+ else
+ s = skiptodigit(p);
+ if (s > p && s[-1] == '-')
+ --s; /* include preceding negative sign */
+ if (*s == NUL)
+ /* empty line should sort before any number */
+ nrs[lnum - eap->line1].st_u.value = -MAXLNUM;
+ else
+ vim_str2nr(s, NULL, NULL, sort_what,
+ &nrs[lnum - eap->line1].st_u.value, NULL, 0);
+ }
+#ifdef FEAT_FLOAT
+ else
+ {
+ s = skipwhite(p);
+ if (*s == '+')
+ s = skipwhite(s + 1);
+
+ if (*s == NUL)
+ /* empty line should sort before any number */
+ nrs[lnum - eap->line1].st_u.value_flt = -DBL_MAX;
+ else
+ nrs[lnum - eap->line1].st_u.value_flt =
+ strtod((char *)s, NULL);
+ }
+#endif
+ *s2 = c;
+ }
+ else
+ {
+ /* Store the column to sort at. */
+ nrs[lnum - eap->line1].st_u.line.start_col_nr = start_col;
+ nrs[lnum - eap->line1].st_u.line.end_col_nr = end_col;
+ }
+
+ nrs[lnum - eap->line1].lnum = lnum;
+
+ if (regmatch.regprog != NULL)
+ fast_breakcheck();
+ if (got_int)
+ goto sortend;
+ }
+
+ /* Allocate a buffer that can hold the longest line. */
+ sortbuf1 = alloc((unsigned)maxlen + 1);
+ if (sortbuf1 == NULL)
+ goto sortend;
+ sortbuf2 = alloc((unsigned)maxlen + 1);
+ if (sortbuf2 == NULL)
+ goto sortend;
+
+ /* Sort the array of line numbers. Note: can't be interrupted! */
+ qsort((void *)nrs, count, sizeof(sorti_T), sort_compare);
+
+ if (sort_abort)
+ goto sortend;
+
+ /* Insert the lines in the sorted order below the last one. */
+ lnum = eap->line2;
+ for (i = 0; i < count; ++i)
+ {
+ linenr_T get_lnum = nrs[eap->forceit ? count - i - 1 : i].lnum;
+
+ // If the original line number of the line being placed is not the same
+ // as "lnum" (accounting for offset), we know that the buffer changed.
+ if (get_lnum + ((linenr_T)count - 1) != lnum)
+ change_occurred = TRUE;
+
+ s = ml_get(get_lnum);
+ if (!unique || i == 0
+ || (sort_ic ? STRICMP(s, sortbuf1) : STRCMP(s, sortbuf1)) != 0)
+ {
+ // Copy the line into a buffer, it may become invalid in
+ // ml_append(). And it's needed for "unique".
+ STRCPY(sortbuf1, s);
+ if (ml_append(lnum++, sortbuf1, (colnr_T)0, FALSE) == FAIL)
+ break;
+ }
+ fast_breakcheck();
+ if (got_int)
+ goto sortend;
+ }
+
+ /* delete the original lines if appending worked */
+ if (i == count)
+ for (i = 0; i < count; ++i)
+ ml_delete(eap->line1, FALSE);
+ else
+ count = 0;
+
+ /* Adjust marks for deleted (or added) lines and prepare for displaying. */
+ deleted = (long)(count - (lnum - eap->line2));
+ if (deleted > 0)
+ {
+ mark_adjust(eap->line2 - deleted, eap->line2, (long)MAXLNUM, -deleted);
+ msgmore(-deleted);
+ }
+ else if (deleted < 0)
+ mark_adjust(eap->line2, MAXLNUM, -deleted, 0L);
+
+ if (change_occurred || deleted != 0)
+ changed_lines(eap->line1, 0, eap->line2 + 1, -deleted);
+
+ curwin->w_cursor.lnum = eap->line1;
+ beginline(BL_WHITE | BL_FIX);
+
+sortend:
+ vim_free(nrs);
+ vim_free(sortbuf1);
+ vim_free(sortbuf2);
+ vim_regfree(regmatch.regprog);
+ if (got_int)
+ emsg(_(e_interr));
+}
+
+/*
+ * ":retab".
+ */
+ void
+ex_retab(exarg_T *eap)
+{
+ linenr_T lnum;
+ int got_tab = FALSE;
+ long num_spaces = 0;
+ long num_tabs;
+ long len;
+ long col;
+ long vcol;
+ long start_col = 0; /* For start of white-space string */
+ long start_vcol = 0; /* For start of white-space string */
+ long old_len;
+ char_u *ptr;
+ char_u *new_line = (char_u *)1; /* init to non-NULL */
+ int did_undo; /* called u_save for current line */
+#ifdef FEAT_VARTABS
+ int *new_vts_array = NULL;
+ char_u *new_ts_str; /* string value of tab argument */
+#else
+ int temp;
+ int new_ts;
+#endif
+ int save_list;
+ linenr_T first_line = 0; /* first changed line */
+ linenr_T last_line = 0; /* last changed line */
+
+ save_list = curwin->w_p_list;
+ curwin->w_p_list = 0; /* don't want list mode here */
+
+#ifdef FEAT_VARTABS
+ new_ts_str = eap->arg;
+ if (!tabstop_set(eap->arg, &new_vts_array))
+ return;
+ while (vim_isdigit(*(eap->arg)) || *(eap->arg) == ',')
+ ++(eap->arg);
+
+ // This ensures that either new_vts_array and new_ts_str are freshly
+ // allocated, or new_vts_array points to an existing array and new_ts_str
+ // is null.
+ if (new_vts_array == NULL)
+ {
+ new_vts_array = curbuf->b_p_vts_array;
+ new_ts_str = NULL;
+ }
+ else
+ new_ts_str = vim_strnsave(new_ts_str, eap->arg - new_ts_str);
+#else
+ new_ts = getdigits(&(eap->arg));
+ if (new_ts < 0)
+ {
+ emsg(_(e_positive));
+ return;
+ }
+ if (new_ts == 0)
+ new_ts = curbuf->b_p_ts;
+#endif
+ for (lnum = eap->line1; !got_int && lnum <= eap->line2; ++lnum)
+ {
+ ptr = ml_get(lnum);
+ col = 0;
+ vcol = 0;
+ did_undo = FALSE;
+ for (;;)
+ {
+ if (VIM_ISWHITE(ptr[col]))
+ {
+ if (!got_tab && num_spaces == 0)
+ {
+ /* First consecutive white-space */
+ start_vcol = vcol;
+ start_col = col;
+ }
+ if (ptr[col] == ' ')
+ num_spaces++;
+ else
+ got_tab = TRUE;
+ }
+ else
+ {
+ if (got_tab || (eap->forceit && num_spaces > 1))
+ {
+ /* Retabulate this string of white-space */
+
+ /* len is virtual length of white string */
+ len = num_spaces = vcol - start_vcol;
+ num_tabs = 0;
+ if (!curbuf->b_p_et)
+ {
+#ifdef FEAT_VARTABS
+ int t, s;
+
+ tabstop_fromto(start_vcol, vcol,
+ curbuf->b_p_ts, new_vts_array, &t, &s);
+ num_tabs = t;
+ num_spaces = s;
+#else
+ temp = new_ts - (start_vcol % new_ts);
+ if (num_spaces >= temp)
+ {
+ num_spaces -= temp;
+ num_tabs++;
+ }
+ num_tabs += num_spaces / new_ts;
+ num_spaces -= (num_spaces / new_ts) * new_ts;
+#endif
+ }
+ if (curbuf->b_p_et || got_tab ||
+ (num_spaces + num_tabs < len))
+ {
+ if (did_undo == FALSE)
+ {
+ did_undo = TRUE;
+ if (u_save((linenr_T)(lnum - 1),
+ (linenr_T)(lnum + 1)) == FAIL)
+ {
+ new_line = NULL; /* flag out-of-memory */
+ break;
+ }
+ }
+
+ /* len is actual number of white characters used */
+ len = num_spaces + num_tabs;
+ old_len = (long)STRLEN(ptr);
+ new_line = lalloc(old_len - col + start_col + len + 1,
+ TRUE);
+ if (new_line == NULL)
+ break;
+ if (start_col > 0)
+ mch_memmove(new_line, ptr, (size_t)start_col);
+ mch_memmove(new_line + start_col + len,
+ ptr + col, (size_t)(old_len - col + 1));
+ ptr = new_line + start_col;
+ for (col = 0; col < len; col++)
+ ptr[col] = (col < num_tabs) ? '\t' : ' ';
+ ml_replace(lnum, new_line, FALSE);
+ if (first_line == 0)
+ first_line = lnum;
+ last_line = lnum;
+ ptr = new_line;
+ col = start_col + len;
+ }
+ }
+ got_tab = FALSE;
+ num_spaces = 0;
+ }
+ if (ptr[col] == NUL)
+ break;
+ vcol += chartabsize(ptr + col, (colnr_T)vcol);
+ if (has_mbyte)
+ col += (*mb_ptr2len)(ptr + col);
+ else
+ ++col;
+ }
+ if (new_line == NULL) /* out of memory */
+ break;
+ line_breakcheck();
+ }
+ if (got_int)
+ emsg(_(e_interr));
+
+#ifdef FEAT_VARTABS
+ // If a single value was given then it can be considered equal to
+ // either the value of 'tabstop' or the value of 'vartabstop'.
+ if (tabstop_count(curbuf->b_p_vts_array) == 0
+ && tabstop_count(new_vts_array) == 1
+ && curbuf->b_p_ts == tabstop_first(new_vts_array))
+ ; /* not changed */
+ else if (tabstop_count(curbuf->b_p_vts_array) > 0
+ && tabstop_eq(curbuf->b_p_vts_array, new_vts_array))
+ ; /* not changed */
+ else
+ redraw_curbuf_later(NOT_VALID);
+#else
+ if (curbuf->b_p_ts != new_ts)
+ redraw_curbuf_later(NOT_VALID);
+#endif
+ if (first_line != 0)
+ changed_lines(first_line, 0, last_line + 1, 0L);
+
+ curwin->w_p_list = save_list; /* restore 'list' */
+
+#ifdef FEAT_VARTABS
+ if (new_ts_str != NULL) /* set the new tabstop */
+ {
+ // If 'vartabstop' is in use or if the value given to retab has more
+ // than one tabstop then update 'vartabstop'.
+ int *old_vts_ary = curbuf->b_p_vts_array;
+
+ if (tabstop_count(old_vts_ary) > 0 || tabstop_count(new_vts_array) > 1)
+ {
+ set_string_option_direct((char_u *)"vts", -1, new_ts_str,
+ OPT_FREE|OPT_LOCAL, 0);
+ curbuf->b_p_vts_array = new_vts_array;
+ vim_free(old_vts_ary);
+ }
+ else
+ {
+ // 'vartabstop' wasn't in use and a single value was given to
+ // retab then update 'tabstop'.
+ curbuf->b_p_ts = tabstop_first(new_vts_array);
+ vim_free(new_vts_array);
+ }
+ vim_free(new_ts_str);
+ }
+#else
+ curbuf->b_p_ts = new_ts;
+#endif
+ coladvance(curwin->w_curswant);
+
+ u_clearline();
+}
+
+/*
+ * :move command - move lines line1-line2 to line dest
+ *
+ * return FAIL for failure, OK otherwise
+ */
+ int
+do_move(linenr_T line1, linenr_T line2, linenr_T dest)
+{
+ char_u *str;
+ linenr_T l;
+ linenr_T extra; // Num lines added before line1
+ linenr_T num_lines; // Num lines moved
+ linenr_T last_line; // Last line in file after adding new text
+#ifdef FEAT_FOLDING
+ win_T *win;
+ tabpage_T *tp;
+#endif
+
+ if (dest >= line1 && dest < line2)
+ {
+ emsg(_("E134: Cannot move a range of lines into itself"));
+ return FAIL;
+ }
+
+ // Do nothing if we are not actually moving any lines. This will prevent
+ // the 'modified' flag from being set without cause.
+ if (dest == line1 - 1 || dest == line2)
+ {
+ // Move the cursor as if lines were moved (see below) to be backwards
+ // compatible.
+ if (dest >= line1)
+ curwin->w_cursor.lnum = dest;
+ else
+ curwin->w_cursor.lnum = dest + (line2 - line1) + 1;
+
+ return OK;
+ }
+
+ num_lines = line2 - line1 + 1;
+
+ /*
+ * First we copy the old text to its new location -- webb
+ * Also copy the flag that ":global" command uses.
+ */
+ if (u_save(dest, dest + 1) == FAIL)
+ return FAIL;
+ for (extra = 0, l = line1; l <= line2; l++)
+ {
+ str = vim_strsave(ml_get(l + extra));
+ if (str != NULL)
+ {
+ ml_append(dest + l - line1, str, (colnr_T)0, FALSE);
+ vim_free(str);
+ if (dest < line1)
+ extra++;
+ }
+ }
+
+ /*
+ * Now we must be careful adjusting our marks so that we don't overlap our
+ * mark_adjust() calls.
+ *
+ * We adjust the marks within the old text so that they refer to the
+ * last lines of the file (temporarily), because we know no other marks
+ * will be set there since these line numbers did not exist until we added
+ * our new lines.
+ *
+ * Then we adjust the marks on lines between the old and new text positions
+ * (either forwards or backwards).
+ *
+ * And Finally we adjust the marks we put at the end of the file back to
+ * their final destination at the new text position -- webb
+ */
+ last_line = curbuf->b_ml.ml_line_count;
+ mark_adjust_nofold(line1, line2, last_line - line2, 0L);
+ if (dest >= line2)
+ {
+ mark_adjust_nofold(line2 + 1, dest, -num_lines, 0L);
+#ifdef FEAT_FOLDING
+ FOR_ALL_TAB_WINDOWS(tp, win) {
+ if (win->w_buffer == curbuf)
+ foldMoveRange(&win->w_folds, line1, line2, dest);
+ }
+#endif
+ curbuf->b_op_start.lnum = dest - num_lines + 1;
+ curbuf->b_op_end.lnum = dest;
+ }
+ else
+ {
+ mark_adjust_nofold(dest + 1, line1 - 1, num_lines, 0L);
+#ifdef FEAT_FOLDING
+ FOR_ALL_TAB_WINDOWS(tp, win) {
+ if (win->w_buffer == curbuf)
+ foldMoveRange(&win->w_folds, dest + 1, line1 - 1, line2);
+ }
+#endif
+ curbuf->b_op_start.lnum = dest + 1;
+ curbuf->b_op_end.lnum = dest + num_lines;
+ }
+ curbuf->b_op_start.col = curbuf->b_op_end.col = 0;
+ mark_adjust_nofold(last_line - num_lines + 1, last_line,
+ -(last_line - dest - extra), 0L);
+
+ /*
+ * Now we delete the original text -- webb
+ */
+ if (u_save(line1 + extra - 1, line2 + extra + 1) == FAIL)
+ return FAIL;
+
+ for (l = line1; l <= line2; l++)
+ ml_delete(line1 + extra, TRUE);
+
+ if (!global_busy && num_lines > p_report)
+ smsg(NGETTEXT("%ld line moved", "%ld lines moved", num_lines),
+ (long)num_lines);
+
+ /*
+ * Leave the cursor on the last of the moved lines.
+ */
+ if (dest >= line1)
+ curwin->w_cursor.lnum = dest;
+ else
+ curwin->w_cursor.lnum = dest + (line2 - line1) + 1;
+
+ if (line1 < dest)
+ {
+ dest += num_lines + 1;
+ last_line = curbuf->b_ml.ml_line_count;
+ if (dest > last_line + 1)
+ dest = last_line + 1;
+ changed_lines(line1, 0, dest, 0L);
+ }
+ else
+ changed_lines(dest + 1, 0, line1 + num_lines, 0L);
+
+ return OK;
+}
+
+/*
+ * ":copy"
+ */
+ void
+ex_copy(linenr_T line1, linenr_T line2, linenr_T n)
+{
+ linenr_T count;
+ char_u *p;
+
+ count = line2 - line1 + 1;
+ curbuf->b_op_start.lnum = n + 1;
+ curbuf->b_op_end.lnum = n + count;
+ curbuf->b_op_start.col = curbuf->b_op_end.col = 0;
+
+ /*
+ * there are three situations:
+ * 1. destination is above line1
+ * 2. destination is between line1 and line2
+ * 3. destination is below line2
+ *
+ * n = destination (when starting)
+ * curwin->w_cursor.lnum = destination (while copying)
+ * line1 = start of source (while copying)
+ * line2 = end of source (while copying)
+ */
+ if (u_save(n, n + 1) == FAIL)
+ return;
+
+ curwin->w_cursor.lnum = n;
+ while (line1 <= line2)
+ {
+ /* need to use vim_strsave() because the line will be unlocked within
+ * ml_append() */
+ p = vim_strsave(ml_get(line1));
+ if (p != NULL)
+ {
+ ml_append(curwin->w_cursor.lnum, p, (colnr_T)0, FALSE);
+ vim_free(p);
+ }
+ /* situation 2: skip already copied lines */
+ if (line1 == n)
+ line1 = curwin->w_cursor.lnum;
+ ++line1;
+ if (curwin->w_cursor.lnum < line1)
+ ++line1;
+ if (curwin->w_cursor.lnum < line2)
+ ++line2;
+ ++curwin->w_cursor.lnum;
+ }
+
+ appended_lines_mark(n, count);
+
+ msgmore((long)count);
+}
+
+static char_u *prevcmd = NULL; /* the previous command */
+
+#if defined(EXITFREE) || defined(PROTO)
+ void
+free_prev_shellcmd(void)
+{
+ vim_free(prevcmd);
+}
+#endif
+
+/*
+ * Handle the ":!cmd" command. Also for ":r !cmd" and ":w !cmd"
+ * Bangs in the argument are replaced with the previously entered command.
+ * Remember the argument.
+ */
+ void
+do_bang(
+ int addr_count,
+ exarg_T *eap,
+ int forceit,
+ int do_in,
+ int do_out)
+{
+ char_u *arg = eap->arg; /* command */
+ linenr_T line1 = eap->line1; /* start of range */
+ linenr_T line2 = eap->line2; /* end of range */
+ char_u *newcmd = NULL; /* the new command */
+ int free_newcmd = FALSE; /* need to free() newcmd */
+ int ins_prevcmd;
+ char_u *t;
+ char_u *p;
+ char_u *trailarg;
+ int len;
+ int scroll_save = msg_scroll;
+
+ /*
+ * Disallow shell commands for "rvim".
+ * Disallow shell commands from .exrc and .vimrc in current directory for
+ * security reasons.
+ */
+ if (check_restricted() || check_secure())
+ return;
+
+ if (addr_count == 0) /* :! */
+ {
+ msg_scroll = FALSE; /* don't scroll here */
+ autowrite_all();
+ msg_scroll = scroll_save;
+ }
+
+ /*
+ * Try to find an embedded bang, like in :!<cmd> ! [args]
+ * (:!! is indicated by the 'forceit' variable)
+ */
+ ins_prevcmd = forceit;
+ trailarg = arg;
+ do
+ {
+ len = (int)STRLEN(trailarg) + 1;
+ if (newcmd != NULL)
+ len += (int)STRLEN(newcmd);
+ if (ins_prevcmd)
+ {
+ if (prevcmd == NULL)
+ {
+ emsg(_(e_noprev));
+ vim_free(newcmd);
+ return;
+ }
+ len += (int)STRLEN(prevcmd);
+ }
+ if ((t = alloc((unsigned)len)) == NULL)
+ {
+ vim_free(newcmd);
+ return;
+ }
+ *t = NUL;
+ if (newcmd != NULL)
+ STRCAT(t, newcmd);
+ if (ins_prevcmd)
+ STRCAT(t, prevcmd);
+ p = t + STRLEN(t);
+ STRCAT(t, trailarg);
+ vim_free(newcmd);
+ newcmd = t;
+
+ /*
+ * Scan the rest of the argument for '!', which is replaced by the
+ * previous command. "\!" is replaced by "!" (this is vi compatible).
+ */
+ trailarg = NULL;
+ while (*p)
+ {
+ if (*p == '!')
+ {
+ if (p > newcmd && p[-1] == '\\')
+ STRMOVE(p - 1, p);
+ else
+ {
+ trailarg = p;
+ *trailarg++ = NUL;
+ ins_prevcmd = TRUE;
+ break;
+ }
+ }
+ ++p;
+ }
+ } while (trailarg != NULL);
+
+ vim_free(prevcmd);
+ prevcmd = newcmd;
+
+ if (bangredo) /* put cmd in redo buffer for ! command */
+ {
+ /* If % or # appears in the command, it must have been escaped.
+ * Reescape them, so that redoing them does not substitute them by the
+ * buffername. */
+ char_u *cmd = vim_strsave_escaped(prevcmd, (char_u *)"%#");
+
+ if (cmd != NULL)
+ {
+ AppendToRedobuffLit(cmd, -1);
+ vim_free(cmd);
+ }
+ else
+ AppendToRedobuffLit(prevcmd, -1);
+ AppendToRedobuff((char_u *)"\n");
+ bangredo = FALSE;
+ }
+ /*
+ * Add quotes around the command, for shells that need them.
+ */
+ if (*p_shq != NUL)
+ {
+ newcmd = alloc((unsigned)(STRLEN(prevcmd) + 2 * STRLEN(p_shq) + 1));
+ if (newcmd == NULL)
+ return;
+ STRCPY(newcmd, p_shq);
+ STRCAT(newcmd, prevcmd);
+ STRCAT(newcmd, p_shq);
+ free_newcmd = TRUE;
+ }
+ if (addr_count == 0) /* :! */
+ {
+ /* echo the command */
+ msg_start();
+ msg_putchar(':');
+ msg_putchar('!');
+ msg_outtrans(newcmd);
+ msg_clr_eos();
+ windgoto(msg_row, msg_col);
+
+ do_shell(newcmd, 0);
+ }
+ else /* :range! */
+ {
+ /* Careful: This may recursively call do_bang() again! (because of
+ * autocommands) */
+ do_filter(line1, line2, eap, newcmd, do_in, do_out);
+ apply_autocmds(EVENT_SHELLFILTERPOST, NULL, NULL, FALSE, curbuf);
+ }
+ if (free_newcmd)
+ vim_free(newcmd);
+}
+
+/*
+ * do_filter: filter lines through a command given by the user
+ *
+ * We mostly use temp files and the call_shell() routine here. This would
+ * normally be done using pipes on a UNIX machine, but this is more portable
+ * to non-unix machines. The call_shell() routine needs to be able
+ * to deal with redirection somehow, and should handle things like looking
+ * at the PATH env. variable, and adding reasonable extensions to the
+ * command name given by the user. All reasonable versions of call_shell()
+ * do this.
+ * Alternatively, if on Unix and redirecting input or output, but not both,
+ * and the 'shelltemp' option isn't set, use pipes.
+ * We use input redirection if do_in is TRUE.
+ * We use output redirection if do_out is TRUE.
+ */
+ static void
+do_filter(
+ linenr_T line1,
+ linenr_T line2,
+ exarg_T *eap, /* for forced 'ff' and 'fenc' */
+ char_u *cmd,
+ int do_in,
+ int do_out)
+{
+ char_u *itmp = NULL;
+ char_u *otmp = NULL;
+ linenr_T linecount;
+ linenr_T read_linecount;
+ pos_T cursor_save;
+ char_u *cmd_buf;
+ buf_T *old_curbuf = curbuf;
+ int shell_flags = 0;
+
+ if (*cmd == NUL) /* no filter command */
+ return;
+
+ cursor_save = curwin->w_cursor;
+ linecount = line2 - line1 + 1;
+ curwin->w_cursor.lnum = line1;
+ curwin->w_cursor.col = 0;
+ changed_line_abv_curs();
+ invalidate_botline();
+
+ /*
+ * When using temp files:
+ * 1. * Form temp file names
+ * 2. * Write the lines to a temp file
+ * 3. Run the filter command on the temp file
+ * 4. * Read the output of the command into the buffer
+ * 5. * Delete the original lines to be filtered
+ * 6. * Remove the temp files
+ *
+ * When writing the input with a pipe or when catching the output with a
+ * pipe only need to do 3.
+ */
+
+ if (do_out)
+ shell_flags |= SHELL_DOOUT;
+
+#ifdef FEAT_FILTERPIPE
+ if (!do_in && do_out && !p_stmp)
+ {
+ /* Use a pipe to fetch stdout of the command, do not use a temp file. */
+ shell_flags |= SHELL_READ;
+ curwin->w_cursor.lnum = line2;
+ }
+ else if (do_in && !do_out && !p_stmp)
+ {
+ /* Use a pipe to write stdin of the command, do not use a temp file. */
+ shell_flags |= SHELL_WRITE;
+ curbuf->b_op_start.lnum = line1;
+ curbuf->b_op_end.lnum = line2;
+ }
+ else if (do_in && do_out && !p_stmp)
+ {
+ /* Use a pipe to write stdin and fetch stdout of the command, do not
+ * use a temp file. */
+ shell_flags |= SHELL_READ|SHELL_WRITE;
+ curbuf->b_op_start.lnum = line1;
+ curbuf->b_op_end.lnum = line2;
+ curwin->w_cursor.lnum = line2;
+ }
+ else
+#endif
+ if ((do_in && (itmp = vim_tempname('i', FALSE)) == NULL)
+ || (do_out && (otmp = vim_tempname('o', FALSE)) == NULL))
+ {
+ emsg(_(e_notmp));
+ goto filterend;
+ }
+
+/*
+ * The writing and reading of temp files will not be shown.
+ * Vi also doesn't do this and the messages are not very informative.
+ */
+ ++no_wait_return; /* don't call wait_return() while busy */
+ if (itmp != NULL && buf_write(curbuf, itmp, NULL, line1, line2, eap,
+ FALSE, FALSE, FALSE, TRUE) == FAIL)
+ {
+ msg_putchar('\n'); /* keep message from buf_write() */
+ --no_wait_return;
+#if defined(FEAT_EVAL)
+ if (!aborting())
+#endif
+ (void)semsg(_(e_notcreate), itmp); /* will call wait_return */
+ goto filterend;
+ }
+ if (curbuf != old_curbuf)
+ goto filterend;
+
+ if (!do_out)
+ msg_putchar('\n');
+
+ /* Create the shell command in allocated memory. */
+ cmd_buf = make_filter_cmd(cmd, itmp, otmp);
+ if (cmd_buf == NULL)
+ goto filterend;
+
+ windgoto((int)Rows - 1, 0);
+ cursor_on();
+
+ /*
+ * When not redirecting the output the command can write anything to the
+ * screen. If 'shellredir' is equal to ">", screen may be messed up by
+ * stderr output of external command. Clear the screen later.
+ * If do_in is FALSE, this could be something like ":r !cat", which may
+ * also mess up the screen, clear it later.
+ */
+ if (!do_out || STRCMP(p_srr, ">") == 0 || !do_in)
+ redraw_later_clear();
+
+ if (do_out)
+ {
+ if (u_save((linenr_T)(line2), (linenr_T)(line2 + 1)) == FAIL)
+ {
+ vim_free(cmd_buf);
+ goto error;
+ }
+ redraw_curbuf_later(VALID);
+ }
+ read_linecount = curbuf->b_ml.ml_line_count;
+
+ /*
+ * When call_shell() fails wait_return() is called to give the user a
+ * chance to read the error messages. Otherwise errors are ignored, so you
+ * can see the error messages from the command that appear on stdout; use
+ * 'u' to fix the text
+ * Switch to cooked mode when not redirecting stdin, avoids that something
+ * like ":r !cat" hangs.
+ * Pass on the SHELL_DOOUT flag when the output is being redirected.
+ */
+ if (call_shell(cmd_buf, SHELL_FILTER | SHELL_COOKED | shell_flags))
+ {
+ redraw_later_clear();
+ wait_return(FALSE);
+ }
+ vim_free(cmd_buf);
+
+ did_check_timestamps = FALSE;
+ need_check_timestamps = TRUE;
+
+ /* When interrupting the shell command, it may still have produced some
+ * useful output. Reset got_int here, so that readfile() won't cancel
+ * reading. */
+ ui_breakcheck();
+ got_int = FALSE;
+
+ if (do_out)
+ {
+ if (otmp != NULL)
+ {
+ if (readfile(otmp, NULL, line2, (linenr_T)0, (linenr_T)MAXLNUM,
+ eap, READ_FILTER) != OK)
+ {
+#if defined(FEAT_EVAL)
+ if (!aborting())
+#endif
+ {
+ msg_putchar('\n');
+ semsg(_(e_notread), otmp);
+ }
+ goto error;
+ }
+ if (curbuf != old_curbuf)
+ goto filterend;
+ }
+
+ read_linecount = curbuf->b_ml.ml_line_count - read_linecount;
+
+ if (shell_flags & SHELL_READ)
+ {
+ curbuf->b_op_start.lnum = line2 + 1;
+ curbuf->b_op_end.lnum = curwin->w_cursor.lnum;
+ appended_lines_mark(line2, read_linecount);
+ }
+
+ if (do_in)
+ {
+ if (cmdmod.keepmarks || vim_strchr(p_cpo, CPO_REMMARK) == NULL)
+ {
+ if (read_linecount >= linecount)
+ /* move all marks from old lines to new lines */
+ mark_adjust(line1, line2, linecount, 0L);
+ else
+ {
+ /* move marks from old lines to new lines, delete marks
+ * that are in deleted lines */
+ mark_adjust(line1, line1 + read_linecount - 1,
+ linecount, 0L);
+ mark_adjust(line1 + read_linecount, line2, MAXLNUM, 0L);
+ }
+ }
+
+ /*
+ * Put cursor on first filtered line for ":range!cmd".
+ * Adjust '[ and '] (set by buf_write()).
+ */
+ curwin->w_cursor.lnum = line1;
+ del_lines(linecount, TRUE);
+ curbuf->b_op_start.lnum -= linecount; /* adjust '[ */
+ curbuf->b_op_end.lnum -= linecount; /* adjust '] */
+ write_lnum_adjust(-linecount); /* adjust last line
+ for next write */
+#ifdef FEAT_FOLDING
+ foldUpdate(curwin, curbuf->b_op_start.lnum, curbuf->b_op_end.lnum);
+#endif
+ }
+ else
+ {
+ /*
+ * Put cursor on last new line for ":r !cmd".
+ */
+ linecount = curbuf->b_op_end.lnum - curbuf->b_op_start.lnum + 1;
+ curwin->w_cursor.lnum = curbuf->b_op_end.lnum;
+ }
+
+ beginline(BL_WHITE | BL_FIX); /* cursor on first non-blank */
+ --no_wait_return;
+
+ if (linecount > p_report)
+ {
+ if (do_in)
+ {
+ vim_snprintf(msg_buf, sizeof(msg_buf),
+ _("%ld lines filtered"), (long)linecount);
+ if (msg(msg_buf) && !msg_scroll)
+ /* save message to display it after redraw */
+ set_keep_msg((char_u *)msg_buf, 0);
+ }
+ else
+ msgmore((long)linecount);
+ }
+ }
+ else
+ {
+error:
+ /* put cursor back in same position for ":w !cmd" */
+ curwin->w_cursor = cursor_save;
+ --no_wait_return;
+ wait_return(FALSE);
+ }
+
+filterend:
+
+ if (curbuf != old_curbuf)
+ {
+ --no_wait_return;
+ emsg(_("E135: *Filter* Autocommands must not change current buffer"));
+ }
+ if (itmp != NULL)
+ mch_remove(itmp);
+ if (otmp != NULL)
+ mch_remove(otmp);
+ vim_free(itmp);
+ vim_free(otmp);
+}
+
+/*
+ * Call a shell to execute a command.
+ * When "cmd" is NULL start an interactive shell.
+ */
+ void
+do_shell(
+ char_u *cmd,
+ int flags) /* may be SHELL_DOOUT when output is redirected */
+{
+ buf_T *buf;
+#ifndef FEAT_GUI_MSWIN
+ int save_nwr;
+#endif
+#ifdef MSWIN
+ int winstart = FALSE;
+#endif
+
+ /*
+ * Disallow shell commands for "rvim".
+ * Disallow shell commands from .exrc and .vimrc in current directory for
+ * security reasons.
+ */
+ if (check_restricted() || check_secure())
+ {
+ msg_end();
+ return;
+ }
+
+#ifdef MSWIN
+ /*
+ * Check if ":!start" is used.
+ */
+ if (cmd != NULL)
+ winstart = (STRNICMP(cmd, "start ", 6) == 0);
+#endif
+
+ /*
+ * For autocommands we want to get the output on the current screen, to
+ * avoid having to type return below.
+ */
+ msg_putchar('\r'); /* put cursor at start of line */
+ if (!autocmd_busy)
+ {
+#ifdef MSWIN
+ if (!winstart)
+#endif
+ stoptermcap();
+ }
+#ifdef MSWIN
+ if (!winstart)
+#endif
+ msg_putchar('\n'); /* may shift screen one line up */
+
+ /* warning message before calling the shell */
+ if (p_warn && !autocmd_busy && msg_silent == 0)
+ FOR_ALL_BUFFERS(buf)
+ if (bufIsChangedNotTerm(buf))
+ {
+#ifdef FEAT_GUI_MSWIN
+ if (!winstart)
+ starttermcap(); /* don't want a message box here */
+#endif
+ msg_puts(_("[No write since last change]\n"));
+#ifdef FEAT_GUI_MSWIN
+ if (!winstart)
+ stoptermcap();
+#endif
+ break;
+ }
+
+ /* This windgoto is required for when the '\n' resulted in a "delete line
+ * 1" command to the terminal. */
+ if (!swapping_screen())
+ windgoto(msg_row, msg_col);
+ cursor_on();
+ (void)call_shell(cmd, SHELL_COOKED | flags);
+ did_check_timestamps = FALSE;
+ need_check_timestamps = TRUE;
+
+ /*
+ * put the message cursor at the end of the screen, avoids wait_return()
+ * to overwrite the text that the external command showed
+ */
+ if (!swapping_screen())
+ {
+ msg_row = Rows - 1;
+ msg_col = 0;
+ }
+
+ if (autocmd_busy)
+ {
+ if (msg_silent == 0)
+ redraw_later_clear();
+ }
+ else
+ {
+ /*
+ * For ":sh" there is no need to call wait_return(), just redraw.
+ * Also for the Win32 GUI (the output is in a console window).
+ * Otherwise there is probably text on the screen that the user wants
+ * to read before redrawing, so call wait_return().
+ */
+#ifndef FEAT_GUI_MSWIN
+ if (cmd == NULL
+# ifdef WIN3264
+ || (winstart && !need_wait_return)
+# endif
+ )
+ {
+ if (msg_silent == 0)
+ redraw_later_clear();
+ need_wait_return = FALSE;
+ }
+ else
+ {
+ /*
+ * If we switch screens when starttermcap() is called, we really
+ * want to wait for "hit return to continue".
+ */
+ save_nwr = no_wait_return;
+ if (swapping_screen())
+ no_wait_return = FALSE;
+# ifdef AMIGA
+ wait_return(term_console ? -1 : msg_silent == 0); /* see below */
+# else
+ wait_return(msg_silent == 0);
+# endif
+ no_wait_return = save_nwr;
+ }
+#endif /* FEAT_GUI_W32 */
+
+#ifdef MSWIN
+ if (!winstart) /* if winstart==TRUE, never stopped termcap! */
+#endif
+ starttermcap(); /* start termcap if not done by wait_return() */
+
+ /*
+ * In an Amiga window redrawing is caused by asking the window size.
+ * If we got an interrupt this will not work. The chance that the
+ * window size is wrong is very small, but we need to redraw the
+ * screen. Don't do this if ':' hit in wait_return(). THIS IS UGLY
+ * but it saves an extra redraw.
+ */
+#ifdef AMIGA
+ if (skip_redraw) /* ':' hit in wait_return() */
+ {
+ if (msg_silent == 0)
+ redraw_later_clear();
+ }
+ else if (term_console)
+ {
+ OUT_STR(IF_EB("\033[0 q", ESC_STR "[0 q")); /* get window size */
+ if (got_int && msg_silent == 0)
+ redraw_later_clear(); /* if got_int is TRUE, redraw needed */
+ else
+ must_redraw = 0; /* no extra redraw needed */
+ }
+#endif
+ }
+
+ /* display any error messages now */
+ display_errors();
+
+ apply_autocmds(EVENT_SHELLCMDPOST, NULL, NULL, FALSE, curbuf);
+}
+
+#if !defined(UNIX)
+ static char_u *
+find_pipe(char_u *cmd)
+{
+ char_u *p;
+ int inquote = FALSE;
+
+ for (p = cmd; *p != NUL; ++p)
+ {
+ if (!inquote && *p == '|')
+ return p;
+ if (*p == '"')
+ inquote = !inquote;
+ else if (rem_backslash(p))
+ ++p;
+ }
+ return NULL;
+}
+#endif
+
+/*
+ * Create a shell command from a command string, input redirection file and
+ * output redirection file.
+ * Returns an allocated string with the shell command, or NULL for failure.
+ */
+ char_u *
+make_filter_cmd(
+ char_u *cmd, /* command */
+ char_u *itmp, /* NULL or name of input file */
+ char_u *otmp) /* NULL or name of output file */
+{
+ char_u *buf;
+ long_u len;
+
+#if defined(UNIX)
+ int is_fish_shell;
+ char_u *shell_name = get_isolated_shell_name();
+
+ /* Account for fish's different syntax for subshells */
+ is_fish_shell = (fnamecmp(shell_name, "fish") == 0);
+ vim_free(shell_name);
+ if (is_fish_shell)
+ len = (long_u)STRLEN(cmd) + 13; /* "begin; " + "; end" + NUL */
+ else
+#endif
+ len = (long_u)STRLEN(cmd) + 3; /* "()" + NUL */
+ if (itmp != NULL)
+ len += (long_u)STRLEN(itmp) + 9; /* " { < " + " } " */
+ if (otmp != NULL)
+ len += (long_u)STRLEN(otmp) + (long_u)STRLEN(p_srr) + 2; /* " " */
+ buf = lalloc(len, TRUE);
+ if (buf == NULL)
+ return NULL;
+
+#if defined(UNIX)
+ /*
+ * Put braces around the command (for concatenated commands) when
+ * redirecting input and/or output.
+ */
+ if (itmp != NULL || otmp != NULL)
+ {
+ if (is_fish_shell)
+ vim_snprintf((char *)buf, len, "begin; %s; end", (char *)cmd);
+ else
+ vim_snprintf((char *)buf, len, "(%s)", (char *)cmd);
+ }
+ else
+ STRCPY(buf, cmd);
+ if (itmp != NULL)
+ {
+ STRCAT(buf, " < ");
+ STRCAT(buf, itmp);
+ }
+#else
+ /*
+ * For shells that don't understand braces around commands, at least allow
+ * the use of commands in a pipe.
+ */
+ STRCPY(buf, cmd);
+ if (itmp != NULL)
+ {
+ char_u *p;
+
+ /*
+ * If there is a pipe, we have to put the '<' in front of it.
+ * Don't do this when 'shellquote' is not empty, otherwise the
+ * redirection would be inside the quotes.
+ */
+ if (*p_shq == NUL)
+ {
+ p = find_pipe(buf);
+ if (p != NULL)
+ *p = NUL;
+ }
+ STRCAT(buf, " <"); /* " < " causes problems on Amiga */
+ STRCAT(buf, itmp);
+ if (*p_shq == NUL)
+ {
+ p = find_pipe(cmd);
+ if (p != NULL)
+ {
+ STRCAT(buf, " "); /* insert a space before the '|' for DOS */
+ STRCAT(buf, p);
+ }
+ }
+ }
+#endif
+ if (otmp != NULL)
+ append_redir(buf, (int)len, p_srr, otmp);
+
+ return buf;
+}
+
+/*
+ * Append output redirection for file "fname" to the end of string buffer
+ * "buf[buflen]"
+ * Works with the 'shellredir' and 'shellpipe' options.
+ * The caller should make sure that there is enough room:
+ * STRLEN(opt) + STRLEN(fname) + 3
+ */
+ void
+append_redir(
+ char_u *buf,
+ int buflen,
+ char_u *opt,
+ char_u *fname)
+{
+ char_u *p;
+ char_u *end;
+
+ end = buf + STRLEN(buf);
+ /* find "%s" */
+ for (p = opt; (p = vim_strchr(p, '%')) != NULL; ++p)
+ {
+ if (p[1] == 's') /* found %s */
+ break;
+ if (p[1] == '%') /* skip %% */
+ ++p;
+ }
+ if (p != NULL)
+ {
+ *end = ' '; /* not really needed? Not with sh, ksh or bash */
+ vim_snprintf((char *)end + 1, (size_t)(buflen - (end + 1 - buf)),
+ (char *)opt, (char *)fname);
+ }
+ else
+ vim_snprintf((char *)end, (size_t)(buflen - (end - buf)),
+#ifdef FEAT_QUICKFIX
+ " %s %s",
+#else
+ " %s%s", /* " > %s" causes problems on Amiga */
+#endif
+ (char *)opt, (char *)fname);
+}
+
+#if defined(FEAT_VIMINFO) || defined(PROTO)
+
+static int read_viminfo_barline(vir_T *virp, int got_encoding, int force, int writing);
+static void write_viminfo_version(FILE *fp_out);
+static void write_viminfo_barlines(vir_T *virp, FILE *fp_out);
+static int viminfo_errcnt;
+
+ static int
+no_viminfo(void)
+{
+ /* "vim -i NONE" does not read or write a viminfo file */
+ return STRCMP(p_viminfofile, "NONE") == 0;
+}
+
+/*
+ * Report an error for reading a viminfo file.
+ * Count the number of errors. When there are more than 10, return TRUE.
+ */
+ int
+viminfo_error(char *errnum, char *message, char_u *line)
+{
+ vim_snprintf((char *)IObuff, IOSIZE, _("%sviminfo: %s in line: "),
+ errnum, message);
+ STRNCAT(IObuff, line, IOSIZE - STRLEN(IObuff) - 1);
+ if (IObuff[STRLEN(IObuff) - 1] == '\n')
+ IObuff[STRLEN(IObuff) - 1] = NUL;
+ emsg((char *)IObuff);
+ if (++viminfo_errcnt >= 10)
+ {
+ emsg(_("E136: viminfo: Too many errors, skipping rest of file"));
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * read_viminfo() -- Read the viminfo file. Registers etc. which are already
+ * set are not over-written unless "flags" includes VIF_FORCEIT. -- webb
+ */
+ int
+read_viminfo(
+ char_u *file, /* file name or NULL to use default name */
+ int flags) /* VIF_WANT_INFO et al. */
+{
+ FILE *fp;
+ char_u *fname;
+
+ if (no_viminfo())
+ return FAIL;
+
+ fname = viminfo_filename(file); /* get file name in allocated buffer */
+ if (fname == NULL)
+ return FAIL;
+ fp = mch_fopen((char *)fname, READBIN);
+
+ if (p_verbose > 0)
+ {
+ verbose_enter();
+ smsg(_("Reading viminfo file \"%s\"%s%s%s"),
+ fname,
+ (flags & VIF_WANT_INFO) ? _(" info") : "",
+ (flags & VIF_WANT_MARKS) ? _(" marks") : "",
+ (flags & VIF_GET_OLDFILES) ? _(" oldfiles") : "",
+ fp == NULL ? _(" FAILED") : "");
+ verbose_leave();
+ }
+
+ vim_free(fname);
+ if (fp == NULL)
+ return FAIL;
+
+ viminfo_errcnt = 0;
+ do_viminfo(fp, NULL, flags);
+
+ fclose(fp);
+ return OK;
+}
+
+/*
+ * Write the viminfo file. The old one is read in first so that effectively a
+ * merge of current info and old info is done. This allows multiple vims to
+ * run simultaneously, without losing any marks etc.
+ * If "forceit" is TRUE, then the old file is not read in, and only internal
+ * info is written to the file.
+ */
+ void
+write_viminfo(char_u *file, int forceit)
+{
+ char_u *fname;
+ FILE *fp_in = NULL; /* input viminfo file, if any */
+ FILE *fp_out = NULL; /* output viminfo file */
+ char_u *tempname = NULL; /* name of temp viminfo file */
+ stat_T st_new; /* mch_stat() of potential new file */
+#if defined(UNIX) || defined(VMS)
+ mode_t umask_save;
+#endif
+#ifdef UNIX
+ int shortname = FALSE; /* use 8.3 file name */
+ stat_T st_old; /* mch_stat() of existing viminfo file */
+#endif
+#ifdef WIN3264
+ int hidden = FALSE;
+#endif
+
+ if (no_viminfo())
+ return;
+
+ fname = viminfo_filename(file); /* may set to default if NULL */
+ if (fname == NULL)
+ return;
+
+ fp_in = mch_fopen((char *)fname, READBIN);
+ if (fp_in == NULL)
+ {
+ int fd;
+
+ /* if it does exist, but we can't read it, don't try writing */
+ if (mch_stat((char *)fname, &st_new) == 0)
+ goto end;
+
+ /* Create the new .viminfo non-accessible for others, because it may
+ * contain text from non-accessible documents. It is up to the user to
+ * widen access (e.g. to a group). This may also fail if there is a
+ * race condition, then just give up. */
+ fd = mch_open((char *)fname,
+ O_CREAT|O_EXTRA|O_EXCL|O_WRONLY|O_NOFOLLOW, 0600);
+ if (fd < 0)
+ goto end;
+ fp_out = fdopen(fd, WRITEBIN);
+ }
+ else
+ {
+ /*
+ * There is an existing viminfo file. Create a temporary file to
+ * write the new viminfo into, in the same directory as the
+ * existing viminfo file, which will be renamed once all writing is
+ * successful.
+ */
+#ifdef UNIX
+ /*
+ * For Unix we check the owner of the file. It's not very nice to
+ * overwrite a user's viminfo file after a "su root", with a
+ * viminfo file that the user can't read.
+ */
+ st_old.st_dev = (dev_t)0;
+ st_old.st_ino = 0;
+ st_old.st_mode = 0600;
+ if (mch_stat((char *)fname, &st_old) == 0
+ && getuid() != ROOT_UID
+ && !(st_old.st_uid == getuid()
+ ? (st_old.st_mode & 0200)
+ : (st_old.st_gid == getgid()
+ ? (st_old.st_mode & 0020)
+ : (st_old.st_mode & 0002))))
+ {
+ int tt = msg_didany;
+
+ /* avoid a wait_return for this message, it's annoying */
+ semsg(_("E137: Viminfo file is not writable: %s"), fname);
+ msg_didany = tt;
+ fclose(fp_in);
+ goto end;
+ }
+#endif
+#ifdef WIN3264
+ /* Get the file attributes of the existing viminfo file. */
+ hidden = mch_ishidden(fname);
+#endif
+
+ /*
+ * Make tempname, find one that does not exist yet.
+ * Beware of a race condition: If someone logs out and all Vim
+ * instances exit at the same time a temp file might be created between
+ * stat() and open(). Use mch_open() with O_EXCL to avoid that.
+ * May try twice: Once normal and once with shortname set, just in
+ * case somebody puts his viminfo file in an 8.3 filesystem.
+ */
+ for (;;)
+ {
+ int next_char = 'z';
+ char_u *wp;
+
+ tempname = buf_modname(
+#ifdef UNIX
+ shortname,
+#else
+ FALSE,
+#endif
+ fname,
+#ifdef VMS
+ (char_u *)"-tmp",
+#else
+ (char_u *)".tmp",
+#endif
+ FALSE);
+ if (tempname == NULL) /* out of memory */
+ break;
+
+ /*
+ * Try a series of names. Change one character, just before
+ * the extension. This should also work for an 8.3
+ * file name, when after adding the extension it still is
+ * the same file as the original.
+ */
+ wp = tempname + STRLEN(tempname) - 5;
+ if (wp < gettail(tempname)) /* empty file name? */
+ wp = gettail(tempname);
+ for (;;)
+ {
+ /*
+ * Check if tempfile already exists. Never overwrite an
+ * existing file!
+ */
+ if (mch_stat((char *)tempname, &st_new) == 0)
+ {
+#ifdef UNIX
+ /*
+ * Check if tempfile is same as original file. May happen
+ * when modname() gave the same file back. E.g. silly
+ * link, or file name-length reached. Try again with
+ * shortname set.
+ */
+ if (!shortname && st_new.st_dev == st_old.st_dev
+ && st_new.st_ino == st_old.st_ino)
+ {
+ VIM_CLEAR(tempname);
+ shortname = TRUE;
+ break;
+ }
+#endif
+ }
+ else
+ {
+ /* Try creating the file exclusively. This may fail if
+ * another Vim tries to do it at the same time. */
+#ifdef VMS
+ /* fdopen() fails for some reason */
+ umask_save = umask(077);
+ fp_out = mch_fopen((char *)tempname, WRITEBIN);
+ (void)umask(umask_save);
+#else
+ int fd;
+
+ /* Use mch_open() to be able to use O_NOFOLLOW and set file
+ * protection:
+ * Unix: same as original file, but strip s-bit. Reset
+ * umask to avoid it getting in the way.
+ * Others: r&w for user only. */
+# ifdef UNIX
+ umask_save = umask(0);
+ fd = mch_open((char *)tempname,
+ O_CREAT|O_EXTRA|O_EXCL|O_WRONLY|O_NOFOLLOW,
+ (int)((st_old.st_mode & 0777) | 0600));
+ (void)umask(umask_save);
+# else
+ fd = mch_open((char *)tempname,
+ O_CREAT|O_EXTRA|O_EXCL|O_WRONLY|O_NOFOLLOW, 0600);
+# endif
+ if (fd < 0)
+ {
+ fp_out = NULL;
+# ifdef EEXIST
+ /* Avoid trying lots of names while the problem is lack
+ * of premission, only retry if the file already
+ * exists. */
+ if (errno != EEXIST)
+ break;
+# endif
+ }
+ else
+ fp_out = fdopen(fd, WRITEBIN);
+#endif /* VMS */
+ if (fp_out != NULL)
+ break;
+ }
+
+ /* Assume file exists, try again with another name. */
+ if (next_char == 'a' - 1)
+ {
+ /* They all exist? Must be something wrong! Don't write
+ * the viminfo file then. */
+ semsg(_("E929: Too many viminfo temp files, like %s!"),
+ tempname);
+ break;
+ }
+ *wp = next_char;
+ --next_char;
+ }
+
+ if (tempname != NULL)
+ break;
+ /* continue if shortname was set */
+ }
+
+#if defined(UNIX) && defined(HAVE_FCHOWN)
+ if (tempname != NULL && fp_out != NULL)
+ {
+ stat_T tmp_st;
+
+ /*
+ * Make sure the original owner can read/write the tempfile and
+ * otherwise preserve permissions, making sure the group matches.
+ */
+ if (mch_stat((char *)tempname, &tmp_st) >= 0)
+ {
+ if (st_old.st_uid != tmp_st.st_uid)
+ /* Changing the owner might fail, in which case the
+ * file will now owned by the current user, oh well. */
+ vim_ignored = fchown(fileno(fp_out), st_old.st_uid, -1);
+ if (st_old.st_gid != tmp_st.st_gid
+ && fchown(fileno(fp_out), -1, st_old.st_gid) == -1)
+ /* can't set the group to what it should be, remove
+ * group permissions */
+ (void)mch_setperm(tempname, 0600);
+ }
+ else
+ /* can't stat the file, set conservative permissions */
+ (void)mch_setperm(tempname, 0600);
+ }
+#endif
+ }
+
+ /*
+ * Check if the new viminfo file can be written to.
+ */
+ if (fp_out == NULL)
+ {
+ semsg(_("E138: Can't write viminfo file %s!"),
+ (fp_in == NULL || tempname == NULL) ? fname : tempname);
+ if (fp_in != NULL)
+ fclose(fp_in);
+ goto end;
+ }
+
+ if (p_verbose > 0)
+ {
+ verbose_enter();
+ smsg(_("Writing viminfo file \"%s\""), fname);
+ verbose_leave();
+ }
+
+ viminfo_errcnt = 0;
+ do_viminfo(fp_in, fp_out, forceit ? 0 : (VIF_WANT_INFO | VIF_WANT_MARKS));
+
+ if (fclose(fp_out) == EOF)
+ ++viminfo_errcnt;
+
+ if (fp_in != NULL)
+ {
+ fclose(fp_in);
+
+ /* In case of an error keep the original viminfo file. Otherwise
+ * rename the newly written file. Give an error if that fails. */
+ if (viminfo_errcnt == 0)
+ {
+ if (vim_rename(tempname, fname) == -1)
+ {
+ ++viminfo_errcnt;
+ semsg(_("E886: Can't rename viminfo file to %s!"), fname);
+ }
+# ifdef WIN3264
+ /* If the viminfo file was hidden then also hide the new file. */
+ else if (hidden)
+ mch_hide(fname);
+# endif
+ }
+ if (viminfo_errcnt > 0)
+ mch_remove(tempname);
+ }
+
+end:
+ vim_free(fname);
+ vim_free(tempname);
+}
+
+/*
+ * Get the viminfo file name to use.
+ * If "file" is given and not empty, use it (has already been expanded by
+ * cmdline functions).
+ * Otherwise use "-i file_name", value from 'viminfo' or the default, and
+ * expand environment variables.
+ * Returns an allocated string. NULL when out of memory.
+ */
+ static char_u *
+viminfo_filename(char_u *file)
+{
+ if (file == NULL || *file == NUL)
+ {
+ if (*p_viminfofile != NUL)
+ file = p_viminfofile;
+ else if ((file = find_viminfo_parameter('n')) == NULL || *file == NUL)
+ {
+#ifdef VIMINFO_FILE2
+# ifdef VMS
+ if (mch_getenv((char_u *)"SYS$LOGIN") == NULL)
+# else
+# ifdef MSWIN
+ /* Use $VIM only if $HOME is the default "C:/". */
+ if (STRCMP(vim_getenv((char_u *)"HOME", NULL), "C:/") == 0
+ && mch_getenv((char_u *)"HOME") == NULL)
+# else
+ if (mch_getenv((char_u *)"HOME") == NULL)
+# endif
+# endif
+ {
+ /* don't use $VIM when not available. */
+ expand_env((char_u *)"$VIM", NameBuff, MAXPATHL);
+ if (STRCMP("$VIM", NameBuff) != 0) /* $VIM was expanded */
+ file = (char_u *)VIMINFO_FILE2;
+ else
+ file = (char_u *)VIMINFO_FILE;
+ }
+ else
+#endif
+ file = (char_u *)VIMINFO_FILE;
+ }
+ expand_env(file, NameBuff, MAXPATHL);
+ file = NameBuff;
+ }
+ return vim_strsave(file);
+}
+
+/*
+ * do_viminfo() -- Should only be called from read_viminfo() & write_viminfo().
+ */
+ static void
+do_viminfo(FILE *fp_in, FILE *fp_out, int flags)
+{
+ int eof = FALSE;
+ vir_T vir;
+ int merge = FALSE;
+ int do_copy_marks = FALSE;
+ garray_T buflist;
+
+ if ((vir.vir_line = alloc(LSIZE)) == NULL)
+ return;
+ vir.vir_fd = fp_in;
+ vir.vir_conv.vc_type = CONV_NONE;
+ ga_init2(&vir.vir_barlines, (int)sizeof(char_u *), 100);
+ vir.vir_version = -1;
+
+ if (fp_in != NULL)
+ {
+ if (flags & VIF_WANT_INFO)
+ {
+ if (fp_out != NULL)
+ {
+ /* Registers and marks are read and kept separate from what
+ * this Vim is using. They are merged when writing. */
+ prepare_viminfo_registers();
+ prepare_viminfo_marks();
+ }
+
+ eof = read_viminfo_up_to_marks(&vir,
+ flags & VIF_FORCEIT, fp_out != NULL);
+ merge = TRUE;
+ }
+ else if (flags != 0)
+ /* Skip info, find start of marks */
+ while (!(eof = viminfo_readline(&vir))
+ && vir.vir_line[0] != '>')
+ ;
+
+ do_copy_marks = (flags &
+ (VIF_WANT_MARKS | VIF_GET_OLDFILES | VIF_FORCEIT));
+ }
+
+ if (fp_out != NULL)
+ {
+ /* Write the info: */
+ fprintf(fp_out, _("# This viminfo file was generated by Vim %s.\n"),
+ VIM_VERSION_MEDIUM);
+ fputs(_("# You may edit it if you're careful!\n\n"), fp_out);
+ write_viminfo_version(fp_out);
+ fputs(_("# Value of 'encoding' when this file was written\n"), fp_out);
+ fprintf(fp_out, "*encoding=%s\n\n", p_enc);
+ write_viminfo_search_pattern(fp_out);
+ write_viminfo_sub_string(fp_out);
+#ifdef FEAT_CMDHIST
+ write_viminfo_history(fp_out, merge);
+#endif
+ write_viminfo_registers(fp_out);
+ finish_viminfo_registers();
+#ifdef FEAT_EVAL
+ write_viminfo_varlist(fp_out);
+#endif
+ write_viminfo_filemarks(fp_out);
+ finish_viminfo_marks();
+ write_viminfo_bufferlist(fp_out);
+ write_viminfo_barlines(&vir, fp_out);
+
+ if (do_copy_marks)
+ ga_init2(&buflist, sizeof(buf_T *), 50);
+ write_viminfo_marks(fp_out, do_copy_marks ? &buflist : NULL);
+ }
+
+ if (do_copy_marks)
+ {
+ copy_viminfo_marks(&vir, fp_out, &buflist, eof, flags);
+ if (fp_out != NULL)
+ ga_clear(&buflist);
+ }
+
+ vim_free(vir.vir_line);
+ if (vir.vir_conv.vc_type != CONV_NONE)
+ convert_setup(&vir.vir_conv, NULL, NULL);
+ ga_clear_strings(&vir.vir_barlines);
+}
+
+/*
+ * read_viminfo_up_to_marks() -- Only called from do_viminfo(). Reads in the
+ * first part of the viminfo file which contains everything but the marks that
+ * are local to a file. Returns TRUE when end-of-file is reached. -- webb
+ */
+ static int
+read_viminfo_up_to_marks(
+ vir_T *virp,
+ int forceit,
+ int writing)
+{
+ int eof;
+ buf_T *buf;
+ int got_encoding = FALSE;
+
+#ifdef FEAT_CMDHIST
+ prepare_viminfo_history(forceit ? 9999 : 0, writing);
+#endif
+
+ eof = viminfo_readline(virp);
+ while (!eof && virp->vir_line[0] != '>')
+ {
+ switch (virp->vir_line[0])
+ {
+ /* Characters reserved for future expansion, ignored now */
+ case '+': /* "+40 /path/dir file", for running vim without args */
+ case '^': /* to be defined */
+ case '<': /* long line - ignored */
+ /* A comment or empty line. */
+ case NUL:
+ case '\r':
+ case '\n':
+ case '#':
+ eof = viminfo_readline(virp);
+ break;
+ case '|':
+ eof = read_viminfo_barline(virp, got_encoding,
+ forceit, writing);
+ break;
+ case '*': /* "*encoding=value" */
+ got_encoding = TRUE;
+ eof = viminfo_encoding(virp);
+ break;
+ case '!': /* global variable */
+#ifdef FEAT_EVAL
+ eof = read_viminfo_varlist(virp, writing);
+#else
+ eof = viminfo_readline(virp);
+#endif
+ break;
+ case '%': /* entry for buffer list */
+ eof = read_viminfo_bufferlist(virp, writing);
+ break;
+ case '"':
+ /* When registers are in bar lines skip the old style register
+ * lines. */
+ if (virp->vir_version < VIMINFO_VERSION_WITH_REGISTERS)
+ eof = read_viminfo_register(virp, forceit);
+ else
+ do {
+ eof = viminfo_readline(virp);
+ } while (!eof && (virp->vir_line[0] == TAB
+ || virp->vir_line[0] == '<'));
+ break;
+ case '/': /* Search string */
+ case '&': /* Substitute search string */
+ case '~': /* Last search string, followed by '/' or '&' */
+ eof = read_viminfo_search_pattern(virp, forceit);
+ break;
+ case '$':
+ eof = read_viminfo_sub_string(virp, forceit);
+ break;
+ case ':':
+ case '?':
+ case '=':
+ case '@':
+#ifdef FEAT_CMDHIST
+ /* When history is in bar lines skip the old style history
+ * lines. */
+ if (virp->vir_version < VIMINFO_VERSION_WITH_HISTORY)
+ eof = read_viminfo_history(virp, writing);
+ else
+#endif
+ eof = viminfo_readline(virp);
+ break;
+ case '-':
+ case '\'':
+ /* When file marks are in bar lines skip the old style lines. */
+ if (virp->vir_version < VIMINFO_VERSION_WITH_MARKS)
+ eof = read_viminfo_filemark(virp, forceit);
+ else
+ eof = viminfo_readline(virp);
+ break;
+ default:
+ if (viminfo_error("E575: ", _("Illegal starting char"),
+ virp->vir_line))
+ eof = TRUE;
+ else
+ eof = viminfo_readline(virp);
+ break;
+ }
+ }
+
+#ifdef FEAT_CMDHIST
+ /* Finish reading history items. */
+ if (!writing)
+ finish_viminfo_history(virp);
+#endif
+
+ /* Change file names to buffer numbers for fmarks. */
+ FOR_ALL_BUFFERS(buf)
+ fmarks_check_names(buf);
+
+ return eof;
+}
+
+/*
+ * Compare the 'encoding' value in the viminfo file with the current value of
+ * 'encoding'. If different and the 'c' flag is in 'viminfo', setup for
+ * conversion of text with iconv() in viminfo_readstring().
+ */
+ static int
+viminfo_encoding(vir_T *virp)
+{
+ char_u *p;
+ int i;
+
+ if (get_viminfo_parameter('c') != 0)
+ {
+ p = vim_strchr(virp->vir_line, '=');
+ if (p != NULL)
+ {
+ /* remove trailing newline */
+ ++p;
+ for (i = 0; vim_isprintc(p[i]); ++i)
+ ;
+ p[i] = NUL;
+
+ convert_setup(&virp->vir_conv, p, p_enc);
+ }
+ }
+ return viminfo_readline(virp);
+}
+
+/*
+ * Read a line from the viminfo file.
+ * Returns TRUE for end-of-file;
+ */
+ int
+viminfo_readline(vir_T *virp)
+{
+ return vim_fgets(virp->vir_line, LSIZE, virp->vir_fd);
+}
+
+/*
+ * Check string read from viminfo file.
+ * Remove '\n' at the end of the line.
+ * - replace CTRL-V CTRL-V with CTRL-V
+ * - replace CTRL-V 'n' with '\n'
+ *
+ * Check for a long line as written by viminfo_writestring().
+ *
+ * Return the string in allocated memory (NULL when out of memory).
+ */
+ char_u *
+viminfo_readstring(
+ vir_T *virp,
+ int off, /* offset for virp->vir_line */
+ int convert UNUSED) /* convert the string */
+{
+ char_u *retval;
+ char_u *s, *d;
+ long len;
+
+ if (virp->vir_line[off] == Ctrl_V && vim_isdigit(virp->vir_line[off + 1]))
+ {
+ len = atol((char *)virp->vir_line + off + 1);
+ retval = lalloc(len, TRUE);
+ if (retval == NULL)
+ {
+ /* Line too long? File messed up? Skip next line. */
+ (void)vim_fgets(virp->vir_line, 10, virp->vir_fd);
+ return NULL;
+ }
+ (void)vim_fgets(retval, (int)len, virp->vir_fd);
+ s = retval + 1; /* Skip the leading '<' */
+ }
+ else
+ {
+ retval = vim_strsave(virp->vir_line + off);
+ if (retval == NULL)
+ return NULL;
+ s = retval;
+ }
+
+ /* Change CTRL-V CTRL-V to CTRL-V and CTRL-V n to \n in-place. */
+ d = retval;
+ while (*s != NUL && *s != '\n')
+ {
+ if (s[0] == Ctrl_V && s[1] != NUL)
+ {
+ if (s[1] == 'n')
+ *d++ = '\n';
+ else
+ *d++ = Ctrl_V;
+ s += 2;
+ }
+ else
+ *d++ = *s++;
+ }
+ *d = NUL;
+
+ if (convert && virp->vir_conv.vc_type != CONV_NONE && *retval != NUL)
+ {
+ d = string_convert(&virp->vir_conv, retval, NULL);
+ if (d != NULL)
+ {
+ vim_free(retval);
+ retval = d;
+ }
+ }
+
+ return retval;
+}
+
+/*
+ * write string to viminfo file
+ * - replace CTRL-V with CTRL-V CTRL-V
+ * - replace '\n' with CTRL-V 'n'
+ * - add a '\n' at the end
+ *
+ * For a long line:
+ * - write " CTRL-V <length> \n " in first line
+ * - write " < <string> \n " in second line
+ */
+ void
+viminfo_writestring(FILE *fd, char_u *p)
+{
+ int c;
+ char_u *s;
+ int len = 0;
+
+ for (s = p; *s != NUL; ++s)
+ {
+ if (*s == Ctrl_V || *s == '\n')
+ ++len;
+ ++len;
+ }
+
+ /* If the string will be too long, write its length and put it in the next
+ * line. Take into account that some room is needed for what comes before
+ * the string (e.g., variable name). Add something to the length for the
+ * '<', NL and trailing NUL. */
+ if (len > LSIZE / 2)
+ fprintf(fd, IF_EB("\026%d\n<", CTRL_V_STR "%d\n<"), len + 3);
+
+ while ((c = *p++) != NUL)
+ {
+ if (c == Ctrl_V || c == '\n')
+ {
+ putc(Ctrl_V, fd);
+ if (c == '\n')
+ c = 'n';
+ }
+ putc(c, fd);
+ }
+ putc('\n', fd);
+}
+
+/*
+ * Write a string in quotes that barline_parse() can read back.
+ * Breaks the line in less than LSIZE pieces when needed.
+ * Returns remaining characters in the line.
+ */
+ int
+barline_writestring(FILE *fd, char_u *s, int remaining_start)
+{
+ char_u *p;
+ int remaining = remaining_start;
+ int len = 2;
+
+ /* Count the number of characters produced, including quotes. */
+ for (p = s; *p != NUL; ++p)
+ {
+ if (*p == NL)
+ len += 2;
+ else if (*p == '"' || *p == '\\')
+ len += 2;
+ else
+ ++len;
+ }
+ if (len > remaining - 2)
+ {
+ fprintf(fd, ">%d\n|<", len);
+ remaining = LSIZE - 20;
+ }
+
+ putc('"', fd);
+ for (p = s; *p != NUL; ++p)
+ {
+ if (*p == NL)
+ {
+ putc('\\', fd);
+ putc('n', fd);
+ --remaining;
+ }
+ else if (*p == '"' || *p == '\\')
+ {
+ putc('\\', fd);
+ putc(*p, fd);
+ --remaining;
+ }
+ else
+ putc(*p, fd);
+ --remaining;
+
+ if (remaining < 3)
+ {
+ putc('\n', fd);
+ putc('|', fd);
+ putc('<', fd);
+ /* Leave enough space for another continuation. */
+ remaining = LSIZE - 20;
+ }
+ }
+ putc('"', fd);
+ return remaining - 2;
+}
+
+/*
+ * Parse a viminfo line starting with '|'.
+ * Add each decoded value to "values".
+ * Returns TRUE if the next line is to be read after using the parsed values.
+ */
+ static int
+barline_parse(vir_T *virp, char_u *text, garray_T *values)
+{
+ char_u *p = text;
+ char_u *nextp = NULL;
+ char_u *buf = NULL;
+ bval_T *value;
+ int i;
+ int allocated = FALSE;
+ int eof;
+ char_u *sconv;
+ int converted;
+
+ while (*p == ',')
+ {
+ ++p;
+ if (ga_grow(values, 1) == FAIL)
+ break;
+ value = (bval_T *)(values->ga_data) + values->ga_len;
+
+ if (*p == '>')
+ {
+ /* Need to read a continuation line. Put strings in allocated
+ * memory, because virp->vir_line is overwritten. */
+ if (!allocated)
+ {
+ for (i = 0; i < values->ga_len; ++i)
+ {
+ bval_T *vp = (bval_T *)(values->ga_data) + i;
+
+ if (vp->bv_type == BVAL_STRING && !vp->bv_allocated)
+ {
+ vp->bv_string = vim_strnsave(vp->bv_string, vp->bv_len);
+ vp->bv_allocated = TRUE;
+ }
+ }
+ allocated = TRUE;
+ }
+
+ if (vim_isdigit(p[1]))
+ {
+ size_t len;
+ size_t todo;
+ size_t n;
+
+ /* String value was split into lines that are each shorter
+ * than LSIZE:
+ * |{bartype},>{length of "{text}{text2}"}
+ * |<"{text1}
+ * |<{text2}",{value}
+ * Length includes the quotes.
+ */
+ ++p;
+ len = getdigits(&p);
+ buf = alloc((int)(len + 1));
+ if (buf == NULL)
+ return TRUE;
+ p = buf;
+ for (todo = len; todo > 0; todo -= n)
+ {
+ eof = viminfo_readline(virp);
+ if (eof || virp->vir_line[0] != '|'
+ || virp->vir_line[1] != '<')
+ {
+ /* File was truncated or garbled. Read another line if
+ * this one starts with '|'. */
+ vim_free(buf);
+ return eof || virp->vir_line[0] == '|';
+ }
+ /* Get length of text, excluding |< and NL chars. */
+ n = STRLEN(virp->vir_line);
+ while (n > 0 && (virp->vir_line[n - 1] == NL
+ || virp->vir_line[n - 1] == CAR))
+ --n;
+ n -= 2;
+ if (n > todo)
+ {
+ /* more values follow after the string */
+ nextp = virp->vir_line + 2 + todo;
+ n = todo;
+ }
+ mch_memmove(p, virp->vir_line + 2, n);
+ p += n;
+ }
+ *p = NUL;
+ p = buf;
+ }
+ else
+ {
+ /* Line ending in ">" continues in the next line:
+ * |{bartype},{lots of values},>
+ * |<{value},{value}
+ */
+ eof = viminfo_readline(virp);
+ if (eof || virp->vir_line[0] != '|'
+ || virp->vir_line[1] != '<')
+ /* File was truncated or garbled. Read another line if
+ * this one starts with '|'. */
+ return eof || virp->vir_line[0] == '|';
+ p = virp->vir_line + 2;
+ }
+ }
+
+ if (isdigit(*p))
+ {
+ value->bv_type = BVAL_NR;
+ value->bv_nr = getdigits(&p);
+ ++values->ga_len;
+ }
+ else if (*p == '"')
+ {
+ int len = 0;
+ char_u *s = p;
+
+ /* Unescape special characters in-place. */
+ ++p;
+ while (*p != '"')
+ {
+ if (*p == NL || *p == NUL)
+ return TRUE; /* syntax error, drop the value */
+ if (*p == '\\')
+ {
+ ++p;
+ if (*p == 'n')
+ s[len++] = '\n';
+ else
+ s[len++] = *p;
+ ++p;
+ }
+ else
+ s[len++] = *p++;
+ }
+ ++p;
+ s[len] = NUL;
+
+ converted = FALSE;
+ if (virp->vir_conv.vc_type != CONV_NONE && *s != NUL)
+ {
+ sconv = string_convert(&virp->vir_conv, s, NULL);
+ if (sconv != NULL)
+ {
+ if (s == buf)
+ vim_free(s);
+ s = sconv;
+ buf = s;
+ converted = TRUE;
+ }
+ }
+
+ /* Need to copy in allocated memory if the string wasn't allocated
+ * above and we did allocate before, thus vir_line may change. */
+ if (s != buf && allocated)
+ s = vim_strsave(s);
+ value->bv_string = s;
+ value->bv_type = BVAL_STRING;
+ value->bv_len = len;
+ value->bv_allocated = allocated || converted;
+ ++values->ga_len;
+ if (nextp != NULL)
+ {
+ /* values following a long string */
+ p = nextp;
+ nextp = NULL;
+ }
+ }
+ else if (*p == ',')
+ {
+ value->bv_type = BVAL_EMPTY;
+ ++values->ga_len;
+ }
+ else
+ break;
+ }
+ return TRUE;
+}
+
+ static int
+read_viminfo_barline(vir_T *virp, int got_encoding, int force, int writing)
+{
+ char_u *p = virp->vir_line + 1;
+ int bartype;
+ garray_T values;
+ bval_T *vp;
+ int i;
+ int read_next = TRUE;
+
+ /* The format is: |{bartype},{value},...
+ * For a very long string:
+ * |{bartype},>{length of "{text}{text2}"}
+ * |<{text1}
+ * |<{text2},{value}
+ * For a long line not using a string
+ * |{bartype},{lots of values},>
+ * |<{value},{value}
+ */
+ if (*p == '<')
+ {
+ /* Continuation line of an unrecognized item. */
+ if (writing)
+ ga_add_string(&virp->vir_barlines, virp->vir_line);
+ }
+ else
+ {
+ ga_init2(&values, sizeof(bval_T), 20);
+ bartype = getdigits(&p);
+ switch (bartype)
+ {
+ case BARTYPE_VERSION:
+ /* Only use the version when it comes before the encoding.
+ * If it comes later it was copied by a Vim version that
+ * doesn't understand the version. */
+ if (!got_encoding)
+ {
+ read_next = barline_parse(virp, p, &values);
+ vp = (bval_T *)values.ga_data;
+ if (values.ga_len > 0 && vp->bv_type == BVAL_NR)
+ virp->vir_version = vp->bv_nr;
+ }
+ break;
+
+ case BARTYPE_HISTORY:
+ read_next = barline_parse(virp, p, &values);
+ handle_viminfo_history(&values, writing);
+ break;
+
+ case BARTYPE_REGISTER:
+ read_next = barline_parse(virp, p, &values);
+ handle_viminfo_register(&values, force);
+ break;
+
+ case BARTYPE_MARK:
+ read_next = barline_parse(virp, p, &values);
+ handle_viminfo_mark(&values, force);
+ break;
+
+ default:
+ /* copy unrecognized line (for future use) */
+ if (writing)
+ ga_add_string(&virp->vir_barlines, virp->vir_line);
+ }
+ for (i = 0; i < values.ga_len; ++i)
+ {
+ vp = (bval_T *)values.ga_data + i;
+ if (vp->bv_type == BVAL_STRING && vp->bv_allocated)
+ vim_free(vp->bv_string);
+ }
+ ga_clear(&values);
+ }
+
+ if (read_next)
+ return viminfo_readline(virp);
+ return FALSE;
+}
+
+ static void
+write_viminfo_version(FILE *fp_out)
+{
+ fprintf(fp_out, "# Viminfo version\n|%d,%d\n\n",
+ BARTYPE_VERSION, VIMINFO_VERSION);
+}
+
+ static void
+write_viminfo_barlines(vir_T *virp, FILE *fp_out)
+{
+ int i;
+ garray_T *gap = &virp->vir_barlines;
+ int seen_useful = FALSE;
+ char *line;
+
+ if (gap->ga_len > 0)
+ {
+ fputs(_("\n# Bar lines, copied verbatim:\n"), fp_out);
+
+ /* Skip over continuation lines until seeing a useful line. */
+ for (i = 0; i < gap->ga_len; ++i)
+ {
+ line = ((char **)(gap->ga_data))[i];
+ if (seen_useful || line[1] != '<')
+ {
+ fputs(line, fp_out);
+ seen_useful = TRUE;
+ }
+ }
+ }
+}
+#endif /* FEAT_VIMINFO */
+
+/*
+ * Return the current time in seconds. Calls time(), unless test_settime()
+ * was used.
+ */
+ time_T
+vim_time(void)
+{
+# ifdef FEAT_EVAL
+ return time_for_testing == 0 ? time(NULL) : time_for_testing;
+# else
+ return time(NULL);
+# endif
+}
+
+/*
+ * Implementation of ":fixdel", also used by get_stty().
+ * <BS> resulting <Del>
+ * ^? ^H
+ * not ^? ^?
+ */
+ void
+do_fixdel(exarg_T *eap UNUSED)
+{
+ char_u *p;
+
+ p = find_termcode((char_u *)"kb");
+ add_termcode((char_u *)"kD", p != NULL
+ && *p == DEL ? (char_u *)CTRL_H_STR : DEL_STR, FALSE);
+}
+
+ void
+print_line_no_prefix(
+ linenr_T lnum,
+ int use_number,
+ int list)
+{
+ char numbuf[30];
+
+ if (curwin->w_p_nu || use_number)
+ {
+ vim_snprintf(numbuf, sizeof(numbuf),
+ "%*ld ", number_width(curwin), (long)lnum);
+ msg_puts_attr(numbuf, HL_ATTR(HLF_N)); /* Highlight line nrs */
+ }
+ msg_prt_line(ml_get(lnum), list);
+}
+
+/*
+ * Print a text line. Also in silent mode ("ex -s").
+ */
+ void
+print_line(linenr_T lnum, int use_number, int list)
+{
+ int save_silent = silent_mode;
+
+ /* apply :filter /pat/ */
+ if (message_filtered(ml_get(lnum)))
+ return;
+
+ msg_start();
+ silent_mode = FALSE;
+ info_message = TRUE; /* use mch_msg(), not mch_errmsg() */
+ print_line_no_prefix(lnum, use_number, list);
+ if (save_silent)
+ {
+ msg_putchar('\n');
+ cursor_on(); /* msg_start() switches it off */
+ out_flush();
+ silent_mode = save_silent;
+ }
+ info_message = FALSE;
+}
+
+ int
+rename_buffer(char_u *new_fname)
+{
+ char_u *fname, *sfname, *xfname;
+ buf_T *buf;
+
+ buf = curbuf;
+ apply_autocmds(EVENT_BUFFILEPRE, NULL, NULL, FALSE, curbuf);
+ /* buffer changed, don't change name now */
+ if (buf != curbuf)
+ return FAIL;
+#ifdef FEAT_EVAL
+ if (aborting()) /* autocmds may abort script processing */
+ return FAIL;
+#endif
+ /*
+ * The name of the current buffer will be changed.
+ * A new (unlisted) buffer entry needs to be made to hold the old file
+ * name, which will become the alternate file name.
+ * But don't set the alternate file name if the buffer didn't have a
+ * name.
+ */
+ fname = curbuf->b_ffname;
+ sfname = curbuf->b_sfname;
+ xfname = curbuf->b_fname;
+ curbuf->b_ffname = NULL;
+ curbuf->b_sfname = NULL;
+ if (setfname(curbuf, new_fname, NULL, TRUE) == FAIL)
+ {
+ curbuf->b_ffname = fname;
+ curbuf->b_sfname = sfname;
+ return FAIL;
+ }
+ curbuf->b_flags |= BF_NOTEDITED;
+ if (xfname != NULL && *xfname != NUL)
+ {
+ buf = buflist_new(fname, xfname, curwin->w_cursor.lnum, 0);
+ if (buf != NULL && !cmdmod.keepalt)
+ curwin->w_alt_fnum = buf->b_fnum;
+ }
+ vim_free(fname);
+ vim_free(sfname);
+ apply_autocmds(EVENT_BUFFILEPOST, NULL, NULL, FALSE, curbuf);
+
+ /* Change directories when the 'acd' option is set. */
+ DO_AUTOCHDIR;
+ return OK;
+}
+
+/*
+ * ":file[!] [fname]".
+ */
+ void
+ex_file(exarg_T *eap)
+{
+ /* ":0file" removes the file name. Check for illegal uses ":3file",
+ * "0file name", etc. */
+ if (eap->addr_count > 0
+ && (*eap->arg != NUL
+ || eap->line2 > 0
+ || eap->addr_count > 1))
+ {
+ emsg(_(e_invarg));
+ return;
+ }
+
+ if (*eap->arg != NUL || eap->addr_count == 1)
+ {
+ if (rename_buffer(eap->arg) == FAIL)
+ return;
+ redraw_tabline = TRUE;
+ }
+
+ // print file name if no argument or 'F' is not in 'shortmess'
+ if (*eap->arg == NUL || !shortmess(SHM_FILEINFO))
+ fileinfo(FALSE, FALSE, eap->forceit);
+}
+
+/*
+ * ":update".
+ */
+ void
+ex_update(exarg_T *eap)
+{
+ if (curbufIsChanged())
+ (void)do_write(eap);
+}
+
+/*
+ * ":write" and ":saveas".
+ */
+ void
+ex_write(exarg_T *eap)
+{
+ if (eap->usefilter) /* input lines to shell command */
+ do_bang(1, eap, FALSE, TRUE, FALSE);
+ else
+ (void)do_write(eap);
+}
+
+/*
+ * write current buffer to file 'eap->arg'
+ * if 'eap->append' is TRUE, append to the file
+ *
+ * if *eap->arg == NUL write to current file
+ *
+ * return FAIL for failure, OK otherwise
+ */
+ int
+do_write(exarg_T *eap)
+{
+ int other;
+ char_u *fname = NULL; /* init to shut up gcc */
+ char_u *ffname;
+ int retval = FAIL;
+ char_u *free_fname = NULL;
+#ifdef FEAT_BROWSE
+ char_u *browse_file = NULL;
+#endif
+ buf_T *alt_buf = NULL;
+ int name_was_missing;
+
+ if (not_writing()) /* check 'write' option */
+ return FAIL;
+
+ ffname = eap->arg;
+#ifdef FEAT_BROWSE
+ if (cmdmod.browse)
+ {
+ browse_file = do_browse(BROWSE_SAVE, (char_u *)_("Save As"), ffname,
+ NULL, NULL, NULL, curbuf);
+ if (browse_file == NULL)
+ goto theend;
+ ffname = browse_file;
+ }
+#endif
+ if (*ffname == NUL)
+ {
+ if (eap->cmdidx == CMD_saveas)
+ {
+ emsg(_(e_argreq));
+ goto theend;
+ }
+ other = FALSE;
+ }
+ else
+ {
+ fname = ffname;
+ free_fname = fix_fname(ffname);
+ /*
+ * When out-of-memory, keep unexpanded file name, because we MUST be
+ * able to write the file in this situation.
+ */
+ if (free_fname != NULL)
+ ffname = free_fname;
+ other = otherfile(ffname);
+ }
+
+ /*
+ * If we have a new file, put its name in the list of alternate file names.
+ */
+ if (other)
+ {
+ if (vim_strchr(p_cpo, CPO_ALTWRITE) != NULL
+ || eap->cmdidx == CMD_saveas)
+ alt_buf = setaltfname(ffname, fname, (linenr_T)1);
+ else
+ alt_buf = buflist_findname(ffname);
+ if (alt_buf != NULL && alt_buf->b_ml.ml_mfp != NULL)
+ {
+ /* Overwriting a file that is loaded in another buffer is not a
+ * good idea. */
+ emsg(_(e_bufloaded));
+ goto theend;
+ }
+ }
+
+ /*
+ * Writing to the current file is not allowed in readonly mode
+ * and a file name is required.
+ * "nofile" and "nowrite" buffers cannot be written implicitly either.
+ */
+ if (!other && (
+#ifdef FEAT_QUICKFIX
+ bt_dontwrite_msg(curbuf) ||
+#endif
+ check_fname() == FAIL || check_readonly(&eap->forceit, curbuf)))
+ goto theend;
+
+ if (!other)
+ {
+ ffname = curbuf->b_ffname;
+ fname = curbuf->b_fname;
+ /*
+ * Not writing the whole file is only allowed with '!'.
+ */
+ if ( (eap->line1 != 1
+ || eap->line2 != curbuf->b_ml.ml_line_count)
+ && !eap->forceit
+ && !eap->append
+ && !p_wa)
+ {
+#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
+ if (p_confirm || cmdmod.confirm)
+ {
+ if (vim_dialog_yesno(VIM_QUESTION, NULL,
+ (char_u *)_("Write partial file?"), 2) != VIM_YES)
+ goto theend;
+ eap->forceit = TRUE;
+ }
+ else
+#endif
+ {
+ emsg(_("E140: Use ! to write partial buffer"));
+ goto theend;
+ }
+ }
+ }
+
+ if (check_overwrite(eap, curbuf, fname, ffname, other) == OK)
+ {
+ if (eap->cmdidx == CMD_saveas && alt_buf != NULL)
+ {
+ buf_T *was_curbuf = curbuf;
+
+ apply_autocmds(EVENT_BUFFILEPRE, NULL, NULL, FALSE, curbuf);
+ apply_autocmds(EVENT_BUFFILEPRE, NULL, NULL, FALSE, alt_buf);
+#ifdef FEAT_EVAL
+ if (curbuf != was_curbuf || aborting())
+#else
+ if (curbuf != was_curbuf)
+#endif
+ {
+ /* buffer changed, don't change name now */
+ retval = FAIL;
+ goto theend;
+ }
+ /* Exchange the file names for the current and the alternate
+ * buffer. This makes it look like we are now editing the buffer
+ * under the new name. Must be done before buf_write(), because
+ * if there is no file name and 'cpo' contains 'F', it will set
+ * the file name. */
+ fname = alt_buf->b_fname;
+ alt_buf->b_fname = curbuf->b_fname;
+ curbuf->b_fname = fname;
+ fname = alt_buf->b_ffname;
+ alt_buf->b_ffname = curbuf->b_ffname;
+ curbuf->b_ffname = fname;
+ fname = alt_buf->b_sfname;
+ alt_buf->b_sfname = curbuf->b_sfname;
+ curbuf->b_sfname = fname;
+ buf_name_changed(curbuf);
+
+ apply_autocmds(EVENT_BUFFILEPOST, NULL, NULL, FALSE, curbuf);
+ apply_autocmds(EVENT_BUFFILEPOST, NULL, NULL, FALSE, alt_buf);
+ if (!alt_buf->b_p_bl)
+ {
+ alt_buf->b_p_bl = TRUE;
+ apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, alt_buf);
+ }
+#ifdef FEAT_EVAL
+ if (curbuf != was_curbuf || aborting())
+#else
+ if (curbuf != was_curbuf)
+#endif
+ {
+ /* buffer changed, don't write the file */
+ retval = FAIL;
+ goto theend;
+ }
+
+ /* If 'filetype' was empty try detecting it now. */
+ if (*curbuf->b_p_ft == NUL)
+ {
+ if (au_has_group((char_u *)"filetypedetect"))
+ (void)do_doautocmd((char_u *)"filetypedetect BufRead",
+ TRUE, NULL);
+ do_modelines(0);
+ }
+
+ /* Autocommands may have changed buffer names, esp. when
+ * 'autochdir' is set. */
+ fname = curbuf->b_sfname;
+ }
+
+ name_was_missing = curbuf->b_ffname == NULL;
+
+ retval = buf_write(curbuf, ffname, fname, eap->line1, eap->line2,
+ eap, eap->append, eap->forceit, TRUE, FALSE);
+
+ /* After ":saveas fname" reset 'readonly'. */
+ if (eap->cmdidx == CMD_saveas)
+ {
+ if (retval == OK)
+ {
+ curbuf->b_p_ro = FALSE;
+ redraw_tabline = TRUE;
+ }
+ }
+
+ /* Change directories when the 'acd' option is set and the file name
+ * got changed or set. */
+ if (eap->cmdidx == CMD_saveas || name_was_missing)
+ {
+ DO_AUTOCHDIR;
+ }
+ }
+
+theend:
+#ifdef FEAT_BROWSE
+ vim_free(browse_file);
+#endif
+ vim_free(free_fname);
+ return retval;
+}
+
+/*
+ * Check if it is allowed to overwrite a file. If b_flags has BF_NOTEDITED,
+ * BF_NEW or BF_READERR, check for overwriting current file.
+ * May set eap->forceit if a dialog says it's OK to overwrite.
+ * Return OK if it's OK, FAIL if it is not.
+ */
+ int
+check_overwrite(
+ exarg_T *eap,
+ buf_T *buf,
+ char_u *fname, /* file name to be used (can differ from
+ buf->ffname) */
+ char_u *ffname, /* full path version of fname */
+ int other) /* writing under other name */
+{
+ /*
+ * write to other file or b_flags set or not writing the whole file:
+ * overwriting only allowed with '!'
+ */
+ if ( (other
+ || (buf->b_flags & BF_NOTEDITED)
+ || ((buf->b_flags & BF_NEW)
+ && vim_strchr(p_cpo, CPO_OVERNEW) == NULL)
+ || (buf->b_flags & BF_READERR))
+ && !p_wa
+#ifdef FEAT_QUICKFIX
+ && !bt_nofile(buf)
+#endif
+ && vim_fexists(ffname))
+ {
+ if (!eap->forceit && !eap->append)
+ {
+#ifdef UNIX
+ /* with UNIX it is possible to open a directory */
+ if (mch_isdir(ffname))
+ {
+ semsg(_(e_isadir2), ffname);
+ return FAIL;
+ }
+#endif
+#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
+ if (p_confirm || cmdmod.confirm)
+ {
+ char_u buff[DIALOG_MSG_SIZE];
+
+ dialog_msg(buff, _("Overwrite existing file \"%s\"?"), fname);
+ if (vim_dialog_yesno(VIM_QUESTION, NULL, buff, 2) != VIM_YES)
+ return FAIL;
+ eap->forceit = TRUE;
+ }
+ else
+#endif
+ {
+ emsg(_(e_exists));
+ return FAIL;
+ }
+ }
+
+ /* For ":w! filename" check that no swap file exists for "filename". */
+ if (other && !emsg_silent)
+ {
+ char_u *dir;
+ char_u *p;
+ int r;
+ char_u *swapname;
+
+ /* We only try the first entry in 'directory', without checking if
+ * it's writable. If the "." directory is not writable the write
+ * will probably fail anyway.
+ * Use 'shortname' of the current buffer, since there is no buffer
+ * for the written file. */
+ if (*p_dir == NUL)
+ {
+ dir = alloc(5);
+ if (dir == NULL)
+ return FAIL;
+ STRCPY(dir, ".");
+ }
+ else
+ {
+ dir = alloc(MAXPATHL);
+ if (dir == NULL)
+ return FAIL;
+ p = p_dir;
+ copy_option_part(&p, dir, MAXPATHL, ",");
+ }
+ swapname = makeswapname(fname, ffname, curbuf, dir);
+ vim_free(dir);
+ r = vim_fexists(swapname);
+ if (r)
+ {
+#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
+ if (p_confirm || cmdmod.confirm)
+ {
+ char_u buff[DIALOG_MSG_SIZE];
+
+ dialog_msg(buff,
+ _("Swap file \"%s\" exists, overwrite anyway?"),
+ swapname);
+ if (vim_dialog_yesno(VIM_QUESTION, NULL, buff, 2)
+ != VIM_YES)
+ {
+ vim_free(swapname);
+ return FAIL;
+ }
+ eap->forceit = TRUE;
+ }
+ else
+#endif
+ {
+ semsg(_("E768: Swap file exists: %s (:silent! overrides)"),
+ swapname);
+ vim_free(swapname);
+ return FAIL;
+ }
+ }
+ vim_free(swapname);
+ }
+ }
+ return OK;
+}
+
+/*
+ * Handle ":wnext", ":wNext" and ":wprevious" commands.
+ */
+ void
+ex_wnext(exarg_T *eap)
+{
+ int i;
+
+ if (eap->cmd[1] == 'n')
+ i = curwin->w_arg_idx + (int)eap->line2;
+ else
+ i = curwin->w_arg_idx - (int)eap->line2;
+ eap->line1 = 1;
+ eap->line2 = curbuf->b_ml.ml_line_count;
+ if (do_write(eap) != FAIL)
+ do_argfile(eap, i);
+}
+
+/*
+ * ":wall", ":wqall" and ":xall": Write all changed files (and exit).
+ */
+ void
+do_wqall(exarg_T *eap)
+{
+ buf_T *buf;
+ int error = 0;
+ int save_forceit = eap->forceit;
+
+ if (eap->cmdidx == CMD_xall || eap->cmdidx == CMD_wqall)
+ exiting = TRUE;
+
+ FOR_ALL_BUFFERS(buf)
+ {
+#ifdef FEAT_TERMINAL
+ if (exiting && term_job_running(buf->b_term))
+ {
+ no_write_message_nobang(buf);
+ ++error;
+ }
+ else
+#endif
+ if (bufIsChanged(buf) && !bt_dontwrite(buf))
+ {
+ /*
+ * Check if there is a reason the buffer cannot be written:
+ * 1. if the 'write' option is set
+ * 2. if there is no file name (even after browsing)
+ * 3. if the 'readonly' is set (even after a dialog)
+ * 4. if overwriting is allowed (even after a dialog)
+ */
+ if (not_writing())
+ {
+ ++error;
+ break;
+ }
+#ifdef FEAT_BROWSE
+ /* ":browse wall": ask for file name if there isn't one */
+ if (buf->b_ffname == NULL && cmdmod.browse)
+ browse_save_fname(buf);
+#endif
+ if (buf->b_ffname == NULL)
+ {
+ semsg(_("E141: No file name for buffer %ld"), (long)buf->b_fnum);
+ ++error;
+ }
+ else if (check_readonly(&eap->forceit, buf)
+ || check_overwrite(eap, buf, buf->b_fname, buf->b_ffname,
+ FALSE) == FAIL)
+ {
+ ++error;
+ }
+ else
+ {
+ bufref_T bufref;
+
+ set_bufref(&bufref, buf);
+ if (buf_write_all(buf, eap->forceit) == FAIL)
+ ++error;
+ /* an autocommand may have deleted the buffer */
+ if (!bufref_valid(&bufref))
+ buf = firstbuf;
+ }
+ eap->forceit = save_forceit; /* check_overwrite() may set it */
+ }
+ }
+ if (exiting)
+ {
+ if (!error)
+ getout(0); /* exit Vim */
+ not_exiting();
+ }
+}
+
+/*
+ * Check the 'write' option.
+ * Return TRUE and give a message when it's not st.
+ */
+ int
+not_writing(void)
+{
+ if (p_write)
+ return FALSE;
+ emsg(_("E142: File not written: Writing is disabled by 'write' option"));
+ return TRUE;
+}
+
+/*
+ * Check if a buffer is read-only (either 'readonly' option is set or file is
+ * read-only). Ask for overruling in a dialog. Return TRUE and give an error
+ * message when the buffer is readonly.
+ */
+ static int
+check_readonly(int *forceit, buf_T *buf)
+{
+ stat_T st;
+
+ /* Handle a file being readonly when the 'readonly' option is set or when
+ * the file exists and permissions are read-only.
+ * We will send 0777 to check_file_readonly(), as the "perm" variable is
+ * important for device checks but not here. */
+ if (!*forceit && (buf->b_p_ro
+ || (mch_stat((char *)buf->b_ffname, &st) >= 0
+ && check_file_readonly(buf->b_ffname, 0777))))
+ {
+#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
+ if ((p_confirm || cmdmod.confirm) && buf->b_fname != NULL)
+ {
+ char_u buff[DIALOG_MSG_SIZE];
+
+ if (buf->b_p_ro)
+ dialog_msg(buff, _("'readonly' option is set for \"%s\".\nDo you wish to write anyway?"),
+ buf->b_fname);
+ else
+ dialog_msg(buff, _("File permissions of \"%s\" are read-only.\nIt may still be possible to write it.\nDo you wish to try?"),
+ buf->b_fname);
+
+ if (vim_dialog_yesno(VIM_QUESTION, NULL, buff, 2) == VIM_YES)
+ {
+ /* Set forceit, to force the writing of a readonly file */
+ *forceit = TRUE;
+ return FALSE;
+ }
+ else
+ return TRUE;
+ }
+ else
+#endif
+ if (buf->b_p_ro)
+ emsg(_(e_readonly));
+ else
+ semsg(_("E505: \"%s\" is read-only (add ! to override)"),
+ buf->b_fname);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/*
+ * Try to abandon the current file and edit a new or existing file.
+ * "fnum" is the number of the file, if zero use "ffname_arg"/"sfname_arg".
+ * "lnum" is the line number for the cursor in the new file (if non-zero).
+ *
+ * Return:
+ * GETFILE_ERROR for "normal" error,
+ * GETFILE_NOT_WRITTEN for "not written" error,
+ * GETFILE_SAME_FILE for success
+ * GETFILE_OPEN_OTHER for successfully opening another file.
+ */
+ int
+getfile(
+ int fnum,
+ char_u *ffname_arg,
+ char_u *sfname_arg,
+ int setpm,
+ linenr_T lnum,
+ int forceit)
+{
+ char_u *ffname = ffname_arg;
+ char_u *sfname = sfname_arg;
+ int other;
+ int retval;
+ char_u *free_me = NULL;
+
+ if (text_locked())
+ return GETFILE_ERROR;
+ if (curbuf_locked())
+ return GETFILE_ERROR;
+
+ if (fnum == 0)
+ {
+ /* make ffname full path, set sfname */
+ fname_expand(curbuf, &ffname, &sfname);
+ other = otherfile(ffname);
+ free_me = ffname; /* has been allocated, free() later */
+ }
+ else
+ other = (fnum != curbuf->b_fnum);
+
+ if (other)
+ ++no_wait_return; /* don't wait for autowrite message */
+ if (other && !forceit && curbuf->b_nwindows == 1 && !buf_hide(curbuf)
+ && curbufIsChanged() && autowrite(curbuf, forceit) == FAIL)
+ {
+#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
+ if (p_confirm && p_write)
+ dialog_changed(curbuf, FALSE);
+ if (curbufIsChanged())
+#endif
+ {
+ if (other)
+ --no_wait_return;
+ no_write_message();
+ retval = GETFILE_NOT_WRITTEN; /* file has been changed */
+ goto theend;
+ }
+ }
+ if (other)
+ --no_wait_return;
+ if (setpm)
+ setpcmark();
+ if (!other)
+ {
+ if (lnum != 0)
+ curwin->w_cursor.lnum = lnum;
+ check_cursor_lnum();
+ beginline(BL_SOL | BL_FIX);
+ retval = GETFILE_SAME_FILE; /* it's in the same file */
+ }
+ else if (do_ecmd(fnum, ffname, sfname, NULL, lnum,
+ (buf_hide(curbuf) ? ECMD_HIDE : 0) + (forceit ? ECMD_FORCEIT : 0),
+ curwin) == OK)
+ retval = GETFILE_OPEN_OTHER; /* opened another file */
+ else
+ retval = GETFILE_ERROR; /* error encountered */
+
+theend:
+ vim_free(free_me);
+ return retval;
+}
+
+/*
+ * start editing a new file
+ *
+ * fnum: file number; if zero use ffname/sfname
+ * ffname: the file name
+ * - full path if sfname used,
+ * - any file name if sfname is NULL
+ * - empty string to re-edit with the same file name (but may be
+ * in a different directory)
+ * - NULL to start an empty buffer
+ * sfname: the short file name (or NULL)
+ * eap: contains the command to be executed after loading the file and
+ * forced 'ff' and 'fenc'
+ * newlnum: if > 0: put cursor on this line number (if possible)
+ * if ECMD_LASTL: use last position in loaded file
+ * if ECMD_LAST: use last position in all files
+ * if ECMD_ONE: use first line
+ * flags:
+ * ECMD_HIDE: if TRUE don't free the current buffer
+ * ECMD_SET_HELP: set b_help flag of (new) buffer before opening file
+ * ECMD_OLDBUF: use existing buffer if it exists
+ * ECMD_FORCEIT: ! used for Ex command
+ * ECMD_ADDBUF: don't edit, just add to buffer list
+ * oldwin: Should be "curwin" when editing a new buffer in the current
+ * window, NULL when splitting the window first. When not NULL info
+ * of the previous buffer for "oldwin" is stored.
+ *
+ * return FAIL for failure, OK otherwise
+ */
+ int
+do_ecmd(
+ int fnum,
+ char_u *ffname,
+ char_u *sfname,
+ exarg_T *eap, /* can be NULL! */
+ linenr_T newlnum,
+ int flags,
+ win_T *oldwin)
+{
+ int other_file; /* TRUE if editing another file */
+ int oldbuf; /* TRUE if using existing buffer */
+ int auto_buf = FALSE; /* TRUE if autocommands brought us
+ into the buffer unexpectedly */
+ char_u *new_name = NULL;
+#if defined(FEAT_EVAL)
+ int did_set_swapcommand = FALSE;
+#endif
+ buf_T *buf;
+ bufref_T bufref;
+ bufref_T old_curbuf;
+ char_u *free_fname = NULL;
+#ifdef FEAT_BROWSE
+ char_u *browse_file = NULL;
+#endif
+ int retval = FAIL;
+ long n;
+ pos_T orig_pos;
+ linenr_T topline = 0;
+ int newcol = -1;
+ int solcol = -1;
+ pos_T *pos;
+ char_u *command = NULL;
+#ifdef FEAT_SPELL
+ int did_get_winopts = FALSE;
+#endif
+ int readfile_flags = 0;
+ int did_inc_redrawing_disabled = FALSE;
+ long *so_ptr = curwin->w_p_so >= 0 ? &curwin->w_p_so : &p_so;
+
+ if (eap != NULL)
+ command = eap->do_ecmd_cmd;
+ set_bufref(&old_curbuf, curbuf);
+
+ if (fnum != 0)
+ {
+ if (fnum == curbuf->b_fnum) /* file is already being edited */
+ return OK; /* nothing to do */
+ other_file = TRUE;
+ }
+ else
+ {
+#ifdef FEAT_BROWSE
+ if (cmdmod.browse)
+ {
+ if (
+# ifdef FEAT_GUI
+ !gui.in_use &&
+# endif
+ au_has_group((char_u *)"FileExplorer"))
+ {
+ /* No browsing supported but we do have the file explorer:
+ * Edit the directory. */
+ if (ffname == NULL || !mch_isdir(ffname))
+ ffname = (char_u *)".";
+ }
+ else
+ {
+ browse_file = do_browse(0, (char_u *)_("Edit File"), ffname,
+ NULL, NULL, NULL, curbuf);
+ if (browse_file == NULL)
+ goto theend;
+ ffname = browse_file;
+ }
+ }
+#endif
+ /* if no short name given, use ffname for short name */
+ if (sfname == NULL)
+ sfname = ffname;
+#ifdef USE_FNAME_CASE
+# ifdef USE_LONG_FNAME
+ if (USE_LONG_FNAME)
+# endif
+ if (sfname != NULL)
+ fname_case(sfname, 0); /* set correct case for sfname */
+#endif
+
+ if ((flags & ECMD_ADDBUF) && (ffname == NULL || *ffname == NUL))
+ goto theend;
+
+ if (ffname == NULL)
+ other_file = TRUE;
+ /* there is no file name */
+ else if (*ffname == NUL && curbuf->b_ffname == NULL)
+ other_file = FALSE;
+ else
+ {
+ if (*ffname == NUL) /* re-edit with same file name */
+ {
+ ffname = curbuf->b_ffname;
+ sfname = curbuf->b_fname;
+ }
+ free_fname = fix_fname(ffname); /* may expand to full path name */
+ if (free_fname != NULL)
+ ffname = free_fname;
+ other_file = otherfile(ffname);
+ }
+ }
+
+ /*
+ * if the file was changed we may not be allowed to abandon it
+ * - if we are going to re-edit the same file
+ * - or if we are the only window on this file and if ECMD_HIDE is FALSE
+ */
+ if ( ((!other_file && !(flags & ECMD_OLDBUF))
+ || (curbuf->b_nwindows == 1
+ && !(flags & (ECMD_HIDE | ECMD_ADDBUF))))
+ && check_changed(curbuf, (p_awa ? CCGD_AW : 0)
+ | (other_file ? 0 : CCGD_MULTWIN)
+ | ((flags & ECMD_FORCEIT) ? CCGD_FORCEIT : 0)
+ | (eap == NULL ? 0 : CCGD_EXCMD)))
+ {
+ if (fnum == 0 && other_file && ffname != NULL)
+ (void)setaltfname(ffname, sfname, newlnum < 0 ? 0 : newlnum);
+ goto theend;
+ }
+
+ /*
+ * End Visual mode before switching to another buffer, so the text can be
+ * copied into the GUI selection buffer.
+ */
+ reset_VIsual();
+
+#if defined(FEAT_EVAL)
+ if ((command != NULL || newlnum > (linenr_T)0)
+ && *get_vim_var_str(VV_SWAPCOMMAND) == NUL)
+ {
+ int len;
+ char_u *p;
+
+ /* Set v:swapcommand for the SwapExists autocommands. */
+ if (command != NULL)
+ len = (int)STRLEN(command) + 3;
+ else
+ len = 30;
+ p = alloc((unsigned)len);
+ if (p != NULL)
+ {
+ if (command != NULL)
+ vim_snprintf((char *)p, len, ":%s\r", command);
+ else
+ vim_snprintf((char *)p, len, "%ldG", (long)newlnum);
+ set_vim_var_string(VV_SWAPCOMMAND, p, -1);
+ did_set_swapcommand = TRUE;
+ vim_free(p);
+ }
+ }
+#endif
+
+ /*
+ * If we are starting to edit another file, open a (new) buffer.
+ * Otherwise we re-use the current buffer.
+ */
+ if (other_file)
+ {
+ if (!(flags & ECMD_ADDBUF))
+ {
+ if (!cmdmod.keepalt)
+ curwin->w_alt_fnum = curbuf->b_fnum;
+ if (oldwin != NULL)
+ buflist_altfpos(oldwin);
+ }
+
+ if (fnum)
+ buf = buflist_findnr(fnum);
+ else
+ {
+ if (flags & ECMD_ADDBUF)
+ {
+ linenr_T tlnum = 1L;
+
+ if (command != NULL)
+ {
+ tlnum = atol((char *)command);
+ if (tlnum <= 0)
+ tlnum = 1L;
+ }
+ (void)buflist_new(ffname, sfname, tlnum, BLN_LISTED);
+ goto theend;
+ }
+ buf = buflist_new(ffname, sfname, 0L,
+ BLN_CURBUF | ((flags & ECMD_SET_HELP) ? 0 : BLN_LISTED));
+
+ /* autocommands may change curwin and curbuf */
+ if (oldwin != NULL)
+ oldwin = curwin;
+ set_bufref(&old_curbuf, curbuf);
+ }
+ if (buf == NULL)
+ goto theend;
+ if (buf->b_ml.ml_mfp == NULL) /* no memfile yet */
+ {
+ oldbuf = FALSE;
+ }
+ else /* existing memfile */
+ {
+ oldbuf = TRUE;
+ set_bufref(&bufref, buf);
+ (void)buf_check_timestamp(buf, FALSE);
+ /* Check if autocommands made the buffer invalid or changed the
+ * current buffer. */
+ if (!bufref_valid(&bufref) || curbuf != old_curbuf.br_buf)
+ goto theend;
+#ifdef FEAT_EVAL
+ if (aborting()) /* autocmds may abort script processing */
+ goto theend;
+#endif
+ }
+
+ /* May jump to last used line number for a loaded buffer or when asked
+ * for explicitly */
+ if ((oldbuf && newlnum == ECMD_LASTL) || newlnum == ECMD_LAST)
+ {
+ pos = buflist_findfpos(buf);
+ newlnum = pos->lnum;
+ solcol = pos->col;
+ }
+
+ /*
+ * Make the (new) buffer the one used by the current window.
+ * If the old buffer becomes unused, free it if ECMD_HIDE is FALSE.
+ * If the current buffer was empty and has no file name, curbuf
+ * is returned by buflist_new(), nothing to do here.
+ */
+ if (buf != curbuf)
+ {
+ /*
+ * Be careful: The autocommands may delete any buffer and change
+ * the current buffer.
+ * - If the buffer we are going to edit is deleted, give up.
+ * - If the current buffer is deleted, prefer to load the new
+ * buffer when loading a buffer is required. This avoids
+ * loading another buffer which then must be closed again.
+ * - If we ended up in the new buffer already, need to skip a few
+ * things, set auto_buf.
+ */
+ if (buf->b_fname != NULL)
+ new_name = vim_strsave(buf->b_fname);
+ set_bufref(&au_new_curbuf, buf);
+ apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, FALSE, curbuf);
+ if (!bufref_valid(&au_new_curbuf))
+ {
+ /* new buffer has been deleted */
+ delbuf_msg(new_name); /* frees new_name */
+ goto theend;
+ }
+#ifdef FEAT_EVAL
+ if (aborting()) /* autocmds may abort script processing */
+ {
+ vim_free(new_name);
+ goto theend;
+ }
+#endif
+ if (buf == curbuf) /* already in new buffer */
+ auto_buf = TRUE;
+ else
+ {
+ win_T *the_curwin = curwin;
+
+ /* Set the w_closing flag to avoid that autocommands close the
+ * window. And set b_locked for the same reason. */
+ the_curwin->w_closing = TRUE;
+ ++buf->b_locked;
+
+ if (curbuf == old_curbuf.br_buf)
+ buf_copy_options(buf, BCO_ENTER);
+
+ /* Close the link to the current buffer. This will set
+ * oldwin->w_buffer to NULL. */
+ u_sync(FALSE);
+ close_buffer(oldwin, curbuf,
+ (flags & ECMD_HIDE) ? 0 : DOBUF_UNLOAD, FALSE);
+
+ the_curwin->w_closing = FALSE;
+ --buf->b_locked;
+
+#ifdef FEAT_EVAL
+ /* autocmds may abort script processing */
+ if (aborting() && curwin->w_buffer != NULL)
+ {
+ vim_free(new_name);
+ goto theend;
+ }
+#endif
+ /* Be careful again, like above. */
+ if (!bufref_valid(&au_new_curbuf))
+ {
+ /* new buffer has been deleted */
+ delbuf_msg(new_name); /* frees new_name */
+ goto theend;
+ }
+ if (buf == curbuf) /* already in new buffer */
+ auto_buf = TRUE;
+ else
+ {
+#ifdef FEAT_SYN_HL
+ /*
+ * <VN> We could instead free the synblock
+ * and re-attach to buffer, perhaps.
+ */
+ if (curwin->w_buffer == NULL
+ || curwin->w_s == &(curwin->w_buffer->b_s))
+ curwin->w_s = &(buf->b_s);
+#endif
+ curwin->w_buffer = buf;
+ curbuf = buf;
+ ++curbuf->b_nwindows;
+
+ /* Set 'fileformat', 'binary' and 'fenc' when forced. */
+ if (!oldbuf && eap != NULL)
+ {
+ set_file_options(TRUE, eap);
+ set_forced_fenc(eap);
+ }
+ }
+
+ /* May get the window options from the last time this buffer
+ * was in this window (or another window). If not used
+ * before, reset the local window options to the global
+ * values. Also restores old folding stuff. */
+ get_winopts(curbuf);
+#ifdef FEAT_SPELL
+ did_get_winopts = TRUE;
+#endif
+ }
+ vim_free(new_name);
+ au_new_curbuf.br_buf = NULL;
+ au_new_curbuf.br_buf_free_count = 0;
+ }
+
+ curwin->w_pcmark.lnum = 1;
+ curwin->w_pcmark.col = 0;
+ }
+ else /* !other_file */
+ {
+ if ((flags & ECMD_ADDBUF) || check_fname() == FAIL)
+ goto theend;
+
+ oldbuf = (flags & ECMD_OLDBUF);
+ }
+
+ /* Don't redraw until the cursor is in the right line, otherwise
+ * autocommands may cause ml_get errors. */
+ ++RedrawingDisabled;
+ did_inc_redrawing_disabled = TRUE;
+
+ buf = curbuf;
+ if ((flags & ECMD_SET_HELP) || keep_help_flag)
+ {
+ prepare_help_buffer();
+ }
+ else
+ {
+ /* Don't make a buffer listed if it's a help buffer. Useful when
+ * using CTRL-O to go back to a help file. */
+ if (!curbuf->b_help)
+ set_buflisted(TRUE);
+ }
+
+ /* If autocommands change buffers under our fingers, forget about
+ * editing the file. */
+ if (buf != curbuf)
+ goto theend;
+#ifdef FEAT_EVAL
+ if (aborting()) /* autocmds may abort script processing */
+ goto theend;
+#endif
+
+ /* Since we are starting to edit a file, consider the filetype to be
+ * unset. Helps for when an autocommand changes files and expects syntax
+ * highlighting to work in the other file. */
+ did_filetype = FALSE;
+
+/*
+ * other_file oldbuf
+ * FALSE FALSE re-edit same file, buffer is re-used
+ * FALSE TRUE re-edit same file, nothing changes
+ * TRUE FALSE start editing new file, new buffer
+ * TRUE TRUE start editing in existing buffer (nothing to do)
+ */
+ if (!other_file && !oldbuf) /* re-use the buffer */
+ {
+ set_last_cursor(curwin); /* may set b_last_cursor */
+ if (newlnum == ECMD_LAST || newlnum == ECMD_LASTL)
+ {
+ newlnum = curwin->w_cursor.lnum;
+ solcol = curwin->w_cursor.col;
+ }
+ buf = curbuf;
+ if (buf->b_fname != NULL)
+ new_name = vim_strsave(buf->b_fname);
+ else
+ new_name = NULL;
+ set_bufref(&bufref, buf);
+
+ if (p_ur < 0 || curbuf->b_ml.ml_line_count <= p_ur)
+ {
+ /* Save all the text, so that the reload can be undone.
+ * Sync first so that this is a separate undo-able action. */
+ u_sync(FALSE);
+ if (u_savecommon(0, curbuf->b_ml.ml_line_count + 1, 0, TRUE)
+ == FAIL)
+ {
+ vim_free(new_name);
+ goto theend;
+ }
+ u_unchanged(curbuf);
+ buf_freeall(curbuf, BFA_KEEP_UNDO);
+
+ /* tell readfile() not to clear or reload undo info */
+ readfile_flags = READ_KEEP_UNDO;
+ }
+ else
+ buf_freeall(curbuf, 0); /* free all things for buffer */
+
+ /* If autocommands deleted the buffer we were going to re-edit, give
+ * up and jump to the end. */
+ if (!bufref_valid(&bufref))
+ {
+ delbuf_msg(new_name); /* frees new_name */
+ goto theend;
+ }
+ vim_free(new_name);
+
+ /* If autocommands change buffers under our fingers, forget about
+ * re-editing the file. Should do the buf_clear_file(), but perhaps
+ * the autocommands changed the buffer... */
+ if (buf != curbuf)
+ goto theend;
+#ifdef FEAT_EVAL
+ if (aborting()) /* autocmds may abort script processing */
+ goto theend;
+#endif
+ buf_clear_file(curbuf);
+ curbuf->b_op_start.lnum = 0; /* clear '[ and '] marks */
+ curbuf->b_op_end.lnum = 0;
+ }
+
+/*
+ * If we get here we are sure to start editing
+ */
+ /* Assume success now */
+ retval = OK;
+
+ /*
+ * Check if we are editing the w_arg_idx file in the argument list.
+ */
+ check_arg_idx(curwin);
+
+ if (!auto_buf)
+ {
+ /*
+ * Set cursor and init window before reading the file and executing
+ * autocommands. This allows for the autocommands to position the
+ * cursor.
+ */
+ curwin_init();
+
+#ifdef FEAT_FOLDING
+ /* It's possible that all lines in the buffer changed. Need to update
+ * automatic folding for all windows where it's used. */
+ {
+ win_T *win;
+ tabpage_T *tp;
+
+ FOR_ALL_TAB_WINDOWS(tp, win)
+ if (win->w_buffer == curbuf)
+ foldUpdateAll(win);
+ }
+#endif
+
+ /* Change directories when the 'acd' option is set. */
+ DO_AUTOCHDIR;
+
+ /*
+ * Careful: open_buffer() and apply_autocmds() may change the current
+ * buffer and window.
+ */
+ orig_pos = curwin->w_cursor;
+ topline = curwin->w_topline;
+ if (!oldbuf) /* need to read the file */
+ {
+#if defined(HAS_SWAP_EXISTS_ACTION)
+ swap_exists_action = SEA_DIALOG;
+#endif
+ curbuf->b_flags |= BF_CHECK_RO; /* set/reset 'ro' flag */
+
+ /*
+ * Open the buffer and read the file.
+ */
+#if defined(FEAT_EVAL)
+ if (should_abort(open_buffer(FALSE, eap, readfile_flags)))
+ retval = FAIL;
+#else
+ (void)open_buffer(FALSE, eap, readfile_flags);
+#endif
+
+#if defined(HAS_SWAP_EXISTS_ACTION)
+ if (swap_exists_action == SEA_QUIT)
+ retval = FAIL;
+ handle_swap_exists(&old_curbuf);
+#endif
+ }
+ else
+ {
+ /* Read the modelines, but only to set window-local options. Any
+ * buffer-local options have already been set and may have been
+ * changed by the user. */
+ do_modelines(OPT_WINONLY);
+
+ apply_autocmds_retval(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf,
+ &retval);
+ apply_autocmds_retval(EVENT_BUFWINENTER, NULL, NULL, FALSE, curbuf,
+ &retval);
+ }
+ check_arg_idx(curwin);
+
+ /* If autocommands change the cursor position or topline, we should
+ * keep it. Also when it moves within a line. But not when it moves
+ * to the first non-blank. */
+ if (!EQUAL_POS(curwin->w_cursor, orig_pos))
+ {
+ char_u *text = ml_get_curline();
+
+ if (curwin->w_cursor.lnum != orig_pos.lnum
+ || curwin->w_cursor.col != (int)(skipwhite(text) - text))
+ {
+ newlnum = curwin->w_cursor.lnum;
+ newcol = curwin->w_cursor.col;
+ }
+ }
+ if (curwin->w_topline == topline)
+ topline = 0;
+
+ /* Even when cursor didn't move we need to recompute topline. */
+ changed_line_abv_curs();
+
+#ifdef FEAT_TITLE
+ maketitle();
+#endif
+ }
+
+#ifdef FEAT_DIFF
+ /* Tell the diff stuff that this buffer is new and/or needs updating.
+ * Also needed when re-editing the same buffer, because unloading will
+ * have removed it as a diff buffer. */
+ if (curwin->w_p_diff)
+ {
+ diff_buf_add(curbuf);
+ diff_invalidate(curbuf);
+ }
+#endif
+
+#ifdef FEAT_SPELL
+ /* If the window options were changed may need to set the spell language.
+ * Can only do this after the buffer has been properly setup. */
+ if (did_get_winopts && curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
+ (void)did_set_spelllang(curwin);
+#endif
+
+ if (command == NULL)
+ {
+ if (newcol >= 0) /* position set by autocommands */
+ {
+ curwin->w_cursor.lnum = newlnum;
+ curwin->w_cursor.col = newcol;
+ check_cursor();
+ }
+ else if (newlnum > 0) /* line number from caller or old position */
+ {
+ curwin->w_cursor.lnum = newlnum;
+ check_cursor_lnum();
+ if (solcol >= 0 && !p_sol)
+ {
+ /* 'sol' is off: Use last known column. */
+ curwin->w_cursor.col = solcol;
+ check_cursor_col();
+ curwin->w_cursor.coladd = 0;
+ curwin->w_set_curswant = TRUE;
+ }
+ else
+ beginline(BL_SOL | BL_FIX);
+ }
+ else /* no line number, go to last line in Ex mode */
+ {
+ if (exmode_active)
+ curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
+ beginline(BL_WHITE | BL_FIX);
+ }
+ }
+
+ /* Check if cursors in other windows on the same buffer are still valid */
+ check_lnums(FALSE);
+
+ /*
+ * Did not read the file, need to show some info about the file.
+ * Do this after setting the cursor.
+ */
+ if (oldbuf && !auto_buf)
+ {
+ int msg_scroll_save = msg_scroll;
+
+ /* Obey the 'O' flag in 'cpoptions': overwrite any previous file
+ * message. */
+ if (shortmess(SHM_OVERALL) && !exiting && p_verbose == 0)
+ msg_scroll = FALSE;
+ if (!msg_scroll) /* wait a bit when overwriting an error msg */
+ check_for_delay(FALSE);
+ msg_start();
+ msg_scroll = msg_scroll_save;
+ msg_scrolled_ign = TRUE;
+
+ if (!shortmess(SHM_FILEINFO))
+ fileinfo(FALSE, TRUE, FALSE);
+
+ msg_scrolled_ign = FALSE;
+ }
+
+#ifdef FEAT_VIMINFO
+ curbuf->b_last_used = vim_time();
+#endif
+
+ if (command != NULL)
+ do_cmdline(command, NULL, NULL, DOCMD_VERBOSE);
+
+#ifdef FEAT_KEYMAP
+ if (curbuf->b_kmap_state & KEYMAP_INIT)
+ (void)keymap_init();
+#endif
+
+ --RedrawingDisabled;
+ did_inc_redrawing_disabled = FALSE;
+ if (!skip_redraw)
+ {
+ n = *so_ptr;
+ if (topline == 0 && command == NULL)
+ *so_ptr = 9999; // force cursor halfway the window
+ update_topline();
+ curwin->w_scbind_pos = curwin->w_topline;
+ *so_ptr = n;
+ redraw_curbuf_later(NOT_VALID); /* redraw this buffer later */
+ }
+
+ if (p_im)
+ need_start_insertmode = TRUE;
+
+#ifdef FEAT_AUTOCHDIR
+ /* Change directories when the 'acd' option is set and we aren't already in
+ * that directory (should already be done above). Expect getcwd() to be
+ * faster than calling shorten_fnames() unnecessarily. */
+ if (p_acd && curbuf->b_ffname != NULL)
+ {
+ char_u curdir[MAXPATHL];
+ char_u filedir[MAXPATHL];
+
+ vim_strncpy(filedir, curbuf->b_ffname, MAXPATHL - 1);
+ *gettail_sep(filedir) = NUL;
+ if (mch_dirname(curdir, MAXPATHL) != FAIL
+ && vim_fnamecmp(curdir, filedir) != 0)
+ do_autochdir();
+ }
+#endif
+
+#if defined(FEAT_NETBEANS_INTG)
+ if (curbuf->b_ffname != NULL)
+ {
+# ifdef FEAT_NETBEANS_INTG
+ if ((flags & ECMD_SET_HELP) != ECMD_SET_HELP)
+ netbeans_file_opened(curbuf);
+# endif
+ }
+#endif
+
+theend:
+ if (did_inc_redrawing_disabled)
+ --RedrawingDisabled;
+#if defined(FEAT_EVAL)
+ if (did_set_swapcommand)
+ set_vim_var_string(VV_SWAPCOMMAND, NULL, -1);
+#endif
+#ifdef FEAT_BROWSE
+ vim_free(browse_file);
+#endif
+ vim_free(free_fname);
+ return retval;
+}
+
+ static void
+delbuf_msg(char_u *name)
+{
+ semsg(_("E143: Autocommands unexpectedly deleted new buffer %s"),
+ name == NULL ? (char_u *)"" : name);
+ vim_free(name);
+ au_new_curbuf.br_buf = NULL;
+ au_new_curbuf.br_buf_free_count = 0;
+}
+
+static int append_indent = 0; /* autoindent for first line */
+
+/*
+ * ":insert" and ":append", also used by ":change"
+ */
+ void
+ex_append(exarg_T *eap)
+{
+ char_u *theline;
+ int did_undo = FALSE;
+ linenr_T lnum = eap->line2;
+ int indent = 0;
+ char_u *p;
+ int vcol;
+ int empty = (curbuf->b_ml.ml_flags & ML_EMPTY);
+
+ /* the ! flag toggles autoindent */
+ if (eap->forceit)
+ curbuf->b_p_ai = !curbuf->b_p_ai;
+
+ /* First autoindent comes from the line we start on */
+ if (eap->cmdidx != CMD_change && curbuf->b_p_ai && lnum > 0)
+ append_indent = get_indent_lnum(lnum);
+
+ if (eap->cmdidx != CMD_append)
+ --lnum;
+
+ /* when the buffer is empty need to delete the dummy line */
+ if (empty && lnum == 1)
+ lnum = 0;
+
+ State = INSERT; /* behave like in Insert mode */
+ if (curbuf->b_p_iminsert == B_IMODE_LMAP)
+ State |= LANGMAP;
+
+ for (;;)
+ {
+ msg_scroll = TRUE;
+ need_wait_return = FALSE;
+ if (curbuf->b_p_ai)
+ {
+ if (append_indent >= 0)
+ {
+ indent = append_indent;
+ append_indent = -1;
+ }
+ else if (lnum > 0)
+ indent = get_indent_lnum(lnum);
+ }
+ ex_keep_indent = FALSE;
+ if (eap->getline == NULL)
+ {
+ /* No getline() function, use the lines that follow. This ends
+ * when there is no more. */
+ if (eap->nextcmd == NULL || *eap->nextcmd == NUL)
+ break;
+ p = vim_strchr(eap->nextcmd, NL);
+ if (p == NULL)
+ p = eap->nextcmd + STRLEN(eap->nextcmd);
+ theline = vim_strnsave(eap->nextcmd, (int)(p - eap->nextcmd));
+ if (*p != NUL)
+ ++p;
+ eap->nextcmd = p;
+ }
+ else
+ {
+ int save_State = State;
+
+ /* Set State to avoid the cursor shape to be set to INSERT mode
+ * when getline() returns. */
+ State = CMDLINE;
+ theline = eap->getline(
+#ifdef FEAT_EVAL
+ eap->cstack->cs_looplevel > 0 ? -1 :
+#endif
+ NUL, eap->cookie, indent);
+ State = save_State;
+ }
+ lines_left = Rows - 1;
+ if (theline == NULL)
+ break;
+
+ /* Using ^ CTRL-D in getexmodeline() makes us repeat the indent. */
+ if (ex_keep_indent)
+ append_indent = indent;
+
+ /* Look for the "." after automatic indent. */
+ vcol = 0;
+ for (p = theline; indent > vcol; ++p)
+ {
+ if (*p == ' ')
+ ++vcol;
+ else if (*p == TAB)
+ vcol += 8 - vcol % 8;
+ else
+ break;
+ }
+ if ((p[0] == '.' && p[1] == NUL)
+ || (!did_undo && u_save(lnum, lnum + 1 + (empty ? 1 : 0))
+ == FAIL))
+ {
+ vim_free(theline);
+ break;
+ }
+
+ /* don't use autoindent if nothing was typed. */
+ if (p[0] == NUL)
+ theline[0] = NUL;
+
+ did_undo = TRUE;
+ ml_append(lnum, theline, (colnr_T)0, FALSE);
+ appended_lines_mark(lnum + (empty ? 1 : 0), 1L);
+
+ vim_free(theline);
+ ++lnum;
+
+ if (empty)
+ {
+ ml_delete(2L, FALSE);
+ empty = FALSE;
+ }
+ }
+ State = NORMAL;
+
+ if (eap->forceit)
+ curbuf->b_p_ai = !curbuf->b_p_ai;
+
+ /* "start" is set to eap->line2+1 unless that position is invalid (when
+ * eap->line2 pointed to the end of the buffer and nothing was appended)
+ * "end" is set to lnum when something has been appended, otherwise
+ * it is the same than "start" -- Acevedo */
+ curbuf->b_op_start.lnum = (eap->line2 < curbuf->b_ml.ml_line_count) ?
+ eap->line2 + 1 : curbuf->b_ml.ml_line_count;
+ if (eap->cmdidx != CMD_append)
+ --curbuf->b_op_start.lnum;
+ curbuf->b_op_end.lnum = (eap->line2 < lnum)
+ ? lnum : curbuf->b_op_start.lnum;
+ curbuf->b_op_start.col = curbuf->b_op_end.col = 0;
+ curwin->w_cursor.lnum = lnum;
+ check_cursor_lnum();
+ beginline(BL_SOL | BL_FIX);
+
+ need_wait_return = FALSE; /* don't use wait_return() now */
+ ex_no_reprint = TRUE;
+}
+
+/*
+ * ":change"
+ */
+ void
+ex_change(exarg_T *eap)
+{
+ linenr_T lnum;
+
+ if (eap->line2 >= eap->line1
+ && u_save(eap->line1 - 1, eap->line2 + 1) == FAIL)
+ return;
+
+ /* the ! flag toggles autoindent */
+ if (eap->forceit ? !curbuf->b_p_ai : curbuf->b_p_ai)
+ append_indent = get_indent_lnum(eap->line1);
+
+ for (lnum = eap->line2; lnum >= eap->line1; --lnum)
+ {
+ if (curbuf->b_ml.ml_flags & ML_EMPTY) /* nothing to delete */
+ break;
+ ml_delete(eap->line1, FALSE);
+ }
+
+ /* make sure the cursor is not beyond the end of the file now */
+ check_cursor_lnum();
+ deleted_lines_mark(eap->line1, (long)(eap->line2 - lnum));
+
+ /* ":append" on the line above the deleted lines. */
+ eap->line2 = eap->line1;
+ ex_append(eap);
+}
+
+ void
+ex_z(exarg_T *eap)
+{
+ char_u *x;
+ long bigness;
+ char_u *kind;
+ int minus = 0;
+ linenr_T start, end, curs, i;
+ int j;
+ linenr_T lnum = eap->line2;
+
+ /* Vi compatible: ":z!" uses display height, without a count uses
+ * 'scroll' */
+ if (eap->forceit)
+ bigness = curwin->w_height;
+ else if (!ONE_WINDOW)
+ bigness = curwin->w_height - 3;
+ else
+ bigness = curwin->w_p_scr * 2;
+ if (bigness < 1)
+ bigness = 1;
+
+ x = eap->arg;
+ kind = x;
+ if (*kind == '-' || *kind == '+' || *kind == '='
+ || *kind == '^' || *kind == '.')
+ ++x;
+ while (*x == '-' || *x == '+')
+ ++x;
+
+ if (*x != 0)
+ {
+ if (!VIM_ISDIGIT(*x))
+ {
+ emsg(_("E144: non-numeric argument to :z"));
+ return;
+ }
+ else
+ {
+ bigness = atol((char *)x);
+
+ /* bigness could be < 0 if atol(x) overflows. */
+ if (bigness > 2 * curbuf->b_ml.ml_line_count || bigness < 0)
+ bigness = 2 * curbuf->b_ml.ml_line_count;
+
+ p_window = bigness;
+ if (*kind == '=')
+ bigness += 2;
+ }
+ }
+
+ /* the number of '-' and '+' multiplies the distance */
+ if (*kind == '-' || *kind == '+')
+ for (x = kind + 1; *x == *kind; ++x)
+ ;
+
+ switch (*kind)
+ {
+ case '-':
+ start = lnum - bigness * (linenr_T)(x - kind) + 1;
+ end = start + bigness - 1;
+ curs = end;
+ break;
+
+ case '=':
+ start = lnum - (bigness + 1) / 2 + 1;
+ end = lnum + (bigness + 1) / 2 - 1;
+ curs = lnum;
+ minus = 1;
+ break;
+
+ case '^':
+ start = lnum - bigness * 2;
+ end = lnum - bigness;
+ curs = lnum - bigness;
+ break;
+
+ case '.':
+ start = lnum - (bigness + 1) / 2 + 1;
+ end = lnum + (bigness + 1) / 2 - 1;
+ curs = end;
+ break;
+
+ default: /* '+' */
+ start = lnum;
+ if (*kind == '+')
+ start += bigness * (linenr_T)(x - kind - 1) + 1;
+ else if (eap->addr_count == 0)
+ ++start;
+ end = start + bigness - 1;
+ curs = end;
+ break;
+ }
+
+ if (start < 1)
+ start = 1;
+
+ if (end > curbuf->b_ml.ml_line_count)
+ end = curbuf->b_ml.ml_line_count;
+
+ if (curs > curbuf->b_ml.ml_line_count)
+ curs = curbuf->b_ml.ml_line_count;
+ else if (curs < 1)
+ curs = 1;
+
+ for (i = start; i <= end; i++)
+ {
+ if (minus && i == lnum)
+ {
+ msg_putchar('\n');
+
+ for (j = 1; j < Columns; j++)
+ msg_putchar('-');
+ }
+
+ print_line(i, eap->flags & EXFLAG_NR, eap->flags & EXFLAG_LIST);
+
+ if (minus && i == lnum)
+ {
+ msg_putchar('\n');
+
+ for (j = 1; j < Columns; j++)
+ msg_putchar('-');
+ }
+ }
+
+ if (curwin->w_cursor.lnum != curs)
+ {
+ curwin->w_cursor.lnum = curs;
+ curwin->w_cursor.col = 0;
+ }
+ ex_no_reprint = TRUE;
+}
+
+/*
+ * Check if the restricted flag is set.
+ * If so, give an error message and return TRUE.
+ * Otherwise, return FALSE.
+ */
+ int
+check_restricted(void)
+{
+ if (restricted)
+ {
+ emsg(_("E145: Shell commands not allowed in rvim"));
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * Check if the secure flag is set (.exrc or .vimrc in current directory).
+ * If so, give an error message and return TRUE.
+ * Otherwise, return FALSE.
+ */
+ int
+check_secure(void)
+{
+ if (secure)
+ {
+ secure = 2;
+ emsg(_(e_curdir));
+ return TRUE;
+ }
+#ifdef HAVE_SANDBOX
+ /*
+ * In the sandbox more things are not allowed, including the things
+ * disallowed in secure mode.
+ */
+ if (sandbox != 0)
+ {
+ emsg(_(e_sandbox));
+ return TRUE;
+ }
+#endif
+ return FALSE;
+}
+
+static char_u *old_sub = NULL; /* previous substitute pattern */
+static int global_need_beginline; /* call beginline() after ":g" */
+
+/*
+ * Flags that are kept between calls to :substitute.
+ */
+typedef struct {
+ int do_all; /* do multiple substitutions per line */
+ int do_ask; /* ask for confirmation */
+ int do_count; /* count only */
+ int do_error; /* if false, ignore errors */
+ int do_print; /* print last line with subs. */
+ int do_list; /* list last line with subs. */
+ int do_number; /* list last line with line nr*/
+ int do_ic; /* ignore case flag */
+} subflags_T;
+
+/* do_sub()
+ *
+ * Perform a substitution from line eap->line1 to line eap->line2 using the
+ * command pointed to by eap->arg which should be of the form:
+ *
+ * /pattern/substitution/{flags}
+ *
+ * The usual escapes are supported as described in the regexp docs.
+ */
+ void
+do_sub(exarg_T *eap)
+{
+ linenr_T lnum;
+ long i = 0;
+ regmmatch_T regmatch;
+ static subflags_T subflags = {FALSE, FALSE, FALSE, TRUE, FALSE,
+ FALSE, FALSE, 0};
+#ifdef FEAT_EVAL
+ subflags_T subflags_save;
+#endif
+ int save_do_all; /* remember user specified 'g' flag */
+ int save_do_ask; /* remember user specified 'c' flag */
+ char_u *pat = NULL, *sub = NULL; /* init for GCC */
+ int delimiter;
+ int sublen;
+ int got_quit = FALSE;
+ int got_match = FALSE;
+ int temp;
+ int which_pat;
+ char_u *cmd;
+ int save_State;
+ linenr_T first_line = 0; /* first changed line */
+ linenr_T last_line= 0; /* below last changed line AFTER the
+ * change */
+ linenr_T old_line_count = curbuf->b_ml.ml_line_count;
+ linenr_T line2;
+ long nmatch; /* number of lines in match */
+ char_u *sub_firstline; /* allocated copy of first sub line */
+ int endcolumn = FALSE; /* cursor in last column when done */
+ pos_T old_cursor = curwin->w_cursor;
+ int start_nsubs;
+#ifdef FEAT_EVAL
+ int save_ma = 0;
+#endif
+
+ cmd = eap->arg;
+ if (!global_busy)
+ {
+ sub_nsubs = 0;
+ sub_nlines = 0;
+ }
+ start_nsubs = sub_nsubs;
+
+ if (eap->cmdidx == CMD_tilde)
+ which_pat = RE_LAST; /* use last used regexp */
+ else
+ which_pat = RE_SUBST; /* use last substitute regexp */
+
+ /* new pattern and substitution */
+ if (eap->cmd[0] == 's' && *cmd != NUL && !VIM_ISWHITE(*cmd)
+ && vim_strchr((char_u *)"0123456789cegriIp|\"", *cmd) == NULL)
+ {
+ /* don't accept alphanumeric for separator */
+ if (isalpha(*cmd))
+ {
+ emsg(_("E146: Regular expressions can't be delimited by letters"));
+ return;
+ }
+ /*
+ * undocumented vi feature:
+ * "\/sub/" and "\?sub?" use last used search pattern (almost like
+ * //sub/r). "\&sub&" use last substitute pattern (like //sub/).
+ */
+ if (*cmd == '\\')
+ {
+ ++cmd;
+ if (vim_strchr((char_u *)"/?&", *cmd) == NULL)
+ {
+ emsg(_(e_backslash));
+ return;
+ }
+ if (*cmd != '&')
+ which_pat = RE_SEARCH; /* use last '/' pattern */
+ pat = (char_u *)""; /* empty search pattern */
+ delimiter = *cmd++; /* remember delimiter character */
+ }
+ else /* find the end of the regexp */
+ {
+#ifdef FEAT_FKMAP /* reverse the flow of the Farsi characters */
+ if (p_altkeymap && curwin->w_p_rl)
+ lrF_sub(cmd);
+#endif
+ which_pat = RE_LAST; /* use last used regexp */
+ delimiter = *cmd++; /* remember delimiter character */
+ pat = cmd; /* remember start of search pat */
+ cmd = skip_regexp(cmd, delimiter, p_magic, &eap->arg);
+ if (cmd[0] == delimiter) /* end delimiter found */
+ *cmd++ = NUL; /* replace it with a NUL */
+ }
+
+ /*
+ * Small incompatibility: vi sees '\n' as end of the command, but in
+ * Vim we want to use '\n' to find/substitute a NUL.
+ */
+ sub = cmd; /* remember the start of the substitution */
+
+ while (cmd[0])
+ {
+ if (cmd[0] == delimiter) /* end delimiter found */
+ {
+ *cmd++ = NUL; /* replace it with a NUL */
+ break;
+ }
+ if (cmd[0] == '\\' && cmd[1] != 0) /* skip escaped characters */
+ ++cmd;
+ MB_PTR_ADV(cmd);
+ }
+
+ if (!eap->skip)
+ {
+ /* In POSIX vi ":s/pat/%/" uses the previous subst. string. */
+ if (STRCMP(sub, "%") == 0
+ && vim_strchr(p_cpo, CPO_SUBPERCENT) != NULL)
+ {
+ if (old_sub == NULL) /* there is no previous command */
+ {
+ emsg(_(e_nopresub));
+ return;
+ }
+ sub = old_sub;
+ }
+ else
+ {
+ vim_free(old_sub);
+ old_sub = vim_strsave(sub);
+ }
+ }
+ }
+ else if (!eap->skip) /* use previous pattern and substitution */
+ {
+ if (old_sub == NULL) /* there is no previous command */
+ {
+ emsg(_(e_nopresub));
+ return;
+ }
+ pat = NULL; /* search_regcomp() will use previous pattern */
+ sub = old_sub;
+
+ /* Vi compatibility quirk: repeating with ":s" keeps the cursor in the
+ * last column after using "$". */
+ endcolumn = (curwin->w_curswant == MAXCOL);
+ }
+
+ /* Recognize ":%s/\n//" and turn it into a join command, which is much
+ * more efficient.
+ * TODO: find a generic solution to make line-joining operations more
+ * efficient, avoid allocating a string that grows in size.
+ */
+ if (pat != NULL && STRCMP(pat, "\\n") == 0
+ && *sub == NUL
+ && (*cmd == NUL || (cmd[1] == NUL && (*cmd == 'g' || *cmd == 'l'
+ || *cmd == 'p' || *cmd == '#'))))
+ {
+ linenr_T joined_lines_count;
+
+ curwin->w_cursor.lnum = eap->line1;
+ if (*cmd == 'l')
+ eap->flags = EXFLAG_LIST;
+ else if (*cmd == '#')
+ eap->flags = EXFLAG_NR;
+ else if (*cmd == 'p')
+ eap->flags = EXFLAG_PRINT;
+
+ /* The number of lines joined is the number of lines in the range plus
+ * one. One less when the last line is included. */
+ joined_lines_count = eap->line2 - eap->line1 + 1;
+ if (eap->line2 < curbuf->b_ml.ml_line_count)
+ ++joined_lines_count;
+ if (joined_lines_count > 1)
+ {
+ (void)do_join(joined_lines_count, FALSE, TRUE, FALSE, TRUE);
+ sub_nsubs = joined_lines_count - 1;
+ sub_nlines = 1;
+ (void)do_sub_msg(FALSE);
+ ex_may_print(eap);
+ }
+
+ if (!cmdmod.keeppatterns)
+ save_re_pat(RE_SUBST, pat, p_magic);
+#ifdef FEAT_CMDHIST
+ /* put pattern in history */
+ add_to_history(HIST_SEARCH, pat, TRUE, NUL);
+#endif
+
+ return;
+ }
+
+ /*
+ * Find trailing options. When '&' is used, keep old options.
+ */
+ if (*cmd == '&')
+ ++cmd;
+ else
+ {
+ if (!p_ed)
+ {
+ if (p_gd) /* default is global on */
+ subflags.do_all = TRUE;
+ else
+ subflags.do_all = FALSE;
+ subflags.do_ask = FALSE;
+ }
+ subflags.do_error = TRUE;
+ subflags.do_print = FALSE;
+ subflags.do_count = FALSE;
+ subflags.do_number = FALSE;
+ subflags.do_ic = 0;
+ }
+ while (*cmd)
+ {
+ /*
+ * Note that 'g' and 'c' are always inverted, also when p_ed is off.
+ * 'r' is never inverted.
+ */
+ if (*cmd == 'g')
+ subflags.do_all = !subflags.do_all;
+ else if (*cmd == 'c')
+ subflags.do_ask = !subflags.do_ask;
+ else if (*cmd == 'n')
+ subflags.do_count = TRUE;
+ else if (*cmd == 'e')
+ subflags.do_error = !subflags.do_error;
+ else if (*cmd == 'r') /* use last used regexp */
+ which_pat = RE_LAST;
+ else if (*cmd == 'p')
+ subflags.do_print = TRUE;
+ else if (*cmd == '#')
+ {
+ subflags.do_print = TRUE;
+ subflags.do_number = TRUE;
+ }
+ else if (*cmd == 'l')
+ {
+ subflags.do_print = TRUE;
+ subflags.do_list = TRUE;
+ }
+ else if (*cmd == 'i') /* ignore case */
+ subflags.do_ic = 'i';
+ else if (*cmd == 'I') /* don't ignore case */
+ subflags.do_ic = 'I';
+ else
+ break;
+ ++cmd;
+ }
+ if (subflags.do_count)
+ subflags.do_ask = FALSE;
+
+ save_do_all = subflags.do_all;
+ save_do_ask = subflags.do_ask;
+
+ /*
+ * check for a trailing count
+ */
+ cmd = skipwhite(cmd);
+ if (VIM_ISDIGIT(*cmd))
+ {
+ i = getdigits(&cmd);
+ if (i <= 0 && !eap->skip && subflags.do_error)
+ {
+ emsg(_(e_zerocount));
+ return;
+ }
+ eap->line1 = eap->line2;
+ eap->line2 += i - 1;
+ if (eap->line2 > curbuf->b_ml.ml_line_count)
+ eap->line2 = curbuf->b_ml.ml_line_count;
+ }
+
+ /*
+ * check for trailing command or garbage
+ */
+ cmd = skipwhite(cmd);
+ if (*cmd && *cmd != '"') /* if not end-of-line or comment */
+ {
+ eap->nextcmd = check_nextcmd(cmd);
+ if (eap->nextcmd == NULL)
+ {
+ emsg(_(e_trailing));
+ return;
+ }
+ }
+
+ if (eap->skip) /* not executing commands, only parsing */
+ return;
+
+ if (!subflags.do_count && !curbuf->b_p_ma)
+ {
+ /* Substitution is not allowed in non-'modifiable' buffer */
+ emsg(_(e_modifiable));
+ return;
+ }
+
+ if (search_regcomp(pat, RE_SUBST, which_pat, SEARCH_HIS, &regmatch) == FAIL)
+ {
+ if (subflags.do_error)
+ emsg(_(e_invcmd));
+ return;
+ }
+
+ /* the 'i' or 'I' flag overrules 'ignorecase' and 'smartcase' */
+ if (subflags.do_ic == 'i')
+ regmatch.rmm_ic = TRUE;
+ else if (subflags.do_ic == 'I')
+ regmatch.rmm_ic = FALSE;
+
+ sub_firstline = NULL;
+
+ /*
+ * ~ in the substitute pattern is replaced with the old pattern.
+ * We do it here once to avoid it to be replaced over and over again.
+ * But don't do it when it starts with "\=", then it's an expression.
+ */
+ if (!(sub[0] == '\\' && sub[1] == '='))
+ sub = regtilde(sub, p_magic);
+
+ /*
+ * Check for a match on each line.
+ */
+ line2 = eap->line2;
+ for (lnum = eap->line1; lnum <= line2 && !(got_quit
+#if defined(FEAT_EVAL)
+ || aborting()
+#endif
+ ); ++lnum)
+ {
+ nmatch = vim_regexec_multi(&regmatch, curwin, curbuf, lnum,
+ (colnr_T)0, NULL, NULL);
+ if (nmatch)
+ {
+ colnr_T copycol;
+ colnr_T matchcol;
+ colnr_T prev_matchcol = MAXCOL;
+ char_u *new_end, *new_start = NULL;
+ unsigned new_start_len = 0;
+ char_u *p1;
+ int did_sub = FALSE;
+ int lastone;
+ int len, copy_len, needed_len;
+ long nmatch_tl = 0; /* nr of lines matched below lnum */
+ int do_again; /* do it again after joining lines */
+ int skip_match = FALSE;
+ linenr_T sub_firstlnum; /* nr of first sub line */
+
+ /*
+ * The new text is build up step by step, to avoid too much
+ * copying. There are these pieces:
+ * sub_firstline The old text, unmodified.
+ * copycol Column in the old text where we started
+ * looking for a match; from here old text still
+ * needs to be copied to the new text.
+ * matchcol Column number of the old text where to look
+ * for the next match. It's just after the
+ * previous match or one further.
+ * prev_matchcol Column just after the previous match (if any).
+ * Mostly equal to matchcol, except for the first
+ * match and after skipping an empty match.
+ * regmatch.*pos Where the pattern matched in the old text.
+ * new_start The new text, all that has been produced so
+ * far.
+ * new_end The new text, where to append new text.
+ *
+ * lnum The line number where we found the start of
+ * the match. Can be below the line we searched
+ * when there is a \n before a \zs in the
+ * pattern.
+ * sub_firstlnum The line number in the buffer where to look
+ * for a match. Can be different from "lnum"
+ * when the pattern or substitute string contains
+ * line breaks.
+ *
+ * Special situations:
+ * - When the substitute string contains a line break, the part up
+ * to the line break is inserted in the text, but the copy of
+ * the original line is kept. "sub_firstlnum" is adjusted for
+ * the inserted lines.
+ * - When the matched pattern contains a line break, the old line
+ * is taken from the line at the end of the pattern. The lines
+ * in the match are deleted later, "sub_firstlnum" is adjusted
+ * accordingly.
+ *
+ * The new text is built up in new_start[]. It has some extra
+ * room to avoid using alloc()/free() too often. new_start_len is
+ * the length of the allocated memory at new_start.
+ *
+ * Make a copy of the old line, so it won't be taken away when
+ * updating the screen or handling a multi-line match. The "old_"
+ * pointers point into this copy.
+ */
+ sub_firstlnum = lnum;
+ copycol = 0;
+ matchcol = 0;
+
+ /* At first match, remember current cursor position. */
+ if (!got_match)
+ {
+ setpcmark();
+ got_match = TRUE;
+ }
+
+ /*
+ * Loop until nothing more to replace in this line.
+ * 1. Handle match with empty string.
+ * 2. If do_ask is set, ask for confirmation.
+ * 3. substitute the string.
+ * 4. if do_all is set, find next match
+ * 5. break if there isn't another match in this line
+ */
+ for (;;)
+ {
+ /* Advance "lnum" to the line where the match starts. The
+ * match does not start in the first line when there is a line
+ * break before \zs. */
+ if (regmatch.startpos[0].lnum > 0)
+ {
+ lnum += regmatch.startpos[0].lnum;
+ sub_firstlnum += regmatch.startpos[0].lnum;
+ nmatch -= regmatch.startpos[0].lnum;
+ VIM_CLEAR(sub_firstline);
+ }
+
+ if (sub_firstline == NULL)
+ {
+ sub_firstline = vim_strsave(ml_get(sub_firstlnum));
+ if (sub_firstline == NULL)
+ {
+ vim_free(new_start);
+ goto outofmem;
+ }
+ }
+
+ /* Save the line number of the last change for the final
+ * cursor position (just like Vi). */
+ curwin->w_cursor.lnum = lnum;
+ do_again = FALSE;
+
+ /*
+ * 1. Match empty string does not count, except for first
+ * match. This reproduces the strange vi behaviour.
+ * This also catches endless loops.
+ */
+ if (matchcol == prev_matchcol
+ && regmatch.endpos[0].lnum == 0
+ && matchcol == regmatch.endpos[0].col)
+ {
+ if (sub_firstline[matchcol] == NUL)
+ /* We already were at the end of the line. Don't look
+ * for a match in this line again. */
+ skip_match = TRUE;
+ else
+ {
+ /* search for a match at next column */
+ if (has_mbyte)
+ matchcol += mb_ptr2len(sub_firstline + matchcol);
+ else
+ ++matchcol;
+ }
+ goto skip;
+ }
+
+ /* Normally we continue searching for a match just after the
+ * previous match. */
+ matchcol = regmatch.endpos[0].col;
+ prev_matchcol = matchcol;
+
+ /*
+ * 2. If do_count is set only increase the counter.
+ * If do_ask is set, ask for confirmation.
+ */
+ if (subflags.do_count)
+ {
+ /* For a multi-line match, put matchcol at the NUL at
+ * the end of the line and set nmatch to one, so that
+ * we continue looking for a match on the next line.
+ * Avoids that ":s/\nB\@=//gc" get stuck. */
+ if (nmatch > 1)
+ {
+ matchcol = (colnr_T)STRLEN(sub_firstline);
+ nmatch = 1;
+ skip_match = TRUE;
+ }
+ sub_nsubs++;
+ did_sub = TRUE;
+#ifdef FEAT_EVAL
+ /* Skip the substitution, unless an expression is used,
+ * then it is evaluated in the sandbox. */
+ if (!(sub[0] == '\\' && sub[1] == '='))
+#endif
+ goto skip;
+ }
+
+ if (subflags.do_ask)
+ {
+ int typed = 0;
+
+ /* change State to CONFIRM, so that the mouse works
+ * properly */
+ save_State = State;
+ State = CONFIRM;
+#ifdef FEAT_MOUSE
+ setmouse(); /* disable mouse in xterm */
+#endif
+ curwin->w_cursor.col = regmatch.startpos[0].col;
+ if (curwin->w_p_crb)
+ do_check_cursorbind();
+
+ /* When 'cpoptions' contains "u" don't sync undo when
+ * asking for confirmation. */
+ if (vim_strchr(p_cpo, CPO_UNDO) != NULL)
+ ++no_u_sync;
+
+ /*
+ * Loop until 'y', 'n', 'q', CTRL-E or CTRL-Y typed.
+ */
+ while (subflags.do_ask)
+ {
+ if (exmode_active)
+ {
+ char_u *resp;
+ colnr_T sc, ec;
+
+ print_line_no_prefix(lnum,
+ subflags.do_number, subflags.do_list);
+
+ getvcol(curwin, &curwin->w_cursor, &sc, NULL, NULL);
+ curwin->w_cursor.col = regmatch.endpos[0].col - 1;
+ if (curwin->w_cursor.col < 0)
+ curwin->w_cursor.col = 0;
+ getvcol(curwin, &curwin->w_cursor, NULL, NULL, &ec);
+ if (subflags.do_number || curwin->w_p_nu)
+ {
+ int numw = number_width(curwin) + 1;
+ sc += numw;
+ ec += numw;
+ }
+ msg_start();
+ for (i = 0; i < (long)sc; ++i)
+ msg_putchar(' ');
+ for ( ; i <= (long)ec; ++i)
+ msg_putchar('^');
+
+ resp = getexmodeline('?', NULL, 0);
+ if (resp != NULL)
+ {
+ typed = *resp;
+ vim_free(resp);
+ }
+ }
+ else
+ {
+ char_u *orig_line = NULL;
+ int len_change = 0;
+#ifdef FEAT_FOLDING
+ int save_p_fen = curwin->w_p_fen;
+
+ curwin->w_p_fen = FALSE;
+#endif
+ /* Invert the matched string.
+ * Remove the inversion afterwards. */
+ temp = RedrawingDisabled;
+ RedrawingDisabled = 0;
+
+ if (new_start != NULL)
+ {
+ /* There already was a substitution, we would
+ * like to show this to the user. We cannot
+ * really update the line, it would change
+ * what matches. Temporarily replace the line
+ * and change it back afterwards. */
+ orig_line = vim_strsave(ml_get(lnum));
+ if (orig_line != NULL)
+ {
+ char_u *new_line = concat_str(new_start,
+ sub_firstline + copycol);
+
+ if (new_line == NULL)
+ VIM_CLEAR(orig_line);
+ else
+ {
+ /* Position the cursor relative to the
+ * end of the line, the previous
+ * substitute may have inserted or
+ * deleted characters before the
+ * cursor. */
+ len_change = (int)STRLEN(new_line)
+ - (int)STRLEN(orig_line);
+ curwin->w_cursor.col += len_change;
+ ml_replace(lnum, new_line, FALSE);
+ }
+ }
+ }
+
+ search_match_lines = regmatch.endpos[0].lnum
+ - regmatch.startpos[0].lnum;
+ search_match_endcol = regmatch.endpos[0].col
+ + len_change;
+ highlight_match = TRUE;
+
+ update_topline();
+ validate_cursor();
+ update_screen(SOME_VALID);
+ highlight_match = FALSE;
+ redraw_later(SOME_VALID);
+
+#ifdef FEAT_FOLDING
+ curwin->w_p_fen = save_p_fen;
+#endif
+ if (msg_row == Rows - 1)
+ msg_didout = FALSE; /* avoid a scroll-up */
+ msg_starthere();
+ i = msg_scroll;
+ msg_scroll = 0; /* truncate msg when
+ needed */
+ msg_no_more = TRUE;
+ /* write message same highlighting as for
+ * wait_return */
+ smsg_attr(HL_ATTR(HLF_R),
+ _("replace with %s (y/n/a/q/l/^E/^Y)?"), sub);
+ msg_no_more = FALSE;
+ msg_scroll = i;
+ showruler(TRUE);
+ windgoto(msg_row, msg_col);
+ RedrawingDisabled = temp;
+
+#ifdef USE_ON_FLY_SCROLL
+ dont_scroll = FALSE; /* allow scrolling here */
+#endif
+ ++no_mapping; /* don't map this key */
+ ++allow_keys; /* allow special keys */
+ typed = plain_vgetc();
+ --allow_keys;
+ --no_mapping;
+
+ /* clear the question */
+ msg_didout = FALSE; /* don't scroll up */
+ msg_col = 0;
+ gotocmdline(TRUE);
+
+ /* restore the line */
+ if (orig_line != NULL)
+ ml_replace(lnum, orig_line, FALSE);
+ }
+
+ need_wait_return = FALSE; /* no hit-return prompt */
+ if (typed == 'q' || typed == ESC || typed == Ctrl_C
+#ifdef UNIX
+ || typed == intr_char
+#endif
+ )
+ {
+ got_quit = TRUE;
+ break;
+ }
+ if (typed == 'n')
+ break;
+ if (typed == 'y')
+ break;
+ if (typed == 'l')
+ {
+ /* last: replace and then stop */
+ subflags.do_all = FALSE;
+ line2 = lnum;
+ break;
+ }
+ if (typed == 'a')
+ {
+ subflags.do_ask = FALSE;
+ break;
+ }
+#ifdef FEAT_INS_EXPAND
+ if (typed == Ctrl_E)
+ scrollup_clamp();
+ else if (typed == Ctrl_Y)
+ scrolldown_clamp();
+#endif
+ }
+ State = save_State;
+#ifdef FEAT_MOUSE
+ setmouse();
+#endif
+ if (vim_strchr(p_cpo, CPO_UNDO) != NULL)
+ --no_u_sync;
+
+ if (typed == 'n')
+ {
+ /* For a multi-line match, put matchcol at the NUL at
+ * the end of the line and set nmatch to one, so that
+ * we continue looking for a match on the next line.
+ * Avoids that ":%s/\nB\@=//gc" and ":%s/\n/,\r/gc"
+ * get stuck when pressing 'n'. */
+ if (nmatch > 1)
+ {
+ matchcol = (colnr_T)STRLEN(sub_firstline);
+ skip_match = TRUE;
+ }
+ goto skip;
+ }
+ if (got_quit)
+ goto skip;
+ }
+
+ /* Move the cursor to the start of the match, so that we can
+ * use "\=col("."). */
+ curwin->w_cursor.col = regmatch.startpos[0].col;
+
+ /*
+ * 3. substitute the string.
+ */
+#ifdef FEAT_EVAL
+ if (subflags.do_count)
+ {
+ /* prevent accidentally changing the buffer by a function */
+ save_ma = curbuf->b_p_ma;
+ curbuf->b_p_ma = FALSE;
+ sandbox++;
+ }
+ /* Save flags for recursion. They can change for e.g.
+ * :s/^/\=execute("s#^##gn") */
+ subflags_save = subflags;
+#endif
+ /* get length of substitution part */
+ sublen = vim_regsub_multi(&regmatch,
+ sub_firstlnum - regmatch.startpos[0].lnum,
+ sub, sub_firstline, FALSE, p_magic, TRUE);
+#ifdef FEAT_EVAL
+ /* Don't keep flags set by a recursive call. */
+ subflags = subflags_save;
+ if (subflags.do_count)
+ {
+ curbuf->b_p_ma = save_ma;
+ if (sandbox > 0)
+ sandbox--;
+ goto skip;
+ }
+#endif
+
+ /* When the match included the "$" of the last line it may
+ * go beyond the last line of the buffer. */
+ if (nmatch > curbuf->b_ml.ml_line_count - sub_firstlnum + 1)
+ {
+ nmatch = curbuf->b_ml.ml_line_count - sub_firstlnum + 1;
+ skip_match = TRUE;
+ }
+
+ /* Need room for:
+ * - result so far in new_start (not for first sub in line)
+ * - original text up to match
+ * - length of substituted part
+ * - original text after match
+ * Adjust text properties here, since we have all information
+ * needed.
+ */
+ if (nmatch == 1)
+ {
+ p1 = sub_firstline;
+#ifdef FEAT_TEXT_PROP
+ if (curbuf->b_has_textprop)
+ adjust_prop_columns(lnum, regmatch.startpos[0].col,
+ sublen - 1 - (regmatch.endpos[0].col
+ - regmatch.startpos[0].col));
+#endif
+ }
+ else
+ {
+ p1 = ml_get(sub_firstlnum + nmatch - 1);
+ nmatch_tl += nmatch - 1;
+ }
+ copy_len = regmatch.startpos[0].col - copycol;
+ needed_len = copy_len + ((unsigned)STRLEN(p1)
+ - regmatch.endpos[0].col) + sublen + 1;
+ if (new_start == NULL)
+ {
+ /*
+ * Get some space for a temporary buffer to do the
+ * substitution into (and some extra space to avoid
+ * too many calls to alloc()/free()).
+ */
+ new_start_len = needed_len + 50;
+ if ((new_start = alloc_check(new_start_len)) == NULL)
+ goto outofmem;
+ *new_start = NUL;
+ new_end = new_start;
+ }
+ else
+ {
+ /*
+ * Check if the temporary buffer is long enough to do the
+ * substitution into. If not, make it larger (with a bit
+ * extra to avoid too many calls to alloc()/free()).
+ */
+ len = (unsigned)STRLEN(new_start);
+ needed_len += len;
+ if (needed_len > (int)new_start_len)
+ {
+ new_start_len = needed_len + 50;
+ if ((p1 = alloc_check(new_start_len)) == NULL)
+ {
+ vim_free(new_start);
+ goto outofmem;
+ }
+ mch_memmove(p1, new_start, (size_t)(len + 1));
+ vim_free(new_start);
+ new_start = p1;
+ }
+ new_end = new_start + len;
+ }
+
+ /*
+ * copy the text up to the part that matched
+ */
+ mch_memmove(new_end, sub_firstline + copycol, (size_t)copy_len);
+ new_end += copy_len;
+
+ (void)vim_regsub_multi(&regmatch,
+ sub_firstlnum - regmatch.startpos[0].lnum,
+ sub, new_end, TRUE, p_magic, TRUE);
+ sub_nsubs++;
+ did_sub = TRUE;
+
+ /* Move the cursor to the start of the line, to avoid that it
+ * is beyond the end of the line after the substitution. */
+ curwin->w_cursor.col = 0;
+
+ /* For a multi-line match, make a copy of the last matched
+ * line and continue in that one. */
+ if (nmatch > 1)
+ {
+ sub_firstlnum += nmatch - 1;
+ vim_free(sub_firstline);
+ sub_firstline = vim_strsave(ml_get(sub_firstlnum));
+ /* When going beyond the last line, stop substituting. */
+ if (sub_firstlnum <= line2)
+ do_again = TRUE;
+ else
+ subflags.do_all = FALSE;
+ }
+
+ /* Remember next character to be copied. */
+ copycol = regmatch.endpos[0].col;
+
+ if (skip_match)
+ {
+ /* Already hit end of the buffer, sub_firstlnum is one
+ * less than what it ought to be. */
+ vim_free(sub_firstline);
+ sub_firstline = vim_strsave((char_u *)"");
+ copycol = 0;
+ }
+
+ /*
+ * Now the trick is to replace CTRL-M chars with a real line
+ * break. This would make it impossible to insert a CTRL-M in
+ * the text. The line break can be avoided by preceding the
+ * CTRL-M with a backslash. To be able to insert a backslash,
+ * they must be doubled in the string and are halved here.
+ * That is Vi compatible.
+ */
+ for (p1 = new_end; *p1; ++p1)
+ {
+ if (p1[0] == '\\' && p1[1] != NUL) /* remove backslash */
+ STRMOVE(p1, p1 + 1);
+ else if (*p1 == CAR)
+ {
+ if (u_inssub(lnum) == OK) // prepare for undo
+ {
+ colnr_T plen = (colnr_T)(p1 - new_start + 1);
+
+ *p1 = NUL; // truncate up to the CR
+ ml_append(lnum - 1, new_start, plen, FALSE);
+ mark_adjust(lnum + 1, (linenr_T)MAXLNUM, 1L, 0L);
+ if (subflags.do_ask)
+ appended_lines(lnum - 1, 1L);
+ else
+ {
+ if (first_line == 0)
+ first_line = lnum;
+ last_line = lnum + 1;
+ }
+#ifdef FEAT_TEXT_PROP
+ adjust_props_for_split(lnum, plen, 1);
+#endif
+ // all line numbers increase
+ ++sub_firstlnum;
+ ++lnum;
+ ++line2;
+ // move the cursor to the new line, like Vi
+ ++curwin->w_cursor.lnum;
+ // copy the rest
+ STRMOVE(new_start, p1 + 1);
+ p1 = new_start - 1;
+ }
+ }
+ else if (has_mbyte)
+ p1 += (*mb_ptr2len)(p1) - 1;
+ }
+
+ /*
+ * 4. If do_all is set, find next match.
+ * Prevent endless loop with patterns that match empty
+ * strings, e.g. :s/$/pat/g or :s/[a-z]* /(&)/g.
+ * But ":s/\n/#/" is OK.
+ */
+skip:
+ /* We already know that we did the last subst when we are at
+ * the end of the line, except that a pattern like
+ * "bar\|\nfoo" may match at the NUL. "lnum" can be below
+ * "line2" when there is a \zs in the pattern after a line
+ * break. */
+ lastone = (skip_match
+ || got_int
+ || got_quit
+ || lnum > line2
+ || !(subflags.do_all || do_again)
+ || (sub_firstline[matchcol] == NUL && nmatch <= 1
+ && !re_multiline(regmatch.regprog)));
+ nmatch = -1;
+
+ /*
+ * Replace the line in the buffer when needed. This is
+ * skipped when there are more matches.
+ * The check for nmatch_tl is needed for when multi-line
+ * matching must replace the lines before trying to do another
+ * match, otherwise "\@<=" won't work.
+ * When the match starts below where we start searching also
+ * need to replace the line first (using \zs after \n).
+ */
+ if (lastone
+ || nmatch_tl > 0
+ || (nmatch = vim_regexec_multi(&regmatch, curwin,
+ curbuf, sub_firstlnum,
+ matchcol, NULL, NULL)) == 0
+ || regmatch.startpos[0].lnum > 0)
+ {
+ if (new_start != NULL)
+ {
+ /*
+ * Copy the rest of the line, that didn't match.
+ * "matchcol" has to be adjusted, we use the end of
+ * the line as reference, because the substitute may
+ * have changed the number of characters. Same for
+ * "prev_matchcol".
+ */
+ STRCAT(new_start, sub_firstline + copycol);
+ matchcol = (colnr_T)STRLEN(sub_firstline) - matchcol;
+ prev_matchcol = (colnr_T)STRLEN(sub_firstline)
+ - prev_matchcol;
+
+ if (u_savesub(lnum) != OK)
+ break;
+ ml_replace(lnum, new_start, TRUE);
+
+ if (nmatch_tl > 0)
+ {
+ /*
+ * Matched lines have now been substituted and are
+ * useless, delete them. The part after the match
+ * has been appended to new_start, we don't need
+ * it in the buffer.
+ */
+ ++lnum;
+ if (u_savedel(lnum, nmatch_tl) != OK)
+ break;
+ for (i = 0; i < nmatch_tl; ++i)
+ ml_delete(lnum, (int)FALSE);
+ mark_adjust(lnum, lnum + nmatch_tl - 1,
+ (long)MAXLNUM, -nmatch_tl);
+ if (subflags.do_ask)
+ deleted_lines(lnum, nmatch_tl);
+ --lnum;
+ line2 -= nmatch_tl; /* nr of lines decreases */
+ nmatch_tl = 0;
+ }
+
+ /* When asking, undo is saved each time, must also set
+ * changed flag each time. */
+ if (subflags.do_ask)
+ changed_bytes(lnum, 0);
+ else
+ {
+ if (first_line == 0)
+ first_line = lnum;
+ last_line = lnum + 1;
+ }
+
+ sub_firstlnum = lnum;
+ vim_free(sub_firstline); /* free the temp buffer */
+ sub_firstline = new_start;
+ new_start = NULL;
+ matchcol = (colnr_T)STRLEN(sub_firstline) - matchcol;
+ prev_matchcol = (colnr_T)STRLEN(sub_firstline)
+ - prev_matchcol;
+ copycol = 0;
+ }
+ if (nmatch == -1 && !lastone)
+ nmatch = vim_regexec_multi(&regmatch, curwin, curbuf,
+ sub_firstlnum, matchcol, NULL, NULL);
+
+ /*
+ * 5. break if there isn't another match in this line
+ */
+ if (nmatch <= 0)
+ {
+ /* If the match found didn't start where we were
+ * searching, do the next search in the line where we
+ * found the match. */
+ if (nmatch == -1)
+ lnum -= regmatch.startpos[0].lnum;
+ break;
+ }
+ }
+
+ line_breakcheck();
+ }
+
+ if (did_sub)
+ ++sub_nlines;
+ vim_free(new_start); /* for when substitute was cancelled */
+ VIM_CLEAR(sub_firstline); /* free the copy of the original line */
+ }
+
+ line_breakcheck();
+ }
+
+ if (first_line != 0)
+ {
+ /* Need to subtract the number of added lines from "last_line" to get
+ * the line number before the change (same as adding the number of
+ * deleted lines). */
+ i = curbuf->b_ml.ml_line_count - old_line_count;
+ changed_lines(first_line, 0, last_line - i, i);
+ }
+
+outofmem:
+ vim_free(sub_firstline); /* may have to free allocated copy of the line */
+
+ /* ":s/pat//n" doesn't move the cursor */
+ if (subflags.do_count)
+ curwin->w_cursor = old_cursor;
+
+ if (sub_nsubs > start_nsubs)
+ {
+ /* Set the '[ and '] marks. */
+ curbuf->b_op_start.lnum = eap->line1;
+ curbuf->b_op_end.lnum = line2;
+ curbuf->b_op_start.col = curbuf->b_op_end.col = 0;
+
+ if (!global_busy)
+ {
+ /* when interactive leave cursor on the match */
+ if (!subflags.do_ask)
+ {
+ if (endcolumn)
+ coladvance((colnr_T)MAXCOL);
+ else
+ beginline(BL_WHITE | BL_FIX);
+ }
+ if (!do_sub_msg(subflags.do_count) && subflags.do_ask)
+ msg("");
+ }
+ else
+ global_need_beginline = TRUE;
+ if (subflags.do_print)
+ print_line(curwin->w_cursor.lnum,
+ subflags.do_number, subflags.do_list);
+ }
+ else if (!global_busy)
+ {
+ if (got_int) /* interrupted */
+ emsg(_(e_interr));
+ else if (got_match) /* did find something but nothing substituted */
+ msg("");
+ else if (subflags.do_error) /* nothing found */
+ semsg(_(e_patnotf2), get_search_pat());
+ }
+
+#ifdef FEAT_FOLDING
+ if (subflags.do_ask && hasAnyFolding(curwin))
+ /* Cursor position may require updating */
+ changed_window_setting();
+#endif
+
+ vim_regfree(regmatch.regprog);
+
+ /* Restore the flag values, they can be used for ":&&". */
+ subflags.do_all = save_do_all;
+ subflags.do_ask = save_do_ask;
+}
+
+/*
+ * Give message for number of substitutions.
+ * Can also be used after a ":global" command.
+ * Return TRUE if a message was given.
+ */
+ int
+do_sub_msg(
+ int count_only) /* used 'n' flag for ":s" */
+{
+ /*
+ * Only report substitutions when:
+ * - more than 'report' substitutions
+ * - command was typed by user, or number of changed lines > 'report'
+ * - giving messages is not disabled by 'lazyredraw'
+ */
+ if (((sub_nsubs > p_report && (KeyTyped || sub_nlines > 1 || p_report < 1))
+ || count_only)
+ && messaging())
+ {
+ char *msg_single;
+ char *msg_plural;
+
+ if (got_int)
+ STRCPY(msg_buf, _("(Interrupted) "));
+ else
+ *msg_buf = NUL;
+
+ msg_single = count_only
+ ? NGETTEXT("%ld match on %ld line",
+ "%ld matches on %ld line", sub_nsubs)
+ : NGETTEXT("%ld substitution on %ld line",
+ "%ld substitutions on %ld line", sub_nsubs);
+ msg_plural = count_only
+ ? NGETTEXT("%ld match on %ld lines",
+ "%ld matches on %ld lines", sub_nsubs)
+ : NGETTEXT("%ld substitution on %ld lines",
+ "%ld substitutions on %ld lines", sub_nsubs);
+
+ vim_snprintf_add(msg_buf, sizeof(msg_buf),
+ NGETTEXT(msg_single, msg_plural, sub_nlines),
+ sub_nsubs, (long)sub_nlines);
+
+ if (msg(msg_buf))
+ /* save message to display it after redraw */
+ set_keep_msg((char_u *)msg_buf, 0);
+ return TRUE;
+ }
+ if (got_int)
+ {
+ emsg(_(e_interr));
+ return TRUE;
+ }
+ return FALSE;
+}
+
+ static void
+global_exe_one(char_u *cmd, linenr_T lnum)
+{
+ curwin->w_cursor.lnum = lnum;
+ curwin->w_cursor.col = 0;
+ if (*cmd == NUL || *cmd == '\n')
+ do_cmdline((char_u *)"p", NULL, NULL, DOCMD_NOWAIT);
+ else
+ do_cmdline(cmd, NULL, NULL, DOCMD_NOWAIT);
+}
+
+/*
+ * Execute a global command of the form:
+ *
+ * g/pattern/X : execute X on all lines where pattern matches
+ * v/pattern/X : execute X on all lines where pattern does not match
+ *
+ * where 'X' is an EX command
+ *
+ * The command character (as well as the trailing slash) is optional, and
+ * is assumed to be 'p' if missing.
+ *
+ * This is implemented in two passes: first we scan the file for the pattern and
+ * set a mark for each line that (not) matches. Secondly we execute the command
+ * for each line that has a mark. This is required because after deleting
+ * lines we do not know where to search for the next match.
+ */
+ void
+ex_global(exarg_T *eap)
+{
+ linenr_T lnum; /* line number according to old situation */
+ int ndone = 0;
+ int type; /* first char of cmd: 'v' or 'g' */
+ char_u *cmd; /* command argument */
+
+ char_u delim; /* delimiter, normally '/' */
+ char_u *pat;
+ regmmatch_T regmatch;
+ int match;
+ int which_pat;
+
+ /* When nesting the command works on one line. This allows for
+ * ":g/found/v/notfound/command". */
+ if (global_busy && (eap->line1 != 1
+ || eap->line2 != curbuf->b_ml.ml_line_count))
+ {
+ /* will increment global_busy to break out of the loop */
+ emsg(_("E147: Cannot do :global recursive with a range"));
+ return;
+ }
+
+ if (eap->forceit) /* ":global!" is like ":vglobal" */
+ type = 'v';
+ else
+ type = *eap->cmd;
+ cmd = eap->arg;
+ which_pat = RE_LAST; /* default: use last used regexp */
+
+ /*
+ * undocumented vi feature:
+ * "\/" and "\?": use previous search pattern.
+ * "\&": use previous substitute pattern.
+ */
+ if (*cmd == '\\')
+ {
+ ++cmd;
+ if (vim_strchr((char_u *)"/?&", *cmd) == NULL)
+ {
+ emsg(_(e_backslash));
+ return;
+ }
+ if (*cmd == '&')
+ which_pat = RE_SUBST; /* use previous substitute pattern */
+ else
+ which_pat = RE_SEARCH; /* use previous search pattern */
+ ++cmd;
+ pat = (char_u *)"";
+ }
+ else if (*cmd == NUL)
+ {
+ emsg(_("E148: Regular expression missing from global"));
+ return;
+ }
+ else
+ {
+ delim = *cmd; /* get the delimiter */
+ if (delim)
+ ++cmd; /* skip delimiter if there is one */
+ pat = cmd; /* remember start of pattern */
+ cmd = skip_regexp(cmd, delim, p_magic, &eap->arg);
+ if (cmd[0] == delim) /* end delimiter found */
+ *cmd++ = NUL; /* replace it with a NUL */
+ }
+
+#ifdef FEAT_FKMAP /* when in Farsi mode, reverse the character flow */
+ if (p_altkeymap && curwin->w_p_rl)
+ lrFswap(pat,0);
+#endif
+
+ if (search_regcomp(pat, RE_BOTH, which_pat, SEARCH_HIS, &regmatch) == FAIL)
+ {
+ emsg(_(e_invcmd));
+ return;
+ }
+
+ if (global_busy)
+ {
+ lnum = curwin->w_cursor.lnum;
+ match = vim_regexec_multi(&regmatch, curwin, curbuf, lnum,
+ (colnr_T)0, NULL, NULL);
+ if ((type == 'g' && match) || (type == 'v' && !match))
+ global_exe_one(cmd, lnum);
+ }
+ else
+ {
+ /*
+ * pass 1: set marks for each (not) matching line
+ */
+ for (lnum = eap->line1; lnum <= eap->line2 && !got_int; ++lnum)
+ {
+ /* a match on this line? */
+ match = vim_regexec_multi(&regmatch, curwin, curbuf, lnum,
+ (colnr_T)0, NULL, NULL);
+ if ((type == 'g' && match) || (type == 'v' && !match))
+ {
+ ml_setmarked(lnum);
+ ndone++;
+ }
+ line_breakcheck();
+ }
+
+ /*
+ * pass 2: execute the command for each line that has been marked
+ */
+ if (got_int)
+ msg(_(e_interr));
+ else if (ndone == 0)
+ {
+ if (type == 'v')
+ smsg(_("Pattern found in every line: %s"), pat);
+ else
+ smsg(_("Pattern not found: %s"), pat);
+ }
+ else
+ {
+#ifdef FEAT_CLIPBOARD
+ start_global_changes();
+#endif
+ global_exe(cmd);
+#ifdef FEAT_CLIPBOARD
+ end_global_changes();
+#endif
+ }
+
+ ml_clearmarked(); /* clear rest of the marks */
+ }
+
+ vim_regfree(regmatch.regprog);
+}
+
+/*
+ * Execute "cmd" on lines marked with ml_setmarked().
+ */
+ void
+global_exe(char_u *cmd)
+{
+ linenr_T old_lcount; /* b_ml.ml_line_count before the command */
+ buf_T *old_buf = curbuf; /* remember what buffer we started in */
+ linenr_T lnum; /* line number according to old situation */
+
+ /*
+ * Set current position only once for a global command.
+ * If global_busy is set, setpcmark() will not do anything.
+ * If there is an error, global_busy will be incremented.
+ */
+ setpcmark();
+
+ /* When the command writes a message, don't overwrite the command. */
+ msg_didout = TRUE;
+
+ sub_nsubs = 0;
+ sub_nlines = 0;
+ global_need_beginline = FALSE;
+ global_busy = 1;
+ old_lcount = curbuf->b_ml.ml_line_count;
+ while (!got_int && (lnum = ml_firstmarked()) != 0 && global_busy == 1)
+ {
+ global_exe_one(cmd, lnum);
+ ui_breakcheck();
+ }
+
+ global_busy = 0;
+ if (global_need_beginline)
+ beginline(BL_WHITE | BL_FIX);
+ else
+ check_cursor(); /* cursor may be beyond the end of the line */
+
+ /* the cursor may not have moved in the text but a change in a previous
+ * line may move it on the screen */
+ changed_line_abv_curs();
+
+ /* If it looks like no message was written, allow overwriting the
+ * command with the report for number of changes. */
+ if (msg_col == 0 && msg_scrolled == 0)
+ msg_didout = FALSE;
+
+ /* If substitutes done, report number of substitutes, otherwise report
+ * number of extra or deleted lines.
+ * Don't report extra or deleted lines in the edge case where the buffer
+ * we are in after execution is different from the buffer we started in. */
+ if (!do_sub_msg(FALSE) && curbuf == old_buf)
+ msgmore(curbuf->b_ml.ml_line_count - old_lcount);
+}
+
+#ifdef FEAT_VIMINFO
+ int
+read_viminfo_sub_string(vir_T *virp, int force)
+{
+ if (force)
+ vim_free(old_sub);
+ if (force || old_sub == NULL)
+ old_sub = viminfo_readstring(virp, 1, TRUE);
+ return viminfo_readline(virp);
+}
+
+ void
+write_viminfo_sub_string(FILE *fp)
+{
+ if (get_viminfo_parameter('/') != 0 && old_sub != NULL)
+ {
+ fputs(_("\n# Last Substitute String:\n$"), fp);
+ viminfo_writestring(fp, old_sub);
+ }
+}
+#endif /* FEAT_VIMINFO */
+
+#if defined(EXITFREE) || defined(PROTO)
+ void
+free_old_sub(void)
+{
+ vim_free(old_sub);
+}
+#endif
+
+#if defined(FEAT_QUICKFIX) || defined(PROTO)
+/*
+ * Set up for a tagpreview.
+ * Return TRUE when it was created.
+ */
+ int
+prepare_tagpreview(
+ int undo_sync) /* sync undo when leaving the window */
+{
+ win_T *wp;
+
+# ifdef FEAT_GUI
+ need_mouse_correct = TRUE;
+# endif
+
+ /*
+ * If there is already a preview window open, use that one.
+ */
+ if (!curwin->w_p_pvw)
+ {
+ FOR_ALL_WINDOWS(wp)
+ if (wp->w_p_pvw)
+ break;
+ if (wp != NULL)
+ win_enter(wp, undo_sync);
+ else
+ {
+ /*
+ * There is no preview window open yet. Create one.
+ */
+ if (win_split(g_do_tagpreview > 0 ? g_do_tagpreview : 0, 0)
+ == FAIL)
+ return FALSE;
+ curwin->w_p_pvw = TRUE;
+ curwin->w_p_wfh = TRUE;
+ RESET_BINDING(curwin); /* don't take over 'scrollbind'
+ and 'cursorbind' */
+# ifdef FEAT_DIFF
+ curwin->w_p_diff = FALSE; /* no 'diff' */
+# endif
+# ifdef FEAT_FOLDING
+ curwin->w_p_fdc = 0; /* no 'foldcolumn' */
+# endif
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+#endif
+
+
+/*
+ * ":help": open a read-only window on a help file
+ */
+ void
+ex_help(exarg_T *eap)
+{
+ char_u *arg;
+ char_u *tag;
+ FILE *helpfd; /* file descriptor of help file */
+ int n;
+ int i;
+ win_T *wp;
+ int num_matches;
+ char_u **matches;
+ char_u *p;
+ int empty_fnum = 0;
+ int alt_fnum = 0;
+ buf_T *buf;
+#ifdef FEAT_MULTI_LANG
+ int len;
+ char_u *lang;
+#endif
+#ifdef FEAT_FOLDING
+ int old_KeyTyped = KeyTyped;
+#endif
+
+ if (eap != NULL)
+ {
+ /*
+ * A ":help" command ends at the first LF, or at a '|' that is
+ * followed by some text. Set nextcmd to the following command.
+ */
+ for (arg = eap->arg; *arg; ++arg)
+ {
+ if (*arg == '\n' || *arg == '\r'
+ || (*arg == '|' && arg[1] != NUL && arg[1] != '|'))
+ {
+ *arg++ = NUL;
+ eap->nextcmd = arg;
+ break;
+ }
+ }
+ arg = eap->arg;
+
+ if (eap->forceit && *arg == NUL && !curbuf->b_help)
+ {
+ emsg(_("E478: Don't panic!"));
+ return;
+ }
+
+ if (eap->skip) /* not executing commands */
+ return;
+ }
+ else
+ arg = (char_u *)"";
+
+ /* remove trailing blanks */
+ p = arg + STRLEN(arg) - 1;
+ while (p > arg && VIM_ISWHITE(*p) && p[-1] != '\\')
+ *p-- = NUL;
+
+#ifdef FEAT_MULTI_LANG
+ /* Check for a specified language */
+ lang = check_help_lang(arg);
+#endif
+
+ /* When no argument given go to the index. */
+ if (*arg == NUL)
+ arg = (char_u *)"help.txt";
+
+ /*
+ * Check if there is a match for the argument.
+ */
+ n = find_help_tags(arg, &num_matches, &matches,
+ eap != NULL && eap->forceit);
+
+ i = 0;
+#ifdef FEAT_MULTI_LANG
+ if (n != FAIL && lang != NULL)
+ /* Find first item with the requested language. */
+ for (i = 0; i < num_matches; ++i)
+ {
+ len = (int)STRLEN(matches[i]);
+ if (len > 3 && matches[i][len - 3] == '@'
+ && STRICMP(matches[i] + len - 2, lang) == 0)
+ break;
+ }
+#endif
+ if (i >= num_matches || n == FAIL)
+ {
+#ifdef FEAT_MULTI_LANG
+ if (lang != NULL)
+ semsg(_("E661: Sorry, no '%s' help for %s"), lang, arg);
+ else
+#endif
+ semsg(_("E149: Sorry, no help for %s"), arg);
+ if (n != FAIL)
+ FreeWild(num_matches, matches);
+ return;
+ }
+
+ /* The first match (in the requested language) is the best match. */
+ tag = vim_strsave(matches[i]);
+ FreeWild(num_matches, matches);
+
+#ifdef FEAT_GUI
+ need_mouse_correct = TRUE;
+#endif
+
+ /*
+ * Re-use an existing help window or open a new one.
+ * Always open a new one for ":tab help".
+ */
+ if (!bt_help(curwin->w_buffer) || cmdmod.tab != 0)
+ {
+ if (cmdmod.tab != 0)
+ wp = NULL;
+ else
+ FOR_ALL_WINDOWS(wp)
+ if (bt_help(wp->w_buffer))
+ break;
+ if (wp != NULL && wp->w_buffer->b_nwindows > 0)
+ win_enter(wp, TRUE);
+ else
+ {
+ /*
+ * There is no help window yet.
+ * Try to open the file specified by the "helpfile" option.
+ */
+ if ((helpfd = mch_fopen((char *)p_hf, READBIN)) == NULL)
+ {
+ smsg(_("Sorry, help file \"%s\" not found"), p_hf);
+ goto erret;
+ }
+ fclose(helpfd);
+
+ /* Split off help window; put it at far top if no position
+ * specified, the current window is vertically split and
+ * narrow. */
+ n = WSP_HELP;
+ if (cmdmod.split == 0 && curwin->w_width != Columns
+ && curwin->w_width < 80)
+ n |= WSP_TOP;
+ if (win_split(0, n) == FAIL)
+ goto erret;
+
+ if (curwin->w_height < p_hh)
+ win_setheight((int)p_hh);
+
+ /*
+ * Open help file (do_ecmd() will set b_help flag, readfile() will
+ * set b_p_ro flag).
+ * Set the alternate file to the previously edited file.
+ */
+ alt_fnum = curbuf->b_fnum;
+ (void)do_ecmd(0, NULL, NULL, NULL, ECMD_LASTL,
+ ECMD_HIDE + ECMD_SET_HELP,
+ NULL); /* buffer is still open, don't store info */
+ if (!cmdmod.keepalt)
+ curwin->w_alt_fnum = alt_fnum;
+ empty_fnum = curbuf->b_fnum;
+ }
+ }
+
+ if (!p_im)
+ restart_edit = 0; /* don't want insert mode in help file */
+
+#ifdef FEAT_FOLDING
+ /* Restore KeyTyped, setting 'filetype=help' may reset it.
+ * It is needed for do_tag top open folds under the cursor. */
+ KeyTyped = old_KeyTyped;
+#endif
+
+ if (tag != NULL)
+ do_tag(tag, DT_HELP, 1, FALSE, TRUE);
+
+ /* Delete the empty buffer if we're not using it. Careful: autocommands
+ * may have jumped to another window, check that the buffer is not in a
+ * window. */
+ if (empty_fnum != 0 && curbuf->b_fnum != empty_fnum)
+ {
+ buf = buflist_findnr(empty_fnum);
+ if (buf != NULL && buf->b_nwindows == 0)
+ wipe_buffer(buf, TRUE);
+ }
+
+ /* keep the previous alternate file */
+ if (alt_fnum != 0 && curwin->w_alt_fnum == empty_fnum && !cmdmod.keepalt)
+ curwin->w_alt_fnum = alt_fnum;
+
+erret:
+ vim_free(tag);
+}
+
+/*
+ * ":helpclose": Close one help window
+ */
+ void
+ex_helpclose(exarg_T *eap UNUSED)
+{
+ win_T *win;
+
+ FOR_ALL_WINDOWS(win)
+ {
+ if (bt_help(win->w_buffer))
+ {
+ win_close(win, FALSE);
+ return;
+ }
+ }
+}
+
+#if defined(FEAT_MULTI_LANG) || defined(PROTO)
+/*
+ * In an argument search for a language specifiers in the form "@xx".
+ * Changes the "@" to NUL if found, and returns a pointer to "xx".
+ * Returns NULL if not found.
+ */
+ char_u *
+check_help_lang(char_u *arg)
+{
+ int len = (int)STRLEN(arg);
+
+ if (len >= 3 && arg[len - 3] == '@' && ASCII_ISALPHA(arg[len - 2])
+ && ASCII_ISALPHA(arg[len - 1]))
+ {
+ arg[len - 3] = NUL; /* remove the '@' */
+ return arg + len - 2;
+ }
+ return NULL;
+}
+#endif
+
+/*
+ * Return a heuristic indicating how well the given string matches. The
+ * smaller the number, the better the match. This is the order of priorities,
+ * from best match to worst match:
+ * - Match with least alpha-numeric characters is better.
+ * - Match with least total characters is better.
+ * - Match towards the start is better.
+ * - Match starting with "+" is worse (feature instead of command)
+ * Assumption is made that the matched_string passed has already been found to
+ * match some string for which help is requested. webb.
+ */
+ int
+help_heuristic(
+ char_u *matched_string,
+ int offset, /* offset for match */
+ int wrong_case) /* no matching case */
+{
+ int num_letters;
+ char_u *p;
+
+ num_letters = 0;
+ for (p = matched_string; *p; p++)
+ if (ASCII_ISALNUM(*p))
+ num_letters++;
+
+ /*
+ * Multiply the number of letters by 100 to give it a much bigger
+ * weighting than the number of characters.
+ * If there only is a match while ignoring case, add 5000.
+ * If the match starts in the middle of a word, add 10000 to put it
+ * somewhere in the last half.
+ * If the match is more than 2 chars from the start, multiply by 200 to
+ * put it after matches at the start.
+ */
+ if (ASCII_ISALNUM(matched_string[offset]) && offset > 0
+ && ASCII_ISALNUM(matched_string[offset - 1]))
+ offset += 10000;
+ else if (offset > 2)
+ offset *= 200;
+ if (wrong_case)
+ offset += 5000;
+ /* Features are less interesting than the subjects themselves, but "+"
+ * alone is not a feature. */
+ if (matched_string[0] == '+' && matched_string[1] != NUL)
+ offset += 100;
+ return (int)(100 * num_letters + STRLEN(matched_string) + offset);
+}
+
+/*
+ * Compare functions for qsort() below, that checks the help heuristics number
+ * that has been put after the tagname by find_tags().
+ */
+ static int
+#ifdef __BORLANDC__
+_RTLENTRYF
+#endif
+help_compare(const void *s1, const void *s2)
+{
+ char *p1;
+ char *p2;
+
+ p1 = *(char **)s1 + strlen(*(char **)s1) + 1;
+ p2 = *(char **)s2 + strlen(*(char **)s2) + 1;
+ return strcmp(p1, p2);
+}
+
+/*
+ * Find all help tags matching "arg", sort them and return in matches[], with
+ * the number of matches in num_matches.
+ * The matches will be sorted with a "best" match algorithm.
+ * When "keep_lang" is TRUE try keeping the language of the current buffer.
+ */
+ int
+find_help_tags(
+ char_u *arg,
+ int *num_matches,
+ char_u ***matches,
+ int keep_lang)
+{
+ char_u *s, *d;
+ int i;
+ static char *(mtable[]) = {"*", "g*", "[*", "]*", ":*",
+ "/*", "/\\*", "\"*", "**",
+ "cpo-*", "/\\(\\)", "/\\%(\\)",
+ "?", ":?", "?<CR>", "g?", "g?g?", "g??",
+ "-?", "q?", "v_g?",
+ "/\\?", "/\\z(\\)", "\\=", ":s\\=",
+ "[count]", "[quotex]",
+ "[range]", ":[range]",
+ "[pattern]", "\\|", "\\%$",
+ "s/\\~", "s/\\U", "s/\\L",
+ "s/\\1", "s/\\2", "s/\\3", "s/\\9"};
+ static char *(rtable[]) = {"star", "gstar", "[star", "]star", ":star",
+ "/star", "/\\\\star", "quotestar", "starstar",
+ "cpo-star", "/\\\\(\\\\)", "/\\\\%(\\\\)",
+ "?", ":?", "?<CR>", "g?", "g?g?", "g??",
+ "-?", "q?", "v_g?",
+ "/\\\\?", "/\\\\z(\\\\)", "\\\\=", ":s\\\\=",
+ "\\[count]", "\\[quotex]",
+ "\\[range]", ":\\[range]",
+ "\\[pattern]", "\\\\bar", "/\\\\%\\$",
+ "s/\\\\\\~", "s/\\\\U", "s/\\\\L",
+ "s/\\\\1", "s/\\\\2", "s/\\\\3", "s/\\\\9"};
+ static char *(expr_table[]) = {"!=?", "!~?", "<=?", "<?", "==?", "=~?",
+ ">=?", ">?", "is?", "isnot?"};
+ int flags;
+
+ d = IObuff; /* assume IObuff is long enough! */
+
+ if (STRNICMP(arg, "expr-", 5) == 0)
+ {
+ // When the string starting with "expr-" and containing '?' and matches
+ // the table, it is taken literally. Otherwise '?' is recognized as a
+ // wildcard.
+ for (i = (int)(sizeof(expr_table) / sizeof(char *)); --i >= 0; )
+ if (STRCMP(arg + 5, expr_table[i]) == 0)
+ {
+ STRCPY(d, arg);
+ break;
+ }
+ }
+ else
+ {
+ // Recognize a few exceptions to the rule. Some strings that contain
+ // '*' with "star". Otherwise '*' is recognized as a wildcard.
+ for (i = (int)(sizeof(mtable) / sizeof(char *)); --i >= 0; )
+ if (STRCMP(arg, mtable[i]) == 0)
+ {
+ STRCPY(d, rtable[i]);
+ break;
+ }
+ }
+
+ if (i < 0) /* no match in table */
+ {
+ /* Replace "\S" with "/\\S", etc. Otherwise every tag is matched.
+ * Also replace "\%^" and "\%(", they match every tag too.
+ * Also "\zs", "\z1", etc.
+ * Also "\@<", "\@=", "\@<=", etc.
+ * And also "\_$" and "\_^". */
+ if (arg[0] == '\\'
+ && ((arg[1] != NUL && arg[2] == NUL)
+ || (vim_strchr((char_u *)"%_z@", arg[1]) != NULL
+ && arg[2] != NUL)))
+ {
+ STRCPY(d, "/\\\\");
+ STRCPY(d + 3, arg + 1);
+ /* Check for "/\\_$", should be "/\\_\$" */
+ if (d[3] == '_' && d[4] == '$')
+ STRCPY(d + 4, "\\$");
+ }
+ else
+ {
+ /* Replace:
+ * "[:...:]" with "\[:...:]"
+ * "[++...]" with "\[++...]"
+ * "\{" with "\\{" -- matching "} \}"
+ */
+ if ((arg[0] == '[' && (arg[1] == ':'
+ || (arg[1] == '+' && arg[2] == '+')))
+ || (arg[0] == '\\' && arg[1] == '{'))
+ *d++ = '\\';
+
+ /*
+ * If tag starts with "('", skip the "(". Fixes CTRL-] on ('option'.
+ */
+ if (*arg == '(' && arg[1] == '\'')
+ arg++;
+ for (s = arg; *s; ++s)
+ {
+ /*
+ * Replace "|" with "bar" and '"' with "quote" to match the name of
+ * the tags for these commands.
+ * Replace "*" with ".*" and "?" with "." to match command line
+ * completion.
+ * Insert a backslash before '~', '$' and '.' to avoid their
+ * special meaning.
+ */
+ if (d - IObuff > IOSIZE - 10) /* getting too long!? */
+ break;
+ switch (*s)
+ {
+ case '|': STRCPY(d, "bar");
+ d += 3;
+ continue;
+ case '"': STRCPY(d, "quote");
+ d += 5;
+ continue;
+ case '*': *d++ = '.';
+ break;
+ case '?': *d++ = '.';
+ continue;
+ case '$':
+ case '.':
+ case '~': *d++ = '\\';
+ break;
+ }
+
+ /*
+ * Replace "^x" by "CTRL-X". Don't do this for "^_" to make
+ * ":help i_^_CTRL-D" work.
+ * Insert '-' before and after "CTRL-X" when applicable.
+ */
+ if (*s < ' ' || (*s == '^' && s[1] && (ASCII_ISALPHA(s[1])
+ || vim_strchr((char_u *)"?@[\\]^", s[1]) != NULL)))
+ {
+ if (d > IObuff && d[-1] != '_' && d[-1] != '\\')
+ *d++ = '_'; /* prepend a '_' to make x_CTRL-x */
+ STRCPY(d, "CTRL-");
+ d += 5;
+ if (*s < ' ')
+ {
+#ifdef EBCDIC
+ *d++ = CtrlChar(*s);
+#else
+ *d++ = *s + '@';
+#endif
+ if (d[-1] == '\\')
+ *d++ = '\\'; /* double a backslash */
+ }
+ else
+ *d++ = *++s;
+ if (s[1] != NUL && s[1] != '_')
+ *d++ = '_'; /* append a '_' */
+ continue;
+ }
+ else if (*s == '^') /* "^" or "CTRL-^" or "^_" */
+ *d++ = '\\';
+
+ /*
+ * Insert a backslash before a backslash after a slash, for search
+ * pattern tags: "/\|" --> "/\\|".
+ */
+ else if (s[0] == '\\' && s[1] != '\\'
+ && *arg == '/' && s == arg + 1)
+ *d++ = '\\';
+
+ /* "CTRL-\_" -> "CTRL-\\_" to avoid the special meaning of "\_" in
+ * "CTRL-\_CTRL-N" */
+ if (STRNICMP(s, "CTRL-\\_", 7) == 0)
+ {
+ STRCPY(d, "CTRL-\\\\");
+ d += 7;
+ s += 6;
+ }
+
+ *d++ = *s;
+
+ /*
+ * If tag contains "({" or "([", tag terminates at the "(".
+ * This is for help on functions, e.g.: abs({expr}).
+ */
+ if (*s == '(' && (s[1] == '{' || s[1] =='['))
+ break;
+
+ /*
+ * If tag starts with ', toss everything after a second '. Fixes
+ * CTRL-] on 'option'. (would include the trailing '.').
+ */
+ if (*s == '\'' && s > arg && *arg == '\'')
+ break;
+ /* Also '{' and '}'. */
+ if (*s == '}' && s > arg && *arg == '{')
+ break;
+ }
+ *d = NUL;
+
+ if (*IObuff == '`')
+ {
+ if (d > IObuff + 2 && d[-1] == '`')
+ {
+ /* remove the backticks from `command` */
+ mch_memmove(IObuff, IObuff + 1, STRLEN(IObuff));
+ d[-2] = NUL;
+ }
+ else if (d > IObuff + 3 && d[-2] == '`' && d[-1] == ',')
+ {
+ /* remove the backticks and comma from `command`, */
+ mch_memmove(IObuff, IObuff + 1, STRLEN(IObuff));
+ d[-3] = NUL;
+ }
+ else if (d > IObuff + 4 && d[-3] == '`'
+ && d[-2] == '\\' && d[-1] == '.')
+ {
+ /* remove the backticks and dot from `command`\. */
+ mch_memmove(IObuff, IObuff + 1, STRLEN(IObuff));
+ d[-4] = NUL;
+ }
+ }
+ }
+ }
+
+ *matches = (char_u **)"";
+ *num_matches = 0;
+ flags = TAG_HELP | TAG_REGEXP | TAG_NAMES | TAG_VERBOSE;
+ if (keep_lang)
+ flags |= TAG_KEEP_LANG;
+ if (find_tags(IObuff, num_matches, matches, flags, (int)MAXCOL, NULL) == OK
+ && *num_matches > 0)
+ {
+ /* Sort the matches found on the heuristic number that is after the
+ * tag name. */
+ qsort((void *)*matches, (size_t)*num_matches,
+ sizeof(char_u *), help_compare);
+ /* Delete more than TAG_MANY to reduce the size of the listing. */
+ while (*num_matches > TAG_MANY)
+ vim_free((*matches)[--*num_matches]);
+ }
+ return OK;
+}
+
+/*
+ * Called when starting to edit a buffer for a help file.
+ */
+ static void
+prepare_help_buffer(void)
+{
+ char_u *p;
+
+ curbuf->b_help = TRUE;
+#ifdef FEAT_QUICKFIX
+ set_string_option_direct((char_u *)"buftype", -1,
+ (char_u *)"help", OPT_FREE|OPT_LOCAL, 0);
+#endif
+
+ /*
+ * Always set these options after jumping to a help tag, because the
+ * user may have an autocommand that gets in the way.
+ * Accept all ASCII chars for keywords, except ' ', '*', '"', '|', and
+ * latin1 word characters (for translated help files).
+ * Only set it when needed, buf_init_chartab() is some work.
+ */
+ p =
+#ifdef EBCDIC
+ (char_u *)"65-255,^*,^|,^\"";
+#else
+ (char_u *)"!-~,^*,^|,^\",192-255";
+#endif
+ if (STRCMP(curbuf->b_p_isk, p) != 0)
+ {
+ set_string_option_direct((char_u *)"isk", -1, p, OPT_FREE|OPT_LOCAL, 0);
+ check_buf_options(curbuf);
+ (void)buf_init_chartab(curbuf, FALSE);
+ }
+
+#ifdef FEAT_FOLDING
+ /* Don't use the global foldmethod.*/
+ set_string_option_direct((char_u *)"fdm", -1, (char_u *)"manual",
+ OPT_FREE|OPT_LOCAL, 0);
+#endif
+
+ curbuf->b_p_ts = 8; /* 'tabstop' is 8 */
+ curwin->w_p_list = FALSE; /* no list mode */
+
+ curbuf->b_p_ma = FALSE; /* not modifiable */
+ curbuf->b_p_bin = FALSE; /* reset 'bin' before reading file */
+ curwin->w_p_nu = 0; /* no line numbers */
+ curwin->w_p_rnu = 0; /* no relative line numbers */
+ RESET_BINDING(curwin); /* no scroll or cursor binding */
+#ifdef FEAT_ARABIC
+ curwin->w_p_arab = FALSE; /* no arabic mode */
+#endif
+#ifdef FEAT_RIGHTLEFT
+ curwin->w_p_rl = FALSE; /* help window is left-to-right */
+#endif
+#ifdef FEAT_FOLDING
+ curwin->w_p_fen = FALSE; /* No folding in the help window */
+#endif
+#ifdef FEAT_DIFF
+ curwin->w_p_diff = FALSE; /* No 'diff' */
+#endif
+#ifdef FEAT_SPELL
+ curwin->w_p_spell = FALSE; /* No spell checking */
+#endif
+
+ set_buflisted(FALSE);
+}
+
+/*
+ * After reading a help file: May cleanup a help buffer when syntax
+ * highlighting is not used.
+ */
+ void
+fix_help_buffer(void)
+{
+ linenr_T lnum;
+ char_u *line;
+ int in_example = FALSE;
+ int len;
+ char_u *fname;
+ char_u *p;
+ char_u *rt;
+ int mustfree;
+
+ /* Set filetype to "help" if still needed. */
+ if (STRCMP(curbuf->b_p_ft, "help") != 0)
+ {
+ ++curbuf_lock;
+ set_option_value((char_u *)"ft", 0L, (char_u *)"help", OPT_LOCAL);
+ --curbuf_lock;
+ }
+
+#ifdef FEAT_SYN_HL
+ if (!syntax_present(curwin))
+#endif
+ {
+ for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count; ++lnum)
+ {
+ line = ml_get_buf(curbuf, lnum, FALSE);
+ len = (int)STRLEN(line);
+ if (in_example && len > 0 && !VIM_ISWHITE(line[0]))
+ {
+ /* End of example: non-white or '<' in first column. */
+ if (line[0] == '<')
+ {
+ /* blank-out a '<' in the first column */
+ line = ml_get_buf(curbuf, lnum, TRUE);
+ line[0] = ' ';
+ }
+ in_example = FALSE;
+ }
+ if (!in_example && len > 0)
+ {
+ if (line[len - 1] == '>' && (len == 1 || line[len - 2] == ' '))
+ {
+ /* blank-out a '>' in the last column (start of example) */
+ line = ml_get_buf(curbuf, lnum, TRUE);
+ line[len - 1] = ' ';
+ in_example = TRUE;
+ }
+ else if (line[len - 1] == '~')
+ {
+ /* blank-out a '~' at the end of line (header marker) */
+ line = ml_get_buf(curbuf, lnum, TRUE);
+ line[len - 1] = ' ';
+ }
+ }
+ }
+ }
+
+ /*
+ * In the "help.txt" and "help.abx" file, add the locally added help
+ * files. This uses the very first line in the help file.
+ */
+ fname = gettail(curbuf->b_fname);
+ if (fnamecmp(fname, "help.txt") == 0
+#ifdef FEAT_MULTI_LANG
+ || (fnamencmp(fname, "help.", 5) == 0
+ && ASCII_ISALPHA(fname[5])
+ && ASCII_ISALPHA(fname[6])
+ && TOLOWER_ASC(fname[7]) == 'x'
+ && fname[8] == NUL)
+#endif
+ )
+ {
+ for (lnum = 1; lnum < curbuf->b_ml.ml_line_count; ++lnum)
+ {
+ line = ml_get_buf(curbuf, lnum, FALSE);
+ if (strstr((char *)line, "*local-additions*") == NULL)
+ continue;
+
+ /* Go through all directories in 'runtimepath', skipping
+ * $VIMRUNTIME. */
+ p = p_rtp;
+ while (*p != NUL)
+ {
+ copy_option_part(&p, NameBuff, MAXPATHL, ",");
+ mustfree = FALSE;
+ rt = vim_getenv((char_u *)"VIMRUNTIME", &mustfree);
+ if (rt != NULL && fullpathcmp(rt, NameBuff, FALSE) != FPC_SAME)
+ {
+ int fcount;
+ char_u **fnames;
+ FILE *fd;
+ char_u *s;
+ int fi;
+ vimconv_T vc;
+ char_u *cp;
+
+ /* Find all "doc/ *.txt" files in this directory. */
+ add_pathsep(NameBuff);
+#ifdef FEAT_MULTI_LANG
+ STRCAT(NameBuff, "doc/*.??[tx]");
+#else
+ STRCAT(NameBuff, "doc/*.txt");
+#endif
+ if (gen_expand_wildcards(1, &NameBuff, &fcount,
+ &fnames, EW_FILE|EW_SILENT) == OK
+ && fcount > 0)
+ {
+#ifdef FEAT_MULTI_LANG
+ int i1, i2;
+ char_u *f1, *f2;
+ char_u *t1, *t2;
+ char_u *e1, *e2;
+
+ /* If foo.abx is found use it instead of foo.txt in
+ * the same directory. */
+ for (i1 = 0; i1 < fcount; ++i1)
+ {
+ for (i2 = 0; i2 < fcount; ++i2)
+ {
+ if (i1 == i2)
+ continue;
+ if (fnames[i1] == NULL || fnames[i2] == NULL)
+ continue;
+ f1 = fnames[i1];
+ f2 = fnames[i2];
+ t1 = gettail(f1);
+ t2 = gettail(f2);
+ e1 = vim_strrchr(t1, '.');
+ e2 = vim_strrchr(t2, '.');
+ if (e1 == NULL || e2 == NULL)
+ continue;
+ if (fnamecmp(e1, ".txt") != 0
+ && fnamecmp(e1, fname + 4) != 0)
+ {
+ /* Not .txt and not .abx, remove it. */
+ VIM_CLEAR(fnames[i1]);
+ continue;
+ }
+ if (e1 - f1 != e2 - f2
+ || fnamencmp(f1, f2, e1 - f1) != 0)
+ continue;
+ if (fnamecmp(e1, ".txt") == 0
+ && fnamecmp(e2, fname + 4) == 0)
+ /* use .abx instead of .txt */
+ VIM_CLEAR(fnames[i1]);
+ }
+ }
+#endif
+ for (fi = 0; fi < fcount; ++fi)
+ {
+ if (fnames[fi] == NULL)
+ continue;
+ fd = mch_fopen((char *)fnames[fi], "r");
+ if (fd != NULL)
+ {
+ vim_fgets(IObuff, IOSIZE, fd);
+ if (IObuff[0] == '*'
+ && (s = vim_strchr(IObuff + 1, '*'))
+ != NULL)
+ {
+ int this_utf = MAYBE;
+
+ /* Change tag definition to a
+ * reference and remove <CR>/<NL>. */
+ IObuff[0] = '|';
+ *s = '|';
+ while (*s != NUL)
+ {
+ if (*s == '\r' || *s == '\n')
+ *s = NUL;
+ /* The text is utf-8 when a byte
+ * above 127 is found and no
+ * illegal byte sequence is found.
+ */
+ if (*s >= 0x80 && this_utf != FALSE)
+ {
+ int l;
+
+ this_utf = TRUE;
+ l = utf_ptr2len(s);
+ if (l == 1)
+ this_utf = FALSE;
+ s += l - 1;
+ }
+ ++s;
+ }
+
+ /* The help file is latin1 or utf-8;
+ * conversion to the current
+ * 'encoding' may be required. */
+ vc.vc_type = CONV_NONE;
+ convert_setup(&vc, (char_u *)(
+ this_utf == TRUE ? "utf-8"
+ : "latin1"), p_enc);
+ if (vc.vc_type == CONV_NONE)
+ /* No conversion needed. */
+ cp = IObuff;
+ else
+ {
+ /* Do the conversion. If it fails
+ * use the unconverted text. */
+ cp = string_convert(&vc, IObuff,
+ NULL);
+ if (cp == NULL)
+ cp = IObuff;
+ }
+ convert_setup(&vc, NULL, NULL);
+
+ ml_append(lnum, cp, (colnr_T)0, FALSE);
+ if (cp != IObuff)
+ vim_free(cp);
+ ++lnum;
+ }
+ fclose(fd);
+ }
+ }
+ FreeWild(fcount, fnames);
+ }
+ }
+ if (mustfree)
+ vim_free(rt);
+ }
+ break;
+ }
+ }
+}
+
+/*
+ * ":exusage"
+ */
+ void
+ex_exusage(exarg_T *eap UNUSED)
+{
+ do_cmdline_cmd((char_u *)"help ex-cmd-index");
+}
+
+/*
+ * ":viusage"
+ */
+ void
+ex_viusage(exarg_T *eap UNUSED)
+{
+ do_cmdline_cmd((char_u *)"help normal-index");
+}
+
+/*
+ * Generate tags in one help directory.
+ */
+ static void
+helptags_one(
+ char_u *dir, /* doc directory */
+ char_u *ext, /* suffix, ".txt", ".itx", ".frx", etc. */
+ char_u *tagfname, /* "tags" for English, "tags-fr" for French. */
+ int add_help_tags) /* add "help-tags" tag */
+{
+ FILE *fd_tags;
+ FILE *fd;
+ garray_T ga;
+ int filecount;
+ char_u **files;
+ char_u *p1, *p2;
+ int fi;
+ char_u *s;
+ int i;
+ char_u *fname;
+ int dirlen;
+ int utf8 = MAYBE;
+ int this_utf8;
+ int firstline;
+ int mix = FALSE; /* detected mixed encodings */
+
+ /*
+ * Find all *.txt files.
+ */
+ dirlen = (int)STRLEN(dir);
+ STRCPY(NameBuff, dir);
+ STRCAT(NameBuff, "/**/*");
+ STRCAT(NameBuff, ext);
+ if (gen_expand_wildcards(1, &NameBuff, &filecount, &files,
+ EW_FILE|EW_SILENT) == FAIL
+ || filecount == 0)
+ {
+ if (!got_int)
+ semsg(_("E151: No match: %s"), NameBuff);
+ return;
+ }
+
+ /*
+ * Open the tags file for writing.
+ * Do this before scanning through all the files.
+ */
+ STRCPY(NameBuff, dir);
+ add_pathsep(NameBuff);
+ STRCAT(NameBuff, tagfname);
+ fd_tags = mch_fopen((char *)NameBuff, "w");
+ if (fd_tags == NULL)
+ {
+ semsg(_("E152: Cannot open %s for writing"), NameBuff);
+ FreeWild(filecount, files);
+ return;
+ }
+
+ /*
+ * If using the "++t" argument or generating tags for "$VIMRUNTIME/doc"
+ * add the "help-tags" tag.
+ */
+ ga_init2(&ga, (int)sizeof(char_u *), 100);
+ if (add_help_tags || fullpathcmp((char_u *)"$VIMRUNTIME/doc",
+ dir, FALSE) == FPC_SAME)
+ {
+ if (ga_grow(&ga, 1) == FAIL)
+ got_int = TRUE;
+ else
+ {
+ s = alloc(18 + (unsigned)STRLEN(tagfname));
+ if (s == NULL)
+ got_int = TRUE;
+ else
+ {
+ sprintf((char *)s, "help-tags\t%s\t1\n", tagfname);
+ ((char_u **)ga.ga_data)[ga.ga_len] = s;
+ ++ga.ga_len;
+ }
+ }
+ }
+
+ /*
+ * Go over all the files and extract the tags.
+ */
+ for (fi = 0; fi < filecount && !got_int; ++fi)
+ {
+ fd = mch_fopen((char *)files[fi], "r");
+ if (fd == NULL)
+ {
+ semsg(_("E153: Unable to open %s for reading"), files[fi]);
+ continue;
+ }
+ fname = files[fi] + dirlen + 1;
+
+ firstline = TRUE;
+ while (!vim_fgets(IObuff, IOSIZE, fd) && !got_int)
+ {
+ if (firstline)
+ {
+ /* Detect utf-8 file by a non-ASCII char in the first line. */
+ this_utf8 = MAYBE;
+ for (s = IObuff; *s != NUL; ++s)
+ if (*s >= 0x80)
+ {
+ int l;
+
+ this_utf8 = TRUE;
+ l = utf_ptr2len(s);
+ if (l == 1)
+ {
+ /* Illegal UTF-8 byte sequence. */
+ this_utf8 = FALSE;
+ break;
+ }
+ s += l - 1;
+ }
+ if (this_utf8 == MAYBE) /* only ASCII characters found */
+ this_utf8 = FALSE;
+ if (utf8 == MAYBE) /* first file */
+ utf8 = this_utf8;
+ else if (utf8 != this_utf8)
+ {
+ semsg(_("E670: Mix of help file encodings within a language: %s"), files[fi]);
+ mix = !got_int;
+ got_int = TRUE;
+ }
+ firstline = FALSE;
+ }
+ p1 = vim_strchr(IObuff, '*'); /* find first '*' */
+ while (p1 != NULL)
+ {
+ /* Use vim_strbyte() instead of vim_strchr() so that when
+ * 'encoding' is dbcs it still works, don't find '*' in the
+ * second byte. */
+ p2 = vim_strbyte(p1 + 1, '*'); /* find second '*' */
+ if (p2 != NULL && p2 > p1 + 1) /* skip "*" and "**" */
+ {
+ for (s = p1 + 1; s < p2; ++s)
+ if (*s == ' ' || *s == '\t' || *s == '|')
+ break;
+
+ /*
+ * Only accept a *tag* when it consists of valid
+ * characters, there is white space before it and is
+ * followed by a white character or end-of-line.
+ */
+ if (s == p2
+ && (p1 == IObuff || p1[-1] == ' ' || p1[-1] == '\t')
+ && (vim_strchr((char_u *)" \t\n\r", s[1]) != NULL
+ || s[1] == '\0'))
+ {
+ *p2 = '\0';
+ ++p1;
+ if (ga_grow(&ga, 1) == FAIL)
+ {
+ got_int = TRUE;
+ break;
+ }
+ s = alloc((unsigned)(p2 - p1 + STRLEN(fname) + 2));
+ if (s == NULL)
+ {
+ got_int = TRUE;
+ break;
+ }
+ ((char_u **)ga.ga_data)[ga.ga_len] = s;
+ ++ga.ga_len;
+ sprintf((char *)s, "%s\t%s", p1, fname);
+
+ /* find next '*' */
+ p2 = vim_strchr(p2 + 1, '*');
+ }
+ }
+ p1 = p2;
+ }
+ line_breakcheck();
+ }
+
+ fclose(fd);
+ }
+
+ FreeWild(filecount, files);
+
+ if (!got_int)
+ {
+ /*
+ * Sort the tags.
+ */
+ if (ga.ga_data != NULL)
+ sort_strings((char_u **)ga.ga_data, ga.ga_len);
+
+ /*
+ * Check for duplicates.
+ */
+ for (i = 1; i < ga.ga_len; ++i)
+ {
+ p1 = ((char_u **)ga.ga_data)[i - 1];
+ p2 = ((char_u **)ga.ga_data)[i];
+ while (*p1 == *p2)
+ {
+ if (*p2 == '\t')
+ {
+ *p2 = NUL;
+ vim_snprintf((char *)NameBuff, MAXPATHL,
+ _("E154: Duplicate tag \"%s\" in file %s/%s"),
+ ((char_u **)ga.ga_data)[i], dir, p2 + 1);
+ emsg((char *)NameBuff);
+ *p2 = '\t';
+ break;
+ }
+ ++p1;
+ ++p2;
+ }
+ }
+
+ if (utf8 == TRUE)
+ fprintf(fd_tags, "!_TAG_FILE_ENCODING\tutf-8\t//\n");
+
+ /*
+ * Write the tags into the file.
+ */
+ for (i = 0; i < ga.ga_len; ++i)
+ {
+ s = ((char_u **)ga.ga_data)[i];
+ if (STRNCMP(s, "help-tags\t", 10) == 0)
+ /* help-tags entry was added in formatted form */
+ fputs((char *)s, fd_tags);
+ else
+ {
+ fprintf(fd_tags, "%s\t/*", s);
+ for (p1 = s; *p1 != '\t'; ++p1)
+ {
+ /* insert backslash before '\\' and '/' */
+ if (*p1 == '\\' || *p1 == '/')
+ putc('\\', fd_tags);
+ putc(*p1, fd_tags);
+ }
+ fprintf(fd_tags, "*\n");
+ }
+ }
+ }
+ if (mix)
+ got_int = FALSE; /* continue with other languages */
+
+ for (i = 0; i < ga.ga_len; ++i)
+ vim_free(((char_u **)ga.ga_data)[i]);
+ ga_clear(&ga);
+ fclose(fd_tags); /* there is no check for an error... */
+}
+
+/*
+ * Generate tags in one help directory, taking care of translations.
+ */
+ static void
+do_helptags(char_u *dirname, int add_help_tags)
+{
+#ifdef FEAT_MULTI_LANG
+ int len;
+ int i, j;
+ garray_T ga;
+ char_u lang[2];
+ char_u ext[5];
+ char_u fname[8];
+ int filecount;
+ char_u **files;
+
+ /* Get a list of all files in the help directory and in subdirectories. */
+ STRCPY(NameBuff, dirname);
+ add_pathsep(NameBuff);
+ STRCAT(NameBuff, "**");
+ if (gen_expand_wildcards(1, &NameBuff, &filecount, &files,
+ EW_FILE|EW_SILENT) == FAIL
+ || filecount == 0)
+ {
+ semsg(_("E151: No match: %s"), NameBuff);
+ return;
+ }
+
+ /* Go over all files in the directory to find out what languages are
+ * present. */
+ ga_init2(&ga, 1, 10);
+ for (i = 0; i < filecount; ++i)
+ {
+ len = (int)STRLEN(files[i]);
+ if (len > 4)
+ {
+ if (STRICMP(files[i] + len - 4, ".txt") == 0)
+ {
+ /* ".txt" -> language "en" */
+ lang[0] = 'e';
+ lang[1] = 'n';
+ }
+ else if (files[i][len - 4] == '.'
+ && ASCII_ISALPHA(files[i][len - 3])
+ && ASCII_ISALPHA(files[i][len - 2])
+ && TOLOWER_ASC(files[i][len - 1]) == 'x')
+ {
+ /* ".abx" -> language "ab" */
+ lang[0] = TOLOWER_ASC(files[i][len - 3]);
+ lang[1] = TOLOWER_ASC(files[i][len - 2]);
+ }
+ else
+ continue;
+
+ /* Did we find this language already? */
+ for (j = 0; j < ga.ga_len; j += 2)
+ if (STRNCMP(lang, ((char_u *)ga.ga_data) + j, 2) == 0)
+ break;
+ if (j == ga.ga_len)
+ {
+ /* New language, add it. */
+ if (ga_grow(&ga, 2) == FAIL)
+ break;
+ ((char_u *)ga.ga_data)[ga.ga_len++] = lang[0];
+ ((char_u *)ga.ga_data)[ga.ga_len++] = lang[1];
+ }
+ }
+ }
+
+ /*
+ * Loop over the found languages to generate a tags file for each one.
+ */
+ for (j = 0; j < ga.ga_len; j += 2)
+ {
+ STRCPY(fname, "tags-xx");
+ fname[5] = ((char_u *)ga.ga_data)[j];
+ fname[6] = ((char_u *)ga.ga_data)[j + 1];
+ if (fname[5] == 'e' && fname[6] == 'n')
+ {
+ /* English is an exception: use ".txt" and "tags". */
+ fname[4] = NUL;
+ STRCPY(ext, ".txt");
+ }
+ else
+ {
+ /* Language "ab" uses ".abx" and "tags-ab". */
+ STRCPY(ext, ".xxx");
+ ext[1] = fname[5];
+ ext[2] = fname[6];
+ }
+ helptags_one(dirname, ext, fname, add_help_tags);
+ }
+
+ ga_clear(&ga);
+ FreeWild(filecount, files);
+
+#else
+ /* No language support, just use "*.txt" and "tags". */
+ helptags_one(dirname, (char_u *)".txt", (char_u *)"tags", add_help_tags);
+#endif
+}
+
+ static void
+helptags_cb(char_u *fname, void *cookie)
+{
+ do_helptags(fname, *(int *)cookie);
+}
+
+/*
+ * ":helptags"
+ */
+ void
+ex_helptags(exarg_T *eap)
+{
+ expand_T xpc;
+ char_u *dirname;
+ int add_help_tags = FALSE;
+
+ /* Check for ":helptags ++t {dir}". */
+ if (STRNCMP(eap->arg, "++t", 3) == 0 && VIM_ISWHITE(eap->arg[3]))
+ {
+ add_help_tags = TRUE;
+ eap->arg = skipwhite(eap->arg + 3);
+ }
+
+ if (STRCMP(eap->arg, "ALL") == 0)
+ {
+ do_in_path(p_rtp, (char_u *)"doc", DIP_ALL + DIP_DIR,
+ helptags_cb, &add_help_tags);
+ }
+ else
+ {
+ ExpandInit(&xpc);
+ xpc.xp_context = EXPAND_DIRECTORIES;
+ dirname = ExpandOne(&xpc, eap->arg, NULL,
+ WILD_LIST_NOTFOUND|WILD_SILENT, WILD_EXPAND_FREE);
+ if (dirname == NULL || !mch_isdir(dirname))
+ semsg(_("E150: Not a directory: %s"), eap->arg);
+ else
+ do_helptags(dirname, add_help_tags);
+ vim_free(dirname);
+ }
+}
+
+/*
+ * Make the user happy.
+ */
+ void
+ex_smile(exarg_T *eap UNUSED)
+{
+ static char *code[] = {
+ "\34 \4o\14$\4ox\30 \2o\30$\1ox\25 \2o\36$\1o\11 \1o\1$\3 \2$\1 \1o\1$x\5 \1o\1 \1$\1 \2o\10 \1o\44$\1o\7 \2$\1 \2$\1 \2$\1o\1$x\2 \2o\1 \1$\1 \1$\1 \1\"\1$\6 \1o\11$\4 \15$\4 \11$\1o\7 \3$\1o\2$\1o\1$x\2 \1\"\6$\1o\1$\5 \1o\11$\6 \13$\6 \12$\1o\4 \10$x\4 \7$\4 \13$\6 \13$\6 \27$x\4 \27$\4 \15$\4 \16$\2 \3\"\3$x\5 \1\"\3$\4\"\61$\5 \1\"\3$x\6 \3$\3 \1o\62$\5 \1\"\3$\1ox\5 \1o\2$\1\"\3 \63$\7 \3$\1ox\5 \3$\4 \55$\1\"\1 \1\"\6$",
+ "\5o\4$\1ox\4 \1o\3$\4o\5$\2 \45$\3 \1o\21$x\4 \10$\1\"\4$\3 \42$\5 \4$\10\"x\3 \4\"\7 \4$\4 \1\"\34$\1\"\6 \1o\3$x\16 \1\"\3$\1o\5 \3\"\22$\1\"\2$\1\"\11 \3$x\20 \3$\1o\12 \1\"\2$\2\"\6$\4\"\13 \1o\3$x\21 \4$\1o\40 \1o\3$\1\"x\22 \1\"\4$\1o\6 \1o\6$\1o\1\"\4$\1o\10 \1o\4$x\24 \1\"\5$\2o\5 \2\"\4$\1o\5$\1o\3 \1o\4$\2\"x\27 \2\"\5$\4o\2 \1\"\3$\1o\11$\3\"x\32 \2\"\7$\2o\1 \12$x\42 \4\"\13$x\46 \14$x\47 \12$\1\"x\50 \1\"\3$\4\"x"
+ };
+ char *p;
+ int n;
+ int i;
+
+ msg_start();
+ msg_putchar('\n');
+ for (i = 0; i < 2; ++i)
+ for (p = code[i]; *p != NUL; ++p)
+ if (*p == 'x')
+ msg_putchar('\n');
+ else
+ for (n = *p++; n > 0; --n)
+ if (*p == 'o' || *p == '$')
+ msg_putchar_attr(*p, HL_ATTR(HLF_L));
+ else
+ msg_putchar(*p);
+ msg_clr_eos();
+}
+
+/*
+ * ":drop"
+ * Opens the first argument in a window. When there are two or more arguments
+ * the argument list is redefined.
+ */
+ void
+ex_drop(exarg_T *eap)
+{
+ int split = FALSE;
+ win_T *wp;
+ buf_T *buf;
+ tabpage_T *tp;
+
+ /*
+ * Check if the first argument is already being edited in a window. If
+ * so, jump to that window.
+ * We would actually need to check all arguments, but that's complicated
+ * and mostly only one file is dropped.
+ * This also ignores wildcards, since it is very unlikely the user is
+ * editing a file name with a wildcard character.
+ */
+ set_arglist(eap->arg);
+
+ /*
+ * Expanding wildcards may result in an empty argument list. E.g. when
+ * editing "foo.pyc" and ".pyc" is in 'wildignore'. Assume that we
+ * already did an error message for this.
+ */
+ if (ARGCOUNT == 0)
+ return;
+
+ if (cmdmod.tab)
+ {
+ /* ":tab drop file ...": open a tab for each argument that isn't
+ * edited in a window yet. It's like ":tab all" but without closing
+ * windows or tabs. */
+ ex_all(eap);
+ }
+ else
+ {
+ /* ":drop file ...": Edit the first argument. Jump to an existing
+ * window if possible, edit in current window if the current buffer
+ * can be abandoned, otherwise open a new window. */
+ buf = buflist_findnr(ARGLIST[0].ae_fnum);
+
+ FOR_ALL_TAB_WINDOWS(tp, wp)
+ {
+ if (wp->w_buffer == buf)
+ {
+ goto_tabpage_win(tp, wp);
+ curwin->w_arg_idx = 0;
+ return;
+ }
+ }
+
+ /*
+ * Check whether the current buffer is changed. If so, we will need
+ * to split the current window or data could be lost.
+ * Skip the check if the 'hidden' option is set, as in this case the
+ * buffer won't be lost.
+ */
+ if (!buf_hide(curbuf))
+ {
+ ++emsg_off;
+ split = check_changed(curbuf, CCGD_AW | CCGD_EXCMD);
+ --emsg_off;
+ }
+
+ /* Fake a ":sfirst" or ":first" command edit the first argument. */
+ if (split)
+ {
+ eap->cmdidx = CMD_sfirst;
+ eap->cmd[0] = 's';
+ }
+ else
+ eap->cmdidx = CMD_first;
+ ex_rewind(eap);
+ }
+}
+
+/*
+ * Skip over the pattern argument of ":vimgrep /pat/[g][j]".
+ * Put the start of the pattern in "*s", unless "s" is NULL.
+ * If "flags" is not NULL put the flags in it: VGR_GLOBAL, VGR_NOJUMP.
+ * If "s" is not NULL terminate the pattern with a NUL.
+ * Return a pointer to the char just past the pattern plus flags.
+ */
+ char_u *
+skip_vimgrep_pat(char_u *p, char_u **s, int *flags)
+{
+ int c;
+
+ if (vim_isIDc(*p))
+ {
+ /* ":vimgrep pattern fname" */
+ if (s != NULL)
+ *s = p;
+ p = skiptowhite(p);
+ if (s != NULL && *p != NUL)
+ *p++ = NUL;
+ }
+ else
+ {
+ /* ":vimgrep /pattern/[g][j] fname" */
+ if (s != NULL)
+ *s = p + 1;
+ c = *p;
+ p = skip_regexp(p + 1, c, TRUE, NULL);
+ if (*p != c)
+ return NULL;
+
+ /* Truncate the pattern. */
+ if (s != NULL)
+ *p = NUL;
+ ++p;
+
+ /* Find the flags */
+ while (*p == 'g' || *p == 'j')
+ {
+ if (flags != NULL)
+ {
+ if (*p == 'g')
+ *flags |= VGR_GLOBAL;
+ else
+ *flags |= VGR_NOJUMP;
+ }
+ ++p;
+ }
+ }
+ return p;
+}
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * List v:oldfiles in a nice way.
+ */
+ void
+ex_oldfiles(exarg_T *eap UNUSED)
+{
+ list_T *l = get_vim_var_list(VV_OLDFILES);
+ listitem_T *li;
+ int nr = 0;
+ char_u *fname;
+
+ if (l == NULL)
+ msg(_("No old files"));
+ else
+ {
+ msg_start();
+ msg_scroll = TRUE;
+ for (li = l->lv_first; li != NULL && !got_int; li = li->li_next)
+ {
+ ++nr;
+ fname = tv_get_string(&li->li_tv);
+ if (!message_filtered(fname))
+ {
+ msg_outnum((long)nr);
+ msg_puts(": ");
+ msg_outtrans(fname);
+ msg_clr_eos();
+ msg_putchar('\n');
+ out_flush(); /* output one line at a time */
+ ui_breakcheck();
+ }
+ }
+
+ /* Assume "got_int" was set to truncate the listing. */
+ got_int = FALSE;
+
+# ifdef FEAT_BROWSE_CMD
+ if (cmdmod.browse)
+ {
+ quit_more = FALSE;
+ nr = prompt_for_number(FALSE);
+ msg_starthere();
+ if (nr > 0)
+ {
+ char_u *p = list_find_str(get_vim_var_list(VV_OLDFILES),
+ (long)nr);
+
+ if (p != NULL)
+ {
+ p = expand_env_save(p);
+ eap->arg = p;
+ eap->cmdidx = CMD_edit;
+ cmdmod.browse = FALSE;
+ do_exedit(eap, NULL);
+ vim_free(p);
+ }
+ }
+ }
+# endif
+ }
+}
+#endif
diff --git a/src/ex_cmds.h b/src/ex_cmds.h
new file mode 100644
index 0000000..07afb00
--- /dev/null
+++ b/src/ex_cmds.h
@@ -0,0 +1,1819 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * Do ":help uganda" in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ */
+
+/*
+ * This file defines the Ex commands.
+ * When DO_DECLARE_EXCMD is defined, the table with ex command names and
+ * options results.
+ * When DO_DECLARE_EXCMD is NOT defined, the enum with all the Ex commands
+ * results.
+ * This clever trick was invented by Ron Aaron.
+ */
+
+/*
+ * When adding an Ex command:
+ * 1. Add an entry in the table below. Keep it sorted on the shortest
+ * version of the command name that works. If it doesn't start with a
+ * lower case letter, add it at the end.
+ * 2. Run "make cmdidxs" to re-generate ex_cmdidxs.h.
+ * 3. Add a "case: CMD_xxx" in the big switch in ex_docmd.c.
+ * 4. Add an entry in the index for Ex commands at ":help ex-cmd-index".
+ * 5. Add documentation in ../doc/xxx.txt. Add a tag for both the short and
+ * long name of the command.
+ */
+
+#ifdef RANGE
+# undef RANGE /* SASC on Amiga defines it */
+#endif
+
+#define RANGE 0x001 /* allow a linespecs */
+#define BANG 0x002 /* allow a ! after the command name */
+#define EXTRA 0x004 /* allow extra args after command name */
+#define XFILE 0x008 /* expand wildcards in extra part */
+#define NOSPC 0x010 /* no spaces allowed in the extra part */
+#define DFLALL 0x020 /* default file range is 1,$ */
+#define WHOLEFOLD 0x040 /* extend range to include whole fold also
+ when less than two numbers given */
+#define NEEDARG 0x080 /* argument required */
+#define TRLBAR 0x100 /* check for trailing vertical bar */
+#define REGSTR 0x200 /* allow "x for register designation */
+#define COUNT 0x400 /* allow count in argument, after command */
+#define NOTRLCOM 0x800 /* no trailing comment allowed */
+#define ZEROR 0x1000 /* zero line number allowed */
+#define USECTRLV 0x2000 /* do not remove CTRL-V from argument */
+#define NOTADR 0x4000 /* number before command is not an address */
+#define EDITCMD 0x8000 /* allow "+command" argument */
+#define BUFNAME 0x10000L /* accepts buffer name */
+#define BUFUNL 0x20000L /* accepts unlisted buffer too */
+#define ARGOPT 0x40000L /* allow "++opt=val" argument */
+#define SBOXOK 0x80000L /* allowed in the sandbox */
+#define CMDWIN 0x100000L /* allowed in cmdline window; when missing
+ * disallows editing another buffer when
+ * curbuf_lock is set */
+#define MODIFY 0x200000L /* forbidden in non-'modifiable' buffer */
+#define EXFLAGS 0x400000L /* allow flags after count in argument */
+#define FILES (XFILE | EXTRA) /* multiple extra files allowed */
+#define WORD1 (EXTRA | NOSPC) /* one extra word allowed */
+#define FILE1 (FILES | NOSPC) /* 1 file allowed, defaults to current file */
+
+/* values for cmd_addr_type */
+#define ADDR_LINES 0 // buffer line numbers
+#define ADDR_WINDOWS 1 // window number
+#define ADDR_ARGUMENTS 2 // argument number
+#define ADDR_LOADED_BUFFERS 3 // buffer number of loaded buffer
+#define ADDR_BUFFERS 4 // buffer number
+#define ADDR_TABS 5 // tab page number
+#define ADDR_TABS_RELATIVE 6 // Tab page that only relative
+#define ADDR_QUICKFIX 7 // quickfix list entry number
+#define ADDR_OTHER 99 // something else
+
+#ifndef DO_DECLARE_EXCMD
+typedef struct exarg exarg_T;
+#endif
+
+/*
+ * This array maps ex command names to command codes.
+ * The order in which command names are listed below is significant --
+ * ambiguous abbreviations are always resolved to be the first possible match
+ * (e.g. "r" is taken to mean "read", not "rewind", because "read" comes
+ * before "rewind").
+ * Not supported commands are included to avoid ambiguities.
+ */
+#ifdef EX
+# undef EX /* just in case */
+#endif
+#ifdef DO_DECLARE_EXCMD
+# define EX(a, b, c, d, e) {(char_u *)b, c, (long_u)(d), e}
+
+typedef void (*ex_func_T) (exarg_T *eap);
+
+static struct cmdname
+{
+ char_u *cmd_name; /* name of the command */
+ ex_func_T cmd_func; /* function for this command */
+ long_u cmd_argt; /* flags declared above */
+ int cmd_addr_type; /* flag for address type */
+} cmdnames[] =
+#else
+# define EX(a, b, c, d, e) a
+enum CMD_index
+#endif
+{
+EX(CMD_append, "append", ex_append,
+ BANG|RANGE|ZEROR|TRLBAR|CMDWIN|MODIFY,
+ ADDR_LINES),
+EX(CMD_abbreviate, "abbreviate", ex_abbreviate,
+ EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_abclear, "abclear", ex_abclear,
+ EXTRA|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_aboveleft, "aboveleft", ex_wrongmodifier,
+ NEEDARG|EXTRA|NOTRLCOM,
+ ADDR_LINES),
+EX(CMD_all, "all", ex_all,
+ BANG|RANGE|NOTADR|COUNT|TRLBAR,
+ ADDR_LINES),
+EX(CMD_amenu, "amenu", ex_menu,
+ RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_anoremenu, "anoremenu", ex_menu,
+ RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_args, "args", ex_args,
+ BANG|FILES|EDITCMD|ARGOPT|TRLBAR,
+ ADDR_LINES),
+EX(CMD_argadd, "argadd", ex_argadd,
+ BANG|RANGE|NOTADR|ZEROR|FILES|TRLBAR,
+ ADDR_ARGUMENTS),
+EX(CMD_argdelete, "argdelete", ex_argdelete,
+ BANG|RANGE|NOTADR|FILES|TRLBAR,
+ ADDR_ARGUMENTS),
+EX(CMD_argdo, "argdo", ex_listdo,
+ BANG|NEEDARG|EXTRA|NOTRLCOM|RANGE|NOTADR|DFLALL,
+ ADDR_ARGUMENTS),
+EX(CMD_argedit, "argedit", ex_argedit,
+ BANG|NEEDARG|RANGE|NOTADR|ZEROR|FILES|EDITCMD|ARGOPT|TRLBAR,
+ ADDR_ARGUMENTS),
+EX(CMD_argglobal, "argglobal", ex_args,
+ BANG|FILES|EDITCMD|ARGOPT|TRLBAR,
+ ADDR_LINES),
+EX(CMD_arglocal, "arglocal", ex_args,
+ BANG|FILES|EDITCMD|ARGOPT|TRLBAR,
+ ADDR_LINES),
+EX(CMD_argument, "argument", ex_argument,
+ BANG|RANGE|NOTADR|COUNT|EXTRA|EDITCMD|ARGOPT|TRLBAR,
+ ADDR_ARGUMENTS),
+EX(CMD_ascii, "ascii", do_ascii,
+ TRLBAR|SBOXOK|CMDWIN,
+ ADDR_LINES),
+EX(CMD_autocmd, "autocmd", ex_autocmd,
+ BANG|EXTRA|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_augroup, "augroup", ex_autocmd,
+ BANG|WORD1|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_aunmenu, "aunmenu", ex_menu,
+ EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_buffer, "buffer", ex_buffer,
+ BANG|RANGE|NOTADR|BUFNAME|BUFUNL|COUNT|EXTRA|EDITCMD|TRLBAR,
+ ADDR_BUFFERS),
+EX(CMD_bNext, "bNext", ex_bprevious,
+ BANG|RANGE|NOTADR|COUNT|EDITCMD|TRLBAR,
+ ADDR_LINES),
+EX(CMD_ball, "ball", ex_buffer_all,
+ RANGE|NOTADR|COUNT|TRLBAR,
+ ADDR_LINES),
+EX(CMD_badd, "badd", ex_edit,
+ NEEDARG|FILE1|EDITCMD|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_bdelete, "bdelete", ex_bunload,
+ BANG|RANGE|NOTADR|BUFNAME|COUNT|EXTRA|TRLBAR,
+ ADDR_BUFFERS),
+EX(CMD_behave, "behave", ex_behave,
+ BANG|NEEDARG|WORD1|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_belowright, "belowright", ex_wrongmodifier,
+ NEEDARG|EXTRA|NOTRLCOM,
+ ADDR_LINES),
+EX(CMD_bfirst, "bfirst", ex_brewind,
+ BANG|RANGE|NOTADR|EDITCMD|TRLBAR,
+ ADDR_LINES),
+EX(CMD_blast, "blast", ex_blast,
+ BANG|RANGE|NOTADR|EDITCMD|TRLBAR,
+ ADDR_LINES),
+EX(CMD_bmodified, "bmodified", ex_bmodified,
+ BANG|RANGE|NOTADR|COUNT|EDITCMD|TRLBAR,
+ ADDR_LINES),
+EX(CMD_bnext, "bnext", ex_bnext,
+ BANG|RANGE|NOTADR|COUNT|EDITCMD|TRLBAR,
+ ADDR_LINES),
+EX(CMD_botright, "botright", ex_wrongmodifier,
+ NEEDARG|EXTRA|NOTRLCOM,
+ ADDR_LINES),
+EX(CMD_bprevious, "bprevious", ex_bprevious,
+ BANG|RANGE|NOTADR|COUNT|EDITCMD|TRLBAR,
+ ADDR_LINES),
+EX(CMD_brewind, "brewind", ex_brewind,
+ BANG|RANGE|NOTADR|EDITCMD|TRLBAR,
+ ADDR_LINES),
+EX(CMD_break, "break", ex_break,
+ TRLBAR|SBOXOK|CMDWIN,
+ ADDR_LINES),
+EX(CMD_breakadd, "breakadd", ex_breakadd,
+ EXTRA|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_breakdel, "breakdel", ex_breakdel,
+ EXTRA|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_breaklist, "breaklist", ex_breaklist,
+ EXTRA|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_browse, "browse", ex_wrongmodifier,
+ NEEDARG|EXTRA|NOTRLCOM|CMDWIN,
+ ADDR_LINES),
+EX(CMD_buffers, "buffers", buflist_list,
+ BANG|EXTRA|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_bufdo, "bufdo", ex_listdo,
+ BANG|NEEDARG|EXTRA|NOTRLCOM|RANGE|NOTADR|DFLALL,
+ ADDR_BUFFERS),
+EX(CMD_bunload, "bunload", ex_bunload,
+ BANG|RANGE|NOTADR|BUFNAME|COUNT|EXTRA|TRLBAR,
+ ADDR_LOADED_BUFFERS),
+EX(CMD_bwipeout, "bwipeout", ex_bunload,
+ BANG|RANGE|NOTADR|BUFNAME|BUFUNL|COUNT|EXTRA|TRLBAR,
+ ADDR_BUFFERS),
+EX(CMD_change, "change", ex_change,
+ BANG|WHOLEFOLD|RANGE|COUNT|TRLBAR|CMDWIN|MODIFY,
+ ADDR_LINES),
+EX(CMD_cNext, "cNext", ex_cnext,
+ RANGE|NOTADR|COUNT|TRLBAR|BANG,
+ ADDR_LINES),
+EX(CMD_cNfile, "cNfile", ex_cnext,
+ RANGE|NOTADR|COUNT|TRLBAR|BANG,
+ ADDR_LINES),
+EX(CMD_cabbrev, "cabbrev", ex_abbreviate,
+ EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_cabclear, "cabclear", ex_abclear,
+ EXTRA|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_caddbuffer, "caddbuffer", ex_cbuffer,
+ RANGE|NOTADR|WORD1|TRLBAR,
+ ADDR_LINES),
+EX(CMD_caddexpr, "caddexpr", ex_cexpr,
+ NEEDARG|WORD1|NOTRLCOM|TRLBAR,
+ ADDR_LINES),
+EX(CMD_caddfile, "caddfile", ex_cfile,
+ TRLBAR|FILE1,
+ ADDR_LINES),
+EX(CMD_call, "call", ex_call,
+ RANGE|NEEDARG|EXTRA|NOTRLCOM|SBOXOK|CMDWIN,
+ ADDR_LINES),
+EX(CMD_catch, "catch", ex_catch,
+ EXTRA|SBOXOK|CMDWIN,
+ ADDR_LINES),
+EX(CMD_cbuffer, "cbuffer", ex_cbuffer,
+ BANG|RANGE|NOTADR|WORD1|TRLBAR,
+ ADDR_LINES),
+EX(CMD_cbottom, "cbottom", ex_cbottom,
+ TRLBAR,
+ ADDR_LINES),
+EX(CMD_cc, "cc", ex_cc,
+ RANGE|NOTADR|COUNT|TRLBAR|BANG,
+ ADDR_LINES),
+EX(CMD_cclose, "cclose", ex_cclose,
+ RANGE|NOTADR|COUNT|TRLBAR,
+ ADDR_LINES),
+EX(CMD_cd, "cd", ex_cd,
+ BANG|FILE1|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_cdo, "cdo", ex_listdo,
+ BANG|NEEDARG|EXTRA|NOTRLCOM|RANGE|NOTADR|DFLALL,
+ ADDR_QUICKFIX),
+EX(CMD_center, "center", ex_align,
+ TRLBAR|RANGE|WHOLEFOLD|EXTRA|CMDWIN|MODIFY,
+ ADDR_LINES),
+EX(CMD_cexpr, "cexpr", ex_cexpr,
+ NEEDARG|WORD1|NOTRLCOM|TRLBAR|BANG,
+ ADDR_LINES),
+EX(CMD_cfile, "cfile", ex_cfile,
+ TRLBAR|FILE1|BANG,
+ ADDR_LINES),
+EX(CMD_cfdo, "cfdo", ex_listdo,
+ BANG|NEEDARG|EXTRA|NOTRLCOM|RANGE|NOTADR|DFLALL,
+ ADDR_QUICKFIX),
+EX(CMD_cfirst, "cfirst", ex_cc,
+ RANGE|NOTADR|COUNT|TRLBAR|BANG,
+ ADDR_LINES),
+EX(CMD_cgetfile, "cgetfile", ex_cfile,
+ TRLBAR|FILE1,
+ ADDR_LINES),
+EX(CMD_cgetbuffer, "cgetbuffer", ex_cbuffer,
+ RANGE|NOTADR|WORD1|TRLBAR,
+ ADDR_LINES),
+EX(CMD_cgetexpr, "cgetexpr", ex_cexpr,
+ NEEDARG|WORD1|NOTRLCOM|TRLBAR,
+ ADDR_LINES),
+EX(CMD_chdir, "chdir", ex_cd,
+ BANG|FILE1|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_changes, "changes", ex_changes,
+ TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_checkpath, "checkpath", ex_checkpath,
+ TRLBAR|BANG|CMDWIN,
+ ADDR_LINES),
+EX(CMD_checktime, "checktime", ex_checktime,
+ RANGE|NOTADR|BUFNAME|COUNT|EXTRA|TRLBAR,
+ ADDR_LINES),
+EX(CMD_chistory, "chistory", qf_history,
+ TRLBAR,
+ ADDR_LINES),
+EX(CMD_clist, "clist", qf_list,
+ BANG|EXTRA|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_clast, "clast", ex_cc,
+ RANGE|NOTADR|COUNT|TRLBAR|BANG,
+ ADDR_LINES),
+EX(CMD_close, "close", ex_close,
+ BANG|RANGE|NOTADR|COUNT|TRLBAR|CMDWIN,
+ ADDR_WINDOWS),
+EX(CMD_clearjumps, "clearjumps", ex_clearjumps,
+ TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_cmap, "cmap", ex_map,
+ EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_cmapclear, "cmapclear", ex_mapclear,
+ EXTRA|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_cmenu, "cmenu", ex_menu,
+ RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_cnext, "cnext", ex_cnext,
+ RANGE|NOTADR|COUNT|TRLBAR|BANG,
+ ADDR_LINES),
+EX(CMD_cnewer, "cnewer", qf_age,
+ RANGE|NOTADR|COUNT|TRLBAR,
+ ADDR_LINES),
+EX(CMD_cnfile, "cnfile", ex_cnext,
+ RANGE|NOTADR|COUNT|TRLBAR|BANG,
+ ADDR_LINES),
+EX(CMD_cnoremap, "cnoremap", ex_map,
+ EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_cnoreabbrev, "cnoreabbrev", ex_abbreviate,
+ EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_cnoremenu, "cnoremenu", ex_menu,
+ RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_copy, "copy", ex_copymove,
+ RANGE|WHOLEFOLD|EXTRA|TRLBAR|CMDWIN|MODIFY,
+ ADDR_LINES),
+EX(CMD_colder, "colder", qf_age,
+ RANGE|NOTADR|COUNT|TRLBAR,
+ ADDR_LINES),
+EX(CMD_colorscheme, "colorscheme", ex_colorscheme,
+ WORD1|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_command, "command", ex_command,
+ EXTRA|BANG|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_comclear, "comclear", ex_comclear,
+ TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_compiler, "compiler", ex_compiler,
+ BANG|TRLBAR|WORD1|CMDWIN,
+ ADDR_LINES),
+EX(CMD_continue, "continue", ex_continue,
+ TRLBAR|SBOXOK|CMDWIN,
+ ADDR_LINES),
+EX(CMD_confirm, "confirm", ex_wrongmodifier,
+ NEEDARG|EXTRA|NOTRLCOM|CMDWIN,
+ ADDR_LINES),
+EX(CMD_copen, "copen", ex_copen,
+ RANGE|NOTADR|COUNT|TRLBAR,
+ ADDR_LINES),
+EX(CMD_cprevious, "cprevious", ex_cnext,
+ RANGE|NOTADR|COUNT|TRLBAR|BANG,
+ ADDR_LINES),
+EX(CMD_cpfile, "cpfile", ex_cnext,
+ RANGE|NOTADR|COUNT|TRLBAR|BANG,
+ ADDR_LINES),
+EX(CMD_cquit, "cquit", ex_cquit,
+ TRLBAR|BANG,
+ ADDR_LINES),
+EX(CMD_crewind, "crewind", ex_cc,
+ RANGE|NOTADR|COUNT|TRLBAR|BANG,
+ ADDR_LINES),
+EX(CMD_cscope, "cscope", ex_cscope,
+ EXTRA|NOTRLCOM|XFILE,
+ ADDR_LINES),
+EX(CMD_cstag, "cstag", ex_cstag,
+ BANG|TRLBAR|WORD1,
+ ADDR_LINES),
+EX(CMD_cunmap, "cunmap", ex_unmap,
+ EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_cunabbrev, "cunabbrev", ex_abbreviate,
+ EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_cunmenu, "cunmenu", ex_menu,
+ EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_cwindow, "cwindow", ex_cwindow,
+ RANGE|NOTADR|COUNT|TRLBAR,
+ ADDR_LINES),
+EX(CMD_delete, "delete", ex_operators,
+ RANGE|WHOLEFOLD|REGSTR|COUNT|TRLBAR|CMDWIN|MODIFY,
+ ADDR_LINES),
+EX(CMD_delmarks, "delmarks", ex_delmarks,
+ BANG|EXTRA|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_debug, "debug", ex_debug,
+ NEEDARG|EXTRA|NOTRLCOM|SBOXOK|CMDWIN,
+ ADDR_LINES),
+EX(CMD_debuggreedy, "debuggreedy", ex_debuggreedy,
+ RANGE|NOTADR|ZEROR|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_delcommand, "delcommand", ex_delcommand,
+ NEEDARG|WORD1|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_delfunction, "delfunction", ex_delfunction,
+ BANG|NEEDARG|WORD1|CMDWIN,
+ ADDR_LINES),
+EX(CMD_display, "display", ex_display,
+ EXTRA|NOTRLCOM|TRLBAR|SBOXOK|CMDWIN,
+ ADDR_LINES),
+EX(CMD_diffupdate, "diffupdate", ex_diffupdate,
+ BANG|TRLBAR,
+ ADDR_LINES),
+EX(CMD_diffget, "diffget", ex_diffgetput,
+ RANGE|EXTRA|TRLBAR|MODIFY,
+ ADDR_LINES),
+EX(CMD_diffoff, "diffoff", ex_diffoff,
+ BANG|TRLBAR,
+ ADDR_LINES),
+EX(CMD_diffpatch, "diffpatch", ex_diffpatch,
+ EXTRA|FILE1|TRLBAR|MODIFY,
+ ADDR_LINES),
+EX(CMD_diffput, "diffput", ex_diffgetput,
+ RANGE|EXTRA|TRLBAR,
+ ADDR_LINES),
+EX(CMD_diffsplit, "diffsplit", ex_diffsplit,
+ EXTRA|FILE1|TRLBAR,
+ ADDR_LINES),
+EX(CMD_diffthis, "diffthis", ex_diffthis,
+ TRLBAR,
+ ADDR_LINES),
+EX(CMD_digraphs, "digraphs", ex_digraphs,
+ BANG|EXTRA|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_djump, "djump", ex_findpat,
+ BANG|RANGE|DFLALL|WHOLEFOLD|EXTRA,
+ ADDR_LINES),
+EX(CMD_dlist, "dlist", ex_findpat,
+ BANG|RANGE|DFLALL|WHOLEFOLD|EXTRA|CMDWIN,
+ ADDR_LINES),
+EX(CMD_doautocmd, "doautocmd", ex_doautocmd,
+ EXTRA|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_doautoall, "doautoall", ex_doautoall,
+ EXTRA|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_drop, "drop", ex_drop,
+ FILES|EDITCMD|NEEDARG|ARGOPT|TRLBAR,
+ ADDR_LINES),
+EX(CMD_dsearch, "dsearch", ex_findpat,
+ BANG|RANGE|DFLALL|WHOLEFOLD|EXTRA|CMDWIN,
+ ADDR_LINES),
+EX(CMD_dsplit, "dsplit", ex_findpat,
+ BANG|RANGE|DFLALL|WHOLEFOLD|EXTRA,
+ ADDR_LINES),
+EX(CMD_edit, "edit", ex_edit,
+ BANG|FILE1|EDITCMD|ARGOPT|TRLBAR,
+ ADDR_LINES),
+EX(CMD_earlier, "earlier", ex_later,
+ TRLBAR|EXTRA|NOSPC|CMDWIN,
+ ADDR_LINES),
+EX(CMD_echo, "echo", ex_echo,
+ EXTRA|NOTRLCOM|SBOXOK|CMDWIN,
+ ADDR_LINES),
+EX(CMD_echoerr, "echoerr", ex_execute,
+ EXTRA|NOTRLCOM|SBOXOK|CMDWIN,
+ ADDR_LINES),
+EX(CMD_echohl, "echohl", ex_echohl,
+ EXTRA|TRLBAR|SBOXOK|CMDWIN,
+ ADDR_LINES),
+EX(CMD_echomsg, "echomsg", ex_execute,
+ EXTRA|NOTRLCOM|SBOXOK|CMDWIN,
+ ADDR_LINES),
+EX(CMD_echon, "echon", ex_echo,
+ EXTRA|NOTRLCOM|SBOXOK|CMDWIN,
+ ADDR_LINES),
+EX(CMD_else, "else", ex_else,
+ TRLBAR|SBOXOK|CMDWIN,
+ ADDR_LINES),
+EX(CMD_elseif, "elseif", ex_else,
+ EXTRA|NOTRLCOM|SBOXOK|CMDWIN,
+ ADDR_LINES),
+EX(CMD_emenu, "emenu", ex_emenu,
+ NEEDARG|EXTRA|TRLBAR|NOTRLCOM|RANGE|NOTADR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_endif, "endif", ex_endif,
+ TRLBAR|SBOXOK|CMDWIN,
+ ADDR_LINES),
+EX(CMD_endfunction, "endfunction", ex_endfunction,
+ TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_endfor, "endfor", ex_endwhile,
+ TRLBAR|SBOXOK|CMDWIN,
+ ADDR_LINES),
+EX(CMD_endtry, "endtry", ex_endtry,
+ TRLBAR|SBOXOK|CMDWIN,
+ ADDR_LINES),
+EX(CMD_endwhile, "endwhile", ex_endwhile,
+ TRLBAR|SBOXOK|CMDWIN,
+ ADDR_LINES),
+EX(CMD_enew, "enew", ex_edit,
+ BANG|TRLBAR,
+ ADDR_LINES),
+EX(CMD_ex, "ex", ex_edit,
+ BANG|FILE1|EDITCMD|ARGOPT|TRLBAR,
+ ADDR_LINES),
+EX(CMD_execute, "execute", ex_execute,
+ EXTRA|NOTRLCOM|SBOXOK|CMDWIN,
+ ADDR_LINES),
+EX(CMD_exit, "exit", ex_exit,
+ RANGE|WHOLEFOLD|BANG|FILE1|ARGOPT|DFLALL|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_exusage, "exusage", ex_exusage,
+ TRLBAR,
+ ADDR_LINES),
+EX(CMD_file, "file", ex_file,
+ RANGE|NOTADR|ZEROR|BANG|FILE1|TRLBAR,
+ ADDR_LINES),
+EX(CMD_files, "files", buflist_list,
+ BANG|EXTRA|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_filetype, "filetype", ex_filetype,
+ EXTRA|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_filter, "filter", ex_wrongmodifier,
+ BANG|NEEDARG|EXTRA|NOTRLCOM,
+ ADDR_LINES),
+EX(CMD_find, "find", ex_find,
+ RANGE|NOTADR|BANG|FILE1|EDITCMD|ARGOPT|TRLBAR,
+ ADDR_LINES),
+EX(CMD_finally, "finally", ex_finally,
+ TRLBAR|SBOXOK|CMDWIN,
+ ADDR_LINES),
+EX(CMD_finish, "finish", ex_finish,
+ TRLBAR|SBOXOK|CMDWIN,
+ ADDR_LINES),
+EX(CMD_first, "first", ex_rewind,
+ EXTRA|BANG|EDITCMD|ARGOPT|TRLBAR,
+ ADDR_LINES),
+EX(CMD_fixdel, "fixdel", do_fixdel,
+ TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_fold, "fold", ex_fold,
+ RANGE|WHOLEFOLD|TRLBAR|SBOXOK|CMDWIN,
+ ADDR_LINES),
+EX(CMD_foldclose, "foldclose", ex_foldopen,
+ RANGE|BANG|WHOLEFOLD|TRLBAR|SBOXOK|CMDWIN,
+ ADDR_LINES),
+EX(CMD_folddoopen, "folddoopen", ex_folddo,
+ RANGE|DFLALL|NEEDARG|EXTRA|NOTRLCOM,
+ ADDR_LINES),
+EX(CMD_folddoclosed, "folddoclosed", ex_folddo,
+ RANGE|DFLALL|NEEDARG|EXTRA|NOTRLCOM,
+ ADDR_LINES),
+EX(CMD_foldopen, "foldopen", ex_foldopen,
+ RANGE|BANG|WHOLEFOLD|TRLBAR|SBOXOK|CMDWIN,
+ ADDR_LINES),
+EX(CMD_for, "for", ex_while,
+ EXTRA|NOTRLCOM|SBOXOK|CMDWIN,
+ ADDR_LINES),
+EX(CMD_function, "function", ex_function,
+ EXTRA|BANG|SBOXOK|CMDWIN,
+ ADDR_LINES),
+EX(CMD_global, "global", ex_global,
+ RANGE|WHOLEFOLD|BANG|EXTRA|DFLALL|SBOXOK|CMDWIN,
+ ADDR_LINES),
+EX(CMD_goto, "goto", ex_goto,
+ RANGE|NOTADR|COUNT|TRLBAR|SBOXOK|CMDWIN,
+ ADDR_LINES),
+EX(CMD_grep, "grep", ex_make,
+ RANGE|NOTADR|BANG|NEEDARG|EXTRA|NOTRLCOM|TRLBAR|XFILE,
+ ADDR_LINES),
+EX(CMD_grepadd, "grepadd", ex_make,
+ RANGE|NOTADR|BANG|NEEDARG|EXTRA|NOTRLCOM|TRLBAR|XFILE,
+ ADDR_LINES),
+EX(CMD_gui, "gui", ex_gui,
+ BANG|FILES|EDITCMD|ARGOPT|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_gvim, "gvim", ex_gui,
+ BANG|FILES|EDITCMD|ARGOPT|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_help, "help", ex_help,
+ BANG|EXTRA|NOTRLCOM,
+ ADDR_LINES),
+EX(CMD_helpclose, "helpclose", ex_helpclose,
+ RANGE|NOTADR|COUNT|TRLBAR,
+ ADDR_LINES),
+EX(CMD_helpfind, "helpfind", ex_helpfind,
+ EXTRA|NOTRLCOM,
+ ADDR_LINES),
+EX(CMD_helpgrep, "helpgrep", ex_helpgrep,
+ EXTRA|NOTRLCOM|NEEDARG,
+ ADDR_LINES),
+EX(CMD_helptags, "helptags", ex_helptags,
+ NEEDARG|FILES|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_hardcopy, "hardcopy", ex_hardcopy,
+ RANGE|COUNT|EXTRA|TRLBAR|DFLALL|BANG,
+ ADDR_LINES),
+EX(CMD_highlight, "highlight", ex_highlight,
+ BANG|EXTRA|TRLBAR|SBOXOK|CMDWIN,
+ ADDR_LINES),
+EX(CMD_hide, "hide", ex_hide,
+ BANG|RANGE|NOTADR|COUNT|EXTRA|TRLBAR,
+ ADDR_WINDOWS),
+EX(CMD_history, "history", ex_history,
+ EXTRA|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_insert, "insert", ex_append,
+ BANG|RANGE|TRLBAR|CMDWIN|MODIFY,
+ ADDR_LINES),
+EX(CMD_iabbrev, "iabbrev", ex_abbreviate,
+ EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_iabclear, "iabclear", ex_abclear,
+ EXTRA|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_if, "if", ex_if,
+ EXTRA|NOTRLCOM|SBOXOK|CMDWIN,
+ ADDR_LINES),
+EX(CMD_ijump, "ijump", ex_findpat,
+ BANG|RANGE|DFLALL|WHOLEFOLD|EXTRA,
+ ADDR_LINES),
+EX(CMD_ilist, "ilist", ex_findpat,
+ BANG|RANGE|DFLALL|WHOLEFOLD|EXTRA|CMDWIN,
+ ADDR_LINES),
+EX(CMD_imap, "imap", ex_map,
+ EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_imapclear, "imapclear", ex_mapclear,
+ EXTRA|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_imenu, "imenu", ex_menu,
+ RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_inoremap, "inoremap", ex_map,
+ EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_inoreabbrev, "inoreabbrev", ex_abbreviate,
+ EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_inoremenu, "inoremenu", ex_menu,
+ RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_intro, "intro", ex_intro,
+ TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_isearch, "isearch", ex_findpat,
+ BANG|RANGE|DFLALL|WHOLEFOLD|EXTRA|CMDWIN,
+ ADDR_LINES),
+EX(CMD_isplit, "isplit", ex_findpat,
+ BANG|RANGE|DFLALL|WHOLEFOLD|EXTRA,
+ ADDR_LINES),
+EX(CMD_iunmap, "iunmap", ex_unmap,
+ EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_iunabbrev, "iunabbrev", ex_abbreviate,
+ EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_iunmenu, "iunmenu", ex_menu,
+ EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_join, "join", ex_join,
+ BANG|RANGE|WHOLEFOLD|COUNT|EXFLAGS|TRLBAR|CMDWIN|MODIFY,
+ ADDR_LINES),
+EX(CMD_jumps, "jumps", ex_jumps,
+ TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_k, "k", ex_mark,
+ RANGE|WORD1|TRLBAR|SBOXOK|CMDWIN,
+ ADDR_LINES),
+EX(CMD_keepmarks, "keepmarks", ex_wrongmodifier,
+ NEEDARG|EXTRA|NOTRLCOM,
+ ADDR_LINES),
+EX(CMD_keepjumps, "keepjumps", ex_wrongmodifier,
+ NEEDARG|EXTRA|NOTRLCOM,
+ ADDR_LINES),
+EX(CMD_keeppatterns, "keeppatterns", ex_wrongmodifier,
+ NEEDARG|EXTRA|NOTRLCOM,
+ ADDR_LINES),
+EX(CMD_keepalt, "keepalt", ex_wrongmodifier,
+ NEEDARG|EXTRA|NOTRLCOM,
+ ADDR_LINES),
+EX(CMD_list, "list", ex_print,
+ RANGE|WHOLEFOLD|COUNT|EXFLAGS|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_lNext, "lNext", ex_cnext,
+ RANGE|NOTADR|COUNT|TRLBAR|BANG,
+ ADDR_LINES),
+EX(CMD_lNfile, "lNfile", ex_cnext,
+ RANGE|NOTADR|COUNT|TRLBAR|BANG,
+ ADDR_LINES),
+EX(CMD_last, "last", ex_last,
+ EXTRA|BANG|EDITCMD|ARGOPT|TRLBAR,
+ ADDR_LINES),
+EX(CMD_language, "language", ex_language,
+ EXTRA|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_laddexpr, "laddexpr", ex_cexpr,
+ NEEDARG|WORD1|NOTRLCOM|TRLBAR,
+ ADDR_LINES),
+EX(CMD_laddbuffer, "laddbuffer", ex_cbuffer,
+ RANGE|NOTADR|WORD1|TRLBAR,
+ ADDR_LINES),
+EX(CMD_laddfile, "laddfile", ex_cfile,
+ TRLBAR|FILE1,
+ ADDR_LINES),
+EX(CMD_later, "later", ex_later,
+ TRLBAR|EXTRA|NOSPC|CMDWIN,
+ ADDR_LINES),
+EX(CMD_lbuffer, "lbuffer", ex_cbuffer,
+ BANG|RANGE|NOTADR|WORD1|TRLBAR,
+ ADDR_LINES),
+EX(CMD_lbottom, "lbottom", ex_cbottom,
+ TRLBAR,
+ ADDR_LINES),
+EX(CMD_lcd, "lcd", ex_cd,
+ BANG|FILE1|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_lchdir, "lchdir", ex_cd,
+ BANG|FILE1|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_lclose, "lclose", ex_cclose,
+ RANGE|NOTADR|COUNT|TRLBAR,
+ ADDR_LINES),
+EX(CMD_lcscope, "lcscope", ex_cscope,
+ EXTRA|NOTRLCOM|XFILE,
+ ADDR_LINES),
+EX(CMD_ldo, "ldo", ex_listdo,
+ BANG|NEEDARG|EXTRA|NOTRLCOM|RANGE|NOTADR|DFLALL,
+ ADDR_QUICKFIX),
+EX(CMD_left, "left", ex_align,
+ TRLBAR|RANGE|WHOLEFOLD|EXTRA|CMDWIN|MODIFY,
+ ADDR_LINES),
+EX(CMD_leftabove, "leftabove", ex_wrongmodifier,
+ NEEDARG|EXTRA|NOTRLCOM,
+ ADDR_LINES),
+EX(CMD_let, "let", ex_let,
+ EXTRA|NOTRLCOM|SBOXOK|CMDWIN,
+ ADDR_LINES),
+EX(CMD_lexpr, "lexpr", ex_cexpr,
+ NEEDARG|WORD1|NOTRLCOM|TRLBAR|BANG,
+ ADDR_LINES),
+EX(CMD_lfile, "lfile", ex_cfile,
+ TRLBAR|FILE1|BANG,
+ ADDR_LINES),
+EX(CMD_lfdo, "lfdo", ex_listdo,
+ BANG|NEEDARG|EXTRA|NOTRLCOM|RANGE|NOTADR|DFLALL,
+ ADDR_QUICKFIX),
+EX(CMD_lfirst, "lfirst", ex_cc,
+ RANGE|NOTADR|COUNT|TRLBAR|BANG,
+ ADDR_LINES),
+EX(CMD_lgetfile, "lgetfile", ex_cfile,
+ TRLBAR|FILE1,
+ ADDR_LINES),
+EX(CMD_lgetbuffer, "lgetbuffer", ex_cbuffer,
+ RANGE|NOTADR|WORD1|TRLBAR,
+ ADDR_LINES),
+EX(CMD_lgetexpr, "lgetexpr", ex_cexpr,
+ NEEDARG|WORD1|NOTRLCOM|TRLBAR,
+ ADDR_LINES),
+EX(CMD_lgrep, "lgrep", ex_make,
+ RANGE|NOTADR|BANG|NEEDARG|EXTRA|NOTRLCOM|TRLBAR|XFILE,
+ ADDR_LINES),
+EX(CMD_lgrepadd, "lgrepadd", ex_make,
+ RANGE|NOTADR|BANG|NEEDARG|EXTRA|NOTRLCOM|TRLBAR|XFILE,
+ ADDR_LINES),
+EX(CMD_lhelpgrep, "lhelpgrep", ex_helpgrep,
+ EXTRA|NOTRLCOM|NEEDARG,
+ ADDR_LINES),
+EX(CMD_lhistory, "lhistory", qf_history,
+ TRLBAR,
+ ADDR_LINES),
+EX(CMD_ll, "ll", ex_cc,
+ RANGE|NOTADR|COUNT|TRLBAR|BANG,
+ ADDR_LINES),
+EX(CMD_llast, "llast", ex_cc,
+ RANGE|NOTADR|COUNT|TRLBAR|BANG,
+ ADDR_LINES),
+EX(CMD_llist, "llist", qf_list,
+ BANG|EXTRA|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_lmap, "lmap", ex_map,
+ EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_lmapclear, "lmapclear", ex_mapclear,
+ EXTRA|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_lmake, "lmake", ex_make,
+ BANG|EXTRA|NOTRLCOM|TRLBAR|XFILE,
+ ADDR_LINES),
+EX(CMD_lnoremap, "lnoremap", ex_map,
+ EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_lnext, "lnext", ex_cnext,
+ RANGE|NOTADR|COUNT|TRLBAR|BANG,
+ ADDR_LINES),
+EX(CMD_lnewer, "lnewer", qf_age,
+ RANGE|NOTADR|COUNT|TRLBAR,
+ ADDR_LINES),
+EX(CMD_lnfile, "lnfile", ex_cnext,
+ RANGE|NOTADR|COUNT|TRLBAR|BANG,
+ ADDR_LINES),
+EX(CMD_loadview, "loadview", ex_loadview,
+ FILE1|TRLBAR,
+ ADDR_LINES),
+EX(CMD_loadkeymap, "loadkeymap", ex_loadkeymap,
+ CMDWIN,
+ ADDR_LINES),
+EX(CMD_lockmarks, "lockmarks", ex_wrongmodifier,
+ NEEDARG|EXTRA|NOTRLCOM,
+ ADDR_LINES),
+EX(CMD_lockvar, "lockvar", ex_lockvar,
+ BANG|EXTRA|NEEDARG|SBOXOK|CMDWIN,
+ ADDR_LINES),
+EX(CMD_lolder, "lolder", qf_age,
+ RANGE|NOTADR|COUNT|TRLBAR,
+ ADDR_LINES),
+EX(CMD_lopen, "lopen", ex_copen,
+ RANGE|NOTADR|COUNT|TRLBAR,
+ ADDR_LINES),
+EX(CMD_lprevious, "lprevious", ex_cnext,
+ RANGE|NOTADR|COUNT|TRLBAR|BANG,
+ ADDR_LINES),
+EX(CMD_lpfile, "lpfile", ex_cnext,
+ RANGE|NOTADR|COUNT|TRLBAR|BANG,
+ ADDR_LINES),
+EX(CMD_lrewind, "lrewind", ex_cc,
+ RANGE|NOTADR|COUNT|TRLBAR|BANG,
+ ADDR_LINES),
+EX(CMD_ltag, "ltag", ex_tag,
+ NOTADR|TRLBAR|BANG|WORD1,
+ ADDR_LINES),
+EX(CMD_lunmap, "lunmap", ex_unmap,
+ EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_lua, "lua", ex_lua,
+ RANGE|EXTRA|NEEDARG|CMDWIN,
+ ADDR_LINES),
+EX(CMD_luado, "luado", ex_luado,
+ RANGE|DFLALL|EXTRA|NEEDARG|CMDWIN,
+ ADDR_LINES),
+EX(CMD_luafile, "luafile", ex_luafile,
+ RANGE|FILE1|NEEDARG|CMDWIN,
+ ADDR_LINES),
+EX(CMD_lvimgrep, "lvimgrep", ex_vimgrep,
+ RANGE|NOTADR|BANG|NEEDARG|EXTRA|NOTRLCOM|TRLBAR|XFILE,
+ ADDR_LINES),
+EX(CMD_lvimgrepadd, "lvimgrepadd", ex_vimgrep,
+ RANGE|NOTADR|BANG|NEEDARG|EXTRA|NOTRLCOM|TRLBAR|XFILE,
+ ADDR_LINES),
+EX(CMD_lwindow, "lwindow", ex_cwindow,
+ RANGE|NOTADR|COUNT|TRLBAR,
+ ADDR_LINES),
+EX(CMD_ls, "ls", buflist_list,
+ BANG|EXTRA|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_move, "move", ex_copymove,
+ RANGE|WHOLEFOLD|EXTRA|TRLBAR|CMDWIN|MODIFY,
+ ADDR_LINES),
+EX(CMD_mark, "mark", ex_mark,
+ RANGE|WORD1|TRLBAR|SBOXOK|CMDWIN,
+ ADDR_LINES),
+EX(CMD_make, "make", ex_make,
+ BANG|EXTRA|NOTRLCOM|TRLBAR|XFILE,
+ ADDR_LINES),
+EX(CMD_map, "map", ex_map,
+ BANG|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_mapclear, "mapclear", ex_mapclear,
+ EXTRA|BANG|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_marks, "marks", do_marks,
+ EXTRA|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_match, "match", ex_match,
+ RANGE|NOTADR|EXTRA|CMDWIN,
+ ADDR_LINES),
+EX(CMD_menu, "menu", ex_menu,
+ RANGE|NOTADR|ZEROR|BANG|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_menutranslate, "menutranslate", ex_menutranslate,
+ EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_messages, "messages", ex_messages,
+ EXTRA|TRLBAR|RANGE|CMDWIN,
+ ADDR_OTHER),
+EX(CMD_mkexrc, "mkexrc", ex_mkrc,
+ BANG|FILE1|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_mksession, "mksession", ex_mkrc,
+ BANG|FILE1|TRLBAR,
+ ADDR_LINES),
+EX(CMD_mkspell, "mkspell", ex_mkspell,
+ BANG|NEEDARG|EXTRA|NOTRLCOM|TRLBAR|XFILE,
+ ADDR_LINES),
+EX(CMD_mkvimrc, "mkvimrc", ex_mkrc,
+ BANG|FILE1|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_mkview, "mkview", ex_mkrc,
+ BANG|FILE1|TRLBAR,
+ ADDR_LINES),
+EX(CMD_mode, "mode", ex_mode,
+ WORD1|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_mzscheme, "mzscheme", ex_mzscheme,
+ RANGE|EXTRA|DFLALL|NEEDARG|CMDWIN|SBOXOK,
+ ADDR_LINES),
+EX(CMD_mzfile, "mzfile", ex_mzfile,
+ RANGE|FILE1|NEEDARG|CMDWIN,
+ ADDR_LINES),
+EX(CMD_next, "next", ex_next,
+ RANGE|NOTADR|BANG|FILES|EDITCMD|ARGOPT|TRLBAR,
+ ADDR_LINES),
+EX(CMD_nbkey, "nbkey", ex_nbkey,
+ EXTRA|NOTADR|NEEDARG,
+ ADDR_LINES),
+EX(CMD_nbclose, "nbclose", ex_nbclose,
+ TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_nbstart, "nbstart", ex_nbstart,
+ WORD1|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_new, "new", ex_splitview,
+ BANG|FILE1|RANGE|NOTADR|EDITCMD|ARGOPT|TRLBAR,
+ ADDR_LINES),
+EX(CMD_nmap, "nmap", ex_map,
+ EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_nmapclear, "nmapclear", ex_mapclear,
+ EXTRA|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_nmenu, "nmenu", ex_menu,
+ RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_nnoremap, "nnoremap", ex_map,
+ EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_nnoremenu, "nnoremenu", ex_menu,
+ RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_noremap, "noremap", ex_map,
+ BANG|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_noautocmd, "noautocmd", ex_wrongmodifier,
+ NEEDARG|EXTRA|NOTRLCOM,
+ ADDR_LINES),
+EX(CMD_nohlsearch, "nohlsearch", ex_nohlsearch,
+ TRLBAR|SBOXOK|CMDWIN,
+ ADDR_LINES),
+EX(CMD_noreabbrev, "noreabbrev", ex_abbreviate,
+ EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_noremenu, "noremenu", ex_menu,
+ RANGE|NOTADR|ZEROR|BANG|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_noswapfile, "noswapfile", ex_wrongmodifier,
+ NEEDARG|EXTRA|NOTRLCOM,
+ ADDR_LINES),
+EX(CMD_normal, "normal", ex_normal,
+ RANGE|BANG|EXTRA|NEEDARG|NOTRLCOM|USECTRLV|SBOXOK|CMDWIN,
+ ADDR_LINES),
+EX(CMD_number, "number", ex_print,
+ RANGE|WHOLEFOLD|COUNT|EXFLAGS|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_nunmap, "nunmap", ex_unmap,
+ EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_nunmenu, "nunmenu", ex_menu,
+ EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_open, "open", ex_open,
+ RANGE|BANG|EXTRA,
+ ADDR_LINES),
+EX(CMD_oldfiles, "oldfiles", ex_oldfiles,
+ BANG|TRLBAR|SBOXOK|CMDWIN,
+ ADDR_LINES),
+EX(CMD_omap, "omap", ex_map,
+ EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_omapclear, "omapclear", ex_mapclear,
+ EXTRA|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_omenu, "omenu", ex_menu,
+ RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_only, "only", ex_only,
+ BANG|NOTADR|RANGE|COUNT|TRLBAR,
+ ADDR_WINDOWS),
+EX(CMD_onoremap, "onoremap", ex_map,
+ EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_onoremenu, "onoremenu", ex_menu,
+ RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_options, "options", ex_options,
+ TRLBAR,
+ ADDR_LINES),
+EX(CMD_ounmap, "ounmap", ex_unmap,
+ EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_ounmenu, "ounmenu", ex_menu,
+ EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_ownsyntax, "ownsyntax", ex_ownsyntax,
+ EXTRA|NOTRLCOM|SBOXOK|CMDWIN,
+ ADDR_LINES),
+EX(CMD_print, "print", ex_print,
+ RANGE|WHOLEFOLD|COUNT|EXFLAGS|TRLBAR|CMDWIN|SBOXOK,
+ ADDR_LINES),
+EX(CMD_packadd, "packadd", ex_packadd,
+ BANG|FILE1|NEEDARG|TRLBAR|SBOXOK|CMDWIN,
+ ADDR_LINES),
+EX(CMD_packloadall, "packloadall", ex_packloadall,
+ BANG|TRLBAR|SBOXOK|CMDWIN,
+ ADDR_LINES),
+EX(CMD_pclose, "pclose", ex_pclose,
+ BANG|TRLBAR,
+ ADDR_LINES),
+EX(CMD_perl, "perl", ex_perl,
+ RANGE|EXTRA|DFLALL|NEEDARG|SBOXOK|CMDWIN,
+ ADDR_LINES),
+EX(CMD_perldo, "perldo", ex_perldo,
+ RANGE|EXTRA|DFLALL|NEEDARG|CMDWIN,
+ ADDR_LINES),
+EX(CMD_pedit, "pedit", ex_pedit,
+ BANG|FILE1|EDITCMD|ARGOPT|TRLBAR,
+ ADDR_LINES),
+EX(CMD_pop, "pop", ex_tag,
+ RANGE|NOTADR|BANG|COUNT|TRLBAR|ZEROR,
+ ADDR_LINES),
+EX(CMD_popup, "popup", ex_popup,
+ NEEDARG|EXTRA|BANG|TRLBAR|NOTRLCOM|CMDWIN,
+ ADDR_LINES),
+EX(CMD_ppop, "ppop", ex_ptag,
+ RANGE|NOTADR|BANG|COUNT|TRLBAR|ZEROR,
+ ADDR_LINES),
+EX(CMD_preserve, "preserve", ex_preserve,
+ TRLBAR,
+ ADDR_LINES),
+EX(CMD_previous, "previous", ex_previous,
+ EXTRA|RANGE|NOTADR|COUNT|BANG|EDITCMD|ARGOPT|TRLBAR,
+ ADDR_LINES),
+EX(CMD_promptfind, "promptfind", gui_mch_find_dialog,
+ EXTRA|NOTRLCOM|CMDWIN,
+ ADDR_LINES),
+EX(CMD_promptrepl, "promptrepl", gui_mch_replace_dialog,
+ EXTRA|NOTRLCOM|CMDWIN,
+ ADDR_LINES),
+EX(CMD_profile, "profile", ex_profile,
+ BANG|EXTRA|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_profdel, "profdel", ex_breakdel,
+ EXTRA|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_psearch, "psearch", ex_psearch,
+ BANG|RANGE|WHOLEFOLD|DFLALL|EXTRA,
+ ADDR_LINES),
+EX(CMD_ptag, "ptag", ex_ptag,
+ RANGE|NOTADR|BANG|WORD1|TRLBAR|ZEROR,
+ ADDR_LINES),
+EX(CMD_ptNext, "ptNext", ex_ptag,
+ RANGE|NOTADR|BANG|TRLBAR|ZEROR,
+ ADDR_LINES),
+EX(CMD_ptfirst, "ptfirst", ex_ptag,
+ RANGE|NOTADR|BANG|TRLBAR|ZEROR,
+ ADDR_LINES),
+EX(CMD_ptjump, "ptjump", ex_ptag,
+ BANG|TRLBAR|WORD1,
+ ADDR_LINES),
+EX(CMD_ptlast, "ptlast", ex_ptag,
+ BANG|TRLBAR,
+ ADDR_LINES),
+EX(CMD_ptnext, "ptnext", ex_ptag,
+ RANGE|NOTADR|BANG|TRLBAR|ZEROR,
+ ADDR_LINES),
+EX(CMD_ptprevious, "ptprevious", ex_ptag,
+ RANGE|NOTADR|BANG|TRLBAR|ZEROR,
+ ADDR_LINES),
+EX(CMD_ptrewind, "ptrewind", ex_ptag,
+ RANGE|NOTADR|BANG|TRLBAR|ZEROR,
+ ADDR_LINES),
+EX(CMD_ptselect, "ptselect", ex_ptag,
+ BANG|TRLBAR|WORD1,
+ ADDR_LINES),
+EX(CMD_put, "put", ex_put,
+ RANGE|WHOLEFOLD|BANG|REGSTR|TRLBAR|ZEROR|CMDWIN|MODIFY,
+ ADDR_LINES),
+EX(CMD_pwd, "pwd", ex_pwd,
+ TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_python, "python", ex_python,
+ RANGE|EXTRA|NEEDARG|CMDWIN,
+ ADDR_LINES),
+EX(CMD_pydo, "pydo", ex_pydo,
+ RANGE|DFLALL|EXTRA|NEEDARG|CMDWIN,
+ ADDR_LINES),
+EX(CMD_pyfile, "pyfile", ex_pyfile,
+ RANGE|FILE1|NEEDARG|CMDWIN,
+ ADDR_LINES),
+EX(CMD_py3, "py3", ex_py3,
+ RANGE|EXTRA|NEEDARG|CMDWIN,
+ ADDR_LINES),
+EX(CMD_py3do, "py3do", ex_py3do,
+ RANGE|DFLALL|EXTRA|NEEDARG|CMDWIN,
+ ADDR_LINES),
+EX(CMD_python3, "python3", ex_py3,
+ RANGE|EXTRA|NEEDARG|CMDWIN,
+ ADDR_LINES),
+EX(CMD_py3file, "py3file", ex_py3file,
+ RANGE|FILE1|NEEDARG|CMDWIN,
+ ADDR_LINES),
+EX(CMD_pyx, "pyx", ex_pyx,
+ RANGE|EXTRA|NEEDARG|CMDWIN,
+ ADDR_LINES),
+EX(CMD_pyxdo, "pyxdo", ex_pyxdo,
+ RANGE|DFLALL|EXTRA|NEEDARG|CMDWIN,
+ ADDR_LINES),
+EX(CMD_pythonx, "pythonx", ex_pyx,
+ RANGE|EXTRA|NEEDARG|CMDWIN,
+ ADDR_LINES),
+EX(CMD_pyxfile, "pyxfile", ex_pyxfile,
+ RANGE|FILE1|NEEDARG|CMDWIN,
+ ADDR_LINES),
+EX(CMD_quit, "quit", ex_quit,
+ BANG|RANGE|COUNT|NOTADR|TRLBAR|CMDWIN,
+ ADDR_WINDOWS),
+EX(CMD_quitall, "quitall", ex_quit_all,
+ BANG|TRLBAR,
+ ADDR_LINES),
+EX(CMD_qall, "qall", ex_quit_all,
+ BANG|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_read, "read", ex_read,
+ BANG|RANGE|WHOLEFOLD|FILE1|ARGOPT|TRLBAR|ZEROR|CMDWIN|MODIFY,
+ ADDR_LINES),
+EX(CMD_recover, "recover", ex_recover,
+ BANG|FILE1|TRLBAR,
+ ADDR_LINES),
+EX(CMD_redo, "redo", ex_redo,
+ TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_redir, "redir", ex_redir,
+ BANG|FILES|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_redraw, "redraw", ex_redraw,
+ BANG|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_redrawstatus, "redrawstatus", ex_redrawstatus,
+ BANG|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_redrawtabline, "redrawtabline", ex_redrawtabline,
+ TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_registers, "registers", ex_display,
+ EXTRA|NOTRLCOM|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_resize, "resize", ex_resize,
+ RANGE|NOTADR|TRLBAR|WORD1|CMDWIN,
+ ADDR_LINES),
+EX(CMD_retab, "retab", ex_retab,
+ TRLBAR|RANGE|WHOLEFOLD|DFLALL|BANG|WORD1|CMDWIN|MODIFY,
+ ADDR_LINES),
+EX(CMD_return, "return", ex_return,
+ EXTRA|NOTRLCOM|SBOXOK|CMDWIN,
+ ADDR_LINES),
+EX(CMD_rewind, "rewind", ex_rewind,
+ EXTRA|BANG|EDITCMD|ARGOPT|TRLBAR,
+ ADDR_LINES),
+EX(CMD_right, "right", ex_align,
+ TRLBAR|RANGE|WHOLEFOLD|EXTRA|CMDWIN|MODIFY,
+ ADDR_LINES),
+EX(CMD_rightbelow, "rightbelow", ex_wrongmodifier,
+ NEEDARG|EXTRA|NOTRLCOM,
+ ADDR_LINES),
+EX(CMD_runtime, "runtime", ex_runtime,
+ BANG|NEEDARG|FILES|TRLBAR|SBOXOK|CMDWIN,
+ ADDR_LINES),
+EX(CMD_ruby, "ruby", ex_ruby,
+ RANGE|EXTRA|NEEDARG|CMDWIN,
+ ADDR_LINES),
+EX(CMD_rubydo, "rubydo", ex_rubydo,
+ RANGE|DFLALL|EXTRA|NEEDARG|CMDWIN,
+ ADDR_LINES),
+EX(CMD_rubyfile, "rubyfile", ex_rubyfile,
+ RANGE|FILE1|NEEDARG|CMDWIN,
+ ADDR_LINES),
+EX(CMD_rundo, "rundo", ex_rundo,
+ NEEDARG|FILE1,
+ ADDR_LINES),
+EX(CMD_rviminfo, "rviminfo", ex_viminfo,
+ BANG|FILE1|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_substitute, "substitute", do_sub,
+ RANGE|WHOLEFOLD|EXTRA|CMDWIN,
+ ADDR_LINES),
+EX(CMD_sNext, "sNext", ex_previous,
+ EXTRA|RANGE|NOTADR|COUNT|BANG|EDITCMD|ARGOPT|TRLBAR,
+ ADDR_LINES),
+EX(CMD_sargument, "sargument", ex_argument,
+ BANG|RANGE|NOTADR|COUNT|EXTRA|EDITCMD|ARGOPT|TRLBAR,
+ ADDR_ARGUMENTS),
+EX(CMD_sall, "sall", ex_all,
+ BANG|RANGE|NOTADR|COUNT|TRLBAR,
+ ADDR_LINES),
+EX(CMD_sandbox, "sandbox", ex_wrongmodifier,
+ NEEDARG|EXTRA|NOTRLCOM,
+ ADDR_LINES),
+EX(CMD_saveas, "saveas", ex_write,
+ BANG|DFLALL|FILE1|ARGOPT|CMDWIN|TRLBAR,
+ ADDR_LINES),
+EX(CMD_sbuffer, "sbuffer", ex_buffer,
+ BANG|RANGE|NOTADR|BUFNAME|BUFUNL|COUNT|EXTRA|EDITCMD|TRLBAR,
+ ADDR_BUFFERS),
+EX(CMD_sbNext, "sbNext", ex_bprevious,
+ RANGE|NOTADR|COUNT|EDITCMD|TRLBAR,
+ ADDR_LINES),
+EX(CMD_sball, "sball", ex_buffer_all,
+ RANGE|NOTADR|COUNT|EDITCMD|TRLBAR,
+ ADDR_LINES),
+EX(CMD_sbfirst, "sbfirst", ex_brewind,
+ EDITCMD|TRLBAR,
+ ADDR_LINES),
+EX(CMD_sblast, "sblast", ex_blast,
+ EDITCMD|TRLBAR,
+ ADDR_LINES),
+EX(CMD_sbmodified, "sbmodified", ex_bmodified,
+ RANGE|NOTADR|COUNT|EDITCMD|TRLBAR,
+ ADDR_LINES),
+EX(CMD_sbnext, "sbnext", ex_bnext,
+ RANGE|NOTADR|COUNT|EDITCMD|TRLBAR,
+ ADDR_LINES),
+EX(CMD_sbprevious, "sbprevious", ex_bprevious,
+ RANGE|NOTADR|COUNT|EDITCMD|TRLBAR,
+ ADDR_LINES),
+EX(CMD_sbrewind, "sbrewind", ex_brewind,
+ EDITCMD|TRLBAR,
+ ADDR_LINES),
+EX(CMD_scriptnames, "scriptnames", ex_scriptnames,
+ BANG|RANGE|NOTADR|COUNT|TRLBAR|CMDWIN,
+ ADDR_OTHER),
+EX(CMD_scriptencoding, "scriptencoding", ex_scriptencoding,
+ WORD1|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_scscope, "scscope", ex_scscope,
+ EXTRA|NOTRLCOM,
+ ADDR_LINES),
+EX(CMD_set, "set", ex_set,
+ TRLBAR|EXTRA|CMDWIN|SBOXOK,
+ ADDR_LINES),
+EX(CMD_setfiletype, "setfiletype", ex_setfiletype,
+ TRLBAR|EXTRA|NEEDARG|CMDWIN,
+ ADDR_LINES),
+EX(CMD_setglobal, "setglobal", ex_set,
+ TRLBAR|EXTRA|CMDWIN|SBOXOK,
+ ADDR_LINES),
+EX(CMD_setlocal, "setlocal", ex_set,
+ TRLBAR|EXTRA|CMDWIN|SBOXOK,
+ ADDR_LINES),
+EX(CMD_sfind, "sfind", ex_splitview,
+ BANG|FILE1|RANGE|NOTADR|EDITCMD|ARGOPT|TRLBAR,
+ ADDR_LINES),
+EX(CMD_sfirst, "sfirst", ex_rewind,
+ EXTRA|BANG|EDITCMD|ARGOPT|TRLBAR,
+ ADDR_LINES),
+EX(CMD_shell, "shell", ex_shell,
+ TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_simalt, "simalt", ex_simalt,
+ NEEDARG|WORD1|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_sign, "sign", ex_sign,
+ NEEDARG|RANGE|NOTADR|EXTRA|CMDWIN,
+ ADDR_LINES),
+EX(CMD_silent, "silent", ex_wrongmodifier,
+ NEEDARG|EXTRA|BANG|NOTRLCOM|SBOXOK|CMDWIN,
+ ADDR_LINES),
+EX(CMD_sleep, "sleep", ex_sleep,
+ RANGE|NOTADR|COUNT|EXTRA|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_slast, "slast", ex_last,
+ EXTRA|BANG|EDITCMD|ARGOPT|TRLBAR,
+ ADDR_LINES),
+EX(CMD_smagic, "smagic", ex_submagic,
+ RANGE|WHOLEFOLD|EXTRA|CMDWIN,
+ ADDR_LINES),
+EX(CMD_smap, "smap", ex_map,
+ EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_smapclear, "smapclear", ex_mapclear,
+ EXTRA|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_smenu, "smenu", ex_menu,
+ RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_snext, "snext", ex_next,
+ RANGE|NOTADR|BANG|FILES|EDITCMD|ARGOPT|TRLBAR,
+ ADDR_LINES),
+EX(CMD_snomagic, "snomagic", ex_submagic,
+ RANGE|WHOLEFOLD|EXTRA|CMDWIN,
+ ADDR_LINES),
+EX(CMD_snoremap, "snoremap", ex_map,
+ EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_snoremenu, "snoremenu", ex_menu,
+ RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_source, "source", ex_source,
+ BANG|FILE1|TRLBAR|SBOXOK|CMDWIN,
+ ADDR_LINES),
+EX(CMD_sort, "sort", ex_sort,
+ RANGE|DFLALL|WHOLEFOLD|BANG|EXTRA|NOTRLCOM|MODIFY,
+ ADDR_LINES),
+EX(CMD_split, "split", ex_splitview,
+ BANG|FILE1|RANGE|NOTADR|EDITCMD|ARGOPT|TRLBAR,
+ ADDR_LINES),
+EX(CMD_spellgood, "spellgood", ex_spell,
+ BANG|RANGE|NOTADR|NEEDARG|EXTRA|TRLBAR,
+ ADDR_LINES),
+EX(CMD_spelldump, "spelldump", ex_spelldump,
+ BANG|TRLBAR,
+ ADDR_LINES),
+EX(CMD_spellinfo, "spellinfo", ex_spellinfo,
+ TRLBAR,
+ ADDR_LINES),
+EX(CMD_spellrepall, "spellrepall", ex_spellrepall,
+ TRLBAR,
+ ADDR_LINES),
+EX(CMD_spellundo, "spellundo", ex_spell,
+ BANG|RANGE|NOTADR|NEEDARG|EXTRA|TRLBAR,
+ ADDR_LINES),
+EX(CMD_spellwrong, "spellwrong", ex_spell,
+ BANG|RANGE|NOTADR|NEEDARG|EXTRA|TRLBAR,
+ ADDR_LINES),
+EX(CMD_sprevious, "sprevious", ex_previous,
+ EXTRA|RANGE|NOTADR|COUNT|BANG|EDITCMD|ARGOPT|TRLBAR,
+ ADDR_LINES),
+EX(CMD_srewind, "srewind", ex_rewind,
+ EXTRA|BANG|EDITCMD|ARGOPT|TRLBAR,
+ ADDR_LINES),
+EX(CMD_stop, "stop", ex_stop,
+ TRLBAR|BANG|CMDWIN,
+ ADDR_LINES),
+EX(CMD_stag, "stag", ex_stag,
+ RANGE|NOTADR|BANG|WORD1|TRLBAR|ZEROR,
+ ADDR_LINES),
+EX(CMD_startinsert, "startinsert", ex_startinsert,
+ BANG|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_startgreplace, "startgreplace", ex_startinsert,
+ BANG|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_startreplace, "startreplace", ex_startinsert,
+ BANG|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_stopinsert, "stopinsert", ex_stopinsert,
+ BANG|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_stjump, "stjump", ex_stag,
+ BANG|TRLBAR|WORD1,
+ ADDR_LINES),
+EX(CMD_stselect, "stselect", ex_stag,
+ BANG|TRLBAR|WORD1,
+ ADDR_LINES),
+EX(CMD_sunhide, "sunhide", ex_buffer_all,
+ RANGE|NOTADR|COUNT|TRLBAR,
+ ADDR_LINES),
+EX(CMD_sunmap, "sunmap", ex_unmap,
+ EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_sunmenu, "sunmenu", ex_menu,
+ EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_suspend, "suspend", ex_stop,
+ TRLBAR|BANG|CMDWIN,
+ ADDR_LINES),
+EX(CMD_sview, "sview", ex_splitview,
+ BANG|FILE1|RANGE|NOTADR|EDITCMD|ARGOPT|TRLBAR,
+ ADDR_LINES),
+EX(CMD_swapname, "swapname", ex_swapname,
+ TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_syntax, "syntax", ex_syntax,
+ EXTRA|NOTRLCOM|CMDWIN,
+ ADDR_LINES),
+EX(CMD_syntime, "syntime", ex_syntime,
+ NEEDARG|WORD1|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_syncbind, "syncbind", ex_syncbind,
+ TRLBAR,
+ ADDR_LINES),
+EX(CMD_smile, "smile", ex_smile,
+ TRLBAR|CMDWIN|SBOXOK,
+ ADDR_LINES),
+EX(CMD_t, "t", ex_copymove,
+ RANGE|WHOLEFOLD|EXTRA|TRLBAR|CMDWIN|MODIFY,
+ ADDR_LINES),
+EX(CMD_tNext, "tNext", ex_tag,
+ RANGE|NOTADR|BANG|TRLBAR|ZEROR,
+ ADDR_LINES),
+EX(CMD_tag, "tag", ex_tag,
+ RANGE|NOTADR|BANG|WORD1|TRLBAR|ZEROR,
+ ADDR_LINES),
+EX(CMD_tags, "tags", do_tags,
+ TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_tab, "tab", ex_wrongmodifier,
+ NEEDARG|EXTRA|NOTRLCOM,
+ ADDR_TABS),
+EX(CMD_tabclose, "tabclose", ex_tabclose,
+ BANG|RANGE|NOTADR|ZEROR|EXTRA|NOSPC|TRLBAR|CMDWIN,
+ ADDR_TABS),
+EX(CMD_tabdo, "tabdo", ex_listdo,
+ NEEDARG|EXTRA|NOTRLCOM|RANGE|NOTADR|DFLALL,
+ ADDR_TABS),
+EX(CMD_tabedit, "tabedit", ex_splitview,
+ BANG|FILE1|RANGE|NOTADR|ZEROR|EDITCMD|ARGOPT|TRLBAR,
+ ADDR_TABS),
+EX(CMD_tabfind, "tabfind", ex_splitview,
+ BANG|FILE1|RANGE|NOTADR|ZEROR|EDITCMD|ARGOPT|NEEDARG|TRLBAR,
+ ADDR_TABS),
+EX(CMD_tabfirst, "tabfirst", ex_tabnext,
+ TRLBAR,
+ ADDR_TABS),
+EX(CMD_tabmove, "tabmove", ex_tabmove,
+ RANGE|NOTADR|ZEROR|EXTRA|NOSPC|TRLBAR,
+ ADDR_TABS),
+EX(CMD_tablast, "tablast", ex_tabnext,
+ TRLBAR,
+ ADDR_TABS),
+EX(CMD_tabnext, "tabnext", ex_tabnext,
+ RANGE|NOTADR|ZEROR|EXTRA|NOSPC|TRLBAR,
+ ADDR_TABS),
+EX(CMD_tabnew, "tabnew", ex_splitview,
+ BANG|FILE1|RANGE|NOTADR|ZEROR|EDITCMD|ARGOPT|TRLBAR,
+ ADDR_TABS),
+EX(CMD_tabonly, "tabonly", ex_tabonly,
+ BANG|RANGE|NOTADR|ZEROR|EXTRA|NOSPC|TRLBAR|CMDWIN,
+ ADDR_TABS),
+EX(CMD_tabprevious, "tabprevious", ex_tabnext,
+ RANGE|NOTADR|ZEROR|EXTRA|NOSPC|TRLBAR,
+ ADDR_TABS_RELATIVE),
+EX(CMD_tabNext, "tabNext", ex_tabnext,
+ RANGE|NOTADR|ZEROR|EXTRA|NOSPC|TRLBAR,
+ ADDR_TABS_RELATIVE),
+EX(CMD_tabrewind, "tabrewind", ex_tabnext,
+ TRLBAR,
+ ADDR_TABS),
+EX(CMD_tabs, "tabs", ex_tabs,
+ TRLBAR|CMDWIN,
+ ADDR_TABS),
+EX(CMD_tcl, "tcl", ex_tcl,
+ RANGE|EXTRA|NEEDARG|CMDWIN,
+ ADDR_LINES),
+EX(CMD_tcldo, "tcldo", ex_tcldo,
+ RANGE|DFLALL|EXTRA|NEEDARG|CMDWIN,
+ ADDR_LINES),
+EX(CMD_tclfile, "tclfile", ex_tclfile,
+ RANGE|FILE1|NEEDARG|CMDWIN,
+ ADDR_LINES),
+EX(CMD_tearoff, "tearoff", ex_tearoff,
+ NEEDARG|EXTRA|TRLBAR|NOTRLCOM|CMDWIN,
+ ADDR_LINES),
+EX(CMD_terminal, "terminal", ex_terminal,
+ RANGE|BANG|FILES|CMDWIN,
+ ADDR_LINES),
+EX(CMD_tfirst, "tfirst", ex_tag,
+ RANGE|NOTADR|BANG|TRLBAR|ZEROR,
+ ADDR_LINES),
+EX(CMD_throw, "throw", ex_throw,
+ EXTRA|NEEDARG|SBOXOK|CMDWIN,
+ ADDR_LINES),
+EX(CMD_tjump, "tjump", ex_tag,
+ BANG|TRLBAR|WORD1,
+ ADDR_LINES),
+EX(CMD_tlast, "tlast", ex_tag,
+ BANG|TRLBAR,
+ ADDR_LINES),
+EX(CMD_tlmenu, "tlmenu", ex_menu,
+ RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_tlnoremenu, "tlnoremenu", ex_menu,
+ RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_tlunmenu, "tlunmenu", ex_menu,
+ RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_tmenu, "tmenu", ex_menu,
+ RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_tmap, "tmap", ex_map,
+ EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_tmapclear, "tmapclear", ex_mapclear,
+ EXTRA|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_tnext, "tnext", ex_tag,
+ RANGE|NOTADR|BANG|TRLBAR|ZEROR,
+ ADDR_LINES),
+EX(CMD_tnoremap, "tnoremap", ex_map,
+ EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_topleft, "topleft", ex_wrongmodifier,
+ NEEDARG|EXTRA|NOTRLCOM,
+ ADDR_LINES),
+EX(CMD_tprevious, "tprevious", ex_tag,
+ RANGE|NOTADR|BANG|TRLBAR|ZEROR,
+ ADDR_LINES),
+EX(CMD_trewind, "trewind", ex_tag,
+ RANGE|NOTADR|BANG|TRLBAR|ZEROR,
+ ADDR_LINES),
+EX(CMD_try, "try", ex_try,
+ TRLBAR|SBOXOK|CMDWIN,
+ ADDR_LINES),
+EX(CMD_tselect, "tselect", ex_tag,
+ BANG|TRLBAR|WORD1,
+ ADDR_LINES),
+EX(CMD_tunmenu, "tunmenu", ex_menu,
+ EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_tunmap, "tunmap", ex_unmap,
+ EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_undo, "undo", ex_undo,
+ RANGE|NOTADR|COUNT|ZEROR|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_undojoin, "undojoin", ex_undojoin,
+ TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_undolist, "undolist", ex_undolist,
+ TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_unabbreviate, "unabbreviate", ex_abbreviate,
+ EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_unhide, "unhide", ex_buffer_all,
+ RANGE|NOTADR|COUNT|TRLBAR,
+ ADDR_LINES),
+EX(CMD_unlet, "unlet", ex_unlet,
+ BANG|EXTRA|NEEDARG|SBOXOK|CMDWIN,
+ ADDR_LINES),
+EX(CMD_unlockvar, "unlockvar", ex_lockvar,
+ BANG|EXTRA|NEEDARG|SBOXOK|CMDWIN,
+ ADDR_LINES),
+EX(CMD_unmap, "unmap", ex_unmap,
+ BANG|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_unmenu, "unmenu", ex_menu,
+ BANG|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_unsilent, "unsilent", ex_wrongmodifier,
+ NEEDARG|EXTRA|NOTRLCOM|SBOXOK|CMDWIN,
+ ADDR_LINES),
+EX(CMD_update, "update", ex_update,
+ RANGE|WHOLEFOLD|BANG|FILE1|ARGOPT|DFLALL|TRLBAR,
+ ADDR_LINES),
+EX(CMD_vglobal, "vglobal", ex_global,
+ RANGE|WHOLEFOLD|EXTRA|DFLALL|CMDWIN,
+ ADDR_LINES),
+EX(CMD_version, "version", ex_version,
+ EXTRA|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_verbose, "verbose", ex_wrongmodifier,
+ NEEDARG|RANGE|NOTADR|EXTRA|NOTRLCOM|SBOXOK|CMDWIN,
+ ADDR_LINES),
+EX(CMD_vertical, "vertical", ex_wrongmodifier,
+ NEEDARG|EXTRA|NOTRLCOM,
+ ADDR_LINES),
+EX(CMD_visual, "visual", ex_edit,
+ BANG|FILE1|EDITCMD|ARGOPT|TRLBAR,
+ ADDR_LINES),
+EX(CMD_view, "view", ex_edit,
+ BANG|FILE1|EDITCMD|ARGOPT|TRLBAR,
+ ADDR_LINES),
+EX(CMD_vimgrep, "vimgrep", ex_vimgrep,
+ RANGE|NOTADR|BANG|NEEDARG|EXTRA|NOTRLCOM|TRLBAR|XFILE,
+ ADDR_LINES),
+EX(CMD_vimgrepadd, "vimgrepadd", ex_vimgrep,
+ RANGE|NOTADR|BANG|NEEDARG|EXTRA|NOTRLCOM|TRLBAR|XFILE,
+ ADDR_LINES),
+EX(CMD_viusage, "viusage", ex_viusage,
+ TRLBAR,
+ ADDR_LINES),
+EX(CMD_vmap, "vmap", ex_map,
+ EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_vmapclear, "vmapclear", ex_mapclear,
+ EXTRA|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_vmenu, "vmenu", ex_menu,
+ RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_vnoremap, "vnoremap", ex_map,
+ EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_vnew, "vnew", ex_splitview,
+ BANG|FILE1|RANGE|NOTADR|EDITCMD|ARGOPT|TRLBAR,
+ ADDR_LINES),
+EX(CMD_vnoremenu, "vnoremenu", ex_menu,
+ RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_vsplit, "vsplit", ex_splitview,
+ BANG|FILE1|RANGE|NOTADR|EDITCMD|ARGOPT|TRLBAR,
+ ADDR_LINES),
+EX(CMD_vunmap, "vunmap", ex_unmap,
+ EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_vunmenu, "vunmenu", ex_menu,
+ EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_write, "write", ex_write,
+ RANGE|WHOLEFOLD|BANG|FILE1|ARGOPT|DFLALL|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_wNext, "wNext", ex_wnext,
+ RANGE|WHOLEFOLD|NOTADR|BANG|FILE1|ARGOPT|TRLBAR,
+ ADDR_LINES),
+EX(CMD_wall, "wall", do_wqall,
+ BANG|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_while, "while", ex_while,
+ EXTRA|NOTRLCOM|SBOXOK|CMDWIN,
+ ADDR_LINES),
+EX(CMD_winsize, "winsize", ex_winsize,
+ EXTRA|NEEDARG|TRLBAR,
+ ADDR_LINES),
+EX(CMD_wincmd, "wincmd", ex_wincmd,
+ NEEDARG|WORD1|RANGE|NOTADR|CMDWIN,
+ ADDR_WINDOWS),
+EX(CMD_windo, "windo", ex_listdo,
+ NEEDARG|EXTRA|NOTRLCOM|RANGE|NOTADR|DFLALL,
+ ADDR_WINDOWS),
+EX(CMD_winpos, "winpos", ex_winpos,
+ EXTRA|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_wnext, "wnext", ex_wnext,
+ RANGE|NOTADR|BANG|FILE1|ARGOPT|TRLBAR,
+ ADDR_LINES),
+EX(CMD_wprevious, "wprevious", ex_wnext,
+ RANGE|NOTADR|BANG|FILE1|ARGOPT|TRLBAR,
+ ADDR_LINES),
+EX(CMD_wq, "wq", ex_exit,
+ RANGE|WHOLEFOLD|BANG|FILE1|ARGOPT|DFLALL|TRLBAR,
+ ADDR_LINES),
+EX(CMD_wqall, "wqall", do_wqall,
+ BANG|FILE1|ARGOPT|DFLALL|TRLBAR,
+ ADDR_LINES),
+EX(CMD_wundo, "wundo", ex_wundo,
+ BANG|NEEDARG|FILE1,
+ ADDR_LINES),
+EX(CMD_wviminfo, "wviminfo", ex_viminfo,
+ BANG|FILE1|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_xit, "xit", ex_exit,
+ RANGE|WHOLEFOLD|BANG|FILE1|ARGOPT|DFLALL|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_xall, "xall", do_wqall,
+ BANG|TRLBAR,
+ ADDR_LINES),
+EX(CMD_xmap, "xmap", ex_map,
+ EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_xmapclear, "xmapclear", ex_mapclear,
+ EXTRA|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_xmenu, "xmenu", ex_menu,
+ RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_xnoremap, "xnoremap", ex_map,
+ EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_xnoremenu, "xnoremenu", ex_menu,
+ RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_xunmap, "xunmap", ex_unmap,
+ EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_xunmenu, "xunmenu", ex_menu,
+ EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+ ADDR_LINES),
+EX(CMD_yank, "yank", ex_operators,
+ RANGE|WHOLEFOLD|REGSTR|COUNT|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_z, "z", ex_z,
+ RANGE|WHOLEFOLD|EXTRA|EXFLAGS|TRLBAR|CMDWIN,
+ ADDR_LINES),
+
+/* commands that don't start with a lowercase letter */
+EX(CMD_bang, "!", ex_bang,
+ RANGE|WHOLEFOLD|BANG|FILES|CMDWIN,
+ ADDR_LINES),
+EX(CMD_pound, "#", ex_print,
+ RANGE|WHOLEFOLD|COUNT|EXFLAGS|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_and, "&", do_sub,
+ RANGE|WHOLEFOLD|EXTRA|CMDWIN|MODIFY,
+ ADDR_LINES),
+EX(CMD_star, "*", ex_at,
+ RANGE|WHOLEFOLD|EXTRA|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_lshift, "<", ex_operators,
+ RANGE|WHOLEFOLD|COUNT|EXFLAGS|TRLBAR|CMDWIN|MODIFY,
+ ADDR_LINES),
+EX(CMD_equal, "=", ex_equal,
+ RANGE|TRLBAR|DFLALL|EXFLAGS|CMDWIN,
+ ADDR_LINES),
+EX(CMD_rshift, ">", ex_operators,
+ RANGE|WHOLEFOLD|COUNT|EXFLAGS|TRLBAR|CMDWIN|MODIFY,
+ ADDR_LINES),
+EX(CMD_at, "@", ex_at,
+ RANGE|WHOLEFOLD|EXTRA|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_Next, "Next", ex_previous,
+ EXTRA|RANGE|NOTADR|COUNT|BANG|EDITCMD|ARGOPT|TRLBAR,
+ ADDR_LINES),
+EX(CMD_Print, "Print", ex_print,
+ RANGE|WHOLEFOLD|COUNT|EXFLAGS|TRLBAR|CMDWIN,
+ ADDR_LINES),
+EX(CMD_X, "X", ex_X,
+ TRLBAR,
+ ADDR_LINES),
+EX(CMD_tilde, "~", do_sub,
+ RANGE|WHOLEFOLD|EXTRA|CMDWIN|MODIFY,
+ ADDR_LINES),
+
+#ifndef DO_DECLARE_EXCMD
+#ifdef FEAT_USR_CMDS
+ CMD_SIZE, /* MUST be after all real commands! */
+ CMD_USER = -1, /* User-defined command */
+ CMD_USER_BUF = -2 /* User-defined command local to buffer */
+#else
+ CMD_SIZE /* MUST be the last one! */
+#endif
+#endif
+};
+
+#ifndef DO_DECLARE_EXCMD
+typedef enum CMD_index cmdidx_T;
+
+/*
+ * Arguments used for Ex commands.
+ */
+struct exarg
+{
+ char_u *arg; /* argument of the command */
+ char_u *nextcmd; /* next command (NULL if none) */
+ char_u *cmd; /* the name of the command (except for :make) */
+ char_u **cmdlinep; /* pointer to pointer of allocated cmdline */
+ cmdidx_T cmdidx; /* the index for the command */
+ long argt; /* flags for the command */
+ int skip; /* don't execute the command, only parse it */
+ int forceit; /* TRUE if ! present */
+ int addr_count; /* the number of addresses given */
+ linenr_T line1; /* the first line number */
+ linenr_T line2; /* the second line number or count */
+ int addr_type; /* type of the count/range */
+ int flags; /* extra flags after count: EXFLAG_ */
+ char_u *do_ecmd_cmd; /* +command arg to be used in edited file */
+ linenr_T do_ecmd_lnum; /* the line number in an edited file */
+ int append; /* TRUE with ":w >>file" command */
+ int usefilter; /* TRUE with ":w !command" and ":r!command" */
+ int amount; /* number of '>' or '<' for shift command */
+ int regname; /* register name (NUL if none) */
+ int force_bin; /* 0, FORCE_BIN or FORCE_NOBIN */
+ int read_edit; /* ++edit argument */
+ int force_ff; /* ++ff= argument (first char of argument) */
+ int force_enc; /* ++enc= argument (index in cmd[]) */
+ int bad_char; /* BAD_KEEP, BAD_DROP or replacement byte */
+#ifdef FEAT_USR_CMDS
+ int useridx; /* user command index */
+#endif
+ char *errmsg; /* returned error message */
+ char_u *(*getline)(int, void *, int);
+ void *cookie; /* argument for getline() */
+#ifdef FEAT_EVAL
+ struct condstack *cstack; /* condition stack for ":if" etc. */
+#endif
+ long verbose_save; // saved value of p_verbose
+ int save_msg_silent; // saved value of msg_silent
+ int did_esilent; // how many times emsg_silent was incremented
+#ifdef HAVE_SANDBOX
+ int did_sandbox; // when TRUE did ++sandbox
+#endif
+};
+
+#define FORCE_BIN 1 /* ":edit ++bin file" */
+#define FORCE_NOBIN 2 /* ":edit ++nobin file" */
+
+/* Values for "flags" */
+#define EXFLAG_LIST 0x01 /* 'l': list */
+#define EXFLAG_NR 0x02 /* '#': number */
+#define EXFLAG_PRINT 0x04 /* 'p': print */
+
+#endif
diff --git a/src/ex_cmds2.c b/src/ex_cmds2.c
new file mode 100644
index 0000000..30efcdf
--- /dev/null
+++ b/src/ex_cmds2.c
@@ -0,0 +1,5729 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * ex_cmds2.c: some more functions for command line commands
+ */
+
+#include "vim.h"
+#include "version.h"
+
+static void cmd_source(char_u *fname, exarg_T *eap);
+
+#ifdef FEAT_EVAL
+/* Growarray to store info about already sourced scripts.
+ * For Unix also store the dev/ino, so that we don't have to stat() each
+ * script when going through the list. */
+typedef struct scriptitem_S
+{
+ char_u *sn_name;
+# ifdef UNIX
+ int sn_dev_valid;
+ dev_t sn_dev;
+ ino_t sn_ino;
+# endif
+# ifdef FEAT_PROFILE
+ int sn_prof_on; /* TRUE when script is/was profiled */
+ int sn_pr_force; /* forceit: profile functions in this script */
+ proftime_T sn_pr_child; /* time set when going into first child */
+ int sn_pr_nest; /* nesting for sn_pr_child */
+ /* profiling the script as a whole */
+ int sn_pr_count; /* nr of times sourced */
+ proftime_T sn_pr_total; /* time spent in script + children */
+ proftime_T sn_pr_self; /* time spent in script itself */
+ proftime_T sn_pr_start; /* time at script start */
+ proftime_T sn_pr_children; /* time in children after script start */
+ /* profiling the script per line */
+ garray_T sn_prl_ga; /* things stored for every line */
+ proftime_T sn_prl_start; /* start time for current line */
+ proftime_T sn_prl_children; /* time spent in children for this line */
+ proftime_T sn_prl_wait; /* wait start time for current line */
+ int sn_prl_idx; /* index of line being timed; -1 if none */
+ int sn_prl_execed; /* line being timed was executed */
+# endif
+} scriptitem_T;
+
+static garray_T script_items = {0, 0, sizeof(scriptitem_T), 4, NULL};
+#define SCRIPT_ITEM(id) (((scriptitem_T *)script_items.ga_data)[(id) - 1])
+
+# ifdef FEAT_PROFILE
+/* Struct used in sn_prl_ga for every line of a script. */
+typedef struct sn_prl_S
+{
+ int snp_count; /* nr of times line was executed */
+ proftime_T sn_prl_total; /* time spent in a line + children */
+ proftime_T sn_prl_self; /* time spent in a line itself */
+} sn_prl_T;
+
+# define PRL_ITEM(si, idx) (((sn_prl_T *)(si)->sn_prl_ga.ga_data)[(idx)])
+# endif
+#endif
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+static int debug_greedy = FALSE; /* batch mode debugging: don't save
+ and restore typeahead. */
+static void do_setdebugtracelevel(char_u *arg);
+static void do_checkbacktracelevel(void);
+static void do_showbacktrace(char_u *cmd);
+
+static char_u *debug_oldval = NULL; /* old and newval for debug expressions */
+static char_u *debug_newval = NULL;
+static int debug_expr = 0; /* use debug_expr */
+
+ int
+has_watchexpr(void)
+{
+ return debug_expr;
+}
+
+/*
+ * do_debug(): Debug mode.
+ * Repeatedly get Ex commands, until told to continue normal execution.
+ */
+ void
+do_debug(char_u *cmd)
+{
+ int save_msg_scroll = msg_scroll;
+ int save_State = State;
+ int save_did_emsg = did_emsg;
+ int save_cmd_silent = cmd_silent;
+ int save_msg_silent = msg_silent;
+ int save_emsg_silent = emsg_silent;
+ int save_redir_off = redir_off;
+ tasave_T typeaheadbuf;
+ int typeahead_saved = FALSE;
+ int save_ignore_script = 0;
+ int save_ex_normal_busy;
+ int n;
+ char_u *cmdline = NULL;
+ char_u *p;
+ char *tail = NULL;
+ static int last_cmd = 0;
+#define CMD_CONT 1
+#define CMD_NEXT 2
+#define CMD_STEP 3
+#define CMD_FINISH 4
+#define CMD_QUIT 5
+#define CMD_INTERRUPT 6
+#define CMD_BACKTRACE 7
+#define CMD_FRAME 8
+#define CMD_UP 9
+#define CMD_DOWN 10
+
+#ifdef ALWAYS_USE_GUI
+ /* Can't do this when there is no terminal for input/output. */
+ if (!gui.in_use)
+ {
+ /* Break as soon as possible. */
+ debug_break_level = 9999;
+ return;
+ }
+#endif
+
+ /* Make sure we are in raw mode and start termcap mode. Might have side
+ * effects... */
+ settmode(TMODE_RAW);
+ starttermcap();
+
+ ++RedrawingDisabled; /* don't redisplay the window */
+ ++no_wait_return; /* don't wait for return */
+ did_emsg = FALSE; /* don't use error from debugged stuff */
+ cmd_silent = FALSE; /* display commands */
+ msg_silent = FALSE; /* display messages */
+ emsg_silent = FALSE; /* display error messages */
+ redir_off = TRUE; /* don't redirect debug commands */
+
+ State = NORMAL;
+ debug_mode = TRUE;
+
+ if (!debug_did_msg)
+ msg(_("Entering Debug mode. Type \"cont\" to continue."));
+ if (debug_oldval != NULL)
+ {
+ smsg(_("Oldval = \"%s\""), debug_oldval);
+ vim_free(debug_oldval);
+ debug_oldval = NULL;
+ }
+ if (debug_newval != NULL)
+ {
+ smsg(_("Newval = \"%s\""), debug_newval);
+ vim_free(debug_newval);
+ debug_newval = NULL;
+ }
+ if (sourcing_name != NULL)
+ msg((char *)sourcing_name);
+ if (sourcing_lnum != 0)
+ smsg(_("line %ld: %s"), (long)sourcing_lnum, cmd);
+ else
+ smsg(_("cmd: %s"), cmd);
+ /*
+ * Repeat getting a command and executing it.
+ */
+ for (;;)
+ {
+ msg_scroll = TRUE;
+ need_wait_return = FALSE;
+
+ /* Save the current typeahead buffer and replace it with an empty one.
+ * This makes sure we get input from the user here and don't interfere
+ * with the commands being executed. Reset "ex_normal_busy" to avoid
+ * the side effects of using ":normal". Save the stuff buffer and make
+ * it empty. Set ignore_script to avoid reading from script input. */
+ save_ex_normal_busy = ex_normal_busy;
+ ex_normal_busy = 0;
+ if (!debug_greedy)
+ {
+ save_typeahead(&typeaheadbuf);
+ typeahead_saved = TRUE;
+ save_ignore_script = ignore_script;
+ ignore_script = TRUE;
+ }
+
+ vim_free(cmdline);
+ cmdline = getcmdline_prompt('>', NULL, 0, EXPAND_NOTHING, NULL);
+
+ if (typeahead_saved)
+ {
+ restore_typeahead(&typeaheadbuf);
+ ignore_script = save_ignore_script;
+ }
+ ex_normal_busy = save_ex_normal_busy;
+
+ cmdline_row = msg_row;
+ msg_starthere();
+ if (cmdline != NULL)
+ {
+ /* If this is a debug command, set "last_cmd".
+ * If not, reset "last_cmd".
+ * For a blank line use previous command. */
+ p = skipwhite(cmdline);
+ if (*p != NUL)
+ {
+ switch (*p)
+ {
+ case 'c': last_cmd = CMD_CONT;
+ tail = "ont";
+ break;
+ case 'n': last_cmd = CMD_NEXT;
+ tail = "ext";
+ break;
+ case 's': last_cmd = CMD_STEP;
+ tail = "tep";
+ break;
+ case 'f':
+ last_cmd = 0;
+ if (p[1] == 'r')
+ {
+ last_cmd = CMD_FRAME;
+ tail = "rame";
+ }
+ else
+ {
+ last_cmd = CMD_FINISH;
+ tail = "inish";
+ }
+ break;
+ case 'q': last_cmd = CMD_QUIT;
+ tail = "uit";
+ break;
+ case 'i': last_cmd = CMD_INTERRUPT;
+ tail = "nterrupt";
+ break;
+ case 'b': last_cmd = CMD_BACKTRACE;
+ if (p[1] == 't')
+ tail = "t";
+ else
+ tail = "acktrace";
+ break;
+ case 'w': last_cmd = CMD_BACKTRACE;
+ tail = "here";
+ break;
+ case 'u': last_cmd = CMD_UP;
+ tail = "p";
+ break;
+ case 'd': last_cmd = CMD_DOWN;
+ tail = "own";
+ break;
+ default: last_cmd = 0;
+ }
+ if (last_cmd != 0)
+ {
+ /* Check that the tail matches. */
+ ++p;
+ while (*p != NUL && *p == *tail)
+ {
+ ++p;
+ ++tail;
+ }
+ if (ASCII_ISALPHA(*p) && last_cmd != CMD_FRAME)
+ last_cmd = 0;
+ }
+ }
+
+ if (last_cmd != 0)
+ {
+ /* Execute debug command: decided where to break next and
+ * return. */
+ switch (last_cmd)
+ {
+ case CMD_CONT:
+ debug_break_level = -1;
+ break;
+ case CMD_NEXT:
+ debug_break_level = ex_nesting_level;
+ break;
+ case CMD_STEP:
+ debug_break_level = 9999;
+ break;
+ case CMD_FINISH:
+ debug_break_level = ex_nesting_level - 1;
+ break;
+ case CMD_QUIT:
+ got_int = TRUE;
+ debug_break_level = -1;
+ break;
+ case CMD_INTERRUPT:
+ got_int = TRUE;
+ debug_break_level = 9999;
+ /* Do not repeat ">interrupt" cmd, continue stepping. */
+ last_cmd = CMD_STEP;
+ break;
+ case CMD_BACKTRACE:
+ do_showbacktrace(cmd);
+ continue;
+ case CMD_FRAME:
+ if (*p == NUL)
+ {
+ do_showbacktrace(cmd);
+ }
+ else
+ {
+ p = skipwhite(p);
+ do_setdebugtracelevel(p);
+ }
+ continue;
+ case CMD_UP:
+ debug_backtrace_level++;
+ do_checkbacktracelevel();
+ continue;
+ case CMD_DOWN:
+ debug_backtrace_level--;
+ do_checkbacktracelevel();
+ continue;
+ }
+ /* Going out reset backtrace_level */
+ debug_backtrace_level = 0;
+ break;
+ }
+
+ /* don't debug this command */
+ n = debug_break_level;
+ debug_break_level = -1;
+ (void)do_cmdline(cmdline, getexline, NULL,
+ DOCMD_VERBOSE|DOCMD_EXCRESET);
+ debug_break_level = n;
+ }
+ lines_left = Rows - 1;
+ }
+ vim_free(cmdline);
+
+ --RedrawingDisabled;
+ --no_wait_return;
+ redraw_all_later(NOT_VALID);
+ need_wait_return = FALSE;
+ msg_scroll = save_msg_scroll;
+ lines_left = Rows - 1;
+ State = save_State;
+ debug_mode = FALSE;
+ did_emsg = save_did_emsg;
+ cmd_silent = save_cmd_silent;
+ msg_silent = save_msg_silent;
+ emsg_silent = save_emsg_silent;
+ redir_off = save_redir_off;
+
+ /* Only print the message again when typing a command before coming back
+ * here. */
+ debug_did_msg = TRUE;
+}
+
+ static int
+get_maxbacktrace_level(void)
+{
+ char *p, *q;
+ int maxbacktrace = 0;
+
+ if (sourcing_name != NULL)
+ {
+ p = (char *)sourcing_name;
+ while ((q = strstr(p, "..")) != NULL)
+ {
+ p = q + 2;
+ maxbacktrace++;
+ }
+ }
+ return maxbacktrace;
+}
+
+ static void
+do_setdebugtracelevel(char_u *arg)
+{
+ int level;
+
+ level = atoi((char *)arg);
+ if (*arg == '+' || level < 0)
+ debug_backtrace_level += level;
+ else
+ debug_backtrace_level = level;
+
+ do_checkbacktracelevel();
+}
+
+ static void
+do_checkbacktracelevel(void)
+{
+ if (debug_backtrace_level < 0)
+ {
+ debug_backtrace_level = 0;
+ msg(_("frame is zero"));
+ }
+ else
+ {
+ int max = get_maxbacktrace_level();
+
+ if (debug_backtrace_level > max)
+ {
+ debug_backtrace_level = max;
+ smsg(_("frame at highest level: %d"), max);
+ }
+ }
+}
+
+ static void
+do_showbacktrace(char_u *cmd)
+{
+ char *cur;
+ char *next;
+ int i = 0;
+ int max = get_maxbacktrace_level();
+
+ if (sourcing_name != NULL)
+ {
+ cur = (char *)sourcing_name;
+ while (!got_int)
+ {
+ next = strstr(cur, "..");
+ if (next != NULL)
+ *next = NUL;
+ if (i == max - debug_backtrace_level)
+ smsg("->%d %s", max - i, cur);
+ else
+ smsg(" %d %s", max - i, cur);
+ ++i;
+ if (next == NULL)
+ break;
+ *next = '.';
+ cur = next + 2;
+ }
+ }
+ if (sourcing_lnum != 0)
+ smsg(_("line %ld: %s"), (long)sourcing_lnum, cmd);
+ else
+ smsg(_("cmd: %s"), cmd);
+}
+
+/*
+ * ":debug".
+ */
+ void
+ex_debug(exarg_T *eap)
+{
+ int debug_break_level_save = debug_break_level;
+
+ debug_break_level = 9999;
+ do_cmdline_cmd(eap->arg);
+ debug_break_level = debug_break_level_save;
+}
+
+static char_u *debug_breakpoint_name = NULL;
+static linenr_T debug_breakpoint_lnum;
+
+/*
+ * When debugging or a breakpoint is set on a skipped command, no debug prompt
+ * is shown by do_one_cmd(). This situation is indicated by debug_skipped, and
+ * debug_skipped_name is then set to the source name in the breakpoint case. If
+ * a skipped command decides itself that a debug prompt should be displayed, it
+ * can do so by calling dbg_check_skipped().
+ */
+static int debug_skipped;
+static char_u *debug_skipped_name;
+
+/*
+ * Go to debug mode when a breakpoint was encountered or "ex_nesting_level" is
+ * at or below the break level. But only when the line is actually
+ * executed. Return TRUE and set breakpoint_name for skipped commands that
+ * decide to execute something themselves.
+ * Called from do_one_cmd() before executing a command.
+ */
+ void
+dbg_check_breakpoint(exarg_T *eap)
+{
+ char_u *p;
+
+ debug_skipped = FALSE;
+ if (debug_breakpoint_name != NULL)
+ {
+ if (!eap->skip)
+ {
+ /* replace K_SNR with "<SNR>" */
+ if (debug_breakpoint_name[0] == K_SPECIAL
+ && debug_breakpoint_name[1] == KS_EXTRA
+ && debug_breakpoint_name[2] == (int)KE_SNR)
+ p = (char_u *)"<SNR>";
+ else
+ p = (char_u *)"";
+ smsg(_("Breakpoint in \"%s%s\" line %ld"),
+ p,
+ debug_breakpoint_name + (*p == NUL ? 0 : 3),
+ (long)debug_breakpoint_lnum);
+ debug_breakpoint_name = NULL;
+ do_debug(eap->cmd);
+ }
+ else
+ {
+ debug_skipped = TRUE;
+ debug_skipped_name = debug_breakpoint_name;
+ debug_breakpoint_name = NULL;
+ }
+ }
+ else if (ex_nesting_level <= debug_break_level)
+ {
+ if (!eap->skip)
+ do_debug(eap->cmd);
+ else
+ {
+ debug_skipped = TRUE;
+ debug_skipped_name = NULL;
+ }
+ }
+}
+
+/*
+ * Go to debug mode if skipped by dbg_check_breakpoint() because eap->skip was
+ * set. Return TRUE when the debug mode is entered this time.
+ */
+ int
+dbg_check_skipped(exarg_T *eap)
+{
+ int prev_got_int;
+
+ if (debug_skipped)
+ {
+ /*
+ * Save the value of got_int and reset it. We don't want a previous
+ * interruption cause flushing the input buffer.
+ */
+ prev_got_int = got_int;
+ got_int = FALSE;
+ debug_breakpoint_name = debug_skipped_name;
+ /* eap->skip is TRUE */
+ eap->skip = FALSE;
+ (void)dbg_check_breakpoint(eap);
+ eap->skip = TRUE;
+ got_int |= prev_got_int;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * The list of breakpoints: dbg_breakp.
+ * This is a grow-array of structs.
+ */
+struct debuggy
+{
+ int dbg_nr; /* breakpoint number */
+ int dbg_type; /* DBG_FUNC, DBG_FILE or DBG_EXPR */
+ char_u *dbg_name; /* function, expression or file name */
+ regprog_T *dbg_prog; /* regexp program */
+ linenr_T dbg_lnum; /* line number in function or file */
+ int dbg_forceit; /* ! used */
+#ifdef FEAT_EVAL
+ typval_T *dbg_val; /* last result of watchexpression */
+#endif
+ int dbg_level; /* stored nested level for expr */
+};
+
+static garray_T dbg_breakp = {0, 0, sizeof(struct debuggy), 4, NULL};
+#define BREAKP(idx) (((struct debuggy *)dbg_breakp.ga_data)[idx])
+#define DEBUGGY(gap, idx) (((struct debuggy *)gap->ga_data)[idx])
+static int last_breakp = 0; /* nr of last defined breakpoint */
+
+#ifdef FEAT_PROFILE
+/* Profiling uses file and func names similar to breakpoints. */
+static garray_T prof_ga = {0, 0, sizeof(struct debuggy), 4, NULL};
+#endif
+#define DBG_FUNC 1
+#define DBG_FILE 2
+#define DBG_EXPR 3
+
+static linenr_T debuggy_find(int file,char_u *fname, linenr_T after, garray_T *gap, int *fp);
+
+/*
+ * Parse the arguments of ":profile", ":breakadd" or ":breakdel" and put them
+ * in the entry just after the last one in dbg_breakp. Note that "dbg_name"
+ * is allocated.
+ * Returns FAIL for failure.
+ */
+ static int
+dbg_parsearg(
+ char_u *arg,
+ garray_T *gap) /* either &dbg_breakp or &prof_ga */
+{
+ char_u *p = arg;
+ char_u *q;
+ struct debuggy *bp;
+ int here = FALSE;
+
+ if (ga_grow(gap, 1) == FAIL)
+ return FAIL;
+ bp = &DEBUGGY(gap, gap->ga_len);
+
+ /* Find "func" or "file". */
+ if (STRNCMP(p, "func", 4) == 0)
+ bp->dbg_type = DBG_FUNC;
+ else if (STRNCMP(p, "file", 4) == 0)
+ bp->dbg_type = DBG_FILE;
+ else if (
+#ifdef FEAT_PROFILE
+ gap != &prof_ga &&
+#endif
+ STRNCMP(p, "here", 4) == 0)
+ {
+ if (curbuf->b_ffname == NULL)
+ {
+ emsg(_(e_noname));
+ return FAIL;
+ }
+ bp->dbg_type = DBG_FILE;
+ here = TRUE;
+ }
+ else if (
+#ifdef FEAT_PROFILE
+ gap != &prof_ga &&
+#endif
+ STRNCMP(p, "expr", 4) == 0)
+ bp->dbg_type = DBG_EXPR;
+ else
+ {
+ semsg(_(e_invarg2), p);
+ return FAIL;
+ }
+ p = skipwhite(p + 4);
+
+ /* Find optional line number. */
+ if (here)
+ bp->dbg_lnum = curwin->w_cursor.lnum;
+ else if (
+#ifdef FEAT_PROFILE
+ gap != &prof_ga &&
+#endif
+ VIM_ISDIGIT(*p))
+ {
+ bp->dbg_lnum = getdigits(&p);
+ p = skipwhite(p);
+ }
+ else
+ bp->dbg_lnum = 0;
+
+ /* Find the function or file name. Don't accept a function name with (). */
+ if ((!here && *p == NUL)
+ || (here && *p != NUL)
+ || (bp->dbg_type == DBG_FUNC && strstr((char *)p, "()") != NULL))
+ {
+ semsg(_(e_invarg2), arg);
+ return FAIL;
+ }
+
+ if (bp->dbg_type == DBG_FUNC)
+ bp->dbg_name = vim_strsave(p);
+ else if (here)
+ bp->dbg_name = vim_strsave(curbuf->b_ffname);
+ else if (bp->dbg_type == DBG_EXPR)
+ {
+ bp->dbg_name = vim_strsave(p);
+ if (bp->dbg_name != NULL)
+ bp->dbg_val = eval_expr(bp->dbg_name, NULL);
+ }
+ else
+ {
+ /* Expand the file name in the same way as do_source(). This means
+ * doing it twice, so that $DIR/file gets expanded when $DIR is
+ * "~/dir". */
+ q = expand_env_save(p);
+ if (q == NULL)
+ return FAIL;
+ p = expand_env_save(q);
+ vim_free(q);
+ if (p == NULL)
+ return FAIL;
+ if (*p != '*')
+ {
+ bp->dbg_name = fix_fname(p);
+ vim_free(p);
+ }
+ else
+ bp->dbg_name = p;
+ }
+
+ if (bp->dbg_name == NULL)
+ return FAIL;
+ return OK;
+}
+
+/*
+ * ":breakadd". Also used for ":profile".
+ */
+ void
+ex_breakadd(exarg_T *eap)
+{
+ struct debuggy *bp;
+ char_u *pat;
+ garray_T *gap;
+
+ gap = &dbg_breakp;
+#ifdef FEAT_PROFILE
+ if (eap->cmdidx == CMD_profile)
+ gap = &prof_ga;
+#endif
+
+ if (dbg_parsearg(eap->arg, gap) == OK)
+ {
+ bp = &DEBUGGY(gap, gap->ga_len);
+ bp->dbg_forceit = eap->forceit;
+
+ if (bp->dbg_type != DBG_EXPR)
+ {
+ pat = file_pat_to_reg_pat(bp->dbg_name, NULL, NULL, FALSE);
+ if (pat != NULL)
+ {
+ bp->dbg_prog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
+ vim_free(pat);
+ }
+ if (pat == NULL || bp->dbg_prog == NULL)
+ vim_free(bp->dbg_name);
+ else
+ {
+ if (bp->dbg_lnum == 0) /* default line number is 1 */
+ bp->dbg_lnum = 1;
+#ifdef FEAT_PROFILE
+ if (eap->cmdidx != CMD_profile)
+#endif
+ {
+ DEBUGGY(gap, gap->ga_len).dbg_nr = ++last_breakp;
+ ++debug_tick;
+ }
+ ++gap->ga_len;
+ }
+ }
+ else
+ {
+ /* DBG_EXPR */
+ DEBUGGY(gap, gap->ga_len++).dbg_nr = ++last_breakp;
+ ++debug_tick;
+ }
+ }
+}
+
+/*
+ * ":debuggreedy".
+ */
+ void
+ex_debuggreedy(exarg_T *eap)
+{
+ if (eap->addr_count == 0 || eap->line2 != 0)
+ debug_greedy = TRUE;
+ else
+ debug_greedy = FALSE;
+}
+
+/*
+ * ":breakdel" and ":profdel".
+ */
+ void
+ex_breakdel(exarg_T *eap)
+{
+ struct debuggy *bp, *bpi;
+ int nr;
+ int todel = -1;
+ int del_all = FALSE;
+ int i;
+ linenr_T best_lnum = 0;
+ garray_T *gap;
+
+ gap = &dbg_breakp;
+ if (eap->cmdidx == CMD_profdel)
+ {
+#ifdef FEAT_PROFILE
+ gap = &prof_ga;
+#else
+ ex_ni(eap);
+ return;
+#endif
+ }
+
+ if (vim_isdigit(*eap->arg))
+ {
+ /* ":breakdel {nr}" */
+ nr = atol((char *)eap->arg);
+ for (i = 0; i < gap->ga_len; ++i)
+ if (DEBUGGY(gap, i).dbg_nr == nr)
+ {
+ todel = i;
+ break;
+ }
+ }
+ else if (*eap->arg == '*')
+ {
+ todel = 0;
+ del_all = TRUE;
+ }
+ else
+ {
+ /* ":breakdel {func|file|expr} [lnum] {name}" */
+ if (dbg_parsearg(eap->arg, gap) == FAIL)
+ return;
+ bp = &DEBUGGY(gap, gap->ga_len);
+ for (i = 0; i < gap->ga_len; ++i)
+ {
+ bpi = &DEBUGGY(gap, i);
+ if (bp->dbg_type == bpi->dbg_type
+ && STRCMP(bp->dbg_name, bpi->dbg_name) == 0
+ && (bp->dbg_lnum == bpi->dbg_lnum
+ || (bp->dbg_lnum == 0
+ && (best_lnum == 0
+ || bpi->dbg_lnum < best_lnum))))
+ {
+ todel = i;
+ best_lnum = bpi->dbg_lnum;
+ }
+ }
+ vim_free(bp->dbg_name);
+ }
+
+ if (todel < 0)
+ semsg(_("E161: Breakpoint not found: %s"), eap->arg);
+ else
+ {
+ while (gap->ga_len > 0)
+ {
+ vim_free(DEBUGGY(gap, todel).dbg_name);
+#ifdef FEAT_EVAL
+ if (DEBUGGY(gap, todel).dbg_type == DBG_EXPR
+ && DEBUGGY(gap, todel).dbg_val != NULL)
+ free_tv(DEBUGGY(gap, todel).dbg_val);
+#endif
+ vim_regfree(DEBUGGY(gap, todel).dbg_prog);
+ --gap->ga_len;
+ if (todel < gap->ga_len)
+ mch_memmove(&DEBUGGY(gap, todel), &DEBUGGY(gap, todel + 1),
+ (gap->ga_len - todel) * sizeof(struct debuggy));
+#ifdef FEAT_PROFILE
+ if (eap->cmdidx == CMD_breakdel)
+#endif
+ ++debug_tick;
+ if (!del_all)
+ break;
+ }
+
+ /* If all breakpoints were removed clear the array. */
+ if (gap->ga_len == 0)
+ ga_clear(gap);
+ }
+}
+
+/*
+ * ":breaklist".
+ */
+ void
+ex_breaklist(exarg_T *eap UNUSED)
+{
+ struct debuggy *bp;
+ int i;
+
+ if (dbg_breakp.ga_len == 0)
+ msg(_("No breakpoints defined"));
+ else
+ for (i = 0; i < dbg_breakp.ga_len; ++i)
+ {
+ bp = &BREAKP(i);
+ if (bp->dbg_type == DBG_FILE)
+ home_replace(NULL, bp->dbg_name, NameBuff, MAXPATHL, TRUE);
+ if (bp->dbg_type != DBG_EXPR)
+ smsg(_("%3d %s %s line %ld"),
+ bp->dbg_nr,
+ bp->dbg_type == DBG_FUNC ? "func" : "file",
+ bp->dbg_type == DBG_FUNC ? bp->dbg_name : NameBuff,
+ (long)bp->dbg_lnum);
+ else
+ smsg(_("%3d expr %s"),
+ bp->dbg_nr, bp->dbg_name);
+ }
+}
+
+/*
+ * Find a breakpoint for a function or sourced file.
+ * Returns line number at which to break; zero when no matching breakpoint.
+ */
+ linenr_T
+dbg_find_breakpoint(
+ int file, /* TRUE for a file, FALSE for a function */
+ char_u *fname, /* file or function name */
+ linenr_T after) /* after this line number */
+{
+ return debuggy_find(file, fname, after, &dbg_breakp, NULL);
+}
+
+#if defined(FEAT_PROFILE) || defined(PROTO)
+/*
+ * Return TRUE if profiling is on for a function or sourced file.
+ */
+ int
+has_profiling(
+ int file, /* TRUE for a file, FALSE for a function */
+ char_u *fname, /* file or function name */
+ int *fp) /* return: forceit */
+{
+ return (debuggy_find(file, fname, (linenr_T)0, &prof_ga, fp)
+ != (linenr_T)0);
+}
+#endif
+
+/*
+ * Common code for dbg_find_breakpoint() and has_profiling().
+ */
+ static linenr_T
+debuggy_find(
+ int file, /* TRUE for a file, FALSE for a function */
+ char_u *fname, /* file or function name */
+ linenr_T after, /* after this line number */
+ garray_T *gap, /* either &dbg_breakp or &prof_ga */
+ int *fp) /* if not NULL: return forceit */
+{
+ struct debuggy *bp;
+ int i;
+ linenr_T lnum = 0;
+ char_u *name = fname;
+ int prev_got_int;
+
+ /* Return quickly when there are no breakpoints. */
+ if (gap->ga_len == 0)
+ return (linenr_T)0;
+
+ /* Replace K_SNR in function name with "<SNR>". */
+ if (!file && fname[0] == K_SPECIAL)
+ {
+ name = alloc((unsigned)STRLEN(fname) + 3);
+ if (name == NULL)
+ name = fname;
+ else
+ {
+ STRCPY(name, "<SNR>");
+ STRCPY(name + 5, fname + 3);
+ }
+ }
+
+ for (i = 0; i < gap->ga_len; ++i)
+ {
+ /* Skip entries that are not useful or are for a line that is beyond
+ * an already found breakpoint. */
+ bp = &DEBUGGY(gap, i);
+ if (((bp->dbg_type == DBG_FILE) == file &&
+ bp->dbg_type != DBG_EXPR && (
+#ifdef FEAT_PROFILE
+ gap == &prof_ga ||
+#endif
+ (bp->dbg_lnum > after && (lnum == 0 || bp->dbg_lnum < lnum)))))
+ {
+ /*
+ * Save the value of got_int and reset it. We don't want a
+ * previous interruption cancel matching, only hitting CTRL-C
+ * while matching should abort it.
+ */
+ prev_got_int = got_int;
+ got_int = FALSE;
+ if (vim_regexec_prog(&bp->dbg_prog, FALSE, name, (colnr_T)0))
+ {
+ lnum = bp->dbg_lnum;
+ if (fp != NULL)
+ *fp = bp->dbg_forceit;
+ }
+ got_int |= prev_got_int;
+ }
+#ifdef FEAT_EVAL
+ else if (bp->dbg_type == DBG_EXPR)
+ {
+ typval_T *tv;
+ int line = FALSE;
+
+ prev_got_int = got_int;
+ got_int = FALSE;
+
+ tv = eval_expr(bp->dbg_name, NULL);
+ if (tv != NULL)
+ {
+ if (bp->dbg_val == NULL)
+ {
+ debug_oldval = typval_tostring(NULL);
+ bp->dbg_val = tv;
+ debug_newval = typval_tostring(bp->dbg_val);
+ line = TRUE;
+ }
+ else
+ {
+ if (typval_compare(tv, bp->dbg_val, TYPE_EQUAL,
+ TRUE, FALSE) == OK
+ && tv->vval.v_number == FALSE)
+ {
+ typval_T *v;
+
+ line = TRUE;
+ debug_oldval = typval_tostring(bp->dbg_val);
+ /* Need to evaluate again, typval_compare() overwrites
+ * "tv". */
+ v = eval_expr(bp->dbg_name, NULL);
+ debug_newval = typval_tostring(v);
+ free_tv(bp->dbg_val);
+ bp->dbg_val = v;
+ }
+ free_tv(tv);
+ }
+ }
+ else if (bp->dbg_val != NULL)
+ {
+ debug_oldval = typval_tostring(bp->dbg_val);
+ debug_newval = typval_tostring(NULL);
+ free_tv(bp->dbg_val);
+ bp->dbg_val = NULL;
+ line = TRUE;
+ }
+
+ if (line)
+ {
+ lnum = after > 0 ? after : 1;
+ break;
+ }
+
+ got_int |= prev_got_int;
+ }
+#endif
+ }
+ if (name != fname)
+ vim_free(name);
+
+ return lnum;
+}
+
+/*
+ * Called when a breakpoint was encountered.
+ */
+ void
+dbg_breakpoint(char_u *name, linenr_T lnum)
+{
+ /* We need to check if this line is actually executed in do_one_cmd() */
+ debug_breakpoint_name = name;
+ debug_breakpoint_lnum = lnum;
+}
+
+
+# if defined(FEAT_PROFILE) || defined(FEAT_RELTIME) || defined(PROTO)
+/*
+ * Store the current time in "tm".
+ */
+ void
+profile_start(proftime_T *tm)
+{
+# ifdef WIN3264
+ QueryPerformanceCounter(tm);
+# else
+ gettimeofday(tm, NULL);
+# endif
+}
+
+/*
+ * Compute the elapsed time from "tm" till now and store in "tm".
+ */
+ void
+profile_end(proftime_T *tm)
+{
+ proftime_T now;
+
+# ifdef WIN3264
+ QueryPerformanceCounter(&now);
+ tm->QuadPart = now.QuadPart - tm->QuadPart;
+# else
+ gettimeofday(&now, NULL);
+ tm->tv_usec = now.tv_usec - tm->tv_usec;
+ tm->tv_sec = now.tv_sec - tm->tv_sec;
+ if (tm->tv_usec < 0)
+ {
+ tm->tv_usec += 1000000;
+ --tm->tv_sec;
+ }
+# endif
+}
+
+/*
+ * Subtract the time "tm2" from "tm".
+ */
+ void
+profile_sub(proftime_T *tm, proftime_T *tm2)
+{
+# ifdef WIN3264
+ tm->QuadPart -= tm2->QuadPart;
+# else
+ tm->tv_usec -= tm2->tv_usec;
+ tm->tv_sec -= tm2->tv_sec;
+ if (tm->tv_usec < 0)
+ {
+ tm->tv_usec += 1000000;
+ --tm->tv_sec;
+ }
+# endif
+}
+
+/*
+ * Return a string that represents the time in "tm".
+ * Uses a static buffer!
+ */
+ char *
+profile_msg(proftime_T *tm)
+{
+ static char buf[50];
+
+# ifdef WIN3264
+ LARGE_INTEGER fr;
+
+ QueryPerformanceFrequency(&fr);
+ sprintf(buf, "%10.6lf", (double)tm->QuadPart / (double)fr.QuadPart);
+# else
+ sprintf(buf, "%3ld.%06ld", (long)tm->tv_sec, (long)tm->tv_usec);
+# endif
+ return buf;
+}
+
+# if defined(FEAT_FLOAT) || defined(PROTO)
+/*
+ * Return a float that represents the time in "tm".
+ */
+ float_T
+profile_float(proftime_T *tm)
+{
+# ifdef WIN3264
+ LARGE_INTEGER fr;
+
+ QueryPerformanceFrequency(&fr);
+ return (float_T)tm->QuadPart / (float_T)fr.QuadPart;
+# else
+ return (float_T)tm->tv_sec + (float_T)tm->tv_usec / 1000000.0;
+# endif
+}
+# endif
+
+/*
+ * Put the time "msec" past now in "tm".
+ */
+ void
+profile_setlimit(long msec, proftime_T *tm)
+{
+ if (msec <= 0) /* no limit */
+ profile_zero(tm);
+ else
+ {
+# ifdef WIN3264
+ LARGE_INTEGER fr;
+
+ QueryPerformanceCounter(tm);
+ QueryPerformanceFrequency(&fr);
+ tm->QuadPart += (LONGLONG)((double)msec / 1000.0 * (double)fr.QuadPart);
+# else
+ long usec;
+
+ gettimeofday(tm, NULL);
+ usec = (long)tm->tv_usec + (long)msec * 1000;
+ tm->tv_usec = usec % 1000000L;
+ tm->tv_sec += usec / 1000000L;
+# endif
+ }
+}
+
+/*
+ * Return TRUE if the current time is past "tm".
+ */
+ int
+profile_passed_limit(proftime_T *tm)
+{
+ proftime_T now;
+
+# ifdef WIN3264
+ if (tm->QuadPart == 0) /* timer was not set */
+ return FALSE;
+ QueryPerformanceCounter(&now);
+ return (now.QuadPart > tm->QuadPart);
+# else
+ if (tm->tv_sec == 0) /* timer was not set */
+ return FALSE;
+ gettimeofday(&now, NULL);
+ return (now.tv_sec > tm->tv_sec
+ || (now.tv_sec == tm->tv_sec && now.tv_usec > tm->tv_usec));
+# endif
+}
+
+/*
+ * Set the time in "tm" to zero.
+ */
+ void
+profile_zero(proftime_T *tm)
+{
+# ifdef WIN3264
+ tm->QuadPart = 0;
+# else
+ tm->tv_usec = 0;
+ tm->tv_sec = 0;
+# endif
+}
+
+# endif /* FEAT_PROFILE || FEAT_RELTIME */
+
+# if defined(FEAT_TIMERS) || defined(PROTO)
+static timer_T *first_timer = NULL;
+static long last_timer_id = 0;
+
+ long
+proftime_time_left(proftime_T *due, proftime_T *now)
+{
+# ifdef WIN3264
+ LARGE_INTEGER fr;
+
+ if (now->QuadPart > due->QuadPart)
+ return 0;
+ QueryPerformanceFrequency(&fr);
+ return (long)(((double)(due->QuadPart - now->QuadPart)
+ / (double)fr.QuadPart) * 1000);
+# else
+ if (now->tv_sec > due->tv_sec)
+ return 0;
+ return (due->tv_sec - now->tv_sec) * 1000
+ + (due->tv_usec - now->tv_usec) / 1000;
+# endif
+}
+
+/*
+ * Insert a timer in the list of timers.
+ */
+ static void
+insert_timer(timer_T *timer)
+{
+ timer->tr_next = first_timer;
+ timer->tr_prev = NULL;
+ if (first_timer != NULL)
+ first_timer->tr_prev = timer;
+ first_timer = timer;
+ did_add_timer = TRUE;
+}
+
+/*
+ * Take a timer out of the list of timers.
+ */
+ static void
+remove_timer(timer_T *timer)
+{
+ if (timer->tr_prev == NULL)
+ first_timer = timer->tr_next;
+ else
+ timer->tr_prev->tr_next = timer->tr_next;
+ if (timer->tr_next != NULL)
+ timer->tr_next->tr_prev = timer->tr_prev;
+}
+
+ static void
+free_timer(timer_T *timer)
+{
+ free_callback(timer->tr_callback, timer->tr_partial);
+ vim_free(timer);
+}
+
+/*
+ * Create a timer and return it. NULL if out of memory.
+ * Caller should set the callback.
+ */
+ timer_T *
+create_timer(long msec, int repeat)
+{
+ timer_T *timer = (timer_T *)alloc_clear(sizeof(timer_T));
+ long prev_id = last_timer_id;
+
+ if (timer == NULL)
+ return NULL;
+ if (++last_timer_id <= prev_id)
+ /* Overflow! Might cause duplicates... */
+ last_timer_id = 0;
+ timer->tr_id = last_timer_id;
+ insert_timer(timer);
+ if (repeat != 0)
+ timer->tr_repeat = repeat - 1;
+ timer->tr_interval = msec;
+
+ profile_setlimit(msec, &timer->tr_due);
+ return timer;
+}
+
+/*
+ * Invoke the callback of "timer".
+ */
+ static void
+timer_callback(timer_T *timer)
+{
+ typval_T rettv;
+ int dummy;
+ typval_T argv[2];
+
+ argv[0].v_type = VAR_NUMBER;
+ argv[0].vval.v_number = (varnumber_T)timer->tr_id;
+ argv[1].v_type = VAR_UNKNOWN;
+
+ call_func(timer->tr_callback, (int)STRLEN(timer->tr_callback),
+ &rettv, 1, argv, NULL, 0L, 0L, &dummy, TRUE,
+ timer->tr_partial, NULL);
+ clear_tv(&rettv);
+}
+
+/*
+ * Call timers that are due.
+ * Return the time in msec until the next timer is due.
+ * Returns -1 if there are no pending timers.
+ */
+ long
+check_due_timer(void)
+{
+ timer_T *timer;
+ timer_T *timer_next;
+ long this_due;
+ long next_due = -1;
+ proftime_T now;
+ int did_one = FALSE;
+ int need_update_screen = FALSE;
+ long current_id = last_timer_id;
+
+ /* Don't run any timers while exiting or dealing with an error. */
+ if (exiting || aborting())
+ return next_due;
+
+ profile_start(&now);
+ for (timer = first_timer; timer != NULL && !got_int; timer = timer_next)
+ {
+ timer_next = timer->tr_next;
+
+ if (timer->tr_id == -1 || timer->tr_firing || timer->tr_paused)
+ continue;
+ this_due = proftime_time_left(&timer->tr_due, &now);
+ if (this_due <= 1)
+ {
+ /* Save and restore a lot of flags, because the timer fires while
+ * waiting for a character, which might be halfway a command. */
+ int save_timer_busy = timer_busy;
+ int save_vgetc_busy = vgetc_busy;
+ int save_did_emsg = did_emsg;
+ int save_called_emsg = called_emsg;
+ int save_must_redraw = must_redraw;
+ int save_trylevel = trylevel;
+ int save_did_throw = did_throw;
+ int save_ex_pressedreturn = get_pressedreturn();
+ except_T *save_current_exception = current_exception;
+ vimvars_save_T vvsave;
+
+ /* Create a scope for running the timer callback, ignoring most of
+ * the current scope, such as being inside a try/catch. */
+ timer_busy = timer_busy > 0 || vgetc_busy > 0;
+ vgetc_busy = 0;
+ called_emsg = FALSE;
+ did_emsg = FALSE;
+ did_uncaught_emsg = FALSE;
+ must_redraw = 0;
+ trylevel = 0;
+ did_throw = FALSE;
+ current_exception = NULL;
+ save_vimvars(&vvsave);
+
+ timer->tr_firing = TRUE;
+ timer_callback(timer);
+ timer->tr_firing = FALSE;
+
+ timer_next = timer->tr_next;
+ did_one = TRUE;
+ timer_busy = save_timer_busy;
+ vgetc_busy = save_vgetc_busy;
+ if (did_uncaught_emsg)
+ ++timer->tr_emsg_count;
+ did_emsg = save_did_emsg;
+ called_emsg = save_called_emsg;
+ trylevel = save_trylevel;
+ did_throw = save_did_throw;
+ current_exception = save_current_exception;
+ restore_vimvars(&vvsave);
+ if (must_redraw != 0)
+ need_update_screen = TRUE;
+ must_redraw = must_redraw > save_must_redraw
+ ? must_redraw : save_must_redraw;
+ set_pressedreturn(save_ex_pressedreturn);
+
+ /* Only fire the timer again if it repeats and stop_timer() wasn't
+ * called while inside the callback (tr_id == -1). */
+ if (timer->tr_repeat != 0 && timer->tr_id != -1
+ && timer->tr_emsg_count < 3)
+ {
+ profile_setlimit(timer->tr_interval, &timer->tr_due);
+ this_due = proftime_time_left(&timer->tr_due, &now);
+ if (this_due < 1)
+ this_due = 1;
+ if (timer->tr_repeat > 0)
+ --timer->tr_repeat;
+ }
+ else
+ {
+ this_due = -1;
+ remove_timer(timer);
+ free_timer(timer);
+ }
+ }
+ if (this_due > 0 && (next_due == -1 || next_due > this_due))
+ next_due = this_due;
+ }
+
+ if (did_one)
+ redraw_after_callback(need_update_screen);
+
+#ifdef FEAT_BEVAL_TERM
+ if (bevalexpr_due_set)
+ {
+ this_due = proftime_time_left(&bevalexpr_due, &now);
+ if (this_due <= 1)
+ {
+ bevalexpr_due_set = FALSE;
+ if (balloonEval == NULL)
+ {
+ balloonEval = (BalloonEval *)alloc_clear(sizeof(BalloonEval));
+ balloonEvalForTerm = TRUE;
+ }
+ if (balloonEval != NULL)
+ general_beval_cb(balloonEval, 0);
+ }
+ else if (next_due == -1 || next_due > this_due)
+ next_due = this_due;
+ }
+#endif
+#ifdef FEAT_TERMINAL
+ /* Some terminal windows may need their buffer updated. */
+ next_due = term_check_timers(next_due, &now);
+#endif
+
+ return current_id != last_timer_id ? 1 : next_due;
+}
+
+/*
+ * Find a timer by ID. Returns NULL if not found;
+ */
+ timer_T *
+find_timer(long id)
+{
+ timer_T *timer;
+
+ if (id >= 0)
+ {
+ for (timer = first_timer; timer != NULL; timer = timer->tr_next)
+ if (timer->tr_id == id)
+ return timer;
+ }
+ return NULL;
+}
+
+
+/*
+ * Stop a timer and delete it.
+ */
+ void
+stop_timer(timer_T *timer)
+{
+ if (timer->tr_firing)
+ /* Free the timer after the callback returns. */
+ timer->tr_id = -1;
+ else
+ {
+ remove_timer(timer);
+ free_timer(timer);
+ }
+}
+
+ void
+stop_all_timers(void)
+{
+ timer_T *timer;
+ timer_T *timer_next;
+
+ for (timer = first_timer; timer != NULL; timer = timer_next)
+ {
+ timer_next = timer->tr_next;
+ stop_timer(timer);
+ }
+}
+
+ void
+add_timer_info(typval_T *rettv, timer_T *timer)
+{
+ list_T *list = rettv->vval.v_list;
+ dict_T *dict = dict_alloc();
+ dictitem_T *di;
+ long remaining;
+ proftime_T now;
+
+ if (dict == NULL)
+ return;
+ list_append_dict(list, dict);
+
+ dict_add_number(dict, "id", timer->tr_id);
+ dict_add_number(dict, "time", (long)timer->tr_interval);
+
+ profile_start(&now);
+ remaining = proftime_time_left(&timer->tr_due, &now);
+ dict_add_number(dict, "remaining", (long)remaining);
+
+ dict_add_number(dict, "repeat",
+ (long)(timer->tr_repeat < 0 ? -1 : timer->tr_repeat + 1));
+ dict_add_number(dict, "paused", (long)(timer->tr_paused));
+
+ di = dictitem_alloc((char_u *)"callback");
+ if (di != NULL)
+ {
+ if (dict_add(dict, di) == FAIL)
+ vim_free(di);
+ else if (timer->tr_partial != NULL)
+ {
+ di->di_tv.v_type = VAR_PARTIAL;
+ di->di_tv.vval.v_partial = timer->tr_partial;
+ ++timer->tr_partial->pt_refcount;
+ }
+ else
+ {
+ di->di_tv.v_type = VAR_FUNC;
+ di->di_tv.vval.v_string = vim_strsave(timer->tr_callback);
+ }
+ }
+}
+
+ void
+add_timer_info_all(typval_T *rettv)
+{
+ timer_T *timer;
+
+ for (timer = first_timer; timer != NULL; timer = timer->tr_next)
+ if (timer->tr_id != -1)
+ add_timer_info(rettv, timer);
+}
+
+/*
+ * Mark references in partials of timers.
+ */
+ int
+set_ref_in_timer(int copyID)
+{
+ int abort = FALSE;
+ timer_T *timer;
+ typval_T tv;
+
+ for (timer = first_timer; timer != NULL; timer = timer->tr_next)
+ {
+ if (timer->tr_partial != NULL)
+ {
+ tv.v_type = VAR_PARTIAL;
+ tv.vval.v_partial = timer->tr_partial;
+ }
+ else
+ {
+ tv.v_type = VAR_FUNC;
+ tv.vval.v_string = timer->tr_callback;
+ }
+ abort = abort || set_ref_in_item(&tv, copyID, NULL, NULL);
+ }
+ return abort;
+}
+
+# if defined(EXITFREE) || defined(PROTO)
+ void
+timer_free_all()
+{
+ timer_T *timer;
+
+ while (first_timer != NULL)
+ {
+ timer = first_timer;
+ remove_timer(timer);
+ free_timer(timer);
+ }
+}
+# endif
+# endif
+
+#if defined(FEAT_SYN_HL) && defined(FEAT_RELTIME) && defined(FEAT_FLOAT) && defined(FEAT_PROFILE)
+# if defined(HAVE_MATH_H)
+# include <math.h>
+# endif
+
+/*
+ * Divide the time "tm" by "count" and store in "tm2".
+ */
+ void
+profile_divide(proftime_T *tm, int count, proftime_T *tm2)
+{
+ if (count == 0)
+ profile_zero(tm2);
+ else
+ {
+# ifdef WIN3264
+ tm2->QuadPart = tm->QuadPart / count;
+# else
+ double usec = (tm->tv_sec * 1000000.0 + tm->tv_usec) / count;
+
+ tm2->tv_sec = floor(usec / 1000000.0);
+ tm2->tv_usec = vim_round(usec - (tm2->tv_sec * 1000000.0));
+# endif
+ }
+}
+#endif
+
+# if defined(FEAT_PROFILE) || defined(PROTO)
+/*
+ * Functions for profiling.
+ */
+static void script_dump_profile(FILE *fd);
+static proftime_T prof_wait_time;
+
+/*
+ * Add the time "tm2" to "tm".
+ */
+ void
+profile_add(proftime_T *tm, proftime_T *tm2)
+{
+# ifdef WIN3264
+ tm->QuadPart += tm2->QuadPart;
+# else
+ tm->tv_usec += tm2->tv_usec;
+ tm->tv_sec += tm2->tv_sec;
+ if (tm->tv_usec >= 1000000)
+ {
+ tm->tv_usec -= 1000000;
+ ++tm->tv_sec;
+ }
+# endif
+}
+
+/*
+ * Add the "self" time from the total time and the children's time.
+ */
+ void
+profile_self(proftime_T *self, proftime_T *total, proftime_T *children)
+{
+ /* Check that the result won't be negative. Can happen with recursive
+ * calls. */
+#ifdef WIN3264
+ if (total->QuadPart <= children->QuadPart)
+ return;
+#else
+ if (total->tv_sec < children->tv_sec
+ || (total->tv_sec == children->tv_sec
+ && total->tv_usec <= children->tv_usec))
+ return;
+#endif
+ profile_add(self, total);
+ profile_sub(self, children);
+}
+
+/*
+ * Get the current waittime.
+ */
+ void
+profile_get_wait(proftime_T *tm)
+{
+ *tm = prof_wait_time;
+}
+
+/*
+ * Subtract the passed waittime since "tm" from "tma".
+ */
+ void
+profile_sub_wait(proftime_T *tm, proftime_T *tma)
+{
+ proftime_T tm3 = prof_wait_time;
+
+ profile_sub(&tm3, tm);
+ profile_sub(tma, &tm3);
+}
+
+/*
+ * Return TRUE if "tm1" and "tm2" are equal.
+ */
+ int
+profile_equal(proftime_T *tm1, proftime_T *tm2)
+{
+# ifdef WIN3264
+ return (tm1->QuadPart == tm2->QuadPart);
+# else
+ return (tm1->tv_usec == tm2->tv_usec && tm1->tv_sec == tm2->tv_sec);
+# endif
+}
+
+/*
+ * Return <0, 0 or >0 if "tm1" < "tm2", "tm1" == "tm2" or "tm1" > "tm2"
+ */
+ int
+profile_cmp(const proftime_T *tm1, const proftime_T *tm2)
+{
+# ifdef WIN3264
+ return (int)(tm2->QuadPart - tm1->QuadPart);
+# else
+ if (tm1->tv_sec == tm2->tv_sec)
+ return tm2->tv_usec - tm1->tv_usec;
+ return tm2->tv_sec - tm1->tv_sec;
+# endif
+}
+
+static char_u *profile_fname = NULL;
+static proftime_T pause_time;
+
+/*
+ * ":profile cmd args"
+ */
+ void
+ex_profile(exarg_T *eap)
+{
+ char_u *e;
+ int len;
+
+ e = skiptowhite(eap->arg);
+ len = (int)(e - eap->arg);
+ e = skipwhite(e);
+
+ if (len == 5 && STRNCMP(eap->arg, "start", 5) == 0 && *e != NUL)
+ {
+ vim_free(profile_fname);
+ profile_fname = expand_env_save_opt(e, TRUE);
+ do_profiling = PROF_YES;
+ profile_zero(&prof_wait_time);
+ set_vim_var_nr(VV_PROFILING, 1L);
+ }
+ else if (do_profiling == PROF_NONE)
+ emsg(_("E750: First use \":profile start {fname}\""));
+ else if (STRCMP(eap->arg, "pause") == 0)
+ {
+ if (do_profiling == PROF_YES)
+ profile_start(&pause_time);
+ do_profiling = PROF_PAUSED;
+ }
+ else if (STRCMP(eap->arg, "continue") == 0)
+ {
+ if (do_profiling == PROF_PAUSED)
+ {
+ profile_end(&pause_time);
+ profile_add(&prof_wait_time, &pause_time);
+ }
+ do_profiling = PROF_YES;
+ }
+ else
+ {
+ /* The rest is similar to ":breakadd". */
+ ex_breakadd(eap);
+ }
+}
+
+/* Command line expansion for :profile. */
+static enum
+{
+ PEXP_SUBCMD, /* expand :profile sub-commands */
+ PEXP_FUNC /* expand :profile func {funcname} */
+} pexpand_what;
+
+static char *pexpand_cmds[] = {
+ "start",
+#define PROFCMD_START 0
+ "pause",
+#define PROFCMD_PAUSE 1
+ "continue",
+#define PROFCMD_CONTINUE 2
+ "func",
+#define PROFCMD_FUNC 3
+ "file",
+#define PROFCMD_FILE 4
+ NULL
+#define PROFCMD_LAST 5
+};
+
+/*
+ * Function given to ExpandGeneric() to obtain the profile command
+ * specific expansion.
+ */
+ char_u *
+get_profile_name(expand_T *xp UNUSED, int idx)
+{
+ switch (pexpand_what)
+ {
+ case PEXP_SUBCMD:
+ return (char_u *)pexpand_cmds[idx];
+ /* case PEXP_FUNC: TODO */
+ default:
+ return NULL;
+ }
+}
+
+/*
+ * Handle command line completion for :profile command.
+ */
+ void
+set_context_in_profile_cmd(expand_T *xp, char_u *arg)
+{
+ char_u *end_subcmd;
+
+ /* Default: expand subcommands. */
+ xp->xp_context = EXPAND_PROFILE;
+ pexpand_what = PEXP_SUBCMD;
+ xp->xp_pattern = arg;
+
+ end_subcmd = skiptowhite(arg);
+ if (*end_subcmd == NUL)
+ return;
+
+ if (end_subcmd - arg == 5 && STRNCMP(arg, "start", 5) == 0)
+ {
+ xp->xp_context = EXPAND_FILES;
+ xp->xp_pattern = skipwhite(end_subcmd);
+ return;
+ }
+
+ /* TODO: expand function names after "func" */
+ xp->xp_context = EXPAND_NOTHING;
+}
+
+/*
+ * Dump the profiling info.
+ */
+ void
+profile_dump(void)
+{
+ FILE *fd;
+
+ if (profile_fname != NULL)
+ {
+ fd = mch_fopen((char *)profile_fname, "w");
+ if (fd == NULL)
+ semsg(_(e_notopen), profile_fname);
+ else
+ {
+ script_dump_profile(fd);
+ func_dump_profile(fd);
+ fclose(fd);
+ }
+ }
+}
+
+/*
+ * Start profiling script "fp".
+ */
+ static void
+script_do_profile(scriptitem_T *si)
+{
+ si->sn_pr_count = 0;
+ profile_zero(&si->sn_pr_total);
+ profile_zero(&si->sn_pr_self);
+
+ ga_init2(&si->sn_prl_ga, sizeof(sn_prl_T), 100);
+ si->sn_prl_idx = -1;
+ si->sn_prof_on = TRUE;
+ si->sn_pr_nest = 0;
+}
+
+/*
+ * Save time when starting to invoke another script or function.
+ */
+ void
+script_prof_save(
+ proftime_T *tm) /* place to store wait time */
+{
+ scriptitem_T *si;
+
+ if (current_sctx.sc_sid > 0 && current_sctx.sc_sid <= script_items.ga_len)
+ {
+ si = &SCRIPT_ITEM(current_sctx.sc_sid);
+ if (si->sn_prof_on && si->sn_pr_nest++ == 0)
+ profile_start(&si->sn_pr_child);
+ }
+ profile_get_wait(tm);
+}
+
+/*
+ * Count time spent in children after invoking another script or function.
+ */
+ void
+script_prof_restore(proftime_T *tm)
+{
+ scriptitem_T *si;
+
+ if (current_sctx.sc_sid > 0 && current_sctx.sc_sid <= script_items.ga_len)
+ {
+ si = &SCRIPT_ITEM(current_sctx.sc_sid);
+ if (si->sn_prof_on && --si->sn_pr_nest == 0)
+ {
+ profile_end(&si->sn_pr_child);
+ profile_sub_wait(tm, &si->sn_pr_child); /* don't count wait time */
+ profile_add(&si->sn_pr_children, &si->sn_pr_child);
+ profile_add(&si->sn_prl_children, &si->sn_pr_child);
+ }
+ }
+}
+
+static proftime_T inchar_time;
+
+/*
+ * Called when starting to wait for the user to type a character.
+ */
+ void
+prof_inchar_enter(void)
+{
+ profile_start(&inchar_time);
+}
+
+/*
+ * Called when finished waiting for the user to type a character.
+ */
+ void
+prof_inchar_exit(void)
+{
+ profile_end(&inchar_time);
+ profile_add(&prof_wait_time, &inchar_time);
+}
+
+/*
+ * Dump the profiling results for all scripts in file "fd".
+ */
+ static void
+script_dump_profile(FILE *fd)
+{
+ int id;
+ scriptitem_T *si;
+ int i;
+ FILE *sfd;
+ sn_prl_T *pp;
+
+ for (id = 1; id <= script_items.ga_len; ++id)
+ {
+ si = &SCRIPT_ITEM(id);
+ if (si->sn_prof_on)
+ {
+ fprintf(fd, "SCRIPT %s\n", si->sn_name);
+ if (si->sn_pr_count == 1)
+ fprintf(fd, "Sourced 1 time\n");
+ else
+ fprintf(fd, "Sourced %d times\n", si->sn_pr_count);
+ fprintf(fd, "Total time: %s\n", profile_msg(&si->sn_pr_total));
+ fprintf(fd, " Self time: %s\n", profile_msg(&si->sn_pr_self));
+ fprintf(fd, "\n");
+ fprintf(fd, "count total (s) self (s)\n");
+
+ sfd = mch_fopen((char *)si->sn_name, "r");
+ if (sfd == NULL)
+ fprintf(fd, "Cannot open file!\n");
+ else
+ {
+ /* Keep going till the end of file, so that trailing
+ * continuation lines are listed. */
+ for (i = 0; ; ++i)
+ {
+ if (vim_fgets(IObuff, IOSIZE, sfd))
+ break;
+ /* When a line has been truncated, append NL, taking care
+ * of multi-byte characters . */
+ if (IObuff[IOSIZE - 2] != NUL && IObuff[IOSIZE - 2] != NL)
+ {
+ int n = IOSIZE - 2;
+
+ if (enc_utf8)
+ {
+ /* Move to the first byte of this char.
+ * utf_head_off() doesn't work, because it checks
+ * for a truncated character. */
+ while (n > 0 && (IObuff[n] & 0xc0) == 0x80)
+ --n;
+ }
+ else if (has_mbyte)
+ n -= mb_head_off(IObuff, IObuff + n);
+ IObuff[n] = NL;
+ IObuff[n + 1] = NUL;
+ }
+ if (i < si->sn_prl_ga.ga_len
+ && (pp = &PRL_ITEM(si, i))->snp_count > 0)
+ {
+ fprintf(fd, "%5d ", pp->snp_count);
+ if (profile_equal(&pp->sn_prl_total, &pp->sn_prl_self))
+ fprintf(fd, " ");
+ else
+ fprintf(fd, "%s ", profile_msg(&pp->sn_prl_total));
+ fprintf(fd, "%s ", profile_msg(&pp->sn_prl_self));
+ }
+ else
+ fprintf(fd, " ");
+ fprintf(fd, "%s", IObuff);
+ }
+ fclose(sfd);
+ }
+ fprintf(fd, "\n");
+ }
+ }
+}
+
+/*
+ * Return TRUE when a function defined in the current script should be
+ * profiled.
+ */
+ int
+prof_def_func(void)
+{
+ if (current_sctx.sc_sid > 0)
+ return SCRIPT_ITEM(current_sctx.sc_sid).sn_pr_force;
+ return FALSE;
+}
+
+# endif
+#endif
+
+/*
+ * If 'autowrite' option set, try to write the file.
+ * Careful: autocommands may make "buf" invalid!
+ *
+ * return FAIL for failure, OK otherwise
+ */
+ int
+autowrite(buf_T *buf, int forceit)
+{
+ int r;
+ bufref_T bufref;
+
+ if (!(p_aw || p_awa) || !p_write
+#ifdef FEAT_QUICKFIX
+ /* never autowrite a "nofile" or "nowrite" buffer */
+ || bt_dontwrite(buf)
+#endif
+ || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
+ return FAIL;
+ set_bufref(&bufref, buf);
+ r = buf_write_all(buf, forceit);
+
+ /* Writing may succeed but the buffer still changed, e.g., when there is a
+ * conversion error. We do want to return FAIL then. */
+ if (bufref_valid(&bufref) && bufIsChanged(buf))
+ r = FAIL;
+ return r;
+}
+
+/*
+ * Flush all buffers, except the ones that are readonly or are never written.
+ */
+ void
+autowrite_all(void)
+{
+ buf_T *buf;
+
+ if (!(p_aw || p_awa) || !p_write)
+ return;
+ FOR_ALL_BUFFERS(buf)
+ if (bufIsChanged(buf) && !buf->b_p_ro && !bt_dontwrite(buf))
+ {
+ bufref_T bufref;
+
+ set_bufref(&bufref, buf);
+
+ (void)buf_write_all(buf, FALSE);
+
+ /* an autocommand may have deleted the buffer */
+ if (!bufref_valid(&bufref))
+ buf = firstbuf;
+ }
+}
+
+/*
+ * Return TRUE if buffer was changed and cannot be abandoned.
+ * For flags use the CCGD_ values.
+ */
+ int
+check_changed(buf_T *buf, int flags)
+{
+ int forceit = (flags & CCGD_FORCEIT);
+ bufref_T bufref;
+
+ set_bufref(&bufref, buf);
+
+ if ( !forceit
+ && bufIsChanged(buf)
+ && ((flags & CCGD_MULTWIN) || buf->b_nwindows <= 1)
+ && (!(flags & CCGD_AW) || autowrite(buf, forceit) == FAIL))
+ {
+#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
+ if ((p_confirm || cmdmod.confirm) && p_write)
+ {
+ buf_T *buf2;
+ int count = 0;
+
+ if (flags & CCGD_ALLBUF)
+ FOR_ALL_BUFFERS(buf2)
+ if (bufIsChanged(buf2)
+ && (buf2->b_ffname != NULL
+# ifdef FEAT_BROWSE
+ || cmdmod.browse
+# endif
+ ))
+ ++count;
+ if (!bufref_valid(&bufref))
+ /* Autocommand deleted buffer, oops! It's not changed now. */
+ return FALSE;
+
+ dialog_changed(buf, count > 1);
+
+ if (!bufref_valid(&bufref))
+ /* Autocommand deleted buffer, oops! It's not changed now. */
+ return FALSE;
+ return bufIsChanged(buf);
+ }
+#endif
+ if (flags & CCGD_EXCMD)
+ no_write_message();
+ else
+ no_write_message_nobang(curbuf);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
+
+#if defined(FEAT_BROWSE) || defined(PROTO)
+/*
+ * When wanting to write a file without a file name, ask the user for a name.
+ */
+ void
+browse_save_fname(buf_T *buf)
+{
+ if (buf->b_fname == NULL)
+ {
+ char_u *fname;
+
+ fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"),
+ NULL, NULL, NULL, NULL, buf);
+ if (fname != NULL)
+ {
+ if (setfname(buf, fname, NULL, TRUE) == OK)
+ buf->b_flags |= BF_NOTEDITED;
+ vim_free(fname);
+ }
+ }
+}
+#endif
+
+/*
+ * Ask the user what to do when abandoning a changed buffer.
+ * Must check 'write' option first!
+ */
+ void
+dialog_changed(
+ buf_T *buf,
+ int checkall) /* may abandon all changed buffers */
+{
+ char_u buff[DIALOG_MSG_SIZE];
+ int ret;
+ buf_T *buf2;
+ exarg_T ea;
+
+ dialog_msg(buff, _("Save changes to \"%s\"?"), buf->b_fname);
+ if (checkall)
+ ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
+ else
+ ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
+
+ /* Init ea pseudo-structure, this is needed for the check_overwrite()
+ * function. */
+ ea.append = ea.forceit = FALSE;
+
+ if (ret == VIM_YES)
+ {
+#ifdef FEAT_BROWSE
+ /* May get file name, when there is none */
+ browse_save_fname(buf);
+#endif
+ if (buf->b_fname != NULL && check_overwrite(&ea, buf,
+ buf->b_fname, buf->b_ffname, FALSE) == OK)
+ /* didn't hit Cancel */
+ (void)buf_write_all(buf, FALSE);
+ }
+ else if (ret == VIM_NO)
+ {
+ unchanged(buf, TRUE);
+ }
+ else if (ret == VIM_ALL)
+ {
+ /*
+ * Write all modified files that can be written.
+ * Skip readonly buffers, these need to be confirmed
+ * individually.
+ */
+ FOR_ALL_BUFFERS(buf2)
+ {
+ if (bufIsChanged(buf2)
+ && (buf2->b_ffname != NULL
+#ifdef FEAT_BROWSE
+ || cmdmod.browse
+#endif
+ )
+ && !buf2->b_p_ro)
+ {
+ bufref_T bufref;
+
+ set_bufref(&bufref, buf2);
+#ifdef FEAT_BROWSE
+ /* May get file name, when there is none */
+ browse_save_fname(buf2);
+#endif
+ if (buf2->b_fname != NULL && check_overwrite(&ea, buf2,
+ buf2->b_fname, buf2->b_ffname, FALSE) == OK)
+ /* didn't hit Cancel */
+ (void)buf_write_all(buf2, FALSE);
+
+ /* an autocommand may have deleted the buffer */
+ if (!bufref_valid(&bufref))
+ buf2 = firstbuf;
+ }
+ }
+ }
+ else if (ret == VIM_DISCARDALL)
+ {
+ /*
+ * mark all buffers as unchanged
+ */
+ FOR_ALL_BUFFERS(buf2)
+ unchanged(buf2, TRUE);
+ }
+}
+#endif
+
+/*
+ * Return TRUE if the buffer "buf" can be abandoned, either by making it
+ * hidden, autowriting it or unloading it.
+ */
+ int
+can_abandon(buf_T *buf, int forceit)
+{
+ return ( buf_hide(buf)
+ || !bufIsChanged(buf)
+ || buf->b_nwindows > 1
+ || autowrite(buf, forceit) == OK
+ || forceit);
+}
+
+/*
+ * Add a buffer number to "bufnrs", unless it's already there.
+ */
+ static void
+add_bufnum(int *bufnrs, int *bufnump, int nr)
+{
+ int i;
+
+ for (i = 0; i < *bufnump; ++i)
+ if (bufnrs[i] == nr)
+ return;
+ bufnrs[*bufnump] = nr;
+ *bufnump = *bufnump + 1;
+}
+
+/*
+ * Return TRUE if any buffer was changed and cannot be abandoned.
+ * That changed buffer becomes the current buffer.
+ * When "unload" is TRUE the current buffer is unloaded instead of making it
+ * hidden. This is used for ":q!".
+ */
+ int
+check_changed_any(
+ int hidden, /* Only check hidden buffers */
+ int unload)
+{
+ int ret = FALSE;
+ buf_T *buf;
+ int save;
+ int i;
+ int bufnum = 0;
+ int bufcount = 0;
+ int *bufnrs;
+ tabpage_T *tp;
+ win_T *wp;
+
+ /* Make a list of all buffers, with the most important ones first. */
+ FOR_ALL_BUFFERS(buf)
+ ++bufcount;
+
+ if (bufcount == 0)
+ return FALSE;
+
+ bufnrs = (int *)alloc(sizeof(int) * bufcount);
+ if (bufnrs == NULL)
+ return FALSE;
+
+ /* curbuf */
+ bufnrs[bufnum++] = curbuf->b_fnum;
+
+ /* buffers in current tab */
+ FOR_ALL_WINDOWS(wp)
+ if (wp->w_buffer != curbuf)
+ add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
+
+ /* buffers in other tabs */
+ FOR_ALL_TABPAGES(tp)
+ if (tp != curtab)
+ for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next)
+ add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
+
+ /* any other buffer */
+ FOR_ALL_BUFFERS(buf)
+ add_bufnum(bufnrs, &bufnum, buf->b_fnum);
+
+ for (i = 0; i < bufnum; ++i)
+ {
+ buf = buflist_findnr(bufnrs[i]);
+ if (buf == NULL)
+ continue;
+ if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf))
+ {
+ bufref_T bufref;
+
+ set_bufref(&bufref, buf);
+#ifdef FEAT_TERMINAL
+ if (term_job_running(buf->b_term))
+ {
+ if (term_try_stop_job(buf) == FAIL)
+ break;
+ }
+ else
+#endif
+ /* Try auto-writing the buffer. If this fails but the buffer no
+ * longer exists it's not changed, that's OK. */
+ if (check_changed(buf, (p_awa ? CCGD_AW : 0)
+ | CCGD_MULTWIN
+ | CCGD_ALLBUF) && bufref_valid(&bufref))
+ break; /* didn't save - still changes */
+ }
+ }
+
+ if (i >= bufnum)
+ goto theend;
+
+ /* Get here if "buf" cannot be abandoned. */
+ ret = TRUE;
+ exiting = FALSE;
+#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
+ /*
+ * When ":confirm" used, don't give an error message.
+ */
+ if (!(p_confirm || cmdmod.confirm))
+#endif
+ {
+ /* There must be a wait_return for this message, do_buffer()
+ * may cause a redraw. But wait_return() is a no-op when vgetc()
+ * is busy (Quit used from window menu), then make sure we don't
+ * cause a scroll up. */
+ if (vgetc_busy > 0)
+ {
+ msg_row = cmdline_row;
+ msg_col = 0;
+ msg_didout = FALSE;
+ }
+ if (
+#ifdef FEAT_TERMINAL
+ term_job_running(buf->b_term)
+ ? semsg(_("E947: Job still running in buffer \"%s\""),
+ buf->b_fname)
+ :
+#endif
+ semsg(_("E162: No write since last change for buffer \"%s\""),
+ buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname))
+ {
+ save = no_wait_return;
+ no_wait_return = FALSE;
+ wait_return(FALSE);
+ no_wait_return = save;
+ }
+ }
+
+ /* Try to find a window that contains the buffer. */
+ if (buf != curbuf)
+ FOR_ALL_TAB_WINDOWS(tp, wp)
+ if (wp->w_buffer == buf)
+ {
+ bufref_T bufref;
+
+ set_bufref(&bufref, buf);
+
+ goto_tabpage_win(tp, wp);
+
+ /* Paranoia: did autocms wipe out the buffer with changes? */
+ if (!bufref_valid(&bufref))
+ goto theend;
+ goto buf_found;
+ }
+buf_found:
+
+ /* Open the changed buffer in the current window. */
+ if (buf != curbuf)
+ set_curbuf(buf, unload ? DOBUF_UNLOAD : DOBUF_GOTO);
+
+theend:
+ vim_free(bufnrs);
+ return ret;
+}
+
+/*
+ * return FAIL if there is no file name, OK if there is one
+ * give error message for FAIL
+ */
+ int
+check_fname(void)
+{
+ if (curbuf->b_ffname == NULL)
+ {
+ emsg(_(e_noname));
+ return FAIL;
+ }
+ return OK;
+}
+
+/*
+ * flush the contents of a buffer, unless it has no file name
+ *
+ * return FAIL for failure, OK otherwise
+ */
+ int
+buf_write_all(buf_T *buf, int forceit)
+{
+ int retval;
+ buf_T *old_curbuf = curbuf;
+
+ retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
+ (linenr_T)1, buf->b_ml.ml_line_count, NULL,
+ FALSE, forceit, TRUE, FALSE));
+ if (curbuf != old_curbuf)
+ {
+ msg_source(HL_ATTR(HLF_W));
+ msg(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
+ }
+ return retval;
+}
+
+/*
+ * Code to handle the argument list.
+ */
+
+static int do_arglist(char_u *str, int what, int after, int will_edit);
+static void alist_check_arg_idx(void);
+static void alist_add_list(int count, char_u **files, int after, int will_edit);
+#define AL_SET 1
+#define AL_ADD 2
+#define AL_DEL 3
+
+/*
+ * Isolate one argument, taking backticks.
+ * Changes the argument in-place, puts a NUL after it. Backticks remain.
+ * Return a pointer to the start of the next argument.
+ */
+ static char_u *
+do_one_arg(char_u *str)
+{
+ char_u *p;
+ int inbacktick;
+
+ inbacktick = FALSE;
+ for (p = str; *str; ++str)
+ {
+ /* When the backslash is used for escaping the special meaning of a
+ * character we need to keep it until wildcard expansion. */
+ if (rem_backslash(str))
+ {
+ *p++ = *str++;
+ *p++ = *str;
+ }
+ else
+ {
+ /* An item ends at a space not in backticks */
+ if (!inbacktick && vim_isspace(*str))
+ break;
+ if (*str == '`')
+ inbacktick ^= TRUE;
+ *p++ = *str;
+ }
+ }
+ str = skipwhite(str);
+ *p = NUL;
+
+ return str;
+}
+
+/*
+ * Separate the arguments in "str" and return a list of pointers in the
+ * growarray "gap".
+ */
+ static int
+get_arglist(garray_T *gap, char_u *str, int escaped)
+{
+ ga_init2(gap, (int)sizeof(char_u *), 20);
+ while (*str != NUL)
+ {
+ if (ga_grow(gap, 1) == FAIL)
+ {
+ ga_clear(gap);
+ return FAIL;
+ }
+ ((char_u **)gap->ga_data)[gap->ga_len++] = str;
+
+ /* If str is escaped, don't handle backslashes or spaces */
+ if (!escaped)
+ return OK;
+
+ /* Isolate one argument, change it in-place, put a NUL after it. */
+ str = do_one_arg(str);
+ }
+ return OK;
+}
+
+#if defined(FEAT_QUICKFIX) || defined(FEAT_SYN_HL) || defined(PROTO)
+/*
+ * Parse a list of arguments (file names), expand them and return in
+ * "fnames[fcountp]". When "wig" is TRUE, removes files matching 'wildignore'.
+ * Return FAIL or OK.
+ */
+ int
+get_arglist_exp(
+ char_u *str,
+ int *fcountp,
+ char_u ***fnamesp,
+ int wig)
+{
+ garray_T ga;
+ int i;
+
+ if (get_arglist(&ga, str, TRUE) == FAIL)
+ return FAIL;
+ if (wig == TRUE)
+ i = expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
+ fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
+ else
+ i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
+ fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
+
+ ga_clear(&ga);
+ return i;
+}
+#endif
+
+/*
+ * Redefine the argument list.
+ */
+ void
+set_arglist(char_u *str)
+{
+ do_arglist(str, AL_SET, 0, FALSE);
+}
+
+/*
+ * "what" == AL_SET: Redefine the argument list to 'str'.
+ * "what" == AL_ADD: add files in 'str' to the argument list after "after".
+ * "what" == AL_DEL: remove files in 'str' from the argument list.
+ *
+ * Return FAIL for failure, OK otherwise.
+ */
+ static int
+do_arglist(
+ char_u *str,
+ int what,
+ int after UNUSED, // 0 means before first one
+ int will_edit) // will edit added argument
+{
+ garray_T new_ga;
+ int exp_count;
+ char_u **exp_files;
+ int i;
+ char_u *p;
+ int match;
+ int arg_escaped = TRUE;
+
+ /*
+ * Set default argument for ":argadd" command.
+ */
+ if (what == AL_ADD && *str == NUL)
+ {
+ if (curbuf->b_ffname == NULL)
+ return FAIL;
+ str = curbuf->b_fname;
+ arg_escaped = FALSE;
+ }
+
+ /*
+ * Collect all file name arguments in "new_ga".
+ */
+ if (get_arglist(&new_ga, str, arg_escaped) == FAIL)
+ return FAIL;
+
+ if (what == AL_DEL)
+ {
+ regmatch_T regmatch;
+ int didone;
+
+ /*
+ * Delete the items: use each item as a regexp and find a match in the
+ * argument list.
+ */
+ regmatch.rm_ic = p_fic; /* ignore case when 'fileignorecase' is set */
+ for (i = 0; i < new_ga.ga_len && !got_int; ++i)
+ {
+ p = ((char_u **)new_ga.ga_data)[i];
+ p = file_pat_to_reg_pat(p, NULL, NULL, FALSE);
+ if (p == NULL)
+ break;
+ regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
+ if (regmatch.regprog == NULL)
+ {
+ vim_free(p);
+ break;
+ }
+
+ didone = FALSE;
+ for (match = 0; match < ARGCOUNT; ++match)
+ if (vim_regexec(&regmatch, alist_name(&ARGLIST[match]),
+ (colnr_T)0))
+ {
+ didone = TRUE;
+ vim_free(ARGLIST[match].ae_fname);
+ mch_memmove(ARGLIST + match, ARGLIST + match + 1,
+ (ARGCOUNT - match - 1) * sizeof(aentry_T));
+ --ALIST(curwin)->al_ga.ga_len;
+ if (curwin->w_arg_idx > match)
+ --curwin->w_arg_idx;
+ --match;
+ }
+
+ vim_regfree(regmatch.regprog);
+ vim_free(p);
+ if (!didone)
+ semsg(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]);
+ }
+ ga_clear(&new_ga);
+ }
+ else
+ {
+ i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data,
+ &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND);
+ ga_clear(&new_ga);
+ if (i == FAIL || exp_count == 0)
+ {
+ emsg(_(e_nomatch));
+ return FAIL;
+ }
+
+ if (what == AL_ADD)
+ {
+ alist_add_list(exp_count, exp_files, after, will_edit);
+ vim_free(exp_files);
+ }
+ else /* what == AL_SET */
+ alist_set(ALIST(curwin), exp_count, exp_files, will_edit, NULL, 0);
+ }
+
+ alist_check_arg_idx();
+
+ return OK;
+}
+
+/*
+ * Check the validity of the arg_idx for each other window.
+ */
+ static void
+alist_check_arg_idx(void)
+{
+ win_T *win;
+ tabpage_T *tp;
+
+ FOR_ALL_TAB_WINDOWS(tp, win)
+ if (win->w_alist == curwin->w_alist)
+ check_arg_idx(win);
+}
+
+/*
+ * Return TRUE if window "win" is editing the file at the current argument
+ * index.
+ */
+ static int
+editing_arg_idx(win_T *win)
+{
+ return !(win->w_arg_idx >= WARGCOUNT(win)
+ || (win->w_buffer->b_fnum
+ != WARGLIST(win)[win->w_arg_idx].ae_fnum
+ && (win->w_buffer->b_ffname == NULL
+ || !(fullpathcmp(
+ alist_name(&WARGLIST(win)[win->w_arg_idx]),
+ win->w_buffer->b_ffname, TRUE) & FPC_SAME))));
+}
+
+/*
+ * Check if window "win" is editing the w_arg_idx file in its argument list.
+ */
+ void
+check_arg_idx(win_T *win)
+{
+ if (WARGCOUNT(win) > 1 && !editing_arg_idx(win))
+ {
+ /* We are not editing the current entry in the argument list.
+ * Set "arg_had_last" if we are editing the last one. */
+ win->w_arg_idx_invalid = TRUE;
+ if (win->w_arg_idx != WARGCOUNT(win) - 1
+ && arg_had_last == FALSE
+ && ALIST(win) == &global_alist
+ && GARGCOUNT > 0
+ && win->w_arg_idx < GARGCOUNT
+ && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum
+ || (win->w_buffer->b_ffname != NULL
+ && (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]),
+ win->w_buffer->b_ffname, TRUE) & FPC_SAME))))
+ arg_had_last = TRUE;
+ }
+ else
+ {
+ /* We are editing the current entry in the argument list.
+ * Set "arg_had_last" if it's also the last one */
+ win->w_arg_idx_invalid = FALSE;
+ if (win->w_arg_idx == WARGCOUNT(win) - 1
+ && win->w_alist == &global_alist)
+ arg_had_last = TRUE;
+ }
+}
+
+/*
+ * ":args", ":argslocal" and ":argsglobal".
+ */
+ void
+ex_args(exarg_T *eap)
+{
+ int i;
+
+ if (eap->cmdidx != CMD_args)
+ {
+ alist_unlink(ALIST(curwin));
+ if (eap->cmdidx == CMD_argglobal)
+ ALIST(curwin) = &global_alist;
+ else /* eap->cmdidx == CMD_arglocal */
+ alist_new();
+ }
+
+ if (*eap->arg != NUL)
+ {
+ /*
+ * ":args file ..": define new argument list, handle like ":next"
+ * Also for ":argslocal file .." and ":argsglobal file ..".
+ */
+ ex_next(eap);
+ }
+ else if (eap->cmdidx == CMD_args)
+ {
+ /*
+ * ":args": list arguments.
+ */
+ if (ARGCOUNT > 0)
+ {
+ char_u **items = (char_u **)alloc(sizeof(char_u *) * ARGCOUNT);
+
+ if (items != NULL)
+ {
+ /* Overwrite the command, for a short list there is no
+ * scrolling required and no wait_return(). */
+ gotocmdline(TRUE);
+
+ for (i = 0; i < ARGCOUNT; ++i)
+ items[i] = alist_name(&ARGLIST[i]);
+ list_in_columns(items, ARGCOUNT, curwin->w_arg_idx);
+ vim_free(items);
+ }
+ }
+ }
+ else if (eap->cmdidx == CMD_arglocal)
+ {
+ garray_T *gap = &curwin->w_alist->al_ga;
+
+ /*
+ * ":argslocal": make a local copy of the global argument list.
+ */
+ if (ga_grow(gap, GARGCOUNT) == OK)
+ for (i = 0; i < GARGCOUNT; ++i)
+ if (GARGLIST[i].ae_fname != NULL)
+ {
+ AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname =
+ vim_strsave(GARGLIST[i].ae_fname);
+ AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum =
+ GARGLIST[i].ae_fnum;
+ ++gap->ga_len;
+ }
+ }
+}
+
+/*
+ * ":previous", ":sprevious", ":Next" and ":sNext".
+ */
+ void
+ex_previous(exarg_T *eap)
+{
+ /* If past the last one already, go to the last one. */
+ if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT)
+ do_argfile(eap, ARGCOUNT - 1);
+ else
+ do_argfile(eap, curwin->w_arg_idx - (int)eap->line2);
+}
+
+/*
+ * ":rewind", ":first", ":sfirst" and ":srewind".
+ */
+ void
+ex_rewind(exarg_T *eap)
+{
+ do_argfile(eap, 0);
+}
+
+/*
+ * ":last" and ":slast".
+ */
+ void
+ex_last(exarg_T *eap)
+{
+ do_argfile(eap, ARGCOUNT - 1);
+}
+
+/*
+ * ":argument" and ":sargument".
+ */
+ void
+ex_argument(exarg_T *eap)
+{
+ int i;
+
+ if (eap->addr_count > 0)
+ i = eap->line2 - 1;
+ else
+ i = curwin->w_arg_idx;
+ do_argfile(eap, i);
+}
+
+/*
+ * Edit file "argn" of the argument lists.
+ */
+ void
+do_argfile(exarg_T *eap, int argn)
+{
+ int other;
+ char_u *p;
+ int old_arg_idx = curwin->w_arg_idx;
+
+ if (argn < 0 || argn >= ARGCOUNT)
+ {
+ if (ARGCOUNT <= 1)
+ emsg(_("E163: There is only one file to edit"));
+ else if (argn < 0)
+ emsg(_("E164: Cannot go before first file"));
+ else
+ emsg(_("E165: Cannot go beyond last file"));
+ }
+ else
+ {
+ setpcmark();
+#ifdef FEAT_GUI
+ need_mouse_correct = TRUE;
+#endif
+
+ /* split window or create new tab page first */
+ if (*eap->cmd == 's' || cmdmod.tab != 0)
+ {
+ if (win_split(0, 0) == FAIL)
+ return;
+ RESET_BINDING(curwin);
+ }
+ else
+ {
+ /*
+ * if 'hidden' set, only check for changed file when re-editing
+ * the same buffer
+ */
+ other = TRUE;
+ if (buf_hide(curbuf))
+ {
+ p = fix_fname(alist_name(&ARGLIST[argn]));
+ other = otherfile(p);
+ vim_free(p);
+ }
+ if ((!buf_hide(curbuf) || !other)
+ && check_changed(curbuf, CCGD_AW
+ | (other ? 0 : CCGD_MULTWIN)
+ | (eap->forceit ? CCGD_FORCEIT : 0)
+ | CCGD_EXCMD))
+ return;
+ }
+
+ curwin->w_arg_idx = argn;
+ if (argn == ARGCOUNT - 1 && curwin->w_alist == &global_alist)
+ arg_had_last = TRUE;
+
+ /* Edit the file; always use the last known line number.
+ * When it fails (e.g. Abort for already edited file) restore the
+ * argument index. */
+ if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL,
+ eap, ECMD_LAST,
+ (buf_hide(curwin->w_buffer) ? ECMD_HIDE : 0)
+ + (eap->forceit ? ECMD_FORCEIT : 0), curwin) == FAIL)
+ curwin->w_arg_idx = old_arg_idx;
+ /* like Vi: set the mark where the cursor is in the file. */
+ else if (eap->cmdidx != CMD_argdo)
+ setmark('\'');
+ }
+}
+
+/*
+ * ":next", and commands that behave like it.
+ */
+ void
+ex_next(exarg_T *eap)
+{
+ int i;
+
+ /*
+ * check for changed buffer now, if this fails the argument list is not
+ * redefined.
+ */
+ if ( buf_hide(curbuf)
+ || eap->cmdidx == CMD_snext
+ || !check_changed(curbuf, CCGD_AW
+ | (eap->forceit ? CCGD_FORCEIT : 0)
+ | CCGD_EXCMD))
+ {
+ if (*eap->arg != NUL) /* redefine file list */
+ {
+ if (do_arglist(eap->arg, AL_SET, 0, TRUE) == FAIL)
+ return;
+ i = 0;
+ }
+ else
+ i = curwin->w_arg_idx + (int)eap->line2;
+ do_argfile(eap, i);
+ }
+}
+
+/*
+ * ":argedit"
+ */
+ void
+ex_argedit(exarg_T *eap)
+{
+ int i = eap->addr_count ? (int)eap->line2 : curwin->w_arg_idx + 1;
+ // Whether curbuf will be reused, curbuf->b_ffname will be set.
+ int curbuf_is_reusable = curbuf_reusable();
+
+ if (do_arglist(eap->arg, AL_ADD, i, TRUE) == FAIL)
+ return;
+#ifdef FEAT_TITLE
+ maketitle();
+#endif
+
+ if (curwin->w_arg_idx == 0
+ && (curbuf->b_ml.ml_flags & ML_EMPTY)
+ && (curbuf->b_ffname == NULL || curbuf_is_reusable))
+ i = 0;
+ /* Edit the argument. */
+ if (i < ARGCOUNT)
+ do_argfile(eap, i);
+}
+
+/*
+ * ":argadd"
+ */
+ void
+ex_argadd(exarg_T *eap)
+{
+ do_arglist(eap->arg, AL_ADD,
+ eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1,
+ FALSE);
+#ifdef FEAT_TITLE
+ maketitle();
+#endif
+}
+
+/*
+ * ":argdelete"
+ */
+ void
+ex_argdelete(exarg_T *eap)
+{
+ int i;
+ int n;
+
+ if (eap->addr_count > 0)
+ {
+ /* ":1,4argdel": Delete all arguments in the range. */
+ if (eap->line2 > ARGCOUNT)
+ eap->line2 = ARGCOUNT;
+ n = eap->line2 - eap->line1 + 1;
+ if (*eap->arg != NUL)
+ /* Can't have both a range and an argument. */
+ emsg(_(e_invarg));
+ else if (n <= 0)
+ {
+ /* Don't give an error for ":%argdel" if the list is empty. */
+ if (eap->line1 != 1 || eap->line2 != 0)
+ emsg(_(e_invrange));
+ }
+ else
+ {
+ for (i = eap->line1; i <= eap->line2; ++i)
+ vim_free(ARGLIST[i - 1].ae_fname);
+ mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
+ (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T)));
+ ALIST(curwin)->al_ga.ga_len -= n;
+ if (curwin->w_arg_idx >= eap->line2)
+ curwin->w_arg_idx -= n;
+ else if (curwin->w_arg_idx > eap->line1)
+ curwin->w_arg_idx = eap->line1;
+ if (ARGCOUNT == 0)
+ curwin->w_arg_idx = 0;
+ else if (curwin->w_arg_idx >= ARGCOUNT)
+ curwin->w_arg_idx = ARGCOUNT - 1;
+ }
+ }
+ else if (*eap->arg == NUL)
+ emsg(_(e_argreq));
+ else
+ do_arglist(eap->arg, AL_DEL, 0, FALSE);
+#ifdef FEAT_TITLE
+ maketitle();
+#endif
+}
+
+/*
+ * ":argdo", ":windo", ":bufdo", ":tabdo", ":cdo", ":ldo", ":cfdo" and ":lfdo"
+ */
+ void
+ex_listdo(exarg_T *eap)
+{
+ int i;
+ win_T *wp;
+ tabpage_T *tp;
+ buf_T *buf = curbuf;
+ int next_fnum = 0;
+#if defined(FEAT_SYN_HL)
+ char_u *save_ei = NULL;
+#endif
+ char_u *p_shm_save;
+#ifdef FEAT_QUICKFIX
+ int qf_size = 0;
+ int qf_idx;
+#endif
+
+#ifndef FEAT_QUICKFIX
+ if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo ||
+ eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
+ {
+ ex_ni(eap);
+ return;
+ }
+#endif
+
+#if defined(FEAT_SYN_HL)
+ if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
+ /* Don't do syntax HL autocommands. Skipping the syntax file is a
+ * great speed improvement. */
+ save_ei = au_event_disable(",Syntax");
+#endif
+#ifdef FEAT_CLIPBOARD
+ start_global_changes();
+#endif
+
+ if (eap->cmdidx == CMD_windo
+ || eap->cmdidx == CMD_tabdo
+ || buf_hide(curbuf)
+ || !check_changed(curbuf, CCGD_AW
+ | (eap->forceit ? CCGD_FORCEIT : 0)
+ | CCGD_EXCMD))
+ {
+ i = 0;
+ /* start at the eap->line1 argument/window/buffer */
+ wp = firstwin;
+ tp = first_tabpage;
+ switch (eap->cmdidx)
+ {
+ case CMD_windo:
+ for ( ; wp != NULL && i + 1 < eap->line1; wp = wp->w_next)
+ i++;
+ break;
+ case CMD_tabdo:
+ for( ; tp != NULL && i + 1 < eap->line1; tp = tp->tp_next)
+ i++;
+ break;
+ case CMD_argdo:
+ i = eap->line1 - 1;
+ break;
+ default:
+ break;
+ }
+ /* set pcmark now */
+ if (eap->cmdidx == CMD_bufdo)
+ {
+ /* Advance to the first listed buffer after "eap->line1". */
+ for (buf = firstbuf; buf != NULL && (buf->b_fnum < eap->line1
+ || !buf->b_p_bl); buf = buf->b_next)
+ if (buf->b_fnum > eap->line2)
+ {
+ buf = NULL;
+ break;
+ }
+ if (buf != NULL)
+ goto_buffer(eap, DOBUF_FIRST, FORWARD, buf->b_fnum);
+ }
+#ifdef FEAT_QUICKFIX
+ else if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
+ || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
+ {
+ qf_size = qf_get_size(eap);
+ if (qf_size <= 0 || eap->line1 > qf_size)
+ buf = NULL;
+ else
+ {
+ ex_cc(eap);
+
+ buf = curbuf;
+ i = eap->line1 - 1;
+ if (eap->addr_count <= 0)
+ /* default is all the quickfix/location list entries */
+ eap->line2 = qf_size;
+ }
+ }
+#endif
+ else
+ setpcmark();
+ listcmd_busy = TRUE; /* avoids setting pcmark below */
+
+ while (!got_int && buf != NULL)
+ {
+ if (eap->cmdidx == CMD_argdo)
+ {
+ /* go to argument "i" */
+ if (i == ARGCOUNT)
+ break;
+ /* Don't call do_argfile() when already there, it will try
+ * reloading the file. */
+ if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
+ {
+ /* Clear 'shm' to avoid that the file message overwrites
+ * any output from the command. */
+ p_shm_save = vim_strsave(p_shm);
+ set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
+ do_argfile(eap, i);
+ set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
+ vim_free(p_shm_save);
+ }
+ if (curwin->w_arg_idx != i)
+ break;
+ }
+ else if (eap->cmdidx == CMD_windo)
+ {
+ /* go to window "wp" */
+ if (!win_valid(wp))
+ break;
+ win_goto(wp);
+ if (curwin != wp)
+ break; /* something must be wrong */
+ wp = curwin->w_next;
+ }
+ else if (eap->cmdidx == CMD_tabdo)
+ {
+ /* go to window "tp" */
+ if (!valid_tabpage(tp))
+ break;
+ goto_tabpage_tp(tp, TRUE, TRUE);
+ tp = tp->tp_next;
+ }
+ else if (eap->cmdidx == CMD_bufdo)
+ {
+ /* Remember the number of the next listed buffer, in case
+ * ":bwipe" is used or autocommands do something strange. */
+ next_fnum = -1;
+ for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
+ if (buf->b_p_bl)
+ {
+ next_fnum = buf->b_fnum;
+ break;
+ }
+ }
+
+ ++i;
+
+ /* execute the command */
+ do_cmdline(eap->arg, eap->getline, eap->cookie,
+ DOCMD_VERBOSE + DOCMD_NOWAIT);
+
+ if (eap->cmdidx == CMD_bufdo)
+ {
+ /* Done? */
+ if (next_fnum < 0 || next_fnum > eap->line2)
+ break;
+ /* Check if the buffer still exists. */
+ FOR_ALL_BUFFERS(buf)
+ if (buf->b_fnum == next_fnum)
+ break;
+ if (buf == NULL)
+ break;
+
+ /* Go to the next buffer. Clear 'shm' to avoid that the file
+ * message overwrites any output from the command. */
+ p_shm_save = vim_strsave(p_shm);
+ set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
+ goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
+ set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
+ vim_free(p_shm_save);
+
+ /* If autocommands took us elsewhere, quit here. */
+ if (curbuf->b_fnum != next_fnum)
+ break;
+ }
+
+#ifdef FEAT_QUICKFIX
+ if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
+ || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
+ {
+ if (i >= qf_size || i >= eap->line2)
+ break;
+
+ qf_idx = qf_get_cur_idx(eap);
+
+ ex_cnext(eap);
+
+ /* If jumping to the next quickfix entry fails, quit here */
+ if (qf_get_cur_idx(eap) == qf_idx)
+ break;
+ }
+#endif
+
+ if (eap->cmdidx == CMD_windo)
+ {
+ validate_cursor(); /* cursor may have moved */
+
+ /* required when 'scrollbind' has been set */
+ if (curwin->w_p_scb)
+ do_check_scrollbind(TRUE);
+ }
+
+ if (eap->cmdidx == CMD_windo || eap->cmdidx == CMD_tabdo)
+ if (i+1 > eap->line2)
+ break;
+ if (eap->cmdidx == CMD_argdo && i >= eap->line2)
+ break;
+ }
+ listcmd_busy = FALSE;
+ }
+
+#if defined(FEAT_SYN_HL)
+ if (save_ei != NULL)
+ {
+ au_event_restore(save_ei);
+ apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
+ curbuf->b_fname, TRUE, curbuf);
+ }
+#endif
+#ifdef FEAT_CLIPBOARD
+ end_global_changes();
+#endif
+}
+
+/*
+ * Add files[count] to the arglist of the current window after arg "after".
+ * The file names in files[count] must have been allocated and are taken over.
+ * Files[] itself is not taken over.
+ */
+ static void
+alist_add_list(
+ int count,
+ char_u **files,
+ int after, // where to add: 0 = before first one
+ int will_edit) // will edit adding argument
+{
+ int i;
+ int old_argcount = ARGCOUNT;
+
+ if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
+ {
+ if (after < 0)
+ after = 0;
+ if (after > ARGCOUNT)
+ after = ARGCOUNT;
+ if (after < ARGCOUNT)
+ mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
+ (ARGCOUNT - after) * sizeof(aentry_T));
+ for (i = 0; i < count; ++i)
+ {
+ int flags = BLN_LISTED | (will_edit ? BLN_CURBUF : 0);
+
+ ARGLIST[after + i].ae_fname = files[i];
+ ARGLIST[after + i].ae_fnum = buflist_add(files[i], flags);
+ }
+ ALIST(curwin)->al_ga.ga_len += count;
+ if (old_argcount > 0 && curwin->w_arg_idx >= after)
+ curwin->w_arg_idx += count;
+ return;
+ }
+
+ for (i = 0; i < count; ++i)
+ vim_free(files[i]);
+}
+
+#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
+/*
+ * Function given to ExpandGeneric() to obtain the possible arguments of the
+ * argedit and argdelete commands.
+ */
+ char_u *
+get_arglist_name(expand_T *xp UNUSED, int idx)
+{
+ if (idx >= ARGCOUNT)
+ return NULL;
+
+ return alist_name(&ARGLIST[idx]);
+}
+#endif
+
+
+#ifdef FEAT_EVAL
+/*
+ * ":compiler[!] {name}"
+ */
+ void
+ex_compiler(exarg_T *eap)
+{
+ char_u *buf;
+ char_u *old_cur_comp = NULL;
+ char_u *p;
+
+ if (*eap->arg == NUL)
+ {
+ /* List all compiler scripts. */
+ do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
+ /* ) keep the indenter happy... */
+ }
+ else
+ {
+ buf = alloc((unsigned)(STRLEN(eap->arg) + 14));
+ if (buf != NULL)
+ {
+ if (eap->forceit)
+ {
+ /* ":compiler! {name}" sets global options */
+ do_cmdline_cmd((char_u *)
+ "command -nargs=* CompilerSet set <args>");
+ }
+ else
+ {
+ /* ":compiler! {name}" sets local options.
+ * To remain backwards compatible "current_compiler" is always
+ * used. A user's compiler plugin may set it, the distributed
+ * plugin will then skip the settings. Afterwards set
+ * "b:current_compiler" and restore "current_compiler".
+ * Explicitly prepend "g:" to make it work in a function. */
+ old_cur_comp = get_var_value((char_u *)"g:current_compiler");
+ if (old_cur_comp != NULL)
+ old_cur_comp = vim_strsave(old_cur_comp);
+ do_cmdline_cmd((char_u *)
+ "command -nargs=* CompilerSet setlocal <args>");
+ }
+ do_unlet((char_u *)"g:current_compiler", TRUE);
+ do_unlet((char_u *)"b:current_compiler", TRUE);
+
+ sprintf((char *)buf, "compiler/%s.vim", eap->arg);
+ if (source_runtime(buf, DIP_ALL) == FAIL)
+ semsg(_("E666: compiler not supported: %s"), eap->arg);
+ vim_free(buf);
+
+ do_cmdline_cmd((char_u *)":delcommand CompilerSet");
+
+ /* Set "b:current_compiler" from "current_compiler". */
+ p = get_var_value((char_u *)"g:current_compiler");
+ if (p != NULL)
+ set_internal_string_var((char_u *)"b:current_compiler", p);
+
+ /* Restore "current_compiler" for ":compiler {name}". */
+ if (!eap->forceit)
+ {
+ if (old_cur_comp != NULL)
+ {
+ set_internal_string_var((char_u *)"g:current_compiler",
+ old_cur_comp);
+ vim_free(old_cur_comp);
+ }
+ else
+ do_unlet((char_u *)"g:current_compiler", TRUE);
+ }
+ }
+ }
+}
+#endif
+
+/*
+ * ":runtime [what] {name}"
+ */
+ void
+ex_runtime(exarg_T *eap)
+{
+ char_u *arg = eap->arg;
+ char_u *p = skiptowhite(arg);
+ int len = (int)(p - arg);
+ int flags = eap->forceit ? DIP_ALL : 0;
+
+ if (STRNCMP(arg, "START", len) == 0)
+ {
+ flags += DIP_START + DIP_NORTP;
+ arg = skipwhite(arg + len);
+ }
+ else if (STRNCMP(arg, "OPT", len) == 0)
+ {
+ flags += DIP_OPT + DIP_NORTP;
+ arg = skipwhite(arg + len);
+ }
+ else if (STRNCMP(arg, "PACK", len) == 0)
+ {
+ flags += DIP_START + DIP_OPT + DIP_NORTP;
+ arg = skipwhite(arg + len);
+ }
+ else if (STRNCMP(arg, "ALL", len) == 0)
+ {
+ flags += DIP_START + DIP_OPT;
+ arg = skipwhite(arg + len);
+ }
+
+ source_runtime(arg, flags);
+}
+
+ static void
+source_callback(char_u *fname, void *cookie UNUSED)
+{
+ (void)do_source(fname, FALSE, DOSO_NONE);
+}
+
+/*
+ * Find the file "name" in all directories in "path" and invoke
+ * "callback(fname, cookie)".
+ * "name" can contain wildcards.
+ * When "flags" has DIP_ALL: source all files, otherwise only the first one.
+ * When "flags" has DIP_DIR: find directories instead of files.
+ * When "flags" has DIP_ERR: give an error message if there is no match.
+ *
+ * return FAIL when no file could be sourced, OK otherwise.
+ */
+ int
+do_in_path(
+ char_u *path,
+ char_u *name,
+ int flags,
+ void (*callback)(char_u *fname, void *ck),
+ void *cookie)
+{
+ char_u *rtp;
+ char_u *np;
+ char_u *buf;
+ char_u *rtp_copy;
+ char_u *tail;
+ int num_files;
+ char_u **files;
+ int i;
+ int did_one = FALSE;
+#ifdef AMIGA
+ struct Process *proc = (struct Process *)FindTask(0L);
+ APTR save_winptr = proc->pr_WindowPtr;
+
+ /* Avoid a requester here for a volume that doesn't exist. */
+ proc->pr_WindowPtr = (APTR)-1L;
+#endif
+
+ /* Make a copy of 'runtimepath'. Invoking the callback may change the
+ * value. */
+ rtp_copy = vim_strsave(path);
+ buf = alloc(MAXPATHL);
+ if (buf != NULL && rtp_copy != NULL)
+ {
+ if (p_verbose > 1 && name != NULL)
+ {
+ verbose_enter();
+ smsg(_("Searching for \"%s\" in \"%s\""),
+ (char *)name, (char *)path);
+ verbose_leave();
+ }
+
+ /* Loop over all entries in 'runtimepath'. */
+ rtp = rtp_copy;
+ while (*rtp != NUL && ((flags & DIP_ALL) || !did_one))
+ {
+ size_t buflen;
+
+ /* Copy the path from 'runtimepath' to buf[]. */
+ copy_option_part(&rtp, buf, MAXPATHL, ",");
+ buflen = STRLEN(buf);
+
+ /* Skip after or non-after directories. */
+ if (flags & (DIP_NOAFTER | DIP_AFTER))
+ {
+ int is_after = buflen >= 5
+ && STRCMP(buf + buflen - 5, "after") == 0;
+
+ if ((is_after && (flags & DIP_NOAFTER))
+ || (!is_after && (flags & DIP_AFTER)))
+ continue;
+ }
+
+ if (name == NULL)
+ {
+ (*callback)(buf, (void *) &cookie);
+ if (!did_one)
+ did_one = (cookie == NULL);
+ }
+ else if (buflen + STRLEN(name) + 2 < MAXPATHL)
+ {
+ add_pathsep(buf);
+ tail = buf + STRLEN(buf);
+
+ /* Loop over all patterns in "name" */
+ np = name;
+ while (*np != NUL && ((flags & DIP_ALL) || !did_one))
+ {
+ /* Append the pattern from "name" to buf[]. */
+ copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
+ "\t ");
+
+ if (p_verbose > 2)
+ {
+ verbose_enter();
+ smsg(_("Searching for \"%s\""), buf);
+ verbose_leave();
+ }
+
+ /* Expand wildcards, invoke the callback for each match. */
+ if (gen_expand_wildcards(1, &buf, &num_files, &files,
+ (flags & DIP_DIR) ? EW_DIR : EW_FILE) == OK)
+ {
+ for (i = 0; i < num_files; ++i)
+ {
+ (*callback)(files[i], cookie);
+ did_one = TRUE;
+ if (!(flags & DIP_ALL))
+ break;
+ }
+ FreeWild(num_files, files);
+ }
+ }
+ }
+ }
+ }
+ vim_free(buf);
+ vim_free(rtp_copy);
+ if (!did_one && name != NULL)
+ {
+ char *basepath = path == p_rtp ? "runtimepath" : "packpath";
+
+ if (flags & DIP_ERR)
+ semsg(_(e_dirnotf), basepath, name);
+ else if (p_verbose > 0)
+ {
+ verbose_enter();
+ smsg(_("not found in '%s': \"%s\""), basepath, name);
+ verbose_leave();
+ }
+ }
+
+#ifdef AMIGA
+ proc->pr_WindowPtr = save_winptr;
+#endif
+
+ return did_one ? OK : FAIL;
+}
+
+/*
+ * Find "name" in "path". When found, invoke the callback function for
+ * it: callback(fname, "cookie")
+ * When "flags" has DIP_ALL repeat for all matches, otherwise only the first
+ * one is used.
+ * Returns OK when at least one match found, FAIL otherwise.
+ *
+ * If "name" is NULL calls callback for each entry in "path". Cookie is
+ * passed by reference in this case, setting it to NULL indicates that callback
+ * has done its job.
+ */
+ static int
+do_in_path_and_pp(
+ char_u *path,
+ char_u *name,
+ int flags,
+ void (*callback)(char_u *fname, void *ck),
+ void *cookie)
+{
+ int done = FAIL;
+ char_u *s;
+ int len;
+ char *start_dir = "pack/*/start/*/%s";
+ char *opt_dir = "pack/*/opt/*/%s";
+
+ if ((flags & DIP_NORTP) == 0)
+ done = do_in_path(path, name, flags, callback, cookie);
+
+ if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_START))
+ {
+ len = (int)(STRLEN(start_dir) + STRLEN(name));
+ s = alloc(len);
+ if (s == NULL)
+ return FAIL;
+ vim_snprintf((char *)s, len, start_dir, name);
+ done = do_in_path(p_pp, s, flags, callback, cookie);
+ vim_free(s);
+ }
+
+ if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_OPT))
+ {
+ len = (int)(STRLEN(opt_dir) + STRLEN(name));
+ s = alloc(len);
+ if (s == NULL)
+ return FAIL;
+ vim_snprintf((char *)s, len, opt_dir, name);
+ done = do_in_path(p_pp, s, flags, callback, cookie);
+ vim_free(s);
+ }
+
+ return done;
+}
+
+/*
+ * Just like do_in_path_and_pp(), using 'runtimepath' for "path".
+ */
+ int
+do_in_runtimepath(
+ char_u *name,
+ int flags,
+ void (*callback)(char_u *fname, void *ck),
+ void *cookie)
+{
+ return do_in_path_and_pp(p_rtp, name, flags, callback, cookie);
+}
+
+/*
+ * Source the file "name" from all directories in 'runtimepath'.
+ * "name" can contain wildcards.
+ * When "flags" has DIP_ALL: source all files, otherwise only the first one.
+ *
+ * return FAIL when no file could be sourced, OK otherwise.
+ */
+ int
+source_runtime(char_u *name, int flags)
+{
+ return source_in_path(p_rtp, name, flags);
+}
+
+/*
+ * Just like source_runtime(), but use "path" instead of 'runtimepath'.
+ */
+ int
+source_in_path(char_u *path, char_u *name, int flags)
+{
+ return do_in_path_and_pp(path, name, flags, source_callback, NULL);
+}
+
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+
+/*
+ * Expand wildcards in "pat" and invoke do_source() for each match.
+ */
+ static void
+source_all_matches(char_u *pat)
+{
+ int num_files;
+ char_u **files;
+ int i;
+
+ if (gen_expand_wildcards(1, &pat, &num_files, &files, EW_FILE) == OK)
+ {
+ for (i = 0; i < num_files; ++i)
+ (void)do_source(files[i], FALSE, DOSO_NONE);
+ FreeWild(num_files, files);
+ }
+}
+
+/*
+ * Add the package directory to 'runtimepath'.
+ */
+ static int
+add_pack_dir_to_rtp(char_u *fname)
+{
+ char_u *p4, *p3, *p2, *p1, *p;
+ char_u *entry;
+ char_u *insp = NULL;
+ int c;
+ char_u *new_rtp;
+ int keep;
+ size_t oldlen;
+ size_t addlen;
+ size_t new_rtp_len;
+ char_u *afterdir = NULL;
+ size_t afterlen = 0;
+ char_u *after_insp = NULL;
+ char_u *ffname = NULL;
+ size_t fname_len;
+ char_u *buf = NULL;
+ char_u *rtp_ffname;
+ int match;
+ int retval = FAIL;
+
+ p4 = p3 = p2 = p1 = get_past_head(fname);
+ for (p = p1; *p; MB_PTR_ADV(p))
+ if (vim_ispathsep_nocolon(*p))
+ {
+ p4 = p3; p3 = p2; p2 = p1; p1 = p;
+ }
+
+ /* now we have:
+ * rtp/pack/name/start/name
+ * p4 p3 p2 p1
+ *
+ * find the part up to "pack" in 'runtimepath' */
+ c = *++p4; /* append pathsep in order to expand symlink */
+ *p4 = NUL;
+ ffname = fix_fname(fname);
+ *p4 = c;
+ if (ffname == NULL)
+ return FAIL;
+
+ // Find "ffname" in "p_rtp", ignoring '/' vs '\' differences.
+ // Also stop at the first "after" directory.
+ fname_len = STRLEN(ffname);
+ buf = alloc(MAXPATHL);
+ if (buf == NULL)
+ goto theend;
+ for (entry = p_rtp; *entry != NUL; )
+ {
+ char_u *cur_entry = entry;
+
+ copy_option_part(&entry, buf, MAXPATHL, ",");
+ if (insp == NULL)
+ {
+ add_pathsep(buf);
+ rtp_ffname = fix_fname(buf);
+ if (rtp_ffname == NULL)
+ goto theend;
+ match = vim_fnamencmp(rtp_ffname, ffname, fname_len) == 0;
+ vim_free(rtp_ffname);
+ if (match)
+ // Insert "ffname" after this entry (and comma).
+ insp = entry;
+ }
+
+ if ((p = (char_u *)strstr((char *)buf, "after")) != NULL
+ && p > buf
+ && vim_ispathsep(p[-1])
+ && (vim_ispathsep(p[5]) || p[5] == NUL || p[5] == ','))
+ {
+ if (insp == NULL)
+ // Did not find "ffname" before the first "after" directory,
+ // insert it before this entry.
+ insp = cur_entry;
+ after_insp = cur_entry;
+ break;
+ }
+ }
+
+ if (insp == NULL)
+ // Both "fname" and "after" not found, append at the end.
+ insp = p_rtp + STRLEN(p_rtp);
+
+ // check if rtp/pack/name/start/name/after exists
+ afterdir = concat_fnames(fname, (char_u *)"after", TRUE);
+ if (afterdir != NULL && mch_isdir(afterdir))
+ afterlen = STRLEN(afterdir) + 1; // add one for comma
+
+ oldlen = STRLEN(p_rtp);
+ addlen = STRLEN(fname) + 1; // add one for comma
+ new_rtp = alloc((int)(oldlen + addlen + afterlen + 1)); // add one for NUL
+ if (new_rtp == NULL)
+ goto theend;
+
+ // We now have 'rtp' parts: {keep}{keep_after}{rest}.
+ // Create new_rtp, first: {keep},{fname}
+ keep = (int)(insp - p_rtp);
+ mch_memmove(new_rtp, p_rtp, keep);
+ new_rtp_len = keep;
+ if (*insp == NUL)
+ new_rtp[new_rtp_len++] = ','; // add comma before
+ mch_memmove(new_rtp + new_rtp_len, fname, addlen - 1);
+ new_rtp_len += addlen - 1;
+ if (*insp != NUL)
+ new_rtp[new_rtp_len++] = ','; // add comma after
+
+ if (afterlen > 0 && after_insp != NULL)
+ {
+ int keep_after = (int)(after_insp - p_rtp);
+
+ // Add to new_rtp: {keep},{fname}{keep_after},{afterdir}
+ mch_memmove(new_rtp + new_rtp_len, p_rtp + keep,
+ keep_after - keep);
+ new_rtp_len += keep_after - keep;
+ mch_memmove(new_rtp + new_rtp_len, afterdir, afterlen - 1);
+ new_rtp_len += afterlen - 1;
+ new_rtp[new_rtp_len++] = ',';
+ keep = keep_after;
+ }
+
+ if (p_rtp[keep] != NUL)
+ // Append rest: {keep},{fname}{keep_after},{afterdir}{rest}
+ mch_memmove(new_rtp + new_rtp_len, p_rtp + keep, oldlen - keep + 1);
+ else
+ new_rtp[new_rtp_len] = NUL;
+
+ if (afterlen > 0 && after_insp == NULL)
+ {
+ // Append afterdir when "after" was not found:
+ // {keep},{fname}{rest},{afterdir}
+ STRCAT(new_rtp, ",");
+ STRCAT(new_rtp, afterdir);
+ }
+
+ set_option_value((char_u *)"rtp", 0L, new_rtp, 0);
+ vim_free(new_rtp);
+ retval = OK;
+
+theend:
+ vim_free(buf);
+ vim_free(ffname);
+ vim_free(afterdir);
+ return retval;
+}
+
+/*
+ * Load scripts in "plugin" and "ftdetect" directories of the package.
+ */
+ static int
+load_pack_plugin(char_u *fname)
+{
+ static char *plugpat = "%s/plugin/**/*.vim";
+ static char *ftpat = "%s/ftdetect/*.vim";
+ int len;
+ char_u *ffname = fix_fname(fname);
+ char_u *pat = NULL;
+ int retval = FAIL;
+
+ if (ffname == NULL)
+ return FAIL;
+ len = (int)STRLEN(ffname) + (int)STRLEN(ftpat);
+ pat = alloc(len);
+ if (pat == NULL)
+ goto theend;
+ vim_snprintf((char *)pat, len, plugpat, ffname);
+ source_all_matches(pat);
+
+ {
+ char_u *cmd = vim_strsave((char_u *)"g:did_load_filetypes");
+
+ /* If runtime/filetype.vim wasn't loaded yet, the scripts will be
+ * found when it loads. */
+ if (cmd != NULL && eval_to_number(cmd) > 0)
+ {
+ do_cmdline_cmd((char_u *)"augroup filetypedetect");
+ vim_snprintf((char *)pat, len, ftpat, ffname);
+ source_all_matches(pat);
+ do_cmdline_cmd((char_u *)"augroup END");
+ }
+ vim_free(cmd);
+ }
+ vim_free(pat);
+ retval = OK;
+
+theend:
+ vim_free(ffname);
+ return retval;
+}
+
+/* used for "cookie" of add_pack_plugin() */
+static int APP_ADD_DIR;
+static int APP_LOAD;
+static int APP_BOTH;
+
+ static void
+add_pack_plugin(char_u *fname, void *cookie)
+{
+ if (cookie != &APP_LOAD)
+ {
+ char_u *buf = alloc(MAXPATHL);
+ char_u *p;
+ int found = FALSE;
+
+ if (buf == NULL)
+ return;
+ p = p_rtp;
+ while (*p != NUL)
+ {
+ copy_option_part(&p, buf, MAXPATHL, ",");
+ if (pathcmp((char *)buf, (char *)fname, -1) == 0)
+ {
+ found = TRUE;
+ break;
+ }
+ }
+ vim_free(buf);
+ if (!found)
+ /* directory is not yet in 'runtimepath', add it */
+ if (add_pack_dir_to_rtp(fname) == FAIL)
+ return;
+ }
+
+ if (cookie != &APP_ADD_DIR)
+ load_pack_plugin(fname);
+}
+
+/*
+ * Add all packages in the "start" directory to 'runtimepath'.
+ */
+ void
+add_pack_start_dirs(void)
+{
+ do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR,
+ add_pack_plugin, &APP_ADD_DIR);
+}
+
+/*
+ * Load plugins from all packages in the "start" directory.
+ */
+ void
+load_start_packages(void)
+{
+ did_source_packages = TRUE;
+ do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR,
+ add_pack_plugin, &APP_LOAD);
+}
+
+/*
+ * ":packloadall"
+ * Find plugins in the package directories and source them.
+ */
+ void
+ex_packloadall(exarg_T *eap)
+{
+ if (!did_source_packages || eap->forceit)
+ {
+ /* First do a round to add all directories to 'runtimepath', then load
+ * the plugins. This allows for plugins to use an autoload directory
+ * of another plugin. */
+ add_pack_start_dirs();
+ load_start_packages();
+ }
+}
+
+/*
+ * ":packadd[!] {name}"
+ */
+ void
+ex_packadd(exarg_T *eap)
+{
+ static char *plugpat = "pack/*/%s/%s";
+ int len;
+ char *pat;
+ int round;
+ int res = OK;
+
+ /* Round 1: use "start", round 2: use "opt". */
+ for (round = 1; round <= 2; ++round)
+ {
+ /* Only look under "start" when loading packages wasn't done yet. */
+ if (round == 1 && did_source_packages)
+ continue;
+
+ len = (int)STRLEN(plugpat) + (int)STRLEN(eap->arg) + 5;
+ pat = (char *)alloc(len);
+ if (pat == NULL)
+ return;
+ vim_snprintf(pat, len, plugpat, round == 1 ? "start" : "opt", eap->arg);
+ /* The first round don't give a "not found" error, in the second round
+ * only when nothing was found in the first round. */
+ res = do_in_path(p_pp, (char_u *)pat,
+ DIP_ALL + DIP_DIR + (round == 2 && res == FAIL ? DIP_ERR : 0),
+ add_pack_plugin, eap->forceit ? &APP_ADD_DIR : &APP_BOTH);
+ vim_free(pat);
+ }
+}
+#endif
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * ":options"
+ */
+ void
+ex_options(
+ exarg_T *eap UNUSED)
+{
+ vim_setenv((char_u *)"OPTWIN_CMD", (char_u *)(cmdmod.tab ? "tab" : ""));
+ cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
+}
+#endif
+
+#if defined(FEAT_PYTHON3) || defined(FEAT_PYTHON) || defined(PROTO)
+
+# if (defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)) || defined(PROTO)
+/*
+ * Detect Python 3 or 2, and initialize 'pyxversion'.
+ */
+ void
+init_pyxversion(void)
+{
+ if (p_pyx == 0)
+ {
+ if (python3_enabled(FALSE))
+ p_pyx = 3;
+ else if (python_enabled(FALSE))
+ p_pyx = 2;
+ }
+}
+# endif
+
+/*
+ * Does a file contain one of the following strings at the beginning of any
+ * line?
+ * "#!(any string)python2" => returns 2
+ * "#!(any string)python3" => returns 3
+ * "# requires python 2.x" => returns 2
+ * "# requires python 3.x" => returns 3
+ * otherwise return 0.
+ */
+ static int
+requires_py_version(char_u *filename)
+{
+ FILE *file;
+ int requires_py_version = 0;
+ int i, lines;
+
+ lines = (int)p_mls;
+ if (lines < 0)
+ lines = 5;
+
+ file = mch_fopen((char *)filename, "r");
+ if (file != NULL)
+ {
+ for (i = 0; i < lines; i++)
+ {
+ if (vim_fgets(IObuff, IOSIZE, file))
+ break;
+ if (i == 0 && IObuff[0] == '#' && IObuff[1] == '!')
+ {
+ /* Check shebang. */
+ if (strstr((char *)IObuff + 2, "python2") != NULL)
+ {
+ requires_py_version = 2;
+ break;
+ }
+ if (strstr((char *)IObuff + 2, "python3") != NULL)
+ {
+ requires_py_version = 3;
+ break;
+ }
+ }
+ IObuff[21] = '\0';
+ if (STRCMP("# requires python 2.x", IObuff) == 0)
+ {
+ requires_py_version = 2;
+ break;
+ }
+ if (STRCMP("# requires python 3.x", IObuff) == 0)
+ {
+ requires_py_version = 3;
+ break;
+ }
+ }
+ fclose(file);
+ }
+ return requires_py_version;
+}
+
+
+/*
+ * Source a python file using the requested python version.
+ */
+ static void
+source_pyx_file(exarg_T *eap, char_u *fname)
+{
+ exarg_T ex;
+ int v = requires_py_version(fname);
+
+# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
+ init_pyxversion();
+# endif
+ if (v == 0)
+ {
+# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
+ /* user didn't choose a preference, 'pyx' is used */
+ v = p_pyx;
+# elif defined(FEAT_PYTHON)
+ v = 2;
+# elif defined(FEAT_PYTHON3)
+ v = 3;
+# endif
+ }
+
+ /*
+ * now source, if required python version is not supported show
+ * unobtrusive message.
+ */
+ if (eap == NULL)
+ vim_memset(&ex, 0, sizeof(ex));
+ else
+ ex = *eap;
+ ex.arg = fname;
+ ex.cmd = (char_u *)(v == 2 ? "pyfile" : "pyfile3");
+
+ if (v == 2)
+ {
+# ifdef FEAT_PYTHON
+ ex_pyfile(&ex);
+# else
+ vim_snprintf((char *)IObuff, IOSIZE,
+ _("W20: Required python version 2.x not supported, ignoring file: %s"),
+ fname);
+ msg((char *)IObuff);
+# endif
+ return;
+ }
+ else
+ {
+# ifdef FEAT_PYTHON3
+ ex_py3file(&ex);
+# else
+ vim_snprintf((char *)IObuff, IOSIZE,
+ _("W21: Required python version 3.x not supported, ignoring file: %s"),
+ fname);
+ msg((char *)IObuff);
+# endif
+ return;
+ }
+}
+
+/*
+ * ":pyxfile {fname}"
+ */
+ void
+ex_pyxfile(exarg_T *eap)
+{
+ source_pyx_file(eap, eap->arg);
+}
+
+/*
+ * ":pyx"
+ */
+ void
+ex_pyx(exarg_T *eap)
+{
+# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
+ init_pyxversion();
+ if (p_pyx == 2)
+ ex_python(eap);
+ else
+ ex_py3(eap);
+# elif defined(FEAT_PYTHON)
+ ex_python(eap);
+# elif defined(FEAT_PYTHON3)
+ ex_py3(eap);
+# endif
+}
+
+/*
+ * ":pyxdo"
+ */
+ void
+ex_pyxdo(exarg_T *eap)
+{
+# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
+ init_pyxversion();
+ if (p_pyx == 2)
+ ex_pydo(eap);
+ else
+ ex_py3do(eap);
+# elif defined(FEAT_PYTHON)
+ ex_pydo(eap);
+# elif defined(FEAT_PYTHON3)
+ ex_py3do(eap);
+# endif
+}
+
+#endif
+
+/*
+ * ":source {fname}"
+ */
+ void
+ex_source(exarg_T *eap)
+{
+#ifdef FEAT_BROWSE
+ if (cmdmod.browse)
+ {
+ char_u *fname = NULL;
+
+ fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
+ NULL, NULL,
+ (char_u *)_(BROWSE_FILTER_MACROS), NULL);
+ if (fname != NULL)
+ {
+ cmd_source(fname, eap);
+ vim_free(fname);
+ }
+ }
+ else
+#endif
+ cmd_source(eap->arg, eap);
+}
+
+ static void
+cmd_source(char_u *fname, exarg_T *eap)
+{
+ if (*fname == NUL)
+ emsg(_(e_argreq));
+
+ else if (eap != NULL && eap->forceit)
+ /* ":source!": read Normal mode commands
+ * Need to execute the commands directly. This is required at least
+ * for:
+ * - ":g" command busy
+ * - after ":argdo", ":windo" or ":bufdo"
+ * - another command follows
+ * - inside a loop
+ */
+ openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
+#ifdef FEAT_EVAL
+ || eap->cstack->cs_idx >= 0
+#endif
+ );
+
+ /* ":source" read ex commands */
+ else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
+ semsg(_(e_notopen), fname);
+}
+
+/*
+ * ":source" and associated commands.
+ */
+/*
+ * Structure used to store info for each sourced file.
+ * It is shared between do_source() and getsourceline().
+ * This is required, because it needs to be handed to do_cmdline() and
+ * sourcing can be done recursively.
+ */
+struct source_cookie
+{
+ FILE *fp; /* opened file for sourcing */
+ char_u *nextline; /* if not NULL: line that was read ahead */
+ int finished; /* ":finish" used */
+#if defined(USE_CRNL) || defined(USE_CR)
+ int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
+ int error; /* TRUE if LF found after CR-LF */
+#endif
+#ifdef FEAT_EVAL
+ linenr_T breakpoint; /* next line with breakpoint or zero */
+ char_u *fname; /* name of sourced file */
+ int dbg_tick; /* debug_tick when breakpoint was set */
+ int level; /* top nesting level of sourced file */
+#endif
+ vimconv_T conv; /* type of conversion */
+};
+
+#ifdef FEAT_EVAL
+/*
+ * Return the address holding the next breakpoint line for a source cookie.
+ */
+ linenr_T *
+source_breakpoint(void *cookie)
+{
+ return &((struct source_cookie *)cookie)->breakpoint;
+}
+
+/*
+ * Return the address holding the debug tick for a source cookie.
+ */
+ int *
+source_dbg_tick(void *cookie)
+{
+ return &((struct source_cookie *)cookie)->dbg_tick;
+}
+
+/*
+ * Return the nesting level for a source cookie.
+ */
+ int
+source_level(void *cookie)
+{
+ return ((struct source_cookie *)cookie)->level;
+}
+#endif
+
+static char_u *get_one_sourceline(struct source_cookie *sp);
+
+#if (defined(WIN32) && defined(FEAT_CSCOPE)) || defined(HAVE_FD_CLOEXEC)
+# define USE_FOPEN_NOINH
+/*
+ * Special function to open a file without handle inheritance.
+ * When possible the handle is closed on exec().
+ */
+ static FILE *
+fopen_noinh_readbin(char *filename)
+{
+# ifdef WIN32
+ int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
+# else
+ int fd_tmp = mch_open(filename, O_RDONLY, 0);
+# endif
+
+ if (fd_tmp == -1)
+ return NULL;
+
+# ifdef HAVE_FD_CLOEXEC
+ {
+ int fdflags = fcntl(fd_tmp, F_GETFD);
+ if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
+ (void)fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC);
+ }
+# endif
+
+ return fdopen(fd_tmp, READBIN);
+}
+#endif
+
+
+/*
+ * do_source: Read the file "fname" and execute its lines as EX commands.
+ *
+ * This function may be called recursively!
+ *
+ * return FAIL if file could not be opened, OK otherwise
+ */
+ int
+do_source(
+ char_u *fname,
+ int check_other, /* check for .vimrc and _vimrc */
+ int is_vimrc) /* DOSO_ value */
+{
+ struct source_cookie cookie;
+ char_u *save_sourcing_name;
+ linenr_T save_sourcing_lnum;
+ char_u *p;
+ char_u *fname_exp;
+ char_u *firstline = NULL;
+ int retval = FAIL;
+#ifdef FEAT_EVAL
+ sctx_T save_current_sctx;
+ static scid_T last_current_SID = 0;
+ static int last_current_SID_seq = 0;
+ funccal_entry_T funccalp_entry;
+ int save_debug_break_level = debug_break_level;
+ scriptitem_T *si = NULL;
+# ifdef UNIX
+ stat_T st;
+ int stat_ok;
+# endif
+#endif
+#ifdef STARTUPTIME
+ struct timeval tv_rel;
+ struct timeval tv_start;
+#endif
+#ifdef FEAT_PROFILE
+ proftime_T wait_start;
+#endif
+ int trigger_source_post = FALSE;
+
+ p = expand_env_save(fname);
+ if (p == NULL)
+ return retval;
+ fname_exp = fix_fname(p);
+ vim_free(p);
+ if (fname_exp == NULL)
+ return retval;
+ if (mch_isdir(fname_exp))
+ {
+ smsg(_("Cannot source a directory: \"%s\""), fname);
+ goto theend;
+ }
+
+ /* Apply SourceCmd autocommands, they should get the file and source it. */
+ if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
+ && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
+ FALSE, curbuf))
+ {
+#ifdef FEAT_EVAL
+ retval = aborting() ? FAIL : OK;
+#else
+ retval = OK;
+#endif
+ if (retval == OK)
+ // Apply SourcePost autocommands.
+ apply_autocmds(EVENT_SOURCEPOST, fname_exp, fname_exp,
+ FALSE, curbuf);
+ goto theend;
+ }
+
+ /* Apply SourcePre autocommands, they may get the file. */
+ apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
+
+#ifdef USE_FOPEN_NOINH
+ cookie.fp = fopen_noinh_readbin((char *)fname_exp);
+#else
+ cookie.fp = mch_fopen((char *)fname_exp, READBIN);
+#endif
+ if (cookie.fp == NULL && check_other)
+ {
+ /*
+ * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
+ * and ".exrc" by "_exrc" or vice versa.
+ */
+ p = gettail(fname_exp);
+ if ((*p == '.' || *p == '_')
+ && (STRICMP(p + 1, "vimrc") == 0
+ || STRICMP(p + 1, "gvimrc") == 0
+ || STRICMP(p + 1, "exrc") == 0))
+ {
+ if (*p == '_')
+ *p = '.';
+ else
+ *p = '_';
+#ifdef USE_FOPEN_NOINH
+ cookie.fp = fopen_noinh_readbin((char *)fname_exp);
+#else
+ cookie.fp = mch_fopen((char *)fname_exp, READBIN);
+#endif
+ }
+ }
+
+ if (cookie.fp == NULL)
+ {
+ if (p_verbose > 0)
+ {
+ verbose_enter();
+ if (sourcing_name == NULL)
+ smsg(_("could not source \"%s\""), fname);
+ else
+ smsg(_("line %ld: could not source \"%s\""),
+ sourcing_lnum, fname);
+ verbose_leave();
+ }
+ goto theend;
+ }
+
+ /*
+ * The file exists.
+ * - In verbose mode, give a message.
+ * - For a vimrc file, may want to set 'compatible', call vimrc_found().
+ */
+ if (p_verbose > 1)
+ {
+ verbose_enter();
+ if (sourcing_name == NULL)
+ smsg(_("sourcing \"%s\""), fname);
+ else
+ smsg(_("line %ld: sourcing \"%s\""),
+ sourcing_lnum, fname);
+ verbose_leave();
+ }
+ if (is_vimrc == DOSO_VIMRC)
+ vimrc_found(fname_exp, (char_u *)"MYVIMRC");
+ else if (is_vimrc == DOSO_GVIMRC)
+ vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
+
+#ifdef USE_CRNL
+ /* If no automatic file format: Set default to CR-NL. */
+ if (*p_ffs == NUL)
+ cookie.fileformat = EOL_DOS;
+ else
+ cookie.fileformat = EOL_UNKNOWN;
+ cookie.error = FALSE;
+#endif
+
+#ifdef USE_CR
+ /* If no automatic file format: Set default to CR. */
+ if (*p_ffs == NUL)
+ cookie.fileformat = EOL_MAC;
+ else
+ cookie.fileformat = EOL_UNKNOWN;
+ cookie.error = FALSE;
+#endif
+
+ cookie.nextline = NULL;
+ cookie.finished = FALSE;
+
+#ifdef FEAT_EVAL
+ /*
+ * Check if this script has a breakpoint.
+ */
+ cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
+ cookie.fname = fname_exp;
+ cookie.dbg_tick = debug_tick;
+
+ cookie.level = ex_nesting_level;
+#endif
+
+ /*
+ * Keep the sourcing name/lnum, for recursive calls.
+ */
+ save_sourcing_name = sourcing_name;
+ sourcing_name = fname_exp;
+ save_sourcing_lnum = sourcing_lnum;
+ sourcing_lnum = 0;
+
+#ifdef STARTUPTIME
+ if (time_fd != NULL)
+ time_push(&tv_rel, &tv_start);
+#endif
+
+#ifdef FEAT_EVAL
+# ifdef FEAT_PROFILE
+ if (do_profiling == PROF_YES)
+ prof_child_enter(&wait_start); /* entering a child now */
+# endif
+
+ /* Don't use local function variables, if called from a function.
+ * Also starts profiling timer for nested script. */
+ save_funccal(&funccalp_entry);
+
+ // Check if this script was sourced before to finds its SID.
+ // If it's new, generate a new SID.
+ // Always use a new sequence number.
+ save_current_sctx = current_sctx;
+ current_sctx.sc_seq = ++last_current_SID_seq;
+ current_sctx.sc_lnum = 0;
+# ifdef UNIX
+ stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
+# endif
+ for (current_sctx.sc_sid = script_items.ga_len; current_sctx.sc_sid > 0;
+ --current_sctx.sc_sid)
+ {
+ si = &SCRIPT_ITEM(current_sctx.sc_sid);
+ if (si->sn_name != NULL
+ && (
+# ifdef UNIX
+ /* Compare dev/ino when possible, it catches symbolic
+ * links. Also compare file names, the inode may change
+ * when the file was edited. */
+ ((stat_ok && si->sn_dev_valid)
+ && (si->sn_dev == st.st_dev
+ && si->sn_ino == st.st_ino)) ||
+# endif
+ fnamecmp(si->sn_name, fname_exp) == 0))
+ break;
+ }
+ if (current_sctx.sc_sid == 0)
+ {
+ current_sctx.sc_sid = ++last_current_SID;
+ if (ga_grow(&script_items,
+ (int)(current_sctx.sc_sid - script_items.ga_len)) == FAIL)
+ goto almosttheend;
+ while (script_items.ga_len < current_sctx.sc_sid)
+ {
+ ++script_items.ga_len;
+ SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
+# ifdef FEAT_PROFILE
+ SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
+# endif
+ }
+ si = &SCRIPT_ITEM(current_sctx.sc_sid);
+ si->sn_name = fname_exp;
+ fname_exp = vim_strsave(si->sn_name); // used for autocmd
+# ifdef UNIX
+ if (stat_ok)
+ {
+ si->sn_dev_valid = TRUE;
+ si->sn_dev = st.st_dev;
+ si->sn_ino = st.st_ino;
+ }
+ else
+ si->sn_dev_valid = FALSE;
+# endif
+
+ /* Allocate the local script variables to use for this script. */
+ new_script_vars(current_sctx.sc_sid);
+ }
+
+# ifdef FEAT_PROFILE
+ if (do_profiling == PROF_YES)
+ {
+ int forceit;
+
+ /* Check if we do profiling for this script. */
+ if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
+ {
+ script_do_profile(si);
+ si->sn_pr_force = forceit;
+ }
+ if (si->sn_prof_on)
+ {
+ ++si->sn_pr_count;
+ profile_start(&si->sn_pr_start);
+ profile_zero(&si->sn_pr_children);
+ }
+ }
+# endif
+#endif
+
+ cookie.conv.vc_type = CONV_NONE; /* no conversion */
+
+ /* Read the first line so we can check for a UTF-8 BOM. */
+ firstline = getsourceline(0, (void *)&cookie, 0);
+ if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
+ && firstline[1] == 0xbb && firstline[2] == 0xbf)
+ {
+ /* Found BOM; setup conversion, skip over BOM and recode the line. */
+ convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
+ p = string_convert(&cookie.conv, firstline + 3, NULL);
+ if (p == NULL)
+ p = vim_strsave(firstline + 3);
+ if (p != NULL)
+ {
+ vim_free(firstline);
+ firstline = p;
+ }
+ }
+
+ /*
+ * Call do_cmdline, which will call getsourceline() to get the lines.
+ */
+ do_cmdline(firstline, getsourceline, (void *)&cookie,
+ DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
+ retval = OK;
+
+#ifdef FEAT_PROFILE
+ if (do_profiling == PROF_YES)
+ {
+ /* Get "si" again, "script_items" may have been reallocated. */
+ si = &SCRIPT_ITEM(current_sctx.sc_sid);
+ if (si->sn_prof_on)
+ {
+ profile_end(&si->sn_pr_start);
+ profile_sub_wait(&wait_start, &si->sn_pr_start);
+ profile_add(&si->sn_pr_total, &si->sn_pr_start);
+ profile_self(&si->sn_pr_self, &si->sn_pr_start,
+ &si->sn_pr_children);
+ }
+ }
+#endif
+
+ if (got_int)
+ emsg(_(e_interr));
+ sourcing_name = save_sourcing_name;
+ sourcing_lnum = save_sourcing_lnum;
+ if (p_verbose > 1)
+ {
+ verbose_enter();
+ smsg(_("finished sourcing %s"), fname);
+ if (sourcing_name != NULL)
+ smsg(_("continuing in %s"), sourcing_name);
+ verbose_leave();
+ }
+#ifdef STARTUPTIME
+ if (time_fd != NULL)
+ {
+ vim_snprintf((char *)IObuff, IOSIZE, "sourcing %s", fname);
+ time_msg((char *)IObuff, &tv_start);
+ time_pop(&tv_rel);
+ }
+#endif
+
+ if (!got_int)
+ trigger_source_post = TRUE;
+
+#ifdef FEAT_EVAL
+ /*
+ * After a "finish" in debug mode, need to break at first command of next
+ * sourced file.
+ */
+ if (save_debug_break_level > ex_nesting_level
+ && debug_break_level == ex_nesting_level)
+ ++debug_break_level;
+#endif
+
+#ifdef FEAT_EVAL
+almosttheend:
+ current_sctx = save_current_sctx;
+ restore_funccal();
+# ifdef FEAT_PROFILE
+ if (do_profiling == PROF_YES)
+ prof_child_exit(&wait_start); /* leaving a child now */
+# endif
+#endif
+ fclose(cookie.fp);
+ vim_free(cookie.nextline);
+ vim_free(firstline);
+ convert_setup(&cookie.conv, NULL, NULL);
+
+ if (trigger_source_post)
+ apply_autocmds(EVENT_SOURCEPOST, fname_exp, fname_exp, FALSE, curbuf);
+
+theend:
+ vim_free(fname_exp);
+ return retval;
+}
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+
+/*
+ * ":scriptnames"
+ */
+ void
+ex_scriptnames(exarg_T *eap)
+{
+ int i;
+
+ if (eap->addr_count > 0)
+ {
+ // :script {scriptId}: edit the script
+ if (eap->line2 < 1 || eap->line2 > script_items.ga_len)
+ emsg(_(e_invarg));
+ else
+ {
+ eap->arg = SCRIPT_ITEM(eap->line2).sn_name;
+ do_exedit(eap, NULL);
+ }
+ return;
+ }
+
+ for (i = 1; i <= script_items.ga_len && !got_int; ++i)
+ if (SCRIPT_ITEM(i).sn_name != NULL)
+ {
+ home_replace(NULL, SCRIPT_ITEM(i).sn_name,
+ NameBuff, MAXPATHL, TRUE);
+ smsg("%3d: %s", i, NameBuff);
+ }
+}
+
+# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
+/*
+ * Fix slashes in the list of script names for 'shellslash'.
+ */
+ void
+scriptnames_slash_adjust(void)
+{
+ int i;
+
+ for (i = 1; i <= script_items.ga_len; ++i)
+ if (SCRIPT_ITEM(i).sn_name != NULL)
+ slash_adjust(SCRIPT_ITEM(i).sn_name);
+}
+# endif
+
+/*
+ * Get a pointer to a script name. Used for ":verbose set".
+ */
+ char_u *
+get_scriptname(scid_T id)
+{
+ if (id == SID_MODELINE)
+ return (char_u *)_("modeline");
+ if (id == SID_CMDARG)
+ return (char_u *)_("--cmd argument");
+ if (id == SID_CARG)
+ return (char_u *)_("-c argument");
+ if (id == SID_ENV)
+ return (char_u *)_("environment variable");
+ if (id == SID_ERROR)
+ return (char_u *)_("error handler");
+ return SCRIPT_ITEM(id).sn_name;
+}
+
+# if defined(EXITFREE) || defined(PROTO)
+ void
+free_scriptnames(void)
+{
+ int i;
+
+ for (i = script_items.ga_len; i > 0; --i)
+ vim_free(SCRIPT_ITEM(i).sn_name);
+ ga_clear(&script_items);
+}
+# endif
+
+#endif
+
+#if defined(USE_CR) || defined(PROTO)
+
+# if defined(__MSL__) && (__MSL__ >= 22)
+/*
+ * Newer version of the Metrowerks library handle DOS and UNIX files
+ * without help.
+ * Test with earlier versions, MSL 2.2 is the library supplied with
+ * Codewarrior Pro 2.
+ */
+ char *
+fgets_cr(char *s, int n, FILE *stream)
+{
+ return fgets(s, n, stream);
+}
+# else
+/*
+ * Version of fgets() which also works for lines ending in a <CR> only
+ * (Macintosh format).
+ * For older versions of the Metrowerks library.
+ * At least CodeWarrior 9 needed this code.
+ */
+ char *
+fgets_cr(char *s, int n, FILE *stream)
+{
+ int c = 0;
+ int char_read = 0;
+
+ while (!feof(stream) && c != '\r' && c != '\n' && char_read < n - 1)
+ {
+ c = fgetc(stream);
+ s[char_read++] = c;
+ /* If the file is in DOS format, we need to skip a NL after a CR. I
+ * thought it was the other way around, but this appears to work... */
+ if (c == '\n')
+ {
+ c = fgetc(stream);
+ if (c != '\r')
+ ungetc(c, stream);
+ }
+ }
+
+ s[char_read] = 0;
+ if (char_read == 0)
+ return NULL;
+
+ if (feof(stream) && char_read == 1)
+ return NULL;
+
+ return s;
+}
+# endif
+#endif
+
+/*
+ * Get one full line from a sourced file.
+ * Called by do_cmdline() when it's called from do_source().
+ *
+ * Return a pointer to the line in allocated memory.
+ * Return NULL for end-of-file or some error.
+ */
+ char_u *
+getsourceline(int c UNUSED, void *cookie, int indent UNUSED)
+{
+ struct source_cookie *sp = (struct source_cookie *)cookie;
+ char_u *line;
+ char_u *p;
+
+#ifdef FEAT_EVAL
+ /* If breakpoints have been added/deleted need to check for it. */
+ if (sp->dbg_tick < debug_tick)
+ {
+ sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
+ sp->dbg_tick = debug_tick;
+ }
+# ifdef FEAT_PROFILE
+ if (do_profiling == PROF_YES)
+ script_line_end();
+# endif
+#endif
+ /*
+ * Get current line. If there is a read-ahead line, use it, otherwise get
+ * one now.
+ */
+ if (sp->finished)
+ line = NULL;
+ else if (sp->nextline == NULL)
+ line = get_one_sourceline(sp);
+ else
+ {
+ line = sp->nextline;
+ sp->nextline = NULL;
+ ++sourcing_lnum;
+ }
+#ifdef FEAT_PROFILE
+ if (line != NULL && do_profiling == PROF_YES)
+ script_line_start();
+#endif
+
+ /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
+ * contain the 'C' flag. */
+ if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
+ {
+ /* compensate for the one line read-ahead */
+ --sourcing_lnum;
+
+ // Get the next line and concatenate it when it starts with a
+ // backslash. We always need to read the next line, keep it in
+ // sp->nextline.
+ /* Also check for a comment in between continuation lines: "\ */
+ sp->nextline = get_one_sourceline(sp);
+ if (sp->nextline != NULL
+ && (*(p = skipwhite(sp->nextline)) == '\\'
+ || (p[0] == '"' && p[1] == '\\' && p[2] == ' ')))
+ {
+ garray_T ga;
+
+ ga_init2(&ga, (int)sizeof(char_u), 400);
+ ga_concat(&ga, line);
+ if (*p == '\\')
+ ga_concat(&ga, p + 1);
+ for (;;)
+ {
+ vim_free(sp->nextline);
+ sp->nextline = get_one_sourceline(sp);
+ if (sp->nextline == NULL)
+ break;
+ p = skipwhite(sp->nextline);
+ if (*p == '\\')
+ {
+ // Adjust the growsize to the current length to speed up
+ // concatenating many lines.
+ if (ga.ga_len > 400)
+ {
+ if (ga.ga_len > 8000)
+ ga.ga_growsize = 8000;
+ else
+ ga.ga_growsize = ga.ga_len;
+ }
+ ga_concat(&ga, p + 1);
+ }
+ else if (p[0] != '"' || p[1] != '\\' || p[2] != ' ')
+ break;
+ }
+ ga_append(&ga, NUL);
+ vim_free(line);
+ line = ga.ga_data;
+ }
+ }
+
+ if (line != NULL && sp->conv.vc_type != CONV_NONE)
+ {
+ char_u *s;
+
+ /* Convert the encoding of the script line. */
+ s = string_convert(&sp->conv, line, NULL);
+ if (s != NULL)
+ {
+ vim_free(line);
+ line = s;
+ }
+ }
+
+#ifdef FEAT_EVAL
+ /* Did we encounter a breakpoint? */
+ if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
+ {
+ dbg_breakpoint(sp->fname, sourcing_lnum);
+ /* Find next breakpoint. */
+ sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
+ sp->dbg_tick = debug_tick;
+ }
+#endif
+
+ return line;
+}
+
+ static char_u *
+get_one_sourceline(struct source_cookie *sp)
+{
+ garray_T ga;
+ int len;
+ int c;
+ char_u *buf;
+#ifdef USE_CRNL
+ int has_cr; /* CR-LF found */
+#endif
+#ifdef USE_CR
+ char_u *scan;
+#endif
+ int have_read = FALSE;
+
+ /* use a growarray to store the sourced line */
+ ga_init2(&ga, 1, 250);
+
+ /*
+ * Loop until there is a finished line (or end-of-file).
+ */
+ sourcing_lnum++;
+ for (;;)
+ {
+ /* make room to read at least 120 (more) characters */
+ if (ga_grow(&ga, 120) == FAIL)
+ break;
+ buf = (char_u *)ga.ga_data;
+
+#ifdef USE_CR
+ if (sp->fileformat == EOL_MAC)
+ {
+ if (fgets_cr((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
+ sp->fp) == NULL)
+ break;
+ }
+ else
+#endif
+ if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
+ sp->fp) == NULL)
+ break;
+ len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
+#ifdef USE_CRNL
+ /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
+ * CTRL-Z by its own, or after a NL. */
+ if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
+ && sp->fileformat == EOL_DOS
+ && buf[len - 1] == Ctrl_Z)
+ {
+ buf[len - 1] = NUL;
+ break;
+ }
+#endif
+
+#ifdef USE_CR
+ /* If the read doesn't stop on a new line, and there's
+ * some CR then we assume a Mac format */
+ if (sp->fileformat == EOL_UNKNOWN)
+ {
+ if (buf[len - 1] != '\n' && vim_strchr(buf, '\r') != NULL)
+ sp->fileformat = EOL_MAC;
+ else
+ sp->fileformat = EOL_UNIX;
+ }
+
+ if (sp->fileformat == EOL_MAC)
+ {
+ scan = vim_strchr(buf, '\r');
+
+ if (scan != NULL)
+ {
+ *scan = '\n';
+ if (*(scan + 1) != 0)
+ {
+ *(scan + 1) = 0;
+ fseek(sp->fp, (long)(scan - buf - len + 1), SEEK_CUR);
+ }
+ }
+ len = STRLEN(buf);
+ }
+#endif
+
+ have_read = TRUE;
+ ga.ga_len = len;
+
+ /* If the line was longer than the buffer, read more. */
+ if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
+ continue;
+
+ if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
+ {
+#ifdef USE_CRNL
+ has_cr = (len >= 2 && buf[len - 2] == '\r');
+ if (sp->fileformat == EOL_UNKNOWN)
+ {
+ if (has_cr)
+ sp->fileformat = EOL_DOS;
+ else
+ sp->fileformat = EOL_UNIX;
+ }
+
+ if (sp->fileformat == EOL_DOS)
+ {
+ if (has_cr) /* replace trailing CR */
+ {
+ buf[len - 2] = '\n';
+ --len;
+ --ga.ga_len;
+ }
+ else /* lines like ":map xx yy^M" will have failed */
+ {
+ if (!sp->error)
+ {
+ msg_source(HL_ATTR(HLF_W));
+ emsg(_("W15: Warning: Wrong line separator, ^M may be missing"));
+ }
+ sp->error = TRUE;
+ sp->fileformat = EOL_UNIX;
+ }
+ }
+#endif
+ /* The '\n' is escaped if there is an odd number of ^V's just
+ * before it, first set "c" just before the 'V's and then check
+ * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
+ for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
+ ;
+ if ((len & 1) != (c & 1)) /* escaped NL, read more */
+ {
+ sourcing_lnum++;
+ continue;
+ }
+
+ buf[len - 1] = NUL; /* remove the NL */
+ }
+
+ /*
+ * Check for ^C here now and then, so recursive :so can be broken.
+ */
+ line_breakcheck();
+ break;
+ }
+
+ if (have_read)
+ return (char_u *)ga.ga_data;
+
+ vim_free(ga.ga_data);
+ return NULL;
+}
+
+#if defined(FEAT_PROFILE) || defined(PROTO)
+/*
+ * Called when starting to read a script line.
+ * "sourcing_lnum" must be correct!
+ * When skipping lines it may not actually be executed, but we won't find out
+ * until later and we need to store the time now.
+ */
+ void
+script_line_start(void)
+{
+ scriptitem_T *si;
+ sn_prl_T *pp;
+
+ if (current_sctx.sc_sid <= 0 || current_sctx.sc_sid > script_items.ga_len)
+ return;
+ si = &SCRIPT_ITEM(current_sctx.sc_sid);
+ if (si->sn_prof_on && sourcing_lnum >= 1)
+ {
+ /* Grow the array before starting the timer, so that the time spent
+ * here isn't counted. */
+ (void)ga_grow(&si->sn_prl_ga,
+ (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
+ si->sn_prl_idx = sourcing_lnum - 1;
+ while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
+ && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
+ {
+ /* Zero counters for a line that was not used before. */
+ pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
+ pp->snp_count = 0;
+ profile_zero(&pp->sn_prl_total);
+ profile_zero(&pp->sn_prl_self);
+ ++si->sn_prl_ga.ga_len;
+ }
+ si->sn_prl_execed = FALSE;
+ profile_start(&si->sn_prl_start);
+ profile_zero(&si->sn_prl_children);
+ profile_get_wait(&si->sn_prl_wait);
+ }
+}
+
+/*
+ * Called when actually executing a function line.
+ */
+ void
+script_line_exec(void)
+{
+ scriptitem_T *si;
+
+ if (current_sctx.sc_sid <= 0 || current_sctx.sc_sid > script_items.ga_len)
+ return;
+ si = &SCRIPT_ITEM(current_sctx.sc_sid);
+ if (si->sn_prof_on && si->sn_prl_idx >= 0)
+ si->sn_prl_execed = TRUE;
+}
+
+/*
+ * Called when done with a script line.
+ */
+ void
+script_line_end(void)
+{
+ scriptitem_T *si;
+ sn_prl_T *pp;
+
+ if (current_sctx.sc_sid <= 0 || current_sctx.sc_sid > script_items.ga_len)
+ return;
+ si = &SCRIPT_ITEM(current_sctx.sc_sid);
+ if (si->sn_prof_on && si->sn_prl_idx >= 0
+ && si->sn_prl_idx < si->sn_prl_ga.ga_len)
+ {
+ if (si->sn_prl_execed)
+ {
+ pp = &PRL_ITEM(si, si->sn_prl_idx);
+ ++pp->snp_count;
+ profile_end(&si->sn_prl_start);
+ profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
+ profile_add(&pp->sn_prl_total, &si->sn_prl_start);
+ profile_self(&pp->sn_prl_self, &si->sn_prl_start,
+ &si->sn_prl_children);
+ }
+ si->sn_prl_idx = -1;
+ }
+}
+#endif
+
+/*
+ * ":scriptencoding": Set encoding conversion for a sourced script.
+ * Without the multi-byte feature it's simply ignored.
+ */
+ void
+ex_scriptencoding(exarg_T *eap UNUSED)
+{
+ struct source_cookie *sp;
+ char_u *name;
+
+ if (!getline_equal(eap->getline, eap->cookie, getsourceline))
+ {
+ emsg(_("E167: :scriptencoding used outside of a sourced file"));
+ return;
+ }
+
+ if (*eap->arg != NUL)
+ {
+ name = enc_canonize(eap->arg);
+ if (name == NULL) /* out of memory */
+ return;
+ }
+ else
+ name = eap->arg;
+
+ /* Setup for conversion from the specified encoding to 'encoding'. */
+ sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
+ convert_setup(&sp->conv, name, p_enc);
+
+ if (name != eap->arg)
+ vim_free(name);
+}
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * ":finish": Mark a sourced file as finished.
+ */
+ void
+ex_finish(exarg_T *eap)
+{
+ if (getline_equal(eap->getline, eap->cookie, getsourceline))
+ do_finish(eap, FALSE);
+ else
+ emsg(_("E168: :finish used outside of a sourced file"));
+}
+
+/*
+ * Mark a sourced file as finished. Possibly makes the ":finish" pending.
+ * Also called for a pending finish at the ":endtry" or after returning from
+ * an extra do_cmdline(). "reanimate" is used in the latter case.
+ */
+ void
+do_finish(exarg_T *eap, int reanimate)
+{
+ int idx;
+
+ if (reanimate)
+ ((struct source_cookie *)getline_cookie(eap->getline,
+ eap->cookie))->finished = FALSE;
+
+ /*
+ * Cleanup (and inactivate) conditionals, but stop when a try conditional
+ * not in its finally clause (which then is to be executed next) is found.
+ * In this case, make the ":finish" pending for execution at the ":endtry".
+ * Otherwise, finish normally.
+ */
+ idx = cleanup_conditionals(eap->cstack, 0, TRUE);
+ if (idx >= 0)
+ {
+ eap->cstack->cs_pending[idx] = CSTP_FINISH;
+ report_make_pending(CSTP_FINISH, NULL);
+ }
+ else
+ ((struct source_cookie *)getline_cookie(eap->getline,
+ eap->cookie))->finished = TRUE;
+}
+
+
+/*
+ * Return TRUE when a sourced file had the ":finish" command: Don't give error
+ * message for missing ":endif".
+ * Return FALSE when not sourcing a file.
+ */
+ int
+source_finished(
+ char_u *(*fgetline)(int, void *, int),
+ void *cookie)
+{
+ return (getline_equal(fgetline, cookie, getsourceline)
+ && ((struct source_cookie *)getline_cookie(
+ fgetline, cookie))->finished);
+}
+#endif
+
+/*
+ * ":checktime [buffer]"
+ */
+ void
+ex_checktime(exarg_T *eap)
+{
+ buf_T *buf;
+ int save_no_check_timestamps = no_check_timestamps;
+
+ no_check_timestamps = 0;
+ if (eap->addr_count == 0) /* default is all buffers */
+ check_timestamps(FALSE);
+ else
+ {
+ buf = buflist_findnr((int)eap->line2);
+ if (buf != NULL) /* cannot happen? */
+ (void)buf_check_timestamp(buf, FALSE);
+ }
+ no_check_timestamps = save_no_check_timestamps;
+}
+
+#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
+ && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
+# define HAVE_GET_LOCALE_VAL
+ static char_u *
+get_locale_val(int what)
+{
+ char_u *loc;
+
+ /* Obtain the locale value from the libraries. */
+ loc = (char_u *)setlocale(what, NULL);
+
+# ifdef WIN32
+ if (loc != NULL)
+ {
+ char_u *p;
+
+ /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
+ * one of the values (e.g., LC_CTYPE) differs. */
+ p = vim_strchr(loc, '=');
+ if (p != NULL)
+ {
+ loc = ++p;
+ while (*p != NUL) /* remove trailing newline */
+ {
+ if (*p < ' ' || *p == ';')
+ {
+ *p = NUL;
+ break;
+ }
+ ++p;
+ }
+ }
+ }
+# endif
+
+ return loc;
+}
+#endif
+
+
+#ifdef WIN32
+/*
+ * On MS-Windows locale names are strings like "German_Germany.1252", but
+ * gettext expects "de". Try to translate one into another here for a few
+ * supported languages.
+ */
+ static char_u *
+gettext_lang(char_u *name)
+{
+ int i;
+ static char *(mtable[]) = {
+ "afrikaans", "af",
+ "czech", "cs",
+ "dutch", "nl",
+ "german", "de",
+ "english_united kingdom", "en_GB",
+ "spanish", "es",
+ "french", "fr",
+ "italian", "it",
+ "japanese", "ja",
+ "korean", "ko",
+ "norwegian", "no",
+ "polish", "pl",
+ "russian", "ru",
+ "slovak", "sk",
+ "swedish", "sv",
+ "ukrainian", "uk",
+ "chinese_china", "zh_CN",
+ "chinese_taiwan", "zh_TW",
+ NULL};
+
+ for (i = 0; mtable[i] != NULL; i += 2)
+ if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
+ return (char_u *)mtable[i + 1];
+ return name;
+}
+#endif
+
+#if defined(FEAT_MULTI_LANG) || defined(PROTO)
+/*
+ * Return TRUE when "lang" starts with a valid language name.
+ * Rejects NULL, empty string, "C", "C.UTF-8" and others.
+ */
+ static int
+is_valid_mess_lang(char_u *lang)
+{
+ return lang != NULL && ASCII_ISALPHA(lang[0]) && ASCII_ISALPHA(lang[1]);
+}
+
+/*
+ * Obtain the current messages language. Used to set the default for
+ * 'helplang'. May return NULL or an empty string.
+ */
+ char_u *
+get_mess_lang(void)
+{
+ char_u *p;
+
+# ifdef HAVE_GET_LOCALE_VAL
+# if defined(LC_MESSAGES)
+ p = get_locale_val(LC_MESSAGES);
+# else
+ /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
+ * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
+ * and LC_MONETARY may be set differently for a Japanese working in the
+ * US. */
+ p = get_locale_val(LC_COLLATE);
+# endif
+# else
+ p = mch_getenv((char_u *)"LC_ALL");
+ if (!is_valid_mess_lang(p))
+ {
+ p = mch_getenv((char_u *)"LC_MESSAGES");
+ if (!is_valid_mess_lang(p))
+ p = mch_getenv((char_u *)"LANG");
+ }
+# endif
+# ifdef WIN32
+ p = gettext_lang(p);
+# endif
+ return is_valid_mess_lang(p) ? p : NULL;
+}
+#endif
+
+/* Complicated #if; matches with where get_mess_env() is used below. */
+#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
+ && defined(LC_MESSAGES))) \
+ || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
+ && !defined(LC_MESSAGES))
+/*
+ * Get the language used for messages from the environment.
+ */
+ static char_u *
+get_mess_env(void)
+{
+ char_u *p;
+
+ p = mch_getenv((char_u *)"LC_ALL");
+ if (p == NULL || *p == NUL)
+ {
+ p = mch_getenv((char_u *)"LC_MESSAGES");
+ if (p == NULL || *p == NUL)
+ {
+ p = mch_getenv((char_u *)"LANG");
+ if (p != NULL && VIM_ISDIGIT(*p))
+ p = NULL; /* ignore something like "1043" */
+# ifdef HAVE_GET_LOCALE_VAL
+ if (p == NULL || *p == NUL)
+ p = get_locale_val(LC_CTYPE);
+# endif
+ }
+ }
+ return p;
+}
+#endif
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+
+/*
+ * Set the "v:lang" variable according to the current locale setting.
+ * Also do "v:lc_time"and "v:ctype".
+ */
+ void
+set_lang_var(void)
+{
+ char_u *loc;
+
+# ifdef HAVE_GET_LOCALE_VAL
+ loc = get_locale_val(LC_CTYPE);
+# else
+ /* setlocale() not supported: use the default value */
+ loc = (char_u *)"C";
+# endif
+ set_vim_var_string(VV_CTYPE, loc, -1);
+
+ /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
+ * back to LC_CTYPE if it's empty. */
+# if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES)
+ loc = get_locale_val(LC_MESSAGES);
+# else
+ loc = get_mess_env();
+# endif
+ set_vim_var_string(VV_LANG, loc, -1);
+
+# ifdef HAVE_GET_LOCALE_VAL
+ loc = get_locale_val(LC_TIME);
+# endif
+ set_vim_var_string(VV_LC_TIME, loc, -1);
+}
+#endif
+
+#if defined(HAVE_LOCALE_H) || defined(X_LOCALE) \
+/*
+ * ":language": Set the language (locale).
+ */
+ void
+ex_language(exarg_T *eap)
+{
+ char *loc;
+ char_u *p;
+ char_u *name;
+ int what = LC_ALL;
+ char *whatstr = "";
+#ifdef LC_MESSAGES
+# define VIM_LC_MESSAGES LC_MESSAGES
+#else
+# define VIM_LC_MESSAGES 6789
+#endif
+
+ name = eap->arg;
+
+ /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
+ * Allow abbreviation, but require at least 3 characters to avoid
+ * confusion with a two letter language name "me" or "ct". */
+ p = skiptowhite(eap->arg);
+ if ((*p == NUL || VIM_ISWHITE(*p)) && p - eap->arg >= 3)
+ {
+ if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
+ {
+ what = VIM_LC_MESSAGES;
+ name = skipwhite(p);
+ whatstr = "messages ";
+ }
+ else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
+ {
+ what = LC_CTYPE;
+ name = skipwhite(p);
+ whatstr = "ctype ";
+ }
+ else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
+ {
+ what = LC_TIME;
+ name = skipwhite(p);
+ whatstr = "time ";
+ }
+ }
+
+ if (*name == NUL)
+ {
+#ifndef LC_MESSAGES
+ if (what == VIM_LC_MESSAGES)
+ p = get_mess_env();
+ else
+#endif
+ p = (char_u *)setlocale(what, NULL);
+ if (p == NULL || *p == NUL)
+ p = (char_u *)"Unknown";
+ smsg(_("Current %slanguage: \"%s\""), whatstr, p);
+ }
+ else
+ {
+#ifndef LC_MESSAGES
+ if (what == VIM_LC_MESSAGES)
+ loc = "";
+ else
+#endif
+ {
+ loc = setlocale(what, (char *)name);
+#if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
+ /* Make sure strtod() uses a decimal point, not a comma. */
+ setlocale(LC_NUMERIC, "C");
+#endif
+ }
+ if (loc == NULL)
+ semsg(_("E197: Cannot set language to \"%s\""), name);
+ else
+ {
+#ifdef HAVE_NL_MSG_CAT_CNTR
+ /* Need to do this for GNU gettext, otherwise cached translations
+ * will be used again. */
+ extern int _nl_msg_cat_cntr;
+
+ ++_nl_msg_cat_cntr;
+#endif
+ /* Reset $LC_ALL, otherwise it would overrule everything. */
+ vim_setenv((char_u *)"LC_ALL", (char_u *)"");
+
+ if (what != LC_TIME)
+ {
+ /* Tell gettext() what to translate to. It apparently doesn't
+ * use the currently effective locale. Also do this when
+ * FEAT_GETTEXT isn't defined, so that shell commands use this
+ * value. */
+ if (what == LC_ALL)
+ {
+ vim_setenv((char_u *)"LANG", name);
+
+ /* Clear $LANGUAGE because GNU gettext uses it. */
+ vim_setenv((char_u *)"LANGUAGE", (char_u *)"");
+# ifdef WIN32
+ /* Apparently MS-Windows printf() may cause a crash when
+ * we give it 8-bit text while it's expecting text in the
+ * current locale. This call avoids that. */
+ setlocale(LC_CTYPE, "C");
+# endif
+ }
+ if (what != LC_CTYPE)
+ {
+ char_u *mname;
+#ifdef WIN32
+ mname = gettext_lang(name);
+#else
+ mname = name;
+#endif
+ vim_setenv((char_u *)"LC_MESSAGES", mname);
+#ifdef FEAT_MULTI_LANG
+ set_helplang_default(mname);
+#endif
+ }
+ }
+
+# ifdef FEAT_EVAL
+ /* Set v:lang, v:lc_time and v:ctype to the final result. */
+ set_lang_var();
+# endif
+# ifdef FEAT_TITLE
+ maketitle();
+# endif
+ }
+ }
+}
+
+# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
+
+static char_u **locales = NULL; /* Array of all available locales */
+
+# ifndef WIN32
+static int did_init_locales = FALSE;
+
+/* Return an array of strings for all available locales + NULL for the
+ * last element. Return NULL in case of error. */
+ static char_u **
+find_locales(void)
+{
+ garray_T locales_ga;
+ char_u *loc;
+
+ /* Find all available locales by running command "locale -a". If this
+ * doesn't work we won't have completion. */
+ char_u *locale_a = get_cmd_output((char_u *)"locale -a",
+ NULL, SHELL_SILENT, NULL);
+ if (locale_a == NULL)
+ return NULL;
+ ga_init2(&locales_ga, sizeof(char_u *), 20);
+
+ /* Transform locale_a string where each locale is separated by "\n"
+ * into an array of locale strings. */
+ loc = (char_u *)strtok((char *)locale_a, "\n");
+
+ while (loc != NULL)
+ {
+ if (ga_grow(&locales_ga, 1) == FAIL)
+ break;
+ loc = vim_strsave(loc);
+ if (loc == NULL)
+ break;
+
+ ((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] = loc;
+ loc = (char_u *)strtok(NULL, "\n");
+ }
+ vim_free(locale_a);
+ if (ga_grow(&locales_ga, 1) == FAIL)
+ {
+ ga_clear(&locales_ga);
+ return NULL;
+ }
+ ((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL;
+ return (char_u **)locales_ga.ga_data;
+}
+# endif
+
+/*
+ * Lazy initialization of all available locales.
+ */
+ static void
+init_locales(void)
+{
+# ifndef WIN32
+ if (!did_init_locales)
+ {
+ did_init_locales = TRUE;
+ locales = find_locales();
+ }
+# endif
+}
+
+# if defined(EXITFREE) || defined(PROTO)
+ void
+free_locales(void)
+{
+ int i;
+ if (locales != NULL)
+ {
+ for (i = 0; locales[i] != NULL; i++)
+ vim_free(locales[i]);
+ VIM_CLEAR(locales);
+ }
+}
+# endif
+
+/*
+ * Function given to ExpandGeneric() to obtain the possible arguments of the
+ * ":language" command.
+ */
+ char_u *
+get_lang_arg(expand_T *xp UNUSED, int idx)
+{
+ if (idx == 0)
+ return (char_u *)"messages";
+ if (idx == 1)
+ return (char_u *)"ctype";
+ if (idx == 2)
+ return (char_u *)"time";
+
+ init_locales();
+ if (locales == NULL)
+ return NULL;
+ return locales[idx - 3];
+}
+
+/*
+ * Function given to ExpandGeneric() to obtain the available locales.
+ */
+ char_u *
+get_locales(expand_T *xp UNUSED, int idx)
+{
+ init_locales();
+ if (locales == NULL)
+ return NULL;
+ return locales[idx];
+}
+# endif
+
+#endif
diff --git a/src/ex_docmd.c b/src/ex_docmd.c
new file mode 100644
index 0000000..b90ea7b
--- /dev/null
+++ b/src/ex_docmd.c
@@ -0,0 +1,12587 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * ex_docmd.c: functions for executing an Ex command line.
+ */
+
+#include "vim.h"
+
+static int quitmore = 0;
+static int ex_pressedreturn = FALSE;
+#ifndef FEAT_PRINTER
+# define ex_hardcopy ex_ni
+#endif
+
+#ifdef FEAT_USR_CMDS
+typedef struct ucmd
+{
+ char_u *uc_name; /* The command name */
+ long_u uc_argt; /* The argument type */
+ char_u *uc_rep; /* The command's replacement string */
+ long uc_def; /* The default value for a range/count */
+ int uc_compl; /* completion type */
+ int uc_addr_type; /* The command's address type */
+# ifdef FEAT_EVAL
+ sctx_T uc_script_ctx; /* SCTX where the command was defined */
+# ifdef FEAT_CMDL_COMPL
+ char_u *uc_compl_arg; /* completion argument if any */
+# endif
+# endif
+} ucmd_T;
+
+#define UC_BUFFER 1 /* -buffer: local to current buffer */
+
+static garray_T ucmds = {0, 0, sizeof(ucmd_T), 4, NULL};
+
+#define USER_CMD(i) (&((ucmd_T *)(ucmds.ga_data))[i])
+#define USER_CMD_GA(gap, i) (&((ucmd_T *)((gap)->ga_data))[i])
+
+static void do_ucmd(exarg_T *eap);
+static void ex_command(exarg_T *eap);
+static void ex_delcommand(exarg_T *eap);
+# ifdef FEAT_CMDL_COMPL
+static char_u *get_user_command_name(int idx);
+# endif
+
+/* Wether a command index indicates a user command. */
+# define IS_USER_CMDIDX(idx) ((int)(idx) < 0)
+
+#else
+# define ex_command ex_ni
+# define ex_comclear ex_ni
+# define ex_delcommand ex_ni
+/* Wether a command index indicates a user command. */
+# define IS_USER_CMDIDX(idx) (FALSE)
+#endif
+
+#ifdef FEAT_EVAL
+static char_u *do_one_cmd(char_u **, int, struct condstack *, char_u *(*fgetline)(int, void *, int), void *cookie);
+#else
+static char_u *do_one_cmd(char_u **, int, char_u *(*fgetline)(int, void *, int), void *cookie);
+static int if_level = 0; /* depth in :if */
+#endif
+static void free_cmdmod(void);
+static void append_command(char_u *cmd);
+static char_u *find_command(exarg_T *eap, int *full);
+
+static void ex_abbreviate(exarg_T *eap);
+static void ex_map(exarg_T *eap);
+static void ex_unmap(exarg_T *eap);
+static void ex_mapclear(exarg_T *eap);
+static void ex_abclear(exarg_T *eap);
+#ifndef FEAT_MENU
+# define ex_emenu ex_ni
+# define ex_menu ex_ni
+# define ex_menutranslate ex_ni
+#endif
+static void ex_autocmd(exarg_T *eap);
+static void ex_doautocmd(exarg_T *eap);
+static void ex_bunload(exarg_T *eap);
+static void ex_buffer(exarg_T *eap);
+static void ex_bmodified(exarg_T *eap);
+static void ex_bnext(exarg_T *eap);
+static void ex_bprevious(exarg_T *eap);
+static void ex_brewind(exarg_T *eap);
+static void ex_blast(exarg_T *eap);
+static char_u *getargcmd(char_u **);
+static char_u *skip_cmd_arg(char_u *p, int rembs);
+static int getargopt(exarg_T *eap);
+#ifndef FEAT_QUICKFIX
+# define ex_make ex_ni
+# define ex_cbuffer ex_ni
+# define ex_cc ex_ni
+# define ex_cnext ex_ni
+# define ex_cfile ex_ni
+# define qf_list ex_ni
+# define qf_age ex_ni
+# define qf_history ex_ni
+# define ex_helpgrep ex_ni
+# define ex_vimgrep ex_ni
+#endif
+#if !defined(FEAT_QUICKFIX)
+# define ex_cclose ex_ni
+# define ex_copen ex_ni
+# define ex_cwindow ex_ni
+# define ex_cbottom ex_ni
+#endif
+#if !defined(FEAT_QUICKFIX) || !defined(FEAT_EVAL)
+# define ex_cexpr ex_ni
+#endif
+
+static linenr_T get_address(exarg_T *, char_u **, int addr_type, int skip, int silent, int to_other_file, int address_count);
+static void get_flags(exarg_T *eap);
+#if !defined(FEAT_PERL) \
+ || !defined(FEAT_PYTHON) || !defined(FEAT_PYTHON3) \
+ || !defined(FEAT_TCL) \
+ || !defined(FEAT_RUBY) \
+ || !defined(FEAT_LUA) \
+ || !defined(FEAT_MZSCHEME)
+# define HAVE_EX_SCRIPT_NI
+static void ex_script_ni(exarg_T *eap);
+#endif
+static char *invalid_range(exarg_T *eap);
+static void correct_range(exarg_T *eap);
+#ifdef FEAT_QUICKFIX
+static char_u *replace_makeprg(exarg_T *eap, char_u *p, char_u **cmdlinep);
+#endif
+static char_u *repl_cmdline(exarg_T *eap, char_u *src, int srclen, char_u *repl, char_u **cmdlinep);
+static void ex_highlight(exarg_T *eap);
+static void ex_colorscheme(exarg_T *eap);
+static void ex_quit(exarg_T *eap);
+static void ex_cquit(exarg_T *eap);
+static void ex_quit_all(exarg_T *eap);
+static void ex_close(exarg_T *eap);
+static void ex_win_close(int forceit, win_T *win, tabpage_T *tp);
+static void ex_only(exarg_T *eap);
+static void ex_resize(exarg_T *eap);
+static void ex_stag(exarg_T *eap);
+static void ex_tabclose(exarg_T *eap);
+static void ex_tabonly(exarg_T *eap);
+static void ex_tabnext(exarg_T *eap);
+static void ex_tabmove(exarg_T *eap);
+static void ex_tabs(exarg_T *eap);
+#if defined(FEAT_QUICKFIX)
+static void ex_pclose(exarg_T *eap);
+static void ex_ptag(exarg_T *eap);
+static void ex_pedit(exarg_T *eap);
+#else
+# define ex_pclose ex_ni
+# define ex_ptag ex_ni
+# define ex_pedit ex_ni
+#endif
+static void ex_hide(exarg_T *eap);
+static void ex_stop(exarg_T *eap);
+static void ex_exit(exarg_T *eap);
+static void ex_print(exarg_T *eap);
+#ifdef FEAT_BYTEOFF
+static void ex_goto(exarg_T *eap);
+#else
+# define ex_goto ex_ni
+#endif
+static void ex_shell(exarg_T *eap);
+static void ex_preserve(exarg_T *eap);
+static void ex_recover(exarg_T *eap);
+static void ex_mode(exarg_T *eap);
+static void ex_wrongmodifier(exarg_T *eap);
+static void ex_find(exarg_T *eap);
+static void ex_open(exarg_T *eap);
+static void ex_edit(exarg_T *eap);
+#ifndef FEAT_GUI
+# define ex_gui ex_nogui
+static void ex_nogui(exarg_T *eap);
+#endif
+#if defined(FEAT_GUI_W32) && defined(FEAT_MENU) && defined(FEAT_TEAROFF)
+static void ex_tearoff(exarg_T *eap);
+#else
+# define ex_tearoff ex_ni
+#endif
+#if (defined(FEAT_GUI_MSWIN) || defined(FEAT_GUI_GTK) \
+ || defined(FEAT_TERM_POPUP_MENU)) && defined(FEAT_MENU)
+static void ex_popup(exarg_T *eap);
+#else
+# define ex_popup ex_ni
+#endif
+#ifndef FEAT_GUI_MSWIN
+# define ex_simalt ex_ni
+#endif
+#if !defined(FEAT_GUI_MSWIN) && !defined(FEAT_GUI_GTK) && !defined(FEAT_GUI_MOTIF)
+# define gui_mch_find_dialog ex_ni
+# define gui_mch_replace_dialog ex_ni
+#endif
+#if !defined(FEAT_GUI_GTK)
+# define ex_helpfind ex_ni
+#endif
+#ifndef FEAT_CSCOPE
+# define ex_cscope ex_ni
+# define ex_scscope ex_ni
+# define ex_cstag ex_ni
+#endif
+#ifndef FEAT_SYN_HL
+# define ex_syntax ex_ni
+# define ex_ownsyntax ex_ni
+#endif
+#ifndef FEAT_EVAL
+# define ex_packadd ex_ni
+# define ex_packloadall ex_ni
+#endif
+#if !defined(FEAT_SYN_HL) || !defined(FEAT_PROFILE)
+# define ex_syntime ex_ni
+#endif
+#ifndef FEAT_SPELL
+# define ex_spell ex_ni
+# define ex_mkspell ex_ni
+# define ex_spelldump ex_ni
+# define ex_spellinfo ex_ni
+# define ex_spellrepall ex_ni
+#endif
+#ifndef FEAT_PERSISTENT_UNDO
+# define ex_rundo ex_ni
+# define ex_wundo ex_ni
+#endif
+#ifndef FEAT_LUA
+# define ex_lua ex_script_ni
+# define ex_luado ex_ni
+# define ex_luafile ex_ni
+#endif
+#ifndef FEAT_MZSCHEME
+# define ex_mzscheme ex_script_ni
+# define ex_mzfile ex_ni
+#endif
+#ifndef FEAT_PERL
+# define ex_perl ex_script_ni
+# define ex_perldo ex_ni
+#endif
+#ifndef FEAT_PYTHON
+# define ex_python ex_script_ni
+# define ex_pydo ex_ni
+# define ex_pyfile ex_ni
+#endif
+#ifndef FEAT_PYTHON3
+# define ex_py3 ex_script_ni
+# define ex_py3do ex_ni
+# define ex_py3file ex_ni
+#endif
+#if !defined(FEAT_PYTHON) && !defined(FEAT_PYTHON3)
+# define ex_pyx ex_script_ni
+# define ex_pyxdo ex_ni
+# define ex_pyxfile ex_ni
+#endif
+#ifndef FEAT_TCL
+# define ex_tcl ex_script_ni
+# define ex_tcldo ex_ni
+# define ex_tclfile ex_ni
+#endif
+#ifndef FEAT_RUBY
+# define ex_ruby ex_script_ni
+# define ex_rubydo ex_ni
+# define ex_rubyfile ex_ni
+#endif
+#ifndef FEAT_KEYMAP
+# define ex_loadkeymap ex_ni
+#endif
+static void ex_swapname(exarg_T *eap);
+static void ex_syncbind(exarg_T *eap);
+static void ex_read(exarg_T *eap);
+static void ex_pwd(exarg_T *eap);
+static void ex_equal(exarg_T *eap);
+static void ex_sleep(exarg_T *eap);
+static void do_exmap(exarg_T *eap, int isabbrev);
+static void ex_winsize(exarg_T *eap);
+static void ex_wincmd(exarg_T *eap);
+#if defined(FEAT_GUI) || defined(UNIX) || defined(VMS) || defined(MSWIN)
+static void ex_winpos(exarg_T *eap);
+#else
+# define ex_winpos ex_ni
+#endif
+static void ex_operators(exarg_T *eap);
+static void ex_put(exarg_T *eap);
+static void ex_copymove(exarg_T *eap);
+static void ex_submagic(exarg_T *eap);
+static void ex_join(exarg_T *eap);
+static void ex_at(exarg_T *eap);
+static void ex_bang(exarg_T *eap);
+static void ex_undo(exarg_T *eap);
+#ifdef FEAT_PERSISTENT_UNDO
+static void ex_wundo(exarg_T *eap);
+static void ex_rundo(exarg_T *eap);
+#endif
+static void ex_redo(exarg_T *eap);
+static void ex_later(exarg_T *eap);
+static void ex_redir(exarg_T *eap);
+static void ex_redrawstatus(exarg_T *eap);
+static void ex_redrawtabline(exarg_T *eap);
+static void close_redir(void);
+static void ex_mkrc(exarg_T *eap);
+static void ex_mark(exarg_T *eap);
+#ifdef FEAT_USR_CMDS
+static char *uc_fun_cmd(void);
+static char_u *find_ucmd(exarg_T *eap, char_u *p, int *full, expand_T *xp, int *compl);
+#endif
+static void ex_startinsert(exarg_T *eap);
+static void ex_stopinsert(exarg_T *eap);
+#ifdef FEAT_FIND_ID
+static void ex_checkpath(exarg_T *eap);
+static void ex_findpat(exarg_T *eap);
+#else
+# define ex_findpat ex_ni
+# define ex_checkpath ex_ni
+#endif
+#if defined(FEAT_FIND_ID) && defined(FEAT_QUICKFIX)
+static void ex_psearch(exarg_T *eap);
+#else
+# define ex_psearch ex_ni
+#endif
+static void ex_tag(exarg_T *eap);
+static void ex_tag_cmd(exarg_T *eap, char_u *name);
+#ifndef FEAT_EVAL
+# define ex_scriptnames ex_ni
+# define ex_finish ex_ni
+# define ex_echo ex_ni
+# define ex_echohl ex_ni
+# define ex_execute ex_ni
+# define ex_call ex_ni
+# define ex_if ex_ni
+# define ex_endif ex_ni
+# define ex_else ex_ni
+# define ex_while ex_ni
+# define ex_continue ex_ni
+# define ex_break ex_ni
+# define ex_endwhile ex_ni
+# define ex_throw ex_ni
+# define ex_try ex_ni
+# define ex_catch ex_ni
+# define ex_finally ex_ni
+# define ex_endtry ex_ni
+# define ex_endfunction ex_ni
+# define ex_let ex_ni
+# define ex_unlet ex_ni
+# define ex_lockvar ex_ni
+# define ex_unlockvar ex_ni
+# define ex_function ex_ni
+# define ex_delfunction ex_ni
+# define ex_return ex_ni
+# define ex_oldfiles ex_ni
+#endif
+static char_u *arg_all(void);
+#ifdef FEAT_SESSION
+static int makeopens(FILE *fd, char_u *dirnow);
+static int put_view(FILE *fd, win_T *wp, int add_edit, unsigned *flagp, int current_arg_idx);
+static void ex_loadview(exarg_T *eap);
+static char_u *get_view_file(int c);
+static int did_lcd; /* whether ":lcd" was produced for a session */
+#else
+# define ex_loadview ex_ni
+#endif
+#ifndef FEAT_EVAL
+# define ex_compiler ex_ni
+#endif
+#ifdef FEAT_VIMINFO
+static void ex_viminfo(exarg_T *eap);
+#else
+# define ex_viminfo ex_ni
+#endif
+static void ex_behave(exarg_T *eap);
+static void ex_filetype(exarg_T *eap);
+static void ex_setfiletype(exarg_T *eap);
+#ifndef FEAT_DIFF
+# define ex_diffoff ex_ni
+# define ex_diffpatch ex_ni
+# define ex_diffgetput ex_ni
+# define ex_diffsplit ex_ni
+# define ex_diffthis ex_ni
+# define ex_diffupdate ex_ni
+#endif
+static void ex_digraphs(exarg_T *eap);
+static void ex_set(exarg_T *eap);
+#if !defined(FEAT_EVAL)
+# define ex_options ex_ni
+#endif
+#ifdef FEAT_SEARCH_EXTRA
+static void ex_nohlsearch(exarg_T *eap);
+static void ex_match(exarg_T *eap);
+#else
+# define ex_nohlsearch ex_ni
+# define ex_match ex_ni
+#endif
+#ifdef FEAT_CRYPT
+static void ex_X(exarg_T *eap);
+#else
+# define ex_X ex_ni
+#endif
+#ifdef FEAT_FOLDING
+static void ex_fold(exarg_T *eap);
+static void ex_foldopen(exarg_T *eap);
+static void ex_folddo(exarg_T *eap);
+#else
+# define ex_fold ex_ni
+# define ex_foldopen ex_ni
+# define ex_folddo ex_ni
+#endif
+#if !(defined(HAVE_LOCALE_H) || defined(X_LOCALE))
+# define ex_language ex_ni
+#endif
+#ifndef FEAT_SIGNS
+# define ex_sign ex_ni
+#endif
+#ifndef FEAT_NETBEANS_INTG
+# define ex_nbclose ex_ni
+# define ex_nbkey ex_ni
+# define ex_nbstart ex_ni
+#endif
+
+#ifndef FEAT_EVAL
+# define ex_debug ex_ni
+# define ex_breakadd ex_ni
+# define ex_debuggreedy ex_ni
+# define ex_breakdel ex_ni
+# define ex_breaklist ex_ni
+#endif
+
+#ifndef FEAT_CMDHIST
+# define ex_history ex_ni
+#endif
+#ifndef FEAT_JUMPLIST
+# define ex_jumps ex_ni
+# define ex_clearjumps ex_ni
+# define ex_changes ex_ni
+#endif
+
+#ifndef FEAT_PROFILE
+# define ex_profile ex_ni
+#endif
+#ifndef FEAT_TERMINAL
+# define ex_terminal ex_ni
+#endif
+
+/*
+ * Declare cmdnames[].
+ */
+#define DO_DECLARE_EXCMD
+#include "ex_cmds.h"
+#include "ex_cmdidxs.h"
+
+static char_u dollar_command[2] = {'$', 0};
+
+
+#ifdef FEAT_EVAL
+/* Struct for storing a line inside a while/for loop */
+typedef struct
+{
+ char_u *line; /* command line */
+ linenr_T lnum; /* sourcing_lnum of the line */
+} wcmd_T;
+
+/*
+ * Structure used to store info for line position in a while or for loop.
+ * This is required, because do_one_cmd() may invoke ex_function(), which
+ * reads more lines that may come from the while/for loop.
+ */
+struct loop_cookie
+{
+ garray_T *lines_gap; /* growarray with line info */
+ int current_line; /* last read line from growarray */
+ int repeating; /* TRUE when looping a second time */
+ /* When "repeating" is FALSE use "getline" and "cookie" to get lines */
+ char_u *(*getline)(int, void *, int);
+ void *cookie;
+};
+
+static char_u *get_loop_line(int c, void *cookie, int indent);
+static int store_loop_line(garray_T *gap, char_u *line);
+static void free_cmdlines(garray_T *gap);
+
+/* Struct to save a few things while debugging. Used in do_cmdline() only. */
+struct dbg_stuff
+{
+ int trylevel;
+ int force_abort;
+ except_T *caught_stack;
+ char_u *vv_exception;
+ char_u *vv_throwpoint;
+ int did_emsg;
+ int got_int;
+ int did_throw;
+ int need_rethrow;
+ int check_cstack;
+ except_T *current_exception;
+};
+
+ static void
+save_dbg_stuff(struct dbg_stuff *dsp)
+{
+ dsp->trylevel = trylevel; trylevel = 0;
+ dsp->force_abort = force_abort; force_abort = FALSE;
+ dsp->caught_stack = caught_stack; caught_stack = NULL;
+ dsp->vv_exception = v_exception(NULL);
+ dsp->vv_throwpoint = v_throwpoint(NULL);
+
+ /* Necessary for debugging an inactive ":catch", ":finally", ":endtry" */
+ dsp->did_emsg = did_emsg; did_emsg = FALSE;
+ dsp->got_int = got_int; got_int = FALSE;
+ dsp->did_throw = did_throw; did_throw = FALSE;
+ dsp->need_rethrow = need_rethrow; need_rethrow = FALSE;
+ dsp->check_cstack = check_cstack; check_cstack = FALSE;
+ dsp->current_exception = current_exception; current_exception = NULL;
+}
+
+ static void
+restore_dbg_stuff(struct dbg_stuff *dsp)
+{
+ suppress_errthrow = FALSE;
+ trylevel = dsp->trylevel;
+ force_abort = dsp->force_abort;
+ caught_stack = dsp->caught_stack;
+ (void)v_exception(dsp->vv_exception);
+ (void)v_throwpoint(dsp->vv_throwpoint);
+ did_emsg = dsp->did_emsg;
+ got_int = dsp->got_int;
+ did_throw = dsp->did_throw;
+ need_rethrow = dsp->need_rethrow;
+ check_cstack = dsp->check_cstack;
+ current_exception = dsp->current_exception;
+}
+#endif
+
+/*
+ * do_exmode(): Repeatedly get commands for the "Ex" mode, until the ":vi"
+ * command is given.
+ */
+ void
+do_exmode(
+ int improved) /* TRUE for "improved Ex" mode */
+{
+ int save_msg_scroll;
+ int prev_msg_row;
+ linenr_T prev_line;
+ varnumber_T changedtick;
+
+ if (improved)
+ exmode_active = EXMODE_VIM;
+ else
+ exmode_active = EXMODE_NORMAL;
+ State = NORMAL;
+
+ /* When using ":global /pat/ visual" and then "Q" we return to continue
+ * the :global command. */
+ if (global_busy)
+ return;
+
+ save_msg_scroll = msg_scroll;
+ ++RedrawingDisabled; /* don't redisplay the window */
+ ++no_wait_return; /* don't wait for return */
+#ifdef FEAT_GUI
+ /* Ignore scrollbar and mouse events in Ex mode */
+ ++hold_gui_events;
+#endif
+
+ msg(_("Entering Ex mode. Type \"visual\" to go to Normal mode."));
+ while (exmode_active)
+ {
+ /* Check for a ":normal" command and no more characters left. */
+ if (ex_normal_busy > 0 && typebuf.tb_len == 0)
+ {
+ exmode_active = FALSE;
+ break;
+ }
+ msg_scroll = TRUE;
+ need_wait_return = FALSE;
+ ex_pressedreturn = FALSE;
+ ex_no_reprint = FALSE;
+ changedtick = CHANGEDTICK(curbuf);
+ prev_msg_row = msg_row;
+ prev_line = curwin->w_cursor.lnum;
+ if (improved)
+ {
+ cmdline_row = msg_row;
+ do_cmdline(NULL, getexline, NULL, 0);
+ }
+ else
+ do_cmdline(NULL, getexmodeline, NULL, DOCMD_NOWAIT);
+ lines_left = Rows - 1;
+
+ if ((prev_line != curwin->w_cursor.lnum
+ || changedtick != CHANGEDTICK(curbuf)) && !ex_no_reprint)
+ {
+ if (curbuf->b_ml.ml_flags & ML_EMPTY)
+ emsg(_(e_emptybuf));
+ else
+ {
+ if (ex_pressedreturn)
+ {
+ /* go up one line, to overwrite the ":<CR>" line, so the
+ * output doesn't contain empty lines. */
+ msg_row = prev_msg_row;
+ if (prev_msg_row == Rows - 1)
+ msg_row--;
+ }
+ msg_col = 0;
+ print_line_no_prefix(curwin->w_cursor.lnum, FALSE, FALSE);
+ msg_clr_eos();
+ }
+ }
+ else if (ex_pressedreturn && !ex_no_reprint) /* must be at EOF */
+ {
+ if (curbuf->b_ml.ml_flags & ML_EMPTY)
+ emsg(_(e_emptybuf));
+ else
+ emsg(_("E501: At end-of-file"));
+ }
+ }
+
+#ifdef FEAT_GUI
+ --hold_gui_events;
+#endif
+ --RedrawingDisabled;
+ --no_wait_return;
+ update_screen(CLEAR);
+ need_wait_return = FALSE;
+ msg_scroll = save_msg_scroll;
+}
+
+/*
+ * Execute a simple command line. Used for translated commands like "*".
+ */
+ int
+do_cmdline_cmd(char_u *cmd)
+{
+ return do_cmdline(cmd, NULL, NULL,
+ DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_KEYTYPED);
+}
+
+/*
+ * do_cmdline(): execute one Ex command line
+ *
+ * 1. Execute "cmdline" when it is not NULL.
+ * If "cmdline" is NULL, or more lines are needed, fgetline() is used.
+ * 2. Split up in parts separated with '|'.
+ *
+ * This function can be called recursively!
+ *
+ * flags:
+ * DOCMD_VERBOSE - The command will be included in the error message.
+ * DOCMD_NOWAIT - Don't call wait_return() and friends.
+ * DOCMD_REPEAT - Repeat execution until fgetline() returns NULL.
+ * DOCMD_KEYTYPED - Don't reset KeyTyped.
+ * DOCMD_EXCRESET - Reset the exception environment (used for debugging).
+ * DOCMD_KEEPLINE - Store first typed line (for repeating with ".").
+ *
+ * return FAIL if cmdline could not be executed, OK otherwise
+ */
+ int
+do_cmdline(
+ char_u *cmdline,
+ char_u *(*fgetline)(int, void *, int),
+ void *cookie, /* argument for fgetline() */
+ int flags)
+{
+ char_u *next_cmdline; /* next cmd to execute */
+ char_u *cmdline_copy = NULL; /* copy of cmd line */
+ int used_getline = FALSE; /* used "fgetline" to obtain command */
+ static int recursive = 0; /* recursive depth */
+ int msg_didout_before_start = 0;
+ int count = 0; /* line number count */
+ int did_inc = FALSE; /* incremented RedrawingDisabled */
+ int retval = OK;
+#ifdef FEAT_EVAL
+ struct condstack cstack; /* conditional stack */
+ garray_T lines_ga; /* keep lines for ":while"/":for" */
+ int current_line = 0; /* active line in lines_ga */
+ char_u *fname = NULL; /* function or script name */
+ linenr_T *breakpoint = NULL; /* ptr to breakpoint field in cookie */
+ int *dbg_tick = NULL; /* ptr to dbg_tick field in cookie */
+ struct dbg_stuff debug_saved; /* saved things for debug mode */
+ int initial_trylevel;
+ struct msglist **saved_msg_list = NULL;
+ struct msglist *private_msg_list;
+
+ /* "fgetline" and "cookie" passed to do_one_cmd() */
+ char_u *(*cmd_getline)(int, void *, int);
+ void *cmd_cookie;
+ struct loop_cookie cmd_loop_cookie;
+ void *real_cookie;
+ int getline_is_func;
+#else
+# define cmd_getline fgetline
+# define cmd_cookie cookie
+#endif
+ static int call_depth = 0; /* recursiveness */
+
+#ifdef FEAT_EVAL
+ /* For every pair of do_cmdline()/do_one_cmd() calls, use an extra memory
+ * location for storing error messages to be converted to an exception.
+ * This ensures that the do_errthrow() call in do_one_cmd() does not
+ * combine the messages stored by an earlier invocation of do_one_cmd()
+ * with the command name of the later one. This would happen when
+ * BufWritePost autocommands are executed after a write error. */
+ saved_msg_list = msg_list;
+ msg_list = &private_msg_list;
+ private_msg_list = NULL;
+#endif
+
+ /* It's possible to create an endless loop with ":execute", catch that
+ * here. The value of 200 allows nested function calls, ":source", etc.
+ * Allow 200 or 'maxfuncdepth', whatever is larger. */
+ if (call_depth >= 200
+#ifdef FEAT_EVAL
+ && call_depth >= p_mfd
+#endif
+ )
+ {
+ emsg(_("E169: Command too recursive"));
+#ifdef FEAT_EVAL
+ /* When converting to an exception, we do not include the command name
+ * since this is not an error of the specific command. */
+ do_errthrow((struct condstack *)NULL, (char_u *)NULL);
+ msg_list = saved_msg_list;
+#endif
+ return FAIL;
+ }
+ ++call_depth;
+
+#ifdef FEAT_EVAL
+ cstack.cs_idx = -1;
+ cstack.cs_looplevel = 0;
+ cstack.cs_trylevel = 0;
+ cstack.cs_emsg_silent_list = NULL;
+ cstack.cs_lflags = 0;
+ ga_init2(&lines_ga, (int)sizeof(wcmd_T), 10);
+
+ real_cookie = getline_cookie(fgetline, cookie);
+
+ /* Inside a function use a higher nesting level. */
+ getline_is_func = getline_equal(fgetline, cookie, get_func_line);
+ if (getline_is_func && ex_nesting_level == func_level(real_cookie))
+ ++ex_nesting_level;
+
+ /* Get the function or script name and the address where the next breakpoint
+ * line and the debug tick for a function or script are stored. */
+ if (getline_is_func)
+ {
+ fname = func_name(real_cookie);
+ breakpoint = func_breakpoint(real_cookie);
+ dbg_tick = func_dbg_tick(real_cookie);
+ }
+ else if (getline_equal(fgetline, cookie, getsourceline))
+ {
+ fname = sourcing_name;
+ breakpoint = source_breakpoint(real_cookie);
+ dbg_tick = source_dbg_tick(real_cookie);
+ }
+
+ /*
+ * Initialize "force_abort" and "suppress_errthrow" at the top level.
+ */
+ if (!recursive)
+ {
+ force_abort = FALSE;
+ suppress_errthrow = FALSE;
+ }
+
+ /*
+ * If requested, store and reset the global values controlling the
+ * exception handling (used when debugging). Otherwise clear it to avoid
+ * a bogus compiler warning when the optimizer uses inline functions...
+ */
+ if (flags & DOCMD_EXCRESET)
+ save_dbg_stuff(&debug_saved);
+ else
+ vim_memset(&debug_saved, 0, sizeof(debug_saved));
+
+ initial_trylevel = trylevel;
+
+ /*
+ * "did_throw" will be set to TRUE when an exception is being thrown.
+ */
+ did_throw = FALSE;
+#endif
+ /*
+ * "did_emsg" will be set to TRUE when emsg() is used, in which case we
+ * cancel the whole command line, and any if/endif or loop.
+ * If force_abort is set, we cancel everything.
+ */
+ did_emsg = FALSE;
+
+ /*
+ * KeyTyped is only set when calling vgetc(). Reset it here when not
+ * calling vgetc() (sourced command lines).
+ */
+ if (!(flags & DOCMD_KEYTYPED)
+ && !getline_equal(fgetline, cookie, getexline))
+ KeyTyped = FALSE;
+
+ /*
+ * Continue executing command lines:
+ * - when inside an ":if", ":while" or ":for"
+ * - for multiple commands on one line, separated with '|'
+ * - when repeating until there are no more lines (for ":source")
+ */
+ next_cmdline = cmdline;
+ do
+ {
+#ifdef FEAT_EVAL
+ getline_is_func = getline_equal(fgetline, cookie, get_func_line);
+#endif
+
+ /* stop skipping cmds for an error msg after all endif/while/for */
+ if (next_cmdline == NULL
+#ifdef FEAT_EVAL
+ && !force_abort
+ && cstack.cs_idx < 0
+ && !(getline_is_func && func_has_abort(real_cookie))
+#endif
+ )
+ did_emsg = FALSE;
+
+ /*
+ * 1. If repeating a line in a loop, get a line from lines_ga.
+ * 2. If no line given: Get an allocated line with fgetline().
+ * 3. If a line is given: Make a copy, so we can mess with it.
+ */
+
+#ifdef FEAT_EVAL
+ /* 1. If repeating, get a previous line from lines_ga. */
+ if (cstack.cs_looplevel > 0 && current_line < lines_ga.ga_len)
+ {
+ /* Each '|' separated command is stored separately in lines_ga, to
+ * be able to jump to it. Don't use next_cmdline now. */
+ VIM_CLEAR(cmdline_copy);
+
+ /* Check if a function has returned or, unless it has an unclosed
+ * try conditional, aborted. */
+ if (getline_is_func)
+ {
+# ifdef FEAT_PROFILE
+ if (do_profiling == PROF_YES)
+ func_line_end(real_cookie);
+# endif
+ if (func_has_ended(real_cookie))
+ {
+ retval = FAIL;
+ break;
+ }
+ }
+#ifdef FEAT_PROFILE
+ else if (do_profiling == PROF_YES
+ && getline_equal(fgetline, cookie, getsourceline))
+ script_line_end();
+#endif
+
+ /* Check if a sourced file hit a ":finish" command. */
+ if (source_finished(fgetline, cookie))
+ {
+ retval = FAIL;
+ break;
+ }
+
+ /* If breakpoints have been added/deleted need to check for it. */
+ if (breakpoint != NULL && dbg_tick != NULL
+ && *dbg_tick != debug_tick)
+ {
+ *breakpoint = dbg_find_breakpoint(
+ getline_equal(fgetline, cookie, getsourceline),
+ fname, sourcing_lnum);
+ *dbg_tick = debug_tick;
+ }
+
+ next_cmdline = ((wcmd_T *)(lines_ga.ga_data))[current_line].line;
+ sourcing_lnum = ((wcmd_T *)(lines_ga.ga_data))[current_line].lnum;
+
+ /* Did we encounter a breakpoint? */
+ if (breakpoint != NULL && *breakpoint != 0
+ && *breakpoint <= sourcing_lnum)
+ {
+ dbg_breakpoint(fname, sourcing_lnum);
+ /* Find next breakpoint. */
+ *breakpoint = dbg_find_breakpoint(
+ getline_equal(fgetline, cookie, getsourceline),
+ fname, sourcing_lnum);
+ *dbg_tick = debug_tick;
+ }
+# ifdef FEAT_PROFILE
+ if (do_profiling == PROF_YES)
+ {
+ if (getline_is_func)
+ func_line_start(real_cookie);
+ else if (getline_equal(fgetline, cookie, getsourceline))
+ script_line_start();
+ }
+# endif
+ }
+
+ if (cstack.cs_looplevel > 0)
+ {
+ /* Inside a while/for loop we need to store the lines and use them
+ * again. Pass a different "fgetline" function to do_one_cmd()
+ * below, so that it stores lines in or reads them from
+ * "lines_ga". Makes it possible to define a function inside a
+ * while/for loop. */
+ cmd_getline = get_loop_line;
+ cmd_cookie = (void *)&cmd_loop_cookie;
+ cmd_loop_cookie.lines_gap = &lines_ga;
+ cmd_loop_cookie.current_line = current_line;
+ cmd_loop_cookie.getline = fgetline;
+ cmd_loop_cookie.cookie = cookie;
+ cmd_loop_cookie.repeating = (current_line < lines_ga.ga_len);
+ }
+ else
+ {
+ cmd_getline = fgetline;
+ cmd_cookie = cookie;
+ }
+#endif
+
+ /* 2. If no line given, get an allocated line with fgetline(). */
+ if (next_cmdline == NULL)
+ {
+ /*
+ * Need to set msg_didout for the first line after an ":if",
+ * otherwise the ":if" will be overwritten.
+ */
+ if (count == 1 && getline_equal(fgetline, cookie, getexline))
+ msg_didout = TRUE;
+ if (fgetline == NULL || (next_cmdline = fgetline(':', cookie,
+#ifdef FEAT_EVAL
+ cstack.cs_idx < 0 ? 0 : (cstack.cs_idx + 1) * 2
+#else
+ 0
+#endif
+ )) == NULL)
+ {
+ /* Don't call wait_return for aborted command line. The NULL
+ * returned for the end of a sourced file or executed function
+ * doesn't do this. */
+ if (KeyTyped && !(flags & DOCMD_REPEAT))
+ need_wait_return = FALSE;
+ retval = FAIL;
+ break;
+ }
+ used_getline = TRUE;
+
+ /*
+ * Keep the first typed line. Clear it when more lines are typed.
+ */
+ if (flags & DOCMD_KEEPLINE)
+ {
+ vim_free(repeat_cmdline);
+ if (count == 0)
+ repeat_cmdline = vim_strsave(next_cmdline);
+ else
+ repeat_cmdline = NULL;
+ }
+ }
+
+ /* 3. Make a copy of the command so we can mess with it. */
+ else if (cmdline_copy == NULL)
+ {
+ next_cmdline = vim_strsave(next_cmdline);
+ if (next_cmdline == NULL)
+ {
+ emsg(_(e_outofmem));
+ retval = FAIL;
+ break;
+ }
+ }
+ cmdline_copy = next_cmdline;
+
+#ifdef FEAT_EVAL
+ /*
+ * Save the current line when inside a ":while" or ":for", and when
+ * the command looks like a ":while" or ":for", because we may need it
+ * later. When there is a '|' and another command, it is stored
+ * separately, because we need to be able to jump back to it from an
+ * :endwhile/:endfor.
+ */
+ if (current_line == lines_ga.ga_len
+ && (cstack.cs_looplevel || has_loop_cmd(next_cmdline)))
+ {
+ if (store_loop_line(&lines_ga, next_cmdline) == FAIL)
+ {
+ retval = FAIL;
+ break;
+ }
+ }
+ did_endif = FALSE;
+#endif
+
+ if (count++ == 0)
+ {
+ /*
+ * All output from the commands is put below each other, without
+ * waiting for a return. Don't do this when executing commands
+ * from a script or when being called recursive (e.g. for ":e
+ * +command file").
+ */
+ if (!(flags & DOCMD_NOWAIT) && !recursive)
+ {
+ msg_didout_before_start = msg_didout;
+ msg_didany = FALSE; /* no output yet */
+ msg_start();
+ msg_scroll = TRUE; /* put messages below each other */
+ ++no_wait_return; /* don't wait for return until finished */
+ ++RedrawingDisabled;
+ did_inc = TRUE;
+ }
+ }
+
+ if (p_verbose >= 15 && sourcing_name != NULL)
+ {
+ ++no_wait_return;
+ verbose_enter_scroll();
+
+ smsg(_("line %ld: %s"),
+ (long)sourcing_lnum, cmdline_copy);
+ if (msg_silent == 0)
+ msg_puts("\n"); /* don't overwrite this */
+
+ verbose_leave_scroll();
+ --no_wait_return;
+ }
+
+ /*
+ * 2. Execute one '|' separated command.
+ * do_one_cmd() will return NULL if there is no trailing '|'.
+ * "cmdline_copy" can change, e.g. for '%' and '#' expansion.
+ */
+ ++recursive;
+ next_cmdline = do_one_cmd(&cmdline_copy, flags & DOCMD_VERBOSE,
+#ifdef FEAT_EVAL
+ &cstack,
+#endif
+ cmd_getline, cmd_cookie);
+ --recursive;
+
+#ifdef FEAT_EVAL
+ if (cmd_cookie == (void *)&cmd_loop_cookie)
+ /* Use "current_line" from "cmd_loop_cookie", it may have been
+ * incremented when defining a function. */
+ current_line = cmd_loop_cookie.current_line;
+#endif
+
+ if (next_cmdline == NULL)
+ {
+ VIM_CLEAR(cmdline_copy);
+#ifdef FEAT_CMDHIST
+ /*
+ * If the command was typed, remember it for the ':' register.
+ * Do this AFTER executing the command to make :@: work.
+ */
+ if (getline_equal(fgetline, cookie, getexline)
+ && new_last_cmdline != NULL)
+ {
+ vim_free(last_cmdline);
+ last_cmdline = new_last_cmdline;
+ new_last_cmdline = NULL;
+ }
+#endif
+ }
+ else
+ {
+ /* need to copy the command after the '|' to cmdline_copy, for the
+ * next do_one_cmd() */
+ STRMOVE(cmdline_copy, next_cmdline);
+ next_cmdline = cmdline_copy;
+ }
+
+
+#ifdef FEAT_EVAL
+ /* reset did_emsg for a function that is not aborted by an error */
+ if (did_emsg && !force_abort
+ && getline_equal(fgetline, cookie, get_func_line)
+ && !func_has_abort(real_cookie))
+ did_emsg = FALSE;
+
+ if (cstack.cs_looplevel > 0)
+ {
+ ++current_line;
+
+ /*
+ * An ":endwhile", ":endfor" and ":continue" is handled here.
+ * If we were executing commands, jump back to the ":while" or
+ * ":for".
+ * If we were not executing commands, decrement cs_looplevel.
+ */
+ if (cstack.cs_lflags & (CSL_HAD_CONT | CSL_HAD_ENDLOOP))
+ {
+ cstack.cs_lflags &= ~(CSL_HAD_CONT | CSL_HAD_ENDLOOP);
+
+ /* Jump back to the matching ":while" or ":for". Be careful
+ * not to use a cs_line[] from an entry that isn't a ":while"
+ * or ":for": It would make "current_line" invalid and can
+ * cause a crash. */
+ if (!did_emsg && !got_int && !did_throw
+ && cstack.cs_idx >= 0
+ && (cstack.cs_flags[cstack.cs_idx]
+ & (CSF_WHILE | CSF_FOR))
+ && cstack.cs_line[cstack.cs_idx] >= 0
+ && (cstack.cs_flags[cstack.cs_idx] & CSF_ACTIVE))
+ {
+ current_line = cstack.cs_line[cstack.cs_idx];
+ /* remember we jumped there */
+ cstack.cs_lflags |= CSL_HAD_LOOP;
+ line_breakcheck(); /* check if CTRL-C typed */
+
+ /* Check for the next breakpoint at or after the ":while"
+ * or ":for". */
+ if (breakpoint != NULL)
+ {
+ *breakpoint = dbg_find_breakpoint(
+ getline_equal(fgetline, cookie, getsourceline),
+ fname,
+ ((wcmd_T *)lines_ga.ga_data)[current_line].lnum-1);
+ *dbg_tick = debug_tick;
+ }
+ }
+ else
+ {
+ /* can only get here with ":endwhile" or ":endfor" */
+ if (cstack.cs_idx >= 0)
+ rewind_conditionals(&cstack, cstack.cs_idx - 1,
+ CSF_WHILE | CSF_FOR, &cstack.cs_looplevel);
+ }
+ }
+
+ /*
+ * For a ":while" or ":for" we need to remember the line number.
+ */
+ else if (cstack.cs_lflags & CSL_HAD_LOOP)
+ {
+ cstack.cs_lflags &= ~CSL_HAD_LOOP;
+ cstack.cs_line[cstack.cs_idx] = current_line - 1;
+ }
+ }
+
+ /* Check for the next breakpoint after a watchexpression */
+ if (breakpoint != NULL && has_watchexpr())
+ {
+ *breakpoint = dbg_find_breakpoint(FALSE, fname, sourcing_lnum);
+ *dbg_tick = debug_tick;
+ }
+
+ /*
+ * When not inside any ":while" loop, clear remembered lines.
+ */
+ if (cstack.cs_looplevel == 0)
+ {
+ if (lines_ga.ga_len > 0)
+ {
+ sourcing_lnum =
+ ((wcmd_T *)lines_ga.ga_data)[lines_ga.ga_len - 1].lnum;
+ free_cmdlines(&lines_ga);
+ }
+ current_line = 0;
+ }
+
+ /*
+ * A ":finally" makes did_emsg, got_int, and did_throw pending for
+ * being restored at the ":endtry". Reset them here and set the
+ * ACTIVE and FINALLY flags, so that the finally clause gets executed.
+ * This includes the case where a missing ":endif", ":endwhile" or
+ * ":endfor" was detected by the ":finally" itself.
+ */
+ if (cstack.cs_lflags & CSL_HAD_FINA)
+ {
+ cstack.cs_lflags &= ~CSL_HAD_FINA;
+ report_make_pending(cstack.cs_pending[cstack.cs_idx]
+ & (CSTP_ERROR | CSTP_INTERRUPT | CSTP_THROW),
+ did_throw ? (void *)current_exception : NULL);
+ did_emsg = got_int = did_throw = FALSE;
+ cstack.cs_flags[cstack.cs_idx] |= CSF_ACTIVE | CSF_FINALLY;
+ }
+
+ /* Update global "trylevel" for recursive calls to do_cmdline() from
+ * within this loop. */
+ trylevel = initial_trylevel + cstack.cs_trylevel;
+
+ /*
+ * If the outermost try conditional (across function calls and sourced
+ * files) is aborted because of an error, an interrupt, or an uncaught
+ * exception, cancel everything. If it is left normally, reset
+ * force_abort to get the non-EH compatible abortion behavior for
+ * the rest of the script.
+ */
+ if (trylevel == 0 && !did_emsg && !got_int && !did_throw)
+ force_abort = FALSE;
+
+ /* Convert an interrupt to an exception if appropriate. */
+ (void)do_intthrow(&cstack);
+#endif /* FEAT_EVAL */
+
+ }
+ /*
+ * Continue executing command lines when:
+ * - no CTRL-C typed, no aborting error, no exception thrown or try
+ * conditionals need to be checked for executing finally clauses or
+ * catching an interrupt exception
+ * - didn't get an error message or lines are not typed
+ * - there is a command after '|', inside a :if, :while, :for or :try, or
+ * looping for ":source" command or function call.
+ */
+ while (!((got_int
+#ifdef FEAT_EVAL
+ || (did_emsg && force_abort) || did_throw
+#endif
+ )
+#ifdef FEAT_EVAL
+ && cstack.cs_trylevel == 0
+#endif
+ )
+ && !(did_emsg
+#ifdef FEAT_EVAL
+ /* Keep going when inside try/catch, so that the error can be
+ * deal with, except when it is a syntax error, it may cause
+ * the :endtry to be missed. */
+ && (cstack.cs_trylevel == 0 || did_emsg_syntax)
+#endif
+ && used_getline
+ && (getline_equal(fgetline, cookie, getexmodeline)
+ || getline_equal(fgetline, cookie, getexline)))
+ && (next_cmdline != NULL
+#ifdef FEAT_EVAL
+ || cstack.cs_idx >= 0
+#endif
+ || (flags & DOCMD_REPEAT)));
+
+ vim_free(cmdline_copy);
+ did_emsg_syntax = FALSE;
+#ifdef FEAT_EVAL
+ free_cmdlines(&lines_ga);
+ ga_clear(&lines_ga);
+
+ if (cstack.cs_idx >= 0)
+ {
+ /*
+ * If a sourced file or executed function ran to its end, report the
+ * unclosed conditional.
+ */
+ if (!got_int && !did_throw
+ && ((getline_equal(fgetline, cookie, getsourceline)
+ && !source_finished(fgetline, cookie))
+ || (getline_equal(fgetline, cookie, get_func_line)
+ && !func_has_ended(real_cookie))))
+ {
+ if (cstack.cs_flags[cstack.cs_idx] & CSF_TRY)
+ emsg(_(e_endtry));
+ else if (cstack.cs_flags[cstack.cs_idx] & CSF_WHILE)
+ emsg(_(e_endwhile));
+ else if (cstack.cs_flags[cstack.cs_idx] & CSF_FOR)
+ emsg(_(e_endfor));
+ else
+ emsg(_(e_endif));
+ }
+
+ /*
+ * Reset "trylevel" in case of a ":finish" or ":return" or a missing
+ * ":endtry" in a sourced file or executed function. If the try
+ * conditional is in its finally clause, ignore anything pending.
+ * If it is in a catch clause, finish the caught exception.
+ * Also cleanup any "cs_forinfo" structures.
+ */
+ do
+ {
+ int idx = cleanup_conditionals(&cstack, 0, TRUE);
+
+ if (idx >= 0)
+ --idx; /* remove try block not in its finally clause */
+ rewind_conditionals(&cstack, idx, CSF_WHILE | CSF_FOR,
+ &cstack.cs_looplevel);
+ }
+ while (cstack.cs_idx >= 0);
+ trylevel = initial_trylevel;
+ }
+
+ /* If a missing ":endtry", ":endwhile", ":endfor", or ":endif" or a memory
+ * lack was reported above and the error message is to be converted to an
+ * exception, do this now after rewinding the cstack. */
+ do_errthrow(&cstack, getline_equal(fgetline, cookie, get_func_line)
+ ? (char_u *)"endfunction" : (char_u *)NULL);
+
+ if (trylevel == 0)
+ {
+ /*
+ * When an exception is being thrown out of the outermost try
+ * conditional, discard the uncaught exception, disable the conversion
+ * of interrupts or errors to exceptions, and ensure that no more
+ * commands are executed.
+ */
+ if (did_throw)
+ {
+ void *p = NULL;
+ char_u *saved_sourcing_name;
+ int saved_sourcing_lnum;
+ struct msglist *messages = NULL, *next;
+
+ /*
+ * If the uncaught exception is a user exception, report it as an
+ * error. If it is an error exception, display the saved error
+ * message now. For an interrupt exception, do nothing; the
+ * interrupt message is given elsewhere.
+ */
+ switch (current_exception->type)
+ {
+ case ET_USER:
+ vim_snprintf((char *)IObuff, IOSIZE,
+ _("E605: Exception not caught: %s"),
+ current_exception->value);
+ p = vim_strsave(IObuff);
+ break;
+ case ET_ERROR:
+ messages = current_exception->messages;
+ current_exception->messages = NULL;
+ break;
+ case ET_INTERRUPT:
+ break;
+ }
+
+ saved_sourcing_name = sourcing_name;
+ saved_sourcing_lnum = sourcing_lnum;
+ sourcing_name = current_exception->throw_name;
+ sourcing_lnum = current_exception->throw_lnum;
+ current_exception->throw_name = NULL;
+
+ discard_current_exception(); /* uses IObuff if 'verbose' */
+ suppress_errthrow = TRUE;
+ force_abort = TRUE;
+
+ if (messages != NULL)
+ {
+ do
+ {
+ next = messages->next;
+ emsg(messages->msg);
+ vim_free(messages->msg);
+ vim_free(messages);
+ messages = next;
+ }
+ while (messages != NULL);
+ }
+ else if (p != NULL)
+ {
+ emsg(p);
+ vim_free(p);
+ }
+ vim_free(sourcing_name);
+ sourcing_name = saved_sourcing_name;
+ sourcing_lnum = saved_sourcing_lnum;
+ }
+
+ /*
+ * On an interrupt or an aborting error not converted to an exception,
+ * disable the conversion of errors to exceptions. (Interrupts are not
+ * converted any more, here.) This enables also the interrupt message
+ * when force_abort is set and did_emsg unset in case of an interrupt
+ * from a finally clause after an error.
+ */
+ else if (got_int || (did_emsg && force_abort))
+ suppress_errthrow = TRUE;
+ }
+
+ /*
+ * The current cstack will be freed when do_cmdline() returns. An uncaught
+ * exception will have to be rethrown in the previous cstack. If a function
+ * has just returned or a script file was just finished and the previous
+ * cstack belongs to the same function or, respectively, script file, it
+ * will have to be checked for finally clauses to be executed due to the
+ * ":return" or ":finish". This is done in do_one_cmd().
+ */
+ if (did_throw)
+ need_rethrow = TRUE;
+ if ((getline_equal(fgetline, cookie, getsourceline)
+ && ex_nesting_level > source_level(real_cookie))
+ || (getline_equal(fgetline, cookie, get_func_line)
+ && ex_nesting_level > func_level(real_cookie) + 1))
+ {
+ if (!did_throw)
+ check_cstack = TRUE;
+ }
+ else
+ {
+ /* When leaving a function, reduce nesting level. */
+ if (getline_equal(fgetline, cookie, get_func_line))
+ --ex_nesting_level;
+ /*
+ * Go to debug mode when returning from a function in which we are
+ * single-stepping.
+ */
+ if ((getline_equal(fgetline, cookie, getsourceline)
+ || getline_equal(fgetline, cookie, get_func_line))
+ && ex_nesting_level + 1 <= debug_break_level)
+ do_debug(getline_equal(fgetline, cookie, getsourceline)
+ ? (char_u *)_("End of sourced file")
+ : (char_u *)_("End of function"));
+ }
+
+ /*
+ * Restore the exception environment (done after returning from the
+ * debugger).
+ */
+ if (flags & DOCMD_EXCRESET)
+ restore_dbg_stuff(&debug_saved);
+
+ msg_list = saved_msg_list;
+#endif /* FEAT_EVAL */
+
+ /*
+ * If there was too much output to fit on the command line, ask the user to
+ * hit return before redrawing the screen. With the ":global" command we do
+ * this only once after the command is finished.
+ */
+ if (did_inc)
+ {
+ --RedrawingDisabled;
+ --no_wait_return;
+ msg_scroll = FALSE;
+
+ /*
+ * When just finished an ":if"-":else" which was typed, no need to
+ * wait for hit-return. Also for an error situation.
+ */
+ if (retval == FAIL
+#ifdef FEAT_EVAL
+ || (did_endif && KeyTyped && !did_emsg)
+#endif
+ )
+ {
+ need_wait_return = FALSE;
+ msg_didany = FALSE; /* don't wait when restarting edit */
+ }
+ else if (need_wait_return)
+ {
+ /*
+ * The msg_start() above clears msg_didout. The wait_return we do
+ * here should not overwrite the command that may be shown before
+ * doing that.
+ */
+ msg_didout |= msg_didout_before_start;
+ wait_return(FALSE);
+ }
+ }
+
+#ifdef FEAT_EVAL
+ did_endif = FALSE; /* in case do_cmdline used recursively */
+#else
+ /*
+ * Reset if_level, in case a sourced script file contains more ":if" than
+ * ":endif" (could be ":if x | foo | endif").
+ */
+ if_level = 0;
+#endif
+
+ --call_depth;
+ return retval;
+}
+
+#ifdef FEAT_EVAL
+/*
+ * Obtain a line when inside a ":while" or ":for" loop.
+ */
+ static char_u *
+get_loop_line(int c, void *cookie, int indent)
+{
+ struct loop_cookie *cp = (struct loop_cookie *)cookie;
+ wcmd_T *wp;
+ char_u *line;
+
+ if (cp->current_line + 1 >= cp->lines_gap->ga_len)
+ {
+ if (cp->repeating)
+ return NULL; /* trying to read past ":endwhile"/":endfor" */
+
+ /* First time inside the ":while"/":for": get line normally. */
+ if (cp->getline == NULL)
+ line = getcmdline(c, 0L, indent);
+ else
+ line = cp->getline(c, cp->cookie, indent);
+ if (line != NULL && store_loop_line(cp->lines_gap, line) == OK)
+ ++cp->current_line;
+
+ return line;
+ }
+
+ KeyTyped = FALSE;
+ ++cp->current_line;
+ wp = (wcmd_T *)(cp->lines_gap->ga_data) + cp->current_line;
+ sourcing_lnum = wp->lnum;
+ return vim_strsave(wp->line);
+}
+
+/*
+ * Store a line in "gap" so that a ":while" loop can execute it again.
+ */
+ static int
+store_loop_line(garray_T *gap, char_u *line)
+{
+ if (ga_grow(gap, 1) == FAIL)
+ return FAIL;
+ ((wcmd_T *)(gap->ga_data))[gap->ga_len].line = vim_strsave(line);
+ ((wcmd_T *)(gap->ga_data))[gap->ga_len].lnum = sourcing_lnum;
+ ++gap->ga_len;
+ return OK;
+}
+
+/*
+ * Free the lines stored for a ":while" or ":for" loop.
+ */
+ static void
+free_cmdlines(garray_T *gap)
+{
+ while (gap->ga_len > 0)
+ {
+ vim_free(((wcmd_T *)(gap->ga_data))[gap->ga_len - 1].line);
+ --gap->ga_len;
+ }
+}
+#endif
+
+/*
+ * If "fgetline" is get_loop_line(), return TRUE if the getline it uses equals
+ * "func". * Otherwise return TRUE when "fgetline" equals "func".
+ */
+ int
+getline_equal(
+ char_u *(*fgetline)(int, void *, int),
+ void *cookie UNUSED, /* argument for fgetline() */
+ char_u *(*func)(int, void *, int))
+{
+#ifdef FEAT_EVAL
+ char_u *(*gp)(int, void *, int);
+ struct loop_cookie *cp;
+
+ /* When "fgetline" is "get_loop_line()" use the "cookie" to find the
+ * function that's originally used to obtain the lines. This may be
+ * nested several levels. */
+ gp = fgetline;
+ cp = (struct loop_cookie *)cookie;
+ while (gp == get_loop_line)
+ {
+ gp = cp->getline;
+ cp = cp->cookie;
+ }
+ return gp == func;
+#else
+ return fgetline == func;
+#endif
+}
+
+/*
+ * If "fgetline" is get_loop_line(), return the cookie used by the original
+ * getline function. Otherwise return "cookie".
+ */
+ void *
+getline_cookie(
+ char_u *(*fgetline)(int, void *, int) UNUSED,
+ void *cookie) /* argument for fgetline() */
+{
+#ifdef FEAT_EVAL
+ char_u *(*gp)(int, void *, int);
+ struct loop_cookie *cp;
+
+ /* When "fgetline" is "get_loop_line()" use the "cookie" to find the
+ * cookie that's originally used to obtain the lines. This may be nested
+ * several levels. */
+ gp = fgetline;
+ cp = (struct loop_cookie *)cookie;
+ while (gp == get_loop_line)
+ {
+ gp = cp->getline;
+ cp = cp->cookie;
+ }
+ return cp;
+#else
+ return cookie;
+#endif
+}
+
+
+/*
+ * Helper function to apply an offset for buffer commands, i.e. ":bdelete",
+ * ":bwipeout", etc.
+ * Returns the buffer number.
+ */
+ static int
+compute_buffer_local_count(int addr_type, int lnum, int offset)
+{
+ buf_T *buf;
+ buf_T *nextbuf;
+ int count = offset;
+
+ buf = firstbuf;
+ while (buf->b_next != NULL && buf->b_fnum < lnum)
+ buf = buf->b_next;
+ while (count != 0)
+ {
+ count += (offset < 0) ? 1 : -1;
+ nextbuf = (offset < 0) ? buf->b_prev : buf->b_next;
+ if (nextbuf == NULL)
+ break;
+ buf = nextbuf;
+ if (addr_type == ADDR_LOADED_BUFFERS)
+ /* skip over unloaded buffers */
+ while (buf->b_ml.ml_mfp == NULL)
+ {
+ nextbuf = (offset < 0) ? buf->b_prev : buf->b_next;
+ if (nextbuf == NULL)
+ break;
+ buf = nextbuf;
+ }
+ }
+ /* we might have gone too far, last buffer is not loadedd */
+ if (addr_type == ADDR_LOADED_BUFFERS)
+ while (buf->b_ml.ml_mfp == NULL)
+ {
+ nextbuf = (offset >= 0) ? buf->b_prev : buf->b_next;
+ if (nextbuf == NULL)
+ break;
+ buf = nextbuf;
+ }
+ return buf->b_fnum;
+}
+
+ static int
+current_win_nr(win_T *win)
+{
+ win_T *wp;
+ int nr = 0;
+
+ FOR_ALL_WINDOWS(wp)
+ {
+ ++nr;
+ if (wp == win)
+ break;
+ }
+ return nr;
+}
+
+ static int
+current_tab_nr(tabpage_T *tab)
+{
+ tabpage_T *tp;
+ int nr = 0;
+
+ FOR_ALL_TABPAGES(tp)
+ {
+ ++nr;
+ if (tp == tab)
+ break;
+ }
+ return nr;
+}
+
+# define CURRENT_WIN_NR current_win_nr(curwin)
+# define LAST_WIN_NR current_win_nr(NULL)
+# define CURRENT_TAB_NR current_tab_nr(curtab)
+# define LAST_TAB_NR current_tab_nr(NULL)
+
+/*
+ * Execute one Ex command.
+ *
+ * If 'sourcing' is TRUE, the command will be included in the error message.
+ *
+ * 1. skip comment lines and leading space
+ * 2. handle command modifiers
+ * 3. find the command
+ * 4. parse range
+ * 5. Parse the command.
+ * 6. parse arguments
+ * 7. switch on command name
+ *
+ * Note: "fgetline" can be NULL.
+ *
+ * This function may be called recursively!
+ */
+#if (_MSC_VER == 1200)
+/*
+ * Avoid optimisation bug in VC++ version 6.0
+ */
+ #pragma optimize( "g", off )
+#endif
+ static char_u *
+do_one_cmd(
+ char_u **cmdlinep,
+ int sourcing,
+#ifdef FEAT_EVAL
+ struct condstack *cstack,
+#endif
+ char_u *(*fgetline)(int, void *, int),
+ void *cookie) /* argument for fgetline() */
+{
+ char_u *p;
+ linenr_T lnum;
+ long n;
+ char *errormsg = NULL; /* error message */
+ char_u *after_modifier = NULL;
+ exarg_T ea; /* Ex command arguments */
+ int save_msg_scroll = msg_scroll;
+ cmdmod_T save_cmdmod;
+ int ni; /* set when Not Implemented */
+ char_u *cmd;
+
+ vim_memset(&ea, 0, sizeof(ea));
+ ea.line1 = 1;
+ ea.line2 = 1;
+#ifdef FEAT_EVAL
+ ++ex_nesting_level;
+#endif
+
+ /* When the last file has not been edited :q has to be typed twice. */
+ if (quitmore
+#ifdef FEAT_EVAL
+ /* avoid that a function call in 'statusline' does this */
+ && !getline_equal(fgetline, cookie, get_func_line)
+#endif
+ /* avoid that an autocommand, e.g. QuitPre, does this */
+ && !getline_equal(fgetline, cookie, getnextac))
+ --quitmore;
+
+ /*
+ * Reset browse, confirm, etc.. They are restored when returning, for
+ * recursive calls.
+ */
+ save_cmdmod = cmdmod;
+
+ /* "#!anything" is handled like a comment. */
+ if ((*cmdlinep)[0] == '#' && (*cmdlinep)[1] == '!')
+ goto doend;
+
+/*
+ * 1. Skip comment lines and leading white space and colons.
+ * 2. Handle command modifiers.
+ */
+ // The "ea" structure holds the arguments that can be used.
+ ea.cmd = *cmdlinep;
+ ea.cmdlinep = cmdlinep;
+ ea.getline = fgetline;
+ ea.cookie = cookie;
+#ifdef FEAT_EVAL
+ ea.cstack = cstack;
+#endif
+ if (parse_command_modifiers(&ea, &errormsg, FALSE) == FAIL)
+ goto doend;
+
+ after_modifier = ea.cmd;
+
+#ifdef FEAT_EVAL
+ ea.skip = did_emsg || got_int || did_throw || (cstack->cs_idx >= 0
+ && !(cstack->cs_flags[cstack->cs_idx] & CSF_ACTIVE));
+#else
+ ea.skip = (if_level > 0);
+#endif
+
+/*
+ * 3. Skip over the range to find the command. Let "p" point to after it.
+ *
+ * We need the command to know what kind of range it uses.
+ */
+ cmd = ea.cmd;
+ ea.cmd = skip_range(ea.cmd, NULL);
+ if (*ea.cmd == '*' && vim_strchr(p_cpo, CPO_STAR) == NULL)
+ ea.cmd = skipwhite(ea.cmd + 1);
+ p = find_command(&ea, NULL);
+
+#ifdef FEAT_EVAL
+# ifdef FEAT_PROFILE
+ // Count this line for profiling if skip is TRUE.
+ if (do_profiling == PROF_YES
+ && (!ea.skip || cstack->cs_idx == 0 || (cstack->cs_idx > 0
+ && (cstack->cs_flags[cstack->cs_idx - 1] & CSF_ACTIVE))))
+ {
+ int skip = did_emsg || got_int || did_throw;
+
+ if (ea.cmdidx == CMD_catch)
+ skip = !skip && !(cstack->cs_idx >= 0
+ && (cstack->cs_flags[cstack->cs_idx] & CSF_THROWN)
+ && !(cstack->cs_flags[cstack->cs_idx] & CSF_CAUGHT));
+ else if (ea.cmdidx == CMD_else || ea.cmdidx == CMD_elseif)
+ skip = skip || !(cstack->cs_idx >= 0
+ && !(cstack->cs_flags[cstack->cs_idx]
+ & (CSF_ACTIVE | CSF_TRUE)));
+ else if (ea.cmdidx == CMD_finally)
+ skip = FALSE;
+ else if (ea.cmdidx != CMD_endif
+ && ea.cmdidx != CMD_endfor
+ && ea.cmdidx != CMD_endtry
+ && ea.cmdidx != CMD_endwhile)
+ skip = ea.skip;
+
+ if (!skip)
+ {
+ if (getline_equal(fgetline, cookie, get_func_line))
+ func_line_exec(getline_cookie(fgetline, cookie));
+ else if (getline_equal(fgetline, cookie, getsourceline))
+ script_line_exec();
+ }
+ }
+# endif
+
+ /* May go to debug mode. If this happens and the ">quit" debug command is
+ * used, throw an interrupt exception and skip the next command. */
+ dbg_check_breakpoint(&ea);
+ if (!ea.skip && got_int)
+ {
+ ea.skip = TRUE;
+ (void)do_intthrow(cstack);
+ }
+#endif
+
+/*
+ * 4. parse a range specifier of the form: addr [,addr] [;addr] ..
+ *
+ * where 'addr' is:
+ *
+ * % (entire file)
+ * $ [+-NUM]
+ * 'x [+-NUM] (where x denotes a currently defined mark)
+ * . [+-NUM]
+ * [+-NUM]..
+ * NUM
+ *
+ * The ea.cmd pointer is updated to point to the first character following the
+ * range spec. If an initial address is found, but no second, the upper bound
+ * is equal to the lower.
+ */
+
+ /* ea.addr_type for user commands is set by find_ucmd */
+ if (!IS_USER_CMDIDX(ea.cmdidx))
+ {
+ if (ea.cmdidx != CMD_SIZE)
+ ea.addr_type = cmdnames[(int)ea.cmdidx].cmd_addr_type;
+ else
+ ea.addr_type = ADDR_LINES;
+
+ /* :wincmd range depends on the argument. */
+ if (ea.cmdidx == CMD_wincmd && p != NULL)
+ get_wincmd_addr_type(skipwhite(p), &ea);
+ }
+
+ ea.cmd = cmd;
+ if (parse_cmd_address(&ea, &errormsg, FALSE) == FAIL)
+ goto doend;
+
+/*
+ * 5. Parse the command.
+ */
+
+ /*
+ * Skip ':' and any white space
+ */
+ ea.cmd = skipwhite(ea.cmd);
+ while (*ea.cmd == ':')
+ ea.cmd = skipwhite(ea.cmd + 1);
+
+ /*
+ * If we got a line, but no command, then go to the line.
+ * If we find a '|' or '\n' we set ea.nextcmd.
+ */
+ if (*ea.cmd == NUL || *ea.cmd == '"'
+ || (ea.nextcmd = check_nextcmd(ea.cmd)) != NULL)
+ {
+ /*
+ * strange vi behaviour:
+ * ":3" jumps to line 3
+ * ":3|..." prints line 3
+ * ":|" prints current line
+ */
+ if (ea.skip) /* skip this if inside :if */
+ goto doend;
+ if (*ea.cmd == '|' || (exmode_active && ea.line1 != ea.line2))
+ {
+ ea.cmdidx = CMD_print;
+ ea.argt = RANGE+COUNT+TRLBAR;
+ if ((errormsg = invalid_range(&ea)) == NULL)
+ {
+ correct_range(&ea);
+ ex_print(&ea);
+ }
+ }
+ else if (ea.addr_count != 0)
+ {
+ if (ea.line2 > curbuf->b_ml.ml_line_count)
+ {
+ /* With '-' in 'cpoptions' a line number past the file is an
+ * error, otherwise put it at the end of the file. */
+ if (vim_strchr(p_cpo, CPO_MINUS) != NULL)
+ ea.line2 = -1;
+ else
+ ea.line2 = curbuf->b_ml.ml_line_count;
+ }
+
+ if (ea.line2 < 0)
+ errormsg = _(e_invrange);
+ else
+ {
+ if (ea.line2 == 0)
+ curwin->w_cursor.lnum = 1;
+ else
+ curwin->w_cursor.lnum = ea.line2;
+ beginline(BL_SOL | BL_FIX);
+ }
+ }
+ goto doend;
+ }
+
+ /* If this looks like an undefined user command and there are CmdUndefined
+ * autocommands defined, trigger the matching autocommands. */
+ if (p != NULL && ea.cmdidx == CMD_SIZE && !ea.skip
+ && ASCII_ISUPPER(*ea.cmd)
+ && has_cmdundefined())
+ {
+ int ret;
+
+ p = ea.cmd;
+ while (ASCII_ISALNUM(*p))
+ ++p;
+ p = vim_strnsave(ea.cmd, (int)(p - ea.cmd));
+ ret = apply_autocmds(EVENT_CMDUNDEFINED, p, p, TRUE, NULL);
+ vim_free(p);
+ /* If the autocommands did something and didn't cause an error, try
+ * finding the command again. */
+ p = (ret
+#ifdef FEAT_EVAL
+ && !aborting()
+#endif
+ ) ? find_command(&ea, NULL) : ea.cmd;
+ }
+
+#ifdef FEAT_USR_CMDS
+ if (p == NULL)
+ {
+ if (!ea.skip)
+ errormsg = _("E464: Ambiguous use of user-defined command");
+ goto doend;
+ }
+ /* Check for wrong commands. */
+ if (*p == '!' && ea.cmd[1] == 0151 && ea.cmd[0] == 78
+ && !IS_USER_CMDIDX(ea.cmdidx))
+ {
+ errormsg = uc_fun_cmd();
+ goto doend;
+ }
+#endif
+ if (ea.cmdidx == CMD_SIZE)
+ {
+ if (!ea.skip)
+ {
+ STRCPY(IObuff, _("E492: Not an editor command"));
+ if (!sourcing)
+ {
+ /* If the modifier was parsed OK the error must be in the
+ * following command */
+ if (after_modifier != NULL)
+ append_command(after_modifier);
+ else
+ append_command(*cmdlinep);
+ }
+ errormsg = (char *)IObuff;
+ did_emsg_syntax = TRUE;
+ }
+ goto doend;
+ }
+
+ ni = (!IS_USER_CMDIDX(ea.cmdidx)
+ && (cmdnames[ea.cmdidx].cmd_func == ex_ni
+#ifdef HAVE_EX_SCRIPT_NI
+ || cmdnames[ea.cmdidx].cmd_func == ex_script_ni
+#endif
+ ));
+
+#ifndef FEAT_EVAL
+ /*
+ * When the expression evaluation is disabled, recognize the ":if" and
+ * ":endif" commands and ignore everything in between it.
+ */
+ if (ea.cmdidx == CMD_if)
+ ++if_level;
+ if (if_level)
+ {
+ if (ea.cmdidx == CMD_endif)
+ --if_level;
+ goto doend;
+ }
+
+#endif
+
+ /* forced commands */
+ if (*p == '!' && ea.cmdidx != CMD_substitute
+ && ea.cmdidx != CMD_smagic && ea.cmdidx != CMD_snomagic)
+ {
+ ++p;
+ ea.forceit = TRUE;
+ }
+ else
+ ea.forceit = FALSE;
+
+/*
+ * 6. Parse arguments.
+ */
+ if (!IS_USER_CMDIDX(ea.cmdidx))
+ ea.argt = (long)cmdnames[(int)ea.cmdidx].cmd_argt;
+
+ if (!ea.skip)
+ {
+#ifdef HAVE_SANDBOX
+ if (sandbox != 0 && !(ea.argt & SBOXOK))
+ {
+ /* Command not allowed in sandbox. */
+ errormsg = _(e_sandbox);
+ goto doend;
+ }
+#endif
+ if (!curbuf->b_p_ma && (ea.argt & MODIFY))
+ {
+ /* Command not allowed in non-'modifiable' buffer */
+ errormsg = _(e_modifiable);
+ goto doend;
+ }
+
+ if (text_locked() && !(ea.argt & CMDWIN)
+ && !IS_USER_CMDIDX(ea.cmdidx))
+ {
+ /* Command not allowed when editing the command line. */
+ errormsg = _(get_text_locked_msg());
+ goto doend;
+ }
+
+ /* Disallow editing another buffer when "curbuf_lock" is set.
+ * Do allow ":checktime" (it is postponed).
+ * Do allow ":edit" (check for an argument later).
+ * Do allow ":file" with no arguments (check for an argument later). */
+ if (!(ea.argt & CMDWIN)
+ && ea.cmdidx != CMD_checktime
+ && ea.cmdidx != CMD_edit
+ && ea.cmdidx != CMD_file
+ && !IS_USER_CMDIDX(ea.cmdidx)
+ && curbuf_locked())
+ goto doend;
+
+ if (!ni && !(ea.argt & RANGE) && ea.addr_count > 0)
+ {
+ /* no range allowed */
+ errormsg = _(e_norange);
+ goto doend;
+ }
+ }
+
+ if (!ni && !(ea.argt & BANG) && ea.forceit) /* no <!> allowed */
+ {
+ errormsg = _(e_nobang);
+ goto doend;
+ }
+
+ /*
+ * Don't complain about the range if it is not used
+ * (could happen if line_count is accidentally set to 0).
+ */
+ if (!ea.skip && !ni)
+ {
+ /*
+ * If the range is backwards, ask for confirmation and, if given, swap
+ * ea.line1 & ea.line2 so it's forwards again.
+ * When global command is busy, don't ask, will fail below.
+ */
+ if (!global_busy && ea.line1 > ea.line2)
+ {
+ if (msg_silent == 0)
+ {
+ if (sourcing || exmode_active)
+ {
+ errormsg = _("E493: Backwards range given");
+ goto doend;
+ }
+ if (ask_yesno((char_u *)
+ _("Backwards range given, OK to swap"), FALSE) != 'y')
+ goto doend;
+ }
+ lnum = ea.line1;
+ ea.line1 = ea.line2;
+ ea.line2 = lnum;
+ }
+ if ((errormsg = invalid_range(&ea)) != NULL)
+ goto doend;
+ }
+
+ if ((ea.argt & NOTADR) && ea.addr_count == 0) /* default is 1, not cursor */
+ ea.line2 = 1;
+
+ correct_range(&ea);
+
+#ifdef FEAT_FOLDING
+ if (((ea.argt & WHOLEFOLD) || ea.addr_count >= 2) && !global_busy
+ && ea.addr_type == ADDR_LINES)
+ {
+ /* Put the first line at the start of a closed fold, put the last line
+ * at the end of a closed fold. */
+ (void)hasFolding(ea.line1, &ea.line1, NULL);
+ (void)hasFolding(ea.line2, NULL, &ea.line2);
+ }
+#endif
+
+#ifdef FEAT_QUICKFIX
+ /*
+ * For the ":make" and ":grep" commands we insert the 'makeprg'/'grepprg'
+ * option here, so things like % get expanded.
+ */
+ p = replace_makeprg(&ea, p, cmdlinep);
+ if (p == NULL)
+ goto doend;
+#endif
+
+ /*
+ * Skip to start of argument.
+ * Don't do this for the ":!" command, because ":!! -l" needs the space.
+ */
+ if (ea.cmdidx == CMD_bang)
+ ea.arg = p;
+ else
+ ea.arg = skipwhite(p);
+
+ // ":file" cannot be run with an argument when "curbuf_lock" is set
+ if (ea.cmdidx == CMD_file && *ea.arg != NUL && curbuf_locked())
+ goto doend;
+
+ /*
+ * Check for "++opt=val" argument.
+ * Must be first, allow ":w ++enc=utf8 !cmd"
+ */
+ if (ea.argt & ARGOPT)
+ while (ea.arg[0] == '+' && ea.arg[1] == '+')
+ if (getargopt(&ea) == FAIL && !ni)
+ {
+ errormsg = _(e_invarg);
+ goto doend;
+ }
+
+ if (ea.cmdidx == CMD_write || ea.cmdidx == CMD_update)
+ {
+ if (*ea.arg == '>') /* append */
+ {
+ if (*++ea.arg != '>') /* typed wrong */
+ {
+ errormsg = _("E494: Use w or w>>");
+ goto doend;
+ }
+ ea.arg = skipwhite(ea.arg + 1);
+ ea.append = TRUE;
+ }
+ else if (*ea.arg == '!' && ea.cmdidx == CMD_write) /* :w !filter */
+ {
+ ++ea.arg;
+ ea.usefilter = TRUE;
+ }
+ }
+
+ if (ea.cmdidx == CMD_read)
+ {
+ if (ea.forceit)
+ {
+ ea.usefilter = TRUE; /* :r! filter if ea.forceit */
+ ea.forceit = FALSE;
+ }
+ else if (*ea.arg == '!') /* :r !filter */
+ {
+ ++ea.arg;
+ ea.usefilter = TRUE;
+ }
+ }
+
+ if (ea.cmdidx == CMD_lshift || ea.cmdidx == CMD_rshift)
+ {
+ ea.amount = 1;
+ while (*ea.arg == *ea.cmd) /* count number of '>' or '<' */
+ {
+ ++ea.arg;
+ ++ea.amount;
+ }
+ ea.arg = skipwhite(ea.arg);
+ }
+
+ /*
+ * Check for "+command" argument, before checking for next command.
+ * Don't do this for ":read !cmd" and ":write !cmd".
+ */
+ if ((ea.argt & EDITCMD) && !ea.usefilter)
+ ea.do_ecmd_cmd = getargcmd(&ea.arg);
+
+ /*
+ * Check for '|' to separate commands and '"' to start comments.
+ * Don't do this for ":read !cmd" and ":write !cmd".
+ */
+ if ((ea.argt & TRLBAR) && !ea.usefilter)
+ separate_nextcmd(&ea);
+
+ /*
+ * Check for <newline> to end a shell command.
+ * Also do this for ":read !cmd", ":write !cmd" and ":global".
+ * Any others?
+ */
+ else if (ea.cmdidx == CMD_bang
+ || ea.cmdidx == CMD_terminal
+ || ea.cmdidx == CMD_global
+ || ea.cmdidx == CMD_vglobal
+ || ea.usefilter)
+ {
+ for (p = ea.arg; *p; ++p)
+ {
+ /* Remove one backslash before a newline, so that it's possible to
+ * pass a newline to the shell and also a newline that is preceded
+ * with a backslash. This makes it impossible to end a shell
+ * command in a backslash, but that doesn't appear useful.
+ * Halving the number of backslashes is incompatible with previous
+ * versions. */
+ if (*p == '\\' && p[1] == '\n')
+ STRMOVE(p, p + 1);
+ else if (*p == '\n')
+ {
+ ea.nextcmd = p + 1;
+ *p = NUL;
+ break;
+ }
+ }
+ }
+
+ if ((ea.argt & DFLALL) && ea.addr_count == 0)
+ {
+ buf_T *buf;
+
+ ea.line1 = 1;
+ switch (ea.addr_type)
+ {
+ case ADDR_LINES:
+ ea.line2 = curbuf->b_ml.ml_line_count;
+ break;
+ case ADDR_LOADED_BUFFERS:
+ buf = firstbuf;
+ while (buf->b_next != NULL && buf->b_ml.ml_mfp == NULL)
+ buf = buf->b_next;
+ ea.line1 = buf->b_fnum;
+ buf = lastbuf;
+ while (buf->b_prev != NULL && buf->b_ml.ml_mfp == NULL)
+ buf = buf->b_prev;
+ ea.line2 = buf->b_fnum;
+ break;
+ case ADDR_BUFFERS:
+ ea.line1 = firstbuf->b_fnum;
+ ea.line2 = lastbuf->b_fnum;
+ break;
+ case ADDR_WINDOWS:
+ ea.line2 = LAST_WIN_NR;
+ break;
+ case ADDR_TABS:
+ ea.line2 = LAST_TAB_NR;
+ break;
+ case ADDR_TABS_RELATIVE:
+ ea.line2 = 1;
+ break;
+ case ADDR_ARGUMENTS:
+ if (ARGCOUNT == 0)
+ ea.line1 = ea.line2 = 0;
+ else
+ ea.line2 = ARGCOUNT;
+ break;
+#ifdef FEAT_QUICKFIX
+ case ADDR_QUICKFIX:
+ ea.line2 = qf_get_size(&ea);
+ if (ea.line2 == 0)
+ ea.line2 = 1;
+ break;
+#endif
+ }
+ }
+
+ /* accept numbered register only when no count allowed (:put) */
+ if ( (ea.argt & REGSTR)
+ && *ea.arg != NUL
+ /* Do not allow register = for user commands */
+ && (!IS_USER_CMDIDX(ea.cmdidx) || *ea.arg != '=')
+ && !((ea.argt & COUNT) && VIM_ISDIGIT(*ea.arg)))
+ {
+#ifndef FEAT_CLIPBOARD
+ /* check these explicitly for a more specific error message */
+ if (*ea.arg == '*' || *ea.arg == '+')
+ {
+ errormsg = _(e_invalidreg);
+ goto doend;
+ }
+#endif
+ if (valid_yank_reg(*ea.arg, (ea.cmdidx != CMD_put
+ && !IS_USER_CMDIDX(ea.cmdidx))))
+ {
+ ea.regname = *ea.arg++;
+#ifdef FEAT_EVAL
+ /* for '=' register: accept the rest of the line as an expression */
+ if (ea.arg[-1] == '=' && ea.arg[0] != NUL)
+ {
+ set_expr_line(vim_strsave(ea.arg));
+ ea.arg += STRLEN(ea.arg);
+ }
+#endif
+ ea.arg = skipwhite(ea.arg);
+ }
+ }
+
+ /*
+ * Check for a count. When accepting a BUFNAME, don't use "123foo" as a
+ * count, it's a buffer name.
+ */
+ if ((ea.argt & COUNT) && VIM_ISDIGIT(*ea.arg)
+ && (!(ea.argt & BUFNAME) || *(p = skipdigits(ea.arg)) == NUL
+ || VIM_ISWHITE(*p)))
+ {
+ n = getdigits(&ea.arg);
+ ea.arg = skipwhite(ea.arg);
+ if (n <= 0 && !ni && (ea.argt & ZEROR) == 0)
+ {
+ errormsg = _(e_zerocount);
+ goto doend;
+ }
+ if (ea.argt & NOTADR) /* e.g. :buffer 2, :sleep 3 */
+ {
+ ea.line2 = n;
+ if (ea.addr_count == 0)
+ ea.addr_count = 1;
+ }
+ else
+ {
+ ea.line1 = ea.line2;
+ ea.line2 += n - 1;
+ ++ea.addr_count;
+ /*
+ * Be vi compatible: no error message for out of range.
+ */
+ if (ea.addr_type == ADDR_LINES
+ && ea.line2 > curbuf->b_ml.ml_line_count)
+ ea.line2 = curbuf->b_ml.ml_line_count;
+ }
+ }
+
+ /*
+ * Check for flags: 'l', 'p' and '#'.
+ */
+ if (ea.argt & EXFLAGS)
+ get_flags(&ea);
+ /* no arguments allowed */
+ if (!ni && !(ea.argt & EXTRA) && *ea.arg != NUL
+ && *ea.arg != '"' && (*ea.arg != '|' || (ea.argt & TRLBAR) == 0))
+ {
+ errormsg = _(e_trailing);
+ goto doend;
+ }
+
+ if (!ni && (ea.argt & NEEDARG) && *ea.arg == NUL)
+ {
+ errormsg = _(e_argreq);
+ goto doend;
+ }
+
+#ifdef FEAT_EVAL
+ /*
+ * Skip the command when it's not going to be executed.
+ * The commands like :if, :endif, etc. always need to be executed.
+ * Also make an exception for commands that handle a trailing command
+ * themselves.
+ */
+ if (ea.skip)
+ {
+ switch (ea.cmdidx)
+ {
+ /* commands that need evaluation */
+ case CMD_while:
+ case CMD_endwhile:
+ case CMD_for:
+ case CMD_endfor:
+ case CMD_if:
+ case CMD_elseif:
+ case CMD_else:
+ case CMD_endif:
+ case CMD_try:
+ case CMD_catch:
+ case CMD_finally:
+ case CMD_endtry:
+ case CMD_function:
+ break;
+
+ /* Commands that handle '|' themselves. Check: A command should
+ * either have the TRLBAR flag, appear in this list or appear in
+ * the list at ":help :bar". */
+ case CMD_aboveleft:
+ case CMD_and:
+ case CMD_belowright:
+ case CMD_botright:
+ case CMD_browse:
+ case CMD_call:
+ case CMD_confirm:
+ case CMD_delfunction:
+ case CMD_djump:
+ case CMD_dlist:
+ case CMD_dsearch:
+ case CMD_dsplit:
+ case CMD_echo:
+ case CMD_echoerr:
+ case CMD_echomsg:
+ case CMD_echon:
+ case CMD_execute:
+ case CMD_filter:
+ case CMD_help:
+ case CMD_hide:
+ case CMD_ijump:
+ case CMD_ilist:
+ case CMD_isearch:
+ case CMD_isplit:
+ case CMD_keepalt:
+ case CMD_keepjumps:
+ case CMD_keepmarks:
+ case CMD_keeppatterns:
+ case CMD_leftabove:
+ case CMD_let:
+ case CMD_lockmarks:
+ case CMD_lua:
+ case CMD_match:
+ case CMD_mzscheme:
+ case CMD_noautocmd:
+ case CMD_noswapfile:
+ case CMD_perl:
+ case CMD_psearch:
+ case CMD_python:
+ case CMD_py3:
+ case CMD_python3:
+ case CMD_return:
+ case CMD_rightbelow:
+ case CMD_ruby:
+ case CMD_silent:
+ case CMD_smagic:
+ case CMD_snomagic:
+ case CMD_substitute:
+ case CMD_syntax:
+ case CMD_tab:
+ case CMD_tcl:
+ case CMD_throw:
+ case CMD_tilde:
+ case CMD_topleft:
+ case CMD_unlet:
+ case CMD_verbose:
+ case CMD_vertical:
+ case CMD_wincmd:
+ break;
+
+ default: goto doend;
+ }
+ }
+#endif
+
+ if (ea.argt & XFILE)
+ {
+ if (expand_filename(&ea, cmdlinep, &errormsg) == FAIL)
+ goto doend;
+ }
+
+ /*
+ * Accept buffer name. Cannot be used at the same time with a buffer
+ * number. Don't do this for a user command.
+ */
+ if ((ea.argt & BUFNAME) && *ea.arg != NUL && ea.addr_count == 0
+ && !IS_USER_CMDIDX(ea.cmdidx))
+ {
+ /*
+ * :bdelete, :bwipeout and :bunload take several arguments, separated
+ * by spaces: find next space (skipping over escaped characters).
+ * The others take one argument: ignore trailing spaces.
+ */
+ if (ea.cmdidx == CMD_bdelete || ea.cmdidx == CMD_bwipeout
+ || ea.cmdidx == CMD_bunload)
+ p = skiptowhite_esc(ea.arg);
+ else
+ {
+ p = ea.arg + STRLEN(ea.arg);
+ while (p > ea.arg && VIM_ISWHITE(p[-1]))
+ --p;
+ }
+ ea.line2 = buflist_findpat(ea.arg, p, (ea.argt & BUFUNL) != 0,
+ FALSE, FALSE);
+ if (ea.line2 < 0) /* failed */
+ goto doend;
+ ea.addr_count = 1;
+ ea.arg = skipwhite(p);
+ }
+
+ /* The :try command saves the emsg_silent flag, reset it here when
+ * ":silent! try" was used, it should only apply to :try itself. */
+ if (ea.cmdidx == CMD_try && ea.did_esilent > 0)
+ {
+ emsg_silent -= ea.did_esilent;
+ if (emsg_silent < 0)
+ emsg_silent = 0;
+ ea.did_esilent = 0;
+ }
+
+/*
+ * 7. Execute the command.
+ */
+
+#ifdef FEAT_USR_CMDS
+ if (IS_USER_CMDIDX(ea.cmdidx))
+ {
+ /*
+ * Execute a user-defined command.
+ */
+ do_ucmd(&ea);
+ }
+ else
+#endif
+ {
+ /*
+ * Call the function to execute the command.
+ */
+ ea.errmsg = NULL;
+ (cmdnames[ea.cmdidx].cmd_func)(&ea);
+ if (ea.errmsg != NULL)
+ errormsg = _(ea.errmsg);
+ }
+
+#ifdef FEAT_EVAL
+ /*
+ * If the command just executed called do_cmdline(), any throw or ":return"
+ * or ":finish" encountered there must also check the cstack of the still
+ * active do_cmdline() that called this do_one_cmd(). Rethrow an uncaught
+ * exception, or reanimate a returned function or finished script file and
+ * return or finish it again.
+ */
+ if (need_rethrow)
+ do_throw(cstack);
+ else if (check_cstack)
+ {
+ if (source_finished(fgetline, cookie))
+ do_finish(&ea, TRUE);
+ else if (getline_equal(fgetline, cookie, get_func_line)
+ && current_func_returned())
+ do_return(&ea, TRUE, FALSE, NULL);
+ }
+ need_rethrow = check_cstack = FALSE;
+#endif
+
+doend:
+ if (curwin->w_cursor.lnum == 0) /* can happen with zero line number */
+ {
+ curwin->w_cursor.lnum = 1;
+ curwin->w_cursor.col = 0;
+ }
+
+ if (errormsg != NULL && *errormsg != NUL && !did_emsg)
+ {
+ if (sourcing)
+ {
+ if (errormsg != (char *)IObuff)
+ {
+ STRCPY(IObuff, errormsg);
+ errormsg = (char *)IObuff;
+ }
+ append_command(*cmdlinep);
+ }
+ emsg(errormsg);
+ }
+#ifdef FEAT_EVAL
+ do_errthrow(cstack,
+ (ea.cmdidx != CMD_SIZE && !IS_USER_CMDIDX(ea.cmdidx))
+ ? cmdnames[(int)ea.cmdidx].cmd_name : (char_u *)NULL);
+#endif
+
+ if (ea.verbose_save >= 0)
+ p_verbose = ea.verbose_save;
+
+ free_cmdmod();
+ cmdmod = save_cmdmod;
+
+ if (ea.save_msg_silent != -1)
+ {
+ /* messages could be enabled for a serious error, need to check if the
+ * counters don't become negative */
+ if (!did_emsg || msg_silent > ea.save_msg_silent)
+ msg_silent = ea.save_msg_silent;
+ emsg_silent -= ea.did_esilent;
+ if (emsg_silent < 0)
+ emsg_silent = 0;
+ /* Restore msg_scroll, it's set by file I/O commands, even when no
+ * message is actually displayed. */
+ msg_scroll = save_msg_scroll;
+
+ /* "silent reg" or "silent echo x" inside "redir" leaves msg_col
+ * somewhere in the line. Put it back in the first column. */
+ if (redirecting())
+ msg_col = 0;
+ }
+
+#ifdef HAVE_SANDBOX
+ if (ea.did_sandbox)
+ --sandbox;
+#endif
+
+ if (ea.nextcmd && *ea.nextcmd == NUL) /* not really a next command */
+ ea.nextcmd = NULL;
+
+#ifdef FEAT_EVAL
+ --ex_nesting_level;
+#endif
+
+ return ea.nextcmd;
+}
+#if (_MSC_VER == 1200)
+ #pragma optimize( "", on )
+#endif
+
+/*
+ * Parse and skip over command modifiers:
+ * - update eap->cmd
+ * - store flags in "cmdmod".
+ * - Set ex_pressedreturn for an empty command line.
+ * - set msg_silent for ":silent"
+ * - set 'eventignore' to "all" for ":noautocmd"
+ * - set p_verbose for ":verbose"
+ * - Increment "sandbox" for ":sandbox"
+ * When "skip_only" is TRUE the global variables are not changed, except for
+ * "cmdmod".
+ * Return FAIL when the command is not to be executed.
+ * May set "errormsg" to an error message.
+ */
+ int
+parse_command_modifiers(exarg_T *eap, char **errormsg, int skip_only)
+{
+ char_u *p;
+
+ vim_memset(&cmdmod, 0, sizeof(cmdmod));
+ eap->verbose_save = -1;
+ eap->save_msg_silent = -1;
+
+ // Repeat until no more command modifiers are found.
+ for (;;)
+ {
+ while (*eap->cmd == ' ' || *eap->cmd == '\t' || *eap->cmd == ':')
+ ++eap->cmd;
+
+ /* in ex mode, an empty line works like :+ */
+ if (*eap->cmd == NUL && exmode_active
+ && (getline_equal(eap->getline, eap->cookie, getexmodeline)
+ || getline_equal(eap->getline, eap->cookie, getexline))
+ && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
+ {
+ eap->cmd = (char_u *)"+";
+ if (!skip_only)
+ ex_pressedreturn = TRUE;
+ }
+
+ /* ignore comment and empty lines */
+ if (*eap->cmd == '"')
+ return FAIL;
+ if (*eap->cmd == NUL)
+ {
+ if (!skip_only)
+ ex_pressedreturn = TRUE;
+ return FAIL;
+ }
+
+ p = skip_range(eap->cmd, NULL);
+ switch (*p)
+ {
+ /* When adding an entry, also modify cmd_exists(). */
+ case 'a': if (!checkforcmd(&eap->cmd, "aboveleft", 3))
+ break;
+ cmdmod.split |= WSP_ABOVE;
+ continue;
+
+ case 'b': if (checkforcmd(&eap->cmd, "belowright", 3))
+ {
+ cmdmod.split |= WSP_BELOW;
+ continue;
+ }
+ if (checkforcmd(&eap->cmd, "browse", 3))
+ {
+#ifdef FEAT_BROWSE_CMD
+ cmdmod.browse = TRUE;
+#endif
+ continue;
+ }
+ if (!checkforcmd(&eap->cmd, "botright", 2))
+ break;
+ cmdmod.split |= WSP_BOT;
+ continue;
+
+ case 'c': if (!checkforcmd(&eap->cmd, "confirm", 4))
+ break;
+#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
+ cmdmod.confirm = TRUE;
+#endif
+ continue;
+
+ case 'k': if (checkforcmd(&eap->cmd, "keepmarks", 3))
+ {
+ cmdmod.keepmarks = TRUE;
+ continue;
+ }
+ if (checkforcmd(&eap->cmd, "keepalt", 5))
+ {
+ cmdmod.keepalt = TRUE;
+ continue;
+ }
+ if (checkforcmd(&eap->cmd, "keeppatterns", 5))
+ {
+ cmdmod.keeppatterns = TRUE;
+ continue;
+ }
+ if (!checkforcmd(&eap->cmd, "keepjumps", 5))
+ break;
+ cmdmod.keepjumps = TRUE;
+ continue;
+
+ case 'f': /* only accept ":filter {pat} cmd" */
+ {
+ char_u *reg_pat;
+
+ if (!checkforcmd(&p, "filter", 4)
+ || *p == NUL || ends_excmd(*p))
+ break;
+ if (*p == '!')
+ {
+ cmdmod.filter_force = TRUE;
+ p = skipwhite(p + 1);
+ if (*p == NUL || ends_excmd(*p))
+ break;
+ }
+ if (skip_only)
+ p = skip_vimgrep_pat(p, NULL, NULL);
+ else
+ // NOTE: This puts a NUL after the pattern.
+ p = skip_vimgrep_pat(p, &reg_pat, NULL);
+ if (p == NULL || *p == NUL)
+ break;
+ if (!skip_only)
+ {
+ cmdmod.filter_regmatch.regprog =
+ vim_regcomp(reg_pat, RE_MAGIC);
+ if (cmdmod.filter_regmatch.regprog == NULL)
+ break;
+ }
+ eap->cmd = p;
+ continue;
+ }
+
+ /* ":hide" and ":hide | cmd" are not modifiers */
+ case 'h': if (p != eap->cmd || !checkforcmd(&p, "hide", 3)
+ || *p == NUL || ends_excmd(*p))
+ break;
+ eap->cmd = p;
+ cmdmod.hide = TRUE;
+ continue;
+
+ case 'l': if (checkforcmd(&eap->cmd, "lockmarks", 3))
+ {
+ cmdmod.lockmarks = TRUE;
+ continue;
+ }
+
+ if (!checkforcmd(&eap->cmd, "leftabove", 5))
+ break;
+ cmdmod.split |= WSP_ABOVE;
+ continue;
+
+ case 'n': if (checkforcmd(&eap->cmd, "noautocmd", 3))
+ {
+ if (cmdmod.save_ei == NULL && !skip_only)
+ {
+ /* Set 'eventignore' to "all". Restore the
+ * existing option value later. */
+ cmdmod.save_ei = vim_strsave(p_ei);
+ set_string_option_direct((char_u *)"ei", -1,
+ (char_u *)"all", OPT_FREE, SID_NONE);
+ }
+ continue;
+ }
+ if (!checkforcmd(&eap->cmd, "noswapfile", 3))
+ break;
+ cmdmod.noswapfile = TRUE;
+ continue;
+
+ case 'r': if (!checkforcmd(&eap->cmd, "rightbelow", 6))
+ break;
+ cmdmod.split |= WSP_BELOW;
+ continue;
+
+ case 's': if (checkforcmd(&eap->cmd, "sandbox", 3))
+ {
+#ifdef HAVE_SANDBOX
+ if (!skip_only)
+ {
+ if (!eap->did_sandbox)
+ ++sandbox;
+ eap->did_sandbox = TRUE;
+ }
+#endif
+ continue;
+ }
+ if (!checkforcmd(&eap->cmd, "silent", 3))
+ break;
+ if (!skip_only)
+ {
+ if (eap->save_msg_silent == -1)
+ eap->save_msg_silent = msg_silent;
+ ++msg_silent;
+ }
+ if (*eap->cmd == '!' && !VIM_ISWHITE(eap->cmd[-1]))
+ {
+ /* ":silent!", but not "silent !cmd" */
+ eap->cmd = skipwhite(eap->cmd + 1);
+ if (!skip_only)
+ {
+ ++emsg_silent;
+ ++eap->did_esilent;
+ }
+ }
+ continue;
+
+ case 't': if (checkforcmd(&p, "tab", 3))
+ {
+ if (!skip_only)
+ {
+ long tabnr = get_address(eap, &eap->cmd,
+ ADDR_TABS, eap->skip,
+ skip_only, FALSE, 1);
+ if (tabnr == MAXLNUM)
+ cmdmod.tab = tabpage_index(curtab) + 1;
+ else
+ {
+ if (tabnr < 0 || tabnr > LAST_TAB_NR)
+ {
+ *errormsg = _(e_invrange);
+ return FAIL;
+ }
+ cmdmod.tab = tabnr + 1;
+ }
+ }
+ eap->cmd = p;
+ continue;
+ }
+ if (!checkforcmd(&eap->cmd, "topleft", 2))
+ break;
+ cmdmod.split |= WSP_TOP;
+ continue;
+
+ case 'u': if (!checkforcmd(&eap->cmd, "unsilent", 3))
+ break;
+ if (!skip_only)
+ {
+ if (eap->save_msg_silent == -1)
+ eap->save_msg_silent = msg_silent;
+ msg_silent = 0;
+ }
+ continue;
+
+ case 'v': if (checkforcmd(&eap->cmd, "vertical", 4))
+ {
+ cmdmod.split |= WSP_VERT;
+ continue;
+ }
+ if (!checkforcmd(&p, "verbose", 4))
+ break;
+ if (!skip_only)
+ {
+ if (eap->verbose_save < 0)
+ eap->verbose_save = p_verbose;
+ if (vim_isdigit(*eap->cmd))
+ p_verbose = atoi((char *)eap->cmd);
+ else
+ p_verbose = 1;
+ }
+ eap->cmd = p;
+ continue;
+ }
+ break;
+ }
+
+ return OK;
+}
+
+/*
+ * Free contents of "cmdmod".
+ */
+ static void
+free_cmdmod(void)
+{
+ if (cmdmod.save_ei != NULL)
+ {
+ /* Restore 'eventignore' to the value before ":noautocmd". */
+ set_string_option_direct((char_u *)"ei", -1, cmdmod.save_ei,
+ OPT_FREE, SID_NONE);
+ free_string_option(cmdmod.save_ei);
+ }
+
+ if (cmdmod.filter_regmatch.regprog != NULL)
+ vim_regfree(cmdmod.filter_regmatch.regprog);
+}
+
+/*
+ * Parse the address range, if any, in "eap".
+ * May set the last search pattern, unless "silent" is TRUE.
+ * Return FAIL and set "errormsg" or return OK.
+ */
+ int
+parse_cmd_address(exarg_T *eap, char **errormsg, int silent)
+{
+ int address_count = 1;
+ linenr_T lnum;
+
+ // Repeat for all ',' or ';' separated addresses.
+ for (;;)
+ {
+ eap->line1 = eap->line2;
+ switch (eap->addr_type)
+ {
+ case ADDR_LINES:
+ // default is current line number
+ eap->line2 = curwin->w_cursor.lnum;
+ break;
+ case ADDR_WINDOWS:
+ eap->line2 = CURRENT_WIN_NR;
+ break;
+ case ADDR_ARGUMENTS:
+ eap->line2 = curwin->w_arg_idx + 1;
+ if (eap->line2 > ARGCOUNT)
+ eap->line2 = ARGCOUNT;
+ break;
+ case ADDR_LOADED_BUFFERS:
+ case ADDR_BUFFERS:
+ eap->line2 = curbuf->b_fnum;
+ break;
+ case ADDR_TABS:
+ eap->line2 = CURRENT_TAB_NR;
+ break;
+ case ADDR_TABS_RELATIVE:
+ eap->line2 = 1;
+ break;
+#ifdef FEAT_QUICKFIX
+ case ADDR_QUICKFIX:
+ eap->line2 = qf_get_cur_valid_idx(eap);
+ break;
+#endif
+ }
+ eap->cmd = skipwhite(eap->cmd);
+ lnum = get_address(eap, &eap->cmd, eap->addr_type, eap->skip, silent,
+ eap->addr_count == 0, address_count++);
+ if (eap->cmd == NULL) // error detected
+ return FAIL;
+ if (lnum == MAXLNUM)
+ {
+ if (*eap->cmd == '%') // '%' - all lines
+ {
+ ++eap->cmd;
+ switch (eap->addr_type)
+ {
+ case ADDR_LINES:
+ eap->line1 = 1;
+ eap->line2 = curbuf->b_ml.ml_line_count;
+ break;
+ case ADDR_LOADED_BUFFERS:
+ {
+ buf_T *buf = firstbuf;
+
+ while (buf->b_next != NULL
+ && buf->b_ml.ml_mfp == NULL)
+ buf = buf->b_next;
+ eap->line1 = buf->b_fnum;
+ buf = lastbuf;
+ while (buf->b_prev != NULL
+ && buf->b_ml.ml_mfp == NULL)
+ buf = buf->b_prev;
+ eap->line2 = buf->b_fnum;
+ break;
+ }
+ case ADDR_BUFFERS:
+ eap->line1 = firstbuf->b_fnum;
+ eap->line2 = lastbuf->b_fnum;
+ break;
+ case ADDR_WINDOWS:
+ case ADDR_TABS:
+ if (IS_USER_CMDIDX(eap->cmdidx))
+ {
+ eap->line1 = 1;
+ eap->line2 = eap->addr_type == ADDR_WINDOWS
+ ? LAST_WIN_NR : LAST_TAB_NR;
+ }
+ else
+ {
+ // there is no Vim command which uses '%' and
+ // ADDR_WINDOWS or ADDR_TABS
+ *errormsg = _(e_invrange);
+ return FAIL;
+ }
+ break;
+ case ADDR_TABS_RELATIVE:
+ case ADDR_OTHER:
+ *errormsg = _(e_invrange);
+ return FAIL;
+ case ADDR_ARGUMENTS:
+ if (ARGCOUNT == 0)
+ eap->line1 = eap->line2 = 0;
+ else
+ {
+ eap->line1 = 1;
+ eap->line2 = ARGCOUNT;
+ }
+ break;
+#ifdef FEAT_QUICKFIX
+ case ADDR_QUICKFIX:
+ eap->line1 = 1;
+ eap->line2 = qf_get_size(eap);
+ if (eap->line2 == 0)
+ eap->line2 = 1;
+ break;
+#endif
+ }
+ ++eap->addr_count;
+ }
+ else if (*eap->cmd == '*' && vim_strchr(p_cpo, CPO_STAR) == NULL)
+ {
+ pos_T *fp;
+
+ // '*' - visual area
+ if (eap->addr_type != ADDR_LINES)
+ {
+ *errormsg = _(e_invrange);
+ return FAIL;
+ }
+
+ ++eap->cmd;
+ if (!eap->skip)
+ {
+ fp = getmark('<', FALSE);
+ if (check_mark(fp) == FAIL)
+ return FAIL;
+ eap->line1 = fp->lnum;
+ fp = getmark('>', FALSE);
+ if (check_mark(fp) == FAIL)
+ return FAIL;
+ eap->line2 = fp->lnum;
+ ++eap->addr_count;
+ }
+ }
+ }
+ else
+ eap->line2 = lnum;
+ eap->addr_count++;
+
+ if (*eap->cmd == ';')
+ {
+ if (!eap->skip)
+ {
+ curwin->w_cursor.lnum = eap->line2;
+ // don't leave the cursor on an illegal line or column
+ check_cursor();
+ }
+ }
+ else if (*eap->cmd != ',')
+ break;
+ ++eap->cmd;
+ }
+
+ // One address given: set start and end lines.
+ if (eap->addr_count == 1)
+ {
+ eap->line1 = eap->line2;
+ // ... but only implicit: really no address given
+ if (lnum == MAXLNUM)
+ eap->addr_count = 0;
+ }
+ return OK;
+}
+
+/*
+ * Check for an Ex command with optional tail.
+ * If there is a match advance "pp" to the argument and return TRUE.
+ */
+ int
+checkforcmd(
+ char_u **pp, /* start of command */
+ char *cmd, /* name of command */
+ int len) /* required length */
+{
+ int i;
+
+ for (i = 0; cmd[i] != NUL; ++i)
+ if (((char_u *)cmd)[i] != (*pp)[i])
+ break;
+ if (i >= len && !isalpha((*pp)[i]))
+ {
+ *pp = skipwhite(*pp + i);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * Append "cmd" to the error message in IObuff.
+ * Takes care of limiting the length and handling 0xa0, which would be
+ * invisible otherwise.
+ */
+ static void
+append_command(char_u *cmd)
+{
+ char_u *s = cmd;
+ char_u *d;
+
+ STRCAT(IObuff, ": ");
+ d = IObuff + STRLEN(IObuff);
+ while (*s != NUL && d - IObuff < IOSIZE - 7)
+ {
+ if (enc_utf8 ? (s[0] == 0xc2 && s[1] == 0xa0) : *s == 0xa0)
+ {
+ s += enc_utf8 ? 2 : 1;
+ STRCPY(d, "<a0>");
+ d += 4;
+ }
+ else
+ MB_COPY_CHAR(s, d);
+ }
+ *d = NUL;
+}
+
+/*
+ * Find an Ex command by its name, either built-in or user.
+ * Start of the name can be found at eap->cmd.
+ * Returns pointer to char after the command name.
+ * "full" is set to TRUE if the whole command name matched.
+ * Returns NULL for an ambiguous user command.
+ */
+ static char_u *
+find_command(exarg_T *eap, int *full UNUSED)
+{
+ int len;
+ char_u *p;
+ int i;
+
+ /*
+ * Isolate the command and search for it in the command table.
+ * Exceptions:
+ * - the 'k' command can directly be followed by any character.
+ * - the 's' command can be followed directly by 'c', 'g', 'i', 'I' or 'r'
+ * but :sre[wind] is another command, as are :scr[iptnames],
+ * :scs[cope], :sim[alt], :sig[ns] and :sil[ent].
+ * - the "d" command can directly be followed by 'l' or 'p' flag.
+ */
+ p = eap->cmd;
+ if (*p == 'k')
+ {
+ eap->cmdidx = CMD_k;
+ ++p;
+ }
+ else if (p[0] == 's'
+ && ((p[1] == 'c' && (p[2] == NUL || (p[2] != 's' && p[2] != 'r'
+ && (p[3] == NUL || (p[3] != 'i' && p[4] != 'p')))))
+ || p[1] == 'g'
+ || (p[1] == 'i' && p[2] != 'm' && p[2] != 'l' && p[2] != 'g')
+ || p[1] == 'I'
+ || (p[1] == 'r' && p[2] != 'e')))
+ {
+ eap->cmdidx = CMD_substitute;
+ ++p;
+ }
+ else
+ {
+ while (ASCII_ISALPHA(*p))
+ ++p;
+ /* for python 3.x support ":py3", ":python3", ":py3file", etc. */
+ if (eap->cmd[0] == 'p' && eap->cmd[1] == 'y')
+ while (ASCII_ISALNUM(*p))
+ ++p;
+
+ /* check for non-alpha command */
+ if (p == eap->cmd && vim_strchr((char_u *)"@*!=><&~#", *p) != NULL)
+ ++p;
+ len = (int)(p - eap->cmd);
+ if (*eap->cmd == 'd' && (p[-1] == 'l' || p[-1] == 'p'))
+ {
+ /* Check for ":dl", ":dell", etc. to ":deletel": that's
+ * :delete with the 'l' flag. Same for 'p'. */
+ for (i = 0; i < len; ++i)
+ if (eap->cmd[i] != ((char_u *)"delete")[i])
+ break;
+ if (i == len - 1)
+ {
+ --len;
+ if (p[-1] == 'l')
+ eap->flags |= EXFLAG_LIST;
+ else
+ eap->flags |= EXFLAG_PRINT;
+ }
+ }
+
+ if (ASCII_ISLOWER(eap->cmd[0]))
+ {
+ int c1 = eap->cmd[0];
+ int c2 = eap->cmd[1];
+
+ if (command_count != (int)CMD_SIZE)
+ {
+ iemsg(_("E943: Command table needs to be updated, run 'make cmdidxs'"));
+ getout(1);
+ }
+
+ /* Use a precomputed index for fast look-up in cmdnames[]
+ * taking into account the first 2 letters of eap->cmd. */
+ eap->cmdidx = cmdidxs1[CharOrdLow(c1)];
+ if (ASCII_ISLOWER(c2))
+ eap->cmdidx += cmdidxs2[CharOrdLow(c1)][CharOrdLow(c2)];
+ }
+ else
+ eap->cmdidx = CMD_bang;
+
+ for ( ; (int)eap->cmdidx < (int)CMD_SIZE;
+ eap->cmdidx = (cmdidx_T)((int)eap->cmdidx + 1))
+ if (STRNCMP(cmdnames[(int)eap->cmdidx].cmd_name, (char *)eap->cmd,
+ (size_t)len) == 0)
+ {
+#ifdef FEAT_EVAL
+ if (full != NULL
+ && cmdnames[(int)eap->cmdidx].cmd_name[len] == NUL)
+ *full = TRUE;
+#endif
+ break;
+ }
+
+#ifdef FEAT_USR_CMDS
+ /* Look for a user defined command as a last resort. Let ":Print" be
+ * overruled by a user defined command. */
+ if ((eap->cmdidx == CMD_SIZE || eap->cmdidx == CMD_Print)
+ && *eap->cmd >= 'A' && *eap->cmd <= 'Z')
+ {
+ /* User defined commands may contain digits. */
+ while (ASCII_ISALNUM(*p))
+ ++p;
+ p = find_ucmd(eap, p, full, NULL, NULL);
+ }
+#endif
+ if (p == eap->cmd)
+ eap->cmdidx = CMD_SIZE;
+ }
+
+ return p;
+}
+
+#ifdef FEAT_USR_CMDS
+/*
+ * Search for a user command that matches "eap->cmd".
+ * Return cmdidx in "eap->cmdidx", flags in "eap->argt", idx in "eap->useridx".
+ * Return a pointer to just after the command.
+ * Return NULL if there is no matching command.
+ */
+ static char_u *
+find_ucmd(
+ exarg_T *eap,
+ char_u *p, /* end of the command (possibly including count) */
+ int *full, /* set to TRUE for a full match */
+ expand_T *xp, /* used for completion, NULL otherwise */
+ int *compl) /* completion flags or NULL */
+{
+ int len = (int)(p - eap->cmd);
+ int j, k, matchlen = 0;
+ ucmd_T *uc;
+ int found = FALSE;
+ int possible = FALSE;
+ char_u *cp, *np; /* Point into typed cmd and test name */
+ garray_T *gap;
+ int amb_local = FALSE; /* Found ambiguous buffer-local command,
+ only full match global is accepted. */
+
+ /*
+ * Look for buffer-local user commands first, then global ones.
+ */
+ gap = &curbuf->b_ucmds;
+ for (;;)
+ {
+ for (j = 0; j < gap->ga_len; ++j)
+ {
+ uc = USER_CMD_GA(gap, j);
+ cp = eap->cmd;
+ np = uc->uc_name;
+ k = 0;
+ while (k < len && *np != NUL && *cp++ == *np++)
+ k++;
+ if (k == len || (*np == NUL && vim_isdigit(eap->cmd[k])))
+ {
+ /* If finding a second match, the command is ambiguous. But
+ * not if a buffer-local command wasn't a full match and a
+ * global command is a full match. */
+ if (k == len && found && *np != NUL)
+ {
+ if (gap == &ucmds)
+ return NULL;
+ amb_local = TRUE;
+ }
+
+ if (!found || (k == len && *np == NUL))
+ {
+ /* If we matched up to a digit, then there could
+ * be another command including the digit that we
+ * should use instead.
+ */
+ if (k == len)
+ found = TRUE;
+ else
+ possible = TRUE;
+
+ if (gap == &ucmds)
+ eap->cmdidx = CMD_USER;
+ else
+ eap->cmdidx = CMD_USER_BUF;
+ eap->argt = (long)uc->uc_argt;
+ eap->useridx = j;
+ eap->addr_type = uc->uc_addr_type;
+
+# ifdef FEAT_CMDL_COMPL
+ if (compl != NULL)
+ *compl = uc->uc_compl;
+# ifdef FEAT_EVAL
+ if (xp != NULL)
+ {
+ xp->xp_arg = uc->uc_compl_arg;
+ xp->xp_script_ctx = uc->uc_script_ctx;
+ xp->xp_script_ctx.sc_lnum += sourcing_lnum;
+ }
+# endif
+# endif
+ /* Do not search for further abbreviations
+ * if this is an exact match. */
+ matchlen = k;
+ if (k == len && *np == NUL)
+ {
+ if (full != NULL)
+ *full = TRUE;
+ amb_local = FALSE;
+ break;
+ }
+ }
+ }
+ }
+
+ /* Stop if we found a full match or searched all. */
+ if (j < gap->ga_len || gap == &ucmds)
+ break;
+ gap = &ucmds;
+ }
+
+ /* Only found ambiguous matches. */
+ if (amb_local)
+ {
+ if (xp != NULL)
+ xp->xp_context = EXPAND_UNSUCCESSFUL;
+ return NULL;
+ }
+
+ /* The match we found may be followed immediately by a number. Move "p"
+ * back to point to it. */
+ if (found || possible)
+ return p + (matchlen - len);
+ return p;
+}
+#endif
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+static struct cmdmod
+{
+ char *name;
+ int minlen;
+ int has_count; /* :123verbose :3tab */
+} cmdmods[] = {
+ {"aboveleft", 3, FALSE},
+ {"belowright", 3, FALSE},
+ {"botright", 2, FALSE},
+ {"browse", 3, FALSE},
+ {"confirm", 4, FALSE},
+ {"filter", 4, FALSE},
+ {"hide", 3, FALSE},
+ {"keepalt", 5, FALSE},
+ {"keepjumps", 5, FALSE},
+ {"keepmarks", 3, FALSE},
+ {"keeppatterns", 5, FALSE},
+ {"leftabove", 5, FALSE},
+ {"lockmarks", 3, FALSE},
+ {"noautocmd", 3, FALSE},
+ {"noswapfile", 3, FALSE},
+ {"rightbelow", 6, FALSE},
+ {"sandbox", 3, FALSE},
+ {"silent", 3, FALSE},
+ {"tab", 3, TRUE},
+ {"topleft", 2, FALSE},
+ {"unsilent", 3, FALSE},
+ {"verbose", 4, TRUE},
+ {"vertical", 4, FALSE},
+};
+
+/*
+ * Return length of a command modifier (including optional count).
+ * Return zero when it's not a modifier.
+ */
+ int
+modifier_len(char_u *cmd)
+{
+ int i, j;
+ char_u *p = cmd;
+
+ if (VIM_ISDIGIT(*cmd))
+ p = skipwhite(skipdigits(cmd));
+ for (i = 0; i < (int)(sizeof(cmdmods) / sizeof(struct cmdmod)); ++i)
+ {
+ for (j = 0; p[j] != NUL; ++j)
+ if (p[j] != cmdmods[i].name[j])
+ break;
+ if (!ASCII_ISALPHA(p[j]) && j >= cmdmods[i].minlen
+ && (p == cmd || cmdmods[i].has_count))
+ return j + (int)(p - cmd);
+ }
+ return 0;
+}
+
+/*
+ * Return > 0 if an Ex command "name" exists.
+ * Return 2 if there is an exact match.
+ * Return 3 if there is an ambiguous match.
+ */
+ int
+cmd_exists(char_u *name)
+{
+ exarg_T ea;
+ int full = FALSE;
+ int i;
+ int j;
+ char_u *p;
+
+ /* Check command modifiers. */
+ for (i = 0; i < (int)(sizeof(cmdmods) / sizeof(struct cmdmod)); ++i)
+ {
+ for (j = 0; name[j] != NUL; ++j)
+ if (name[j] != cmdmods[i].name[j])
+ break;
+ if (name[j] == NUL && j >= cmdmods[i].minlen)
+ return (cmdmods[i].name[j] == NUL ? 2 : 1);
+ }
+
+ /* Check built-in commands and user defined commands.
+ * For ":2match" and ":3match" we need to skip the number. */
+ ea.cmd = (*name == '2' || *name == '3') ? name + 1 : name;
+ ea.cmdidx = (cmdidx_T)0;
+ p = find_command(&ea, &full);
+ if (p == NULL)
+ return 3;
+ if (vim_isdigit(*name) && ea.cmdidx != CMD_match)
+ return 0;
+ if (*skipwhite(p) != NUL)
+ return 0; /* trailing garbage */
+ return (ea.cmdidx == CMD_SIZE ? 0 : (full ? 2 : 1));
+}
+#endif
+
+/*
+ * This is all pretty much copied from do_one_cmd(), with all the extra stuff
+ * we don't need/want deleted. Maybe this could be done better if we didn't
+ * repeat all this stuff. The only problem is that they may not stay
+ * perfectly compatible with each other, but then the command line syntax
+ * probably won't change that much -- webb.
+ */
+ char_u *
+set_one_cmd_context(
+ expand_T *xp,
+ char_u *buff) /* buffer for command string */
+{
+ char_u *p;
+ char_u *cmd, *arg;
+ int len = 0;
+ exarg_T ea;
+#if defined(FEAT_USR_CMDS) && defined(FEAT_CMDL_COMPL)
+ int compl = EXPAND_NOTHING;
+#endif
+#ifdef FEAT_CMDL_COMPL
+ int delim;
+#endif
+ int forceit = FALSE;
+ int usefilter = FALSE; /* filter instead of file name */
+
+ ExpandInit(xp);
+ xp->xp_pattern = buff;
+ xp->xp_context = EXPAND_COMMANDS; /* Default until we get past command */
+ ea.argt = 0;
+
+/*
+ * 1. skip comment lines and leading space, colons or bars
+ */
+ for (cmd = buff; vim_strchr((char_u *)" \t:|", *cmd) != NULL; cmd++)
+ ;
+ xp->xp_pattern = cmd;
+
+ if (*cmd == NUL)
+ return NULL;
+ if (*cmd == '"') /* ignore comment lines */
+ {
+ xp->xp_context = EXPAND_NOTHING;
+ return NULL;
+ }
+
+/*
+ * 3. Skip over the range to find the command.
+ */
+ cmd = skip_range(cmd, &xp->xp_context);
+ xp->xp_pattern = cmd;
+ if (*cmd == NUL)
+ return NULL;
+ if (*cmd == '"')
+ {
+ xp->xp_context = EXPAND_NOTHING;
+ return NULL;
+ }
+
+ if (*cmd == '|' || *cmd == '\n')
+ return cmd + 1; /* There's another command */
+
+ /*
+ * Isolate the command and search for it in the command table.
+ * Exceptions:
+ * - the 'k' command can directly be followed by any character, but
+ * do accept "keepmarks", "keepalt" and "keepjumps".
+ * - the 's' command can be followed directly by 'c', 'g', 'i', 'I' or 'r'
+ */
+ if (*cmd == 'k' && cmd[1] != 'e')
+ {
+ ea.cmdidx = CMD_k;
+ p = cmd + 1;
+ }
+ else
+ {
+ p = cmd;
+ while (ASCII_ISALPHA(*p) || *p == '*') /* Allow * wild card */
+ ++p;
+ /* a user command may contain digits */
+ if (ASCII_ISUPPER(cmd[0]))
+ while (ASCII_ISALNUM(*p) || *p == '*')
+ ++p;
+ /* for python 3.x: ":py3*" commands completion */
+ if (cmd[0] == 'p' && cmd[1] == 'y' && p == cmd + 2 && *p == '3')
+ {
+ ++p;
+ while (ASCII_ISALPHA(*p) || *p == '*')
+ ++p;
+ }
+ /* check for non-alpha command */
+ if (p == cmd && vim_strchr((char_u *)"@*!=><&~#", *p) != NULL)
+ ++p;
+ len = (int)(p - cmd);
+
+ if (len == 0)
+ {
+ xp->xp_context = EXPAND_UNSUCCESSFUL;
+ return NULL;
+ }
+ for (ea.cmdidx = (cmdidx_T)0; (int)ea.cmdidx < (int)CMD_SIZE;
+ ea.cmdidx = (cmdidx_T)((int)ea.cmdidx + 1))
+ if (STRNCMP(cmdnames[(int)ea.cmdidx].cmd_name, cmd,
+ (size_t)len) == 0)
+ break;
+
+#ifdef FEAT_USR_CMDS
+ if (cmd[0] >= 'A' && cmd[0] <= 'Z')
+ while (ASCII_ISALNUM(*p) || *p == '*') /* Allow * wild card */
+ ++p;
+#endif
+ }
+
+ /*
+ * If the cursor is touching the command, and it ends in an alpha-numeric
+ * character, complete the command name.
+ */
+ if (*p == NUL && ASCII_ISALNUM(p[-1]))
+ return NULL;
+
+ if (ea.cmdidx == CMD_SIZE)
+ {
+ if (*cmd == 's' && vim_strchr((char_u *)"cgriI", cmd[1]) != NULL)
+ {
+ ea.cmdidx = CMD_substitute;
+ p = cmd + 1;
+ }
+#ifdef FEAT_USR_CMDS
+ else if (cmd[0] >= 'A' && cmd[0] <= 'Z')
+ {
+ ea.cmd = cmd;
+ p = find_ucmd(&ea, p, NULL, xp,
+# if defined(FEAT_CMDL_COMPL)
+ &compl
+# else
+ NULL
+# endif
+ );
+ if (p == NULL)
+ ea.cmdidx = CMD_SIZE; /* ambiguous user command */
+ }
+#endif
+ }
+ if (ea.cmdidx == CMD_SIZE)
+ {
+ /* Not still touching the command and it was an illegal one */
+ xp->xp_context = EXPAND_UNSUCCESSFUL;
+ return NULL;
+ }
+
+ xp->xp_context = EXPAND_NOTHING; /* Default now that we're past command */
+
+ if (*p == '!') /* forced commands */
+ {
+ forceit = TRUE;
+ ++p;
+ }
+
+/*
+ * 6. parse arguments
+ */
+ if (!IS_USER_CMDIDX(ea.cmdidx))
+ ea.argt = (long)cmdnames[(int)ea.cmdidx].cmd_argt;
+
+ arg = skipwhite(p);
+
+ if (ea.cmdidx == CMD_write || ea.cmdidx == CMD_update)
+ {
+ if (*arg == '>') /* append */
+ {
+ if (*++arg == '>')
+ ++arg;
+ arg = skipwhite(arg);
+ }
+ else if (*arg == '!' && ea.cmdidx == CMD_write) /* :w !filter */
+ {
+ ++arg;
+ usefilter = TRUE;
+ }
+ }
+
+ if (ea.cmdidx == CMD_read)
+ {
+ usefilter = forceit; /* :r! filter if forced */
+ if (*arg == '!') /* :r !filter */
+ {
+ ++arg;
+ usefilter = TRUE;
+ }
+ }
+
+ if (ea.cmdidx == CMD_lshift || ea.cmdidx == CMD_rshift)
+ {
+ while (*arg == *cmd) /* allow any number of '>' or '<' */
+ ++arg;
+ arg = skipwhite(arg);
+ }
+
+ /* Does command allow "+command"? */
+ if ((ea.argt & EDITCMD) && !usefilter && *arg == '+')
+ {
+ /* Check if we're in the +command */
+ p = arg + 1;
+ arg = skip_cmd_arg(arg, FALSE);
+
+ /* Still touching the command after '+'? */
+ if (*arg == NUL)
+ return p;
+
+ /* Skip space(s) after +command to get to the real argument */
+ arg = skipwhite(arg);
+ }
+
+ /*
+ * Check for '|' to separate commands and '"' to start comments.
+ * Don't do this for ":read !cmd" and ":write !cmd".
+ */
+ if ((ea.argt & TRLBAR) && !usefilter)
+ {
+ p = arg;
+ /* ":redir @" is not the start of a comment */
+ if (ea.cmdidx == CMD_redir && p[0] == '@' && p[1] == '"')
+ p += 2;
+ while (*p)
+ {
+ if (*p == Ctrl_V)
+ {
+ if (p[1] != NUL)
+ ++p;
+ }
+ else if ( (*p == '"' && !(ea.argt & NOTRLCOM))
+ || *p == '|' || *p == '\n')
+ {
+ if (*(p - 1) != '\\')
+ {
+ if (*p == '|' || *p == '\n')
+ return p + 1;
+ return NULL; /* It's a comment */
+ }
+ }
+ MB_PTR_ADV(p);
+ }
+ }
+
+ /* no arguments allowed */
+ if (!(ea.argt & EXTRA) && *arg != NUL &&
+ vim_strchr((char_u *)"|\"", *arg) == NULL)
+ return NULL;
+
+ /* Find start of last argument (argument just before cursor): */
+ p = buff;
+ xp->xp_pattern = p;
+ len = (int)STRLEN(buff);
+ while (*p && p < buff + len)
+ {
+ if (*p == ' ' || *p == TAB)
+ {
+ /* argument starts after a space */
+ xp->xp_pattern = ++p;
+ }
+ else
+ {
+ if (*p == '\\' && *(p + 1) != NUL)
+ ++p; /* skip over escaped character */
+ MB_PTR_ADV(p);
+ }
+ }
+
+ if (ea.argt & XFILE)
+ {
+ int c;
+ int in_quote = FALSE;
+ char_u *bow = NULL; /* Beginning of word */
+
+ /*
+ * Allow spaces within back-quotes to count as part of the argument
+ * being expanded.
+ */
+ xp->xp_pattern = skipwhite(arg);
+ p = xp->xp_pattern;
+ while (*p != NUL)
+ {
+ if (has_mbyte)
+ c = mb_ptr2char(p);
+ else
+ c = *p;
+ if (c == '\\' && p[1] != NUL)
+ ++p;
+ else if (c == '`')
+ {
+ if (!in_quote)
+ {
+ xp->xp_pattern = p;
+ bow = p + 1;
+ }
+ in_quote = !in_quote;
+ }
+ /* An argument can contain just about everything, except
+ * characters that end the command and white space. */
+ else if (c == '|' || c == '\n' || c == '"' || (VIM_ISWHITE(c)
+#ifdef SPACE_IN_FILENAME
+ && (!(ea.argt & NOSPC) || usefilter)
+#endif
+ ))
+ {
+ len = 0; /* avoid getting stuck when space is in 'isfname' */
+ while (*p != NUL)
+ {
+ if (has_mbyte)
+ c = mb_ptr2char(p);
+ else
+ c = *p;
+ if (c == '`' || vim_isfilec_or_wc(c))
+ break;
+ if (has_mbyte)
+ len = (*mb_ptr2len)(p);
+ else
+ len = 1;
+ MB_PTR_ADV(p);
+ }
+ if (in_quote)
+ bow = p;
+ else
+ xp->xp_pattern = p;
+ p -= len;
+ }
+ MB_PTR_ADV(p);
+ }
+
+ /*
+ * If we are still inside the quotes, and we passed a space, just
+ * expand from there.
+ */
+ if (bow != NULL && in_quote)
+ xp->xp_pattern = bow;
+ xp->xp_context = EXPAND_FILES;
+
+ /* For a shell command more chars need to be escaped. */
+ if (usefilter || ea.cmdidx == CMD_bang || ea.cmdidx == CMD_terminal)
+ {
+#ifndef BACKSLASH_IN_FILENAME
+ xp->xp_shell = TRUE;
+#endif
+ /* When still after the command name expand executables. */
+ if (xp->xp_pattern == skipwhite(arg))
+ xp->xp_context = EXPAND_SHELLCMD;
+ }
+
+ /* Check for environment variable */
+ if (*xp->xp_pattern == '$'
+#if defined(MSWIN)
+ || *xp->xp_pattern == '%'
+#endif
+ )
+ {
+ for (p = xp->xp_pattern + 1; *p != NUL; ++p)
+ if (!vim_isIDc(*p))
+ break;
+ if (*p == NUL)
+ {
+ xp->xp_context = EXPAND_ENV_VARS;
+ ++xp->xp_pattern;
+#if defined(FEAT_USR_CMDS) && defined(FEAT_CMDL_COMPL)
+ /* Avoid that the assignment uses EXPAND_FILES again. */
+ if (compl != EXPAND_USER_DEFINED && compl != EXPAND_USER_LIST)
+ compl = EXPAND_ENV_VARS;
+#endif
+ }
+ }
+#if defined(FEAT_CMDL_COMPL)
+ /* Check for user names */
+ if (*xp->xp_pattern == '~')
+ {
+ for (p = xp->xp_pattern + 1; *p != NUL && *p != '/'; ++p)
+ ;
+ /* Complete ~user only if it partially matches a user name.
+ * A full match ~user<Tab> will be replaced by user's home
+ * directory i.e. something like ~user<Tab> -> /home/user/ */
+ if (*p == NUL && p > xp->xp_pattern + 1
+ && match_user(xp->xp_pattern + 1) >= 1)
+ {
+ xp->xp_context = EXPAND_USER;
+ ++xp->xp_pattern;
+ }
+ }
+#endif
+ }
+
+/*
+ * 6. Switch on command name.
+ */
+ switch (ea.cmdidx)
+ {
+ case CMD_find:
+ case CMD_sfind:
+ case CMD_tabfind:
+ if (xp->xp_context == EXPAND_FILES)
+ xp->xp_context = EXPAND_FILES_IN_PATH;
+ break;
+ case CMD_cd:
+ case CMD_chdir:
+ case CMD_lcd:
+ case CMD_lchdir:
+ if (xp->xp_context == EXPAND_FILES)
+ xp->xp_context = EXPAND_DIRECTORIES;
+ break;
+ case CMD_help:
+ xp->xp_context = EXPAND_HELP;
+ xp->xp_pattern = arg;
+ break;
+
+ /* Command modifiers: return the argument.
+ * Also for commands with an argument that is a command. */
+ case CMD_aboveleft:
+ case CMD_argdo:
+ case CMD_belowright:
+ case CMD_botright:
+ case CMD_browse:
+ case CMD_bufdo:
+ case CMD_cdo:
+ case CMD_cfdo:
+ case CMD_confirm:
+ case CMD_debug:
+ case CMD_folddoclosed:
+ case CMD_folddoopen:
+ case CMD_hide:
+ case CMD_keepalt:
+ case CMD_keepjumps:
+ case CMD_keepmarks:
+ case CMD_keeppatterns:
+ case CMD_ldo:
+ case CMD_leftabove:
+ case CMD_lfdo:
+ case CMD_lockmarks:
+ case CMD_noautocmd:
+ case CMD_noswapfile:
+ case CMD_rightbelow:
+ case CMD_sandbox:
+ case CMD_silent:
+ case CMD_tab:
+ case CMD_tabdo:
+ case CMD_topleft:
+ case CMD_verbose:
+ case CMD_vertical:
+ case CMD_windo:
+ return arg;
+
+ case CMD_filter:
+ if (*arg != NUL)
+ arg = skip_vimgrep_pat(arg, NULL, NULL);
+ if (arg == NULL || *arg == NUL)
+ {
+ xp->xp_context = EXPAND_NOTHING;
+ return NULL;
+ }
+ return skipwhite(arg);
+
+#ifdef FEAT_CMDL_COMPL
+# ifdef FEAT_SEARCH_EXTRA
+ case CMD_match:
+ if (*arg == NUL || !ends_excmd(*arg))
+ {
+ /* also complete "None" */
+ set_context_in_echohl_cmd(xp, arg);
+ arg = skipwhite(skiptowhite(arg));
+ if (*arg != NUL)
+ {
+ xp->xp_context = EXPAND_NOTHING;
+ arg = skip_regexp(arg + 1, *arg, p_magic, NULL);
+ }
+ }
+ return find_nextcmd(arg);
+# endif
+
+/*
+ * All completion for the +cmdline_compl feature goes here.
+ */
+
+# ifdef FEAT_USR_CMDS
+ case CMD_command:
+ /* Check for attributes */
+ while (*arg == '-')
+ {
+ arg++; /* Skip "-" */
+ p = skiptowhite(arg);
+ if (*p == NUL)
+ {
+ /* Cursor is still in the attribute */
+ p = vim_strchr(arg, '=');
+ if (p == NULL)
+ {
+ /* No "=", so complete attribute names */
+ xp->xp_context = EXPAND_USER_CMD_FLAGS;
+ xp->xp_pattern = arg;
+ return NULL;
+ }
+
+ /* For the -complete, -nargs and -addr attributes, we complete
+ * their arguments as well.
+ */
+ if (STRNICMP(arg, "complete", p - arg) == 0)
+ {
+ xp->xp_context = EXPAND_USER_COMPLETE;
+ xp->xp_pattern = p + 1;
+ return NULL;
+ }
+ else if (STRNICMP(arg, "nargs", p - arg) == 0)
+ {
+ xp->xp_context = EXPAND_USER_NARGS;
+ xp->xp_pattern = p + 1;
+ return NULL;
+ }
+ else if (STRNICMP(arg, "addr", p - arg) == 0)
+ {
+ xp->xp_context = EXPAND_USER_ADDR_TYPE;
+ xp->xp_pattern = p + 1;
+ return NULL;
+ }
+ return NULL;
+ }
+ arg = skipwhite(p);
+ }
+
+ /* After the attributes comes the new command name */
+ p = skiptowhite(arg);
+ if (*p == NUL)
+ {
+ xp->xp_context = EXPAND_USER_COMMANDS;
+ xp->xp_pattern = arg;
+ break;
+ }
+
+ /* And finally comes a normal command */
+ return skipwhite(p);
+
+ case CMD_delcommand:
+ xp->xp_context = EXPAND_USER_COMMANDS;
+ xp->xp_pattern = arg;
+ break;
+# endif
+
+ case CMD_global:
+ case CMD_vglobal:
+ delim = *arg; /* get the delimiter */
+ if (delim)
+ ++arg; /* skip delimiter if there is one */
+
+ while (arg[0] != NUL && arg[0] != delim)
+ {
+ if (arg[0] == '\\' && arg[1] != NUL)
+ ++arg;
+ ++arg;
+ }
+ if (arg[0] != NUL)
+ return arg + 1;
+ break;
+ case CMD_and:
+ case CMD_substitute:
+ delim = *arg;
+ if (delim)
+ {
+ /* skip "from" part */
+ ++arg;
+ arg = skip_regexp(arg, delim, p_magic, NULL);
+ }
+ /* skip "to" part */
+ while (arg[0] != NUL && arg[0] != delim)
+ {
+ if (arg[0] == '\\' && arg[1] != NUL)
+ ++arg;
+ ++arg;
+ }
+ if (arg[0] != NUL) /* skip delimiter */
+ ++arg;
+ while (arg[0] && vim_strchr((char_u *)"|\"#", arg[0]) == NULL)
+ ++arg;
+ if (arg[0] != NUL)
+ return arg;
+ break;
+ case CMD_isearch:
+ case CMD_dsearch:
+ case CMD_ilist:
+ case CMD_dlist:
+ case CMD_ijump:
+ case CMD_psearch:
+ case CMD_djump:
+ case CMD_isplit:
+ case CMD_dsplit:
+ arg = skipwhite(skipdigits(arg)); /* skip count */
+ if (*arg == '/') /* Match regexp, not just whole words */
+ {
+ for (++arg; *arg && *arg != '/'; arg++)
+ if (*arg == '\\' && arg[1] != NUL)
+ arg++;
+ if (*arg)
+ {
+ arg = skipwhite(arg + 1);
+
+ /* Check for trailing illegal characters */
+ if (*arg && vim_strchr((char_u *)"|\"\n", *arg) == NULL)
+ xp->xp_context = EXPAND_NOTHING;
+ else
+ return arg;
+ }
+ }
+ break;
+
+ case CMD_autocmd:
+ return set_context_in_autocmd(xp, arg, FALSE);
+ case CMD_doautocmd:
+ case CMD_doautoall:
+ return set_context_in_autocmd(xp, arg, TRUE);
+ case CMD_set:
+ set_context_in_set_cmd(xp, arg, 0);
+ break;
+ case CMD_setglobal:
+ set_context_in_set_cmd(xp, arg, OPT_GLOBAL);
+ break;
+ case CMD_setlocal:
+ set_context_in_set_cmd(xp, arg, OPT_LOCAL);
+ break;
+ case CMD_tag:
+ case CMD_stag:
+ case CMD_ptag:
+ case CMD_ltag:
+ case CMD_tselect:
+ case CMD_stselect:
+ case CMD_ptselect:
+ case CMD_tjump:
+ case CMD_stjump:
+ case CMD_ptjump:
+ if (*p_wop != NUL)
+ xp->xp_context = EXPAND_TAGS_LISTFILES;
+ else
+ xp->xp_context = EXPAND_TAGS;
+ xp->xp_pattern = arg;
+ break;
+ case CMD_augroup:
+ xp->xp_context = EXPAND_AUGROUP;
+ xp->xp_pattern = arg;
+ break;
+#ifdef FEAT_SYN_HL
+ case CMD_syntax:
+ set_context_in_syntax_cmd(xp, arg);
+ break;
+#endif
+#ifdef FEAT_EVAL
+ case CMD_let:
+ case CMD_if:
+ case CMD_elseif:
+ case CMD_while:
+ case CMD_for:
+ case CMD_echo:
+ case CMD_echon:
+ case CMD_execute:
+ case CMD_echomsg:
+ case CMD_echoerr:
+ case CMD_call:
+ case CMD_return:
+ case CMD_cexpr:
+ case CMD_caddexpr:
+ case CMD_cgetexpr:
+ case CMD_lexpr:
+ case CMD_laddexpr:
+ case CMD_lgetexpr:
+ set_context_for_expression(xp, arg, ea.cmdidx);
+ break;
+
+ case CMD_unlet:
+ while ((xp->xp_pattern = vim_strchr(arg, ' ')) != NULL)
+ arg = xp->xp_pattern + 1;
+
+ xp->xp_context = EXPAND_USER_VARS;
+ xp->xp_pattern = arg;
+
+ if (*xp->xp_pattern == '$')
+ {
+ xp->xp_context = EXPAND_ENV_VARS;
+ ++xp->xp_pattern;
+ }
+
+ break;
+
+ case CMD_function:
+ case CMD_delfunction:
+ xp->xp_context = EXPAND_USER_FUNC;
+ xp->xp_pattern = arg;
+ break;
+
+ case CMD_echohl:
+ set_context_in_echohl_cmd(xp, arg);
+ break;
+#endif
+ case CMD_highlight:
+ set_context_in_highlight_cmd(xp, arg);
+ break;
+#ifdef FEAT_CSCOPE
+ case CMD_cscope:
+ case CMD_lcscope:
+ case CMD_scscope:
+ set_context_in_cscope_cmd(xp, arg, ea.cmdidx);
+ break;
+#endif
+#ifdef FEAT_SIGNS
+ case CMD_sign:
+ set_context_in_sign_cmd(xp, arg);
+ break;
+#endif
+ case CMD_bdelete:
+ case CMD_bwipeout:
+ case CMD_bunload:
+ while ((xp->xp_pattern = vim_strchr(arg, ' ')) != NULL)
+ arg = xp->xp_pattern + 1;
+ /* FALLTHROUGH */
+ case CMD_buffer:
+ case CMD_sbuffer:
+ case CMD_checktime:
+ xp->xp_context = EXPAND_BUFFERS;
+ xp->xp_pattern = arg;
+ break;
+#ifdef FEAT_USR_CMDS
+ case CMD_USER:
+ case CMD_USER_BUF:
+ if (compl != EXPAND_NOTHING)
+ {
+ /* XFILE: file names are handled above */
+ if (!(ea.argt & XFILE))
+ {
+# ifdef FEAT_MENU
+ if (compl == EXPAND_MENUS)
+ return set_context_in_menu_cmd(xp, cmd, arg, forceit);
+# endif
+ if (compl == EXPAND_COMMANDS)
+ return arg;
+ if (compl == EXPAND_MAPPINGS)
+ return set_context_in_map_cmd(xp, (char_u *)"map",
+ arg, forceit, FALSE, FALSE, CMD_map);
+ /* Find start of last argument. */
+ p = arg;
+ while (*p)
+ {
+ if (*p == ' ')
+ /* argument starts after a space */
+ arg = p + 1;
+ else if (*p == '\\' && *(p + 1) != NUL)
+ ++p; /* skip over escaped character */
+ MB_PTR_ADV(p);
+ }
+ xp->xp_pattern = arg;
+ }
+ xp->xp_context = compl;
+ }
+ break;
+#endif
+ case CMD_map: case CMD_noremap:
+ case CMD_nmap: case CMD_nnoremap:
+ case CMD_vmap: case CMD_vnoremap:
+ case CMD_omap: case CMD_onoremap:
+ case CMD_imap: case CMD_inoremap:
+ case CMD_cmap: case CMD_cnoremap:
+ case CMD_lmap: case CMD_lnoremap:
+ case CMD_smap: case CMD_snoremap:
+ case CMD_tmap: case CMD_tnoremap:
+ case CMD_xmap: case CMD_xnoremap:
+ return set_context_in_map_cmd(xp, cmd, arg, forceit,
+ FALSE, FALSE, ea.cmdidx);
+ case CMD_unmap:
+ case CMD_nunmap:
+ case CMD_vunmap:
+ case CMD_ounmap:
+ case CMD_iunmap:
+ case CMD_cunmap:
+ case CMD_lunmap:
+ case CMD_sunmap:
+ case CMD_tunmap:
+ case CMD_xunmap:
+ return set_context_in_map_cmd(xp, cmd, arg, forceit,
+ FALSE, TRUE, ea.cmdidx);
+ case CMD_mapclear:
+ case CMD_nmapclear:
+ case CMD_vmapclear:
+ case CMD_omapclear:
+ case CMD_imapclear:
+ case CMD_cmapclear:
+ case CMD_lmapclear:
+ case CMD_smapclear:
+ case CMD_tmapclear:
+ case CMD_xmapclear:
+ xp->xp_context = EXPAND_MAPCLEAR;
+ xp->xp_pattern = arg;
+ break;
+
+ case CMD_abbreviate: case CMD_noreabbrev:
+ case CMD_cabbrev: case CMD_cnoreabbrev:
+ case CMD_iabbrev: case CMD_inoreabbrev:
+ return set_context_in_map_cmd(xp, cmd, arg, forceit,
+ TRUE, FALSE, ea.cmdidx);
+ case CMD_unabbreviate:
+ case CMD_cunabbrev:
+ case CMD_iunabbrev:
+ return set_context_in_map_cmd(xp, cmd, arg, forceit,
+ TRUE, TRUE, ea.cmdidx);
+#ifdef FEAT_MENU
+ case CMD_menu: case CMD_noremenu: case CMD_unmenu:
+ case CMD_amenu: case CMD_anoremenu: case CMD_aunmenu:
+ case CMD_nmenu: case CMD_nnoremenu: case CMD_nunmenu:
+ case CMD_vmenu: case CMD_vnoremenu: case CMD_vunmenu:
+ case CMD_omenu: case CMD_onoremenu: case CMD_ounmenu:
+ case CMD_imenu: case CMD_inoremenu: case CMD_iunmenu:
+ case CMD_cmenu: case CMD_cnoremenu: case CMD_cunmenu:
+ case CMD_tlmenu: case CMD_tlnoremenu: case CMD_tlunmenu:
+ case CMD_tmenu: case CMD_tunmenu:
+ case CMD_popup: case CMD_tearoff: case CMD_emenu:
+ return set_context_in_menu_cmd(xp, cmd, arg, forceit);
+#endif
+
+ case CMD_colorscheme:
+ xp->xp_context = EXPAND_COLORS;
+ xp->xp_pattern = arg;
+ break;
+
+ case CMD_compiler:
+ xp->xp_context = EXPAND_COMPILER;
+ xp->xp_pattern = arg;
+ break;
+
+ case CMD_ownsyntax:
+ xp->xp_context = EXPAND_OWNSYNTAX;
+ xp->xp_pattern = arg;
+ break;
+
+ case CMD_setfiletype:
+ xp->xp_context = EXPAND_FILETYPE;
+ xp->xp_pattern = arg;
+ break;
+
+ case CMD_packadd:
+ xp->xp_context = EXPAND_PACKADD;
+ xp->xp_pattern = arg;
+ break;
+
+#if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
+ case CMD_language:
+ p = skiptowhite(arg);
+ if (*p == NUL)
+ {
+ xp->xp_context = EXPAND_LANGUAGE;
+ xp->xp_pattern = arg;
+ }
+ else
+ {
+ if ( STRNCMP(arg, "messages", p - arg) == 0
+ || STRNCMP(arg, "ctype", p - arg) == 0
+ || STRNCMP(arg, "time", p - arg) == 0)
+ {
+ xp->xp_context = EXPAND_LOCALES;
+ xp->xp_pattern = skipwhite(p);
+ }
+ else
+ xp->xp_context = EXPAND_NOTHING;
+ }
+ break;
+#endif
+#if defined(FEAT_PROFILE)
+ case CMD_profile:
+ set_context_in_profile_cmd(xp, arg);
+ break;
+#endif
+ case CMD_behave:
+ xp->xp_context = EXPAND_BEHAVE;
+ xp->xp_pattern = arg;
+ break;
+
+ case CMD_messages:
+ xp->xp_context = EXPAND_MESSAGES;
+ xp->xp_pattern = arg;
+ break;
+
+#if defined(FEAT_CMDHIST)
+ case CMD_history:
+ xp->xp_context = EXPAND_HISTORY;
+ xp->xp_pattern = arg;
+ break;
+#endif
+#if defined(FEAT_PROFILE)
+ case CMD_syntime:
+ xp->xp_context = EXPAND_SYNTIME;
+ xp->xp_pattern = arg;
+ break;
+#endif
+
+ case CMD_argdelete:
+ while ((xp->xp_pattern = vim_strchr(arg, ' ')) != NULL)
+ arg = xp->xp_pattern + 1;
+ xp->xp_context = EXPAND_ARGLIST;
+ xp->xp_pattern = arg;
+ break;
+
+#endif /* FEAT_CMDL_COMPL */
+
+ default:
+ break;
+ }
+ return NULL;
+}
+
+/*
+ * Skip a range specifier of the form: addr [,addr] [;addr] ..
+ *
+ * Backslashed delimiters after / or ? will be skipped, and commands will
+ * not be expanded between /'s and ?'s or after "'".
+ *
+ * Also skip white space and ":" characters.
+ * Returns the "cmd" pointer advanced to beyond the range.
+ */
+ char_u *
+skip_range(
+ char_u *cmd,
+ int *ctx) /* pointer to xp_context or NULL */
+{
+ unsigned delim;
+
+ while (vim_strchr((char_u *)" \t0123456789.$%'/?-+,;\\", *cmd) != NULL)
+ {
+ if (*cmd == '\\')
+ {
+ if (cmd[1] == '?' || cmd[1] == '/' || cmd[1] == '&')
+ ++cmd;
+ else
+ break;
+ }
+ else if (*cmd == '\'')
+ {
+ if (*++cmd == NUL && ctx != NULL)
+ *ctx = EXPAND_NOTHING;
+ }
+ else if (*cmd == '/' || *cmd == '?')
+ {
+ delim = *cmd++;
+ while (*cmd != NUL && *cmd != delim)
+ if (*cmd++ == '\\' && *cmd != NUL)
+ ++cmd;
+ if (*cmd == NUL && ctx != NULL)
+ *ctx = EXPAND_NOTHING;
+ }
+ if (*cmd != NUL)
+ ++cmd;
+ }
+
+ /* Skip ":" and white space. */
+ while (*cmd == ':')
+ cmd = skipwhite(cmd + 1);
+
+ return cmd;
+}
+
+/*
+ * Get a single EX address.
+ *
+ * Set ptr to the next character after the part that was interpreted.
+ * Set ptr to NULL when an error is encountered.
+ * This may set the last used search pattern.
+ *
+ * Return MAXLNUM when no Ex address was found.
+ */
+ static linenr_T
+get_address(
+ exarg_T *eap UNUSED,
+ char_u **ptr,
+ int addr_type, // flag: one of ADDR_LINES, ...
+ int skip, // only skip the address, don't use it
+ int silent, // no errors or side effects
+ int to_other_file, // flag: may jump to other file
+ int address_count UNUSED) // 1 for first address, >1 after comma
+{
+ int c;
+ int i;
+ long n;
+ char_u *cmd;
+ pos_T pos;
+ pos_T *fp;
+ linenr_T lnum;
+ buf_T *buf;
+
+ cmd = skipwhite(*ptr);
+ lnum = MAXLNUM;
+ do
+ {
+ switch (*cmd)
+ {
+ case '.': /* '.' - Cursor position */
+ ++cmd;
+ switch (addr_type)
+ {
+ case ADDR_LINES:
+ lnum = curwin->w_cursor.lnum;
+ break;
+ case ADDR_WINDOWS:
+ lnum = CURRENT_WIN_NR;
+ break;
+ case ADDR_ARGUMENTS:
+ lnum = curwin->w_arg_idx + 1;
+ break;
+ case ADDR_LOADED_BUFFERS:
+ case ADDR_BUFFERS:
+ lnum = curbuf->b_fnum;
+ break;
+ case ADDR_TABS:
+ lnum = CURRENT_TAB_NR;
+ break;
+ case ADDR_TABS_RELATIVE:
+ emsg(_(e_invrange));
+ cmd = NULL;
+ goto error;
+ break;
+#ifdef FEAT_QUICKFIX
+ case ADDR_QUICKFIX:
+ lnum = qf_get_cur_valid_idx(eap);
+ break;
+#endif
+ }
+ break;
+
+ case '$': /* '$' - last line */
+ ++cmd;
+ switch (addr_type)
+ {
+ case ADDR_LINES:
+ lnum = curbuf->b_ml.ml_line_count;
+ break;
+ case ADDR_WINDOWS:
+ lnum = LAST_WIN_NR;
+ break;
+ case ADDR_ARGUMENTS:
+ lnum = ARGCOUNT;
+ break;
+ case ADDR_LOADED_BUFFERS:
+ buf = lastbuf;
+ while (buf->b_ml.ml_mfp == NULL)
+ {
+ if (buf->b_prev == NULL)
+ break;
+ buf = buf->b_prev;
+ }
+ lnum = buf->b_fnum;
+ break;
+ case ADDR_BUFFERS:
+ lnum = lastbuf->b_fnum;
+ break;
+ case ADDR_TABS:
+ lnum = LAST_TAB_NR;
+ break;
+ case ADDR_TABS_RELATIVE:
+ emsg(_(e_invrange));
+ cmd = NULL;
+ goto error;
+ break;
+#ifdef FEAT_QUICKFIX
+ case ADDR_QUICKFIX:
+ lnum = qf_get_size(eap);
+ if (lnum == 0)
+ lnum = 1;
+ break;
+#endif
+ }
+ break;
+
+ case '\'': /* ''' - mark */
+ if (*++cmd == NUL)
+ {
+ cmd = NULL;
+ goto error;
+ }
+ if (addr_type != ADDR_LINES)
+ {
+ emsg(_(e_invaddr));
+ cmd = NULL;
+ goto error;
+ }
+ if (skip)
+ ++cmd;
+ else
+ {
+ /* Only accept a mark in another file when it is
+ * used by itself: ":'M". */
+ fp = getmark(*cmd, to_other_file && cmd[1] == NUL);
+ ++cmd;
+ if (fp == (pos_T *)-1)
+ /* Jumped to another file. */
+ lnum = curwin->w_cursor.lnum;
+ else
+ {
+ if (check_mark(fp) == FAIL)
+ {
+ cmd = NULL;
+ goto error;
+ }
+ lnum = fp->lnum;
+ }
+ }
+ break;
+
+ case '/':
+ case '?': /* '/' or '?' - search */
+ c = *cmd++;
+ if (addr_type != ADDR_LINES)
+ {
+ emsg(_(e_invaddr));
+ cmd = NULL;
+ goto error;
+ }
+ if (skip) /* skip "/pat/" */
+ {
+ cmd = skip_regexp(cmd, c, (int)p_magic, NULL);
+ if (*cmd == c)
+ ++cmd;
+ }
+ else
+ {
+ int flags;
+
+ pos = curwin->w_cursor; // save curwin->w_cursor
+
+ // When '/' or '?' follows another address, start from
+ // there.
+ if (lnum != MAXLNUM)
+ curwin->w_cursor.lnum = lnum;
+
+ // Start a forward search at the end of the line (unless
+ // before the first line).
+ // Start a backward search at the start of the line.
+ // This makes sure we never match in the current
+ // line, and can match anywhere in the
+ // next/previous line.
+ if (c == '/' && curwin->w_cursor.lnum > 0)
+ curwin->w_cursor.col = MAXCOL;
+ else
+ curwin->w_cursor.col = 0;
+ searchcmdlen = 0;
+ flags = silent ? 0 : SEARCH_HIS | SEARCH_MSG;
+ if (!do_search(NULL, c, cmd, 1L, flags, NULL, NULL))
+ {
+ curwin->w_cursor = pos;
+ cmd = NULL;
+ goto error;
+ }
+ lnum = curwin->w_cursor.lnum;
+ curwin->w_cursor = pos;
+ /* adjust command string pointer */
+ cmd += searchcmdlen;
+ }
+ break;
+
+ case '\\': /* "\?", "\/" or "\&", repeat search */
+ ++cmd;
+ if (addr_type != ADDR_LINES)
+ {
+ emsg(_(e_invaddr));
+ cmd = NULL;
+ goto error;
+ }
+ if (*cmd == '&')
+ i = RE_SUBST;
+ else if (*cmd == '?' || *cmd == '/')
+ i = RE_SEARCH;
+ else
+ {
+ emsg(_(e_backslash));
+ cmd = NULL;
+ goto error;
+ }
+
+ if (!skip)
+ {
+ /*
+ * When search follows another address, start from
+ * there.
+ */
+ if (lnum != MAXLNUM)
+ pos.lnum = lnum;
+ else
+ pos.lnum = curwin->w_cursor.lnum;
+
+ /*
+ * Start the search just like for the above
+ * do_search().
+ */
+ if (*cmd != '?')
+ pos.col = MAXCOL;
+ else
+ pos.col = 0;
+ pos.coladd = 0;
+ if (searchit(curwin, curbuf, &pos, NULL,
+ *cmd == '?' ? BACKWARD : FORWARD,
+ (char_u *)"", 1L, SEARCH_MSG,
+ i, (linenr_T)0, NULL, NULL) != FAIL)
+ lnum = pos.lnum;
+ else
+ {
+ cmd = NULL;
+ goto error;
+ }
+ }
+ ++cmd;
+ break;
+
+ default:
+ if (VIM_ISDIGIT(*cmd)) /* absolute line number */
+ lnum = getdigits(&cmd);
+ }
+
+ for (;;)
+ {
+ cmd = skipwhite(cmd);
+ if (*cmd != '-' && *cmd != '+' && !VIM_ISDIGIT(*cmd))
+ break;
+
+ if (lnum == MAXLNUM)
+ {
+ switch (addr_type)
+ {
+ case ADDR_LINES:
+ /* "+1" is same as ".+1" */
+ lnum = curwin->w_cursor.lnum;
+ break;
+ case ADDR_WINDOWS:
+ lnum = CURRENT_WIN_NR;
+ break;
+ case ADDR_ARGUMENTS:
+ lnum = curwin->w_arg_idx + 1;
+ break;
+ case ADDR_LOADED_BUFFERS:
+ case ADDR_BUFFERS:
+ lnum = curbuf->b_fnum;
+ break;
+ case ADDR_TABS:
+ lnum = CURRENT_TAB_NR;
+ break;
+ case ADDR_TABS_RELATIVE:
+ lnum = 1;
+ break;
+#ifdef FEAT_QUICKFIX
+ case ADDR_QUICKFIX:
+ lnum = qf_get_cur_valid_idx(eap);
+ break;
+#endif
+ }
+ }
+
+ if (VIM_ISDIGIT(*cmd))
+ i = '+'; /* "number" is same as "+number" */
+ else
+ i = *cmd++;
+ if (!VIM_ISDIGIT(*cmd)) /* '+' is '+1', but '+0' is not '+1' */
+ n = 1;
+ else
+ n = getdigits(&cmd);
+
+ if (addr_type == ADDR_TABS_RELATIVE)
+ {
+ emsg(_(e_invrange));
+ cmd = NULL;
+ goto error;
+ }
+ else if (addr_type == ADDR_LOADED_BUFFERS
+ || addr_type == ADDR_BUFFERS)
+ lnum = compute_buffer_local_count(
+ addr_type, lnum, (i == '-') ? -1 * n : n);
+ else
+ {
+#ifdef FEAT_FOLDING
+ /* Relative line addressing, need to adjust for folded lines
+ * now, but only do it after the first address. */
+ if (addr_type == ADDR_LINES && (i == '-' || i == '+')
+ && address_count >= 2)
+ (void)hasFolding(lnum, NULL, &lnum);
+#endif
+ if (i == '-')
+ lnum -= n;
+ else
+ lnum += n;
+ }
+ }
+ } while (*cmd == '/' || *cmd == '?');
+
+error:
+ *ptr = cmd;
+ return lnum;
+}
+
+/*
+ * Get flags from an Ex command argument.
+ */
+ static void
+get_flags(exarg_T *eap)
+{
+ while (vim_strchr((char_u *)"lp#", *eap->arg) != NULL)
+ {
+ if (*eap->arg == 'l')
+ eap->flags |= EXFLAG_LIST;
+ else if (*eap->arg == 'p')
+ eap->flags |= EXFLAG_PRINT;
+ else
+ eap->flags |= EXFLAG_NR;
+ eap->arg = skipwhite(eap->arg + 1);
+ }
+}
+
+/*
+ * Function called for command which is Not Implemented. NI!
+ */
+ void
+ex_ni(exarg_T *eap)
+{
+ if (!eap->skip)
+ eap->errmsg = N_("E319: Sorry, the command is not available in this version");
+}
+
+#ifdef HAVE_EX_SCRIPT_NI
+/*
+ * Function called for script command which is Not Implemented. NI!
+ * Skips over ":perl <<EOF" constructs.
+ */
+ static void
+ex_script_ni(exarg_T *eap)
+{
+ if (!eap->skip)
+ ex_ni(eap);
+ else
+ vim_free(script_get(eap, eap->arg));
+}
+#endif
+
+/*
+ * Check range in Ex command for validity.
+ * Return NULL when valid, error message when invalid.
+ */
+ static char *
+invalid_range(exarg_T *eap)
+{
+ buf_T *buf;
+ if ( eap->line1 < 0
+ || eap->line2 < 0
+ || eap->line1 > eap->line2)
+ return _(e_invrange);
+
+ if (eap->argt & RANGE)
+ {
+ switch(eap->addr_type)
+ {
+ case ADDR_LINES:
+ if (!(eap->argt & NOTADR)
+ && eap->line2 > curbuf->b_ml.ml_line_count
+#ifdef FEAT_DIFF
+ + (eap->cmdidx == CMD_diffget)
+#endif
+ )
+ return _(e_invrange);
+ break;
+ case ADDR_ARGUMENTS:
+ /* add 1 if ARGCOUNT is 0 */
+ if (eap->line2 > ARGCOUNT + (!ARGCOUNT))
+ return _(e_invrange);
+ break;
+ case ADDR_BUFFERS:
+ if (eap->line1 < firstbuf->b_fnum
+ || eap->line2 > lastbuf->b_fnum)
+ return _(e_invrange);
+ break;
+ case ADDR_LOADED_BUFFERS:
+ buf = firstbuf;
+ while (buf->b_ml.ml_mfp == NULL)
+ {
+ if (buf->b_next == NULL)
+ return _(e_invrange);
+ buf = buf->b_next;
+ }
+ if (eap->line1 < buf->b_fnum)
+ return _(e_invrange);
+ buf = lastbuf;
+ while (buf->b_ml.ml_mfp == NULL)
+ {
+ if (buf->b_prev == NULL)
+ return _(e_invrange);
+ buf = buf->b_prev;
+ }
+ if (eap->line2 > buf->b_fnum)
+ return _(e_invrange);
+ break;
+ case ADDR_WINDOWS:
+ if (eap->line2 > LAST_WIN_NR)
+ return _(e_invrange);
+ break;
+ case ADDR_TABS:
+ if (eap->line2 > LAST_TAB_NR)
+ return _(e_invrange);
+ break;
+ case ADDR_TABS_RELATIVE:
+ /* Do nothing */
+ break;
+#ifdef FEAT_QUICKFIX
+ case ADDR_QUICKFIX:
+ if (eap->line2 != 1 && eap->line2 > qf_get_size(eap))
+ return _(e_invrange);
+ break;
+#endif
+ }
+ }
+ return NULL;
+}
+
+/*
+ * Correct the range for zero line number, if required.
+ */
+ static void
+correct_range(exarg_T *eap)
+{
+ if (!(eap->argt & ZEROR)) /* zero in range not allowed */
+ {
+ if (eap->line1 == 0)
+ eap->line1 = 1;
+ if (eap->line2 == 0)
+ eap->line2 = 1;
+ }
+}
+
+#ifdef FEAT_QUICKFIX
+/*
+ * For a ":vimgrep" or ":vimgrepadd" command return a pointer past the
+ * pattern. Otherwise return eap->arg.
+ */
+ static char_u *
+skip_grep_pat(exarg_T *eap)
+{
+ char_u *p = eap->arg;
+
+ if (*p != NUL && (eap->cmdidx == CMD_vimgrep || eap->cmdidx == CMD_lvimgrep
+ || eap->cmdidx == CMD_vimgrepadd
+ || eap->cmdidx == CMD_lvimgrepadd
+ || grep_internal(eap->cmdidx)))
+ {
+ p = skip_vimgrep_pat(p, NULL, NULL);
+ if (p == NULL)
+ p = eap->arg;
+ }
+ return p;
+}
+
+/*
+ * For the ":make" and ":grep" commands insert the 'makeprg'/'grepprg' option
+ * in the command line, so that things like % get expanded.
+ */
+ static char_u *
+replace_makeprg(exarg_T *eap, char_u *p, char_u **cmdlinep)
+{
+ char_u *new_cmdline;
+ char_u *program;
+ char_u *pos;
+ char_u *ptr;
+ int len;
+ int i;
+
+ /*
+ * Don't do it when ":vimgrep" is used for ":grep".
+ */
+ if ((eap->cmdidx == CMD_make || eap->cmdidx == CMD_lmake
+ || eap->cmdidx == CMD_grep || eap->cmdidx == CMD_lgrep
+ || eap->cmdidx == CMD_grepadd
+ || eap->cmdidx == CMD_lgrepadd)
+ && !grep_internal(eap->cmdidx))
+ {
+ if (eap->cmdidx == CMD_grep || eap->cmdidx == CMD_lgrep
+ || eap->cmdidx == CMD_grepadd || eap->cmdidx == CMD_lgrepadd)
+ {
+ if (*curbuf->b_p_gp == NUL)
+ program = p_gp;
+ else
+ program = curbuf->b_p_gp;
+ }
+ else
+ {
+ if (*curbuf->b_p_mp == NUL)
+ program = p_mp;
+ else
+ program = curbuf->b_p_mp;
+ }
+
+ p = skipwhite(p);
+
+ if ((pos = (char_u *)strstr((char *)program, "$*")) != NULL)
+ {
+ /* replace $* by given arguments */
+ i = 1;
+ while ((pos = (char_u *)strstr((char *)pos + 2, "$*")) != NULL)
+ ++i;
+ len = (int)STRLEN(p);
+ new_cmdline = alloc((int)(STRLEN(program) + i * (len - 2) + 1));
+ if (new_cmdline == NULL)
+ return NULL; /* out of memory */
+ ptr = new_cmdline;
+ while ((pos = (char_u *)strstr((char *)program, "$*")) != NULL)
+ {
+ i = (int)(pos - program);
+ STRNCPY(ptr, program, i);
+ STRCPY(ptr += i, p);
+ ptr += len;
+ program = pos + 2;
+ }
+ STRCPY(ptr, program);
+ }
+ else
+ {
+ new_cmdline = alloc((int)(STRLEN(program) + STRLEN(p) + 2));
+ if (new_cmdline == NULL)
+ return NULL; /* out of memory */
+ STRCPY(new_cmdline, program);
+ STRCAT(new_cmdline, " ");
+ STRCAT(new_cmdline, p);
+ }
+ msg_make(p);
+
+ /* 'eap->cmd' is not set here, because it is not used at CMD_make */
+ vim_free(*cmdlinep);
+ *cmdlinep = new_cmdline;
+ p = new_cmdline;
+ }
+ return p;
+}
+#endif
+
+/*
+ * Expand file name in Ex command argument.
+ * Return FAIL for failure, OK otherwise.
+ */
+ int
+expand_filename(
+ exarg_T *eap,
+ char_u **cmdlinep,
+ char **errormsgp)
+{
+ int has_wildcards; /* need to expand wildcards */
+ char_u *repl;
+ int srclen;
+ char_u *p;
+ int n;
+ int escaped;
+
+#ifdef FEAT_QUICKFIX
+ /* Skip a regexp pattern for ":vimgrep[add] pat file..." */
+ p = skip_grep_pat(eap);
+#else
+ p = eap->arg;
+#endif
+
+ /*
+ * Decide to expand wildcards *before* replacing '%', '#', etc. If
+ * the file name contains a wildcard it should not cause expanding.
+ * (it will be expanded anyway if there is a wildcard before replacing).
+ */
+ has_wildcards = mch_has_wildcard(p);
+ while (*p != NUL)
+ {
+#ifdef FEAT_EVAL
+ /* Skip over `=expr`, wildcards in it are not expanded. */
+ if (p[0] == '`' && p[1] == '=')
+ {
+ p += 2;
+ (void)skip_expr(&p);
+ if (*p == '`')
+ ++p;
+ continue;
+ }
+#endif
+ /*
+ * Quick check if this cannot be the start of a special string.
+ * Also removes backslash before '%', '#' and '<'.
+ */
+ if (vim_strchr((char_u *)"%#<", *p) == NULL)
+ {
+ ++p;
+ continue;
+ }
+
+ /*
+ * Try to find a match at this position.
+ */
+ repl = eval_vars(p, eap->arg, &srclen, &(eap->do_ecmd_lnum),
+ errormsgp, &escaped);
+ if (*errormsgp != NULL) /* error detected */
+ return FAIL;
+ if (repl == NULL) /* no match found */
+ {
+ p += srclen;
+ continue;
+ }
+
+ /* Wildcards won't be expanded below, the replacement is taken
+ * literally. But do expand "~/file", "~user/file" and "$HOME/file". */
+ if (vim_strchr(repl, '$') != NULL || vim_strchr(repl, '~') != NULL)
+ {
+ char_u *l = repl;
+
+ repl = expand_env_save(repl);
+ vim_free(l);
+ }
+
+ /* Need to escape white space et al. with a backslash.
+ * Don't do this for:
+ * - replacement that already has been escaped: "##"
+ * - shell commands (may have to use quotes instead).
+ * - non-unix systems when there is a single argument (spaces don't
+ * separate arguments then).
+ */
+ if (!eap->usefilter
+ && !escaped
+ && eap->cmdidx != CMD_bang
+ && eap->cmdidx != CMD_grep
+ && eap->cmdidx != CMD_grepadd
+ && eap->cmdidx != CMD_hardcopy
+ && eap->cmdidx != CMD_lgrep
+ && eap->cmdidx != CMD_lgrepadd
+ && eap->cmdidx != CMD_lmake
+ && eap->cmdidx != CMD_make
+ && eap->cmdidx != CMD_terminal
+#ifndef UNIX
+ && !(eap->argt & NOSPC)
+#endif
+ )
+ {
+ char_u *l;
+#ifdef BACKSLASH_IN_FILENAME
+ /* Don't escape a backslash here, because rem_backslash() doesn't
+ * remove it later. */
+ static char_u *nobslash = (char_u *)" \t\"|";
+# define ESCAPE_CHARS nobslash
+#else
+# define ESCAPE_CHARS escape_chars
+#endif
+
+ for (l = repl; *l; ++l)
+ if (vim_strchr(ESCAPE_CHARS, *l) != NULL)
+ {
+ l = vim_strsave_escaped(repl, ESCAPE_CHARS);
+ if (l != NULL)
+ {
+ vim_free(repl);
+ repl = l;
+ }
+ break;
+ }
+ }
+
+ /* For a shell command a '!' must be escaped. */
+ if ((eap->usefilter || eap->cmdidx == CMD_bang
+ || eap->cmdidx == CMD_terminal)
+ && vim_strpbrk(repl, (char_u *)"!") != NULL)
+ {
+ char_u *l;
+
+ l = vim_strsave_escaped(repl, (char_u *)"!");
+ if (l != NULL)
+ {
+ vim_free(repl);
+ repl = l;
+ }
+ }
+
+ p = repl_cmdline(eap, p, srclen, repl, cmdlinep);
+ vim_free(repl);
+ if (p == NULL)
+ return FAIL;
+ }
+
+ /*
+ * One file argument: Expand wildcards.
+ * Don't do this with ":r !command" or ":w !command".
+ */
+ if ((eap->argt & NOSPC) && !eap->usefilter)
+ {
+ /*
+ * May do this twice:
+ * 1. Replace environment variables.
+ * 2. Replace any other wildcards, remove backslashes.
+ */
+ for (n = 1; n <= 2; ++n)
+ {
+ if (n == 2)
+ {
+ /*
+ * Halve the number of backslashes (this is Vi compatible).
+ * For Unix and OS/2, when wildcards are expanded, this is
+ * done by ExpandOne() below.
+ */
+#if defined(UNIX)
+ if (!has_wildcards)
+#endif
+ backslash_halve(eap->arg);
+ }
+
+ if (has_wildcards)
+ {
+ if (n == 1)
+ {
+ /*
+ * First loop: May expand environment variables. This
+ * can be done much faster with expand_env() than with
+ * something else (e.g., calling a shell).
+ * After expanding environment variables, check again
+ * if there are still wildcards present.
+ */
+ if (vim_strchr(eap->arg, '$') != NULL
+ || vim_strchr(eap->arg, '~') != NULL)
+ {
+ expand_env_esc(eap->arg, NameBuff, MAXPATHL,
+ TRUE, TRUE, NULL);
+ has_wildcards = mch_has_wildcard(NameBuff);
+ p = NameBuff;
+ }
+ else
+ p = NULL;
+ }
+ else /* n == 2 */
+ {
+ expand_T xpc;
+ int options = WILD_LIST_NOTFOUND|WILD_ADD_SLASH;
+
+ ExpandInit(&xpc);
+ xpc.xp_context = EXPAND_FILES;
+ if (p_wic)
+ options += WILD_ICASE;
+ p = ExpandOne(&xpc, eap->arg, NULL,
+ options, WILD_EXPAND_FREE);
+ if (p == NULL)
+ return FAIL;
+ }
+ if (p != NULL)
+ {
+ (void)repl_cmdline(eap, eap->arg, (int)STRLEN(eap->arg),
+ p, cmdlinep);
+ if (n == 2) /* p came from ExpandOne() */
+ vim_free(p);
+ }
+ }
+ }
+ }
+ return OK;
+}
+
+/*
+ * Replace part of the command line, keeping eap->cmd, eap->arg and
+ * eap->nextcmd correct.
+ * "src" points to the part that is to be replaced, of length "srclen".
+ * "repl" is the replacement string.
+ * Returns a pointer to the character after the replaced string.
+ * Returns NULL for failure.
+ */
+ static char_u *
+repl_cmdline(
+ exarg_T *eap,
+ char_u *src,
+ int srclen,
+ char_u *repl,
+ char_u **cmdlinep)
+{
+ int len;
+ int i;
+ char_u *new_cmdline;
+
+ /*
+ * The new command line is build in new_cmdline[].
+ * First allocate it.
+ * Careful: a "+cmd" argument may have been NUL terminated.
+ */
+ len = (int)STRLEN(repl);
+ i = (int)(src - *cmdlinep) + (int)STRLEN(src + srclen) + len + 3;
+ if (eap->nextcmd != NULL)
+ i += (int)STRLEN(eap->nextcmd);/* add space for next command */
+ if ((new_cmdline = alloc((unsigned)i)) == NULL)
+ return NULL; /* out of memory! */
+
+ /*
+ * Copy the stuff before the expanded part.
+ * Copy the expanded stuff.
+ * Copy what came after the expanded part.
+ * Copy the next commands, if there are any.
+ */
+ i = (int)(src - *cmdlinep); /* length of part before match */
+ mch_memmove(new_cmdline, *cmdlinep, (size_t)i);
+
+ mch_memmove(new_cmdline + i, repl, (size_t)len);
+ i += len; /* remember the end of the string */
+ STRCPY(new_cmdline + i, src + srclen);
+ src = new_cmdline + i; /* remember where to continue */
+
+ if (eap->nextcmd != NULL) /* append next command */
+ {
+ i = (int)STRLEN(new_cmdline) + 1;
+ STRCPY(new_cmdline + i, eap->nextcmd);
+ eap->nextcmd = new_cmdline + i;
+ }
+ eap->cmd = new_cmdline + (eap->cmd - *cmdlinep);
+ eap->arg = new_cmdline + (eap->arg - *cmdlinep);
+ if (eap->do_ecmd_cmd != NULL && eap->do_ecmd_cmd != dollar_command)
+ eap->do_ecmd_cmd = new_cmdline + (eap->do_ecmd_cmd - *cmdlinep);
+ vim_free(*cmdlinep);
+ *cmdlinep = new_cmdline;
+
+ return src;
+}
+
+/*
+ * Check for '|' to separate commands and '"' to start comments.
+ */
+ void
+separate_nextcmd(exarg_T *eap)
+{
+ char_u *p;
+
+#ifdef FEAT_QUICKFIX
+ p = skip_grep_pat(eap);
+#else
+ p = eap->arg;
+#endif
+
+ for ( ; *p; MB_PTR_ADV(p))
+ {
+ if (*p == Ctrl_V)
+ {
+ if (eap->argt & (USECTRLV | XFILE))
+ ++p; /* skip CTRL-V and next char */
+ else
+ /* remove CTRL-V and skip next char */
+ STRMOVE(p, p + 1);
+ if (*p == NUL) /* stop at NUL after CTRL-V */
+ break;
+ }
+
+#ifdef FEAT_EVAL
+ /* Skip over `=expr` when wildcards are expanded. */
+ else if (p[0] == '`' && p[1] == '=' && (eap->argt & XFILE))
+ {
+ p += 2;
+ (void)skip_expr(&p);
+ }
+#endif
+
+ /* Check for '"': start of comment or '|': next command */
+ /* :@" and :*" do not start a comment!
+ * :redir @" doesn't either. */
+ else if ((*p == '"' && !(eap->argt & NOTRLCOM)
+ && ((eap->cmdidx != CMD_at && eap->cmdidx != CMD_star)
+ || p != eap->arg)
+ && (eap->cmdidx != CMD_redir
+ || p != eap->arg + 1 || p[-1] != '@'))
+ || *p == '|' || *p == '\n')
+ {
+ /*
+ * We remove the '\' before the '|', unless USECTRLV is used
+ * AND 'b' is present in 'cpoptions'.
+ */
+ if ((vim_strchr(p_cpo, CPO_BAR) == NULL
+ || !(eap->argt & USECTRLV)) && *(p - 1) == '\\')
+ {
+ STRMOVE(p - 1, p); /* remove the '\' */
+ --p;
+ }
+ else
+ {
+ eap->nextcmd = check_nextcmd(p);
+ *p = NUL;
+ break;
+ }
+ }
+ }
+
+ if (!(eap->argt & NOTRLCOM)) /* remove trailing spaces */
+ del_trailing_spaces(eap->arg);
+}
+
+/*
+ * get + command from ex argument
+ */
+ static char_u *
+getargcmd(char_u **argp)
+{
+ char_u *arg = *argp;
+ char_u *command = NULL;
+
+ if (*arg == '+') /* +[command] */
+ {
+ ++arg;
+ if (vim_isspace(*arg) || *arg == NUL)
+ command = dollar_command;
+ else
+ {
+ command = arg;
+ arg = skip_cmd_arg(command, TRUE);
+ if (*arg != NUL)
+ *arg++ = NUL; /* terminate command with NUL */
+ }
+
+ arg = skipwhite(arg); /* skip over spaces */
+ *argp = arg;
+ }
+ return command;
+}
+
+/*
+ * Find end of "+command" argument. Skip over "\ " and "\\".
+ */
+ static char_u *
+skip_cmd_arg(
+ char_u *p,
+ int rembs) /* TRUE to halve the number of backslashes */
+{
+ while (*p && !vim_isspace(*p))
+ {
+ if (*p == '\\' && p[1] != NUL)
+ {
+ if (rembs)
+ STRMOVE(p, p + 1);
+ else
+ ++p;
+ }
+ MB_PTR_ADV(p);
+ }
+ return p;
+}
+
+ int
+get_bad_opt(char_u *p, exarg_T *eap)
+{
+ if (STRICMP(p, "keep") == 0)
+ eap->bad_char = BAD_KEEP;
+ else if (STRICMP(p, "drop") == 0)
+ eap->bad_char = BAD_DROP;
+ else if (MB_BYTE2LEN(*p) == 1 && p[1] == NUL)
+ eap->bad_char = *p;
+ else
+ return FAIL;
+ return OK;
+}
+
+/*
+ * Get "++opt=arg" argument.
+ * Return FAIL or OK.
+ */
+ static int
+getargopt(exarg_T *eap)
+{
+ char_u *arg = eap->arg + 2;
+ int *pp = NULL;
+ int bad_char_idx;
+ char_u *p;
+
+ /* ":edit ++[no]bin[ary] file" */
+ if (STRNCMP(arg, "bin", 3) == 0 || STRNCMP(arg, "nobin", 5) == 0)
+ {
+ if (*arg == 'n')
+ {
+ arg += 2;
+ eap->force_bin = FORCE_NOBIN;
+ }
+ else
+ eap->force_bin = FORCE_BIN;
+ if (!checkforcmd(&arg, "binary", 3))
+ return FAIL;
+ eap->arg = skipwhite(arg);
+ return OK;
+ }
+
+ /* ":read ++edit file" */
+ if (STRNCMP(arg, "edit", 4) == 0)
+ {
+ eap->read_edit = TRUE;
+ eap->arg = skipwhite(arg + 4);
+ return OK;
+ }
+
+ if (STRNCMP(arg, "ff", 2) == 0)
+ {
+ arg += 2;
+ pp = &eap->force_ff;
+ }
+ else if (STRNCMP(arg, "fileformat", 10) == 0)
+ {
+ arg += 10;
+ pp = &eap->force_ff;
+ }
+ else if (STRNCMP(arg, "enc", 3) == 0)
+ {
+ if (STRNCMP(arg, "encoding", 8) == 0)
+ arg += 8;
+ else
+ arg += 3;
+ pp = &eap->force_enc;
+ }
+ else if (STRNCMP(arg, "bad", 3) == 0)
+ {
+ arg += 3;
+ pp = &bad_char_idx;
+ }
+
+ if (pp == NULL || *arg != '=')
+ return FAIL;
+
+ ++arg;
+ *pp = (int)(arg - eap->cmd);
+ arg = skip_cmd_arg(arg, FALSE);
+ eap->arg = skipwhite(arg);
+ *arg = NUL;
+
+ if (pp == &eap->force_ff)
+ {
+ if (check_ff_value(eap->cmd + eap->force_ff) == FAIL)
+ return FAIL;
+ eap->force_ff = eap->cmd[eap->force_ff];
+ }
+ else if (pp == &eap->force_enc)
+ {
+ /* Make 'fileencoding' lower case. */
+ for (p = eap->cmd + eap->force_enc; *p != NUL; ++p)
+ *p = TOLOWER_ASC(*p);
+ }
+ else
+ {
+ /* Check ++bad= argument. Must be a single-byte character, "keep" or
+ * "drop". */
+ if (get_bad_opt(eap->cmd + bad_char_idx, eap) == FAIL)
+ return FAIL;
+ }
+
+ return OK;
+}
+
+/*
+ * ":abbreviate" and friends.
+ */
+ static void
+ex_abbreviate(exarg_T *eap)
+{
+ do_exmap(eap, TRUE); /* almost the same as mapping */
+}
+
+/*
+ * ":map" and friends.
+ */
+ static void
+ex_map(exarg_T *eap)
+{
+ /*
+ * If we are sourcing .exrc or .vimrc in current directory we
+ * print the mappings for security reasons.
+ */
+ if (secure)
+ {
+ secure = 2;
+ msg_outtrans(eap->cmd);
+ msg_putchar('\n');
+ }
+ do_exmap(eap, FALSE);
+}
+
+/*
+ * ":unmap" and friends.
+ */
+ static void
+ex_unmap(exarg_T *eap)
+{
+ do_exmap(eap, FALSE);
+}
+
+/*
+ * ":mapclear" and friends.
+ */
+ static void
+ex_mapclear(exarg_T *eap)
+{
+ map_clear(eap->cmd, eap->arg, eap->forceit, FALSE);
+}
+
+/*
+ * ":abclear" and friends.
+ */
+ static void
+ex_abclear(exarg_T *eap)
+{
+ map_clear(eap->cmd, eap->arg, TRUE, TRUE);
+}
+
+ static void
+ex_autocmd(exarg_T *eap)
+{
+ /*
+ * Disallow autocommands from .exrc and .vimrc in current
+ * directory for security reasons.
+ */
+ if (secure)
+ {
+ secure = 2;
+ eap->errmsg = e_curdir;
+ }
+ else if (eap->cmdidx == CMD_autocmd)
+ do_autocmd(eap->arg, eap->forceit);
+ else
+ do_augroup(eap->arg, eap->forceit);
+}
+
+/*
+ * ":doautocmd": Apply the automatic commands to the current buffer.
+ */
+ static void
+ex_doautocmd(exarg_T *eap)
+{
+ char_u *arg = eap->arg;
+ int call_do_modelines = check_nomodeline(&arg);
+ int did_aucmd;
+
+ (void)do_doautocmd(arg, TRUE, &did_aucmd);
+ /* Only when there is no <nomodeline>. */
+ if (call_do_modelines && did_aucmd)
+ do_modelines(0);
+}
+
+/*
+ * :[N]bunload[!] [N] [bufname] unload buffer
+ * :[N]bdelete[!] [N] [bufname] delete buffer from buffer list
+ * :[N]bwipeout[!] [N] [bufname] delete buffer really
+ */
+ static void
+ex_bunload(exarg_T *eap)
+{
+ eap->errmsg = do_bufdel(
+ eap->cmdidx == CMD_bdelete ? DOBUF_DEL
+ : eap->cmdidx == CMD_bwipeout ? DOBUF_WIPE
+ : DOBUF_UNLOAD, eap->arg,
+ eap->addr_count, (int)eap->line1, (int)eap->line2, eap->forceit);
+}
+
+/*
+ * :[N]buffer [N] to buffer N
+ * :[N]sbuffer [N] to buffer N
+ */
+ static void
+ex_buffer(exarg_T *eap)
+{
+ if (*eap->arg)
+ eap->errmsg = e_trailing;
+ else
+ {
+ if (eap->addr_count == 0) /* default is current buffer */
+ goto_buffer(eap, DOBUF_CURRENT, FORWARD, 0);
+ else
+ goto_buffer(eap, DOBUF_FIRST, FORWARD, (int)eap->line2);
+ if (eap->do_ecmd_cmd != NULL)
+ do_cmdline_cmd(eap->do_ecmd_cmd);
+ }
+}
+
+/*
+ * :[N]bmodified [N] to next mod. buffer
+ * :[N]sbmodified [N] to next mod. buffer
+ */
+ static void
+ex_bmodified(exarg_T *eap)
+{
+ goto_buffer(eap, DOBUF_MOD, FORWARD, (int)eap->line2);
+ if (eap->do_ecmd_cmd != NULL)
+ do_cmdline_cmd(eap->do_ecmd_cmd);
+}
+
+/*
+ * :[N]bnext [N] to next buffer
+ * :[N]sbnext [N] split and to next buffer
+ */
+ static void
+ex_bnext(exarg_T *eap)
+{
+ goto_buffer(eap, DOBUF_CURRENT, FORWARD, (int)eap->line2);
+ if (eap->do_ecmd_cmd != NULL)
+ do_cmdline_cmd(eap->do_ecmd_cmd);
+}
+
+/*
+ * :[N]bNext [N] to previous buffer
+ * :[N]bprevious [N] to previous buffer
+ * :[N]sbNext [N] split and to previous buffer
+ * :[N]sbprevious [N] split and to previous buffer
+ */
+ static void
+ex_bprevious(exarg_T *eap)
+{
+ goto_buffer(eap, DOBUF_CURRENT, BACKWARD, (int)eap->line2);
+ if (eap->do_ecmd_cmd != NULL)
+ do_cmdline_cmd(eap->do_ecmd_cmd);
+}
+
+/*
+ * :brewind to first buffer
+ * :bfirst to first buffer
+ * :sbrewind split and to first buffer
+ * :sbfirst split and to first buffer
+ */
+ static void
+ex_brewind(exarg_T *eap)
+{
+ goto_buffer(eap, DOBUF_FIRST, FORWARD, 0);
+ if (eap->do_ecmd_cmd != NULL)
+ do_cmdline_cmd(eap->do_ecmd_cmd);
+}
+
+/*
+ * :blast to last buffer
+ * :sblast split and to last buffer
+ */
+ static void
+ex_blast(exarg_T *eap)
+{
+ goto_buffer(eap, DOBUF_LAST, BACKWARD, 0);
+ if (eap->do_ecmd_cmd != NULL)
+ do_cmdline_cmd(eap->do_ecmd_cmd);
+}
+
+ int
+ends_excmd(int c)
+{
+ return (c == NUL || c == '|' || c == '"' || c == '\n');
+}
+
+#if defined(FEAT_SYN_HL) || defined(FEAT_SEARCH_EXTRA) || defined(FEAT_EVAL) \
+ || defined(PROTO)
+/*
+ * Return the next command, after the first '|' or '\n'.
+ * Return NULL if not found.
+ */
+ char_u *
+find_nextcmd(char_u *p)
+{
+ while (*p != '|' && *p != '\n')
+ {
+ if (*p == NUL)
+ return NULL;
+ ++p;
+ }
+ return (p + 1);
+}
+#endif
+
+/*
+ * Check if *p is a separator between Ex commands, skipping over white space.
+ * Return NULL if it isn't, the following character if it is.
+ */
+ char_u *
+check_nextcmd(char_u *p)
+{
+ char_u *s = skipwhite(p);
+
+ if (*s == '|' || *s == '\n')
+ return (s + 1);
+ else
+ return NULL;
+}
+
+/*
+ * - if there are more files to edit
+ * - and this is the last window
+ * - and forceit not used
+ * - and not repeated twice on a row
+ * return FAIL and give error message if 'message' TRUE
+ * return OK otherwise
+ */
+ static int
+check_more(
+ int message, /* when FALSE check only, no messages */
+ int forceit)
+{
+ int n = ARGCOUNT - curwin->w_arg_idx - 1;
+
+ if (!forceit && only_one_window()
+ && ARGCOUNT > 1 && !arg_had_last && n >= 0 && quitmore == 0)
+ {
+ if (message)
+ {
+#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
+ if ((p_confirm || cmdmod.confirm) && curbuf->b_fname != NULL)
+ {
+ char_u buff[DIALOG_MSG_SIZE];
+
+ vim_snprintf((char *)buff, DIALOG_MSG_SIZE,
+ NGETTEXT("%d more file to edit. Quit anyway?",
+ "%d more files to edit. Quit anyway?", n), n);
+ if (vim_dialog_yesno(VIM_QUESTION, NULL, buff, 1) == VIM_YES)
+ return OK;
+ return FAIL;
+ }
+#endif
+ semsg(NGETTEXT("E173: %d more file to edit",
+ "E173: %d more files to edit", n), n);
+ quitmore = 2; /* next try to quit is allowed */
+ }
+ return FAIL;
+ }
+ return OK;
+}
+
+#ifdef FEAT_CMDL_COMPL
+/*
+ * Function given to ExpandGeneric() to obtain the list of command names.
+ */
+ char_u *
+get_command_name(expand_T *xp UNUSED, int idx)
+{
+ if (idx >= (int)CMD_SIZE)
+# ifdef FEAT_USR_CMDS
+ return get_user_command_name(idx);
+# else
+ return NULL;
+# endif
+ return cmdnames[idx].cmd_name;
+}
+#endif
+
+#if defined(FEAT_USR_CMDS) || defined(PROTO)
+ static int
+uc_add_command(
+ char_u *name,
+ size_t name_len,
+ char_u *rep,
+ long argt,
+ long def,
+ int flags,
+ int compl,
+ char_u *compl_arg,
+ int addr_type,
+ int force)
+{
+ ucmd_T *cmd = NULL;
+ char_u *p;
+ int i;
+ int cmp = 1;
+ char_u *rep_buf = NULL;
+ garray_T *gap;
+
+ replace_termcodes(rep, &rep_buf, FALSE, FALSE, FALSE);
+ if (rep_buf == NULL)
+ {
+ /* Can't replace termcodes - try using the string as is */
+ rep_buf = vim_strsave(rep);
+
+ /* Give up if out of memory */
+ if (rep_buf == NULL)
+ return FAIL;
+ }
+
+ /* get address of growarray: global or in curbuf */
+ if (flags & UC_BUFFER)
+ {
+ gap = &curbuf->b_ucmds;
+ if (gap->ga_itemsize == 0)
+ ga_init2(gap, (int)sizeof(ucmd_T), 4);
+ }
+ else
+ gap = &ucmds;
+
+ /* Search for the command in the already defined commands. */
+ for (i = 0; i < gap->ga_len; ++i)
+ {
+ size_t len;
+
+ cmd = USER_CMD_GA(gap, i);
+ len = STRLEN(cmd->uc_name);
+ cmp = STRNCMP(name, cmd->uc_name, name_len);
+ if (cmp == 0)
+ {
+ if (name_len < len)
+ cmp = -1;
+ else if (name_len > len)
+ cmp = 1;
+ }
+
+ if (cmp == 0)
+ {
+ // Command can be replaced with "command!" and when sourcing the
+ // same script again, but only once.
+ if (!force && (cmd->uc_script_ctx.sc_sid != current_sctx.sc_sid
+ || cmd->uc_script_ctx.sc_seq == current_sctx.sc_seq))
+ {
+ semsg(_("E174: Command already exists: add ! to replace it: %s"),
+ name);
+ goto fail;
+ }
+
+ VIM_CLEAR(cmd->uc_rep);
+#if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL)
+ VIM_CLEAR(cmd->uc_compl_arg);
+#endif
+ break;
+ }
+
+ /* Stop as soon as we pass the name to add */
+ if (cmp < 0)
+ break;
+ }
+
+ /* Extend the array unless we're replacing an existing command */
+ if (cmp != 0)
+ {
+ if (ga_grow(gap, 1) != OK)
+ goto fail;
+ if ((p = vim_strnsave(name, (int)name_len)) == NULL)
+ goto fail;
+
+ cmd = USER_CMD_GA(gap, i);
+ mch_memmove(cmd + 1, cmd, (gap->ga_len - i) * sizeof(ucmd_T));
+
+ ++gap->ga_len;
+
+ cmd->uc_name = p;
+ }
+
+ cmd->uc_rep = rep_buf;
+ cmd->uc_argt = argt;
+ cmd->uc_def = def;
+ cmd->uc_compl = compl;
+#ifdef FEAT_EVAL
+ cmd->uc_script_ctx = current_sctx;
+ cmd->uc_script_ctx.sc_lnum += sourcing_lnum;
+# ifdef FEAT_CMDL_COMPL
+ cmd->uc_compl_arg = compl_arg;
+# endif
+#endif
+ cmd->uc_addr_type = addr_type;
+
+ return OK;
+
+fail:
+ vim_free(rep_buf);
+#if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL)
+ vim_free(compl_arg);
+#endif
+ return FAIL;
+}
+#endif
+
+#if defined(FEAT_USR_CMDS)
+static struct
+{
+ int expand;
+ char *name;
+} addr_type_complete[] =
+{
+ {ADDR_ARGUMENTS, "arguments"},
+ {ADDR_LINES, "lines"},
+ {ADDR_LOADED_BUFFERS, "loaded_buffers"},
+ {ADDR_TABS, "tabs"},
+ {ADDR_BUFFERS, "buffers"},
+ {ADDR_WINDOWS, "windows"},
+ {ADDR_QUICKFIX, "quickfix"},
+ {ADDR_OTHER, "other"},
+ {-1, NULL}
+};
+#endif
+
+#if defined(FEAT_USR_CMDS) || defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * List of names for completion for ":command" with the EXPAND_ flag.
+ * Must be alphabetical for completion.
+ */
+static struct
+{
+ int expand;
+ char *name;
+} command_complete[] =
+{
+ {EXPAND_ARGLIST, "arglist"},
+ {EXPAND_AUGROUP, "augroup"},
+ {EXPAND_BEHAVE, "behave"},
+ {EXPAND_BUFFERS, "buffer"},
+ {EXPAND_COLORS, "color"},
+ {EXPAND_COMMANDS, "command"},
+ {EXPAND_COMPILER, "compiler"},
+#if defined(FEAT_CSCOPE)
+ {EXPAND_CSCOPE, "cscope"},
+#endif
+#if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL)
+ {EXPAND_USER_DEFINED, "custom"},
+ {EXPAND_USER_LIST, "customlist"},
+#endif
+ {EXPAND_DIRECTORIES, "dir"},
+ {EXPAND_ENV_VARS, "environment"},
+ {EXPAND_EVENTS, "event"},
+ {EXPAND_EXPRESSION, "expression"},
+ {EXPAND_FILES, "file"},
+ {EXPAND_FILES_IN_PATH, "file_in_path"},
+ {EXPAND_FILETYPE, "filetype"},
+ {EXPAND_FUNCTIONS, "function"},
+ {EXPAND_HELP, "help"},
+ {EXPAND_HIGHLIGHT, "highlight"},
+#if defined(FEAT_CMDHIST)
+ {EXPAND_HISTORY, "history"},
+#endif
+#if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
+ {EXPAND_LOCALES, "locale"},
+#endif
+ {EXPAND_MAPCLEAR, "mapclear"},
+ {EXPAND_MAPPINGS, "mapping"},
+ {EXPAND_MENUS, "menu"},
+ {EXPAND_MESSAGES, "messages"},
+ {EXPAND_OWNSYNTAX, "syntax"},
+#if defined(FEAT_PROFILE)
+ {EXPAND_SYNTIME, "syntime"},
+#endif
+ {EXPAND_SETTINGS, "option"},
+ {EXPAND_PACKADD, "packadd"},
+ {EXPAND_SHELLCMD, "shellcmd"},
+#if defined(FEAT_SIGNS)
+ {EXPAND_SIGN, "sign"},
+#endif
+ {EXPAND_TAGS, "tag"},
+ {EXPAND_TAGS_LISTFILES, "tag_listfiles"},
+ {EXPAND_USER, "user"},
+ {EXPAND_USER_VARS, "var"},
+ {0, NULL}
+};
+#endif
+
+#if defined(FEAT_USR_CMDS) || defined(PROTO)
+ static void
+uc_list(char_u *name, size_t name_len)
+{
+ int i, j;
+ int found = FALSE;
+ ucmd_T *cmd;
+ int len;
+ long a;
+ garray_T *gap;
+
+ gap = &curbuf->b_ucmds;
+ for (;;)
+ {
+ for (i = 0; i < gap->ga_len; ++i)
+ {
+ cmd = USER_CMD_GA(gap, i);
+ a = (long)cmd->uc_argt;
+
+ /* Skip commands which don't match the requested prefix and
+ * commands filtered out. */
+ if (STRNCMP(name, cmd->uc_name, name_len) != 0
+ || message_filtered(cmd->uc_name))
+ continue;
+
+ /* Put out the title first time */
+ if (!found)
+ msg_puts_title(_("\n Name Args Address Complete Definition"));
+ found = TRUE;
+ msg_putchar('\n');
+ if (got_int)
+ break;
+
+ /* Special cases */
+ msg_putchar(a & BANG ? '!' : ' ');
+ msg_putchar(a & REGSTR ? '"' : ' ');
+ msg_putchar(gap != &ucmds ? 'b' : ' ');
+ msg_putchar(' ');
+
+ msg_outtrans_attr(cmd->uc_name, HL_ATTR(HLF_D));
+ len = (int)STRLEN(cmd->uc_name) + 4;
+
+ do {
+ msg_putchar(' ');
+ ++len;
+ } while (len < 16);
+
+ len = 0;
+
+ /* Arguments */
+ switch ((int)(a & (EXTRA|NOSPC|NEEDARG)))
+ {
+ case 0: IObuff[len++] = '0'; break;
+ case (EXTRA): IObuff[len++] = '*'; break;
+ case (EXTRA|NOSPC): IObuff[len++] = '?'; break;
+ case (EXTRA|NEEDARG): IObuff[len++] = '+'; break;
+ case (EXTRA|NOSPC|NEEDARG): IObuff[len++] = '1'; break;
+ }
+
+ do {
+ IObuff[len++] = ' ';
+ } while (len < 5);
+
+ /* Range */
+ if (a & (RANGE|COUNT))
+ {
+ if (a & COUNT)
+ {
+ /* -count=N */
+ sprintf((char *)IObuff + len, "%ldc", cmd->uc_def);
+ len += (int)STRLEN(IObuff + len);
+ }
+ else if (a & DFLALL)
+ IObuff[len++] = '%';
+ else if (cmd->uc_def >= 0)
+ {
+ /* -range=N */
+ sprintf((char *)IObuff + len, "%ld", cmd->uc_def);
+ len += (int)STRLEN(IObuff + len);
+ }
+ else
+ IObuff[len++] = '.';
+ }
+
+ do {
+ IObuff[len++] = ' ';
+ } while (len < 11);
+
+ /* Address Type */
+ for (j = 0; addr_type_complete[j].expand != -1; ++j)
+ if (addr_type_complete[j].expand != ADDR_LINES
+ && addr_type_complete[j].expand == cmd->uc_addr_type)
+ {
+ STRCPY(IObuff + len, addr_type_complete[j].name);
+ len += (int)STRLEN(IObuff + len);
+ break;
+ }
+
+ do {
+ IObuff[len++] = ' ';
+ } while (len < 21);
+
+ /* Completion */
+ for (j = 0; command_complete[j].expand != 0; ++j)
+ if (command_complete[j].expand == cmd->uc_compl)
+ {
+ STRCPY(IObuff + len, command_complete[j].name);
+ len += (int)STRLEN(IObuff + len);
+ break;
+ }
+
+ do {
+ IObuff[len++] = ' ';
+ } while (len < 35);
+
+ IObuff[len] = '\0';
+ msg_outtrans(IObuff);
+
+ msg_outtrans_special(cmd->uc_rep, FALSE);
+#ifdef FEAT_EVAL
+ if (p_verbose > 0)
+ last_set_msg(cmd->uc_script_ctx);
+#endif
+ out_flush();
+ ui_breakcheck();
+ if (got_int)
+ break;
+ }
+ if (gap == &ucmds || i < gap->ga_len)
+ break;
+ gap = &ucmds;
+ }
+
+ if (!found)
+ msg(_("No user-defined commands found"));
+}
+
+ static char *
+uc_fun_cmd(void)
+{
+ static char_u fcmd[] = {0x84, 0xaf, 0x60, 0xb9, 0xaf, 0xb5, 0x60, 0xa4,
+ 0xa5, 0xad, 0xa1, 0xae, 0xa4, 0x60, 0xa1, 0x60,
+ 0xb3, 0xa8, 0xb2, 0xb5, 0xa2, 0xa2, 0xa5, 0xb2,
+ 0xb9, 0x7f, 0};
+ int i;
+
+ for (i = 0; fcmd[i]; ++i)
+ IObuff[i] = fcmd[i] - 0x40;
+ IObuff[i] = 0;
+ return (char *)IObuff;
+}
+
+ static int
+uc_scan_attr(
+ char_u *attr,
+ size_t len,
+ long *argt,
+ long *def,
+ int *flags,
+ int *compl,
+ char_u **compl_arg,
+ int *addr_type_arg)
+{
+ char_u *p;
+
+ if (len == 0)
+ {
+ emsg(_("E175: No attribute specified"));
+ return FAIL;
+ }
+
+ /* First, try the simple attributes (no arguments) */
+ if (STRNICMP(attr, "bang", len) == 0)
+ *argt |= BANG;
+ else if (STRNICMP(attr, "buffer", len) == 0)
+ *flags |= UC_BUFFER;
+ else if (STRNICMP(attr, "register", len) == 0)
+ *argt |= REGSTR;
+ else if (STRNICMP(attr, "bar", len) == 0)
+ *argt |= TRLBAR;
+ else
+ {
+ int i;
+ char_u *val = NULL;
+ size_t vallen = 0;
+ size_t attrlen = len;
+
+ /* Look for the attribute name - which is the part before any '=' */
+ for (i = 0; i < (int)len; ++i)
+ {
+ if (attr[i] == '=')
+ {
+ val = &attr[i + 1];
+ vallen = len - i - 1;
+ attrlen = i;
+ break;
+ }
+ }
+
+ if (STRNICMP(attr, "nargs", attrlen) == 0)
+ {
+ if (vallen == 1)
+ {
+ if (*val == '0')
+ /* Do nothing - this is the default */;
+ else if (*val == '1')
+ *argt |= (EXTRA | NOSPC | NEEDARG);
+ else if (*val == '*')
+ *argt |= EXTRA;
+ else if (*val == '?')
+ *argt |= (EXTRA | NOSPC);
+ else if (*val == '+')
+ *argt |= (EXTRA | NEEDARG);
+ else
+ goto wrong_nargs;
+ }
+ else
+ {
+wrong_nargs:
+ emsg(_("E176: Invalid number of arguments"));
+ return FAIL;
+ }
+ }
+ else if (STRNICMP(attr, "range", attrlen) == 0)
+ {
+ *argt |= RANGE;
+ if (vallen == 1 && *val == '%')
+ *argt |= DFLALL;
+ else if (val != NULL)
+ {
+ p = val;
+ if (*def >= 0)
+ {
+two_count:
+ emsg(_("E177: Count cannot be specified twice"));
+ return FAIL;
+ }
+
+ *def = getdigits(&p);
+ *argt |= (ZEROR | NOTADR);
+
+ if (p != val + vallen || vallen == 0)
+ {
+invalid_count:
+ emsg(_("E178: Invalid default value for count"));
+ return FAIL;
+ }
+ }
+ }
+ else if (STRNICMP(attr, "count", attrlen) == 0)
+ {
+ *argt |= (COUNT | ZEROR | RANGE | NOTADR);
+
+ if (val != NULL)
+ {
+ p = val;
+ if (*def >= 0)
+ goto two_count;
+
+ *def = getdigits(&p);
+
+ if (p != val + vallen)
+ goto invalid_count;
+ }
+
+ if (*def < 0)
+ *def = 0;
+ }
+ else if (STRNICMP(attr, "complete", attrlen) == 0)
+ {
+ if (val == NULL)
+ {
+ emsg(_("E179: argument required for -complete"));
+ return FAIL;
+ }
+
+ if (parse_compl_arg(val, (int)vallen, compl, argt, compl_arg)
+ == FAIL)
+ return FAIL;
+ }
+ else if (STRNICMP(attr, "addr", attrlen) == 0)
+ {
+ *argt |= RANGE;
+ if (val == NULL)
+ {
+ emsg(_("E179: argument required for -addr"));
+ return FAIL;
+ }
+ if (parse_addr_type_arg(val, (int)vallen, argt, addr_type_arg)
+ == FAIL)
+ return FAIL;
+ if (addr_type_arg != ADDR_LINES)
+ *argt |= (ZEROR | NOTADR) ;
+ }
+ else
+ {
+ char_u ch = attr[len];
+ attr[len] = '\0';
+ semsg(_("E181: Invalid attribute: %s"), attr);
+ attr[len] = ch;
+ return FAIL;
+ }
+ }
+
+ return OK;
+}
+
+/*
+ * ":command ..."
+ */
+ static void
+ex_command(exarg_T *eap)
+{
+ char_u *name;
+ char_u *end;
+ char_u *p;
+ long argt = 0;
+ long def = -1;
+ int flags = 0;
+ int compl = EXPAND_NOTHING;
+ char_u *compl_arg = NULL;
+ int addr_type_arg = ADDR_LINES;
+ int has_attr = (eap->arg[0] == '-');
+ int name_len;
+
+ p = eap->arg;
+
+ /* Check for attributes */
+ while (*p == '-')
+ {
+ ++p;
+ end = skiptowhite(p);
+ if (uc_scan_attr(p, end - p, &argt, &def, &flags, &compl,
+ &compl_arg, &addr_type_arg)
+ == FAIL)
+ return;
+ p = skipwhite(end);
+ }
+
+ /* Get the name (if any) and skip to the following argument */
+ name = p;
+ if (ASCII_ISALPHA(*p))
+ while (ASCII_ISALNUM(*p))
+ ++p;
+ if (!ends_excmd(*p) && !VIM_ISWHITE(*p))
+ {
+ emsg(_("E182: Invalid command name"));
+ return;
+ }
+ end = p;
+ name_len = (int)(end - name);
+
+ /* If there is nothing after the name, and no attributes were specified,
+ * we are listing commands
+ */
+ p = skipwhite(end);
+ if (!has_attr && ends_excmd(*p))
+ {
+ uc_list(name, end - name);
+ }
+ else if (!ASCII_ISUPPER(*name))
+ {
+ emsg(_("E183: User defined commands must start with an uppercase letter"));
+ return;
+ }
+ else if ((name_len == 1 && *name == 'X')
+ || (name_len <= 4
+ && STRNCMP(name, "Next", name_len > 4 ? 4 : name_len) == 0))
+ {
+ emsg(_("E841: Reserved name, cannot be used for user defined command"));
+ return;
+ }
+ else
+ uc_add_command(name, end - name, p, argt, def, flags, compl, compl_arg,
+ addr_type_arg, eap->forceit);
+}
+
+/*
+ * ":comclear"
+ * Clear all user commands, global and for current buffer.
+ */
+ void
+ex_comclear(exarg_T *eap UNUSED)
+{
+ uc_clear(&ucmds);
+ uc_clear(&curbuf->b_ucmds);
+}
+
+/*
+ * Clear all user commands for "gap".
+ */
+ void
+uc_clear(garray_T *gap)
+{
+ int i;
+ ucmd_T *cmd;
+
+ for (i = 0; i < gap->ga_len; ++i)
+ {
+ cmd = USER_CMD_GA(gap, i);
+ vim_free(cmd->uc_name);
+ vim_free(cmd->uc_rep);
+# if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL)
+ vim_free(cmd->uc_compl_arg);
+# endif
+ }
+ ga_clear(gap);
+}
+
+ static void
+ex_delcommand(exarg_T *eap)
+{
+ int i = 0;
+ ucmd_T *cmd = NULL;
+ int cmp = -1;
+ garray_T *gap;
+
+ gap = &curbuf->b_ucmds;
+ for (;;)
+ {
+ for (i = 0; i < gap->ga_len; ++i)
+ {
+ cmd = USER_CMD_GA(gap, i);
+ cmp = STRCMP(eap->arg, cmd->uc_name);
+ if (cmp <= 0)
+ break;
+ }
+ if (gap == &ucmds || cmp == 0)
+ break;
+ gap = &ucmds;
+ }
+
+ if (cmp != 0)
+ {
+ semsg(_("E184: No such user-defined command: %s"), eap->arg);
+ return;
+ }
+
+ vim_free(cmd->uc_name);
+ vim_free(cmd->uc_rep);
+# if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL)
+ vim_free(cmd->uc_compl_arg);
+# endif
+
+ --gap->ga_len;
+
+ if (i < gap->ga_len)
+ mch_memmove(cmd, cmd + 1, (gap->ga_len - i) * sizeof(ucmd_T));
+}
+
+/*
+ * split and quote args for <f-args>
+ */
+ static char_u *
+uc_split_args(char_u *arg, size_t *lenp)
+{
+ char_u *buf;
+ char_u *p;
+ char_u *q;
+ int len;
+
+ /* Precalculate length */
+ p = arg;
+ len = 2; /* Initial and final quotes */
+
+ while (*p)
+ {
+ if (p[0] == '\\' && p[1] == '\\')
+ {
+ len += 2;
+ p += 2;
+ }
+ else if (p[0] == '\\' && VIM_ISWHITE(p[1]))
+ {
+ len += 1;
+ p += 2;
+ }
+ else if (*p == '\\' || *p == '"')
+ {
+ len += 2;
+ p += 1;
+ }
+ else if (VIM_ISWHITE(*p))
+ {
+ p = skipwhite(p);
+ if (*p == NUL)
+ break;
+ len += 3; /* "," */
+ }
+ else
+ {
+ int charlen = (*mb_ptr2len)(p);
+
+ len += charlen;
+ p += charlen;
+ }
+ }
+
+ buf = alloc(len + 1);
+ if (buf == NULL)
+ {
+ *lenp = 0;
+ return buf;
+ }
+
+ p = arg;
+ q = buf;
+ *q++ = '"';
+ while (*p)
+ {
+ if (p[0] == '\\' && p[1] == '\\')
+ {
+ *q++ = '\\';
+ *q++ = '\\';
+ p += 2;
+ }
+ else if (p[0] == '\\' && VIM_ISWHITE(p[1]))
+ {
+ *q++ = p[1];
+ p += 2;
+ }
+ else if (*p == '\\' || *p == '"')
+ {
+ *q++ = '\\';
+ *q++ = *p++;
+ }
+ else if (VIM_ISWHITE(*p))
+ {
+ p = skipwhite(p);
+ if (*p == NUL)
+ break;
+ *q++ = '"';
+ *q++ = ',';
+ *q++ = '"';
+ }
+ else
+ {
+ MB_COPY_CHAR(p, q);
+ }
+ }
+ *q++ = '"';
+ *q = 0;
+
+ *lenp = len;
+ return buf;
+}
+
+ static size_t
+add_cmd_modifier(char_u *buf, char *mod_str, int *multi_mods)
+{
+ size_t result;
+
+ result = STRLEN(mod_str);
+ if (*multi_mods)
+ result += 1;
+ if (buf != NULL)
+ {
+ if (*multi_mods)
+ STRCAT(buf, " ");
+ STRCAT(buf, mod_str);
+ }
+
+ *multi_mods = 1;
+
+ return result;
+}
+
+/*
+ * Check for a <> code in a user command.
+ * "code" points to the '<'. "len" the length of the <> (inclusive).
+ * "buf" is where the result is to be added.
+ * "split_buf" points to a buffer used for splitting, caller should free it.
+ * "split_len" is the length of what "split_buf" contains.
+ * Returns the length of the replacement, which has been added to "buf".
+ * Returns -1 if there was no match, and only the "<" has been copied.
+ */
+ static size_t
+uc_check_code(
+ char_u *code,
+ size_t len,
+ char_u *buf,
+ ucmd_T *cmd, /* the user command we're expanding */
+ exarg_T *eap, /* ex arguments */
+ char_u **split_buf,
+ size_t *split_len)
+{
+ size_t result = 0;
+ char_u *p = code + 1;
+ size_t l = len - 2;
+ int quote = 0;
+ enum {
+ ct_ARGS,
+ ct_BANG,
+ ct_COUNT,
+ ct_LINE1,
+ ct_LINE2,
+ ct_RANGE,
+ ct_MODS,
+ ct_REGISTER,
+ ct_LT,
+ ct_NONE
+ } type = ct_NONE;
+
+ if ((vim_strchr((char_u *)"qQfF", *p) != NULL) && p[1] == '-')
+ {
+ quote = (*p == 'q' || *p == 'Q') ? 1 : 2;
+ p += 2;
+ l -= 2;
+ }
+
+ ++l;
+ if (l <= 1)
+ type = ct_NONE;
+ else if (STRNICMP(p, "args>", l) == 0)
+ type = ct_ARGS;
+ else if (STRNICMP(p, "bang>", l) == 0)
+ type = ct_BANG;
+ else if (STRNICMP(p, "count>", l) == 0)
+ type = ct_COUNT;
+ else if (STRNICMP(p, "line1>", l) == 0)
+ type = ct_LINE1;
+ else if (STRNICMP(p, "line2>", l) == 0)
+ type = ct_LINE2;
+ else if (STRNICMP(p, "range>", l) == 0)
+ type = ct_RANGE;
+ else if (STRNICMP(p, "lt>", l) == 0)
+ type = ct_LT;
+ else if (STRNICMP(p, "reg>", l) == 0 || STRNICMP(p, "register>", l) == 0)
+ type = ct_REGISTER;
+ else if (STRNICMP(p, "mods>", l) == 0)
+ type = ct_MODS;
+
+ switch (type)
+ {
+ case ct_ARGS:
+ /* Simple case first */
+ if (*eap->arg == NUL)
+ {
+ if (quote == 1)
+ {
+ result = 2;
+ if (buf != NULL)
+ STRCPY(buf, "''");
+ }
+ else
+ result = 0;
+ break;
+ }
+
+ /* When specified there is a single argument don't split it.
+ * Works for ":Cmd %" when % is "a b c". */
+ if ((eap->argt & NOSPC) && quote == 2)
+ quote = 1;
+
+ switch (quote)
+ {
+ case 0: /* No quoting, no splitting */
+ result = STRLEN(eap->arg);
+ if (buf != NULL)
+ STRCPY(buf, eap->arg);
+ break;
+ case 1: /* Quote, but don't split */
+ result = STRLEN(eap->arg) + 2;
+ for (p = eap->arg; *p; ++p)
+ {
+ if (enc_dbcs != 0 && (*mb_ptr2len)(p) == 2)
+ /* DBCS can contain \ in a trail byte, skip the
+ * double-byte character. */
+ ++p;
+ else
+ if (*p == '\\' || *p == '"')
+ ++result;
+ }
+
+ if (buf != NULL)
+ {
+ *buf++ = '"';
+ for (p = eap->arg; *p; ++p)
+ {
+ if (enc_dbcs != 0 && (*mb_ptr2len)(p) == 2)
+ /* DBCS can contain \ in a trail byte, copy the
+ * double-byte character to avoid escaping. */
+ *buf++ = *p++;
+ else
+ if (*p == '\\' || *p == '"')
+ *buf++ = '\\';
+ *buf++ = *p;
+ }
+ *buf = '"';
+ }
+
+ break;
+ case 2: /* Quote and split (<f-args>) */
+ /* This is hard, so only do it once, and cache the result */
+ if (*split_buf == NULL)
+ *split_buf = uc_split_args(eap->arg, split_len);
+
+ result = *split_len;
+ if (buf != NULL && result != 0)
+ STRCPY(buf, *split_buf);
+
+ break;
+ }
+ break;
+
+ case ct_BANG:
+ result = eap->forceit ? 1 : 0;
+ if (quote)
+ result += 2;
+ if (buf != NULL)
+ {
+ if (quote)
+ *buf++ = '"';
+ if (eap->forceit)
+ *buf++ = '!';
+ if (quote)
+ *buf = '"';
+ }
+ break;
+
+ case ct_LINE1:
+ case ct_LINE2:
+ case ct_RANGE:
+ case ct_COUNT:
+ {
+ char num_buf[20];
+ long num = (type == ct_LINE1) ? eap->line1 :
+ (type == ct_LINE2) ? eap->line2 :
+ (type == ct_RANGE) ? eap->addr_count :
+ (eap->addr_count > 0) ? eap->line2 : cmd->uc_def;
+ size_t num_len;
+
+ sprintf(num_buf, "%ld", num);
+ num_len = STRLEN(num_buf);
+ result = num_len;
+
+ if (quote)
+ result += 2;
+
+ if (buf != NULL)
+ {
+ if (quote)
+ *buf++ = '"';
+ STRCPY(buf, num_buf);
+ buf += num_len;
+ if (quote)
+ *buf = '"';
+ }
+
+ break;
+ }
+
+ case ct_MODS:
+ {
+ int multi_mods = 0;
+ typedef struct {
+ int *varp;
+ char *name;
+ } mod_entry_T;
+ static mod_entry_T mod_entries[] = {
+#ifdef FEAT_BROWSE_CMD
+ {&cmdmod.browse, "browse"},
+#endif
+#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
+ {&cmdmod.confirm, "confirm"},
+#endif
+ {&cmdmod.hide, "hide"},
+ {&cmdmod.keepalt, "keepalt"},
+ {&cmdmod.keepjumps, "keepjumps"},
+ {&cmdmod.keepmarks, "keepmarks"},
+ {&cmdmod.keeppatterns, "keeppatterns"},
+ {&cmdmod.lockmarks, "lockmarks"},
+ {&cmdmod.noswapfile, "noswapfile"},
+ {NULL, NULL}
+ };
+ int i;
+
+ result = quote ? 2 : 0;
+ if (buf != NULL)
+ {
+ if (quote)
+ *buf++ = '"';
+ *buf = '\0';
+ }
+
+ /* :aboveleft and :leftabove */
+ if (cmdmod.split & WSP_ABOVE)
+ result += add_cmd_modifier(buf, "aboveleft", &multi_mods);
+ /* :belowright and :rightbelow */
+ if (cmdmod.split & WSP_BELOW)
+ result += add_cmd_modifier(buf, "belowright", &multi_mods);
+ /* :botright */
+ if (cmdmod.split & WSP_BOT)
+ result += add_cmd_modifier(buf, "botright", &multi_mods);
+
+ /* the modifiers that are simple flags */
+ for (i = 0; mod_entries[i].varp != NULL; ++i)
+ if (*mod_entries[i].varp)
+ result += add_cmd_modifier(buf, mod_entries[i].name,
+ &multi_mods);
+
+ /* TODO: How to support :noautocmd? */
+#ifdef HAVE_SANDBOX
+ /* TODO: How to support :sandbox?*/
+#endif
+ /* :silent */
+ if (msg_silent > 0)
+ result += add_cmd_modifier(buf,
+ emsg_silent > 0 ? "silent!" : "silent", &multi_mods);
+ /* :tab */
+ if (cmdmod.tab > 0)
+ result += add_cmd_modifier(buf, "tab", &multi_mods);
+ /* :topleft */
+ if (cmdmod.split & WSP_TOP)
+ result += add_cmd_modifier(buf, "topleft", &multi_mods);
+ /* TODO: How to support :unsilent?*/
+ /* :verbose */
+ if (p_verbose > 0)
+ result += add_cmd_modifier(buf, "verbose", &multi_mods);
+ /* :vertical */
+ if (cmdmod.split & WSP_VERT)
+ result += add_cmd_modifier(buf, "vertical", &multi_mods);
+ if (quote && buf != NULL)
+ {
+ buf += result - 2;
+ *buf = '"';
+ }
+ break;
+ }
+
+ case ct_REGISTER:
+ result = eap->regname ? 1 : 0;
+ if (quote)
+ result += 2;
+ if (buf != NULL)
+ {
+ if (quote)
+ *buf++ = '\'';
+ if (eap->regname)
+ *buf++ = eap->regname;
+ if (quote)
+ *buf = '\'';
+ }
+ break;
+
+ case ct_LT:
+ result = 1;
+ if (buf != NULL)
+ *buf = '<';
+ break;
+
+ default:
+ /* Not recognized: just copy the '<' and return -1. */
+ result = (size_t)-1;
+ if (buf != NULL)
+ *buf = '<';
+ break;
+ }
+
+ return result;
+}
+
+ static void
+do_ucmd(exarg_T *eap)
+{
+ char_u *buf;
+ char_u *p;
+ char_u *q;
+
+ char_u *start;
+ char_u *end = NULL;
+ char_u *ksp;
+ size_t len, totlen;
+
+ size_t split_len = 0;
+ char_u *split_buf = NULL;
+ ucmd_T *cmd;
+#ifdef FEAT_EVAL
+ sctx_T save_current_sctx = current_sctx;
+#endif
+
+ if (eap->cmdidx == CMD_USER)
+ cmd = USER_CMD(eap->useridx);
+ else
+ cmd = USER_CMD_GA(&curbuf->b_ucmds, eap->useridx);
+
+ /*
+ * Replace <> in the command by the arguments.
+ * First round: "buf" is NULL, compute length, allocate "buf".
+ * Second round: copy result into "buf".
+ */
+ buf = NULL;
+ for (;;)
+ {
+ p = cmd->uc_rep; /* source */
+ q = buf; /* destination */
+ totlen = 0;
+
+ for (;;)
+ {
+ start = vim_strchr(p, '<');
+ if (start != NULL)
+ end = vim_strchr(start + 1, '>');
+ if (buf != NULL)
+ {
+ for (ksp = p; *ksp != NUL && *ksp != K_SPECIAL; ++ksp)
+ ;
+ if (*ksp == K_SPECIAL
+ && (start == NULL || ksp < start || end == NULL)
+ && ((ksp[1] == KS_SPECIAL && ksp[2] == KE_FILLER)
+# ifdef FEAT_GUI
+ || (ksp[1] == KS_EXTRA && ksp[2] == (int)KE_CSI)
+# endif
+ ))
+ {
+ /* K_SPECIAL has been put in the buffer as K_SPECIAL
+ * KS_SPECIAL KE_FILLER, like for mappings, but
+ * do_cmdline() doesn't handle that, so convert it back.
+ * Also change K_SPECIAL KS_EXTRA KE_CSI into CSI. */
+ len = ksp - p;
+ if (len > 0)
+ {
+ mch_memmove(q, p, len);
+ q += len;
+ }
+ *q++ = ksp[1] == KS_SPECIAL ? K_SPECIAL : CSI;
+ p = ksp + 3;
+ continue;
+ }
+ }
+
+ /* break if no <item> is found */
+ if (start == NULL || end == NULL)
+ break;
+
+ /* Include the '>' */
+ ++end;
+
+ /* Take everything up to the '<' */
+ len = start - p;
+ if (buf == NULL)
+ totlen += len;
+ else
+ {
+ mch_memmove(q, p, len);
+ q += len;
+ }
+
+ len = uc_check_code(start, end - start, q, cmd, eap,
+ &split_buf, &split_len);
+ if (len == (size_t)-1)
+ {
+ /* no match, continue after '<' */
+ p = start + 1;
+ len = 1;
+ }
+ else
+ p = end;
+ if (buf == NULL)
+ totlen += len;
+ else
+ q += len;
+ }
+ if (buf != NULL) /* second time here, finished */
+ {
+ STRCPY(q, p);
+ break;
+ }
+
+ totlen += STRLEN(p); /* Add on the trailing characters */
+ buf = alloc((unsigned)(totlen + 1));
+ if (buf == NULL)
+ {
+ vim_free(split_buf);
+ return;
+ }
+ }
+
+#ifdef FEAT_EVAL
+ current_sctx.sc_sid = cmd->uc_script_ctx.sc_sid;
+#endif
+ (void)do_cmdline(buf, eap->getline, eap->cookie,
+ DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_KEYTYPED);
+#ifdef FEAT_EVAL
+ current_sctx = save_current_sctx;
+#endif
+ vim_free(buf);
+ vim_free(split_buf);
+}
+
+# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
+ static char_u *
+get_user_command_name(int idx)
+{
+ return get_user_commands(NULL, idx - (int)CMD_SIZE);
+}
+
+/*
+ * Function given to ExpandGeneric() to obtain the list of user command names.
+ */
+ char_u *
+get_user_commands(expand_T *xp UNUSED, int idx)
+{
+ if (idx < curbuf->b_ucmds.ga_len)
+ return USER_CMD_GA(&curbuf->b_ucmds, idx)->uc_name;
+ idx -= curbuf->b_ucmds.ga_len;
+ if (idx < ucmds.ga_len)
+ return USER_CMD(idx)->uc_name;
+ return NULL;
+}
+
+/*
+ * Function given to ExpandGeneric() to obtain the list of user address type names.
+ */
+ char_u *
+get_user_cmd_addr_type(expand_T *xp UNUSED, int idx)
+{
+ return (char_u *)addr_type_complete[idx].name;
+}
+
+/*
+ * Function given to ExpandGeneric() to obtain the list of user command
+ * attributes.
+ */
+ char_u *
+get_user_cmd_flags(expand_T *xp UNUSED, int idx)
+{
+ static char *user_cmd_flags[] =
+ {"addr", "bang", "bar", "buffer", "complete",
+ "count", "nargs", "range", "register"};
+
+ if (idx >= (int)(sizeof(user_cmd_flags) / sizeof(user_cmd_flags[0])))
+ return NULL;
+ return (char_u *)user_cmd_flags[idx];
+}
+
+/*
+ * Function given to ExpandGeneric() to obtain the list of values for -nargs.
+ */
+ char_u *
+get_user_cmd_nargs(expand_T *xp UNUSED, int idx)
+{
+ static char *user_cmd_nargs[] = {"0", "1", "*", "?", "+"};
+
+ if (idx >= (int)(sizeof(user_cmd_nargs) / sizeof(user_cmd_nargs[0])))
+ return NULL;
+ return (char_u *)user_cmd_nargs[idx];
+}
+
+/*
+ * Function given to ExpandGeneric() to obtain the list of values for -complete.
+ */
+ char_u *
+get_user_cmd_complete(expand_T *xp UNUSED, int idx)
+{
+ return (char_u *)command_complete[idx].name;
+}
+# endif /* FEAT_CMDL_COMPL */
+
+/*
+ * Parse address type argument
+ */
+ int
+parse_addr_type_arg(
+ char_u *value,
+ int vallen,
+ long *argt,
+ int *addr_type_arg)
+{
+ int i, a, b;
+
+ for (i = 0; addr_type_complete[i].expand != -1; ++i)
+ {
+ a = (int)STRLEN(addr_type_complete[i].name) == vallen;
+ b = STRNCMP(value, addr_type_complete[i].name, vallen) == 0;
+ if (a && b)
+ {
+ *addr_type_arg = addr_type_complete[i].expand;
+ break;
+ }
+ }
+
+ if (addr_type_complete[i].expand == -1)
+ {
+ char_u *err = value;
+
+ for (i = 0; err[i] != NUL && !VIM_ISWHITE(err[i]); i++)
+ ;
+ err[i] = NUL;
+ semsg(_("E180: Invalid address type value: %s"), err);
+ return FAIL;
+ }
+
+ if (*addr_type_arg != ADDR_LINES)
+ *argt |= NOTADR;
+
+ return OK;
+}
+
+#endif /* FEAT_USR_CMDS */
+
+#if defined(FEAT_USR_CMDS) || defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * Parse a completion argument "value[vallen]".
+ * The detected completion goes in "*complp", argument type in "*argt".
+ * When there is an argument, for function and user defined completion, it's
+ * copied to allocated memory and stored in "*compl_arg".
+ * Returns FAIL if something is wrong.
+ */
+ int
+parse_compl_arg(
+ char_u *value,
+ int vallen,
+ int *complp,
+ long *argt,
+ char_u **compl_arg UNUSED)
+{
+ char_u *arg = NULL;
+# if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL)
+ size_t arglen = 0;
+# endif
+ int i;
+ int valend = vallen;
+
+ /* Look for any argument part - which is the part after any ',' */
+ for (i = 0; i < vallen; ++i)
+ {
+ if (value[i] == ',')
+ {
+ arg = &value[i + 1];
+# if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL)
+ arglen = vallen - i - 1;
+# endif
+ valend = i;
+ break;
+ }
+ }
+
+ for (i = 0; command_complete[i].expand != 0; ++i)
+ {
+ if ((int)STRLEN(command_complete[i].name) == valend
+ && STRNCMP(value, command_complete[i].name, valend) == 0)
+ {
+ *complp = command_complete[i].expand;
+ if (command_complete[i].expand == EXPAND_BUFFERS)
+ *argt |= BUFNAME;
+ else if (command_complete[i].expand == EXPAND_DIRECTORIES
+ || command_complete[i].expand == EXPAND_FILES)
+ *argt |= XFILE;
+ break;
+ }
+ }
+
+ if (command_complete[i].expand == 0)
+ {
+ semsg(_("E180: Invalid complete value: %s"), value);
+ return FAIL;
+ }
+
+# if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL)
+ if (*complp != EXPAND_USER_DEFINED && *complp != EXPAND_USER_LIST
+ && arg != NULL)
+# else
+ if (arg != NULL)
+# endif
+ {
+ emsg(_("E468: Completion argument only allowed for custom completion"));
+ return FAIL;
+ }
+
+# if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL)
+ if ((*complp == EXPAND_USER_DEFINED || *complp == EXPAND_USER_LIST)
+ && arg == NULL)
+ {
+ emsg(_("E467: Custom completion requires a function argument"));
+ return FAIL;
+ }
+
+ if (arg != NULL)
+ *compl_arg = vim_strnsave(arg, (int)arglen);
+# endif
+ return OK;
+}
+
+ int
+cmdcomplete_str_to_type(char_u *complete_str)
+{
+ int i;
+
+ for (i = 0; command_complete[i].expand != 0; ++i)
+ if (STRCMP(complete_str, command_complete[i].name) == 0)
+ return command_complete[i].expand;
+
+ return EXPAND_NOTHING;
+}
+#endif
+
+ static void
+ex_colorscheme(exarg_T *eap)
+{
+ if (*eap->arg == NUL)
+ {
+#ifdef FEAT_EVAL
+ char_u *expr = vim_strsave((char_u *)"g:colors_name");
+ char_u *p = NULL;
+
+ if (expr != NULL)
+ {
+ ++emsg_off;
+ p = eval_to_string(expr, NULL, FALSE);
+ --emsg_off;
+ vim_free(expr);
+ }
+ if (p != NULL)
+ {
+ msg((char *)p);
+ vim_free(p);
+ }
+ else
+ msg("default");
+#else
+ msg(_("unknown"));
+#endif
+ }
+ else if (load_colors(eap->arg) == FAIL)
+ semsg(_("E185: Cannot find color scheme '%s'"), eap->arg);
+
+#ifdef FEAT_VTP
+ else if (has_vtp_working())
+ {
+ // background color change requires clear + redraw
+ update_screen(CLEAR);
+ redrawcmd();
+ }
+#endif
+}
+
+ static void
+ex_highlight(exarg_T *eap)
+{
+ if (*eap->arg == NUL && eap->cmd[2] == '!')
+ msg(_("Greetings, Vim user!"));
+ do_highlight(eap->arg, eap->forceit, FALSE);
+}
+
+
+/*
+ * Call this function if we thought we were going to exit, but we won't
+ * (because of an error). May need to restore the terminal mode.
+ */
+ void
+not_exiting(void)
+{
+ exiting = FALSE;
+ settmode(TMODE_RAW);
+}
+
+ static int
+before_quit_autocmds(win_T *wp, int quit_all, int forceit)
+{
+ apply_autocmds(EVENT_QUITPRE, NULL, NULL, FALSE, wp->w_buffer);
+
+ /* Bail out when autocommands closed the window.
+ * Refuse to quit when the buffer in the last window is being closed (can
+ * only happen in autocommands). */
+ if (!win_valid(wp)
+ || curbuf_locked()
+ || (wp->w_buffer->b_nwindows == 1 && wp->w_buffer->b_locked > 0))
+ return TRUE;
+
+ if (quit_all || (check_more(FALSE, forceit) == OK && only_one_window()))
+ {
+ apply_autocmds(EVENT_EXITPRE, NULL, NULL, FALSE, curbuf);
+ /* Refuse to quit when locked or when the buffer in the last window is
+ * being closed (can only happen in autocommands). */
+ if (curbuf_locked()
+ || (curbuf->b_nwindows == 1 && curbuf->b_locked > 0))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/*
+ * ":quit": quit current window, quit Vim if the last window is closed.
+ * ":{nr}quit": quit window {nr}
+ */
+ static void
+ex_quit(exarg_T *eap)
+{
+ win_T *wp;
+
+#ifdef FEAT_CMDWIN
+ if (cmdwin_type != 0)
+ {
+ cmdwin_result = Ctrl_C;
+ return;
+ }
+#endif
+ /* Don't quit while editing the command line. */
+ if (text_locked())
+ {
+ text_locked_msg();
+ return;
+ }
+ if (eap->addr_count > 0)
+ {
+ int wnr = eap->line2;
+
+ for (wp = firstwin; wp->w_next != NULL; wp = wp->w_next)
+ if (--wnr <= 0)
+ break;
+ }
+ else
+ wp = curwin;
+
+ /* Refuse to quit when locked. */
+ if (curbuf_locked())
+ return;
+
+ /* Trigger QuitPre and maybe ExitPre */
+ if (before_quit_autocmds(wp, FALSE, eap->forceit))
+ return;
+
+#ifdef FEAT_NETBEANS_INTG
+ netbeansForcedQuit = eap->forceit;
+#endif
+
+ /*
+ * If there are more files or windows we won't exit.
+ */
+ if (check_more(FALSE, eap->forceit) == OK && only_one_window())
+ exiting = TRUE;
+ if ((!buf_hide(wp->w_buffer)
+ && check_changed(wp->w_buffer, (p_awa ? CCGD_AW : 0)
+ | (eap->forceit ? CCGD_FORCEIT : 0)
+ | CCGD_EXCMD))
+ || check_more(TRUE, eap->forceit) == FAIL
+ || (only_one_window() && check_changed_any(eap->forceit, TRUE)))
+ {
+ not_exiting();
+ }
+ else
+ {
+ /* quit last window
+ * Note: only_one_window() returns true, even so a help window is
+ * still open. In that case only quit, if no address has been
+ * specified. Example:
+ * :h|wincmd w|1q - don't quit
+ * :h|wincmd w|q - quit
+ */
+ if (only_one_window() && (ONE_WINDOW || eap->addr_count == 0))
+ getout(0);
+ not_exiting();
+#ifdef FEAT_GUI
+ need_mouse_correct = TRUE;
+#endif
+ /* close window; may free buffer */
+ win_close(wp, !buf_hide(wp->w_buffer) || eap->forceit);
+ }
+}
+
+/*
+ * ":cquit".
+ */
+ static void
+ex_cquit(exarg_T *eap UNUSED)
+{
+ getout(1); /* this does not always pass on the exit code to the Manx
+ compiler. why? */
+}
+
+/*
+ * ":qall": try to quit all windows
+ */
+ static void
+ex_quit_all(exarg_T *eap)
+{
+# ifdef FEAT_CMDWIN
+ if (cmdwin_type != 0)
+ {
+ if (eap->forceit)
+ cmdwin_result = K_XF1; /* ex_window() takes care of this */
+ else
+ cmdwin_result = K_XF2;
+ return;
+ }
+# endif
+
+ /* Don't quit while editing the command line. */
+ if (text_locked())
+ {
+ text_locked_msg();
+ return;
+ }
+
+ if (before_quit_autocmds(curwin, TRUE, eap->forceit))
+ return;
+
+ exiting = TRUE;
+ if (eap->forceit || !check_changed_any(FALSE, FALSE))
+ getout(0);
+ not_exiting();
+}
+
+/*
+ * ":close": close current window, unless it is the last one
+ */
+ static void
+ex_close(exarg_T *eap)
+{
+ win_T *win;
+ int winnr = 0;
+#ifdef FEAT_CMDWIN
+ if (cmdwin_type != 0)
+ cmdwin_result = Ctrl_C;
+ else
+#endif
+ if (!text_locked() && !curbuf_locked())
+ {
+ if (eap->addr_count == 0)
+ ex_win_close(eap->forceit, curwin, NULL);
+ else
+ {
+ FOR_ALL_WINDOWS(win)
+ {
+ winnr++;
+ if (winnr == eap->line2)
+ break;
+ }
+ if (win == NULL)
+ win = lastwin;
+ ex_win_close(eap->forceit, win, NULL);
+ }
+ }
+}
+
+#ifdef FEAT_QUICKFIX
+/*
+ * ":pclose": Close any preview window.
+ */
+ static void
+ex_pclose(exarg_T *eap)
+{
+ win_T *win;
+
+ FOR_ALL_WINDOWS(win)
+ if (win->w_p_pvw)
+ {
+ ex_win_close(eap->forceit, win, NULL);
+ break;
+ }
+}
+#endif
+
+/*
+ * Close window "win" and take care of handling closing the last window for a
+ * modified buffer.
+ */
+ static void
+ex_win_close(
+ int forceit,
+ win_T *win,
+ tabpage_T *tp) /* NULL or the tab page "win" is in */
+{
+ int need_hide;
+ buf_T *buf = win->w_buffer;
+
+ need_hide = (bufIsChanged(buf) && buf->b_nwindows <= 1);
+ if (need_hide && !buf_hide(buf) && !forceit)
+ {
+#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
+ if ((p_confirm || cmdmod.confirm) && p_write)
+ {
+ bufref_T bufref;
+
+ set_bufref(&bufref, buf);
+ dialog_changed(buf, FALSE);
+ if (bufref_valid(&bufref) && bufIsChanged(buf))
+ return;
+ need_hide = FALSE;
+ }
+ else
+#endif
+ {
+ no_write_message();
+ return;
+ }
+ }
+
+#ifdef FEAT_GUI
+ need_mouse_correct = TRUE;
+#endif
+
+ /* free buffer when not hiding it or when it's a scratch buffer */
+ if (tp == NULL)
+ win_close(win, !need_hide && !buf_hide(buf));
+ else
+ win_close_othertab(win, !need_hide && !buf_hide(buf), tp);
+}
+
+/*
+ * Handle the argument for a tabpage related ex command.
+ * Returns a tabpage number.
+ * When an error is encountered then eap->errmsg is set.
+ */
+ static int
+get_tabpage_arg(exarg_T *eap)
+{
+ int tab_number;
+ int unaccept_arg0 = (eap->cmdidx == CMD_tabmove) ? 0 : 1;
+
+ if (eap->arg && *eap->arg != NUL)
+ {
+ char_u *p = eap->arg;
+ char_u *p_save;
+ int relative = 0; /* argument +N/-N means: go to N places to the
+ * right/left relative to the current position. */
+
+ if (*p == '-')
+ {
+ relative = -1;
+ p++;
+ }
+ else if (*p == '+')
+ {
+ relative = 1;
+ p++;
+ }
+
+ p_save = p;
+ tab_number = getdigits(&p);
+
+ if (relative == 0)
+ {
+ if (STRCMP(p, "$") == 0)
+ tab_number = LAST_TAB_NR;
+ else if (p == p_save || *p_save == '-' || *p != NUL
+ || tab_number > LAST_TAB_NR)
+ {
+ /* No numbers as argument. */
+ eap->errmsg = e_invarg;
+ goto theend;
+ }
+ }
+ else
+ {
+ if (*p_save == NUL)
+ tab_number = 1;
+ else if (p == p_save || *p_save == '-' || *p != NUL
+ || tab_number == 0)
+ {
+ /* No numbers as argument. */
+ eap->errmsg = e_invarg;
+ goto theend;
+ }
+ tab_number = tab_number * relative + tabpage_index(curtab);
+ if (!unaccept_arg0 && relative == -1)
+ --tab_number;
+ }
+ if (tab_number < unaccept_arg0 || tab_number > LAST_TAB_NR)
+ eap->errmsg = e_invarg;
+ }
+ else if (eap->addr_count > 0)
+ {
+ if (unaccept_arg0 && eap->line2 == 0)
+ {
+ eap->errmsg = e_invrange;
+ tab_number = 0;
+ }
+ else
+ {
+ tab_number = eap->line2;
+ if (!unaccept_arg0 && *skipwhite(*eap->cmdlinep) == '-')
+ {
+ --tab_number;
+ if (tab_number < unaccept_arg0)
+ eap->errmsg = e_invarg;
+ }
+ }
+ }
+ else
+ {
+ switch (eap->cmdidx)
+ {
+ case CMD_tabnext:
+ tab_number = tabpage_index(curtab) + 1;
+ if (tab_number > LAST_TAB_NR)
+ tab_number = 1;
+ break;
+ case CMD_tabmove:
+ tab_number = LAST_TAB_NR;
+ break;
+ default:
+ tab_number = tabpage_index(curtab);
+ }
+ }
+
+theend:
+ return tab_number;
+}
+
+/*
+ * ":tabclose": close current tab page, unless it is the last one.
+ * ":tabclose N": close tab page N.
+ */
+ static void
+ex_tabclose(exarg_T *eap)
+{
+ tabpage_T *tp;
+ int tab_number;
+
+# ifdef FEAT_CMDWIN
+ if (cmdwin_type != 0)
+ cmdwin_result = K_IGNORE;
+ else
+# endif
+ if (first_tabpage->tp_next == NULL)
+ emsg(_("E784: Cannot close last tab page"));
+ else
+ {
+ tab_number = get_tabpage_arg(eap);
+ if (eap->errmsg == NULL)
+ {
+ tp = find_tabpage(tab_number);
+ if (tp == NULL)
+ {
+ beep_flush();
+ return;
+ }
+ if (tp != curtab)
+ {
+ tabpage_close_other(tp, eap->forceit);
+ return;
+ }
+ else if (!text_locked() && !curbuf_locked())
+ tabpage_close(eap->forceit);
+ }
+ }
+}
+
+/*
+ * ":tabonly": close all tab pages except the current one
+ */
+ static void
+ex_tabonly(exarg_T *eap)
+{
+ tabpage_T *tp;
+ int done;
+ int tab_number;
+
+# ifdef FEAT_CMDWIN
+ if (cmdwin_type != 0)
+ cmdwin_result = K_IGNORE;
+ else
+# endif
+ if (first_tabpage->tp_next == NULL)
+ msg(_("Already only one tab page"));
+ else
+ {
+ tab_number = get_tabpage_arg(eap);
+ if (eap->errmsg == NULL)
+ {
+ goto_tabpage(tab_number);
+ /* Repeat this up to a 1000 times, because autocommands may
+ * mess up the lists. */
+ for (done = 0; done < 1000; ++done)
+ {
+ FOR_ALL_TABPAGES(tp)
+ if (tp->tp_topframe != topframe)
+ {
+ tabpage_close_other(tp, eap->forceit);
+ /* if we failed to close it quit */
+ if (valid_tabpage(tp))
+ done = 1000;
+ /* start over, "tp" is now invalid */
+ break;
+ }
+ if (first_tabpage->tp_next == NULL)
+ break;
+ }
+ }
+ }
+}
+
+/*
+ * Close the current tab page.
+ */
+ void
+tabpage_close(int forceit)
+{
+ /* First close all the windows but the current one. If that worked then
+ * close the last window in this tab, that will close it. */
+ if (!ONE_WINDOW)
+ close_others(TRUE, forceit);
+ if (ONE_WINDOW)
+ ex_win_close(forceit, curwin, NULL);
+# ifdef FEAT_GUI
+ need_mouse_correct = TRUE;
+# endif
+}
+
+/*
+ * Close tab page "tp", which is not the current tab page.
+ * Note that autocommands may make "tp" invalid.
+ * Also takes care of the tab pages line disappearing when closing the
+ * last-but-one tab page.
+ */
+ void
+tabpage_close_other(tabpage_T *tp, int forceit)
+{
+ int done = 0;
+ win_T *wp;
+ int h = tabline_height();
+
+ /* Limit to 1000 windows, autocommands may add a window while we close
+ * one. OK, so I'm paranoid... */
+ while (++done < 1000)
+ {
+ wp = tp->tp_firstwin;
+ ex_win_close(forceit, wp, tp);
+
+ /* Autocommands may delete the tab page under our fingers and we may
+ * fail to close a window with a modified buffer. */
+ if (!valid_tabpage(tp) || tp->tp_firstwin == wp)
+ break;
+ }
+
+ apply_autocmds(EVENT_TABCLOSED, NULL, NULL, FALSE, curbuf);
+
+ redraw_tabline = TRUE;
+ if (h != tabline_height())
+ shell_new_rows();
+}
+
+/*
+ * ":only".
+ */
+ static void
+ex_only(exarg_T *eap)
+{
+ win_T *wp;
+ int wnr;
+# ifdef FEAT_GUI
+ need_mouse_correct = TRUE;
+# endif
+ if (eap->addr_count > 0)
+ {
+ wnr = eap->line2;
+ for (wp = firstwin; --wnr > 0; )
+ {
+ if (wp->w_next == NULL)
+ break;
+ else
+ wp = wp->w_next;
+ }
+ win_goto(wp);
+ }
+ close_others(TRUE, eap->forceit);
+}
+
+/*
+ * ":all" and ":sall".
+ * Also used for ":tab drop file ..." after setting the argument list.
+ */
+ void
+ex_all(exarg_T *eap)
+{
+ if (eap->addr_count == 0)
+ eap->line2 = 9999;
+ do_arg_all((int)eap->line2, eap->forceit, eap->cmdidx == CMD_drop);
+}
+
+ static void
+ex_hide(exarg_T *eap UNUSED)
+{
+ /* ":hide" or ":hide | cmd": hide current window */
+ if (!eap->skip)
+ {
+#ifdef FEAT_GUI
+ need_mouse_correct = TRUE;
+#endif
+ if (eap->addr_count == 0)
+ win_close(curwin, FALSE); /* don't free buffer */
+ else
+ {
+ int winnr = 0;
+ win_T *win;
+
+ FOR_ALL_WINDOWS(win)
+ {
+ winnr++;
+ if (winnr == eap->line2)
+ break;
+ }
+ if (win == NULL)
+ win = lastwin;
+ win_close(win, FALSE);
+ }
+ }
+}
+
+/*
+ * ":stop" and ":suspend": Suspend Vim.
+ */
+ static void
+ex_stop(exarg_T *eap)
+{
+ /*
+ * Disallow suspending for "rvim".
+ */
+ if (!check_restricted())
+ {
+ if (!eap->forceit)
+ autowrite_all();
+ windgoto((int)Rows - 1, 0);
+ out_char('\n');
+ out_flush();
+ stoptermcap();
+ out_flush(); /* needed for SUN to restore xterm buffer */
+#ifdef FEAT_TITLE
+ mch_restore_title(SAVE_RESTORE_BOTH); /* restore window titles */
+#endif
+ ui_suspend(); /* call machine specific function */
+#ifdef FEAT_TITLE
+ maketitle();
+ resettitle(); /* force updating the title */
+#endif
+ starttermcap();
+ scroll_start(); /* scroll screen before redrawing */
+ redraw_later_clear();
+ shell_resized(); /* may have resized window */
+ }
+}
+
+/*
+ * ":exit", ":xit" and ":wq": Write file and quite the current window.
+ */
+ static void
+ex_exit(exarg_T *eap)
+{
+#ifdef FEAT_CMDWIN
+ if (cmdwin_type != 0)
+ {
+ cmdwin_result = Ctrl_C;
+ return;
+ }
+#endif
+ /* Don't quit while editing the command line. */
+ if (text_locked())
+ {
+ text_locked_msg();
+ return;
+ }
+
+ if (before_quit_autocmds(curwin, FALSE, eap->forceit))
+ return;
+
+ /*
+ * if more files or windows we won't exit
+ */
+ if (check_more(FALSE, eap->forceit) == OK && only_one_window())
+ exiting = TRUE;
+ if ( ((eap->cmdidx == CMD_wq
+ || curbufIsChanged())
+ && do_write(eap) == FAIL)
+ || check_more(TRUE, eap->forceit) == FAIL
+ || (only_one_window() && check_changed_any(eap->forceit, FALSE)))
+ {
+ not_exiting();
+ }
+ else
+ {
+ if (only_one_window()) /* quit last window, exit Vim */
+ getout(0);
+ not_exiting();
+# ifdef FEAT_GUI
+ need_mouse_correct = TRUE;
+# endif
+ /* Quit current window, may free the buffer. */
+ win_close(curwin, !buf_hide(curwin->w_buffer));
+ }
+}
+
+/*
+ * ":print", ":list", ":number".
+ */
+ static void
+ex_print(exarg_T *eap)
+{
+ if (curbuf->b_ml.ml_flags & ML_EMPTY)
+ emsg(_(e_emptybuf));
+ else
+ {
+ for ( ;!got_int; ui_breakcheck())
+ {
+ print_line(eap->line1,
+ (eap->cmdidx == CMD_number || eap->cmdidx == CMD_pound
+ || (eap->flags & EXFLAG_NR)),
+ eap->cmdidx == CMD_list || (eap->flags & EXFLAG_LIST));
+ if (++eap->line1 > eap->line2)
+ break;
+ out_flush(); /* show one line at a time */
+ }
+ setpcmark();
+ /* put cursor at last line */
+ curwin->w_cursor.lnum = eap->line2;
+ beginline(BL_SOL | BL_FIX);
+ }
+
+ ex_no_reprint = TRUE;
+}
+
+#ifdef FEAT_BYTEOFF
+ static void
+ex_goto(exarg_T *eap)
+{
+ goto_byte(eap->line2);
+}
+#endif
+
+/*
+ * ":shell".
+ */
+ static void
+ex_shell(exarg_T *eap UNUSED)
+{
+ do_shell(NULL, 0);
+}
+
+#if defined(HAVE_DROP_FILE) || defined(PROTO)
+
+static int drop_busy = FALSE;
+static int drop_filec;
+static char_u **drop_filev = NULL;
+static int drop_split;
+static void (*drop_callback)(void *);
+static void *drop_cookie;
+
+ static void
+handle_drop_internal(void)
+{
+ exarg_T ea;
+ int save_msg_scroll = msg_scroll;
+
+ // Setting the argument list may cause screen updates and being called
+ // recursively. Avoid that by setting drop_busy.
+ drop_busy = TRUE;
+
+ /* Check whether the current buffer is changed. If so, we will need
+ * to split the current window or data could be lost.
+ * We don't need to check if the 'hidden' option is set, as in this
+ * case the buffer won't be lost.
+ */
+ if (!buf_hide(curbuf) && !drop_split)
+ {
+ ++emsg_off;
+ drop_split = check_changed(curbuf, CCGD_AW);
+ --emsg_off;
+ }
+ if (drop_split)
+ {
+ if (win_split(0, 0) == FAIL)
+ return;
+ RESET_BINDING(curwin);
+
+ /* When splitting the window, create a new alist. Otherwise the
+ * existing one is overwritten. */
+ alist_unlink(curwin->w_alist);
+ alist_new();
+ }
+
+ /*
+ * Set up the new argument list.
+ */
+ alist_set(ALIST(curwin), drop_filec, drop_filev, FALSE, NULL, 0);
+
+ /*
+ * Move to the first file.
+ */
+ /* Fake up a minimal "next" command for do_argfile() */
+ vim_memset(&ea, 0, sizeof(ea));
+ ea.cmd = (char_u *)"next";
+ do_argfile(&ea, 0);
+
+ /* do_ecmd() may set need_start_insertmode, but since we never left Insert
+ * mode that is not needed here. */
+ need_start_insertmode = FALSE;
+
+ /* Restore msg_scroll, otherwise a following command may cause scrolling
+ * unexpectedly. The screen will be redrawn by the caller, thus
+ * msg_scroll being set by displaying a message is irrelevant. */
+ msg_scroll = save_msg_scroll;
+
+ if (drop_callback != NULL)
+ drop_callback(drop_cookie);
+
+ drop_filev = NULL;
+ drop_busy = FALSE;
+}
+
+/*
+ * Handle a file drop. The code is here because a drop is *nearly* like an
+ * :args command, but not quite (we have a list of exact filenames, so we
+ * don't want to (a) parse a command line, or (b) expand wildcards). So the
+ * code is very similar to :args and hence needs access to a lot of the static
+ * functions in this file.
+ *
+ * The "filev" list must have been allocated using alloc(), as should each item
+ * in the list. This function takes over responsibility for freeing the "filev"
+ * list.
+ */
+ void
+handle_drop(
+ int filec, // the number of files dropped
+ char_u **filev, // the list of files dropped
+ int split, // force splitting the window
+ void (*callback)(void *), // to be called after setting the argument
+ // list
+ void *cookie) // argument for "callback" (allocated)
+{
+ // Cannot handle recursive drops, finish the pending one.
+ if (drop_busy)
+ {
+ FreeWild(filec, filev);
+ vim_free(cookie);
+ return;
+ }
+
+ // When calling handle_drop() more than once in a row we only use the last
+ // one.
+ if (drop_filev != NULL)
+ {
+ FreeWild(drop_filec, drop_filev);
+ vim_free(drop_cookie);
+ }
+
+ drop_filec = filec;
+ drop_filev = filev;
+ drop_split = split;
+ drop_callback = callback;
+ drop_cookie = cookie;
+
+ // Postpone this when:
+ // - editing the command line
+ // - not possible to change the current buffer
+ // - updating the screen
+ // As it may change buffers and window structures that are in use and cause
+ // freed memory to be used.
+ if (text_locked() || curbuf_locked() || updating_screen)
+ return;
+
+ handle_drop_internal();
+}
+
+/*
+ * To be called when text is unlocked, curbuf is unlocked or updating_screen is
+ * reset: Handle a postponed drop.
+ */
+ void
+handle_any_postponed_drop(void)
+{
+ if (!drop_busy && drop_filev != NULL
+ && !text_locked() && !curbuf_locked() && !updating_screen)
+ handle_drop_internal();
+}
+#endif
+
+/*
+ * Clear an argument list: free all file names and reset it to zero entries.
+ */
+ void
+alist_clear(alist_T *al)
+{
+ while (--al->al_ga.ga_len >= 0)
+ vim_free(AARGLIST(al)[al->al_ga.ga_len].ae_fname);
+ ga_clear(&al->al_ga);
+}
+
+/*
+ * Init an argument list.
+ */
+ void
+alist_init(alist_T *al)
+{
+ ga_init2(&al->al_ga, (int)sizeof(aentry_T), 5);
+}
+
+/*
+ * Remove a reference from an argument list.
+ * Ignored when the argument list is the global one.
+ * If the argument list is no longer used by any window, free it.
+ */
+ void
+alist_unlink(alist_T *al)
+{
+ if (al != &global_alist && --al->al_refcount <= 0)
+ {
+ alist_clear(al);
+ vim_free(al);
+ }
+}
+
+/*
+ * Create a new argument list and use it for the current window.
+ */
+ void
+alist_new(void)
+{
+ curwin->w_alist = (alist_T *)alloc((unsigned)sizeof(alist_T));
+ if (curwin->w_alist == NULL)
+ {
+ curwin->w_alist = &global_alist;
+ ++global_alist.al_refcount;
+ }
+ else
+ {
+ curwin->w_alist->al_refcount = 1;
+ curwin->w_alist->id = ++max_alist_id;
+ alist_init(curwin->w_alist);
+ }
+}
+
+#if !defined(UNIX) || defined(PROTO)
+/*
+ * Expand the file names in the global argument list.
+ * If "fnum_list" is not NULL, use "fnum_list[fnum_len]" as a list of buffer
+ * numbers to be re-used.
+ */
+ void
+alist_expand(int *fnum_list, int fnum_len)
+{
+ char_u **old_arg_files;
+ int old_arg_count;
+ char_u **new_arg_files;
+ int new_arg_file_count;
+ char_u *save_p_su = p_su;
+ int i;
+
+ /* Don't use 'suffixes' here. This should work like the shell did the
+ * expansion. Also, the vimrc file isn't read yet, thus the user
+ * can't set the options. */
+ p_su = empty_option;
+ old_arg_files = (char_u **)alloc((unsigned)(sizeof(char_u *) * GARGCOUNT));
+ if (old_arg_files != NULL)
+ {
+ for (i = 0; i < GARGCOUNT; ++i)
+ old_arg_files[i] = vim_strsave(GARGLIST[i].ae_fname);
+ old_arg_count = GARGCOUNT;
+ if (expand_wildcards(old_arg_count, old_arg_files,
+ &new_arg_file_count, &new_arg_files,
+ EW_FILE|EW_NOTFOUND|EW_ADDSLASH|EW_NOERROR) == OK
+ && new_arg_file_count > 0)
+ {
+ alist_set(&global_alist, new_arg_file_count, new_arg_files,
+ TRUE, fnum_list, fnum_len);
+ FreeWild(old_arg_count, old_arg_files);
+ }
+ }
+ p_su = save_p_su;
+}
+#endif
+
+/*
+ * Set the argument list for the current window.
+ * Takes over the allocated files[] and the allocated fnames in it.
+ */
+ void
+alist_set(
+ alist_T *al,
+ int count,
+ char_u **files,
+ int use_curbuf,
+ int *fnum_list,
+ int fnum_len)
+{
+ int i;
+ static int recursive = 0;
+
+ if (recursive)
+ {
+ emsg(_(e_au_recursive));
+ return;
+ }
+ ++recursive;
+
+ alist_clear(al);
+ if (ga_grow(&al->al_ga, count) == OK)
+ {
+ for (i = 0; i < count; ++i)
+ {
+ if (got_int)
+ {
+ /* When adding many buffers this can take a long time. Allow
+ * interrupting here. */
+ while (i < count)
+ vim_free(files[i++]);
+ break;
+ }
+
+ /* May set buffer name of a buffer previously used for the
+ * argument list, so that it's re-used by alist_add. */
+ if (fnum_list != NULL && i < fnum_len)
+ buf_set_name(fnum_list[i], files[i]);
+
+ alist_add(al, files[i], use_curbuf ? 2 : 1);
+ ui_breakcheck();
+ }
+ vim_free(files);
+ }
+ else
+ FreeWild(count, files);
+ if (al == &global_alist)
+ arg_had_last = FALSE;
+
+ --recursive;
+}
+
+/*
+ * Add file "fname" to argument list "al".
+ * "fname" must have been allocated and "al" must have been checked for room.
+ */
+ void
+alist_add(
+ alist_T *al,
+ char_u *fname,
+ int set_fnum) /* 1: set buffer number; 2: re-use curbuf */
+{
+ if (fname == NULL) /* don't add NULL file names */
+ return;
+#ifdef BACKSLASH_IN_FILENAME
+ slash_adjust(fname);
+#endif
+ AARGLIST(al)[al->al_ga.ga_len].ae_fname = fname;
+ if (set_fnum > 0)
+ AARGLIST(al)[al->al_ga.ga_len].ae_fnum =
+ buflist_add(fname, BLN_LISTED | (set_fnum == 2 ? BLN_CURBUF : 0));
+ ++al->al_ga.ga_len;
+}
+
+#if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
+/*
+ * Adjust slashes in file names. Called after 'shellslash' was set.
+ */
+ void
+alist_slash_adjust(void)
+{
+ int i;
+ win_T *wp;
+ tabpage_T *tp;
+
+ for (i = 0; i < GARGCOUNT; ++i)
+ if (GARGLIST[i].ae_fname != NULL)
+ slash_adjust(GARGLIST[i].ae_fname);
+ FOR_ALL_TAB_WINDOWS(tp, wp)
+ if (wp->w_alist != &global_alist)
+ for (i = 0; i < WARGCOUNT(wp); ++i)
+ if (WARGLIST(wp)[i].ae_fname != NULL)
+ slash_adjust(WARGLIST(wp)[i].ae_fname);
+}
+#endif
+
+/*
+ * ":preserve".
+ */
+ static void
+ex_preserve(exarg_T *eap UNUSED)
+{
+ curbuf->b_flags |= BF_PRESERVED;
+ ml_preserve(curbuf, TRUE);
+}
+
+/*
+ * ":recover".
+ */
+ static void
+ex_recover(exarg_T *eap)
+{
+ /* Set recoverymode right away to avoid the ATTENTION prompt. */
+ recoverymode = TRUE;
+ if (!check_changed(curbuf, (p_awa ? CCGD_AW : 0)
+ | CCGD_MULTWIN
+ | (eap->forceit ? CCGD_FORCEIT : 0)
+ | CCGD_EXCMD)
+
+ && (*eap->arg == NUL
+ || setfname(curbuf, eap->arg, NULL, TRUE) == OK))
+ ml_recover();
+ recoverymode = FALSE;
+}
+
+/*
+ * Command modifier used in a wrong way.
+ */
+ static void
+ex_wrongmodifier(exarg_T *eap)
+{
+ eap->errmsg = e_invcmd;
+}
+
+/*
+ * :sview [+command] file split window with new file, read-only
+ * :split [[+command] file] split window with current or new file
+ * :vsplit [[+command] file] split window vertically with current or new file
+ * :new [[+command] file] split window with no or new file
+ * :vnew [[+command] file] split vertically window with no or new file
+ * :sfind [+command] file split window with file in 'path'
+ *
+ * :tabedit open new Tab page with empty window
+ * :tabedit [+command] file open new Tab page and edit "file"
+ * :tabnew [[+command] file] just like :tabedit
+ * :tabfind [+command] file open new Tab page and find "file"
+ */
+ void
+ex_splitview(exarg_T *eap)
+{
+ win_T *old_curwin = curwin;
+#if defined(FEAT_SEARCHPATH) || defined(FEAT_BROWSE)
+ char_u *fname = NULL;
+#endif
+#ifdef FEAT_BROWSE
+ int browse_flag = cmdmod.browse;
+#endif
+ int use_tab = eap->cmdidx == CMD_tabedit
+ || eap->cmdidx == CMD_tabfind
+ || eap->cmdidx == CMD_tabnew;
+
+#ifdef FEAT_GUI
+ need_mouse_correct = TRUE;
+#endif
+
+#ifdef FEAT_QUICKFIX
+ /* A ":split" in the quickfix window works like ":new". Don't want two
+ * quickfix windows. But it's OK when doing ":tab split". */
+ if (bt_quickfix(curbuf) && cmdmod.tab == 0)
+ {
+ if (eap->cmdidx == CMD_split)
+ eap->cmdidx = CMD_new;
+ if (eap->cmdidx == CMD_vsplit)
+ eap->cmdidx = CMD_vnew;
+ }
+#endif
+
+#ifdef FEAT_SEARCHPATH
+ if (eap->cmdidx == CMD_sfind || eap->cmdidx == CMD_tabfind)
+ {
+ fname = find_file_in_path(eap->arg, (int)STRLEN(eap->arg),
+ FNAME_MESS, TRUE, curbuf->b_ffname);
+ if (fname == NULL)
+ goto theend;
+ eap->arg = fname;
+ }
+# ifdef FEAT_BROWSE
+ else
+# endif
+#endif
+#ifdef FEAT_BROWSE
+ if (cmdmod.browse
+ && eap->cmdidx != CMD_vnew
+ && eap->cmdidx != CMD_new)
+ {
+ if (
+# ifdef FEAT_GUI
+ !gui.in_use &&
+# endif
+ au_has_group((char_u *)"FileExplorer"))
+ {
+ /* No browsing supported but we do have the file explorer:
+ * Edit the directory. */
+ if (*eap->arg == NUL || !mch_isdir(eap->arg))
+ eap->arg = (char_u *)".";
+ }
+ else
+ {
+ fname = do_browse(0, (char_u *)(use_tab
+ ? _("Edit File in new tab page")
+ : _("Edit File in new window")),
+ eap->arg, NULL, NULL, NULL, curbuf);
+ if (fname == NULL)
+ goto theend;
+ eap->arg = fname;
+ }
+ }
+ cmdmod.browse = FALSE; /* Don't browse again in do_ecmd(). */
+#endif
+
+ /*
+ * Either open new tab page or split the window.
+ */
+ if (use_tab)
+ {
+ if (win_new_tabpage(cmdmod.tab != 0 ? cmdmod.tab
+ : eap->addr_count == 0 ? 0
+ : (int)eap->line2 + 1) != FAIL)
+ {
+ do_exedit(eap, old_curwin);
+
+ /* set the alternate buffer for the window we came from */
+ if (curwin != old_curwin
+ && win_valid(old_curwin)
+ && old_curwin->w_buffer != curbuf
+ && !cmdmod.keepalt)
+ old_curwin->w_alt_fnum = curbuf->b_fnum;
+ }
+ }
+ else if (win_split(eap->addr_count > 0 ? (int)eap->line2 : 0,
+ *eap->cmd == 'v' ? WSP_VERT : 0) != FAIL)
+ {
+ /* Reset 'scrollbind' when editing another file, but keep it when
+ * doing ":split" without arguments. */
+ if (*eap->arg != NUL
+# ifdef FEAT_BROWSE
+ || cmdmod.browse
+# endif
+ )
+ {
+ RESET_BINDING(curwin);
+ }
+ else
+ do_check_scrollbind(FALSE);
+ do_exedit(eap, old_curwin);
+ }
+
+# ifdef FEAT_BROWSE
+ cmdmod.browse = browse_flag;
+# endif
+
+# if defined(FEAT_SEARCHPATH) || defined(FEAT_BROWSE)
+theend:
+ vim_free(fname);
+# endif
+}
+
+/*
+ * Open a new tab page.
+ */
+ void
+tabpage_new(void)
+{
+ exarg_T ea;
+
+ vim_memset(&ea, 0, sizeof(ea));
+ ea.cmdidx = CMD_tabnew;
+ ea.cmd = (char_u *)"tabn";
+ ea.arg = (char_u *)"";
+ ex_splitview(&ea);
+}
+
+/*
+ * :tabnext command
+ */
+ static void
+ex_tabnext(exarg_T *eap)
+{
+ int tab_number;
+
+ switch (eap->cmdidx)
+ {
+ case CMD_tabfirst:
+ case CMD_tabrewind:
+ goto_tabpage(1);
+ break;
+ case CMD_tablast:
+ goto_tabpage(9999);
+ break;
+ case CMD_tabprevious:
+ case CMD_tabNext:
+ if (eap->arg && *eap->arg != NUL)
+ {
+ char_u *p = eap->arg;
+ char_u *p_save = p;
+
+ tab_number = getdigits(&p);
+ if (p == p_save || *p_save == '-' || *p != NUL
+ || tab_number == 0)
+ {
+ /* No numbers as argument. */
+ eap->errmsg = e_invarg;
+ return;
+ }
+ }
+ else
+ {
+ if (eap->addr_count == 0)
+ tab_number = 1;
+ else
+ {
+ tab_number = eap->line2;
+ if (tab_number < 1)
+ {
+ eap->errmsg = e_invrange;
+ return;
+ }
+ }
+ }
+ goto_tabpage(-tab_number);
+ break;
+ default: /* CMD_tabnext */
+ tab_number = get_tabpage_arg(eap);
+ if (eap->errmsg == NULL)
+ goto_tabpage(tab_number);
+ break;
+ }
+}
+
+/*
+ * :tabmove command
+ */
+ static void
+ex_tabmove(exarg_T *eap)
+{
+ int tab_number;
+
+ tab_number = get_tabpage_arg(eap);
+ if (eap->errmsg == NULL)
+ tabpage_move(tab_number);
+}
+
+/*
+ * :tabs command: List tabs and their contents.
+ */
+ static void
+ex_tabs(exarg_T *eap UNUSED)
+{
+ tabpage_T *tp;
+ win_T *wp;
+ int tabcount = 1;
+
+ msg_start();
+ msg_scroll = TRUE;
+ for (tp = first_tabpage; tp != NULL && !got_int; tp = tp->tp_next)
+ {
+ msg_putchar('\n');
+ vim_snprintf((char *)IObuff, IOSIZE, _("Tab page %d"), tabcount++);
+ msg_outtrans_attr(IObuff, HL_ATTR(HLF_T));
+ out_flush(); /* output one line at a time */
+ ui_breakcheck();
+
+ if (tp == curtab)
+ wp = firstwin;
+ else
+ wp = tp->tp_firstwin;
+ for ( ; wp != NULL && !got_int; wp = wp->w_next)
+ {
+ msg_putchar('\n');
+ msg_putchar(wp == curwin ? '>' : ' ');
+ msg_putchar(' ');
+ msg_putchar(bufIsChanged(wp->w_buffer) ? '+' : ' ');
+ msg_putchar(' ');
+ if (buf_spname(wp->w_buffer) != NULL)
+ vim_strncpy(IObuff, buf_spname(wp->w_buffer), IOSIZE - 1);
+ else
+ home_replace(wp->w_buffer, wp->w_buffer->b_fname,
+ IObuff, IOSIZE, TRUE);
+ msg_outtrans(IObuff);
+ out_flush(); /* output one line at a time */
+ ui_breakcheck();
+ }
+ }
+}
+
+/*
+ * ":mode": Set screen mode.
+ * If no argument given, just get the screen size and redraw.
+ */
+ static void
+ex_mode(exarg_T *eap)
+{
+ if (*eap->arg == NUL)
+ shell_resized();
+ else
+ mch_screenmode(eap->arg);
+}
+
+/*
+ * ":resize".
+ * set, increment or decrement current window height
+ */
+ static void
+ex_resize(exarg_T *eap)
+{
+ int n;
+ win_T *wp = curwin;
+
+ if (eap->addr_count > 0)
+ {
+ n = eap->line2;
+ for (wp = firstwin; wp->w_next != NULL && --n > 0; wp = wp->w_next)
+ ;
+ }
+
+# ifdef FEAT_GUI
+ need_mouse_correct = TRUE;
+# endif
+ n = atol((char *)eap->arg);
+ if (cmdmod.split & WSP_VERT)
+ {
+ if (*eap->arg == '-' || *eap->arg == '+')
+ n += curwin->w_width;
+ else if (n == 0 && eap->arg[0] == NUL) /* default is very wide */
+ n = 9999;
+ win_setwidth_win((int)n, wp);
+ }
+ else
+ {
+ if (*eap->arg == '-' || *eap->arg == '+')
+ n += curwin->w_height;
+ else if (n == 0 && eap->arg[0] == NUL) /* default is very high */
+ n = 9999;
+ win_setheight_win((int)n, wp);
+ }
+}
+
+/*
+ * ":find [+command] <file>" command.
+ */
+ static void
+ex_find(exarg_T *eap)
+{
+#ifdef FEAT_SEARCHPATH
+ char_u *fname;
+ int count;
+
+ fname = find_file_in_path(eap->arg, (int)STRLEN(eap->arg), FNAME_MESS,
+ TRUE, curbuf->b_ffname);
+ if (eap->addr_count > 0)
+ {
+ /* Repeat finding the file "count" times. This matters when it
+ * appears several times in the path. */
+ count = eap->line2;
+ while (fname != NULL && --count > 0)
+ {
+ vim_free(fname);
+ fname = find_file_in_path(NULL, 0, FNAME_MESS,
+ FALSE, curbuf->b_ffname);
+ }
+ }
+
+ if (fname != NULL)
+ {
+ eap->arg = fname;
+#endif
+ do_exedit(eap, NULL);
+#ifdef FEAT_SEARCHPATH
+ vim_free(fname);
+ }
+#endif
+}
+
+/*
+ * ":open" simulation: for now just work like ":visual".
+ */
+ static void
+ex_open(exarg_T *eap)
+{
+ regmatch_T regmatch;
+ char_u *p;
+
+ curwin->w_cursor.lnum = eap->line2;
+ beginline(BL_SOL | BL_FIX);
+ if (*eap->arg == '/')
+ {
+ /* ":open /pattern/": put cursor in column found with pattern */
+ ++eap->arg;
+ p = skip_regexp(eap->arg, '/', p_magic, NULL);
+ *p = NUL;
+ regmatch.regprog = vim_regcomp(eap->arg, p_magic ? RE_MAGIC : 0);
+ if (regmatch.regprog != NULL)
+ {
+ regmatch.rm_ic = p_ic;
+ p = ml_get_curline();
+ if (vim_regexec(&regmatch, p, (colnr_T)0))
+ curwin->w_cursor.col = (colnr_T)(regmatch.startp[0] - p);
+ else
+ emsg(_(e_nomatch));
+ vim_regfree(regmatch.regprog);
+ }
+ /* Move to the NUL, ignore any other arguments. */
+ eap->arg += STRLEN(eap->arg);
+ }
+ check_cursor();
+
+ eap->cmdidx = CMD_visual;
+ do_exedit(eap, NULL);
+}
+
+/*
+ * ":edit", ":badd", ":visual".
+ */
+ static void
+ex_edit(exarg_T *eap)
+{
+ do_exedit(eap, NULL);
+}
+
+/*
+ * ":edit <file>" command and alikes.
+ */
+ void
+do_exedit(
+ exarg_T *eap,
+ win_T *old_curwin) /* curwin before doing a split or NULL */
+{
+ int n;
+ int need_hide;
+ int exmode_was = exmode_active;
+
+ /*
+ * ":vi" command ends Ex mode.
+ */
+ if (exmode_active && (eap->cmdidx == CMD_visual
+ || eap->cmdidx == CMD_view))
+ {
+ exmode_active = FALSE;
+ if (*eap->arg == NUL)
+ {
+ /* Special case: ":global/pat/visual\NLvi-commands" */
+ if (global_busy)
+ {
+ int rd = RedrawingDisabled;
+ int nwr = no_wait_return;
+ int ms = msg_scroll;
+#ifdef FEAT_GUI
+ int he = hold_gui_events;
+#endif
+
+ if (eap->nextcmd != NULL)
+ {
+ stuffReadbuff(eap->nextcmd);
+ eap->nextcmd = NULL;
+ }
+
+ if (exmode_was != EXMODE_VIM)
+ settmode(TMODE_RAW);
+ RedrawingDisabled = 0;
+ no_wait_return = 0;
+ need_wait_return = FALSE;
+ msg_scroll = 0;
+#ifdef FEAT_GUI
+ hold_gui_events = 0;
+#endif
+ must_redraw = CLEAR;
+
+ main_loop(FALSE, TRUE);
+
+ RedrawingDisabled = rd;
+ no_wait_return = nwr;
+ msg_scroll = ms;
+#ifdef FEAT_GUI
+ hold_gui_events = he;
+#endif
+ }
+ return;
+ }
+ }
+
+ if ((eap->cmdidx == CMD_new
+ || eap->cmdidx == CMD_tabnew
+ || eap->cmdidx == CMD_tabedit
+ || eap->cmdidx == CMD_vnew) && *eap->arg == NUL)
+ {
+ /* ":new" or ":tabnew" without argument: edit an new empty buffer */
+ setpcmark();
+ (void)do_ecmd(0, NULL, NULL, eap, ECMD_ONE,
+ ECMD_HIDE + (eap->forceit ? ECMD_FORCEIT : 0),
+ old_curwin == NULL ? curwin : NULL);
+ }
+ else if ((eap->cmdidx != CMD_split && eap->cmdidx != CMD_vsplit)
+ || *eap->arg != NUL
+#ifdef FEAT_BROWSE
+ || cmdmod.browse
+#endif
+ )
+ {
+ /* Can't edit another file when "curbuf_lock" is set. Only ":edit"
+ * can bring us here, others are stopped earlier. */
+ if (*eap->arg != NUL && curbuf_locked())
+ return;
+
+ n = readonlymode;
+ if (eap->cmdidx == CMD_view || eap->cmdidx == CMD_sview)
+ readonlymode = TRUE;
+ else if (eap->cmdidx == CMD_enew)
+ readonlymode = FALSE; /* 'readonly' doesn't make sense in an
+ empty buffer */
+ setpcmark();
+ if (do_ecmd(0, (eap->cmdidx == CMD_enew ? NULL : eap->arg),
+ NULL, eap,
+ /* ":edit" goes to first line if Vi compatible */
+ (*eap->arg == NUL && eap->do_ecmd_lnum == 0
+ && vim_strchr(p_cpo, CPO_GOTO1) != NULL)
+ ? ECMD_ONE : eap->do_ecmd_lnum,
+ (buf_hide(curbuf) ? ECMD_HIDE : 0)
+ + (eap->forceit ? ECMD_FORCEIT : 0)
+ /* after a split we can use an existing buffer */
+ + (old_curwin != NULL ? ECMD_OLDBUF : 0)
+ + (eap->cmdidx == CMD_badd ? ECMD_ADDBUF : 0 )
+ , old_curwin == NULL ? curwin : NULL) == FAIL)
+ {
+ /* Editing the file failed. If the window was split, close it. */
+ if (old_curwin != NULL)
+ {
+ need_hide = (curbufIsChanged() && curbuf->b_nwindows <= 1);
+ if (!need_hide || buf_hide(curbuf))
+ {
+#if defined(FEAT_EVAL)
+ cleanup_T cs;
+
+ /* Reset the error/interrupt/exception state here so that
+ * aborting() returns FALSE when closing a window. */
+ enter_cleanup(&cs);
+#endif
+#ifdef FEAT_GUI
+ need_mouse_correct = TRUE;
+#endif
+ win_close(curwin, !need_hide && !buf_hide(curbuf));
+
+#if defined(FEAT_EVAL)
+ /* Restore the error/interrupt/exception state if not
+ * discarded by a new aborting error, interrupt, or
+ * uncaught exception. */
+ leave_cleanup(&cs);
+#endif
+ }
+ }
+ }
+ else if (readonlymode && curbuf->b_nwindows == 1)
+ {
+ /* When editing an already visited buffer, 'readonly' won't be set
+ * but the previous value is kept. With ":view" and ":sview" we
+ * want the file to be readonly, except when another window is
+ * editing the same buffer. */
+ curbuf->b_p_ro = TRUE;
+ }
+ readonlymode = n;
+ }
+ else
+ {
+ if (eap->do_ecmd_cmd != NULL)
+ do_cmdline_cmd(eap->do_ecmd_cmd);
+#ifdef FEAT_TITLE
+ n = curwin->w_arg_idx_invalid;
+#endif
+ check_arg_idx(curwin);
+#ifdef FEAT_TITLE
+ if (n != curwin->w_arg_idx_invalid)
+ maketitle();
+#endif
+ }
+
+ /*
+ * if ":split file" worked, set alternate file name in old window to new
+ * file
+ */
+ if (old_curwin != NULL
+ && *eap->arg != NUL
+ && curwin != old_curwin
+ && win_valid(old_curwin)
+ && old_curwin->w_buffer != curbuf
+ && !cmdmod.keepalt)
+ old_curwin->w_alt_fnum = curbuf->b_fnum;
+
+ ex_no_reprint = TRUE;
+}
+
+#ifndef FEAT_GUI
+/*
+ * ":gui" and ":gvim" when there is no GUI.
+ */
+ static void
+ex_nogui(exarg_T *eap)
+{
+ eap->errmsg = e_nogvim;
+}
+#endif
+
+#if defined(FEAT_GUI_W32) && defined(FEAT_MENU) && defined(FEAT_TEAROFF)
+ static void
+ex_tearoff(exarg_T *eap)
+{
+ gui_make_tearoff(eap->arg);
+}
+#endif
+
+#if (defined(FEAT_GUI_MSWIN) || defined(FEAT_GUI_GTK) \
+ || defined(FEAT_TERM_POPUP_MENU)) && defined(FEAT_MENU)
+ static void
+ex_popup(exarg_T *eap)
+{
+# if defined(FEAT_GUI_MSWIN) || defined(FEAT_GUI_GTK)
+ if (gui.in_use)
+ gui_make_popup(eap->arg, eap->forceit);
+# ifdef FEAT_TERM_POPUP_MENU
+ else
+# endif
+# endif
+# ifdef FEAT_TERM_POPUP_MENU
+ pum_make_popup(eap->arg, eap->forceit);
+# endif
+}
+#endif
+
+ static void
+ex_swapname(exarg_T *eap UNUSED)
+{
+ if (curbuf->b_ml.ml_mfp == NULL || curbuf->b_ml.ml_mfp->mf_fname == NULL)
+ msg(_("No swap file"));
+ else
+ msg((char *)curbuf->b_ml.ml_mfp->mf_fname);
+}
+
+/*
+ * ":syncbind" forces all 'scrollbind' windows to have the same relative
+ * offset.
+ * (1998-11-02 16:21:01 R. Edward Ralston <eralston@computer.org>)
+ */
+ static void
+ex_syncbind(exarg_T *eap UNUSED)
+{
+ win_T *wp;
+ win_T *save_curwin = curwin;
+ buf_T *save_curbuf = curbuf;
+ long topline;
+ long y;
+ linenr_T old_linenr = curwin->w_cursor.lnum;
+
+ setpcmark();
+
+ /*
+ * determine max topline
+ */
+ if (curwin->w_p_scb)
+ {
+ topline = curwin->w_topline;
+ FOR_ALL_WINDOWS(wp)
+ {
+ if (wp->w_p_scb && wp->w_buffer)
+ {
+ y = wp->w_buffer->b_ml.ml_line_count - get_scrolloff_value();
+ if (topline > y)
+ topline = y;
+ }
+ }
+ if (topline < 1)
+ topline = 1;
+ }
+ else
+ {
+ topline = 1;
+ }
+
+
+ /*
+ * Set all scrollbind windows to the same topline.
+ */
+ FOR_ALL_WINDOWS(curwin)
+ {
+ if (curwin->w_p_scb)
+ {
+ curbuf = curwin->w_buffer;
+ y = topline - curwin->w_topline;
+ if (y > 0)
+ scrollup(y, TRUE);
+ else
+ scrolldown(-y, TRUE);
+ curwin->w_scbind_pos = topline;
+ redraw_later(VALID);
+ cursor_correct();
+ curwin->w_redr_status = TRUE;
+ }
+ }
+ curwin = save_curwin;
+ curbuf = save_curbuf;
+ if (curwin->w_p_scb)
+ {
+ did_syncbind = TRUE;
+ checkpcmark();
+ if (old_linenr != curwin->w_cursor.lnum)
+ {
+ char_u ctrl_o[2];
+
+ ctrl_o[0] = Ctrl_O;
+ ctrl_o[1] = 0;
+ ins_typebuf(ctrl_o, REMAP_NONE, 0, TRUE, FALSE);
+ }
+ }
+}
+
+
+ static void
+ex_read(exarg_T *eap)
+{
+ int i;
+ int empty = (curbuf->b_ml.ml_flags & ML_EMPTY);
+ linenr_T lnum;
+
+ if (eap->usefilter) /* :r!cmd */
+ do_bang(1, eap, FALSE, FALSE, TRUE);
+ else
+ {
+ if (u_save(eap->line2, (linenr_T)(eap->line2 + 1)) == FAIL)
+ return;
+
+#ifdef FEAT_BROWSE
+ if (cmdmod.browse)
+ {
+ char_u *browseFile;
+
+ browseFile = do_browse(0, (char_u *)_("Append File"), eap->arg,
+ NULL, NULL, NULL, curbuf);
+ if (browseFile != NULL)
+ {
+ i = readfile(browseFile, NULL,
+ eap->line2, (linenr_T)0, (linenr_T)MAXLNUM, eap, 0);
+ vim_free(browseFile);
+ }
+ else
+ i = OK;
+ }
+ else
+#endif
+ if (*eap->arg == NUL)
+ {
+ if (check_fname() == FAIL) /* check for no file name */
+ return;
+ i = readfile(curbuf->b_ffname, curbuf->b_fname,
+ eap->line2, (linenr_T)0, (linenr_T)MAXLNUM, eap, 0);
+ }
+ else
+ {
+ if (vim_strchr(p_cpo, CPO_ALTREAD) != NULL)
+ (void)setaltfname(eap->arg, eap->arg, (linenr_T)1);
+ i = readfile(eap->arg, NULL,
+ eap->line2, (linenr_T)0, (linenr_T)MAXLNUM, eap, 0);
+
+ }
+ if (i != OK)
+ {
+#if defined(FEAT_EVAL)
+ if (!aborting())
+#endif
+ semsg(_(e_notopen), eap->arg);
+ }
+ else
+ {
+ if (empty && exmode_active)
+ {
+ /* Delete the empty line that remains. Historically ex does
+ * this but vi doesn't. */
+ if (eap->line2 == 0)
+ lnum = curbuf->b_ml.ml_line_count;
+ else
+ lnum = 1;
+ if (*ml_get(lnum) == NUL && u_savedel(lnum, 1L) == OK)
+ {
+ ml_delete(lnum, FALSE);
+ if (curwin->w_cursor.lnum > 1
+ && curwin->w_cursor.lnum >= lnum)
+ --curwin->w_cursor.lnum;
+ deleted_lines_mark(lnum, 1L);
+ }
+ }
+ redraw_curbuf_later(VALID);
+ }
+ }
+}
+
+static char_u *prev_dir = NULL;
+
+#if defined(EXITFREE) || defined(PROTO)
+ void
+free_cd_dir(void)
+{
+ VIM_CLEAR(prev_dir);
+ VIM_CLEAR(globaldir);
+}
+#endif
+
+/*
+ * Deal with the side effects of changing the current directory.
+ * When "local" is TRUE then this was after an ":lcd" command.
+ */
+ void
+post_chdir(int local)
+{
+ VIM_CLEAR(curwin->w_localdir);
+ if (local)
+ {
+ /* If still in global directory, need to remember current
+ * directory as global directory. */
+ if (globaldir == NULL && prev_dir != NULL)
+ globaldir = vim_strsave(prev_dir);
+ /* Remember this local directory for the window. */
+ if (mch_dirname(NameBuff, MAXPATHL) == OK)
+ curwin->w_localdir = vim_strsave(NameBuff);
+ }
+ else
+ {
+ /* We are now in the global directory, no need to remember its
+ * name. */
+ VIM_CLEAR(globaldir);
+ }
+
+ shorten_fnames(TRUE);
+}
+
+
+/*
+ * ":cd", ":lcd", ":chdir" and ":lchdir".
+ */
+ void
+ex_cd(exarg_T *eap)
+{
+ char_u *new_dir;
+ char_u *tofree;
+ int dir_differs;
+
+ new_dir = eap->arg;
+#if !defined(UNIX) && !defined(VMS)
+ /* for non-UNIX ":cd" means: print current directory */
+ if (*new_dir == NUL)
+ ex_pwd(NULL);
+ else
+#endif
+ {
+ if (allbuf_locked())
+ return;
+ if (vim_strchr(p_cpo, CPO_CHDIR) != NULL && curbufIsChanged()
+ && !eap->forceit)
+ {
+ emsg(_("E747: Cannot change directory, buffer is modified (add ! to override)"));
+ return;
+ }
+
+ /* ":cd -": Change to previous directory */
+ if (STRCMP(new_dir, "-") == 0)
+ {
+ if (prev_dir == NULL)
+ {
+ emsg(_("E186: No previous directory"));
+ return;
+ }
+ new_dir = prev_dir;
+ }
+
+ /* Save current directory for next ":cd -" */
+ tofree = prev_dir;
+ if (mch_dirname(NameBuff, MAXPATHL) == OK)
+ prev_dir = vim_strsave(NameBuff);
+ else
+ prev_dir = NULL;
+
+#if defined(UNIX) || defined(VMS)
+ /* for UNIX ":cd" means: go to home directory */
+ if (*new_dir == NUL)
+ {
+ /* use NameBuff for home directory name */
+# ifdef VMS
+ char_u *p;
+
+ p = mch_getenv((char_u *)"SYS$LOGIN");
+ if (p == NULL || *p == NUL) /* empty is the same as not set */
+ NameBuff[0] = NUL;
+ else
+ vim_strncpy(NameBuff, p, MAXPATHL - 1);
+# else
+ expand_env((char_u *)"$HOME", NameBuff, MAXPATHL);
+# endif
+ new_dir = NameBuff;
+ }
+#endif
+ dir_differs = new_dir == NULL || prev_dir == NULL
+ || pathcmp((char *)prev_dir, (char *)new_dir, -1) != 0;
+ if (new_dir == NULL || (dir_differs && vim_chdir(new_dir)))
+ emsg(_(e_failed));
+ else
+ {
+ int is_local_chdir = eap->cmdidx == CMD_lcd
+ || eap->cmdidx == CMD_lchdir;
+
+ post_chdir(is_local_chdir);
+
+ /* Echo the new current directory if the command was typed. */
+ if (KeyTyped || p_verbose >= 5)
+ ex_pwd(eap);
+
+ if (dir_differs)
+ apply_autocmds(EVENT_DIRCHANGED,
+ is_local_chdir ? (char_u *)"window" : (char_u *)"global",
+ new_dir, FALSE, curbuf);
+ }
+ vim_free(tofree);
+ }
+}
+
+/*
+ * ":pwd".
+ */
+ static void
+ex_pwd(exarg_T *eap UNUSED)
+{
+ if (mch_dirname(NameBuff, MAXPATHL) == OK)
+ {
+#ifdef BACKSLASH_IN_FILENAME
+ slash_adjust(NameBuff);
+#endif
+ msg((char *)NameBuff);
+ }
+ else
+ emsg(_("E187: Unknown"));
+}
+
+/*
+ * ":=".
+ */
+ static void
+ex_equal(exarg_T *eap)
+{
+ smsg("%ld", (long)eap->line2);
+ ex_may_print(eap);
+}
+
+ static void
+ex_sleep(exarg_T *eap)
+{
+ int n;
+ long len;
+
+ if (cursor_valid())
+ {
+ n = W_WINROW(curwin) + curwin->w_wrow - msg_scrolled;
+ if (n >= 0)
+ windgoto((int)n, curwin->w_wincol + curwin->w_wcol);
+ }
+
+ len = eap->line2;
+ switch (*eap->arg)
+ {
+ case 'm': break;
+ case NUL: len *= 1000L; break;
+ default: semsg(_(e_invarg2), eap->arg); return;
+ }
+ do_sleep(len);
+}
+
+/*
+ * Sleep for "msec" milliseconds, but keep checking for a CTRL-C every second.
+ */
+ void
+do_sleep(long msec)
+{
+ long done;
+ long wait_now;
+
+ cursor_on();
+ out_flush_cursor(FALSE, FALSE);
+ for (done = 0; !got_int && done < msec; done += wait_now)
+ {
+ wait_now = msec - done > 1000L ? 1000L : msec - done;
+#ifdef FEAT_TIMERS
+ {
+ long due_time = check_due_timer();
+
+ if (due_time > 0 && due_time < wait_now)
+ wait_now = due_time;
+ }
+#endif
+#ifdef FEAT_JOB_CHANNEL
+ if (has_any_channel() && wait_now > 100L)
+ wait_now = 100L;
+#endif
+ ui_delay(wait_now, TRUE);
+#ifdef FEAT_JOB_CHANNEL
+ if (has_any_channel())
+ ui_breakcheck_force(TRUE);
+ else
+#endif
+ ui_breakcheck();
+#ifdef MESSAGE_QUEUE
+ /* Process the netbeans and clientserver messages that may have been
+ * received in the call to ui_breakcheck() when the GUI is in use. This
+ * may occur when running a test case. */
+ parse_queued_messages();
+#endif
+ }
+
+ // If CTRL-C was typed to interrupt the sleep, drop the CTRL-C from the
+ // input buffer, otherwise a following call to input() fails.
+ if (got_int)
+ (void)vpeekc();
+}
+
+ static void
+do_exmap(exarg_T *eap, int isabbrev)
+{
+ int mode;
+ char_u *cmdp;
+
+ cmdp = eap->cmd;
+ mode = get_map_mode(&cmdp, eap->forceit || isabbrev);
+
+ switch (do_map((*cmdp == 'n') ? 2 : (*cmdp == 'u'),
+ eap->arg, mode, isabbrev))
+ {
+ case 1: emsg(_(e_invarg));
+ break;
+ case 2: emsg((isabbrev ? _(e_noabbr) : _(e_nomap)));
+ break;
+ }
+}
+
+/*
+ * ":winsize" command (obsolete).
+ */
+ static void
+ex_winsize(exarg_T *eap)
+{
+ int w, h;
+ char_u *arg = eap->arg;
+ char_u *p;
+
+ w = getdigits(&arg);
+ arg = skipwhite(arg);
+ p = arg;
+ h = getdigits(&arg);
+ if (*p != NUL && *arg == NUL)
+ set_shellsize(w, h, TRUE);
+ else
+ emsg(_("E465: :winsize requires two number arguments"));
+}
+
+ static void
+ex_wincmd(exarg_T *eap)
+{
+ int xchar = NUL;
+ char_u *p;
+
+ if (*eap->arg == 'g' || *eap->arg == Ctrl_G)
+ {
+ /* CTRL-W g and CTRL-W CTRL-G have an extra command character */
+ if (eap->arg[1] == NUL)
+ {
+ emsg(_(e_invarg));
+ return;
+ }
+ xchar = eap->arg[1];
+ p = eap->arg + 2;
+ }
+ else
+ p = eap->arg + 1;
+
+ eap->nextcmd = check_nextcmd(p);
+ p = skipwhite(p);
+ if (*p != NUL && *p != '"' && eap->nextcmd == NULL)
+ emsg(_(e_invarg));
+ else if (!eap->skip)
+ {
+ /* Pass flags on for ":vertical wincmd ]". */
+ postponed_split_flags = cmdmod.split;
+ postponed_split_tab = cmdmod.tab;
+ do_window(*eap->arg, eap->addr_count > 0 ? eap->line2 : 0L, xchar);
+ postponed_split_flags = 0;
+ postponed_split_tab = 0;
+ }
+}
+
+#if defined(FEAT_GUI) || defined(UNIX) || defined(VMS) || defined(MSWIN)
+/*
+ * ":winpos".
+ */
+ static void
+ex_winpos(exarg_T *eap)
+{
+ int x, y;
+ char_u *arg = eap->arg;
+ char_u *p;
+
+ if (*arg == NUL)
+ {
+# if defined(FEAT_GUI) || defined(MSWIN)
+# ifdef FEAT_GUI
+ if (gui.in_use && gui_mch_get_winpos(&x, &y) != FAIL)
+# else
+ if (mch_get_winpos(&x, &y) != FAIL)
+# endif
+ {
+ sprintf((char *)IObuff, _("Window position: X %d, Y %d"), x, y);
+ msg((char *)IObuff);
+ }
+ else
+# endif
+ emsg(_("E188: Obtaining window position not implemented for this platform"));
+ }
+ else
+ {
+ x = getdigits(&arg);
+ arg = skipwhite(arg);
+ p = arg;
+ y = getdigits(&arg);
+ if (*p == NUL || *arg != NUL)
+ {
+ emsg(_("E466: :winpos requires two number arguments"));
+ return;
+ }
+# ifdef FEAT_GUI
+ if (gui.in_use)
+ gui_mch_set_winpos(x, y);
+ else if (gui.starting)
+ {
+ /* Remember the coordinates for when the window is opened. */
+ gui_win_x = x;
+ gui_win_y = y;
+ }
+# ifdef HAVE_TGETENT
+ else
+# endif
+# else
+# ifdef MSWIN
+ mch_set_winpos(x, y);
+# endif
+# endif
+# ifdef HAVE_TGETENT
+ if (*T_CWP)
+ term_set_winpos(x, y);
+# endif
+ }
+}
+#endif
+
+/*
+ * Handle command that work like operators: ":delete", ":yank", ":>" and ":<".
+ */
+ static void
+ex_operators(exarg_T *eap)
+{
+ oparg_T oa;
+
+ clear_oparg(&oa);
+ oa.regname = eap->regname;
+ oa.start.lnum = eap->line1;
+ oa.end.lnum = eap->line2;
+ oa.line_count = eap->line2 - eap->line1 + 1;
+ oa.motion_type = MLINE;
+ virtual_op = FALSE;
+ if (eap->cmdidx != CMD_yank) /* position cursor for undo */
+ {
+ setpcmark();
+ curwin->w_cursor.lnum = eap->line1;
+ beginline(BL_SOL | BL_FIX);
+ }
+
+ if (VIsual_active)
+ end_visual_mode();
+
+ switch (eap->cmdidx)
+ {
+ case CMD_delete:
+ oa.op_type = OP_DELETE;
+ op_delete(&oa);
+ break;
+
+ case CMD_yank:
+ oa.op_type = OP_YANK;
+ (void)op_yank(&oa, FALSE, TRUE);
+ break;
+
+ default: /* CMD_rshift or CMD_lshift */
+ if (
+#ifdef FEAT_RIGHTLEFT
+ (eap->cmdidx == CMD_rshift) ^ curwin->w_p_rl
+#else
+ eap->cmdidx == CMD_rshift
+#endif
+ )
+ oa.op_type = OP_RSHIFT;
+ else
+ oa.op_type = OP_LSHIFT;
+ op_shift(&oa, FALSE, eap->amount);
+ break;
+ }
+ virtual_op = MAYBE;
+ ex_may_print(eap);
+}
+
+/*
+ * ":put".
+ */
+ static void
+ex_put(exarg_T *eap)
+{
+ /* ":0put" works like ":1put!". */
+ if (eap->line2 == 0)
+ {
+ eap->line2 = 1;
+ eap->forceit = TRUE;
+ }
+ curwin->w_cursor.lnum = eap->line2;
+ do_put(eap->regname, eap->forceit ? BACKWARD : FORWARD, 1L,
+ PUT_LINE|PUT_CURSLINE);
+}
+
+/*
+ * Handle ":copy" and ":move".
+ */
+ static void
+ex_copymove(exarg_T *eap)
+{
+ long n;
+
+ n = get_address(eap, &eap->arg, eap->addr_type, FALSE, FALSE, FALSE, 1);
+ if (eap->arg == NULL) /* error detected */
+ {
+ eap->nextcmd = NULL;
+ return;
+ }
+ get_flags(eap);
+
+ /*
+ * move or copy lines from 'eap->line1'-'eap->line2' to below line 'n'
+ */
+ if (n == MAXLNUM || n < 0 || n > curbuf->b_ml.ml_line_count)
+ {
+ emsg(_(e_invaddr));
+ return;
+ }
+
+ if (eap->cmdidx == CMD_move)
+ {
+ if (do_move(eap->line1, eap->line2, n) == FAIL)
+ return;
+ }
+ else
+ ex_copy(eap->line1, eap->line2, n);
+ u_clearline();
+ beginline(BL_SOL | BL_FIX);
+ ex_may_print(eap);
+}
+
+/*
+ * Print the current line if flags were given to the Ex command.
+ */
+ void
+ex_may_print(exarg_T *eap)
+{
+ if (eap->flags != 0)
+ {
+ print_line(curwin->w_cursor.lnum, (eap->flags & EXFLAG_NR),
+ (eap->flags & EXFLAG_LIST));
+ ex_no_reprint = TRUE;
+ }
+}
+
+/*
+ * ":smagic" and ":snomagic".
+ */
+ static void
+ex_submagic(exarg_T *eap)
+{
+ int magic_save = p_magic;
+
+ p_magic = (eap->cmdidx == CMD_smagic);
+ do_sub(eap);
+ p_magic = magic_save;
+}
+
+/*
+ * ":join".
+ */
+ static void
+ex_join(exarg_T *eap)
+{
+ curwin->w_cursor.lnum = eap->line1;
+ if (eap->line1 == eap->line2)
+ {
+ if (eap->addr_count >= 2) /* :2,2join does nothing */
+ return;
+ if (eap->line2 == curbuf->b_ml.ml_line_count)
+ {
+ beep_flush();
+ return;
+ }
+ ++eap->line2;
+ }
+ (void)do_join(eap->line2 - eap->line1 + 1, !eap->forceit, TRUE, TRUE, TRUE);
+ beginline(BL_WHITE | BL_FIX);
+ ex_may_print(eap);
+}
+
+/*
+ * ":[addr]@r" or ":[addr]*r": execute register
+ */
+ static void
+ex_at(exarg_T *eap)
+{
+ int c;
+ int prev_len = typebuf.tb_len;
+
+ curwin->w_cursor.lnum = eap->line2;
+ check_cursor_col();
+
+#ifdef USE_ON_FLY_SCROLL
+ dont_scroll = TRUE; /* disallow scrolling here */
+#endif
+
+ /* get the register name. No name means to use the previous one */
+ c = *eap->arg;
+ if (c == NUL || (c == '*' && *eap->cmd == '*'))
+ c = '@';
+ /* Put the register in the typeahead buffer with the "silent" flag. */
+ if (do_execreg(c, TRUE, vim_strchr(p_cpo, CPO_EXECBUF) != NULL, TRUE)
+ == FAIL)
+ {
+ beep_flush();
+ }
+ else
+ {
+ int save_efr = exec_from_reg;
+
+ exec_from_reg = TRUE;
+
+ /*
+ * Execute from the typeahead buffer.
+ * Continue until the stuff buffer is empty and all added characters
+ * have been consumed.
+ */
+ while (!stuff_empty() || typebuf.tb_len > prev_len)
+ (void)do_cmdline(NULL, getexline, NULL, DOCMD_NOWAIT|DOCMD_VERBOSE);
+
+ exec_from_reg = save_efr;
+ }
+}
+
+/*
+ * ":!".
+ */
+ static void
+ex_bang(exarg_T *eap)
+{
+ do_bang(eap->addr_count, eap, eap->forceit, TRUE, TRUE);
+}
+
+/*
+ * ":undo".
+ */
+ static void
+ex_undo(exarg_T *eap)
+{
+ if (eap->addr_count == 1) /* :undo 123 */
+ undo_time(eap->line2, FALSE, FALSE, TRUE);
+ else
+ u_undo(1);
+}
+
+#ifdef FEAT_PERSISTENT_UNDO
+ static void
+ex_wundo(exarg_T *eap)
+{
+ char_u hash[UNDO_HASH_SIZE];
+
+ u_compute_hash(hash);
+ u_write_undo(eap->arg, eap->forceit, curbuf, hash);
+}
+
+ static void
+ex_rundo(exarg_T *eap)
+{
+ char_u hash[UNDO_HASH_SIZE];
+
+ u_compute_hash(hash);
+ u_read_undo(eap->arg, hash, NULL);
+}
+#endif
+
+/*
+ * ":redo".
+ */
+ static void
+ex_redo(exarg_T *eap UNUSED)
+{
+ u_redo(1);
+}
+
+/*
+ * ":earlier" and ":later".
+ */
+ static void
+ex_later(exarg_T *eap)
+{
+ long count = 0;
+ int sec = FALSE;
+ int file = FALSE;
+ char_u *p = eap->arg;
+
+ if (*p == NUL)
+ count = 1;
+ else if (isdigit(*p))
+ {
+ count = getdigits(&p);
+ switch (*p)
+ {
+ case 's': ++p; sec = TRUE; break;
+ case 'm': ++p; sec = TRUE; count *= 60; break;
+ case 'h': ++p; sec = TRUE; count *= 60 * 60; break;
+ case 'd': ++p; sec = TRUE; count *= 24 * 60 * 60; break;
+ case 'f': ++p; file = TRUE; break;
+ }
+ }
+
+ if (*p != NUL)
+ semsg(_(e_invarg2), eap->arg);
+ else
+ undo_time(eap->cmdidx == CMD_earlier ? -count : count,
+ sec, file, FALSE);
+}
+
+/*
+ * ":redir": start/stop redirection.
+ */
+ static void
+ex_redir(exarg_T *eap)
+{
+ char *mode;
+ char_u *fname;
+ char_u *arg = eap->arg;
+
+#ifdef FEAT_EVAL
+ if (redir_execute)
+ {
+ emsg(_("E930: Cannot use :redir inside execute()"));
+ return;
+ }
+#endif
+
+ if (STRICMP(eap->arg, "END") == 0)
+ close_redir();
+ else
+ {
+ if (*arg == '>')
+ {
+ ++arg;
+ if (*arg == '>')
+ {
+ ++arg;
+ mode = "a";
+ }
+ else
+ mode = "w";
+ arg = skipwhite(arg);
+
+ close_redir();
+
+ /* Expand environment variables and "~/". */
+ fname = expand_env_save(arg);
+ if (fname == NULL)
+ return;
+#ifdef FEAT_BROWSE
+ if (cmdmod.browse)
+ {
+ char_u *browseFile;
+
+ browseFile = do_browse(BROWSE_SAVE,
+ (char_u *)_("Save Redirection"),
+ fname, NULL, NULL,
+ (char_u *)_(BROWSE_FILTER_ALL_FILES), curbuf);
+ if (browseFile == NULL)
+ return; /* operation cancelled */
+ vim_free(fname);
+ fname = browseFile;
+ eap->forceit = TRUE; /* since dialog already asked */
+ }
+#endif
+
+ redir_fd = open_exfile(fname, eap->forceit, mode);
+ vim_free(fname);
+ }
+#ifdef FEAT_EVAL
+ else if (*arg == '@')
+ {
+ /* redirect to a register a-z (resp. A-Z for appending) */
+ close_redir();
+ ++arg;
+ if (ASCII_ISALPHA(*arg)
+# ifdef FEAT_CLIPBOARD
+ || *arg == '*'
+ || *arg == '+'
+# endif
+ || *arg == '"')
+ {
+ redir_reg = *arg++;
+ if (*arg == '>' && arg[1] == '>') /* append */
+ arg += 2;
+ else
+ {
+ /* Can use both "@a" and "@a>". */
+ if (*arg == '>')
+ arg++;
+ /* Make register empty when not using @A-@Z and the
+ * command is valid. */
+ if (*arg == NUL && !isupper(redir_reg))
+ write_reg_contents(redir_reg, (char_u *)"", -1, FALSE);
+ }
+ }
+ if (*arg != NUL)
+ {
+ redir_reg = 0;
+ semsg(_(e_invarg2), eap->arg);
+ }
+ }
+ else if (*arg == '=' && arg[1] == '>')
+ {
+ int append;
+
+ /* redirect to a variable */
+ close_redir();
+ arg += 2;
+
+ if (*arg == '>')
+ {
+ ++arg;
+ append = TRUE;
+ }
+ else
+ append = FALSE;
+
+ if (var_redir_start(skipwhite(arg), append) == OK)
+ redir_vname = 1;
+ }
+#endif
+
+ /* TODO: redirect to a buffer */
+
+ else
+ semsg(_(e_invarg2), eap->arg);
+ }
+
+ /* Make sure redirection is not off. Can happen for cmdline completion
+ * that indirectly invokes a command to catch its output. */
+ if (redir_fd != NULL
+#ifdef FEAT_EVAL
+ || redir_reg || redir_vname
+#endif
+ )
+ redir_off = FALSE;
+}
+
+/*
+ * ":redraw": force redraw
+ */
+ void
+ex_redraw(exarg_T *eap)
+{
+ int r = RedrawingDisabled;
+ int p = p_lz;
+
+ RedrawingDisabled = 0;
+ p_lz = FALSE;
+ validate_cursor();
+ update_topline();
+ update_screen(eap->forceit ? CLEAR : VIsual_active ? INVERTED : 0);
+#ifdef FEAT_TITLE
+ if (need_maketitle)
+ maketitle();
+#endif
+ RedrawingDisabled = r;
+ p_lz = p;
+
+ /* Reset msg_didout, so that a message that's there is overwritten. */
+ msg_didout = FALSE;
+ msg_col = 0;
+
+ /* No need to wait after an intentional redraw. */
+ need_wait_return = FALSE;
+
+ out_flush();
+}
+
+/*
+ * ":redrawstatus": force redraw of status line(s)
+ */
+ static void
+ex_redrawstatus(exarg_T *eap UNUSED)
+{
+ int r = RedrawingDisabled;
+ int p = p_lz;
+
+ RedrawingDisabled = 0;
+ p_lz = FALSE;
+ if (eap->forceit)
+ status_redraw_all();
+ else
+ status_redraw_curbuf();
+ update_screen(VIsual_active ? INVERTED : 0);
+ RedrawingDisabled = r;
+ p_lz = p;
+ out_flush();
+}
+
+/*
+ * ":redrawtabline": force redraw of the tabline
+ */
+ static void
+ex_redrawtabline(exarg_T *eap UNUSED)
+{
+ int r = RedrawingDisabled;
+ int p = p_lz;
+
+ RedrawingDisabled = 0;
+ p_lz = FALSE;
+
+ draw_tabline();
+
+ RedrawingDisabled = r;
+ p_lz = p;
+ out_flush();
+}
+
+ static void
+close_redir(void)
+{
+ if (redir_fd != NULL)
+ {
+ fclose(redir_fd);
+ redir_fd = NULL;
+ }
+#ifdef FEAT_EVAL
+ redir_reg = 0;
+ if (redir_vname)
+ {
+ var_redir_stop();
+ redir_vname = 0;
+ }
+#endif
+}
+
+#if defined(FEAT_SESSION) && defined(USE_CRNL)
+# define MKSESSION_NL
+static int mksession_nl = FALSE; /* use NL only in put_eol() */
+#endif
+
+/*
+ * ":mkexrc", ":mkvimrc", ":mkview" and ":mksession".
+ */
+ static void
+ex_mkrc(
+ exarg_T *eap)
+{
+ FILE *fd;
+ int failed = FALSE;
+ char_u *fname;
+#ifdef FEAT_BROWSE
+ char_u *browseFile = NULL;
+#endif
+#ifdef FEAT_SESSION
+ int view_session = FALSE;
+ int using_vdir = FALSE; /* using 'viewdir'? */
+ char_u *viewFile = NULL;
+ unsigned *flagp;
+#endif
+
+ if (eap->cmdidx == CMD_mksession || eap->cmdidx == CMD_mkview)
+ {
+#ifdef FEAT_SESSION
+ view_session = TRUE;
+#else
+ ex_ni(eap);
+ return;
+#endif
+ }
+
+#ifdef FEAT_SESSION
+ /* Use the short file name until ":lcd" is used. We also don't use the
+ * short file name when 'acd' is set, that is checked later. */
+ did_lcd = FALSE;
+
+ /* ":mkview" or ":mkview 9": generate file name with 'viewdir' */
+ if (eap->cmdidx == CMD_mkview
+ && (*eap->arg == NUL
+ || (vim_isdigit(*eap->arg) && eap->arg[1] == NUL)))
+ {
+ eap->forceit = TRUE;
+ fname = get_view_file(*eap->arg);
+ if (fname == NULL)
+ return;
+ viewFile = fname;
+ using_vdir = TRUE;
+ }
+ else
+#endif
+ if (*eap->arg != NUL)
+ fname = eap->arg;
+ else if (eap->cmdidx == CMD_mkvimrc)
+ fname = (char_u *)VIMRC_FILE;
+#ifdef FEAT_SESSION
+ else if (eap->cmdidx == CMD_mksession)
+ fname = (char_u *)SESSION_FILE;
+#endif
+ else
+ fname = (char_u *)EXRC_FILE;
+
+#ifdef FEAT_BROWSE
+ if (cmdmod.browse)
+ {
+ browseFile = do_browse(BROWSE_SAVE,
+# ifdef FEAT_SESSION
+ eap->cmdidx == CMD_mkview ? (char_u *)_("Save View") :
+ eap->cmdidx == CMD_mksession ? (char_u *)_("Save Session") :
+# endif
+ (char_u *)_("Save Setup"),
+ fname, (char_u *)"vim", NULL,
+ (char_u *)_(BROWSE_FILTER_MACROS), NULL);
+ if (browseFile == NULL)
+ goto theend;
+ fname = browseFile;
+ eap->forceit = TRUE; /* since dialog already asked */
+ }
+#endif
+
+#if defined(FEAT_SESSION) && defined(vim_mkdir)
+ /* When using 'viewdir' may have to create the directory. */
+ if (using_vdir && !mch_isdir(p_vdir))
+ vim_mkdir_emsg(p_vdir, 0755);
+#endif
+
+ fd = open_exfile(fname, eap->forceit, WRITEBIN);
+ if (fd != NULL)
+ {
+#ifdef FEAT_SESSION
+ if (eap->cmdidx == CMD_mkview)
+ flagp = &vop_flags;
+ else
+ flagp = &ssop_flags;
+#endif
+
+#ifdef MKSESSION_NL
+ /* "unix" in 'sessionoptions': use NL line separator */
+ if (view_session && (*flagp & SSOP_UNIX))
+ mksession_nl = TRUE;
+#endif
+
+ /* Write the version command for :mkvimrc */
+ if (eap->cmdidx == CMD_mkvimrc)
+ (void)put_line(fd, "version 6.0");
+
+#ifdef FEAT_SESSION
+ if (eap->cmdidx == CMD_mksession)
+ {
+ if (put_line(fd, "let SessionLoad = 1") == FAIL)
+ failed = TRUE;
+ }
+
+ if (eap->cmdidx != CMD_mkview)
+#endif
+ {
+ /* Write setting 'compatible' first, because it has side effects.
+ * For that same reason only do it when needed. */
+ if (p_cp)
+ (void)put_line(fd, "if !&cp | set cp | endif");
+ else
+ (void)put_line(fd, "if &cp | set nocp | endif");
+ }
+
+#ifdef FEAT_SESSION
+ if (!view_session
+ || (eap->cmdidx == CMD_mksession
+ && (*flagp & SSOP_OPTIONS)))
+#endif
+ failed |= (makemap(fd, NULL) == FAIL
+ || makeset(fd, OPT_GLOBAL, FALSE) == FAIL);
+
+#ifdef FEAT_SESSION
+ if (!failed && view_session)
+ {
+ if (put_line(fd, "let s:so_save = &so | let s:siso_save = &siso | set so=0 siso=0") == FAIL)
+ failed = TRUE;
+ if (eap->cmdidx == CMD_mksession)
+ {
+ char_u *dirnow; /* current directory */
+
+ dirnow = alloc(MAXPATHL);
+ if (dirnow == NULL)
+ failed = TRUE;
+ else
+ {
+ /*
+ * Change to session file's dir.
+ */
+ if (mch_dirname(dirnow, MAXPATHL) == FAIL
+ || mch_chdir((char *)dirnow) != 0)
+ *dirnow = NUL;
+ if (*dirnow != NUL && (ssop_flags & SSOP_SESDIR))
+ {
+ if (vim_chdirfile(fname, NULL) == OK)
+ shorten_fnames(TRUE);
+ }
+ else if (*dirnow != NUL
+ && (ssop_flags & SSOP_CURDIR) && globaldir != NULL)
+ {
+ if (mch_chdir((char *)globaldir) == 0)
+ shorten_fnames(TRUE);
+ }
+
+ failed |= (makeopens(fd, dirnow) == FAIL);
+
+ /* restore original dir */
+ if (*dirnow != NUL && ((ssop_flags & SSOP_SESDIR)
+ || ((ssop_flags & SSOP_CURDIR) && globaldir != NULL)))
+ {
+ if (mch_chdir((char *)dirnow) != 0)
+ emsg(_(e_prev_dir));
+ shorten_fnames(TRUE);
+ }
+ vim_free(dirnow);
+ }
+ }
+ else
+ {
+ failed |= (put_view(fd, curwin, !using_vdir, flagp,
+ -1) == FAIL);
+ }
+ if (put_line(fd, "let &so = s:so_save | let &siso = s:siso_save")
+ == FAIL)
+ failed = TRUE;
+# ifdef FEAT_SEARCH_EXTRA
+ if (no_hlsearch && put_line(fd, "nohlsearch") == FAIL)
+ failed = TRUE;
+# endif
+ if (put_line(fd, "doautoall SessionLoadPost") == FAIL)
+ failed = TRUE;
+ if (eap->cmdidx == CMD_mksession)
+ {
+ if (put_line(fd, "unlet SessionLoad") == FAIL)
+ failed = TRUE;
+ }
+ }
+#endif
+ if (put_line(fd, "\" vim: set ft=vim :") == FAIL)
+ failed = TRUE;
+
+ failed |= fclose(fd);
+
+ if (failed)
+ emsg(_(e_write));
+#if defined(FEAT_EVAL) && defined(FEAT_SESSION)
+ else if (eap->cmdidx == CMD_mksession)
+ {
+ /* successful session write - set this_session var */
+ char_u *tbuf;
+
+ tbuf = alloc(MAXPATHL);
+ if (tbuf != NULL)
+ {
+ if (vim_FullName(fname, tbuf, MAXPATHL, FALSE) == OK)
+ set_vim_var_string(VV_THIS_SESSION, tbuf, -1);
+ vim_free(tbuf);
+ }
+ }
+#endif
+#ifdef MKSESSION_NL
+ mksession_nl = FALSE;
+#endif
+ }
+
+#ifdef FEAT_BROWSE
+theend:
+ vim_free(browseFile);
+#endif
+#ifdef FEAT_SESSION
+ vim_free(viewFile);
+#endif
+}
+
+#if ((defined(FEAT_SESSION) || defined(FEAT_EVAL)) && defined(vim_mkdir)) \
+ || defined(PROTO)
+ int
+vim_mkdir_emsg(char_u *name, int prot)
+{
+ if (vim_mkdir(name, prot) != 0)
+ {
+ semsg(_("E739: Cannot create directory: %s"), name);
+ return FAIL;
+ }
+ return OK;
+}
+#endif
+
+/*
+ * Open a file for writing for an Ex command, with some checks.
+ * Return file descriptor, or NULL on failure.
+ */
+ FILE *
+open_exfile(
+ char_u *fname,
+ int forceit,
+ char *mode) /* "w" for create new file or "a" for append */
+{
+ FILE *fd;
+
+#ifdef UNIX
+ /* with Unix it is possible to open a directory */
+ if (mch_isdir(fname))
+ {
+ semsg(_(e_isadir2), fname);
+ return NULL;
+ }
+#endif
+ if (!forceit && *mode != 'a' && vim_fexists(fname))
+ {
+ semsg(_("E189: \"%s\" exists (add ! to override)"), fname);
+ return NULL;
+ }
+
+ if ((fd = mch_fopen((char *)fname, mode)) == NULL)
+ semsg(_("E190: Cannot open \"%s\" for writing"), fname);
+
+ return fd;
+}
+
+/*
+ * ":mark" and ":k".
+ */
+ static void
+ex_mark(exarg_T *eap)
+{
+ pos_T pos;
+
+ if (*eap->arg == NUL) /* No argument? */
+ emsg(_(e_argreq));
+ else if (eap->arg[1] != NUL) /* more than one character? */
+ emsg(_(e_trailing));
+ else
+ {
+ pos = curwin->w_cursor; /* save curwin->w_cursor */
+ curwin->w_cursor.lnum = eap->line2;
+ beginline(BL_WHITE | BL_FIX);
+ if (setmark(*eap->arg) == FAIL) /* set mark */
+ emsg(_("E191: Argument must be a letter or forward/backward quote"));
+ curwin->w_cursor = pos; /* restore curwin->w_cursor */
+ }
+}
+
+/*
+ * Update w_topline, w_leftcol and the cursor position.
+ */
+ void
+update_topline_cursor(void)
+{
+ check_cursor(); /* put cursor on valid line */
+ update_topline();
+ if (!curwin->w_p_wrap)
+ validate_cursor();
+ update_curswant();
+}
+
+/*
+ * Save the current State and go to Normal mode.
+ * Return TRUE if the typeahead could be saved.
+ */
+ int
+save_current_state(save_state_T *sst)
+{
+ sst->save_msg_scroll = msg_scroll;
+ sst->save_restart_edit = restart_edit;
+ sst->save_msg_didout = msg_didout;
+ sst->save_State = State;
+ sst->save_insertmode = p_im;
+ sst->save_finish_op = finish_op;
+ sst->save_opcount = opcount;
+
+ msg_scroll = FALSE; /* no msg scrolling in Normal mode */
+ restart_edit = 0; /* don't go to Insert mode */
+ p_im = FALSE; /* don't use 'insertmode' */
+
+ /*
+ * Save the current typeahead. This is required to allow using ":normal"
+ * from an event handler and makes sure we don't hang when the argument
+ * ends with half a command.
+ */
+ save_typeahead(&sst->tabuf);
+ return sst->tabuf.typebuf_valid;
+}
+
+ void
+restore_current_state(save_state_T *sst)
+{
+ /* Restore the previous typeahead. */
+ restore_typeahead(&sst->tabuf);
+
+ msg_scroll = sst->save_msg_scroll;
+ restart_edit = sst->save_restart_edit;
+ p_im = sst->save_insertmode;
+ finish_op = sst->save_finish_op;
+ opcount = sst->save_opcount;
+ msg_didout |= sst->save_msg_didout; /* don't reset msg_didout now */
+
+ /* Restore the state (needed when called from a function executed for
+ * 'indentexpr'). Update the mouse and cursor, they may have changed. */
+ State = sst->save_State;
+#ifdef CURSOR_SHAPE
+ ui_cursor_shape(); /* may show different cursor shape */
+#endif
+}
+
+/*
+ * ":normal[!] {commands}": Execute normal mode commands.
+ */
+ void
+ex_normal(exarg_T *eap)
+{
+ save_state_T save_state;
+ char_u *arg = NULL;
+ int l;
+ char_u *p;
+
+ if (ex_normal_lock > 0)
+ {
+ emsg(_(e_secure));
+ return;
+ }
+ if (ex_normal_busy >= p_mmd)
+ {
+ emsg(_("E192: Recursive use of :normal too deep"));
+ return;
+ }
+
+ /*
+ * vgetc() expects a CSI and K_SPECIAL to have been escaped. Don't do
+ * this for the K_SPECIAL leading byte, otherwise special keys will not
+ * work.
+ */
+ if (has_mbyte)
+ {
+ int len = 0;
+
+ /* Count the number of characters to be escaped. */
+ for (p = eap->arg; *p != NUL; ++p)
+ {
+#ifdef FEAT_GUI
+ if (*p == CSI) /* leadbyte CSI */
+ len += 2;
+#endif
+ for (l = (*mb_ptr2len)(p) - 1; l > 0; --l)
+ if (*++p == K_SPECIAL /* trailbyte K_SPECIAL or CSI */
+#ifdef FEAT_GUI
+ || *p == CSI
+#endif
+ )
+ len += 2;
+ }
+ if (len > 0)
+ {
+ arg = alloc((unsigned)(STRLEN(eap->arg) + len + 1));
+ if (arg != NULL)
+ {
+ len = 0;
+ for (p = eap->arg; *p != NUL; ++p)
+ {
+ arg[len++] = *p;
+#ifdef FEAT_GUI
+ if (*p == CSI)
+ {
+ arg[len++] = KS_EXTRA;
+ arg[len++] = (int)KE_CSI;
+ }
+#endif
+ for (l = (*mb_ptr2len)(p) - 1; l > 0; --l)
+ {
+ arg[len++] = *++p;
+ if (*p == K_SPECIAL)
+ {
+ arg[len++] = KS_SPECIAL;
+ arg[len++] = KE_FILLER;
+ }
+#ifdef FEAT_GUI
+ else if (*p == CSI)
+ {
+ arg[len++] = KS_EXTRA;
+ arg[len++] = (int)KE_CSI;
+ }
+#endif
+ }
+ arg[len] = NUL;
+ }
+ }
+ }
+ }
+
+ ++ex_normal_busy;
+ if (save_current_state(&save_state))
+ {
+ /*
+ * Repeat the :normal command for each line in the range. When no
+ * range given, execute it just once, without positioning the cursor
+ * first.
+ */
+ do
+ {
+ if (eap->addr_count != 0)
+ {
+ curwin->w_cursor.lnum = eap->line1++;
+ curwin->w_cursor.col = 0;
+ check_cursor_moved(curwin);
+ }
+
+ exec_normal_cmd(arg != NULL
+ ? arg
+ : eap->arg, eap->forceit ? REMAP_NONE : REMAP_YES, FALSE);
+ }
+ while (eap->addr_count > 0 && eap->line1 <= eap->line2 && !got_int);
+ }
+
+ /* Might not return to the main loop when in an event handler. */
+ update_topline_cursor();
+
+ restore_current_state(&save_state);
+ --ex_normal_busy;
+#ifdef FEAT_MOUSE
+ setmouse();
+#endif
+#ifdef CURSOR_SHAPE
+ ui_cursor_shape(); /* may show different cursor shape */
+#endif
+
+ vim_free(arg);
+}
+
+/*
+ * ":startinsert", ":startreplace" and ":startgreplace"
+ */
+ static void
+ex_startinsert(exarg_T *eap)
+{
+ if (eap->forceit)
+ {
+ /* cursor line can be zero on startup */
+ if (!curwin->w_cursor.lnum)
+ curwin->w_cursor.lnum = 1;
+ coladvance((colnr_T)MAXCOL);
+ curwin->w_curswant = MAXCOL;
+ curwin->w_set_curswant = FALSE;
+ }
+
+ /* Ignore the command when already in Insert mode. Inserting an
+ * expression register that invokes a function can do this. */
+ if (State & INSERT)
+ return;
+
+ if (eap->cmdidx == CMD_startinsert)
+ restart_edit = 'a';
+ else if (eap->cmdidx == CMD_startreplace)
+ restart_edit = 'R';
+ else
+ restart_edit = 'V';
+
+ if (!eap->forceit)
+ {
+ if (eap->cmdidx == CMD_startinsert)
+ restart_edit = 'i';
+ curwin->w_curswant = 0; /* avoid MAXCOL */
+ }
+}
+
+/*
+ * ":stopinsert"
+ */
+ static void
+ex_stopinsert(exarg_T *eap UNUSED)
+{
+ restart_edit = 0;
+ stop_insert_mode = TRUE;
+ clearmode();
+}
+
+/*
+ * Execute normal mode command "cmd".
+ * "remap" can be REMAP_NONE or REMAP_YES.
+ */
+ void
+exec_normal_cmd(char_u *cmd, int remap, int silent)
+{
+ /* Stuff the argument into the typeahead buffer. */
+ ins_typebuf(cmd, remap, 0, TRUE, silent);
+ exec_normal(FALSE, FALSE, FALSE);
+}
+
+/*
+ * Execute normal_cmd() until there is no typeahead left.
+ * When "use_vpeekc" is TRUE use vpeekc() to check for available chars.
+ */
+ void
+exec_normal(int was_typed, int use_vpeekc, int may_use_terminal_loop UNUSED)
+{
+ oparg_T oa;
+
+ clear_oparg(&oa);
+ finish_op = FALSE;
+ while ((!stuff_empty()
+ || ((was_typed || !typebuf_typed()) && typebuf.tb_len > 0)
+ || (use_vpeekc && vpeekc() != NUL))
+ && !got_int)
+ {
+ update_topline_cursor();
+#ifdef FEAT_TERMINAL
+ if (may_use_terminal_loop && term_use_loop()
+ && oa.op_type == OP_NOP && oa.regname == NUL
+ && !VIsual_active)
+ {
+ /* If terminal_loop() returns OK we got a key that is handled
+ * in Normal model. With FAIL we first need to position the
+ * cursor and the screen needs to be redrawn. */
+ if (terminal_loop(TRUE) == OK)
+ normal_cmd(&oa, TRUE);
+ }
+ else
+#endif
+ /* execute a Normal mode cmd */
+ normal_cmd(&oa, TRUE);
+ }
+}
+
+#ifdef FEAT_FIND_ID
+ static void
+ex_checkpath(exarg_T *eap)
+{
+ find_pattern_in_path(NULL, 0, 0, FALSE, FALSE, CHECK_PATH, 1L,
+ eap->forceit ? ACTION_SHOW_ALL : ACTION_SHOW,
+ (linenr_T)1, (linenr_T)MAXLNUM);
+}
+
+#if defined(FEAT_QUICKFIX)
+/*
+ * ":psearch"
+ */
+ static void
+ex_psearch(exarg_T *eap)
+{
+ g_do_tagpreview = p_pvh;
+ ex_findpat(eap);
+ g_do_tagpreview = 0;
+}
+#endif
+
+ static void
+ex_findpat(exarg_T *eap)
+{
+ int whole = TRUE;
+ long n;
+ char_u *p;
+ int action;
+
+ switch (cmdnames[eap->cmdidx].cmd_name[2])
+ {
+ case 'e': /* ":psearch", ":isearch" and ":dsearch" */
+ if (cmdnames[eap->cmdidx].cmd_name[0] == 'p')
+ action = ACTION_GOTO;
+ else
+ action = ACTION_SHOW;
+ break;
+ case 'i': /* ":ilist" and ":dlist" */
+ action = ACTION_SHOW_ALL;
+ break;
+ case 'u': /* ":ijump" and ":djump" */
+ action = ACTION_GOTO;
+ break;
+ default: /* ":isplit" and ":dsplit" */
+ action = ACTION_SPLIT;
+ break;
+ }
+
+ n = 1;
+ if (vim_isdigit(*eap->arg)) /* get count */
+ {
+ n = getdigits(&eap->arg);
+ eap->arg = skipwhite(eap->arg);
+ }
+ if (*eap->arg == '/') /* Match regexp, not just whole words */
+ {
+ whole = FALSE;
+ ++eap->arg;
+ p = skip_regexp(eap->arg, '/', p_magic, NULL);
+ if (*p)
+ {
+ *p++ = NUL;
+ p = skipwhite(p);
+
+ /* Check for trailing illegal characters */
+ if (!ends_excmd(*p))
+ eap->errmsg = e_trailing;
+ else
+ eap->nextcmd = check_nextcmd(p);
+ }
+ }
+ if (!eap->skip)
+ find_pattern_in_path(eap->arg, 0, (int)STRLEN(eap->arg),
+ whole, !eap->forceit,
+ *eap->cmd == 'd' ? FIND_DEFINE : FIND_ANY,
+ n, action, eap->line1, eap->line2);
+}
+#endif
+
+
+#ifdef FEAT_QUICKFIX
+/*
+ * ":ptag", ":ptselect", ":ptjump", ":ptnext", etc.
+ */
+ static void
+ex_ptag(exarg_T *eap)
+{
+ g_do_tagpreview = p_pvh; /* will be reset to 0 in ex_tag_cmd() */
+ ex_tag_cmd(eap, cmdnames[eap->cmdidx].cmd_name + 1);
+}
+
+/*
+ * ":pedit"
+ */
+ static void
+ex_pedit(exarg_T *eap)
+{
+ win_T *curwin_save = curwin;
+
+ g_do_tagpreview = p_pvh;
+ prepare_tagpreview(TRUE);
+ keep_help_flag = bt_help(curwin_save->w_buffer);
+ do_exedit(eap, NULL);
+ keep_help_flag = FALSE;
+ if (curwin != curwin_save && win_valid(curwin_save))
+ {
+ /* Return cursor to where we were */
+ validate_cursor();
+ redraw_later(VALID);
+ win_enter(curwin_save, TRUE);
+ }
+ g_do_tagpreview = 0;
+}
+#endif
+
+/*
+ * ":stag", ":stselect" and ":stjump".
+ */
+ static void
+ex_stag(exarg_T *eap)
+{
+ postponed_split = -1;
+ postponed_split_flags = cmdmod.split;
+ postponed_split_tab = cmdmod.tab;
+ ex_tag_cmd(eap, cmdnames[eap->cmdidx].cmd_name + 1);
+ postponed_split_flags = 0;
+ postponed_split_tab = 0;
+}
+
+/*
+ * ":tag", ":tselect", ":tjump", ":tnext", etc.
+ */
+ static void
+ex_tag(exarg_T *eap)
+{
+ ex_tag_cmd(eap, cmdnames[eap->cmdidx].cmd_name);
+}
+
+ static void
+ex_tag_cmd(exarg_T *eap, char_u *name)
+{
+ int cmd;
+
+ switch (name[1])
+ {
+ case 'j': cmd = DT_JUMP; /* ":tjump" */
+ break;
+ case 's': cmd = DT_SELECT; /* ":tselect" */
+ break;
+ case 'p': cmd = DT_PREV; /* ":tprevious" */
+ break;
+ case 'N': cmd = DT_PREV; /* ":tNext" */
+ break;
+ case 'n': cmd = DT_NEXT; /* ":tnext" */
+ break;
+ case 'o': cmd = DT_POP; /* ":pop" */
+ break;
+ case 'f': /* ":tfirst" */
+ case 'r': cmd = DT_FIRST; /* ":trewind" */
+ break;
+ case 'l': cmd = DT_LAST; /* ":tlast" */
+ break;
+ default: /* ":tag" */
+#ifdef FEAT_CSCOPE
+ if (p_cst && *eap->arg != NUL)
+ {
+ ex_cstag(eap);
+ return;
+ }
+#endif
+ cmd = DT_TAG;
+ break;
+ }
+
+ if (name[0] == 'l')
+ {
+#ifndef FEAT_QUICKFIX
+ ex_ni(eap);
+ return;
+#else
+ cmd = DT_LTAG;
+#endif
+ }
+
+ do_tag(eap->arg, cmd, eap->addr_count > 0 ? (int)eap->line2 : 1,
+ eap->forceit, TRUE);
+}
+
+/*
+ * Check "str" for starting with a special cmdline variable.
+ * If found return one of the SPEC_ values and set "*usedlen" to the length of
+ * the variable. Otherwise return -1 and "*usedlen" is unchanged.
+ */
+ int
+find_cmdline_var(char_u *src, int *usedlen)
+{
+ int len;
+ int i;
+ static char *(spec_str[]) = {
+ "%",
+#define SPEC_PERC 0
+ "#",
+#define SPEC_HASH (SPEC_PERC + 1)
+ "<cword>", /* cursor word */
+#define SPEC_CWORD (SPEC_HASH + 1)
+ "<cWORD>", /* cursor WORD */
+#define SPEC_CCWORD (SPEC_CWORD + 1)
+ "<cexpr>", /* expr under cursor */
+#define SPEC_CEXPR (SPEC_CCWORD + 1)
+ "<cfile>", /* cursor path name */
+#define SPEC_CFILE (SPEC_CEXPR + 1)
+ "<sfile>", /* ":so" file name */
+#define SPEC_SFILE (SPEC_CFILE + 1)
+ "<slnum>", /* ":so" file line number */
+#define SPEC_SLNUM (SPEC_SFILE + 1)
+ "<afile>", /* autocommand file name */
+#define SPEC_AFILE (SPEC_SLNUM + 1)
+ "<abuf>", /* autocommand buffer number */
+#define SPEC_ABUF (SPEC_AFILE + 1)
+ "<amatch>", /* autocommand match name */
+#define SPEC_AMATCH (SPEC_ABUF + 1)
+ "<sflnum>", /* script file line number */
+#define SPEC_SFLNUM (SPEC_AMATCH + 1)
+#ifdef FEAT_CLIENTSERVER
+ "<client>"
+# define SPEC_CLIENT (SPEC_SFLNUM + 1)
+#endif
+ };
+
+ for (i = 0; i < (int)(sizeof(spec_str) / sizeof(char *)); ++i)
+ {
+ len = (int)STRLEN(spec_str[i]);
+ if (STRNCMP(src, spec_str[i], len) == 0)
+ {
+ *usedlen = len;
+ return i;
+ }
+ }
+ return -1;
+}
+
+/*
+ * Evaluate cmdline variables.
+ *
+ * change '%' to curbuf->b_ffname
+ * '#' to curwin->w_altfile
+ * '<cword>' to word under the cursor
+ * '<cWORD>' to WORD under the cursor
+ * '<cfile>' to path name under the cursor
+ * '<sfile>' to sourced file name
+ * '<slnum>' to sourced file line number
+ * '<afile>' to file name for autocommand
+ * '<abuf>' to buffer number for autocommand
+ * '<amatch>' to matching name for autocommand
+ *
+ * When an error is detected, "errormsg" is set to a non-NULL pointer (may be
+ * "" for error without a message) and NULL is returned.
+ * Returns an allocated string if a valid match was found.
+ * Returns NULL if no match was found. "usedlen" then still contains the
+ * number of characters to skip.
+ */
+ char_u *
+eval_vars(
+ char_u *src, /* pointer into commandline */
+ char_u *srcstart, /* beginning of valid memory for src */
+ int *usedlen, /* characters after src that are used */
+ linenr_T *lnump, /* line number for :e command, or NULL */
+ char **errormsg, /* pointer to error message */
+ int *escaped) /* return value has escaped white space (can
+ * be NULL) */
+{
+ int i;
+ char_u *s;
+ char_u *result;
+ char_u *resultbuf = NULL;
+ int resultlen;
+ buf_T *buf;
+ int valid = VALID_HEAD + VALID_PATH; /* assume valid result */
+ int spec_idx;
+#ifdef FEAT_MODIFY_FNAME
+ int tilde_file = FALSE;
+ int skip_mod = FALSE;
+#endif
+ char_u strbuf[30];
+
+ *errormsg = NULL;
+ if (escaped != NULL)
+ *escaped = FALSE;
+
+ /*
+ * Check if there is something to do.
+ */
+ spec_idx = find_cmdline_var(src, usedlen);
+ if (spec_idx < 0) /* no match */
+ {
+ *usedlen = 1;
+ return NULL;
+ }
+
+ /*
+ * Skip when preceded with a backslash "\%" and "\#".
+ * Note: In "\\%" the % is also not recognized!
+ */
+ if (src > srcstart && src[-1] == '\\')
+ {
+ *usedlen = 0;
+ STRMOVE(src - 1, src); /* remove backslash */
+ return NULL;
+ }
+
+ /*
+ * word or WORD under cursor
+ */
+ if (spec_idx == SPEC_CWORD || spec_idx == SPEC_CCWORD
+ || spec_idx == SPEC_CEXPR)
+ {
+ resultlen = find_ident_under_cursor(&result,
+ spec_idx == SPEC_CWORD ? (FIND_IDENT | FIND_STRING)
+ : spec_idx == SPEC_CEXPR ? (FIND_IDENT | FIND_STRING | FIND_EVAL)
+ : FIND_STRING);
+ if (resultlen == 0)
+ {
+ *errormsg = "";
+ return NULL;
+ }
+ }
+
+ /*
+ * '#': Alternate file name
+ * '%': Current file name
+ * File name under the cursor
+ * File name for autocommand
+ * and following modifiers
+ */
+ else
+ {
+ switch (spec_idx)
+ {
+ case SPEC_PERC: /* '%': current file */
+ if (curbuf->b_fname == NULL)
+ {
+ result = (char_u *)"";
+ valid = 0; /* Must have ":p:h" to be valid */
+ }
+ else
+ {
+ result = curbuf->b_fname;
+#ifdef FEAT_MODIFY_FNAME
+ tilde_file = STRCMP(result, "~") == 0;
+#endif
+ }
+ break;
+
+ case SPEC_HASH: /* '#' or "#99": alternate file */
+ if (src[1] == '#') /* "##": the argument list */
+ {
+ result = arg_all();
+ resultbuf = result;
+ *usedlen = 2;
+ if (escaped != NULL)
+ *escaped = TRUE;
+#ifdef FEAT_MODIFY_FNAME
+ skip_mod = TRUE;
+#endif
+ break;
+ }
+ s = src + 1;
+ if (*s == '<') /* "#<99" uses v:oldfiles */
+ ++s;
+ i = (int)getdigits(&s);
+ if (s == src + 2 && src[1] == '-')
+ /* just a minus sign, don't skip over it */
+ s--;
+ *usedlen = (int)(s - src); /* length of what we expand */
+
+ if (src[1] == '<' && i != 0)
+ {
+ if (*usedlen < 2)
+ {
+ /* Should we give an error message for #<text? */
+ *usedlen = 1;
+ return NULL;
+ }
+#ifdef FEAT_EVAL
+ result = list_find_str(get_vim_var_list(VV_OLDFILES),
+ (long)i);
+ if (result == NULL)
+ {
+ *errormsg = "";
+ return NULL;
+ }
+#else
+ *errormsg = _("E809: #< is not available without the +eval feature");
+ return NULL;
+#endif
+ }
+ else
+ {
+ if (i == 0 && src[1] == '<' && *usedlen > 1)
+ *usedlen = 1;
+ buf = buflist_findnr(i);
+ if (buf == NULL)
+ {
+ *errormsg = _("E194: No alternate file name to substitute for '#'");
+ return NULL;
+ }
+ if (lnump != NULL)
+ *lnump = ECMD_LAST;
+ if (buf->b_fname == NULL)
+ {
+ result = (char_u *)"";
+ valid = 0; /* Must have ":p:h" to be valid */
+ }
+ else
+ {
+ result = buf->b_fname;
+#ifdef FEAT_MODIFY_FNAME
+ tilde_file = STRCMP(result, "~") == 0;
+#endif
+ }
+ }
+ break;
+
+#ifdef FEAT_SEARCHPATH
+ case SPEC_CFILE: /* file name under cursor */
+ result = file_name_at_cursor(FNAME_MESS|FNAME_HYP, 1L, NULL);
+ if (result == NULL)
+ {
+ *errormsg = "";
+ return NULL;
+ }
+ resultbuf = result; /* remember allocated string */
+ break;
+#endif
+
+ case SPEC_AFILE: /* file name for autocommand */
+ result = autocmd_fname;
+ if (result != NULL && !autocmd_fname_full)
+ {
+ /* Still need to turn the fname into a full path. It is
+ * postponed to avoid a delay when <afile> is not used. */
+ autocmd_fname_full = TRUE;
+ result = FullName_save(autocmd_fname, FALSE);
+ vim_free(autocmd_fname);
+ autocmd_fname = result;
+ }
+ if (result == NULL)
+ {
+ *errormsg = _("E495: no autocommand file name to substitute for \"<afile>\"");
+ return NULL;
+ }
+ result = shorten_fname1(result);
+ break;
+
+ case SPEC_ABUF: /* buffer number for autocommand */
+ if (autocmd_bufnr <= 0)
+ {
+ *errormsg = _("E496: no autocommand buffer number to substitute for \"<abuf>\"");
+ return NULL;
+ }
+ sprintf((char *)strbuf, "%d", autocmd_bufnr);
+ result = strbuf;
+ break;
+
+ case SPEC_AMATCH: /* match name for autocommand */
+ result = autocmd_match;
+ if (result == NULL)
+ {
+ *errormsg = _("E497: no autocommand match name to substitute for \"<amatch>\"");
+ return NULL;
+ }
+ break;
+
+ case SPEC_SFILE: /* file name for ":so" command */
+ result = sourcing_name;
+ if (result == NULL)
+ {
+ *errormsg = _("E498: no :source file name to substitute for \"<sfile>\"");
+ return NULL;
+ }
+ break;
+
+ case SPEC_SLNUM: /* line in file for ":so" command */
+ if (sourcing_name == NULL || sourcing_lnum == 0)
+ {
+ *errormsg = _("E842: no line number to use for \"<slnum>\"");
+ return NULL;
+ }
+ sprintf((char *)strbuf, "%ld", (long)sourcing_lnum);
+ result = strbuf;
+ break;
+
+#ifdef FEAT_EVAL
+ case SPEC_SFLNUM: /* line in script file */
+ if (current_sctx.sc_lnum + sourcing_lnum == 0)
+ {
+ *errormsg = _("E961: no line number to use for \"<sflnum>\"");
+ return NULL;
+ }
+ sprintf((char *)strbuf, "%ld",
+ (long)(current_sctx.sc_lnum + sourcing_lnum));
+ result = strbuf;
+ break;
+#endif
+
+#ifdef FEAT_CLIENTSERVER
+ case SPEC_CLIENT: /* Source of last submitted input */
+ sprintf((char *)strbuf, PRINTF_HEX_LONG_U,
+ (long_u)clientWindow);
+ result = strbuf;
+ break;
+#endif
+
+ default:
+ result = (char_u *)""; /* avoid gcc warning */
+ break;
+ }
+
+ resultlen = (int)STRLEN(result); /* length of new string */
+ if (src[*usedlen] == '<') /* remove the file name extension */
+ {
+ ++*usedlen;
+ if ((s = vim_strrchr(result, '.')) != NULL && s >= gettail(result))
+ resultlen = (int)(s - result);
+ }
+#ifdef FEAT_MODIFY_FNAME
+ else if (!skip_mod)
+ {
+ valid |= modify_fname(src, tilde_file, usedlen, &result, &resultbuf,
+ &resultlen);
+ if (result == NULL)
+ {
+ *errormsg = "";
+ return NULL;
+ }
+ }
+#endif
+ }
+
+ if (resultlen == 0 || valid != VALID_HEAD + VALID_PATH)
+ {
+ if (valid != VALID_HEAD + VALID_PATH)
+ /* xgettext:no-c-format */
+ *errormsg = _("E499: Empty file name for '%' or '#', only works with \":p:h\"");
+ else
+ *errormsg = _("E500: Evaluates to an empty string");
+ result = NULL;
+ }
+ else
+ result = vim_strnsave(result, resultlen);
+ vim_free(resultbuf);
+ return result;
+}
+
+/*
+ * Concatenate all files in the argument list, separated by spaces, and return
+ * it in one allocated string.
+ * Spaces and backslashes in the file names are escaped with a backslash.
+ * Returns NULL when out of memory.
+ */
+ static char_u *
+arg_all(void)
+{
+ int len;
+ int idx;
+ char_u *retval = NULL;
+ char_u *p;
+
+ /*
+ * Do this loop two times:
+ * first time: compute the total length
+ * second time: concatenate the names
+ */
+ for (;;)
+ {
+ len = 0;
+ for (idx = 0; idx < ARGCOUNT; ++idx)
+ {
+ p = alist_name(&ARGLIST[idx]);
+ if (p != NULL)
+ {
+ if (len > 0)
+ {
+ /* insert a space in between names */
+ if (retval != NULL)
+ retval[len] = ' ';
+ ++len;
+ }
+ for ( ; *p != NUL; ++p)
+ {
+ if (*p == ' '
+#ifndef BACKSLASH_IN_FILENAME
+ || *p == '\\'
+#endif
+ || *p == '`')
+ {
+ /* insert a backslash */
+ if (retval != NULL)
+ retval[len] = '\\';
+ ++len;
+ }
+ if (retval != NULL)
+ retval[len] = *p;
+ ++len;
+ }
+ }
+ }
+
+ /* second time: break here */
+ if (retval != NULL)
+ {
+ retval[len] = NUL;
+ break;
+ }
+
+ /* allocate memory */
+ retval = alloc((unsigned)len + 1);
+ if (retval == NULL)
+ break;
+ }
+
+ return retval;
+}
+
+/*
+ * Expand the <sfile> string in "arg".
+ *
+ * Returns an allocated string, or NULL for any error.
+ */
+ char_u *
+expand_sfile(char_u *arg)
+{
+ char *errormsg;
+ int len;
+ char_u *result;
+ char_u *newres;
+ char_u *repl;
+ int srclen;
+ char_u *p;
+
+ result = vim_strsave(arg);
+ if (result == NULL)
+ return NULL;
+
+ for (p = result; *p; )
+ {
+ if (STRNCMP(p, "<sfile>", 7) != 0)
+ ++p;
+ else
+ {
+ /* replace "<sfile>" with the sourced file name, and do ":" stuff */
+ repl = eval_vars(p, result, &srclen, NULL, &errormsg, NULL);
+ if (errormsg != NULL)
+ {
+ if (*errormsg)
+ emsg(errormsg);
+ vim_free(result);
+ return NULL;
+ }
+ if (repl == NULL) /* no match (cannot happen) */
+ {
+ p += srclen;
+ continue;
+ }
+ len = (int)STRLEN(result) - srclen + (int)STRLEN(repl) + 1;
+ newres = alloc(len);
+ if (newres == NULL)
+ {
+ vim_free(repl);
+ vim_free(result);
+ return NULL;
+ }
+ mch_memmove(newres, result, (size_t)(p - result));
+ STRCPY(newres + (p - result), repl);
+ len = (int)STRLEN(newres);
+ STRCAT(newres, p + srclen);
+ vim_free(repl);
+ vim_free(result);
+ result = newres;
+ p = newres + len; /* continue after the match */
+ }
+ }
+
+ return result;
+}
+
+#ifdef FEAT_SESSION
+static int ses_winsizes(FILE *fd, int restore_size,
+ win_T *tab_firstwin);
+static int ses_win_rec(FILE *fd, frame_T *fr);
+static frame_T *ses_skipframe(frame_T *fr);
+static int ses_do_frame(frame_T *fr);
+static int ses_do_win(win_T *wp);
+static int ses_arglist(FILE *fd, char *cmd, garray_T *gap, int fullname, unsigned *flagp);
+static int ses_put_fname(FILE *fd, char_u *name, unsigned *flagp);
+static int ses_fname(FILE *fd, buf_T *buf, unsigned *flagp, int add_eol);
+
+/*
+ * Write openfile commands for the current buffers to an .exrc file.
+ * Return FAIL on error, OK otherwise.
+ */
+ static int
+makeopens(
+ FILE *fd,
+ char_u *dirnow) /* Current directory name */
+{
+ buf_T *buf;
+ int only_save_windows = TRUE;
+ int nr;
+ int restore_size = TRUE;
+ win_T *wp;
+ char_u *sname;
+ win_T *edited_win = NULL;
+ int tabnr;
+ int restore_stal = FALSE;
+ win_T *tab_firstwin;
+ frame_T *tab_topframe;
+ int cur_arg_idx = 0;
+ int next_arg_idx = 0;
+
+ if (ssop_flags & SSOP_BUFFERS)
+ only_save_windows = FALSE; /* Save ALL buffers */
+
+ /*
+ * Begin by setting the this_session variable, and then other
+ * sessionable variables.
+ */
+#ifdef FEAT_EVAL
+ if (put_line(fd, "let v:this_session=expand(\"<sfile>:p\")") == FAIL)
+ return FAIL;
+ if (ssop_flags & SSOP_GLOBALS)
+ if (store_session_globals(fd) == FAIL)
+ return FAIL;
+#endif
+
+ /*
+ * Close all windows and tabs but one.
+ */
+ if (put_line(fd, "silent only") == FAIL)
+ return FAIL;
+ if ((ssop_flags & SSOP_TABPAGES)
+ && put_line(fd, "silent tabonly") == FAIL)
+ return FAIL;
+
+ /*
+ * Now a :cd command to the session directory or the current directory
+ */
+ if (ssop_flags & SSOP_SESDIR)
+ {
+ if (put_line(fd, "exe \"cd \" . escape(expand(\"<sfile>:p:h\"), ' ')")
+ == FAIL)
+ return FAIL;
+ }
+ else if (ssop_flags & SSOP_CURDIR)
+ {
+ sname = home_replace_save(NULL, globaldir != NULL ? globaldir : dirnow);
+ if (sname == NULL
+ || fputs("cd ", fd) < 0
+ || ses_put_fname(fd, sname, &ssop_flags) == FAIL
+ || put_eol(fd) == FAIL)
+ {
+ vim_free(sname);
+ return FAIL;
+ }
+ vim_free(sname);
+ }
+
+ /*
+ * If there is an empty, unnamed buffer we will wipe it out later.
+ * Remember the buffer number.
+ */
+ if (put_line(fd, "if expand('%') == '' && !&modified && line('$') <= 1 && getline(1) == ''") == FAIL)
+ return FAIL;
+ if (put_line(fd, " let s:wipebuf = bufnr('%')") == FAIL)
+ return FAIL;
+ if (put_line(fd, "endif") == FAIL)
+ return FAIL;
+
+ /*
+ * Now save the current files, current buffer first.
+ */
+ if (put_line(fd, "set shortmess=aoO") == FAIL)
+ return FAIL;
+
+ /* the global argument list */
+ if (ses_arglist(fd, "argglobal", &global_alist.al_ga,
+ !(ssop_flags & SSOP_CURDIR), &ssop_flags) == FAIL)
+ return FAIL;
+
+ if (ssop_flags & SSOP_RESIZE)
+ {
+ /* Note: after the restore we still check it worked!*/
+ if (fprintf(fd, "set lines=%ld columns=%ld" , Rows, Columns) < 0
+ || put_eol(fd) == FAIL)
+ return FAIL;
+ }
+
+#ifdef FEAT_GUI
+ if (gui.in_use && (ssop_flags & SSOP_WINPOS))
+ {
+ int x, y;
+
+ if (gui_mch_get_winpos(&x, &y) == OK)
+ {
+ /* Note: after the restore we still check it worked!*/
+ if (fprintf(fd, "winpos %d %d", x, y) < 0 || put_eol(fd) == FAIL)
+ return FAIL;
+ }
+ }
+#endif
+
+ /*
+ * When there are two or more tabpages and 'showtabline' is 1 the tabline
+ * will be displayed when creating the next tab. That resizes the windows
+ * in the first tab, which may cause problems. Set 'showtabline' to 2
+ * temporarily to avoid that.
+ */
+ if (p_stal == 1 && first_tabpage->tp_next != NULL)
+ {
+ if (put_line(fd, "set stal=2") == FAIL)
+ return FAIL;
+ restore_stal = TRUE;
+ }
+
+ /*
+ * May repeat putting Windows for each tab, when "tabpages" is in
+ * 'sessionoptions'.
+ * Don't use goto_tabpage(), it may change directory and trigger
+ * autocommands.
+ */
+ tab_firstwin = firstwin; /* first window in tab page "tabnr" */
+ tab_topframe = topframe;
+ if ((ssop_flags & SSOP_TABPAGES))
+ {
+ tabpage_T *tp;
+
+ // Similar to ses_win_rec() below, populate the tab pages first so
+ // later local options won't be copied to the new tabs.
+ FOR_ALL_TABPAGES(tp)
+ if (tp->tp_next != NULL && put_line(fd, "tabnew") == FAIL)
+ return FAIL;
+ if (first_tabpage->tp_next != NULL && put_line(fd, "tabrewind") == FAIL)
+ return FAIL;
+ }
+ for (tabnr = 1; ; ++tabnr)
+ {
+ int need_tabnext = FALSE;
+ int cnr = 1;
+
+ if ((ssop_flags & SSOP_TABPAGES))
+ {
+ tabpage_T *tp = find_tabpage(tabnr);
+
+ if (tp == NULL)
+ break; /* done all tab pages */
+ if (tp == curtab)
+ {
+ tab_firstwin = firstwin;
+ tab_topframe = topframe;
+ }
+ else
+ {
+ tab_firstwin = tp->tp_firstwin;
+ tab_topframe = tp->tp_topframe;
+ }
+ if (tabnr > 1)
+ need_tabnext = TRUE;
+ }
+
+ /*
+ * Before creating the window layout, try loading one file. If this
+ * is aborted we don't end up with a number of useless windows.
+ * This may have side effects! (e.g., compressed or network file).
+ */
+ for (wp = tab_firstwin; wp != NULL; wp = wp->w_next)
+ {
+ if (ses_do_win(wp)
+ && wp->w_buffer->b_ffname != NULL
+ && !bt_help(wp->w_buffer)
+#ifdef FEAT_QUICKFIX
+ && !bt_nofile(wp->w_buffer)
+#endif
+ )
+ {
+ if (need_tabnext && put_line(fd, "tabnext") == FAIL)
+ return FAIL;
+ need_tabnext = FALSE;
+
+ if (fputs("edit ", fd) < 0
+ || ses_fname(fd, wp->w_buffer, &ssop_flags, TRUE)
+ == FAIL)
+ return FAIL;
+ if (!wp->w_arg_idx_invalid)
+ edited_win = wp;
+ break;
+ }
+ }
+
+ /* If no file got edited create an empty tab page. */
+ if (need_tabnext && put_line(fd, "tabnext") == FAIL)
+ return FAIL;
+
+ /*
+ * Save current window layout.
+ */
+ if (put_line(fd, "set splitbelow splitright") == FAIL)
+ return FAIL;
+ if (ses_win_rec(fd, tab_topframe) == FAIL)
+ return FAIL;
+ if (!p_sb && put_line(fd, "set nosplitbelow") == FAIL)
+ return FAIL;
+ if (!p_spr && put_line(fd, "set nosplitright") == FAIL)
+ return FAIL;
+
+ /*
+ * Check if window sizes can be restored (no windows omitted).
+ * Remember the window number of the current window after restoring.
+ */
+ nr = 0;
+ for (wp = tab_firstwin; wp != NULL; wp = W_NEXT(wp))
+ {
+ if (ses_do_win(wp))
+ ++nr;
+ else
+ restore_size = FALSE;
+ if (curwin == wp)
+ cnr = nr;
+ }
+
+ /* Go to the first window. */
+ if (put_line(fd, "wincmd t") == FAIL)
+ return FAIL;
+
+ /*
+ * If more than one window, see if sizes can be restored.
+ * First set 'winheight' and 'winwidth' to 1 to avoid the windows being
+ * resized when moving between windows.
+ * Do this before restoring the view, so that the topline and the
+ * cursor can be set. This is done again below.
+ * winminheight and winminwidth need to be set to avoid an error if the
+ * user has set winheight or winwidth.
+ */
+ if (put_line(fd, "set winminheight=0") == FAIL
+ || put_line(fd, "set winheight=1") == FAIL
+ || put_line(fd, "set winminwidth=0") == FAIL
+ || put_line(fd, "set winwidth=1") == FAIL)
+ return FAIL;
+ if (nr > 1 && ses_winsizes(fd, restore_size, tab_firstwin) == FAIL)
+ return FAIL;
+
+ /*
+ * Restore the view of the window (options, file, cursor, etc.).
+ */
+ for (wp = tab_firstwin; wp != NULL; wp = wp->w_next)
+ {
+ if (!ses_do_win(wp))
+ continue;
+ if (put_view(fd, wp, wp != edited_win, &ssop_flags,
+ cur_arg_idx) == FAIL)
+ return FAIL;
+ if (nr > 1 && put_line(fd, "wincmd w") == FAIL)
+ return FAIL;
+ next_arg_idx = wp->w_arg_idx;
+ }
+
+ /* The argument index in the first tab page is zero, need to set it in
+ * each window. For further tab pages it's the window where we do
+ * "tabedit". */
+ cur_arg_idx = next_arg_idx;
+
+ /*
+ * Restore cursor to the current window if it's not the first one.
+ */
+ if (cnr > 1 && (fprintf(fd, "%dwincmd w", cnr) < 0
+ || put_eol(fd) == FAIL))
+ return FAIL;
+
+ /*
+ * Restore window sizes again after jumping around in windows, because
+ * the current window has a minimum size while others may not.
+ */
+ if (nr > 1 && ses_winsizes(fd, restore_size, tab_firstwin) == FAIL)
+ return FAIL;
+
+ /* Don't continue in another tab page when doing only the current one
+ * or when at the last tab page. */
+ if (!(ssop_flags & SSOP_TABPAGES))
+ break;
+ }
+
+ if (ssop_flags & SSOP_TABPAGES)
+ {
+ if (fprintf(fd, "tabnext %d", tabpage_index(curtab)) < 0
+ || put_eol(fd) == FAIL)
+ return FAIL;
+ }
+ if (restore_stal && put_line(fd, "set stal=1") == FAIL)
+ return FAIL;
+
+ // Now put the remaining buffers into the buffer list.
+ // This is near the end, so that when 'hidden' is set we don't create extra
+ // buffers. If the buffer was already created with another command the
+ // ":badd" will have no effect.
+ FOR_ALL_BUFFERS(buf)
+ {
+ if (!(only_save_windows && buf->b_nwindows == 0)
+ && !(buf->b_help && !(ssop_flags & SSOP_HELP))
+#ifdef FEAT_TERMINAL
+ // Skip terminal buffers: finished ones are not useful, others
+ // will be resurrected and result in a new buffer.
+ && !bt_terminal(buf)
+#endif
+ && buf->b_fname != NULL
+ && buf->b_p_bl)
+ {
+ if (fprintf(fd, "badd +%ld ", buf->b_wininfo == NULL ? 1L
+ : buf->b_wininfo->wi_fpos.lnum) < 0
+ || ses_fname(fd, buf, &ssop_flags, TRUE) == FAIL)
+ return FAIL;
+ }
+ }
+
+ /*
+ * Wipe out an empty unnamed buffer we started in.
+ */
+ if (put_line(fd, "if exists('s:wipebuf') && len(win_findbuf(s:wipebuf)) == 0")
+ == FAIL)
+ return FAIL;
+ if (put_line(fd, " silent exe 'bwipe ' . s:wipebuf") == FAIL)
+ return FAIL;
+ if (put_line(fd, "endif") == FAIL)
+ return FAIL;
+ if (put_line(fd, "unlet! s:wipebuf") == FAIL)
+ return FAIL;
+
+ /* Re-apply 'winheight', 'winwidth' and 'shortmess'. */
+ if (fprintf(fd, "set winheight=%ld winwidth=%ld shortmess=%s",
+ p_wh, p_wiw, p_shm) < 0 || put_eol(fd) == FAIL)
+ return FAIL;
+ /* Re-apply 'winminheight' and 'winminwidth'. */
+ if (fprintf(fd, "set winminheight=%ld winminwidth=%ld",
+ p_wmh, p_wmw) < 0 || put_eol(fd) == FAIL)
+ return FAIL;
+
+ /*
+ * Lastly, execute the x.vim file if it exists.
+ */
+ if (put_line(fd, "let s:sx = expand(\"<sfile>:p:r\").\"x.vim\"") == FAIL
+ || put_line(fd, "if file_readable(s:sx)") == FAIL
+ || put_line(fd, " exe \"source \" . fnameescape(s:sx)") == FAIL
+ || put_line(fd, "endif") == FAIL)
+ return FAIL;
+
+ return OK;
+}
+
+ static int
+ses_winsizes(
+ FILE *fd,
+ int restore_size,
+ win_T *tab_firstwin)
+{
+ int n = 0;
+ win_T *wp;
+
+ if (restore_size && (ssop_flags & SSOP_WINSIZE))
+ {
+ for (wp = tab_firstwin; wp != NULL; wp = wp->w_next)
+ {
+ if (!ses_do_win(wp))
+ continue;
+ ++n;
+
+ /* restore height when not full height */
+ if (wp->w_height + wp->w_status_height < topframe->fr_height
+ && (fprintf(fd,
+ "exe '%dresize ' . ((&lines * %ld + %ld) / %ld)",
+ n, (long)wp->w_height, Rows / 2, Rows) < 0
+ || put_eol(fd) == FAIL))
+ return FAIL;
+
+ /* restore width when not full width */
+ if (wp->w_width < Columns && (fprintf(fd,
+ "exe 'vert %dresize ' . ((&columns * %ld + %ld) / %ld)",
+ n, (long)wp->w_width, Columns / 2, Columns) < 0
+ || put_eol(fd) == FAIL))
+ return FAIL;
+ }
+ }
+ else
+ {
+ /* Just equalise window sizes */
+ if (put_line(fd, "wincmd =") == FAIL)
+ return FAIL;
+ }
+ return OK;
+}
+
+/*
+ * Write commands to "fd" to recursively create windows for frame "fr",
+ * horizontally and vertically split.
+ * After the commands the last window in the frame is the current window.
+ * Returns FAIL when writing the commands to "fd" fails.
+ */
+ static int
+ses_win_rec(FILE *fd, frame_T *fr)
+{
+ frame_T *frc;
+ int count = 0;
+
+ if (fr->fr_layout != FR_LEAF)
+ {
+ /* Find first frame that's not skipped and then create a window for
+ * each following one (first frame is already there). */
+ frc = ses_skipframe(fr->fr_child);
+ if (frc != NULL)
+ while ((frc = ses_skipframe(frc->fr_next)) != NULL)
+ {
+ /* Make window as big as possible so that we have lots of room
+ * to split. */
+ if (put_line(fd, "wincmd _ | wincmd |") == FAIL
+ || put_line(fd, fr->fr_layout == FR_COL
+ ? "split" : "vsplit") == FAIL)
+ return FAIL;
+ ++count;
+ }
+
+ /* Go back to the first window. */
+ if (count > 0 && (fprintf(fd, fr->fr_layout == FR_COL
+ ? "%dwincmd k" : "%dwincmd h", count) < 0
+ || put_eol(fd) == FAIL))
+ return FAIL;
+
+ /* Recursively create frames/windows in each window of this column or
+ * row. */
+ frc = ses_skipframe(fr->fr_child);
+ while (frc != NULL)
+ {
+ ses_win_rec(fd, frc);
+ frc = ses_skipframe(frc->fr_next);
+ /* Go to next window. */
+ if (frc != NULL && put_line(fd, "wincmd w") == FAIL)
+ return FAIL;
+ }
+ }
+ return OK;
+}
+
+/*
+ * Skip frames that don't contain windows we want to save in the Session.
+ * Returns NULL when there none.
+ */
+ static frame_T *
+ses_skipframe(frame_T *fr)
+{
+ frame_T *frc;
+
+ FOR_ALL_FRAMES(frc, fr)
+ if (ses_do_frame(frc))
+ break;
+ return frc;
+}
+
+/*
+ * Return TRUE if frame "fr" has a window somewhere that we want to save in
+ * the Session.
+ */
+ static int
+ses_do_frame(frame_T *fr)
+{
+ frame_T *frc;
+
+ if (fr->fr_layout == FR_LEAF)
+ return ses_do_win(fr->fr_win);
+ FOR_ALL_FRAMES(frc, fr->fr_child)
+ if (ses_do_frame(frc))
+ return TRUE;
+ return FALSE;
+}
+
+/*
+ * Return non-zero if window "wp" is to be stored in the Session.
+ */
+ static int
+ses_do_win(win_T *wp)
+{
+#ifdef FEAT_TERMINAL
+ if (bt_terminal(wp->w_buffer))
+ return !term_is_finished(wp->w_buffer)
+ && (ssop_flags & SSOP_TERMINAL)
+ && term_should_restore(wp->w_buffer);
+#endif
+ if (wp->w_buffer->b_fname == NULL
+#ifdef FEAT_QUICKFIX
+ /* When 'buftype' is "nofile" can't restore the window contents. */
+ || bt_nofile(wp->w_buffer)
+#endif
+ )
+ return (ssop_flags & SSOP_BLANK);
+ if (bt_help(wp->w_buffer))
+ return (ssop_flags & SSOP_HELP);
+ return TRUE;
+}
+
+ static int
+put_view_curpos(FILE *fd, win_T *wp, char *spaces)
+{
+ int r;
+
+ if (wp->w_curswant == MAXCOL)
+ r = fprintf(fd, "%snormal! $", spaces);
+ else
+ r = fprintf(fd, "%snormal! 0%d|", spaces, wp->w_virtcol + 1);
+ return r < 0 || put_eol(fd) == FAIL ? FALSE : OK;
+}
+
+/*
+ * Write commands to "fd" to restore the view of a window.
+ * Caller must make sure 'scrolloff' is zero.
+ */
+ static int
+put_view(
+ FILE *fd,
+ win_T *wp,
+ int add_edit, /* add ":edit" command to view */
+ unsigned *flagp, /* vop_flags or ssop_flags */
+ int current_arg_idx) /* current argument index of the window, use
+ * -1 if unknown */
+{
+ win_T *save_curwin;
+ int f;
+ int do_cursor;
+ int did_next = FALSE;
+
+ /* Always restore cursor position for ":mksession". For ":mkview" only
+ * when 'viewoptions' contains "cursor". */
+ do_cursor = (flagp == &ssop_flags || *flagp & SSOP_CURSOR);
+
+ /*
+ * Local argument list.
+ */
+ if (wp->w_alist == &global_alist)
+ {
+ if (put_line(fd, "argglobal") == FAIL)
+ return FAIL;
+ }
+ else
+ {
+ if (ses_arglist(fd, "arglocal", &wp->w_alist->al_ga,
+ flagp == &vop_flags
+ || !(*flagp & SSOP_CURDIR)
+ || wp->w_localdir != NULL, flagp) == FAIL)
+ return FAIL;
+ }
+
+ /* Only when part of a session: restore the argument index. Some
+ * arguments may have been deleted, check if the index is valid. */
+ if (wp->w_arg_idx != current_arg_idx && wp->w_arg_idx < WARGCOUNT(wp)
+ && flagp == &ssop_flags)
+ {
+ if (fprintf(fd, "%ldargu", (long)wp->w_arg_idx + 1) < 0
+ || put_eol(fd) == FAIL)
+ return FAIL;
+ did_next = TRUE;
+ }
+
+ /* Edit the file. Skip this when ":next" already did it. */
+ if (add_edit && (!did_next || wp->w_arg_idx_invalid))
+ {
+# ifdef FEAT_TERMINAL
+ if (bt_terminal(wp->w_buffer))
+ {
+ if (term_write_session(fd, wp) == FAIL)
+ return FAIL;
+ }
+ else
+# endif
+ /*
+ * Load the file.
+ */
+ if (wp->w_buffer->b_ffname != NULL
+# ifdef FEAT_QUICKFIX
+ && !bt_nofile(wp->w_buffer)
+# endif
+ )
+ {
+ /*
+ * Editing a file in this buffer: use ":edit file".
+ * This may have side effects! (e.g., compressed or network file).
+ *
+ * Note, if a buffer for that file already exists, use :badd to
+ * edit that buffer, to not lose folding information (:edit resets
+ * folds in other buffers)
+ */
+ if (fputs("if bufexists(\"", fd) < 0
+ || ses_fname(fd, wp->w_buffer, flagp, FALSE) == FAIL
+ || fputs("\") | buffer ", fd) < 0
+ || ses_fname(fd, wp->w_buffer, flagp, FALSE) == FAIL
+ || fputs(" | else | edit ", fd) < 0
+ || ses_fname(fd, wp->w_buffer, flagp, FALSE) == FAIL
+ || fputs(" | endif", fd) < 0
+ || put_eol(fd) == FAIL)
+ return FAIL;
+ }
+ else
+ {
+ /* No file in this buffer, just make it empty. */
+ if (put_line(fd, "enew") == FAIL)
+ return FAIL;
+#ifdef FEAT_QUICKFIX
+ if (wp->w_buffer->b_ffname != NULL)
+ {
+ /* The buffer does have a name, but it's not a file name. */
+ if (fputs("file ", fd) < 0
+ || ses_fname(fd, wp->w_buffer, flagp, TRUE) == FAIL)
+ return FAIL;
+ }
+#endif
+ do_cursor = FALSE;
+ }
+ }
+
+ /*
+ * Local mappings and abbreviations.
+ */
+ if ((*flagp & (SSOP_OPTIONS | SSOP_LOCALOPTIONS))
+ && makemap(fd, wp->w_buffer) == FAIL)
+ return FAIL;
+
+ /*
+ * Local options. Need to go to the window temporarily.
+ * Store only local values when using ":mkview" and when ":mksession" is
+ * used and 'sessionoptions' doesn't include "options".
+ * Some folding options are always stored when "folds" is included,
+ * otherwise the folds would not be restored correctly.
+ */
+ save_curwin = curwin;
+ curwin = wp;
+ curbuf = curwin->w_buffer;
+ if (*flagp & (SSOP_OPTIONS | SSOP_LOCALOPTIONS))
+ f = makeset(fd, OPT_LOCAL,
+ flagp == &vop_flags || !(*flagp & SSOP_OPTIONS));
+#ifdef FEAT_FOLDING
+ else if (*flagp & SSOP_FOLDS)
+ f = makefoldset(fd);
+#endif
+ else
+ f = OK;
+ curwin = save_curwin;
+ curbuf = curwin->w_buffer;
+ if (f == FAIL)
+ return FAIL;
+
+#ifdef FEAT_FOLDING
+ /*
+ * Save Folds when 'buftype' is empty and for help files.
+ */
+ if ((*flagp & SSOP_FOLDS)
+ && wp->w_buffer->b_ffname != NULL
+ && (bt_normal(wp->w_buffer) || bt_help(wp->w_buffer)))
+ {
+ if (put_folds(fd, wp) == FAIL)
+ return FAIL;
+ }
+#endif
+
+ /*
+ * Set the cursor after creating folds, since that moves the cursor.
+ */
+ if (do_cursor)
+ {
+
+ /* Restore the cursor line in the file and relatively in the
+ * window. Don't use "G", it changes the jumplist. */
+ if (fprintf(fd, "let s:l = %ld - ((%ld * winheight(0) + %ld) / %ld)",
+ (long)wp->w_cursor.lnum,
+ (long)(wp->w_cursor.lnum - wp->w_topline),
+ (long)wp->w_height / 2, (long)wp->w_height) < 0
+ || put_eol(fd) == FAIL
+ || put_line(fd, "if s:l < 1 | let s:l = 1 | endif") == FAIL
+ || put_line(fd, "exe s:l") == FAIL
+ || put_line(fd, "normal! zt") == FAIL
+ || fprintf(fd, "%ld", (long)wp->w_cursor.lnum) < 0
+ || put_eol(fd) == FAIL)
+ return FAIL;
+ /* Restore the cursor column and left offset when not wrapping. */
+ if (wp->w_cursor.col == 0)
+ {
+ if (put_line(fd, "normal! 0") == FAIL)
+ return FAIL;
+ }
+ else
+ {
+ if (!wp->w_p_wrap && wp->w_leftcol > 0 && wp->w_width > 0)
+ {
+ if (fprintf(fd,
+ "let s:c = %ld - ((%ld * winwidth(0) + %ld) / %ld)",
+ (long)wp->w_virtcol + 1,
+ (long)(wp->w_virtcol - wp->w_leftcol),
+ (long)wp->w_width / 2, (long)wp->w_width) < 0
+ || put_eol(fd) == FAIL
+ || put_line(fd, "if s:c > 0") == FAIL
+ || fprintf(fd,
+ " exe 'normal! ' . s:c . '|zs' . %ld . '|'",
+ (long)wp->w_virtcol + 1) < 0
+ || put_eol(fd) == FAIL
+ || put_line(fd, "else") == FAIL
+ || put_view_curpos(fd, wp, " ") == FAIL
+ || put_line(fd, "endif") == FAIL)
+ return FAIL;
+ }
+ else if (put_view_curpos(fd, wp, "") == FAIL)
+ return FAIL;
+ }
+ }
+
+ /*
+ * Local directory, if the current flag is not view options or the "curdir"
+ * option is included.
+ */
+ if (wp->w_localdir != NULL
+ && (flagp != &vop_flags || (*flagp & SSOP_CURDIR)))
+ {
+ if (fputs("lcd ", fd) < 0
+ || ses_put_fname(fd, wp->w_localdir, flagp) == FAIL
+ || put_eol(fd) == FAIL)
+ return FAIL;
+ did_lcd = TRUE;
+ }
+
+ return OK;
+}
+
+/*
+ * Write an argument list to the session file.
+ * Returns FAIL if writing fails.
+ */
+ static int
+ses_arglist(
+ FILE *fd,
+ char *cmd,
+ garray_T *gap,
+ int fullname, /* TRUE: use full path name */
+ unsigned *flagp)
+{
+ int i;
+ char_u *buf = NULL;
+ char_u *s;
+
+ if (fputs(cmd, fd) < 0 || put_eol(fd) == FAIL)
+ return FAIL;
+ if (put_line(fd, "%argdel") == FAIL)
+ return FAIL;
+ for (i = 0; i < gap->ga_len; ++i)
+ {
+ /* NULL file names are skipped (only happens when out of memory). */
+ s = alist_name(&((aentry_T *)gap->ga_data)[i]);
+ if (s != NULL)
+ {
+ if (fullname)
+ {
+ buf = alloc(MAXPATHL);
+ if (buf != NULL)
+ {
+ (void)vim_FullName(s, buf, MAXPATHL, FALSE);
+ s = buf;
+ }
+ }
+ if (fputs("$argadd ", fd) < 0
+ || ses_put_fname(fd, s, flagp) == FAIL
+ || put_eol(fd) == FAIL)
+ {
+ vim_free(buf);
+ return FAIL;
+ }
+ vim_free(buf);
+ }
+ }
+ return OK;
+}
+
+/*
+ * Write a buffer name to the session file.
+ * Also ends the line, if "add_eol" is TRUE.
+ * Returns FAIL if writing fails.
+ */
+ static int
+ses_fname(FILE *fd, buf_T *buf, unsigned *flagp, int add_eol)
+{
+ char_u *name;
+
+ /* Use the short file name if the current directory is known at the time
+ * the session file will be sourced.
+ * Don't do this for ":mkview", we don't know the current directory.
+ * Don't do this after ":lcd", we don't keep track of what the current
+ * directory is. */
+ if (buf->b_sfname != NULL
+ && flagp == &ssop_flags
+ && (ssop_flags & (SSOP_CURDIR | SSOP_SESDIR))
+#ifdef FEAT_AUTOCHDIR
+ && !p_acd
+#endif
+ && !did_lcd)
+ name = buf->b_sfname;
+ else
+ name = buf->b_ffname;
+ if (ses_put_fname(fd, name, flagp) == FAIL
+ || (add_eol && put_eol(fd) == FAIL))
+ return FAIL;
+ return OK;
+}
+
+/*
+ * Write a file name to the session file.
+ * Takes care of the "slash" option in 'sessionoptions' and escapes special
+ * characters.
+ * Returns FAIL if writing fails or out of memory.
+ */
+ static int
+ses_put_fname(FILE *fd, char_u *name, unsigned *flagp)
+{
+ char_u *sname;
+ char_u *p;
+ int retval = OK;
+
+ sname = home_replace_save(NULL, name);
+ if (sname == NULL)
+ return FAIL;
+
+ if (*flagp & SSOP_SLASH)
+ {
+ /* change all backslashes to forward slashes */
+ for (p = sname; *p != NUL; MB_PTR_ADV(p))
+ if (*p == '\\')
+ *p = '/';
+ }
+
+ /* escape special characters */
+ p = vim_strsave_fnameescape(sname, FALSE);
+ vim_free(sname);
+ if (p == NULL)
+ return FAIL;
+
+ /* write the result */
+ if (fputs((char *)p, fd) < 0)
+ retval = FAIL;
+
+ vim_free(p);
+ return retval;
+}
+
+/*
+ * ":loadview [nr]"
+ */
+ static void
+ex_loadview(exarg_T *eap)
+{
+ char_u *fname;
+
+ fname = get_view_file(*eap->arg);
+ if (fname != NULL)
+ {
+ do_source(fname, FALSE, DOSO_NONE);
+ vim_free(fname);
+ }
+}
+
+/*
+ * Get the name of the view file for the current buffer.
+ */
+ static char_u *
+get_view_file(int c)
+{
+ int len = 0;
+ char_u *p, *s;
+ char_u *retval;
+ char_u *sname;
+
+ if (curbuf->b_ffname == NULL)
+ {
+ emsg(_(e_noname));
+ return NULL;
+ }
+ sname = home_replace_save(NULL, curbuf->b_ffname);
+ if (sname == NULL)
+ return NULL;
+
+ /*
+ * We want a file name without separators, because we're not going to make
+ * a directory.
+ * "normal" path separator -> "=+"
+ * "=" -> "=="
+ * ":" path separator -> "=-"
+ */
+ for (p = sname; *p; ++p)
+ if (*p == '=' || vim_ispathsep(*p))
+ ++len;
+ retval = alloc((unsigned)(STRLEN(sname) + len + STRLEN(p_vdir) + 9));
+ if (retval != NULL)
+ {
+ STRCPY(retval, p_vdir);
+ add_pathsep(retval);
+ s = retval + STRLEN(retval);
+ for (p = sname; *p; ++p)
+ {
+ if (*p == '=')
+ {
+ *s++ = '=';
+ *s++ = '=';
+ }
+ else if (vim_ispathsep(*p))
+ {
+ *s++ = '=';
+#if defined(BACKSLASH_IN_FILENAME) || defined(AMIGA) || defined(VMS)
+ if (*p == ':')
+ *s++ = '-';
+ else
+#endif
+ *s++ = '+';
+ }
+ else
+ *s++ = *p;
+ }
+ *s++ = '=';
+ *s++ = c;
+ STRCPY(s, ".vim");
+ }
+
+ vim_free(sname);
+ return retval;
+}
+
+#endif /* FEAT_SESSION */
+
+/*
+ * Write end-of-line character(s) for ":mkexrc", ":mkvimrc" and ":mksession".
+ * Return FAIL for a write error.
+ */
+ int
+put_eol(FILE *fd)
+{
+ if (
+#ifdef USE_CRNL
+ (
+# ifdef MKSESSION_NL
+ !mksession_nl &&
+# endif
+ (putc('\r', fd) < 0)) ||
+#endif
+ (putc('\n', fd) < 0))
+ return FAIL;
+ return OK;
+}
+
+/*
+ * Write a line to "fd".
+ * Return FAIL for a write error.
+ */
+ int
+put_line(FILE *fd, char *s)
+{
+ if (fputs(s, fd) < 0 || put_eol(fd) == FAIL)
+ return FAIL;
+ return OK;
+}
+
+#ifdef FEAT_VIMINFO
+/*
+ * ":rviminfo" and ":wviminfo".
+ */
+ static void
+ex_viminfo(
+ exarg_T *eap)
+{
+ char_u *save_viminfo;
+
+ save_viminfo = p_viminfo;
+ if (*p_viminfo == NUL)
+ p_viminfo = (char_u *)"'100";
+ if (eap->cmdidx == CMD_rviminfo)
+ {
+ if (read_viminfo(eap->arg, VIF_WANT_INFO | VIF_WANT_MARKS
+ | (eap->forceit ? VIF_FORCEIT : 0)) == FAIL)
+ emsg(_("E195: Cannot open viminfo file for reading"));
+ }
+ else
+ write_viminfo(eap->arg, eap->forceit);
+ p_viminfo = save_viminfo;
+}
+#endif
+
+#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
+/*
+ * Make a dialog message in "buff[DIALOG_MSG_SIZE]".
+ * "format" must contain "%s".
+ */
+ void
+dialog_msg(char_u *buff, char *format, char_u *fname)
+{
+ if (fname == NULL)
+ fname = (char_u *)_("Untitled");
+ vim_snprintf((char *)buff, DIALOG_MSG_SIZE, format, fname);
+}
+#endif
+
+/*
+ * ":behave {mswin,xterm}"
+ */
+ static void
+ex_behave(exarg_T *eap)
+{
+ if (STRCMP(eap->arg, "mswin") == 0)
+ {
+ set_option_value((char_u *)"selection", 0L, (char_u *)"exclusive", 0);
+ set_option_value((char_u *)"selectmode", 0L, (char_u *)"mouse,key", 0);
+ set_option_value((char_u *)"mousemodel", 0L, (char_u *)"popup", 0);
+ set_option_value((char_u *)"keymodel", 0L,
+ (char_u *)"startsel,stopsel", 0);
+ }
+ else if (STRCMP(eap->arg, "xterm") == 0)
+ {
+ set_option_value((char_u *)"selection", 0L, (char_u *)"inclusive", 0);
+ set_option_value((char_u *)"selectmode", 0L, (char_u *)"", 0);
+ set_option_value((char_u *)"mousemodel", 0L, (char_u *)"extend", 0);
+ set_option_value((char_u *)"keymodel", 0L, (char_u *)"", 0);
+ }
+ else
+ semsg(_(e_invarg2), eap->arg);
+}
+
+#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
+/*
+ * Function given to ExpandGeneric() to obtain the possible arguments of the
+ * ":behave {mswin,xterm}" command.
+ */
+ char_u *
+get_behave_arg(expand_T *xp UNUSED, int idx)
+{
+ if (idx == 0)
+ return (char_u *)"mswin";
+ if (idx == 1)
+ return (char_u *)"xterm";
+ return NULL;
+}
+
+/*
+ * Function given to ExpandGeneric() to obtain the possible arguments of the
+ * ":messages {clear}" command.
+ */
+ char_u *
+get_messages_arg(expand_T *xp UNUSED, int idx)
+{
+ if (idx == 0)
+ return (char_u *)"clear";
+ return NULL;
+}
+#endif
+
+#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
+ char_u *
+get_mapclear_arg(expand_T *xp UNUSED, int idx)
+{
+ if (idx == 0)
+ return (char_u *)"<buffer>";
+ return NULL;
+}
+#endif
+
+static int filetype_detect = FALSE;
+static int filetype_plugin = FALSE;
+static int filetype_indent = FALSE;
+
+/*
+ * ":filetype [plugin] [indent] {on,off,detect}"
+ * on: Load the filetype.vim file to install autocommands for file types.
+ * off: Load the ftoff.vim file to remove all autocommands for file types.
+ * plugin on: load filetype.vim and ftplugin.vim
+ * plugin off: load ftplugof.vim
+ * indent on: load filetype.vim and indent.vim
+ * indent off: load indoff.vim
+ */
+ static void
+ex_filetype(exarg_T *eap)
+{
+ char_u *arg = eap->arg;
+ int plugin = FALSE;
+ int indent = FALSE;
+
+ if (*eap->arg == NUL)
+ {
+ /* Print current status. */
+ smsg("filetype detection:%s plugin:%s indent:%s",
+ filetype_detect ? "ON" : "OFF",
+ filetype_plugin ? (filetype_detect ? "ON" : "(on)") : "OFF",
+ filetype_indent ? (filetype_detect ? "ON" : "(on)") : "OFF");
+ return;
+ }
+
+ /* Accept "plugin" and "indent" in any order. */
+ for (;;)
+ {
+ if (STRNCMP(arg, "plugin", 6) == 0)
+ {
+ plugin = TRUE;
+ arg = skipwhite(arg + 6);
+ continue;
+ }
+ if (STRNCMP(arg, "indent", 6) == 0)
+ {
+ indent = TRUE;
+ arg = skipwhite(arg + 6);
+ continue;
+ }
+ break;
+ }
+ if (STRCMP(arg, "on") == 0 || STRCMP(arg, "detect") == 0)
+ {
+ if (*arg == 'o' || !filetype_detect)
+ {
+ source_runtime((char_u *)FILETYPE_FILE, DIP_ALL);
+ filetype_detect = TRUE;
+ if (plugin)
+ {
+ source_runtime((char_u *)FTPLUGIN_FILE, DIP_ALL);
+ filetype_plugin = TRUE;
+ }
+ if (indent)
+ {
+ source_runtime((char_u *)INDENT_FILE, DIP_ALL);
+ filetype_indent = TRUE;
+ }
+ }
+ if (*arg == 'd')
+ {
+ (void)do_doautocmd((char_u *)"filetypedetect BufRead", TRUE, NULL);
+ do_modelines(0);
+ }
+ }
+ else if (STRCMP(arg, "off") == 0)
+ {
+ if (plugin || indent)
+ {
+ if (plugin)
+ {
+ source_runtime((char_u *)FTPLUGOF_FILE, DIP_ALL);
+ filetype_plugin = FALSE;
+ }
+ if (indent)
+ {
+ source_runtime((char_u *)INDOFF_FILE, DIP_ALL);
+ filetype_indent = FALSE;
+ }
+ }
+ else
+ {
+ source_runtime((char_u *)FTOFF_FILE, DIP_ALL);
+ filetype_detect = FALSE;
+ }
+ }
+ else
+ semsg(_(e_invarg2), arg);
+}
+
+/*
+ * ":setfiletype [FALLBACK] {name}"
+ */
+ static void
+ex_setfiletype(exarg_T *eap)
+{
+ if (!did_filetype)
+ {
+ char_u *arg = eap->arg;
+
+ if (STRNCMP(arg, "FALLBACK ", 9) == 0)
+ arg += 9;
+
+ set_option_value((char_u *)"filetype", 0L, arg, OPT_LOCAL);
+ if (arg != eap->arg)
+ did_filetype = FALSE;
+ }
+}
+
+ static void
+ex_digraphs(exarg_T *eap UNUSED)
+{
+#ifdef FEAT_DIGRAPHS
+ if (*eap->arg != NUL)
+ putdigraph(eap->arg);
+ else
+ listdigraphs(eap->forceit);
+#else
+ emsg(_("E196: No digraphs in this version"));
+#endif
+}
+
+ static void
+ex_set(exarg_T *eap)
+{
+ int flags = 0;
+
+ if (eap->cmdidx == CMD_setlocal)
+ flags = OPT_LOCAL;
+ else if (eap->cmdidx == CMD_setglobal)
+ flags = OPT_GLOBAL;
+#if defined(FEAT_EVAL) && defined(FEAT_BROWSE)
+ if (cmdmod.browse && flags == 0)
+ ex_options(eap);
+ else
+#endif
+ (void)do_set(eap->arg, flags);
+}
+
+#if defined(FEAT_SEARCH_EXTRA) || defined(PROTO)
+ void
+set_no_hlsearch(int flag)
+{
+ no_hlsearch = flag;
+# ifdef FEAT_EVAL
+ set_vim_var_nr(VV_HLSEARCH, !no_hlsearch && p_hls);
+# endif
+}
+
+/*
+ * ":nohlsearch"
+ */
+ static void
+ex_nohlsearch(exarg_T *eap UNUSED)
+{
+ set_no_hlsearch(TRUE);
+ redraw_all_later(SOME_VALID);
+}
+
+/*
+ * ":[N]match {group} {pattern}"
+ * Sets nextcmd to the start of the next command, if any. Also called when
+ * skipping commands to find the next command.
+ */
+ static void
+ex_match(exarg_T *eap)
+{
+ char_u *p;
+ char_u *g = NULL;
+ char_u *end;
+ int c;
+ int id;
+
+ if (eap->line2 <= 3)
+ id = eap->line2;
+ else
+ {
+ emsg(_(e_invcmd));
+ return;
+ }
+
+ /* First clear any old pattern. */
+ if (!eap->skip)
+ match_delete(curwin, id, FALSE);
+
+ if (ends_excmd(*eap->arg))
+ end = eap->arg;
+ else if ((STRNICMP(eap->arg, "none", 4) == 0
+ && (VIM_ISWHITE(eap->arg[4]) || ends_excmd(eap->arg[4]))))
+ end = eap->arg + 4;
+ else
+ {
+ p = skiptowhite(eap->arg);
+ if (!eap->skip)
+ g = vim_strnsave(eap->arg, (int)(p - eap->arg));
+ p = skipwhite(p);
+ if (*p == NUL)
+ {
+ /* There must be two arguments. */
+ vim_free(g);
+ semsg(_(e_invarg2), eap->arg);
+ return;
+ }
+ end = skip_regexp(p + 1, *p, TRUE, NULL);
+ if (!eap->skip)
+ {
+ if (*end != NUL && !ends_excmd(*skipwhite(end + 1)))
+ {
+ vim_free(g);
+ eap->errmsg = e_trailing;
+ return;
+ }
+ if (*end != *p)
+ {
+ vim_free(g);
+ semsg(_(e_invarg2), p);
+ return;
+ }
+
+ c = *end;
+ *end = NUL;
+ match_add(curwin, g, p + 1, 10, id, NULL, NULL);
+ vim_free(g);
+ *end = c;
+ }
+ }
+ eap->nextcmd = find_nextcmd(end);
+}
+#endif
+
+#ifdef FEAT_CRYPT
+/*
+ * ":X": Get crypt key
+ */
+ static void
+ex_X(exarg_T *eap UNUSED)
+{
+ crypt_check_current_method();
+ (void)crypt_get_key(TRUE, TRUE);
+}
+#endif
+
+#ifdef FEAT_FOLDING
+ static void
+ex_fold(exarg_T *eap)
+{
+ if (foldManualAllowed(TRUE))
+ foldCreate(eap->line1, eap->line2);
+}
+
+ static void
+ex_foldopen(exarg_T *eap)
+{
+ opFoldRange(eap->line1, eap->line2, eap->cmdidx == CMD_foldopen,
+ eap->forceit, FALSE);
+}
+
+ static void
+ex_folddo(exarg_T *eap)
+{
+ linenr_T lnum;
+
+#ifdef FEAT_CLIPBOARD
+ start_global_changes();
+#endif
+
+ /* First set the marks for all lines closed/open. */
+ for (lnum = eap->line1; lnum <= eap->line2; ++lnum)
+ if (hasFolding(lnum, NULL, NULL) == (eap->cmdidx == CMD_folddoclosed))
+ ml_setmarked(lnum);
+
+ /* Execute the command on the marked lines. */
+ global_exe(eap->arg);
+ ml_clearmarked(); /* clear rest of the marks */
+#ifdef FEAT_CLIPBOARD
+ end_global_changes();
+#endif
+}
+#endif
+
+#ifdef FEAT_QUICKFIX
+/*
+ * Returns TRUE if the supplied Ex cmdidx is for a location list command
+ * instead of a quickfix command.
+ */
+ int
+is_loclist_cmd(int cmdidx)
+{
+ if (cmdidx < 0 || cmdidx >= CMD_SIZE)
+ return FALSE;
+ return cmdnames[cmdidx].cmd_name[0] == 'l';
+}
+#endif
+
+# if defined(FEAT_TIMERS) || defined(PROTO)
+ int
+get_pressedreturn(void)
+{
+ return ex_pressedreturn;
+}
+
+ void
+set_pressedreturn(int val)
+{
+ ex_pressedreturn = val;
+}
+#endif
diff --git a/src/ex_eval.c b/src/ex_eval.c
new file mode 100644
index 0000000..63bca67
--- /dev/null
+++ b/src/ex_eval.c
@@ -0,0 +1,2294 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * ex_eval.c: functions for Ex command line for the +eval feature.
+ */
+
+#include "vim.h"
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+
+static int throw_exception(void *, except_type_T, char_u *);
+static char *get_end_emsg(struct condstack *cstack);
+
+/*
+ * Exception handling terms:
+ *
+ * :try ":try" command \
+ * ... try block |
+ * :catch RE ":catch" command |
+ * ... catch clause |- try conditional
+ * :finally ":finally" command |
+ * ... finally clause |
+ * :endtry ":endtry" command /
+ *
+ * The try conditional may have any number of catch clauses and at most one
+ * finally clause. A ":throw" command can be inside the try block, a catch
+ * clause, the finally clause, or in a function called or script sourced from
+ * there or even outside the try conditional. Try conditionals may be nested.
+ */
+
+/*
+ * Configuration whether an exception is thrown on error or interrupt. When
+ * the preprocessor macros below evaluate to FALSE, an error (did_emsg) or
+ * interrupt (got_int) under an active try conditional terminates the script
+ * after the non-active finally clauses of all active try conditionals have been
+ * executed. Otherwise, errors and/or interrupts are converted into catchable
+ * exceptions (did_throw additionally set), which terminate the script only if
+ * not caught. For user exceptions, only did_throw is set. (Note: got_int can
+ * be set asynchronously afterwards by a SIGINT, so did_throw && got_int is not
+ * a reliant test that the exception currently being thrown is an interrupt
+ * exception. Similarly, did_emsg can be set afterwards on an error in an
+ * (unskipped) conditional command inside an inactive conditional, so did_throw
+ * && did_emsg is not a reliant test that the exception currently being thrown
+ * is an error exception.) - The macros can be defined as expressions checking
+ * for a variable that is allowed to be changed during execution of a script.
+ */
+#if 0
+/* Expressions used for testing during the development phase. */
+# define THROW_ON_ERROR (!eval_to_number("$VIMNOERRTHROW"))
+# define THROW_ON_INTERRUPT (!eval_to_number("$VIMNOINTTHROW"))
+# define THROW_TEST
+#else
+/* Values used for the Vim release. */
+# define THROW_ON_ERROR TRUE
+# define THROW_ON_ERROR_TRUE
+# define THROW_ON_INTERRUPT TRUE
+# define THROW_ON_INTERRUPT_TRUE
+#endif
+
+/*
+ * When several errors appear in a row, setting "force_abort" is delayed until
+ * the failing command returned. "cause_abort" is set to TRUE meanwhile, in
+ * order to indicate that situation. This is useful when "force_abort" was set
+ * during execution of a function call from an expression: the aborting of the
+ * expression evaluation is done without producing any error messages, but all
+ * error messages on parsing errors during the expression evaluation are given
+ * (even if a try conditional is active).
+ */
+static int cause_abort = FALSE;
+
+/*
+ * Return TRUE when immediately aborting on error, or when an interrupt
+ * occurred or an exception was thrown but not caught. Use for ":{range}call"
+ * to check whether an aborted function that does not handle a range itself
+ * should be called again for the next line in the range. Also used for
+ * cancelling expression evaluation after a function call caused an immediate
+ * abort. Note that the first emsg() call temporarily resets "force_abort"
+ * until the throw point for error messages has been reached. That is, during
+ * cancellation of an expression evaluation after an aborting function call or
+ * due to a parsing error, aborting() always returns the same value.
+ */
+ int
+aborting(void)
+{
+ return (did_emsg && force_abort) || got_int || did_throw;
+}
+
+/*
+ * The value of "force_abort" is temporarily reset by the first emsg() call
+ * during an expression evaluation, and "cause_abort" is used instead. It might
+ * be necessary to restore "force_abort" even before the throw point for the
+ * error message has been reached. update_force_abort() should be called then.
+ */
+ void
+update_force_abort(void)
+{
+ if (cause_abort)
+ force_abort = TRUE;
+}
+
+/*
+ * Return TRUE if a command with a subcommand resulting in "retcode" should
+ * abort the script processing. Can be used to suppress an autocommand after
+ * execution of a failing subcommand as long as the error message has not been
+ * displayed and actually caused the abortion.
+ */
+ int
+should_abort(int retcode)
+{
+ return ((retcode == FAIL && trylevel != 0 && !emsg_silent) || aborting());
+}
+
+/*
+ * Return TRUE if a function with the "abort" flag should not be considered
+ * ended on an error. This means that parsing commands is continued in order
+ * to find finally clauses to be executed, and that some errors in skipped
+ * commands are still reported.
+ */
+ int
+aborted_in_try(void)
+{
+ /* This function is only called after an error. In this case, "force_abort"
+ * determines whether searching for finally clauses is necessary. */
+ return force_abort;
+}
+
+/*
+ * cause_errthrow(): Cause a throw of an error exception if appropriate.
+ * Return TRUE if the error message should not be displayed by emsg().
+ * Sets "ignore", if the emsg() call should be ignored completely.
+ *
+ * When several messages appear in the same command, the first is usually the
+ * most specific one and used as the exception value. The "severe" flag can be
+ * set to TRUE, if a later but severer message should be used instead.
+ */
+ int
+cause_errthrow(
+ char_u *mesg,
+ int severe,
+ int *ignore)
+{
+ struct msglist *elem;
+ struct msglist **plist;
+
+ /*
+ * Do nothing when displaying the interrupt message or reporting an
+ * uncaught exception (which has already been discarded then) at the top
+ * level. Also when no exception can be thrown. The message will be
+ * displayed by emsg().
+ */
+ if (suppress_errthrow)
+ return FALSE;
+
+ /*
+ * If emsg() has not been called previously, temporarily reset
+ * "force_abort" until the throw point for error messages has been
+ * reached. This ensures that aborting() returns the same value for all
+ * errors that appear in the same command. This means particularly that
+ * for parsing errors during expression evaluation emsg() will be called
+ * multiply, even when the expression is evaluated from a finally clause
+ * that was activated due to an aborting error, interrupt, or exception.
+ */
+ if (!did_emsg)
+ {
+ cause_abort = force_abort;
+ force_abort = FALSE;
+ }
+
+ /*
+ * If no try conditional is active and no exception is being thrown and
+ * there has not been an error in a try conditional or a throw so far, do
+ * nothing (for compatibility of non-EH scripts). The message will then
+ * be displayed by emsg(). When ":silent!" was used and we are not
+ * currently throwing an exception, do nothing. The message text will
+ * then be stored to v:errmsg by emsg() without displaying it.
+ */
+ if (((trylevel == 0 && !cause_abort) || emsg_silent) && !did_throw)
+ return FALSE;
+
+ /*
+ * Ignore an interrupt message when inside a try conditional or when an
+ * exception is being thrown or when an error in a try conditional or
+ * throw has been detected previously. This is important in order that an
+ * interrupt exception is catchable by the innermost try conditional and
+ * not replaced by an interrupt message error exception.
+ */
+ if (mesg == (char_u *)_(e_interr))
+ {
+ *ignore = TRUE;
+ return TRUE;
+ }
+
+ /*
+ * Ensure that all commands in nested function calls and sourced files
+ * are aborted immediately.
+ */
+ cause_abort = TRUE;
+
+ /*
+ * When an exception is being thrown, some commands (like conditionals) are
+ * not skipped. Errors in those commands may affect what of the subsequent
+ * commands are regarded part of catch and finally clauses. Catching the
+ * exception would then cause execution of commands not intended by the
+ * user, who wouldn't even get aware of the problem. Therefor, discard the
+ * exception currently being thrown to prevent it from being caught. Just
+ * execute finally clauses and terminate.
+ */
+ if (did_throw)
+ {
+ /* When discarding an interrupt exception, reset got_int to prevent the
+ * same interrupt being converted to an exception again and discarding
+ * the error exception we are about to throw here. */
+ if (current_exception->type == ET_INTERRUPT)
+ got_int = FALSE;
+ discard_current_exception();
+ }
+
+#ifdef THROW_TEST
+ if (!THROW_ON_ERROR)
+ {
+ /*
+ * Print error message immediately without searching for a matching
+ * catch clause; just finally clauses are executed before the script
+ * is terminated.
+ */
+ return FALSE;
+ }
+ else
+#endif
+ {
+ /*
+ * Prepare the throw of an error exception, so that everything will
+ * be aborted (except for executing finally clauses), until the error
+ * exception is caught; if still uncaught at the top level, the error
+ * message will be displayed and the script processing terminated
+ * then. - This function has no access to the conditional stack.
+ * Thus, the actual throw is made after the failing command has
+ * returned. - Throw only the first of several errors in a row, except
+ * a severe error is following.
+ */
+ if (msg_list != NULL)
+ {
+ plist = msg_list;
+ while (*plist != NULL)
+ plist = &(*plist)->next;
+
+ elem = (struct msglist *)alloc((unsigned)sizeof(struct msglist));
+ if (elem == NULL)
+ {
+ suppress_errthrow = TRUE;
+ emsg(_(e_outofmem));
+ }
+ else
+ {
+ elem->msg = (char *)vim_strsave(mesg);
+ if (elem->msg == NULL)
+ {
+ vim_free(elem);
+ suppress_errthrow = TRUE;
+ emsg(_(e_outofmem));
+ }
+ else
+ {
+ elem->next = NULL;
+ elem->throw_msg = NULL;
+ *plist = elem;
+ if (plist == msg_list || severe)
+ {
+ char *tmsg;
+
+ /* Skip the extra "Vim " prefix for message "E458". */
+ tmsg = elem->msg;
+ if (STRNCMP(tmsg, "Vim E", 5) == 0
+ && VIM_ISDIGIT(tmsg[5])
+ && VIM_ISDIGIT(tmsg[6])
+ && VIM_ISDIGIT(tmsg[7])
+ && tmsg[8] == ':'
+ && tmsg[9] == ' ')
+ (*msg_list)->throw_msg = &tmsg[4];
+ else
+ (*msg_list)->throw_msg = tmsg;
+ }
+ }
+ }
+ }
+ return TRUE;
+ }
+}
+
+/*
+ * Free a "msg_list" and the messages it contains.
+ */
+ static void
+free_msglist(struct msglist *l)
+{
+ struct msglist *messages, *next;
+
+ messages = l;
+ while (messages != NULL)
+ {
+ next = messages->next;
+ vim_free(messages->msg);
+ vim_free(messages);
+ messages = next;
+ }
+}
+
+/*
+ * Free global "*msg_list" and the messages it contains, then set "*msg_list"
+ * to NULL.
+ */
+ void
+free_global_msglist(void)
+{
+ free_msglist(*msg_list);
+ *msg_list = NULL;
+}
+
+/*
+ * Throw the message specified in the call to cause_errthrow() above as an
+ * error exception. If cstack is NULL, postpone the throw until do_cmdline()
+ * has returned (see do_one_cmd()).
+ */
+ void
+do_errthrow(struct condstack *cstack, char_u *cmdname)
+{
+ /*
+ * Ensure that all commands in nested function calls and sourced files
+ * are aborted immediately.
+ */
+ if (cause_abort)
+ {
+ cause_abort = FALSE;
+ force_abort = TRUE;
+ }
+
+ /* If no exception is to be thrown or the conversion should be done after
+ * returning to a previous invocation of do_one_cmd(), do nothing. */
+ if (msg_list == NULL || *msg_list == NULL)
+ return;
+
+ if (throw_exception(*msg_list, ET_ERROR, cmdname) == FAIL)
+ free_msglist(*msg_list);
+ else
+ {
+ if (cstack != NULL)
+ do_throw(cstack);
+ else
+ need_rethrow = TRUE;
+ }
+ *msg_list = NULL;
+}
+
+/*
+ * do_intthrow(): Replace the current exception by an interrupt or interrupt
+ * exception if appropriate. Return TRUE if the current exception is discarded,
+ * FALSE otherwise.
+ */
+ int
+do_intthrow(struct condstack *cstack)
+{
+ /*
+ * If no interrupt occurred or no try conditional is active and no exception
+ * is being thrown, do nothing (for compatibility of non-EH scripts).
+ */
+ if (!got_int || (trylevel == 0 && !did_throw))
+ return FALSE;
+
+#ifdef THROW_TEST /* avoid warning for condition always true */
+ if (!THROW_ON_INTERRUPT)
+ {
+ /*
+ * The interrupt aborts everything except for executing finally clauses.
+ * Discard any user or error or interrupt exception currently being
+ * thrown.
+ */
+ if (did_throw)
+ discard_current_exception();
+ }
+ else
+#endif
+ {
+ /*
+ * Throw an interrupt exception, so that everything will be aborted
+ * (except for executing finally clauses), until the interrupt exception
+ * is caught; if still uncaught at the top level, the script processing
+ * will be terminated then. - If an interrupt exception is already
+ * being thrown, do nothing.
+ *
+ */
+ if (did_throw)
+ {
+ if (current_exception->type == ET_INTERRUPT)
+ return FALSE;
+
+ /* An interrupt exception replaces any user or error exception. */
+ discard_current_exception();
+ }
+ if (throw_exception("Vim:Interrupt", ET_INTERRUPT, NULL) != FAIL)
+ do_throw(cstack);
+ }
+
+ return TRUE;
+}
+
+/*
+ * Get an exception message that is to be stored in current_exception->value.
+ */
+ char *
+get_exception_string(
+ void *value,
+ except_type_T type,
+ char_u *cmdname,
+ int *should_free)
+{
+ char *ret;
+ char *mesg;
+ int cmdlen;
+ char *p, *val;
+
+ if (type == ET_ERROR)
+ {
+ *should_free = TRUE;
+ mesg = ((struct msglist *)value)->throw_msg;
+ if (cmdname != NULL && *cmdname != NUL)
+ {
+ cmdlen = (int)STRLEN(cmdname);
+ ret = (char *)vim_strnsave((char_u *)"Vim(",
+ 4 + cmdlen + 2 + (int)STRLEN(mesg));
+ if (ret == NULL)
+ return ret;
+ STRCPY(&ret[4], cmdname);
+ STRCPY(&ret[4 + cmdlen], "):");
+ val = ret + 4 + cmdlen + 2;
+ }
+ else
+ {
+ ret = (char *)vim_strnsave((char_u *)"Vim:", 4 + (int)STRLEN(mesg));
+ if (ret == NULL)
+ return ret;
+ val = ret + 4;
+ }
+
+ /* msg_add_fname may have been used to prefix the message with a file
+ * name in quotes. In the exception value, put the file name in
+ * parentheses and move it to the end. */
+ for (p = mesg; ; p++)
+ {
+ if (*p == NUL
+ || (*p == 'E'
+ && VIM_ISDIGIT(p[1])
+ && (p[2] == ':'
+ || (VIM_ISDIGIT(p[2])
+ && (p[3] == ':'
+ || (VIM_ISDIGIT(p[3])
+ && p[4] == ':'))))))
+ {
+ if (*p == NUL || p == mesg)
+ STRCAT(val, mesg); /* 'E123' missing or at beginning */
+ else
+ {
+ /* '"filename" E123: message text' */
+ if (mesg[0] != '"' || p-2 < &mesg[1] ||
+ p[-2] != '"' || p[-1] != ' ')
+ /* "E123:" is part of the file name. */
+ continue;
+
+ STRCAT(val, p);
+ p[-2] = NUL;
+ sprintf((char *)(val + STRLEN(p)), " (%s)", &mesg[1]);
+ p[-2] = '"';
+ }
+ break;
+ }
+ }
+ }
+ else
+ {
+ *should_free = FALSE;
+ ret = value;
+ }
+
+ return ret;
+}
+
+
+/*
+ * Throw a new exception. Return FAIL when out of memory or it was tried to
+ * throw an illegal user exception. "value" is the exception string for a
+ * user or interrupt exception, or points to a message list in case of an
+ * error exception.
+ */
+ static int
+throw_exception(void *value, except_type_T type, char_u *cmdname)
+{
+ except_T *excp;
+ int should_free;
+
+ /*
+ * Disallow faking Interrupt or error exceptions as user exceptions. They
+ * would be treated differently from real interrupt or error exceptions
+ * when no active try block is found, see do_cmdline().
+ */
+ if (type == ET_USER)
+ {
+ if (STRNCMP((char_u *)value, "Vim", 3) == 0
+ && (((char_u *)value)[3] == NUL || ((char_u *)value)[3] == ':'
+ || ((char_u *)value)[3] == '('))
+ {
+ emsg(_("E608: Cannot :throw exceptions with 'Vim' prefix"));
+ goto fail;
+ }
+ }
+
+ excp = (except_T *)alloc((unsigned)sizeof(except_T));
+ if (excp == NULL)
+ goto nomem;
+
+ if (type == ET_ERROR)
+ /* Store the original message and prefix the exception value with
+ * "Vim:" or, if a command name is given, "Vim(cmdname):". */
+ excp->messages = (struct msglist *)value;
+
+ excp->value = get_exception_string(value, type, cmdname, &should_free);
+ if (excp->value == NULL && should_free)
+ goto nomem;
+
+ excp->type = type;
+ excp->throw_name = vim_strsave(sourcing_name == NULL
+ ? (char_u *)"" : sourcing_name);
+ if (excp->throw_name == NULL)
+ {
+ if (should_free)
+ vim_free(excp->value);
+ goto nomem;
+ }
+ excp->throw_lnum = sourcing_lnum;
+
+ if (p_verbose >= 13 || debug_break_level > 0)
+ {
+ int save_msg_silent = msg_silent;
+
+ if (debug_break_level > 0)
+ msg_silent = FALSE; /* display messages */
+ else
+ verbose_enter();
+ ++no_wait_return;
+ if (debug_break_level > 0 || *p_vfile == NUL)
+ msg_scroll = TRUE; /* always scroll up, don't overwrite */
+
+ smsg(_("Exception thrown: %s"), excp->value);
+ msg_puts("\n"); /* don't overwrite this either */
+
+ if (debug_break_level > 0 || *p_vfile == NUL)
+ cmdline_row = msg_row;
+ --no_wait_return;
+ if (debug_break_level > 0)
+ msg_silent = save_msg_silent;
+ else
+ verbose_leave();
+ }
+
+ current_exception = excp;
+ return OK;
+
+nomem:
+ vim_free(excp);
+ suppress_errthrow = TRUE;
+ emsg(_(e_outofmem));
+fail:
+ current_exception = NULL;
+ return FAIL;
+}
+
+/*
+ * Discard an exception. "was_finished" is set when the exception has been
+ * caught and the catch clause has been ended normally.
+ */
+ static void
+discard_exception(except_T *excp, int was_finished)
+{
+ char_u *saved_IObuff;
+
+ if (excp == NULL)
+ {
+ internal_error("discard_exception()");
+ return;
+ }
+
+ if (p_verbose >= 13 || debug_break_level > 0)
+ {
+ int save_msg_silent = msg_silent;
+
+ saved_IObuff = vim_strsave(IObuff);
+ if (debug_break_level > 0)
+ msg_silent = FALSE; /* display messages */
+ else
+ verbose_enter();
+ ++no_wait_return;
+ if (debug_break_level > 0 || *p_vfile == NUL)
+ msg_scroll = TRUE; /* always scroll up, don't overwrite */
+ smsg(was_finished
+ ? _("Exception finished: %s")
+ : _("Exception discarded: %s"),
+ excp->value);
+ msg_puts("\n"); /* don't overwrite this either */
+ if (debug_break_level > 0 || *p_vfile == NUL)
+ cmdline_row = msg_row;
+ --no_wait_return;
+ if (debug_break_level > 0)
+ msg_silent = save_msg_silent;
+ else
+ verbose_leave();
+ STRCPY(IObuff, saved_IObuff);
+ vim_free(saved_IObuff);
+ }
+ if (excp->type != ET_INTERRUPT)
+ vim_free(excp->value);
+ if (excp->type == ET_ERROR)
+ free_msglist(excp->messages);
+ vim_free(excp->throw_name);
+ vim_free(excp);
+}
+
+/*
+ * Discard the exception currently being thrown.
+ */
+ void
+discard_current_exception(void)
+{
+ if (current_exception != NULL)
+ {
+ discard_exception(current_exception, FALSE);
+ current_exception = NULL;
+ }
+ did_throw = FALSE;
+ need_rethrow = FALSE;
+}
+
+/*
+ * Put an exception on the caught stack.
+ */
+ static void
+catch_exception(except_T *excp)
+{
+ excp->caught = caught_stack;
+ caught_stack = excp;
+ set_vim_var_string(VV_EXCEPTION, (char_u *)excp->value, -1);
+ if (*excp->throw_name != NUL)
+ {
+ if (excp->throw_lnum != 0)
+ vim_snprintf((char *)IObuff, IOSIZE, _("%s, line %ld"),
+ excp->throw_name, (long)excp->throw_lnum);
+ else
+ vim_snprintf((char *)IObuff, IOSIZE, "%s", excp->throw_name);
+ set_vim_var_string(VV_THROWPOINT, IObuff, -1);
+ }
+ else
+ /* throw_name not set on an exception from a command that was typed. */
+ set_vim_var_string(VV_THROWPOINT, NULL, -1);
+
+ if (p_verbose >= 13 || debug_break_level > 0)
+ {
+ int save_msg_silent = msg_silent;
+
+ if (debug_break_level > 0)
+ msg_silent = FALSE; /* display messages */
+ else
+ verbose_enter();
+ ++no_wait_return;
+ if (debug_break_level > 0 || *p_vfile == NUL)
+ msg_scroll = TRUE; /* always scroll up, don't overwrite */
+
+ smsg(_("Exception caught: %s"), excp->value);
+ msg_puts("\n"); /* don't overwrite this either */
+
+ if (debug_break_level > 0 || *p_vfile == NUL)
+ cmdline_row = msg_row;
+ --no_wait_return;
+ if (debug_break_level > 0)
+ msg_silent = save_msg_silent;
+ else
+ verbose_leave();
+ }
+}
+
+/*
+ * Remove an exception from the caught stack.
+ */
+ static void
+finish_exception(except_T *excp)
+{
+ if (excp != caught_stack)
+ internal_error("finish_exception()");
+ caught_stack = caught_stack->caught;
+ if (caught_stack != NULL)
+ {
+ set_vim_var_string(VV_EXCEPTION, (char_u *)caught_stack->value, -1);
+ if (*caught_stack->throw_name != NUL)
+ {
+ if (caught_stack->throw_lnum != 0)
+ vim_snprintf((char *)IObuff, IOSIZE,
+ _("%s, line %ld"), caught_stack->throw_name,
+ (long)caught_stack->throw_lnum);
+ else
+ vim_snprintf((char *)IObuff, IOSIZE, "%s",
+ caught_stack->throw_name);
+ set_vim_var_string(VV_THROWPOINT, IObuff, -1);
+ }
+ else
+ /* throw_name not set on an exception from a command that was
+ * typed. */
+ set_vim_var_string(VV_THROWPOINT, NULL, -1);
+ }
+ else
+ {
+ set_vim_var_string(VV_EXCEPTION, NULL, -1);
+ set_vim_var_string(VV_THROWPOINT, NULL, -1);
+ }
+
+ /* Discard the exception, but use the finish message for 'verbose'. */
+ discard_exception(excp, TRUE);
+}
+
+/*
+ * Flags specifying the message displayed by report_pending.
+ */
+#define RP_MAKE 0
+#define RP_RESUME 1
+#define RP_DISCARD 2
+
+/*
+ * Report information about something pending in a finally clause if required by
+ * the 'verbose' option or when debugging. "action" tells whether something is
+ * made pending or something pending is resumed or discarded. "pending" tells
+ * what is pending. "value" specifies the return value for a pending ":return"
+ * or the exception value for a pending exception.
+ */
+ static void
+report_pending(int action, int pending, void *value)
+{
+ char *mesg;
+ char *s;
+ int save_msg_silent;
+
+
+ switch (action)
+ {
+ case RP_MAKE:
+ mesg = _("%s made pending");
+ break;
+ case RP_RESUME:
+ mesg = _("%s resumed");
+ break;
+ /* case RP_DISCARD: */
+ default:
+ mesg = _("%s discarded");
+ break;
+ }
+
+ switch (pending)
+ {
+ case CSTP_NONE:
+ return;
+
+ case CSTP_CONTINUE:
+ s = ":continue";
+ break;
+ case CSTP_BREAK:
+ s = ":break";
+ break;
+ case CSTP_FINISH:
+ s = ":finish";
+ break;
+ case CSTP_RETURN:
+ /* ":return" command producing value, allocated */
+ s = (char *)get_return_cmd(value);
+ break;
+
+ default:
+ if (pending & CSTP_THROW)
+ {
+ vim_snprintf((char *)IObuff, IOSIZE, mesg, _("Exception"));
+ mesg = (char *)vim_strnsave(IObuff, (int)STRLEN(IObuff) + 4);
+ STRCAT(mesg, ": %s");
+ s = (char *)((except_T *)value)->value;
+ }
+ else if ((pending & CSTP_ERROR) && (pending & CSTP_INTERRUPT))
+ s = _("Error and interrupt");
+ else if (pending & CSTP_ERROR)
+ s = _("Error");
+ else /* if (pending & CSTP_INTERRUPT) */
+ s = _("Interrupt");
+ }
+
+ save_msg_silent = msg_silent;
+ if (debug_break_level > 0)
+ msg_silent = FALSE; /* display messages */
+ ++no_wait_return;
+ msg_scroll = TRUE; /* always scroll up, don't overwrite */
+ smsg(mesg, s);
+ msg_puts("\n"); /* don't overwrite this either */
+ cmdline_row = msg_row;
+ --no_wait_return;
+ if (debug_break_level > 0)
+ msg_silent = save_msg_silent;
+
+ if (pending == CSTP_RETURN)
+ vim_free(s);
+ else if (pending & CSTP_THROW)
+ vim_free(mesg);
+}
+
+/*
+ * If something is made pending in a finally clause, report it if required by
+ * the 'verbose' option or when debugging.
+ */
+ void
+report_make_pending(int pending, void *value)
+{
+ if (p_verbose >= 14 || debug_break_level > 0)
+ {
+ if (debug_break_level <= 0)
+ verbose_enter();
+ report_pending(RP_MAKE, pending, value);
+ if (debug_break_level <= 0)
+ verbose_leave();
+ }
+}
+
+/*
+ * If something pending in a finally clause is resumed at the ":endtry", report
+ * it if required by the 'verbose' option or when debugging.
+ */
+ void
+report_resume_pending(int pending, void *value)
+{
+ if (p_verbose >= 14 || debug_break_level > 0)
+ {
+ if (debug_break_level <= 0)
+ verbose_enter();
+ report_pending(RP_RESUME, pending, value);
+ if (debug_break_level <= 0)
+ verbose_leave();
+ }
+}
+
+/*
+ * If something pending in a finally clause is discarded, report it if required
+ * by the 'verbose' option or when debugging.
+ */
+ void
+report_discard_pending(int pending, void *value)
+{
+ if (p_verbose >= 14 || debug_break_level > 0)
+ {
+ if (debug_break_level <= 0)
+ verbose_enter();
+ report_pending(RP_DISCARD, pending, value);
+ if (debug_break_level <= 0)
+ verbose_leave();
+ }
+}
+
+
+/*
+ * ":if".
+ */
+ void
+ex_if(exarg_T *eap)
+{
+ int error;
+ int skip;
+ int result;
+ struct condstack *cstack = eap->cstack;
+
+ if (cstack->cs_idx == CSTACK_LEN - 1)
+ eap->errmsg = N_("E579: :if nesting too deep");
+ else
+ {
+ ++cstack->cs_idx;
+ cstack->cs_flags[cstack->cs_idx] = 0;
+
+ /*
+ * Don't do something after an error, interrupt, or throw, or when there
+ * is a surrounding conditional and it was not active.
+ */
+ skip = did_emsg || got_int || did_throw || (cstack->cs_idx > 0
+ && !(cstack->cs_flags[cstack->cs_idx - 1] & CSF_ACTIVE));
+
+ result = eval_to_bool(eap->arg, &error, &eap->nextcmd, skip);
+
+ if (!skip && !error)
+ {
+ if (result)
+ cstack->cs_flags[cstack->cs_idx] = CSF_ACTIVE | CSF_TRUE;
+ }
+ else
+ /* set TRUE, so this conditional will never get active */
+ cstack->cs_flags[cstack->cs_idx] = CSF_TRUE;
+ }
+}
+
+/*
+ * ":endif".
+ */
+ void
+ex_endif(exarg_T *eap)
+{
+ did_endif = TRUE;
+ if (eap->cstack->cs_idx < 0
+ || (eap->cstack->cs_flags[eap->cstack->cs_idx]
+ & (CSF_WHILE | CSF_FOR | CSF_TRY)))
+ eap->errmsg = N_("E580: :endif without :if");
+ else
+ {
+ /*
+ * When debugging or a breakpoint was encountered, display the debug
+ * prompt (if not already done). This shows the user that an ":endif"
+ * is executed when the ":if" or a previous ":elseif" was not TRUE.
+ * Handle a ">quit" debug command as if an interrupt had occurred before
+ * the ":endif". That is, throw an interrupt exception if appropriate.
+ * Doing this here prevents an exception for a parsing error being
+ * discarded by throwing the interrupt exception later on.
+ */
+ if (!(eap->cstack->cs_flags[eap->cstack->cs_idx] & CSF_TRUE)
+ && dbg_check_skipped(eap))
+ (void)do_intthrow(eap->cstack);
+
+ --eap->cstack->cs_idx;
+ }
+}
+
+/*
+ * ":else" and ":elseif".
+ */
+ void
+ex_else(exarg_T *eap)
+{
+ int error;
+ int skip;
+ int result;
+ struct condstack *cstack = eap->cstack;
+
+ /*
+ * Don't do something after an error, interrupt, or throw, or when there is
+ * a surrounding conditional and it was not active.
+ */
+ skip = did_emsg || got_int || did_throw || (cstack->cs_idx > 0
+ && !(cstack->cs_flags[cstack->cs_idx - 1] & CSF_ACTIVE));
+
+ if (cstack->cs_idx < 0
+ || (cstack->cs_flags[cstack->cs_idx]
+ & (CSF_WHILE | CSF_FOR | CSF_TRY)))
+ {
+ if (eap->cmdidx == CMD_else)
+ {
+ eap->errmsg = N_("E581: :else without :if");
+ return;
+ }
+ eap->errmsg = N_("E582: :elseif without :if");
+ skip = TRUE;
+ }
+ else if (cstack->cs_flags[cstack->cs_idx] & CSF_ELSE)
+ {
+ if (eap->cmdidx == CMD_else)
+ {
+ eap->errmsg = N_("E583: multiple :else");
+ return;
+ }
+ eap->errmsg = N_("E584: :elseif after :else");
+ skip = TRUE;
+ }
+
+ /* if skipping or the ":if" was TRUE, reset ACTIVE, otherwise set it */
+ if (skip || cstack->cs_flags[cstack->cs_idx] & CSF_TRUE)
+ {
+ if (eap->errmsg == NULL)
+ cstack->cs_flags[cstack->cs_idx] = CSF_TRUE;
+ skip = TRUE; /* don't evaluate an ":elseif" */
+ }
+ else
+ cstack->cs_flags[cstack->cs_idx] = CSF_ACTIVE;
+
+ /*
+ * When debugging or a breakpoint was encountered, display the debug prompt
+ * (if not already done). This shows the user that an ":else" or ":elseif"
+ * is executed when the ":if" or previous ":elseif" was not TRUE. Handle
+ * a ">quit" debug command as if an interrupt had occurred before the
+ * ":else" or ":elseif". That is, set "skip" and throw an interrupt
+ * exception if appropriate. Doing this here prevents that an exception
+ * for a parsing errors is discarded when throwing the interrupt exception
+ * later on.
+ */
+ if (!skip && dbg_check_skipped(eap) && got_int)
+ {
+ (void)do_intthrow(cstack);
+ skip = TRUE;
+ }
+
+ if (eap->cmdidx == CMD_elseif)
+ {
+ result = eval_to_bool(eap->arg, &error, &eap->nextcmd, skip);
+ /* When throwing error exceptions, we want to throw always the first
+ * of several errors in a row. This is what actually happens when
+ * a conditional error was detected above and there is another failure
+ * when parsing the expression. Since the skip flag is set in this
+ * case, the parsing error will be ignored by emsg(). */
+
+ if (!skip && !error)
+ {
+ if (result)
+ cstack->cs_flags[cstack->cs_idx] = CSF_ACTIVE | CSF_TRUE;
+ else
+ cstack->cs_flags[cstack->cs_idx] = 0;
+ }
+ else if (eap->errmsg == NULL)
+ /* set TRUE, so this conditional will never get active */
+ cstack->cs_flags[cstack->cs_idx] = CSF_TRUE;
+ }
+ else
+ cstack->cs_flags[cstack->cs_idx] |= CSF_ELSE;
+}
+
+/*
+ * Handle ":while" and ":for".
+ */
+ void
+ex_while(exarg_T *eap)
+{
+ int error;
+ int skip;
+ int result;
+ struct condstack *cstack = eap->cstack;
+
+ if (cstack->cs_idx == CSTACK_LEN - 1)
+ eap->errmsg = N_("E585: :while/:for nesting too deep");
+ else
+ {
+ /*
+ * The loop flag is set when we have jumped back from the matching
+ * ":endwhile" or ":endfor". When not set, need to initialise this
+ * cstack entry.
+ */
+ if ((cstack->cs_lflags & CSL_HAD_LOOP) == 0)
+ {
+ ++cstack->cs_idx;
+ ++cstack->cs_looplevel;
+ cstack->cs_line[cstack->cs_idx] = -1;
+ }
+ cstack->cs_flags[cstack->cs_idx] =
+ eap->cmdidx == CMD_while ? CSF_WHILE : CSF_FOR;
+
+ /*
+ * Don't do something after an error, interrupt, or throw, or when
+ * there is a surrounding conditional and it was not active.
+ */
+ skip = did_emsg || got_int || did_throw || (cstack->cs_idx > 0
+ && !(cstack->cs_flags[cstack->cs_idx - 1] & CSF_ACTIVE));
+ if (eap->cmdidx == CMD_while)
+ {
+ /*
+ * ":while bool-expr"
+ */
+ result = eval_to_bool(eap->arg, &error, &eap->nextcmd, skip);
+ }
+ else
+ {
+ void *fi;
+
+ /*
+ * ":for var in list-expr"
+ */
+ if ((cstack->cs_lflags & CSL_HAD_LOOP) != 0)
+ {
+ /* Jumping here from a ":continue" or ":endfor": use the
+ * previously evaluated list. */
+ fi = cstack->cs_forinfo[cstack->cs_idx];
+ error = FALSE;
+ }
+ else
+ {
+ /* Evaluate the argument and get the info in a structure. */
+ fi = eval_for_line(eap->arg, &error, &eap->nextcmd, skip);
+ cstack->cs_forinfo[cstack->cs_idx] = fi;
+ }
+
+ /* use the element at the start of the list and advance */
+ if (!error && fi != NULL && !skip)
+ result = next_for_item(fi, eap->arg);
+ else
+ result = FALSE;
+
+ if (!result)
+ {
+ free_for_info(fi);
+ cstack->cs_forinfo[cstack->cs_idx] = NULL;
+ }
+ }
+
+ /*
+ * If this cstack entry was just initialised and is active, set the
+ * loop flag, so do_cmdline() will set the line number in cs_line[].
+ * If executing the command a second time, clear the loop flag.
+ */
+ if (!skip && !error && result)
+ {
+ cstack->cs_flags[cstack->cs_idx] |= (CSF_ACTIVE | CSF_TRUE);
+ cstack->cs_lflags ^= CSL_HAD_LOOP;
+ }
+ else
+ {
+ cstack->cs_lflags &= ~CSL_HAD_LOOP;
+ /* If the ":while" evaluates to FALSE or ":for" is past the end of
+ * the list, show the debug prompt at the ":endwhile"/":endfor" as
+ * if there was a ":break" in a ":while"/":for" evaluating to
+ * TRUE. */
+ if (!skip && !error)
+ cstack->cs_flags[cstack->cs_idx] |= CSF_TRUE;
+ }
+ }
+}
+
+/*
+ * ":continue"
+ */
+ void
+ex_continue(exarg_T *eap)
+{
+ int idx;
+ struct condstack *cstack = eap->cstack;
+
+ if (cstack->cs_looplevel <= 0 || cstack->cs_idx < 0)
+ eap->errmsg = N_("E586: :continue without :while or :for");
+ else
+ {
+ /* Try to find the matching ":while". This might stop at a try
+ * conditional not in its finally clause (which is then to be executed
+ * next). Therefor, inactivate all conditionals except the ":while"
+ * itself (if reached). */
+ idx = cleanup_conditionals(cstack, CSF_WHILE | CSF_FOR, FALSE);
+ if (idx >= 0 && (cstack->cs_flags[idx] & (CSF_WHILE | CSF_FOR)))
+ {
+ rewind_conditionals(cstack, idx, CSF_TRY, &cstack->cs_trylevel);
+
+ /*
+ * Set CSL_HAD_CONT, so do_cmdline() will jump back to the
+ * matching ":while".
+ */
+ cstack->cs_lflags |= CSL_HAD_CONT; /* let do_cmdline() handle it */
+ }
+ else
+ {
+ /* If a try conditional not in its finally clause is reached first,
+ * make the ":continue" pending for execution at the ":endtry". */
+ cstack->cs_pending[idx] = CSTP_CONTINUE;
+ report_make_pending(CSTP_CONTINUE, NULL);
+ }
+ }
+}
+
+/*
+ * ":break"
+ */
+ void
+ex_break(exarg_T *eap)
+{
+ int idx;
+ struct condstack *cstack = eap->cstack;
+
+ if (cstack->cs_looplevel <= 0 || cstack->cs_idx < 0)
+ eap->errmsg = N_("E587: :break without :while or :for");
+ else
+ {
+ /* Inactivate conditionals until the matching ":while" or a try
+ * conditional not in its finally clause (which is then to be
+ * executed next) is found. In the latter case, make the ":break"
+ * pending for execution at the ":endtry". */
+ idx = cleanup_conditionals(cstack, CSF_WHILE | CSF_FOR, TRUE);
+ if (idx >= 0 && !(cstack->cs_flags[idx] & (CSF_WHILE | CSF_FOR)))
+ {
+ cstack->cs_pending[idx] = CSTP_BREAK;
+ report_make_pending(CSTP_BREAK, NULL);
+ }
+ }
+}
+
+/*
+ * ":endwhile" and ":endfor"
+ */
+ void
+ex_endwhile(exarg_T *eap)
+{
+ struct condstack *cstack = eap->cstack;
+ int idx;
+ char *err;
+ int csf;
+ int fl;
+
+ if (eap->cmdidx == CMD_endwhile)
+ {
+ err = e_while;
+ csf = CSF_WHILE;
+ }
+ else
+ {
+ err = e_for;
+ csf = CSF_FOR;
+ }
+
+ if (cstack->cs_looplevel <= 0 || cstack->cs_idx < 0)
+ eap->errmsg = err;
+ else
+ {
+ fl = cstack->cs_flags[cstack->cs_idx];
+ if (!(fl & csf))
+ {
+ /* If we are in a ":while" or ":for" but used the wrong endloop
+ * command, do not rewind to the next enclosing ":for"/":while". */
+ if (fl & CSF_WHILE)
+ eap->errmsg = _("E732: Using :endfor with :while");
+ else if (fl & CSF_FOR)
+ eap->errmsg = _("E733: Using :endwhile with :for");
+ }
+ if (!(fl & (CSF_WHILE | CSF_FOR)))
+ {
+ if (!(fl & CSF_TRY))
+ eap->errmsg = e_endif;
+ else if (fl & CSF_FINALLY)
+ eap->errmsg = e_endtry;
+ /* Try to find the matching ":while" and report what's missing. */
+ for (idx = cstack->cs_idx; idx > 0; --idx)
+ {
+ fl = cstack->cs_flags[idx];
+ if ((fl & CSF_TRY) && !(fl & CSF_FINALLY))
+ {
+ /* Give up at a try conditional not in its finally clause.
+ * Ignore the ":endwhile"/":endfor". */
+ eap->errmsg = err;
+ return;
+ }
+ if (fl & csf)
+ break;
+ }
+ /* Cleanup and rewind all contained (and unclosed) conditionals. */
+ (void)cleanup_conditionals(cstack, CSF_WHILE | CSF_FOR, FALSE);
+ rewind_conditionals(cstack, idx, CSF_TRY, &cstack->cs_trylevel);
+ }
+
+ /*
+ * When debugging or a breakpoint was encountered, display the debug
+ * prompt (if not already done). This shows the user that an
+ * ":endwhile"/":endfor" is executed when the ":while" was not TRUE or
+ * after a ":break". Handle a ">quit" debug command as if an
+ * interrupt had occurred before the ":endwhile"/":endfor". That is,
+ * throw an interrupt exception if appropriate. Doing this here
+ * prevents that an exception for a parsing error is discarded when
+ * throwing the interrupt exception later on.
+ */
+ else if (cstack->cs_flags[cstack->cs_idx] & CSF_TRUE
+ && !(cstack->cs_flags[cstack->cs_idx] & CSF_ACTIVE)
+ && dbg_check_skipped(eap))
+ (void)do_intthrow(cstack);
+
+ /*
+ * Set loop flag, so do_cmdline() will jump back to the matching
+ * ":while" or ":for".
+ */
+ cstack->cs_lflags |= CSL_HAD_ENDLOOP;
+ }
+}
+
+
+/*
+ * ":throw expr"
+ */
+ void
+ex_throw(exarg_T *eap)
+{
+ char_u *arg = eap->arg;
+ char_u *value;
+
+ if (*arg != NUL && *arg != '|' && *arg != '\n')
+ value = eval_to_string_skip(arg, &eap->nextcmd, eap->skip);
+ else
+ {
+ emsg(_(e_argreq));
+ value = NULL;
+ }
+
+ /* On error or when an exception is thrown during argument evaluation, do
+ * not throw. */
+ if (!eap->skip && value != NULL)
+ {
+ if (throw_exception(value, ET_USER, NULL) == FAIL)
+ vim_free(value);
+ else
+ do_throw(eap->cstack);
+ }
+}
+
+/*
+ * Throw the current exception through the specified cstack. Common routine
+ * for ":throw" (user exception) and error and interrupt exceptions. Also
+ * used for rethrowing an uncaught exception.
+ */
+ void
+do_throw(struct condstack *cstack)
+{
+ int idx;
+ int inactivate_try = FALSE;
+
+ /*
+ * Cleanup and inactivate up to the next surrounding try conditional that
+ * is not in its finally clause. Normally, do not inactivate the try
+ * conditional itself, so that its ACTIVE flag can be tested below. But
+ * if a previous error or interrupt has not been converted to an exception,
+ * inactivate the try conditional, too, as if the conversion had been done,
+ * and reset the did_emsg or got_int flag, so this won't happen again at
+ * the next surrounding try conditional.
+ */
+#ifndef THROW_ON_ERROR_TRUE
+ if (did_emsg && !THROW_ON_ERROR)
+ {
+ inactivate_try = TRUE;
+ did_emsg = FALSE;
+ }
+#endif
+#ifndef THROW_ON_INTERRUPT_TRUE
+ if (got_int && !THROW_ON_INTERRUPT)
+ {
+ inactivate_try = TRUE;
+ got_int = FALSE;
+ }
+#endif
+ idx = cleanup_conditionals(cstack, 0, inactivate_try);
+ if (idx >= 0)
+ {
+ /*
+ * If this try conditional is active and we are before its first
+ * ":catch", set THROWN so that the ":catch" commands will check
+ * whether the exception matches. When the exception came from any of
+ * the catch clauses, it will be made pending at the ":finally" (if
+ * present) and rethrown at the ":endtry". This will also happen if
+ * the try conditional is inactive. This is the case when we are
+ * throwing an exception due to an error or interrupt on the way from
+ * a preceding ":continue", ":break", ":return", ":finish", error or
+ * interrupt (not converted to an exception) to the finally clause or
+ * from a preceding throw of a user or error or interrupt exception to
+ * the matching catch clause or the finally clause.
+ */
+ if (!(cstack->cs_flags[idx] & CSF_CAUGHT))
+ {
+ if (cstack->cs_flags[idx] & CSF_ACTIVE)
+ cstack->cs_flags[idx] |= CSF_THROWN;
+ else
+ /* THROWN may have already been set for a catchable exception
+ * that has been discarded. Ensure it is reset for the new
+ * exception. */
+ cstack->cs_flags[idx] &= ~CSF_THROWN;
+ }
+ cstack->cs_flags[idx] &= ~CSF_ACTIVE;
+ cstack->cs_exception[idx] = current_exception;
+ }
+#if 0
+ /* TODO: Add optimization below. Not yet done because of interface
+ * problems to eval.c and ex_cmds2.c. (Servatius) */
+ else
+ {
+ /*
+ * There are no catch clauses to check or finally clauses to execute.
+ * End the current script or function. The exception will be rethrown
+ * in the caller.
+ */
+ if (getline_equal(eap->getline, eap->cookie, get_func_line))
+ current_funccal->returned = TRUE;
+ elseif (eap->get_func_line == getsourceline)
+ ((struct source_cookie *)eap->cookie)->finished = TRUE;
+ }
+#endif
+
+ did_throw = TRUE;
+}
+
+/*
+ * ":try"
+ */
+ void
+ex_try(exarg_T *eap)
+{
+ int skip;
+ struct condstack *cstack = eap->cstack;
+
+ if (cstack->cs_idx == CSTACK_LEN - 1)
+ eap->errmsg = N_("E601: :try nesting too deep");
+ else
+ {
+ ++cstack->cs_idx;
+ ++cstack->cs_trylevel;
+ cstack->cs_flags[cstack->cs_idx] = CSF_TRY;
+ cstack->cs_pending[cstack->cs_idx] = CSTP_NONE;
+
+ /*
+ * Don't do something after an error, interrupt, or throw, or when there
+ * is a surrounding conditional and it was not active.
+ */
+ skip = did_emsg || got_int || did_throw || (cstack->cs_idx > 0
+ && !(cstack->cs_flags[cstack->cs_idx - 1] & CSF_ACTIVE));
+
+ if (!skip)
+ {
+ /* Set ACTIVE and TRUE. TRUE means that the corresponding ":catch"
+ * commands should check for a match if an exception is thrown and
+ * that the finally clause needs to be executed. */
+ cstack->cs_flags[cstack->cs_idx] |= CSF_ACTIVE | CSF_TRUE;
+
+ /*
+ * ":silent!", even when used in a try conditional, disables
+ * displaying of error messages and conversion of errors to
+ * exceptions. When the silent commands again open a try
+ * conditional, save "emsg_silent" and reset it so that errors are
+ * again converted to exceptions. The value is restored when that
+ * try conditional is left. If it is left normally, the commands
+ * following the ":endtry" are again silent. If it is left by
+ * a ":continue", ":break", ":return", or ":finish", the commands
+ * executed next are again silent. If it is left due to an
+ * aborting error, an interrupt, or an exception, restoring
+ * "emsg_silent" does not matter since we are already in the
+ * aborting state and/or the exception has already been thrown.
+ * The effect is then just freeing the memory that was allocated
+ * to save the value.
+ */
+ if (emsg_silent)
+ {
+ eslist_T *elem;
+
+ elem = (eslist_T *)alloc((unsigned)sizeof(struct eslist_elem));
+ if (elem == NULL)
+ emsg(_(e_outofmem));
+ else
+ {
+ elem->saved_emsg_silent = emsg_silent;
+ elem->next = cstack->cs_emsg_silent_list;
+ cstack->cs_emsg_silent_list = elem;
+ cstack->cs_flags[cstack->cs_idx] |= CSF_SILENT;
+ emsg_silent = 0;
+ }
+ }
+ }
+
+ }
+}
+
+/*
+ * ":catch /{pattern}/" and ":catch"
+ */
+ void
+ex_catch(exarg_T *eap)
+{
+ int idx = 0;
+ int give_up = FALSE;
+ int skip = FALSE;
+ int caught = FALSE;
+ char_u *end;
+ int save_char = 0;
+ char_u *save_cpo;
+ regmatch_T regmatch;
+ int prev_got_int;
+ struct condstack *cstack = eap->cstack;
+ char_u *pat;
+
+ if (cstack->cs_trylevel <= 0 || cstack->cs_idx < 0)
+ {
+ eap->errmsg = N_("E603: :catch without :try");
+ give_up = TRUE;
+ }
+ else
+ {
+ if (!(cstack->cs_flags[cstack->cs_idx] & CSF_TRY))
+ {
+ /* Report what's missing if the matching ":try" is not in its
+ * finally clause. */
+ eap->errmsg = get_end_emsg(cstack);
+ skip = TRUE;
+ }
+ for (idx = cstack->cs_idx; idx > 0; --idx)
+ if (cstack->cs_flags[idx] & CSF_TRY)
+ break;
+ if (cstack->cs_flags[idx] & CSF_FINALLY)
+ {
+ /* Give up for a ":catch" after ":finally" and ignore it.
+ * Just parse. */
+ eap->errmsg = N_("E604: :catch after :finally");
+ give_up = TRUE;
+ }
+ else
+ rewind_conditionals(cstack, idx, CSF_WHILE | CSF_FOR,
+ &cstack->cs_looplevel);
+ }
+
+ if (ends_excmd(*eap->arg)) /* no argument, catch all errors */
+ {
+ pat = (char_u *)".*";
+ end = NULL;
+ eap->nextcmd = find_nextcmd(eap->arg);
+ }
+ else
+ {
+ pat = eap->arg + 1;
+ end = skip_regexp(pat, *eap->arg, TRUE, NULL);
+ }
+
+ if (!give_up)
+ {
+ /*
+ * Don't do something when no exception has been thrown or when the
+ * corresponding try block never got active (because of an inactive
+ * surrounding conditional or after an error or interrupt or throw).
+ */
+ if (!did_throw || !(cstack->cs_flags[idx] & CSF_TRUE))
+ skip = TRUE;
+
+ /*
+ * Check for a match only if an exception is thrown but not caught by
+ * a previous ":catch". An exception that has replaced a discarded
+ * exception is not checked (THROWN is not set then).
+ */
+ if (!skip && (cstack->cs_flags[idx] & CSF_THROWN)
+ && !(cstack->cs_flags[idx] & CSF_CAUGHT))
+ {
+ if (end != NULL && *end != NUL && !ends_excmd(*skipwhite(end + 1)))
+ {
+ emsg(_(e_trailing));
+ return;
+ }
+
+ /* When debugging or a breakpoint was encountered, display the
+ * debug prompt (if not already done) before checking for a match.
+ * This is a helpful hint for the user when the regular expression
+ * matching fails. Handle a ">quit" debug command as if an
+ * interrupt had occurred before the ":catch". That is, discard
+ * the original exception, replace it by an interrupt exception,
+ * and don't catch it in this try block. */
+ if (!dbg_check_skipped(eap) || !do_intthrow(cstack))
+ {
+ /* Terminate the pattern and avoid the 'l' flag in 'cpoptions'
+ * while compiling it. */
+ if (end != NULL)
+ {
+ save_char = *end;
+ *end = NUL;
+ }
+ save_cpo = p_cpo;
+ p_cpo = (char_u *)"";
+ /* Disable error messages, it will make current_exception
+ * invalid. */
+ ++emsg_off;
+ regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
+ --emsg_off;
+ regmatch.rm_ic = FALSE;
+ if (end != NULL)
+ *end = save_char;
+ p_cpo = save_cpo;
+ if (regmatch.regprog == NULL)
+ semsg(_(e_invarg2), pat);
+ else
+ {
+ /*
+ * Save the value of got_int and reset it. We don't want
+ * a previous interruption cancel matching, only hitting
+ * CTRL-C while matching should abort it.
+ */
+ prev_got_int = got_int;
+ got_int = FALSE;
+ caught = vim_regexec_nl(&regmatch,
+ (char_u *)current_exception->value, (colnr_T)0);
+ got_int |= prev_got_int;
+ vim_regfree(regmatch.regprog);
+ }
+ }
+ }
+
+ if (caught)
+ {
+ /* Make this ":catch" clause active and reset did_emsg, got_int,
+ * and did_throw. Put the exception on the caught stack. */
+ cstack->cs_flags[idx] |= CSF_ACTIVE | CSF_CAUGHT;
+ did_emsg = got_int = did_throw = FALSE;
+ catch_exception((except_T *)cstack->cs_exception[idx]);
+ /* It's mandatory that the current exception is stored in the cstack
+ * so that it can be discarded at the next ":catch", ":finally", or
+ * ":endtry" or when the catch clause is left by a ":continue",
+ * ":break", ":return", ":finish", error, interrupt, or another
+ * exception. */
+ if (cstack->cs_exception[cstack->cs_idx] != current_exception)
+ internal_error("ex_catch()");
+ }
+ else
+ {
+ /*
+ * If there is a preceding catch clause and it caught the exception,
+ * finish the exception now. This happens also after errors except
+ * when this ":catch" was after the ":finally" or not within
+ * a ":try". Make the try conditional inactive so that the
+ * following catch clauses are skipped. On an error or interrupt
+ * after the preceding try block or catch clause was left by
+ * a ":continue", ":break", ":return", or ":finish", discard the
+ * pending action.
+ */
+ cleanup_conditionals(cstack, CSF_TRY, TRUE);
+ }
+ }
+
+ if (end != NULL)
+ eap->nextcmd = find_nextcmd(end);
+}
+
+/*
+ * ":finally"
+ */
+ void
+ex_finally(exarg_T *eap)
+{
+ int idx;
+ int skip = FALSE;
+ int pending = CSTP_NONE;
+ struct condstack *cstack = eap->cstack;
+
+ if (cstack->cs_trylevel <= 0 || cstack->cs_idx < 0)
+ eap->errmsg = N_("E606: :finally without :try");
+ else
+ {
+ if (!(cstack->cs_flags[cstack->cs_idx] & CSF_TRY))
+ {
+ eap->errmsg = get_end_emsg(cstack);
+ for (idx = cstack->cs_idx - 1; idx > 0; --idx)
+ if (cstack->cs_flags[idx] & CSF_TRY)
+ break;
+ /* Make this error pending, so that the commands in the following
+ * finally clause can be executed. This overrules also a pending
+ * ":continue", ":break", ":return", or ":finish". */
+ pending = CSTP_ERROR;
+ }
+ else
+ idx = cstack->cs_idx;
+
+ if (cstack->cs_flags[idx] & CSF_FINALLY)
+ {
+ /* Give up for a multiple ":finally" and ignore it. */
+ eap->errmsg = N_("E607: multiple :finally");
+ return;
+ }
+ rewind_conditionals(cstack, idx, CSF_WHILE | CSF_FOR,
+ &cstack->cs_looplevel);
+
+ /*
+ * Don't do something when the corresponding try block never got active
+ * (because of an inactive surrounding conditional or after an error or
+ * interrupt or throw) or for a ":finally" without ":try" or a multiple
+ * ":finally". After every other error (did_emsg or the conditional
+ * errors detected above) or after an interrupt (got_int) or an
+ * exception (did_throw), the finally clause must be executed.
+ */
+ skip = !(cstack->cs_flags[cstack->cs_idx] & CSF_TRUE);
+
+ if (!skip)
+ {
+ /* When debugging or a breakpoint was encountered, display the
+ * debug prompt (if not already done). The user then knows that the
+ * finally clause is executed. */
+ if (dbg_check_skipped(eap))
+ {
+ /* Handle a ">quit" debug command as if an interrupt had
+ * occurred before the ":finally". That is, discard the
+ * original exception and replace it by an interrupt
+ * exception. */
+ (void)do_intthrow(cstack);
+ }
+
+ /*
+ * If there is a preceding catch clause and it caught the exception,
+ * finish the exception now. This happens also after errors except
+ * when this is a multiple ":finally" or one not within a ":try".
+ * After an error or interrupt, this also discards a pending
+ * ":continue", ":break", ":finish", or ":return" from the preceding
+ * try block or catch clause.
+ */
+ cleanup_conditionals(cstack, CSF_TRY, FALSE);
+
+ /*
+ * Make did_emsg, got_int, did_throw pending. If set, they overrule
+ * a pending ":continue", ":break", ":return", or ":finish". Then
+ * we have particularly to discard a pending return value (as done
+ * by the call to cleanup_conditionals() above when did_emsg or
+ * got_int is set). The pending values are restored by the
+ * ":endtry", except if there is a new error, interrupt, exception,
+ * ":continue", ":break", ":return", or ":finish" in the following
+ * finally clause. A missing ":endwhile", ":endfor" or ":endif"
+ * detected here is treated as if did_emsg and did_throw had
+ * already been set, respectively in case that the error is not
+ * converted to an exception, did_throw had already been unset.
+ * We must not set did_emsg here since that would suppress the
+ * error message.
+ */
+ if (pending == CSTP_ERROR || did_emsg || got_int || did_throw)
+ {
+ if (cstack->cs_pending[cstack->cs_idx] == CSTP_RETURN)
+ {
+ report_discard_pending(CSTP_RETURN,
+ cstack->cs_rettv[cstack->cs_idx]);
+ discard_pending_return(cstack->cs_rettv[cstack->cs_idx]);
+ }
+ if (pending == CSTP_ERROR && !did_emsg)
+ pending |= (THROW_ON_ERROR) ? CSTP_THROW : 0;
+ else
+ pending |= did_throw ? CSTP_THROW : 0;
+ pending |= did_emsg ? CSTP_ERROR : 0;
+ pending |= got_int ? CSTP_INTERRUPT : 0;
+ cstack->cs_pending[cstack->cs_idx] = pending;
+
+ /* It's mandatory that the current exception is stored in the
+ * cstack so that it can be rethrown at the ":endtry" or be
+ * discarded if the finally clause is left by a ":continue",
+ * ":break", ":return", ":finish", error, interrupt, or another
+ * exception. When emsg() is called for a missing ":endif" or
+ * a missing ":endwhile"/":endfor" detected here, the
+ * exception will be discarded. */
+ if (did_throw && cstack->cs_exception[cstack->cs_idx]
+ != current_exception)
+ internal_error("ex_finally()");
+ }
+
+ /*
+ * Set CSL_HAD_FINA, so do_cmdline() will reset did_emsg,
+ * got_int, and did_throw and make the finally clause active.
+ * This will happen after emsg() has been called for a missing
+ * ":endif" or a missing ":endwhile"/":endfor" detected here, so
+ * that the following finally clause will be executed even then.
+ */
+ cstack->cs_lflags |= CSL_HAD_FINA;
+ }
+ }
+}
+
+/*
+ * ":endtry"
+ */
+ void
+ex_endtry(exarg_T *eap)
+{
+ int idx;
+ int skip;
+ int rethrow = FALSE;
+ int pending = CSTP_NONE;
+ void *rettv = NULL;
+ struct condstack *cstack = eap->cstack;
+
+ if (cstack->cs_trylevel <= 0 || cstack->cs_idx < 0)
+ eap->errmsg = N_("E602: :endtry without :try");
+ else
+ {
+ /*
+ * Don't do something after an error, interrupt or throw in the try
+ * block, catch clause, or finally clause preceding this ":endtry" or
+ * when an error or interrupt occurred after a ":continue", ":break",
+ * ":return", or ":finish" in a try block or catch clause preceding this
+ * ":endtry" or when the try block never got active (because of an
+ * inactive surrounding conditional or after an error or interrupt or
+ * throw) or when there is a surrounding conditional and it has been
+ * made inactive by a ":continue", ":break", ":return", or ":finish" in
+ * the finally clause. The latter case need not be tested since then
+ * anything pending has already been discarded. */
+ skip = did_emsg || got_int || did_throw ||
+ !(cstack->cs_flags[cstack->cs_idx] & CSF_TRUE);
+
+ if (!(cstack->cs_flags[cstack->cs_idx] & CSF_TRY))
+ {
+ eap->errmsg = get_end_emsg(cstack);
+ /* Find the matching ":try" and report what's missing. */
+ idx = cstack->cs_idx;
+ do
+ --idx;
+ while (idx > 0 && !(cstack->cs_flags[idx] & CSF_TRY));
+ rewind_conditionals(cstack, idx, CSF_WHILE | CSF_FOR,
+ &cstack->cs_looplevel);
+ skip = TRUE;
+
+ /*
+ * If an exception is being thrown, discard it to prevent it from
+ * being rethrown at the end of this function. It would be
+ * discarded by the error message, anyway. Resets did_throw.
+ * This does not affect the script termination due to the error
+ * since "trylevel" is decremented after emsg() has been called.
+ */
+ if (did_throw)
+ discard_current_exception();
+ }
+ else
+ {
+ idx = cstack->cs_idx;
+
+ /*
+ * If we stopped with the exception currently being thrown at this
+ * try conditional since we didn't know that it doesn't have
+ * a finally clause, we need to rethrow it after closing the try
+ * conditional.
+ */
+ if (did_throw && (cstack->cs_flags[idx] & CSF_TRUE)
+ && !(cstack->cs_flags[idx] & CSF_FINALLY))
+ rethrow = TRUE;
+ }
+
+ /* If there was no finally clause, show the user when debugging or
+ * a breakpoint was encountered that the end of the try conditional has
+ * been reached: display the debug prompt (if not already done). Do
+ * this on normal control flow or when an exception was thrown, but not
+ * on an interrupt or error not converted to an exception or when
+ * a ":break", ":continue", ":return", or ":finish" is pending. These
+ * actions are carried out immediately.
+ */
+ if ((rethrow || (!skip
+ && !(cstack->cs_flags[idx] & CSF_FINALLY)
+ && !cstack->cs_pending[idx]))
+ && dbg_check_skipped(eap))
+ {
+ /* Handle a ">quit" debug command as if an interrupt had occurred
+ * before the ":endtry". That is, throw an interrupt exception and
+ * set "skip" and "rethrow". */
+ if (got_int)
+ {
+ skip = TRUE;
+ (void)do_intthrow(cstack);
+ /* The do_intthrow() call may have reset did_throw or
+ * cstack->cs_pending[idx].*/
+ rethrow = FALSE;
+ if (did_throw && !(cstack->cs_flags[idx] & CSF_FINALLY))
+ rethrow = TRUE;
+ }
+ }
+
+ /*
+ * If a ":return" is pending, we need to resume it after closing the
+ * try conditional; remember the return value. If there was a finally
+ * clause making an exception pending, we need to rethrow it. Make it
+ * the exception currently being thrown.
+ */
+ if (!skip)
+ {
+ pending = cstack->cs_pending[idx];
+ cstack->cs_pending[idx] = CSTP_NONE;
+ if (pending == CSTP_RETURN)
+ rettv = cstack->cs_rettv[idx];
+ else if (pending & CSTP_THROW)
+ current_exception = cstack->cs_exception[idx];
+ }
+
+ /*
+ * Discard anything pending on an error, interrupt, or throw in the
+ * finally clause. If there was no ":finally", discard a pending
+ * ":continue", ":break", ":return", or ":finish" if an error or
+ * interrupt occurred afterwards, but before the ":endtry" was reached.
+ * If an exception was caught by the last of the catch clauses and there
+ * was no finally clause, finish the exception now. This happens also
+ * after errors except when this ":endtry" is not within a ":try".
+ * Restore "emsg_silent" if it has been reset by this try conditional.
+ */
+ (void)cleanup_conditionals(cstack, CSF_TRY | CSF_SILENT, TRUE);
+
+ --cstack->cs_idx;
+ --cstack->cs_trylevel;
+
+ if (!skip)
+ {
+ report_resume_pending(pending,
+ (pending == CSTP_RETURN) ? rettv :
+ (pending & CSTP_THROW) ? (void *)current_exception : NULL);
+ switch (pending)
+ {
+ case CSTP_NONE:
+ break;
+
+ /* Reactivate a pending ":continue", ":break", ":return",
+ * ":finish" from the try block or a catch clause of this try
+ * conditional. This is skipped, if there was an error in an
+ * (unskipped) conditional command or an interrupt afterwards
+ * or if the finally clause is present and executed a new error,
+ * interrupt, throw, ":continue", ":break", ":return", or
+ * ":finish". */
+ case CSTP_CONTINUE:
+ ex_continue(eap);
+ break;
+ case CSTP_BREAK:
+ ex_break(eap);
+ break;
+ case CSTP_RETURN:
+ do_return(eap, FALSE, FALSE, rettv);
+ break;
+ case CSTP_FINISH:
+ do_finish(eap, FALSE);
+ break;
+
+ /* When the finally clause was entered due to an error,
+ * interrupt or throw (as opposed to a ":continue", ":break",
+ * ":return", or ":finish"), restore the pending values of
+ * did_emsg, got_int, and did_throw. This is skipped, if there
+ * was a new error, interrupt, throw, ":continue", ":break",
+ * ":return", or ":finish". in the finally clause. */
+ default:
+ if (pending & CSTP_ERROR)
+ did_emsg = TRUE;
+ if (pending & CSTP_INTERRUPT)
+ got_int = TRUE;
+ if (pending & CSTP_THROW)
+ rethrow = TRUE;
+ break;
+ }
+ }
+
+ if (rethrow)
+ /* Rethrow the current exception (within this cstack). */
+ do_throw(cstack);
+ }
+}
+
+/*
+ * enter_cleanup() and leave_cleanup()
+ *
+ * Functions to be called before/after invoking a sequence of autocommands for
+ * cleanup for a failed command. (Failure means here that a call to emsg()
+ * has been made, an interrupt occurred, or there is an uncaught exception
+ * from a previous autocommand execution of the same command.)
+ *
+ * Call enter_cleanup() with a pointer to a cleanup_T and pass the same
+ * pointer to leave_cleanup(). The cleanup_T structure stores the pending
+ * error/interrupt/exception state.
+ */
+
+/*
+ * This function works a bit like ex_finally() except that there was not
+ * actually an extra try block around the part that failed and an error or
+ * interrupt has not (yet) been converted to an exception. This function
+ * saves the error/interrupt/ exception state and prepares for the call to
+ * do_cmdline() that is going to be made for the cleanup autocommand
+ * execution.
+ */
+ void
+enter_cleanup(cleanup_T *csp)
+{
+ int pending = CSTP_NONE;
+
+ /*
+ * Postpone did_emsg, got_int, did_throw. The pending values will be
+ * restored by leave_cleanup() except if there was an aborting error,
+ * interrupt, or uncaught exception after this function ends.
+ */
+ if (did_emsg || got_int || did_throw || need_rethrow)
+ {
+ csp->pending = (did_emsg ? CSTP_ERROR : 0)
+ | (got_int ? CSTP_INTERRUPT : 0)
+ | (did_throw ? CSTP_THROW : 0)
+ | (need_rethrow ? CSTP_THROW : 0);
+
+ /* If we are currently throwing an exception (did_throw), save it as
+ * well. On an error not yet converted to an exception, update
+ * "force_abort" and reset "cause_abort" (as do_errthrow() would do).
+ * This is needed for the do_cmdline() call that is going to be made
+ * for autocommand execution. We need not save *msg_list because
+ * there is an extra instance for every call of do_cmdline(), anyway.
+ */
+ if (did_throw || need_rethrow)
+ {
+ csp->exception = current_exception;
+ current_exception = NULL;
+ }
+ else
+ {
+ csp->exception = NULL;
+ if (did_emsg)
+ {
+ force_abort |= cause_abort;
+ cause_abort = FALSE;
+ }
+ }
+ did_emsg = got_int = did_throw = need_rethrow = FALSE;
+
+ /* Report if required by the 'verbose' option or when debugging. */
+ report_make_pending(pending, csp->exception);
+ }
+ else
+ {
+ csp->pending = CSTP_NONE;
+ csp->exception = NULL;
+ }
+}
+
+/*
+ * See comment above enter_cleanup() for how this function is used.
+ *
+ * This function is a bit like ex_endtry() except that there was not actually
+ * an extra try block around the part that failed and an error or interrupt
+ * had not (yet) been converted to an exception when the cleanup autocommand
+ * sequence was invoked.
+ *
+ * This function has to be called with the address of the cleanup_T structure
+ * filled by enter_cleanup() as an argument; it restores the error/interrupt/
+ * exception state saved by that function - except there was an aborting
+ * error, an interrupt or an uncaught exception during execution of the
+ * cleanup autocommands. In the latter case, the saved error/interrupt/
+ * exception state is discarded.
+ */
+ void
+leave_cleanup(cleanup_T *csp)
+{
+ int pending = csp->pending;
+
+ if (pending == CSTP_NONE) /* nothing to do */
+ return;
+
+ /* If there was an aborting error, an interrupt, or an uncaught exception
+ * after the corresponding call to enter_cleanup(), discard what has been
+ * made pending by it. Report this to the user if required by the
+ * 'verbose' option or when debugging. */
+ if (aborting() || need_rethrow)
+ {
+ if (pending & CSTP_THROW)
+ /* Cancel the pending exception (includes report). */
+ discard_exception((except_T *)csp->exception, FALSE);
+ else
+ report_discard_pending(pending, NULL);
+
+ /* If an error was about to be converted to an exception when
+ * enter_cleanup() was called, free the message list. */
+ if (msg_list != NULL)
+ free_global_msglist();
+ }
+
+ /*
+ * If there was no new error, interrupt, or throw between the calls
+ * to enter_cleanup() and leave_cleanup(), restore the pending
+ * error/interrupt/exception state.
+ */
+ else
+ {
+ /*
+ * If there was an exception being thrown when enter_cleanup() was
+ * called, we need to rethrow it. Make it the exception currently
+ * being thrown.
+ */
+ if (pending & CSTP_THROW)
+ current_exception = csp->exception;
+
+ /*
+ * If an error was about to be converted to an exception when
+ * enter_cleanup() was called, let "cause_abort" take the part of
+ * "force_abort" (as done by cause_errthrow()).
+ */
+ else if (pending & CSTP_ERROR)
+ {
+ cause_abort = force_abort;
+ force_abort = FALSE;
+ }
+
+ /*
+ * Restore the pending values of did_emsg, got_int, and did_throw.
+ */
+ if (pending & CSTP_ERROR)
+ did_emsg = TRUE;
+ if (pending & CSTP_INTERRUPT)
+ got_int = TRUE;
+ if (pending & CSTP_THROW)
+ need_rethrow = TRUE; /* did_throw will be set by do_one_cmd() */
+
+ /* Report if required by the 'verbose' option or when debugging. */
+ report_resume_pending(pending,
+ (pending & CSTP_THROW) ? (void *)current_exception : NULL);
+ }
+}
+
+
+/*
+ * Make conditionals inactive and discard what's pending in finally clauses
+ * until the conditional type searched for or a try conditional not in its
+ * finally clause is reached. If this is in an active catch clause, finish
+ * the caught exception.
+ * Return the cstack index where the search stopped.
+ * Values used for "searched_cond" are (CSF_WHILE | CSF_FOR) or CSF_TRY or 0,
+ * the latter meaning the innermost try conditional not in its finally clause.
+ * "inclusive" tells whether the conditional searched for should be made
+ * inactive itself (a try conditional not in its finally clause possibly find
+ * before is always made inactive). If "inclusive" is TRUE and
+ * "searched_cond" is CSF_TRY|CSF_SILENT, the saved former value of
+ * "emsg_silent", if reset when the try conditional finally reached was
+ * entered, is restored (used by ex_endtry()). This is normally done only
+ * when such a try conditional is left.
+ */
+ int
+cleanup_conditionals(
+ struct condstack *cstack,
+ int searched_cond,
+ int inclusive)
+{
+ int idx;
+ int stop = FALSE;
+
+ for (idx = cstack->cs_idx; idx >= 0; --idx)
+ {
+ if (cstack->cs_flags[idx] & CSF_TRY)
+ {
+ /*
+ * Discard anything pending in a finally clause and continue the
+ * search. There may also be a pending ":continue", ":break",
+ * ":return", or ":finish" before the finally clause. We must not
+ * discard it, unless an error or interrupt occurred afterwards.
+ */
+ if (did_emsg || got_int || (cstack->cs_flags[idx] & CSF_FINALLY))
+ {
+ switch (cstack->cs_pending[idx])
+ {
+ case CSTP_NONE:
+ break;
+
+ case CSTP_CONTINUE:
+ case CSTP_BREAK:
+ case CSTP_FINISH:
+ report_discard_pending(cstack->cs_pending[idx], NULL);
+ cstack->cs_pending[idx] = CSTP_NONE;
+ break;
+
+ case CSTP_RETURN:
+ report_discard_pending(CSTP_RETURN,
+ cstack->cs_rettv[idx]);
+ discard_pending_return(cstack->cs_rettv[idx]);
+ cstack->cs_pending[idx] = CSTP_NONE;
+ break;
+
+ default:
+ if (cstack->cs_flags[idx] & CSF_FINALLY)
+ {
+ if (cstack->cs_pending[idx] & CSTP_THROW)
+ {
+ /* Cancel the pending exception. This is in the
+ * finally clause, so that the stack of the
+ * caught exceptions is not involved. */
+ discard_exception((except_T *)
+ cstack->cs_exception[idx],
+ FALSE);
+ }
+ else
+ report_discard_pending(cstack->cs_pending[idx],
+ NULL);
+ cstack->cs_pending[idx] = CSTP_NONE;
+ }
+ break;
+ }
+ }
+
+ /*
+ * Stop at a try conditional not in its finally clause. If this try
+ * conditional is in an active catch clause, finish the caught
+ * exception.
+ */
+ if (!(cstack->cs_flags[idx] & CSF_FINALLY))
+ {
+ if ((cstack->cs_flags[idx] & CSF_ACTIVE)
+ && (cstack->cs_flags[idx] & CSF_CAUGHT))
+ finish_exception((except_T *)cstack->cs_exception[idx]);
+ /* Stop at this try conditional - except the try block never
+ * got active (because of an inactive surrounding conditional
+ * or when the ":try" appeared after an error or interrupt or
+ * throw). */
+ if (cstack->cs_flags[idx] & CSF_TRUE)
+ {
+ if (searched_cond == 0 && !inclusive)
+ break;
+ stop = TRUE;
+ }
+ }
+ }
+
+ /* Stop on the searched conditional type (even when the surrounding
+ * conditional is not active or something has been made pending).
+ * If "inclusive" is TRUE and "searched_cond" is CSF_TRY|CSF_SILENT,
+ * check first whether "emsg_silent" needs to be restored. */
+ if (cstack->cs_flags[idx] & searched_cond)
+ {
+ if (!inclusive)
+ break;
+ stop = TRUE;
+ }
+ cstack->cs_flags[idx] &= ~CSF_ACTIVE;
+ if (stop && searched_cond != (CSF_TRY | CSF_SILENT))
+ break;
+
+ /*
+ * When leaving a try conditional that reset "emsg_silent" on its
+ * entry after saving the original value, restore that value here and
+ * free the memory used to store it.
+ */
+ if ((cstack->cs_flags[idx] & CSF_TRY)
+ && (cstack->cs_flags[idx] & CSF_SILENT))
+ {
+ eslist_T *elem;
+
+ elem = cstack->cs_emsg_silent_list;
+ cstack->cs_emsg_silent_list = elem->next;
+ emsg_silent = elem->saved_emsg_silent;
+ vim_free(elem);
+ cstack->cs_flags[idx] &= ~CSF_SILENT;
+ }
+ if (stop)
+ break;
+ }
+ return idx;
+}
+
+/*
+ * Return an appropriate error message for a missing endwhile/endfor/endif.
+ */
+ static char *
+get_end_emsg(struct condstack *cstack)
+{
+ if (cstack->cs_flags[cstack->cs_idx] & CSF_WHILE)
+ return e_endwhile;
+ if (cstack->cs_flags[cstack->cs_idx] & CSF_FOR)
+ return e_endfor;
+ return e_endif;
+}
+
+
+/*
+ * Rewind conditionals until index "idx" is reached. "cond_type" and
+ * "cond_level" specify a conditional type and the address of a level variable
+ * which is to be decremented with each skipped conditional of the specified
+ * type.
+ * Also free "for info" structures where needed.
+ */
+ void
+rewind_conditionals(
+ struct condstack *cstack,
+ int idx,
+ int cond_type,
+ int *cond_level)
+{
+ while (cstack->cs_idx > idx)
+ {
+ if (cstack->cs_flags[cstack->cs_idx] & cond_type)
+ --*cond_level;
+ if (cstack->cs_flags[cstack->cs_idx] & CSF_FOR)
+ free_for_info(cstack->cs_forinfo[cstack->cs_idx]);
+ --cstack->cs_idx;
+ }
+}
+
+/*
+ * ":endfunction" when not after a ":function"
+ */
+ void
+ex_endfunction(exarg_T *eap UNUSED)
+{
+ emsg(_("E193: :endfunction not inside a function"));
+}
+
+/*
+ * Return TRUE if the string "p" looks like a ":while" or ":for" command.
+ */
+ int
+has_loop_cmd(char_u *p)
+{
+ int len;
+
+ /* skip modifiers, white space and ':' */
+ for (;;)
+ {
+ while (*p == ' ' || *p == '\t' || *p == ':')
+ ++p;
+ len = modifier_len(p);
+ if (len == 0)
+ break;
+ p += len;
+ }
+ if ((p[0] == 'w' && p[1] == 'h')
+ || (p[0] == 'f' && p[1] == 'o' && p[2] == 'r'))
+ return TRUE;
+ return FALSE;
+}
+
+#endif /* FEAT_EVAL */
diff --git a/src/ex_getln.c b/src/ex_getln.c
new file mode 100644
index 0000000..cba082a
--- /dev/null
+++ b/src/ex_getln.c
@@ -0,0 +1,7484 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * ex_getln.c: Functions for entering and editing an Ex command line.
+ */
+
+#include "vim.h"
+
+#ifndef MAX
+# define MAX(x,y) ((x) > (y) ? (x) : (y))
+#endif
+
+/*
+ * Variables shared between getcmdline(), redrawcmdline() and others.
+ * These need to be saved when using CTRL-R |, that's why they are in a
+ * structure.
+ */
+struct cmdline_info
+{
+ char_u *cmdbuff; /* pointer to command line buffer */
+ int cmdbufflen; /* length of cmdbuff */
+ int cmdlen; /* number of chars in command line */
+ int cmdpos; /* current cursor position */
+ int cmdspos; /* cursor column on screen */
+ int cmdfirstc; /* ':', '/', '?', '=', '>' or NUL */
+ int cmdindent; /* number of spaces before cmdline */
+ char_u *cmdprompt; /* message in front of cmdline */
+ int cmdattr; /* attributes for prompt */
+ int overstrike; /* Typing mode on the command line. Shared by
+ getcmdline() and put_on_cmdline(). */
+ expand_T *xpc; /* struct being used for expansion, xp_pattern
+ may point into cmdbuff */
+ int xp_context; /* type of expansion */
+# ifdef FEAT_EVAL
+ char_u *xp_arg; /* user-defined expansion arg */
+ int input_fn; /* when TRUE Invoked for input() function */
+# endif
+};
+
+// The current cmdline_info. It is initialized in getcmdline() and after that
+// used by other functions. When invoking getcmdline() recursively it needs
+// to be saved with save_cmdline() and restored with restore_cmdline().
+static struct cmdline_info ccline;
+
+static int cmd_showtail; /* Only show path tail in lists ? */
+
+#ifdef FEAT_EVAL
+static int new_cmdpos; /* position set by set_cmdline_pos() */
+#endif
+
+static int extra_char = NUL; /* extra character to display when redrawing
+ * the command line */
+static int extra_char_shift;
+
+#ifdef FEAT_CMDHIST
+typedef struct hist_entry
+{
+ int hisnum; /* identifying number */
+ int viminfo; /* when TRUE hisstr comes from viminfo */
+ char_u *hisstr; /* actual entry, separator char after the NUL */
+ time_t time_set; /* when it was typed, zero if unknown */
+} histentry_T;
+
+static histentry_T *(history[HIST_COUNT]) = {NULL, NULL, NULL, NULL, NULL};
+static int hisidx[HIST_COUNT] = {-1, -1, -1, -1, -1}; /* lastused entry */
+static int hisnum[HIST_COUNT] = {0, 0, 0, 0, 0};
+ /* identifying (unique) number of newest history entry */
+static int hislen = 0; /* actual length of history tables */
+
+static int hist_char2type(int c);
+#endif
+
+#ifdef FEAT_RIGHTLEFT
+static int cmd_hkmap = 0; /* Hebrew mapping during command line */
+#endif
+
+#ifdef FEAT_FKMAP
+static int cmd_fkmap = 0; /* Farsi mapping during command line */
+#endif
+
+static char_u *getcmdline_int(int firstc, long count, int indent, int init_ccline);
+static int cmdline_charsize(int idx);
+static void set_cmdspos(void);
+static void set_cmdspos_cursor(void);
+static void correct_cmdspos(int idx, int cells);
+static void alloc_cmdbuff(int len);
+static int realloc_cmdbuff(int len);
+static void draw_cmdline(int start, int len);
+static void save_cmdline(struct cmdline_info *ccp);
+static void restore_cmdline(struct cmdline_info *ccp);
+static int cmdline_paste(int regname, int literally, int remcr);
+#ifdef FEAT_WILDMENU
+static void cmdline_del(int from);
+#endif
+static void redrawcmdprompt(void);
+static void cursorcmd(void);
+static int ccheck_abbr(int);
+static int nextwild(expand_T *xp, int type, int options, int escape);
+static void escape_fname(char_u **pp);
+static int showmatches(expand_T *xp, int wildmenu);
+static void set_expand_context(expand_T *xp);
+static int ExpandFromContext(expand_T *xp, char_u *, int *, char_u ***, int);
+static int expand_showtail(expand_T *xp);
+#ifdef FEAT_CMDL_COMPL
+static int expand_shellcmd(char_u *filepat, int *num_file, char_u ***file, int flagsarg);
+static int ExpandRTDir(char_u *pat, int flags, int *num_file, char_u ***file, char *dirname[]);
+static int ExpandPackAddDir(char_u *pat, int *num_file, char_u ***file);
+# ifdef FEAT_CMDHIST
+static char_u *get_history_arg(expand_T *xp, int idx);
+# endif
+# if defined(FEAT_USR_CMDS) && defined(FEAT_EVAL)
+static int ExpandUserDefined(expand_T *xp, regmatch_T *regmatch, int *num_file, char_u ***file);
+static int ExpandUserList(expand_T *xp, int *num_file, char_u ***file);
+# endif
+#endif
+#ifdef FEAT_CMDHIST
+static void clear_hist_entry(histentry_T *hisptr);
+#endif
+
+#ifdef FEAT_CMDWIN
+static int open_cmdwin(void);
+#endif
+
+#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
+static int
+#ifdef __BORLANDC__
+_RTLENTRYF
+#endif
+sort_func_compare(const void *s1, const void *s2);
+#endif
+
+
+ static void
+trigger_cmd_autocmd(int typechar, int evt)
+{
+ char_u typestr[2];
+
+ typestr[0] = typechar;
+ typestr[1] = NUL;
+ apply_autocmds(evt, typestr, typestr, FALSE, curbuf);
+}
+
+/*
+ * Abandon the command line.
+ */
+ static void
+abandon_cmdline(void)
+{
+ VIM_CLEAR(ccline.cmdbuff);
+ if (msg_scrolled == 0)
+ compute_cmdrow();
+ msg("");
+ redraw_cmdline = TRUE;
+}
+
+#ifdef FEAT_SEARCH_EXTRA
+/*
+ * Guess that the pattern matches everything. Only finds specific cases, such
+ * as a trailing \|, which can happen while typing a pattern.
+ */
+ static int
+empty_pattern(char_u *p)
+{
+ size_t n = STRLEN(p);
+
+ /* remove trailing \v and the like */
+ while (n >= 2 && p[n - 2] == '\\'
+ && vim_strchr((char_u *)"mMvVcCZ", p[n - 1]) != NULL)
+ n -= 2;
+ return n == 0 || (n >= 2 && p[n - 2] == '\\' && p[n - 1] == '|');
+}
+
+// Struct to store the viewstate during 'incsearch' highlighting.
+typedef struct {
+ colnr_T vs_curswant;
+ colnr_T vs_leftcol;
+ linenr_T vs_topline;
+# ifdef FEAT_DIFF
+ int vs_topfill;
+# endif
+ linenr_T vs_botline;
+ linenr_T vs_empty_rows;
+} viewstate_T;
+
+ static void
+save_viewstate(viewstate_T *vs)
+{
+ vs->vs_curswant = curwin->w_curswant;
+ vs->vs_leftcol = curwin->w_leftcol;
+ vs->vs_topline = curwin->w_topline;
+# ifdef FEAT_DIFF
+ vs->vs_topfill = curwin->w_topfill;
+# endif
+ vs->vs_botline = curwin->w_botline;
+ vs->vs_empty_rows = curwin->w_empty_rows;
+}
+
+ static void
+restore_viewstate(viewstate_T *vs)
+{
+ curwin->w_curswant = vs->vs_curswant;
+ curwin->w_leftcol = vs->vs_leftcol;
+ curwin->w_topline = vs->vs_topline;
+# ifdef FEAT_DIFF
+ curwin->w_topfill = vs->vs_topfill;
+# endif
+ curwin->w_botline = vs->vs_botline;
+ curwin->w_empty_rows = vs->vs_empty_rows;
+}
+
+// Struct to store the state of 'incsearch' highlighting.
+typedef struct {
+ pos_T search_start; // where 'incsearch' starts searching
+ pos_T save_cursor;
+ viewstate_T init_viewstate;
+ viewstate_T old_viewstate;
+ pos_T match_start;
+ pos_T match_end;
+ int did_incsearch;
+ int incsearch_postponed;
+ int magic_save;
+} incsearch_state_T;
+
+ static void
+init_incsearch_state(incsearch_state_T *is_state)
+{
+ is_state->match_start = curwin->w_cursor;
+ is_state->did_incsearch = FALSE;
+ is_state->incsearch_postponed = FALSE;
+ is_state->magic_save = p_magic;
+ CLEAR_POS(&is_state->match_end);
+ is_state->save_cursor = curwin->w_cursor; // may be restored later
+ is_state->search_start = curwin->w_cursor;
+ save_viewstate(&is_state->init_viewstate);
+ save_viewstate(&is_state->old_viewstate);
+}
+
+/*
+ * First move cursor to end of match, then to the start. This
+ * moves the whole match onto the screen when 'nowrap' is set.
+ */
+ static void
+set_search_match(pos_T *t)
+{
+ t->lnum += search_match_lines;
+ t->col = search_match_endcol;
+ if (t->lnum > curbuf->b_ml.ml_line_count)
+ {
+ t->lnum = curbuf->b_ml.ml_line_count;
+ coladvance((colnr_T)MAXCOL);
+ }
+}
+
+/*
+ * Return TRUE when 'incsearch' highlighting is to be done.
+ * Sets search_first_line and search_last_line to the address range.
+ * May change the last search pattern.
+ */
+ static int
+do_incsearch_highlighting(int firstc, incsearch_state_T *is_state,
+ int *skiplen, int *patlen)
+{
+ char_u *cmd;
+ cmdmod_T save_cmdmod = cmdmod;
+ char_u *p;
+ int delim_optional = FALSE;
+ int delim;
+ char_u *end;
+ char *dummy;
+ exarg_T ea;
+ pos_T save_cursor;
+ int use_last_pat;
+
+ *skiplen = 0;
+ *patlen = ccline.cmdlen;
+
+ if (!p_is || cmd_silent)
+ return FALSE;
+
+ // by default search all lines
+ search_first_line = 0;
+ search_last_line = MAXLNUM;
+
+ if (firstc == '/' || firstc == '?')
+ return TRUE;
+ if (firstc != ':')
+ return FALSE;
+
+ vim_memset(&ea, 0, sizeof(ea));
+ ea.line1 = 1;
+ ea.line2 = 1;
+ ea.cmd = ccline.cmdbuff;
+ ea.addr_type = ADDR_LINES;
+
+ parse_command_modifiers(&ea, &dummy, TRUE);
+ cmdmod = save_cmdmod;
+
+ cmd = skip_range(ea.cmd, NULL);
+ if (vim_strchr((char_u *)"sgvl", *cmd) == NULL)
+ return FALSE;
+
+ // Skip over "substitute" to find the pattern separator.
+ for (p = cmd; ASCII_ISALPHA(*p); ++p)
+ ;
+ if (*skipwhite(p) == NUL)
+ return FALSE;
+
+ if (STRNCMP(cmd, "substitute", p - cmd) == 0
+ || STRNCMP(cmd, "smagic", p - cmd) == 0
+ || STRNCMP(cmd, "snomagic", MAX(p - cmd, 3)) == 0
+ || STRNCMP(cmd, "vglobal", p - cmd) == 0)
+ {
+ if (*cmd == 's' && cmd[1] == 'm')
+ p_magic = TRUE;
+ else if (*cmd == 's' && cmd[1] == 'n')
+ p_magic = FALSE;
+ }
+ else if (STRNCMP(cmd, "sort", MAX(p - cmd, 3)) == 0)
+ {
+ // skip over flags
+ while (ASCII_ISALPHA(*(p = skipwhite(p))))
+ ++p;
+ if (*p == NUL)
+ return FALSE;
+ }
+ else if (STRNCMP(cmd, "vimgrep", MAX(p - cmd, 3)) == 0
+ || STRNCMP(cmd, "vimgrepadd", MAX(p - cmd, 8)) == 0
+ || STRNCMP(cmd, "lvimgrep", MAX(p - cmd, 2)) == 0
+ || STRNCMP(cmd, "lvimgrepadd", MAX(p - cmd, 9)) == 0
+ || STRNCMP(cmd, "global", p - cmd) == 0)
+ {
+ // skip over "!"
+ if (*p == '!')
+ {
+ p++;
+ if (*skipwhite(p) == NUL)
+ return FALSE;
+ }
+ if (*cmd != 'g')
+ delim_optional = TRUE;
+ }
+ else
+ return FALSE;
+
+ p = skipwhite(p);
+ delim = (delim_optional && vim_isIDc(*p)) ? ' ' : *p++;
+ end = skip_regexp(p, delim, p_magic, NULL);
+
+ use_last_pat = end == p && *end == delim;
+
+ if (end == p && !use_last_pat)
+ return FALSE;
+
+ // Don't do 'hlsearch' highlighting if the pattern matches everything.
+ if (!use_last_pat)
+ {
+ char c = *end;
+ int empty;
+
+ *end = NUL;
+ empty = empty_pattern(p);
+ *end = c;
+ if (empty)
+ return FALSE;
+ }
+
+ // found a non-empty pattern or //
+ *skiplen = (int)(p - ccline.cmdbuff);
+ *patlen = (int)(end - p);
+
+ // parse the address range
+ save_cursor = curwin->w_cursor;
+ curwin->w_cursor = is_state->search_start;
+ parse_cmd_address(&ea, &dummy, TRUE);
+ if (ea.addr_count > 0)
+ {
+ // Allow for reverse match.
+ if (ea.line2 < ea.line1)
+ {
+ search_first_line = ea.line2;
+ search_last_line = ea.line1;
+ }
+ else
+ {
+ search_first_line = ea.line1;
+ search_last_line = ea.line2;
+ }
+ }
+ else if (cmd[0] == 's' && cmd[1] != 'o')
+ {
+ // :s defaults to the current line
+ search_first_line = curwin->w_cursor.lnum;
+ search_last_line = curwin->w_cursor.lnum;
+ }
+
+ curwin->w_cursor = save_cursor;
+ return TRUE;
+}
+
+ static void
+finish_incsearch_highlighting(
+ int gotesc,
+ incsearch_state_T *is_state,
+ int call_update_screen)
+{
+ if (is_state->did_incsearch)
+ {
+ is_state->did_incsearch = FALSE;
+ if (gotesc)
+ curwin->w_cursor = is_state->save_cursor;
+ else
+ {
+ if (!EQUAL_POS(is_state->save_cursor, is_state->search_start))
+ {
+ // put the '" mark at the original position
+ curwin->w_cursor = is_state->save_cursor;
+ setpcmark();
+ }
+ curwin->w_cursor = is_state->search_start;
+ }
+ restore_viewstate(&is_state->old_viewstate);
+ highlight_match = FALSE;
+
+ // by default search all lines
+ search_first_line = 0;
+ search_last_line = MAXLNUM;
+
+ p_magic = is_state->magic_save;
+
+ validate_cursor(); /* needed for TAB */
+ redraw_all_later(SOME_VALID);
+ if (call_update_screen)
+ update_screen(SOME_VALID);
+ }
+}
+
+/*
+ * Do 'incsearch' highlighting if desired.
+ */
+ static void
+may_do_incsearch_highlighting(
+ int firstc,
+ long count,
+ incsearch_state_T *is_state)
+{
+ int skiplen, patlen;
+ int found; // do_search() result
+ pos_T end_pos;
+#ifdef FEAT_RELTIME
+ proftime_T tm;
+#endif
+ int next_char;
+ int use_last_pat;
+
+ // Parsing range may already set the last search pattern.
+ // NOTE: must call restore_last_search_pattern() before returning!
+ save_last_search_pattern();
+
+ if (!do_incsearch_highlighting(firstc, is_state, &skiplen, &patlen))
+ {
+ restore_last_search_pattern();
+ finish_incsearch_highlighting(FALSE, is_state, TRUE);
+ return;
+ }
+
+ // If there is a character waiting, search and redraw later.
+ if (char_avail())
+ {
+ restore_last_search_pattern();
+ is_state->incsearch_postponed = TRUE;
+ return;
+ }
+ is_state->incsearch_postponed = FALSE;
+
+ if (search_first_line == 0)
+ // start at the original cursor position
+ curwin->w_cursor = is_state->search_start;
+ else if (search_first_line > curbuf->b_ml.ml_line_count)
+ {
+ // start after the last line
+ curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
+ curwin->w_cursor.col = MAXCOL;
+ }
+ else
+ {
+ // start at the first line in the range
+ curwin->w_cursor.lnum = search_first_line;
+ curwin->w_cursor.col = 0;
+ }
+
+ // Use the previous pattern for ":s//".
+ next_char = ccline.cmdbuff[skiplen + patlen];
+ use_last_pat = patlen == 0 && skiplen > 0
+ && ccline.cmdbuff[skiplen - 1] == next_char;
+
+ // If there is no pattern, don't do anything.
+ if (patlen == 0 && !use_last_pat)
+ {
+ found = 0;
+ set_no_hlsearch(TRUE); // turn off previous highlight
+ redraw_all_later(SOME_VALID);
+ }
+ else
+ {
+ int search_flags = SEARCH_OPT + SEARCH_NOOF + SEARCH_PEEK;
+
+ cursor_off(); // so the user knows we're busy
+ out_flush();
+ ++emsg_off; // so it doesn't beep if bad expr
+#ifdef FEAT_RELTIME
+ // Set the time limit to half a second.
+ profile_setlimit(500L, &tm);
+#endif
+ if (!p_hls)
+ search_flags += SEARCH_KEEP;
+ if (search_first_line != 0)
+ search_flags += SEARCH_START;
+ ccline.cmdbuff[skiplen + patlen] = NUL;
+ found = do_search(NULL, firstc == ':' ? '/' : firstc,
+ ccline.cmdbuff + skiplen, count, search_flags,
+#ifdef FEAT_RELTIME
+ &tm, NULL
+#else
+ NULL, NULL
+#endif
+ );
+ ccline.cmdbuff[skiplen + patlen] = next_char;
+ --emsg_off;
+
+ if (curwin->w_cursor.lnum < search_first_line
+ || curwin->w_cursor.lnum > search_last_line)
+ {
+ // match outside of address range
+ found = 0;
+ curwin->w_cursor = is_state->search_start;
+ }
+
+ // if interrupted while searching, behave like it failed
+ if (got_int)
+ {
+ (void)vpeekc(); // remove <C-C> from input stream
+ got_int = FALSE; // don't abandon the command line
+ found = 0;
+ }
+ else if (char_avail())
+ // cancelled searching because a char was typed
+ is_state->incsearch_postponed = TRUE;
+ }
+ if (found != 0)
+ highlight_match = TRUE; // highlight position
+ else
+ highlight_match = FALSE; // remove highlight
+
+ // First restore the old curwin values, so the screen is positioned in the
+ // same way as the actual search command.
+ restore_viewstate(&is_state->old_viewstate);
+ changed_cline_bef_curs();
+ update_topline();
+
+ if (found != 0)
+ {
+ pos_T save_pos = curwin->w_cursor;
+
+ is_state->match_start = curwin->w_cursor;
+ set_search_match(&curwin->w_cursor);
+ validate_cursor();
+ end_pos = curwin->w_cursor;
+ is_state->match_end = end_pos;
+ curwin->w_cursor = save_pos;
+ }
+ else
+ end_pos = curwin->w_cursor; // shutup gcc 4
+
+ // Disable 'hlsearch' highlighting if the pattern matches everything.
+ // Avoids a flash when typing "foo\|".
+ if (!use_last_pat)
+ {
+ next_char = ccline.cmdbuff[skiplen + patlen];
+ ccline.cmdbuff[skiplen + patlen] = NUL;
+ if (empty_pattern(ccline.cmdbuff) && !no_hlsearch)
+ {
+ redraw_all_later(SOME_VALID);
+ set_no_hlsearch(TRUE);
+ }
+ ccline.cmdbuff[skiplen + patlen] = next_char;
+ }
+
+ validate_cursor();
+ // May redraw the status line to show the cursor position.
+ if (p_ru && curwin->w_status_height > 0)
+ curwin->w_redr_status = TRUE;
+
+ update_screen(SOME_VALID);
+ restore_last_search_pattern();
+
+ // Leave it at the end to make CTRL-R CTRL-W work. But not when beyond the
+ // end of the pattern, e.g. for ":s/pat/".
+ if (ccline.cmdbuff[skiplen + patlen] != NUL)
+ curwin->w_cursor = is_state->search_start;
+ else if (found != 0)
+ curwin->w_cursor = end_pos;
+
+ msg_starthere();
+ redrawcmdline();
+ is_state->did_incsearch = TRUE;
+}
+
+/*
+ * May adjust 'incsearch' highlighting for typing CTRL-G and CTRL-T, go to next
+ * or previous match.
+ * Returns FAIL when jumping to cmdline_not_changed;
+ */
+ static int
+may_adjust_incsearch_highlighting(
+ int firstc,
+ long count,
+ incsearch_state_T *is_state,
+ int c)
+{
+ int skiplen, patlen;
+ pos_T t;
+ char_u *pat;
+ int search_flags = SEARCH_NOOF;
+ int i;
+ int save;
+
+ // Parsing range may already set the last search pattern.
+ // NOTE: must call restore_last_search_pattern() before returning!
+ save_last_search_pattern();
+
+ if (!do_incsearch_highlighting(firstc, is_state, &skiplen, &patlen))
+ {
+ restore_last_search_pattern();
+ return OK;
+ }
+ if (patlen == 0 && ccline.cmdbuff[skiplen] == NUL)
+ {
+ restore_last_search_pattern();
+ return FAIL;
+ }
+
+ if (firstc == ccline.cmdbuff[skiplen])
+ {
+ pat = last_search_pattern();
+ skiplen = 0;
+ patlen = (int)STRLEN(pat);
+ }
+ else
+ pat = ccline.cmdbuff + skiplen;
+
+ cursor_off();
+ out_flush();
+ if (c == Ctrl_G)
+ {
+ t = is_state->match_end;
+ if (LT_POS(is_state->match_start, is_state->match_end))
+ // Start searching at the end of the match not at the beginning of
+ // the next column.
+ (void)decl(&t);
+ search_flags += SEARCH_COL;
+ }
+ else
+ t = is_state->match_start;
+ if (!p_hls)
+ search_flags += SEARCH_KEEP;
+ ++emsg_off;
+ save = pat[patlen];
+ pat[patlen] = NUL;
+ i = searchit(curwin, curbuf, &t, NULL,
+ c == Ctrl_G ? FORWARD : BACKWARD,
+ pat, count, search_flags,
+ RE_SEARCH, 0, NULL, NULL);
+ --emsg_off;
+ pat[patlen] = save;
+ if (i)
+ {
+ is_state->search_start = is_state->match_start;
+ is_state->match_end = t;
+ is_state->match_start = t;
+ if (c == Ctrl_T && firstc != '?')
+ {
+ // Move just before the current match, so that when nv_search
+ // finishes the cursor will be put back on the match.
+ is_state->search_start = t;
+ (void)decl(&is_state->search_start);
+ }
+ else if (c == Ctrl_G && firstc == '?')
+ {
+ // Move just after the current match, so that when nv_search
+ // finishes the cursor will be put back on the match.
+ is_state->search_start = t;
+ (void)incl(&is_state->search_start);
+ }
+ if (LT_POS(t, is_state->search_start) && c == Ctrl_G)
+ {
+ // wrap around
+ is_state->search_start = t;
+ if (firstc == '?')
+ (void)incl(&is_state->search_start);
+ else
+ (void)decl(&is_state->search_start);
+ }
+
+ set_search_match(&is_state->match_end);
+ curwin->w_cursor = is_state->match_start;
+ changed_cline_bef_curs();
+ update_topline();
+ validate_cursor();
+ highlight_match = TRUE;
+ save_viewstate(&is_state->old_viewstate);
+ update_screen(NOT_VALID);
+ redrawcmdline();
+ }
+ else
+ vim_beep(BO_ERROR);
+ restore_last_search_pattern();
+ return FAIL;
+}
+
+/*
+ * When CTRL-L typed: add character from the match to the pattern.
+ * May set "*c" to the added character.
+ * Return OK when jumping to cmdline_not_changed.
+ */
+ static int
+may_add_char_to_search(int firstc, int *c, incsearch_state_T *is_state)
+{
+ int skiplen, patlen;
+
+ // Parsing range may already set the last search pattern.
+ // NOTE: must call restore_last_search_pattern() before returning!
+ save_last_search_pattern();
+
+ if (!do_incsearch_highlighting(firstc, is_state, &skiplen, &patlen))
+ {
+ restore_last_search_pattern();
+ return FAIL;
+ }
+ restore_last_search_pattern();
+
+ // Add a character from under the cursor for 'incsearch'.
+ if (is_state->did_incsearch)
+ {
+ curwin->w_cursor = is_state->match_end;
+ if (!EQUAL_POS(curwin->w_cursor, is_state->search_start))
+ {
+ *c = gchar_cursor();
+
+ // If 'ignorecase' and 'smartcase' are set and the
+ // command line has no uppercase characters, convert
+ // the character to lowercase.
+ if (p_ic && p_scs && !pat_has_uppercase(ccline.cmdbuff + skiplen))
+ *c = MB_TOLOWER(*c);
+ if (*c != NUL)
+ {
+ if (*c == firstc || vim_strchr((char_u *)(
+ p_magic ? "\\~^$.*[" : "\\^$"), *c) != NULL)
+ {
+ // put a backslash before special characters
+ stuffcharReadbuff(*c);
+ *c = '\\';
+ }
+ // add any composing characters
+ if (mb_char2len(*c) != mb_ptr2len(ml_get_cursor()))
+ {
+ int save_c = *c;
+
+ while (mb_char2len(*c) != mb_ptr2len(ml_get_cursor()))
+ {
+ curwin->w_cursor.col += mb_char2len(*c);
+ *c = gchar_cursor();
+ stuffcharReadbuff(*c);
+ }
+ *c = save_c;
+ }
+ return FAIL;
+ }
+ }
+ }
+ return OK;
+}
+#endif
+
+ void
+cmdline_init(void)
+{
+ vim_memset(&ccline, 0, sizeof(struct cmdline_info));
+}
+
+/*
+ * getcmdline() - accept a command line starting with firstc.
+ *
+ * firstc == ':' get ":" command line.
+ * firstc == '/' or '?' get search pattern
+ * firstc == '=' get expression
+ * firstc == '@' get text for input() function
+ * firstc == '>' get text for debug mode
+ * firstc == NUL get text for :insert command
+ * firstc == -1 like NUL, and break on CTRL-C
+ *
+ * The line is collected in ccline.cmdbuff, which is reallocated to fit the
+ * command line.
+ *
+ * Careful: getcmdline() can be called recursively!
+ *
+ * Return pointer to allocated string if there is a commandline, NULL
+ * otherwise.
+ */
+ char_u *
+getcmdline(
+ int firstc,
+ long count, // only used for incremental search
+ int indent) // indent for inside conditionals
+{
+ return getcmdline_int(firstc, count, indent, TRUE);
+}
+
+ static char_u *
+getcmdline_int(
+ int firstc,
+ long count UNUSED, // only used for incremental search
+ int indent, // indent for inside conditionals
+ int init_ccline) // clear ccline first
+{
+ int c;
+ int i;
+ int j;
+ int gotesc = FALSE; /* TRUE when <ESC> just typed */
+ int do_abbr; /* when TRUE check for abbr. */
+#ifdef FEAT_CMDHIST
+ char_u *lookfor = NULL; /* string to match */
+ int hiscnt; /* current history line in use */
+ int histype; /* history type to be used */
+#endif
+#ifdef FEAT_SEARCH_EXTRA
+ incsearch_state_T is_state;
+#endif
+ int did_wild_list = FALSE; /* did wild_list() recently */
+ int wim_index = 0; /* index in wim_flags[] */
+ int res;
+ int save_msg_scroll = msg_scroll;
+ int save_State = State; /* remember State when called */
+ int some_key_typed = FALSE; /* one of the keys was typed */
+#ifdef FEAT_MOUSE
+ /* mouse drag and release events are ignored, unless they are
+ * preceded with a mouse down event */
+ int ignore_drag_release = TRUE;
+#endif
+#ifdef FEAT_EVAL
+ int break_ctrl_c = FALSE;
+#endif
+ expand_T xpc;
+ long *b_im_ptr = NULL;
+ struct cmdline_info save_ccline;
+ int did_save_ccline = FALSE;
+ int cmdline_type;
+
+ if (ccline.cmdbuff != NULL)
+ {
+ // Being called recursively. Since ccline is global, we need to save
+ // the current buffer and restore it when returning.
+ save_cmdline(&save_ccline);
+ did_save_ccline = TRUE;
+ }
+ if (init_ccline)
+ vim_memset(&ccline, 0, sizeof(struct cmdline_info));
+
+#ifdef FEAT_EVAL
+ if (firstc == -1)
+ {
+ firstc = NUL;
+ break_ctrl_c = TRUE;
+ }
+#endif
+#ifdef FEAT_RIGHTLEFT
+ /* start without Hebrew mapping for a command line */
+ if (firstc == ':' || firstc == '=' || firstc == '>')
+ cmd_hkmap = 0;
+#endif
+
+ ccline.overstrike = FALSE; /* always start in insert mode */
+
+#ifdef FEAT_SEARCH_EXTRA
+ init_incsearch_state(&is_state);
+#endif
+
+ /*
+ * set some variables for redrawcmd()
+ */
+ ccline.cmdfirstc = (firstc == '@' ? 0 : firstc);
+ ccline.cmdindent = (firstc > 0 ? indent : 0);
+
+ /* alloc initial ccline.cmdbuff */
+ alloc_cmdbuff(exmode_active ? 250 : indent + 1);
+ if (ccline.cmdbuff == NULL)
+ goto theend; // out of memory
+ ccline.cmdlen = ccline.cmdpos = 0;
+ ccline.cmdbuff[0] = NUL;
+ sb_text_start_cmdline();
+
+ /* autoindent for :insert and :append */
+ if (firstc <= 0)
+ {
+ vim_memset(ccline.cmdbuff, ' ', indent);
+ ccline.cmdbuff[indent] = NUL;
+ ccline.cmdpos = indent;
+ ccline.cmdspos = indent;
+ ccline.cmdlen = indent;
+ }
+
+ ExpandInit(&xpc);
+ ccline.xpc = &xpc;
+
+#ifdef FEAT_RIGHTLEFT
+ if (curwin->w_p_rl && *curwin->w_p_rlc == 's'
+ && (firstc == '/' || firstc == '?'))
+ cmdmsg_rl = TRUE;
+ else
+ cmdmsg_rl = FALSE;
+#endif
+
+ redir_off = TRUE; /* don't redirect the typed command */
+ if (!cmd_silent)
+ {
+ i = msg_scrolled;
+ msg_scrolled = 0; /* avoid wait_return message */
+ gotocmdline(TRUE);
+ msg_scrolled += i;
+ redrawcmdprompt(); /* draw prompt or indent */
+ set_cmdspos();
+ }
+ xpc.xp_context = EXPAND_NOTHING;
+ xpc.xp_backslash = XP_BS_NONE;
+#ifndef BACKSLASH_IN_FILENAME
+ xpc.xp_shell = FALSE;
+#endif
+
+#if defined(FEAT_EVAL)
+ if (ccline.input_fn)
+ {
+ xpc.xp_context = ccline.xp_context;
+ xpc.xp_pattern = ccline.cmdbuff;
+# if defined(FEAT_USR_CMDS) && defined(FEAT_CMDL_COMPL)
+ xpc.xp_arg = ccline.xp_arg;
+# endif
+ }
+#endif
+
+ /*
+ * Avoid scrolling when called by a recursive do_cmdline(), e.g. when
+ * doing ":@0" when register 0 doesn't contain a CR.
+ */
+ msg_scroll = FALSE;
+
+ State = CMDLINE;
+
+ if (firstc == '/' || firstc == '?' || firstc == '@')
+ {
+ /* Use ":lmap" mappings for search pattern and input(). */
+ if (curbuf->b_p_imsearch == B_IMODE_USE_INSERT)
+ b_im_ptr = &curbuf->b_p_iminsert;
+ else
+ b_im_ptr = &curbuf->b_p_imsearch;
+ if (*b_im_ptr == B_IMODE_LMAP)
+ State |= LANGMAP;
+#ifdef HAVE_INPUT_METHOD
+ im_set_active(*b_im_ptr == B_IMODE_IM);
+#endif
+ }
+#ifdef HAVE_INPUT_METHOD
+ else if (p_imcmdline)
+ im_set_active(TRUE);
+#endif
+
+#ifdef FEAT_MOUSE
+ setmouse();
+#endif
+#ifdef CURSOR_SHAPE
+ ui_cursor_shape(); /* may show different cursor shape */
+#endif
+
+ /* When inside an autocommand for writing "exiting" may be set and
+ * terminal mode set to cooked. Need to set raw mode here then. */
+ settmode(TMODE_RAW);
+
+ /* Trigger CmdlineEnter autocommands. */
+ cmdline_type = firstc == NUL ? '-' : firstc;
+ trigger_cmd_autocmd(cmdline_type, EVENT_CMDLINEENTER);
+
+#ifdef FEAT_CMDHIST
+ init_history();
+ hiscnt = hislen; /* set hiscnt to impossible history value */
+ histype = hist_char2type(firstc);
+#endif
+
+#ifdef FEAT_DIGRAPHS
+ do_digraph(-1); /* init digraph typeahead */
+#endif
+
+ /* If something above caused an error, reset the flags, we do want to type
+ * and execute commands. Display may be messed up a bit. */
+ if (did_emsg)
+ redrawcmd();
+ did_emsg = FALSE;
+ got_int = FALSE;
+
+ /*
+ * Collect the command string, handling editing keys.
+ */
+ for (;;)
+ {
+ redir_off = TRUE; /* Don't redirect the typed command.
+ Repeated, because a ":redir" inside
+ completion may switch it on. */
+#ifdef USE_ON_FLY_SCROLL
+ dont_scroll = FALSE; /* allow scrolling here */
+#endif
+ quit_more = FALSE; /* reset after CTRL-D which had a more-prompt */
+
+ did_emsg = FALSE; /* There can't really be a reason why an error
+ that occurs while typing a command should
+ cause the command not to be executed. */
+
+ cursorcmd(); /* set the cursor on the right spot */
+
+ /* Get a character. Ignore K_IGNORE and K_NOP, they should not do
+ * anything, such as stop completion. */
+ do
+ {
+ c = safe_vgetc();
+ } while (c == K_IGNORE || c == K_NOP);
+
+ if (KeyTyped)
+ {
+ some_key_typed = TRUE;
+#ifdef FEAT_RIGHTLEFT
+ if (cmd_hkmap)
+ c = hkmap(c);
+# ifdef FEAT_FKMAP
+ if (cmd_fkmap)
+ c = cmdl_fkmap(c);
+# endif
+ if (cmdmsg_rl && !KeyStuffed)
+ {
+ /* Invert horizontal movements and operations. Only when
+ * typed by the user directly, not when the result of a
+ * mapping. */
+ switch (c)
+ {
+ case K_RIGHT: c = K_LEFT; break;
+ case K_S_RIGHT: c = K_S_LEFT; break;
+ case K_C_RIGHT: c = K_C_LEFT; break;
+ case K_LEFT: c = K_RIGHT; break;
+ case K_S_LEFT: c = K_S_RIGHT; break;
+ case K_C_LEFT: c = K_C_RIGHT; break;
+ }
+ }
+#endif
+ }
+
+ /*
+ * Ignore got_int when CTRL-C was typed here.
+ * Don't ignore it in :global, we really need to break then, e.g., for
+ * ":g/pat/normal /pat" (without the <CR>).
+ * Don't ignore it for the input() function.
+ */
+ if ((c == Ctrl_C
+#ifdef UNIX
+ || c == intr_char
+#endif
+ )
+#if defined(FEAT_EVAL) || defined(FEAT_CRYPT)
+ && firstc != '@'
+#endif
+#ifdef FEAT_EVAL
+ && !break_ctrl_c
+#endif
+ && !global_busy)
+ got_int = FALSE;
+
+#ifdef FEAT_CMDHIST
+ /* free old command line when finished moving around in the history
+ * list */
+ if (lookfor != NULL
+ && c != K_S_DOWN && c != K_S_UP
+ && c != K_DOWN && c != K_UP
+ && c != K_PAGEDOWN && c != K_PAGEUP
+ && c != K_KPAGEDOWN && c != K_KPAGEUP
+ && c != K_LEFT && c != K_RIGHT
+ && (xpc.xp_numfiles > 0 || (c != Ctrl_P && c != Ctrl_N)))
+ VIM_CLEAR(lookfor);
+#endif
+
+ /*
+ * When there are matching completions to select <S-Tab> works like
+ * CTRL-P (unless 'wc' is <S-Tab>).
+ */
+ if (c != p_wc && c == K_S_TAB && xpc.xp_numfiles > 0)
+ c = Ctrl_P;
+
+#ifdef FEAT_WILDMENU
+ /* Special translations for 'wildmenu' */
+ if (did_wild_list && p_wmnu)
+ {
+ if (c == K_LEFT)
+ c = Ctrl_P;
+ else if (c == K_RIGHT)
+ c = Ctrl_N;
+ }
+ /* Hitting CR after "emenu Name.": complete submenu */
+ if (xpc.xp_context == EXPAND_MENUNAMES && p_wmnu
+ && ccline.cmdpos > 1
+ && ccline.cmdbuff[ccline.cmdpos - 1] == '.'
+ && ccline.cmdbuff[ccline.cmdpos - 2] != '\\'
+ && (c == '\n' || c == '\r' || c == K_KENTER))
+ c = K_DOWN;
+#endif
+
+ /* free expanded names when finished walking through matches */
+ if (xpc.xp_numfiles != -1
+ && !(c == p_wc && KeyTyped) && c != p_wcm
+ && c != Ctrl_N && c != Ctrl_P && c != Ctrl_A
+ && c != Ctrl_L)
+ {
+ (void)ExpandOne(&xpc, NULL, NULL, 0, WILD_FREE);
+ did_wild_list = FALSE;
+#ifdef FEAT_WILDMENU
+ if (!p_wmnu || (c != K_UP && c != K_DOWN))
+#endif
+ xpc.xp_context = EXPAND_NOTHING;
+ wim_index = 0;
+#ifdef FEAT_WILDMENU
+ if (p_wmnu && wild_menu_showing != 0)
+ {
+ int skt = KeyTyped;
+ int old_RedrawingDisabled = RedrawingDisabled;
+
+ if (ccline.input_fn)
+ RedrawingDisabled = 0;
+
+ if (wild_menu_showing == WM_SCROLLED)
+ {
+ /* Entered command line, move it up */
+ cmdline_row--;
+ redrawcmd();
+ }
+ else if (save_p_ls != -1)
+ {
+ /* restore 'laststatus' and 'winminheight' */
+ p_ls = save_p_ls;
+ p_wmh = save_p_wmh;
+ last_status(FALSE);
+ update_screen(VALID); /* redraw the screen NOW */
+ redrawcmd();
+ save_p_ls = -1;
+ }
+ else
+ {
+ win_redraw_last_status(topframe);
+ redraw_statuslines();
+ }
+ KeyTyped = skt;
+ wild_menu_showing = 0;
+ if (ccline.input_fn)
+ RedrawingDisabled = old_RedrawingDisabled;
+ }
+#endif
+ }
+
+#ifdef FEAT_WILDMENU
+ /* Special translations for 'wildmenu' */
+ if (xpc.xp_context == EXPAND_MENUNAMES && p_wmnu)
+ {
+ /* Hitting <Down> after "emenu Name.": complete submenu */
+ if (c == K_DOWN && ccline.cmdpos > 0
+ && ccline.cmdbuff[ccline.cmdpos - 1] == '.')
+ c = p_wc;
+ else if (c == K_UP)
+ {
+ /* Hitting <Up>: Remove one submenu name in front of the
+ * cursor */
+ int found = FALSE;
+
+ j = (int)(xpc.xp_pattern - ccline.cmdbuff);
+ i = 0;
+ while (--j > 0)
+ {
+ /* check for start of menu name */
+ if (ccline.cmdbuff[j] == ' '
+ && ccline.cmdbuff[j - 1] != '\\')
+ {
+ i = j + 1;
+ break;
+ }
+ /* check for start of submenu name */
+ if (ccline.cmdbuff[j] == '.'
+ && ccline.cmdbuff[j - 1] != '\\')
+ {
+ if (found)
+ {
+ i = j + 1;
+ break;
+ }
+ else
+ found = TRUE;
+ }
+ }
+ if (i > 0)
+ cmdline_del(i);
+ c = p_wc;
+ xpc.xp_context = EXPAND_NOTHING;
+ }
+ }
+ if ((xpc.xp_context == EXPAND_FILES
+ || xpc.xp_context == EXPAND_DIRECTORIES
+ || xpc.xp_context == EXPAND_SHELLCMD) && p_wmnu)
+ {
+ char_u upseg[5];
+
+ upseg[0] = PATHSEP;
+ upseg[1] = '.';
+ upseg[2] = '.';
+ upseg[3] = PATHSEP;
+ upseg[4] = NUL;
+
+ if (c == K_DOWN
+ && ccline.cmdpos > 0
+ && ccline.cmdbuff[ccline.cmdpos - 1] == PATHSEP
+ && (ccline.cmdpos < 3
+ || ccline.cmdbuff[ccline.cmdpos - 2] != '.'
+ || ccline.cmdbuff[ccline.cmdpos - 3] != '.'))
+ {
+ /* go down a directory */
+ c = p_wc;
+ }
+ else if (STRNCMP(xpc.xp_pattern, upseg + 1, 3) == 0 && c == K_DOWN)
+ {
+ /* If in a direct ancestor, strip off one ../ to go down */
+ int found = FALSE;
+
+ j = ccline.cmdpos;
+ i = (int)(xpc.xp_pattern - ccline.cmdbuff);
+ while (--j > i)
+ {
+ if (has_mbyte)
+ j -= (*mb_head_off)(ccline.cmdbuff, ccline.cmdbuff + j);
+ if (vim_ispathsep(ccline.cmdbuff[j]))
+ {
+ found = TRUE;
+ break;
+ }
+ }
+ if (found
+ && ccline.cmdbuff[j - 1] == '.'
+ && ccline.cmdbuff[j - 2] == '.'
+ && (vim_ispathsep(ccline.cmdbuff[j - 3]) || j == i + 2))
+ {
+ cmdline_del(j - 2);
+ c = p_wc;
+ }
+ }
+ else if (c == K_UP)
+ {
+ /* go up a directory */
+ int found = FALSE;
+
+ j = ccline.cmdpos - 1;
+ i = (int)(xpc.xp_pattern - ccline.cmdbuff);
+ while (--j > i)
+ {
+ if (has_mbyte)
+ j -= (*mb_head_off)(ccline.cmdbuff, ccline.cmdbuff + j);
+ if (vim_ispathsep(ccline.cmdbuff[j])
+#ifdef BACKSLASH_IN_FILENAME
+ && vim_strchr((char_u *)" *?[{`$%#",
+ ccline.cmdbuff[j + 1]) == NULL
+#endif
+ )
+ {
+ if (found)
+ {
+ i = j + 1;
+ break;
+ }
+ else
+ found = TRUE;
+ }
+ }
+
+ if (!found)
+ j = i;
+ else if (STRNCMP(ccline.cmdbuff + j, upseg, 4) == 0)
+ j += 4;
+ else if (STRNCMP(ccline.cmdbuff + j, upseg + 1, 3) == 0
+ && j == i)
+ j += 3;
+ else
+ j = 0;
+ if (j > 0)
+ {
+ /* TODO this is only for DOS/UNIX systems - need to put in
+ * machine-specific stuff here and in upseg init */
+ cmdline_del(j);
+ put_on_cmdline(upseg + 1, 3, FALSE);
+ }
+ else if (ccline.cmdpos > i)
+ cmdline_del(i);
+
+ /* Now complete in the new directory. Set KeyTyped in case the
+ * Up key came from a mapping. */
+ c = p_wc;
+ KeyTyped = TRUE;
+ }
+ }
+
+#endif /* FEAT_WILDMENU */
+
+ /* CTRL-\ CTRL-N goes to Normal mode, CTRL-\ CTRL-G goes to Insert
+ * mode when 'insertmode' is set, CTRL-\ e prompts for an expression. */
+ if (c == Ctrl_BSL)
+ {
+ ++no_mapping;
+ ++allow_keys;
+ c = plain_vgetc();
+ --no_mapping;
+ --allow_keys;
+ /* CTRL-\ e doesn't work when obtaining an expression, unless it
+ * is in a mapping. */
+ if (c != Ctrl_N && c != Ctrl_G && (c != 'e'
+ || (ccline.cmdfirstc == '=' && KeyTyped)
+#ifdef FEAT_EVAL
+ || cmdline_star > 0
+#endif
+ ))
+ {
+ vungetc(c);
+ c = Ctrl_BSL;
+ }
+#ifdef FEAT_EVAL
+ else if (c == 'e')
+ {
+ char_u *p = NULL;
+ int len;
+
+ /*
+ * Replace the command line with the result of an expression.
+ * Need to save and restore the current command line, to be
+ * able to enter a new one...
+ */
+ if (ccline.cmdpos == ccline.cmdlen)
+ new_cmdpos = 99999; /* keep it at the end */
+ else
+ new_cmdpos = ccline.cmdpos;
+
+ c = get_expr_register();
+ if (c == '=')
+ {
+ /* Need to save and restore ccline. And set "textlock"
+ * to avoid nasty things like going to another buffer when
+ * evaluating an expression. */
+ ++textlock;
+ p = get_expr_line();
+ --textlock;
+
+ if (p != NULL)
+ {
+ len = (int)STRLEN(p);
+ if (realloc_cmdbuff(len + 1) == OK)
+ {
+ ccline.cmdlen = len;
+ STRCPY(ccline.cmdbuff, p);
+ vim_free(p);
+
+ /* Restore the cursor or use the position set with
+ * set_cmdline_pos(). */
+ if (new_cmdpos > ccline.cmdlen)
+ ccline.cmdpos = ccline.cmdlen;
+ else
+ ccline.cmdpos = new_cmdpos;
+
+ KeyTyped = FALSE; /* Don't do p_wc completion. */
+ redrawcmd();
+ goto cmdline_changed;
+ }
+ vim_free(p);
+ }
+ }
+ beep_flush();
+ got_int = FALSE; /* don't abandon the command line */
+ did_emsg = FALSE;
+ emsg_on_display = FALSE;
+ redrawcmd();
+ goto cmdline_not_changed;
+ }
+#endif
+ else
+ {
+ if (c == Ctrl_G && p_im && restart_edit == 0)
+ restart_edit = 'a';
+ gotesc = TRUE; /* will free ccline.cmdbuff after putting it
+ in history */
+ goto returncmd; /* back to Normal mode */
+ }
+ }
+
+#ifdef FEAT_CMDWIN
+ if (c == cedit_key || c == K_CMDWIN)
+ {
+ if (ex_normal_busy == 0 && got_int == FALSE)
+ {
+ /*
+ * Open a window to edit the command line (and history).
+ */
+ c = open_cmdwin();
+ some_key_typed = TRUE;
+ }
+ }
+# ifdef FEAT_DIGRAPHS
+ else
+# endif
+#endif
+#ifdef FEAT_DIGRAPHS
+ c = do_digraph(c);
+#endif
+
+ if (c == '\n' || c == '\r' || c == K_KENTER || (c == ESC
+ && (!KeyTyped || vim_strchr(p_cpo, CPO_ESC) != NULL)))
+ {
+ /* In Ex mode a backslash escapes a newline. */
+ if (exmode_active
+ && c != ESC
+ && ccline.cmdpos == ccline.cmdlen
+ && ccline.cmdpos > 0
+ && ccline.cmdbuff[ccline.cmdpos - 1] == '\\')
+ {
+ if (c == K_KENTER)
+ c = '\n';
+ }
+ else
+ {
+ gotesc = FALSE; /* Might have typed ESC previously, don't
+ truncate the cmdline now. */
+ if (ccheck_abbr(c + ABBR_OFF))
+ goto cmdline_changed;
+ if (!cmd_silent)
+ {
+ windgoto(msg_row, 0);
+ out_flush();
+ }
+ break;
+ }
+ }
+
+ /*
+ * Completion for 'wildchar' or 'wildcharm' key.
+ * - hitting <ESC> twice means: abandon command line.
+ * - wildcard expansion is only done when the 'wildchar' key is really
+ * typed, not when it comes from a macro
+ */
+ if ((c == p_wc && !gotesc && KeyTyped) || c == p_wcm)
+ {
+ if (xpc.xp_numfiles > 0) /* typed p_wc at least twice */
+ {
+ /* if 'wildmode' contains "list" may still need to list */
+ if (xpc.xp_numfiles > 1
+ && !did_wild_list
+ && (wim_flags[wim_index] & WIM_LIST))
+ {
+ (void)showmatches(&xpc, FALSE);
+ redrawcmd();
+ did_wild_list = TRUE;
+ }
+ if (wim_flags[wim_index] & WIM_LONGEST)
+ res = nextwild(&xpc, WILD_LONGEST, WILD_NO_BEEP,
+ firstc != '@');
+ else if (wim_flags[wim_index] & WIM_FULL)
+ res = nextwild(&xpc, WILD_NEXT, WILD_NO_BEEP,
+ firstc != '@');
+ else
+ res = OK; /* don't insert 'wildchar' now */
+ }
+ else /* typed p_wc first time */
+ {
+ wim_index = 0;
+ j = ccline.cmdpos;
+ /* if 'wildmode' first contains "longest", get longest
+ * common part */
+ if (wim_flags[0] & WIM_LONGEST)
+ res = nextwild(&xpc, WILD_LONGEST, WILD_NO_BEEP,
+ firstc != '@');
+ else
+ res = nextwild(&xpc, WILD_EXPAND_KEEP, WILD_NO_BEEP,
+ firstc != '@');
+
+ /* if interrupted while completing, behave like it failed */
+ if (got_int)
+ {
+ (void)vpeekc(); /* remove <C-C> from input stream */
+ got_int = FALSE; /* don't abandon the command line */
+ (void)ExpandOne(&xpc, NULL, NULL, 0, WILD_FREE);
+#ifdef FEAT_WILDMENU
+ xpc.xp_context = EXPAND_NOTHING;
+#endif
+ goto cmdline_changed;
+ }
+
+ /* when more than one match, and 'wildmode' first contains
+ * "list", or no change and 'wildmode' contains "longest,list",
+ * list all matches */
+ if (res == OK && xpc.xp_numfiles > 1)
+ {
+ /* a "longest" that didn't do anything is skipped (but not
+ * "list:longest") */
+ if (wim_flags[0] == WIM_LONGEST && ccline.cmdpos == j)
+ wim_index = 1;
+ if ((wim_flags[wim_index] & WIM_LIST)
+#ifdef FEAT_WILDMENU
+ || (p_wmnu && (wim_flags[wim_index] & WIM_FULL) != 0)
+#endif
+ )
+ {
+ if (!(wim_flags[0] & WIM_LONGEST))
+ {
+#ifdef FEAT_WILDMENU
+ int p_wmnu_save = p_wmnu;
+ p_wmnu = 0;
+#endif
+ /* remove match */
+ nextwild(&xpc, WILD_PREV, 0, firstc != '@');
+#ifdef FEAT_WILDMENU
+ p_wmnu = p_wmnu_save;
+#endif
+ }
+#ifdef FEAT_WILDMENU
+ (void)showmatches(&xpc, p_wmnu
+ && ((wim_flags[wim_index] & WIM_LIST) == 0));
+#else
+ (void)showmatches(&xpc, FALSE);
+#endif
+ redrawcmd();
+ did_wild_list = TRUE;
+ if (wim_flags[wim_index] & WIM_LONGEST)
+ nextwild(&xpc, WILD_LONGEST, WILD_NO_BEEP,
+ firstc != '@');
+ else if (wim_flags[wim_index] & WIM_FULL)
+ nextwild(&xpc, WILD_NEXT, WILD_NO_BEEP,
+ firstc != '@');
+ }
+ else
+ vim_beep(BO_WILD);
+ }
+#ifdef FEAT_WILDMENU
+ else if (xpc.xp_numfiles == -1)
+ xpc.xp_context = EXPAND_NOTHING;
+#endif
+ }
+ if (wim_index < 3)
+ ++wim_index;
+ if (c == ESC)
+ gotesc = TRUE;
+ if (res == OK)
+ goto cmdline_changed;
+ }
+
+ gotesc = FALSE;
+
+ /* <S-Tab> goes to last match, in a clumsy way */
+ if (c == K_S_TAB && KeyTyped)
+ {
+ if (nextwild(&xpc, WILD_EXPAND_KEEP, 0, firstc != '@') == OK
+ && nextwild(&xpc, WILD_PREV, 0, firstc != '@') == OK
+ && nextwild(&xpc, WILD_PREV, 0, firstc != '@') == OK)
+ goto cmdline_changed;
+ }
+
+ if (c == NUL || c == K_ZERO) /* NUL is stored as NL */
+ c = NL;
+
+ do_abbr = TRUE; /* default: check for abbreviation */
+
+ /*
+ * Big switch for a typed command line character.
+ */
+ switch (c)
+ {
+ case K_BS:
+ case Ctrl_H:
+ case K_DEL:
+ case K_KDEL:
+ case Ctrl_W:
+#ifdef FEAT_FKMAP
+ if (cmd_fkmap && c == K_BS)
+ c = K_DEL;
+#endif
+ if (c == K_KDEL)
+ c = K_DEL;
+
+ /*
+ * delete current character is the same as backspace on next
+ * character, except at end of line
+ */
+ if (c == K_DEL && ccline.cmdpos != ccline.cmdlen)
+ ++ccline.cmdpos;
+ if (has_mbyte && c == K_DEL)
+ ccline.cmdpos += mb_off_next(ccline.cmdbuff,
+ ccline.cmdbuff + ccline.cmdpos);
+ if (ccline.cmdpos > 0)
+ {
+ char_u *p;
+
+ j = ccline.cmdpos;
+ p = ccline.cmdbuff + j;
+ if (has_mbyte)
+ {
+ p = mb_prevptr(ccline.cmdbuff, p);
+ if (c == Ctrl_W)
+ {
+ while (p > ccline.cmdbuff && vim_isspace(*p))
+ p = mb_prevptr(ccline.cmdbuff, p);
+ i = mb_get_class(p);
+ while (p > ccline.cmdbuff && mb_get_class(p) == i)
+ p = mb_prevptr(ccline.cmdbuff, p);
+ if (mb_get_class(p) != i)
+ p += (*mb_ptr2len)(p);
+ }
+ }
+ else if (c == Ctrl_W)
+ {
+ while (p > ccline.cmdbuff && vim_isspace(p[-1]))
+ --p;
+ i = vim_iswordc(p[-1]);
+ while (p > ccline.cmdbuff && !vim_isspace(p[-1])
+ && vim_iswordc(p[-1]) == i)
+ --p;
+ }
+ else
+ --p;
+ ccline.cmdpos = (int)(p - ccline.cmdbuff);
+ ccline.cmdlen -= j - ccline.cmdpos;
+ i = ccline.cmdpos;
+ while (i < ccline.cmdlen)
+ ccline.cmdbuff[i++] = ccline.cmdbuff[j++];
+
+ /* Truncate at the end, required for multi-byte chars. */
+ ccline.cmdbuff[ccline.cmdlen] = NUL;
+#ifdef FEAT_SEARCH_EXTRA
+ if (ccline.cmdlen == 0)
+ {
+ is_state.search_start = is_state.save_cursor;
+ /* save view settings, so that the screen
+ * won't be restored at the wrong position */
+ is_state.old_viewstate = is_state.init_viewstate;
+ }
+#endif
+ redrawcmd();
+ }
+ else if (ccline.cmdlen == 0 && c != Ctrl_W
+ && ccline.cmdprompt == NULL && indent == 0)
+ {
+ /* In ex and debug mode it doesn't make sense to return. */
+ if (exmode_active
+#ifdef FEAT_EVAL
+ || ccline.cmdfirstc == '>'
+#endif
+ )
+ goto cmdline_not_changed;
+
+ VIM_CLEAR(ccline.cmdbuff); /* no commandline to return */
+ if (!cmd_silent)
+ {
+#ifdef FEAT_RIGHTLEFT
+ if (cmdmsg_rl)
+ msg_col = Columns;
+ else
+#endif
+ msg_col = 0;
+ msg_putchar(' '); /* delete ':' */
+ }
+#ifdef FEAT_SEARCH_EXTRA
+ if (ccline.cmdlen == 0)
+ is_state.search_start = is_state.save_cursor;
+#endif
+ redraw_cmdline = TRUE;
+ goto returncmd; /* back to cmd mode */
+ }
+ goto cmdline_changed;
+
+ case K_INS:
+ case K_KINS:
+#ifdef FEAT_FKMAP
+ /* if Farsi mode set, we are in reverse insert mode -
+ Do not change the mode */
+ if (cmd_fkmap)
+ beep_flush();
+ else
+#endif
+ ccline.overstrike = !ccline.overstrike;
+#ifdef CURSOR_SHAPE
+ ui_cursor_shape(); /* may show different cursor shape */
+#endif
+ goto cmdline_not_changed;
+
+ case Ctrl_HAT:
+ if (map_to_exists_mode((char_u *)"", LANGMAP, FALSE))
+ {
+ /* ":lmap" mappings exists, toggle use of mappings. */
+ State ^= LANGMAP;
+#ifdef HAVE_INPUT_METHOD
+ im_set_active(FALSE); /* Disable input method */
+#endif
+ if (b_im_ptr != NULL)
+ {
+ if (State & LANGMAP)
+ *b_im_ptr = B_IMODE_LMAP;
+ else
+ *b_im_ptr = B_IMODE_NONE;
+ }
+ }
+#ifdef HAVE_INPUT_METHOD
+ else
+ {
+ /* There are no ":lmap" mappings, toggle IM. When
+ * 'imdisable' is set don't try getting the status, it's
+ * always off. */
+ if ((p_imdisable && b_im_ptr != NULL)
+ ? *b_im_ptr == B_IMODE_IM : im_get_status())
+ {
+ im_set_active(FALSE); /* Disable input method */
+ if (b_im_ptr != NULL)
+ *b_im_ptr = B_IMODE_NONE;
+ }
+ else
+ {
+ im_set_active(TRUE); /* Enable input method */
+ if (b_im_ptr != NULL)
+ *b_im_ptr = B_IMODE_IM;
+ }
+ }
+#endif
+ if (b_im_ptr != NULL)
+ {
+ if (b_im_ptr == &curbuf->b_p_iminsert)
+ set_iminsert_global();
+ else
+ set_imsearch_global();
+ }
+#ifdef CURSOR_SHAPE
+ ui_cursor_shape(); /* may show different cursor shape */
+#endif
+#if defined(FEAT_KEYMAP)
+ /* Show/unshow value of 'keymap' in status lines later. */
+ status_redraw_curbuf();
+#endif
+ goto cmdline_not_changed;
+
+/* case '@': only in very old vi */
+ case Ctrl_U:
+ /* delete all characters left of the cursor */
+ j = ccline.cmdpos;
+ ccline.cmdlen -= j;
+ i = ccline.cmdpos = 0;
+ while (i < ccline.cmdlen)
+ ccline.cmdbuff[i++] = ccline.cmdbuff[j++];
+ /* Truncate at the end, required for multi-byte chars. */
+ ccline.cmdbuff[ccline.cmdlen] = NUL;
+#ifdef FEAT_SEARCH_EXTRA
+ if (ccline.cmdlen == 0)
+ is_state.search_start = is_state.save_cursor;
+#endif
+ redrawcmd();
+ goto cmdline_changed;
+
+#ifdef FEAT_CLIPBOARD
+ case Ctrl_Y:
+ /* Copy the modeless selection, if there is one. */
+ if (clip_star.state != SELECT_CLEARED)
+ {
+ if (clip_star.state == SELECT_DONE)
+ clip_copy_modeless_selection(TRUE);
+ goto cmdline_not_changed;
+ }
+ break;
+#endif
+
+ case ESC: /* get here if p_wc != ESC or when ESC typed twice */
+ case Ctrl_C:
+ /* In exmode it doesn't make sense to return. Except when
+ * ":normal" runs out of characters. */
+ if (exmode_active
+ && (ex_normal_busy == 0 || typebuf.tb_len > 0))
+ goto cmdline_not_changed;
+
+ gotesc = TRUE; /* will free ccline.cmdbuff after
+ putting it in history */
+ goto returncmd; /* back to cmd mode */
+
+ case Ctrl_R: /* insert register */
+#ifdef USE_ON_FLY_SCROLL
+ dont_scroll = TRUE; /* disallow scrolling here */
+#endif
+ putcmdline('"', TRUE);
+ ++no_mapping;
+ i = c = plain_vgetc(); /* CTRL-R <char> */
+ if (i == Ctrl_O)
+ i = Ctrl_R; /* CTRL-R CTRL-O == CTRL-R CTRL-R */
+ if (i == Ctrl_R)
+ c = plain_vgetc(); /* CTRL-R CTRL-R <char> */
+ extra_char = NUL;
+ --no_mapping;
+#ifdef FEAT_EVAL
+ /*
+ * Insert the result of an expression.
+ * Need to save the current command line, to be able to enter
+ * a new one...
+ */
+ new_cmdpos = -1;
+ if (c == '=')
+ {
+ if (ccline.cmdfirstc == '=' // can't do this recursively
+ || cmdline_star > 0) // or when typing a password
+ {
+ beep_flush();
+ c = ESC;
+ }
+ else
+ c = get_expr_register();
+ }
+#endif
+ if (c != ESC) /* use ESC to cancel inserting register */
+ {
+ cmdline_paste(c, i == Ctrl_R, FALSE);
+
+#ifdef FEAT_EVAL
+ /* When there was a serious error abort getting the
+ * command line. */
+ if (aborting())
+ {
+ gotesc = TRUE; /* will free ccline.cmdbuff after
+ putting it in history */
+ goto returncmd; /* back to cmd mode */
+ }
+#endif
+ KeyTyped = FALSE; /* Don't do p_wc completion. */
+#ifdef FEAT_EVAL
+ if (new_cmdpos >= 0)
+ {
+ /* set_cmdline_pos() was used */
+ if (new_cmdpos > ccline.cmdlen)
+ ccline.cmdpos = ccline.cmdlen;
+ else
+ ccline.cmdpos = new_cmdpos;
+ }
+#endif
+ }
+ redrawcmd();
+ goto cmdline_changed;
+
+ case Ctrl_D:
+ if (showmatches(&xpc, FALSE) == EXPAND_NOTHING)
+ break; /* Use ^D as normal char instead */
+
+ redrawcmd();
+ continue; /* don't do incremental search now */
+
+ case K_RIGHT:
+ case K_S_RIGHT:
+ case K_C_RIGHT:
+ do
+ {
+ if (ccline.cmdpos >= ccline.cmdlen)
+ break;
+ i = cmdline_charsize(ccline.cmdpos);
+ if (KeyTyped && ccline.cmdspos + i >= Columns * Rows)
+ break;
+ ccline.cmdspos += i;
+ if (has_mbyte)
+ ccline.cmdpos += (*mb_ptr2len)(ccline.cmdbuff
+ + ccline.cmdpos);
+ else
+ ++ccline.cmdpos;
+ }
+ while ((c == K_S_RIGHT || c == K_C_RIGHT
+ || (mod_mask & (MOD_MASK_SHIFT|MOD_MASK_CTRL)))
+ && ccline.cmdbuff[ccline.cmdpos] != ' ');
+ if (has_mbyte)
+ set_cmdspos_cursor();
+ goto cmdline_not_changed;
+
+ case K_LEFT:
+ case K_S_LEFT:
+ case K_C_LEFT:
+ if (ccline.cmdpos == 0)
+ goto cmdline_not_changed;
+ do
+ {
+ --ccline.cmdpos;
+ if (has_mbyte) /* move to first byte of char */
+ ccline.cmdpos -= (*mb_head_off)(ccline.cmdbuff,
+ ccline.cmdbuff + ccline.cmdpos);
+ ccline.cmdspos -= cmdline_charsize(ccline.cmdpos);
+ }
+ while (ccline.cmdpos > 0
+ && (c == K_S_LEFT || c == K_C_LEFT
+ || (mod_mask & (MOD_MASK_SHIFT|MOD_MASK_CTRL)))
+ && ccline.cmdbuff[ccline.cmdpos - 1] != ' ');
+ if (has_mbyte)
+ set_cmdspos_cursor();
+ goto cmdline_not_changed;
+
+ case K_IGNORE:
+ /* Ignore mouse event or open_cmdwin() result. */
+ goto cmdline_not_changed;
+
+#ifdef FEAT_GUI_W32
+ /* On Win32 ignore <M-F4>, we get it when closing the window was
+ * cancelled. */
+ case K_F4:
+ if (mod_mask == MOD_MASK_ALT)
+ {
+ redrawcmd(); /* somehow the cmdline is cleared */
+ goto cmdline_not_changed;
+ }
+ break;
+#endif
+
+#ifdef FEAT_MOUSE
+ case K_MIDDLEDRAG:
+ case K_MIDDLERELEASE:
+ goto cmdline_not_changed; /* Ignore mouse */
+
+ case K_MIDDLEMOUSE:
+# ifdef FEAT_GUI
+ /* When GUI is active, also paste when 'mouse' is empty */
+ if (!gui.in_use)
+# endif
+ if (!mouse_has(MOUSE_COMMAND))
+ goto cmdline_not_changed; /* Ignore mouse */
+# ifdef FEAT_CLIPBOARD
+ if (clip_star.available)
+ cmdline_paste('*', TRUE, TRUE);
+ else
+# endif
+ cmdline_paste(0, TRUE, TRUE);
+ redrawcmd();
+ goto cmdline_changed;
+
+# ifdef FEAT_DND
+ case K_DROP:
+ cmdline_paste('~', TRUE, FALSE);
+ redrawcmd();
+ goto cmdline_changed;
+# endif
+
+ case K_LEFTDRAG:
+ case K_LEFTRELEASE:
+ case K_RIGHTDRAG:
+ case K_RIGHTRELEASE:
+ /* Ignore drag and release events when the button-down wasn't
+ * seen before. */
+ if (ignore_drag_release)
+ goto cmdline_not_changed;
+ /* FALLTHROUGH */
+ case K_LEFTMOUSE:
+ case K_RIGHTMOUSE:
+ if (c == K_LEFTRELEASE || c == K_RIGHTRELEASE)
+ ignore_drag_release = TRUE;
+ else
+ ignore_drag_release = FALSE;
+# ifdef FEAT_GUI
+ /* When GUI is active, also move when 'mouse' is empty */
+ if (!gui.in_use)
+# endif
+ if (!mouse_has(MOUSE_COMMAND))
+ goto cmdline_not_changed; /* Ignore mouse */
+# ifdef FEAT_CLIPBOARD
+ if (mouse_row < cmdline_row && clip_star.available)
+ {
+ int button, is_click, is_drag;
+
+ /*
+ * Handle modeless selection.
+ */
+ button = get_mouse_button(KEY2TERMCAP1(c),
+ &is_click, &is_drag);
+ if (mouse_model_popup() && button == MOUSE_LEFT
+ && (mod_mask & MOD_MASK_SHIFT))
+ {
+ /* Translate shift-left to right button. */
+ button = MOUSE_RIGHT;
+ mod_mask &= ~MOD_MASK_SHIFT;
+ }
+ clip_modeless(button, is_click, is_drag);
+ goto cmdline_not_changed;
+ }
+# endif
+
+ set_cmdspos();
+ for (ccline.cmdpos = 0; ccline.cmdpos < ccline.cmdlen;
+ ++ccline.cmdpos)
+ {
+ i = cmdline_charsize(ccline.cmdpos);
+ if (mouse_row <= cmdline_row + ccline.cmdspos / Columns
+ && mouse_col < ccline.cmdspos % Columns + i)
+ break;
+ if (has_mbyte)
+ {
+ /* Count ">" for double-wide char that doesn't fit. */
+ correct_cmdspos(ccline.cmdpos, i);
+ ccline.cmdpos += (*mb_ptr2len)(ccline.cmdbuff
+ + ccline.cmdpos) - 1;
+ }
+ ccline.cmdspos += i;
+ }
+ goto cmdline_not_changed;
+
+ /* Mouse scroll wheel: ignored here */
+ case K_MOUSEDOWN:
+ case K_MOUSEUP:
+ case K_MOUSELEFT:
+ case K_MOUSERIGHT:
+ /* Alternate buttons ignored here */
+ case K_X1MOUSE:
+ case K_X1DRAG:
+ case K_X1RELEASE:
+ case K_X2MOUSE:
+ case K_X2DRAG:
+ case K_X2RELEASE:
+ case K_MOUSEMOVE:
+ goto cmdline_not_changed;
+
+#endif /* FEAT_MOUSE */
+
+#ifdef FEAT_GUI
+ case K_LEFTMOUSE_NM: /* mousefocus click, ignored */
+ case K_LEFTRELEASE_NM:
+ goto cmdline_not_changed;
+
+ case K_VER_SCROLLBAR:
+ if (msg_scrolled == 0)
+ {
+ gui_do_scroll();
+ redrawcmd();
+ }
+ goto cmdline_not_changed;
+
+ case K_HOR_SCROLLBAR:
+ if (msg_scrolled == 0)
+ {
+ gui_do_horiz_scroll(scrollbar_value, FALSE);
+ redrawcmd();
+ }
+ goto cmdline_not_changed;
+#endif
+#ifdef FEAT_GUI_TABLINE
+ case K_TABLINE:
+ case K_TABMENU:
+ /* Don't want to change any tabs here. Make sure the same tab
+ * is still selected. */
+ if (gui_use_tabline())
+ gui_mch_set_curtab(tabpage_index(curtab));
+ goto cmdline_not_changed;
+#endif
+
+ case K_SELECT: /* end of Select mode mapping - ignore */
+ goto cmdline_not_changed;
+
+ case Ctrl_B: /* begin of command line */
+ case K_HOME:
+ case K_KHOME:
+ case K_S_HOME:
+ case K_C_HOME:
+ ccline.cmdpos = 0;
+ set_cmdspos();
+ goto cmdline_not_changed;
+
+ case Ctrl_E: /* end of command line */
+ case K_END:
+ case K_KEND:
+ case K_S_END:
+ case K_C_END:
+ ccline.cmdpos = ccline.cmdlen;
+ set_cmdspos_cursor();
+ goto cmdline_not_changed;
+
+ case Ctrl_A: /* all matches */
+ if (nextwild(&xpc, WILD_ALL, 0, firstc != '@') == FAIL)
+ break;
+ goto cmdline_changed;
+
+ case Ctrl_L:
+#ifdef FEAT_SEARCH_EXTRA
+ if (may_add_char_to_search(firstc, &c, &is_state) == OK)
+ goto cmdline_not_changed;
+#endif
+
+ /* completion: longest common part */
+ if (nextwild(&xpc, WILD_LONGEST, 0, firstc != '@') == FAIL)
+ break;
+ goto cmdline_changed;
+
+ case Ctrl_N: /* next match */
+ case Ctrl_P: /* previous match */
+ if (xpc.xp_numfiles > 0)
+ {
+ if (nextwild(&xpc, (c == Ctrl_P) ? WILD_PREV : WILD_NEXT,
+ 0, firstc != '@') == FAIL)
+ break;
+ goto cmdline_not_changed;
+ }
+#ifdef FEAT_CMDHIST
+ /* FALLTHROUGH */
+ case K_UP:
+ case K_DOWN:
+ case K_S_UP:
+ case K_S_DOWN:
+ case K_PAGEUP:
+ case K_KPAGEUP:
+ case K_PAGEDOWN:
+ case K_KPAGEDOWN:
+ if (hislen == 0 || firstc == NUL) /* no history */
+ goto cmdline_not_changed;
+
+ i = hiscnt;
+
+ /* save current command string so it can be restored later */
+ if (lookfor == NULL)
+ {
+ if ((lookfor = vim_strsave(ccline.cmdbuff)) == NULL)
+ goto cmdline_not_changed;
+ lookfor[ccline.cmdpos] = NUL;
+ }
+
+ j = (int)STRLEN(lookfor);
+ for (;;)
+ {
+ /* one step backwards */
+ if (c == K_UP|| c == K_S_UP || c == Ctrl_P
+ || c == K_PAGEUP || c == K_KPAGEUP)
+ {
+ if (hiscnt == hislen) /* first time */
+ hiscnt = hisidx[histype];
+ else if (hiscnt == 0 && hisidx[histype] != hislen - 1)
+ hiscnt = hislen - 1;
+ else if (hiscnt != hisidx[histype] + 1)
+ --hiscnt;
+ else /* at top of list */
+ {
+ hiscnt = i;
+ break;
+ }
+ }
+ else /* one step forwards */
+ {
+ /* on last entry, clear the line */
+ if (hiscnt == hisidx[histype])
+ {
+ hiscnt = hislen;
+ break;
+ }
+
+ /* not on a history line, nothing to do */
+ if (hiscnt == hislen)
+ break;
+ if (hiscnt == hislen - 1) /* wrap around */
+ hiscnt = 0;
+ else
+ ++hiscnt;
+ }
+ if (hiscnt < 0 || history[histype][hiscnt].hisstr == NULL)
+ {
+ hiscnt = i;
+ break;
+ }
+ if ((c != K_UP && c != K_DOWN)
+ || hiscnt == i
+ || STRNCMP(history[histype][hiscnt].hisstr,
+ lookfor, (size_t)j) == 0)
+ break;
+ }
+
+ if (hiscnt != i) /* jumped to other entry */
+ {
+ char_u *p;
+ int len;
+ int old_firstc;
+
+ VIM_CLEAR(ccline.cmdbuff);
+ xpc.xp_context = EXPAND_NOTHING;
+ if (hiscnt == hislen)
+ p = lookfor; /* back to the old one */
+ else
+ p = history[histype][hiscnt].hisstr;
+
+ if (histype == HIST_SEARCH
+ && p != lookfor
+ && (old_firstc = p[STRLEN(p) + 1]) != firstc)
+ {
+ /* Correct for the separator character used when
+ * adding the history entry vs the one used now.
+ * First loop: count length.
+ * Second loop: copy the characters. */
+ for (i = 0; i <= 1; ++i)
+ {
+ len = 0;
+ for (j = 0; p[j] != NUL; ++j)
+ {
+ /* Replace old sep with new sep, unless it is
+ * escaped. */
+ if (p[j] == old_firstc
+ && (j == 0 || p[j - 1] != '\\'))
+ {
+ if (i > 0)
+ ccline.cmdbuff[len] = firstc;
+ }
+ else
+ {
+ /* Escape new sep, unless it is already
+ * escaped. */
+ if (p[j] == firstc
+ && (j == 0 || p[j - 1] != '\\'))
+ {
+ if (i > 0)
+ ccline.cmdbuff[len] = '\\';
+ ++len;
+ }
+ if (i > 0)
+ ccline.cmdbuff[len] = p[j];
+ }
+ ++len;
+ }
+ if (i == 0)
+ {
+ alloc_cmdbuff(len);
+ if (ccline.cmdbuff == NULL)
+ goto returncmd;
+ }
+ }
+ ccline.cmdbuff[len] = NUL;
+ }
+ else
+ {
+ alloc_cmdbuff((int)STRLEN(p));
+ if (ccline.cmdbuff == NULL)
+ goto returncmd;
+ STRCPY(ccline.cmdbuff, p);
+ }
+
+ ccline.cmdpos = ccline.cmdlen = (int)STRLEN(ccline.cmdbuff);
+ redrawcmd();
+ goto cmdline_changed;
+ }
+ beep_flush();
+#endif
+ goto cmdline_not_changed;
+
+#ifdef FEAT_SEARCH_EXTRA
+ case Ctrl_G: /* next match */
+ case Ctrl_T: /* previous match */
+ if (may_adjust_incsearch_highlighting(
+ firstc, count, &is_state, c) == FAIL)
+ goto cmdline_not_changed;
+ break;
+#endif
+
+ case Ctrl_V:
+ case Ctrl_Q:
+#ifdef FEAT_MOUSE
+ ignore_drag_release = TRUE;
+#endif
+ putcmdline('^', TRUE);
+ c = get_literal(); /* get next (two) character(s) */
+ do_abbr = FALSE; /* don't do abbreviation now */
+ extra_char = NUL;
+ /* may need to remove ^ when composing char was typed */
+ if (enc_utf8 && utf_iscomposing(c) && !cmd_silent)
+ {
+ draw_cmdline(ccline.cmdpos, ccline.cmdlen - ccline.cmdpos);
+ msg_putchar(' ');
+ cursorcmd();
+ }
+ break;
+
+#ifdef FEAT_DIGRAPHS
+ case Ctrl_K:
+#ifdef FEAT_MOUSE
+ ignore_drag_release = TRUE;
+#endif
+ putcmdline('?', TRUE);
+#ifdef USE_ON_FLY_SCROLL
+ dont_scroll = TRUE; /* disallow scrolling here */
+#endif
+ c = get_digraph(TRUE);
+ extra_char = NUL;
+ if (c != NUL)
+ break;
+
+ redrawcmd();
+ goto cmdline_not_changed;
+#endif /* FEAT_DIGRAPHS */
+
+#ifdef FEAT_RIGHTLEFT
+ case Ctrl__: /* CTRL-_: switch language mode */
+ if (!p_ari)
+ break;
+# ifdef FEAT_FKMAP
+ if (p_altkeymap)
+ {
+ cmd_fkmap = !cmd_fkmap;
+ if (cmd_fkmap) /* in Farsi always in Insert mode */
+ ccline.overstrike = FALSE;
+ }
+ else /* Hebrew is default */
+# endif
+ cmd_hkmap = !cmd_hkmap;
+ goto cmdline_not_changed;
+#endif
+
+ case K_PS:
+ bracketed_paste(PASTE_CMDLINE, FALSE, NULL);
+ goto cmdline_changed;
+
+ default:
+#ifdef UNIX
+ if (c == intr_char)
+ {
+ gotesc = TRUE; /* will free ccline.cmdbuff after
+ putting it in history */
+ goto returncmd; /* back to Normal mode */
+ }
+#endif
+ /*
+ * Normal character with no special meaning. Just set mod_mask
+ * to 0x0 so that typing Shift-Space in the GUI doesn't enter
+ * the string <S-Space>. This should only happen after ^V.
+ */
+ if (!IS_SPECIAL(c))
+ mod_mask = 0x0;
+ break;
+ }
+ /*
+ * End of switch on command line character.
+ * We come here if we have a normal character.
+ */
+
+ if (do_abbr && (IS_SPECIAL(c) || !vim_iswordc(c))
+ && (ccheck_abbr(
+ // Add ABBR_OFF for characters above 0x100, this is
+ // what check_abbr() expects.
+ (has_mbyte && c >= 0x100) ? (c + ABBR_OFF) : c)
+ || c == Ctrl_RSB))
+ goto cmdline_changed;
+
+ /*
+ * put the character in the command line
+ */
+ if (IS_SPECIAL(c) || mod_mask != 0)
+ put_on_cmdline(get_special_key_name(c, mod_mask), -1, TRUE);
+ else
+ {
+ if (has_mbyte)
+ {
+ j = (*mb_char2bytes)(c, IObuff);
+ IObuff[j] = NUL; /* exclude composing chars */
+ put_on_cmdline(IObuff, j, TRUE);
+ }
+ else
+ {
+ IObuff[0] = c;
+ put_on_cmdline(IObuff, 1, TRUE);
+ }
+ }
+ goto cmdline_changed;
+
+/*
+ * This part implements incremental searches for "/" and "?"
+ * Jump to cmdline_not_changed when a character has been read but the command
+ * line did not change. Then we only search and redraw if something changed in
+ * the past.
+ * Jump to cmdline_changed when the command line did change.
+ * (Sorry for the goto's, I know it is ugly).
+ */
+cmdline_not_changed:
+#ifdef FEAT_SEARCH_EXTRA
+ if (!is_state.incsearch_postponed)
+ continue;
+#endif
+
+cmdline_changed:
+ /* Trigger CmdlineChanged autocommands. */
+ trigger_cmd_autocmd(cmdline_type, EVENT_CMDLINECHANGED);
+
+#ifdef FEAT_SEARCH_EXTRA
+ may_do_incsearch_highlighting(firstc, count, &is_state);
+#endif
+
+#ifdef FEAT_RIGHTLEFT
+ if (cmdmsg_rl
+# ifdef FEAT_ARABIC
+ || (p_arshape && !p_tbidi && enc_utf8)
+# endif
+ )
+ /* Always redraw the whole command line to fix shaping and
+ * right-left typing. Not efficient, but it works.
+ * Do it only when there are no characters left to read
+ * to avoid useless intermediate redraws. */
+ if (vpeekc() == NUL)
+ redrawcmd();
+#endif
+ }
+
+returncmd:
+
+#ifdef FEAT_RIGHTLEFT
+ cmdmsg_rl = FALSE;
+#endif
+
+#ifdef FEAT_FKMAP
+ cmd_fkmap = 0;
+#endif
+
+ ExpandCleanup(&xpc);
+ ccline.xpc = NULL;
+
+#ifdef FEAT_SEARCH_EXTRA
+ finish_incsearch_highlighting(gotesc, &is_state, FALSE);
+#endif
+
+ if (ccline.cmdbuff != NULL)
+ {
+ /*
+ * Put line in history buffer (":" and "=" only when it was typed).
+ */
+#ifdef FEAT_CMDHIST
+ if (ccline.cmdlen && firstc != NUL
+ && (some_key_typed || histype == HIST_SEARCH))
+ {
+ add_to_history(histype, ccline.cmdbuff, TRUE,
+ histype == HIST_SEARCH ? firstc : NUL);
+ if (firstc == ':')
+ {
+ vim_free(new_last_cmdline);
+ new_last_cmdline = vim_strsave(ccline.cmdbuff);
+ }
+ }
+#endif
+
+ if (gotesc)
+ abandon_cmdline();
+ }
+
+ /*
+ * If the screen was shifted up, redraw the whole screen (later).
+ * If the line is too long, clear it, so ruler and shown command do
+ * not get printed in the middle of it.
+ */
+ msg_check();
+ msg_scroll = save_msg_scroll;
+ redir_off = FALSE;
+
+ /* When the command line was typed, no need for a wait-return prompt. */
+ if (some_key_typed)
+ need_wait_return = FALSE;
+
+ /* Trigger CmdlineLeave autocommands. */
+ trigger_cmd_autocmd(cmdline_type, EVENT_CMDLINELEAVE);
+
+ State = save_State;
+#ifdef HAVE_INPUT_METHOD
+ if (b_im_ptr != NULL && *b_im_ptr != B_IMODE_LMAP)
+ im_save_status(b_im_ptr);
+ im_set_active(FALSE);
+#endif
+#ifdef FEAT_MOUSE
+ setmouse();
+#endif
+#ifdef CURSOR_SHAPE
+ ui_cursor_shape(); /* may show different cursor shape */
+#endif
+ sb_text_end_cmdline();
+
+theend:
+ {
+ char_u *p = ccline.cmdbuff;
+
+ if (did_save_ccline)
+ restore_cmdline(&save_ccline);
+ else
+ ccline.cmdbuff = NULL;
+ return p;
+ }
+}
+
+#if (defined(FEAT_CRYPT) || defined(FEAT_EVAL)) || defined(PROTO)
+/*
+ * Get a command line with a prompt.
+ * This is prepared to be called recursively from getcmdline() (e.g. by
+ * f_input() when evaluating an expression from CTRL-R =).
+ * Returns the command line in allocated memory, or NULL.
+ */
+ char_u *
+getcmdline_prompt(
+ int firstc,
+ char_u *prompt, /* command line prompt */
+ int attr, /* attributes for prompt */
+ int xp_context, /* type of expansion */
+ char_u *xp_arg) /* user-defined expansion argument */
+{
+ char_u *s;
+ struct cmdline_info save_ccline;
+ int did_save_ccline = FALSE;
+ int msg_col_save = msg_col;
+ int msg_silent_save = msg_silent;
+
+ if (ccline.cmdbuff != NULL)
+ {
+ // Save the values of the current cmdline and restore them below.
+ save_cmdline(&save_ccline);
+ did_save_ccline = TRUE;
+ }
+
+ vim_memset(&ccline, 0, sizeof(struct cmdline_info));
+ ccline.cmdprompt = prompt;
+ ccline.cmdattr = attr;
+# ifdef FEAT_EVAL
+ ccline.xp_context = xp_context;
+ ccline.xp_arg = xp_arg;
+ ccline.input_fn = (firstc == '@');
+# endif
+ msg_silent = 0;
+ s = getcmdline_int(firstc, 1L, 0, FALSE);
+
+ if (did_save_ccline)
+ restore_cmdline(&save_ccline);
+
+ msg_silent = msg_silent_save;
+ /* Restore msg_col, the prompt from input() may have changed it.
+ * But only if called recursively and the commandline is therefore being
+ * restored to an old one; if not, the input() prompt stays on the screen,
+ * so we need its modified msg_col left intact. */
+ if (ccline.cmdbuff != NULL)
+ msg_col = msg_col_save;
+
+ return s;
+}
+#endif
+
+/*
+ * Return TRUE when the text must not be changed and we can't switch to
+ * another window or buffer. Used when editing the command line, evaluating
+ * 'balloonexpr', etc.
+ */
+ int
+text_locked(void)
+{
+#ifdef FEAT_CMDWIN
+ if (cmdwin_type != 0)
+ return TRUE;
+#endif
+ return textlock != 0;
+}
+
+/*
+ * Give an error message for a command that isn't allowed while the cmdline
+ * window is open or editing the cmdline in another way.
+ */
+ void
+text_locked_msg(void)
+{
+ emsg(_(get_text_locked_msg()));
+}
+
+ char *
+get_text_locked_msg(void)
+{
+#ifdef FEAT_CMDWIN
+ if (cmdwin_type != 0)
+ return e_cmdwin;
+#endif
+ return e_secure;
+}
+
+/*
+ * Check if "curbuf_lock" or "allbuf_lock" is set and return TRUE when it is
+ * and give an error message.
+ */
+ int
+curbuf_locked(void)
+{
+ if (curbuf_lock > 0)
+ {
+ emsg(_("E788: Not allowed to edit another buffer now"));
+ return TRUE;
+ }
+ return allbuf_locked();
+}
+
+/*
+ * Check if "allbuf_lock" is set and return TRUE when it is and give an error
+ * message.
+ */
+ int
+allbuf_locked(void)
+{
+ if (allbuf_lock > 0)
+ {
+ emsg(_("E811: Not allowed to change buffer information now"));
+ return TRUE;
+ }
+ return FALSE;
+}
+
+ static int
+cmdline_charsize(int idx)
+{
+#if defined(FEAT_CRYPT) || defined(FEAT_EVAL)
+ if (cmdline_star > 0) /* showing '*', always 1 position */
+ return 1;
+#endif
+ return ptr2cells(ccline.cmdbuff + idx);
+}
+
+/*
+ * Compute the offset of the cursor on the command line for the prompt and
+ * indent.
+ */
+ static void
+set_cmdspos(void)
+{
+ if (ccline.cmdfirstc != NUL)
+ ccline.cmdspos = 1 + ccline.cmdindent;
+ else
+ ccline.cmdspos = 0 + ccline.cmdindent;
+}
+
+/*
+ * Compute the screen position for the cursor on the command line.
+ */
+ static void
+set_cmdspos_cursor(void)
+{
+ int i, m, c;
+
+ set_cmdspos();
+ if (KeyTyped)
+ {
+ m = Columns * Rows;
+ if (m < 0) /* overflow, Columns or Rows at weird value */
+ m = MAXCOL;
+ }
+ else
+ m = MAXCOL;
+ for (i = 0; i < ccline.cmdlen && i < ccline.cmdpos; ++i)
+ {
+ c = cmdline_charsize(i);
+ /* Count ">" for double-wide multi-byte char that doesn't fit. */
+ if (has_mbyte)
+ correct_cmdspos(i, c);
+ /* If the cmdline doesn't fit, show cursor on last visible char.
+ * Don't move the cursor itself, so we can still append. */
+ if ((ccline.cmdspos += c) >= m)
+ {
+ ccline.cmdspos -= c;
+ break;
+ }
+ if (has_mbyte)
+ i += (*mb_ptr2len)(ccline.cmdbuff + i) - 1;
+ }
+}
+
+/*
+ * Check if the character at "idx", which is "cells" wide, is a multi-byte
+ * character that doesn't fit, so that a ">" must be displayed.
+ */
+ static void
+correct_cmdspos(int idx, int cells)
+{
+ if ((*mb_ptr2len)(ccline.cmdbuff + idx) > 1
+ && (*mb_ptr2cells)(ccline.cmdbuff + idx) > 1
+ && ccline.cmdspos % Columns + cells > Columns)
+ ccline.cmdspos++;
+}
+
+/*
+ * Get an Ex command line for the ":" command.
+ */
+ char_u *
+getexline(
+ int c, /* normally ':', NUL for ":append" */
+ void *cookie UNUSED,
+ int indent) /* indent for inside conditionals */
+{
+ /* When executing a register, remove ':' that's in front of each line. */
+ if (exec_from_reg && vpeekc() == ':')
+ (void)vgetc();
+ return getcmdline(c, 1L, indent);
+}
+
+/*
+ * Get an Ex command line for Ex mode.
+ * In Ex mode we only use the OS supplied line editing features and no
+ * mappings or abbreviations.
+ * Returns a string in allocated memory or NULL.
+ */
+ char_u *
+getexmodeline(
+ int promptc, /* normally ':', NUL for ":append" and '?' for
+ :s prompt */
+ void *cookie UNUSED,
+ int indent) /* indent for inside conditionals */
+{
+ garray_T line_ga;
+ char_u *pend;
+ int startcol = 0;
+ int c1 = 0;
+ int escaped = FALSE; /* CTRL-V typed */
+ int vcol = 0;
+ char_u *p;
+ int prev_char;
+ int len;
+
+ /* Switch cursor on now. This avoids that it happens after the "\n", which
+ * confuses the system function that computes tabstops. */
+ cursor_on();
+
+ /* always start in column 0; write a newline if necessary */
+ compute_cmdrow();
+ if ((msg_col || msg_didout) && promptc != '?')
+ msg_putchar('\n');
+ if (promptc == ':')
+ {
+ /* indent that is only displayed, not in the line itself */
+ if (p_prompt)
+ msg_putchar(':');
+ while (indent-- > 0)
+ msg_putchar(' ');
+ startcol = msg_col;
+ }
+
+ ga_init2(&line_ga, 1, 30);
+
+ /* autoindent for :insert and :append is in the line itself */
+ if (promptc <= 0)
+ {
+ vcol = indent;
+ while (indent >= 8)
+ {
+ ga_append(&line_ga, TAB);
+ msg_puts(" ");
+ indent -= 8;
+ }
+ while (indent-- > 0)
+ {
+ ga_append(&line_ga, ' ');
+ msg_putchar(' ');
+ }
+ }
+ ++no_mapping;
+ ++allow_keys;
+
+ /*
+ * Get the line, one character at a time.
+ */
+ got_int = FALSE;
+ while (!got_int)
+ {
+ long sw;
+ char_u *s;
+
+ if (ga_grow(&line_ga, 40) == FAIL)
+ break;
+
+ /*
+ * Get one character at a time.
+ */
+ prev_char = c1;
+
+ /* Check for a ":normal" command and no more characters left. */
+ if (ex_normal_busy > 0 && typebuf.tb_len == 0)
+ c1 = '\n';
+ else
+ c1 = vgetc();
+
+ /*
+ * Handle line editing.
+ * Previously this was left to the system, putting the terminal in
+ * cooked mode, but then CTRL-D and CTRL-T can't be used properly.
+ */
+ if (got_int)
+ {
+ msg_putchar('\n');
+ break;
+ }
+
+ if (c1 == K_PS)
+ {
+ bracketed_paste(PASTE_EX, FALSE, &line_ga);
+ goto redraw;
+ }
+
+ if (!escaped)
+ {
+ /* CR typed means "enter", which is NL */
+ if (c1 == '\r')
+ c1 = '\n';
+
+ if (c1 == BS || c1 == K_BS
+ || c1 == DEL || c1 == K_DEL || c1 == K_KDEL)
+ {
+ if (line_ga.ga_len > 0)
+ {
+ if (has_mbyte)
+ {
+ p = (char_u *)line_ga.ga_data;
+ p[line_ga.ga_len] = NUL;
+ len = (*mb_head_off)(p, p + line_ga.ga_len - 1) + 1;
+ line_ga.ga_len -= len;
+ }
+ else
+ --line_ga.ga_len;
+ goto redraw;
+ }
+ continue;
+ }
+
+ if (c1 == Ctrl_U)
+ {
+ msg_col = startcol;
+ msg_clr_eos();
+ line_ga.ga_len = 0;
+ goto redraw;
+ }
+
+ if (c1 == Ctrl_T)
+ {
+ sw = get_sw_value(curbuf);
+ p = (char_u *)line_ga.ga_data;
+ p[line_ga.ga_len] = NUL;
+ indent = get_indent_str(p, 8, FALSE);
+ indent += sw - indent % sw;
+add_indent:
+ while (get_indent_str(p, 8, FALSE) < indent)
+ {
+ (void)ga_grow(&line_ga, 2); /* one more for the NUL */
+ p = (char_u *)line_ga.ga_data;
+ s = skipwhite(p);
+ mch_memmove(s + 1, s, line_ga.ga_len - (s - p) + 1);
+ *s = ' ';
+ ++line_ga.ga_len;
+ }
+redraw:
+ /* redraw the line */
+ msg_col = startcol;
+ vcol = 0;
+ p = (char_u *)line_ga.ga_data;
+ p[line_ga.ga_len] = NUL;
+ while (p < (char_u *)line_ga.ga_data + line_ga.ga_len)
+ {
+ if (*p == TAB)
+ {
+ do
+ {
+ msg_putchar(' ');
+ } while (++vcol % 8);
+ ++p;
+ }
+ else
+ {
+ len = MB_PTR2LEN(p);
+ msg_outtrans_len(p, len);
+ vcol += ptr2cells(p);
+ p += len;
+ }
+ }
+ msg_clr_eos();
+ windgoto(msg_row, msg_col);
+ continue;
+ }
+
+ if (c1 == Ctrl_D)
+ {
+ /* Delete one shiftwidth. */
+ p = (char_u *)line_ga.ga_data;
+ if (prev_char == '0' || prev_char == '^')
+ {
+ if (prev_char == '^')
+ ex_keep_indent = TRUE;
+ indent = 0;
+ p[--line_ga.ga_len] = NUL;
+ }
+ else
+ {
+ p[line_ga.ga_len] = NUL;
+ indent = get_indent_str(p, 8, FALSE);
+ if (indent > 0)
+ {
+ --indent;
+ indent -= indent % get_sw_value(curbuf);
+ }
+ }
+ while (get_indent_str(p, 8, FALSE) > indent)
+ {
+ s = skipwhite(p);
+ mch_memmove(s - 1, s, line_ga.ga_len - (s - p) + 1);
+ --line_ga.ga_len;
+ }
+ goto add_indent;
+ }
+
+ if (c1 == Ctrl_V || c1 == Ctrl_Q)
+ {
+ escaped = TRUE;
+ continue;
+ }
+
+ /* Ignore special key codes: mouse movement, K_IGNORE, etc. */
+ if (IS_SPECIAL(c1))
+ continue;
+ }
+
+ if (IS_SPECIAL(c1))
+ c1 = '?';
+ if (has_mbyte)
+ len = (*mb_char2bytes)(c1,
+ (char_u *)line_ga.ga_data + line_ga.ga_len);
+ else
+ {
+ len = 1;
+ ((char_u *)line_ga.ga_data)[line_ga.ga_len] = c1;
+ }
+ if (c1 == '\n')
+ msg_putchar('\n');
+ else if (c1 == TAB)
+ {
+ /* Don't use chartabsize(), 'ts' can be different */
+ do
+ {
+ msg_putchar(' ');
+ } while (++vcol % 8);
+ }
+ else
+ {
+ msg_outtrans_len(
+ ((char_u *)line_ga.ga_data) + line_ga.ga_len, len);
+ vcol += char2cells(c1);
+ }
+ line_ga.ga_len += len;
+ escaped = FALSE;
+
+ windgoto(msg_row, msg_col);
+ pend = (char_u *)(line_ga.ga_data) + line_ga.ga_len;
+
+ /* We are done when a NL is entered, but not when it comes after an
+ * odd number of backslashes, that results in a NUL. */
+ if (line_ga.ga_len > 0 && pend[-1] == '\n')
+ {
+ int bcount = 0;
+
+ while (line_ga.ga_len - 2 >= bcount && pend[-2 - bcount] == '\\')
+ ++bcount;
+
+ if (bcount > 0)
+ {
+ /* Halve the number of backslashes: "\NL" -> "NUL", "\\NL" ->
+ * "\NL", etc. */
+ line_ga.ga_len -= (bcount + 1) / 2;
+ pend -= (bcount + 1) / 2;
+ pend[-1] = '\n';
+ }
+
+ if ((bcount & 1) == 0)
+ {
+ --line_ga.ga_len;
+ --pend;
+ *pend = NUL;
+ break;
+ }
+ }
+ }
+
+ --no_mapping;
+ --allow_keys;
+
+ /* make following messages go to the next line */
+ msg_didout = FALSE;
+ msg_col = 0;
+ if (msg_row < Rows - 1)
+ ++msg_row;
+ emsg_on_display = FALSE; /* don't want ui_delay() */
+
+ if (got_int)
+ ga_clear(&line_ga);
+
+ return (char_u *)line_ga.ga_data;
+}
+
+# if defined(MCH_CURSOR_SHAPE) || defined(FEAT_GUI) \
+ || defined(FEAT_MOUSESHAPE) || defined(PROTO)
+/*
+ * Return TRUE if ccline.overstrike is on.
+ */
+ int
+cmdline_overstrike(void)
+{
+ return ccline.overstrike;
+}
+
+/*
+ * Return TRUE if the cursor is at the end of the cmdline.
+ */
+ int
+cmdline_at_end(void)
+{
+ return (ccline.cmdpos >= ccline.cmdlen);
+}
+#endif
+
+#if (defined(FEAT_XIM) && (defined(FEAT_GUI_GTK))) || defined(PROTO)
+/*
+ * Return the virtual column number at the current cursor position.
+ * This is used by the IM code to obtain the start of the preedit string.
+ */
+ colnr_T
+cmdline_getvcol_cursor(void)
+{
+ if (ccline.cmdbuff == NULL || ccline.cmdpos > ccline.cmdlen)
+ return MAXCOL;
+
+ if (has_mbyte)
+ {
+ colnr_T col;
+ int i = 0;
+
+ for (col = 0; i < ccline.cmdpos; ++col)
+ i += (*mb_ptr2len)(ccline.cmdbuff + i);
+
+ return col;
+ }
+ else
+ return ccline.cmdpos;
+}
+#endif
+
+#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
+/*
+ * If part of the command line is an IM preedit string, redraw it with
+ * IM feedback attributes. The cursor position is restored after drawing.
+ */
+ static void
+redrawcmd_preedit(void)
+{
+ if ((State & CMDLINE)
+ && xic != NULL
+ /* && im_get_status() doesn't work when using SCIM */
+ && !p_imdisable
+ && im_is_preediting())
+ {
+ int cmdpos = 0;
+ int cmdspos;
+ int old_row;
+ int old_col;
+ colnr_T col;
+
+ old_row = msg_row;
+ old_col = msg_col;
+ cmdspos = ((ccline.cmdfirstc != NUL) ? 1 : 0) + ccline.cmdindent;
+
+ if (has_mbyte)
+ {
+ for (col = 0; col < preedit_start_col
+ && cmdpos < ccline.cmdlen; ++col)
+ {
+ cmdspos += (*mb_ptr2cells)(ccline.cmdbuff + cmdpos);
+ cmdpos += (*mb_ptr2len)(ccline.cmdbuff + cmdpos);
+ }
+ }
+ else
+ {
+ cmdspos += preedit_start_col;
+ cmdpos += preedit_start_col;
+ }
+
+ msg_row = cmdline_row + (cmdspos / (int)Columns);
+ msg_col = cmdspos % (int)Columns;
+ if (msg_row >= Rows)
+ msg_row = Rows - 1;
+
+ for (col = 0; cmdpos < ccline.cmdlen; ++col)
+ {
+ int char_len;
+ int char_attr;
+
+ char_attr = im_get_feedback_attr(col);
+ if (char_attr < 0)
+ break; /* end of preedit string */
+
+ if (has_mbyte)
+ char_len = (*mb_ptr2len)(ccline.cmdbuff + cmdpos);
+ else
+ char_len = 1;
+
+ msg_outtrans_len_attr(ccline.cmdbuff + cmdpos, char_len, char_attr);
+ cmdpos += char_len;
+ }
+
+ msg_row = old_row;
+ msg_col = old_col;
+ }
+}
+#endif /* FEAT_XIM && FEAT_GUI_GTK */
+
+/*
+ * Allocate a new command line buffer.
+ * Assigns the new buffer to ccline.cmdbuff and ccline.cmdbufflen.
+ */
+ static void
+alloc_cmdbuff(int len)
+{
+ /*
+ * give some extra space to avoid having to allocate all the time
+ */
+ if (len < 80)
+ len = 100;
+ else
+ len += 20;
+
+ ccline.cmdbuff = alloc(len); /* caller should check for out-of-memory */
+ ccline.cmdbufflen = len;
+}
+
+/*
+ * Re-allocate the command line to length len + something extra.
+ * return FAIL for failure, OK otherwise
+ */
+ static int
+realloc_cmdbuff(int len)
+{
+ char_u *p;
+
+ if (len < ccline.cmdbufflen)
+ return OK; /* no need to resize */
+
+ p = ccline.cmdbuff;
+ alloc_cmdbuff(len); /* will get some more */
+ if (ccline.cmdbuff == NULL) /* out of memory */
+ {
+ ccline.cmdbuff = p; /* keep the old one */
+ return FAIL;
+ }
+ /* There isn't always a NUL after the command, but it may need to be
+ * there, thus copy up to the NUL and add a NUL. */
+ mch_memmove(ccline.cmdbuff, p, (size_t)ccline.cmdlen);
+ ccline.cmdbuff[ccline.cmdlen] = NUL;
+ vim_free(p);
+
+ if (ccline.xpc != NULL
+ && ccline.xpc->xp_pattern != NULL
+ && ccline.xpc->xp_context != EXPAND_NOTHING
+ && ccline.xpc->xp_context != EXPAND_UNSUCCESSFUL)
+ {
+ int i = (int)(ccline.xpc->xp_pattern - p);
+
+ /* If xp_pattern points inside the old cmdbuff it needs to be adjusted
+ * to point into the newly allocated memory. */
+ if (i >= 0 && i <= ccline.cmdlen)
+ ccline.xpc->xp_pattern = ccline.cmdbuff + i;
+ }
+
+ return OK;
+}
+
+#if defined(FEAT_ARABIC) || defined(PROTO)
+static char_u *arshape_buf = NULL;
+
+# if defined(EXITFREE) || defined(PROTO)
+ void
+free_cmdline_buf(void)
+{
+ vim_free(arshape_buf);
+}
+# endif
+#endif
+
+/*
+ * Draw part of the cmdline at the current cursor position. But draw stars
+ * when cmdline_star is TRUE.
+ */
+ static void
+draw_cmdline(int start, int len)
+{
+#if defined(FEAT_CRYPT) || defined(FEAT_EVAL)
+ int i;
+
+ if (cmdline_star > 0)
+ for (i = 0; i < len; ++i)
+ {
+ msg_putchar('*');
+ if (has_mbyte)
+ i += (*mb_ptr2len)(ccline.cmdbuff + start + i) - 1;
+ }
+ else
+#endif
+#ifdef FEAT_ARABIC
+ if (p_arshape && !p_tbidi && enc_utf8 && len > 0)
+ {
+ static int buflen = 0;
+ char_u *p;
+ int j;
+ int newlen = 0;
+ int mb_l;
+ int pc, pc1 = 0;
+ int prev_c = 0;
+ int prev_c1 = 0;
+ int u8c;
+ int u8cc[MAX_MCO];
+ int nc = 0;
+
+ /*
+ * Do arabic shaping into a temporary buffer. This is very
+ * inefficient!
+ */
+ if (len * 2 + 2 > buflen)
+ {
+ /* Re-allocate the buffer. We keep it around to avoid a lot of
+ * alloc()/free() calls. */
+ vim_free(arshape_buf);
+ buflen = len * 2 + 2;
+ arshape_buf = alloc(buflen);
+ if (arshape_buf == NULL)
+ return; /* out of memory */
+ }
+
+ if (utf_iscomposing(utf_ptr2char(ccline.cmdbuff + start)))
+ {
+ /* Prepend a space to draw the leading composing char on. */
+ arshape_buf[0] = ' ';
+ newlen = 1;
+ }
+
+ for (j = start; j < start + len; j += mb_l)
+ {
+ p = ccline.cmdbuff + j;
+ u8c = utfc_ptr2char_len(p, u8cc, start + len - j);
+ mb_l = utfc_ptr2len_len(p, start + len - j);
+ if (ARABIC_CHAR(u8c))
+ {
+ /* Do Arabic shaping. */
+ if (cmdmsg_rl)
+ {
+ /* displaying from right to left */
+ pc = prev_c;
+ pc1 = prev_c1;
+ prev_c1 = u8cc[0];
+ if (j + mb_l >= start + len)
+ nc = NUL;
+ else
+ nc = utf_ptr2char(p + mb_l);
+ }
+ else
+ {
+ /* displaying from left to right */
+ if (j + mb_l >= start + len)
+ pc = NUL;
+ else
+ {
+ int pcc[MAX_MCO];
+
+ pc = utfc_ptr2char_len(p + mb_l, pcc,
+ start + len - j - mb_l);
+ pc1 = pcc[0];
+ }
+ nc = prev_c;
+ }
+ prev_c = u8c;
+
+ u8c = arabic_shape(u8c, NULL, &u8cc[0], pc, pc1, nc);
+
+ newlen += (*mb_char2bytes)(u8c, arshape_buf + newlen);
+ if (u8cc[0] != 0)
+ {
+ newlen += (*mb_char2bytes)(u8cc[0], arshape_buf + newlen);
+ if (u8cc[1] != 0)
+ newlen += (*mb_char2bytes)(u8cc[1],
+ arshape_buf + newlen);
+ }
+ }
+ else
+ {
+ prev_c = u8c;
+ mch_memmove(arshape_buf + newlen, p, mb_l);
+ newlen += mb_l;
+ }
+ }
+
+ msg_outtrans_len(arshape_buf, newlen);
+ }
+ else
+#endif
+ msg_outtrans_len(ccline.cmdbuff + start, len);
+}
+
+/*
+ * Put a character on the command line. Shifts the following text to the
+ * right when "shift" is TRUE. Used for CTRL-V, CTRL-K, etc.
+ * "c" must be printable (fit in one display cell)!
+ */
+ void
+putcmdline(int c, int shift)
+{
+ if (cmd_silent)
+ return;
+ msg_no_more = TRUE;
+ msg_putchar(c);
+ if (shift)
+ draw_cmdline(ccline.cmdpos, ccline.cmdlen - ccline.cmdpos);
+ msg_no_more = FALSE;
+ cursorcmd();
+ extra_char = c;
+ extra_char_shift = shift;
+}
+
+/*
+ * Undo a putcmdline(c, FALSE).
+ */
+ void
+unputcmdline(void)
+{
+ if (cmd_silent)
+ return;
+ msg_no_more = TRUE;
+ if (ccline.cmdlen == ccline.cmdpos)
+ msg_putchar(' ');
+ else if (has_mbyte)
+ draw_cmdline(ccline.cmdpos,
+ (*mb_ptr2len)(ccline.cmdbuff + ccline.cmdpos));
+ else
+ draw_cmdline(ccline.cmdpos, 1);
+ msg_no_more = FALSE;
+ cursorcmd();
+ extra_char = NUL;
+}
+
+/*
+ * Put the given string, of the given length, onto the command line.
+ * If len is -1, then STRLEN() is used to calculate the length.
+ * If 'redraw' is TRUE then the new part of the command line, and the remaining
+ * part will be redrawn, otherwise it will not. If this function is called
+ * twice in a row, then 'redraw' should be FALSE and redrawcmd() should be
+ * called afterwards.
+ */
+ int
+put_on_cmdline(char_u *str, int len, int redraw)
+{
+ int retval;
+ int i;
+ int m;
+ int c;
+
+ if (len < 0)
+ len = (int)STRLEN(str);
+
+ /* Check if ccline.cmdbuff needs to be longer */
+ if (ccline.cmdlen + len + 1 >= ccline.cmdbufflen)
+ retval = realloc_cmdbuff(ccline.cmdlen + len + 1);
+ else
+ retval = OK;
+ if (retval == OK)
+ {
+ if (!ccline.overstrike)
+ {
+ mch_memmove(ccline.cmdbuff + ccline.cmdpos + len,
+ ccline.cmdbuff + ccline.cmdpos,
+ (size_t)(ccline.cmdlen - ccline.cmdpos));
+ ccline.cmdlen += len;
+ }
+ else
+ {
+ if (has_mbyte)
+ {
+ /* Count nr of characters in the new string. */
+ m = 0;
+ for (i = 0; i < len; i += (*mb_ptr2len)(str + i))
+ ++m;
+ /* Count nr of bytes in cmdline that are overwritten by these
+ * characters. */
+ for (i = ccline.cmdpos; i < ccline.cmdlen && m > 0;
+ i += (*mb_ptr2len)(ccline.cmdbuff + i))
+ --m;
+ if (i < ccline.cmdlen)
+ {
+ mch_memmove(ccline.cmdbuff + ccline.cmdpos + len,
+ ccline.cmdbuff + i, (size_t)(ccline.cmdlen - i));
+ ccline.cmdlen += ccline.cmdpos + len - i;
+ }
+ else
+ ccline.cmdlen = ccline.cmdpos + len;
+ }
+ else if (ccline.cmdpos + len > ccline.cmdlen)
+ ccline.cmdlen = ccline.cmdpos + len;
+ }
+ mch_memmove(ccline.cmdbuff + ccline.cmdpos, str, (size_t)len);
+ ccline.cmdbuff[ccline.cmdlen] = NUL;
+
+ if (enc_utf8)
+ {
+ /* When the inserted text starts with a composing character,
+ * backup to the character before it. There could be two of them.
+ */
+ i = 0;
+ c = utf_ptr2char(ccline.cmdbuff + ccline.cmdpos);
+ while (ccline.cmdpos > 0 && utf_iscomposing(c))
+ {
+ i = (*mb_head_off)(ccline.cmdbuff,
+ ccline.cmdbuff + ccline.cmdpos - 1) + 1;
+ ccline.cmdpos -= i;
+ len += i;
+ c = utf_ptr2char(ccline.cmdbuff + ccline.cmdpos);
+ }
+#ifdef FEAT_ARABIC
+ if (i == 0 && ccline.cmdpos > 0 && arabic_maycombine(c))
+ {
+ /* Check the previous character for Arabic combining pair. */
+ i = (*mb_head_off)(ccline.cmdbuff,
+ ccline.cmdbuff + ccline.cmdpos - 1) + 1;
+ if (arabic_combine(utf_ptr2char(ccline.cmdbuff
+ + ccline.cmdpos - i), c))
+ {
+ ccline.cmdpos -= i;
+ len += i;
+ }
+ else
+ i = 0;
+ }
+#endif
+ if (i != 0)
+ {
+ /* Also backup the cursor position. */
+ i = ptr2cells(ccline.cmdbuff + ccline.cmdpos);
+ ccline.cmdspos -= i;
+ msg_col -= i;
+ if (msg_col < 0)
+ {
+ msg_col += Columns;
+ --msg_row;
+ }
+ }
+ }
+
+ if (redraw && !cmd_silent)
+ {
+ msg_no_more = TRUE;
+ i = cmdline_row;
+ cursorcmd();
+ draw_cmdline(ccline.cmdpos, ccline.cmdlen - ccline.cmdpos);
+ /* Avoid clearing the rest of the line too often. */
+ if (cmdline_row != i || ccline.overstrike)
+ msg_clr_eos();
+ msg_no_more = FALSE;
+ }
+#ifdef FEAT_FKMAP
+ /*
+ * If we are in Farsi command mode, the character input must be in
+ * Insert mode. So do not advance the cmdpos.
+ */
+ if (!cmd_fkmap)
+#endif
+ {
+ if (KeyTyped)
+ {
+ m = Columns * Rows;
+ if (m < 0) /* overflow, Columns or Rows at weird value */
+ m = MAXCOL;
+ }
+ else
+ m = MAXCOL;
+ for (i = 0; i < len; ++i)
+ {
+ c = cmdline_charsize(ccline.cmdpos);
+ /* count ">" for a double-wide char that doesn't fit. */
+ if (has_mbyte)
+ correct_cmdspos(ccline.cmdpos, c);
+ /* Stop cursor at the end of the screen, but do increment the
+ * insert position, so that entering a very long command
+ * works, even though you can't see it. */
+ if (ccline.cmdspos + c < m)
+ ccline.cmdspos += c;
+
+ if (has_mbyte)
+ {
+ c = (*mb_ptr2len)(ccline.cmdbuff + ccline.cmdpos) - 1;
+ if (c > len - i - 1)
+ c = len - i - 1;
+ ccline.cmdpos += c;
+ i += c;
+ }
+ ++ccline.cmdpos;
+ }
+ }
+ }
+ if (redraw)
+ msg_check();
+ return retval;
+}
+
+static struct cmdline_info prev_ccline;
+static int prev_ccline_used = FALSE;
+
+/*
+ * Save ccline, because obtaining the "=" register may execute "normal :cmd"
+ * and overwrite it. But get_cmdline_str() may need it, thus make it
+ * available globally in prev_ccline.
+ */
+ static void
+save_cmdline(struct cmdline_info *ccp)
+{
+ if (!prev_ccline_used)
+ {
+ vim_memset(&prev_ccline, 0, sizeof(struct cmdline_info));
+ prev_ccline_used = TRUE;
+ }
+ *ccp = prev_ccline;
+ prev_ccline = ccline;
+ ccline.cmdbuff = NULL; // signal that ccline is not in use
+}
+
+/*
+ * Restore ccline after it has been saved with save_cmdline().
+ */
+ static void
+restore_cmdline(struct cmdline_info *ccp)
+{
+ ccline = prev_ccline;
+ prev_ccline = *ccp;
+}
+
+/*
+ * Paste a yank register into the command line.
+ * Used by CTRL-R command in command-line mode.
+ * insert_reg() can't be used here, because special characters from the
+ * register contents will be interpreted as commands.
+ *
+ * Return FAIL for failure, OK otherwise.
+ */
+ static int
+cmdline_paste(
+ int regname,
+ int literally, /* Insert text literally instead of "as typed" */
+ int remcr) /* remove trailing CR */
+{
+ long i;
+ char_u *arg;
+ char_u *p;
+ int allocated;
+
+ /* check for valid regname; also accept special characters for CTRL-R in
+ * the command line */
+ if (regname != Ctrl_F && regname != Ctrl_P && regname != Ctrl_W
+ && regname != Ctrl_A && regname != Ctrl_L
+ && !valid_yank_reg(regname, FALSE))
+ return FAIL;
+
+ /* A register containing CTRL-R can cause an endless loop. Allow using
+ * CTRL-C to break the loop. */
+ line_breakcheck();
+ if (got_int)
+ return FAIL;
+
+#ifdef FEAT_CLIPBOARD
+ regname = may_get_selection(regname);
+#endif
+
+ // Need to set "textlock" to avoid nasty things like going to another
+ // buffer when evaluating an expression.
+ ++textlock;
+ i = get_spec_reg(regname, &arg, &allocated, TRUE);
+ --textlock;
+
+ if (i)
+ {
+ /* Got the value of a special register in "arg". */
+ if (arg == NULL)
+ return FAIL;
+
+ /* When 'incsearch' is set and CTRL-R CTRL-W used: skip the duplicate
+ * part of the word. */
+ p = arg;
+ if (p_is && regname == Ctrl_W)
+ {
+ char_u *w;
+ int len;
+
+ /* Locate start of last word in the cmd buffer. */
+ for (w = ccline.cmdbuff + ccline.cmdpos; w > ccline.cmdbuff; )
+ {
+ if (has_mbyte)
+ {
+ len = (*mb_head_off)(ccline.cmdbuff, w - 1) + 1;
+ if (!vim_iswordc(mb_ptr2char(w - len)))
+ break;
+ w -= len;
+ }
+ else
+ {
+ if (!vim_iswordc(w[-1]))
+ break;
+ --w;
+ }
+ }
+ len = (int)((ccline.cmdbuff + ccline.cmdpos) - w);
+ if (p_ic ? STRNICMP(w, arg, len) == 0 : STRNCMP(w, arg, len) == 0)
+ p += len;
+ }
+
+ cmdline_paste_str(p, literally);
+ if (allocated)
+ vim_free(arg);
+ return OK;
+ }
+
+ return cmdline_paste_reg(regname, literally, remcr);
+}
+
+/*
+ * Put a string on the command line.
+ * When "literally" is TRUE, insert literally.
+ * When "literally" is FALSE, insert as typed, but don't leave the command
+ * line.
+ */
+ void
+cmdline_paste_str(char_u *s, int literally)
+{
+ int c, cv;
+
+ if (literally)
+ put_on_cmdline(s, -1, TRUE);
+ else
+ while (*s != NUL)
+ {
+ cv = *s;
+ if (cv == Ctrl_V && s[1])
+ ++s;
+ if (has_mbyte)
+ c = mb_cptr2char_adv(&s);
+ else
+ c = *s++;
+ if (cv == Ctrl_V || c == ESC || c == Ctrl_C
+ || c == CAR || c == NL || c == Ctrl_L
+#ifdef UNIX
+ || c == intr_char
+#endif
+ || (c == Ctrl_BSL && *s == Ctrl_N))
+ stuffcharReadbuff(Ctrl_V);
+ stuffcharReadbuff(c);
+ }
+}
+
+#ifdef FEAT_WILDMENU
+/*
+ * Delete characters on the command line, from "from" to the current
+ * position.
+ */
+ static void
+cmdline_del(int from)
+{
+ mch_memmove(ccline.cmdbuff + from, ccline.cmdbuff + ccline.cmdpos,
+ (size_t)(ccline.cmdlen - ccline.cmdpos + 1));
+ ccline.cmdlen -= ccline.cmdpos - from;
+ ccline.cmdpos = from;
+}
+#endif
+
+/*
+ * This function is called when the screen size changes and with incremental
+ * search and in other situations where the command line may have been
+ * overwritten.
+ */
+ void
+redrawcmdline(void)
+{
+ redrawcmdline_ex(TRUE);
+}
+
+ void
+redrawcmdline_ex(int do_compute_cmdrow)
+{
+ if (cmd_silent)
+ return;
+ need_wait_return = FALSE;
+ if (do_compute_cmdrow)
+ compute_cmdrow();
+ redrawcmd();
+ cursorcmd();
+}
+
+ static void
+redrawcmdprompt(void)
+{
+ int i;
+
+ if (cmd_silent)
+ return;
+ if (ccline.cmdfirstc != NUL)
+ msg_putchar(ccline.cmdfirstc);
+ if (ccline.cmdprompt != NULL)
+ {
+ msg_puts_attr((char *)ccline.cmdprompt, ccline.cmdattr);
+ ccline.cmdindent = msg_col + (msg_row - cmdline_row) * Columns;
+ /* do the reverse of set_cmdspos() */
+ if (ccline.cmdfirstc != NUL)
+ --ccline.cmdindent;
+ }
+ else
+ for (i = ccline.cmdindent; i > 0; --i)
+ msg_putchar(' ');
+}
+
+/*
+ * Redraw what is currently on the command line.
+ */
+ void
+redrawcmd(void)
+{
+ if (cmd_silent)
+ return;
+
+ /* when 'incsearch' is set there may be no command line while redrawing */
+ if (ccline.cmdbuff == NULL)
+ {
+ windgoto(cmdline_row, 0);
+ msg_clr_eos();
+ return;
+ }
+
+ msg_start();
+ redrawcmdprompt();
+
+ /* Don't use more prompt, truncate the cmdline if it doesn't fit. */
+ msg_no_more = TRUE;
+ draw_cmdline(0, ccline.cmdlen);
+ msg_clr_eos();
+ msg_no_more = FALSE;
+
+ set_cmdspos_cursor();
+ if (extra_char != NUL)
+ putcmdline(extra_char, extra_char_shift);
+
+ /*
+ * An emsg() before may have set msg_scroll. This is used in normal mode,
+ * in cmdline mode we can reset them now.
+ */
+ msg_scroll = FALSE; /* next message overwrites cmdline */
+
+ /* Typing ':' at the more prompt may set skip_redraw. We don't want this
+ * in cmdline mode */
+ skip_redraw = FALSE;
+}
+
+ void
+compute_cmdrow(void)
+{
+ if (exmode_active || msg_scrolled != 0)
+ cmdline_row = Rows - 1;
+ else
+ cmdline_row = W_WINROW(lastwin) + lastwin->w_height
+ + lastwin->w_status_height;
+}
+
+ static void
+cursorcmd(void)
+{
+ if (cmd_silent)
+ return;
+
+#ifdef FEAT_RIGHTLEFT
+ if (cmdmsg_rl)
+ {
+ msg_row = cmdline_row + (ccline.cmdspos / (int)(Columns - 1));
+ msg_col = (int)Columns - (ccline.cmdspos % (int)(Columns - 1)) - 1;
+ if (msg_row <= 0)
+ msg_row = Rows - 1;
+ }
+ else
+#endif
+ {
+ msg_row = cmdline_row + (ccline.cmdspos / (int)Columns);
+ msg_col = ccline.cmdspos % (int)Columns;
+ if (msg_row >= Rows)
+ msg_row = Rows - 1;
+ }
+
+ windgoto(msg_row, msg_col);
+#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
+ if (p_imst == IM_ON_THE_SPOT)
+ redrawcmd_preedit();
+#endif
+#ifdef MCH_CURSOR_SHAPE
+ mch_update_cursor();
+#endif
+}
+
+ void
+gotocmdline(int clr)
+{
+ msg_start();
+#ifdef FEAT_RIGHTLEFT
+ if (cmdmsg_rl)
+ msg_col = Columns - 1;
+ else
+#endif
+ msg_col = 0; /* always start in column 0 */
+ if (clr) /* clear the bottom line(s) */
+ msg_clr_eos(); /* will reset clear_cmdline */
+ windgoto(cmdline_row, 0);
+}
+
+/*
+ * Check the word in front of the cursor for an abbreviation.
+ * Called when the non-id character "c" has been entered.
+ * When an abbreviation is recognized it is removed from the text with
+ * backspaces and the replacement string is inserted, followed by "c".
+ */
+ static int
+ccheck_abbr(int c)
+{
+ int spos = 0;
+
+ if (p_paste || no_abbr) /* no abbreviations or in paste mode */
+ return FALSE;
+
+ /* Do not consider '<,'> be part of the mapping, skip leading whitespace.
+ * Actually accepts any mark. */
+ while (VIM_ISWHITE(ccline.cmdbuff[spos]) && spos < ccline.cmdlen)
+ spos++;
+ if (ccline.cmdlen - spos > 5
+ && ccline.cmdbuff[spos] == '\''
+ && ccline.cmdbuff[spos + 2] == ','
+ && ccline.cmdbuff[spos + 3] == '\'')
+ spos += 5;
+ else
+ /* check abbreviation from the beginning of the commandline */
+ spos = 0;
+
+ return check_abbr(c, ccline.cmdbuff, ccline.cmdpos, spos);
+}
+
+#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
+ static int
+#ifdef __BORLANDC__
+_RTLENTRYF
+#endif
+sort_func_compare(const void *s1, const void *s2)
+{
+ char_u *p1 = *(char_u **)s1;
+ char_u *p2 = *(char_u **)s2;
+
+ if (*p1 != '<' && *p2 == '<') return -1;
+ if (*p1 == '<' && *p2 != '<') return 1;
+ return STRCMP(p1, p2);
+}
+#endif
+
+/*
+ * Return FAIL if this is not an appropriate context in which to do
+ * completion of anything, return OK if it is (even if there are no matches).
+ * For the caller, this means that the character is just passed through like a
+ * normal character (instead of being expanded). This allows :s/^I^D etc.
+ */
+ static int
+nextwild(
+ expand_T *xp,
+ int type,
+ int options, /* extra options for ExpandOne() */
+ int escape) /* if TRUE, escape the returned matches */
+{
+ int i, j;
+ char_u *p1;
+ char_u *p2;
+ int difflen;
+ int v;
+
+ if (xp->xp_numfiles == -1)
+ {
+ set_expand_context(xp);
+ cmd_showtail = expand_showtail(xp);
+ }
+
+ if (xp->xp_context == EXPAND_UNSUCCESSFUL)
+ {
+ beep_flush();
+ return OK; /* Something illegal on command line */
+ }
+ if (xp->xp_context == EXPAND_NOTHING)
+ {
+ /* Caller can use the character as a normal char instead */
+ return FAIL;
+ }
+
+ msg_puts("..."); /* show that we are busy */
+ out_flush();
+
+ i = (int)(xp->xp_pattern - ccline.cmdbuff);
+ xp->xp_pattern_len = ccline.cmdpos - i;
+
+ if (type == WILD_NEXT || type == WILD_PREV)
+ {
+ /*
+ * Get next/previous match for a previous expanded pattern.
+ */
+ p2 = ExpandOne(xp, NULL, NULL, 0, type);
+ }
+ else
+ {
+ /*
+ * Translate string into pattern and expand it.
+ */
+ if ((p1 = addstar(xp->xp_pattern, xp->xp_pattern_len,
+ xp->xp_context)) == NULL)
+ p2 = NULL;
+ else
+ {
+ int use_options = options |
+ WILD_HOME_REPLACE|WILD_ADD_SLASH|WILD_SILENT;
+ if (escape)
+ use_options |= WILD_ESCAPE;
+
+ if (p_wic)
+ use_options += WILD_ICASE;
+ p2 = ExpandOne(xp, p1,
+ vim_strnsave(&ccline.cmdbuff[i], xp->xp_pattern_len),
+ use_options, type);
+ vim_free(p1);
+ /* longest match: make sure it is not shorter, happens with :help */
+ if (p2 != NULL && type == WILD_LONGEST)
+ {
+ for (j = 0; j < xp->xp_pattern_len; ++j)
+ if (ccline.cmdbuff[i + j] == '*'
+ || ccline.cmdbuff[i + j] == '?')
+ break;
+ if ((int)STRLEN(p2) < j)
+ VIM_CLEAR(p2);
+ }
+ }
+ }
+
+ if (p2 != NULL && !got_int)
+ {
+ difflen = (int)STRLEN(p2) - xp->xp_pattern_len;
+ if (ccline.cmdlen + difflen + 4 > ccline.cmdbufflen)
+ {
+ v = realloc_cmdbuff(ccline.cmdlen + difflen + 4);
+ xp->xp_pattern = ccline.cmdbuff + i;
+ }
+ else
+ v = OK;
+ if (v == OK)
+ {
+ mch_memmove(&ccline.cmdbuff[ccline.cmdpos + difflen],
+ &ccline.cmdbuff[ccline.cmdpos],
+ (size_t)(ccline.cmdlen - ccline.cmdpos + 1));
+ mch_memmove(&ccline.cmdbuff[i], p2, STRLEN(p2));
+ ccline.cmdlen += difflen;
+ ccline.cmdpos += difflen;
+ }
+ }
+ vim_free(p2);
+
+ redrawcmd();
+ cursorcmd();
+
+ /* When expanding a ":map" command and no matches are found, assume that
+ * the key is supposed to be inserted literally */
+ if (xp->xp_context == EXPAND_MAPPINGS && p2 == NULL)
+ return FAIL;
+
+ if (xp->xp_numfiles <= 0 && p2 == NULL)
+ beep_flush();
+ else if (xp->xp_numfiles == 1)
+ /* free expanded pattern */
+ (void)ExpandOne(xp, NULL, NULL, 0, WILD_FREE);
+
+ return OK;
+}
+
+/*
+ * Do wildcard expansion on the string 'str'.
+ * Chars that should not be expanded must be preceded with a backslash.
+ * Return a pointer to allocated memory containing the new string.
+ * Return NULL for failure.
+ *
+ * "orig" is the originally expanded string, copied to allocated memory. It
+ * should either be kept in orig_save or freed. When "mode" is WILD_NEXT or
+ * WILD_PREV "orig" should be NULL.
+ *
+ * Results are cached in xp->xp_files and xp->xp_numfiles, except when "mode"
+ * is WILD_EXPAND_FREE or WILD_ALL.
+ *
+ * mode = WILD_FREE: just free previously expanded matches
+ * mode = WILD_EXPAND_FREE: normal expansion, do not keep matches
+ * mode = WILD_EXPAND_KEEP: normal expansion, keep matches
+ * mode = WILD_NEXT: use next match in multiple match, wrap to first
+ * mode = WILD_PREV: use previous match in multiple match, wrap to first
+ * mode = WILD_ALL: return all matches concatenated
+ * mode = WILD_LONGEST: return longest matched part
+ * mode = WILD_ALL_KEEP: get all matches, keep matches
+ *
+ * options = WILD_LIST_NOTFOUND: list entries without a match
+ * options = WILD_HOME_REPLACE: do home_replace() for buffer names
+ * options = WILD_USE_NL: Use '\n' for WILD_ALL
+ * options = WILD_NO_BEEP: Don't beep for multiple matches
+ * options = WILD_ADD_SLASH: add a slash after directory names
+ * options = WILD_KEEP_ALL: don't remove 'wildignore' entries
+ * options = WILD_SILENT: don't print warning messages
+ * options = WILD_ESCAPE: put backslash before special chars
+ * options = WILD_ICASE: ignore case for files
+ *
+ * The variables xp->xp_context and xp->xp_backslash must have been set!
+ */
+ char_u *
+ExpandOne(
+ expand_T *xp,
+ char_u *str,
+ char_u *orig, /* allocated copy of original of expanded string */
+ int options,
+ int mode)
+{
+ char_u *ss = NULL;
+ static int findex;
+ static char_u *orig_save = NULL; /* kept value of orig */
+ int orig_saved = FALSE;
+ int i;
+ long_u len;
+ int non_suf_match; /* number without matching suffix */
+
+ /*
+ * first handle the case of using an old match
+ */
+ if (mode == WILD_NEXT || mode == WILD_PREV)
+ {
+ if (xp->xp_numfiles > 0)
+ {
+ if (mode == WILD_PREV)
+ {
+ if (findex == -1)
+ findex = xp->xp_numfiles;
+ --findex;
+ }
+ else /* mode == WILD_NEXT */
+ ++findex;
+
+ /*
+ * When wrapping around, return the original string, set findex to
+ * -1.
+ */
+ if (findex < 0)
+ {
+ if (orig_save == NULL)
+ findex = xp->xp_numfiles - 1;
+ else
+ findex = -1;
+ }
+ if (findex >= xp->xp_numfiles)
+ {
+ if (orig_save == NULL)
+ findex = 0;
+ else
+ findex = -1;
+ }
+#ifdef FEAT_WILDMENU
+ if (p_wmnu)
+ win_redr_status_matches(xp, xp->xp_numfiles, xp->xp_files,
+ findex, cmd_showtail);
+#endif
+ if (findex == -1)
+ return vim_strsave(orig_save);
+ return vim_strsave(xp->xp_files[findex]);
+ }
+ else
+ return NULL;
+ }
+
+ /* free old names */
+ if (xp->xp_numfiles != -1 && mode != WILD_ALL && mode != WILD_LONGEST)
+ {
+ FreeWild(xp->xp_numfiles, xp->xp_files);
+ xp->xp_numfiles = -1;
+ VIM_CLEAR(orig_save);
+ }
+ findex = 0;
+
+ if (mode == WILD_FREE) /* only release file name */
+ return NULL;
+
+ if (xp->xp_numfiles == -1)
+ {
+ vim_free(orig_save);
+ orig_save = orig;
+ orig_saved = TRUE;
+
+ /*
+ * Do the expansion.
+ */
+ if (ExpandFromContext(xp, str, &xp->xp_numfiles, &xp->xp_files,
+ options) == FAIL)
+ {
+#ifdef FNAME_ILLEGAL
+ /* Illegal file name has been silently skipped. But when there
+ * are wildcards, the real problem is that there was no match,
+ * causing the pattern to be added, which has illegal characters.
+ */
+ if (!(options & WILD_SILENT) && (options & WILD_LIST_NOTFOUND))
+ semsg(_(e_nomatch2), str);
+#endif
+ }
+ else if (xp->xp_numfiles == 0)
+ {
+ if (!(options & WILD_SILENT))
+ semsg(_(e_nomatch2), str);
+ }
+ else
+ {
+ /* Escape the matches for use on the command line. */
+ ExpandEscape(xp, str, xp->xp_numfiles, xp->xp_files, options);
+
+ /*
+ * Check for matching suffixes in file names.
+ */
+ if (mode != WILD_ALL && mode != WILD_ALL_KEEP
+ && mode != WILD_LONGEST)
+ {
+ if (xp->xp_numfiles)
+ non_suf_match = xp->xp_numfiles;
+ else
+ non_suf_match = 1;
+ if ((xp->xp_context == EXPAND_FILES
+ || xp->xp_context == EXPAND_DIRECTORIES)
+ && xp->xp_numfiles > 1)
+ {
+ /*
+ * More than one match; check suffix.
+ * The files will have been sorted on matching suffix in
+ * expand_wildcards, only need to check the first two.
+ */
+ non_suf_match = 0;
+ for (i = 0; i < 2; ++i)
+ if (match_suffix(xp->xp_files[i]))
+ ++non_suf_match;
+ }
+ if (non_suf_match != 1)
+ {
+ /* Can we ever get here unless it's while expanding
+ * interactively? If not, we can get rid of this all
+ * together. Don't really want to wait for this message
+ * (and possibly have to hit return to continue!).
+ */
+ if (!(options & WILD_SILENT))
+ emsg(_(e_toomany));
+ else if (!(options & WILD_NO_BEEP))
+ beep_flush();
+ }
+ if (!(non_suf_match != 1 && mode == WILD_EXPAND_FREE))
+ ss = vim_strsave(xp->xp_files[0]);
+ }
+ }
+ }
+
+ /* Find longest common part */
+ if (mode == WILD_LONGEST && xp->xp_numfiles > 0)
+ {
+ int mb_len = 1;
+ int c0, ci;
+
+ for (len = 0; xp->xp_files[0][len]; len += mb_len)
+ {
+ if (has_mbyte)
+ {
+ mb_len = (*mb_ptr2len)(&xp->xp_files[0][len]);
+ c0 =(* mb_ptr2char)(&xp->xp_files[0][len]);
+ }
+ else
+ c0 = xp->xp_files[0][len];
+ for (i = 1; i < xp->xp_numfiles; ++i)
+ {
+ if (has_mbyte)
+ ci =(* mb_ptr2char)(&xp->xp_files[i][len]);
+ else
+ ci = xp->xp_files[i][len];
+ if (p_fic && (xp->xp_context == EXPAND_DIRECTORIES
+ || xp->xp_context == EXPAND_FILES
+ || xp->xp_context == EXPAND_SHELLCMD
+ || xp->xp_context == EXPAND_BUFFERS))
+ {
+ if (MB_TOLOWER(c0) != MB_TOLOWER(ci))
+ break;
+ }
+ else if (c0 != ci)
+ break;
+ }
+ if (i < xp->xp_numfiles)
+ {
+ if (!(options & WILD_NO_BEEP))
+ vim_beep(BO_WILD);
+ break;
+ }
+ }
+
+ ss = alloc((unsigned)len + 1);
+ if (ss)
+ vim_strncpy(ss, xp->xp_files[0], (size_t)len);
+ findex = -1; /* next p_wc gets first one */
+ }
+
+ /* Concatenate all matching names */
+ if (mode == WILD_ALL && xp->xp_numfiles > 0)
+ {
+ len = 0;
+ for (i = 0; i < xp->xp_numfiles; ++i)
+ len += (long_u)STRLEN(xp->xp_files[i]) + 1;
+ ss = lalloc(len, TRUE);
+ if (ss != NULL)
+ {
+ *ss = NUL;
+ for (i = 0; i < xp->xp_numfiles; ++i)
+ {
+ STRCAT(ss, xp->xp_files[i]);
+ if (i != xp->xp_numfiles - 1)
+ STRCAT(ss, (options & WILD_USE_NL) ? "\n" : " ");
+ }
+ }
+ }
+
+ if (mode == WILD_EXPAND_FREE || mode == WILD_ALL)
+ ExpandCleanup(xp);
+
+ /* Free "orig" if it wasn't stored in "orig_save". */
+ if (!orig_saved)
+ vim_free(orig);
+
+ return ss;
+}
+
+/*
+ * Prepare an expand structure for use.
+ */
+ void
+ExpandInit(expand_T *xp)
+{
+ xp->xp_pattern = NULL;
+ xp->xp_pattern_len = 0;
+ xp->xp_backslash = XP_BS_NONE;
+#ifndef BACKSLASH_IN_FILENAME
+ xp->xp_shell = FALSE;
+#endif
+ xp->xp_numfiles = -1;
+ xp->xp_files = NULL;
+#if defined(FEAT_USR_CMDS) && defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL)
+ xp->xp_arg = NULL;
+#endif
+ xp->xp_line = NULL;
+}
+
+/*
+ * Cleanup an expand structure after use.
+ */
+ void
+ExpandCleanup(expand_T *xp)
+{
+ if (xp->xp_numfiles >= 0)
+ {
+ FreeWild(xp->xp_numfiles, xp->xp_files);
+ xp->xp_numfiles = -1;
+ }
+}
+
+ void
+ExpandEscape(
+ expand_T *xp,
+ char_u *str,
+ int numfiles,
+ char_u **files,
+ int options)
+{
+ int i;
+ char_u *p;
+
+ /*
+ * May change home directory back to "~"
+ */
+ if (options & WILD_HOME_REPLACE)
+ tilde_replace(str, numfiles, files);
+
+ if (options & WILD_ESCAPE)
+ {
+ if (xp->xp_context == EXPAND_FILES
+ || xp->xp_context == EXPAND_FILES_IN_PATH
+ || xp->xp_context == EXPAND_SHELLCMD
+ || xp->xp_context == EXPAND_BUFFERS
+ || xp->xp_context == EXPAND_DIRECTORIES)
+ {
+ /*
+ * Insert a backslash into a file name before a space, \, %, #
+ * and wildmatch characters, except '~'.
+ */
+ for (i = 0; i < numfiles; ++i)
+ {
+ /* for ":set path=" we need to escape spaces twice */
+ if (xp->xp_backslash == XP_BS_THREE)
+ {
+ p = vim_strsave_escaped(files[i], (char_u *)" ");
+ if (p != NULL)
+ {
+ vim_free(files[i]);
+ files[i] = p;
+#if defined(BACKSLASH_IN_FILENAME)
+ p = vim_strsave_escaped(files[i], (char_u *)" ");
+ if (p != NULL)
+ {
+ vim_free(files[i]);
+ files[i] = p;
+ }
+#endif
+ }
+ }
+#ifdef BACKSLASH_IN_FILENAME
+ p = vim_strsave_fnameescape(files[i], FALSE);
+#else
+ p = vim_strsave_fnameescape(files[i], xp->xp_shell);
+#endif
+ if (p != NULL)
+ {
+ vim_free(files[i]);
+ files[i] = p;
+ }
+
+ /* If 'str' starts with "\~", replace "~" at start of
+ * files[i] with "\~". */
+ if (str[0] == '\\' && str[1] == '~' && files[i][0] == '~')
+ escape_fname(&files[i]);
+ }
+ xp->xp_backslash = XP_BS_NONE;
+
+ /* If the first file starts with a '+' escape it. Otherwise it
+ * could be seen as "+cmd". */
+ if (*files[0] == '+')
+ escape_fname(&files[0]);
+ }
+ else if (xp->xp_context == EXPAND_TAGS)
+ {
+ /*
+ * Insert a backslash before characters in a tag name that
+ * would terminate the ":tag" command.
+ */
+ for (i = 0; i < numfiles; ++i)
+ {
+ p = vim_strsave_escaped(files[i], (char_u *)"\\|\"");
+ if (p != NULL)
+ {
+ vim_free(files[i]);
+ files[i] = p;
+ }
+ }
+ }
+ }
+}
+
+/*
+ * Escape special characters in "fname" for when used as a file name argument
+ * after a Vim command, or, when "shell" is non-zero, a shell command.
+ * Returns the result in allocated memory.
+ */
+ char_u *
+vim_strsave_fnameescape(char_u *fname, int shell)
+{
+ char_u *p;
+#ifdef BACKSLASH_IN_FILENAME
+ char_u buf[20];
+ int j = 0;
+
+ /* Don't escape '[', '{' and '!' if they are in 'isfname'. */
+ for (p = PATH_ESC_CHARS; *p != NUL; ++p)
+ if ((*p != '[' && *p != '{' && *p != '!') || !vim_isfilec(*p))
+ buf[j++] = *p;
+ buf[j] = NUL;
+ p = vim_strsave_escaped(fname, buf);
+#else
+ p = vim_strsave_escaped(fname, shell ? SHELL_ESC_CHARS : PATH_ESC_CHARS);
+ if (shell && csh_like_shell() && p != NULL)
+ {
+ char_u *s;
+
+ /* For csh and similar shells need to put two backslashes before '!'.
+ * One is taken by Vim, one by the shell. */
+ s = vim_strsave_escaped(p, (char_u *)"!");
+ vim_free(p);
+ p = s;
+ }
+#endif
+
+ /* '>' and '+' are special at the start of some commands, e.g. ":edit" and
+ * ":write". "cd -" has a special meaning. */
+ if (p != NULL && (*p == '>' || *p == '+' || (*p == '-' && p[1] == NUL)))
+ escape_fname(&p);
+
+ return p;
+}
+
+/*
+ * Put a backslash before the file name in "pp", which is in allocated memory.
+ */
+ static void
+escape_fname(char_u **pp)
+{
+ char_u *p;
+
+ p = alloc((unsigned)(STRLEN(*pp) + 2));
+ if (p != NULL)
+ {
+ p[0] = '\\';
+ STRCPY(p + 1, *pp);
+ vim_free(*pp);
+ *pp = p;
+ }
+}
+
+/*
+ * For each file name in files[num_files]:
+ * If 'orig_pat' starts with "~/", replace the home directory with "~".
+ */
+ void
+tilde_replace(
+ char_u *orig_pat,
+ int num_files,
+ char_u **files)
+{
+ int i;
+ char_u *p;
+
+ if (orig_pat[0] == '~' && vim_ispathsep(orig_pat[1]))
+ {
+ for (i = 0; i < num_files; ++i)
+ {
+ p = home_replace_save(NULL, files[i]);
+ if (p != NULL)
+ {
+ vim_free(files[i]);
+ files[i] = p;
+ }
+ }
+ }
+}
+
+/*
+ * Show all matches for completion on the command line.
+ * Returns EXPAND_NOTHING when the character that triggered expansion should
+ * be inserted like a normal character.
+ */
+ static int
+showmatches(expand_T *xp, int wildmenu UNUSED)
+{
+#define L_SHOWFILE(m) (showtail ? sm_gettail(files_found[m]) : files_found[m])
+ int num_files;
+ char_u **files_found;
+ int i, j, k;
+ int maxlen;
+ int lines;
+ int columns;
+ char_u *p;
+ int lastlen;
+ int attr;
+ int showtail;
+
+ if (xp->xp_numfiles == -1)
+ {
+ set_expand_context(xp);
+ i = expand_cmdline(xp, ccline.cmdbuff, ccline.cmdpos,
+ &num_files, &files_found);
+ showtail = expand_showtail(xp);
+ if (i != EXPAND_OK)
+ return i;
+
+ }
+ else
+ {
+ num_files = xp->xp_numfiles;
+ files_found = xp->xp_files;
+ showtail = cmd_showtail;
+ }
+
+#ifdef FEAT_WILDMENU
+ if (!wildmenu)
+ {
+#endif
+ msg_didany = FALSE; /* lines_left will be set */
+ msg_start(); /* prepare for paging */
+ msg_putchar('\n');
+ out_flush();
+ cmdline_row = msg_row;
+ msg_didany = FALSE; /* lines_left will be set again */
+ msg_start(); /* prepare for paging */
+#ifdef FEAT_WILDMENU
+ }
+#endif
+
+ if (got_int)
+ got_int = FALSE; /* only int. the completion, not the cmd line */
+#ifdef FEAT_WILDMENU
+ else if (wildmenu)
+ win_redr_status_matches(xp, num_files, files_found, -1, showtail);
+#endif
+ else
+ {
+ /* find the length of the longest file name */
+ maxlen = 0;
+ for (i = 0; i < num_files; ++i)
+ {
+ if (!showtail && (xp->xp_context == EXPAND_FILES
+ || xp->xp_context == EXPAND_SHELLCMD
+ || xp->xp_context == EXPAND_BUFFERS))
+ {
+ home_replace(NULL, files_found[i], NameBuff, MAXPATHL, TRUE);
+ j = vim_strsize(NameBuff);
+ }
+ else
+ j = vim_strsize(L_SHOWFILE(i));
+ if (j > maxlen)
+ maxlen = j;
+ }
+
+ if (xp->xp_context == EXPAND_TAGS_LISTFILES)
+ lines = num_files;
+ else
+ {
+ /* compute the number of columns and lines for the listing */
+ maxlen += 2; /* two spaces between file names */
+ columns = ((int)Columns + 2) / maxlen;
+ if (columns < 1)
+ columns = 1;
+ lines = (num_files + columns - 1) / columns;
+ }
+
+ attr = HL_ATTR(HLF_D); /* find out highlighting for directories */
+
+ if (xp->xp_context == EXPAND_TAGS_LISTFILES)
+ {
+ msg_puts_attr(_("tagname"), HL_ATTR(HLF_T));
+ msg_clr_eos();
+ msg_advance(maxlen - 3);
+ msg_puts_attr(_(" kind file\n"), HL_ATTR(HLF_T));
+ }
+
+ /* list the files line by line */
+ for (i = 0; i < lines; ++i)
+ {
+ lastlen = 999;
+ for (k = i; k < num_files; k += lines)
+ {
+ if (xp->xp_context == EXPAND_TAGS_LISTFILES)
+ {
+ msg_outtrans_attr(files_found[k], HL_ATTR(HLF_D));
+ p = files_found[k] + STRLEN(files_found[k]) + 1;
+ msg_advance(maxlen + 1);
+ msg_puts((char *)p);
+ msg_advance(maxlen + 3);
+ msg_outtrans_long_attr(p + 2, HL_ATTR(HLF_D));
+ break;
+ }
+ for (j = maxlen - lastlen; --j >= 0; )
+ msg_putchar(' ');
+ if (xp->xp_context == EXPAND_FILES
+ || xp->xp_context == EXPAND_SHELLCMD
+ || xp->xp_context == EXPAND_BUFFERS)
+ {
+ /* highlight directories */
+ if (xp->xp_numfiles != -1)
+ {
+ char_u *halved_slash;
+ char_u *exp_path;
+
+ /* Expansion was done before and special characters
+ * were escaped, need to halve backslashes. Also
+ * $HOME has been replaced with ~/. */
+ exp_path = expand_env_save_opt(files_found[k], TRUE);
+ halved_slash = backslash_halve_save(
+ exp_path != NULL ? exp_path : files_found[k]);
+ j = mch_isdir(halved_slash != NULL ? halved_slash
+ : files_found[k]);
+ vim_free(exp_path);
+ vim_free(halved_slash);
+ }
+ else
+ /* Expansion was done here, file names are literal. */
+ j = mch_isdir(files_found[k]);
+ if (showtail)
+ p = L_SHOWFILE(k);
+ else
+ {
+ home_replace(NULL, files_found[k], NameBuff, MAXPATHL,
+ TRUE);
+ p = NameBuff;
+ }
+ }
+ else
+ {
+ j = FALSE;
+ p = L_SHOWFILE(k);
+ }
+ lastlen = msg_outtrans_attr(p, j ? attr : 0);
+ }
+ if (msg_col > 0) /* when not wrapped around */
+ {
+ msg_clr_eos();
+ msg_putchar('\n');
+ }
+ out_flush(); /* show one line at a time */
+ if (got_int)
+ {
+ got_int = FALSE;
+ break;
+ }
+ }
+
+ /*
+ * we redraw the command below the lines that we have just listed
+ * This is a bit tricky, but it saves a lot of screen updating.
+ */
+ cmdline_row = msg_row; /* will put it back later */
+ }
+
+ if (xp->xp_numfiles == -1)
+ FreeWild(num_files, files_found);
+
+ return EXPAND_OK;
+}
+
+/*
+ * Private gettail for showmatches() (and win_redr_status_matches()):
+ * Find tail of file name path, but ignore trailing "/".
+ */
+ char_u *
+sm_gettail(char_u *s)
+{
+ char_u *p;
+ char_u *t = s;
+ int had_sep = FALSE;
+
+ for (p = s; *p != NUL; )
+ {
+ if (vim_ispathsep(*p)
+#ifdef BACKSLASH_IN_FILENAME
+ && !rem_backslash(p)
+#endif
+ )
+ had_sep = TRUE;
+ else if (had_sep)
+ {
+ t = p;
+ had_sep = FALSE;
+ }
+ MB_PTR_ADV(p);
+ }
+ return t;
+}
+
+/*
+ * Return TRUE if we only need to show the tail of completion matches.
+ * When not completing file names or there is a wildcard in the path FALSE is
+ * returned.
+ */
+ static int
+expand_showtail(expand_T *xp)
+{
+ char_u *s;
+ char_u *end;
+
+ /* When not completing file names a "/" may mean something different. */
+ if (xp->xp_context != EXPAND_FILES
+ && xp->xp_context != EXPAND_SHELLCMD
+ && xp->xp_context != EXPAND_DIRECTORIES)
+ return FALSE;
+
+ end = gettail(xp->xp_pattern);
+ if (end == xp->xp_pattern) /* there is no path separator */
+ return FALSE;
+
+ for (s = xp->xp_pattern; s < end; s++)
+ {
+ /* Skip escaped wildcards. Only when the backslash is not a path
+ * separator, on DOS the '*' "path\*\file" must not be skipped. */
+ if (rem_backslash(s))
+ ++s;
+ else if (vim_strchr((char_u *)"*?[", *s) != NULL)
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*
+ * Prepare a string for expansion.
+ * When expanding file names: The string will be used with expand_wildcards().
+ * Copy "fname[len]" into allocated memory and add a '*' at the end.
+ * When expanding other names: The string will be used with regcomp(). Copy
+ * the name into allocated memory and prepend "^".
+ */
+ char_u *
+addstar(
+ char_u *fname,
+ int len,
+ int context) /* EXPAND_FILES etc. */
+{
+ char_u *retval;
+ int i, j;
+ int new_len;
+ char_u *tail;
+ int ends_in_star;
+
+ if (context != EXPAND_FILES
+ && context != EXPAND_FILES_IN_PATH
+ && context != EXPAND_SHELLCMD
+ && context != EXPAND_DIRECTORIES)
+ {
+ /*
+ * Matching will be done internally (on something other than files).
+ * So we convert the file-matching-type wildcards into our kind for
+ * use with vim_regcomp(). First work out how long it will be:
+ */
+
+ /* For help tags the translation is done in find_help_tags().
+ * For a tag pattern starting with "/" no translation is needed. */
+ if (context == EXPAND_HELP
+ || context == EXPAND_COLORS
+ || context == EXPAND_COMPILER
+ || context == EXPAND_OWNSYNTAX
+ || context == EXPAND_FILETYPE
+ || context == EXPAND_PACKADD
+ || ((context == EXPAND_TAGS_LISTFILES
+ || context == EXPAND_TAGS)
+ && fname[0] == '/'))
+ retval = vim_strnsave(fname, len);
+ else
+ {
+ new_len = len + 2; /* +2 for '^' at start, NUL at end */
+ for (i = 0; i < len; i++)
+ {
+ if (fname[i] == '*' || fname[i] == '~')
+ new_len++; /* '*' needs to be replaced by ".*"
+ '~' needs to be replaced by "\~" */
+
+ /* Buffer names are like file names. "." should be literal */
+ if (context == EXPAND_BUFFERS && fname[i] == '.')
+ new_len++; /* "." becomes "\." */
+
+ /* Custom expansion takes care of special things, match
+ * backslashes literally (perhaps also for other types?) */
+ if ((context == EXPAND_USER_DEFINED
+ || context == EXPAND_USER_LIST) && fname[i] == '\\')
+ new_len++; /* '\' becomes "\\" */
+ }
+ retval = alloc(new_len);
+ if (retval != NULL)
+ {
+ retval[0] = '^';
+ j = 1;
+ for (i = 0; i < len; i++, j++)
+ {
+ /* Skip backslash. But why? At least keep it for custom
+ * expansion. */
+ if (context != EXPAND_USER_DEFINED
+ && context != EXPAND_USER_LIST
+ && fname[i] == '\\'
+ && ++i == len)
+ break;
+
+ switch (fname[i])
+ {
+ case '*': retval[j++] = '.';
+ break;
+ case '~': retval[j++] = '\\';
+ break;
+ case '?': retval[j] = '.';
+ continue;
+ case '.': if (context == EXPAND_BUFFERS)
+ retval[j++] = '\\';
+ break;
+ case '\\': if (context == EXPAND_USER_DEFINED
+ || context == EXPAND_USER_LIST)
+ retval[j++] = '\\';
+ break;
+ }
+ retval[j] = fname[i];
+ }
+ retval[j] = NUL;
+ }
+ }
+ }
+ else
+ {
+ retval = alloc(len + 4);
+ if (retval != NULL)
+ {
+ vim_strncpy(retval, fname, len);
+
+ /*
+ * Don't add a star to *, ~, ~user, $var or `cmd`.
+ * * would become **, which walks the whole tree.
+ * ~ would be at the start of the file name, but not the tail.
+ * $ could be anywhere in the tail.
+ * ` could be anywhere in the file name.
+ * When the name ends in '$' don't add a star, remove the '$'.
+ */
+ tail = gettail(retval);
+ ends_in_star = (len > 0 && retval[len - 1] == '*');
+#ifndef BACKSLASH_IN_FILENAME
+ for (i = len - 2; i >= 0; --i)
+ {
+ if (retval[i] != '\\')
+ break;
+ ends_in_star = !ends_in_star;
+ }
+#endif
+ if ((*retval != '~' || tail != retval)
+ && !ends_in_star
+ && vim_strchr(tail, '$') == NULL
+ && vim_strchr(retval, '`') == NULL)
+ retval[len++] = '*';
+ else if (len > 0 && retval[len - 1] == '$')
+ --len;
+ retval[len] = NUL;
+ }
+ }
+ return retval;
+}
+
+/*
+ * Must parse the command line so far to work out what context we are in.
+ * Completion can then be done based on that context.
+ * This routine sets the variables:
+ * xp->xp_pattern The start of the pattern to be expanded within
+ * the command line (ends at the cursor).
+ * xp->xp_context The type of thing to expand. Will be one of:
+ *
+ * EXPAND_UNSUCCESSFUL Used sometimes when there is something illegal on
+ * the command line, like an unknown command. Caller
+ * should beep.
+ * EXPAND_NOTHING Unrecognised context for completion, use char like
+ * a normal char, rather than for completion. eg
+ * :s/^I/
+ * EXPAND_COMMANDS Cursor is still touching the command, so complete
+ * it.
+ * EXPAND_BUFFERS Complete file names for :buf and :sbuf commands.
+ * EXPAND_FILES After command with XFILE set, or after setting
+ * with P_EXPAND set. eg :e ^I, :w>>^I
+ * EXPAND_DIRECTORIES In some cases this is used instead of the latter
+ * when we know only directories are of interest. eg
+ * :set dir=^I
+ * EXPAND_SHELLCMD After ":!cmd", ":r !cmd" or ":w !cmd".
+ * EXPAND_SETTINGS Complete variable names. eg :set d^I
+ * EXPAND_BOOL_SETTINGS Complete boolean variables only, eg :set no^I
+ * EXPAND_TAGS Complete tags from the files in p_tags. eg :ta a^I
+ * EXPAND_TAGS_LISTFILES As above, but list filenames on ^D, after :tselect
+ * EXPAND_HELP Complete tags from the file 'helpfile'/tags
+ * EXPAND_EVENTS Complete event names
+ * EXPAND_SYNTAX Complete :syntax command arguments
+ * EXPAND_HIGHLIGHT Complete highlight (syntax) group names
+ * EXPAND_AUGROUP Complete autocommand group names
+ * EXPAND_USER_VARS Complete user defined variable names, eg :unlet a^I
+ * EXPAND_MAPPINGS Complete mapping and abbreviation names,
+ * eg :unmap a^I , :cunab x^I
+ * EXPAND_FUNCTIONS Complete internal or user defined function names,
+ * eg :call sub^I
+ * EXPAND_USER_FUNC Complete user defined function names, eg :delf F^I
+ * EXPAND_EXPRESSION Complete internal or user defined function/variable
+ * names in expressions, eg :while s^I
+ * EXPAND_ENV_VARS Complete environment variable names
+ * EXPAND_USER Complete user names
+ */
+ static void
+set_expand_context(expand_T *xp)
+{
+ /* only expansion for ':', '>' and '=' command-lines */
+ if (ccline.cmdfirstc != ':'
+#ifdef FEAT_EVAL
+ && ccline.cmdfirstc != '>' && ccline.cmdfirstc != '='
+ && !ccline.input_fn
+#endif
+ )
+ {
+ xp->xp_context = EXPAND_NOTHING;
+ return;
+ }
+ set_cmd_context(xp, ccline.cmdbuff, ccline.cmdlen, ccline.cmdpos, TRUE);
+}
+
+ void
+set_cmd_context(
+ expand_T *xp,
+ char_u *str, /* start of command line */
+ int len, /* length of command line (excl. NUL) */
+ int col, /* position of cursor */
+ int use_ccline UNUSED) /* use ccline for info */
+{
+ int old_char = NUL;
+ char_u *nextcomm;
+
+ /*
+ * Avoid a UMR warning from Purify, only save the character if it has been
+ * written before.
+ */
+ if (col < len)
+ old_char = str[col];
+ str[col] = NUL;
+ nextcomm = str;
+
+#ifdef FEAT_EVAL
+ if (use_ccline && ccline.cmdfirstc == '=')
+ {
+# ifdef FEAT_CMDL_COMPL
+ /* pass CMD_SIZE because there is no real command */
+ set_context_for_expression(xp, str, CMD_SIZE);
+# endif
+ }
+ else if (use_ccline && ccline.input_fn)
+ {
+ xp->xp_context = ccline.xp_context;
+ xp->xp_pattern = ccline.cmdbuff;
+# if defined(FEAT_USR_CMDS) && defined(FEAT_CMDL_COMPL)
+ xp->xp_arg = ccline.xp_arg;
+# endif
+ }
+ else
+#endif
+ while (nextcomm != NULL)
+ nextcomm = set_one_cmd_context(xp, nextcomm);
+
+ /* Store the string here so that call_user_expand_func() can get to them
+ * easily. */
+ xp->xp_line = str;
+ xp->xp_col = col;
+
+ str[col] = old_char;
+}
+
+/*
+ * Expand the command line "str" from context "xp".
+ * "xp" must have been set by set_cmd_context().
+ * xp->xp_pattern points into "str", to where the text that is to be expanded
+ * starts.
+ * Returns EXPAND_UNSUCCESSFUL when there is something illegal before the
+ * cursor.
+ * Returns EXPAND_NOTHING when there is nothing to expand, might insert the
+ * key that triggered expansion literally.
+ * Returns EXPAND_OK otherwise.
+ */
+ int
+expand_cmdline(
+ expand_T *xp,
+ char_u *str, /* start of command line */
+ int col, /* position of cursor */
+ int *matchcount, /* return: nr of matches */
+ char_u ***matches) /* return: array of pointers to matches */
+{
+ char_u *file_str = NULL;
+ int options = WILD_ADD_SLASH|WILD_SILENT;
+
+ if (xp->xp_context == EXPAND_UNSUCCESSFUL)
+ {
+ beep_flush();
+ return EXPAND_UNSUCCESSFUL; /* Something illegal on command line */
+ }
+ if (xp->xp_context == EXPAND_NOTHING)
+ {
+ /* Caller can use the character as a normal char instead */
+ return EXPAND_NOTHING;
+ }
+
+ /* add star to file name, or convert to regexp if not exp. files. */
+ xp->xp_pattern_len = (int)(str + col - xp->xp_pattern);
+ file_str = addstar(xp->xp_pattern, xp->xp_pattern_len, xp->xp_context);
+ if (file_str == NULL)
+ return EXPAND_UNSUCCESSFUL;
+
+ if (p_wic)
+ options += WILD_ICASE;
+
+ /* find all files that match the description */
+ if (ExpandFromContext(xp, file_str, matchcount, matches, options) == FAIL)
+ {
+ *matchcount = 0;
+ *matches = NULL;
+ }
+ vim_free(file_str);
+
+ return EXPAND_OK;
+}
+
+#ifdef FEAT_MULTI_LANG
+/*
+ * Cleanup matches for help tags:
+ * Remove "@ab" if the top of 'helplang' is "ab" and the language of the first
+ * tag matches it. Otherwise remove "@en" if "en" is the only language.
+ */
+ static void
+cleanup_help_tags(int num_file, char_u **file)
+{
+ int i, j;
+ int len;
+ char_u buf[4];
+ char_u *p = buf;
+
+ if (p_hlg[0] != NUL && (p_hlg[0] != 'e' || p_hlg[1] != 'n'))
+ {
+ *p++ = '@';
+ *p++ = p_hlg[0];
+ *p++ = p_hlg[1];
+ }
+ *p = NUL;
+
+ for (i = 0; i < num_file; ++i)
+ {
+ len = (int)STRLEN(file[i]) - 3;
+ if (len <= 0)
+ continue;
+ if (STRCMP(file[i] + len, "@en") == 0)
+ {
+ /* Sorting on priority means the same item in another language may
+ * be anywhere. Search all items for a match up to the "@en". */
+ for (j = 0; j < num_file; ++j)
+ if (j != i && (int)STRLEN(file[j]) == len + 3
+ && STRNCMP(file[i], file[j], len + 1) == 0)
+ break;
+ if (j == num_file)
+ /* item only exists with @en, remove it */
+ file[i][len] = NUL;
+ }
+ }
+
+ if (*buf != NUL)
+ for (i = 0; i < num_file; ++i)
+ {
+ len = (int)STRLEN(file[i]) - 3;
+ if (len <= 0)
+ continue;
+ if (STRCMP(file[i] + len, buf) == 0)
+ {
+ /* remove the default language */
+ file[i][len] = NUL;
+ }
+ }
+}
+#endif
+
+/*
+ * Do the expansion based on xp->xp_context and "pat".
+ */
+ static int
+ExpandFromContext(
+ expand_T *xp,
+ char_u *pat,
+ int *num_file,
+ char_u ***file,
+ int options) /* EW_ flags */
+{
+#ifdef FEAT_CMDL_COMPL
+ regmatch_T regmatch;
+#endif
+ int ret;
+ int flags;
+
+ flags = EW_DIR; /* include directories */
+ if (options & WILD_LIST_NOTFOUND)
+ flags |= EW_NOTFOUND;
+ if (options & WILD_ADD_SLASH)
+ flags |= EW_ADDSLASH;
+ if (options & WILD_KEEP_ALL)
+ flags |= EW_KEEPALL;
+ if (options & WILD_SILENT)
+ flags |= EW_SILENT;
+ if (options & WILD_ALLLINKS)
+ flags |= EW_ALLLINKS;
+
+ if (xp->xp_context == EXPAND_FILES
+ || xp->xp_context == EXPAND_DIRECTORIES
+ || xp->xp_context == EXPAND_FILES_IN_PATH)
+ {
+ /*
+ * Expand file or directory names.
+ */
+ int free_pat = FALSE;
+ int i;
+
+ /* for ":set path=" and ":set tags=" halve backslashes for escaped
+ * space */
+ if (xp->xp_backslash != XP_BS_NONE)
+ {
+ free_pat = TRUE;
+ pat = vim_strsave(pat);
+ for (i = 0; pat[i]; ++i)
+ if (pat[i] == '\\')
+ {
+ if (xp->xp_backslash == XP_BS_THREE
+ && pat[i + 1] == '\\'
+ && pat[i + 2] == '\\'
+ && pat[i + 3] == ' ')
+ STRMOVE(pat + i, pat + i + 3);
+ if (xp->xp_backslash == XP_BS_ONE
+ && pat[i + 1] == ' ')
+ STRMOVE(pat + i, pat + i + 1);
+ }
+ }
+
+ if (xp->xp_context == EXPAND_FILES)
+ flags |= EW_FILE;
+ else if (xp->xp_context == EXPAND_FILES_IN_PATH)
+ flags |= (EW_FILE | EW_PATH);
+ else
+ flags = (flags | EW_DIR) & ~EW_FILE;
+ if (options & WILD_ICASE)
+ flags |= EW_ICASE;
+
+ /* Expand wildcards, supporting %:h and the like. */
+ ret = expand_wildcards_eval(&pat, num_file, file, flags);
+ if (free_pat)
+ vim_free(pat);
+ return ret;
+ }
+
+ *file = (char_u **)"";
+ *num_file = 0;
+ if (xp->xp_context == EXPAND_HELP)
+ {
+ /* With an empty argument we would get all the help tags, which is
+ * very slow. Get matches for "help" instead. */
+ if (find_help_tags(*pat == NUL ? (char_u *)"help" : pat,
+ num_file, file, FALSE) == OK)
+ {
+#ifdef FEAT_MULTI_LANG
+ cleanup_help_tags(*num_file, *file);
+#endif
+ return OK;
+ }
+ return FAIL;
+ }
+
+#ifndef FEAT_CMDL_COMPL
+ return FAIL;
+#else
+ if (xp->xp_context == EXPAND_SHELLCMD)
+ return expand_shellcmd(pat, num_file, file, flags);
+ if (xp->xp_context == EXPAND_OLD_SETTING)
+ return ExpandOldSetting(num_file, file);
+ if (xp->xp_context == EXPAND_BUFFERS)
+ return ExpandBufnames(pat, num_file, file, options);
+ if (xp->xp_context == EXPAND_TAGS
+ || xp->xp_context == EXPAND_TAGS_LISTFILES)
+ return expand_tags(xp->xp_context == EXPAND_TAGS, pat, num_file, file);
+ if (xp->xp_context == EXPAND_COLORS)
+ {
+ char *directories[] = {"colors", NULL};
+ return ExpandRTDir(pat, DIP_START + DIP_OPT, num_file, file,
+ directories);
+ }
+ if (xp->xp_context == EXPAND_COMPILER)
+ {
+ char *directories[] = {"compiler", NULL};
+ return ExpandRTDir(pat, 0, num_file, file, directories);
+ }
+ if (xp->xp_context == EXPAND_OWNSYNTAX)
+ {
+ char *directories[] = {"syntax", NULL};
+ return ExpandRTDir(pat, 0, num_file, file, directories);
+ }
+ if (xp->xp_context == EXPAND_FILETYPE)
+ {
+ char *directories[] = {"syntax", "indent", "ftplugin", NULL};
+ return ExpandRTDir(pat, 0, num_file, file, directories);
+ }
+# if defined(FEAT_USR_CMDS) && defined(FEAT_EVAL)
+ if (xp->xp_context == EXPAND_USER_LIST)
+ return ExpandUserList(xp, num_file, file);
+# endif
+ if (xp->xp_context == EXPAND_PACKADD)
+ return ExpandPackAddDir(pat, num_file, file);
+
+ regmatch.regprog = vim_regcomp(pat, p_magic ? RE_MAGIC : 0);
+ if (regmatch.regprog == NULL)
+ return FAIL;
+
+ /* set ignore-case according to p_ic, p_scs and pat */
+ regmatch.rm_ic = ignorecase(pat);
+
+ if (xp->xp_context == EXPAND_SETTINGS
+ || xp->xp_context == EXPAND_BOOL_SETTINGS)
+ ret = ExpandSettings(xp, &regmatch, num_file, file);
+ else if (xp->xp_context == EXPAND_MAPPINGS)
+ ret = ExpandMappings(&regmatch, num_file, file);
+# if defined(FEAT_USR_CMDS) && defined(FEAT_EVAL)
+ else if (xp->xp_context == EXPAND_USER_DEFINED)
+ ret = ExpandUserDefined(xp, &regmatch, num_file, file);
+# endif
+ else
+ {
+ static struct expgen
+ {
+ int context;
+ char_u *((*func)(expand_T *, int));
+ int ic;
+ int escaped;
+ } tab[] =
+ {
+ {EXPAND_COMMANDS, get_command_name, FALSE, TRUE},
+ {EXPAND_BEHAVE, get_behave_arg, TRUE, TRUE},
+ {EXPAND_MAPCLEAR, get_mapclear_arg, TRUE, TRUE},
+ {EXPAND_MESSAGES, get_messages_arg, TRUE, TRUE},
+#ifdef FEAT_CMDHIST
+ {EXPAND_HISTORY, get_history_arg, TRUE, TRUE},
+#endif
+#ifdef FEAT_USR_CMDS
+ {EXPAND_USER_COMMANDS, get_user_commands, FALSE, TRUE},
+ {EXPAND_USER_ADDR_TYPE, get_user_cmd_addr_type, FALSE, TRUE},
+ {EXPAND_USER_CMD_FLAGS, get_user_cmd_flags, FALSE, TRUE},
+ {EXPAND_USER_NARGS, get_user_cmd_nargs, FALSE, TRUE},
+ {EXPAND_USER_COMPLETE, get_user_cmd_complete, FALSE, TRUE},
+#endif
+#ifdef FEAT_EVAL
+ {EXPAND_USER_VARS, get_user_var_name, FALSE, TRUE},
+ {EXPAND_FUNCTIONS, get_function_name, FALSE, TRUE},
+ {EXPAND_USER_FUNC, get_user_func_name, FALSE, TRUE},
+ {EXPAND_EXPRESSION, get_expr_name, FALSE, TRUE},
+#endif
+#ifdef FEAT_MENU
+ {EXPAND_MENUS, get_menu_name, FALSE, TRUE},
+ {EXPAND_MENUNAMES, get_menu_names, FALSE, TRUE},
+#endif
+#ifdef FEAT_SYN_HL
+ {EXPAND_SYNTAX, get_syntax_name, TRUE, TRUE},
+#endif
+#ifdef FEAT_PROFILE
+ {EXPAND_SYNTIME, get_syntime_arg, TRUE, TRUE},
+#endif
+ {EXPAND_HIGHLIGHT, get_highlight_name, TRUE, TRUE},
+ {EXPAND_EVENTS, get_event_name, TRUE, TRUE},
+ {EXPAND_AUGROUP, get_augroup_name, TRUE, TRUE},
+#ifdef FEAT_CSCOPE
+ {EXPAND_CSCOPE, get_cscope_name, TRUE, TRUE},
+#endif
+#ifdef FEAT_SIGNS
+ {EXPAND_SIGN, get_sign_name, TRUE, TRUE},
+#endif
+#ifdef FEAT_PROFILE
+ {EXPAND_PROFILE, get_profile_name, TRUE, TRUE},
+#endif
+#if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
+ {EXPAND_LANGUAGE, get_lang_arg, TRUE, FALSE},
+ {EXPAND_LOCALES, get_locales, TRUE, FALSE},
+#endif
+ {EXPAND_ENV_VARS, get_env_name, TRUE, TRUE},
+ {EXPAND_USER, get_users, TRUE, FALSE},
+ {EXPAND_ARGLIST, get_arglist_name, TRUE, FALSE},
+ };
+ int i;
+
+ /*
+ * Find a context in the table and call the ExpandGeneric() with the
+ * right function to do the expansion.
+ */
+ ret = FAIL;
+ for (i = 0; i < (int)(sizeof(tab) / sizeof(struct expgen)); ++i)
+ if (xp->xp_context == tab[i].context)
+ {
+ if (tab[i].ic)
+ regmatch.rm_ic = TRUE;
+ ret = ExpandGeneric(xp, &regmatch, num_file, file,
+ tab[i].func, tab[i].escaped);
+ break;
+ }
+ }
+
+ vim_regfree(regmatch.regprog);
+
+ return ret;
+#endif /* FEAT_CMDL_COMPL */
+}
+
+#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
+/*
+ * Expand a list of names.
+ *
+ * Generic function for command line completion. It calls a function to
+ * obtain strings, one by one. The strings are matched against a regexp
+ * program. Matching strings are copied into an array, which is returned.
+ *
+ * Returns OK when no problems encountered, FAIL for error (out of memory).
+ */
+ int
+ExpandGeneric(
+ expand_T *xp,
+ regmatch_T *regmatch,
+ int *num_file,
+ char_u ***file,
+ char_u *((*func)(expand_T *, int)),
+ /* returns a string from the list */
+ int escaped)
+{
+ int i;
+ int count = 0;
+ int round;
+ char_u *str;
+
+ /* do this loop twice:
+ * round == 0: count the number of matching names
+ * round == 1: copy the matching names into allocated memory
+ */
+ for (round = 0; round <= 1; ++round)
+ {
+ for (i = 0; ; ++i)
+ {
+ str = (*func)(xp, i);
+ if (str == NULL) /* end of list */
+ break;
+ if (*str == NUL) /* skip empty strings */
+ continue;
+
+ if (vim_regexec(regmatch, str, (colnr_T)0))
+ {
+ if (round)
+ {
+ if (escaped)
+ str = vim_strsave_escaped(str, (char_u *)" \t\\.");
+ else
+ str = vim_strsave(str);
+ (*file)[count] = str;
+#ifdef FEAT_MENU
+ if (func == get_menu_names && str != NULL)
+ {
+ /* test for separator added by get_menu_names() */
+ str += STRLEN(str) - 1;
+ if (*str == '\001')
+ *str = '.';
+ }
+#endif
+ }
+ ++count;
+ }
+ }
+ if (round == 0)
+ {
+ if (count == 0)
+ return OK;
+ *num_file = count;
+ *file = (char_u **)alloc((unsigned)(count * sizeof(char_u *)));
+ if (*file == NULL)
+ {
+ *file = (char_u **)"";
+ return FAIL;
+ }
+ count = 0;
+ }
+ }
+
+ /* Sort the results. Keep menu's in the specified order. */
+ if (xp->xp_context != EXPAND_MENUNAMES && xp->xp_context != EXPAND_MENUS)
+ {
+ if (xp->xp_context == EXPAND_EXPRESSION
+ || xp->xp_context == EXPAND_FUNCTIONS
+ || xp->xp_context == EXPAND_USER_FUNC)
+ /* <SNR> functions should be sorted to the end. */
+ qsort((void *)*file, (size_t)*num_file, sizeof(char_u *),
+ sort_func_compare);
+ else
+ sort_strings(*file, *num_file);
+ }
+
+#ifdef FEAT_CMDL_COMPL
+ /* Reset the variables used for special highlight names expansion, so that
+ * they don't show up when getting normal highlight names by ID. */
+ reset_expand_highlight();
+#endif
+
+ return OK;
+}
+
+/*
+ * Complete a shell command.
+ * Returns FAIL or OK;
+ */
+ static int
+expand_shellcmd(
+ char_u *filepat, /* pattern to match with command names */
+ int *num_file, /* return: number of matches */
+ char_u ***file, /* return: array with matches */
+ int flagsarg) /* EW_ flags */
+{
+ char_u *pat;
+ int i;
+ char_u *path = NULL;
+ int mustfree = FALSE;
+ garray_T ga;
+ char_u *buf = alloc(MAXPATHL);
+ size_t l;
+ char_u *s, *e;
+ int flags = flagsarg;
+ int ret;
+ int did_curdir = FALSE;
+ hashtab_T found_ht;
+ hashitem_T *hi;
+ hash_T hash;
+
+ if (buf == NULL)
+ return FAIL;
+
+ /* for ":set path=" and ":set tags=" halve backslashes for escaped
+ * space */
+ pat = vim_strsave(filepat);
+ for (i = 0; pat[i]; ++i)
+ if (pat[i] == '\\' && pat[i + 1] == ' ')
+ STRMOVE(pat + i, pat + i + 1);
+
+ flags |= EW_FILE | EW_EXEC | EW_SHELLCMD;
+
+ if (pat[0] == '.' && (vim_ispathsep(pat[1])
+ || (pat[1] == '.' && vim_ispathsep(pat[2]))))
+ path = (char_u *)".";
+ else
+ {
+ /* For an absolute name we don't use $PATH. */
+ if (!mch_isFullName(pat))
+ path = vim_getenv((char_u *)"PATH", &mustfree);
+ if (path == NULL)
+ path = (char_u *)"";
+ }
+
+ /*
+ * Go over all directories in $PATH. Expand matches in that directory and
+ * collect them in "ga". When "." is not in $PATH also expand for the
+ * current directory, to find "subdir/cmd".
+ */
+ ga_init2(&ga, (int)sizeof(char *), 10);
+ hash_init(&found_ht);
+ for (s = path; ; s = e)
+ {
+#if defined(MSWIN)
+ e = vim_strchr(s, ';');
+#else
+ e = vim_strchr(s, ':');
+#endif
+ if (e == NULL)
+ e = s + STRLEN(s);
+
+ if (*s == NUL)
+ {
+ if (did_curdir)
+ break;
+ // Find directories in the current directory, path is empty.
+ did_curdir = TRUE;
+ flags |= EW_DIR;
+ }
+ else if (STRNCMP(s, ".", (int)(e - s)) == 0)
+ {
+ did_curdir = TRUE;
+ flags |= EW_DIR;
+ }
+ else
+ // Do not match directories inside a $PATH item.
+ flags &= ~EW_DIR;
+
+ l = e - s;
+ if (l > MAXPATHL - 5)
+ break;
+ vim_strncpy(buf, s, l);
+ add_pathsep(buf);
+ l = STRLEN(buf);
+ vim_strncpy(buf + l, pat, MAXPATHL - 1 - l);
+
+ /* Expand matches in one directory of $PATH. */
+ ret = expand_wildcards(1, &buf, num_file, file, flags);
+ if (ret == OK)
+ {
+ if (ga_grow(&ga, *num_file) == FAIL)
+ FreeWild(*num_file, *file);
+ else
+ {
+ for (i = 0; i < *num_file; ++i)
+ {
+ char_u *name = (*file)[i];
+
+ if (STRLEN(name) > l)
+ {
+ // Check if this name was already found.
+ hash = hash_hash(name + l);
+ hi = hash_lookup(&found_ht, name + l, hash);
+ if (HASHITEM_EMPTY(hi))
+ {
+ // Remove the path that was prepended.
+ STRMOVE(name, name + l);
+ ((char_u **)ga.ga_data)[ga.ga_len++] = name;
+ hash_add_item(&found_ht, hi, name, hash);
+ name = NULL;
+ }
+ }
+ vim_free(name);
+ }
+ vim_free(*file);
+ }
+ }
+ if (*e != NUL)
+ ++e;
+ }
+ *file = ga.ga_data;
+ *num_file = ga.ga_len;
+
+ vim_free(buf);
+ vim_free(pat);
+ if (mustfree)
+ vim_free(path);
+ hash_clear(&found_ht);
+ return OK;
+}
+
+
+# if defined(FEAT_USR_CMDS) && defined(FEAT_EVAL)
+/*
+ * Call "user_expand_func()" to invoke a user defined Vim script function and
+ * return the result (either a string or a List).
+ */
+ static void *
+call_user_expand_func(
+ void *(*user_expand_func)(char_u *, int, typval_T *),
+ expand_T *xp,
+ int *num_file,
+ char_u ***file)
+{
+ int keep = 0;
+ typval_T args[4];
+ sctx_T save_current_sctx = current_sctx;
+ char_u *pat = NULL;
+ void *ret;
+
+ if (xp->xp_arg == NULL || xp->xp_arg[0] == '\0' || xp->xp_line == NULL)
+ return NULL;
+ *num_file = 0;
+ *file = NULL;
+
+ if (ccline.cmdbuff != NULL)
+ {
+ keep = ccline.cmdbuff[ccline.cmdlen];
+ ccline.cmdbuff[ccline.cmdlen] = 0;
+ }
+
+ pat = vim_strnsave(xp->xp_pattern, xp->xp_pattern_len);
+
+ args[0].v_type = VAR_STRING;
+ args[0].vval.v_string = pat;
+ args[1].v_type = VAR_STRING;
+ args[1].vval.v_string = xp->xp_line;
+ args[2].v_type = VAR_NUMBER;
+ args[2].vval.v_number = xp->xp_col;
+ args[3].v_type = VAR_UNKNOWN;
+
+ current_sctx = xp->xp_script_ctx;
+
+ ret = user_expand_func(xp->xp_arg, 3, args);
+
+ current_sctx = save_current_sctx;
+ if (ccline.cmdbuff != NULL)
+ ccline.cmdbuff[ccline.cmdlen] = keep;
+
+ vim_free(pat);
+ return ret;
+}
+
+/*
+ * Expand names with a function defined by the user.
+ */
+ static int
+ExpandUserDefined(
+ expand_T *xp,
+ regmatch_T *regmatch,
+ int *num_file,
+ char_u ***file)
+{
+ char_u *retstr;
+ char_u *s;
+ char_u *e;
+ int keep;
+ garray_T ga;
+ int skip;
+
+ retstr = call_user_expand_func(call_func_retstr, xp, num_file, file);
+ if (retstr == NULL)
+ return FAIL;
+
+ ga_init2(&ga, (int)sizeof(char *), 3);
+ for (s = retstr; *s != NUL; s = e)
+ {
+ e = vim_strchr(s, '\n');
+ if (e == NULL)
+ e = s + STRLEN(s);
+ keep = *e;
+ *e = NUL;
+
+ skip = xp->xp_pattern[0] && vim_regexec(regmatch, s, (colnr_T)0) == 0;
+ *e = keep;
+
+ if (!skip)
+ {
+ if (ga_grow(&ga, 1) == FAIL)
+ break;
+ ((char_u **)ga.ga_data)[ga.ga_len] = vim_strnsave(s, (int)(e - s));
+ ++ga.ga_len;
+ }
+
+ if (*e != NUL)
+ ++e;
+ }
+ vim_free(retstr);
+ *file = ga.ga_data;
+ *num_file = ga.ga_len;
+ return OK;
+}
+
+/*
+ * Expand names with a list returned by a function defined by the user.
+ */
+ static int
+ExpandUserList(
+ expand_T *xp,
+ int *num_file,
+ char_u ***file)
+{
+ list_T *retlist;
+ listitem_T *li;
+ garray_T ga;
+
+ retlist = call_user_expand_func(call_func_retlist, xp, num_file, file);
+ if (retlist == NULL)
+ return FAIL;
+
+ ga_init2(&ga, (int)sizeof(char *), 3);
+ /* Loop over the items in the list. */
+ for (li = retlist->lv_first; li != NULL; li = li->li_next)
+ {
+ if (li->li_tv.v_type != VAR_STRING || li->li_tv.vval.v_string == NULL)
+ continue; /* Skip non-string items and empty strings */
+
+ if (ga_grow(&ga, 1) == FAIL)
+ break;
+
+ ((char_u **)ga.ga_data)[ga.ga_len] =
+ vim_strsave(li->li_tv.vval.v_string);
+ ++ga.ga_len;
+ }
+ list_unref(retlist);
+
+ *file = ga.ga_data;
+ *num_file = ga.ga_len;
+ return OK;
+}
+#endif
+
+/*
+ * Expand color scheme, compiler or filetype names.
+ * Search from 'runtimepath':
+ * 'runtimepath'/{dirnames}/{pat}.vim
+ * When "flags" has DIP_START: search also from 'start' of 'packpath':
+ * 'packpath'/pack/ * /start/ * /{dirnames}/{pat}.vim
+ * When "flags" has DIP_OPT: search also from 'opt' of 'packpath':
+ * 'packpath'/pack/ * /opt/ * /{dirnames}/{pat}.vim
+ * "dirnames" is an array with one or more directory names.
+ */
+ static int
+ExpandRTDir(
+ char_u *pat,
+ int flags,
+ int *num_file,
+ char_u ***file,
+ char *dirnames[])
+{
+ char_u *s;
+ char_u *e;
+ char_u *match;
+ garray_T ga;
+ int i;
+ int pat_len;
+
+ *num_file = 0;
+ *file = NULL;
+ pat_len = (int)STRLEN(pat);
+ ga_init2(&ga, (int)sizeof(char *), 10);
+
+ for (i = 0; dirnames[i] != NULL; ++i)
+ {
+ s = alloc((unsigned)(STRLEN(dirnames[i]) + pat_len + 7));
+ if (s == NULL)
+ {
+ ga_clear_strings(&ga);
+ return FAIL;
+ }
+ sprintf((char *)s, "%s/%s*.vim", dirnames[i], pat);
+ globpath(p_rtp, s, &ga, 0);
+ vim_free(s);
+ }
+
+ if (flags & DIP_START) {
+ for (i = 0; dirnames[i] != NULL; ++i)
+ {
+ s = alloc((unsigned)(STRLEN(dirnames[i]) + pat_len + 22));
+ if (s == NULL)
+ {
+ ga_clear_strings(&ga);
+ return FAIL;
+ }
+ sprintf((char *)s, "pack/*/start/*/%s/%s*.vim", dirnames[i], pat);
+ globpath(p_pp, s, &ga, 0);
+ vim_free(s);
+ }
+ }
+
+ if (flags & DIP_OPT) {
+ for (i = 0; dirnames[i] != NULL; ++i)
+ {
+ s = alloc((unsigned)(STRLEN(dirnames[i]) + pat_len + 20));
+ if (s == NULL)
+ {
+ ga_clear_strings(&ga);
+ return FAIL;
+ }
+ sprintf((char *)s, "pack/*/opt/*/%s/%s*.vim", dirnames[i], pat);
+ globpath(p_pp, s, &ga, 0);
+ vim_free(s);
+ }
+ }
+
+ for (i = 0; i < ga.ga_len; ++i)
+ {
+ match = ((char_u **)ga.ga_data)[i];
+ s = match;
+ e = s + STRLEN(s);
+ if (e - 4 > s && STRNICMP(e - 4, ".vim", 4) == 0)
+ {
+ e -= 4;
+ for (s = e; s > match; MB_PTR_BACK(match, s))
+ if (s < match || vim_ispathsep(*s))
+ break;
+ ++s;
+ *e = NUL;
+ mch_memmove(match, s, e - s + 1);
+ }
+ }
+
+ if (ga.ga_len == 0)
+ return FAIL;
+
+ /* Sort and remove duplicates which can happen when specifying multiple
+ * directories in dirnames. */
+ remove_duplicates(&ga);
+
+ *file = ga.ga_data;
+ *num_file = ga.ga_len;
+ return OK;
+}
+
+/*
+ * Expand loadplugin names:
+ * 'packpath'/pack/ * /opt/{pat}
+ */
+ static int
+ExpandPackAddDir(
+ char_u *pat,
+ int *num_file,
+ char_u ***file)
+{
+ char_u *s;
+ char_u *e;
+ char_u *match;
+ garray_T ga;
+ int i;
+ int pat_len;
+
+ *num_file = 0;
+ *file = NULL;
+ pat_len = (int)STRLEN(pat);
+ ga_init2(&ga, (int)sizeof(char *), 10);
+
+ s = alloc((unsigned)(pat_len + 26));
+ if (s == NULL)
+ {
+ ga_clear_strings(&ga);
+ return FAIL;
+ }
+ sprintf((char *)s, "pack/*/opt/%s*", pat);
+ globpath(p_pp, s, &ga, 0);
+ vim_free(s);
+
+ for (i = 0; i < ga.ga_len; ++i)
+ {
+ match = ((char_u **)ga.ga_data)[i];
+ s = gettail(match);
+ e = s + STRLEN(s);
+ mch_memmove(match, s, e - s + 1);
+ }
+
+ if (ga.ga_len == 0)
+ return FAIL;
+
+ /* Sort and remove duplicates which can happen when specifying multiple
+ * directories in dirnames. */
+ remove_duplicates(&ga);
+
+ *file = ga.ga_data;
+ *num_file = ga.ga_len;
+ return OK;
+}
+
+#endif
+
+#if defined(FEAT_CMDL_COMPL) || defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * Expand "file" for all comma-separated directories in "path".
+ * Adds the matches to "ga". Caller must init "ga".
+ */
+ void
+globpath(
+ char_u *path,
+ char_u *file,
+ garray_T *ga,
+ int expand_options)
+{
+ expand_T xpc;
+ char_u *buf;
+ int i;
+ int num_p;
+ char_u **p;
+
+ buf = alloc(MAXPATHL);
+ if (buf == NULL)
+ return;
+
+ ExpandInit(&xpc);
+ xpc.xp_context = EXPAND_FILES;
+
+ /* Loop over all entries in {path}. */
+ while (*path != NUL)
+ {
+ /* Copy one item of the path to buf[] and concatenate the file name. */
+ copy_option_part(&path, buf, MAXPATHL, ",");
+ if (STRLEN(buf) + STRLEN(file) + 2 < MAXPATHL)
+ {
+# if defined(MSWIN)
+ /* Using the platform's path separator (\) makes vim incorrectly
+ * treat it as an escape character, use '/' instead. */
+ if (*buf != NUL && !after_pathsep(buf, buf + STRLEN(buf)))
+ STRCAT(buf, "/");
+# else
+ add_pathsep(buf);
+# endif
+ STRCAT(buf, file);
+ if (ExpandFromContext(&xpc, buf, &num_p, &p,
+ WILD_SILENT|expand_options) != FAIL && num_p > 0)
+ {
+ ExpandEscape(&xpc, buf, num_p, p, WILD_SILENT|expand_options);
+
+ if (ga_grow(ga, num_p) == OK)
+ {
+ for (i = 0; i < num_p; ++i)
+ {
+ ((char_u **)ga->ga_data)[ga->ga_len] =
+ vim_strnsave(p[i], (int)STRLEN(p[i]));
+ ++ga->ga_len;
+ }
+ }
+
+ FreeWild(num_p, p);
+ }
+ }
+ }
+
+ vim_free(buf);
+}
+
+#endif
+
+#if defined(FEAT_CMDHIST) || defined(PROTO)
+
+/*********************************
+ * Command line history stuff *
+ *********************************/
+
+/*
+ * Translate a history character to the associated type number.
+ */
+ static int
+hist_char2type(int c)
+{
+ if (c == ':')
+ return HIST_CMD;
+ if (c == '=')
+ return HIST_EXPR;
+ if (c == '@')
+ return HIST_INPUT;
+ if (c == '>')
+ return HIST_DEBUG;
+ return HIST_SEARCH; /* must be '?' or '/' */
+}
+
+/*
+ * Table of history names.
+ * These names are used in :history and various hist...() functions.
+ * It is sufficient to give the significant prefix of a history name.
+ */
+
+static char *(history_names[]) =
+{
+ "cmd",
+ "search",
+ "expr",
+ "input",
+ "debug",
+ NULL
+};
+
+#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
+/*
+ * Function given to ExpandGeneric() to obtain the possible first
+ * arguments of the ":history command.
+ */
+ static char_u *
+get_history_arg(expand_T *xp UNUSED, int idx)
+{
+ static char_u compl[2] = { NUL, NUL };
+ char *short_names = ":=@>?/";
+ int short_names_count = (int)STRLEN(short_names);
+ int history_name_count = sizeof(history_names) / sizeof(char *) - 1;
+
+ if (idx < short_names_count)
+ {
+ compl[0] = (char_u)short_names[idx];
+ return compl;
+ }
+ if (idx < short_names_count + history_name_count)
+ return (char_u *)history_names[idx - short_names_count];
+ if (idx == short_names_count + history_name_count)
+ return (char_u *)"all";
+ return NULL;
+}
+#endif
+
+/*
+ * init_history() - Initialize the command line history.
+ * Also used to re-allocate the history when the size changes.
+ */
+ void
+init_history(void)
+{
+ int newlen; /* new length of history table */
+ histentry_T *temp;
+ int i;
+ int j;
+ int type;
+
+ /*
+ * If size of history table changed, reallocate it
+ */
+ newlen = (int)p_hi;
+ if (newlen != hislen) /* history length changed */
+ {
+ for (type = 0; type < HIST_COUNT; ++type) /* adjust the tables */
+ {
+ if (newlen)
+ {
+ temp = (histentry_T *)lalloc(
+ (long_u)(newlen * sizeof(histentry_T)), TRUE);
+ if (temp == NULL) /* out of memory! */
+ {
+ if (type == 0) /* first one: just keep the old length */
+ {
+ newlen = hislen;
+ break;
+ }
+ /* Already changed one table, now we can only have zero
+ * length for all tables. */
+ newlen = 0;
+ type = -1;
+ continue;
+ }
+ }
+ else
+ temp = NULL;
+ if (newlen == 0 || temp != NULL)
+ {
+ if (hisidx[type] < 0) /* there are no entries yet */
+ {
+ for (i = 0; i < newlen; ++i)
+ clear_hist_entry(&temp[i]);
+ }
+ else if (newlen > hislen) /* array becomes bigger */
+ {
+ for (i = 0; i <= hisidx[type]; ++i)
+ temp[i] = history[type][i];
+ j = i;
+ for ( ; i <= newlen - (hislen - hisidx[type]); ++i)
+ clear_hist_entry(&temp[i]);
+ for ( ; j < hislen; ++i, ++j)
+ temp[i] = history[type][j];
+ }
+ else /* array becomes smaller or 0 */
+ {
+ j = hisidx[type];
+ for (i = newlen - 1; ; --i)
+ {
+ if (i >= 0) /* copy newest entries */
+ temp[i] = history[type][j];
+ else /* remove older entries */
+ vim_free(history[type][j].hisstr);
+ if (--j < 0)
+ j = hislen - 1;
+ if (j == hisidx[type])
+ break;
+ }
+ hisidx[type] = newlen - 1;
+ }
+ vim_free(history[type]);
+ history[type] = temp;
+ }
+ }
+ hislen = newlen;
+ }
+}
+
+ static void
+clear_hist_entry(histentry_T *hisptr)
+{
+ hisptr->hisnum = 0;
+ hisptr->viminfo = FALSE;
+ hisptr->hisstr = NULL;
+ hisptr->time_set = 0;
+}
+
+/*
+ * Check if command line 'str' is already in history.
+ * If 'move_to_front' is TRUE, matching entry is moved to end of history.
+ */
+ static int
+in_history(
+ int type,
+ char_u *str,
+ int move_to_front, /* Move the entry to the front if it exists */
+ int sep,
+ int writing) /* ignore entries read from viminfo */
+{
+ int i;
+ int last_i = -1;
+ char_u *p;
+
+ if (hisidx[type] < 0)
+ return FALSE;
+ i = hisidx[type];
+ do
+ {
+ if (history[type][i].hisstr == NULL)
+ return FALSE;
+
+ /* For search history, check that the separator character matches as
+ * well. */
+ p = history[type][i].hisstr;
+ if (STRCMP(str, p) == 0
+ && !(writing && history[type][i].viminfo)
+ && (type != HIST_SEARCH || sep == p[STRLEN(p) + 1]))
+ {
+ if (!move_to_front)
+ return TRUE;
+ last_i = i;
+ break;
+ }
+ if (--i < 0)
+ i = hislen - 1;
+ } while (i != hisidx[type]);
+
+ if (last_i >= 0)
+ {
+ str = history[type][i].hisstr;
+ while (i != hisidx[type])
+ {
+ if (++i >= hislen)
+ i = 0;
+ history[type][last_i] = history[type][i];
+ last_i = i;
+ }
+ history[type][i].hisnum = ++hisnum[type];
+ history[type][i].viminfo = FALSE;
+ history[type][i].hisstr = str;
+ history[type][i].time_set = vim_time();
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * Convert history name (from table above) to its HIST_ equivalent.
+ * When "name" is empty, return "cmd" history.
+ * Returns -1 for unknown history name.
+ */
+ int
+get_histtype(char_u *name)
+{
+ int i;
+ int len = (int)STRLEN(name);
+
+ /* No argument: use current history. */
+ if (len == 0)
+ return hist_char2type(ccline.cmdfirstc);
+
+ for (i = 0; history_names[i] != NULL; ++i)
+ if (STRNICMP(name, history_names[i], len) == 0)
+ return i;
+
+ if (vim_strchr((char_u *)":=@>?/", name[0]) != NULL && name[1] == NUL)
+ return hist_char2type(name[0]);
+
+ return -1;
+}
+
+static int last_maptick = -1; /* last seen maptick */
+
+/*
+ * Add the given string to the given history. If the string is already in the
+ * history then it is moved to the front. "histype" may be one of he HIST_
+ * values.
+ */
+ void
+add_to_history(
+ int histype,
+ char_u *new_entry,
+ int in_map, /* consider maptick when inside a mapping */
+ int sep) /* separator character used (search hist) */
+{
+ histentry_T *hisptr;
+ int len;
+
+ if (hislen == 0) /* no history */
+ return;
+
+ if (cmdmod.keeppatterns && histype == HIST_SEARCH)
+ return;
+
+ /*
+ * Searches inside the same mapping overwrite each other, so that only
+ * the last line is kept. Be careful not to remove a line that was moved
+ * down, only lines that were added.
+ */
+ if (histype == HIST_SEARCH && in_map)
+ {
+ if (maptick == last_maptick && hisidx[HIST_SEARCH] >= 0)
+ {
+ /* Current line is from the same mapping, remove it */
+ hisptr = &history[HIST_SEARCH][hisidx[HIST_SEARCH]];
+ vim_free(hisptr->hisstr);
+ clear_hist_entry(hisptr);
+ --hisnum[histype];
+ if (--hisidx[HIST_SEARCH] < 0)
+ hisidx[HIST_SEARCH] = hislen - 1;
+ }
+ last_maptick = -1;
+ }
+ if (!in_history(histype, new_entry, TRUE, sep, FALSE))
+ {
+ if (++hisidx[histype] == hislen)
+ hisidx[histype] = 0;
+ hisptr = &history[histype][hisidx[histype]];
+ vim_free(hisptr->hisstr);
+
+ /* Store the separator after the NUL of the string. */
+ len = (int)STRLEN(new_entry);
+ hisptr->hisstr = vim_strnsave(new_entry, len + 2);
+ if (hisptr->hisstr != NULL)
+ hisptr->hisstr[len + 1] = sep;
+
+ hisptr->hisnum = ++hisnum[histype];
+ hisptr->viminfo = FALSE;
+ hisptr->time_set = vim_time();
+ if (histype == HIST_SEARCH && in_map)
+ last_maptick = maptick;
+ }
+}
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+
+/*
+ * Get identifier of newest history entry.
+ * "histype" may be one of the HIST_ values.
+ */
+ int
+get_history_idx(int histype)
+{
+ if (hislen == 0 || histype < 0 || histype >= HIST_COUNT
+ || hisidx[histype] < 0)
+ return -1;
+
+ return history[histype][hisidx[histype]].hisnum;
+}
+
+/*
+ * Calculate history index from a number:
+ * num > 0: seen as identifying number of a history entry
+ * num < 0: relative position in history wrt newest entry
+ * "histype" may be one of the HIST_ values.
+ */
+ static int
+calc_hist_idx(int histype, int num)
+{
+ int i;
+ histentry_T *hist;
+ int wrapped = FALSE;
+
+ if (hislen == 0 || histype < 0 || histype >= HIST_COUNT
+ || (i = hisidx[histype]) < 0 || num == 0)
+ return -1;
+
+ hist = history[histype];
+ if (num > 0)
+ {
+ while (hist[i].hisnum > num)
+ if (--i < 0)
+ {
+ if (wrapped)
+ break;
+ i += hislen;
+ wrapped = TRUE;
+ }
+ if (hist[i].hisnum == num && hist[i].hisstr != NULL)
+ return i;
+ }
+ else if (-num <= hislen)
+ {
+ i += num + 1;
+ if (i < 0)
+ i += hislen;
+ if (hist[i].hisstr != NULL)
+ return i;
+ }
+ return -1;
+}
+
+/*
+ * Get a history entry by its index.
+ * "histype" may be one of the HIST_ values.
+ */
+ char_u *
+get_history_entry(int histype, int idx)
+{
+ idx = calc_hist_idx(histype, idx);
+ if (idx >= 0)
+ return history[histype][idx].hisstr;
+ else
+ return (char_u *)"";
+}
+
+/*
+ * Clear all entries of a history.
+ * "histype" may be one of the HIST_ values.
+ */
+ int
+clr_history(int histype)
+{
+ int i;
+ histentry_T *hisptr;
+
+ if (hislen != 0 && histype >= 0 && histype < HIST_COUNT)
+ {
+ hisptr = history[histype];
+ for (i = hislen; i--;)
+ {
+ vim_free(hisptr->hisstr);
+ clear_hist_entry(hisptr);
+ hisptr++;
+ }
+ hisidx[histype] = -1; /* mark history as cleared */
+ hisnum[histype] = 0; /* reset identifier counter */
+ return OK;
+ }
+ return FAIL;
+}
+
+/*
+ * Remove all entries matching {str} from a history.
+ * "histype" may be one of the HIST_ values.
+ */
+ int
+del_history_entry(int histype, char_u *str)
+{
+ regmatch_T regmatch;
+ histentry_T *hisptr;
+ int idx;
+ int i;
+ int last;
+ int found = FALSE;
+
+ regmatch.regprog = NULL;
+ regmatch.rm_ic = FALSE; /* always match case */
+ if (hislen != 0
+ && histype >= 0
+ && histype < HIST_COUNT
+ && *str != NUL
+ && (idx = hisidx[histype]) >= 0
+ && (regmatch.regprog = vim_regcomp(str, RE_MAGIC + RE_STRING))
+ != NULL)
+ {
+ i = last = idx;
+ do
+ {
+ hisptr = &history[histype][i];
+ if (hisptr->hisstr == NULL)
+ break;
+ if (vim_regexec(&regmatch, hisptr->hisstr, (colnr_T)0))
+ {
+ found = TRUE;
+ vim_free(hisptr->hisstr);
+ clear_hist_entry(hisptr);
+ }
+ else
+ {
+ if (i != last)
+ {
+ history[histype][last] = *hisptr;
+ clear_hist_entry(hisptr);
+ }
+ if (--last < 0)
+ last += hislen;
+ }
+ if (--i < 0)
+ i += hislen;
+ } while (i != idx);
+ if (history[histype][idx].hisstr == NULL)
+ hisidx[histype] = -1;
+ }
+ vim_regfree(regmatch.regprog);
+ return found;
+}
+
+/*
+ * Remove an indexed entry from a history.
+ * "histype" may be one of the HIST_ values.
+ */
+ int
+del_history_idx(int histype, int idx)
+{
+ int i, j;
+
+ i = calc_hist_idx(histype, idx);
+ if (i < 0)
+ return FALSE;
+ idx = hisidx[histype];
+ vim_free(history[histype][i].hisstr);
+
+ /* When deleting the last added search string in a mapping, reset
+ * last_maptick, so that the last added search string isn't deleted again.
+ */
+ if (histype == HIST_SEARCH && maptick == last_maptick && i == idx)
+ last_maptick = -1;
+
+ while (i != idx)
+ {
+ j = (i + 1) % hislen;
+ history[histype][i] = history[histype][j];
+ i = j;
+ }
+ clear_hist_entry(&history[histype][i]);
+ if (--i < 0)
+ i += hislen;
+ hisidx[histype] = i;
+ return TRUE;
+}
+
+#endif /* FEAT_EVAL */
+
+#if defined(FEAT_CRYPT) || defined(PROTO)
+/*
+ * Very specific function to remove the value in ":set key=val" from the
+ * history.
+ */
+ void
+remove_key_from_history(void)
+{
+ char_u *p;
+ int i;
+
+ i = hisidx[HIST_CMD];
+ if (i < 0)
+ return;
+ p = history[HIST_CMD][i].hisstr;
+ if (p != NULL)
+ for ( ; *p; ++p)
+ if (STRNCMP(p, "key", 3) == 0 && !isalpha(p[3]))
+ {
+ p = vim_strchr(p + 3, '=');
+ if (p == NULL)
+ break;
+ ++p;
+ for (i = 0; p[i] && !VIM_ISWHITE(p[i]); ++i)
+ if (p[i] == '\\' && p[i + 1])
+ ++i;
+ STRMOVE(p, p + i);
+ --p;
+ }
+}
+#endif
+
+#endif /* FEAT_CMDHIST */
+
+#if defined(FEAT_EVAL) || defined(FEAT_CMDWIN) || defined(PROTO)
+/*
+ * Get pointer to the command line info to use. save_ccline() may clear
+ * ccline and put the previous value in prev_ccline.
+ */
+ static struct cmdline_info *
+get_ccline_ptr(void)
+{
+ if ((State & CMDLINE) == 0)
+ return NULL;
+ if (ccline.cmdbuff != NULL)
+ return &ccline;
+ if (prev_ccline_used && prev_ccline.cmdbuff != NULL)
+ return &prev_ccline;
+ return NULL;
+}
+#endif
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * Get the current command line in allocated memory.
+ * Only works when the command line is being edited.
+ * Returns NULL when something is wrong.
+ */
+ char_u *
+get_cmdline_str(void)
+{
+ struct cmdline_info *p;
+
+ if (cmdline_star > 0)
+ return NULL;
+ p = get_ccline_ptr();
+ if (p == NULL)
+ return NULL;
+ return vim_strnsave(p->cmdbuff, p->cmdlen);
+}
+
+/*
+ * Get the current command line position, counted in bytes.
+ * Zero is the first position.
+ * Only works when the command line is being edited.
+ * Returns -1 when something is wrong.
+ */
+ int
+get_cmdline_pos(void)
+{
+ struct cmdline_info *p = get_ccline_ptr();
+
+ if (p == NULL)
+ return -1;
+ return p->cmdpos;
+}
+
+/*
+ * Set the command line byte position to "pos". Zero is the first position.
+ * Only works when the command line is being edited.
+ * Returns 1 when failed, 0 when OK.
+ */
+ int
+set_cmdline_pos(
+ int pos)
+{
+ struct cmdline_info *p = get_ccline_ptr();
+
+ if (p == NULL)
+ return 1;
+
+ /* The position is not set directly but after CTRL-\ e or CTRL-R = has
+ * changed the command line. */
+ if (pos < 0)
+ new_cmdpos = 0;
+ else
+ new_cmdpos = pos;
+ return 0;
+}
+#endif
+
+#if defined(FEAT_EVAL) || defined(FEAT_CMDWIN) || defined(PROTO)
+/*
+ * Get the current command-line type.
+ * Returns ':' or '/' or '?' or '@' or '>' or '-'
+ * Only works when the command line is being edited.
+ * Returns NUL when something is wrong.
+ */
+ int
+get_cmdline_type(void)
+{
+ struct cmdline_info *p = get_ccline_ptr();
+
+ if (p == NULL)
+ return NUL;
+ if (p->cmdfirstc == NUL)
+ return
+# ifdef FEAT_EVAL
+ (p->input_fn) ? '@' :
+# endif
+ '-';
+ return p->cmdfirstc;
+}
+#endif
+
+#if defined(FEAT_QUICKFIX) || defined(FEAT_CMDHIST) || defined(PROTO)
+/*
+ * Get indices "num1,num2" that specify a range within a list (not a range of
+ * text lines in a buffer!) from a string. Used for ":history" and ":clist".
+ * Returns OK if parsed successfully, otherwise FAIL.
+ */
+ int
+get_list_range(char_u **str, int *num1, int *num2)
+{
+ int len;
+ int first = FALSE;
+ varnumber_T num;
+
+ *str = skipwhite(*str);
+ if (**str == '-' || vim_isdigit(**str)) /* parse "from" part of range */
+ {
+ vim_str2nr(*str, NULL, &len, 0, &num, NULL, 0);
+ *str += len;
+ *num1 = (int)num;
+ first = TRUE;
+ }
+ *str = skipwhite(*str);
+ if (**str == ',') /* parse "to" part of range */
+ {
+ *str = skipwhite(*str + 1);
+ vim_str2nr(*str, NULL, &len, 0, &num, NULL, 0);
+ if (len > 0)
+ {
+ *num2 = (int)num;
+ *str = skipwhite(*str + len);
+ }
+ else if (!first) /* no number given at all */
+ return FAIL;
+ }
+ else if (first) /* only one number given */
+ *num2 = *num1;
+ return OK;
+}
+#endif
+
+#if defined(FEAT_CMDHIST) || defined(PROTO)
+/*
+ * :history command - print a history
+ */
+ void
+ex_history(exarg_T *eap)
+{
+ histentry_T *hist;
+ int histype1 = HIST_CMD;
+ int histype2 = HIST_CMD;
+ int hisidx1 = 1;
+ int hisidx2 = -1;
+ int idx;
+ int i, j, k;
+ char_u *end;
+ char_u *arg = eap->arg;
+
+ if (hislen == 0)
+ {
+ msg(_("'history' option is zero"));
+ return;
+ }
+
+ if (!(VIM_ISDIGIT(*arg) || *arg == '-' || *arg == ','))
+ {
+ end = arg;
+ while (ASCII_ISALPHA(*end)
+ || vim_strchr((char_u *)":=@>/?", *end) != NULL)
+ end++;
+ i = *end;
+ *end = NUL;
+ histype1 = get_histtype(arg);
+ if (histype1 == -1)
+ {
+ if (STRNICMP(arg, "all", STRLEN(arg)) == 0)
+ {
+ histype1 = 0;
+ histype2 = HIST_COUNT-1;
+ }
+ else
+ {
+ *end = i;
+ emsg(_(e_trailing));
+ return;
+ }
+ }
+ else
+ histype2 = histype1;
+ *end = i;
+ }
+ else
+ end = arg;
+ if (!get_list_range(&end, &hisidx1, &hisidx2) || *end != NUL)
+ {
+ emsg(_(e_trailing));
+ return;
+ }
+
+ for (; !got_int && histype1 <= histype2; ++histype1)
+ {
+ STRCPY(IObuff, "\n # ");
+ STRCAT(STRCAT(IObuff, history_names[histype1]), " history");
+ msg_puts_title((char *)IObuff);
+ idx = hisidx[histype1];
+ hist = history[histype1];
+ j = hisidx1;
+ k = hisidx2;
+ if (j < 0)
+ j = (-j > hislen) ? 0 : hist[(hislen+j+idx+1) % hislen].hisnum;
+ if (k < 0)
+ k = (-k > hislen) ? 0 : hist[(hislen+k+idx+1) % hislen].hisnum;
+ if (idx >= 0 && j <= k)
+ for (i = idx + 1; !got_int; ++i)
+ {
+ if (i == hislen)
+ i = 0;
+ if (hist[i].hisstr != NULL
+ && hist[i].hisnum >= j && hist[i].hisnum <= k)
+ {
+ msg_putchar('\n');
+ sprintf((char *)IObuff, "%c%6d ", i == idx ? '>' : ' ',
+ hist[i].hisnum);
+ if (vim_strsize(hist[i].hisstr) > (int)Columns - 10)
+ trunc_string(hist[i].hisstr, IObuff + STRLEN(IObuff),
+ (int)Columns - 10, IOSIZE - (int)STRLEN(IObuff));
+ else
+ STRCAT(IObuff, hist[i].hisstr);
+ msg_outtrans(IObuff);
+ out_flush();
+ }
+ if (i == idx)
+ break;
+ }
+ }
+}
+#endif
+
+#if (defined(FEAT_VIMINFO) && defined(FEAT_CMDHIST)) || defined(PROTO)
+/*
+ * Buffers for history read from a viminfo file. Only valid while reading.
+ */
+static histentry_T *viminfo_history[HIST_COUNT] =
+ {NULL, NULL, NULL, NULL, NULL};
+static int viminfo_hisidx[HIST_COUNT] = {0, 0, 0, 0, 0};
+static int viminfo_hislen[HIST_COUNT] = {0, 0, 0, 0, 0};
+static int viminfo_add_at_front = FALSE;
+
+/*
+ * Translate a history type number to the associated character.
+ */
+ static int
+hist_type2char(
+ int type,
+ int use_question) /* use '?' instead of '/' */
+{
+ if (type == HIST_CMD)
+ return ':';
+ if (type == HIST_SEARCH)
+ {
+ if (use_question)
+ return '?';
+ else
+ return '/';
+ }
+ if (type == HIST_EXPR)
+ return '=';
+ return '@';
+}
+
+/*
+ * Prepare for reading the history from the viminfo file.
+ * This allocates history arrays to store the read history lines.
+ */
+ void
+prepare_viminfo_history(int asklen, int writing)
+{
+ int i;
+ int num;
+ int type;
+ int len;
+
+ init_history();
+ viminfo_add_at_front = (asklen != 0 && !writing);
+ if (asklen > hislen)
+ asklen = hislen;
+
+ for (type = 0; type < HIST_COUNT; ++type)
+ {
+ /* Count the number of empty spaces in the history list. Entries read
+ * from viminfo previously are also considered empty. If there are
+ * more spaces available than we request, then fill them up. */
+ for (i = 0, num = 0; i < hislen; i++)
+ if (history[type][i].hisstr == NULL || history[type][i].viminfo)
+ num++;
+ len = asklen;
+ if (num > len)
+ len = num;
+ if (len <= 0)
+ viminfo_history[type] = NULL;
+ else
+ viminfo_history[type] = (histentry_T *)lalloc(
+ (long_u)(len * sizeof(histentry_T)), FALSE);
+ if (viminfo_history[type] == NULL)
+ len = 0;
+ viminfo_hislen[type] = len;
+ viminfo_hisidx[type] = 0;
+ }
+}
+
+/*
+ * Accept a line from the viminfo, store it in the history array when it's
+ * new.
+ */
+ int
+read_viminfo_history(vir_T *virp, int writing)
+{
+ int type;
+ long_u len;
+ char_u *val;
+ char_u *p;
+
+ type = hist_char2type(virp->vir_line[0]);
+ if (viminfo_hisidx[type] < viminfo_hislen[type])
+ {
+ val = viminfo_readstring(virp, 1, TRUE);
+ if (val != NULL && *val != NUL)
+ {
+ int sep = (*val == ' ' ? NUL : *val);
+
+ if (!in_history(type, val + (type == HIST_SEARCH),
+ viminfo_add_at_front, sep, writing))
+ {
+ /* Need to re-allocate to append the separator byte. */
+ len = STRLEN(val);
+ p = lalloc(len + 2, TRUE);
+ if (p != NULL)
+ {
+ if (type == HIST_SEARCH)
+ {
+ /* Search entry: Move the separator from the first
+ * column to after the NUL. */
+ mch_memmove(p, val + 1, (size_t)len);
+ p[len] = sep;
+ }
+ else
+ {
+ /* Not a search entry: No separator in the viminfo
+ * file, add a NUL separator. */
+ mch_memmove(p, val, (size_t)len + 1);
+ p[len + 1] = NUL;
+ }
+ viminfo_history[type][viminfo_hisidx[type]].hisstr = p;
+ viminfo_history[type][viminfo_hisidx[type]].time_set = 0;
+ viminfo_history[type][viminfo_hisidx[type]].viminfo = TRUE;
+ viminfo_history[type][viminfo_hisidx[type]].hisnum = 0;
+ viminfo_hisidx[type]++;
+ }
+ }
+ }
+ vim_free(val);
+ }
+ return viminfo_readline(virp);
+}
+
+/*
+ * Accept a new style history line from the viminfo, store it in the history
+ * array when it's new.
+ */
+ void
+handle_viminfo_history(
+ garray_T *values,
+ int writing)
+{
+ int type;
+ long_u len;
+ char_u *val;
+ char_u *p;
+ bval_T *vp = (bval_T *)values->ga_data;
+
+ /* Check the format:
+ * |{bartype},{histtype},{timestamp},{separator},"text" */
+ if (values->ga_len < 4
+ || vp[0].bv_type != BVAL_NR
+ || vp[1].bv_type != BVAL_NR
+ || (vp[2].bv_type != BVAL_NR && vp[2].bv_type != BVAL_EMPTY)
+ || vp[3].bv_type != BVAL_STRING)
+ return;
+
+ type = vp[0].bv_nr;
+ if (type >= HIST_COUNT)
+ return;
+ if (viminfo_hisidx[type] < viminfo_hislen[type])
+ {
+ val = vp[3].bv_string;
+ if (val != NULL && *val != NUL)
+ {
+ int sep = type == HIST_SEARCH && vp[2].bv_type == BVAL_NR
+ ? vp[2].bv_nr : NUL;
+ int idx;
+ int overwrite = FALSE;
+
+ if (!in_history(type, val, viminfo_add_at_front, sep, writing))
+ {
+ /* If lines were written by an older Vim we need to avoid
+ * getting duplicates. See if the entry already exists. */
+ for (idx = 0; idx < viminfo_hisidx[type]; ++idx)
+ {
+ p = viminfo_history[type][idx].hisstr;
+ if (STRCMP(val, p) == 0
+ && (type != HIST_SEARCH || sep == p[STRLEN(p) + 1]))
+ {
+ overwrite = TRUE;
+ break;
+ }
+ }
+
+ if (!overwrite)
+ {
+ /* Need to re-allocate to append the separator byte. */
+ len = vp[3].bv_len;
+ p = lalloc(len + 2, TRUE);
+ }
+ else
+ len = 0; /* for picky compilers */
+ if (p != NULL)
+ {
+ viminfo_history[type][idx].time_set = vp[1].bv_nr;
+ if (!overwrite)
+ {
+ mch_memmove(p, val, (size_t)len + 1);
+ /* Put the separator after the NUL. */
+ p[len + 1] = sep;
+ viminfo_history[type][idx].hisstr = p;
+ viminfo_history[type][idx].hisnum = 0;
+ viminfo_history[type][idx].viminfo = TRUE;
+ viminfo_hisidx[type]++;
+ }
+ }
+ }
+ }
+ }
+}
+
+/*
+ * Concatenate history lines from viminfo after the lines typed in this Vim.
+ */
+ static void
+concat_history(int type)
+{
+ int idx;
+ int i;
+
+ idx = hisidx[type] + viminfo_hisidx[type];
+ if (idx >= hislen)
+ idx -= hislen;
+ else if (idx < 0)
+ idx = hislen - 1;
+ if (viminfo_add_at_front)
+ hisidx[type] = idx;
+ else
+ {
+ if (hisidx[type] == -1)
+ hisidx[type] = hislen - 1;
+ do
+ {
+ if (history[type][idx].hisstr != NULL
+ || history[type][idx].viminfo)
+ break;
+ if (++idx == hislen)
+ idx = 0;
+ } while (idx != hisidx[type]);
+ if (idx != hisidx[type] && --idx < 0)
+ idx = hislen - 1;
+ }
+ for (i = 0; i < viminfo_hisidx[type]; i++)
+ {
+ vim_free(history[type][idx].hisstr);
+ history[type][idx].hisstr = viminfo_history[type][i].hisstr;
+ history[type][idx].viminfo = TRUE;
+ history[type][idx].time_set = viminfo_history[type][i].time_set;
+ if (--idx < 0)
+ idx = hislen - 1;
+ }
+ idx += 1;
+ idx %= hislen;
+ for (i = 0; i < viminfo_hisidx[type]; i++)
+ {
+ history[type][idx++].hisnum = ++hisnum[type];
+ idx %= hislen;
+ }
+}
+
+#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
+ static int
+#ifdef __BORLANDC__
+_RTLENTRYF
+#endif
+sort_hist(const void *s1, const void *s2)
+{
+ histentry_T *p1 = *(histentry_T **)s1;
+ histentry_T *p2 = *(histentry_T **)s2;
+
+ if (p1->time_set < p2->time_set) return -1;
+ if (p1->time_set > p2->time_set) return 1;
+ return 0;
+}
+#endif
+
+/*
+ * Merge history lines from viminfo and lines typed in this Vim based on the
+ * timestamp;
+ */
+ static void
+merge_history(int type)
+{
+ int max_len;
+ histentry_T **tot_hist;
+ histentry_T *new_hist;
+ int i;
+ int len;
+
+ /* Make one long list with all entries. */
+ max_len = hislen + viminfo_hisidx[type];
+ tot_hist = (histentry_T **)alloc(max_len * (int)sizeof(histentry_T *));
+ new_hist = (histentry_T *)alloc(hislen * (int)sizeof(histentry_T));
+ if (tot_hist == NULL || new_hist == NULL)
+ {
+ vim_free(tot_hist);
+ vim_free(new_hist);
+ return;
+ }
+ for (i = 0; i < viminfo_hisidx[type]; i++)
+ tot_hist[i] = &viminfo_history[type][i];
+ len = i;
+ for (i = 0; i < hislen; i++)
+ if (history[type][i].hisstr != NULL)
+ tot_hist[len++] = &history[type][i];
+
+ /* Sort the list on timestamp. */
+ qsort((void *)tot_hist, (size_t)len, sizeof(histentry_T *), sort_hist);
+
+ /* Keep the newest ones. */
+ for (i = 0; i < hislen; i++)
+ {
+ if (i < len)
+ {
+ new_hist[i] = *tot_hist[i];
+ tot_hist[i]->hisstr = NULL;
+ if (new_hist[i].hisnum == 0)
+ new_hist[i].hisnum = ++hisnum[type];
+ }
+ else
+ clear_hist_entry(&new_hist[i]);
+ }
+ hisidx[type] = (i < len ? i : len) - 1;
+
+ /* Free what is not kept. */
+ for (i = 0; i < viminfo_hisidx[type]; i++)
+ vim_free(viminfo_history[type][i].hisstr);
+ for (i = 0; i < hislen; i++)
+ vim_free(history[type][i].hisstr);
+ vim_free(history[type]);
+ history[type] = new_hist;
+ vim_free(tot_hist);
+}
+
+/*
+ * Finish reading history lines from viminfo. Not used when writing viminfo.
+ */
+ void
+finish_viminfo_history(vir_T *virp)
+{
+ int type;
+ int merge = virp->vir_version >= VIMINFO_VERSION_WITH_HISTORY;
+
+ for (type = 0; type < HIST_COUNT; ++type)
+ {
+ if (history[type] == NULL)
+ continue;
+
+ if (merge)
+ merge_history(type);
+ else
+ concat_history(type);
+
+ VIM_CLEAR(viminfo_history[type]);
+ viminfo_hisidx[type] = 0;
+ }
+}
+
+/*
+ * Write history to viminfo file in "fp".
+ * When "merge" is TRUE merge history lines with a previously read viminfo
+ * file, data is in viminfo_history[].
+ * When "merge" is FALSE just write all history lines. Used for ":wviminfo!".
+ */
+ void
+write_viminfo_history(FILE *fp, int merge)
+{
+ int i;
+ int type;
+ int num_saved;
+ int round;
+
+ init_history();
+ if (hislen == 0)
+ return;
+ for (type = 0; type < HIST_COUNT; ++type)
+ {
+ num_saved = get_viminfo_parameter(hist_type2char(type, FALSE));
+ if (num_saved == 0)
+ continue;
+ if (num_saved < 0) /* Use default */
+ num_saved = hislen;
+ fprintf(fp, _("\n# %s History (newest to oldest):\n"),
+ type == HIST_CMD ? _("Command Line") :
+ type == HIST_SEARCH ? _("Search String") :
+ type == HIST_EXPR ? _("Expression") :
+ type == HIST_INPUT ? _("Input Line") :
+ _("Debug Line"));
+ if (num_saved > hislen)
+ num_saved = hislen;
+
+ /*
+ * Merge typed and viminfo history:
+ * round 1: history of typed commands.
+ * round 2: history from recently read viminfo.
+ */
+ for (round = 1; round <= 2; ++round)
+ {
+ if (round == 1)
+ /* start at newest entry, somewhere in the list */
+ i = hisidx[type];
+ else if (viminfo_hisidx[type] > 0)
+ /* start at newest entry, first in the list */
+ i = 0;
+ else
+ /* empty list */
+ i = -1;
+ if (i >= 0)
+ while (num_saved > 0
+ && !(round == 2 && i >= viminfo_hisidx[type]))
+ {
+ char_u *p;
+ time_t timestamp;
+ int c = NUL;
+
+ if (round == 1)
+ {
+ p = history[type][i].hisstr;
+ timestamp = history[type][i].time_set;
+ }
+ else
+ {
+ p = viminfo_history[type] == NULL ? NULL
+ : viminfo_history[type][i].hisstr;
+ timestamp = viminfo_history[type] == NULL ? 0
+ : viminfo_history[type][i].time_set;
+ }
+
+ if (p != NULL && (round == 2
+ || !merge
+ || !history[type][i].viminfo))
+ {
+ --num_saved;
+ fputc(hist_type2char(type, TRUE), fp);
+ /* For the search history: put the separator in the
+ * second column; use a space if there isn't one. */
+ if (type == HIST_SEARCH)
+ {
+ c = p[STRLEN(p) + 1];
+ putc(c == NUL ? ' ' : c, fp);
+ }
+ viminfo_writestring(fp, p);
+
+ {
+ char cbuf[NUMBUFLEN];
+
+ /* New style history with a bar line. Format:
+ * |{bartype},{histtype},{timestamp},{separator},"text" */
+ if (c == NUL)
+ cbuf[0] = NUL;
+ else
+ sprintf(cbuf, "%d", c);
+ fprintf(fp, "|%d,%d,%ld,%s,", BARTYPE_HISTORY,
+ type, (long)timestamp, cbuf);
+ barline_writestring(fp, p, LSIZE - 20);
+ putc('\n', fp);
+ }
+ }
+ if (round == 1)
+ {
+ /* Decrement index, loop around and stop when back at
+ * the start. */
+ if (--i < 0)
+ i = hislen - 1;
+ if (i == hisidx[type])
+ break;
+ }
+ else
+ {
+ /* Increment index. Stop at the end in the while. */
+ ++i;
+ }
+ }
+ }
+ for (i = 0; i < viminfo_hisidx[type]; ++i)
+ if (viminfo_history[type] != NULL)
+ vim_free(viminfo_history[type][i].hisstr);
+ VIM_CLEAR(viminfo_history[type]);
+ viminfo_hisidx[type] = 0;
+ }
+}
+#endif /* FEAT_VIMINFO */
+
+#if defined(FEAT_FKMAP) || defined(PROTO)
+/*
+ * Write a character at the current cursor+offset position.
+ * It is directly written into the command buffer block.
+ */
+ void
+cmd_pchar(int c, int offset)
+{
+ if (ccline.cmdpos + offset >= ccline.cmdlen || ccline.cmdpos + offset < 0)
+ {
+ emsg(_("E198: cmd_pchar beyond the command length"));
+ return;
+ }
+ ccline.cmdbuff[ccline.cmdpos + offset] = (char_u)c;
+ ccline.cmdbuff[ccline.cmdlen] = NUL;
+}
+
+ int
+cmd_gchar(int offset)
+{
+ if (ccline.cmdpos + offset >= ccline.cmdlen || ccline.cmdpos + offset < 0)
+ {
+ // emsg(_("cmd_gchar beyond the command length"));
+ return NUL;
+ }
+ return (int)ccline.cmdbuff[ccline.cmdpos + offset];
+}
+#endif
+
+#if defined(FEAT_CMDWIN) || defined(PROTO)
+/*
+ * Open a window on the current command line and history. Allow editing in
+ * the window. Returns when the window is closed.
+ * Returns:
+ * CR if the command is to be executed
+ * Ctrl_C if it is to be abandoned
+ * K_IGNORE if editing continues
+ */
+ static int
+open_cmdwin(void)
+{
+ bufref_T old_curbuf;
+ win_T *old_curwin = curwin;
+ bufref_T bufref;
+ win_T *wp;
+ int i;
+ linenr_T lnum;
+ int histtype;
+ garray_T winsizes;
+ int save_restart_edit = restart_edit;
+ int save_State = State;
+ int save_exmode = exmode_active;
+#ifdef FEAT_RIGHTLEFT
+ int save_cmdmsg_rl = cmdmsg_rl;
+#endif
+#ifdef FEAT_FOLDING
+ int save_KeyTyped;
+#endif
+
+ /* Can't do this recursively. Can't do it when typing a password. */
+ if (cmdwin_type != 0
+# if defined(FEAT_CRYPT) || defined(FEAT_EVAL)
+ || cmdline_star > 0
+# endif
+ )
+ {
+ beep_flush();
+ return K_IGNORE;
+ }
+ set_bufref(&old_curbuf, curbuf);
+
+ /* Save current window sizes. */
+ win_size_save(&winsizes);
+
+ /* Don't execute autocommands while creating the window. */
+ block_autocmds();
+
+#if defined(FEAT_INS_EXPAND)
+ // When using completion in Insert mode with <C-R>=<C-F> one can open the
+ // command line window, but we don't want the popup menu then.
+ pum_undisplay();
+#endif
+
+ /* don't use a new tab page */
+ cmdmod.tab = 0;
+ cmdmod.noswapfile = 1;
+
+ /* Create a window for the command-line buffer. */
+ if (win_split((int)p_cwh, WSP_BOT) == FAIL)
+ {
+ beep_flush();
+ unblock_autocmds();
+ return K_IGNORE;
+ }
+ cmdwin_type = get_cmdline_type();
+
+ /* Create the command-line buffer empty. */
+ (void)do_ecmd(0, NULL, NULL, NULL, ECMD_ONE, ECMD_HIDE, NULL);
+ (void)setfname(curbuf, (char_u *)"[Command Line]", NULL, TRUE);
+ set_option_value((char_u *)"bt", 0L, (char_u *)"nofile", OPT_LOCAL);
+ curbuf->b_p_ma = TRUE;
+#ifdef FEAT_FOLDING
+ curwin->w_p_fen = FALSE;
+#endif
+# ifdef FEAT_RIGHTLEFT
+ curwin->w_p_rl = cmdmsg_rl;
+ cmdmsg_rl = FALSE;
+# endif
+ RESET_BINDING(curwin);
+
+ /* Do execute autocommands for setting the filetype (load syntax). */
+ unblock_autocmds();
+ /* But don't allow switching to another buffer. */
+ ++curbuf_lock;
+
+ /* Showing the prompt may have set need_wait_return, reset it. */
+ need_wait_return = FALSE;
+
+ histtype = hist_char2type(cmdwin_type);
+ if (histtype == HIST_CMD || histtype == HIST_DEBUG)
+ {
+ if (p_wc == TAB)
+ {
+ add_map((char_u *)"<buffer> <Tab> <C-X><C-V>", INSERT);
+ add_map((char_u *)"<buffer> <Tab> a<C-X><C-V>", NORMAL);
+ }
+ set_option_value((char_u *)"ft", 0L, (char_u *)"vim", OPT_LOCAL);
+ }
+ --curbuf_lock;
+
+ /* Reset 'textwidth' after setting 'filetype' (the Vim filetype plugin
+ * sets 'textwidth' to 78). */
+ curbuf->b_p_tw = 0;
+
+ /* Fill the buffer with the history. */
+ init_history();
+ if (hislen > 0)
+ {
+ i = hisidx[histtype];
+ if (i >= 0)
+ {
+ lnum = 0;
+ do
+ {
+ if (++i == hislen)
+ i = 0;
+ if (history[histtype][i].hisstr != NULL)
+ ml_append(lnum++, history[histtype][i].hisstr,
+ (colnr_T)0, FALSE);
+ }
+ while (i != hisidx[histtype]);
+ }
+ }
+
+ /* Replace the empty last line with the current command-line and put the
+ * cursor there. */
+ ml_replace(curbuf->b_ml.ml_line_count, ccline.cmdbuff, TRUE);
+ curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
+ curwin->w_cursor.col = ccline.cmdpos;
+ changed_line_abv_curs();
+ invalidate_botline();
+ redraw_later(SOME_VALID);
+
+ /* No Ex mode here! */
+ exmode_active = 0;
+
+ State = NORMAL;
+# ifdef FEAT_MOUSE
+ setmouse();
+# endif
+
+ /* Trigger CmdwinEnter autocommands. */
+ trigger_cmd_autocmd(cmdwin_type, EVENT_CMDWINENTER);
+ if (restart_edit != 0) /* autocmd with ":startinsert" */
+ stuffcharReadbuff(K_NOP);
+
+ i = RedrawingDisabled;
+ RedrawingDisabled = 0;
+
+ /*
+ * Call the main loop until <CR> or CTRL-C is typed.
+ */
+ cmdwin_result = 0;
+ main_loop(TRUE, FALSE);
+
+ RedrawingDisabled = i;
+
+# ifdef FEAT_FOLDING
+ save_KeyTyped = KeyTyped;
+# endif
+
+ /* Trigger CmdwinLeave autocommands. */
+ trigger_cmd_autocmd(cmdwin_type, EVENT_CMDWINLEAVE);
+
+# ifdef FEAT_FOLDING
+ /* Restore KeyTyped in case it is modified by autocommands */
+ KeyTyped = save_KeyTyped;
+# endif
+
+ cmdwin_type = 0;
+ exmode_active = save_exmode;
+
+ /* Safety check: The old window or buffer was deleted: It's a bug when
+ * this happens! */
+ if (!win_valid(old_curwin) || !bufref_valid(&old_curbuf))
+ {
+ cmdwin_result = Ctrl_C;
+ emsg(_("E199: Active window or buffer deleted"));
+ }
+ else
+ {
+# if defined(FEAT_EVAL)
+ /* autocmds may abort script processing */
+ if (aborting() && cmdwin_result != K_IGNORE)
+ cmdwin_result = Ctrl_C;
+# endif
+ /* Set the new command line from the cmdline buffer. */
+ vim_free(ccline.cmdbuff);
+ if (cmdwin_result == K_XF1 || cmdwin_result == K_XF2) /* :qa[!] typed */
+ {
+ char *p = (cmdwin_result == K_XF2) ? "qa" : "qa!";
+
+ if (histtype == HIST_CMD)
+ {
+ /* Execute the command directly. */
+ ccline.cmdbuff = vim_strsave((char_u *)p);
+ cmdwin_result = CAR;
+ }
+ else
+ {
+ /* First need to cancel what we were doing. */
+ ccline.cmdbuff = NULL;
+ stuffcharReadbuff(':');
+ stuffReadbuff((char_u *)p);
+ stuffcharReadbuff(CAR);
+ }
+ }
+ else if (cmdwin_result == K_XF2) /* :qa typed */
+ {
+ ccline.cmdbuff = vim_strsave((char_u *)"qa");
+ cmdwin_result = CAR;
+ }
+ else if (cmdwin_result == Ctrl_C)
+ {
+ /* :q or :close, don't execute any command
+ * and don't modify the cmd window. */
+ ccline.cmdbuff = NULL;
+ }
+ else
+ ccline.cmdbuff = vim_strsave(ml_get_curline());
+ if (ccline.cmdbuff == NULL)
+ {
+ ccline.cmdbuff = vim_strsave((char_u *)"");
+ ccline.cmdlen = 0;
+ ccline.cmdbufflen = 1;
+ ccline.cmdpos = 0;
+ cmdwin_result = Ctrl_C;
+ }
+ else
+ {
+ ccline.cmdlen = (int)STRLEN(ccline.cmdbuff);
+ ccline.cmdbufflen = ccline.cmdlen + 1;
+ ccline.cmdpos = curwin->w_cursor.col;
+ if (ccline.cmdpos > ccline.cmdlen)
+ ccline.cmdpos = ccline.cmdlen;
+ if (cmdwin_result == K_IGNORE)
+ {
+ set_cmdspos_cursor();
+ redrawcmd();
+ }
+ }
+
+ /* Don't execute autocommands while deleting the window. */
+ block_autocmds();
+# ifdef FEAT_CONCEAL
+ /* Avoid command-line window first character being concealed. */
+ curwin->w_p_cole = 0;
+# endif
+ wp = curwin;
+ set_bufref(&bufref, curbuf);
+ win_goto(old_curwin);
+ win_close(wp, TRUE);
+
+ /* win_close() may have already wiped the buffer when 'bh' is
+ * set to 'wipe' */
+ if (bufref_valid(&bufref))
+ close_buffer(NULL, bufref.br_buf, DOBUF_WIPE, FALSE);
+
+ /* Restore window sizes. */
+ win_size_restore(&winsizes);
+
+ unblock_autocmds();
+ }
+
+ ga_clear(&winsizes);
+ restart_edit = save_restart_edit;
+# ifdef FEAT_RIGHTLEFT
+ cmdmsg_rl = save_cmdmsg_rl;
+# endif
+
+ State = save_State;
+# ifdef FEAT_MOUSE
+ setmouse();
+# endif
+
+ return cmdwin_result;
+}
+#endif /* FEAT_CMDWIN */
+
+/*
+ * Used for commands that either take a simple command string argument, or:
+ * cmd << endmarker
+ * {script}
+ * endmarker
+ * Returns a pointer to allocated memory with {script} or NULL.
+ */
+ char_u *
+script_get(exarg_T *eap, char_u *cmd)
+{
+ char_u *theline;
+ char *end_pattern = NULL;
+ char dot[] = ".";
+ garray_T ga;
+
+ if (cmd[0] != '<' || cmd[1] != '<' || eap->getline == NULL)
+ return NULL;
+
+ ga_init2(&ga, 1, 0x400);
+
+ if (cmd[2] != NUL)
+ end_pattern = (char *)skipwhite(cmd + 2);
+ else
+ end_pattern = dot;
+
+ for (;;)
+ {
+ theline = eap->getline(
+#ifdef FEAT_EVAL
+ eap->cstack->cs_looplevel > 0 ? -1 :
+#endif
+ NUL, eap->cookie, 0);
+
+ if (theline == NULL || STRCMP(end_pattern, theline) == 0)
+ {
+ vim_free(theline);
+ break;
+ }
+
+ ga_concat(&ga, theline);
+ ga_append(&ga, '\n');
+ vim_free(theline);
+ }
+ ga_append(&ga, NUL);
+
+ return (char_u *)ga.ga_data;
+}
diff --git a/src/farsi.c b/src/farsi.c
new file mode 100644
index 0000000..48dd991
--- /dev/null
+++ b/src/farsi.c
@@ -0,0 +1,2179 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * farsi.c: functions for Farsi language
+ */
+
+#include "vim.h"
+
+#if defined(FEAT_FKMAP) || defined(PROTO)
+
+static int F_is_TyB_TyC_TyD(int src, int offset);
+
+/*
+ * Convert the given Farsi character into a _X or _X_ type
+ */
+ static int
+toF_Xor_X_(int c)
+{
+ int tempc;
+
+ switch (c)
+ {
+ case BE: return _BE;
+ case PE: return _PE;
+ case TE: return _TE;
+ case SE: return _SE;
+ case JIM: return _JIM;
+ case CHE: return _CHE;
+ case HE_J: return _HE_J;
+ case XE: return _XE;
+ case SIN: return _SIN;
+ case SHIN: return _SHIN;
+ case SAD: return _SAD;
+ case ZAD: return _ZAD;
+ case AYN: return _AYN;
+ case AYN_: return _AYN_;
+ case GHAYN: return _GHAYN;
+ case GHAYN_: return _GHAYN_;
+ case FE: return _FE;
+ case GHAF: return _GHAF;
+ case KAF: return _KAF;
+ case GAF: return _GAF;
+ case LAM: return _LAM;
+ case MIM: return _MIM;
+ case NOON: return _NOON;
+ case YE:
+ case YE_: return _YE;
+ case YEE:
+ case YEE_: return _YEE;
+ case IE:
+ case IE_: return _IE;
+ case F_HE:
+ tempc = _HE;
+
+ if (p_ri && (curwin->w_cursor.col + 1
+ < (colnr_T)STRLEN(ml_get_curline())))
+ {
+ inc_cursor();
+
+ if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR))
+ tempc = _HE_;
+
+ dec_cursor();
+ }
+ if (!p_ri && STRLEN(ml_get_curline()))
+ {
+ dec_cursor();
+
+ if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR))
+ tempc = _HE_;
+
+ inc_cursor();
+ }
+
+ return tempc;
+ }
+ return 0;
+}
+
+/*
+ * Convert the given Farsi character into Farsi capital character.
+ */
+ static int
+toF_TyA(int c)
+{
+ switch (c)
+ {
+ case ALEF_: return ALEF;
+ case ALEF_U_H_: return ALEF_U_H;
+ case _BE: return BE;
+ case _PE: return PE;
+ case _TE: return TE;
+ case _SE: return SE;
+ case _JIM: return JIM;
+ case _CHE: return CHE;
+ case _HE_J: return HE_J;
+ case _XE: return XE;
+ case _SIN: return SIN;
+ case _SHIN: return SHIN;
+ case _SAD: return SAD;
+ case _ZAD: return ZAD;
+ case _AYN:
+ case AYN_:
+ case _AYN_: return AYN;
+ case _GHAYN:
+ case GHAYN_:
+ case _GHAYN_: return GHAYN;
+ case _FE: return FE;
+ case _GHAF: return GHAF;
+ /* I am not sure what it is !!! case _KAF_H: */
+ case _KAF: return KAF;
+ case _GAF: return GAF;
+ case _LAM: return LAM;
+ case _MIM: return MIM;
+ case _NOON: return NOON;
+ case _YE:
+ case YE_: return YE;
+ case _YEE:
+ case YEE_: return YEE;
+ case TEE_: return TEE;
+ case _IE:
+ case IE_: return IE;
+ case _HE:
+ case _HE_: return F_HE;
+ }
+ return c;
+}
+
+/*
+ * Is the character under the cursor+offset in the given buffer a join type.
+ * That is a character that is combined with the others.
+ * Note: the offset is used only for command line buffer.
+ */
+ static int
+F_is_TyB_TyC_TyD(int src, int offset)
+{
+ int c;
+
+ if (src == SRC_EDT)
+ c = gchar_cursor();
+ else
+ c = cmd_gchar(AT_CURSOR+offset);
+
+ switch (c)
+ {
+ case _LAM:
+ case _BE:
+ case _PE:
+ case _TE:
+ case _SE:
+ case _JIM:
+ case _CHE:
+ case _HE_J:
+ case _XE:
+ case _SIN:
+ case _SHIN:
+ case _SAD:
+ case _ZAD:
+ case _TA:
+ case _ZA:
+ case _AYN:
+ case _AYN_:
+ case _GHAYN:
+ case _GHAYN_:
+ case _FE:
+ case _GHAF:
+ case _KAF:
+ case _KAF_H:
+ case _GAF:
+ case _MIM:
+ case _NOON:
+ case _YE:
+ case _YEE:
+ case _IE:
+ case _HE_:
+ case _HE:
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * Is the Farsi character one of the terminating only type.
+ */
+ static int
+F_is_TyE(int c)
+{
+ switch (c)
+ {
+ case ALEF_A:
+ case ALEF_D_H:
+ case DAL:
+ case ZAL:
+ case RE:
+ case ZE:
+ case JE:
+ case WAW:
+ case WAW_H:
+ case HAMZE:
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * Is the Farsi character one of the none leading type.
+ */
+ static int
+F_is_TyC_TyD(int c)
+{
+ switch (c)
+ {
+ case ALEF_:
+ case ALEF_U_H_:
+ case _AYN_:
+ case AYN_:
+ case _GHAYN_:
+ case GHAYN_:
+ case _HE_:
+ case YE_:
+ case IE_:
+ case TEE_:
+ case YEE_:
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * Convert a none leading Farsi char into a leading type.
+ */
+ static int
+toF_TyB(int c)
+{
+ switch (c)
+ {
+ case ALEF_: return ALEF;
+ case ALEF_U_H_: return ALEF_U_H;
+ case _AYN_: return _AYN;
+ case AYN_: return AYN; /* exception - there are many of them */
+ case _GHAYN_: return _GHAYN;
+ case GHAYN_: return GHAYN; /* exception - there are many of them */
+ case _HE_: return _HE;
+ case YE_: return YE;
+ case IE_: return IE;
+ case TEE_: return TEE;
+ case YEE_: return YEE;
+ }
+ return c;
+}
+
+
+ static void
+put_and_redo(int c)
+{
+ pchar_cursor(c);
+ AppendCharToRedobuff(K_BS);
+ AppendCharToRedobuff(c);
+}
+
+/*
+ * Overwrite the current redo and cursor characters + left adjust.
+ */
+ static void
+put_curr_and_l_to_X(int c)
+{
+ int tempc;
+
+ if (curwin->w_p_rl && p_ri)
+ return;
+
+ if ((curwin->w_cursor.col < (colnr_T)STRLEN(ml_get_curline())))
+ {
+ if ((p_ri && curwin->w_cursor.col) || !p_ri)
+ {
+ if (p_ri)
+ dec_cursor();
+ else
+ inc_cursor();
+
+ if (F_is_TyC_TyD((tempc = gchar_cursor())))
+ {
+ pchar_cursor(toF_TyB(tempc));
+ AppendCharToRedobuff(K_BS);
+ AppendCharToRedobuff(tempc);
+ }
+
+ if (p_ri)
+ inc_cursor();
+ else
+ dec_cursor();
+ }
+ }
+
+ put_and_redo(c);
+}
+
+/*
+ * Change the char. under the cursor to a X_ or X type
+ */
+ static void
+chg_c_toX_orX(void)
+{
+ int tempc, curc;
+
+ switch ((curc = gchar_cursor()))
+ {
+ case _BE:
+ tempc = BE;
+ break;
+ case _PE:
+ tempc = PE;
+ break;
+ case _TE:
+ tempc = TE;
+ break;
+ case _SE:
+ tempc = SE;
+ break;
+ case _JIM:
+ tempc = JIM;
+ break;
+ case _CHE:
+ tempc = CHE;
+ break;
+ case _HE_J:
+ tempc = HE_J;
+ break;
+ case _XE:
+ tempc = XE;
+ break;
+ case _SIN:
+ tempc = SIN;
+ break;
+ case _SHIN:
+ tempc = SHIN;
+ break;
+ case _SAD:
+ tempc = SAD;
+ break;
+ case _ZAD:
+ tempc = ZAD;
+ break;
+ case _FE:
+ tempc = FE;
+ break;
+ case _GHAF:
+ tempc = GHAF;
+ break;
+ case _KAF_H:
+ case _KAF:
+ tempc = KAF;
+ break;
+ case _GAF:
+ tempc = GAF;
+ break;
+ case _AYN:
+ tempc = AYN;
+ break;
+ case _AYN_:
+ tempc = AYN_;
+ break;
+ case _GHAYN:
+ tempc = GHAYN;
+ break;
+ case _GHAYN_:
+ tempc = GHAYN_;
+ break;
+ case _LAM:
+ tempc = LAM;
+ break;
+ case _MIM:
+ tempc = MIM;
+ break;
+ case _NOON:
+ tempc = NOON;
+ break;
+ case _HE:
+ case _HE_:
+ tempc = F_HE;
+ break;
+ case _YE:
+ case _IE:
+ case _YEE:
+ if (p_ri)
+ {
+ inc_cursor();
+ if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR))
+ tempc = (curc == _YE ? YE_ :
+ (curc == _IE ? IE_ : YEE_));
+ else
+ tempc = (curc == _YE ? YE :
+ (curc == _IE ? IE : YEE));
+ dec_cursor();
+ }
+ else
+ {
+ if (curwin->w_cursor.col)
+ {
+ dec_cursor();
+ if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR))
+ tempc = (curc == _YE ? YE_ :
+ (curc == _IE ? IE_ : YEE_));
+ else
+ tempc = (curc == _YE ? YE :
+ (curc == _IE ? IE : YEE));
+ inc_cursor();
+ }
+ else
+ tempc = (curc == _YE ? YE :
+ (curc == _IE ? IE : YEE));
+ }
+ break;
+ default:
+ tempc = 0;
+ }
+
+ if (tempc)
+ put_and_redo(tempc);
+}
+
+/*
+ * Change the char. under the cursor to a _X_ or X_ type
+ */
+ static void
+chg_c_to_X_orX_(void)
+{
+ int tempc;
+
+ switch (gchar_cursor())
+ {
+ case ALEF:
+ tempc = ALEF_;
+ break;
+ case ALEF_U_H:
+ tempc = ALEF_U_H_;
+ break;
+ case _AYN:
+ tempc = _AYN_;
+ break;
+ case AYN:
+ tempc = AYN_;
+ break;
+ case _GHAYN:
+ tempc = _GHAYN_;
+ break;
+ case GHAYN:
+ tempc = GHAYN_;
+ break;
+ case _HE:
+ tempc = _HE_;
+ break;
+ case YE:
+ tempc = YE_;
+ break;
+ case IE:
+ tempc = IE_;
+ break;
+ case TEE:
+ tempc = TEE_;
+ break;
+ case YEE:
+ tempc = YEE_;
+ break;
+ default:
+ tempc = 0;
+ }
+
+ if (tempc)
+ put_and_redo(tempc);
+}
+
+/*
+ * Change the char. under the cursor to a _X_ or _X type
+ */
+ static void
+chg_c_to_X_or_X(void)
+{
+ int tempc;
+
+ tempc = gchar_cursor();
+
+ if (curwin->w_cursor.col + 1 < (colnr_T)STRLEN(ml_get_curline()))
+ {
+ inc_cursor();
+
+ if ((tempc == F_HE) && (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR)))
+ {
+ tempc = _HE_;
+
+ dec_cursor();
+
+ put_and_redo(tempc);
+ return;
+ }
+
+ dec_cursor();
+ }
+
+ if ((tempc = toF_Xor_X_(tempc)) != 0)
+ put_and_redo(tempc);
+}
+
+/*
+ * Change the character left to the cursor to a _X_ or X_ type
+ */
+ static void
+chg_l_to_X_orX_(void)
+{
+ int tempc;
+
+ if (curwin->w_cursor.col != 0 &&
+ (curwin->w_cursor.col + 1 == (colnr_T)STRLEN(ml_get_curline())))
+ return;
+
+ if (!curwin->w_cursor.col && p_ri)
+ return;
+
+ if (p_ri)
+ dec_cursor();
+ else
+ inc_cursor();
+
+ switch (gchar_cursor())
+ {
+ case ALEF:
+ tempc = ALEF_;
+ break;
+ case ALEF_U_H:
+ tempc = ALEF_U_H_;
+ break;
+ case _AYN:
+ tempc = _AYN_;
+ break;
+ case AYN:
+ tempc = AYN_;
+ break;
+ case _GHAYN:
+ tempc = _GHAYN_;
+ break;
+ case GHAYN:
+ tempc = GHAYN_;
+ break;
+ case _HE:
+ tempc = _HE_;
+ break;
+ case YE:
+ tempc = YE_;
+ break;
+ case IE:
+ tempc = IE_;
+ break;
+ case TEE:
+ tempc = TEE_;
+ break;
+ case YEE:
+ tempc = YEE_;
+ break;
+ default:
+ tempc = 0;
+ }
+
+ if (tempc)
+ put_and_redo(tempc);
+
+ if (p_ri)
+ inc_cursor();
+ else
+ dec_cursor();
+}
+
+/*
+ * Change the character left to the cursor to a X or _X type
+ */
+ static void
+chg_l_toXor_X(void)
+{
+ int tempc;
+
+ if (curwin->w_cursor.col != 0 &&
+ (curwin->w_cursor.col + 1 == (colnr_T)STRLEN(ml_get_curline())))
+ return;
+
+ if (!curwin->w_cursor.col && p_ri)
+ return;
+
+ if (p_ri)
+ dec_cursor();
+ else
+ inc_cursor();
+
+ switch (gchar_cursor())
+ {
+ case ALEF_:
+ tempc = ALEF;
+ break;
+ case ALEF_U_H_:
+ tempc = ALEF_U_H;
+ break;
+ case _AYN_:
+ tempc = _AYN;
+ break;
+ case AYN_:
+ tempc = AYN;
+ break;
+ case _GHAYN_:
+ tempc = _GHAYN;
+ break;
+ case GHAYN_:
+ tempc = GHAYN;
+ break;
+ case _HE_:
+ tempc = _HE;
+ break;
+ case YE_:
+ tempc = YE;
+ break;
+ case IE_:
+ tempc = IE;
+ break;
+ case TEE_:
+ tempc = TEE;
+ break;
+ case YEE_:
+ tempc = YEE;
+ break;
+ default:
+ tempc = 0;
+ }
+
+ if (tempc)
+ put_and_redo(tempc);
+
+ if (p_ri)
+ inc_cursor();
+ else
+ dec_cursor();
+}
+
+/*
+ * Change the character right to the cursor to a _X or _X_ type
+ */
+ static void
+chg_r_to_Xor_X_(void)
+{
+ int tempc, c;
+
+ if (curwin->w_cursor.col)
+ {
+ if (!p_ri)
+ dec_cursor();
+
+ tempc = gchar_cursor();
+
+ if ((c = toF_Xor_X_(tempc)) != 0)
+ put_and_redo(c);
+
+ if (!p_ri)
+ inc_cursor();
+
+ }
+}
+
+/*
+ * Map Farsi keyboard when in fkmap mode.
+ */
+ int
+fkmap(int c)
+{
+ int tempc;
+ int insert_mode = (State & INSERT);
+ static int revins = 0;
+
+ if (IS_SPECIAL(c))
+ return c;
+
+ if (insert_mode)
+ {
+ if (VIM_ISDIGIT(c) || ((c == '.' || c == '+' || c == '-' ||
+ c == '^' || c == '%' || c == '#' || c == '=') && revins))
+ {
+ /* Numbers are entered left-to-right. */
+ if (!revins)
+ {
+ if (curwin->w_cursor.col)
+ {
+ if (!p_ri)
+ dec_cursor();
+
+ chg_c_toX_orX ();
+ chg_l_toXor_X ();
+
+ if (!p_ri)
+ inc_cursor();
+ }
+ }
+
+ arrow_used = TRUE;
+ (void)stop_arrow();
+
+ if (!curwin->w_p_rl && revins)
+ inc_cursor();
+
+ ++revins;
+ p_ri = 1;
+ }
+ else if (revins)
+ {
+ /* Stop entering number. */
+ arrow_used = TRUE;
+ (void)stop_arrow();
+
+ revins = 0;
+ if (curwin->w_p_rl)
+ {
+ while ((F_isdigit(gchar_cursor())
+ || (gchar_cursor() == F_PERIOD
+ || gchar_cursor() == F_PLUS
+ || gchar_cursor() == F_MINUS
+ || gchar_cursor() == F_MUL
+ || gchar_cursor() == F_DIVIDE
+ || gchar_cursor() == F_PERCENT
+ || gchar_cursor() == F_EQUALS))
+ && gchar_cursor() != NUL)
+ ++curwin->w_cursor.col;
+ }
+ else
+ {
+ if (curwin->w_cursor.col)
+ while ((F_isdigit(gchar_cursor())
+ || (gchar_cursor() == F_PERIOD
+ || gchar_cursor() == F_PLUS
+ || gchar_cursor() == F_MINUS
+ || gchar_cursor() == F_MUL
+ || gchar_cursor() == F_DIVIDE
+ || gchar_cursor() == F_PERCENT
+ || gchar_cursor() == F_EQUALS))
+ && --curwin->w_cursor.col)
+ ;
+
+ if (!F_isdigit(gchar_cursor()))
+ ++curwin->w_cursor.col;
+ }
+ }
+ }
+
+ if (!revins)
+ {
+ if (curwin->w_p_rl)
+ p_ri = 0;
+ if (!curwin->w_p_rl)
+ p_ri = 1;
+ }
+
+ if ((c < 0x100) && (isalpha(c) || c == '&' || c == '^' || c == ';' ||
+ c == '\''|| c == ',' || c == '[' ||
+ c == ']' || c == '{' || c == '}'))
+ chg_r_to_Xor_X_();
+
+ tempc = 0;
+
+ switch (c)
+ {
+ case '`':
+ case ' ':
+ case '.':
+ case '!':
+ case '"':
+ case '$':
+ case '%':
+ case '^':
+ case '&':
+ case '/':
+ case '(':
+ case ')':
+ case '=':
+ case '\\':
+ case '?':
+ case '+':
+ case '-':
+ case '_':
+ case '*':
+ case ':':
+ case '#':
+ case '~':
+ case '@':
+ case '<':
+ case '>':
+ case '{':
+ case '}':
+ case '|':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case 'B':
+ case 'E':
+ case 'F':
+ case 'H':
+ case 'I':
+ case 'K':
+ case 'L':
+ case 'M':
+ case 'O':
+ case 'P':
+ case 'Q':
+ case 'R':
+ case 'T':
+ case 'U':
+ case 'W':
+ case 'Y':
+ case NL:
+ case TAB:
+
+ if (p_ri && c == NL && curwin->w_cursor.col && insert_mode)
+ {
+ /*
+ * If the char before the cursor is _X_ or X_ do not change
+ * the one under the cursor with X type.
+ */
+ dec_cursor();
+
+ if (F_isalpha(gchar_cursor()))
+ {
+ inc_cursor();
+ return NL;
+ }
+
+ inc_cursor();
+ }
+
+ if (!p_ri && !curwin->w_cursor.col)
+ {
+ switch (c)
+ {
+ case '0': return FARSI_0;
+ case '1': return FARSI_1;
+ case '2': return FARSI_2;
+ case '3': return FARSI_3;
+ case '4': return FARSI_4;
+ case '5': return FARSI_5;
+ case '6': return FARSI_6;
+ case '7': return FARSI_7;
+ case '8': return FARSI_8;
+ case '9': return FARSI_9;
+ case 'B': return F_PSP;
+ case 'E': return JAZR_N;
+ case 'F': return ALEF_D_H;
+ case 'H': return ALEF_A;
+ case 'I': return TASH;
+ case 'K': return F_LQUOT;
+ case 'L': return F_RQUOT;
+ case 'M': return HAMZE;
+ case 'O': return '[';
+ case 'P': return ']';
+ case 'Q': return OO;
+ case 'R': return MAD_N;
+ case 'T': return OW;
+ case 'U': return MAD;
+ case 'W': return OW_OW;
+ case 'Y': return JAZR;
+ case '`': return F_PCN;
+ case '!': return F_EXCL;
+ case '@': return F_COMMA;
+ case '#': return F_DIVIDE;
+ case '$': return F_CURRENCY;
+ case '%': return F_PERCENT;
+ case '^': return F_MUL;
+ case '&': return F_BCOMMA;
+ case '*': return F_STAR;
+ case '(': return F_LPARENT;
+ case ')': return F_RPARENT;
+ case '-': return F_MINUS;
+ case '_': return F_UNDERLINE;
+ case '=': return F_EQUALS;
+ case '+': return F_PLUS;
+ case '\\': return F_BSLASH;
+ case '|': return F_PIPE;
+ case ':': return F_DCOLON;
+ case '"': return F_SEMICOLON;
+ case '.': return F_PERIOD;
+ case '/': return F_SLASH;
+ case '<': return F_LESS;
+ case '>': return F_GREATER;
+ case '?': return F_QUESTION;
+ case ' ': return F_BLANK;
+ }
+ break;
+ }
+
+ if (insert_mode)
+ {
+ if (!p_ri)
+ dec_cursor();
+
+ switch ((tempc = gchar_cursor()))
+ {
+ case _BE:
+ case _PE:
+ case _TE:
+ case _SE:
+ case _JIM:
+ case _CHE:
+ case _HE_J:
+ case _XE:
+ case _SIN:
+ case _SHIN:
+ case _SAD:
+ case _ZAD:
+ case _FE:
+ case _GHAF:
+ case _KAF:
+ case _KAF_H:
+ case _GAF:
+ case _LAM:
+ case _MIM:
+ case _NOON:
+ case _HE:
+ case _HE_:
+ case _TA:
+ case _ZA:
+ put_curr_and_l_to_X(toF_TyA(tempc));
+ break;
+ case _AYN:
+ case _AYN_:
+
+ if (!p_ri)
+ if (!curwin->w_cursor.col)
+ {
+ put_curr_and_l_to_X(AYN);
+ break;
+ }
+
+ if (p_ri)
+ inc_cursor();
+ else
+ dec_cursor();
+
+ if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR))
+ tempc = AYN_;
+ else
+ tempc = AYN;
+
+ if (p_ri)
+ dec_cursor();
+ else
+ inc_cursor();
+
+ put_curr_and_l_to_X(tempc);
+
+ break;
+ case _GHAYN:
+ case _GHAYN_:
+
+ if (!p_ri)
+ if (!curwin->w_cursor.col)
+ {
+ put_curr_and_l_to_X(GHAYN);
+ break;
+ }
+
+ if (p_ri)
+ inc_cursor();
+ else
+ dec_cursor();
+
+ if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR))
+ tempc = GHAYN_;
+ else
+ tempc = GHAYN;
+
+ if (p_ri)
+ dec_cursor();
+ else
+ inc_cursor();
+
+ put_curr_and_l_to_X(tempc);
+ break;
+ case _YE:
+ case _IE:
+ case _YEE:
+ if (!p_ri)
+ if (!curwin->w_cursor.col)
+ {
+ put_curr_and_l_to_X((tempc == _YE ? YE :
+ (tempc == _IE ? IE : YEE)));
+ break;
+ }
+
+ if (p_ri)
+ inc_cursor();
+ else
+ dec_cursor();
+
+ if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR))
+ tempc = (tempc == _YE ? YE_ :
+ (tempc == _IE ? IE_ : YEE_));
+ else
+ tempc = (tempc == _YE ? YE :
+ (tempc == _IE ? IE : YEE));
+
+ if (p_ri)
+ dec_cursor();
+ else
+ inc_cursor();
+
+ put_curr_and_l_to_X(tempc);
+ break;
+ }
+
+ if (!p_ri)
+ inc_cursor();
+ }
+
+ tempc = 0;
+
+ switch (c)
+ {
+ case '0': return FARSI_0;
+ case '1': return FARSI_1;
+ case '2': return FARSI_2;
+ case '3': return FARSI_3;
+ case '4': return FARSI_4;
+ case '5': return FARSI_5;
+ case '6': return FARSI_6;
+ case '7': return FARSI_7;
+ case '8': return FARSI_8;
+ case '9': return FARSI_9;
+ case 'B': return F_PSP;
+ case 'E': return JAZR_N;
+ case 'F': return ALEF_D_H;
+ case 'H': return ALEF_A;
+ case 'I': return TASH;
+ case 'K': return F_LQUOT;
+ case 'L': return F_RQUOT;
+ case 'M': return HAMZE;
+ case 'O': return '[';
+ case 'P': return ']';
+ case 'Q': return OO;
+ case 'R': return MAD_N;
+ case 'T': return OW;
+ case 'U': return MAD;
+ case 'W': return OW_OW;
+ case 'Y': return JAZR;
+ case '`': return F_PCN;
+ case '!': return F_EXCL;
+ case '@': return F_COMMA;
+ case '#': return F_DIVIDE;
+ case '$': return F_CURRENCY;
+ case '%': return F_PERCENT;
+ case '^': return F_MUL;
+ case '&': return F_BCOMMA;
+ case '*': return F_STAR;
+ case '(': return F_LPARENT;
+ case ')': return F_RPARENT;
+ case '-': return F_MINUS;
+ case '_': return F_UNDERLINE;
+ case '=': return F_EQUALS;
+ case '+': return F_PLUS;
+ case '\\': return F_BSLASH;
+ case '|': return F_PIPE;
+ case ':': return F_DCOLON;
+ case '"': return F_SEMICOLON;
+ case '.': return F_PERIOD;
+ case '/': return F_SLASH;
+ case '<': return F_LESS;
+ case '>': return F_GREATER;
+ case '?': return F_QUESTION;
+ case ' ': return F_BLANK;
+ }
+ break;
+
+ case 'a':
+ tempc = _SHIN;
+ break;
+ case 'A':
+ tempc = WAW_H;
+ break;
+ case 'b':
+ tempc = ZAL;
+ break;
+ case 'c':
+ tempc = ZE;
+ break;
+ case 'C':
+ tempc = JE;
+ break;
+ case 'd':
+ tempc = _YE;
+ break;
+ case 'D':
+ tempc = _YEE;
+ break;
+ case 'e':
+ tempc = _SE;
+ break;
+ case 'f':
+ tempc = _BE;
+ break;
+ case 'g':
+ tempc = _LAM;
+ break;
+ case 'G':
+ if (!curwin->w_cursor.col && STRLEN(ml_get_curline()))
+ {
+
+ if (gchar_cursor() == _LAM)
+ chg_c_toX_orX ();
+ else if (p_ri)
+ chg_c_to_X_or_X ();
+ }
+
+ if (!p_ri)
+ if (!curwin->w_cursor.col)
+ return ALEF_U_H;
+
+ if (!p_ri)
+ dec_cursor();
+
+ if (gchar_cursor() == _LAM)
+ {
+ chg_c_toX_orX ();
+ chg_l_toXor_X ();
+ tempc = ALEF_U_H;
+ }
+ else if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR))
+ {
+ tempc = ALEF_U_H_;
+ chg_l_toXor_X ();
+ }
+ else
+ tempc = ALEF_U_H;
+
+ if (!p_ri)
+ inc_cursor();
+
+ return tempc;
+ case 'h':
+ if (!curwin->w_cursor.col && STRLEN(ml_get_curline()))
+ {
+ if (p_ri)
+ chg_c_to_X_or_X ();
+
+ }
+
+ if (!p_ri)
+ if (!curwin->w_cursor.col)
+ return ALEF;
+
+ if (!p_ri)
+ dec_cursor();
+
+ if (gchar_cursor() == _LAM)
+ {
+ chg_l_toXor_X();
+ del_char(FALSE);
+ AppendCharToRedobuff(K_BS);
+
+ if (!p_ri)
+ dec_cursor();
+
+ tempc = LA;
+ }
+ else
+ {
+ if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR))
+ {
+ tempc = ALEF_;
+ chg_l_toXor_X ();
+ }
+ else
+ tempc = ALEF;
+ }
+
+ if (!p_ri)
+ inc_cursor();
+
+ return tempc;
+ case 'i':
+ if (!curwin->w_cursor.col && STRLEN(ml_get_curline()))
+ {
+ if (!p_ri && !F_is_TyE(tempc))
+ chg_c_to_X_orX_ ();
+ if (p_ri)
+ chg_c_to_X_or_X ();
+
+ }
+
+ if (!p_ri && !curwin->w_cursor.col)
+ return _HE;
+
+ if (!p_ri)
+ dec_cursor();
+
+ if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR))
+ tempc = _HE_;
+ else
+ tempc = _HE;
+
+ if (!p_ri)
+ inc_cursor();
+ break;
+ case 'j':
+ tempc = _TE;
+ break;
+ case 'J':
+ if (!curwin->w_cursor.col && STRLEN(ml_get_curline()))
+ {
+ if (p_ri)
+ chg_c_to_X_or_X ();
+
+ }
+
+ if (!p_ri)
+ if (!curwin->w_cursor.col)
+ return TEE;
+
+ if (!p_ri)
+ dec_cursor();
+
+ if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR))
+ {
+ tempc = TEE_;
+ chg_l_toXor_X ();
+ }
+ else
+ tempc = TEE;
+
+ if (!p_ri)
+ inc_cursor();
+
+ return tempc;
+ case 'k':
+ tempc = _NOON;
+ break;
+ case 'l':
+ tempc = _MIM;
+ break;
+ case 'm':
+ tempc = _PE;
+ break;
+ case 'n':
+ case 'N':
+ tempc = DAL;
+ break;
+ case 'o':
+ tempc = _XE;
+ break;
+ case 'p':
+ tempc = _HE_J;
+ break;
+ case 'q':
+ tempc = _ZAD;
+ break;
+ case 'r':
+ tempc = _GHAF;
+ break;
+ case 's':
+ tempc = _SIN;
+ break;
+ case 'S':
+ tempc = _IE;
+ break;
+ case 't':
+ tempc = _FE;
+ break;
+ case 'u':
+ if (!curwin->w_cursor.col && STRLEN(ml_get_curline()))
+ {
+ if (!p_ri && !F_is_TyE(tempc))
+ chg_c_to_X_orX_ ();
+ if (p_ri)
+ chg_c_to_X_or_X ();
+
+ }
+
+ if (!p_ri && !curwin->w_cursor.col)
+ return _AYN;
+
+ if (!p_ri)
+ dec_cursor();
+
+ if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR))
+ tempc = _AYN_;
+ else
+ tempc = _AYN;
+
+ if (!p_ri)
+ inc_cursor();
+ break;
+ case 'v':
+ case 'V':
+ tempc = RE;
+ break;
+ case 'w':
+ tempc = _SAD;
+ break;
+ case 'x':
+ case 'X':
+ tempc = _TA;
+ break;
+ case 'y':
+ if (!curwin->w_cursor.col && STRLEN(ml_get_curline()))
+ {
+ if (!p_ri && !F_is_TyE(tempc))
+ chg_c_to_X_orX_ ();
+ if (p_ri)
+ chg_c_to_X_or_X ();
+
+ }
+
+ if (!p_ri && !curwin->w_cursor.col)
+ return _GHAYN;
+
+ if (!p_ri)
+ dec_cursor();
+
+ if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR))
+ tempc = _GHAYN_;
+ else
+ tempc = _GHAYN;
+
+ if (!p_ri)
+ inc_cursor();
+
+ break;
+ case 'z':
+ tempc = _ZA;
+ break;
+ case 'Z':
+ tempc = _KAF_H;
+ break;
+ case ';':
+ tempc = _KAF;
+ break;
+ case '\'':
+ tempc = _GAF;
+ break;
+ case ',':
+ tempc = WAW;
+ break;
+ case '[':
+ tempc = _JIM;
+ break;
+ case ']':
+ tempc = _CHE;
+ break;
+ }
+
+ if (F_isalpha(tempc) || F_isdigit(tempc))
+ {
+ if (!curwin->w_cursor.col && STRLEN(ml_get_curline()))
+ {
+ if (!p_ri && !F_is_TyE(tempc))
+ chg_c_to_X_orX_();
+ if (p_ri)
+ chg_c_to_X_or_X();
+ }
+
+ if (curwin->w_cursor.col)
+ {
+ if (!p_ri)
+ dec_cursor();
+
+ if (F_is_TyE(tempc))
+ chg_l_toXor_X();
+ else
+ chg_l_to_X_orX_();
+
+ if (!p_ri)
+ inc_cursor();
+ }
+ }
+ if (tempc)
+ return tempc;
+ return c;
+}
+
+/*
+ * Convert a none leading Farsi char into a leading type.
+ */
+ static int
+toF_leading(int c)
+{
+ switch (c)
+ {
+ case ALEF_: return ALEF;
+ case ALEF_U_H_: return ALEF_U_H;
+ case BE: return _BE;
+ case PE: return _PE;
+ case TE: return _TE;
+ case SE: return _SE;
+ case JIM: return _JIM;
+ case CHE: return _CHE;
+ case HE_J: return _HE_J;
+ case XE: return _XE;
+ case SIN: return _SIN;
+ case SHIN: return _SHIN;
+ case SAD: return _SAD;
+ case ZAD: return _ZAD;
+
+ case AYN:
+ case AYN_:
+ case _AYN_: return _AYN;
+
+ case GHAYN:
+ case GHAYN_:
+ case _GHAYN_: return _GHAYN;
+
+ case FE: return _FE;
+ case GHAF: return _GHAF;
+ case KAF: return _KAF;
+ case GAF: return _GAF;
+ case LAM: return _LAM;
+ case MIM: return _MIM;
+ case NOON: return _NOON;
+
+ case _HE_:
+ case F_HE: return _HE;
+
+ case YE:
+ case YE_: return _YE;
+
+ case IE_:
+ case IE: return _IE;
+
+ case YEE:
+ case YEE_: return _YEE;
+ }
+ return c;
+}
+
+/*
+ * Convert a given Farsi char into right joining type.
+ */
+ static int
+toF_Rjoin(int c)
+{
+ switch (c)
+ {
+ case ALEF: return ALEF_;
+ case ALEF_U_H: return ALEF_U_H_;
+ case BE: return _BE;
+ case PE: return _PE;
+ case TE: return _TE;
+ case SE: return _SE;
+ case JIM: return _JIM;
+ case CHE: return _CHE;
+ case HE_J: return _HE_J;
+ case XE: return _XE;
+ case SIN: return _SIN;
+ case SHIN: return _SHIN;
+ case SAD: return _SAD;
+ case ZAD: return _ZAD;
+
+ case AYN:
+ case AYN_:
+ case _AYN: return _AYN_;
+
+ case GHAYN:
+ case GHAYN_:
+ case _GHAYN_: return _GHAYN_;
+
+ case FE: return _FE;
+ case GHAF: return _GHAF;
+ case KAF: return _KAF;
+ case GAF: return _GAF;
+ case LAM: return _LAM;
+ case MIM: return _MIM;
+ case NOON: return _NOON;
+
+ case _HE:
+ case F_HE: return _HE_;
+
+ case YE:
+ case YE_: return _YE;
+
+ case IE_:
+ case IE: return _IE;
+
+ case TEE: return TEE_;
+
+ case YEE:
+ case YEE_: return _YEE;
+ }
+ return c;
+}
+
+/*
+ * Can a given Farsi character join via its left edj.
+ */
+ static int
+canF_Ljoin(int c)
+{
+ switch (c)
+ {
+ case _BE:
+ case BE:
+ case PE:
+ case _PE:
+ case TE:
+ case _TE:
+ case SE:
+ case _SE:
+ case JIM:
+ case _JIM:
+ case CHE:
+ case _CHE:
+ case HE_J:
+ case _HE_J:
+ case XE:
+ case _XE:
+ case SIN:
+ case _SIN:
+ case SHIN:
+ case _SHIN:
+ case SAD:
+ case _SAD:
+ case ZAD:
+ case _ZAD:
+ case _TA:
+ case _ZA:
+ case AYN:
+ case _AYN:
+ case _AYN_:
+ case AYN_:
+ case GHAYN:
+ case GHAYN_:
+ case _GHAYN_:
+ case _GHAYN:
+ case FE:
+ case _FE:
+ case GHAF:
+ case _GHAF:
+ case _KAF_H:
+ case KAF:
+ case _KAF:
+ case GAF:
+ case _GAF:
+ case LAM:
+ case _LAM:
+ case MIM:
+ case _MIM:
+ case NOON:
+ case _NOON:
+ case IE:
+ case _IE:
+ case IE_:
+ case YE:
+ case _YE:
+ case YE_:
+ case YEE:
+ case _YEE:
+ case YEE_:
+ case F_HE:
+ case _HE:
+ case _HE_:
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * Can a given Farsi character join via its right edj.
+ */
+ static int
+canF_Rjoin(int c)
+{
+ switch (c)
+ {
+ case ALEF:
+ case ALEF_:
+ case ALEF_U_H:
+ case ALEF_U_H_:
+ case DAL:
+ case ZAL:
+ case RE:
+ case JE:
+ case ZE:
+ case TEE:
+ case TEE_:
+ case WAW:
+ case WAW_H:
+ return TRUE;
+ }
+
+ return canF_Ljoin(c);
+
+}
+
+/*
+ * is a given Farsi character a terminating type.
+ */
+ static int
+F_isterm(int c)
+{
+ switch (c)
+ {
+ case ALEF:
+ case ALEF_:
+ case ALEF_U_H:
+ case ALEF_U_H_:
+ case DAL:
+ case ZAL:
+ case RE:
+ case JE:
+ case ZE:
+ case WAW:
+ case WAW_H:
+ case TEE:
+ case TEE_:
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/*
+ * Convert the given Farsi character into a ending type .
+ */
+ static int
+toF_ending(int c)
+{
+ switch (c)
+ {
+ case _BE: return BE;
+ case _PE: return PE;
+ case _TE: return TE;
+ case _SE: return SE;
+ case _JIM: return JIM;
+ case _CHE: return CHE;
+ case _HE_J: return HE_J;
+ case _XE: return XE;
+ case _SIN: return SIN;
+ case _SHIN: return SHIN;
+ case _SAD: return SAD;
+ case _ZAD: return ZAD;
+ case _AYN: return AYN;
+ case _AYN_: return AYN_;
+ case _GHAYN: return GHAYN;
+ case _GHAYN_: return GHAYN_;
+ case _FE: return FE;
+ case _GHAF: return GHAF;
+ case _KAF_H:
+ case _KAF: return KAF;
+ case _GAF: return GAF;
+ case _LAM: return LAM;
+ case _MIM: return MIM;
+ case _NOON: return NOON;
+ case _YE: return YE_;
+ case YE_: return YE;
+ case _YEE: return YEE_;
+ case YEE_: return YEE;
+ case TEE: return TEE_;
+ case _IE: return IE_;
+ case IE_: return IE;
+ case _HE:
+ case _HE_: return F_HE;
+ }
+ return c;
+}
+
+/*
+ * Convert the Farsi 3342 standard into Farsi VIM.
+ */
+ static void
+conv_to_pvim(void)
+{
+ char_u *ptr;
+ int lnum, llen, i;
+
+ for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count; ++lnum)
+ {
+ ptr = ml_get((linenr_T)lnum);
+
+ llen = (int)STRLEN(ptr);
+
+ for (i = 0; i < llen-1; i++)
+ {
+ if (canF_Ljoin(ptr[i]) && canF_Rjoin(ptr[i+1]))
+ {
+ ptr[i] = toF_leading(ptr[i]);
+ ++i;
+
+ while (i < llen && canF_Rjoin(ptr[i]))
+ {
+ ptr[i] = toF_Rjoin(ptr[i]);
+ if (F_isterm(ptr[i]) || !F_isalpha(ptr[i]))
+ break;
+ ++i;
+ }
+ if (!F_isalpha(ptr[i]) || !canF_Rjoin(ptr[i]))
+ ptr[i-1] = toF_ending(ptr[i-1]);
+ }
+ else
+ ptr[i] = toF_TyA(ptr[i]);
+ }
+ }
+
+ /*
+ * Following lines contains Farsi encoded character.
+ */
+
+ do_cmdline_cmd((char_u *)"%s/\202\231/\232/ge");
+ do_cmdline_cmd((char_u *)"%s/\201\231/\370\334/ge");
+
+ /* Assume the screen has been messed up: clear it and redraw. */
+ redraw_later(CLEAR);
+ msg_attr(farsi_text_1, HL_ATTR(HLF_S));
+}
+
+/*
+ * Convert the Farsi VIM into Farsi 3342 standard.
+ */
+ static void
+conv_to_pstd(void)
+{
+ char_u *ptr;
+ int lnum, llen, i;
+
+ /*
+ * Following line contains Farsi encoded character.
+ */
+ do_cmdline_cmd((char_u *)"%s/\232/\202\231/ge");
+
+ for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count; ++lnum)
+ {
+ ptr = ml_get((linenr_T)lnum);
+ llen = (int)STRLEN(ptr);
+
+ for (i = 0; i < llen; i++)
+ ptr[i] = toF_TyA(ptr[i]);
+ }
+
+ /* Assume the screen has been messed up: clear it and redraw. */
+ redraw_later(CLEAR);
+ msg_attr(farsi_text_2, HL_ATTR(HLF_S));
+}
+
+/*
+ * left-right swap the characters in buf[len].
+ */
+ static void
+lrswapbuf(char_u *buf, int len)
+{
+ char_u *s, *e;
+ int c;
+
+ s = buf;
+ e = buf + len - 1;
+
+ while (e > s)
+ {
+ c = *s;
+ *s = *e;
+ *e = c;
+ ++s;
+ --e;
+ }
+}
+
+/*
+ * swap all the characters in reverse direction
+ */
+ char_u *
+lrswap(char_u *ibuf)
+{
+ if (ibuf != NULL && *ibuf != NUL)
+ lrswapbuf(ibuf, (int)STRLEN(ibuf));
+ return ibuf;
+}
+
+/*
+ * swap all the Farsi characters in reverse direction
+ */
+ char_u *
+lrFswap(char_u *cmdbuf, int len)
+{
+ int i, cnt;
+
+ if (cmdbuf == NULL)
+ return cmdbuf;
+
+ if (len == 0 && (len = (int)STRLEN(cmdbuf)) == 0)
+ return cmdbuf;
+
+ for (i = 0; i < len; i++)
+ {
+ for (cnt = 0; i + cnt < len
+ && (F_isalpha(cmdbuf[i + cnt])
+ || F_isdigit(cmdbuf[i + cnt])
+ || cmdbuf[i + cnt] == ' '); ++cnt)
+ ;
+
+ lrswapbuf(cmdbuf + i, cnt);
+ i += cnt;
+ }
+ return cmdbuf;
+}
+
+/*
+ * Reverse the characters in the search path and substitute section
+ * accordingly.
+ * TODO: handle different separator characters. Use skip_regexp().
+ */
+ char_u *
+lrF_sub(char_u *ibuf)
+{
+ char_u *p, *ep;
+ int i, cnt;
+
+ p = ibuf;
+
+ /* Find the boundary of the search path */
+ while (((p = vim_strchr(p + 1, '/')) != NULL) && p[-1] == '\\')
+ ;
+
+ if (p == NULL)
+ return ibuf;
+
+ /* Reverse the Farsi characters in the search path. */
+ lrFswap(ibuf, (int)(p-ibuf));
+
+ /* Now find the boundary of the substitute section */
+ if ((ep = (char_u *)strrchr((char *)++p, '/')) != NULL)
+ cnt = (int)(ep - p);
+ else
+ cnt = (int)STRLEN(p);
+
+ /* Reverse the characters in the substitute section and take care of '\' */
+ for (i = 0; i < cnt-1; i++)
+ if (p[i] == '\\')
+ {
+ p[i] = p[i+1] ;
+ p[++i] = '\\';
+ }
+
+ lrswapbuf(p, cnt);
+
+ return ibuf;
+}
+
+/*
+ * Map Farsi keyboard when in cmd_fkmap mode.
+ */
+ int
+cmdl_fkmap(int c)
+{
+ int tempc;
+
+ switch (c)
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '`':
+ case ' ':
+ case '.':
+ case '!':
+ case '"':
+ case '$':
+ case '%':
+ case '^':
+ case '&':
+ case '/':
+ case '(':
+ case ')':
+ case '=':
+ case '\\':
+ case '?':
+ case '+':
+ case '-':
+ case '_':
+ case '*':
+ case ':':
+ case '#':
+ case '~':
+ case '@':
+ case '<':
+ case '>':
+ case '{':
+ case '}':
+ case '|':
+ case 'B':
+ case 'E':
+ case 'F':
+ case 'H':
+ case 'I':
+ case 'K':
+ case 'L':
+ case 'M':
+ case 'O':
+ case 'P':
+ case 'Q':
+ case 'R':
+ case 'T':
+ case 'U':
+ case 'W':
+ case 'Y':
+ case NL:
+ case TAB:
+
+ switch ((tempc = cmd_gchar(AT_CURSOR)))
+ {
+ case _BE:
+ case _PE:
+ case _TE:
+ case _SE:
+ case _JIM:
+ case _CHE:
+ case _HE_J:
+ case _XE:
+ case _SIN:
+ case _SHIN:
+ case _SAD:
+ case _ZAD:
+ case _AYN:
+ case _GHAYN:
+ case _FE:
+ case _GHAF:
+ case _KAF:
+ case _GAF:
+ case _LAM:
+ case _MIM:
+ case _NOON:
+ case _HE:
+ case _HE_:
+ cmd_pchar(toF_TyA(tempc), AT_CURSOR);
+ break;
+ case _AYN_:
+ cmd_pchar(AYN_, AT_CURSOR);
+ break;
+ case _GHAYN_:
+ cmd_pchar(GHAYN_, AT_CURSOR);
+ break;
+ case _IE:
+ if (F_is_TyB_TyC_TyD(SRC_CMD, AT_CURSOR+1))
+ cmd_pchar(IE_, AT_CURSOR);
+ else
+ cmd_pchar(IE, AT_CURSOR);
+ break;
+ case _YEE:
+ if (F_is_TyB_TyC_TyD(SRC_CMD, AT_CURSOR+1))
+ cmd_pchar(YEE_, AT_CURSOR);
+ else
+ cmd_pchar(YEE, AT_CURSOR);
+ break;
+ case _YE:
+ if (F_is_TyB_TyC_TyD(SRC_CMD, AT_CURSOR+1))
+ cmd_pchar(YE_, AT_CURSOR);
+ else
+ cmd_pchar(YE, AT_CURSOR);
+ }
+
+ switch (c)
+ {
+ case '0': return FARSI_0;
+ case '1': return FARSI_1;
+ case '2': return FARSI_2;
+ case '3': return FARSI_3;
+ case '4': return FARSI_4;
+ case '5': return FARSI_5;
+ case '6': return FARSI_6;
+ case '7': return FARSI_7;
+ case '8': return FARSI_8;
+ case '9': return FARSI_9;
+ case 'B': return F_PSP;
+ case 'E': return JAZR_N;
+ case 'F': return ALEF_D_H;
+ case 'H': return ALEF_A;
+ case 'I': return TASH;
+ case 'K': return F_LQUOT;
+ case 'L': return F_RQUOT;
+ case 'M': return HAMZE;
+ case 'O': return '[';
+ case 'P': return ']';
+ case 'Q': return OO;
+ case 'R': return MAD_N;
+ case 'T': return OW;
+ case 'U': return MAD;
+ case 'W': return OW_OW;
+ case 'Y': return JAZR;
+ case '`': return F_PCN;
+ case '!': return F_EXCL;
+ case '@': return F_COMMA;
+ case '#': return F_DIVIDE;
+ case '$': return F_CURRENCY;
+ case '%': return F_PERCENT;
+ case '^': return F_MUL;
+ case '&': return F_BCOMMA;
+ case '*': return F_STAR;
+ case '(': return F_LPARENT;
+ case ')': return F_RPARENT;
+ case '-': return F_MINUS;
+ case '_': return F_UNDERLINE;
+ case '=': return F_EQUALS;
+ case '+': return F_PLUS;
+ case '\\': return F_BSLASH;
+ case '|': return F_PIPE;
+ case ':': return F_DCOLON;
+ case '"': return F_SEMICOLON;
+ case '.': return F_PERIOD;
+ case '/': return F_SLASH;
+ case '<': return F_LESS;
+ case '>': return F_GREATER;
+ case '?': return F_QUESTION;
+ case ' ': return F_BLANK;
+ }
+
+ break;
+
+ case 'a': return _SHIN;
+ case 'A': return WAW_H;
+ case 'b': return ZAL;
+ case 'c': return ZE;
+ case 'C': return JE;
+ case 'd': return _YE;
+ case 'D': return _YEE;
+ case 'e': return _SE;
+ case 'f': return _BE;
+ case 'g': return _LAM;
+ case 'G':
+ if (cmd_gchar(AT_CURSOR) == _LAM)
+ {
+ cmd_pchar(LAM, AT_CURSOR);
+ return ALEF_U_H;
+ }
+
+ if (F_is_TyB_TyC_TyD(SRC_CMD, AT_CURSOR))
+ return ALEF_U_H_;
+ else
+ return ALEF_U_H;
+ case 'h':
+ if (cmd_gchar(AT_CURSOR) == _LAM)
+ {
+ cmd_pchar(LA, AT_CURSOR);
+ redrawcmdline();
+ return K_IGNORE;
+ }
+
+ if (F_is_TyB_TyC_TyD(SRC_CMD, AT_CURSOR))
+ return ALEF_;
+ else
+ return ALEF;
+ case 'i':
+ if (F_is_TyB_TyC_TyD(SRC_CMD, AT_CURSOR))
+ return _HE_;
+ else
+ return _HE;
+ case 'j': return _TE;
+ case 'J':
+ if (F_is_TyB_TyC_TyD(SRC_CMD, AT_CURSOR))
+ return TEE_;
+ else
+ return TEE;
+ case 'k': return _NOON;
+ case 'l': return _MIM;
+ case 'm': return _PE;
+ case 'n':
+ case 'N': return DAL;
+ case 'o': return _XE;
+ case 'p': return _HE_J;
+ case 'q': return _ZAD;
+ case 'r': return _GHAF;
+ case 's': return _SIN;
+ case 'S': return _IE;
+ case 't': return _FE;
+ case 'u':
+ if (F_is_TyB_TyC_TyD(SRC_CMD, AT_CURSOR))
+ return _AYN_;
+ else
+ return _AYN;
+ case 'v':
+ case 'V': return RE;
+ case 'w': return _SAD;
+ case 'x':
+ case 'X': return _TA;
+ case 'y':
+ if (F_is_TyB_TyC_TyD(SRC_CMD, AT_CURSOR))
+ return _GHAYN_;
+ else
+ return _GHAYN;
+ case 'z':
+ case 'Z': return _ZA;
+ case ';': return _KAF;
+ case '\'': return _GAF;
+ case ',': return WAW;
+ case '[': return _JIM;
+ case ']': return _CHE;
+ }
+
+ return c;
+}
+
+/*
+ * F_isalpha returns TRUE if 'c' is a Farsi alphabet
+ */
+ int
+F_isalpha(int c)
+{
+ return ((c >= TEE_ && c <= _YE)
+ || (c >= ALEF_A && c <= YE)
+ || (c >= _IE && c <= YE_));
+}
+
+/*
+ * F_isdigit returns TRUE if 'c' is a Farsi digit
+ */
+ int
+F_isdigit(int c)
+{
+ return (c >= FARSI_0 && c <= FARSI_9);
+}
+
+/*
+ * F_ischar returns TRUE if 'c' is a Farsi character.
+ */
+ int
+F_ischar(int c)
+{
+ return (c >= TEE_ && c <= YE_);
+}
+
+ void
+farsi_f8(cmdarg_T *cap UNUSED)
+{
+ if (p_altkeymap)
+ {
+ if (curwin->w_farsi & W_R_L)
+ {
+ p_fkmap = 0;
+ do_cmdline_cmd((char_u *)"set norl");
+ msg("");
+ }
+ else
+ {
+ p_fkmap = 1;
+ do_cmdline_cmd((char_u *)"set rl");
+ msg("");
+ }
+
+ curwin->w_farsi = curwin->w_farsi ^ W_R_L;
+ }
+}
+
+ void
+farsi_f9(cmdarg_T *cap UNUSED)
+{
+ if (p_altkeymap && curwin->w_p_rl)
+ {
+ curwin->w_farsi = curwin->w_farsi ^ W_CONV;
+ if (curwin->w_farsi & W_CONV)
+ conv_to_pvim();
+ else
+ conv_to_pstd();
+ }
+}
+
+#endif /* FEAT_FKMAP */
diff --git a/src/farsi.h b/src/farsi.h
new file mode 100644
index 0000000..e91bdf7
--- /dev/null
+++ b/src/farsi.h
@@ -0,0 +1,234 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * Do ":help uganda" in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ */
+
+/*
+ * Farsi characters are categorized into following types:
+ *
+ * TyA (for capital letter representation)
+ * TyB (for types that look like _X e.g. AYN)
+ * TyC (for types that look like X_ e.g. YE_)
+ * TyD (for types that look like _X_ e.g. _AYN_)
+ * TyE (for types that look like X e.g. RE)
+ */
+
+/*
+ * Farsi character set definition
+ */
+
+/*
+ * Begin of the non-standard part
+ */
+
+#define TEE_ 0x80
+#define ALEF_U_H_ 0x81
+#define ALEF_ 0x82
+#define _BE 0x83
+#define _PE 0x84
+#define _TE 0x85
+#define _SE 0x86
+#define _JIM 0x87
+#define _CHE 0x88
+#define _HE_J 0x89
+#define _XE 0x8a
+#define _SIN 0x8b
+#define _SHIN 0x8c
+#define _SAD 0x8d
+#define _ZAD 0x8e
+#define _AYN 0x8f
+#define _AYN_ 0x90
+#define AYN_ 0x91
+#define _GHAYN 0x92
+#define _GHAYN_ 0x93
+#define GHAYN_ 0x94
+#define _FE 0x95
+#define _GHAF 0x96
+#define _KAF 0x97
+#define _GAF 0x98
+#define _LAM 0x99
+#define LA 0x9a
+#define _MIM 0x9b
+#define _NOON 0x9c
+#define _HE 0x9d
+#define _HE_ 0x9e
+#define _YE 0x9f
+#define _IE 0xec
+#define IE_ 0xed
+#define IE 0xfb
+#define _YEE 0xee
+#define YEE_ 0xef
+#define YE_ 0xff
+
+/*
+ * End of the non-standard part
+ */
+
+/*
+ * Standard part
+ */
+
+#define F_BLANK 0xa0 /* Farsi ' ' (SP) character */
+#define F_PSP 0xa1 /* PSP for capitalizing of a character */
+#define F_PCN 0xa2 /* PCN for redefining of the hamye meaning */
+#define F_EXCL 0xa3 /* Farsi ! character */
+#define F_CURRENCY 0xa4 /* Farsi Rial character */
+#define F_PERCENT 0xa5 /* Farsi % character */
+#define F_PERIOD 0xa6 /* Farsi '.' character */
+#define F_COMMA 0xa7 /* Farsi ',' character */
+#define F_LPARENT 0xa8 /* Farsi '(' character */
+#define F_RPARENT 0xa9 /* Farsi ')' character */
+#define F_MUL 0xaa /* Farsi 'x' character */
+#define F_PLUS 0xab /* Farsi '+' character */
+#define F_BCOMMA 0xac /* Farsi comma character */
+#define F_MINUS 0xad /* Farsi '-' character */
+#define F_DIVIDE 0xae /* Farsi divide (/) character */
+#define F_SLASH 0xaf /* Farsi '/' character */
+
+#define FARSI_0 0xb0
+#define FARSI_1 0xb1
+#define FARSI_2 0xb2
+#define FARSI_3 0xb3
+#define FARSI_4 0xb4
+#define FARSI_5 0xb5
+#define FARSI_6 0xb6
+#define FARSI_7 0xb7
+#define FARSI_8 0xb8
+#define FARSI_9 0xb9
+
+#define F_DCOLON 0xba /* Farsi ':' character */
+#define F_SEMICOLON 0xbb /* Farsi ';' character */
+#define F_GREATER 0xbc /* Farsi '>' character */
+#define F_EQUALS 0xbd /* Farsi '=' character */
+#define F_LESS 0xbe /* Farsi '<' character */
+#define F_QUESTION 0xbf /* Farsi ? character */
+
+#define ALEF_A 0xc0
+#define ALEF 0xc1
+#define HAMZE 0xc2
+#define BE 0xc3
+#define PE 0xc4
+#define TE 0xc5
+#define SE 0xc6
+#define JIM 0xc7
+#define CHE 0xc8
+#define HE_J 0xc9
+#define XE 0xca
+#define DAL 0xcb
+#define ZAL 0xcc
+#define RE 0xcd
+#define ZE 0xce
+#define JE 0xcf
+#define SIN 0xd0
+#define SHIN 0xd1
+#define SAD 0xd2
+#define ZAD 0xd3
+#define _TA 0xd4
+#define _ZA 0xd5
+#define AYN 0xd6
+#define GHAYN 0xd7
+#define FE 0xd8
+#define GHAF 0xd9
+#define KAF 0xda
+#define GAF 0xdb
+#define LAM 0xdc
+#define MIM 0xdd
+#define NOON 0xde
+#define WAW 0xdf
+#define F_HE 0xe0 /* F_ added for name clash with Perl */
+#define YE 0xe1
+#define TEE 0xfc
+#define _KAF_H 0xfd
+#define YEE 0xfe
+
+#define F_LBRACK 0xe2 /* Farsi '[' character */
+#define F_RBRACK 0xe3 /* Farsi ']' character */
+#define F_LBRACE 0xe4 /* Farsi '{' character */
+#define F_RBRACE 0xe5 /* Farsi '}' character */
+#define F_LQUOT 0xe6 /* Farsi left quotation character */
+#define F_RQUOT 0xe7 /* Farsi right quotation character */
+#define F_STAR 0xe8 /* Farsi '*' character */
+#define F_UNDERLINE 0xe9 /* Farsi '_' character */
+#define F_PIPE 0xea /* Farsi '|' character */
+#define F_BSLASH 0xeb /* Farsi '\' character */
+
+#define MAD 0xf0
+#define JAZR 0xf1
+#define OW 0xf2
+#define MAD_N 0xf3
+#define JAZR_N 0xf4
+#define OW_OW 0xf5
+#define TASH 0xf6
+#define OO 0xf7
+#define ALEF_U_H 0xf8
+#define WAW_H 0xf9
+#define ALEF_D_H 0xfa
+
+/*
+ * global definitions
+ * ==================
+ */
+
+#define SRC_EDT 0
+#define SRC_CMD 1
+
+#define AT_CURSOR 0
+
+/*
+ * definitions for the window dependent functions (w_farsi).
+ */
+#define W_CONV 0x1
+#define W_R_L 0x2
+
+
+/* special Farsi text messages */
+
+EXTERN char farsi_text_1[]
+#ifdef DO_INIT
+ = { YE_, _SIN, RE, ALEF_, _FE, ' ', 'V', 'I', 'M',
+ ' ', F_HE, _BE, ' ', SHIN, RE, _GAF, DAL,' ', NOON,
+ ALEF_, _YE, ALEF_, _PE, '\0'}
+#endif
+ ;
+
+EXTERN char farsi_text_2[]
+#ifdef DO_INIT
+ = { YE_, _SIN, RE, ALEF_, _FE, ' ', FARSI_3, FARSI_3,
+ FARSI_4, FARSI_2, ' ', DAL, RE, ALEF, DAL, _NOON,
+ ALEF_, _TE, _SIN, ALEF, ' ', F_HE, _BE, ' ', SHIN,
+ RE, _GAF, DAL, ' ', NOON, ALEF_, _YE, ALEF_, _PE, '\0'}
+#endif
+ ;
+
+EXTERN char farsi_text_3[]
+#ifdef DO_INIT
+ = { DAL, WAW, _SHIN, _YE, _MIM, _NOON, ' ', YE_, _NOON,
+ ALEF_,_BE, _YE, _TE, _SHIN, _PE, ' ', 'R','E','P','L',
+ 'A','C','E', ' ', NOON, ALEF_, _MIM, RE, _FE, ZE, ALEF,
+ ' ', 'R', 'E', 'V', 'E', 'R', 'S', 'E', ' ', 'I', 'N',
+ 'S', 'E', 'R', 'T', ' ', SHIN, WAW, RE, ' ', ALEF_, _BE,
+ ' ', YE_, _SIN, RE, ALEF_, _FE, ' ', RE, DAL, ' ', RE,
+ ALEF_, _KAF,' ', MIM, ALEF_, _GAF, _NOON, _HE, '\0'}
+#endif
+ ;
+
+#if 0 /* not used */
+EXTERN char_u farsi_text_4[]
+#ifdef DO_INIT
+ = { DAL, WAW, _SHIN, _YE, _MIM, _NOON, ' ', YE_, _NOON,
+ ALEF_, _BE, _YE, _TE, _SHIN, _PE, ' ', '<', 'C','T','R',
+ 'L','-','B','>', ' ', NOON, ALEF_, _MIM, RE, _FE, ZE,
+ ALEF, ' ', YE_, _SIN, RE, ALEF_, _FE, ' ', RE, DAL, ' ',
+ RE, ALEF_, _KAF,' ', MIM, ALEF_, _GAF, _NOON, _HE, '\0'}
+#endif
+ ;
+#endif
+
+EXTERN char farsi_text_5[]
+#ifdef DO_INIT
+ = { ' ', YE_, _SIN, RE, ALEF_, _FE, '\0'}
+#endif
+ ;
diff --git a/src/feature.h b/src/feature.h
new file mode 100644
index 0000000..a41e79f
--- /dev/null
+++ b/src/feature.h
@@ -0,0 +1,1352 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * Do ":help uganda" in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ */
+/*
+ * feature.h: Defines for optional code and preferences
+ *
+ * Edit this file to include/exclude parts of Vim, before compiling.
+ * The only other file that may be edited is Makefile, it contains machine
+ * specific options.
+ *
+ * To include specific options, change the "#if*" and "#endif" into comments,
+ * or uncomment the "#define".
+ * To exclude specific options, change the "#define" into a comment.
+ */
+
+/*
+ * When adding a new feature:
+ * - Add a #define below.
+ * - Add a message in the table above ex_version().
+ * - Add a string to f_has().
+ * - Add a feature to ":help feature-list" in doc/eval.txt.
+ * - Add feature to ":help +feature-list" in doc/various.txt.
+ * - Add comment for the documentation of commands that use the feature.
+ */
+
+/*
+ * Basic choices:
+ * ==============
+ *
+ * +tiny almost no features enabled, not even multiple windows
+ * +small few features enabled, as basic as possible
+ * +normal A default selection of features enabled
+ * +big many features enabled, as rich as possible.
+ * +huge all possible features enabled.
+ *
+ * When +small is used, +tiny is also included. +normal implies +small, etc.
+ */
+
+/*
+ * Uncomment one of these to override the default. For unix use a configure
+ * argument, see Makefile.
+ */
+#if !defined(FEAT_TINY) && !defined(FEAT_SMALL) && !defined(FEAT_NORMAL) \
+ && !defined(FEAT_BIG) && !defined(FEAT_HUGE)
+/* #define FEAT_TINY */
+/* #define FEAT_SMALL */
+/* #define FEAT_NORMAL */
+/* #define FEAT_BIG */
+/* #define FEAT_HUGE */
+#endif
+
+/*
+ * For Unix, Mac and Win32 use +huge by default. These days CPUs are fast and
+ * Memory is cheap.
+ * Use +big for older systems: Other MS-Windows and VMS.
+ * Otherwise use +normal
+ */
+#if !defined(FEAT_TINY) && !defined(FEAT_SMALL) && !defined(FEAT_NORMAL) \
+ && !defined(FEAT_BIG) && !defined(FEAT_HUGE)
+# if defined(UNIX) || defined(WIN3264) || defined(MACOS_X)
+# define FEAT_HUGE
+# else
+# if defined(MSWIN) || defined(VMS) || defined(AMIGA)
+# define FEAT_BIG
+# else
+# define FEAT_NORMAL
+# endif
+# endif
+#endif
+
+/*
+ * Each feature implies including the "smaller" ones.
+ */
+#ifdef FEAT_HUGE
+# define FEAT_BIG
+#endif
+#ifdef FEAT_BIG
+# define FEAT_NORMAL
+#endif
+#ifdef FEAT_NORMAL
+# define FEAT_SMALL
+#endif
+#ifdef FEAT_SMALL
+# define FEAT_TINY
+#endif
+
+/*
+ * Optional code (see ":help +feature-list")
+ * =============
+ */
+
+/*
+ * These features used to be optional but are now always enabled.
+ * +windows Multiple windows. Without this there is no help
+ * window and no status lines.
+ * +vertsplit Vertically split windows.
+ */
+
+/*
+ * +cmdhist Command line history.
+ */
+#ifdef FEAT_SMALL
+# define FEAT_CMDHIST
+#endif
+
+/*
+ * Message history is fixed at 200 message, 20 for the tiny version.
+ */
+#ifdef FEAT_SMALL
+# define MAX_MSG_HIST_LEN 200
+#else
+# define MAX_MSG_HIST_LEN 20
+#endif
+
+/*
+ * +jumplist Jumplist, CTRL-O and CTRL-I commands.
+ */
+#ifdef FEAT_SMALL
+# define FEAT_JUMPLIST
+#endif
+
+/* the cmdline-window requires FEAT_CMDHIST */
+#if defined(FEAT_CMDHIST)
+# define FEAT_CMDWIN
+#endif
+
+/*
+ * +folding Fold lines.
+ */
+#ifdef FEAT_NORMAL
+# define FEAT_FOLDING
+#endif
+
+/*
+ * +digraphs Digraphs.
+ * In insert mode and on the command line you will be
+ * able to use digraphs. The CTRL-K command will work.
+ * Define OLD_DIGRAPHS to get digraphs compatible with
+ * Vim 5.x. The new ones are from RFC 1345.
+ */
+#ifdef FEAT_NORMAL
+# define FEAT_DIGRAPHS
+/* #define OLD_DIGRAPHS */
+#endif
+
+/*
+ * +langmap 'langmap' option. Only useful when you put your
+ * keyboard in a special language mode, e.g. for typing
+ * greek.
+ */
+#ifdef FEAT_BIG
+# define FEAT_LANGMAP
+#endif
+
+/*
+ * +keymap 'keymap' option. Allows you to map typed keys in
+ * Insert mode for a special language.
+ */
+#ifdef FEAT_BIG
+# define FEAT_KEYMAP
+#endif
+
+/*
+ * +localmap Mappings and abbreviations local to a buffer.
+ */
+#ifdef FEAT_NORMAL
+# define FEAT_LOCALMAP
+#endif
+
+/*
+ * +insert_expand CTRL-N/CTRL-P/CTRL-X in insert mode. Takes about
+ * 4Kbyte of code.
+ */
+#ifdef FEAT_NORMAL
+# define FEAT_INS_EXPAND
+#endif
+
+/*
+ * +cmdline_compl completion of mappings/abbreviations in cmdline mode.
+ * Takes a few Kbyte of code.
+ */
+#ifdef FEAT_NORMAL
+# define FEAT_CMDL_COMPL
+#endif
+
+#ifdef FEAT_NORMAL
+# define VIM_BACKTICK /* internal backtick expansion */
+#endif
+
+/*
+ * +visual Visual mode - now always included.
+ * +visualextra Extra features for Visual mode (mostly block operators).
+ * Now always included.
+ */
+
+/*
+ * +virtualedit 'virtualedit' option and its implementation
+ * Now always included.
+ */
+
+/*
+ * +cmdline_info 'showcmd' and 'ruler' options.
+ */
+#ifdef FEAT_NORMAL
+# define FEAT_CMDL_INFO
+#endif
+
+/*
+ * +linebreak 'showbreak', 'breakat' and 'linebreak' options.
+ * Also 'numberwidth'.
+ */
+#ifdef FEAT_NORMAL
+# define FEAT_LINEBREAK
+#endif
+
+/*
+ * +extra_search 'hlsearch' and 'incsearch' options.
+ */
+#ifdef FEAT_NORMAL
+# define FEAT_SEARCH_EXTRA
+#endif
+
+/*
+ * +quickfix Quickfix commands.
+ */
+#ifdef FEAT_NORMAL
+# define FEAT_QUICKFIX
+#endif
+
+/*
+ * +file_in_path "gf" and "<cfile>" commands.
+ */
+#ifdef FEAT_NORMAL
+# define FEAT_SEARCHPATH
+#endif
+
+/*
+ * +find_in_path "[I" ":isearch" "^W^I", ":checkpath", etc.
+ */
+#ifdef FEAT_NORMAL
+# ifdef FEAT_SEARCHPATH /* FEAT_SEARCHPATH is required */
+# define FEAT_FIND_ID
+# endif
+#endif
+
+/*
+ * +path_extra up/downwards searching in 'path' and 'tags'.
+ */
+#ifdef FEAT_NORMAL
+# define FEAT_PATH_EXTRA
+#endif
+
+/*
+ * +rightleft Right-to-left editing/typing support.
+ *
+ * Disabled for EBCDIC as it requires multibyte.
+ */
+#if defined(FEAT_BIG) && !defined(DISABLE_RIGHTLEFT) && !defined(EBCDIC)
+# define FEAT_RIGHTLEFT
+#endif
+
+/*
+ * +farsi Farsi (Persian language) Keymap support.
+ * Requires FEAT_RIGHTLEFT.
+ *
+ * Disabled for EBCDIC as it requires multibyte.
+ */
+#if defined(FEAT_BIG) && !defined(DISABLE_FARSI) && !defined(EBCDIC)
+# define FEAT_FKMAP
+#endif
+#ifdef FEAT_FKMAP
+# ifndef FEAT_RIGHTLEFT
+# define FEAT_RIGHTLEFT
+# endif
+#endif
+
+/*
+ * +arabic Arabic keymap and shaping support.
+ * Requires FEAT_RIGHTLEFT
+ *
+ * Disabled for EBCDIC as it requires multibyte.
+ */
+#if defined(FEAT_BIG) && !defined(DISABLE_ARABIC) && !defined(EBCDIC)
+# define FEAT_ARABIC
+#endif
+#ifdef FEAT_ARABIC
+# ifndef FEAT_RIGHTLEFT
+# define FEAT_RIGHTLEFT
+# endif
+#endif
+
+/*
+ * +emacs_tags When FEAT_EMACS_TAGS defined: Include support for
+ * emacs style TAGS file.
+ */
+#ifdef FEAT_BIG
+# define FEAT_EMACS_TAGS
+#endif
+
+/*
+ * +tag_binary Can use a binary search for the tags file.
+ *
+ * Disabled for EBCDIC:
+ * On z/OS Unix we have the problem that /bin/sort sorts ASCII instead of
+ * EBCDIC. With this binary search doesn't work, as VIM expects a tag file
+ * sorted by character values. I'm not sure how to fix this. Should we really
+ * do a EBCDIC to ASCII conversion for this??
+ */
+#if !defined(EBCDIC)
+# define FEAT_TAG_BINS
+#endif
+
+/*
+ * +tag_old_static Old style static tags: "file:tag file ..". Slows
+ * down tag searching a bit.
+ */
+#ifdef FEAT_NORMAL
+# define FEAT_TAG_OLDSTATIC
+#endif
+
+/*
+ * +tag_any_white Allow any white space to separate the fields in a tags
+ * file. When not defined, only a TAB is allowed.
+ */
+/* #define FEAT_TAG_ANYWHITE */
+
+/*
+ * +cscope Unix only: Cscope support.
+ */
+#if defined(UNIX) && defined(FEAT_BIG) && !defined(FEAT_CSCOPE) && !defined(MACOS_X)
+# define FEAT_CSCOPE
+#endif
+
+/*
+ * +eval Built-in script language and expression evaluation,
+ * ":let", ":if", etc.
+ * +float Floating point variables.
+ * +num64 64-bit Number.
+ */
+#ifdef FEAT_NORMAL
+# define FEAT_EVAL
+# if defined(HAVE_FLOAT_FUNCS) || defined(WIN3264) || defined(MACOS_X)
+# define FEAT_FLOAT
+# endif
+# if defined(HAVE_STDINT_H) || defined(WIN3264) || (VIM_SIZEOF_LONG >= 8)
+# define FEAT_NUM64
+# endif
+#endif
+
+#ifdef FEAT_EVAL
+# define HAVE_SANDBOX
+#endif
+
+/*
+ * +profile Profiling for functions and scripts.
+ */
+#if defined(FEAT_HUGE) \
+ && defined(FEAT_EVAL) \
+ && ((defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)) \
+ || defined(WIN3264))
+# define FEAT_PROFILE
+#endif
+
+/*
+ * +reltime reltime() function
+ */
+#if defined(FEAT_NORMAL) \
+ && defined(FEAT_EVAL) \
+ && ((defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)) \
+ || defined(WIN3264))
+# define FEAT_RELTIME
+#endif
+
+/*
+ * +timers timer_start()
+ */
+#if defined(FEAT_RELTIME) && (defined(UNIX) || defined(WIN32) || defined(VMS) )
+# define FEAT_TIMERS
+#endif
+
+/*
+ * +textobjects Text objects: "vaw", "das", etc.
+ */
+#if defined(FEAT_NORMAL) && defined(FEAT_EVAL)
+# define FEAT_TEXTOBJ
+#endif
+
+/*
+ * Insert mode completion with 'completefunc'.
+ */
+#if defined(FEAT_INS_EXPAND) && defined(FEAT_EVAL)
+# define FEAT_COMPL_FUNC
+#endif
+
+/*
+ * +user_commands Allow the user to define his own commands.
+ */
+#ifdef FEAT_NORMAL
+# define FEAT_USR_CMDS
+#endif
+
+/*
+ * +printer ":hardcopy" command
+ * +postscript Printing uses PostScript file output.
+ */
+#if defined(FEAT_NORMAL) && (defined(MSWIN) || defined(FEAT_EVAL)) \
+ && !defined(AMIGA)
+# define FEAT_PRINTER
+#endif
+#if defined(FEAT_PRINTER) && ((defined(MSWIN) && defined(MSWINPS)) \
+ || (!defined(MSWIN) && defined(FEAT_EVAL)))
+# define FEAT_POSTSCRIPT
+#endif
+
+/*
+ * +modify_fname modifiers for file name. E.g., "%:p:h".
+ */
+#ifdef FEAT_NORMAL
+# define FEAT_MODIFY_FNAME
+#endif
+
+/*
+ * +diff Displaying diffs in a nice way.
+ * Requires +windows and +autocmd.
+ */
+#if defined(FEAT_NORMAL)
+# define FEAT_DIFF
+#endif
+
+/*
+ * +title 'title' and 'icon' options
+ * +statusline 'statusline', 'rulerformat' and special format of
+ * 'titlestring' and 'iconstring' options.
+ * +byte_offset '%o' in 'statusline' and builtin functions line2byte()
+ * and byte2line().
+ * Note: Required for Macintosh.
+ */
+#if defined(FEAT_NORMAL)
+# define FEAT_TITLE
+#endif
+
+#ifdef FEAT_NORMAL
+# define FEAT_STL_OPT
+# ifndef FEAT_CMDL_INFO
+# define FEAT_CMDL_INFO /* 'ruler' is required for 'statusline' */
+# endif
+#endif
+
+#ifdef FEAT_NORMAL
+# define FEAT_BYTEOFF
+#endif
+
+/*
+ * +wildignore 'wildignore' and 'backupskip' options
+ * Needed for Unix to make "crontab -e" work.
+ */
+#if defined(FEAT_NORMAL) || defined(UNIX)
+# define FEAT_WILDIGN
+#endif
+
+/*
+ * +wildmenu 'wildmenu' option
+ */
+#if defined(FEAT_NORMAL)
+# define FEAT_WILDMENU
+#endif
+
+/*
+ * +viminfo reading/writing the viminfo file. Takes about 8Kbyte
+ * of code.
+ * VIMINFO_FILE Location of user .viminfo file (should start with $).
+ * VIMINFO_FILE2 Location of alternate user .viminfo file.
+ */
+#ifdef FEAT_NORMAL
+# define FEAT_VIMINFO
+/* #define VIMINFO_FILE "$HOME/foo/.viminfo" */
+/* #define VIMINFO_FILE2 "~/bar/.viminfo" */
+#endif
+
+/*
+ * +syntax syntax highlighting. When using this, it's a good
+ * idea to have +autocmd and +eval too.
+ */
+#if defined(FEAT_NORMAL) || defined(PROTO)
+# define FEAT_SYN_HL
+#endif
+
+/*
+ * +conceal 'conceal' option. Needs syntax highlighting
+ * as this is how the concealed text is defined.
+ */
+#if defined(FEAT_BIG) && defined(FEAT_SYN_HL)
+# define FEAT_CONCEAL
+#endif
+
+/*
+ * +textprop Text properties
+ */
+#if defined(FEAT_EVAL) && defined(FEAT_SYN_HL)
+# define FEAT_TEXT_PROP
+#endif
+
+/*
+ * +spell spell checking
+ *
+ * Disabled for EBCDIC: * Doesn't work (SIGSEGV).
+ */
+#if (defined(FEAT_NORMAL) || defined(PROTO)) && !defined(EBCDIC)
+# define FEAT_SPELL
+#endif
+
+/*
+ * +builtin_terms Choose one out of the following four:
+ *
+ * NO_BUILTIN_TCAPS Do not include any builtin termcap entries (used only
+ * with HAVE_TGETENT defined).
+ *
+ * (nothing) Machine specific termcap entries will be included.
+ *
+ * SOME_BUILTIN_TCAPS Include most useful builtin termcap entries (used only
+ * with NO_BUILTIN_TCAPS not defined).
+ * This is the default.
+ *
+ * ALL_BUILTIN_TCAPS Include all builtin termcap entries
+ * (used only with NO_BUILTIN_TCAPS not defined).
+ */
+#ifdef HAVE_TGETENT
+/* #define NO_BUILTIN_TCAPS */
+#endif
+
+#if !defined(NO_BUILTIN_TCAPS)
+# ifdef FEAT_BIG
+# define ALL_BUILTIN_TCAPS
+# else
+# define SOME_BUILTIN_TCAPS /* default */
+# endif
+#endif
+
+/*
+ * +lispindent lisp indenting (From Eric Fischer).
+ * +cindent C code indenting (From Eric Fischer).
+ * +smartindent smart C code indenting when the 'si' option is set.
+ *
+ * These two need to be defined when making prototypes.
+ */
+#if defined(FEAT_NORMAL) || defined(PROTO)
+# define FEAT_LISP
+#endif
+
+#if defined(FEAT_NORMAL) || defined(PROTO)
+# define FEAT_CINDENT
+#endif
+
+#ifdef FEAT_NORMAL
+# define FEAT_SMARTINDENT
+#endif
+
+/*
+ * +comments 'comments' option.
+ */
+#ifdef FEAT_NORMAL
+# define FEAT_COMMENTS
+#endif
+
+/*
+ * +cryptv Encryption (by Mohsin Ahmed <mosh@sasi.com>).
+ */
+#if defined(FEAT_NORMAL) && !defined(FEAT_CRYPT) || defined(PROTO)
+# define FEAT_CRYPT
+#endif
+
+/*
+ * +mksession ":mksession" command.
+ * Requires +windows and +vertsplit.
+ */
+#if defined(FEAT_NORMAL)
+# define FEAT_SESSION
+#endif
+
+/*
+ * +multi_lang Multi language support. ":menutrans", ":language", etc.
+ * +gettext Message translations (requires +multi_lang)
+ * (only when "lang" archive unpacked)
+ */
+#ifdef FEAT_NORMAL
+# define FEAT_MULTI_LANG
+#endif
+#if defined(HAVE_GETTEXT) && defined(FEAT_MULTI_LANG) \
+ && (defined(HAVE_LOCALE_H) || defined(X_LOCALE))
+# define FEAT_GETTEXT
+#endif
+
+/*
+ * +multi_byte Generic multi-byte character handling.
+ * Now always enabled.
+ */
+
+/*
+ * +multi_byte_ime Win32 IME input method. Only for far-east Windows, so
+ * IME can be used to input chars. Not tested much!
+ */
+#if defined(FEAT_GUI_W32) && !defined(FEAT_MBYTE_IME)
+/* #define FEAT_MBYTE_IME */
+# endif
+
+/* Use iconv() when it's available. */
+#if (defined(HAVE_ICONV_H) && defined(HAVE_ICONV)) || defined(DYNAMIC_ICONV)
+# define USE_ICONV
+#endif
+
+/*
+ * +xim X Input Method. For entering special languages like
+ * chinese and Japanese.
+ * +hangul_input Internal Hangul input method. Must be included
+ * through configure: "--enable-hangulin"
+ * Both are for Unix and VMS only.
+ */
+#ifndef FEAT_XIM
+/* #define FEAT_XIM */
+#endif
+
+#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
+# define USE_XIM 1 /* needed for GTK include files */
+#endif
+
+#ifdef FEAT_HANGULIN
+# define HANGUL_DEFAULT_KEYBOARD 2 /* 2 or 3 bulsik keyboard */
+# define ESC_CHG_TO_ENG_MODE /* if defined, when ESC pressed,
+ * turn to english mode
+ */
+# if defined(FEAT_XIM) && !defined(LINT)
+ Error: You should select only ONE of XIM and HANGUL INPUT
+# endif
+#endif
+#if defined(FEAT_HANGULIN) || defined(FEAT_XIM)
+/* # define X_LOCALE */ /* for OS with incomplete locale
+ support, like old linux versions. */
+#endif
+
+/*
+ * +xfontset X fontset support. For outputting wide characters.
+ */
+#ifndef FEAT_XFONTSET
+# if defined(HAVE_X11) && !defined(FEAT_GUI_GTK)
+# define FEAT_XFONTSET
+# else
+/* # define FEAT_XFONTSET */
+# endif
+#endif
+
+/*
+ * +libcall libcall() function
+ */
+/* Using dlopen() also requires dlsym() to be available. */
+#if defined(HAVE_DLOPEN) && defined(HAVE_DLSYM)
+# define USE_DLOPEN
+#endif
+#if defined(FEAT_EVAL) && (defined(WIN3264) || ((defined(UNIX) || defined(VMS)) \
+ && (defined(USE_DLOPEN) || defined(HAVE_SHL_LOAD))))
+# define FEAT_LIBCALL
+#endif
+
+/*
+ * +menu ":menu" command
+ */
+#ifdef FEAT_NORMAL
+# define FEAT_MENU
+# ifdef FEAT_GUI_W32
+# define FEAT_TEAROFF
+# endif
+#endif
+
+/*
+ * popup menu in a terminal
+ */
+#if defined(FEAT_MENU) && !defined(ALWAYS_USE_GUI) && defined(FEAT_INS_EXPAND)
+# define FEAT_TERM_POPUP_MENU
+#endif
+
+/* There are two ways to use XPM. */
+#if (defined(HAVE_XM_XPMP_H) && defined(FEAT_GUI_MOTIF)) \
+ || defined(HAVE_X11_XPM_H)
+# define HAVE_XPM 1
+#endif
+
+/*
+ * +toolbar Include code for a toolbar (for the Win32 GUI, GTK
+ * always has it). But only if menus are enabled.
+ */
+#if defined(FEAT_NORMAL) && defined(FEAT_MENU) \
+ && (defined(FEAT_GUI_GTK) \
+ || defined(FEAT_GUI_MSWIN) \
+ || ((defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA)) \
+ && defined(HAVE_XPM)) \
+ || defined(FEAT_GUI_PHOTON))
+# define FEAT_TOOLBAR
+#endif
+
+
+#if defined(FEAT_TOOLBAR) && !defined(FEAT_MENU)
+# define FEAT_MENU
+#endif
+
+/*
+ * GUI tabline
+ */
+#if defined(FEAT_NORMAL) \
+ && (defined(FEAT_GUI_GTK) \
+ || (defined(FEAT_GUI_MOTIF) && defined(HAVE_XM_NOTEBOOK_H)) \
+ || defined(FEAT_GUI_MAC) \
+ || (defined(FEAT_GUI_MSWIN) \
+ && (!defined(_MSC_VER) || _MSC_VER > 1020)))
+# define FEAT_GUI_TABLINE
+#endif
+
+/*
+ * +browse ":browse" command.
+ * or just the ":browse" command modifier
+ */
+#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_PHOTON) || defined(FEAT_GUI_MAC)
+# define FEAT_BROWSE
+# endif
+#endif
+
+/*
+ * On some systems, when we compile with the GUI, we always use it. On Mac
+ * 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(FEAT_GUI_MAC) && !defined(MACOS_X_DARWIN))
+# define ALWAYS_USE_GUI
+#endif
+
+/*
+ * +dialog_gui Use GUI dialog.
+ * +dialog_con May use Console dialog.
+ * When none of these defined there is no dialog support.
+ */
+#ifdef FEAT_NORMAL
+# if ((defined(FEAT_GUI_ATHENA) || defined(FEAT_GUI_MOTIF)) \
+ && defined(HAVE_X11_XPM_H)) \
+ || defined(FEAT_GUI_GTK) \
+ || defined(FEAT_GUI_PHOTON) \
+ || defined(FEAT_GUI_MSWIN) \
+ || defined(FEAT_GUI_MAC)
+# define FEAT_CON_DIALOG
+# define FEAT_GUI_DIALOG
+# else
+# define FEAT_CON_DIALOG
+# endif
+#endif
+#if !defined(FEAT_GUI_DIALOG) && (defined(FEAT_GUI_MOTIF) \
+ || defined(FEAT_GUI_ATHENA) || defined(FEAT_GUI_GTK) \
+ || defined(FEAT_GUI_W32))
+/* need a dialog to show error messages when starting from the desktop */
+# define FEAT_GUI_DIALOG
+#endif
+#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))
+# define FEAT_GUI_TEXTDIALOG
+# ifndef ALWAYS_USE_GUI
+# define FEAT_CON_DIALOG
+# endif
+#endif
+
+/*
+ * +termguicolors 'termguicolors' option.
+ */
+#if (defined(FEAT_BIG) && defined(FEAT_SYN_HL)) && !defined(ALWAYS_USE_GUI)
+# define FEAT_TERMGUICOLORS
+#endif
+
+/* Mac specific thing: Codewarrior interface. */
+#ifdef FEAT_GUI_MAC
+# define FEAT_CW_EDITOR
+#endif
+
+/*
+ * +vartabs 'vartabstop' and 'varsofttabstop' options.
+ */
+#ifdef FEAT_BIG
+# define FEAT_VARTABS
+#endif
+
+/*
+ * Preferences:
+ * ============
+ */
+
+/*
+ * +writebackup 'writebackup' is default on:
+ * Use a backup file while overwriting a file. But it's
+ * deleted again when 'backup' is not set. Changing this
+ * is strongly discouraged: You can lose all your
+ * changes when the computer crashes while writing the
+ * file.
+ * VMS note: It does work on VMS as well, but because of
+ * version handling it does not have any purpose.
+ * Overwrite will write to the new version.
+ */
+#ifndef VMS
+# define FEAT_WRITEBACKUP
+#endif
+
+/*
+ * +xterm_save The t_ti and t_te entries for the builtin xterm will
+ * be set to save the screen when starting Vim and
+ * restoring it when exiting.
+ */
+/* #define FEAT_XTERM_SAVE */
+
+/*
+ * DEBUG Output a lot of debugging garbage.
+ */
+/* #define DEBUG */
+
+/*
+ * STARTUPTIME Time the startup process. Writes a file with
+ * timestamps.
+ */
+#if defined(FEAT_NORMAL) \
+ && ((defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)) \
+ || defined(WIN3264))
+# define STARTUPTIME 1
+#endif
+
+/*
+ * MEM_PROFILE Debugging of memory allocation and freeing.
+ */
+/* #define MEM_PROFILE */
+
+/*
+ * VIMRC_FILE Name of the .vimrc file in current dir.
+ */
+/* #define VIMRC_FILE ".vimrc" */
+
+/*
+ * EXRC_FILE Name of the .exrc file in current dir.
+ */
+/* #define EXRC_FILE ".exrc" */
+
+/*
+ * GVIMRC_FILE Name of the .gvimrc file in current dir.
+ */
+/* #define GVIMRC_FILE ".gvimrc" */
+
+/*
+ * SESSION_FILE Name of the default ":mksession" file.
+ */
+#define SESSION_FILE "Session.vim"
+
+/*
+ * USR_VIMRC_FILE Name of the user .vimrc file.
+ * USR_VIMRC_FILE2 Name of alternate user .vimrc file.
+ * USR_VIMRC_FILE3 Name of alternate user .vimrc file.
+ */
+/* #define USR_VIMRC_FILE "~/foo/.vimrc" */
+/* #define USR_VIMRC_FILE2 "~/bar/.vimrc" */
+/* #define USR_VIMRC_FILE3 "$VIM/.vimrc" */
+
+/*
+ * VIM_DEFAULTS_FILE Name of the defaults.vim script file
+ */
+/* #define VIM_DEFAULTS_FILE "$VIMRUNTIME/defaults.vim" */
+
+/*
+ * EVIM_FILE Name of the evim.vim script file
+ */
+/* #define EVIM_FILE "$VIMRUNTIME/evim.vim" */
+
+/*
+ * USR_EXRC_FILE Name of the user .exrc file.
+ * USR_EXRC_FILE2 Name of the alternate user .exrc file.
+ */
+/* #define USR_EXRC_FILE "~/foo/.exrc" */
+/* #define USR_EXRC_FILE2 "~/bar/.exrc" */
+
+/*
+ * USR_GVIMRC_FILE Name of the user .gvimrc file.
+ * USR_GVIMRC_FILE2 Name of the alternate user .gvimrc file.
+ */
+/* #define USR_GVIMRC_FILE "~/foo/.gvimrc" */
+/* #define USR_GVIMRC_FILE2 "~/bar/.gvimrc" */
+/* #define USR_GVIMRC_FILE3 "$VIM/.gvimrc" */
+
+/*
+ * SYS_VIMRC_FILE Name of the system-wide .vimrc file.
+ */
+/* #define SYS_VIMRC_FILE "/etc/vimrc" */
+
+/*
+ * SYS_GVIMRC_FILE Name of the system-wide .gvimrc file.
+ */
+/* #define SYS_GVIMRC_FILE "/etc/gvimrc" */
+
+/*
+ * DFLT_HELPFILE Name of the help file.
+ */
+/* # define DFLT_HELPFILE "$VIMRUNTIME/doc/help.txt.gz" */
+
+/*
+ * File names for:
+ * FILETYPE_FILE switch on file type detection
+ * FTPLUGIN_FILE switch on loading filetype plugin files
+ * INDENT_FILE switch on loading indent files
+ * FTOFF_FILE switch off file type detection
+ * FTPLUGOF_FILE switch off loading settings files
+ * INDOFF_FILE switch off loading indent files
+ */
+/* # define FILETYPE_FILE "filetype.vim" */
+/* # define FTPLUGIN_FILE "ftplugin.vim" */
+/* # define INDENT_FILE "indent.vim" */
+/* # define FTOFF_FILE "ftoff.vim" */
+/* # define FTPLUGOF_FILE "ftplugof.vim" */
+/* # define INDOFF_FILE "indoff.vim" */
+
+/*
+ * SYS_MENU_FILE Name of the default menu.vim file.
+ */
+/* # define SYS_MENU_FILE "$VIMRUNTIME/menu.vim" */
+
+/*
+ * SYS_OPTWIN_FILE Name of the default optwin.vim file.
+ */
+#ifndef SYS_OPTWIN_FILE
+# define SYS_OPTWIN_FILE "$VIMRUNTIME/optwin.vim"
+#endif
+
+/*
+ * SYNTAX_FNAME Name of a syntax file, where %s is the syntax name.
+ */
+/* #define SYNTAX_FNAME "/foo/%s.vim" */
+
+/*
+ * RUNTIME_DIRNAME Generic name for the directory of the runtime files.
+ */
+#ifndef RUNTIME_DIRNAME
+# define RUNTIME_DIRNAME "runtime"
+#endif
+
+/*
+ * RUNTIME_GLOBAL Comma-separated list of directory names for global Vim
+ * runtime directories.
+ * Don't define this if the preprocessor can't handle
+ * string concatenation.
+ * Also set by "--with-global-runtime" configure argument.
+ */
+/* #define RUNTIME_GLOBAL "/etc/vim" */
+
+/*
+ * RUNTIME_GLOBAL_AFTER Comma-separated list of directory names for global Vim
+ * runtime after directories.
+ * Don't define this if the preprocessor can't handle
+ * string concatenation.
+ * Also set by "--with-global-runtime" configure argument.
+ */
+/* #define RUNTIME_GLOBAL_AFTER "/etc/vim/after" */
+
+/*
+ * MODIFIED_BY Name of who modified Vim. Required when distributing
+ * a modified version of Vim.
+ * Also from the "--with-modified-by" configure argument.
+ */
+/* #define MODIFIED_BY "John Doe" */
+
+/*
+ * Machine dependent:
+ * ==================
+ */
+
+/*
+ * +fork Unix only: fork() support (detected by configure)
+ * +system Use system() instead of fork/exec for starting a
+ * shell. Doesn't work for the GUI!
+ */
+/* #define USE_SYSTEM */
+
+/*
+ * +X11 Unix only. Include code for xterm title saving and X
+ * clipboard. Only works if HAVE_X11 is also defined.
+ */
+#if (defined(FEAT_NORMAL) || defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA))
+# define WANT_X11
+#endif
+
+/*
+ * XSMP - X11 Session Management Protocol
+ * It may be preferred to disable this if the GUI supports it (e.g.,
+ * GNOME/KDE) and implement save-yourself etc. through that, but it may also
+ * be cleaner to have all SM-aware vims do the same thing (libSM does not
+ * depend upon X11).
+ * If your GUI wants to support SM itself, change this ifdef.
+ * I'm assuming that any X11 implementation will cope with this for now.
+ */
+#if defined(HAVE_X11) && defined(WANT_X11) && defined(HAVE_X11_SM_SMLIB_H)
+# define USE_XSMP
+#endif
+#if defined(USE_XSMP_INTERACT) && !defined(USE_XSMP)
+# undef USE_XSMP_INTERACT
+#endif
+
+/*
+ * +mouse_xterm Unix only: Include code for xterm mouse handling.
+ * +mouse_dec idem, for Dec mouse handling.
+ * +mouse_jsbterm idem, for Jsbterm mouse handling.
+ * +mouse_netterm idem, for Netterm mouse handling.
+ * (none) MS-DOS mouse support.
+ * +mouse_gpm Unix only: Include code for Linux console mouse
+ * handling.
+ * +mouse_pterm PTerm mouse support for QNX
+ * +mouse_sgr Unix only: Include code for for SGR-styled mouse.
+ * +mouse_sysmouse Unix only: Include code for FreeBSD and DragonFly
+ * console mouse handling.
+ * +mouse_urxvt Unix only: Include code for for urxvt mosue handling.
+ * +mouse Any mouse support (any of the above enabled).
+ */
+/* OS/2 and Amiga console have no mouse support */
+#if !defined(AMIGA)
+# ifdef FEAT_NORMAL
+# define FEAT_MOUSE_XTERM
+# endif
+# ifdef FEAT_BIG
+# define FEAT_MOUSE_NET
+# endif
+# ifdef FEAT_BIG
+# define FEAT_MOUSE_DEC
+# endif
+# ifdef FEAT_BIG
+# define FEAT_MOUSE_URXVT
+# endif
+# ifdef FEAT_BIG
+# define FEAT_MOUSE_SGR
+# endif
+# if defined(FEAT_NORMAL) && defined(WIN3264)
+# define DOS_MOUSE
+# endif
+# if defined(FEAT_NORMAL) && defined(__QNX__)
+# define FEAT_MOUSE_PTERM
+# endif
+#endif
+
+/*
+ * Note: Only one of the following may be defined:
+ * FEAT_MOUSE_GPM
+ * FEAT_SYSMOUSE
+ * FEAT_MOUSE_JSB
+ * FEAT_MOUSE_PTERM
+ */
+#if defined(FEAT_NORMAL) && defined(HAVE_GPM)
+# define FEAT_MOUSE_GPM
+#endif
+
+#if defined(FEAT_NORMAL) && defined(HAVE_SYSMOUSE)
+# define FEAT_SYSMOUSE
+#endif
+
+/* urxvt is a small variation of mouse_xterm, and shares its code */
+#if defined(FEAT_MOUSE_URXVT) && !defined(FEAT_MOUSE_XTERM)
+# define FEAT_MOUSE_XTERM
+#endif
+
+/* sgr is a small variation of mouse_xterm, and shares its code */
+#if defined(FEAT_MOUSE_SGR) && !defined(FEAT_MOUSE_XTERM)
+# define FEAT_MOUSE_XTERM
+#endif
+
+/* Define FEAT_MOUSE when any of the above is defined or FEAT_GUI. */
+#if !defined(FEAT_MOUSE_TTY) \
+ && (defined(FEAT_MOUSE_XTERM) \
+ || defined(FEAT_MOUSE_NET) \
+ || defined(FEAT_MOUSE_DEC) \
+ || defined(DOS_MOUSE) \
+ || defined(FEAT_MOUSE_GPM) \
+ || defined(FEAT_MOUSE_JSB) \
+ || defined(FEAT_MOUSE_PTERM) \
+ || defined(FEAT_SYSMOUSE) \
+ || defined(FEAT_MOUSE_URXVT) \
+ || defined(FEAT_MOUSE_SGR))
+# define FEAT_MOUSE_TTY /* include non-GUI mouse support */
+#endif
+#if !defined(FEAT_MOUSE) && (defined(FEAT_MOUSE_TTY) || defined(FEAT_GUI))
+# define FEAT_MOUSE /* include generic mouse support */
+#endif
+
+/*
+ * +clipboard Clipboard support. Always used for the GUI.
+ * +xterm_clipboard Unix only: Include code for handling the clipboard
+ * in an xterm like in the GUI.
+ */
+
+#ifdef FEAT_CYGWIN_WIN32_CLIPBOARD
+# define FEAT_CLIPBOARD
+#endif
+
+#ifdef FEAT_GUI
+# ifndef FEAT_CLIPBOARD
+# define FEAT_CLIPBOARD
+# endif
+#endif
+
+#if defined(FEAT_NORMAL) \
+ && (defined(UNIX) || defined(VMS)) \
+ && defined(WANT_X11) && defined(HAVE_X11)
+# define FEAT_XCLIPBOARD
+# ifndef FEAT_CLIPBOARD
+# define FEAT_CLIPBOARD
+# endif
+#endif
+
+/*
+ * +dnd Drag'n'drop support. Always used for the GTK+ GUI.
+ */
+#if defined(FEAT_CLIPBOARD) && defined(FEAT_GUI_GTK)
+# define FEAT_DND
+#endif
+
+#if defined(FEAT_GUI_MSWIN) && defined(FEAT_SMALL)
+# define MSWIN_FIND_REPLACE /* include code for find/replace dialog */
+# define MSWIN_FR_BUFSIZE 256
+#endif
+
+#if defined(FEAT_GUI_GTK) || defined(FEAT_GUI_MOTIF) \
+ || defined(MSWIN_FIND_REPLACE)
+# define FIND_REPLACE_DIALOG 1
+#endif
+
+/*
+ * +clientserver Remote control via the remote_send() function
+ * and the --remote argument
+ */
+#if (defined(WIN32) || defined(FEAT_XCLIPBOARD)) && defined(FEAT_EVAL)
+# define FEAT_CLIENTSERVER
+#endif
+
+/*
+ * +autoservername Automatically generate a servername for clientserver
+ * when --servername is not passed on the command line.
+ */
+#if defined(FEAT_CLIENTSERVER) && !defined(FEAT_AUTOSERVERNAME)
+# ifdef WIN3264
+ /* Always enabled on MS-Windows. */
+# define FEAT_AUTOSERVERNAME
+# else
+ /* Enable here if you don't use configure. */
+/* # define FEAT_AUTOSERVERNAME */
+# endif
+#endif
+
+/*
+ * +termresponse send t_RV to obtain terminal response. Used for xterm
+ * to check if mouse dragging can be used and if term
+ * codes can be obtained.
+ */
+#if (defined(FEAT_NORMAL) || defined(FEAT_MOUSE)) && defined(HAVE_TGETENT)
+# define FEAT_TERMRESPONSE
+#endif
+
+/*
+ * cursor shape Adjust the shape of the cursor to the mode.
+ * mouse shape Adjust the shape of the mouse pointer to the mode.
+ */
+#ifdef FEAT_NORMAL
+/* MS-DOS console and Win32 console can change cursor shape */
+# if defined(WIN3264) && !defined(FEAT_GUI_W32)
+# define MCH_CURSOR_SHAPE
+# endif
+# if defined(FEAT_GUI_W32) || defined(FEAT_GUI_MOTIF) \
+ || defined(FEAT_GUI_ATHENA) || defined(FEAT_GUI_GTK) \
+ || defined(FEAT_GUI_PHOTON)
+# define FEAT_MOUSESHAPE
+# endif
+#endif
+
+/* GUI and some consoles can change the shape of the cursor. The code is also
+ * needed for the 'mouseshape' and 'concealcursor' options. */
+#if defined(FEAT_GUI) \
+ || defined(MCH_CURSOR_SHAPE) \
+ || defined(FEAT_MOUSESHAPE) \
+ || defined(FEAT_CONCEAL) \
+ || (defined(UNIX) && defined(FEAT_NORMAL))
+# define CURSOR_SHAPE
+#endif
+
+#if defined(FEAT_MZSCHEME) && (defined(FEAT_GUI_W32) || defined(FEAT_GUI_GTK) \
+ || defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA) \
+ || defined(FEAT_GUI_MAC))
+# define MZSCHEME_GUI_THREADS
+#endif
+
+/*
+ * +ARP Amiga only. Use arp.library, DOS 2.0 is not required.
+ */
+#if !defined(NO_ARP) && !defined(__amigaos4__)
+# define FEAT_ARP
+#endif
+
+/*
+ * +GUI_Athena To compile Vim with or without the GUI (gvim) you have
+ * +GUI_Motif to edit the Makefile.
+ */
+
+/*
+ * +ole Win32 OLE automation: Use Makefile.ovc.
+ */
+
+/*
+ * These features can only be included by using a configure argument. See the
+ * Makefile for a line to uncomment.
+ * +lua Lua interface: "--enable-luainterp"
+ * +mzscheme MzScheme interface: "--enable-mzscheme"
+ * +perl Perl interface: "--enable-perlinterp"
+ * +python Python interface: "--enable-pythoninterp"
+ * +tcl TCL interface: "--enable-tclinterp"
+ * +netbeans_intg Netbeans integration
+ * +channel Inter process communication
+ */
+
+/*
+ * These features are automatically detected:
+ * +terminfo
+ * +tgetent
+ */
+
+/*
+ * The Netbeans feature requires +eval.
+ */
+#if !defined(FEAT_EVAL) && defined(FEAT_NETBEANS_INTG)
+# undef FEAT_NETBEANS_INTG
+#endif
+
+/*
+ * The +channel feature requires +eval.
+ */
+#if !defined(FEAT_EVAL) && defined(FEAT_JOB_CHANNEL)
+# undef FEAT_JOB_CHANNEL
+#endif
+
+/*
+ * +terminal ":terminal" command. Runs a terminal in a window.
+ * requires +channel
+ */
+#if defined(FEAT_TERMINAL) && !defined(FEAT_JOB_CHANNEL)
+# undef FEAT_TERMINAL
+#endif
+#if defined(FEAT_TERMINAL) && !defined(CURSOR_SHAPE)
+# define CURSOR_SHAPE
+#endif
+
+/*
+ * +signs Allow signs to be displayed to the left of text lines.
+ * Adds the ":sign" command.
+ */
+#if defined(FEAT_BIG) || defined(FEAT_NETBEANS_INTG)
+# define FEAT_SIGNS
+# if ((defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA)) \
+ && defined(HAVE_X11_XPM_H)) \
+ || defined(FEAT_GUI_GTK) \
+ || (defined(WIN32) && defined(FEAT_GUI))
+# define FEAT_SIGN_ICONS
+# endif
+#endif
+
+/*
+ * +balloon_eval Allow balloon expression evaluation. Used with a
+ * debugger and for tooltips.
+ * Only for GUIs where it was implemented.
+ */
+#if (defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA) \
+ || defined(FEAT_GUI_GTK) || defined(FEAT_GUI_W32)) \
+ && ( ((defined(FEAT_TOOLBAR) || defined(FEAT_GUI_TABLINE)) \
+ && !defined(FEAT_GUI_GTK) && !defined(FEAT_GUI_W32)) \
+ || defined(FEAT_NETBEANS_INTG) || defined(FEAT_EVAL))
+# define FEAT_BEVAL_GUI
+# if !defined(FEAT_XFONTSET) && !defined(FEAT_GUI_GTK) \
+ && !defined(FEAT_GUI_W32)
+# define FEAT_XFONTSET
+# endif
+#endif
+
+#if defined(FEAT_BEVAL_GUI) && (defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA))
+# define FEAT_BEVAL_TIP /* balloon eval used for toolbar tooltip */
+#endif
+
+/*
+ * +balloon_eval_term Allow balloon expression evaluation in the terminal.
+ */
+#if defined(FEAT_HUGE) && defined(FEAT_TIMERS) && \
+ (defined(UNIX) || defined(VMS) || (defined(WIN32) && !defined(FEAT_GUI_W32)))
+# define FEAT_BEVAL_TERM
+#endif
+
+#if defined(FEAT_BEVAL_GUI) || defined(FEAT_BEVAL_TERM)
+# define FEAT_BEVAL
+#endif
+
+/* both Motif and Athena are X11 and share some code */
+#if defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA)
+# define FEAT_GUI_X11
+#endif
+
+#if defined(FEAT_NETBEANS_INTG)
+// NetBeans uses menus.
+# if !defined(FEAT_MENU)
+# define FEAT_MENU
+# endif
+#endif
+
+#if 0
+/*
+ * +footer Motif only: Add a message area at the bottom of the
+ * main window area.
+ */
+# define FEAT_FOOTER
+#endif
+
+/*
+ * +autochdir 'autochdir' option.
+ */
+#if defined(FEAT_NETBEANS_INTG) || defined(FEAT_BIG)
+# define FEAT_AUTOCHDIR
+#endif
+
+/*
+ * +persistent_undo 'undofile', 'undodir' options, :wundo and :rundo, and
+ * implementation.
+ */
+#ifdef FEAT_NORMAL
+# define FEAT_PERSISTENT_UNDO
+#endif
+
+/*
+ * +filterpipe
+ */
+#if (defined(UNIX) && !defined(USE_SYSTEM)) \
+ || (defined(WIN3264) && defined(FEAT_GUI_W32))
+# define FEAT_FILTERPIPE
+#endif
+
+/*
+ * +vtp: Win32 virtual console.
+ */
+#if !defined(FEAT_GUI) && defined(WIN3264)
+# define FEAT_VTP
+#endif
diff --git a/src/fileio.c b/src/fileio.c
new file mode 100644
index 0000000..bf724f6
--- /dev/null
+++ b/src/fileio.c
@@ -0,0 +1,7872 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * fileio.c: read from and write to a file
+ */
+
+#include "vim.h"
+
+#if defined(__TANDEM) || defined(__MINT__)
+# include <limits.h> /* for SSIZE_MAX */
+#endif
+
+#if defined(HAVE_UTIME) && defined(HAVE_UTIME_H)
+# include <utime.h> /* for struct utimbuf */
+#endif
+
+#define BUFSIZE 8192 /* size of normal write buffer */
+#define SMBUFSIZE 256 /* size of emergency write buffer */
+
+/* Is there any system that doesn't have access()? */
+#define USE_MCH_ACCESS
+
+static char_u *next_fenc(char_u **pp);
+#ifdef FEAT_EVAL
+static char_u *readfile_charconvert(char_u *fname, char_u *fenc, int *fdp);
+#endif
+#ifdef FEAT_VIMINFO
+static void check_marks_read(void);
+#endif
+#ifdef FEAT_CRYPT
+static char_u *check_for_cryptkey(char_u *cryptkey, char_u *ptr, long *sizep, off_T *filesizep, int newfile, char_u *fname, int *did_ask);
+#endif
+static int set_rw_fname(char_u *fname, char_u *sfname);
+static int msg_add_fileformat(int eol_type);
+static void msg_add_eol(void);
+static int check_mtime(buf_T *buf, stat_T *s);
+static int time_differs(long t1, long t2);
+
+#define HAS_BW_FLAGS
+#define FIO_LATIN1 0x01 /* convert Latin1 */
+#define FIO_UTF8 0x02 /* convert UTF-8 */
+#define FIO_UCS2 0x04 /* convert UCS-2 */
+#define FIO_UCS4 0x08 /* convert UCS-4 */
+#define FIO_UTF16 0x10 /* convert UTF-16 */
+#ifdef WIN3264
+# define FIO_CODEPAGE 0x20 /* convert MS-Windows codepage */
+# define FIO_PUT_CP(x) (((x) & 0xffff) << 16) /* put codepage in top word */
+# define FIO_GET_CP(x) (((x)>>16) & 0xffff) /* get codepage from top word */
+#endif
+#ifdef MACOS_CONVERT
+# define FIO_MACROMAN 0x20 /* convert MacRoman */
+#endif
+#define FIO_ENDIAN_L 0x80 /* little endian */
+#define FIO_ENCRYPTED 0x1000 /* encrypt written bytes */
+#define FIO_NOCONVERT 0x2000 /* skip encoding conversion */
+#define FIO_UCSBOM 0x4000 /* check for BOM at start of file */
+#define FIO_ALL -1 /* allow all formats */
+
+/* When converting, a read() or write() may leave some bytes to be converted
+ * for the next call. The value is guessed... */
+#define CONV_RESTLEN 30
+
+/* We have to guess how much a sequence of bytes may expand when converting
+ * with iconv() to be able to allocate a buffer. */
+#define ICONV_MULT 8
+
+/*
+ * Structure to pass arguments from buf_write() to buf_write_bytes().
+ */
+struct bw_info
+{
+ int bw_fd; /* file descriptor */
+ char_u *bw_buf; /* buffer with data to be written */
+ int bw_len; /* length of data */
+#ifdef HAS_BW_FLAGS
+ int bw_flags; /* FIO_ flags */
+#endif
+#ifdef FEAT_CRYPT
+ buf_T *bw_buffer; /* buffer being written */
+#endif
+ char_u bw_rest[CONV_RESTLEN]; /* not converted bytes */
+ int bw_restlen; /* nr of bytes in bw_rest[] */
+ int bw_first; /* first write call */
+ char_u *bw_conv_buf; /* buffer for writing converted chars */
+ int bw_conv_buflen; /* size of bw_conv_buf */
+ int bw_conv_error; /* set for conversion error */
+ linenr_T bw_conv_error_lnum; /* first line with error or zero */
+ linenr_T bw_start_lnum; /* line number at start of buffer */
+#ifdef USE_ICONV
+ iconv_t bw_iconv_fd; /* descriptor for iconv() or -1 */
+#endif
+};
+
+static int buf_write_bytes(struct bw_info *ip);
+
+static linenr_T readfile_linenr(linenr_T linecnt, char_u *p, char_u *endp);
+static int ucs2bytes(unsigned c, char_u **pp, int flags);
+static int need_conversion(char_u *fenc);
+static int get_fio_flags(char_u *ptr);
+static char_u *check_for_bom(char_u *p, long size, int *lenp, int flags);
+static int make_bom(char_u *buf, char_u *name);
+#ifdef WIN3264
+static int get_win_fio_flags(char_u *ptr);
+#endif
+#ifdef MACOS_CONVERT
+static int get_mac_fio_flags(char_u *ptr);
+#endif
+static char *e_auchangedbuf = N_("E812: Autocommands changed buffer or buffer name");
+
+ void
+filemess(
+ buf_T *buf,
+ char_u *name,
+ char_u *s,
+ int attr)
+{
+ int msg_scroll_save;
+
+ if (msg_silent != 0)
+ return;
+ msg_add_fname(buf, name); /* put file name in IObuff with quotes */
+ /* If it's extremely long, truncate it. */
+ if (STRLEN(IObuff) > IOSIZE - 80)
+ IObuff[IOSIZE - 80] = NUL;
+ STRCAT(IObuff, s);
+ /*
+ * For the first message may have to start a new line.
+ * For further ones overwrite the previous one, reset msg_scroll before
+ * calling filemess().
+ */
+ msg_scroll_save = msg_scroll;
+ if (shortmess(SHM_OVERALL) && !exiting && p_verbose == 0)
+ msg_scroll = FALSE;
+ if (!msg_scroll) /* wait a bit when overwriting an error msg */
+ check_for_delay(FALSE);
+ msg_start();
+ msg_scroll = msg_scroll_save;
+ msg_scrolled_ign = TRUE;
+ /* may truncate the message to avoid a hit-return prompt */
+ msg_outtrans_attr(msg_may_trunc(FALSE, IObuff), attr);
+ msg_clr_eos();
+ out_flush();
+ msg_scrolled_ign = FALSE;
+}
+
+/*
+ * Read lines from file "fname" into the buffer after line "from".
+ *
+ * 1. We allocate blocks with lalloc, as big as possible.
+ * 2. Each block is filled with characters from the file with a single read().
+ * 3. The lines are inserted in the buffer with ml_append().
+ *
+ * (caller must check that fname != NULL, unless READ_STDIN is used)
+ *
+ * "lines_to_skip" is the number of lines that must be skipped
+ * "lines_to_read" is the number of lines that are appended
+ * When not recovering lines_to_skip is 0 and lines_to_read MAXLNUM.
+ *
+ * flags:
+ * READ_NEW starting to edit a new buffer
+ * READ_FILTER reading filter output
+ * READ_STDIN read from stdin instead of a file
+ * READ_BUFFER read from curbuf instead of a file (converting after reading
+ * stdin)
+ * READ_DUMMY read into a dummy buffer (to check if file contents changed)
+ * READ_KEEP_UNDO don't clear undo info or read it from a file
+ * READ_FIFO read from fifo/socket instead of a file
+ *
+ * return FAIL for failure, NOTDONE for directory (failure), or OK
+ */
+ int
+readfile(
+ char_u *fname,
+ char_u *sfname,
+ linenr_T from,
+ linenr_T lines_to_skip,
+ linenr_T lines_to_read,
+ exarg_T *eap, /* can be NULL! */
+ int flags)
+{
+ int fd = 0;
+ int newfile = (flags & READ_NEW);
+ int check_readonly;
+ int filtering = (flags & READ_FILTER);
+ int read_stdin = (flags & READ_STDIN);
+ int read_buffer = (flags & READ_BUFFER);
+ int read_fifo = (flags & READ_FIFO);
+ int set_options = newfile || read_buffer
+ || (eap != NULL && eap->read_edit);
+ linenr_T read_buf_lnum = 1; /* next line to read from curbuf */
+ colnr_T read_buf_col = 0; /* next char to read from this line */
+ char_u c;
+ linenr_T lnum = from;
+ char_u *ptr = NULL; /* pointer into read buffer */
+ char_u *buffer = NULL; /* read buffer */
+ char_u *new_buffer = NULL; /* init to shut up gcc */
+ char_u *line_start = NULL; /* init to shut up gcc */
+ int wasempty; /* buffer was empty before reading */
+ colnr_T len;
+ long size = 0;
+ char_u *p;
+ off_T filesize = 0;
+ int skip_read = FALSE;
+#ifdef FEAT_CRYPT
+ char_u *cryptkey = NULL;
+ int did_ask_for_key = FALSE;
+#endif
+#ifdef FEAT_PERSISTENT_UNDO
+ context_sha256_T sha_ctx;
+ int read_undo_file = FALSE;
+#endif
+ int split = 0; /* number of split lines */
+#define UNKNOWN 0x0fffffff /* file size is unknown */
+ linenr_T linecnt;
+ int error = FALSE; /* errors encountered */
+ int ff_error = EOL_UNKNOWN; /* file format with errors */
+ long linerest = 0; /* remaining chars in line */
+#ifdef UNIX
+ int perm = 0;
+ int swap_mode = -1; /* protection bits for swap file */
+#else
+ int perm;
+#endif
+ int fileformat = 0; /* end-of-line format */
+ int keep_fileformat = FALSE;
+ stat_T st;
+ int file_readonly;
+ linenr_T skip_count = 0;
+ linenr_T read_count = 0;
+ int msg_save = msg_scroll;
+ linenr_T read_no_eol_lnum = 0; /* non-zero lnum when last line of
+ * last read was missing the eol */
+ int try_mac;
+ int try_dos;
+ int try_unix;
+ int file_rewind = FALSE;
+ int can_retry;
+ linenr_T conv_error = 0; /* line nr with conversion error */
+ linenr_T illegal_byte = 0; /* line nr with illegal byte */
+ int keep_dest_enc = FALSE; /* don't retry when char doesn't fit
+ in destination encoding */
+ int bad_char_behavior = BAD_REPLACE;
+ /* BAD_KEEP, BAD_DROP or character to
+ * replace with */
+ char_u *tmpname = NULL; /* name of 'charconvert' output file */
+ int fio_flags = 0;
+ char_u *fenc; /* fileencoding to use */
+ int fenc_alloced; /* fenc_next is in allocated memory */
+ char_u *fenc_next = NULL; /* next item in 'fencs' or NULL */
+ int advance_fenc = FALSE;
+ long real_size = 0;
+#ifdef USE_ICONV
+ iconv_t iconv_fd = (iconv_t)-1; /* descriptor for iconv() or -1 */
+# ifdef FEAT_EVAL
+ int did_iconv = FALSE; /* TRUE when iconv() failed and trying
+ 'charconvert' next */
+# endif
+#endif
+ int converted = FALSE; /* TRUE if conversion done */
+ int notconverted = FALSE; /* TRUE if conversion wanted but it
+ wasn't possible */
+ char_u conv_rest[CONV_RESTLEN];
+ int conv_restlen = 0; /* nr of bytes in conv_rest[] */
+ buf_T *old_curbuf;
+ char_u *old_b_ffname;
+ char_u *old_b_fname;
+ int using_b_ffname;
+ int using_b_fname;
+
+ au_did_filetype = FALSE; /* reset before triggering any autocommands */
+
+ curbuf->b_no_eol_lnum = 0; /* in case it was set by the previous read */
+
+ /*
+ * If there is no file name yet, use the one for the read file.
+ * BF_NOTEDITED is set to reflect this.
+ * Don't do this for a read from a filter.
+ * Only do this when 'cpoptions' contains the 'f' flag.
+ */
+ if (curbuf->b_ffname == NULL
+ && !filtering
+ && fname != NULL
+ && vim_strchr(p_cpo, CPO_FNAMER) != NULL
+ && !(flags & READ_DUMMY))
+ {
+ if (set_rw_fname(fname, sfname) == FAIL)
+ return FAIL;
+ }
+
+ /* Remember the initial values of curbuf, curbuf->b_ffname and
+ * curbuf->b_fname to detect whether they are altered as a result of
+ * executing nasty autocommands. Also check if "fname" and "sfname"
+ * point to one of these values. */
+ old_curbuf = curbuf;
+ old_b_ffname = curbuf->b_ffname;
+ old_b_fname = curbuf->b_fname;
+ using_b_ffname = (fname == curbuf->b_ffname)
+ || (sfname == curbuf->b_ffname);
+ using_b_fname = (fname == curbuf->b_fname) || (sfname == curbuf->b_fname);
+
+ /* After reading a file the cursor line changes but we don't want to
+ * display the line. */
+ ex_no_reprint = TRUE;
+
+ /* don't display the file info for another buffer now */
+ need_fileinfo = FALSE;
+
+ /*
+ * For Unix: Use the short file name whenever possible.
+ * Avoids problems with networks and when directory names are changed.
+ * Don't do this for MS-DOS, a "cd" in a sub-shell may have moved us to
+ * another directory, which we don't detect.
+ */
+ if (sfname == NULL)
+ sfname = fname;
+#if defined(UNIX)
+ fname = sfname;
+#endif
+
+ /*
+ * The BufReadCmd and FileReadCmd events intercept the reading process by
+ * executing the associated commands instead.
+ */
+ if (!filtering && !read_stdin && !read_buffer)
+ {
+ pos_T pos;
+
+ pos = curbuf->b_op_start;
+
+ /* Set '[ mark to the line above where the lines go (line 1 if zero). */
+ curbuf->b_op_start.lnum = ((from == 0) ? 1 : from);
+ curbuf->b_op_start.col = 0;
+
+ if (newfile)
+ {
+ if (apply_autocmds_exarg(EVENT_BUFREADCMD, NULL, sfname,
+ FALSE, curbuf, eap))
+#ifdef FEAT_EVAL
+ return aborting() ? FAIL : OK;
+#else
+ return OK;
+#endif
+ }
+ else if (apply_autocmds_exarg(EVENT_FILEREADCMD, sfname, sfname,
+ FALSE, NULL, eap))
+#ifdef FEAT_EVAL
+ return aborting() ? FAIL : OK;
+#else
+ return OK;
+#endif
+
+ curbuf->b_op_start = pos;
+ }
+
+ if ((shortmess(SHM_OVER) || curbuf->b_help) && p_verbose == 0)
+ msg_scroll = FALSE; /* overwrite previous file message */
+ else
+ msg_scroll = TRUE; /* don't overwrite previous file message */
+
+ /*
+ * If the name ends in a path separator, we can't open it. Check here,
+ * because reading the file may actually work, but then creating the swap
+ * file may destroy it! Reported on MS-DOS and Win 95.
+ * If the name is too long we might crash further on, quit here.
+ */
+ if (fname != NULL && *fname != NUL)
+ {
+ p = fname + STRLEN(fname);
+ if (after_pathsep(fname, p) || STRLEN(fname) >= MAXPATHL)
+ {
+ filemess(curbuf, fname, (char_u *)_("Illegal file name"), 0);
+ msg_end();
+ msg_scroll = msg_save;
+ return FAIL;
+ }
+ }
+
+ if (!read_stdin && !read_buffer && !read_fifo)
+ {
+#ifdef UNIX
+ /*
+ * On Unix it is possible to read a directory, so we have to
+ * check for it before the mch_open().
+ */
+ perm = mch_getperm(fname);
+ if (perm >= 0 && !S_ISREG(perm) /* not a regular file ... */
+ && !S_ISFIFO(perm) /* ... or fifo */
+ && !S_ISSOCK(perm) /* ... or socket */
+# ifdef OPEN_CHR_FILES
+ && !(S_ISCHR(perm) && is_dev_fd_file(fname))
+ /* ... or a character special file named /dev/fd/<n> */
+# endif
+ )
+ {
+ int retval = FAIL;
+
+ if (S_ISDIR(perm))
+ {
+ filemess(curbuf, fname, (char_u *)_("is a directory"), 0);
+ retval = NOTDONE;
+ }
+ else
+ filemess(curbuf, fname, (char_u *)_("is not a file"), 0);
+ msg_end();
+ msg_scroll = msg_save;
+ return retval;
+ }
+#endif
+#if defined(MSWIN)
+ /*
+ * MS-Windows allows opening a device, but we will probably get stuck
+ * trying to read it.
+ */
+ if (!p_odev && mch_nodetype(fname) == NODE_WRITABLE)
+ {
+ filemess(curbuf, fname, (char_u *)_("is a device (disabled with 'opendevice' option)"), 0);
+ msg_end();
+ msg_scroll = msg_save;
+ return FAIL;
+ }
+#endif
+ }
+
+ /* Set default or forced 'fileformat' and 'binary'. */
+ set_file_options(set_options, eap);
+
+ /*
+ * When opening a new file we take the readonly flag from the file.
+ * Default is r/w, can be set to r/o below.
+ * Don't reset it when in readonly mode
+ * Only set/reset b_p_ro when BF_CHECK_RO is set.
+ */
+ check_readonly = (newfile && (curbuf->b_flags & BF_CHECK_RO));
+ if (check_readonly && !readonlymode)
+ curbuf->b_p_ro = FALSE;
+
+ if (newfile && !read_stdin && !read_buffer && !read_fifo)
+ {
+ /* Remember time of file. */
+ if (mch_stat((char *)fname, &st) >= 0)
+ {
+ buf_store_time(curbuf, &st, fname);
+ curbuf->b_mtime_read = curbuf->b_mtime;
+#ifdef UNIX
+ /*
+ * Use the protection bits of the original file for the swap file.
+ * This makes it possible for others to read the name of the
+ * edited file from the swapfile, but only if they can read the
+ * edited file.
+ * Remove the "write" and "execute" bits for group and others
+ * (they must not write the swapfile).
+ * Add the "read" and "write" bits for the user, otherwise we may
+ * not be able to write to the file ourselves.
+ * Setting the bits is done below, after creating the swap file.
+ */
+ 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;
+ curbuf->b_fab_mrs = st.st_fab_mrs;
+#endif
+ }
+ else
+ {
+ curbuf->b_mtime = 0;
+ curbuf->b_mtime_read = 0;
+ curbuf->b_orig_size = 0;
+ curbuf->b_orig_mode = 0;
+ }
+
+ /* Reset the "new file" flag. It will be set again below when the
+ * file doesn't exist. */
+ curbuf->b_flags &= ~(BF_NEW | BF_NEW_W);
+ }
+
+/*
+ * for UNIX: check readonly with perm and mch_access()
+ * for Amiga: check readonly by trying to open the file for writing
+ */
+ file_readonly = FALSE;
+ if (read_stdin)
+ {
+#if defined(MSWIN)
+ /* Force binary I/O on stdin to avoid CR-LF -> LF conversion. */
+ setmode(0, O_BINARY);
+#endif
+ }
+ else if (!read_buffer)
+ {
+#ifdef USE_MCH_ACCESS
+ if (
+# ifdef UNIX
+ !(perm & 0222) ||
+# endif
+ mch_access((char *)fname, W_OK))
+ file_readonly = TRUE;
+ fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0);
+#else
+ if (!newfile
+ || readonlymode
+ || (fd = mch_open((char *)fname, O_RDWR | O_EXTRA, 0)) < 0)
+ {
+ file_readonly = TRUE;
+ /* try to open ro */
+ fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0);
+ }
+#endif
+ }
+
+ if (fd < 0) /* cannot open at all */
+ {
+#ifndef UNIX
+ int isdir_f;
+#endif
+ msg_scroll = msg_save;
+#ifndef UNIX
+ /*
+ * On Amiga we can't open a directory, check here.
+ */
+ isdir_f = (mch_isdir(fname));
+ perm = mch_getperm(fname); /* check if the file exists */
+ if (isdir_f)
+ {
+ filemess(curbuf, sfname, (char_u *)_("is a directory"), 0);
+ curbuf->b_p_ro = TRUE; /* must use "w!" now */
+ }
+ else
+#endif
+ if (newfile)
+ {
+ if (perm < 0
+#ifdef ENOENT
+ && errno == ENOENT
+#endif
+ )
+ {
+ /*
+ * Set the 'new-file' flag, so that when the file has
+ * been created by someone else, a ":w" will complain.
+ */
+ curbuf->b_flags |= BF_NEW;
+
+ /* Create a swap file now, so that other Vims are warned
+ * that we are editing this file. Don't do this for a
+ * "nofile" or "nowrite" buffer type. */
+#ifdef FEAT_QUICKFIX
+ if (!bt_dontwrite(curbuf))
+#endif
+ {
+ check_need_swap(newfile);
+ /* SwapExists autocommand may mess things up */
+ if (curbuf != old_curbuf
+ || (using_b_ffname
+ && (old_b_ffname != curbuf->b_ffname))
+ || (using_b_fname
+ && (old_b_fname != curbuf->b_fname)))
+ {
+ emsg(_(e_auchangedbuf));
+ return FAIL;
+ }
+ }
+ if (dir_of_file_exists(fname))
+ filemess(curbuf, sfname, (char_u *)_("[New File]"), 0);
+ else
+ filemess(curbuf, sfname,
+ (char_u *)_("[New DIRECTORY]"), 0);
+#ifdef FEAT_VIMINFO
+ /* Even though this is a new file, it might have been
+ * edited before and deleted. Get the old marks. */
+ check_marks_read();
+#endif
+ /* Set forced 'fileencoding'. */
+ if (eap != NULL)
+ set_forced_fenc(eap);
+ apply_autocmds_exarg(EVENT_BUFNEWFILE, sfname, sfname,
+ FALSE, curbuf, eap);
+ /* remember the current fileformat */
+ save_file_ff(curbuf);
+
+#if defined(FEAT_EVAL)
+ if (aborting()) /* autocmds may abort script processing */
+ return FAIL;
+#endif
+ return OK; /* a new file is not an error */
+ }
+ else
+ {
+ filemess(curbuf, sfname, (char_u *)(
+# ifdef EFBIG
+ (errno == EFBIG) ? _("[File too big]") :
+# endif
+# ifdef EOVERFLOW
+ (errno == EOVERFLOW) ? _("[File too big]") :
+# endif
+ _("[Permission Denied]")), 0);
+ curbuf->b_p_ro = TRUE; /* must use "w!" now */
+ }
+ }
+
+ return FAIL;
+ }
+
+ /*
+ * Only set the 'ro' flag for readonly files the first time they are
+ * loaded. Help files always get readonly mode
+ */
+ if ((check_readonly && file_readonly) || curbuf->b_help)
+ curbuf->b_p_ro = TRUE;
+
+ if (set_options)
+ {
+ /* Don't change 'eol' if reading from buffer as it will already be
+ * correctly set when reading stdin. */
+ if (!read_buffer)
+ {
+ curbuf->b_p_eol = TRUE;
+ curbuf->b_start_eol = TRUE;
+ }
+ curbuf->b_p_bomb = FALSE;
+ curbuf->b_start_bomb = FALSE;
+ }
+
+ /* Create a swap file now, so that other Vims are warned that we are
+ * editing this file.
+ * Don't do this for a "nofile" or "nowrite" buffer type. */
+#ifdef FEAT_QUICKFIX
+ if (!bt_dontwrite(curbuf))
+#endif
+ {
+ check_need_swap(newfile);
+ if (!read_stdin && (curbuf != old_curbuf
+ || (using_b_ffname && (old_b_ffname != curbuf->b_ffname))
+ || (using_b_fname && (old_b_fname != curbuf->b_fname))))
+ {
+ emsg(_(e_auchangedbuf));
+ if (!read_buffer)
+ close(fd);
+ return FAIL;
+ }
+#ifdef UNIX
+ /* Set swap file protection bits after creating it. */
+ if (swap_mode > 0 && curbuf->b_ml.ml_mfp != NULL
+ && curbuf->b_ml.ml_mfp->mf_fname != NULL)
+ {
+ char_u *swap_fname = curbuf->b_ml.ml_mfp->mf_fname;
+
+ /*
+ * If the group-read bit is set but not the world-read bit, then
+ * the group must be equal to the group of the original file. If
+ * we can't make that happen then reset the group-read bit. This
+ * avoids making the swap file readable to more users when the
+ * primary group of the user is too permissive.
+ */
+ if ((swap_mode & 044) == 040)
+ {
+ stat_T swap_st;
+
+ if (mch_stat((char *)swap_fname, &swap_st) >= 0
+ && st.st_gid != swap_st.st_gid
+# ifdef HAVE_FCHOWN
+ && fchown(curbuf->b_ml.ml_mfp->mf_fd, -1, st.st_gid)
+ == -1
+# endif
+ )
+ swap_mode &= 0600;
+ }
+
+ (void)mch_setperm(swap_fname, (long)swap_mode);
+ }
+#endif
+ }
+
+#if defined(HAS_SWAP_EXISTS_ACTION)
+ /* If "Quit" selected at ATTENTION dialog, don't load the file */
+ if (swap_exists_action == SEA_QUIT)
+ {
+ if (!read_buffer && !read_stdin)
+ close(fd);
+ return FAIL;
+ }
+#endif
+
+ ++no_wait_return; /* don't wait for return yet */
+
+ /*
+ * Set '[ mark to the line above where the lines go (line 1 if zero).
+ */
+ curbuf->b_op_start.lnum = ((from == 0) ? 1 : from);
+ curbuf->b_op_start.col = 0;
+
+ try_mac = (vim_strchr(p_ffs, 'm') != NULL);
+ try_dos = (vim_strchr(p_ffs, 'd') != NULL);
+ try_unix = (vim_strchr(p_ffs, 'x') != NULL);
+
+ if (!read_buffer)
+ {
+ int m = msg_scroll;
+ int n = msg_scrolled;
+
+ /*
+ * The file must be closed again, the autocommands may want to change
+ * the file before reading it.
+ */
+ if (!read_stdin)
+ close(fd); /* ignore errors */
+
+ /*
+ * The output from the autocommands should not overwrite anything and
+ * should not be overwritten: Set msg_scroll, restore its value if no
+ * output was done.
+ */
+ msg_scroll = TRUE;
+ if (filtering)
+ apply_autocmds_exarg(EVENT_FILTERREADPRE, NULL, sfname,
+ FALSE, curbuf, eap);
+ else if (read_stdin)
+ apply_autocmds_exarg(EVENT_STDINREADPRE, NULL, sfname,
+ FALSE, curbuf, eap);
+ else if (newfile)
+ apply_autocmds_exarg(EVENT_BUFREADPRE, NULL, sfname,
+ FALSE, curbuf, eap);
+ else
+ apply_autocmds_exarg(EVENT_FILEREADPRE, sfname, sfname,
+ FALSE, NULL, eap);
+ /* autocommands may have changed it */
+ try_mac = (vim_strchr(p_ffs, 'm') != NULL);
+ try_dos = (vim_strchr(p_ffs, 'd') != NULL);
+ try_unix = (vim_strchr(p_ffs, 'x') != NULL);
+
+ if (msg_scrolled == n)
+ msg_scroll = m;
+
+#ifdef FEAT_EVAL
+ if (aborting()) /* autocmds may abort script processing */
+ {
+ --no_wait_return;
+ msg_scroll = msg_save;
+ curbuf->b_p_ro = TRUE; /* must use "w!" now */
+ return FAIL;
+ }
+#endif
+ /*
+ * Don't allow the autocommands to change the current buffer.
+ * Try to re-open the file.
+ *
+ * Don't allow the autocommands to change the buffer name either
+ * (cd for example) if it invalidates fname or sfname.
+ */
+ if (!read_stdin && (curbuf != old_curbuf
+ || (using_b_ffname && (old_b_ffname != curbuf->b_ffname))
+ || (using_b_fname && (old_b_fname != curbuf->b_fname))
+ || (fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0)) < 0))
+ {
+ --no_wait_return;
+ msg_scroll = msg_save;
+ if (fd < 0)
+ emsg(_("E200: *ReadPre autocommands made the file unreadable"));
+ else
+ emsg(_("E201: *ReadPre autocommands must not change current buffer"));
+ curbuf->b_p_ro = TRUE; /* must use "w!" now */
+ return FAIL;
+ }
+ }
+
+ /* Autocommands may add lines to the file, need to check if it is empty */
+ wasempty = (curbuf->b_ml.ml_flags & ML_EMPTY);
+
+ if (!recoverymode && !filtering && !(flags & READ_DUMMY))
+ {
+ /*
+ * Show the user that we are busy reading the input. Sometimes this
+ * may take a while. When reading from stdin another program may
+ * still be running, don't move the cursor to the last line, unless
+ * always using the GUI.
+ */
+ if (read_stdin)
+ {
+ if (!is_not_a_term())
+ {
+#ifndef ALWAYS_USE_GUI
+ mch_msg(_("Vim: Reading from stdin...\n"));
+#endif
+#ifdef FEAT_GUI
+ /* Also write a message in the GUI window, if there is one. */
+ if (gui.in_use && !gui.dying && !gui.starting)
+ {
+ p = (char_u *)_("Reading from stdin...");
+ gui_write(p, (int)STRLEN(p));
+ }
+#endif
+ }
+ }
+ else if (!read_buffer)
+ filemess(curbuf, sfname, (char_u *)"", 0);
+ }
+
+ msg_scroll = FALSE; /* overwrite the file message */
+
+ /*
+ * Set linecnt now, before the "retry" caused by a wrong guess for
+ * fileformat, and after the autocommands, which may change them.
+ */
+ linecnt = curbuf->b_ml.ml_line_count;
+
+ /* "++bad=" argument. */
+ if (eap != NULL && eap->bad_char != 0)
+ {
+ bad_char_behavior = eap->bad_char;
+ if (set_options)
+ curbuf->b_bad_char = eap->bad_char;
+ }
+ else
+ curbuf->b_bad_char = 0;
+
+ /*
+ * Decide which 'encoding' to use or use first.
+ */
+ if (eap != NULL && eap->force_enc != 0)
+ {
+ fenc = enc_canonize(eap->cmd + eap->force_enc);
+ fenc_alloced = TRUE;
+ keep_dest_enc = TRUE;
+ }
+ else if (curbuf->b_p_bin)
+ {
+ fenc = (char_u *)""; /* binary: don't convert */
+ fenc_alloced = FALSE;
+ }
+ else if (curbuf->b_help)
+ {
+ char_u firstline[80];
+ int fc;
+
+ /* Help files are either utf-8 or latin1. Try utf-8 first, if this
+ * fails it must be latin1.
+ * Always do this when 'encoding' is "utf-8". Otherwise only do
+ * this when needed to avoid [converted] remarks all the time.
+ * It is needed when the first line contains non-ASCII characters.
+ * That is only in *.??x files. */
+ fenc = (char_u *)"latin1";
+ c = enc_utf8;
+ if (!c && !read_stdin)
+ {
+ fc = fname[STRLEN(fname) - 1];
+ if (TOLOWER_ASC(fc) == 'x')
+ {
+ /* Read the first line (and a bit more). Immediately rewind to
+ * the start of the file. If the read() fails "len" is -1. */
+ len = read_eintr(fd, firstline, 80);
+ vim_lseek(fd, (off_T)0L, SEEK_SET);
+ for (p = firstline; p < firstline + len; ++p)
+ if (*p >= 0x80)
+ {
+ c = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (c)
+ {
+ fenc_next = fenc;
+ fenc = (char_u *)"utf-8";
+
+ /* When the file is utf-8 but a character doesn't fit in
+ * 'encoding' don't retry. In help text editing utf-8 bytes
+ * doesn't make sense. */
+ if (!enc_utf8)
+ keep_dest_enc = TRUE;
+ }
+ fenc_alloced = FALSE;
+ }
+ else if (*p_fencs == NUL)
+ {
+ fenc = curbuf->b_p_fenc; /* use format from buffer */
+ fenc_alloced = FALSE;
+ }
+ else
+ {
+ fenc_next = p_fencs; /* try items in 'fileencodings' */
+ fenc = next_fenc(&fenc_next);
+ fenc_alloced = TRUE;
+ }
+
+ /*
+ * Jump back here to retry reading the file in different ways.
+ * Reasons to retry:
+ * - encoding conversion failed: try another one from "fenc_next"
+ * - BOM detected and fenc was set, need to setup conversion
+ * - "fileformat" check failed: try another
+ *
+ * Variables set for special retry actions:
+ * "file_rewind" Rewind the file to start reading it again.
+ * "advance_fenc" Advance "fenc" using "fenc_next".
+ * "skip_read" Re-use already read bytes (BOM detected).
+ * "did_iconv" iconv() conversion failed, try 'charconvert'.
+ * "keep_fileformat" Don't reset "fileformat".
+ *
+ * Other status indicators:
+ * "tmpname" When != NULL did conversion with 'charconvert'.
+ * Output file has to be deleted afterwards.
+ * "iconv_fd" When != -1 did conversion with iconv().
+ */
+retry:
+
+ if (file_rewind)
+ {
+ if (read_buffer)
+ {
+ read_buf_lnum = 1;
+ read_buf_col = 0;
+ }
+ else if (read_stdin || vim_lseek(fd, (off_T)0L, SEEK_SET) != 0)
+ {
+ /* Can't rewind the file, give up. */
+ error = TRUE;
+ goto failed;
+ }
+ /* Delete the previously read lines. */
+ while (lnum > from)
+ ml_delete(lnum--, FALSE);
+ file_rewind = FALSE;
+ if (set_options)
+ {
+ curbuf->b_p_bomb = FALSE;
+ curbuf->b_start_bomb = FALSE;
+ }
+ conv_error = 0;
+ }
+
+ /*
+ * When retrying with another "fenc" and the first time "fileformat"
+ * will be reset.
+ */
+ if (keep_fileformat)
+ keep_fileformat = FALSE;
+ else
+ {
+ if (eap != NULL && eap->force_ff != 0)
+ {
+ fileformat = get_fileformat_force(curbuf, eap);
+ try_unix = try_dos = try_mac = FALSE;
+ }
+ else if (curbuf->b_p_bin)
+ fileformat = EOL_UNIX; /* binary: use Unix format */
+ else if (*p_ffs == NUL)
+ fileformat = get_fileformat(curbuf);/* use format from buffer */
+ else
+ fileformat = EOL_UNKNOWN; /* detect from file */
+ }
+
+#ifdef USE_ICONV
+ if (iconv_fd != (iconv_t)-1)
+ {
+ /* aborted conversion with iconv(), close the descriptor */
+ iconv_close(iconv_fd);
+ iconv_fd = (iconv_t)-1;
+ }
+#endif
+
+ if (advance_fenc)
+ {
+ /*
+ * Try the next entry in 'fileencodings'.
+ */
+ advance_fenc = FALSE;
+
+ if (eap != NULL && eap->force_enc != 0)
+ {
+ /* Conversion given with "++cc=" wasn't possible, read
+ * without conversion. */
+ notconverted = TRUE;
+ conv_error = 0;
+ if (fenc_alloced)
+ vim_free(fenc);
+ fenc = (char_u *)"";
+ fenc_alloced = FALSE;
+ }
+ else
+ {
+ if (fenc_alloced)
+ vim_free(fenc);
+ if (fenc_next != NULL)
+ {
+ fenc = next_fenc(&fenc_next);
+ fenc_alloced = (fenc_next != NULL);
+ }
+ else
+ {
+ fenc = (char_u *)"";
+ fenc_alloced = FALSE;
+ }
+ }
+ if (tmpname != NULL)
+ {
+ mch_remove(tmpname); /* delete converted file */
+ VIM_CLEAR(tmpname);
+ }
+ }
+
+ /*
+ * Conversion may be required when the encoding of the file is different
+ * from 'encoding' or 'encoding' is UTF-16, UCS-2 or UCS-4.
+ */
+ fio_flags = 0;
+ converted = need_conversion(fenc);
+ if (converted)
+ {
+
+ /* "ucs-bom" means we need to check the first bytes of the file
+ * for a BOM. */
+ if (STRCMP(fenc, ENC_UCSBOM) == 0)
+ fio_flags = FIO_UCSBOM;
+
+ /*
+ * Check if UCS-2/4 or Latin1 to UTF-8 conversion needs to be
+ * done. This is handled below after read(). Prepare the
+ * fio_flags to avoid having to parse the string each time.
+ * Also check for Unicode to Latin1 conversion, because iconv()
+ * appears not to handle this correctly. This works just like
+ * conversion to UTF-8 except how the resulting character is put in
+ * the buffer.
+ */
+ else if (enc_utf8 || STRCMP(p_enc, "latin1") == 0)
+ fio_flags = get_fio_flags(fenc);
+
+#ifdef WIN3264
+ /*
+ * Conversion from an MS-Windows codepage to UTF-8 or another codepage
+ * is handled with MultiByteToWideChar().
+ */
+ if (fio_flags == 0)
+ fio_flags = get_win_fio_flags(fenc);
+#endif
+
+#ifdef MACOS_CONVERT
+ /* Conversion from Apple MacRoman to latin1 or UTF-8 */
+ if (fio_flags == 0)
+ fio_flags = get_mac_fio_flags(fenc);
+#endif
+
+#ifdef USE_ICONV
+ /*
+ * Try using iconv() if we can't convert internally.
+ */
+ if (fio_flags == 0
+# ifdef FEAT_EVAL
+ && !did_iconv
+# endif
+ )
+ iconv_fd = (iconv_t)my_iconv_open(
+ enc_utf8 ? (char_u *)"utf-8" : p_enc, fenc);
+#endif
+
+#ifdef FEAT_EVAL
+ /*
+ * Use the 'charconvert' expression when conversion is required
+ * and we can't do it internally or with iconv().
+ */
+ if (fio_flags == 0 && !read_stdin && !read_buffer && *p_ccv != NUL
+ && !read_fifo
+# ifdef USE_ICONV
+ && iconv_fd == (iconv_t)-1
+# endif
+ )
+ {
+# ifdef USE_ICONV
+ did_iconv = FALSE;
+# endif
+ /* Skip conversion when it's already done (retry for wrong
+ * "fileformat"). */
+ if (tmpname == NULL)
+ {
+ tmpname = readfile_charconvert(fname, fenc, &fd);
+ if (tmpname == NULL)
+ {
+ /* Conversion failed. Try another one. */
+ advance_fenc = TRUE;
+ if (fd < 0)
+ {
+ /* Re-opening the original file failed! */
+ emsg(_("E202: Conversion made file unreadable!"));
+ error = TRUE;
+ goto failed;
+ }
+ goto retry;
+ }
+ }
+ }
+ else
+#endif
+ {
+ if (fio_flags == 0
+#ifdef USE_ICONV
+ && iconv_fd == (iconv_t)-1
+#endif
+ )
+ {
+ /* Conversion wanted but we can't.
+ * Try the next conversion in 'fileencodings' */
+ advance_fenc = TRUE;
+ goto retry;
+ }
+ }
+ }
+
+ /* Set "can_retry" when it's possible to rewind the file and try with
+ * another "fenc" value. It's FALSE when no other "fenc" to try, reading
+ * stdin or fixed at a specific encoding. */
+ can_retry = (*fenc != NUL && !read_stdin && !read_fifo && !keep_dest_enc);
+
+ if (!skip_read)
+ {
+ linerest = 0;
+ filesize = 0;
+ skip_count = lines_to_skip;
+ read_count = lines_to_read;
+ conv_restlen = 0;
+#ifdef FEAT_PERSISTENT_UNDO
+ read_undo_file = (newfile && (flags & READ_KEEP_UNDO) == 0
+ && curbuf->b_ffname != NULL
+ && curbuf->b_p_udf
+ && !filtering
+ && !read_fifo
+ && !read_stdin
+ && !read_buffer);
+ if (read_undo_file)
+ sha256_start(&sha_ctx);
+#endif
+#ifdef FEAT_CRYPT
+ if (curbuf->b_cryptstate != NULL)
+ {
+ /* Need to free the state, but keep the key, don't want to ask for
+ * it again. */
+ crypt_free_state(curbuf->b_cryptstate);
+ curbuf->b_cryptstate = NULL;
+ }
+#endif
+ }
+
+ while (!error && !got_int)
+ {
+ /*
+ * We allocate as much space for the file as we can get, plus
+ * space for the old line plus room for one terminating NUL.
+ * The amount is limited by the fact that read() only can read
+ * upto max_unsigned characters (and other things).
+ */
+ if (!skip_read)
+ {
+#if defined(SSIZE_MAX) && (SSIZE_MAX < 0x10000L)
+ size = SSIZE_MAX; /* use max I/O size, 52K */
+#else
+ /* Use buffer >= 64K. Add linerest to double the size if the
+ * line gets very long, to avoid a lot of copying. But don't
+ * read more than 1 Mbyte at a time, so we can be interrupted.
+ */
+ size = 0x10000L + linerest;
+ if (size > 0x100000L)
+ size = 0x100000L;
+#endif
+ }
+
+ /* Protect against the argument of lalloc() going negative. */
+ if (size < 0 || size + linerest + 1 < 0 || linerest >= MAXCOL)
+ {
+ ++split;
+ *ptr = NL; /* split line by inserting a NL */
+ size = 1;
+ }
+ else
+ {
+ if (!skip_read)
+ {
+ for ( ; size >= 10; size = (long)((long_u)size >> 1))
+ {
+ if ((new_buffer = lalloc((long_u)(size + linerest + 1),
+ FALSE)) != NULL)
+ break;
+ }
+ if (new_buffer == NULL)
+ {
+ do_outofmem_msg((long_u)(size * 2 + linerest + 1));
+ error = TRUE;
+ break;
+ }
+ if (linerest) /* copy characters from the previous buffer */
+ mch_memmove(new_buffer, ptr - linerest, (size_t)linerest);
+ vim_free(buffer);
+ buffer = new_buffer;
+ ptr = buffer + linerest;
+ line_start = buffer;
+
+ /* May need room to translate into.
+ * For iconv() we don't really know the required space, use a
+ * factor ICONV_MULT.
+ * latin1 to utf-8: 1 byte becomes up to 2 bytes
+ * utf-16 to utf-8: 2 bytes become up to 3 bytes, 4 bytes
+ * become up to 4 bytes, size must be multiple of 2
+ * ucs-2 to utf-8: 2 bytes become up to 3 bytes, size must be
+ * multiple of 2
+ * ucs-4 to utf-8: 4 bytes become up to 6 bytes, size must be
+ * multiple of 4 */
+ real_size = (int)size;
+#ifdef USE_ICONV
+ if (iconv_fd != (iconv_t)-1)
+ size = size / ICONV_MULT;
+ else
+#endif
+ if (fio_flags & FIO_LATIN1)
+ size = size / 2;
+ else if (fio_flags & (FIO_UCS2 | FIO_UTF16))
+ size = (size * 2 / 3) & ~1;
+ else if (fio_flags & FIO_UCS4)
+ size = (size * 2 / 3) & ~3;
+ else if (fio_flags == FIO_UCSBOM)
+ size = size / ICONV_MULT; /* worst case */
+#ifdef WIN3264
+ else if (fio_flags & FIO_CODEPAGE)
+ size = size / ICONV_MULT; /* also worst case */
+#endif
+#ifdef MACOS_CONVERT
+ else if (fio_flags & FIO_MACROMAN)
+ size = size / ICONV_MULT; /* also worst case */
+#endif
+
+ if (conv_restlen > 0)
+ {
+ /* Insert unconverted bytes from previous line. */
+ mch_memmove(ptr, conv_rest, conv_restlen);
+ ptr += conv_restlen;
+ size -= conv_restlen;
+ }
+
+ if (read_buffer)
+ {
+ /*
+ * Read bytes from curbuf. Used for converting text read
+ * from stdin.
+ */
+ if (read_buf_lnum > from)
+ size = 0;
+ else
+ {
+ int n, ni;
+ long tlen;
+
+ tlen = 0;
+ for (;;)
+ {
+ p = ml_get(read_buf_lnum) + read_buf_col;
+ n = (int)STRLEN(p);
+ if ((int)tlen + n + 1 > size)
+ {
+ /* Filled up to "size", append partial line.
+ * Change NL to NUL to reverse the effect done
+ * below. */
+ n = (int)(size - tlen);
+ for (ni = 0; ni < n; ++ni)
+ {
+ if (p[ni] == NL)
+ ptr[tlen++] = NUL;
+ else
+ ptr[tlen++] = p[ni];
+ }
+ read_buf_col += n;
+ break;
+ }
+ else
+ {
+ /* Append whole line and new-line. Change NL
+ * to NUL to reverse the effect done below. */
+ for (ni = 0; ni < n; ++ni)
+ {
+ if (p[ni] == NL)
+ ptr[tlen++] = NUL;
+ else
+ ptr[tlen++] = p[ni];
+ }
+ ptr[tlen++] = NL;
+ read_buf_col = 0;
+ if (++read_buf_lnum > from)
+ {
+ /* When the last line didn't have an
+ * end-of-line don't add it now either. */
+ if (!curbuf->b_p_eol)
+ --tlen;
+ size = tlen;
+ break;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ /*
+ * Read bytes from the file.
+ */
+ size = read_eintr(fd, ptr, size);
+ }
+
+#ifdef FEAT_CRYPT
+ /*
+ * At start of file: Check for magic number of encryption.
+ */
+ if (filesize == 0 && size > 0)
+ cryptkey = check_for_cryptkey(cryptkey, ptr, &size,
+ &filesize, newfile, sfname,
+ &did_ask_for_key);
+ /*
+ * Decrypt the read bytes. This is done before checking for
+ * EOF because the crypt layer may be buffering.
+ */
+ if (cryptkey != NULL && curbuf->b_cryptstate != NULL
+ && size > 0)
+ {
+# ifdef CRYPT_NOT_INPLACE
+ if (crypt_works_inplace(curbuf->b_cryptstate))
+ {
+# endif
+ crypt_decode_inplace(curbuf->b_cryptstate, ptr, size);
+# ifdef CRYPT_NOT_INPLACE
+ }
+ else
+ {
+ char_u *newptr = NULL;
+ int decrypted_size;
+
+ decrypted_size = crypt_decode_alloc(
+ curbuf->b_cryptstate, ptr, size, &newptr);
+
+ /* If the crypt layer is buffering, not producing
+ * anything yet, need to read more. */
+ if (decrypted_size == 0)
+ continue;
+
+ if (linerest == 0)
+ {
+ /* Simple case: reuse returned buffer (may be
+ * NULL, checked later). */
+ new_buffer = newptr;
+ }
+ else
+ {
+ long_u new_size;
+
+ /* Need new buffer to add bytes carried over. */
+ new_size = (long_u)(decrypted_size + linerest + 1);
+ new_buffer = lalloc(new_size, FALSE);
+ if (new_buffer == NULL)
+ {
+ do_outofmem_msg(new_size);
+ error = TRUE;
+ break;
+ }
+
+ mch_memmove(new_buffer, buffer, linerest);
+ if (newptr != NULL)
+ mch_memmove(new_buffer + linerest, newptr,
+ decrypted_size);
+ }
+
+ if (new_buffer != NULL)
+ {
+ vim_free(buffer);
+ buffer = new_buffer;
+ new_buffer = NULL;
+ line_start = buffer;
+ ptr = buffer + linerest;
+ }
+ size = decrypted_size;
+ }
+# endif
+ }
+#endif
+
+ if (size <= 0)
+ {
+ if (size < 0) /* read error */
+ error = TRUE;
+ else if (conv_restlen > 0)
+ {
+ /*
+ * Reached end-of-file but some trailing bytes could
+ * not be converted. Truncated file?
+ */
+
+ /* When we did a conversion report an error. */
+ if (fio_flags != 0
+#ifdef USE_ICONV
+ || iconv_fd != (iconv_t)-1
+#endif
+ )
+ {
+ if (can_retry)
+ goto rewind_retry;
+ if (conv_error == 0)
+ conv_error = curbuf->b_ml.ml_line_count
+ - linecnt + 1;
+ }
+ /* Remember the first linenr with an illegal byte */
+ else if (illegal_byte == 0)
+ illegal_byte = curbuf->b_ml.ml_line_count
+ - linecnt + 1;
+ if (bad_char_behavior == BAD_DROP)
+ {
+ *(ptr - conv_restlen) = NUL;
+ conv_restlen = 0;
+ }
+ else
+ {
+ /* Replace the trailing bytes with the replacement
+ * character if we were converting; if we weren't,
+ * leave the UTF8 checking code to do it, as it
+ * works slightly differently. */
+ if (bad_char_behavior != BAD_KEEP && (fio_flags != 0
+#ifdef USE_ICONV
+ || iconv_fd != (iconv_t)-1
+#endif
+ ))
+ {
+ while (conv_restlen > 0)
+ {
+ *(--ptr) = bad_char_behavior;
+ --conv_restlen;
+ }
+ }
+ fio_flags = 0; /* don't convert this */
+#ifdef USE_ICONV
+ if (iconv_fd != (iconv_t)-1)
+ {
+ iconv_close(iconv_fd);
+ iconv_fd = (iconv_t)-1;
+ }
+#endif
+ }
+ }
+ }
+ }
+ skip_read = FALSE;
+
+ /*
+ * At start of file (or after crypt magic number): Check for BOM.
+ * Also check for a BOM for other Unicode encodings, but not after
+ * converting with 'charconvert' or when a BOM has already been
+ * found.
+ */
+ if ((filesize == 0
+#ifdef FEAT_CRYPT
+ || (cryptkey != NULL
+ && filesize == crypt_get_header_len(
+ crypt_get_method_nr(curbuf)))
+#endif
+ )
+ && (fio_flags == FIO_UCSBOM
+ || (!curbuf->b_p_bomb
+ && tmpname == NULL
+ && (*fenc == 'u' || (*fenc == NUL && enc_utf8)))))
+ {
+ char_u *ccname;
+ int blen;
+
+ /* no BOM detection in a short file or in binary mode */
+ if (size < 2 || curbuf->b_p_bin)
+ ccname = NULL;
+ else
+ ccname = check_for_bom(ptr, size, &blen,
+ fio_flags == FIO_UCSBOM ? FIO_ALL : get_fio_flags(fenc));
+ if (ccname != NULL)
+ {
+ /* Remove BOM from the text */
+ filesize += blen;
+ size -= blen;
+ mch_memmove(ptr, ptr + blen, (size_t)size);
+ if (set_options)
+ {
+ curbuf->b_p_bomb = TRUE;
+ curbuf->b_start_bomb = TRUE;
+ }
+ }
+
+ if (fio_flags == FIO_UCSBOM)
+ {
+ if (ccname == NULL)
+ {
+ /* No BOM detected: retry with next encoding. */
+ advance_fenc = TRUE;
+ }
+ else
+ {
+ /* BOM detected: set "fenc" and jump back */
+ if (fenc_alloced)
+ vim_free(fenc);
+ fenc = ccname;
+ fenc_alloced = FALSE;
+ }
+ /* retry reading without getting new bytes or rewinding */
+ skip_read = TRUE;
+ goto retry;
+ }
+ }
+
+ /* Include not converted bytes. */
+ ptr -= conv_restlen;
+ size += conv_restlen;
+ conv_restlen = 0;
+ /*
+ * Break here for a read error or end-of-file.
+ */
+ if (size <= 0)
+ break;
+
+
+#ifdef USE_ICONV
+ if (iconv_fd != (iconv_t)-1)
+ {
+ /*
+ * Attempt conversion of the read bytes to 'encoding' using
+ * iconv().
+ */
+ const char *fromp;
+ char *top;
+ size_t from_size;
+ size_t to_size;
+
+ fromp = (char *)ptr;
+ from_size = size;
+ ptr += size;
+ top = (char *)ptr;
+ to_size = real_size - size;
+
+ /*
+ * If there is conversion error or not enough room try using
+ * another conversion. Except for when there is no
+ * alternative (help files).
+ */
+ while ((iconv(iconv_fd, (void *)&fromp, &from_size,
+ &top, &to_size)
+ == (size_t)-1 && ICONV_ERRNO != ICONV_EINVAL)
+ || from_size > CONV_RESTLEN)
+ {
+ if (can_retry)
+ goto rewind_retry;
+ if (conv_error == 0)
+ conv_error = readfile_linenr(linecnt,
+ ptr, (char_u *)top);
+
+ /* Deal with a bad byte and continue with the next. */
+ ++fromp;
+ --from_size;
+ if (bad_char_behavior == BAD_KEEP)
+ {
+ *top++ = *(fromp - 1);
+ --to_size;
+ }
+ else if (bad_char_behavior != BAD_DROP)
+ {
+ *top++ = bad_char_behavior;
+ --to_size;
+ }
+ }
+
+ if (from_size > 0)
+ {
+ /* Some remaining characters, keep them for the next
+ * round. */
+ mch_memmove(conv_rest, (char_u *)fromp, from_size);
+ conv_restlen = (int)from_size;
+ }
+
+ /* move the linerest to before the converted characters */
+ line_start = ptr - linerest;
+ mch_memmove(line_start, buffer, (size_t)linerest);
+ size = (long)((char_u *)top - ptr);
+ }
+#endif
+
+#ifdef WIN3264
+ if (fio_flags & FIO_CODEPAGE)
+ {
+ char_u *src, *dst;
+ WCHAR ucs2buf[3];
+ int ucs2len;
+ int codepage = FIO_GET_CP(fio_flags);
+ int bytelen;
+ int found_bad;
+ char replstr[2];
+
+ /*
+ * Conversion from an MS-Windows codepage or UTF-8 to UTF-8 or
+ * a codepage, using standard MS-Windows functions. This
+ * requires two steps:
+ * 1. convert from 'fileencoding' to ucs-2
+ * 2. convert from ucs-2 to 'encoding'
+ *
+ * Because there may be illegal bytes AND an incomplete byte
+ * sequence at the end, we may have to do the conversion one
+ * character at a time to get it right.
+ */
+
+ /* Replacement string for WideCharToMultiByte(). */
+ if (bad_char_behavior > 0)
+ replstr[0] = bad_char_behavior;
+ else
+ replstr[0] = '?';
+ replstr[1] = NUL;
+
+ /*
+ * Move the bytes to the end of the buffer, so that we have
+ * room to put the result at the start.
+ */
+ src = ptr + real_size - size;
+ mch_memmove(src, ptr, size);
+
+ /*
+ * Do the conversion.
+ */
+ dst = ptr;
+ size = size;
+ while (size > 0)
+ {
+ found_bad = FALSE;
+
+# ifdef CP_UTF8 /* VC 4.1 doesn't define CP_UTF8 */
+ if (codepage == CP_UTF8)
+ {
+ /* Handle CP_UTF8 input ourselves to be able to handle
+ * trailing bytes properly.
+ * Get one UTF-8 character from src. */
+ bytelen = (int)utf_ptr2len_len(src, size);
+ if (bytelen > size)
+ {
+ /* Only got some bytes of a character. Normally
+ * it's put in "conv_rest", but if it's too long
+ * deal with it as if they were illegal bytes. */
+ if (bytelen <= CONV_RESTLEN)
+ break;
+
+ /* weird overlong byte sequence */
+ bytelen = size;
+ found_bad = TRUE;
+ }
+ else
+ {
+ int u8c = utf_ptr2char(src);
+
+ if (u8c > 0xffff || (*src >= 0x80 && bytelen == 1))
+ found_bad = TRUE;
+ ucs2buf[0] = u8c;
+ ucs2len = 1;
+ }
+ }
+ else
+# endif
+ {
+ /* We don't know how long the byte sequence is, try
+ * from one to three bytes. */
+ for (bytelen = 1; bytelen <= size && bytelen <= 3;
+ ++bytelen)
+ {
+ ucs2len = MultiByteToWideChar(codepage,
+ MB_ERR_INVALID_CHARS,
+ (LPCSTR)src, bytelen,
+ ucs2buf, 3);
+ if (ucs2len > 0)
+ break;
+ }
+ if (ucs2len == 0)
+ {
+ /* If we have only one byte then it's probably an
+ * incomplete byte sequence. Otherwise discard
+ * one byte as a bad character. */
+ if (size == 1)
+ break;
+ found_bad = TRUE;
+ bytelen = 1;
+ }
+ }
+
+ if (!found_bad)
+ {
+ int i;
+
+ /* Convert "ucs2buf[ucs2len]" to 'enc' in "dst". */
+ if (enc_utf8)
+ {
+ /* From UCS-2 to UTF-8. Cannot fail. */
+ for (i = 0; i < ucs2len; ++i)
+ dst += utf_char2bytes(ucs2buf[i], dst);
+ }
+ else
+ {
+ BOOL bad = FALSE;
+ int dstlen;
+
+ /* From UCS-2 to "enc_codepage". If the
+ * conversion uses the default character "?",
+ * the data doesn't fit in this encoding. */
+ dstlen = WideCharToMultiByte(enc_codepage, 0,
+ (LPCWSTR)ucs2buf, ucs2len,
+ (LPSTR)dst, (int)(src - dst),
+ replstr, &bad);
+ if (bad)
+ found_bad = TRUE;
+ else
+ dst += dstlen;
+ }
+ }
+
+ if (found_bad)
+ {
+ /* Deal with bytes we can't convert. */
+ if (can_retry)
+ goto rewind_retry;
+ if (conv_error == 0)
+ conv_error = readfile_linenr(linecnt, ptr, dst);
+ if (bad_char_behavior != BAD_DROP)
+ {
+ if (bad_char_behavior == BAD_KEEP)
+ {
+ mch_memmove(dst, src, bytelen);
+ dst += bytelen;
+ }
+ else
+ *dst++ = bad_char_behavior;
+ }
+ }
+
+ src += bytelen;
+ size -= bytelen;
+ }
+
+ if (size > 0)
+ {
+ /* An incomplete byte sequence remaining. */
+ mch_memmove(conv_rest, src, size);
+ conv_restlen = size;
+ }
+
+ /* The new size is equal to how much "dst" was advanced. */
+ size = (long)(dst - ptr);
+ }
+ else
+#endif
+#ifdef MACOS_CONVERT
+ if (fio_flags & FIO_MACROMAN)
+ {
+ /*
+ * Conversion from Apple MacRoman char encoding to UTF-8 or
+ * latin1. This is in os_mac_conv.c.
+ */
+ if (macroman2enc(ptr, &size, real_size) == FAIL)
+ goto rewind_retry;
+ }
+ else
+#endif
+ if (fio_flags != 0)
+ {
+ int u8c;
+ char_u *dest;
+ char_u *tail = NULL;
+
+ /*
+ * "enc_utf8" set: Convert Unicode or Latin1 to UTF-8.
+ * "enc_utf8" not set: Convert Unicode to Latin1.
+ * Go from end to start through the buffer, because the number
+ * of bytes may increase.
+ * "dest" points to after where the UTF-8 bytes go, "p" points
+ * to after the next character to convert.
+ */
+ dest = ptr + real_size;
+ if (fio_flags == FIO_LATIN1 || fio_flags == FIO_UTF8)
+ {
+ p = ptr + size;
+ if (fio_flags == FIO_UTF8)
+ {
+ /* Check for a trailing incomplete UTF-8 sequence */
+ tail = ptr + size - 1;
+ while (tail > ptr && (*tail & 0xc0) == 0x80)
+ --tail;
+ if (tail + utf_byte2len(*tail) <= ptr + size)
+ tail = NULL;
+ else
+ p = tail;
+ }
+ }
+ else if (fio_flags & (FIO_UCS2 | FIO_UTF16))
+ {
+ /* Check for a trailing byte */
+ p = ptr + (size & ~1);
+ if (size & 1)
+ tail = p;
+ if ((fio_flags & FIO_UTF16) && p > ptr)
+ {
+ /* Check for a trailing leading word */
+ if (fio_flags & FIO_ENDIAN_L)
+ {
+ u8c = (*--p << 8);
+ u8c += *--p;
+ }
+ else
+ {
+ u8c = *--p;
+ u8c += (*--p << 8);
+ }
+ if (u8c >= 0xd800 && u8c <= 0xdbff)
+ tail = p;
+ else
+ p += 2;
+ }
+ }
+ else /* FIO_UCS4 */
+ {
+ /* Check for trailing 1, 2 or 3 bytes */
+ p = ptr + (size & ~3);
+ if (size & 3)
+ tail = p;
+ }
+
+ /* If there is a trailing incomplete sequence move it to
+ * conv_rest[]. */
+ if (tail != NULL)
+ {
+ conv_restlen = (int)((ptr + size) - tail);
+ mch_memmove(conv_rest, (char_u *)tail, conv_restlen);
+ size -= conv_restlen;
+ }
+
+
+ while (p > ptr)
+ {
+ if (fio_flags & FIO_LATIN1)
+ u8c = *--p;
+ else if (fio_flags & (FIO_UCS2 | FIO_UTF16))
+ {
+ if (fio_flags & FIO_ENDIAN_L)
+ {
+ u8c = (*--p << 8);
+ u8c += *--p;
+ }
+ else
+ {
+ u8c = *--p;
+ u8c += (*--p << 8);
+ }
+ if ((fio_flags & FIO_UTF16)
+ && u8c >= 0xdc00 && u8c <= 0xdfff)
+ {
+ int u16c;
+
+ if (p == ptr)
+ {
+ /* Missing leading word. */
+ if (can_retry)
+ goto rewind_retry;
+ if (conv_error == 0)
+ conv_error = readfile_linenr(linecnt,
+ ptr, p);
+ if (bad_char_behavior == BAD_DROP)
+ continue;
+ if (bad_char_behavior != BAD_KEEP)
+ u8c = bad_char_behavior;
+ }
+
+ /* found second word of double-word, get the first
+ * word and compute the resulting character */
+ if (fio_flags & FIO_ENDIAN_L)
+ {
+ u16c = (*--p << 8);
+ u16c += *--p;
+ }
+ else
+ {
+ u16c = *--p;
+ u16c += (*--p << 8);
+ }
+ u8c = 0x10000 + ((u16c & 0x3ff) << 10)
+ + (u8c & 0x3ff);
+
+ /* Check if the word is indeed a leading word. */
+ if (u16c < 0xd800 || u16c > 0xdbff)
+ {
+ if (can_retry)
+ goto rewind_retry;
+ if (conv_error == 0)
+ conv_error = readfile_linenr(linecnt,
+ ptr, p);
+ if (bad_char_behavior == BAD_DROP)
+ continue;
+ if (bad_char_behavior != BAD_KEEP)
+ u8c = bad_char_behavior;
+ }
+ }
+ }
+ else if (fio_flags & FIO_UCS4)
+ {
+ if (fio_flags & FIO_ENDIAN_L)
+ {
+ u8c = (unsigned)*--p << 24;
+ u8c += (unsigned)*--p << 16;
+ u8c += (unsigned)*--p << 8;
+ u8c += *--p;
+ }
+ else /* big endian */
+ {
+ u8c = *--p;
+ u8c += (unsigned)*--p << 8;
+ u8c += (unsigned)*--p << 16;
+ u8c += (unsigned)*--p << 24;
+ }
+ }
+ else /* UTF-8 */
+ {
+ if (*--p < 0x80)
+ u8c = *p;
+ else
+ {
+ len = utf_head_off(ptr, p);
+ p -= len;
+ u8c = utf_ptr2char(p);
+ if (len == 0)
+ {
+ /* Not a valid UTF-8 character, retry with
+ * another fenc when possible, otherwise just
+ * report the error. */
+ if (can_retry)
+ goto rewind_retry;
+ if (conv_error == 0)
+ conv_error = readfile_linenr(linecnt,
+ ptr, p);
+ if (bad_char_behavior == BAD_DROP)
+ continue;
+ if (bad_char_behavior != BAD_KEEP)
+ u8c = bad_char_behavior;
+ }
+ }
+ }
+ if (enc_utf8) /* produce UTF-8 */
+ {
+ dest -= utf_char2len(u8c);
+ (void)utf_char2bytes(u8c, dest);
+ }
+ else /* produce Latin1 */
+ {
+ --dest;
+ if (u8c >= 0x100)
+ {
+ /* character doesn't fit in latin1, retry with
+ * another fenc when possible, otherwise just
+ * report the error. */
+ if (can_retry)
+ goto rewind_retry;
+ if (conv_error == 0)
+ conv_error = readfile_linenr(linecnt, ptr, p);
+ if (bad_char_behavior == BAD_DROP)
+ ++dest;
+ else if (bad_char_behavior == BAD_KEEP)
+ *dest = u8c;
+ else if (eap != NULL && eap->bad_char != 0)
+ *dest = bad_char_behavior;
+ else
+ *dest = 0xBF;
+ }
+ else
+ *dest = u8c;
+ }
+ }
+
+ /* move the linerest to before the converted characters */
+ line_start = dest - linerest;
+ mch_memmove(line_start, buffer, (size_t)linerest);
+ size = (long)((ptr + real_size) - dest);
+ ptr = dest;
+ }
+ else if (enc_utf8 && !curbuf->b_p_bin)
+ {
+ int incomplete_tail = FALSE;
+
+ /* Reading UTF-8: Check if the bytes are valid UTF-8. */
+ for (p = ptr; ; ++p)
+ {
+ int todo = (int)((ptr + size) - p);
+ int l;
+
+ if (todo <= 0)
+ break;
+ if (*p >= 0x80)
+ {
+ /* A length of 1 means it's an illegal byte. Accept
+ * an incomplete character at the end though, the next
+ * read() will get the next bytes, we'll check it
+ * then. */
+ l = utf_ptr2len_len(p, todo);
+ if (l > todo && !incomplete_tail)
+ {
+ /* Avoid retrying with a different encoding when
+ * a truncated file is more likely, or attempting
+ * to read the rest of an incomplete sequence when
+ * we have already done so. */
+ if (p > ptr || filesize > 0)
+ incomplete_tail = TRUE;
+ /* Incomplete byte sequence, move it to conv_rest[]
+ * and try to read the rest of it, unless we've
+ * already done so. */
+ if (p > ptr)
+ {
+ conv_restlen = todo;
+ mch_memmove(conv_rest, p, conv_restlen);
+ size -= conv_restlen;
+ break;
+ }
+ }
+ if (l == 1 || l > todo)
+ {
+ /* Illegal byte. If we can try another encoding
+ * do that, unless at EOF where a truncated
+ * file is more likely than a conversion error. */
+ if (can_retry && !incomplete_tail)
+ break;
+#ifdef USE_ICONV
+ /* When we did a conversion report an error. */
+ if (iconv_fd != (iconv_t)-1 && conv_error == 0)
+ conv_error = readfile_linenr(linecnt, ptr, p);
+#endif
+ /* Remember the first linenr with an illegal byte */
+ if (conv_error == 0 && illegal_byte == 0)
+ illegal_byte = readfile_linenr(linecnt, ptr, p);
+
+ /* Drop, keep or replace the bad byte. */
+ if (bad_char_behavior == BAD_DROP)
+ {
+ mch_memmove(p, p + 1, todo - 1);
+ --p;
+ --size;
+ }
+ else if (bad_char_behavior != BAD_KEEP)
+ *p = bad_char_behavior;
+ }
+ else
+ p += l - 1;
+ }
+ }
+ if (p < ptr + size && !incomplete_tail)
+ {
+ /* Detected a UTF-8 error. */
+rewind_retry:
+ /* Retry reading with another conversion. */
+#if defined(FEAT_EVAL) && defined(USE_ICONV)
+ if (*p_ccv != NUL && iconv_fd != (iconv_t)-1)
+ /* iconv() failed, try 'charconvert' */
+ did_iconv = TRUE;
+ else
+#endif
+ /* use next item from 'fileencodings' */
+ advance_fenc = TRUE;
+ file_rewind = TRUE;
+ goto retry;
+ }
+ }
+
+ /* count the number of characters (after conversion!) */
+ filesize += size;
+
+ /*
+ * when reading the first part of a file: guess EOL type
+ */
+ if (fileformat == EOL_UNKNOWN)
+ {
+ /* First try finding a NL, for Dos and Unix */
+ if (try_dos || try_unix)
+ {
+ /* Reset the carriage return counter. */
+ if (try_mac)
+ try_mac = 1;
+
+ for (p = ptr; p < ptr + size; ++p)
+ {
+ if (*p == NL)
+ {
+ if (!try_unix
+ || (try_dos && p > ptr && p[-1] == CAR))
+ fileformat = EOL_DOS;
+ else
+ fileformat = EOL_UNIX;
+ break;
+ }
+ else if (*p == CAR && try_mac)
+ try_mac++;
+ }
+
+ /* Don't give in to EOL_UNIX if EOL_MAC is more likely */
+ if (fileformat == EOL_UNIX && try_mac)
+ {
+ /* Need to reset the counters when retrying fenc. */
+ try_mac = 1;
+ try_unix = 1;
+ for (; p >= ptr && *p != CAR; p--)
+ ;
+ if (p >= ptr)
+ {
+ for (p = ptr; p < ptr + size; ++p)
+ {
+ if (*p == NL)
+ try_unix++;
+ else if (*p == CAR)
+ try_mac++;
+ }
+ if (try_mac > try_unix)
+ fileformat = EOL_MAC;
+ }
+ }
+ else if (fileformat == EOL_UNKNOWN && try_mac == 1)
+ /* Looking for CR but found no end-of-line markers at
+ * all: use the default format. */
+ fileformat = default_fileformat();
+ }
+
+ /* No NL found: may use Mac format */
+ if (fileformat == EOL_UNKNOWN && try_mac)
+ fileformat = EOL_MAC;
+
+ /* Still nothing found? Use first format in 'ffs' */
+ if (fileformat == EOL_UNKNOWN)
+ fileformat = default_fileformat();
+
+ /* if editing a new file: may set p_tx and p_ff */
+ if (set_options)
+ set_fileformat(fileformat, OPT_LOCAL);
+ }
+ }
+
+ /*
+ * This loop is executed once for every character read.
+ * Keep it fast!
+ */
+ if (fileformat == EOL_MAC)
+ {
+ --ptr;
+ while (++ptr, --size >= 0)
+ {
+ /* catch most common case first */
+ if ((c = *ptr) != NUL && c != CAR && c != NL)
+ continue;
+ if (c == NUL)
+ *ptr = NL; /* NULs are replaced by newlines! */
+ else if (c == NL)
+ *ptr = CAR; /* NLs are replaced by CRs! */
+ else
+ {
+ if (skip_count == 0)
+ {
+ *ptr = NUL; /* end of line */
+ len = (colnr_T) (ptr - line_start + 1);
+ if (ml_append(lnum, line_start, len, newfile) == FAIL)
+ {
+ error = TRUE;
+ break;
+ }
+#ifdef FEAT_PERSISTENT_UNDO
+ if (read_undo_file)
+ sha256_update(&sha_ctx, line_start, len);
+#endif
+ ++lnum;
+ if (--read_count == 0)
+ {
+ error = TRUE; /* break loop */
+ line_start = ptr; /* nothing left to write */
+ break;
+ }
+ }
+ else
+ --skip_count;
+ line_start = ptr + 1;
+ }
+ }
+ }
+ else
+ {
+ --ptr;
+ while (++ptr, --size >= 0)
+ {
+ if ((c = *ptr) != NUL && c != NL) /* catch most common case */
+ continue;
+ if (c == NUL)
+ *ptr = NL; /* NULs are replaced by newlines! */
+ else
+ {
+ if (skip_count == 0)
+ {
+ *ptr = NUL; /* end of line */
+ len = (colnr_T)(ptr - line_start + 1);
+ if (fileformat == EOL_DOS)
+ {
+ if (ptr > line_start && ptr[-1] == CAR)
+ {
+ /* remove CR before NL */
+ ptr[-1] = NUL;
+ --len;
+ }
+ /*
+ * Reading in Dos format, but no CR-LF found!
+ * When 'fileformats' includes "unix", delete all
+ * the lines read so far and start all over again.
+ * Otherwise give an error message later.
+ */
+ else if (ff_error != EOL_DOS)
+ {
+ if ( try_unix
+ && !read_stdin
+ && (read_buffer
+ || vim_lseek(fd, (off_T)0L, SEEK_SET)
+ == 0))
+ {
+ fileformat = EOL_UNIX;
+ if (set_options)
+ set_fileformat(EOL_UNIX, OPT_LOCAL);
+ file_rewind = TRUE;
+ keep_fileformat = TRUE;
+ goto retry;
+ }
+ ff_error = EOL_DOS;
+ }
+ }
+ if (ml_append(lnum, line_start, len, newfile) == FAIL)
+ {
+ error = TRUE;
+ break;
+ }
+#ifdef FEAT_PERSISTENT_UNDO
+ if (read_undo_file)
+ sha256_update(&sha_ctx, line_start, len);
+#endif
+ ++lnum;
+ if (--read_count == 0)
+ {
+ error = TRUE; /* break loop */
+ line_start = ptr; /* nothing left to write */
+ break;
+ }
+ }
+ else
+ --skip_count;
+ line_start = ptr + 1;
+ }
+ }
+ }
+ linerest = (long)(ptr - line_start);
+ ui_breakcheck();
+ }
+
+failed:
+ /* not an error, max. number of lines reached */
+ if (error && read_count == 0)
+ error = FALSE;
+
+ /*
+ * If we get EOF in the middle of a line, note the fact and
+ * complete the line ourselves.
+ * In Dos format ignore a trailing CTRL-Z, unless 'binary' set.
+ */
+ if (!error
+ && !got_int
+ && linerest != 0
+ && !(!curbuf->b_p_bin
+ && fileformat == EOL_DOS
+ && *line_start == Ctrl_Z
+ && ptr == line_start + 1))
+ {
+ /* remember for when writing */
+ if (set_options)
+ curbuf->b_p_eol = FALSE;
+ *ptr = NUL;
+ len = (colnr_T)(ptr - line_start + 1);
+ if (ml_append(lnum, line_start, len, newfile) == FAIL)
+ error = TRUE;
+ else
+ {
+#ifdef FEAT_PERSISTENT_UNDO
+ if (read_undo_file)
+ sha256_update(&sha_ctx, line_start, len);
+#endif
+ read_no_eol_lnum = ++lnum;
+ }
+ }
+
+ if (set_options)
+ save_file_ff(curbuf); /* remember the current file format */
+
+#ifdef FEAT_CRYPT
+ if (curbuf->b_cryptstate != NULL)
+ {
+ crypt_free_state(curbuf->b_cryptstate);
+ curbuf->b_cryptstate = NULL;
+ }
+ if (cryptkey != NULL && cryptkey != curbuf->b_p_key)
+ crypt_free_key(cryptkey);
+ /* Don't set cryptkey to NULL, it's used below as a flag that
+ * encryption was used. */
+#endif
+
+ /* If editing a new file: set 'fenc' for the current buffer.
+ * Also for ":read ++edit file". */
+ if (set_options)
+ set_string_option_direct((char_u *)"fenc", -1, fenc,
+ OPT_FREE|OPT_LOCAL, 0);
+ if (fenc_alloced)
+ vim_free(fenc);
+#ifdef USE_ICONV
+ if (iconv_fd != (iconv_t)-1)
+ {
+ iconv_close(iconv_fd);
+ iconv_fd = (iconv_t)-1;
+ }
+#endif
+
+ if (!read_buffer && !read_stdin)
+ close(fd); /* errors are ignored */
+#ifdef HAVE_FD_CLOEXEC
+ else
+ {
+ int fdflags = fcntl(fd, F_GETFD);
+ if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
+ (void)fcntl(fd, F_SETFD, fdflags | FD_CLOEXEC);
+ }
+#endif
+ vim_free(buffer);
+
+#ifdef HAVE_DUP
+ if (read_stdin)
+ {
+ /* Use stderr for stdin, makes shell commands work. */
+ close(0);
+ vim_ignored = dup(2);
+ }
+#endif
+
+ if (tmpname != NULL)
+ {
+ mch_remove(tmpname); /* delete converted file */
+ vim_free(tmpname);
+ }
+ --no_wait_return; /* may wait for return now */
+
+ /*
+ * In recovery mode everything but autocommands is skipped.
+ */
+ if (!recoverymode)
+ {
+ /* need to delete the last line, which comes from the empty buffer */
+ if (newfile && wasempty && !(curbuf->b_ml.ml_flags & ML_EMPTY))
+ {
+#ifdef FEAT_NETBEANS_INTG
+ netbeansFireChanges = 0;
+#endif
+ ml_delete(curbuf->b_ml.ml_line_count, FALSE);
+#ifdef FEAT_NETBEANS_INTG
+ netbeansFireChanges = 1;
+#endif
+ --linecnt;
+ }
+ linecnt = curbuf->b_ml.ml_line_count - linecnt;
+ if (filesize == 0)
+ linecnt = 0;
+ if (newfile || read_buffer)
+ {
+ redraw_curbuf_later(NOT_VALID);
+#ifdef FEAT_DIFF
+ /* After reading the text into the buffer the diff info needs to
+ * be updated. */
+ diff_invalidate(curbuf);
+#endif
+#ifdef FEAT_FOLDING
+ /* All folds in the window are invalid now. Mark them for update
+ * before triggering autocommands. */
+ foldUpdateAll(curwin);
+#endif
+ }
+ else if (linecnt) /* appended at least one line */
+ appended_lines_mark(from, linecnt);
+
+#ifndef ALWAYS_USE_GUI
+ /*
+ * If we were reading from the same terminal as where messages go,
+ * the screen will have been messed up.
+ * Switch on raw mode now and clear the screen.
+ */
+ if (read_stdin)
+ {
+ settmode(TMODE_RAW); /* set to raw mode */
+ starttermcap();
+ screenclear();
+ }
+#endif
+
+ if (got_int)
+ {
+ if (!(flags & READ_DUMMY))
+ {
+ filemess(curbuf, sfname, (char_u *)_(e_interr), 0);
+ if (newfile)
+ curbuf->b_p_ro = TRUE; /* must use "w!" now */
+ }
+ msg_scroll = msg_save;
+#ifdef FEAT_VIMINFO
+ check_marks_read();
+#endif
+ return OK; /* an interrupt isn't really an error */
+ }
+
+ if (!filtering && !(flags & READ_DUMMY))
+ {
+ msg_add_fname(curbuf, sfname); /* fname in IObuff with quotes */
+ c = FALSE;
+
+#ifdef UNIX
+ if (S_ISFIFO(perm)) /* fifo */
+ {
+ STRCAT(IObuff, _("[fifo]"));
+ c = TRUE;
+ }
+ if (S_ISSOCK(perm)) /* or socket */
+ {
+ STRCAT(IObuff, _("[socket]"));
+ c = TRUE;
+ }
+# ifdef OPEN_CHR_FILES
+ if (S_ISCHR(perm)) /* or character special */
+ {
+ STRCAT(IObuff, _("[character special]"));
+ c = TRUE;
+ }
+# endif
+#endif
+ if (curbuf->b_p_ro)
+ {
+ STRCAT(IObuff, shortmess(SHM_RO) ? _("[RO]") : _("[readonly]"));
+ c = TRUE;
+ }
+ if (read_no_eol_lnum)
+ {
+ msg_add_eol();
+ c = TRUE;
+ }
+ if (ff_error == EOL_DOS)
+ {
+ STRCAT(IObuff, _("[CR missing]"));
+ c = TRUE;
+ }
+ if (split)
+ {
+ STRCAT(IObuff, _("[long lines split]"));
+ c = TRUE;
+ }
+ if (notconverted)
+ {
+ STRCAT(IObuff, _("[NOT converted]"));
+ c = TRUE;
+ }
+ else if (converted)
+ {
+ STRCAT(IObuff, _("[converted]"));
+ c = TRUE;
+ }
+#ifdef FEAT_CRYPT
+ if (cryptkey != NULL)
+ {
+ crypt_append_msg(curbuf);
+ c = TRUE;
+ }
+#endif
+ if (conv_error != 0)
+ {
+ sprintf((char *)IObuff + STRLEN(IObuff),
+ _("[CONVERSION ERROR in line %ld]"), (long)conv_error);
+ c = TRUE;
+ }
+ else if (illegal_byte > 0)
+ {
+ sprintf((char *)IObuff + STRLEN(IObuff),
+ _("[ILLEGAL BYTE in line %ld]"), (long)illegal_byte);
+ c = TRUE;
+ }
+ else if (error)
+ {
+ STRCAT(IObuff, _("[READ ERRORS]"));
+ c = TRUE;
+ }
+ if (msg_add_fileformat(fileformat))
+ c = TRUE;
+#ifdef FEAT_CRYPT
+ if (cryptkey != NULL)
+ msg_add_lines(c, (long)linecnt, filesize
+ - crypt_get_header_len(crypt_get_method_nr(curbuf)));
+ else
+#endif
+ msg_add_lines(c, (long)linecnt, filesize);
+
+ VIM_CLEAR(keep_msg);
+ msg_scrolled_ign = TRUE;
+#ifdef ALWAYS_USE_GUI
+ /* Don't show the message when reading stdin, it would end up in a
+ * message box (which might be shown when exiting!) */
+ if (read_stdin || read_buffer)
+ p = msg_may_trunc(FALSE, IObuff);
+ else
+#endif
+ p = (char_u *)msg_trunc_attr((char *)IObuff, FALSE, 0);
+ if (read_stdin || read_buffer || restart_edit != 0
+ || (msg_scrolled != 0 && !need_wait_return))
+ /* Need to repeat the message after redrawing when:
+ * - When reading from stdin (the screen will be cleared next).
+ * - When restart_edit is set (otherwise there will be a delay
+ * before redrawing).
+ * - When the screen was scrolled but there is no wait-return
+ * prompt. */
+ set_keep_msg(p, 0);
+ msg_scrolled_ign = FALSE;
+ }
+
+ /* with errors writing the file requires ":w!" */
+ if (newfile && (error
+ || conv_error != 0
+ || (illegal_byte > 0 && bad_char_behavior != BAD_KEEP)))
+ curbuf->b_p_ro = TRUE;
+
+ u_clearline(); /* cannot use "U" command after adding lines */
+
+ /*
+ * In Ex mode: cursor at last new line.
+ * Otherwise: cursor at first new line.
+ */
+ if (exmode_active)
+ curwin->w_cursor.lnum = from + linecnt;
+ else
+ curwin->w_cursor.lnum = from + 1;
+ check_cursor_lnum();
+ beginline(BL_WHITE | BL_FIX); /* on first non-blank */
+
+ /*
+ * Set '[ and '] marks to the newly read lines.
+ */
+ curbuf->b_op_start.lnum = from + 1;
+ curbuf->b_op_start.col = 0;
+ curbuf->b_op_end.lnum = from + linecnt;
+ curbuf->b_op_end.col = 0;
+
+#ifdef WIN32
+ /*
+ * Work around a weird problem: When a file has two links (only
+ * possible on NTFS) and we write through one link, then stat() it
+ * through the other link, the timestamp information may be wrong.
+ * It's correct again after reading the file, thus reset the timestamp
+ * here.
+ */
+ if (newfile && !read_stdin && !read_buffer
+ && mch_stat((char *)fname, &st) >= 0)
+ {
+ buf_store_time(curbuf, &st, fname);
+ curbuf->b_mtime_read = curbuf->b_mtime;
+ }
+#endif
+ }
+ msg_scroll = msg_save;
+
+#ifdef FEAT_VIMINFO
+ /*
+ * Get the marks before executing autocommands, so they can be used there.
+ */
+ check_marks_read();
+#endif
+
+ /*
+ * We remember if the last line of the read didn't have
+ * an eol even when 'binary' is off, to support turning 'fixeol' off,
+ * or writing the read again with 'binary' on. The latter is required
+ * for ":autocmd FileReadPost *.gz set bin|'[,']!gunzip" to work.
+ */
+ curbuf->b_no_eol_lnum = read_no_eol_lnum;
+
+ /* When reloading a buffer put the cursor at the first line that is
+ * different. */
+ if (flags & READ_KEEP_UNDO)
+ u_find_first_changed();
+
+#ifdef FEAT_PERSISTENT_UNDO
+ /*
+ * When opening a new file locate undo info and read it.
+ */
+ if (read_undo_file)
+ {
+ char_u hash[UNDO_HASH_SIZE];
+
+ sha256_finish(&sha_ctx, hash);
+ u_read_undo(NULL, hash, fname);
+ }
+#endif
+
+ if (!read_stdin && !read_fifo && (!read_buffer || sfname != NULL))
+ {
+ int m = msg_scroll;
+ int n = msg_scrolled;
+
+ /* Save the fileformat now, otherwise the buffer will be considered
+ * modified if the format/encoding was automatically detected. */
+ if (set_options)
+ save_file_ff(curbuf);
+
+ /*
+ * The output from the autocommands should not overwrite anything and
+ * should not be overwritten: Set msg_scroll, restore its value if no
+ * output was done.
+ */
+ msg_scroll = TRUE;
+ if (filtering)
+ apply_autocmds_exarg(EVENT_FILTERREADPOST, NULL, sfname,
+ FALSE, curbuf, eap);
+ else if (newfile || (read_buffer && sfname != NULL))
+ {
+ apply_autocmds_exarg(EVENT_BUFREADPOST, NULL, sfname,
+ FALSE, curbuf, eap);
+ if (!au_did_filetype && *curbuf->b_p_ft != NUL)
+ /*
+ * EVENT_FILETYPE was not triggered but the buffer already has a
+ * filetype. Trigger EVENT_FILETYPE using the existing filetype.
+ */
+ apply_autocmds(EVENT_FILETYPE, curbuf->b_p_ft, curbuf->b_fname,
+ TRUE, curbuf);
+ }
+ else
+ apply_autocmds_exarg(EVENT_FILEREADPOST, sfname, sfname,
+ FALSE, NULL, eap);
+ if (msg_scrolled == n)
+ msg_scroll = m;
+# ifdef FEAT_EVAL
+ if (aborting()) /* autocmds may abort script processing */
+ return FAIL;
+# endif
+ }
+
+ if (recoverymode && error)
+ return FAIL;
+ return OK;
+}
+
+#if defined(OPEN_CHR_FILES) || defined(PROTO)
+/*
+ * Returns TRUE if the file name argument is of the form "/dev/fd/\d\+",
+ * which is the name of files used for process substitution output by
+ * some shells on some operating systems, e.g., bash on SunOS.
+ * Do not accept "/dev/fd/[012]", opening these may hang Vim.
+ */
+ int
+is_dev_fd_file(char_u *fname)
+{
+ return (STRNCMP(fname, "/dev/fd/", 8) == 0
+ && VIM_ISDIGIT(fname[8])
+ && *skipdigits(fname + 9) == NUL
+ && (fname[9] != NUL
+ || (fname[8] != '0' && fname[8] != '1' && fname[8] != '2')));
+}
+#endif
+
+/*
+ * From the current line count and characters read after that, estimate the
+ * line number where we are now.
+ * Used for error messages that include a line number.
+ */
+ static linenr_T
+readfile_linenr(
+ linenr_T linecnt, /* line count before reading more bytes */
+ char_u *p, /* start of more bytes read */
+ char_u *endp) /* end of more bytes read */
+{
+ char_u *s;
+ linenr_T lnum;
+
+ lnum = curbuf->b_ml.ml_line_count - linecnt + 1;
+ for (s = p; s < endp; ++s)
+ if (*s == '\n')
+ ++lnum;
+ return lnum;
+}
+
+/*
+ * Fill "*eap" to force the 'fileencoding', 'fileformat' and 'binary to be
+ * equal to the buffer "buf". Used for calling readfile().
+ * Returns OK or FAIL.
+ */
+ int
+prep_exarg(exarg_T *eap, buf_T *buf)
+{
+ eap->cmd = alloc(15 + (unsigned)STRLEN(buf->b_p_fenc));
+ if (eap->cmd == NULL)
+ return FAIL;
+
+ sprintf((char *)eap->cmd, "e ++enc=%s", buf->b_p_fenc);
+ eap->force_enc = 8;
+ eap->bad_char = buf->b_bad_char;
+ eap->force_ff = *buf->b_p_ff;
+
+ eap->force_bin = buf->b_p_bin ? FORCE_BIN : FORCE_NOBIN;
+ eap->read_edit = FALSE;
+ eap->forceit = FALSE;
+ return OK;
+}
+
+/*
+ * Set default or forced 'fileformat' and 'binary'.
+ */
+ void
+set_file_options(int set_options, exarg_T *eap)
+{
+ /* set default 'fileformat' */
+ if (set_options)
+ {
+ if (eap != NULL && eap->force_ff != 0)
+ set_fileformat(get_fileformat_force(curbuf, eap), OPT_LOCAL);
+ else if (*p_ffs != NUL)
+ set_fileformat(default_fileformat(), OPT_LOCAL);
+ }
+
+ /* set or reset 'binary' */
+ if (eap != NULL && eap->force_bin != 0)
+ {
+ int oldval = curbuf->b_p_bin;
+
+ curbuf->b_p_bin = (eap->force_bin == FORCE_BIN);
+ set_options_bin(oldval, curbuf->b_p_bin, OPT_LOCAL);
+ }
+}
+
+/*
+ * Set forced 'fileencoding'.
+ */
+ void
+set_forced_fenc(exarg_T *eap)
+{
+ if (eap->force_enc != 0)
+ {
+ char_u *fenc = enc_canonize(eap->cmd + eap->force_enc);
+
+ if (fenc != NULL)
+ set_string_option_direct((char_u *)"fenc", -1,
+ fenc, OPT_FREE|OPT_LOCAL, 0);
+ vim_free(fenc);
+ }
+}
+
+/*
+ * Find next fileencoding to use from 'fileencodings'.
+ * "pp" points to fenc_next. It's advanced to the next item.
+ * When there are no more items, an empty string is returned and *pp is set to
+ * NULL.
+ * When *pp is not set to NULL, the result is in allocated memory.
+ */
+ static char_u *
+next_fenc(char_u **pp)
+{
+ char_u *p;
+ char_u *r;
+
+ if (**pp == NUL)
+ {
+ *pp = NULL;
+ return (char_u *)"";
+ }
+ p = vim_strchr(*pp, ',');
+ if (p == NULL)
+ {
+ r = enc_canonize(*pp);
+ *pp += STRLEN(*pp);
+ }
+ else
+ {
+ r = vim_strnsave(*pp, (int)(p - *pp));
+ *pp = p + 1;
+ if (r != NULL)
+ {
+ p = enc_canonize(r);
+ vim_free(r);
+ r = p;
+ }
+ }
+ if (r == NULL) /* out of memory */
+ {
+ r = (char_u *)"";
+ *pp = NULL;
+ }
+ return r;
+}
+
+#ifdef FEAT_EVAL
+/*
+ * Convert a file with the 'charconvert' expression.
+ * This closes the file which is to be read, converts it and opens the
+ * resulting file for reading.
+ * Returns name of the resulting converted file (the caller should delete it
+ * after reading it).
+ * Returns NULL if the conversion failed ("*fdp" is not set) .
+ */
+ static char_u *
+readfile_charconvert(
+ char_u *fname, /* name of input file */
+ char_u *fenc, /* converted from */
+ int *fdp) /* in/out: file descriptor of file */
+{
+ char_u *tmpname;
+ char *errmsg = NULL;
+
+ tmpname = vim_tempname('r', FALSE);
+ if (tmpname == NULL)
+ errmsg = _("Can't find temp file for conversion");
+ else
+ {
+ close(*fdp); /* close the input file, ignore errors */
+ *fdp = -1;
+ if (eval_charconvert(fenc, enc_utf8 ? (char_u *)"utf-8" : p_enc,
+ fname, tmpname) == FAIL)
+ errmsg = _("Conversion with 'charconvert' failed");
+ if (errmsg == NULL && (*fdp = mch_open((char *)tmpname,
+ O_RDONLY | O_EXTRA, 0)) < 0)
+ errmsg = _("can't read output of 'charconvert'");
+ }
+
+ if (errmsg != NULL)
+ {
+ /* Don't use emsg(), it breaks mappings, the retry with
+ * another type of conversion might still work. */
+ msg(errmsg);
+ if (tmpname != NULL)
+ {
+ mch_remove(tmpname); /* delete converted file */
+ VIM_CLEAR(tmpname);
+ }
+ }
+
+ /* If the input file is closed, open it (caller should check for error). */
+ if (*fdp < 0)
+ *fdp = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0);
+
+ return tmpname;
+}
+#endif
+
+
+#ifdef FEAT_VIMINFO
+/*
+ * Read marks for the current buffer from the viminfo file, when we support
+ * buffer marks and the buffer has a name.
+ */
+ static void
+check_marks_read(void)
+{
+ if (!curbuf->b_marks_read && get_viminfo_parameter('\'') > 0
+ && curbuf->b_ffname != NULL)
+ read_viminfo(NULL, VIF_WANT_MARKS);
+
+ /* Always set b_marks_read; needed when 'viminfo' is changed to include
+ * the ' parameter after opening a buffer. */
+ curbuf->b_marks_read = TRUE;
+}
+#endif
+
+#if defined(FEAT_CRYPT) || defined(PROTO)
+/*
+ * Check for magic number used for encryption. Applies to the current buffer.
+ * If found, the magic number is removed from ptr[*sizep] and *sizep and
+ * *filesizep are updated.
+ * Return the (new) encryption key, NULL for no encryption.
+ */
+ static char_u *
+check_for_cryptkey(
+ char_u *cryptkey, /* previous encryption key or NULL */
+ char_u *ptr, /* pointer to read bytes */
+ long *sizep, /* length of read bytes */
+ off_T *filesizep, /* nr of bytes used from file */
+ int newfile, /* editing a new buffer */
+ char_u *fname, /* file name to display */
+ int *did_ask) /* flag: whether already asked for key */
+{
+ int method = crypt_method_nr_from_magic((char *)ptr, *sizep);
+ int b_p_ro = curbuf->b_p_ro;
+
+ if (method >= 0)
+ {
+ /* Mark the buffer as read-only until the decryption has taken place.
+ * Avoids accidentally overwriting the file with garbage. */
+ curbuf->b_p_ro = TRUE;
+
+ /* Set the cryptmethod local to the buffer. */
+ crypt_set_cm_option(curbuf, method);
+ if (cryptkey == NULL && !*did_ask)
+ {
+ if (*curbuf->b_p_key)
+ cryptkey = curbuf->b_p_key;
+ else
+ {
+ /* When newfile is TRUE, store the typed key in the 'key'
+ * option and don't free it. bf needs hash of the key saved.
+ * Don't ask for the key again when first time Enter was hit.
+ * Happens when retrying to detect encoding. */
+ smsg(_(need_key_msg), fname);
+ msg_scroll = TRUE;
+ crypt_check_method(method);
+ cryptkey = crypt_get_key(newfile, FALSE);
+ *did_ask = TRUE;
+
+ /* check if empty key entered */
+ if (cryptkey != NULL && *cryptkey == NUL)
+ {
+ if (cryptkey != curbuf->b_p_key)
+ vim_free(cryptkey);
+ cryptkey = NULL;
+ }
+ }
+ }
+
+ if (cryptkey != NULL)
+ {
+ int header_len;
+
+ curbuf->b_cryptstate = crypt_create_from_header(
+ method, cryptkey, ptr);
+ crypt_set_cm_option(curbuf, method);
+
+ /* Remove cryptmethod specific header from the text. */
+ header_len = crypt_get_header_len(method);
+ if (*sizep <= header_len)
+ /* invalid header, buffer can't be encrypted */
+ return NULL;
+ *filesizep += header_len;
+ *sizep -= header_len;
+ mch_memmove(ptr, ptr + header_len, (size_t)*sizep);
+
+ /* Restore the read-only flag. */
+ curbuf->b_p_ro = b_p_ro;
+ }
+ }
+ /* When starting to edit a new file which does not have encryption, clear
+ * the 'key' option, except when starting up (called with -x argument) */
+ else if (newfile && *curbuf->b_p_key != NUL && !starting)
+ set_option_value((char_u *)"key", 0L, (char_u *)"", OPT_LOCAL);
+
+ return cryptkey;
+}
+#endif /* FEAT_CRYPT */
+
+#ifdef UNIX
+ static void
+set_file_time(
+ char_u *fname,
+ time_t atime, /* access time */
+ time_t mtime) /* modification time */
+{
+# if defined(HAVE_UTIME) && defined(HAVE_UTIME_H)
+ struct utimbuf buf;
+
+ buf.actime = atime;
+ buf.modtime = mtime;
+ (void)utime((char *)fname, &buf);
+# else
+# if defined(HAVE_UTIMES)
+ struct timeval tvp[2];
+
+ tvp[0].tv_sec = atime;
+ tvp[0].tv_usec = 0;
+ tvp[1].tv_sec = mtime;
+ tvp[1].tv_usec = 0;
+# ifdef NeXT
+ (void)utimes((char *)fname, tvp);
+# else
+ (void)utimes((char *)fname, (const struct timeval *)&tvp);
+# endif
+# endif
+# endif
+}
+#endif /* UNIX */
+
+#if defined(VMS) && !defined(MIN)
+/* Older DECC compiler for VAX doesn't define MIN() */
+# define MIN(a, b) ((a) < (b) ? (a) : (b))
+#endif
+
+/*
+ * Return TRUE if a file appears to be read-only from the file permissions.
+ */
+ int
+check_file_readonly(
+ char_u *fname, /* full path to file */
+ int perm) /* known permissions on file */
+{
+#ifndef USE_MCH_ACCESS
+ int fd = 0;
+#endif
+
+ return (
+#ifdef USE_MCH_ACCESS
+# ifdef UNIX
+ (perm & 0222) == 0 ||
+# endif
+ mch_access((char *)fname, W_OK)
+#else
+ (fd = mch_open((char *)fname, O_RDWR | O_EXTRA, 0)) < 0
+ ? TRUE : (close(fd), FALSE)
+#endif
+ );
+}
+
+
+/*
+ * buf_write() - write to file "fname" lines "start" through "end"
+ *
+ * We do our own buffering here because fwrite() is so slow.
+ *
+ * If "forceit" is true, we don't care for errors when attempting backups.
+ * In case of an error everything possible is done to restore the original
+ * file. But when "forceit" is TRUE, we risk losing it.
+ *
+ * When "reset_changed" is TRUE and "append" == FALSE and "start" == 1 and
+ * "end" == curbuf->b_ml.ml_line_count, reset curbuf->b_changed.
+ *
+ * This function must NOT use NameBuff (because it's called by autowrite()).
+ *
+ * return FAIL for failure, OK otherwise
+ */
+ int
+buf_write(
+ buf_T *buf,
+ char_u *fname,
+ char_u *sfname,
+ linenr_T start,
+ linenr_T end,
+ exarg_T *eap, /* for forced 'ff' and 'fenc', can be
+ NULL! */
+ int append, /* append to the file */
+ int forceit,
+ int reset_changed,
+ int filtering)
+{
+ int fd;
+ char_u *backup = NULL;
+ int backup_copy = FALSE; /* copy the original file? */
+ int dobackup;
+ char_u *ffname;
+ char_u *wfname = NULL; /* name of file to write to */
+ char_u *s;
+ char_u *ptr;
+ char_u c;
+ int len;
+ linenr_T lnum;
+ long nchars;
+ char_u *errmsg = NULL;
+ int errmsg_allocated = FALSE;
+ char_u *errnum = NULL;
+ char_u *buffer;
+ char_u smallbuf[SMBUFSIZE];
+ char_u *backup_ext;
+ int bufsize;
+ long perm; /* file permissions */
+ int retval = OK;
+ int newfile = FALSE; /* TRUE if file doesn't exist yet */
+ int msg_save = msg_scroll;
+ int overwriting; /* TRUE if writing over original */
+ int no_eol = FALSE; /* no end-of-line written */
+ int device = FALSE; /* writing to a device */
+ stat_T st_old;
+ int prev_got_int = got_int;
+ int checking_conversion;
+ int file_readonly = FALSE; /* overwritten file is read-only */
+ static char *err_readonly = "is read-only (cannot override: \"W\" in 'cpoptions')";
+#if defined(UNIX) /*XXX fix me sometime? */
+ int made_writable = FALSE; /* 'w' bit has been set */
+#endif
+ /* writing everything */
+ int whole = (start == 1 && end == buf->b_ml.ml_line_count);
+ linenr_T old_line_count = buf->b_ml.ml_line_count;
+ int attr;
+ int fileformat;
+ int write_bin;
+ struct bw_info write_info; /* info for buf_write_bytes() */
+ int converted = FALSE;
+ int notconverted = FALSE;
+ char_u *fenc; /* effective 'fileencoding' */
+ char_u *fenc_tofree = NULL; /* allocated "fenc" */
+#ifdef HAS_BW_FLAGS
+ int wb_flags = 0;
+#endif
+#ifdef HAVE_ACL
+ vim_acl_T acl = NULL; /* ACL copied from original file to
+ backup or new file */
+#endif
+#ifdef FEAT_PERSISTENT_UNDO
+ int write_undo_file = FALSE;
+ context_sha256_T sha_ctx;
+#endif
+ unsigned int bkc = get_bkc_value(buf);
+
+ if (fname == NULL || *fname == NUL) /* safety check */
+ return FAIL;
+ if (buf->b_ml.ml_mfp == NULL)
+ {
+ /* This can happen during startup when there is a stray "w" in the
+ * vimrc file. */
+ emsg(_(e_emptybuf));
+ return FAIL;
+ }
+
+ /*
+ * Disallow writing from .exrc and .vimrc in current directory for
+ * security reasons.
+ */
+ if (check_secure())
+ return FAIL;
+
+ /* Avoid a crash for a long name. */
+ if (STRLEN(fname) >= MAXPATHL)
+ {
+ emsg(_(e_longname));
+ return FAIL;
+ }
+
+ /* must init bw_conv_buf and bw_iconv_fd before jumping to "fail" */
+ write_info.bw_conv_buf = NULL;
+ write_info.bw_conv_error = FALSE;
+ write_info.bw_conv_error_lnum = 0;
+ write_info.bw_restlen = 0;
+#ifdef USE_ICONV
+ write_info.bw_iconv_fd = (iconv_t)-1;
+#endif
+#ifdef FEAT_CRYPT
+ write_info.bw_buffer = buf;
+#endif
+
+ /* After writing a file changedtick changes but we don't want to display
+ * the line. */
+ ex_no_reprint = TRUE;
+
+ /*
+ * If there is no file name yet, use the one for the written file.
+ * BF_NOTEDITED is set to reflect this (in case the write fails).
+ * Don't do this when the write is for a filter command.
+ * Don't do this when appending.
+ * Only do this when 'cpoptions' contains the 'F' flag.
+ */
+ if (buf->b_ffname == NULL
+ && reset_changed
+ && whole
+ && buf == curbuf
+#ifdef FEAT_QUICKFIX
+ && !bt_nofile(buf)
+#endif
+ && !filtering
+ && (!append || vim_strchr(p_cpo, CPO_FNAMEAPP) != NULL)
+ && vim_strchr(p_cpo, CPO_FNAMEW) != NULL)
+ {
+ if (set_rw_fname(fname, sfname) == FAIL)
+ return FAIL;
+ buf = curbuf; /* just in case autocmds made "buf" invalid */
+ }
+
+ if (sfname == NULL)
+ sfname = fname;
+ /*
+ * For Unix: Use the short file name whenever possible.
+ * Avoids problems with networks and when directory names are changed.
+ * Don't do this for MS-DOS, a "cd" in a sub-shell may have moved us to
+ * another directory, which we don't detect
+ */
+ ffname = fname; /* remember full fname */
+#ifdef UNIX
+ fname = sfname;
+#endif
+
+ if (buf->b_ffname != NULL && fnamecmp(ffname, buf->b_ffname) == 0)
+ overwriting = TRUE;
+ else
+ overwriting = FALSE;
+
+ if (exiting)
+ settmode(TMODE_COOK); /* when exiting allow typeahead now */
+
+ ++no_wait_return; /* don't wait for return yet */
+
+ /*
+ * Set '[ and '] marks to the lines to be written.
+ */
+ buf->b_op_start.lnum = start;
+ buf->b_op_start.col = 0;
+ buf->b_op_end.lnum = end;
+ buf->b_op_end.col = 0;
+
+ {
+ aco_save_T aco;
+ int buf_ffname = FALSE;
+ int buf_sfname = FALSE;
+ int buf_fname_f = FALSE;
+ int buf_fname_s = FALSE;
+ int did_cmd = FALSE;
+ int nofile_err = FALSE;
+ int empty_memline = (buf->b_ml.ml_mfp == NULL);
+ bufref_T bufref;
+
+ /*
+ * Apply PRE autocommands.
+ * Set curbuf to the buffer to be written.
+ * Careful: The autocommands may call buf_write() recursively!
+ */
+ if (ffname == buf->b_ffname)
+ buf_ffname = TRUE;
+ if (sfname == buf->b_sfname)
+ buf_sfname = TRUE;
+ if (fname == buf->b_ffname)
+ buf_fname_f = TRUE;
+ if (fname == buf->b_sfname)
+ buf_fname_s = TRUE;
+
+ /* set curwin/curbuf to buf and save a few things */
+ aucmd_prepbuf(&aco, buf);
+ set_bufref(&bufref, buf);
+
+ if (append)
+ {
+ if (!(did_cmd = apply_autocmds_exarg(EVENT_FILEAPPENDCMD,
+ sfname, sfname, FALSE, curbuf, eap)))
+ {
+#ifdef FEAT_QUICKFIX
+ if (overwriting && bt_nofile(curbuf))
+ nofile_err = TRUE;
+ else
+#endif
+ apply_autocmds_exarg(EVENT_FILEAPPENDPRE,
+ sfname, sfname, FALSE, curbuf, eap);
+ }
+ }
+ else if (filtering)
+ {
+ apply_autocmds_exarg(EVENT_FILTERWRITEPRE,
+ NULL, sfname, FALSE, curbuf, eap);
+ }
+ else if (reset_changed && whole)
+ {
+ int was_changed = curbufIsChanged();
+
+ did_cmd = apply_autocmds_exarg(EVENT_BUFWRITECMD,
+ sfname, sfname, FALSE, curbuf, eap);
+ if (did_cmd)
+ {
+ if (was_changed && !curbufIsChanged())
+ {
+ /* Written everything correctly and BufWriteCmd has reset
+ * 'modified': Correct the undo information so that an
+ * undo now sets 'modified'. */
+ u_unchanged(curbuf);
+ u_update_save_nr(curbuf);
+ }
+ }
+ else
+ {
+#ifdef FEAT_QUICKFIX
+ if (overwriting && bt_nofile(curbuf))
+ nofile_err = TRUE;
+ else
+#endif
+ apply_autocmds_exarg(EVENT_BUFWRITEPRE,
+ sfname, sfname, FALSE, curbuf, eap);
+ }
+ }
+ else
+ {
+ if (!(did_cmd = apply_autocmds_exarg(EVENT_FILEWRITECMD,
+ sfname, sfname, FALSE, curbuf, eap)))
+ {
+#ifdef FEAT_QUICKFIX
+ if (overwriting && bt_nofile(curbuf))
+ nofile_err = TRUE;
+ else
+#endif
+ apply_autocmds_exarg(EVENT_FILEWRITEPRE,
+ sfname, sfname, FALSE, curbuf, eap);
+ }
+ }
+
+ /* restore curwin/curbuf and a few other things */
+ aucmd_restbuf(&aco);
+
+ /*
+ * In three situations we return here and don't write the file:
+ * 1. the autocommands deleted or unloaded the buffer.
+ * 2. The autocommands abort script processing.
+ * 3. If one of the "Cmd" autocommands was executed.
+ */
+ if (!bufref_valid(&bufref))
+ buf = NULL;
+ if (buf == NULL || (buf->b_ml.ml_mfp == NULL && !empty_memline)
+ || did_cmd || nofile_err
+#ifdef FEAT_EVAL
+ || aborting()
+#endif
+ )
+ {
+ --no_wait_return;
+ msg_scroll = msg_save;
+ if (nofile_err)
+ emsg(_("E676: No matching autocommands for acwrite buffer"));
+
+ if (nofile_err
+#ifdef FEAT_EVAL
+ || aborting()
+#endif
+ )
+ /* An aborting error, interrupt or exception in the
+ * autocommands. */
+ return FAIL;
+ if (did_cmd)
+ {
+ if (buf == NULL)
+ /* The buffer was deleted. We assume it was written
+ * (can't retry anyway). */
+ return OK;
+ if (overwriting)
+ {
+ /* Assume the buffer was written, update the timestamp. */
+ ml_timestamp(buf);
+ if (append)
+ buf->b_flags &= ~BF_NEW;
+ else
+ buf->b_flags &= ~BF_WRITE_MASK;
+ }
+ if (reset_changed && buf->b_changed && !append
+ && (overwriting || vim_strchr(p_cpo, CPO_PLUS) != NULL))
+ /* Buffer still changed, the autocommands didn't work
+ * properly. */
+ return FAIL;
+ return OK;
+ }
+#ifdef FEAT_EVAL
+ if (!aborting())
+#endif
+ emsg(_("E203: Autocommands deleted or unloaded buffer to be written"));
+ return FAIL;
+ }
+
+ /*
+ * The autocommands may have changed the number of lines in the file.
+ * When writing the whole file, adjust the end.
+ * When writing part of the file, assume that the autocommands only
+ * changed the number of lines that are to be written (tricky!).
+ */
+ if (buf->b_ml.ml_line_count != old_line_count)
+ {
+ if (whole) /* write all */
+ end = buf->b_ml.ml_line_count;
+ else if (buf->b_ml.ml_line_count > old_line_count) /* more lines */
+ end += buf->b_ml.ml_line_count - old_line_count;
+ else /* less lines */
+ {
+ end -= old_line_count - buf->b_ml.ml_line_count;
+ if (end < start)
+ {
+ --no_wait_return;
+ msg_scroll = msg_save;
+ emsg(_("E204: Autocommand changed number of lines in unexpected way"));
+ return FAIL;
+ }
+ }
+ }
+
+ /*
+ * The autocommands may have changed the name of the buffer, which may
+ * be kept in fname, ffname and sfname.
+ */
+ if (buf_ffname)
+ ffname = buf->b_ffname;
+ if (buf_sfname)
+ sfname = buf->b_sfname;
+ if (buf_fname_f)
+ fname = buf->b_ffname;
+ if (buf_fname_s)
+ fname = buf->b_sfname;
+ }
+
+#ifdef FEAT_NETBEANS_INTG
+ if (netbeans_active() && isNetbeansBuffer(buf))
+ {
+ if (whole)
+ {
+ /*
+ * b_changed can be 0 after an undo, but we still need to write
+ * the buffer to NetBeans.
+ */
+ if (buf->b_changed || isNetbeansModified(buf))
+ {
+ --no_wait_return; /* may wait for return now */
+ msg_scroll = msg_save;
+ netbeans_save_buffer(buf); /* no error checking... */
+ return retval;
+ }
+ else
+ {
+ errnum = (char_u *)"E656: ";
+ errmsg = (char_u *)_("NetBeans disallows writes of unmodified buffers");
+ buffer = NULL;
+ goto fail;
+ }
+ }
+ else
+ {
+ errnum = (char_u *)"E657: ";
+ errmsg = (char_u *)_("Partial writes disallowed for NetBeans buffers");
+ buffer = NULL;
+ goto fail;
+ }
+ }
+#endif
+
+ if (shortmess(SHM_OVER) && !exiting)
+ msg_scroll = FALSE; /* overwrite previous file message */
+ else
+ msg_scroll = TRUE; /* don't overwrite previous file message */
+ if (!filtering)
+ filemess(buf,
+#ifndef UNIX
+ sfname,
+#else
+ fname,
+#endif
+ (char_u *)"", 0); /* show that we are busy */
+ msg_scroll = FALSE; /* always overwrite the file message now */
+
+ buffer = alloc(BUFSIZE);
+ if (buffer == NULL) /* can't allocate big buffer, use small
+ * one (to be able to write when out of
+ * memory) */
+ {
+ buffer = smallbuf;
+ bufsize = SMBUFSIZE;
+ }
+ else
+ bufsize = BUFSIZE;
+
+ /*
+ * Get information about original file (if there is one).
+ */
+#if defined(UNIX)
+ st_old.st_dev = 0;
+ st_old.st_ino = 0;
+ perm = -1;
+ if (mch_stat((char *)fname, &st_old) < 0)
+ newfile = TRUE;
+ else
+ {
+ perm = st_old.st_mode;
+ if (!S_ISREG(st_old.st_mode)) /* not a file */
+ {
+ if (S_ISDIR(st_old.st_mode))
+ {
+ errnum = (char_u *)"E502: ";
+ errmsg = (char_u *)_("is a directory");
+ goto fail;
+ }
+ if (mch_nodetype(fname) != NODE_WRITABLE)
+ {
+ errnum = (char_u *)"E503: ";
+ errmsg = (char_u *)_("is not a file or writable device");
+ goto fail;
+ }
+ /* It's a device of some kind (or a fifo) which we can write to
+ * but for which we can't make a backup. */
+ device = TRUE;
+ newfile = TRUE;
+ perm = -1;
+ }
+ }
+#else /* !UNIX */
+ /*
+ * Check for a writable device name.
+ */
+ c = mch_nodetype(fname);
+ if (c == NODE_OTHER)
+ {
+ errnum = (char_u *)"E503: ";
+ errmsg = (char_u *)_("is not a file or writable device");
+ goto fail;
+ }
+ if (c == NODE_WRITABLE)
+ {
+# if defined(MSWIN)
+ /* MS-Windows allows opening a device, but we will probably get stuck
+ * trying to write to it. */
+ if (!p_odev)
+ {
+ errnum = (char_u *)"E796: ";
+ errmsg = (char_u *)_("writing to device disabled with 'opendevice' option");
+ goto fail;
+ }
+# endif
+ device = TRUE;
+ newfile = TRUE;
+ perm = -1;
+ }
+ else
+ {
+ perm = mch_getperm(fname);
+ if (perm < 0)
+ newfile = TRUE;
+ else if (mch_isdir(fname))
+ {
+ errnum = (char_u *)"E502: ";
+ errmsg = (char_u *)_("is a directory");
+ goto fail;
+ }
+ if (overwriting)
+ (void)mch_stat((char *)fname, &st_old);
+ }
+#endif /* !UNIX */
+
+ if (!device && !newfile)
+ {
+ /*
+ * Check if the file is really writable (when renaming the file to
+ * make a backup we won't discover it later).
+ */
+ file_readonly = check_file_readonly(fname, (int)perm);
+
+ if (!forceit && file_readonly)
+ {
+ if (vim_strchr(p_cpo, CPO_FWRITE) != NULL)
+ {
+ errnum = (char_u *)"E504: ";
+ errmsg = (char_u *)_(err_readonly);
+ }
+ else
+ {
+ errnum = (char_u *)"E505: ";
+ errmsg = (char_u *)_("is read-only (add ! to override)");
+ }
+ goto fail;
+ }
+
+ /*
+ * Check if the timestamp hasn't changed since reading the file.
+ */
+ if (overwriting)
+ {
+ retval = check_mtime(buf, &st_old);
+ if (retval == FAIL)
+ goto fail;
+ }
+ }
+
+#ifdef HAVE_ACL
+ /*
+ * For systems that support ACL: get the ACL from the original file.
+ */
+ if (!newfile)
+ acl = mch_get_acl(fname);
+#endif
+
+ /*
+ * If 'backupskip' is not empty, don't make a backup for some files.
+ */
+ dobackup = (p_wb || p_bk || *p_pm != NUL);
+#ifdef FEAT_WILDIGN
+ if (dobackup && *p_bsk != NUL && match_file_list(p_bsk, sfname, ffname))
+ dobackup = FALSE;
+#endif
+
+ /*
+ * Save the value of got_int and reset it. We don't want a previous
+ * interruption cancel writing, only hitting CTRL-C while writing should
+ * abort it.
+ */
+ prev_got_int = got_int;
+ got_int = FALSE;
+
+ /* Mark the buffer as 'being saved' to prevent changed buffer warnings */
+ buf->b_saving = TRUE;
+
+ /*
+ * If we are not appending or filtering, the file exists, and the
+ * 'writebackup', 'backup' or 'patchmode' option is set, need a backup.
+ * When 'patchmode' is set also make a backup when appending.
+ *
+ * Do not make any backup, if 'writebackup' and 'backup' are both switched
+ * off. This helps when editing large files on almost-full disks.
+ */
+ if (!(append && *p_pm == NUL) && !filtering && perm >= 0 && dobackup)
+ {
+#if defined(UNIX) || defined(WIN32)
+ stat_T st;
+#endif
+
+ if ((bkc & BKC_YES) || append) /* "yes" */
+ backup_copy = TRUE;
+#if defined(UNIX) || defined(WIN32)
+ else if ((bkc & BKC_AUTO)) /* "auto" */
+ {
+ int i;
+
+# ifdef UNIX
+ /*
+ * Don't rename the file when:
+ * - it's a hard link
+ * - it's a symbolic link
+ * - we don't have write permission in the directory
+ * - we can't set the owner/group of the new file
+ */
+ if (st_old.st_nlink > 1
+ || mch_lstat((char *)fname, &st) < 0
+ || st.st_dev != st_old.st_dev
+ || st.st_ino != st_old.st_ino
+# ifndef HAVE_FCHOWN
+ || st.st_uid != st_old.st_uid
+ || st.st_gid != st_old.st_gid
+# endif
+ )
+ backup_copy = TRUE;
+ else
+# else
+# ifdef WIN32
+ /* On NTFS file systems hard links are possible. */
+ if (mch_is_linked(fname))
+ backup_copy = TRUE;
+ else
+# endif
+# endif
+ {
+ /*
+ * Check if we can create a file and set the owner/group to
+ * the ones from the original file.
+ * First find a file name that doesn't exist yet (use some
+ * arbitrary numbers).
+ */
+ STRCPY(IObuff, fname);
+ for (i = 4913; ; i += 123)
+ {
+ sprintf((char *)gettail(IObuff), "%d", i);
+ if (mch_lstat((char *)IObuff, &st) < 0)
+ break;
+ }
+ fd = mch_open((char *)IObuff,
+ O_CREAT|O_WRONLY|O_EXCL|O_NOFOLLOW, perm);
+ if (fd < 0) /* can't write in directory */
+ backup_copy = TRUE;
+ else
+ {
+# ifdef UNIX
+# ifdef HAVE_FCHOWN
+ vim_ignored = fchown(fd, st_old.st_uid, st_old.st_gid);
+# endif
+ if (mch_stat((char *)IObuff, &st) < 0
+ || st.st_uid != st_old.st_uid
+ || st.st_gid != st_old.st_gid
+ || (long)st.st_mode != perm)
+ backup_copy = TRUE;
+# endif
+ /* Close the file before removing it, on MS-Windows we
+ * can't delete an open file. */
+ close(fd);
+ mch_remove(IObuff);
+# ifdef MSWIN
+ /* MS-Windows may trigger a virus scanner to open the
+ * file, we can't delete it then. Keep trying for half a
+ * second. */
+ {
+ int try;
+
+ for (try = 0; try < 10; ++try)
+ {
+ if (mch_lstat((char *)IObuff, &st) < 0)
+ break;
+ ui_delay(50L, TRUE); /* wait 50 msec */
+ mch_remove(IObuff);
+ }
+ }
+# endif
+ }
+ }
+ }
+
+ /*
+ * Break symlinks and/or hardlinks if we've been asked to.
+ */
+ if ((bkc & BKC_BREAKSYMLINK) || (bkc & BKC_BREAKHARDLINK))
+ {
+# ifdef UNIX
+ int lstat_res;
+
+ lstat_res = mch_lstat((char *)fname, &st);
+
+ /* Symlinks. */
+ if ((bkc & BKC_BREAKSYMLINK)
+ && lstat_res == 0
+ && st.st_ino != st_old.st_ino)
+ backup_copy = FALSE;
+
+ /* Hardlinks. */
+ if ((bkc & BKC_BREAKHARDLINK)
+ && st_old.st_nlink > 1
+ && (lstat_res != 0 || st.st_ino == st_old.st_ino))
+ backup_copy = FALSE;
+# else
+# if defined(WIN32)
+ /* Symlinks. */
+ if ((bkc & BKC_BREAKSYMLINK) && mch_is_symbolic_link(fname))
+ backup_copy = FALSE;
+
+ /* Hardlinks. */
+ if ((bkc & BKC_BREAKHARDLINK) && mch_is_hard_link(fname))
+ backup_copy = FALSE;
+# endif
+# endif
+ }
+
+#endif
+
+ /* make sure we have a valid backup extension to use */
+ if (*p_bex == NUL)
+ backup_ext = (char_u *)".bak";
+ else
+ backup_ext = p_bex;
+
+ if (backup_copy
+ && (fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0)) >= 0)
+ {
+ int bfd;
+ char_u *copybuf, *wp;
+ int some_error = FALSE;
+ stat_T st_new;
+ char_u *dirp;
+ char_u *rootname;
+#if defined(UNIX) || defined(WIN3264)
+ char_u *p;
+#endif
+#if defined(UNIX)
+ int did_set_shortname;
+ mode_t umask_save;
+#endif
+
+ copybuf = alloc(BUFSIZE + 1);
+ if (copybuf == NULL)
+ {
+ some_error = TRUE; /* out of memory */
+ goto nobackup;
+ }
+
+ /*
+ * Try to make the backup in each directory in the 'bdir' option.
+ *
+ * Unix semantics has it, that we may have a writable file,
+ * that cannot be recreated with a simple open(..., O_CREAT, ) e.g:
+ * - the directory is not writable,
+ * - the file may be a symbolic link,
+ * - the file may belong to another user/group, etc.
+ *
+ * For these reasons, the existing writable file must be truncated
+ * and reused. Creation of a backup COPY will be attempted.
+ */
+ dirp = p_bdir;
+ while (*dirp)
+ {
+#ifdef UNIX
+ st_new.st_ino = 0;
+ st_new.st_dev = 0;
+ st_new.st_gid = 0;
+#endif
+
+ /*
+ * Isolate one directory name, using an entry in 'bdir'.
+ */
+ (void)copy_option_part(&dirp, copybuf, BUFSIZE, ",");
+
+#if defined(UNIX) || defined(WIN3264)
+ p = copybuf + STRLEN(copybuf);
+ if (after_pathsep(copybuf, p) && p[-1] == p[-2])
+ // Ends with '//', use full path
+ if ((p = make_percent_swname(copybuf, fname)) != NULL)
+ {
+ backup = modname(p, backup_ext, FALSE);
+ vim_free(p);
+ }
+#endif
+ rootname = get_file_in_dir(fname, copybuf);
+ if (rootname == NULL)
+ {
+ some_error = TRUE; /* out of memory */
+ goto nobackup;
+ }
+
+#if defined(UNIX)
+ did_set_shortname = FALSE;
+#endif
+
+ /*
+ * May try twice if 'shortname' not set.
+ */
+ for (;;)
+ {
+ /*
+ * Make the backup file name.
+ */
+ if (backup == NULL)
+ backup = buf_modname((buf->b_p_sn || buf->b_shortname),
+ rootname, backup_ext, FALSE);
+ if (backup == NULL)
+ {
+ vim_free(rootname);
+ some_error = TRUE; /* out of memory */
+ goto nobackup;
+ }
+
+ /*
+ * Check if backup file already exists.
+ */
+ if (mch_stat((char *)backup, &st_new) >= 0)
+ {
+#ifdef UNIX
+ /*
+ * Check if backup file is same as original file.
+ * May happen when modname() gave the same file back.
+ * E.g. silly link, or file name-length reached.
+ * If we don't check here, we either ruin the file
+ * when copying or erase it after writing. jw.
+ */
+ if (st_new.st_dev == st_old.st_dev
+ && st_new.st_ino == st_old.st_ino)
+ {
+ VIM_CLEAR(backup); /* no backup file to delete */
+ /*
+ * may try again with 'shortname' set
+ */
+ if (!(buf->b_shortname || buf->b_p_sn))
+ {
+ buf->b_shortname = TRUE;
+ did_set_shortname = TRUE;
+ continue;
+ }
+ /* setting shortname didn't help */
+ if (did_set_shortname)
+ buf->b_shortname = FALSE;
+ break;
+ }
+#endif
+
+ /*
+ * If we are not going to keep the backup file, don't
+ * delete an existing one, try to use another name.
+ * Change one character, just before the extension.
+ */
+ if (!p_bk)
+ {
+ wp = backup + STRLEN(backup) - 1
+ - STRLEN(backup_ext);
+ if (wp < backup) /* empty file name ??? */
+ wp = backup;
+ *wp = 'z';
+ while (*wp > 'a'
+ && mch_stat((char *)backup, &st_new) >= 0)
+ --*wp;
+ /* They all exist??? Must be something wrong. */
+ if (*wp == 'a')
+ VIM_CLEAR(backup);
+ }
+ }
+ break;
+ }
+ vim_free(rootname);
+
+ /*
+ * Try to create the backup file
+ */
+ if (backup != NULL)
+ {
+ /* remove old backup, if present */
+ mch_remove(backup);
+ /* Open with O_EXCL to avoid the file being created while
+ * we were sleeping (symlink hacker attack?). Reset umask
+ * if possible to avoid mch_setperm() below. */
+#ifdef UNIX
+ umask_save = umask(0);
+#endif
+ bfd = mch_open((char *)backup,
+ O_WRONLY|O_CREAT|O_EXTRA|O_EXCL|O_NOFOLLOW,
+ perm & 0777);
+#ifdef UNIX
+ (void)umask(umask_save);
+#endif
+ if (bfd < 0)
+ VIM_CLEAR(backup);
+ else
+ {
+ /* Set file protection same as original file, but
+ * strip s-bit. Only needed if umask() wasn't used
+ * above. */
+#ifndef UNIX
+ (void)mch_setperm(backup, perm & 0777);
+#else
+ /*
+ * Try to set the group of the backup same as the
+ * original file. If this fails, set the protection
+ * bits for the group same as the protection bits for
+ * others.
+ */
+ if (st_new.st_gid != st_old.st_gid
+# ifdef HAVE_FCHOWN /* sequent-ptx lacks fchown() */
+ && fchown(bfd, (uid_t)-1, st_old.st_gid) != 0
+# endif
+ )
+ mch_setperm(backup,
+ (perm & 0707) | ((perm & 07) << 3));
+# if defined(HAVE_SELINUX) || defined(HAVE_SMACK)
+ mch_copy_sec(fname, backup);
+# endif
+#endif
+
+ /*
+ * copy the file.
+ */
+ write_info.bw_fd = bfd;
+ write_info.bw_buf = copybuf;
+#ifdef HAS_BW_FLAGS
+ write_info.bw_flags = FIO_NOCONVERT;
+#endif
+ while ((write_info.bw_len = read_eintr(fd, copybuf,
+ BUFSIZE)) > 0)
+ {
+ if (buf_write_bytes(&write_info) == FAIL)
+ {
+ errmsg = (char_u *)_("E506: Can't write to backup file (add ! to override)");
+ break;
+ }
+ ui_breakcheck();
+ if (got_int)
+ {
+ errmsg = (char_u *)_(e_interr);
+ break;
+ }
+ }
+
+ if (close(bfd) < 0 && errmsg == NULL)
+ errmsg = (char_u *)_("E507: Close error for backup file (add ! to override)");
+ if (write_info.bw_len < 0)
+ errmsg = (char_u *)_("E508: Can't read file for backup (add ! to override)");
+#ifdef UNIX
+ set_file_time(backup, st_old.st_atime, st_old.st_mtime);
+#endif
+#ifdef HAVE_ACL
+ mch_set_acl(backup, acl);
+#endif
+#if defined(HAVE_SELINUX) || defined(HAVE_SMACK)
+ mch_copy_sec(fname, backup);
+#endif
+ break;
+ }
+ }
+ }
+ nobackup:
+ close(fd); /* ignore errors for closing read file */
+ vim_free(copybuf);
+
+ if (backup == NULL && errmsg == NULL)
+ errmsg = (char_u *)_("E509: Cannot create backup file (add ! to override)");
+ /* ignore errors when forceit is TRUE */
+ if ((some_error || errmsg != NULL) && !forceit)
+ {
+ retval = FAIL;
+ goto fail;
+ }
+ errmsg = NULL;
+ }
+ else
+ {
+ char_u *dirp;
+ char_u *p;
+ char_u *rootname;
+
+ /*
+ * Make a backup by renaming the original file.
+ */
+ /*
+ * If 'cpoptions' includes the "W" flag, we don't want to
+ * overwrite a read-only file. But rename may be possible
+ * anyway, thus we need an extra check here.
+ */
+ if (file_readonly && vim_strchr(p_cpo, CPO_FWRITE) != NULL)
+ {
+ errnum = (char_u *)"E504: ";
+ errmsg = (char_u *)_(err_readonly);
+ goto fail;
+ }
+
+ /*
+ *
+ * Form the backup file name - change path/fo.o.h to
+ * path/fo.o.h.bak Try all directories in 'backupdir', first one
+ * that works is used.
+ */
+ dirp = p_bdir;
+ while (*dirp)
+ {
+ /*
+ * Isolate one directory name and make the backup file name.
+ */
+ (void)copy_option_part(&dirp, IObuff, IOSIZE, ",");
+
+#if defined(UNIX) || defined(WIN3264)
+ p = IObuff + STRLEN(IObuff);
+ if (after_pathsep(IObuff, p) && p[-1] == p[-2])
+ // path ends with '//', use full path
+ if ((p = make_percent_swname(IObuff, fname)) != NULL)
+ {
+ backup = modname(p, backup_ext, FALSE);
+ vim_free(p);
+ }
+#endif
+ if (backup == NULL)
+ {
+ rootname = get_file_in_dir(fname, IObuff);
+ if (rootname == NULL)
+ backup = NULL;
+ else
+ {
+ backup = buf_modname(
+ (buf->b_p_sn || buf->b_shortname),
+ rootname, backup_ext, FALSE);
+ vim_free(rootname);
+ }
+ }
+
+ if (backup != NULL)
+ {
+ /*
+ * If we are not going to keep the backup file, don't
+ * delete an existing one, try to use another name.
+ * Change one character, just before the extension.
+ */
+ if (!p_bk && mch_getperm(backup) >= 0)
+ {
+ p = backup + STRLEN(backup) - 1 - STRLEN(backup_ext);
+ if (p < backup) /* empty file name ??? */
+ p = backup;
+ *p = 'z';
+ while (*p > 'a' && mch_getperm(backup) >= 0)
+ --*p;
+ /* They all exist??? Must be something wrong! */
+ if (*p == 'a')
+ VIM_CLEAR(backup);
+ }
+ }
+ if (backup != NULL)
+ {
+ /*
+ * Delete any existing backup and move the current version
+ * to the backup. For safety, we don't remove the backup
+ * until the write has finished successfully. And if the
+ * 'backup' option is set, leave it around.
+ */
+ /*
+ * If the renaming of the original file to the backup file
+ * works, quit here.
+ */
+ if (vim_rename(fname, backup) == 0)
+ break;
+
+ VIM_CLEAR(backup); /* don't do the rename below */
+ }
+ }
+ if (backup == NULL && !forceit)
+ {
+ errmsg = (char_u *)_("E510: Can't make backup file (add ! to override)");
+ goto fail;
+ }
+ }
+ }
+
+#if defined(UNIX)
+ /* When using ":w!" and the file was read-only: make it writable */
+ if (forceit && perm >= 0 && !(perm & 0200) && st_old.st_uid == getuid()
+ && vim_strchr(p_cpo, CPO_FWRITE) == NULL)
+ {
+ perm |= 0200;
+ (void)mch_setperm(fname, perm);
+ made_writable = TRUE;
+ }
+#endif
+
+ /* When using ":w!" and writing to the current file, 'readonly' makes no
+ * sense, reset it, unless 'Z' appears in 'cpoptions'. */
+ if (forceit && overwriting && vim_strchr(p_cpo, CPO_KEEPRO) == NULL)
+ {
+ buf->b_p_ro = FALSE;
+#ifdef FEAT_TITLE
+ need_maketitle = TRUE; /* set window title later */
+#endif
+ status_redraw_all(); /* redraw status lines later */
+ }
+
+ if (end > buf->b_ml.ml_line_count)
+ end = buf->b_ml.ml_line_count;
+ if (buf->b_ml.ml_flags & ML_EMPTY)
+ start = end + 1;
+
+ /*
+ * If the original file is being overwritten, there is a small chance that
+ * we crash in the middle of writing. Therefore the file is preserved now.
+ * This makes all block numbers positive so that recovery does not need
+ * the original file.
+ * Don't do this if there is a backup file and we are exiting.
+ */
+ if (reset_changed && !newfile && overwriting
+ && !(exiting && backup != NULL))
+ {
+ ml_preserve(buf, FALSE);
+ if (got_int)
+ {
+ errmsg = (char_u *)_(e_interr);
+ goto restore_backup;
+ }
+ }
+
+#ifdef VMS
+ vms_remove_version(fname); /* remove version */
+#endif
+ /* Default: write the file directly. May write to a temp file for
+ * multi-byte conversion. */
+ wfname = fname;
+
+ /* Check for forced 'fileencoding' from "++opt=val" argument. */
+ if (eap != NULL && eap->force_enc != 0)
+ {
+ fenc = eap->cmd + eap->force_enc;
+ fenc = enc_canonize(fenc);
+ fenc_tofree = fenc;
+ }
+ else
+ fenc = buf->b_p_fenc;
+
+ /*
+ * Check if the file needs to be converted.
+ */
+ converted = need_conversion(fenc);
+
+ /*
+ * Check if UTF-8 to UCS-2/4 or Latin1 conversion needs to be done. Or
+ * Latin1 to Unicode conversion. This is handled in buf_write_bytes().
+ * Prepare the flags for it and allocate bw_conv_buf when needed.
+ */
+ if (converted && (enc_utf8 || STRCMP(p_enc, "latin1") == 0))
+ {
+ wb_flags = get_fio_flags(fenc);
+ if (wb_flags & (FIO_UCS2 | FIO_UCS4 | FIO_UTF16 | FIO_UTF8))
+ {
+ /* Need to allocate a buffer to translate into. */
+ if (wb_flags & (FIO_UCS2 | FIO_UTF16 | FIO_UTF8))
+ write_info.bw_conv_buflen = bufsize * 2;
+ else /* FIO_UCS4 */
+ write_info.bw_conv_buflen = bufsize * 4;
+ write_info.bw_conv_buf
+ = lalloc((long_u)write_info.bw_conv_buflen, TRUE);
+ if (write_info.bw_conv_buf == NULL)
+ end = 0;
+ }
+ }
+
+#ifdef WIN3264
+ if (converted && wb_flags == 0 && (wb_flags = get_win_fio_flags(fenc)) != 0)
+ {
+ /* Convert UTF-8 -> UCS-2 and UCS-2 -> DBCS. Worst-case * 4: */
+ write_info.bw_conv_buflen = bufsize * 4;
+ write_info.bw_conv_buf
+ = lalloc((long_u)write_info.bw_conv_buflen, TRUE);
+ if (write_info.bw_conv_buf == NULL)
+ end = 0;
+ }
+#endif
+
+#ifdef MACOS_CONVERT
+ if (converted && wb_flags == 0 && (wb_flags = get_mac_fio_flags(fenc)) != 0)
+ {
+ write_info.bw_conv_buflen = bufsize * 3;
+ write_info.bw_conv_buf
+ = lalloc((long_u)write_info.bw_conv_buflen, TRUE);
+ if (write_info.bw_conv_buf == NULL)
+ end = 0;
+ }
+#endif
+
+#if defined(FEAT_EVAL) || defined(USE_ICONV)
+ if (converted && wb_flags == 0)
+ {
+# ifdef USE_ICONV
+ /*
+ * Use iconv() conversion when conversion is needed and it's not done
+ * internally.
+ */
+ write_info.bw_iconv_fd = (iconv_t)my_iconv_open(fenc,
+ enc_utf8 ? (char_u *)"utf-8" : p_enc);
+ if (write_info.bw_iconv_fd != (iconv_t)-1)
+ {
+ /* We're going to use iconv(), allocate a buffer to convert in. */
+ write_info.bw_conv_buflen = bufsize * ICONV_MULT;
+ write_info.bw_conv_buf
+ = lalloc((long_u)write_info.bw_conv_buflen, TRUE);
+ if (write_info.bw_conv_buf == NULL)
+ end = 0;
+ write_info.bw_first = TRUE;
+ }
+# ifdef FEAT_EVAL
+ else
+# endif
+# endif
+
+# ifdef FEAT_EVAL
+ /*
+ * When the file needs to be converted with 'charconvert' after
+ * writing, write to a temp file instead and let the conversion
+ * overwrite the original file.
+ */
+ if (*p_ccv != NUL)
+ {
+ wfname = vim_tempname('w', FALSE);
+ if (wfname == NULL) /* Can't write without a tempfile! */
+ {
+ errmsg = (char_u *)_("E214: Can't find temp file for writing");
+ goto restore_backup;
+ }
+ }
+# endif
+ }
+#endif
+ if (converted && wb_flags == 0
+#ifdef USE_ICONV
+ && write_info.bw_iconv_fd == (iconv_t)-1
+# endif
+# ifdef FEAT_EVAL
+ && wfname == fname
+# endif
+ )
+ {
+ if (!forceit)
+ {
+ errmsg = (char_u *)_("E213: Cannot convert (add ! to write without conversion)");
+ goto restore_backup;
+ }
+ notconverted = TRUE;
+ }
+
+ /*
+ * If conversion is taking place, we may first pretend to write and check
+ * for conversion errors. Then loop again to write for real.
+ * When not doing conversion this writes for real right away.
+ */
+ for (checking_conversion = TRUE; ; checking_conversion = FALSE)
+ {
+ /*
+ * There is no need to check conversion when:
+ * - there is no conversion
+ * - we make a backup file, that can be restored in case of conversion
+ * failure.
+ */
+ if (!converted || dobackup)
+ checking_conversion = FALSE;
+
+ if (checking_conversion)
+ {
+ /* Make sure we don't write anything. */
+ fd = -1;
+ write_info.bw_fd = fd;
+ }
+ else
+ {
+#ifdef HAVE_FTRUNCATE
+# define TRUNC_ON_OPEN 0
+#else
+# define TRUNC_ON_OPEN O_TRUNC
+#endif
+ /*
+ * Open the file "wfname" for writing.
+ * We may try to open the file twice: If we can't write to the file
+ * and forceit is TRUE we delete the existing file and try to
+ * create a new one. If this still fails we may have lost the
+ * original file! (this may happen when the user reached his
+ * quotum for number of files).
+ * Appending will fail if the file does not exist and forceit is
+ * FALSE.
+ */
+ while ((fd = mch_open((char *)wfname, O_WRONLY | O_EXTRA | (append
+ ? (forceit ? (O_APPEND | O_CREAT) : O_APPEND)
+ : (O_CREAT | TRUNC_ON_OPEN))
+ , perm < 0 ? 0666 : (perm & 0777))) < 0)
+ {
+ /*
+ * A forced write will try to create a new file if the old one
+ * is still readonly. This may also happen when the directory
+ * is read-only. In that case the mch_remove() will fail.
+ */
+ if (errmsg == NULL)
+ {
+#ifdef UNIX
+ stat_T st;
+
+ /* Don't delete the file when it's a hard or symbolic link.
+ */
+ if ((!newfile && st_old.st_nlink > 1)
+ || (mch_lstat((char *)fname, &st) == 0
+ && (st.st_dev != st_old.st_dev
+ || st.st_ino != st_old.st_ino)))
+ errmsg = (char_u *)_("E166: Can't open linked file for writing");
+ else
+#endif
+ {
+ errmsg = (char_u *)_("E212: Can't open file for writing");
+ if (forceit && vim_strchr(p_cpo, CPO_FWRITE) == NULL
+ && perm >= 0)
+ {
+#ifdef UNIX
+ /* we write to the file, thus it should be marked
+ writable after all */
+ if (!(perm & 0200))
+ made_writable = TRUE;
+ perm |= 0200;
+ if (st_old.st_uid != getuid()
+ || st_old.st_gid != getgid())
+ perm &= 0777;
+#endif
+ if (!append) /* don't remove when appending */
+ mch_remove(wfname);
+ continue;
+ }
+ }
+ }
+
+restore_backup:
+ {
+ stat_T st;
+
+ /*
+ * If we failed to open the file, we don't need a backup.
+ * Throw it away. If we moved or removed the original file
+ * try to put the backup in its place.
+ */
+ if (backup != NULL && wfname == fname)
+ {
+ if (backup_copy)
+ {
+ /*
+ * There is a small chance that we removed the
+ * original, try to move the copy in its place.
+ * This may not work if the vim_rename() fails.
+ * In that case we leave the copy around.
+ */
+ /* If file does not exist, put the copy in its
+ * place */
+ if (mch_stat((char *)fname, &st) < 0)
+ vim_rename(backup, fname);
+ /* if original file does exist throw away the copy
+ */
+ if (mch_stat((char *)fname, &st) >= 0)
+ mch_remove(backup);
+ }
+ else
+ {
+ /* try to put the original file back */
+ vim_rename(backup, fname);
+ }
+ }
+
+ /* if original file no longer exists give an extra warning
+ */
+ if (!newfile && mch_stat((char *)fname, &st) < 0)
+ end = 0;
+ }
+
+ if (wfname != fname)
+ vim_free(wfname);
+ goto fail;
+ }
+ write_info.bw_fd = fd;
+
+#if defined(UNIX)
+ {
+ stat_T st;
+
+ /* Double check we are writing the intended file before making
+ * any changes. */
+ if (overwriting
+ && (!dobackup || backup_copy)
+ && fname == wfname
+ && perm >= 0
+ && mch_fstat(fd, &st) == 0
+ && st.st_ino != st_old.st_ino)
+ {
+ close(fd);
+ errmsg = (char_u *)_("E949: File changed while writing");
+ goto fail;
+ }
+ }
+#endif
+#ifdef HAVE_FTRUNCATE
+ if (!append)
+ vim_ignored = ftruncate(fd, (off_t)0);
+#endif
+
+#if defined(WIN3264)
+ if (backup != NULL && overwriting && !append)
+ {
+ if (backup_copy)
+ (void)mch_copy_file_attribute(wfname, backup);
+ else
+ (void)mch_copy_file_attribute(backup, wfname);
+ }
+
+ if (!overwriting && !append)
+ {
+ if (buf->b_ffname != NULL)
+ (void)mch_copy_file_attribute(buf->b_ffname, wfname);
+ /* Should copy resource fork */
+ }
+#endif
+
+#ifdef FEAT_CRYPT
+ if (*buf->b_p_key != NUL && !filtering)
+ {
+ char_u *header;
+ int header_len;
+
+ buf->b_cryptstate = crypt_create_for_writing(
+ crypt_get_method_nr(buf),
+ buf->b_p_key, &header, &header_len);
+ if (buf->b_cryptstate == NULL || header == NULL)
+ end = 0;
+ else
+ {
+ /* Write magic number, so that Vim knows how this file is
+ * encrypted when reading it back. */
+ write_info.bw_buf = header;
+ write_info.bw_len = header_len;
+ write_info.bw_flags = FIO_NOCONVERT;
+ if (buf_write_bytes(&write_info) == FAIL)
+ end = 0;
+ wb_flags |= FIO_ENCRYPTED;
+ vim_free(header);
+ }
+ }
+#endif
+ }
+ errmsg = NULL;
+
+ write_info.bw_buf = buffer;
+ nchars = 0;
+
+ /* use "++bin", "++nobin" or 'binary' */
+ if (eap != NULL && eap->force_bin != 0)
+ write_bin = (eap->force_bin == FORCE_BIN);
+ else
+ write_bin = buf->b_p_bin;
+
+ /*
+ * The BOM is written just after the encryption magic number.
+ * Skip it when appending and the file already existed, the BOM only
+ * makes sense at the start of the file.
+ */
+ if (buf->b_p_bomb && !write_bin && (!append || perm < 0))
+ {
+ write_info.bw_len = make_bom(buffer, fenc);
+ if (write_info.bw_len > 0)
+ {
+ /* don't convert, do encryption */
+ write_info.bw_flags = FIO_NOCONVERT | wb_flags;
+ if (buf_write_bytes(&write_info) == FAIL)
+ end = 0;
+ else
+ nchars += write_info.bw_len;
+ }
+ }
+ write_info.bw_start_lnum = start;
+
+#ifdef FEAT_PERSISTENT_UNDO
+ write_undo_file = (buf->b_p_udf
+ && overwriting
+ && !append
+ && !filtering
+ && reset_changed
+ && !checking_conversion);
+ if (write_undo_file)
+ /* Prepare for computing the hash value of the text. */
+ sha256_start(&sha_ctx);
+#endif
+
+ write_info.bw_len = bufsize;
+#ifdef HAS_BW_FLAGS
+ write_info.bw_flags = wb_flags;
+#endif
+ fileformat = get_fileformat_force(buf, eap);
+ s = buffer;
+ len = 0;
+ for (lnum = start; lnum <= end; ++lnum)
+ {
+ /*
+ * The next while loop is done once for each character written.
+ * Keep it fast!
+ */
+ ptr = ml_get_buf(buf, lnum, FALSE) - 1;
+#ifdef FEAT_PERSISTENT_UNDO
+ if (write_undo_file)
+ sha256_update(&sha_ctx, ptr + 1,
+ (UINT32_T)(STRLEN(ptr + 1) + 1));
+#endif
+ while ((c = *++ptr) != NUL)
+ {
+ if (c == NL)
+ *s = NUL; /* replace newlines with NULs */
+ else if (c == CAR && fileformat == EOL_MAC)
+ *s = NL; /* Mac: replace CRs with NLs */
+ else
+ *s = c;
+ ++s;
+ if (++len != bufsize)
+ continue;
+ if (buf_write_bytes(&write_info) == FAIL)
+ {
+ end = 0; /* write error: break loop */
+ break;
+ }
+ nchars += bufsize;
+ s = buffer;
+ len = 0;
+ write_info.bw_start_lnum = lnum;
+ }
+ /* write failed or last line has no EOL: stop here */
+ if (end == 0
+ || (lnum == end
+ && (write_bin || !buf->b_p_fixeol)
+ && (lnum == buf->b_no_eol_lnum
+ || (lnum == buf->b_ml.ml_line_count
+ && !buf->b_p_eol))))
+ {
+ ++lnum; /* written the line, count it */
+ no_eol = TRUE;
+ break;
+ }
+ if (fileformat == EOL_UNIX)
+ *s++ = NL;
+ else
+ {
+ *s++ = CAR; /* EOL_MAC or EOL_DOS: write CR */
+ if (fileformat == EOL_DOS) /* write CR-NL */
+ {
+ if (++len == bufsize)
+ {
+ if (buf_write_bytes(&write_info) == FAIL)
+ {
+ end = 0; /* write error: break loop */
+ break;
+ }
+ nchars += bufsize;
+ s = buffer;
+ len = 0;
+ }
+ *s++ = NL;
+ }
+ }
+ if (++len == bufsize && end)
+ {
+ if (buf_write_bytes(&write_info) == FAIL)
+ {
+ end = 0; /* write error: break loop */
+ break;
+ }
+ nchars += bufsize;
+ s = buffer;
+ len = 0;
+
+ ui_breakcheck();
+ if (got_int)
+ {
+ end = 0; /* Interrupted, break loop */
+ break;
+ }
+ }
+#ifdef VMS
+ /*
+ * On VMS there is a problem: newlines get added when writing
+ * blocks at a time. Fix it by writing a line at a time.
+ * This is much slower!
+ * Explanation: VAX/DECC RTL insists that records in some RMS
+ * structures end with a newline (carriage return) character, and
+ * if they don't it adds one.
+ * With other RMS structures it works perfect without this fix.
+ */
+ if (buf->b_fab_rfm == FAB$C_VFC
+ || ((buf->b_fab_rat & (FAB$M_FTN | FAB$M_CR)) != 0))
+ {
+ int b2write;
+
+ buf->b_fab_mrs = (buf->b_fab_mrs == 0
+ ? MIN(4096, bufsize)
+ : MIN(buf->b_fab_mrs, bufsize));
+
+ b2write = len;
+ while (b2write > 0)
+ {
+ write_info.bw_len = MIN(b2write, buf->b_fab_mrs);
+ if (buf_write_bytes(&write_info) == FAIL)
+ {
+ end = 0;
+ break;
+ }
+ b2write -= MIN(b2write, buf->b_fab_mrs);
+ }
+ write_info.bw_len = bufsize;
+ nchars += len;
+ s = buffer;
+ len = 0;
+ }
+#endif
+ }
+ if (len > 0 && end > 0)
+ {
+ write_info.bw_len = len;
+ if (buf_write_bytes(&write_info) == FAIL)
+ end = 0; /* write error */
+ nchars += len;
+ }
+
+ /* Stop when writing done or an error was encountered. */
+ if (!checking_conversion || end == 0)
+ break;
+
+ /* If no error happened until now, writing should be ok, so loop to
+ * really write the buffer. */
+ }
+
+ /* If we started writing, finish writing. Also when an error was
+ * encountered. */
+ if (!checking_conversion)
+ {
+#if defined(UNIX) && defined(HAVE_FSYNC)
+ /*
+ * On many journalling file systems there is a bug that causes both the
+ * original and the backup file to be lost when halting the system
+ * right after writing the file. That's because only the meta-data is
+ * journalled. Syncing the file slows down the system, but assures it
+ * has been written to disk and we don't lose it.
+ * For a device do try the fsync() but don't complain if it does not
+ * work (could be a pipe).
+ * If the 'fsync' option is FALSE, don't fsync(). Useful for laptops.
+ */
+ if (p_fs && fsync(fd) != 0 && !device)
+ {
+ errmsg = (char_u *)_(e_fsync);
+ end = 0;
+ }
+#endif
+
+#if defined(HAVE_SELINUX) || defined(HAVE_SMACK)
+ /* Probably need to set the security context. */
+ if (!backup_copy)
+ mch_copy_sec(backup, wfname);
+#endif
+
+#ifdef UNIX
+ /* When creating a new file, set its owner/group to that of the
+ * original file. Get the new device and inode number. */
+ if (backup != NULL && !backup_copy)
+ {
+# ifdef HAVE_FCHOWN
+ stat_T st;
+
+ /* Don't change the owner when it's already OK, some systems remove
+ * permission or ACL stuff. */
+ if (mch_stat((char *)wfname, &st) < 0
+ || st.st_uid != st_old.st_uid
+ || st.st_gid != st_old.st_gid)
+ {
+ /* changing owner might not be possible */
+ vim_ignored = fchown(fd, st_old.st_uid, -1);
+ /* if changing group fails clear the group permissions */
+ if (fchown(fd, -1, st_old.st_gid) == -1 && perm > 0)
+ perm &= ~070;
+ }
+# endif
+ buf_setino(buf);
+ }
+ else if (!buf->b_dev_valid)
+ /* Set the inode when creating a new file. */
+ buf_setino(buf);
+#endif
+
+#ifdef UNIX
+ if (made_writable)
+ perm &= ~0200; /* reset 'w' bit for security reasons */
+#endif
+#ifdef HAVE_FCHMOD
+ /* set permission of new file same as old file */
+ if (perm >= 0)
+ (void)mch_fsetperm(fd, perm);
+#endif
+ if (close(fd) != 0)
+ {
+ errmsg = (char_u *)_("E512: Close failed");
+ end = 0;
+ }
+
+#ifndef HAVE_FCHMOD
+ /* set permission of new file same as old file */
+ if (perm >= 0)
+ (void)mch_setperm(wfname, perm);
+#endif
+#ifdef HAVE_ACL
+ /*
+ * Probably need to set the ACL before changing the user (can't set the
+ * ACL on a file the user doesn't own).
+ * On Solaris, with ZFS and the aclmode property set to "discard" (the
+ * default), chmod() discards all part of a file's ACL that don't
+ * represent the mode of the file. It's non-trivial for us to discover
+ * whether we're in that situation, so we simply always re-set the ACL.
+ */
+# ifndef HAVE_SOLARIS_ZFS_ACL
+ if (!backup_copy)
+# endif
+ mch_set_acl(wfname, acl);
+#endif
+#ifdef FEAT_CRYPT
+ if (buf->b_cryptstate != NULL)
+ {
+ crypt_free_state(buf->b_cryptstate);
+ buf->b_cryptstate = NULL;
+ }
+#endif
+
+#if defined(FEAT_EVAL)
+ if (wfname != fname)
+ {
+ /*
+ * The file was written to a temp file, now it needs to be
+ * converted with 'charconvert' to (overwrite) the output file.
+ */
+ if (end != 0)
+ {
+ if (eval_charconvert(enc_utf8 ? (char_u *)"utf-8" : p_enc,
+ fenc, wfname, fname) == FAIL)
+ {
+ write_info.bw_conv_error = TRUE;
+ end = 0;
+ }
+ }
+ mch_remove(wfname);
+ vim_free(wfname);
+ }
+#endif
+ }
+
+ if (end == 0)
+ {
+ /*
+ * Error encountered.
+ */
+ if (errmsg == NULL)
+ {
+ if (write_info.bw_conv_error)
+ {
+ if (write_info.bw_conv_error_lnum == 0)
+ errmsg = (char_u *)_("E513: write error, conversion failed (make 'fenc' empty to override)");
+ else
+ {
+ errmsg_allocated = TRUE;
+ errmsg = alloc(300);
+ vim_snprintf((char *)errmsg, 300, _("E513: write error, conversion failed in line %ld (make 'fenc' empty to override)"),
+ (long)write_info.bw_conv_error_lnum);
+ }
+ }
+ else if (got_int)
+ errmsg = (char_u *)_(e_interr);
+ else
+ errmsg = (char_u *)_("E514: write error (file system full?)");
+ }
+
+ /*
+ * If we have a backup file, try to put it in place of the new file,
+ * because the new file is probably corrupt. This avoids losing the
+ * original file when trying to make a backup when writing the file a
+ * second time.
+ * When "backup_copy" is set we need to copy the backup over the new
+ * file. Otherwise rename the backup file.
+ * If this is OK, don't give the extra warning message.
+ */
+ if (backup != NULL)
+ {
+ if (backup_copy)
+ {
+ /* This may take a while, if we were interrupted let the user
+ * know we got the message. */
+ if (got_int)
+ {
+ msg(_(e_interr));
+ out_flush();
+ }
+ if ((fd = mch_open((char *)backup, O_RDONLY | O_EXTRA, 0)) >= 0)
+ {
+ if ((write_info.bw_fd = mch_open((char *)fname,
+ O_WRONLY | O_CREAT | O_TRUNC | O_EXTRA,
+ perm & 0777)) >= 0)
+ {
+ /* copy the file. */
+ write_info.bw_buf = smallbuf;
+#ifdef HAS_BW_FLAGS
+ write_info.bw_flags = FIO_NOCONVERT;
+#endif
+ while ((write_info.bw_len = read_eintr(fd, smallbuf,
+ SMBUFSIZE)) > 0)
+ if (buf_write_bytes(&write_info) == FAIL)
+ break;
+
+ if (close(write_info.bw_fd) >= 0
+ && write_info.bw_len == 0)
+ end = 1; /* success */
+ }
+ close(fd); /* ignore errors for closing read file */
+ }
+ }
+ else
+ {
+ if (vim_rename(backup, fname) == 0)
+ end = 1;
+ }
+ }
+ goto fail;
+ }
+
+ lnum -= start; /* compute number of written lines */
+ --no_wait_return; /* may wait for return now */
+
+#if !(defined(UNIX) || defined(VMS))
+ fname = sfname; /* use shortname now, for the messages */
+#endif
+ if (!filtering)
+ {
+ msg_add_fname(buf, fname); /* put fname in IObuff with quotes */
+ c = FALSE;
+ if (write_info.bw_conv_error)
+ {
+ STRCAT(IObuff, _(" CONVERSION ERROR"));
+ c = TRUE;
+ if (write_info.bw_conv_error_lnum != 0)
+ vim_snprintf_add((char *)IObuff, IOSIZE, _(" in line %ld;"),
+ (long)write_info.bw_conv_error_lnum);
+ }
+ else if (notconverted)
+ {
+ STRCAT(IObuff, _("[NOT converted]"));
+ c = TRUE;
+ }
+ else if (converted)
+ {
+ STRCAT(IObuff, _("[converted]"));
+ c = TRUE;
+ }
+ if (device)
+ {
+ STRCAT(IObuff, _("[Device]"));
+ c = TRUE;
+ }
+ else if (newfile)
+ {
+ STRCAT(IObuff, shortmess(SHM_NEW) ? _("[New]") : _("[New File]"));
+ c = TRUE;
+ }
+ if (no_eol)
+ {
+ msg_add_eol();
+ c = TRUE;
+ }
+ /* may add [unix/dos/mac] */
+ if (msg_add_fileformat(fileformat))
+ c = TRUE;
+#ifdef FEAT_CRYPT
+ if (wb_flags & FIO_ENCRYPTED)
+ {
+ crypt_append_msg(buf);
+ c = TRUE;
+ }
+#endif
+ msg_add_lines(c, (long)lnum, nchars); /* add line/char count */
+ if (!shortmess(SHM_WRITE))
+ {
+ if (append)
+ STRCAT(IObuff, shortmess(SHM_WRI) ? _(" [a]") : _(" appended"));
+ else
+ STRCAT(IObuff, shortmess(SHM_WRI) ? _(" [w]") : _(" written"));
+ }
+
+ set_keep_msg((char_u *)msg_trunc_attr((char *)IObuff, FALSE, 0), 0);
+ }
+
+ /* When written everything correctly: reset 'modified'. Unless not
+ * writing to the original file and '+' is not in 'cpoptions'. */
+ if (reset_changed && whole && !append
+ && !write_info.bw_conv_error
+ && (overwriting || vim_strchr(p_cpo, CPO_PLUS) != NULL))
+ {
+ unchanged(buf, TRUE);
+ /* b:changedtick is always incremented in unchanged() but that
+ * should not trigger a TextChanged event. */
+ if (buf->b_last_changedtick + 1 == CHANGEDTICK(buf))
+ buf->b_last_changedtick = CHANGEDTICK(buf);
+ u_unchanged(buf);
+ u_update_save_nr(buf);
+ }
+
+ /*
+ * If written to the current file, update the timestamp of the swap file
+ * and reset the BF_WRITE_MASK flags. Also sets buf->b_mtime.
+ */
+ if (overwriting)
+ {
+ ml_timestamp(buf);
+ if (append)
+ buf->b_flags &= ~BF_NEW;
+ else
+ buf->b_flags &= ~BF_WRITE_MASK;
+ }
+
+ /*
+ * If we kept a backup until now, and we are in patch mode, then we make
+ * the backup file our 'original' file.
+ */
+ if (*p_pm && dobackup)
+ {
+ char *org = (char *)buf_modname((buf->b_p_sn || buf->b_shortname),
+ fname, p_pm, FALSE);
+
+ if (backup != NULL)
+ {
+ stat_T st;
+
+ /*
+ * If the original file does not exist yet
+ * the current backup file becomes the original file
+ */
+ if (org == NULL)
+ emsg(_("E205: Patchmode: can't save original file"));
+ else if (mch_stat(org, &st) < 0)
+ {
+ vim_rename(backup, (char_u *)org);
+ VIM_CLEAR(backup); /* don't delete the file */
+#ifdef UNIX
+ set_file_time((char_u *)org, st_old.st_atime, st_old.st_mtime);
+#endif
+ }
+ }
+ /*
+ * If there is no backup file, remember that a (new) file was
+ * created.
+ */
+ else
+ {
+ int empty_fd;
+
+ if (org == NULL
+ || (empty_fd = mch_open(org,
+ O_CREAT | O_EXTRA | O_EXCL | O_NOFOLLOW,
+ perm < 0 ? 0666 : (perm & 0777))) < 0)
+ emsg(_("E206: patchmode: can't touch empty original file"));
+ else
+ close(empty_fd);
+ }
+ if (org != NULL)
+ {
+ mch_setperm((char_u *)org, mch_getperm(fname) & 0777);
+ vim_free(org);
+ }
+ }
+
+ /*
+ * Remove the backup unless 'backup' option is set
+ */
+ if (!p_bk && backup != NULL && mch_remove(backup) != 0)
+ emsg(_("E207: Can't delete backup file"));
+
+ goto nofail;
+
+ /*
+ * Finish up. We get here either after failure or success.
+ */
+fail:
+ --no_wait_return; /* may wait for return now */
+nofail:
+
+ /* Done saving, we accept changed buffer warnings again */
+ buf->b_saving = FALSE;
+
+ vim_free(backup);
+ if (buffer != smallbuf)
+ vim_free(buffer);
+ vim_free(fenc_tofree);
+ vim_free(write_info.bw_conv_buf);
+#ifdef USE_ICONV
+ if (write_info.bw_iconv_fd != (iconv_t)-1)
+ {
+ iconv_close(write_info.bw_iconv_fd);
+ write_info.bw_iconv_fd = (iconv_t)-1;
+ }
+#endif
+#ifdef HAVE_ACL
+ mch_free_acl(acl);
+#endif
+
+ if (errmsg != NULL)
+ {
+ int numlen = errnum != NULL ? (int)STRLEN(errnum) : 0;
+
+ attr = HL_ATTR(HLF_E); /* set highlight for error messages */
+ msg_add_fname(buf,
+#ifndef UNIX
+ sfname
+#else
+ fname
+#endif
+ ); /* put file name in IObuff with quotes */
+ if (STRLEN(IObuff) + STRLEN(errmsg) + numlen >= IOSIZE)
+ IObuff[IOSIZE - STRLEN(errmsg) - numlen - 1] = NUL;
+ /* If the error message has the form "is ...", put the error number in
+ * front of the file name. */
+ if (errnum != NULL)
+ {
+ STRMOVE(IObuff + numlen, IObuff);
+ mch_memmove(IObuff, errnum, (size_t)numlen);
+ }
+ STRCAT(IObuff, errmsg);
+ emsg((char *)IObuff);
+ if (errmsg_allocated)
+ vim_free(errmsg);
+
+ retval = FAIL;
+ if (end == 0)
+ {
+ msg_puts_attr(_("\nWARNING: Original file may be lost or damaged\n"),
+ attr | MSG_HIST);
+ msg_puts_attr(_("don't quit the editor until the file is successfully written!"),
+ attr | MSG_HIST);
+
+ /* Update the timestamp to avoid an "overwrite changed file"
+ * prompt when writing again. */
+ if (mch_stat((char *)fname, &st_old) >= 0)
+ {
+ buf_store_time(buf, &st_old, fname);
+ buf->b_mtime_read = buf->b_mtime;
+ }
+ }
+ }
+ msg_scroll = msg_save;
+
+#ifdef FEAT_PERSISTENT_UNDO
+ /*
+ * When writing the whole file and 'undofile' is set, also write the undo
+ * file.
+ */
+ if (retval == OK && write_undo_file)
+ {
+ char_u hash[UNDO_HASH_SIZE];
+
+ sha256_finish(&sha_ctx, hash);
+ u_write_undo(NULL, FALSE, buf, hash);
+ }
+#endif
+
+#ifdef FEAT_EVAL
+ if (!should_abort(retval))
+#else
+ if (!got_int)
+#endif
+ {
+ aco_save_T aco;
+
+ curbuf->b_no_eol_lnum = 0; /* in case it was set by the previous read */
+
+ /*
+ * Apply POST autocommands.
+ * Careful: The autocommands may call buf_write() recursively!
+ */
+ aucmd_prepbuf(&aco, buf);
+
+ if (append)
+ apply_autocmds_exarg(EVENT_FILEAPPENDPOST, fname, fname,
+ FALSE, curbuf, eap);
+ else if (filtering)
+ apply_autocmds_exarg(EVENT_FILTERWRITEPOST, NULL, fname,
+ FALSE, curbuf, eap);
+ else if (reset_changed && whole)
+ apply_autocmds_exarg(EVENT_BUFWRITEPOST, fname, fname,
+ FALSE, curbuf, eap);
+ else
+ apply_autocmds_exarg(EVENT_FILEWRITEPOST, fname, fname,
+ FALSE, curbuf, eap);
+
+ /* restore curwin/curbuf and a few other things */
+ aucmd_restbuf(&aco);
+
+#ifdef FEAT_EVAL
+ if (aborting()) /* autocmds may abort script processing */
+ retval = FALSE;
+#endif
+ }
+
+ got_int |= prev_got_int;
+
+ return retval;
+}
+
+/*
+ * Set the name of the current buffer. Use when the buffer doesn't have a
+ * name and a ":r" or ":w" command with a file name is used.
+ */
+ static int
+set_rw_fname(char_u *fname, char_u *sfname)
+{
+ buf_T *buf = curbuf;
+
+ /* It's like the unnamed buffer is deleted.... */
+ if (curbuf->b_p_bl)
+ apply_autocmds(EVENT_BUFDELETE, NULL, NULL, FALSE, curbuf);
+ apply_autocmds(EVENT_BUFWIPEOUT, NULL, NULL, FALSE, curbuf);
+#ifdef FEAT_EVAL
+ if (aborting()) /* autocmds may abort script processing */
+ return FAIL;
+#endif
+ if (curbuf != buf)
+ {
+ /* We are in another buffer now, don't do the renaming. */
+ emsg(_(e_auchangedbuf));
+ return FAIL;
+ }
+
+ if (setfname(curbuf, fname, sfname, FALSE) == OK)
+ curbuf->b_flags |= BF_NOTEDITED;
+
+ /* ....and a new named one is created */
+ apply_autocmds(EVENT_BUFNEW, NULL, NULL, FALSE, curbuf);
+ if (curbuf->b_p_bl)
+ apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, curbuf);
+#ifdef FEAT_EVAL
+ if (aborting()) /* autocmds may abort script processing */
+ return FAIL;
+#endif
+
+ /* Do filetype detection now if 'filetype' is empty. */
+ if (*curbuf->b_p_ft == NUL)
+ {
+ if (au_has_group((char_u *)"filetypedetect"))
+ (void)do_doautocmd((char_u *)"filetypedetect BufRead", FALSE, NULL);
+ do_modelines(0);
+ }
+
+ return OK;
+}
+
+/*
+ * Put file name into IObuff with quotes.
+ */
+ void
+msg_add_fname(buf_T *buf, char_u *fname)
+{
+ if (fname == NULL)
+ fname = (char_u *)"-stdin-";
+ home_replace(buf, fname, IObuff + 1, IOSIZE - 4, TRUE);
+ IObuff[0] = '"';
+ STRCAT(IObuff, "\" ");
+}
+
+/*
+ * Append message for text mode to IObuff.
+ * Return TRUE if something appended.
+ */
+ static int
+msg_add_fileformat(int eol_type)
+{
+#ifndef USE_CRNL
+ if (eol_type == EOL_DOS)
+ {
+ STRCAT(IObuff, shortmess(SHM_TEXT) ? _("[dos]") : _("[dos format]"));
+ return TRUE;
+ }
+#endif
+#ifndef USE_CR
+ if (eol_type == EOL_MAC)
+ {
+ STRCAT(IObuff, shortmess(SHM_TEXT) ? _("[mac]") : _("[mac format]"));
+ return TRUE;
+ }
+#endif
+#if defined(USE_CRNL) || defined(USE_CR)
+ if (eol_type == EOL_UNIX)
+ {
+ STRCAT(IObuff, shortmess(SHM_TEXT) ? _("[unix]") : _("[unix format]"));
+ return TRUE;
+ }
+#endif
+ return FALSE;
+}
+
+/*
+ * Append line and character count to IObuff.
+ */
+ void
+msg_add_lines(
+ int insert_space,
+ long lnum,
+ off_T nchars)
+{
+ char_u *p;
+
+ p = IObuff + STRLEN(IObuff);
+
+ if (insert_space)
+ *p++ = ' ';
+ if (shortmess(SHM_LINES))
+ vim_snprintf((char *)p, IOSIZE - (p - IObuff),
+ "%ldL, %lldC", lnum, (long_long_T)nchars);
+ else
+ {
+ sprintf((char *)p, NGETTEXT("%ld line, ", "%ld lines, ", lnum), lnum);
+ p += STRLEN(p);
+ vim_snprintf((char *)p, IOSIZE - (p - IObuff),
+ NGETTEXT("%lld character", "%lld characters", nchars),
+ (long_long_T)nchars);
+ }
+}
+
+/*
+ * Append message for missing line separator to IObuff.
+ */
+ static void
+msg_add_eol(void)
+{
+ STRCAT(IObuff, shortmess(SHM_LAST) ? _("[noeol]") : _("[Incomplete last line]"));
+}
+
+/*
+ * Check modification time of file, before writing to it.
+ * The size isn't checked, because using a tool like "gzip" takes care of
+ * using the same timestamp but can't set the size.
+ */
+ static int
+check_mtime(buf_T *buf, stat_T *st)
+{
+ if (buf->b_mtime_read != 0
+ && time_differs((long)st->st_mtime, buf->b_mtime_read))
+ {
+ msg_scroll = TRUE; /* don't overwrite messages here */
+ msg_silent = 0; /* must give this prompt */
+ /* don't use emsg() here, don't want to flush the buffers */
+ msg_attr(_("WARNING: The file has been changed since reading it!!!"),
+ HL_ATTR(HLF_E));
+ if (ask_yesno((char_u *)_("Do you really want to write to it"),
+ TRUE) == 'n')
+ return FAIL;
+ msg_scroll = FALSE; /* always overwrite the file message now */
+ }
+ return OK;
+}
+
+ static int
+time_differs(long t1, long t2)
+{
+#if defined(__linux__) || defined(MSWIN)
+ /* On a FAT filesystem, esp. under Linux, there are only 5 bits to store
+ * the seconds. Since the roundoff is done when flushing the inode, the
+ * time may change unexpectedly by one second!!! */
+ return (t1 - t2 > 1 || t2 - t1 > 1);
+#else
+ return (t1 != t2);
+#endif
+}
+
+/*
+ * Call write() to write a number of bytes to the file.
+ * Handles encryption and 'encoding' conversion.
+ *
+ * Return FAIL for failure, OK otherwise.
+ */
+ static int
+buf_write_bytes(struct bw_info *ip)
+{
+ int wlen;
+ char_u *buf = ip->bw_buf; /* data to write */
+ int len = ip->bw_len; /* length of data */
+#ifdef HAS_BW_FLAGS
+ int flags = ip->bw_flags; /* extra flags */
+#endif
+
+ /*
+ * Skip conversion when writing the crypt magic number or the BOM.
+ */
+ if (!(flags & FIO_NOCONVERT))
+ {
+ char_u *p;
+ unsigned c;
+ int n;
+
+ if (flags & FIO_UTF8)
+ {
+ /*
+ * Convert latin1 in the buffer to UTF-8 in the file.
+ */
+ p = ip->bw_conv_buf; /* translate to buffer */
+ for (wlen = 0; wlen < len; ++wlen)
+ p += utf_char2bytes(buf[wlen], p);
+ buf = ip->bw_conv_buf;
+ len = (int)(p - ip->bw_conv_buf);
+ }
+ else if (flags & (FIO_UCS4 | FIO_UTF16 | FIO_UCS2 | FIO_LATIN1))
+ {
+ /*
+ * Convert UTF-8 bytes in the buffer to UCS-2, UCS-4, UTF-16 or
+ * Latin1 chars in the file.
+ */
+ if (flags & FIO_LATIN1)
+ p = buf; /* translate in-place (can only get shorter) */
+ else
+ p = ip->bw_conv_buf; /* translate to buffer */
+ for (wlen = 0; wlen < len; wlen += n)
+ {
+ if (wlen == 0 && ip->bw_restlen != 0)
+ {
+ int l;
+
+ /* Use remainder of previous call. Append the start of
+ * buf[] to get a full sequence. Might still be too
+ * short! */
+ l = CONV_RESTLEN - ip->bw_restlen;
+ if (l > len)
+ l = len;
+ mch_memmove(ip->bw_rest + ip->bw_restlen, buf, (size_t)l);
+ n = utf_ptr2len_len(ip->bw_rest, ip->bw_restlen + l);
+ if (n > ip->bw_restlen + len)
+ {
+ /* We have an incomplete byte sequence at the end to
+ * be written. We can't convert it without the
+ * remaining bytes. Keep them for the next call. */
+ if (ip->bw_restlen + len > CONV_RESTLEN)
+ return FAIL;
+ ip->bw_restlen += len;
+ break;
+ }
+ if (n > 1)
+ c = utf_ptr2char(ip->bw_rest);
+ else
+ c = ip->bw_rest[0];
+ if (n >= ip->bw_restlen)
+ {
+ n -= ip->bw_restlen;
+ ip->bw_restlen = 0;
+ }
+ else
+ {
+ ip->bw_restlen -= n;
+ mch_memmove(ip->bw_rest, ip->bw_rest + n,
+ (size_t)ip->bw_restlen);
+ n = 0;
+ }
+ }
+ else
+ {
+ n = utf_ptr2len_len(buf + wlen, len - wlen);
+ if (n > len - wlen)
+ {
+ /* We have an incomplete byte sequence at the end to
+ * be written. We can't convert it without the
+ * remaining bytes. Keep them for the next call. */
+ if (len - wlen > CONV_RESTLEN)
+ return FAIL;
+ ip->bw_restlen = len - wlen;
+ mch_memmove(ip->bw_rest, buf + wlen,
+ (size_t)ip->bw_restlen);
+ break;
+ }
+ if (n > 1)
+ c = utf_ptr2char(buf + wlen);
+ else
+ c = buf[wlen];
+ }
+
+ if (ucs2bytes(c, &p, flags) && !ip->bw_conv_error)
+ {
+ ip->bw_conv_error = TRUE;
+ ip->bw_conv_error_lnum = ip->bw_start_lnum;
+ }
+ if (c == NL)
+ ++ip->bw_start_lnum;
+ }
+ if (flags & FIO_LATIN1)
+ len = (int)(p - buf);
+ else
+ {
+ buf = ip->bw_conv_buf;
+ len = (int)(p - ip->bw_conv_buf);
+ }
+ }
+
+#ifdef WIN3264
+ else if (flags & FIO_CODEPAGE)
+ {
+ /*
+ * Convert UTF-8 or codepage to UCS-2 and then to MS-Windows
+ * codepage.
+ */
+ char_u *from;
+ size_t fromlen;
+ char_u *to;
+ int u8c;
+ BOOL bad = FALSE;
+ int needed;
+
+ if (ip->bw_restlen > 0)
+ {
+ /* Need to concatenate the remainder of the previous call and
+ * the bytes of the current call. Use the end of the
+ * conversion buffer for this. */
+ fromlen = len + ip->bw_restlen;
+ from = ip->bw_conv_buf + ip->bw_conv_buflen - fromlen;
+ mch_memmove(from, ip->bw_rest, (size_t)ip->bw_restlen);
+ mch_memmove(from + ip->bw_restlen, buf, (size_t)len);
+ }
+ else
+ {
+ from = buf;
+ fromlen = len;
+ }
+
+ to = ip->bw_conv_buf;
+ if (enc_utf8)
+ {
+ /* Convert from UTF-8 to UCS-2, to the start of the buffer.
+ * The buffer has been allocated to be big enough. */
+ while (fromlen > 0)
+ {
+ n = (int)utf_ptr2len_len(from, (int)fromlen);
+ if (n > (int)fromlen) /* incomplete byte sequence */
+ break;
+ u8c = utf_ptr2char(from);
+ *to++ = (u8c & 0xff);
+ *to++ = (u8c >> 8);
+ fromlen -= n;
+ from += n;
+ }
+
+ /* Copy remainder to ip->bw_rest[] to be used for the next
+ * call. */
+ if (fromlen > CONV_RESTLEN)
+ {
+ /* weird overlong sequence */
+ ip->bw_conv_error = TRUE;
+ return FAIL;
+ }
+ mch_memmove(ip->bw_rest, from, fromlen);
+ ip->bw_restlen = (int)fromlen;
+ }
+ else
+ {
+ /* Convert from enc_codepage to UCS-2, to the start of the
+ * buffer. The buffer has been allocated to be big enough. */
+ ip->bw_restlen = 0;
+ needed = MultiByteToWideChar(enc_codepage,
+ MB_ERR_INVALID_CHARS, (LPCSTR)from, (int)fromlen,
+ NULL, 0);
+ if (needed == 0)
+ {
+ /* When conversion fails there may be a trailing byte. */
+ needed = MultiByteToWideChar(enc_codepage,
+ MB_ERR_INVALID_CHARS, (LPCSTR)from, (int)fromlen - 1,
+ NULL, 0);
+ if (needed == 0)
+ {
+ /* Conversion doesn't work. */
+ ip->bw_conv_error = TRUE;
+ return FAIL;
+ }
+ /* Save the trailing byte for the next call. */
+ ip->bw_rest[0] = from[fromlen - 1];
+ ip->bw_restlen = 1;
+ }
+ needed = MultiByteToWideChar(enc_codepage, MB_ERR_INVALID_CHARS,
+ (LPCSTR)from, (int)(fromlen - ip->bw_restlen),
+ (LPWSTR)to, needed);
+ if (needed == 0)
+ {
+ /* Safety check: Conversion doesn't work. */
+ ip->bw_conv_error = TRUE;
+ return FAIL;
+ }
+ to += needed * 2;
+ }
+
+ fromlen = to - ip->bw_conv_buf;
+ buf = to;
+# ifdef CP_UTF8 /* VC 4.1 doesn't define CP_UTF8 */
+ if (FIO_GET_CP(flags) == CP_UTF8)
+ {
+ /* Convert from UCS-2 to UTF-8, using the remainder of the
+ * conversion buffer. Fails when out of space. */
+ for (from = ip->bw_conv_buf; fromlen > 1; fromlen -= 2)
+ {
+ u8c = *from++;
+ u8c += (*from++ << 8);
+ to += utf_char2bytes(u8c, to);
+ if (to + 6 >= ip->bw_conv_buf + ip->bw_conv_buflen)
+ {
+ ip->bw_conv_error = TRUE;
+ return FAIL;
+ }
+ }
+ len = (int)(to - buf);
+ }
+ else
+# endif
+ {
+ /* Convert from UCS-2 to the codepage, using the remainder of
+ * the conversion buffer. If the conversion uses the default
+ * character "0", the data doesn't fit in this encoding, so
+ * fail. */
+ len = WideCharToMultiByte(FIO_GET_CP(flags), 0,
+ (LPCWSTR)ip->bw_conv_buf, (int)fromlen / sizeof(WCHAR),
+ (LPSTR)to, (int)(ip->bw_conv_buflen - fromlen), 0,
+ &bad);
+ if (bad)
+ {
+ ip->bw_conv_error = TRUE;
+ return FAIL;
+ }
+ }
+ }
+#endif
+
+#ifdef MACOS_CONVERT
+ else if (flags & FIO_MACROMAN)
+ {
+ /*
+ * Convert UTF-8 or latin1 to Apple MacRoman.
+ */
+ char_u *from;
+ size_t fromlen;
+
+ if (ip->bw_restlen > 0)
+ {
+ /* Need to concatenate the remainder of the previous call and
+ * the bytes of the current call. Use the end of the
+ * conversion buffer for this. */
+ fromlen = len + ip->bw_restlen;
+ from = ip->bw_conv_buf + ip->bw_conv_buflen - fromlen;
+ mch_memmove(from, ip->bw_rest, (size_t)ip->bw_restlen);
+ mch_memmove(from + ip->bw_restlen, buf, (size_t)len);
+ }
+ else
+ {
+ from = buf;
+ fromlen = len;
+ }
+
+ if (enc2macroman(from, fromlen,
+ ip->bw_conv_buf, &len, ip->bw_conv_buflen,
+ ip->bw_rest, &ip->bw_restlen) == FAIL)
+ {
+ ip->bw_conv_error = TRUE;
+ return FAIL;
+ }
+ buf = ip->bw_conv_buf;
+ }
+#endif
+
+#ifdef USE_ICONV
+ if (ip->bw_iconv_fd != (iconv_t)-1)
+ {
+ const char *from;
+ size_t fromlen;
+ char *to;
+ size_t tolen;
+
+ /* Convert with iconv(). */
+ if (ip->bw_restlen > 0)
+ {
+ char *fp;
+
+ /* Need to concatenate the remainder of the previous call and
+ * the bytes of the current call. Use the end of the
+ * conversion buffer for this. */
+ fromlen = len + ip->bw_restlen;
+ fp = (char *)ip->bw_conv_buf + ip->bw_conv_buflen - fromlen;
+ mch_memmove(fp, ip->bw_rest, (size_t)ip->bw_restlen);
+ mch_memmove(fp + ip->bw_restlen, buf, (size_t)len);
+ from = fp;
+ tolen = ip->bw_conv_buflen - fromlen;
+ }
+ else
+ {
+ from = (const char *)buf;
+ fromlen = len;
+ tolen = ip->bw_conv_buflen;
+ }
+ to = (char *)ip->bw_conv_buf;
+
+ if (ip->bw_first)
+ {
+ size_t save_len = tolen;
+
+ /* output the initial shift state sequence */
+ (void)iconv(ip->bw_iconv_fd, NULL, NULL, &to, &tolen);
+
+ /* There is a bug in iconv() on Linux (which appears to be
+ * wide-spread) which sets "to" to NULL and messes up "tolen".
+ */
+ if (to == NULL)
+ {
+ to = (char *)ip->bw_conv_buf;
+ tolen = save_len;
+ }
+ ip->bw_first = FALSE;
+ }
+
+ /*
+ * If iconv() has an error or there is not enough room, fail.
+ */
+ if ((iconv(ip->bw_iconv_fd, (void *)&from, &fromlen, &to, &tolen)
+ == (size_t)-1 && ICONV_ERRNO != ICONV_EINVAL)
+ || fromlen > CONV_RESTLEN)
+ {
+ ip->bw_conv_error = TRUE;
+ return FAIL;
+ }
+
+ /* copy remainder to ip->bw_rest[] to be used for the next call. */
+ if (fromlen > 0)
+ mch_memmove(ip->bw_rest, (void *)from, fromlen);
+ ip->bw_restlen = (int)fromlen;
+
+ buf = ip->bw_conv_buf;
+ len = (int)((char_u *)to - ip->bw_conv_buf);
+ }
+#endif
+ }
+
+ if (ip->bw_fd < 0)
+ /* Only checking conversion, which is OK if we get here. */
+ return OK;
+
+#ifdef FEAT_CRYPT
+ if (flags & FIO_ENCRYPTED)
+ {
+ /* Encrypt the data. Do it in-place if possible, otherwise use an
+ * allocated buffer. */
+# ifdef CRYPT_NOT_INPLACE
+ if (crypt_works_inplace(ip->bw_buffer->b_cryptstate))
+ {
+# endif
+ crypt_encode_inplace(ip->bw_buffer->b_cryptstate, buf, len);
+# ifdef CRYPT_NOT_INPLACE
+ }
+ else
+ {
+ char_u *outbuf;
+
+ len = crypt_encode_alloc(curbuf->b_cryptstate, buf, len, &outbuf);
+ if (len == 0)
+ return OK; /* Crypt layer is buffering, will flush later. */
+ wlen = write_eintr(ip->bw_fd, outbuf, len);
+ vim_free(outbuf);
+ return (wlen < len) ? FAIL : OK;
+ }
+# endif
+ }
+#endif
+
+ wlen = write_eintr(ip->bw_fd, buf, len);
+ return (wlen < len) ? FAIL : OK;
+}
+
+/*
+ * Convert a Unicode character to bytes.
+ * Return TRUE for an error, FALSE when it's OK.
+ */
+ static int
+ucs2bytes(
+ unsigned c, /* in: character */
+ char_u **pp, /* in/out: pointer to result */
+ int flags) /* FIO_ flags */
+{
+ char_u *p = *pp;
+ int error = FALSE;
+ int cc;
+
+
+ if (flags & FIO_UCS4)
+ {
+ if (flags & FIO_ENDIAN_L)
+ {
+ *p++ = c;
+ *p++ = (c >> 8);
+ *p++ = (c >> 16);
+ *p++ = (c >> 24);
+ }
+ else
+ {
+ *p++ = (c >> 24);
+ *p++ = (c >> 16);
+ *p++ = (c >> 8);
+ *p++ = c;
+ }
+ }
+ else if (flags & (FIO_UCS2 | FIO_UTF16))
+ {
+ if (c >= 0x10000)
+ {
+ if (flags & FIO_UTF16)
+ {
+ /* Make two words, ten bits of the character in each. First
+ * word is 0xd800 - 0xdbff, second one 0xdc00 - 0xdfff */
+ c -= 0x10000;
+ if (c >= 0x100000)
+ error = TRUE;
+ cc = ((c >> 10) & 0x3ff) + 0xd800;
+ if (flags & FIO_ENDIAN_L)
+ {
+ *p++ = cc;
+ *p++ = ((unsigned)cc >> 8);
+ }
+ else
+ {
+ *p++ = ((unsigned)cc >> 8);
+ *p++ = cc;
+ }
+ c = (c & 0x3ff) + 0xdc00;
+ }
+ else
+ error = TRUE;
+ }
+ if (flags & FIO_ENDIAN_L)
+ {
+ *p++ = c;
+ *p++ = (c >> 8);
+ }
+ else
+ {
+ *p++ = (c >> 8);
+ *p++ = c;
+ }
+ }
+ else /* Latin1 */
+ {
+ if (c >= 0x100)
+ {
+ error = TRUE;
+ *p++ = 0xBF;
+ }
+ else
+ *p++ = c;
+ }
+
+ *pp = p;
+ return error;
+}
+
+/*
+ * Return TRUE if file encoding "fenc" requires conversion from or to
+ * 'encoding'.
+ */
+ static int
+need_conversion(char_u *fenc)
+{
+ int same_encoding;
+ int enc_flags;
+ int fenc_flags;
+
+ if (*fenc == NUL || STRCMP(p_enc, fenc) == 0)
+ {
+ same_encoding = TRUE;
+ fenc_flags = 0;
+ }
+ else
+ {
+ /* Ignore difference between "ansi" and "latin1", "ucs-4" and
+ * "ucs-4be", etc. */
+ enc_flags = get_fio_flags(p_enc);
+ fenc_flags = get_fio_flags(fenc);
+ same_encoding = (enc_flags != 0 && fenc_flags == enc_flags);
+ }
+ if (same_encoding)
+ {
+ /* Specified encoding matches with 'encoding'. This requires
+ * conversion when 'encoding' is Unicode but not UTF-8. */
+ return enc_unicode != 0;
+ }
+
+ /* Encodings differ. However, conversion is not needed when 'enc' is any
+ * Unicode encoding and the file is UTF-8. */
+ return !(enc_utf8 && fenc_flags == FIO_UTF8);
+}
+
+/*
+ * Check "ptr" for a unicode encoding and return the FIO_ flags needed for the
+ * internal conversion.
+ * if "ptr" is an empty string, use 'encoding'.
+ */
+ static int
+get_fio_flags(char_u *ptr)
+{
+ int prop;
+
+ if (*ptr == NUL)
+ ptr = p_enc;
+
+ prop = enc_canon_props(ptr);
+ if (prop & ENC_UNICODE)
+ {
+ if (prop & ENC_2BYTE)
+ {
+ if (prop & ENC_ENDIAN_L)
+ return FIO_UCS2 | FIO_ENDIAN_L;
+ return FIO_UCS2;
+ }
+ if (prop & ENC_4BYTE)
+ {
+ if (prop & ENC_ENDIAN_L)
+ return FIO_UCS4 | FIO_ENDIAN_L;
+ return FIO_UCS4;
+ }
+ if (prop & ENC_2WORD)
+ {
+ if (prop & ENC_ENDIAN_L)
+ return FIO_UTF16 | FIO_ENDIAN_L;
+ return FIO_UTF16;
+ }
+ return FIO_UTF8;
+ }
+ if (prop & ENC_LATIN1)
+ return FIO_LATIN1;
+ /* must be ENC_DBCS, requires iconv() */
+ return 0;
+}
+
+#ifdef WIN3264
+/*
+ * Check "ptr" for a MS-Windows codepage name and return the FIO_ flags needed
+ * for the conversion MS-Windows can do for us. Also accept "utf-8".
+ * Used for conversion between 'encoding' and 'fileencoding'.
+ */
+ static int
+get_win_fio_flags(char_u *ptr)
+{
+ int cp;
+
+ /* Cannot do this when 'encoding' is not utf-8 and not a codepage. */
+ if (!enc_utf8 && enc_codepage <= 0)
+ return 0;
+
+ cp = encname2codepage(ptr);
+ if (cp == 0)
+ {
+# ifdef CP_UTF8 /* VC 4.1 doesn't define CP_UTF8 */
+ if (STRCMP(ptr, "utf-8") == 0)
+ cp = CP_UTF8;
+ else
+# endif
+ return 0;
+ }
+ return FIO_PUT_CP(cp) | FIO_CODEPAGE;
+}
+#endif
+
+#ifdef MACOS_CONVERT
+/*
+ * Check "ptr" for a Carbon supported encoding and return the FIO_ flags
+ * needed for the internal conversion to/from utf-8 or latin1.
+ */
+ static int
+get_mac_fio_flags(char_u *ptr)
+{
+ if ((enc_utf8 || STRCMP(p_enc, "latin1") == 0)
+ && (enc_canon_props(ptr) & ENC_MACROMAN))
+ return FIO_MACROMAN;
+ return 0;
+}
+#endif
+
+/*
+ * Check for a Unicode BOM (Byte Order Mark) at the start of p[size].
+ * "size" must be at least 2.
+ * Return the name of the encoding and set "*lenp" to the length.
+ * Returns NULL when no BOM found.
+ */
+ static char_u *
+check_for_bom(
+ char_u *p,
+ long size,
+ int *lenp,
+ int flags)
+{
+ char *name = NULL;
+ int len = 2;
+
+ if (p[0] == 0xef && p[1] == 0xbb && size >= 3 && p[2] == 0xbf
+ && (flags == FIO_ALL || flags == FIO_UTF8 || flags == 0))
+ {
+ name = "utf-8"; /* EF BB BF */
+ len = 3;
+ }
+ else if (p[0] == 0xff && p[1] == 0xfe)
+ {
+ if (size >= 4 && p[2] == 0 && p[3] == 0
+ && (flags == FIO_ALL || flags == (FIO_UCS4 | FIO_ENDIAN_L)))
+ {
+ name = "ucs-4le"; /* FF FE 00 00 */
+ len = 4;
+ }
+ else if (flags == (FIO_UCS2 | FIO_ENDIAN_L))
+ name = "ucs-2le"; /* FF FE */
+ else if (flags == FIO_ALL || flags == (FIO_UTF16 | FIO_ENDIAN_L))
+ /* utf-16le is preferred, it also works for ucs-2le text */
+ name = "utf-16le"; /* FF FE */
+ }
+ else if (p[0] == 0xfe && p[1] == 0xff
+ && (flags == FIO_ALL || flags == FIO_UCS2 || flags == FIO_UTF16))
+ {
+ /* Default to utf-16, it works also for ucs-2 text. */
+ if (flags == FIO_UCS2)
+ name = "ucs-2"; /* FE FF */
+ else
+ name = "utf-16"; /* FE FF */
+ }
+ else if (size >= 4 && p[0] == 0 && p[1] == 0 && p[2] == 0xfe
+ && p[3] == 0xff && (flags == FIO_ALL || flags == FIO_UCS4))
+ {
+ name = "ucs-4"; /* 00 00 FE FF */
+ len = 4;
+ }
+
+ *lenp = len;
+ return (char_u *)name;
+}
+
+/*
+ * Generate a BOM in "buf[4]" for encoding "name".
+ * Return the length of the BOM (zero when no BOM).
+ */
+ static int
+make_bom(char_u *buf, char_u *name)
+{
+ int flags;
+ char_u *p;
+
+ flags = get_fio_flags(name);
+
+ /* Can't put a BOM in a non-Unicode file. */
+ if (flags == FIO_LATIN1 || flags == 0)
+ return 0;
+
+ if (flags == FIO_UTF8) /* UTF-8 */
+ {
+ buf[0] = 0xef;
+ buf[1] = 0xbb;
+ buf[2] = 0xbf;
+ return 3;
+ }
+ p = buf;
+ (void)ucs2bytes(0xfeff, &p, flags);
+ return (int)(p - buf);
+}
+
+/*
+ * Try to find a shortname by comparing the fullname with the current
+ * directory.
+ * Returns "full_path" or pointer into "full_path" if shortened.
+ */
+ char_u *
+shorten_fname1(char_u *full_path)
+{
+ char_u *dirname;
+ char_u *p = full_path;
+
+ dirname = alloc(MAXPATHL);
+ if (dirname == NULL)
+ return full_path;
+ if (mch_dirname(dirname, MAXPATHL) == OK)
+ {
+ p = shorten_fname(full_path, dirname);
+ if (p == NULL || *p == NUL)
+ p = full_path;
+ }
+ vim_free(dirname);
+ return p;
+}
+
+/*
+ * Try to find a shortname by comparing the fullname with the current
+ * directory.
+ * Returns NULL if not shorter name possible, pointer into "full_path"
+ * otherwise.
+ */
+ char_u *
+shorten_fname(char_u *full_path, char_u *dir_name)
+{
+ int len;
+ char_u *p;
+
+ if (full_path == NULL)
+ return NULL;
+ len = (int)STRLEN(dir_name);
+ if (fnamencmp(dir_name, full_path, len) == 0)
+ {
+ p = full_path + len;
+#if defined(MSWIN)
+ /*
+ * MSWIN: when a file is in the root directory, dir_name will end in a
+ * slash, since C: by itself does not define a specific dir. In this
+ * case p may already be correct. <negri>
+ */
+ if (!((len > 2) && (*(p - 2) == ':')))
+#endif
+ {
+ if (vim_ispathsep(*p))
+ ++p;
+#ifndef VMS /* the path separator is always part of the path */
+ else
+ p = NULL;
+#endif
+ }
+ }
+#if defined(MSWIN)
+ /*
+ * When using a file in the current drive, remove the drive name:
+ * "A:\dir\file" -> "\dir\file". This helps when moving a session file on
+ * a floppy from "A:\dir" to "B:\dir".
+ */
+ else if (len > 3
+ && TOUPPER_LOC(full_path[0]) == TOUPPER_LOC(dir_name[0])
+ && full_path[1] == ':'
+ && vim_ispathsep(full_path[2]))
+ p = full_path + 2;
+#endif
+ else
+ p = NULL;
+ return p;
+}
+
+/*
+ * Shorten filename of a buffer.
+ * When "force" is TRUE: Use full path from now on for files currently being
+ * edited, both for file name and swap file name. Try to shorten the file
+ * names a bit, if safe to do so.
+ * When "force" is FALSE: Only try to shorten absolute file names.
+ * For buffers that have buftype "nofile" or "scratch": never change the file
+ * name.
+ */
+ void
+shorten_buf_fname(buf_T *buf, char_u *dirname, int force)
+{
+ char_u *p;
+
+ if (buf->b_fname != NULL
+#ifdef FEAT_QUICKFIX
+ && !bt_nofile(buf)
+#endif
+ && !path_with_url(buf->b_fname)
+ && (force
+ || buf->b_sfname == NULL
+ || mch_isFullName(buf->b_sfname)))
+ {
+ if (buf->b_sfname != buf->b_ffname)
+ VIM_CLEAR(buf->b_sfname);
+ p = shorten_fname(buf->b_ffname, dirname);
+ if (p != NULL)
+ {
+ buf->b_sfname = vim_strsave(p);
+ buf->b_fname = buf->b_sfname;
+ }
+ if (p == NULL || buf->b_fname == NULL)
+ buf->b_fname = buf->b_ffname;
+ }
+}
+
+/*
+ * Shorten filenames for all buffers.
+ */
+ void
+shorten_fnames(int force)
+{
+ char_u dirname[MAXPATHL];
+ buf_T *buf;
+
+ mch_dirname(dirname, MAXPATHL);
+ FOR_ALL_BUFFERS(buf)
+ {
+ shorten_buf_fname(buf, dirname, force);
+
+ /* Always make the swap file name a full path, a "nofile" buffer may
+ * also have a swap file. */
+ mf_fullname(buf->b_ml.ml_mfp);
+ }
+ status_redraw_all();
+ redraw_tabline = TRUE;
+}
+
+#if (defined(FEAT_DND) && defined(FEAT_GUI_GTK)) \
+ || defined(FEAT_GUI_MSWIN) \
+ || defined(FEAT_GUI_MAC) \
+ || defined(PROTO)
+/*
+ * Shorten all filenames in "fnames[count]" by current directory.
+ */
+ void
+shorten_filenames(char_u **fnames, int count)
+{
+ int i;
+ char_u dirname[MAXPATHL];
+ char_u *p;
+
+ if (fnames == NULL || count < 1)
+ return;
+ mch_dirname(dirname, sizeof(dirname));
+ for (i = 0; i < count; ++i)
+ {
+ if ((p = shorten_fname(fnames[i], dirname)) != NULL)
+ {
+ /* shorten_fname() returns pointer in given "fnames[i]". If free
+ * "fnames[i]" first, "p" becomes invalid. So we need to copy
+ * "p" first then free fnames[i]. */
+ p = vim_strsave(p);
+ vim_free(fnames[i]);
+ fnames[i] = p;
+ }
+ }
+}
+#endif
+
+/*
+ * Add extension to file name - change path/fo.o.h to path/fo.o.h.ext or
+ * fo_o_h.ext for MSDOS or when shortname option set.
+ *
+ * Assumed that fname is a valid name found in the filesystem we assure that
+ * the return value is a different name and ends in 'ext'.
+ * "ext" MUST be at most 4 characters long if it starts with a dot, 3
+ * characters otherwise.
+ * Space for the returned name is allocated, must be freed later.
+ * Returns NULL when out of memory.
+ */
+ char_u *
+modname(
+ char_u *fname,
+ char_u *ext,
+ int prepend_dot) /* may prepend a '.' to file name */
+{
+ return buf_modname((curbuf->b_p_sn || curbuf->b_shortname),
+ fname, ext, prepend_dot);
+}
+
+ char_u *
+buf_modname(
+ int shortname, /* use 8.3 file name */
+ char_u *fname,
+ char_u *ext,
+ int prepend_dot) /* may prepend a '.' to file name */
+{
+ char_u *retval;
+ char_u *s;
+ char_u *e;
+ char_u *ptr;
+ int fnamelen, extlen;
+
+ extlen = (int)STRLEN(ext);
+
+ /*
+ * If there is no file name we must get the name of the current directory
+ * (we need the full path in case :cd is used).
+ */
+ if (fname == NULL || *fname == NUL)
+ {
+ retval = alloc((unsigned)(MAXPATHL + extlen + 3));
+ if (retval == NULL)
+ return NULL;
+ if (mch_dirname(retval, MAXPATHL) == FAIL ||
+ (fnamelen = (int)STRLEN(retval)) == 0)
+ {
+ vim_free(retval);
+ return NULL;
+ }
+ if (!after_pathsep(retval, retval + fnamelen))
+ {
+ retval[fnamelen++] = PATHSEP;
+ retval[fnamelen] = NUL;
+ }
+ prepend_dot = FALSE; /* nothing to prepend a dot to */
+ }
+ else
+ {
+ fnamelen = (int)STRLEN(fname);
+ retval = alloc((unsigned)(fnamelen + extlen + 3));
+ if (retval == NULL)
+ return NULL;
+ STRCPY(retval, fname);
+#ifdef VMS
+ vms_remove_version(retval); /* we do not need versions here */
+#endif
+ }
+
+ /*
+ * search backwards until we hit a '/', '\' or ':' replacing all '.'
+ * by '_' for MSDOS or when shortname option set and ext starts with a dot.
+ * Then truncate what is after the '/', '\' or ':' to 8 characters for
+ * MSDOS and 26 characters for AMIGA, a lot more for UNIX.
+ */
+ for (ptr = retval + fnamelen; ptr > retval; MB_PTR_BACK(retval, ptr))
+ {
+ if (*ext == '.'
+#ifdef USE_LONG_FNAME
+ && (!USE_LONG_FNAME || shortname)
+#else
+ && shortname
+#endif
+ )
+ if (*ptr == '.') /* replace '.' by '_' */
+ *ptr = '_';
+ if (vim_ispathsep(*ptr))
+ {
+ ++ptr;
+ break;
+ }
+ }
+
+ /* the file name has at most BASENAMELEN characters. */
+ if (STRLEN(ptr) > (unsigned)BASENAMELEN)
+ ptr[BASENAMELEN] = '\0';
+
+ s = ptr + STRLEN(ptr);
+
+ /*
+ * For 8.3 file names we may have to reduce the length.
+ */
+#ifdef USE_LONG_FNAME
+ if (!USE_LONG_FNAME || shortname)
+#else
+ if (shortname)
+#endif
+ {
+ /*
+ * If there is no file name, or the file name ends in '/', and the
+ * extension starts with '.', put a '_' before the dot, because just
+ * ".ext" is invalid.
+ */
+ if (fname == NULL || *fname == NUL
+ || vim_ispathsep(fname[STRLEN(fname) - 1]))
+ {
+ if (*ext == '.')
+ *s++ = '_';
+ }
+ /*
+ * If the extension starts with '.', truncate the base name at 8
+ * characters
+ */
+ else if (*ext == '.')
+ {
+ if ((size_t)(s - ptr) > (size_t)8)
+ {
+ s = ptr + 8;
+ *s = '\0';
+ }
+ }
+ /*
+ * If the extension doesn't start with '.', and the file name
+ * doesn't have an extension yet, append a '.'
+ */
+ else if ((e = vim_strchr(ptr, '.')) == NULL)
+ *s++ = '.';
+ /*
+ * If the extension doesn't start with '.', and there already is an
+ * extension, it may need to be truncated
+ */
+ else if ((int)STRLEN(e) + extlen > 4)
+ s = e + 4 - extlen;
+ }
+#if defined(USE_LONG_FNAME) || defined(WIN3264)
+ /*
+ * If there is no file name, and the extension starts with '.', put a
+ * '_' before the dot, because just ".ext" may be invalid if it's on a
+ * FAT partition, and on HPFS it doesn't matter.
+ */
+ else if ((fname == NULL || *fname == NUL) && *ext == '.')
+ *s++ = '_';
+#endif
+
+ /*
+ * Append the extension.
+ * ext can start with '.' and cannot exceed 3 more characters.
+ */
+ STRCPY(s, ext);
+
+ /*
+ * Prepend the dot.
+ */
+ if (prepend_dot && !shortname && *(e = gettail(retval)) != '.'
+#ifdef USE_LONG_FNAME
+ && USE_LONG_FNAME
+#endif
+ )
+ {
+ STRMOVE(e + 1, e);
+ *e = '.';
+ }
+
+ /*
+ * Check that, after appending the extension, the file name is really
+ * different.
+ */
+ if (fname != NULL && STRCMP(fname, retval) == 0)
+ {
+ /* we search for a character that can be replaced by '_' */
+ while (--s >= ptr)
+ {
+ if (*s != '_')
+ {
+ *s = '_';
+ break;
+ }
+ }
+ if (s < ptr) /* fname was "________.<ext>", how tricky! */
+ *ptr = 'v';
+ }
+ return retval;
+}
+
+/*
+ * Like fgets(), but if the file line is too long, it is truncated and the
+ * rest of the line is thrown away. Returns TRUE for end-of-file.
+ * If the line is truncated then buf[size - 2] will not be NUL.
+ */
+ int
+vim_fgets(char_u *buf, int size, FILE *fp)
+{
+ char *eof;
+#define FGETS_SIZE 200
+ char tbuf[FGETS_SIZE];
+
+ buf[size - 2] = NUL;
+#ifdef USE_CR
+ eof = fgets_cr((char *)buf, size, fp);
+#else
+ eof = fgets((char *)buf, size, fp);
+#endif
+ if (buf[size - 2] != NUL && buf[size - 2] != '\n')
+ {
+ buf[size - 1] = NUL; /* Truncate the line */
+
+ /* Now throw away the rest of the line: */
+ do
+ {
+ tbuf[FGETS_SIZE - 2] = NUL;
+#ifdef USE_CR
+ vim_ignoredp = fgets_cr((char *)tbuf, FGETS_SIZE, fp);
+#else
+ vim_ignoredp = fgets((char *)tbuf, FGETS_SIZE, fp);
+#endif
+ } while (tbuf[FGETS_SIZE - 2] != NUL && tbuf[FGETS_SIZE - 2] != '\n');
+ }
+ return (eof == NULL);
+}
+
+#if defined(USE_CR) || defined(PROTO)
+/*
+ * Like vim_fgets(), but accept any line terminator: CR, CR-LF or LF.
+ * Returns TRUE for end-of-file.
+ * Only used for the Mac, because it's much slower than vim_fgets().
+ */
+ int
+tag_fgets(char_u *buf, int size, FILE *fp)
+{
+ int i = 0;
+ int c;
+ int eof = FALSE;
+
+ for (;;)
+ {
+ c = fgetc(fp);
+ if (c == EOF)
+ {
+ eof = TRUE;
+ break;
+ }
+ if (c == '\r')
+ {
+ /* Always store a NL for end-of-line. */
+ if (i < size - 1)
+ buf[i++] = '\n';
+ c = fgetc(fp);
+ if (c != '\n') /* Macintosh format: single CR. */
+ ungetc(c, fp);
+ break;
+ }
+ if (i < size - 1)
+ buf[i++] = c;
+ if (c == '\n')
+ break;
+ }
+ buf[i] = NUL;
+ return eof;
+}
+#endif
+
+/*
+ * rename() only works if both files are on the same file system, this
+ * function will (attempts to?) copy the file across if rename fails -- webb
+ * Return -1 for failure, 0 for success.
+ */
+ int
+vim_rename(char_u *from, char_u *to)
+{
+ int fd_in;
+ int fd_out;
+ int n;
+ char *errmsg = NULL;
+ char *buffer;
+#ifdef AMIGA
+ BPTR flock;
+#endif
+ stat_T st;
+ long perm;
+#ifdef HAVE_ACL
+ vim_acl_T acl; /* ACL from original file */
+#endif
+ int use_tmp_file = FALSE;
+
+ /*
+ * When the names are identical, there is nothing to do. When they refer
+ * to the same file (ignoring case and slash/backslash differences) but
+ * the file name differs we need to go through a temp file.
+ */
+ if (fnamecmp(from, to) == 0)
+ {
+ if (p_fic && STRCMP(gettail(from), gettail(to)) != 0)
+ use_tmp_file = TRUE;
+ else
+ return 0;
+ }
+
+ /*
+ * Fail if the "from" file doesn't exist. Avoids that "to" is deleted.
+ */
+ if (mch_stat((char *)from, &st) < 0)
+ return -1;
+
+#ifdef UNIX
+ {
+ stat_T st_to;
+
+ /* It's possible for the source and destination to be the same file.
+ * This happens when "from" and "to" differ in case and are on a FAT32
+ * filesystem. In that case go through a temp file name. */
+ if (mch_stat((char *)to, &st_to) >= 0
+ && st.st_dev == st_to.st_dev
+ && st.st_ino == st_to.st_ino)
+ use_tmp_file = TRUE;
+ }
+#endif
+#ifdef WIN3264
+ {
+ BY_HANDLE_FILE_INFORMATION info1, info2;
+
+ /* It's possible for the source and destination to be the same file.
+ * In that case go through a temp file name. This makes rename("foo",
+ * "./foo") a no-op (in a complicated way). */
+ if (win32_fileinfo(from, &info1) == FILEINFO_OK
+ && win32_fileinfo(to, &info2) == FILEINFO_OK
+ && info1.dwVolumeSerialNumber == info2.dwVolumeSerialNumber
+ && info1.nFileIndexHigh == info2.nFileIndexHigh
+ && info1.nFileIndexLow == info2.nFileIndexLow)
+ use_tmp_file = TRUE;
+ }
+#endif
+
+ if (use_tmp_file)
+ {
+ char tempname[MAXPATHL + 1];
+
+ /*
+ * Find a name that doesn't exist and is in the same directory.
+ * Rename "from" to "tempname" and then rename "tempname" to "to".
+ */
+ if (STRLEN(from) >= MAXPATHL - 5)
+ return -1;
+ STRCPY(tempname, from);
+ for (n = 123; n < 99999; ++n)
+ {
+ sprintf((char *)gettail((char_u *)tempname), "%d", n);
+ if (mch_stat(tempname, &st) < 0)
+ {
+ if (mch_rename((char *)from, tempname) == 0)
+ {
+ if (mch_rename(tempname, (char *)to) == 0)
+ return 0;
+ /* Strange, the second step failed. Try moving the
+ * file back and return failure. */
+ mch_rename(tempname, (char *)from);
+ return -1;
+ }
+ /* If it fails for one temp name it will most likely fail
+ * for any temp name, give up. */
+ return -1;
+ }
+ }
+ return -1;
+ }
+
+ /*
+ * Delete the "to" file, this is required on some systems to make the
+ * mch_rename() work, on other systems it makes sure that we don't have
+ * two files when the mch_rename() fails.
+ */
+
+#ifdef AMIGA
+ /*
+ * With MSDOS-compatible filesystems (crossdos, messydos) it is possible
+ * that the name of the "to" file is the same as the "from" file, even
+ * though the names are different. To avoid the chance of accidentally
+ * deleting the "from" file (horror!) we lock it during the remove.
+ *
+ * When used for making a backup before writing the file: This should not
+ * happen with ":w", because startscript() should detect this problem and
+ * set buf->b_shortname, causing modname() to return a correct ".bak" file
+ * name. This problem does exist with ":w filename", but then the
+ * original file will be somewhere else so the backup isn't really
+ * important. If autoscripting is off the rename may fail.
+ */
+ flock = Lock((UBYTE *)from, (long)ACCESS_READ);
+#endif
+ mch_remove(to);
+#ifdef AMIGA
+ if (flock)
+ UnLock(flock);
+#endif
+
+ /*
+ * First try a normal rename, return if it works.
+ */
+ if (mch_rename((char *)from, (char *)to) == 0)
+ return 0;
+
+ /*
+ * Rename() failed, try copying the file.
+ */
+ perm = mch_getperm(from);
+#ifdef HAVE_ACL
+ /* For systems that support ACL: get the ACL from the original file. */
+ acl = mch_get_acl(from);
+#endif
+ fd_in = mch_open((char *)from, O_RDONLY|O_EXTRA, 0);
+ if (fd_in == -1)
+ {
+#ifdef HAVE_ACL
+ mch_free_acl(acl);
+#endif
+ return -1;
+ }
+
+ /* Create the new file with same permissions as the original. */
+ fd_out = mch_open((char *)to,
+ O_CREAT|O_EXCL|O_WRONLY|O_EXTRA|O_NOFOLLOW, (int)perm);
+ if (fd_out == -1)
+ {
+ close(fd_in);
+#ifdef HAVE_ACL
+ mch_free_acl(acl);
+#endif
+ return -1;
+ }
+
+ buffer = (char *)alloc(BUFSIZE);
+ if (buffer == NULL)
+ {
+ close(fd_out);
+ close(fd_in);
+#ifdef HAVE_ACL
+ mch_free_acl(acl);
+#endif
+ return -1;
+ }
+
+ while ((n = read_eintr(fd_in, buffer, BUFSIZE)) > 0)
+ if (write_eintr(fd_out, buffer, n) != n)
+ {
+ errmsg = _("E208: Error writing to \"%s\"");
+ break;
+ }
+
+ vim_free(buffer);
+ close(fd_in);
+ if (close(fd_out) < 0)
+ errmsg = _("E209: Error closing \"%s\"");
+ if (n < 0)
+ {
+ errmsg = _("E210: Error reading \"%s\"");
+ to = from;
+ }
+#ifndef UNIX /* for Unix mch_open() already set the permission */
+ mch_setperm(to, perm);
+#endif
+#ifdef HAVE_ACL
+ mch_set_acl(to, acl);
+ mch_free_acl(acl);
+#endif
+#if defined(HAVE_SELINUX) || defined(HAVE_SMACK)
+ mch_copy_sec(from, to);
+#endif
+ if (errmsg != NULL)
+ {
+ semsg(errmsg, to);
+ return -1;
+ }
+ mch_remove(from);
+ return 0;
+}
+
+static int already_warned = FALSE;
+
+/*
+ * Check if any not hidden buffer has been changed.
+ * Postpone the check if there are characters in the stuff buffer, a global
+ * command is being executed, a mapping is being executed or an autocommand is
+ * busy.
+ * Returns TRUE if some message was written (screen should be redrawn and
+ * cursor positioned).
+ */
+ int
+check_timestamps(
+ int focus) /* called for GUI focus event */
+{
+ buf_T *buf;
+ int didit = 0;
+ int n;
+
+ /* Don't check timestamps while system() or another low-level function may
+ * cause us to lose and gain focus. */
+ if (no_check_timestamps > 0)
+ return FALSE;
+
+ /* Avoid doing a check twice. The OK/Reload dialog can cause a focus
+ * event and we would keep on checking if the file is steadily growing.
+ * Do check again after typing something. */
+ if (focus && did_check_timestamps)
+ {
+ need_check_timestamps = TRUE;
+ return FALSE;
+ }
+
+ if (!stuff_empty() || global_busy || !typebuf_typed()
+ || autocmd_busy || curbuf_lock > 0 || allbuf_lock > 0)
+ need_check_timestamps = TRUE; /* check later */
+ else
+ {
+ ++no_wait_return;
+ did_check_timestamps = TRUE;
+ already_warned = FALSE;
+ FOR_ALL_BUFFERS(buf)
+ {
+ /* Only check buffers in a window. */
+ if (buf->b_nwindows > 0)
+ {
+ bufref_T bufref;
+
+ set_bufref(&bufref, buf);
+ n = buf_check_timestamp(buf, focus);
+ if (didit < n)
+ didit = n;
+ if (n > 0 && !bufref_valid(&bufref))
+ {
+ /* Autocommands have removed the buffer, start at the
+ * first one again. */
+ buf = firstbuf;
+ continue;
+ }
+ }
+ }
+ --no_wait_return;
+ need_check_timestamps = FALSE;
+ if (need_wait_return && didit == 2)
+ {
+ /* make sure msg isn't overwritten */
+ msg_puts("\n");
+ out_flush();
+ }
+ }
+ return didit;
+}
+
+/*
+ * Move all the lines from buffer "frombuf" to buffer "tobuf".
+ * Return OK or FAIL. When FAIL "tobuf" is incomplete and/or "frombuf" is not
+ * empty.
+ */
+ static int
+move_lines(buf_T *frombuf, buf_T *tobuf)
+{
+ buf_T *tbuf = curbuf;
+ int retval = OK;
+ linenr_T lnum;
+ char_u *p;
+
+ /* Copy the lines in "frombuf" to "tobuf". */
+ curbuf = tobuf;
+ for (lnum = 1; lnum <= frombuf->b_ml.ml_line_count; ++lnum)
+ {
+ p = vim_strsave(ml_get_buf(frombuf, lnum, FALSE));
+ if (p == NULL || ml_append(lnum - 1, p, 0, FALSE) == FAIL)
+ {
+ vim_free(p);
+ retval = FAIL;
+ break;
+ }
+ vim_free(p);
+ }
+
+ /* Delete all the lines in "frombuf". */
+ if (retval != FAIL)
+ {
+ curbuf = frombuf;
+ for (lnum = curbuf->b_ml.ml_line_count; lnum > 0; --lnum)
+ if (ml_delete(lnum, FALSE) == FAIL)
+ {
+ /* Oops! We could try putting back the saved lines, but that
+ * might fail again... */
+ retval = FAIL;
+ break;
+ }
+ }
+
+ curbuf = tbuf;
+ return retval;
+}
+
+/*
+ * Check if buffer "buf" has been changed.
+ * Also check if the file for a new buffer unexpectedly appeared.
+ * return 1 if a changed buffer was found.
+ * return 2 if a message has been displayed.
+ * return 0 otherwise.
+ */
+ int
+buf_check_timestamp(
+ buf_T *buf,
+ int focus UNUSED) /* called for GUI focus event */
+{
+ stat_T st;
+ int stat_res;
+ int retval = 0;
+ char_u *path;
+ char *tbuf;
+ char *mesg = NULL;
+ char *mesg2 = "";
+ int helpmesg = FALSE;
+ int reload = FALSE;
+ char *reason;
+#if defined(FEAT_CON_DIALOG) || defined(FEAT_GUI_DIALOG)
+ int can_reload = FALSE;
+#endif
+ off_T orig_size = buf->b_orig_size;
+ int orig_mode = buf->b_orig_mode;
+#ifdef FEAT_GUI
+ int save_mouse_correct = need_mouse_correct;
+#endif
+ static int busy = FALSE;
+ int n;
+#ifdef FEAT_EVAL
+ char_u *s;
+#endif
+ bufref_T bufref;
+
+ set_bufref(&bufref, buf);
+
+ /* If there is no file name, the buffer is not loaded, 'buftype' is
+ * set, we are in the middle of a save or being called recursively: ignore
+ * this buffer. */
+ if (buf->b_ffname == NULL
+ || buf->b_ml.ml_mfp == NULL
+ || !bt_normal(buf)
+ || buf->b_saving
+ || busy
+#ifdef FEAT_NETBEANS_INTG
+ || isNetbeansBuffer(buf)
+#endif
+#ifdef FEAT_TERMINAL
+ || buf->b_term != NULL
+#endif
+ )
+ return 0;
+
+ if ( !(buf->b_flags & BF_NOTEDITED)
+ && buf->b_mtime != 0
+ && ((stat_res = mch_stat((char *)buf->b_ffname, &st)) < 0
+ || time_differs((long)st.st_mtime, buf->b_mtime)
+ || st.st_size != buf->b_orig_size
+#ifdef HAVE_ST_MODE
+ || (int)st.st_mode != buf->b_orig_mode
+#else
+ || mch_getperm(buf->b_ffname) != buf->b_orig_mode
+#endif
+ ))
+ {
+ retval = 1;
+
+ // set b_mtime to stop further warnings (e.g., when executing
+ // FileChangedShell autocmd)
+ if (stat_res < 0)
+ {
+ // When 'autoread' is set we'll check the file again to see if it
+ // re-appears.
+ buf->b_mtime = buf->b_p_ar;
+ buf->b_orig_size = 0;
+ buf->b_orig_mode = 0;
+ }
+ else
+ buf_store_time(buf, &st, buf->b_ffname);
+
+ /* Don't do anything for a directory. Might contain the file
+ * explorer. */
+ if (mch_isdir(buf->b_fname))
+ ;
+
+ /*
+ * If 'autoread' is set, the buffer has no changes and the file still
+ * exists, reload the buffer. Use the buffer-local option value if it
+ * was set, the global option value otherwise.
+ */
+ else if ((buf->b_p_ar >= 0 ? buf->b_p_ar : p_ar)
+ && !bufIsChanged(buf) && stat_res >= 0)
+ reload = TRUE;
+ else
+ {
+ if (stat_res < 0)
+ reason = "deleted";
+ else if (bufIsChanged(buf))
+ reason = "conflict";
+ /*
+ * Check if the file contents really changed to avoid giving a
+ * warning when only the timestamp was set (e.g., checked out of
+ * CVS). Always warn when the buffer was changed.
+ */
+ else if (orig_size != buf->b_orig_size || buf_contents_changed(buf))
+ reason = "changed";
+ else if (orig_mode != buf->b_orig_mode)
+ reason = "mode";
+ else
+ reason = "time";
+
+ /*
+ * Only give the warning if there are no FileChangedShell
+ * autocommands.
+ * Avoid being called recursively by setting "busy".
+ */
+ busy = TRUE;
+#ifdef FEAT_EVAL
+ set_vim_var_string(VV_FCS_REASON, (char_u *)reason, -1);
+ set_vim_var_string(VV_FCS_CHOICE, (char_u *)"", -1);
+#endif
+ ++allbuf_lock;
+ n = apply_autocmds(EVENT_FILECHANGEDSHELL,
+ buf->b_fname, buf->b_fname, FALSE, buf);
+ --allbuf_lock;
+ busy = FALSE;
+ if (n)
+ {
+ if (!bufref_valid(&bufref))
+ emsg(_("E246: FileChangedShell autocommand deleted buffer"));
+#ifdef FEAT_EVAL
+ s = get_vim_var_str(VV_FCS_CHOICE);
+ if (STRCMP(s, "reload") == 0 && *reason != 'd')
+ reload = TRUE;
+ else if (STRCMP(s, "ask") == 0)
+ n = FALSE;
+ else
+#endif
+ return 2;
+ }
+ if (!n)
+ {
+ if (*reason == 'd')
+ mesg = _("E211: File \"%s\" no longer available");
+ else
+ {
+ helpmesg = TRUE;
+#if defined(FEAT_CON_DIALOG) || defined(FEAT_GUI_DIALOG)
+ can_reload = TRUE;
+#endif
+ if (reason[2] == 'n')
+ {
+ mesg = _("W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as well");
+ mesg2 = _("See \":help W12\" for more info.");
+ }
+ else if (reason[1] == 'h')
+ {
+ mesg = _("W11: Warning: File \"%s\" has changed since editing started");
+ mesg2 = _("See \":help W11\" for more info.");
+ }
+ else if (*reason == 'm')
+ {
+ mesg = _("W16: Warning: Mode of file \"%s\" has changed since editing started");
+ mesg2 = _("See \":help W16\" for more info.");
+ }
+ else
+ /* Only timestamp changed, store it to avoid a warning
+ * in check_mtime() later. */
+ buf->b_mtime_read = buf->b_mtime;
+ }
+ }
+ }
+
+ }
+ else if ((buf->b_flags & BF_NEW) && !(buf->b_flags & BF_NEW_W)
+ && vim_fexists(buf->b_ffname))
+ {
+ retval = 1;
+ mesg = _("W13: Warning: File \"%s\" has been created after editing started");
+ buf->b_flags |= BF_NEW_W;
+#if defined(FEAT_CON_DIALOG) || defined(FEAT_GUI_DIALOG)
+ can_reload = TRUE;
+#endif
+ }
+
+ if (mesg != NULL)
+ {
+ path = home_replace_save(buf, buf->b_fname);
+ if (path != NULL)
+ {
+ if (!helpmesg)
+ mesg2 = "";
+ tbuf = (char *)alloc((unsigned)(STRLEN(path) + STRLEN(mesg)
+ + STRLEN(mesg2) + 2));
+ sprintf(tbuf, mesg, path);
+#ifdef FEAT_EVAL
+ /* Set warningmsg here, before the unimportant and output-specific
+ * mesg2 has been appended. */
+ set_vim_var_string(VV_WARNINGMSG, (char_u *)tbuf, -1);
+#endif
+#if defined(FEAT_CON_DIALOG) || defined(FEAT_GUI_DIALOG)
+ if (can_reload)
+ {
+ if (*mesg2 != NUL)
+ {
+ STRCAT(tbuf, "\n");
+ STRCAT(tbuf, mesg2);
+ }
+ if (do_dialog(VIM_WARNING, (char_u *)_("Warning"),
+ (char_u *)tbuf,
+ (char_u *)_("&OK\n&Load File"), 1, NULL, TRUE) == 2)
+ reload = TRUE;
+ }
+ else
+#endif
+ if (State > NORMAL_BUSY || (State & CMDLINE) || already_warned)
+ {
+ if (*mesg2 != NUL)
+ {
+ STRCAT(tbuf, "; ");
+ STRCAT(tbuf, mesg2);
+ }
+ emsg(tbuf);
+ retval = 2;
+ }
+ else
+ {
+ if (!autocmd_busy)
+ {
+ msg_start();
+ msg_puts_attr(tbuf, HL_ATTR(HLF_E) + MSG_HIST);
+ if (*mesg2 != NUL)
+ msg_puts_attr(mesg2, HL_ATTR(HLF_W) + MSG_HIST);
+ msg_clr_eos();
+ (void)msg_end();
+ if (emsg_silent == 0)
+ {
+ out_flush();
+#ifdef FEAT_GUI
+ if (!focus)
+#endif
+ /* give the user some time to think about it */
+ ui_delay(1000L, TRUE);
+
+ /* don't redraw and erase the message */
+ redraw_cmdline = FALSE;
+ }
+ }
+ already_warned = TRUE;
+ }
+
+ vim_free(path);
+ vim_free(tbuf);
+ }
+ }
+
+ if (reload)
+ {
+ /* Reload the buffer. */
+ buf_reload(buf, orig_mode);
+#ifdef FEAT_PERSISTENT_UNDO
+ if (buf->b_p_udf && buf->b_ffname != NULL)
+ {
+ char_u hash[UNDO_HASH_SIZE];
+ buf_T *save_curbuf = curbuf;
+
+ /* Any existing undo file is unusable, write it now. */
+ curbuf = buf;
+ u_compute_hash(hash);
+ u_write_undo(NULL, FALSE, buf, hash);
+ curbuf = save_curbuf;
+ }
+#endif
+ }
+
+ /* Trigger FileChangedShell when the file was changed in any way. */
+ if (bufref_valid(&bufref) && retval != 0)
+ (void)apply_autocmds(EVENT_FILECHANGEDSHELLPOST,
+ buf->b_fname, buf->b_fname, FALSE, buf);
+#ifdef FEAT_GUI
+ /* restore this in case an autocommand has set it; it would break
+ * 'mousefocus' */
+ need_mouse_correct = save_mouse_correct;
+#endif
+
+ return retval;
+}
+
+/*
+ * Reload a buffer that is already loaded.
+ * Used when the file was changed outside of Vim.
+ * "orig_mode" is buf->b_orig_mode before the need for reloading was detected.
+ * buf->b_orig_mode may have been reset already.
+ */
+ void
+buf_reload(buf_T *buf, int orig_mode)
+{
+ exarg_T ea;
+ pos_T old_cursor;
+ linenr_T old_topline;
+ int old_ro = buf->b_p_ro;
+ buf_T *savebuf;
+ bufref_T bufref;
+ int saved = OK;
+ aco_save_T aco;
+ int flags = READ_NEW;
+
+ /* set curwin/curbuf for "buf" and save some things */
+ aucmd_prepbuf(&aco, buf);
+
+ /* We only want to read the text from the file, not reset the syntax
+ * highlighting, clear marks, diff status, etc. Force the fileformat
+ * and encoding to be the same. */
+ if (prep_exarg(&ea, buf) == OK)
+ {
+ old_cursor = curwin->w_cursor;
+ old_topline = curwin->w_topline;
+
+ if (p_ur < 0 || curbuf->b_ml.ml_line_count <= p_ur)
+ {
+ /* Save all the text, so that the reload can be undone.
+ * Sync first so that this is a separate undo-able action. */
+ u_sync(FALSE);
+ saved = u_savecommon(0, curbuf->b_ml.ml_line_count + 1, 0, TRUE);
+ flags |= READ_KEEP_UNDO;
+ }
+
+ /*
+ * To behave like when a new file is edited (matters for
+ * BufReadPost autocommands) we first need to delete the current
+ * buffer contents. But if reading the file fails we should keep
+ * the old contents. Can't use memory only, the file might be
+ * too big. Use a hidden buffer to move the buffer contents to.
+ */
+ if (BUFEMPTY() || saved == FAIL)
+ savebuf = NULL;
+ else
+ {
+ /* Allocate a buffer without putting it in the buffer list. */
+ savebuf = buflist_new(NULL, NULL, (linenr_T)1, BLN_DUMMY);
+ set_bufref(&bufref, savebuf);
+ if (savebuf != NULL && buf == curbuf)
+ {
+ /* Open the memline. */
+ curbuf = savebuf;
+ curwin->w_buffer = savebuf;
+ saved = ml_open(curbuf);
+ curbuf = buf;
+ curwin->w_buffer = buf;
+ }
+ if (savebuf == NULL || saved == FAIL || buf != curbuf
+ || move_lines(buf, savebuf) == FAIL)
+ {
+ semsg(_("E462: Could not prepare for reloading \"%s\""),
+ buf->b_fname);
+ saved = FAIL;
+ }
+ }
+
+ if (saved == OK)
+ {
+ curbuf->b_flags |= BF_CHECK_RO; /* check for RO again */
+ keep_filetype = TRUE; /* don't detect 'filetype' */
+ if (readfile(buf->b_ffname, buf->b_fname, (linenr_T)0,
+ (linenr_T)0,
+ (linenr_T)MAXLNUM, &ea, flags) != OK)
+ {
+#if defined(FEAT_EVAL)
+ if (!aborting())
+#endif
+ semsg(_("E321: Could not reload \"%s\""), buf->b_fname);
+ if (savebuf != NULL && bufref_valid(&bufref) && buf == curbuf)
+ {
+ /* Put the text back from the save buffer. First
+ * delete any lines that readfile() added. */
+ while (!BUFEMPTY())
+ if (ml_delete(buf->b_ml.ml_line_count, FALSE) == FAIL)
+ break;
+ (void)move_lines(savebuf, buf);
+ }
+ }
+ else if (buf == curbuf) /* "buf" still valid */
+ {
+ /* Mark the buffer as unmodified and free undo info. */
+ unchanged(buf, TRUE);
+ if ((flags & READ_KEEP_UNDO) == 0)
+ {
+ u_blockfree(buf);
+ u_clearall(buf);
+ }
+ else
+ {
+ /* Mark all undo states as changed. */
+ u_unchanged(curbuf);
+ }
+ }
+ }
+ vim_free(ea.cmd);
+
+ if (savebuf != NULL && bufref_valid(&bufref))
+ wipe_buffer(savebuf, FALSE);
+
+#ifdef FEAT_DIFF
+ /* Invalidate diff info if necessary. */
+ diff_invalidate(curbuf);
+#endif
+
+ /* Restore the topline and cursor position and check it (lines may
+ * have been removed). */
+ if (old_topline > curbuf->b_ml.ml_line_count)
+ curwin->w_topline = curbuf->b_ml.ml_line_count;
+ else
+ curwin->w_topline = old_topline;
+ curwin->w_cursor = old_cursor;
+ check_cursor();
+ update_topline();
+ keep_filetype = FALSE;
+#ifdef FEAT_FOLDING
+ {
+ win_T *wp;
+ tabpage_T *tp;
+
+ /* Update folds unless they are defined manually. */
+ FOR_ALL_TAB_WINDOWS(tp, wp)
+ if (wp->w_buffer == curwin->w_buffer
+ && !foldmethodIsManual(wp))
+ foldUpdateAll(wp);
+ }
+#endif
+ /* If the mode didn't change and 'readonly' was set, keep the old
+ * value; the user probably used the ":view" command. But don't
+ * reset it, might have had a read error. */
+ if (orig_mode == curbuf->b_orig_mode)
+ curbuf->b_p_ro |= old_ro;
+
+ /* Modelines must override settings done by autocommands. */
+ do_modelines(0);
+ }
+
+ /* restore curwin/curbuf and a few other things */
+ aucmd_restbuf(&aco);
+ /* Careful: autocommands may have made "buf" invalid! */
+}
+
+ void
+buf_store_time(buf_T *buf, stat_T *st, char_u *fname UNUSED)
+{
+ buf->b_mtime = (long)st->st_mtime;
+ buf->b_orig_size = st->st_size;
+#ifdef HAVE_ST_MODE
+ buf->b_orig_mode = (int)st->st_mode;
+#else
+ buf->b_orig_mode = mch_getperm(fname);
+#endif
+}
+
+/*
+ * Adjust the line with missing eol, used for the next write.
+ * Used for do_filter(), when the input lines for the filter are deleted.
+ */
+ void
+write_lnum_adjust(linenr_T offset)
+{
+ if (curbuf->b_no_eol_lnum != 0) /* only if there is a missing eol */
+ curbuf->b_no_eol_lnum += offset;
+}
+
+#if defined(TEMPDIRNAMES) || defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * Delete "name" and everything in it, recursively.
+ * return 0 for succes, -1 if some file was not deleted.
+ */
+ int
+delete_recursive(char_u *name)
+{
+ int result = 0;
+ char_u **files;
+ int file_count;
+ int i;
+ char_u *exp;
+
+ /* A symbolic link to a directory itself is deleted, not the directory it
+ * points to. */
+ if (
+# if defined(UNIX) || defined(WIN32)
+ mch_isrealdir(name)
+# else
+ mch_isdir(name)
+# endif
+ )
+ {
+ vim_snprintf((char *)NameBuff, MAXPATHL, "%s/*", name);
+ exp = vim_strsave(NameBuff);
+ if (exp == NULL)
+ return -1;
+ if (gen_expand_wildcards(1, &exp, &file_count, &files,
+ EW_DIR|EW_FILE|EW_SILENT|EW_ALLLINKS|EW_DODOT|EW_EMPTYOK) == OK)
+ {
+ for (i = 0; i < file_count; ++i)
+ if (delete_recursive(files[i]) != 0)
+ result = -1;
+ FreeWild(file_count, files);
+ }
+ else
+ result = -1;
+ vim_free(exp);
+ (void)mch_rmdir(name);
+ }
+ else
+ result = mch_remove(name) == 0 ? 0 : -1;
+
+ return result;
+}
+#endif
+
+#if defined(TEMPDIRNAMES) || defined(PROTO)
+static long temp_count = 0; /* Temp filename counter. */
+
+/*
+ * Delete the temp directory and all files it contains.
+ */
+ void
+vim_deltempdir(void)
+{
+ if (vim_tempdir != NULL)
+ {
+ /* remove the trailing path separator */
+ gettail(vim_tempdir)[-1] = NUL;
+ delete_recursive(vim_tempdir);
+ VIM_CLEAR(vim_tempdir);
+ }
+}
+
+/*
+ * Directory "tempdir" was created. Expand this name to a full path and put
+ * it in "vim_tempdir". This avoids that using ":cd" would confuse us.
+ * "tempdir" must be no longer than MAXPATHL.
+ */
+ static void
+vim_settempdir(char_u *tempdir)
+{
+ char_u *buf;
+
+ buf = alloc((unsigned)MAXPATHL + 2);
+ if (buf != NULL)
+ {
+ if (vim_FullName(tempdir, buf, MAXPATHL, FALSE) == FAIL)
+ STRCPY(buf, tempdir);
+ add_pathsep(buf);
+ vim_tempdir = vim_strsave(buf);
+ vim_free(buf);
+ }
+}
+#endif
+
+/*
+ * vim_tempname(): Return a unique name that can be used for a temp file.
+ *
+ * The temp file is NOT guaranteed to be created. If "keep" is FALSE it is
+ * guaranteed to NOT be created.
+ *
+ * The returned pointer is to allocated memory.
+ * The returned pointer is NULL if no valid name was found.
+ */
+ char_u *
+vim_tempname(
+ int extra_char UNUSED, /* char to use in the name instead of '?' */
+ int keep UNUSED)
+{
+#ifdef USE_TMPNAM
+ char_u itmp[L_tmpnam]; /* use tmpnam() */
+#else
+ char_u itmp[TEMPNAMELEN];
+#endif
+
+#ifdef TEMPDIRNAMES
+ static char *(tempdirs[]) = {TEMPDIRNAMES};
+ int i;
+# ifndef EEXIST
+ stat_T st;
+# endif
+
+ /*
+ * This will create a directory for private use by this instance of Vim.
+ * This is done once, and the same directory is used for all temp files.
+ * This method avoids security problems because of symlink attacks et al.
+ * It's also a bit faster, because we only need to check for an existing
+ * file when creating the directory and not for each temp file.
+ */
+ if (vim_tempdir == NULL)
+ {
+ /*
+ * Try the entries in TEMPDIRNAMES to create the temp directory.
+ */
+ for (i = 0; i < (int)(sizeof(tempdirs) / sizeof(char *)); ++i)
+ {
+# ifndef HAVE_MKDTEMP
+ size_t itmplen;
+ long nr;
+ long off;
+# endif
+
+ /* Expand $TMP, leave room for "/v1100000/999999999".
+ * Skip the directory check if the expansion fails. */
+ expand_env((char_u *)tempdirs[i], itmp, TEMPNAMELEN - 20);
+ if (itmp[0] != '$' && mch_isdir(itmp))
+ {
+ /* directory exists */
+ add_pathsep(itmp);
+
+# ifdef HAVE_MKDTEMP
+ {
+# if defined(UNIX) || defined(VMS)
+ /* Make sure the umask doesn't remove the executable bit.
+ * "repl" has been reported to use "177". */
+ mode_t umask_save = umask(077);
+# endif
+ /* Leave room for filename */
+ STRCAT(itmp, "vXXXXXX");
+ if (mkdtemp((char *)itmp) != NULL)
+ vim_settempdir(itmp);
+# if defined(UNIX) || defined(VMS)
+ (void)umask(umask_save);
+# endif
+ }
+# else
+ /* Get an arbitrary number of up to 6 digits. When it's
+ * unlikely that it already exists it will be faster,
+ * otherwise it doesn't matter. The use of mkdir() avoids any
+ * security problems because of the predictable number. */
+ nr = (mch_get_pid() + (long)time(NULL)) % 1000000L;
+ itmplen = STRLEN(itmp);
+
+ /* Try up to 10000 different values until we find a name that
+ * doesn't exist. */
+ for (off = 0; off < 10000L; ++off)
+ {
+ int r;
+# if defined(UNIX) || defined(VMS)
+ mode_t umask_save;
+# endif
+
+ sprintf((char *)itmp + itmplen, "v%ld", nr + off);
+# ifndef EEXIST
+ /* If mkdir() does not set errno to EEXIST, check for
+ * existing file here. There is a race condition then,
+ * although it's fail-safe. */
+ if (mch_stat((char *)itmp, &st) >= 0)
+ continue;
+# endif
+# if defined(UNIX) || defined(VMS)
+ /* Make sure the umask doesn't remove the executable bit.
+ * "repl" has been reported to use "177". */
+ umask_save = umask(077);
+# endif
+ r = vim_mkdir(itmp, 0700);
+# if defined(UNIX) || defined(VMS)
+ (void)umask(umask_save);
+# endif
+ if (r == 0)
+ {
+ vim_settempdir(itmp);
+ break;
+ }
+# ifdef EEXIST
+ /* If the mkdir() didn't fail because the file/dir exists,
+ * we probably can't create any dir here, try another
+ * place. */
+ if (errno != EEXIST)
+# endif
+ break;
+ }
+# endif /* HAVE_MKDTEMP */
+ if (vim_tempdir != NULL)
+ break;
+ }
+ }
+ }
+
+ if (vim_tempdir != NULL)
+ {
+ /* There is no need to check if the file exists, because we own the
+ * directory and nobody else creates a file in it. */
+ sprintf((char *)itmp, "%s%ld", vim_tempdir, temp_count++);
+ return vim_strsave(itmp);
+ }
+
+ return NULL;
+
+#else /* TEMPDIRNAMES */
+
+# ifdef WIN3264
+ char szTempFile[_MAX_PATH + 1];
+ char buf4[4];
+ char_u *retval;
+ char_u *p;
+
+ STRCPY(itmp, "");
+ if (GetTempPath(_MAX_PATH, szTempFile) == 0)
+ {
+ szTempFile[0] = '.'; /* GetTempPath() failed, use current dir */
+ szTempFile[1] = NUL;
+ }
+ strcpy(buf4, "VIM");
+ buf4[2] = extra_char; /* make it "VIa", "VIb", etc. */
+ if (GetTempFileName(szTempFile, buf4, 0, (LPSTR)itmp) == 0)
+ return NULL;
+ if (!keep)
+ /* GetTempFileName() will create the file, we don't want that */
+ (void)DeleteFile((LPSTR)itmp);
+
+ /* Backslashes in a temp file name cause problems when filtering with
+ * "sh". NOTE: This also checks 'shellcmdflag' to help those people who
+ * didn't set 'shellslash'. */
+ retval = vim_strsave(itmp);
+ if (*p_shcf == '-' || p_ssl)
+ for (p = retval; *p; ++p)
+ if (*p == '\\')
+ *p = '/';
+ return retval;
+
+# else /* WIN3264 */
+
+# ifdef USE_TMPNAM
+ char_u *p;
+
+ /* tmpnam() will make its own name */
+ p = tmpnam((char *)itmp);
+ if (p == NULL || *p == NUL)
+ return NULL;
+# else
+ char_u *p;
+
+# ifdef VMS_TEMPNAM
+ /* mktemp() is not working on VMS. It seems to be
+ * a do-nothing function. Therefore we use tempnam().
+ */
+ sprintf((char *)itmp, "VIM%c", extra_char);
+ p = (char_u *)tempnam("tmp:", (char *)itmp);
+ if (p != NULL)
+ {
+ /* VMS will use '.LIS' if we don't explicitly specify an extension,
+ * and VIM will then be unable to find the file later */
+ STRCPY(itmp, p);
+ STRCAT(itmp, ".txt");
+ free(p);
+ }
+ else
+ return NULL;
+# else
+ STRCPY(itmp, TEMPNAME);
+ if ((p = vim_strchr(itmp, '?')) != NULL)
+ *p = extra_char;
+ if (mktemp((char *)itmp) == NULL)
+ return NULL;
+# endif
+# endif
+
+ return vim_strsave(itmp);
+# endif /* WIN3264 */
+#endif /* TEMPDIRNAMES */
+}
+
+#if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
+/*
+ * Convert all backslashes in fname to forward slashes in-place, unless when
+ * it looks like a URL.
+ */
+ void
+forward_slash(char_u *fname)
+{
+ char_u *p;
+
+ if (path_with_url(fname))
+ return;
+ for (p = fname; *p != NUL; ++p)
+ /* The Big5 encoding can have '\' in the trail byte. */
+ if (enc_dbcs != 0 && (*mb_ptr2len)(p) > 1)
+ ++p;
+ else if (*p == '\\')
+ *p = '/';
+}
+#endif
+
+/*
+ * Try matching a filename with a "pattern" ("prog" is NULL), or use the
+ * precompiled regprog "prog" ("pattern" is NULL). That avoids calling
+ * vim_regcomp() often.
+ * Used for autocommands and 'wildignore'.
+ * Returns TRUE if there is a match, FALSE otherwise.
+ */
+ int
+match_file_pat(
+ char_u *pattern, /* pattern to match with */
+ regprog_T **prog, /* pre-compiled regprog or NULL */
+ char_u *fname, /* full path of file name */
+ char_u *sfname, /* short file name or NULL */
+ char_u *tail, /* tail of path */
+ int allow_dirs) /* allow matching with dir */
+{
+ regmatch_T regmatch;
+ int result = FALSE;
+
+ regmatch.rm_ic = p_fic; /* ignore case if 'fileignorecase' is set */
+ if (prog != NULL)
+ regmatch.regprog = *prog;
+ else
+ regmatch.regprog = vim_regcomp(pattern, RE_MAGIC);
+
+ /*
+ * Try for a match with the pattern with:
+ * 1. the full file name, when the pattern has a '/'.
+ * 2. the short file name, when the pattern has a '/'.
+ * 3. the tail of the file name, when the pattern has no '/'.
+ */
+ if (regmatch.regprog != NULL
+ && ((allow_dirs
+ && (vim_regexec(&regmatch, fname, (colnr_T)0)
+ || (sfname != NULL
+ && vim_regexec(&regmatch, sfname, (colnr_T)0))))
+ || (!allow_dirs && vim_regexec(&regmatch, tail, (colnr_T)0))))
+ result = TRUE;
+
+ if (prog != NULL)
+ *prog = regmatch.regprog;
+ else
+ vim_regfree(regmatch.regprog);
+ return result;
+}
+
+#if defined(FEAT_WILDIGN) || defined(PROTO)
+/*
+ * Return TRUE if a file matches with a pattern in "list".
+ * "list" is a comma-separated list of patterns, like 'wildignore'.
+ * "sfname" is the short file name or NULL, "ffname" the long file name.
+ */
+ int
+match_file_list(char_u *list, char_u *sfname, char_u *ffname)
+{
+ char_u buf[100];
+ char_u *tail;
+ char_u *regpat;
+ char allow_dirs;
+ int match;
+ char_u *p;
+
+ tail = gettail(sfname);
+
+ /* try all patterns in 'wildignore' */
+ p = list;
+ while (*p)
+ {
+ copy_option_part(&p, buf, 100, ",");
+ regpat = file_pat_to_reg_pat(buf, NULL, &allow_dirs, FALSE);
+ if (regpat == NULL)
+ break;
+ match = match_file_pat(regpat, NULL, ffname, sfname,
+ tail, (int)allow_dirs);
+ vim_free(regpat);
+ if (match)
+ return TRUE;
+ }
+ return FALSE;
+}
+#endif
+
+/*
+ * Convert the given pattern "pat" which has shell style wildcards in it, into
+ * a regular expression, and return the result in allocated memory. If there
+ * is a directory path separator to be matched, then TRUE is put in
+ * allow_dirs, otherwise FALSE is put there -- webb.
+ * Handle backslashes before special characters, like "\*" and "\ ".
+ *
+ * Returns NULL when out of memory.
+ */
+ char_u *
+file_pat_to_reg_pat(
+ char_u *pat,
+ char_u *pat_end, /* first char after pattern or NULL */
+ char *allow_dirs, /* Result passed back out in here */
+ int no_bslash UNUSED) /* Don't use a backward slash as pathsep */
+{
+ int size = 2; /* '^' at start, '$' at end */
+ char_u *endp;
+ char_u *reg_pat;
+ char_u *p;
+ int i;
+ int nested = 0;
+ int add_dollar = TRUE;
+
+ if (allow_dirs != NULL)
+ *allow_dirs = FALSE;
+ if (pat_end == NULL)
+ pat_end = pat + STRLEN(pat);
+
+ for (p = pat; p < pat_end; p++)
+ {
+ switch (*p)
+ {
+ case '*':
+ case '.':
+ case ',':
+ case '{':
+ case '}':
+ case '~':
+ size += 2; /* extra backslash */
+ break;
+#ifdef BACKSLASH_IN_FILENAME
+ case '\\':
+ case '/':
+ size += 4; /* could become "[\/]" */
+ break;
+#endif
+ default:
+ size++;
+ if (enc_dbcs != 0 && (*mb_ptr2len)(p) > 1)
+ {
+ ++p;
+ ++size;
+ }
+ break;
+ }
+ }
+ reg_pat = alloc(size + 1);
+ if (reg_pat == NULL)
+ return NULL;
+
+ i = 0;
+
+ if (pat[0] == '*')
+ while (pat[0] == '*' && pat < pat_end - 1)
+ pat++;
+ else
+ reg_pat[i++] = '^';
+ endp = pat_end - 1;
+ if (endp >= pat && *endp == '*')
+ {
+ while (endp - pat > 0 && *endp == '*')
+ endp--;
+ add_dollar = FALSE;
+ }
+ for (p = pat; *p && nested >= 0 && p <= endp; p++)
+ {
+ switch (*p)
+ {
+ case '*':
+ reg_pat[i++] = '.';
+ reg_pat[i++] = '*';
+ while (p[1] == '*') /* "**" matches like "*" */
+ ++p;
+ break;
+ case '.':
+ case '~':
+ reg_pat[i++] = '\\';
+ reg_pat[i++] = *p;
+ break;
+ case '?':
+ reg_pat[i++] = '.';
+ break;
+ case '\\':
+ if (p[1] == NUL)
+ break;
+#ifdef BACKSLASH_IN_FILENAME
+ if (!no_bslash)
+ {
+ /* translate:
+ * "\x" to "\\x" e.g., "dir\file"
+ * "\*" to "\\.*" e.g., "dir\*.c"
+ * "\?" to "\\." e.g., "dir\??.c"
+ * "\+" to "\+" e.g., "fileX\+.c"
+ */
+ if ((vim_isfilec(p[1]) || p[1] == '*' || p[1] == '?')
+ && p[1] != '+')
+ {
+ reg_pat[i++] = '[';
+ reg_pat[i++] = '\\';
+ reg_pat[i++] = '/';
+ reg_pat[i++] = ']';
+ if (allow_dirs != NULL)
+ *allow_dirs = TRUE;
+ break;
+ }
+ }
+#endif
+ /* Undo escaping from ExpandEscape():
+ * foo\?bar -> foo?bar
+ * foo\%bar -> foo%bar
+ * foo\,bar -> foo,bar
+ * foo\ bar -> foo bar
+ * Don't unescape \, * and others that are also special in a
+ * regexp.
+ * An escaped { must be unescaped since we use magic not
+ * verymagic. Use "\\\{n,m\}"" to get "\{n,m}".
+ */
+ if (*++p == '?'
+#ifdef BACKSLASH_IN_FILENAME
+ && no_bslash
+#endif
+ )
+ reg_pat[i++] = '?';
+ else
+ if (*p == ',' || *p == '%' || *p == '#'
+ || vim_isspace(*p) || *p == '{' || *p == '}')
+ reg_pat[i++] = *p;
+ else if (*p == '\\' && p[1] == '\\' && p[2] == '{')
+ {
+ reg_pat[i++] = '\\';
+ reg_pat[i++] = '{';
+ p += 2;
+ }
+ else
+ {
+ if (allow_dirs != NULL && vim_ispathsep(*p)
+#ifdef BACKSLASH_IN_FILENAME
+ && (!no_bslash || *p != '\\')
+#endif
+ )
+ *allow_dirs = TRUE;
+ reg_pat[i++] = '\\';
+ reg_pat[i++] = *p;
+ }
+ break;
+#ifdef BACKSLASH_IN_FILENAME
+ case '/':
+ reg_pat[i++] = '[';
+ reg_pat[i++] = '\\';
+ reg_pat[i++] = '/';
+ reg_pat[i++] = ']';
+ if (allow_dirs != NULL)
+ *allow_dirs = TRUE;
+ break;
+#endif
+ case '{':
+ reg_pat[i++] = '\\';
+ reg_pat[i++] = '(';
+ nested++;
+ break;
+ case '}':
+ reg_pat[i++] = '\\';
+ reg_pat[i++] = ')';
+ --nested;
+ break;
+ case ',':
+ if (nested)
+ {
+ reg_pat[i++] = '\\';
+ reg_pat[i++] = '|';
+ }
+ else
+ reg_pat[i++] = ',';
+ break;
+ default:
+ if (enc_dbcs != 0 && (*mb_ptr2len)(p) > 1)
+ reg_pat[i++] = *p++;
+ else if (allow_dirs != NULL && vim_ispathsep(*p))
+ *allow_dirs = TRUE;
+ reg_pat[i++] = *p;
+ break;
+ }
+ }
+ if (add_dollar)
+ reg_pat[i++] = '$';
+ reg_pat[i] = NUL;
+ if (nested != 0)
+ {
+ if (nested < 0)
+ emsg(_("E219: Missing {."));
+ else
+ emsg(_("E220: Missing }."));
+ VIM_CLEAR(reg_pat);
+ }
+ return reg_pat;
+}
+
+#if defined(EINTR) || defined(PROTO)
+/*
+ * Version of read() that retries when interrupted by EINTR (possibly
+ * by a SIGWINCH).
+ */
+ long
+read_eintr(int fd, void *buf, size_t bufsize)
+{
+ long ret;
+
+ for (;;)
+ {
+ ret = vim_read(fd, buf, bufsize);
+ if (ret >= 0 || errno != EINTR)
+ break;
+ }
+ return ret;
+}
+
+/*
+ * Version of write() that retries when interrupted by EINTR (possibly
+ * by a SIGWINCH).
+ */
+ long
+write_eintr(int fd, void *buf, size_t bufsize)
+{
+ long ret = 0;
+ long wlen;
+
+ /* Repeat the write() so long it didn't fail, other than being interrupted
+ * by a signal. */
+ while (ret < (long)bufsize)
+ {
+ wlen = vim_write(fd, (char *)buf + ret, bufsize - ret);
+ if (wlen < 0)
+ {
+ if (errno != EINTR)
+ break;
+ }
+ else
+ ret += wlen;
+ }
+ return ret;
+}
+#endif
diff --git a/src/fold.c b/src/fold.c
new file mode 100644
index 0000000..7446f7c
--- /dev/null
+++ b/src/fold.c
@@ -0,0 +1,3608 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ * vim600:fdm=marker fdl=1 fdc=3:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * fold.c: code for folding
+ */
+
+#include "vim.h"
+
+#if defined(FEAT_FOLDING) || defined(PROTO)
+
+/* local declarations. {{{1 */
+/* typedef fold_T {{{2 */
+/*
+ * The toplevel folds for each window are stored in the w_folds growarray.
+ * Each toplevel fold can contain an array of second level folds in the
+ * fd_nested growarray.
+ * The info stored in both growarrays is the same: An array of fold_T.
+ */
+typedef struct
+{
+ linenr_T fd_top; /* first line of fold; for nested fold
+ * relative to parent */
+ linenr_T fd_len; /* number of lines in the fold */
+ garray_T fd_nested; /* array of nested folds */
+ char fd_flags; /* see below */
+ char fd_small; /* TRUE, FALSE or MAYBE: fold smaller than
+ 'foldminlines'; MAYBE applies to nested
+ folds too */
+} fold_T;
+
+#define FD_OPEN 0 /* fold is open (nested ones can be closed) */
+#define FD_CLOSED 1 /* fold is closed */
+#define FD_LEVEL 2 /* depends on 'foldlevel' (nested folds too) */
+
+#define MAX_LEVEL 20 /* maximum fold depth */
+
+/* static functions {{{2 */
+static void newFoldLevelWin(win_T *wp);
+static int checkCloseRec(garray_T *gap, linenr_T lnum, int level);
+static int foldFind(garray_T *gap, linenr_T lnum, fold_T **fpp);
+static int foldLevelWin(win_T *wp, linenr_T lnum);
+static void checkupdate(win_T *wp);
+static void setFoldRepeat(linenr_T lnum, long count, int do_open);
+static linenr_T setManualFold(linenr_T lnum, int opening, int recurse, int *donep);
+static linenr_T setManualFoldWin(win_T *wp, linenr_T lnum, int opening, int recurse, int *donep);
+static void foldOpenNested(fold_T *fpr);
+static void deleteFoldEntry(garray_T *gap, int idx, int recursive);
+static void foldMarkAdjustRecurse(garray_T *gap, linenr_T line1, linenr_T line2, long amount, long amount_after);
+static int getDeepestNestingRecurse(garray_T *gap);
+static int check_closed(win_T *win, fold_T *fp, int *use_levelp, int level, int *maybe_smallp, linenr_T lnum_off);
+static void checkSmall(win_T *wp, fold_T *fp, linenr_T lnum_off);
+static void setSmallMaybe(garray_T *gap);
+static void foldCreateMarkers(linenr_T start, linenr_T end);
+static void foldAddMarker(linenr_T lnum, char_u *marker, int markerlen);
+static void deleteFoldMarkers(fold_T *fp, int recursive, linenr_T lnum_off);
+static void foldDelMarker(linenr_T lnum, char_u *marker, int markerlen);
+static void foldUpdateIEMS(win_T *wp, linenr_T top, linenr_T bot);
+static void parseMarker(win_T *wp);
+
+static char *e_nofold = N_("E490: No fold found");
+
+/*
+ * While updating the folds lines between invalid_top and invalid_bot have an
+ * undefined fold level. Only used for the window currently being updated.
+ */
+static linenr_T invalid_top = (linenr_T)0;
+static linenr_T invalid_bot = (linenr_T)0;
+
+/*
+ * When using 'foldexpr' we sometimes get the level of the next line, which
+ * calls foldlevel() to get the level of the current line, which hasn't been
+ * stored yet. To get around this chicken-egg problem the level of the
+ * previous line is stored here when available. prev_lnum is zero when the
+ * level is not available.
+ */
+static linenr_T prev_lnum = 0;
+static int prev_lnum_lvl = -1;
+
+/* Flags used for "done" argument of setManualFold. */
+#define DONE_NOTHING 0
+#define DONE_ACTION 1 /* did close or open a fold */
+#define DONE_FOLD 2 /* did find a fold */
+
+static int foldstartmarkerlen;
+static char_u *foldendmarker;
+static int foldendmarkerlen;
+
+/* Exported folding functions. {{{1 */
+/* copyFoldingState() {{{2 */
+
+/*
+ * Copy that folding state from window "wp_from" to window "wp_to".
+ */
+ void
+copyFoldingState(win_T *wp_from, win_T *wp_to)
+{
+ wp_to->w_fold_manual = wp_from->w_fold_manual;
+ wp_to->w_foldinvalid = wp_from->w_foldinvalid;
+ cloneFoldGrowArray(&wp_from->w_folds, &wp_to->w_folds);
+}
+
+/* hasAnyFolding() {{{2 */
+/*
+ * Return TRUE if there may be folded lines in the current window.
+ */
+ int
+hasAnyFolding(win_T *win)
+{
+ /* very simple now, but can become more complex later */
+ return (win->w_p_fen
+ && (!foldmethodIsManual(win) || win->w_folds.ga_len > 0));
+}
+
+/* hasFolding() {{{2 */
+/*
+ * Return TRUE if line "lnum" in the current window is part of a closed
+ * fold.
+ * When returning TRUE, *firstp and *lastp are set to the first and last
+ * lnum of the sequence of folded lines (skipped when NULL).
+ */
+ int
+hasFolding(linenr_T lnum, linenr_T *firstp, linenr_T *lastp)
+{
+ return hasFoldingWin(curwin, lnum, firstp, lastp, TRUE, NULL);
+}
+
+/* hasFoldingWin() {{{2 */
+ int
+hasFoldingWin(
+ win_T *win,
+ linenr_T lnum,
+ linenr_T *firstp,
+ linenr_T *lastp,
+ int cache, /* when TRUE: use cached values of window */
+ foldinfo_T *infop) /* where to store fold info */
+{
+ int had_folded = FALSE;
+ linenr_T first = 0;
+ linenr_T last = 0;
+ linenr_T lnum_rel = lnum;
+ int x;
+ fold_T *fp;
+ int level = 0;
+ int use_level = FALSE;
+ int maybe_small = FALSE;
+ garray_T *gap;
+ int low_level = 0;
+
+ checkupdate(win);
+
+ /*
+ * Return quickly when there is no folding at all in this window.
+ */
+ if (!hasAnyFolding(win))
+ {
+ if (infop != NULL)
+ infop->fi_level = 0;
+ return FALSE;
+ }
+
+ if (cache)
+ {
+ /*
+ * First look in cached info for displayed lines. This is probably
+ * the fastest, but it can only be used if the entry is still valid.
+ */
+ x = find_wl_entry(win, lnum);
+ if (x >= 0)
+ {
+ first = win->w_lines[x].wl_lnum;
+ last = win->w_lines[x].wl_lastlnum;
+ had_folded = win->w_lines[x].wl_folded;
+ }
+ }
+
+ if (first == 0)
+ {
+ /*
+ * Recursively search for a fold that contains "lnum".
+ */
+ gap = &win->w_folds;
+ for (;;)
+ {
+ if (!foldFind(gap, lnum_rel, &fp))
+ break;
+
+ /* Remember lowest level of fold that starts in "lnum". */
+ if (lnum_rel == fp->fd_top && low_level == 0)
+ low_level = level + 1;
+
+ first += fp->fd_top;
+ last += fp->fd_top;
+
+ /* is this fold closed? */
+ had_folded = check_closed(win, fp, &use_level, level,
+ &maybe_small, lnum - lnum_rel);
+ if (had_folded)
+ {
+ /* Fold closed: Set last and quit loop. */
+ last += fp->fd_len - 1;
+ break;
+ }
+
+ /* Fold found, but it's open: Check nested folds. Line number is
+ * relative to containing fold. */
+ gap = &fp->fd_nested;
+ lnum_rel -= fp->fd_top;
+ ++level;
+ }
+ }
+
+ if (!had_folded)
+ {
+ if (infop != NULL)
+ {
+ infop->fi_level = level;
+ infop->fi_lnum = lnum - lnum_rel;
+ infop->fi_low_level = low_level == 0 ? level : low_level;
+ }
+ return FALSE;
+ }
+
+ if (last > win->w_buffer->b_ml.ml_line_count)
+ last = win->w_buffer->b_ml.ml_line_count;
+ if (lastp != NULL)
+ *lastp = last;
+ if (firstp != NULL)
+ *firstp = first;
+ if (infop != NULL)
+ {
+ infop->fi_level = level + 1;
+ infop->fi_lnum = first;
+ infop->fi_low_level = low_level == 0 ? level + 1 : low_level;
+ }
+ return TRUE;
+}
+
+/* foldLevel() {{{2 */
+/*
+ * Return fold level at line number "lnum" in the current window.
+ */
+ int
+foldLevel(linenr_T lnum)
+{
+ /* While updating the folds lines between invalid_top and invalid_bot have
+ * an undefined fold level. Otherwise update the folds first. */
+ if (invalid_top == (linenr_T)0)
+ checkupdate(curwin);
+ else if (lnum == prev_lnum && prev_lnum_lvl >= 0)
+ return prev_lnum_lvl;
+ else if (lnum >= invalid_top && lnum <= invalid_bot)
+ return -1;
+
+ /* Return quickly when there is no folding at all in this window. */
+ if (!hasAnyFolding(curwin))
+ return 0;
+
+ return foldLevelWin(curwin, lnum);
+}
+
+/* lineFolded() {{{2 */
+/*
+ * Low level function to check if a line is folded. Doesn't use any caching.
+ * Return TRUE if line is folded.
+ * Return FALSE if line is not folded.
+ * Return MAYBE if the line is folded when next to a folded line.
+ */
+ int
+lineFolded(win_T *win, linenr_T lnum)
+{
+ return foldedCount(win, lnum, NULL) != 0;
+}
+
+/* foldedCount() {{{2 */
+/*
+ * Count the number of lines that are folded at line number "lnum".
+ * Normally "lnum" is the first line of a possible fold, and the returned
+ * number is the number of lines in the fold.
+ * Doesn't use caching from the displayed window.
+ * Returns number of folded lines from "lnum", or 0 if line is not folded.
+ * When "infop" is not NULL, fills *infop with the fold level info.
+ */
+ long
+foldedCount(win_T *win, linenr_T lnum, foldinfo_T *infop)
+{
+ linenr_T last;
+
+ if (hasFoldingWin(win, lnum, NULL, &last, FALSE, infop))
+ return (long)(last - lnum + 1);
+ return 0;
+}
+
+/* foldmethodIsManual() {{{2 */
+/*
+ * Return TRUE if 'foldmethod' is "manual"
+ */
+ int
+foldmethodIsManual(win_T *wp)
+{
+ return (wp->w_p_fdm[3] == 'u');
+}
+
+/* foldmethodIsIndent() {{{2 */
+/*
+ * Return TRUE if 'foldmethod' is "indent"
+ */
+ int
+foldmethodIsIndent(win_T *wp)
+{
+ return (wp->w_p_fdm[0] == 'i');
+}
+
+/* foldmethodIsExpr() {{{2 */
+/*
+ * Return TRUE if 'foldmethod' is "expr"
+ */
+ int
+foldmethodIsExpr(win_T *wp)
+{
+ return (wp->w_p_fdm[1] == 'x');
+}
+
+/* foldmethodIsMarker() {{{2 */
+/*
+ * Return TRUE if 'foldmethod' is "marker"
+ */
+ int
+foldmethodIsMarker(win_T *wp)
+{
+ return (wp->w_p_fdm[2] == 'r');
+}
+
+/* foldmethodIsSyntax() {{{2 */
+/*
+ * Return TRUE if 'foldmethod' is "syntax"
+ */
+ int
+foldmethodIsSyntax(win_T *wp)
+{
+ return (wp->w_p_fdm[0] == 's');
+}
+
+/* foldmethodIsDiff() {{{2 */
+/*
+ * Return TRUE if 'foldmethod' is "diff"
+ */
+ int
+foldmethodIsDiff(win_T *wp)
+{
+ return (wp->w_p_fdm[0] == 'd');
+}
+
+/* closeFold() {{{2 */
+/*
+ * Close fold for current window at line "lnum".
+ * Repeat "count" times.
+ */
+ void
+closeFold(linenr_T lnum, long count)
+{
+ setFoldRepeat(lnum, count, FALSE);
+}
+
+/* closeFoldRecurse() {{{2 */
+/*
+ * Close fold for current window at line "lnum" recursively.
+ */
+ void
+closeFoldRecurse(linenr_T lnum)
+{
+ (void)setManualFold(lnum, FALSE, TRUE, NULL);
+}
+
+/* opFoldRange() {{{2 */
+/*
+ * Open or Close folds for current window in lines "first" to "last".
+ * Used for "zo", "zO", "zc" and "zC" in Visual mode.
+ */
+ void
+opFoldRange(
+ linenr_T first,
+ linenr_T last,
+ int opening, /* TRUE to open, FALSE to close */
+ int recurse, /* TRUE to do it recursively */
+ int had_visual) /* TRUE when Visual selection used */
+{
+ int done = DONE_NOTHING; /* avoid error messages */
+ linenr_T lnum;
+ linenr_T lnum_next;
+
+ for (lnum = first; lnum <= last; lnum = lnum_next + 1)
+ {
+ lnum_next = lnum;
+ /* Opening one level only: next fold to open is after the one going to
+ * be opened. */
+ if (opening && !recurse)
+ (void)hasFolding(lnum, NULL, &lnum_next);
+ (void)setManualFold(lnum, opening, recurse, &done);
+ /* Closing one level only: next line to close a fold is after just
+ * closed fold. */
+ if (!opening && !recurse)
+ (void)hasFolding(lnum, NULL, &lnum_next);
+ }
+ if (done == DONE_NOTHING)
+ emsg(_(e_nofold));
+ /* Force a redraw to remove the Visual highlighting. */
+ if (had_visual)
+ redraw_curbuf_later(INVERTED);
+}
+
+/* openFold() {{{2 */
+/*
+ * Open fold for current window at line "lnum".
+ * Repeat "count" times.
+ */
+ void
+openFold(linenr_T lnum, long count)
+{
+ setFoldRepeat(lnum, count, TRUE);
+}
+
+/* openFoldRecurse() {{{2 */
+/*
+ * Open fold for current window at line "lnum" recursively.
+ */
+ void
+openFoldRecurse(linenr_T lnum)
+{
+ (void)setManualFold(lnum, TRUE, TRUE, NULL);
+}
+
+/* foldOpenCursor() {{{2 */
+/*
+ * Open folds until the cursor line is not in a closed fold.
+ */
+ void
+foldOpenCursor(void)
+{
+ int done;
+
+ checkupdate(curwin);
+ if (hasAnyFolding(curwin))
+ for (;;)
+ {
+ done = DONE_NOTHING;
+ (void)setManualFold(curwin->w_cursor.lnum, TRUE, FALSE, &done);
+ if (!(done & DONE_ACTION))
+ break;
+ }
+}
+
+/* newFoldLevel() {{{2 */
+/*
+ * Set new foldlevel for current window.
+ */
+ void
+newFoldLevel(void)
+{
+ newFoldLevelWin(curwin);
+
+#ifdef FEAT_DIFF
+ if (foldmethodIsDiff(curwin) && curwin->w_p_scb)
+ {
+ win_T *wp;
+
+ /*
+ * Set the same foldlevel in other windows in diff mode.
+ */
+ FOR_ALL_WINDOWS(wp)
+ {
+ if (wp != curwin && foldmethodIsDiff(wp) && wp->w_p_scb)
+ {
+ wp->w_p_fdl = curwin->w_p_fdl;
+ newFoldLevelWin(wp);
+ }
+ }
+ }
+#endif
+}
+
+ static void
+newFoldLevelWin(win_T *wp)
+{
+ fold_T *fp;
+ int i;
+
+ checkupdate(wp);
+ if (wp->w_fold_manual)
+ {
+ /* Set all flags for the first level of folds to FD_LEVEL. Following
+ * manual open/close will then change the flags to FD_OPEN or
+ * FD_CLOSED for those folds that don't use 'foldlevel'. */
+ fp = (fold_T *)wp->w_folds.ga_data;
+ for (i = 0; i < wp->w_folds.ga_len; ++i)
+ fp[i].fd_flags = FD_LEVEL;
+ wp->w_fold_manual = FALSE;
+ }
+ changed_window_setting_win(wp);
+}
+
+/* foldCheckClose() {{{2 */
+/*
+ * Apply 'foldlevel' to all folds that don't contain the cursor.
+ */
+ void
+foldCheckClose(void)
+{
+ if (*p_fcl != NUL) /* can only be "all" right now */
+ {
+ checkupdate(curwin);
+ if (checkCloseRec(&curwin->w_folds, curwin->w_cursor.lnum,
+ (int)curwin->w_p_fdl))
+ changed_window_setting();
+ }
+}
+
+/* checkCloseRec() {{{2 */
+ static int
+checkCloseRec(garray_T *gap, linenr_T lnum, int level)
+{
+ fold_T *fp;
+ int retval = FALSE;
+ int i;
+
+ fp = (fold_T *)gap->ga_data;
+ for (i = 0; i < gap->ga_len; ++i)
+ {
+ /* Only manually opened folds may need to be closed. */
+ if (fp[i].fd_flags == FD_OPEN)
+ {
+ if (level <= 0 && (lnum < fp[i].fd_top
+ || lnum >= fp[i].fd_top + fp[i].fd_len))
+ {
+ fp[i].fd_flags = FD_LEVEL;
+ retval = TRUE;
+ }
+ else
+ retval |= checkCloseRec(&fp[i].fd_nested, lnum - fp[i].fd_top,
+ level - 1);
+ }
+ }
+ return retval;
+}
+
+/* foldCreateAllowed() {{{2 */
+/*
+ * Return TRUE if it's allowed to manually create or delete a fold.
+ * Give an error message and return FALSE if not.
+ */
+ int
+foldManualAllowed(int create)
+{
+ if (foldmethodIsManual(curwin) || foldmethodIsMarker(curwin))
+ return TRUE;
+ if (create)
+ emsg(_("E350: Cannot create fold with current 'foldmethod'"));
+ else
+ emsg(_("E351: Cannot delete fold with current 'foldmethod'"));
+ return FALSE;
+}
+
+/* foldCreate() {{{2 */
+/*
+ * Create a fold from line "start" to line "end" (inclusive) in the current
+ * window.
+ */
+ void
+foldCreate(linenr_T start, linenr_T end)
+{
+ fold_T *fp;
+ garray_T *gap;
+ garray_T fold_ga;
+ int i, j;
+ int cont;
+ int use_level = FALSE;
+ int closed = FALSE;
+ int level = 0;
+ linenr_T start_rel = start;
+ linenr_T end_rel = end;
+
+ if (start > end)
+ {
+ /* reverse the range */
+ end = start_rel;
+ start = end_rel;
+ start_rel = start;
+ end_rel = end;
+ }
+
+ /* When 'foldmethod' is "marker" add markers, which creates the folds. */
+ if (foldmethodIsMarker(curwin))
+ {
+ foldCreateMarkers(start, end);
+ return;
+ }
+
+ checkupdate(curwin);
+
+ /* Find the place to insert the new fold. */
+ gap = &curwin->w_folds;
+ for (;;)
+ {
+ if (!foldFind(gap, start_rel, &fp))
+ break;
+ if (fp->fd_top + fp->fd_len > end_rel)
+ {
+ /* New fold is completely inside this fold: Go one level deeper. */
+ gap = &fp->fd_nested;
+ start_rel -= fp->fd_top;
+ end_rel -= fp->fd_top;
+ if (use_level || fp->fd_flags == FD_LEVEL)
+ {
+ use_level = TRUE;
+ if (level >= curwin->w_p_fdl)
+ closed = TRUE;
+ }
+ else if (fp->fd_flags == FD_CLOSED)
+ closed = TRUE;
+ ++level;
+ }
+ else
+ {
+ /* This fold and new fold overlap: Insert here and move some folds
+ * inside the new fold. */
+ break;
+ }
+ }
+
+ i = (int)(fp - (fold_T *)gap->ga_data);
+ if (ga_grow(gap, 1) == OK)
+ {
+ fp = (fold_T *)gap->ga_data + i;
+ ga_init2(&fold_ga, (int)sizeof(fold_T), 10);
+
+ /* Count number of folds that will be contained in the new fold. */
+ for (cont = 0; i + cont < gap->ga_len; ++cont)
+ if (fp[cont].fd_top > end_rel)
+ break;
+ if (cont > 0 && ga_grow(&fold_ga, cont) == OK)
+ {
+ /* If the first fold starts before the new fold, let the new fold
+ * start there. Otherwise the existing fold would change. */
+ if (start_rel > fp->fd_top)
+ start_rel = fp->fd_top;
+
+ /* When last contained fold isn't completely contained, adjust end
+ * of new fold. */
+ if (end_rel < fp[cont - 1].fd_top + fp[cont - 1].fd_len - 1)
+ end_rel = fp[cont - 1].fd_top + fp[cont - 1].fd_len - 1;
+ /* Move contained folds to inside new fold. */
+ mch_memmove(fold_ga.ga_data, fp, sizeof(fold_T) * cont);
+ fold_ga.ga_len += cont;
+ i += cont;
+
+ /* Adjust line numbers in contained folds to be relative to the
+ * new fold. */
+ for (j = 0; j < cont; ++j)
+ ((fold_T *)fold_ga.ga_data)[j].fd_top -= start_rel;
+ }
+ /* Move remaining entries to after the new fold. */
+ if (i < gap->ga_len)
+ mch_memmove(fp + 1, (fold_T *)gap->ga_data + i,
+ sizeof(fold_T) * (gap->ga_len - i));
+ gap->ga_len = gap->ga_len + 1 - cont;
+
+ /* insert new fold */
+ fp->fd_nested = fold_ga;
+ fp->fd_top = start_rel;
+ fp->fd_len = end_rel - start_rel + 1;
+
+ /* We want the new fold to be closed. If it would remain open because
+ * of using 'foldlevel', need to adjust fd_flags of containing folds.
+ */
+ if (use_level && !closed && level < curwin->w_p_fdl)
+ closeFold(start, 1L);
+ if (!use_level)
+ curwin->w_fold_manual = TRUE;
+ fp->fd_flags = FD_CLOSED;
+ fp->fd_small = MAYBE;
+
+ /* redraw */
+ changed_window_setting();
+ }
+}
+
+/* deleteFold() {{{2 */
+/*
+ * Delete a fold at line "start" in the current window.
+ * When "end" is not 0, delete all folds from "start" to "end".
+ * When "recursive" is TRUE delete recursively.
+ */
+ void
+deleteFold(
+ linenr_T start,
+ linenr_T end,
+ int recursive,
+ int had_visual) /* TRUE when Visual selection used */
+{
+ garray_T *gap;
+ fold_T *fp;
+ garray_T *found_ga;
+ fold_T *found_fp = NULL;
+ linenr_T found_off = 0;
+ int use_level;
+ int maybe_small = FALSE;
+ int level = 0;
+ linenr_T lnum = start;
+ linenr_T lnum_off;
+ int did_one = FALSE;
+ linenr_T first_lnum = MAXLNUM;
+ linenr_T last_lnum = 0;
+
+ checkupdate(curwin);
+
+ while (lnum <= end)
+ {
+ /* Find the deepest fold for "start". */
+ gap = &curwin->w_folds;
+ found_ga = NULL;
+ lnum_off = 0;
+ use_level = FALSE;
+ for (;;)
+ {
+ if (!foldFind(gap, lnum - lnum_off, &fp))
+ break;
+ /* lnum is inside this fold, remember info */
+ found_ga = gap;
+ found_fp = fp;
+ found_off = lnum_off;
+
+ /* if "lnum" is folded, don't check nesting */
+ if (check_closed(curwin, fp, &use_level, level,
+ &maybe_small, lnum_off))
+ break;
+
+ /* check nested folds */
+ gap = &fp->fd_nested;
+ lnum_off += fp->fd_top;
+ ++level;
+ }
+ if (found_ga == NULL)
+ {
+ ++lnum;
+ }
+ else
+ {
+ lnum = found_fp->fd_top + found_fp->fd_len + found_off;
+
+ if (foldmethodIsManual(curwin))
+ deleteFoldEntry(found_ga,
+ (int)(found_fp - (fold_T *)found_ga->ga_data), recursive);
+ else
+ {
+ if (first_lnum > found_fp->fd_top + found_off)
+ first_lnum = found_fp->fd_top + found_off;
+ if (last_lnum < lnum)
+ last_lnum = lnum;
+ if (!did_one)
+ parseMarker(curwin);
+ deleteFoldMarkers(found_fp, recursive, found_off);
+ }
+ did_one = TRUE;
+
+ /* redraw window */
+ changed_window_setting();
+ }
+ }
+ if (!did_one)
+ {
+ emsg(_(e_nofold));
+ /* Force a redraw to remove the Visual highlighting. */
+ if (had_visual)
+ redraw_curbuf_later(INVERTED);
+ }
+ else
+ /* Deleting markers may make cursor column invalid. */
+ check_cursor_col();
+
+ if (last_lnum > 0)
+ changed_lines(first_lnum, (colnr_T)0, last_lnum, 0L);
+}
+
+/* clearFolding() {{{2 */
+/*
+ * Remove all folding for window "win".
+ */
+ void
+clearFolding(win_T *win)
+{
+ deleteFoldRecurse(&win->w_folds);
+ win->w_foldinvalid = FALSE;
+}
+
+/* foldUpdate() {{{2 */
+/*
+ * Update folds for changes in the buffer of a window.
+ * Note that inserted/deleted lines must have already been taken care of by
+ * calling foldMarkAdjust().
+ * The changes in lines from top to bot (inclusive).
+ */
+ void
+foldUpdate(win_T *wp, linenr_T top, linenr_T bot)
+{
+ fold_T *fp;
+
+ if (disable_fold_update > 0)
+ return;
+
+ /* Mark all folds from top to bot as maybe-small. */
+ (void)foldFind(&wp->w_folds, top, &fp);
+ while (fp < (fold_T *)wp->w_folds.ga_data + wp->w_folds.ga_len
+ && fp->fd_top < bot)
+ {
+ fp->fd_small = MAYBE;
+ ++fp;
+ }
+
+ if (foldmethodIsIndent(wp)
+ || foldmethodIsExpr(wp)
+ || foldmethodIsMarker(wp)
+#ifdef FEAT_DIFF
+ || foldmethodIsDiff(wp)
+#endif
+ || foldmethodIsSyntax(wp))
+ {
+ int save_got_int = got_int;
+
+ /* reset got_int here, otherwise it won't work */
+ got_int = FALSE;
+ foldUpdateIEMS(wp, top, bot);
+ got_int |= save_got_int;
+ }
+}
+
+/* foldUpdateAll() {{{2 */
+/*
+ * Update all lines in a window for folding.
+ * Used when a fold setting changes or after reloading the buffer.
+ * The actual updating is postponed until fold info is used, to avoid doing
+ * every time a setting is changed or a syntax item is added.
+ */
+ void
+foldUpdateAll(win_T *win)
+{
+ win->w_foldinvalid = TRUE;
+ redraw_win_later(win, NOT_VALID);
+}
+
+/* foldMoveTo() {{{2 */
+/*
+ * If "updown" is FALSE: Move to the start or end of the fold.
+ * If "updown" is TRUE: move to fold at the same level.
+ * If not moved return FAIL.
+ */
+ int
+foldMoveTo(
+ int updown,
+ int dir, /* FORWARD or BACKWARD */
+ long count)
+{
+ long n;
+ int retval = FAIL;
+ linenr_T lnum_off;
+ linenr_T lnum_found;
+ linenr_T lnum;
+ int use_level;
+ int maybe_small;
+ garray_T *gap;
+ fold_T *fp;
+ int level;
+ int last;
+
+ checkupdate(curwin);
+
+ /* Repeat "count" times. */
+ for (n = 0; n < count; ++n)
+ {
+ /* Find nested folds. Stop when a fold is closed. The deepest fold
+ * that moves the cursor is used. */
+ lnum_off = 0;
+ gap = &curwin->w_folds;
+ use_level = FALSE;
+ maybe_small = FALSE;
+ lnum_found = curwin->w_cursor.lnum;
+ level = 0;
+ last = FALSE;
+ for (;;)
+ {
+ if (!foldFind(gap, curwin->w_cursor.lnum - lnum_off, &fp))
+ {
+ if (!updown)
+ break;
+
+ /* When moving up, consider a fold above the cursor; when
+ * moving down consider a fold below the cursor. */
+ if (dir == FORWARD)
+ {
+ if (fp - (fold_T *)gap->ga_data >= gap->ga_len)
+ break;
+ --fp;
+ }
+ else
+ {
+ if (fp == (fold_T *)gap->ga_data)
+ break;
+ }
+ /* don't look for contained folds, they will always move
+ * the cursor too far. */
+ last = TRUE;
+ }
+
+ if (!last)
+ {
+ /* Check if this fold is closed. */
+ if (check_closed(curwin, fp, &use_level, level,
+ &maybe_small, lnum_off))
+ last = TRUE;
+
+ /* "[z" and "]z" stop at closed fold */
+ if (last && !updown)
+ break;
+ }
+
+ if (updown)
+ {
+ if (dir == FORWARD)
+ {
+ /* to start of next fold if there is one */
+ if (fp + 1 - (fold_T *)gap->ga_data < gap->ga_len)
+ {
+ lnum = fp[1].fd_top + lnum_off;
+ if (lnum > curwin->w_cursor.lnum)
+ lnum_found = lnum;
+ }
+ }
+ else
+ {
+ /* to end of previous fold if there is one */
+ if (fp > (fold_T *)gap->ga_data)
+ {
+ lnum = fp[-1].fd_top + lnum_off + fp[-1].fd_len - 1;
+ if (lnum < curwin->w_cursor.lnum)
+ lnum_found = lnum;
+ }
+ }
+ }
+ else
+ {
+ /* Open fold found, set cursor to its start/end and then check
+ * nested folds. */
+ if (dir == FORWARD)
+ {
+ lnum = fp->fd_top + lnum_off + fp->fd_len - 1;
+ if (lnum > curwin->w_cursor.lnum)
+ lnum_found = lnum;
+ }
+ else
+ {
+ lnum = fp->fd_top + lnum_off;
+ if (lnum < curwin->w_cursor.lnum)
+ lnum_found = lnum;
+ }
+ }
+
+ if (last)
+ break;
+
+ /* Check nested folds (if any). */
+ gap = &fp->fd_nested;
+ lnum_off += fp->fd_top;
+ ++level;
+ }
+ if (lnum_found != curwin->w_cursor.lnum)
+ {
+ if (retval == FAIL)
+ setpcmark();
+ curwin->w_cursor.lnum = lnum_found;
+ curwin->w_cursor.col = 0;
+ retval = OK;
+ }
+ else
+ break;
+ }
+
+ return retval;
+}
+
+/* foldInitWin() {{{2 */
+/*
+ * Init the fold info in a new window.
+ */
+ void
+foldInitWin(win_T *new_win)
+{
+ ga_init2(&new_win->w_folds, (int)sizeof(fold_T), 10);
+}
+
+/* find_wl_entry() {{{2 */
+/*
+ * Find an entry in the win->w_lines[] array for buffer line "lnum".
+ * Only valid entries are considered (for entries where wl_valid is FALSE the
+ * line number can be wrong).
+ * Returns index of entry or -1 if not found.
+ */
+ int
+find_wl_entry(win_T *win, linenr_T lnum)
+{
+ int i;
+
+ for (i = 0; i < win->w_lines_valid; ++i)
+ if (win->w_lines[i].wl_valid)
+ {
+ if (lnum < win->w_lines[i].wl_lnum)
+ return -1;
+ if (lnum <= win->w_lines[i].wl_lastlnum)
+ return i;
+ }
+ return -1;
+}
+
+/* foldAdjustVisual() {{{2 */
+/*
+ * Adjust the Visual area to include any fold at the start or end completely.
+ */
+ void
+foldAdjustVisual(void)
+{
+ pos_T *start, *end;
+ char_u *ptr;
+
+ if (!VIsual_active || !hasAnyFolding(curwin))
+ return;
+
+ if (LTOREQ_POS(VIsual, curwin->w_cursor))
+ {
+ start = &VIsual;
+ end = &curwin->w_cursor;
+ }
+ else
+ {
+ start = &curwin->w_cursor;
+ end = &VIsual;
+ }
+ if (hasFolding(start->lnum, &start->lnum, NULL))
+ start->col = 0;
+ if (hasFolding(end->lnum, NULL, &end->lnum))
+ {
+ ptr = ml_get(end->lnum);
+ end->col = (colnr_T)STRLEN(ptr);
+ if (end->col > 0 && *p_sel == 'o')
+ --end->col;
+ /* prevent cursor from moving on the trail byte */
+ if (has_mbyte)
+ mb_adjust_cursor();
+ }
+}
+
+/* cursor_foldstart() {{{2 */
+/*
+ * Move the cursor to the first line of a closed fold.
+ */
+ void
+foldAdjustCursor(void)
+{
+ (void)hasFolding(curwin->w_cursor.lnum, &curwin->w_cursor.lnum, NULL);
+}
+
+/* Internal functions for "fold_T" {{{1 */
+/* cloneFoldGrowArray() {{{2 */
+/*
+ * Will "clone" (i.e deep copy) a garray_T of folds.
+ *
+ * Return FAIL if the operation cannot be completed, otherwise OK.
+ */
+ void
+cloneFoldGrowArray(garray_T *from, garray_T *to)
+{
+ int i;
+ fold_T *from_p;
+ fold_T *to_p;
+
+ ga_init2(to, from->ga_itemsize, from->ga_growsize);
+ if (from->ga_len == 0 || ga_grow(to, from->ga_len) == FAIL)
+ return;
+
+ from_p = (fold_T *)from->ga_data;
+ to_p = (fold_T *)to->ga_data;
+
+ for (i = 0; i < from->ga_len; i++)
+ {
+ to_p->fd_top = from_p->fd_top;
+ to_p->fd_len = from_p->fd_len;
+ to_p->fd_flags = from_p->fd_flags;
+ to_p->fd_small = from_p->fd_small;
+ cloneFoldGrowArray(&from_p->fd_nested, &to_p->fd_nested);
+ ++to->ga_len;
+ ++from_p;
+ ++to_p;
+ }
+}
+
+/* foldFind() {{{2 */
+/*
+ * Search for line "lnum" in folds of growarray "gap".
+ * Set *fpp to the fold struct for the fold that contains "lnum" or
+ * the first fold below it (careful: it can be beyond the end of the array!).
+ * Returns FALSE when there is no fold that contains "lnum".
+ */
+ static int
+foldFind(garray_T *gap, linenr_T lnum, fold_T **fpp)
+{
+ linenr_T low, high;
+ fold_T *fp;
+ int i;
+
+ /*
+ * Perform a binary search.
+ * "low" is lowest index of possible match.
+ * "high" is highest index of possible match.
+ */
+ fp = (fold_T *)gap->ga_data;
+ low = 0;
+ high = gap->ga_len - 1;
+ while (low <= high)
+ {
+ i = (low + high) / 2;
+ if (fp[i].fd_top > lnum)
+ /* fold below lnum, adjust high */
+ high = i - 1;
+ else if (fp[i].fd_top + fp[i].fd_len <= lnum)
+ /* fold above lnum, adjust low */
+ low = i + 1;
+ else
+ {
+ /* lnum is inside this fold */
+ *fpp = fp + i;
+ return TRUE;
+ }
+ }
+ *fpp = fp + low;
+ return FALSE;
+}
+
+/* foldLevelWin() {{{2 */
+/*
+ * Return fold level at line number "lnum" in window "wp".
+ */
+ static int
+foldLevelWin(win_T *wp, linenr_T lnum)
+{
+ fold_T *fp;
+ linenr_T lnum_rel = lnum;
+ int level = 0;
+ garray_T *gap;
+
+ /* Recursively search for a fold that contains "lnum". */
+ gap = &wp->w_folds;
+ for (;;)
+ {
+ if (!foldFind(gap, lnum_rel, &fp))
+ break;
+ /* Check nested folds. Line number is relative to containing fold. */
+ gap = &fp->fd_nested;
+ lnum_rel -= fp->fd_top;
+ ++level;
+ }
+
+ return level;
+}
+
+/* checkupdate() {{{2 */
+/*
+ * Check if the folds in window "wp" are invalid and update them if needed.
+ */
+ static void
+checkupdate(win_T *wp)
+{
+ if (wp->w_foldinvalid)
+ {
+ foldUpdate(wp, (linenr_T)1, (linenr_T)MAXLNUM); /* will update all */
+ wp->w_foldinvalid = FALSE;
+ }
+}
+
+/* setFoldRepeat() {{{2 */
+/*
+ * Open or close fold for current window at line "lnum".
+ * Repeat "count" times.
+ */
+ static void
+setFoldRepeat(linenr_T lnum, long count, int do_open)
+{
+ int done;
+ long n;
+
+ for (n = 0; n < count; ++n)
+ {
+ done = DONE_NOTHING;
+ (void)setManualFold(lnum, do_open, FALSE, &done);
+ if (!(done & DONE_ACTION))
+ {
+ /* Only give an error message when no fold could be opened. */
+ if (n == 0 && !(done & DONE_FOLD))
+ emsg(_(e_nofold));
+ break;
+ }
+ }
+}
+
+/* setManualFold() {{{2 */
+/*
+ * Open or close the fold in the current window which contains "lnum".
+ * Also does this for other windows in diff mode when needed.
+ */
+ static linenr_T
+setManualFold(
+ linenr_T lnum,
+ int opening, /* TRUE when opening, FALSE when closing */
+ int recurse, /* TRUE when closing/opening recursive */
+ int *donep)
+{
+#ifdef FEAT_DIFF
+ if (foldmethodIsDiff(curwin) && curwin->w_p_scb)
+ {
+ win_T *wp;
+ linenr_T dlnum;
+
+ /*
+ * Do the same operation in other windows in diff mode. Calculate the
+ * line number from the diffs.
+ */
+ FOR_ALL_WINDOWS(wp)
+ {
+ if (wp != curwin && foldmethodIsDiff(wp) && wp->w_p_scb)
+ {
+ dlnum = diff_lnum_win(curwin->w_cursor.lnum, wp);
+ if (dlnum != 0)
+ (void)setManualFoldWin(wp, dlnum, opening, recurse, NULL);
+ }
+ }
+ }
+#endif
+
+ return setManualFoldWin(curwin, lnum, opening, recurse, donep);
+}
+
+/* setManualFoldWin() {{{2 */
+/*
+ * Open or close the fold in window "wp" which contains "lnum".
+ * "donep", when not NULL, points to flag that is set to DONE_FOLD when some
+ * fold was found and to DONE_ACTION when some fold was opened or closed.
+ * When "donep" is NULL give an error message when no fold was found for
+ * "lnum", but only if "wp" is "curwin".
+ * Return the line number of the next line that could be closed.
+ * It's only valid when "opening" is TRUE!
+ */
+ static linenr_T
+setManualFoldWin(
+ win_T *wp,
+ linenr_T lnum,
+ int opening, /* TRUE when opening, FALSE when closing */
+ int recurse, /* TRUE when closing/opening recursive */
+ int *donep)
+{
+ fold_T *fp;
+ fold_T *fp2;
+ fold_T *found = NULL;
+ int j;
+ int level = 0;
+ int use_level = FALSE;
+ int found_fold = FALSE;
+ garray_T *gap;
+ linenr_T next = MAXLNUM;
+ linenr_T off = 0;
+ int done = 0;
+
+ checkupdate(wp);
+
+ /*
+ * Find the fold, open or close it.
+ */
+ gap = &wp->w_folds;
+ for (;;)
+ {
+ if (!foldFind(gap, lnum, &fp))
+ {
+ /* If there is a following fold, continue there next time. */
+ if (fp < (fold_T *)gap->ga_data + gap->ga_len)
+ next = fp->fd_top + off;
+ break;
+ }
+
+ /* lnum is inside this fold */
+ found_fold = TRUE;
+
+ /* If there is a following fold, continue there next time. */
+ if (fp + 1 < (fold_T *)gap->ga_data + gap->ga_len)
+ next = fp[1].fd_top + off;
+
+ /* Change from level-dependent folding to manual. */
+ if (use_level || fp->fd_flags == FD_LEVEL)
+ {
+ use_level = TRUE;
+ if (level >= wp->w_p_fdl)
+ fp->fd_flags = FD_CLOSED;
+ else
+ fp->fd_flags = FD_OPEN;
+ fp2 = (fold_T *)fp->fd_nested.ga_data;
+ for (j = 0; j < fp->fd_nested.ga_len; ++j)
+ fp2[j].fd_flags = FD_LEVEL;
+ }
+
+ /* Simple case: Close recursively means closing the fold. */
+ if (!opening && recurse)
+ {
+ if (fp->fd_flags != FD_CLOSED)
+ {
+ done |= DONE_ACTION;
+ fp->fd_flags = FD_CLOSED;
+ }
+ }
+ else if (fp->fd_flags == FD_CLOSED)
+ {
+ /* When opening, open topmost closed fold. */
+ if (opening)
+ {
+ fp->fd_flags = FD_OPEN;
+ done |= DONE_ACTION;
+ if (recurse)
+ foldOpenNested(fp);
+ }
+ break;
+ }
+
+ /* fold is open, check nested folds */
+ found = fp;
+ gap = &fp->fd_nested;
+ lnum -= fp->fd_top;
+ off += fp->fd_top;
+ ++level;
+ }
+ if (found_fold)
+ {
+ /* When closing and not recurse, close deepest open fold. */
+ if (!opening && found != NULL)
+ {
+ found->fd_flags = FD_CLOSED;
+ done |= DONE_ACTION;
+ }
+ wp->w_fold_manual = TRUE;
+ if (done & DONE_ACTION)
+ changed_window_setting_win(wp);
+ done |= DONE_FOLD;
+ }
+ else if (donep == NULL && wp == curwin)
+ emsg(_(e_nofold));
+
+ if (donep != NULL)
+ *donep |= done;
+
+ return next;
+}
+
+/* foldOpenNested() {{{2 */
+/*
+ * Open all nested folds in fold "fpr" recursively.
+ */
+ static void
+foldOpenNested(fold_T *fpr)
+{
+ int i;
+ fold_T *fp;
+
+ fp = (fold_T *)fpr->fd_nested.ga_data;
+ for (i = 0; i < fpr->fd_nested.ga_len; ++i)
+ {
+ foldOpenNested(&fp[i]);
+ fp[i].fd_flags = FD_OPEN;
+ }
+}
+
+/* deleteFoldEntry() {{{2 */
+/*
+ * Delete fold "idx" from growarray "gap".
+ * When "recursive" is TRUE also delete all the folds contained in it.
+ * When "recursive" is FALSE contained folds are moved one level up.
+ */
+ static void
+deleteFoldEntry(garray_T *gap, int idx, int recursive)
+{
+ fold_T *fp;
+ int i;
+ long moved;
+ fold_T *nfp;
+
+ fp = (fold_T *)gap->ga_data + idx;
+ if (recursive || fp->fd_nested.ga_len == 0)
+ {
+ /* recursively delete the contained folds */
+ deleteFoldRecurse(&fp->fd_nested);
+ --gap->ga_len;
+ if (idx < gap->ga_len)
+ mch_memmove(fp, fp + 1, sizeof(fold_T) * (gap->ga_len - idx));
+ }
+ else
+ {
+ /* Move nested folds one level up, to overwrite the fold that is
+ * deleted. */
+ moved = fp->fd_nested.ga_len;
+ if (ga_grow(gap, (int)(moved - 1)) == OK)
+ {
+ /* Get "fp" again, the array may have been reallocated. */
+ fp = (fold_T *)gap->ga_data + idx;
+
+ /* adjust fd_top and fd_flags for the moved folds */
+ nfp = (fold_T *)fp->fd_nested.ga_data;
+ for (i = 0; i < moved; ++i)
+ {
+ nfp[i].fd_top += fp->fd_top;
+ if (fp->fd_flags == FD_LEVEL)
+ nfp[i].fd_flags = FD_LEVEL;
+ if (fp->fd_small == MAYBE)
+ nfp[i].fd_small = MAYBE;
+ }
+
+ /* move the existing folds down to make room */
+ if (idx + 1 < gap->ga_len)
+ mch_memmove(fp + moved, fp + 1,
+ sizeof(fold_T) * (gap->ga_len - (idx + 1)));
+ /* move the contained folds one level up */
+ mch_memmove(fp, nfp, (size_t)(sizeof(fold_T) * moved));
+ vim_free(nfp);
+ gap->ga_len += moved - 1;
+ }
+ }
+}
+
+/* deleteFoldRecurse() {{{2 */
+/*
+ * Delete nested folds in a fold.
+ */
+ void
+deleteFoldRecurse(garray_T *gap)
+{
+ int i;
+
+ for (i = 0; i < gap->ga_len; ++i)
+ deleteFoldRecurse(&(((fold_T *)(gap->ga_data))[i].fd_nested));
+ ga_clear(gap);
+}
+
+/* foldMarkAdjust() {{{2 */
+/*
+ * Update line numbers of folds for inserted/deleted lines.
+ */
+ void
+foldMarkAdjust(
+ win_T *wp,
+ linenr_T line1,
+ linenr_T line2,
+ long amount,
+ long amount_after)
+{
+ /* If deleting marks from line1 to line2, but not deleting all those
+ * lines, set line2 so that only deleted lines have their folds removed. */
+ if (amount == MAXLNUM && line2 >= line1 && line2 - line1 >= -amount_after)
+ line2 = line1 - amount_after - 1;
+ /* If appending a line in Insert mode, it should be included in the fold
+ * just above the line. */
+ if ((State & INSERT) && amount == (linenr_T)1 && line2 == MAXLNUM)
+ --line1;
+ foldMarkAdjustRecurse(&wp->w_folds, line1, line2, amount, amount_after);
+}
+
+/* foldMarkAdjustRecurse() {{{2 */
+ static void
+foldMarkAdjustRecurse(
+ garray_T *gap,
+ linenr_T line1,
+ linenr_T line2,
+ long amount,
+ long amount_after)
+{
+ fold_T *fp;
+ int i;
+ linenr_T last;
+ linenr_T top;
+
+ /* In Insert mode an inserted line at the top of a fold is considered part
+ * of the fold, otherwise it isn't. */
+ if ((State & INSERT) && amount == (linenr_T)1 && line2 == MAXLNUM)
+ top = line1 + 1;
+ else
+ top = line1;
+
+ /* Find the fold containing or just below "line1". */
+ (void)foldFind(gap, line1, &fp);
+
+ /*
+ * Adjust all folds below "line1" that are affected.
+ */
+ for (i = (int)(fp - (fold_T *)gap->ga_data); i < gap->ga_len; ++i, ++fp)
+ {
+ /*
+ * Check for these situations:
+ * 1 2 3
+ * 1 2 3
+ * line1 2 3 4 5
+ * 2 3 4 5
+ * 2 3 4 5
+ * line2 2 3 4 5
+ * 3 5 6
+ * 3 5 6
+ */
+
+ last = fp->fd_top + fp->fd_len - 1; /* last line of fold */
+
+ /* 1. fold completely above line1: nothing to do */
+ if (last < line1)
+ continue;
+
+ /* 6. fold below line2: only adjust for amount_after */
+ if (fp->fd_top > line2)
+ {
+ if (amount_after == 0)
+ break;
+ fp->fd_top += amount_after;
+ }
+ else
+ {
+ if (fp->fd_top >= top && last <= line2)
+ {
+ /* 4. fold completely contained in range */
+ if (amount == MAXLNUM)
+ {
+ /* Deleting lines: delete the fold completely */
+ deleteFoldEntry(gap, i, TRUE);
+ --i; /* adjust index for deletion */
+ --fp;
+ }
+ else
+ fp->fd_top += amount;
+ }
+ else
+ {
+ if (fp->fd_top < top)
+ {
+ /* 2 or 3: need to correct nested folds too */
+ foldMarkAdjustRecurse(&fp->fd_nested, line1 - fp->fd_top,
+ line2 - fp->fd_top, amount, amount_after);
+ if (last <= line2)
+ {
+ /* 2. fold contains line1, line2 is below fold */
+ if (amount == MAXLNUM)
+ fp->fd_len = line1 - fp->fd_top;
+ else
+ fp->fd_len += amount;
+ }
+ else
+ {
+ /* 3. fold contains line1 and line2 */
+ fp->fd_len += amount_after;
+ }
+ }
+ else
+ {
+ /* 5. fold is below line1 and contains line2; need to
+ * correct nested folds too */
+ if (amount == MAXLNUM)
+ {
+ foldMarkAdjustRecurse(&fp->fd_nested,
+ line1 - fp->fd_top,
+ line2 - fp->fd_top,
+ amount,
+ amount_after + (fp->fd_top - top));
+ fp->fd_len -= line2 - fp->fd_top + 1;
+ fp->fd_top = line1;
+ }
+ else
+ {
+ foldMarkAdjustRecurse(&fp->fd_nested,
+ line1 - fp->fd_top,
+ line2 - fp->fd_top,
+ amount,
+ amount_after - amount);
+ fp->fd_len += amount_after - amount;
+ fp->fd_top += amount;
+ }
+ }
+ }
+ }
+ }
+}
+
+/* getDeepestNesting() {{{2 */
+/*
+ * Get the lowest 'foldlevel' value that makes the deepest nested fold in the
+ * current window open.
+ */
+ int
+getDeepestNesting(void)
+{
+ checkupdate(curwin);
+ return getDeepestNestingRecurse(&curwin->w_folds);
+}
+
+ static int
+getDeepestNestingRecurse(garray_T *gap)
+{
+ int i;
+ int level;
+ int maxlevel = 0;
+ fold_T *fp;
+
+ fp = (fold_T *)gap->ga_data;
+ for (i = 0; i < gap->ga_len; ++i)
+ {
+ level = getDeepestNestingRecurse(&fp[i].fd_nested) + 1;
+ if (level > maxlevel)
+ maxlevel = level;
+ }
+
+ return maxlevel;
+}
+
+/* check_closed() {{{2 */
+/*
+ * Check if a fold is closed and update the info needed to check nested folds.
+ */
+ static int
+check_closed(
+ win_T *win,
+ fold_T *fp,
+ int *use_levelp, /* TRUE: outer fold had FD_LEVEL */
+ int level, /* folding depth */
+ int *maybe_smallp, /* TRUE: outer this had fd_small == MAYBE */
+ linenr_T lnum_off) /* line number offset for fp->fd_top */
+{
+ int closed = FALSE;
+
+ /* Check if this fold is closed. If the flag is FD_LEVEL this
+ * fold and all folds it contains depend on 'foldlevel'. */
+ if (*use_levelp || fp->fd_flags == FD_LEVEL)
+ {
+ *use_levelp = TRUE;
+ if (level >= win->w_p_fdl)
+ closed = TRUE;
+ }
+ else if (fp->fd_flags == FD_CLOSED)
+ closed = TRUE;
+
+ /* Small fold isn't closed anyway. */
+ if (fp->fd_small == MAYBE)
+ *maybe_smallp = TRUE;
+ if (closed)
+ {
+ if (*maybe_smallp)
+ fp->fd_small = MAYBE;
+ checkSmall(win, fp, lnum_off);
+ if (fp->fd_small == TRUE)
+ closed = FALSE;
+ }
+ return closed;
+}
+
+/* checkSmall() {{{2 */
+/*
+ * Update fd_small field of fold "fp".
+ */
+ static void
+checkSmall(
+ win_T *wp,
+ fold_T *fp,
+ linenr_T lnum_off) /* offset for fp->fd_top */
+{
+ int count;
+ int n;
+
+ if (fp->fd_small == MAYBE)
+ {
+ /* Mark any nested folds to maybe-small */
+ setSmallMaybe(&fp->fd_nested);
+
+ if (fp->fd_len > curwin->w_p_fml)
+ fp->fd_small = FALSE;
+ else
+ {
+ count = 0;
+ for (n = 0; n < fp->fd_len; ++n)
+ {
+ count += plines_win_nofold(wp, fp->fd_top + lnum_off + n);
+ if (count > curwin->w_p_fml)
+ {
+ fp->fd_small = FALSE;
+ return;
+ }
+ }
+ fp->fd_small = TRUE;
+ }
+ }
+}
+
+/* setSmallMaybe() {{{2 */
+/*
+ * Set small flags in "gap" to MAYBE.
+ */
+ static void
+setSmallMaybe(garray_T *gap)
+{
+ int i;
+ fold_T *fp;
+
+ fp = (fold_T *)gap->ga_data;
+ for (i = 0; i < gap->ga_len; ++i)
+ fp[i].fd_small = MAYBE;
+}
+
+/* foldCreateMarkers() {{{2 */
+/*
+ * Create a fold from line "start" to line "end" (inclusive) in the current
+ * window by adding markers.
+ */
+ static void
+foldCreateMarkers(linenr_T start, linenr_T end)
+{
+ if (!curbuf->b_p_ma)
+ {
+ emsg(_(e_modifiable));
+ return;
+ }
+ parseMarker(curwin);
+
+ foldAddMarker(start, curwin->w_p_fmr, foldstartmarkerlen);
+ foldAddMarker(end, foldendmarker, foldendmarkerlen);
+
+ /* Update both changes here, to avoid all folds after the start are
+ * changed when the start marker is inserted and the end isn't. */
+ changed_lines(start, (colnr_T)0, end, 0L);
+}
+
+/* foldAddMarker() {{{2 */
+/*
+ * Add "marker[markerlen]" in 'commentstring' to line "lnum".
+ */
+ static void
+foldAddMarker(linenr_T lnum, char_u *marker, int markerlen)
+{
+ char_u *cms = curbuf->b_p_cms;
+ char_u *line;
+ int line_len;
+ char_u *newline;
+ char_u *p = (char_u *)strstr((char *)curbuf->b_p_cms, "%s");
+ int line_is_comment = FALSE;
+
+ /* Allocate a new line: old-line + 'cms'-start + marker + 'cms'-end */
+ line = ml_get(lnum);
+ line_len = (int)STRLEN(line);
+
+ if (u_save(lnum - 1, lnum + 1) == OK)
+ {
+#if defined(FEAT_COMMENTS)
+ /* Check if the line ends with an unclosed comment */
+ (void)skip_comment(line, FALSE, FALSE, &line_is_comment);
+#endif
+ newline = alloc((unsigned)(line_len + markerlen + STRLEN(cms) + 1));
+ if (newline == NULL)
+ return;
+ STRCPY(newline, line);
+ /* Append the marker to the end of the line */
+ if (p == NULL || line_is_comment)
+ vim_strncpy(newline + line_len, marker, markerlen);
+ else
+ {
+ STRCPY(newline + line_len, cms);
+ STRNCPY(newline + line_len + (p - cms), marker, markerlen);
+ STRCPY(newline + line_len + (p - cms) + markerlen, p + 2);
+ }
+
+ ml_replace(lnum, newline, FALSE);
+ }
+}
+
+/* deleteFoldMarkers() {{{2 */
+/*
+ * Delete the markers for a fold, causing it to be deleted.
+ */
+ static void
+deleteFoldMarkers(
+ fold_T *fp,
+ int recursive,
+ linenr_T lnum_off) /* offset for fp->fd_top */
+{
+ int i;
+
+ if (recursive)
+ for (i = 0; i < fp->fd_nested.ga_len; ++i)
+ deleteFoldMarkers((fold_T *)fp->fd_nested.ga_data + i, TRUE,
+ lnum_off + fp->fd_top);
+ foldDelMarker(fp->fd_top + lnum_off, curwin->w_p_fmr, foldstartmarkerlen);
+ foldDelMarker(fp->fd_top + lnum_off + fp->fd_len - 1,
+ foldendmarker, foldendmarkerlen);
+}
+
+/* foldDelMarker() {{{2 */
+/*
+ * Delete marker "marker[markerlen]" at the end of line "lnum".
+ * Delete 'commentstring' if it matches.
+ * If the marker is not found, there is no error message. Could a missing
+ * close-marker.
+ */
+ static void
+foldDelMarker(linenr_T lnum, char_u *marker, int markerlen)
+{
+ char_u *line;
+ char_u *newline;
+ char_u *p;
+ int len;
+ char_u *cms = curbuf->b_p_cms;
+ char_u *cms2;
+
+ line = ml_get(lnum);
+ for (p = line; *p != NUL; ++p)
+ if (STRNCMP(p, marker, markerlen) == 0)
+ {
+ /* Found the marker, include a digit if it's there. */
+ len = markerlen;
+ if (VIM_ISDIGIT(p[len]))
+ ++len;
+ if (*cms != NUL)
+ {
+ /* Also delete 'commentstring' if it matches. */
+ cms2 = (char_u *)strstr((char *)cms, "%s");
+ if (p - line >= cms2 - cms
+ && STRNCMP(p - (cms2 - cms), cms, cms2 - cms) == 0
+ && STRNCMP(p + len, cms2 + 2, STRLEN(cms2 + 2)) == 0)
+ {
+ p -= cms2 - cms;
+ len += (int)STRLEN(cms) - 2;
+ }
+ }
+ if (u_save(lnum - 1, lnum + 1) == OK)
+ {
+ /* Make new line: text-before-marker + text-after-marker */
+ newline = alloc((unsigned)(STRLEN(line) - len + 1));
+ if (newline != NULL)
+ {
+ STRNCPY(newline, line, p - line);
+ STRCPY(newline + (p - line), p + len);
+ ml_replace(lnum, newline, FALSE);
+ }
+ }
+ break;
+ }
+}
+
+/* get_foldtext() {{{2 */
+/*
+ * Return the text for a closed fold at line "lnum", with last line "lnume".
+ * When 'foldtext' isn't set puts the result in "buf[FOLD_TEXT_LEN]".
+ * Otherwise the result is in allocated memory.
+ */
+ char_u *
+get_foldtext(
+ win_T *wp,
+ linenr_T lnum,
+ linenr_T lnume,
+ foldinfo_T *foldinfo,
+ char_u *buf)
+{
+ char_u *text = NULL;
+#ifdef FEAT_EVAL
+ /* an error occurred when evaluating 'fdt' setting */
+ static int got_fdt_error = FALSE;
+ int save_did_emsg = did_emsg;
+ static win_T *last_wp = NULL;
+ static linenr_T last_lnum = 0;
+
+ if (last_wp != wp || last_wp == NULL
+ || last_lnum > lnum || last_lnum == 0)
+ /* window changed, try evaluating foldtext setting once again */
+ got_fdt_error = FALSE;
+
+ if (!got_fdt_error)
+ /* a previous error should not abort evaluating 'foldexpr' */
+ did_emsg = FALSE;
+
+ if (*wp->w_p_fdt != NUL)
+ {
+ char_u dashes[MAX_LEVEL + 2];
+ win_T *save_curwin;
+ int level;
+ char_u *p;
+
+ /* Set "v:foldstart" and "v:foldend". */
+ set_vim_var_nr(VV_FOLDSTART, lnum);
+ set_vim_var_nr(VV_FOLDEND, lnume);
+
+ /* Set "v:folddashes" to a string of "level" dashes. */
+ /* Set "v:foldlevel" to "level". */
+ level = foldinfo->fi_level;
+ if (level > (int)sizeof(dashes) - 1)
+ level = (int)sizeof(dashes) - 1;
+ vim_memset(dashes, '-', (size_t)level);
+ dashes[level] = NUL;
+ set_vim_var_string(VV_FOLDDASHES, dashes, -1);
+ set_vim_var_nr(VV_FOLDLEVEL, (long)level);
+
+ /* skip evaluating foldtext on errors */
+ if (!got_fdt_error)
+ {
+ save_curwin = curwin;
+ curwin = wp;
+ curbuf = wp->w_buffer;
+
+ ++emsg_silent; /* handle exceptions, but don't display errors */
+ text = eval_to_string_safe(wp->w_p_fdt, NULL,
+ was_set_insecurely((char_u *)"foldtext", OPT_LOCAL));
+ --emsg_silent;
+
+ if (text == NULL || did_emsg)
+ got_fdt_error = TRUE;
+
+ curwin = save_curwin;
+ curbuf = curwin->w_buffer;
+ }
+ last_lnum = lnum;
+ last_wp = wp;
+ set_vim_var_string(VV_FOLDDASHES, NULL, -1);
+
+ if (!did_emsg && save_did_emsg)
+ did_emsg = save_did_emsg;
+
+ if (text != NULL)
+ {
+ /* Replace unprintable characters, if there are any. But
+ * replace a TAB with a space. */
+ for (p = text; *p != NUL; ++p)
+ {
+ int len;
+
+ if (has_mbyte && (len = (*mb_ptr2len)(p)) > 1)
+ {
+ if (!vim_isprintc((*mb_ptr2char)(p)))
+ break;
+ p += len - 1;
+ }
+ else
+ if (*p == TAB)
+ *p = ' ';
+ else if (ptr2cells(p) > 1)
+ break;
+ }
+ if (*p != NUL)
+ {
+ p = transstr(text);
+ vim_free(text);
+ text = p;
+ }
+ }
+ }
+ if (text == NULL)
+#endif
+ {
+ long count = (long)(lnume - lnum + 1);
+
+ vim_snprintf((char *)buf, FOLD_TEXT_LEN,
+ NGETTEXT("+--%3ld line folded ",
+ "+--%3ld lines folded ", count),
+ count);
+ text = buf;
+ }
+ return text;
+}
+
+/* foldtext_cleanup() {{{2 */
+/*
+ * Remove 'foldmarker' and 'commentstring' from "str" (in-place).
+ */
+ void
+foldtext_cleanup(char_u *str)
+{
+ char_u *cms_start; /* first part or the whole comment */
+ int cms_slen = 0; /* length of cms_start */
+ char_u *cms_end; /* last part of the comment or NULL */
+ int cms_elen = 0; /* length of cms_end */
+ char_u *s;
+ char_u *p;
+ int len;
+ int did1 = FALSE;
+ int did2 = FALSE;
+
+ /* Ignore leading and trailing white space in 'commentstring'. */
+ cms_start = skipwhite(curbuf->b_p_cms);
+ cms_slen = (int)STRLEN(cms_start);
+ while (cms_slen > 0 && VIM_ISWHITE(cms_start[cms_slen - 1]))
+ --cms_slen;
+
+ /* locate "%s" in 'commentstring', use the part before and after it. */
+ cms_end = (char_u *)strstr((char *)cms_start, "%s");
+ if (cms_end != NULL)
+ {
+ cms_elen = cms_slen - (int)(cms_end - cms_start);
+ cms_slen = (int)(cms_end - cms_start);
+
+ /* exclude white space before "%s" */
+ while (cms_slen > 0 && VIM_ISWHITE(cms_start[cms_slen - 1]))
+ --cms_slen;
+
+ /* skip "%s" and white space after it */
+ s = skipwhite(cms_end + 2);
+ cms_elen -= (int)(s - cms_end);
+ cms_end = s;
+ }
+ parseMarker(curwin);
+
+ for (s = str; *s != NUL; )
+ {
+ len = 0;
+ if (STRNCMP(s, curwin->w_p_fmr, foldstartmarkerlen) == 0)
+ len = foldstartmarkerlen;
+ else if (STRNCMP(s, foldendmarker, foldendmarkerlen) == 0)
+ len = foldendmarkerlen;
+ if (len > 0)
+ {
+ if (VIM_ISDIGIT(s[len]))
+ ++len;
+
+ /* May remove 'commentstring' start. Useful when it's a double
+ * quote and we already removed a double quote. */
+ for (p = s; p > str && VIM_ISWHITE(p[-1]); --p)
+ ;
+ if (p >= str + cms_slen
+ && STRNCMP(p - cms_slen, cms_start, cms_slen) == 0)
+ {
+ len += (int)(s - p) + cms_slen;
+ s = p - cms_slen;
+ }
+ }
+ else if (cms_end != NULL)
+ {
+ if (!did1 && cms_slen > 0 && STRNCMP(s, cms_start, cms_slen) == 0)
+ {
+ len = cms_slen;
+ did1 = TRUE;
+ }
+ else if (!did2 && cms_elen > 0
+ && STRNCMP(s, cms_end, cms_elen) == 0)
+ {
+ len = cms_elen;
+ did2 = TRUE;
+ }
+ }
+ if (len != 0)
+ {
+ while (VIM_ISWHITE(s[len]))
+ ++len;
+ STRMOVE(s, s + len);
+ }
+ else
+ {
+ MB_PTR_ADV(s);
+ }
+ }
+}
+
+/* Folding by indent, expr, marker and syntax. {{{1 */
+/* Define "fline_T", passed to get fold level for a line. {{{2 */
+typedef struct
+{
+ win_T *wp; /* window */
+ linenr_T lnum; /* current line number */
+ linenr_T off; /* offset between lnum and real line number */
+ linenr_T lnum_save; /* line nr used by foldUpdateIEMSRecurse() */
+ int lvl; /* current level (-1 for undefined) */
+ int lvl_next; /* level used for next line */
+ int start; /* number of folds that are forced to start at
+ this line. */
+ int end; /* level of fold that is forced to end below
+ this line */
+ int had_end; /* level of fold that is forced to end above
+ this line (copy of "end" of prev. line) */
+} fline_T;
+
+/* Flag is set when redrawing is needed. */
+static int fold_changed;
+
+/* Function declarations. {{{2 */
+static linenr_T foldUpdateIEMSRecurse(garray_T *gap, int level, linenr_T startlnum, fline_T *flp, void (*getlevel)(fline_T *), linenr_T bot, int topflags);
+static int foldInsert(garray_T *gap, int i);
+static void foldSplit(garray_T *gap, int i, linenr_T top, linenr_T bot);
+static void foldRemove(garray_T *gap, linenr_T top, linenr_T bot);
+static void foldMerge(fold_T *fp1, garray_T *gap, fold_T *fp2);
+static void foldlevelIndent(fline_T *flp);
+#ifdef FEAT_DIFF
+static void foldlevelDiff(fline_T *flp);
+#endif
+static void foldlevelExpr(fline_T *flp);
+static void foldlevelMarker(fline_T *flp);
+static void foldlevelSyntax(fline_T *flp);
+
+/* foldUpdateIEMS() {{{2 */
+/*
+ * Update the folding for window "wp", at least from lines "top" to "bot".
+ * Return TRUE if any folds did change.
+ */
+ static void
+foldUpdateIEMS(win_T *wp, linenr_T top, linenr_T bot)
+{
+ linenr_T start;
+ linenr_T end;
+ fline_T fline;
+ void (*getlevel)(fline_T *);
+ int level;
+ fold_T *fp;
+
+ /* Avoid problems when being called recursively. */
+ if (invalid_top != (linenr_T)0)
+ return;
+
+ if (wp->w_foldinvalid)
+ {
+ /* Need to update all folds. */
+ top = 1;
+ bot = wp->w_buffer->b_ml.ml_line_count;
+ wp->w_foldinvalid = FALSE;
+
+ /* Mark all folds a maybe-small. */
+ setSmallMaybe(&wp->w_folds);
+ }
+
+#ifdef FEAT_DIFF
+ /* add the context for "diff" folding */
+ if (foldmethodIsDiff(wp))
+ {
+ if (top > diff_context)
+ top -= diff_context;
+ else
+ top = 1;
+ bot += diff_context;
+ }
+#endif
+
+ /* When deleting lines at the end of the buffer "top" can be past the end
+ * of the buffer. */
+ if (top > wp->w_buffer->b_ml.ml_line_count)
+ top = wp->w_buffer->b_ml.ml_line_count;
+
+ fold_changed = FALSE;
+ fline.wp = wp;
+ fline.off = 0;
+ fline.lvl = 0;
+ fline.lvl_next = -1;
+ fline.start = 0;
+ fline.end = MAX_LEVEL + 1;
+ fline.had_end = MAX_LEVEL + 1;
+
+ invalid_top = top;
+ invalid_bot = bot;
+
+ if (foldmethodIsMarker(wp))
+ {
+ getlevel = foldlevelMarker;
+
+ /* Init marker variables to speed up foldlevelMarker(). */
+ parseMarker(wp);
+
+ /* Need to get the level of the line above top, it is used if there is
+ * no marker at the top. */
+ if (top > 1)
+ {
+ /* Get the fold level at top - 1. */
+ level = foldLevelWin(wp, top - 1);
+
+ /* The fold may end just above the top, check for that. */
+ fline.lnum = top - 1;
+ fline.lvl = level;
+ getlevel(&fline);
+
+ /* If a fold started here, we already had the level, if it stops
+ * here, we need to use lvl_next. Could also start and end a fold
+ * in the same line. */
+ if (fline.lvl > level)
+ fline.lvl = level - (fline.lvl - fline.lvl_next);
+ else
+ fline.lvl = fline.lvl_next;
+ }
+ fline.lnum = top;
+ getlevel(&fline);
+ }
+ else
+ {
+ fline.lnum = top;
+ if (foldmethodIsExpr(wp))
+ {
+ getlevel = foldlevelExpr;
+ /* start one line back, because a "<1" may indicate the end of a
+ * fold in the topline */
+ if (top > 1)
+ --fline.lnum;
+ }
+ else if (foldmethodIsSyntax(wp))
+ getlevel = foldlevelSyntax;
+#ifdef FEAT_DIFF
+ else if (foldmethodIsDiff(wp))
+ getlevel = foldlevelDiff;
+#endif
+ else
+ getlevel = foldlevelIndent;
+
+ /* Backup to a line for which the fold level is defined. Since it's
+ * always defined for line one, we will stop there. */
+ fline.lvl = -1;
+ for ( ; !got_int; --fline.lnum)
+ {
+ /* Reset lvl_next each time, because it will be set to a value for
+ * the next line, but we search backwards here. */
+ fline.lvl_next = -1;
+ getlevel(&fline);
+ if (fline.lvl >= 0)
+ break;
+ }
+ }
+
+ /*
+ * If folding is defined by the syntax, it is possible that a change in
+ * one line will cause all sub-folds of the current fold to change (e.g.,
+ * closing a C-style comment can cause folds in the subsequent lines to
+ * appear). To take that into account we should adjust the value of "bot"
+ * to point to the end of the current fold:
+ */
+ if (foldlevelSyntax == getlevel)
+ {
+ garray_T *gap = &wp->w_folds;
+ fold_T *fpn = NULL;
+ int current_fdl = 0;
+ linenr_T fold_start_lnum = 0;
+ linenr_T lnum_rel = fline.lnum;
+
+ while (current_fdl < fline.lvl)
+ {
+ if (!foldFind(gap, lnum_rel, &fpn))
+ break;
+ ++current_fdl;
+
+ fold_start_lnum += fpn->fd_top;
+ gap = &fpn->fd_nested;
+ lnum_rel -= fpn->fd_top;
+ }
+ if (fpn != NULL && current_fdl == fline.lvl)
+ {
+ linenr_T fold_end_lnum = fold_start_lnum + fpn->fd_len;
+
+ if (fold_end_lnum > bot)
+ bot = fold_end_lnum;
+ }
+ }
+
+ start = fline.lnum;
+ end = bot;
+ /* Do at least one line. */
+ if (start > end && end < wp->w_buffer->b_ml.ml_line_count)
+ end = start;
+ while (!got_int)
+ {
+ /* Always stop at the end of the file ("end" can be past the end of
+ * the file). */
+ if (fline.lnum > wp->w_buffer->b_ml.ml_line_count)
+ break;
+ if (fline.lnum > end)
+ {
+ /* For "marker", "expr" and "syntax" methods: If a change caused
+ * a fold to be removed, we need to continue at least until where
+ * it ended. */
+ if (getlevel != foldlevelMarker
+ && getlevel != foldlevelSyntax
+ && getlevel != foldlevelExpr)
+ break;
+ if ((start <= end
+ && foldFind(&wp->w_folds, end, &fp)
+ && fp->fd_top + fp->fd_len - 1 > end)
+ || (fline.lvl == 0
+ && foldFind(&wp->w_folds, fline.lnum, &fp)
+ && fp->fd_top < fline.lnum))
+ end = fp->fd_top + fp->fd_len - 1;
+ else if (getlevel == foldlevelSyntax
+ && foldLevelWin(wp, fline.lnum) != fline.lvl)
+ /* For "syntax" method: Compare the foldlevel that the syntax
+ * tells us to the foldlevel from the existing folds. If they
+ * don't match continue updating folds. */
+ end = fline.lnum;
+ else
+ break;
+ }
+
+ /* A level 1 fold starts at a line with foldlevel > 0. */
+ if (fline.lvl > 0)
+ {
+ invalid_top = fline.lnum;
+ invalid_bot = end;
+ end = foldUpdateIEMSRecurse(&wp->w_folds,
+ 1, start, &fline, getlevel, end, FD_LEVEL);
+ start = fline.lnum;
+ }
+ else
+ {
+ if (fline.lnum == wp->w_buffer->b_ml.ml_line_count)
+ break;
+ ++fline.lnum;
+ fline.lvl = fline.lvl_next;
+ getlevel(&fline);
+ }
+ }
+
+ /* There can't be any folds from start until end now. */
+ foldRemove(&wp->w_folds, start, end);
+
+ /* If some fold changed, need to redraw and position cursor. */
+ if (fold_changed && wp->w_p_fen)
+ changed_window_setting_win(wp);
+
+ /* If we updated folds past "bot", need to redraw more lines. Don't do
+ * this in other situations, the changed lines will be redrawn anyway and
+ * this method can cause the whole window to be updated. */
+ if (end != bot)
+ {
+ if (wp->w_redraw_top == 0 || wp->w_redraw_top > top)
+ wp->w_redraw_top = top;
+ if (wp->w_redraw_bot < end)
+ wp->w_redraw_bot = end;
+ }
+
+ invalid_top = (linenr_T)0;
+}
+
+/* foldUpdateIEMSRecurse() {{{2 */
+/*
+ * Update a fold that starts at "flp->lnum". At this line there is always a
+ * valid foldlevel, and its level >= "level".
+ * "flp" is valid for "flp->lnum" when called and it's valid when returning.
+ * "flp->lnum" is set to the lnum just below the fold, if it ends before
+ * "bot", it's "bot" plus one if the fold continues and it's bigger when using
+ * the marker method and a text change made following folds to change.
+ * When returning, "flp->lnum_save" is the line number that was used to get
+ * the level when the level at "flp->lnum" is invalid.
+ * Remove any folds from "startlnum" up to here at this level.
+ * Recursively update nested folds.
+ * Below line "bot" there are no changes in the text.
+ * "flp->lnum", "flp->lnum_save" and "bot" are relative to the start of the
+ * outer fold.
+ * "flp->off" is the offset to the real line number in the buffer.
+ *
+ * All this would be a lot simpler if all folds in the range would be deleted
+ * and then created again. But we would lose all information about the
+ * folds, even when making changes that don't affect the folding (e.g. "vj~").
+ *
+ * Returns bot, which may have been increased for lines that also need to be
+ * updated as a result of a detected change in the fold.
+ */
+ static linenr_T
+foldUpdateIEMSRecurse(
+ garray_T *gap,
+ int level,
+ linenr_T startlnum,
+ fline_T *flp,
+ void (*getlevel)(fline_T *),
+ linenr_T bot,
+ int topflags) /* flags used by containing fold */
+{
+ linenr_T ll;
+ fold_T *fp = NULL;
+ fold_T *fp2;
+ int lvl = level;
+ linenr_T startlnum2 = startlnum;
+ linenr_T firstlnum = flp->lnum; /* first lnum we got */
+ int i;
+ int finish = FALSE;
+ linenr_T linecount = flp->wp->w_buffer->b_ml.ml_line_count - flp->off;
+ int concat;
+
+ /*
+ * If using the marker method, the start line is not the start of a fold
+ * at the level we're dealing with and the level is non-zero, we must use
+ * the previous fold. But ignore a fold that starts at or below
+ * startlnum, it must be deleted.
+ */
+ if (getlevel == foldlevelMarker && flp->start <= flp->lvl - level
+ && flp->lvl > 0)
+ {
+ (void)foldFind(gap, startlnum - 1, &fp);
+ if (fp >= ((fold_T *)gap->ga_data) + gap->ga_len
+ || fp->fd_top >= startlnum)
+ fp = NULL;
+ }
+
+ /*
+ * Loop over all lines in this fold, or until "bot" is hit.
+ * Handle nested folds inside of this fold.
+ * "flp->lnum" is the current line. When finding the end of the fold, it
+ * is just below the end of the fold.
+ * "*flp" contains the level of the line "flp->lnum" or a following one if
+ * there are lines with an invalid fold level. "flp->lnum_save" is the
+ * line number that was used to get the fold level (below "flp->lnum" when
+ * it has an invalid fold level). When called the fold level is always
+ * valid, thus "flp->lnum_save" is equal to "flp->lnum".
+ */
+ flp->lnum_save = flp->lnum;
+ while (!got_int)
+ {
+ /* Updating folds can be slow, check for CTRL-C. */
+ line_breakcheck();
+
+ /* Set "lvl" to the level of line "flp->lnum". When flp->start is set
+ * and after the first line of the fold, set the level to zero to
+ * force the fold to end. Do the same when had_end is set: Previous
+ * line was marked as end of a fold. */
+ lvl = flp->lvl;
+ if (lvl > MAX_LEVEL)
+ lvl = MAX_LEVEL;
+ if (flp->lnum > firstlnum
+ && (level > lvl - flp->start || level >= flp->had_end))
+ lvl = 0;
+
+ if (flp->lnum > bot && !finish && fp != NULL)
+ {
+ /* For "marker" and "syntax" methods:
+ * - If a change caused a nested fold to be removed, we need to
+ * delete it and continue at least until where it ended.
+ * - If a change caused a nested fold to be created, or this fold
+ * to continue below its original end, need to finish this fold.
+ */
+ if (getlevel != foldlevelMarker
+ && getlevel != foldlevelExpr
+ && getlevel != foldlevelSyntax)
+ break;
+ i = 0;
+ fp2 = fp;
+ if (lvl >= level)
+ {
+ /* Compute how deep the folds currently are, if it's deeper
+ * than "lvl" then some must be deleted, need to update
+ * at least one nested fold. */
+ ll = flp->lnum - fp->fd_top;
+ while (foldFind(&fp2->fd_nested, ll, &fp2))
+ {
+ ++i;
+ ll -= fp2->fd_top;
+ }
+ }
+ if (lvl < level + i)
+ {
+ (void)foldFind(&fp->fd_nested, flp->lnum - fp->fd_top, &fp2);
+ if (fp2 != NULL)
+ bot = fp2->fd_top + fp2->fd_len - 1 + fp->fd_top;
+ }
+ else if (fp->fd_top + fp->fd_len <= flp->lnum && lvl >= level)
+ finish = TRUE;
+ else
+ break;
+ }
+
+ /* At the start of the first nested fold and at the end of the current
+ * fold: check if existing folds at this level, before the current
+ * one, need to be deleted or truncated. */
+ if (fp == NULL
+ && (lvl != level
+ || flp->lnum_save >= bot
+ || flp->start != 0
+ || flp->had_end <= MAX_LEVEL
+ || flp->lnum == linecount))
+ {
+ /*
+ * Remove or update folds that have lines between startlnum and
+ * firstlnum.
+ */
+ while (!got_int)
+ {
+ /* set concat to 1 if it's allowed to concatenated this fold
+ * with a previous one that touches it. */
+ if (flp->start != 0 || flp->had_end <= MAX_LEVEL)
+ concat = 0;
+ else
+ concat = 1;
+
+ /* Find an existing fold to re-use. Preferably one that
+ * includes startlnum, otherwise one that ends just before
+ * startlnum or starts after it. */
+ if (foldFind(gap, startlnum, &fp)
+ || (fp < ((fold_T *)gap->ga_data) + gap->ga_len
+ && fp->fd_top <= firstlnum)
+ || foldFind(gap, firstlnum - concat, &fp)
+ || (fp < ((fold_T *)gap->ga_data) + gap->ga_len
+ && ((lvl < level && fp->fd_top < flp->lnum)
+ || (lvl >= level
+ && fp->fd_top <= flp->lnum_save))))
+ {
+ if (fp->fd_top + fp->fd_len + concat > firstlnum)
+ {
+ /* Use existing fold for the new fold. If it starts
+ * before where we started looking, extend it. If it
+ * starts at another line, update nested folds to keep
+ * their position, compensating for the new fd_top. */
+ if (fp->fd_top == firstlnum)
+ {
+ /* have found a fold beginning where we want */
+ }
+ else if (fp->fd_top >= startlnum)
+ {
+ if (fp->fd_top > firstlnum)
+ /* like lines are inserted */
+ foldMarkAdjustRecurse(&fp->fd_nested,
+ (linenr_T)0, (linenr_T)MAXLNUM,
+ (long)(fp->fd_top - firstlnum), 0L);
+ else
+ /* like lines are deleted */
+ foldMarkAdjustRecurse(&fp->fd_nested,
+ (linenr_T)0,
+ (long)(firstlnum - fp->fd_top - 1),
+ (linenr_T)MAXLNUM,
+ (long)(fp->fd_top - firstlnum));
+ fp->fd_len += fp->fd_top - firstlnum;
+ fp->fd_top = firstlnum;
+ fold_changed = TRUE;
+ }
+ else if ((flp->start != 0 && lvl == level)
+ || firstlnum != startlnum)
+ {
+ linenr_T breakstart;
+ linenr_T breakend;
+
+ /*
+ * Before there was a fold spanning from above
+ * startlnum to below firstlnum. This fold is valid
+ * above startlnum (because we are not updating
+ * that range), but there should now be a break in
+ * it.
+ * If the break is because we are now forced to
+ * start a new fold at the level "level" at line
+ * fline->lnum, then we need to split the fold at
+ * fline->lnum.
+ * If the break is because the range
+ * [startlnum, firstlnum) is now at a lower indent
+ * than "level", we need to split the fold in this
+ * range.
+ * Any splits have to be done recursively.
+ */
+ if (firstlnum != startlnum)
+ {
+ breakstart = startlnum;
+ breakend = firstlnum;
+ }
+ else
+ {
+ breakstart = flp->lnum;
+ breakend = flp->lnum;
+ }
+ foldRemove(&fp->fd_nested, breakstart - fp->fd_top,
+ breakend - fp->fd_top);
+ i = (int)(fp - (fold_T *)gap->ga_data);
+ foldSplit(gap, i, breakstart, breakend - 1);
+ fp = (fold_T *)gap->ga_data + i + 1;
+
+ /* If using the "marker" or "syntax" method, we
+ * need to continue until the end of the fold is
+ * found. */
+ if (getlevel == foldlevelMarker
+ || getlevel == foldlevelExpr
+ || getlevel == foldlevelSyntax)
+ finish = TRUE;
+ }
+
+ if (fp->fd_top == startlnum && concat)
+ {
+ i = (int)(fp - (fold_T *)gap->ga_data);
+ if (i != 0)
+ {
+ fp2 = fp - 1;
+ if (fp2->fd_top + fp2->fd_len == fp->fd_top)
+ {
+ foldMerge(fp2, gap, fp);
+ fp = fp2;
+ }
+ }
+ }
+ break;
+ }
+ if (fp->fd_top >= startlnum)
+ {
+ /* A fold that starts at or after startlnum and stops
+ * before the new fold must be deleted. Continue
+ * looking for the next one. */
+ deleteFoldEntry(gap,
+ (int)(fp - (fold_T *)gap->ga_data), TRUE);
+ }
+ else
+ {
+ /* A fold has some lines above startlnum, truncate it
+ * to stop just above startlnum. */
+ fp->fd_len = startlnum - fp->fd_top;
+ foldMarkAdjustRecurse(&fp->fd_nested,
+ (linenr_T)fp->fd_len, (linenr_T)MAXLNUM,
+ (linenr_T)MAXLNUM, 0L);
+ fold_changed = TRUE;
+ }
+ }
+ else
+ {
+ /* Insert new fold. Careful: ga_data may be NULL and it
+ * may change! */
+ i = (int)(fp - (fold_T *)gap->ga_data);
+ if (foldInsert(gap, i) != OK)
+ return bot;
+ fp = (fold_T *)gap->ga_data + i;
+ /* The new fold continues until bot, unless we find the
+ * end earlier. */
+ fp->fd_top = firstlnum;
+ fp->fd_len = bot - firstlnum + 1;
+ /* When the containing fold is open, the new fold is open.
+ * The new fold is closed if the fold above it is closed.
+ * The first fold depends on the containing fold. */
+ if (topflags == FD_OPEN)
+ {
+ flp->wp->w_fold_manual = TRUE;
+ fp->fd_flags = FD_OPEN;
+ }
+ else if (i <= 0)
+ {
+ fp->fd_flags = topflags;
+ if (topflags != FD_LEVEL)
+ flp->wp->w_fold_manual = TRUE;
+ }
+ else
+ fp->fd_flags = (fp - 1)->fd_flags;
+ fp->fd_small = MAYBE;
+ /* If using the "marker", "expr" or "syntax" method, we
+ * need to continue until the end of the fold is found. */
+ if (getlevel == foldlevelMarker
+ || getlevel == foldlevelExpr
+ || getlevel == foldlevelSyntax)
+ finish = TRUE;
+ fold_changed = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (lvl < level || flp->lnum > linecount)
+ {
+ /*
+ * Found a line with a lower foldlevel, this fold ends just above
+ * "flp->lnum".
+ */
+ break;
+ }
+
+ /*
+ * The fold includes the line "flp->lnum" and "flp->lnum_save".
+ * Check "fp" for safety.
+ */
+ if (lvl > level && fp != NULL)
+ {
+ /*
+ * There is a nested fold, handle it recursively.
+ */
+ /* At least do one line (can happen when finish is TRUE). */
+ if (bot < flp->lnum)
+ bot = flp->lnum;
+
+ /* Line numbers in the nested fold are relative to the start of
+ * this fold. */
+ flp->lnum = flp->lnum_save - fp->fd_top;
+ flp->off += fp->fd_top;
+ i = (int)(fp - (fold_T *)gap->ga_data);
+ bot = foldUpdateIEMSRecurse(&fp->fd_nested, level + 1,
+ startlnum2 - fp->fd_top, flp, getlevel,
+ bot - fp->fd_top, fp->fd_flags);
+ fp = (fold_T *)gap->ga_data + i;
+ flp->lnum += fp->fd_top;
+ flp->lnum_save += fp->fd_top;
+ flp->off -= fp->fd_top;
+ bot += fp->fd_top;
+ startlnum2 = flp->lnum;
+
+ /* This fold may end at the same line, don't incr. flp->lnum. */
+ }
+ else
+ {
+ /*
+ * Get the level of the next line, then continue the loop to check
+ * if it ends there.
+ * Skip over undefined lines, to find the foldlevel after it.
+ * For the last line in the file the foldlevel is always valid.
+ */
+ flp->lnum = flp->lnum_save;
+ ll = flp->lnum + 1;
+ while (!got_int)
+ {
+ /* Make the previous level available to foldlevel(). */
+ prev_lnum = flp->lnum;
+ prev_lnum_lvl = flp->lvl;
+
+ if (++flp->lnum > linecount)
+ break;
+ flp->lvl = flp->lvl_next;
+ getlevel(flp);
+ if (flp->lvl >= 0 || flp->had_end <= MAX_LEVEL)
+ break;
+ }
+ prev_lnum = 0;
+ if (flp->lnum > linecount)
+ break;
+
+ /* leave flp->lnum_save to lnum of the line that was used to get
+ * the level, flp->lnum to the lnum of the next line. */
+ flp->lnum_save = flp->lnum;
+ flp->lnum = ll;
+ }
+ }
+
+ if (fp == NULL) /* only happens when got_int is set */
+ return bot;
+
+ /*
+ * Get here when:
+ * lvl < level: the folds ends just above "flp->lnum"
+ * lvl >= level: fold continues below "bot"
+ */
+
+ /* Current fold at least extends until lnum. */
+ if (fp->fd_len < flp->lnum - fp->fd_top)
+ {
+ fp->fd_len = flp->lnum - fp->fd_top;
+ fp->fd_small = MAYBE;
+ fold_changed = TRUE;
+ }
+
+ /* Delete contained folds from the end of the last one found until where
+ * we stopped looking. */
+ foldRemove(&fp->fd_nested, startlnum2 - fp->fd_top,
+ flp->lnum - 1 - fp->fd_top);
+
+ if (lvl < level)
+ {
+ /* End of fold found, update the length when it got shorter. */
+ if (fp->fd_len != flp->lnum - fp->fd_top)
+ {
+ if (fp->fd_top + fp->fd_len - 1 > bot)
+ {
+ /* fold continued below bot */
+ if (getlevel == foldlevelMarker
+ || getlevel == foldlevelExpr
+ || getlevel == foldlevelSyntax)
+ {
+ /* marker method: truncate the fold and make sure the
+ * previously included lines are processed again */
+ bot = fp->fd_top + fp->fd_len - 1;
+ fp->fd_len = flp->lnum - fp->fd_top;
+ }
+ else
+ {
+ /* indent or expr method: split fold to create a new one
+ * below bot */
+ i = (int)(fp - (fold_T *)gap->ga_data);
+ foldSplit(gap, i, flp->lnum, bot);
+ fp = (fold_T *)gap->ga_data + i;
+ }
+ }
+ else
+ fp->fd_len = flp->lnum - fp->fd_top;
+ fold_changed = TRUE;
+ }
+ }
+
+ /* delete following folds that end before the current line */
+ for (;;)
+ {
+ fp2 = fp + 1;
+ if (fp2 >= (fold_T *)gap->ga_data + gap->ga_len
+ || fp2->fd_top > flp->lnum)
+ break;
+ if (fp2->fd_top + fp2->fd_len > flp->lnum)
+ {
+ if (fp2->fd_top < flp->lnum)
+ {
+ /* Make fold that includes lnum start at lnum. */
+ foldMarkAdjustRecurse(&fp2->fd_nested,
+ (linenr_T)0, (long)(flp->lnum - fp2->fd_top - 1),
+ (linenr_T)MAXLNUM, (long)(fp2->fd_top - flp->lnum));
+ fp2->fd_len -= flp->lnum - fp2->fd_top;
+ fp2->fd_top = flp->lnum;
+ fold_changed = TRUE;
+ }
+
+ if (lvl >= level)
+ {
+ /* merge new fold with existing fold that follows */
+ foldMerge(fp, gap, fp2);
+ }
+ break;
+ }
+ fold_changed = TRUE;
+ deleteFoldEntry(gap, (int)(fp2 - (fold_T *)gap->ga_data), TRUE);
+ }
+
+ /* Need to redraw the lines we inspected, which might be further down than
+ * was asked for. */
+ if (bot < flp->lnum - 1)
+ bot = flp->lnum - 1;
+
+ return bot;
+}
+
+/* foldInsert() {{{2 */
+/*
+ * Insert a new fold in "gap" at position "i".
+ * Returns OK for success, FAIL for failure.
+ */
+ static int
+foldInsert(garray_T *gap, int i)
+{
+ fold_T *fp;
+
+ if (ga_grow(gap, 1) != OK)
+ return FAIL;
+ fp = (fold_T *)gap->ga_data + i;
+ if (i < gap->ga_len)
+ mch_memmove(fp + 1, fp, sizeof(fold_T) * (gap->ga_len - i));
+ ++gap->ga_len;
+ ga_init2(&fp->fd_nested, (int)sizeof(fold_T), 10);
+ return OK;
+}
+
+/* foldSplit() {{{2 */
+/*
+ * Split the "i"th fold in "gap", which starts before "top" and ends below
+ * "bot" in two pieces, one ending above "top" and the other starting below
+ * "bot".
+ * The caller must first have taken care of any nested folds from "top" to
+ * "bot"!
+ */
+ static void
+foldSplit(
+ garray_T *gap,
+ int i,
+ linenr_T top,
+ linenr_T bot)
+{
+ fold_T *fp;
+ fold_T *fp2;
+ garray_T *gap1;
+ garray_T *gap2;
+ int idx;
+ int len;
+
+ /* The fold continues below bot, need to split it. */
+ if (foldInsert(gap, i + 1) == FAIL)
+ return;
+ fp = (fold_T *)gap->ga_data + i;
+ fp[1].fd_top = bot + 1;
+ fp[1].fd_len = fp->fd_len - (fp[1].fd_top - fp->fd_top);
+ fp[1].fd_flags = fp->fd_flags;
+ fp[1].fd_small = MAYBE;
+ fp->fd_small = MAYBE;
+
+ /* Move nested folds below bot to new fold. There can't be
+ * any between top and bot, they have been removed by the caller. */
+ gap1 = &fp->fd_nested;
+ gap2 = &fp[1].fd_nested;
+ (void)(foldFind(gap1, bot + 1 - fp->fd_top, &fp2));
+ len = (int)((fold_T *)gap1->ga_data + gap1->ga_len - fp2);
+ if (len > 0 && ga_grow(gap2, len) == OK)
+ {
+ for (idx = 0; idx < len; ++idx)
+ {
+ ((fold_T *)gap2->ga_data)[idx] = fp2[idx];
+ ((fold_T *)gap2->ga_data)[idx].fd_top
+ -= fp[1].fd_top - fp->fd_top;
+ }
+ gap2->ga_len = len;
+ gap1->ga_len -= len;
+ }
+ fp->fd_len = top - fp->fd_top;
+ fold_changed = TRUE;
+}
+
+/* foldRemove() {{{2 */
+/*
+ * Remove folds within the range "top" to and including "bot".
+ * Check for these situations:
+ * 1 2 3
+ * 1 2 3
+ * top 2 3 4 5
+ * 2 3 4 5
+ * bot 2 3 4 5
+ * 3 5 6
+ * 3 5 6
+ *
+ * 1: not changed
+ * 2: truncate to stop above "top"
+ * 3: split in two parts, one stops above "top", other starts below "bot".
+ * 4: deleted
+ * 5: made to start below "bot".
+ * 6: not changed
+ */
+ static void
+foldRemove(garray_T *gap, linenr_T top, linenr_T bot)
+{
+ fold_T *fp = NULL;
+
+ if (bot < top)
+ return; /* nothing to do */
+
+ for (;;)
+ {
+ /* Find fold that includes top or a following one. */
+ if (foldFind(gap, top, &fp) && fp->fd_top < top)
+ {
+ /* 2: or 3: need to delete nested folds */
+ foldRemove(&fp->fd_nested, top - fp->fd_top, bot - fp->fd_top);
+ if (fp->fd_top + fp->fd_len - 1 > bot)
+ {
+ /* 3: need to split it. */
+ foldSplit(gap, (int)(fp - (fold_T *)gap->ga_data), top, bot);
+ }
+ else
+ {
+ /* 2: truncate fold at "top". */
+ fp->fd_len = top - fp->fd_top;
+ }
+ fold_changed = TRUE;
+ continue;
+ }
+ if (fp >= (fold_T *)(gap->ga_data) + gap->ga_len
+ || fp->fd_top > bot)
+ {
+ /* 6: Found a fold below bot, can stop looking. */
+ break;
+ }
+ if (fp->fd_top >= top)
+ {
+ /* Found an entry below top. */
+ fold_changed = TRUE;
+ if (fp->fd_top + fp->fd_len - 1 > bot)
+ {
+ /* 5: Make fold that includes bot start below bot. */
+ foldMarkAdjustRecurse(&fp->fd_nested,
+ (linenr_T)0, (long)(bot - fp->fd_top),
+ (linenr_T)MAXLNUM, (long)(fp->fd_top - bot - 1));
+ fp->fd_len -= bot - fp->fd_top + 1;
+ fp->fd_top = bot + 1;
+ break;
+ }
+
+ /* 4: Delete completely contained fold. */
+ deleteFoldEntry(gap, (int)(fp - (fold_T *)gap->ga_data), TRUE);
+ }
+ }
+}
+
+/* foldReverseOrder() {{{2 */
+ static void
+foldReverseOrder(garray_T *gap, linenr_T start_arg, linenr_T end_arg)
+{
+ fold_T *left, *right;
+ fold_T tmp;
+ linenr_T start = start_arg;
+ linenr_T end = end_arg;
+
+ for (; start < end; start++, end--)
+ {
+ left = (fold_T *)gap->ga_data + start;
+ right = (fold_T *)gap->ga_data + end;
+ tmp = *left;
+ *left = *right;
+ *right = tmp;
+ }
+}
+
+/* foldMoveRange() {{{2 */
+/*
+ * Move folds within the inclusive range "line1" to "line2" to after "dest"
+ * requires "line1" <= "line2" <= "dest"
+ *
+ * There are the following situations for the first fold at or below line1 - 1.
+ * 1 2 3 4
+ * 1 2 3 4
+ * line1 2 3 4
+ * 2 3 4 5 6 7
+ * line2 3 4 5 6 7
+ * 3 4 6 7 8 9
+ * dest 4 7 8 9
+ * 4 7 8 10
+ * 4 7 8 10
+ *
+ * In the following descriptions, "moved" means moving in the buffer, *and* in
+ * the fold array.
+ * Meanwhile, "shifted" just means moving in the buffer.
+ * 1. not changed
+ * 2. truncated above line1
+ * 3. length reduced by line2 - line1, folds starting between the end of 3 and
+ * dest are truncated and shifted up
+ * 4. internal folds moved (from [line1, line2] to dest)
+ * 5. moved to dest.
+ * 6. truncated below line2 and moved.
+ * 7. length reduced by line2 - dest, folds starting between line2 and dest are
+ * removed, top is moved down by move_len.
+ * 8. truncated below dest and shifted up.
+ * 9. shifted up
+ * 10. not changed
+ */
+
+ static void
+truncate_fold(fold_T *fp, linenr_T end)
+{
+ end += 1;
+ foldRemove(&fp->fd_nested, end - fp->fd_top, MAXLNUM);
+ fp->fd_len = end - fp->fd_top;
+}
+
+#define fold_end(fp) ((fp)->fd_top + (fp)->fd_len - 1)
+#define valid_fold(fp, gap) ((fp) < ((fold_T *)(gap)->ga_data + (gap)->ga_len))
+#define fold_index(fp, gap) ((size_t)(fp - ((fold_T *)(gap)->ga_data)))
+
+ void
+foldMoveRange(garray_T *gap, linenr_T line1, linenr_T line2, linenr_T dest)
+{
+ fold_T *fp;
+ linenr_T range_len = line2 - line1 + 1;
+ linenr_T move_len = dest - line2;
+ int at_start = foldFind(gap, line1 - 1, &fp);
+ size_t move_start = 0, move_end = 0, dest_index = 0;
+
+ if (at_start)
+ {
+ if (fold_end(fp) > dest)
+ {
+ /* Case 4
+ * don't have to change this fold, but have to move nested folds.
+ */
+ foldMoveRange(&fp->fd_nested, line1 - fp->fd_top, line2 -
+ fp->fd_top, dest - fp->fd_top);
+ return;
+ }
+ else if (fold_end(fp) > line2)
+ {
+ /* Case 3
+ * Remove nested folds between line1 and line2 & reduce the
+ * length of fold by "range_len".
+ * Folds after this one must be dealt with.
+ */
+ foldMarkAdjustRecurse(&fp->fd_nested, line1 - fp->fd_top, line2 -
+ fp->fd_top, MAXLNUM, -range_len);
+ fp->fd_len -= range_len;
+ }
+ else
+ /* Case 2 truncate fold, folds after this one must be dealt with. */
+ truncate_fold(fp, line1 - 1);
+
+ /* Look at the next fold, and treat that one as if it were the first
+ * after "line1" (because now it is). */
+ fp = fp + 1;
+ }
+
+ if (!valid_fold(fp, gap) || fp->fd_top > dest)
+ {
+ /* Case 10
+ * No folds after "line1" and before "dest"
+ */
+ return;
+ }
+ else if (fp->fd_top > line2)
+ {
+ for (; valid_fold(fp, gap) && fold_end(fp) <= dest; fp++)
+ /* Case 9. (for all case 9's) -- shift up. */
+ fp->fd_top -= range_len;
+
+ if (valid_fold(fp, gap) && fp->fd_top <= dest)
+ {
+ /* Case 8. -- ensure truncated at dest, shift up */
+ truncate_fold(fp, dest);
+ fp->fd_top -= range_len;
+ }
+ return;
+ }
+ else if (fold_end(fp) > dest)
+ {
+ /* Case 7 -- remove nested folds and shrink */
+ foldMarkAdjustRecurse(&fp->fd_nested, line2 + 1 - fp->fd_top, dest -
+ fp->fd_top, MAXLNUM, -move_len);
+ fp->fd_len -= move_len;
+ fp->fd_top += move_len;
+ return;
+ }
+
+ /* Case 5 or 6
+ * changes rely on whether there are folds between the end of
+ * this fold and "dest".
+ */
+ move_start = fold_index(fp, gap);
+
+ for (; valid_fold(fp, gap) && fp->fd_top <= dest; fp++)
+ {
+ if (fp->fd_top <= line2)
+ {
+ /* 1. 2. or 3. */
+ if (fold_end(fp) > line2)
+ /* 2. or 3., truncate before moving */
+ truncate_fold(fp, line2);
+
+ fp->fd_top += move_len;
+ continue;
+ }
+
+ /* Record index of the first fold after the moved range. */
+ if (move_end == 0)
+ move_end = fold_index(fp, gap);
+
+ if (fold_end(fp) > dest)
+ truncate_fold(fp, dest);
+
+ fp->fd_top -= range_len;
+ }
+
+ dest_index = fold_index(fp, gap);
+
+ /*
+ * All folds are now correct, but not necessarily in the correct order. We
+ * must swap folds in the range [move_end, dest_index) with those in the
+ * range [move_start, move_end).
+ */
+ if (move_end == 0)
+ /* There are no folds after those moved, hence no folds have been moved
+ * out of order. */
+ return;
+ foldReverseOrder(gap, (linenr_T)move_start, (linenr_T)dest_index - 1);
+ foldReverseOrder(gap, (linenr_T)move_start,
+ (linenr_T)(move_start + dest_index - move_end - 1));
+ foldReverseOrder(gap, (linenr_T)(move_start + dest_index - move_end),
+ (linenr_T)(dest_index - 1));
+}
+#undef fold_end
+#undef valid_fold
+#undef fold_index
+
+/* foldMerge() {{{2 */
+/*
+ * Merge two adjacent folds (and the nested ones in them).
+ * This only works correctly when the folds are really adjacent! Thus "fp1"
+ * must end just above "fp2".
+ * The resulting fold is "fp1", nested folds are moved from "fp2" to "fp1".
+ * Fold entry "fp2" in "gap" is deleted.
+ */
+ static void
+foldMerge(fold_T *fp1, garray_T *gap, fold_T *fp2)
+{
+ fold_T *fp3;
+ fold_T *fp4;
+ int idx;
+ garray_T *gap1 = &fp1->fd_nested;
+ garray_T *gap2 = &fp2->fd_nested;
+
+ /* If the last nested fold in fp1 touches the first nested fold in fp2,
+ * merge them recursively. */
+ if (foldFind(gap1, fp1->fd_len - 1L, &fp3) && foldFind(gap2, 0L, &fp4))
+ foldMerge(fp3, gap2, fp4);
+
+ /* Move nested folds in fp2 to the end of fp1. */
+ if (gap2->ga_len > 0 && ga_grow(gap1, gap2->ga_len) == OK)
+ {
+ for (idx = 0; idx < gap2->ga_len; ++idx)
+ {
+ ((fold_T *)gap1->ga_data)[gap1->ga_len]
+ = ((fold_T *)gap2->ga_data)[idx];
+ ((fold_T *)gap1->ga_data)[gap1->ga_len].fd_top += fp1->fd_len;
+ ++gap1->ga_len;
+ }
+ gap2->ga_len = 0;
+ }
+
+ fp1->fd_len += fp2->fd_len;
+ deleteFoldEntry(gap, (int)(fp2 - (fold_T *)gap->ga_data), TRUE);
+ fold_changed = TRUE;
+}
+
+/* foldlevelIndent() {{{2 */
+/*
+ * Low level function to get the foldlevel for the "indent" method.
+ * Doesn't use any caching.
+ * Returns a level of -1 if the foldlevel depends on surrounding lines.
+ */
+ static void
+foldlevelIndent(fline_T *flp)
+{
+ char_u *s;
+ buf_T *buf;
+ linenr_T lnum = flp->lnum + flp->off;
+
+ buf = flp->wp->w_buffer;
+ s = skipwhite(ml_get_buf(buf, lnum, FALSE));
+
+ /* empty line or lines starting with a character in 'foldignore': level
+ * depends on surrounding lines */
+ if (*s == NUL || vim_strchr(flp->wp->w_p_fdi, *s) != NULL)
+ {
+ /* first and last line can't be undefined, use level 0 */
+ if (lnum == 1 || lnum == buf->b_ml.ml_line_count)
+ flp->lvl = 0;
+ else
+ flp->lvl = -1;
+ }
+ else
+ flp->lvl = get_indent_buf(buf, lnum) / get_sw_value(buf);
+ if (flp->lvl > flp->wp->w_p_fdn)
+ {
+ flp->lvl = flp->wp->w_p_fdn;
+ if (flp->lvl < 0)
+ flp->lvl = 0;
+ }
+}
+
+/* foldlevelDiff() {{{2 */
+#ifdef FEAT_DIFF
+/*
+ * Low level function to get the foldlevel for the "diff" method.
+ * Doesn't use any caching.
+ */
+ static void
+foldlevelDiff(fline_T *flp)
+{
+ if (diff_infold(flp->wp, flp->lnum + flp->off))
+ flp->lvl = 1;
+ else
+ flp->lvl = 0;
+}
+#endif
+
+/* foldlevelExpr() {{{2 */
+/*
+ * Low level function to get the foldlevel for the "expr" method.
+ * Doesn't use any caching.
+ * Returns a level of -1 if the foldlevel depends on surrounding lines.
+ */
+ static void
+foldlevelExpr(fline_T *flp)
+{
+#ifndef FEAT_EVAL
+ flp->start = FALSE;
+ flp->lvl = 0;
+#else
+ win_T *win;
+ int n;
+ int c;
+ linenr_T lnum = flp->lnum + flp->off;
+ int save_keytyped;
+
+ win = curwin;
+ curwin = flp->wp;
+ curbuf = flp->wp->w_buffer;
+ set_vim_var_nr(VV_LNUM, lnum);
+
+ flp->start = 0;
+ flp->had_end = flp->end;
+ flp->end = MAX_LEVEL + 1;
+ if (lnum <= 1)
+ flp->lvl = 0;
+
+ /* KeyTyped may be reset to 0 when calling a function which invokes
+ * do_cmdline(). To make 'foldopen' work correctly restore KeyTyped. */
+ save_keytyped = KeyTyped;
+ n = (int)eval_foldexpr(flp->wp->w_p_fde, &c);
+ KeyTyped = save_keytyped;
+
+ switch (c)
+ {
+ /* "a1", "a2", .. : add to the fold level */
+ case 'a': if (flp->lvl >= 0)
+ {
+ flp->lvl += n;
+ flp->lvl_next = flp->lvl;
+ }
+ flp->start = n;
+ break;
+
+ /* "s1", "s2", .. : subtract from the fold level */
+ case 's': if (flp->lvl >= 0)
+ {
+ if (n > flp->lvl)
+ flp->lvl_next = 0;
+ else
+ flp->lvl_next = flp->lvl - n;
+ flp->end = flp->lvl_next + 1;
+ }
+ break;
+
+ /* ">1", ">2", .. : start a fold with a certain level */
+ case '>': flp->lvl = n;
+ flp->lvl_next = n;
+ flp->start = 1;
+ break;
+
+ /* "<1", "<2", .. : end a fold with a certain level */
+ case '<': flp->lvl_next = n - 1;
+ flp->end = n;
+ break;
+
+ /* "=": No change in level */
+ case '=': flp->lvl_next = flp->lvl;
+ break;
+
+ /* "-1", "0", "1", ..: set fold level */
+ default: if (n < 0)
+ /* Use the current level for the next line, so that "a1"
+ * will work there. */
+ flp->lvl_next = flp->lvl;
+ else
+ flp->lvl_next = n;
+ flp->lvl = n;
+ break;
+ }
+
+ /* If the level is unknown for the first or the last line in the file, use
+ * level 0. */
+ if (flp->lvl < 0)
+ {
+ if (lnum <= 1)
+ {
+ flp->lvl = 0;
+ flp->lvl_next = 0;
+ }
+ if (lnum == curbuf->b_ml.ml_line_count)
+ flp->lvl_next = 0;
+ }
+
+ curwin = win;
+ curbuf = curwin->w_buffer;
+#endif
+}
+
+/* parseMarker() {{{2 */
+/*
+ * Parse 'foldmarker' and set "foldendmarker", "foldstartmarkerlen" and
+ * "foldendmarkerlen".
+ * Relies on the option value to have been checked for correctness already.
+ */
+ static void
+parseMarker(win_T *wp)
+{
+ foldendmarker = vim_strchr(wp->w_p_fmr, ',');
+ foldstartmarkerlen = (int)(foldendmarker++ - wp->w_p_fmr);
+ foldendmarkerlen = (int)STRLEN(foldendmarker);
+}
+
+/* foldlevelMarker() {{{2 */
+/*
+ * Low level function to get the foldlevel for the "marker" method.
+ * "foldendmarker", "foldstartmarkerlen" and "foldendmarkerlen" must have been
+ * set before calling this.
+ * Requires that flp->lvl is set to the fold level of the previous line!
+ * Careful: This means you can't call this function twice on the same line.
+ * Doesn't use any caching.
+ * Sets flp->start when a start marker was found.
+ */
+ static void
+foldlevelMarker(fline_T *flp)
+{
+ char_u *startmarker;
+ int cstart;
+ int cend;
+ int start_lvl = flp->lvl;
+ char_u *s;
+ int n;
+
+ /* cache a few values for speed */
+ startmarker = flp->wp->w_p_fmr;
+ cstart = *startmarker;
+ ++startmarker;
+ cend = *foldendmarker;
+
+ /* Default: no start found, next level is same as current level */
+ flp->start = 0;
+ flp->lvl_next = flp->lvl;
+
+ s = ml_get_buf(flp->wp->w_buffer, flp->lnum + flp->off, FALSE);
+ while (*s)
+ {
+ if (*s == cstart
+ && STRNCMP(s + 1, startmarker, foldstartmarkerlen - 1) == 0)
+ {
+ /* found startmarker: set flp->lvl */
+ s += foldstartmarkerlen;
+ if (VIM_ISDIGIT(*s))
+ {
+ n = atoi((char *)s);
+ if (n > 0)
+ {
+ flp->lvl = n;
+ flp->lvl_next = n;
+ if (n <= start_lvl)
+ flp->start = 1;
+ else
+ flp->start = n - start_lvl;
+ }
+ }
+ else
+ {
+ ++flp->lvl;
+ ++flp->lvl_next;
+ ++flp->start;
+ }
+ }
+ else if (*s == cend
+ && STRNCMP(s + 1, foldendmarker + 1, foldendmarkerlen - 1) == 0)
+ {
+ /* found endmarker: set flp->lvl_next */
+ s += foldendmarkerlen;
+ if (VIM_ISDIGIT(*s))
+ {
+ n = atoi((char *)s);
+ if (n > 0)
+ {
+ flp->lvl = n;
+ flp->lvl_next = n - 1;
+ /* never start a fold with an end marker */
+ if (flp->lvl_next > start_lvl)
+ flp->lvl_next = start_lvl;
+ }
+ }
+ else
+ --flp->lvl_next;
+ }
+ else
+ MB_PTR_ADV(s);
+ }
+
+ /* The level can't go negative, must be missing a start marker. */
+ if (flp->lvl_next < 0)
+ flp->lvl_next = 0;
+}
+
+/* foldlevelSyntax() {{{2 */
+/*
+ * Low level function to get the foldlevel for the "syntax" method.
+ * Doesn't use any caching.
+ */
+ static void
+foldlevelSyntax(fline_T *flp)
+{
+#ifndef FEAT_SYN_HL
+ flp->start = 0;
+ flp->lvl = 0;
+#else
+ linenr_T lnum = flp->lnum + flp->off;
+ int n;
+
+ /* Use the maximum fold level at the start of this line and the next. */
+ flp->lvl = syn_get_foldlevel(flp->wp, lnum);
+ flp->start = 0;
+ if (lnum < flp->wp->w_buffer->b_ml.ml_line_count)
+ {
+ n = syn_get_foldlevel(flp->wp, lnum + 1);
+ if (n > flp->lvl)
+ {
+ flp->start = n - flp->lvl; /* fold(s) start here */
+ flp->lvl = n;
+ }
+ }
+#endif
+}
+
+/* functions for storing the fold state in a View {{{1 */
+/* put_folds() {{{2 */
+#if defined(FEAT_SESSION) || defined(PROTO)
+static int put_folds_recurse(FILE *fd, garray_T *gap, linenr_T off);
+static int put_foldopen_recurse(FILE *fd, win_T *wp, garray_T *gap, linenr_T off);
+static int put_fold_open_close(FILE *fd, fold_T *fp, linenr_T off);
+
+/*
+ * Write commands to "fd" to restore the manual folds in window "wp".
+ * Return FAIL if writing fails.
+ */
+ int
+put_folds(FILE *fd, win_T *wp)
+{
+ if (foldmethodIsManual(wp))
+ {
+ if (put_line(fd, "silent! normal! zE") == FAIL
+ || put_folds_recurse(fd, &wp->w_folds, (linenr_T)0) == FAIL)
+ return FAIL;
+ }
+
+ /* If some folds are manually opened/closed, need to restore that. */
+ if (wp->w_fold_manual)
+ return put_foldopen_recurse(fd, wp, &wp->w_folds, (linenr_T)0);
+
+ return OK;
+}
+
+/* put_folds_recurse() {{{2 */
+/*
+ * Write commands to "fd" to recreate manually created folds.
+ * Returns FAIL when writing failed.
+ */
+ static int
+put_folds_recurse(FILE *fd, garray_T *gap, linenr_T off)
+{
+ int i;
+ fold_T *fp;
+
+ fp = (fold_T *)gap->ga_data;
+ for (i = 0; i < gap->ga_len; i++)
+ {
+ /* Do nested folds first, they will be created closed. */
+ if (put_folds_recurse(fd, &fp->fd_nested, off + fp->fd_top) == FAIL)
+ return FAIL;
+ if (fprintf(fd, "%ld,%ldfold", fp->fd_top + off,
+ fp->fd_top + off + fp->fd_len - 1) < 0
+ || put_eol(fd) == FAIL)
+ return FAIL;
+ ++fp;
+ }
+ return OK;
+}
+
+/* put_foldopen_recurse() {{{2 */
+/*
+ * Write commands to "fd" to open and close manually opened/closed folds.
+ * Returns FAIL when writing failed.
+ */
+ static int
+put_foldopen_recurse(
+ FILE *fd,
+ win_T *wp,
+ garray_T *gap,
+ linenr_T off)
+{
+ int i;
+ int level;
+ fold_T *fp;
+
+ fp = (fold_T *)gap->ga_data;
+ for (i = 0; i < gap->ga_len; i++)
+ {
+ if (fp->fd_flags != FD_LEVEL)
+ {
+ if (fp->fd_nested.ga_len > 0)
+ {
+ /* open nested folds while this fold is open */
+ if (fprintf(fd, "%ld", fp->fd_top + off) < 0
+ || put_eol(fd) == FAIL
+ || put_line(fd, "normal! zo") == FAIL)
+ return FAIL;
+ if (put_foldopen_recurse(fd, wp, &fp->fd_nested,
+ off + fp->fd_top)
+ == FAIL)
+ return FAIL;
+ /* close the parent when needed */
+ if (fp->fd_flags == FD_CLOSED)
+ {
+ if (put_fold_open_close(fd, fp, off) == FAIL)
+ return FAIL;
+ }
+ }
+ else
+ {
+ /* Open or close the leaf according to the window foldlevel.
+ * Do not close a leaf that is already closed, as it will close
+ * the parent. */
+ level = foldLevelWin(wp, off + fp->fd_top);
+ if ((fp->fd_flags == FD_CLOSED && wp->w_p_fdl >= level)
+ || (fp->fd_flags != FD_CLOSED && wp->w_p_fdl < level))
+ if (put_fold_open_close(fd, fp, off) == FAIL)
+ return FAIL;
+ }
+ }
+ ++fp;
+ }
+
+ return OK;
+}
+
+/* put_fold_open_close() {{{2 */
+/*
+ * Write the open or close command to "fd".
+ * Returns FAIL when writing failed.
+ */
+ static int
+put_fold_open_close(FILE *fd, fold_T *fp, linenr_T off)
+{
+ if (fprintf(fd, "%ld", fp->fd_top + off) < 0
+ || put_eol(fd) == FAIL
+ || fprintf(fd, "normal! z%c",
+ fp->fd_flags == FD_CLOSED ? 'c' : 'o') < 0
+ || put_eol(fd) == FAIL)
+ return FAIL;
+
+ return OK;
+}
+#endif /* FEAT_SESSION */
+
+/* }}}1 */
+#endif /* defined(FEAT_FOLDING) || defined(PROTO) */
diff --git a/src/getchar.c b/src/getchar.c
new file mode 100644
index 0000000..fe74dbf
--- /dev/null
+++ b/src/getchar.c
@@ -0,0 +1,5323 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * getchar.c
+ *
+ * functions related with getting a character from the user/mapping/redo/...
+ *
+ * manipulations with redo buffer and stuff buffer
+ * mappings and abbreviations
+ */
+
+#include "vim.h"
+
+/*
+ * These buffers are used for storing:
+ * - stuffed characters: A command that is translated into another command.
+ * - redo characters: will redo the last change.
+ * - recorded characters: for the "q" command.
+ *
+ * The bytes are stored like in the typeahead buffer:
+ * - K_SPECIAL introduces a special key (two more bytes follow). A literal
+ * K_SPECIAL is stored as K_SPECIAL KS_SPECIAL KE_FILLER.
+ * - CSI introduces a GUI termcap code (also when gui.in_use is FALSE,
+ * otherwise switching the GUI on would make mappings invalid).
+ * A literal CSI is stored as CSI KS_EXTRA KE_CSI.
+ * These translations are also done on multi-byte characters!
+ *
+ * Escaping CSI bytes is done by the system-specific input functions, called
+ * by ui_inchar().
+ * Escaping K_SPECIAL is done by inchar().
+ * Un-escaping is done by vgetc().
+ */
+
+#define MINIMAL_SIZE 20 /* minimal size for b_str */
+
+static buffheader_T redobuff = {{NULL, {NUL}}, NULL, 0, 0};
+static buffheader_T old_redobuff = {{NULL, {NUL}}, NULL, 0, 0};
+static buffheader_T recordbuff = {{NULL, {NUL}}, NULL, 0, 0};
+
+static int typeahead_char = 0; /* typeahead char that's not flushed */
+
+/*
+ * when block_redo is TRUE redo buffer will not be changed
+ * used by edit() to repeat insertions and 'V' command for redoing
+ */
+static int block_redo = FALSE;
+
+/*
+ * Make a hash value for a mapping.
+ * "mode" is the lower 4 bits of the State for the mapping.
+ * "c1" is the first character of the "lhs".
+ * Returns a value between 0 and 255, index in maphash.
+ * Put Normal/Visual mode mappings mostly separately from Insert/Cmdline mode.
+ */
+#define MAP_HASH(mode, c1) (((mode) & (NORMAL + VISUAL + SELECTMODE + OP_PENDING + TERMINAL)) ? (c1) : ((c1) ^ 0x80))
+
+/*
+ * Each mapping is put in one of the 256 hash lists, to speed up finding it.
+ */
+static mapblock_T *(maphash[256]);
+static int maphash_valid = FALSE;
+
+/*
+ * List used for abbreviations.
+ */
+static mapblock_T *first_abbr = NULL; /* first entry in abbrlist */
+
+static int KeyNoremap = 0; /* remapping flags */
+
+/*
+ * Variables used by vgetorpeek() and flush_buffers().
+ *
+ * typebuf.tb_buf[] contains all characters that are not consumed yet.
+ * typebuf.tb_buf[typebuf.tb_off] is the first valid character.
+ * typebuf.tb_buf[typebuf.tb_off + typebuf.tb_len - 1] is the last valid char.
+ * typebuf.tb_buf[typebuf.tb_off + typebuf.tb_len] must be NUL.
+ * The head of the buffer may contain the result of mappings, abbreviations
+ * and @a commands. The length of this part is typebuf.tb_maplen.
+ * typebuf.tb_silent is the part where <silent> applies.
+ * After the head are characters that come from the terminal.
+ * typebuf.tb_no_abbr_cnt is the number of characters in typebuf.tb_buf that
+ * should not be considered for abbreviations.
+ * Some parts of typebuf.tb_buf may not be mapped. These parts are remembered
+ * in typebuf.tb_noremap[], which is the same length as typebuf.tb_buf and
+ * contains RM_NONE for the characters that are not to be remapped.
+ * typebuf.tb_noremap[typebuf.tb_off] is the first valid flag.
+ * (typebuf has been put in globals.h, because check_termcode() needs it).
+ */
+#define RM_YES 0 /* tb_noremap: remap */
+#define RM_NONE 1 /* tb_noremap: don't remap */
+#define RM_SCRIPT 2 /* tb_noremap: remap local script mappings */
+#define RM_ABBR 4 /* tb_noremap: don't remap, do abbrev. */
+
+/* typebuf.tb_buf has three parts: room in front (for result of mappings), the
+ * middle for typeahead and room for new characters (which needs to be 3 *
+ * MAXMAPLEN) for the Amiga).
+ */
+#define TYPELEN_INIT (5 * (MAXMAPLEN + 3))
+static char_u typebuf_init[TYPELEN_INIT]; /* initial typebuf.tb_buf */
+static char_u noremapbuf_init[TYPELEN_INIT]; /* initial typebuf.tb_noremap */
+
+static int last_recorded_len = 0; /* number of last recorded chars */
+
+static int read_readbuf(buffheader_T *buf, int advance);
+static void init_typebuf(void);
+static void may_sync_undo(void);
+static void closescript(void);
+static int vgetorpeek(int);
+static void map_free(mapblock_T **);
+static void validate_maphash(void);
+static void showmap(mapblock_T *mp, int local);
+static int inchar(char_u *buf, int maxlen, long wait_time);
+#ifdef FEAT_EVAL
+static char_u *eval_map_expr(char_u *str, int c);
+#endif
+
+/*
+ * Free and clear a buffer.
+ */
+ void
+free_buff(buffheader_T *buf)
+{
+ buffblock_T *p, *np;
+
+ for (p = buf->bh_first.b_next; p != NULL; p = np)
+ {
+ np = p->b_next;
+ vim_free(p);
+ }
+ buf->bh_first.b_next = NULL;
+}
+
+/*
+ * Return the contents of a buffer as a single string.
+ * K_SPECIAL and CSI in the returned string are escaped.
+ */
+ static char_u *
+get_buffcont(
+ buffheader_T *buffer,
+ int dozero) /* count == zero is not an error */
+{
+ long_u count = 0;
+ char_u *p = NULL;
+ char_u *p2;
+ char_u *str;
+ buffblock_T *bp;
+
+ /* compute the total length of the string */
+ for (bp = buffer->bh_first.b_next; bp != NULL; bp = bp->b_next)
+ count += (long_u)STRLEN(bp->b_str);
+
+ if ((count || dozero) && (p = lalloc(count + 1, TRUE)) != NULL)
+ {
+ p2 = p;
+ for (bp = buffer->bh_first.b_next; bp != NULL; bp = bp->b_next)
+ for (str = bp->b_str; *str; )
+ *p2++ = *str++;
+ *p2 = NUL;
+ }
+ return (p);
+}
+
+/*
+ * Return the contents of the record buffer as a single string
+ * and clear the record buffer.
+ * K_SPECIAL and CSI in the returned string are escaped.
+ */
+ char_u *
+get_recorded(void)
+{
+ char_u *p;
+ size_t len;
+
+ p = get_buffcont(&recordbuff, TRUE);
+ free_buff(&recordbuff);
+
+ /*
+ * Remove the characters that were added the last time, these must be the
+ * (possibly mapped) characters that stopped the recording.
+ */
+ len = STRLEN(p);
+ if ((int)len >= last_recorded_len)
+ {
+ len -= last_recorded_len;
+ p[len] = NUL;
+ }
+
+ /*
+ * When stopping recording from Insert mode with CTRL-O q, also remove the
+ * CTRL-O.
+ */
+ if (len > 0 && restart_edit != 0 && p[len - 1] == Ctrl_O)
+ p[len - 1] = NUL;
+
+ return (p);
+}
+
+/*
+ * Return the contents of the redo buffer as a single string.
+ * K_SPECIAL and CSI in the returned string are escaped.
+ */
+ char_u *
+get_inserted(void)
+{
+ return get_buffcont(&redobuff, FALSE);
+}
+
+/*
+ * Add string "s" after the current block of buffer "buf".
+ * K_SPECIAL and CSI should have been escaped already.
+ */
+ static void
+add_buff(
+ buffheader_T *buf,
+ char_u *s,
+ long slen) /* length of "s" or -1 */
+{
+ buffblock_T *p;
+ long_u len;
+
+ if (slen < 0)
+ slen = (long)STRLEN(s);
+ if (slen == 0) /* don't add empty strings */
+ return;
+
+ if (buf->bh_first.b_next == NULL) /* first add to list */
+ {
+ buf->bh_space = 0;
+ buf->bh_curr = &(buf->bh_first);
+ }
+ else if (buf->bh_curr == NULL) /* buffer has already been read */
+ {
+ iemsg(_("E222: Add to read buffer"));
+ return;
+ }
+ else if (buf->bh_index != 0)
+ mch_memmove(buf->bh_first.b_next->b_str,
+ buf->bh_first.b_next->b_str + buf->bh_index,
+ STRLEN(buf->bh_first.b_next->b_str + buf->bh_index) + 1);
+ buf->bh_index = 0;
+
+ if (buf->bh_space >= (int)slen)
+ {
+ len = (long_u)STRLEN(buf->bh_curr->b_str);
+ vim_strncpy(buf->bh_curr->b_str + len, s, (size_t)slen);
+ buf->bh_space -= slen;
+ }
+ else
+ {
+ if (slen < MINIMAL_SIZE)
+ len = MINIMAL_SIZE;
+ else
+ len = slen;
+ p = (buffblock_T *)lalloc((long_u)(sizeof(buffblock_T) + len),
+ TRUE);
+ if (p == NULL)
+ return; /* no space, just forget it */
+ buf->bh_space = (int)(len - slen);
+ vim_strncpy(p->b_str, s, (size_t)slen);
+
+ p->b_next = buf->bh_curr->b_next;
+ buf->bh_curr->b_next = p;
+ buf->bh_curr = p;
+ }
+ return;
+}
+
+/*
+ * Add number "n" to buffer "buf".
+ */
+ static void
+add_num_buff(buffheader_T *buf, long n)
+{
+ char_u number[32];
+
+ sprintf((char *)number, "%ld", n);
+ add_buff(buf, number, -1L);
+}
+
+/*
+ * Add character 'c' to buffer "buf".
+ * Translates special keys, NUL, CSI, K_SPECIAL and multibyte characters.
+ */
+ static void
+add_char_buff(buffheader_T *buf, int c)
+{
+ char_u bytes[MB_MAXBYTES + 1];
+ int len;
+ int i;
+ char_u temp[4];
+
+ if (IS_SPECIAL(c))
+ len = 1;
+ else
+ len = (*mb_char2bytes)(c, bytes);
+ for (i = 0; i < len; ++i)
+ {
+ if (!IS_SPECIAL(c))
+ c = bytes[i];
+
+ if (IS_SPECIAL(c) || c == K_SPECIAL || c == NUL)
+ {
+ /* translate special key code into three byte sequence */
+ temp[0] = K_SPECIAL;
+ temp[1] = K_SECOND(c);
+ temp[2] = K_THIRD(c);
+ temp[3] = NUL;
+ }
+#ifdef FEAT_GUI
+ else if (c == CSI)
+ {
+ /* Translate a CSI to a CSI - KS_EXTRA - KE_CSI sequence */
+ temp[0] = CSI;
+ temp[1] = KS_EXTRA;
+ temp[2] = (int)KE_CSI;
+ temp[3] = NUL;
+ }
+#endif
+ else
+ {
+ temp[0] = c;
+ temp[1] = NUL;
+ }
+ add_buff(buf, temp, -1L);
+ }
+}
+
+/* First read ahead buffer. Used for translated commands. */
+static buffheader_T readbuf1 = {{NULL, {NUL}}, NULL, 0, 0};
+
+/* Second read ahead buffer. Used for redo. */
+static buffheader_T readbuf2 = {{NULL, {NUL}}, NULL, 0, 0};
+
+/*
+ * Get one byte from the read buffers. Use readbuf1 one first, use readbuf2
+ * if that one is empty.
+ * If advance == TRUE go to the next char.
+ * No translation is done K_SPECIAL and CSI are escaped.
+ */
+ static int
+read_readbuffers(int advance)
+{
+ int c;
+
+ c = read_readbuf(&readbuf1, advance);
+ if (c == NUL)
+ c = read_readbuf(&readbuf2, advance);
+ return c;
+}
+
+ static int
+read_readbuf(buffheader_T *buf, int advance)
+{
+ char_u c;
+ buffblock_T *curr;
+
+ if (buf->bh_first.b_next == NULL) /* buffer is empty */
+ return NUL;
+
+ curr = buf->bh_first.b_next;
+ c = curr->b_str[buf->bh_index];
+
+ if (advance)
+ {
+ if (curr->b_str[++buf->bh_index] == NUL)
+ {
+ buf->bh_first.b_next = curr->b_next;
+ vim_free(curr);
+ buf->bh_index = 0;
+ }
+ }
+ return c;
+}
+
+/*
+ * Prepare the read buffers for reading (if they contain something).
+ */
+ static void
+start_stuff(void)
+{
+ if (readbuf1.bh_first.b_next != NULL)
+ {
+ readbuf1.bh_curr = &(readbuf1.bh_first);
+ readbuf1.bh_space = 0;
+ }
+ if (readbuf2.bh_first.b_next != NULL)
+ {
+ readbuf2.bh_curr = &(readbuf2.bh_first);
+ readbuf2.bh_space = 0;
+ }
+}
+
+/*
+ * Return TRUE if the stuff buffer is empty.
+ */
+ int
+stuff_empty(void)
+{
+ return (readbuf1.bh_first.b_next == NULL
+ && readbuf2.bh_first.b_next == NULL);
+}
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * Return TRUE if readbuf1 is empty. There may still be redo characters in
+ * redbuf2.
+ */
+ int
+readbuf1_empty(void)
+{
+ return (readbuf1.bh_first.b_next == NULL);
+}
+#endif
+
+/*
+ * Set a typeahead character that won't be flushed.
+ */
+ void
+typeahead_noflush(int c)
+{
+ typeahead_char = c;
+}
+
+/*
+ * Remove the contents of the stuff buffer and the mapped characters in the
+ * typeahead buffer (used in case of an error). If "flush_typeahead" is true,
+ * flush all typeahead characters (used when interrupted by a CTRL-C).
+ */
+ void
+flush_buffers(flush_buffers_T flush_typeahead)
+{
+ init_typebuf();
+
+ start_stuff();
+ while (read_readbuffers(TRUE) != NUL)
+ ;
+
+ if (flush_typeahead == FLUSH_MINIMAL)
+ {
+ // remove mapped characters at the start only
+ typebuf.tb_off += typebuf.tb_maplen;
+ typebuf.tb_len -= typebuf.tb_maplen;
+ }
+ else
+ {
+ // remove typeahead
+ if (flush_typeahead == FLUSH_INPUT)
+ // We have to get all characters, because we may delete the first
+ // part of an escape sequence. In an xterm we get one char at a
+ // time and we have to get them all.
+ while (inchar(typebuf.tb_buf, typebuf.tb_buflen - 1, 10L) != 0)
+ ;
+ typebuf.tb_off = MAXMAPLEN;
+ typebuf.tb_len = 0;
+#if defined(FEAT_CLIENTSERVER) || defined(FEAT_EVAL)
+ /* Reset the flag that text received from a client or from feedkeys()
+ * was inserted in the typeahead buffer. */
+ typebuf_was_filled = FALSE;
+#endif
+ }
+ typebuf.tb_maplen = 0;
+ typebuf.tb_silent = 0;
+ cmd_silent = FALSE;
+ typebuf.tb_no_abbr_cnt = 0;
+}
+
+/*
+ * The previous contents of the redo buffer is kept in old_redobuffer.
+ * This is used for the CTRL-O <.> command in insert mode.
+ */
+ void
+ResetRedobuff(void)
+{
+ if (!block_redo)
+ {
+ free_buff(&old_redobuff);
+ old_redobuff = redobuff;
+ redobuff.bh_first.b_next = NULL;
+ }
+}
+
+/*
+ * Discard the contents of the redo buffer and restore the previous redo
+ * buffer.
+ */
+ void
+CancelRedo(void)
+{
+ if (!block_redo)
+ {
+ free_buff(&redobuff);
+ redobuff = old_redobuff;
+ old_redobuff.bh_first.b_next = NULL;
+ start_stuff();
+ while (read_readbuffers(TRUE) != NUL)
+ ;
+ }
+}
+
+/*
+ * Save redobuff and old_redobuff to save_redobuff and save_old_redobuff.
+ * Used before executing autocommands and user functions.
+ */
+ void
+saveRedobuff(save_redo_T *save_redo)
+{
+ char_u *s;
+
+ save_redo->sr_redobuff = redobuff;
+ redobuff.bh_first.b_next = NULL;
+ save_redo->sr_old_redobuff = old_redobuff;
+ old_redobuff.bh_first.b_next = NULL;
+
+ /* Make a copy, so that ":normal ." in a function works. */
+ s = get_buffcont(&save_redo->sr_redobuff, FALSE);
+ if (s != NULL)
+ {
+ add_buff(&redobuff, s, -1L);
+ vim_free(s);
+ }
+}
+
+/*
+ * Restore redobuff and old_redobuff from save_redobuff and save_old_redobuff.
+ * Used after executing autocommands and user functions.
+ */
+ void
+restoreRedobuff(save_redo_T *save_redo)
+{
+ free_buff(&redobuff);
+ redobuff = save_redo->sr_redobuff;
+ free_buff(&old_redobuff);
+ old_redobuff = save_redo->sr_old_redobuff;
+}
+
+/*
+ * Append "s" to the redo buffer.
+ * K_SPECIAL and CSI should already have been escaped.
+ */
+ void
+AppendToRedobuff(char_u *s)
+{
+ if (!block_redo)
+ add_buff(&redobuff, s, -1L);
+}
+
+/*
+ * Append to Redo buffer literally, escaping special characters with CTRL-V.
+ * K_SPECIAL and CSI are escaped as well.
+ */
+ void
+AppendToRedobuffLit(
+ char_u *str,
+ int len) /* length of "str" or -1 for up to the NUL */
+{
+ char_u *s = str;
+ int c;
+ char_u *start;
+
+ if (block_redo)
+ return;
+
+ while (len < 0 ? *s != NUL : s - str < len)
+ {
+ /* Put a string of normal characters in the redo buffer (that's
+ * faster). */
+ start = s;
+ while (*s >= ' '
+#ifndef EBCDIC
+ && *s < DEL /* EBCDIC: all chars above space are normal */
+#endif
+ && (len < 0 || s - str < len))
+ ++s;
+
+ /* Don't put '0' or '^' as last character, just in case a CTRL-D is
+ * typed next. */
+ if (*s == NUL && (s[-1] == '0' || s[-1] == '^'))
+ --s;
+ if (s > start)
+ add_buff(&redobuff, start, (long)(s - start));
+
+ if (*s == NUL || (len >= 0 && s - str >= len))
+ break;
+
+ /* Handle a special or multibyte character. */
+ if (has_mbyte)
+ /* Handle composing chars separately. */
+ c = mb_cptr2char_adv(&s);
+ else
+ c = *s++;
+ if (c < ' ' || c == DEL || (*s == NUL && (c == '0' || c == '^')))
+ add_char_buff(&redobuff, Ctrl_V);
+
+ /* CTRL-V '0' must be inserted as CTRL-V 048 (EBCDIC: xf0) */
+ if (*s == NUL && c == '0')
+#ifdef EBCDIC
+ add_buff(&redobuff, (char_u *)"xf0", 3L);
+#else
+ add_buff(&redobuff, (char_u *)"048", 3L);
+#endif
+ else
+ add_char_buff(&redobuff, c);
+ }
+}
+
+/*
+ * Append a character to the redo buffer.
+ * Translates special keys, NUL, CSI, K_SPECIAL and multibyte characters.
+ */
+ void
+AppendCharToRedobuff(int c)
+{
+ if (!block_redo)
+ add_char_buff(&redobuff, c);
+}
+
+/*
+ * Append a number to the redo buffer.
+ */
+ void
+AppendNumberToRedobuff(long n)
+{
+ if (!block_redo)
+ add_num_buff(&redobuff, n);
+}
+
+/*
+ * Append string "s" to the stuff buffer.
+ * CSI and K_SPECIAL must already have been escaped.
+ */
+ void
+stuffReadbuff(char_u *s)
+{
+ add_buff(&readbuf1, s, -1L);
+}
+
+/*
+ * Append string "s" to the redo stuff buffer.
+ * CSI and K_SPECIAL must already have been escaped.
+ */
+ void
+stuffRedoReadbuff(char_u *s)
+{
+ add_buff(&readbuf2, s, -1L);
+}
+
+ void
+stuffReadbuffLen(char_u *s, long len)
+{
+ add_buff(&readbuf1, s, len);
+}
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * Stuff "s" into the stuff buffer, leaving special key codes unmodified and
+ * escaping other K_SPECIAL and CSI bytes.
+ * Change CR, LF and ESC into a space.
+ */
+ void
+stuffReadbuffSpec(char_u *s)
+{
+ int c;
+
+ while (*s != NUL)
+ {
+ if (*s == K_SPECIAL && s[1] != NUL && s[2] != NUL)
+ {
+ /* Insert special key literally. */
+ stuffReadbuffLen(s, 3L);
+ s += 3;
+ }
+ else
+ {
+ c = mb_ptr2char_adv(&s);
+ if (c == CAR || c == NL || c == ESC)
+ c = ' ';
+ stuffcharReadbuff(c);
+ }
+ }
+}
+#endif
+
+/*
+ * Append a character to the stuff buffer.
+ * Translates special keys, NUL, CSI, K_SPECIAL and multibyte characters.
+ */
+ void
+stuffcharReadbuff(int c)
+{
+ add_char_buff(&readbuf1, c);
+}
+
+/*
+ * Append a number to the stuff buffer.
+ */
+ void
+stuffnumReadbuff(long n)
+{
+ add_num_buff(&readbuf1, n);
+}
+
+/*
+ * Read a character from the redo buffer. Translates K_SPECIAL, CSI and
+ * multibyte characters.
+ * The redo buffer is left as it is.
+ * If init is TRUE, prepare for redo, return FAIL if nothing to redo, OK
+ * otherwise.
+ * If old is TRUE, use old_redobuff instead of redobuff.
+ */
+ static int
+read_redo(int init, int old_redo)
+{
+ static buffblock_T *bp;
+ static char_u *p;
+ int c;
+ int n;
+ char_u buf[MB_MAXBYTES + 1];
+ int i;
+
+ if (init)
+ {
+ if (old_redo)
+ bp = old_redobuff.bh_first.b_next;
+ else
+ bp = redobuff.bh_first.b_next;
+ if (bp == NULL)
+ return FAIL;
+ p = bp->b_str;
+ return OK;
+ }
+ if ((c = *p) != NUL)
+ {
+ /* Reverse the conversion done by add_char_buff() */
+ /* For a multi-byte character get all the bytes and return the
+ * converted character. */
+ if (has_mbyte && (c != K_SPECIAL || p[1] == KS_SPECIAL))
+ n = MB_BYTE2LEN_CHECK(c);
+ else
+ n = 1;
+ for (i = 0; ; ++i)
+ {
+ if (c == K_SPECIAL) /* special key or escaped K_SPECIAL */
+ {
+ c = TO_SPECIAL(p[1], p[2]);
+ p += 2;
+ }
+#ifdef FEAT_GUI
+ if (c == CSI) /* escaped CSI */
+ p += 2;
+#endif
+ if (*++p == NUL && bp->b_next != NULL)
+ {
+ bp = bp->b_next;
+ p = bp->b_str;
+ }
+ buf[i] = c;
+ if (i == n - 1) /* last byte of a character */
+ {
+ if (n != 1)
+ c = (*mb_ptr2char)(buf);
+ break;
+ }
+ c = *p;
+ if (c == NUL) /* cannot happen? */
+ break;
+ }
+ }
+
+ return c;
+}
+
+/*
+ * Copy the rest of the redo buffer into the stuff buffer (in a slow way).
+ * If old_redo is TRUE, use old_redobuff instead of redobuff.
+ * The escaped K_SPECIAL and CSI are copied without translation.
+ */
+ static void
+copy_redo(int old_redo)
+{
+ int c;
+
+ while ((c = read_redo(FALSE, old_redo)) != NUL)
+ add_char_buff(&readbuf2, c);
+}
+
+/*
+ * Stuff the redo buffer into readbuf2.
+ * Insert the redo count into the command.
+ * If "old_redo" is TRUE, the last but one command is repeated
+ * instead of the last command (inserting text). This is used for
+ * CTRL-O <.> in insert mode
+ *
+ * return FAIL for failure, OK otherwise
+ */
+ int
+start_redo(long count, int old_redo)
+{
+ int c;
+
+ /* init the pointers; return if nothing to redo */
+ if (read_redo(TRUE, old_redo) == FAIL)
+ return FAIL;
+
+ c = read_redo(FALSE, old_redo);
+
+ /* copy the buffer name, if present */
+ if (c == '"')
+ {
+ add_buff(&readbuf2, (char_u *)"\"", 1L);
+ c = read_redo(FALSE, old_redo);
+
+ /* if a numbered buffer is used, increment the number */
+ if (c >= '1' && c < '9')
+ ++c;
+ add_char_buff(&readbuf2, c);
+
+ /* the expression register should be re-evaluated */
+ if (c == '=')
+ {
+ add_char_buff(&readbuf2, CAR);
+ cmd_silent = TRUE;
+ }
+
+ c = read_redo(FALSE, old_redo);
+ }
+
+ if (c == 'v') /* redo Visual */
+ {
+ VIsual = curwin->w_cursor;
+ VIsual_active = TRUE;
+ VIsual_select = FALSE;
+ VIsual_reselect = TRUE;
+ redo_VIsual_busy = TRUE;
+ c = read_redo(FALSE, old_redo);
+ }
+
+ /* try to enter the count (in place of a previous count) */
+ if (count)
+ {
+ while (VIM_ISDIGIT(c)) /* skip "old" count */
+ c = read_redo(FALSE, old_redo);
+ add_num_buff(&readbuf2, count);
+ }
+
+ /* copy from the redo buffer into the stuff buffer */
+ add_char_buff(&readbuf2, c);
+ copy_redo(old_redo);
+ return OK;
+}
+
+/*
+ * Repeat the last insert (R, o, O, a, A, i or I command) by stuffing
+ * the redo buffer into readbuf2.
+ * return FAIL for failure, OK otherwise
+ */
+ int
+start_redo_ins(void)
+{
+ int c;
+
+ if (read_redo(TRUE, FALSE) == FAIL)
+ return FAIL;
+ start_stuff();
+
+ /* skip the count and the command character */
+ while ((c = read_redo(FALSE, FALSE)) != NUL)
+ {
+ if (vim_strchr((char_u *)"AaIiRrOo", c) != NULL)
+ {
+ if (c == 'O' || c == 'o')
+ add_buff(&readbuf2, NL_STR, -1L);
+ break;
+ }
+ }
+
+ /* copy the typed text from the redo buffer into the stuff buffer */
+ copy_redo(FALSE);
+ block_redo = TRUE;
+ return OK;
+}
+
+ void
+stop_redo_ins(void)
+{
+ block_redo = FALSE;
+}
+
+/*
+ * Initialize typebuf.tb_buf to point to typebuf_init.
+ * alloc() cannot be used here: In out-of-memory situations it would
+ * be impossible to type anything.
+ */
+ static void
+init_typebuf(void)
+{
+ if (typebuf.tb_buf == NULL)
+ {
+ typebuf.tb_buf = typebuf_init;
+ typebuf.tb_noremap = noremapbuf_init;
+ typebuf.tb_buflen = TYPELEN_INIT;
+ typebuf.tb_len = 0;
+ typebuf.tb_off = MAXMAPLEN + 4;
+ typebuf.tb_change_cnt = 1;
+ }
+}
+
+/*
+ * Insert a string in position 'offset' in the typeahead buffer (for "@r"
+ * and ":normal" command, vgetorpeek() and check_termcode()).
+ *
+ * If noremap is REMAP_YES, new string can be mapped again.
+ * If noremap is REMAP_NONE, new string cannot be mapped again.
+ * If noremap is REMAP_SKIP, fist char of new string cannot be mapped again,
+ * but abbreviations are allowed.
+ * If noremap is REMAP_SCRIPT, new string cannot be mapped again, except for
+ * script-local mappings.
+ * If noremap is > 0, that many characters of the new string cannot be mapped.
+ *
+ * If nottyped is TRUE, the string does not return KeyTyped (don't use when
+ * offset is non-zero!).
+ *
+ * If silent is TRUE, cmd_silent is set when the characters are obtained.
+ *
+ * return FAIL for failure, OK otherwise
+ */
+ int
+ins_typebuf(
+ char_u *str,
+ int noremap,
+ int offset,
+ int nottyped,
+ int silent)
+{
+ char_u *s1, *s2;
+ int newlen;
+ int addlen;
+ int i;
+ int newoff;
+ int val;
+ int nrm;
+
+ init_typebuf();
+ if (++typebuf.tb_change_cnt == 0)
+ typebuf.tb_change_cnt = 1;
+
+ addlen = (int)STRLEN(str);
+
+ if (offset == 0 && addlen <= typebuf.tb_off)
+ {
+ /*
+ * Easy case: there is room in front of typebuf.tb_buf[typebuf.tb_off]
+ */
+ typebuf.tb_off -= addlen;
+ mch_memmove(typebuf.tb_buf + typebuf.tb_off, str, (size_t)addlen);
+ }
+ else if (typebuf.tb_len == 0 && typebuf.tb_buflen
+ >= addlen + 3 * (MAXMAPLEN + 4))
+ {
+ /*
+ * Buffer is empty and string fits in the existing buffer.
+ * Leave some space before and after, if possible.
+ */
+ typebuf.tb_off = (typebuf.tb_buflen - addlen - 3 * (MAXMAPLEN + 4)) / 2;
+ mch_memmove(typebuf.tb_buf + typebuf.tb_off, str, (size_t)addlen);
+ }
+ else
+ {
+ /*
+ * Need to allocate a new buffer.
+ * In typebuf.tb_buf there must always be room for 3 * (MAXMAPLEN + 4)
+ * characters. We add some extra room to avoid having to allocate too
+ * often.
+ */
+ newoff = MAXMAPLEN + 4;
+ newlen = typebuf.tb_len + addlen + newoff + 4 * (MAXMAPLEN + 4);
+ if (newlen < 0) /* string is getting too long */
+ {
+ emsg(_(e_toocompl)); /* also calls flush_buffers */
+ setcursor();
+ return FAIL;
+ }
+ s1 = alloc(newlen);
+ if (s1 == NULL) /* out of memory */
+ return FAIL;
+ s2 = alloc(newlen);
+ if (s2 == NULL) /* out of memory */
+ {
+ vim_free(s1);
+ return FAIL;
+ }
+ typebuf.tb_buflen = newlen;
+
+ /* copy the old chars, before the insertion point */
+ mch_memmove(s1 + newoff, typebuf.tb_buf + typebuf.tb_off,
+ (size_t)offset);
+ /* copy the new chars */
+ mch_memmove(s1 + newoff + offset, str, (size_t)addlen);
+ /* copy the old chars, after the insertion point, including the NUL at
+ * the end */
+ mch_memmove(s1 + newoff + offset + addlen,
+ typebuf.tb_buf + typebuf.tb_off + offset,
+ (size_t)(typebuf.tb_len - offset + 1));
+ if (typebuf.tb_buf != typebuf_init)
+ vim_free(typebuf.tb_buf);
+ typebuf.tb_buf = s1;
+
+ mch_memmove(s2 + newoff, typebuf.tb_noremap + typebuf.tb_off,
+ (size_t)offset);
+ mch_memmove(s2 + newoff + offset + addlen,
+ typebuf.tb_noremap + typebuf.tb_off + offset,
+ (size_t)(typebuf.tb_len - offset));
+ if (typebuf.tb_noremap != noremapbuf_init)
+ vim_free(typebuf.tb_noremap);
+ typebuf.tb_noremap = s2;
+
+ typebuf.tb_off = newoff;
+ }
+ typebuf.tb_len += addlen;
+
+ /* If noremap == REMAP_SCRIPT: do remap script-local mappings. */
+ if (noremap == REMAP_SCRIPT)
+ val = RM_SCRIPT;
+ else if (noremap == REMAP_SKIP)
+ val = RM_ABBR;
+ else
+ val = RM_NONE;
+
+ /*
+ * Adjust typebuf.tb_noremap[] for the new characters:
+ * If noremap == REMAP_NONE or REMAP_SCRIPT: new characters are
+ * (sometimes) not remappable
+ * If noremap == REMAP_YES: all the new characters are mappable
+ * If noremap > 0: "noremap" characters are not remappable, the rest
+ * mappable
+ */
+ if (noremap == REMAP_SKIP)
+ nrm = 1;
+ else if (noremap < 0)
+ nrm = addlen;
+ else
+ nrm = noremap;
+ for (i = 0; i < addlen; ++i)
+ typebuf.tb_noremap[typebuf.tb_off + i + offset] =
+ (--nrm >= 0) ? val : RM_YES;
+
+ /* tb_maplen and tb_silent only remember the length of mapped and/or
+ * silent mappings at the start of the buffer, assuming that a mapped
+ * sequence doesn't result in typed characters. */
+ if (nottyped || typebuf.tb_maplen > offset)
+ typebuf.tb_maplen += addlen;
+ if (silent || typebuf.tb_silent > offset)
+ {
+ typebuf.tb_silent += addlen;
+ cmd_silent = TRUE;
+ }
+ if (typebuf.tb_no_abbr_cnt && offset == 0) /* and not used for abbrev.s */
+ typebuf.tb_no_abbr_cnt += addlen;
+
+ return OK;
+}
+
+/*
+ * Put character "c" back into the typeahead buffer.
+ * Can be used for a character obtained by vgetc() that needs to be put back.
+ * Uses cmd_silent, KeyTyped and KeyNoremap to restore the flags belonging to
+ * the char.
+ */
+ void
+ins_char_typebuf(int c)
+{
+ char_u buf[MB_MAXBYTES + 1];
+ if (IS_SPECIAL(c))
+ {
+ buf[0] = K_SPECIAL;
+ buf[1] = K_SECOND(c);
+ buf[2] = K_THIRD(c);
+ buf[3] = NUL;
+ }
+ else
+ buf[(*mb_char2bytes)(c, buf)] = NUL;
+ (void)ins_typebuf(buf, KeyNoremap, 0, !KeyTyped, cmd_silent);
+}
+
+/*
+ * Return TRUE if the typeahead buffer was changed (while waiting for a
+ * character to arrive). Happens when a message was received from a client or
+ * from feedkeys().
+ * But check in a more generic way to avoid trouble: When "typebuf.tb_buf"
+ * changed it was reallocated and the old pointer can no longer be used.
+ * Or "typebuf.tb_off" may have been changed and we would overwrite characters
+ * that was just added.
+ */
+ int
+typebuf_changed(
+ int tb_change_cnt) /* old value of typebuf.tb_change_cnt */
+{
+ return (tb_change_cnt != 0 && (typebuf.tb_change_cnt != tb_change_cnt
+#if defined(FEAT_CLIENTSERVER) || defined(FEAT_EVAL)
+ || typebuf_was_filled
+#endif
+ ));
+}
+
+/*
+ * Return TRUE if there are no characters in the typeahead buffer that have
+ * not been typed (result from a mapping or come from ":normal").
+ */
+ int
+typebuf_typed(void)
+{
+ return typebuf.tb_maplen == 0;
+}
+
+/*
+ * Return the number of characters that are mapped (or not typed).
+ */
+ int
+typebuf_maplen(void)
+{
+ return typebuf.tb_maplen;
+}
+
+/*
+ * remove "len" characters from typebuf.tb_buf[typebuf.tb_off + offset]
+ */
+ void
+del_typebuf(int len, int offset)
+{
+ int i;
+
+ if (len == 0)
+ return; /* nothing to do */
+
+ typebuf.tb_len -= len;
+
+ /*
+ * Easy case: Just increase typebuf.tb_off.
+ */
+ if (offset == 0 && typebuf.tb_buflen - (typebuf.tb_off + len)
+ >= 3 * MAXMAPLEN + 3)
+ typebuf.tb_off += len;
+ /*
+ * Have to move the characters in typebuf.tb_buf[] and typebuf.tb_noremap[]
+ */
+ else
+ {
+ i = typebuf.tb_off + offset;
+ /*
+ * Leave some extra room at the end to avoid reallocation.
+ */
+ if (typebuf.tb_off > MAXMAPLEN)
+ {
+ mch_memmove(typebuf.tb_buf + MAXMAPLEN,
+ typebuf.tb_buf + typebuf.tb_off, (size_t)offset);
+ mch_memmove(typebuf.tb_noremap + MAXMAPLEN,
+ typebuf.tb_noremap + typebuf.tb_off, (size_t)offset);
+ typebuf.tb_off = MAXMAPLEN;
+ }
+ /* adjust typebuf.tb_buf (include the NUL at the end) */
+ mch_memmove(typebuf.tb_buf + typebuf.tb_off + offset,
+ typebuf.tb_buf + i + len,
+ (size_t)(typebuf.tb_len - offset + 1));
+ /* adjust typebuf.tb_noremap[] */
+ mch_memmove(typebuf.tb_noremap + typebuf.tb_off + offset,
+ typebuf.tb_noremap + i + len,
+ (size_t)(typebuf.tb_len - offset));
+ }
+
+ if (typebuf.tb_maplen > offset) /* adjust tb_maplen */
+ {
+ if (typebuf.tb_maplen < offset + len)
+ typebuf.tb_maplen = offset;
+ else
+ typebuf.tb_maplen -= len;
+ }
+ if (typebuf.tb_silent > offset) /* adjust tb_silent */
+ {
+ if (typebuf.tb_silent < offset + len)
+ typebuf.tb_silent = offset;
+ else
+ typebuf.tb_silent -= len;
+ }
+ if (typebuf.tb_no_abbr_cnt > offset) /* adjust tb_no_abbr_cnt */
+ {
+ if (typebuf.tb_no_abbr_cnt < offset + len)
+ typebuf.tb_no_abbr_cnt = offset;
+ else
+ typebuf.tb_no_abbr_cnt -= len;
+ }
+
+#if defined(FEAT_CLIENTSERVER) || defined(FEAT_EVAL)
+ /* Reset the flag that text received from a client or from feedkeys()
+ * was inserted in the typeahead buffer. */
+ typebuf_was_filled = FALSE;
+#endif
+ if (++typebuf.tb_change_cnt == 0)
+ typebuf.tb_change_cnt = 1;
+}
+
+/*
+ * Write typed characters to script file.
+ * If recording is on put the character in the recordbuffer.
+ */
+ static void
+gotchars(char_u *chars, int len)
+{
+ char_u *s = chars;
+ int i;
+ static char_u buf[4];
+ static int buflen = 0;
+ int todo = len;
+
+ while (todo--)
+ {
+ buf[buflen++] = *s++;
+
+ // When receiving a special key sequence, store it until we have all
+ // the bytes and we can decide what to do with it.
+ if (buflen == 1 && buf[0] == K_SPECIAL)
+ continue;
+ if (buflen == 2)
+ continue;
+ if (buflen == 3 && buf[1] == KS_EXTRA
+ && (buf[2] == KE_FOCUSGAINED || buf[2] == KE_FOCUSLOST))
+ {
+ // Drop K_FOCUSGAINED and K_FOCUSLOST, they are not useful in a
+ // recording.
+ buflen = 0;
+ continue;
+ }
+
+ /* Handle one byte at a time; no translation to be done. */
+ for (i = 0; i < buflen; ++i)
+ updatescript(buf[i]);
+
+ if (reg_recording != 0)
+ {
+ buf[buflen] = NUL;
+ add_buff(&recordbuff, buf, (long)buflen);
+ /* remember how many chars were last recorded */
+ last_recorded_len += buflen;
+ }
+ buflen = 0;
+ }
+ may_sync_undo();
+
+#ifdef FEAT_EVAL
+ /* output "debug mode" message next time in debug mode */
+ debug_did_msg = FALSE;
+#endif
+
+ /* Since characters have been typed, consider the following to be in
+ * another mapping. Search string will be kept in history. */
+ ++maptick;
+}
+
+/*
+ * Sync undo. Called when typed characters are obtained from the typeahead
+ * buffer, or when a menu is used.
+ * Do not sync:
+ * - In Insert mode, unless cursor key has been used.
+ * - While reading a script file.
+ * - When no_u_sync is non-zero.
+ */
+ static void
+may_sync_undo(void)
+{
+ if ((!(State & (INSERT + CMDLINE)) || arrow_used)
+ && scriptin[curscript] == NULL)
+ u_sync(FALSE);
+}
+
+/*
+ * Make "typebuf" empty and allocate new buffers.
+ * Returns FAIL when out of memory.
+ */
+ int
+alloc_typebuf(void)
+{
+ typebuf.tb_buf = alloc(TYPELEN_INIT);
+ typebuf.tb_noremap = alloc(TYPELEN_INIT);
+ if (typebuf.tb_buf == NULL || typebuf.tb_noremap == NULL)
+ {
+ free_typebuf();
+ return FAIL;
+ }
+ typebuf.tb_buflen = TYPELEN_INIT;
+ typebuf.tb_off = MAXMAPLEN + 4; /* can insert without realloc */
+ typebuf.tb_len = 0;
+ typebuf.tb_maplen = 0;
+ typebuf.tb_silent = 0;
+ typebuf.tb_no_abbr_cnt = 0;
+ if (++typebuf.tb_change_cnt == 0)
+ typebuf.tb_change_cnt = 1;
+ return OK;
+}
+
+/*
+ * Free the buffers of "typebuf".
+ */
+ void
+free_typebuf(void)
+{
+ if (typebuf.tb_buf == typebuf_init)
+ internal_error("Free typebuf 1");
+ else
+ vim_free(typebuf.tb_buf);
+ if (typebuf.tb_noremap == noremapbuf_init)
+ internal_error("Free typebuf 2");
+ else
+ vim_free(typebuf.tb_noremap);
+}
+
+/*
+ * When doing ":so! file", the current typeahead needs to be saved, and
+ * restored when "file" has been read completely.
+ */
+static typebuf_T saved_typebuf[NSCRIPT];
+
+ int
+save_typebuf(void)
+{
+ init_typebuf();
+ saved_typebuf[curscript] = typebuf;
+ /* If out of memory: restore typebuf and close file. */
+ if (alloc_typebuf() == FAIL)
+ {
+ closescript();
+ return FAIL;
+ }
+ return OK;
+}
+
+static int old_char = -1; /* character put back by vungetc() */
+static int old_mod_mask; /* mod_mask for ungotten character */
+#ifdef FEAT_MOUSE
+static int old_mouse_row; /* mouse_row related to old_char */
+static int old_mouse_col; /* mouse_col related to old_char */
+#endif
+
+/*
+ * Save all three kinds of typeahead, so that the user must type at a prompt.
+ */
+ void
+save_typeahead(tasave_T *tp)
+{
+ tp->save_typebuf = typebuf;
+ tp->typebuf_valid = (alloc_typebuf() == OK);
+ if (!tp->typebuf_valid)
+ typebuf = tp->save_typebuf;
+
+ tp->old_char = old_char;
+ tp->old_mod_mask = old_mod_mask;
+ old_char = -1;
+
+ tp->save_readbuf1 = readbuf1;
+ readbuf1.bh_first.b_next = NULL;
+ tp->save_readbuf2 = readbuf2;
+ readbuf2.bh_first.b_next = NULL;
+# ifdef USE_INPUT_BUF
+ tp->save_inputbuf = get_input_buf();
+# endif
+}
+
+/*
+ * Restore the typeahead to what it was before calling save_typeahead().
+ * The allocated memory is freed, can only be called once!
+ */
+ void
+restore_typeahead(tasave_T *tp)
+{
+ if (tp->typebuf_valid)
+ {
+ free_typebuf();
+ typebuf = tp->save_typebuf;
+ }
+
+ old_char = tp->old_char;
+ old_mod_mask = tp->old_mod_mask;
+
+ free_buff(&readbuf1);
+ readbuf1 = tp->save_readbuf1;
+ free_buff(&readbuf2);
+ readbuf2 = tp->save_readbuf2;
+# ifdef USE_INPUT_BUF
+ set_input_buf(tp->save_inputbuf);
+# endif
+}
+
+/*
+ * Open a new script file for the ":source!" command.
+ */
+ void
+openscript(
+ char_u *name,
+ int directly) /* when TRUE execute directly */
+{
+ if (curscript + 1 == NSCRIPT)
+ {
+ emsg(_(e_nesting));
+ return;
+ }
+#ifdef FEAT_EVAL
+ if (ignore_script)
+ /* Not reading from script, also don't open one. Warning message? */
+ return;
+#endif
+
+ if (scriptin[curscript] != NULL) /* already reading script */
+ ++curscript;
+ /* use NameBuff for expanded name */
+ expand_env(name, NameBuff, MAXPATHL);
+ if ((scriptin[curscript] = mch_fopen((char *)NameBuff, READBIN)) == NULL)
+ {
+ semsg(_(e_notopen), name);
+ if (curscript)
+ --curscript;
+ return;
+ }
+ if (save_typebuf() == FAIL)
+ return;
+
+ /*
+ * Execute the commands from the file right now when using ":source!"
+ * after ":global" or ":argdo" or in a loop. Also when another command
+ * follows. This means the display won't be updated. Don't do this
+ * always, "make test" would fail.
+ */
+ if (directly)
+ {
+ oparg_T oa;
+ int oldcurscript;
+ int save_State = State;
+ int save_restart_edit = restart_edit;
+ int save_insertmode = p_im;
+ int save_finish_op = finish_op;
+ int save_msg_scroll = msg_scroll;
+
+ State = NORMAL;
+ msg_scroll = FALSE; /* no msg scrolling in Normal mode */
+ restart_edit = 0; /* don't go to Insert mode */
+ p_im = FALSE; /* don't use 'insertmode' */
+ clear_oparg(&oa);
+ finish_op = FALSE;
+
+ oldcurscript = curscript;
+ do
+ {
+ update_topline_cursor(); /* update cursor position and topline */
+ normal_cmd(&oa, FALSE); /* execute one command */
+ vpeekc(); /* check for end of file */
+ }
+ while (scriptin[oldcurscript] != NULL);
+
+ State = save_State;
+ msg_scroll = save_msg_scroll;
+ restart_edit = save_restart_edit;
+ p_im = save_insertmode;
+ finish_op = save_finish_op;
+ }
+}
+
+/*
+ * Close the currently active input script.
+ */
+ static void
+closescript(void)
+{
+ free_typebuf();
+ typebuf = saved_typebuf[curscript];
+
+ fclose(scriptin[curscript]);
+ scriptin[curscript] = NULL;
+ if (curscript > 0)
+ --curscript;
+}
+
+#if defined(EXITFREE) || defined(PROTO)
+ void
+close_all_scripts(void)
+{
+ while (scriptin[0] != NULL)
+ closescript();
+}
+#endif
+
+#if defined(FEAT_INS_EXPAND) || defined(PROTO)
+/*
+ * Return TRUE when reading keys from a script file.
+ */
+ int
+using_script(void)
+{
+ return scriptin[curscript] != NULL;
+}
+#endif
+
+/*
+ * This function is called just before doing a blocking wait. Thus after
+ * waiting 'updatetime' for a character to arrive.
+ */
+ void
+before_blocking(void)
+{
+ updatescript(0);
+#ifdef FEAT_EVAL
+ if (may_garbage_collect)
+ garbage_collect(FALSE);
+#endif
+}
+
+/*
+ * updatescipt() is called when a character can be written into the script file
+ * or when we have waited some time for a character (c == 0)
+ *
+ * All the changed memfiles are synced if c == 0 or when the number of typed
+ * characters reaches 'updatecount' and 'updatecount' is non-zero.
+ */
+ void
+updatescript(int c)
+{
+ static int count = 0;
+
+ if (c && scriptout)
+ putc(c, scriptout);
+ if (c == 0 || (p_uc > 0 && ++count >= p_uc))
+ {
+ ml_sync_all(c == 0, TRUE);
+ count = 0;
+ }
+}
+
+/*
+ * Get the next input character.
+ * Can return a special key or a multi-byte character.
+ * Can return NUL when called recursively, use safe_vgetc() if that's not
+ * wanted.
+ * This translates escaped K_SPECIAL and CSI bytes to a K_SPECIAL or CSI byte.
+ * Collects the bytes of a multibyte character into the whole character.
+ * Returns the modifiers in the global "mod_mask".
+ */
+ int
+vgetc(void)
+{
+ int c, c2;
+ int n;
+ char_u buf[MB_MAXBYTES + 1];
+ int i;
+
+#ifdef FEAT_EVAL
+ /* Do garbage collection when garbagecollect() was called previously and
+ * we are now at the toplevel. */
+ if (may_garbage_collect && want_garbage_collect)
+ garbage_collect(FALSE);
+#endif
+
+ /*
+ * If a character was put back with vungetc, it was already processed.
+ * Return it directly.
+ */
+ if (old_char != -1)
+ {
+ c = old_char;
+ old_char = -1;
+ mod_mask = old_mod_mask;
+#ifdef FEAT_MOUSE
+ mouse_row = old_mouse_row;
+ mouse_col = old_mouse_col;
+#endif
+ }
+ else
+ {
+ mod_mask = 0x0;
+ last_recorded_len = 0;
+ for (;;) /* this is done twice if there are modifiers */
+ {
+ int did_inc = FALSE;
+
+ if (mod_mask
+#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
+ || im_is_preediting()
+#endif
+ )
+ {
+ /* no mapping after modifier has been read */
+ ++no_mapping;
+ ++allow_keys;
+ did_inc = TRUE; /* mod_mask may change value */
+ }
+ c = vgetorpeek(TRUE);
+ if (did_inc)
+ {
+ --no_mapping;
+ --allow_keys;
+ }
+
+ /* Get two extra bytes for special keys */
+ if (c == K_SPECIAL
+#ifdef FEAT_GUI
+ || c == CSI
+#endif
+ )
+ {
+ int save_allow_keys = allow_keys;
+
+ ++no_mapping;
+ allow_keys = 0; /* make sure BS is not found */
+ c2 = vgetorpeek(TRUE); /* no mapping for these chars */
+ c = vgetorpeek(TRUE);
+ --no_mapping;
+ allow_keys = save_allow_keys;
+ if (c2 == KS_MODIFIER)
+ {
+ mod_mask = c;
+ continue;
+ }
+ c = TO_SPECIAL(c2, c);
+
+#if defined(FEAT_GUI_W32) && defined(FEAT_MENU) && defined(FEAT_TEAROFF)
+ /* Handle K_TEAROFF here, the caller of vgetc() doesn't need to
+ * know that a menu was torn off */
+ if (c == K_TEAROFF)
+ {
+ char_u name[200];
+ int i;
+
+ /* get menu path, it ends with a <CR> */
+ for (i = 0; (c = vgetorpeek(TRUE)) != '\r'; )
+ {
+ name[i] = c;
+ if (i < 199)
+ ++i;
+ }
+ name[i] = NUL;
+ gui_make_tearoff(name);
+ continue;
+ }
+#endif
+#if defined(FEAT_GUI) && defined(FEAT_GUI_GTK) && defined(FEAT_MENU)
+ /* GTK: <F10> normally selects the menu, but it's passed until
+ * here to allow mapping it. Intercept and invoke the GTK
+ * behavior if it's not mapped. */
+ if (c == K_F10 && gui.menubar != NULL)
+ {
+ gtk_menu_shell_select_first(GTK_MENU_SHELL(gui.menubar), FALSE);
+ continue;
+ }
+#endif
+#ifdef FEAT_GUI
+ /* Handle focus event here, so that the caller doesn't need to
+ * know about it. Return K_IGNORE so that we loop once (needed if
+ * 'lazyredraw' is set). */
+ if (c == K_FOCUSGAINED || c == K_FOCUSLOST)
+ {
+ ui_focus_change(c == K_FOCUSGAINED);
+ c = K_IGNORE;
+ }
+
+ /* Translate K_CSI to CSI. The special key is only used to avoid
+ * it being recognized as the start of a special key. */
+ if (c == K_CSI)
+ c = CSI;
+#endif
+ }
+ /* a keypad or special function key was not mapped, use it like
+ * its ASCII equivalent */
+ switch (c)
+ {
+ case K_KPLUS: c = '+'; break;
+ case K_KMINUS: c = '-'; break;
+ case K_KDIVIDE: c = '/'; break;
+ case K_KMULTIPLY: c = '*'; break;
+ case K_KENTER: c = CAR; break;
+ case K_KPOINT:
+#ifdef WIN32
+ // Can be either '.' or a ',',
+ // depending on the type of keypad.
+ c = MapVirtualKey(VK_DECIMAL, 2); break;
+#else
+ c = '.'; break;
+#endif
+ case K_K0: c = '0'; break;
+ case K_K1: c = '1'; break;
+ case K_K2: c = '2'; break;
+ case K_K3: c = '3'; break;
+ case K_K4: c = '4'; break;
+ case K_K5: c = '5'; break;
+ case K_K6: c = '6'; break;
+ case K_K7: c = '7'; break;
+ case K_K8: c = '8'; break;
+ case K_K9: c = '9'; break;
+
+ case K_XHOME:
+ case K_ZHOME: if (mod_mask == MOD_MASK_SHIFT)
+ {
+ c = K_S_HOME;
+ mod_mask = 0;
+ }
+ else if (mod_mask == MOD_MASK_CTRL)
+ {
+ c = K_C_HOME;
+ mod_mask = 0;
+ }
+ else
+ c = K_HOME;
+ break;
+ case K_XEND:
+ case K_ZEND: if (mod_mask == MOD_MASK_SHIFT)
+ {
+ c = K_S_END;
+ mod_mask = 0;
+ }
+ else if (mod_mask == MOD_MASK_CTRL)
+ {
+ c = K_C_END;
+ mod_mask = 0;
+ }
+ else
+ c = K_END;
+ break;
+
+ case K_XUP: c = K_UP; break;
+ case K_XDOWN: c = K_DOWN; break;
+ case K_XLEFT: c = K_LEFT; break;
+ case K_XRIGHT: c = K_RIGHT; break;
+ }
+
+ /* For a multi-byte character get all the bytes and return the
+ * converted character.
+ * Note: This will loop until enough bytes are received!
+ */
+ if (has_mbyte && (n = MB_BYTE2LEN_CHECK(c)) > 1)
+ {
+ ++no_mapping;
+ buf[0] = c;
+ for (i = 1; i < n; ++i)
+ {
+ buf[i] = vgetorpeek(TRUE);
+ if (buf[i] == K_SPECIAL
+#ifdef FEAT_GUI
+ || buf[i] == CSI
+#endif
+ )
+ {
+ /* Must be a K_SPECIAL - KS_SPECIAL - KE_FILLER sequence,
+ * which represents a K_SPECIAL (0x80),
+ * or a CSI - KS_EXTRA - KE_CSI sequence, which represents
+ * a CSI (0x9B),
+ * of a K_SPECIAL - KS_EXTRA - KE_CSI, which is CSI too. */
+ c = vgetorpeek(TRUE);
+ if (vgetorpeek(TRUE) == (int)KE_CSI && c == KS_EXTRA)
+ buf[i] = CSI;
+ }
+ }
+ --no_mapping;
+ c = (*mb_ptr2char)(buf);
+ }
+
+ break;
+ }
+ }
+
+#ifdef FEAT_EVAL
+ /*
+ * In the main loop "may_garbage_collect" can be set to do garbage
+ * collection in the first next vgetc(). It's disabled after that to
+ * avoid internally used Lists and Dicts to be freed.
+ */
+ may_garbage_collect = FALSE;
+#endif
+#ifdef FEAT_BEVAL_TERM
+ if (c != K_MOUSEMOVE && c != K_IGNORE)
+ {
+ /* Don't trigger 'balloonexpr' unless only the mouse was moved. */
+ bevalexpr_due_set = FALSE;
+ ui_remove_balloon();
+ }
+#endif
+
+ return c;
+}
+
+/*
+ * Like vgetc(), but never return a NUL when called recursively, get a key
+ * directly from the user (ignoring typeahead).
+ */
+ int
+safe_vgetc(void)
+{
+ int c;
+
+ c = vgetc();
+ if (c == NUL)
+ c = get_keystroke();
+ return c;
+}
+
+/*
+ * Like safe_vgetc(), but loop to handle K_IGNORE.
+ * Also ignore scrollbar events.
+ */
+ int
+plain_vgetc(void)
+{
+ int c;
+
+ do
+ {
+ c = safe_vgetc();
+ } while (c == K_IGNORE || c == K_VER_SCROLLBAR || c == K_HOR_SCROLLBAR);
+
+ if (c == K_PS)
+ /* Only handle the first pasted character. Drop the rest, since we
+ * don't know what to do with it. */
+ c = bracketed_paste(PASTE_ONE_CHAR, FALSE, NULL);
+
+ return c;
+}
+
+/*
+ * Check if a character is available, such that vgetc() will not block.
+ * If the next character is a special character or multi-byte, the returned
+ * character is not valid!.
+ * Returns NUL if no character is available.
+ */
+ int
+vpeekc(void)
+{
+ if (old_char != -1)
+ return old_char;
+ return vgetorpeek(FALSE);
+}
+
+#if defined(FEAT_TERMRESPONSE) || defined(FEAT_TERMINAL) || defined(PROTO)
+/*
+ * Like vpeekc(), but don't allow mapping. Do allow checking for terminal
+ * codes.
+ */
+ int
+vpeekc_nomap(void)
+{
+ int c;
+
+ ++no_mapping;
+ ++allow_keys;
+ c = vpeekc();
+ --no_mapping;
+ --allow_keys;
+ return c;
+}
+#endif
+
+#if defined(FEAT_INS_EXPAND) || defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * Check if any character is available, also half an escape sequence.
+ * Trick: when no typeahead found, but there is something in the typeahead
+ * buffer, it must be an ESC that is recognized as the start of a key code.
+ */
+ int
+vpeekc_any(void)
+{
+ int c;
+
+ c = vpeekc();
+ if (c == NUL && typebuf.tb_len > 0)
+ c = ESC;
+ return c;
+}
+#endif
+
+/*
+ * Call vpeekc() without causing anything to be mapped.
+ * Return TRUE if a character is available, FALSE otherwise.
+ */
+ int
+char_avail(void)
+{
+ int retval;
+
+#ifdef FEAT_EVAL
+ /* When test_override("char_avail", 1) was called pretend there is no
+ * typeahead. */
+ if (disable_char_avail_for_testing)
+ return FALSE;
+#endif
+ ++no_mapping;
+ retval = vpeekc();
+ --no_mapping;
+ return (retval != NUL);
+}
+
+/*
+ * unget one character (can only be done once!)
+ */
+ void
+vungetc(int c)
+{
+ old_char = c;
+ old_mod_mask = mod_mask;
+#ifdef FEAT_MOUSE
+ old_mouse_row = mouse_row;
+ old_mouse_col = mouse_col;
+#endif
+}
+
+/*
+ * Get a byte:
+ * 1. from the stuffbuffer
+ * This is used for abbreviated commands like "D" -> "d$".
+ * Also used to redo a command for ".".
+ * 2. from the typeahead buffer
+ * Stores text obtained previously but not used yet.
+ * Also stores the result of mappings.
+ * Also used for the ":normal" command.
+ * 3. from the user
+ * This may do a blocking wait if "advance" is TRUE.
+ *
+ * if "advance" is TRUE (vgetc()):
+ * Really get the character.
+ * KeyTyped is set to TRUE in the case the user typed the key.
+ * KeyStuffed is TRUE if the character comes from the stuff buffer.
+ * if "advance" is FALSE (vpeekc()):
+ * Just look whether there is a character available.
+ * Return NUL if not.
+ *
+ * When "no_mapping" is zero, checks for mappings in the current mode.
+ * Only returns one byte (of a multi-byte character).
+ * K_SPECIAL and CSI may be escaped, need to get two more bytes then.
+ */
+ static int
+vgetorpeek(int advance)
+{
+ int c, c1;
+ int keylen;
+ char_u *s;
+ mapblock_T *mp;
+#ifdef FEAT_LOCALMAP
+ mapblock_T *mp2;
+#endif
+ mapblock_T *mp_match;
+ int mp_match_len = 0;
+ int timedout = FALSE; /* waited for more than 1 second
+ for mapping to complete */
+ int mapdepth = 0; /* check for recursive mapping */
+ int mode_deleted = FALSE; /* set when mode has been deleted */
+ int local_State;
+ int mlen;
+ int max_mlen;
+ int i;
+#ifdef FEAT_CMDL_INFO
+ int new_wcol, new_wrow;
+#endif
+#ifdef FEAT_GUI
+# ifdef FEAT_MENU
+ int idx;
+# endif
+ int shape_changed = FALSE; /* adjusted cursor shape */
+#endif
+ int n;
+#ifdef FEAT_LANGMAP
+ int nolmaplen;
+#endif
+ int old_wcol, old_wrow;
+ int wait_tb_len;
+
+ /*
+ * This function doesn't work very well when called recursively. This may
+ * happen though, because of:
+ * 1. The call to add_to_showcmd(). char_avail() is then used to check if
+ * there is a character available, which calls this function. In that
+ * case we must return NUL, to indicate no character is available.
+ * 2. A GUI callback function writes to the screen, causing a
+ * wait_return().
+ * Using ":normal" can also do this, but it saves the typeahead buffer,
+ * thus it should be OK. But don't get a key from the user then.
+ */
+ if (vgetc_busy > 0 && ex_normal_busy == 0)
+ return NUL;
+
+ local_State = get_real_state();
+
+ ++vgetc_busy;
+
+ if (advance)
+ KeyStuffed = FALSE;
+
+ init_typebuf();
+ start_stuff();
+ if (advance && typebuf.tb_maplen == 0)
+ reg_executing = 0;
+ do
+ {
+/*
+ * get a character: 1. from the stuffbuffer
+ */
+ if (typeahead_char != 0)
+ {
+ c = typeahead_char;
+ if (advance)
+ typeahead_char = 0;
+ }
+ else
+ c = read_readbuffers(advance);
+ if (c != NUL && !got_int)
+ {
+ if (advance)
+ {
+ /* KeyTyped = FALSE; When the command that stuffed something
+ * was typed, behave like the stuffed command was typed.
+ * needed for CTRL-W CTRL-] to open a fold, for example. */
+ KeyStuffed = TRUE;
+ }
+ if (typebuf.tb_no_abbr_cnt == 0)
+ typebuf.tb_no_abbr_cnt = 1; /* no abbreviations now */
+ }
+ else
+ {
+ /*
+ * Loop until we either find a matching mapped key, or we
+ * are sure that it is not a mapped key.
+ * If a mapped key sequence is found we go back to the start to
+ * try re-mapping.
+ */
+ for (;;)
+ {
+ /*
+ * ui_breakcheck() is slow, don't use it too often when
+ * inside a mapping. But call it each time for typed
+ * characters.
+ */
+ if (typebuf.tb_maplen)
+ line_breakcheck();
+ else
+ ui_breakcheck(); /* check for CTRL-C */
+ keylen = 0;
+ if (got_int)
+ {
+ /* flush all input */
+ c = inchar(typebuf.tb_buf, typebuf.tb_buflen - 1, 0L);
+ /*
+ * If inchar() returns TRUE (script file was active) or we
+ * are inside a mapping, get out of Insert mode.
+ * Otherwise we behave like having gotten a CTRL-C.
+ * As a result typing CTRL-C in insert mode will
+ * really insert a CTRL-C.
+ */
+ if ((c || typebuf.tb_maplen)
+ && (State & (INSERT + CMDLINE)))
+ c = ESC;
+ else
+ c = Ctrl_C;
+ flush_buffers(FLUSH_INPUT); // flush all typeahead
+
+ if (advance)
+ {
+ /* Also record this character, it might be needed to
+ * get out of Insert mode. */
+ *typebuf.tb_buf = c;
+ gotchars(typebuf.tb_buf, 1);
+ }
+ cmd_silent = FALSE;
+
+ break;
+ }
+ else if (typebuf.tb_len > 0)
+ {
+ /*
+ * Check for a mappable key sequence.
+ * Walk through one maphash[] list until we find an
+ * entry that matches.
+ *
+ * Don't look for mappings if:
+ * - no_mapping set: mapping disabled (e.g. for CTRL-V)
+ * - maphash_valid not set: no mappings present.
+ * - typebuf.tb_buf[typebuf.tb_off] should not be remapped
+ * - in insert or cmdline mode and 'paste' option set
+ * - waiting for "hit return to continue" and CR or SPACE
+ * typed
+ * - waiting for a char with --more--
+ * - in Ctrl-X mode, and we get a valid char for that mode
+ */
+ mp = NULL;
+ max_mlen = 0;
+ c1 = typebuf.tb_buf[typebuf.tb_off];
+ if (no_mapping == 0 && maphash_valid
+ && (no_zero_mapping == 0 || c1 != '0')
+ && (typebuf.tb_maplen == 0
+ || (p_remap
+ && (typebuf.tb_noremap[typebuf.tb_off]
+ & (RM_NONE|RM_ABBR)) == 0))
+ && !(p_paste && (State & (INSERT + CMDLINE)))
+ && !(State == HITRETURN && (c1 == CAR || c1 == ' '))
+ && State != ASKMORE
+ && State != CONFIRM
+#ifdef FEAT_INS_EXPAND
+ && !((ctrl_x_mode_not_default()
+ && vim_is_ctrl_x_key(c1))
+ || ((compl_cont_status & CONT_LOCAL)
+ && (c1 == Ctrl_N || c1 == Ctrl_P)))
+#endif
+ )
+ {
+#ifdef FEAT_LANGMAP
+ if (c1 == K_SPECIAL)
+ nolmaplen = 2;
+ else
+ {
+ LANGMAP_ADJUST(c1,
+ (State & (CMDLINE | INSERT)) == 0
+ && get_real_state() != SELECTMODE);
+ nolmaplen = 0;
+ }
+#endif
+#ifdef FEAT_LOCALMAP
+ /* First try buffer-local mappings. */
+ mp = curbuf->b_maphash[MAP_HASH(local_State, c1)];
+ mp2 = maphash[MAP_HASH(local_State, c1)];
+ if (mp == NULL)
+ {
+ /* There are no buffer-local mappings. */
+ mp = mp2;
+ mp2 = NULL;
+ }
+#else
+ mp = maphash[MAP_HASH(local_State, c1)];
+#endif
+ /*
+ * Loop until a partly matching mapping is found or
+ * all (local) mappings have been checked.
+ * The longest full match is remembered in "mp_match".
+ * A full match is only accepted if there is no partly
+ * match, so "aa" and "aaa" can both be mapped.
+ */
+ mp_match = NULL;
+ mp_match_len = 0;
+ for ( ; mp != NULL;
+#ifdef FEAT_LOCALMAP
+ mp->m_next == NULL ? (mp = mp2, mp2 = NULL) :
+#endif
+ (mp = mp->m_next))
+ {
+ /*
+ * Only consider an entry if the first character
+ * matches and it is for the current state.
+ * Skip ":lmap" mappings if keys were mapped.
+ */
+ if (mp->m_keys[0] == c1
+ && (mp->m_mode & local_State)
+ && ((mp->m_mode & LANGMAP) == 0
+ || typebuf.tb_maplen == 0))
+ {
+#ifdef FEAT_LANGMAP
+ int nomap = nolmaplen;
+ int c2;
+#endif
+ /* find the match length of this mapping */
+ for (mlen = 1; mlen < typebuf.tb_len; ++mlen)
+ {
+#ifdef FEAT_LANGMAP
+ c2 = typebuf.tb_buf[typebuf.tb_off + mlen];
+ if (nomap > 0)
+ --nomap;
+ else if (c2 == K_SPECIAL)
+ nomap = 2;
+ else
+ LANGMAP_ADJUST(c2, TRUE);
+ if (mp->m_keys[mlen] != c2)
+#else
+ if (mp->m_keys[mlen] !=
+ typebuf.tb_buf[typebuf.tb_off + mlen])
+#endif
+ break;
+ }
+
+ /* Don't allow mapping the first byte(s) of a
+ * multi-byte char. Happens when mapping
+ * <M-a> and then changing 'encoding'. Beware
+ * that 0x80 is escaped. */
+ {
+ char_u *p1 = mp->m_keys;
+ char_u *p2 = mb_unescape(&p1);
+
+ if (has_mbyte && p2 != NULL
+ && MB_BYTE2LEN(c1) > MB_PTR2LEN(p2))
+ mlen = 0;
+ }
+ /*
+ * Check an entry whether it matches.
+ * - Full match: mlen == keylen
+ * - Partly match: mlen == typebuf.tb_len
+ */
+ keylen = mp->m_keylen;
+ if (mlen == keylen
+ || (mlen == typebuf.tb_len
+ && typebuf.tb_len < keylen))
+ {
+ /*
+ * If only script-local mappings are
+ * allowed, check if the mapping starts
+ * with K_SNR.
+ */
+ s = typebuf.tb_noremap + typebuf.tb_off;
+ if (*s == RM_SCRIPT
+ && (mp->m_keys[0] != K_SPECIAL
+ || mp->m_keys[1] != KS_EXTRA
+ || mp->m_keys[2]
+ != (int)KE_SNR))
+ continue;
+ /*
+ * If one of the typed keys cannot be
+ * remapped, skip the entry.
+ */
+ for (n = mlen; --n >= 0; )
+ if (*s++ & (RM_NONE|RM_ABBR))
+ break;
+ if (n >= 0)
+ continue;
+
+ if (keylen > typebuf.tb_len)
+ {
+ if (!timedout && !(mp_match != NULL
+ && mp_match->m_nowait))
+ {
+ /* break at a partly match */
+ keylen = KEYLEN_PART_MAP;
+ break;
+ }
+ }
+ else if (keylen > mp_match_len)
+ {
+ /* found a longer match */
+ mp_match = mp;
+ mp_match_len = keylen;
+ }
+ }
+ else
+ /* No match; may have to check for
+ * termcode at next character. */
+ if (max_mlen < mlen)
+ max_mlen = mlen;
+ }
+ }
+
+ /* If no partly match found, use the longest full
+ * match. */
+ if (keylen != KEYLEN_PART_MAP)
+ {
+ mp = mp_match;
+ keylen = mp_match_len;
+ }
+ }
+
+ /* Check for match with 'pastetoggle' */
+ if (*p_pt != NUL && mp == NULL && (State & (INSERT|NORMAL)))
+ {
+ for (mlen = 0; mlen < typebuf.tb_len && p_pt[mlen];
+ ++mlen)
+ if (p_pt[mlen] != typebuf.tb_buf[typebuf.tb_off
+ + mlen])
+ break;
+ if (p_pt[mlen] == NUL) /* match */
+ {
+ /* write chars to script file(s) */
+ if (mlen > typebuf.tb_maplen)
+ gotchars(typebuf.tb_buf + typebuf.tb_off
+ + typebuf.tb_maplen,
+ mlen - typebuf.tb_maplen);
+
+ del_typebuf(mlen, 0); /* remove the chars */
+ set_option_value((char_u *)"paste",
+ (long)!p_paste, NULL, 0);
+ if (!(State & INSERT))
+ {
+ msg_col = 0;
+ msg_row = Rows - 1;
+ msg_clr_eos(); /* clear ruler */
+ }
+ status_redraw_all();
+ redraw_statuslines();
+ showmode();
+ setcursor();
+ continue;
+ }
+ /* Need more chars for partly match. */
+ if (mlen == typebuf.tb_len)
+ keylen = KEYLEN_PART_KEY;
+ else if (max_mlen < mlen)
+ /* no match, may have to check for termcode at
+ * next character */
+ max_mlen = mlen + 1;
+ }
+
+ if ((mp == NULL || max_mlen >= mp_match_len)
+ && keylen != KEYLEN_PART_MAP)
+ {
+ int save_keylen = keylen;
+
+ /*
+ * When no matching mapping found or found a
+ * non-matching mapping that matches at least what the
+ * matching mapping matched:
+ * Check if we have a terminal code, when:
+ * mapping is allowed,
+ * keys have not been mapped,
+ * and not an ESC sequence, not in insert mode or
+ * p_ek is on,
+ * and when not timed out,
+ */
+ if ((no_mapping == 0 || allow_keys != 0)
+ && (typebuf.tb_maplen == 0
+ || (p_remap && typebuf.tb_noremap[
+ typebuf.tb_off] == RM_YES))
+ && !timedout)
+ {
+ keylen = check_termcode(max_mlen + 1,
+ NULL, 0, NULL);
+
+ /* If no termcode matched but 'pastetoggle'
+ * matched partially it's like an incomplete key
+ * sequence. */
+ if (keylen == 0 && save_keylen == KEYLEN_PART_KEY)
+ keylen = KEYLEN_PART_KEY;
+
+ /*
+ * When getting a partial match, but the last
+ * characters were not typed, don't wait for a
+ * typed character to complete the termcode.
+ * This helps a lot when a ":normal" command ends
+ * in an ESC.
+ */
+ if (keylen < 0
+ && typebuf.tb_len == typebuf.tb_maplen)
+ keylen = 0;
+ }
+ else
+ keylen = 0;
+ if (keylen == 0) /* no matching terminal code */
+ {
+#ifdef AMIGA /* check for window bounds report */
+ if (typebuf.tb_maplen == 0 && (typebuf.tb_buf[
+ typebuf.tb_off] & 0xff) == CSI)
+ {
+ for (s = typebuf.tb_buf + typebuf.tb_off + 1;
+ s < typebuf.tb_buf + typebuf.tb_off
+ + typebuf.tb_len
+ && (VIM_ISDIGIT(*s) || *s == ';'
+ || *s == ' ');
+ ++s)
+ ;
+ if (*s == 'r' || *s == '|') /* found one */
+ {
+ del_typebuf((int)(s + 1 -
+ (typebuf.tb_buf + typebuf.tb_off)), 0);
+ /* get size and redraw screen */
+ shell_resized();
+ continue;
+ }
+ if (*s == NUL) /* need more characters */
+ keylen = KEYLEN_PART_KEY;
+ }
+ if (keylen >= 0)
+#endif
+ /* When there was a matching mapping and no
+ * termcode could be replaced after another one,
+ * use that mapping (loop around). If there was
+ * no mapping use the character from the
+ * typeahead buffer right here. */
+ if (mp == NULL)
+ {
+/*
+ * get a character: 2. from the typeahead buffer
+ */
+ c = typebuf.tb_buf[typebuf.tb_off] & 255;
+ if (advance) /* remove chars from tb_buf */
+ {
+ cmd_silent = (typebuf.tb_silent > 0);
+ if (typebuf.tb_maplen > 0)
+ KeyTyped = FALSE;
+ else
+ {
+ KeyTyped = TRUE;
+ /* write char to script file(s) */
+ gotchars(typebuf.tb_buf
+ + typebuf.tb_off, 1);
+ }
+ KeyNoremap = typebuf.tb_noremap[
+ typebuf.tb_off];
+ del_typebuf(1, 0);
+ }
+ break; /* got character, break for loop */
+ }
+ }
+ if (keylen > 0) /* full matching terminal code */
+ {
+#if defined(FEAT_GUI) && defined(FEAT_MENU)
+ if (typebuf.tb_len >= 2
+ && typebuf.tb_buf[typebuf.tb_off] == K_SPECIAL
+ && typebuf.tb_buf[typebuf.tb_off + 1]
+ == KS_MENU)
+ {
+ /*
+ * Using a menu may cause a break in undo!
+ * It's like using gotchars(), but without
+ * recording or writing to a script file.
+ */
+ may_sync_undo();
+ del_typebuf(3, 0);
+ idx = get_menu_index(current_menu, local_State);
+ if (idx != MENU_INDEX_INVALID)
+ {
+ /*
+ * In Select mode and a Visual mode menu
+ * is used: Switch to Visual mode
+ * temporarily. Append K_SELECT to switch
+ * back to Select mode.
+ */
+ if (VIsual_active && VIsual_select
+ && (current_menu->modes & VISUAL))
+ {
+ VIsual_select = FALSE;
+ (void)ins_typebuf(K_SELECT_STRING,
+ REMAP_NONE, 0, TRUE, FALSE);
+ }
+ ins_typebuf(current_menu->strings[idx],
+ current_menu->noremap[idx],
+ 0, TRUE,
+ current_menu->silent[idx]);
+ }
+ }
+#endif /* FEAT_GUI && FEAT_MENU */
+ continue; /* try mapping again */
+ }
+
+ /* Partial match: get some more characters. When a
+ * matching mapping was found use that one. */
+ if (mp == NULL || keylen < 0)
+ keylen = KEYLEN_PART_KEY;
+ else
+ keylen = mp_match_len;
+ }
+
+ /* complete match */
+ if (keylen >= 0 && keylen <= typebuf.tb_len)
+ {
+#ifdef FEAT_EVAL
+ int save_m_expr;
+ int save_m_noremap;
+ int save_m_silent;
+ char_u *save_m_keys;
+ char_u *save_m_str;
+#else
+# define save_m_noremap mp->m_noremap
+# define save_m_silent mp->m_silent
+#endif
+
+ /* write chars to script file(s) */
+ if (keylen > typebuf.tb_maplen)
+ gotchars(typebuf.tb_buf + typebuf.tb_off
+ + typebuf.tb_maplen,
+ keylen - typebuf.tb_maplen);
+
+ cmd_silent = (typebuf.tb_silent > 0);
+ del_typebuf(keylen, 0); /* remove the mapped keys */
+
+ /*
+ * Put the replacement string in front of mapstr.
+ * The depth check catches ":map x y" and ":map y x".
+ */
+ if (++mapdepth >= p_mmd)
+ {
+ emsg(_("E223: recursive mapping"));
+ if (State & CMDLINE)
+ redrawcmdline();
+ else
+ setcursor();
+ flush_buffers(FLUSH_MINIMAL);
+ mapdepth = 0; /* for next one */
+ c = -1;
+ break;
+ }
+
+ /*
+ * In Select mode and a Visual mode mapping is used:
+ * Switch to Visual mode temporarily. Append K_SELECT
+ * to switch back to Select mode.
+ */
+ if (VIsual_active && VIsual_select
+ && (mp->m_mode & VISUAL))
+ {
+ VIsual_select = FALSE;
+ (void)ins_typebuf(K_SELECT_STRING, REMAP_NONE,
+ 0, TRUE, FALSE);
+ }
+
+#ifdef FEAT_EVAL
+ /* Copy the values from *mp that are used, because
+ * evaluating the expression may invoke a function
+ * that redefines the mapping, thereby making *mp
+ * invalid. */
+ save_m_expr = mp->m_expr;
+ save_m_noremap = mp->m_noremap;
+ save_m_silent = mp->m_silent;
+ save_m_keys = NULL; /* only saved when needed */
+ save_m_str = NULL; /* only saved when needed */
+
+ /*
+ * Handle ":map <expr>": evaluate the {rhs} as an
+ * expression. Also save and restore the command line
+ * for "normal :".
+ */
+ if (mp->m_expr)
+ {
+ int save_vgetc_busy = vgetc_busy;
+
+ vgetc_busy = 0;
+ save_m_keys = vim_strsave(mp->m_keys);
+ save_m_str = vim_strsave(mp->m_str);
+ s = eval_map_expr(save_m_str, NUL);
+ vgetc_busy = save_vgetc_busy;
+ }
+ else
+#endif
+ s = mp->m_str;
+
+ /*
+ * Insert the 'to' part in the typebuf.tb_buf.
+ * If 'from' field is the same as the start of the
+ * 'to' field, don't remap the first character (but do
+ * allow abbreviations).
+ * If m_noremap is set, don't remap the whole 'to'
+ * part.
+ */
+ if (s == NULL)
+ i = FAIL;
+ else
+ {
+ int noremap;
+
+ if (save_m_noremap != REMAP_YES)
+ noremap = save_m_noremap;
+ else if (
+#ifdef FEAT_EVAL
+ STRNCMP(s, save_m_keys != NULL
+ ? save_m_keys : mp->m_keys,
+ (size_t)keylen)
+#else
+ STRNCMP(s, mp->m_keys, (size_t)keylen)
+#endif
+ != 0)
+ noremap = REMAP_YES;
+ else
+ noremap = REMAP_SKIP;
+ i = ins_typebuf(s, noremap,
+ 0, TRUE, cmd_silent || save_m_silent);
+#ifdef FEAT_EVAL
+ if (save_m_expr)
+ vim_free(s);
+#endif
+ }
+#ifdef FEAT_EVAL
+ vim_free(save_m_keys);
+ vim_free(save_m_str);
+#endif
+ if (i == FAIL)
+ {
+ c = -1;
+ break;
+ }
+ continue;
+ }
+ }
+
+/*
+ * get a character: 3. from the user - handle <Esc> in Insert mode
+ */
+ /*
+ * Special case: if we get an <ESC> in insert mode and there
+ * are no more characters at once, we pretend to go out of
+ * insert mode. This prevents the one second delay after
+ * typing an <ESC>. If we get something after all, we may
+ * have to redisplay the mode. That the cursor is in the wrong
+ * place does not matter.
+ */
+ c = 0;
+#ifdef FEAT_CMDL_INFO
+ new_wcol = curwin->w_wcol;
+ new_wrow = curwin->w_wrow;
+#endif
+ if ( advance
+ && typebuf.tb_len == 1
+ && typebuf.tb_buf[typebuf.tb_off] == ESC
+ && !no_mapping
+ && ex_normal_busy == 0
+ && typebuf.tb_maplen == 0
+ && (State & INSERT)
+ && (p_timeout
+ || (keylen == KEYLEN_PART_KEY && p_ttimeout))
+ && (c = inchar(typebuf.tb_buf + typebuf.tb_off
+ + typebuf.tb_len, 3, 25L)) == 0)
+ {
+ colnr_T col = 0, vcol;
+ char_u *ptr;
+
+ if (mode_displayed)
+ {
+ unshowmode(TRUE);
+ mode_deleted = TRUE;
+ }
+#ifdef FEAT_GUI
+ /* may show a different cursor shape */
+ if (gui.in_use && State != NORMAL && !cmd_silent)
+ {
+ int save_State;
+
+ save_State = State;
+ State = NORMAL;
+ gui_update_cursor(TRUE, FALSE);
+ State = save_State;
+ shape_changed = TRUE;
+ }
+#endif
+ validate_cursor();
+ old_wcol = curwin->w_wcol;
+ old_wrow = curwin->w_wrow;
+
+ /* move cursor left, if possible */
+ if (curwin->w_cursor.col != 0)
+ {
+ if (curwin->w_wcol > 0)
+ {
+ if (did_ai)
+ {
+ /*
+ * We are expecting to truncate the trailing
+ * white-space, so find the last non-white
+ * character -- webb
+ */
+ col = vcol = curwin->w_wcol = 0;
+ ptr = ml_get_curline();
+ while (col < curwin->w_cursor.col)
+ {
+ if (!VIM_ISWHITE(ptr[col]))
+ curwin->w_wcol = vcol;
+ vcol += lbr_chartabsize(ptr, ptr + col,
+ (colnr_T)vcol);
+ if (has_mbyte)
+ col += (*mb_ptr2len)(ptr + col);
+ else
+ ++col;
+ }
+ curwin->w_wrow = curwin->w_cline_row
+ + curwin->w_wcol / curwin->w_width;
+ curwin->w_wcol %= curwin->w_width;
+ curwin->w_wcol += curwin_col_off();
+ col = 0; /* no correction needed */
+ }
+ else
+ {
+ --curwin->w_wcol;
+ col = curwin->w_cursor.col - 1;
+ }
+ }
+ else if (curwin->w_p_wrap && curwin->w_wrow)
+ {
+ --curwin->w_wrow;
+ curwin->w_wcol = curwin->w_width - 1;
+ col = curwin->w_cursor.col - 1;
+ }
+ if (has_mbyte && col > 0 && curwin->w_wcol > 0)
+ {
+ /* Correct when the cursor is on the right halve
+ * of a double-wide character. */
+ ptr = ml_get_curline();
+ col -= (*mb_head_off)(ptr, ptr + col);
+ if ((*mb_ptr2cells)(ptr + col) > 1)
+ --curwin->w_wcol;
+ }
+ }
+ setcursor();
+ out_flush();
+#ifdef FEAT_CMDL_INFO
+ new_wcol = curwin->w_wcol;
+ new_wrow = curwin->w_wrow;
+#endif
+ curwin->w_wcol = old_wcol;
+ curwin->w_wrow = old_wrow;
+ }
+ if (c < 0)
+ continue; /* end of input script reached */
+
+ /* Allow mapping for just typed characters. When we get here c
+ * is the number of extra bytes and typebuf.tb_len is 1. */
+ for (n = 1; n <= c; ++n)
+ typebuf.tb_noremap[typebuf.tb_off + n] = RM_YES;
+ typebuf.tb_len += c;
+
+ /* buffer full, don't map */
+ if (typebuf.tb_len >= typebuf.tb_maplen + MAXMAPLEN)
+ {
+ timedout = TRUE;
+ continue;
+ }
+
+ if (ex_normal_busy > 0)
+ {
+#ifdef FEAT_CMDWIN
+ static int tc = 0;
+#endif
+
+ /* No typeahead left and inside ":normal". Must return
+ * something to avoid getting stuck. When an incomplete
+ * mapping is present, behave like it timed out. */
+ if (typebuf.tb_len > 0)
+ {
+ timedout = TRUE;
+ continue;
+ }
+ /* When 'insertmode' is set, ESC just beeps in Insert
+ * mode. Use CTRL-L to make edit() return.
+ * For the command line only CTRL-C always breaks it.
+ * For the cmdline window: Alternate between ESC and
+ * CTRL-C: ESC for most situations and CTRL-C to close the
+ * cmdline window. */
+ if (p_im && (State & INSERT))
+ c = Ctrl_L;
+#ifdef FEAT_TERMINAL
+ else if (terminal_is_active())
+ c = K_CANCEL;
+#endif
+ else if ((State & CMDLINE)
+#ifdef FEAT_CMDWIN
+ || (cmdwin_type > 0 && tc == ESC)
+#endif
+ )
+ c = Ctrl_C;
+ else
+ c = ESC;
+#ifdef FEAT_CMDWIN
+ tc = c;
+#endif
+ break;
+ }
+
+/*
+ * get a character: 3. from the user - update display
+ */
+ /* In insert mode a screen update is skipped when characters
+ * are still available. But when those available characters
+ * are part of a mapping, and we are going to do a blocking
+ * wait here. Need to update the screen to display the
+ * changed text so far. Also for when 'lazyredraw' is set and
+ * redrawing was postponed because there was something in the
+ * input buffer (e.g., termresponse). */
+ if (((State & INSERT) != 0 || p_lz) && (State & CMDLINE) == 0
+ && advance && must_redraw != 0 && !need_wait_return)
+ {
+ update_screen(0);
+ setcursor(); /* put cursor back where it belongs */
+ }
+
+ /*
+ * If we have a partial match (and are going to wait for more
+ * input from the user), show the partially matched characters
+ * to the user with showcmd.
+ */
+#ifdef FEAT_CMDL_INFO
+ i = 0;
+#endif
+ c1 = 0;
+ if (typebuf.tb_len > 0 && advance && !exmode_active)
+ {
+ if (((State & (NORMAL | INSERT)) || State == LANGMAP)
+ && State != HITRETURN)
+ {
+ /* this looks nice when typing a dead character map */
+ if (State & INSERT
+ && ptr2cells(typebuf.tb_buf + typebuf.tb_off
+ + typebuf.tb_len - 1) == 1)
+ {
+ edit_putchar(typebuf.tb_buf[typebuf.tb_off
+ + typebuf.tb_len - 1], FALSE);
+ setcursor(); /* put cursor back where it belongs */
+ c1 = 1;
+ }
+#ifdef FEAT_CMDL_INFO
+ /* need to use the col and row from above here */
+ old_wcol = curwin->w_wcol;
+ old_wrow = curwin->w_wrow;
+ curwin->w_wcol = new_wcol;
+ curwin->w_wrow = new_wrow;
+ push_showcmd();
+ if (typebuf.tb_len > SHOWCMD_COLS)
+ i = typebuf.tb_len - SHOWCMD_COLS;
+ while (i < typebuf.tb_len)
+ (void)add_to_showcmd(typebuf.tb_buf[typebuf.tb_off
+ + i++]);
+ curwin->w_wcol = old_wcol;
+ curwin->w_wrow = old_wrow;
+#endif
+ }
+
+ /* this looks nice when typing a dead character map */
+ if ((State & CMDLINE)
+#if defined(FEAT_CRYPT) || defined(FEAT_EVAL)
+ && cmdline_star == 0
+#endif
+ && ptr2cells(typebuf.tb_buf + typebuf.tb_off
+ + typebuf.tb_len - 1) == 1)
+ {
+ putcmdline(typebuf.tb_buf[typebuf.tb_off
+ + typebuf.tb_len - 1], FALSE);
+ c1 = 1;
+ }
+ }
+
+/*
+ * get a character: 3. from the user - get it
+ */
+ if (typebuf.tb_len == 0)
+ // timedout may have been set while waiting for a mapping
+ // that has a <Nop> RHS.
+ timedout = FALSE;
+
+ wait_tb_len = typebuf.tb_len;
+ c = inchar(typebuf.tb_buf + typebuf.tb_off + typebuf.tb_len,
+ typebuf.tb_buflen - typebuf.tb_off - typebuf.tb_len - 1,
+ !advance
+ ? 0
+ : ((typebuf.tb_len == 0
+ || !(p_timeout || (p_ttimeout
+ && keylen == KEYLEN_PART_KEY)))
+ ? -1L
+ : ((keylen == KEYLEN_PART_KEY && p_ttm >= 0)
+ ? p_ttm
+ : p_tm)));
+
+#ifdef FEAT_CMDL_INFO
+ if (i != 0)
+ pop_showcmd();
+#endif
+ if (c1 == 1)
+ {
+ if (State & INSERT)
+ edit_unputchar();
+ if (State & CMDLINE)
+ unputcmdline();
+ else
+ setcursor(); /* put cursor back where it belongs */
+ }
+
+ if (c < 0)
+ continue; /* end of input script reached */
+ if (c == NUL) /* no character available */
+ {
+ if (!advance)
+ break;
+ if (wait_tb_len > 0) /* timed out */
+ {
+ timedout = TRUE;
+ continue;
+ }
+ }
+ else
+ { /* allow mapping for just typed characters */
+ while (typebuf.tb_buf[typebuf.tb_off
+ + typebuf.tb_len] != NUL)
+ typebuf.tb_noremap[typebuf.tb_off
+ + typebuf.tb_len++] = RM_YES;
+#ifdef HAVE_INPUT_METHOD
+ /* Get IM status right after getting keys, not after the
+ * timeout for a mapping (focus may be lost by then). */
+ vgetc_im_active = im_get_status();
+#endif
+ }
+ } /* for (;;) */
+ } /* if (!character from stuffbuf) */
+
+ /* if advance is FALSE don't loop on NULs */
+ } while ((c < 0 && c != K_CANCEL) || (advance && c == NUL));
+
+ /*
+ * The "INSERT" message is taken care of here:
+ * if we return an ESC to exit insert mode, the message is deleted
+ * if we don't return an ESC but deleted the message before, redisplay it
+ */
+ if (advance && p_smd && msg_silent == 0 && (State & INSERT))
+ {
+ if (c == ESC && !mode_deleted && !no_mapping && mode_displayed)
+ {
+ if (typebuf.tb_len && !KeyTyped)
+ redraw_cmdline = TRUE; /* delete mode later */
+ else
+ unshowmode(FALSE);
+ }
+ else if (c != ESC && mode_deleted)
+ {
+ if (typebuf.tb_len && !KeyTyped)
+ redraw_cmdline = TRUE; /* show mode later */
+ else
+ showmode();
+ }
+ }
+#ifdef FEAT_GUI
+ /* may unshow different cursor shape */
+ if (gui.in_use && shape_changed)
+ gui_update_cursor(TRUE, FALSE);
+#endif
+
+ --vgetc_busy;
+
+ return c;
+}
+
+/*
+ * inchar() - get one character from
+ * 1. a scriptfile
+ * 2. the keyboard
+ *
+ * As much characters as we can get (upto 'maxlen') are put in "buf" and
+ * NUL terminated (buffer length must be 'maxlen' + 1).
+ * Minimum for "maxlen" is 3!!!!
+ *
+ * "tb_change_cnt" is the value of typebuf.tb_change_cnt if "buf" points into
+ * it. When typebuf.tb_change_cnt changes (e.g., when a message is received
+ * from a remote client) "buf" can no longer be used. "tb_change_cnt" is 0
+ * otherwise.
+ *
+ * If we got an interrupt all input is read until none is available.
+ *
+ * If wait_time == 0 there is no waiting for the char.
+ * If wait_time == n we wait for n msec for a character to arrive.
+ * If wait_time == -1 we wait forever for a character to arrive.
+ *
+ * Return the number of obtained characters.
+ * Return -1 when end of input script reached.
+ */
+ static int
+inchar(
+ char_u *buf,
+ int maxlen,
+ long wait_time) /* milli seconds */
+{
+ int len = 0; /* init for GCC */
+ int retesc = FALSE; /* return ESC with gotint */
+ int script_char;
+ int tb_change_cnt = typebuf.tb_change_cnt;
+
+ if (wait_time == -1L || wait_time > 100L) /* flush output before waiting */
+ {
+ cursor_on();
+ out_flush_cursor(FALSE, FALSE);
+#if defined(FEAT_GUI) && defined(FEAT_MOUSESHAPE)
+ if (gui.in_use && postponed_mouseshape)
+ update_mouseshape(-1);
+#endif
+ }
+
+ /*
+ * Don't reset these when at the hit-return prompt, otherwise a endless
+ * recursive loop may result (write error in swapfile, hit-return, timeout
+ * on char wait, flush swapfile, write error....).
+ */
+ if (State != HITRETURN)
+ {
+ did_outofmem_msg = FALSE; /* display out of memory message (again) */
+ did_swapwrite_msg = FALSE; /* display swap file write error again */
+ }
+ undo_off = FALSE; /* restart undo now */
+
+ /*
+ * Get a character from a script file if there is one.
+ * If interrupted: Stop reading script files, close them all.
+ */
+ script_char = -1;
+ while (scriptin[curscript] != NULL && script_char < 0
+#ifdef FEAT_EVAL
+ && !ignore_script
+#endif
+ )
+ {
+
+#ifdef MESSAGE_QUEUE
+ parse_queued_messages();
+#endif
+
+ if (got_int || (script_char = getc(scriptin[curscript])) < 0)
+ {
+ /* Reached EOF.
+ * Careful: closescript() frees typebuf.tb_buf[] and buf[] may
+ * point inside typebuf.tb_buf[]. Don't use buf[] after this! */
+ closescript();
+ /*
+ * When reading script file is interrupted, return an ESC to get
+ * back to normal mode.
+ * Otherwise return -1, because typebuf.tb_buf[] has changed.
+ */
+ if (got_int)
+ retesc = TRUE;
+ else
+ return -1;
+ }
+ else
+ {
+ buf[0] = script_char;
+ len = 1;
+ }
+ }
+
+ if (script_char < 0) /* did not get a character from script */
+ {
+ /*
+ * If we got an interrupt, skip all previously typed characters and
+ * return TRUE if quit reading script file.
+ * Stop reading typeahead when a single CTRL-C was read,
+ * fill_input_buf() returns this when not able to read from stdin.
+ * Don't use buf[] here, closescript() may have freed typebuf.tb_buf[]
+ * and buf may be pointing inside typebuf.tb_buf[].
+ */
+ if (got_int)
+ {
+#define DUM_LEN MAXMAPLEN * 3 + 3
+ char_u dum[DUM_LEN + 1];
+
+ for (;;)
+ {
+ len = ui_inchar(dum, DUM_LEN, 0L, 0);
+ if (len == 0 || (len == 1 && dum[0] == 3))
+ break;
+ }
+ return retesc;
+ }
+
+ /*
+ * Always flush the output characters when getting input characters
+ * from the user and not just peeking.
+ */
+ if (wait_time == -1L || wait_time > 10L)
+ out_flush();
+
+ /*
+ * Fill up to a third of the buffer, because each character may be
+ * tripled below.
+ */
+ len = ui_inchar(buf, maxlen / 3, wait_time, tb_change_cnt);
+ }
+
+ /* If the typebuf was changed further down, it is like nothing was added by
+ * this call. */
+ if (typebuf_changed(tb_change_cnt))
+ return 0;
+
+ /* Note the change in the typeahead buffer, this matters for when
+ * vgetorpeek() is called recursively, e.g. using getchar(1) in a timer
+ * function. */
+ if (len > 0 && ++typebuf.tb_change_cnt == 0)
+ typebuf.tb_change_cnt = 1;
+
+ return fix_input_buffer(buf, len);
+}
+
+/*
+ * Fix typed characters for use by vgetc() and check_termcode().
+ * buf[] must have room to triple the number of bytes!
+ * Returns the new length.
+ */
+ int
+fix_input_buffer(char_u *buf, int len)
+{
+ int i;
+ char_u *p = buf;
+
+ /*
+ * Two characters are special: NUL and K_SPECIAL.
+ * When compiled With the GUI CSI is also special.
+ * Replace NUL by K_SPECIAL KS_ZERO KE_FILLER
+ * Replace K_SPECIAL by K_SPECIAL KS_SPECIAL KE_FILLER
+ * Replace CSI by K_SPECIAL KS_EXTRA KE_CSI
+ */
+ for (i = len; --i >= 0; ++p)
+ {
+#ifdef FEAT_GUI
+ /* When the GUI is used any character can come after a CSI, don't
+ * escape it. */
+ if (gui.in_use && p[0] == CSI && i >= 2)
+ {
+ p += 2;
+ i -= 2;
+ }
+ /* When the GUI is not used CSI needs to be escaped. */
+ else if (!gui.in_use && p[0] == CSI)
+ {
+ mch_memmove(p + 3, p + 1, (size_t)i);
+ *p++ = K_SPECIAL;
+ *p++ = KS_EXTRA;
+ *p = (int)KE_CSI;
+ len += 2;
+ }
+ else
+#endif
+ if (p[0] == NUL || (p[0] == K_SPECIAL
+ /* timeout may generate K_CURSORHOLD */
+ && (i < 2 || p[1] != KS_EXTRA || p[2] != (int)KE_CURSORHOLD)
+#if defined(WIN3264) && !defined(FEAT_GUI)
+ /* Win32 console passes modifiers */
+ && (i < 2 || p[1] != KS_MODIFIER)
+#endif
+ ))
+ {
+ mch_memmove(p + 3, p + 1, (size_t)i);
+ p[2] = K_THIRD(p[0]);
+ p[1] = K_SECOND(p[0]);
+ p[0] = K_SPECIAL;
+ p += 2;
+ len += 2;
+ }
+ }
+ *p = NUL; /* add trailing NUL */
+ return len;
+}
+
+#if defined(USE_INPUT_BUF) || defined(PROTO)
+/*
+ * Return TRUE when bytes are in the input buffer or in the typeahead buffer.
+ * Normally the input buffer would be sufficient, but the server_to_input_buf()
+ * or feedkeys() may insert characters in the typeahead buffer while we are
+ * waiting for input to arrive.
+ */
+ int
+input_available(void)
+{
+ return (!vim_is_input_buf_empty()
+# if defined(FEAT_CLIENTSERVER) || defined(FEAT_EVAL)
+ || typebuf_was_filled
+# endif
+ );
+}
+#endif
+
+/*
+ * map[!] : show all key mappings
+ * map[!] {lhs} : show key mapping for {lhs}
+ * map[!] {lhs} {rhs} : set key mapping for {lhs} to {rhs}
+ * noremap[!] {lhs} {rhs} : same, but no remapping for {rhs}
+ * unmap[!] {lhs} : remove key mapping for {lhs}
+ * abbr : show all abbreviations
+ * abbr {lhs} : show abbreviations for {lhs}
+ * abbr {lhs} {rhs} : set abbreviation for {lhs} to {rhs}
+ * noreabbr {lhs} {rhs} : same, but no remapping for {rhs}
+ * unabbr {lhs} : remove abbreviation for {lhs}
+ *
+ * maptype: 0 for :map, 1 for :unmap, 2 for noremap.
+ *
+ * arg is pointer to any arguments. Note: arg cannot be a read-only string,
+ * it will be modified.
+ *
+ * for :map mode is NORMAL + VISUAL + SELECTMODE + OP_PENDING
+ * for :map! mode is INSERT + CMDLINE
+ * for :cmap mode is CMDLINE
+ * for :imap mode is INSERT
+ * for :lmap mode is LANGMAP
+ * for :nmap mode is NORMAL
+ * for :vmap mode is VISUAL + SELECTMODE
+ * for :xmap mode is VISUAL
+ * for :smap mode is SELECTMODE
+ * for :omap mode is OP_PENDING
+ * for :tmap mode is TERMINAL
+ *
+ * for :abbr mode is INSERT + CMDLINE
+ * for :iabbr mode is INSERT
+ * for :cabbr mode is CMDLINE
+ *
+ * Return 0 for success
+ * 1 for invalid arguments
+ * 2 for no match
+ * 4 for out of mem
+ * 5 for entry not unique
+ */
+ int
+do_map(
+ int maptype,
+ char_u *arg,
+ int mode,
+ int abbrev) /* not a mapping but an abbreviation */
+{
+ char_u *keys;
+ mapblock_T *mp, **mpp;
+ char_u *rhs;
+ char_u *p;
+ int n;
+ int len = 0; /* init for GCC */
+ char_u *newstr;
+ int hasarg;
+ int haskey;
+ int did_it = FALSE;
+#ifdef FEAT_LOCALMAP
+ int did_local = FALSE;
+#endif
+ int round;
+ char_u *keys_buf = NULL;
+ char_u *arg_buf = NULL;
+ int retval = 0;
+ int do_backslash;
+ int hash;
+ int new_hash;
+ mapblock_T **abbr_table;
+ mapblock_T **map_table;
+ int unique = FALSE;
+ int nowait = FALSE;
+ int silent = FALSE;
+ int special = FALSE;
+#ifdef FEAT_EVAL
+ int expr = FALSE;
+#endif
+ int noremap;
+ char_u *orig_rhs;
+
+ keys = arg;
+ map_table = maphash;
+ abbr_table = &first_abbr;
+
+ /* For ":noremap" don't remap, otherwise do remap. */
+ if (maptype == 2)
+ noremap = REMAP_NONE;
+ else
+ noremap = REMAP_YES;
+
+ /* Accept <buffer>, <nowait>, <silent>, <expr> <script> and <unique> in
+ * any order. */
+ for (;;)
+ {
+#ifdef FEAT_LOCALMAP
+ /*
+ * Check for "<buffer>": mapping local to buffer.
+ */
+ if (STRNCMP(keys, "<buffer>", 8) == 0)
+ {
+ keys = skipwhite(keys + 8);
+ map_table = curbuf->b_maphash;
+ abbr_table = &curbuf->b_first_abbr;
+ continue;
+ }
+#endif
+
+ /*
+ * Check for "<nowait>": don't wait for more characters.
+ */
+ if (STRNCMP(keys, "<nowait>", 8) == 0)
+ {
+ keys = skipwhite(keys + 8);
+ nowait = TRUE;
+ continue;
+ }
+
+ /*
+ * Check for "<silent>": don't echo commands.
+ */
+ if (STRNCMP(keys, "<silent>", 8) == 0)
+ {
+ keys = skipwhite(keys + 8);
+ silent = TRUE;
+ continue;
+ }
+
+ /*
+ * Check for "<special>": accept special keys in <>
+ */
+ if (STRNCMP(keys, "<special>", 9) == 0)
+ {
+ keys = skipwhite(keys + 9);
+ special = TRUE;
+ continue;
+ }
+
+#ifdef FEAT_EVAL
+ /*
+ * Check for "<script>": remap script-local mappings only
+ */
+ if (STRNCMP(keys, "<script>", 8) == 0)
+ {
+ keys = skipwhite(keys + 8);
+ noremap = REMAP_SCRIPT;
+ continue;
+ }
+
+ /*
+ * Check for "<expr>": {rhs} is an expression.
+ */
+ if (STRNCMP(keys, "<expr>", 6) == 0)
+ {
+ keys = skipwhite(keys + 6);
+ expr = TRUE;
+ continue;
+ }
+#endif
+ /*
+ * Check for "<unique>": don't overwrite an existing mapping.
+ */
+ if (STRNCMP(keys, "<unique>", 8) == 0)
+ {
+ keys = skipwhite(keys + 8);
+ unique = TRUE;
+ continue;
+ }
+ break;
+ }
+
+ validate_maphash();
+
+ /*
+ * Find end of keys and skip CTRL-Vs (and backslashes) in it.
+ * Accept backslash like CTRL-V when 'cpoptions' does not contain 'B'.
+ * with :unmap white space is included in the keys, no argument possible.
+ */
+ p = keys;
+ do_backslash = (vim_strchr(p_cpo, CPO_BSLASH) == NULL);
+ while (*p && (maptype == 1 || !VIM_ISWHITE(*p)))
+ {
+ if ((p[0] == Ctrl_V || (do_backslash && p[0] == '\\')) &&
+ p[1] != NUL)
+ ++p; /* skip CTRL-V or backslash */
+ ++p;
+ }
+ if (*p != NUL)
+ *p++ = NUL;
+
+ p = skipwhite(p);
+ rhs = p;
+ hasarg = (*rhs != NUL);
+ haskey = (*keys != NUL);
+
+ /* check for :unmap without argument */
+ if (maptype == 1 && !haskey)
+ {
+ retval = 1;
+ goto theend;
+ }
+
+ /*
+ * If mapping has been given as ^V<C_UP> say, then replace the term codes
+ * with the appropriate two bytes. If it is a shifted special key, unshift
+ * it too, giving another two bytes.
+ * replace_termcodes() may move the result to allocated memory, which
+ * needs to be freed later (*keys_buf and *arg_buf).
+ * replace_termcodes() also removes CTRL-Vs and sometimes backslashes.
+ */
+ if (haskey)
+ keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, special);
+ orig_rhs = rhs;
+ if (hasarg)
+ {
+ if (STRICMP(rhs, "<nop>") == 0) /* "<Nop>" means nothing */
+ rhs = (char_u *)"";
+ else
+ rhs = replace_termcodes(rhs, &arg_buf, FALSE, TRUE, special);
+ }
+
+#ifdef FEAT_FKMAP
+ /*
+ * When in right-to-left mode and alternate keymap option set,
+ * reverse the character flow in the rhs in Farsi.
+ */
+ if (p_altkeymap && curwin->w_p_rl)
+ lrswap(rhs);
+#endif
+
+ /*
+ * check arguments and translate function keys
+ */
+ if (haskey)
+ {
+ len = (int)STRLEN(keys);
+ if (len > MAXMAPLEN) /* maximum length of MAXMAPLEN chars */
+ {
+ retval = 1;
+ goto theend;
+ }
+
+ if (abbrev && maptype != 1)
+ {
+ /*
+ * If an abbreviation ends in a keyword character, the
+ * rest must be all keyword-char or all non-keyword-char.
+ * Otherwise we won't be able to find the start of it in a
+ * vi-compatible way.
+ */
+ if (has_mbyte)
+ {
+ int first, last;
+ int same = -1;
+
+ first = vim_iswordp(keys);
+ last = first;
+ p = keys + (*mb_ptr2len)(keys);
+ n = 1;
+ while (p < keys + len)
+ {
+ ++n; /* nr of (multi-byte) chars */
+ last = vim_iswordp(p); /* type of last char */
+ if (same == -1 && last != first)
+ same = n - 1; /* count of same char type */
+ p += (*mb_ptr2len)(p);
+ }
+ if (last && n > 2 && same >= 0 && same < n - 1)
+ {
+ retval = 1;
+ goto theend;
+ }
+ }
+ else if (vim_iswordc(keys[len - 1])) // ends in keyword char
+ for (n = 0; n < len - 2; ++n)
+ if (vim_iswordc(keys[n]) != vim_iswordc(keys[len - 2]))
+ {
+ retval = 1;
+ goto theend;
+ }
+ /* An abbreviation cannot contain white space. */
+ for (n = 0; n < len; ++n)
+ if (VIM_ISWHITE(keys[n]))
+ {
+ retval = 1;
+ goto theend;
+ }
+ }
+ }
+
+ if (haskey && hasarg && abbrev) /* if we will add an abbreviation */
+ no_abbr = FALSE; /* reset flag that indicates there are
+ no abbreviations */
+
+ if (!haskey || (maptype != 1 && !hasarg))
+ msg_start();
+
+#ifdef FEAT_LOCALMAP
+ /*
+ * Check if a new local mapping wasn't already defined globally.
+ */
+ if (map_table == curbuf->b_maphash && haskey && hasarg && maptype != 1)
+ {
+ /* need to loop over all global hash lists */
+ for (hash = 0; hash < 256 && !got_int; ++hash)
+ {
+ if (abbrev)
+ {
+ if (hash != 0) /* there is only one abbreviation list */
+ break;
+ mp = first_abbr;
+ }
+ else
+ mp = maphash[hash];
+ for ( ; mp != NULL && !got_int; mp = mp->m_next)
+ {
+ /* check entries with the same mode */
+ if ((mp->m_mode & mode) != 0
+ && mp->m_keylen == len
+ && unique
+ && STRNCMP(mp->m_keys, keys, (size_t)len) == 0)
+ {
+ if (abbrev)
+ semsg(_("E224: global abbreviation already exists for %s"),
+ mp->m_keys);
+ else
+ semsg(_("E225: global mapping already exists for %s"),
+ mp->m_keys);
+ retval = 5;
+ goto theend;
+ }
+ }
+ }
+ }
+
+ /*
+ * When listing global mappings, also list buffer-local ones here.
+ */
+ if (map_table != curbuf->b_maphash && !hasarg && maptype != 1)
+ {
+ /* need to loop over all global hash lists */
+ for (hash = 0; hash < 256 && !got_int; ++hash)
+ {
+ if (abbrev)
+ {
+ if (hash != 0) /* there is only one abbreviation list */
+ break;
+ mp = curbuf->b_first_abbr;
+ }
+ else
+ mp = curbuf->b_maphash[hash];
+ for ( ; mp != NULL && !got_int; mp = mp->m_next)
+ {
+ /* check entries with the same mode */
+ if ((mp->m_mode & mode) != 0)
+ {
+ if (!haskey) /* show all entries */
+ {
+ showmap(mp, TRUE);
+ did_local = TRUE;
+ }
+ else
+ {
+ n = mp->m_keylen;
+ if (STRNCMP(mp->m_keys, keys,
+ (size_t)(n < len ? n : len)) == 0)
+ {
+ showmap(mp, TRUE);
+ did_local = TRUE;
+ }
+ }
+ }
+ }
+ }
+ }
+#endif
+
+ /*
+ * Find an entry in the maphash[] list that matches.
+ * For :unmap we may loop two times: once to try to unmap an entry with a
+ * matching 'from' part, a second time, if the first fails, to unmap an
+ * entry with a matching 'to' part. This was done to allow ":ab foo bar"
+ * to be unmapped by typing ":unab foo", where "foo" will be replaced by
+ * "bar" because of the abbreviation.
+ */
+ for (round = 0; (round == 0 || maptype == 1) && round <= 1
+ && !did_it && !got_int; ++round)
+ {
+ /* need to loop over all hash lists */
+ for (hash = 0; hash < 256 && !got_int; ++hash)
+ {
+ if (abbrev)
+ {
+ if (hash > 0) /* there is only one abbreviation list */
+ break;
+ mpp = abbr_table;
+ }
+ else
+ mpp = &(map_table[hash]);
+ for (mp = *mpp; mp != NULL && !got_int; mp = *mpp)
+ {
+
+ if (!(mp->m_mode & mode)) /* skip entries with wrong mode */
+ {
+ mpp = &(mp->m_next);
+ continue;
+ }
+ if (!haskey) /* show all entries */
+ {
+ showmap(mp, map_table != maphash);
+ did_it = TRUE;
+ }
+ else /* do we have a match? */
+ {
+ if (round) /* second round: Try unmap "rhs" string */
+ {
+ n = (int)STRLEN(mp->m_str);
+ p = mp->m_str;
+ }
+ else
+ {
+ n = mp->m_keylen;
+ p = mp->m_keys;
+ }
+ if (STRNCMP(p, keys, (size_t)(n < len ? n : len)) == 0)
+ {
+ if (maptype == 1) /* delete entry */
+ {
+ /* Only accept a full match. For abbreviations we
+ * ignore trailing space when matching with the
+ * "lhs", since an abbreviation can't have
+ * trailing space. */
+ if (n != len && (!abbrev || round || n > len
+ || *skipwhite(keys + n) != NUL))
+ {
+ mpp = &(mp->m_next);
+ continue;
+ }
+ /*
+ * We reset the indicated mode bits. If nothing is
+ * left the entry is deleted below.
+ */
+ mp->m_mode &= ~mode;
+ did_it = TRUE; /* remember we did something */
+ }
+ else if (!hasarg) /* show matching entry */
+ {
+ showmap(mp, map_table != maphash);
+ did_it = TRUE;
+ }
+ else if (n != len) /* new entry is ambiguous */
+ {
+ mpp = &(mp->m_next);
+ continue;
+ }
+ else if (unique)
+ {
+ if (abbrev)
+ semsg(_("E226: abbreviation already exists for %s"),
+ p);
+ else
+ semsg(_("E227: mapping already exists for %s"), p);
+ retval = 5;
+ goto theend;
+ }
+ else /* new rhs for existing entry */
+ {
+ mp->m_mode &= ~mode; /* remove mode bits */
+ if (mp->m_mode == 0 && !did_it) /* reuse entry */
+ {
+ newstr = vim_strsave(rhs);
+ if (newstr == NULL)
+ {
+ retval = 4; /* no mem */
+ goto theend;
+ }
+ vim_free(mp->m_str);
+ mp->m_str = newstr;
+ vim_free(mp->m_orig_str);
+ mp->m_orig_str = vim_strsave(orig_rhs);
+ mp->m_noremap = noremap;
+ mp->m_nowait = nowait;
+ mp->m_silent = silent;
+ mp->m_mode = mode;
+#ifdef FEAT_EVAL
+ mp->m_expr = expr;
+ mp->m_script_ctx = current_sctx;
+ mp->m_script_ctx.sc_lnum += sourcing_lnum;
+#endif
+ did_it = TRUE;
+ }
+ }
+ if (mp->m_mode == 0) /* entry can be deleted */
+ {
+ map_free(mpp);
+ continue; /* continue with *mpp */
+ }
+
+ /*
+ * May need to put this entry into another hash list.
+ */
+ new_hash = MAP_HASH(mp->m_mode, mp->m_keys[0]);
+ if (!abbrev && new_hash != hash)
+ {
+ *mpp = mp->m_next;
+ mp->m_next = map_table[new_hash];
+ map_table[new_hash] = mp;
+
+ continue; /* continue with *mpp */
+ }
+ }
+ }
+ mpp = &(mp->m_next);
+ }
+ }
+ }
+
+ if (maptype == 1) /* delete entry */
+ {
+ if (!did_it)
+ retval = 2; /* no match */
+ else if (*keys == Ctrl_C)
+ {
+ /* If CTRL-C has been unmapped, reuse it for Interrupting. */
+#ifdef FEAT_LOCALMAP
+ if (map_table == curbuf->b_maphash)
+ curbuf->b_mapped_ctrl_c &= ~mode;
+ else
+#endif
+ mapped_ctrl_c &= ~mode;
+ }
+ goto theend;
+ }
+
+ if (!haskey || !hasarg) /* print entries */
+ {
+ if (!did_it
+#ifdef FEAT_LOCALMAP
+ && !did_local
+#endif
+ )
+ {
+ if (abbrev)
+ msg(_("No abbreviation found"));
+ else
+ msg(_("No mapping found"));
+ }
+ goto theend; /* listing finished */
+ }
+
+ if (did_it) /* have added the new entry already */
+ goto theend;
+
+ /*
+ * Get here when adding a new entry to the maphash[] list or abbrlist.
+ */
+ mp = (mapblock_T *)alloc((unsigned)sizeof(mapblock_T));
+ if (mp == NULL)
+ {
+ retval = 4; /* no mem */
+ goto theend;
+ }
+
+ /* If CTRL-C has been mapped, don't always use it for Interrupting. */
+ if (*keys == Ctrl_C)
+ {
+#ifdef FEAT_LOCALMAP
+ if (map_table == curbuf->b_maphash)
+ curbuf->b_mapped_ctrl_c |= mode;
+ else
+#endif
+ mapped_ctrl_c |= mode;
+ }
+
+ mp->m_keys = vim_strsave(keys);
+ mp->m_str = vim_strsave(rhs);
+ mp->m_orig_str = vim_strsave(orig_rhs);
+ if (mp->m_keys == NULL || mp->m_str == NULL)
+ {
+ vim_free(mp->m_keys);
+ vim_free(mp->m_str);
+ vim_free(mp->m_orig_str);
+ vim_free(mp);
+ retval = 4; /* no mem */
+ goto theend;
+ }
+ mp->m_keylen = (int)STRLEN(mp->m_keys);
+ mp->m_noremap = noremap;
+ mp->m_nowait = nowait;
+ mp->m_silent = silent;
+ mp->m_mode = mode;
+#ifdef FEAT_EVAL
+ mp->m_expr = expr;
+ mp->m_script_ctx = current_sctx;
+ mp->m_script_ctx.sc_lnum += sourcing_lnum;
+#endif
+
+ /* add the new entry in front of the abbrlist or maphash[] list */
+ if (abbrev)
+ {
+ mp->m_next = *abbr_table;
+ *abbr_table = mp;
+ }
+ else
+ {
+ n = MAP_HASH(mp->m_mode, mp->m_keys[0]);
+ mp->m_next = map_table[n];
+ map_table[n] = mp;
+ }
+
+theend:
+ vim_free(keys_buf);
+ vim_free(arg_buf);
+ return retval;
+}
+
+/*
+ * Delete one entry from the abbrlist or maphash[].
+ * "mpp" is a pointer to the m_next field of the PREVIOUS entry!
+ */
+ static void
+map_free(mapblock_T **mpp)
+{
+ mapblock_T *mp;
+
+ mp = *mpp;
+ vim_free(mp->m_keys);
+ vim_free(mp->m_str);
+ vim_free(mp->m_orig_str);
+ *mpp = mp->m_next;
+ vim_free(mp);
+}
+
+/*
+ * Initialize maphash[] for first use.
+ */
+ static void
+validate_maphash(void)
+{
+ if (!maphash_valid)
+ {
+ vim_memset(maphash, 0, sizeof(maphash));
+ maphash_valid = TRUE;
+ }
+}
+
+/*
+ * Get the mapping mode from the command name.
+ */
+ int
+get_map_mode(char_u **cmdp, int forceit)
+{
+ char_u *p;
+ int modec;
+ int mode;
+
+ p = *cmdp;
+ modec = *p++;
+ if (modec == 'i')
+ mode = INSERT; /* :imap */
+ else if (modec == 'l')
+ mode = LANGMAP; /* :lmap */
+ else if (modec == 'c')
+ mode = CMDLINE; /* :cmap */
+ else if (modec == 'n' && *p != 'o') /* avoid :noremap */
+ mode = NORMAL; /* :nmap */
+ else if (modec == 'v')
+ mode = VISUAL + SELECTMODE; /* :vmap */
+ else if (modec == 'x')
+ mode = VISUAL; /* :xmap */
+ else if (modec == 's')
+ mode = SELECTMODE; /* :smap */
+ else if (modec == 'o')
+ mode = OP_PENDING; /* :omap */
+ else if (modec == 't')
+ mode = TERMINAL; /* :tmap */
+ else
+ {
+ --p;
+ if (forceit)
+ mode = INSERT + CMDLINE; /* :map ! */
+ else
+ mode = VISUAL + SELECTMODE + NORMAL + OP_PENDING;/* :map */
+ }
+
+ *cmdp = p;
+ return mode;
+}
+
+/*
+ * Clear all mappings or abbreviations.
+ * 'abbr' should be FALSE for mappings, TRUE for abbreviations.
+ */
+ void
+map_clear(
+ char_u *cmdp,
+ char_u *arg UNUSED,
+ int forceit,
+ int abbr)
+{
+ int mode;
+#ifdef FEAT_LOCALMAP
+ int local;
+
+ local = (STRCMP(arg, "<buffer>") == 0);
+ if (!local && *arg != NUL)
+ {
+ emsg(_(e_invarg));
+ return;
+ }
+#endif
+
+ mode = get_map_mode(&cmdp, forceit);
+ map_clear_int(curbuf, mode,
+#ifdef FEAT_LOCALMAP
+ local,
+#else
+ FALSE,
+#endif
+ abbr);
+}
+
+/*
+ * Clear all mappings in "mode".
+ */
+ void
+map_clear_int(
+ buf_T *buf UNUSED, /* buffer for local mappings */
+ int mode, /* mode in which to delete */
+ int local UNUSED, /* TRUE for buffer-local mappings */
+ int abbr) /* TRUE for abbreviations */
+{
+ mapblock_T *mp, **mpp;
+ int hash;
+ int new_hash;
+
+ validate_maphash();
+
+ for (hash = 0; hash < 256; ++hash)
+ {
+ if (abbr)
+ {
+ if (hash > 0) /* there is only one abbrlist */
+ break;
+#ifdef FEAT_LOCALMAP
+ if (local)
+ mpp = &buf->b_first_abbr;
+ else
+#endif
+ mpp = &first_abbr;
+ }
+ else
+ {
+#ifdef FEAT_LOCALMAP
+ if (local)
+ mpp = &buf->b_maphash[hash];
+ else
+#endif
+ mpp = &maphash[hash];
+ }
+ while (*mpp != NULL)
+ {
+ mp = *mpp;
+ if (mp->m_mode & mode)
+ {
+ mp->m_mode &= ~mode;
+ if (mp->m_mode == 0) /* entry can be deleted */
+ {
+ map_free(mpp);
+ continue;
+ }
+ /*
+ * May need to put this entry into another hash list.
+ */
+ new_hash = MAP_HASH(mp->m_mode, mp->m_keys[0]);
+ if (!abbr && new_hash != hash)
+ {
+ *mpp = mp->m_next;
+#ifdef FEAT_LOCALMAP
+ if (local)
+ {
+ mp->m_next = buf->b_maphash[new_hash];
+ buf->b_maphash[new_hash] = mp;
+ }
+ else
+#endif
+ {
+ mp->m_next = maphash[new_hash];
+ maphash[new_hash] = mp;
+ }
+ continue; /* continue with *mpp */
+ }
+ }
+ mpp = &(mp->m_next);
+ }
+ }
+}
+
+/*
+ * Return characters to represent the map mode in an allocated string.
+ * Returns NULL when out of memory.
+ */
+ char_u *
+map_mode_to_chars(int mode)
+{
+ garray_T mapmode;
+
+ ga_init2(&mapmode, 1, 7);
+
+ if ((mode & (INSERT + CMDLINE)) == INSERT + CMDLINE)
+ ga_append(&mapmode, '!'); /* :map! */
+ else if (mode & INSERT)
+ ga_append(&mapmode, 'i'); /* :imap */
+ else if (mode & LANGMAP)
+ ga_append(&mapmode, 'l'); /* :lmap */
+ else if (mode & CMDLINE)
+ ga_append(&mapmode, 'c'); /* :cmap */
+ else if ((mode & (NORMAL + VISUAL + SELECTMODE + OP_PENDING))
+ == NORMAL + VISUAL + SELECTMODE + OP_PENDING)
+ ga_append(&mapmode, ' '); /* :map */
+ else
+ {
+ if (mode & NORMAL)
+ ga_append(&mapmode, 'n'); /* :nmap */
+ if (mode & OP_PENDING)
+ ga_append(&mapmode, 'o'); /* :omap */
+ if ((mode & (VISUAL + SELECTMODE)) == VISUAL + SELECTMODE)
+ ga_append(&mapmode, 'v'); /* :vmap */
+ else
+ {
+ if (mode & VISUAL)
+ ga_append(&mapmode, 'x'); /* :xmap */
+ if (mode & SELECTMODE)
+ ga_append(&mapmode, 's'); /* :smap */
+ }
+ }
+
+ ga_append(&mapmode, NUL);
+ return (char_u *)mapmode.ga_data;
+}
+
+ static void
+showmap(
+ mapblock_T *mp,
+ int local) /* TRUE for buffer-local map */
+{
+ int len = 1;
+ char_u *mapchars;
+
+ if (message_filtered(mp->m_keys) && message_filtered(mp->m_str))
+ return;
+
+ if (msg_didout || msg_silent != 0)
+ {
+ msg_putchar('\n');
+ if (got_int) /* 'q' typed at MORE prompt */
+ return;
+ }
+
+ mapchars = map_mode_to_chars(mp->m_mode);
+ if (mapchars != NULL)
+ {
+ msg_puts((char *)mapchars);
+ len = (int)STRLEN(mapchars);
+ vim_free(mapchars);
+ }
+
+ while (++len <= 3)
+ msg_putchar(' ');
+
+ /* Display the LHS. Get length of what we write. */
+ len = msg_outtrans_special(mp->m_keys, TRUE);
+ do
+ {
+ msg_putchar(' '); /* padd with blanks */
+ ++len;
+ } while (len < 12);
+
+ if (mp->m_noremap == REMAP_NONE)
+ msg_puts_attr("*", HL_ATTR(HLF_8));
+ else if (mp->m_noremap == REMAP_SCRIPT)
+ msg_puts_attr("&", HL_ATTR(HLF_8));
+ else
+ msg_putchar(' ');
+
+ if (local)
+ msg_putchar('@');
+ else
+ msg_putchar(' ');
+
+ /* Use FALSE below if we only want things like <Up> to show up as such on
+ * the rhs, and not M-x etc, TRUE gets both -- webb */
+ if (*mp->m_str == NUL)
+ msg_puts_attr("<Nop>", HL_ATTR(HLF_8));
+ else
+ {
+ /* Remove escaping of CSI, because "m_str" is in a format to be used
+ * as typeahead. */
+ char_u *s = vim_strsave(mp->m_str);
+ if (s != NULL)
+ {
+ vim_unescape_csi(s);
+ msg_outtrans_special(s, FALSE);
+ vim_free(s);
+ }
+ }
+#ifdef FEAT_EVAL
+ if (p_verbose > 0)
+ last_set_msg(mp->m_script_ctx);
+#endif
+ out_flush(); /* show one line at a time */
+}
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * Return TRUE if a map exists that has "str" in the rhs for mode "modechars".
+ * Recognize termcap codes in "str".
+ * Also checks mappings local to the current buffer.
+ */
+ int
+map_to_exists(char_u *str, char_u *modechars, int abbr)
+{
+ int mode = 0;
+ char_u *rhs;
+ char_u *buf;
+ int retval;
+
+ rhs = replace_termcodes(str, &buf, FALSE, TRUE, FALSE);
+
+ if (vim_strchr(modechars, 'n') != NULL)
+ mode |= NORMAL;
+ if (vim_strchr(modechars, 'v') != NULL)
+ mode |= VISUAL + SELECTMODE;
+ if (vim_strchr(modechars, 'x') != NULL)
+ mode |= VISUAL;
+ if (vim_strchr(modechars, 's') != NULL)
+ mode |= SELECTMODE;
+ if (vim_strchr(modechars, 'o') != NULL)
+ mode |= OP_PENDING;
+ if (vim_strchr(modechars, 'i') != NULL)
+ mode |= INSERT;
+ if (vim_strchr(modechars, 'l') != NULL)
+ mode |= LANGMAP;
+ if (vim_strchr(modechars, 'c') != NULL)
+ mode |= CMDLINE;
+
+ retval = map_to_exists_mode(rhs, mode, abbr);
+ vim_free(buf);
+
+ return retval;
+}
+#endif
+
+/*
+ * Return TRUE if a map exists that has "str" in the rhs for mode "mode".
+ * Also checks mappings local to the current buffer.
+ */
+ int
+map_to_exists_mode(char_u *rhs, int mode, int abbr)
+{
+ mapblock_T *mp;
+ int hash;
+# ifdef FEAT_LOCALMAP
+ int exp_buffer = FALSE;
+
+ validate_maphash();
+
+ /* Do it twice: once for global maps and once for local maps. */
+ for (;;)
+ {
+# endif
+ for (hash = 0; hash < 256; ++hash)
+ {
+ if (abbr)
+ {
+ if (hash > 0) /* there is only one abbr list */
+ break;
+#ifdef FEAT_LOCALMAP
+ if (exp_buffer)
+ mp = curbuf->b_first_abbr;
+ else
+#endif
+ mp = first_abbr;
+ }
+# ifdef FEAT_LOCALMAP
+ else if (exp_buffer)
+ mp = curbuf->b_maphash[hash];
+# endif
+ else
+ mp = maphash[hash];
+ for (; mp; mp = mp->m_next)
+ {
+ if ((mp->m_mode & mode)
+ && strstr((char *)mp->m_str, (char *)rhs) != NULL)
+ return TRUE;
+ }
+ }
+# ifdef FEAT_LOCALMAP
+ if (exp_buffer)
+ break;
+ exp_buffer = TRUE;
+ }
+# endif
+
+ return FALSE;
+}
+
+#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
+/*
+ * Used below when expanding mapping/abbreviation names.
+ */
+static int expand_mapmodes = 0;
+static int expand_isabbrev = 0;
+#ifdef FEAT_LOCALMAP
+static int expand_buffer = FALSE;
+#endif
+
+/*
+ * Work out what to complete when doing command line completion of mapping
+ * or abbreviation names.
+ */
+ char_u *
+set_context_in_map_cmd(
+ expand_T *xp,
+ char_u *cmd,
+ char_u *arg,
+ int forceit, /* TRUE if '!' given */
+ int isabbrev, /* TRUE if abbreviation */
+ int isunmap, /* TRUE if unmap/unabbrev command */
+ cmdidx_T cmdidx)
+{
+ if (forceit && cmdidx != CMD_map && cmdidx != CMD_unmap)
+ xp->xp_context = EXPAND_NOTHING;
+ else
+ {
+ if (isunmap)
+ expand_mapmodes = get_map_mode(&cmd, forceit || isabbrev);
+ else
+ {
+ expand_mapmodes = INSERT + CMDLINE;
+ if (!isabbrev)
+ expand_mapmodes += VISUAL + SELECTMODE + NORMAL + OP_PENDING;
+ }
+ expand_isabbrev = isabbrev;
+ xp->xp_context = EXPAND_MAPPINGS;
+#ifdef FEAT_LOCALMAP
+ expand_buffer = FALSE;
+#endif
+ for (;;)
+ {
+#ifdef FEAT_LOCALMAP
+ if (STRNCMP(arg, "<buffer>", 8) == 0)
+ {
+ expand_buffer = TRUE;
+ arg = skipwhite(arg + 8);
+ continue;
+ }
+#endif
+ if (STRNCMP(arg, "<unique>", 8) == 0)
+ {
+ arg = skipwhite(arg + 8);
+ continue;
+ }
+ if (STRNCMP(arg, "<nowait>", 8) == 0)
+ {
+ arg = skipwhite(arg + 8);
+ continue;
+ }
+ if (STRNCMP(arg, "<silent>", 8) == 0)
+ {
+ arg = skipwhite(arg + 8);
+ continue;
+ }
+ if (STRNCMP(arg, "<special>", 9) == 0)
+ {
+ arg = skipwhite(arg + 9);
+ continue;
+ }
+#ifdef FEAT_EVAL
+ if (STRNCMP(arg, "<script>", 8) == 0)
+ {
+ arg = skipwhite(arg + 8);
+ continue;
+ }
+ if (STRNCMP(arg, "<expr>", 6) == 0)
+ {
+ arg = skipwhite(arg + 6);
+ continue;
+ }
+#endif
+ break;
+ }
+ xp->xp_pattern = arg;
+ }
+
+ return NULL;
+}
+
+/*
+ * Find all mapping/abbreviation names that match regexp 'prog'.
+ * For command line expansion of ":[un]map" and ":[un]abbrev" in all modes.
+ * Return OK if matches found, FAIL otherwise.
+ */
+ int
+ExpandMappings(
+ regmatch_T *regmatch,
+ int *num_file,
+ char_u ***file)
+{
+ mapblock_T *mp;
+ int hash;
+ int count;
+ int round;
+ char_u *p;
+ int i;
+
+ validate_maphash();
+
+ *num_file = 0; /* return values in case of FAIL */
+ *file = NULL;
+
+ /*
+ * round == 1: Count the matches.
+ * round == 2: Build the array to keep the matches.
+ */
+ for (round = 1; round <= 2; ++round)
+ {
+ count = 0;
+
+ for (i = 0; i < 7; ++i)
+ {
+ if (i == 0)
+ p = (char_u *)"<silent>";
+ else if (i == 1)
+ p = (char_u *)"<unique>";
+#ifdef FEAT_EVAL
+ else if (i == 2)
+ p = (char_u *)"<script>";
+ else if (i == 3)
+ p = (char_u *)"<expr>";
+#endif
+#ifdef FEAT_LOCALMAP
+ else if (i == 4 && !expand_buffer)
+ p = (char_u *)"<buffer>";
+#endif
+ else if (i == 5)
+ p = (char_u *)"<nowait>";
+ else if (i == 6)
+ p = (char_u *)"<special>";
+ else
+ continue;
+
+ if (vim_regexec(regmatch, p, (colnr_T)0))
+ {
+ if (round == 1)
+ ++count;
+ else
+ (*file)[count++] = vim_strsave(p);
+ }
+ }
+
+ for (hash = 0; hash < 256; ++hash)
+ {
+ if (expand_isabbrev)
+ {
+ if (hash > 0) /* only one abbrev list */
+ break; /* for (hash) */
+ mp = first_abbr;
+ }
+#ifdef FEAT_LOCALMAP
+ else if (expand_buffer)
+ mp = curbuf->b_maphash[hash];
+#endif
+ else
+ mp = maphash[hash];
+ for (; mp; mp = mp->m_next)
+ {
+ if (mp->m_mode & expand_mapmodes)
+ {
+ p = translate_mapping(mp->m_keys, TRUE);
+ if (p != NULL && vim_regexec(regmatch, p, (colnr_T)0))
+ {
+ if (round == 1)
+ ++count;
+ else
+ {
+ (*file)[count++] = p;
+ p = NULL;
+ }
+ }
+ vim_free(p);
+ }
+ } /* for (mp) */
+ } /* for (hash) */
+
+ if (count == 0) /* no match found */
+ break; /* for (round) */
+
+ if (round == 1)
+ {
+ *file = (char_u **)alloc((unsigned)(count * sizeof(char_u *)));
+ if (*file == NULL)
+ return FAIL;
+ }
+ } /* for (round) */
+
+ if (count > 1)
+ {
+ char_u **ptr1;
+ char_u **ptr2;
+ char_u **ptr3;
+
+ /* Sort the matches */
+ sort_strings(*file, count);
+
+ /* Remove multiple entries */
+ ptr1 = *file;
+ ptr2 = ptr1 + 1;
+ ptr3 = ptr1 + count;
+
+ while (ptr2 < ptr3)
+ {
+ if (STRCMP(*ptr1, *ptr2))
+ *++ptr1 = *ptr2++;
+ else
+ {
+ vim_free(*ptr2++);
+ count--;
+ }
+ }
+ }
+
+ *num_file = count;
+ return (count == 0 ? FAIL : OK);
+}
+#endif /* FEAT_CMDL_COMPL */
+
+/*
+ * Check for an abbreviation.
+ * Cursor is at ptr[col].
+ * When inserting, mincol is where insert started.
+ * For the command line, mincol is what is to be skipped over.
+ * "c" is the character typed before check_abbr was called. It may have
+ * ABBR_OFF added to avoid prepending a CTRL-V to it.
+ *
+ * Historic vi practice: The last character of an abbreviation must be an id
+ * character ([a-zA-Z0-9_]). The characters in front of it must be all id
+ * characters or all non-id characters. This allows for abbr. "#i" to
+ * "#include".
+ *
+ * Vim addition: Allow for abbreviations that end in a non-keyword character.
+ * Then there must be white space before the abbr.
+ *
+ * return TRUE if there is an abbreviation, FALSE if not
+ */
+ int
+check_abbr(
+ int c,
+ char_u *ptr,
+ int col,
+ int mincol)
+{
+ int len;
+ int scol; /* starting column of the abbr. */
+ int j;
+ char_u *s;
+ char_u tb[MB_MAXBYTES + 4];
+ mapblock_T *mp;
+#ifdef FEAT_LOCALMAP
+ mapblock_T *mp2;
+#endif
+ int clen = 0; /* length in characters */
+ int is_id = TRUE;
+ int vim_abbr;
+
+ if (typebuf.tb_no_abbr_cnt) /* abbrev. are not recursive */
+ return FALSE;
+
+ /* no remapping implies no abbreviation, except for CTRL-] */
+ if ((KeyNoremap & (RM_NONE|RM_SCRIPT)) != 0 && c != Ctrl_RSB)
+ return FALSE;
+
+ /*
+ * Check for word before the cursor: If it ends in a keyword char all
+ * chars before it must be keyword chars or non-keyword chars, but not
+ * white space. If it ends in a non-keyword char we accept any characters
+ * before it except white space.
+ */
+ if (col == 0) /* cannot be an abbr. */
+ return FALSE;
+
+ if (has_mbyte)
+ {
+ char_u *p;
+
+ p = mb_prevptr(ptr, ptr + col);
+ if (!vim_iswordp(p))
+ vim_abbr = TRUE; /* Vim added abbr. */
+ else
+ {
+ vim_abbr = FALSE; /* vi compatible abbr. */
+ if (p > ptr)
+ is_id = vim_iswordp(mb_prevptr(ptr, p));
+ }
+ clen = 1;
+ while (p > ptr + mincol)
+ {
+ p = mb_prevptr(ptr, p);
+ if (vim_isspace(*p) || (!vim_abbr && is_id != vim_iswordp(p)))
+ {
+ p += (*mb_ptr2len)(p);
+ break;
+ }
+ ++clen;
+ }
+ scol = (int)(p - ptr);
+ }
+ else
+ {
+ if (!vim_iswordc(ptr[col - 1]))
+ vim_abbr = TRUE; /* Vim added abbr. */
+ else
+ {
+ vim_abbr = FALSE; /* vi compatible abbr. */
+ if (col > 1)
+ is_id = vim_iswordc(ptr[col - 2]);
+ }
+ for (scol = col - 1; scol > 0 && !vim_isspace(ptr[scol - 1])
+ && (vim_abbr || is_id == vim_iswordc(ptr[scol - 1])); --scol)
+ ;
+ }
+
+ if (scol < mincol)
+ scol = mincol;
+ if (scol < col) /* there is a word in front of the cursor */
+ {
+ ptr += scol;
+ len = col - scol;
+#ifdef FEAT_LOCALMAP
+ mp = curbuf->b_first_abbr;
+ mp2 = first_abbr;
+ if (mp == NULL)
+ {
+ mp = mp2;
+ mp2 = NULL;
+ }
+#else
+ mp = first_abbr;
+#endif
+ for ( ; mp;
+#ifdef FEAT_LOCALMAP
+ mp->m_next == NULL ? (mp = mp2, mp2 = NULL) :
+#endif
+ (mp = mp->m_next))
+ {
+ int qlen = mp->m_keylen;
+ char_u *q = mp->m_keys;
+ int match;
+
+ if (vim_strbyte(mp->m_keys, K_SPECIAL) != NULL)
+ {
+ char_u *qe = vim_strsave(mp->m_keys);
+
+ /* might have CSI escaped mp->m_keys */
+ if (qe != NULL)
+ {
+ q = qe;
+ vim_unescape_csi(q);
+ qlen = (int)STRLEN(q);
+ }
+ }
+
+ /* find entries with right mode and keys */
+ match = (mp->m_mode & State)
+ && qlen == len
+ && !STRNCMP(q, ptr, (size_t)len);
+ if (q != mp->m_keys)
+ vim_free(q);
+ if (match)
+ break;
+ }
+ if (mp != NULL)
+ {
+ /*
+ * Found a match:
+ * Insert the rest of the abbreviation in typebuf.tb_buf[].
+ * This goes from end to start.
+ *
+ * Characters 0x000 - 0x100: normal chars, may need CTRL-V,
+ * except K_SPECIAL: Becomes K_SPECIAL KS_SPECIAL KE_FILLER
+ * Characters where IS_SPECIAL() == TRUE: key codes, need
+ * K_SPECIAL. Other characters (with ABBR_OFF): don't use CTRL-V.
+ *
+ * Character CTRL-] is treated specially - it completes the
+ * abbreviation, but is not inserted into the input stream.
+ */
+ j = 0;
+ if (c != Ctrl_RSB)
+ {
+ /* special key code, split up */
+ if (IS_SPECIAL(c) || c == K_SPECIAL)
+ {
+ tb[j++] = K_SPECIAL;
+ tb[j++] = K_SECOND(c);
+ tb[j++] = K_THIRD(c);
+ }
+ else
+ {
+ if (c < ABBR_OFF && (c < ' ' || c > '~'))
+ tb[j++] = Ctrl_V; /* special char needs CTRL-V */
+ if (has_mbyte)
+ {
+ /* if ABBR_OFF has been added, remove it here */
+ if (c >= ABBR_OFF)
+ c -= ABBR_OFF;
+ j += (*mb_char2bytes)(c, tb + j);
+ }
+ else
+ tb[j++] = c;
+ }
+ tb[j] = NUL;
+ /* insert the last typed char */
+ (void)ins_typebuf(tb, 1, 0, TRUE, mp->m_silent);
+ }
+#ifdef FEAT_EVAL
+ if (mp->m_expr)
+ s = eval_map_expr(mp->m_str, c);
+ else
+#endif
+ s = mp->m_str;
+ if (s != NULL)
+ {
+ /* insert the to string */
+ (void)ins_typebuf(s, mp->m_noremap, 0, TRUE, mp->m_silent);
+ /* no abbrev. for these chars */
+ typebuf.tb_no_abbr_cnt += (int)STRLEN(s) + j + 1;
+#ifdef FEAT_EVAL
+ if (mp->m_expr)
+ vim_free(s);
+#endif
+ }
+
+ tb[0] = Ctrl_H;
+ tb[1] = NUL;
+ if (has_mbyte)
+ len = clen; /* Delete characters instead of bytes */
+ while (len-- > 0) /* delete the from string */
+ (void)ins_typebuf(tb, 1, 0, TRUE, mp->m_silent);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+#ifdef FEAT_EVAL
+/*
+ * Evaluate the RHS of a mapping or abbreviations and take care of escaping
+ * special characters.
+ */
+ static char_u *
+eval_map_expr(
+ char_u *str,
+ int c) /* NUL or typed character for abbreviation */
+{
+ char_u *res;
+ char_u *p;
+ char_u *expr;
+ pos_T save_cursor;
+ int save_msg_col;
+ int save_msg_row;
+
+ /* Remove escaping of CSI, because "str" is in a format to be used as
+ * typeahead. */
+ expr = vim_strsave(str);
+ if (expr == NULL)
+ return NULL;
+ vim_unescape_csi(expr);
+
+ /* Forbid changing text or using ":normal" to avoid most of the bad side
+ * effects. Also restore the cursor position. */
+ ++textlock;
+ ++ex_normal_lock;
+ set_vim_var_char(c); /* set v:char to the typed character */
+ save_cursor = curwin->w_cursor;
+ save_msg_col = msg_col;
+ save_msg_row = msg_row;
+ p = eval_to_string(expr, NULL, FALSE);
+ --textlock;
+ --ex_normal_lock;
+ curwin->w_cursor = save_cursor;
+ msg_col = save_msg_col;
+ msg_row = save_msg_row;
+
+ vim_free(expr);
+
+ if (p == NULL)
+ return NULL;
+ /* Escape CSI in the result to be able to use the string as typeahead. */
+ res = vim_strsave_escape_csi(p);
+ vim_free(p);
+
+ return res;
+}
+#endif
+
+/*
+ * Copy "p" to allocated memory, escaping K_SPECIAL and CSI so that the result
+ * can be put in the typeahead buffer.
+ * Returns NULL when out of memory.
+ */
+ char_u *
+vim_strsave_escape_csi(
+ char_u *p)
+{
+ char_u *res;
+ char_u *s, *d;
+
+ /* Need a buffer to hold up to three times as much. Four in case of an
+ * illegal utf-8 byte:
+ * 0xc0 -> 0xc3 0x80 -> 0xc3 K_SPECIAL KS_SPECIAL KE_FILLER */
+ res = alloc((unsigned)(STRLEN(p) * 4) + 1);
+ if (res != NULL)
+ {
+ d = res;
+ for (s = p; *s != NUL; )
+ {
+ if (s[0] == K_SPECIAL && s[1] != NUL && s[2] != NUL)
+ {
+ /* Copy special key unmodified. */
+ *d++ = *s++;
+ *d++ = *s++;
+ *d++ = *s++;
+ }
+ else
+ {
+ /* Add character, possibly multi-byte to destination, escaping
+ * CSI and K_SPECIAL. Be careful, it can be an illegal byte! */
+ d = add_char2buf(PTR2CHAR(s), d);
+ s += MB_CPTR2LEN(s);
+ }
+ }
+ *d = NUL;
+ }
+ return res;
+}
+
+/*
+ * Remove escaping from CSI and K_SPECIAL characters. Reverse of
+ * vim_strsave_escape_csi(). Works in-place.
+ */
+ void
+vim_unescape_csi(char_u *p)
+{
+ char_u *s = p, *d = p;
+
+ while (*s != NUL)
+ {
+ if (s[0] == K_SPECIAL && s[1] == KS_SPECIAL && s[2] == KE_FILLER)
+ {
+ *d++ = K_SPECIAL;
+ s += 3;
+ }
+ else if ((s[0] == K_SPECIAL || s[0] == CSI)
+ && s[1] == KS_EXTRA && s[2] == (int)KE_CSI)
+ {
+ *d++ = CSI;
+ s += 3;
+ }
+ else
+ *d++ = *s++;
+ }
+ *d = NUL;
+}
+
+/*
+ * Write map commands for the current mappings to an .exrc file.
+ * Return FAIL on error, OK otherwise.
+ */
+ int
+makemap(
+ FILE *fd,
+ buf_T *buf) /* buffer for local mappings or NULL */
+{
+ mapblock_T *mp;
+ char_u c1, c2, c3;
+ char_u *p;
+ char *cmd;
+ int abbr;
+ int hash;
+ int did_cpo = FALSE;
+ int i;
+
+ validate_maphash();
+
+ /*
+ * Do the loop twice: Once for mappings, once for abbreviations.
+ * Then loop over all map hash lists.
+ */
+ for (abbr = 0; abbr < 2; ++abbr)
+ for (hash = 0; hash < 256; ++hash)
+ {
+ if (abbr)
+ {
+ if (hash > 0) /* there is only one abbr list */
+ break;
+#ifdef FEAT_LOCALMAP
+ if (buf != NULL)
+ mp = buf->b_first_abbr;
+ else
+#endif
+ mp = first_abbr;
+ }
+ else
+ {
+#ifdef FEAT_LOCALMAP
+ if (buf != NULL)
+ mp = buf->b_maphash[hash];
+ else
+#endif
+ mp = maphash[hash];
+ }
+
+ for ( ; mp; mp = mp->m_next)
+ {
+ /* skip script-local mappings */
+ if (mp->m_noremap == REMAP_SCRIPT)
+ continue;
+
+ /* skip mappings that contain a <SNR> (script-local thing),
+ * they probably don't work when loaded again */
+ for (p = mp->m_str; *p != NUL; ++p)
+ if (p[0] == K_SPECIAL && p[1] == KS_EXTRA
+ && p[2] == (int)KE_SNR)
+ break;
+ if (*p != NUL)
+ continue;
+
+ /* It's possible to create a mapping and then ":unmap" certain
+ * modes. We recreate this here by mapping the individual
+ * modes, which requires up to three of them. */
+ c1 = NUL;
+ c2 = NUL;
+ c3 = NUL;
+ if (abbr)
+ cmd = "abbr";
+ else
+ cmd = "map";
+ switch (mp->m_mode)
+ {
+ case NORMAL + VISUAL + SELECTMODE + OP_PENDING:
+ break;
+ case NORMAL:
+ c1 = 'n';
+ break;
+ case VISUAL:
+ c1 = 'x';
+ break;
+ case SELECTMODE:
+ c1 = 's';
+ break;
+ case OP_PENDING:
+ c1 = 'o';
+ break;
+ case NORMAL + VISUAL:
+ c1 = 'n';
+ c2 = 'x';
+ break;
+ case NORMAL + SELECTMODE:
+ c1 = 'n';
+ c2 = 's';
+ break;
+ case NORMAL + OP_PENDING:
+ c1 = 'n';
+ c2 = 'o';
+ break;
+ case VISUAL + SELECTMODE:
+ c1 = 'v';
+ break;
+ case VISUAL + OP_PENDING:
+ c1 = 'x';
+ c2 = 'o';
+ break;
+ case SELECTMODE + OP_PENDING:
+ c1 = 's';
+ c2 = 'o';
+ break;
+ case NORMAL + VISUAL + SELECTMODE:
+ c1 = 'n';
+ c2 = 'v';
+ break;
+ case NORMAL + VISUAL + OP_PENDING:
+ c1 = 'n';
+ c2 = 'x';
+ c3 = 'o';
+ break;
+ case NORMAL + SELECTMODE + OP_PENDING:
+ c1 = 'n';
+ c2 = 's';
+ c3 = 'o';
+ break;
+ case VISUAL + SELECTMODE + OP_PENDING:
+ c1 = 'v';
+ c2 = 'o';
+ break;
+ case CMDLINE + INSERT:
+ if (!abbr)
+ cmd = "map!";
+ break;
+ case CMDLINE:
+ c1 = 'c';
+ break;
+ case INSERT:
+ c1 = 'i';
+ break;
+ case LANGMAP:
+ c1 = 'l';
+ break;
+ case TERMINAL:
+ c1 = 't';
+ break;
+ default:
+ iemsg(_("E228: makemap: Illegal mode"));
+ return FAIL;
+ }
+ do /* do this twice if c2 is set, 3 times with c3 */
+ {
+ /* When outputting <> form, need to make sure that 'cpo'
+ * is set to the Vim default. */
+ if (!did_cpo)
+ {
+ if (*mp->m_str == NUL) /* will use <Nop> */
+ did_cpo = TRUE;
+ else
+ for (i = 0; i < 2; ++i)
+ for (p = (i ? mp->m_str : mp->m_keys); *p; ++p)
+ if (*p == K_SPECIAL || *p == NL)
+ did_cpo = TRUE;
+ if (did_cpo)
+ {
+ if (fprintf(fd, "let s:cpo_save=&cpo") < 0
+ || put_eol(fd) < 0
+ || fprintf(fd, "set cpo&vim") < 0
+ || put_eol(fd) < 0)
+ return FAIL;
+ }
+ }
+ if (c1 && putc(c1, fd) < 0)
+ return FAIL;
+ if (mp->m_noremap != REMAP_YES && fprintf(fd, "nore") < 0)
+ return FAIL;
+ if (fputs(cmd, fd) < 0)
+ return FAIL;
+ if (buf != NULL && fputs(" <buffer>", fd) < 0)
+ return FAIL;
+ if (mp->m_nowait && fputs(" <nowait>", fd) < 0)
+ return FAIL;
+ if (mp->m_silent && fputs(" <silent>", fd) < 0)
+ return FAIL;
+#ifdef FEAT_EVAL
+ if (mp->m_noremap == REMAP_SCRIPT
+ && fputs("<script>", fd) < 0)
+ return FAIL;
+ if (mp->m_expr && fputs(" <expr>", fd) < 0)
+ return FAIL;
+#endif
+
+ if ( putc(' ', fd) < 0
+ || put_escstr(fd, mp->m_keys, 0) == FAIL
+ || putc(' ', fd) < 0
+ || put_escstr(fd, mp->m_str, 1) == FAIL
+ || put_eol(fd) < 0)
+ return FAIL;
+ c1 = c2;
+ c2 = c3;
+ c3 = NUL;
+ } while (c1 != NUL);
+ }
+ }
+
+ if (did_cpo)
+ if (fprintf(fd, "let &cpo=s:cpo_save") < 0
+ || put_eol(fd) < 0
+ || fprintf(fd, "unlet s:cpo_save") < 0
+ || put_eol(fd) < 0)
+ return FAIL;
+ return OK;
+}
+
+/*
+ * write escape string to file
+ * "what": 0 for :map lhs, 1 for :map rhs, 2 for :set
+ *
+ * return FAIL for failure, OK otherwise
+ */
+ int
+put_escstr(FILE *fd, char_u *strstart, int what)
+{
+ char_u *str = strstart;
+ int c;
+ int modifiers;
+
+ /* :map xx <Nop> */
+ if (*str == NUL && what == 1)
+ {
+ if (fprintf(fd, "<Nop>") < 0)
+ return FAIL;
+ return OK;
+ }
+
+ for ( ; *str != NUL; ++str)
+ {
+ char_u *p;
+
+ /* Check for a multi-byte character, which may contain escaped
+ * K_SPECIAL and CSI bytes */
+ p = mb_unescape(&str);
+ if (p != NULL)
+ {
+ while (*p != NUL)
+ if (fputc(*p++, fd) < 0)
+ return FAIL;
+ --str;
+ continue;
+ }
+
+ c = *str;
+ /*
+ * Special key codes have to be translated to be able to make sense
+ * when they are read back.
+ */
+ if (c == K_SPECIAL && what != 2)
+ {
+ modifiers = 0x0;
+ if (str[1] == KS_MODIFIER)
+ {
+ modifiers = str[2];
+ str += 3;
+ c = *str;
+ }
+ if (c == K_SPECIAL)
+ {
+ c = TO_SPECIAL(str[1], str[2]);
+ str += 2;
+ }
+ if (IS_SPECIAL(c) || modifiers) /* special key */
+ {
+ if (fputs((char *)get_special_key_name(c, modifiers), fd) < 0)
+ return FAIL;
+ continue;
+ }
+ }
+
+ /*
+ * A '\n' in a map command should be written as <NL>.
+ * A '\n' in a set command should be written as \^V^J.
+ */
+ if (c == NL)
+ {
+ if (what == 2)
+ {
+ if (fprintf(fd, IF_EB("\\\026\n", "\\" CTRL_V_STR "\n")) < 0)
+ return FAIL;
+ }
+ else
+ {
+ if (fprintf(fd, "<NL>") < 0)
+ return FAIL;
+ }
+ continue;
+ }
+
+ /*
+ * Some characters have to be escaped with CTRL-V to
+ * prevent them from misinterpreted in DoOneCmd().
+ * A space, Tab and '"' has to be escaped with a backslash to
+ * prevent it to be misinterpreted in do_set().
+ * A space has to be escaped with a CTRL-V when it's at the start of a
+ * ":map" rhs.
+ * A '<' has to be escaped with a CTRL-V to prevent it being
+ * interpreted as the start of a special key name.
+ * A space in the lhs of a :map needs a CTRL-V.
+ */
+ if (what == 2 && (VIM_ISWHITE(c) || c == '"' || c == '\\'))
+ {
+ if (putc('\\', fd) < 0)
+ return FAIL;
+ }
+ else if (c < ' ' || c > '~' || c == '|'
+ || (what == 0 && c == ' ')
+ || (what == 1 && str == strstart && c == ' ')
+ || (what != 2 && c == '<'))
+ {
+ if (putc(Ctrl_V, fd) < 0)
+ return FAIL;
+ }
+ if (putc(c, fd) < 0)
+ return FAIL;
+ }
+ return OK;
+}
+
+/*
+ * Check all mappings for the presence of special key codes.
+ * Used after ":set term=xxx".
+ */
+ void
+check_map_keycodes(void)
+{
+ mapblock_T *mp;
+ char_u *p;
+ int i;
+ char_u buf[3];
+ char_u *save_name;
+ int abbr;
+ int hash;
+#ifdef FEAT_LOCALMAP
+ buf_T *bp;
+#endif
+
+ validate_maphash();
+ save_name = sourcing_name;
+ sourcing_name = (char_u *)"mappings"; /* avoids giving error messages */
+
+#ifdef FEAT_LOCALMAP
+ /* This this once for each buffer, and then once for global
+ * mappings/abbreviations with bp == NULL */
+ for (bp = firstbuf; ; bp = bp->b_next)
+ {
+#endif
+ /*
+ * Do the loop twice: Once for mappings, once for abbreviations.
+ * Then loop over all map hash lists.
+ */
+ for (abbr = 0; abbr <= 1; ++abbr)
+ for (hash = 0; hash < 256; ++hash)
+ {
+ if (abbr)
+ {
+ if (hash) /* there is only one abbr list */
+ break;
+#ifdef FEAT_LOCALMAP
+ if (bp != NULL)
+ mp = bp->b_first_abbr;
+ else
+#endif
+ mp = first_abbr;
+ }
+ else
+ {
+#ifdef FEAT_LOCALMAP
+ if (bp != NULL)
+ mp = bp->b_maphash[hash];
+ else
+#endif
+ mp = maphash[hash];
+ }
+ for ( ; mp != NULL; mp = mp->m_next)
+ {
+ for (i = 0; i <= 1; ++i) /* do this twice */
+ {
+ if (i == 0)
+ p = mp->m_keys; /* once for the "from" part */
+ else
+ p = mp->m_str; /* and once for the "to" part */
+ while (*p)
+ {
+ if (*p == K_SPECIAL)
+ {
+ ++p;
+ if (*p < 128) /* for "normal" tcap entries */
+ {
+ buf[0] = p[0];
+ buf[1] = p[1];
+ buf[2] = NUL;
+ (void)add_termcap_entry(buf, FALSE);
+ }
+ ++p;
+ }
+ ++p;
+ }
+ }
+ }
+ }
+#ifdef FEAT_LOCALMAP
+ if (bp == NULL)
+ break;
+ }
+#endif
+ sourcing_name = save_name;
+}
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * Check the string "keys" against the lhs of all mappings.
+ * Return pointer to rhs of mapping (mapblock->m_str).
+ * NULL when no mapping found.
+ */
+ char_u *
+check_map(
+ char_u *keys,
+ int mode,
+ int exact, /* require exact match */
+ int ign_mod, /* ignore preceding modifier */
+ int abbr, /* do abbreviations */
+ mapblock_T **mp_ptr, /* return: pointer to mapblock or NULL */
+ int *local_ptr) /* return: buffer-local mapping or NULL */
+{
+ int hash;
+ int len, minlen;
+ mapblock_T *mp;
+ char_u *s;
+#ifdef FEAT_LOCALMAP
+ int local;
+#endif
+
+ validate_maphash();
+
+ len = (int)STRLEN(keys);
+#ifdef FEAT_LOCALMAP
+ for (local = 1; local >= 0; --local)
+#endif
+ /* loop over all hash lists */
+ for (hash = 0; hash < 256; ++hash)
+ {
+ if (abbr)
+ {
+ if (hash > 0) /* there is only one list. */
+ break;
+#ifdef FEAT_LOCALMAP
+ if (local)
+ mp = curbuf->b_first_abbr;
+ else
+#endif
+ mp = first_abbr;
+ }
+#ifdef FEAT_LOCALMAP
+ else if (local)
+ mp = curbuf->b_maphash[hash];
+#endif
+ else
+ mp = maphash[hash];
+ for ( ; mp != NULL; mp = mp->m_next)
+ {
+ /* skip entries with wrong mode, wrong length and not matching
+ * ones */
+ if ((mp->m_mode & mode) && (!exact || mp->m_keylen == len))
+ {
+ if (len > mp->m_keylen)
+ minlen = mp->m_keylen;
+ else
+ minlen = len;
+ s = mp->m_keys;
+ if (ign_mod && s[0] == K_SPECIAL && s[1] == KS_MODIFIER
+ && s[2] != NUL)
+ {
+ s += 3;
+ if (len > mp->m_keylen - 3)
+ minlen = mp->m_keylen - 3;
+ }
+ if (STRNCMP(s, keys, minlen) == 0)
+ {
+ if (mp_ptr != NULL)
+ *mp_ptr = mp;
+ if (local_ptr != NULL)
+#ifdef FEAT_LOCALMAP
+ *local_ptr = local;
+#else
+ *local_ptr = 0;
+#endif
+ return mp->m_str;
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+#endif
+
+#if defined(MSWIN) || defined(MACOS_X)
+
+#define VIS_SEL (VISUAL+SELECTMODE) /* abbreviation */
+
+/*
+ * Default mappings for some often used keys.
+ */
+static struct initmap
+{
+ char_u *arg;
+ int mode;
+} initmappings[] =
+{
+#if defined(MSWIN)
+ /* Use the Windows (CUA) keybindings. */
+# ifdef FEAT_GUI
+ /* paste, copy and cut */
+ {(char_u *)"<S-Insert> \"*P", NORMAL},
+ {(char_u *)"<S-Insert> \"-d\"*P", VIS_SEL},
+ {(char_u *)"<S-Insert> <C-R><C-O>*", INSERT+CMDLINE},
+ {(char_u *)"<C-Insert> \"*y", VIS_SEL},
+ {(char_u *)"<S-Del> \"*d", VIS_SEL},
+ {(char_u *)"<C-Del> \"*d", VIS_SEL},
+ {(char_u *)"<C-X> \"*d", VIS_SEL},
+ /* Missing: CTRL-C (cancel) and CTRL-V (block selection) */
+# else
+ {(char_u *)"\316w <C-Home>", NORMAL+VIS_SEL},
+ {(char_u *)"\316w <C-Home>", INSERT+CMDLINE},
+ {(char_u *)"\316u <C-End>", NORMAL+VIS_SEL},
+ {(char_u *)"\316u <C-End>", INSERT+CMDLINE},
+
+ /* paste, copy and cut */
+# ifdef FEAT_CLIPBOARD
+ {(char_u *)"\316\324 \"*P", NORMAL}, /* SHIFT-Insert is "*P */
+ {(char_u *)"\316\324 \"-d\"*P", VIS_SEL}, /* SHIFT-Insert is "-d"*P */
+ {(char_u *)"\316\324 \022\017*", INSERT}, /* SHIFT-Insert is ^R^O* */
+ {(char_u *)"\316\325 \"*y", VIS_SEL}, /* CTRL-Insert is "*y */
+ {(char_u *)"\316\327 \"*d", VIS_SEL}, /* SHIFT-Del is "*d */
+ {(char_u *)"\316\330 \"*d", VIS_SEL}, /* CTRL-Del is "*d */
+ {(char_u *)"\030 \"-d", VIS_SEL}, /* CTRL-X is "-d */
+# else
+ {(char_u *)"\316\324 P", NORMAL}, /* SHIFT-Insert is P */
+ {(char_u *)"\316\324 \"-dP", VIS_SEL}, /* SHIFT-Insert is "-dP */
+ {(char_u *)"\316\324 \022\017\"", INSERT}, /* SHIFT-Insert is ^R^O" */
+ {(char_u *)"\316\325 y", VIS_SEL}, /* CTRL-Insert is y */
+ {(char_u *)"\316\327 d", VIS_SEL}, /* SHIFT-Del is d */
+ {(char_u *)"\316\330 d", VIS_SEL}, /* CTRL-Del is d */
+# endif
+# endif
+#endif
+
+#if defined(MACOS_X)
+ /* Use the Standard MacOS binding. */
+ /* paste, copy and cut */
+ {(char_u *)"<D-v> \"*P", NORMAL},
+ {(char_u *)"<D-v> \"-d\"*P", VIS_SEL},
+ {(char_u *)"<D-v> <C-R>*", INSERT+CMDLINE},
+ {(char_u *)"<D-c> \"*y", VIS_SEL},
+ {(char_u *)"<D-x> \"*d", VIS_SEL},
+ {(char_u *)"<Backspace> \"-d", VIS_SEL},
+#endif
+};
+
+# undef VIS_SEL
+#endif
+
+/*
+ * Set up default mappings.
+ */
+ void
+init_mappings(void)
+{
+#if defined(MSWIN) || defined(MACOS_X)
+ int i;
+
+ for (i = 0; i < (int)(sizeof(initmappings) / sizeof(struct initmap)); ++i)
+ add_map(initmappings[i].arg, initmappings[i].mode);
+#endif
+}
+
+#if defined(MSWIN) || defined(FEAT_CMDWIN) || defined(MACOS_X) \
+ || defined(PROTO)
+/*
+ * Add a mapping "map" for mode "mode".
+ * Need to put string in allocated memory, because do_map() will modify it.
+ */
+ void
+add_map(char_u *map, int mode)
+{
+ char_u *s;
+ char_u *cpo_save = p_cpo;
+
+ p_cpo = (char_u *)""; /* Allow <> notation */
+ s = vim_strsave(map);
+ if (s != NULL)
+ {
+ (void)do_map(0, s, mode, FALSE);
+ vim_free(s);
+ }
+ p_cpo = cpo_save;
+}
+#endif
diff --git a/src/glbl_ime.cpp b/src/glbl_ime.cpp
new file mode 100644
index 0000000..91d52ed
--- /dev/null
+++ b/src/glbl_ime.cpp
@@ -0,0 +1,263 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * Do ":help uganda" in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ */
+
+/*
+ * DESCRIPTION:
+ * This module produces Global IME for Vim, on Windows with Internet
+ * Explorer 5.01 or higher. You need three files "dimm.idl", "dimm.h", and
+ * "dimm_i.c" when compile this module at your self. "dimm.h", and
+ * "dimm_i.c" are generated from "dimm.idl" by using MIDL.EXE as like
+ * "if_ole.h". You can get "dimm.idl" in MSDN web site. I got it below
+ * URL.
+ *
+ * WHAT IS THE GLOBAL IME?:
+ * Global IME makes capability input Chinese, Japanese, and Korean text into
+ * Vim buffer on any language version of Windows 98, Windows 95, and Windows
+ * NT 4.0. See below URL for detail of Global IME. You can also find
+ * various language version of Global IME at same place.
+ *
+ * RUNTIME REQUIREMENTS:
+ * - Internet Explorer 5.01 or higher.
+ * - Global IME (with language pack?).
+ * - Of course Vim for Windows.
+ *
+ * URLS:
+ * - Where you can probably get "dimm.idl".
+ * http://msdn.microsoft.com/downloads/samples/internet/libraries/ie5_lib/sample.asp
+ * - Global IME detailed information.
+ * http://www.microsoft.com/windows/ie/features/ime.asp
+ */
+
+#ifdef GLOBAL_IME
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <objbase.h>
+extern "C" {
+#include "vim.h"
+}
+#include "dimm.h"
+#include "glbl_ime.h"
+
+static IActiveIMMApp *pIApp = NULL;
+static IActiveIMMMessagePumpOwner *pIMsg = NULL;
+static HWND s_hWnd = NULL;
+static BOOL s_bStatus = FALSE; /* for evacuate */
+
+/*
+ * Initialize Global IME.
+ * "atom" must be return value of RegisterClass(Ex).
+ */
+ void
+global_ime_init(ATOM atom, HWND hWnd)
+{
+ IUnknown *pI;
+ HRESULT hr;
+
+ if (pIApp != NULL || pIMsg != NULL)
+ return;
+ OleInitialize(NULL);
+
+ /*
+ * Get interface IUnknown
+ */
+ hr = CoCreateInstance(CLSID_CActiveIMM, NULL, CLSCTX_SERVER,
+ IID_IUnknown, (void**)&pI);
+ if (FAILED(hr) || !pI)
+ return;
+
+ /*
+ * Get interface IActiveIMMApp
+ */
+ hr = pI->QueryInterface(IID_IActiveIMMApp, (void**)&pIApp);
+ if (FAILED(hr))
+ pIApp = NULL;
+
+ /*
+ * Get interface IActiveIMMMessagePumpOwner
+ */
+ hr = pI->QueryInterface(IID_IActiveIMMMessagePumpOwner, (void**)&pIMsg);
+ if (FAILED(hr))
+ pIMsg = NULL;
+
+ if (pIApp != NULL)
+ {
+ pIApp->Activate(TRUE);
+ pIApp->FilterClientWindows(&atom, 1);
+ }
+ if (pIMsg != NULL)
+ pIMsg->Start();
+
+ pI->Release();
+ s_hWnd = hWnd;
+}
+
+/*
+ * Reset and clear Global IME.
+ */
+ void
+global_ime_end()
+{
+ if (pIApp != NULL)
+ {
+ IActiveIMMApp *p = pIApp;
+
+ pIApp = NULL;
+ p->FilterClientWindows(NULL, 0);
+ p->Deactivate();
+ p->Release();
+ }
+ if (pIMsg != NULL)
+ {
+ IActiveIMMMessagePumpOwner *p = pIMsg;
+
+ pIMsg = NULL;
+ p->End();
+ p->Release();
+ }
+ OleUninitialize();
+}
+
+/*
+ * Replacement for DefWindowProc().
+ */
+ LRESULT WINAPI
+global_ime_DefWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
+{
+ LRESULT lResult;
+
+ if (pIApp == NULL || pIApp->OnDefWindowProc(hWnd, Msg,
+ wParam, lParam, &lResult) != S_OK)
+ {
+#if defined(WIN3264)
+ if (wide_WindowProc)
+ lResult = DefWindowProcW(hWnd, Msg, wParam, lParam);
+ else
+#endif
+ lResult = DefWindowProc(hWnd, Msg, wParam, lParam);
+ }
+ return lResult;
+}
+
+/*
+ * Replace with TranslateMessage()
+ */
+ BOOL WINAPI
+global_ime_TranslateMessage(CONST MSG *lpMsg)
+{
+ if (pIMsg == NULL || pIMsg->OnTranslateMessage(lpMsg) == S_FALSE)
+ return TranslateMessage(lpMsg);
+ return TRUE;
+}
+
+/*
+ * Set position of IME composition window.
+ *
+ * You have to call this before starting composition. If once composition
+ * started, this can take no effect until that composition have finished. So
+ * you should handle WM_IME_STARTCOMPOSITION and call this function.
+ */
+ void WINAPI
+global_ime_set_position(POINT *pPoint)
+{
+ HIMC hImc = NULL;
+
+ if (pIApp == NULL || pPoint == NULL)
+ return;
+
+ if (SUCCEEDED(pIApp->GetContext(s_hWnd, &hImc)))
+ {
+ COMPOSITIONFORM CompForm;
+
+ CompForm.dwStyle = CFS_POINT;
+ CompForm.ptCurrentPos = *pPoint;
+ pIApp->SetCompositionWindow(hImc, &CompForm);
+ pIApp->ReleaseContext(s_hWnd, hImc);
+ }
+}
+
+/*
+ * Set font to Global IME
+ */
+/* GIME_TEST */
+ void WINAPI
+global_ime_set_font(LOGFONT *pFont)
+{
+ HIMC hImc = NULL;
+
+ if (pIApp == NULL || pFont == NULL)
+ return;
+
+ if (SUCCEEDED(pIApp->GetContext(s_hWnd, &hImc)))
+ {
+ pIApp->SetCompositionFontA(hImc, pFont);
+ pIApp->ReleaseContext(s_hWnd, hImc);
+ }
+}
+
+#if 0
+/*
+ * for IME control. Save current status of IME, and set force new-status to
+ * English (turn off).
+ */
+ void WINAPI
+global_ime_status_evacuate()
+{
+ HIMC hImc;
+
+ if (pIApp != NULL && SUCCEEDED(pIApp->GetContext(s_hWnd, &hImc)))
+ {
+ s_bStatus = (pIApp->GetOpenStatus(hImc) == 0) ? TRUE : FALSE;
+ pIApp->SetOpenStatus(hImc, FALSE);
+ pIApp->ReleaseContext(s_hWnd, hImc);
+ }
+}
+
+/*
+ * for IME control. Change IME status to last saved one.
+ */
+ void WINAPI
+global_ime_status_restore()
+{
+ HIMC hImc;
+
+ if (pIApp != NULL && SUCCEEDED(pIApp->GetContext(s_hWnd, &hImc)))
+ {
+ pIApp->SetOpenStatus(hImc, s_bStatus);
+ pIApp->ReleaseContext(s_hWnd, hImc);
+ }
+}
+#endif
+
+ void WINAPI
+global_ime_set_status(int status)
+{
+ HIMC hImc;
+
+ if (pIApp != NULL && SUCCEEDED(pIApp->GetContext(s_hWnd, &hImc)))
+ {
+ pIApp->SetOpenStatus(hImc, status ? TRUE : FALSE);
+ pIApp->ReleaseContext(s_hWnd, hImc);
+ }
+}
+
+ int WINAPI
+global_ime_get_status()
+{
+ int status = 0;
+ HIMC hImc;
+
+ if (pIApp != NULL && SUCCEEDED(pIApp->GetContext(s_hWnd, &hImc)))
+ {
+ status = pIApp->GetOpenStatus(hImc) ? 1 : 0;
+ pIApp->ReleaseContext(s_hWnd, hImc);
+ }
+ return status;
+}
+
+#endif /* GLOBAL_IME */
diff --git a/src/glbl_ime.h b/src/glbl_ime.h
new file mode 100644
index 0000000..45ed07f
--- /dev/null
+++ b/src/glbl_ime.h
@@ -0,0 +1,33 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * Do ":help uganda" in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ */
+
+#ifdef GLOBAL_IME
+#ifndef _INC_GLOBAL_IME
+#define _INC_GLOBAL_IME
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+ void global_ime_init(ATOM, HWND);
+ void global_ime_end(void);
+ LRESULT WINAPI global_ime_DefWindowProc(HWND, UINT, WPARAM, LPARAM);
+ BOOL WINAPI global_ime_TranslateMessage(CONST MSG *);
+ void WINAPI global_ime_set_position(POINT*);
+ void WINAPI global_ime_set_font(LOGFONT*);
+#if 0
+ void WINAPI global_ime_status_evacuate(void);
+ void WINAPI global_ime_status_restore(void);
+#endif
+ void WINAPI global_ime_set_status(int status);
+ int WINAPI global_ime_get_status(void);
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* _INC_GLOBAL_IME */
+#endif /* GLOBAL_IME */
diff --git a/src/globals.h b/src/globals.h
new file mode 100644
index 0000000..6cc3be2
--- /dev/null
+++ b/src/globals.h
@@ -0,0 +1,1670 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * Do ":help uganda" in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ */
+
+/*
+ * definition of global variables
+ */
+
+/*
+ * Number of Rows and Columns in the screen.
+ * Must be long to be able to use them as options in option.c.
+ * Note: Use screen_Rows and screen_Columns to access items in ScreenLines[].
+ * They may have different values when the screen wasn't (re)allocated yet
+ * after setting Rows or Columns (e.g., when starting up).
+ */
+EXTERN long Rows /* nr of rows in the screen */
+#ifdef DO_INIT
+# if defined(WIN3264)
+ = 25L
+# else
+ = 24L
+# endif
+#endif
+ ;
+EXTERN long Columns INIT(= 80); /* nr of columns in the screen */
+
+/*
+ * The characters that are currently on the screen are kept in ScreenLines[].
+ * It is a single block of characters, the size of the screen plus one line.
+ * The attributes for those characters are kept in ScreenAttrs[].
+ *
+ * "LineOffset[n]" is the offset from ScreenLines[] for the start of line 'n'.
+ * The same value is used for ScreenLinesUC[] and ScreenAttrs[].
+ *
+ * Note: before the screen is initialized and when out of memory these can be
+ * NULL.
+ */
+EXTERN schar_T *ScreenLines INIT(= NULL);
+EXTERN sattr_T *ScreenAttrs INIT(= NULL);
+EXTERN unsigned *LineOffset INIT(= NULL);
+EXTERN char_u *LineWraps INIT(= NULL); /* line wraps to next line */
+
+/*
+ * When using Unicode characters (in UTF-8 encoding) the character in
+ * ScreenLinesUC[] contains the Unicode for the character at this position, or
+ * NUL when the character in ScreenLines[] is to be used (ASCII char).
+ * The composing characters are to be drawn on top of the original character.
+ * ScreenLinesC[0][off] is only to be used when ScreenLinesUC[off] != 0.
+ * Note: These three are only allocated when enc_utf8 is set!
+ */
+EXTERN u8char_T *ScreenLinesUC INIT(= NULL); /* decoded UTF-8 characters */
+EXTERN u8char_T *ScreenLinesC[MAX_MCO]; /* composing characters */
+EXTERN int Screen_mco INIT(= 0); /* value of p_mco used when
+ allocating ScreenLinesC[] */
+
+/* Only used for euc-jp: Second byte of a character that starts with 0x8e.
+ * These are single-width. */
+EXTERN schar_T *ScreenLines2 INIT(= NULL);
+
+/*
+ * Indexes for tab page line:
+ * N > 0 for label of tab page N
+ * N == 0 for no label
+ * N < 0 for closing tab page -N
+ * N == -999 for closing current tab page
+ */
+EXTERN short *TabPageIdxs INIT(= NULL);
+
+EXTERN int screen_Rows INIT(= 0); /* actual size of ScreenLines[] */
+EXTERN int screen_Columns INIT(= 0); /* actual size of ScreenLines[] */
+
+/*
+ * When vgetc() is called, it sets mod_mask to the set of modifiers that are
+ * held down based on the MOD_MASK_* symbols that are read first.
+ */
+EXTERN int mod_mask INIT(= 0x0); /* current key modifiers */
+
+/*
+ * Cmdline_row is the row where the command line starts, just below the
+ * last window.
+ * When the cmdline gets longer than the available space the screen gets
+ * scrolled up. After a CTRL-D (show matches), after hitting ':' after
+ * "hit return", and for the :global command, the command line is
+ * temporarily moved. The old position is restored with the next call to
+ * update_screen().
+ */
+EXTERN int cmdline_row;
+
+EXTERN int redraw_cmdline INIT(= FALSE); /* cmdline must be redrawn */
+EXTERN int clear_cmdline INIT(= FALSE); /* cmdline must be cleared */
+EXTERN int mode_displayed INIT(= FALSE); /* mode is being displayed */
+EXTERN int no_win_do_lines_ins INIT(= FALSE); /* don't insert lines */
+#if defined(FEAT_CRYPT) || defined(FEAT_EVAL)
+EXTERN int cmdline_star INIT(= FALSE); /* cmdline is crypted */
+#endif
+
+EXTERN int exec_from_reg INIT(= FALSE); /* executing register */
+
+EXTERN int screen_cleared INIT(= FALSE); /* screen has been cleared */
+
+/*
+ * When '$' is included in 'cpoptions' option set:
+ * When a change command is given that deletes only part of a line, a dollar
+ * is put at the end of the changed text. dollar_vcol is set to the virtual
+ * column of this '$'. -1 is used to indicate no $ is being displayed.
+ */
+EXTERN colnr_T dollar_vcol INIT(= -1);
+
+#ifdef FEAT_INS_EXPAND
+/*
+ * Variables for Insert mode completion.
+ */
+
+/* Length in bytes of the text being completed (this is deleted to be replaced
+ * by the match.) */
+EXTERN int compl_length INIT(= 0);
+
+/* Set when character typed while looking for matches and it means we should
+ * stop looking for matches. */
+EXTERN int compl_interrupted INIT(= FALSE);
+
+/* List of flags for method of completion. */
+EXTERN int compl_cont_status INIT(= 0);
+# define CONT_ADDING 1 /* "normal" or "adding" expansion */
+# define CONT_INTRPT (2 + 4) /* a ^X interrupted the current expansion */
+ /* it's set only iff N_ADDS is set */
+# define CONT_N_ADDS 4 /* next ^X<> will add-new or expand-current */
+# define CONT_S_IPOS 8 /* next ^X<> will set initial_pos?
+ * if so, word-wise-expansion will set SOL */
+# define CONT_SOL 16 /* pattern includes start of line, just for
+ * word-wise expansion, not set for ^X^L */
+# define CONT_LOCAL 32 /* for ctrl_x_mode 0, ^X^P/^X^N do a local
+ * expansion, (eg use complete=.) */
+#endif
+
+/*
+ * Functions for putting characters in the command line,
+ * while keeping ScreenLines[] updated.
+ */
+#ifdef FEAT_RIGHTLEFT
+EXTERN int cmdmsg_rl INIT(= FALSE); /* cmdline is drawn right to left */
+#endif
+EXTERN int msg_col;
+EXTERN int msg_row;
+EXTERN int msg_scrolled; /* Number of screen lines that windows have
+ * scrolled because of printing messages. */
+EXTERN int msg_scrolled_ign INIT(= FALSE);
+ /* when TRUE don't set need_wait_return in
+ msg_puts_attr() when msg_scrolled is
+ non-zero */
+
+EXTERN char_u *keep_msg INIT(= NULL); /* msg to be shown after redraw */
+EXTERN int keep_msg_attr INIT(= 0); /* highlight attr for keep_msg */
+EXTERN int keep_msg_more INIT(= FALSE); /* keep_msg was set by msgmore() */
+EXTERN int need_fileinfo INIT(= FALSE);/* do fileinfo() after redraw */
+EXTERN int msg_scroll INIT(= FALSE); /* msg_start() will scroll */
+EXTERN int msg_didout INIT(= FALSE); /* msg_outstr() was used in line */
+EXTERN int msg_didany INIT(= FALSE); /* msg_outstr() was used at all */
+EXTERN int msg_nowait INIT(= FALSE); /* don't wait for this msg */
+EXTERN int emsg_off INIT(= 0); /* don't display errors for now,
+ unless 'debug' is set. */
+EXTERN int info_message INIT(= FALSE); /* printing informative message */
+EXTERN int msg_hist_off INIT(= FALSE); /* don't add messages to history */
+#ifdef FEAT_EVAL
+EXTERN int need_clr_eos INIT(= FALSE); /* need to clear text before
+ displaying a message. */
+EXTERN int emsg_skip INIT(= 0); /* don't display errors for
+ expression that is skipped */
+EXTERN int emsg_severe INIT(= FALSE); /* use message of next of several
+ emsg() calls for throw */
+EXTERN int did_endif INIT(= FALSE); /* just had ":endif" */
+EXTERN dict_T vimvardict; /* Dictionary with v: variables */
+EXTERN dict_T globvardict; /* Dictionary with g: variables */
+#endif
+EXTERN int did_emsg; /* set by emsg() when the message
+ is displayed or thrown */
+#ifdef FEAT_EVAL
+EXTERN int called_vim_beep; /* set if vim_beep() is called */
+EXTERN int did_uncaught_emsg; /* emsg() was called and did not
+ cause an exception */
+#endif
+EXTERN int did_emsg_syntax; /* did_emsg set because of a
+ syntax error */
+EXTERN int called_emsg; /* always set by emsg() */
+EXTERN int ex_exitval INIT(= 0); /* exit value for ex mode */
+EXTERN int emsg_on_display INIT(= FALSE); /* there is an error message */
+EXTERN int rc_did_emsg INIT(= FALSE); /* vim_regcomp() called emsg() */
+
+EXTERN int no_wait_return INIT(= 0); /* don't wait for return for now */
+EXTERN int need_wait_return INIT(= 0); /* need to wait for return later */
+EXTERN int did_wait_return INIT(= FALSE); /* wait_return() was used and
+ nothing written since then */
+#ifdef FEAT_TITLE
+EXTERN int need_maketitle INIT(= TRUE); /* call maketitle() soon */
+#endif
+
+EXTERN int quit_more INIT(= FALSE); /* 'q' hit at "--more--" msg */
+#if defined(UNIX) || defined(VMS) || defined(MACOS_X)
+EXTERN int newline_on_exit INIT(= FALSE); /* did msg in altern. screen */
+EXTERN int intr_char INIT(= 0); /* extra interrupt character */
+#endif
+#if (defined(UNIX) || defined(VMS)) && defined(FEAT_X11)
+EXTERN int x_no_connect INIT(= FALSE); /* don't connect to X server */
+# if defined(FEAT_CLIENTSERVER)
+EXTERN int x_force_connect INIT(= FALSE); /* Do connect to X server.
+ Overrules x_no_connect and
+ "exclude" in 'clipboard'. */
+# endif
+#endif
+EXTERN int ex_keep_indent INIT(= FALSE); /* getexmodeline(): keep indent */
+EXTERN int vgetc_busy INIT(= 0); /* when inside vgetc() then > 0 */
+
+EXTERN int didset_vim INIT(= FALSE); /* did set $VIM ourselves */
+EXTERN int didset_vimruntime INIT(= FALSE); /* idem for $VIMRUNTIME */
+
+/*
+ * Lines left before a "more" message. Ex mode needs to be able to reset this
+ * after you type something.
+ */
+EXTERN int lines_left INIT(= -1); /* lines left for listing */
+EXTERN int msg_no_more INIT(= FALSE); /* don't use more prompt, truncate
+ messages */
+
+EXTERN char_u *sourcing_name INIT( = NULL);/* name of error message source */
+EXTERN linenr_T sourcing_lnum INIT(= 0); /* line number of the source file */
+
+#ifdef FEAT_EVAL
+EXTERN int ex_nesting_level INIT(= 0); /* nesting level */
+EXTERN int debug_break_level INIT(= -1); /* break below this level */
+EXTERN int debug_did_msg INIT(= FALSE); /* did "debug mode" message */
+EXTERN int debug_tick INIT(= 0); /* breakpoint change count */
+EXTERN int debug_backtrace_level INIT(= 0); /* breakpoint backtrace level */
+# ifdef FEAT_PROFILE
+EXTERN int do_profiling INIT(= PROF_NONE); /* PROF_ values */
+# endif
+
+/*
+ * The exception currently being thrown. Used to pass an exception to
+ * a different cstack. Also used for discarding an exception before it is
+ * caught or made pending. Only valid when did_throw is TRUE.
+ */
+EXTERN except_T *current_exception;
+
+/*
+ * did_throw: An exception is being thrown. Reset when the exception is caught
+ * or as long as it is pending in a finally clause.
+ */
+EXTERN int did_throw INIT(= FALSE);
+
+/*
+ * need_rethrow: set to TRUE when a throw that cannot be handled in do_cmdline()
+ * must be propagated to the cstack of the previously called do_cmdline().
+ */
+EXTERN int need_rethrow INIT(= FALSE);
+
+/*
+ * check_cstack: set to TRUE when a ":finish" or ":return" that cannot be
+ * handled in do_cmdline() must be propagated to the cstack of the previously
+ * called do_cmdline().
+ */
+EXTERN int check_cstack INIT(= FALSE);
+
+/*
+ * Number of nested try conditionals (across function calls and ":source"
+ * commands).
+ */
+EXTERN int trylevel INIT(= 0);
+
+/*
+ * When "force_abort" is TRUE, always skip commands after an error message,
+ * even after the outermost ":endif", ":endwhile" or ":endfor" or for a
+ * function without the "abort" flag. It is set to TRUE when "trylevel" is
+ * non-zero (and ":silent!" was not used) or an exception is being thrown at
+ * the time an error is detected. It is set to FALSE when "trylevel" gets
+ * zero again and there was no error or interrupt or throw.
+ */
+EXTERN int force_abort INIT(= FALSE);
+
+/*
+ * "msg_list" points to a variable in the stack of do_cmdline() which keeps
+ * the list of arguments of several emsg() calls, one of which is to be
+ * converted to an error exception immediately after the failing command
+ * returns. The message to be used for the exception value is pointed to by
+ * the "throw_msg" field of the first element in the list. It is usually the
+ * same as the "msg" field of that element, but can be identical to the "msg"
+ * field of a later list element, when the "emsg_severe" flag was set when the
+ * emsg() call was made.
+ */
+EXTERN struct msglist **msg_list INIT(= NULL);
+
+/*
+ * suppress_errthrow: When TRUE, don't convert an error to an exception. Used
+ * when displaying the interrupt message or reporting an exception that is still
+ * uncaught at the top level (which has already been discarded then). Also used
+ * for the error message when no exception can be thrown.
+ */
+EXTERN int suppress_errthrow INIT(= FALSE);
+
+/*
+ * The stack of all caught and not finished exceptions. The exception on the
+ * top of the stack is the one got by evaluation of v:exception. The complete
+ * stack of all caught and pending exceptions is embedded in the various
+ * cstacks; the pending exceptions, however, are not on the caught stack.
+ */
+EXTERN except_T *caught_stack INIT(= NULL);
+
+#endif
+
+#ifdef FEAT_EVAL
+/*
+ * Garbage collection can only take place when we are sure there are no Lists
+ * or Dictionaries being used internally. This is flagged with
+ * "may_garbage_collect" when we are at the toplevel.
+ * "want_garbage_collect" is set by the garbagecollect() function, which means
+ * we do garbage collection before waiting for a char at the toplevel.
+ * "garbage_collect_at_exit" indicates garbagecollect(1) was called.
+ */
+EXTERN int may_garbage_collect INIT(= FALSE);
+EXTERN int want_garbage_collect INIT(= FALSE);
+EXTERN int garbage_collect_at_exit INIT(= FALSE);
+
+// Script CTX being sourced or was sourced to define the current function.
+EXTERN sctx_T current_sctx INIT(= {0 COMMA 0 COMMA 0});
+#endif
+
+EXTERN int did_source_packages INIT(= FALSE);
+
+/* Magic number used for hashitem "hi_key" value indicating a deleted item.
+ * Only the address is used. */
+EXTERN char_u hash_removed;
+
+
+EXTERN int scroll_region INIT(= FALSE); /* term supports scroll region */
+EXTERN int t_colors INIT(= 0); /* int value of T_CCO */
+
+/*
+ * When highlight_match is TRUE, highlight a match, starting at the cursor
+ * position. Search_match_lines is the number of lines after the match (0 for
+ * a match within one line), search_match_endcol the column number of the
+ * character just after the match in the last line.
+ */
+EXTERN int highlight_match INIT(= FALSE); // show search match pos
+EXTERN linenr_T search_match_lines; // lines of of matched string
+EXTERN colnr_T search_match_endcol; // col nr of match end
+#ifdef FEAT_SEARCH_EXTRA
+EXTERN linenr_T search_first_line INIT(= 0); // for :{FIRST},{last}s/pat
+EXTERN linenr_T search_last_line INIT(= MAXLNUM); // for :{first},{LAST}s/pat
+#endif
+
+EXTERN int no_smartcase INIT(= FALSE); /* don't use 'smartcase' once */
+
+EXTERN int need_check_timestamps INIT(= FALSE); /* need to check file
+ timestamps asap */
+EXTERN int did_check_timestamps INIT(= FALSE); /* did check timestamps
+ recently */
+EXTERN int no_check_timestamps INIT(= 0); /* Don't check timestamps */
+
+EXTERN int highlight_attr[HLF_COUNT]; /* Highl. attr for each context. */
+#ifdef FEAT_STL_OPT
+# define USER_HIGHLIGHT
+#endif
+#ifdef USER_HIGHLIGHT
+EXTERN int highlight_user[9]; /* User[1-9] attributes */
+# ifdef FEAT_STL_OPT
+EXTERN int highlight_stlnc[9]; /* On top of user */
+# ifdef FEAT_TERMINAL
+EXTERN int highlight_stlterm[9]; /* On top of user */
+EXTERN int highlight_stltermnc[9]; /* On top of user */
+# endif
+# endif
+#endif
+#ifdef FEAT_TERMINAL
+ // When TRUE skip calling terminal_loop() once. Used when
+ // typing ':' at the more prompt.
+EXTERN int skip_term_loop INIT(= FALSE);
+#endif
+#ifdef FEAT_GUI
+EXTERN char_u *use_gvimrc INIT(= NULL); /* "-U" cmdline argument */
+#endif
+EXTERN int cterm_normal_fg_color INIT(= 0);
+EXTERN int cterm_normal_fg_bold INIT(= 0);
+EXTERN int cterm_normal_bg_color INIT(= 0);
+#ifdef FEAT_TERMGUICOLORS
+EXTERN guicolor_T cterm_normal_fg_gui_color INIT(= INVALCOLOR);
+EXTERN guicolor_T cterm_normal_bg_gui_color INIT(= INVALCOLOR);
+#endif
+#ifdef FEAT_TERMRESPONSE
+EXTERN int is_mac_terminal INIT(= FALSE); /* recognized Terminal.app */
+#endif
+
+EXTERN int autocmd_busy INIT(= FALSE); /* Is apply_autocmds() busy? */
+EXTERN int autocmd_no_enter INIT(= FALSE); /* *Enter autocmds disabled */
+EXTERN int autocmd_no_leave INIT(= FALSE); /* *Leave autocmds disabled */
+EXTERN int modified_was_set; /* did ":set modified" */
+EXTERN int did_filetype INIT(= FALSE); /* FileType event found */
+EXTERN int au_did_filetype INIT(= FALSE);
+EXTERN int keep_filetype INIT(= FALSE); /* value for did_filetype when
+ starting to execute
+ autocommands */
+
+/* When deleting the current buffer, another one must be loaded. If we know
+ * which one is preferred, au_new_curbuf is set to it */
+EXTERN bufref_T au_new_curbuf INIT(= {NULL COMMA 0 COMMA 0});
+
+/* When deleting a buffer/window and autocmd_busy is TRUE, do not free the
+ * buffer/window. but link it in the list starting with
+ * au_pending_free_buf/ap_pending_free_win, using b_next/w_next.
+ * Free the buffer/window when autocmd_busy is being set to FALSE. */
+EXTERN buf_T *au_pending_free_buf INIT(= NULL);
+EXTERN win_T *au_pending_free_win INIT(= NULL);
+
+#ifdef FEAT_MOUSE
+/*
+ * Mouse coordinates, set by check_termcode()
+ */
+EXTERN int mouse_row;
+EXTERN int mouse_col;
+EXTERN int mouse_past_bottom INIT(= FALSE);/* mouse below last line */
+EXTERN int mouse_past_eol INIT(= FALSE); /* mouse right of line */
+EXTERN int mouse_dragging INIT(= 0); /* extending Visual area with
+ mouse dragging */
+# if defined(FEAT_MOUSE_DEC)
+/*
+ * When the DEC mouse has been pressed but not yet released we enable
+ * automatic querys for the mouse position.
+ */
+EXTERN int WantQueryMouse INIT(= FALSE);
+# endif
+
+# ifdef FEAT_GUI
+/* When the window layout is about to be changed, need_mouse_correct is set,
+ * so that gui_mouse_correct() is called afterwards, to correct the mouse
+ * pointer when focus-follow-mouse is being used. */
+EXTERN int need_mouse_correct INIT(= FALSE);
+
+/* When double clicking, topline must be the same */
+EXTERN linenr_T gui_prev_topline INIT(= 0);
+# ifdef FEAT_DIFF
+EXTERN int gui_prev_topfill INIT(= 0);
+# endif
+# endif
+
+# ifdef FEAT_MOUSESHAPE
+EXTERN int drag_status_line INIT(= FALSE); /* dragging the status line */
+EXTERN int postponed_mouseshape INIT(= FALSE); /* postponed updating the
+ mouse pointer shape */
+EXTERN int drag_sep_line INIT(= FALSE); /* dragging vert separator */
+# endif
+
+#endif
+
+#ifdef FEAT_DIFF
+/* Value set from 'diffopt'. */
+EXTERN int diff_context INIT(= 6); /* context for folds */
+EXTERN int diff_foldcolumn INIT(= 2); /* 'foldcolumn' for diff mode */
+EXTERN int diff_need_scrollbind INIT(= FALSE);
+#endif
+
+#ifdef FEAT_MENU
+/* The root of the menu hierarchy. */
+EXTERN vimmenu_T *root_menu INIT(= NULL);
+/*
+ * While defining the system menu, sys_menu is TRUE. This avoids
+ * overruling of menus that the user already defined.
+ */
+EXTERN int sys_menu INIT(= FALSE);
+#endif
+
+/* While redrawing the screen this flag is set. It means the screen size
+ * ('lines' and 'rows') must not be changed. */
+EXTERN int updating_screen INIT(= FALSE);
+
+#ifdef FEAT_GUI
+# ifdef FEAT_MENU
+/* Menu item just selected, set by check_termcode() */
+EXTERN vimmenu_T *current_menu;
+
+/* Set to TRUE after adding/removing menus to ensure they are updated */
+EXTERN int force_menu_update INIT(= FALSE);
+# endif
+# ifdef FEAT_GUI_TABLINE
+/* Tab in tab pages line just selected, set by check_termcode() */
+EXTERN int current_tab;
+
+/* Menu entry in tab pages line menu just selected, set by check_termcode() */
+EXTERN int current_tabmenu;
+# define TABLINE_MENU_CLOSE 1
+# define TABLINE_MENU_NEW 2
+# define TABLINE_MENU_OPEN 3
+# endif
+
+/* Scrollbar moved and new value, set by check_termcode() */
+EXTERN int current_scrollbar;
+EXTERN long_u scrollbar_value;
+
+/* found "-rv" or "-reverse" in command line args */
+EXTERN int found_reverse_arg INIT(= FALSE);
+
+/* "-fn" or "-font" command line argument */
+EXTERN char *font_argument INIT(= NULL);
+
+# ifdef FEAT_GUI_GTK
+/* "-bg" or "-background" command line argument */
+EXTERN char *background_argument INIT(= NULL);
+
+/* "-fg" or "-foreground" command line argument */
+EXTERN char *foreground_argument INIT(= NULL);
+# endif
+
+/*
+ * While executing external commands or in Ex mode, should not insert GUI
+ * events in the input buffer: Set hold_gui_events to non-zero.
+ *
+ * volatile because it is used in signal handler sig_sysmouse().
+ */
+EXTERN volatile sig_atomic_t hold_gui_events INIT(= 0);
+
+/*
+ * When resizing the shell is postponed, remember the new size, and call
+ * gui_resize_shell() later.
+ */
+EXTERN int new_pixel_width INIT(= 0);
+EXTERN int new_pixel_height INIT(= 0);
+
+/* Window position from ":winpos", to be used when opening the GUI window. */
+EXTERN int gui_win_x INIT(= -1);
+EXTERN int gui_win_y INIT(= -1);
+#endif
+
+#ifdef FEAT_CLIPBOARD
+EXTERN VimClipboard clip_star; /* PRIMARY selection in X11 */
+# ifdef FEAT_X11
+EXTERN VimClipboard clip_plus; /* CLIPBOARD selection in X11 */
+# else
+# define clip_plus clip_star /* there is only one clipboard */
+# define ONE_CLIPBOARD
+# endif
+
+# define CLIP_UNNAMED 1
+# define CLIP_UNNAMED_PLUS 2
+EXTERN int clip_unnamed INIT(= 0); /* above two values or'ed */
+
+EXTERN int clip_autoselect_star INIT(= FALSE);
+EXTERN int clip_autoselect_plus INIT(= FALSE);
+EXTERN int clip_autoselectml INIT(= FALSE);
+EXTERN int clip_html INIT(= FALSE);
+EXTERN regprog_T *clip_exclude_prog INIT(= NULL);
+EXTERN int clip_unnamed_saved INIT(= 0);
+#endif
+
+/*
+ * All windows are linked in a list. firstwin points to the first entry,
+ * lastwin to the last entry (can be the same as firstwin) and curwin to the
+ * currently active window.
+ */
+EXTERN win_T *firstwin; /* first window */
+EXTERN win_T *lastwin; /* last window */
+EXTERN win_T *prevwin INIT(= NULL); /* previous window */
+# define ONE_WINDOW (firstwin == lastwin)
+# define W_NEXT(wp) ((wp)->w_next)
+# define FOR_ALL_WINDOWS(wp) for (wp = firstwin; wp != NULL; wp = wp->w_next)
+# define FOR_ALL_FRAMES(frp, first_frame) \
+ for (frp = first_frame; frp != NULL; frp = frp->fr_next)
+# define FOR_ALL_TABPAGES(tp) for (tp = first_tabpage; tp != NULL; tp = tp->tp_next)
+# define FOR_ALL_WINDOWS_IN_TAB(tp, wp) \
+ for ((wp) = ((tp) == NULL || (tp) == curtab) \
+ ? firstwin : (tp)->tp_firstwin; (wp); (wp) = (wp)->w_next)
+/*
+ * When using this macro "break" only breaks out of the inner loop. Use "goto"
+ * to break out of the tabpage loop.
+ */
+# define FOR_ALL_TAB_WINDOWS(tp, wp) \
+ for ((tp) = first_tabpage; (tp) != NULL; (tp) = (tp)->tp_next) \
+ for ((wp) = ((tp) == curtab) \
+ ? firstwin : (tp)->tp_firstwin; (wp); (wp) = (wp)->w_next)
+
+EXTERN win_T *curwin; /* currently active window */
+
+EXTERN win_T *aucmd_win; /* window used in aucmd_prepbuf() */
+EXTERN int aucmd_win_used INIT(= FALSE); /* aucmd_win is being used */
+
+/*
+ * The window layout is kept in a tree of frames. topframe points to the top
+ * of the tree.
+ */
+EXTERN frame_T *topframe; /* top of the window frame tree */
+
+/*
+ * Tab pages are alternative topframes. "first_tabpage" points to the first
+ * one in the list, "curtab" is the current one.
+ */
+EXTERN tabpage_T *first_tabpage;
+EXTERN tabpage_T *curtab;
+EXTERN int redraw_tabline INIT(= FALSE); /* need to redraw tabline */
+
+/*
+ * All buffers are linked in a list. 'firstbuf' points to the first entry,
+ * 'lastbuf' to the last entry and 'curbuf' to the currently active buffer.
+ */
+EXTERN buf_T *firstbuf INIT(= NULL); /* first buffer */
+EXTERN buf_T *lastbuf INIT(= NULL); /* last buffer */
+EXTERN buf_T *curbuf INIT(= NULL); /* currently active buffer */
+
+#define FOR_ALL_BUFFERS(buf) for (buf = firstbuf; buf != NULL; buf = buf->b_next)
+
+// Iterate through all the signs placed in a buffer
+#define FOR_ALL_SIGNS_IN_BUF(buf, sign) \
+ for (sign = buf->b_signlist; sign != NULL; sign = sign->next)
+
+/* Flag that is set when switching off 'swapfile'. It means that all blocks
+ * are to be loaded into memory. Shouldn't be global... */
+EXTERN int mf_dont_release INIT(= FALSE); /* don't release blocks */
+
+/*
+ * List of files being edited (global argument list). curwin->w_alist points
+ * to this when the window is using the global argument list.
+ */
+EXTERN alist_T global_alist; /* global argument list */
+EXTERN int max_alist_id INIT(= 0); /* the previous argument list id */
+EXTERN int arg_had_last INIT(= FALSE); /* accessed last file in
+ global_alist */
+
+EXTERN int ru_col; /* column for ruler */
+#ifdef FEAT_STL_OPT
+EXTERN int ru_wid; /* 'rulerfmt' width of ruler when non-zero */
+#endif
+EXTERN int sc_col; /* column for shown command */
+
+#ifdef TEMPDIRNAMES
+EXTERN char_u *vim_tempdir INIT(= NULL); /* Name of Vim's own temp dir.
+ Ends in a slash. */
+#endif
+
+/*
+ * When starting or exiting some things are done differently (e.g. screen
+ * updating).
+ */
+EXTERN int starting INIT(= NO_SCREEN);
+ /* first NO_SCREEN, then NO_BUFFERS and then
+ * set to 0 when starting up finished */
+EXTERN int exiting INIT(= FALSE);
+ /* TRUE when planning to exit Vim. Might
+ * still keep on running if there is a changed
+ * buffer. */
+EXTERN int really_exiting INIT(= FALSE);
+ /* TRUE when we are sure to exit, e.g., after
+ * a deadly signal */
+EXTERN int v_dying INIT(= 0); /* internal value of v:dying */
+EXTERN int stdout_isatty INIT(= TRUE); /* is stdout a terminal? */
+
+#if defined(FEAT_AUTOCHDIR)
+EXTERN int test_autochdir INIT(= FALSE);
+#endif
+#if defined(EXITFREE)
+EXTERN int entered_free_all_mem INIT(= FALSE);
+ /* TRUE when in or after free_all_mem() */
+#endif
+/* volatile because it is used in signal handler deathtrap(). */
+EXTERN volatile sig_atomic_t full_screen INIT(= FALSE);
+ /* TRUE when doing full-screen output
+ * otherwise only writing some messages */
+
+EXTERN int restricted INIT(= FALSE);
+ /* TRUE when started as "rvim" */
+EXTERN int secure INIT(= FALSE);
+ /* non-zero when only "safe" commands are
+ * allowed, e.g. when sourcing .exrc or .vimrc
+ * in current directory */
+
+EXTERN int textlock INIT(= 0);
+ /* non-zero when changing text and jumping to
+ * another window or buffer is not allowed */
+
+EXTERN int curbuf_lock INIT(= 0);
+ /* non-zero when the current buffer can't be
+ * changed. Used for FileChangedRO. */
+EXTERN int allbuf_lock INIT(= 0);
+ /* non-zero when no buffer name can be
+ * changed, no buffer can be deleted and
+ * current directory can't be changed.
+ * Used for SwapExists et al. */
+#ifdef HAVE_SANDBOX
+EXTERN int sandbox INIT(= 0);
+ /* Non-zero when evaluating an expression in a
+ * "sandbox". Several things are not allowed
+ * then. */
+#endif
+
+EXTERN int silent_mode INIT(= FALSE);
+ /* set to TRUE when "-s" commandline argument
+ * used for ex */
+
+EXTERN pos_T VIsual; /* start position of active Visual selection */
+EXTERN int VIsual_active INIT(= FALSE);
+ /* whether Visual mode is active */
+EXTERN int VIsual_select INIT(= FALSE);
+ /* whether Select mode is active */
+EXTERN int VIsual_reselect;
+ /* whether to restart the selection after a
+ * Select mode mapping or menu */
+
+EXTERN int VIsual_mode INIT(= 'v');
+ /* type of Visual mode */
+
+EXTERN int redo_VIsual_busy INIT(= FALSE);
+ /* TRUE when redoing Visual */
+
+#ifdef FEAT_MOUSE
+/*
+ * When pasting text with the middle mouse button in visual mode with
+ * restart_edit set, remember where it started so we can set Insstart.
+ */
+EXTERN pos_T where_paste_started;
+#endif
+
+/*
+ * This flag is used to make auto-indent work right on lines where only a
+ * <RETURN> or <ESC> is typed. It is set when an auto-indent is done, and
+ * reset when any other editing is done on the line. If an <ESC> or <RETURN>
+ * is received, and did_ai is TRUE, the line is truncated.
+ */
+EXTERN int did_ai INIT(= FALSE);
+
+/*
+ * Column of first char after autoindent. 0 when no autoindent done. Used
+ * when 'backspace' is 0, to avoid backspacing over autoindent.
+ */
+EXTERN colnr_T ai_col INIT(= 0);
+
+#ifdef FEAT_COMMENTS
+/*
+ * This is a character which will end a start-middle-end comment when typed as
+ * the first character on a new line. It is taken from the last character of
+ * the "end" comment leader when the COM_AUTO_END flag is given for that
+ * comment end in 'comments'. It is only valid when did_ai is TRUE.
+ */
+EXTERN int end_comment_pending INIT(= NUL);
+#endif
+
+/*
+ * This flag is set after a ":syncbind" to let the check_scrollbind() function
+ * know that it should not attempt to perform scrollbinding due to the scroll
+ * that was a result of the ":syncbind." (Otherwise, check_scrollbind() will
+ * undo some of the work done by ":syncbind.") -ralston
+ */
+EXTERN int did_syncbind INIT(= FALSE);
+
+#ifdef FEAT_SMARTINDENT
+/*
+ * This flag is set when a smart indent has been performed. When the next typed
+ * character is a '{' the inserted tab will be deleted again.
+ */
+EXTERN int did_si INIT(= FALSE);
+
+/*
+ * This flag is set after an auto indent. If the next typed character is a '}'
+ * one indent will be removed.
+ */
+EXTERN int can_si INIT(= FALSE);
+
+/*
+ * This flag is set after an "O" command. If the next typed character is a '{'
+ * one indent will be removed.
+ */
+EXTERN int can_si_back INIT(= FALSE);
+#endif
+
+EXTERN pos_T saved_cursor /* w_cursor before formatting text. */
+#ifdef DO_INIT
+ = {0, 0, 0}
+#endif
+ ;
+
+/*
+ * Stuff for insert mode.
+ */
+EXTERN pos_T Insstart; /* This is where the latest
+ * insert/append mode started. */
+
+/* This is where the latest insert/append mode started. In contrast to
+ * Insstart, this won't be reset by certain keys and is needed for
+ * op_insert(), to detect correctly where inserting by the user started. */
+EXTERN pos_T Insstart_orig;
+
+/*
+ * Stuff for VREPLACE mode.
+ */
+EXTERN int orig_line_count INIT(= 0); /* Line count when "gR" started */
+EXTERN int vr_lines_changed INIT(= 0); /* #Lines changed by "gR" so far */
+
+#if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
+/* argument to SETJMP() for handling X IO errors */
+EXTERN JMP_BUF x_jump_env;
+#endif
+
+/*
+ * These flags are set based upon 'fileencoding'.
+ * Note that "enc_utf8" is also set for "unicode", because the characters are
+ * internally stored as UTF-8 (to avoid trouble with NUL bytes).
+ */
+#define DBCS_JPN 932 /* japan */
+#define DBCS_JPNU 9932 /* euc-jp */
+#define DBCS_KOR 949 /* korea */
+#define DBCS_KORU 9949 /* euc-kr */
+#define DBCS_CHS 936 /* chinese */
+#define DBCS_CHSU 9936 /* euc-cn */
+#define DBCS_CHT 950 /* taiwan */
+#define DBCS_CHTU 9950 /* euc-tw */
+#define DBCS_2BYTE 1 /* 2byte- */
+#define DBCS_DEBUG -1
+
+EXTERN int enc_dbcs INIT(= 0); /* One of DBCS_xxx values if
+ DBCS encoding */
+EXTERN int enc_unicode INIT(= 0); /* 2: UCS-2 or UTF-16, 4: UCS-4 */
+EXTERN int enc_utf8 INIT(= FALSE); /* UTF-8 encoded Unicode */
+EXTERN int enc_latin1like INIT(= TRUE); /* 'encoding' is latin1 comp. */
+#if defined(WIN3264) || defined(FEAT_CYGWIN_WIN32_CLIPBOARD)
+/* Codepage nr of 'encoding'. Negative means it's not been set yet, zero
+ * means 'encoding' is not a valid codepage. */
+EXTERN int enc_codepage INIT(= -1);
+EXTERN int enc_latin9 INIT(= FALSE); /* 'encoding' is latin9 */
+#endif
+EXTERN int has_mbyte INIT(= 0); /* any multi-byte encoding */
+
+#if defined(WIN3264)
+EXTERN int wide_WindowProc INIT(= FALSE); /* use wide WindowProc() */
+#endif
+
+/*
+ * To speed up BYTELEN() we fill a table with the byte lengths whenever
+ * enc_utf8 or enc_dbcs changes.
+ */
+EXTERN char mb_bytelen_tab[256];
+
+/* Variables that tell what conversion is used for keyboard input and display
+ * output. */
+EXTERN vimconv_T input_conv; /* type of input conversion */
+EXTERN vimconv_T output_conv; /* type of output conversion */
+
+/*
+ * Function pointers, used to quickly get to the right function. Each has
+ * three possible values: latin_ (8-bit), utfc_ or utf_ (utf-8) and dbcs_
+ * (DBCS).
+ * The value is set in mb_init();
+ */
+/* length of char in bytes, including following composing chars */
+EXTERN int (*mb_ptr2len)(char_u *p) INIT(= latin_ptr2len);
+/* idem, with limit on string length */
+EXTERN int (*mb_ptr2len_len)(char_u *p, int size) INIT(= latin_ptr2len_len);
+/* byte length of char */
+EXTERN int (*mb_char2len)(int c) INIT(= latin_char2len);
+/* convert char to bytes, return the length */
+EXTERN int (*mb_char2bytes)(int c, char_u *buf) INIT(= latin_char2bytes);
+EXTERN int (*mb_ptr2cells)(char_u *p) INIT(= latin_ptr2cells);
+EXTERN int (*mb_ptr2cells_len)(char_u *p, int size) INIT(= latin_ptr2cells_len);
+EXTERN int (*mb_char2cells)(int c) INIT(= latin_char2cells);
+EXTERN int (*mb_off2cells)(unsigned off, unsigned max_off) INIT(= latin_off2cells);
+EXTERN int (*mb_ptr2char)(char_u *p) INIT(= latin_ptr2char);
+EXTERN int (*mb_head_off)(char_u *base, char_u *p) INIT(= latin_head_off);
+
+# if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
+/* Pointers to functions and variables to be loaded at runtime */
+EXTERN size_t (*iconv) (iconv_t cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft);
+EXTERN iconv_t (*iconv_open) (const char *tocode, const char *fromcode);
+EXTERN int (*iconv_close) (iconv_t cd);
+EXTERN int (*iconvctl) (iconv_t cd, int request, void *argument);
+EXTERN int* (*iconv_errno) (void);
+# endif
+
+
+#ifdef FEAT_XIM
+# ifdef FEAT_GUI_GTK
+EXTERN GtkIMContext *xic INIT(= NULL);
+/*
+ * Start and end column of the preedit area in virtual columns from the start
+ * of the text line. When there is no preedit area they are set to MAXCOL.
+ * "preedit_end_col" is needed for coloring the preedited string. Drawing the
+ * color between "preedit_start_col" and curpos did not work, because some XIM
+ * set the cursor position to the first char of the string.
+ */
+EXTERN colnr_T preedit_start_col INIT(= MAXCOL);
+EXTERN colnr_T preedit_end_col INIT(= MAXCOL);
+
+/* "xim_changed_while_preediting" is set when changed() can set the 'modified'
+ * flag even while preediting. */
+EXTERN int xim_changed_while_preediting INIT(= FALSE);
+# else
+EXTERN XIC xic INIT(= NULL);
+# endif
+# ifdef FEAT_GUI
+EXTERN guicolor_T xim_fg_color INIT(= INVALCOLOR);
+EXTERN guicolor_T xim_bg_color INIT(= INVALCOLOR);
+# endif
+#endif
+
+#ifdef FEAT_HANGULIN
+EXTERN int composing_hangul INIT(= 0);
+EXTERN char_u composing_hangul_buffer[5];
+#endif
+
+/*
+ * "State" is the main state of Vim.
+ * There are other variables that modify the state:
+ * "Visual_mode" When State is NORMAL or INSERT.
+ * "finish_op" When State is NORMAL, after typing the operator and before
+ * typing the motion command.
+ * "motion_force" Last motion_force from do_pending_operator()
+ * "debug_mode" Debug mode.
+ */
+EXTERN int State INIT(= NORMAL); /* This is the current state of the
+ * command interpreter. */
+#ifdef FEAT_EVAL
+EXTERN int debug_mode INIT(= FALSE);
+#endif
+
+EXTERN int finish_op INIT(= FALSE);/* TRUE while an operator is pending */
+EXTERN long opcount INIT(= 0); /* count for pending operator */
+EXTERN int motion_force INIT(= 0); // motion force for pending operator
+
+/*
+ * Ex mode (Q) state
+ */
+EXTERN int exmode_active INIT(= 0); /* zero, EXMODE_NORMAL or EXMODE_VIM */
+EXTERN int ex_no_reprint INIT(= FALSE); /* no need to print after z or p */
+
+EXTERN int reg_recording INIT(= 0); /* register for recording or zero */
+EXTERN int reg_executing INIT(= 0); /* register being executed or zero */
+
+EXTERN int no_mapping INIT(= FALSE); /* currently no mapping allowed */
+EXTERN int no_zero_mapping INIT(= 0); /* mapping zero not allowed */
+EXTERN int allow_keys INIT(= FALSE); /* allow key codes when no_mapping
+ * is set */
+EXTERN int no_u_sync INIT(= 0); /* Don't call u_sync() */
+#ifdef FEAT_EVAL
+EXTERN int u_sync_once INIT(= 0); /* Call u_sync() once when evaluating
+ an expression. */
+#endif
+
+EXTERN int restart_edit INIT(= 0); /* call edit when next cmd finished */
+EXTERN int arrow_used; /* Normally FALSE, set to TRUE after
+ * hitting cursor key in insert mode.
+ * Used by vgetorpeek() to decide when
+ * to call u_sync() */
+EXTERN int ins_at_eol INIT(= FALSE); /* put cursor after eol when
+ restarting edit after CTRL-O */
+#ifdef FEAT_INS_EXPAND
+EXTERN char_u *edit_submode INIT(= NULL); /* msg for CTRL-X submode */
+EXTERN char_u *edit_submode_pre INIT(= NULL); /* prepended to edit_submode */
+EXTERN char_u *edit_submode_extra INIT(= NULL);/* appended to edit_submode */
+EXTERN hlf_T edit_submode_highl; /* highl. method for extra info */
+#endif
+
+EXTERN int no_abbr INIT(= TRUE); /* TRUE when no abbreviations loaded */
+
+#ifdef USE_EXE_NAME
+EXTERN char_u *exe_name; /* the name of the executable */
+#endif
+
+#ifdef USE_ON_FLY_SCROLL
+EXTERN int dont_scroll INIT(= FALSE);/* don't use scrollbars when TRUE */
+#endif
+EXTERN int mapped_ctrl_c INIT(= FALSE); /* modes where CTRL-C is mapped */
+EXTERN int ctrl_c_interrupts INIT(= TRUE); /* CTRL-C sets got_int */
+
+EXTERN cmdmod_T cmdmod; /* Ex command modifiers */
+
+EXTERN int msg_silent INIT(= 0); /* don't print messages */
+EXTERN int emsg_silent INIT(= 0); /* don't print error messages */
+EXTERN int emsg_noredir INIT(= 0); /* don't redirect error messages */
+EXTERN int cmd_silent INIT(= FALSE); /* don't echo the command line */
+
+# define HAS_SWAP_EXISTS_ACTION
+EXTERN int swap_exists_action INIT(= SEA_NONE);
+ /* For dialog when swap file already
+ * exists. */
+EXTERN int swap_exists_did_quit INIT(= FALSE);
+ /* Selected "quit" at the dialog. */
+
+EXTERN char_u *IObuff; /* sprintf's are done in this buffer,
+ size is IOSIZE */
+EXTERN char_u *NameBuff; /* file names are expanded in this
+ * buffer, size is MAXPATHL */
+EXTERN char msg_buf[MSG_BUF_LEN]; /* small buffer for messages */
+
+/* When non-zero, postpone redrawing. */
+EXTERN int RedrawingDisabled INIT(= 0);
+
+EXTERN int readonlymode INIT(= FALSE); /* Set to TRUE for "view" */
+EXTERN int recoverymode INIT(= FALSE); /* Set to TRUE for "-r" option */
+
+EXTERN typebuf_T typebuf /* typeahead buffer */
+#ifdef DO_INIT
+ = {NULL, NULL, 0, 0, 0, 0, 0, 0, 0}
+#endif
+ ;
+EXTERN int ex_normal_busy INIT(= 0); /* recursiveness of ex_normal() */
+EXTERN int ex_normal_lock INIT(= 0); /* forbid use of ex_normal() */
+#ifdef FEAT_EVAL
+EXTERN int ignore_script INIT(= FALSE); /* ignore script input */
+#endif
+EXTERN int stop_insert_mode; /* for ":stopinsert" and 'insertmode' */
+
+EXTERN int KeyTyped; /* TRUE if user typed current char */
+EXTERN int KeyStuffed; /* TRUE if current char from stuffbuf */
+#ifdef HAVE_INPUT_METHOD
+EXTERN int vgetc_im_active; /* Input Method was active for last
+ character obtained from vgetc() */
+#endif
+EXTERN int maptick INIT(= 0); /* tick for each non-mapped char */
+
+EXTERN int must_redraw INIT(= 0); /* type of redraw necessary */
+EXTERN int skip_redraw INIT(= FALSE); /* skip redraw once */
+EXTERN int do_redraw INIT(= FALSE); /* extra redraw once */
+
+EXTERN int need_highlight_changed INIT(= TRUE);
+
+#define NSCRIPT 15
+EXTERN FILE *scriptin[NSCRIPT]; /* streams to read script from */
+EXTERN int curscript INIT(= 0); /* index in scriptin[] */
+EXTERN FILE *scriptout INIT(= NULL); /* stream to write script to */
+EXTERN int read_cmd_fd INIT(= 0); /* fd to read commands from */
+
+/* volatile because it is used in signal handler catch_sigint(). */
+EXTERN volatile sig_atomic_t got_int INIT(= FALSE); /* set to TRUE when interrupt
+ signal occurred */
+#ifdef USE_TERM_CONSOLE
+EXTERN int term_console INIT(= FALSE); /* set to TRUE when console used */
+#endif
+EXTERN int termcap_active INIT(= FALSE); /* set by starttermcap() */
+EXTERN int cur_tmode INIT(= TMODE_COOK); /* input terminal mode */
+EXTERN int bangredo INIT(= FALSE); /* set to TRUE with ! command */
+EXTERN int searchcmdlen; /* length of previous search cmd */
+#ifdef FEAT_SYN_HL
+EXTERN int reg_do_extmatch INIT(= 0); /* Used when compiling regexp:
+ * REX_SET to allow \z\(...\),
+ * REX_USE to allow \z\1 et al. */
+EXTERN reg_extmatch_T *re_extmatch_in INIT(= NULL); /* Used by vim_regexec():
+ * strings for \z\1...\z\9 */
+EXTERN reg_extmatch_T *re_extmatch_out INIT(= NULL); /* Set by vim_regexec()
+ * to store \z\(...\) matches */
+#endif
+
+EXTERN int did_outofmem_msg INIT(= FALSE);
+ /* set after out of memory msg */
+EXTERN int did_swapwrite_msg INIT(= FALSE);
+ /* set after swap write error msg */
+EXTERN int undo_off INIT(= FALSE); /* undo switched off for now */
+EXTERN int global_busy INIT(= 0); /* set when :global is executing */
+EXTERN int listcmd_busy INIT(= FALSE); /* set when :argdo, :windo or
+ :bufdo is executing */
+EXTERN int need_start_insertmode INIT(= FALSE);
+ /* start insert mode soon */
+EXTERN char_u *last_cmdline INIT(= NULL); /* last command line (for ":) */
+EXTERN char_u *repeat_cmdline INIT(= NULL); /* command line for "." */
+#ifdef FEAT_CMDHIST
+EXTERN char_u *new_last_cmdline INIT(= NULL); /* new value for last_cmdline */
+#endif
+EXTERN char_u *autocmd_fname INIT(= NULL); /* fname for <afile> on cmdline */
+EXTERN int autocmd_fname_full; /* autocmd_fname is full path */
+EXTERN int autocmd_bufnr INIT(= 0); /* fnum for <abuf> on cmdline */
+EXTERN char_u *autocmd_match INIT(= NULL); /* name for <amatch> on cmdline */
+EXTERN int did_cursorhold INIT(= FALSE); /* set when CursorHold t'gerd */
+EXTERN pos_T last_cursormoved /* for CursorMoved event */
+# ifdef DO_INIT
+ = {0, 0, 0}
+# endif
+ ;
+
+EXTERN int postponed_split INIT(= 0); /* for CTRL-W CTRL-] command */
+EXTERN int postponed_split_flags INIT(= 0); /* args for win_split() */
+EXTERN int postponed_split_tab INIT(= 0); /* cmdmod.tab */
+#ifdef FEAT_QUICKFIX
+EXTERN int g_do_tagpreview INIT(= 0); /* for tag preview commands:
+ height of preview window */
+#endif
+EXTERN int replace_offset INIT(= 0); /* offset for replace_push() */
+
+EXTERN char_u *escape_chars INIT(= (char_u *)" \t\\\"|");
+ /* need backslash in cmd line */
+
+EXTERN int keep_help_flag INIT(= FALSE); /* doing :ta from help file */
+
+/*
+ * When a string option is NULL (which only happens in out-of-memory
+ * situations), it is set to empty_option, to avoid having to check for NULL
+ * everywhere.
+ */
+EXTERN char_u *empty_option INIT(= (char_u *)"");
+
+EXTERN int redir_off INIT(= FALSE); /* no redirection for a moment */
+EXTERN FILE *redir_fd INIT(= NULL); /* message redirection file */
+#ifdef FEAT_EVAL
+EXTERN int redir_reg INIT(= 0); /* message redirection register */
+EXTERN int redir_vname INIT(= 0); /* message redirection variable */
+EXTERN int redir_execute INIT(= 0); /* execute() redirection */
+#endif
+
+#ifdef FEAT_LANGMAP
+EXTERN char_u langmap_mapchar[256]; /* mapping for language keys */
+#endif
+
+#ifdef FEAT_WILDMENU
+EXTERN int save_p_ls INIT(= -1); /* Save 'laststatus' setting */
+EXTERN int save_p_wmh INIT(= -1); /* Save 'winminheight' setting */
+EXTERN int wild_menu_showing INIT(= 0);
+# define WM_SHOWN 1 /* wildmenu showing */
+# define WM_SCROLLED 2 /* wildmenu showing with scroll */
+#endif
+
+#ifdef MSWIN
+EXTERN char_u toupper_tab[256]; /* table for toupper() */
+EXTERN char_u tolower_tab[256]; /* table for tolower() */
+#endif
+
+#ifdef FEAT_LINEBREAK
+EXTERN char breakat_flags[256]; /* which characters are in 'breakat' */
+#endif
+
+/* These are in version.c, call init_longVersion() before use. */
+extern char *Version;
+#if defined(HAVE_DATE_TIME) && defined(VMS) && defined(VAXC)
+extern char longVersion[];
+#else
+EXTERN char *longVersion;
+#endif
+
+/*
+ * Some file names are stored in pathdef.c, which is generated from the
+ * Makefile to make their value depend on the Makefile.
+ */
+#ifdef HAVE_PATHDEF
+extern char_u *default_vim_dir;
+extern char_u *default_vimruntime_dir;
+extern char_u *all_cflags;
+extern char_u *all_lflags;
+# ifdef VMS
+extern char_u *compiler_version;
+extern char_u *compiled_arch;
+# endif
+extern char_u *compiled_user;
+extern char_u *compiled_sys;
+#endif
+
+/* When a window has a local directory, the absolute path of the global
+ * current directory is stored here (in allocated memory). If the current
+ * directory is not a local directory, globaldir is NULL. */
+EXTERN char_u *globaldir INIT(= NULL);
+
+/* Characters from 'listchars' option */
+EXTERN int lcs_eol INIT(= '$');
+EXTERN int lcs_ext INIT(= NUL);
+EXTERN int lcs_prec INIT(= NUL);
+EXTERN int lcs_nbsp INIT(= NUL);
+EXTERN int lcs_space INIT(= NUL);
+EXTERN int lcs_tab1 INIT(= NUL);
+EXTERN int lcs_tab2 INIT(= NUL);
+EXTERN int lcs_tab3 INIT(= NUL);
+EXTERN int lcs_trail INIT(= NUL);
+#ifdef FEAT_CONCEAL
+EXTERN int lcs_conceal INIT(= ' ');
+#endif
+
+/* Characters from 'fillchars' option */
+EXTERN int fill_stl INIT(= ' ');
+EXTERN int fill_stlnc INIT(= ' ');
+EXTERN int fill_vert INIT(= ' ');
+EXTERN int fill_fold INIT(= '-');
+EXTERN int fill_diff INIT(= '-');
+
+#ifdef FEAT_FOLDING
+EXTERN int disable_fold_update INIT(= 0);
+#endif
+
+/* Whether 'keymodel' contains "stopsel" and "startsel". */
+EXTERN int km_stopsel INIT(= FALSE);
+EXTERN int km_startsel INIT(= FALSE);
+
+#ifdef FEAT_CMDWIN
+EXTERN int cedit_key INIT(= -1); /* key value of 'cedit' option */
+EXTERN int cmdwin_type INIT(= 0); /* type of cmdline window or 0 */
+EXTERN int cmdwin_result INIT(= 0); /* result of cmdline window or 0 */
+#endif
+
+EXTERN char_u no_lines_msg[] INIT(= N_("--No lines in buffer--"));
+
+/*
+ * When ":global" is used to number of substitutions and changed lines is
+ * accumulated until it's finished.
+ * Also used for ":spellrepall".
+ */
+EXTERN long sub_nsubs; /* total number of substitutions */
+EXTERN linenr_T sub_nlines; /* total number of lines changed */
+
+/* table to store parsed 'wildmode' */
+EXTERN char_u wim_flags[4];
+
+#if defined(FEAT_TITLE) && defined(FEAT_STL_OPT)
+/* whether titlestring and iconstring contains statusline syntax */
+# define STL_IN_ICON 1
+# define STL_IN_TITLE 2
+EXTERN int stl_syntax INIT(= 0);
+#endif
+
+#ifdef FEAT_SEARCH_EXTRA
+/* don't use 'hlsearch' temporarily */
+EXTERN int no_hlsearch INIT(= FALSE);
+#endif
+
+#if defined(FEAT_BEVAL) && !defined(NO_X11_INCLUDES)
+EXTERN BalloonEval *balloonEval INIT(= NULL);
+EXTERN int balloonEvalForTerm INIT(= FALSE);
+# if defined(FEAT_NETBEANS_INTG)
+EXTERN int bevalServers INIT(= 0);
+# define BEVAL_NETBEANS 0x01
+# endif
+#endif
+
+#ifdef CURSOR_SHAPE
+/* the table is in misc2.c, because of initializations */
+extern cursorentry_T shape_table[SHAPE_IDX_COUNT];
+#endif
+
+#ifdef FEAT_PRINTER
+/*
+ * Printer stuff shared between hardcopy.c and machine-specific printing code.
+ */
+# define OPT_PRINT_TOP 0
+# define OPT_PRINT_BOT 1
+# define OPT_PRINT_LEFT 2
+# define OPT_PRINT_RIGHT 3
+# define OPT_PRINT_HEADERHEIGHT 4
+# define OPT_PRINT_SYNTAX 5
+# define OPT_PRINT_NUMBER 6
+# define OPT_PRINT_WRAP 7
+# define OPT_PRINT_DUPLEX 8
+# define OPT_PRINT_PORTRAIT 9
+# define OPT_PRINT_PAPER 10
+# define OPT_PRINT_COLLATE 11
+# define OPT_PRINT_JOBSPLIT 12
+# define OPT_PRINT_FORMFEED 13
+
+# define OPT_PRINT_NUM_OPTIONS 14
+
+EXTERN option_table_T printer_opts[OPT_PRINT_NUM_OPTIONS]
+# ifdef DO_INIT
+ =
+{
+ {"top", TRUE, 0, NULL, 0, FALSE},
+ {"bottom", TRUE, 0, NULL, 0, FALSE},
+ {"left", TRUE, 0, NULL, 0, FALSE},
+ {"right", TRUE, 0, NULL, 0, FALSE},
+ {"header", TRUE, 0, NULL, 0, FALSE},
+ {"syntax", FALSE, 0, NULL, 0, FALSE},
+ {"number", FALSE, 0, NULL, 0, FALSE},
+ {"wrap", FALSE, 0, NULL, 0, FALSE},
+ {"duplex", FALSE, 0, NULL, 0, FALSE},
+ {"portrait", FALSE, 0, NULL, 0, FALSE},
+ {"paper", FALSE, 0, NULL, 0, FALSE},
+ {"collate", FALSE, 0, NULL, 0, FALSE},
+ {"jobsplit", FALSE, 0, NULL, 0, FALSE},
+ {"formfeed", FALSE, 0, NULL, 0, FALSE},
+}
+# endif
+;
+
+/* For prt_get_unit(). */
+# define PRT_UNIT_NONE -1
+# define PRT_UNIT_PERC 0
+# define PRT_UNIT_INCH 1
+# define PRT_UNIT_MM 2
+# define PRT_UNIT_POINT 3
+# define PRT_UNIT_NAMES {"pc", "in", "mm", "pt"}
+#endif
+
+#if (defined(FEAT_PRINTER) && defined(FEAT_STL_OPT)) \
+ || defined(FEAT_GUI_TABLINE)
+/* Page number used for %N in 'pageheader' and 'guitablabel'. */
+EXTERN linenr_T printer_page_num;
+#endif
+
+#ifdef FEAT_XCLIPBOARD
+EXTERN char *xterm_display INIT(= NULL); /* xterm display name; points
+ into argv[] */
+EXTERN Display *xterm_dpy INIT(= NULL); /* xterm display pointer */
+#endif
+#if defined(FEAT_XCLIPBOARD) || defined(FEAT_GUI_X11)
+EXTERN XtAppContext app_context INIT(= (XtAppContext)NULL);
+#endif
+
+#ifdef FEAT_GUI_GTK
+EXTERN guint32 gtk_socket_id INIT(= 0);
+EXTERN int echo_wid_arg INIT(= FALSE); /* --echo-wid argument */
+#endif
+
+#ifdef FEAT_GUI_W32
+/*
+ * The value of the --windowid argument.
+ * For embedding gvim inside another application.
+ */
+EXTERN long_u win_socket_id INIT(= 0);
+#endif
+
+#if defined(FEAT_CLIENTSERVER) || defined(FEAT_EVAL)
+EXTERN int typebuf_was_filled INIT(= FALSE); /* received text from client
+ or from feedkeys() */
+#endif
+
+#ifdef FEAT_CLIENTSERVER
+EXTERN char_u *serverName INIT(= NULL); /* name of the server */
+# ifdef FEAT_X11
+EXTERN Window commWindow INIT(= None);
+EXTERN Window clientWindow INIT(= None);
+EXTERN Atom commProperty INIT(= None);
+EXTERN char_u *serverDelayedStartName INIT(= NULL);
+# else
+# ifdef PROTO
+typedef int HWND;
+# endif
+EXTERN HWND clientWindow INIT(= 0);
+# endif
+#endif
+
+#if defined(UNIX) || defined(VMS)
+EXTERN int term_is_xterm INIT(= FALSE); /* xterm-like 'term' */
+#endif
+
+#ifdef BACKSLASH_IN_FILENAME
+EXTERN char psepc INIT(= '\\'); /* normal path separator character */
+EXTERN char psepcN INIT(= '/'); /* abnormal path separator character */
+/* normal path separator string */
+EXTERN char pseps[2] INIT(= {'\\' COMMA 0});
+#endif
+
+/* Set to TRUE when an operator is being executed with virtual editing, MAYBE
+ * when no operator is being executed, FALSE otherwise. */
+EXTERN int virtual_op INIT(= MAYBE);
+
+#ifdef FEAT_SYN_HL
+/* Display tick, incremented for each call to update_screen() */
+EXTERN disptick_T display_tick INIT(= 0);
+#endif
+
+#ifdef FEAT_SPELL
+/* Line in which spell checking wasn't highlighted because it touched the
+ * cursor position in Insert mode. */
+EXTERN linenr_T spell_redraw_lnum INIT(= 0);
+#endif
+
+#ifdef FEAT_CONCEAL
+/* Set when the cursor line needs to be redrawn. */
+EXTERN int need_cursor_line_redraw INIT(= FALSE);
+#endif
+
+#ifdef USE_MCH_ERRMSG
+/* Grow array to collect error messages in until they can be displayed. */
+EXTERN garray_T error_ga
+# ifdef DO_INIT
+ = {0, 0, 0, 0, NULL}
+# endif
+ ;
+#endif
+
+#ifdef FEAT_NETBEANS_INTG
+EXTERN char *netbeansArg INIT(= NULL); /* the -nb[:host:port:passwd] arg */
+EXTERN int netbeansFireChanges INIT(= 1); /* send buffer changes if != 0 */
+EXTERN int netbeansForcedQuit INIT(= 0);/* don't write modified files */
+EXTERN int netbeansReadFile INIT(= 1); /* OK to read from disk if != 0 */
+EXTERN int netbeansSuppressNoLines INIT(= 0); /* skip "No lines in buffer" */
+#endif
+
+/*
+ * The error messages that can be shared are included here.
+ * Excluded are errors that are only used once and debugging messages.
+ */
+EXTERN char e_abort[] INIT(= N_("E470: Command aborted"));
+EXTERN char e_argreq[] INIT(= N_("E471: Argument required"));
+EXTERN char e_backslash[] INIT(= N_("E10: \\ should be followed by /, ? or &"));
+#ifdef FEAT_CMDWIN
+EXTERN char e_cmdwin[] INIT(= N_("E11: Invalid in command-line window; <CR> executes, CTRL-C quits"));
+#endif
+EXTERN char e_curdir[] INIT(= N_("E12: Command not allowed from exrc/vimrc in current dir or tag search"));
+#ifdef FEAT_EVAL
+EXTERN char e_endif[] INIT(= N_("E171: Missing :endif"));
+EXTERN char e_endtry[] INIT(= N_("E600: Missing :endtry"));
+EXTERN char e_endwhile[] INIT(= N_("E170: Missing :endwhile"));
+EXTERN char e_endfor[] INIT(= N_("E170: Missing :endfor"));
+EXTERN char e_while[] INIT(= N_("E588: :endwhile without :while"));
+EXTERN char e_for[] INIT(= N_("E588: :endfor without :for"));
+#endif
+EXTERN char e_exists[] INIT(= N_("E13: File exists (add ! to override)"));
+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) \
+ || defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MSWIN)
+EXTERN char e_font[] INIT(= N_("E235: Unknown font: %s"));
+#endif
+#if defined(FEAT_GUI_X11) && !defined(FEAT_GUI_GTK)
+EXTERN char e_fontwidth[] INIT(= N_("E236: Font \"%s\" is not fixed-width"));
+#endif
+EXTERN char e_internal[] INIT(= N_("E473: Internal error"));
+EXTERN char e_intern2[] INIT(= N_("E685: Internal error: %s"));
+EXTERN char e_interr[] INIT(= N_("Interrupted"));
+EXTERN char e_invaddr[] INIT(= N_("E14: Invalid address"));
+EXTERN char e_invarg[] INIT(= N_("E474: Invalid argument"));
+EXTERN char e_invarg2[] INIT(= N_("E475: Invalid argument: %s"));
+EXTERN char e_invargval[] INIT(= N_("E475: Invalid value for argument %s"));
+EXTERN char e_invargNval[] INIT(= N_("E475: Invalid value for argument %s: %s"));
+#ifdef FEAT_EVAL
+EXTERN char e_invexpr2[] INIT(= N_("E15: Invalid expression: %s"));
+#endif
+EXTERN char e_invrange[] INIT(= N_("E16: Invalid range"));
+EXTERN char e_invcmd[] INIT(= N_("E476: Invalid command"));
+#if defined(UNIX) || defined(FEAT_SYN_HL) || defined(FEAT_SPELL)
+EXTERN char e_isadir2[] INIT(= N_("E17: \"%s\" is a directory"));
+#endif
+#ifdef FEAT_LIBCALL
+EXTERN char e_libcall[] INIT(= N_("E364: Library call failed for \"%s()\""));
+#endif
+#ifdef HAVE_FSYNC
+EXTERN char e_fsync[] INIT(= N_("E667: Fsync failed"));
+#endif
+#if defined(DYNAMIC_PERL) \
+ || defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3) \
+ || defined(DYNAMIC_RUBY) \
+ || defined(DYNAMIC_TCL) \
+ || defined(DYNAMIC_ICONV) \
+ || defined(DYNAMIC_GETTEXT) \
+ || defined(DYNAMIC_MZSCHEME) \
+ || defined(DYNAMIC_LUA) \
+ || defined(FEAT_TERMINAL)
+EXTERN char e_loadlib[] INIT(= N_("E370: Could not load library %s"));
+EXTERN char e_loadfunc[] INIT(= N_("E448: Could not load library function %s"));
+#endif
+EXTERN char e_markinval[] INIT(= N_("E19: Mark has invalid line number"));
+EXTERN char e_marknotset[] INIT(= N_("E20: Mark not set"));
+EXTERN char e_modifiable[] INIT(= N_("E21: Cannot make changes, 'modifiable' is off"));
+EXTERN char e_nesting[] INIT(= N_("E22: Scripts nested too deep"));
+EXTERN char e_noalt[] INIT(= N_("E23: No alternate file"));
+EXTERN char e_noabbr[] INIT(= N_("E24: No such abbreviation"));
+EXTERN char e_nobang[] INIT(= N_("E477: No ! allowed"));
+#ifndef FEAT_GUI
+EXTERN char e_nogvim[] INIT(= N_("E25: GUI cannot be used: Not enabled at compile time"));
+#endif
+#ifndef FEAT_RIGHTLEFT
+EXTERN char e_nohebrew[] INIT(= N_("E26: Hebrew cannot be used: Not enabled at compile time\n"));
+#endif
+#ifndef FEAT_FKMAP
+EXTERN char e_nofarsi[] INIT(= N_("E27: Farsi cannot be used: Not enabled at compile time\n"));
+#endif
+#ifndef FEAT_ARABIC
+EXTERN char e_noarabic[] INIT(= N_("E800: Arabic cannot be used: Not enabled at compile time\n"));
+#endif
+#if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_SYN_HL)
+EXTERN char e_nogroup[] INIT(= N_("E28: No such highlight group name: %s"));
+#endif
+EXTERN char e_noinstext[] INIT(= N_("E29: No inserted text yet"));
+EXTERN char e_nolastcmd[] INIT(= N_("E30: No previous command line"));
+EXTERN char e_nomap[] INIT(= N_("E31: No such mapping"));
+EXTERN char e_nomatch[] INIT(= N_("E479: No match"));
+EXTERN char e_nomatch2[] INIT(= N_("E480: No match: %s"));
+EXTERN char e_noname[] INIT(= N_("E32: No file name"));
+EXTERN char e_nopresub[] INIT(= N_("E33: No previous substitute regular expression"));
+EXTERN char e_noprev[] INIT(= N_("E34: No previous command"));
+EXTERN char e_noprevre[] INIT(= N_("E35: No previous regular expression"));
+EXTERN char e_norange[] INIT(= N_("E481: No range allowed"));
+EXTERN char e_noroom[] INIT(= N_("E36: Not enough room"));
+#ifdef FEAT_CLIENTSERVER
+EXTERN char e_noserver[] INIT(= N_("E247: no registered server named \"%s\""));
+#endif
+EXTERN char e_notcreate[] INIT(= N_("E482: Can't create file %s"));
+EXTERN char e_notmp[] INIT(= N_("E483: Can't get temp file name"));
+EXTERN char e_notopen[] INIT(= N_("E484: Can't open file %s"));
+EXTERN char e_notread[] INIT(= N_("E485: Can't read file %s"));
+EXTERN char e_null[] INIT(= N_("E38: Null argument"));
+#if defined(FEAT_DIGRAPHS) || defined(FEAT_TIMERS)
+EXTERN char e_number_exp[] INIT(= N_("E39: Number expected"));
+#endif
+#ifdef FEAT_QUICKFIX
+EXTERN char e_openerrf[] INIT(= N_("E40: Can't open errorfile %s"));
+#endif
+#if defined(FEAT_GUI_GTK) || defined(FEAT_GUI_X11)
+EXTERN char e_opendisp[] INIT(= N_("E233: cannot open display"));
+#endif
+EXTERN char e_outofmem[] INIT(= N_("E41: Out of memory!"));
+#ifdef FEAT_INS_EXPAND
+EXTERN char e_patnotf[] INIT(= N_("Pattern not found"));
+#endif
+EXTERN char e_patnotf2[] INIT(= N_("E486: Pattern not found: %s"));
+EXTERN char e_positive[] INIT(= N_("E487: Argument must be positive"));
+#if defined(UNIX) || defined(FEAT_SESSION)
+EXTERN char e_prev_dir[] INIT(= N_("E459: Cannot go back to previous directory"));
+#endif
+
+#ifdef FEAT_QUICKFIX
+EXTERN char e_quickfix[] INIT(= N_("E42: No Errors"));
+EXTERN char e_loclist[] INIT(= N_("E776: No location list"));
+#endif
+EXTERN char e_re_damg[] INIT(= N_("E43: Damaged match string"));
+EXTERN char e_re_corr[] INIT(= N_("E44: Corrupted regexp program"));
+EXTERN char e_readonly[] INIT(= N_("E45: 'readonly' option is set (add ! to override)"));
+#ifdef FEAT_EVAL
+EXTERN char e_readonlyvar[] INIT(= N_("E46: Cannot change read-only variable \"%s\""));
+EXTERN char e_readonlysbx[] INIT(= N_("E794: Cannot set variable in the sandbox: \"%s\""));
+EXTERN char e_emptykey[] INIT(= N_("E713: Cannot use empty key for Dictionary"));
+EXTERN char e_dictreq[] INIT(= N_("E715: Dictionary required"));
+EXTERN char e_listidx[] INIT(= N_("E684: list index out of range: %ld"));
+EXTERN char e_blobidx[] INIT(= N_("E979: Blob index out of range: %ld"));
+EXTERN char e_invalblob[] INIT(= N_("E978: Invalid operation for Blob"));
+EXTERN char e_toomanyarg[] INIT(= N_("E118: Too many arguments for function: %s"));
+EXTERN char e_dictkey[] INIT(= N_("E716: Key not present in Dictionary: %s"));
+EXTERN char e_listreq[] INIT(= N_("E714: List required"));
+EXTERN char e_listblobreq[] INIT(= N_("E897: List or Blob required"));
+EXTERN char e_listdictarg[] INIT(= N_("E712: Argument of %s must be a List or Dictionary"));
+EXTERN char e_listdictblobarg[] INIT(= N_("E896: Argument of %s must be a List, Dictionary or Blob"));
+#endif
+#ifdef FEAT_QUICKFIX
+EXTERN char e_readerrf[] INIT(= N_("E47: Error while reading errorfile"));
+#endif
+#ifdef HAVE_SANDBOX
+EXTERN char e_sandbox[] INIT(= N_("E48: Not allowed in sandbox"));
+#endif
+EXTERN char e_secure[] INIT(= N_("E523: Not allowed here"));
+#if defined(AMIGA) || defined(MACOS_X) || defined(MSWIN) \
+ || defined(UNIX) || defined(VMS)
+EXTERN char e_screenmode[] INIT(= N_("E359: Screen mode setting not supported"));
+#endif
+EXTERN char e_scroll[] INIT(= N_("E49: Invalid scroll size"));
+EXTERN char e_shellempty[] INIT(= N_("E91: 'shell' option is empty"));
+#if defined(FEAT_SIGN_ICONS) && !defined(FEAT_GUI_GTK)
+EXTERN char e_signdata[] INIT(= N_("E255: Couldn't read in sign data!"));
+#endif
+EXTERN char e_swapclose[] INIT(= N_("E72: Close error on swap file"));
+EXTERN char e_tagstack[] INIT(= N_("E73: tag stack empty"));
+EXTERN char e_toocompl[] INIT(= N_("E74: Command too complex"));
+EXTERN char e_longname[] INIT(= N_("E75: Name too long"));
+EXTERN char e_toomsbra[] INIT(= N_("E76: Too many ["));
+EXTERN char e_toomany[] INIT(= N_("E77: Too many file names"));
+EXTERN char e_trailing[] INIT(= N_("E488: Trailing characters"));
+EXTERN char e_umark[] INIT(= N_("E78: Unknown mark"));
+EXTERN char e_wildexpand[] INIT(= N_("E79: Cannot expand wildcards"));
+EXTERN char e_winheight[] INIT(= N_("E591: 'winheight' cannot be smaller than 'winminheight'"));
+EXTERN char e_winwidth[] INIT(= N_("E592: 'winwidth' cannot be smaller than 'winminwidth'"));
+EXTERN char e_write[] INIT(= N_("E80: Error while writing"));
+EXTERN char e_zerocount[] INIT(= N_("E939: Positive count required"));
+#ifdef FEAT_EVAL
+EXTERN char e_usingsid[] INIT(= N_("E81: Using <SID> not in a script context"));
+#endif
+#ifdef FEAT_CLIENTSERVER
+EXTERN char e_invexprmsg[] INIT(= N_("E449: Invalid expression received"));
+#endif
+#ifdef FEAT_NETBEANS_INTG
+EXTERN char e_guarded[] INIT(= N_("E463: Region is guarded, cannot modify"));
+EXTERN char e_nbreadonly[] INIT(= N_("E744: NetBeans does not allow changes in read-only files"));
+#endif
+EXTERN char e_maxmempat[] INIT(= N_("E363: pattern uses more memory than 'maxmempattern'"));
+EXTERN char e_emptybuf[] INIT(= N_("E749: empty buffer"));
+EXTERN char e_nobufnr[] INIT(= N_("E86: Buffer %ld does not exist"));
+
+EXTERN char e_invalpat[] INIT(= N_("E682: Invalid search pattern or delimiter"));
+EXTERN char e_bufloaded[] INIT(= N_("E139: File is loaded in another buffer"));
+#if defined(FEAT_SYN_HL) || \
+ (defined(FEAT_INS_EXPAND) && defined(FEAT_COMPL_FUNC))
+EXTERN char e_notset[] INIT(= N_("E764: Option '%s' is not set"));
+#endif
+#ifndef FEAT_CLIPBOARD
+EXTERN char e_invalidreg[] INIT(= N_("E850: Invalid register name"));
+#endif
+EXTERN char e_dirnotf[] INIT(= N_("E919: Directory not found in '%s': \"%s\""));
+EXTERN char e_au_recursive[] INIT(= N_("E952: Autocommand caused recursive behavior"));
+#ifdef FEAT_MENU
+EXTERN char e_menuothermode[] INIT(= N_("E328: Menu only exists in another mode"));
+#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"));
+
+#ifdef FEAT_CRYPT
+EXTERN char need_key_msg[] INIT(= N_("Need encryption key for \"%s\""));
+#endif
+
+/*
+ * Comms. with the session manager (XSMP)
+ */
+#ifdef USE_XSMP
+EXTERN int xsmp_icefd INIT(= -1); /* The actual connection */
+#endif
+
+/* For undo we need to know the lowest time possible. */
+EXTERN time_T starttime;
+
+#ifdef STARTUPTIME
+EXTERN FILE *time_fd INIT(= NULL); /* where to write startup timing */
+#endif
+
+/*
+ * Some compilers warn for not using a return value, but in some situations we
+ * can't do anything useful with the value. Assign to this variable to avoid
+ * the warning.
+ */
+EXTERN int vim_ignored;
+EXTERN char *vim_ignoredp;
+
+#ifdef FEAT_EVAL
+/* set by alloc_fail(): ID */
+EXTERN alloc_id_T alloc_fail_id INIT(= aid_none);
+/* set by alloc_fail(), when zero alloc() returns NULL */
+EXTERN int alloc_fail_countdown INIT(= -1);
+/* set by alloc_fail(), number of times alloc() returns NULL */
+EXTERN int alloc_fail_repeat INIT(= 0);
+
+/* flags set by test_override() */
+EXTERN int disable_char_avail_for_testing INIT(= FALSE);
+EXTERN int disable_redraw_for_testing INIT(= FALSE);
+EXTERN int ignore_redraw_flag_for_testing INIT(= FALSE);
+EXTERN int nfa_fail_for_testing INIT(= FALSE);
+
+EXTERN int in_free_unref_items INIT(= FALSE);
+#endif
+
+#ifdef FEAT_TIMERS
+EXTERN int did_add_timer INIT(= FALSE);
+EXTERN int timer_busy INIT(= 0); /* when timer is inside vgetc() then > 0 */
+#endif
+
+#ifdef FEAT_BEVAL_TERM
+EXTERN int bevalexpr_due_set INIT(= FALSE);
+EXTERN proftime_T bevalexpr_due;
+#endif
+
+#ifdef FEAT_EVAL
+EXTERN time_T time_for_testing INIT(= 0);
+
+/* Abort conversion to string after a recursion error. */
+EXTERN int did_echo_string_emsg INIT(= FALSE);
+
+/* Used for checking if local variables or arguments used in a lambda. */
+EXTERN int *eval_lavars_used INIT(= NULL);
+#endif
+
+#ifdef WIN3264
+EXTERN int ctrl_break_was_pressed INIT(= FALSE);
+#endif
+
+#ifdef FEAT_TEXT_PROP
+EXTERN int text_prop_frozen INIT(= 0);
+#endif
+
+/*
+ * Optional Farsi support. Include it here, so EXTERN and INIT are defined.
+ */
+#ifdef FEAT_FKMAP
+# include "farsi.h"
+#endif
+
+/*
+ * Optional Arabic support. Include it here, so EXTERN and INIT are defined.
+ */
+#ifdef FEAT_ARABIC
+# include "arabic.h"
+#endif
diff --git a/src/gui.c b/src/gui.c
new file mode 100644
index 0000000..d993bc6
--- /dev/null
+++ b/src/gui.c
@@ -0,0 +1,5460 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ * GUI/Motif support by Robert Webb
+ *
+ * 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.
+ */
+
+#include "vim.h"
+
+/* Structure containing all the GUI information */
+gui_T gui;
+
+#if !defined(FEAT_GUI_GTK)
+static void set_guifontwide(char_u *font_name);
+#endif
+static void gui_check_pos(void);
+static void gui_outstr(char_u *, int);
+static int gui_screenchar(int off, int flags, guicolor_T fg, guicolor_T bg, int back);
+static void gui_delete_lines(int row, int count);
+static void gui_insert_lines(int row, int count);
+#if defined(FEAT_GUI_TABLINE) || defined(PROTO)
+static int gui_has_tabline(void);
+#endif
+static void gui_do_scrollbar(win_T *wp, int which, int enable);
+static void gui_update_horiz_scrollbar(int);
+static void gui_set_fg_color(char_u *name);
+static void gui_set_bg_color(char_u *name);
+static win_T *xy2win(int x, int y);
+
+#ifdef GUI_MAY_FORK
+static void gui_do_fork(void);
+
+static int gui_read_child_pipe(int fd);
+
+/* Return values for gui_read_child_pipe */
+enum {
+ GUI_CHILD_IO_ERROR,
+ GUI_CHILD_OK,
+ GUI_CHILD_FAILED
+};
+#endif
+
+static void gui_attempt_start(void);
+
+static int can_update_cursor = TRUE; /* can display the cursor */
+static int disable_flush = 0; /* If > 0, gui_mch_flush() is disabled. */
+
+/*
+ * The Athena scrollbars can move the thumb to after the end of the scrollbar,
+ * 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)
+# define SCROLL_PAST_END
+#endif
+
+/*
+ * gui_start -- Called when user wants to start the GUI.
+ *
+ * Careful: This function can be called recursively when there is a ":gui"
+ * command in the .gvimrc file. Only the first call should fork, not the
+ * recursive call.
+ */
+ void
+gui_start(void)
+{
+ char_u *old_term;
+ static int recursive = 0;
+
+ old_term = vim_strsave(T_NAME);
+
+ settmode(TMODE_COOK); /* stop RAW mode */
+ if (full_screen)
+ cursor_on(); /* needed for ":gui" in .vimrc */
+ full_screen = FALSE;
+
+ ++recursive;
+
+#ifdef GUI_MAY_FORK
+ /*
+ * Quit the current process and continue in the child.
+ * Makes "gvim file" disconnect from the shell it was started in.
+ * Don't do this when Vim was started with "-f" or the 'f' flag is present
+ * in 'guioptions'.
+ * Don't do this when there is a running job, we can only get the status
+ * of a child from the parent.
+ */
+ if (gui.dofork && !vim_strchr(p_go, GO_FORG) && recursive <= 1
+# ifdef FEAT_JOB_CHANNEL
+ && !job_any_running()
+# endif
+ )
+ {
+ gui_do_fork();
+ }
+ else
+#endif
+ {
+#ifdef FEAT_GUI_GTK
+ /* If there is 'f' in 'guioptions' and specify -g argument,
+ * gui_mch_init_check() was not called yet. */
+ if (gui_mch_init_check() != OK)
+ getout_preserve_modified(1);
+#endif
+ gui_attempt_start();
+ }
+
+ if (!gui.in_use) /* failed to start GUI */
+ {
+ /* Back to old term settings
+ *
+ * FIXME: If we got here because a child process failed and flagged to
+ * the parent to resume, and X11 is enabled with FEAT_TITLE, this will
+ * hit an X11 I/O error and do a longjmp(), leaving recursive
+ * permanently set to 1. This is probably not as big a problem as it
+ * sounds, because gui_mch_init() in both gui_x11.c and gui_gtk_x11.c
+ * return "OK" unconditionally, so it would be very difficult to
+ * actually hit this case.
+ */
+ termcapinit(old_term);
+ settmode(TMODE_RAW); /* restart RAW mode */
+#ifdef FEAT_TITLE
+ set_title_defaults(); /* set 'title' and 'icon' again */
+#endif
+ }
+
+ vim_free(old_term);
+
+ /* If the GUI started successfully, trigger the GUIEnter event, otherwise
+ * the GUIFailed event. */
+ gui_mch_update();
+ apply_autocmds(gui.in_use ? EVENT_GUIENTER : EVENT_GUIFAILED,
+ NULL, NULL, FALSE, curbuf);
+ --recursive;
+}
+
+/*
+ * Set_termname() will call gui_init() to start the GUI.
+ * Set the "starting" flag, to indicate that the GUI will start.
+ *
+ * We don't want to open the GUI shell until after we've read .gvimrc,
+ * otherwise we don't know what font we will use, and hence we don't know
+ * what size the shell should be. So if there are errors in the .gvimrc
+ * file, they will have to go to the terminal: Set full_screen to FALSE.
+ * full_screen will be set to TRUE again by a successful termcapinit().
+ */
+ static void
+gui_attempt_start(void)
+{
+ static int recursive = 0;
+
+ ++recursive;
+ gui.starting = TRUE;
+
+#ifdef FEAT_GUI_GTK
+ gui.event_time = GDK_CURRENT_TIME;
+#endif
+
+ termcapinit((char_u *)"builtin_gui");
+ gui.starting = recursive - 1;
+
+#if defined(FEAT_GUI_GTK) || defined(FEAT_GUI_X11)
+ if (gui.in_use)
+ {
+# ifdef FEAT_EVAL
+ Window x11_window;
+ Display *x11_display;
+
+ if (gui_get_x11_windis(&x11_window, &x11_display) == OK)
+ set_vim_var_nr(VV_WINDOWID, (long)x11_window);
+# endif
+
+ /* Display error messages in a dialog now. */
+ display_errors();
+ }
+#endif
+ --recursive;
+}
+
+#ifdef GUI_MAY_FORK
+
+/* for waitpid() */
+# if defined(HAVE_SYS_WAIT_H) || defined(HAVE_UNION_WAIT)
+# include <sys/wait.h>
+# endif
+
+/*
+ * Create a new process, by forking. In the child, start the GUI, and in
+ * the parent, exit.
+ *
+ * If something goes wrong, this will return with gui.in_use still set
+ * to FALSE, in which case the caller should continue execution without
+ * the GUI.
+ *
+ * If the child fails to start the GUI, then the child will exit and the
+ * parent will return. If the child succeeds, then the parent will exit
+ * and the child will return.
+ */
+ static void
+gui_do_fork(void)
+{
+ int pipefd[2]; /* pipe between parent and child */
+ int pipe_error;
+ int status;
+ int exit_status;
+ pid_t pid = -1;
+
+ /* Setup a pipe between the child and the parent, so that the parent
+ * knows when the child has done the setsid() call and is allowed to
+ * exit. */
+ pipe_error = (pipe(pipefd) < 0);
+ pid = fork();
+ if (pid < 0) /* Fork error */
+ {
+ emsg(_("E851: Failed to create a new process for the GUI"));
+ return;
+ }
+ else if (pid > 0) /* Parent */
+ {
+ /* Give the child some time to do the setsid(), otherwise the
+ * exit() may kill the child too (when starting gvim from inside a
+ * gvim). */
+ if (!pipe_error)
+ {
+ /* The read returns when the child closes the pipe (or when
+ * the child dies for some reason). */
+ close(pipefd[1]);
+ status = gui_read_child_pipe(pipefd[0]);
+ if (status == GUI_CHILD_FAILED)
+ {
+ /* The child failed to start the GUI, so the caller must
+ * continue. There may be more error information written
+ * to stderr by the child. */
+# ifdef __NeXT__
+ wait4(pid, &exit_status, 0, (struct rusage *)0);
+# else
+ waitpid(pid, &exit_status, 0);
+# endif
+ emsg(_("E852: The child process failed to start the GUI"));
+ return;
+ }
+ else if (status == GUI_CHILD_IO_ERROR)
+ {
+ pipe_error = TRUE;
+ }
+ /* else GUI_CHILD_OK: parent exit */
+ }
+
+ if (pipe_error)
+ ui_delay(300L, TRUE);
+
+ /* When swapping screens we may need to go to the next line, e.g.,
+ * after a hit-enter prompt and using ":gui". */
+ if (newline_on_exit)
+ mch_errmsg("\r\n");
+
+ /*
+ * The parent must skip the normal exit() processing, the child
+ * will do it. For example, GTK messes up signals when exiting.
+ */
+ _exit(0);
+ }
+ /* Child */
+
+#ifdef FEAT_GUI_GTK
+ /* Call gtk_init_check() here after fork(). See gui_init_check(). */
+ if (gui_mch_init_check() != OK)
+ getout_preserve_modified(1);
+#endif
+
+# if defined(HAVE_SETSID) || defined(HAVE_SETPGID)
+ /*
+ * Change our process group. On some systems/shells a CTRL-C in the
+ * shell where Vim was started would otherwise kill gvim!
+ */
+# if defined(HAVE_SETSID)
+ (void)setsid();
+# else
+ (void)setpgid(0, 0);
+# endif
+# endif
+ if (!pipe_error)
+ close(pipefd[0]);
+
+# if defined(FEAT_GUI_GNOME) && defined(FEAT_SESSION)
+ /* Tell the session manager our new PID */
+ gui_mch_forked();
+# endif
+
+ /* Try to start the GUI */
+ gui_attempt_start();
+
+ /* Notify the parent */
+ if (!pipe_error)
+ {
+ if (gui.in_use)
+ write_eintr(pipefd[1], "ok", 3);
+ else
+ write_eintr(pipefd[1], "fail", 5);
+ close(pipefd[1]);
+ }
+
+ /* If we failed to start the GUI, exit now. */
+ if (!gui.in_use)
+ getout_preserve_modified(1);
+}
+
+/*
+ * Read from a pipe assumed to be connected to the child process (this
+ * function is called from the parent).
+ * Return GUI_CHILD_OK if the child successfully started the GUI,
+ * GUY_CHILD_FAILED if the child failed, or GUI_CHILD_IO_ERROR if there was
+ * some other error.
+ *
+ * The file descriptor will be closed before the function returns.
+ */
+ static int
+gui_read_child_pipe(int fd)
+{
+ long bytes_read;
+#define READ_BUFFER_SIZE 10
+ char buffer[READ_BUFFER_SIZE];
+
+ bytes_read = read_eintr(fd, buffer, READ_BUFFER_SIZE - 1);
+#undef READ_BUFFER_SIZE
+ close(fd);
+ if (bytes_read < 0)
+ return GUI_CHILD_IO_ERROR;
+ buffer[bytes_read] = NUL;
+ if (strcmp(buffer, "ok") == 0)
+ return GUI_CHILD_OK;
+ return GUI_CHILD_FAILED;
+}
+
+#endif /* GUI_MAY_FORK */
+
+/*
+ * Call this when vim starts up, whether or not the GUI is started
+ */
+ void
+gui_prepare(int *argc, char **argv)
+{
+ gui.in_use = FALSE; /* No GUI yet (maybe later) */
+ gui.starting = FALSE; /* No GUI yet (maybe later) */
+ gui_mch_prepare(argc, argv);
+}
+
+/*
+ * Try initializing the GUI and check if it can be started.
+ * Used from main() to check early if "vim -g" can start the GUI.
+ * Used from gui_init() to prepare for starting the GUI.
+ * Returns FAIL or OK.
+ */
+ int
+gui_init_check(void)
+{
+ static int result = MAYBE;
+
+ if (result != MAYBE)
+ {
+ if (result == FAIL)
+ emsg(_("E229: Cannot start the GUI"));
+ return result;
+ }
+
+ gui.shell_created = FALSE;
+ gui.dying = FALSE;
+ gui.in_focus = TRUE; /* so the guicursor setting works */
+ gui.dragged_sb = SBAR_NONE;
+ gui.dragged_wp = NULL;
+ gui.pointer_hidden = FALSE;
+ gui.col = 0;
+ gui.row = 0;
+ gui.num_cols = Columns;
+ gui.num_rows = Rows;
+
+ gui.cursor_is_valid = FALSE;
+ gui.scroll_region_top = 0;
+ gui.scroll_region_bot = Rows - 1;
+ gui.scroll_region_left = 0;
+ gui.scroll_region_right = Columns - 1;
+ gui.highlight_mask = HL_NORMAL;
+ gui.char_width = 1;
+ gui.char_height = 1;
+ gui.char_ascent = 0;
+ gui.border_width = 0;
+
+ gui.norm_font = NOFONT;
+#ifndef FEAT_GUI_GTK
+ gui.bold_font = NOFONT;
+ gui.ital_font = NOFONT;
+ gui.boldital_font = NOFONT;
+# ifdef FEAT_XFONTSET
+ gui.fontset = NOFONTSET;
+# endif
+#endif
+ gui.wide_font = NOFONT;
+#ifndef FEAT_GUI_GTK
+ gui.wide_bold_font = NOFONT;
+ gui.wide_ital_font = NOFONT;
+ gui.wide_boldital_font = NOFONT;
+#endif
+
+#ifdef FEAT_MENU
+# ifndef FEAT_GUI_GTK
+# ifdef FONTSET_ALWAYS
+ gui.menu_fontset = NOFONTSET;
+# else
+ gui.menu_font = NOFONT;
+# endif
+# endif
+ gui.menu_is_active = TRUE; /* default: include menu */
+# ifndef FEAT_GUI_GTK
+ gui.menu_height = MENU_DEFAULT_HEIGHT;
+ gui.menu_width = 0;
+# endif
+#endif
+#if defined(FEAT_TOOLBAR) && (defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA))
+ gui.toolbar_height = 0;
+#endif
+#if defined(FEAT_FOOTER) && defined(FEAT_GUI_MOTIF)
+ gui.footer_height = 0;
+#endif
+#ifdef FEAT_BEVAL_TIP
+ gui.tooltip_fontset = NOFONTSET;
+#endif
+
+ gui.scrollbar_width = gui.scrollbar_height = SB_DEFAULT_WIDTH;
+ gui.prev_wrap = -1;
+
+#ifdef ALWAYS_USE_GUI
+ result = OK;
+#else
+# ifdef FEAT_GUI_GTK
+ /*
+ * Note: Don't call gtk_init_check() before fork, it will be called after
+ * the fork. When calling it before fork, it make vim hang for a while.
+ * See gui_do_fork().
+ * Use a simpler check if the GUI window can probably be opened.
+ */
+ result = gui.dofork ? gui_mch_early_init_check(TRUE) : gui_mch_init_check();
+# else
+ result = gui_mch_init_check();
+# endif
+#endif
+ return result;
+}
+
+/*
+ * This is the call which starts the GUI.
+ */
+ void
+gui_init(void)
+{
+ win_T *wp;
+ static int recursive = 0;
+
+ /*
+ * It's possible to use ":gui" in a .gvimrc file. The first halve of this
+ * function will then be executed at the first call, the rest by the
+ * recursive call. This allow the shell to be opened halfway reading a
+ * gvimrc file.
+ */
+ if (!recursive)
+ {
+ ++recursive;
+
+ clip_init(TRUE);
+
+ /* If can't initialize, don't try doing the rest */
+ if (gui_init_check() == FAIL)
+ {
+ --recursive;
+ clip_init(FALSE);
+ return;
+ }
+
+ /*
+ * Reset 'paste'. It's useful in the terminal, but not in the GUI. It
+ * breaks the Paste toolbar button.
+ */
+ set_option_value((char_u *)"paste", 0L, NULL, 0);
+
+ /*
+ * Set up system-wide default menus.
+ */
+#if defined(SYS_MENU_FILE) && defined(FEAT_MENU)
+ if (vim_strchr(p_go, GO_NOSYSMENU) == NULL)
+ {
+ sys_menu = TRUE;
+ do_source((char_u *)SYS_MENU_FILE, FALSE, DOSO_NONE);
+ sys_menu = FALSE;
+ }
+#endif
+
+ /*
+ * Switch on the mouse by default, unless the user changed it already.
+ * This can then be changed in the .gvimrc.
+ */
+ if (!option_was_set((char_u *)"mouse"))
+ set_string_option_direct((char_u *)"mouse", -1,
+ (char_u *)"a", OPT_FREE, SID_NONE);
+
+ /*
+ * If -U option given, use only the initializations from that file and
+ * nothing else. Skip all initializations for "-U NONE" or "-u NORC".
+ */
+ if (use_gvimrc != NULL)
+ {
+ if (STRCMP(use_gvimrc, "NONE") != 0
+ && STRCMP(use_gvimrc, "NORC") != 0
+ && do_source(use_gvimrc, FALSE, DOSO_NONE) != OK)
+ semsg(_("E230: Cannot read from \"%s\""), use_gvimrc);
+ }
+ else
+ {
+ /*
+ * Get system wide defaults for gvim, only when file name defined.
+ */
+#ifdef SYS_GVIMRC_FILE
+ do_source((char_u *)SYS_GVIMRC_FILE, FALSE, DOSO_NONE);
+#endif
+
+ /*
+ * Try to read GUI initialization commands from the following
+ * places:
+ * - environment variable GVIMINIT
+ * - the user gvimrc file (~/.gvimrc)
+ * - the second user gvimrc file ($VIM/.gvimrc for Dos)
+ * - the third user gvimrc file ($VIM/.gvimrc for Amiga)
+ * The first that exists is used, the rest is ignored.
+ */
+ if (process_env((char_u *)"GVIMINIT", FALSE) == FAIL
+ && do_source((char_u *)USR_GVIMRC_FILE, TRUE,
+ DOSO_GVIMRC) == FAIL
+#ifdef USR_GVIMRC_FILE2
+ && do_source((char_u *)USR_GVIMRC_FILE2, TRUE,
+ DOSO_GVIMRC) == FAIL
+#endif
+#ifdef USR_GVIMRC_FILE3
+ && do_source((char_u *)USR_GVIMRC_FILE3, TRUE,
+ DOSO_GVIMRC) == FAIL
+#endif
+ )
+ {
+#ifdef USR_GVIMRC_FILE4
+ (void)do_source((char_u *)USR_GVIMRC_FILE4, TRUE, DOSO_GVIMRC);
+#endif
+ }
+
+ /*
+ * Read initialization commands from ".gvimrc" in current
+ * directory. This is only done if the 'exrc' option is set.
+ * Because of security reasons we disallow shell and write
+ * commands now, except for unix if the file is owned by the user
+ * or 'secure' option has been reset in environment of global
+ * ".gvimrc".
+ * Only do this if GVIMRC_FILE is not the same as USR_GVIMRC_FILE,
+ * USR_GVIMRC_FILE2, USR_GVIMRC_FILE3 or SYS_GVIMRC_FILE.
+ */
+ if (p_exrc)
+ {
+#ifdef UNIX
+ {
+ stat_T s;
+
+ /* if ".gvimrc" file is not owned by user, set 'secure'
+ * mode */
+ if (mch_stat(GVIMRC_FILE, &s) || s.st_uid != getuid())
+ secure = p_secure;
+ }
+#else
+ secure = p_secure;
+#endif
+
+ if ( fullpathcmp((char_u *)USR_GVIMRC_FILE,
+ (char_u *)GVIMRC_FILE, FALSE) != FPC_SAME
+#ifdef SYS_GVIMRC_FILE
+ && fullpathcmp((char_u *)SYS_GVIMRC_FILE,
+ (char_u *)GVIMRC_FILE, FALSE) != FPC_SAME
+#endif
+#ifdef USR_GVIMRC_FILE2
+ && fullpathcmp((char_u *)USR_GVIMRC_FILE2,
+ (char_u *)GVIMRC_FILE, FALSE) != FPC_SAME
+#endif
+#ifdef USR_GVIMRC_FILE3
+ && fullpathcmp((char_u *)USR_GVIMRC_FILE3,
+ (char_u *)GVIMRC_FILE, FALSE) != FPC_SAME
+#endif
+#ifdef USR_GVIMRC_FILE4
+ && fullpathcmp((char_u *)USR_GVIMRC_FILE4,
+ (char_u *)GVIMRC_FILE, FALSE) != FPC_SAME
+#endif
+ )
+ do_source((char_u *)GVIMRC_FILE, TRUE, DOSO_GVIMRC);
+
+ if (secure == 2)
+ need_wait_return = TRUE;
+ secure = 0;
+ }
+ }
+
+ if (need_wait_return || msg_didany)
+ wait_return(TRUE);
+
+ --recursive;
+ }
+
+ /* If recursive call opened the shell, return here from the first call */
+ if (gui.in_use)
+ return;
+
+ /*
+ * Create the GUI shell.
+ */
+ gui.in_use = TRUE; /* Must be set after menus have been set up */
+ if (gui_mch_init() == FAIL)
+ goto error;
+
+ /* Avoid a delay for an error message that was printed in the terminal
+ * where Vim was started. */
+ emsg_on_display = FALSE;
+ msg_scrolled = 0;
+ clear_sb_text(TRUE);
+ need_wait_return = FALSE;
+ msg_didany = FALSE;
+
+ /*
+ * Check validity of any generic resources that may have been loaded.
+ */
+ if (gui.border_width < 0)
+ gui.border_width = 0;
+
+ /*
+ * Set up the fonts. First use a font specified with "-fn" or "-font".
+ */
+ if (font_argument != NULL)
+ set_option_value((char_u *)"gfn", 0L, (char_u *)font_argument, 0);
+ if (
+#ifdef FEAT_XFONTSET
+ (*p_guifontset == NUL
+ || gui_init_font(p_guifontset, TRUE) == FAIL) &&
+#endif
+ gui_init_font(*p_guifont == NUL ? hl_get_font_name()
+ : p_guifont, FALSE) == FAIL)
+ {
+ emsg(_("E665: Cannot start GUI, no valid font found"));
+ goto error2;
+ }
+ if (gui_get_wide_font() == FAIL)
+ emsg(_("E231: 'guifontwide' invalid"));
+
+ gui.num_cols = Columns;
+ gui.num_rows = Rows;
+ gui_reset_scroll_region();
+
+ /* Create initial scrollbars */
+ FOR_ALL_WINDOWS(wp)
+ {
+ gui_create_scrollbar(&wp->w_scrollbars[SBAR_LEFT], SBAR_LEFT, wp);
+ gui_create_scrollbar(&wp->w_scrollbars[SBAR_RIGHT], SBAR_RIGHT, wp);
+ }
+ gui_create_scrollbar(&gui.bottom_sbar, SBAR_BOTTOM, NULL);
+
+#ifdef FEAT_MENU
+ gui_create_initial_menus(root_menu);
+#endif
+#ifdef FEAT_SIGN_ICONS
+ sign_gui_started();
+#endif
+
+ /* Configure the desired menu and scrollbars */
+ gui_init_which_components(NULL);
+
+ /* All components of the GUI have been created now */
+ gui.shell_created = TRUE;
+
+#ifndef FEAT_GUI_GTK
+ // Set the shell size, adjusted for the screen size. For GTK this only
+ // works after the shell has been opened, thus it is further down.
+ // For MS-Windows pass FALSE for "mustset" to make --windowid work.
+ gui_set_shellsize(FALSE, TRUE, RESIZE_BOTH);
+#endif
+#if defined(FEAT_GUI_MOTIF) && defined(FEAT_MENU)
+ /* Need to set the size of the menubar after all the menus have been
+ * created. */
+ gui_mch_compute_menu_height((Widget)0);
+#endif
+
+ /*
+ * Actually open the GUI shell.
+ */
+ if (gui_mch_open() != FAIL)
+ {
+#ifdef FEAT_TITLE
+ maketitle();
+ resettitle();
+#endif
+ init_gui_options();
+#ifdef FEAT_ARABIC
+ /* Our GUI can't do bidi. */
+ p_tbidi = FALSE;
+#endif
+#if defined(FEAT_GUI_GTK)
+ /* Give GTK+ a chance to put all widget's into place. */
+ gui_mch_update();
+
+# ifdef FEAT_MENU
+ /* If there is no 'm' in 'guioptions' we need to remove the menu now.
+ * It was still there to make F10 work. */
+ if (vim_strchr(p_go, GO_MENUS) == NULL)
+ {
+ --gui.starting;
+ gui_mch_enable_menu(FALSE);
+ ++gui.starting;
+ gui_mch_update();
+ }
+# endif
+
+ /* Now make sure the shell fits on the screen. */
+ gui_set_shellsize(TRUE, TRUE, RESIZE_BOTH);
+#endif
+ /* When 'lines' was set while starting up the topframe may have to be
+ * resized. */
+ win_new_shellsize();
+
+#ifdef FEAT_BEVAL_GUI
+ /* Always create the Balloon Evaluation area, but disable it when
+ * 'ballooneval' is off. */
+ if (balloonEval != NULL)
+ {
+# ifdef FEAT_VARTABS
+ vim_free(balloonEval->vts);
+# endif
+ vim_free(balloonEval);
+ }
+ balloonEvalForTerm = FALSE;
+# ifdef FEAT_GUI_GTK
+ balloonEval = gui_mch_create_beval_area(gui.drawarea, NULL,
+ &general_beval_cb, NULL);
+# else
+# if defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA)
+ {
+ extern Widget textArea;
+ balloonEval = gui_mch_create_beval_area(textArea, NULL,
+ &general_beval_cb, NULL);
+ }
+# else
+# ifdef FEAT_GUI_W32
+ balloonEval = gui_mch_create_beval_area(NULL, NULL,
+ &general_beval_cb, NULL);
+# endif
+# endif
+# endif
+ if (!p_beval)
+ gui_mch_disable_beval_area(balloonEval);
+#endif
+
+#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
+ if (!im_xim_isvalid_imactivate())
+ emsg(_("E599: Value of 'imactivatekey' is invalid"));
+#endif
+ /* When 'cmdheight' was set during startup it may not have taken
+ * effect yet. */
+ if (p_ch != 1L)
+ command_height();
+
+ return;
+ }
+
+error2:
+#ifdef FEAT_GUI_X11
+ /* undo gui_mch_init() */
+ gui_mch_uninit();
+#endif
+
+error:
+ gui.in_use = FALSE;
+ clip_init(FALSE);
+}
+
+
+ void
+gui_exit(int rc)
+{
+ /* don't free the fonts, it leads to a BUS error
+ * richard@whitequeen.com Jul 99 */
+ free_highlight_fonts();
+ gui.in_use = FALSE;
+ gui_mch_exit(rc);
+}
+
+#if defined(FEAT_GUI_GTK) || defined(FEAT_GUI_X11) || defined(FEAT_GUI_MSWIN) \
+ || defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC) || defined(PROTO)
+# define NEED_GUI_UPDATE_SCREEN 1
+/*
+ * Called when the GUI shell is closed by the user. If there are no changed
+ * files Vim exits, otherwise there will be a dialog to ask the user what to
+ * do.
+ * When this function returns, Vim should NOT exit!
+ */
+ void
+gui_shell_closed(void)
+{
+ cmdmod_T save_cmdmod;
+
+ save_cmdmod = cmdmod;
+
+ /* Only exit when there are no changed files */
+ exiting = TRUE;
+# ifdef FEAT_BROWSE
+ cmdmod.browse = TRUE;
+# endif
+# if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
+ cmdmod.confirm = TRUE;
+# endif
+ /* If there are changed buffers, present the user with a dialog if
+ * possible, otherwise give an error message. */
+ if (!check_changed_any(FALSE, FALSE))
+ getout(0);
+
+ exiting = FALSE;
+ cmdmod = save_cmdmod;
+ gui_update_screen(); /* redraw, window may show changed buffer */
+}
+#endif
+
+/*
+ * Set the font. "font_list" is a comma separated list of font names. The
+ * first font name that works is used. If none is found, use the default
+ * font.
+ * If "fontset" is TRUE, the "font_list" is used as one name for the fontset.
+ * Return OK when able to set the font. When it failed FAIL is returned and
+ * the fonts are unchanged.
+ */
+ int
+gui_init_font(char_u *font_list, int fontset UNUSED)
+{
+#define FONTLEN 320
+ char_u font_name[FONTLEN];
+ int font_list_empty = FALSE;
+ int ret = FAIL;
+
+ if (!gui.in_use)
+ return FAIL;
+
+ font_name[0] = NUL;
+ if (*font_list == NUL)
+ font_list_empty = TRUE;
+ else
+ {
+#ifdef FEAT_XFONTSET
+ /* When using a fontset, the whole list of fonts is one name. */
+ if (fontset)
+ ret = gui_mch_init_font(font_list, TRUE);
+ else
+#endif
+ while (*font_list != NUL)
+ {
+ /* Isolate one comma separated font name. */
+ (void)copy_option_part(&font_list, font_name, FONTLEN, ",");
+
+ /* Careful!!! The Win32 version of gui_mch_init_font(), when
+ * called with "*" will change p_guifont to the selected font
+ * name, which frees the old value. This makes font_list
+ * invalid. Thus when OK is returned here, font_list must no
+ * longer be used! */
+ if (gui_mch_init_font(font_name, FALSE) == OK)
+ {
+#if !defined(FEAT_GUI_GTK)
+ /* If it's a Unicode font, try setting 'guifontwide' to a
+ * similar double-width font. */
+ if ((p_guifontwide == NULL || *p_guifontwide == NUL)
+ && strstr((char *)font_name, "10646") != NULL)
+ set_guifontwide(font_name);
+#endif
+ ret = OK;
+ break;
+ }
+ }
+ }
+
+ if (ret != OK
+ && STRCMP(font_list, "*") != 0
+ && (font_list_empty || gui.norm_font == NOFONT))
+ {
+ /*
+ * Couldn't load any font in 'font_list', keep the current font if
+ * there is one. If 'font_list' is empty, or if there is no current
+ * font, tell gui_mch_init_font() to try to find a font we can load.
+ */
+ ret = gui_mch_init_font(NULL, FALSE);
+ }
+
+ if (ret == OK)
+ {
+#ifndef FEAT_GUI_GTK
+ /* Set normal font as current font */
+# ifdef FEAT_XFONTSET
+ if (gui.fontset != NOFONTSET)
+ gui_mch_set_fontset(gui.fontset);
+ else
+# endif
+ gui_mch_set_font(gui.norm_font);
+#endif
+ gui_set_shellsize(TRUE, TRUE, RESIZE_BOTH);
+ }
+
+ return ret;
+}
+
+#ifndef FEAT_GUI_GTK
+/*
+ * Try setting 'guifontwide' to a font twice as wide as "name".
+ */
+ static void
+set_guifontwide(char_u *name)
+{
+ int i = 0;
+ char_u wide_name[FONTLEN + 10]; /* room for 2 * width and '*' */
+ char_u *wp = NULL;
+ char_u *p;
+ GuiFont font;
+
+ wp = wide_name;
+ for (p = name; *p != NUL; ++p)
+ {
+ *wp++ = *p;
+ if (*p == '-')
+ {
+ ++i;
+ if (i == 6) /* font type: change "--" to "-*-" */
+ {
+ if (p[1] == '-')
+ *wp++ = '*';
+ }
+ else if (i == 12) /* found the width */
+ {
+ ++p;
+ i = getdigits(&p);
+ if (i != 0)
+ {
+ /* Double the width specification. */
+ sprintf((char *)wp, "%d%s", i * 2, p);
+ font = gui_mch_get_font(wide_name, FALSE);
+ if (font != NOFONT)
+ {
+ gui_mch_free_font(gui.wide_font);
+ gui.wide_font = font;
+ set_string_option_direct((char_u *)"gfw", -1,
+ wide_name, OPT_FREE, 0);
+ }
+ }
+ break;
+ }
+ }
+ }
+}
+#endif /* !FEAT_GUI_GTK */
+
+/*
+ * Get the font for 'guifontwide'.
+ * Return FAIL for an invalid font name.
+ */
+ int
+gui_get_wide_font(void)
+{
+ GuiFont font = NOFONT;
+ char_u font_name[FONTLEN];
+ char_u *p;
+
+ if (!gui.in_use) /* Can't allocate font yet, assume it's OK. */
+ return OK; /* Will give an error message later. */
+
+ if (p_guifontwide != NULL && *p_guifontwide != NUL)
+ {
+ for (p = p_guifontwide; *p != NUL; )
+ {
+ /* Isolate one comma separated font name. */
+ (void)copy_option_part(&p, font_name, FONTLEN, ",");
+ font = gui_mch_get_font(font_name, FALSE);
+ if (font != NOFONT)
+ break;
+ }
+ if (font == NOFONT)
+ return FAIL;
+ }
+
+ gui_mch_free_font(gui.wide_font);
+#ifdef FEAT_GUI_GTK
+ /* Avoid unnecessary overhead if 'guifontwide' is equal to 'guifont'. */
+ if (font != NOFONT && gui.norm_font != NOFONT
+ && pango_font_description_equal(font, gui.norm_font))
+ {
+ gui.wide_font = NOFONT;
+ gui_mch_free_font(font);
+ }
+ else
+#endif
+ gui.wide_font = font;
+#ifdef FEAT_GUI_MSWIN
+ gui_mch_wide_font_changed();
+#else
+ /*
+ * TODO: setup wide_bold_font, wide_ital_font and wide_boldital_font to
+ * support those fonts for 'guifontwide'.
+ */
+#endif
+ return OK;
+}
+
+ void
+gui_set_cursor(int row, int col)
+{
+ gui.row = row;
+ gui.col = col;
+}
+
+/*
+ * gui_check_pos - check if the cursor is on the screen.
+ */
+ static void
+gui_check_pos(void)
+{
+ if (gui.row >= screen_Rows)
+ gui.row = screen_Rows - 1;
+ if (gui.col >= screen_Columns)
+ gui.col = screen_Columns - 1;
+ if (gui.cursor_row >= screen_Rows || gui.cursor_col >= screen_Columns)
+ gui.cursor_is_valid = FALSE;
+}
+
+/*
+ * Redraw the cursor if necessary or when forced.
+ * Careful: The contents of ScreenLines[] must match what is on the screen,
+ * otherwise this goes wrong. May need to call out_flush() first.
+ */
+ void
+gui_update_cursor(
+ int force, /* when TRUE, update even when not moved */
+ int clear_selection)/* clear selection under cursor */
+{
+ int cur_width = 0;
+ int cur_height = 0;
+ int old_hl_mask;
+ cursorentry_T *shape;
+ int id;
+#ifdef FEAT_TERMINAL
+ guicolor_T shape_fg = INVALCOLOR;
+ guicolor_T shape_bg = INVALCOLOR;
+#endif
+ guicolor_T cfg, cbg, cc; /* cursor fore-/background color */
+ int cattr; /* cursor attributes */
+ int attr;
+ attrentry_T *aep = NULL;
+
+ /* Don't update the cursor when halfway busy scrolling or the screen size
+ * doesn't match 'columns' and 'lines. ScreenLines[] isn't valid then. */
+ if (!can_update_cursor || screen_Columns != gui.num_cols
+ || screen_Rows != gui.num_rows)
+ return;
+
+ gui_check_pos();
+ if (!gui.cursor_is_valid || force
+ || gui.row != gui.cursor_row || gui.col != gui.cursor_col)
+ {
+ gui_undraw_cursor();
+ if (gui.row < 0)
+ return;
+#ifdef HAVE_INPUT_METHOD
+ if (gui.row != gui.cursor_row || gui.col != gui.cursor_col)
+ im_set_position(gui.row, gui.col);
+#endif
+ gui.cursor_row = gui.row;
+ gui.cursor_col = gui.col;
+
+ /* Only write to the screen after ScreenLines[] has been initialized */
+ if (!screen_cleared || ScreenLines == NULL)
+ return;
+
+ /* Clear the selection if we are about to write over it */
+ if (clear_selection)
+ clip_may_clear_selection(gui.row, gui.row);
+ /* Check that the cursor is inside the shell (resizing may have made
+ * it invalid) */
+ if (gui.row >= screen_Rows || gui.col >= screen_Columns)
+ return;
+
+ gui.cursor_is_valid = TRUE;
+
+ /*
+ * How the cursor is drawn depends on the current mode.
+ * When in a terminal window use the shape/color specified there.
+ */
+#ifdef FEAT_TERMINAL
+ if (terminal_is_active())
+ shape = term_get_cursor_shape(&shape_fg, &shape_bg);
+ else
+#endif
+ shape = &shape_table[get_shape_idx(FALSE)];
+ if (State & LANGMAP)
+ id = shape->id_lm;
+ else
+ id = shape->id;
+
+ /* get the colors and attributes for the cursor. Default is inverted */
+ cfg = INVALCOLOR;
+ cbg = INVALCOLOR;
+ cattr = HL_INVERSE;
+ gui_mch_set_blinking(shape->blinkwait,
+ shape->blinkon,
+ shape->blinkoff);
+ if (shape->blinkwait == 0 || shape->blinkon == 0
+ || shape->blinkoff == 0)
+ gui_mch_stop_blink(FALSE);
+#ifdef FEAT_TERMINAL
+ if (shape_bg != INVALCOLOR)
+ {
+ cattr = 0;
+ cfg = shape_fg;
+ cbg = shape_bg;
+ }
+ else
+#endif
+ if (id > 0)
+ {
+ cattr = syn_id2colors(id, &cfg, &cbg);
+#if defined(HAVE_INPUT_METHOD) || defined(FEAT_HANGULIN)
+ {
+ static int iid;
+ guicolor_T fg, bg;
+
+ if (
+# if defined(FEAT_GUI_GTK) && defined(FEAT_XIM) && !defined(FEAT_HANGULIN)
+ preedit_get_status()
+# else
+ im_get_status()
+# endif
+ )
+ {
+ iid = syn_name2id((char_u *)"CursorIM");
+ if (iid > 0)
+ {
+ syn_id2colors(iid, &fg, &bg);
+ if (bg != INVALCOLOR)
+ cbg = bg;
+ if (fg != INVALCOLOR)
+ cfg = fg;
+ }
+ }
+ }
+#endif
+ }
+
+ /*
+ * Get the attributes for the character under the cursor.
+ * When no cursor color was given, use the character color.
+ */
+ attr = ScreenAttrs[LineOffset[gui.row] + gui.col];
+ if (attr > HL_ALL)
+ aep = syn_gui_attr2entry(attr);
+ if (aep != NULL)
+ {
+ attr = aep->ae_attr;
+ if (cfg == INVALCOLOR)
+ cfg = ((attr & HL_INVERSE) ? aep->ae_u.gui.bg_color
+ : aep->ae_u.gui.fg_color);
+ if (cbg == INVALCOLOR)
+ cbg = ((attr & HL_INVERSE) ? aep->ae_u.gui.fg_color
+ : aep->ae_u.gui.bg_color);
+ }
+ if (cfg == INVALCOLOR)
+ cfg = (attr & HL_INVERSE) ? gui.back_pixel : gui.norm_pixel;
+ if (cbg == INVALCOLOR)
+ cbg = (attr & HL_INVERSE) ? gui.norm_pixel : gui.back_pixel;
+
+#ifdef FEAT_XIM
+ if (aep != NULL)
+ {
+ xim_bg_color = ((attr & HL_INVERSE) ? aep->ae_u.gui.fg_color
+ : aep->ae_u.gui.bg_color);
+ xim_fg_color = ((attr & HL_INVERSE) ? aep->ae_u.gui.bg_color
+ : aep->ae_u.gui.fg_color);
+ if (xim_bg_color == INVALCOLOR)
+ xim_bg_color = (attr & HL_INVERSE) ? gui.norm_pixel
+ : gui.back_pixel;
+ if (xim_fg_color == INVALCOLOR)
+ xim_fg_color = (attr & HL_INVERSE) ? gui.back_pixel
+ : gui.norm_pixel;
+ }
+ else
+ {
+ xim_bg_color = (attr & HL_INVERSE) ? gui.norm_pixel
+ : gui.back_pixel;
+ xim_fg_color = (attr & HL_INVERSE) ? gui.back_pixel
+ : gui.norm_pixel;
+ }
+#endif
+
+ attr &= ~HL_INVERSE;
+ if (cattr & HL_INVERSE)
+ {
+ cc = cbg;
+ cbg = cfg;
+ cfg = cc;
+ }
+ cattr &= ~HL_INVERSE;
+
+ /*
+ * When we don't have window focus, draw a hollow cursor.
+ */
+ if (!gui.in_focus)
+ {
+ gui_mch_draw_hollow_cursor(cbg);
+ return;
+ }
+
+ old_hl_mask = gui.highlight_mask;
+ if (shape->shape == SHAPE_BLOCK
+#ifdef FEAT_HANGULIN
+ || composing_hangul
+#endif
+ )
+ {
+ /*
+ * Draw the text character with the cursor colors. Use the
+ * character attributes plus the cursor attributes.
+ */
+ gui.highlight_mask = (cattr | attr);
+#ifdef FEAT_HANGULIN
+ if (composing_hangul)
+ {
+ char_u *comp_buf;
+ int comp_len;
+
+ comp_buf = hangul_composing_buffer_get(&comp_len);
+ if (comp_buf)
+ {
+ (void)gui_outstr_nowrap(comp_buf, comp_len,
+ GUI_MON_IS_CURSOR | GUI_MON_NOCLEAR,
+ cfg, cbg, 0);
+ vim_free(comp_buf);
+ }
+ }
+ else
+#endif
+ (void)gui_screenchar(LineOffset[gui.row] + gui.col,
+ GUI_MON_IS_CURSOR | GUI_MON_NOCLEAR, cfg, cbg, 0);
+ }
+ else
+ {
+#if defined(FEAT_RIGHTLEFT)
+ int col_off = FALSE;
+#endif
+ /*
+ * First draw the partial cursor, then overwrite with the text
+ * character, using a transparent background.
+ */
+ if (shape->shape == SHAPE_VER)
+ {
+ cur_height = gui.char_height;
+ cur_width = (gui.char_width * shape->percentage + 99) / 100;
+ }
+ else
+ {
+ cur_height = (gui.char_height * shape->percentage + 99) / 100;
+ cur_width = gui.char_width;
+ }
+ if (has_mbyte && (*mb_off2cells)(LineOffset[gui.row] + gui.col,
+ LineOffset[gui.row] + screen_Columns) > 1)
+ {
+ /* Double wide character. */
+ if (shape->shape != SHAPE_VER)
+ cur_width += gui.char_width;
+#ifdef FEAT_RIGHTLEFT
+ if (CURSOR_BAR_RIGHT)
+ {
+ /* gui.col points to the left halve of the character but
+ * the vertical line needs to be on the right halve.
+ * A double-wide horizontal line is also drawn from the
+ * right halve in gui_mch_draw_part_cursor(). */
+ col_off = TRUE;
+ ++gui.col;
+ }
+#endif
+ }
+ gui_mch_draw_part_cursor(cur_width, cur_height, cbg);
+#if defined(FEAT_RIGHTLEFT)
+ if (col_off)
+ --gui.col;
+#endif
+
+#ifndef FEAT_GUI_MSWIN /* doesn't seem to work for MSWindows */
+ gui.highlight_mask = ScreenAttrs[LineOffset[gui.row] + gui.col];
+ (void)gui_screenchar(LineOffset[gui.row] + gui.col,
+ GUI_MON_TRS_CURSOR | GUI_MON_NOCLEAR,
+ (guicolor_T)0, (guicolor_T)0, 0);
+#endif
+ }
+ gui.highlight_mask = old_hl_mask;
+ }
+}
+
+#if defined(FEAT_MENU) || defined(PROTO)
+ void
+gui_position_menu(void)
+{
+# if !defined(FEAT_GUI_GTK) && !defined(FEAT_GUI_MOTIF)
+ if (gui.menu_is_active && gui.in_use)
+ gui_mch_set_menu_pos(0, 0, gui.menu_width, gui.menu_height);
+# endif
+}
+#endif
+
+/*
+ * Position the various GUI components (text area, menu). The vertical
+ * scrollbars are NOT handled here. See gui_update_scrollbars().
+ */
+ static void
+gui_position_components(int total_width UNUSED)
+{
+ int text_area_x;
+ int text_area_y;
+ int text_area_width;
+ int text_area_height;
+
+ /* avoid that moving components around generates events */
+ ++hold_gui_events;
+
+ text_area_x = 0;
+ if (gui.which_scrollbars[SBAR_LEFT])
+ text_area_x += gui.scrollbar_width;
+
+ text_area_y = 0;
+#if defined(FEAT_MENU) && !(defined(FEAT_GUI_GTK) || defined(FEAT_GUI_PHOTON))
+ gui.menu_width = total_width;
+ if (gui.menu_is_active)
+ text_area_y += gui.menu_height;
+#endif
+#if defined(FEAT_TOOLBAR) && defined(FEAT_GUI_MSWIN)
+ if (vim_strchr(p_go, GO_TOOLBAR) != NULL)
+ text_area_y = TOOLBAR_BUTTON_HEIGHT + TOOLBAR_BORDER_HEIGHT;
+#endif
+
+# if defined(FEAT_GUI_TABLINE) && (defined(FEAT_GUI_MSWIN) \
+ || defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_MAC))
+ if (gui_has_tabline())
+ text_area_y += gui.tabline_height;
+#endif
+
+#if defined(FEAT_TOOLBAR) && (defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA))
+ if (vim_strchr(p_go, GO_TOOLBAR) != NULL)
+ {
+# ifdef FEAT_GUI_ATHENA
+ gui_mch_set_toolbar_pos(0, text_area_y,
+ gui.menu_width, gui.toolbar_height);
+# endif
+ text_area_y += gui.toolbar_height;
+ }
+#endif
+
+ text_area_width = gui.num_cols * gui.char_width + gui.border_offset * 2;
+ text_area_height = gui.num_rows * gui.char_height + gui.border_offset * 2;
+
+ gui_mch_set_text_area_pos(text_area_x,
+ text_area_y,
+ text_area_width,
+ text_area_height
+#if defined(FEAT_XIM) && !defined(FEAT_GUI_GTK)
+ + xim_get_status_area_height()
+#endif
+ );
+#ifdef FEAT_MENU
+ gui_position_menu();
+#endif
+ if (gui.which_scrollbars[SBAR_BOTTOM])
+ gui_mch_set_scrollbar_pos(&gui.bottom_sbar,
+ text_area_x,
+ text_area_y + text_area_height,
+ text_area_width,
+ gui.scrollbar_height);
+ gui.left_sbar_x = 0;
+ gui.right_sbar_x = text_area_x + text_area_width;
+
+ --hold_gui_events;
+}
+
+/*
+ * Get the width of the widgets and decorations to the side of the text area.
+ */
+ int
+gui_get_base_width(void)
+{
+ int base_width;
+
+ base_width = 2 * gui.border_offset;
+ if (gui.which_scrollbars[SBAR_LEFT])
+ base_width += gui.scrollbar_width;
+ if (gui.which_scrollbars[SBAR_RIGHT])
+ base_width += gui.scrollbar_width;
+ return base_width;
+}
+
+/*
+ * Get the height of the widgets and decorations above and below the text area.
+ */
+ int
+gui_get_base_height(void)
+{
+ int base_height;
+
+ base_height = 2 * gui.border_offset;
+ if (gui.which_scrollbars[SBAR_BOTTOM])
+ base_height += gui.scrollbar_height;
+#ifdef FEAT_GUI_GTK
+ /* We can't take the sizes properly into account until anything is
+ * realized. Therefore we recalculate all the values here just before
+ * setting the size. (--mdcki) */
+#else
+# ifdef FEAT_MENU
+ if (gui.menu_is_active)
+ base_height += gui.menu_height;
+# endif
+# ifdef FEAT_TOOLBAR
+ if (vim_strchr(p_go, GO_TOOLBAR) != NULL)
+# if defined(FEAT_GUI_MSWIN) && defined(FEAT_TOOLBAR)
+ base_height += (TOOLBAR_BUTTON_HEIGHT + TOOLBAR_BORDER_HEIGHT);
+# else
+ base_height += gui.toolbar_height;
+# endif
+# endif
+# if defined(FEAT_GUI_TABLINE) && (defined(FEAT_GUI_MSWIN) \
+ || defined(FEAT_GUI_MOTIF))
+ if (gui_has_tabline())
+ base_height += gui.tabline_height;
+# endif
+# ifdef FEAT_FOOTER
+ if (vim_strchr(p_go, GO_FOOTER) != NULL)
+ base_height += gui.footer_height;
+# endif
+# if defined(FEAT_GUI_MOTIF) && defined(FEAT_MENU)
+ base_height += gui_mch_text_area_extra_height();
+# endif
+#endif
+ return base_height;
+}
+
+/*
+ * Should be called after the GUI shell has been resized. Its arguments are
+ * the new width and height of the shell in pixels.
+ */
+ void
+gui_resize_shell(int pixel_width, int pixel_height)
+{
+ static int busy = FALSE;
+
+ if (!gui.shell_created) /* ignore when still initializing */
+ return;
+
+ /*
+ * Can't resize the screen while it is being redrawn. Remember the new
+ * size and handle it later.
+ */
+ if (updating_screen || busy)
+ {
+ new_pixel_width = pixel_width;
+ new_pixel_height = pixel_height;
+ return;
+ }
+
+again:
+ new_pixel_width = 0;
+ new_pixel_height = 0;
+ busy = TRUE;
+
+ /* Flush pending output before redrawing */
+ out_flush();
+
+ gui.num_cols = (pixel_width - gui_get_base_width()) / gui.char_width;
+ gui.num_rows = (pixel_height - gui_get_base_height()) / gui.char_height;
+
+ gui_position_components(pixel_width);
+ gui_reset_scroll_region();
+
+ /*
+ * At the "more" and ":confirm" prompt there is no redraw, put the cursor
+ * at the last line here (why does it have to be one row too low?).
+ */
+ if (State == ASKMORE || State == CONFIRM)
+ gui.row = gui.num_rows;
+
+ /* Only comparing Rows and Columns may be sufficient, but let's stay on
+ * the safe side. */
+ if (gui.num_rows != screen_Rows || gui.num_cols != screen_Columns
+ || gui.num_rows != Rows || gui.num_cols != Columns)
+ shell_resized();
+
+ gui_update_scrollbars(TRUE);
+ gui_update_cursor(FALSE, TRUE);
+#if defined(FEAT_XIM) && !defined(FEAT_GUI_GTK)
+ xim_set_status_area();
+#endif
+
+ busy = FALSE;
+
+ /* We may have been called again while redrawing the screen.
+ * Need to do it all again with the latest size then. But only if the size
+ * actually changed. */
+ if (new_pixel_height)
+ {
+ if (pixel_width == new_pixel_width && pixel_height == new_pixel_height)
+ {
+ new_pixel_width = 0;
+ new_pixel_height = 0;
+ }
+ else
+ {
+ pixel_width = new_pixel_width;
+ pixel_height = new_pixel_height;
+ goto again;
+ }
+ }
+}
+
+/*
+ * Check if gui_resize_shell() must be called.
+ */
+ void
+gui_may_resize_shell(void)
+{
+ if (new_pixel_height)
+ /* careful: gui_resize_shell() may postpone the resize again if we
+ * were called indirectly by it */
+ gui_resize_shell(new_pixel_width, new_pixel_height);
+}
+
+ int
+gui_get_shellsize(void)
+{
+ Rows = gui.num_rows;
+ Columns = gui.num_cols;
+ return OK;
+}
+
+/*
+ * Set the size of the Vim shell according to Rows and Columns.
+ * If "fit_to_display" is TRUE then the size may be reduced to fit the window
+ * on the screen.
+ * When "mustset" is TRUE the size was set by the user. When FALSE a UI
+ * component was added or removed (e.g., a scrollbar).
+ */
+ void
+gui_set_shellsize(
+ int mustset UNUSED,
+ int fit_to_display,
+ int direction) /* RESIZE_HOR, RESIZE_VER */
+{
+ int base_width;
+ int base_height;
+ int width;
+ int height;
+ int min_width;
+ int min_height;
+ int screen_w;
+ int screen_h;
+#ifdef FEAT_GUI_GTK
+ int un_maximize = mustset;
+ int did_adjust = 0;
+#endif
+ int x = -1, y = -1;
+
+ if (!gui.shell_created)
+ return;
+
+#if defined(MSWIN) || defined(FEAT_GUI_GTK)
+ /* If not setting to a user specified size and maximized, calculate the
+ * number of characters that fit in the maximized window. */
+ if (!mustset && (vim_strchr(p_go, GO_KEEPWINSIZE) != NULL
+ || gui_mch_maximized()))
+ {
+ gui_mch_newfont();
+ return;
+ }
+#endif
+
+ base_width = gui_get_base_width();
+ base_height = gui_get_base_height();
+ if (fit_to_display)
+ /* Remember the original window position. */
+ (void)gui_mch_get_winpos(&x, &y);
+
+ width = Columns * gui.char_width + base_width;
+ height = Rows * gui.char_height + base_height;
+
+ if (fit_to_display)
+ {
+ gui_mch_get_screen_dimensions(&screen_w, &screen_h);
+ if ((direction & RESIZE_HOR) && width > screen_w)
+ {
+ Columns = (screen_w - base_width) / gui.char_width;
+ if (Columns < MIN_COLUMNS)
+ Columns = MIN_COLUMNS;
+ width = Columns * gui.char_width + base_width;
+#ifdef FEAT_GUI_GTK
+ ++did_adjust;
+#endif
+ }
+ if ((direction & RESIZE_VERT) && height > screen_h)
+ {
+ Rows = (screen_h - base_height) / gui.char_height;
+ check_shellsize();
+ height = Rows * gui.char_height + base_height;
+#ifdef FEAT_GUI_GTK
+ ++did_adjust;
+#endif
+ }
+#ifdef FEAT_GUI_GTK
+ if (did_adjust == 2 || (width + gui.char_width >= screen_w
+ && height + gui.char_height >= screen_h))
+ /* don't unmaximize if at maximum size */
+ un_maximize = FALSE;
+#endif
+ }
+ limit_screen_size();
+ gui.num_cols = Columns;
+ gui.num_rows = Rows;
+
+ min_width = base_width + MIN_COLUMNS * gui.char_width;
+ min_height = base_height + MIN_LINES * gui.char_height;
+ min_height += tabline_height() * gui.char_height;
+
+#ifdef FEAT_GUI_GTK
+ if (un_maximize)
+ {
+ /* If the window size is smaller than the screen unmaximize the
+ * window, otherwise resizing won't work. */
+ gui_mch_get_screen_dimensions(&screen_w, &screen_h);
+ if ((width + gui.char_width < screen_w
+ || height + gui.char_height * 2 < screen_h)
+ && gui_mch_maximized())
+ gui_mch_unmaximize();
+ }
+#endif
+
+ gui_mch_set_shellsize(width, height, min_width, min_height,
+ base_width, base_height, direction);
+
+ if (fit_to_display && x >= 0 && y >= 0)
+ {
+ /* Some window managers put the Vim window left of/above the screen.
+ * Only change the position if it wasn't already negative before
+ * (happens on MS-Windows with a secondary monitor). */
+ gui_mch_update();
+ if (gui_mch_get_winpos(&x, &y) == OK && (x < 0 || y < 0))
+ gui_mch_set_winpos(x < 0 ? 0 : x, y < 0 ? 0 : y);
+ }
+
+ gui_position_components(width);
+ gui_update_scrollbars(TRUE);
+ gui_reset_scroll_region();
+}
+
+/*
+ * Called when Rows and/or Columns has changed.
+ */
+ void
+gui_new_shellsize(void)
+{
+ gui_reset_scroll_region();
+}
+
+/*
+ * Make scroll region cover whole screen.
+ */
+ void
+gui_reset_scroll_region(void)
+{
+ gui.scroll_region_top = 0;
+ gui.scroll_region_bot = gui.num_rows - 1;
+ gui.scroll_region_left = 0;
+ gui.scroll_region_right = gui.num_cols - 1;
+}
+
+ void
+gui_start_highlight(int mask)
+{
+ if (mask > HL_ALL) /* highlight code */
+ gui.highlight_mask = mask;
+ else /* mask */
+ gui.highlight_mask |= mask;
+}
+
+ void
+gui_stop_highlight(int mask)
+{
+ if (mask > HL_ALL) /* highlight code */
+ gui.highlight_mask = HL_NORMAL;
+ else /* mask */
+ gui.highlight_mask &= ~mask;
+}
+
+/*
+ * Clear a rectangular region of the screen from text pos (row1, col1) to
+ * (row2, col2) inclusive.
+ */
+ void
+gui_clear_block(
+ int row1,
+ int col1,
+ int row2,
+ int col2)
+{
+ /* Clear the selection if we are about to write over it */
+ clip_may_clear_selection(row1, row2);
+
+ gui_mch_clear_block(row1, col1, row2, col2);
+
+ /* Invalidate cursor if it was in this block */
+ if ( gui.cursor_row >= row1 && gui.cursor_row <= row2
+ && gui.cursor_col >= col1 && gui.cursor_col <= col2)
+ gui.cursor_is_valid = FALSE;
+}
+
+/*
+ * Write code to update the cursor later. This avoids the need to flush the
+ * output buffer before calling gui_update_cursor().
+ */
+ void
+gui_update_cursor_later(void)
+{
+ OUT_STR(IF_EB("\033|s", ESC_STR "|s"));
+}
+
+ void
+gui_write(
+ char_u *s,
+ int len)
+{
+ char_u *p;
+ int arg1 = 0, arg2 = 0;
+ int force_cursor = FALSE; /* force cursor update */
+ int force_scrollbar = FALSE;
+ static win_T *old_curwin = NULL;
+
+/* #define DEBUG_GUI_WRITE */
+#ifdef DEBUG_GUI_WRITE
+ {
+ int i;
+ char_u *str;
+
+ printf("gui_write(%d):\n ", len);
+ for (i = 0; i < len; i++)
+ if (s[i] == ESC)
+ {
+ if (i != 0)
+ printf("\n ");
+ printf("<ESC>");
+ }
+ else
+ {
+ str = transchar_byte(s[i]);
+ if (str[0] && str[1])
+ printf("<%s>", (char *)str);
+ else
+ printf("%s", (char *)str);
+ }
+ printf("\n");
+ }
+#endif
+ while (len)
+ {
+ if (s[0] == ESC && s[1] == '|')
+ {
+ p = s + 2;
+ if (VIM_ISDIGIT(*p) || (*p == '-' && VIM_ISDIGIT(*(p + 1))))
+ {
+ arg1 = getdigits(&p);
+ if (p > s + len)
+ break;
+ if (*p == ';')
+ {
+ ++p;
+ arg2 = getdigits(&p);
+ if (p > s + len)
+ break;
+ }
+ }
+ switch (*p)
+ {
+ case 'C': /* Clear screen */
+ clip_scroll_selection(9999);
+ gui_mch_clear_all();
+ gui.cursor_is_valid = FALSE;
+ force_scrollbar = TRUE;
+ break;
+ case 'M': /* Move cursor */
+ gui_set_cursor(arg1, arg2);
+ break;
+ case 's': /* force cursor (shape) update */
+ force_cursor = TRUE;
+ break;
+ case 'R': /* Set scroll region */
+ if (arg1 < arg2)
+ {
+ gui.scroll_region_top = arg1;
+ gui.scroll_region_bot = arg2;
+ }
+ else
+ {
+ gui.scroll_region_top = arg2;
+ gui.scroll_region_bot = arg1;
+ }
+ break;
+ case 'V': /* Set vertical scroll region */
+ if (arg1 < arg2)
+ {
+ gui.scroll_region_left = arg1;
+ gui.scroll_region_right = arg2;
+ }
+ else
+ {
+ gui.scroll_region_left = arg2;
+ gui.scroll_region_right = arg1;
+ }
+ break;
+ case 'd': /* Delete line */
+ gui_delete_lines(gui.row, 1);
+ break;
+ case 'D': /* Delete lines */
+ gui_delete_lines(gui.row, arg1);
+ break;
+ case 'i': /* Insert line */
+ gui_insert_lines(gui.row, 1);
+ break;
+ case 'I': /* Insert lines */
+ gui_insert_lines(gui.row, arg1);
+ break;
+ case '$': /* Clear to end-of-line */
+ gui_clear_block(gui.row, gui.col, gui.row,
+ (int)Columns - 1);
+ break;
+ case 'h': /* Turn on highlighting */
+ gui_start_highlight(arg1);
+ break;
+ case 'H': /* Turn off highlighting */
+ gui_stop_highlight(arg1);
+ break;
+ case 'f': /* flash the window (visual bell) */
+ gui_mch_flash(arg1 == 0 ? 20 : arg1);
+ break;
+ default:
+ p = s + 1; /* Skip the ESC */
+ break;
+ }
+ len -= (int)(++p - s);
+ s = p;
+ }
+ else if (
+#ifdef EBCDIC
+ CtrlChar(s[0]) != 0 /* Ctrl character */
+#else
+ s[0] < 0x20 /* Ctrl character */
+#endif
+#ifdef FEAT_SIGN_ICONS
+ && s[0] != SIGN_BYTE
+# ifdef FEAT_NETBEANS_INTG
+ && s[0] != MULTISIGN_BYTE
+# endif
+#endif
+ )
+ {
+ if (s[0] == '\n') /* NL */
+ {
+ gui.col = 0;
+ if (gui.row < gui.scroll_region_bot)
+ gui.row++;
+ else
+ gui_delete_lines(gui.scroll_region_top, 1);
+ }
+ else if (s[0] == '\r') /* CR */
+ {
+ gui.col = 0;
+ }
+ else if (s[0] == '\b') /* Backspace */
+ {
+ if (gui.col)
+ --gui.col;
+ }
+ else if (s[0] == Ctrl_L) /* cursor-right */
+ {
+ ++gui.col;
+ }
+ else if (s[0] == Ctrl_G) /* Beep */
+ {
+ gui_mch_beep();
+ }
+ /* Other Ctrl character: shouldn't happen! */
+
+ --len; /* Skip this char */
+ ++s;
+ }
+ else
+ {
+ p = s;
+ while (len > 0 && (
+#ifdef EBCDIC
+ CtrlChar(*p) == 0
+#else
+ *p >= 0x20
+#endif
+#ifdef FEAT_SIGN_ICONS
+ || *p == SIGN_BYTE
+# ifdef FEAT_NETBEANS_INTG
+ || *p == MULTISIGN_BYTE
+# endif
+#endif
+ ))
+ {
+ len--;
+ p++;
+ }
+ gui_outstr(s, (int)(p - s));
+ s = p;
+ }
+ }
+
+ /* Postponed update of the cursor (won't work if "can_update_cursor" isn't
+ * set). */
+ if (force_cursor)
+ gui_update_cursor(TRUE, TRUE);
+
+ /* When switching to another window the dragging must have stopped.
+ * Required for GTK, dragged_sb isn't reset. */
+ if (old_curwin != curwin)
+ gui.dragged_sb = SBAR_NONE;
+
+ /* Update the scrollbars after clearing the screen or when switched
+ * to another window.
+ * Update the horizontal scrollbar always, it's difficult to check all
+ * situations where it might change. */
+ if (force_scrollbar || old_curwin != curwin)
+ gui_update_scrollbars(force_scrollbar);
+ else
+ gui_update_horiz_scrollbar(FALSE);
+ old_curwin = curwin;
+
+ /*
+ * We need to make sure this is cleared since Athena doesn't tell us when
+ * he is done dragging. Do the same for GTK.
+ */
+#if defined(FEAT_GUI_ATHENA) || defined(FEAT_GUI_GTK)
+ gui.dragged_sb = SBAR_NONE;
+#endif
+
+ gui_may_flush(); /* In case vim decides to take a nap */
+}
+
+/*
+ * When ScreenLines[] is invalid, updating the cursor should not be done, it
+ * produces wrong results. Call gui_dont_update_cursor() before that code and
+ * gui_can_update_cursor() afterwards.
+ */
+ void
+gui_dont_update_cursor(int undraw)
+{
+ if (gui.in_use)
+ {
+ /* Undraw the cursor now, we probably can't do it after the change. */
+ if (undraw)
+ gui_undraw_cursor();
+ can_update_cursor = FALSE;
+ }
+}
+
+ void
+gui_can_update_cursor(void)
+{
+ can_update_cursor = TRUE;
+ /* No need to update the cursor right now, there is always more output
+ * after scrolling. */
+}
+
+/*
+ * Disable issuing gui_mch_flush().
+ */
+ void
+gui_disable_flush(void)
+{
+ ++disable_flush;
+}
+
+/*
+ * Enable issuing gui_mch_flush().
+ */
+ void
+gui_enable_flush(void)
+{
+ --disable_flush;
+}
+
+/*
+ * Issue gui_mch_flush() if it is not disabled.
+ */
+ void
+gui_may_flush(void)
+{
+ if (disable_flush == 0)
+ gui_mch_flush();
+}
+
+ static void
+gui_outstr(char_u *s, int len)
+{
+ int this_len;
+ int cells;
+
+ if (len == 0)
+ return;
+
+ if (len < 0)
+ len = (int)STRLEN(s);
+
+ while (len > 0)
+ {
+ if (has_mbyte)
+ {
+ /* Find out how many chars fit in the current line. */
+ cells = 0;
+ for (this_len = 0; this_len < len; )
+ {
+ cells += (*mb_ptr2cells)(s + this_len);
+ if (gui.col + cells > Columns)
+ break;
+ this_len += (*mb_ptr2len)(s + this_len);
+ }
+ if (this_len > len)
+ this_len = len; /* don't include following composing char */
+ }
+ else
+ if (gui.col + len > Columns)
+ this_len = Columns - gui.col;
+ else
+ this_len = len;
+
+ (void)gui_outstr_nowrap(s, this_len,
+ 0, (guicolor_T)0, (guicolor_T)0, 0);
+ s += this_len;
+ len -= this_len;
+ /* fill up for a double-width char that doesn't fit. */
+ if (len > 0 && gui.col < Columns)
+ (void)gui_outstr_nowrap((char_u *)" ", 1,
+ 0, (guicolor_T)0, (guicolor_T)0, 0);
+ /* The cursor may wrap to the next line. */
+ if (gui.col >= Columns)
+ {
+ gui.col = 0;
+ gui.row++;
+ }
+ }
+}
+
+/*
+ * Output one character (may be one or two display cells).
+ * Caller must check for valid "off".
+ * Returns FAIL or OK, just like gui_outstr_nowrap().
+ */
+ static int
+gui_screenchar(
+ int off, /* Offset from start of screen */
+ int flags,
+ guicolor_T fg, /* colors for cursor */
+ guicolor_T bg, /* colors for cursor */
+ int back) /* backup this many chars when using bold trick */
+{
+ char_u buf[MB_MAXBYTES + 1];
+
+ /* Don't draw right halve of a double-width UTF-8 char. "cannot happen" */
+ if (enc_utf8 && ScreenLines[off] == 0)
+ return OK;
+
+ if (enc_utf8 && ScreenLinesUC[off] != 0)
+ /* Draw UTF-8 multi-byte character. */
+ return gui_outstr_nowrap(buf, utfc_char2bytes(off, buf),
+ flags, fg, bg, back);
+
+ if (enc_dbcs == DBCS_JPNU && ScreenLines[off] == 0x8e)
+ {
+ buf[0] = ScreenLines[off];
+ buf[1] = ScreenLines2[off];
+ return gui_outstr_nowrap(buf, 2, flags, fg, bg, back);
+ }
+
+ /* Draw non-multi-byte character or DBCS character. */
+ return gui_outstr_nowrap(ScreenLines + off,
+ enc_dbcs ? (*mb_ptr2len)(ScreenLines + off) : 1,
+ flags, fg, bg, back);
+}
+
+#ifdef FEAT_GUI_GTK
+/*
+ * Output the string at the given screen position. This is used in place
+ * of gui_screenchar() where possible because Pango needs as much context
+ * as possible to work nicely. It's a lot faster as well.
+ */
+ static int
+gui_screenstr(
+ int off, /* Offset from start of screen */
+ int len, /* string length in screen cells */
+ int flags,
+ guicolor_T fg, /* colors for cursor */
+ guicolor_T bg, /* colors for cursor */
+ int back) /* backup this many chars when using bold trick */
+{
+ char_u *buf;
+ int outlen = 0;
+ int i;
+ int retval;
+
+ if (len <= 0) /* "cannot happen"? */
+ return OK;
+
+ if (enc_utf8)
+ {
+ buf = alloc((unsigned)(len * MB_MAXBYTES + 1));
+ if (buf == NULL)
+ return OK; /* not much we could do here... */
+
+ for (i = off; i < off + len; ++i)
+ {
+ if (ScreenLines[i] == 0)
+ continue; /* skip second half of double-width char */
+
+ if (ScreenLinesUC[i] == 0)
+ buf[outlen++] = ScreenLines[i];
+ else
+ outlen += utfc_char2bytes(i, buf + outlen);
+ }
+
+ buf[outlen] = NUL; /* only to aid debugging */
+ retval = gui_outstr_nowrap(buf, outlen, flags, fg, bg, back);
+ vim_free(buf);
+
+ return retval;
+ }
+ else if (enc_dbcs == DBCS_JPNU)
+ {
+ buf = alloc((unsigned)(len * 2 + 1));
+ if (buf == NULL)
+ return OK; /* not much we could do here... */
+
+ for (i = off; i < off + len; ++i)
+ {
+ buf[outlen++] = ScreenLines[i];
+
+ /* handle double-byte single-width char */
+ if (ScreenLines[i] == 0x8e)
+ buf[outlen++] = ScreenLines2[i];
+ else if (MB_BYTE2LEN(ScreenLines[i]) == 2)
+ buf[outlen++] = ScreenLines[++i];
+ }
+
+ buf[outlen] = NUL; /* only to aid debugging */
+ retval = gui_outstr_nowrap(buf, outlen, flags, fg, bg, back);
+ vim_free(buf);
+
+ return retval;
+ }
+ else
+ {
+ return gui_outstr_nowrap(&ScreenLines[off], len,
+ flags, fg, bg, back);
+ }
+}
+#endif /* FEAT_GUI_GTK */
+
+/*
+ * Output the given string at the current cursor position. If the string is
+ * too long to fit on the line, then it is truncated.
+ * "flags":
+ * GUI_MON_IS_CURSOR should only be used when this function is being called to
+ * actually draw (an inverted) cursor.
+ * GUI_MON_TRS_CURSOR is used to draw the cursor text with a transparent
+ * background.
+ * GUI_MON_NOCLEAR is used to avoid clearing the selection when drawing over
+ * it.
+ * Returns OK, unless "back" is non-zero and using the bold trick, then return
+ * FAIL (the caller should start drawing "back" chars back).
+ */
+ int
+gui_outstr_nowrap(
+ char_u *s,
+ int len,
+ int flags,
+ guicolor_T fg, /* colors for cursor */
+ guicolor_T bg, /* colors for cursor */
+ int back) /* backup this many chars when using bold trick */
+{
+ long_u highlight_mask;
+ long_u hl_mask_todo;
+ guicolor_T fg_color;
+ guicolor_T bg_color;
+ guicolor_T sp_color;
+#if !defined(FEAT_GUI_GTK)
+ GuiFont font = NOFONT;
+ GuiFont wide_font = NOFONT;
+# ifdef FEAT_XFONTSET
+ GuiFontset fontset = NOFONTSET;
+# endif
+#endif
+ attrentry_T *aep = NULL;
+ int draw_flags;
+ int col = gui.col;
+#ifdef FEAT_SIGN_ICONS
+ int draw_sign = FALSE;
+# ifdef FEAT_NETBEANS_INTG
+ int multi_sign = FALSE;
+# endif
+#endif
+
+ if (len < 0)
+ len = (int)STRLEN(s);
+ if (len == 0)
+ return OK;
+
+#ifdef FEAT_SIGN_ICONS
+ if (*s == SIGN_BYTE
+# ifdef FEAT_NETBEANS_INTG
+ || *s == MULTISIGN_BYTE
+# endif
+ )
+ {
+# ifdef FEAT_NETBEANS_INTG
+ if (*s == MULTISIGN_BYTE)
+ multi_sign = TRUE;
+# endif
+ /* draw spaces instead */
+ s = (char_u *)" ";
+ if (len == 1 && col > 0)
+ --col;
+ len = 2;
+ draw_sign = TRUE;
+ highlight_mask = 0;
+ }
+ else
+#endif
+ if (gui.highlight_mask > HL_ALL)
+ {
+ aep = syn_gui_attr2entry(gui.highlight_mask);
+ if (aep == NULL) /* highlighting not set */
+ highlight_mask = 0;
+ else
+ highlight_mask = aep->ae_attr;
+ }
+ else
+ highlight_mask = gui.highlight_mask;
+ hl_mask_todo = highlight_mask;
+
+#if !defined(FEAT_GUI_GTK)
+ /* Set the font */
+ if (aep != NULL && aep->ae_u.gui.font != NOFONT)
+ font = aep->ae_u.gui.font;
+# ifdef FEAT_XFONTSET
+ else if (aep != NULL && aep->ae_u.gui.fontset != NOFONTSET)
+ fontset = aep->ae_u.gui.fontset;
+# endif
+ else
+ {
+# ifdef FEAT_XFONTSET
+ if (gui.fontset != NOFONTSET)
+ fontset = gui.fontset;
+ else
+# endif
+ if (hl_mask_todo & (HL_BOLD | HL_STANDOUT))
+ {
+ if ((hl_mask_todo & HL_ITALIC) && gui.boldital_font != NOFONT)
+ {
+ font = gui.boldital_font;
+ hl_mask_todo &= ~(HL_BOLD | HL_STANDOUT | HL_ITALIC);
+ }
+ else if (gui.bold_font != NOFONT)
+ {
+ font = gui.bold_font;
+ hl_mask_todo &= ~(HL_BOLD | HL_STANDOUT);
+ }
+ else
+ font = gui.norm_font;
+ }
+ else if ((hl_mask_todo & HL_ITALIC) && gui.ital_font != NOFONT)
+ {
+ font = gui.ital_font;
+ hl_mask_todo &= ~HL_ITALIC;
+ }
+ else
+ font = gui.norm_font;
+
+ /*
+ * Choose correct wide_font by font. wide_font should be set with font
+ * at same time in above block. But it will make many "ifdef" nasty
+ * blocks. So we do it here.
+ */
+ if (font == gui.boldital_font && gui.wide_boldital_font)
+ wide_font = gui.wide_boldital_font;
+ else if (font == gui.bold_font && gui.wide_bold_font)
+ wide_font = gui.wide_bold_font;
+ else if (font == gui.ital_font && gui.wide_ital_font)
+ wide_font = gui.wide_ital_font;
+ else if (font == gui.norm_font && gui.wide_font)
+ wide_font = gui.wide_font;
+ }
+# ifdef FEAT_XFONTSET
+ if (fontset != NOFONTSET)
+ gui_mch_set_fontset(fontset);
+ else
+# endif
+ gui_mch_set_font(font);
+#endif
+
+ draw_flags = 0;
+
+ /* Set the color */
+ bg_color = gui.back_pixel;
+ if ((flags & GUI_MON_IS_CURSOR) && gui.in_focus)
+ {
+ draw_flags |= DRAW_CURSOR;
+ fg_color = fg;
+ bg_color = bg;
+ sp_color = fg;
+ }
+ else if (aep != NULL)
+ {
+ fg_color = aep->ae_u.gui.fg_color;
+ if (fg_color == INVALCOLOR)
+ fg_color = gui.norm_pixel;
+ bg_color = aep->ae_u.gui.bg_color;
+ if (bg_color == INVALCOLOR)
+ bg_color = gui.back_pixel;
+ sp_color = aep->ae_u.gui.sp_color;
+ if (sp_color == INVALCOLOR)
+ sp_color = fg_color;
+ }
+ else
+ {
+ fg_color = gui.norm_pixel;
+ sp_color = fg_color;
+ }
+
+ if (highlight_mask & (HL_INVERSE | HL_STANDOUT))
+ {
+#if defined(AMIGA)
+ gui_mch_set_colors(bg_color, fg_color);
+#else
+ gui_mch_set_fg_color(bg_color);
+ gui_mch_set_bg_color(fg_color);
+#endif
+ }
+ else
+ {
+#if defined(AMIGA)
+ gui_mch_set_colors(fg_color, bg_color);
+#else
+ gui_mch_set_fg_color(fg_color);
+ gui_mch_set_bg_color(bg_color);
+#endif
+ }
+ gui_mch_set_sp_color(sp_color);
+
+ /* Clear the selection if we are about to write over it */
+ if (!(flags & GUI_MON_NOCLEAR))
+ clip_may_clear_selection(gui.row, gui.row);
+
+
+ /* If there's no bold font, then fake it */
+ if (hl_mask_todo & (HL_BOLD | HL_STANDOUT))
+ draw_flags |= DRAW_BOLD;
+
+ /*
+ * When drawing bold or italic characters the spill-over from the left
+ * neighbor may be destroyed. Let the caller backup to start redrawing
+ * just after a blank.
+ */
+ if (back != 0 && ((draw_flags & DRAW_BOLD) || (highlight_mask & HL_ITALIC)))
+ return FAIL;
+
+#if defined(FEAT_GUI_GTK)
+ /* If there's no italic font, then fake it.
+ * For GTK2, we don't need a different font for italic style. */
+ if (hl_mask_todo & HL_ITALIC)
+ draw_flags |= DRAW_ITALIC;
+
+ /* Do we underline the text? */
+ if (hl_mask_todo & HL_UNDERLINE)
+ draw_flags |= DRAW_UNDERL;
+
+#else
+ /* Do we underline the text? */
+ if ((hl_mask_todo & HL_UNDERLINE) || (hl_mask_todo & HL_ITALIC))
+ draw_flags |= DRAW_UNDERL;
+#endif
+ /* Do we undercurl the text? */
+ if (hl_mask_todo & HL_UNDERCURL)
+ draw_flags |= DRAW_UNDERC;
+
+ /* Do we strikethrough the text? */
+ if (hl_mask_todo & HL_STRIKETHROUGH)
+ draw_flags |= DRAW_STRIKE;
+
+ /* Do we draw transparently? */
+ if (flags & GUI_MON_TRS_CURSOR)
+ draw_flags |= DRAW_TRANSP;
+
+ /*
+ * Draw the text.
+ */
+#ifdef FEAT_GUI_GTK
+ /* The value returned is the length in display cells */
+ len = gui_gtk2_draw_string(gui.row, col, s, len, draw_flags);
+#else
+ if (enc_utf8)
+ {
+ int start; /* index of bytes to be drawn */
+ int cells; /* cellwidth of bytes to be drawn */
+ int thislen; /* length of bytes to be drawn */
+ int cn; /* cellwidth of current char */
+ int i; /* index of current char */
+ int c; /* current char value */
+ int cl; /* byte length of current char */
+ int comping; /* current char is composing */
+ int scol = col; /* screen column */
+ int curr_wide = FALSE; /* use 'guifontwide' */
+ int prev_wide = FALSE;
+ int wide_changed;
+# ifdef WIN3264
+ int sep_comp = FALSE; /* Don't separate composing chars. */
+# else
+ int sep_comp = TRUE; /* Separate composing chars. */
+# endif
+
+ /* Break the string at a composing character, it has to be drawn on
+ * top of the previous character. */
+ start = 0;
+ cells = 0;
+ for (i = 0; i < len; i += cl)
+ {
+ c = utf_ptr2char(s + i);
+ cn = utf_char2cells(c);
+ comping = utf_iscomposing(c);
+ if (!comping) /* count cells from non-composing chars */
+ cells += cn;
+ if (!comping || sep_comp)
+ {
+ if (cn > 1
+# ifdef FEAT_XFONTSET
+ && fontset == NOFONTSET
+# endif
+ && wide_font != NOFONT)
+ curr_wide = TRUE;
+ else
+ curr_wide = FALSE;
+ }
+ cl = utf_ptr2len(s + i);
+ if (cl == 0) /* hit end of string */
+ len = i + cl; /* len must be wrong "cannot happen" */
+
+ wide_changed = curr_wide != prev_wide;
+
+ /* Print the string so far if it's the last character or there is
+ * a composing character. */
+ if (i + cl >= len || (comping && sep_comp && i > start)
+ || wide_changed
+# if defined(FEAT_GUI_X11)
+ || (cn > 1
+# ifdef FEAT_XFONTSET
+ /* No fontset: At least draw char after wide char at
+ * right position. */
+ && fontset == NOFONTSET
+# endif
+ )
+# endif
+ )
+ {
+ if ((comping && sep_comp) || wide_changed)
+ thislen = i - start;
+ else
+ thislen = i - start + cl;
+ if (thislen > 0)
+ {
+ if (prev_wide)
+ gui_mch_set_font(wide_font);
+ gui_mch_draw_string(gui.row, scol, s + start, thislen,
+ draw_flags);
+ if (prev_wide)
+ gui_mch_set_font(font);
+ start += thislen;
+ }
+ scol += cells;
+ cells = 0;
+ /* Adjust to not draw a character which width is changed
+ * against with last one. */
+ if (wide_changed && !(comping && sep_comp))
+ {
+ scol -= cn;
+ cl = 0;
+ }
+
+# if defined(FEAT_GUI_X11)
+ /* No fontset: draw a space to fill the gap after a wide char
+ * */
+ if (cn > 1 && (draw_flags & DRAW_TRANSP) == 0
+# ifdef FEAT_XFONTSET
+ && fontset == NOFONTSET
+# endif
+ && !wide_changed)
+ gui_mch_draw_string(gui.row, scol - 1, (char_u *)" ",
+ 1, draw_flags);
+# endif
+ }
+ /* Draw a composing char on top of the previous char. */
+ if (comping && sep_comp)
+ {
+# if defined(__APPLE_CC__) && TARGET_API_MAC_CARBON
+ /* Carbon ATSUI autodraws composing char over previous char */
+ gui_mch_draw_string(gui.row, scol, s + i, cl,
+ draw_flags | DRAW_TRANSP);
+# else
+ gui_mch_draw_string(gui.row, scol - cn, s + i, cl,
+ draw_flags | DRAW_TRANSP);
+# endif
+ start = i + cl;
+ }
+ prev_wide = curr_wide;
+ }
+ /* The stuff below assumes "len" is the length in screen columns. */
+ len = scol - col;
+ }
+ else
+ {
+ gui_mch_draw_string(gui.row, col, s, len, draw_flags);
+ if (enc_dbcs == DBCS_JPNU)
+ {
+ /* Get the length in display cells, this can be different from the
+ * number of bytes for "euc-jp". */
+ len = mb_string2cells(s, len);
+ }
+ }
+#endif /* !FEAT_GUI_GTK */
+
+ if (!(flags & (GUI_MON_IS_CURSOR | GUI_MON_TRS_CURSOR)))
+ gui.col = col + len;
+
+ /* May need to invert it when it's part of the selection. */
+ if (flags & GUI_MON_NOCLEAR)
+ clip_may_redraw_selection(gui.row, col, len);
+
+ if (!(flags & (GUI_MON_IS_CURSOR | GUI_MON_TRS_CURSOR)))
+ {
+ /* Invalidate the old physical cursor position if we wrote over it */
+ if (gui.cursor_row == gui.row
+ && gui.cursor_col >= col
+ && gui.cursor_col < col + len)
+ gui.cursor_is_valid = FALSE;
+ }
+
+#ifdef FEAT_SIGN_ICONS
+ if (draw_sign)
+ /* Draw the sign on top of the spaces. */
+ gui_mch_drawsign(gui.row, col, gui.highlight_mask);
+# if defined(FEAT_NETBEANS_INTG) && (defined(FEAT_GUI_X11) \
+ || defined(FEAT_GUI_GTK) || defined(FEAT_GUI_W32))
+ if (multi_sign)
+ netbeans_draw_multisign_indicator(gui.row);
+# endif
+#endif
+
+ return OK;
+}
+
+/*
+ * Un-draw the cursor. Actually this just redraws the character at the given
+ * position. The character just before it too, for when it was in bold.
+ */
+ void
+gui_undraw_cursor(void)
+{
+ if (gui.cursor_is_valid)
+ {
+#ifdef FEAT_HANGULIN
+ if (composing_hangul
+ && gui.col == gui.cursor_col && gui.row == gui.cursor_row)
+ {
+ char_u *comp_buf;
+ int comp_len;
+
+ comp_buf = hangul_composing_buffer_get(&comp_len);
+ if (comp_buf)
+ {
+ (void)gui_outstr_nowrap(comp_buf, comp_len,
+ GUI_MON_IS_CURSOR | GUI_MON_NOCLEAR,
+ gui.norm_pixel, gui.back_pixel, 0);
+ vim_free(comp_buf);
+ }
+ }
+ else
+ {
+#endif
+ if (gui_redraw_block(gui.cursor_row, gui.cursor_col,
+ gui.cursor_row, gui.cursor_col, GUI_MON_NOCLEAR)
+ && gui.cursor_col > 0)
+ (void)gui_redraw_block(gui.cursor_row, gui.cursor_col - 1,
+ gui.cursor_row, gui.cursor_col - 1, GUI_MON_NOCLEAR);
+#ifdef FEAT_HANGULIN
+ if (composing_hangul)
+ (void)gui_redraw_block(gui.cursor_row, gui.cursor_col + 1,
+ gui.cursor_row, gui.cursor_col + 1, GUI_MON_NOCLEAR);
+ }
+#endif
+ /* Cursor_is_valid is reset when the cursor is undrawn, also reset it
+ * here in case it wasn't needed to undraw it. */
+ gui.cursor_is_valid = FALSE;
+ }
+}
+
+ void
+gui_redraw(
+ int x,
+ int y,
+ int w,
+ int h)
+{
+ int row1, col1, row2, col2;
+
+ row1 = Y_2_ROW(y);
+ col1 = X_2_COL(x);
+ row2 = Y_2_ROW(y + h - 1);
+ col2 = X_2_COL(x + w - 1);
+
+ (void)gui_redraw_block(row1, col1, row2, col2, GUI_MON_NOCLEAR);
+
+ /*
+ * We may need to redraw the cursor, but don't take it upon us to change
+ * its location after a scroll.
+ * (maybe be more strict even and test col too?)
+ * These things may be outside the update/clipping region and reality may
+ * not reflect Vims internal ideas if these operations are clipped away.
+ */
+ if (gui.row == gui.cursor_row)
+ gui_update_cursor(TRUE, TRUE);
+}
+
+/*
+ * Draw a rectangular block of characters, from row1 to row2 (inclusive) and
+ * from col1 to col2 (inclusive).
+ * Return TRUE when the character before the first drawn character has
+ * different attributes (may have to be redrawn too).
+ */
+ int
+gui_redraw_block(
+ int row1,
+ int col1,
+ int row2,
+ int col2,
+ int flags) /* flags for gui_outstr_nowrap() */
+{
+ int old_row, old_col;
+ long_u old_hl_mask;
+ int off;
+ sattr_T first_attr;
+ int idx, len;
+ int back, nback;
+ int retval = FALSE;
+ int orig_col1, orig_col2;
+
+ /* Don't try to update when ScreenLines is not valid */
+ if (!screen_cleared || ScreenLines == NULL)
+ return retval;
+
+ /* Don't try to draw outside the shell! */
+ /* Check everything, strange values may be caused by a big border width */
+ col1 = check_col(col1);
+ col2 = check_col(col2);
+ row1 = check_row(row1);
+ row2 = check_row(row2);
+
+ /* Remember where our cursor was */
+ old_row = gui.row;
+ old_col = gui.col;
+ old_hl_mask = gui.highlight_mask;
+ orig_col1 = col1;
+ orig_col2 = col2;
+
+ for (gui.row = row1; gui.row <= row2; gui.row++)
+ {
+ /* When only half of a double-wide character is in the block, include
+ * the other half. */
+ col1 = orig_col1;
+ col2 = orig_col2;
+ off = LineOffset[gui.row];
+ if (enc_dbcs != 0)
+ {
+ if (col1 > 0)
+ col1 -= dbcs_screen_head_off(ScreenLines + off,
+ ScreenLines + off + col1);
+ col2 += dbcs_screen_tail_off(ScreenLines + off,
+ ScreenLines + off + col2);
+ }
+ else if (enc_utf8)
+ {
+ if (ScreenLines[off + col1] == 0)
+ {
+ if (col1 > 0)
+ --col1;
+ else
+ {
+ // FIXME: how can the first character ever be zero?
+ // Make this IEMSGN when it no longer breaks Travis CI.
+ vim_snprintf((char *)IObuff, IOSIZE,
+ "INTERNAL ERROR: NUL in ScreenLines in row %ld",
+ (long)gui.row);
+ msg((char *)IObuff);
+ }
+ }
+#ifdef FEAT_GUI_GTK
+ if (col2 + 1 < Columns && ScreenLines[off + col2 + 1] == 0)
+ ++col2;
+#endif
+ }
+ gui.col = col1;
+ off = LineOffset[gui.row] + gui.col;
+ len = col2 - col1 + 1;
+
+ /* Find how many chars back this highlighting starts, or where a space
+ * is. Needed for when the bold trick is used */
+ for (back = 0; back < col1; ++back)
+ if (ScreenAttrs[off - 1 - back] != ScreenAttrs[off]
+ || ScreenLines[off - 1 - back] == ' ')
+ break;
+ retval = (col1 > 0 && ScreenAttrs[off - 1] != 0 && back == 0
+ && ScreenLines[off - 1] != ' ');
+
+ /* Break it up in strings of characters with the same attributes. */
+ /* Print UTF-8 characters individually. */
+ while (len > 0)
+ {
+ first_attr = ScreenAttrs[off];
+ gui.highlight_mask = first_attr;
+#if !defined(FEAT_GUI_GTK)
+ if (enc_utf8 && ScreenLinesUC[off] != 0)
+ {
+ /* output multi-byte character separately */
+ nback = gui_screenchar(off, flags,
+ (guicolor_T)0, (guicolor_T)0, back);
+ if (gui.col < Columns && ScreenLines[off + 1] == 0)
+ idx = 2;
+ else
+ idx = 1;
+ }
+ else if (enc_dbcs == DBCS_JPNU && ScreenLines[off] == 0x8e)
+ {
+ /* output double-byte, single-width character separately */
+ nback = gui_screenchar(off, flags,
+ (guicolor_T)0, (guicolor_T)0, back);
+ idx = 1;
+ }
+ else
+#endif
+ {
+#ifdef FEAT_GUI_GTK
+ for (idx = 0; idx < len; ++idx)
+ {
+ if (enc_utf8 && ScreenLines[off + idx] == 0)
+ continue; /* skip second half of double-width char */
+ if (ScreenAttrs[off + idx] != first_attr)
+ break;
+ }
+ /* gui_screenstr() takes care of multibyte chars */
+ nback = gui_screenstr(off, idx, flags,
+ (guicolor_T)0, (guicolor_T)0, back);
+#else
+ for (idx = 0; idx < len && ScreenAttrs[off + idx] == first_attr;
+ idx++)
+ {
+ /* Stop at a multi-byte Unicode character. */
+ if (enc_utf8 && ScreenLinesUC[off + idx] != 0)
+ break;
+ if (enc_dbcs == DBCS_JPNU)
+ {
+ /* Stop at a double-byte single-width char. */
+ if (ScreenLines[off + idx] == 0x8e)
+ break;
+ if (len > 1 && (*mb_ptr2len)(ScreenLines
+ + off + idx) == 2)
+ ++idx; /* skip second byte of double-byte char */
+ }
+ }
+ nback = gui_outstr_nowrap(ScreenLines + off, idx, flags,
+ (guicolor_T)0, (guicolor_T)0, back);
+#endif
+ }
+ if (nback == FAIL)
+ {
+ /* Must back up to start drawing where a bold or italic word
+ * starts. */
+ off -= back;
+ len += back;
+ gui.col -= back;
+ }
+ else
+ {
+ off += idx;
+ len -= idx;
+ }
+ back = 0;
+ }
+ }
+
+ /* Put the cursor back where it was */
+ gui.row = old_row;
+ gui.col = old_col;
+ gui.highlight_mask = (int)old_hl_mask;
+
+ return retval;
+}
+
+ static void
+gui_delete_lines(int row, int count)
+{
+ if (count <= 0)
+ return;
+
+ if (row + count > gui.scroll_region_bot)
+ /* Scrolled out of region, just blank the lines out */
+ gui_clear_block(row, gui.scroll_region_left,
+ gui.scroll_region_bot, gui.scroll_region_right);
+ else
+ {
+ gui_mch_delete_lines(row, count);
+
+ /* If the cursor was in the deleted lines it's now gone. If the
+ * cursor was in the scrolled lines adjust its position. */
+ if (gui.cursor_row >= row
+ && gui.cursor_col >= gui.scroll_region_left
+ && gui.cursor_col <= gui.scroll_region_right)
+ {
+ if (gui.cursor_row < row + count)
+ gui.cursor_is_valid = FALSE;
+ else if (gui.cursor_row <= gui.scroll_region_bot)
+ gui.cursor_row -= count;
+ }
+ }
+}
+
+ static void
+gui_insert_lines(int row, int count)
+{
+ if (count <= 0)
+ return;
+
+ if (row + count > gui.scroll_region_bot)
+ /* Scrolled out of region, just blank the lines out */
+ gui_clear_block(row, gui.scroll_region_left,
+ gui.scroll_region_bot, gui.scroll_region_right);
+ else
+ {
+ gui_mch_insert_lines(row, count);
+
+ 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 - count)
+ gui.cursor_row += count;
+ else if (gui.cursor_row <= gui.scroll_region_bot)
+ gui.cursor_is_valid = FALSE;
+ }
+ }
+}
+
+#ifdef FEAT_TIMERS
+/*
+ * Passed to ui_wait_for_chars_or_timer(), ignoring extra arguments.
+ */
+ static int
+gui_wait_for_chars_3(
+ long wtime,
+ int *interrupted UNUSED,
+ int ignore_input UNUSED)
+{
+ return gui_mch_wait_for_chars(wtime);
+}
+#endif
+
+/*
+ * Returns OK if a character was found to be available within the given time,
+ * or FAIL otherwise.
+ */
+ static int
+gui_wait_for_chars_or_timer(
+ long wtime,
+ int *interrupted UNUSED,
+ int ignore_input UNUSED)
+{
+#ifdef FEAT_TIMERS
+ return ui_wait_for_chars_or_timer(wtime, gui_wait_for_chars_3,
+ interrupted, ignore_input);
+#else
+ return gui_mch_wait_for_chars(wtime);
+#endif
+}
+
+/*
+ * The main GUI input routine. Waits for a character from the keyboard.
+ * "wtime" == -1 Wait forever.
+ * "wtime" == 0 Don't wait.
+ * "wtime" > 0 Wait wtime milliseconds for a character.
+ *
+ * Returns the number of characters read or zero when timed out or interrupted.
+ * "buf" may be NULL, in which case a non-zero number is returned if characters
+ * are available.
+ */
+ static int
+gui_wait_for_chars_buf(
+ char_u *buf,
+ int maxlen,
+ long wtime, // don't use "time", MIPS cannot handle it
+ int tb_change_cnt)
+{
+ int retval;
+
+#ifdef FEAT_MENU
+ // If we're going to wait a bit, update the menus and mouse shape for the
+ // current State.
+ if (wtime != 0)
+ gui_update_menus(0);
+#endif
+
+ gui_mch_update();
+ if (input_available()) // Got char, return immediately
+ {
+ if (buf != NULL && !typebuf_changed(tb_change_cnt))
+ return read_from_input_buf(buf, (long)maxlen);
+ return 0;
+ }
+ if (wtime == 0) // Don't wait for char
+ return FAIL;
+
+ // Before waiting, flush any output to the screen.
+ gui_mch_flush();
+
+ // Blink while waiting for a character.
+ gui_mch_start_blink();
+
+ // Common function to loop until "wtime" is met, while handling timers and
+ // other callbacks.
+ retval = inchar_loop(buf, maxlen, wtime, tb_change_cnt,
+ gui_wait_for_chars_or_timer, NULL);
+
+ gui_mch_stop_blink(TRUE);
+
+ return retval;
+}
+
+/*
+ * Wait for a character from the keyboard without actually reading it.
+ * Also deals with timers.
+ * wtime == -1 Wait forever.
+ * wtime == 0 Don't wait.
+ * 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_wait_for_chars(long wtime, int tb_change_cnt)
+{
+ return gui_wait_for_chars_buf(NULL, 0, wtime, tb_change_cnt);
+}
+
+/*
+ * Equivalent of mch_inchar() for the GUI.
+ */
+ int
+gui_inchar(
+ char_u *buf,
+ int maxlen,
+ long wtime, /* milli seconds */
+ int tb_change_cnt)
+{
+ return gui_wait_for_chars_buf(buf, maxlen, wtime, tb_change_cnt);
+}
+
+/*
+ * Fill p[4] with mouse coordinates encoded for check_termcode().
+ */
+ static void
+fill_mouse_coord(char_u *p, int col, int row)
+{
+ p[0] = (char_u)(col / 128 + ' ' + 1);
+ p[1] = (char_u)(col % 128 + ' ' + 1);
+ p[2] = (char_u)(row / 128 + ' ' + 1);
+ p[3] = (char_u)(row % 128 + ' ' + 1);
+}
+
+/*
+ * Generic mouse support function. Add a mouse event to the input buffer with
+ * the given properties.
+ * button --- may be any of MOUSE_LEFT, MOUSE_MIDDLE, MOUSE_RIGHT,
+ * MOUSE_X1, MOUSE_X2
+ * MOUSE_DRAG, or MOUSE_RELEASE.
+ * MOUSE_4 and MOUSE_5 are used for vertical scroll wheel,
+ * MOUSE_6 and MOUSE_7 for horizontal scroll wheel.
+ * x, y --- Coordinates of mouse in pixels.
+ * repeated_click --- TRUE if this click comes only a short time after a
+ * previous click.
+ * modifiers --- Bit field which may be any of the following modifiers
+ * or'ed together: MOUSE_SHIFT | MOUSE_CTRL | MOUSE_ALT.
+ * This function will ignore drag events where the mouse has not moved to a new
+ * character.
+ */
+ void
+gui_send_mouse_event(
+ int button,
+ int x,
+ int y,
+ int repeated_click,
+ int_u modifiers)
+{
+ static int prev_row = 0, prev_col = 0;
+ static int prev_button = -1;
+ static int num_clicks = 1;
+ char_u string[10];
+ enum key_extra button_char;
+ int row, col;
+#ifdef FEAT_CLIPBOARD
+ int checkfor;
+ int did_clip = FALSE;
+#endif
+
+ /*
+ * Scrolling may happen at any time, also while a selection is present.
+ */
+ switch (button)
+ {
+ case MOUSE_X1:
+ button_char = KE_X1MOUSE;
+ goto button_set;
+ case MOUSE_X2:
+ button_char = KE_X2MOUSE;
+ goto button_set;
+ case MOUSE_4:
+ button_char = KE_MOUSEDOWN;
+ goto button_set;
+ case MOUSE_5:
+ button_char = KE_MOUSEUP;
+ goto button_set;
+ case MOUSE_6:
+ button_char = KE_MOUSELEFT;
+ goto button_set;
+ case MOUSE_7:
+ button_char = KE_MOUSERIGHT;
+button_set:
+ {
+ /* Don't put events in the input queue now. */
+ if (hold_gui_events)
+ return;
+
+ string[3] = CSI;
+ string[4] = KS_EXTRA;
+ string[5] = (int)button_char;
+
+ /* Pass the pointer coordinates of the scroll event so that we
+ * know which window to scroll. */
+ row = gui_xy2colrow(x, y, &col);
+ string[6] = (char_u)(col / 128 + ' ' + 1);
+ string[7] = (char_u)(col % 128 + ' ' + 1);
+ string[8] = (char_u)(row / 128 + ' ' + 1);
+ string[9] = (char_u)(row % 128 + ' ' + 1);
+
+ if (modifiers == 0)
+ add_to_input_buf(string + 3, 7);
+ else
+ {
+ string[0] = CSI;
+ string[1] = KS_MODIFIER;
+ string[2] = 0;
+ if (modifiers & MOUSE_SHIFT)
+ string[2] |= MOD_MASK_SHIFT;
+ if (modifiers & MOUSE_CTRL)
+ string[2] |= MOD_MASK_CTRL;
+ if (modifiers & MOUSE_ALT)
+ string[2] |= MOD_MASK_ALT;
+ add_to_input_buf(string, 10);
+ }
+ return;
+ }
+ }
+
+#ifdef FEAT_CLIPBOARD
+ /* If a clipboard selection is in progress, handle it */
+ if (clip_star.state == SELECT_IN_PROGRESS)
+ {
+ clip_process_selection(button, X_2_COL(x), Y_2_ROW(y), repeated_click);
+ return;
+ }
+
+ /* Determine which mouse settings to look for based on the current mode */
+ switch (get_real_state())
+ {
+ case NORMAL_BUSY:
+ case OP_PENDING:
+# ifdef FEAT_TERMINAL
+ case TERMINAL:
+# endif
+ case NORMAL: checkfor = MOUSE_NORMAL; break;
+ case VISUAL: checkfor = MOUSE_VISUAL; break;
+ case SELECTMODE: checkfor = MOUSE_VISUAL; break;
+ case REPLACE:
+ case REPLACE+LANGMAP:
+ case VREPLACE:
+ case VREPLACE+LANGMAP:
+ case INSERT:
+ case INSERT+LANGMAP: checkfor = MOUSE_INSERT; break;
+ case ASKMORE:
+ case HITRETURN: /* At the more- and hit-enter prompt pass the
+ mouse event for a click on or below the
+ message line. */
+ if (Y_2_ROW(y) >= msg_row)
+ checkfor = MOUSE_NORMAL;
+ else
+ checkfor = MOUSE_RETURN;
+ break;
+
+ /*
+ * On the command line, use the clipboard selection on all lines
+ * but the command line. But not when pasting.
+ */
+ case CMDLINE:
+ case CMDLINE+LANGMAP:
+ if (Y_2_ROW(y) < cmdline_row && button != MOUSE_MIDDLE)
+ checkfor = MOUSE_NONE;
+ else
+ checkfor = MOUSE_COMMAND;
+ break;
+
+ default:
+ checkfor = MOUSE_NONE;
+ break;
+ };
+
+ /*
+ * Allow clipboard selection of text on the command line in "normal"
+ * modes. Don't do this when dragging the status line, or extending a
+ * Visual selection.
+ */
+ if ((State == NORMAL || State == NORMAL_BUSY || (State & INSERT))
+ && Y_2_ROW(y) >= topframe->fr_height + firstwin->w_winrow
+ && button != MOUSE_DRAG
+# ifdef FEAT_MOUSESHAPE
+ && !drag_status_line
+ && !drag_sep_line
+# endif
+ )
+ checkfor = MOUSE_NONE;
+
+ /*
+ * Use modeless selection when holding CTRL and SHIFT pressed.
+ */
+ if ((modifiers & MOUSE_CTRL) && (modifiers & MOUSE_SHIFT))
+ checkfor = MOUSE_NONEF;
+
+ /*
+ * In Ex mode, always use modeless selection.
+ */
+ if (exmode_active)
+ checkfor = MOUSE_NONE;
+
+ /*
+ * If the mouse settings say to not use the mouse, use the modeless
+ * selection. But if Visual is active, assume that only the Visual area
+ * will be selected.
+ * Exception: On the command line, both the selection is used and a mouse
+ * key is send.
+ */
+ if (!mouse_has(checkfor) || checkfor == MOUSE_COMMAND)
+ {
+ /* Don't do modeless selection in Visual mode. */
+ if (checkfor != MOUSE_NONEF && VIsual_active && (State & NORMAL))
+ return;
+
+ /*
+ * When 'mousemodel' is "popup", shift-left is translated to right.
+ * But not when also using Ctrl.
+ */
+ if (mouse_model_popup() && button == MOUSE_LEFT
+ && (modifiers & MOUSE_SHIFT) && !(modifiers & MOUSE_CTRL))
+ {
+ button = MOUSE_RIGHT;
+ modifiers &= ~ MOUSE_SHIFT;
+ }
+
+ /* If the selection is done, allow the right button to extend it.
+ * If the selection is cleared, allow the right button to start it
+ * from the cursor position. */
+ if (button == MOUSE_RIGHT)
+ {
+ if (clip_star.state == SELECT_CLEARED)
+ {
+ if (State & CMDLINE)
+ {
+ col = msg_col;
+ row = msg_row;
+ }
+ else
+ {
+ col = curwin->w_wcol;
+ row = curwin->w_wrow + W_WINROW(curwin);
+ }
+ clip_start_selection(col, row, FALSE);
+ }
+ clip_process_selection(button, X_2_COL(x), Y_2_ROW(y),
+ repeated_click);
+ did_clip = TRUE;
+ }
+ /* Allow the left button to start the selection */
+ else if (button == MOUSE_LEFT)
+ {
+ clip_start_selection(X_2_COL(x), Y_2_ROW(y), repeated_click);
+ did_clip = TRUE;
+ }
+
+ /* Always allow pasting */
+ if (button != MOUSE_MIDDLE)
+ {
+ if (!mouse_has(checkfor) || button == MOUSE_RELEASE)
+ return;
+ if (checkfor != MOUSE_COMMAND)
+ button = MOUSE_LEFT;
+ }
+ repeated_click = FALSE;
+ }
+
+ if (clip_star.state != SELECT_CLEARED && !did_clip)
+ clip_clear_selection(&clip_star);
+#endif
+
+ /* Don't put events in the input queue now. */
+ if (hold_gui_events)
+ return;
+
+ row = gui_xy2colrow(x, y, &col);
+
+ /*
+ * If we are dragging and the mouse hasn't moved far enough to be on a
+ * different character, then don't send an event to vim.
+ */
+ if (button == MOUSE_DRAG)
+ {
+ if (row == prev_row && col == prev_col)
+ return;
+ /* Dragging above the window, set "row" to -1 to cause a scroll. */
+ if (y < 0)
+ row = -1;
+ }
+
+ /*
+ * If topline has changed (window scrolled) since the last click, reset
+ * repeated_click, because we don't want starting Visual mode when
+ * clicking on a different character in the text.
+ */
+ if (curwin->w_topline != gui_prev_topline
+#ifdef FEAT_DIFF
+ || curwin->w_topfill != gui_prev_topfill
+#endif
+ )
+ repeated_click = FALSE;
+
+ string[0] = CSI; /* this sequence is recognized by check_termcode() */
+ string[1] = KS_MOUSE;
+ string[2] = KE_FILLER;
+ if (button != MOUSE_DRAG && button != MOUSE_RELEASE)
+ {
+ if (repeated_click)
+ {
+ /*
+ * Handle multiple clicks. They only count if the mouse is still
+ * pointing at the same character.
+ */
+ if (button != prev_button || row != prev_row || col != prev_col)
+ num_clicks = 1;
+ else if (++num_clicks > 4)
+ num_clicks = 1;
+ }
+ else
+ num_clicks = 1;
+ prev_button = button;
+ gui_prev_topline = curwin->w_topline;
+#ifdef FEAT_DIFF
+ gui_prev_topfill = curwin->w_topfill;
+#endif
+
+ string[3] = (char_u)(button | 0x20);
+ SET_NUM_MOUSE_CLICKS(string[3], num_clicks);
+ }
+ else
+ string[3] = (char_u)button;
+
+ string[3] |= modifiers;
+ fill_mouse_coord(string + 4, col, row);
+ add_to_input_buf(string, 8);
+
+ if (row < 0)
+ prev_row = 0;
+ else
+ prev_row = row;
+ prev_col = col;
+
+ /*
+ * We need to make sure this is cleared since Athena doesn't tell us when
+ * he is done dragging. Neither does GTK+ 2 -- at least for now.
+ */
+#if defined(FEAT_GUI_ATHENA) || defined(FEAT_GUI_GTK)
+ gui.dragged_sb = SBAR_NONE;
+#endif
+}
+
+/*
+ * Convert x and y coordinate to column and row in text window.
+ * Corrects for multi-byte character.
+ * returns column in "*colp" and row as return value;
+ */
+ int
+gui_xy2colrow(int x, int y, int *colp)
+{
+ int col = check_col(X_2_COL(x));
+ int row = check_row(Y_2_ROW(y));
+
+ *colp = mb_fix_col(col, row);
+ return row;
+}
+
+#if defined(FEAT_MENU) || defined(PROTO)
+/*
+ * Callback function for when a menu entry has been selected.
+ */
+ void
+gui_menu_cb(vimmenu_T *menu)
+{
+ char_u bytes[sizeof(long_u)];
+
+ /* Don't put events in the input queue now. */
+ if (hold_gui_events)
+ return;
+
+ bytes[0] = CSI;
+ bytes[1] = KS_MENU;
+ bytes[2] = KE_FILLER;
+ add_to_input_buf(bytes, 3);
+ add_long_to_buf((long_u)menu, bytes);
+ add_to_input_buf_csi(bytes, sizeof(long_u));
+}
+#endif
+
+static int prev_which_scrollbars[3];
+
+/*
+ * Set which components are present.
+ * If "oldval" is not NULL, "oldval" is the previous value, the new value is
+ * in p_go.
+ */
+ void
+gui_init_which_components(char_u *oldval UNUSED)
+{
+#ifdef FEAT_MENU
+ static int prev_menu_is_active = -1;
+#endif
+#ifdef FEAT_TOOLBAR
+ static int prev_toolbar = -1;
+ int using_toolbar = FALSE;
+#endif
+#ifdef FEAT_GUI_TABLINE
+ int using_tabline;
+#endif
+#ifdef FEAT_FOOTER
+ static int prev_footer = -1;
+ int using_footer = FALSE;
+#endif
+#if defined(FEAT_MENU)
+ static int prev_tearoff = -1;
+ int using_tearoff = FALSE;
+#endif
+
+ char_u *p;
+ int i;
+#ifdef FEAT_MENU
+ int grey_old, grey_new;
+ char_u *temp;
+#endif
+ win_T *wp;
+ int need_set_size;
+ int fix_size;
+
+#ifdef FEAT_MENU
+ if (oldval != NULL && gui.in_use)
+ {
+ /*
+ * Check if the menu's go from grey to non-grey or vise versa.
+ */
+ grey_old = (vim_strchr(oldval, GO_GREY) != NULL);
+ grey_new = (vim_strchr(p_go, GO_GREY) != NULL);
+ if (grey_old != grey_new)
+ {
+ temp = p_go;
+ p_go = oldval;
+ gui_update_menus(MENU_ALL_MODES);
+ p_go = temp;
+ }
+ }
+ gui.menu_is_active = FALSE;
+#endif
+
+ for (i = 0; i < 3; i++)
+ gui.which_scrollbars[i] = FALSE;
+ for (p = p_go; *p; p++)
+ switch (*p)
+ {
+ case GO_LEFT:
+ gui.which_scrollbars[SBAR_LEFT] = TRUE;
+ break;
+ case GO_RIGHT:
+ gui.which_scrollbars[SBAR_RIGHT] = TRUE;
+ break;
+ case GO_VLEFT:
+ if (win_hasvertsplit())
+ gui.which_scrollbars[SBAR_LEFT] = TRUE;
+ break;
+ case GO_VRIGHT:
+ if (win_hasvertsplit())
+ gui.which_scrollbars[SBAR_RIGHT] = TRUE;
+ break;
+ case GO_BOT:
+ gui.which_scrollbars[SBAR_BOTTOM] = TRUE;
+ break;
+#ifdef FEAT_MENU
+ case GO_MENUS:
+ gui.menu_is_active = TRUE;
+ break;
+#endif
+ case GO_GREY:
+ /* make menu's have grey items, ignored here */
+ break;
+#ifdef FEAT_TOOLBAR
+ case GO_TOOLBAR:
+ using_toolbar = TRUE;
+ break;
+#endif
+#ifdef FEAT_FOOTER
+ case GO_FOOTER:
+ using_footer = TRUE;
+ break;
+#endif
+ case GO_TEAROFF:
+#if defined(FEAT_MENU)
+ using_tearoff = TRUE;
+#endif
+ break;
+ default:
+ /* Ignore options that are not supported */
+ break;
+ }
+
+ if (gui.in_use)
+ {
+ need_set_size = 0;
+ fix_size = FALSE;
+
+#ifdef FEAT_GUI_TABLINE
+ /* Update the GUI tab line, it may appear or disappear. This may
+ * cause the non-GUI tab line to disappear or appear. */
+ using_tabline = gui_has_tabline();
+ if (!gui_mch_showing_tabline() != !using_tabline)
+ {
+ /* We don't want a resize event change "Rows" here, save and
+ * restore it. Resizing is handled below. */
+ i = Rows;
+ gui_update_tabline();
+ Rows = i;
+ need_set_size |= RESIZE_VERT;
+ if (using_tabline)
+ fix_size = TRUE;
+ if (!gui_use_tabline())
+ redraw_tabline = TRUE; /* may draw non-GUI tab line */
+ }
+#endif
+
+ for (i = 0; i < 3; i++)
+ {
+ /* The scrollbar needs to be updated when it is shown/unshown and
+ * when switching tab pages. But the size only changes when it's
+ * shown/unshown. Thus we need two places to remember whether a
+ * scrollbar is there or not. */
+ if (gui.which_scrollbars[i] != prev_which_scrollbars[i]
+ || gui.which_scrollbars[i]
+ != curtab->tp_prev_which_scrollbars[i])
+ {
+ if (i == SBAR_BOTTOM)
+ gui_mch_enable_scrollbar(&gui.bottom_sbar,
+ gui.which_scrollbars[i]);
+ else
+ {
+ FOR_ALL_WINDOWS(wp)
+ {
+ gui_do_scrollbar(wp, i, gui.which_scrollbars[i]);
+ }
+ }
+ if (gui.which_scrollbars[i] != prev_which_scrollbars[i])
+ {
+ if (i == SBAR_BOTTOM)
+ need_set_size |= RESIZE_VERT;
+ else
+ need_set_size |= RESIZE_HOR;
+ if (gui.which_scrollbars[i])
+ fix_size = TRUE;
+ }
+ }
+ curtab->tp_prev_which_scrollbars[i] = gui.which_scrollbars[i];
+ prev_which_scrollbars[i] = gui.which_scrollbars[i];
+ }
+
+#ifdef FEAT_MENU
+ if (gui.menu_is_active != prev_menu_is_active)
+ {
+ /* We don't want a resize event change "Rows" here, save and
+ * restore it. Resizing is handled below. */
+ i = Rows;
+ gui_mch_enable_menu(gui.menu_is_active);
+ Rows = i;
+ prev_menu_is_active = gui.menu_is_active;
+ need_set_size |= RESIZE_VERT;
+ if (gui.menu_is_active)
+ fix_size = TRUE;
+ }
+#endif
+
+#ifdef FEAT_TOOLBAR
+ if (using_toolbar != prev_toolbar)
+ {
+ gui_mch_show_toolbar(using_toolbar);
+ prev_toolbar = using_toolbar;
+ need_set_size |= RESIZE_VERT;
+ if (using_toolbar)
+ fix_size = TRUE;
+ }
+#endif
+#ifdef FEAT_FOOTER
+ if (using_footer != prev_footer)
+ {
+ gui_mch_enable_footer(using_footer);
+ prev_footer = using_footer;
+ need_set_size |= RESIZE_VERT;
+ if (using_footer)
+ fix_size = TRUE;
+ }
+#endif
+#if defined(FEAT_MENU) && !(defined(WIN3264) && !defined(FEAT_TEAROFF))
+ if (using_tearoff != prev_tearoff)
+ {
+ gui_mch_toggle_tearoffs(using_tearoff);
+ prev_tearoff = using_tearoff;
+ }
+#endif
+ if (need_set_size != 0)
+ {
+#ifdef FEAT_GUI_GTK
+ long prev_Columns = Columns;
+ long prev_Rows = Rows;
+#endif
+ /* Adjust the size of the window to make the text area keep the
+ * same size and to avoid that part of our window is off-screen
+ * and a scrollbar can't be used, for example. */
+ gui_set_shellsize(FALSE, fix_size, need_set_size);
+
+#ifdef FEAT_GUI_GTK
+ /* GTK has the annoying habit of sending us resize events when
+ * changing the window size ourselves. This mostly happens when
+ * waiting for a character to arrive, quite unpredictably, and may
+ * change Columns and Rows when we don't want it. Wait for a
+ * character here to avoid this effect.
+ * If you remove this, please test this command for resizing
+ * effects (with optional left scrollbar): ":vsp|q|vsp|q|vsp|q".
+ * Don't do this while starting up though.
+ * Don't change Rows when adding menu/toolbar/tabline.
+ * Don't change Columns when adding vertical toolbar. */
+ if (!gui.starting && need_set_size != (RESIZE_VERT | RESIZE_HOR))
+ (void)char_avail();
+ if ((need_set_size & RESIZE_VERT) == 0)
+ Rows = prev_Rows;
+ if ((need_set_size & RESIZE_HOR) == 0)
+ Columns = prev_Columns;
+#endif
+ }
+ /* When the console tabline appears or disappears the window positions
+ * change. */
+ if (firstwin->w_winrow != tabline_height())
+ shell_new_rows(); /* recompute window positions and heights */
+ }
+}
+
+#if defined(FEAT_GUI_TABLINE) || defined(PROTO)
+/*
+ * Return TRUE if the GUI is taking care of the tabline.
+ * It may still be hidden if 'showtabline' is zero.
+ */
+ int
+gui_use_tabline(void)
+{
+ return gui.in_use && vim_strchr(p_go, GO_TABLINE) != NULL;
+}
+
+/*
+ * Return TRUE if the GUI is showing the tabline.
+ * This uses 'showtabline'.
+ */
+ static int
+gui_has_tabline(void)
+{
+ if (!gui_use_tabline()
+ || p_stal == 0
+ || (p_stal == 1 && first_tabpage->tp_next == NULL))
+ return FALSE;
+ return TRUE;
+}
+
+/*
+ * Update the tabline.
+ * This may display/undisplay the tabline and update the labels.
+ */
+ void
+gui_update_tabline(void)
+{
+ int showit = gui_has_tabline();
+ int shown = gui_mch_showing_tabline();
+
+ if (!gui.starting && starting == 0)
+ {
+ /* Updating the tabline uses direct GUI commands, flush
+ * outstanding instructions first. (esp. clear screen) */
+ out_flush();
+
+ if (!showit != !shown)
+ gui_mch_show_tabline(showit);
+ if (showit != 0)
+ gui_mch_update_tabline();
+
+ /* When the tabs change from hidden to shown or from shown to
+ * hidden the size of the text area should remain the same. */
+ if (!showit != !shown)
+ gui_set_shellsize(FALSE, showit, RESIZE_VERT);
+ }
+}
+
+/*
+ * Get the label or tooltip for tab page "tp" into NameBuff[].
+ */
+ void
+get_tabline_label(
+ tabpage_T *tp,
+ int tooltip) /* TRUE: get tooltip */
+{
+ int modified = FALSE;
+ char_u buf[40];
+ int wincount;
+ win_T *wp;
+ char_u **opt;
+
+ /* Use 'guitablabel' or 'guitabtooltip' if it's set. */
+ opt = (tooltip ? &p_gtt : &p_gtl);
+ if (**opt != NUL)
+ {
+ int use_sandbox = FALSE;
+ int save_called_emsg = called_emsg;
+ char_u res[MAXPATHL];
+ tabpage_T *save_curtab;
+ char_u *opt_name = (char_u *)(tooltip ? "guitabtooltip"
+ : "guitablabel");
+
+ called_emsg = FALSE;
+
+ printer_page_num = tabpage_index(tp);
+# ifdef FEAT_EVAL
+ set_vim_var_nr(VV_LNUM, printer_page_num);
+ use_sandbox = was_set_insecurely(opt_name, 0);
+# endif
+ /* It's almost as going to the tabpage, but without autocommands. */
+ curtab->tp_firstwin = firstwin;
+ curtab->tp_lastwin = lastwin;
+ curtab->tp_curwin = curwin;
+ save_curtab = curtab;
+ curtab = tp;
+ topframe = curtab->tp_topframe;
+ firstwin = curtab->tp_firstwin;
+ lastwin = curtab->tp_lastwin;
+ curwin = curtab->tp_curwin;
+ curbuf = curwin->w_buffer;
+
+ /* Can't use NameBuff directly, build_stl_str_hl() uses it. */
+ build_stl_str_hl(curwin, res, MAXPATHL, *opt, use_sandbox,
+ 0, (int)Columns, NULL, NULL);
+ STRCPY(NameBuff, res);
+
+ /* Back to the original curtab. */
+ curtab = save_curtab;
+ topframe = curtab->tp_topframe;
+ firstwin = curtab->tp_firstwin;
+ lastwin = curtab->tp_lastwin;
+ curwin = curtab->tp_curwin;
+ curbuf = curwin->w_buffer;
+
+ if (called_emsg)
+ set_string_option_direct(opt_name, -1,
+ (char_u *)"", OPT_FREE, SID_ERROR);
+ called_emsg |= save_called_emsg;
+ }
+
+ /* If 'guitablabel'/'guitabtooltip' is not set or the result is empty then
+ * use a default label. */
+ if (**opt == NUL || *NameBuff == NUL)
+ {
+ /* Get the buffer name into NameBuff[] and shorten it. */
+ get_trans_bufname(tp == curtab ? curbuf : tp->tp_curwin->w_buffer);
+ if (!tooltip)
+ shorten_dir(NameBuff);
+
+ wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
+ for (wincount = 0; wp != NULL; wp = wp->w_next, ++wincount)
+ if (bufIsChanged(wp->w_buffer))
+ modified = TRUE;
+ if (modified || wincount > 1)
+ {
+ if (wincount > 1)
+ vim_snprintf((char *)buf, sizeof(buf), "%d", wincount);
+ else
+ buf[0] = NUL;
+ if (modified)
+ STRCAT(buf, "+");
+ STRCAT(buf, " ");
+ STRMOVE(NameBuff + STRLEN(buf), NameBuff);
+ mch_memmove(NameBuff, buf, STRLEN(buf));
+ }
+ }
+}
+
+/*
+ * Send the event for clicking to select tab page "nr".
+ * Returns TRUE if it was done, FALSE when skipped because we are already at
+ * that tab page or the cmdline window is open.
+ */
+ int
+send_tabline_event(int nr)
+{
+ char_u string[3];
+
+ if (nr == tabpage_index(curtab))
+ return FALSE;
+
+ /* Don't put events in the input queue now. */
+ if (hold_gui_events
+# ifdef FEAT_CMDWIN
+ || cmdwin_type != 0
+# endif
+ )
+ {
+ /* Set it back to the current tab page. */
+ gui_mch_set_curtab(tabpage_index(curtab));
+ return FALSE;
+ }
+
+ string[0] = CSI;
+ string[1] = KS_TABLINE;
+ string[2] = KE_FILLER;
+ add_to_input_buf(string, 3);
+ string[0] = nr;
+ add_to_input_buf_csi(string, 1);
+ return TRUE;
+}
+
+/*
+ * Send a tabline menu event
+ */
+ void
+send_tabline_menu_event(int tabidx, int event)
+{
+ char_u string[3];
+
+ // Don't put events in the input queue now.
+ if (hold_gui_events)
+ return;
+
+ // Cannot close the last tabpage.
+ if (event == TABLINE_MENU_CLOSE && first_tabpage->tp_next == NULL)
+ return;
+
+ string[0] = CSI;
+ string[1] = KS_TABMENU;
+ string[2] = KE_FILLER;
+ add_to_input_buf(string, 3);
+ string[0] = tabidx;
+ string[1] = (char_u)(long)event;
+ add_to_input_buf_csi(string, 2);
+}
+
+#endif
+
+/*
+ * Scrollbar stuff:
+ */
+
+/*
+ * Remove all scrollbars. Used before switching to another tab page.
+ */
+ void
+gui_remove_scrollbars(void)
+{
+ int i;
+ win_T *wp;
+
+ for (i = 0; i < 3; i++)
+ {
+ if (i == SBAR_BOTTOM)
+ gui_mch_enable_scrollbar(&gui.bottom_sbar, FALSE);
+ else
+ {
+ FOR_ALL_WINDOWS(wp)
+ {
+ gui_do_scrollbar(wp, i, FALSE);
+ }
+ }
+ curtab->tp_prev_which_scrollbars[i] = -1;
+ }
+}
+
+ void
+gui_create_scrollbar(scrollbar_T *sb, int type, win_T *wp)
+{
+ static int sbar_ident = 0;
+
+ sb->ident = sbar_ident++; /* No check for too big, but would it happen? */
+ sb->wp = wp;
+ sb->type = type;
+ sb->value = 0;
+#ifdef FEAT_GUI_ATHENA
+ sb->pixval = 0;
+#endif
+ sb->size = 1;
+ sb->max = 1;
+ sb->top = 0;
+ sb->height = 0;
+ sb->width = 0;
+ sb->status_height = 0;
+ gui_mch_create_scrollbar(sb, (wp == NULL) ? SBAR_HORIZ : SBAR_VERT);
+}
+
+/*
+ * Find the scrollbar with the given index.
+ */
+ scrollbar_T *
+gui_find_scrollbar(long ident)
+{
+ win_T *wp;
+
+ if (gui.bottom_sbar.ident == ident)
+ return &gui.bottom_sbar;
+ FOR_ALL_WINDOWS(wp)
+ {
+ if (wp->w_scrollbars[SBAR_LEFT].ident == ident)
+ return &wp->w_scrollbars[SBAR_LEFT];
+ if (wp->w_scrollbars[SBAR_RIGHT].ident == ident)
+ return &wp->w_scrollbars[SBAR_RIGHT];
+ }
+ return NULL;
+}
+
+/*
+ * For most systems: Put a code in the input buffer for a dragged scrollbar.
+ *
+ * For Win32, Macintosh and GTK+ 2:
+ * Scrollbars seem to grab focus and vim doesn't read the input queue until
+ * you stop dragging the scrollbar. We get here each time the scrollbar is
+ * dragged another pixel, but as far as the rest of vim goes, it thinks
+ * we're just hanging in the call to DispatchMessage() in
+ * process_message(). The DispatchMessage() call that hangs was passed a
+ * mouse button click event in the scrollbar window. -- webb.
+ *
+ * Solution: Do the scrolling right here. But only when allowed.
+ * Ignore the scrollbars while executing an external command or when there
+ * are still characters to be processed.
+ */
+ void
+gui_drag_scrollbar(scrollbar_T *sb, long value, int still_dragging)
+{
+ win_T *wp;
+ int sb_num;
+#ifdef USE_ON_FLY_SCROLL
+ colnr_T old_leftcol = curwin->w_leftcol;
+ linenr_T old_topline = curwin->w_topline;
+# ifdef FEAT_DIFF
+ int old_topfill = curwin->w_topfill;
+# endif
+#else
+ char_u bytes[sizeof(long_u)];
+ int byte_count;
+#endif
+
+ if (sb == NULL)
+ return;
+
+ /* Don't put events in the input queue now. */
+ if (hold_gui_events)
+ return;
+
+#ifdef FEAT_CMDWIN
+ if (cmdwin_type != 0 && sb->wp != curwin)
+ return;
+#endif
+
+ if (still_dragging)
+ {
+ if (sb->wp == NULL)
+ gui.dragged_sb = SBAR_BOTTOM;
+ else if (sb == &sb->wp->w_scrollbars[SBAR_LEFT])
+ gui.dragged_sb = SBAR_LEFT;
+ else
+ gui.dragged_sb = SBAR_RIGHT;
+ gui.dragged_wp = sb->wp;
+ }
+ else
+ {
+ gui.dragged_sb = SBAR_NONE;
+#ifdef FEAT_GUI_GTK
+ /* Keep the "dragged_wp" value until after the scrolling, for when the
+ * mouse button is released. GTK2 doesn't send the button-up event. */
+ gui.dragged_wp = NULL;
+#endif
+ }
+
+ /* Vertical sbar info is kept in the first sbar (the left one) */
+ if (sb->wp != NULL)
+ sb = &sb->wp->w_scrollbars[0];
+
+ /*
+ * Check validity of value
+ */
+ if (value < 0)
+ value = 0;
+#ifdef SCROLL_PAST_END
+ else if (value > sb->max)
+ value = sb->max;
+#else
+ if (value > sb->max - sb->size + 1)
+ value = sb->max - sb->size + 1;
+#endif
+
+ sb->value = value;
+
+#ifdef USE_ON_FLY_SCROLL
+ /* When not allowed to do the scrolling right now, return.
+ * This also checked input_available(), but that causes the first click in
+ * a scrollbar to be ignored when Vim doesn't have focus. */
+ if (dont_scroll)
+ return;
+#endif
+#ifdef FEAT_INS_EXPAND
+ /* Disallow scrolling the current window when the completion popup menu is
+ * visible. */
+ if ((sb->wp == NULL || sb->wp == curwin) && pum_visible())
+ return;
+#endif
+
+#ifdef FEAT_RIGHTLEFT
+ if (sb->wp == NULL && curwin->w_p_rl)
+ {
+ value = sb->max + 1 - sb->size - value;
+ if (value < 0)
+ value = 0;
+ }
+#endif
+
+ if (sb->wp != NULL) /* vertical scrollbar */
+ {
+ sb_num = 0;
+ for (wp = firstwin; wp != sb->wp && wp != NULL; wp = wp->w_next)
+ sb_num++;
+ if (wp == NULL)
+ return;
+
+#ifdef USE_ON_FLY_SCROLL
+ current_scrollbar = sb_num;
+ scrollbar_value = value;
+ if (State & NORMAL)
+ {
+ gui_do_scroll();
+ setcursor();
+ }
+ else if (State & INSERT)
+ {
+ ins_scroll();
+ setcursor();
+ }
+ else if (State & CMDLINE)
+ {
+ if (msg_scrolled == 0)
+ {
+ gui_do_scroll();
+ redrawcmdline();
+ }
+ }
+# ifdef FEAT_FOLDING
+ /* Value may have been changed for closed fold. */
+ sb->value = sb->wp->w_topline - 1;
+# endif
+
+ /* When dragging one scrollbar and there is another one at the other
+ * side move the thumb of that one too. */
+ if (gui.which_scrollbars[SBAR_RIGHT] && gui.which_scrollbars[SBAR_LEFT])
+ gui_mch_set_scrollbar_thumb(
+ &sb->wp->w_scrollbars[
+ sb == &sb->wp->w_scrollbars[SBAR_RIGHT]
+ ? SBAR_LEFT : SBAR_RIGHT],
+ sb->value, sb->size, sb->max);
+
+#else
+ bytes[0] = CSI;
+ bytes[1] = KS_VER_SCROLLBAR;
+ bytes[2] = KE_FILLER;
+ bytes[3] = (char_u)sb_num;
+ byte_count = 4;
+#endif
+ }
+ else
+ {
+#ifdef USE_ON_FLY_SCROLL
+ scrollbar_value = value;
+
+ if (State & NORMAL)
+ gui_do_horiz_scroll(scrollbar_value, FALSE);
+ else if (State & INSERT)
+ ins_horscroll();
+ else if (State & CMDLINE)
+ {
+ if (msg_scrolled == 0)
+ {
+ gui_do_horiz_scroll(scrollbar_value, FALSE);
+ redrawcmdline();
+ }
+ }
+ if (old_leftcol != curwin->w_leftcol)
+ {
+ updateWindow(curwin); /* update window, status and cmdline */
+ setcursor();
+ }
+#else
+ bytes[0] = CSI;
+ bytes[1] = KS_HOR_SCROLLBAR;
+ bytes[2] = KE_FILLER;
+ byte_count = 3;
+#endif
+ }
+
+#ifdef USE_ON_FLY_SCROLL
+ /*
+ * synchronize other windows, as necessary according to 'scrollbind'
+ */
+ if (curwin->w_p_scb
+ && ((sb->wp == NULL && curwin->w_leftcol != old_leftcol)
+ || (sb->wp == curwin && (curwin->w_topline != old_topline
+# ifdef FEAT_DIFF
+ || curwin->w_topfill != old_topfill
+# endif
+ ))))
+ {
+ do_check_scrollbind(TRUE);
+ /* need to update the window right here */
+ FOR_ALL_WINDOWS(wp)
+ if (wp->w_redr_type > 0)
+ updateWindow(wp);
+ setcursor();
+ }
+ out_flush_cursor(FALSE, TRUE);
+#else
+ add_to_input_buf(bytes, byte_count);
+ add_long_to_buf((long_u)value, bytes);
+ add_to_input_buf_csi(bytes, sizeof(long_u));
+#endif
+}
+
+/*
+ * Scrollbar stuff:
+ */
+
+/*
+ * Called when something in the window layout has changed.
+ */
+ void
+gui_may_update_scrollbars(void)
+{
+ if (gui.in_use && starting == 0)
+ {
+ out_flush();
+ gui_init_which_components(NULL);
+ gui_update_scrollbars(TRUE);
+ }
+ need_mouse_correct = TRUE;
+}
+
+ void
+gui_update_scrollbars(
+ int force) /* Force all scrollbars to get updated */
+{
+ win_T *wp;
+ scrollbar_T *sb;
+ long val, size, max; /* need 32 bits here */
+ int which_sb;
+ int h, y;
+ static win_T *prev_curwin = NULL;
+
+ /* Update the horizontal scrollbar */
+ gui_update_horiz_scrollbar(force);
+
+#ifndef WIN3264
+ /* Return straight away if there is neither a left nor right scrollbar.
+ * On MS-Windows this is required anyway for scrollwheel messages. */
+ if (!gui.which_scrollbars[SBAR_LEFT] && !gui.which_scrollbars[SBAR_RIGHT])
+ return;
+#endif
+
+ /*
+ * Don't want to update a scrollbar while we're dragging it. But if we
+ * have both a left and right scrollbar, and we drag one of them, we still
+ * need to update the other one.
+ */
+ if (!force && (gui.dragged_sb == SBAR_LEFT || gui.dragged_sb == SBAR_RIGHT)
+ && gui.which_scrollbars[SBAR_LEFT]
+ && gui.which_scrollbars[SBAR_RIGHT])
+ {
+ /*
+ * If we have two scrollbars and one of them is being dragged, just
+ * copy the scrollbar position from the dragged one to the other one.
+ */
+ which_sb = SBAR_LEFT + SBAR_RIGHT - gui.dragged_sb;
+ if (gui.dragged_wp != NULL)
+ gui_mch_set_scrollbar_thumb(
+ &gui.dragged_wp->w_scrollbars[which_sb],
+ gui.dragged_wp->w_scrollbars[0].value,
+ gui.dragged_wp->w_scrollbars[0].size,
+ gui.dragged_wp->w_scrollbars[0].max);
+ }
+
+ /* avoid that moving components around generates events */
+ ++hold_gui_events;
+
+ for (wp = firstwin; wp != NULL; wp = W_NEXT(wp))
+ {
+ if (wp->w_buffer == NULL) /* just in case */
+ continue;
+ /* Skip a scrollbar that is being dragged. */
+ if (!force && (gui.dragged_sb == SBAR_LEFT
+ || gui.dragged_sb == SBAR_RIGHT)
+ && gui.dragged_wp == wp)
+ continue;
+
+#ifdef SCROLL_PAST_END
+ max = wp->w_buffer->b_ml.ml_line_count - 1;
+#else
+ max = wp->w_buffer->b_ml.ml_line_count + wp->w_height - 2;
+#endif
+ if (max < 0) /* empty buffer */
+ max = 0;
+ val = wp->w_topline - 1;
+ size = wp->w_height;
+#ifdef SCROLL_PAST_END
+ if (val > max) /* just in case */
+ val = max;
+#else
+ if (size > max + 1) /* just in case */
+ size = max + 1;
+ if (val > max - size + 1)
+ val = max - size + 1;
+#endif
+ if (val < 0) /* minimal value is 0 */
+ val = 0;
+
+ /*
+ * Scrollbar at index 0 (the left one) contains all the information.
+ * It would be the same info for left and right so we just store it for
+ * one of them.
+ */
+ sb = &wp->w_scrollbars[0];
+
+ /*
+ * Note: no check for valid w_botline. If it's not valid the
+ * scrollbars will be updated later anyway.
+ */
+ if (size < 1 || wp->w_botline - 2 > max)
+ {
+ /*
+ * This can happen during changing files. Just don't update the
+ * scrollbar for now.
+ */
+ sb->height = 0; /* Force update next time */
+ if (gui.which_scrollbars[SBAR_LEFT])
+ gui_do_scrollbar(wp, SBAR_LEFT, FALSE);
+ if (gui.which_scrollbars[SBAR_RIGHT])
+ gui_do_scrollbar(wp, SBAR_RIGHT, FALSE);
+ continue;
+ }
+ if (force || sb->height != wp->w_height
+ || sb->top != wp->w_winrow
+ || sb->status_height != wp->w_status_height
+ || sb->width != wp->w_width
+ || prev_curwin != curwin)
+ {
+ /* Height, width or position of scrollbar has changed. For
+ * vertical split: curwin changed. */
+ sb->height = wp->w_height;
+ sb->top = wp->w_winrow;
+ sb->status_height = wp->w_status_height;
+ sb->width = wp->w_width;
+
+ /* Calculate height and position in pixels */
+ h = (sb->height + sb->status_height) * gui.char_height;
+ y = sb->top * gui.char_height + gui.border_offset;
+#if defined(FEAT_MENU) && !defined(FEAT_GUI_GTK) && !defined(FEAT_GUI_MOTIF) && !defined(FEAT_GUI_PHOTON)
+ if (gui.menu_is_active)
+ y += gui.menu_height;
+#endif
+
+#if defined(FEAT_TOOLBAR) && (defined(FEAT_GUI_MSWIN) || defined(FEAT_GUI_ATHENA))
+ if (vim_strchr(p_go, GO_TOOLBAR) != NULL)
+# ifdef FEAT_GUI_ATHENA
+ y += gui.toolbar_height;
+# else
+# ifdef FEAT_GUI_MSWIN
+ y += TOOLBAR_BUTTON_HEIGHT + TOOLBAR_BORDER_HEIGHT;
+# endif
+# endif
+#endif
+
+#if defined(FEAT_GUI_TABLINE) && defined(FEAT_GUI_MSWIN)
+ if (gui_has_tabline())
+ y += gui.tabline_height;
+#endif
+
+ if (wp->w_winrow == 0)
+ {
+ /* Height of top scrollbar includes width of top border */
+ h += gui.border_offset;
+ y -= gui.border_offset;
+ }
+ if (gui.which_scrollbars[SBAR_LEFT])
+ {
+ gui_mch_set_scrollbar_pos(&wp->w_scrollbars[SBAR_LEFT],
+ gui.left_sbar_x, y,
+ gui.scrollbar_width, h);
+ gui_do_scrollbar(wp, SBAR_LEFT, TRUE);
+ }
+ if (gui.which_scrollbars[SBAR_RIGHT])
+ {
+ gui_mch_set_scrollbar_pos(&wp->w_scrollbars[SBAR_RIGHT],
+ gui.right_sbar_x, y,
+ gui.scrollbar_width, h);
+ gui_do_scrollbar(wp, SBAR_RIGHT, TRUE);
+ }
+ }
+
+ /* Reduce the number of calls to gui_mch_set_scrollbar_thumb() by
+ * checking if the thumb moved at least a pixel. Only do this for
+ * Athena, most other GUIs require the update anyway to make the
+ * arrows work. */
+#ifdef FEAT_GUI_ATHENA
+ if (max == 0)
+ y = 0;
+ else
+ y = (val * (sb->height + 2) * gui.char_height + max / 2) / max;
+ if (force || sb->pixval != y || sb->size != size || sb->max != max)
+#else
+ if (force || sb->value != val || sb->size != size || sb->max != max)
+#endif
+ {
+ /* Thumb of scrollbar has moved */
+ sb->value = val;
+#ifdef FEAT_GUI_ATHENA
+ sb->pixval = y;
+#endif
+ sb->size = size;
+ sb->max = max;
+ if (gui.which_scrollbars[SBAR_LEFT]
+ && (gui.dragged_sb != SBAR_LEFT || gui.dragged_wp != wp))
+ gui_mch_set_scrollbar_thumb(&wp->w_scrollbars[SBAR_LEFT],
+ val, size, max);
+ if (gui.which_scrollbars[SBAR_RIGHT]
+ && (gui.dragged_sb != SBAR_RIGHT || gui.dragged_wp != wp))
+ gui_mch_set_scrollbar_thumb(&wp->w_scrollbars[SBAR_RIGHT],
+ val, size, max);
+ }
+ }
+ prev_curwin = curwin;
+ --hold_gui_events;
+}
+
+/*
+ * Enable or disable a scrollbar.
+ * Check for scrollbars for vertically split windows which are not enabled
+ * sometimes.
+ */
+ static void
+gui_do_scrollbar(
+ win_T *wp,
+ int which, /* SBAR_LEFT or SBAR_RIGHT */
+ int enable) /* TRUE to enable scrollbar */
+{
+ int midcol = curwin->w_wincol + curwin->w_width / 2;
+ int has_midcol = (wp->w_wincol <= midcol
+ && wp->w_wincol + wp->w_width >= midcol);
+
+ /* Only enable scrollbars that contain the middle column of the current
+ * window. */
+ if (gui.which_scrollbars[SBAR_RIGHT] != gui.which_scrollbars[SBAR_LEFT])
+ {
+ /* Scrollbars only on one side. Don't enable scrollbars that don't
+ * contain the middle column of the current window. */
+ if (!has_midcol)
+ enable = FALSE;
+ }
+ else
+ {
+ /* Scrollbars on both sides. Don't enable scrollbars that neither
+ * contain the middle column of the current window nor are on the far
+ * side. */
+ if (midcol > Columns / 2)
+ {
+ if (which == SBAR_LEFT ? wp->w_wincol != 0 : !has_midcol)
+ enable = FALSE;
+ }
+ else
+ {
+ if (which == SBAR_RIGHT ? wp->w_wincol + wp->w_width != Columns
+ : !has_midcol)
+ enable = FALSE;
+ }
+ }
+ gui_mch_enable_scrollbar(&wp->w_scrollbars[which], enable);
+}
+
+/*
+ * Scroll a window according to the values set in the globals current_scrollbar
+ * and scrollbar_value. Return TRUE if the cursor in the current window moved
+ * or FALSE otherwise.
+ */
+ int
+gui_do_scroll(void)
+{
+ win_T *wp, *save_wp;
+ int i;
+ long nlines;
+ pos_T old_cursor;
+ linenr_T old_topline;
+#ifdef FEAT_DIFF
+ int old_topfill;
+#endif
+
+ for (wp = firstwin, i = 0; i < current_scrollbar; wp = W_NEXT(wp), i++)
+ if (wp == NULL)
+ break;
+ if (wp == NULL)
+ /* Couldn't find window */
+ return FALSE;
+
+ /*
+ * Compute number of lines to scroll. If zero, nothing to do.
+ */
+ nlines = (long)scrollbar_value + 1 - (long)wp->w_topline;
+ if (nlines == 0)
+ return FALSE;
+
+ save_wp = curwin;
+ old_topline = wp->w_topline;
+#ifdef FEAT_DIFF
+ old_topfill = wp->w_topfill;
+#endif
+ old_cursor = wp->w_cursor;
+ curwin = wp;
+ curbuf = wp->w_buffer;
+ if (nlines < 0)
+ scrolldown(-nlines, gui.dragged_wp == NULL);
+ else
+ scrollup(nlines, gui.dragged_wp == NULL);
+ /* Reset dragged_wp after using it. "dragged_sb" will have been reset for
+ * the mouse-up event already, but we still want it to behave like when
+ * dragging. But not the next click in an arrow. */
+ if (gui.dragged_sb == SBAR_NONE)
+ gui.dragged_wp = NULL;
+
+ if (old_topline != wp->w_topline
+#ifdef FEAT_DIFF
+ || old_topfill != wp->w_topfill
+#endif
+ )
+ {
+ if (get_scrolloff_value() != 0)
+ {
+ cursor_correct(); /* fix window for 'so' */
+ update_topline(); /* avoid up/down jump */
+ }
+ if (old_cursor.lnum != wp->w_cursor.lnum)
+ coladvance(wp->w_curswant);
+ wp->w_scbind_pos = wp->w_topline;
+ }
+
+ /* Make sure wp->w_leftcol and wp->w_skipcol are correct. */
+ validate_cursor();
+
+ curwin = save_wp;
+ curbuf = save_wp->w_buffer;
+
+ /*
+ * Don't call updateWindow() when nothing has changed (it will overwrite
+ * the status line!).
+ */
+ if (old_topline != wp->w_topline
+ || wp->w_redr_type != 0
+#ifdef FEAT_DIFF
+ || old_topfill != wp->w_topfill
+#endif
+ )
+ {
+ int type = VALID;
+
+#ifdef FEAT_INS_EXPAND
+ if (pum_visible())
+ {
+ type = NOT_VALID;
+ wp->w_lines_valid = 0;
+ }
+#endif
+ /* Don't set must_redraw here, it may cause the popup menu to
+ * disappear when losing focus after a scrollbar drag. */
+ if (wp->w_redr_type < type)
+ wp->w_redr_type = type;
+ mch_disable_flush();
+ updateWindow(wp); /* update window, status line, and cmdline */
+ mch_enable_flush();
+ }
+
+#ifdef FEAT_INS_EXPAND
+ /* May need to redraw the popup menu. */
+ if (pum_visible())
+ pum_redraw();
+#endif
+
+ return (wp == curwin && !EQUAL_POS(curwin->w_cursor, old_cursor));
+}
+
+
+/*
+ * Horizontal scrollbar stuff:
+ */
+
+/*
+ * Return length of line "lnum" for horizontal scrolling.
+ */
+ static colnr_T
+scroll_line_len(linenr_T lnum)
+{
+ char_u *p;
+ colnr_T col;
+ int w;
+
+ p = ml_get(lnum);
+ col = 0;
+ if (*p != NUL)
+ for (;;)
+ {
+ w = chartabsize(p, col);
+ MB_PTR_ADV(p);
+ if (*p == NUL) /* don't count the last character */
+ break;
+ col += w;
+ }
+ return col;
+}
+
+/* Remember which line is currently the longest, so that we don't have to
+ * search for it when scrolling horizontally. */
+static linenr_T longest_lnum = 0;
+
+/*
+ * Find longest visible line number. If this is not possible (or not desired,
+ * by setting 'h' in "guioptions") then the current line number is returned.
+ */
+ static linenr_T
+gui_find_longest_lnum(void)
+{
+ linenr_T ret = 0;
+
+ /* Calculate maximum for horizontal scrollbar. Check for reasonable
+ * line numbers, topline and botline can be invalid when displaying is
+ * postponed. */
+ if (vim_strchr(p_go, GO_HORSCROLL) == NULL
+ && curwin->w_topline <= curwin->w_cursor.lnum
+ && curwin->w_botline > curwin->w_cursor.lnum
+ && curwin->w_botline <= curbuf->b_ml.ml_line_count + 1)
+ {
+ linenr_T lnum;
+ colnr_T n;
+ long max = 0;
+
+ /* Use maximum of all visible lines. Remember the lnum of the
+ * longest line, closest to the cursor line. Used when scrolling
+ * below. */
+ for (lnum = curwin->w_topline; lnum < curwin->w_botline; ++lnum)
+ {
+ n = scroll_line_len(lnum);
+ if (n > (colnr_T)max)
+ {
+ max = n;
+ ret = lnum;
+ }
+ else if (n == (colnr_T)max
+ && abs((int)(lnum - curwin->w_cursor.lnum))
+ < abs((int)(ret - curwin->w_cursor.lnum)))
+ ret = lnum;
+ }
+ }
+ else
+ /* Use cursor line only. */
+ ret = curwin->w_cursor.lnum;
+
+ return ret;
+}
+
+ static void
+gui_update_horiz_scrollbar(int force)
+{
+ long value, size, max; /* need 32 bit ints here */
+
+ if (!gui.which_scrollbars[SBAR_BOTTOM])
+ return;
+
+ if (!force && gui.dragged_sb == SBAR_BOTTOM)
+ return;
+
+ if (!force && curwin->w_p_wrap && gui.prev_wrap)
+ return;
+
+ /*
+ * It is possible for the cursor to be invalid if we're in the middle of
+ * something (like changing files). If so, don't do anything for now.
+ */
+ if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
+ {
+ gui.bottom_sbar.value = -1;
+ return;
+ }
+
+ size = curwin->w_width;
+ if (curwin->w_p_wrap)
+ {
+ value = 0;
+#ifdef SCROLL_PAST_END
+ max = 0;
+#else
+ max = curwin->w_width - 1;
+#endif
+ }
+ else
+ {
+ value = curwin->w_leftcol;
+
+ longest_lnum = gui_find_longest_lnum();
+ max = scroll_line_len(longest_lnum);
+
+ if (virtual_active())
+ {
+ /* May move the cursor even further to the right. */
+ if (curwin->w_virtcol >= (colnr_T)max)
+ max = curwin->w_virtcol;
+ }
+
+#ifndef SCROLL_PAST_END
+ max += curwin->w_width - 1;
+#endif
+ /* The line number isn't scrolled, thus there is less space when
+ * 'number' or 'relativenumber' is set (also for 'foldcolumn'). */
+ size -= curwin_col_off();
+#ifndef SCROLL_PAST_END
+ max -= curwin_col_off();
+#endif
+ }
+
+#ifndef SCROLL_PAST_END
+ if (value > max - size + 1)
+ value = max - size + 1; /* limit the value to allowable range */
+#endif
+
+#ifdef FEAT_RIGHTLEFT
+ if (curwin->w_p_rl)
+ {
+ value = max + 1 - size - value;
+ if (value < 0)
+ {
+ size += value;
+ value = 0;
+ }
+ }
+#endif
+ if (!force && value == gui.bottom_sbar.value && size == gui.bottom_sbar.size
+ && max == gui.bottom_sbar.max)
+ return;
+
+ gui.bottom_sbar.value = value;
+ gui.bottom_sbar.size = size;
+ gui.bottom_sbar.max = max;
+ gui.prev_wrap = curwin->w_p_wrap;
+
+ gui_mch_set_scrollbar_thumb(&gui.bottom_sbar, value, size, max);
+}
+
+/*
+ * Do a horizontal scroll. Return TRUE if the cursor moved, FALSE otherwise.
+ */
+ int
+gui_do_horiz_scroll(long_u leftcol, int compute_longest_lnum)
+{
+ /* no wrapping, no scrolling */
+ if (curwin->w_p_wrap)
+ return FALSE;
+
+ if (curwin->w_leftcol == (colnr_T)leftcol)
+ return FALSE;
+
+ curwin->w_leftcol = (colnr_T)leftcol;
+
+ /* When the line of the cursor is too short, move the cursor to the
+ * longest visible line. */
+ if (vim_strchr(p_go, GO_HORSCROLL) == NULL
+ && !virtual_active()
+ && (colnr_T)leftcol > scroll_line_len(curwin->w_cursor.lnum))
+ {
+ if (compute_longest_lnum)
+ {
+ curwin->w_cursor.lnum = gui_find_longest_lnum();
+ curwin->w_cursor.col = 0;
+ }
+ /* Do a sanity check on "longest_lnum", just in case. */
+ else if (longest_lnum >= curwin->w_topline
+ && longest_lnum < curwin->w_botline)
+ {
+ curwin->w_cursor.lnum = longest_lnum;
+ curwin->w_cursor.col = 0;
+ }
+ }
+
+ return leftcol_changed();
+}
+
+/*
+ * Check that none of the colors are the same as the background color
+ */
+ void
+gui_check_colors(void)
+{
+ if (gui.norm_pixel == gui.back_pixel || gui.norm_pixel == INVALCOLOR)
+ {
+ gui_set_bg_color((char_u *)"White");
+ if (gui.norm_pixel == gui.back_pixel || gui.norm_pixel == INVALCOLOR)
+ gui_set_fg_color((char_u *)"Black");
+ }
+}
+
+ static void
+gui_set_fg_color(char_u *name)
+{
+ gui.norm_pixel = gui_get_color(name);
+ hl_set_fg_color_name(vim_strsave(name));
+}
+
+ static void
+gui_set_bg_color(char_u *name)
+{
+ gui.back_pixel = gui_get_color(name);
+ hl_set_bg_color_name(vim_strsave(name));
+}
+
+/*
+ * Allocate a color by name.
+ * Returns INVALCOLOR and gives an error message when failed.
+ */
+ guicolor_T
+gui_get_color(char_u *name)
+{
+ guicolor_T t;
+
+ if (*name == NUL)
+ return INVALCOLOR;
+ t = gui_mch_get_color(name);
+
+ if (t == INVALCOLOR
+#if defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK)
+ && gui.in_use
+#endif
+ )
+ semsg(_("E254: Cannot allocate color %s"), name);
+ return t;
+}
+
+/*
+ * Return the grey value of a color (range 0-255).
+ */
+ int
+gui_get_lightness(guicolor_T pixel)
+{
+ long_u rgb = (long_u)gui_mch_get_rgb(pixel);
+
+ return (int)( (((rgb >> 16) & 0xff) * 299)
+ + (((rgb >> 8) & 0xff) * 587)
+ + ((rgb & 0xff) * 114)) / 1000;
+}
+
+#if defined(FEAT_GUI_X11) || defined(PROTO)
+ void
+gui_new_scrollbar_colors(void)
+{
+ win_T *wp;
+
+ /* Nothing to do if GUI hasn't started yet. */
+ if (!gui.in_use)
+ return;
+
+ FOR_ALL_WINDOWS(wp)
+ {
+ gui_mch_set_scrollbar_colors(&(wp->w_scrollbars[SBAR_LEFT]));
+ gui_mch_set_scrollbar_colors(&(wp->w_scrollbars[SBAR_RIGHT]));
+ }
+ gui_mch_set_scrollbar_colors(&gui.bottom_sbar);
+}
+#endif
+
+/*
+ * Call this when focus has changed.
+ */
+ void
+gui_focus_change(int in_focus)
+{
+/*
+ * Skip this code to avoid drawing the cursor when debugging and switching
+ * between the debugger window and gvim.
+ */
+#if 1
+ gui.in_focus = in_focus;
+ out_flush_cursor(TRUE, FALSE);
+
+# ifdef FEAT_XIM
+ xim_set_focus(in_focus);
+# endif
+
+ /* Put events in the input queue only when allowed.
+ * ui_focus_change() isn't called directly, because it invokes
+ * autocommands and that must not happen asynchronously. */
+ if (!hold_gui_events)
+ {
+ char_u bytes[3];
+
+ bytes[0] = CSI;
+ bytes[1] = KS_EXTRA;
+ bytes[2] = in_focus ? (int)KE_FOCUSGAINED : (int)KE_FOCUSLOST;
+ add_to_input_buf(bytes, 3);
+ }
+#endif
+}
+
+/*
+ * Called when the mouse moved (but not when dragging).
+ */
+ void
+gui_mouse_moved(int x, int y)
+{
+ win_T *wp;
+ char_u st[8];
+
+ /* Ignore this while still starting up. */
+ if (!gui.in_use || gui.starting)
+ return;
+
+#ifdef FEAT_MOUSESHAPE
+ /* Get window pointer, and update mouse shape as well. */
+ wp = xy2win(x, y);
+#endif
+
+ /* Only handle this when 'mousefocus' set and ... */
+ if (p_mousef
+ && !hold_gui_events /* not holding events */
+ && (State & (NORMAL|INSERT))/* Normal/Visual/Insert mode */
+ && State != HITRETURN /* but not hit-return prompt */
+ && msg_scrolled == 0 /* no scrolled message */
+ && !need_mouse_correct /* not moving the pointer */
+ && gui.in_focus) /* gvim in focus */
+ {
+ /* Don't move the mouse when it's left or right of the Vim window */
+ if (x < 0 || x > Columns * gui.char_width)
+ return;
+#ifndef FEAT_MOUSESHAPE
+ wp = xy2win(x, y);
+#endif
+ if (wp == curwin || wp == NULL)
+ return; /* still in the same old window, or none at all */
+
+ /* Ignore position in the tab pages line. */
+ if (Y_2_ROW(y) < tabline_height())
+ return;
+
+ /*
+ * format a mouse click on status line input
+ * ala gui_send_mouse_event(0, x, y, 0, 0);
+ * Trick: Use a column number -1, so that get_pseudo_mouse_code() will
+ * generate a K_LEFTMOUSE_NM key code.
+ */
+ if (finish_op)
+ {
+ /* abort the current operator first */
+ st[0] = ESC;
+ add_to_input_buf(st, 1);
+ }
+ st[0] = CSI;
+ st[1] = KS_MOUSE;
+ st[2] = KE_FILLER;
+ st[3] = (char_u)MOUSE_LEFT;
+ fill_mouse_coord(st + 4,
+ wp->w_wincol == 0 ? -1 : wp->w_wincol + MOUSE_COLOFF,
+ wp->w_height + W_WINROW(wp));
+
+ add_to_input_buf(st, 8);
+ st[3] = (char_u)MOUSE_RELEASE;
+ add_to_input_buf(st, 8);
+#ifdef FEAT_GUI_GTK
+ /* Need to wake up the main loop */
+ if (gtk_main_level() > 0)
+ gtk_main_quit();
+#endif
+ }
+}
+
+/*
+ * Called when mouse should be moved to window with focus.
+ */
+ void
+gui_mouse_correct(void)
+{
+ int x, y;
+ win_T *wp = NULL;
+
+ need_mouse_correct = FALSE;
+
+ if (!(gui.in_use && p_mousef))
+ return;
+
+ gui_mch_getmouse(&x, &y);
+ /* Don't move the mouse when it's left or right of the Vim window */
+ if (x < 0 || x > Columns * gui.char_width)
+ return;
+ if (y >= 0 && Y_2_ROW(y) >= tabline_height())
+ wp = xy2win(x, y);
+ if (wp != curwin && wp != NULL) /* If in other than current window */
+ {
+ validate_cline_row();
+ gui_mch_setmouse((int)W_ENDCOL(curwin) * gui.char_width - 3,
+ (W_WINROW(curwin) + curwin->w_wrow) * gui.char_height
+ + (gui.char_height) / 2);
+ }
+}
+
+/*
+ * Find window where the mouse pointer "x" / "y" coordinate is in.
+ */
+ static win_T *
+xy2win(int x UNUSED, int y UNUSED)
+{
+ int row;
+ int col;
+ win_T *wp;
+
+ row = Y_2_ROW(y);
+ col = X_2_COL(x);
+ if (row < 0 || col < 0) /* before first window */
+ return NULL;
+ wp = mouse_find_win(&row, &col);
+ if (wp == NULL)
+ return NULL;
+#ifdef FEAT_MOUSESHAPE
+ if (State == HITRETURN || State == ASKMORE)
+ {
+ if (Y_2_ROW(y) >= msg_row)
+ update_mouseshape(SHAPE_IDX_MOREL);
+ else
+ update_mouseshape(SHAPE_IDX_MORE);
+ }
+ else if (row > wp->w_height) /* below status line */
+ update_mouseshape(SHAPE_IDX_CLINE);
+ else if (!(State & CMDLINE) && wp->w_vsep_width > 0 && col == wp->w_width
+ && (row != wp->w_height || !stl_connected(wp)) && msg_scrolled == 0)
+ update_mouseshape(SHAPE_IDX_VSEP);
+ else if (!(State & CMDLINE) && wp->w_status_height > 0
+ && row == wp->w_height && msg_scrolled == 0)
+ update_mouseshape(SHAPE_IDX_STATUS);
+ else
+ update_mouseshape(-2);
+#endif
+ return wp;
+}
+
+/*
+ * ":gui" and ":gvim": Change from the terminal version to the GUI version.
+ * File names may be given to redefine the args list.
+ */
+ void
+ex_gui(exarg_T *eap)
+{
+ char_u *arg = eap->arg;
+
+ /*
+ * Check for "-f" argument: foreground, don't fork.
+ * Also don't fork when started with "gvim -f".
+ * Do fork when using "gui -b".
+ */
+ if (arg[0] == '-'
+ && (arg[1] == 'f' || arg[1] == 'b')
+ && (arg[2] == NUL || VIM_ISWHITE(arg[2])))
+ {
+ gui.dofork = (arg[1] == 'b');
+ eap->arg = skipwhite(eap->arg + 2);
+ }
+ if (!gui.in_use)
+ {
+ /* Clear the command. Needed for when forking+exiting, to avoid part
+ * of the argument ending up after the shell prompt. */
+ msg_clr_eos_force();
+ gui_start();
+#ifdef FEAT_JOB_CHANNEL
+ channel_gui_register_all();
+#endif
+ }
+ if (!ends_excmd(*eap->arg))
+ ex_next(eap);
+}
+
+#if ((defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK) || defined(FEAT_GUI_W32) \
+ || defined(FEAT_GUI_PHOTON)) && defined(FEAT_TOOLBAR)) || defined(PROTO)
+/*
+ * This is shared between Athena, Motif and GTK.
+ */
+
+/*
+ * Callback function for do_in_runtimepath().
+ */
+ static void
+gfp_setname(char_u *fname, void *cookie)
+{
+ char_u *gfp_buffer = cookie;
+
+ if (STRLEN(fname) >= MAXPATHL)
+ *gfp_buffer = NUL;
+ else
+ STRCPY(gfp_buffer, fname);
+}
+
+/*
+ * Find the path of bitmap "name" with extension "ext" in 'runtimepath'.
+ * Return FAIL for failure and OK if buffer[MAXPATHL] contains the result.
+ */
+ int
+gui_find_bitmap(char_u *name, char_u *buffer, char *ext)
+{
+ if (STRLEN(name) > MAXPATHL - 14)
+ return FAIL;
+ vim_snprintf((char *)buffer, MAXPATHL, "bitmaps/%s.%s", name, ext);
+ if (do_in_runtimepath(buffer, 0, gfp_setname, buffer) == FAIL
+ || *buffer == NUL)
+ return FAIL;
+ return OK;
+}
+
+# if !defined(FEAT_GUI_GTK) || defined(PROTO)
+/*
+ * Given the name of the "icon=" argument, try finding the bitmap file for the
+ * icon. If it is an absolute path name, use it as it is. Otherwise append
+ * "ext" and search for it in 'runtimepath'.
+ * The result is put in "buffer[MAXPATHL]". If something fails "buffer"
+ * contains "name".
+ */
+ void
+gui_find_iconfile(char_u *name, char_u *buffer, char *ext)
+{
+ char_u buf[MAXPATHL + 1];
+
+ expand_env(name, buffer, MAXPATHL);
+ if (!mch_isFullName(buffer) && gui_find_bitmap(buffer, buf, ext) == OK)
+ STRCPY(buffer, buf);
+}
+# endif
+#endif
+
+#if defined(FEAT_GUI_GTK) || defined(FEAT_GUI_X11) || defined(PROTO)
+ void
+display_errors(void)
+{
+ char_u *p;
+
+ if (isatty(2))
+ fflush(stderr);
+ else if (error_ga.ga_data != NULL)
+ {
+ /* avoid putting up a message box with blanks only */
+ for (p = (char_u *)error_ga.ga_data; *p != NUL; ++p)
+ if (!isspace(*p))
+ {
+ /* Truncate a very long message, it will go off-screen. */
+ if (STRLEN(p) > 2000)
+ STRCPY(p + 2000 - 14, "...(truncated)");
+ (void)do_dialog(VIM_ERROR, (char_u *)_("Error"),
+ p, (char_u *)_("&Ok"), 1, NULL, FALSE);
+ break;
+ }
+ ga_clear(&error_ga);
+ }
+}
+#endif
+
+#if defined(NO_CONSOLE_INPUT) || defined(PROTO)
+/*
+ * Return TRUE if still starting up and there is no place to enter text.
+ * For GTK and X11 we check if stderr is not a tty, which means we were
+ * (probably) started from the desktop. Also check stdin, "vim >& file" does
+ * allow typing on stdin.
+ */
+ int
+no_console_input(void)
+{
+ return ((!gui.in_use || gui.starting)
+# ifndef NO_CONSOLE
+ && !isatty(0) && !isatty(2)
+# endif
+ );
+}
+#endif
+
+#if defined(FIND_REPLACE_DIALOG) \
+ || defined(NEED_GUI_UPDATE_SCREEN) \
+ || defined(PROTO)
+/*
+ * Update the current window and the screen.
+ */
+ void
+gui_update_screen(void)
+{
+# ifdef FEAT_CONCEAL
+ linenr_T conceal_old_cursor_line = 0;
+ linenr_T conceal_new_cursor_line = 0;
+ int conceal_update_lines = FALSE;
+# endif
+
+ update_topline();
+ validate_cursor();
+
+ /* Trigger CursorMoved if the cursor moved. */
+ if (!finish_op && (has_cursormoved()
+# ifdef FEAT_CONCEAL
+ || curwin->w_p_cole > 0
+# endif
+ ) && !EQUAL_POS(last_cursormoved, curwin->w_cursor))
+ {
+ if (has_cursormoved())
+ apply_autocmds(EVENT_CURSORMOVED, NULL, NULL, FALSE, curbuf);
+# ifdef FEAT_CONCEAL
+ if (curwin->w_p_cole > 0)
+ {
+ conceal_old_cursor_line = last_cursormoved.lnum;
+ conceal_new_cursor_line = curwin->w_cursor.lnum;
+ conceal_update_lines = TRUE;
+ }
+# endif
+ last_cursormoved = curwin->w_cursor;
+ }
+
+# ifdef FEAT_CONCEAL
+ if (conceal_update_lines
+ && (conceal_old_cursor_line != conceal_new_cursor_line
+ || conceal_cursor_line(curwin)
+ || need_cursor_line_redraw))
+ {
+ if (conceal_old_cursor_line != conceal_new_cursor_line)
+ redrawWinline(curwin, conceal_old_cursor_line);
+ redrawWinline(curwin, conceal_new_cursor_line);
+ curwin->w_valid &= ~VALID_CROW;
+ need_cursor_line_redraw = FALSE;
+ }
+# endif
+ update_screen(0); /* may need to update the screen */
+ setcursor();
+ out_flush_cursor(TRUE, FALSE);
+}
+#endif
+
+#if defined(FIND_REPLACE_DIALOG) || defined(PROTO)
+/*
+ * Get the text to use in a find/replace dialog. Uses the last search pattern
+ * if the argument is empty.
+ * Returns an allocated string.
+ */
+ char_u *
+get_find_dialog_text(
+ char_u *arg,
+ int *wwordp, /* return: TRUE if \< \> found */
+ int *mcasep) /* return: TRUE if \C found */
+{
+ char_u *text;
+
+ if (*arg == NUL)
+ text = last_search_pat();
+ else
+ text = arg;
+ if (text != NULL)
+ {
+ text = vim_strsave(text);
+ if (text != NULL)
+ {
+ int len = (int)STRLEN(text);
+ int i;
+
+ /* Remove "\V" */
+ if (len >= 2 && STRNCMP(text, "\\V", 2) == 0)
+ {
+ mch_memmove(text, text + 2, (size_t)(len - 1));
+ len -= 2;
+ }
+
+ /* Recognize "\c" and "\C" and remove. */
+ if (len >= 2 && *text == '\\' && (text[1] == 'c' || text[1] == 'C'))
+ {
+ *mcasep = (text[1] == 'C');
+ mch_memmove(text, text + 2, (size_t)(len - 1));
+ len -= 2;
+ }
+
+ /* Recognize "\<text\>" and remove. */
+ if (len >= 4
+ && STRNCMP(text, "\\<", 2) == 0
+ && STRNCMP(text + len - 2, "\\>", 2) == 0)
+ {
+ *wwordp = TRUE;
+ mch_memmove(text, text + 2, (size_t)(len - 4));
+ text[len - 4] = NUL;
+ }
+
+ /* Recognize "\/" or "\?" and remove. */
+ for (i = 0; i + 1 < len; ++i)
+ if (text[i] == '\\' && (text[i + 1] == '/'
+ || text[i + 1] == '?'))
+ {
+ mch_memmove(text + i, text + i + 1, (size_t)(len - i));
+ --len;
+ }
+ }
+ }
+ return text;
+}
+
+/*
+ * Handle the press of a button in the find-replace dialog.
+ * Return TRUE when something was added to the input buffer.
+ */
+ int
+gui_do_findrepl(
+ int flags, /* one of FRD_REPLACE, FRD_FINDNEXT, etc. */
+ char_u *find_text,
+ char_u *repl_text,
+ int down) /* Search downwards. */
+{
+ garray_T ga;
+ int i;
+ int type = (flags & FRD_TYPE_MASK);
+ char_u *p;
+ regmatch_T regmatch;
+ int save_did_emsg = did_emsg;
+ static int busy = FALSE;
+
+ /* When the screen is being updated we should not change buffers and
+ * windows structures, it may cause freed memory to be used. Also don't
+ * do this recursively (pressing "Find" quickly several times. */
+ if (updating_screen || busy)
+ return FALSE;
+
+ /* refuse replace when text cannot be changed */
+ if ((type == FRD_REPLACE || type == FRD_REPLACEALL) && text_locked())
+ return FALSE;
+
+ busy = TRUE;
+
+ ga_init2(&ga, 1, 100);
+ if (type == FRD_REPLACEALL)
+ ga_concat(&ga, (char_u *)"%s/");
+
+ ga_concat(&ga, (char_u *)"\\V");
+ if (flags & FRD_MATCH_CASE)
+ ga_concat(&ga, (char_u *)"\\C");
+ else
+ ga_concat(&ga, (char_u *)"\\c");
+ if (flags & FRD_WHOLE_WORD)
+ ga_concat(&ga, (char_u *)"\\<");
+ /* escape / and \ */
+ p = vim_strsave_escaped(find_text, (char_u *)"/\\");
+ if (p != NULL)
+ ga_concat(&ga, p);
+ vim_free(p);
+ if (flags & FRD_WHOLE_WORD)
+ ga_concat(&ga, (char_u *)"\\>");
+
+ if (type == FRD_REPLACEALL)
+ {
+ ga_concat(&ga, (char_u *)"/");
+ /* escape / and \ */
+ p = vim_strsave_escaped(repl_text, (char_u *)"/\\");
+ if (p != NULL)
+ ga_concat(&ga, p);
+ vim_free(p);
+ ga_concat(&ga, (char_u *)"/g");
+ }
+ ga_append(&ga, NUL);
+
+ if (type == FRD_REPLACE)
+ {
+ /* Do the replacement when the text at the cursor matches. Thus no
+ * replacement is done if the cursor was moved! */
+ regmatch.regprog = vim_regcomp(ga.ga_data, RE_MAGIC + RE_STRING);
+ regmatch.rm_ic = 0;
+ if (regmatch.regprog != NULL)
+ {
+ p = ml_get_cursor();
+ if (vim_regexec_nl(&regmatch, p, (colnr_T)0)
+ && regmatch.startp[0] == p)
+ {
+ /* Clear the command line to remove any old "No match"
+ * error. */
+ msg_end_prompt();
+
+ if (u_save_cursor() == OK)
+ {
+ /* A button was pressed thus undo should be synced. */
+ u_sync(FALSE);
+
+ del_bytes((long)(regmatch.endp[0] - regmatch.startp[0]),
+ FALSE, FALSE);
+ ins_str(repl_text);
+ }
+ }
+ else
+ msg(_("No match at cursor, finding next"));
+ vim_regfree(regmatch.regprog);
+ }
+ }
+
+ if (type == FRD_REPLACEALL)
+ {
+ /* A button was pressed, thus undo should be synced. */
+ u_sync(FALSE);
+ do_cmdline_cmd(ga.ga_data);
+ }
+ else
+ {
+ int searchflags = SEARCH_MSG + SEARCH_MARK;
+
+ /* Search for the next match.
+ * Don't skip text under cursor for single replace. */
+ if (type == FRD_REPLACE)
+ searchflags += SEARCH_START;
+ i = msg_scroll;
+ if (down)
+ {
+ (void)do_search(NULL, '/', ga.ga_data, 1L, searchflags, NULL, NULL);
+ }
+ else
+ {
+ /* We need to escape '?' if and only if we are searching in the up
+ * direction */
+ p = vim_strsave_escaped(ga.ga_data, (char_u *)"?");
+ if (p != NULL)
+ (void)do_search(NULL, '?', p, 1L, searchflags, NULL, NULL);
+ vim_free(p);
+ }
+
+ msg_scroll = i; /* don't let an error message set msg_scroll */
+ }
+
+ /* Don't want to pass did_emsg to other code, it may cause disabling
+ * syntax HL if we were busy redrawing. */
+ did_emsg = save_did_emsg;
+
+ if (State & (NORMAL | INSERT))
+ {
+ gui_update_screen(); /* update the screen */
+ msg_didout = 0; /* overwrite any message */
+ need_wait_return = FALSE; /* don't wait for return */
+ }
+
+ vim_free(ga.ga_data);
+ busy = FALSE;
+ return (ga.ga_len > 0);
+}
+
+#endif
+
+#if defined(HAVE_DROP_FILE) || defined(PROTO)
+/*
+ * Jump to the window at specified point (x, y).
+ */
+ static void
+gui_wingoto_xy(int x, int y)
+{
+ int row = Y_2_ROW(y);
+ int col = X_2_COL(x);
+ win_T *wp;
+
+ if (row >= 0 && col >= 0)
+ {
+ wp = mouse_find_win(&row, &col);
+ if (wp != NULL && wp != curwin)
+ win_goto(wp);
+ }
+}
+
+/*
+ * Function passed to handle_drop() for the actions to be done after the
+ * argument list has been updated.
+ */
+ static void
+drop_callback(void *cookie)
+{
+ char_u *p = cookie;
+
+ /* If Shift held down, change to first file's directory. If the first
+ * item is a directory, change to that directory (and let the explorer
+ * plugin show the contents). */
+ if (p != NULL)
+ {
+ if (mch_isdir(p))
+ {
+ if (mch_chdir((char *)p) == 0)
+ shorten_fnames(TRUE);
+ }
+ else if (vim_chdirfile(p, "drop") == OK)
+ shorten_fnames(TRUE);
+ vim_free(p);
+ }
+
+ /* Update the screen display */
+ update_screen(NOT_VALID);
+# ifdef FEAT_MENU
+ gui_update_menus(0);
+# endif
+#ifdef FEAT_TITLE
+ maketitle();
+#endif
+ setcursor();
+ out_flush_cursor(FALSE, FALSE);
+}
+
+/*
+ * Process file drop. Mouse cursor position, key modifiers, name of files
+ * and count of files are given. Argument "fnames[count]" has full pathnames
+ * of dropped files, they will be freed in this function, and caller can't use
+ * fnames after call this function.
+ */
+ void
+gui_handle_drop(
+ int x UNUSED,
+ int y UNUSED,
+ int_u modifiers,
+ char_u **fnames,
+ int count)
+{
+ int i;
+ char_u *p;
+ static int entered = FALSE;
+
+ /*
+ * This function is called by event handlers. Just in case we get a
+ * second event before the first one is handled, ignore the second one.
+ * Not sure if this can ever happen, just in case.
+ */
+ if (entered)
+ return;
+ entered = TRUE;
+
+ /*
+ * When the cursor is at the command line, add the file names to the
+ * command line, don't edit the files.
+ */
+ if (State & CMDLINE)
+ {
+ shorten_filenames(fnames, count);
+ for (i = 0; i < count; ++i)
+ {
+ if (fnames[i] != NULL)
+ {
+ if (i > 0)
+ add_to_input_buf((char_u*)" ", 1);
+
+ /* We don't know what command is used thus we can't be sure
+ * about which characters need to be escaped. Only escape the
+ * most common ones. */
+# ifdef BACKSLASH_IN_FILENAME
+ p = vim_strsave_escaped(fnames[i], (char_u *)" \t\"|");
+# else
+ p = vim_strsave_escaped(fnames[i], (char_u *)"\\ \t\"|");
+# endif
+ if (p != NULL)
+ add_to_input_buf_csi(p, (int)STRLEN(p));
+ vim_free(p);
+ vim_free(fnames[i]);
+ }
+ }
+ vim_free(fnames);
+ }
+ else
+ {
+ /* Go to the window under mouse cursor, then shorten given "fnames" by
+ * current window, because a window can have local current dir. */
+ gui_wingoto_xy(x, y);
+ shorten_filenames(fnames, count);
+
+ /* If Shift held down, remember the first item. */
+ if ((modifiers & MOUSE_SHIFT) != 0)
+ p = vim_strsave(fnames[0]);
+ else
+ p = NULL;
+
+ /* Handle the drop, :edit or :split to get to the file. This also
+ * frees fnames[]. Skip this if there is only one item, it's a
+ * directory and Shift is held down. */
+ if (count == 1 && (modifiers & MOUSE_SHIFT) != 0
+ && mch_isdir(fnames[0]))
+ {
+ vim_free(fnames[0]);
+ vim_free(fnames);
+ }
+ else
+ handle_drop(count, fnames, (modifiers & MOUSE_CTRL) != 0,
+ drop_callback, (void *)p);
+ }
+
+ entered = FALSE;
+}
+#endif
diff --git a/src/gui.h b/src/gui.h
new file mode 100644
index 0000000..a57b0a3
--- /dev/null
+++ b/src/gui.h
@@ -0,0 +1,569 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ * Motif support by Robert Webb
+ *
+ * Do ":help uganda" in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ */
+
+#ifdef FEAT_GUI_MOTIF
+# include <Xm/Xm.h>
+#endif
+
+#ifdef FEAT_GUI_ATHENA
+# include <X11/Intrinsic.h>
+# include <X11/StringDefs.h>
+#endif
+
+#ifdef FEAT_GUI_GTK
+# ifdef VMS /* undef MIN and MAX because Intrinsic.h redefines them anyway */
+# ifdef MAX
+# undef MAX
+# endif
+# ifdef MIN
+# undef MIN
+# endif
+# endif
+# include <X11/Intrinsic.h>
+# include <gtk/gtk.h>
+#endif
+
+#ifdef FEAT_GUI_MAC
+# include <Types.h>
+/*# include <Memory.h>*/
+# include <Quickdraw.h>
+# include <Fonts.h>
+# include <Events.h>
+# include <Menus.h>
+# if !(defined (TARGET_API_MAC_CARBON) && (TARGET_API_MAC_CARBON))
+# include <Windows.h>
+# endif
+# include <Controls.h>
+/*# include <TextEdit.h>*/
+# include <Dialogs.h>
+# include <OSUtils.h>
+/*
+# include <ToolUtils.h>
+# include <SegLoad.h>*/
+#endif
+
+#ifdef FEAT_GUI_PHOTON
+# include <Ph.h>
+# include <Pt.h>
+# include "photon/PxProto.h"
+#endif
+
+/*
+ * 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)
+# define USE_ON_FLY_SCROLL
+#endif
+
+/*
+ * GUIs that support dropping files on a running Vim.
+ */
+#if (defined(FEAT_DND) && defined(FEAT_GUI_GTK)) \
+ || defined(FEAT_GUI_MSWIN) \
+ || defined(FEAT_GUI_MAC)
+# define HAVE_DROP_FILE
+#endif
+
+/*
+ * This define makes menus always use a fontset.
+ * We're not sure if this code always works, thus it can be disabled.
+ */
+#ifdef FEAT_XFONTSET
+# define FONTSET_ALWAYS
+#endif
+
+/*
+ * These macros convert between character row/column and pixel coordinates.
+ * TEXT_X - Convert character column into X pixel coord for drawing strings.
+ * TEXT_Y - Convert character row into Y pixel coord for drawing strings.
+ * FILL_X - Convert character column into X pixel coord for filling the area
+ * under the character.
+ * FILL_Y - Convert character row into Y pixel coord for filling the area
+ * under the character.
+ * X_2_COL - Convert X pixel coord into character column.
+ * Y_2_ROW - Convert Y pixel coord into character row.
+ */
+#ifdef FEAT_GUI_W32
+# define TEXT_X(col) ((col) * gui.char_width)
+# define TEXT_Y(row) ((row) * gui.char_height + gui.char_ascent)
+# define FILL_X(col) ((col) * gui.char_width)
+# define FILL_Y(row) ((row) * gui.char_height)
+# define X_2_COL(x) ((x) / gui.char_width)
+# define Y_2_ROW(y) ((y) / gui.char_height)
+#else
+# define TEXT_X(col) ((col) * gui.char_width + gui.border_offset)
+# define FILL_X(col) ((col) * gui.char_width + gui.border_offset)
+# define X_2_COL(x) (((x) - gui.border_offset) / gui.char_width)
+# define TEXT_Y(row) ((row) * gui.char_height + gui.char_ascent \
+ + gui.border_offset)
+# define FILL_Y(row) ((row) * gui.char_height + gui.border_offset)
+# define Y_2_ROW(y) (((y) - gui.border_offset) / gui.char_height)
+#endif
+
+/* Indices for arrays of scrollbars */
+#define SBAR_NONE -1
+#define SBAR_LEFT 0
+#define SBAR_RIGHT 1
+#define SBAR_BOTTOM 2
+
+/* Orientations for scrollbars */
+#define SBAR_VERT 0
+#define SBAR_HORIZ 1
+
+/* Default size of scrollbar */
+#define SB_DEFAULT_WIDTH 16
+
+/* Default height of the menu bar */
+#define MENU_DEFAULT_HEIGHT 1 /* figure it out at runtime */
+
+/* Flags for gui_mch_outstr_nowrap() */
+#define GUI_MON_WRAP_CURSOR 0x01 /* wrap cursor at end of line */
+#define GUI_MON_INVERT 0x02 /* invert the characters */
+#define GUI_MON_IS_CURSOR 0x04 /* drawing cursor */
+#define GUI_MON_TRS_CURSOR 0x08 /* drawing transparent cursor */
+#define GUI_MON_NOCLEAR 0x10 /* don't clear selection */
+
+/* Flags for gui_mch_draw_string() */
+#define DRAW_TRANSP 0x01 /* draw with transparent bg */
+#define DRAW_BOLD 0x02 /* draw bold text */
+#define DRAW_UNDERL 0x04 /* draw underline text */
+#define DRAW_UNDERC 0x08 /* draw undercurl text */
+#if defined(FEAT_GUI_GTK)
+# define DRAW_ITALIC 0x10 /* draw italic text */
+#endif
+#define DRAW_CURSOR 0x20 /* drawing block cursor (win32) */
+#define DRAW_STRIKE 0x40 /* strikethrough */
+
+/* For our own tearoff menu item */
+#define TEAR_STRING "-->Detach"
+#define TEAR_LEN (9) /* length of above string */
+
+/* for the toolbar */
+#define TOOLBAR_BUTTON_HEIGHT 18
+#define TOOLBAR_BUTTON_WIDTH 18
+#define TOOLBAR_BORDER_HEIGHT 12 /* room above+below buttons for MSWindows */
+
+#ifdef FEAT_GUI_MSWIN
+# define TABLINE_HEIGHT 22
+#endif
+#ifdef FEAT_GUI_MOTIF
+# define TABLINE_HEIGHT 30
+#endif
+
+#if defined(NO_CONSOLE) || defined(FEAT_GUI_GTK) || defined(FEAT_GUI_X11)
+# define NO_CONSOLE_INPUT /* use no_console_input() to check if there
+ is no console input possible */
+#endif
+
+typedef struct GuiScrollbar
+{
+ long ident; /* Unique identifier for each scrollbar */
+ win_T *wp; /* Scrollbar's window, NULL for bottom */
+ int type; /* one of SBAR_{LEFT,RIGHT,BOTTOM} */
+ long value; /* Represents top line number visible */
+#ifdef FEAT_GUI_ATHENA
+ int pixval; /* pixel count of value */
+#endif
+ long size; /* Size of scrollbar thumb */
+ long max; /* Number of lines in buffer */
+
+ /* Values measured in characters: */
+ int top; /* Top of scroll bar (chars from row 0) */
+ int height; /* Current height of scroll bar in rows */
+ int width; /* Current width of scroll bar in cols */
+ int status_height; /* Height of status line */
+#ifdef FEAT_GUI_X11
+ Widget id; /* Id of real scroll bar */
+#endif
+#ifdef FEAT_GUI_GTK
+ GtkWidget *id; /* Id of real scroll bar */
+ unsigned long handler_id; /* Id of "value_changed" signal handler */
+#endif
+
+#ifdef FEAT_GUI_MSWIN
+ HWND id; /* Id of real scroll bar */
+ int scroll_shift; /* The scrollbar stuff can handle only up to
+ 32767 lines. When the file is longer,
+ scroll_shift is set to the number of shifts
+ to reduce the count. */
+#endif
+#ifdef FEAT_GUI_MAC
+ ControlHandle id; /* A handle to the scrollbar */
+#endif
+#ifdef FEAT_GUI_PHOTON
+ PtWidget_t *id;
+#endif
+} scrollbar_T;
+
+typedef long guicolor_T; /* handle for a GUI color; for X11 this should
+ be "Pixel", but that's an unsigned and we
+ need a signed value */
+#define INVALCOLOR (guicolor_T)-11111 /* number for invalid color; on 32 bit
+ displays there is a tiny chance this is an
+ actual color */
+#define CTERMCOLOR (guicolor_T)-11110 /* only used for cterm.bg_rgb and
+ cterm.fg_rgb: use cterm color */
+
+#ifdef FEAT_GUI_GTK
+ typedef PangoFontDescription *GuiFont; /* handle for a GUI font */
+ typedef PangoFontDescription *GuiFontset; /* handle for a GUI fontset */
+# define NOFONT (GuiFont)NULL
+# define NOFONTSET (GuiFontset)NULL
+#else
+# ifdef FEAT_GUI_PHOTON
+ typedef char *GuiFont;
+ typedef char *GuiFontset;
+# define NOFONT (GuiFont)NULL
+# define NOFONTSET (GuiFontset)NULL
+# else
+# ifdef FEAT_GUI_X11
+ typedef XFontStruct *GuiFont; /* handle for a GUI font */
+ typedef XFontSet GuiFontset; /* handle for a GUI fontset */
+# define NOFONT (GuiFont)0
+# define NOFONTSET (GuiFontset)0
+# else
+ typedef long_u GuiFont; /* handle for a GUI font */
+ typedef long_u GuiFontset; /* handle for a GUI fontset */
+# define NOFONT (GuiFont)0
+# define NOFONTSET (GuiFontset)0
+# endif
+# endif
+#endif
+
+typedef struct Gui
+{
+ int in_focus; /* Vim has input focus */
+ int in_use; /* Is the GUI being used? */
+ int starting; /* GUI will start in a little while */
+ int shell_created; /* Has the shell been created yet? */
+ int dying; /* Is vim dying? Then output to terminal */
+ int dofork; /* Use fork() when GUI is starting */
+ int dragged_sb; /* Which scrollbar being dragged, if any? */
+ win_T *dragged_wp; /* Which WIN's sb being dragged, if any? */
+ int pointer_hidden; /* Is the mouse pointer hidden? */
+ int col; /* Current cursor column in GUI display */
+ int row; /* Current cursor row in GUI display */
+ int cursor_col; /* Physical cursor column in GUI display */
+ int cursor_row; /* Physical cursor row in GUI display */
+ char cursor_is_valid; /* There is a cursor at cursor_row/col */
+ int num_cols; /* Number of columns */
+ int num_rows; /* Number of rows */
+ int scroll_region_top; /* Top (first) line of scroll region */
+ int scroll_region_bot; /* Bottom (last) line of scroll region */
+ int scroll_region_left; /* Left (first) column of scroll region */
+ int scroll_region_right; /* Right (last) col. of scroll region */
+ int highlight_mask; /* Highlight attribute mask */
+ int scrollbar_width; /* Width of vertical scrollbars */
+ int scrollbar_height; /* Height of horizontal scrollbar */
+ int left_sbar_x; /* Calculated x coord for left scrollbar */
+ int right_sbar_x; /* Calculated x coord for right scrollbar */
+
+#ifdef FEAT_MENU
+# ifndef FEAT_GUI_GTK
+ int menu_height; /* Height of the menu bar */
+ int menu_width; /* Width of the menu bar */
+# endif
+ char menu_is_active; /* TRUE if menu is present */
+# ifdef FEAT_GUI_ATHENA
+ char menu_height_fixed; /* TRUE if menu height fixed */
+# endif
+#endif
+
+ scrollbar_T bottom_sbar; /* Bottom scrollbar */
+ int which_scrollbars[3];/* Which scrollbar boxes are active? */
+ int prev_wrap; /* For updating the horizontal scrollbar */
+ int char_width; /* Width of char cell in pixels */
+ int char_height; /* Height of char cell in pixels, includes
+ 'linespace' */
+ int char_ascent; /* Ascent of char in pixels */
+ int border_width; /* Width of our border around text area */
+ int border_offset; /* Total pixel offset for all borders */
+
+ GuiFont norm_font; /* Normal font */
+#ifndef FEAT_GUI_GTK
+ GuiFont bold_font; /* Bold font */
+ GuiFont ital_font; /* Italic font */
+ GuiFont boldital_font; /* Bold-Italic font */
+#else
+ int font_can_bold; /* Whether norm_font supports bold weight.
+ * The styled font variants are not used. */
+#endif
+
+#if defined(FEAT_MENU) && !defined(FEAT_GUI_GTK)
+# ifdef FONTSET_ALWAYS
+ GuiFontset menu_fontset; /* set of fonts for multi-byte chars */
+# else
+ GuiFont menu_font; /* menu item font */
+# endif
+#endif
+ GuiFont wide_font; /* Normal 'guifontwide' font */
+#ifndef FEAT_GUI_GTK
+ GuiFont wide_bold_font; /* Bold 'guifontwide' font */
+ GuiFont wide_ital_font; /* Italic 'guifontwide' font */
+ GuiFont wide_boldital_font; /* Bold-Italic 'guifontwide' font */
+#endif
+#ifdef FEAT_XFONTSET
+ GuiFontset fontset; /* set of fonts for multi-byte chars */
+#endif
+ guicolor_T back_pixel; /* Color of background */
+ guicolor_T norm_pixel; /* Color of normal text */
+ guicolor_T def_back_pixel; /* default Color of background */
+ guicolor_T def_norm_pixel; /* default Color of normal text */
+
+#ifdef FEAT_GUI_X11
+ char *rsrc_menu_fg_name; /* Color of menu & dialog foreground */
+ guicolor_T menu_fg_pixel; /* Same in Pixel format */
+ char *rsrc_menu_bg_name; /* Color of menu & dialog background */
+ guicolor_T menu_bg_pixel; /* Same in Pixel format */
+ char *rsrc_scroll_fg_name; /* Color of scrollbar foreground */
+ guicolor_T scroll_fg_pixel; /* Same in Pixel format */
+ char *rsrc_scroll_bg_name; /* Color of scrollbar background */
+ guicolor_T scroll_bg_pixel; /* Same in Pixel format */
+
+# ifdef FEAT_GUI_MOTIF
+ guicolor_T menu_def_fg_pixel; /* Default menu foreground */
+ guicolor_T menu_def_bg_pixel; /* Default menu background */
+ guicolor_T scroll_def_fg_pixel; /* Default scrollbar foreground */
+ guicolor_T scroll_def_bg_pixel; /* Default scrollbar background */
+# endif
+ Display *dpy; /* X display */
+ Window wid; /* Window id of text area */
+ int visibility; /* Is shell partially/fully obscured? */
+ GC text_gc;
+ GC back_gc;
+ GC invert_gc;
+ Cursor blank_pointer; /* Blank pointer */
+
+ /* X Resources */
+ char_u *rsrc_font_name; /* Resource font name, used if 'guifont'
+ not set */
+ char_u *rsrc_bold_font_name; /* Resource bold font name */
+ char_u *rsrc_ital_font_name; /* Resource italic font name */
+ char_u *rsrc_boldital_font_name; /* Resource bold-italic font name */
+ char_u *rsrc_menu_font_name; /* Resource menu Font name */
+ Bool rsrc_rev_video; /* Use reverse video? */
+
+ char_u *geom; /* Geometry, eg "80x24" */
+ Bool color_approx; /* Some color was approximated */
+#endif
+
+#ifdef FEAT_GUI_GTK
+# ifndef USE_GTK3
+ int visibility; /* Is shell partially/fully obscured? */
+# endif
+ GdkCursor *blank_pointer; /* Blank pointer */
+
+ /* X Resources */
+ char_u *geom; /* Geometry, eg "80x24" */
+
+ GtkWidget *mainwin; /* top level GTK window */
+ GtkWidget *formwin; /* manages all the windows below */
+ GtkWidget *drawarea; /* the "text" area */
+# ifdef FEAT_MENU
+ GtkWidget *menubar; /* menubar */
+# endif
+# ifdef FEAT_TOOLBAR
+ GtkWidget *toolbar; /* toolbar */
+# endif
+# ifdef FEAT_GUI_GNOME
+ GtkWidget *menubar_h; /* menubar handle */
+ GtkWidget *toolbar_h; /* toolbar handle */
+# endif
+# ifdef USE_GTK3
+ GdkRGBA *fgcolor; /* GDK-styled foreground color */
+ GdkRGBA *bgcolor; /* GDK-styled background color */
+ GdkRGBA *spcolor; /* GDK-styled special color */
+# else
+ GdkColor *fgcolor; /* GDK-styled foreground color */
+ GdkColor *bgcolor; /* GDK-styled background color */
+ GdkColor *spcolor; /* GDK-styled special color */
+# endif
+# ifdef USE_GTK3
+ cairo_surface_t *surface; /* drawarea surface */
+ gboolean by_signal; /* cause of draw operation */
+# else
+ GdkGC *text_gc; /* cached GC for normal text */
+# endif
+ PangoContext *text_context; /* the context used for all text */
+ PangoFont *ascii_font; /* cached font for ASCII strings */
+ PangoGlyphString *ascii_glyphs; /* cached code point -> glyph map */
+# ifdef FEAT_GUI_TABLINE
+ GtkWidget *tabline; /* tab pages line handle */
+# endif
+
+ GtkAccelGroup *accel_group;
+ GtkWidget *filedlg; /* file selection dialog */
+ char_u *browse_fname; /* file name from filedlg */
+
+ guint32 event_time;
+#endif /* FEAT_GUI_GTK */
+
+#if defined(FEAT_GUI_TABLINE) \
+ && (defined(FEAT_GUI_W32) || defined(FEAT_GUI_MOTIF) \
+ || defined(FEAT_GUI_MAC))
+ int tabline_height;
+#endif
+
+#ifdef FEAT_FOOTER
+ int footer_height; /* height of the message footer */
+#endif
+
+#if defined(FEAT_TOOLBAR) \
+ && (defined(FEAT_GUI_ATHENA) || defined(FEAT_GUI_MOTIF))
+ int toolbar_height; /* height of the toolbar */
+#endif
+
+#ifdef FEAT_BEVAL_TIP
+ /* Tooltip properties; also used for balloon evaluation */
+ char_u *rsrc_tooltip_font_name; /* tooltip font name */
+ char *rsrc_tooltip_fg_name; /* tooltip foreground color name */
+ char *rsrc_tooltip_bg_name; /* tooltip background color name */
+ guicolor_T tooltip_fg_pixel; /* tooltip foreground color */
+ guicolor_T tooltip_bg_pixel; /* tooltip background color */
+ XFontSet tooltip_fontset; /* tooltip fontset */
+#endif
+
+#ifdef FEAT_GUI_MSWIN
+ GuiFont currFont; /* Current font */
+ guicolor_T currFgColor; /* Current foreground text color */
+ guicolor_T currBgColor; /* Current background text color */
+ guicolor_T currSpColor; /* Current special text color */
+#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 */
+ PtWidget_t *vimContainer; /* PtPanel */
+# if defined(FEAT_MENU) || defined(FEAT_TOOLBAR)
+ PtWidget_t *vimToolBarGroup;
+# endif
+# ifdef FEAT_MENU
+ PtWidget_t *vimMenuBar;
+# endif
+# ifdef FEAT_TOOLBAR
+ PtWidget_t *vimToolBar;
+ int toolbar_height;
+# endif
+ PhEvent_t *event_buffer;
+#endif
+
+#ifdef FEAT_XIM
+ char *rsrc_input_method;
+ char *rsrc_preedit_type_name;
+#endif
+} gui_T;
+
+extern gui_T gui; /* this is defined in gui.c */
+
+/* definitions of available window positionings for gui_*_position_in_parent()
+ */
+typedef enum
+{
+ VW_POS_MOUSE,
+ VW_POS_CENTER,
+ VW_POS_TOP_CENTER
+} gui_win_pos_T;
+
+#ifdef FIND_REPLACE_DIALOG
+/*
+ * Flags used to distinguish the different contexts in which the
+ * find/replace callback may be called.
+ */
+# define FRD_FINDNEXT 1 /* Find next in find dialog */
+# define FRD_R_FINDNEXT 2 /* Find next in repl dialog */
+# define FRD_REPLACE 3 /* Replace once */
+# define FRD_REPLACEALL 4 /* Replace remaining matches */
+# define FRD_UNDO 5 /* Undo replaced text */
+# define FRD_TYPE_MASK 7 /* Mask for the callback type */
+/* Flags which change the way searching is done. */
+# define FRD_WHOLE_WORD 0x08 /* match whole word only */
+# define FRD_MATCH_CASE 0x10 /* match case */
+#endif
+
+#ifdef FEAT_GUI_GTK
+/*
+ * Convenience macros to convert from 'encoding' to 'termencoding' and
+ * vice versa. If no conversion is necessary the passed-in pointer is
+ * returned as is, without allocating any memory. Thus additional _FREE()
+ * macros are provided. The _FREE() macros also set the pointer to NULL,
+ * in order to avoid bugs due to illegal memory access only happening if
+ * 'encoding' != utf-8...
+ *
+ * Defining these macros as pure expressions looks a bit tricky but
+ * avoids depending on the context of the macro expansion. One of the
+ * rare occasions where the comma operator comes in handy :)
+ *
+ * Note: Do NOT keep the result around when handling control back to
+ * the main Vim! The user could change 'encoding' at any time.
+ */
+# define CONVERT_TO_UTF8(String) \
+ ((output_conv.vc_type == CONV_NONE || (String) == NULL) \
+ ? (String) \
+ : string_convert(&output_conv, (String), NULL))
+
+# define CONVERT_TO_UTF8_FREE(String) \
+ ((String) = ((output_conv.vc_type == CONV_NONE) \
+ ? (char_u *)NULL \
+ : (vim_free(String), (char_u *)NULL)))
+
+# define CONVERT_FROM_UTF8(String) \
+ ((input_conv.vc_type == CONV_NONE || (String) == NULL) \
+ ? (String) \
+ : string_convert(&input_conv, (String), NULL))
+
+# define CONVERT_FROM_UTF8_FREE(String) \
+ ((String) = ((input_conv.vc_type == CONV_NONE) \
+ ? (char_u *)NULL \
+ : (vim_free(String), (char_u *)NULL)))
+
+#else
+# define CONVERT_TO_UTF8(String) (String)
+# define CONVERT_TO_UTF8_FREE(String) ((String) = (char_u *)NULL)
+# define CONVERT_FROM_UTF8(String) (String)
+# define CONVERT_FROM_UTF8_FREE(String) ((String) = (char_u *)NULL)
+#endif /* FEAT_GUI_GTK */
+
+#ifdef FEAT_GUI_GTK
+/*
+ * The second parameter of g_signal_handlers_disconnect_by_func() is supposed
+ * to be a function pointer which was passed to g_signal_connect_*() somewhere
+ * previously, and hence it must be of type GCallback, i.e., void (*)(void).
+ *
+ * Meanwhile, g_signal_handlers_disconnect_by_func() is a macro calling
+ * g_signal_handlers_disconnect_matched(), and the second parameter of the
+ * former is to be passed to the sixth parameter of the latter the type of
+ * which, however, is declared as void * in the function signature.
+ *
+ * While the ISO C Standard does not require that function pointers be
+ * interconvertible to void *, widely-used compilers such as gcc and clang
+ * do such conversion implicitly and automatically on some platforms without
+ * issuing any warning.
+ *
+ * For Solaris Studio, that is not the case. An explicit type cast is needed
+ * to suppress warnings on that particular conversion.
+ */
+# if defined(__SUNPRO_C) && defined(USE_GTK3)
+# define FUNC2GENERIC(func) (void *)(func)
+# else
+# define FUNC2GENERIC(func) G_CALLBACK(func)
+# endif
+#endif /* FEAT_GUI_GTK */
+
+#if defined(UNIX) && !defined(FEAT_GUI_MAC)
+# define GUI_MAY_FORK
+#endif
diff --git a/src/gui_at_fs.c b/src/gui_at_fs.c
new file mode 100644
index 0000000..e65a266
--- /dev/null
+++ b/src/gui_at_fs.c
@@ -0,0 +1,2734 @@
+/* vi:set ts=8 sts=4 sw=4 noet: */
+
+/*
+ * Copyright 1989 Software Research Associates, Inc., Tokyo, Japan
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Software Research Associates not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Software Research Associates
+ * makes no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * SOFTWARE RESEARCH ASSOCIATES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+ * IN NO EVENT SHALL SOFTWARE RESEARCH ASSOCIATES BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Erik M. van der Poel
+ * Software Research Associates, Inc., Tokyo, Japan
+ * erik@sra.co.jp
+ */
+/*
+ * Author's addresses:
+ * erik@sra.co.jp
+ * erik%sra.co.jp@uunet.uu.net
+ * erik%sra.co.jp@mcvax.uucp
+ * try junet instead of co.jp
+ * Erik M. van der Poel
+ * Software Research Associates, Inc.
+ * 1-1-1 Hirakawa-cho, Chiyoda-ku
+ * Tokyo 102 Japan. TEL +81-3-234-2692
+ */
+
+/*
+ * Heavely modified for Vim by Bram Moolenaar
+ */
+
+#include "vim.h"
+
+/* Only include this when using the file browser */
+
+#ifdef FEAT_BROWSE
+
+/* Weird complication: for "make lint" Text.h doesn't combine with Xm.h */
+#if defined(FEAT_GUI_MOTIF) && defined(FMT8BIT)
+# undef FMT8BIT
+#endif
+
+#ifndef FEAT_GUI_NEXTAW
+# include "gui_at_sb.h"
+#endif
+
+/***************** SFinternal.h */
+
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include <X11/Xos.h>
+#ifdef FEAT_GUI_NEXTAW
+# include <X11/neXtaw/Text.h>
+# include <X11/neXtaw/AsciiText.h>
+# include <X11/neXtaw/Scrollbar.h>
+#else
+# include <X11/Xaw/Text.h>
+# include <X11/Xaw/AsciiText.h>
+#endif
+
+#define SEL_FILE_CANCEL -1
+#define SEL_FILE_OK 0
+#define SEL_FILE_NULL 1
+#define SEL_FILE_TEXT 2
+
+#define SF_DO_SCROLL 1
+#define SF_DO_NOT_SCROLL 0
+
+typedef struct
+{
+ int statDone;
+ char *real;
+ char *shown;
+} SFEntry;
+
+typedef struct
+{
+ char *dir;
+ char *path;
+ SFEntry *entries;
+ int nEntries;
+ int vOrigin;
+ int nChars;
+ int hOrigin;
+ int changed;
+ int beginSelection;
+ int endSelection;
+ time_t mtime;
+} SFDir;
+
+static char SFstartDir[MAXPATHL],
+ SFcurrentPath[MAXPATHL],
+ SFcurrentDir[MAXPATHL];
+
+static Widget selFile,
+ selFileField,
+ selFileForm,
+ selFileHScroll,
+ selFileHScrolls[3],
+ selFileLists[3],
+ selFileOK,
+ selFileCancel,
+ selFilePrompt,
+ selFileVScrolls[3];
+
+static Display *SFdisplay;
+
+static int SFcharWidth, SFcharAscent, SFcharHeight;
+
+static SFDir *SFdirs = NULL;
+
+static int SFdirEnd;
+static int SFdirPtr;
+
+static Pixel SFfore, SFback;
+
+static Atom SFwmDeleteWindow;
+
+static XSegment SFsegs[2], SFcompletionSegs[2];
+
+static XawTextPosition SFtextPos;
+
+static int SFupperX, SFlowerY, SFupperY;
+
+static int SFtextX, SFtextYoffset;
+
+static int SFentryWidth, SFentryHeight;
+
+static int SFlineToTextH = 3;
+static int SFlineToTextV = 3;
+
+static int SFbesideText = 3;
+static int SFaboveAndBelowText = 2;
+
+static int SFcharsPerEntry = 15;
+
+static int SFlistSize = 10;
+
+static int SFcurrentInvert[3] = { -1, -1, -1 };
+
+static int SFworkProcAdded = 0;
+
+static XtAppContext SFapp;
+
+static int SFpathScrollWidth, SFvScrollHeight, SFhScrollWidth;
+
+#ifdef FEAT_XFONTSET
+static char SFtextBuffer[MAXPATHL*sizeof(wchar_t)];
+#else
+static char SFtextBuffer[MAXPATHL];
+#endif
+
+static int SFbuttonPressed = 0;
+
+static XtIntervalId SFdirModTimerId;
+
+static int (*SFfunc)();
+
+static int SFstatus = SEL_FILE_NULL;
+
+/***************** forward declare static functions */
+
+static void SFsetText(char *path);
+static void SFtextChanged(void);
+static int SFgetDir(SFDir *dir);
+static void SFdrawLists(int doScroll);
+static void SFdrawList(int n, int doScroll);
+static void SFclearList(int n, int doScroll);
+static char SFstatChar(stat_T *statBuf);
+static void SFmotionList(Widget w, int n, XMotionEvent *event);
+static void SFvSliderMovedCallback(Widget w, int n, int nw);
+static Boolean SFworkProc(void);
+static int SFcompareEntries(const void *p, const void *q);
+
+/***************** xstat.h */
+
+#ifndef S_IXUSR
+# define S_IXUSR 0100
+#endif
+#ifndef S_IXGRP
+# define S_IXGRP 0010
+#endif
+#ifndef S_IXOTH
+# define S_IXOTH 0001
+#endif
+
+#define S_ISXXX(m) ((m) & (S_IXUSR | S_IXGRP | S_IXOTH))
+
+/***************** Path.c */
+
+#include <pwd.h>
+
+typedef struct
+{
+ char *name;
+ char *dir;
+} SFLogin;
+
+static int SFdoNotTouchDirPtr = 0;
+
+static int SFdoNotTouchVorigin = 0;
+
+static SFDir SFrootDir, SFhomeDir;
+
+static SFLogin *SFlogins;
+
+static int SFtwiddle = 0;
+
+ static int
+SFchdir(char *path)
+{
+ int result;
+
+ result = 0;
+
+ if (strcmp(path, SFcurrentDir))
+ {
+ result = mch_chdir(path);
+ if (!result)
+ (void) strcpy(SFcurrentDir, path);
+ }
+
+ return result;
+}
+
+ static void
+SFfree(int i)
+{
+ SFDir *dir;
+ int j;
+
+ dir = &(SFdirs[i]);
+
+ for (j = dir->nEntries - 1; j >= 0; j--)
+ {
+ if (dir->entries[j].shown != dir->entries[j].real)
+ XtFree(dir->entries[j].shown);
+ XtFree(dir->entries[j].real);
+ }
+
+ XtFree((char *)dir->entries);
+ XtFree(dir->dir);
+
+ dir->dir = NULL;
+}
+
+ static void
+SFstrdup(char **s1, char *s2)
+{
+ *s1 = strcpy(XtMalloc((unsigned)(strlen(s2) + 1)), s2);
+}
+
+ static void
+SFunreadableDir(SFDir *dir)
+{
+ char *cannotOpen = _("<cannot open> ");
+
+ dir->entries = (SFEntry *) XtMalloc(sizeof(SFEntry));
+ dir->entries[0].statDone = 1;
+ SFstrdup(&dir->entries[0].real, cannotOpen);
+ dir->entries[0].shown = dir->entries[0].real;
+ dir->nEntries = 1;
+ dir->nChars = strlen(cannotOpen);
+}
+
+ static void
+SFreplaceText(SFDir *dir, char *str)
+{
+ int len;
+
+ *(dir->path) = 0;
+ len = strlen(str);
+ if (str[len - 1] == '/')
+ (void) strcat(SFcurrentPath, str);
+ else
+ (void) strncat(SFcurrentPath, str, len - 1);
+ if (strncmp(SFcurrentPath, SFstartDir, strlen(SFstartDir)))
+ SFsetText(SFcurrentPath);
+ else
+ SFsetText(&(SFcurrentPath[strlen(SFstartDir)]));
+
+ SFtextChanged();
+}
+
+ static void
+SFexpand(char *str)
+{
+ int len;
+ int cmp;
+ char *name, *growing;
+ SFDir *dir;
+ SFEntry *entry, *max;
+
+ len = strlen(str);
+
+ dir = &(SFdirs[SFdirEnd - 1]);
+
+ if (dir->beginSelection == -1)
+ {
+ SFstrdup(&str, str);
+ SFreplaceText(dir, str);
+ XtFree(str);
+ return;
+ }
+ else if (dir->beginSelection == dir->endSelection)
+ {
+ SFreplaceText(dir, dir->entries[dir->beginSelection].shown);
+ return;
+ }
+
+ max = &(dir->entries[dir->endSelection + 1]);
+
+ name = dir->entries[dir->beginSelection].shown;
+ SFstrdup(&growing, name);
+
+ cmp = 0;
+ while (!cmp)
+ {
+ entry = &(dir->entries[dir->beginSelection]);
+ while (entry < max)
+ {
+ if ((cmp = strncmp(growing, entry->shown, len)))
+ break;
+ entry++;
+ }
+ len++;
+ }
+
+ /*
+ * SFreplaceText() expects filename
+ */
+ growing[len - 2] = ' ';
+
+ growing[len - 1] = 0;
+ SFreplaceText(dir, growing);
+ XtFree(growing);
+}
+
+ static int
+SFfindFile(SFDir *dir, char *str)
+{
+ int i, last, max;
+ char *name, save;
+ SFEntry *entries;
+ int len;
+ int begin, end;
+ int result;
+
+ len = strlen(str);
+
+ if (str[len - 1] == ' ')
+ {
+ SFexpand(str);
+ return 1;
+ }
+ else if (str[len - 1] == '/')
+ len--;
+
+ max = dir->nEntries;
+
+ entries = dir->entries;
+
+ i = 0;
+ while (i < max)
+ {
+ name = entries[i].shown;
+ last = strlen(name) - 1;
+ save = name[last];
+ name[last] = 0;
+
+ result = strncmp(str, name, len);
+
+ name[last] = save;
+ if (result <= 0)
+ break;
+ i++;
+ }
+ begin = i;
+ while (i < max)
+ {
+ name = entries[i].shown;
+ last = strlen(name) - 1;
+ save = name[last];
+ name[last] = 0;
+
+ result = strncmp(str, name, len);
+
+ name[last] = save;
+ if (result)
+ break;
+ i++;
+ }
+ end = i;
+
+ if (begin != end)
+ {
+ if ((dir->beginSelection != begin) || (dir->endSelection != end - 1))
+ {
+ dir->changed = 1;
+ dir->beginSelection = begin;
+ if (str[strlen(str) - 1] == '/')
+ dir->endSelection = begin;
+ else
+ dir->endSelection = end - 1;
+ }
+ }
+ else if (dir->beginSelection != -1)
+ {
+ dir->changed = 1;
+ dir->beginSelection = -1;
+ dir->endSelection = -1;
+ }
+
+ if (SFdoNotTouchVorigin
+ || ((begin > dir->vOrigin) && (end < dir->vOrigin + SFlistSize)))
+ {
+ SFdoNotTouchVorigin = 0;
+ return 0;
+ }
+
+ i = begin - 1;
+ if (i > max - SFlistSize)
+ i = max - SFlistSize;
+ if (i < 0)
+ i = 0;
+
+ if (dir->vOrigin != i)
+ {
+ dir->vOrigin = i;
+ dir->changed = 1;
+ }
+
+ return 0;
+}
+
+ static void
+SFunselect(void)
+{
+ SFDir *dir;
+
+ dir = &(SFdirs[SFdirEnd - 1]);
+ if (dir->beginSelection != -1)
+ dir->changed = 1;
+ dir->beginSelection = -1;
+ dir->endSelection = -1;
+}
+
+ static int
+SFcompareLogins(const void *p, const void *q)
+{
+ return strcmp(((SFLogin *)p)->name, ((SFLogin *)q)->name);
+}
+
+ static void
+SFgetHomeDirs(void)
+{
+ struct passwd *pw;
+ int Alloc;
+ int i;
+ SFEntry *entries = NULL;
+ int len;
+ int maxChars;
+
+ Alloc = 1;
+ i = 1;
+ entries = (SFEntry *)XtMalloc(sizeof(SFEntry));
+ SFlogins = (SFLogin *)XtMalloc(sizeof(SFLogin));
+ entries[0].real = XtMalloc(3);
+ (void) strcpy(entries[0].real, "~");
+ entries[0].shown = entries[0].real;
+ entries[0].statDone = 1;
+ SFlogins[0].name = "";
+ pw = getpwuid((int) getuid());
+ SFstrdup(&SFlogins[0].dir, pw ? pw->pw_dir : "/");
+ maxChars = 0;
+
+ (void) setpwent();
+
+ while ((pw = getpwent()) && (*(pw->pw_name)))
+ {
+ if (i >= Alloc)
+ {
+ Alloc *= 2;
+ entries = (SFEntry *) XtRealloc((char *)entries,
+ (unsigned)(Alloc * sizeof(SFEntry)));
+ SFlogins = (SFLogin *) XtRealloc((char *)SFlogins,
+ (unsigned)(Alloc * sizeof(SFLogin)));
+ }
+ len = strlen(pw->pw_name);
+ entries[i].real = XtMalloc((unsigned) (len + 3));
+ (void) strcat(strcpy(entries[i].real, "~"), pw->pw_name);
+ entries[i].shown = entries[i].real;
+ entries[i].statDone = 1;
+ if (len > maxChars)
+ maxChars = len;
+ SFstrdup(&SFlogins[i].name, pw->pw_name);
+ SFstrdup(&SFlogins[i].dir, pw->pw_dir);
+ i++;
+ }
+
+ SFhomeDir.dir = XtMalloc(1);
+ SFhomeDir.dir[0] = 0;
+ SFhomeDir.path = SFcurrentPath;
+ SFhomeDir.entries = entries;
+ SFhomeDir.nEntries = i;
+ SFhomeDir.vOrigin = 0; /* :-) */
+ SFhomeDir.nChars = maxChars + 2;
+ SFhomeDir.hOrigin = 0;
+ SFhomeDir.changed = 1;
+ SFhomeDir.beginSelection = -1;
+ SFhomeDir.endSelection = -1;
+
+ qsort((char *)entries, (size_t)i, sizeof(SFEntry), SFcompareEntries);
+ qsort((char *)SFlogins, (size_t)i, sizeof(SFLogin), SFcompareLogins);
+
+ for (i--; i >= 0; i--)
+ (void)strcat(entries[i].real, "/");
+}
+
+ static int
+SFfindHomeDir(char *begin, char *end)
+{
+ char save;
+ char *theRest;
+ int i;
+
+ save = *end;
+ *end = 0;
+
+ for (i = SFhomeDir.nEntries - 1; i >= 0; i--)
+ {
+ if (!strcmp(SFhomeDir.entries[i].real, begin))
+ {
+ *end = save;
+ SFstrdup(&theRest, end);
+ (void) strcat(strcat(strcpy(SFcurrentPath,
+ SFlogins[i].dir), "/"), theRest);
+ XtFree(theRest);
+ SFsetText(SFcurrentPath);
+ SFtextChanged();
+ return 1;
+ }
+ }
+
+ *end = save;
+
+ return 0;
+}
+
+ static void
+SFupdatePath(void)
+{
+ static int Alloc;
+ static int wasTwiddle = 0;
+ char *begin, *end;
+ int i, j;
+ int prevChange;
+ int SFdirPtrSave, SFdirEndSave;
+ SFDir *dir;
+
+ if (!SFdirs)
+ {
+ SFdirs = (SFDir *) XtMalloc((Alloc = 10) * sizeof(SFDir));
+ dir = &(SFdirs[0]);
+ SFstrdup(&dir->dir, "/");
+ (void) SFchdir("/");
+ (void) SFgetDir(dir);
+ for (j = 1; j < Alloc; j++)
+ SFdirs[j].dir = NULL;
+ dir->path = SFcurrentPath + 1;
+ dir->vOrigin = 0;
+ dir->hOrigin = 0;
+ dir->changed = 1;
+ dir->beginSelection = -1;
+ dir->endSelection = -1;
+ SFhomeDir.dir = NULL;
+ }
+
+ SFdirEndSave = SFdirEnd;
+ SFdirEnd = 1;
+
+ SFdirPtrSave = SFdirPtr;
+ SFdirPtr = 0;
+
+ begin = NULL;
+
+ if (SFcurrentPath[0] == '~')
+ {
+ if (!SFtwiddle)
+ {
+ SFtwiddle = 1;
+ dir = &(SFdirs[0]);
+ SFrootDir = *dir;
+ if (!SFhomeDir.dir)
+ SFgetHomeDirs();
+ *dir = SFhomeDir;
+ dir->changed = 1;
+ }
+ end = SFcurrentPath;
+ SFdoNotTouchDirPtr = 1;
+ wasTwiddle = 1;
+ }
+ else
+ {
+ if (SFtwiddle)
+ {
+ SFtwiddle = 0;
+ dir = &(SFdirs[0]);
+ *dir = SFrootDir;
+ dir->changed = 1;
+ }
+ end = SFcurrentPath + 1;
+ }
+
+ i = 0;
+
+ prevChange = 0;
+
+ while (*end)
+ {
+ while (*end++ == '/')
+ ;
+ end--;
+ begin = end;
+ while ((*end) && (*end++ != '/'))
+ ;
+ if ((end - SFcurrentPath <= SFtextPos) && (*(end - 1) == '/'))
+ {
+ SFdirPtr = i - 1;
+ if (SFdirPtr < 0)
+ SFdirPtr = 0;
+ }
+ if (*begin)
+ {
+ if (*(end - 1) == '/')
+ {
+ char save = *end;
+
+ if (SFtwiddle)
+ {
+ if (SFfindHomeDir(begin, end))
+ return;
+ }
+ *end = 0;
+ i++;
+ SFdirEnd++;
+ if (i >= Alloc)
+ {
+ SFdirs = (SFDir *) XtRealloc((char *) SFdirs,
+ (unsigned)((Alloc *= 2) * sizeof(SFDir)));
+ for (j = Alloc / 2; j < Alloc; j++)
+ SFdirs[j].dir = NULL;
+ }
+ dir = &(SFdirs[i]);
+ if ((!(dir->dir)) || prevChange || strcmp(dir->dir, begin))
+ {
+ if (dir->dir)
+ SFfree(i);
+ prevChange = 1;
+ SFstrdup(&dir->dir, begin);
+ dir->path = end;
+ dir->vOrigin = 0;
+ dir->hOrigin = 0;
+ dir->changed = 1;
+ dir->beginSelection = -1;
+ dir->endSelection = -1;
+ (void)SFfindFile(dir - 1, begin);
+ if (SFchdir(SFcurrentPath) || SFgetDir(dir))
+ {
+ SFunreadableDir(dir);
+ break;
+ }
+ }
+ *end = save;
+ if (!save)
+ SFunselect();
+ }
+ else
+ {
+ if (SFfindFile(&(SFdirs[SFdirEnd-1]), begin))
+ return;
+ }
+ }
+ else
+ SFunselect();
+ }
+
+ if ((end == SFcurrentPath + 1) && (!SFtwiddle))
+ SFunselect();
+
+ for (i = SFdirEnd; i < Alloc; i++)
+ if (SFdirs[i].dir)
+ SFfree(i);
+
+ if (SFdoNotTouchDirPtr)
+ {
+ if (wasTwiddle)
+ {
+ wasTwiddle = 0;
+ SFdirPtr = SFdirEnd - 2;
+ if (SFdirPtr < 0)
+ SFdirPtr = 0;
+ }
+ else
+ SFdirPtr = SFdirPtrSave;
+ SFdoNotTouchDirPtr = 0;
+ }
+
+ if ((SFdirPtr != SFdirPtrSave) || (SFdirEnd != SFdirEndSave))
+ {
+#ifdef FEAT_GUI_NEXTAW
+ XawScrollbarSetThumb( selFileHScroll,
+ (float) (((double) SFdirPtr) / SFdirEnd),
+ (float) (((double) ((SFdirEnd < 3) ? SFdirEnd : 3)) /
+ SFdirEnd));
+#else
+ vim_XawScrollbarSetThumb( selFileHScroll,
+ (float) (((double) SFdirPtr) / SFdirEnd),
+ (float) (((double) ((SFdirEnd < 3) ? SFdirEnd : 3)) /
+ SFdirEnd),
+ (double)SFdirEnd);
+#endif
+ }
+
+ if (SFdirPtr != SFdirPtrSave)
+ SFdrawLists(SF_DO_SCROLL);
+ else
+ for (i = 0; i < 3; i++)
+ {
+ if (SFdirPtr + i < SFdirEnd)
+ {
+ if (SFdirs[SFdirPtr + i].changed)
+ {
+ SFdirs[SFdirPtr + i].changed = 0;
+ SFdrawList(i, SF_DO_SCROLL);
+ }
+ }
+ else
+ SFclearList(i, SF_DO_SCROLL);
+ }
+}
+
+#ifdef XtNinternational
+ static int
+WcsLen(wchar_t *p)
+{
+ int i = 0;
+ while (*p++ != 0)
+ i++;
+ return i;
+}
+#endif
+
+ static void
+SFsetText(char *path)
+{
+ XawTextBlock text;
+
+ text.firstPos = 0;
+ text.length = strlen(path);
+ text.ptr = path;
+ text.format = FMT8BIT;
+
+#ifdef XtNinternational
+ if ((unsigned long)_XawTextFormat((TextWidget)selFileField) == XawFmtWide)
+ {
+ XawTextReplace(selFileField, (XawTextPosition)0,
+ (XawTextPosition)WcsLen((wchar_t *)&SFtextBuffer[0]), &text);
+ XawTextSetInsertionPoint(selFileField,
+ (XawTextPosition)WcsLen((wchar_t *)&SFtextBuffer[0]));
+ }
+ else
+ {
+ XawTextReplace(selFileField, (XawTextPosition)0,
+ (XawTextPosition)strlen(SFtextBuffer), &text);
+ XawTextSetInsertionPoint(selFileField,
+ (XawTextPosition)strlen(SFtextBuffer));
+ }
+#else
+ XawTextReplace(selFileField, (XawTextPosition)0,
+ (XawTextPosition)strlen(SFtextBuffer), &text);
+ XawTextSetInsertionPoint(selFileField,
+ (XawTextPosition)strlen(SFtextBuffer));
+#endif
+}
+
+ static void
+SFbuttonPressList(
+ Widget w UNUSED,
+ int n UNUSED,
+ XButtonPressedEvent *event UNUSED)
+{
+ SFbuttonPressed = 1;
+}
+
+ static void
+SFbuttonReleaseList(
+ Widget w,
+ int n,
+ XButtonReleasedEvent *event)
+{
+ SFDir *dir;
+
+ SFbuttonPressed = 0;
+
+ if (SFcurrentInvert[n] != -1)
+ {
+ if (n < 2)
+ SFdoNotTouchDirPtr = 1;
+ SFdoNotTouchVorigin = 1;
+ dir = &(SFdirs[SFdirPtr + n]);
+ SFreplaceText(dir,
+ dir->entries[dir->vOrigin + SFcurrentInvert[n]].shown);
+ SFmotionList(w, n, (XMotionEvent *) event);
+ }
+}
+
+ static int
+SFcheckDir(int n, SFDir *dir)
+{
+ stat_T statBuf;
+ int i;
+
+ if ((!mch_stat(".", &statBuf)) && (statBuf.st_mtime != dir->mtime))
+ {
+ /*
+ * If the pointer is currently in the window that we are about
+ * to update, we must warp it to prevent the user from
+ * accidentally selecting the wrong file.
+ */
+ if (SFcurrentInvert[n] != -1)
+ {
+ XWarpPointer(
+ SFdisplay,
+ None,
+ XtWindow(selFileLists[n]),
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0);
+ }
+
+ for (i = dir->nEntries - 1; i >= 0; i--)
+ {
+ if (dir->entries[i].shown != dir->entries[i].real)
+ XtFree(dir->entries[i].shown);
+ XtFree(dir->entries[i].real);
+ }
+ XtFree((char *) dir->entries);
+ if (SFgetDir(dir))
+ SFunreadableDir(dir);
+ if (dir->vOrigin > dir->nEntries - SFlistSize)
+ dir->vOrigin = dir->nEntries - SFlistSize;
+ if (dir->vOrigin < 0)
+ dir->vOrigin = 0;
+ if (dir->hOrigin > dir->nChars - SFcharsPerEntry)
+ dir->hOrigin = dir->nChars - SFcharsPerEntry;
+ if (dir->hOrigin < 0)
+ dir->hOrigin = 0;
+ dir->beginSelection = -1;
+ dir->endSelection = -1;
+ SFdoNotTouchVorigin = 1;
+ if ((dir + 1)->dir)
+ (void) SFfindFile(dir, (dir + 1)->dir);
+ else
+ (void) SFfindFile(dir, dir->path);
+
+ if (!SFworkProcAdded)
+ {
+ (void) XtAppAddWorkProc(SFapp, (XtWorkProc)SFworkProc, NULL);
+ SFworkProcAdded = 1;
+ }
+ return 1;
+ }
+ return 0;
+}
+
+ static int
+SFcheckFiles(SFDir *dir)
+{
+ int from, to;
+ int result;
+ char oldc, newc;
+ int i;
+ char *str;
+ int last;
+ stat_T statBuf;
+
+ result = 0;
+
+ from = dir->vOrigin;
+ to = dir->vOrigin + SFlistSize;
+ if (to > dir->nEntries)
+ to = dir->nEntries;
+
+ for (i = from; i < to; i++)
+ {
+ str = dir->entries[i].real;
+ last = strlen(str) - 1;
+ oldc = str[last];
+ str[last] = 0;
+ if (mch_stat(str, &statBuf))
+ newc = ' ';
+ else
+ newc = SFstatChar(&statBuf);
+ str[last] = newc;
+ if (newc != oldc)
+ result = 1;
+ }
+
+ return result;
+}
+
+ static void
+SFdirModTimer(XtPointer cl UNUSED, XtIntervalId *id UNUSED)
+{
+ static int n = -1;
+ static int f = 0;
+ char save;
+ SFDir *dir;
+
+ if ((!SFtwiddle) && (SFdirPtr < SFdirEnd))
+ {
+ n++;
+ if ((n > 2) || (SFdirPtr + n >= SFdirEnd))
+ {
+ n = 0;
+ f++;
+ if ((f > 2) || (SFdirPtr + f >= SFdirEnd))
+ f = 0;
+ }
+ dir = &(SFdirs[SFdirPtr + n]);
+ save = *(dir->path);
+ *(dir->path) = 0;
+ if (SFchdir(SFcurrentPath))
+ {
+ *(dir->path) = save;
+
+ /*
+ * force a re-read
+ */
+ *(dir->dir) = 0;
+
+ SFupdatePath();
+ }
+ else
+ {
+ *(dir->path) = save;
+ if (SFcheckDir(n, dir) || ((f == n) && SFcheckFiles(dir)))
+ SFdrawList(n, SF_DO_SCROLL);
+ }
+ }
+
+ SFdirModTimerId = XtAppAddTimeOut(SFapp, (unsigned long) 1000,
+ SFdirModTimer, (XtPointer) NULL);
+}
+
+/* Return a single character describing what kind of file STATBUF is. */
+
+ static char
+SFstatChar(stat_T *statBuf)
+{
+ if (S_ISDIR (statBuf->st_mode))
+ return '/';
+ if (S_ISREG (statBuf->st_mode))
+ return S_ISXXX (statBuf->st_mode) ? '*' : ' ';
+#ifdef S_ISSOCK
+ if (S_ISSOCK (statBuf->st_mode))
+ return '=';
+#endif /* S_ISSOCK */
+ return ' ';
+}
+
+/***************** Draw.c */
+
+#ifdef FEAT_GUI_NEXTAW
+# include <X11/neXtaw/Cardinals.h>
+#else
+# include <X11/Xaw/Cardinals.h>
+#endif
+
+#ifdef FEAT_XFONTSET
+# define SF_DEFAULT_FONT "-misc-fixed-medium-r-normal--14-*"
+#else
+# define SF_DEFAULT_FONT "9x15"
+#endif
+
+#ifdef ABS
+# undef ABS
+#endif
+#define ABS(x) (((x) < 0) ? (-(x)) : (x))
+
+typedef struct
+{
+ char *fontname;
+} TextData;
+
+static GC SFlineGC, SFscrollGC, SFinvertGC, SFtextGC;
+
+static XtResource textResources[] =
+{
+#ifdef FEAT_XFONTSET
+ {XtNfontSet, XtCFontSet, XtRString, sizeof (char *),
+ XtOffsetOf(TextData, fontname), XtRString, SF_DEFAULT_FONT},
+#else
+ {XtNfont, XtCFont, XtRString, sizeof (char *),
+ XtOffsetOf(TextData, fontname), XtRString, SF_DEFAULT_FONT},
+#endif
+};
+
+#ifdef FEAT_XFONTSET
+static XFontSet SFfont;
+#else
+static XFontStruct *SFfont;
+#endif
+
+static int SFcurrentListY;
+
+static XtIntervalId SFscrollTimerId;
+
+ static void
+SFinitFont(void)
+{
+ TextData *data;
+#ifdef FEAT_XFONTSET
+ XFontSetExtents *extents;
+ char **missing, *def_str;
+ int num_missing;
+#endif
+
+ data = XtNew(TextData);
+
+ XtGetApplicationResources(selFileForm, (XtPointer) data, textResources,
+ XtNumber(textResources), (Arg *) NULL, ZERO);
+
+#ifdef FEAT_XFONTSET
+ SFfont = XCreateFontSet(SFdisplay, data->fontname,
+ &missing, &num_missing, &def_str);
+#else
+ SFfont = XLoadQueryFont(SFdisplay, data->fontname);
+#endif
+ if (!SFfont)
+ {
+#ifdef FEAT_XFONTSET
+ SFfont = XCreateFontSet(SFdisplay, SF_DEFAULT_FONT,
+ &missing, &num_missing, &def_str);
+#else
+ SFfont = XLoadQueryFont(SFdisplay, SF_DEFAULT_FONT);
+#endif
+ if (!SFfont)
+ {
+ semsg(_("E616: vim_SelFile: can't get font %s"), SF_DEFAULT_FONT);
+ SFstatus = SEL_FILE_CANCEL;
+ return;
+ }
+ }
+
+#ifdef FEAT_XFONTSET
+ extents = XExtentsOfFontSet(SFfont);
+ SFcharWidth = extents->max_logical_extent.width;
+ SFcharAscent = -extents->max_logical_extent.y;
+ SFcharHeight = extents->max_logical_extent.height;
+#else
+ SFcharWidth = (SFfont->max_bounds.width + SFfont->min_bounds.width) / 2;
+ SFcharAscent = SFfont->max_bounds.ascent;
+ SFcharHeight = SFcharAscent + SFfont->max_bounds.descent;
+#endif
+}
+
+ static void
+SFcreateGC(void)
+{
+ XGCValues gcValues;
+ XRectangle rectangles[1];
+
+ gcValues.foreground = SFfore;
+
+ SFlineGC = XtGetGC(
+ selFileLists[0],
+ (XtGCMask)GCForeground,
+ &gcValues);
+
+ SFscrollGC = XtGetGC(
+ selFileLists[0],
+ (XtGCMask)0,
+ &gcValues);
+
+ gcValues.function = GXxor;
+ gcValues.foreground = SFfore ^ SFback;
+ gcValues.background = SFfore ^ SFback;
+
+ SFinvertGC = XtGetGC(
+ selFileLists[0],
+ (XtGCMask)GCFunction | GCForeground | GCBackground,
+ &gcValues);
+
+ gcValues.foreground = SFfore;
+ gcValues.background = SFback;
+#ifndef FEAT_XFONTSET
+ gcValues.font = SFfont->fid;
+#endif
+
+ SFtextGC = XCreateGC(
+ SFdisplay,
+ XtWindow(selFileLists[0]),
+#ifdef FEAT_XFONTSET
+ (unsigned long)GCForeground | GCBackground,
+#else
+ (unsigned long)GCForeground | GCBackground | GCFont,
+#endif
+ &gcValues);
+
+ rectangles[0].x = SFlineToTextH + SFbesideText;
+ rectangles[0].y = 0;
+ rectangles[0].width = SFcharsPerEntry * SFcharWidth;
+ rectangles[0].height = SFupperY + 1;
+
+ XSetClipRectangles(
+ SFdisplay,
+ SFtextGC,
+ 0,
+ 0,
+ rectangles,
+ 1,
+ Unsorted);
+}
+
+ static void
+SFclearList(int n, int doScroll)
+{
+ SFDir *dir;
+
+ SFcurrentInvert[n] = -1;
+
+ XClearWindow(SFdisplay, XtWindow(selFileLists[n]));
+
+ XDrawSegments(SFdisplay, XtWindow(selFileLists[n]), SFlineGC, SFsegs, 2);
+
+ if (doScroll)
+ {
+ dir = &(SFdirs[SFdirPtr + n]);
+
+ if ((SFdirPtr + n < SFdirEnd) && dir->nEntries && dir->nChars)
+ {
+#ifdef FEAT_GUI_NEXTAW
+ XawScrollbarSetThumb(
+ selFileVScrolls[n],
+ (float) (((double) dir->vOrigin) /
+ dir->nEntries),
+ (float) (((double) ((dir->nEntries < SFlistSize)
+ ? dir->nEntries : SFlistSize)) /
+ dir->nEntries));
+#else
+ vim_XawScrollbarSetThumb(
+ selFileVScrolls[n],
+ (float) (((double) dir->vOrigin) /
+ dir->nEntries),
+ (float) (((double) ((dir->nEntries < SFlistSize)
+ ? dir->nEntries : SFlistSize)) /
+ dir->nEntries),
+ (double)dir->nEntries);
+#endif
+
+#ifdef FEAT_GUI_NEXTAW
+ XawScrollbarSetThumb(
+ selFileHScrolls[n],
+ (float) (((double) dir->hOrigin) / dir->nChars),
+ (float) (((double) ((dir->nChars <
+ SFcharsPerEntry) ? dir->nChars :
+ SFcharsPerEntry)) / dir->nChars));
+#else
+ vim_XawScrollbarSetThumb(
+ selFileHScrolls[n],
+ (float) (((double) dir->hOrigin) / dir->nChars),
+ (float) (((double) ((dir->nChars <
+ SFcharsPerEntry) ? dir->nChars :
+ SFcharsPerEntry)) / dir->nChars),
+ (double)dir->nChars);
+#endif
+ }
+ else
+ {
+#ifdef FEAT_GUI_NEXTAW
+ XawScrollbarSetThumb(selFileVScrolls[n], (float) 0.0,
+ (float) 1.0);
+#else
+ vim_XawScrollbarSetThumb(selFileVScrolls[n], (float) 0.0,
+ (float) 1.0, 1.0);
+#endif
+#ifdef FEAT_GUI_NEXTAW
+ XawScrollbarSetThumb(selFileHScrolls[n], (float) 0.0,
+ (float) 1.0);
+#else
+ vim_XawScrollbarSetThumb(selFileHScrolls[n], (float) 0.0,
+ (float) 1.0, 1.0);
+#endif
+ }
+ }
+}
+
+ static void
+SFdeleteEntry(SFDir *dir, SFEntry *entry)
+{
+ SFEntry *e;
+ SFEntry *end;
+ int n;
+ int idx;
+
+ idx = entry - dir->entries;
+
+ if (idx < dir->beginSelection)
+ dir->beginSelection--;
+ if (idx <= dir->endSelection)
+ dir->endSelection--;
+ if (dir->beginSelection > dir->endSelection)
+ dir->beginSelection = dir->endSelection = -1;
+
+ if (idx < dir->vOrigin)
+ dir->vOrigin--;
+
+ XtFree(entry->real);
+
+ end = &(dir->entries[dir->nEntries - 1]);
+
+ for (e = entry; e < end; e++)
+ *e = *(e + 1);
+
+ if (!(--dir->nEntries))
+ return;
+
+ n = dir - &(SFdirs[SFdirPtr]);
+ if ((n < 0) || (n > 2))
+ return;
+
+#ifdef FEAT_GUI_NEXTAW
+ XawScrollbarSetThumb(
+ selFileVScrolls[n],
+ (float) (((double) dir->vOrigin) / dir->nEntries),
+ (float) (((double) ((dir->nEntries < SFlistSize) ?
+ dir->nEntries : SFlistSize)) / dir->nEntries));
+#else
+ vim_XawScrollbarSetThumb(
+ selFileVScrolls[n],
+ (float) (((double) dir->vOrigin) / dir->nEntries),
+ (float) (((double) ((dir->nEntries < SFlistSize) ?
+ dir->nEntries : SFlistSize)) / dir->nEntries),
+ (double)dir->nEntries);
+#endif
+}
+
+ static void
+SFwriteStatChar(
+ char *name,
+ int last,
+ stat_T *statBuf)
+{
+ name[last] = SFstatChar(statBuf);
+}
+
+ static int
+SFstatAndCheck(SFDir *dir, SFEntry *entry)
+{
+ stat_T statBuf;
+ char save;
+ int last;
+
+ /*
+ * must be restored before returning
+ */
+ save = *(dir->path);
+ *(dir->path) = 0;
+
+ if (!SFchdir(SFcurrentPath))
+ {
+ last = strlen(entry->real) - 1;
+ entry->real[last] = 0;
+ entry->statDone = 1;
+ if ((!mch_stat(entry->real, &statBuf))
+#ifdef S_IFLNK
+ || (!mch_lstat(entry->real, &statBuf))
+#endif
+ )
+ {
+ if (SFfunc)
+ {
+ char *shown;
+
+ shown = NULL;
+ if (SFfunc(entry->real, &shown, &statBuf))
+ {
+ if (shown)
+ {
+ int len;
+
+ len = strlen(shown);
+ entry->shown = XtMalloc((unsigned) (len + 2));
+ (void) strcpy(entry->shown, shown);
+ SFwriteStatChar(entry->shown, len, &statBuf);
+ entry->shown[len + 1] = 0;
+ }
+ }
+ else
+ {
+ SFdeleteEntry(dir, entry);
+
+ *(dir->path) = save;
+ return 1;
+ }
+ }
+ SFwriteStatChar(entry->real, last, &statBuf);
+ }
+ else
+ entry->real[last] = ' ';
+ }
+
+ *(dir->path) = save;
+ return 0;
+}
+
+
+ static void
+SFdrawStrings(
+ Window w,
+ SFDir *dir,
+ int from,
+ int to)
+{
+ int i;
+ SFEntry *entry;
+ int x;
+
+ x = SFtextX - dir->hOrigin * SFcharWidth;
+
+ if (dir->vOrigin + to >= dir->nEntries)
+ to = dir->nEntries - dir->vOrigin - 1;
+ for (i = from; i <= to; i++)
+ {
+ entry = &(dir->entries[dir->vOrigin + i]);
+ if (!(entry->statDone))
+ {
+ if (SFstatAndCheck(dir, entry))
+ {
+ if (dir->vOrigin + to >= dir->nEntries)
+ to = dir->nEntries - dir->vOrigin - 1;
+ i--;
+ continue;
+ }
+ }
+#ifdef FEAT_XFONTSET
+ XmbDrawImageString(
+ SFdisplay,
+ w,
+ SFfont,
+ SFtextGC,
+ x,
+ SFtextYoffset + i * SFentryHeight,
+ entry->shown,
+ strlen(entry->shown));
+#else
+ XDrawImageString(
+ SFdisplay,
+ w,
+ SFtextGC,
+ x,
+ SFtextYoffset + i * SFentryHeight,
+ entry->shown,
+ strlen(entry->shown));
+#endif
+ if (dir->vOrigin + i == dir->beginSelection)
+ {
+ XDrawLine(
+ SFdisplay,
+ w,
+ SFlineGC,
+ SFlineToTextH + 1,
+ SFlowerY + i * SFentryHeight,
+ SFlineToTextH + SFentryWidth - 2,
+ SFlowerY + i * SFentryHeight);
+ }
+ if ((dir->vOrigin + i >= dir->beginSelection) &&
+ (dir->vOrigin + i <= dir->endSelection))
+ {
+ SFcompletionSegs[0].y1 = SFcompletionSegs[1].y1 =
+ SFlowerY + i * SFentryHeight;
+ SFcompletionSegs[0].y2 = SFcompletionSegs[1].y2 =
+ SFlowerY + (i + 1) * SFentryHeight - 1;
+ XDrawSegments(
+ SFdisplay,
+ w,
+ SFlineGC,
+ SFcompletionSegs,
+ 2);
+ }
+ if (dir->vOrigin + i == dir->endSelection)
+ {
+ XDrawLine(
+ SFdisplay,
+ w,
+ SFlineGC,
+ SFlineToTextH + 1,
+ SFlowerY + (i + 1) * SFentryHeight - 1,
+ SFlineToTextH + SFentryWidth - 2,
+ SFlowerY + (i + 1) * SFentryHeight - 1);
+ }
+ }
+}
+
+ static void
+SFdrawList(int n, int doScroll)
+{
+ SFDir *dir;
+ Window w;
+
+ SFclearList(n, doScroll);
+
+ if (SFdirPtr + n < SFdirEnd)
+ {
+ dir = &(SFdirs[SFdirPtr + n]);
+ w = XtWindow(selFileLists[n]);
+#ifdef FEAT_XFONTSET
+ XmbDrawImageString(
+ SFdisplay,
+ w,
+ SFfont,
+ SFtextGC,
+ SFtextX - dir->hOrigin * SFcharWidth,
+ SFlineToTextV + SFaboveAndBelowText + SFcharAscent,
+ dir->dir,
+ strlen(dir->dir));
+#else
+ XDrawImageString(
+ SFdisplay,
+ w,
+ SFtextGC,
+ SFtextX - dir->hOrigin * SFcharWidth,
+ SFlineToTextV + SFaboveAndBelowText + SFcharAscent,
+ dir->dir,
+ strlen(dir->dir));
+#endif
+ SFdrawStrings(w, dir, 0, SFlistSize - 1);
+ }
+}
+
+ static void
+SFdrawLists(int doScroll)
+{
+ int i;
+
+ for (i = 0; i < 3; i++)
+ SFdrawList(i, doScroll);
+}
+
+ static void
+SFinvertEntry(int n)
+{
+ XFillRectangle(
+ SFdisplay,
+ XtWindow(selFileLists[n]),
+ SFinvertGC,
+ SFlineToTextH,
+ SFcurrentInvert[n] * SFentryHeight + SFlowerY,
+ SFentryWidth,
+ SFentryHeight);
+}
+
+ static unsigned long
+SFscrollTimerInterval(void)
+{
+ static int maxVal = 200;
+ static int varyDist = 50;
+ static int minDist = 50;
+ int t;
+ int dist;
+
+ if (SFcurrentListY < SFlowerY)
+ dist = SFlowerY - SFcurrentListY;
+ else if (SFcurrentListY > SFupperY)
+ dist = SFcurrentListY - SFupperY;
+ else
+ return (unsigned long) 1;
+
+ t = maxVal - ((maxVal / varyDist) * (dist - minDist));
+
+ if (t < 1)
+ t = 1;
+
+ if (t > maxVal)
+ t = maxVal;
+
+ return (unsigned long)t;
+}
+
+ static void
+SFscrollTimer(XtPointer p, XtIntervalId *id UNUSED)
+{
+ SFDir *dir;
+ int save;
+ int n;
+
+ n = (long)p;
+
+ dir = &(SFdirs[SFdirPtr + n]);
+ save = dir->vOrigin;
+
+ if (SFcurrentListY < SFlowerY)
+ {
+ if (dir->vOrigin > 0)
+ SFvSliderMovedCallback(selFileVScrolls[n], n, dir->vOrigin - 1);
+ }
+ else if (SFcurrentListY > SFupperY)
+ {
+ if (dir->vOrigin < dir->nEntries - SFlistSize)
+ SFvSliderMovedCallback(selFileVScrolls[n], n, dir->vOrigin + 1);
+ }
+
+ if (dir->vOrigin != save)
+ {
+ if (dir->nEntries)
+ {
+#ifdef FEAT_GUI_NEXTAW
+ XawScrollbarSetThumb(
+ selFileVScrolls[n],
+ (float) (((double) dir->vOrigin) / dir->nEntries),
+ (float) (((double) ((dir->nEntries < SFlistSize) ?
+ dir->nEntries : SFlistSize)) / dir->nEntries));
+#else
+ vim_XawScrollbarSetThumb(
+ selFileVScrolls[n],
+ (float) (((double) dir->vOrigin) / dir->nEntries),
+ (float) (((double) ((dir->nEntries < SFlistSize) ?
+ dir->nEntries : SFlistSize)) / dir->nEntries),
+ (double)dir->nEntries);
+#endif
+ }
+ }
+
+ if (SFbuttonPressed)
+ SFscrollTimerId = XtAppAddTimeOut(SFapp,
+ SFscrollTimerInterval(), SFscrollTimer,
+ (XtPointer)(long_u)n);
+}
+
+ static int
+SFnewInvertEntry(int n, XMotionEvent *event)
+{
+ int x, y;
+ int nw;
+ static int SFscrollTimerAdded = 0;
+
+ x = event->x;
+ y = event->y;
+
+ if (SFdirPtr + n >= SFdirEnd)
+ return -1;
+
+ if ((x >= 0) && (x <= SFupperX) && (y >= SFlowerY) && (y <= SFupperY))
+ {
+ SFDir *dir = &(SFdirs[SFdirPtr + n]);
+
+ if (SFscrollTimerAdded)
+ {
+ SFscrollTimerAdded = 0;
+ XtRemoveTimeOut(SFscrollTimerId);
+ }
+
+ nw = (y - SFlowerY) / SFentryHeight;
+ if (dir->vOrigin + nw >= dir->nEntries)
+ return -1;
+ return nw;
+ }
+ else
+ {
+ if (SFbuttonPressed)
+ {
+ SFcurrentListY = y;
+ if (!SFscrollTimerAdded)
+ {
+ SFscrollTimerAdded = 1;
+ SFscrollTimerId = XtAppAddTimeOut(SFapp,
+ SFscrollTimerInterval(), SFscrollTimer,
+ (XtPointer)(long_u)n);
+ }
+ }
+ return -1;
+ }
+}
+
+ static void
+SFenterList(Widget w UNUSED, int n, XEnterWindowEvent *event)
+{
+ int nw;
+
+ /* sanity */
+ if (SFcurrentInvert[n] != -1)
+ {
+ SFinvertEntry(n);
+ SFcurrentInvert[n] = -1;
+ }
+
+ nw = SFnewInvertEntry(n, (XMotionEvent *) event);
+ if (nw != -1)
+ {
+ SFcurrentInvert[n] = nw;
+ SFinvertEntry(n);
+ }
+}
+
+ static void
+SFleaveList(Widget w UNUSED, int n, XEvent *event UNUSED)
+{
+ if (SFcurrentInvert[n] != -1)
+ {
+ SFinvertEntry(n);
+ SFcurrentInvert[n] = -1;
+ }
+}
+
+ static void
+SFmotionList(Widget w UNUSED, int n, XMotionEvent *event)
+{
+ int nw;
+
+ nw = SFnewInvertEntry(n, event);
+
+ if (nw != SFcurrentInvert[n])
+ {
+ if (SFcurrentInvert[n] != -1)
+ SFinvertEntry(n);
+ SFcurrentInvert[n] = nw;
+ if (nw != -1)
+ SFinvertEntry(n);
+ }
+}
+
+ static void
+SFvFloatSliderMovedCallback(Widget w, XtPointer n, XtPointer fnew)
+{
+ int nw;
+
+ nw = (*(float *)fnew) * SFdirs[SFdirPtr + (int)(long)n].nEntries;
+ SFvSliderMovedCallback(w, (int)(long)n, nw);
+}
+
+ static void
+SFvSliderMovedCallback(Widget w UNUSED, int n, int nw)
+{
+ int old;
+ Window win;
+ SFDir *dir;
+
+ dir = &(SFdirs[SFdirPtr + n]);
+
+ old = dir->vOrigin;
+ dir->vOrigin = nw;
+
+ if (old == nw)
+ return;
+
+ win = XtWindow(selFileLists[n]);
+
+ if (ABS(nw - old) < SFlistSize)
+ {
+ if (nw > old)
+ {
+ XCopyArea(
+ SFdisplay,
+ win,
+ win,
+ SFscrollGC,
+ SFlineToTextH,
+ SFlowerY + (nw - old) * SFentryHeight,
+ SFentryWidth + SFlineToTextH,
+ (SFlistSize - (nw - old)) * SFentryHeight,
+ SFlineToTextH,
+ SFlowerY);
+ XClearArea(
+ SFdisplay,
+ win,
+ SFlineToTextH,
+ SFlowerY + (SFlistSize - (nw - old)) *
+ SFentryHeight,
+ SFentryWidth + SFlineToTextH,
+ (nw - old) * SFentryHeight,
+ False);
+ SFdrawStrings(win, dir, SFlistSize - (nw - old),
+ SFlistSize - 1);
+ }
+ else
+ {
+ XCopyArea(
+ SFdisplay,
+ win,
+ win,
+ SFscrollGC,
+ SFlineToTextH,
+ SFlowerY,
+ SFentryWidth + SFlineToTextH,
+ (SFlistSize - (old - nw)) * SFentryHeight,
+ SFlineToTextH,
+ SFlowerY + (old - nw) * SFentryHeight);
+ XClearArea(
+ SFdisplay,
+ win,
+ SFlineToTextH,
+ SFlowerY,
+ SFentryWidth + SFlineToTextH,
+ (old - nw) * SFentryHeight,
+ False);
+ SFdrawStrings(win, dir, 0, old - nw);
+ }
+ }
+ else
+ {
+ XClearArea(
+ SFdisplay,
+ win,
+ SFlineToTextH,
+ SFlowerY,
+ SFentryWidth + SFlineToTextH,
+ SFlistSize * SFentryHeight,
+ False);
+ SFdrawStrings(win, dir, 0, SFlistSize - 1);
+ }
+}
+
+ static void
+SFvAreaSelectedCallback(Widget w, XtPointer n, XtPointer pnew)
+{
+ SFDir *dir;
+ int nw = (int)(long)pnew;
+
+ dir = &(SFdirs[SFdirPtr + (int)(long)n]);
+
+#ifdef FEAT_GUI_NEXTAW
+ if (nw < 0)
+ {
+ if (nw > -SFvScrollHeight)
+ nw = -1;
+ else
+ nw = -SFlistSize;
+ }
+ else if (nw > 0)
+ {
+ if (nw < SFvScrollHeight)
+ nw = 1;
+ else
+ nw = SFlistSize;
+ }
+#endif
+ nw += dir->vOrigin;
+
+ if (nw > dir->nEntries - SFlistSize)
+ nw = dir->nEntries - SFlistSize;
+
+ if (nw < 0)
+ nw = 0;
+
+ if (dir->nEntries)
+ {
+ float f;
+
+ f = ((double) nw) / dir->nEntries;
+
+#ifdef FEAT_GUI_NEXTAW
+ XawScrollbarSetThumb(
+ w,
+ f,
+ (float) (((double) ((dir->nEntries < SFlistSize) ?
+ dir->nEntries : SFlistSize)) / dir->nEntries));
+#else
+ vim_XawScrollbarSetThumb(
+ w,
+ f,
+ (float) (((double) ((dir->nEntries < SFlistSize) ?
+ dir->nEntries : SFlistSize)) / dir->nEntries),
+ (double)dir->nEntries);
+#endif
+ }
+
+ SFvSliderMovedCallback(w, (int)(long)n, nw);
+}
+
+ static void
+SFhSliderMovedCallback(Widget w UNUSED, XtPointer n, XtPointer nw)
+{
+ SFDir *dir;
+ int save;
+
+ dir = &(SFdirs[SFdirPtr + (int)(long)n]);
+ save = dir->hOrigin;
+ dir->hOrigin = (*(float *)nw) * dir->nChars;
+ if (dir->hOrigin == save)
+ return;
+
+ SFdrawList((int)(long)n, SF_DO_NOT_SCROLL);
+}
+
+ static void
+SFhAreaSelectedCallback(Widget w, XtPointer n, XtPointer pnew)
+{
+ SFDir *dir;
+ int nw = (int)(long)pnew;
+
+ dir = &(SFdirs[SFdirPtr + (int)(long)n]);
+
+#ifdef FEAT_GUI_NEXTAW
+ if (nw < 0)
+ {
+ if (nw > -SFhScrollWidth)
+ nw = -1;
+ else
+ nw = -SFcharsPerEntry;
+ }
+ else if (nw > 0)
+ {
+ if (nw < SFhScrollWidth)
+ nw = 1;
+ else
+ nw = SFcharsPerEntry;
+ }
+#endif
+ nw += dir->hOrigin;
+
+ if (nw > dir->nChars - SFcharsPerEntry)
+ nw = dir->nChars - SFcharsPerEntry;
+
+ if (nw < 0)
+ nw = 0;
+
+ if (dir->nChars)
+ {
+ float f;
+
+ f = ((double) nw) / dir->nChars;
+
+#ifdef FEAT_GUI_NEXTAW
+ XawScrollbarSetThumb(
+ w,
+ f,
+ (float) (((double) ((dir->nChars < SFcharsPerEntry) ?
+ dir->nChars : SFcharsPerEntry)) / dir->nChars));
+#else
+ vim_XawScrollbarSetThumb(
+ w,
+ f,
+ (float) (((double) ((dir->nChars < SFcharsPerEntry) ?
+ dir->nChars : SFcharsPerEntry)) / dir->nChars),
+ (double)dir->nChars);
+#endif
+
+ SFhSliderMovedCallback(w, n, (XtPointer)&f);
+ }
+}
+
+ static void
+SFpathSliderMovedCallback(
+ Widget w UNUSED,
+ XtPointer client_data UNUSED,
+ XtPointer nw)
+{
+ SFDir *dir;
+ int n;
+ XawTextPosition pos;
+ int SFdirPtrSave;
+
+ SFdirPtrSave = SFdirPtr;
+ SFdirPtr = (*(float *)nw) * SFdirEnd;
+ if (SFdirPtr == SFdirPtrSave)
+ return;
+
+ SFdrawLists(SF_DO_SCROLL);
+
+ n = 2;
+ while (SFdirPtr + n >= SFdirEnd)
+ n--;
+
+ dir = &(SFdirs[SFdirPtr + n]);
+
+ pos = dir->path - SFcurrentPath;
+
+ if (!strncmp(SFcurrentPath, SFstartDir, strlen(SFstartDir)))
+ {
+ pos -= strlen(SFstartDir);
+ if (pos < 0)
+ pos = 0;
+ }
+
+ XawTextSetInsertionPoint(selFileField, pos);
+}
+
+ static void
+SFpathAreaSelectedCallback(
+ Widget w,
+ XtPointer client_data UNUSED,
+ XtPointer pnew)
+{
+ int nw = (int)(long)pnew;
+ float f;
+
+#ifdef FEAT_GUI_NEXTAW
+ if (nw < 0)
+ {
+ if (nw > -SFpathScrollWidth)
+ nw = -1;
+ else
+ nw = -3;
+ }
+ else if (nw > 0)
+ {
+ if (nw < SFpathScrollWidth)
+ nw = 1;
+ else
+ nw = 3;
+ }
+#endif
+ nw += SFdirPtr;
+
+ if (nw > SFdirEnd - 3)
+ nw = SFdirEnd - 3;
+
+ if (nw < 0)
+ nw = 0;
+
+ f = ((double) nw) / SFdirEnd;
+
+#ifdef FEAT_GUI_NEXTAW
+ XawScrollbarSetThumb(
+ w,
+ f,
+ (float) (((double) ((SFdirEnd < 3) ? SFdirEnd : 3)) / SFdirEnd));
+#else
+ vim_XawScrollbarSetThumb(
+ w,
+ f,
+ (float) (((double) ((SFdirEnd < 3) ? SFdirEnd : 3)) / SFdirEnd),
+ (double)SFdirEnd);
+#endif
+
+ SFpathSliderMovedCallback(w, (XtPointer) NULL, (XtPointer)&f);
+}
+
+ static Boolean
+SFworkProc(void)
+{
+ SFDir *dir;
+ SFEntry *entry;
+
+ for (dir = &(SFdirs[SFdirEnd - 1]); dir >= SFdirs; dir--)
+ {
+ if (!(dir->nEntries))
+ continue;
+ for (entry = &(dir->entries[dir->nEntries - 1]);
+ entry >= dir->entries;
+ entry--)
+ {
+ if (!(entry->statDone))
+ {
+ (void)SFstatAndCheck(dir, entry);
+ return False;
+ }
+ }
+ }
+
+ SFworkProcAdded = 0;
+
+ return True;
+}
+
+/***************** Dir.c */
+
+ static int
+SFcompareEntries(const void *p, const void *q)
+{
+ return strcmp(((SFEntry *)p)->real, ((SFEntry *)q)->real);
+}
+
+ static int
+SFgetDir(
+ SFDir *dir)
+{
+ SFEntry *result = NULL;
+ int Alloc = 0;
+ int i;
+ DIR *dirp;
+ struct dirent *dp;
+ char *str;
+ int len;
+ int maxChars;
+ stat_T statBuf;
+
+ maxChars = strlen(dir->dir) - 1;
+
+ dir->entries = NULL;
+ dir->nEntries = 0;
+ dir->nChars = 0;
+
+ result = NULL;
+ i = 0;
+
+ dirp = opendir(".");
+ if (!dirp)
+ return 1;
+
+ (void)mch_stat(".", &statBuf);
+ dir->mtime = statBuf.st_mtime;
+
+ while ((dp = readdir(dirp)))
+ {
+ /* Ignore "." and ".." */
+ if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0)
+ continue;
+ if (i >= Alloc)
+ {
+ Alloc = 2 * (Alloc + 1);
+ result = (SFEntry *) XtRealloc((char *) result,
+ (unsigned) (Alloc * sizeof(SFEntry)));
+ }
+ result[i].statDone = 0;
+ str = dp->d_name;
+ len = strlen(str);
+ result[i].real = XtMalloc((unsigned) (len + 2));
+ (void) strcat(strcpy(result[i].real, str), " ");
+ if (len > maxChars)
+ maxChars = len;
+ result[i].shown = result[i].real;
+ i++;
+ }
+
+ qsort((char *) result, (size_t) i, sizeof(SFEntry), SFcompareEntries);
+
+ dir->entries = result;
+ dir->nEntries = i;
+ dir->nChars = maxChars + 1;
+
+ closedir(dirp);
+
+ return 0;
+}
+
+/***************** SFinternal.h */
+
+#include <sys/param.h>
+#include <X11/cursorfont.h>
+#include <X11/Composite.h>
+#include <X11/Shell.h>
+#ifdef FEAT_GUI_NEXTAW
+# include <X11/neXtaw/Form.h>
+# include <X11/neXtaw/Command.h>
+# include <X11/neXtaw/Label.h>
+#else
+#include <X11/Xaw/Form.h>
+#include <X11/Xaw/Command.h>
+#include <X11/Xaw/Label.h>
+#endif
+
+static char *oneLineTextEditTranslations = "\
+ <Key>Return: redraw-display()\n\
+ Ctrl<Key>M: redraw-display()\n\
+";
+
+ static void
+SFexposeList(
+ Widget w UNUSED,
+ XtPointer n,
+ XEvent *event,
+ Boolean *cont UNUSED)
+{
+ if ((event->type == NoExpose) || event->xexpose.count)
+ return;
+
+ SFdrawList((int)(long)n, SF_DO_NOT_SCROLL);
+}
+
+ static void
+SFmodVerifyCallback(
+ Widget w UNUSED,
+ XtPointer client_data UNUSED,
+ XEvent *event,
+ Boolean *cont UNUSED)
+{
+ char buf[2];
+
+ if ((XLookupString(&(event->xkey), buf, 2, NULL, NULL) == 1) &&
+ ((*buf) == '\r'))
+ SFstatus = SEL_FILE_OK;
+ else
+ SFstatus = SEL_FILE_TEXT;
+}
+
+ static void
+SFokCallback(Widget w UNUSED, XtPointer cl UNUSED, XtPointer cd UNUSED)
+{
+ SFstatus = SEL_FILE_OK;
+}
+
+static XtCallbackRec SFokSelect[] =
+{
+ { SFokCallback, (XtPointer) NULL },
+ { NULL, (XtPointer) NULL },
+};
+
+ static void
+SFcancelCallback(Widget w UNUSED, XtPointer cl UNUSED, XtPointer cd UNUSED)
+{
+ SFstatus = SEL_FILE_CANCEL;
+}
+
+static XtCallbackRec SFcancelSelect[] =
+{
+ { SFcancelCallback, (XtPointer) NULL },
+ { NULL, (XtPointer) NULL },
+};
+
+ static void
+SFdismissAction(
+ Widget w UNUSED,
+ XEvent *event,
+ String *params UNUSED,
+ Cardinal *num_params UNUSED)
+{
+ if (event->type == ClientMessage
+ && (Atom)event->xclient.data.l[0] != SFwmDeleteWindow)
+ return;
+
+ SFstatus = SEL_FILE_CANCEL;
+}
+
+static char *wmDeleteWindowTranslation = "\
+ <Message>WM_PROTOCOLS: SelFileDismiss()\n\
+";
+
+static XtActionsRec actions[] =
+{
+ {"SelFileDismiss", SFdismissAction},
+};
+
+ static void
+SFsetColors(
+ guicolor_T bg,
+ guicolor_T fg,
+ guicolor_T scroll_bg,
+ guicolor_T scroll_fg)
+{
+ if (selFileForm)
+ {
+ XtVaSetValues(selFileForm, XtNbackground, bg,
+ XtNforeground, fg,
+ XtNborderColor, bg,
+ NULL);
+ }
+ {
+ int i;
+
+ for (i = 0; i < 3; ++i)
+ {
+ if (selFileLists[i])
+ {
+ XtVaSetValues(selFileLists[i], XtNbackground, bg,
+ XtNforeground, fg,
+ XtNborderColor, fg,
+ NULL);
+ }
+ }
+ }
+ if (selFileOK)
+ {
+ XtVaSetValues(selFileOK, XtNbackground, bg,
+ XtNforeground, fg,
+ XtNborderColor, fg,
+ NULL);
+ }
+ if (selFileCancel)
+ {
+ XtVaSetValues(selFileCancel, XtNbackground, bg,
+ XtNforeground, fg,
+ XtNborderColor, fg,
+ NULL);
+ }
+ if (selFilePrompt)
+ {
+ XtVaSetValues(selFilePrompt, XtNbackground, bg,
+ XtNforeground, fg,
+ NULL);
+ }
+ if (gui.dpy)
+ {
+ XSetBackground(gui.dpy, SFtextGC, bg);
+ XSetForeground(gui.dpy, SFtextGC, fg);
+ XSetForeground(gui.dpy, SFlineGC, fg);
+
+ /* This is an xor GC, so combine the fg and background */
+ XSetBackground(gui.dpy, SFinvertGC, fg ^ bg);
+ XSetForeground(gui.dpy, SFinvertGC, fg ^ bg);
+ }
+ if (selFileHScroll)
+ {
+ XtVaSetValues(selFileHScroll, XtNbackground, scroll_bg,
+ XtNforeground, scroll_fg,
+ XtNborderColor, fg,
+ NULL);
+ }
+ {
+ int i;
+
+ for (i = 0; i < 3; i++)
+ {
+ XtVaSetValues(selFileVScrolls[i], XtNbackground, scroll_bg,
+ XtNforeground, scroll_fg,
+ XtNborderColor, fg,
+ NULL);
+ XtVaSetValues(selFileHScrolls[i], XtNbackground, scroll_bg,
+ XtNforeground, scroll_fg,
+ XtNborderColor, fg,
+ NULL);
+ }
+ }
+}
+
+ static void
+SFcreateWidgets(
+ Widget toplevel,
+ char *prompt,
+ char *ok,
+ char *cancel)
+{
+ Cardinal n;
+ int listWidth, listHeight;
+ int listSpacing = 10;
+ int scrollThickness = 15;
+ int hScrollX, hScrollY;
+ int vScrollX, vScrollY;
+
+ selFile = XtVaAppCreateShell("selFile", "SelFile",
+ transientShellWidgetClass, SFdisplay,
+ XtNtransientFor, toplevel,
+ XtNtitle, prompt,
+ NULL);
+
+ /* Add WM_DELETE_WINDOW protocol */
+ XtAppAddActions(XtWidgetToApplicationContext(selFile),
+ actions, XtNumber(actions));
+ XtOverrideTranslations(selFile,
+ XtParseTranslationTable(wmDeleteWindowTranslation));
+
+ selFileForm = XtVaCreateManagedWidget("selFileForm",
+ formWidgetClass, selFile,
+ XtNdefaultDistance, 30,
+ XtNforeground, SFfore,
+ XtNbackground, SFback,
+ XtNborderColor, SFback,
+ NULL);
+
+ selFilePrompt = XtVaCreateManagedWidget("selFilePrompt",
+ labelWidgetClass, selFileForm,
+ XtNlabel, prompt,
+ XtNresizable, True,
+ XtNtop, XtChainTop,
+ XtNbottom, XtChainTop,
+ XtNleft, XtChainLeft,
+ XtNright, XtChainLeft,
+ XtNborderWidth, 0,
+ XtNforeground, SFfore,
+ XtNbackground, SFback,
+ NULL);
+
+ /*
+ XtVaGetValues(selFilePrompt,
+ XtNforeground, &SFfore,
+ XtNbackground, &SFback,
+ NULL);
+ */
+
+ SFinitFont();
+
+ SFentryWidth = SFbesideText + SFcharsPerEntry * SFcharWidth +
+ SFbesideText;
+ SFentryHeight = SFaboveAndBelowText + SFcharHeight +
+ SFaboveAndBelowText;
+
+ listWidth = SFlineToTextH + SFentryWidth + SFlineToTextH + 1 +
+ scrollThickness;
+ listHeight = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 +
+ SFlineToTextV + SFlistSize * SFentryHeight +
+ SFlineToTextV + 1 + scrollThickness;
+
+ SFpathScrollWidth = 3 * listWidth + 2 * listSpacing + 4;
+
+ hScrollX = -1;
+ hScrollY = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 +
+ SFlineToTextV + SFlistSize * SFentryHeight +
+ SFlineToTextV;
+ SFhScrollWidth = SFlineToTextH + SFentryWidth + SFlineToTextH;
+
+ vScrollX = SFlineToTextH + SFentryWidth + SFlineToTextH;
+ vScrollY = SFlineToTextV + SFentryHeight + SFlineToTextV;
+ SFvScrollHeight = SFlineToTextV + SFlistSize * SFentryHeight +
+ SFlineToTextV;
+
+ SFupperX = SFlineToTextH + SFentryWidth + SFlineToTextH - 1;
+ SFlowerY = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 +
+ SFlineToTextV;
+ SFupperY = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 +
+ SFlineToTextV + SFlistSize * SFentryHeight - 1;
+
+ SFtextX = SFlineToTextH + SFbesideText;
+ SFtextYoffset = SFlowerY + SFaboveAndBelowText + SFcharAscent;
+
+ SFsegs[0].x1 = 0;
+ SFsegs[0].y1 = vScrollY;
+ SFsegs[0].x2 = vScrollX - 1;
+ SFsegs[0].y2 = vScrollY;
+ SFsegs[1].x1 = vScrollX;
+ SFsegs[1].y1 = 0;
+ SFsegs[1].x2 = vScrollX;
+ SFsegs[1].y2 = vScrollY - 1;
+
+ SFcompletionSegs[0].x1 = SFcompletionSegs[0].x2 = SFlineToTextH;
+ SFcompletionSegs[1].x1 = SFcompletionSegs[1].x2 =
+ SFlineToTextH + SFentryWidth - 1;
+
+ selFileField = XtVaCreateManagedWidget("selFileField",
+ asciiTextWidgetClass, selFileForm,
+ XtNwidth, 3 * listWidth + 2 * listSpacing + 4,
+ XtNborderColor, SFfore,
+ XtNfromVert, selFilePrompt,
+ XtNvertDistance, 10,
+ XtNresizable, True,
+ XtNtop, XtChainTop,
+ XtNbottom, XtChainTop,
+ XtNleft, XtChainLeft,
+ XtNright, XtChainLeft,
+ XtNstring, SFtextBuffer,
+ XtNlength, MAXPATHL,
+ XtNeditType, XawtextEdit,
+ XtNwrap, XawtextWrapWord,
+ XtNresize, XawtextResizeHeight,
+ XtNuseStringInPlace, True,
+ NULL);
+
+ XtOverrideTranslations(selFileField,
+ XtParseTranslationTable(oneLineTextEditTranslations));
+ XtSetKeyboardFocus(selFileForm, selFileField);
+
+ selFileHScroll = XtVaCreateManagedWidget("selFileHScroll",
+#ifdef FEAT_GUI_NEXTAW
+ scrollbarWidgetClass, selFileForm,
+#else
+ vim_scrollbarWidgetClass, selFileForm,
+#endif
+ XtNorientation, XtorientHorizontal,
+ XtNwidth, SFpathScrollWidth,
+ XtNheight, scrollThickness,
+ XtNborderColor, SFfore,
+ XtNfromVert, selFileField,
+ XtNvertDistance, 30,
+ XtNtop, XtChainTop,
+ XtNbottom, XtChainTop,
+ XtNleft, XtChainLeft,
+ XtNright, XtChainLeft,
+ XtNforeground, gui.scroll_fg_pixel,
+ XtNbackground, gui.scroll_bg_pixel,
+#ifndef FEAT_GUI_NEXTAW
+ XtNlimitThumb, 1,
+#endif
+ NULL);
+
+ XtAddCallback(selFileHScroll, XtNjumpProc,
+ (XtCallbackProc) SFpathSliderMovedCallback, (XtPointer)NULL);
+ XtAddCallback(selFileHScroll, XtNscrollProc,
+ (XtCallbackProc) SFpathAreaSelectedCallback, (XtPointer)NULL);
+
+ selFileLists[0] = XtVaCreateManagedWidget("selFileList1",
+ compositeWidgetClass, selFileForm,
+ XtNwidth, listWidth,
+ XtNheight, listHeight,
+ XtNforeground, SFfore,
+ XtNbackground, SFback,
+ XtNborderColor, SFfore,
+ XtNfromVert, selFileHScroll,
+ XtNvertDistance, 10,
+ XtNtop, XtChainTop,
+ XtNbottom, XtChainTop,
+ XtNleft, XtChainLeft,
+ XtNright, XtChainLeft,
+ NULL);
+
+ selFileLists[1] = XtVaCreateManagedWidget("selFileList2",
+ compositeWidgetClass, selFileForm,
+ XtNwidth, listWidth,
+ XtNheight, listHeight,
+ XtNforeground, SFfore,
+ XtNbackground, SFback,
+ XtNborderColor, SFfore,
+ XtNfromHoriz, selFileLists[0],
+ XtNfromVert, selFileHScroll,
+ XtNhorizDistance, listSpacing,
+ XtNvertDistance, 10,
+ XtNtop, XtChainTop,
+ XtNbottom, XtChainTop,
+ XtNleft, XtChainLeft,
+ XtNright, XtChainLeft,
+ NULL);
+
+ selFileLists[2] = XtVaCreateManagedWidget("selFileList3",
+ compositeWidgetClass, selFileForm,
+ XtNwidth, listWidth,
+ XtNheight, listHeight,
+ XtNforeground, SFfore,
+ XtNbackground, SFback,
+ XtNborderColor, SFfore,
+ XtNfromHoriz, selFileLists[1],
+ XtNfromVert, selFileHScroll,
+ XtNhorizDistance, listSpacing,
+ XtNvertDistance, 10,
+ XtNtop, XtChainTop,
+ XtNbottom, XtChainTop,
+ XtNleft, XtChainLeft,
+ XtNright, XtChainLeft,
+ NULL);
+
+ for (n = 0; n < 3; n++)
+ {
+ selFileVScrolls[n] = XtVaCreateManagedWidget("selFileVScroll",
+#ifdef FEAT_GUI_NEXTAW
+ scrollbarWidgetClass, selFileLists[n],
+#else
+ vim_scrollbarWidgetClass, selFileLists[n],
+#endif
+ XtNx, vScrollX,
+ XtNy, vScrollY,
+ XtNwidth, scrollThickness,
+ XtNheight, SFvScrollHeight,
+ XtNborderColor, SFfore,
+ XtNforeground, gui.scroll_fg_pixel,
+ XtNbackground, gui.scroll_bg_pixel,
+#ifndef FEAT_GUI_NEXTAW
+ XtNlimitThumb, 1,
+#endif
+ NULL);
+
+ XtAddCallback(selFileVScrolls[n], XtNjumpProc,
+ (XtCallbackProc)SFvFloatSliderMovedCallback,
+ (XtPointer)(long_u)n);
+ XtAddCallback(selFileVScrolls[n], XtNscrollProc,
+ (XtCallbackProc)SFvAreaSelectedCallback, (XtPointer)(long_u)n);
+
+ selFileHScrolls[n] = XtVaCreateManagedWidget("selFileHScroll",
+#ifdef FEAT_GUI_NEXTAW
+ scrollbarWidgetClass, selFileLists[n],
+#else
+ vim_scrollbarWidgetClass, selFileLists[n],
+#endif
+ XtNorientation, XtorientHorizontal,
+ XtNx, hScrollX,
+ XtNy, hScrollY,
+ XtNwidth, SFhScrollWidth,
+ XtNheight, scrollThickness,
+ XtNborderColor, SFfore,
+ XtNforeground, gui.scroll_fg_pixel,
+ XtNbackground, gui.scroll_bg_pixel,
+#ifndef FEAT_GUI_NEXTAW
+ XtNlimitThumb, 1,
+#endif
+ NULL);
+
+ XtAddCallback(selFileHScrolls[n], XtNjumpProc,
+ (XtCallbackProc)SFhSliderMovedCallback,
+ (XtPointer)(long_u)n);
+ XtAddCallback(selFileHScrolls[n], XtNscrollProc,
+ (XtCallbackProc)SFhAreaSelectedCallback, (XtPointer)(long_u)n);
+ }
+
+ selFileOK = XtVaCreateManagedWidget("selFileOK",
+ commandWidgetClass, selFileForm,
+ XtNlabel, ok,
+ XtNresizable, True,
+ XtNcallback, SFokSelect,
+ XtNforeground, SFfore,
+ XtNbackground, SFback,
+ XtNborderColor, SFfore,
+ XtNfromHoriz, selFileLists[0],
+ XtNfromVert, selFileLists[0],
+ XtNvertDistance, 30,
+ XtNtop, XtChainTop,
+ XtNbottom, XtChainTop,
+ XtNleft, XtChainLeft,
+ XtNright, XtChainLeft,
+ NULL);
+
+ selFileCancel = XtVaCreateManagedWidget("selFileCancel",
+ commandWidgetClass, selFileForm,
+ XtNlabel, cancel,
+ XtNresizable, True,
+ XtNcallback, SFcancelSelect,
+ XtNforeground, SFfore,
+ XtNbackground, SFback,
+ XtNborderColor, SFfore,
+ XtNfromHoriz, selFileOK,
+ XtNfromVert, selFileLists[0],
+ XtNhorizDistance, 30,
+ XtNvertDistance, 30,
+ XtNtop, XtChainTop,
+ XtNbottom, XtChainTop,
+ XtNleft, XtChainLeft,
+ XtNright, XtChainLeft,
+ NULL);
+
+ XtSetMappedWhenManaged(selFile, False);
+ XtRealizeWidget(selFile);
+
+ /* Add WM_DELETE_WINDOW protocol */
+ SFwmDeleteWindow = XInternAtom(SFdisplay, "WM_DELETE_WINDOW", False);
+ XSetWMProtocols(SFdisplay, XtWindow(selFile), &SFwmDeleteWindow, 1);
+
+ SFcreateGC();
+
+ for (n = 0; n < 3; n++)
+ {
+ XtAddEventHandler(selFileLists[n], ExposureMask, True,
+ (XtEventHandler)SFexposeList, (XtPointer)(long_u)n);
+ XtAddEventHandler(selFileLists[n], EnterWindowMask, False,
+ (XtEventHandler)SFenterList, (XtPointer)(long_u)n);
+ XtAddEventHandler(selFileLists[n], LeaveWindowMask, False,
+ (XtEventHandler)SFleaveList, (XtPointer)(long_u)n);
+ XtAddEventHandler(selFileLists[n], PointerMotionMask, False,
+ (XtEventHandler)SFmotionList, (XtPointer)(long_u)n);
+ XtAddEventHandler(selFileLists[n], ButtonPressMask, False,
+ (XtEventHandler)SFbuttonPressList, (XtPointer)(long_u)n);
+ XtAddEventHandler(selFileLists[n], ButtonReleaseMask, False,
+ (XtEventHandler)SFbuttonReleaseList, (XtPointer)(long_u)n);
+ }
+
+ XtAddEventHandler(selFileField, KeyPressMask, False,
+ SFmodVerifyCallback, (XtPointer)NULL);
+
+ SFapp = XtWidgetToApplicationContext(selFile);
+}
+
+ static void
+SFtextChanged(void)
+{
+#if defined(FEAT_XFONTSET) && defined(XtNinternational)
+ if ((unsigned long)_XawTextFormat((TextWidget)selFileField) == XawFmtWide)
+ {
+ wchar_t *wcbuf=(wchar_t *)SFtextBuffer;
+
+ if ((wcbuf[0] == L'/') || (wcbuf[0] == L'~'))
+ {
+ (void) wcstombs(SFcurrentPath, wcbuf, MAXPATHL);
+ SFtextPos = XawTextGetInsertionPoint(selFileField);
+ }
+ else
+ {
+ strcpy(SFcurrentPath, SFstartDir);
+ (void) wcstombs(SFcurrentPath + strlen(SFcurrentPath), wcbuf, MAXPATHL);
+
+ SFtextPos = XawTextGetInsertionPoint(selFileField) + strlen(SFstartDir);
+ }
+ }
+ else
+#endif
+ if ((SFtextBuffer[0] == '/') || (SFtextBuffer[0] == '~'))
+ {
+ (void) strcpy(SFcurrentPath, SFtextBuffer);
+ SFtextPos = XawTextGetInsertionPoint(selFileField);
+ }
+ else
+ {
+ (void) strcat(strcpy(SFcurrentPath, SFstartDir), SFtextBuffer);
+
+ SFtextPos = XawTextGetInsertionPoint(selFileField) + strlen(SFstartDir);
+ }
+
+ if (!SFworkProcAdded)
+ {
+ (void) XtAppAddWorkProc(SFapp, (XtWorkProc)SFworkProc, NULL);
+ SFworkProcAdded = 1;
+ }
+
+ SFupdatePath();
+}
+
+ static char *
+SFgetText(void)
+{
+#if defined(FEAT_XFONTSET) && defined(XtNinternational)
+ char *buf;
+
+ if ((unsigned long)_XawTextFormat((TextWidget)selFileField) == XawFmtWide)
+ {
+ wchar_t *wcbuf;
+ int mbslength;
+
+ XtVaGetValues(selFileField,
+ XtNstring, &wcbuf,
+ NULL);
+ mbslength = wcstombs(NULL, wcbuf, 0);
+ /* Hack: some broken wcstombs() returns zero, just get a large buffer */
+ if (mbslength == 0 && wcbuf != NULL && wcbuf[0] != 0)
+ mbslength = MAXPATHL;
+ buf=(char *)XtMalloc(mbslength + 1);
+ wcstombs(buf, wcbuf, mbslength +1);
+ return buf;
+ }
+#endif
+ return (char *)vim_strsave((char_u *)SFtextBuffer);
+}
+
+ static void
+SFprepareToReturn(void)
+{
+ SFstatus = SEL_FILE_NULL;
+ XtRemoveGrab(selFile);
+ XtUnmapWidget(selFile);
+ XtRemoveTimeOut(SFdirModTimerId);
+ if (SFchdir(SFstartDir))
+ {
+ emsg(_("E614: vim_SelFile: can't return to current directory"));
+ SFstatus = SEL_FILE_CANCEL;
+ }
+}
+
+ char *
+vim_SelFile(
+ Widget toplevel,
+ char *prompt,
+ char *init_path,
+ int (*show_entry)(),
+ int x,
+ int y,
+ guicolor_T fg,
+ guicolor_T bg,
+ guicolor_T scroll_fg,
+ guicolor_T scroll_bg) /* The "Scrollbar" group colors */
+{
+ static int firstTime = 1;
+ XEvent event;
+ char *name_return;
+
+ if (prompt == NULL)
+ prompt = _("Pathname:");
+ SFfore = fg;
+ SFback = bg;
+
+ if (mch_dirname((char_u *)SFstartDir, MAXPATHL) == FAIL)
+ {
+ emsg(_("E615: vim_SelFile: can't get current directory"));
+ return NULL;
+ }
+
+ if (firstTime)
+ {
+ firstTime = 0;
+ SFdisplay = XtDisplay(toplevel);
+ SFcreateWidgets(toplevel, prompt, _("OK"), _("Cancel"));
+ }
+ else
+ {
+ XtVaSetValues(selFilePrompt, XtNlabel, prompt, NULL);
+ XtVaSetValues(selFile, XtNtitle, prompt, NULL);
+ SFsetColors(bg, fg, scroll_bg, scroll_fg);
+ }
+
+ XtVaSetValues(selFile, XtNx, x, XtNy, y, NULL);
+ XtMapWidget(selFile);
+
+ (void)strcat(SFstartDir, "/");
+ (void)strcpy(SFcurrentDir, SFstartDir);
+
+ if (init_path)
+ {
+ if (init_path[0] == '/')
+ {
+ (void)strcpy(SFcurrentPath, init_path);
+ if (strncmp(SFcurrentPath, SFstartDir, strlen(SFstartDir)))
+ SFsetText(SFcurrentPath);
+ else
+ SFsetText(&(SFcurrentPath[strlen(SFstartDir)]));
+ }
+ else
+ {
+ (void)strcat(strcpy(SFcurrentPath, SFstartDir), init_path);
+ SFsetText(&(SFcurrentPath[strlen(SFstartDir)]));
+ }
+ }
+ else
+ (void)strcpy(SFcurrentPath, SFstartDir);
+
+ SFfunc = show_entry;
+
+ SFtextChanged();
+
+ XtAddGrab(selFile, True, True);
+
+ SFdirModTimerId = XtAppAddTimeOut(SFapp, (unsigned long) 1000,
+ SFdirModTimer, (XtPointer) NULL);
+
+ for (;;)
+ {
+ XtAppNextEvent(SFapp, &event);
+ XtDispatchEvent(&event);
+ switch (SFstatus)
+ {
+ case SEL_FILE_TEXT:
+ SFstatus = SEL_FILE_NULL;
+ SFtextChanged();
+ break;
+ case SEL_FILE_OK:
+ name_return = SFgetText();
+ SFprepareToReturn();
+ return name_return;
+ case SEL_FILE_CANCEL:
+ SFprepareToReturn();
+ return NULL;
+ case SEL_FILE_NULL:
+ break;
+ }
+ }
+}
+#endif /* FEAT_BROWSE */
diff --git a/src/gui_at_sb.c b/src/gui_at_sb.c
new file mode 100644
index 0000000..72dc8c8
--- /dev/null
+++ b/src/gui_at_sb.c
@@ -0,0 +1,1192 @@
+/* vi:set ts=8 sts=4 sw=4 noet: */
+/*
+ * MODIFIED ATHENA SCROLLBAR (USING ARROWHEADS AT ENDS OF TRAVEL)
+ * Modifications Copyright 1992 by Mitch Trachtenberg
+ * Rights, permissions, and disclaimer of warranty are as in the DEC and MIT
+ * notice below.
+ * $XConsortium: Scrollbar.c,v 1.72 94/04/17 20:12:40 kaleb Exp $
+ */
+
+/*
+ * Modified for Vim by Bill Foster and Bram Moolenaar
+ */
+
+/*
+
+Copyright (c) 1987, 1988, 1994 X Consortium
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X
+CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the X Consortium shall not be
+used in advertising or otherwise to promote the sale, use or other dealings in
+this Software without prior written authorization from the X Consortium.
+
+Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted, provided that
+the above copyright notice appear in all copies and that both that copyright
+notice and this permission notice appear in supporting documentation, and that
+the name of Digital not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL DIGITAL
+BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+*/
+
+/* ScrollBar.c */
+/* created by weissman, Mon Jul 7 13:20:03 1986 */
+/* converted by swick, Thu Aug 27 1987 */
+
+#include "vim.h"
+
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+
+#include <X11/Xaw/XawInit.h>
+#include "gui_at_sb.h"
+
+#include <X11/Xmu/Drawing.h>
+
+/* Private definitions. */
+
+static char defaultTranslations[] =
+ "<Btn1Down>: NotifyScroll()\n\
+ <Btn2Down>: MoveThumb() NotifyThumb()\n\
+ <Btn3Down>: NotifyScroll()\n\
+ <Btn4Down>: ScrollOneLineUp()\n\
+ Shift<Btn4Down>: ScrollPageUp()\n\
+ <Btn5Down>: ScrollOneLineDown()\n\
+ Shift<Btn5Down>: ScrollPageDown()\n\
+ <Btn1Motion>: HandleThumb()\n\
+ <Btn3Motion>: HandleThumb()\n\
+ <Btn2Motion>: MoveThumb() NotifyThumb()\n\
+ <BtnUp>: EndScroll()";
+
+static float floatZero = 0.0;
+
+#define Offset(field) XtOffsetOf(ScrollbarRec, field)
+
+static XtResource resources[] =
+{
+ {XtNlength, XtCLength, XtRDimension, sizeof(Dimension),
+ Offset(scrollbar.length), XtRImmediate, (XtPointer) 1},
+ {XtNthickness, XtCThickness, XtRDimension, sizeof(Dimension),
+ Offset(scrollbar.thickness), XtRImmediate, (XtPointer) 14},
+ {XtNorientation, XtCOrientation, XtROrientation, sizeof(XtOrientation),
+ Offset(scrollbar.orientation), XtRImmediate, (XtPointer) XtorientVertical},
+ {XtNscrollProc, XtCCallback, XtRCallback, sizeof(XtPointer),
+ Offset(scrollbar.scrollProc), XtRCallback, NULL},
+ {XtNthumbProc, XtCCallback, XtRCallback, sizeof(XtPointer),
+ Offset(scrollbar.thumbProc), XtRCallback, NULL},
+ {XtNjumpProc, XtCCallback, XtRCallback, sizeof(XtPointer),
+ Offset(scrollbar.jumpProc), XtRCallback, NULL},
+ {XtNthumb, XtCThumb, XtRBitmap, sizeof(Pixmap),
+ Offset(scrollbar.thumb), XtRImmediate, (XtPointer) XtUnspecifiedPixmap},
+ {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
+ Offset(scrollbar.foreground), XtRString, XtDefaultForeground},
+ {XtNshown, XtCShown, XtRFloat, sizeof(float),
+ Offset(scrollbar.shown), XtRFloat, (XtPointer)&floatZero},
+ {XtNtopOfThumb, XtCTopOfThumb, XtRFloat, sizeof(float),
+ Offset(scrollbar.top), XtRFloat, (XtPointer)&floatZero},
+ {XtNmaxOfThumb, XtCMaxOfThumb, XtRFloat, sizeof(float),
+ Offset(scrollbar.max), XtRFloat, (XtPointer)&floatZero},
+ {XtNminimumThumb, XtCMinimumThumb, XtRDimension, sizeof(Dimension),
+ Offset(scrollbar.min_thumb), XtRImmediate, (XtPointer) 7},
+ {XtNshadowWidth, XtCShadowWidth, XtRDimension, sizeof(Dimension),
+ Offset(scrollbar.shadow_width), XtRImmediate, (XtPointer) 1},
+ {XtNtopShadowPixel, XtCTopShadowPixel, XtRPixel, sizeof(Pixel),
+ Offset(scrollbar.top_shadow_pixel), XtRString, XtDefaultBackground},
+ {XtNbottomShadowPixel, XtCBottomShadowPixel, XtRPixel, sizeof(Pixel),
+ Offset(scrollbar.bot_shadow_pixel), XtRString, XtDefaultForeground},
+ {XtNlimitThumb, XtCLimitThumb, XtRBool, sizeof(Bool),
+ Offset(scrollbar.limit_thumb), XtRImmediate, (XtPointer)0}
+};
+#undef Offset
+
+static void ClassInitialize(void);
+static void Initialize(Widget, Widget, ArgList, Cardinal *);
+static void Destroy(Widget);
+static void Realize(Widget, Mask *, XSetWindowAttributes *);
+static void Resize(Widget);
+static void Redisplay(Widget, XEvent *, Region);
+static Boolean SetValues(Widget, Widget, Widget, ArgList, Cardinal *);
+
+static void HandleThumb(Widget, XEvent *, String *, Cardinal *);
+static void MoveThumb(Widget, XEvent *, String *, Cardinal *);
+static void NotifyThumb(Widget, XEvent *, String *, Cardinal *);
+static void NotifyScroll(Widget, XEvent *, String *, Cardinal *);
+static void EndScroll(Widget, XEvent *, String *, Cardinal *);
+static void ScrollOneLineUp(Widget, XEvent *, String *, Cardinal *);
+static void ScrollOneLineDown(Widget, XEvent *, String *, Cardinal *);
+static void ScrollPageUp(Widget, XEvent *, String *, Cardinal *);
+static void ScrollPageDown(Widget, XEvent *, String *, Cardinal *);
+static void ScrollSome(Widget w, XEvent *event, int call_data);
+static void _Xaw3dDrawShadows(Widget, XEvent *, Region, int);
+static void AllocTopShadowGC(Widget);
+static void AllocBotShadowGC(Widget);
+
+static XtActionsRec actions[] =
+{
+ {"HandleThumb", HandleThumb},
+ {"MoveThumb", MoveThumb},
+ {"NotifyThumb", NotifyThumb},
+ {"NotifyScroll", NotifyScroll},
+ {"EndScroll", EndScroll},
+ {"ScrollOneLineUp", ScrollOneLineUp},
+ {"ScrollOneLineDown", ScrollOneLineDown},
+ {"ScrollPageUp", ScrollPageUp},
+ {"ScrollPageDown", ScrollPageDown}
+};
+
+
+ScrollbarClassRec vim_scrollbarClassRec =
+{
+ { /* core fields */
+ /* superclass */ (WidgetClass) &simpleClassRec,
+ /* class_name */ "Scrollbar",
+ /* size */ sizeof(ScrollbarRec),
+ /* class_initialize */ ClassInitialize,
+ /* class_part_init */ NULL,
+ /* class_inited */ FALSE,
+ /* initialize */ Initialize,
+ /* initialize_hook */ NULL,
+ /* realize */ Realize,
+ /* actions */ actions,
+ /* num_actions */ XtNumber(actions),
+ /* resources */ resources,
+ /* num_resources */ XtNumber(resources),
+ /* xrm_class */ NULLQUARK,
+ /* compress_motion */ TRUE,
+ /* compress_exposure*/ TRUE,
+ /* compress_enterleave*/ TRUE,
+ /* visible_interest */ FALSE,
+ /* destroy */ Destroy,
+ /* resize */ Resize,
+ /* expose */ Redisplay,
+ /* set_values */ SetValues,
+ /* set_values_hook */ NULL,
+ /* set_values_almost */ XtInheritSetValuesAlmost,
+ /* get_values_hook */ NULL,
+ /* accept_focus */ NULL,
+ /* version */ XtVersion,
+ /* callback_private */ NULL,
+ /* tm_table */ defaultTranslations,
+ /* query_geometry */ XtInheritQueryGeometry,
+ /* display_accelerator*/ XtInheritDisplayAccelerator,
+ /* extension */ NULL
+ },
+ { /* simple fields */
+ /* change_sensitive */ XtInheritChangeSensitive,
+#ifndef OLDXAW
+ /* extension */ NULL
+#endif
+ },
+ { /* scrollbar fields */
+ /* empty */ 0
+ }
+};
+
+WidgetClass vim_scrollbarWidgetClass = (WidgetClass)&vim_scrollbarClassRec;
+
+#define NoButton -1
+#define PICKLENGTH(widget, x, y) \
+ ((widget->scrollbar.orientation == XtorientHorizontal) ? (x) : (y))
+#define AT_MIN(x,y) ((x) < (y) ? (x) : (y))
+#define AT_MAX(x,y) ((x) > (y) ? (x) : (y))
+
+#define LINE_DELAY 300
+#define PAGE_DELAY 300
+#define LINE_REPEAT 50
+#define PAGE_REPEAT 250
+
+ static void
+ClassInitialize(void)
+{
+ XawInitializeWidgetSet();
+ XtAddConverter( XtRString, XtROrientation, XmuCvtStringToOrientation,
+ (XtConvertArgList)NULL, (Cardinal)0 );
+}
+
+#define MARGIN(sbw) (sbw)->scrollbar.thickness + (sbw)->scrollbar.shadow_width
+
+ static void
+FillArea(
+ ScrollbarWidget sbw,
+ Position top,
+ Position bottom,
+ int fill,
+ int draw_shadow)
+{
+ int tlen = bottom - top; /* length of thumb in pixels */
+ int sw, margin, floor;
+ int lx, ly, lw, lh;
+
+ if (bottom <= 0 || bottom <= top)
+ return;
+ sw = sbw->scrollbar.shadow_width;
+ if (sw < 0)
+ sw = 0;
+ margin = MARGIN (sbw);
+ floor = sbw->scrollbar.length - margin + 2;
+
+ if (sbw->scrollbar.orientation == XtorientHorizontal)
+ {
+ lx = ((top < margin) ? margin : top);
+ ly = sw;
+ lw = (((top + tlen) > floor) ? floor - top : tlen);
+ lh = sbw->core.height - 2 * sw;
+ }
+ else
+ {
+ lx = sw;
+ ly = ((top < margin) ? margin : top);
+ lw = sbw->core.width - 2 * sw;
+ lh = (((top + tlen) > floor) ? floor - top : tlen);
+ }
+ if (lh <= 0 || lw <= 0)
+ return;
+
+ if (draw_shadow)
+ {
+ if (!(sbw->scrollbar.orientation == XtorientHorizontal))
+ {
+ /* Top border */
+ XDrawLine (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
+ sbw->scrollbar.top_shadow_GC,
+ lx, ly, lx + lw - 1, ly);
+
+ /* Bottom border */
+ XDrawLine (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
+ sbw->scrollbar.bot_shadow_GC,
+ lx, ly + lh - 1, lx + lw - 1, ly + lh - 1);
+ }
+ else
+ {
+ /* Left border */
+ XDrawLine (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
+ sbw->scrollbar.top_shadow_GC,
+ lx, ly, lx, ly + lh - 1);
+
+ /* Right border */
+ XDrawLine (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
+ sbw->scrollbar.bot_shadow_GC,
+ lx + lw - 1, ly, lx + lw - 1, ly + lh - 1);
+ }
+ return;
+ }
+
+ if (fill)
+ {
+ XFillRectangle(XtDisplay((Widget) sbw), XtWindow((Widget) sbw),
+ sbw->scrollbar.gc,
+ lx, ly, (unsigned int) lw, (unsigned int) lh);
+
+ if (!(sbw->scrollbar.orientation == XtorientHorizontal))
+ {
+ /* Left border */
+ XDrawLine(XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
+ sbw->scrollbar.top_shadow_GC,
+ lx, ly, lx, ly + lh - 1);
+
+ /* Right border */
+ XDrawLine(XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
+ sbw->scrollbar.bot_shadow_GC,
+ lx + lw - 1, ly, lx + lw - 1, ly + lh - 1);
+ }
+ else
+ {
+ /* Top border */
+ XDrawLine(XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
+ sbw->scrollbar.top_shadow_GC,
+ lx, ly, lx + lw - 1, ly);
+
+ /* Bottom border */
+ XDrawLine(XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
+ sbw->scrollbar.bot_shadow_GC,
+ lx, ly + lh - 1, lx + lw - 1, ly + lh - 1);
+ }
+ }
+ else
+ {
+ XClearArea(XtDisplay((Widget) sbw), XtWindow((Widget) sbw),
+ lx, ly, (unsigned int) lw, (unsigned int) lh, FALSE);
+ }
+}
+
+/* Paint the thumb in the area specified by sbw->top and
+ sbw->shown. The old area is erased. The painting and
+ erasing is done cleverly so that no flickering will occur.
+ */
+
+ static void
+PaintThumb(ScrollbarWidget sbw)
+{
+ Position oldtop, oldbot, newtop, newbot;
+ Dimension margin, tzl;
+
+ margin = MARGIN (sbw);
+ tzl = sbw->scrollbar.length - 2 * margin;
+ newtop = margin + (int)(tzl * sbw->scrollbar.top);
+ newbot = newtop + (int)(tzl * sbw->scrollbar.shown) + 1;
+ if (newbot < newtop + (int)sbw->scrollbar.min_thumb)
+ newbot = newtop + sbw->scrollbar.min_thumb;
+
+ oldtop = sbw->scrollbar.topLoc;
+ oldbot = oldtop + sbw->scrollbar.shownLength;
+ sbw->scrollbar.topLoc = newtop;
+ sbw->scrollbar.shownLength = newbot - newtop;
+ if (XtIsRealized ((Widget) sbw))
+ {
+ if (newtop < oldtop)
+ FillArea(sbw, newtop, AT_MIN(newbot, oldtop+1),1,0);
+ if (newtop > oldtop)
+ FillArea(sbw, oldtop, AT_MIN(newtop, oldbot ),0,0);
+ if (newbot < oldbot)
+ FillArea(sbw, AT_MAX(newbot, oldtop), oldbot, 0,0);
+ if (newbot > oldbot)
+ FillArea(sbw, AT_MAX(newtop, oldbot-1), newbot, 1,0);
+
+ /* Only draw the missing shadows */
+ FillArea(sbw, newtop, newbot, 0, 1);
+ }
+}
+
+ static void
+PaintArrows(ScrollbarWidget sbw)
+{
+ XPoint point[6];
+ Dimension thickness = sbw->scrollbar.thickness - 1;
+ Dimension size;
+ Dimension off;
+
+ if (XtIsRealized((Widget) sbw))
+ {
+ if ((int)thickness * 2 > (int)sbw->scrollbar.length)
+ {
+ size = sbw->scrollbar.length / 2;
+ off = (int)(thickness - size) / 2;
+ }
+ else
+ {
+ size = thickness;
+ off = 0;
+ }
+ point[0].x = off + sbw->scrollbar.shadow_width;
+ point[0].y = size;
+ point[1].x = thickness - off - sbw->scrollbar.shadow_width;
+ point[1].y = size;
+ point[2].x = thickness / 2;
+ point[2].y = sbw->scrollbar.shadow_width;
+
+ point[3].x = off + sbw->scrollbar.shadow_width;
+ point[3].y = sbw->scrollbar.length - size;
+ point[4].x = thickness - off - sbw->scrollbar.shadow_width;
+ point[4].y = sbw->scrollbar.length - size;
+ point[5].x = thickness / 2;
+ point[5].y = sbw->scrollbar.length - sbw->scrollbar.shadow_width - 1;
+
+ /* horizontal arrows require that x and y coordinates be swapped */
+ if (sbw->scrollbar.orientation == XtorientHorizontal)
+ {
+ int n;
+ int swap;
+ for (n = 0; n < 6; n++)
+ {
+ swap = point[n].x;
+ point[n].x = point[n].y;
+ point[n].y = swap;
+ }
+ }
+ /* draw the up/left arrow */
+ XFillPolygon (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
+ sbw->scrollbar.gc,
+ point, 3,
+ Convex, CoordModeOrigin);
+ XDrawLines (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
+ sbw->scrollbar.bot_shadow_GC,
+ point, 3,
+ CoordModeOrigin);
+ XDrawLine (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
+ sbw->scrollbar.top_shadow_GC,
+ point[0].x, point[0].y,
+ point[2].x, point[2].y);
+ /* draw the down/right arrow */
+ XFillPolygon (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
+ sbw->scrollbar.gc,
+ point+3, 3,
+ Convex, CoordModeOrigin);
+ XDrawLine (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
+ sbw->scrollbar.top_shadow_GC,
+ point[3].x, point[3].y,
+ point[4].x, point[4].y);
+ XDrawLine (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
+ sbw->scrollbar.top_shadow_GC,
+ point[3].x, point[3].y,
+ point[5].x, point[5].y);
+ XDrawLine (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
+ sbw->scrollbar.bot_shadow_GC,
+ point[4].x, point[4].y,
+ point[5].x, point[5].y);
+ }
+}
+
+ static void
+Destroy(Widget w)
+{
+ ScrollbarWidget sbw = (ScrollbarWidget) w;
+ if (sbw->scrollbar.timer_id != (XtIntervalId) 0)
+ XtRemoveTimeOut (sbw->scrollbar.timer_id);
+ XtReleaseGC(w, sbw->scrollbar.gc);
+ XtReleaseGC(w, sbw->scrollbar.top_shadow_GC);
+ XtReleaseGC(w, sbw->scrollbar.bot_shadow_GC);
+}
+
+ static void
+CreateGC(Widget w)
+{
+ ScrollbarWidget sbw = (ScrollbarWidget) w;
+ XGCValues gcValues;
+ XtGCMask mask;
+ unsigned int depth = 1;
+
+ if (sbw->scrollbar.thumb == XtUnspecifiedPixmap)
+ {
+ sbw->scrollbar.thumb = XmuCreateStippledPixmap (XtScreen(w),
+ (Pixel) 1, (Pixel) 0, depth);
+ }
+ else if (sbw->scrollbar.thumb != None)
+ {
+ Window root;
+ int x, y;
+ unsigned int width, height, bw;
+
+ if (XGetGeometry (XtDisplay(w), sbw->scrollbar.thumb, &root, &x, &y,
+ &width, &height, &bw, &depth) == 0)
+ emsg(_("Scrollbar Widget: Could not get geometry of thumb pixmap."));
+ }
+
+ gcValues.foreground = sbw->scrollbar.foreground;
+ gcValues.background = sbw->core.background_pixel;
+ mask = GCForeground | GCBackground;
+
+ if (sbw->scrollbar.thumb != None)
+ {
+ gcValues.fill_style = FillSolid;
+ mask |= GCFillStyle;
+ }
+ /* the creation should be non-caching, because */
+ /* we now set and clear clip masks on the gc returned */
+ sbw->scrollbar.gc = XtGetGC (w, mask, &gcValues);
+}
+
+ static void
+SetDimensions(ScrollbarWidget sbw)
+{
+ if (sbw->scrollbar.orientation == XtorientVertical)
+ {
+ sbw->scrollbar.length = sbw->core.height;
+ sbw->scrollbar.thickness = sbw->core.width;
+ }
+ else
+ {
+ sbw->scrollbar.length = sbw->core.width;
+ sbw->scrollbar.thickness = sbw->core.height;
+ }
+}
+
+ static void
+Initialize(
+ Widget request UNUSED, /* what the client asked for */
+ Widget new, /* what we're going to give him */
+ ArgList args UNUSED,
+ Cardinal *num_args UNUSED)
+{
+ ScrollbarWidget sbw = (ScrollbarWidget) new;
+
+ CreateGC(new);
+ AllocTopShadowGC(new);
+ AllocBotShadowGC(new);
+
+ if (sbw->core.width == 0)
+ sbw->core.width = (sbw->scrollbar.orientation == XtorientVertical)
+ ? sbw->scrollbar.thickness : sbw->scrollbar.length;
+
+ if (sbw->core.height == 0)
+ sbw->core.height = (sbw->scrollbar.orientation == XtorientHorizontal)
+ ? sbw->scrollbar.thickness : sbw->scrollbar.length;
+
+ SetDimensions(sbw);
+ sbw->scrollbar.scroll_mode = SMODE_NONE;
+ sbw->scrollbar.timer_id = (XtIntervalId)0;
+ sbw->scrollbar.topLoc = 0;
+ sbw->scrollbar.shownLength = sbw->scrollbar.min_thumb;
+}
+
+ static void
+Realize(
+ Widget w,
+ Mask *valueMask,
+ XSetWindowAttributes *attributes)
+{
+ /* The Simple widget actually stuffs the value in the valuemask. */
+ (*vim_scrollbarWidgetClass->core_class.superclass->core_class.realize)
+ (w, valueMask, attributes);
+}
+
+ static Boolean
+SetValues(
+ Widget current, /* what I am */
+ Widget request UNUSED, /* what he wants me to be */
+ Widget desired, /* what I will become */
+ ArgList args UNUSED,
+ Cardinal *num_args UNUSED)
+{
+ ScrollbarWidget sbw = (ScrollbarWidget) current;
+ ScrollbarWidget dsbw = (ScrollbarWidget) desired;
+ Boolean redraw = FALSE;
+
+/*
+ * If these values are outside the acceptable range ignore them...
+ */
+ if (dsbw->scrollbar.top < 0.0 || dsbw->scrollbar.top > 1.0)
+ dsbw->scrollbar.top = sbw->scrollbar.top;
+
+ if (dsbw->scrollbar.shown < 0.0 || dsbw->scrollbar.shown > 1.0)
+ dsbw->scrollbar.shown = sbw->scrollbar.shown;
+
+/*
+ * Change colors and stuff...
+ */
+ if (XtIsRealized(desired))
+ {
+ if (sbw->scrollbar.foreground != dsbw->scrollbar.foreground ||
+ sbw->core.background_pixel != dsbw->core.background_pixel ||
+ sbw->scrollbar.thumb != dsbw->scrollbar.thumb)
+ {
+ XtReleaseGC(desired, sbw->scrollbar.gc);
+ CreateGC (desired);
+ redraw = TRUE;
+ }
+ if (sbw->scrollbar.top != dsbw->scrollbar.top ||
+ sbw->scrollbar.shown != dsbw->scrollbar.shown)
+ redraw = TRUE;
+ }
+ return redraw;
+}
+
+ static void
+Resize(Widget w)
+{
+ /* ForgetGravity has taken care of background, but thumb may
+ * have to move as a result of the new size. */
+ SetDimensions ((ScrollbarWidget) w);
+ Redisplay(w, (XEvent*) NULL, (Region)NULL);
+}
+
+
+ static void
+Redisplay(Widget w, XEvent *event, Region region)
+{
+ ScrollbarWidget sbw = (ScrollbarWidget) w;
+ int x, y;
+ unsigned int width, height;
+
+ _Xaw3dDrawShadows(w, event, region, FALSE);
+
+ if (sbw->scrollbar.orientation == XtorientHorizontal)
+ {
+ x = sbw->scrollbar.topLoc;
+ y = 1;
+ width = sbw->scrollbar.shownLength;
+ height = sbw->core.height - 2;
+ }
+ else
+ {
+ x = 1;
+ y = sbw->scrollbar.topLoc;
+ width = sbw->core.width - 2;
+ height = sbw->scrollbar.shownLength;
+ }
+ if (region == NULL ||
+ XRectInRegion (region, x, y, width, height) != RectangleOut)
+ {
+ /* Forces entire thumb to be painted. */
+ sbw->scrollbar.topLoc = -(sbw->scrollbar.length + 1);
+ PaintThumb (sbw);
+ }
+ /* we'd like to be region aware here!!!! */
+ PaintArrows(sbw);
+}
+
+
+ static Boolean
+CompareEvents(XEvent *oldEvent, XEvent *newEvent)
+{
+#define Check(field) \
+ do { \
+ if (newEvent->field != oldEvent->field) \
+ return False; \
+ } while (0)
+
+ Check(xany.display);
+ Check(xany.type);
+ Check(xany.window);
+
+ switch (newEvent->type)
+ {
+ case MotionNotify:
+ Check(xmotion.state);
+ break;
+ case ButtonPress:
+ case ButtonRelease:
+ Check(xbutton.state);
+ Check(xbutton.button);
+ break;
+ case KeyPress:
+ case KeyRelease:
+ Check(xkey.state);
+ Check(xkey.keycode);
+ break;
+ case EnterNotify:
+ case LeaveNotify:
+ Check(xcrossing.mode);
+ Check(xcrossing.detail);
+ Check(xcrossing.state);
+ break;
+ }
+#undef Check
+
+ return True;
+}
+
+struct EventData
+{
+ XEvent *oldEvent;
+ int count;
+};
+
+ static Bool
+PeekNotifyEvent(Display *dpy, XEvent *event, char *args)
+{
+ struct EventData *eventData = (struct EventData*)args;
+
+ return ((++eventData->count == QLength(dpy)) /* since PeekIf blocks */
+ || CompareEvents(event, eventData->oldEvent));
+}
+
+
+ static Boolean
+LookAhead(Widget w, XEvent *event)
+{
+ XEvent newEvent;
+ struct EventData eventData;
+
+ if (QLength (XtDisplay (w)) == 0)
+ return False;
+
+ eventData.count = 0;
+ eventData.oldEvent = event;
+
+ XPeekIfEvent (XtDisplay (w), &newEvent, PeekNotifyEvent, (char*)&eventData);
+
+ return CompareEvents (event, &newEvent);
+}
+
+
+ static void
+ExtractPosition(
+ XEvent *event,
+ Position *x, /* RETURN */
+ Position *y, /* RETURN */
+ unsigned int *state) /* RETURN */
+{
+ switch (event->type)
+ {
+ case MotionNotify:
+ *x = event->xmotion.x;
+ *y = event->xmotion.y;
+ if (state != NULL)
+ *state = event->xmotion.state;
+ break;
+ case ButtonPress:
+ case ButtonRelease:
+ *x = event->xbutton.x;
+ *y = event->xbutton.y;
+ if (state != NULL)
+ *state = event->xbutton.state;
+ break;
+ case KeyPress:
+ case KeyRelease:
+ *x = event->xkey.x;
+ *y = event->xkey.y;
+ if (state != NULL)
+ *state = event->xkey.state;
+ break;
+ case EnterNotify:
+ case LeaveNotify:
+ *x = event->xcrossing.x;
+ *y = event->xcrossing.y;
+ if (state != NULL)
+ *state = event->xcrossing.state;
+ break;
+ default:
+ *x = 0; *y = 0;
+ if (state != NULL)
+ *state = 0;
+ }
+}
+
+ static void
+HandleThumb(
+ Widget w,
+ XEvent *event,
+ String *params,
+ Cardinal *num_params)
+{
+ Position x, y, loc;
+ ScrollbarWidget sbw = (ScrollbarWidget) w;
+
+ ExtractPosition(event, &x, &y, (unsigned int *)NULL);
+ loc = PICKLENGTH(sbw, x, y);
+ /* if the motion event puts the pointer in thumb, call Move and Notify */
+ /* also call Move and Notify if we're already in continuous scroll mode */
+ if (sbw->scrollbar.scroll_mode == SMODE_CONT ||
+ (loc >= sbw->scrollbar.topLoc &&
+ loc <= sbw->scrollbar.topLoc + (int)sbw->scrollbar.shownLength))
+ {
+ XtCallActionProc(w, "MoveThumb", event, params, *num_params);
+ XtCallActionProc(w, "NotifyThumb", event, params, *num_params);
+ }
+}
+
+ static void
+RepeatNotify(XtPointer client_data, XtIntervalId *idp UNUSED)
+{
+ ScrollbarWidget sbw = (ScrollbarWidget) client_data;
+ int call_data;
+ char mode = sbw->scrollbar.scroll_mode;
+ unsigned long rep;
+
+ if (mode == SMODE_NONE || mode == SMODE_CONT)
+ {
+ sbw->scrollbar.timer_id = (XtIntervalId)0;
+ return;
+ }
+
+ if (mode == SMODE_LINE_DOWN || mode == SMODE_LINE_UP)
+ {
+ call_data = ONE_LINE_DATA;
+ rep = LINE_REPEAT;
+ }
+ else
+ {
+ call_data = ONE_PAGE_DATA;
+ rep = PAGE_REPEAT;
+ }
+
+ if (mode == SMODE_PAGE_UP || mode == SMODE_LINE_UP)
+ call_data = -call_data;
+
+ XtCallCallbacks((Widget)sbw, XtNscrollProc, (XtPointer)(long_u)call_data);
+
+ sbw->scrollbar.timer_id =
+ XtAppAddTimeOut(XtWidgetToApplicationContext((Widget)sbw),
+ rep,
+ RepeatNotify,
+ client_data);
+}
+
+/*
+ * Same as above, but for floating numbers.
+ */
+ static float
+FloatInRange(float num, float small, float big)
+{
+ return (num < small) ? small : ((num > big) ? big : num);
+}
+
+ static void
+ScrollOneLineUp(
+ Widget w,
+ XEvent *event,
+ String *params UNUSED,
+ Cardinal *num_params UNUSED)
+{
+ ScrollSome(w, event, -ONE_LINE_DATA);
+}
+
+ static void
+ScrollOneLineDown(
+ Widget w,
+ XEvent *event,
+ String *params UNUSED,
+ Cardinal *num_params UNUSED)
+{
+ ScrollSome(w, event, ONE_LINE_DATA);
+}
+
+ static void
+ScrollPageDown(
+ Widget w,
+ XEvent *event,
+ String *params UNUSED,
+ Cardinal *num_params UNUSED)
+{
+ ScrollSome(w, event, ONE_PAGE_DATA);
+}
+
+ static void
+ScrollPageUp(
+ Widget w,
+ XEvent *event,
+ String *params UNUSED,
+ Cardinal *num_params UNUSED)
+{
+ ScrollSome(w, event, -ONE_PAGE_DATA);
+}
+
+ static void
+ScrollSome(
+ Widget w,
+ XEvent *event,
+ int call_data)
+{
+ ScrollbarWidget sbw = (ScrollbarWidget) w;
+
+ if (sbw->scrollbar.scroll_mode == SMODE_CONT) /* if scroll continuous */
+ return;
+
+ if (LookAhead(w, event))
+ return;
+
+ sbw->scrollbar.scroll_mode = SMODE_LINE_UP;
+ XtCallCallbacks(w, XtNscrollProc, (XtPointer)(long_u)call_data);
+}
+
+ static void
+NotifyScroll(
+ Widget w,
+ XEvent *event,
+ String *params UNUSED,
+ Cardinal *num_params UNUSED)
+{
+ ScrollbarWidget sbw = (ScrollbarWidget) w;
+ Position x, y, loc;
+ Dimension arrow_size;
+ unsigned long delay = 0;
+ int call_data = 0;
+ unsigned int state;
+
+ if (sbw->scrollbar.scroll_mode == SMODE_CONT) /* if scroll continuous */
+ return;
+
+ if (LookAhead (w, event))
+ return;
+
+ ExtractPosition(event, &x, &y, &state);
+ loc = PICKLENGTH(sbw, x, y);
+
+ if ((int)sbw->scrollbar.thickness * 2 > (int)sbw->scrollbar.length)
+ arrow_size = sbw->scrollbar.length / 2;
+ else
+ arrow_size = sbw->scrollbar.thickness;
+
+ /*
+ * handle CTRL modifier
+ */
+ if (state & ControlMask)
+ {
+ if (loc > sbw->scrollbar.topLoc + (Position)sbw->scrollbar.shownLength)
+ call_data = END_PAGE_DATA;
+ else
+ call_data = -END_PAGE_DATA;
+ sbw->scrollbar.scroll_mode = SMODE_NONE;
+ }
+ /*
+ * handle first arrow zone
+ */
+ else if (loc < (Position)arrow_size)
+ {
+ call_data = -ONE_LINE_DATA;
+ sbw->scrollbar.scroll_mode = SMODE_LINE_UP;
+ delay = LINE_DELAY;
+ }
+
+ /*
+ * handle last arrow zone
+ */
+ else if (loc > (Position)(sbw->scrollbar.length - arrow_size))
+ {
+ call_data = ONE_LINE_DATA;
+ sbw->scrollbar.scroll_mode = SMODE_LINE_DOWN;
+ delay = LINE_DELAY;
+ }
+
+ /*
+ * handle zone "above" the thumb
+ */
+ else if (loc < sbw->scrollbar.topLoc)
+ {
+ call_data = -ONE_PAGE_DATA;
+ sbw->scrollbar.scroll_mode = SMODE_PAGE_UP;
+ delay = PAGE_DELAY;
+ }
+
+ /*
+ * handle zone "below" the thumb
+ */
+ else if (loc > sbw->scrollbar.topLoc + (Position)sbw->scrollbar.shownLength)
+ {
+ call_data = ONE_PAGE_DATA;
+ sbw->scrollbar.scroll_mode = SMODE_PAGE_DOWN;
+ delay = PAGE_DELAY;
+ }
+
+ if (call_data)
+ XtCallCallbacks(w, XtNscrollProc, (XtPointer)(long_u)call_data);
+
+ /* establish autoscroll */
+ if (delay)
+ sbw->scrollbar.timer_id =
+ XtAppAddTimeOut(XtWidgetToApplicationContext(w),
+ delay, RepeatNotify, (XtPointer)w);
+}
+
+ static void
+EndScroll(
+ Widget w,
+ XEvent *event UNUSED,
+ String *params UNUSED,
+ Cardinal *num_params UNUSED)
+{
+ ScrollbarWidget sbw = (ScrollbarWidget) w;
+
+ sbw->scrollbar.scroll_mode = SMODE_NONE;
+ /* no need to remove any autoscroll timeout; it will no-op */
+ /* because the scroll_mode is SMODE_NONE */
+ /* but be sure to remove timeout in destroy proc */
+}
+
+ static float
+FractionLoc(ScrollbarWidget sbw, int x, int y)
+{
+ int margin;
+ float height, width;
+
+ margin = MARGIN(sbw);
+ x -= margin;
+ y -= margin;
+ height = (float)sbw->core.height - 2 * margin;
+ width = (float)sbw->core.width - 2 * margin;
+ return PICKLENGTH(sbw, x / width, y / height);
+}
+
+ static void
+MoveThumb(
+ Widget w,
+ XEvent *event,
+ String *params UNUSED,
+ Cardinal *num_params UNUSED)
+{
+ ScrollbarWidget sbw = (ScrollbarWidget)w;
+ Position x, y;
+ float top;
+ char old_mode = sbw->scrollbar.scroll_mode;
+
+ sbw->scrollbar.scroll_mode = SMODE_CONT; /* indicate continuous scroll */
+
+ if (LookAhead(w, event))
+ return;
+
+ if (!event->xmotion.same_screen)
+ return;
+
+ ExtractPosition(event, &x, &y, (unsigned int *)NULL);
+
+ top = FractionLoc(sbw, x, y);
+
+ if (old_mode != SMODE_CONT) /* start dragging: set offset */
+ {
+ if (event->xbutton.button == Button2)
+ sbw->scrollbar.scroll_off = sbw->scrollbar.shown / 2.;
+ else
+ sbw->scrollbar.scroll_off = top - sbw->scrollbar.top;
+ }
+
+ top -= sbw->scrollbar.scroll_off;
+ if (sbw->scrollbar.limit_thumb)
+ top = FloatInRange(top, 0.0,
+ sbw->scrollbar.max - sbw->scrollbar.shown + 0.000001);
+ else
+ top = FloatInRange(top, 0.0, sbw->scrollbar.max);
+
+ sbw->scrollbar.top = top;
+ PaintThumb(sbw);
+ XFlush(XtDisplay(w)); /* re-draw it before Notifying */
+}
+
+
+ static void
+NotifyThumb(
+ Widget w,
+ XEvent *event,
+ String *params UNUSED,
+ Cardinal *num_params UNUSED)
+{
+ ScrollbarWidget sbw = (ScrollbarWidget)w;
+ /* Use a union to avoid a warning for the weird conversion from float to
+ * XtPointer. Comes from Xaw/Scrollbar.c. */
+ union {
+ XtPointer xtp;
+ float xtf;
+ } xtpf;
+
+ if (LookAhead(w, event))
+ return;
+
+ /* thumbProc is not pretty, but is necessary for backwards
+ compatibility on those architectures for which it work{s,ed};
+ the intent is to pass a (truncated) float by value. */
+ xtpf.xtf = sbw->scrollbar.top;
+ XtCallCallbacks(w, XtNthumbProc, xtpf.xtp);
+ XtCallCallbacks(w, XtNjumpProc, (XtPointer)&sbw->scrollbar.top);
+}
+
+ static void
+AllocTopShadowGC(Widget w)
+{
+ ScrollbarWidget sbw = (ScrollbarWidget) w;
+ XtGCMask valuemask;
+ XGCValues myXGCV;
+
+ valuemask = GCForeground;
+ myXGCV.foreground = sbw->scrollbar.top_shadow_pixel;
+ sbw->scrollbar.top_shadow_GC = XtGetGC(w, valuemask, &myXGCV);
+}
+
+ static void
+AllocBotShadowGC(Widget w)
+{
+ ScrollbarWidget sbw = (ScrollbarWidget) w;
+ XtGCMask valuemask;
+ XGCValues myXGCV;
+
+ valuemask = GCForeground;
+ myXGCV.foreground = sbw->scrollbar.bot_shadow_pixel;
+ sbw->scrollbar.bot_shadow_GC = XtGetGC(w, valuemask, &myXGCV);
+}
+
+ static void
+_Xaw3dDrawShadows(
+ Widget gw,
+ XEvent *event UNUSED,
+ Region region,
+ int out)
+{
+ XPoint pt[6];
+ ScrollbarWidget sbw = (ScrollbarWidget) gw;
+ Dimension s = sbw->scrollbar.shadow_width;
+ /*
+ * draw the shadows using the core part width and height,
+ * and the scrollbar part shadow_width.
+ *
+ * no point to do anything if the shadow_width is 0 or the
+ * widget has not been realized.
+ */
+ if (s > 0 && XtIsRealized(gw))
+ {
+ Dimension h = sbw->core.height;
+ Dimension w = sbw->core.width;
+ Dimension wms = w - s;
+ Dimension hms = h - s;
+ Display *dpy = XtDisplay (gw);
+ Window win = XtWindow (gw);
+ GC top, bot;
+
+ if (out)
+ {
+ top = sbw->scrollbar.top_shadow_GC;
+ bot = sbw->scrollbar.bot_shadow_GC;
+ }
+ else
+ {
+ top = sbw->scrollbar.bot_shadow_GC;
+ bot = sbw->scrollbar.top_shadow_GC;
+ }
+
+ /* top-left shadow */
+ if ((region == NULL) ||
+ (XRectInRegion (region, 0, 0, w, s) != RectangleOut) ||
+ (XRectInRegion (region, 0, 0, s, h) != RectangleOut))
+ {
+ pt[0].x = 0; pt[0].y = h;
+ pt[1].x = pt[1].y = 0;
+ pt[2].x = w; pt[2].y = 0;
+ pt[3].x = wms; pt[3].y = s;
+ pt[4].x = pt[4].y = s;
+ pt[5].x = s; pt[5].y = hms;
+ XFillPolygon (dpy, win, top, pt, 6, Complex, CoordModeOrigin);
+ }
+
+ /* bottom-right shadow */
+ if ((region == NULL) ||
+ (XRectInRegion (region, 0, hms, w, s) != RectangleOut) ||
+ (XRectInRegion (region, wms, 0, s, h) != RectangleOut))
+ {
+ pt[0].x = 0; pt[0].y = h;
+ pt[1].x = w; pt[1].y = h;
+ pt[2].x = w; pt[2].y = 0;
+ pt[3].x = wms; pt[3].y = s;
+ pt[4].x = wms; pt[4].y = hms;
+ pt[5].x = s; pt[5].y = hms;
+ XFillPolygon (dpy, win, bot, pt, 6, Complex, CoordModeOrigin);
+ }
+ }
+}
+
+
+/*
+ * Set the scroll bar to the given location.
+ */
+ void
+vim_XawScrollbarSetThumb(Widget w, double top, double shown, double max)
+{
+ ScrollbarWidget sbw = (ScrollbarWidget) w;
+
+ if (sbw->scrollbar.scroll_mode == SMODE_CONT) /* if still thumbing */
+ return;
+
+ sbw->scrollbar.max = (max > 1.0) ? 1.0 :
+ (max >= 0.0) ? max : sbw->scrollbar.max;
+
+ sbw->scrollbar.top = (top > sbw->scrollbar.max) ? sbw->scrollbar.max :
+ (top >= 0.0) ? top : sbw->scrollbar.top;
+
+ sbw->scrollbar.shown = (shown > 1.0) ? 1.0 :
+ (shown >= 0.0) ? shown : sbw->scrollbar.shown;
+
+ PaintThumb(sbw);
+}
diff --git a/src/gui_at_sb.h b/src/gui_at_sb.h
new file mode 100644
index 0000000..ce3694c
--- /dev/null
+++ b/src/gui_at_sb.h
@@ -0,0 +1,161 @@
+/* vi:set ts=8 sts=4 sw=4 noet: */
+/* MODIFIED ATHENA SCROLLBAR (USING ARROWHEADS AT ENDS OF TRAVEL) */
+/* Modifications Copyright 1992 by Mitch Trachtenberg */
+/* Rights, permissions, and disclaimer of warranty are as in the */
+/* DEC and MIT notice below. See usage warning in .c file. */
+/*
+ * $XConsortium: ScrollbarP.h,v 1.3 94/04/17 20:12:42 jim Exp $
+ */
+
+
+/***********************************************************
+
+Copyright (c) 1987, 1988 X Consortium
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the X Consortium shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from the X Consortium.
+
+
+Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+#ifndef _Scrollbar_h
+#define _Scrollbar_h
+
+/****************************************************************
+ *
+ * Scrollbar Widget
+ *
+ ****************************************************************/
+
+#include <X11/IntrinsicP.h>
+#include <X11/Xaw/SimpleP.h>
+#include <X11/Xmu/Converters.h>
+
+/*
+ * Most things we need are in StringDefs.h
+ */
+#define XtCMinimumThumb "MinimumThumb"
+#define XtCShown "Shown"
+#define XtCTopOfThumb "TopOfThumb"
+#define XtCMaxOfThumb "MaxOfThumb"
+#define XtCShadowWidth "ShadowWidth"
+#define XtCTopShadowPixel "TopShadowPixel"
+#define XtCBottomShadowPixel "BottomShadowPixel"
+#define XtCLimitThumb "LimitThumb"
+
+#define XtNminimumThumb "minimumThumb"
+#define XtNtopOfThumb "topOfThumb"
+#define XtNmaxOfThumb "maxOfThumb"
+#define XtNshadowWidth "shadowWidth"
+#define XtNtopShadowPixel "topShadowPixel"
+#define XtNbottomShadowPixel "bottomShadowPixel"
+#define XtNlimitThumb "limitThumb"
+
+typedef struct _ScrollbarRec *ScrollbarWidget;
+typedef struct _ScrollbarClassRec *ScrollbarWidgetClass;
+
+extern WidgetClass vim_scrollbarWidgetClass;
+
+extern void vim_XawScrollbarSetThumb(Widget, double, double, double);
+
+typedef struct
+{
+ /* public */
+ Pixel foreground; /* thumb foreground color */
+ XtOrientation orientation; /* horizontal or vertical */
+ XtCallbackList scrollProc; /* proportional scroll */
+ XtCallbackList thumbProc; /* jump (to position) scroll */
+ XtCallbackList jumpProc; /* same as thumbProc but pass data by ref */
+ Pixmap thumb; /* thumb color */
+ float top; /* What percent is above the win's top */
+ float shown; /* What percent is shown in the win */
+ float max; /* Maximum value for top */
+ Dimension length; /* either height or width */
+ Dimension thickness; /* either width or height */
+ Dimension min_thumb; /* minimum size for the thumb. */
+
+ /* private */
+ XtIntervalId timer_id; /* autorepeat timer; remove on destruction */
+ char scroll_mode; /* see below */
+ float scroll_off; /* offset from event to top of thumb */
+ GC gc; /* a (shared) gc */
+ Position topLoc; /* Pixel that corresponds to top */
+ Dimension shownLength; /* Num pixels corresponding to shown */
+
+ /* From 3d widget */
+ Dimension shadow_width;
+ Pixel top_shadow_pixel;
+ Pixel bot_shadow_pixel;
+ Bool limit_thumb; /* limit thumb to inside scrollbar */
+ int top_shadow_contrast;
+ int bot_shadow_contrast;
+ GC top_shadow_GC;
+ GC bot_shadow_GC;
+} ScrollbarPart;
+
+#define SMODE_NONE 0
+#define SMODE_CONT 1
+#define SMODE_PAGE_UP 2
+#define SMODE_PAGE_DOWN 3
+#define SMODE_LINE_UP 4
+#define SMODE_LINE_DOWN 5
+
+#define ONE_LINE_DATA 1
+#define ONE_PAGE_DATA 10
+#define END_PAGE_DATA 9999
+
+typedef struct _ScrollbarRec {
+ CorePart core;
+ SimplePart simple;
+ ScrollbarPart scrollbar;
+} ScrollbarRec;
+
+typedef struct {int empty;} ScrollbarClassPart;
+
+typedef struct _ScrollbarClassRec {
+ CoreClassPart core_class;
+ SimpleClassPart simple_class;
+ ScrollbarClassPart scrollbar_class;
+} ScrollbarClassRec;
+
+extern ScrollbarClassRec vim_scrollbarClassRec;
+
+#endif /* _Scrollbar_h */
diff --git a/src/gui_athena.c b/src/gui_athena.c
new file mode 100644
index 0000000..3620e65
--- /dev/null
+++ b/src/gui_athena.c
@@ -0,0 +1,2292 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ * GUI/Motif support by Robert Webb
+ * Athena port by Bill Foster
+ *
+ * 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.
+ */
+
+#include "vim.h"
+
+#include <X11/StringDefs.h>
+#include <X11/Intrinsic.h>
+#ifdef FEAT_GUI_NEXTAW
+# include <X11/neXtaw/Form.h>
+# include <X11/neXtaw/SimpleMenu.h>
+# include <X11/neXtaw/MenuButton.h>
+# include <X11/neXtaw/SmeBSB.h>
+# include <X11/neXtaw/SmeLine.h>
+# include <X11/neXtaw/Box.h>
+# include <X11/neXtaw/Dialog.h>
+# include <X11/neXtaw/Text.h>
+# include <X11/neXtaw/AsciiText.h>
+# include <X11/neXtaw/Scrollbar.h>
+#else
+# include <X11/Xaw/Form.h>
+# include <X11/Xaw/SimpleMenu.h>
+# include <X11/Xaw/MenuButton.h>
+# include <X11/Xaw/SmeBSB.h>
+# include <X11/Xaw/SmeLine.h>
+# include <X11/Xaw/Box.h>
+# include <X11/Xaw/Dialog.h>
+# include <X11/Xaw/Text.h>
+# include <X11/Xaw/AsciiText.h>
+#endif /* FEAT_GUI_NEXTAW */
+
+#ifndef FEAT_GUI_NEXTAW
+# include "gui_at_sb.h"
+#endif
+
+extern Widget vimShell;
+
+static Widget vimForm = (Widget)0;
+Widget textArea = (Widget)0;
+#ifdef FEAT_MENU
+static Widget menuBar = (Widget)0;
+static XtIntervalId timer = 0; /* 0 = expired, otherwise active */
+
+/* Used to figure out menu ordering */
+static vimmenu_T *a_cur_menu = NULL;
+static Cardinal athena_calculate_ins_pos(Widget);
+
+static void gui_athena_popup_callback(Widget, XtPointer, XtPointer);
+static void gui_athena_delayed_arm_action(Widget, XEvent *, String *,
+ Cardinal *);
+static void gui_athena_popdown_submenus_action(Widget, XEvent *,
+ String *, Cardinal *);
+static XtActionsRec pullAction[2] = {
+ { "menu-delayedpopup", (XtActionProc)gui_athena_delayed_arm_action},
+ { "menu-popdownsubmenus", (XtActionProc)gui_athena_popdown_submenus_action}
+};
+#endif
+
+#ifdef FEAT_TOOLBAR
+static void gui_mch_reset_focus(void);
+static Widget toolBar = (Widget)0;
+#endif
+
+#if defined(FEAT_GUI_DIALOG) || defined(FEAT_MENU)
+static void gui_athena_menu_colors(Widget id);
+#endif
+static void gui_athena_scroll_colors(Widget id);
+
+#ifdef FEAT_MENU
+static XtTranslations popupTrans, parentTrans, menuTrans, supermenuTrans;
+static Pixmap pullerBitmap = None;
+static int puller_width = 0;
+#endif
+
+/*
+ * Scrollbar callback (XtNjumpProc) for when the scrollbar is dragged with the
+ * left or middle mouse button.
+ */
+ static void
+gui_athena_scroll_cb_jump(
+ Widget w UNUSED,
+ XtPointer client_data,
+ XtPointer call_data)
+{
+ scrollbar_T *sb, *sb_info;
+ long value;
+
+ sb = gui_find_scrollbar((long)client_data);
+
+ if (sb == NULL)
+ return;
+ else 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];
+ }
+ else /* Bottom scrollbar */
+ sb_info = sb;
+
+ value = (long)(*((float *)call_data) * (float)(sb_info->max + 1) + 0.001);
+ if (value > sb_info->max)
+ value = sb_info->max;
+
+ gui_drag_scrollbar(sb, value, TRUE);
+}
+
+/*
+ * Scrollbar callback (XtNscrollProc) for paging up or down with the left or
+ * right mouse buttons.
+ */
+ static void
+gui_athena_scroll_cb_scroll(
+ Widget w UNUSED,
+ XtPointer client_data,
+ XtPointer call_data)
+{
+ scrollbar_T *sb, *sb_info;
+ long value;
+ int data = (int)(long)call_data;
+ int page;
+
+ sb = gui_find_scrollbar((long)client_data);
+
+ 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;
+#ifdef FEAT_GUI_NEXTAW
+ if (data < 0)
+ {
+ data = (data - gui.char_height + 1) / gui.char_height;
+ if (data > -sb_info->size)
+ data = -1;
+ else
+ data = -page;
+ }
+ else if (data > 0)
+ {
+ data = (data + gui.char_height - 1) / gui.char_height;
+ if (data < sb_info->size)
+ data = 1;
+ else
+ data = page;
+ }
+#else
+ switch (data)
+ {
+ case ONE_LINE_DATA: data = 1; break;
+ case -ONE_LINE_DATA: data = -1; break;
+ case ONE_PAGE_DATA: data = page; break;
+ case -ONE_PAGE_DATA: data = -page; break;
+ case END_PAGE_DATA: data = sb_info->max; break;
+ case -END_PAGE_DATA: data = -sb_info->max; break;
+ default: data = 0; break;
+ }
+#endif
+ }
+ else /* Bottom scrollbar */
+ {
+ sb_info = sb;
+#ifdef FEAT_GUI_NEXTAW
+ if (data < 0)
+ {
+ data = (data - gui.char_width + 1) / gui.char_width;
+ if (data > -sb->size)
+ data = -1;
+ }
+ else if (data > 0)
+ {
+ data = (data + gui.char_width - 1) / gui.char_width;
+ if (data < sb->size)
+ data = 1;
+ }
+#endif
+ if (data < -1) /* page-width left */
+ {
+ if (sb->size > 8)
+ data = -(sb->size - 5);
+ else
+ data = -sb->size;
+ }
+ else if (data > 1) /* page-width right */
+ {
+ if (sb->size > 8)
+ data = (sb->size - 5);
+ else
+ data = sb->size;
+ }
+ }
+
+ value = sb_info->value + data;
+ if (value > sb_info->max)
+ value = sb_info->max;
+ else if (value < 0)
+ value = 0;
+
+ /* Update the bottom scrollbar an extra time (why is this needed?? */
+ if (sb->wp == NULL) /* Bottom scrollbar */
+ gui_mch_set_scrollbar_thumb(sb, value, sb->size, sb->max);
+
+ gui_drag_scrollbar(sb, value, FALSE);
+}
+
+/*
+ * Create all the Athena widgets necessary.
+ */
+ void
+gui_x11_create_widgets(void)
+{
+ /*
+ * We don't have any borders handled internally by the textArea to worry
+ * about so only skip over the configured border width.
+ */
+ gui.border_offset = gui.border_width;
+
+ /* The form containing all the other widgets */
+ vimForm = XtVaCreateManagedWidget("vimForm",
+ formWidgetClass, vimShell,
+ XtNborderWidth, 0,
+ NULL);
+ gui_athena_scroll_colors(vimForm);
+
+#ifdef FEAT_MENU
+ /* The top menu bar */
+ menuBar = XtVaCreateManagedWidget("menuBar",
+ boxWidgetClass, vimForm,
+ XtNresizable, True,
+ XtNtop, XtChainTop,
+ XtNbottom, XtChainTop,
+ XtNleft, XtChainLeft,
+ XtNright, XtChainRight,
+ XtNinsertPosition, athena_calculate_ins_pos,
+ NULL);
+ gui_athena_menu_colors(menuBar);
+ if (gui.menu_fg_pixel != INVALCOLOR)
+ XtVaSetValues(menuBar, XtNborderColor, gui.menu_fg_pixel, NULL);
+#endif
+
+#ifdef FEAT_TOOLBAR
+ /* Don't create it Managed, it will be managed when creating the first
+ * item. Otherwise an empty toolbar shows up. */
+ toolBar = XtVaCreateWidget("toolBar",
+ boxWidgetClass, vimForm,
+ XtNresizable, True,
+ XtNtop, XtChainTop,
+ XtNbottom, XtChainTop,
+ XtNleft, XtChainLeft,
+ XtNright, XtChainRight,
+ XtNorientation, XtorientHorizontal,
+ XtNhSpace, 1,
+ XtNvSpace, 3,
+ XtNinsertPosition, athena_calculate_ins_pos,
+ NULL);
+ gui_athena_menu_colors(toolBar);
+#endif
+
+ /* The text area. */
+ textArea = XtVaCreateManagedWidget("textArea",
+ coreWidgetClass, vimForm,
+ XtNresizable, True,
+ XtNtop, XtChainTop,
+ XtNbottom, XtChainTop,
+ XtNleft, XtChainLeft,
+ XtNright, XtChainLeft,
+ XtNbackground, gui.back_pixel,
+ XtNborderWidth, 0,
+ NULL);
+
+ /*
+ * Install the callbacks.
+ */
+ gui_x11_callbacks(textArea, vimForm);
+
+#ifdef FEAT_MENU
+ popupTrans = XtParseTranslationTable(
+ "<EnterWindow>: menu-popdownsubmenus() highlight() menu-delayedpopup()\n"
+ "<LeaveWindow>: unhighlight()\n"
+ "<BtnUp>: menu-popdownsubmenus() XtMenuPopdown() notify() unhighlight()\n"
+ "<Motion>: highlight() menu-delayedpopup()");
+ parentTrans = XtParseTranslationTable("<LeaveWindow>: unhighlight()");
+ menuTrans = XtParseTranslationTable(
+ "<EnterWindow>: menu-popdownsubmenus() highlight() menu-delayedpopup()\n"
+ "<LeaveWindow>: menu-popdownsubmenus() XtMenuPopdown() unhighlight()\n"
+ "<BtnUp>: notify() unhighlight()\n"
+ "<BtnMotion>: highlight() menu-delayedpopup()");
+ supermenuTrans = XtParseTranslationTable(
+ "<EnterWindow>: menu-popdownsubmenus() highlight() menu-delayedpopup()\n"
+ "<LeaveWindow>: unhighlight()\n"
+ "<BtnUp>: menu-popdownsubmenus() XtMenuPopdown() notify() unhighlight()\n"
+ "<BtnMotion>: highlight() menu-delayedpopup()");
+
+ XtAppAddActions(XtWidgetToApplicationContext(vimForm), pullAction,
+ XtNumber(pullAction));
+#endif
+
+ /* Pretend we don't have input focus, we will get an event if we do. */
+ gui.in_focus = FALSE;
+}
+
+#ifdef FEAT_MENU
+/*
+ * Calculates the Pixmap based on the size of the current menu font.
+ */
+ static Pixmap
+gui_athena_create_pullright_pixmap(Widget w)
+{
+ Pixmap retval;
+#ifdef FONTSET_ALWAYS
+ XFontSet font = None;
+#else
+ XFontStruct *font = NULL;
+#endif
+
+#ifdef FONTSET_ALWAYS
+ if (gui.menu_fontset == NOFONTSET)
+#else
+ if (gui.menu_font == NOFONT)
+#endif
+ {
+ XrmValue from, to;
+ WidgetList children;
+ Cardinal num_children;
+
+#ifdef FONTSET_ALWAYS
+ from.size = strlen(from.addr = XtDefaultFontSet);
+ to.addr = (XtPointer)&font;
+ to.size = sizeof(XFontSet);
+#else
+ from.size = strlen(from.addr = XtDefaultFont);
+ to.addr = (XtPointer)&font;
+ to.size = sizeof(XFontStruct *);
+#endif
+ /* Assumption: The menuBar children will use the same font as the
+ * pulldown menu items AND they will all be of type
+ * XtNfont.
+ */
+ XtVaGetValues(menuBar, XtNchildren, &children,
+ XtNnumChildren, &num_children,
+ NULL);
+ if (XtConvertAndStore(w ? w :
+ (num_children > 0) ? children[0] : menuBar,
+ XtRString, &from,
+#ifdef FONTSET_ALWAYS
+ XtRFontSet, &to
+#else
+ XtRFontStruct, &to
+#endif
+ ) == False)
+ return None;
+ /* "font" should now contain data */
+ }
+ else
+#ifdef FONTSET_ALWAYS
+ font = (XFontSet)gui.menu_fontset;
+#else
+ font = (XFontStruct *)gui.menu_font;
+#endif
+
+ {
+ int width, height;
+ GC draw_gc, undraw_gc;
+ XGCValues gc_values;
+ XPoint points[3];
+
+#ifdef FONTSET_ALWAYS
+ height = fontset_height2(font);
+#else
+ height = font->max_bounds.ascent + font->max_bounds.descent;
+#endif
+ width = height - 2;
+ puller_width = width + 4;
+ retval = XCreatePixmap(gui.dpy,DefaultRootWindow(gui.dpy),width,
+ height, 1);
+ gc_values.foreground = 1;
+ gc_values.background = 0;
+ draw_gc = XCreateGC(gui.dpy, retval,
+ GCForeground | GCBackground,
+ &gc_values);
+ gc_values.foreground = 0;
+ gc_values.background = 1;
+ undraw_gc = XCreateGC(gui.dpy, retval,
+ GCForeground | GCBackground,
+ &gc_values);
+ points[0].x = 0;
+ points[0].y = 0;
+ points[1].x = width - 1;
+ points[1].y = (height - 1) / 2;
+ points[2].x = 0;
+ points[2].y = height - 1;
+ XFillRectangle(gui.dpy, retval, undraw_gc, 0, 0, height, height);
+ XFillPolygon(gui.dpy, retval, draw_gc, points, XtNumber(points),
+ Convex, CoordModeOrigin);
+ XFreeGC(gui.dpy, draw_gc);
+ XFreeGC(gui.dpy, undraw_gc);
+ }
+ return retval;
+}
+#endif
+
+/*
+ * Called when the GUI is not going to start after all.
+ */
+ void
+gui_x11_destroy_widgets(void)
+{
+ textArea = NULL;
+#ifdef FEAT_MENU
+ menuBar = NULL;
+#endif
+#ifdef FEAT_TOOLBAR
+ toolBar = NULL;
+#endif
+}
+
+#if defined(FEAT_TOOLBAR) || defined(PROTO)
+# include "gui_x11_pm.h"
+# ifdef HAVE_X11_XPM_H
+# include <X11/xpm.h>
+# endif
+
+static void createXpmImages(char_u *path, char **xpm, Pixmap *sen);
+
+/*
+ * Allocated a pixmap for toolbar menu "menu".
+ * Return in "sen".
+ */
+ static void
+get_toolbar_pixmap(vimmenu_T *menu, Pixmap *sen)
+{
+ char_u buf[MAXPATHL]; /* buffer storing expanded pathname */
+ char **xpm = NULL; /* xpm array */
+
+ buf[0] = NUL; /* start with NULL path */
+
+ if (menu->iconfile != NULL)
+ {
+ /* Use the "icon=" argument. */
+ gui_find_iconfile(menu->iconfile, buf, "xpm");
+ createXpmImages(buf, NULL, sen);
+
+ /* If it failed, try using the menu name. */
+ if (*sen == (Pixmap)0 && gui_find_bitmap(menu->name, buf, "xpm") == OK)
+ createXpmImages(buf, NULL, sen);
+ if (*sen != (Pixmap)0)
+ return;
+ }
+
+ if (menu->icon_builtin || gui_find_bitmap(menu->name, buf, "xpm") == FAIL)
+ {
+ if (menu->iconidx >= 0 && menu->iconidx
+ < (int)(sizeof(built_in_pixmaps) / sizeof(built_in_pixmaps[0])))
+ xpm = built_in_pixmaps[menu->iconidx];
+ else
+ xpm = tb_blank_xpm;
+ }
+
+ if (xpm != NULL || buf[0] != NUL)
+ createXpmImages(buf, xpm, sen);
+}
+
+/*
+ * Read an Xpm file, doing color substitutions for the foreground and
+ * background colors. If there is an error reading a color xpm file,
+ * drop back and read the monochrome file. If successful, create the
+ * insensitive Pixmap too.
+ */
+ static void
+createXpmImages(char_u *path, char **xpm, Pixmap *sen)
+{
+ Window rootWindow;
+ XpmAttributes attrs;
+ XpmColorSymbol color[5] =
+ {
+ {"none", "none", 0},
+ {"iconColor1", NULL, 0},
+ {"bottomShadowColor", NULL, 0},
+ {"topShadowColor", NULL, 0},
+ {"selectColor", NULL, 0}
+ };
+ int screenNum;
+ int status;
+ Pixmap mask;
+ Pixmap map;
+
+ gui_mch_get_toolbar_colors(
+ &color[BACKGROUND].pixel,
+ &color[FOREGROUND].pixel,
+ &color[BOTTOM_SHADOW].pixel,
+ &color[TOP_SHADOW].pixel,
+ &color[HIGHLIGHT].pixel);
+
+ /* Setup the color substitution table */
+ attrs.valuemask = XpmColorSymbols;
+ attrs.colorsymbols = color;
+ attrs.numsymbols = 5;
+
+ screenNum = DefaultScreen(gui.dpy);
+ rootWindow = RootWindow(gui.dpy, screenNum);
+
+ /* Create the "sensitive" pixmap */
+ if (xpm != NULL)
+ status = XpmCreatePixmapFromData(gui.dpy, rootWindow, xpm,
+ &map, &mask, &attrs);
+ else
+ status = XpmReadFileToPixmap(gui.dpy, rootWindow, (char *)path,
+ &map, &mask, &attrs);
+ if (status == XpmSuccess && map != 0)
+ {
+ XGCValues gcvalues;
+ GC back_gc;
+ GC mask_gc;
+
+ /* Need to create new Pixmaps with the mask applied. */
+ gcvalues.foreground = color[BACKGROUND].pixel;
+ back_gc = XCreateGC(gui.dpy, map, GCForeground, &gcvalues);
+ mask_gc = XCreateGC(gui.dpy, map, GCForeground, &gcvalues);
+ XSetClipMask(gui.dpy, mask_gc, mask);
+
+ /* Create the "sensitive" pixmap. */
+ *sen = XCreatePixmap(gui.dpy, rootWindow,
+ attrs.width, attrs.height,
+ DefaultDepth(gui.dpy, screenNum));
+ XFillRectangle(gui.dpy, *sen, back_gc, 0, 0,
+ attrs.width, attrs.height);
+ XCopyArea(gui.dpy, map, *sen, mask_gc, 0, 0,
+ attrs.width, attrs.height, 0, 0);
+
+ XFreeGC(gui.dpy, back_gc);
+ XFreeGC(gui.dpy, mask_gc);
+ XFreePixmap(gui.dpy, map);
+ }
+ else
+ *sen = 0;
+
+ XpmFreeAttributes(&attrs);
+}
+
+ void
+gui_mch_set_toolbar_pos(
+ int x,
+ int y,
+ int w,
+ int h)
+{
+ Dimension border;
+ int height;
+
+ if (!XtIsManaged(toolBar)) /* nothing to do */
+ return;
+ XtUnmanageChild(toolBar);
+ XtVaGetValues(toolBar,
+ XtNborderWidth, &border,
+ NULL);
+ height = h - 2 * border;
+ if (height < 0)
+ height = 1;
+ XtVaSetValues(toolBar,
+ XtNhorizDistance, x,
+ XtNvertDistance, y,
+ XtNwidth, w - 2 * border,
+ XtNheight, height,
+ NULL);
+ XtManageChild(toolBar);
+}
+#endif
+
+ void
+gui_mch_set_text_area_pos(
+ int x,
+ int y,
+ int w,
+ int h)
+{
+ XtUnmanageChild(textArea);
+ XtVaSetValues(textArea,
+ XtNhorizDistance, x,
+ XtNvertDistance, y,
+ XtNwidth, w,
+ XtNheight, h,
+ NULL);
+ XtManageChild(textArea);
+#ifdef FEAT_TOOLBAR
+ /* Give keyboard focus to the textArea instead of the toolbar. */
+ gui_mch_reset_focus();
+#endif
+}
+
+#ifdef FEAT_TOOLBAR
+/*
+ * A toolbar button has been pushed; now reset the input focus
+ * such that the user can type page up/down etc. and have the
+ * input go to the editor window, not the button
+ */
+ static void
+gui_mch_reset_focus(void)
+{
+ XtSetKeyboardFocus(vimForm, textArea);
+}
+#endif
+
+
+ void
+gui_x11_set_back_color(void)
+{
+ if (textArea != NULL)
+ XtVaSetValues(textArea,
+ XtNbackground, gui.back_pixel,
+ NULL);
+}
+
+#if defined(FEAT_MENU) || defined(PROTO)
+/*
+ * Menu stuff.
+ */
+
+static char_u *make_pull_name(char_u * name);
+static Widget get_popup_entry(Widget w);
+static Widget submenu_widget(Widget);
+static Boolean has_submenu(Widget);
+static void gui_mch_submenu_change(vimmenu_T *mp, int colors);
+static void gui_athena_menu_font(Widget id);
+
+ void
+gui_mch_enable_menu(int flag)
+{
+ if (flag)
+ {
+ XtManageChild(menuBar);
+# ifdef FEAT_TOOLBAR
+ if (XtIsManaged(toolBar))
+ {
+ XtVaSetValues(toolBar,
+ XtNvertDistance, gui.menu_height,
+ NULL);
+ XtVaSetValues(textArea,
+ XtNvertDistance, gui.menu_height + gui.toolbar_height,
+ NULL);
+ }
+# endif
+ }
+ else
+ {
+ XtUnmanageChild(menuBar);
+# ifdef FEAT_TOOLBAR
+ if (XtIsManaged(toolBar))
+ {
+ XtVaSetValues(toolBar,
+ XtNvertDistance, 0,
+ NULL);
+ }
+# endif
+ }
+}
+
+ void
+gui_mch_set_menu_pos(
+ int x,
+ int y,
+ int w,
+ int h)
+{
+ Dimension border;
+ int height;
+
+ XtUnmanageChild(menuBar);
+ XtVaGetValues(menuBar, XtNborderWidth, &border, NULL);
+ /* avoid trouble when there are no menu items, and h is 1 */
+ height = h - 2 * border;
+ if (height < 0)
+ height = 1;
+ XtVaSetValues(menuBar,
+ XtNhorizDistance, x,
+ XtNvertDistance, y,
+ XtNwidth, w - 2 * border,
+ XtNheight, height,
+ NULL);
+ XtManageChild(menuBar);
+}
+
+/*
+ * Used to calculate the insertion position of a widget with respect to its
+ * neighbors.
+ *
+ * Valid range of return values is: 0 (beginning of children) to
+ * numChildren (end of children).
+ */
+ static Cardinal
+athena_calculate_ins_pos(Widget widget)
+{
+ /* Assume that if the parent of the vimmenu_T is NULL, then we can get
+ * to this menu by traversing "next", starting at "root_menu".
+ *
+ * This holds true for popup menus, toolbar, and toplevel menu items.
+ */
+
+ /* Popup menus: "id" is NULL. Only submenu_id is valid */
+
+ /* Menus that are not toplevel: "parent" will be non-NULL, "id" &
+ * "submenu_id" will be non-NULL.
+ */
+
+ /* Toplevel menus: "parent" is NULL, id is the widget of the menu item */
+
+ WidgetList children;
+ Cardinal num_children = 0;
+ int retval;
+ Arg args[2];
+ int n = 0;
+ int i;
+
+ XtSetArg(args[n], XtNchildren, &children); n++;
+ XtSetArg(args[n], XtNnumChildren, &num_children); n++;
+ XtGetValues(XtParent(widget), args, n);
+
+ retval = num_children;
+ for (i = 0; i < (int)num_children; ++i)
+ {
+ Widget current = children[i];
+ vimmenu_T *menu = NULL;
+
+ for (menu = (a_cur_menu->parent == NULL)
+ ? root_menu : a_cur_menu->parent->children;
+ menu != NULL;
+ menu = menu->next)
+ if (current == menu->id
+ && a_cur_menu->priority < menu->priority
+ && i < retval)
+ retval = i;
+ }
+ return retval;
+}
+
+ void
+gui_mch_add_menu(vimmenu_T *menu, int idx UNUSED)
+{
+ char_u *pullright_name;
+ Dimension height, space, border;
+ vimmenu_T *parent = menu->parent;
+
+ a_cur_menu = menu;
+ if (parent == NULL)
+ {
+ if (menu_is_popup(menu->dname))
+ {
+ menu->submenu_id = XtVaCreatePopupShell((char *)menu->dname,
+ simpleMenuWidgetClass, vimShell,
+ XtNinsertPosition, athena_calculate_ins_pos,
+ XtNtranslations, popupTrans,
+ NULL);
+ gui_athena_menu_colors(menu->submenu_id);
+ }
+ else if (menu_is_menubar(menu->dname))
+ {
+ menu->id = XtVaCreateManagedWidget((char *)menu->dname,
+ menuButtonWidgetClass, menuBar,
+ XtNmenuName, menu->dname,
+#ifdef FONTSET_ALWAYS
+ XtNinternational, True,
+#endif
+ NULL);
+ if (menu->id == (Widget)0)
+ return;
+ gui_athena_menu_colors(menu->id);
+ gui_athena_menu_font(menu->id);
+
+ menu->submenu_id = XtVaCreatePopupShell((char *)menu->dname,
+ simpleMenuWidgetClass, menu->id,
+ XtNinsertPosition, athena_calculate_ins_pos,
+ XtNtranslations, supermenuTrans,
+ NULL);
+ gui_athena_menu_colors(menu->submenu_id);
+ gui_athena_menu_font(menu->submenu_id);
+
+ /* Don't update the menu height when it was set at a fixed value */
+ if (!gui.menu_height_fixed)
+ {
+ /*
+ * When we add a top-level item to the menu bar, we can figure
+ * out how high the menu bar should be.
+ */
+ XtVaGetValues(menuBar,
+ XtNvSpace, &space,
+ XtNborderWidth, &border,
+ NULL);
+ XtVaGetValues(menu->id,
+ XtNheight, &height,
+ NULL);
+ gui.menu_height = height + 2 * (space + border);
+ }
+ }
+ }
+ else if (parent->submenu_id != (Widget)0)
+ {
+ menu->id = XtVaCreateManagedWidget((char *)menu->dname,
+ smeBSBObjectClass, parent->submenu_id,
+ XtNlabel, menu->dname,
+#ifdef FONTSET_ALWAYS
+ XtNinternational, True,
+#endif
+ NULL);
+ if (menu->id == (Widget)0)
+ return;
+ if (pullerBitmap == None)
+ pullerBitmap = gui_athena_create_pullright_pixmap(menu->id);
+
+ XtVaSetValues(menu->id, XtNrightBitmap, pullerBitmap,
+ NULL);
+ /* If there are other menu items that are not pulldown menus,
+ * we need to adjust the right margins of those, too.
+ */
+ {
+ WidgetList children;
+ Cardinal num_children;
+ int i;
+
+ XtVaGetValues(parent->submenu_id, XtNchildren, &children,
+ XtNnumChildren, &num_children,
+ NULL);
+ for (i = 0; i < (int)num_children; ++i)
+ {
+ XtVaSetValues(children[i],
+ XtNrightMargin, puller_width,
+ NULL);
+ }
+ }
+ gui_athena_menu_colors(menu->id);
+ gui_athena_menu_font(menu->id);
+
+ pullright_name = make_pull_name(menu->dname);
+ menu->submenu_id = XtVaCreatePopupShell((char *)pullright_name,
+ simpleMenuWidgetClass, parent->submenu_id,
+ XtNtranslations, menuTrans,
+ NULL);
+ gui_athena_menu_colors(menu->submenu_id);
+ gui_athena_menu_font(menu->submenu_id);
+ vim_free(pullright_name);
+ XtAddCallback(menu->submenu_id, XtNpopupCallback,
+ gui_athena_popup_callback, (XtPointer)menu);
+
+ if (parent->parent != NULL)
+ XtOverrideTranslations(parent->submenu_id, parentTrans);
+ }
+ a_cur_menu = NULL;
+}
+
+/* Used to determine whether a SimpleMenu has pulldown entries.
+ *
+ * "id" is the parent of the menu items.
+ * Ignore widget "ignore" in the pane.
+ */
+ static Boolean
+gui_athena_menu_has_submenus(Widget id, Widget ignore)
+{
+ WidgetList children;
+ Cardinal num_children;
+ int i;
+
+ XtVaGetValues(id, XtNchildren, &children,
+ XtNnumChildren, &num_children,
+ NULL);
+ for (i = 0; i < (int)num_children; ++i)
+ {
+ if (children[i] == ignore)
+ continue;
+ if (has_submenu(children[i]))
+ return True;
+ }
+ return False;
+}
+
+ static void
+gui_athena_menu_font(Widget id)
+{
+#ifdef FONTSET_ALWAYS
+ if (gui.menu_fontset != NOFONTSET)
+ {
+ if (XtIsManaged(id))
+ {
+ XtUnmanageChild(id);
+ XtVaSetValues(id, XtNfontSet, gui.menu_fontset, NULL);
+ /* We should force the widget to recalculate its
+ * geometry now. */
+ XtManageChild(id);
+ }
+ else
+ XtVaSetValues(id, XtNfontSet, gui.menu_fontset, NULL);
+ if (has_submenu(id))
+ XtVaSetValues(id, XtNrightBitmap, pullerBitmap, NULL);
+ }
+#else
+ int managed = FALSE;
+
+ if (gui.menu_font != NOFONT)
+ {
+ if (XtIsManaged(id))
+ {
+ XtUnmanageChild(id);
+ managed = TRUE;
+ }
+
+# ifdef FEAT_XFONTSET
+ if (gui.fontset != NOFONTSET)
+ XtVaSetValues(id, XtNfontSet, gui.menu_font, NULL);
+ else
+# endif
+ XtVaSetValues(id, XtNfont, gui.menu_font, NULL);
+ if (has_submenu(id))
+ XtVaSetValues(id, XtNrightBitmap, pullerBitmap, NULL);
+
+ /* Force the widget to recalculate its geometry now. */
+ if (managed)
+ XtManageChild(id);
+ }
+#endif
+}
+
+
+ void
+gui_mch_new_menu_font(void)
+{
+ Pixmap oldpuller = None;
+
+ if (menuBar == (Widget)0)
+ return;
+
+ if (pullerBitmap != None)
+ {
+ oldpuller = pullerBitmap;
+ pullerBitmap = gui_athena_create_pullright_pixmap(NULL);
+ }
+ gui_mch_submenu_change(root_menu, FALSE);
+
+ {
+ /* Iterate through the menubar menu items and get the height of
+ * each one. The menu bar height is set to the maximum of all
+ * the heights.
+ */
+ vimmenu_T *mp;
+ int max_height = 9999;
+
+ for (mp = root_menu; mp != NULL; mp = mp->next)
+ {
+ if (menu_is_menubar(mp->dname))
+ {
+ Dimension height;
+
+ XtVaGetValues(mp->id,
+ XtNheight, &height,
+ NULL);
+ if (height < max_height)
+ max_height = height;
+ }
+ }
+ if (max_height != 9999)
+ {
+ /* Don't update the menu height when it was set at a fixed value */
+ if (!gui.menu_height_fixed)
+ {
+ Dimension space, border;
+
+ XtVaGetValues(menuBar,
+ XtNvSpace, &space,
+ XtNborderWidth, &border,
+ NULL);
+ gui.menu_height = max_height + 2 * (space + border);
+ }
+ }
+ }
+ /* Now, to simulate the window being resized. Only, this
+ * will resize the window to its current state.
+ *
+ * There has to be a better way, but I do not see one at this time.
+ * (David Harrison)
+ */
+ {
+ Position w, h;
+
+ XtVaGetValues(vimShell,
+ XtNwidth, &w,
+ XtNheight, &h,
+ NULL);
+ gui_resize_shell(w, h
+#ifdef FEAT_XIM
+ - xim_get_status_area_height()
+#endif
+ );
+ }
+ gui_set_shellsize(FALSE, TRUE, RESIZE_VERT);
+ ui_new_shellsize();
+ if (oldpuller != None)
+ XFreePixmap(gui.dpy, oldpuller);
+}
+
+#if defined(FEAT_BEVAL_GUI) || defined(PROTO)
+ void
+gui_mch_new_tooltip_font(void)
+{
+# ifdef FEAT_TOOLBAR
+ vimmenu_T *menu;
+
+ if (toolBar == (Widget)0)
+ return;
+
+ menu = gui_find_menu((char_u *)"ToolBar");
+ if (menu != NULL)
+ gui_mch_submenu_change(menu, FALSE);
+# endif
+}
+
+ void
+gui_mch_new_tooltip_colors(void)
+{
+# ifdef FEAT_TOOLBAR
+ vimmenu_T *menu;
+
+ if (toolBar == (Widget)0)
+ return;
+
+ menu = gui_find_menu((char_u *)"ToolBar");
+ if (menu != NULL)
+ gui_mch_submenu_change(menu, TRUE);
+# endif
+}
+#endif
+
+ static void
+gui_mch_submenu_change(
+ vimmenu_T *menu,
+ int colors) /* TRUE for colors, FALSE for font */
+{
+ vimmenu_T *mp;
+
+ for (mp = menu; mp != NULL; mp = mp->next)
+ {
+ if (mp->id != (Widget)0)
+ {
+ if (colors)
+ {
+ gui_athena_menu_colors(mp->id);
+#ifdef FEAT_TOOLBAR
+ /* For a toolbar item: Free the pixmap and allocate a new one,
+ * so that the background color is right. */
+ if (mp->image != (Pixmap)0)
+ {
+ XFreePixmap(gui.dpy, mp->image);
+ get_toolbar_pixmap(mp, &mp->image);
+ if (mp->image != (Pixmap)0)
+ XtVaSetValues(mp->id, XtNbitmap, mp->image, NULL);
+ }
+
+# ifdef FEAT_BEVAL_GUI
+ /* If we have a tooltip, then we need to change its colors */
+ if (mp->tip != NULL)
+ {
+ Arg args[2];
+
+ args[0].name = XtNbackground;
+ args[0].value = gui.tooltip_bg_pixel;
+ args[1].name = XtNforeground;
+ args[1].value = gui.tooltip_fg_pixel;
+ XtSetValues(mp->tip->balloonLabel, &args[0], XtNumber(args));
+ }
+# endif
+#endif
+ }
+ else
+ {
+ gui_athena_menu_font(mp->id);
+#ifdef FEAT_BEVAL_GUI
+ /* If we have a tooltip, then we need to change its font */
+ /* Assume XtNinternational == True (in createBalloonEvalWindow)
+ */
+ if (mp->tip != NULL)
+ {
+ Arg args[1];
+
+ args[0].name = XtNfontSet;
+ args[0].value = (XtArgVal)gui.tooltip_fontset;
+ XtSetValues(mp->tip->balloonLabel, &args[0], XtNumber(args));
+ }
+#endif
+ }
+ }
+
+ if (mp->children != NULL)
+ {
+ /* Set the colors/font for the tear off widget */
+ if (mp->submenu_id != (Widget)0)
+ {
+ if (colors)
+ gui_athena_menu_colors(mp->submenu_id);
+ else
+ gui_athena_menu_font(mp->submenu_id);
+ }
+ /* Set the colors for the children */
+ gui_mch_submenu_change(mp->children, colors);
+ }
+ }
+}
+
+/*
+ * Make a submenu name into a pullright name.
+ * Replace '.' by '_', can't include '.' in the submenu name.
+ */
+ static char_u *
+make_pull_name(char_u * name)
+{
+ char_u *pname;
+ char_u *p;
+
+ pname = vim_strnsave(name, STRLEN(name) + strlen("-pullright"));
+ if (pname != NULL)
+ {
+ strcat((char *)pname, "-pullright");
+ while ((p = vim_strchr(pname, '.')) != NULL)
+ *p = '_';
+ }
+ return pname;
+}
+
+ void
+gui_mch_add_menu_item(vimmenu_T *menu, int idx UNUSED)
+{
+ vimmenu_T *parent = menu->parent;
+
+ a_cur_menu = menu;
+# ifdef FEAT_TOOLBAR
+ if (menu_is_toolbar(parent->name))
+ {
+ WidgetClass type;
+ int n;
+ Arg args[21];
+
+ n = 0;
+ if (menu_is_separator(menu->name))
+ {
+ XtSetArg(args[n], XtNlabel, ""); n++;
+ XtSetArg(args[n], XtNborderWidth, 0); n++;
+ }
+ else
+ {
+ get_toolbar_pixmap(menu, &menu->image);
+ XtSetArg(args[n], XtNlabel, menu->dname); n++;
+ XtSetArg(args[n], XtNinternalHeight, 1); n++;
+ XtSetArg(args[n], XtNinternalWidth, 1); n++;
+ XtSetArg(args[n], XtNborderWidth, 1); n++;
+ if (menu->image != 0)
+ XtSetArg(args[n], XtNbitmap, menu->image); n++;
+ }
+ XtSetArg(args[n], XtNhighlightThickness, 0); n++;
+ type = commandWidgetClass;
+ /* TODO: figure out the position in the toolbar?
+ * This currently works fine for the default toolbar, but
+ * what if we add/remove items during later runtime?
+ */
+
+ /* NOTE: "idx" isn't used here. The position is calculated by
+ * athena_calculate_ins_pos(). The position it calculates
+ * should be equal to "idx".
+ */
+ /* TODO: Could we just store "idx" and use that as the child
+ * placement?
+ */
+
+ if (menu->id == NULL)
+ {
+ menu->id = XtCreateManagedWidget((char *)menu->dname,
+ type, toolBar, args, n);
+ XtAddCallback(menu->id,
+ XtNcallback, gui_x11_menu_cb, menu);
+ }
+ else
+ XtSetValues(menu->id, args, n);
+ gui_athena_menu_colors(menu->id);
+
+#ifdef FEAT_BEVAL_GUI
+ gui_mch_menu_set_tip(menu);
+#endif
+
+ menu->parent = parent;
+ menu->submenu_id = NULL;
+ if (!XtIsManaged(toolBar)
+ && vim_strchr(p_go, GO_TOOLBAR) != NULL)
+ gui_mch_show_toolbar(TRUE);
+ gui.toolbar_height = gui_mch_compute_toolbar_height();
+ return;
+ } /* toolbar menu item */
+# endif
+
+ /* Add menu separator */
+ if (menu_is_separator(menu->name))
+ {
+ menu->submenu_id = (Widget)0;
+ menu->id = XtVaCreateManagedWidget((char *)menu->dname,
+ smeLineObjectClass, parent->submenu_id,
+ NULL);
+ if (menu->id == (Widget)0)
+ return;
+ gui_athena_menu_colors(menu->id);
+ }
+ else
+ {
+ if (parent != NULL && parent->submenu_id != (Widget)0)
+ {
+ menu->submenu_id = (Widget)0;
+ menu->id = XtVaCreateManagedWidget((char *)menu->dname,
+ smeBSBObjectClass, parent->submenu_id,
+ XtNlabel, menu->dname,
+#ifdef FONTSET_ALWAYS
+ XtNinternational, True,
+#endif
+ NULL);
+ if (menu->id == (Widget)0)
+ return;
+
+ /* If there are other "pulldown" items in this pane, then adjust
+ * the right margin to accommodate the arrow pixmap, otherwise
+ * the right margin will be the same as the left margin.
+ */
+ {
+ Dimension left_margin;
+
+ XtVaGetValues(menu->id, XtNleftMargin, &left_margin, NULL);
+ XtVaSetValues(menu->id, XtNrightMargin,
+ gui_athena_menu_has_submenus(parent->submenu_id, NULL) ?
+ puller_width :
+ left_margin,
+ NULL);
+ }
+
+ gui_athena_menu_colors(menu->id);
+ gui_athena_menu_font(menu->id);
+ XtAddCallback(menu->id, XtNcallback, gui_x11_menu_cb,
+ (XtPointer)menu);
+ }
+ }
+ a_cur_menu = NULL;
+}
+
+#if defined(FEAT_TOOLBAR) || defined(PROTO)
+ void
+gui_mch_show_toolbar(int showit)
+{
+ Cardinal numChildren; /* how many children toolBar has */
+
+ if (toolBar == (Widget)0)
+ return;
+ XtVaGetValues(toolBar, XtNnumChildren, &numChildren, NULL);
+ if (showit && numChildren > 0)
+ {
+ /* Assume that we want to show the toolbar if p_toolbar contains valid
+ * option settings, therefore p_toolbar must not be NULL.
+ */
+ WidgetList children;
+
+ XtVaGetValues(toolBar, XtNchildren, &children, NULL);
+ {
+ void (*action)(BalloonEval *);
+ int text = 0;
+
+ if (strstr((const char *)p_toolbar, "tooltips"))
+ action = &gui_mch_enable_beval_area;
+ else
+ action = &gui_mch_disable_beval_area;
+ if (strstr((const char *)p_toolbar, "text"))
+ text = 1;
+ else if (strstr((const char *)p_toolbar, "icons"))
+ text = -1;
+ if (text != 0)
+ {
+ vimmenu_T *toolbar;
+ vimmenu_T *cur;
+
+ for (toolbar = root_menu; toolbar; toolbar = toolbar->next)
+ if (menu_is_toolbar(toolbar->dname))
+ break;
+ /* Assumption: toolbar is NULL if there is no toolbar,
+ * otherwise it contains the toolbar menu structure.
+ *
+ * Assumption: "numChildren" == the number of items in the list
+ * of items beginning with toolbar->children.
+ */
+ if (toolbar)
+ {
+ for (cur = toolbar->children; cur; cur = cur->next)
+ {
+ Arg args[2];
+ int n = 0;
+
+ /* Enable/Disable tooltip (OK to enable while currently
+ * enabled)
+ */
+ if (cur->tip != NULL)
+ (*action)(cur->tip);
+ if (text == 1)
+ {
+ XtSetArg(args[n], XtNbitmap, None);
+ n++;
+ XtSetArg(args[n], XtNlabel,
+ menu_is_separator(cur->name) ? "" :
+ (char *)cur->dname);
+ n++;
+ }
+ else
+ {
+ XtSetArg(args[n], XtNbitmap, cur->image);
+ n++;
+ XtSetArg(args[n], XtNlabel, (cur->image == None) ?
+ menu_is_separator(cur->name) ?
+ "" :
+ (char *)cur->dname
+ :
+ (char *)None);
+ n++;
+ }
+ if (cur->id != NULL)
+ {
+ XtUnmanageChild(cur->id);
+ XtSetValues(cur->id, args, n);
+ XtManageChild(cur->id);
+ }
+ }
+ }
+ }
+ }
+ gui.toolbar_height = gui_mch_compute_toolbar_height();
+ XtManageChild(toolBar);
+ if (XtIsManaged(menuBar))
+ {
+ XtVaSetValues(textArea,
+ XtNvertDistance, gui.toolbar_height + gui.menu_height,
+ NULL);
+ XtVaSetValues(toolBar,
+ XtNvertDistance, gui.menu_height,
+ NULL);
+ }
+ else
+ {
+ XtVaSetValues(textArea,
+ XtNvertDistance, gui.toolbar_height,
+ NULL);
+ XtVaSetValues(toolBar,
+ XtNvertDistance, 0,
+ NULL);
+ }
+ }
+ else
+ {
+ gui.toolbar_height = 0;
+ if (XtIsManaged(menuBar))
+ XtVaSetValues(textArea,
+ XtNvertDistance, gui.menu_height,
+ NULL);
+ else
+ XtVaSetValues(textArea,
+ XtNvertDistance, 0,
+ NULL);
+
+ XtUnmanageChild(toolBar);
+ }
+ gui_set_shellsize(FALSE, FALSE, RESIZE_VERT);
+}
+
+
+ int
+gui_mch_compute_toolbar_height(void)
+{
+ Dimension height; /* total Toolbar height */
+ Dimension whgt; /* height of each widget */
+ Dimension marginHeight; /* XmNmarginHeight of toolBar */
+ Dimension shadowThickness; /* thickness of Xtparent(toolBar) */
+ WidgetList children; /* list of toolBar's children */
+ Cardinal numChildren; /* how many children toolBar has */
+ int i;
+
+ height = 0;
+ shadowThickness = 0;
+ marginHeight = 0;
+ if (toolBar != (Widget)0)
+ {
+ XtVaGetValues(toolBar,
+ XtNborderWidth, &shadowThickness,
+ XtNvSpace, &marginHeight,
+ XtNchildren, &children,
+ XtNnumChildren, &numChildren,
+ NULL);
+ for (i = 0; i < (int)numChildren; i++)
+ {
+ whgt = 0;
+
+ XtVaGetValues(children[i], XtNheight, &whgt, NULL);
+ if (height < whgt)
+ height = whgt;
+ }
+ }
+
+ return (int)(height + (marginHeight << 1) + (shadowThickness << 1));
+}
+
+ void
+gui_mch_get_toolbar_colors(
+ Pixel *bgp,
+ Pixel *fgp,
+ Pixel *bsp,
+ Pixel *tsp,
+ Pixel *hsp)
+{
+ XtVaGetValues(toolBar, XtNbackground, bgp, XtNborderColor, fgp, NULL);
+ *bsp = *bgp;
+ *tsp = *fgp;
+ *hsp = *tsp;
+}
+#endif
+
+
+ void
+gui_mch_toggle_tearoffs(int enable UNUSED)
+{
+ /* no tearoff menus */
+}
+
+ void
+gui_mch_new_menu_colors(void)
+{
+ if (menuBar == (Widget)0)
+ return;
+ if (gui.menu_fg_pixel != INVALCOLOR)
+ XtVaSetValues(menuBar, XtNborderColor, gui.menu_fg_pixel, NULL);
+ gui_athena_menu_colors(menuBar);
+#ifdef FEAT_TOOLBAR
+ gui_athena_menu_colors(toolBar);
+#endif
+
+ gui_mch_submenu_change(root_menu, TRUE);
+}
+
+/*
+ * Destroy the machine specific menu widget.
+ */
+ void
+gui_mch_destroy_menu(vimmenu_T *menu)
+{
+ Widget parent;
+
+ /* There is no item for the toolbar. */
+ if (menu->id == (Widget)0)
+ return;
+
+ parent = XtParent(menu->id);
+
+ /* When removing the last "pulldown" menu item from a pane, adjust the
+ * right margins of the remaining widgets.
+ */
+ if (menu->submenu_id != (Widget)0)
+ {
+ /* Go through the menu items in the parent of this item and
+ * adjust their margins, if necessary.
+ * This takes care of the case when we delete the last menu item in a
+ * pane that has a submenu. In this case, there will be no arrow
+ * pixmaps shown anymore.
+ */
+ {
+ WidgetList children;
+ Cardinal num_children;
+ int i;
+ Dimension right_margin = 0;
+ Boolean get_left_margin = False;
+
+ XtVaGetValues(parent, XtNchildren, &children,
+ XtNnumChildren, &num_children,
+ NULL);
+ if (gui_athena_menu_has_submenus(parent, menu->id))
+ right_margin = puller_width;
+ else
+ get_left_margin = True;
+
+ for (i = 0; i < (int)num_children; ++i)
+ {
+ if (children[i] == menu->id)
+ continue;
+ if (get_left_margin == True)
+ {
+ Dimension left_margin;
+
+ XtVaGetValues(children[i], XtNleftMargin, &left_margin,
+ NULL);
+ XtVaSetValues(children[i], XtNrightMargin, left_margin,
+ NULL);
+ }
+ else
+ XtVaSetValues(children[i], XtNrightMargin, right_margin,
+ NULL);
+ }
+ }
+ }
+ /* Please be sure to destroy the parent widget first (i.e. menu->id).
+ *
+ * This code should be basically identical to that in the file gui_motif.c
+ * because they are both Xt based.
+ */
+ if (menu->id != (Widget)0)
+ {
+ Cardinal num_children;
+ Dimension height, space, border;
+
+ XtVaGetValues(menuBar,
+ XtNvSpace, &space,
+ XtNborderWidth, &border,
+ NULL);
+ XtVaGetValues(menu->id,
+ XtNheight, &height,
+ NULL);
+#if defined(FEAT_TOOLBAR) && defined(FEAT_BEVAL_GUI)
+ if (parent == toolBar && menu->tip != NULL)
+ {
+ /* We try to destroy this before the actual menu, because there are
+ * callbacks, etc. that will be unregistered during the tooltip
+ * destruction.
+ *
+ * If you call "gui_mch_destroy_beval_area()" after destroying
+ * menu->id, then the tooltip's window will have already been
+ * deallocated by Xt, and unknown behaviour will ensue (probably
+ * a core dump).
+ */
+ gui_mch_destroy_beval_area(menu->tip);
+ menu->tip = NULL;
+ }
+#endif
+ /*
+ * This is a hack to stop the Athena simpleMenuWidget from getting a
+ * BadValue error when a menu's last child is destroyed. We check to
+ * see if this is the last child and if so, don't delete it. The parent
+ * will be deleted soon anyway, and it will delete its children like
+ * all good widgets do.
+ */
+ /* NOTE: The cause of the BadValue X Protocol Error is because when the
+ * last child is destroyed, it is first unmanaged, thus causing a
+ * geometry resize request from the parent Shell widget.
+ * Since the Shell widget has no more children, it is resized to have
+ * width/height of 0. XConfigureWindow() is then called with the
+ * width/height of 0, which generates the BadValue.
+ *
+ * This happens in phase two of the widget destruction process.
+ */
+ {
+ if (parent != menuBar
+#ifdef FEAT_TOOLBAR
+ && parent != toolBar
+#endif
+ )
+ {
+ XtVaGetValues(parent, XtNnumChildren, &num_children, NULL);
+ if (num_children > 1)
+ XtDestroyWidget(menu->id);
+ }
+ else
+ XtDestroyWidget(menu->id);
+ menu->id = (Widget)0;
+ }
+
+ if (parent == menuBar)
+ {
+ if (!gui.menu_height_fixed)
+ gui.menu_height = height + 2 * (space + border);
+ }
+#ifdef FEAT_TOOLBAR
+ else if (parent == toolBar)
+ {
+ /* When removing last toolbar item, don't display the toolbar. */
+ XtVaGetValues(toolBar, XtNnumChildren, &num_children, NULL);
+ if (num_children == 0)
+ gui_mch_show_toolbar(FALSE);
+ else
+ gui.toolbar_height = gui_mch_compute_toolbar_height();
+ }
+#endif
+ }
+ if (menu->submenu_id != (Widget)0)
+ {
+ XtDestroyWidget(menu->submenu_id);
+ menu->submenu_id = (Widget)0;
+ }
+}
+
+ static void
+gui_athena_menu_timeout(
+ XtPointer client_data,
+ XtIntervalId *id UNUSED)
+{
+ Widget w = (Widget)client_data;
+ Widget popup;
+
+ timer = 0;
+ if (XtIsSubclass(w,smeBSBObjectClass))
+ {
+ Pixmap p;
+
+ XtVaGetValues(w, XtNrightBitmap, &p, NULL);
+ if ((p != None) && (p != XtUnspecifiedPixmap))
+ {
+ /* We are dealing with an item that has a submenu */
+ popup = get_popup_entry(XtParent(w));
+ if (popup == (Widget)0)
+ return;
+ XtPopup(popup, XtGrabNonexclusive);
+ }
+ }
+}
+
+/* This routine is used to calculate the position (in screen coordinates)
+ * where a submenu should appear relative to the menu entry that popped it
+ * up. It should appear even with and just slightly to the left of the
+ * rightmost end of the menu entry that caused the popup.
+ *
+ * This is called when XtPopup() is called.
+ */
+ static void
+gui_athena_popup_callback(
+ Widget w,
+ XtPointer client_data,
+ XtPointer call_data UNUSED)
+{
+ /* Assumption: XtIsSubclass(XtParent(w),simpleMenuWidgetClass) */
+ vimmenu_T *menu = (vimmenu_T *)client_data;
+ Dimension width;
+ Position root_x, root_y;
+
+ /* First, popdown any siblings that may have menus popped up */
+ {
+ vimmenu_T *i;
+
+ for (i = menu->parent->children; i != NULL; i = i->next)
+ {
+ if (i->submenu_id != NULL && XtIsManaged(i->submenu_id))
+ XtPopdown(i->submenu_id);
+ }
+ }
+ XtVaGetValues(XtParent(w),
+ XtNwidth, &width,
+ NULL);
+ /* Assumption: XawSimpleMenuGetActiveEntry(XtParent(w)) == menu->id */
+ /* i.e. This IS the active entry */
+ XtTranslateCoords(menu->id,width - 5, 0, &root_x, &root_y);
+ XtVaSetValues(w, XtNx, root_x,
+ XtNy, root_y,
+ NULL);
+}
+
+ static void
+gui_athena_popdown_submenus_action(
+ Widget w,
+ XEvent *event,
+ String *args,
+ Cardinal *nargs)
+{
+ WidgetList children;
+ Cardinal num_children;
+
+ XtVaGetValues(w, XtNchildren, &children,
+ XtNnumChildren, &num_children,
+ NULL);
+ for (; num_children > 0; --num_children)
+ {
+ Widget child = children[num_children - 1];
+
+ if (has_submenu(child))
+ {
+ Widget temp_w;
+
+ temp_w = submenu_widget(child);
+ gui_athena_popdown_submenus_action(temp_w,event,args,nargs);
+ XtPopdown(temp_w);
+ }
+ }
+}
+
+/* Used to determine if the given widget has a submenu that can be popped up. */
+ static Boolean
+has_submenu(Widget widget)
+{
+ if ((widget != NULL) && XtIsSubclass(widget,smeBSBObjectClass))
+ {
+ Pixmap p;
+
+ XtVaGetValues(widget, XtNrightBitmap, &p, NULL);
+ if ((p != None) && (p != XtUnspecifiedPixmap))
+ return True;
+ }
+ return False;
+}
+
+ static void
+gui_athena_delayed_arm_action(
+ Widget w,
+ XEvent *event,
+ String *args,
+ Cardinal *nargs)
+{
+ Dimension width, height;
+
+ if (event->type != MotionNotify)
+ return;
+
+ XtVaGetValues(w,
+ XtNwidth, &width,
+ XtNheight, &height,
+ NULL);
+
+ if (event->xmotion.x >= (int)width || event->xmotion.y >= (int)height)
+ return;
+
+ {
+ static Widget previous_active_widget = NULL;
+ Widget current;
+
+ current = XawSimpleMenuGetActiveEntry(w);
+ if (current != previous_active_widget)
+ {
+ if (timer)
+ {
+ /* If the timeout hasn't been triggered, remove it */
+ XtRemoveTimeOut(timer);
+ }
+ gui_athena_popdown_submenus_action(w,event,args,nargs);
+ if (has_submenu(current))
+ {
+ XtAppAddTimeOut(XtWidgetToApplicationContext(w), 600L,
+ gui_athena_menu_timeout,
+ (XtPointer)current);
+ }
+ previous_active_widget = current;
+ }
+ }
+}
+
+ static Widget
+get_popup_entry(Widget w)
+{
+ Widget menuw;
+
+ /* Get the active entry for the current menu */
+ if ((menuw = XawSimpleMenuGetActiveEntry(w)) == (Widget)0)
+ return NULL;
+
+ return submenu_widget(menuw);
+}
+
+/* Given the widget that has been determined to have a submenu, return the submenu widget
+ * that is to be popped up.
+ */
+ static Widget
+submenu_widget(Widget widget)
+{
+ /* Precondition: has_submenu(widget) == True
+ * XtIsSubclass(XtParent(widget),simpleMenuWidgetClass) == True
+ */
+
+ char_u *pullright_name;
+ Widget popup;
+
+ pullright_name = make_pull_name((char_u *)XtName(widget));
+ popup = XtNameToWidget(XtParent(widget), (char *)pullright_name);
+ vim_free(pullright_name);
+
+ return popup;
+ /* Postcondition: (popup != NULL) implies
+ * (XtIsSubclass(popup,simpleMenuWidgetClass) == True) */
+}
+
+ void
+gui_mch_show_popupmenu(vimmenu_T *menu)
+{
+ int rootx, rooty, winx, winy;
+ Window root, child;
+ unsigned int mask;
+
+ if (menu->submenu_id == (Widget)0)
+ return;
+
+ /* Position the popup menu at the pointer */
+ if (XQueryPointer(gui.dpy, XtWindow(vimShell), &root, &child,
+ &rootx, &rooty, &winx, &winy, &mask))
+ {
+ rootx -= 30;
+ if (rootx < 0)
+ rootx = 0;
+ rooty -= 5;
+ if (rooty < 0)
+ rooty = 0;
+ XtVaSetValues(menu->submenu_id,
+ XtNx, rootx,
+ XtNy, rooty,
+ NULL);
+ }
+
+ XtOverrideTranslations(menu->submenu_id, popupTrans);
+ XtPopupSpringLoaded(menu->submenu_id);
+}
+
+#endif /* FEAT_MENU */
+
+/*
+ * Set the menu and scrollbar colors to their default values.
+ */
+ void
+gui_mch_def_colors(void)
+{
+ /*
+ * Get the colors ourselves. Using the automatic conversion doesn't
+ * handle looking for approximate colors.
+ */
+ if (gui.in_use)
+ {
+ gui.menu_fg_pixel = gui_get_color((char_u *)gui.rsrc_menu_fg_name);
+ gui.menu_bg_pixel = gui_get_color((char_u *)gui.rsrc_menu_bg_name);
+ gui.scroll_fg_pixel = gui_get_color((char_u *)gui.rsrc_scroll_fg_name);
+ gui.scroll_bg_pixel = gui_get_color((char_u *)gui.rsrc_scroll_bg_name);
+#ifdef FEAT_BEVAL_GUI
+ gui.tooltip_fg_pixel = gui_get_color((char_u *)gui.rsrc_tooltip_fg_name);
+ gui.tooltip_bg_pixel = gui_get_color((char_u *)gui.rsrc_tooltip_bg_name);
+#endif
+ }
+}
+
+
+/*
+ * Scrollbar stuff.
+ */
+
+ void
+gui_mch_set_scrollbar_thumb(
+ scrollbar_T *sb,
+ long val,
+ long size,
+ long max)
+{
+ double v, s;
+
+ if (sb->id == (Widget)0)
+ return;
+
+ /*
+ * Athena scrollbar must go from 0.0 to 1.0.
+ */
+ if (max == 0)
+ {
+ /* So you can't scroll it at all (normally it scrolls past end) */
+#ifdef FEAT_GUI_NEXTAW
+ XawScrollbarSetThumb(sb->id, 0.0, 1.0);
+#else
+ vim_XawScrollbarSetThumb(sb->id, 0.0, 1.0, 0.0);
+#endif
+ }
+ else
+ {
+ v = (double)val / (double)(max + 1);
+ s = (double)size / (double)(max + 1);
+#ifdef FEAT_GUI_NEXTAW
+ XawScrollbarSetThumb(sb->id, v, s);
+#else
+ vim_XawScrollbarSetThumb(sb->id, v, s, 1.0);
+#endif
+ }
+}
+
+ void
+gui_mch_set_scrollbar_pos(
+ scrollbar_T *sb,
+ int x,
+ int y,
+ int w,
+ int h)
+{
+ if (sb->id == (Widget)0)
+ return;
+
+ XtUnmanageChild(sb->id);
+ XtVaSetValues(sb->id,
+ XtNhorizDistance, x,
+ XtNvertDistance, y,
+ XtNwidth, w,
+ XtNheight, h,
+ NULL);
+ XtManageChild(sb->id);
+}
+
+ void
+gui_mch_enable_scrollbar(scrollbar_T *sb, int flag)
+{
+ if (sb->id != (Widget)0)
+ {
+ if (flag)
+ XtManageChild(sb->id);
+ else
+ XtUnmanageChild(sb->id);
+ }
+}
+
+ void
+gui_mch_create_scrollbar(
+ scrollbar_T *sb,
+ int orient) /* SBAR_VERT or SBAR_HORIZ */
+{
+ sb->id = XtVaCreateWidget("scrollBar",
+#ifdef FEAT_GUI_NEXTAW
+ scrollbarWidgetClass, vimForm,
+#else
+ vim_scrollbarWidgetClass, vimForm,
+#endif
+ XtNresizable, True,
+ XtNtop, XtChainTop,
+ XtNbottom, XtChainTop,
+ XtNleft, XtChainLeft,
+ XtNright, XtChainLeft,
+ XtNborderWidth, 0,
+ XtNorientation, (orient == SBAR_VERT) ? XtorientVertical
+ : XtorientHorizontal,
+ XtNforeground, gui.scroll_fg_pixel,
+ XtNbackground, gui.scroll_bg_pixel,
+ NULL);
+ if (sb->id == (Widget)0)
+ return;
+
+ XtAddCallback(sb->id, XtNjumpProc,
+ gui_athena_scroll_cb_jump, (XtPointer)sb->ident);
+ XtAddCallback(sb->id, XtNscrollProc,
+ gui_athena_scroll_cb_scroll, (XtPointer)sb->ident);
+
+#ifdef FEAT_GUI_NEXTAW
+ XawScrollbarSetThumb(sb->id, 0.0, 1.0);
+#else
+ vim_XawScrollbarSetThumb(sb->id, 0.0, 1.0, 0.0);
+#endif
+}
+
+ void
+gui_mch_destroy_scrollbar(scrollbar_T *sb)
+{
+ if (sb->id != (Widget)0)
+ XtDestroyWidget(sb->id);
+}
+
+ void
+gui_mch_set_scrollbar_colors(scrollbar_T *sb)
+{
+ if (sb->id != (Widget)0)
+ XtVaSetValues(sb->id,
+ XtNforeground, gui.scroll_fg_pixel,
+ XtNbackground, gui.scroll_bg_pixel,
+ NULL);
+
+ /* This is needed for the rectangle below the vertical scrollbars. */
+ if (sb == &gui.bottom_sbar && vimForm != (Widget)0)
+ gui_athena_scroll_colors(vimForm);
+}
+
+/*
+ * Miscellaneous stuff:
+ */
+ Window
+gui_x11_get_wid(void)
+{
+ return XtWindow(textArea);
+}
+
+#if defined(FEAT_BROWSE) || defined(PROTO)
+/*
+ * Put up a file requester.
+ * Returns the selected name in allocated memory, or NULL for Cancel.
+ */
+ char_u *
+gui_mch_browse(
+ int saving UNUSED, /* select file to write */
+ char_u *title, /* title for the window */
+ char_u *dflt, /* default name */
+ char_u *ext UNUSED, /* extension added */
+ char_u *initdir, /* initial directory, NULL for current dir */
+ char_u *filter UNUSED) /* file name filter */
+{
+ Position x, y;
+ char_u dirbuf[MAXPATHL];
+
+ /* Concatenate "initdir" and "dflt". */
+ if (initdir == NULL || *initdir == NUL)
+ mch_dirname(dirbuf, MAXPATHL);
+ else if (STRLEN(initdir) + 2 < MAXPATHL)
+ STRCPY(dirbuf, initdir);
+ else
+ dirbuf[0] = NUL;
+ if (dflt != NULL && *dflt != NUL
+ && STRLEN(dirbuf) + 2 + STRLEN(dflt) < MAXPATHL)
+ {
+ add_pathsep(dirbuf);
+ STRCAT(dirbuf, dflt);
+ }
+
+ /* Position the file selector just below the menubar */
+ XtTranslateCoords(vimShell, (Position)0, (Position)
+#ifdef FEAT_MENU
+ gui.menu_height
+#else
+ 0
+#endif
+ , &x, &y);
+ return (char_u *)vim_SelFile(vimShell, (char *)title, (char *)dirbuf,
+ NULL, (int)x, (int)y, gui.menu_fg_pixel, gui.menu_bg_pixel,
+ gui.scroll_fg_pixel, gui.scroll_bg_pixel);
+}
+#endif
+
+#if defined(FEAT_GUI_DIALOG) || defined(PROTO)
+
+static int dialogStatus;
+static Atom dialogatom;
+
+/*
+ * Callback function for the textfield. When CR is hit this works like
+ * hitting the "OK" button, ESC like "Cancel".
+ */
+ static void
+keyhit_callback(
+ Widget w UNUSED,
+ XtPointer client_data UNUSED,
+ XEvent *event,
+ Boolean *cont UNUSED)
+{
+ char buf[2];
+
+ if (XLookupString(&(event->xkey), buf, 2, NULL, NULL) == 1)
+ {
+ if (*buf == CAR)
+ dialogStatus = 1;
+ else if (*buf == ESC)
+ dialogStatus = 0;
+ }
+}
+
+ static void
+butproc(
+ Widget w UNUSED,
+ XtPointer client_data,
+ XtPointer call_data UNUSED)
+{
+ dialogStatus = (int)(long)client_data + 1;
+}
+
+/*
+ * Function called when dialog window closed.
+ */
+ static void
+dialog_wm_handler(
+ Widget w UNUSED,
+ XtPointer client_data UNUSED,
+ XEvent *event,
+ Boolean *dum UNUSED)
+{
+ if (event->type == ClientMessage
+ && (Atom)((XClientMessageEvent *)event)->data.l[0] == dialogatom)
+ dialogStatus = 0;
+}
+
+ int
+gui_mch_dialog(
+ int type UNUSED,
+ char_u *title,
+ char_u *message,
+ char_u *buttons,
+ int dfltbutton UNUSED,
+ char_u *textfield,
+ int ex_cmd UNUSED)
+{
+ char_u *buts;
+ char_u *p, *next;
+ XtAppContext app;
+ XEvent event;
+ Position wd, hd;
+ Position wv, hv;
+ Position x, y;
+ Widget dialog;
+ Widget dialogshell;
+ Widget dialogmessage;
+ Widget dialogtextfield = 0;
+ Widget dialogButton;
+ Widget prev_dialogButton = NULL;
+ int butcount;
+ int vertical;
+
+ if (title == NULL)
+ title = (char_u *)_("Vim dialog");
+ dialogStatus = -1;
+
+ /* if our pointer is currently hidden, then we should show it. */
+ gui_mch_mousehide(FALSE);
+
+ /* Check 'v' flag in 'guioptions': vertical button placement. */
+ vertical = (vim_strchr(p_go, GO_VERTICAL) != NULL);
+
+ /* The shell is created each time, to make sure it is resized properly */
+ dialogshell = XtVaCreatePopupShell("dialogShell",
+ transientShellWidgetClass, vimShell,
+ XtNtitle, title,
+ NULL);
+ if (dialogshell == (Widget)0)
+ goto error;
+
+ dialog = XtVaCreateManagedWidget("dialog",
+ formWidgetClass, dialogshell,
+ XtNdefaultDistance, 20,
+ NULL);
+ if (dialog == (Widget)0)
+ goto error;
+ gui_athena_menu_colors(dialog);
+ dialogmessage = XtVaCreateManagedWidget("dialogMessage",
+ labelWidgetClass, dialog,
+ XtNlabel, message,
+ XtNtop, XtChainTop,
+ XtNbottom, XtChainTop,
+ XtNleft, XtChainLeft,
+ XtNright, XtChainLeft,
+ XtNresizable, True,
+ XtNborderWidth, 0,
+ NULL);
+ gui_athena_menu_colors(dialogmessage);
+
+ if (textfield != NULL)
+ {
+ dialogtextfield = XtVaCreateManagedWidget("textfield",
+ asciiTextWidgetClass, dialog,
+ XtNwidth, 400,
+ XtNtop, XtChainTop,
+ XtNbottom, XtChainTop,
+ XtNleft, XtChainLeft,
+ XtNright, XtChainRight,
+ XtNfromVert, dialogmessage,
+ XtNresizable, True,
+ XtNstring, textfield,
+ XtNlength, IOSIZE,
+ XtNuseStringInPlace, True,
+ XtNeditType, XawtextEdit,
+ XtNwrap, XawtextWrapNever,
+ XtNresize, XawtextResizeHeight,
+ NULL);
+ XtManageChild(dialogtextfield);
+ XtAddEventHandler(dialogtextfield, KeyPressMask, False,
+ (XtEventHandler)keyhit_callback, (XtPointer)NULL);
+ XawTextSetInsertionPoint(dialogtextfield,
+ (XawTextPosition)STRLEN(textfield));
+ XtSetKeyboardFocus(dialog, dialogtextfield);
+ }
+
+ /* make a copy, so that we can insert NULs */
+ buts = vim_strsave(buttons);
+ if (buts == NULL)
+ return -1;
+
+ p = buts;
+ for (butcount = 0; *p; ++butcount)
+ {
+ for (next = p; *next; ++next)
+ {
+ if (*next == DLG_HOTKEY_CHAR)
+ STRMOVE(next, next + 1);
+ if (*next == DLG_BUTTON_SEP)
+ {
+ *next++ = NUL;
+ break;
+ }
+ }
+ dialogButton = XtVaCreateManagedWidget("button",
+ commandWidgetClass, dialog,
+ XtNlabel, p,
+ XtNtop, XtChainBottom,
+ XtNbottom, XtChainBottom,
+ XtNleft, XtChainLeft,
+ XtNright, XtChainLeft,
+ XtNfromVert, textfield == NULL ? dialogmessage : dialogtextfield,
+ XtNvertDistance, vertical ? 4 : 20,
+ XtNresizable, False,
+ NULL);
+ gui_athena_menu_colors(dialogButton);
+ if (butcount > 0)
+ XtVaSetValues(dialogButton,
+ vertical ? XtNfromVert : XtNfromHoriz, prev_dialogButton,
+ NULL);
+
+ XtAddCallback(dialogButton, XtNcallback, butproc, (XtPointer)(long_u)butcount);
+ p = next;
+ prev_dialogButton = dialogButton;
+ }
+ vim_free(buts);
+
+ XtRealizeWidget(dialogshell);
+
+ /* Setup for catching the close-window event, don't let it close Vim! */
+ dialogatom = XInternAtom(gui.dpy, "WM_DELETE_WINDOW", False);
+ XSetWMProtocols(gui.dpy, XtWindow(dialogshell), &dialogatom, 1);
+ XtAddEventHandler(dialogshell, NoEventMask, True, dialog_wm_handler, NULL);
+
+ XtVaGetValues(dialogshell,
+ XtNwidth, &wd,
+ XtNheight, &hd,
+ NULL);
+ XtVaGetValues(vimShell,
+ XtNwidth, &wv,
+ XtNheight, &hv,
+ NULL);
+ XtTranslateCoords(vimShell,
+ (Position)((wv - wd) / 2),
+ (Position)((hv - hd) / 2),
+ &x, &y);
+ if (x < 0)
+ x = 0;
+ if (y < 0)
+ y = 0;
+ XtVaSetValues(dialogshell, XtNx, x, XtNy, y, NULL);
+
+ /* Position the mouse pointer in the dialog, required for when focus
+ * follows mouse. */
+ XWarpPointer(gui.dpy, (Window)0, XtWindow(dialogshell), 0, 0, 0, 0, 20, 40);
+
+
+ app = XtWidgetToApplicationContext(dialogshell);
+
+ XtPopup(dialogshell, XtGrabNonexclusive);
+
+ for (;;)
+ {
+ XtAppNextEvent(app, &event);
+ XtDispatchEvent(&event);
+ if (dialogStatus >= 0)
+ break;
+ }
+
+ XtPopdown(dialogshell);
+
+ if (textfield != NULL && dialogStatus < 0)
+ *textfield = NUL;
+
+error:
+ XtDestroyWidget(dialogshell);
+
+ return dialogStatus;
+}
+#endif
+
+#if defined(FEAT_GUI_DIALOG) || defined(FEAT_MENU)
+/*
+ * Set the colors of Widget "id" to the menu colors.
+ */
+ static void
+gui_athena_menu_colors(Widget id)
+{
+ if (gui.menu_bg_pixel != INVALCOLOR)
+ XtVaSetValues(id, XtNbackground, gui.menu_bg_pixel, NULL);
+ if (gui.menu_fg_pixel != INVALCOLOR)
+ XtVaSetValues(id, XtNforeground, gui.menu_fg_pixel, NULL);
+}
+#endif
+
+/*
+ * Set the colors of Widget "id" to the scroll colors.
+ */
+ static void
+gui_athena_scroll_colors(Widget id)
+{
+ if (gui.scroll_bg_pixel != INVALCOLOR)
+ XtVaSetValues(id, XtNbackground, gui.scroll_bg_pixel, NULL);
+ if (gui.scroll_fg_pixel != INVALCOLOR)
+ XtVaSetValues(id, XtNforeground, gui.scroll_fg_pixel, NULL);
+}
diff --git a/src/gui_beval.c b/src/gui_beval.c
new file mode 100644
index 0000000..3a28218
--- /dev/null
+++ b/src/gui_beval.c
@@ -0,0 +1,1225 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ * Visual Workshop integration by Gordon Prieur
+ *
+ * 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.
+ */
+
+#include "vim.h"
+
+#if defined(FEAT_BEVAL_GUI) || defined(PROTO)
+
+/* on Win32 only get_beval_info() is required */
+#if !defined(FEAT_GUI_W32) || defined(PROTO)
+
+#ifdef FEAT_GUI_GTK
+# if GTK_CHECK_VERSION(3,0,0)
+# include <gdk/gdkkeysyms-compat.h>
+# else
+# include <gdk/gdkkeysyms.h>
+# endif
+# include <gtk/gtk.h>
+#else
+# include <X11/keysym.h>
+# ifdef FEAT_GUI_MOTIF
+# include <Xm/PushB.h>
+# include <Xm/Separator.h>
+# include <Xm/List.h>
+# include <Xm/Label.h>
+# include <Xm/AtomMgr.h>
+# include <Xm/Protocols.h>
+# else
+ /* Assume Athena */
+# include <X11/Shell.h>
+# ifdef FEAT_GUI_NEXTAW
+# include <X11/neXtaw/Label.h>
+# else
+# include <X11/Xaw/Label.h>
+# endif
+# endif
+#endif
+
+#ifndef FEAT_GUI_GTK
+extern Widget vimShell;
+
+/*
+ * Currently, we assume that there can be only one BalloonEval showing
+ * on-screen at any given moment. This variable will hold the currently
+ * showing BalloonEval or NULL if none is showing.
+ */
+static BalloonEval *current_beval = NULL;
+#endif
+
+#ifdef FEAT_GUI_GTK
+static void addEventHandler(GtkWidget *, BalloonEval *);
+static void removeEventHandler(BalloonEval *);
+static gint target_event_cb(GtkWidget *, GdkEvent *, gpointer);
+static gint mainwin_event_cb(GtkWidget *, GdkEvent *, gpointer);
+static void pointer_event(BalloonEval *, int, int, unsigned);
+static void key_event(BalloonEval *, unsigned, int);
+static gboolean timeout_cb(gpointer);
+# if GTK_CHECK_VERSION(3,0,0)
+static gboolean balloon_draw_event_cb (GtkWidget *, cairo_t *, gpointer);
+# else
+static gint balloon_expose_event_cb (GtkWidget *, GdkEventExpose *, gpointer);
+# endif
+#else
+static void addEventHandler(Widget, BalloonEval *);
+static void removeEventHandler(BalloonEval *);
+static void pointerEventEH(Widget, XtPointer, XEvent *, Boolean *);
+static void pointerEvent(BalloonEval *, XEvent *);
+static void timerRoutine(XtPointer, XtIntervalId *);
+#endif
+static void cancelBalloon(BalloonEval *);
+static void requestBalloon(BalloonEval *);
+static void drawBalloon(BalloonEval *);
+static void undrawBalloon(BalloonEval *beval);
+static void createBalloonEvalWindow(BalloonEval *);
+
+/*
+ * Create a balloon-evaluation area for a Widget.
+ * There can be either a "mesg" for a fixed string or "mesgCB" to generate a
+ * message by calling this callback function.
+ * When "mesg" is not NULL it must remain valid for as long as the balloon is
+ * used. It is not freed here.
+ * Returns a pointer to the resulting object (NULL when out of memory).
+ */
+ BalloonEval *
+gui_mch_create_beval_area(
+ void *target,
+ char_u *mesg,
+ void (*mesgCB)(BalloonEval *, int),
+ void *clientData)
+{
+#ifndef FEAT_GUI_GTK
+ char *display_name; /* get from gui.dpy */
+ int screen_num;
+ char *p;
+#endif
+ BalloonEval *beval;
+
+ if (mesg != NULL && mesgCB != NULL)
+ {
+ iemsg(_("E232: Cannot create BalloonEval with both message and callback"));
+ return NULL;
+ }
+
+ beval = (BalloonEval *)alloc_clear(sizeof(BalloonEval));
+ if (beval != NULL)
+ {
+#ifdef FEAT_GUI_GTK
+ beval->target = GTK_WIDGET(target);
+#else
+ beval->target = (Widget)target;
+ beval->appContext = XtWidgetToApplicationContext((Widget)target);
+#endif
+ beval->showState = ShS_NEUTRAL;
+ beval->msg = mesg;
+ beval->msgCB = mesgCB;
+ beval->clientData = clientData;
+
+ /*
+ * Set up event handler which will keep its eyes on the pointer,
+ * and when the pointer rests in a certain spot for a given time
+ * interval, show the beval.
+ */
+ addEventHandler(beval->target, beval);
+ createBalloonEvalWindow(beval);
+
+#ifndef FEAT_GUI_GTK
+ /*
+ * Now create and save the screen width and height. Used in drawing.
+ */
+ display_name = DisplayString(gui.dpy);
+ p = strrchr(display_name, '.');
+ if (p != NULL)
+ screen_num = atoi(++p);
+ else
+ screen_num = 0;
+ beval->screen_width = DisplayWidth(gui.dpy, screen_num);
+ beval->screen_height = DisplayHeight(gui.dpy, screen_num);
+#endif
+ }
+
+ return beval;
+}
+
+#if defined(FEAT_BEVAL_TIP) || defined(PROTO)
+/*
+ * Destroy a balloon-eval and free its associated memory.
+ */
+ void
+gui_mch_destroy_beval_area(BalloonEval *beval)
+{
+ cancelBalloon(beval);
+ removeEventHandler(beval);
+ /* Children will automatically be destroyed */
+# ifdef FEAT_GUI_GTK
+ gtk_widget_destroy(beval->balloonShell);
+# else
+ XtDestroyWidget(beval->balloonShell);
+# endif
+# ifdef FEAT_VARTABS
+ if (beval->vts)
+ vim_free(beval->vts);
+# endif
+ vim_free(beval);
+}
+#endif
+
+ void
+gui_mch_enable_beval_area(BalloonEval *beval)
+{
+ if (beval != NULL)
+ addEventHandler(beval->target, beval);
+}
+
+ void
+gui_mch_disable_beval_area(BalloonEval *beval)
+{
+ if (beval != NULL)
+ removeEventHandler(beval);
+}
+
+#if defined(FEAT_BEVAL_TIP) || defined(PROTO)
+/*
+ * This function returns the BalloonEval * associated with the currently
+ * displayed tooltip. Returns NULL if there is no tooltip currently showing.
+ *
+ * Assumption: Only one tooltip can be shown at a time.
+ */
+ BalloonEval *
+gui_mch_currently_showing_beval(void)
+{
+ return current_beval;
+}
+#endif
+#endif /* !FEAT_GUI_W32 */
+
+#if defined(FEAT_NETBEANS_INTG) || defined(FEAT_EVAL) || defined(PROTO)
+# if !defined(FEAT_GUI_W32) || defined(PROTO)
+
+/*
+ * Show a balloon with "mesg".
+ */
+ void
+gui_mch_post_balloon(BalloonEval *beval, char_u *mesg)
+{
+ beval->msg = mesg;
+ if (mesg != NULL)
+ drawBalloon(beval);
+ else
+ undrawBalloon(beval);
+}
+# endif /* !FEAT_GUI_W32 */
+#endif /* FEAT_NETBEANS_INTG || PROTO */
+
+#if !defined(FEAT_GUI_W32) || defined(PROTO)
+#if defined(FEAT_BEVAL_TIP) || defined(PROTO)
+/*
+ * Hide the given balloon.
+ */
+ void
+gui_mch_unpost_balloon(BalloonEval *beval)
+{
+ undrawBalloon(beval);
+}
+#endif
+
+#ifdef FEAT_GUI_GTK
+ static void
+addEventHandler(GtkWidget *target, BalloonEval *beval)
+{
+ /*
+ * Connect to the generic "event" signal instead of the individual
+ * signals for each event type, because the former is emitted earlier.
+ * This allows us to catch events independently of the signal handlers
+ * in gui_gtk_x11.c.
+ */
+ g_signal_connect(G_OBJECT(target), "event",
+ G_CALLBACK(target_event_cb),
+ beval);
+ /*
+ * Nasty: Key press events go to the main window thus the drawing area
+ * will never see them. This means we have to connect to the main window
+ * as well in order to catch those events.
+ */
+ if (gtk_socket_id == 0 && gui.mainwin != NULL
+ && gtk_widget_is_ancestor(target, gui.mainwin))
+ {
+ g_signal_connect(G_OBJECT(gui.mainwin), "event",
+ G_CALLBACK(mainwin_event_cb),
+ beval);
+ }
+}
+
+ static void
+removeEventHandler(BalloonEval *beval)
+{
+ g_signal_handlers_disconnect_by_func(G_OBJECT(beval->target),
+ FUNC2GENERIC(target_event_cb),
+ beval);
+
+ if (gtk_socket_id == 0 && gui.mainwin != NULL
+ && gtk_widget_is_ancestor(beval->target, gui.mainwin))
+ {
+ g_signal_handlers_disconnect_by_func(G_OBJECT(gui.mainwin),
+ FUNC2GENERIC(mainwin_event_cb),
+ beval);
+ }
+}
+
+ static gint
+target_event_cb(GtkWidget *widget, GdkEvent *event, gpointer data)
+{
+ BalloonEval *beval = (BalloonEval *)data;
+
+ switch (event->type)
+ {
+ case GDK_ENTER_NOTIFY:
+ pointer_event(beval, (int)event->crossing.x,
+ (int)event->crossing.y,
+ event->crossing.state);
+ break;
+ case GDK_MOTION_NOTIFY:
+ if (event->motion.is_hint)
+ {
+ int x;
+ int y;
+ GdkModifierType state;
+ /*
+ * GDK_POINTER_MOTION_HINT_MASK is set, thus we cannot obtain
+ * the coordinates from the GdkEventMotion struct directly.
+ */
+# if GTK_CHECK_VERSION(3,0,0)
+ {
+ GdkWindow * const win = gtk_widget_get_window(widget);
+ GdkDisplay * const dpy = gdk_window_get_display(win);
+# if GTK_CHECK_VERSION(3,20,0)
+ GdkSeat * const seat = gdk_display_get_default_seat(dpy);
+ GdkDevice * const dev = gdk_seat_get_pointer(seat);
+# else
+ GdkDeviceManager * const mngr = gdk_display_get_device_manager(dpy);
+ GdkDevice * const dev = gdk_device_manager_get_client_pointer(mngr);
+# endif
+ gdk_window_get_device_position(win, dev , &x, &y, &state);
+ }
+# else
+ gdk_window_get_pointer(widget->window, &x, &y, &state);
+# endif
+ pointer_event(beval, x, y, (unsigned int)state);
+ }
+ else
+ {
+ pointer_event(beval, (int)event->motion.x,
+ (int)event->motion.y,
+ event->motion.state);
+ }
+ break;
+ case GDK_LEAVE_NOTIFY:
+ /*
+ * Ignore LeaveNotify events that are not "normal".
+ * Apparently we also get it when somebody else grabs focus.
+ */
+ if (event->crossing.mode == GDK_CROSSING_NORMAL)
+ cancelBalloon(beval);
+ break;
+ case GDK_BUTTON_PRESS:
+ case GDK_SCROLL:
+ cancelBalloon(beval);
+ break;
+ case GDK_KEY_PRESS:
+ key_event(beval, event->key.keyval, TRUE);
+ break;
+ case GDK_KEY_RELEASE:
+ key_event(beval, event->key.keyval, FALSE);
+ break;
+ default:
+ break;
+ }
+
+ return FALSE; /* continue emission */
+}
+
+ static gint
+mainwin_event_cb(GtkWidget *widget UNUSED, GdkEvent *event, gpointer data)
+{
+ BalloonEval *beval = (BalloonEval *)data;
+
+ switch (event->type)
+ {
+ case GDK_KEY_PRESS:
+ key_event(beval, event->key.keyval, TRUE);
+ break;
+ case GDK_KEY_RELEASE:
+ key_event(beval, event->key.keyval, FALSE);
+ break;
+ default:
+ break;
+ }
+
+ return FALSE; /* continue emission */
+}
+
+ static void
+pointer_event(BalloonEval *beval, int x, int y, unsigned state)
+{
+ int distance;
+
+ distance = ABS(x - beval->x) + ABS(y - beval->y);
+
+ if (distance > 4)
+ {
+ /*
+ * Moved out of the balloon location: cancel it.
+ * Remember button state
+ */
+ beval->state = state;
+ cancelBalloon(beval);
+
+ /* Mouse buttons are pressed - no balloon now */
+ if (!(state & ((int)GDK_BUTTON1_MASK | (int)GDK_BUTTON2_MASK
+ | (int)GDK_BUTTON3_MASK)))
+ {
+ beval->x = x;
+ beval->y = y;
+
+ if (state & (int)GDK_MOD1_MASK)
+ {
+ /*
+ * Alt is pressed -- enter super-evaluate-mode,
+ * where there is no time delay
+ */
+ if (beval->msgCB != NULL)
+ {
+ beval->showState = ShS_PENDING;
+ (*beval->msgCB)(beval, state);
+ }
+ }
+ else
+ {
+ beval->timerID = g_timeout_add((guint)p_bdlay,
+ &timeout_cb, beval);
+ }
+ }
+ }
+}
+
+ static void
+key_event(BalloonEval *beval, unsigned keyval, int is_keypress)
+{
+ if (beval->showState == ShS_SHOWING && beval->msgCB != NULL)
+ {
+ switch (keyval)
+ {
+ case GDK_Shift_L:
+ case GDK_Shift_R:
+ beval->showState = ShS_UPDATE_PENDING;
+ (*beval->msgCB)(beval, (is_keypress)
+ ? (int)GDK_SHIFT_MASK : 0);
+ break;
+ case GDK_Control_L:
+ case GDK_Control_R:
+ beval->showState = ShS_UPDATE_PENDING;
+ (*beval->msgCB)(beval, (is_keypress)
+ ? (int)GDK_CONTROL_MASK : 0);
+ break;
+ default:
+ /* Don't do this for key release, we apparently get these with
+ * focus changes in some GTK version. */
+ if (is_keypress)
+ cancelBalloon(beval);
+ break;
+ }
+ }
+ else
+ cancelBalloon(beval);
+}
+
+ static gboolean
+timeout_cb(gpointer data)
+{
+ BalloonEval *beval = (BalloonEval *)data;
+
+ beval->timerID = 0;
+ /*
+ * If the timer event happens then the mouse has stopped long enough for
+ * a request to be started. The request will only send to the debugger if
+ * there the mouse is pointing at real data.
+ */
+ requestBalloon(beval);
+
+ return FALSE; /* don't call me again */
+}
+
+# if GTK_CHECK_VERSION(3,0,0)
+ static gboolean
+balloon_draw_event_cb(GtkWidget *widget,
+ cairo_t *cr,
+ gpointer data UNUSED)
+{
+ GtkStyleContext *context = NULL;
+ gint width = -1, height = -1;
+
+ if (widget == NULL)
+ return TRUE;
+
+ context = gtk_widget_get_style_context(widget);
+ width = gtk_widget_get_allocated_width(widget);
+ height = gtk_widget_get_allocated_height(widget);
+
+ gtk_style_context_save(context);
+
+ gtk_style_context_add_class(context, "tooltip");
+ gtk_style_context_set_state(context, GTK_STATE_FLAG_NORMAL);
+
+ cairo_save(cr);
+ gtk_render_frame(context, cr, 0, 0, width, height);
+ gtk_render_background(context, cr, 0, 0, width, height);
+ cairo_restore(cr);
+
+ gtk_style_context_restore(context);
+
+ return FALSE;
+}
+# else
+ static gint
+balloon_expose_event_cb(GtkWidget *widget,
+ GdkEventExpose *event,
+ gpointer data UNUSED)
+{
+ gtk_paint_flat_box(widget->style, widget->window,
+ GTK_STATE_NORMAL, GTK_SHADOW_OUT,
+ &event->area, widget, "tooltip",
+ 0, 0, -1, -1);
+
+ return FALSE; /* continue emission */
+}
+# endif /* !GTK_CHECK_VERSION(3,0,0) */
+
+#else /* !FEAT_GUI_GTK */
+
+ static void
+addEventHandler(Widget target, BalloonEval *beval)
+{
+ XtAddEventHandler(target,
+ PointerMotionMask | EnterWindowMask |
+ LeaveWindowMask | ButtonPressMask | KeyPressMask |
+ KeyReleaseMask,
+ False,
+ pointerEventEH, (XtPointer)beval);
+}
+
+ static void
+removeEventHandler(BalloonEval *beval)
+{
+ XtRemoveEventHandler(beval->target,
+ PointerMotionMask | EnterWindowMask |
+ LeaveWindowMask | ButtonPressMask | KeyPressMask |
+ KeyReleaseMask,
+ False,
+ pointerEventEH, (XtPointer)beval);
+}
+
+
+/*
+ * The X event handler. All it does is call the real event handler.
+ */
+ static void
+pointerEventEH(
+ Widget w UNUSED,
+ XtPointer client_data,
+ XEvent *event,
+ Boolean *unused UNUSED)
+{
+ BalloonEval *beval = (BalloonEval *)client_data;
+ pointerEvent(beval, event);
+}
+
+
+/*
+ * The real event handler. Called by pointerEventEH() whenever an event we are
+ * interested in occurs.
+ */
+
+ static void
+pointerEvent(BalloonEval *beval, XEvent *event)
+{
+ Position distance; /* a measure of how much the pointer moved */
+ Position delta; /* used to compute distance */
+
+ switch (event->type)
+ {
+ case EnterNotify:
+ case MotionNotify:
+ delta = event->xmotion.x - beval->x;
+ if (delta < 0)
+ delta = -delta;
+ distance = delta;
+ delta = event->xmotion.y - beval->y;
+ if (delta < 0)
+ delta = -delta;
+ distance += delta;
+ if (distance > 4)
+ {
+ /*
+ * Moved out of the balloon location: cancel it.
+ * Remember button state
+ */
+ beval->state = event->xmotion.state;
+ if (beval->state & (Button1Mask|Button2Mask|Button3Mask))
+ {
+ /* Mouse buttons are pressed - no balloon now */
+ cancelBalloon(beval);
+ }
+ else if (beval->state & (Mod1Mask|Mod2Mask|Mod3Mask))
+ {
+ /*
+ * Alt is pressed -- enter super-evaluate-mode,
+ * where there is no time delay
+ */
+ beval->x = event->xmotion.x;
+ beval->y = event->xmotion.y;
+ beval->x_root = event->xmotion.x_root;
+ beval->y_root = event->xmotion.y_root;
+ cancelBalloon(beval);
+ if (beval->msgCB != NULL)
+ {
+ beval->showState = ShS_PENDING;
+ (*beval->msgCB)(beval, beval->state);
+ }
+ }
+ else
+ {
+ beval->x = event->xmotion.x;
+ beval->y = event->xmotion.y;
+ beval->x_root = event->xmotion.x_root;
+ beval->y_root = event->xmotion.y_root;
+ cancelBalloon(beval);
+ beval->timerID = XtAppAddTimeOut( beval->appContext,
+ (long_u)p_bdlay, timerRoutine, beval);
+ }
+ }
+ break;
+
+ /*
+ * Motif and Athena version: Keystrokes will be caught by the
+ * "textArea" widget, and handled in gui_x11_key_hit_cb().
+ */
+ case KeyPress:
+ if (beval->showState == ShS_SHOWING && beval->msgCB != NULL)
+ {
+ Modifiers modifier;
+ KeySym keysym;
+
+ XtTranslateKeycode(gui.dpy,
+ event->xkey.keycode, event->xkey.state,
+ &modifier, &keysym);
+ if (keysym == XK_Shift_L || keysym == XK_Shift_R)
+ {
+ beval->showState = ShS_UPDATE_PENDING;
+ (*beval->msgCB)(beval, ShiftMask);
+ }
+ else if (keysym == XK_Control_L || keysym == XK_Control_R)
+ {
+ beval->showState = ShS_UPDATE_PENDING;
+ (*beval->msgCB)(beval, ControlMask);
+ }
+ else
+ cancelBalloon(beval);
+ }
+ else
+ cancelBalloon(beval);
+ break;
+
+ case KeyRelease:
+ if (beval->showState == ShS_SHOWING && beval->msgCB != NULL)
+ {
+ Modifiers modifier;
+ KeySym keysym;
+
+ XtTranslateKeycode(gui.dpy, event->xkey.keycode,
+ event->xkey.state, &modifier, &keysym);
+ if ((keysym == XK_Shift_L) || (keysym == XK_Shift_R)) {
+ beval->showState = ShS_UPDATE_PENDING;
+ (*beval->msgCB)(beval, 0);
+ }
+ else if ((keysym == XK_Control_L) || (keysym == XK_Control_R))
+ {
+ beval->showState = ShS_UPDATE_PENDING;
+ (*beval->msgCB)(beval, 0);
+ }
+ else
+ cancelBalloon(beval);
+ }
+ else
+ cancelBalloon(beval);
+ break;
+
+ case LeaveNotify:
+ /* Ignore LeaveNotify events that are not "normal".
+ * Apparently we also get it when somebody else grabs focus.
+ * Happens for me every two seconds (some clipboard tool?) */
+ if (event->xcrossing.mode == NotifyNormal)
+ cancelBalloon(beval);
+ break;
+
+ case ButtonPress:
+ cancelBalloon(beval);
+ break;
+
+ default:
+ break;
+ }
+}
+
+ static void
+timerRoutine(XtPointer dx, XtIntervalId *id UNUSED)
+{
+ BalloonEval *beval = (BalloonEval *)dx;
+
+ beval->timerID = (XtIntervalId)NULL;
+
+ /*
+ * If the timer event happens then the mouse has stopped long enough for
+ * a request to be started. The request will only send to the debugger if
+ * there the mouse is pointing at real data.
+ */
+ requestBalloon(beval);
+}
+
+#endif /* !FEAT_GUI_GTK */
+
+ static void
+requestBalloon(BalloonEval *beval)
+{
+ if (beval->showState != ShS_PENDING)
+ {
+ /* Determine the beval to display */
+ if (beval->msgCB != NULL)
+ {
+ beval->showState = ShS_PENDING;
+ (*beval->msgCB)(beval, beval->state);
+ }
+ else if (beval->msg != NULL)
+ drawBalloon(beval);
+ }
+}
+
+#ifdef FEAT_GUI_GTK
+/*
+ * Convert the string to UTF-8 if 'encoding' is not "utf-8".
+ * Replace any non-printable characters and invalid bytes sequences with
+ * "^X" or "<xx>" escapes, and apply SpecialKey highlighting to them.
+ * TAB and NL are passed through unscathed.
+ */
+# define IS_NONPRINTABLE(c) (((c) < 0x20 && (c) != TAB && (c) != NL) \
+ || (c) == DEL)
+ static void
+set_printable_label_text(GtkLabel *label, char_u *text)
+{
+ char_u *convbuf = NULL;
+ char_u *buf;
+ char_u *p;
+ char_u *pdest;
+ unsigned int len;
+ int charlen;
+ int uc;
+ PangoAttrList *attr_list;
+
+ /* Convert to UTF-8 if it isn't already */
+ if (output_conv.vc_type != CONV_NONE)
+ {
+ convbuf = string_convert(&output_conv, text, NULL);
+ if (convbuf != NULL)
+ text = convbuf;
+ }
+
+ /* First let's see how much we need to allocate */
+ len = 0;
+ for (p = text; *p != NUL; p += charlen)
+ {
+ if ((*p & 0x80) == 0) /* be quick for ASCII */
+ {
+ charlen = 1;
+ len += IS_NONPRINTABLE(*p) ? 2 : 1; /* nonprintable: ^X */
+ }
+ else
+ {
+ charlen = utf_ptr2len(p);
+ uc = utf_ptr2char(p);
+
+ if (charlen != utf_char2len(uc))
+ charlen = 1; /* reject overlong sequences */
+
+ if (charlen == 1 || uc < 0xa0) /* illegal byte or */
+ len += 4; /* control char: <xx> */
+ else if (!utf_printable(uc))
+ /* Note: we assume here that utf_printable() doesn't
+ * care about characters outside the BMP. */
+ len += 6; /* nonprintable: <xxxx> */
+ else
+ len += charlen;
+ }
+ }
+
+ attr_list = pango_attr_list_new();
+ buf = alloc(len + 1);
+
+ /* Now go for the real work */
+ if (buf != NULL)
+ {
+ attrentry_T *aep;
+ PangoAttribute *attr;
+ guicolor_T pixel;
+#if GTK_CHECK_VERSION(3,0,0)
+ GdkRGBA color = { 0.0, 0.0, 0.0, 1.0 };
+# if PANGO_VERSION_CHECK(1,38,0)
+ PangoAttribute *attr_alpha;
+# endif
+#else
+ GdkColor color = { 0, 0, 0, 0 };
+#endif
+
+ /* Look up the RGB values of the SpecialKey foreground color. */
+ aep = syn_gui_attr2entry(HL_ATTR(HLF_8));
+ pixel = (aep != NULL) ? aep->ae_u.gui.fg_color : INVALCOLOR;
+ if (pixel != INVALCOLOR)
+# if GTK_CHECK_VERSION(3,0,0)
+ {
+ color.red = ((pixel & 0xff0000) >> 16) / 255.0;
+ color.green = ((pixel & 0xff00) >> 8) / 255.0;
+ color.blue = (pixel & 0xff) / 255.0;
+ color.alpha = 1.0;
+ }
+# else
+ gdk_colormap_query_color(gtk_widget_get_colormap(gui.drawarea),
+ (unsigned long)pixel, &color);
+# endif
+
+ pdest = buf;
+ p = text;
+ while (*p != NUL)
+ {
+ /* Be quick for ASCII */
+ if ((*p & 0x80) == 0 && !IS_NONPRINTABLE(*p))
+ {
+ *pdest++ = *p++;
+ }
+ else
+ {
+ charlen = utf_ptr2len(p);
+ uc = utf_ptr2char(p);
+
+ if (charlen != utf_char2len(uc))
+ charlen = 1; /* reject overlong sequences */
+
+ if (charlen == 1 || uc < 0xa0 || !utf_printable(uc))
+ {
+ int outlen;
+
+ /* Careful: we can't just use transchar_byte() here,
+ * since 'encoding' is not necessarily set to "utf-8". */
+ if (*p & 0x80 && charlen == 1)
+ {
+ transchar_hex(pdest, *p); /* <xx> */
+ outlen = 4;
+ }
+ else if (uc >= 0x80)
+ {
+ /* Note: we assume here that utf_printable() doesn't
+ * care about characters outside the BMP. */
+ transchar_hex(pdest, uc); /* <xx> or <xxxx> */
+ outlen = (uc < 0x100) ? 4 : 6;
+ }
+ else
+ {
+ transchar_nonprint(pdest, *p); /* ^X */
+ outlen = 2;
+ }
+ if (pixel != INVALCOLOR)
+ {
+#if GTK_CHECK_VERSION(3,0,0)
+# define DOUBLE2UINT16(val) ((guint16)((val) * 65535 + 0.5))
+ attr = pango_attr_foreground_new(
+ DOUBLE2UINT16(color.red),
+ DOUBLE2UINT16(color.green),
+ DOUBLE2UINT16(color.blue));
+# if PANGO_VERSION_CHECK(1,38,0)
+ attr_alpha = pango_attr_foreground_alpha_new(
+ DOUBLE2UINT16(color.alpha));
+# endif
+# undef DOUBLE2UINT16
+#else
+ attr = pango_attr_foreground_new(
+ color.red, color.green, color.blue);
+#endif
+ attr->start_index = pdest - buf;
+ attr->end_index = pdest - buf + outlen;
+ pango_attr_list_insert(attr_list, attr);
+#if GTK_CHECK_VERSION(3,0,0)
+# if PANGO_VERSION_CHECK(1,38,0)
+ attr_alpha->start_index = pdest - buf;
+ attr_alpha->end_index = pdest - buf + outlen;
+ pango_attr_list_insert(attr_list, attr_alpha);
+# endif
+#endif
+ }
+ pdest += outlen;
+ p += charlen;
+ }
+ else
+ {
+ do
+ *pdest++ = *p++;
+ while (--charlen != 0);
+ }
+ }
+ }
+ *pdest = NUL;
+ }
+
+ vim_free(convbuf);
+
+ gtk_label_set_text(label, (const char *)buf);
+ vim_free(buf);
+
+ gtk_label_set_attributes(label, attr_list);
+ pango_attr_list_unref(attr_list);
+}
+# undef IS_NONPRINTABLE
+
+/*
+ * Draw a balloon.
+ */
+ static void
+drawBalloon(BalloonEval *beval)
+{
+ if (beval->msg != NULL)
+ {
+ GtkRequisition requisition;
+ int screen_w;
+ int screen_h;
+ int screen_x;
+ int screen_y;
+ int x;
+ int y;
+ int x_offset = EVAL_OFFSET_X;
+ int y_offset = EVAL_OFFSET_Y;
+ PangoLayout *layout;
+
+# if !GTK_CHECK_VERSION(3,22,2)
+ GdkScreen *screen;
+
+ screen = gtk_widget_get_screen(beval->target);
+ gtk_window_set_screen(GTK_WINDOW(beval->balloonShell), screen);
+# endif
+ gui_gtk_get_screen_geom_of_win(beval->target,
+ &screen_x, &screen_y, &screen_w, &screen_h);
+# if !GTK_CHECK_VERSION(3,0,0)
+ gtk_widget_ensure_style(beval->balloonShell);
+ gtk_widget_ensure_style(beval->balloonLabel);
+# endif
+
+ set_printable_label_text(GTK_LABEL(beval->balloonLabel), beval->msg);
+ /*
+ * Dirty trick: Enable wrapping mode on the label's layout behind its
+ * back. This way GtkLabel won't try to constrain the wrap width to a
+ * builtin maximum value of about 65 Latin characters.
+ */
+ layout = gtk_label_get_layout(GTK_LABEL(beval->balloonLabel));
+# ifdef PANGO_WRAP_WORD_CHAR
+ pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR);
+# else
+ pango_layout_set_wrap(layout, PANGO_WRAP_WORD);
+# endif
+ pango_layout_set_width(layout,
+ /* try to come up with some reasonable width */
+ PANGO_SCALE * CLAMP(gui.num_cols * gui.char_width,
+ screen_w / 2,
+ MAX(20, screen_w - 20)));
+
+ /* Calculate the balloon's width and height. */
+# if GTK_CHECK_VERSION(3,0,0)
+ gtk_widget_get_preferred_size(beval->balloonShell, &requisition, NULL);
+# else
+ gtk_widget_size_request(beval->balloonShell, &requisition);
+# endif
+
+ /* Compute position of the balloon area */
+ gdk_window_get_origin(gtk_widget_get_window(beval->target), &x, &y);
+ x += beval->x;
+ y += beval->y;
+
+ /* Get out of the way of the mouse pointer */
+ if (x + x_offset + requisition.width > screen_x + screen_w)
+ y_offset += 15;
+ if (y + y_offset + requisition.height > screen_y + screen_h)
+ y_offset = -requisition.height - EVAL_OFFSET_Y;
+
+ /* Sanitize values */
+ x = CLAMP(x + x_offset, 0,
+ MAX(0, screen_x + screen_w - requisition.width));
+ y = CLAMP(y + y_offset, 0,
+ MAX(0, screen_y + screen_h - requisition.height));
+
+ /* Show the balloon */
+# if GTK_CHECK_VERSION(3,0,0)
+ gtk_window_move(GTK_WINDOW(beval->balloonShell), x, y);
+# else
+ gtk_widget_set_uposition(beval->balloonShell, x, y);
+# endif
+ gtk_widget_show(beval->balloonShell);
+
+ beval->showState = ShS_SHOWING;
+ }
+}
+
+/*
+ * Undraw a balloon.
+ */
+ static void
+undrawBalloon(BalloonEval *beval)
+{
+ if (beval->balloonShell != NULL)
+ gtk_widget_hide(beval->balloonShell);
+ beval->showState = ShS_NEUTRAL;
+}
+
+ static void
+cancelBalloon(BalloonEval *beval)
+{
+ if (beval->showState == ShS_SHOWING
+ || beval->showState == ShS_UPDATE_PENDING)
+ undrawBalloon(beval);
+
+ if (beval->timerID != 0)
+ {
+ g_source_remove(beval->timerID);
+ beval->timerID = 0;
+ }
+ beval->showState = ShS_NEUTRAL;
+}
+
+ static void
+createBalloonEvalWindow(BalloonEval *beval)
+{
+ beval->balloonShell = gtk_window_new(GTK_WINDOW_POPUP);
+
+ gtk_widget_set_app_paintable(beval->balloonShell, TRUE);
+ gtk_window_set_resizable(GTK_WINDOW(beval->balloonShell), FALSE);
+ gtk_widget_set_name(beval->balloonShell, "gtk-tooltips");
+ gtk_container_set_border_width(GTK_CONTAINER(beval->balloonShell), 4);
+
+# if GTK_CHECK_VERSION(3,0,0)
+ g_signal_connect(G_OBJECT(beval->balloonShell), "draw",
+ G_CALLBACK(balloon_draw_event_cb), NULL);
+# else
+ gtk_signal_connect((GtkObject*)(beval->balloonShell), "expose_event",
+ GTK_SIGNAL_FUNC(balloon_expose_event_cb), NULL);
+# endif
+ beval->balloonLabel = gtk_label_new(NULL);
+
+ gtk_label_set_line_wrap(GTK_LABEL(beval->balloonLabel), FALSE);
+ gtk_label_set_justify(GTK_LABEL(beval->balloonLabel), GTK_JUSTIFY_LEFT);
+# if GTK_CHECK_VERSION(3,16,0)
+ gtk_label_set_xalign(GTK_LABEL(beval->balloonLabel), 0.5);
+ gtk_label_set_yalign(GTK_LABEL(beval->balloonLabel), 0.5);
+# elif GTK_CHECK_VERSION(3,14,0)
+ GValue align_val = G_VALUE_INIT;
+ g_value_init(&align_val, G_TYPE_FLOAT);
+ g_value_set_float(&align_val, 0.5);
+ g_object_set_property(G_OBJECT(beval->balloonLabel), "xalign", &align_val);
+ g_object_set_property(G_OBJECT(beval->balloonLabel), "yalign", &align_val);
+ g_value_unset(&align_val);
+# else
+ gtk_misc_set_alignment(GTK_MISC(beval->balloonLabel), 0.5f, 0.5f);
+# endif
+ gtk_widget_set_name(beval->balloonLabel, "vim-balloon-label");
+ gtk_widget_show(beval->balloonLabel);
+
+ gtk_container_add(GTK_CONTAINER(beval->balloonShell), beval->balloonLabel);
+}
+
+#else /* !FEAT_GUI_GTK */
+
+/*
+ * Draw a balloon.
+ */
+ static void
+drawBalloon(BalloonEval *beval)
+{
+ Dimension w;
+ Dimension h;
+ Position tx;
+ Position ty;
+
+ if (beval->msg != NULL)
+ {
+ /* Show the Balloon */
+
+ /* Calculate the label's width and height */
+#ifdef FEAT_GUI_MOTIF
+ XmString s;
+
+ /* For the callback function we parse NL characters to create a
+ * multi-line label. This doesn't work for all languages, but
+ * XmStringCreateLocalized() doesn't do multi-line labels... */
+ if (beval->msgCB != NULL)
+ s = XmStringCreateLtoR((char *)beval->msg, XmFONTLIST_DEFAULT_TAG);
+ else
+ s = XmStringCreateLocalized((char *)beval->msg);
+ {
+ XmFontList fl;
+
+ fl = gui_motif_fontset2fontlist(&gui.tooltip_fontset);
+ if (fl == NULL)
+ {
+ XmStringFree(s);
+ return;
+ }
+ XmStringExtent(fl, s, &w, &h);
+ XmFontListFree(fl);
+ }
+ w += gui.border_offset << 1;
+ h += gui.border_offset << 1;
+ XtVaSetValues(beval->balloonLabel, XmNlabelString, s, NULL);
+ XmStringFree(s);
+#else /* Athena */
+ /* Assume XtNinternational == True */
+ XFontSet fset;
+ XFontSetExtents *ext;
+
+ XtVaGetValues(beval->balloonLabel, XtNfontSet, &fset, NULL);
+ ext = XExtentsOfFontSet(fset);
+ h = ext->max_ink_extent.height;
+ w = XmbTextEscapement(fset,
+ (char *)beval->msg,
+ (int)STRLEN(beval->msg));
+ w += gui.border_offset << 1;
+ h += gui.border_offset << 1;
+ XtVaSetValues(beval->balloonLabel, XtNlabel, beval->msg, NULL);
+#endif
+
+ /* Compute position of the balloon area */
+ tx = beval->x_root + EVAL_OFFSET_X;
+ ty = beval->y_root + EVAL_OFFSET_Y;
+ if ((tx + w) > beval->screen_width)
+ tx = beval->screen_width - w;
+ if ((ty + h) > beval->screen_height)
+ ty = beval->screen_height - h;
+#ifdef FEAT_GUI_MOTIF
+ XtVaSetValues(beval->balloonShell,
+ XmNx, tx,
+ XmNy, ty,
+ NULL);
+#else
+ /* Athena */
+ XtVaSetValues(beval->balloonShell,
+ XtNx, tx,
+ XtNy, ty,
+ NULL);
+#endif
+ /* Set tooltip colors */
+ {
+ Arg args[2];
+
+#ifdef FEAT_GUI_MOTIF
+ args[0].name = XmNbackground;
+ args[0].value = gui.tooltip_bg_pixel;
+ args[1].name = XmNforeground;
+ args[1].value = gui.tooltip_fg_pixel;
+#else /* Athena */
+ args[0].name = XtNbackground;
+ args[0].value = gui.tooltip_bg_pixel;
+ args[1].name = XtNforeground;
+ args[1].value = gui.tooltip_fg_pixel;
+#endif
+ XtSetValues(beval->balloonLabel, &args[0], XtNumber(args));
+ }
+
+ XtPopup(beval->balloonShell, XtGrabNone);
+
+ beval->showState = ShS_SHOWING;
+
+ current_beval = beval;
+ }
+}
+
+/*
+ * Undraw a balloon.
+ */
+ static void
+undrawBalloon(BalloonEval *beval)
+{
+ if (beval->balloonShell != (Widget)0)
+ XtPopdown(beval->balloonShell);
+ beval->showState = ShS_NEUTRAL;
+
+ current_beval = NULL;
+}
+
+ static void
+cancelBalloon(BalloonEval *beval)
+{
+ if (beval->showState == ShS_SHOWING
+ || beval->showState == ShS_UPDATE_PENDING)
+ undrawBalloon(beval);
+
+ if (beval->timerID != (XtIntervalId)NULL)
+ {
+ XtRemoveTimeOut(beval->timerID);
+ beval->timerID = (XtIntervalId)NULL;
+ }
+ beval->showState = ShS_NEUTRAL;
+}
+
+
+ static void
+createBalloonEvalWindow(BalloonEval *beval)
+{
+ Arg args[12];
+ int n;
+
+ n = 0;
+#ifdef FEAT_GUI_MOTIF
+ XtSetArg(args[n], XmNallowShellResize, True); n++;
+ beval->balloonShell = XtAppCreateShell("balloonEval", "BalloonEval",
+ overrideShellWidgetClass, gui.dpy, args, n);
+#else
+ /* Athena */
+ XtSetArg(args[n], XtNallowShellResize, True); n++;
+ beval->balloonShell = XtAppCreateShell("balloonEval", "BalloonEval",
+ overrideShellWidgetClass, gui.dpy, args, n);
+#endif
+
+ n = 0;
+#ifdef FEAT_GUI_MOTIF
+ {
+ XmFontList fl;
+
+ fl = gui_motif_fontset2fontlist(&gui.tooltip_fontset);
+ XtSetArg(args[n], XmNforeground, gui.tooltip_fg_pixel); n++;
+ XtSetArg(args[n], XmNbackground, gui.tooltip_bg_pixel); n++;
+ XtSetArg(args[n], XmNfontList, fl); n++;
+ XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
+ beval->balloonLabel = XtCreateManagedWidget("balloonLabel",
+ xmLabelWidgetClass, beval->balloonShell, args, n);
+ }
+#else /* FEAT_GUI_ATHENA */
+ XtSetArg(args[n], XtNforeground, gui.tooltip_fg_pixel); n++;
+ XtSetArg(args[n], XtNbackground, gui.tooltip_bg_pixel); n++;
+ XtSetArg(args[n], XtNinternational, True); n++;
+ XtSetArg(args[n], XtNfontSet, gui.tooltip_fontset); n++;
+ beval->balloonLabel = XtCreateManagedWidget("balloonLabel",
+ labelWidgetClass, beval->balloonShell, args, n);
+#endif
+}
+
+#endif /* !FEAT_GUI_GTK */
+#endif /* !FEAT_GUI_W32 */
+
+#endif /* FEAT_BEVAL_GUI */
diff --git a/src/gui_dwrite.cpp b/src/gui_dwrite.cpp
new file mode 100644
index 0000000..8e03dff
--- /dev/null
+++ b/src/gui_dwrite.cpp
@@ -0,0 +1,1345 @@
+/* vi:set ts=8 sts=4 sw=4 noet: */
+/*
+ * Author: MURAOKA Taro <koron.kaoriya@gmail.com>
+ *
+ * Contributors:
+ * - Ken Takata
+ * - Yasuhiro Matsumoto
+ *
+ * Copyright (C) 2013 MURAOKA Taro <koron.kaoriya@gmail.com>
+ * THIS FILE IS DISTRIBUTED UNDER THE VIM LICENSE.
+ */
+
+#define WIN32_LEAN_AND_MEAN
+
+#ifndef DYNAMIC_DIRECTX
+# if WINVER < 0x0600
+# error WINVER must be 0x0600 or above to use DirectWrite(DirectX)
+# endif
+#endif
+
+#include <windows.h>
+#include <crtdbg.h>
+#include <assert.h>
+#include <math.h>
+#include <d2d1.h>
+#include <d2d1helper.h>
+
+// Disable these macros to compile with old VC and newer SDK (V8.1 or later).
+#if defined(_MSC_VER) && (_MSC_VER < 1700)
+# define _COM_Outptr_ __out
+# define _In_reads_(s)
+# define _In_reads_opt_(s)
+# define _Maybenull_
+# define _Out_writes_(s)
+# define _Out_writes_opt_(s)
+# define _Out_writes_to_(x, y)
+# define _Out_writes_to_opt_(x, y)
+# define _Outptr_
+#endif
+
+#ifdef FEAT_DIRECTX_COLOR_EMOJI
+# include <dwrite_2.h>
+#else
+# include <dwrite.h>
+#endif
+
+#include "gui_dwrite.h"
+
+#ifdef __MINGW32__
+# define __maybenull SAL__maybenull
+# define __in SAL__in
+# define __out SAL__out
+#endif
+
+#if (defined(_MSC_VER) && (_MSC_VER >= 1700)) || (__cplusplus >= 201103L)
+# define FINAL final
+#else
+# define FINAL
+#endif
+
+#ifdef DYNAMIC_DIRECTX
+extern "C" HINSTANCE vimLoadLib(char *name);
+
+typedef int (WINAPI *PGETUSERDEFAULTLOCALENAME)(LPWSTR, int);
+typedef HRESULT (WINAPI *PD2D1CREATEFACTORY)(D2D1_FACTORY_TYPE,
+ REFIID, const D2D1_FACTORY_OPTIONS *, void **);
+typedef HRESULT (WINAPI *PDWRITECREATEFACTORY)(DWRITE_FACTORY_TYPE,
+ REFIID, IUnknown **);
+
+static HINSTANCE hD2D1DLL = NULL;
+static HINSTANCE hDWriteDLL = NULL;
+
+static PGETUSERDEFAULTLOCALENAME pGetUserDefaultLocaleName = NULL;
+static PD2D1CREATEFACTORY pD2D1CreateFactory = NULL;
+static PDWRITECREATEFACTORY pDWriteCreateFactory = NULL;
+
+#define GetUserDefaultLocaleName (*pGetUserDefaultLocaleName)
+#define D2D1CreateFactory (*pD2D1CreateFactory)
+#define DWriteCreateFactory (*pDWriteCreateFactory)
+
+ static void
+unload(HINSTANCE &hinst)
+{
+ if (hinst != NULL)
+ {
+ FreeLibrary(hinst);
+ hinst = NULL;
+ }
+}
+#endif // DYNAMIC_DIRECTX
+
+template <class T> inline void SafeRelease(T **ppT)
+{
+ if (*ppT)
+ {
+ (*ppT)->Release();
+ *ppT = NULL;
+ }
+}
+
+ static DWRITE_PIXEL_GEOMETRY
+ToPixelGeometry(int value)
+{
+ switch (value)
+ {
+ default:
+ case 0:
+ return DWRITE_PIXEL_GEOMETRY_FLAT;
+ case 1:
+ return DWRITE_PIXEL_GEOMETRY_RGB;
+ case 2:
+ return DWRITE_PIXEL_GEOMETRY_BGR;
+ }
+}
+
+ static int
+ToInt(DWRITE_PIXEL_GEOMETRY value)
+{
+ switch (value)
+ {
+ case DWRITE_PIXEL_GEOMETRY_FLAT:
+ return 0;
+ case DWRITE_PIXEL_GEOMETRY_RGB:
+ return 1;
+ case DWRITE_PIXEL_GEOMETRY_BGR:
+ return 2;
+ default:
+ return -1;
+ }
+}
+
+ static DWRITE_RENDERING_MODE
+ToRenderingMode(int value)
+{
+ switch (value)
+ {
+ default:
+ case 0:
+ return DWRITE_RENDERING_MODE_DEFAULT;
+ case 1:
+ return DWRITE_RENDERING_MODE_ALIASED;
+ case 2:
+ return DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC;
+ case 3:
+ return DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL;
+ case 4:
+ return DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL;
+ case 5:
+ return DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC;
+ case 6:
+ return DWRITE_RENDERING_MODE_OUTLINE;
+ }
+}
+
+ static D2D1_TEXT_ANTIALIAS_MODE
+ToTextAntialiasMode(int value)
+{
+ switch (value)
+ {
+ default:
+ case 0:
+ return D2D1_TEXT_ANTIALIAS_MODE_DEFAULT;
+ case 1:
+ return D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE;
+ case 2:
+ return D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE;
+ case 3:
+ return D2D1_TEXT_ANTIALIAS_MODE_ALIASED;
+ }
+}
+
+ static int
+ToInt(DWRITE_RENDERING_MODE value)
+{
+ switch (value)
+ {
+ case DWRITE_RENDERING_MODE_DEFAULT:
+ return 0;
+ case DWRITE_RENDERING_MODE_ALIASED:
+ return 1;
+ case DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC:
+ return 2;
+ case DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL:
+ return 3;
+ case DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL:
+ return 4;
+ case DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC:
+ return 5;
+ case DWRITE_RENDERING_MODE_OUTLINE:
+ return 6;
+ default:
+ return -1;
+ }
+}
+
+class FontCache {
+public:
+ struct Item {
+ HFONT hFont;
+ IDWriteTextFormat* pTextFormat;
+ DWRITE_FONT_WEIGHT fontWeight;
+ DWRITE_FONT_STYLE fontStyle;
+ Item() : hFont(NULL), pTextFormat(NULL) {}
+ };
+
+private:
+ int mSize;
+ Item *mItems;
+
+public:
+ FontCache(int size = 2) :
+ mSize(size),
+ mItems(new Item[size])
+ {
+ }
+
+ ~FontCache()
+ {
+ for (int i = 0; i < mSize; ++i)
+ SafeRelease(&mItems[i].pTextFormat);
+ delete[] mItems;
+ }
+
+ bool get(HFONT hFont, Item &item)
+ {
+ int n = find(hFont);
+ if (n < 0)
+ return false;
+ item = mItems[n];
+ slide(n);
+ return true;
+ }
+
+ void put(const Item& item)
+ {
+ int n = find(item.hFont);
+ if (n < 0)
+ n = mSize - 1;
+ if (mItems[n].pTextFormat != item.pTextFormat)
+ {
+ SafeRelease(&mItems[n].pTextFormat);
+ item.pTextFormat->AddRef();
+ }
+ mItems[n] = item;
+ slide(n);
+ }
+
+private:
+ int find(HFONT hFont)
+ {
+ for (int i = 0; i < mSize; ++i)
+ {
+ if (mItems[i].hFont == hFont)
+ return i;
+ }
+ return -1;
+ }
+
+ void slide(int nextTop)
+ {
+ if (nextTop == 0)
+ return;
+ Item tmp = mItems[nextTop];
+ for (int i = nextTop - 1; i >= 0; --i)
+ mItems[i + 1] = mItems[i];
+ mItems[0] = tmp;
+ }
+};
+
+enum DrawingMode {
+ DM_GDI = 0,
+ DM_DIRECTX = 1,
+ DM_INTEROP = 2,
+};
+
+struct DWriteContext {
+ HDC mHDC;
+ RECT mBindRect;
+ DrawingMode mDMode;
+ HDC mInteropHDC;
+ bool mDrawing;
+ bool mFallbackDC;
+
+ ID2D1Factory *mD2D1Factory;
+
+ ID2D1DCRenderTarget *mRT;
+ ID2D1GdiInteropRenderTarget *mGDIRT;
+ ID2D1SolidColorBrush *mBrush;
+ ID2D1Bitmap *mBitmap;
+
+ IDWriteFactory *mDWriteFactory;
+#ifdef FEAT_DIRECTX_COLOR_EMOJI
+ IDWriteFactory2 *mDWriteFactory2;
+#endif
+
+ IDWriteGdiInterop *mGdiInterop;
+ IDWriteRenderingParams *mRenderingParams;
+
+ FontCache mFontCache;
+ IDWriteTextFormat *mTextFormat;
+ DWRITE_FONT_WEIGHT mFontWeight;
+ DWRITE_FONT_STYLE mFontStyle;
+
+ D2D1_TEXT_ANTIALIAS_MODE mTextAntialiasMode;
+
+ // METHODS
+
+ DWriteContext();
+
+ virtual ~DWriteContext();
+
+ HRESULT CreateDeviceResources();
+
+ void DiscardDeviceResources();
+
+ HRESULT CreateTextFormatFromLOGFONT(const LOGFONTW &logFont,
+ IDWriteTextFormat **ppTextFormat);
+
+ HRESULT SetFontByLOGFONT(const LOGFONTW &logFont);
+
+ void SetFont(HFONT hFont);
+
+ void Rebind();
+
+ void BindDC(HDC hdc, const RECT *rect);
+
+ HRESULT SetDrawingMode(DrawingMode mode);
+
+ ID2D1Brush* SolidBrush(COLORREF color);
+
+ void DrawText(const WCHAR *text, int len,
+ int x, int y, int w, int h, int cellWidth, COLORREF color,
+ UINT fuOptions, const RECT *lprc, const INT *lpDx);
+
+ void FillRect(const RECT *rc, COLORREF color);
+
+ void DrawLine(int x1, int y1, int x2, int y2, COLORREF color);
+
+ void SetPixel(int x, int y, COLORREF color);
+
+ void Scroll(int x, int y, const RECT *rc);
+
+ void Flush();
+
+ void SetRenderingParams(
+ const DWriteRenderingParams *params);
+
+ DWriteRenderingParams *GetRenderingParams(
+ DWriteRenderingParams *params);
+};
+
+class AdjustedGlyphRun : public DWRITE_GLYPH_RUN
+{
+private:
+ FLOAT &mAccum;
+ FLOAT mDelta;
+ FLOAT *mAdjustedAdvances;
+
+public:
+ AdjustedGlyphRun(
+ const DWRITE_GLYPH_RUN *glyphRun,
+ FLOAT cellWidth,
+ FLOAT &accum) :
+ DWRITE_GLYPH_RUN(*glyphRun),
+ mAccum(accum),
+ mDelta(0.0f),
+ mAdjustedAdvances(new FLOAT[glyphRun->glyphCount])
+ {
+ assert(cellWidth != 0.0f);
+ for (UINT32 i = 0; i < glyphRun->glyphCount; ++i)
+ {
+ FLOAT orig = glyphRun->glyphAdvances[i];
+ FLOAT adjusted = adjustToCell(orig, cellWidth);
+ mAdjustedAdvances[i] = adjusted;
+ mDelta += adjusted - orig;
+ }
+ glyphAdvances = mAdjustedAdvances;
+ }
+
+ ~AdjustedGlyphRun()
+ {
+ mAccum += mDelta;
+ delete[] mAdjustedAdvances;
+ }
+
+ static FLOAT adjustToCell(FLOAT value, FLOAT cellWidth)
+ {
+ int cellCount = int(floor(value / cellWidth + 0.5f));
+ if (cellCount < 1)
+ cellCount = 1;
+ return cellCount * cellWidth;
+ }
+};
+
+struct TextRendererContext {
+ // const fields.
+ COLORREF color;
+ FLOAT cellWidth;
+
+ // working fields.
+ FLOAT offsetX;
+};
+
+class TextRenderer FINAL : public IDWriteTextRenderer
+{
+public:
+ TextRenderer(
+ DWriteContext* pDWC) :
+ cRefCount_(0),
+ pDWC_(pDWC)
+ {
+ AddRef();
+ }
+
+ // add "virtual" to avoid a compiler warning
+ virtual ~TextRenderer()
+ {
+ }
+
+ IFACEMETHOD(IsPixelSnappingDisabled)(
+ __maybenull void* clientDrawingContext,
+ __out BOOL* isDisabled)
+ {
+ *isDisabled = FALSE;
+ return S_OK;
+ }
+
+ IFACEMETHOD(GetCurrentTransform)(
+ __maybenull void* clientDrawingContext,
+ __out DWRITE_MATRIX* transform)
+ {
+ // forward the render target's transform
+ pDWC_->mRT->GetTransform(
+ reinterpret_cast<D2D1_MATRIX_3X2_F*>(transform));
+ return S_OK;
+ }
+
+ IFACEMETHOD(GetPixelsPerDip)(
+ __maybenull void* clientDrawingContext,
+ __out FLOAT* pixelsPerDip)
+ {
+ float dpiX, unused;
+ pDWC_->mRT->GetDpi(&dpiX, &unused);
+ *pixelsPerDip = dpiX / 96.0f;
+ return S_OK;
+ }
+
+ IFACEMETHOD(DrawUnderline)(
+ __maybenull void* clientDrawingContext,
+ FLOAT baselineOriginX,
+ FLOAT baselineOriginY,
+ __in DWRITE_UNDERLINE const* underline,
+ IUnknown* clientDrawingEffect)
+ {
+ return E_NOTIMPL;
+ }
+
+ IFACEMETHOD(DrawStrikethrough)(
+ __maybenull void* clientDrawingContext,
+ FLOAT baselineOriginX,
+ FLOAT baselineOriginY,
+ __in DWRITE_STRIKETHROUGH const* strikethrough,
+ IUnknown* clientDrawingEffect)
+ {
+ return E_NOTIMPL;
+ }
+
+ IFACEMETHOD(DrawInlineObject)(
+ __maybenull void* clientDrawingContext,
+ FLOAT originX,
+ FLOAT originY,
+ IDWriteInlineObject* inlineObject,
+ BOOL isSideways,
+ BOOL isRightToLeft,
+ IUnknown* clientDrawingEffect)
+ {
+ return E_NOTIMPL;
+ }
+
+ IFACEMETHOD(DrawGlyphRun)(
+ __maybenull void* clientDrawingContext,
+ FLOAT baselineOriginX,
+ FLOAT baselineOriginY,
+ DWRITE_MEASURING_MODE measuringMode,
+ __in DWRITE_GLYPH_RUN const* glyphRun,
+ __in DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription,
+ IUnknown* clientDrawingEffect)
+ {
+ TextRendererContext *context =
+ reinterpret_cast<TextRendererContext*>(clientDrawingContext);
+
+ AdjustedGlyphRun adjustedGlyphRun(glyphRun, context->cellWidth,
+ context->offsetX);
+
+#ifdef FEAT_DIRECTX_COLOR_EMOJI
+ if (pDWC_->mDWriteFactory2 != NULL)
+ {
+ IDWriteColorGlyphRunEnumerator *enumerator = NULL;
+ HRESULT hr = pDWC_->mDWriteFactory2->TranslateColorGlyphRun(
+ baselineOriginX + context->offsetX,
+ baselineOriginY,
+ &adjustedGlyphRun,
+ NULL,
+ DWRITE_MEASURING_MODE_GDI_NATURAL,
+ NULL,
+ 0,
+ &enumerator);
+ if (SUCCEEDED(hr))
+ {
+ // Draw by IDWriteFactory2 for color emoji
+ BOOL hasRun = TRUE;
+ enumerator->MoveNext(&hasRun);
+ while (hasRun)
+ {
+ const DWRITE_COLOR_GLYPH_RUN* colorGlyphRun;
+ enumerator->GetCurrentRun(&colorGlyphRun);
+
+ pDWC_->mBrush->SetColor(colorGlyphRun->runColor);
+ pDWC_->mRT->DrawGlyphRun(
+ D2D1::Point2F(
+ colorGlyphRun->baselineOriginX,
+ colorGlyphRun->baselineOriginY),
+ &colorGlyphRun->glyphRun,
+ pDWC_->mBrush,
+ DWRITE_MEASURING_MODE_NATURAL);
+ enumerator->MoveNext(&hasRun);
+ }
+ SafeRelease(&enumerator);
+ return S_OK;
+ }
+ }
+#endif
+
+ // Draw by IDWriteFactory (without color emoji)
+ pDWC_->mRT->DrawGlyphRun(
+ D2D1::Point2F(
+ baselineOriginX + context->offsetX,
+ baselineOriginY),
+ &adjustedGlyphRun,
+ pDWC_->SolidBrush(context->color),
+ DWRITE_MEASURING_MODE_NATURAL);
+ return S_OK;
+ }
+
+public:
+ IFACEMETHOD_(unsigned long, AddRef) ()
+ {
+ return InterlockedIncrement(&cRefCount_);
+ }
+
+ IFACEMETHOD_(unsigned long, Release) ()
+ {
+ long newCount = InterlockedDecrement(&cRefCount_);
+
+ if (newCount == 0)
+ {
+ delete this;
+ return 0;
+ }
+ return newCount;
+ }
+
+ IFACEMETHOD(QueryInterface)(
+ IID const& riid,
+ void** ppvObject)
+ {
+ if (__uuidof(IDWriteTextRenderer) == riid)
+ {
+ *ppvObject = this;
+ }
+ else if (__uuidof(IDWritePixelSnapping) == riid)
+ {
+ *ppvObject = this;
+ }
+ else if (__uuidof(IUnknown) == riid)
+ {
+ *ppvObject = this;
+ }
+ else
+ {
+ *ppvObject = NULL;
+ return E_FAIL;
+ }
+
+ return S_OK;
+ }
+
+private:
+ long cRefCount_;
+ DWriteContext* pDWC_;
+};
+
+DWriteContext::DWriteContext() :
+ mHDC(NULL),
+ mBindRect(),
+ mDMode(DM_GDI),
+ mInteropHDC(NULL),
+ mDrawing(false),
+ mFallbackDC(false),
+ mD2D1Factory(NULL),
+ mRT(NULL),
+ mGDIRT(NULL),
+ mBrush(NULL),
+ mBitmap(NULL),
+ mDWriteFactory(NULL),
+#ifdef FEAT_DIRECTX_COLOR_EMOJI
+ mDWriteFactory2(NULL),
+#endif
+ mGdiInterop(NULL),
+ mRenderingParams(NULL),
+ mFontCache(8),
+ mTextFormat(NULL),
+ mFontWeight(DWRITE_FONT_WEIGHT_NORMAL),
+ mFontStyle(DWRITE_FONT_STYLE_NORMAL),
+ mTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_DEFAULT)
+{
+ HRESULT hr;
+
+ hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED,
+ __uuidof(ID2D1Factory), NULL,
+ reinterpret_cast<void**>(&mD2D1Factory));
+ _RPT2(_CRT_WARN, "D2D1CreateFactory: hr=%p p=%p\n", hr, mD2D1Factory);
+
+ if (SUCCEEDED(hr))
+ {
+ hr = DWriteCreateFactory(
+ DWRITE_FACTORY_TYPE_SHARED,
+ __uuidof(IDWriteFactory),
+ reinterpret_cast<IUnknown**>(&mDWriteFactory));
+ _RPT2(_CRT_WARN, "DWriteCreateFactory: hr=%p p=%p\n", hr,
+ mDWriteFactory);
+ }
+
+#ifdef FEAT_DIRECTX_COLOR_EMOJI
+ if (SUCCEEDED(hr))
+ {
+ DWriteCreateFactory(
+ DWRITE_FACTORY_TYPE_SHARED,
+ __uuidof(IDWriteFactory2),
+ reinterpret_cast<IUnknown**>(&mDWriteFactory2));
+ _RPT1(_CRT_WARN, "IDWriteFactory2: %s\n", SUCCEEDED(hr) ? "available" : "not available");
+ }
+#endif
+
+ if (SUCCEEDED(hr))
+ {
+ hr = mDWriteFactory->GetGdiInterop(&mGdiInterop);
+ _RPT2(_CRT_WARN, "GetGdiInterop: hr=%p p=%p\n", hr, mGdiInterop);
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = mDWriteFactory->CreateRenderingParams(&mRenderingParams);
+ _RPT2(_CRT_WARN, "CreateRenderingParams: hr=%p p=%p\n", hr,
+ mRenderingParams);
+ }
+}
+
+DWriteContext::~DWriteContext()
+{
+ SafeRelease(&mTextFormat);
+ SafeRelease(&mRenderingParams);
+ SafeRelease(&mGdiInterop);
+ SafeRelease(&mDWriteFactory);
+#ifdef FEAT_DIRECTX_COLOR_EMOJI
+ SafeRelease(&mDWriteFactory2);
+#endif
+ SafeRelease(&mBitmap);
+ SafeRelease(&mBrush);
+ SafeRelease(&mGDIRT);
+ SafeRelease(&mRT);
+ SafeRelease(&mD2D1Factory);
+}
+
+ HRESULT
+DWriteContext::CreateDeviceResources()
+{
+ HRESULT hr;
+
+ if (mRT != NULL)
+ return S_OK;
+
+ D2D1_RENDER_TARGET_PROPERTIES props = {
+ D2D1_RENDER_TARGET_TYPE_DEFAULT,
+ { DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE },
+ 0, 0,
+ D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE,
+ D2D1_FEATURE_LEVEL_DEFAULT
+ };
+ hr = mD2D1Factory->CreateDCRenderTarget(&props, &mRT);
+ _RPT2(_CRT_WARN, "CreateDCRenderTarget: hr=%p p=%p\n", hr, mRT);
+
+ if (SUCCEEDED(hr))
+ {
+ // This always succeeds.
+ mRT->QueryInterface(
+ __uuidof(ID2D1GdiInteropRenderTarget),
+ reinterpret_cast<void**>(&mGDIRT));
+ _RPT1(_CRT_WARN, "GdiInteropRenderTarget: p=%p\n", mGDIRT);
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = mRT->CreateSolidColorBrush(
+ D2D1::ColorF(D2D1::ColorF::Black),
+ &mBrush);
+ _RPT2(_CRT_WARN, "CreateSolidColorBrush: hr=%p p=%p\n", hr, mBrush);
+ }
+
+ if (SUCCEEDED(hr))
+ Rebind();
+
+ return hr;
+}
+
+ void
+DWriteContext::DiscardDeviceResources()
+{
+ SafeRelease(&mBitmap);
+ SafeRelease(&mBrush);
+ SafeRelease(&mGDIRT);
+ SafeRelease(&mRT);
+}
+
+ HRESULT
+DWriteContext::CreateTextFormatFromLOGFONT(const LOGFONTW &logFont,
+ IDWriteTextFormat **ppTextFormat)
+{
+ // Most of this function is copied from: https://github.com/Microsoft/Windows-classic-samples/blob/master/Samples/Win7Samples/multimedia/DirectWrite/RenderTest/TextHelpers.cpp
+ HRESULT hr = S_OK;
+ IDWriteTextFormat *pTextFormat = NULL;
+
+ IDWriteFont *font = NULL;
+ IDWriteFontFamily *fontFamily = NULL;
+ IDWriteLocalizedStrings *localizedFamilyNames = NULL;
+ float fontSize = 0;
+
+ if (SUCCEEDED(hr))
+ {
+ hr = mGdiInterop->CreateFontFromLOGFONT(&logFont, &font);
+ }
+
+ // Get the font family to which this font belongs.
+ if (SUCCEEDED(hr))
+ {
+ hr = font->GetFontFamily(&fontFamily);
+ }
+
+ // Get the family names. This returns an object that encapsulates one or
+ // more names with the same meaning but in different languages.
+ if (SUCCEEDED(hr))
+ {
+ hr = fontFamily->GetFamilyNames(&localizedFamilyNames);
+ }
+
+ // Get the family name at index zero. If we were going to display the name
+ // we'd want to try to find one that matched the use locale, but for
+ // purposes of creating a text format object any language will do.
+
+ wchar_t familyName[100];
+ if (SUCCEEDED(hr))
+ {
+ hr = localizedFamilyNames->GetString(0, familyName,
+ ARRAYSIZE(familyName));
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ // Use lfHeight of the LOGFONT as font size.
+ fontSize = float(logFont.lfHeight);
+
+ if (fontSize < 0)
+ {
+ // Negative lfHeight represents the size of the em unit.
+ fontSize = -fontSize;
+ }
+ else
+ {
+ // Positive lfHeight represents the cell height (ascent +
+ // descent).
+ DWRITE_FONT_METRICS fontMetrics;
+ font->GetMetrics(&fontMetrics);
+
+ // Convert the cell height (ascent + descent) from design units
+ // to ems.
+ float cellHeight = static_cast<float>(
+ fontMetrics.ascent + fontMetrics.descent)
+ / fontMetrics.designUnitsPerEm;
+
+ // Divide the font size by the cell height to get the font em
+ // size.
+ fontSize /= cellHeight;
+ }
+ }
+
+ // The text format includes a locale name. Ideally, this would be the
+ // language of the text, which may or may not be the same as the primary
+ // language of the user. However, for our purposes the user locale will do.
+ wchar_t localeName[LOCALE_NAME_MAX_LENGTH];
+ if (SUCCEEDED(hr))
+ {
+ if (GetUserDefaultLocaleName(localeName, LOCALE_NAME_MAX_LENGTH) == 0)
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ // Create the text format object.
+ hr = mDWriteFactory->CreateTextFormat(
+ familyName,
+ NULL, // no custom font collection
+ font->GetWeight(),
+ font->GetStyle(),
+ font->GetStretch(),
+ fontSize,
+ localeName,
+ &pTextFormat);
+ }
+
+ if (SUCCEEDED(hr))
+ hr = pTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING);
+
+ if (SUCCEEDED(hr))
+ hr = pTextFormat->SetParagraphAlignment(
+ DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
+
+ if (SUCCEEDED(hr))
+ hr = pTextFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP);
+
+ SafeRelease(&localizedFamilyNames);
+ SafeRelease(&fontFamily);
+ SafeRelease(&font);
+
+ if (SUCCEEDED(hr))
+ *ppTextFormat = pTextFormat;
+ else
+ SafeRelease(&pTextFormat);
+
+ return hr;
+}
+
+ HRESULT
+DWriteContext::SetFontByLOGFONT(const LOGFONTW &logFont)
+{
+ HRESULT hr = S_OK;
+ IDWriteTextFormat *pTextFormat = NULL;
+
+ hr = CreateTextFormatFromLOGFONT(logFont, &pTextFormat);
+
+ if (SUCCEEDED(hr))
+ {
+ SafeRelease(&mTextFormat);
+ mTextFormat = pTextFormat;
+ mFontWeight = static_cast<DWRITE_FONT_WEIGHT>(logFont.lfWeight);
+ mFontStyle = logFont.lfItalic ? DWRITE_FONT_STYLE_ITALIC
+ : DWRITE_FONT_STYLE_NORMAL;
+ }
+
+ return hr;
+}
+
+ void
+DWriteContext::SetFont(HFONT hFont)
+{
+ FontCache::Item item;
+ if (mFontCache.get(hFont, item))
+ {
+ if (item.pTextFormat != NULL)
+ {
+ item.pTextFormat->AddRef();
+ SafeRelease(&mTextFormat);
+ mTextFormat = item.pTextFormat;
+ mFontWeight = item.fontWeight;
+ mFontStyle = item.fontStyle;
+ mFallbackDC = false;
+ }
+ else
+ mFallbackDC = true;
+ return;
+ }
+
+ HRESULT hr = E_FAIL;
+ LOGFONTW lf;
+ if (GetObjectW(hFont, sizeof(lf), &lf))
+ hr = SetFontByLOGFONT(lf);
+
+ item.hFont = hFont;
+ if (SUCCEEDED(hr))
+ {
+ item.pTextFormat = mTextFormat;
+ item.fontWeight = mFontWeight;
+ item.fontStyle = mFontStyle;
+ mFallbackDC = false;
+ }
+ else
+ mFallbackDC = true;
+ mFontCache.put(item);
+}
+
+ void
+DWriteContext::Rebind()
+{
+ SafeRelease(&mBitmap);
+
+ mRT->BindDC(mHDC, &mBindRect);
+ mRT->SetTransform(D2D1::IdentityMatrix());
+
+ D2D1_BITMAP_PROPERTIES props = {
+ {DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE},
+ 96.0f, 96.0f
+ };
+ mRT->CreateBitmap(
+ D2D1::SizeU(mBindRect.right - mBindRect.left,
+ mBindRect.bottom - mBindRect.top),
+ props, &mBitmap);
+}
+
+ void
+DWriteContext::BindDC(HDC hdc, const RECT *rect)
+{
+ mHDC = hdc;
+ mBindRect = *rect;
+
+ if (mRT == NULL)
+ CreateDeviceResources();
+ else
+ {
+ Flush();
+ Rebind();
+ }
+}
+
+ HRESULT
+DWriteContext::SetDrawingMode(DrawingMode mode)
+{
+ HRESULT hr = S_OK;
+
+ switch (mode)
+ {
+ default:
+ case DM_GDI:
+ if (mInteropHDC != NULL)
+ {
+ mGDIRT->ReleaseDC(NULL);
+ mInteropHDC = NULL;
+ }
+ if (mDrawing)
+ {
+ hr = mRT->EndDraw();
+ if (hr == D2DERR_RECREATE_TARGET)
+ {
+ hr = S_OK;
+ DiscardDeviceResources();
+ CreateDeviceResources();
+ }
+ mDrawing = false;
+ }
+ break;
+
+ case DM_DIRECTX:
+ if (mInteropHDC != NULL)
+ {
+ mGDIRT->ReleaseDC(NULL);
+ mInteropHDC = NULL;
+ }
+ else if (mDrawing == false)
+ {
+ CreateDeviceResources();
+ mRT->BeginDraw();
+ mDrawing = true;
+ }
+ break;
+
+ case DM_INTEROP:
+ if (mDrawing == false)
+ {
+ CreateDeviceResources();
+ mRT->BeginDraw();
+ mDrawing = true;
+ }
+ if (mInteropHDC == NULL)
+ hr = mGDIRT->GetDC(D2D1_DC_INITIALIZE_MODE_COPY, &mInteropHDC);
+ break;
+ }
+ mDMode = mode;
+ return hr;
+}
+
+ ID2D1Brush*
+DWriteContext::SolidBrush(COLORREF color)
+{
+ mBrush->SetColor(D2D1::ColorF(UINT32(GetRValue(color)) << 16 |
+ UINT32(GetGValue(color)) << 8 | UINT32(GetBValue(color))));
+ return mBrush;
+}
+
+ void
+DWriteContext::DrawText(const WCHAR *text, int len,
+ int x, int y, int w, int h, int cellWidth, COLORREF color,
+ UINT fuOptions, const RECT *lprc, const INT *lpDx)
+{
+ if (mFallbackDC)
+ {
+ // Fall back to GDI rendering.
+ HRESULT hr = SetDrawingMode(DM_INTEROP);
+ if (SUCCEEDED(hr))
+ {
+ HGDIOBJ hFont = ::GetCurrentObject(mHDC, OBJ_FONT);
+ HGDIOBJ hOldFont = ::SelectObject(mInteropHDC, hFont);
+ ::SetTextColor(mInteropHDC, color);
+ ::SetBkMode(mInteropHDC, ::GetBkMode(mHDC));
+ ::ExtTextOutW(mInteropHDC, x, y, fuOptions, lprc, text, len, lpDx);
+ ::SelectObject(mInteropHDC, hOldFont);
+ }
+ return;
+ }
+
+ HRESULT hr;
+ IDWriteTextLayout *textLayout = NULL;
+
+ SetDrawingMode(DM_DIRECTX);
+
+ hr = mDWriteFactory->CreateTextLayout(text, len, mTextFormat,
+ FLOAT(w), FLOAT(h), &textLayout);
+
+ if (SUCCEEDED(hr))
+ {
+ DWRITE_TEXT_RANGE textRange = { 0, UINT32(len) };
+ textLayout->SetFontWeight(mFontWeight, textRange);
+ textLayout->SetFontStyle(mFontStyle, textRange);
+
+ TextRenderer renderer(this);
+ TextRendererContext context = { color, FLOAT(cellWidth), 0.0f };
+ textLayout->Draw(&context, &renderer, FLOAT(x), FLOAT(y) - 0.5f);
+ }
+
+ SafeRelease(&textLayout);
+}
+
+ void
+DWriteContext::FillRect(const RECT *rc, COLORREF color)
+{
+ if (mDMode == DM_INTEROP)
+ {
+ // GDI functions are used before this call. Keep using GDI.
+ // (Switching to Direct2D causes terrible slowdown.)
+ HBRUSH hbr = ::CreateSolidBrush(color);
+ ::FillRect(mInteropHDC, rc, hbr);
+ ::DeleteObject(HGDIOBJ(hbr));
+ }
+ else
+ {
+ SetDrawingMode(DM_DIRECTX);
+ mRT->FillRectangle(
+ D2D1::RectF(FLOAT(rc->left), FLOAT(rc->top),
+ FLOAT(rc->right), FLOAT(rc->bottom)),
+ SolidBrush(color));
+ }
+}
+
+ void
+DWriteContext::DrawLine(int x1, int y1, int x2, int y2, COLORREF color)
+{
+ if (mDMode == DM_INTEROP)
+ {
+ // GDI functions are used before this call. Keep using GDI.
+ // (Switching to Direct2D causes terrible slowdown.)
+ HPEN hpen = ::CreatePen(PS_SOLID, 1, color);
+ HGDIOBJ old_pen = ::SelectObject(mInteropHDC, HGDIOBJ(hpen));
+ ::MoveToEx(mInteropHDC, x1, y1, NULL);
+ ::LineTo(mInteropHDC, x2, y2);
+ ::SelectObject(mInteropHDC, old_pen);
+ ::DeleteObject(HGDIOBJ(hpen));
+ }
+ else
+ {
+ SetDrawingMode(DM_DIRECTX);
+ mRT->DrawLine(
+ D2D1::Point2F(FLOAT(x1), FLOAT(y1) + 0.5f),
+ D2D1::Point2F(FLOAT(x2), FLOAT(y2) + 0.5f),
+ SolidBrush(color));
+ }
+}
+
+ void
+DWriteContext::SetPixel(int x, int y, COLORREF color)
+{
+ if (mDMode == DM_INTEROP)
+ {
+ // GDI functions are used before this call. Keep using GDI.
+ // (Switching to Direct2D causes terrible slowdown.)
+ ::SetPixel(mInteropHDC, x, y, color);
+ }
+ else
+ {
+ SetDrawingMode(DM_DIRECTX);
+ // Direct2D doesn't have SetPixel API. Use DrawLine instead.
+ mRT->DrawLine(
+ D2D1::Point2F(FLOAT(x), FLOAT(y) + 0.5f),
+ D2D1::Point2F(FLOAT(x+1), FLOAT(y) + 0.5f),
+ SolidBrush(color));
+ }
+}
+
+ void
+DWriteContext::Scroll(int x, int y, const RECT *rc)
+{
+ SetDrawingMode(DM_DIRECTX);
+ mRT->Flush();
+
+ D2D1_RECT_U srcRect;
+ D2D1_POINT_2U destPoint;
+ if (x >= 0)
+ {
+ srcRect.left = rc->left;
+ srcRect.right = rc->right - x;
+ destPoint.x = rc->left + x;
+ }
+ else
+ {
+ srcRect.left = rc->left - x;
+ srcRect.right = rc->right;
+ destPoint.x = rc->left;
+ }
+ if (y >= 0)
+ {
+ srcRect.top = rc->top;
+ srcRect.bottom = rc->bottom - y;
+ destPoint.y = rc->top + y;
+ }
+ else
+ {
+ srcRect.top = rc->top - y;
+ srcRect.bottom = rc->bottom;
+ destPoint.y = rc->top;
+ }
+ mBitmap->CopyFromRenderTarget(&destPoint, mRT, &srcRect);
+
+ D2D1_RECT_F destRect = {
+ FLOAT(destPoint.x), FLOAT(destPoint.y),
+ FLOAT(destPoint.x + srcRect.right - srcRect.left),
+ FLOAT(destPoint.y + srcRect.bottom - srcRect.top)
+ };
+ mRT->DrawBitmap(mBitmap, destRect, 1.0F,
+ D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR, destRect);
+}
+
+ void
+DWriteContext::Flush()
+{
+ SetDrawingMode(DM_GDI);
+}
+
+ void
+DWriteContext::SetRenderingParams(
+ const DWriteRenderingParams *params)
+{
+ if (mDWriteFactory == NULL)
+ return;
+
+ IDWriteRenderingParams *renderingParams = NULL;
+ D2D1_TEXT_ANTIALIAS_MODE textAntialiasMode =
+ D2D1_TEXT_ANTIALIAS_MODE_DEFAULT;
+ HRESULT hr;
+ if (params != NULL)
+ {
+ hr = mDWriteFactory->CreateCustomRenderingParams(params->gamma,
+ params->enhancedContrast, params->clearTypeLevel,
+ ToPixelGeometry(params->pixelGeometry),
+ ToRenderingMode(params->renderingMode), &renderingParams);
+ textAntialiasMode = ToTextAntialiasMode(params->textAntialiasMode);
+ }
+ else
+ hr = mDWriteFactory->CreateRenderingParams(&renderingParams);
+ if (SUCCEEDED(hr) && renderingParams != NULL)
+ {
+ SafeRelease(&mRenderingParams);
+ mRenderingParams = renderingParams;
+ mTextAntialiasMode = textAntialiasMode;
+
+ Flush();
+ mRT->SetTextRenderingParams(mRenderingParams);
+ mRT->SetTextAntialiasMode(mTextAntialiasMode);
+ }
+}
+
+ DWriteRenderingParams *
+DWriteContext::GetRenderingParams(
+ DWriteRenderingParams *params)
+{
+ if (params != NULL && mRenderingParams != NULL)
+ {
+ params->gamma = mRenderingParams->GetGamma();
+ params->enhancedContrast = mRenderingParams->GetEnhancedContrast();
+ params->clearTypeLevel = mRenderingParams->GetClearTypeLevel();
+ params->pixelGeometry = ToInt(mRenderingParams->GetPixelGeometry());
+ params->renderingMode = ToInt(mRenderingParams->GetRenderingMode());
+ params->textAntialiasMode = mTextAntialiasMode;
+ }
+ return params;
+}
+
+////////////////////////////////////////////////////////////////////////////
+// PUBLIC C INTERFACES
+
+ void
+DWrite_Init(void)
+{
+#ifdef DYNAMIC_DIRECTX
+ // Load libraries.
+ hD2D1DLL = vimLoadLib(const_cast<char*>("d2d1.dll"));
+ hDWriteDLL = vimLoadLib(const_cast<char*>("dwrite.dll"));
+ if (hD2D1DLL == NULL || hDWriteDLL == NULL)
+ {
+ DWrite_Final();
+ return;
+ }
+ // Get address of procedures.
+ pGetUserDefaultLocaleName = (PGETUSERDEFAULTLOCALENAME)GetProcAddress(
+ GetModuleHandle("kernel32.dll"), "GetUserDefaultLocaleName");
+ pD2D1CreateFactory = (PD2D1CREATEFACTORY)GetProcAddress(hD2D1DLL,
+ "D2D1CreateFactory");
+ pDWriteCreateFactory = (PDWRITECREATEFACTORY)GetProcAddress(hDWriteDLL,
+ "DWriteCreateFactory");
+#endif
+}
+
+ void
+DWrite_Final(void)
+{
+#ifdef DYNAMIC_DIRECTX
+ pGetUserDefaultLocaleName = NULL;
+ pD2D1CreateFactory = NULL;
+ pDWriteCreateFactory = NULL;
+ unload(hDWriteDLL);
+ unload(hD2D1DLL);
+#endif
+}
+
+ DWriteContext *
+DWriteContext_Open(void)
+{
+#ifdef DYNAMIC_DIRECTX
+ if (pGetUserDefaultLocaleName == NULL || pD2D1CreateFactory == NULL
+ || pDWriteCreateFactory == NULL)
+ return NULL;
+#endif
+ return new DWriteContext();
+}
+
+ void
+DWriteContext_BindDC(DWriteContext *ctx, HDC hdc, const RECT *rect)
+{
+ if (ctx != NULL)
+ ctx->BindDC(hdc, rect);
+}
+
+ void
+DWriteContext_SetFont(DWriteContext *ctx, HFONT hFont)
+{
+ if (ctx != NULL)
+ ctx->SetFont(hFont);
+}
+
+ void
+DWriteContext_DrawText(
+ DWriteContext *ctx,
+ const WCHAR *text,
+ int len,
+ int x,
+ int y,
+ int w,
+ int h,
+ int cellWidth,
+ COLORREF color,
+ UINT fuOptions,
+ const RECT *lprc,
+ const INT *lpDx)
+{
+ if (ctx != NULL)
+ ctx->DrawText(text, len, x, y, w, h, cellWidth, color,
+ fuOptions, lprc, lpDx);
+}
+
+ void
+DWriteContext_FillRect(DWriteContext *ctx, const RECT *rc, COLORREF color)
+{
+ if (ctx != NULL)
+ ctx->FillRect(rc, color);
+}
+
+ void
+DWriteContext_DrawLine(DWriteContext *ctx, int x1, int y1, int x2, int y2,
+ COLORREF color)
+{
+ if (ctx != NULL)
+ ctx->DrawLine(x1, y1, x2, y2, color);
+}
+
+ void
+DWriteContext_SetPixel(DWriteContext *ctx, int x, int y, COLORREF color)
+{
+ if (ctx != NULL)
+ ctx->SetPixel(x, y, color);
+}
+
+ void
+DWriteContext_Scroll(DWriteContext *ctx, int x, int y, const RECT *rc)
+{
+ if (ctx != NULL)
+ ctx->Scroll(x, y, rc);
+}
+
+ void
+DWriteContext_Flush(DWriteContext *ctx)
+{
+ if (ctx != NULL)
+ ctx->Flush();
+}
+
+ void
+DWriteContext_Close(DWriteContext *ctx)
+{
+ delete ctx;
+}
+
+ void
+DWriteContext_SetRenderingParams(
+ DWriteContext *ctx,
+ const DWriteRenderingParams *params)
+{
+ if (ctx != NULL)
+ ctx->SetRenderingParams(params);
+}
+
+ DWriteRenderingParams *
+DWriteContext_GetRenderingParams(
+ DWriteContext *ctx,
+ DWriteRenderingParams *params)
+{
+ if (ctx != NULL)
+ return ctx->GetRenderingParams(params);
+ else
+ return NULL;
+}
diff --git a/src/gui_dwrite.h b/src/gui_dwrite.h
new file mode 100644
index 0000000..5de06f9
--- /dev/null
+++ b/src/gui_dwrite.h
@@ -0,0 +1,92 @@
+/* vi:set ts=8 sts=4 sw=4 noet: */
+/*
+ * Author: MURAOKA Taro <koron.kaoriya@gmail.com>
+ *
+ * Contributors:
+ * - Ken Takata
+ * - Yasuhiro Matsumoto
+ *
+ * Copyright (C) 2013 MURAOKA Taro <koron.kaoriya@gmail.com>
+ * THIS FILE IS DISTRIBUTED UNDER THE VIM LICENSE.
+ */
+
+#ifndef GUI_DWRITE_H
+#define GUI_DWRITE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct DWriteContext DWriteContext;
+
+typedef struct DWriteRenderingParams {
+ float gamma;
+ float enhancedContrast;
+ float clearTypeLevel;
+ /*
+ * pixelGeometry:
+ * 0 - DWRITE_PIXEL_GEOMETRY_FLAT
+ * 1 - DWRITE_PIXEL_GEOMETRY_RGB
+ * 2 - DWRITE_PIXEL_GEOMETRY_BGR
+ */
+ int pixelGeometry;
+ /*
+ * renderingMode:
+ * 0 - DWRITE_RENDERING_MODE_DEFAULT
+ * 1 - DWRITE_RENDERING_MODE_ALIASED
+ * 2 - DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC
+ * 3 - DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL
+ * 4 - DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL
+ * 5 - DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC
+ * 6 - DWRITE_RENDERING_MODE_OUTLINE
+ */
+ int renderingMode;
+ /*
+ * antialiasMode:
+ * 0 - D2D1_TEXT_ANTIALIAS_MODE_DEFAULT
+ * 1 - D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE
+ * 2 - D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE
+ * 3 - D2D1_TEXT_ANTIALIAS_MODE_ALIASED
+ */
+ int textAntialiasMode;
+} DWriteRenderingParams;
+
+void DWrite_Init(void);
+void DWrite_Final(void);
+
+DWriteContext *DWriteContext_Open(void);
+void DWriteContext_BindDC(DWriteContext *ctx, HDC hdc, const RECT *rect);
+void DWriteContext_SetFont(DWriteContext *ctx, HFONT hFont);
+void DWriteContext_DrawText(
+ DWriteContext *ctx,
+ const WCHAR *text,
+ int len,
+ int x,
+ int y,
+ int w,
+ int h,
+ int cellWidth,
+ COLORREF color,
+ UINT fuOptions,
+ const RECT *lprc,
+ const INT *lpDx);
+void DWriteContext_FillRect(DWriteContext *ctx, const RECT *rc, COLORREF color);
+void DWriteContext_DrawLine(DWriteContext *ctx, int x1, int y1, int x2, int y2,
+ COLORREF color);
+void DWriteContext_SetPixel(DWriteContext *ctx, int x, int y, COLORREF color);
+void DWriteContext_Scroll(DWriteContext *ctx, int x, int y, const RECT *rc);
+void DWriteContext_Flush(DWriteContext *ctx);
+void DWriteContext_Close(DWriteContext *ctx);
+
+void DWriteContext_SetRenderingParams(
+ DWriteContext *ctx,
+ const DWriteRenderingParams *params);
+
+DWriteRenderingParams *DWriteContext_GetRenderingParams(
+ DWriteContext *ctx,
+ DWriteRenderingParams *params);
+
+#ifdef __cplusplus
+}
+#endif
+#endif/*GUI_DWRITE_H*/
diff --git a/src/gui_gtk.c b/src/gui_gtk.c
new file mode 100644
index 0000000..3d08934
--- /dev/null
+++ b/src/gui_gtk.c
@@ -0,0 +1,2609 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * Porting to GTK+ was done by:
+ *
+ * (C) 1998,1999,2000 by Marcin Dalecki <martin@dalecki.de>
+ *
+ * With GREAT support and continuous encouragements by Andy Kahn and of
+ * course Bram Moolenaar!
+ *
+ * Support for GTK+ 2 was added by:
+ *
+ * (C) 2002,2003 Jason Hildebrand <jason@peaceworks.ca>
+ * Daniel Elstner <daniel.elstner@gmx.net>
+ *
+ * Best supporting actor (He helped somewhat, aesthetically speaking):
+ * Maxime Romano <verbophobe@hotmail.com>
+ *
+ * Support for GTK+ 3 was added by:
+ *
+ * 2016 Kazunobu Kuriyama <kazunobu.kuriyama@gmail.com>
+ *
+ * With the help of Marius Gedminas and the word of Bram Moolenaar,
+ * "Let's give this some time to mature."
+ */
+
+#include "vim.h"
+
+#ifdef FEAT_GUI_GTK
+# include "gui_gtk_f.h"
+#endif
+
+/* GTK defines MAX and MIN, but some system header files as well. Undefine
+ * them and don't use them. */
+#ifdef MIN
+# undef MIN
+#endif
+#ifdef MAX
+# undef MAX
+#endif
+
+#ifdef FEAT_GUI_GNOME
+/* Gnome redefines _() and N_(). Grrr... */
+# ifdef _
+# undef _
+# endif
+# ifdef N_
+# undef N_
+# endif
+# ifdef textdomain
+# undef textdomain
+# endif
+# ifdef bindtextdomain
+# undef bindtextdomain
+# endif
+# ifdef bind_textdomain_codeset
+# undef bind_textdomain_codeset
+# endif
+# if defined(FEAT_GETTEXT) && !defined(ENABLE_NLS)
+# define ENABLE_NLS /* so the texts in the dialog boxes are translated */
+# endif
+# include <gnome.h>
+#endif
+
+#ifdef FEAT_GUI_GTK
+# if GTK_CHECK_VERSION(3,0,0)
+# include <gdk/gdkkeysyms-compat.h>
+# else
+# include <gdk/gdkkeysyms.h>
+# endif
+# include <gdk/gdk.h>
+# ifdef WIN3264
+# include <gdk/gdkwin32.h>
+# else
+# include <gdk/gdkx.h>
+# endif
+
+# include <gtk/gtk.h>
+#else
+/* define these items to be able to generate prototypes without GTK */
+typedef int GtkWidget;
+# define gpointer int
+# define guint8 int
+# define GdkPixmap int
+# define GdkBitmap int
+# define GtkIconFactory int
+# define GtkToolbar int
+# define GtkAdjustment int
+# define gboolean int
+# define GdkEventKey int
+# define CancelData int
+#endif
+
+static void entry_activate_cb(GtkWidget *widget, gpointer data);
+static void entry_changed_cb(GtkWidget *entry, GtkWidget *dialog);
+static void find_replace_cb(GtkWidget *widget, gpointer data);
+#if defined(FEAT_BROWSE) || defined(PROTO)
+static void recent_func_log_func(
+ const gchar *log_domain,
+ GLogLevelFlags log_level,
+ const gchar *message,
+ gpointer user_data);
+#endif
+
+#if defined(FEAT_TOOLBAR)
+/*
+ * Table from BuiltIn## icon indices to GTK+ stock IDs. Order must exactly
+ * match toolbar_names[] in menu.c! All stock icons including the "vim-*"
+ * ones can be overridden in your gtkrc file.
+ */
+# if GTK_CHECK_VERSION(3,10,0)
+static const char * const menu_themed_names[] =
+{
+ /* 00 */ "document-new", /* sub. GTK_STOCK_NEW */
+ /* 01 */ "document-open", /* sub. GTK_STOCK_OPEN */
+ /* 02 */ "document-save", /* sub. GTK_STOCK_SAVE */
+ /* 03 */ "edit-undo", /* sub. GTK_STOCK_UNDO */
+ /* 04 */ "edit-redo", /* sub. GTK_STOCK_REDO */
+ /* 05 */ "edit-cut", /* sub. GTK_STOCK_CUT */
+ /* 06 */ "edit-copy", /* sub. GTK_STOCK_COPY */
+ /* 07 */ "edit-paste", /* sub. GTK_STOCK_PASTE */
+ /* 08 */ "document-print", /* sub. GTK_STOCK_PRINT */
+ /* 09 */ "help-browser", /* sub. GTK_STOCK_HELP */
+ /* 10 */ "edit-find", /* sub. GTK_STOCK_FIND */
+# if GTK_CHECK_VERSION(3,14,0)
+ /* Use the file names in gui_gtk_res.xml, cutting off the extension.
+ * Similar changes follow. */
+ /* 11 */ "stock_vim_save_all",
+ /* 12 */ "stock_vim_session_save",
+ /* 13 */ "stock_vim_session_new",
+ /* 14 */ "stock_vim_session_load",
+# else
+ /* 11 */ "vim-save-all",
+ /* 12 */ "vim-session-save",
+ /* 13 */ "vim-session-new",
+ /* 14 */ "vim-session-load",
+# endif
+ /* 15 */ "system-run", /* sub. GTK_STOCK_EXECUTE */
+ /* 16 */ "edit-find-replace", /* sub. GTK_STOCK_FIND_AND_REPLACE */
+ /* 17 */ "window-close", /* sub. GTK_STOCK_CLOSE, FIXME: fuzzy */
+# if GTK_CHECK_VERSION(3,14,0)
+ /* 18 */ "stock_vim_window_maximize",
+ /* 19 */ "stock_vim_window_minimize",
+ /* 20 */ "stock_vim_window_split",
+ /* 21 */ "stock_vim_shell",
+# else
+ /* 18 */ "vim-window-maximize",
+ /* 19 */ "vim-window-minimize",
+ /* 20 */ "vim-window-split",
+ /* 21 */ "vim-shell",
+# endif
+ /* 22 */ "go-previous", /* sub. GTK_STOCK_GO_BACK */
+ /* 23 */ "go-next", /* sub. GTK_STOCK_GO_FORWARD */
+# if GTK_CHECK_VERSION(3,14,0)
+ /* 24 */ "stock_vim_find_help",
+# else
+ /* 24 */ "vim-find-help",
+# endif
+ /* 25 */ "gtk-convert", /* sub. GTK_STOCK_CONVERT */
+ /* 26 */ "go-jump", /* sub. GTK_STOCK_JUMP_TO */
+# if GTK_CHECK_VERSION(3,14,0)
+ /* 27 */ "stock_vim_build_tags",
+ /* 28 */ "stock_vim_window_split_vertical",
+ /* 29 */ "stock_vim_window_maximize_width",
+ /* 30 */ "stock_vim_window_minimize_width",
+# else
+ /* 27 */ "vim-build-tags",
+ /* 28 */ "vim-window-split-vertical",
+ /* 29 */ "vim-window-maximize-width",
+ /* 30 */ "vim-window-minimize-width",
+# endif
+ /* 31 */ "application-exit", /* GTK_STOCK_QUIT */
+};
+# else /* !GTK_CHECK_VERSION(3,10,0) */
+static const char * const menu_stock_ids[] =
+{
+ /* 00 */ GTK_STOCK_NEW,
+ /* 01 */ GTK_STOCK_OPEN,
+ /* 02 */ GTK_STOCK_SAVE,
+ /* 03 */ GTK_STOCK_UNDO,
+ /* 04 */ GTK_STOCK_REDO,
+ /* 05 */ GTK_STOCK_CUT,
+ /* 06 */ GTK_STOCK_COPY,
+ /* 07 */ GTK_STOCK_PASTE,
+ /* 08 */ GTK_STOCK_PRINT,
+ /* 09 */ GTK_STOCK_HELP,
+ /* 10 */ GTK_STOCK_FIND,
+ /* 11 */ "vim-save-all",
+ /* 12 */ "vim-session-save",
+ /* 13 */ "vim-session-new",
+ /* 14 */ "vim-session-load",
+ /* 15 */ GTK_STOCK_EXECUTE,
+ /* 16 */ GTK_STOCK_FIND_AND_REPLACE,
+ /* 17 */ GTK_STOCK_CLOSE, /* FIXME: fuzzy */
+ /* 18 */ "vim-window-maximize",
+ /* 19 */ "vim-window-minimize",
+ /* 20 */ "vim-window-split",
+ /* 21 */ "vim-shell",
+ /* 22 */ GTK_STOCK_GO_BACK,
+ /* 23 */ GTK_STOCK_GO_FORWARD,
+ /* 24 */ "vim-find-help",
+ /* 25 */ GTK_STOCK_CONVERT,
+ /* 26 */ GTK_STOCK_JUMP_TO,
+ /* 27 */ "vim-build-tags",
+ /* 28 */ "vim-window-split-vertical",
+ /* 29 */ "vim-window-maximize-width",
+ /* 30 */ "vim-window-minimize-width",
+ /* 31 */ GTK_STOCK_QUIT
+};
+# endif /* !GTK_CHECK_VERSION(3,10,0) */
+
+# ifdef USE_GRESOURCE
+# if !GTK_CHECK_VERSION(3,10,0)
+typedef struct IconNames {
+ const char *icon_name;
+ const char *file_name;
+} IconNames;
+
+static IconNames stock_vim_icons[] = {
+ { "vim-build-tags", "stock_vim_build_tags.png" },
+ { "vim-find-help", "stock_vim_find_help.png" },
+ { "vim-save-all", "stock_vim_save_all.png" },
+ { "vim-session-load", "stock_vim_session_load.png" },
+ { "vim-session-new", "stock_vim_session_new.png" },
+ { "vim-session-save", "stock_vim_session_save.png" },
+ { "vim-shell", "stock_vim_shell.png" },
+ { "vim-window-maximize", "stock_vim_window_maximize.png" },
+ { "vim-window-maximize-width", "stock_vim_window_maximize_width.png" },
+ { "vim-window-minimize", "stock_vim_window_minimize.png" },
+ { "vim-window-minimize-width", "stock_vim_window_minimize_width.png" },
+ { "vim-window-split", "stock_vim_window_split.png" },
+ { "vim-window-split-vertical", "stock_vim_window_split_vertical.png" },
+ { NULL, NULL }
+};
+# endif
+# endif /* USE_G_RESOURCE */
+
+# ifndef USE_GRESOURCE
+ static void
+add_stock_icon(GtkIconFactory *factory,
+ const char *stock_id,
+ const guint8 *inline_data,
+ int data_length)
+{
+ GdkPixbuf *pixbuf;
+ GtkIconSet *icon_set;
+
+ pixbuf = gdk_pixbuf_new_from_inline(data_length, inline_data, FALSE, NULL);
+ icon_set = gtk_icon_set_new_from_pixbuf(pixbuf);
+
+ gtk_icon_factory_add(factory, stock_id, icon_set);
+
+ gtk_icon_set_unref(icon_set);
+ g_object_unref(pixbuf);
+}
+# endif
+
+ static int
+lookup_menu_iconfile(char_u *iconfile, char_u *dest)
+{
+ expand_env(iconfile, dest, MAXPATHL);
+
+ if (mch_isFullName(dest))
+ {
+ return vim_fexists(dest);
+ }
+ else
+ {
+ static const char suffixes[][4] = {"png", "xpm", "bmp"};
+ char_u buf[MAXPATHL];
+ unsigned int i;
+
+ for (i = 0; i < G_N_ELEMENTS(suffixes); ++i)
+ if (gui_find_bitmap(dest, buf, (char *)suffixes[i]) == OK)
+ {
+ STRCPY(dest, buf);
+ return TRUE;
+ }
+
+ return FALSE;
+ }
+}
+
+ static GtkWidget *
+load_menu_iconfile(char_u *name, GtkIconSize icon_size)
+{
+ GtkWidget *image = NULL;
+# if GTK_CHECK_VERSION(3,10,0)
+ int pixel_size = -1;
+
+ switch (icon_size)
+ {
+ case GTK_ICON_SIZE_MENU:
+ pixel_size = 16;
+ break;
+ case GTK_ICON_SIZE_SMALL_TOOLBAR:
+ pixel_size = 16;
+ break;
+ case GTK_ICON_SIZE_LARGE_TOOLBAR:
+ pixel_size = 24;
+ break;
+ case GTK_ICON_SIZE_BUTTON:
+ pixel_size = 16;
+ break;
+ case GTK_ICON_SIZE_DND:
+ pixel_size = 32;
+ break;
+ case GTK_ICON_SIZE_DIALOG:
+ pixel_size = 48;
+ break;
+ case GTK_ICON_SIZE_INVALID:
+ /* FALLTHROUGH */
+ default:
+ pixel_size = 0;
+ break;
+ }
+
+ if (pixel_size > 0 || pixel_size == -1)
+ {
+ GdkPixbuf * const pixbuf
+ = gdk_pixbuf_new_from_file_at_scale((const char *)name,
+ pixel_size, pixel_size, TRUE, NULL);
+ if (pixbuf != NULL)
+ {
+ image = gtk_image_new_from_pixbuf(pixbuf);
+ g_object_unref(pixbuf);
+ }
+ }
+ if (image == NULL)
+ image = gtk_image_new_from_icon_name("image-missing", icon_size);
+
+ return image;
+# else /* !GTK_CHECK_VERSION(3,10,0) */
+ GtkIconSet *icon_set;
+ GtkIconSource *icon_source;
+
+ /*
+ * Rather than loading the icon directly into a GtkImage, create
+ * a new GtkIconSet and put it in there. This way we can easily
+ * scale the toolbar icons on the fly when needed.
+ */
+ icon_set = gtk_icon_set_new();
+ icon_source = gtk_icon_source_new();
+
+ gtk_icon_source_set_filename(icon_source, (const char *)name);
+ gtk_icon_set_add_source(icon_set, icon_source);
+
+ image = gtk_image_new_from_icon_set(icon_set, icon_size);
+
+ gtk_icon_source_free(icon_source);
+ gtk_icon_set_unref(icon_set);
+
+ return image;
+# endif /* !GTK_CHECK_VERSION(3,10,0) */
+}
+
+ static GtkWidget *
+create_menu_icon(vimmenu_T *menu, GtkIconSize icon_size)
+{
+ GtkWidget *image = NULL;
+ char_u buf[MAXPATHL];
+
+ /* First use a specified "icon=" argument. */
+ if (menu->iconfile != NULL && lookup_menu_iconfile(menu->iconfile, buf))
+ image = load_menu_iconfile(buf, icon_size);
+
+ /* If not found and not builtin specified try using the menu name. */
+ if (image == NULL && !menu->icon_builtin
+ && lookup_menu_iconfile(menu->name, buf))
+ image = load_menu_iconfile(buf, icon_size);
+
+ /* Still not found? Then use a builtin icon, a blank one as fallback. */
+ if (image == NULL)
+ {
+# if GTK_CHECK_VERSION(3,10,0)
+ const char *icon_name = NULL;
+ const int n_names = G_N_ELEMENTS(menu_themed_names);
+
+ if (menu->iconidx >= 0 && menu->iconidx < n_names)
+ icon_name = menu_themed_names[menu->iconidx];
+ if (icon_name == NULL)
+ icon_name = "image-missing";
+
+ image = gtk_image_new_from_icon_name(icon_name, icon_size);
+# else
+ const char *stock_id;
+ const int n_ids = G_N_ELEMENTS(menu_stock_ids);
+
+ if (menu->iconidx >= 0 && menu->iconidx < n_ids)
+ stock_id = menu_stock_ids[menu->iconidx];
+ else
+ stock_id = GTK_STOCK_MISSING_IMAGE;
+
+ image = gtk_image_new_from_stock(stock_id, icon_size);
+# endif
+ }
+
+ return image;
+}
+
+ static gint
+toolbar_button_focus_in_event(GtkWidget *widget UNUSED,
+ GdkEventFocus *event UNUSED,
+ gpointer data UNUSED)
+{
+ /* When we're in a GtkPlug, we don't have window focus events, only widget
+ * focus. To emulate stand-alone gvim, if a button gets focus (e.g.,
+ * <Tab> into GtkPlug) immediately pass it to mainwin. */
+ if (gtk_socket_id != 0)
+ gtk_widget_grab_focus(gui.drawarea);
+
+ return TRUE;
+}
+#endif /* FEAT_TOOLBAR */
+
+#if defined(FEAT_TOOLBAR) || defined(PROTO)
+
+ void
+gui_gtk_register_stock_icons(void)
+{
+# ifndef USE_GRESOURCE
+# include "../pixmaps/stock_icons.h"
+ GtkIconFactory *factory;
+
+ factory = gtk_icon_factory_new();
+# define ADD_ICON(Name, Data) add_stock_icon(factory, Name, Data, (int)sizeof(Data))
+
+ ADD_ICON("vim-build-tags", stock_vim_build_tags);
+ ADD_ICON("vim-find-help", stock_vim_find_help);
+ ADD_ICON("vim-save-all", stock_vim_save_all);
+ ADD_ICON("vim-session-load", stock_vim_session_load);
+ ADD_ICON("vim-session-new", stock_vim_session_new);
+ ADD_ICON("vim-session-save", stock_vim_session_save);
+ ADD_ICON("vim-shell", stock_vim_shell);
+ ADD_ICON("vim-window-maximize", stock_vim_window_maximize);
+ ADD_ICON("vim-window-maximize-width", stock_vim_window_maximize_width);
+ ADD_ICON("vim-window-minimize", stock_vim_window_minimize);
+ ADD_ICON("vim-window-minimize-width", stock_vim_window_minimize_width);
+ ADD_ICON("vim-window-split", stock_vim_window_split);
+ ADD_ICON("vim-window-split-vertical", stock_vim_window_split_vertical);
+
+# undef ADD_ICON
+
+ gtk_icon_factory_add_default(factory);
+ g_object_unref(factory);
+# else /* defined(USE_GRESOURCE) */
+ const char * const path_prefix = "/org/vim/gui/icon";
+# if GTK_CHECK_VERSION(3,14,0)
+ GdkScreen *screen = NULL;
+ GtkIconTheme *icon_theme = NULL;
+
+ if (GTK_IS_WIDGET(gui.mainwin))
+ screen = gtk_widget_get_screen(gui.mainwin);
+ else
+ screen = gdk_screen_get_default();
+ icon_theme = gtk_icon_theme_get_for_screen(screen);
+ gtk_icon_theme_add_resource_path(icon_theme, path_prefix);
+# elif GTK_CHECK_VERSION(3,0,0)
+ IconNames *names;
+
+ for (names = stock_vim_icons; names->icon_name != NULL; names++)
+ {
+ char path[MAXPATHL];
+
+ vim_snprintf(path, MAXPATHL, "%s/%s", path_prefix, names->file_name);
+ GdkPixbuf *pixbuf = NULL;
+ pixbuf = gdk_pixbuf_new_from_resource(path, NULL);
+ if (pixbuf != NULL)
+ {
+ const gint size = MAX(gdk_pixbuf_get_width(pixbuf),
+ gdk_pixbuf_get_height(pixbuf));
+ if (size > 16)
+ {
+ /* An icon theme is supposed to provide fixed-size
+ * image files for each size, e.g., 16, 22, 24, ...
+ * Naturally, in contrast to GtkIconSet, GtkIconTheme
+ * won't prepare size variants for us out of a single
+ * fixed-size image.
+ *
+ * Currently, Vim provides 24x24 images only while the
+ * icon size on the menu and the toolbar is set to 16x16
+ * by default.
+ *
+ * Resize them by ourselves until we have our own fully
+ * fledged icon theme. */
+ GdkPixbuf *src = pixbuf;
+ pixbuf = gdk_pixbuf_scale_simple(src,
+ 16, 16,
+ GDK_INTERP_BILINEAR);
+ if (pixbuf == NULL)
+ pixbuf = src;
+ else
+ g_object_unref(src);
+ }
+ gtk_icon_theme_add_builtin_icon(names->icon_name, size, pixbuf);
+ g_object_unref(pixbuf);
+ }
+ }
+# else /* !GTK_CHECK_VERSION(3,0.0) */
+ GtkIconFactory * const factory = gtk_icon_factory_new();
+ IconNames *names;
+
+ for (names = stock_vim_icons; names->icon_name != NULL; names++)
+ {
+ char path[MAXPATHL];
+ GdkPixbuf *pixbuf;
+
+ vim_snprintf(path, MAXPATHL, "%s/%s", path_prefix, names->file_name);
+ pixbuf = gdk_pixbuf_new_from_resource(path, NULL);
+ if (pixbuf != NULL)
+ {
+ GtkIconSet *icon_set = gtk_icon_set_new_from_pixbuf(pixbuf);
+ gtk_icon_factory_add(factory, names->icon_name, icon_set);
+ gtk_icon_set_unref(icon_set);
+ g_object_unref(pixbuf);
+ }
+ }
+
+ gtk_icon_factory_add_default(factory);
+ g_object_unref(factory);
+# endif /* !GTK_CHECK_VERSION(3,0,0) */
+# endif /* defined(USE_GRESOURCE) */
+}
+
+#endif /* FEAT_TOOLBAR */
+
+#if defined(FEAT_MENU) || defined(PROTO)
+
+/*
+ * Translate Vim's mnemonic tagging to GTK+ style and convert to UTF-8
+ * if necessary. The caller must vim_free() the returned string.
+ *
+ * Input Output
+ * _ __
+ * && &
+ * & _ stripped if use_mnemonic == FALSE
+ * <Tab> end of menu label text
+ */
+ static char_u *
+translate_mnemonic_tag(char_u *name, int use_mnemonic)
+{
+ char_u *buf;
+ char_u *psrc;
+ char_u *pdest;
+ int n_underscores = 0;
+
+ name = CONVERT_TO_UTF8(name);
+ if (name == NULL)
+ return NULL;
+
+ for (psrc = name; *psrc != NUL && *psrc != TAB; ++psrc)
+ if (*psrc == '_')
+ ++n_underscores;
+
+ buf = alloc((unsigned)(psrc - name + n_underscores + 1));
+ if (buf != NULL)
+ {
+ pdest = buf;
+ for (psrc = name; *psrc != NUL && *psrc != TAB; ++psrc)
+ {
+ if (*psrc == '_')
+ {
+ *pdest++ = '_';
+ *pdest++ = '_';
+ }
+ else if (*psrc != '&')
+ {
+ *pdest++ = *psrc;
+ }
+ else if (*(psrc + 1) == '&')
+ {
+ *pdest++ = *psrc++;
+ }
+ else if (use_mnemonic)
+ {
+ *pdest++ = '_';
+ }
+ }
+ *pdest = NUL;
+ }
+
+ CONVERT_TO_UTF8_FREE(name);
+ return buf;
+}
+
+ static void
+menu_item_new(vimmenu_T *menu, GtkWidget *parent_widget)
+{
+ GtkWidget *box;
+ char_u *text;
+ int use_mnemonic;
+
+ /* It would be neat to have image menu items, but that would require major
+ * changes to Vim's menu system. Not to mention that all the translations
+ * had to be updated. */
+ menu->id = gtk_menu_item_new();
+# if GTK_CHECK_VERSION(3,2,0)
+ box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 20);
+ gtk_box_set_homogeneous(GTK_BOX(box), FALSE);
+# else
+ box = gtk_hbox_new(FALSE, 20);
+# endif
+
+ use_mnemonic = (p_wak[0] != 'n' || !GTK_IS_MENU_BAR(parent_widget));
+ text = translate_mnemonic_tag(menu->name, use_mnemonic);
+
+ menu->label = gtk_label_new_with_mnemonic((const char *)text);
+ vim_free(text);
+
+ gtk_box_pack_start(GTK_BOX(box), menu->label, FALSE, FALSE, 0);
+
+ if (menu->actext != NULL && menu->actext[0] != NUL)
+ {
+ text = CONVERT_TO_UTF8(menu->actext);
+
+ gtk_box_pack_end(GTK_BOX(box),
+ gtk_label_new((const char *)text),
+ FALSE, FALSE, 0);
+
+ CONVERT_TO_UTF8_FREE(text);
+ }
+
+ gtk_container_add(GTK_CONTAINER(menu->id), box);
+ gtk_widget_show_all(menu->id);
+}
+
+ void
+gui_mch_add_menu(vimmenu_T *menu, int idx)
+{
+ vimmenu_T *parent;
+ GtkWidget *parent_widget;
+
+ if (menu->name[0] == ']' || menu_is_popup(menu->name))
+ {
+ menu->submenu_id = gtk_menu_new();
+ return;
+ }
+
+ parent = menu->parent;
+
+ if ((parent != NULL && parent->submenu_id == NULL)
+ || !menu_is_menubar(menu->name))
+ return;
+
+ parent_widget = (parent != NULL) ? parent->submenu_id : gui.menubar;
+ menu_item_new(menu, parent_widget);
+
+# if !GTK_CHECK_VERSION(3,4,0)
+ /* since the tearoff should always appear first, increment idx */
+ if (parent != NULL && !menu_is_popup(parent->name))
+ ++idx;
+# endif
+
+ gtk_menu_shell_insert(GTK_MENU_SHELL(parent_widget), menu->id, idx);
+
+ menu->submenu_id = gtk_menu_new();
+
+ gtk_menu_set_accel_group(GTK_MENU(menu->submenu_id), gui.accel_group);
+ gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu->id), menu->submenu_id);
+
+# if !GTK_CHECK_VERSION(3,4,0)
+ menu->tearoff_handle = gtk_tearoff_menu_item_new();
+ if (vim_strchr(p_go, GO_TEAROFF) != NULL)
+ gtk_widget_show(menu->tearoff_handle);
+# if GTK_CHECK_VERSION(3,0,0)
+ gtk_menu_shell_prepend(GTK_MENU_SHELL(menu->submenu_id),
+ menu->tearoff_handle);
+# else
+ gtk_menu_prepend(GTK_MENU(menu->submenu_id), menu->tearoff_handle);
+# endif
+# endif
+}
+
+ static void
+menu_item_activate(GtkWidget *widget UNUSED, gpointer data)
+{
+ gui_menu_cb((vimmenu_T *)data);
+}
+
+ void
+gui_mch_add_menu_item(vimmenu_T *menu, int idx)
+{
+ vimmenu_T *parent;
+
+ parent = menu->parent;
+
+# ifdef FEAT_TOOLBAR
+ if (menu_is_toolbar(parent->name))
+ {
+ GtkToolbar *toolbar;
+
+ toolbar = GTK_TOOLBAR(gui.toolbar);
+ menu->submenu_id = NULL;
+
+ if (menu_is_separator(menu->name))
+ {
+# if GTK_CHECK_VERSION(3,0,0)
+ GtkToolItem *item = gtk_separator_tool_item_new();
+ gtk_separator_tool_item_set_draw(GTK_SEPARATOR_TOOL_ITEM(item),
+ TRUE);
+ gtk_tool_item_set_expand(GTK_TOOL_ITEM(item), FALSE);
+ gtk_widget_show(GTK_WIDGET(item));
+
+ gtk_toolbar_insert(toolbar, item, idx);
+# else
+ gtk_toolbar_insert_space(toolbar, idx);
+# endif
+ menu->id = NULL;
+ }
+ else
+ {
+ char_u *text;
+ char_u *tooltip;
+
+ text = CONVERT_TO_UTF8(menu->dname);
+ tooltip = CONVERT_TO_UTF8(menu->strings[MENU_INDEX_TIP]);
+ if (tooltip != NULL && !utf_valid_string(tooltip, NULL))
+ /* Invalid text, can happen when 'encoding' is changed. Avoid
+ * a nasty GTK error message, skip the tooltip. */
+ CONVERT_TO_UTF8_FREE(tooltip);
+
+# if GTK_CHECK_VERSION(3,0,0)
+ {
+ GtkWidget *icon;
+ GtkToolItem *item;
+
+ icon = create_menu_icon(menu,
+ gtk_toolbar_get_icon_size(toolbar));
+ item = gtk_tool_button_new(icon, (const gchar *)text);
+ gtk_tool_item_set_tooltip_text(item, (const gchar *)tooltip);
+ g_signal_connect(G_OBJECT(item), "clicked",
+ G_CALLBACK(&menu_item_activate), menu);
+ gtk_widget_show_all(GTK_WIDGET(item));
+
+ gtk_toolbar_insert(toolbar, item, idx);
+
+ menu->id = GTK_WIDGET(item);
+ }
+# else
+ menu->id = gtk_toolbar_insert_item(
+ toolbar,
+ (const char *)text,
+ (const char *)tooltip,
+ NULL,
+ create_menu_icon(menu, gtk_toolbar_get_icon_size(toolbar)),
+ G_CALLBACK(&menu_item_activate),
+ menu,
+ idx);
+# endif
+
+ if (gtk_socket_id != 0)
+ g_signal_connect(G_OBJECT(menu->id), "focus-in-event",
+ G_CALLBACK(toolbar_button_focus_in_event), NULL);
+
+ CONVERT_TO_UTF8_FREE(text);
+ CONVERT_TO_UTF8_FREE(tooltip);
+ }
+ }
+ else
+# endif /* FEAT_TOOLBAR */
+ {
+ /* No parent, must be a non-menubar menu */
+ if (parent == NULL || parent->submenu_id == NULL)
+ return;
+
+# if !GTK_CHECK_VERSION(3,4,0)
+ /* Make place for the possible tearoff handle item. Not in the popup
+ * menu, it doesn't have a tearoff item. */
+ if (!menu_is_popup(parent->name))
+ ++idx;
+# endif
+
+ if (menu_is_separator(menu->name))
+ {
+ /* Separator: Just add it */
+# if GTK_CHECK_VERSION(3,0,0)
+ menu->id = gtk_separator_menu_item_new();
+# else
+ menu->id = gtk_menu_item_new();
+ gtk_widget_set_sensitive(menu->id, FALSE);
+# endif
+ gtk_widget_show(menu->id);
+ gtk_menu_shell_insert(GTK_MENU_SHELL(parent->submenu_id),
+ menu->id, idx);
+
+ return;
+ }
+
+ /* Add textual menu item. */
+ menu_item_new(menu, parent->submenu_id);
+ gtk_widget_show(menu->id);
+ gtk_menu_shell_insert(GTK_MENU_SHELL(parent->submenu_id),
+ menu->id, idx);
+
+ if (menu->id != NULL)
+ g_signal_connect(G_OBJECT(menu->id), "activate",
+ G_CALLBACK(menu_item_activate), menu);
+ }
+}
+#endif /* FEAT_MENU */
+
+
+ void
+gui_mch_set_text_area_pos(int x, int y, int w, int h)
+{
+ gtk_form_move_resize(GTK_FORM(gui.formwin), gui.drawarea, x, y, w, h);
+}
+
+
+#if defined(FEAT_MENU) || defined(PROTO)
+/*
+ * Enable or disable accelerators for the toplevel menus.
+ */
+ void
+gui_gtk_set_mnemonics(int enable)
+{
+ vimmenu_T *menu;
+ char_u *name;
+
+ for (menu = root_menu; menu != NULL; menu = menu->next)
+ {
+ if (menu->id == NULL)
+ continue;
+
+ name = translate_mnemonic_tag(menu->name, enable);
+ gtk_label_set_text_with_mnemonic(GTK_LABEL(menu->label),
+ (const char *)name);
+ vim_free(name);
+ }
+}
+
+# if !GTK_CHECK_VERSION(3,4,0)
+ static void
+recurse_tearoffs(vimmenu_T *menu, int val)
+{
+ for (; menu != NULL; menu = menu->next)
+ {
+ if (menu->submenu_id != NULL && menu->tearoff_handle != NULL
+ && menu->name[0] != ']' && !menu_is_popup(menu->name))
+ {
+ if (val)
+ gtk_widget_show(menu->tearoff_handle);
+ else
+ gtk_widget_hide(menu->tearoff_handle);
+ }
+ recurse_tearoffs(menu->children, val);
+ }
+}
+# endif
+
+# if GTK_CHECK_VERSION(3,4,0)
+ void
+gui_mch_toggle_tearoffs(int enable UNUSED)
+{
+ /* Do nothing */
+}
+# else
+ void
+gui_mch_toggle_tearoffs(int enable)
+{
+ recurse_tearoffs(root_menu, enable);
+}
+# endif
+#endif /* FEAT_MENU */
+
+#if defined(FEAT_TOOLBAR)
+ static int
+get_menu_position(vimmenu_T *menu)
+{
+ vimmenu_T *node;
+ int idx = 0;
+
+ for (node = menu->parent->children; node != menu; node = node->next)
+ {
+ g_return_val_if_fail(node != NULL, -1);
+ ++idx;
+ }
+
+ return idx;
+}
+#endif /* FEAT_TOOLBAR */
+
+
+#if defined(FEAT_TOOLBAR) || defined(PROTO)
+ void
+gui_mch_menu_set_tip(vimmenu_T *menu)
+{
+ if (menu->id != NULL && menu->parent != NULL
+ && gui.toolbar != NULL && menu_is_toolbar(menu->parent->name))
+ {
+ char_u *tooltip;
+
+ tooltip = CONVERT_TO_UTF8(menu->strings[MENU_INDEX_TIP]);
+ if (tooltip != NULL && utf_valid_string(tooltip, NULL))
+# if GTK_CHECK_VERSION(3,0,0)
+ /* Only set the tooltip when it's valid utf-8. */
+ gtk_widget_set_tooltip_text(menu->id, (const gchar *)tooltip);
+# else
+ /* Only set the tooltip when it's valid utf-8. */
+ gtk_tooltips_set_tip(GTK_TOOLBAR(gui.toolbar)->tooltips,
+ menu->id, (const char *)tooltip, NULL);
+# endif
+ CONVERT_TO_UTF8_FREE(tooltip);
+ }
+}
+#endif /* FEAT_TOOLBAR */
+
+
+#if defined(FEAT_MENU) || defined(PROTO)
+/*
+ * Destroy the machine specific menu widget.
+ */
+ void
+gui_mch_destroy_menu(vimmenu_T *menu)
+{
+ /* Don't let gtk_container_remove automatically destroy menu->id. */
+ if (menu->id != NULL)
+ g_object_ref(menu->id);
+
+ /* Workaround for a spurious gtk warning in Ubuntu: "Trying to remove
+ * a child that doesn't believe we're its parent."
+ * Remove widget from gui.menubar before destroying it. */
+ if (menu->id != NULL && gui.menubar != NULL
+ && gtk_widget_get_parent(menu->id) == gui.menubar)
+ gtk_container_remove(GTK_CONTAINER(gui.menubar), menu->id);
+
+# ifdef FEAT_TOOLBAR
+ if (menu->parent != NULL && menu_is_toolbar(menu->parent->name))
+ {
+ if (menu_is_separator(menu->name))
+# if GTK_CHECK_VERSION(3,0,0)
+ {
+ GtkToolItem *item = NULL;
+
+ item = gtk_toolbar_get_nth_item(GTK_TOOLBAR(gui.toolbar),
+ get_menu_position(menu));
+ if (item != NULL)
+ gtk_container_remove(GTK_CONTAINER(gui.toolbar),
+ GTK_WIDGET(item));
+ }
+# else
+ gtk_toolbar_remove_space(GTK_TOOLBAR(gui.toolbar),
+ get_menu_position(menu));
+# endif
+ else if (menu->id != NULL)
+ gtk_widget_destroy(menu->id);
+ }
+ else
+# endif /* FEAT_TOOLBAR */
+ {
+ if (menu->submenu_id != NULL)
+ gtk_widget_destroy(menu->submenu_id);
+
+ if (menu->id != NULL)
+ gtk_widget_destroy(menu->id);
+ }
+
+ if (menu->id != NULL)
+ g_object_unref(menu->id);
+ menu->submenu_id = NULL;
+ menu->id = NULL;
+}
+#endif /* FEAT_MENU */
+
+
+/*
+ * Scrollbar stuff.
+ */
+ void
+gui_mch_set_scrollbar_thumb(scrollbar_T *sb, long val, long size, long max)
+{
+ if (sb->id != NULL)
+ {
+ GtkAdjustment *adjustment;
+
+ adjustment = gtk_range_get_adjustment(GTK_RANGE(sb->id));
+
+ gtk_adjustment_set_lower(adjustment, 0.0);
+ gtk_adjustment_set_value(adjustment, val);
+ gtk_adjustment_set_upper(adjustment, max + 1);
+ gtk_adjustment_set_page_size(adjustment, size);
+ gtk_adjustment_set_page_increment(adjustment,
+ size < 3L ? 1L : size - 2L);
+ gtk_adjustment_set_step_increment(adjustment, 1.0);
+
+ g_signal_handler_block(G_OBJECT(adjustment), (gulong)sb->handler_id);
+
+#if !GTK_CHECK_VERSION(3,18,0)
+ gtk_adjustment_changed(adjustment);
+#endif
+
+ g_signal_handler_unblock(G_OBJECT(adjustment),
+ (gulong)sb->handler_id);
+ }
+}
+
+ void
+gui_mch_set_scrollbar_pos(scrollbar_T *sb, int x, int y, int w, int h)
+{
+ if (sb->id != NULL)
+ gtk_form_move_resize(GTK_FORM(gui.formwin), sb->id, x, y, w, h);
+}
+
+/*
+ * Take action upon scrollbar dragging.
+ */
+ static void
+adjustment_value_changed(GtkAdjustment *adjustment, gpointer data)
+{
+ scrollbar_T *sb;
+ long value;
+ int dragging = FALSE;
+
+#ifdef FEAT_XIM
+ /* cancel any preediting */
+ if (im_is_preediting())
+ xim_reset();
+#endif
+
+ sb = gui_find_scrollbar((long)data);
+ value = gtk_adjustment_get_value(adjustment);
+#if !GTK_CHECK_VERSION(3,0,0)
+ /*
+ * The dragging argument must be right for the scrollbar to work with
+ * closed folds. This isn't documented, hopefully this will keep on
+ * working in later GTK versions.
+ *
+ * FIXME: Well, it doesn't work in GTK2. :)
+ * HACK: Get the mouse pointer position, if it appears to be on an arrow
+ * button set "dragging" to FALSE. This assumes square buttons!
+ */
+ if (sb != NULL)
+ {
+ dragging = TRUE;
+
+ if (sb->wp != NULL)
+ {
+ int x;
+ int y;
+ GdkModifierType state;
+ int width;
+ int height;
+
+ /* vertical scrollbar: need to set "dragging" properly in case
+ * there are closed folds. */
+ gdk_window_get_pointer(sb->id->window, &x, &y, &state);
+ gdk_window_get_size(sb->id->window, &width, &height);
+ if (x >= 0 && x < width && y >= 0 && y < height)
+ {
+ if (y < width)
+ {
+ /* up arrow: move one (closed fold) line up */
+ dragging = FALSE;
+ value = sb->wp->w_topline - 2;
+ }
+ else if (y > height - width)
+ {
+ /* down arrow: move one (closed fold) line down */
+ dragging = FALSE;
+ value = sb->wp->w_topline;
+ }
+ }
+ }
+ }
+#endif /* !GTK_CHECK_VERSION(3,0,0) */
+ gui_drag_scrollbar(sb, value, dragging);
+}
+
+/* SBAR_VERT or SBAR_HORIZ */
+ void
+gui_mch_create_scrollbar(scrollbar_T *sb, int orient)
+{
+ if (orient == SBAR_HORIZ)
+#if GTK_CHECK_VERSION(3,2,0)
+ sb->id = gtk_scrollbar_new(GTK_ORIENTATION_HORIZONTAL, NULL);
+#else
+ sb->id = gtk_hscrollbar_new(NULL);
+#endif
+ else if (orient == SBAR_VERT)
+#if GTK_CHECK_VERSION(3,2,0)
+ sb->id = gtk_scrollbar_new(GTK_ORIENTATION_VERTICAL, NULL);
+#else
+ sb->id = gtk_vscrollbar_new(NULL);
+#endif
+
+ if (sb->id != NULL)
+ {
+ GtkAdjustment *adjustment;
+
+ gtk_widget_set_can_focus(sb->id, FALSE);
+ gtk_form_put(GTK_FORM(gui.formwin), sb->id, 0, 0);
+
+ adjustment = gtk_range_get_adjustment(GTK_RANGE(sb->id));
+
+ sb->handler_id = g_signal_connect(
+ G_OBJECT(adjustment), "value-changed",
+ G_CALLBACK(adjustment_value_changed),
+ GINT_TO_POINTER(sb->ident));
+ gui_mch_update();
+ }
+}
+
+ void
+gui_mch_destroy_scrollbar(scrollbar_T *sb)
+{
+ if (sb->id != NULL)
+ {
+ gtk_widget_destroy(sb->id);
+ sb->id = NULL;
+ }
+ gui_mch_update();
+}
+
+#if defined(FEAT_BROWSE) || defined(PROTO)
+/*
+ * Implementation of the file selector related stuff
+ */
+
+#ifndef USE_FILE_CHOOSER
+ static void
+browse_ok_cb(GtkWidget *widget UNUSED, gpointer cbdata)
+{
+ gui_T *vw = (gui_T *)cbdata;
+
+ if (vw->browse_fname != NULL)
+ g_free(vw->browse_fname);
+
+ vw->browse_fname = (char_u *)g_strdup(gtk_file_selection_get_filename(
+ GTK_FILE_SELECTION(vw->filedlg)));
+ gtk_widget_hide(vw->filedlg);
+}
+
+ static void
+browse_cancel_cb(GtkWidget *widget UNUSED, gpointer cbdata)
+{
+ gui_T *vw = (gui_T *)cbdata;
+
+ if (vw->browse_fname != NULL)
+ {
+ g_free(vw->browse_fname);
+ vw->browse_fname = NULL;
+ }
+ gtk_widget_hide(vw->filedlg);
+}
+
+ static gboolean
+browse_destroy_cb(GtkWidget *widget UNUSED)
+{
+ if (gui.browse_fname != NULL)
+ {
+ g_free(gui.browse_fname);
+ gui.browse_fname = NULL;
+ }
+ gui.filedlg = NULL;
+ gtk_main_quit();
+ return FALSE;
+}
+#endif
+
+/*
+ * Put up a file requester.
+ * Returns the selected name in allocated memory, or NULL for Cancel.
+ * saving, select file to write
+ * title title for the window
+ * dflt default name
+ * ext not used (extension added)
+ * initdir initial directory, NULL for current dir
+ * filter not used (file name filter)
+ */
+ char_u *
+gui_mch_browse(int saving UNUSED,
+ char_u *title,
+ char_u *dflt,
+ char_u *ext UNUSED,
+ char_u *initdir,
+ char_u *filter)
+{
+#ifdef USE_FILE_CHOOSER
+ GtkWidget *fc;
+#endif
+ char_u dirbuf[MAXPATHL];
+ guint log_handler;
+ const gchar *domain = "Gtk";
+
+ title = CONVERT_TO_UTF8(title);
+
+ /* GTK has a bug, it only works with an absolute path. */
+ if (initdir == NULL || *initdir == NUL)
+ mch_dirname(dirbuf, MAXPATHL);
+ else if (vim_FullName(initdir, dirbuf, MAXPATHL - 2, FALSE) == FAIL)
+ dirbuf[0] = NUL;
+ /* Always need a trailing slash for a directory. */
+ add_pathsep(dirbuf);
+
+ /* If our pointer is currently hidden, then we should show it. */
+ gui_mch_mousehide(FALSE);
+
+ /* Hack: The GTK file dialog warns when it can't access a new file, this
+ * makes it shut up. http://bugzilla.gnome.org/show_bug.cgi?id=664587 */
+ log_handler = g_log_set_handler(domain, G_LOG_LEVEL_WARNING,
+ recent_func_log_func, NULL);
+
+#ifdef USE_FILE_CHOOSER
+ /* We create the dialog each time, so that the button text can be "Open"
+ * or "Save" according to the action. */
+ fc = gtk_file_chooser_dialog_new((const gchar *)title,
+ GTK_WINDOW(gui.mainwin),
+ saving ? GTK_FILE_CHOOSER_ACTION_SAVE
+ : GTK_FILE_CHOOSER_ACTION_OPEN,
+# if GTK_CHECK_VERSION(3,10,0)
+ _("_Cancel"), GTK_RESPONSE_CANCEL,
+ saving ? _("_Save") : _("_Open"), GTK_RESPONSE_ACCEPT,
+# else
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ saving ? GTK_STOCK_SAVE : GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
+# endif
+ NULL);
+ gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(fc),
+ (const gchar *)dirbuf);
+
+ if (filter != NULL && *filter != NUL)
+ {
+ int i = 0;
+ char_u *patt;
+ char_u *p = filter;
+ GtkFileFilter *gfilter;
+
+ gfilter = gtk_file_filter_new();
+ patt = alloc(STRLEN(filter));
+ while (p != NULL && *p != NUL)
+ {
+ if (*p == '\n' || *p == ';' || *p == '\t')
+ {
+ STRNCPY(patt, filter, i);
+ patt[i] = '\0';
+ if (*p == '\t')
+ gtk_file_filter_set_name(gfilter, (gchar *)patt);
+ else
+ {
+ gtk_file_filter_add_pattern(gfilter, (gchar *)patt);
+ if (*p == '\n')
+ {
+ gtk_file_chooser_add_filter((GtkFileChooser *)fc,
+ gfilter);
+ if (*(p + 1) != NUL)
+ gfilter = gtk_file_filter_new();
+ }
+ }
+ filter = ++p;
+ i = 0;
+ }
+ else
+ {
+ p++;
+ i++;
+ }
+ }
+ vim_free(patt);
+ }
+ if (saving && dflt != NULL && *dflt != NUL)
+ gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(fc), (char *)dflt);
+
+ gui.browse_fname = NULL;
+ if (gtk_dialog_run(GTK_DIALOG(fc)) == GTK_RESPONSE_ACCEPT)
+ {
+ char *filename;
+
+ filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fc));
+ gui.browse_fname = (char_u *)g_strdup(filename);
+ g_free(filename);
+ }
+ gtk_widget_destroy(GTK_WIDGET(fc));
+
+#else /* !USE_FILE_CHOOSER */
+
+ if (gui.filedlg == NULL)
+ {
+ GtkFileSelection *fs; /* shortcut */
+
+ gui.filedlg = gtk_file_selection_new((const gchar *)title);
+ gtk_window_set_modal(GTK_WINDOW(gui.filedlg), TRUE);
+ gtk_window_set_transient_for(GTK_WINDOW(gui.filedlg),
+ GTK_WINDOW(gui.mainwin));
+ fs = GTK_FILE_SELECTION(gui.filedlg);
+
+ gtk_container_border_width(GTK_CONTAINER(fs), 4);
+
+ gtk_signal_connect(GTK_OBJECT(fs->ok_button),
+ "clicked", GTK_SIGNAL_FUNC(browse_ok_cb), &gui);
+ gtk_signal_connect(GTK_OBJECT(fs->cancel_button),
+ "clicked", GTK_SIGNAL_FUNC(browse_cancel_cb), &gui);
+ /* gtk_signal_connect() doesn't work for destroy, it causes a hang */
+ gtk_signal_connect_object(GTK_OBJECT(gui.filedlg),
+ "destroy", GTK_SIGNAL_FUNC(browse_destroy_cb),
+ GTK_OBJECT(gui.filedlg));
+ }
+ else
+ gtk_window_set_title(GTK_WINDOW(gui.filedlg), (const gchar *)title);
+
+ /* Concatenate "initdir" and "dflt". */
+ if (dflt != NULL && *dflt != NUL
+ && STRLEN(dirbuf) + 2 + STRLEN(dflt) < MAXPATHL)
+ STRCAT(dirbuf, dflt);
+
+ gtk_file_selection_set_filename(GTK_FILE_SELECTION(gui.filedlg),
+ (const gchar *)dirbuf);
+
+ gtk_widget_show(gui.filedlg);
+ gtk_main();
+#endif /* !USE_FILE_CHOOSER */
+ g_log_remove_handler(domain, log_handler);
+
+ CONVERT_TO_UTF8_FREE(title);
+ if (gui.browse_fname == NULL)
+ return NULL;
+
+ /* shorten the file name if possible */
+ return vim_strsave(shorten_fname1(gui.browse_fname));
+}
+
+/*
+ * Put up a directory selector
+ * Returns the selected name in allocated memory, or NULL for Cancel.
+ * title title for the window
+ * dflt default name
+ * initdir initial directory, NULL for current dir
+ */
+ char_u *
+gui_mch_browsedir(
+ char_u *title,
+ char_u *initdir)
+{
+# if defined(GTK_FILE_CHOOSER) /* Only in GTK 2.4 and later. */
+ char_u dirbuf[MAXPATHL];
+ char_u *p;
+ GtkWidget *dirdlg; /* file selection dialog */
+ char_u *dirname = NULL;
+
+ title = CONVERT_TO_UTF8(title);
+
+ dirdlg = gtk_file_chooser_dialog_new(
+ (const gchar *)title,
+ GTK_WINDOW(gui.mainwin),
+ GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
+# if GTK_CHECK_VERSION(3,10,0)
+ _("_Cancel"), GTK_RESPONSE_CANCEL,
+ _("_OK"), GTK_RESPONSE_ACCEPT,
+# else
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
+# endif
+ NULL);
+
+ CONVERT_TO_UTF8_FREE(title);
+
+ /* if our pointer is currently hidden, then we should show it. */
+ gui_mch_mousehide(FALSE);
+
+ /* GTK appears to insist on an absolute path. */
+ if (initdir == NULL || *initdir == NUL
+ || vim_FullName(initdir, dirbuf, MAXPATHL - 10, FALSE) == FAIL)
+ mch_dirname(dirbuf, MAXPATHL - 10);
+
+ /* Always need a trailing slash for a directory.
+ * Also add a dummy file name, so that we get to the directory. */
+ add_pathsep(dirbuf);
+ STRCAT(dirbuf, "@zd(*&1|");
+ gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dirdlg),
+ (const gchar *)dirbuf);
+
+ /* Run the dialog. */
+ if (gtk_dialog_run(GTK_DIALOG(dirdlg)) == GTK_RESPONSE_ACCEPT)
+ dirname = (char_u *)gtk_file_chooser_get_filename(
+ GTK_FILE_CHOOSER(dirdlg));
+ gtk_widget_destroy(dirdlg);
+ if (dirname == NULL)
+ return NULL;
+
+ /* shorten the file name if possible */
+ p = vim_strsave(shorten_fname1(dirname));
+ g_free(dirname);
+ return p;
+
+# else /* !defined(GTK_FILE_CHOOSER) */
+ /* For GTK 2.2 and earlier: fall back to ordinary file selector. */
+ return gui_mch_browse(0, title, NULL, NULL, initdir, NULL);
+# endif /* !defined(GTK_FILE_CHOOSER) */
+}
+
+
+#endif /* FEAT_BROWSE */
+
+#if defined(FEAT_GUI_DIALOG) || defined(PROTO)
+
+ static GtkWidget *
+create_message_dialog(int type, char_u *title, char_u *message)
+{
+ GtkWidget *dialog;
+ GtkMessageType message_type;
+
+ switch (type)
+ {
+ case VIM_ERROR: message_type = GTK_MESSAGE_ERROR; break;
+ case VIM_WARNING: message_type = GTK_MESSAGE_WARNING; break;
+ case VIM_QUESTION: message_type = GTK_MESSAGE_QUESTION; break;
+ default: message_type = GTK_MESSAGE_INFO; break;
+ }
+
+ message = CONVERT_TO_UTF8(message);
+ dialog = gtk_message_dialog_new(GTK_WINDOW(gui.mainwin),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ message_type,
+ GTK_BUTTONS_NONE,
+ "%s", (const char *)message);
+ CONVERT_TO_UTF8_FREE(message);
+
+ if (title != NULL)
+ {
+ title = CONVERT_TO_UTF8(title);
+ gtk_window_set_title(GTK_WINDOW(dialog), (const char *)title);
+ CONVERT_TO_UTF8_FREE(title);
+ }
+ else if (type == VIM_GENERIC)
+ {
+ gtk_window_set_title(GTK_WINDOW(dialog), "VIM");
+ }
+
+ return dialog;
+}
+
+/*
+ * Split up button_string into individual button labels by inserting
+ * NUL bytes. Also replace the Vim-style mnemonic accelerator prefix
+ * '&' with '_'. button_string must point to allocated memory!
+ * Return an allocated array of pointers into button_string.
+ */
+ static char **
+split_button_string(char_u *button_string, int *n_buttons)
+{
+ char **array;
+ char_u *p;
+ unsigned int count = 1;
+
+ for (p = button_string; *p != NUL; ++p)
+ if (*p == DLG_BUTTON_SEP)
+ ++count;
+
+ array = (char **)alloc((count + 1) * sizeof(char *));
+ count = 0;
+
+ if (array != NULL)
+ {
+ array[count++] = (char *)button_string;
+ for (p = button_string; *p != NUL; )
+ {
+ if (*p == DLG_BUTTON_SEP)
+ {
+ *p++ = NUL;
+ array[count++] = (char *)p;
+ }
+ else if (*p == DLG_HOTKEY_CHAR)
+ *p++ = '_';
+ else
+ MB_PTR_ADV(p);
+ }
+ array[count] = NULL; /* currently not relied upon, but doesn't hurt */
+ }
+
+ *n_buttons = count;
+ return array;
+}
+
+ static char **
+split_button_translation(const char *message)
+{
+ char **buttons = NULL;
+ char_u *str;
+ int n_buttons = 0;
+ int n_expected = 1;
+
+ for (str = (char_u *)message; *str != NUL; ++str)
+ if (*str == DLG_BUTTON_SEP)
+ ++n_expected;
+
+ str = (char_u *)_(message);
+ if (str != NULL)
+ {
+ if (output_conv.vc_type != CONV_NONE)
+ str = string_convert(&output_conv, str, NULL);
+ else
+ str = vim_strsave(str);
+
+ if (str != NULL)
+ buttons = split_button_string(str, &n_buttons);
+ }
+ /*
+ * Uh-oh... this should never ever happen. But we don't wanna crash
+ * if the translation is broken, thus fall back to the untranslated
+ * buttons string in case of emergency.
+ */
+ if (buttons == NULL || n_buttons != n_expected)
+ {
+ vim_free(buttons);
+ vim_free(str);
+ buttons = NULL;
+ str = vim_strsave((char_u *)message);
+
+ if (str != NULL)
+ buttons = split_button_string(str, &n_buttons);
+ if (buttons == NULL)
+ vim_free(str);
+ }
+
+ return buttons;
+}
+
+ static int
+button_equal(const char *a, const char *b)
+{
+ while (*a != '\0' && *b != '\0')
+ {
+ if (*a == '_' && *++a == '\0')
+ break;
+ if (*b == '_' && *++b == '\0')
+ break;
+
+ if (g_unichar_tolower(g_utf8_get_char(a))
+ != g_unichar_tolower(g_utf8_get_char(b)))
+ return FALSE;
+
+ a = g_utf8_next_char(a);
+ b = g_utf8_next_char(b);
+ }
+
+ return (*a == '\0' && *b == '\0');
+}
+
+ static void
+dialog_add_buttons(GtkDialog *dialog, char_u *button_string)
+{
+ char **ok;
+ char **ync; /* "yes no cancel" */
+ char **buttons;
+ int n_buttons = 0;
+ int idx;
+
+ button_string = vim_strsave(button_string); /* must be writable */
+ if (button_string == NULL)
+ return;
+
+ /* Check 'v' flag in 'guioptions': vertical button placement. */
+ if (vim_strchr(p_go, GO_VERTICAL) != NULL)
+ {
+# if GTK_CHECK_VERSION(3,0,0)
+ /* Add GTK+ 3 code if necessary. */
+ /* N.B. GTK+ 3 doesn't allow you to access vbox and action_area via
+ * the C API. */
+# else
+ GtkWidget *vbutton_box;
+
+ vbutton_box = gtk_vbutton_box_new();
+ gtk_widget_show(vbutton_box);
+ gtk_box_pack_end(GTK_BOX(GTK_DIALOG(dialog)->vbox),
+ vbutton_box, TRUE, FALSE, 0);
+ /* Overrule the "action_area" value, hopefully this works... */
+ GTK_DIALOG(dialog)->action_area = vbutton_box;
+# endif
+ }
+
+ /*
+ * Yes this is ugly, I don't particularly like it either. But doing it
+ * this way has the compelling advantage that translations need not to
+ * be touched at all. See below what 'ok' and 'ync' are used for.
+ */
+ ok = split_button_translation(N_("&Ok"));
+ ync = split_button_translation(N_("&Yes\n&No\n&Cancel"));
+ buttons = split_button_string(button_string, &n_buttons);
+
+ /*
+ * Yes, the buttons are in reversed order to match the GNOME 2 desktop
+ * environment. Don't hit me -- it's all about consistency.
+ * Well, apparently somebody changed his mind: with GTK 2.2.4 it works the
+ * other way around...
+ */
+ for (idx = 1; idx <= n_buttons; ++idx)
+ {
+ char *label;
+ char_u *label8;
+
+ label = buttons[idx - 1];
+ /*
+ * Perform some guesswork to find appropriate stock items for the
+ * buttons. We have to compare with a sample of the translated
+ * button string to get things right. Yes, this is hackish :/
+ *
+ * But even the common button labels aren't necessarily translated,
+ * since anyone can create their own dialogs using Vim functions.
+ * Thus we have to check for those too.
+ */
+ if (ok != NULL && ync != NULL) /* almost impossible to fail */
+ {
+# if GTK_CHECK_VERSION(3,10,0)
+ if (button_equal(label, ok[0])) label = _("OK");
+ else if (button_equal(label, ync[0])) label = _("Yes");
+ else if (button_equal(label, ync[1])) label = _("No");
+ else if (button_equal(label, ync[2])) label = _("Cancel");
+ else if (button_equal(label, "Ok")) label = _("OK");
+ else if (button_equal(label, "Yes")) label = _("Yes");
+ else if (button_equal(label, "No")) label = _("No");
+ else if (button_equal(label, "Cancel")) label = _("Cancel");
+# else
+ if (button_equal(label, ok[0])) label = GTK_STOCK_OK;
+ else if (button_equal(label, ync[0])) label = GTK_STOCK_YES;
+ else if (button_equal(label, ync[1])) label = GTK_STOCK_NO;
+ else if (button_equal(label, ync[2])) label = GTK_STOCK_CANCEL;
+ else if (button_equal(label, "Ok")) label = GTK_STOCK_OK;
+ else if (button_equal(label, "Yes")) label = GTK_STOCK_YES;
+ else if (button_equal(label, "No")) label = GTK_STOCK_NO;
+ else if (button_equal(label, "Cancel")) label = GTK_STOCK_CANCEL;
+# endif
+ }
+ label8 = CONVERT_TO_UTF8((char_u *)label);
+ gtk_dialog_add_button(dialog, (const gchar *)label8, idx);
+ CONVERT_TO_UTF8_FREE(label8);
+ }
+
+ if (ok != NULL)
+ vim_free(*ok);
+ if (ync != NULL)
+ vim_free(*ync);
+ vim_free(ok);
+ vim_free(ync);
+ vim_free(buttons);
+ vim_free(button_string);
+}
+
+/*
+ * Allow mnemonic accelerators to be activated without pressing <Alt>.
+ * I'm not sure if it's a wise idea to do this. However, the old GTK+ 1.2
+ * GUI used to work this way, and I consider the impact on UI consistency
+ * low enough to justify implementing this as a special Vim feature.
+ */
+typedef struct _DialogInfo
+{
+ int ignore_enter; /* no default button, ignore "Enter" */
+ int noalt; /* accept accelerators without Alt */
+ GtkDialog *dialog; /* Widget of the dialog */
+} DialogInfo;
+
+ static gboolean
+dialog_key_press_event_cb(GtkWidget *widget, GdkEventKey *event, gpointer data)
+{
+ DialogInfo *di = (DialogInfo *)data;
+
+ /* Ignore hitting Enter (or Space) when there is no default button. */
+ if (di->ignore_enter && (event->keyval == GDK_Return
+ || event->keyval == ' '))
+ return TRUE;
+ else /* A different key was pressed, return to normal behavior */
+ di->ignore_enter = FALSE;
+
+ /* Close the dialog when hitting "Esc". */
+ if (event->keyval == GDK_Escape)
+ {
+ gtk_dialog_response(di->dialog, GTK_RESPONSE_REJECT);
+ return TRUE;
+ }
+
+ if (di->noalt
+ && (event->state & gtk_accelerator_get_default_mod_mask()) == 0)
+ {
+ return gtk_window_mnemonic_activate(
+ GTK_WINDOW(widget), event->keyval,
+ gtk_window_get_mnemonic_modifier(GTK_WINDOW(widget)));
+ }
+
+ return FALSE; /* continue emission */
+}
+
+ int
+gui_mch_dialog(int type, /* type of dialog */
+ char_u *title, /* title of dialog */
+ char_u *message, /* message text */
+ char_u *buttons, /* names of buttons */
+ int def_but, /* default button */
+ char_u *textfield, /* text for textfield or NULL */
+ int ex_cmd UNUSED)
+{
+ GtkWidget *dialog;
+ GtkWidget *entry = NULL;
+ char_u *text;
+ int response;
+ DialogInfo dialoginfo;
+
+ dialog = create_message_dialog(type, title, message);
+ dialoginfo.dialog = GTK_DIALOG(dialog);
+ dialog_add_buttons(GTK_DIALOG(dialog), buttons);
+
+ if (textfield != NULL)
+ {
+ GtkWidget *alignment;
+
+ entry = gtk_entry_new();
+ gtk_widget_show(entry);
+
+ /* Make Enter work like pressing OK. */
+ gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE);
+
+ text = CONVERT_TO_UTF8(textfield);
+ gtk_entry_set_text(GTK_ENTRY(entry), (const char *)text);
+ CONVERT_TO_UTF8_FREE(text);
+
+# if GTK_CHECK_VERSION(3,14,0)
+ gtk_widget_set_halign(GTK_WIDGET(entry), GTK_ALIGN_CENTER);
+ gtk_widget_set_valign(GTK_WIDGET(entry), GTK_ALIGN_CENTER);
+ gtk_widget_set_hexpand(GTK_WIDGET(entry), TRUE);
+ gtk_widget_set_vexpand(GTK_WIDGET(entry), TRUE);
+
+ alignment = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
+# else
+ alignment = gtk_alignment_new((float)0.5, (float)0.5,
+ (float)1.0, (float)1.0);
+# endif
+ gtk_container_add(GTK_CONTAINER(alignment), entry);
+ gtk_container_set_border_width(GTK_CONTAINER(alignment), 5);
+ gtk_widget_show(alignment);
+
+# if GTK_CHECK_VERSION(3,0,0)
+ {
+ GtkWidget * const vbox
+ = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
+ gtk_box_pack_start(GTK_BOX(vbox),
+ alignment, TRUE, FALSE, 0);
+ }
+# else
+ gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
+ alignment, TRUE, FALSE, 0);
+# endif
+ dialoginfo.noalt = FALSE;
+ }
+ else
+ dialoginfo.noalt = TRUE;
+
+ /* Allow activation of mnemonic accelerators without pressing <Alt> when
+ * there is no textfield. Handle pressing Esc. */
+ g_signal_connect(G_OBJECT(dialog), "key-press-event",
+ G_CALLBACK(&dialog_key_press_event_cb), &dialoginfo);
+
+ if (def_but > 0)
+ {
+ gtk_dialog_set_default_response(GTK_DIALOG(dialog), def_but);
+ dialoginfo.ignore_enter = FALSE;
+ }
+ else
+ /* No default button, ignore pressing Enter. */
+ dialoginfo.ignore_enter = TRUE;
+
+ /* Show the mouse pointer if it's currently hidden. */
+ gui_mch_mousehide(FALSE);
+
+ response = gtk_dialog_run(GTK_DIALOG(dialog));
+
+ /* GTK_RESPONSE_NONE means the dialog was programmatically destroyed. */
+ if (response != GTK_RESPONSE_NONE)
+ {
+ if (response == GTK_RESPONSE_ACCEPT) /* Enter pressed */
+ response = def_but;
+ if (textfield != NULL)
+ {
+ text = (char_u *)gtk_entry_get_text(GTK_ENTRY(entry));
+ text = CONVERT_FROM_UTF8(text);
+
+ vim_strncpy(textfield, text, IOSIZE - 1);
+
+ CONVERT_FROM_UTF8_FREE(text);
+ }
+ gtk_widget_destroy(dialog);
+ }
+
+ return response > 0 ? response : 0;
+}
+
+#endif /* FEAT_GUI_DIALOG */
+
+
+#if defined(FEAT_MENU) || defined(PROTO)
+
+ void
+gui_mch_show_popupmenu(vimmenu_T *menu)
+{
+# if defined(FEAT_XIM)
+ /*
+ * Append a submenu for selecting an input method. This is
+ * currently the only way to switch input methods at runtime.
+ */
+# if !GTK_CHECK_VERSION(3,10,0)
+ if (xic != NULL && g_object_get_data(G_OBJECT(menu->submenu_id),
+ "vim-has-im-menu") == NULL)
+ {
+ GtkWidget *menuitem;
+ GtkWidget *submenu;
+ char_u *name;
+
+ menuitem = gtk_separator_menu_item_new();
+ gtk_widget_show(menuitem);
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu->submenu_id), menuitem);
+
+ name = (char_u *)_("Input _Methods");
+ name = CONVERT_TO_UTF8(name);
+ menuitem = gtk_menu_item_new_with_mnemonic((const char *)name);
+ CONVERT_TO_UTF8_FREE(name);
+ gtk_widget_show(menuitem);
+
+ submenu = gtk_menu_new();
+ gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), submenu);
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu->submenu_id), menuitem);
+
+ gtk_im_multicontext_append_menuitems(GTK_IM_MULTICONTEXT(xic),
+ GTK_MENU_SHELL(submenu));
+ g_object_set_data(G_OBJECT(menu->submenu_id),
+ "vim-has-im-menu", GINT_TO_POINTER(TRUE));
+ }
+# endif
+# endif /* FEAT_XIM */
+
+# if GTK_CHECK_VERSION(3,22,2)
+ {
+ GdkEventButton trigger;
+
+ /* A pseudo event to have gtk_menu_popup_at_pointer() work. Since the
+ * function calculates the popup menu position on the basis of the
+ * actual pointer position when it is invoked, the fields x, y, x_root
+ * and y_root are set to zero for convenience. */
+ trigger.type = GDK_BUTTON_PRESS;
+ trigger.window = gtk_widget_get_window(gui.drawarea);
+ trigger.send_event = FALSE;
+ trigger.time = gui.event_time;
+ trigger.x = 0.0;
+ trigger.y = 0.0;
+ trigger.axes = NULL;
+ trigger.state = 0;
+ trigger.button = 3;
+ trigger.device = NULL;
+ trigger.x_root = 0.0;
+ trigger.y_root = 0.0;
+
+ gtk_menu_popup_at_pointer(GTK_MENU(menu->submenu_id),
+ (GdkEvent *)&trigger);
+ }
+#else
+ gtk_menu_popup(GTK_MENU(menu->submenu_id),
+ NULL, NULL,
+ (GtkMenuPositionFunc)NULL, NULL,
+ 3U, gui.event_time);
+#endif
+}
+
+/* Ugly global variable to pass "mouse_pos" flag from gui_make_popup() to
+ * popup_menu_position_func(). */
+static int popup_mouse_pos;
+
+/*
+ * Menu position callback; used by gui_make_popup() to place the menu
+ * at the current text cursor position.
+ *
+ * Note: The push_in output argument seems to affect scrolling of huge
+ * menus that don't fit on the screen. Leave it at the default for now.
+ */
+ static void
+popup_menu_position_func(GtkMenu *menu UNUSED,
+ gint *x, gint *y,
+ gboolean *push_in UNUSED,
+ gpointer user_data UNUSED)
+{
+ gdk_window_get_origin(gtk_widget_get_window(gui.drawarea), x, y);
+
+ if (popup_mouse_pos)
+ {
+ int mx, my;
+
+ gui_mch_getmouse(&mx, &my);
+ *x += mx;
+ *y += my;
+ }
+ else if (curwin != NULL && gui.drawarea != NULL &&
+ gtk_widget_get_window(gui.drawarea) != NULL)
+ {
+ /* Find the cursor position in the current window */
+ *x += FILL_X(curwin->w_wincol + curwin->w_wcol + 1) + 1;
+ *y += FILL_Y(W_WINROW(curwin) + curwin->w_wrow + 1) + 1;
+ }
+}
+
+ void
+gui_make_popup(char_u *path_name, int mouse_pos)
+{
+ vimmenu_T *menu;
+
+ popup_mouse_pos = mouse_pos;
+
+ menu = gui_find_menu(path_name);
+
+ if (menu != NULL && menu->submenu_id != NULL)
+ {
+# if GTK_CHECK_VERSION(3,22,2)
+ GdkWindow * const win = gtk_widget_get_window(gui.drawarea);
+ GdkEventButton trigger;
+
+ /* A pseudo event to have gtk_menu_popup_at_*() functions work. Since
+ * the position where the menu pops up is automatically adjusted by
+ * the functions, none of the fields x, y, x_root and y_root has to be
+ * set to a specific value here; therefore, they are set to zero for
+ * convenience.*/
+ trigger.type = GDK_BUTTON_PRESS;
+ trigger.window = win;
+ trigger.send_event = FALSE;
+ trigger.time = GDK_CURRENT_TIME;
+ trigger.x = 0.0;
+ trigger.y = 0.0;
+ trigger.axes = NULL;
+ trigger.state = 0;
+ trigger.button = 0;
+ trigger.device = NULL;
+ trigger.x_root = 0.0;
+ trigger.y_root = 0.0;
+
+ if (mouse_pos)
+ gtk_menu_popup_at_pointer(GTK_MENU(menu->submenu_id),
+ (GdkEvent *)&trigger);
+ else
+ {
+ gint origin_x, origin_y;
+ GdkRectangle rect = { 0, 0, 0, 0 };
+
+ gdk_window_get_origin(win, &origin_x, &origin_y);
+ popup_menu_position_func(NULL, &rect.x, &rect.y, NULL, NULL);
+
+ rect.x -= origin_x;
+ rect.y -= origin_y;
+
+ gtk_menu_popup_at_rect(GTK_MENU(menu->submenu_id),
+ win,
+ &rect,
+ GDK_GRAVITY_SOUTH_EAST,
+ GDK_GRAVITY_NORTH_WEST,
+ (GdkEvent *)&trigger);
+ }
+# else
+ gtk_menu_popup(GTK_MENU(menu->submenu_id),
+ NULL, NULL,
+ &popup_menu_position_func, NULL,
+ 0U, (guint32)GDK_CURRENT_TIME);
+# endif
+ }
+}
+
+#endif /* FEAT_MENU */
+
+
+/*
+ * We don't create it twice.
+ */
+
+typedef struct _SharedFindReplace
+{
+ GtkWidget *dialog; /* the main dialog widget */
+ GtkWidget *wword; /* 'Whole word only' check button */
+ GtkWidget *mcase; /* 'Match case' check button */
+ GtkWidget *up; /* search direction 'Up' radio button */
+ GtkWidget *down; /* search direction 'Down' radio button */
+ GtkWidget *what; /* 'Find what' entry text widget */
+ GtkWidget *with; /* 'Replace with' entry text widget */
+ GtkWidget *find; /* 'Find Next' action button */
+ GtkWidget *replace; /* 'Replace With' action button */
+ GtkWidget *all; /* 'Replace All' action button */
+} SharedFindReplace;
+
+static SharedFindReplace find_widgets = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
+static SharedFindReplace repl_widgets = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
+
+ static int
+find_key_press_event(
+ GtkWidget *widget UNUSED,
+ GdkEventKey *event,
+ SharedFindReplace *frdp)
+{
+ /* If the user is holding one of the key modifiers we will just bail out,
+ * thus preserving the possibility of normal focus traversal.
+ */
+ if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK))
+ return FALSE;
+
+ /* the Escape key synthesizes a cancellation action */
+ if (event->keyval == GDK_Escape)
+ {
+ gtk_widget_hide(frdp->dialog);
+
+ return TRUE;
+ }
+
+ /* It would be delightful if it where possible to do search history
+ * operations on the K_UP and K_DOWN keys here.
+ */
+
+ return FALSE;
+}
+
+ static GtkWidget *
+#if GTK_CHECK_VERSION(3,10,0)
+create_image_button(const char *stock_id UNUSED,
+ const char *label)
+#else
+create_image_button(const char *stock_id,
+ const char *label)
+#endif
+{
+ char_u *text;
+ GtkWidget *box;
+ GtkWidget *alignment;
+ GtkWidget *button;
+
+ text = CONVERT_TO_UTF8((char_u *)label);
+
+#if GTK_CHECK_VERSION(3,2,0)
+ box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 3);
+ gtk_box_set_homogeneous(GTK_BOX(box), FALSE);
+#else
+ box = gtk_hbox_new(FALSE, 3);
+#endif
+#if !GTK_CHECK_VERSION(3,10,0)
+ if (stock_id != NULL)
+ gtk_box_pack_start(GTK_BOX(box),
+ gtk_image_new_from_stock(stock_id, GTK_ICON_SIZE_BUTTON),
+ FALSE, FALSE, 0);
+#endif
+ gtk_box_pack_start(GTK_BOX(box),
+ gtk_label_new((const char *)text),
+ FALSE, FALSE, 0);
+
+ CONVERT_TO_UTF8_FREE(text);
+
+#if GTK_CHECK_VERSION(3,14,0)
+ gtk_widget_set_halign(GTK_WIDGET(box), GTK_ALIGN_CENTER);
+ gtk_widget_set_valign(GTK_WIDGET(box), GTK_ALIGN_CENTER);
+ gtk_widget_set_hexpand(GTK_WIDGET(box), TRUE);
+ gtk_widget_set_vexpand(GTK_WIDGET(box), TRUE);
+
+ alignment = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
+#else
+ alignment = gtk_alignment_new((float)0.5, (float)0.5,
+ (float)0.0, (float)0.0);
+#endif
+ gtk_container_add(GTK_CONTAINER(alignment), box);
+ gtk_widget_show_all(alignment);
+
+ button = gtk_button_new();
+ gtk_container_add(GTK_CONTAINER(button), alignment);
+
+ return button;
+}
+
+/*
+ * This is currently only used by find_replace_dialog_create(), and
+ * I'd really like to keep it at that. In other words: don't spread
+ * this nasty hack all over the code. Think twice.
+ */
+ static const char *
+convert_localized_message(char_u **buffer, const char *message)
+{
+ if (output_conv.vc_type == CONV_NONE)
+ return message;
+
+ vim_free(*buffer);
+ *buffer = string_convert(&output_conv, (char_u *)message, NULL);
+
+ return (const char *)*buffer;
+}
+
+/*
+ * Returns the number of characters in GtkEntry.
+ */
+ static unsigned long
+entry_get_text_length(GtkEntry *entry)
+{
+ g_return_val_if_fail(entry != NULL, 0);
+ g_return_val_if_fail(GTK_IS_ENTRY(entry) == TRUE, 0);
+
+#if GTK_CHECK_VERSION(2,18,0)
+ /* 2.18 introduced a new object GtkEntryBuffer to handle text data for
+ * GtkEntry instead of letting each instance of the latter have its own
+ * storage for that. The code below is almost identical to the
+ * implementation of gtk_entry_get_text_length() for the versions >= 2.18.
+ */
+ return gtk_entry_buffer_get_length(gtk_entry_get_buffer(entry));
+#elif GTK_CHECK_VERSION(2,14,0)
+ /* 2.14 introduced a new function to avoid memory management bugs which can
+ * happen when gtk_entry_get_text() is used without due care and attention.
+ */
+ return gtk_entry_get_text_length(entry);
+#else
+ /* gtk_entry_get_text() returns the pointer to the storage allocated
+ * internally by the widget. Accordingly, use the one with great care:
+ * Don't free it nor modify the contents it points to; call the function
+ * every time you need the pointer since its value may have been changed
+ * by the widget. */
+ return g_utf8_strlen(gtk_entry_get_text(entry), -1);
+#endif
+}
+
+ static void
+find_replace_dialog_create(char_u *arg, int do_replace)
+{
+ GtkWidget *hbox; /* main top down box */
+ GtkWidget *actionarea;
+ GtkWidget *table;
+ GtkWidget *tmp;
+ GtkWidget *vbox;
+ gboolean sensitive;
+ SharedFindReplace *frdp;
+ char_u *entry_text;
+ int wword = FALSE;
+ int mcase = !p_ic;
+ char_u *conv_buffer = NULL;
+# define CONV(message) convert_localized_message(&conv_buffer, (message))
+
+ frdp = (do_replace) ? (&repl_widgets) : (&find_widgets);
+
+ /* Get the search string to use. */
+ entry_text = get_find_dialog_text(arg, &wword, &mcase);
+
+ if (entry_text != NULL && output_conv.vc_type != CONV_NONE)
+ {
+ char_u *old_text = entry_text;
+ entry_text = string_convert(&output_conv, entry_text, NULL);
+ vim_free(old_text);
+ }
+
+ /*
+ * If the dialog already exists, just raise it.
+ */
+ if (frdp->dialog)
+ {
+ if (entry_text != NULL)
+ {
+ gtk_entry_set_text(GTK_ENTRY(frdp->what), (char *)entry_text);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(frdp->wword),
+ (gboolean)wword);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(frdp->mcase),
+ (gboolean)mcase);
+ }
+ gtk_window_present(GTK_WINDOW(frdp->dialog));
+
+ /* For :promptfind dialog, always give keyboard focus to 'what' entry.
+ * For :promptrepl dialog, give it to 'with' entry if 'what' has an
+ * non-empty entry; otherwise, to 'what' entry. */
+ gtk_widget_grab_focus(frdp->what);
+ if (do_replace && entry_get_text_length(GTK_ENTRY(frdp->what)) > 0)
+ gtk_widget_grab_focus(frdp->with);
+
+ vim_free(entry_text);
+ return;
+ }
+
+ frdp->dialog = gtk_dialog_new();
+#if GTK_CHECK_VERSION(3,0,0)
+ /* Nothing equivalent to gtk_dialog_set_has_separator() in GTK+ 3. */
+#else
+ gtk_dialog_set_has_separator(GTK_DIALOG(frdp->dialog), FALSE);
+#endif
+ gtk_window_set_transient_for(GTK_WINDOW(frdp->dialog), GTK_WINDOW(gui.mainwin));
+ gtk_window_set_destroy_with_parent(GTK_WINDOW(frdp->dialog), TRUE);
+
+ if (do_replace)
+ {
+ gtk_window_set_title(GTK_WINDOW(frdp->dialog),
+ CONV(_("VIM - Search and Replace...")));
+ }
+ else
+ {
+ gtk_window_set_title(GTK_WINDOW(frdp->dialog),
+ CONV(_("VIM - Search...")));
+ }
+
+#if GTK_CHECK_VERSION(3,2,0)
+ hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
+ gtk_box_set_homogeneous(GTK_BOX(hbox), FALSE);
+#else
+ hbox = gtk_hbox_new(FALSE, 0);
+#endif
+ gtk_container_set_border_width(GTK_CONTAINER(hbox), 10);
+#if GTK_CHECK_VERSION(3,0,0)
+ {
+ GtkWidget * const dialog_vbox
+ = gtk_dialog_get_content_area(GTK_DIALOG(frdp->dialog));
+ gtk_container_add(GTK_CONTAINER(dialog_vbox), hbox);
+ }
+#else
+ gtk_container_add(GTK_CONTAINER(GTK_DIALOG(frdp->dialog)->vbox), hbox);
+#endif
+
+ if (do_replace)
+#if GTK_CHECK_VERSION(3,4,0)
+ table = gtk_grid_new();
+#else
+ table = gtk_table_new(1024, 4, FALSE);
+#endif
+ else
+#if GTK_CHECK_VERSION(3,4,0)
+ table = gtk_grid_new();
+#else
+ table = gtk_table_new(1024, 3, FALSE);
+#endif
+ gtk_box_pack_start(GTK_BOX(hbox), table, TRUE, TRUE, 0);
+ gtk_container_set_border_width(GTK_CONTAINER(table), 4);
+
+ tmp = gtk_label_new(CONV(_("Find what:")));
+#if GTK_CHECK_VERSION(3,16,0)
+ gtk_label_set_xalign(GTK_LABEL(tmp), 0.0);
+ gtk_label_set_yalign(GTK_LABEL(tmp), 0.5);
+#elif GTK_CHECK_VERSION(3,14,0)
+ {
+ GValue align_val = G_VALUE_INIT;
+
+ g_value_init(&align_val, G_TYPE_FLOAT);
+
+ g_value_set_float(&align_val, 0.0);
+ g_object_set_property(G_OBJECT(tmp), "xalign", &align_val);
+
+ g_value_set_float(&align_val, 0.5);
+ g_object_set_property(G_OBJECT(tmp), "yalign", &align_val);
+
+ g_value_unset(&align_val);
+ }
+#else
+ gtk_misc_set_alignment(GTK_MISC(tmp), (gfloat)0.0, (gfloat)0.5);
+#endif
+#if GTK_CHECK_VERSION(3,4,0)
+ gtk_grid_attach(GTK_GRID(table), tmp, 0, 0, 2, 1);
+#else
+ gtk_table_attach(GTK_TABLE(table), tmp, 0, 1, 0, 1,
+ GTK_FILL, GTK_EXPAND, 2, 2);
+#endif
+ frdp->what = gtk_entry_new();
+ sensitive = (entry_text != NULL && entry_text[0] != NUL);
+ if (entry_text != NULL)
+ gtk_entry_set_text(GTK_ENTRY(frdp->what), (char *)entry_text);
+ g_signal_connect(G_OBJECT(frdp->what), "changed",
+ G_CALLBACK(entry_changed_cb), frdp->dialog);
+ g_signal_connect_after(G_OBJECT(frdp->what), "key-press-event",
+ G_CALLBACK(find_key_press_event),
+ (gpointer) frdp);
+#if GTK_CHECK_VERSION(3,4,0)
+ gtk_grid_attach(GTK_GRID(table), frdp->what, 2, 0, 5, 1);
+#else
+ gtk_table_attach(GTK_TABLE(table), frdp->what, 1, 1024, 0, 1,
+ GTK_EXPAND | GTK_FILL, GTK_EXPAND, 2, 2);
+#endif
+
+ if (do_replace)
+ {
+ tmp = gtk_label_new(CONV(_("Replace with:")));
+#if GTK_CHECK_VERSION(3,16,0)
+ gtk_label_set_xalign(GTK_LABEL(tmp), 0.0);
+ gtk_label_set_yalign(GTK_LABEL(tmp), 0.5);
+#elif GTK_CHECK_VERSION(3,14,0)
+ {
+ GValue align_val = G_VALUE_INIT;
+
+ g_value_init(&align_val, G_TYPE_FLOAT);
+
+ g_value_set_float(&align_val, 0.0);
+ g_object_set_property(G_OBJECT(tmp), "xalign", &align_val);
+
+ g_value_set_float(&align_val, 0.5);
+ g_object_set_property(G_OBJECT(tmp), "yalign", &align_val);
+
+ g_value_unset(&align_val);
+ }
+#else
+ gtk_misc_set_alignment(GTK_MISC(tmp), (gfloat)0.0, (gfloat)0.5);
+#endif
+#if GTK_CHECK_VERSION(3,4,0)
+ gtk_grid_attach(GTK_GRID(table), tmp, 0, 1, 2, 1);
+#else
+ gtk_table_attach(GTK_TABLE(table), tmp, 0, 1, 1, 2,
+ GTK_FILL, GTK_EXPAND, 2, 2);
+#endif
+ frdp->with = gtk_entry_new();
+ g_signal_connect(G_OBJECT(frdp->with), "activate",
+ G_CALLBACK(find_replace_cb),
+ GINT_TO_POINTER(FRD_R_FINDNEXT));
+ g_signal_connect_after(G_OBJECT(frdp->with), "key-press-event",
+ G_CALLBACK(find_key_press_event),
+ (gpointer) frdp);
+#if GTK_CHECK_VERSION(3,4,0)
+ gtk_grid_attach(GTK_GRID(table), frdp->with, 2, 1, 5, 1);
+#else
+ gtk_table_attach(GTK_TABLE(table), frdp->with, 1, 1024, 1, 2,
+ GTK_EXPAND | GTK_FILL, GTK_EXPAND, 2, 2);
+#endif
+
+ /*
+ * Make the entry activation only change the input focus onto the
+ * with item.
+ */
+ g_signal_connect(G_OBJECT(frdp->what), "activate",
+ G_CALLBACK(entry_activate_cb), frdp->with);
+ }
+ else
+ {
+ /*
+ * Make the entry activation do the search.
+ */
+ g_signal_connect(G_OBJECT(frdp->what), "activate",
+ G_CALLBACK(find_replace_cb),
+ GINT_TO_POINTER(FRD_FINDNEXT));
+ }
+
+ /* whole word only button */
+ frdp->wword = gtk_check_button_new_with_label(CONV(_("Match whole word only")));
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(frdp->wword),
+ (gboolean)wword);
+ if (do_replace)
+#if GTK_CHECK_VERSION(3,4,0)
+ gtk_grid_attach(GTK_GRID(table), frdp->wword, 0, 2, 5, 1);
+#else
+ gtk_table_attach(GTK_TABLE(table), frdp->wword, 0, 1023, 2, 3,
+ GTK_FILL, GTK_EXPAND, 2, 2);
+#endif
+ else
+#if GTK_CHECK_VERSION(3,4,0)
+ gtk_grid_attach(GTK_GRID(table), frdp->wword, 0, 3, 5, 1);
+#else
+ gtk_table_attach(GTK_TABLE(table), frdp->wword, 0, 1023, 1, 2,
+ GTK_FILL, GTK_EXPAND, 2, 2);
+#endif
+
+ /* match case button */
+ frdp->mcase = gtk_check_button_new_with_label(CONV(_("Match case")));
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(frdp->mcase),
+ (gboolean)mcase);
+ if (do_replace)
+#if GTK_CHECK_VERSION(3,4,0)
+ gtk_grid_attach(GTK_GRID(table), frdp->mcase, 0, 3, 5, 1);
+#else
+ gtk_table_attach(GTK_TABLE(table), frdp->mcase, 0, 1023, 3, 4,
+ GTK_FILL, GTK_EXPAND, 2, 2);
+#endif
+ else
+#if GTK_CHECK_VERSION(3,4,0)
+ gtk_grid_attach(GTK_GRID(table), frdp->mcase, 0, 4, 5, 1);
+#else
+ gtk_table_attach(GTK_TABLE(table), frdp->mcase, 0, 1023, 2, 3,
+ GTK_FILL, GTK_EXPAND, 2, 2);
+#endif
+
+ tmp = gtk_frame_new(CONV(_("Direction")));
+ if (do_replace)
+#if GTK_CHECK_VERSION(3,4,0)
+ gtk_grid_attach(GTK_GRID(table), tmp, 5, 2, 2, 4);
+#else
+ gtk_table_attach(GTK_TABLE(table), tmp, 1023, 1024, 2, 4,
+ GTK_FILL, GTK_FILL, 2, 2);
+#endif
+ else
+#if GTK_CHECK_VERSION(3,4,0)
+ gtk_grid_attach(GTK_GRID(table), tmp, 5, 2, 1, 3);
+#else
+ gtk_table_attach(GTK_TABLE(table), tmp, 1023, 1024, 1, 3,
+ GTK_FILL, GTK_FILL, 2, 2);
+#endif
+#if GTK_CHECK_VERSION(3,2,0)
+ vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
+ gtk_box_set_homogeneous(GTK_BOX(vbox), FALSE);
+#else
+ vbox = gtk_vbox_new(FALSE, 0);
+#endif
+ gtk_container_set_border_width(GTK_CONTAINER(vbox), 0);
+ gtk_container_add(GTK_CONTAINER(tmp), vbox);
+
+ /* 'Up' and 'Down' buttons */
+ frdp->up = gtk_radio_button_new_with_label(NULL, CONV(_("Up")));
+ gtk_box_pack_start(GTK_BOX(vbox), frdp->up, TRUE, TRUE, 0);
+ frdp->down = gtk_radio_button_new_with_label(
+ gtk_radio_button_get_group(GTK_RADIO_BUTTON(frdp->up)),
+ CONV(_("Down")));
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(frdp->down), TRUE);
+ gtk_container_set_border_width(GTK_CONTAINER(vbox), 2);
+ gtk_box_pack_start(GTK_BOX(vbox), frdp->down, TRUE, TRUE, 0);
+
+ /* vbox to hold the action buttons */
+#if GTK_CHECK_VERSION(3,2,0)
+ actionarea = gtk_button_box_new(GTK_ORIENTATION_VERTICAL);
+#else
+ actionarea = gtk_vbutton_box_new();
+#endif
+ gtk_container_set_border_width(GTK_CONTAINER(actionarea), 2);
+ gtk_box_pack_end(GTK_BOX(hbox), actionarea, FALSE, FALSE, 0);
+
+ /* 'Find Next' button */
+#if GTK_CHECK_VERSION(3,10,0)
+ frdp->find = create_image_button(NULL, _("Find Next"));
+#else
+ frdp->find = create_image_button(GTK_STOCK_FIND, _("Find Next"));
+#endif
+ gtk_widget_set_sensitive(frdp->find, sensitive);
+
+ g_signal_connect(G_OBJECT(frdp->find), "clicked",
+ G_CALLBACK(find_replace_cb),
+ (do_replace) ? GINT_TO_POINTER(FRD_R_FINDNEXT)
+ : GINT_TO_POINTER(FRD_FINDNEXT));
+
+ gtk_widget_set_can_default(frdp->find, TRUE);
+ gtk_box_pack_start(GTK_BOX(actionarea), frdp->find, FALSE, FALSE, 0);
+ gtk_widget_grab_default(frdp->find);
+
+ if (do_replace)
+ {
+ /* 'Replace' button */
+#if GTK_CHECK_VERSION(3,10,0)
+ frdp->replace = create_image_button(NULL, _("Replace"));
+#else
+ frdp->replace = create_image_button(GTK_STOCK_CONVERT, _("Replace"));
+#endif
+ gtk_widget_set_sensitive(frdp->replace, sensitive);
+ gtk_widget_set_can_default(frdp->find, TRUE);
+ gtk_box_pack_start(GTK_BOX(actionarea), frdp->replace, FALSE, FALSE, 0);
+ g_signal_connect(G_OBJECT(frdp->replace), "clicked",
+ G_CALLBACK(find_replace_cb),
+ GINT_TO_POINTER(FRD_REPLACE));
+
+ /* 'Replace All' button */
+#if GTK_CHECK_VERSION(3,10,0)
+ frdp->all = create_image_button(NULL, _("Replace All"));
+#else
+ frdp->all = create_image_button(GTK_STOCK_CONVERT, _("Replace All"));
+#endif
+ gtk_widget_set_sensitive(frdp->all, sensitive);
+ gtk_widget_set_can_default(frdp->all, TRUE);
+ gtk_box_pack_start(GTK_BOX(actionarea), frdp->all, FALSE, FALSE, 0);
+ g_signal_connect(G_OBJECT(frdp->all), "clicked",
+ G_CALLBACK(find_replace_cb),
+ GINT_TO_POINTER(FRD_REPLACEALL));
+ }
+
+ /* 'Cancel' button */
+#if GTK_CHECK_VERSION(3,10,0)
+ tmp = gtk_button_new_with_mnemonic(_("_Close"));
+#else
+ tmp = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
+#endif
+ gtk_widget_set_can_default(tmp, TRUE);
+ gtk_box_pack_end(GTK_BOX(actionarea), tmp, FALSE, FALSE, 0);
+ g_signal_connect_swapped(G_OBJECT(tmp),
+ "clicked", G_CALLBACK(gtk_widget_hide),
+ G_OBJECT(frdp->dialog));
+ g_signal_connect_swapped(G_OBJECT(frdp->dialog),
+ "delete-event", G_CALLBACK(gtk_widget_hide_on_delete),
+ G_OBJECT(frdp->dialog));
+
+#if GTK_CHECK_VERSION(3,2,0)
+ tmp = gtk_separator_new(GTK_ORIENTATION_VERTICAL);
+#else
+ tmp = gtk_vseparator_new();
+#endif
+ gtk_box_pack_end(GTK_BOX(hbox), tmp, FALSE, FALSE, 10);
+
+ /* Suppress automatic show of the unused action area */
+#if GTK_CHECK_VERSION(3,0,0)
+# if !GTK_CHECK_VERSION(3,12,0)
+ gtk_widget_hide(gtk_dialog_get_action_area(GTK_DIALOG(frdp->dialog)));
+# endif
+#else
+ gtk_widget_hide(GTK_DIALOG(frdp->dialog)->action_area);
+#endif
+ gtk_widget_show_all(hbox);
+ gtk_widget_show(frdp->dialog);
+
+ vim_free(entry_text);
+ vim_free(conv_buffer);
+#undef CONV
+}
+
+ void
+gui_mch_find_dialog(exarg_T *eap)
+{
+ if (gui.in_use)
+ find_replace_dialog_create(eap->arg, FALSE);
+}
+
+ void
+gui_mch_replace_dialog(exarg_T *eap)
+{
+ if (gui.in_use)
+ find_replace_dialog_create(eap->arg, TRUE);
+}
+
+/*
+ * Callback for actions of the find and replace dialogs
+ */
+ static void
+find_replace_cb(GtkWidget *widget UNUSED, gpointer data)
+{
+ int flags;
+ char_u *find_text;
+ char_u *repl_text;
+ gboolean direction_down;
+ SharedFindReplace *sfr;
+
+ flags = (int)(long)data; /* avoid a lint warning here */
+
+ /* Get the search/replace strings from the dialog */
+ if (flags == FRD_FINDNEXT)
+ {
+ repl_text = NULL;
+ sfr = &find_widgets;
+ }
+ else
+ {
+ repl_text = (char_u *)gtk_entry_get_text(GTK_ENTRY(repl_widgets.with));
+ sfr = &repl_widgets;
+ }
+
+ find_text = (char_u *)gtk_entry_get_text(GTK_ENTRY(sfr->what));
+ direction_down = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(sfr->down));
+
+ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(sfr->wword)))
+ flags |= FRD_WHOLE_WORD;
+ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(sfr->mcase)))
+ flags |= FRD_MATCH_CASE;
+
+ repl_text = CONVERT_FROM_UTF8(repl_text);
+ find_text = CONVERT_FROM_UTF8(find_text);
+ gui_do_findrepl(flags, find_text, repl_text, direction_down);
+ CONVERT_FROM_UTF8_FREE(repl_text);
+ CONVERT_FROM_UTF8_FREE(find_text);
+}
+
+/* our usual callback function */
+ static void
+entry_activate_cb(GtkWidget *widget UNUSED, gpointer data)
+{
+ gtk_widget_grab_focus(GTK_WIDGET(data));
+}
+
+/*
+ * Syncing the find/replace dialogs on the fly is utterly useless crack,
+ * and causes nothing but problems. Please tell me a use case for which
+ * you'd need both a find dialog and a find/replace one at the same time,
+ * without being able to actually use them separately since they're syncing
+ * all the time. I don't think it's worthwhile to fix this nonsense,
+ * particularly evil incarnation of braindeadness, whatever; I'd much rather
+ * see it extinguished from this planet. Thanks for listening. Sorry.
+ */
+ static void
+entry_changed_cb(GtkWidget * entry, GtkWidget * dialog)
+{
+ const gchar *entry_text;
+ gboolean nonempty;
+
+ entry_text = gtk_entry_get_text(GTK_ENTRY(entry));
+
+ if (!entry_text)
+ return; /* shouldn't happen */
+
+ nonempty = (entry_text[0] != '\0');
+
+ if (dialog == find_widgets.dialog)
+ {
+ gtk_widget_set_sensitive(find_widgets.find, nonempty);
+ }
+
+ if (dialog == repl_widgets.dialog)
+ {
+ gtk_widget_set_sensitive(repl_widgets.find, nonempty);
+ gtk_widget_set_sensitive(repl_widgets.replace, nonempty);
+ gtk_widget_set_sensitive(repl_widgets.all, nonempty);
+ }
+}
+
+/*
+ * ":helpfind"
+ */
+ void
+ex_helpfind(exarg_T *eap UNUSED)
+{
+ /* This will fail when menus are not loaded. Well, it's only for
+ * backwards compatibility anyway. */
+ do_cmdline_cmd((char_u *)"emenu ToolBar.FindHelp");
+}
+
+#if defined(FEAT_BROWSE) || defined(PROTO)
+ static void
+recent_func_log_func(const gchar *log_domain UNUSED,
+ GLogLevelFlags log_level UNUSED,
+ const gchar *message UNUSED,
+ gpointer user_data UNUSED)
+{
+ /* We just want to suppress the warnings. */
+ /* http://bugzilla.gnome.org/show_bug.cgi?id=664587 */
+}
+#endif
diff --git a/src/gui_gtk_f.c b/src/gui_gtk_f.c
new file mode 100644
index 0000000..3f376c0
--- /dev/null
+++ b/src/gui_gtk_f.c
@@ -0,0 +1,896 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * (C) 1998,1999 by Marcin Dalecki <martin@dalecki.de>
+ *
+ * Support for GTK+ 2 was added by:
+ *
+ * (C) 2002,2003 Jason Hildebrand <jason@peaceworks.ca>
+ * Daniel Elstner <daniel.elstner@gmx.net>
+ *
+ * This is a special purpose container widget, which manages arbitrary
+ * children at arbitrary positions width arbitrary sizes. This finally puts
+ * an end on our resize problems with which we where struggling for such a
+ * long time.
+ *
+ * Support for GTK+ 3 was added by:
+ *
+ * 2016 Kazunobu Kuriyama <kazunobu.kuriyama@gmail.com>
+ */
+
+#include "vim.h"
+#include <gtk/gtk.h> /* without this it compiles, but gives errors at
+ runtime! */
+#include "gui_gtk_f.h"
+#if !GTK_CHECK_VERSION(3,0,0)
+# include <gtk/gtksignal.h>
+#endif
+#ifdef WIN3264
+# include <gdk/gdkwin32.h>
+#else
+# include <gdk/gdkx.h>
+#endif
+
+typedef struct _GtkFormChild GtkFormChild;
+
+struct _GtkFormChild
+{
+ GtkWidget *widget;
+ GdkWindow *window;
+ gint x; /* relative subwidget x position */
+ gint y; /* relative subwidget y position */
+ gint mapped;
+};
+
+
+static void gtk_form_class_init(GtkFormClass *klass);
+static void gtk_form_init(GtkForm *form);
+
+static void gtk_form_realize(GtkWidget *widget);
+static void gtk_form_unrealize(GtkWidget *widget);
+static void gtk_form_map(GtkWidget *widget);
+static void gtk_form_size_request(GtkWidget *widget,
+ GtkRequisition *requisition);
+#if GTK_CHECK_VERSION(3,0,0)
+static void gtk_form_get_preferred_width(GtkWidget *widget,
+ gint *minimal_width,
+ gint *natural_width);
+static void gtk_form_get_preferred_height(GtkWidget *widget,
+ gint *minimal_height,
+ gint *natural_height);
+#endif
+static void gtk_form_size_allocate(GtkWidget *widget,
+ GtkAllocation *allocation);
+#if GTK_CHECK_VERSION(3,0,0)
+static gboolean gtk_form_draw(GtkWidget *widget,
+ cairo_t *cr);
+#else
+static gint gtk_form_expose(GtkWidget *widget,
+ GdkEventExpose *event);
+#endif
+
+static void gtk_form_remove(GtkContainer *container,
+ GtkWidget *widget);
+static void gtk_form_forall(GtkContainer *container,
+ gboolean include_internals,
+ GtkCallback callback,
+ gpointer callback_data);
+
+static void gtk_form_attach_child_window(GtkForm *form,
+ GtkFormChild *child);
+static void gtk_form_realize_child(GtkForm *form,
+ GtkFormChild *child);
+static void gtk_form_position_child(GtkForm *form,
+ GtkFormChild *child,
+ gboolean force_allocate);
+static void gtk_form_position_children(GtkForm *form);
+
+static void gtk_form_send_configure(GtkForm *form);
+
+static void gtk_form_child_map(GtkWidget *widget, gpointer user_data);
+static void gtk_form_child_unmap(GtkWidget *widget, gpointer user_data);
+
+#if !GTK_CHECK_VERSION(3,0,0)
+static GtkWidgetClass *parent_class = NULL;
+#endif
+
+/* Public interface
+ */
+
+ GtkWidget *
+gtk_form_new(void)
+{
+ GtkForm *form;
+
+#if GTK_CHECK_VERSION(3,0,0)
+ form = g_object_new(GTK_TYPE_FORM, NULL);
+#else
+ form = gtk_type_new(gtk_form_get_type());
+#endif
+
+ return GTK_WIDGET(form);
+}
+
+ void
+gtk_form_put(GtkForm *form,
+ GtkWidget *child_widget,
+ gint x,
+ gint y)
+{
+ GtkFormChild *child;
+
+ g_return_if_fail(GTK_IS_FORM(form));
+
+ /* LINTED: avoid warning: conversion to 'unsigned long' */
+ child = g_new(GtkFormChild, 1);
+
+ child->widget = child_widget;
+ child->window = NULL;
+ child->x = x;
+ child->y = y;
+#if GTK_CHECK_VERSION(3,0,0)
+ gtk_widget_set_size_request(child->widget, -1, -1);
+#else
+ child->widget->requisition.width = 0;
+ child->widget->requisition.height = 0;
+#endif
+ child->mapped = FALSE;
+
+ form->children = g_list_append(form->children, child);
+
+ /* child->window must be created and attached to the widget _before_
+ * it has been realized, or else things will break with GTK2. Note
+ * that gtk_widget_set_parent() realizes the widget if it's visible
+ * and its parent is mapped.
+ */
+ if (gtk_widget_get_realized(GTK_WIDGET(form)))
+ gtk_form_attach_child_window(form, child);
+
+ gtk_widget_set_parent(child_widget, GTK_WIDGET(form));
+
+ if (gtk_widget_get_realized(GTK_WIDGET(form))
+ && !gtk_widget_get_realized(child_widget))
+ gtk_form_realize_child(form, child);
+
+ gtk_form_position_child(form, child, TRUE);
+}
+
+ void
+gtk_form_move(GtkForm *form,
+ GtkWidget *child_widget,
+ gint x,
+ gint y)
+{
+ GList *tmp_list;
+ GtkFormChild *child;
+
+ g_return_if_fail(GTK_IS_FORM(form));
+
+ for (tmp_list = form->children; tmp_list; tmp_list = tmp_list->next)
+ {
+ child = tmp_list->data;
+ if (child->widget == child_widget)
+ {
+ child->x = x;
+ child->y = y;
+
+ gtk_form_position_child(form, child, TRUE);
+ return;
+ }
+ }
+}
+
+ void
+gtk_form_freeze(GtkForm *form)
+{
+ g_return_if_fail(GTK_IS_FORM(form));
+
+ ++form->freeze_count;
+}
+
+ void
+gtk_form_thaw(GtkForm *form)
+{
+ g_return_if_fail(GTK_IS_FORM(form));
+
+ if (form->freeze_count)
+ {
+ if (!(--form->freeze_count))
+ {
+ gtk_form_position_children(form);
+ gtk_widget_queue_draw(GTK_WIDGET(form));
+ }
+ }
+}
+
+/* Basic Object handling procedures
+ */
+#if GTK_CHECK_VERSION(3,0,0)
+G_DEFINE_TYPE(GtkForm, gtk_form, GTK_TYPE_CONTAINER)
+#else
+ GtkType
+gtk_form_get_type(void)
+{
+ static GtkType form_type = 0;
+
+ if (!form_type)
+ {
+ GtkTypeInfo form_info;
+
+ vim_memset(&form_info, 0, sizeof(form_info));
+ form_info.type_name = "GtkForm";
+ form_info.object_size = sizeof(GtkForm);
+ form_info.class_size = sizeof(GtkFormClass);
+ form_info.class_init_func = (GtkClassInitFunc)gtk_form_class_init;
+ form_info.object_init_func = (GtkObjectInitFunc)gtk_form_init;
+
+ form_type = gtk_type_unique(GTK_TYPE_CONTAINER, &form_info);
+ }
+ return form_type;
+}
+#endif /* !GTK_CHECK_VERSION(3,0,0) */
+
+ static void
+gtk_form_class_init(GtkFormClass *klass)
+{
+ GtkWidgetClass *widget_class;
+ GtkContainerClass *container_class;
+
+ widget_class = (GtkWidgetClass *) klass;
+ container_class = (GtkContainerClass *) klass;
+
+#if !GTK_CHECK_VERSION(3,0,0)
+ parent_class = gtk_type_class(gtk_container_get_type());
+#endif
+
+ widget_class->realize = gtk_form_realize;
+ widget_class->unrealize = gtk_form_unrealize;
+ widget_class->map = gtk_form_map;
+#if GTK_CHECK_VERSION(3,0,0)
+ widget_class->get_preferred_width = gtk_form_get_preferred_width;
+ widget_class->get_preferred_height = gtk_form_get_preferred_height;
+#else
+ widget_class->size_request = gtk_form_size_request;
+#endif
+ widget_class->size_allocate = gtk_form_size_allocate;
+#if GTK_CHECK_VERSION(3,0,0)
+ widget_class->draw = gtk_form_draw;
+#else
+ widget_class->expose_event = gtk_form_expose;
+#endif
+
+ container_class->remove = gtk_form_remove;
+ container_class->forall = gtk_form_forall;
+}
+
+ static void
+gtk_form_init(GtkForm *form)
+{
+#if GTK_CHECK_VERSION(3,0,0)
+ gtk_widget_set_has_window(GTK_WIDGET(form), TRUE);
+#endif
+ form->children = NULL;
+ form->bin_window = NULL;
+ form->freeze_count = 0;
+}
+
+/*
+ * Widget methods
+ */
+
+ static void
+gtk_form_realize(GtkWidget *widget)
+{
+ GList *tmp_list;
+ GtkForm *form;
+ GdkWindowAttr attributes;
+ gint attributes_mask;
+ GtkAllocation allocation;
+
+ g_return_if_fail(GTK_IS_FORM(widget));
+
+ form = GTK_FORM(widget);
+ gtk_widget_set_realized(widget, TRUE);
+
+ gtk_widget_get_allocation(widget, &allocation);
+ attributes.window_type = GDK_WINDOW_CHILD;
+ attributes.x = allocation.x;
+ attributes.y = allocation.y;
+ attributes.width = allocation.width;
+ attributes.height = allocation.height;
+ attributes.wclass = GDK_INPUT_OUTPUT;
+ attributes.visual = gtk_widget_get_visual(widget);
+#if GTK_CHECK_VERSION(3,0,0)
+ attributes.event_mask = GDK_EXPOSURE_MASK;
+#else
+ attributes.colormap = gtk_widget_get_colormap(widget);
+ attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
+#endif
+
+#if GTK_CHECK_VERSION(3,0,0)
+ attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
+#else
+ attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
+#endif
+
+ gtk_widget_set_window(widget,
+ gdk_window_new(gtk_widget_get_parent_window(widget),
+ &attributes, attributes_mask));
+ gdk_window_set_user_data(gtk_widget_get_window(widget), widget);
+
+ attributes.x = 0;
+ attributes.y = 0;
+ attributes.event_mask = gtk_widget_get_events(widget);
+
+ form->bin_window = gdk_window_new(gtk_widget_get_window(widget),
+ &attributes, attributes_mask);
+ gdk_window_set_user_data(form->bin_window, widget);
+
+#if GTK_CHECK_VERSION(3,0,0)
+ {
+ GtkStyleContext * const sctx = gtk_widget_get_style_context(widget);
+
+ gtk_style_context_add_class(sctx, "gtk-form");
+ gtk_style_context_set_state(sctx, GTK_STATE_FLAG_NORMAL);
+# if !GTK_CHECK_VERSION(3,18,0)
+ gtk_style_context_set_background(sctx, gtk_widget_get_window(widget));
+ gtk_style_context_set_background(sctx, form->bin_window);
+# endif
+ }
+#else
+ widget->style = gtk_style_attach(widget->style, widget->window);
+ gtk_style_set_background(widget->style, widget->window, GTK_STATE_NORMAL);
+ gtk_style_set_background(widget->style, form->bin_window, GTK_STATE_NORMAL);
+#endif
+
+ for (tmp_list = form->children; tmp_list; tmp_list = tmp_list->next)
+ {
+ GtkFormChild *child = tmp_list->data;
+
+ gtk_form_attach_child_window(form, child);
+
+ if (gtk_widget_get_visible(child->widget))
+ gtk_form_realize_child(form, child);
+ }
+}
+
+
+/* After reading the documentation at
+ * http://developer.gnome.org/doc/API/2.0/gtk/gtk-changes-2-0.html
+ * I think it should be possible to remove this function when compiling
+ * against gtk-2.0. It doesn't seem to cause problems, though.
+ *
+ * Well, I reckon at least the gdk_window_show(form->bin_window)
+ * is necessary. GtkForm is anything but a usual container widget.
+ */
+ static void
+gtk_form_map(GtkWidget *widget)
+{
+ GList *tmp_list;
+ GtkForm *form;
+
+ g_return_if_fail(GTK_IS_FORM(widget));
+
+ form = GTK_FORM(widget);
+
+ gtk_widget_set_mapped(widget, TRUE);
+
+ gdk_window_show(gtk_widget_get_window(widget));
+ gdk_window_show(form->bin_window);
+
+ for (tmp_list = form->children; tmp_list; tmp_list = tmp_list->next)
+ {
+ GtkFormChild *child = tmp_list->data;
+
+ if (gtk_widget_get_visible(child->widget)
+ && !gtk_widget_get_mapped(child->widget))
+ gtk_widget_map(child->widget);
+ }
+}
+
+ static void
+gtk_form_unrealize(GtkWidget *widget)
+{
+ GList *tmp_list;
+ GtkForm *form;
+
+ g_return_if_fail(GTK_IS_FORM(widget));
+
+ form = GTK_FORM(widget);
+
+ tmp_list = form->children;
+
+ gdk_window_set_user_data(form->bin_window, NULL);
+ gdk_window_destroy(form->bin_window);
+ form->bin_window = NULL;
+
+ while (tmp_list)
+ {
+ GtkFormChild *child = tmp_list->data;
+
+ if (child->window != NULL)
+ {
+ g_signal_handlers_disconnect_by_func(G_OBJECT(child->widget),
+ FUNC2GENERIC(gtk_form_child_map),
+ child);
+ g_signal_handlers_disconnect_by_func(G_OBJECT(child->widget),
+ FUNC2GENERIC(gtk_form_child_unmap),
+ child);
+
+ gdk_window_set_user_data(child->window, NULL);
+ gdk_window_destroy(child->window);
+
+ child->window = NULL;
+ }
+
+ tmp_list = tmp_list->next;
+ }
+
+#if GTK_CHECK_VERSION(3,0,0)
+ if (GTK_WIDGET_CLASS (gtk_form_parent_class)->unrealize)
+ (* GTK_WIDGET_CLASS (gtk_form_parent_class)->unrealize) (widget);
+#else
+ if (GTK_WIDGET_CLASS (parent_class)->unrealize)
+ (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
+#endif
+}
+
+ static void
+gtk_form_size_request(GtkWidget *widget, GtkRequisition *requisition)
+{
+ g_return_if_fail(GTK_IS_FORM(widget));
+ g_return_if_fail(requisition != NULL);
+
+ requisition->width = 1;
+ requisition->height = 1;
+}
+
+#if GTK_CHECK_VERSION(3,0,0)
+ static void
+gtk_form_get_preferred_width(GtkWidget *widget,
+ gint *minimal_width,
+ gint *natural_width)
+{
+ GtkRequisition requisition;
+
+ gtk_form_size_request(widget, &requisition);
+
+ *minimal_width = requisition.width;
+ *natural_width = requisition.width;
+}
+
+ static void
+gtk_form_get_preferred_height(GtkWidget *widget,
+ gint *minimal_height,
+ gint *natural_height)
+{
+ GtkRequisition requisition;
+
+ gtk_form_size_request(widget, &requisition);
+
+ *minimal_height = requisition.height;
+ *natural_height = requisition.height;
+}
+#endif /* GTK_CHECK_VERSION(3,0,0) */
+
+ static void
+gtk_form_size_allocate(GtkWidget *widget, GtkAllocation *allocation)
+{
+ GList *tmp_list;
+ GtkForm *form;
+ gboolean need_reposition;
+ GtkAllocation cur_alloc;
+
+ g_return_if_fail(GTK_IS_FORM(widget));
+
+ gtk_widget_get_allocation(widget, &cur_alloc);
+
+ if (cur_alloc.x == allocation->x
+ && cur_alloc.y == allocation->y
+ && cur_alloc.width == allocation->width
+ && cur_alloc.height == allocation->height)
+ return;
+
+ need_reposition = cur_alloc.width != allocation->width
+ || cur_alloc.height != allocation->height;
+ form = GTK_FORM(widget);
+
+ if (need_reposition)
+ {
+ tmp_list = form->children;
+
+ while (tmp_list)
+ {
+ GtkFormChild *child = tmp_list->data;
+ gtk_form_position_child(form, child, TRUE);
+
+ tmp_list = tmp_list->next;
+ }
+ }
+
+ if (gtk_widget_get_realized(widget))
+ {
+ gdk_window_move_resize(gtk_widget_get_window(widget),
+ allocation->x, allocation->y,
+ allocation->width, allocation->height);
+ gdk_window_move_resize(GTK_FORM(widget)->bin_window,
+ 0, 0,
+ allocation->width, allocation->height);
+ }
+ gtk_widget_set_allocation(widget, allocation);
+ if (need_reposition)
+ gtk_form_send_configure(form);
+}
+
+#if GTK_CHECK_VERSION(3,0,0)
+ static void
+gtk_form_render_background(GtkWidget *widget, cairo_t *cr)
+{
+ gtk_render_background(gtk_widget_get_style_context(widget), cr,
+ 0, 0,
+ gtk_widget_get_allocated_width(widget),
+ gtk_widget_get_allocated_height(widget));
+}
+
+ static gboolean
+gtk_form_draw(GtkWidget *widget, cairo_t *cr)
+{
+ GList *tmp_list = NULL;
+ GtkForm *form = NULL;
+
+ g_return_val_if_fail(GTK_IS_FORM(widget), FALSE);
+
+ gtk_form_render_background(widget, cr);
+
+ form = GTK_FORM(widget);
+ for (tmp_list = form->children; tmp_list; tmp_list = tmp_list->next)
+ {
+ GtkFormChild * const formchild = tmp_list->data;
+
+ if (!gtk_widget_get_has_window(formchild->widget) &&
+ gtk_cairo_should_draw_window(cr, formchild->window))
+ {
+ /* To get gtk_widget_draw() to work, it is required to call
+ * gtk_widget_size_allocate() in advance with a well-posed
+ * allocation for a given child widget in order to set a
+ * certain private GtkWidget variable, called
+ * widget->priv->alloc_need, to the proper value; othewise,
+ * gtk_widget_draw() fails and the relevant scrollbar won't
+ * appear on the screen.
+ *
+ * Calling gtk_form_position_child() like this is one of ways
+ * to make sure of that. */
+ gtk_form_position_child(form, formchild, TRUE);
+
+ gtk_form_render_background(formchild->widget, cr);
+ }
+ }
+
+ return GTK_WIDGET_CLASS(gtk_form_parent_class)->draw(widget, cr);
+}
+#else /* !GTK_CHECK_VERSION(3,0,0) */
+ static gint
+gtk_form_expose(GtkWidget *widget, GdkEventExpose *event)
+{
+ GList *tmp_list;
+ GtkForm *form;
+
+ g_return_val_if_fail(GTK_IS_FORM(widget), FALSE);
+
+ form = GTK_FORM(widget);
+
+ if (event->window == form->bin_window)
+ return FALSE;
+
+ for (tmp_list = form->children; tmp_list; tmp_list = tmp_list->next)
+ gtk_container_propagate_expose(GTK_CONTAINER(widget),
+ GTK_WIDGET(((GtkFormChild *)tmp_list->data)->widget),
+ event);
+
+ return FALSE;
+}
+#endif /* !GTK_CHECK_VERSION(3,0,0) */
+
+/* Container method
+ */
+ static void
+gtk_form_remove(GtkContainer *container, GtkWidget *widget)
+{
+ GList *tmp_list;
+ GtkForm *form;
+ GtkFormChild *child = NULL; /* init for gcc */
+
+ g_return_if_fail(GTK_IS_FORM(container));
+
+ form = GTK_FORM(container);
+
+ tmp_list = form->children;
+ while (tmp_list)
+ {
+ child = tmp_list->data;
+ if (child->widget == widget)
+ break;
+ tmp_list = tmp_list->next;
+ }
+
+ if (tmp_list)
+ {
+#if GTK_CHECK_VERSION(3,0,0)
+ const gboolean was_visible = gtk_widget_get_visible(widget);
+#endif
+ if (child->window)
+ {
+ g_signal_handlers_disconnect_by_func(G_OBJECT(child->widget),
+ FUNC2GENERIC(&gtk_form_child_map), child);
+ g_signal_handlers_disconnect_by_func(G_OBJECT(child->widget),
+ FUNC2GENERIC(&gtk_form_child_unmap), child);
+
+ /* FIXME: This will cause problems for reparenting NO_WINDOW
+ * widgets out of a GtkForm
+ */
+ gdk_window_set_user_data(child->window, NULL);
+ gdk_window_destroy(child->window);
+ }
+ gtk_widget_unparent(widget);
+#if GTK_CHECK_VERSION(3,0,0)
+ if (was_visible)
+ gtk_widget_queue_resize(GTK_WIDGET(container));
+#endif
+ form->children = g_list_remove_link(form->children, tmp_list);
+ g_list_free_1(tmp_list);
+ g_free(child);
+ }
+}
+
+ static void
+gtk_form_forall(GtkContainer *container,
+ gboolean include_internals UNUSED,
+ GtkCallback callback,
+ gpointer callback_data)
+{
+ GtkForm *form;
+ GtkFormChild *child;
+ GList *tmp_list;
+
+ g_return_if_fail(GTK_IS_FORM(container));
+ g_return_if_fail(callback != NULL);
+
+ form = GTK_FORM(container);
+
+ tmp_list = form->children;
+ while (tmp_list)
+ {
+ child = tmp_list->data;
+ tmp_list = tmp_list->next;
+
+ (*callback) (child->widget, callback_data);
+ }
+}
+
+/* Operations on children
+ */
+
+ static void
+gtk_form_attach_child_window(GtkForm *form, GtkFormChild *child)
+{
+ if (child->window != NULL)
+ return; /* been there, done that */
+
+ if (!gtk_widget_get_has_window(child->widget))
+ {
+ GtkWidget *widget;
+ GdkWindowAttr attributes;
+ gint attributes_mask;
+ GtkRequisition requisition;
+
+ widget = GTK_WIDGET(form);
+
+#if GTK_CHECK_VERSION(3,0,0)
+ gtk_widget_get_preferred_size(child->widget, &requisition, NULL);
+#else
+ requisition = child->widget->requisition;
+#endif
+ attributes.window_type = GDK_WINDOW_CHILD;
+ attributes.x = child->x;
+ attributes.y = child->y;
+ attributes.width = requisition.width;
+ attributes.height = requisition.height;
+ attributes.wclass = GDK_INPUT_OUTPUT;
+ attributes.visual = gtk_widget_get_visual(widget);
+#if !GTK_CHECK_VERSION(3,0,0)
+ attributes.colormap = gtk_widget_get_colormap(widget);
+#endif
+ attributes.event_mask = GDK_EXPOSURE_MASK;
+
+#if GTK_CHECK_VERSION(3,0,0)
+ attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
+#else
+ attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
+#endif
+ child->window = gdk_window_new(form->bin_window,
+ &attributes, attributes_mask);
+ gdk_window_set_user_data(child->window, widget);
+
+#if GTK_CHECK_VERSION(3,0,0)
+ {
+ GtkStyleContext * const sctx = gtk_widget_get_style_context(widget);
+
+ gtk_style_context_set_state(sctx, GTK_STATE_FLAG_NORMAL);
+# if !GTK_CHECK_VERSION(3,18,0)
+ gtk_style_context_set_background(sctx, child->window);
+# endif
+ }
+#else
+ gtk_style_set_background(widget->style,
+ child->window,
+ GTK_STATE_NORMAL);
+#endif
+
+ gtk_widget_set_parent_window(child->widget, child->window);
+ /*
+ * Install signal handlers to map/unmap child->window
+ * alongside with the actual widget.
+ */
+ g_signal_connect(G_OBJECT(child->widget), "map",
+ G_CALLBACK(&gtk_form_child_map), child);
+ g_signal_connect(G_OBJECT(child->widget), "unmap",
+ G_CALLBACK(&gtk_form_child_unmap), child);
+ }
+ else if (!gtk_widget_get_realized(child->widget))
+ {
+ gtk_widget_set_parent_window(child->widget, form->bin_window);
+ }
+}
+
+ static void
+gtk_form_realize_child(GtkForm *form, GtkFormChild *child)
+{
+ gtk_form_attach_child_window(form, child);
+ gtk_widget_realize(child->widget);
+}
+
+ static void
+gtk_form_position_child(GtkForm *form, GtkFormChild *child,
+ gboolean force_allocate)
+{
+ gint x;
+ gint y;
+
+ x = child->x;
+ y = child->y;
+
+ if ((x >= G_MINSHORT) && (x <= G_MAXSHORT) &&
+ (y >= G_MINSHORT) && (y <= G_MAXSHORT))
+ {
+ if (!child->mapped)
+ {
+ if (gtk_widget_get_mapped(GTK_WIDGET(form))
+ && gtk_widget_get_visible(child->widget))
+ {
+ if (!gtk_widget_get_mapped(child->widget))
+ gtk_widget_map(child->widget);
+
+ child->mapped = TRUE;
+ force_allocate = TRUE;
+ }
+ }
+
+ if (force_allocate)
+ {
+ GtkAllocation allocation;
+ GtkRequisition requisition;
+
+#if GTK_CHECK_VERSION(3,0,0)
+ gtk_widget_get_preferred_size(child->widget, &requisition, NULL);
+#else
+ requisition = child->widget->requisition;
+#endif
+
+ if (!gtk_widget_get_has_window(child->widget))
+ {
+ if (child->window)
+ {
+ gdk_window_move_resize(child->window,
+ x, y,
+ requisition.width,
+ requisition.height);
+ }
+
+ allocation.x = 0;
+ allocation.y = 0;
+ }
+ else
+ {
+ allocation.x = x;
+ allocation.y = y;
+ }
+
+ allocation.width = requisition.width;
+ allocation.height = requisition.height;
+
+ gtk_widget_size_allocate(child->widget, &allocation);
+ }
+ }
+ else
+ {
+ if (child->mapped)
+ {
+ child->mapped = FALSE;
+
+ if (gtk_widget_get_mapped(child->widget))
+ gtk_widget_unmap(child->widget);
+ }
+ }
+}
+
+ static void
+gtk_form_position_children(GtkForm *form)
+{
+ GList *tmp_list;
+
+ for (tmp_list = form->children; tmp_list; tmp_list = tmp_list->next)
+ gtk_form_position_child(form, tmp_list->data, FALSE);
+}
+
+ void
+gtk_form_move_resize(GtkForm *form, GtkWidget *widget,
+ gint x, gint y, gint w, gint h)
+{
+#if GTK_CHECK_VERSION(3,0,0)
+ gtk_widget_set_size_request(widget, w, h);
+#else
+ widget->requisition.width = w;
+ widget->requisition.height = h;
+#endif
+
+ gtk_form_move(form, widget, x, y);
+}
+
+ static void
+gtk_form_send_configure(GtkForm *form)
+{
+ GtkWidget *widget;
+ GdkEventConfigure event;
+ GtkAllocation allocation;
+
+ widget = GTK_WIDGET(form);
+
+ gtk_widget_get_allocation(widget, &allocation);
+ event.type = GDK_CONFIGURE;
+ event.window = gtk_widget_get_window(widget);
+ event.x = allocation.x;
+ event.y = allocation.y;
+ event.width = allocation.width;
+ event.height = allocation.height;
+
+ gtk_main_do_event((GdkEvent*)&event);
+}
+
+ static void
+gtk_form_child_map(GtkWidget *widget UNUSED, gpointer user_data)
+{
+ GtkFormChild *child;
+
+ child = (GtkFormChild *)user_data;
+
+ child->mapped = TRUE;
+ gdk_window_show(child->window);
+}
+
+ static void
+gtk_form_child_unmap(GtkWidget *widget UNUSED, gpointer user_data)
+{
+ GtkFormChild *child;
+
+ child = (GtkFormChild *)user_data;
+
+ child->mapped = FALSE;
+ gdk_window_hide(child->window);
+}
diff --git a/src/gui_gtk_f.h b/src/gui_gtk_f.h
new file mode 100644
index 0000000..be7693a
--- /dev/null
+++ b/src/gui_gtk_f.h
@@ -0,0 +1,85 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * Do ":help uganda" in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ */
+
+#ifndef __GTK_FORM_H__
+#define __GTK_FORM_H__
+
+#ifdef USE_GTK3
+#include <gtk/gtk.h>
+#else
+#include <gdk/gdk.h>
+#include <gtk/gtkcontainer.h>
+#endif
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GTK_TYPE_FORM (gtk_form_get_type ())
+#ifdef USE_GTK3
+#define GTK_FORM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GTK_TYPE_FORM, GtkForm))
+#define GTK_FORM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GTK_TYPE_FORM, GtkFormClass))
+#define GTK_IS_FORM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GTK_TYPE_FORM))
+#define GTK_IS_FORM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GTK_TYPE_FORM))
+#else
+#define GTK_FORM(obj) (GTK_CHECK_CAST ((obj), GTK_TYPE_FORM, GtkForm))
+#define GTK_FORM_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GTK_TYPE_FORM, GtkFormClass))
+#define GTK_IS_FORM(obj) (GTK_CHECK_TYPE ((obj), GTK_TYPE_FORM))
+#define GTK_IS_FORM_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GTK_TYPE_FORM))
+#endif
+
+
+typedef struct _GtkForm GtkForm;
+typedef struct _GtkFormClass GtkFormClass;
+
+struct _GtkForm
+{
+ GtkContainer container;
+
+ GList *children;
+ GdkWindow *bin_window;
+ gint freeze_count;
+};
+
+struct _GtkFormClass
+{
+ GtkContainerClass parent_class;
+};
+
+#ifdef USE_GTK3
+GType gtk_form_get_type(void);
+#else
+GtkType gtk_form_get_type(void);
+#endif
+
+GtkWidget *gtk_form_new(void);
+
+void gtk_form_put(GtkForm * form, GtkWidget * widget,
+ gint x, gint y);
+
+void gtk_form_move(GtkForm *form, GtkWidget * widget,
+ gint x, gint y);
+
+void gtk_form_move_resize(GtkForm * form, GtkWidget * widget,
+ gint x, gint y,
+ gint w, gint h);
+
+/* These disable and enable moving and repainting respectively. If you
+ * want to update the layout's offsets but do not want it to repaint
+ * itself, you should use these functions.
+ */
+
+void gtk_form_freeze(GtkForm *form);
+void gtk_form_thaw(GtkForm *form);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __GTK_FORM_H__ */
diff --git a/src/gui_gtk_res.xml b/src/gui_gtk_res.xml
new file mode 100644
index 0000000..d6c7a59
--- /dev/null
+++ b/src/gui_gtk_res.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<gresources>
+ <gresource prefix="/org/vim/gui/icon">
+ <file>stock_vim_build_tags.png</file>
+ <file>stock_vim_find_help.png</file>
+ <file>stock_vim_save_all.png</file>
+ <file>stock_vim_session_load.png</file>
+ <file>stock_vim_session_new.png</file>
+ <file>stock_vim_session_save.png</file>
+ <file>stock_vim_shell.png</file>
+ <file>stock_vim_window_maximize.png</file>
+ <file>stock_vim_window_maximize_width.png</file>
+ <file>stock_vim_window_minimize.png</file>
+ <file>stock_vim_window_minimize_width.png</file>
+ <file>stock_vim_window_split.png</file>
+ <file>stock_vim_window_split_vertical.png</file>
+ </gresource>
+</gresources>
diff --git a/src/gui_gtk_vms.h b/src/gui_gtk_vms.h
new file mode 100644
index 0000000..268c9f3
--- /dev/null
+++ b/src/gui_gtk_vms.h
@@ -0,0 +1,740 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * Do ":help uganda" in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ *
+ * File MOTIF_REDEFINES.H originally delivers together with
+ * OpenVMS Porting Library
+ * http://www.openvms.compaq.com/openvms/products/ips/porting.html
+ *
+ * This file has been modified for Vim development.
+ * Original file contains just defines that GTK for OpenVMS uses,
+ * but not all functions that DECW library has. Therefore it has been expanded
+ * with necessary defines for Vim on OpenVMS with GTK GUI.
+ *
+ * Zoltan Arpadffy <arpadffy@polarhome.com>
+ */
+
+/*
+ *************************************************************************
+ * *
+ * Copyright 2000 Compaq Computer Corporation *
+ * *
+ * COMPAQ Registered in U.S. Patent and Trademark Office. *
+ * *
+ *************************************************************************
+ * IMPORTANT: Carefully read the License Terms below before *
+ * proceeding. By use of these materials you agree to these terms. *
+ * If you do not agree to these terms, you may not use this software or *
+ * the accompanying documentation. *
+ *************************************************************************
+ * LICENSE TERMS *
+ * 1. GRANT *
+ * Compaq Computer Corporation ("COMPAQ") grants you the right to use, *
+ * modify, and distribute the following source code (the "Software") *
+ * on any number of computers. You may use the Software as part of *
+ * creating a software program or product intended for commercial or *
+ * non-commercial distribution in machine-readable source code, binary, *
+ * or executable formats. You may distribute the Software as *
+ * machine-readable source code provided this license is not removed *
+ * from the Software and any modifications are conspicuously indicated. *
+ * 2. COPYRIGHT *
+ * The Software is owned by COMPAQ and its suppliers and is protected by *
+ * copyright laws and international treaties. Your use of the Software *
+ * and associated documentation is subject to the applicable copyright *
+ * laws and the express rights and restrictions of these terms. *
+ * 3. RESTRICTIONS *
+ * You may not remove any copyright, trademark, or other proprietary *
+ * notices from the Software or the associated documentation. *
+ * You are responsible for compliance with all applicable export or *
+ * re-export control laws and regulations if you export the Software. *
+ * This license is governed by and is to be construed under the laws *
+ * of the State of Texas. *
+ * *
+ * DISCLAIMER OF WARRANTY AND LIABILITY *
+ * Compaq shall not be liable for technical or editorial errors or *
+ * omissions contained herein. The information contained herein is *
+ * subject to change without notice. *
+ * *
+ * THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. *
+ * THE ENTIRE RISK ARISING OUT OF THE USE OF THIS SOFTWARE REMAINS WITH *
+ * RECIPIENT. IN NO EVENT SHALL COMPAQ BE LIABLE FOR ANY DIRECT, *
+ * CONSEQUENTIAL, INCIDENTAL, SPECIAL, PUNITIVE OR OTHER DAMAGES *
+ * WHATSOEVER (INCLUDING WITHOUT LIMITATION DAMAGES FOR LOSS OF BUSINESS *
+ * PROFITS, BUSINESS INTERRUPTION, OR LOSS OF BUSINESS INFORMATION), *
+ * EVEN IF COMPAQ HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES *
+ * AND WHETHER IN AN ACTION OF CONTRACT OR TORT INCLUDING NEGLIGENCE. *
+ * *
+ * If you have any questions concerning this license, please contact: *
+ * Compaq Computer Corporation, Software Business Practices, ZKO1-2/D22, *
+ * 110 Spit Brook Road, Nashua, NH. 03062-2698. *
+ * *
+ *************************************************************************
+ */
+
+/* INTRINSIC.H omits proto if XtFree is defined */
+/* VMS_BEGIN_C_PLUS_PLUS */
+extern void XtFree(char*);
+extern void XTFREE(char*);
+/* VMS_END_C_PLUS_PLUS */
+
+#define _XRegisterFilterByType _XREGISTERFILTERBYTYPE
+
+#define XAllocClassHint XALLOCCLASSHINT
+#define XAllocColor XALLOCCOLOR
+#define XAllocColorCells XALLOCCOLORCELLS
+#define XAllocSizeHints XALLOCSIZEHINTS
+#define XAllocWMHints XALLOCWMHINTS
+#define XAutoRepeatOff XAUTOREPEATOFF
+#define XAutoRepeatOn XAUTOREPEATON
+#define XBaseFontNameListOfFontSet XBASEFONTNAMELISTOFFONTSET
+#define XBell XBELL
+#define XBitmapPad XBITMAPPAD
+#define XChangeActivePointerGrab XCHANGEACTIVEPOINTERGRAB
+#define XChangeGC XCHANGEGC
+#define XChangeProperty XCHANGEPROPERTY
+#define XChangeWindowAttributes XCHANGEWINDOWATTRIBUTES
+#define XCheckIfEvent XCHECKIFEVENT
+#define XCheckMaskEvent XCHECKMASKEVENT
+#define XCheckTypedEvent XCHECKTYPEDEVENT
+#define XCheckTypedWindowEvent XCHECKTYPEDWINDOWEVENT
+#define XCheckWindowEvent XCHECKWINDOWEVENT
+#define XClearArea XCLEARAREA
+#define XClearWindow XCLEARWINDOW
+#define XClipBox XCLIPBOX
+#define XCloseDisplay XCLOSEDISPLAY
+#define XCloseIM XCLOSEIM
+#define XConfigureWindow XCONFIGUREWINDOW
+#define XConvertSelection XCONVERTSELECTION
+#define XCopyArea XCOPYAREA
+#define XCopyGC XCOPYGC
+#define XCopyPlane XCOPYPLANE
+#define XCreateBitmapFromData XCREATEBITMAPFROMDATA
+#define XCreateColormap XCREATECOLORMAP
+#define XCreateFontCursor XCREATEFONTCURSOR
+#define XCreateFontSet XCREATEFONTSET
+#define XCreateGC XCREATEGC
+#define XCreateIC XCREATEIC
+#define XCreateImage XCREATEIMAGE
+#define XCreatePixmap XCREATEPIXMAP
+#define XCreatePixmapCursor XCREATEPIXMAPCURSOR
+#define XCreatePixmapFromBitmapData XCREATEPIXMAPFROMBITMAPDATA
+#define XCreateRegion XCREATEREGION
+#define XCreateSimpleWindow XCREATESIMPLEWINDOW
+#define XCreateWindow XCREATEWINDOW
+#define XDefaultRootWindow XDEFAULTROOTWINDOW
+#define XDefaultScreenOfDisplay XDEFAULTSCREENOFDISPLAY
+#define XDefineCursor XDEFINECURSOR
+#define XDeleteProperty XDELETEPROPERTY
+#define XDestroyIC XDESTROYIC
+#define XDestroyRegion XDESTROYREGION
+#define XDestroyWindow XDESTROYWINDOW
+#define XDisplayName XDISPLAYNAME
+#define XDisplayOfScreen XDISPLAYOFSCREEN
+#define XDisplayString XDISPLAYSTRING
+#define XDrawArc XDRAWARC
+#define XDrawImageString XDRAWIMAGESTRING
+#define XDrawImageString16 XDRAWIMAGESTRING16
+#define XDrawLine XDRAWLINE
+#define XDrawLines XDRAWLINES
+#define XDrawPoint XDRAWPOINT
+#define XDrawPoints XDRAWPOINTS
+#define XDrawRectangle XDRAWRECTANGLE
+#define XDrawSegments XDRAWSEGMENTS
+#define XDrawString XDRAWSTRING
+#define XDrawString16 XDRAWSTRING16
+#define XEmptyRegion XEMPTYREGION
+#define XEqualRegion XEQUALREGION
+#define XEventsQueued XEVENTSQUEUED
+#define XExtentsOfFontSet XEXTENTSOFFONTSET
+#define XFetchBuffer XFETCHBUFFER
+#define XFillArc XFILLARC
+#define XFillPolygon XFILLPOLYGON
+#define XFillRectangle XFILLRECTANGLE
+#define XFillRectangles XFILLRECTANGLES
+#define XFilterEvent XFILTEREVENT
+#define XFlush XFLUSH
+#define XFontsOfFontSet XFONTSOFFONTSET
+#define XFree XFREE
+#define XFreeColormap XFREECOLORMAP
+#define XFreeColors XFREECOLORS
+#define XFreeCursor XFREECURSOR
+#define XFreeFont XFREEFONT
+#define XFreeFontInfo XFREEFONTINFO
+#define XFreeFontNames XFREEFONTNAMES
+#define XFreeFontSet XFREEFONTSET
+#define XFreeGC XFREEGC
+#define XFreeModifiermap XFREEMODIFIERMAP
+#define XFreePixmap XFREEPIXMAP
+#define XFreeStringList XFREESTRINGLIST
+#define XGetAtomName XGETATOMNAME
+#define XGetDefault XGETDEFAULT
+#define XGetErrorDatabaseText XGETERRORDATABASETEXT
+#define XGetErrorText XGETERRORTEXT
+#define XGetFontProperty XGETFONTPROPERTY
+#define XGetGCValues XGETGCVALUES
+#define XGetGeometry XGETGEOMETRY
+#define XGetIconSizes XGETICONSIZES
+#define XGetICValues XGETICVALUES
+#define XGetIMValues XGETIMVALUES
+#define XGetImage XGETIMAGE
+#define XGetKeyboardControl XGETKEYBOARDCONTROL
+#define XGetModifierMapping XGETMODIFIERMAPPING
+#define XGetMotionEvents XGETMOTIONEVENTS
+#define XGetNormalHints XGETNORMALHINTS
+#define XGetSelectionOwner XGETSELECTIONOWNER
+#define XGetSubImage XGETSUBIMAGE
+#define XGetVisualInfo XGETVISUALINFO
+#define XGetWMColormapWindows XGETWMCOLORMAPWINDOWS
+#define XGetWMIconName XGETWMICONNAME
+#define XGetWMProtocols XGETWMPROTOCOLS
+#define XGetWMHints XGETWMHINTS
+#define XGetWMName XGETWMNAME
+#define XGetWMNormalHints XGETWMNORMALHINTS
+#define XGetWindowAttributes XGETWINDOWATTRIBUTES
+#define XGetWindowProperty XGETWINDOWPROPERTY
+#define XGrabKeyboard XGRABKEYBOARD
+#define XGrabPointer XGRABPOINTER
+#define XGrabServer XGRABSERVER
+#define XHeightOfScreen XHEIGHTOFSCREEN
+#define XIconifyWindow XICONIFYWINDOW
+#define XIfEvent XIFEVENT
+#define XInternAtom XINTERNATOM
+#define XIntersectRegion XINTERSECTREGION
+#define XKeycodeToKeysym XKEYCODETOKEYSYM
+#define XKeysymToKeycode XKEYSYMTOKEYCODE
+#define XKeysymToString XKEYSYMTOSTRING
+#define XListFonts XLISTFONTS
+#define XListFontsWithInfo XLISTFONTSWITHINFO
+#define XListPixmapFormats XLISTPIXMAPFORMATS
+#define XListProperties XLISTPROPERTIES
+#define XLoadQueryFont XLOADQUERYFONT
+#define XLookupString XLOOKUPSTRING
+#define XLowerWindow XLOWERWINDOW
+#define XMapRaised XMAPRAISED
+#define XMapWindow XMAPWINDOW
+#define XMatchVisualInfo XMATCHVISUALINFO
+#define XMoveResizeWindow XMOVERESIZEWINDOW
+#define XMoveWindow XMOVEWINDOW
+#define XNextEvent XNEXTEVENT
+#define XOffsetRegion XOFFSETREGION
+#define XOpenDisplay XOPENDISPLAY
+#define XOpenIM XOPENIM
+#define XParseColor XPARSECOLOR
+#define XParseGeometry XPARSEGEOMETRY
+#define XPeekEvent XPEEKEVENT
+#define XPending XPENDING
+#define XPointInRegion XPOINTINREGION
+#define XPolygonRegion XPOLYGONREGION
+#define XPutBackEvent XPUTBACKEVENT
+#define XPutImage XPUTIMAGE
+#define XRootWindow XROOTWINDOW
+#define XQueryColor XQUERYCOLOR
+#define XQueryColors XQUERYCOLORS
+#define XQueryExtension XQUERYEXTENSION
+#define XQueryPointer XQUERYPOINTER
+#define XQueryTree XQUERYTREE
+#define XRaiseWindow XRAISEWINDOW
+#define XReconfigureWMWindow XRECONFIGUREWMWINDOW
+#define XRectInRegion XRECTINREGION
+#define XRefreshKeyboardMapping XREFRESHKEYBOARDMAPPING
+#define XReparentWindow XREPARENTWINDOW
+#define XResizeWindow XRESIZEWINDOW
+#define XRestackWindows XRESTACKWINDOWS
+#define XRootWindowOfScreen XROOTWINDOWOFSCREEN
+#define XScreenNumberOfScreen XSCREENNUMBEROFSCREEN
+#define XSelectAsyncEvent XSELECTASYNCEVENT
+#define XSelectAsyncInput XSELECTASYNCINPUT
+#define XSelectInput XSELECTINPUT
+#define XSendEvent XSENDEVENT
+#define XServerVendor XSERVERVENDOR
+#define XSetBackground XSETBACKGROUND
+#define XSetClassHint XSETCLASSHINT
+#define XSetClipMask XSETCLIPMASK
+#define XSetClipOrigin XSETCLIPORIGIN
+#define XSetClipRectangles XSETCLIPRECTANGLES
+#define XSetCloseDownMode XSETCLOSEDOWNMODE
+#define XSetCommand XSETCOMMAND
+#define XSetDashes XSETDASHES
+#define XSetErrorHandler XSETERRORHANDLER
+#define XSetFillStyle XSETFILLSTYLE
+#define XSetFont XSETFONT
+#define XSetForeground XSETFOREGROUND
+#define XSetFunction XSETFUNCTION
+#define XSetGraphicsExposures XSETGRAPHICSEXPOSURES
+#define XSetICFocus XSETICFOCUS
+#define XSetICValues XSETICVALUES
+#define XSetIOErrorHandler XSETIOERRORHANDLER
+#define XSetInputFocus XSETINPUTFOCUS
+#define XSetLineAttributes XSETLINEATTRIBUTES
+#define XSetLocaleModifiers XSETLOCALEMODIFIERS
+#define XSetNormalHints XSETNORMALHINTS
+#define XSetRegion XSETREGION
+#define XSetSelectionOwner XSETSELECTIONOWNER
+#define XSetStipple XSETSTIPPLE
+#define XSetSubwindowMode XSETSUBWINDOWMODE
+#define XSetTSOrigin XSETTSORIGIN
+#define XSetTile XSETTILE
+#define XSetTransientForHint XSETTRANSIENTFORHINT
+#define XSetWMColormapWindows XSETWMCOLORMAPWINDOWS
+#define XSetWMHints XSETWMHINTS
+#define XSetWMIconName XSETWMICONNAME
+#define XSetWMName XSETWMNAME
+#define XSetWMNormalHints XSETWMNORMALHINTS
+#define XSetWMProperties XSETWMPROPERTIES
+#define XSetWMProtocols XSETWMPROTOCOLS
+#define XSetWindowBackground XSETWINDOWBACKGROUND
+#define XSetWindowBackgroundPixmap XSETWINDOWBACKGROUNDPIXMAP
+#define XSetWindowColormap XSETWINDOWCOLORMAP
+#define XShapeCombineMask XSHAPECOMBINEMASK
+#define XShapeCombineRectangles XSHAPECOMBINERECTANGLES
+#define XShapeGetRectangles XSHAPEGETRECTANGLES
+#define XShrinkRegion XSHRINKREGION
+#define XStoreBuffer XSTOREBUFFER
+#define XStoreColor XSTORECOLOR
+#define XStoreColors XSTORECOLORS
+#define XStoreName XSTORENAME
+#define XStringToKeysym XSTRINGTOKEYSYM
+#define XSubtractRegion XSUBTRACTREGION
+#define XSupportsLocale XSUPPORTSLOCALE
+#define XSync XSYNC
+#define XSynchronize XSYNCHRONIZE
+#define XTextExtents XTEXTEXTENTS
+#define XTextExtents16 XTEXTEXTENTS16
+#define XTextWidth XTEXTWIDTH
+#define XTextWidth16 XTEXTWIDTH16
+#define XTranslateCoordinates XTRANSLATECOORDINATES
+#define XUndefineCursor XUNDEFINECURSOR
+#define XUngrabKeyboard XUNGRABKEYBOARD
+#define XUngrabPointer XUNGRABPOINTER
+#define XUngrabServer XUNGRABSERVER
+#define XUnionRectWithRegion XUNIONRECTWITHREGION
+#define XUnionRegion XUNIONREGION
+#define XUnmapWindow XUNMAPWINDOW
+#define _XUnregisterFilter _XUNREGISTERFILTER
+#define XUnsetICFocus XUNSETICFOCUS
+#define XVaCreateNestedList XVACREATENESTEDLIST
+#define XVisualIDFromVisual XVISUALIDFROMVISUAL
+#define XWarpPointer XWARPPOINTER
+#define XWidthOfScreen XWIDTHOFSCREEN
+#define XWindowEvent XWINDOWEVENT
+#define XWithdrawWindow XWITHDRAWWINDOW
+#define XXorRegion XXORREGION
+#define XmAddProtocolCallback XMADDPROTOCOLCALLBACK
+#define XmAddProtocols XMADDPROTOCOLS
+#define XmChangeColor XMCHANGECOLOR
+#define XmClipboardCopy XMCLIPBOARDCOPY
+#define XmClipboardEndCopy XMCLIPBOARDENDCOPY
+#define XmClipboardInquireLength XMCLIPBOARDINQUIRELENGTH
+#define XmClipboardLock XMCLIPBOARDLOCK
+#define XmClipboardRetrieve XMCLIPBOARDRETRIEVE
+#define XmClipboardStartCopy XMCLIPBOARDSTARTCOPY
+#define XmClipboardUnlock XMCLIPBOARDUNLOCK
+#define XmCreateArrowButton XMCREATEARROWBUTTON
+#define XmCreateArrowButtonGadget XMCREATEARROWBUTTONGADGET
+#define XmCreateCascadeButton XMCREATECASCADEBUTTON
+#define XmCreateDialogShell XMCREATEDIALOGSHELL
+#define XmCreateDragIcon XMCREATEDRAGICON
+#define XmCreateDrawingArea XMCREATEDRAWINGAREA
+#define XmCreateDrawnButton XMCREATEDRAWNBUTTON
+#define XmCreateFileSelectionBox XMCREATEFILESELECTIONBOX
+#define XmCreateFileSelectionDialog XMCREATEFILESELECTIONDIALOG
+#define XmCreateForm XMCREATEFORM
+#define XmCreateFormDialog XMCREATEFORMDIALOG
+#define XmCreateFrame XMCREATEFRAME
+#define XmCreateInformationDialog XMCREATEINFORMATIONDIALOG
+#define XmCreateLabelGadget XMCREATELABELGADGET
+#define XmCreateMainWindow XMCREATEMAINWINDOW
+#define XmCreateMenuBar XMCREATEMENUBAR
+#define XmCreateMessageBox XMCREATEMESSAGEBOX
+#define XmCreateMessageDialog XMCREATEMESSAGEDIALOG
+#define XmCreateOptionMenu XMCREATEOPTIONMENU
+#define XmCreatePanedWindow XMCREATEPANEDWINDOW
+#define XmCreatePopupMenu XMCREATEPOPUPMENU
+#define XmCreatePromptDialog XMCREATEPROMPTDIALOG
+#define XmCreatePulldownMenu XMCREATEPULLDOWNMENU
+#define XmCreatePushButton XMCREATEPUSHBUTTON
+#define XmCreatePushButtonGadget XMCREATEPUSHBUTTONGADGET
+#define XmCreateQuestionDialog XMCREATEQUESTIONDIALOG
+#define XmCreateRadioBox XMCREATERADIOBOX
+#define XmCreateRowColumn XMCREATEROWCOLUMN
+#define XmCreateScale XMCREATESCALE
+#define XmCreateScrollBar XMCREATESCROLLBAR
+#define XmCreateScrolledList XMCREATESCROLLEDLIST
+#define XmCreateScrolledText XMCREATESCROLLEDTEXT
+#define XmCreateScrolledWindow XMCREATESCROLLEDWINDOW
+#define XmCreateSelectionDialog XMCREATESELECTIONDIALOG
+#define XmCreateSeparator XMCREATESEPARATOR
+#define XmCreateSeparatorGadget XMCREATESEPARATORGADGET
+#define XmCreateTemplateDialog XMCREATETEMPLATEDIALOG
+#define XmCreateText XMCREATETEXT
+#define XmCreateTextField XMCREATETEXTFIELD
+#define XmCreateToggleButton XMCREATETOGGLEBUTTON
+#define XmCreateToggleButtonGadget XMCREATETOGGLEBUTTONGADGET
+#define XmDragStart XMDRAGSTART
+#define XmDropSiteRegister XMDROPSITEREGISTER
+#define XmDropSiteUnregister XMDROPSITEUNREGISTER
+#define XmDropSiteUpdate XMDROPSITEUPDATE
+#define XmDropTransferStart XMDROPTRANSFERSTART
+#define XmFileSelectionBoxGetChild XMFILESELECTIONBOXGETCHILD
+#define XmFileSelectionDoSearch XMFILESELECTIONDOSEARCH
+#define XmFontListAppendEntry XMFONTLISTAPPENDENTRY
+#define XmFontListCopy XMFONTLISTCOPY
+#define XmFontListCreate XMFONTLISTCREATE
+#define XmFontListEntryCreate XMFONTLISTENTRYCREATE
+#define XmFontListEntryFree XMFONTLISTENTRYFREE
+#define XmFontListEntryGetFont XMFONTLISTENTRYGETFONT
+#define XmFontListEntryGetTag XMFONTLISTENTRYGETTAG
+#define XmFontListEntryLoad XMFONTLISTENTRYLOAD
+#define XmFontListFree XMFONTLISTFREE
+#define XmFontListFreeFontContext XMFONTLISTFREEFONTCONTEXT
+#define XmFontListGetNextFont XMFONTLISTGETNEXTFONT
+#define XmFontListInitFontContext XMFONTLISTINITFONTCONTEXT
+#define XmFontListNextEntry XMFONTLISTNEXTENTRY
+#define XmGetColors XMGETCOLORS
+#define XmGetFocusWidget XMGETFOCUSWIDGET
+#define XmGetMenuCursor XMGETMENUCURSOR
+#define XmGetPixmapByDepth XMGETPIXMAPBYDEPTH
+#define XmGetTearOffControl XMGETTEAROFFCONTROL
+#define XmGetXmDisplay XMGETXMDISPLAY
+#define XmImMbLookupString XMIMMBLOOKUPSTRING
+#define XmImRegister XMIMREGISTER
+#define XmImSetFocusValues XMIMSETFOCUSVALUES
+#define XmImSetValues XMIMSETVALUES
+#define XmImUnregister XMIMUNREGISTER
+#define XmImUnsetFocus XMIMUNSETFOCUS
+#define XmInternAtom XMINTERNATOM
+#define XmIsMotifWMRunning XMISMOTIFWMRUNNING
+#define XmListAddItem XMLISTADDITEM
+#define XmListAddItemUnselected XMLISTADDITEMUNSELECTED
+#define XmListAddItemsUnselected XMLISTADDITEMSUNSELECTED
+#define XmListDeleteAllItems XMLISTDELETEALLITEMS
+#define XmListDeleteItemsPos XMLISTDELETEITEMSPOS
+#define XmListDeletePos XMLISTDELETEPOS
+#define XmListDeselectAllItems XMLISTDESELECTALLITEMS
+#define XmListDeselectPos XMLISTDESELECTPOS
+#define XmListGetKbdItemPos XMLISTGETKBDITEMPOS
+#define XmListGetMatchPos XMLISTGETMATCHPOS
+#define XmListGetSelectedPos XMLISTGETSELECTEDPOS
+#define XmListPosSelected XMLISTPOSSELECTED
+#define XmListSelectItem XMLISTSELECTITEM
+#define XmListSelectPos XMLISTSELECTPOS
+#define XmListSetBottomPos XMLISTSETBOTTOMPOS
+#define XmListSetItem XMLISTSETITEM
+#define XmListSetKbdItemPos XMLISTSETKBDITEMPOS
+#define XmListSetPos XMLISTSETPOS
+#define XmMainWindowSetAreas XMMAINWINDOWSETAREAS
+#define XmMenuPosition XMMENUPOSITION
+#define XmMessageBoxGetChild XMMESSAGEBOXGETCHILD
+#define XmOptionButtonGadget XMOPTIONBUTTONGADGET
+#define XmOptionLabelGadget XMOPTIONLABELGADGET
+#define XmProcessTraversal XMPROCESSTRAVERSAL
+#define XmQmotif XMQMOTIF
+#define XmRemoveProtocolCallback XMREMOVEPROTOCOLCALLBACK
+#define XmRepTypeGetId XMREPTYPEGETID
+#define XmRepTypeGetRecord XMREPTYPEGETRECORD
+#define XmRepTypeRegister XMREPTYPEREGISTER
+#define XmRepTypeValidValue XMREPTYPEVALIDVALUE
+#define XmScrollBarSetValues XMSCROLLBARSETVALUES
+#define XmScrolledWindowSetAreas XMSCROLLEDWINDOWSETAREAS
+#define XmSelectionBoxGetChild XMSELECTIONBOXGETCHILD
+#define XmStringByteCompare XMSTRINGBYTECOMPARE
+#define XmStringCompare XMSTRINGCOMPARE
+#define XmStringConcat XMSTRINGCONCAT
+#define XmStringCopy XMSTRINGCOPY
+#define XmStringCreate XMSTRINGCREATE
+#define XmStringCreateLocalized XMSTRINGCREATELOCALIZED
+#define XmStringCreateLtoR XMSTRINGCREATELTOR
+#define XmStringCreateSimple XMSTRINGCREATESIMPLE
+#define XmStringDraw XMSTRINGDRAW
+#define XmStringDrawUnderline XMSTRINGDRAWUNDERLINE
+#define XmStringExtent XMSTRINGEXTENT
+#define XmStringFree XMSTRINGFREE
+#define XmStringFreeContext XMSTRINGFREECONTEXT
+#define XmStringGetLtoR XMSTRINGGETLTOR
+#define XmStringGetNextComponent XMSTRINGGETNEXTCOMPONENT
+#define XmStringGetNextSegment XMSTRINGGETNEXTSEGMENT
+#define XmStringInitContext XMSTRINGINITCONTEXT
+#define XmStringLength XMSTRINGLENGTH
+#define XmStringLtoRCreate XMSTRINGLTORCREATE
+#define XmStringNConcat XMSTRINGNCONCAT
+#define XmStringSegmentCreate XMSTRINGSEGMENTCREATE
+#define XmStringWidth XMSTRINGWIDTH
+#define XmTextClearSelection XMTEXTCLEARSELECTION
+#define XmTextFieldGetEditable XMTEXTFIELDGETEDITABLE
+#define XmTextFieldGetInsertionPosition XMTEXTFIELDGETINSERTIONPOSITION
+#define XmTextFieldGetLastPosition XMTEXTFIELDGETLASTPOSITION
+#define XmTextFieldGetSelection XMTEXTFIELDGETSELECTION
+#define XmTextFieldGetString XMTEXTFIELDGETSTRING
+#define XmTextFieldInsert XMTEXTFIELDINSERT
+#define XmTextFieldRemove XMTEXTFIELDREMOVE
+#define XmTextFieldSetSelection XMTEXTFIELDSETSELECTION
+#define XmTextFieldSetString XMTEXTFIELDSETSTRING
+#define XmTextGetCursorPosition XMTEXTGETCURSORPOSITION
+#define XmTextGetInsertionPosition XMTEXTGETINSERTIONPOSITION
+#define XmTextGetLastPosition XMTEXTGETLASTPOSITION
+#define XmTextGetMaxLength XMTEXTGETMAXLENGTH
+#define XmTextGetSelection XMTEXTGETSELECTION
+#define XmTextGetSelectionPosition XMTEXTGETSELECTIONPOSITION
+#define XmTextGetString XMTEXTGETSTRING
+#define XmTextInsert XMTEXTINSERT
+#define XmTextRemove XMTEXTREMOVE
+#define XmTextReplace XMTEXTREPLACE
+#define XmTextSetCursorPosition XMTEXTSETCURSORPOSITION
+#define XmTextSetHighlight XMTEXTSETHIGHLIGHT
+#define XmTextSetInsertionPosition XMTEXTSETINSERTIONPOSITION
+#define XmTextSetSelection XMTEXTSETSELECTION
+#define XmTextSetString XMTEXTSETSTRING
+#define XmToggleButtonGadgetGetState XMTOGGLEBUTTONGADGETGETSTATE
+#define XmToggleButtonGadgetSetState XMTOGGLEBUTTONGADGETSETSTATE
+#define XmToggleButtonGetState XMTOGGLEBUTTONGETSTATE
+#define XmToggleButtonSetState XMTOGGLEBUTTONSETSTATE
+#define XmUpdateDisplay XMUPDATEDISPLAY
+#define XmVaCreateSimpleRadioBox XMVACREATESIMPLERADIOBOX
+#define XmbDrawString XMBDRAWSTRING
+#define XmbLookupString XMBLOOKUPSTRING
+#define XmbResetIC XMBRESETIC
+#define XmbSetWMProperties XMBSETWMPROPERTIES
+#define XmbTextEscapement XMBTEXTESCAPEMENT
+#define XmbTextExtents XMBTEXTEXTENTS
+#define XmbTextListToTextProperty XMBTEXTLISTTOTEXTPROPERTY
+#define XmbTextPropertyToTextList XMBTEXTPROPERTYTOTEXTLIST
+#define XmuClientWindow XMUCLIENTWINDOW
+#define XmuPrintDefaultErrorMessage XMUPRINTDEFAULTERRORMESSAGE
+#define XrmGetDatabase XRMGETDATABASE
+#define XrmGetResource XRMGETRESOURCE
+#define XrmPutStringResource XRMPUTSTRINGRESOURCE
+#define XrmQuarkToString XRMQUARKTOSTRING
+#define XrmStringToQuark XRMSTRINGTOQUARK
+#define XtAddCallback XTADDCALLBACK
+#define XtAddCallbacks XTADDCALLBACKS
+#define XtAddEventHandler XTADDEVENTHANDLER
+#define XtAddGrab XTADDGRAB
+#define XtAllocateGC XTALLOCATEGC
+#define XtAppAddActions XTAPPADDACTIONS
+#define XtAppAddInput XTAPPADDINPUT
+#define XtAppAddTimeOut XTAPPADDTIMEOUT
+#define XtAppCreateShell XTAPPCREATESHELL
+#define XtAppInitialize XTAPPINITIALIZE
+#define XtAppNextEvent XTAPPNEXTEVENT
+#define XtAppPeekEvent XTAPPPEEKEVENT
+#define XtAppPending XTAPPPENDING
+#define XtAppProcessEvent XTAPPPROCESSEVENT
+#define XtAppSetErrorHandler XTAPPSETERRORHANDLER
+#define XtAppSetFallbackResources XTAPPSETFALLBACKRESOURCES
+#define XtAppSetWarningHandler XTAPPSETWARNINGHANDLER
+#define XtAppSetWarningMsgHandler XTAPPSETWARNINGMSGHANDLER
+#define XtAppWarning XTAPPWARNING
+#define XtCallActionProc XTCALLACTIONPROC
+#define XtCallCallbackList XTCALLCALLBACKLIST
+#define XtCallCallbacks XTCALLCALLBACKS
+#define XtConfigureWidget XTCONFIGUREWIDGET
+#define XtConvertAndStore XTCONVERTANDSTORE
+#define XtCreateApplicationContext XTCREATEAPPLICATIONCONTEXT
+#define XtCreateManagedWidget XTCREATEMANAGEDWIDGET
+#define XtCreatePopupShell XTCREATEPOPUPSHELL
+#define XtCreateWidget XTCREATEWIDGET
+#define XtDatabase XTDATABASE
+#define XtDestroyWidget XTDESTROYWIDGET
+#define XtDisownSelection XTDISOWNSELECTION
+#define XtDispatchEvent XTDISPATCHEVENT
+#define XtDisplayOfObject XTDISPLAYOFOBJECT
+#define XtDisplayStringConvWarning XTDISPLAYSTRINGCONVWARNING
+#define XtDisplayToApplicationContext XTDISPLAYTOAPPLICATIONCONTEXT
+#define XtFree XTFREE
+#define XtGetActionKeysym XTGETACTIONKEYSYM
+#define XtGetActionList XTGETACTIONLIST
+#define XtGetApplicationNameAndClass XTGETAPPLICATIONNAMEANDCLASS
+#define XtGetApplicationResources XTGETAPPLICATIONRESOURCES
+#define XtGetGC XTGETGC
+#define XtGetMultiClickTime XTGETMULTICLICKTIME
+#define XtGetSelectionValue XTGETSELECTIONVALUE
+#define XtGetSelectionValues XTGETSELECTIONVALUES
+#define XtGetSubresources XTGETSUBRESOURCES
+#define XtGetValues XTGETVALUES
+#define XtGrabKeyboard XTGRABKEYBOARD
+#define XtGrabPointer XTGRABPOINTER
+#define XtHasCallbacks XTHASCALLBACKS
+#define XtInitializeWidgetClass XTINITIALIZEWIDGETCLASS
+#define XtInsertEventHandler XTINSERTEVENTHANDLER
+#define XtIsManaged XTISMANAGED
+#define XtIsObject XTISOBJECT
+#define XtIsSensitive XTISSENSITIVE
+#define XtIsSubclass XTISSUBCLASS
+#define XtLastTimestampProcessed XTLASTTIMESTAMPPROCESSED
+#define XtMakeGeometryRequest XTMAKEGEOMETRYREQUEST
+#define XtMakeResizeRequest XTMAKERESIZEREQUEST
+#define XtMalloc XTMALLOC
+#define XtManageChild XTMANAGECHILD
+#define XtManageChildren XTMANAGECHILDREN
+#define XtMergeArgLists XTMERGEARGLISTS
+#define XtMoveWidget XTMOVEWIDGET
+#define XtName XTNAME
+#define XtNameToWidget XTNAMETOWIDGET
+#define XtOpenDisplay XTOPENDISPLAY
+#define XtOverrideTranslations XTOVERRIDETRANSLATIONS
+#define XtOwnSelection XTOWNSELECTION
+#define XtParent XTPARENT
+#define XtParseTranslationTable XTPARSETRANSLATIONTABLE
+#define XtPopdown XTPOPDOWN
+#define XtPopup XTPOPUP
+#define XtQueryGeometry XTQUERYGEOMETRY
+#define XtRealizeWidget XTREALIZEWIDGET
+#define XtRealloc XTREALLOC
+#define XtReleaseGC XTRELEASEGC
+#define XtRemoveAllCallbacks XTREMOVEALLCALLBACKS
+#define XtRemoveCallback XTREMOVECALLBACK
+#define XtRemoveEventHandler XTREMOVEEVENTHANDLER
+#define XtRemoveGrab XTREMOVEGRAB
+#define XtRemoveInput XTREMOVEINPUT
+#define XtRemoveTimeOut XTREMOVETIMEOUT
+#define XtResizeWidget XTRESIZEWIDGET
+#define XtResolvePathname XTRESOLVEPATHNAME
+#define XtSetKeyboardFocus XTSETKEYBOARDFOCUS
+#define XtSetMappedWhenManaged XTSETMAPPEDWHENMANAGED
+#define XtSetSensitive XTSETSENSITIVE
+#define XtSetTypeConverter XTSETTYPECONVERTER
+#define XtSetValues XTSETVALUES
+#define XtShellStrings XTSHELLSTRINGS
+#define XtStrings XTSTRINGS
+#define XtToolkitInitialize XTTOOLKITINITIALIZE
+#define XtTranslateCoords XTTRANSLATECOORDS
+#define XtTranslateKeycode XTTRANSLATEKEYCODE
+#define XtUngrabKeyboard XTUNGRABKEYBOARD
+#define XtUngrabPointer XTUNGRABPOINTER
+#define XtUnmanageChild XTUNMANAGECHILD
+#define XtUnmanageChildren XTUNMANAGECHILDREN
+#define XtUnrealizeWidget XTUNREALIZEWIDGET
+#define XtVaAppCreateShell XTVAAPPCREATESHELL
+#define XtVaCreateManagedWidget XTVACREATEMANAGEDWIDGET
+#define XtVaCreatePopupShell XTVACREATEPOPUPSHELL
+#define XtVaCreateWidget XTVACREATEWIDGET
+#define XtVaGetValues XTVAGETVALUES
+#define XtVaSetValues XTVASETVALUES
+#define XtWarning XTWARNING
+#define XtWidgetToApplicationContext XTWIDGETTOAPPLICATIONCONTEXT
+#define XtWindow XTWINDOW
+#define XtWindowOfObject XTWINDOWOFOBJECT
+#define XtWindowToWidget XTWINDOWTOWIDGET
+#define XwcDrawString XWCDRAWSTRING
+#define XwcFreeStringList XWCFREESTRINGLIST
+#define XwcTextEscapement XWCTEXTESCAPEMENT
+#define XwcTextExtents XWCTEXTEXTENTS
+#define XwcTextListToTextProperty XWCTEXTLISTTOTEXTPROPERTY
+#define XwcTextPropertyToTextList XWCTEXTPROPERTYTOTEXTLIST
+#define _XmBottomShadowColorDefault _XMBOTTOMSHADOWCOLORDEFAULT
+#define _XmClearBorder _XMCLEARBORDER
+#define _XmConfigureObject _XMCONFIGUREOBJECT
+#define _XmDestroyParentCallback _XMDESTROYPARENTCALLBACK
+#define _XmDrawArrow _XMDRAWARROW
+#define _XmDrawShadows _XMDRAWSHADOWS
+#define _XmFontListGetDefaultFont _XMFONTLISTGETDEFAULTFONT
+#define _XmFromHorizontalPixels _XMFROMHORIZONTALPIXELS
+#define _XmFromVerticalPixels _XMFROMVERTICALPIXELS
+#define _XmGetClassExtensionPtr _XMGETCLASSEXTENSIONPTR
+#define _XmGetDefaultFontList _XMGETDEFAULTFONTLIST
+#define _XmGetTextualDragIcon _XMGETTEXTUALDRAGICON
+#define _XmGetWidgetExtData _XMGETWIDGETEXTDATA
+#define _XmGrabKeyboard _XMGRABKEYBOARD
+#define _XmGrabPointer _XMGRABPOINTER
+#define _XmInheritClass _XMINHERITCLASS
+#define _XmInputInGadget _XMINPUTINGADGET
+#define _XmMakeGeometryRequest _XMMAKEGEOMETRYREQUEST
+#define _XmMenuPopDown _XMMENUPOPDOWN
+#define _XmMoveObject _XMMOVEOBJECT
+#define _XmNavigChangeManaged _XMNAVIGCHANGEMANAGED
+#define _XmOSBuildFileList _XMOSBUILDFILELIST
+#define _XmOSFileCompare _XMOSFILECOMPARE
+#define _XmOSFindPatternPart _XMOSFINDPATTERNPART
+#define _XmOSQualifyFileSpec _XMOSQUALIFYFILESPEC
+#define _XmPostPopupMenu _XMPOSTPOPUPMENU
+#define _XmPrimitiveEnter _XMPRIMITIVEENTER
+#define _XmPrimitiveLeave _XMPRIMITIVELEAVE
+#define _XmRedisplayGadgets _XMREDISPLAYGADGETS
+#define _XmShellIsExclusive _XMSHELLISEXCLUSIVE
+#define _XmStringDraw _XMSTRINGDRAW
+#define _XmStringGetTextConcat _XMSTRINGGETTEXTCONCAT
+#define _XmStrings _XMSTRINGS
+#define _XmToHorizontalPixels _XMTOHORIZONTALPIXELS
+#define _XmToVerticalPixels _XMTOVERTICALPIXELS
+#define _XmTopShadowColorDefault _XMTOPSHADOWCOLORDEFAULT
+#define _Xm_fastPtr _XM_FASTPTR
+#define _XtCheckSubclassFlag _XTCHECKSUBCLASSFLAG
+#define _XtInherit _XTINHERIT
+#define _XtInheritTranslations _XTINHERITTRANSLATIONS
+#define applicationShellWidgetClass APPLICATIONSHELLWIDGETCLASS
+#define compositeWidgetClass COMPOSITEWIDGETCLASS
+#define overrideShellWidgetClass OVERRIDESHELLWIDGETCLASS
+#define shellWidgetClass SHELLWIDGETCLASS
+#define topLevelShellClassRec TOPLEVELSHELLCLASSREC
+#define topLevelShellWidgetClass TOPLEVELSHELLWIDGETCLASS
+#define transientShellWidgetClass TRANSIENTSHELLWIDGETCLASS
+#define vendorShellClassRec VENDORSHELLCLASSREC
+#define vendorShellWidgetClass VENDORSHELLWIDGETCLASS
+#define wmShellWidgetClass WMSHELLWIDGETCLASS
+#define xmArrowButtonWidgetClass XMARROWBUTTONWIDGETCLASS
+#define xmCascadeButtonClassRec XMCASCADEBUTTONCLASSREC
+#define xmCascadeButtonGadgetClass XMCASCADEBUTTONGADGETCLASS
+#define xmCascadeButtonWidgetClass XMCASCADEBUTTONWIDGETCLASS
+#define xmDialogShellWidgetClass XMDIALOGSHELLWIDGETCLASS
+#define xmDrawingAreaWidgetClass XMDRAWINGAREAWIDGETCLASS
+#define xmDrawnButtonWidgetClass XMDRAWNBUTTONWIDGETCLASS
+#define xmFileSelectionBoxWidgetClass XMFILESELECTIONBOXWIDGETCLASS
+#define xmFormWidgetClass XMFORMWIDGETCLASS
+#define xmFrameWidgetClass XMFRAMEWIDGETCLASS
+#define xmGadgetClass XMGADGETCLASS
+#define xmLabelGadgetClass XMLABELGADGETCLASS
+#define xmLabelWidgetClass XMLABELWIDGETCLASS
+#define xmListWidgetClass XMLISTWIDGETCLASS
+#define xmMainWindowWidgetClass XMMAINWINDOWWIDGETCLASS
+#define xmManagerClassRec XMMANAGERCLASSREC
+#define xmManagerWidgetClass XMMANAGERWIDGETCLASS
+#define xmMenuShellWidgetClass XMMENUSHELLWIDGETCLASS
+#define xmMessageBoxWidgetClass XMMESSAGEBOXWIDGETCLASS
+#define xmPrimitiveClassRec XMPRIMITIVECLASSREC
+#define xmPrimitiveWidgetClass XMPRIMITIVEWIDGETCLASS
+#define xmPushButtonClassRec XMPUSHBUTTONCLASSREC
+#define xmPushButtonGadgetClass XMPUSHBUTTONGADGETCLASS
+#define xmPushButtonWidgetClass XMPUSHBUTTONWIDGETCLASS
+#define xmRowColumnWidgetClass XMROWCOLUMNWIDGETCLASS
+#define xmSashWidgetClass XMSASHWIDGETCLASS
+#define xmScrollBarWidgetClass XMSCROLLBARWIDGETCLASS
+#define xmScrolledWindowClassRec XMSCROLLEDWINDOWCLASSREC
+#define xmScrolledWindowWidgetClass XMSCROLLEDWINDOWWIDGETCLASS
+#define xmSeparatorGadgetClass XMSEPARATORGADGETCLASS
+#define xmSeparatorWidgetClass XMSEPARATORWIDGETCLASS
+#define xmTextFieldWidgetClass XMTEXTFIELDWIDGETCLASS
+#define xmTextWidgetClass XMTEXTWIDGETCLASS
+#define xmToggleButtonGadgetClass XMTOGGLEBUTTONGADGETCLASS
+#define xmToggleButtonWidgetClass XMTOGGLEBUTTONWIDGETCLASS
+
+/*
+** XtRegisterDrawable and XtUnregisterDrawable don't exist until R6.
+** So we have to fake it for R5 and earlier. It would be real nice to
+** include X11.h here and then test for R6 by checking
+** XlibSpecificationRelease. But including X11.h defines the symbol "None"
+** and there's Mozilla code in gfx/src/gtk that defines an enum element
+** named None. So for now hard code this is R5....
+*/
+#ifndef VMS_X11R6
+/* R5 or earlier */
+#define _XtRegisterWindow _XTREGISTERWINDOW
+#define _XtUnregisterWindow _XTUNREGISTERWINDOW
+/* original code is fixed so we don't need this now */
+#if 0
+#define XtRegisterDrawable(display,drawable,widget) \
+{ extern void _XtRegisterWindow(Window,Widget); \
+ _XtRegisterWindow(drawable,widget); \
+}
+#define XtUnregisterDrawable(display,drawable) \
+{ extern void _XtUnregisterWindow(Window,Widget); \
+ _XtUnregisterWindow(drawable,XtWindowToWidget(display,drawable)); \
+}
+#endif
+#else
+/* R6 or later */
+#define XtRegisterDrawable XTREGISTERDRAWABLE
+#define XtUnregisterDrawable XTUNREGISTERDRAWABLE
+#endif
diff --git a/src/gui_gtk_x11.c b/src/gui_gtk_x11.c
new file mode 100644
index 0000000..b76aacd
--- /dev/null
+++ b/src/gui_gtk_x11.c
@@ -0,0 +1,7162 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * Porting to GTK+ was done by:
+ *
+ * (C) 1998,1999,2000 by Marcin Dalecki <martin@dalecki.de>
+ *
+ * With GREAT support and continuous encouragements by Andy Kahn and of
+ * course Bram Moolenaar!
+ *
+ * Support for GTK+ 2 was added by:
+ *
+ * (C) 2002,2003 Jason Hildebrand <jason@peaceworks.ca>
+ * Daniel Elstner <daniel.elstner@gmx.net>
+ *
+ * Support for GTK+ 3 was added by:
+ *
+ * 2016 Kazunobu Kuriyama <kazunobu.kuriyama@gmail.com>
+ */
+
+#include "vim.h"
+#ifdef USE_GRESOURCE
+#include "auto/gui_gtk_gresources.h"
+#endif
+
+#ifdef FEAT_GUI_GNOME
+/* Gnome redefines _() and N_(). Grrr... */
+# ifdef _
+# undef _
+# endif
+# ifdef N_
+# undef N_
+# endif
+# ifdef textdomain
+# undef textdomain
+# endif
+# ifdef bindtextdomain
+# undef bindtextdomain
+# endif
+# ifdef bind_textdomain_codeset
+# undef bind_textdomain_codeset
+# endif
+# if defined(FEAT_GETTEXT) && !defined(ENABLE_NLS)
+# define ENABLE_NLS /* so the texts in the dialog boxes are translated */
+# endif
+# include <gnome.h>
+# include "version.h"
+/* missing prototype in bonobo-dock-item.h */
+extern void bonobo_dock_item_set_behavior(BonoboDockItem *dock_item, BonoboDockItemBehavior beh);
+#endif
+
+#if !defined(FEAT_GUI_GTK) && defined(PROTO)
+/* When generating prototypes we don't want syntax errors. */
+# define GdkAtom int
+# define GdkEventExpose int
+# define GdkEventFocus int
+# define GdkEventVisibility int
+# define GdkEventProperty int
+# define GtkContainer int
+# define GtkTargetEntry int
+# define GtkType int
+# define GtkWidget int
+# define gint int
+# define gpointer int
+# define guint int
+# define GdkEventKey int
+# define GdkEventSelection int
+# define GtkSelectionData int
+# define GdkEventMotion int
+# define GdkEventButton int
+# define GdkDragContext int
+# define GdkEventConfigure int
+# define GdkEventClient int
+#else
+# if GTK_CHECK_VERSION(3,0,0)
+# include <gdk/gdkkeysyms-compat.h>
+# include <gtk/gtkx.h>
+# else
+# include <gdk/gdkkeysyms.h>
+# endif
+# include <gdk/gdk.h>
+# ifdef WIN3264
+# include <gdk/gdkwin32.h>
+# else
+# include <gdk/gdkx.h>
+# endif
+# include <gtk/gtk.h>
+# include "gui_gtk_f.h"
+#endif
+
+#ifdef HAVE_X11_SUNKEYSYM_H
+# include <X11/Sunkeysym.h>
+#endif
+
+/*
+ * Easy-to-use macro for multihead support.
+ */
+#define GET_X_ATOM(atom) gdk_x11_atom_to_xatom_for_display( \
+ gtk_widget_get_display(gui.mainwin), atom)
+
+/* Selection type distinguishers */
+enum
+{
+ TARGET_TYPE_NONE,
+ TARGET_UTF8_STRING,
+ TARGET_STRING,
+ TARGET_COMPOUND_TEXT,
+ TARGET_HTML,
+ TARGET_TEXT,
+ TARGET_TEXT_URI_LIST,
+ TARGET_TEXT_PLAIN,
+ TARGET_VIM,
+ TARGET_VIMENC
+};
+
+/*
+ * Table of selection targets supported by Vim.
+ * Note: Order matters, preferred types should come first.
+ */
+static const GtkTargetEntry selection_targets[] =
+{
+ {VIMENC_ATOM_NAME, 0, TARGET_VIMENC},
+ {VIM_ATOM_NAME, 0, TARGET_VIM},
+ {"text/html", 0, TARGET_HTML},
+ {"UTF8_STRING", 0, TARGET_UTF8_STRING},
+ {"COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT},
+ {"TEXT", 0, TARGET_TEXT},
+ {"STRING", 0, TARGET_STRING}
+};
+#define N_SELECTION_TARGETS (sizeof(selection_targets) / sizeof(selection_targets[0]))
+
+#ifdef FEAT_DND
+/*
+ * Table of DnD targets supported by Vim.
+ * Note: Order matters, preferred types should come first.
+ */
+static const GtkTargetEntry dnd_targets[] =
+{
+ {"text/uri-list", 0, TARGET_TEXT_URI_LIST},
+ {"text/html", 0, TARGET_HTML},
+ {"UTF8_STRING", 0, TARGET_UTF8_STRING},
+ {"STRING", 0, TARGET_STRING},
+ {"text/plain", 0, TARGET_TEXT_PLAIN}
+};
+# define N_DND_TARGETS (sizeof(dnd_targets) / sizeof(dnd_targets[0]))
+#endif
+
+
+/*
+ * "Monospace" is a standard font alias that should be present
+ * on all proper Pango/fontconfig installations.
+ */
+# define DEFAULT_FONT "Monospace 10"
+
+#if !(defined(FEAT_GUI_GNOME) && defined(FEAT_SESSION))
+/*
+ * Atoms used to communicate save-yourself from the X11 session manager. There
+ * is no need to move them into the GUI struct, since they should be constant.
+ */
+static GdkAtom wm_protocols_atom = GDK_NONE;
+static GdkAtom save_yourself_atom = GDK_NONE;
+#endif
+
+/*
+ * Atoms used to control/reference X11 selections.
+ */
+static GdkAtom html_atom = GDK_NONE;
+static GdkAtom utf8_string_atom = GDK_NONE;
+static GdkAtom vim_atom = GDK_NONE; /* Vim's own special selection format */
+static GdkAtom vimenc_atom = GDK_NONE; /* Vim's extended selection format */
+
+/*
+ * Keycodes recognized by vim.
+ * NOTE: when changing this, the table in gui_x11.c probably needs the same
+ * change!
+ */
+static struct special_key
+{
+ guint key_sym;
+ char_u code0;
+ char_u code1;
+}
+const special_keys[] =
+{
+ {GDK_Up, 'k', 'u'},
+ {GDK_Down, 'k', 'd'},
+ {GDK_Left, 'k', 'l'},
+ {GDK_Right, 'k', 'r'},
+ {GDK_F1, 'k', '1'},
+ {GDK_F2, 'k', '2'},
+ {GDK_F3, 'k', '3'},
+ {GDK_F4, 'k', '4'},
+ {GDK_F5, 'k', '5'},
+ {GDK_F6, 'k', '6'},
+ {GDK_F7, 'k', '7'},
+ {GDK_F8, 'k', '8'},
+ {GDK_F9, 'k', '9'},
+ {GDK_F10, 'k', ';'},
+ {GDK_F11, 'F', '1'},
+ {GDK_F12, 'F', '2'},
+ {GDK_F13, 'F', '3'},
+ {GDK_F14, 'F', '4'},
+ {GDK_F15, 'F', '5'},
+ {GDK_F16, 'F', '6'},
+ {GDK_F17, 'F', '7'},
+ {GDK_F18, 'F', '8'},
+ {GDK_F19, 'F', '9'},
+ {GDK_F20, 'F', 'A'},
+ {GDK_F21, 'F', 'B'},
+ {GDK_Pause, 'F', 'B'}, /* Pause == F21 according to netbeans.txt */
+ {GDK_F22, 'F', 'C'},
+ {GDK_F23, 'F', 'D'},
+ {GDK_F24, 'F', 'E'},
+ {GDK_F25, 'F', 'F'},
+ {GDK_F26, 'F', 'G'},
+ {GDK_F27, 'F', 'H'},
+ {GDK_F28, 'F', 'I'},
+ {GDK_F29, 'F', 'J'},
+ {GDK_F30, 'F', 'K'},
+ {GDK_F31, 'F', 'L'},
+ {GDK_F32, 'F', 'M'},
+ {GDK_F33, 'F', 'N'},
+ {GDK_F34, 'F', 'O'},
+ {GDK_F35, 'F', 'P'},
+#ifdef SunXK_F36
+ {SunXK_F36, 'F', 'Q'},
+ {SunXK_F37, 'F', 'R'},
+#endif
+ {GDK_Help, '%', '1'},
+ {GDK_Undo, '&', '8'},
+ {GDK_BackSpace, 'k', 'b'},
+ {GDK_Insert, 'k', 'I'},
+ {GDK_Delete, 'k', 'D'},
+ {GDK_3270_BackTab, 'k', 'B'},
+ {GDK_Clear, 'k', 'C'},
+ {GDK_Home, 'k', 'h'},
+ {GDK_End, '@', '7'},
+ {GDK_Prior, 'k', 'P'},
+ {GDK_Next, 'k', 'N'},
+ {GDK_Print, '%', '9'},
+ /* Keypad keys: */
+ {GDK_KP_Left, 'k', 'l'},
+ {GDK_KP_Right, 'k', 'r'},
+ {GDK_KP_Up, 'k', 'u'},
+ {GDK_KP_Down, 'k', 'd'},
+ {GDK_KP_Insert, KS_EXTRA, (char_u)KE_KINS},
+ {GDK_KP_Delete, KS_EXTRA, (char_u)KE_KDEL},
+ {GDK_KP_Home, 'K', '1'},
+ {GDK_KP_End, 'K', '4'},
+ {GDK_KP_Prior, 'K', '3'}, /* page up */
+ {GDK_KP_Next, 'K', '5'}, /* page down */
+
+ {GDK_KP_Add, 'K', '6'},
+ {GDK_KP_Subtract, 'K', '7'},
+ {GDK_KP_Divide, 'K', '8'},
+ {GDK_KP_Multiply, 'K', '9'},
+ {GDK_KP_Enter, 'K', 'A'},
+ {GDK_KP_Decimal, 'K', 'B'},
+
+ {GDK_KP_0, 'K', 'C'},
+ {GDK_KP_1, 'K', 'D'},
+ {GDK_KP_2, 'K', 'E'},
+ {GDK_KP_3, 'K', 'F'},
+ {GDK_KP_4, 'K', 'G'},
+ {GDK_KP_5, 'K', 'H'},
+ {GDK_KP_6, 'K', 'I'},
+ {GDK_KP_7, 'K', 'J'},
+ {GDK_KP_8, 'K', 'K'},
+ {GDK_KP_9, 'K', 'L'},
+
+ /* End of list marker: */
+ {0, 0, 0}
+};
+
+/*
+ * Flags for command line options table below.
+ */
+#define ARG_FONT 1
+#define ARG_GEOMETRY 2
+#define ARG_REVERSE 3
+#define ARG_NOREVERSE 4
+#define ARG_BACKGROUND 5
+#define ARG_FOREGROUND 6
+#define ARG_ICONIC 7
+#define ARG_ROLE 8
+#define ARG_NETBEANS 9
+#define ARG_XRM 10 /* ignored */
+#define ARG_MENUFONT 11 /* ignored */
+#define ARG_INDEX_MASK 0x00ff
+#define ARG_HAS_VALUE 0x0100 /* a value is expected after the argument */
+#define ARG_NEEDS_GUI 0x0200 /* need to initialize the GUI for this */
+#define ARG_FOR_GTK 0x0400 /* argument is handled by GTK+ or GNOME */
+#define ARG_COMPAT_LONG 0x0800 /* accept -foo but substitute with --foo */
+#define ARG_KEEP 0x1000 /* don't remove argument from argv[] */
+
+/*
+ * This table holds all the X GUI command line options allowed. This includes
+ * the standard ones so that we can skip them when Vim is started without the
+ * GUI (but the GUI might start up later).
+ *
+ * When changing this, also update doc/gui_x11.txt and the usage message!!!
+ */
+typedef struct
+{
+ const char *name;
+ unsigned int flags;
+}
+cmdline_option_T;
+
+static const cmdline_option_T cmdline_options[] =
+{
+ /* We handle these options ourselves */
+ {"-fn", ARG_FONT|ARG_HAS_VALUE},
+ {"-font", ARG_FONT|ARG_HAS_VALUE},
+ {"-geom", ARG_GEOMETRY|ARG_HAS_VALUE},
+ {"-geometry", ARG_GEOMETRY|ARG_HAS_VALUE},
+ {"-rv", ARG_REVERSE},
+ {"-reverse", ARG_REVERSE},
+ {"+rv", ARG_NOREVERSE},
+ {"+reverse", ARG_NOREVERSE},
+ {"-bg", ARG_BACKGROUND|ARG_HAS_VALUE},
+ {"-background", ARG_BACKGROUND|ARG_HAS_VALUE},
+ {"-fg", ARG_FOREGROUND|ARG_HAS_VALUE},
+ {"-foreground", ARG_FOREGROUND|ARG_HAS_VALUE},
+ {"-iconic", ARG_ICONIC},
+ {"--role", ARG_ROLE|ARG_HAS_VALUE},
+#ifdef FEAT_NETBEANS_INTG
+ {"-nb", ARG_NETBEANS}, /* non-standard value format */
+ {"-xrm", ARG_XRM|ARG_HAS_VALUE}, /* not implemented */
+ {"-mf", ARG_MENUFONT|ARG_HAS_VALUE}, /* not implemented */
+ {"-menufont", ARG_MENUFONT|ARG_HAS_VALUE}, /* not implemented */
+#endif
+ /* Arguments handled by GTK (and GNOME) internally. */
+ {"--g-fatal-warnings", ARG_FOR_GTK},
+ {"--gdk-debug", ARG_FOR_GTK|ARG_HAS_VALUE},
+ {"--gdk-no-debug", ARG_FOR_GTK|ARG_HAS_VALUE},
+ {"--gtk-debug", ARG_FOR_GTK|ARG_HAS_VALUE},
+ {"--gtk-no-debug", ARG_FOR_GTK|ARG_HAS_VALUE},
+ {"--gtk-module", ARG_FOR_GTK|ARG_HAS_VALUE},
+ {"--sync", ARG_FOR_GTK},
+ {"--display", ARG_FOR_GTK|ARG_HAS_VALUE|ARG_COMPAT_LONG},
+ {"--name", ARG_FOR_GTK|ARG_HAS_VALUE|ARG_COMPAT_LONG},
+ {"--class", ARG_FOR_GTK|ARG_HAS_VALUE|ARG_COMPAT_LONG},
+ {"--screen", ARG_FOR_GTK|ARG_HAS_VALUE},
+ {"--gxid-host", ARG_FOR_GTK|ARG_HAS_VALUE},
+ {"--gxid-port", ARG_FOR_GTK|ARG_HAS_VALUE},
+#ifdef FEAT_GUI_GNOME
+ {"--load-modules", ARG_FOR_GTK|ARG_HAS_VALUE},
+ {"--sm-client-id", ARG_FOR_GTK|ARG_HAS_VALUE},
+ {"--sm-config-prefix", ARG_FOR_GTK|ARG_HAS_VALUE},
+ {"--sm-disable", ARG_FOR_GTK},
+ {"--oaf-ior-fd", ARG_FOR_GTK|ARG_HAS_VALUE},
+ {"--oaf-activate-iid", ARG_FOR_GTK|ARG_HAS_VALUE},
+ {"--oaf-private", ARG_FOR_GTK},
+ {"--enable-sound", ARG_FOR_GTK},
+ {"--disable-sound", ARG_FOR_GTK},
+ {"--espeaker", ARG_FOR_GTK|ARG_HAS_VALUE},
+ {"-?", ARG_FOR_GTK|ARG_NEEDS_GUI},
+ {"--help", ARG_FOR_GTK|ARG_NEEDS_GUI|ARG_KEEP},
+ {"--usage", ARG_FOR_GTK|ARG_NEEDS_GUI},
+# if 0 /* conflicts with Vim's own --version argument */
+ {"--version", ARG_FOR_GTK|ARG_NEEDS_GUI},
+# endif
+ {"--disable-crash-dialog", ARG_FOR_GTK},
+#endif
+ {NULL, 0}
+};
+
+static int gui_argc = 0;
+static char **gui_argv = NULL;
+
+static const char *role_argument = NULL;
+#if defined(FEAT_GUI_GNOME) && defined(FEAT_SESSION)
+static const char *restart_command = NULL;
+static char *abs_restart_command = NULL;
+#endif
+static int found_iconic_arg = FALSE;
+
+#ifdef FEAT_GUI_GNOME
+/*
+ * Can't use Gnome if --socketid given
+ */
+static int using_gnome = 0;
+#else
+# define using_gnome 0
+#endif
+
+/*
+ * 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)
+{
+ const cmdline_option_T *option;
+ int i = 0;
+ int len = 0;
+
+#if defined(FEAT_GUI_GNOME) && defined(FEAT_SESSION)
+ /*
+ * Determine the command used to invoke Vim, to be passed as restart
+ * command to the session manager. If argv[0] contains any directory
+ * components try building an absolute path, otherwise leave it as is.
+ */
+ restart_command = argv[0];
+
+ if (strchr(argv[0], G_DIR_SEPARATOR) != NULL)
+ {
+ char_u buf[MAXPATHL];
+
+ if (mch_FullName((char_u *)argv[0], buf, (int)sizeof(buf), TRUE) == OK)
+ {
+ abs_restart_command = (char *)vim_strsave(buf);
+ restart_command = abs_restart_command;
+ }
+ }
+#endif
+
+ /*
+ * Move all the entries in argv which are relevant to GTK+ and GNOME
+ * into gui_argv. Freed later in gui_mch_init().
+ */
+ gui_argc = 0;
+ gui_argv = (char **)alloc((unsigned)((*argc + 1) * sizeof(char *)));
+
+ g_return_if_fail(gui_argv != NULL);
+
+ gui_argv[gui_argc++] = argv[i++];
+
+ while (i < *argc)
+ {
+ /* Don't waste CPU cycles on non-option arguments. */
+ if (argv[i][0] != '-' && argv[i][0] != '+')
+ {
+ ++i;
+ continue;
+ }
+
+ /* Look for argv[i] in cmdline_options[] table. */
+ for (option = &cmdline_options[0]; option->name != NULL; ++option)
+ {
+ len = strlen(option->name);
+
+ if (strncmp(argv[i], option->name, len) == 0)
+ {
+ if (argv[i][len] == '\0')
+ break;
+ /* allow --foo=bar style */
+ if (argv[i][len] == '=' && (option->flags & ARG_HAS_VALUE))
+ break;
+#ifdef FEAT_NETBEANS_INTG
+ /* darn, -nb has non-standard syntax */
+ if (vim_strchr((char_u *)":=", argv[i][len]) != NULL
+ && (option->flags & ARG_INDEX_MASK) == ARG_NETBEANS)
+ break;
+#endif
+ }
+ else if ((option->flags & ARG_COMPAT_LONG)
+ && strcmp(argv[i], option->name + 1) == 0)
+ {
+ /* Replace the standard X arguments "-name" and "-display"
+ * with their GNU-style long option counterparts. */
+ argv[i] = (char *)option->name;
+ break;
+ }
+ }
+ if (option->name == NULL) /* no match */
+ {
+ ++i;
+ continue;
+ }
+
+ if (option->flags & ARG_FOR_GTK)
+ {
+ /* Move the argument into gui_argv, which
+ * will later be passed to gtk_init_check() */
+ gui_argv[gui_argc++] = argv[i];
+ }
+ else
+ {
+ char *value = NULL;
+
+ /* Extract the option's value if there is one.
+ * Accept both "--foo bar" and "--foo=bar" style. */
+ if (option->flags & ARG_HAS_VALUE)
+ {
+ if (argv[i][len] == '=')
+ value = &argv[i][len + 1];
+ else if (i + 1 < *argc && strcmp(argv[i + 1], "--") != 0)
+ value = argv[i + 1];
+ }
+
+ /* Check for options handled by Vim itself */
+ switch (option->flags & ARG_INDEX_MASK)
+ {
+ case ARG_REVERSE:
+ found_reverse_arg = TRUE;
+ break;
+ case ARG_NOREVERSE:
+ found_reverse_arg = FALSE;
+ break;
+ case ARG_FONT:
+ font_argument = value;
+ break;
+ case ARG_GEOMETRY:
+ if (value != NULL)
+ gui.geom = vim_strsave((char_u *)value);
+ break;
+ case ARG_BACKGROUND:
+ background_argument = value;
+ break;
+ case ARG_FOREGROUND:
+ foreground_argument = value;
+ break;
+ case ARG_ICONIC:
+ found_iconic_arg = TRUE;
+ break;
+ case ARG_ROLE:
+ role_argument = value; /* used later in gui_mch_open() */
+ break;
+#ifdef FEAT_NETBEANS_INTG
+ case ARG_NETBEANS:
+ gui.dofork = FALSE; /* don't fork() when starting GUI */
+ netbeansArg = argv[i];
+ break;
+#endif
+ default:
+ break;
+ }
+ }
+
+ /* These arguments make gnome_program_init() print a message and exit.
+ * Must start the GUI for this, otherwise ":gui" will exit later!
+ * Only when the GUI can start. */
+ if ((option->flags & ARG_NEEDS_GUI)
+ && gui_mch_early_init_check(FALSE) == OK)
+ gui.starting = TRUE;
+
+ if (option->flags & ARG_KEEP)
+ ++i;
+ else
+ {
+ /* Remove the flag from the argument vector. */
+ if (--*argc > i)
+ {
+ int n_strip = 1;
+
+ /* Move the argument's value as well, if there is one. */
+ if ((option->flags & ARG_HAS_VALUE)
+ && argv[i][len] != '='
+ && strcmp(argv[i + 1], "--") != 0)
+ {
+ ++n_strip;
+ --*argc;
+ if (option->flags & ARG_FOR_GTK)
+ gui_argv[gui_argc++] = argv[i + 1];
+ }
+
+ if (*argc > i)
+ mch_memmove(&argv[i], &argv[i + n_strip],
+ (*argc - i) * sizeof(char *));
+ }
+ argv[*argc] = NULL;
+ }
+ }
+
+ gui_argv[gui_argc] = NULL;
+}
+
+#if defined(EXITFREE) || defined(PROTO)
+ void
+gui_mch_free_all(void)
+{
+ vim_free(gui_argv);
+#if defined(FEAT_GUI_GNOME) && defined(FEAT_SESSION)
+ vim_free(abs_restart_command);
+#endif
+}
+#endif
+
+#if !GTK_CHECK_VERSION(3,0,0)
+/*
+ * This should be maybe completely removed.
+ * Doesn't seem possible, since check_copy_area() relies on
+ * this information. --danielk
+ */
+ static gint
+visibility_event(GtkWidget *widget UNUSED,
+ GdkEventVisibility *event,
+ gpointer data UNUSED)
+{
+ gui.visibility = event->state;
+ /*
+ * When we do an gdk_window_copy_area(), and the window is partially
+ * obscured, we want to receive an event to tell us whether it worked
+ * or not.
+ */
+ if (gui.text_gc != NULL)
+ gdk_gc_set_exposures(gui.text_gc,
+ gui.visibility != GDK_VISIBILITY_UNOBSCURED);
+ return FALSE;
+}
+#endif /* !GTK_CHECK_VERSION(3,0,0) */
+
+/*
+ * Redraw the corresponding portions of the screen.
+ */
+#if GTK_CHECK_VERSION(3,0,0)
+static gboolean is_key_pressed = FALSE;
+static gboolean blink_mode = TRUE;
+
+static gboolean gui_gtk_is_blink_on(void);
+
+ static void
+gui_gtk3_redraw(int x, int y, int width, int height)
+{
+ /* Range checks are left to gui_redraw_block() */
+ gui_redraw_block(Y_2_ROW(y), X_2_COL(x),
+ Y_2_ROW(y + height - 1), X_2_COL(x + width - 1),
+ GUI_MON_NOCLEAR);
+}
+
+ static void
+gui_gtk3_update_cursor(cairo_t *cr)
+{
+ if (gui.row == gui.cursor_row)
+ {
+ gui.by_signal = TRUE;
+ if (State & CMDLINE)
+ gui_update_cursor(TRUE, FALSE);
+ else
+ gui_update_cursor(TRUE, TRUE);
+ gui.by_signal = FALSE;
+ cairo_paint(cr);
+ }
+}
+
+ static gboolean
+gui_gtk3_should_draw_cursor(void)
+{
+ unsigned int cond = 0;
+ cond |= gui_gtk_is_blink_on();
+ if (gui.cursor_col >= gui.col)
+ cond |= is_key_pressed;
+ cond |= gui.in_focus == FALSE;
+ return cond;
+}
+
+ static gboolean
+draw_event(GtkWidget *widget UNUSED,
+ cairo_t *cr,
+ gpointer user_data UNUSED)
+{
+ /* Skip this when the GUI isn't set up yet, will redraw later. */
+ if (gui.starting)
+ return FALSE;
+
+ out_flush(); /* make sure all output has been processed */
+ /* for GTK+ 3, may induce other draw events. */
+
+ cairo_set_source_surface(cr, gui.surface, 0, 0);
+
+ /* Draw the window without the cursor. */
+ gui.by_signal = TRUE;
+ {
+ cairo_rectangle_list_t *list = NULL;
+
+ list = cairo_copy_clip_rectangle_list(cr);
+ if (list->status != CAIRO_STATUS_CLIP_NOT_REPRESENTABLE)
+ {
+ int i;
+
+ /* First clear all the blocks and then redraw them. Just in case
+ * some blocks overlap. */
+ for (i = 0; i < list->num_rectangles; i++)
+ {
+ const cairo_rectangle_t rect = list->rectangles[i];
+
+ gui_mch_clear_block(Y_2_ROW((int)rect.y), 0,
+ Y_2_ROW((int)(rect.y + rect.height)) - 1, Columns - 1);
+ }
+
+ for (i = 0; i < list->num_rectangles; i++)
+ {
+ const cairo_rectangle_t rect = list->rectangles[i];
+
+ if (blink_mode)
+ gui_gtk3_redraw(rect.x, rect.y, rect.width, rect.height);
+ else
+ {
+ if (get_real_state() & VISUAL)
+ gui_gtk3_redraw(rect.x, rect.y,
+ rect.width, rect.height);
+ else
+ gui_redraw(rect.x, rect.y, rect.width, rect.height);
+ }
+ }
+ }
+ cairo_rectangle_list_destroy(list);
+
+ if (get_real_state() & VISUAL)
+ {
+ if (gui.cursor_row == gui.row && gui.cursor_col >= gui.col)
+ gui_update_cursor(TRUE, TRUE);
+ }
+
+ cairo_paint(cr);
+ }
+ gui.by_signal = FALSE;
+
+ /* Add the cursor to the window if necessary.*/
+ if (gui_gtk3_should_draw_cursor() && blink_mode)
+ gui_gtk3_update_cursor(cr);
+
+ return FALSE;
+}
+#else /* !GTK_CHECK_VERSION(3,0,0) */
+ static gint
+expose_event(GtkWidget *widget UNUSED,
+ GdkEventExpose *event,
+ gpointer data UNUSED)
+{
+ /* Skip this when the GUI isn't set up yet, will redraw later. */
+ if (gui.starting)
+ return FALSE;
+
+ out_flush(); /* make sure all output has been processed */
+ gui_redraw(event->area.x, event->area.y,
+ event->area.width, event->area.height);
+
+ /* Clear the border areas if needed */
+ if (event->area.x < FILL_X(0))
+ gdk_window_clear_area(gui.drawarea->window, 0, 0, FILL_X(0), 0);
+ if (event->area.y < FILL_Y(0))
+ gdk_window_clear_area(gui.drawarea->window, 0, 0, 0, FILL_Y(0));
+ if (event->area.x > FILL_X(Columns))
+ gdk_window_clear_area(gui.drawarea->window,
+ FILL_X((int)Columns), 0, 0, 0);
+ if (event->area.y > FILL_Y(Rows))
+ gdk_window_clear_area(gui.drawarea->window, 0, FILL_Y((int)Rows), 0, 0);
+
+ return FALSE;
+}
+#endif /* !GTK_CHECK_VERSION(3,0,0) */
+
+#ifdef FEAT_CLIENTSERVER
+/*
+ * Handle changes to the "Comm" property
+ */
+ static gint
+property_event(GtkWidget *widget,
+ GdkEventProperty *event,
+ gpointer data UNUSED)
+{
+ if (event->type == GDK_PROPERTY_NOTIFY
+ && event->state == (int)GDK_PROPERTY_NEW_VALUE
+ && GDK_WINDOW_XID(event->window) == commWindow
+ && GET_X_ATOM(event->atom) == commProperty)
+ {
+ XEvent xev;
+
+ /* Translate to XLib */
+ xev.xproperty.type = PropertyNotify;
+ xev.xproperty.atom = commProperty;
+ xev.xproperty.window = commWindow;
+ xev.xproperty.state = PropertyNewValue;
+ serverEventProc(GDK_WINDOW_XDISPLAY(gtk_widget_get_window(widget)),
+ &xev, 0);
+ }
+ return FALSE;
+}
+#endif /* defined(FEAT_CLIENTSERVER) */
+
+/*
+ * Handle changes to the "Xft/DPI" setting
+ */
+ static void
+gtk_settings_xft_dpi_changed_cb(GtkSettings *gtk_settings UNUSED,
+ GParamSpec *pspec UNUSED,
+ gpointer data UNUSED)
+{
+ // Create a new PangoContext for this screen, and initialize it
+ // with the current font if necessary.
+ if (gui.text_context != NULL)
+ g_object_unref(gui.text_context);
+
+ gui.text_context = gtk_widget_create_pango_context(gui.mainwin);
+ pango_context_set_base_dir(gui.text_context, PANGO_DIRECTION_LTR);
+
+ if (gui.norm_font != NULL)
+ {
+ // force default font
+ gui_mch_init_font(*p_guifont == NUL ? NULL : p_guifont, FALSE);
+ gui_set_shellsize(TRUE, FALSE, RESIZE_BOTH);
+ }
+}
+
+typedef gboolean timeout_cb_type;
+
+/*
+ * Start a timer that will invoke the specified callback.
+ * Returns the ID of the timer.
+ */
+ static guint
+timeout_add(int time, timeout_cb_type (*callback)(gpointer), int *flagp)
+{
+ return g_timeout_add((guint)time, (GSourceFunc)callback, flagp);
+}
+
+ static void
+timeout_remove(guint timer)
+{
+ g_source_remove(timer);
+}
+
+
+/****************************************************************************
+ * Focus handlers:
+ */
+
+
+/*
+ * 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
+ */
+
+#define BLINK_NONE 0
+#define BLINK_OFF 1
+#define BLINK_ON 2
+
+static int blink_state = BLINK_NONE;
+static long_u blink_waittime = 700;
+static long_u blink_ontime = 400;
+static long_u blink_offtime = 250;
+static guint blink_timer = 0;
+
+#if GTK_CHECK_VERSION(3,0,0)
+ static gboolean
+gui_gtk_is_blink_on(void)
+{
+ return blink_state == BLINK_ON;
+}
+#endif
+
+ int
+gui_mch_is_blinking(void)
+{
+ return blink_state != BLINK_NONE;
+}
+
+ int
+gui_mch_is_blink_off(void)
+{
+ return blink_state == BLINK_OFF;
+}
+
+ void
+gui_mch_set_blinking(long waittime, long on, long off)
+{
+#if GTK_CHECK_VERSION(3,0,0)
+ if (waittime == 0 || on == 0 || off == 0)
+ {
+ blink_mode = FALSE;
+
+ blink_waittime = 700;
+ blink_ontime = 400;
+ blink_offtime = 250;
+ }
+ else
+ {
+ blink_mode = TRUE;
+
+ blink_waittime = waittime;
+ blink_ontime = on;
+ blink_offtime = off;
+ }
+#else
+ blink_waittime = waittime;
+ 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 (blink_timer)
+ {
+ timeout_remove(blink_timer);
+ blink_timer = 0;
+ }
+ if (blink_state == BLINK_OFF && may_call_gui_update_cursor)
+ {
+ gui_update_cursor(TRUE, FALSE);
+ gui_mch_flush();
+ }
+ blink_state = BLINK_NONE;
+}
+
+ static timeout_cb_type
+blink_cb(gpointer data UNUSED)
+{
+ if (blink_state == BLINK_ON)
+ {
+ gui_undraw_cursor();
+ blink_state = BLINK_OFF;
+ blink_timer = timeout_add(blink_offtime, blink_cb, NULL);
+ }
+ else
+ {
+ gui_update_cursor(TRUE, FALSE);
+ blink_state = BLINK_ON;
+ blink_timer = timeout_add(blink_ontime, blink_cb, NULL);
+ }
+ gui_mch_flush();
+
+ return FALSE; /* don't happen again */
+}
+
+/*
+ * Start the cursor blinking. If it was already blinking, this restarts the
+ * waiting time and shows the cursor.
+ */
+ void
+gui_mch_start_blink(void)
+{
+ if (blink_timer)
+ {
+ timeout_remove(blink_timer);
+ blink_timer = 0;
+ }
+ /* Only switch blinking on if none of the times is zero */
+ if (blink_waittime && blink_ontime && blink_offtime && gui.in_focus)
+ {
+ blink_timer = timeout_add(blink_waittime, blink_cb, NULL);
+ blink_state = BLINK_ON;
+ gui_update_cursor(TRUE, FALSE);
+ gui_mch_flush();
+ }
+}
+
+ static gint
+enter_notify_event(GtkWidget *widget UNUSED,
+ GdkEventCrossing *event UNUSED,
+ gpointer data UNUSED)
+{
+ if (blink_state == BLINK_NONE)
+ gui_mch_start_blink();
+
+ /* make sure keyboard input goes there */
+ if (gtk_socket_id == 0 || !gtk_widget_has_focus(gui.drawarea))
+ gtk_widget_grab_focus(gui.drawarea);
+
+ return FALSE;
+}
+
+ static gint
+leave_notify_event(GtkWidget *widget UNUSED,
+ GdkEventCrossing *event UNUSED,
+ gpointer data UNUSED)
+{
+ if (blink_state != BLINK_NONE)
+ gui_mch_stop_blink(TRUE);
+
+ return FALSE;
+}
+
+ static gint
+focus_in_event(GtkWidget *widget,
+ GdkEventFocus *event UNUSED,
+ gpointer data UNUSED)
+{
+ gui_focus_change(TRUE);
+
+ if (blink_state == BLINK_NONE)
+ gui_mch_start_blink();
+
+ /* make sure keyboard input goes to the draw area (if this is focus for a
+ * window) */
+ if (widget != gui.drawarea)
+ gtk_widget_grab_focus(gui.drawarea);
+
+ return TRUE;
+}
+
+ static gint
+focus_out_event(GtkWidget *widget UNUSED,
+ GdkEventFocus *event UNUSED,
+ gpointer data UNUSED)
+{
+ gui_focus_change(FALSE);
+
+ if (blink_state != BLINK_NONE)
+ gui_mch_stop_blink(TRUE);
+
+ return TRUE;
+}
+
+
+/*
+ * Translate a GDK key value to UTF-8 independently of the current locale.
+ * The output is written to string, which must have room for at least 6 bytes
+ * plus the NUL terminator. Returns the length in bytes.
+ *
+ * This function is used in the GTK+ 2 GUI only. The GTK+ 1 code makes use
+ * of GdkEventKey::string instead. But event->string is evil; see here why:
+ * http://developer.gnome.org/doc/API/2.0/gdk/gdk-Event-Structures.html#GdkEventKey
+ */
+ static int
+keyval_to_string(unsigned int keyval, unsigned int state, char_u *string)
+{
+ int len;
+ guint32 uc;
+
+ uc = gdk_keyval_to_unicode(keyval);
+ if (uc != 0)
+ {
+ /* Check for CTRL-foo */
+ if ((state & GDK_CONTROL_MASK) && uc >= 0x20 && uc < 0x80)
+ {
+ /* These mappings look arbitrary at the first glance, but in fact
+ * resemble quite exactly the behaviour of the GTK+ 1.2 GUI on my
+ * machine. The only difference is BS vs. DEL for CTRL-8 (makes
+ * more sense and is consistent with usual terminal behaviour). */
+ if (uc >= '@')
+ string[0] = uc & 0x1F;
+ else if (uc == '2')
+ string[0] = NUL;
+ else if (uc >= '3' && uc <= '7')
+ string[0] = uc ^ 0x28;
+ else if (uc == '8')
+ string[0] = BS;
+ else if (uc == '?')
+ string[0] = DEL;
+ else
+ string[0] = uc;
+ len = 1;
+ }
+ else
+ {
+ /* Translate a normal key to UTF-8. This doesn't work for dead
+ * keys of course, you _have_ to use an input method for that. */
+ len = utf_char2bytes((int)uc, string);
+ }
+ }
+ else
+ {
+ /* Translate keys which are represented by ASCII control codes in Vim.
+ * There are only a few of those; most control keys are translated to
+ * special terminal-like control sequences. */
+ len = 1;
+ switch (keyval)
+ {
+ case GDK_Tab: case GDK_KP_Tab: case GDK_ISO_Left_Tab:
+ string[0] = TAB;
+ break;
+ case GDK_Linefeed:
+ string[0] = NL;
+ break;
+ case GDK_Return: case GDK_ISO_Enter: case GDK_3270_Enter:
+ string[0] = CAR;
+ break;
+ case GDK_Escape:
+ string[0] = ESC;
+ break;
+ default:
+ len = 0;
+ break;
+ }
+ }
+ string[len] = NUL;
+
+ return len;
+}
+
+ static int
+modifiers_gdk2vim(guint state)
+{
+ int modifiers = 0;
+
+ if (state & GDK_SHIFT_MASK)
+ modifiers |= MOD_MASK_SHIFT;
+ if (state & GDK_CONTROL_MASK)
+ modifiers |= MOD_MASK_CTRL;
+ if (state & GDK_MOD1_MASK)
+ modifiers |= MOD_MASK_ALT;
+#if GTK_CHECK_VERSION(2,10,0)
+ if (state & GDK_SUPER_MASK)
+ modifiers |= MOD_MASK_META;
+#endif
+ if (state & GDK_MOD4_MASK)
+ modifiers |= MOD_MASK_META;
+
+ return modifiers;
+}
+
+ static int
+modifiers_gdk2mouse(guint state)
+{
+ int modifiers = 0;
+
+ if (state & GDK_SHIFT_MASK)
+ modifiers |= MOUSE_SHIFT;
+ if (state & GDK_CONTROL_MASK)
+ modifiers |= MOUSE_CTRL;
+ if (state & GDK_MOD1_MASK)
+ modifiers |= MOUSE_ALT;
+
+ return modifiers;
+}
+
+/*
+ * Main keyboard handler:
+ */
+ static gint
+key_press_event(GtkWidget *widget UNUSED,
+ GdkEventKey *event,
+ gpointer data UNUSED)
+{
+ /* For GTK+ 2 we know for sure how large the string might get.
+ * (That is, up to 6 bytes + NUL + CSI escapes + safety measure.) */
+ char_u string[32], string2[32];
+ guint key_sym;
+ int len;
+ int i;
+ int modifiers;
+ int key;
+ guint state;
+ char_u *s, *d;
+
+#if GTK_CHECK_VERSION(3,0,0)
+ is_key_pressed = TRUE;
+ gui_mch_stop_blink(TRUE);
+#endif
+
+ gui.event_time = event->time;
+ key_sym = event->keyval;
+ state = event->state;
+
+#ifdef FEAT_XIM
+ if (xim_queue_key_press_event(event, TRUE))
+ return TRUE;
+#endif
+
+#ifdef FEAT_HANGULIN
+ if (key_sym == GDK_space && (state & GDK_SHIFT_MASK))
+ {
+ hangul_input_state_toggle();
+ return TRUE;
+ }
+#endif
+
+#ifdef SunXK_F36
+ /*
+ * These keys have bogus lookup strings, and trapping them here is
+ * easier than trying to XRebindKeysym() on them with every possible
+ * combination of modifiers.
+ */
+ if (key_sym == SunXK_F36 || key_sym == SunXK_F37)
+ len = 0;
+ else
+#endif
+ {
+ len = keyval_to_string(key_sym, state, string2);
+
+ /* Careful: convert_input() doesn't handle the NUL character.
+ * No need to convert pure ASCII anyway, thus the len > 1 check. */
+ if (len > 1 && input_conv.vc_type != CONV_NONE)
+ len = convert_input(string2, len, sizeof(string2));
+
+ s = string2;
+ d = string;
+ for (i = 0; i < len; ++i)
+ {
+ *d++ = s[i];
+ if (d[-1] == CSI && d + 2 < string + sizeof(string))
+ {
+ /* Turn CSI into K_CSI. */
+ *d++ = KS_EXTRA;
+ *d++ = (int)KE_CSI;
+ }
+ }
+ len = d - string;
+ }
+
+ /* Shift-Tab results in Left_Tab, but we want <S-Tab> */
+ if (key_sym == GDK_ISO_Left_Tab)
+ {
+ key_sym = GDK_Tab;
+ state |= GDK_SHIFT_MASK;
+ }
+
+#ifdef FEAT_MENU
+ /* If there is a menu and 'wak' is "yes", or 'wak' is "menu" and the key
+ * is a menu shortcut, we ignore everything with the ALT modifier. */
+ if ((state & GDK_MOD1_MASK)
+ && gui.menu_is_active
+ && (*p_wak == 'y'
+ || (*p_wak == 'm'
+ && len == 1
+ && gui_is_menu_shortcut(string[0]))))
+ /* For GTK2 we return false to signify that we haven't handled the
+ * keypress, so that gtk will handle the mnemonic or accelerator. */
+ return FALSE;
+#endif
+
+ /* Check for Alt/Meta key (Mod1Mask), but not for a BS, DEL or character
+ * that already has the 8th bit set.
+ * Don't do this for <S-M-Tab>, that should become K_S_TAB with ALT.
+ * Don't do this for double-byte encodings, it turns the char into a lead
+ * byte. */
+ if (len == 1
+ && ((state & GDK_MOD1_MASK)
+#if GTK_CHECK_VERSION(2,10,0)
+ || (state & GDK_SUPER_MASK)
+#endif
+ )
+ && !(key_sym == GDK_BackSpace || key_sym == GDK_Delete)
+ && (string[0] & 0x80) == 0
+ && !(key_sym == GDK_Tab && (state & GDK_SHIFT_MASK))
+ && !enc_dbcs
+ )
+ {
+ string[0] |= 0x80;
+ state &= ~GDK_MOD1_MASK; /* don't use it again */
+ if (enc_utf8) /* convert to utf-8 */
+ {
+ string[1] = string[0] & 0xbf;
+ string[0] = ((unsigned)string[0] >> 6) + 0xc0;
+ if (string[1] == CSI)
+ {
+ string[2] = KS_EXTRA;
+ string[3] = (int)KE_CSI;
+ len = 4;
+ }
+ else
+ len = 2;
+ }
+ }
+
+ /* Check for special keys. Also do this when len == 1 (key has an ASCII
+ * value) to detect backspace, delete and keypad keys. */
+ if (len == 0 || len == 1)
+ {
+ for (i = 0; special_keys[i].key_sym != 0; i++)
+ {
+ if (special_keys[i].key_sym == key_sym)
+ {
+ string[0] = CSI;
+ string[1] = special_keys[i].code0;
+ string[2] = special_keys[i].code1;
+ len = -3;
+ break;
+ }
+ }
+ }
+
+ if (len == 0) /* Unrecognized key */
+ return TRUE;
+
+ /* Special keys (and a few others) may have modifiers. Also when using a
+ * double-byte encoding (can't set the 8th bit). */
+ if (len == -3 || key_sym == GDK_space || key_sym == GDK_Tab
+ || key_sym == GDK_Return || key_sym == GDK_Linefeed
+ || key_sym == GDK_Escape || key_sym == GDK_KP_Tab
+ || key_sym == GDK_ISO_Enter || key_sym == GDK_3270_Enter
+ || (enc_dbcs && len == 1 && ((state & GDK_MOD1_MASK)
+#if GTK_CHECK_VERSION(2,10,0)
+ || (state & GDK_SUPER_MASK)
+#endif
+ )))
+ {
+ modifiers = modifiers_gdk2vim(state);
+
+ /*
+ * For some keys a shift modifier is translated into another key
+ * code.
+ */
+ if (len == -3)
+ key = TO_SPECIAL(string[1], string[2]);
+ else
+ key = string[0];
+
+ key = simplify_key(key, &modifiers);
+ if (key == CSI)
+ key = K_CSI;
+ if (IS_SPECIAL(key))
+ {
+ string[0] = CSI;
+ string[1] = K_SECOND(key);
+ string[2] = K_THIRD(key);
+ len = 3;
+ }
+ else
+ {
+ string[0] = key;
+ len = 1;
+ }
+
+ if (modifiers != 0)
+ {
+ string2[0] = CSI;
+ string2[1] = KS_MODIFIER;
+ string2[2] = modifiers;
+ add_to_input_buf(string2, 3);
+ }
+ }
+
+ if (len == 1 && ((string[0] == Ctrl_C && ctrl_c_interrupts)
+ || (string[0] == intr_char && intr_char != Ctrl_C)))
+ {
+ trash_input_buf();
+ got_int = TRUE;
+ }
+
+ add_to_input_buf(string, len);
+
+ /* blank out the pointer if necessary */
+ if (p_mh)
+ gui_mch_mousehide(TRUE);
+
+ return TRUE;
+}
+
+#if defined(FEAT_XIM) || GTK_CHECK_VERSION(3,0,0)
+ static gboolean
+key_release_event(GtkWidget *widget UNUSED,
+ GdkEventKey *event,
+ gpointer data UNUSED)
+{
+# if GTK_CHECK_VERSION(3,0,0)
+ is_key_pressed = FALSE;
+ gui_mch_start_blink();
+# endif
+# if defined(FEAT_XIM)
+ gui.event_time = event->time;
+ /*
+ * GTK+ 2 input methods may do fancy stuff on key release events too.
+ * With the default IM for instance, you can enter any UCS code point
+ * by holding down CTRL-SHIFT and typing hexadecimal digits.
+ */
+ return xim_queue_key_press_event(event, FALSE);
+# else
+ return TRUE;
+# endif
+}
+#endif
+
+
+/****************************************************************************
+ * Selection handlers:
+ */
+
+/* Remember when clip_lose_selection was called from here, we must not call
+ * gtk_selection_owner_set() then. */
+static int in_selection_clear_event = FALSE;
+
+ static gint
+selection_clear_event(GtkWidget *widget UNUSED,
+ GdkEventSelection *event,
+ gpointer user_data UNUSED)
+{
+ in_selection_clear_event = TRUE;
+ if (event->selection == clip_plus.gtk_sel_atom)
+ clip_lose_selection(&clip_plus);
+ else
+ clip_lose_selection(&clip_star);
+ in_selection_clear_event = FALSE;
+
+ return TRUE;
+}
+
+#define RS_NONE 0 /* selection_received_cb() not called yet */
+#define RS_OK 1 /* selection_received_cb() called and OK */
+#define RS_FAIL 2 /* selection_received_cb() called and failed */
+static int received_selection = RS_NONE;
+
+ static void
+selection_received_cb(GtkWidget *widget UNUSED,
+ GtkSelectionData *data,
+ guint time_ UNUSED,
+ gpointer user_data UNUSED)
+{
+ VimClipboard *cbd;
+ char_u *text;
+ char_u *tmpbuf = NULL;
+ guchar *tmpbuf_utf8 = NULL;
+ int len;
+ int motion_type = MAUTO;
+
+ if (gtk_selection_data_get_selection(data) == clip_plus.gtk_sel_atom)
+ cbd = &clip_plus;
+ else
+ cbd = &clip_star;
+
+ text = (char_u *)gtk_selection_data_get_data(data);
+ len = gtk_selection_data_get_length(data);
+
+ if (text == NULL || len <= 0)
+ {
+ received_selection = RS_FAIL;
+ /* clip_free_selection(cbd); ??? */
+
+ return;
+ }
+
+ if (gtk_selection_data_get_data_type(data) == vim_atom)
+ {
+ motion_type = *text++;
+ --len;
+ }
+ else if (gtk_selection_data_get_data_type(data) == vimenc_atom)
+ {
+ char_u *enc;
+ vimconv_T conv;
+
+ motion_type = *text++;
+ --len;
+
+ enc = text;
+ text += STRLEN(text) + 1;
+ len -= text - enc;
+
+ /* If the encoding of the text is different from 'encoding', attempt
+ * converting it. */
+ conv.vc_type = CONV_NONE;
+ convert_setup(&conv, enc, p_enc);
+ if (conv.vc_type != CONV_NONE)
+ {
+ tmpbuf = string_convert(&conv, text, &len);
+ if (tmpbuf != NULL)
+ text = tmpbuf;
+ convert_setup(&conv, NULL, NULL);
+ }
+ }
+
+ /* gtk_selection_data_get_text() handles all the nasty details
+ * and targets and encodings etc. This rocks so hard. */
+ else
+ {
+ tmpbuf_utf8 = gtk_selection_data_get_text(data);
+ if (tmpbuf_utf8 != NULL)
+ {
+ len = STRLEN(tmpbuf_utf8);
+ if (input_conv.vc_type != CONV_NONE)
+ {
+ tmpbuf = string_convert(&input_conv, tmpbuf_utf8, &len);
+ if (tmpbuf != NULL)
+ text = tmpbuf;
+ }
+ else
+ text = tmpbuf_utf8;
+ }
+ else if (len >= 2 && text[0] == 0xff && text[1] == 0xfe)
+ {
+ vimconv_T conv;
+
+ /* UTF-16, we get this for HTML */
+ conv.vc_type = CONV_NONE;
+ convert_setup_ext(&conv, (char_u *)"utf-16le", FALSE, p_enc, TRUE);
+
+ if (conv.vc_type != CONV_NONE)
+ {
+ text += 2;
+ len -= 2;
+ tmpbuf = string_convert(&conv, text, &len);
+ convert_setup(&conv, NULL, NULL);
+ }
+ if (tmpbuf != NULL)
+ text = tmpbuf;
+ }
+ }
+
+ /* Chop off any trailing NUL bytes. OpenOffice sends these. */
+ while (len > 0 && text[len - 1] == NUL)
+ --len;
+
+ clip_yank_selection(motion_type, text, (long)len, cbd);
+ received_selection = RS_OK;
+ vim_free(tmpbuf);
+ g_free(tmpbuf_utf8);
+}
+
+/*
+ * Prepare our selection data for passing it to the external selection
+ * client.
+ */
+ static void
+selection_get_cb(GtkWidget *widget UNUSED,
+ GtkSelectionData *selection_data,
+ guint info,
+ guint time_ UNUSED,
+ gpointer user_data UNUSED)
+{
+ char_u *string;
+ char_u *tmpbuf;
+ long_u tmplen;
+ int length;
+ int motion_type;
+ GdkAtom type;
+ VimClipboard *cbd;
+
+ if (gtk_selection_data_get_selection(selection_data)
+ == clip_plus.gtk_sel_atom)
+ cbd = &clip_plus;
+ else
+ cbd = &clip_star;
+
+ if (!cbd->owned)
+ return; /* Shouldn't ever happen */
+
+ if (info != (guint)TARGET_STRING
+ && (!clip_html || info != (guint)TARGET_HTML)
+ && info != (guint)TARGET_UTF8_STRING
+ && info != (guint)TARGET_VIMENC
+ && info != (guint)TARGET_VIM
+ && info != (guint)TARGET_COMPOUND_TEXT
+ && info != (guint)TARGET_TEXT)
+ return;
+
+ /* get the selection from the '*'/'+' register */
+ clip_get_selection(cbd);
+
+ motion_type = clip_convert_selection(&string, &tmplen, cbd);
+ if (motion_type < 0 || string == NULL)
+ return;
+ /* Due to int arguments we can't handle more than G_MAXINT. Also
+ * reserve one extra byte for NUL or the motion type; just in case.
+ * (Not that pasting 2G of text is ever going to work, but... ;-) */
+ length = MIN(tmplen, (long_u)(G_MAXINT - 1));
+
+ if (info == (guint)TARGET_VIM)
+ {
+ tmpbuf = alloc((unsigned)length + 1);
+ if (tmpbuf != NULL)
+ {
+ tmpbuf[0] = motion_type;
+ mch_memmove(tmpbuf + 1, string, (size_t)length);
+ }
+ /* For our own format, the first byte contains the motion type */
+ ++length;
+ vim_free(string);
+ string = tmpbuf;
+ type = vim_atom;
+ }
+
+ else if (info == (guint)TARGET_HTML)
+ {
+ vimconv_T conv;
+
+ /* Since we get utf-16, we probably should set it as well. */
+ conv.vc_type = CONV_NONE;
+ convert_setup_ext(&conv, p_enc, TRUE, (char_u *)"utf-16le", FALSE);
+ if (conv.vc_type != CONV_NONE)
+ {
+ tmpbuf = string_convert(&conv, string, &length);
+ convert_setup(&conv, NULL, NULL);
+ vim_free(string);
+ string = tmpbuf;
+ }
+
+ /* Prepend the BOM: "fffe" */
+ if (string != NULL)
+ {
+ tmpbuf = alloc(length + 2);
+ tmpbuf[0] = 0xff;
+ tmpbuf[1] = 0xfe;
+ mch_memmove(tmpbuf + 2, string, (size_t)length);
+ vim_free(string);
+ string = tmpbuf;
+ length += 2;
+
+#if !GTK_CHECK_VERSION(3,0,0)
+ /* Looks redundant even for GTK2 because these values are
+ * overwritten by gtk_selection_data_set() that follows. */
+ selection_data->type = selection_data->target;
+ selection_data->format = 16; /* 16 bits per char */
+#endif
+ gtk_selection_data_set(selection_data, html_atom, 16,
+ string, length);
+ vim_free(string);
+ }
+ return;
+ }
+ else if (info == (guint)TARGET_VIMENC)
+ {
+ int l = STRLEN(p_enc);
+
+ /* contents: motion_type 'encoding' NUL text */
+ tmpbuf = alloc((unsigned)length + l + 2);
+ if (tmpbuf != NULL)
+ {
+ tmpbuf[0] = motion_type;
+ STRCPY(tmpbuf + 1, p_enc);
+ mch_memmove(tmpbuf + l + 2, string, (size_t)length);
+ }
+ length += l + 2;
+ vim_free(string);
+ string = tmpbuf;
+ type = vimenc_atom;
+ }
+
+ /* gtk_selection_data_set_text() handles everything for us. This is
+ * so easy and simple and cool, it'd be insane not to use it. */
+ else
+ {
+ if (output_conv.vc_type != CONV_NONE)
+ {
+ tmpbuf = string_convert(&output_conv, string, &length);
+ vim_free(string);
+ if (tmpbuf == NULL)
+ return;
+ string = tmpbuf;
+ }
+ /* Validate the string to avoid runtime warnings */
+ if (g_utf8_validate((const char *)string, (gssize)length, NULL))
+ {
+ gtk_selection_data_set_text(selection_data,
+ (const char *)string, length);
+ }
+ vim_free(string);
+ return;
+ }
+
+ if (string != NULL)
+ {
+#if !GTK_CHECK_VERSION(3,0,0)
+ /* Looks redundant even for GTK2 because these values are
+ * overwritten by gtk_selection_data_set() that follows. */
+ selection_data->type = selection_data->target;
+ selection_data->format = 8; /* 8 bits per char */
+#endif
+ gtk_selection_data_set(selection_data, type, 8, string, length);
+ vim_free(string);
+ }
+}
+
+/*
+ * Check if the GUI can be started. Called before gvimrc is sourced and
+ * before fork().
+ * Return OK or FAIL.
+ */
+ int
+gui_mch_early_init_check(int give_message)
+{
+ char_u *p;
+
+ /* Guess that when $DISPLAY isn't set the GUI can't start. */
+ p = mch_getenv((char_u *)"DISPLAY");
+ if (p == NULL || *p == NUL)
+ {
+ gui.dying = TRUE;
+ if (give_message)
+ emsg(_((char *)e_opendisp));
+ return FAIL;
+ }
+ return OK;
+}
+
+/*
+ * Check if the GUI can be started. Called before gvimrc is sourced but after
+ * fork().
+ * Return OK or FAIL.
+ */
+ int
+gui_mch_init_check(void)
+{
+#ifdef USE_GRESOURCE
+ static int res_registered = FALSE;
+
+ if (!res_registered)
+ {
+ /* Call this function in the GUI process; otherwise, the resources
+ * won't be available. Don't call it twice. */
+ res_registered = TRUE;
+ gui_gtk_register_resource();
+ }
+#endif
+
+#if GTK_CHECK_VERSION(3,10,0)
+ /* Vim currently assumes that Gtk means X11, so it cannot use native Gtk
+ * support for other backends such as Wayland. */
+ gdk_set_allowed_backends ("x11");
+#endif
+
+#ifdef FEAT_GUI_GNOME
+ if (gtk_socket_id == 0)
+ using_gnome = 1;
+#endif
+
+ /* This defaults to argv[0], but we want it to match the name of the
+ * shipped gvim.desktop so that Vim's windows can be associated with this
+ * file. */
+ g_set_prgname("gvim");
+
+ /* Don't use gtk_init() or gnome_init(), it exits on failure. */
+ if (!gtk_init_check(&gui_argc, &gui_argv))
+ {
+ gui.dying = TRUE;
+ emsg(_((char *)e_opendisp));
+ return FAIL;
+ }
+
+ return OK;
+}
+
+/****************************************************************************
+ * Mouse handling callbacks
+ */
+
+
+static guint mouse_click_timer = 0;
+static int mouse_timed_out = TRUE;
+
+/*
+ * Timer used to recognize multiple clicks of the mouse button
+ */
+ static timeout_cb_type
+mouse_click_timer_cb(gpointer data)
+{
+ /* we don't use this information currently */
+ int *timed_out = (int *) data;
+
+ *timed_out = TRUE;
+ return FALSE; /* don't happen again */
+}
+
+static guint motion_repeat_timer = 0;
+static int motion_repeat_offset = FALSE;
+static timeout_cb_type motion_repeat_timer_cb(gpointer);
+
+ static void
+process_motion_notify(int x, int y, GdkModifierType state)
+{
+ int button;
+ int_u vim_modifiers;
+ GtkAllocation allocation;
+
+ button = (state & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK |
+ GDK_BUTTON3_MASK | GDK_BUTTON4_MASK |
+ GDK_BUTTON5_MASK))
+ ? MOUSE_DRAG : ' ';
+
+ /* If our pointer is currently hidden, then we should show it. */
+ gui_mch_mousehide(FALSE);
+
+ /* Just moving the rodent above the drawing area without any button
+ * being pressed. */
+ if (button != MOUSE_DRAG)
+ {
+ gui_mouse_moved(x, y);
+ return;
+ }
+
+ /* translate modifier coding between the main engine and GTK */
+ vim_modifiers = modifiers_gdk2mouse(state);
+
+ /* inform the editor engine about the occurrence of this event */
+ gui_send_mouse_event(button, x, y, FALSE, vim_modifiers);
+
+ /*
+ * Auto repeat timer handling.
+ */
+ gtk_widget_get_allocation(gui.drawarea, &allocation);
+
+ if (x < 0 || y < 0
+ || x >= allocation.width
+ || y >= allocation.height)
+ {
+
+ int dx;
+ int dy;
+ int offshoot;
+ int delay = 10;
+
+ /* Calculate the maximal distance of the cursor from the drawing area.
+ * (offshoot can't become negative here!).
+ */
+ dx = x < 0 ? -x : x - allocation.width;
+ dy = y < 0 ? -y : y - allocation.height;
+
+ offshoot = dx > dy ? dx : dy;
+
+ /* Make a linearly decaying timer delay with a threshold of 5 at a
+ * distance of 127 pixels from the main window.
+ *
+ * One could think endlessly about the most ergonomic variant here.
+ * For example it could make sense to calculate the distance from the
+ * drags start instead...
+ *
+ * Maybe a parabolic interpolation would suite us better here too...
+ */
+ if (offshoot > 127)
+ {
+ /* 5 appears to be somehow near to my perceptual limits :-). */
+ delay = 5;
+ }
+ else
+ {
+ delay = (130 * (127 - offshoot)) / 127 + 5;
+ }
+
+ /* shoot again */
+ if (!motion_repeat_timer)
+ motion_repeat_timer = timeout_add(delay, motion_repeat_timer_cb,
+ NULL);
+ }
+}
+
+#if GTK_CHECK_VERSION(3,0,0)
+ static GdkDevice *
+gui_gtk_get_pointer_device(GtkWidget *widget)
+{
+ GdkWindow * const win = gtk_widget_get_window(widget);
+ GdkDisplay * const dpy = gdk_window_get_display(win);
+# if GTK_CHECK_VERSION(3,20,0)
+ GdkSeat * const seat = gdk_display_get_default_seat(dpy);
+ return gdk_seat_get_pointer(seat);
+# else
+ GdkDeviceManager * const mngr = gdk_display_get_device_manager(dpy);
+ return gdk_device_manager_get_client_pointer(mngr);
+# endif
+}
+
+ static GdkWindow *
+gui_gtk_get_pointer(GtkWidget *widget,
+ gint *x,
+ gint *y,
+ GdkModifierType *state)
+{
+ GdkWindow * const win = gtk_widget_get_window(widget);
+ GdkDevice * const dev = gui_gtk_get_pointer_device(widget);
+ return gdk_window_get_device_position(win, dev , x, y, state);
+}
+
+# if defined(FEAT_GUI_TABLINE) || defined(PROTO)
+ static GdkWindow *
+gui_gtk_window_at_position(GtkWidget *widget,
+ gint *x,
+ gint *y)
+{
+ GdkDevice * const dev = gui_gtk_get_pointer_device(widget);
+ return gdk_device_get_window_at_position(dev, x, y);
+}
+# endif
+#else /* !GTK_CHECK_VERSION(3,0,0) */
+# define gui_gtk_get_pointer(wid, x, y, s) \
+ gdk_window_get_pointer((wid)->window, x, y, s)
+# define gui_gtk_window_at_position(wid, x, y) gdk_window_at_pointer(x, y)
+#endif
+
+/*
+ * Timer used to recognize multiple clicks of the mouse button.
+ */
+ static timeout_cb_type
+motion_repeat_timer_cb(gpointer data UNUSED)
+{
+ int x;
+ int y;
+ GdkModifierType state;
+
+ gui_gtk_get_pointer(gui.drawarea, &x, &y, &state);
+
+ if (!(state & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK |
+ GDK_BUTTON3_MASK | GDK_BUTTON4_MASK |
+ GDK_BUTTON5_MASK)))
+ {
+ motion_repeat_timer = 0;
+ return FALSE;
+ }
+
+ /* If there already is a mouse click in the input buffer, wait another
+ * time (otherwise we would create a backlog of clicks) */
+ if (vim_used_in_input_buf() > 10)
+ return TRUE;
+
+ motion_repeat_timer = 0;
+
+ /*
+ * Fake a motion event.
+ * Trick: Pretend the mouse moved to the next character on every other
+ * event, otherwise drag events will be discarded, because they are still
+ * in the same character.
+ */
+ if (motion_repeat_offset)
+ x += gui.char_width;
+
+ motion_repeat_offset = !motion_repeat_offset;
+ process_motion_notify(x, y, state);
+
+ /* Don't happen again. We will get reinstalled in the synthetic event
+ * if needed -- thus repeating should still work. */
+ return FALSE;
+}
+
+ static gint
+motion_notify_event(GtkWidget *widget,
+ GdkEventMotion *event,
+ gpointer data UNUSED)
+{
+ if (event->is_hint)
+ {
+ int x;
+ int y;
+ GdkModifierType state;
+
+ gui_gtk_get_pointer(widget, &x, &y, &state);
+ process_motion_notify(x, y, state);
+ }
+ else
+ {
+ process_motion_notify((int)event->x, (int)event->y,
+ (GdkModifierType)event->state);
+ }
+
+ return TRUE; /* handled */
+}
+
+
+/*
+ * Mouse button handling. Note please that we are capturing multiple click's
+ * by our own timeout mechanism instead of the one provided by GTK+ itself.
+ * This is due to the way the generic VIM code is recognizing multiple clicks.
+ */
+ static gint
+button_press_event(GtkWidget *widget,
+ GdkEventButton *event,
+ gpointer data UNUSED)
+{
+ int button;
+ int repeated_click = FALSE;
+ int x, y;
+ int_u vim_modifiers;
+
+ gui.event_time = event->time;
+
+ /* Make sure we have focus now we've been selected */
+ if (gtk_socket_id != 0 && !gtk_widget_has_focus(widget))
+ gtk_widget_grab_focus(widget);
+
+ /*
+ * Don't let additional events about multiple clicks send by GTK to us
+ * after the initial button press event confuse us.
+ */
+ if (event->type != GDK_BUTTON_PRESS)
+ return FALSE;
+
+ x = event->x;
+ y = event->y;
+
+ /* Handle multiple clicks */
+ if (!mouse_timed_out && mouse_click_timer)
+ {
+ timeout_remove(mouse_click_timer);
+ mouse_click_timer = 0;
+ repeated_click = TRUE;
+ }
+
+ mouse_timed_out = FALSE;
+ mouse_click_timer = timeout_add(p_mouset, mouse_click_timer_cb,
+ &mouse_timed_out);
+
+ switch (event->button)
+ {
+ /* Keep in sync with gui_x11.c.
+ * Buttons 4-7 are handled in scroll_event() */
+ case 1: button = MOUSE_LEFT; break;
+ case 2: button = MOUSE_MIDDLE; break;
+ case 3: button = MOUSE_RIGHT; break;
+ case 8: button = MOUSE_X1; break;
+ case 9: button = MOUSE_X2; break;
+ default:
+ return FALSE; /* Unknown button */
+ }
+
+#ifdef FEAT_XIM
+ /* cancel any preediting */
+ if (im_is_preediting())
+ xim_reset();
+#endif
+
+ vim_modifiers = modifiers_gdk2mouse(event->state);
+
+ gui_send_mouse_event(button, x, y, repeated_click, vim_modifiers);
+
+ return TRUE;
+}
+
+/*
+ * GTK+ 2 abstracts scrolling via the GdkEventScroll.
+ */
+ static gboolean
+scroll_event(GtkWidget *widget,
+ GdkEventScroll *event,
+ gpointer data UNUSED)
+{
+ int button;
+ int_u vim_modifiers;
+
+ if (gtk_socket_id != 0 && !gtk_widget_has_focus(widget))
+ gtk_widget_grab_focus(widget);
+
+ switch (event->direction)
+ {
+ case GDK_SCROLL_UP:
+ button = MOUSE_4;
+ break;
+ case GDK_SCROLL_DOWN:
+ button = MOUSE_5;
+ break;
+ case GDK_SCROLL_LEFT:
+ button = MOUSE_7;
+ break;
+ case GDK_SCROLL_RIGHT:
+ button = MOUSE_6;
+ break;
+ default: /* This shouldn't happen */
+ return FALSE;
+ }
+
+# ifdef FEAT_XIM
+ /* cancel any preediting */
+ if (im_is_preediting())
+ xim_reset();
+# endif
+
+ vim_modifiers = modifiers_gdk2mouse(event->state);
+
+ gui_send_mouse_event(button, (int)event->x, (int)event->y,
+ FALSE, vim_modifiers);
+
+ return TRUE;
+}
+
+
+ static gint
+button_release_event(GtkWidget *widget UNUSED,
+ GdkEventButton *event,
+ gpointer data UNUSED)
+{
+ int x, y;
+ int_u vim_modifiers;
+
+ gui.event_time = event->time;
+
+ /* Remove any motion "machine gun" timers used for automatic further
+ extension of allocation areas if outside of the applications window
+ area .*/
+ if (motion_repeat_timer)
+ {
+ timeout_remove(motion_repeat_timer);
+ motion_repeat_timer = 0;
+ }
+
+ x = event->x;
+ y = event->y;
+
+ vim_modifiers = modifiers_gdk2mouse(event->state);
+
+ gui_send_mouse_event(MOUSE_RELEASE, x, y, FALSE, vim_modifiers);
+
+ return TRUE;
+}
+
+
+#ifdef FEAT_DND
+/****************************************************************************
+ * Drag aNd Drop support handlers.
+ */
+
+/*
+ * Count how many items there may be and separate them with a NUL.
+ * Apparently the items are separated with \r\n. This is not documented,
+ * thus be careful not to go past the end. Also allow separation with
+ * NUL characters.
+ */
+ static int
+count_and_decode_uri_list(char_u *out, char_u *raw, int len)
+{
+ int i;
+ char_u *p = out;
+ int count = 0;
+
+ for (i = 0; i < len; ++i)
+ {
+ if (raw[i] == NUL || raw[i] == '\n' || raw[i] == '\r')
+ {
+ if (p > out && p[-1] != NUL)
+ {
+ ++count;
+ *p++ = NUL;
+ }
+ }
+ else if (raw[i] == '%' && i + 2 < len && hexhex2nr(raw + i + 1) > 0)
+ {
+ *p++ = hexhex2nr(raw + i + 1);
+ i += 2;
+ }
+ else
+ *p++ = raw[i];
+ }
+ if (p > out && p[-1] != NUL)
+ {
+ *p = NUL; /* last item didn't have \r or \n */
+ ++count;
+ }
+ return count;
+}
+
+/*
+ * Parse NUL separated "src" strings. Make it an array "outlist" form. On
+ * this process, URI which protocol is not "file:" are removed. Return
+ * length of array (less than "max").
+ */
+ static int
+filter_uri_list(char_u **outlist, int max, char_u *src)
+{
+ int i, j;
+
+ for (i = j = 0; i < max; ++i)
+ {
+ outlist[i] = NULL;
+ if (STRNCMP(src, "file:", 5) == 0)
+ {
+ src += 5;
+ if (STRNCMP(src, "//localhost", 11) == 0)
+ src += 11;
+ while (src[0] == '/' && src[1] == '/')
+ ++src;
+ outlist[j++] = vim_strsave(src);
+ }
+ src += STRLEN(src) + 1;
+ }
+ return j;
+}
+
+ static char_u **
+parse_uri_list(int *count, char_u *data, int len)
+{
+ int n = 0;
+ char_u *tmp = NULL;
+ char_u **array = NULL;
+
+ if (data != NULL && len > 0 && (tmp = (char_u *)alloc(len + 1)) != NULL)
+ {
+ n = count_and_decode_uri_list(tmp, data, len);
+ if (n > 0 && (array = (char_u **)alloc(n * sizeof(char_u *))) != NULL)
+ n = filter_uri_list(array, n, tmp);
+ }
+ vim_free(tmp);
+ *count = n;
+ return array;
+}
+
+ static void
+drag_handle_uri_list(GdkDragContext *context,
+ GtkSelectionData *data,
+ guint time_,
+ GdkModifierType state,
+ gint x,
+ gint y)
+{
+ char_u **fnames;
+ int nfiles = 0;
+
+ fnames = parse_uri_list(&nfiles,
+ (char_u *)gtk_selection_data_get_data(data),
+ gtk_selection_data_get_length(data));
+
+ if (fnames != NULL && nfiles > 0)
+ {
+ int_u modifiers;
+
+ gtk_drag_finish(context, TRUE, FALSE, time_); /* accept */
+
+ modifiers = modifiers_gdk2mouse(state);
+
+ gui_handle_drop(x, y, modifiers, fnames, nfiles);
+ }
+ else
+ vim_free(fnames);
+}
+
+ static void
+drag_handle_text(GdkDragContext *context,
+ GtkSelectionData *data,
+ guint time_,
+ GdkModifierType state)
+{
+ char_u dropkey[6] = {CSI, KS_MODIFIER, 0, CSI, KS_EXTRA, (char_u)KE_DROP};
+ char_u *text;
+ int len;
+ char_u *tmpbuf = NULL;
+
+ text = (char_u *)gtk_selection_data_get_data(data);
+ len = gtk_selection_data_get_length(data);
+
+ if (gtk_selection_data_get_data_type(data) == utf8_string_atom)
+ {
+ if (input_conv.vc_type != CONV_NONE)
+ tmpbuf = string_convert(&input_conv, text, &len);
+ if (tmpbuf != NULL)
+ text = tmpbuf;
+ }
+
+ dnd_yank_drag_data(text, (long)len);
+ gtk_drag_finish(context, TRUE, FALSE, time_); /* accept */
+ vim_free(tmpbuf);
+
+ dropkey[2] = modifiers_gdk2vim(state);
+
+ if (dropkey[2] != 0)
+ add_to_input_buf(dropkey, (int)sizeof(dropkey));
+ else
+ add_to_input_buf(dropkey + 3, (int)(sizeof(dropkey) - 3));
+}
+
+/*
+ * DND receiver.
+ */
+ static void
+drag_data_received_cb(GtkWidget *widget,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ GtkSelectionData *data,
+ guint info,
+ guint time_,
+ gpointer user_data UNUSED)
+{
+ GdkModifierType state;
+
+ /* Guard against trash */
+ const guchar * const data_data = gtk_selection_data_get_data(data);
+ const gint data_length = gtk_selection_data_get_length(data);
+ const gint data_format = gtk_selection_data_get_format(data);
+
+ if (data_data == NULL
+ || data_length <= 0
+ || data_format != 8
+ || data_data[data_length] != '\0')
+ {
+ gtk_drag_finish(context, FALSE, FALSE, time_);
+ return;
+ }
+
+ /* Get the current modifier state for proper distinguishment between
+ * different operations later. */
+ gui_gtk_get_pointer(widget, NULL, NULL, &state);
+
+ /* Not sure about the role of "text/plain" here... */
+ if (info == (guint)TARGET_TEXT_URI_LIST)
+ drag_handle_uri_list(context, data, time_, state, x, y);
+ else
+ drag_handle_text(context, data, time_, state);
+
+}
+#endif /* FEAT_DND */
+
+
+#if defined(FEAT_GUI_GNOME) && defined(FEAT_SESSION)
+/*
+ * GnomeClient interact callback. Check for unsaved buffers that cannot
+ * be abandoned and pop up a dialog asking the user for confirmation if
+ * necessary.
+ */
+ static void
+sm_client_check_changed_any(GnomeClient *client UNUSED,
+ gint key,
+ GnomeDialogType type UNUSED,
+ gpointer data UNUSED)
+{
+ cmdmod_T save_cmdmod;
+ gboolean shutdown_cancelled;
+
+ save_cmdmod = cmdmod;
+
+# ifdef FEAT_BROWSE
+ cmdmod.browse = TRUE;
+# endif
+# if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
+ cmdmod.confirm = TRUE;
+# endif
+ /*
+ * If there are changed buffers, present the user with
+ * a dialog if possible, otherwise give an error message.
+ */
+ shutdown_cancelled = check_changed_any(FALSE, FALSE);
+
+ exiting = FALSE;
+ cmdmod = save_cmdmod;
+ setcursor(); /* position the cursor */
+ out_flush();
+ /*
+ * If the user hit the [Cancel] button the whole shutdown
+ * will be cancelled. Wow, quite powerful feature (:
+ */
+ gnome_interaction_key_return(key, shutdown_cancelled);
+}
+
+/*
+ * Generate a script that can be used to restore the current editing session.
+ * Save the value of v:this_session before running :mksession in order to make
+ * automagic session save fully transparent. Return TRUE on success.
+ */
+ static int
+write_session_file(char_u *filename)
+{
+ char_u *escaped_filename;
+ char *mksession_cmdline;
+ unsigned int save_ssop_flags;
+ int failed;
+
+ /*
+ * Build an ex command line to create a script that restores the current
+ * session if executed. Escape the filename to avoid nasty surprises.
+ */
+ escaped_filename = vim_strsave_escaped(filename, escape_chars);
+ if (escaped_filename == NULL)
+ return FALSE;
+ mksession_cmdline = g_strconcat("mksession ", (char *)escaped_filename,
+ NULL);
+ vim_free(escaped_filename);
+
+ /*
+ * Use a reasonable hardcoded set of 'sessionoptions' flags to avoid
+ * unpredictable effects when the session is saved automatically. Also,
+ * we definitely need SSOP_GLOBALS to be able to restore v:this_session.
+ * Don't use SSOP_BUFFERS to prevent the buffer list from becoming
+ * enormously large if the GNOME session feature is used regularly.
+ */
+ save_ssop_flags = ssop_flags;
+ ssop_flags = (SSOP_BLANK|SSOP_CURDIR|SSOP_FOLDS|SSOP_GLOBALS
+ |SSOP_HELP|SSOP_OPTIONS|SSOP_WINSIZE|SSOP_TABPAGES);
+
+ do_cmdline_cmd((char_u *)"let Save_VV_this_session = v:this_session");
+ failed = (do_cmdline_cmd((char_u *)mksession_cmdline) == FAIL);
+ do_cmdline_cmd((char_u *)"let v:this_session = Save_VV_this_session");
+ do_unlet((char_u *)"Save_VV_this_session", TRUE);
+
+ ssop_flags = save_ssop_flags;
+ g_free(mksession_cmdline);
+
+ /*
+ * Reopen the file and append a command to restore v:this_session,
+ * as if this save never happened. This is to avoid conflicts with
+ * the user's own sessions. FIXME: It's probably less hackish to add
+ * a "stealth" flag to 'sessionoptions' -- gotta ask Bram.
+ */
+ if (!failed)
+ {
+ FILE *fd;
+
+ fd = open_exfile(filename, TRUE, APPENDBIN);
+
+ failed = (fd == NULL
+ || put_line(fd, "let v:this_session = Save_VV_this_session") == FAIL
+ || put_line(fd, "unlet Save_VV_this_session") == FAIL);
+
+ if (fd != NULL && fclose(fd) != 0)
+ failed = TRUE;
+
+ if (failed)
+ mch_remove(filename);
+ }
+
+ return !failed;
+}
+
+/*
+ * "save_yourself" signal handler. Initiate an interaction to ask the user
+ * for confirmation if necessary. Save the current editing session and tell
+ * the session manager how to restart Vim.
+ */
+ static gboolean
+sm_client_save_yourself(GnomeClient *client,
+ gint phase UNUSED,
+ GnomeSaveStyle save_style UNUSED,
+ gboolean shutdown UNUSED,
+ GnomeInteractStyle interact_style,
+ gboolean fast UNUSED,
+ gpointer data UNUSED)
+{
+ static const char suffix[] = "-session.vim";
+ char *session_file;
+ unsigned int len;
+ gboolean success;
+
+ /* Always request an interaction if possible. check_changed_any()
+ * won't actually show a dialog unless any buffers have been modified.
+ * There doesn't seem to be an obvious way to check that without
+ * automatically firing the dialog. Anyway, it works just fine. */
+ if (interact_style == GNOME_INTERACT_ANY)
+ gnome_client_request_interaction(client, GNOME_DIALOG_NORMAL,
+ &sm_client_check_changed_any,
+ NULL);
+ out_flush();
+ ml_sync_all(FALSE, FALSE); /* preserve all swap files */
+
+ /* The path is unique for each session save. We do neither know nor care
+ * which session script will actually be used later. This decision is in
+ * the domain of the session manager. */
+ session_file = gnome_config_get_real_path(
+ gnome_client_get_config_prefix(client));
+ len = strlen(session_file);
+
+ if (len > 0 && session_file[len-1] == G_DIR_SEPARATOR)
+ --len; /* get rid of the superfluous trailing '/' */
+
+ session_file = g_renew(char, session_file, len + sizeof(suffix));
+ memcpy(session_file + len, suffix, sizeof(suffix));
+
+ success = write_session_file((char_u *)session_file);
+
+ if (success)
+ {
+ const char *argv[8];
+ int i;
+
+ /* Tell the session manager how to wipe out the stored session data.
+ * This isn't as dangerous as it looks, don't worry :) session_file
+ * is a unique absolute filename. Usually it'll be something like
+ * `/home/user/.gnome2/vim-XXXXXX-session.vim'. */
+ i = 0;
+ argv[i++] = "rm";
+ argv[i++] = session_file;
+ argv[i] = NULL;
+
+ gnome_client_set_discard_command(client, i, (char **)argv);
+
+ /* Tell the session manager how to restore the just saved session.
+ * This is easily done thanks to Vim's -S option. Pass the -f flag
+ * since there's no need to fork -- it might even cause confusion.
+ * Also pass the window role to give the WM something to match on.
+ * The role is set in gui_mch_open(), thus should _never_ be NULL. */
+ i = 0;
+ argv[i++] = restart_command;
+ argv[i++] = "-f";
+ argv[i++] = "-g";
+ argv[i++] = "--role";
+ argv[i++] = gtk_window_get_role(GTK_WINDOW(gui.mainwin));
+ argv[i++] = "-S";
+ argv[i++] = session_file;
+ argv[i] = NULL;
+
+ gnome_client_set_restart_command(client, i, (char **)argv);
+ gnome_client_set_clone_command(client, 0, NULL);
+ }
+
+ g_free(session_file);
+
+ return success;
+}
+
+/*
+ * Called when the session manager wants us to die. There isn't much to save
+ * here since "save_yourself" has been emitted before (unless serious trouble
+ * is happening).
+ */
+ static void
+sm_client_die(GnomeClient *client UNUSED, gpointer data UNUSED)
+{
+ /* Don't write messages to the GUI anymore */
+ full_screen = FALSE;
+
+ vim_strncpy(IObuff, (char_u *)
+ _("Vim: Received \"die\" request from session manager\n"),
+ IOSIZE - 1);
+ preserve_exit();
+}
+
+/*
+ * Connect our signal handlers to be notified on session save and shutdown.
+ */
+ static void
+setup_save_yourself(void)
+{
+ GnomeClient *client;
+
+ client = gnome_master_client();
+
+ if (client != NULL)
+ {
+ /* Must use the deprecated gtk_signal_connect() for compatibility
+ * with GNOME 1. Arrgh, zombies! */
+ gtk_signal_connect(GTK_OBJECT(client), "save_yourself",
+ GTK_SIGNAL_FUNC(&sm_client_save_yourself), NULL);
+ gtk_signal_connect(GTK_OBJECT(client), "die",
+ GTK_SIGNAL_FUNC(&sm_client_die), NULL);
+ }
+}
+
+#else /* !(FEAT_GUI_GNOME && FEAT_SESSION) */
+
+# ifdef USE_XSMP
+/*
+ * GTK tells us that XSMP needs attention
+ */
+ static gboolean
+local_xsmp_handle_requests(
+ GIOChannel *source UNUSED,
+ GIOCondition condition,
+ gpointer data)
+{
+ if (condition == G_IO_IN)
+ {
+ /* Do stuff; maybe close connection */
+ if (xsmp_handle_requests() == FAIL)
+ g_io_channel_unref((GIOChannel *)data);
+ return TRUE;
+ }
+ /* Error */
+ g_io_channel_unref((GIOChannel *)data);
+ xsmp_close();
+ return TRUE;
+}
+# endif /* USE_XSMP */
+
+/*
+ * Setup the WM_PROTOCOLS to indicate we want the WM_SAVE_YOURSELF event.
+ * This is an ugly use of X functions. GTK doesn't offer an alternative.
+ */
+ static void
+setup_save_yourself(void)
+{
+ Atom *existing_atoms = NULL;
+ int count = 0;
+
+# ifdef USE_XSMP
+ if (xsmp_icefd != -1)
+ {
+ /*
+ * Use XSMP is preference to legacy WM_SAVE_YOURSELF;
+ * set up GTK IO monitor
+ */
+ GIOChannel *g_io = g_io_channel_unix_new(xsmp_icefd);
+
+ g_io_add_watch(g_io, G_IO_IN | G_IO_ERR | G_IO_HUP,
+ local_xsmp_handle_requests, (gpointer)g_io);
+ g_io_channel_unref(g_io);
+ }
+ else
+# endif
+ {
+ /* Fall back to old method */
+
+ /* first get the existing value */
+ GdkWindow * const mainwin_win = gtk_widget_get_window(gui.mainwin);
+
+ if (XGetWMProtocols(GDK_WINDOW_XDISPLAY(mainwin_win),
+ GDK_WINDOW_XID(mainwin_win),
+ &existing_atoms, &count))
+ {
+ Atom *new_atoms;
+ Atom save_yourself_xatom;
+ int i;
+
+ save_yourself_xatom = GET_X_ATOM(save_yourself_atom);
+
+ /* check if WM_SAVE_YOURSELF isn't there yet */
+ for (i = 0; i < count; ++i)
+ if (existing_atoms[i] == save_yourself_xatom)
+ break;
+
+ if (i == count)
+ {
+ /* allocate an Atoms array which is one item longer */
+ new_atoms = (Atom *)alloc((unsigned)((count + 1)
+ * sizeof(Atom)));
+ if (new_atoms != NULL)
+ {
+ memcpy(new_atoms, existing_atoms, count * sizeof(Atom));
+ new_atoms[count] = save_yourself_xatom;
+ XSetWMProtocols(GDK_WINDOW_XDISPLAY(mainwin_win),
+ GDK_WINDOW_XID(mainwin_win),
+ new_atoms, count + 1);
+ vim_free(new_atoms);
+ }
+ }
+ XFree(existing_atoms);
+ }
+ }
+}
+
+/*
+ * Installing a global event filter seems to be the only way to catch
+ * client messages of type WM_PROTOCOLS without overriding GDK's own
+ * client message event filter. Well, that's still better than trying
+ * to guess what the GDK filter had done if it had been invoked instead
+ *
+ * GTK2_FIXME: This doesn't seem to work. For some reason we never
+ * receive WM_SAVE_YOURSELF even though everything is set up correctly.
+ * I have the nasty feeling modern session managers just don't send this
+ * deprecated message anymore. Addition: confirmed by several people.
+ *
+ * The GNOME session support is much cooler anyway. Unlike this ugly
+ * WM_SAVE_YOURSELF hack it actually stores the session... And yes,
+ * it should work with KDE as well.
+ */
+ static GdkFilterReturn
+global_event_filter(GdkXEvent *xev,
+ GdkEvent *event UNUSED,
+ gpointer data UNUSED)
+{
+ XEvent *xevent = (XEvent *)xev;
+
+ if (xevent != NULL
+ && xevent->type == ClientMessage
+ && xevent->xclient.message_type == GET_X_ATOM(wm_protocols_atom)
+ && (long_u)xevent->xclient.data.l[0]
+ == GET_X_ATOM(save_yourself_atom))
+ {
+ out_flush();
+ ml_sync_all(FALSE, FALSE); /* preserve all swap files */
+ /*
+ * Set the window's WM_COMMAND property, to let the window manager
+ * know we are done saving ourselves. We don't want to be
+ * restarted, thus set argv to NULL.
+ */
+ XSetCommand(GDK_WINDOW_XDISPLAY(gtk_widget_get_window(gui.mainwin)),
+ GDK_WINDOW_XID(gtk_widget_get_window(gui.mainwin)),
+ NULL, 0);
+ return GDK_FILTER_REMOVE;
+ }
+
+ return GDK_FILTER_CONTINUE;
+}
+#endif /* !(FEAT_GUI_GNOME && FEAT_SESSION) */
+
+
+/*
+ * Setup the window icon & xcmdsrv comm after the main window has been realized.
+ */
+ static void
+mainwin_realize(GtkWidget *widget UNUSED, gpointer data UNUSED)
+{
+/* If you get an error message here, you still need to unpack the runtime
+ * archive! */
+#ifdef magick
+# undef magick
+#endif
+ /* A bit hackish, but avoids casting later and allows optimization */
+# define static static const
+#define magick vim32x32
+#include "../runtime/vim32x32.xpm"
+#undef magick
+#define magick vim16x16
+#include "../runtime/vim16x16.xpm"
+#undef magick
+#define magick vim48x48
+#include "../runtime/vim48x48.xpm"
+#undef magick
+# undef static
+
+ GdkWindow * const mainwin_win = gtk_widget_get_window(gui.mainwin);
+
+ /* When started with "--echo-wid" argument, write window ID on stdout. */
+ if (echo_wid_arg)
+ {
+ printf("WID: %ld\n", (long)GDK_WINDOW_XID(mainwin_win));
+ fflush(stdout);
+ }
+
+ if (vim_strchr(p_go, GO_ICON) != NULL)
+ {
+ /*
+ * Add an icon to the main window. For fun and convenience of the user.
+ */
+ GList *icons = NULL;
+
+ icons = g_list_prepend(icons, gdk_pixbuf_new_from_xpm_data(vim16x16));
+ icons = g_list_prepend(icons, gdk_pixbuf_new_from_xpm_data(vim32x32));
+ icons = g_list_prepend(icons, gdk_pixbuf_new_from_xpm_data(vim48x48));
+
+ gtk_window_set_icon_list(GTK_WINDOW(gui.mainwin), icons);
+
+ g_list_foreach(icons, (GFunc)&g_object_unref, NULL);
+ g_list_free(icons);
+ }
+
+#if !(defined(FEAT_GUI_GNOME) && defined(FEAT_SESSION))
+ /* Register a handler for WM_SAVE_YOURSELF with GDK's low-level X I/F */
+ gdk_window_add_filter(NULL, &global_event_filter, NULL);
+#endif
+ /* Setup to indicate to the window manager that we want to catch the
+ * WM_SAVE_YOURSELF event. For GNOME, this connects to the session
+ * manager instead. */
+#if defined(FEAT_GUI_GNOME) && defined(FEAT_SESSION)
+ if (using_gnome)
+#endif
+ setup_save_yourself();
+
+#ifdef FEAT_CLIENTSERVER
+ if (serverName == NULL && serverDelayedStartName != NULL)
+ {
+ /* This is a :gui command in a plain vim with no previous server */
+ commWindow = GDK_WINDOW_XID(mainwin_win);
+
+ (void)serverRegisterName(GDK_WINDOW_XDISPLAY(mainwin_win),
+ serverDelayedStartName);
+ }
+ else
+ {
+ /*
+ * Cannot handle "XLib-only" windows with gtk event routines, we'll
+ * have to change the "server" registration to that of the main window
+ * If we have not registered a name yet, remember the window.
+ */
+ serverChangeRegisteredWindow(GDK_WINDOW_XDISPLAY(mainwin_win),
+ GDK_WINDOW_XID(mainwin_win));
+ }
+ gtk_widget_add_events(gui.mainwin, GDK_PROPERTY_CHANGE_MASK);
+ g_signal_connect(G_OBJECT(gui.mainwin), "property-notify-event",
+ G_CALLBACK(property_event), NULL);
+#endif
+}
+
+ static GdkCursor *
+create_blank_pointer(void)
+{
+ GdkWindow *root_window = NULL;
+#if GTK_CHECK_VERSION(3,0,0)
+ GdkPixbuf *blank_mask;
+#else
+ GdkPixmap *blank_mask;
+#endif
+ GdkCursor *cursor;
+#if GTK_CHECK_VERSION(3,0,0)
+ GdkRGBA color = { 0.0, 0.0, 0.0, 1.0 };
+#else
+ GdkColor color = { 0, 0, 0, 0 };
+ char blank_data[] = { 0x0 };
+#endif
+
+#if GTK_CHECK_VERSION(3,12,0)
+ {
+ GdkWindow * const win = gtk_widget_get_window(gui.mainwin);
+ GdkScreen * const scrn = gdk_window_get_screen(win);
+ root_window = gdk_screen_get_root_window(scrn);
+ }
+#else
+ root_window = gtk_widget_get_root_window(gui.mainwin);
+#endif
+
+ /* Create a pseudo blank pointer, which is in fact one pixel by one pixel
+ * in size. */
+#if GTK_CHECK_VERSION(3,0,0)
+ {
+ cairo_surface_t *surf;
+ cairo_t *cr;
+
+ surf = cairo_image_surface_create(CAIRO_FORMAT_A1, 1, 1);
+ cr = cairo_create(surf);
+
+ cairo_set_source_rgba(cr,
+ color.red,
+ color.green,
+ color.blue,
+ color.alpha);
+ cairo_rectangle(cr, 0, 0, 1, 1);
+ cairo_fill(cr);
+ cairo_destroy(cr);
+
+ blank_mask = gdk_pixbuf_get_from_surface(surf, 0, 0, 1, 1);
+ cairo_surface_destroy(surf);
+
+ cursor = gdk_cursor_new_from_pixbuf(gdk_window_get_display(root_window),
+ blank_mask, 0, 0);
+ g_object_unref(blank_mask);
+ }
+#else
+ blank_mask = gdk_bitmap_create_from_data(root_window, blank_data, 1, 1);
+ cursor = gdk_cursor_new_from_pixmap(blank_mask, blank_mask,
+ &color, &color, 0, 0);
+ gdk_bitmap_unref(blank_mask);
+#endif
+
+ return cursor;
+}
+
+ static void
+mainwin_screen_changed_cb(GtkWidget *widget,
+ GdkScreen *previous_screen UNUSED,
+ gpointer data UNUSED)
+{
+ if (!gtk_widget_has_screen(widget))
+ return;
+
+ /*
+ * Recreate the invisible mouse cursor.
+ */
+ if (gui.blank_pointer != NULL)
+#if GTK_CHECK_VERSION(3,0,0)
+ g_object_unref(G_OBJECT(gui.blank_pointer));
+#else
+ gdk_cursor_unref(gui.blank_pointer);
+#endif
+
+ gui.blank_pointer = create_blank_pointer();
+
+ if (gui.pointer_hidden && gtk_widget_get_window(gui.drawarea) != NULL)
+ gdk_window_set_cursor(gtk_widget_get_window(gui.drawarea),
+ gui.blank_pointer);
+
+ /*
+ * Create a new PangoContext for this screen, and initialize it
+ * with the current font if necessary.
+ */
+ if (gui.text_context != NULL)
+ g_object_unref(gui.text_context);
+
+ gui.text_context = gtk_widget_create_pango_context(widget);
+ pango_context_set_base_dir(gui.text_context, PANGO_DIRECTION_LTR);
+
+ if (gui.norm_font != NULL)
+ {
+ gui_mch_init_font(p_guifont, FALSE);
+ gui_set_shellsize(TRUE, FALSE, RESIZE_BOTH);
+ }
+}
+
+/*
+ * After the drawing area comes up, we calculate all colors and create the
+ * dummy blank cursor.
+ *
+ * Don't try to set any VIM scrollbar sizes anywhere here. I'm relying on the
+ * fact that the main VIM engine doesn't take them into account anywhere.
+ */
+ static void
+drawarea_realize_cb(GtkWidget *widget, gpointer data UNUSED)
+{
+ GtkWidget *sbar;
+ GtkAllocation allocation;
+
+#ifdef FEAT_XIM
+ xim_init();
+#endif
+ gui_mch_new_colors();
+#if GTK_CHECK_VERSION(3,0,0)
+ gui.surface = gdk_window_create_similar_surface(
+ gtk_widget_get_window(widget),
+ CAIRO_CONTENT_COLOR_ALPHA,
+ gtk_widget_get_allocated_width(widget),
+ gtk_widget_get_allocated_height(widget));
+#else
+ gui.text_gc = gdk_gc_new(gui.drawarea->window);
+#endif
+
+ gui.blank_pointer = create_blank_pointer();
+ if (gui.pointer_hidden)
+ gdk_window_set_cursor(gtk_widget_get_window(widget), gui.blank_pointer);
+
+ /* get the actual size of the scrollbars, if they are realized */
+ sbar = firstwin->w_scrollbars[SBAR_LEFT].id;
+ if (!sbar || (!gui.which_scrollbars[SBAR_LEFT]
+ && firstwin->w_scrollbars[SBAR_RIGHT].id))
+ sbar = firstwin->w_scrollbars[SBAR_RIGHT].id;
+ gtk_widget_get_allocation(sbar, &allocation);
+ if (sbar && gtk_widget_get_realized(sbar) && allocation.width)
+ gui.scrollbar_width = allocation.width;
+
+ sbar = gui.bottom_sbar.id;
+ if (sbar && gtk_widget_get_realized(sbar) && allocation.height)
+ gui.scrollbar_height = allocation.height;
+}
+
+/*
+ * Properly clean up on shutdown.
+ */
+ static void
+drawarea_unrealize_cb(GtkWidget *widget UNUSED, gpointer data UNUSED)
+{
+ /* Don't write messages to the GUI anymore */
+ full_screen = FALSE;
+
+#ifdef FEAT_XIM
+ im_shutdown();
+#endif
+ if (gui.ascii_glyphs != NULL)
+ {
+ pango_glyph_string_free(gui.ascii_glyphs);
+ gui.ascii_glyphs = NULL;
+ }
+ if (gui.ascii_font != NULL)
+ {
+ g_object_unref(gui.ascii_font);
+ gui.ascii_font = NULL;
+ }
+ g_object_unref(gui.text_context);
+ gui.text_context = NULL;
+
+#if GTK_CHECK_VERSION(3,0,0)
+ if (gui.surface != NULL)
+ {
+ cairo_surface_destroy(gui.surface);
+ gui.surface = NULL;
+ }
+#else
+ g_object_unref(gui.text_gc);
+ gui.text_gc = NULL;
+#endif
+
+#if GTK_CHECK_VERSION(3,0,0)
+ g_object_unref(G_OBJECT(gui.blank_pointer));
+#else
+ gdk_cursor_unref(gui.blank_pointer);
+#endif
+ gui.blank_pointer = NULL;
+}
+
+#if GTK_CHECK_VERSION(3,22,2)
+ static void
+drawarea_style_updated_cb(GtkWidget *widget UNUSED,
+ gpointer data UNUSED)
+#else
+ static void
+drawarea_style_set_cb(GtkWidget *widget UNUSED,
+ GtkStyle *previous_style UNUSED,
+ gpointer data UNUSED)
+#endif
+{
+ gui_mch_new_colors();
+}
+
+#if GTK_CHECK_VERSION(3,0,0)
+ static gboolean
+drawarea_configure_event_cb(GtkWidget *widget,
+ GdkEventConfigure *event,
+ gpointer data UNUSED)
+{
+ static int cur_width = 0;
+ static int cur_height = 0;
+
+ g_return_val_if_fail(event
+ && event->width >= 1 && event->height >= 1, TRUE);
+
+# if GTK_CHECK_VERSION(3,22,2) && !GTK_CHECK_VERSION(3,22,4)
+ /* As of 3.22.2, GdkWindows have started distributing configure events to
+ * their "native" children (https://git.gnome.org/browse/gtk+/commit/?h=gtk-3-22&id=12579fe71b3b8f79eb9c1b80e429443bcc437dd0).
+ *
+ * As can be seen from the implementation of move_native_children() and
+ * configure_native_child() in gdkwindow.c, those functions actually
+ * propagate configure events to every child, failing to distinguish
+ * "native" one from non-native one.
+ *
+ * Naturally, configure events propagated to here like that are fallacious
+ * and, as a matter of fact, they trigger a geometric collapse of
+ * gui.drawarea in fullscreen and miximized modes.
+ *
+ * To filter out such nuisance events, we are making use of the fact that
+ * the field send_event of such GdkEventConfigures is set to FALSE in
+ * configure_native_child().
+ *
+ * Obviously, this is a terrible hack making GVim depend on GTK's
+ * implementation details. Therefore, watch out any relevant internal
+ * changes happening in GTK in the feature (sigh).
+ */
+ /* Follow-up
+ * After a few weeks later, the GdkWindow change mentioned above was
+ * reverted (https://git.gnome.org/browse/gtk+/commit/?h=gtk-3-22&id=f70039cb9603a02d2369fec4038abf40a1711155).
+ * The corresponding official release is 3.22.4. */
+ if (event->send_event == FALSE)
+ return TRUE;
+# endif
+
+ if (event->width == cur_width && event->height == cur_height)
+ return TRUE;
+
+ cur_width = event->width;
+ cur_height = event->height;
+
+ if (gui.surface != NULL)
+ cairo_surface_destroy(gui.surface);
+
+ gui.surface = gdk_window_create_similar_surface(
+ gtk_widget_get_window(widget),
+ CAIRO_CONTENT_COLOR_ALPHA,
+ event->width, event->height);
+
+ gtk_widget_queue_draw(widget);
+
+ return TRUE;
+}
+#endif
+
+/*
+ * Callback routine for the "delete_event" signal on the toplevel window.
+ * Tries to vim gracefully, or refuses to exit with changed buffers.
+ */
+ static gint
+delete_event_cb(GtkWidget *widget UNUSED,
+ GdkEventAny *event UNUSED,
+ gpointer data UNUSED)
+{
+ gui_shell_closed();
+ return TRUE;
+}
+
+#if defined(FEAT_MENU) || defined(FEAT_TOOLBAR) || defined(FEAT_GUI_TABLINE)
+ static int
+get_item_dimensions(GtkWidget *widget, GtkOrientation orientation)
+{
+# ifdef FEAT_GUI_GNOME
+ GtkOrientation item_orientation = GTK_ORIENTATION_HORIZONTAL;
+
+ if (using_gnome && widget != NULL)
+ {
+ GtkWidget *parent;
+ BonoboDockItem *dockitem;
+
+ parent = gtk_widget_get_parent(widget);
+ if (G_TYPE_FROM_INSTANCE(parent) == BONOBO_TYPE_DOCK_ITEM)
+ {
+ /* Only menu & toolbar are dock items. Could tabline be?
+ * Seem to be only the 2 defined in GNOME */
+ widget = parent;
+ dockitem = BONOBO_DOCK_ITEM(widget);
+
+ if (dockitem == NULL || dockitem->is_floating)
+ return 0;
+ item_orientation = bonobo_dock_item_get_orientation(dockitem);
+ }
+ }
+# else
+# define item_orientation GTK_ORIENTATION_HORIZONTAL
+# endif
+
+ if (widget != NULL
+ && item_orientation == orientation
+ && gtk_widget_get_realized(widget)
+ && gtk_widget_get_visible(widget))
+ {
+# if GTK_CHECK_VERSION(3,0,0) || !defined(FEAT_GUI_GNOME)
+ GtkAllocation allocation;
+
+ gtk_widget_get_allocation(widget, &allocation);
+ return allocation.height;
+# else
+ if (orientation == GTK_ORIENTATION_HORIZONTAL)
+ return widget->allocation.height;
+ else
+ return widget->allocation.width;
+# endif
+ }
+ return 0;
+}
+#endif
+
+ static int
+get_menu_tool_width(void)
+{
+ int width = 0;
+
+#ifdef FEAT_GUI_GNOME /* these are never vertical without GNOME */
+# ifdef FEAT_MENU
+ width += get_item_dimensions(gui.menubar, GTK_ORIENTATION_VERTICAL);
+# endif
+# ifdef FEAT_TOOLBAR
+ width += get_item_dimensions(gui.toolbar, GTK_ORIENTATION_VERTICAL);
+# endif
+# ifdef FEAT_GUI_TABLINE
+ if (gui.tabline != NULL)
+ width += get_item_dimensions(gui.tabline, GTK_ORIENTATION_VERTICAL);
+# endif
+#endif
+
+ return width;
+}
+
+ static int
+get_menu_tool_height(void)
+{
+ int height = 0;
+
+#ifdef FEAT_MENU
+ height += get_item_dimensions(gui.menubar, GTK_ORIENTATION_HORIZONTAL);
+#endif
+#ifdef FEAT_TOOLBAR
+ height += get_item_dimensions(gui.toolbar, GTK_ORIENTATION_HORIZONTAL);
+#endif
+#ifdef FEAT_GUI_TABLINE
+ if (gui.tabline != NULL)
+ height += get_item_dimensions(gui.tabline, GTK_ORIENTATION_HORIZONTAL);
+#endif
+
+ return height;
+}
+
+/* This controls whether we can set the real window hints at
+ * start-up when in a GtkPlug.
+ * 0 = normal processing (default)
+ * 1 = init. hints set, no-one's tried to reset since last check
+ * 2 = init. hints set, attempt made to change hints
+ */
+static int init_window_hints_state = 0;
+
+ static void
+update_window_manager_hints(int force_width, int force_height)
+{
+ static int old_width = 0;
+ static int old_height = 0;
+ static int old_min_width = 0;
+ static int old_min_height = 0;
+ static int old_char_width = 0;
+ static int old_char_height = 0;
+
+ int width;
+ int height;
+ int min_width;
+ int min_height;
+
+ /* At start-up, don't try to set the hints until the initial
+ * values have been used (those that dictate our initial size)
+ * Let forced (i.e., correct) values through always.
+ */
+ if (!(force_width && force_height) && init_window_hints_state > 0)
+ {
+ /* Don't do it! */
+ init_window_hints_state = 2;
+ return;
+ }
+
+ /* This also needs to be done when the main window isn't there yet,
+ * otherwise the hints don't work. */
+ width = gui_get_base_width();
+ height = gui_get_base_height();
+# ifdef FEAT_MENU
+ height += tabline_height() * gui.char_height;
+# endif
+ width += get_menu_tool_width();
+ height += get_menu_tool_height();
+
+ /* GtkSockets use GtkPlug's [gui,mainwin] min-size hints to determine
+ * their actual widget size. When we set our size ourselves (e.g.,
+ * 'set columns=' or init. -geom) we briefly set the min. to the size
+ * we wish to be instead of the legitimate minimum so that we actually
+ * resize correctly.
+ */
+ if (force_width && force_height)
+ {
+ min_width = force_width;
+ min_height = force_height;
+ }
+ else
+ {
+ min_width = width + MIN_COLUMNS * gui.char_width;
+ min_height = height + MIN_LINES * gui.char_height;
+ }
+
+ /* Avoid an expose event when the size didn't change. */
+ if (width != old_width
+ || height != old_height
+ || min_width != old_min_width
+ || min_height != old_min_height
+ || gui.char_width != old_char_width
+ || gui.char_height != old_char_height)
+ {
+ GdkGeometry geometry;
+ GdkWindowHints geometry_mask;
+
+ geometry.width_inc = gui.char_width;
+ geometry.height_inc = gui.char_height;
+ geometry.base_width = width;
+ geometry.base_height = height;
+ geometry.min_width = min_width;
+ geometry.min_height = min_height;
+ geometry_mask = GDK_HINT_BASE_SIZE|GDK_HINT_RESIZE_INC
+ |GDK_HINT_MIN_SIZE;
+ /* Using gui.formwin as geometry widget doesn't work as expected
+ * with GTK+ 2 -- dunno why. Presumably all the resizing hacks
+ * in Vim confuse GTK+. */
+ gtk_window_set_geometry_hints(GTK_WINDOW(gui.mainwin), gui.mainwin,
+ &geometry, geometry_mask);
+ old_width = width;
+ old_height = height;
+ old_min_width = min_width;
+ old_min_height = min_height;
+ old_char_width = gui.char_width;
+ old_char_height = gui.char_height;
+ }
+}
+
+#ifdef FEAT_TOOLBAR
+
+/*
+ * This extra effort wouldn't be necessary if we only used stock icons in the
+ * toolbar, as we do for all builtin icons. But user-defined toolbar icons
+ * shouldn't be treated differently, thus we do need this.
+ */
+ static void
+icon_size_changed_foreach(GtkWidget *widget, gpointer user_data)
+{
+ if (GTK_IS_IMAGE(widget))
+ {
+ GtkImage *image = (GtkImage *)widget;
+
+# if GTK_CHECK_VERSION(3,10,0)
+ if (gtk_image_get_storage_type(image) == GTK_IMAGE_ICON_NAME)
+ {
+ const GtkIconSize icon_size = GPOINTER_TO_INT(user_data);
+ const gchar *icon_name;
+
+ gtk_image_get_icon_name(image, &icon_name, NULL);
+
+ gtk_image_set_from_icon_name(image, icon_name, icon_size);
+ }
+# else
+ /* User-defined icons are stored in a GtkIconSet */
+ if (gtk_image_get_storage_type(image) == GTK_IMAGE_ICON_SET)
+ {
+ GtkIconSet *icon_set;
+ GtkIconSize icon_size;
+
+ gtk_image_get_icon_set(image, &icon_set, &icon_size);
+ icon_size = (GtkIconSize)(long)user_data;
+
+ gtk_icon_set_ref(icon_set);
+ gtk_image_set_from_icon_set(image, icon_set, icon_size);
+ gtk_icon_set_unref(icon_set);
+ }
+# endif
+ }
+ else if (GTK_IS_CONTAINER(widget))
+ {
+ gtk_container_foreach((GtkContainer *)widget,
+ &icon_size_changed_foreach,
+ user_data);
+ }
+}
+
+ static void
+set_toolbar_style(GtkToolbar *toolbar)
+{
+ GtkToolbarStyle style;
+ GtkIconSize size;
+ GtkIconSize oldsize;
+
+ if ((toolbar_flags & (TOOLBAR_TEXT | TOOLBAR_ICONS | TOOLBAR_HORIZ))
+ == (TOOLBAR_TEXT | TOOLBAR_ICONS | TOOLBAR_HORIZ))
+ style = GTK_TOOLBAR_BOTH_HORIZ;
+ else if ((toolbar_flags & (TOOLBAR_TEXT | TOOLBAR_ICONS))
+ == (TOOLBAR_TEXT | TOOLBAR_ICONS))
+ style = GTK_TOOLBAR_BOTH;
+ else if (toolbar_flags & TOOLBAR_TEXT)
+ style = GTK_TOOLBAR_TEXT;
+ else
+ style = GTK_TOOLBAR_ICONS;
+
+ gtk_toolbar_set_style(toolbar, style);
+# if !GTK_CHECK_VERSION(3,0,0)
+ gtk_toolbar_set_tooltips(toolbar, (toolbar_flags & TOOLBAR_TOOLTIPS) != 0);
+# endif
+
+ switch (tbis_flags)
+ {
+ case TBIS_TINY: size = GTK_ICON_SIZE_MENU; break;
+ case TBIS_SMALL: size = GTK_ICON_SIZE_SMALL_TOOLBAR; break;
+ case TBIS_MEDIUM: size = GTK_ICON_SIZE_BUTTON; break;
+ case TBIS_LARGE: size = GTK_ICON_SIZE_LARGE_TOOLBAR; break;
+ case TBIS_HUGE: size = GTK_ICON_SIZE_DND; break;
+ case TBIS_GIANT: size = GTK_ICON_SIZE_DIALOG; break;
+ default: size = GTK_ICON_SIZE_INVALID; break;
+ }
+ oldsize = gtk_toolbar_get_icon_size(toolbar);
+
+ if (size == GTK_ICON_SIZE_INVALID)
+ {
+ /* Let global user preferences decide the icon size. */
+ gtk_toolbar_unset_icon_size(toolbar);
+ size = gtk_toolbar_get_icon_size(toolbar);
+ }
+ if (size != oldsize)
+ {
+ gtk_container_foreach(GTK_CONTAINER(toolbar),
+ &icon_size_changed_foreach,
+ GINT_TO_POINTER((int)size));
+ }
+ gtk_toolbar_set_icon_size(toolbar, size);
+}
+
+#endif /* FEAT_TOOLBAR */
+
+#if defined(FEAT_GUI_TABLINE) || defined(PROTO)
+static int ignore_tabline_evt = FALSE;
+static GtkWidget *tabline_menu;
+# if !GTK_CHECK_VERSION(3,0,0)
+static GtkTooltips *tabline_tooltip;
+# endif
+static int clicked_page; /* page clicked in tab line */
+
+/*
+ * Handle selecting an item in the tab line popup menu.
+ */
+ static void
+tabline_menu_handler(GtkMenuItem *item UNUSED, gpointer user_data)
+{
+ /* Add the string cmd into input buffer */
+ send_tabline_menu_event(clicked_page, (int)(long)user_data);
+}
+
+ static void
+add_tabline_menu_item(GtkWidget *menu, char_u *text, int resp)
+{
+ GtkWidget *item;
+ char_u *utf_text;
+
+ utf_text = CONVERT_TO_UTF8(text);
+ item = gtk_menu_item_new_with_label((const char *)utf_text);
+ gtk_widget_show(item);
+ CONVERT_TO_UTF8_FREE(utf_text);
+
+ gtk_container_add(GTK_CONTAINER(menu), item);
+ g_signal_connect(G_OBJECT(item), "activate",
+ G_CALLBACK(tabline_menu_handler),
+ GINT_TO_POINTER(resp));
+}
+
+/*
+ * Create a menu for the tab line.
+ */
+ static GtkWidget *
+create_tabline_menu(void)
+{
+ GtkWidget *menu;
+
+ menu = gtk_menu_new();
+ add_tabline_menu_item(menu, (char_u *)_("Close tab"), TABLINE_MENU_CLOSE);
+ add_tabline_menu_item(menu, (char_u *)_("New tab"), TABLINE_MENU_NEW);
+ add_tabline_menu_item(menu, (char_u *)_("Open Tab..."), TABLINE_MENU_OPEN);
+
+ return menu;
+}
+
+ static gboolean
+on_tabline_menu(GtkWidget *widget, GdkEvent *event)
+{
+ /* Was this button press event ? */
+ if (event->type == GDK_BUTTON_PRESS)
+ {
+ GdkEventButton *bevent = (GdkEventButton *)event;
+ int x = bevent->x;
+ int y = bevent->y;
+ GtkWidget *tabwidget;
+ GdkWindow *tabwin;
+
+ /* When ignoring events return TRUE so that the selected page doesn't
+ * change. */
+ if (hold_gui_events
+# ifdef FEAT_CMDWIN
+ || cmdwin_type != 0
+# endif
+ )
+ return TRUE;
+
+ tabwin = gui_gtk_window_at_position(gui.mainwin, &x, &y);
+
+ gdk_window_get_user_data(tabwin, (gpointer)&tabwidget);
+ clicked_page = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(tabwidget),
+ "tab_num"));
+
+ /* If the event was generated for 3rd button popup the menu. */
+ if (bevent->button == 3)
+ {
+# if GTK_CHECK_VERSION(3,22,2)
+ gtk_menu_popup_at_pointer(GTK_MENU(widget), event);
+# else
+ gtk_menu_popup(GTK_MENU(widget), NULL, NULL, NULL, NULL,
+ bevent->button, bevent->time);
+# endif
+ /* We handled the event. */
+ return TRUE;
+ }
+ else if (bevent->button == 1)
+ {
+ if (clicked_page == 0)
+ {
+ /* Click after all tabs moves to next tab page. When "x" is
+ * small guess it's the left button. */
+ send_tabline_event(x < 50 ? -1 : 0);
+ }
+ }
+ }
+
+ /* We didn't handle the event. */
+ return FALSE;
+}
+
+/*
+ * Handle selecting one of the tabs.
+ */
+ static void
+on_select_tab(
+ GtkNotebook *notebook UNUSED,
+ gpointer *page UNUSED,
+ gint idx,
+ gpointer data UNUSED)
+{
+ if (!ignore_tabline_evt)
+ send_tabline_event(idx + 1);
+}
+
+# if GTK_CHECK_VERSION(2,10,0)
+/*
+ * Handle reordering the tabs (using D&D).
+ */
+ static void
+on_tab_reordered(
+ GtkNotebook *notebook UNUSED,
+ gpointer *page UNUSED,
+ gint idx,
+ gpointer data UNUSED)
+{
+ if (!ignore_tabline_evt)
+ {
+ if ((tabpage_index(curtab) - 1) < idx)
+ tabpage_move(idx + 1);
+ else
+ tabpage_move(idx);
+ }
+}
+# endif
+
+/*
+ * Show or hide the tabline.
+ */
+ void
+gui_mch_show_tabline(int showit)
+{
+ if (gui.tabline == NULL)
+ return;
+
+ if (!showit != !gtk_notebook_get_show_tabs(GTK_NOTEBOOK(gui.tabline)))
+ {
+ /* Note: this may cause a resize event */
+ gtk_notebook_set_show_tabs(GTK_NOTEBOOK(gui.tabline), showit);
+ update_window_manager_hints(0, 0);
+ if (showit)
+ gtk_widget_set_can_focus(GTK_WIDGET(gui.tabline), FALSE);
+ }
+
+ gui_mch_update();
+}
+
+/*
+ * Return TRUE when tabline is displayed.
+ */
+ int
+gui_mch_showing_tabline(void)
+{
+ return gui.tabline != NULL
+ && gtk_notebook_get_show_tabs(GTK_NOTEBOOK(gui.tabline));
+}
+
+/*
+ * Update the labels of the tabline.
+ */
+ void
+gui_mch_update_tabline(void)
+{
+ GtkWidget *page;
+ GtkWidget *event_box;
+ GtkWidget *label;
+ tabpage_T *tp;
+ int nr = 0;
+ int tab_num;
+ int curtabidx = 0;
+ char_u *labeltext;
+
+ if (gui.tabline == NULL)
+ return;
+
+ ignore_tabline_evt = TRUE;
+
+ /* Add a label for each tab page. They all contain the same text area. */
+ for (tp = first_tabpage; tp != NULL; tp = tp->tp_next, ++nr)
+ {
+ if (tp == curtab)
+ curtabidx = nr;
+
+ tab_num = nr + 1;
+
+ page = gtk_notebook_get_nth_page(GTK_NOTEBOOK(gui.tabline), nr);
+ if (page == NULL)
+ {
+ /* Add notebook page */
+# if GTK_CHECK_VERSION(3,2,0)
+ page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
+ gtk_box_set_homogeneous(GTK_BOX(page), FALSE);
+# else
+ page = gtk_vbox_new(FALSE, 0);
+# endif
+ gtk_widget_show(page);
+ event_box = gtk_event_box_new();
+ gtk_widget_show(event_box);
+ label = gtk_label_new("-Empty-");
+# if !GTK_CHECK_VERSION(3,14,0)
+ gtk_misc_set_padding(GTK_MISC(label), 2, 2);
+# endif
+ gtk_container_add(GTK_CONTAINER(event_box), label);
+ gtk_widget_show(label);
+ gtk_notebook_insert_page(GTK_NOTEBOOK(gui.tabline),
+ page,
+ event_box,
+ nr++);
+# if GTK_CHECK_VERSION(2,10,0)
+ gtk_notebook_set_tab_reorderable(GTK_NOTEBOOK(gui.tabline),
+ page,
+ TRUE);
+# endif
+ }
+
+ event_box = gtk_notebook_get_tab_label(GTK_NOTEBOOK(gui.tabline), page);
+ g_object_set_data(G_OBJECT(event_box), "tab_num",
+ GINT_TO_POINTER(tab_num));
+ label = gtk_bin_get_child(GTK_BIN(event_box));
+ get_tabline_label(tp, FALSE);
+ labeltext = CONVERT_TO_UTF8(NameBuff);
+ gtk_label_set_text(GTK_LABEL(label), (const char *)labeltext);
+ CONVERT_TO_UTF8_FREE(labeltext);
+
+ get_tabline_label(tp, TRUE);
+ labeltext = CONVERT_TO_UTF8(NameBuff);
+# if GTK_CHECK_VERSION(3,0,0)
+ gtk_widget_set_tooltip_text(event_box, (const gchar *)labeltext);
+# else
+ gtk_tooltips_set_tip(GTK_TOOLTIPS(tabline_tooltip), event_box,
+ (const char *)labeltext, NULL);
+# endif
+ CONVERT_TO_UTF8_FREE(labeltext);
+ }
+
+ /* Remove any old labels. */
+ while (gtk_notebook_get_nth_page(GTK_NOTEBOOK(gui.tabline), nr) != NULL)
+ gtk_notebook_remove_page(GTK_NOTEBOOK(gui.tabline), nr);
+
+ if (gtk_notebook_get_current_page(GTK_NOTEBOOK(gui.tabline)) != curtabidx)
+ gtk_notebook_set_current_page(GTK_NOTEBOOK(gui.tabline), curtabidx);
+
+ /* Make sure everything is in place before drawing text. */
+ gui_mch_update();
+
+ ignore_tabline_evt = FALSE;
+}
+
+/*
+ * Set the current tab to "nr". First tab is 1.
+ */
+ void
+gui_mch_set_curtab(int nr)
+{
+ if (gui.tabline == NULL)
+ return;
+
+ ignore_tabline_evt = TRUE;
+ if (gtk_notebook_get_current_page(GTK_NOTEBOOK(gui.tabline)) != nr - 1)
+ gtk_notebook_set_current_page(GTK_NOTEBOOK(gui.tabline), nr - 1);
+ ignore_tabline_evt = FALSE;
+}
+
+#endif /* FEAT_GUI_TABLINE */
+
+/*
+ * Add selection targets for PRIMARY and CLIPBOARD selections.
+ */
+ void
+gui_gtk_set_selection_targets(void)
+{
+ int i, j = 0;
+ int n_targets = N_SELECTION_TARGETS;
+ GtkTargetEntry targets[N_SELECTION_TARGETS];
+
+ for (i = 0; i < (int)N_SELECTION_TARGETS; ++i)
+ {
+ /* OpenOffice tries to use TARGET_HTML and fails when we don't
+ * return something, instead of trying another target. Therefore only
+ * offer TARGET_HTML when it works. */
+ if (!clip_html && selection_targets[i].info == TARGET_HTML)
+ n_targets--;
+ else
+ targets[j++] = selection_targets[i];
+ }
+
+ gtk_selection_clear_targets(gui.drawarea, (GdkAtom)GDK_SELECTION_PRIMARY);
+ gtk_selection_clear_targets(gui.drawarea, (GdkAtom)clip_plus.gtk_sel_atom);
+ gtk_selection_add_targets(gui.drawarea,
+ (GdkAtom)GDK_SELECTION_PRIMARY,
+ targets, n_targets);
+ gtk_selection_add_targets(gui.drawarea,
+ (GdkAtom)clip_plus.gtk_sel_atom,
+ targets, n_targets);
+}
+
+/*
+ * Set up for receiving DND items.
+ */
+ void
+gui_gtk_set_dnd_targets(void)
+{
+ int i, j = 0;
+ int n_targets = N_DND_TARGETS;
+ GtkTargetEntry targets[N_DND_TARGETS];
+
+ for (i = 0; i < (int)N_DND_TARGETS; ++i)
+ {
+ if (!clip_html && dnd_targets[i].info == TARGET_HTML)
+ n_targets--;
+ else
+ targets[j++] = dnd_targets[i];
+ }
+
+ gtk_drag_dest_unset(gui.drawarea);
+ gtk_drag_dest_set(gui.drawarea,
+ GTK_DEST_DEFAULT_ALL,
+ targets, n_targets,
+ GDK_ACTION_COPY | GDK_ACTION_MOVE);
+}
+
+/*
+ * Initialize the GUI. Create all the windows, set up all the callbacks etc.
+ * Returns OK for success, FAIL when the GUI can't be started.
+ */
+ int
+gui_mch_init(void)
+{
+ GtkWidget *vbox;
+
+#ifdef FEAT_GUI_GNOME
+ /* Initialize the GNOME libraries. gnome_program_init()/gnome_init()
+ * exits on failure, but that's a non-issue because we already called
+ * gtk_init_check() in gui_mch_init_check(). */
+ if (using_gnome)
+ {
+ gnome_program_init(VIMPACKAGE, VIM_VERSION_SHORT,
+ LIBGNOMEUI_MODULE, gui_argc, gui_argv, NULL);
+# if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
+ {
+ char *p = setlocale(LC_NUMERIC, NULL);
+
+ /* Make sure strtod() uses a decimal point, not a comma. Gnome
+ * init may change it. */
+ if (p == NULL || strcmp(p, "C") != 0)
+ setlocale(LC_NUMERIC, "C");
+ }
+# endif
+ }
+#endif
+ VIM_CLEAR(gui_argv);
+
+#if GLIB_CHECK_VERSION(2,1,3)
+ /* Set the human-readable application name */
+ g_set_application_name("Vim");
+#endif
+ /*
+ * Force UTF-8 output no matter what the value of 'encoding' is.
+ * did_set_string_option() in option.c prohibits changing 'termencoding'
+ * to something else than UTF-8 if the GUI is in use.
+ */
+ set_option_value((char_u *)"termencoding", 0L, (char_u *)"utf-8", 0);
+
+#ifdef FEAT_TOOLBAR
+ gui_gtk_register_stock_icons();
+#endif
+ /* FIXME: Need to install the classic icons and a gtkrc.classic file.
+ * The hard part is deciding install locations and the Makefile magic. */
+#if !GTK_CHECK_VERSION(3,0,0)
+# if 0
+ gtk_rc_parse("gtkrc");
+# endif
+#endif
+
+ /* Initialize values */
+ gui.border_width = 2;
+ gui.scrollbar_width = SB_DEFAULT_WIDTH;
+ gui.scrollbar_height = SB_DEFAULT_WIDTH;
+#if GTK_CHECK_VERSION(3,0,0)
+ gui.fgcolor = g_new(GdkRGBA, 1);
+ gui.bgcolor = g_new(GdkRGBA, 1);
+ gui.spcolor = g_new(GdkRGBA, 1);
+#else
+ /* LINTED: avoid warning: conversion to 'unsigned long' */
+ gui.fgcolor = g_new0(GdkColor, 1);
+ /* LINTED: avoid warning: conversion to 'unsigned long' */
+ gui.bgcolor = g_new0(GdkColor, 1);
+ /* LINTED: avoid warning: conversion to 'unsigned long' */
+ gui.spcolor = g_new0(GdkColor, 1);
+#endif
+
+ /* Initialise atoms */
+ html_atom = gdk_atom_intern("text/html", FALSE);
+ utf8_string_atom = gdk_atom_intern("UTF8_STRING", FALSE);
+
+ /* Set default foreground and background colors. */
+ gui.norm_pixel = gui.def_norm_pixel;
+ gui.back_pixel = gui.def_back_pixel;
+
+ if (gtk_socket_id != 0)
+ {
+ GtkWidget *plug;
+
+ /* Use GtkSocket from another app. */
+ plug = gtk_plug_new_for_display(gdk_display_get_default(),
+ gtk_socket_id);
+ if (plug != NULL && gtk_plug_get_socket_window(GTK_PLUG(plug)) != NULL)
+ {
+ gui.mainwin = plug;
+ }
+ else
+ {
+ g_warning("Connection to GTK+ socket (ID %u) failed",
+ (unsigned int)gtk_socket_id);
+ /* Pretend we never wanted it if it failed (get own window) */
+ gtk_socket_id = 0;
+ }
+ }
+
+ if (gtk_socket_id == 0)
+ {
+#ifdef FEAT_GUI_GNOME
+ if (using_gnome)
+ {
+ gui.mainwin = gnome_app_new("Vim", NULL);
+# ifdef USE_XSMP
+ /* Use the GNOME save-yourself functionality now. */
+ xsmp_close();
+# endif
+ }
+ else
+#endif
+ gui.mainwin = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ }
+
+ gtk_widget_set_name(gui.mainwin, "vim-main-window");
+
+ /* Create the PangoContext used for drawing all text. */
+ gui.text_context = gtk_widget_create_pango_context(gui.mainwin);
+ pango_context_set_base_dir(gui.text_context, PANGO_DIRECTION_LTR);
+
+ gtk_container_set_border_width(GTK_CONTAINER(gui.mainwin), 0);
+ gtk_widget_add_events(gui.mainwin, GDK_VISIBILITY_NOTIFY_MASK);
+
+ g_signal_connect(G_OBJECT(gui.mainwin), "delete-event",
+ G_CALLBACK(&delete_event_cb), NULL);
+
+ g_signal_connect(G_OBJECT(gui.mainwin), "realize",
+ G_CALLBACK(&mainwin_realize), NULL);
+
+ g_signal_connect(G_OBJECT(gui.mainwin), "screen-changed",
+ G_CALLBACK(&mainwin_screen_changed_cb), NULL);
+
+ gui.accel_group = gtk_accel_group_new();
+ gtk_window_add_accel_group(GTK_WINDOW(gui.mainwin), gui.accel_group);
+
+ /* A vertical box holds the menubar, toolbar and main text window. */
+#if GTK_CHECK_VERSION(3,2,0)
+ vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
+ gtk_box_set_homogeneous(GTK_BOX(vbox), FALSE);
+#else
+ vbox = gtk_vbox_new(FALSE, 0);
+#endif
+
+#ifdef FEAT_GUI_GNOME
+ if (using_gnome)
+ {
+# if defined(FEAT_MENU)
+ /* automagically restore menubar/toolbar placement */
+ gnome_app_enable_layout_config(GNOME_APP(gui.mainwin), TRUE);
+# endif
+ gnome_app_set_contents(GNOME_APP(gui.mainwin), vbox);
+ }
+ else
+#endif
+ {
+ gtk_container_add(GTK_CONTAINER(gui.mainwin), vbox);
+ gtk_widget_show(vbox);
+ }
+
+#ifdef FEAT_MENU
+ /*
+ * Create the menubar and handle
+ */
+ gui.menubar = gtk_menu_bar_new();
+ gtk_widget_set_name(gui.menubar, "vim-menubar");
+
+ /* Avoid that GTK takes <F10> away from us. */
+ {
+ GtkSettings *gtk_settings;
+
+ gtk_settings = gtk_settings_get_for_screen(gdk_screen_get_default());
+ g_object_set(gtk_settings, "gtk-menu-bar-accel", NULL, NULL);
+ }
+
+
+# ifdef FEAT_GUI_GNOME
+ if (using_gnome)
+ {
+ BonoboDockItem *dockitem;
+
+ gnome_app_set_menus(GNOME_APP(gui.mainwin), GTK_MENU_BAR(gui.menubar));
+ dockitem = gnome_app_get_dock_item_by_name(GNOME_APP(gui.mainwin),
+ GNOME_APP_MENUBAR_NAME);
+ /* We don't want the menu to float. */
+ bonobo_dock_item_set_behavior(dockitem,
+ bonobo_dock_item_get_behavior(dockitem)
+ | BONOBO_DOCK_ITEM_BEH_NEVER_FLOATING);
+ gui.menubar_h = GTK_WIDGET(dockitem);
+ }
+ else
+# endif /* FEAT_GUI_GNOME */
+ {
+ /* Always show the menubar, otherwise <F10> doesn't work. It may be
+ * disabled in gui_init() later. */
+ gtk_widget_show(gui.menubar);
+ gtk_box_pack_start(GTK_BOX(vbox), gui.menubar, FALSE, FALSE, 0);
+ }
+#endif /* FEAT_MENU */
+
+#ifdef FEAT_TOOLBAR
+ /*
+ * Create the toolbar and handle
+ */
+ /* some aesthetics on the toolbar */
+# ifdef USE_GTK3
+ /* TODO: Add GTK+ 3 code here using GtkCssProvider if necessary. */
+ /* N.B. Since the default value of GtkToolbar::button-relief is
+ * GTK_RELIEF_NONE, there's no need to specify that, probably. */
+# else
+ gtk_rc_parse_string(
+ "style \"vim-toolbar-style\" {\n"
+ " GtkToolbar::button_relief = GTK_RELIEF_NONE\n"
+ "}\n"
+ "widget \"*.vim-toolbar\" style \"vim-toolbar-style\"\n");
+# endif
+ gui.toolbar = gtk_toolbar_new();
+ gtk_widget_set_name(gui.toolbar, "vim-toolbar");
+ set_toolbar_style(GTK_TOOLBAR(gui.toolbar));
+
+# ifdef FEAT_GUI_GNOME
+ if (using_gnome)
+ {
+ BonoboDockItem *dockitem;
+
+ gnome_app_set_toolbar(GNOME_APP(gui.mainwin), GTK_TOOLBAR(gui.toolbar));
+ dockitem = gnome_app_get_dock_item_by_name(GNOME_APP(gui.mainwin),
+ GNOME_APP_TOOLBAR_NAME);
+ gui.toolbar_h = GTK_WIDGET(dockitem);
+ /* When the toolbar is floating it gets stuck. So long as that isn't
+ * fixed let's disallow floating. */
+ bonobo_dock_item_set_behavior(dockitem,
+ bonobo_dock_item_get_behavior(dockitem)
+ | BONOBO_DOCK_ITEM_BEH_NEVER_FLOATING);
+ gtk_container_set_border_width(GTK_CONTAINER(gui.toolbar), 0);
+ }
+ else
+# endif /* FEAT_GUI_GNOME */
+ {
+ if (vim_strchr(p_go, GO_TOOLBAR) != NULL
+ && (toolbar_flags & (TOOLBAR_TEXT | TOOLBAR_ICONS)))
+ gtk_widget_show(gui.toolbar);
+ gtk_box_pack_start(GTK_BOX(vbox), gui.toolbar, FALSE, FALSE, 0);
+ }
+#endif /* FEAT_TOOLBAR */
+
+#ifdef FEAT_GUI_TABLINE
+ /*
+ * Use a Notebook for the tab pages labels. The labels are hidden by
+ * default.
+ */
+ gui.tabline = gtk_notebook_new();
+ gtk_widget_show(gui.tabline);
+ gtk_box_pack_start(GTK_BOX(vbox), gui.tabline, FALSE, FALSE, 0);
+ gtk_notebook_set_show_border(GTK_NOTEBOOK(gui.tabline), FALSE);
+ gtk_notebook_set_show_tabs(GTK_NOTEBOOK(gui.tabline), FALSE);
+ gtk_notebook_set_scrollable(GTK_NOTEBOOK(gui.tabline), TRUE);
+# if !GTK_CHECK_VERSION(3,0,0)
+ gtk_notebook_set_tab_border(GTK_NOTEBOOK(gui.tabline), FALSE);
+# endif
+
+# if !GTK_CHECK_VERSION(3,0,0)
+ tabline_tooltip = gtk_tooltips_new();
+ gtk_tooltips_enable(GTK_TOOLTIPS(tabline_tooltip));
+# endif
+
+ {
+ GtkWidget *page, *label, *event_box;
+
+ /* Add the first tab. */
+# if GTK_CHECK_VERSION(3,2,0)
+ page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
+ gtk_box_set_homogeneous(GTK_BOX(page), FALSE);
+# else
+ page = gtk_vbox_new(FALSE, 0);
+# endif
+ gtk_widget_show(page);
+ gtk_container_add(GTK_CONTAINER(gui.tabline), page);
+ label = gtk_label_new("-Empty-");
+ gtk_widget_show(label);
+ event_box = gtk_event_box_new();
+ gtk_widget_show(event_box);
+ g_object_set_data(G_OBJECT(event_box), "tab_num", GINT_TO_POINTER(1L));
+# if !GTK_CHECK_VERSION(3,14,0)
+ gtk_misc_set_padding(GTK_MISC(label), 2, 2);
+# endif
+ gtk_container_add(GTK_CONTAINER(event_box), label);
+ gtk_notebook_set_tab_label(GTK_NOTEBOOK(gui.tabline), page, event_box);
+# if GTK_CHECK_VERSION(2,10,0)
+ gtk_notebook_set_tab_reorderable(GTK_NOTEBOOK(gui.tabline), page, TRUE);
+# endif
+ }
+
+ g_signal_connect(G_OBJECT(gui.tabline), "switch-page",
+ G_CALLBACK(on_select_tab), NULL);
+# if GTK_CHECK_VERSION(2,10,0)
+ g_signal_connect(G_OBJECT(gui.tabline), "page-reordered",
+ G_CALLBACK(on_tab_reordered), NULL);
+# endif
+
+ /* Create a popup menu for the tab line and connect it. */
+ tabline_menu = create_tabline_menu();
+ g_signal_connect_swapped(G_OBJECT(gui.tabline), "button-press-event",
+ G_CALLBACK(on_tabline_menu), G_OBJECT(tabline_menu));
+#endif /* FEAT_GUI_TABLINE */
+
+ gui.formwin = gtk_form_new();
+ gtk_container_set_border_width(GTK_CONTAINER(gui.formwin), 0);
+#if !GTK_CHECK_VERSION(3,0,0)
+ gtk_widget_set_events(gui.formwin, GDK_EXPOSURE_MASK);
+#endif
+
+ gui.drawarea = gtk_drawing_area_new();
+#if GTK_CHECK_VERSION(3,22,2)
+ gtk_widget_set_name(gui.drawarea, "vim-gui-drawarea");
+#endif
+#if GTK_CHECK_VERSION(3,0,0)
+ gui.surface = NULL;
+ gui.by_signal = FALSE;
+#endif
+
+ /* Determine which events we will filter. */
+ gtk_widget_set_events(gui.drawarea,
+ GDK_EXPOSURE_MASK |
+ GDK_ENTER_NOTIFY_MASK |
+ GDK_LEAVE_NOTIFY_MASK |
+ GDK_BUTTON_PRESS_MASK |
+ GDK_BUTTON_RELEASE_MASK |
+ GDK_SCROLL_MASK |
+ GDK_KEY_PRESS_MASK |
+ GDK_KEY_RELEASE_MASK |
+ GDK_POINTER_MOTION_MASK |
+ GDK_POINTER_MOTION_HINT_MASK);
+
+ gtk_widget_show(gui.drawarea);
+ gtk_form_put(GTK_FORM(gui.formwin), gui.drawarea, 0, 0);
+ gtk_widget_show(gui.formwin);
+ gtk_box_pack_start(GTK_BOX(vbox), gui.formwin, TRUE, TRUE, 0);
+
+ /* For GtkSockets, key-presses must go to the focus widget (drawarea)
+ * and not the window. */
+ g_signal_connect((gtk_socket_id == 0) ? G_OBJECT(gui.mainwin)
+ : G_OBJECT(gui.drawarea),
+ "key-press-event",
+ G_CALLBACK(key_press_event), NULL);
+#if defined(FEAT_XIM) || GTK_CHECK_VERSION(3,0,0)
+ /* Also forward key release events for the benefit of GTK+ 2 input
+ * modules. Try CTRL-SHIFT-xdigits to enter a Unicode code point. */
+ g_signal_connect((gtk_socket_id == 0) ? G_OBJECT(gui.mainwin)
+ : G_OBJECT(gui.drawarea),
+ "key-release-event",
+ G_CALLBACK(&key_release_event), NULL);
+#endif
+ g_signal_connect(G_OBJECT(gui.drawarea), "realize",
+ G_CALLBACK(drawarea_realize_cb), NULL);
+ g_signal_connect(G_OBJECT(gui.drawarea), "unrealize",
+ G_CALLBACK(drawarea_unrealize_cb), NULL);
+#if GTK_CHECK_VERSION(3,0,0)
+ g_signal_connect(G_OBJECT(gui.drawarea), "configure-event",
+ G_CALLBACK(drawarea_configure_event_cb), NULL);
+#endif
+#if GTK_CHECK_VERSION(3,22,2)
+ g_signal_connect_after(G_OBJECT(gui.drawarea), "style-updated",
+ G_CALLBACK(&drawarea_style_updated_cb), NULL);
+#else
+ g_signal_connect_after(G_OBJECT(gui.drawarea), "style-set",
+ G_CALLBACK(&drawarea_style_set_cb), NULL);
+#endif
+
+#if !GTK_CHECK_VERSION(3,0,0)
+ gui.visibility = GDK_VISIBILITY_UNOBSCURED;
+#endif
+
+#if !(defined(FEAT_GUI_GNOME) && defined(FEAT_SESSION))
+ wm_protocols_atom = gdk_atom_intern("WM_PROTOCOLS", FALSE);
+ save_yourself_atom = gdk_atom_intern("WM_SAVE_YOURSELF", FALSE);
+#endif
+
+ if (gtk_socket_id != 0)
+ /* make sure keyboard input can go to the drawarea */
+ gtk_widget_set_can_focus(gui.drawarea, TRUE);
+
+ /*
+ * Set clipboard specific atoms
+ */
+ vim_atom = gdk_atom_intern(VIM_ATOM_NAME, FALSE);
+ vimenc_atom = gdk_atom_intern(VIMENC_ATOM_NAME, FALSE);
+ clip_star.gtk_sel_atom = GDK_SELECTION_PRIMARY;
+ clip_plus.gtk_sel_atom = gdk_atom_intern("CLIPBOARD", FALSE);
+
+ /*
+ * Start out by adding the configured border width into the border offset.
+ */
+ gui.border_offset = gui.border_width;
+
+#if GTK_CHECK_VERSION(3,0,0)
+ g_signal_connect(G_OBJECT(gui.drawarea), "draw",
+ G_CALLBACK(draw_event), NULL);
+#else
+ gtk_signal_connect(GTK_OBJECT(gui.mainwin), "visibility_notify_event",
+ GTK_SIGNAL_FUNC(visibility_event), NULL);
+ gtk_signal_connect(GTK_OBJECT(gui.drawarea), "expose_event",
+ GTK_SIGNAL_FUNC(expose_event), NULL);
+#endif
+
+ /*
+ * Only install these enter/leave callbacks when 'p' in 'guioptions'.
+ * Only needed for some window managers.
+ */
+ if (vim_strchr(p_go, GO_POINTER) != NULL)
+ {
+ g_signal_connect(G_OBJECT(gui.drawarea), "leave-notify-event",
+ G_CALLBACK(leave_notify_event), NULL);
+ g_signal_connect(G_OBJECT(gui.drawarea), "enter-notify-event",
+ G_CALLBACK(enter_notify_event), NULL);
+ }
+
+ /* Real windows can get focus ... GtkPlug, being a mere container can't,
+ * only its widgets. Arguably, this could be common code and we not use
+ * the window focus at all, but let's be safe.
+ */
+ if (gtk_socket_id == 0)
+ {
+ g_signal_connect(G_OBJECT(gui.mainwin), "focus-out-event",
+ G_CALLBACK(focus_out_event), NULL);
+ g_signal_connect(G_OBJECT(gui.mainwin), "focus-in-event",
+ G_CALLBACK(focus_in_event), NULL);
+ }
+ else
+ {
+ g_signal_connect(G_OBJECT(gui.drawarea), "focus-out-event",
+ G_CALLBACK(focus_out_event), NULL);
+ g_signal_connect(G_OBJECT(gui.drawarea), "focus-in-event",
+ G_CALLBACK(focus_in_event), NULL);
+#ifdef FEAT_GUI_TABLINE
+ g_signal_connect(G_OBJECT(gui.tabline), "focus-out-event",
+ G_CALLBACK(focus_out_event), NULL);
+ g_signal_connect(G_OBJECT(gui.tabline), "focus-in-event",
+ G_CALLBACK(focus_in_event), NULL);
+#endif /* FEAT_GUI_TABLINE */
+ }
+
+ g_signal_connect(G_OBJECT(gui.drawarea), "motion-notify-event",
+ G_CALLBACK(motion_notify_event), NULL);
+ g_signal_connect(G_OBJECT(gui.drawarea), "button-press-event",
+ G_CALLBACK(button_press_event), NULL);
+ g_signal_connect(G_OBJECT(gui.drawarea), "button-release-event",
+ G_CALLBACK(button_release_event), NULL);
+ g_signal_connect(G_OBJECT(gui.drawarea), "scroll-event",
+ G_CALLBACK(&scroll_event), NULL);
+
+ /*
+ * Add selection handler functions.
+ */
+ g_signal_connect(G_OBJECT(gui.drawarea), "selection-clear-event",
+ G_CALLBACK(selection_clear_event), NULL);
+ g_signal_connect(G_OBJECT(gui.drawarea), "selection-received",
+ G_CALLBACK(selection_received_cb), NULL);
+
+ gui_gtk_set_selection_targets();
+
+ g_signal_connect(G_OBJECT(gui.drawarea), "selection-get",
+ G_CALLBACK(selection_get_cb), NULL);
+
+ /* Pretend we don't have input focus, we will get an event if we do. */
+ gui.in_focus = FALSE;
+
+ // Handle changes to the "Xft/DPI" setting.
+ {
+ GtkSettings *gtk_settings =
+ gtk_settings_get_for_screen(gdk_screen_get_default());
+
+ g_signal_connect(gtk_settings, "notify::gtk-xft-dpi",
+ G_CALLBACK(gtk_settings_xft_dpi_changed_cb), NULL);
+ }
+
+ return OK;
+}
+
+#if (defined(FEAT_GUI_GNOME) && defined(FEAT_SESSION)) || defined(PROTO)
+/*
+ * This is called from gui_start() after a fork() has been done.
+ * We have to tell the session manager our new PID.
+ */
+ void
+gui_mch_forked(void)
+{
+ if (using_gnome)
+ {
+ GnomeClient *client;
+
+ client = gnome_master_client();
+
+ if (client != NULL)
+ gnome_client_set_process_id(client, getpid());
+ }
+}
+#endif /* FEAT_GUI_GNOME && FEAT_SESSION */
+
+#if GTK_CHECK_VERSION(3,0,0)
+ static GdkRGBA
+color_to_rgba(guicolor_T color)
+{
+ GdkRGBA rgba;
+ rgba.red = ((color & 0xff0000) >> 16) / 255.0;
+ rgba.green = ((color & 0xff00) >> 8) / 255.0;
+ rgba.blue = ((color & 0xff)) / 255.0;
+ rgba.alpha = 1.0;
+ return rgba;
+}
+
+ static void
+set_cairo_source_rgba_from_color(cairo_t *cr, guicolor_T color)
+{
+ const GdkRGBA rgba = color_to_rgba(color);
+ cairo_set_source_rgba(cr, rgba.red, rgba.green, rgba.blue, rgba.alpha);
+}
+#endif /* GTK_CHECK_VERSION(3,0,0) */
+
+/*
+ * Called when the foreground or background color has been changed.
+ * This used to change the graphics contexts directly but we are
+ * currently manipulating them where desired.
+ */
+ void
+gui_mch_new_colors(void)
+{
+ if (gui.drawarea != NULL && gtk_widget_get_window(gui.drawarea) != NULL)
+ {
+#if !GTK_CHECK_VERSION(3,22,2)
+ GdkWindow * const da_win = gtk_widget_get_window(gui.drawarea);
+#endif
+
+#if GTK_CHECK_VERSION(3,22,2)
+ GtkStyleContext * const context
+ = gtk_widget_get_style_context(gui.drawarea);
+ GtkCssProvider * const provider = gtk_css_provider_new();
+ gchar * const css = g_strdup_printf(
+ "widget#vim-gui-drawarea {\n"
+ " background-color: #%.2lx%.2lx%.2lx;\n"
+ "}\n",
+ (gui.back_pixel >> 16) & 0xff,
+ (gui.back_pixel >> 8) & 0xff,
+ gui.back_pixel & 0xff);
+
+ gtk_css_provider_load_from_data(provider, css, -1, NULL);
+ gtk_style_context_add_provider(context,
+ GTK_STYLE_PROVIDER(provider), G_MAXUINT);
+
+ g_free(css);
+ g_object_unref(provider);
+#elif GTK_CHECK_VERSION(3,4,0) /* !GTK_CHECK_VERSION(3,22,2) */
+ GdkRGBA rgba;
+
+ rgba = color_to_rgba(gui.back_pixel);
+ {
+ cairo_pattern_t * const pat = cairo_pattern_create_rgba(
+ rgba.red, rgba.green, rgba.blue, rgba.alpha);
+ if (pat != NULL)
+ {
+ gdk_window_set_background_pattern(da_win, pat);
+ cairo_pattern_destroy(pat);
+ }
+ else
+ gdk_window_set_background_rgba(da_win, &rgba);
+ }
+#else /* !GTK_CHECK_VERSION(3,4,0) */
+ GdkColor color = { 0, 0, 0, 0 };
+
+ color.pixel = gui.back_pixel;
+ gdk_window_set_background(da_win, &color);
+#endif /* !GTK_CHECK_VERSION(3,22,2) */
+ }
+}
+
+/*
+ * This signal informs us about the need to rearrange our sub-widgets.
+ */
+ static gint
+form_configure_event(GtkWidget *widget UNUSED,
+ GdkEventConfigure *event,
+ gpointer data UNUSED)
+{
+ int usable_height = event->height;
+
+#if GTK_CHECK_VERSION(3,22,2) && !GTK_CHECK_VERSION(3,22,4)
+ /* As of 3.22.2, GdkWindows have started distributing configure events to
+ * their "native" children (https://git.gnome.org/browse/gtk+/commit/?h=gtk-3-22&id=12579fe71b3b8f79eb9c1b80e429443bcc437dd0).
+ *
+ * As can be seen from the implementation of move_native_children() and
+ * configure_native_child() in gdkwindow.c, those functions actually
+ * propagate configure events to every child, failing to distinguish
+ * "native" one from non-native one.
+ *
+ * Naturally, configure events propagated to here like that are fallacious
+ * and, as a matter of fact, they trigger a geometric collapse of
+ * gui.formwin.
+ *
+ * To filter out such fallacious events, check if the given event is the
+ * one that was sent out to the right place. Ignore it if not.
+ */
+ /* Follow-up
+ * After a few weeks later, the GdkWindow change mentioned above was
+ * reverted (https://git.gnome.org/browse/gtk+/commit/?h=gtk-3-22&id=f70039cb9603a02d2369fec4038abf40a1711155).
+ * The corresponding official release is 3.22.4. */
+ if (event->window != gtk_widget_get_window(gui.formwin))
+ return TRUE;
+#endif
+
+ /* When in a GtkPlug, we can't guarantee valid heights (as a round
+ * no. of char-heights), so we have to manually sanitise them.
+ * Widths seem to sort themselves out, don't ask me why.
+ */
+ if (gtk_socket_id != 0)
+ usable_height -= (gui.char_height - (gui.char_height/2)); /* sic. */
+
+ gtk_form_freeze(GTK_FORM(gui.formwin));
+ gui_resize_shell(event->width, usable_height);
+ gtk_form_thaw(GTK_FORM(gui.formwin));
+
+ return TRUE;
+}
+
+/*
+ * Function called when window already closed.
+ * We can't do much more here than to trying to preserve what had been done,
+ * since the window is already inevitably going away.
+ */
+ static void
+mainwin_destroy_cb(GObject *object UNUSED, gpointer data UNUSED)
+{
+ /* Don't write messages to the GUI anymore */
+ full_screen = FALSE;
+
+ gui.mainwin = NULL;
+ gui.drawarea = NULL;
+
+ if (!exiting) /* only do anything if the destroy was unexpected */
+ {
+ vim_strncpy(IObuff,
+ (char_u *)_("Vim: Main window unexpectedly destroyed\n"),
+ IOSIZE - 1);
+ preserve_exit();
+ }
+#ifdef USE_GRESOURCE
+ gui_gtk_unregister_resource();
+#endif
+}
+
+
+/*
+ * Bit of a hack to ensure we start GtkPlug windows with the correct window
+ * hints (and thus the required size from -geom), but that after that we
+ * put the hints back to normal (the actual minimum size) so we may
+ * subsequently be resized smaller. GtkSocket (the parent end) uses the
+ * plug's window 'min hints to set *its* minimum size, but that's also the
+ * only way we have of making ourselves bigger (by set lines/columns).
+ * Thus set hints at start-up to ensure correct init. size, then a
+ * second after the final attempt to reset the real minimum hints (done by
+ * scrollbar init.), actually do the standard hints and stop the timer.
+ * We'll not let the default hints be set while this timer's active.
+ */
+ static timeout_cb_type
+check_startup_plug_hints(gpointer data UNUSED)
+{
+ if (init_window_hints_state == 1)
+ {
+ /* Safe to use normal hints now */
+ init_window_hints_state = 0;
+ update_window_manager_hints(0, 0);
+ return FALSE; /* stop timer */
+ }
+
+ /* Keep on trying */
+ init_window_hints_state = 1;
+ return TRUE;
+}
+
+/*
+ * Open the GUI window which was created by a call to gui_mch_init().
+ */
+ int
+gui_mch_open(void)
+{
+ guicolor_T fg_pixel = INVALCOLOR;
+ guicolor_T bg_pixel = INVALCOLOR;
+ guint pixel_width;
+ guint pixel_height;
+
+ /*
+ * Allow setting a window role on the command line, or invent one
+ * if none was specified. This is mainly useful for GNOME session
+ * support; allowing the WM to restore window placement.
+ */
+ if (role_argument != NULL)
+ {
+ gtk_window_set_role(GTK_WINDOW(gui.mainwin), role_argument);
+ }
+ else
+ {
+ char *role;
+
+ /* Invent a unique-enough ID string for the role */
+ role = g_strdup_printf("vim-%u-%u-%u",
+ (unsigned)mch_get_pid(),
+ (unsigned)g_random_int(),
+ (unsigned)time(NULL));
+
+ gtk_window_set_role(GTK_WINDOW(gui.mainwin), role);
+ g_free(role);
+ }
+
+ if (gui_win_x != -1 && gui_win_y != -1)
+ gtk_window_move(GTK_WINDOW(gui.mainwin), gui_win_x, gui_win_y);
+
+ /* Determine user specified geometry, if present. */
+ if (gui.geom != NULL)
+ {
+ int mask;
+ unsigned int w, h;
+ int x = 0;
+ int y = 0;
+
+ mask = XParseGeometry((char *)gui.geom, &x, &y, &w, &h);
+
+ if (mask & WidthValue)
+ Columns = w;
+ if (mask & HeightValue)
+ {
+ if (p_window > (long)h - 1 || !option_was_set((char_u *)"window"))
+ p_window = h - 1;
+ Rows = h;
+ }
+ limit_screen_size();
+
+ pixel_width = (guint)(gui_get_base_width() + Columns * gui.char_width);
+ pixel_height = (guint)(gui_get_base_height() + Rows * gui.char_height);
+
+ pixel_width += get_menu_tool_width();
+ pixel_height += get_menu_tool_height();
+
+ if (mask & (XValue | YValue))
+ {
+ int ww, hh;
+ gui_mch_get_screen_dimensions(&ww, &hh);
+ hh += p_ghr + get_menu_tool_height();
+ ww += get_menu_tool_width();
+ if (mask & XNegative)
+ x += ww - pixel_width;
+ if (mask & YNegative)
+ y += hh - pixel_height;
+ gtk_window_move(GTK_WINDOW(gui.mainwin), x, y);
+ }
+ VIM_CLEAR(gui.geom);
+
+ /* From now until everyone's stopped trying to set the window hints
+ * to their correct minimum values, stop them being set as we need
+ * them to remain at our required size for the parent GtkSocket to
+ * give us the right initial size.
+ */
+ if (gtk_socket_id != 0 && (mask & WidthValue || mask & HeightValue))
+ {
+ update_window_manager_hints(pixel_width, pixel_height);
+ init_window_hints_state = 1;
+ timeout_add(1000, check_startup_plug_hints, NULL);
+ }
+ }
+
+ pixel_width = (guint)(gui_get_base_width() + Columns * gui.char_width);
+ pixel_height = (guint)(gui_get_base_height() + Rows * gui.char_height);
+ /* For GTK2 changing the size of the form widget doesn't cause window
+ * resizing. */
+ if (gtk_socket_id == 0)
+ gtk_window_resize(GTK_WINDOW(gui.mainwin), pixel_width, pixel_height);
+ update_window_manager_hints(0, 0);
+
+ if (foreground_argument != NULL)
+ fg_pixel = gui_get_color((char_u *)foreground_argument);
+ if (fg_pixel == INVALCOLOR)
+ fg_pixel = gui_get_color((char_u *)"Black");
+
+ if (background_argument != NULL)
+ bg_pixel = gui_get_color((char_u *)background_argument);
+ if (bg_pixel == INVALCOLOR)
+ bg_pixel = gui_get_color((char_u *)"White");
+
+ if (found_reverse_arg)
+ {
+ gui.def_norm_pixel = bg_pixel;
+ gui.def_back_pixel = fg_pixel;
+ }
+ else
+ {
+ gui.def_norm_pixel = fg_pixel;
+ gui.def_back_pixel = bg_pixel;
+ }
+
+ /* Get the colors from the "Normal" and "Menu" 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 */
+ gui_check_colors();
+
+ /* Get the colors for the highlight groups (gui_check_colors() might have
+ * changed them). */
+ highlight_gui_started(); /* re-init colors and fonts */
+
+ g_signal_connect(G_OBJECT(gui.mainwin), "destroy",
+ G_CALLBACK(mainwin_destroy_cb), NULL);
+
+#ifdef FEAT_HANGULIN
+ hangul_keyboard_set();
+#endif
+
+ /*
+ * Notify the fixed area about the need to resize the contents of the
+ * gui.formwin, which we use for random positioning of the included
+ * components.
+ *
+ * We connect this signal deferred finally after anything is in place,
+ * since this is intended to handle resizements coming from the window
+ * manager upon us and should not interfere with what VIM is requesting
+ * upon startup.
+ */
+ g_signal_connect(G_OBJECT(gui.formwin), "configure-event",
+ G_CALLBACK(form_configure_event), NULL);
+
+#ifdef FEAT_DND
+ /* Set up for receiving DND items. */
+ gui_gtk_set_dnd_targets();
+
+ g_signal_connect(G_OBJECT(gui.drawarea), "drag-data-received",
+ G_CALLBACK(drag_data_received_cb), NULL);
+#endif
+
+ /* With GTK+ 2, we need to iconify the window before calling show()
+ * to avoid mapping the window for a short time. */
+ if (found_iconic_arg && gtk_socket_id == 0)
+ gui_mch_iconify();
+
+ {
+#if defined(FEAT_GUI_GNOME) && defined(FEAT_MENU)
+ unsigned long menu_handler = 0;
+# ifdef FEAT_TOOLBAR
+ unsigned long tool_handler = 0;
+# endif
+ /*
+ * Urgh hackish :/ For some reason BonoboDockLayout always forces a
+ * show when restoring the saved layout configuration. We can't just
+ * hide the widgets again after gtk_widget_show(gui.mainwin) since it's
+ * a toplevel window and thus will be realized immediately. Instead,
+ * connect signal handlers to hide the widgets just after they've been
+ * marked visible, but before the main window is realized.
+ */
+ if (using_gnome && vim_strchr(p_go, GO_MENUS) == NULL)
+ menu_handler = g_signal_connect_after(gui.menubar_h, "show",
+ G_CALLBACK(&gtk_widget_hide),
+ NULL);
+# ifdef FEAT_TOOLBAR
+ if (using_gnome && vim_strchr(p_go, GO_TOOLBAR) == NULL
+ && (toolbar_flags & (TOOLBAR_TEXT | TOOLBAR_ICONS)))
+ tool_handler = g_signal_connect_after(gui.toolbar_h, "show",
+ G_CALLBACK(&gtk_widget_hide),
+ NULL);
+# endif
+#endif
+ gtk_widget_show(gui.mainwin);
+
+#if defined(FEAT_GUI_GNOME) && defined(FEAT_MENU)
+ if (menu_handler != 0)
+ g_signal_handler_disconnect(gui.menubar_h, menu_handler);
+# ifdef FEAT_TOOLBAR
+ if (tool_handler != 0)
+ g_signal_handler_disconnect(gui.toolbar_h, tool_handler);
+# endif
+#endif
+ }
+
+ return OK;
+}
+
+
+ void
+gui_mch_exit(int rc UNUSED)
+{
+ if (gui.mainwin != NULL)
+ gtk_widget_destroy(gui.mainwin);
+}
+
+/*
+ * Get the position of the top left corner of the window.
+ */
+ int
+gui_mch_get_winpos(int *x, int *y)
+{
+ gtk_window_get_position(GTK_WINDOW(gui.mainwin), x, y);
+ 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)
+{
+ gtk_window_move(GTK_WINDOW(gui.mainwin), x, y);
+}
+
+#if !GTK_CHECK_VERSION(3,0,0)
+# if 0
+static int resize_idle_installed = FALSE;
+/*
+ * Idle handler to force resize. Used by gui_mch_set_shellsize() to ensure
+ * the shell size doesn't exceed the window size, i.e. if the window manager
+ * ignored our size request. Usually this happens if the window is maximized.
+ *
+ * FIXME: It'd be nice if we could find a little more orthodox solution.
+ * See also the remark below in gui_mch_set_shellsize().
+ *
+ * DISABLED: When doing ":set lines+=1" this function would first invoke
+ * gui_resize_shell() with the old size, then the normal callback would
+ * report the new size through form_configure_event(). That caused the window
+ * layout to be messed up.
+ */
+ static gboolean
+force_shell_resize_idle(gpointer data)
+{
+ if (gui.mainwin != NULL
+ && GTK_WIDGET_REALIZED(gui.mainwin)
+ && GTK_WIDGET_VISIBLE(gui.mainwin))
+ {
+ int width;
+ int height;
+
+ gtk_window_get_size(GTK_WINDOW(gui.mainwin), &width, &height);
+
+ width -= get_menu_tool_width();
+ height -= get_menu_tool_height();
+
+ gui_resize_shell(width, height);
+ }
+
+ resize_idle_installed = FALSE;
+ return FALSE; /* don't call me again */
+}
+# endif
+#endif /* !GTK_CHECK_VERSION(3,0,0) */
+
+/*
+ * Return TRUE if the main window is maximized.
+ */
+ int
+gui_mch_maximized(void)
+{
+ return (gui.mainwin != NULL && gtk_widget_get_window(gui.mainwin) != NULL
+ && (gdk_window_get_state(gtk_widget_get_window(gui.mainwin))
+ & GDK_WINDOW_STATE_MAXIMIZED));
+}
+
+/*
+ * Unmaximize the main window
+ */
+ void
+gui_mch_unmaximize(void)
+{
+ if (gui.mainwin != NULL)
+ gtk_window_unmaximize(GTK_WINDOW(gui.mainwin));
+}
+
+/*
+ * Called when the font changed while the window is maximized or GO_KEEPWINSIZE
+ * is set. Compute the new Rows and Columns. This is like resizing the
+ * window.
+ */
+ void
+gui_mch_newfont(void)
+{
+ int w, h;
+
+ gtk_window_get_size(GTK_WINDOW(gui.mainwin), &w, &h);
+ w -= get_menu_tool_width();
+ h -= get_menu_tool_height();
+ gui_resize_shell(w, h);
+}
+
+/*
+ * Set the windows size.
+ */
+ void
+gui_mch_set_shellsize(int width, int height,
+ int min_width UNUSED, int min_height UNUSED,
+ int base_width UNUSED, int base_height UNUSED,
+ int direction UNUSED)
+{
+ /* give GTK+ a chance to put all widget's into place */
+ gui_mch_update();
+
+ /* this will cause the proper resizement to happen too */
+ if (gtk_socket_id == 0)
+ update_window_manager_hints(0, 0);
+
+ /* With GTK+ 2, changing the size of the form widget doesn't resize
+ * the window. So let's do it the other way around and resize the
+ * main window instead. */
+ width += get_menu_tool_width();
+ height += get_menu_tool_height();
+
+ if (gtk_socket_id == 0)
+ gtk_window_resize(GTK_WINDOW(gui.mainwin), width, height);
+ else
+ update_window_manager_hints(width, height);
+
+# if !GTK_CHECK_VERSION(3,0,0)
+# if 0
+ if (!resize_idle_installed)
+ {
+ g_idle_add_full(GDK_PRIORITY_EVENTS + 10,
+ &force_shell_resize_idle, NULL, NULL);
+ resize_idle_installed = TRUE;
+ }
+# endif
+# endif /* !GTK_CHECK_VERSION(3,0,0) */
+ /*
+ * Wait until all events are processed to prevent a crash because the
+ * real size of the drawing area doesn't reflect Vim's internal ideas.
+ *
+ * This is a bit of a hack, since Vim is a terminal application with a GUI
+ * on top, while the GUI expects to be the boss.
+ */
+ gui_mch_update();
+}
+
+ void
+gui_gtk_get_screen_geom_of_win(
+ GtkWidget *wid,
+ int *screen_x,
+ int *screen_y,
+ int *width,
+ int *height)
+{
+ GdkRectangle geometry;
+ GdkWindow *win = gtk_widget_get_window(wid);
+#if GTK_CHECK_VERSION(3,22,0)
+ GdkDisplay *dpy = gtk_widget_get_display(wid);
+ GdkMonitor *monitor = gdk_display_get_monitor_at_window(dpy, win);
+
+ gdk_monitor_get_geometry(monitor, &geometry);
+#else
+ GdkScreen* screen;
+ int monitor;
+
+ if (wid != NULL && gtk_widget_has_screen(wid))
+ screen = gtk_widget_get_screen(wid);
+ else
+ screen = gdk_screen_get_default();
+ monitor = gdk_screen_get_monitor_at_window(screen, win);
+ gdk_screen_get_monitor_geometry(screen, monitor, &geometry);
+#endif
+ *screen_x = geometry.x;
+ *screen_y = geometry.y;
+ *width = geometry.width;
+ *height = geometry.height;
+}
+
+/*
+ * The screen size is used to make sure the initial window doesn't get bigger
+ * than the screen. This subtracts some room for menubar, toolbar and window
+ * decorations.
+ */
+ void
+gui_mch_get_screen_dimensions(int *screen_w, int *screen_h)
+{
+ int x, y;
+
+ gui_gtk_get_screen_geom_of_win(gui.mainwin, &x, &y, screen_w, screen_h);
+
+ /* Subtract 'guiheadroom' from the height to allow some room for the
+ * window manager (task list and window title bar). */
+ *screen_h -= p_ghr;
+
+ /*
+ * FIXME: dirty trick: Because the gui_get_base_height() doesn't include
+ * the toolbar and menubar for GTK, we subtract them from the screen
+ * height, so that the window size can be made to fit on the screen.
+ * This should be completely changed later.
+ */
+ *screen_w -= get_menu_tool_width();
+ *screen_h -= get_menu_tool_height();
+}
+
+#if defined(FEAT_TITLE) || defined(PROTO)
+ void
+gui_mch_settitle(char_u *title, char_u *icon UNUSED)
+{
+ if (title != NULL && output_conv.vc_type != CONV_NONE)
+ title = string_convert(&output_conv, title, NULL);
+
+ gtk_window_set_title(GTK_WINDOW(gui.mainwin), (const char *)title);
+
+ if (output_conv.vc_type != CONV_NONE)
+ vim_free(title);
+}
+#endif /* FEAT_TITLE */
+
+#if defined(FEAT_MENU) || defined(PROTO)
+ void
+gui_mch_enable_menu(int showit)
+{
+ GtkWidget *widget;
+
+# ifdef FEAT_GUI_GNOME
+ if (using_gnome)
+ widget = gui.menubar_h;
+ else
+# endif
+ widget = gui.menubar;
+
+ /* Do not disable the menu while starting up, otherwise F10 doesn't work. */
+ if (!showit != !gtk_widget_get_visible(widget) && !gui.starting)
+ {
+ if (showit)
+ gtk_widget_show(widget);
+ else
+ gtk_widget_hide(widget);
+
+ update_window_manager_hints(0, 0);
+ }
+}
+#endif /* FEAT_MENU */
+
+#if defined(FEAT_TOOLBAR) || defined(PROTO)
+ void
+gui_mch_show_toolbar(int showit)
+{
+ GtkWidget *widget;
+
+ if (gui.toolbar == NULL)
+ return;
+
+# ifdef FEAT_GUI_GNOME
+ if (using_gnome)
+ widget = gui.toolbar_h;
+ else
+# endif
+ widget = gui.toolbar;
+
+ if (showit)
+ set_toolbar_style(GTK_TOOLBAR(gui.toolbar));
+
+ if (!showit != !gtk_widget_get_visible(widget))
+ {
+ if (showit)
+ gtk_widget_show(widget);
+ else
+ gtk_widget_hide(widget);
+
+ update_window_manager_hints(0, 0);
+ }
+}
+#endif /* FEAT_TOOLBAR */
+
+/*
+ * Check if a given font is a CJK font. This is done in a very crude manner. It
+ * just see if U+04E00 for zh and ja and U+AC00 for ko are covered in a given
+ * font. Consequently, this function cannot be used as a general purpose check
+ * for CJK-ness for which fontconfig APIs should be used. This is only used by
+ * gui_mch_init_font() to deal with 'CJK fixed width fonts'.
+ */
+ static int
+is_cjk_font(PangoFontDescription *font_desc)
+{
+ static const char * const cjk_langs[] =
+ {"zh_CN", "zh_TW", "zh_HK", "ja", "ko"};
+
+ PangoFont *font;
+ unsigned i;
+ int is_cjk = FALSE;
+
+ font = pango_context_load_font(gui.text_context, font_desc);
+
+ if (font == NULL)
+ return FALSE;
+
+ for (i = 0; !is_cjk && i < G_N_ELEMENTS(cjk_langs); ++i)
+ {
+ PangoCoverage *coverage;
+ gunichar uc;
+
+ coverage = pango_font_get_coverage(
+ font, pango_language_from_string(cjk_langs[i]));
+
+ if (coverage != NULL)
+ {
+ uc = (cjk_langs[i][0] == 'k') ? 0xAC00 : 0x4E00;
+ is_cjk = (pango_coverage_get(coverage, uc) == PANGO_COVERAGE_EXACT);
+ pango_coverage_unref(coverage);
+ }
+ }
+
+ g_object_unref(font);
+
+ return is_cjk;
+}
+
+/*
+ * Adjust gui.char_height (after 'linespace' was changed).
+ */
+ int
+gui_mch_adjust_charheight(void)
+{
+ PangoFontMetrics *metrics;
+ int ascent;
+ int descent;
+
+ metrics = pango_context_get_metrics(gui.text_context, gui.norm_font,
+ pango_context_get_language(gui.text_context));
+ ascent = pango_font_metrics_get_ascent(metrics);
+ descent = pango_font_metrics_get_descent(metrics);
+
+ pango_font_metrics_unref(metrics);
+
+ gui.char_height = (ascent + descent + PANGO_SCALE - 1) / PANGO_SCALE
+ + p_linespace;
+ /* LINTED: avoid warning: bitwise operation on signed value */
+ gui.char_ascent = PANGO_PIXELS(ascent + p_linespace * PANGO_SCALE / 2);
+
+ /* A not-positive value of char_height may crash Vim. Only happens
+ * if 'linespace' is negative (which does make sense sometimes). */
+ gui.char_ascent = MAX(gui.char_ascent, 0);
+ gui.char_height = MAX(gui.char_height, gui.char_ascent + 1);
+
+ return OK;
+}
+
+#if GTK_CHECK_VERSION(3,0,0)
+/* Callback function used in gui_mch_font_dialog() */
+ static gboolean
+font_filter(const PangoFontFamily *family,
+ const PangoFontFace *face UNUSED,
+ gpointer data UNUSED)
+{
+ return pango_font_family_is_monospace((PangoFontFamily *)family);
+}
+#endif
+
+/*
+ * Put up a font dialog and return the selected font name in allocated memory.
+ * "oldval" is the previous value. Return NULL when cancelled.
+ * This should probably go into gui_gtk.c. Hmm.
+ * FIXME:
+ * The GTK2 font selection dialog has no filtering API. So we could either
+ * a) implement our own (possibly copying the code from somewhere else) or
+ * b) just live with it.
+ */
+ char_u *
+gui_mch_font_dialog(char_u *oldval)
+{
+ GtkWidget *dialog;
+ int response;
+ char_u *fontname = NULL;
+ char_u *oldname;
+
+#if GTK_CHECK_VERSION(3,2,0)
+ dialog = gtk_font_chooser_dialog_new(NULL, NULL);
+ gtk_font_chooser_set_filter_func(GTK_FONT_CHOOSER(dialog), font_filter,
+ NULL, NULL);
+#else
+ dialog = gtk_font_selection_dialog_new(NULL);
+#endif
+
+ gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(gui.mainwin));
+ gtk_window_set_destroy_with_parent(GTK_WINDOW(dialog), TRUE);
+
+ if (oldval != NULL && oldval[0] != NUL)
+ {
+ if (output_conv.vc_type != CONV_NONE)
+ oldname = string_convert(&output_conv, oldval, NULL);
+ else
+ oldname = oldval;
+
+ /* Annoying bug in GTK (or Pango): if the font name does not include a
+ * size, zero is used. Use default point size ten. */
+ if (!vim_isdigit(oldname[STRLEN(oldname) - 1]))
+ {
+ char_u *p = vim_strnsave(oldname, STRLEN(oldname) + 3);
+
+ if (p != NULL)
+ {
+ STRCPY(p + STRLEN(p), " 10");
+ if (oldname != oldval)
+ vim_free(oldname);
+ oldname = p;
+ }
+ }
+
+#if GTK_CHECK_VERSION(3,2,0)
+ gtk_font_chooser_set_font(
+ GTK_FONT_CHOOSER(dialog), (const gchar *)oldname);
+#else
+ gtk_font_selection_dialog_set_font_name(
+ GTK_FONT_SELECTION_DIALOG(dialog), (const char *)oldname);
+#endif
+
+ if (oldname != oldval)
+ vim_free(oldname);
+ }
+ else
+#if GTK_CHECK_VERSION(3,2,0)
+ gtk_font_chooser_set_font(
+ GTK_FONT_CHOOSER(dialog), DEFAULT_FONT);
+#else
+ gtk_font_selection_dialog_set_font_name(
+ GTK_FONT_SELECTION_DIALOG(dialog), DEFAULT_FONT);
+#endif
+
+ response = gtk_dialog_run(GTK_DIALOG(dialog));
+
+ if (response == GTK_RESPONSE_OK)
+ {
+ char *name;
+
+#if GTK_CHECK_VERSION(3,2,0)
+ name = gtk_font_chooser_get_font(GTK_FONT_CHOOSER(dialog));
+#else
+ name = gtk_font_selection_dialog_get_font_name(
+ GTK_FONT_SELECTION_DIALOG(dialog));
+#endif
+ if (name != NULL)
+ {
+ char_u *p;
+
+ /* Apparently some font names include a comma, need to escape
+ * that, because in 'guifont' it separates names. */
+ p = vim_strsave_escaped((char_u *)name, (char_u *)",");
+ g_free(name);
+ if (p != NULL && input_conv.vc_type != CONV_NONE)
+ {
+ fontname = string_convert(&input_conv, p, NULL);
+ vim_free(p);
+ }
+ else
+ fontname = p;
+ }
+ }
+
+ if (response != GTK_RESPONSE_NONE)
+ gtk_widget_destroy(dialog);
+
+ return fontname;
+}
+
+/*
+ * Some monospace fonts don't support a bold weight, and fall back
+ * silently to the regular weight. But this is no good since our text
+ * drawing function can emulate bold by overstriking. So let's try
+ * to detect whether bold weight is actually available and emulate it
+ * otherwise.
+ *
+ * Note that we don't need to check for italic style since Xft can
+ * emulate italic on its own, provided you have a proper fontconfig
+ * setup. We wouldn't be able to emulate it in Vim anyway.
+ */
+ static void
+get_styled_font_variants(void)
+{
+ PangoFontDescription *bold_font_desc;
+ PangoFont *plain_font;
+ PangoFont *bold_font;
+
+ gui.font_can_bold = FALSE;
+
+ plain_font = pango_context_load_font(gui.text_context, gui.norm_font);
+
+ if (plain_font == NULL)
+ return;
+
+ bold_font_desc = pango_font_description_copy_static(gui.norm_font);
+ pango_font_description_set_weight(bold_font_desc, PANGO_WEIGHT_BOLD);
+
+ bold_font = pango_context_load_font(gui.text_context, bold_font_desc);
+ /*
+ * The comparison relies on the unique handle nature of a PangoFont*,
+ * i.e. it's assumed that a different PangoFont* won't refer to the
+ * same font. Seems to work, and failing here isn't critical anyway.
+ */
+ if (bold_font != NULL)
+ {
+ gui.font_can_bold = (bold_font != plain_font);
+ g_object_unref(bold_font);
+ }
+
+ pango_font_description_free(bold_font_desc);
+ g_object_unref(plain_font);
+}
+
+static PangoEngineShape *default_shape_engine = NULL;
+
+/*
+ * Create a map from ASCII characters in the range [32,126] to glyphs
+ * of the current font. This is used by gui_gtk2_draw_string() to skip
+ * the itemize and shaping process for the most common case.
+ */
+ static void
+ascii_glyph_table_init(void)
+{
+ char_u ascii_chars[2 * 128];
+ PangoAttrList *attr_list;
+ GList *item_list;
+ int i;
+
+ if (gui.ascii_glyphs != NULL)
+ pango_glyph_string_free(gui.ascii_glyphs);
+ if (gui.ascii_font != NULL)
+ g_object_unref(gui.ascii_font);
+
+ gui.ascii_glyphs = NULL;
+ gui.ascii_font = NULL;
+
+ /* For safety, fill in question marks for the control characters.
+ * Put a space between characters to avoid shaping. */
+ for (i = 0; i < 128; ++i)
+ {
+ if (i >= 32 && i < 127)
+ ascii_chars[2 * i] = i;
+ else
+ ascii_chars[2 * i] = '?';
+ ascii_chars[2 * i + 1] = ' ';
+ }
+
+ attr_list = pango_attr_list_new();
+ item_list = pango_itemize(gui.text_context, (const char *)ascii_chars,
+ 0, sizeof(ascii_chars), attr_list, NULL);
+
+ if (item_list != NULL && item_list->next == NULL) /* play safe */
+ {
+ PangoItem *item;
+ int width;
+
+ item = (PangoItem *)item_list->data;
+ width = gui.char_width * PANGO_SCALE;
+
+ /* Remember the shape engine used for ASCII. */
+ default_shape_engine = item->analysis.shape_engine;
+
+ gui.ascii_font = item->analysis.font;
+ g_object_ref(gui.ascii_font);
+
+ gui.ascii_glyphs = pango_glyph_string_new();
+
+ pango_shape((const char *)ascii_chars, sizeof(ascii_chars),
+ &item->analysis, gui.ascii_glyphs);
+
+ g_return_if_fail(gui.ascii_glyphs->num_glyphs == sizeof(ascii_chars));
+
+ for (i = 0; i < gui.ascii_glyphs->num_glyphs; ++i)
+ {
+ PangoGlyphGeometry *geom;
+
+ geom = &gui.ascii_glyphs->glyphs[i].geometry;
+ geom->x_offset += MAX(0, width - geom->width) / 2;
+ geom->width = width;
+ }
+ }
+
+ g_list_foreach(item_list, (GFunc)&pango_item_free, NULL);
+ g_list_free(item_list);
+ pango_attr_list_unref(attr_list);
+}
+
+/*
+ * Initialize Vim to use the font or fontset 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 UNUSED)
+{
+ PangoFontDescription *font_desc;
+ PangoLayout *layout;
+ int width;
+
+ /* If font_name is NULL, this means to use the default, which should
+ * be present on all proper Pango/fontconfig installations. */
+ if (font_name == NULL)
+ font_name = (char_u *)DEFAULT_FONT;
+
+ font_desc = gui_mch_get_font(font_name, FALSE);
+
+ if (font_desc == NULL)
+ return FAIL;
+
+ gui_mch_free_font(gui.norm_font);
+ gui.norm_font = font_desc;
+
+ pango_context_set_font_description(gui.text_context, font_desc);
+
+ layout = pango_layout_new(gui.text_context);
+ pango_layout_set_text(layout, "MW", 2);
+ pango_layout_get_size(layout, &width, NULL);
+ /*
+ * Set char_width to half the width obtained from pango_layout_get_size()
+ * for CJK fixed_width/bi-width fonts. An unpatched version of Xft leads
+ * Pango to use the same width for both non-CJK characters (e.g. Latin
+ * letters and numbers) and CJK characters. This results in 's p a c e d
+ * o u t' rendering when a CJK 'fixed width' font is used. To work around
+ * that, divide the width returned by Pango by 2 if cjk_width is equal to
+ * width for CJK fonts.
+ *
+ * For related bugs, see:
+ * http://bugzilla.gnome.org/show_bug.cgi?id=106618
+ * http://bugzilla.gnome.org/show_bug.cgi?id=106624
+ *
+ * With this, for all four of the following cases, Vim works fine:
+ * guifont=CJK_fixed_width_font
+ * guifont=Non_CJK_fixed_font
+ * guifont=Non_CJK_fixed_font,CJK_Fixed_font
+ * guifont=Non_CJK_fixed_font guifontwide=CJK_fixed_font
+ */
+ if (is_cjk_font(gui.norm_font))
+ {
+ int cjk_width;
+
+ /* Measure the text extent of U+4E00 and U+4E8C */
+ pango_layout_set_text(layout, "\344\270\200\344\272\214", -1);
+ pango_layout_get_size(layout, &cjk_width, NULL);
+
+ if (width == cjk_width) /* Xft not patched */
+ width /= 2;
+ }
+ g_object_unref(layout);
+
+ gui.char_width = (width / 2 + PANGO_SCALE - 1) / PANGO_SCALE;
+
+ /* A zero width may cause a crash. Happens for semi-invalid fontsets. */
+ if (gui.char_width <= 0)
+ gui.char_width = 8;
+
+ gui_mch_adjust_charheight();
+
+ /* Set the fontname, which will be used for information purposes */
+ hl_set_font_name(font_name);
+
+ get_styled_font_variants();
+ ascii_glyph_table_init();
+
+ /* Avoid unnecessary overhead if 'guifontwide' is equal to 'guifont'. */
+ if (gui.wide_font != NULL
+ && pango_font_description_equal(gui.norm_font, gui.wide_font))
+ {
+ pango_font_description_free(gui.wide_font);
+ gui.wide_font = NULL;
+ }
+
+ if (gui_mch_maximized())
+ {
+ /* Update lines and columns in accordance with the new font, keep the
+ * window maximized. */
+ gui_mch_newfont();
+ }
+ else
+ {
+ /* Preserve the logical dimensions of the screen. */
+ update_window_manager_hints(0, 0);
+ }
+
+ return OK;
+}
+
+/*
+ * Get a reference to the font "name".
+ * Return zero for failure.
+ */
+ GuiFont
+gui_mch_get_font(char_u *name, int report_error)
+{
+ PangoFontDescription *font;
+
+ /* can't do this when GUI is not running */
+ if (!gui.in_use || name == NULL)
+ return NULL;
+
+ if (output_conv.vc_type != CONV_NONE)
+ {
+ char_u *buf;
+
+ buf = string_convert(&output_conv, name, NULL);
+ if (buf != NULL)
+ {
+ font = pango_font_description_from_string((const char *)buf);
+ vim_free(buf);
+ }
+ else
+ font = NULL;
+ }
+ else
+ font = pango_font_description_from_string((const char *)name);
+
+ if (font != NULL)
+ {
+ PangoFont *real_font;
+
+ /* pango_context_load_font() bails out if no font size is set */
+ if (pango_font_description_get_size(font) <= 0)
+ pango_font_description_set_size(font, 10 * PANGO_SCALE);
+
+ real_font = pango_context_load_font(gui.text_context, font);
+
+ if (real_font == NULL)
+ {
+ pango_font_description_free(font);
+ font = NULL;
+ }
+ else
+ g_object_unref(real_font);
+ }
+
+ if (font == NULL)
+ {
+ if (report_error)
+ semsg(_((char *)e_font), name);
+ return NULL;
+ }
+
+ return font;
+}
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * Return the name of font "font" in allocated memory.
+ */
+ char_u *
+gui_mch_get_fontname(GuiFont font, char_u *name UNUSED)
+{
+ if (font != NOFONT)
+ {
+ char *pangoname = pango_font_description_to_string(font);
+
+ if (pangoname != NULL)
+ {
+ char_u *s = vim_strsave((char_u *)pangoname);
+
+ g_free(pangoname);
+ return s;
+ }
+ }
+ return NULL;
+}
+#endif
+
+/*
+ * If a font is not going to be used, free its structure.
+ */
+ void
+gui_mch_free_font(GuiFont font)
+{
+ if (font != NOFONT)
+ pango_font_description_free(font);
+}
+
+/*
+ * Return the Pixel value (color) for the given color name.
+ *
+ * Return INVALCOLOR for error.
+ */
+ guicolor_T
+gui_mch_get_color(char_u *name)
+{
+ guicolor_T color = INVALCOLOR;
+
+ if (!gui.in_use) /* can't do this when GUI not running */
+ return color;
+
+ if (name != NULL)
+ color = gui_get_color_cmn(name);
+
+#if GTK_CHECK_VERSION(3,0,0)
+ return color;
+#else
+ if (color == INVALCOLOR)
+ return INVALCOLOR;
+
+ return gui_mch_get_rgb_color(
+ (color & 0xff0000) >> 16,
+ (color & 0xff00) >> 8,
+ color & 0xff);
+#endif
+}
+
+/*
+ * Return the Pixel value (color) for the given RGB values.
+ * Return INVALCOLOR for error.
+ */
+ guicolor_T
+gui_mch_get_rgb_color(int r, int g, int b)
+{
+#if GTK_CHECK_VERSION(3,0,0)
+ return gui_get_rgb_color_cmn(r, g, b);
+#else
+ GdkColor gcolor;
+ int ret;
+
+ gcolor.red = (guint16)(r / 255.0 * 65535 + 0.5);
+ gcolor.green = (guint16)(g / 255.0 * 65535 + 0.5);
+ gcolor.blue = (guint16)(b / 255.0 * 65535 + 0.5);
+
+ ret = gdk_colormap_alloc_color(gtk_widget_get_colormap(gui.drawarea),
+ &gcolor, FALSE, TRUE);
+
+ return ret != 0 ? (guicolor_T)gcolor.pixel : INVALCOLOR;
+#endif
+}
+
+/*
+ * Set the current text foreground color.
+ */
+ void
+gui_mch_set_fg_color(guicolor_T color)
+{
+#if GTK_CHECK_VERSION(3,0,0)
+ *gui.fgcolor = color_to_rgba(color);
+#else
+ gui.fgcolor->pixel = (unsigned long)color;
+#endif
+}
+
+/*
+ * Set the current text background color.
+ */
+ void
+gui_mch_set_bg_color(guicolor_T color)
+{
+#if GTK_CHECK_VERSION(3,0,0)
+ *gui.bgcolor = color_to_rgba(color);
+#else
+ gui.bgcolor->pixel = (unsigned long)color;
+#endif
+}
+
+/*
+ * Set the current text special color.
+ */
+ void
+gui_mch_set_sp_color(guicolor_T color)
+{
+#if GTK_CHECK_VERSION(3,0,0)
+ *gui.spcolor = color_to_rgba(color);
+#else
+ gui.spcolor->pixel = (unsigned long)color;
+#endif
+}
+
+/*
+ * Function-like convenience macro for the sake of efficiency.
+ */
+#define INSERT_PANGO_ATTR(Attribute, AttrList, Start, End) \
+ G_STMT_START{ \
+ PangoAttribute *tmp_attr_; \
+ tmp_attr_ = (Attribute); \
+ tmp_attr_->start_index = (Start); \
+ tmp_attr_->end_index = (End); \
+ pango_attr_list_insert((AttrList), tmp_attr_); \
+ }G_STMT_END
+
+ static void
+apply_wide_font_attr(char_u *s, int len, PangoAttrList *attr_list)
+{
+ char_u *start = NULL;
+ char_u *p;
+ int uc;
+
+ for (p = s; p < s + len; p += utf_byte2len(*p))
+ {
+ uc = utf_ptr2char(p);
+
+ if (start == NULL)
+ {
+ if (uc >= 0x80 && utf_char2cells(uc) == 2)
+ start = p;
+ }
+ else if (uc < 0x80 /* optimization shortcut */
+ || (utf_char2cells(uc) != 2 && !utf_iscomposing(uc)))
+ {
+ INSERT_PANGO_ATTR(pango_attr_font_desc_new(gui.wide_font),
+ attr_list, start - s, p - s);
+ start = NULL;
+ }
+ }
+
+ if (start != NULL)
+ INSERT_PANGO_ATTR(pango_attr_font_desc_new(gui.wide_font),
+ attr_list, start - s, len);
+}
+
+ static int
+count_cluster_cells(char_u *s, PangoItem *item,
+ PangoGlyphString* glyphs, int i,
+ int *cluster_width,
+ int *last_glyph_rbearing)
+{
+ char_u *p;
+ int next; /* glyph start index of next cluster */
+ int start, end; /* string segment of current cluster */
+ int width; /* real cluster width in Pango units */
+ int uc;
+ int cellcount = 0;
+
+ width = glyphs->glyphs[i].geometry.width;
+
+ for (next = i + 1; next < glyphs->num_glyphs; ++next)
+ {
+ if (glyphs->glyphs[next].attr.is_cluster_start)
+ break;
+ else if (glyphs->glyphs[next].geometry.width > width)
+ width = glyphs->glyphs[next].geometry.width;
+ }
+
+ start = item->offset + glyphs->log_clusters[i];
+ end = item->offset + ((next < glyphs->num_glyphs) ?
+ glyphs->log_clusters[next] : item->length);
+
+ for (p = s + start; p < s + end; p += utf_byte2len(*p))
+ {
+ uc = utf_ptr2char(p);
+ if (uc < 0x80)
+ ++cellcount;
+ else if (!utf_iscomposing(uc))
+ cellcount += utf_char2cells(uc);
+ }
+
+ if (last_glyph_rbearing != NULL
+ && cellcount > 0 && next == glyphs->num_glyphs)
+ {
+ PangoRectangle ink_rect;
+ /*
+ * If a certain combining mark had to be taken from a non-monospace
+ * font, we have to compensate manually by adapting x_offset according
+ * to the ink extents of the previous glyph.
+ */
+ pango_font_get_glyph_extents(item->analysis.font,
+ glyphs->glyphs[i].glyph,
+ &ink_rect, NULL);
+
+ if (PANGO_RBEARING(ink_rect) > 0)
+ *last_glyph_rbearing = PANGO_RBEARING(ink_rect);
+ }
+
+ if (cellcount > 0)
+ *cluster_width = width;
+
+ return cellcount;
+}
+
+/*
+ * If there are only combining characters in the cluster, we cannot just
+ * change the width of the previous glyph since there is none. Therefore
+ * some guesswork is needed.
+ *
+ * If ink_rect.x is negative Pango apparently has taken care of the composing
+ * by itself. Actually setting x_offset = 0 should be sufficient then, but due
+ * to problems with composing from different fonts we still need to fine-tune
+ * x_offset to avoid ugliness.
+ *
+ * If ink_rect.x is not negative, force overstriking by pointing x_offset to
+ * the position of the previous glyph. Apparently this happens only with old
+ * X fonts which don't provide the special combining information needed by
+ * Pango.
+ */
+ static void
+setup_zero_width_cluster(PangoItem *item, PangoGlyphInfo *glyph,
+ int last_cellcount, int last_cluster_width,
+ int last_glyph_rbearing)
+{
+ PangoRectangle ink_rect;
+ PangoRectangle logical_rect;
+ int width;
+
+ width = last_cellcount * gui.char_width * PANGO_SCALE;
+ glyph->geometry.x_offset = -width + MAX(0, width - last_cluster_width) / 2;
+ glyph->geometry.width = 0;
+
+ pango_font_get_glyph_extents(item->analysis.font,
+ glyph->glyph,
+ &ink_rect, &logical_rect);
+ if (ink_rect.x < 0)
+ {
+ glyph->geometry.x_offset += last_glyph_rbearing;
+ glyph->geometry.y_offset = logical_rect.height
+ - (gui.char_height - p_linespace) * PANGO_SCALE;
+ }
+ else
+ /* If the accent width is smaller than the cluster width, position it
+ * in the middle. */
+ glyph->geometry.x_offset = -width + MAX(0, width - ink_rect.width) / 2;
+}
+
+#if GTK_CHECK_VERSION(3,0,0)
+ static void
+draw_glyph_string(int row, int col, int num_cells, int flags,
+ PangoFont *font, PangoGlyphString *glyphs,
+ cairo_t *cr)
+#else
+ static void
+draw_glyph_string(int row, int col, int num_cells, int flags,
+ PangoFont *font, PangoGlyphString *glyphs)
+#endif
+{
+ if (!(flags & DRAW_TRANSP))
+ {
+#if GTK_CHECK_VERSION(3,0,0)
+ cairo_set_source_rgba(cr,
+ gui.bgcolor->red, gui.bgcolor->green, gui.bgcolor->blue,
+ gui.bgcolor->alpha);
+ cairo_rectangle(cr,
+ FILL_X(col), FILL_Y(row),
+ num_cells * gui.char_width, gui.char_height);
+ cairo_fill(cr);
+#else
+ gdk_gc_set_foreground(gui.text_gc, gui.bgcolor);
+
+ gdk_draw_rectangle(gui.drawarea->window,
+ gui.text_gc,
+ TRUE,
+ FILL_X(col),
+ FILL_Y(row),
+ num_cells * gui.char_width,
+ gui.char_height);
+#endif
+ }
+
+#if GTK_CHECK_VERSION(3,0,0)
+ cairo_set_source_rgba(cr,
+ gui.fgcolor->red, gui.fgcolor->green, gui.fgcolor->blue,
+ gui.fgcolor->alpha);
+ cairo_move_to(cr, TEXT_X(col), TEXT_Y(row));
+ pango_cairo_show_glyph_string(cr, font, glyphs);
+#else
+ gdk_gc_set_foreground(gui.text_gc, gui.fgcolor);
+
+ gdk_draw_glyphs(gui.drawarea->window,
+ gui.text_gc,
+ font,
+ TEXT_X(col),
+ TEXT_Y(row),
+ glyphs);
+#endif
+
+ /* redraw the contents with an offset of 1 to emulate bold */
+ if ((flags & DRAW_BOLD) && !gui.font_can_bold)
+#if GTK_CHECK_VERSION(3,0,0)
+ {
+ cairo_set_source_rgba(cr,
+ gui.fgcolor->red, gui.fgcolor->green, gui.fgcolor->blue,
+ gui.fgcolor->alpha);
+ cairo_move_to(cr, TEXT_X(col) + 1, TEXT_Y(row));
+ pango_cairo_show_glyph_string(cr, font, glyphs);
+ }
+#else
+ gdk_draw_glyphs(gui.drawarea->window,
+ gui.text_gc,
+ font,
+ TEXT_X(col) + 1,
+ TEXT_Y(row),
+ glyphs);
+#endif
+}
+
+/*
+ * Draw underline and undercurl at the bottom of the character cell.
+ */
+#if GTK_CHECK_VERSION(3,0,0)
+ static void
+draw_under(int flags, int row, int col, int cells, cairo_t *cr)
+#else
+ static void
+draw_under(int flags, int row, int col, int cells)
+#endif
+{
+ int i;
+ int offset;
+ static const int val[8] = {1, 0, 0, 0, 1, 2, 2, 2 };
+ int y = FILL_Y(row + 1) - 1;
+
+ /* Undercurl: draw curl at the bottom of the character cell. */
+ if (flags & DRAW_UNDERC)
+ {
+#if GTK_CHECK_VERSION(3,0,0)
+ cairo_set_line_width(cr, 1.0);
+ cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT);
+ cairo_set_source_rgba(cr,
+ gui.spcolor->red, gui.spcolor->green, gui.spcolor->blue,
+ gui.spcolor->alpha);
+ for (i = FILL_X(col); i < FILL_X(col + cells); ++i)
+ {
+ offset = val[i % 8];
+ cairo_line_to(cr, i, y - offset + 0.5);
+ }
+ cairo_stroke(cr);
+#else
+ gdk_gc_set_foreground(gui.text_gc, gui.spcolor);
+ for (i = FILL_X(col); i < FILL_X(col + cells); ++i)
+ {
+ offset = val[i % 8];
+ gdk_draw_point(gui.drawarea->window, gui.text_gc, i, y - offset);
+ }
+ gdk_gc_set_foreground(gui.text_gc, gui.fgcolor);
+#endif
+ }
+
+ /* Draw a strikethrough line */
+ if (flags & DRAW_STRIKE)
+ {
+#if GTK_CHECK_VERSION(3,0,0)
+ cairo_set_line_width(cr, 1.0);
+ cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT);
+ cairo_set_source_rgba(cr,
+ gui.spcolor->red, gui.spcolor->green, gui.spcolor->blue,
+ gui.spcolor->alpha);
+ cairo_move_to(cr, FILL_X(col), y + 1 - gui.char_height/2 + 0.5);
+ cairo_line_to(cr, FILL_X(col + cells), y + 1 - gui.char_height/2 + 0.5);
+ cairo_stroke(cr);
+#else
+ gdk_gc_set_foreground(gui.text_gc, gui.spcolor);
+ gdk_draw_line(gui.drawarea->window, gui.text_gc,
+ FILL_X(col), y + 1 - gui.char_height/2,
+ FILL_X(col + cells), y + 1 - gui.char_height/2);
+ gdk_gc_set_foreground(gui.text_gc, gui.fgcolor);
+#endif
+ }
+
+ /* Underline: draw a line at the bottom of the character cell. */
+ if (flags & DRAW_UNDERL)
+ {
+ /* When p_linespace is 0, overwrite the bottom row of pixels.
+ * Otherwise put the line just below the character. */
+ if (p_linespace > 1)
+ y -= p_linespace - 1;
+#if GTK_CHECK_VERSION(3,0,0)
+ cairo_set_line_width(cr, 1.0);
+ cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT);
+ cairo_set_source_rgba(cr,
+ gui.fgcolor->red, gui.fgcolor->green, gui.fgcolor->blue,
+ gui.fgcolor->alpha);
+ cairo_move_to(cr, FILL_X(col), y + 0.5);
+ cairo_line_to(cr, FILL_X(col + cells), y + 0.5);
+ cairo_stroke(cr);
+#else
+ gdk_draw_line(gui.drawarea->window, gui.text_gc,
+ FILL_X(col), y,
+ FILL_X(col + cells) - 1, y);
+#endif
+ }
+}
+
+ int
+gui_gtk2_draw_string(int row, int col, char_u *s, int len, int flags)
+{
+ GdkRectangle area; /* area for clip mask */
+ PangoGlyphString *glyphs; /* glyphs of current item */
+ int column_offset = 0; /* column offset in cells */
+ int i;
+ char_u *conv_buf = NULL; /* result of UTF-8 conversion */
+ char_u *new_conv_buf;
+ int convlen;
+ char_u *sp, *bp;
+ int plen;
+#if GTK_CHECK_VERSION(3,0,0)
+ cairo_t *cr;
+#endif
+
+ if (gui.text_context == NULL || gtk_widget_get_window(gui.drawarea) == NULL)
+ return len;
+
+ if (output_conv.vc_type != CONV_NONE)
+ {
+ /*
+ * Convert characters from 'encoding' to 'termencoding', which is set
+ * to UTF-8 by gui_mch_init(). did_set_string_option() in option.c
+ * prohibits changing this to something else than UTF-8 if the GUI is
+ * in use.
+ */
+ convlen = len;
+ conv_buf = string_convert(&output_conv, s, &convlen);
+ g_return_val_if_fail(conv_buf != NULL, len);
+
+ /* Correct for differences in char width: some chars are
+ * double-wide in 'encoding' but single-wide in utf-8. Add a space to
+ * compensate for that. */
+ for (sp = s, bp = conv_buf; sp < s + len && bp < conv_buf + convlen; )
+ {
+ plen = utf_ptr2len(bp);
+ if ((*mb_ptr2cells)(sp) == 2 && utf_ptr2cells(bp) == 1)
+ {
+ new_conv_buf = alloc(convlen + 2);
+ if (new_conv_buf == NULL)
+ return len;
+ plen += bp - conv_buf;
+ mch_memmove(new_conv_buf, conv_buf, plen);
+ new_conv_buf[plen] = ' ';
+ mch_memmove(new_conv_buf + plen + 1, conv_buf + plen,
+ convlen - plen + 1);
+ vim_free(conv_buf);
+ conv_buf = new_conv_buf;
+ ++convlen;
+ bp = conv_buf + plen;
+ plen = 1;
+ }
+ sp += (*mb_ptr2len)(sp);
+ bp += plen;
+ }
+ s = conv_buf;
+ len = convlen;
+ }
+
+ /*
+ * Restrict all drawing to the current screen line in order to prevent
+ * fuzzy font lookups from messing up the screen.
+ */
+ area.x = gui.border_offset;
+ area.y = FILL_Y(row);
+ area.width = gui.num_cols * gui.char_width;
+ area.height = gui.char_height;
+
+#if GTK_CHECK_VERSION(3,0,0)
+ cr = cairo_create(gui.surface);
+ cairo_rectangle(cr, area.x, area.y, area.width, area.height);
+ cairo_clip(cr);
+#else
+ gdk_gc_set_clip_origin(gui.text_gc, 0, 0);
+ gdk_gc_set_clip_rectangle(gui.text_gc, &area);
+#endif
+
+ glyphs = pango_glyph_string_new();
+
+ /*
+ * Optimization hack: If possible, skip the itemize and shaping process
+ * for pure ASCII strings. This optimization is particularly effective
+ * because Vim draws space characters to clear parts of the screen.
+ */
+ if (!(flags & DRAW_ITALIC)
+ && !((flags & DRAW_BOLD) && gui.font_can_bold)
+ && gui.ascii_glyphs != NULL)
+ {
+ char_u *p;
+
+ for (p = s; p < s + len; ++p)
+ if (*p & 0x80)
+ goto not_ascii;
+
+ pango_glyph_string_set_size(glyphs, len);
+
+ for (i = 0; i < len; ++i)
+ {
+ glyphs->glyphs[i] = gui.ascii_glyphs->glyphs[2 * s[i]];
+ glyphs->log_clusters[i] = i;
+ }
+
+#if GTK_CHECK_VERSION(3,0,0)
+ draw_glyph_string(row, col, len, flags, gui.ascii_font, glyphs, cr);
+#else
+ draw_glyph_string(row, col, len, flags, gui.ascii_font, glyphs);
+#endif
+
+ column_offset = len;
+ }
+ else
+not_ascii:
+ {
+ PangoAttrList *attr_list;
+ GList *item_list;
+ int cluster_width;
+ int last_glyph_rbearing;
+ int cells = 0; /* cells occupied by current cluster */
+
+ /* Safety check: pango crashes when invoked with invalid utf-8
+ * characters. */
+ if (!utf_valid_string(s, s + len))
+ {
+ column_offset = len;
+ goto skipitall;
+ }
+
+ /* original width of the current cluster */
+ cluster_width = PANGO_SCALE * gui.char_width;
+
+ /* right bearing of the last non-composing glyph */
+ last_glyph_rbearing = PANGO_SCALE * gui.char_width;
+
+ attr_list = pango_attr_list_new();
+
+ /* If 'guifontwide' is set then use that for double-width characters.
+ * Otherwise just go with 'guifont' and let Pango do its thing. */
+ if (gui.wide_font != NULL)
+ apply_wide_font_attr(s, len, attr_list);
+
+ if ((flags & DRAW_BOLD) && gui.font_can_bold)
+ INSERT_PANGO_ATTR(pango_attr_weight_new(PANGO_WEIGHT_BOLD),
+ attr_list, 0, len);
+ if (flags & DRAW_ITALIC)
+ INSERT_PANGO_ATTR(pango_attr_style_new(PANGO_STYLE_ITALIC),
+ attr_list, 0, len);
+ /*
+ * Break the text into segments with consistent directional level
+ * and shaping engine. Pure Latin text needs only a single segment,
+ * so there's no need to worry about the loop's efficiency. Better
+ * try to optimize elsewhere, e.g. reducing exposes and stuff :)
+ */
+ item_list = pango_itemize(gui.text_context,
+ (const char *)s, 0, len, attr_list, NULL);
+
+ while (item_list != NULL)
+ {
+ PangoItem *item;
+ int item_cells = 0; /* item length in cells */
+
+ item = (PangoItem *)item_list->data;
+ item_list = g_list_delete_link(item_list, item_list);
+ /*
+ * Increment the bidirectional embedding level by 1 if it is not
+ * even. An odd number means the output will be RTL, but we don't
+ * want that since Vim handles right-to-left text on its own. It
+ * would probably be sufficient to just set level = 0, but you can
+ * never know :)
+ *
+ * Unfortunately we can't take advantage of Pango's ability to
+ * render both LTR and RTL at the same time. In order to support
+ * that, Vim's main screen engine would have to make use of Pango
+ * functionality.
+ */
+ item->analysis.level = (item->analysis.level + 1) & (~1U);
+
+ /* HACK: Overrule the shape engine, we don't want shaping to be
+ * done, because drawing the cursor would change the display. */
+ item->analysis.shape_engine = default_shape_engine;
+
+#ifdef HAVE_PANGO_SHAPE_FULL
+ pango_shape_full((const char *)s + item->offset, item->length,
+ (const char *)s, len, &item->analysis, glyphs);
+#else
+ pango_shape((const char *)s + item->offset, item->length,
+ &item->analysis, glyphs);
+#endif
+ /*
+ * Fixed-width hack: iterate over the array and assign a fixed
+ * width to each glyph, thus overriding the choice made by the
+ * shaping engine. We use utf_char2cells() to determine the
+ * number of cells needed.
+ *
+ * Also perform all kind of dark magic to get composing
+ * characters right (and pretty too of course).
+ */
+ for (i = 0; i < glyphs->num_glyphs; ++i)
+ {
+ PangoGlyphInfo *glyph;
+
+ glyph = &glyphs->glyphs[i];
+
+ if (glyph->attr.is_cluster_start)
+ {
+ int cellcount;
+
+ cellcount = count_cluster_cells(
+ s, item, glyphs, i, &cluster_width,
+ (item_list != NULL) ? &last_glyph_rbearing : NULL);
+
+ if (cellcount > 0)
+ {
+ int width;
+
+ width = cellcount * gui.char_width * PANGO_SCALE;
+ glyph->geometry.x_offset +=
+ MAX(0, width - cluster_width) / 2;
+ glyph->geometry.width = width;
+ }
+ else
+ {
+ /* If there are only combining characters in the
+ * cluster, we cannot just change the width of the
+ * previous glyph since there is none. Therefore
+ * some guesswork is needed. */
+ setup_zero_width_cluster(item, glyph, cells,
+ cluster_width,
+ last_glyph_rbearing);
+ }
+
+ item_cells += cellcount;
+ cells = cellcount;
+ }
+ else if (i > 0)
+ {
+ int width;
+
+ /* There is a previous glyph, so we deal with combining
+ * characters the canonical way.
+ * In some circumstances Pango uses a positive x_offset,
+ * then use the width of the previous glyph for this one
+ * and set the previous width to zero.
+ * Otherwise we get a negative x_offset, Pango has already
+ * positioned the combining char, keep the widths as they
+ * are.
+ * For both adjust the x_offset to position the glyph in
+ * the middle. */
+ if (glyph->geometry.x_offset >= 0)
+ {
+ glyphs->glyphs[i].geometry.width =
+ glyphs->glyphs[i - 1].geometry.width;
+ glyphs->glyphs[i - 1].geometry.width = 0;
+ }
+ width = cells * gui.char_width * PANGO_SCALE;
+ glyph->geometry.x_offset +=
+ MAX(0, width - cluster_width) / 2;
+ }
+ else /* i == 0 "cannot happen" */
+ {
+ glyph->geometry.width = 0;
+ }
+ }
+
+ /*** Aaaaand action! ***/
+#if GTK_CHECK_VERSION(3,0,0)
+ draw_glyph_string(row, col + column_offset, item_cells,
+ flags, item->analysis.font, glyphs,
+ cr);
+#else
+ draw_glyph_string(row, col + column_offset, item_cells,
+ flags, item->analysis.font, glyphs);
+#endif
+
+ pango_item_free(item);
+
+ column_offset += item_cells;
+ }
+
+ pango_attr_list_unref(attr_list);
+ }
+
+skipitall:
+ /* Draw underline and undercurl. */
+#if GTK_CHECK_VERSION(3,0,0)
+ draw_under(flags, row, col, column_offset, cr);
+#else
+ draw_under(flags, row, col, column_offset);
+#endif
+
+ pango_glyph_string_free(glyphs);
+ vim_free(conv_buf);
+
+#if GTK_CHECK_VERSION(3,0,0)
+ cairo_destroy(cr);
+ if (!gui.by_signal)
+ gdk_window_invalidate_rect(gtk_widget_get_window(gui.drawarea),
+ &area, FALSE);
+#else
+ gdk_gc_set_clip_rectangle(gui.text_gc, NULL);
+#endif
+
+ return column_offset;
+}
+
+/*
+ * 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 != 0; i++)
+ if (name[0] == special_keys[i].code0
+ && name[1] == special_keys[i].code1)
+ return OK;
+ return FAIL;
+}
+
+#if defined(FEAT_TITLE) || defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * Return the text window-id and display. Only required for X-based GUI's
+ */
+ int
+gui_get_x11_windis(Window *win, Display **dis)
+{
+ if (gui.mainwin != NULL && gtk_widget_get_window(gui.mainwin) != NULL)
+ {
+ *dis = GDK_WINDOW_XDISPLAY(gtk_widget_get_window(gui.mainwin));
+ *win = GDK_WINDOW_XID(gtk_widget_get_window(gui.mainwin));
+ return OK;
+ }
+
+ *dis = NULL;
+ *win = 0;
+ return FAIL;
+}
+#endif
+
+#if defined(FEAT_CLIENTSERVER) \
+ || (defined(FEAT_X11) && defined(FEAT_CLIPBOARD)) || defined(PROTO)
+
+ Display *
+gui_mch_get_display(void)
+{
+ if (gui.mainwin != NULL && gtk_widget_get_window(gui.mainwin) != NULL)
+ return GDK_WINDOW_XDISPLAY(gtk_widget_get_window(gui.mainwin));
+ else
+ return NULL;
+}
+#endif
+
+ void
+gui_mch_beep(void)
+{
+ GdkDisplay *display;
+
+ if (gui.mainwin != NULL && gtk_widget_get_realized(gui.mainwin))
+ display = gtk_widget_get_display(gui.mainwin);
+ else
+ display = gdk_display_get_default();
+
+ if (display != NULL)
+ gdk_display_beep(display);
+}
+
+ void
+gui_mch_flash(int msec)
+{
+#if GTK_CHECK_VERSION(3,0,0)
+ /* TODO Replace GdkGC with Cairo */
+ (void)msec;
+#else
+ GdkGCValues values;
+ GdkGC *invert_gc;
+
+ if (gui.drawarea->window == NULL)
+ return;
+
+ values.foreground.pixel = gui.norm_pixel ^ gui.back_pixel;
+ values.background.pixel = gui.norm_pixel ^ gui.back_pixel;
+ values.function = GDK_XOR;
+ invert_gc = gdk_gc_new_with_values(gui.drawarea->window,
+ &values,
+ GDK_GC_FOREGROUND |
+ GDK_GC_BACKGROUND |
+ GDK_GC_FUNCTION);
+ gdk_gc_set_exposures(invert_gc,
+ gui.visibility != GDK_VISIBILITY_UNOBSCURED);
+ /*
+ * Do a visual beep by changing back and forth in some undetermined way,
+ * the foreground and background colors. This is due to the fact that
+ * there can't be really any prediction about the effects of XOR on
+ * arbitrary X11 servers. However this seems to be enough for what we
+ * intend it to do.
+ */
+ gdk_draw_rectangle(gui.drawarea->window, invert_gc,
+ TRUE,
+ 0, 0,
+ FILL_X((int)Columns) + gui.border_offset,
+ FILL_Y((int)Rows) + gui.border_offset);
+
+ gui_mch_flush();
+ ui_delay((long)msec, TRUE); /* wait so many msec */
+
+ gdk_draw_rectangle(gui.drawarea->window, invert_gc,
+ TRUE,
+ 0, 0,
+ FILL_X((int)Columns) + gui.border_offset,
+ FILL_Y((int)Rows) + gui.border_offset);
+
+ gdk_gc_destroy(invert_gc);
+#endif
+}
+
+/*
+ * 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)
+{
+#if GTK_CHECK_VERSION(3,0,0)
+ const GdkRectangle rect = {
+ FILL_X(c), FILL_Y(r), nc * gui.char_width, nr * gui.char_height
+ };
+ cairo_t * const cr = cairo_create(gui.surface);
+
+ set_cairo_source_rgba_from_color(cr, gui.norm_pixel ^ gui.back_pixel);
+# if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1,9,2)
+ cairo_set_operator(cr, CAIRO_OPERATOR_DIFFERENCE);
+# else
+ /* Give an implementation for older cairo versions if necessary. */
+# endif
+ gdk_cairo_rectangle(cr, &rect);
+ cairo_fill(cr);
+
+ cairo_destroy(cr);
+
+ if (!gui.by_signal)
+ gtk_widget_queue_draw_area(gui.drawarea, rect.x, rect.y,
+ rect.width, rect.height);
+#else
+ GdkGCValues values;
+ GdkGC *invert_gc;
+
+ if (gui.drawarea->window == NULL)
+ return;
+
+ values.foreground.pixel = gui.norm_pixel ^ gui.back_pixel;
+ values.background.pixel = gui.norm_pixel ^ gui.back_pixel;
+ values.function = GDK_XOR;
+ invert_gc = gdk_gc_new_with_values(gui.drawarea->window,
+ &values,
+ GDK_GC_FOREGROUND |
+ GDK_GC_BACKGROUND |
+ GDK_GC_FUNCTION);
+ gdk_gc_set_exposures(invert_gc, gui.visibility !=
+ GDK_VISIBILITY_UNOBSCURED);
+ gdk_draw_rectangle(gui.drawarea->window, invert_gc,
+ TRUE,
+ FILL_X(c), FILL_Y(r),
+ (nc) * gui.char_width, (nr) * gui.char_height);
+ gdk_gc_destroy(invert_gc);
+#endif
+}
+
+/*
+ * Iconify the GUI window.
+ */
+ void
+gui_mch_iconify(void)
+{
+ gtk_window_iconify(GTK_WINDOW(gui.mainwin));
+}
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * Bring the Vim window to the foreground.
+ */
+ void
+gui_mch_set_foreground(void)
+{
+ gtk_window_present(GTK_WINDOW(gui.mainwin));
+}
+#endif
+
+/*
+ * Draw a cursor without focus.
+ */
+ void
+gui_mch_draw_hollow_cursor(guicolor_T color)
+{
+ int i = 1;
+#if GTK_CHECK_VERSION(3,0,0)
+ cairo_t *cr;
+#endif
+
+ if (gtk_widget_get_window(gui.drawarea) == NULL)
+ return;
+
+#if GTK_CHECK_VERSION(3,0,0)
+ cr = cairo_create(gui.surface);
+#endif
+
+ gui_mch_set_fg_color(color);
+
+#if GTK_CHECK_VERSION(3,0,0)
+ cairo_set_source_rgba(cr,
+ gui.fgcolor->red, gui.fgcolor->green, gui.fgcolor->blue,
+ gui.fgcolor->alpha);
+#else
+ gdk_gc_set_foreground(gui.text_gc, gui.fgcolor);
+#endif
+ if (mb_lefthalve(gui.row, gui.col))
+ i = 2;
+#if GTK_CHECK_VERSION(3,0,0)
+ cairo_set_line_width(cr, 1.0);
+ cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT);
+ cairo_rectangle(cr,
+ FILL_X(gui.col) + 0.5, FILL_Y(gui.row) + 0.5,
+ i * gui.char_width - 1, gui.char_height - 1);
+ cairo_stroke(cr);
+ cairo_destroy(cr);
+#else
+ gdk_draw_rectangle(gui.drawarea->window, gui.text_gc,
+ FALSE,
+ FILL_X(gui.col), FILL_Y(gui.row),
+ i * gui.char_width - 1, gui.char_height - 1);
+#endif
+}
+
+/*
+ * Draw part of a cursor, "w" pixels wide, and "h" pixels high, using
+ * color "color".
+ */
+ void
+gui_mch_draw_part_cursor(int w, int h, guicolor_T color)
+{
+ if (gtk_widget_get_window(gui.drawarea) == NULL)
+ return;
+
+ gui_mch_set_fg_color(color);
+
+#if GTK_CHECK_VERSION(3,0,0)
+ {
+ cairo_t *cr;
+
+ cr = cairo_create(gui.surface);
+ cairo_set_source_rgba(cr,
+ gui.fgcolor->red, gui.fgcolor->green, gui.fgcolor->blue,
+ gui.fgcolor->alpha);
+ cairo_rectangle(cr,
+# ifdef FEAT_RIGHTLEFT
+ /* vertical line should be on the right of current point */
+ CURSOR_BAR_RIGHT ? FILL_X(gui.col + 1) - w :
+# endif
+ FILL_X(gui.col), FILL_Y(gui.row) + gui.char_height - h,
+ w, h);
+ cairo_fill(cr);
+ cairo_destroy(cr);
+ }
+#else /* !GTK_CHECK_VERSION(3,0,0) */
+ gdk_gc_set_foreground(gui.text_gc, gui.fgcolor);
+ gdk_draw_rectangle(gui.drawarea->window, gui.text_gc,
+ TRUE,
+# ifdef FEAT_RIGHTLEFT
+ /* vertical line should be on the right of current point */
+ CURSOR_BAR_RIGHT ? FILL_X(gui.col + 1) - w :
+# endif
+ FILL_X(gui.col),
+ FILL_Y(gui.row) + gui.char_height - h,
+ w, h);
+#endif /* !GTK_CHECK_VERSION(3,0,0) */
+}
+
+
+/*
+ * Catch up with any queued X11 events. This may put keyboard input into the
+ * input buffer, call resize call-backs, trigger timers etc. If there is
+ * nothing in the X11 event queue (& no timers pending), then we return
+ * immediately.
+ */
+ void
+gui_mch_update(void)
+{
+ while (g_main_context_pending(NULL) && !vim_is_input_buf_full())
+ g_main_context_iteration(NULL, TRUE);
+}
+
+ static timeout_cb_type
+input_timer_cb(gpointer data)
+{
+ int *timed_out = (int *) data;
+
+ /* Just inform the caller about the occurrence of it */
+ *timed_out = TRUE;
+
+ return FALSE; /* don't happen again */
+}
+
+#ifdef FEAT_JOB_CHANNEL
+ static timeout_cb_type
+channel_poll_cb(gpointer data UNUSED)
+{
+ /* Using an event handler for a channel that may be disconnected does
+ * not work, it hangs. Instead poll for messages. */
+ channel_handle_events(TRUE);
+ parse_queued_messages();
+
+ return TRUE; /* repeat */
+}
+#endif
+
+/*
+ * 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(long wtime)
+{
+ int focus;
+ guint timer;
+ static int timed_out;
+ int retval = FAIL;
+#ifdef FEAT_JOB_CHANNEL
+ guint channel_timer = 0;
+#endif
+
+ timed_out = FALSE;
+
+ // This timeout makes sure that we will return if no characters arrived in
+ // time. If "wtime" is zero just use one.
+ if (wtime >= 0)
+ timer = timeout_add(wtime == 0 ? 1L : wtime,
+ input_timer_cb, &timed_out);
+ else
+ timer = 0;
+
+#ifdef FEAT_JOB_CHANNEL
+ /* If there is a channel with the keep_open flag we need to poll for input
+ * on them. */
+ if (channel_any_keep_open())
+ channel_timer = timeout_add(20, channel_poll_cb, NULL);
+#endif
+
+ focus = gui.in_focus;
+
+ do
+ {
+ /* Stop or start blinking when focus changes */
+ if (gui.in_focus != focus)
+ {
+ if (gui.in_focus)
+ gui_mch_start_blink();
+ else
+ gui_mch_stop_blink(TRUE);
+ focus = gui.in_focus;
+ }
+
+#ifdef MESSAGE_QUEUE
+# ifdef FEAT_TIMERS
+ did_add_timer = FALSE;
+# endif
+ parse_queued_messages();
+# ifdef FEAT_TIMERS
+ if (did_add_timer)
+ /* Need to recompute the waiting time. */
+ goto theend;
+# endif
+#endif
+
+ /*
+ * Loop in GTK+ processing until a timeout or input occurs.
+ * Skip this if input is available anyway (can happen in rare
+ * situations, sort of race condition).
+ */
+ if (!input_available())
+ g_main_context_iteration(NULL, TRUE);
+
+ /* Got char, return immediately */
+ if (input_available())
+ {
+ retval = OK;
+ goto theend;
+ }
+ } while (wtime < 0 || !timed_out);
+
+ /*
+ * Flush all eventually pending (drawing) events.
+ */
+ gui_mch_update();
+
+theend:
+ if (timer != 0 && !timed_out)
+ timeout_remove(timer);
+#ifdef FEAT_JOB_CHANNEL
+ if (channel_timer != 0)
+ timeout_remove(channel_timer);
+#endif
+
+ return retval;
+}
+
+
+/****************************************************************************
+ * Output drawing routines.
+ ****************************************************************************/
+
+
+/* Flush any output to the screen */
+ void
+gui_mch_flush(void)
+{
+ if (gui.mainwin != NULL && gtk_widget_get_realized(gui.mainwin))
+#if GTK_CHECK_VERSION(2,4,0)
+ gdk_display_flush(gtk_widget_get_display(gui.mainwin));
+#else
+ gdk_display_sync(gtk_widget_get_display(gui.mainwin));
+#endif
+}
+
+/*
+ * Clear a rectangular region of the screen from text pos (row1, col1) to
+ * (row2, col2) inclusive.
+ */
+ void
+gui_mch_clear_block(int row1arg, int col1arg, int row2arg, int col2arg)
+{
+
+ int col1 = check_col(col1arg);
+ int col2 = check_col(col2arg);
+ int row1 = check_row(row1arg);
+ int row2 = check_row(row2arg);
+
+#if GTK_CHECK_VERSION(3,0,0)
+ if (gtk_widget_get_window(gui.drawarea) == NULL)
+ return;
+#else
+ GdkColor color;
+
+ if (gui.drawarea->window == NULL)
+ return;
+
+ color.pixel = gui.back_pixel;
+#endif
+
+#if GTK_CHECK_VERSION(3,0,0)
+ {
+ /* Add one pixel to the far right column in case a double-stroked
+ * bold glyph may sit there. */
+ const GdkRectangle rect = {
+ FILL_X(col1), FILL_Y(row1),
+ (col2 - col1 + 1) * gui.char_width + (col2 == Columns - 1),
+ (row2 - row1 + 1) * gui.char_height
+ };
+ GdkWindow * const win = gtk_widget_get_window(gui.drawarea);
+ cairo_t * const cr = cairo_create(gui.surface);
+# if GTK_CHECK_VERSION(3,22,2)
+ set_cairo_source_rgba_from_color(cr, gui.back_pixel);
+# else
+ cairo_pattern_t * const pat = gdk_window_get_background_pattern(win);
+ if (pat != NULL)
+ cairo_set_source(cr, pat);
+ else
+ set_cairo_source_rgba_from_color(cr, gui.back_pixel);
+# endif
+ gdk_cairo_rectangle(cr, &rect);
+ cairo_fill(cr);
+ cairo_destroy(cr);
+
+ if (!gui.by_signal)
+ gdk_window_invalidate_rect(win, &rect, FALSE);
+ }
+#else /* !GTK_CHECK_VERSION(3,0,0) */
+ gdk_gc_set_foreground(gui.text_gc, &color);
+
+ /* Clear one extra pixel at the far right, for when bold characters have
+ * spilled over to the window border. */
+ gdk_draw_rectangle(gui.drawarea->window, gui.text_gc, TRUE,
+ FILL_X(col1), FILL_Y(row1),
+ (col2 - col1 + 1) * gui.char_width
+ + (col2 == Columns - 1),
+ (row2 - row1 + 1) * gui.char_height);
+#endif /* !GTK_CHECK_VERSION(3,0,0) */
+}
+
+#if GTK_CHECK_VERSION(3,0,0)
+ static void
+gui_gtk_window_clear(GdkWindow *win)
+{
+ const GdkRectangle rect = {
+ 0, 0, gdk_window_get_width(win), gdk_window_get_height(win)
+ };
+ cairo_t * const cr = cairo_create(gui.surface);
+# if GTK_CHECK_VERSION(3,22,2)
+ set_cairo_source_rgba_from_color(cr, gui.back_pixel);
+# else
+ cairo_pattern_t * const pat = gdk_window_get_background_pattern(win);
+ if (pat != NULL)
+ cairo_set_source(cr, pat);
+ else
+ set_cairo_source_rgba_from_color(cr, gui.back_pixel);
+# endif
+ gdk_cairo_rectangle(cr, &rect);
+ cairo_fill(cr);
+ cairo_destroy(cr);
+
+ if (!gui.by_signal)
+ gdk_window_invalidate_rect(win, &rect, FALSE);
+}
+#else
+# define gui_gtk_window_clear(win) gdk_window_clear(win)
+#endif
+
+ void
+gui_mch_clear_all(void)
+{
+ if (gtk_widget_get_window(gui.drawarea) != NULL)
+ gui_gtk_window_clear(gtk_widget_get_window(gui.drawarea));
+}
+
+#if !GTK_CHECK_VERSION(3,0,0)
+/*
+ * Redraw any text revealed by scrolling up/down.
+ */
+ static void
+check_copy_area(void)
+{
+ GdkEvent *event;
+ int expose_count;
+
+ if (gui.visibility != GDK_VISIBILITY_PARTIAL)
+ return;
+
+ /* Avoid redrawing the cursor while scrolling or it'll end up where
+ * we don't want it to be. I'm not sure if it's correct to call
+ * gui_dont_update_cursor() at this point but it works as a quick
+ * fix for now. */
+ gui_dont_update_cursor(TRUE);
+
+ do
+ {
+ /* Wait to check whether the scroll worked or not. */
+ event = gdk_event_get_graphics_expose(gui.drawarea->window);
+
+ if (event == NULL)
+ break; /* received NoExpose event */
+
+ gui_redraw(event->expose.area.x, event->expose.area.y,
+ event->expose.area.width, event->expose.area.height);
+
+ expose_count = event->expose.count;
+ gdk_event_free(event);
+ }
+ while (expose_count > 0); /* more events follow */
+
+ gui_can_update_cursor();
+}
+#endif /* !GTK_CHECK_VERSION(3,0,0) */
+
+#if GTK_CHECK_VERSION(3,0,0)
+ static void
+gui_gtk_surface_copy_rect(int dest_x, int dest_y,
+ int src_x, int src_y,
+ int width, int height)
+{
+ cairo_t * const cr = cairo_create(gui.surface);
+
+ cairo_rectangle(cr, dest_x, dest_y, width, height);
+ cairo_clip(cr);
+ cairo_push_group(cr);
+ cairo_set_source_surface(cr, gui.surface, dest_x - src_x, dest_y - src_y);
+ cairo_paint(cr);
+ cairo_pop_group_to_source(cr);
+ cairo_paint(cr);
+
+ cairo_destroy(cr);
+}
+#endif
+
+/*
+ * 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)
+{
+#if GTK_CHECK_VERSION(3,0,0)
+ const int ncols = gui.scroll_region_right - gui.scroll_region_left + 1;
+ const int nrows = gui.scroll_region_bot - row + 1;
+ const int src_nrows = nrows - num_lines;
+
+ gui_gtk_surface_copy_rect(
+ FILL_X(gui.scroll_region_left), FILL_Y(row),
+ FILL_X(gui.scroll_region_left), FILL_Y(row + num_lines),
+ gui.char_width * ncols + 1, gui.char_height * src_nrows);
+ gui_clear_block(
+ gui.scroll_region_bot - num_lines + 1, gui.scroll_region_left,
+ gui.scroll_region_bot, gui.scroll_region_right);
+ gui_gtk3_redraw(
+ FILL_X(gui.scroll_region_left), FILL_Y(row),
+ gui.char_width * ncols + 1, gui.char_height * nrows);
+ if (!gui.by_signal)
+ gtk_widget_queue_draw_area(gui.drawarea,
+ FILL_X(gui.scroll_region_left), FILL_Y(row),
+ gui.char_width * ncols + 1, gui.char_height * nrows);
+#else
+ if (gui.visibility == GDK_VISIBILITY_FULLY_OBSCURED)
+ return; /* Can't see the window */
+
+ gdk_gc_set_foreground(gui.text_gc, gui.fgcolor);
+ gdk_gc_set_background(gui.text_gc, gui.bgcolor);
+
+ /* copy one extra pixel, for when bold has spilled over */
+ gdk_window_copy_area(gui.drawarea->window, gui.text_gc,
+ FILL_X(gui.scroll_region_left), FILL_Y(row),
+ gui.drawarea->window,
+ FILL_X(gui.scroll_region_left),
+ FILL_Y(row + num_lines),
+ gui.char_width * (gui.scroll_region_right
+ - gui.scroll_region_left + 1) + 1,
+ gui.char_height * (gui.scroll_region_bot - row - num_lines + 1));
+
+ gui_clear_block(gui.scroll_region_bot - num_lines + 1,
+ gui.scroll_region_left,
+ gui.scroll_region_bot, gui.scroll_region_right);
+ check_copy_area();
+#endif /* !GTK_CHECK_VERSION(3,0,0) */
+}
+
+/*
+ * 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)
+{
+#if GTK_CHECK_VERSION(3,0,0)
+ const int ncols = gui.scroll_region_right - gui.scroll_region_left + 1;
+ const int nrows = gui.scroll_region_bot - row + 1;
+ const int src_nrows = nrows - num_lines;
+
+ gui_gtk_surface_copy_rect(
+ FILL_X(gui.scroll_region_left), FILL_Y(row + num_lines),
+ FILL_X(gui.scroll_region_left), FILL_Y(row),
+ gui.char_width * ncols + 1, gui.char_height * src_nrows);
+ gui_mch_clear_block(
+ row, gui.scroll_region_left,
+ row + num_lines - 1, gui.scroll_region_right);
+ gui_gtk3_redraw(
+ FILL_X(gui.scroll_region_left), FILL_Y(row),
+ gui.char_width * ncols + 1, gui.char_height * nrows);
+ if (!gui.by_signal)
+ gtk_widget_queue_draw_area(gui.drawarea,
+ FILL_X(gui.scroll_region_left), FILL_Y(row),
+ gui.char_width * ncols + 1, gui.char_height * nrows);
+#else
+ if (gui.visibility == GDK_VISIBILITY_FULLY_OBSCURED)
+ return; /* Can't see the window */
+
+ gdk_gc_set_foreground(gui.text_gc, gui.fgcolor);
+ gdk_gc_set_background(gui.text_gc, gui.bgcolor);
+
+ /* copy one extra pixel, for when bold has spilled over */
+ gdk_window_copy_area(gui.drawarea->window, gui.text_gc,
+ FILL_X(gui.scroll_region_left), FILL_Y(row + num_lines),
+ gui.drawarea->window,
+ FILL_X(gui.scroll_region_left), FILL_Y(row),
+ gui.char_width * (gui.scroll_region_right
+ - gui.scroll_region_left + 1) + 1,
+ gui.char_height * (gui.scroll_region_bot - row - num_lines + 1));
+
+ gui_clear_block(row, gui.scroll_region_left,
+ row + num_lines - 1, gui.scroll_region_right);
+ check_copy_area();
+#endif /* !GTK_CHECK_VERSION(3,0,0) */
+}
+
+/*
+ * X Selection stuff, for cutting and pasting text to other windows.
+ */
+ void
+clip_mch_request_selection(VimClipboard *cbd)
+{
+ GdkAtom target;
+ unsigned i;
+ time_t start;
+
+ for (i = 0; i < N_SELECTION_TARGETS; ++i)
+ {
+ if (!clip_html && selection_targets[i].info == TARGET_HTML)
+ continue;
+ received_selection = RS_NONE;
+ target = gdk_atom_intern(selection_targets[i].target, FALSE);
+
+ gtk_selection_convert(gui.drawarea,
+ cbd->gtk_sel_atom, target,
+ (guint32)GDK_CURRENT_TIME);
+
+ /* Hack: Wait up to three seconds for the selection. A hang was
+ * noticed here when using the netrw plugin combined with ":gui"
+ * during the FocusGained event. */
+ start = time(NULL);
+ while (received_selection == RS_NONE && time(NULL) < start + 3)
+ g_main_context_iteration(NULL, TRUE); /* wait for selection_received_cb */
+
+ if (received_selection != RS_FAIL)
+ return;
+ }
+
+ /* Final fallback position - use the X CUT_BUFFER0 store */
+ yank_cut_buffer0(GDK_WINDOW_XDISPLAY(gtk_widget_get_window(gui.mainwin)),
+ cbd);
+}
+
+/*
+ * Disown the selection.
+ */
+ void
+clip_mch_lose_selection(VimClipboard *cbd UNUSED)
+{
+ if (!in_selection_clear_event)
+ {
+ gtk_selection_owner_set(NULL, cbd->gtk_sel_atom, gui.event_time);
+ gui_mch_update();
+ }
+}
+
+/*
+ * Own the selection and return OK if it worked.
+ */
+ int
+clip_mch_own_selection(VimClipboard *cbd)
+{
+ int success;
+
+ success = gtk_selection_owner_set(gui.drawarea, cbd->gtk_sel_atom,
+ gui.event_time);
+ gui_mch_update();
+ return (success) ? OK : FAIL;
+}
+
+/*
+ * Send the current selection to the clipboard. Do nothing for X because we
+ * will fill in the selection only when requested by another app.
+ */
+ void
+clip_mch_set_selection(VimClipboard *cbd UNUSED)
+{
+}
+
+#if (defined(FEAT_XCLIPBOARD) && defined(USE_SYSTEM)) || defined(PROTO)
+ int
+clip_gtk_owner_exists(VimClipboard *cbd)
+{
+ return gdk_selection_owner_get(cbd->gtk_sel_atom) != NULL;
+}
+#endif
+
+
+#if defined(FEAT_MENU) || defined(PROTO)
+/*
+ * Make a menu item appear either active or not active (grey or not grey).
+ */
+ void
+gui_mch_menu_grey(vimmenu_T *menu, int grey)
+{
+ if (menu->id == NULL)
+ return;
+
+ if (menu_is_separator(menu->name))
+ grey = TRUE;
+
+ gui_mch_menu_hidden(menu, FALSE);
+ /* Be clever about bitfields versus true booleans here! */
+ if (!gtk_widget_get_sensitive(menu->id) == !grey)
+ {
+ gtk_widget_set_sensitive(menu->id, !grey);
+ gui_mch_update();
+ }
+}
+
+/*
+ * Make menu item hidden or not hidden.
+ */
+ void
+gui_mch_menu_hidden(vimmenu_T *menu, int hidden)
+{
+ if (menu->id == 0)
+ return;
+
+ if (hidden)
+ {
+ if (gtk_widget_get_visible(menu->id))
+ {
+ gtk_widget_hide(menu->id);
+ gui_mch_update();
+ }
+ }
+ else
+ {
+ if (!gtk_widget_get_visible(menu->id))
+ {
+ gtk_widget_show(menu->id);
+ gui_mch_update();
+ }
+ }
+}
+
+/*
+ * This is called after setting all the menus to grey/hidden or not.
+ */
+ void
+gui_mch_draw_menubar(void)
+{
+ /* just make sure that the visual changes get effect immediately */
+ gui_mch_update();
+}
+#endif /* FEAT_MENU */
+
+/*
+ * Scrollbar stuff.
+ */
+ void
+gui_mch_enable_scrollbar(scrollbar_T *sb, int flag)
+{
+ if (sb->id == NULL)
+ return;
+
+ gtk_widget_set_visible(sb->id, flag);
+ update_window_manager_hints(0, 0);
+}
+
+
+/*
+ * Return the RGB value of a pixel as long.
+ */
+ guicolor_T
+gui_mch_get_rgb(guicolor_T pixel)
+{
+#if GTK_CHECK_VERSION(3,0,0)
+ return (long_u)pixel;
+#else
+ GdkColor color;
+
+ gdk_colormap_query_color(gtk_widget_get_colormap(gui.drawarea),
+ (unsigned long)pixel, &color);
+
+ return (guicolor_T)(
+ (((unsigned)color.red & 0xff00) << 8)
+ | ((unsigned)color.green & 0xff00)
+ | (((unsigned)color.blue & 0xff00) >> 8));
+#endif
+}
+
+/*
+ * Get current mouse coordinates in text window.
+ */
+ void
+gui_mch_getmouse(int *x, int *y)
+{
+ gui_gtk_get_pointer(gui.drawarea, x, y, NULL);
+}
+
+ void
+gui_mch_setmouse(int x, int y)
+{
+ /* Sorry for the Xlib call, but we can't avoid it, since there is no
+ * internal GDK mechanism present to accomplish this. (and for good
+ * reason...) */
+ XWarpPointer(GDK_WINDOW_XDISPLAY(gtk_widget_get_window(gui.drawarea)),
+ (Window)0, GDK_WINDOW_XID(gtk_widget_get_window(gui.drawarea)),
+ 0, 0, 0U, 0U, x, y);
+}
+
+
+#ifdef FEAT_MOUSESHAPE
+/* The last set mouse pointer shape is remembered, to be used when it goes
+ * from hidden to not hidden. */
+static int last_shape = 0;
+#endif
+
+/*
+ * Use the blank mouse pointer or not.
+ *
+ * hide: TRUE = use blank ptr, FALSE = use parent ptr
+ */
+ void
+gui_mch_mousehide(int hide)
+{
+ if (gui.pointer_hidden != hide)
+ {
+ gui.pointer_hidden = hide;
+ if (gtk_widget_get_window(gui.drawarea) && gui.blank_pointer != NULL)
+ {
+ if (hide)
+ gdk_window_set_cursor(gtk_widget_get_window(gui.drawarea),
+ gui.blank_pointer);
+ else
+#ifdef FEAT_MOUSESHAPE
+ mch_set_mouse_shape(last_shape);
+#else
+ gdk_window_set_cursor(gtk_widget_get_window(gui.drawarea), NULL);
+#endif
+ }
+ }
+}
+
+#if defined(FEAT_MOUSESHAPE) || defined(PROTO)
+
+/* Table for shape IDs. Keep in sync with the mshape_names[] table in
+ * misc2.c! */
+static const int mshape_ids[] =
+{
+ GDK_LEFT_PTR, /* arrow */
+ GDK_CURSOR_IS_PIXMAP, /* blank */
+ GDK_XTERM, /* beam */
+ GDK_SB_V_DOUBLE_ARROW, /* updown */
+ GDK_SIZING, /* udsizing */
+ GDK_SB_H_DOUBLE_ARROW, /* leftright */
+ GDK_SIZING, /* lrsizing */
+ GDK_WATCH, /* busy */
+ GDK_X_CURSOR, /* no */
+ GDK_CROSSHAIR, /* crosshair */
+ GDK_HAND1, /* hand1 */
+ GDK_HAND2, /* hand2 */
+ GDK_PENCIL, /* pencil */
+ GDK_QUESTION_ARROW, /* question */
+ GDK_RIGHT_PTR, /* right-arrow */
+ GDK_CENTER_PTR, /* up-arrow */
+ GDK_LEFT_PTR /* last one */
+};
+
+ void
+mch_set_mouse_shape(int shape)
+{
+ int id;
+ GdkCursor *c;
+
+ if (gtk_widget_get_window(gui.drawarea) == NULL)
+ return;
+
+ if (shape == MSHAPE_HIDE || gui.pointer_hidden)
+ gdk_window_set_cursor(gtk_widget_get_window(gui.drawarea),
+ gui.blank_pointer);
+ else
+ {
+ if (shape >= MSHAPE_NUMBERED)
+ {
+ id = shape - MSHAPE_NUMBERED;
+ if (id >= GDK_LAST_CURSOR)
+ id = GDK_LEFT_PTR;
+ else
+ id &= ~1; /* they are always even (why?) */
+ }
+ else if (shape < (int)(sizeof(mshape_ids) / sizeof(int)))
+ id = mshape_ids[shape];
+ else
+ return;
+ c = gdk_cursor_new_for_display(
+ gtk_widget_get_display(gui.drawarea), (GdkCursorType)id);
+ gdk_window_set_cursor(gtk_widget_get_window(gui.drawarea), c);
+# if GTK_CHECK_VERSION(3,0,0)
+ g_object_unref(G_OBJECT(c));
+# else
+ gdk_cursor_destroy(c); /* Unref, actually. Bloody GTK+ 1. */
+# endif
+ }
+ if (shape != MSHAPE_HIDE)
+ last_shape = shape;
+}
+#endif /* FEAT_MOUSESHAPE */
+
+
+#if defined(FEAT_SIGN_ICONS) || defined(PROTO)
+/*
+ * Signs are currently always 2 chars wide. With GTK+ 2, the image will be
+ * scaled down if the current font is not big enough, or scaled up if the image
+ * size is less than 3/4 of the maximum sign size. With GTK+ 1, the pixmap
+ * will be cut off if the current font is not big enough, or centered if it's
+ * too small.
+ */
+# define SIGN_WIDTH (2 * gui.char_width)
+# define SIGN_HEIGHT (gui.char_height)
+# define SIGN_ASPECT ((double)SIGN_HEIGHT / (double)SIGN_WIDTH)
+
+ void
+gui_mch_drawsign(int row, int col, int typenr)
+{
+ GdkPixbuf *sign;
+
+ sign = (GdkPixbuf *)sign_get_image(typenr);
+
+ if (sign != NULL && gui.drawarea != NULL
+ && gtk_widget_get_window(gui.drawarea) != NULL)
+ {
+ int width;
+ int height;
+ int xoffset;
+ int yoffset;
+ int need_scale;
+
+ width = gdk_pixbuf_get_width(sign);
+ height = gdk_pixbuf_get_height(sign);
+ /*
+ * Decide whether we need to scale. Allow one pixel of border
+ * width to be cut off, in order to avoid excessive scaling for
+ * tiny differences in font size.
+ * Do scale to fit the height to avoid gaps because of linespacing.
+ */
+ need_scale = (width > SIGN_WIDTH + 2
+ || height != SIGN_HEIGHT
+ || (width < 3 * SIGN_WIDTH / 4
+ && height < 3 * SIGN_HEIGHT / 4));
+ if (need_scale)
+ {
+ double aspect;
+ int w = width;
+ int h = height;
+
+ /* Keep the original aspect ratio */
+ aspect = (double)height / (double)width;
+ width = (double)SIGN_WIDTH * SIGN_ASPECT / aspect;
+ width = MIN(width, SIGN_WIDTH);
+ if (((double)(MAX(height, SIGN_HEIGHT)) /
+ (double)(MIN(height, SIGN_HEIGHT))) < 1.15)
+ {
+ /* Change the aspect ratio by at most 15% to fill the
+ * available space completly. */
+ height = (double)SIGN_HEIGHT * SIGN_ASPECT / aspect;
+ height = MIN(height, SIGN_HEIGHT);
+ }
+ else
+ height = (double)width * aspect;
+
+ if (w == width && h == height)
+ {
+ /* no change in dimensions; don't decrease reference counter
+ * (below) */
+ need_scale = FALSE;
+ }
+ else
+ {
+ /* This doesn't seem to be worth caching, and doing so would
+ * complicate the code quite a bit. */
+ sign = gdk_pixbuf_scale_simple(sign, width, height,
+ GDK_INTERP_BILINEAR);
+ if (sign == NULL)
+ return; /* out of memory */
+ }
+ }
+
+ /* The origin is the upper-left corner of the pixmap. Therefore
+ * these offset may become negative if the pixmap is smaller than
+ * the 2x1 cells reserved for the sign icon. */
+ xoffset = (width - SIGN_WIDTH) / 2;
+ yoffset = (height - SIGN_HEIGHT) / 2;
+
+# if GTK_CHECK_VERSION(3,0,0)
+ {
+ cairo_t *cr;
+ cairo_surface_t *bg_surf;
+ cairo_t *bg_cr;
+ cairo_surface_t *sign_surf;
+ cairo_t *sign_cr;
+
+ cr = cairo_create(gui.surface);
+
+ bg_surf = cairo_surface_create_similar(gui.surface,
+ cairo_surface_get_content(gui.surface),
+ SIGN_WIDTH, SIGN_HEIGHT);
+ bg_cr = cairo_create(bg_surf);
+ cairo_set_source_rgba(bg_cr,
+ gui.bgcolor->red, gui.bgcolor->green, gui.bgcolor->blue,
+ gui.bgcolor->alpha);
+ cairo_paint(bg_cr);
+
+ sign_surf = cairo_surface_create_similar(gui.surface,
+ cairo_surface_get_content(gui.surface),
+ SIGN_WIDTH, SIGN_HEIGHT);
+ sign_cr = cairo_create(sign_surf);
+ gdk_cairo_set_source_pixbuf(sign_cr, sign, -xoffset, -yoffset);
+ cairo_paint(sign_cr);
+
+ cairo_set_operator(sign_cr, CAIRO_OPERATOR_DEST_OVER);
+ cairo_set_source_surface(sign_cr, bg_surf, 0, 0);
+ cairo_paint(sign_cr);
+
+ cairo_set_source_surface(cr, sign_surf, FILL_X(col), FILL_Y(row));
+ cairo_paint(cr);
+
+ cairo_destroy(sign_cr);
+ cairo_surface_destroy(sign_surf);
+ cairo_destroy(bg_cr);
+ cairo_surface_destroy(bg_surf);
+ cairo_destroy(cr);
+
+ if (!gui.by_signal)
+ gtk_widget_queue_draw_area(gui.drawarea,
+ FILL_X(col), FILL_Y(col), width, height);
+
+ }
+# else /* !GTK_CHECK_VERSION(3,0,0) */
+ gdk_gc_set_foreground(gui.text_gc, gui.bgcolor);
+
+ gdk_draw_rectangle(gui.drawarea->window,
+ gui.text_gc,
+ TRUE,
+ FILL_X(col),
+ FILL_Y(row),
+ SIGN_WIDTH,
+ SIGN_HEIGHT);
+
+ gdk_pixbuf_render_to_drawable_alpha(sign,
+ gui.drawarea->window,
+ MAX(0, xoffset),
+ MAX(0, yoffset),
+ FILL_X(col) - MIN(0, xoffset),
+ FILL_Y(row) - MIN(0, yoffset),
+ MIN(width, SIGN_WIDTH),
+ MIN(height, SIGN_HEIGHT),
+ GDK_PIXBUF_ALPHA_BILEVEL,
+ 127,
+ GDK_RGB_DITHER_NORMAL,
+ 0, 0);
+# endif /* !GTK_CHECK_VERSION(3,0,0) */
+ if (need_scale)
+ g_object_unref(sign);
+ }
+}
+
+ void *
+gui_mch_register_sign(char_u *signfile)
+{
+ if (signfile[0] != NUL && signfile[0] != '-' && gui.in_use)
+ {
+ GdkPixbuf *sign;
+ GError *error = NULL;
+ char_u *message;
+
+ sign = gdk_pixbuf_new_from_file((const char *)signfile, &error);
+
+ if (error == NULL)
+ return sign;
+
+ message = (char_u *)error->message;
+
+ if (message != NULL && input_conv.vc_type != CONV_NONE)
+ message = string_convert(&input_conv, message, NULL);
+
+ if (message != NULL)
+ {
+ /* The error message is already translated and will be more
+ * descriptive than anything we could possibly do ourselves. */
+ semsg("E255: %s", message);
+
+ if (input_conv.vc_type != CONV_NONE)
+ vim_free(message);
+ }
+ g_error_free(error);
+ }
+
+ return NULL;
+}
+
+ void
+gui_mch_destroy_sign(void *sign)
+{
+ if (sign != NULL)
+ g_object_unref(sign);
+}
+
+#endif /* FEAT_SIGN_ICONS */
diff --git a/src/gui_mac.c b/src/gui_mac.c
new file mode 100644
index 0000000..232b6f2
--- /dev/null
+++ b/src/gui_mac.c
@@ -0,0 +1,6731 @@
+/* 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 <Devices.h> /* 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 <Menus.h>
+#include <Resources.h>
+#include <Processes.h>
+#ifdef USE_AEVENT
+# include <AppleEvents.h>
+# include <AERegistry.h>
+#endif
+# include <Gestalt.h>
+#if UNIVERSAL_INTERFACES_VERSION >= 0x0330
+# include <ControlDefinitions.h>
+# include <Navigation.h> /* 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 <MacHelp.h>
+# 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 = (char_u **) alloc(*numFiles * sizeof(char_u *));
+
+ /* 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 */
+/* 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);
+*/
+
+#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);
+ if (error)
+ {
+ return error;
+ }
+#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 (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);
+ }
+ }*/
+}
+
+/*
+ * ------------------------------------------------------------
+ * 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 = (UniChar *)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);
+
+ /* Interpret META, include SHIFT, etc. */
+ key_char = extract_modifiers(key_char, (int *)&vimModifiers);
+ 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 technic return 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 = (char_u **)alloc(count * sizeof(char_u *));
+ 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 = 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;
+}
+
+/*
+ * 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. */
+/*
+ ATSUAttributeTag fallbackTags[] = { kATSULineFontFallbacksTag };
+ ByteCount fallbackSizes[] = { sizeof(ATSUFontFallbacks) };
+ ATSUCreateFontFallbacks(&gFontFallbacks);
+ ATSUSetObjFontFallbacks(gFontFallbacks, );
+*/
+ 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 (dragRectControl == kCreateEmpty)
+ {
+ dragRgn = NULL;
+ dragRectControl = kNothing;
+ }
+ else*/ 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(VimClipboard *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 = lalloc(scrapSize+1, TRUE); */
+ HLock(textOfClip);
+ error = GetScrapFlavorData(scrap,
+ flavor ? VIMSCRAPFLAVOR : SCRAPTEXTFLAVOR,
+ &scrapSize, *textOfClip);
+ scrapSize -= flavor;
+
+ if (flavor)
+ type = **textOfClip;
+ else
+ type = MAUTO;
+
+ tempclip = lalloc(scrapSize + 1, TRUE);
+ 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(VimClipboard *cbd)
+{
+ /*
+ * TODO: Really nothing to do?
+ */
+}
+
+ int
+clip_mch_own_selection(VimClipboard *cbd)
+{
+ return OK;
+}
+
+/*
+ * Send the current selection to the clipboard.
+ */
+ void
+clip_mch_set_selection(VimClipboard *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., "<D-S-t>" or "<C-7>"), 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, FALSE, FALSE, FALSE);
+ 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
+ * "<D-C-x>" 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 (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);
+ }*/
+ 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
+}
+
+ 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)
+{
+ /* TODO: TODO: TODO: TODO: */
+/* blink_waittime = wait;
+ blink_ontime = on;
+ blink_offtime = off;*/
+}
+
+/*
+ * 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);
+ /* TODO: TODO: TODO: TODO: */
+/* gui_w32_rm_blink_timer();
+ if (blink_state == BLINK_OFF)
+ gui_update_cursor(TRUE, FALSE);
+ blink_state = BLINK_NONE;*/
+}
+
+/*
+ * 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 (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);
+ }*/
+}
+
+/*
+ * 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 */
+ vim_memset(hotKeys, 0, sizeof(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 <ENTER> and <ESC> 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 <mach-o/dyld.h>
+
+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/gui_motif.c b/src/gui_motif.c
new file mode 100644
index 0000000..6eb618f
--- /dev/null
+++ b/src/gui_motif.c
@@ -0,0 +1,4020 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ * GUI/Motif support by Robert Webb
+ *
+ * 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.
+ */
+
+#include "vim.h"
+
+#include <Xm/Form.h>
+#include <Xm/RowColumn.h>
+#include <Xm/PushB.h>
+#include <Xm/Text.h>
+#include <Xm/TextF.h>
+#include <Xm/Separator.h>
+#include <Xm/Label.h>
+#include <Xm/CascadeB.h>
+#include <Xm/ScrollBar.h>
+#include <Xm/MenuShell.h>
+#include <Xm/DrawingA.h>
+#if (XmVersion >= 1002)
+# include <Xm/RepType.h>
+#endif
+#include <Xm/Frame.h>
+#include <Xm/LabelG.h>
+#include <Xm/ToggleBG.h>
+#include <Xm/SeparatoG.h>
+#include <Xm/XmP.h>
+
+#include <X11/keysym.h>
+#include <X11/Xatom.h>
+#include <X11/StringDefs.h>
+#include <X11/Intrinsic.h>
+#ifdef HAVE_X11_XPM_H
+# if defined(VMS)
+# include <xpm.h>
+# else
+# include <X11/xpm.h>
+# endif
+#else
+# ifdef HAVE_XM_XPMP_H
+# include <Xm/XpmP.h>
+# endif
+#endif
+#ifdef HAVE_XM_NOTEBOOK_H
+# include <Xm/Notebook.h>
+#endif
+
+#include "gui_xmebw.h" /* for our Enhanced Button Widget */
+
+#if defined(FEAT_GUI_DIALOG) && defined(HAVE_XPM)
+# include "../pixmaps/alert.xpm"
+# include "../pixmaps/error.xpm"
+# include "../pixmaps/generic.xpm"
+# include "../pixmaps/info.xpm"
+# include "../pixmaps/quest.xpm"
+#endif
+
+#define MOTIF_POPUP
+
+extern Widget vimShell;
+
+static Widget vimForm;
+static Widget textAreaForm;
+Widget textArea;
+#ifdef FEAT_TOOLBAR
+static Widget toolBarFrame;
+static Widget toolBar;
+#endif
+#ifdef FEAT_GUI_TABLINE
+static Widget tabLine;
+static Widget tabLine_menu = 0;
+static int showing_tabline = 0;
+#endif
+#ifdef FEAT_FOOTER
+static Widget footer;
+#endif
+#ifdef FEAT_MENU
+# if (XmVersion >= 1002)
+/* remember the last set value for the tearoff item */
+static int tearoff_val = (int)XmTEAR_OFF_ENABLED;
+# endif
+static Widget menuBar;
+#endif
+
+#ifdef FEAT_TOOLBAR
+# ifdef FEAT_FOOTER
+static void toolbarbutton_enter_cb(Widget, XtPointer, XEvent *, Boolean *);
+static void toolbarbutton_leave_cb(Widget, XtPointer, XEvent *, Boolean *);
+# endif
+static void reset_focus(void);
+#endif
+
+static void gui_motif_menu_colors(Widget id);
+static void gui_motif_scroll_colors(Widget id);
+
+#if (XmVersion >= 1002)
+# define STRING_TAG XmFONTLIST_DEFAULT_TAG
+#else
+# define STRING_TAG XmSTRING_DEFAULT_CHARSET
+#endif
+
+/*
+ * Call-back routines.
+ */
+
+ static void
+scroll_cb(Widget w UNUSED, XtPointer client_data, XtPointer call_data)
+{
+ scrollbar_T *sb;
+ long value;
+ int dragging;
+
+ sb = gui_find_scrollbar((long)client_data);
+
+ value = ((XmScrollBarCallbackStruct *)call_data)->value;
+ dragging = (((XmScrollBarCallbackStruct *)call_data)->reason ==
+ (int)XmCR_DRAG);
+ gui_drag_scrollbar(sb, value, dragging);
+}
+
+#ifdef FEAT_GUI_TABLINE
+ static void
+tabline_cb(
+ Widget w UNUSED,
+ XtPointer client_data UNUSED,
+ XtPointer call_data)
+{
+ XmNotebookCallbackStruct *nptr;
+
+ nptr = (XmNotebookCallbackStruct *)call_data;
+ if (nptr->reason != (int)XmCR_NONE)
+ send_tabline_event(nptr->page_number);
+}
+
+ static void
+tabline_button_cb(
+ Widget w,
+ XtPointer client_data UNUSED,
+ XtPointer call_data UNUSED)
+{
+ int cmd, tab_idx;
+
+ XtVaGetValues(w, XmNuserData, &cmd, NULL);
+ XtVaGetValues(tabLine_menu, XmNuserData, &tab_idx, NULL);
+
+ send_tabline_menu_event(tab_idx, cmd);
+}
+
+/*
+ * Tabline single mouse click timeout handler
+ */
+ static void
+motif_tabline_timer_cb (
+ XtPointer timed_out,
+ XtIntervalId *interval_id UNUSED)
+{
+ *((int *)timed_out) = TRUE;
+}
+
+/*
+ * check if the tabline tab scroller is clicked
+ */
+ static int
+tabline_scroller_clicked(
+ char *scroller_name,
+ XButtonPressedEvent *event)
+{
+ Widget tab_scroll_w;
+ Position pos_x, pos_y;
+ Dimension width, height;
+
+ tab_scroll_w = XtNameToWidget(tabLine, scroller_name);
+ if (tab_scroll_w != (Widget)0) {
+ XtVaGetValues(tab_scroll_w, XmNx, &pos_x, XmNy, &pos_y, XmNwidth,
+ &width, XmNheight, &height, NULL);
+ if (pos_x >= 0) {
+ /* Tab scroller (next) is visible */
+ if ((event->x >= pos_x) && (event->x <= pos_x + width) &&
+ (event->y >= pos_y) && (event->y <= pos_y + height)) {
+ /* Clicked on the scroller */
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+ static void
+tabline_menu_cb(
+ Widget w,
+ XtPointer closure UNUSED,
+ XEvent *e,
+ Boolean *continue_dispatch UNUSED)
+{
+ Widget tab_w;
+ XButtonPressedEvent *event;
+ int tab_idx = 0;
+ WidgetList children;
+ Cardinal numChildren;
+ static XtIntervalId timer = (XtIntervalId)0;
+ static int timed_out = TRUE;
+
+ event = (XButtonPressedEvent *)e;
+
+ if (event->button == Button1)
+ {
+ if (tabline_scroller_clicked("MajorTabScrollerNext", event)
+ || tabline_scroller_clicked("MajorTabScrollerPrevious", event))
+ return;
+
+ if (!timed_out)
+ {
+ XtRemoveTimeOut(timer);
+ timed_out = TRUE;
+
+ /*
+ * Double click on the tabline gutter, add a new tab
+ */
+ send_tabline_menu_event(0, TABLINE_MENU_NEW);
+ }
+ else
+ {
+ /*
+ * Single click on the tabline gutter, start a timer to check
+ * for double clicks
+ */
+ timer = XtAppAddTimeOut(app_context, (long_u)p_mouset,
+ motif_tabline_timer_cb, &timed_out);
+ timed_out = FALSE;
+ }
+ return;
+ }
+
+ if (event->button != Button3)
+ return;
+
+ /* When ignoring events don't show the menu. */
+ if (hold_gui_events
+# ifdef FEAT_CMDWIN
+ || cmdwin_type != 0
+# endif
+ )
+ return;
+
+ if (event->subwindow != None)
+ {
+ tab_w = XtWindowToWidget(XtDisplay(w), event->subwindow);
+ /* LINTED: avoid warning: dubious operation on enum */
+ if (tab_w != (Widget)0 && XmIsPushButton(tab_w))
+ XtVaGetValues(tab_w, XmNpageNumber, &tab_idx, NULL);
+ }
+
+ XtVaSetValues(tabLine_menu, XmNuserData, tab_idx, NULL);
+ XtVaGetValues(tabLine_menu, XmNchildren, &children, XmNnumChildren,
+ &numChildren, NULL);
+ XtManageChildren(children, numChildren);
+ XmMenuPosition(tabLine_menu, (XButtonPressedEvent *)e) ;
+ XtManageChild(tabLine_menu);
+}
+
+ static void
+tabline_balloon_cb(BalloonEval *beval, int state UNUSED)
+{
+ int nr;
+ tabpage_T *tp;
+
+ if (beval->target == (Widget)0)
+ return;
+
+ XtVaGetValues(beval->target, XmNpageNumber, &nr, NULL);
+ tp = find_tabpage(nr);
+ if (tp == NULL)
+ return;
+
+ get_tabline_label(tp, TRUE);
+ gui_mch_post_balloon(beval, NameBuff);
+}
+
+#endif
+
+/*
+ * End of call-back routines
+ */
+
+/*
+ * Implement three dimensional shading of insensitive labels.
+ * By Marcin Dalecki.
+ */
+
+#include <Xm/XmP.h>
+#include <Xm/LabelP.h>
+
+static XtExposeProc old_label_expose = NULL;
+
+ static void
+label_expose(Widget _w, XEvent *_event, Region _region)
+{
+ GC insensitiveGC;
+ XmLabelWidget lw = (XmLabelWidget)_w;
+ unsigned char label_type = (int)XmSTRING;
+
+ XtVaGetValues(_w, XmNlabelType, &label_type, (XtPointer)0);
+
+ if (XtIsSensitive(_w) || label_type != (int)XmSTRING)
+ (*old_label_expose)(_w, _event, _region);
+ else
+ {
+ XGCValues values;
+ XtGCMask mask;
+ XtGCMask dynamic;
+ XFontStruct *fs;
+
+ _XmFontListGetDefaultFont(lw->label.font, &fs);
+
+ /* FIXME: we should be doing the whole drawing ourself here. */
+ insensitiveGC = lw->label.insensitive_GC;
+
+ mask = GCForeground | GCBackground | GCGraphicsExposures;
+ dynamic = GCClipMask | GCClipXOrigin | GCClipYOrigin;
+ values.graphics_exposures = False;
+
+ if (fs != 0)
+ {
+ mask |= GCFont;
+ values.font = fs->fid;
+ }
+
+ if (lw->primitive.top_shadow_pixmap != None
+ && lw->primitive.top_shadow_pixmap != XmUNSPECIFIED_PIXMAP)
+ {
+ mask |= GCFillStyle | GCTile;
+ values.fill_style = FillTiled;
+ values.tile = lw->primitive.top_shadow_pixmap;
+ }
+
+ lw->label.TextRect.x += 1;
+ lw->label.TextRect.y += 1;
+ if (lw->label._acc_text != 0)
+ {
+ lw->label.acc_TextRect.x += 1;
+ lw->label.acc_TextRect.y += 1;
+ }
+
+ values.foreground = lw->primitive.top_shadow_color;
+ values.background = lw->core.background_pixel;
+
+ lw->label.insensitive_GC = XtAllocateGC((Widget)lw, 0, mask,
+ &values, dynamic, (XtGCMask)0);
+ (*old_label_expose)(_w, _event, _region);
+ XtReleaseGC(_w, lw->label.insensitive_GC);
+
+ lw->label.TextRect.x -= 1;
+ lw->label.TextRect.y -= 1;
+ if (lw->label._acc_text != 0)
+ {
+ lw->label.acc_TextRect.x -= 1;
+ lw->label.acc_TextRect.y -= 1;
+ }
+
+ values.foreground = lw->primitive.bottom_shadow_color;
+ values.background = lw->core.background_pixel;
+
+ lw->label.insensitive_GC = XtAllocateGC((Widget) lw, 0, mask,
+ &values, dynamic, (XtGCMask)0);
+ (*old_label_expose)(_w, _event, _region);
+ XtReleaseGC(_w, lw->label.insensitive_GC);
+
+ lw->label.insensitive_GC = insensitiveGC;
+ }
+}
+
+/*
+ * Create all the motif widgets necessary.
+ */
+ void
+gui_x11_create_widgets(void)
+{
+#ifdef FEAT_GUI_TABLINE
+ Widget button, scroller;
+ Arg args[10];
+ int n;
+ XmString xms;
+#endif
+
+ /*
+ * Install the 3D shade effect drawing routines.
+ */
+ if (old_label_expose == NULL)
+ {
+ old_label_expose = xmLabelWidgetClass->core_class.expose;
+ xmLabelWidgetClass->core_class.expose = label_expose;
+ }
+
+ /*
+ * Start out by adding the configured border width into the border offset
+ */
+ gui.border_offset = gui.border_width;
+
+ /*
+ * Install the tearOffModel resource converter.
+ */
+#if (XmVersion >= 1002)
+ XmRepTypeInstallTearOffModelConverter();
+#endif
+
+ /* Make sure the "Quit" menu entry of the window manager is ignored */
+ XtVaSetValues(vimShell, XmNdeleteResponse, XmDO_NOTHING, NULL);
+
+ vimForm = XtVaCreateManagedWidget("vimForm",
+ xmFormWidgetClass, vimShell,
+ XmNborderWidth, 0,
+ XmNhighlightThickness, 0,
+ XmNshadowThickness, 0,
+ XmNmarginWidth, 0,
+ XmNmarginHeight, 0,
+ XmNresizePolicy, XmRESIZE_ANY,
+ NULL);
+ gui_motif_menu_colors(vimForm);
+
+#ifdef FEAT_MENU
+ {
+ Arg al[7]; /* Make sure there is enough room for arguments! */
+ int ac = 0;
+
+# if (XmVersion >= 1002)
+ XtSetArg(al[ac], XmNtearOffModel, tearoff_val); ac++;
+# endif
+ XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
+ XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
+ XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
+# ifndef FEAT_TOOLBAR
+ /* Always stick to right hand side. */
+ XtSetArg(al[ac], XmNrightOffset, 0); ac++;
+# endif
+ XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
+ menuBar = XmCreateMenuBar(vimForm, "menuBar", al, ac);
+ XtManageChild(menuBar);
+
+ /* Remember the default colors, needed for ":hi clear". */
+ XtVaGetValues(menuBar,
+ XmNbackground, &gui.menu_def_bg_pixel,
+ XmNforeground, &gui.menu_def_fg_pixel,
+ NULL);
+ gui_motif_menu_colors(menuBar);
+ }
+#endif
+
+#ifdef FEAT_TOOLBAR
+ /*
+ * Create an empty ToolBar. We should get buttons defined from menu.vim.
+ */
+ toolBarFrame = XtVaCreateWidget("toolBarFrame",
+ xmFrameWidgetClass, vimForm,
+ XmNshadowThickness, 0,
+ XmNmarginHeight, 0,
+ XmNmarginWidth, 0,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ NULL);
+ gui_motif_menu_colors(toolBarFrame);
+
+ toolBar = XtVaCreateManagedWidget("toolBar",
+ xmRowColumnWidgetClass, toolBarFrame,
+ XmNchildType, XmFRAME_WORKAREA_CHILD,
+ XmNrowColumnType, XmWORK_AREA,
+ XmNorientation, XmHORIZONTAL,
+ XmNtraversalOn, False,
+ XmNisHomogeneous, False,
+ XmNpacking, XmPACK_TIGHT,
+ XmNspacing, 0,
+ XmNshadowThickness, 0,
+ XmNhighlightThickness, 0,
+ XmNmarginHeight, 0,
+ XmNmarginWidth, 0,
+ XmNadjustLast, True,
+ NULL);
+ gui_motif_menu_colors(toolBar);
+
+#endif
+
+#ifdef FEAT_GUI_TABLINE
+ /* Create the Vim GUI tabline */
+ n = 0;
+ XtSetArg(args[n], XmNbindingType, XmNONE); n++;
+ XtSetArg(args[n], XmNorientation, XmVERTICAL); n++;
+ XtSetArg(args[n], XmNbackPageSize, XmNONE); n++;
+ XtSetArg(args[n], XmNbackPageNumber, 0); n++;
+ XtSetArg(args[n], XmNbackPagePlacement, XmTOP_RIGHT); n++;
+ XtSetArg(args[n], XmNmajorTabSpacing, 0); n++;
+ XtSetArg(args[n], XmNshadowThickness, 0); n++;
+ XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
+ XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
+ tabLine = XmCreateNotebook(vimForm, "Vim tabline", args, n);
+
+ XtAddCallback(tabLine, XmNpageChangedCallback, (XtCallbackProc)tabline_cb,
+ NULL);
+ XtAddEventHandler(tabLine, ButtonPressMask, False,
+ (XtEventHandler)tabline_menu_cb, NULL);
+
+ gui.tabline_height = TABLINE_HEIGHT;
+
+ /*
+ * Set the size of the minor next/prev scrollers to zero, so
+ * that they are not displayed. Due to a bug in OpenMotif 2.3,
+ * even if these children widget are unmanaged, they are again
+ * managed by the Notebook widget and the notebook widget geometry
+ * is adjusted to account for the minor scroller widgets.
+ */
+ scroller = XtNameToWidget(tabLine, "MinorTabScrollerNext");
+ XtVaSetValues(scroller, XmNwidth, 0, XmNresizable, False,
+ XmNtraversalOn, False, NULL);
+ scroller = XtNameToWidget(tabLine, "MinorTabScrollerPrevious");
+ XtVaSetValues(scroller, XmNwidth, 0, XmNresizable, False,
+ XmNtraversalOn, False, NULL);
+
+ // Create the tabline popup menu
+ tabLine_menu = XmCreatePopupMenu(tabLine, "tabline popup", NULL, 0);
+
+ // Add the buttons to the tabline popup menu
+ n = 0;
+ XtSetArg(args[n], XmNuserData, TABLINE_MENU_CLOSE); n++;
+ xms = XmStringCreate((char *)"Close tab", STRING_TAG);
+ XtSetArg(args[n], XmNlabelString, xms); n++;
+ button = XmCreatePushButton(tabLine_menu, "Close", args, n);
+ XtAddCallback(button, XmNactivateCallback,
+ (XtCallbackProc)tabline_button_cb, NULL);
+ XmStringFree(xms);
+
+ n = 0;
+ XtSetArg(args[n], XmNuserData, TABLINE_MENU_NEW); n++;
+ xms = XmStringCreate((char *)"New Tab", STRING_TAG);
+ XtSetArg(args[n], XmNlabelString, xms); n++;
+ button = XmCreatePushButton(tabLine_menu, "New Tab", args, n);
+ XtAddCallback(button, XmNactivateCallback,
+ (XtCallbackProc)tabline_button_cb, NULL);
+ XmStringFree(xms);
+
+ n = 0;
+ XtSetArg(args[n], XmNuserData, TABLINE_MENU_OPEN); n++;
+ xms = XmStringCreate((char *)"Open tab...", STRING_TAG);
+ XtSetArg(args[n], XmNlabelString, xms); n++;
+ button = XmCreatePushButton(tabLine_menu, "Open tab...", args, n);
+ XtAddCallback(button, XmNactivateCallback,
+ (XtCallbackProc)tabline_button_cb, NULL);
+ XmStringFree(xms);
+#endif
+
+ textAreaForm = XtVaCreateManagedWidget("textAreaForm",
+ xmFormWidgetClass, vimForm,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNmarginWidth, 0,
+ XmNmarginHeight, 0,
+ XmNresizePolicy, XmRESIZE_ANY,
+ NULL);
+ gui_motif_scroll_colors(textAreaForm);
+
+ textArea = XtVaCreateManagedWidget("textArea",
+ xmDrawingAreaWidgetClass, textAreaForm,
+ XmNforeground, gui.norm_pixel,
+ XmNbackground, gui.back_pixel,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+
+ /*
+ * These take some control away from the user, but avoids making them
+ * add resources to get a decent looking setup.
+ */
+ XmNborderWidth, 0,
+ XmNhighlightThickness, 0,
+ XmNshadowThickness, 0,
+ NULL);
+
+#ifdef FEAT_FOOTER
+ /*
+ * Create the Footer.
+ */
+ footer = XtVaCreateWidget("footer",
+ xmLabelGadgetClass, vimForm,
+ XmNalignment, XmALIGNMENT_BEGINNING,
+ XmNmarginHeight, 0,
+ XmNmarginWidth, 0,
+ XmNtraversalOn, False,
+ XmNrecomputeSize, False,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNleftOffset, 5,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ NULL);
+ gui_mch_set_footer((char_u *) "");
+#endif
+
+ /*
+ * Install the callbacks.
+ */
+ gui_x11_callbacks(textArea, vimForm);
+
+ /* Pretend we don't have input focus, we will get an event if we do. */
+ gui.in_focus = FALSE;
+}
+
+/*
+ * Called when the GUI is not going to start after all.
+ */
+ void
+gui_x11_destroy_widgets(void)
+{
+ textArea = NULL;
+#ifdef FEAT_MENU
+ menuBar = NULL;
+#endif
+}
+
+ void
+gui_mch_set_text_area_pos(
+ int x UNUSED,
+ int y UNUSED,
+ int w UNUSED,
+ int h UNUSED)
+{
+#ifdef FEAT_TOOLBAR
+ /* Give keyboard focus to the textArea instead of the toolbar. */
+ reset_focus();
+#endif
+}
+
+ void
+gui_x11_set_back_color(void)
+{
+ if (textArea != NULL)
+#if (XmVersion >= 1002)
+ XmChangeColor(textArea, gui.back_pixel);
+#else
+ XtVaSetValues(textArea,
+ XmNbackground, gui.back_pixel,
+ NULL);
+#endif
+}
+
+/*
+ * Manage dialog centered on pointer. This could be used by the Athena code as
+ * well.
+ */
+ void
+manage_centered(Widget dialog_child)
+{
+ Widget shell = XtParent(dialog_child);
+ Window root, child;
+ unsigned int mask;
+ unsigned int width, height, border_width, depth;
+ int x, y, win_x, win_y, maxX, maxY;
+ Boolean mappedWhenManaged;
+
+ /* Temporarily set value of XmNmappedWhenManaged
+ to stop the dialog from popping up right away */
+ XtVaGetValues(shell, XmNmappedWhenManaged, &mappedWhenManaged, NULL);
+ XtVaSetValues(shell, XmNmappedWhenManaged, False, NULL);
+
+ XtManageChild(dialog_child);
+
+ /* Get the pointer position (x, y) */
+ XQueryPointer(XtDisplay(shell), XtWindow(shell), &root, &child,
+ &x, &y, &win_x, &win_y, &mask);
+
+ /* Translate the pointer position (x, y) into a position for the new
+ window that will place the pointer at its center */
+ XGetGeometry(XtDisplay(shell), XtWindow(shell), &root, &win_x, &win_y,
+ &width, &height, &border_width, &depth);
+ width += 2 * border_width;
+ height += 2 * border_width;
+ x -= width / 2;
+ y -= height / 2;
+
+ /* Ensure that the dialog remains on screen */
+ maxX = XtScreen(shell)->width - width;
+ maxY = XtScreen(shell)->height - height;
+ if (x < 0)
+ x = 0;
+ if (x > maxX)
+ x = maxX;
+ if (y < 0)
+ y = 0;
+ if (y > maxY)
+ y = maxY;
+
+ /* Set desired window position in the DialogShell */
+ XtVaSetValues(shell, XmNx, x, XmNy, y, NULL);
+
+ /* Map the widget */
+ XtMapWidget(shell);
+
+ /* Restore the value of XmNmappedWhenManaged */
+ XtVaSetValues(shell, XmNmappedWhenManaged, mappedWhenManaged, NULL);
+}
+
+#if defined(FEAT_MENU) || defined(FEAT_GUI_DIALOG) || defined(PROTO)
+
+/*
+ * Encapsulate the way an XmFontList is created.
+ */
+ XmFontList
+gui_motif_create_fontlist(XFontStruct *font)
+{
+ XmFontList font_list;
+
+# if (XmVersion <= 1001)
+ /* Motif 1.1 method */
+ font_list = XmFontListCreate(font, STRING_TAG);
+# else
+ /* Motif 1.2 method */
+ XmFontListEntry font_list_entry;
+
+ font_list_entry = XmFontListEntryCreate(STRING_TAG, XmFONT_IS_FONT,
+ (XtPointer)font);
+ font_list = XmFontListAppendEntry(NULL, font_list_entry);
+ XmFontListEntryFree(&font_list_entry);
+# endif
+ return font_list;
+}
+
+# if ((XmVersion > 1001) && defined(FEAT_XFONTSET)) || defined(PROTO)
+ XmFontList
+gui_motif_fontset2fontlist(XFontSet *fontset)
+{
+ XmFontList font_list;
+
+ /* Motif 1.2 method */
+ XmFontListEntry font_list_entry;
+
+ font_list_entry = XmFontListEntryCreate(STRING_TAG,
+ XmFONT_IS_FONTSET,
+ (XtPointer)*fontset);
+ font_list = XmFontListAppendEntry(NULL, font_list_entry);
+ XmFontListEntryFree(&font_list_entry);
+ return font_list;
+}
+# endif
+
+#endif
+
+#if defined(FEAT_MENU) || defined(PROTO)
+/*
+ * Menu stuff.
+ */
+
+static void gui_motif_add_actext(vimmenu_T *menu);
+#if (XmVersion >= 1002)
+static void toggle_tearoff(Widget wid);
+static void gui_mch_recurse_tearoffs(vimmenu_T *menu);
+#endif
+static void submenu_change(vimmenu_T *mp, int colors);
+
+static void do_set_mnemonics(int enable);
+static int menu_enabled = TRUE;
+
+ void
+gui_mch_enable_menu(int flag)
+{
+ if (flag)
+ {
+ XtManageChild(menuBar);
+#ifdef FEAT_TOOLBAR
+ if (XtIsManaged(XtParent(toolBar)))
+ {
+ /* toolBar is attached to top form */
+ XtVaSetValues(XtParent(toolBar),
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, menuBar,
+ NULL);
+#ifdef FEAT_GUI_TABLINE
+ if (showing_tabline)
+ {
+ XtVaSetValues(tabLine,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, XtParent(toolBar),
+ NULL);
+ XtVaSetValues(textAreaForm,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, tabLine,
+ NULL);
+ }
+ else
+#endif
+ XtVaSetValues(textAreaForm,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, XtParent(toolBar),
+ NULL);
+ }
+ else
+#endif
+ {
+#ifdef FEAT_GUI_TABLINE
+ if (showing_tabline)
+ {
+ XtVaSetValues(tabLine,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, menuBar,
+ NULL);
+ XtVaSetValues(textAreaForm,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, tabLine,
+ NULL);
+ }
+ else
+#endif
+ XtVaSetValues(textAreaForm,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, menuBar,
+ NULL);
+ }
+ }
+ else
+ {
+ XtUnmanageChild(menuBar);
+#ifdef FEAT_TOOLBAR
+ if (XtIsManaged(XtParent(toolBar)))
+ {
+ XtVaSetValues(XtParent(toolBar),
+ XmNtopAttachment, XmATTACH_FORM,
+ NULL);
+#ifdef FEAT_GUI_TABLINE
+ if (showing_tabline)
+ {
+ XtVaSetValues(tabLine,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, XtParent(toolBar),
+ NULL);
+ XtVaSetValues(textAreaForm,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, tabLine,
+ NULL);
+ }
+ else
+#endif
+ XtVaSetValues(textAreaForm,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, XtParent(toolBar),
+ NULL);
+ }
+ else
+#endif
+ {
+#ifdef FEAT_GUI_TABLINE
+ if (showing_tabline)
+ {
+ XtVaSetValues(tabLine,
+ XmNtopAttachment, XmATTACH_FORM,
+ NULL);
+ XtVaSetValues(textAreaForm,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, tabLine,
+ NULL);
+ }
+ else
+#endif
+ XtVaSetValues(textAreaForm,
+ XmNtopAttachment, XmATTACH_FORM,
+ NULL);
+ }
+ }
+
+}
+
+/*
+ * Enable or disable mnemonics for the toplevel menus.
+ */
+ void
+gui_motif_set_mnemonics(int enable)
+{
+ /*
+ * Don't enable menu mnemonics when the menu bar is disabled, LessTif
+ * crashes when using a mnemonic then.
+ */
+ if (!menu_enabled)
+ enable = FALSE;
+ do_set_mnemonics(enable);
+}
+
+ static void
+do_set_mnemonics(int enable)
+{
+ vimmenu_T *menu;
+
+ for (menu = root_menu; menu != NULL; menu = menu->next)
+ if (menu->id != (Widget)0)
+ XtVaSetValues(menu->id,
+ XmNmnemonic, enable ? menu->mnemonic : NUL,
+ NULL);
+}
+
+ void
+gui_mch_add_menu(vimmenu_T *menu, int idx)
+{
+ XmString label;
+ Widget shell;
+ vimmenu_T *parent = menu->parent;
+
+#ifdef MOTIF_POPUP
+ if (menu_is_popup(menu->name))
+ {
+ Arg arg[2];
+ int n = 0;
+
+ /* Only create the popup menu when it's actually used, otherwise there
+ * is a delay when using the right mouse button. */
+# if (XmVersion <= 1002)
+ if (mouse_model_popup())
+# endif
+ {
+ if (gui.menu_bg_pixel != INVALCOLOR)
+ {
+ XtSetArg(arg[0], XmNbackground, gui.menu_bg_pixel); n++;
+ }
+ if (gui.menu_fg_pixel != INVALCOLOR)
+ {
+ XtSetArg(arg[1], XmNforeground, gui.menu_fg_pixel); n++;
+ }
+ menu->submenu_id = XmCreatePopupMenu(textArea, "contextMenu",
+ arg, n);
+ menu->id = (Widget)0;
+ }
+ return;
+ }
+#endif
+
+ if (!menu_is_menubar(menu->name)
+ || (parent != NULL && parent->submenu_id == (Widget)0))
+ return;
+
+ label = XmStringCreate((char *)menu->dname, STRING_TAG);
+ if (label == NULL)
+ return;
+ menu->id = XtVaCreateWidget("subMenu",
+ xmCascadeButtonWidgetClass,
+ (parent == NULL) ? menuBar : parent->submenu_id,
+ XmNlabelString, label,
+ XmNmnemonic, p_wak[0] == 'n' ? NUL : menu->mnemonic,
+#if (XmVersion >= 1002)
+ /* submenu: count the tearoff item (needed for LessTif) */
+ XmNpositionIndex, idx + (parent != NULL
+ && tearoff_val == (int)XmTEAR_OFF_ENABLED ? 1 : 0),
+#endif
+ NULL);
+ gui_motif_menu_colors(menu->id);
+ gui_motif_menu_fontlist(menu->id);
+ XmStringFree(label);
+
+ if (menu->id == (Widget)0) /* failed */
+ return;
+
+ /* add accelerator text */
+ gui_motif_add_actext(menu);
+
+ shell = XtVaCreateWidget("subMenuShell",
+ xmMenuShellWidgetClass, menu->id,
+ XmNwidth, 1,
+ XmNheight, 1,
+ NULL);
+ gui_motif_menu_colors(shell);
+ menu->submenu_id = XtVaCreateWidget("rowColumnMenu",
+ xmRowColumnWidgetClass, shell,
+ XmNrowColumnType, XmMENU_PULLDOWN,
+ NULL);
+ gui_motif_menu_colors(menu->submenu_id);
+
+ if (menu->submenu_id == (Widget)0) /* failed */
+ return;
+
+#if (XmVersion >= 1002)
+ /* Set the colors for the tear off widget */
+ toggle_tearoff(menu->submenu_id);
+#endif
+
+ XtVaSetValues(menu->id,
+ XmNsubMenuId, menu->submenu_id,
+ NULL);
+
+ /*
+ * The "Help" menu is a special case, and should be placed at the far
+ * right hand side of the menu-bar. It's recognized by its high priority.
+ */
+ if (parent == NULL && menu->priority >= 9999)
+ XtVaSetValues(menuBar,
+ XmNmenuHelpWidget, menu->id,
+ NULL);
+
+ /*
+ * When we add a top-level item to the menu bar, we can figure out how
+ * high the menu bar should be.
+ */
+ if (parent == NULL)
+ gui_mch_compute_menu_height(menu->id);
+}
+
+
+/*
+ * Add mnemonic and accelerator text to a menu button.
+ */
+ static void
+gui_motif_add_actext(vimmenu_T *menu)
+{
+ XmString label;
+
+ /* Add accelerator text, if there is one */
+ if (menu->actext != NULL && menu->id != (Widget)0)
+ {
+ label = XmStringCreate((char *)menu->actext, STRING_TAG);
+ if (label == NULL)
+ return;
+ XtVaSetValues(menu->id, XmNacceleratorText, label, NULL);
+ XmStringFree(label);
+ }
+}
+
+ void
+gui_mch_toggle_tearoffs(int enable)
+{
+#if (XmVersion >= 1002)
+ if (enable)
+ tearoff_val = (int)XmTEAR_OFF_ENABLED;
+ else
+ tearoff_val = (int)XmTEAR_OFF_DISABLED;
+ toggle_tearoff(menuBar);
+ gui_mch_recurse_tearoffs(root_menu);
+#endif
+}
+
+#if (XmVersion >= 1002)
+/*
+ * Set the tearoff for one menu widget on or off, and set the color of the
+ * tearoff widget.
+ */
+ static void
+toggle_tearoff(Widget wid)
+{
+ Widget w;
+
+ XtVaSetValues(wid, XmNtearOffModel, tearoff_val, NULL);
+ if (tearoff_val == (int)XmTEAR_OFF_ENABLED
+ && (w = XmGetTearOffControl(wid)) != (Widget)0)
+ gui_motif_menu_colors(w);
+}
+
+ static void
+gui_mch_recurse_tearoffs(vimmenu_T *menu)
+{
+ while (menu != NULL)
+ {
+ if (!menu_is_popup(menu->name))
+ {
+ if (menu->submenu_id != (Widget)0)
+ toggle_tearoff(menu->submenu_id);
+ gui_mch_recurse_tearoffs(menu->children);
+ }
+ menu = menu->next;
+ }
+}
+#endif
+
+ int
+gui_mch_text_area_extra_height(void)
+{
+ Dimension shadowHeight;
+
+ XtVaGetValues(textAreaForm, XmNshadowThickness, &shadowHeight, NULL);
+ return shadowHeight;
+}
+
+/*
+ * Compute the height of the menu bar.
+ * We need to check all the items for their position and height, for the case
+ * there are several rows, and/or some characters extend higher or lower.
+ */
+ void
+gui_mch_compute_menu_height(
+ Widget id) /* can be NULL when deleting menu */
+{
+ Dimension y, maxy;
+ Dimension margin, shadow;
+ vimmenu_T *mp;
+ static Dimension height = 21; /* normal height of a menu item */
+
+ /*
+ * Get the height of the new item, before managing it, because it will
+ * still reflect the font size. After managing it depends on the menu
+ * height, which is what we just wanted to get!.
+ */
+ if (id != (Widget)0)
+ XtVaGetValues(id, XmNheight, &height, NULL);
+
+ /* Find any menu Widget, to be able to call XtManageChild() */
+ else
+ for (mp = root_menu; mp != NULL; mp = mp->next)
+ if (mp->id != (Widget)0 && menu_is_menubar(mp->name))
+ {
+ id = mp->id;
+ break;
+ }
+
+ /*
+ * Now manage the menu item, to make them all be positioned (makes an
+ * extra row when needed, removes it when not needed).
+ */
+ if (id != (Widget)0)
+ XtManageChild(id);
+
+ /*
+ * Now find the menu item that is the furthest down, and get its position.
+ */
+ maxy = 0;
+ for (mp = root_menu; mp != NULL; mp = mp->next)
+ {
+ if (mp->id != (Widget)0 && menu_is_menubar(mp->name))
+ {
+ XtVaGetValues(mp->id, XmNy, &y, NULL);
+ if (y > maxy)
+ maxy = y;
+ }
+ }
+
+ XtVaGetValues(menuBar,
+ XmNmarginHeight, &margin,
+ XmNshadowThickness, &shadow,
+ NULL);
+
+ /*
+ * This computation is the result of trial-and-error:
+ * maxy = The maximum position of an item; required for when there are
+ * two or more rows
+ * height = height of an item, before managing it; Hopefully this will
+ * change with the font height. Includes shadow-border.
+ * shadow = shadow-border; must be subtracted from the height.
+ * margin = margin around the menu buttons; Must be added.
+ * Add 4 for the underlining of shortcut keys.
+ */
+ gui.menu_height = maxy + height - 2 * shadow + 2 * margin + 4;
+
+ /* Somehow the menu bar doesn't resize automatically. Set it here,
+ * even though this is a catch 22. Don't do this when starting up,
+ * somehow the menu gets very high then. */
+ if (gui.shell_created)
+ XtVaSetValues(menuBar, XmNheight, gui.menu_height, NULL);
+}
+
+#ifdef FEAT_TOOLBAR
+
+/*
+ * Icons used by the toolbar code.
+ */
+#include "gui_x11_pm.h"
+
+static char **get_toolbar_pixmap(vimmenu_T *menu, char **fname);
+
+/*
+ * Read an Xpm file. Return OK or FAIL.
+ */
+ static int
+check_xpm(char_u *path)
+{
+ XpmAttributes attrs;
+ int status;
+ Pixmap mask;
+ Pixmap map;
+
+ attrs.valuemask = 0;
+
+ /* Create the "sensitive" pixmap */
+ status = XpmReadFileToPixmap(gui.dpy,
+ RootWindow(gui.dpy, DefaultScreen(gui.dpy)),
+ (char *)path, &map, &mask, &attrs);
+ XpmFreeAttributes(&attrs);
+
+ if (status == XpmSuccess)
+ return OK;
+ return FAIL;
+}
+
+
+/*
+ * Allocated a pixmap for toolbar menu "menu".
+ * When it's to be read from a file, "fname" is set to the file name
+ * (in allocated memory).
+ * Return a blank pixmap if it fails.
+ */
+ static char **
+get_toolbar_pixmap(vimmenu_T *menu, char **fname)
+{
+ char_u buf[MAXPATHL]; /* buffer storing expanded pathname */
+ char **xpm = NULL; /* xpm array */
+ int res;
+
+ *fname = NULL;
+ buf[0] = NUL; /* start with NULL path */
+
+ if (menu->iconfile != NULL)
+ {
+ /* Use the "icon=" argument. */
+ gui_find_iconfile(menu->iconfile, buf, "xpm");
+ res = check_xpm(buf);
+
+ /* If it failed, try using the menu name. */
+ if (res == FAIL && gui_find_bitmap(menu->name, buf, "xpm") == OK)
+ res = check_xpm(buf);
+ if (res == OK)
+ {
+ *fname = (char *)vim_strsave(buf);
+ return tb_blank_xpm;
+ }
+ }
+
+ if (menu->icon_builtin || gui_find_bitmap(menu->name, buf, "xpm") == FAIL)
+ {
+ if (menu->iconidx >= 0 && menu->iconidx
+ < (int)(sizeof(built_in_pixmaps) / sizeof(built_in_pixmaps[0])))
+ xpm = built_in_pixmaps[menu->iconidx];
+ else
+ xpm = tb_blank_xpm;
+ }
+
+ return xpm;
+}
+
+/*
+ * Add arguments for the toolbar pixmap to a menu item.
+ */
+ static int
+add_pixmap_args(vimmenu_T *menu, Arg *args, int n)
+{
+ vim_free(menu->xpm_fname);
+ menu->xpm = get_toolbar_pixmap(menu, &menu->xpm_fname);
+ if (menu->xpm == NULL)
+ {
+ XtSetArg(args[n], XmNlabelType, XmSTRING); n++;
+ }
+ else
+ {
+ if (menu->xpm_fname != NULL)
+ {
+ XtSetArg(args[n], XmNpixmapFile, menu->xpm_fname); n++;
+ }
+ XtSetArg(args[n], XmNpixmapData, menu->xpm); n++;
+ XtSetArg(args[n], XmNlabelLocation, XmBOTTOM); n++;
+ }
+ return n;
+}
+#endif /* FEAT_TOOLBAR */
+
+ void
+gui_mch_add_menu_item(vimmenu_T *menu, int idx)
+{
+ XmString label;
+ vimmenu_T *parent = menu->parent;
+
+# ifdef EBCDIC
+ menu->mnemonic = 0;
+# endif
+
+# if (XmVersion <= 1002)
+ /* Don't add Popup menu items when the popup menu isn't used. */
+ if (menu_is_child_of_popup(menu) && !mouse_model_popup())
+ return;
+# endif
+
+# ifdef FEAT_TOOLBAR
+ if (menu_is_toolbar(parent->name))
+ {
+ WidgetClass type;
+ XmString xms = NULL; /* fallback label if pixmap not found */
+ int n;
+ Arg args[18];
+
+ n = 0;
+ if (menu_is_separator(menu->name))
+ {
+ char *cp;
+ Dimension wid;
+
+ /*
+ * A separator has the format "-sep%d[:%d]-". The optional :%d is
+ * a width specifier. If no width is specified then we choose one.
+ */
+ cp = (char *)vim_strchr(menu->name, ':');
+ if (cp != NULL)
+ wid = (Dimension)atoi(++cp);
+ else
+ wid = 4;
+
+ type = xmSeparatorWidgetClass;
+ XtSetArg(args[n], XmNwidth, wid); n++;
+ XtSetArg(args[n], XmNminWidth, wid); n++;
+ XtSetArg(args[n], XmNorientation, XmVERTICAL); n++;
+ XtSetArg(args[n], XmNseparatorType, XmSHADOW_ETCHED_IN); n++;
+ }
+ else
+ {
+ /* Without shadows one can't sense whatever the button has been
+ * pressed or not! However we want to save a bit of space...
+ * Need the highlightThickness to see the focus.
+ */
+ XtSetArg(args[n], XmNhighlightThickness, 1); n++;
+ XtSetArg(args[n], XmNhighlightOnEnter, True); n++;
+ XtSetArg(args[n], XmNmarginWidth, 0); n++;
+ XtSetArg(args[n], XmNmarginHeight, 0); n++;
+ XtSetArg(args[n], XmNtraversalOn, False); n++;
+ /* Set the label here, so that we can switch between icons/text
+ * by changing the XmNlabelType resource. */
+ xms = XmStringCreate((char *)menu->dname, STRING_TAG);
+ XtSetArg(args[n], XmNlabelString, xms); n++;
+
+ n = add_pixmap_args(menu, args, n);
+
+ type = xmEnhancedButtonWidgetClass;
+ }
+
+ XtSetArg(args[n], XmNpositionIndex, idx); n++;
+ if (menu->id == NULL)
+ {
+ menu->id = XtCreateManagedWidget((char *)menu->dname,
+ type, toolBar, args, n);
+ if (menu->id != NULL && type == xmEnhancedButtonWidgetClass)
+ {
+ XtAddCallback(menu->id,
+ XmNactivateCallback, gui_x11_menu_cb, menu);
+# ifdef FEAT_FOOTER
+ XtAddEventHandler(menu->id, EnterWindowMask, False,
+ toolbarbutton_enter_cb, menu);
+ XtAddEventHandler(menu->id, LeaveWindowMask, False,
+ toolbarbutton_leave_cb, menu);
+# endif
+ }
+ }
+ else
+ XtSetValues(menu->id, args, n);
+ if (xms != NULL)
+ XmStringFree(xms);
+
+# ifdef FEAT_BEVAL_GUI
+ gui_mch_menu_set_tip(menu);
+# endif
+
+ menu->parent = parent;
+ menu->submenu_id = NULL;
+ /* When adding first item to toolbar it might have to be enabled .*/
+ if (!XtIsManaged(XtParent(toolBar))
+ && vim_strchr(p_go, GO_TOOLBAR) != NULL)
+ gui_mch_show_toolbar(TRUE);
+ gui.toolbar_height = gui_mch_compute_toolbar_height();
+ return;
+ } /* toolbar menu item */
+# endif
+
+ /* No parent, must be a non-menubar menu */
+ if (parent->submenu_id == (Widget)0)
+ return;
+
+ menu->submenu_id = (Widget)0;
+
+ /* Add menu separator */
+ if (menu_is_separator(menu->name))
+ {
+ menu->id = XtVaCreateWidget("subMenu",
+ xmSeparatorGadgetClass, parent->submenu_id,
+#if (XmVersion >= 1002)
+ /* count the tearoff item (needed for LessTif) */
+ XmNpositionIndex, idx + (tearoff_val == (int)XmTEAR_OFF_ENABLED
+ ? 1 : 0),
+#endif
+ NULL);
+ gui_motif_menu_colors(menu->id);
+ return;
+ }
+
+ label = XmStringCreate((char *)menu->dname, STRING_TAG);
+ if (label == NULL)
+ return;
+ menu->id = XtVaCreateWidget("subMenu",
+ xmPushButtonWidgetClass, parent->submenu_id,
+ XmNlabelString, label,
+ XmNmnemonic, menu->mnemonic,
+#if (XmVersion >= 1002)
+ /* count the tearoff item (needed for LessTif) */
+ XmNpositionIndex, idx + (tearoff_val == (int)XmTEAR_OFF_ENABLED
+ ? 1 : 0),
+#endif
+ NULL);
+ gui_motif_menu_colors(menu->id);
+ gui_motif_menu_fontlist(menu->id);
+ XmStringFree(label);
+
+ if (menu->id != (Widget)0)
+ {
+ XtAddCallback(menu->id, XmNactivateCallback, gui_x11_menu_cb,
+ (XtPointer)menu);
+ /* add accelerator text */
+ gui_motif_add_actext(menu);
+ }
+}
+
+#if (XmVersion <= 1002) || defined(PROTO)
+/*
+ * This function will destroy/create the popup menus dynamically,
+ * according to the value of 'mousemodel'.
+ * This will fix the "right mouse button freeze" that occurs when
+ * there exists a popup menu but it isn't managed.
+ */
+ void
+gui_motif_update_mousemodel(vimmenu_T *menu)
+{
+ int idx = 0;
+
+ /* When GUI hasn't started the menus have not been created. */
+ if (!gui.in_use)
+ return;
+
+ while (menu)
+ {
+ if (menu->children != NULL)
+ {
+ if (menu_is_popup(menu->name))
+ {
+ if (mouse_model_popup())
+ {
+ /* Popup menu will be used. Create the popup menus. */
+ gui_mch_add_menu(menu, idx);
+ gui_motif_update_mousemodel(menu->children);
+ }
+ else
+ {
+ /* Popup menu will not be used. Destroy the popup menus. */
+ gui_motif_update_mousemodel(menu->children);
+ gui_mch_destroy_menu(menu);
+ }
+ }
+ }
+ else if (menu_is_child_of_popup(menu))
+ {
+ if (mouse_model_popup())
+ gui_mch_add_menu_item(menu, idx);
+ else
+ gui_mch_destroy_menu(menu);
+ }
+ menu = menu->next;
+ ++idx;
+ }
+}
+#endif
+
+ void
+gui_mch_new_menu_colors(void)
+{
+ if (menuBar == (Widget)0)
+ return;
+ gui_motif_menu_colors(menuBar);
+#ifdef FEAT_TOOLBAR
+ gui_motif_menu_colors(toolBarFrame);
+ gui_motif_menu_colors(toolBar);
+#endif
+
+ submenu_change(root_menu, TRUE);
+}
+
+ void
+gui_mch_new_menu_font(void)
+{
+ if (menuBar == (Widget)0)
+ return;
+ submenu_change(root_menu, FALSE);
+ {
+ Dimension height;
+ Position w, h;
+
+ XtVaGetValues(menuBar, XmNheight, &height, NULL);
+ gui.menu_height = height;
+
+ XtVaGetValues(vimShell, XtNwidth, &w, XtNheight, &h, NULL);
+ gui_resize_shell(w, h
+#ifdef FEAT_XIM
+ - xim_get_status_area_height()
+#endif
+ );
+ }
+ gui_set_shellsize(FALSE, TRUE, RESIZE_VERT);
+ ui_new_shellsize();
+}
+
+#if defined(FEAT_BEVAL_GUI) || defined(PROTO)
+ void
+gui_mch_new_tooltip_font(void)
+{
+# ifdef FEAT_TOOLBAR
+ vimmenu_T *menu;
+
+ if (toolBar == (Widget)0)
+ return;
+
+ menu = gui_find_menu((char_u *)"ToolBar");
+ if (menu != NULL)
+ submenu_change(menu, FALSE);
+# endif
+}
+
+ void
+gui_mch_new_tooltip_colors(void)
+{
+# ifdef FEAT_TOOLBAR
+ vimmenu_T *toolbar;
+
+ if (toolBar == (Widget)0)
+ return;
+
+ toolbar = gui_find_menu((char_u *)"ToolBar");
+ if (toolbar != NULL)
+ submenu_change(toolbar, TRUE);
+# endif
+}
+#endif
+
+ static void
+submenu_change(
+ vimmenu_T *menu,
+ int colors) /* TRUE for colors, FALSE for font */
+{
+ vimmenu_T *mp;
+
+ for (mp = menu; mp != NULL; mp = mp->next)
+ {
+ if (mp->id != (Widget)0)
+ {
+ if (colors)
+ {
+ gui_motif_menu_colors(mp->id);
+#ifdef FEAT_TOOLBAR
+ /* For a toolbar item: Free the pixmap and allocate a new one,
+ * so that the background color is right. */
+ if (mp->xpm != NULL)
+ {
+ int n = 0;
+ Arg args[18];
+
+ n = add_pixmap_args(mp, args, n);
+ XtSetValues(mp->id, args, n);
+ }
+# ifdef FEAT_BEVAL_GUI
+ /* If we have a tooltip, then we need to change its font */
+ if (mp->tip != NULL)
+ {
+ Arg args[2];
+
+ args[0].name = XmNbackground;
+ args[0].value = gui.tooltip_bg_pixel;
+ args[1].name = XmNforeground;
+ args[1].value = gui.tooltip_fg_pixel;
+ XtSetValues(mp->tip->balloonLabel, &args[0], XtNumber(args));
+ }
+# endif
+#endif
+ }
+ else
+ {
+ gui_motif_menu_fontlist(mp->id);
+#ifdef FEAT_BEVAL_GUI
+ /* If we have a tooltip, then we need to change its font */
+ if (mp->tip != NULL)
+ {
+ Arg args[1];
+
+ args[0].name = XmNfontList;
+ args[0].value = (XtArgVal)gui_motif_fontset2fontlist(
+ &gui.tooltip_fontset);
+ XtSetValues(mp->tip->balloonLabel, &args[0], XtNumber(args));
+ }
+#endif
+ }
+ }
+
+ if (mp->children != NULL)
+ {
+#if (XmVersion >= 1002)
+ /* Set the colors/font for the tear off widget */
+ if (mp->submenu_id != (Widget)0)
+ {
+ if (colors)
+ gui_motif_menu_colors(mp->submenu_id);
+ else
+ gui_motif_menu_fontlist(mp->submenu_id);
+ toggle_tearoff(mp->submenu_id);
+ }
+#endif
+ /* Set the colors for the children */
+ submenu_change(mp->children, colors);
+ }
+ }
+}
+
+/*
+ * Destroy the machine specific menu widget.
+ */
+ void
+gui_mch_destroy_menu(vimmenu_T *menu)
+{
+ /* Please be sure to destroy the parent widget first (i.e. menu->id).
+ * On the other hand, problems have been reported that the submenu must be
+ * deleted first...
+ *
+ * This code should be basically identical to that in the file gui_athena.c
+ * because they are both Xt based.
+ */
+ if (menu->submenu_id != (Widget)0)
+ {
+ XtDestroyWidget(menu->submenu_id);
+ menu->submenu_id = (Widget)0;
+ }
+
+ if (menu->id != (Widget)0)
+ {
+ Widget parent;
+
+ parent = XtParent(menu->id);
+#if defined(FEAT_TOOLBAR) && defined(FEAT_BEVAL_GUI)
+ if (parent == toolBar && menu->tip != NULL)
+ {
+ /* We try to destroy this before the actual menu, because there are
+ * callbacks, etc. that will be unregistered during the tooltip
+ * destruction.
+ *
+ * If you call "gui_mch_destroy_beval_area()" after destroying
+ * menu->id, then the tooltip's window will have already been
+ * deallocated by Xt, and unknown behaviour will ensue (probably
+ * a core dump).
+ */
+ gui_mch_destroy_beval_area(menu->tip);
+ menu->tip = NULL;
+ }
+#endif
+ XtDestroyWidget(menu->id);
+ menu->id = (Widget)0;
+ if (parent == menuBar)
+ gui_mch_compute_menu_height((Widget)0);
+#ifdef FEAT_TOOLBAR
+ else if (parent == toolBar)
+ {
+ Cardinal num_children;
+
+ /* When removing last toolbar item, don't display the toolbar. */
+ XtVaGetValues(toolBar, XmNnumChildren, &num_children, NULL);
+ if (num_children == 0)
+ gui_mch_show_toolbar(FALSE);
+ else
+ gui.toolbar_height = gui_mch_compute_toolbar_height();
+ }
+#endif
+ }
+}
+
+ void
+gui_mch_show_popupmenu(vimmenu_T *menu UNUSED)
+{
+#ifdef MOTIF_POPUP
+ XmMenuPosition(menu->submenu_id, gui_x11_get_last_mouse_event());
+ XtManageChild(menu->submenu_id);
+#endif
+}
+
+#endif /* FEAT_MENU */
+
+/*
+ * Set the menu and scrollbar colors to their default values.
+ */
+ void
+gui_mch_def_colors(void)
+{
+ if (gui.in_use)
+ {
+ /* Use the values saved when starting up. These should come from the
+ * window manager or a resources file. */
+ gui.menu_fg_pixel = gui.menu_def_fg_pixel;
+ gui.menu_bg_pixel = gui.menu_def_bg_pixel;
+ gui.scroll_fg_pixel = gui.scroll_def_fg_pixel;
+ gui.scroll_bg_pixel = gui.scroll_def_bg_pixel;
+#ifdef FEAT_BEVAL_GUI
+ gui.tooltip_fg_pixel =
+ gui_get_color((char_u *)gui.rsrc_tooltip_fg_name);
+ gui.tooltip_bg_pixel =
+ gui_get_color((char_u *)gui.rsrc_tooltip_bg_name);
+#endif
+ }
+}
+
+
+/*
+ * Scrollbar stuff.
+ */
+
+ void
+gui_mch_set_scrollbar_thumb(
+ scrollbar_T *sb,
+ long val,
+ long size,
+ long max)
+{
+ if (sb->id != (Widget)0)
+ XtVaSetValues(sb->id,
+ XmNvalue, val,
+ XmNsliderSize, size,
+ XmNpageIncrement, (size > 2 ? size - 2 : 1),
+ XmNmaximum, max + 1, /* Motif has max one past the end */
+ NULL);
+}
+
+ void
+gui_mch_set_scrollbar_pos(
+ scrollbar_T *sb,
+ int x,
+ int y,
+ int w,
+ int h)
+{
+ if (sb->id != (Widget)0)
+ {
+ if (sb->type == SBAR_LEFT || sb->type == SBAR_RIGHT)
+ {
+ if (y == 0)
+ h -= gui.border_offset;
+ else
+ y -= gui.border_offset;
+ XtVaSetValues(sb->id,
+ XmNtopOffset, y,
+ XmNbottomOffset, -y - h,
+ XmNwidth, w,
+ NULL);
+ }
+ else
+ XtVaSetValues(sb->id,
+ XmNtopOffset, y,
+ XmNleftOffset, x,
+ XmNrightOffset, gui.which_scrollbars[SBAR_RIGHT]
+ ? gui.scrollbar_width : 0,
+ XmNheight, h,
+ NULL);
+ XtManageChild(sb->id);
+ }
+}
+
+ void
+gui_mch_enable_scrollbar(scrollbar_T *sb, int flag)
+{
+ Arg args[16];
+ int n;
+
+ if (sb->id != (Widget)0)
+ {
+ n = 0;
+ if (flag)
+ {
+ switch (sb->type)
+ {
+ case SBAR_LEFT:
+ XtSetArg(args[n], XmNleftOffset, gui.scrollbar_width); n++;
+ break;
+
+ case SBAR_RIGHT:
+ XtSetArg(args[n], XmNrightOffset, gui.scrollbar_width); n++;
+ break;
+
+ case SBAR_BOTTOM:
+ XtSetArg(args[n], XmNbottomOffset, gui.scrollbar_height);n++;
+ break;
+ }
+ XtSetValues(textArea, args, n);
+ XtManageChild(sb->id);
+ }
+ else
+ {
+ if (!gui.which_scrollbars[sb->type])
+ {
+ /* The scrollbars of this type are all disabled, adjust the
+ * textArea attachment offset. */
+ switch (sb->type)
+ {
+ case SBAR_LEFT:
+ XtSetArg(args[n], XmNleftOffset, 0); n++;
+ break;
+
+ case SBAR_RIGHT:
+ XtSetArg(args[n], XmNrightOffset, 0); n++;
+ break;
+
+ case SBAR_BOTTOM:
+ XtSetArg(args[n], XmNbottomOffset, 0);n++;
+ break;
+ }
+ XtSetValues(textArea, args, n);
+ }
+ XtUnmanageChild(sb->id);
+ }
+ }
+}
+
+ void
+gui_mch_create_scrollbar(
+ scrollbar_T *sb,
+ int orient) /* SBAR_VERT or SBAR_HORIZ */
+{
+ Arg args[16];
+ int n;
+
+ n = 0;
+ XtSetArg(args[n], XmNminimum, 0); n++;
+ XtSetArg(args[n], XmNorientation,
+ (orient == SBAR_VERT) ? XmVERTICAL : XmHORIZONTAL); n++;
+
+ switch (sb->type)
+ {
+ case SBAR_LEFT:
+ XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
+ XtSetArg(args[n], XmNbottomAttachment, XmATTACH_OPPOSITE_FORM); n++;
+ XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
+ break;
+
+ case SBAR_RIGHT:
+ XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
+ XtSetArg(args[n], XmNbottomAttachment, XmATTACH_OPPOSITE_FORM); n++;
+ XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
+ break;
+
+ case SBAR_BOTTOM:
+ XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
+ XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
+ XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
+ break;
+ }
+
+ sb->id = XtCreateWidget("scrollBar",
+ xmScrollBarWidgetClass, textAreaForm, args, n);
+
+ /* Remember the default colors, needed for ":hi clear". */
+ if (gui.scroll_def_bg_pixel == (guicolor_T)0
+ && gui.scroll_def_fg_pixel == (guicolor_T)0)
+ XtVaGetValues(sb->id,
+ XmNbackground, &gui.scroll_def_bg_pixel,
+ XmNforeground, &gui.scroll_def_fg_pixel,
+ NULL);
+
+ if (sb->id != (Widget)0)
+ {
+ gui_mch_set_scrollbar_colors(sb);
+ XtAddCallback(sb->id, XmNvalueChangedCallback,
+ scroll_cb, (XtPointer)sb->ident);
+ XtAddCallback(sb->id, XmNdragCallback,
+ scroll_cb, (XtPointer)sb->ident);
+ XtAddEventHandler(sb->id, KeyPressMask, FALSE, gui_x11_key_hit_cb,
+ (XtPointer)0);
+ }
+}
+
+ void
+gui_mch_destroy_scrollbar(scrollbar_T *sb)
+{
+ if (sb->id != (Widget)0)
+ XtDestroyWidget(sb->id);
+}
+
+ void
+gui_mch_set_scrollbar_colors(scrollbar_T *sb)
+{
+ if (sb->id != (Widget)0)
+ {
+ if (gui.scroll_bg_pixel != INVALCOLOR)
+ {
+#if (XmVersion>=1002)
+ XmChangeColor(sb->id, gui.scroll_bg_pixel);
+#else
+ XtVaSetValues(sb->id,
+ XmNtroughColor, gui.scroll_bg_pixel,
+ NULL);
+#endif
+ }
+
+ if (gui.scroll_fg_pixel != INVALCOLOR)
+ XtVaSetValues(sb->id,
+ XmNforeground, gui.scroll_fg_pixel,
+#if (XmVersion<1002)
+ XmNbackground, gui.scroll_fg_pixel,
+#endif
+ NULL);
+ }
+
+ /* This is needed for the rectangle below the vertical scrollbars. */
+ if (sb == &gui.bottom_sbar && textAreaForm != (Widget)0)
+ gui_motif_scroll_colors(textAreaForm);
+}
+
+/*
+ * Miscellaneous stuff:
+ */
+
+ Window
+gui_x11_get_wid(void)
+{
+ return(XtWindow(textArea));
+}
+
+/*
+ * Look for a widget in the widget tree w, with a mnemonic matching keycode.
+ * When one is found, simulate a button press on that widget and give it the
+ * keyboard focus. If the mnemonic is on a label, look in the userData field
+ * of the label to see if it points to another widget, and give that the focus.
+ */
+ static void
+do_mnemonic(Widget w, unsigned int keycode)
+{
+ WidgetList children;
+ int numChildren, i;
+ Boolean isMenu;
+ KeySym mnemonic = '\0';
+ char mneString[2];
+ Widget userData;
+ unsigned char rowColType;
+
+ if (XtIsComposite(w))
+ {
+ if (XtClass(w) == xmRowColumnWidgetClass)
+ {
+ XtVaGetValues(w, XmNrowColumnType, &rowColType, NULL);
+ isMenu = (rowColType != (unsigned char)XmWORK_AREA);
+ }
+ else
+ isMenu = False;
+ if (!isMenu)
+ {
+ XtVaGetValues(w, XmNchildren, &children, XmNnumChildren,
+ &numChildren, NULL);
+ for (i = 0; i < numChildren; i++)
+ do_mnemonic(children[i], keycode);
+ }
+ }
+ else
+ {
+ XtVaGetValues(w, XmNmnemonic, &mnemonic, NULL);
+ if (mnemonic != '\0')
+ {
+ mneString[0] = mnemonic;
+ mneString[1] = '\0';
+ if (XKeysymToKeycode(XtDisplay(XtParent(w)),
+ XStringToKeysym(mneString)) == keycode)
+ {
+ if (XtClass(w) == xmLabelWidgetClass
+ || XtClass(w) == xmLabelGadgetClass)
+ {
+ XtVaGetValues(w, XmNuserData, &userData, NULL);
+ if (userData != NULL && XtIsWidget(userData))
+ XmProcessTraversal(userData, XmTRAVERSE_CURRENT);
+ }
+ else
+ {
+ XKeyPressedEvent keyEvent;
+
+ XmProcessTraversal(w, XmTRAVERSE_CURRENT);
+
+ vim_memset((char *) &keyEvent, 0, sizeof(XKeyPressedEvent));
+ keyEvent.type = KeyPress;
+ keyEvent.serial = 1;
+ keyEvent.send_event = True;
+ keyEvent.display = XtDisplay(w);
+ keyEvent.window = XtWindow(w);
+ XtCallActionProc(w, "Activate", (XEvent *) & keyEvent,
+ NULL, 0);
+ }
+ }
+ }
+ }
+}
+
+/*
+ * Callback routine for dialog mnemonic processing.
+ */
+ static void
+mnemonic_event(Widget w, XtPointer call_data UNUSED, XKeyEvent *event)
+{
+ do_mnemonic(w, event->keycode);
+}
+
+
+/*
+ * Search the widget tree under w for widgets with mnemonics. When found, add
+ * a passive grab to the dialog widget for the mnemonic character, thus
+ * directing mnemonic events to the dialog widget.
+ */
+ static void
+add_mnemonic_grabs(Widget dialog, Widget w)
+{
+ char mneString[2];
+ WidgetList children;
+ int numChildren, i;
+ Boolean isMenu;
+ KeySym mnemonic = '\0';
+ unsigned char rowColType;
+
+ if (XtIsComposite(w))
+ {
+ if (XtClass(w) == xmRowColumnWidgetClass)
+ {
+ XtVaGetValues(w, XmNrowColumnType, &rowColType, NULL);
+ isMenu = (rowColType != (unsigned char)XmWORK_AREA);
+ }
+ else
+ isMenu = False;
+ if (!isMenu)
+ {
+ XtVaGetValues(w, XmNchildren, &children, XmNnumChildren,
+ &numChildren, NULL);
+ for (i = 0; i < numChildren; i++)
+ add_mnemonic_grabs(dialog, children[i]);
+ }
+ }
+ else
+ {
+ XtVaGetValues(w, XmNmnemonic, &mnemonic, NULL);
+ if (mnemonic != '\0')
+ {
+ mneString[0] = mnemonic;
+ mneString[1] = '\0';
+ XtGrabKey(dialog, XKeysymToKeycode(XtDisplay(dialog),
+ XStringToKeysym(mneString)),
+ Mod1Mask, True, GrabModeAsync, GrabModeAsync);
+ }
+ }
+}
+
+/*
+ * Add a handler for mnemonics in a dialog. Motif itself only handles
+ * mnemonics in menus. Mnemonics added or changed after this call will be
+ * ignored.
+ *
+ * To add a mnemonic to a text field or list, set the XmNmnemonic resource on
+ * the appropriate label and set the XmNuserData resource of the label to the
+ * widget to get the focus when the mnemonic is typed.
+ */
+ static void
+activate_dialog_mnemonics(Widget dialog)
+{
+ if (!dialog)
+ return;
+
+ XtAddEventHandler(dialog, KeyPressMask, False,
+ (XtEventHandler) mnemonic_event, (XtPointer) NULL);
+ add_mnemonic_grabs(dialog, dialog);
+}
+
+/*
+ * Removes the event handler and key-grabs for dialog mnemonic handling.
+ */
+ static void
+suppress_dialog_mnemonics(Widget dialog)
+{
+ if (!dialog)
+ return;
+
+ XtUngrabKey(dialog, AnyKey, Mod1Mask);
+ XtRemoveEventHandler(dialog, KeyPressMask, False,
+ (XtEventHandler) mnemonic_event, (XtPointer) NULL);
+}
+
+#if defined(FEAT_BROWSE) || defined(FEAT_GUI_DIALOG)
+/*
+ * Use the 'guifont' or 'guifontset' as a fontlist for a dialog widget.
+ */
+ static void
+set_fontlist(Widget id)
+{
+ XmFontList fl;
+
+#ifdef FONTSET_ALWAYS
+ if (gui.fontset != NOFONTSET)
+ {
+ fl = gui_motif_fontset2fontlist((XFontSet *)&gui.fontset);
+ if (fl != NULL)
+ {
+ if (XtIsManaged(id))
+ {
+ XtUnmanageChild(id);
+ XtVaSetValues(id, XmNfontList, fl, NULL);
+ /* We should force the widget to recalculate its
+ * geometry now. */
+ XtManageChild(id);
+ }
+ else
+ XtVaSetValues(id, XmNfontList, fl, NULL);
+ XmFontListFree(fl);
+ }
+ }
+#else
+ if (gui.norm_font != NOFONT)
+ {
+ fl = gui_motif_create_fontlist((XFontStruct *)gui.norm_font);
+ if (fl != NULL)
+ {
+ if (XtIsManaged(id))
+ {
+ XtUnmanageChild(id);
+ XtVaSetValues(id, XmNfontList, fl, NULL);
+ /* We should force the widget to recalculate its
+ * geometry now. */
+ XtManageChild(id);
+ }
+ else
+ XtVaSetValues(id, XmNfontList, fl, NULL);
+ XmFontListFree(fl);
+ }
+ }
+#endif
+}
+#endif
+
+#if defined(FEAT_BROWSE) || defined(PROTO)
+
+/*
+ * file selector related stuff
+ */
+
+#include <Xm/FileSB.h>
+#include <Xm/XmStrDefs.h>
+
+typedef struct dialog_callback_arg
+{
+ char * args; /* not used right now */
+ int id;
+} dcbarg_T;
+
+static Widget dialog_wgt;
+static char *browse_fname = NULL;
+static XmStringCharSet charset = (XmStringCharSet) XmSTRING_DEFAULT_CHARSET;
+ /* used to set up XmStrings */
+
+static void DialogCancelCB(Widget, XtPointer, XtPointer);
+static void DialogAcceptCB(Widget, XtPointer, XtPointer);
+
+/*
+ * This function is used to translate the predefined label text of the
+ * precomposed dialogs. We do this explicitly to allow:
+ *
+ * - usage of gettext for translation, as in all the other places.
+ *
+ * - equalize the messages between different GUI implementations as far as
+ * possible.
+ */
+ static void
+set_predefined_label(Widget parent, String name, char *new_label)
+{
+ XmString str;
+ Widget w;
+ char_u *p, *next;
+ KeySym mnemonic = NUL;
+
+ w = XtNameToWidget(parent, name);
+
+ if (!w)
+ return;
+
+ p = vim_strsave((char_u *)new_label);
+ if (p == NULL)
+ return;
+ for (next = p; *next; ++next)
+ {
+ if (*next == DLG_HOTKEY_CHAR)
+ {
+ int len = STRLEN(next);
+
+ if (len > 0)
+ {
+ mch_memmove(next, next + 1, len);
+ mnemonic = next[0];
+ }
+ }
+ }
+
+ str = XmStringCreate((char *)p, STRING_TAG);
+ vim_free(p);
+
+ if (str != NULL)
+ {
+ XtVaSetValues(w,
+ XmNlabelString, str,
+ XmNmnemonic, mnemonic,
+ NULL);
+ XmStringFree(str);
+ }
+ gui_motif_menu_fontlist(w);
+}
+
+ static void
+set_predefined_fontlist(Widget parent, String name)
+{
+ Widget w;
+ w = XtNameToWidget(parent, name);
+
+ if (!w)
+ return;
+
+ set_fontlist(w);
+}
+
+/*
+ * Put up a file requester.
+ * Returns the selected name in allocated memory, or NULL for Cancel.
+ */
+ char_u *
+gui_mch_browse(
+ int saving UNUSED, /* select file to write */
+ char_u *title, /* title for the window */
+ char_u *dflt, /* default name */
+ char_u *ext UNUSED, /* not used (extension added) */
+ char_u *initdir, /* initial directory, NULL for current dir */
+ char_u *filter) /* file name filter */
+{
+ char_u dirbuf[MAXPATHL];
+ char_u dfltbuf[MAXPATHL];
+ char_u *pattern;
+ char_u *tofree = NULL;
+
+ /* There a difference between the resource name and value, Therefore, we
+ * avoid to (ab-)use the (maybe internationalized!) dialog title as a
+ * dialog name.
+ */
+
+ dialog_wgt = XmCreateFileSelectionDialog(vimShell, "browseDialog", NULL, 0);
+
+ if (initdir == NULL || *initdir == NUL)
+ {
+ mch_dirname(dirbuf, MAXPATHL);
+ initdir = dirbuf;
+ }
+
+ if (dflt == NULL)
+ dflt = (char_u *)"";
+ else if (STRLEN(initdir) + STRLEN(dflt) + 2 < MAXPATHL)
+ {
+ /* The default selection should be the full path, "dflt" is only the
+ * file name. */
+ STRCPY(dfltbuf, initdir);
+ add_pathsep(dfltbuf);
+ STRCAT(dfltbuf, dflt);
+ dflt = dfltbuf;
+ }
+
+ /* Can only use one pattern for a file name. Get the first pattern out of
+ * the filter. An empty pattern means everything matches. */
+ if (filter == NULL)
+ pattern = (char_u *)"";
+ else
+ {
+ char_u *s, *p;
+
+ s = filter;
+ for (p = filter; *p != NUL; ++p)
+ {
+ if (*p == '\t') /* end of description, start of pattern */
+ s = p + 1;
+ if (*p == ';' || *p == '\n') /* end of (first) pattern */
+ break;
+ }
+ pattern = vim_strnsave(s, p - s);
+ tofree = pattern;
+ if (pattern == NULL)
+ pattern = (char_u *)"";
+ }
+
+ XtVaSetValues(dialog_wgt,
+ XtVaTypedArg,
+ XmNdirectory, XmRString, (char *)initdir, STRLEN(initdir) + 1,
+ XtVaTypedArg,
+ XmNdirSpec, XmRString, (char *)dflt, STRLEN(dflt) + 1,
+ XtVaTypedArg,
+ XmNpattern, XmRString, (char *)pattern, STRLEN(pattern) + 1,
+ XtVaTypedArg,
+ XmNdialogTitle, XmRString, (char *)title, STRLEN(title) + 1,
+ NULL);
+
+ set_predefined_label(dialog_wgt, "Apply", _("&Filter"));
+ set_predefined_label(dialog_wgt, "Cancel", _("&Cancel"));
+ set_predefined_label(dialog_wgt, "Dir", _("Directories"));
+ set_predefined_label(dialog_wgt, "FilterLabel", _("Filter"));
+ set_predefined_label(dialog_wgt, "Help", _("&Help"));
+ set_predefined_label(dialog_wgt, "Items", _("Files"));
+ set_predefined_label(dialog_wgt, "OK", _("&OK"));
+ set_predefined_label(dialog_wgt, "Selection", _("Selection"));
+
+ /* This is to save us from silly external settings using not fixed with
+ * fonts for file selection.
+ */
+ set_predefined_fontlist(dialog_wgt, "DirListSW.DirList");
+ set_predefined_fontlist(dialog_wgt, "ItemsListSW.ItemsList");
+
+ gui_motif_menu_colors(dialog_wgt);
+ if (gui.scroll_bg_pixel != INVALCOLOR)
+ XtVaSetValues(dialog_wgt, XmNtroughColor, gui.scroll_bg_pixel, NULL);
+
+ XtAddCallback(dialog_wgt, XmNokCallback, DialogAcceptCB, (XtPointer)0);
+ XtAddCallback(dialog_wgt, XmNcancelCallback, DialogCancelCB, (XtPointer)0);
+ /* We have no help in this window, so hide help button */
+ XtUnmanageChild(XmFileSelectionBoxGetChild(dialog_wgt,
+ (unsigned char)XmDIALOG_HELP_BUTTON));
+
+ manage_centered(dialog_wgt);
+ activate_dialog_mnemonics(dialog_wgt);
+
+ /* sit in a loop until the dialog box has gone away */
+ do
+ {
+ XtAppProcessEvent(XtWidgetToApplicationContext(dialog_wgt),
+ (XtInputMask)XtIMAll);
+ } while (XtIsManaged(dialog_wgt));
+
+ suppress_dialog_mnemonics(dialog_wgt);
+ XtDestroyWidget(dialog_wgt);
+ vim_free(tofree);
+
+ if (browse_fname == NULL)
+ return NULL;
+ return vim_strsave((char_u *)browse_fname);
+}
+
+/*
+ * The code below was originally taken from
+ * /usr/examples/motif/xmsamplers/xmeditor.c
+ * on Digital Unix 4.0d, but heavily modified.
+ */
+
+/*
+ * Process callback from Dialog cancel actions.
+ */
+ static void
+DialogCancelCB(
+ Widget w UNUSED, /* widget id */
+ XtPointer client_data UNUSED, /* data from application */
+ XtPointer call_data UNUSED) /* data from widget class */
+{
+ if (browse_fname != NULL)
+ {
+ XtFree(browse_fname);
+ browse_fname = NULL;
+ }
+ XtUnmanageChild(dialog_wgt);
+}
+
+/*
+ * Process callback from Dialog actions.
+ */
+ static void
+DialogAcceptCB(
+ Widget w UNUSED, /* widget id */
+ XtPointer client_data UNUSED, /* data from application */
+ XtPointer call_data) /* data from widget class */
+{
+ XmFileSelectionBoxCallbackStruct *fcb;
+
+ if (browse_fname != NULL)
+ {
+ XtFree(browse_fname);
+ browse_fname = NULL;
+ }
+ fcb = (XmFileSelectionBoxCallbackStruct *)call_data;
+
+ /* get the filename from the file selection box */
+ XmStringGetLtoR(fcb->value, charset, &browse_fname);
+
+ /* popdown the file selection box */
+ XtUnmanageChild(dialog_wgt);
+}
+
+#endif /* FEAT_BROWSE */
+
+#if defined(FEAT_GUI_DIALOG) || defined(PROTO)
+
+static int dialogStatus;
+
+/*
+ * Callback function for the textfield. When CR is hit this works like
+ * hitting the "OK" button, ESC like "Cancel".
+ */
+ static void
+keyhit_callback(
+ Widget w,
+ XtPointer client_data UNUSED,
+ XEvent *event,
+ Boolean *cont UNUSED)
+{
+ char buf[2];
+ KeySym key_sym;
+
+ if (XLookupString(&(event->xkey), buf, 2, &key_sym, NULL) == 1)
+ {
+ if (*buf == CAR)
+ dialogStatus = 1;
+ else if (*buf == ESC)
+ dialogStatus = 2;
+ }
+ if ((key_sym == XK_Left || key_sym == XK_Right)
+ && !(event->xkey.state & ShiftMask))
+ XmTextFieldClearSelection(w, XtLastTimestampProcessed(gui.dpy));
+}
+
+ static void
+butproc(
+ Widget w UNUSED,
+ XtPointer client_data,
+ XtPointer call_data UNUSED)
+{
+ dialogStatus = (int)(long)client_data + 1;
+}
+
+#ifdef HAVE_XPM
+
+ static Widget
+create_pixmap_label(
+ Widget parent,
+ String name,
+ char **data,
+ ArgList args,
+ Cardinal arg)
+{
+ Widget label;
+ Display *dsp;
+ Screen *scr;
+ int depth;
+ Pixmap pixmap = 0;
+ XpmAttributes attr;
+ Boolean rs;
+ XpmColorSymbol color[5] =
+ {
+ {"none", NULL, 0},
+ {"iconColor1", NULL, 0},
+ {"bottomShadowColor", NULL, 0},
+ {"topShadowColor", NULL, 0},
+ {"selectColor", NULL, 0}
+ };
+
+ label = XmCreateLabelGadget(parent, name, args, arg);
+
+ /*
+ * We need to be careful here, since in case of gadgets, there is
+ * no way to get the background color directly from the widget itself.
+ * In such cases we get it from The Core part of his parent instead.
+ */
+ dsp = XtDisplayOfObject(label);
+ scr = XtScreenOfObject(label);
+ XtVaGetValues(XtIsSubclass(label, coreWidgetClass)
+ ? label : XtParent(label),
+ XmNdepth, &depth,
+ XmNbackground, &color[0].pixel,
+ XmNforeground, &color[1].pixel,
+ XmNbottomShadowColor, &color[2].pixel,
+ XmNtopShadowColor, &color[3].pixel,
+ XmNhighlight, &color[4].pixel,
+ NULL);
+
+ attr.valuemask = XpmColorSymbols | XpmCloseness | XpmDepth;
+ attr.colorsymbols = color;
+ attr.numsymbols = 5;
+ attr.closeness = 65535;
+ attr.depth = depth;
+ XpmCreatePixmapFromData(dsp, RootWindowOfScreen(scr),
+ data, &pixmap, NULL, &attr);
+
+ XtVaGetValues(label, XmNrecomputeSize, &rs, NULL);
+ XtVaSetValues(label, XmNrecomputeSize, True, NULL);
+ XtVaSetValues(label,
+ XmNlabelType, XmPIXMAP,
+ XmNlabelPixmap, pixmap,
+ NULL);
+ XtVaSetValues(label, XmNrecomputeSize, rs, NULL);
+
+ return label;
+}
+#endif
+
+ int
+gui_mch_dialog(
+ int type UNUSED,
+ char_u *title,
+ char_u *message,
+ char_u *button_names,
+ int dfltbutton,
+ char_u *textfield, /* buffer of size IOSIZE */
+ int ex_cmd UNUSED)
+{
+ char_u *buts;
+ char_u *p, *next;
+ XtAppContext app;
+ XmString label;
+ int butcount;
+ Widget w;
+ Widget dialogform = NULL;
+ Widget form = NULL;
+ Widget dialogtextfield = NULL;
+ Widget *buttons;
+ Widget sep_form = NULL;
+ Boolean vertical;
+ Widget separator = NULL;
+ int n;
+ Arg args[6];
+#ifdef HAVE_XPM
+ char **icon_data = NULL;
+ Widget dialogpixmap = NULL;
+#endif
+
+ if (title == NULL)
+ title = (char_u *)_("Vim dialog");
+
+ /* if our pointer is currently hidden, then we should show it. */
+ gui_mch_mousehide(FALSE);
+
+ dialogform = XmCreateFormDialog(vimShell, (char *)"dialog", NULL, 0);
+
+ /* Check 'v' flag in 'guioptions': vertical button placement. */
+ vertical = (vim_strchr(p_go, GO_VERTICAL) != NULL);
+
+ /* Set the title of the Dialog window */
+ label = XmStringCreateSimple((char *)title);
+ if (label == NULL)
+ return -1;
+ XtVaSetValues(dialogform,
+ XmNdialogTitle, label,
+ XmNhorizontalSpacing, 4,
+ XmNverticalSpacing, vertical ? 0 : 4,
+ NULL);
+ XmStringFree(label);
+
+ /* make a copy, so that we can insert NULs */
+ buts = vim_strsave(button_names);
+ if (buts == NULL)
+ return -1;
+
+ /* Count the number of buttons and allocate buttons[]. */
+ butcount = 1;
+ for (p = buts; *p; ++p)
+ if (*p == DLG_BUTTON_SEP)
+ ++butcount;
+ buttons = (Widget *)alloc((unsigned)(butcount * sizeof(Widget)));
+ if (buttons == NULL)
+ {
+ vim_free(buts);
+ return -1;
+ }
+
+ /*
+ * Create the buttons.
+ */
+ sep_form = (Widget) 0;
+ p = buts;
+ for (butcount = 0; *p; ++butcount)
+ {
+ KeySym mnemonic = NUL;
+
+ for (next = p; *next; ++next)
+ {
+ if (*next == DLG_HOTKEY_CHAR)
+ {
+ int len = STRLEN(next);
+
+ if (len > 0)
+ {
+ mch_memmove(next, next + 1, len);
+ mnemonic = next[0];
+ }
+ }
+ if (*next == DLG_BUTTON_SEP)
+ {
+ *next++ = NUL;
+ break;
+ }
+ }
+ label = XmStringCreate(_((char *)p), STRING_TAG);
+ if (label == NULL)
+ break;
+
+ buttons[butcount] = XtVaCreateManagedWidget("button",
+ xmPushButtonWidgetClass, dialogform,
+ XmNlabelString, label,
+ XmNmnemonic, mnemonic,
+ XmNbottomAttachment, XmATTACH_FORM,
+ XmNbottomOffset, 4,
+ XmNshowAsDefault, butcount == dfltbutton - 1,
+ XmNdefaultButtonShadowThickness, 1,
+ NULL);
+ XmStringFree(label);
+ gui_motif_menu_fontlist(buttons[butcount]);
+
+ /* Layout properly. */
+
+ if (butcount > 0)
+ {
+ if (vertical)
+ XtVaSetValues(buttons[butcount],
+ XmNtopWidget, buttons[butcount - 1],
+ NULL);
+ else
+ {
+ if (*next == NUL)
+ {
+ XtVaSetValues(buttons[butcount],
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNrightOffset, 4,
+ NULL);
+
+ /* fill in a form as invisible separator */
+ sep_form = XtVaCreateWidget("separatorForm",
+ xmFormWidgetClass, dialogform,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, buttons[butcount - 1],
+ XmNrightAttachment, XmATTACH_WIDGET,
+ XmNrightWidget, buttons[butcount],
+ XmNbottomAttachment, XmATTACH_FORM,
+ XmNbottomOffset, 4,
+ NULL);
+ XtManageChild(sep_form);
+ }
+ else
+ {
+ XtVaSetValues(buttons[butcount],
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, buttons[butcount - 1],
+ NULL);
+ }
+ }
+ }
+ else if (!vertical)
+ {
+ if (*next == NUL)
+ {
+ XtVaSetValues(buttons[0],
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNrightOffset, 4,
+ NULL);
+
+ /* fill in a form as invisible separator */
+ sep_form = XtVaCreateWidget("separatorForm",
+ xmFormWidgetClass, dialogform,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNleftOffset, 4,
+ XmNrightAttachment, XmATTACH_WIDGET,
+ XmNrightWidget, buttons[0],
+ XmNbottomAttachment, XmATTACH_FORM,
+ XmNbottomOffset, 4,
+ NULL);
+ XtManageChild(sep_form);
+ }
+ else
+ XtVaSetValues(buttons[0],
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNleftOffset, 4,
+ NULL);
+ }
+
+ XtAddCallback(buttons[butcount], XmNactivateCallback,
+ (XtCallbackProc)butproc, (XtPointer)(long)butcount);
+ p = next;
+ }
+ vim_free(buts);
+
+ separator = (Widget) 0;
+ if (butcount > 0)
+ {
+ /* Create the separator for beauty. */
+ n = 0;
+ XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
+ XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
+ XtSetArg(args[n], XmNbottomWidget, buttons[0]); n++;
+ XtSetArg(args[n], XmNbottomOffset, 4); n++;
+ XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
+ XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
+ separator = XmCreateSeparatorGadget(dialogform, "separator", args, n);
+ XtManageChild(separator);
+ }
+
+ if (textfield != NULL)
+ {
+ dialogtextfield = XtVaCreateWidget("textField",
+ xmTextFieldWidgetClass, dialogform,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ NULL);
+ if (butcount > 0)
+ XtVaSetValues(dialogtextfield,
+ XmNbottomAttachment, XmATTACH_WIDGET,
+ XmNbottomWidget, separator,
+ NULL);
+ else
+ XtVaSetValues(dialogtextfield,
+ XmNbottomAttachment, XmATTACH_FORM,
+ NULL);
+
+ set_fontlist(dialogtextfield);
+ XmTextFieldSetString(dialogtextfield, (char *)textfield);
+ XtManageChild(dialogtextfield);
+ XtAddEventHandler(dialogtextfield, KeyPressMask, False,
+ (XtEventHandler)keyhit_callback, (XtPointer)NULL);
+ }
+
+ /* Form holding both message and pixmap labels */
+ form = XtVaCreateWidget("separatorForm",
+ xmFormWidgetClass, dialogform,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNtopAttachment, XmATTACH_FORM,
+ NULL);
+ XtManageChild(form);
+
+#ifdef HAVE_XPM
+ /* Add a pixmap, left of the message. */
+ switch (type)
+ {
+ case VIM_GENERIC:
+ icon_data = generic_xpm;
+ break;
+ case VIM_ERROR:
+ icon_data = error_xpm;
+ break;
+ case VIM_WARNING:
+ icon_data = alert_xpm;
+ break;
+ case VIM_INFO:
+ icon_data = info_xpm;
+ break;
+ case VIM_QUESTION:
+ icon_data = quest_xpm;
+ break;
+ default:
+ icon_data = generic_xpm;
+ }
+
+ n = 0;
+ XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
+ XtSetArg(args[n], XmNtopOffset, 8); n++;
+ XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
+ XtSetArg(args[n], XmNbottomOffset, 8); n++;
+ XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
+ XtSetArg(args[n], XmNleftOffset, 8); n++;
+
+ dialogpixmap = create_pixmap_label(form, "dialogPixmap",
+ icon_data, args, n);
+ XtManageChild(dialogpixmap);
+#endif
+
+ /* Create the dialog message.
+ * Since LessTif is apparently having problems with the creation of
+ * properly localized string, we use LtoR here. The symptom is that the
+ * string sill not show properly in multiple lines as it does in native
+ * Motif.
+ */
+ label = XmStringCreateLtoR((char *)message, STRING_TAG);
+ if (label == NULL)
+ return -1;
+ w = XtVaCreateManagedWidget("dialogMessage",
+ xmLabelGadgetClass, form,
+ XmNlabelString, label,
+ XmNalignment, XmALIGNMENT_BEGINNING,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNtopOffset, 8,
+#ifdef HAVE_XPM
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, dialogpixmap,
+#else
+ XmNleftAttachment, XmATTACH_FORM,
+#endif
+ XmNleftOffset, 8,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNrightOffset, 8,
+ XmNbottomAttachment, XmATTACH_FORM,
+ XmNbottomOffset, 8,
+ NULL);
+ XmStringFree(label);
+ set_fontlist(w);
+
+ if (textfield != NULL)
+ {
+ XtVaSetValues(form,
+ XmNbottomAttachment, XmATTACH_WIDGET,
+ XmNbottomWidget, dialogtextfield,
+ NULL);
+ }
+ else
+ {
+ if (butcount > 0)
+ XtVaSetValues(form,
+ XmNbottomAttachment, XmATTACH_WIDGET,
+ XmNbottomWidget, separator,
+ NULL);
+ else
+ XtVaSetValues(form,
+ XmNbottomAttachment, XmATTACH_FORM,
+ NULL);
+ }
+
+ if (dfltbutton < 1)
+ dfltbutton = 1;
+ if (dfltbutton > butcount)
+ dfltbutton = butcount;
+ XtVaSetValues(dialogform,
+ XmNdefaultButton, buttons[dfltbutton - 1], NULL);
+ if (textfield != NULL)
+ XtVaSetValues(dialogform, XmNinitialFocus, dialogtextfield, NULL);
+ else
+ XtVaSetValues(dialogform, XmNinitialFocus, buttons[dfltbutton - 1],
+ NULL);
+
+ manage_centered(dialogform);
+ activate_dialog_mnemonics(dialogform);
+
+ if (textfield != NULL && *textfield != NUL)
+ {
+ /* This only works after the textfield has been realised. */
+ XmTextFieldSetSelection(dialogtextfield,
+ (XmTextPosition)0, (XmTextPosition)STRLEN(textfield),
+ XtLastTimestampProcessed(gui.dpy));
+ XmTextFieldSetCursorPosition(dialogtextfield,
+ (XmTextPosition)STRLEN(textfield));
+ }
+
+ app = XtWidgetToApplicationContext(dialogform);
+
+ /* Loop until a button is pressed or the dialog is killed somehow. */
+ dialogStatus = -1;
+ for (;;)
+ {
+ XtAppProcessEvent(app, (XtInputMask)XtIMAll);
+ if (dialogStatus >= 0 || !XtIsManaged(dialogform))
+ break;
+ }
+
+ vim_free(buttons);
+
+ if (textfield != NULL)
+ {
+ p = (char_u *)XmTextGetString(dialogtextfield);
+ if (p == NULL || dialogStatus < 0)
+ *textfield = NUL;
+ else
+ vim_strncpy(textfield, p, IOSIZE - 1);
+ XtFree((char *)p);
+ }
+
+ suppress_dialog_mnemonics(dialogform);
+ XtDestroyWidget(dialogform);
+
+ return dialogStatus;
+}
+#endif /* FEAT_GUI_DIALOG */
+
+#if defined(FEAT_FOOTER) || defined(PROTO)
+
+ static int
+gui_mch_compute_footer_height(void)
+{
+ Dimension height; /* total Toolbar height */
+ Dimension top; /* XmNmarginTop */
+ Dimension bottom; /* XmNmarginBottom */
+ Dimension shadow; /* XmNshadowThickness */
+
+ XtVaGetValues(footer,
+ XmNheight, &height,
+ XmNmarginTop, &top,
+ XmNmarginBottom, &bottom,
+ XmNshadowThickness, &shadow,
+ NULL);
+
+ return (int) height + top + bottom + (shadow << 1);
+}
+
+ void
+gui_mch_enable_footer(int showit)
+{
+ if (showit)
+ {
+ gui.footer_height = gui_mch_compute_footer_height();
+ XtManageChild(footer);
+ }
+ else
+ {
+ gui.footer_height = 0;
+ XtUnmanageChild(footer);
+ }
+ XtVaSetValues(textAreaForm, XmNbottomOffset, gui.footer_height, NULL);
+}
+
+ void
+gui_mch_set_footer(char_u *s)
+{
+ XmString xms;
+
+ xms = XmStringCreate((char *)s, STRING_TAG);
+ if (xms != NULL)
+ {
+ XtVaSetValues(footer, XmNlabelString, xms, NULL);
+ XmStringFree(xms);
+ }
+}
+
+#endif
+
+
+#if defined(FEAT_TOOLBAR) || defined(PROTO)
+ void
+gui_mch_show_toolbar(int showit)
+{
+ Cardinal numChildren; /* how many children toolBar has */
+
+ if (toolBar == (Widget)0)
+ return;
+ XtVaGetValues(toolBar, XmNnumChildren, &numChildren, NULL);
+ if (showit && numChildren > 0)
+ {
+ /* Assume that we want to show the toolbar if p_toolbar contains
+ * valid option settings, therefore p_toolbar must not be NULL.
+ */
+ WidgetList children;
+
+ XtVaGetValues(toolBar, XmNchildren, &children, NULL);
+ {
+ void (*action)(BalloonEval *);
+ int text = 0;
+
+ if (strstr((const char *)p_toolbar, "tooltips"))
+ action = &gui_mch_enable_beval_area;
+ else
+ action = &gui_mch_disable_beval_area;
+ if (strstr((const char *)p_toolbar, "text"))
+ text = 1;
+ else if (strstr((const char *)p_toolbar, "icons"))
+ text = -1;
+ if (text != 0)
+ {
+ vimmenu_T *toolbar;
+ vimmenu_T *cur;
+
+ for (toolbar = root_menu; toolbar; toolbar = toolbar->next)
+ if (menu_is_toolbar(toolbar->dname))
+ break;
+ /* Assumption: toolbar is NULL if there is no toolbar,
+ * otherwise it contains the toolbar menu structure.
+ *
+ * Assumption: "numChildren" == the number of items in the list
+ * of items beginning with toolbar->children.
+ */
+ if (toolbar)
+ {
+ for (cur = toolbar->children; cur; cur = cur->next)
+ {
+ Arg args[1];
+ int n = 0;
+
+ /* Enable/Disable tooltip (OK to enable while
+ * currently enabled). */
+ if (cur->tip != NULL)
+ (*action)(cur->tip);
+ if (!menu_is_separator(cur->name))
+ {
+ if (text == 1 || cur->xpm == NULL)
+ {
+ XtSetArg(args[n], XmNlabelType, XmSTRING);
+ ++n;
+ }
+ if (cur->id != NULL)
+ {
+ XtUnmanageChild(cur->id);
+ XtSetValues(cur->id, args, n);
+ XtManageChild(cur->id);
+ }
+ }
+ }
+ }
+ }
+ }
+ gui.toolbar_height = gui_mch_compute_toolbar_height();
+ XtManageChild(XtParent(toolBar));
+#ifdef FEAT_GUI_TABLINE
+ if (showing_tabline)
+ {
+ XtVaSetValues(tabLine,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, XtParent(toolBar),
+ NULL);
+ XtVaSetValues(textAreaForm,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, tabLine,
+ NULL);
+ }
+ else
+#endif
+ XtVaSetValues(textAreaForm,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, XtParent(toolBar),
+ NULL);
+ if (XtIsManaged(menuBar))
+ XtVaSetValues(XtParent(toolBar),
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, menuBar,
+ NULL);
+ else
+ XtVaSetValues(XtParent(toolBar),
+ XmNtopAttachment, XmATTACH_FORM,
+ NULL);
+ }
+ else
+ {
+ gui.toolbar_height = 0;
+ if (XtIsManaged(menuBar))
+ {
+#ifdef FEAT_GUI_TABLINE
+ if (showing_tabline)
+ {
+ XtVaSetValues(tabLine,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, menuBar,
+ NULL);
+ XtVaSetValues(textAreaForm,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, tabLine,
+ NULL);
+ }
+ else
+#endif
+ XtVaSetValues(textAreaForm,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, menuBar,
+ NULL);
+ }
+ else
+ {
+#ifdef FEAT_GUI_TABLINE
+ if (showing_tabline)
+ {
+ XtVaSetValues(tabLine,
+ XmNtopAttachment, XmATTACH_FORM,
+ NULL);
+ XtVaSetValues(textAreaForm,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, tabLine,
+ NULL);
+ }
+ else
+#endif
+ XtVaSetValues(textAreaForm,
+ XmNtopAttachment, XmATTACH_FORM,
+ NULL);
+ }
+
+ XtUnmanageChild(XtParent(toolBar));
+ }
+ gui_set_shellsize(FALSE, FALSE, RESIZE_VERT);
+}
+
+/*
+ * A toolbar button has been pushed; now reset the input focus
+ * such that the user can type page up/down etc. and have the
+ * input go to the editor window, not the button
+ */
+ static void
+reset_focus(void)
+{
+ if (textArea != NULL)
+ XmProcessTraversal(textArea, XmTRAVERSE_CURRENT);
+}
+
+ int
+gui_mch_compute_toolbar_height(void)
+{
+ Dimension borders;
+ Dimension height; /* total Toolbar height */
+ Dimension whgt; /* height of each widget */
+ WidgetList children; /* list of toolBar's children */
+ Cardinal numChildren; /* how many children toolBar has */
+ int i;
+
+ borders = 0;
+ height = 0;
+ if (toolBar != (Widget)0 && toolBarFrame != (Widget)0)
+ { /* get height of XmFrame parent */
+ Dimension fst;
+ Dimension fmh;
+ Dimension tst;
+ Dimension tmh;
+
+ XtVaGetValues(toolBarFrame,
+ XmNshadowThickness, &fst,
+ XmNmarginHeight, &fmh,
+ NULL);
+ borders += fst + fmh;
+ XtVaGetValues(toolBar,
+ XmNshadowThickness, &tst,
+ XmNmarginHeight, &tmh,
+ XmNchildren, &children,
+ XmNnumChildren, &numChildren, NULL);
+ borders += tst + tmh;
+ for (i = 0; i < (int)numChildren; i++)
+ {
+ whgt = 0;
+ XtVaGetValues(children[i], XmNheight, &whgt, NULL);
+ if (height < whgt)
+ height = whgt;
+ }
+ }
+#ifdef LESSTIF_VERSION
+ /* Hack: When starting up we get wrong dimensions. */
+ if (height < 10)
+ height = 24;
+#endif
+
+ return (int)(height + (borders << 1));
+}
+
+ void
+motif_get_toolbar_colors(
+ Pixel *bgp,
+ Pixel *fgp,
+ Pixel *bsp,
+ Pixel *tsp,
+ Pixel *hsp)
+{
+ XtVaGetValues(toolBar,
+ XmNbackground, bgp,
+ XmNforeground, fgp,
+ XmNbottomShadowColor, bsp,
+ XmNtopShadowColor, tsp,
+ XmNhighlightColor, hsp,
+ NULL);
+}
+
+# ifdef FEAT_FOOTER
+/*
+ * The next toolbar enter/leave callbacks should really do balloon help. But
+ * I have to use footer help for backwards compatibility. Hopefully both will
+ * get implemented and the user will have a choice.
+ */
+ static void
+toolbarbutton_enter_cb(
+ Widget w UNUSED,
+ XtPointer client_data,
+ XEvent *event UNUSED,
+ Boolean *cont UNUSED)
+{
+ vimmenu_T *menu = (vimmenu_T *) client_data;
+
+ if (menu->strings[MENU_INDEX_TIP] != NULL)
+ {
+ if (vim_strchr(p_go, GO_FOOTER) != NULL)
+ gui_mch_set_footer(menu->strings[MENU_INDEX_TIP]);
+ }
+}
+
+ static void
+toolbarbutton_leave_cb(
+ Widget w UNUSED,
+ XtPointer client_data UNUSED,
+ XEvent *event UNUSED,
+ Boolean *cont UNUSED)
+{
+ gui_mch_set_footer((char_u *) "");
+}
+# endif
+#endif
+
+#if defined(FEAT_GUI_TABLINE) || defined(PROTO)
+/*
+ * Show or hide the tabline.
+ */
+ void
+gui_mch_show_tabline(int showit)
+{
+ if (tabLine == (Widget)0)
+ return;
+
+ if (!showit != !showing_tabline)
+ {
+ if (showit)
+ {
+ XtManageChild(tabLine);
+ XtUnmanageChild(XtNameToWidget(tabLine, "PageScroller"));
+ XtUnmanageChild(XtNameToWidget(tabLine, "MinorTabScrollerNext"));
+ XtUnmanageChild(XtNameToWidget(tabLine,
+ "MinorTabScrollerPrevious"));
+#ifdef FEAT_MENU
+# ifdef FEAT_TOOLBAR
+ if (XtIsManaged(XtParent(toolBar)))
+ XtVaSetValues(tabLine,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, XtParent(toolBar), NULL);
+ else
+# endif
+ if (XtIsManaged(menuBar))
+ XtVaSetValues(tabLine,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, menuBar, NULL);
+ else
+#endif
+ XtVaSetValues(tabLine,
+ XmNtopAttachment, XmATTACH_FORM, NULL);
+ XtVaSetValues(textAreaForm,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, tabLine,
+ NULL);
+ }
+ else
+ {
+ XtUnmanageChild(tabLine);
+#ifdef FEAT_MENU
+# ifdef FEAT_TOOLBAR
+ if (XtIsManaged(XtParent(toolBar)))
+ XtVaSetValues(textAreaForm,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, XtParent(toolBar), NULL);
+ else
+# endif
+ if (XtIsManaged(menuBar))
+ XtVaSetValues(textAreaForm,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, menuBar, NULL);
+ else
+#endif
+ XtVaSetValues(textAreaForm,
+ XmNtopAttachment, XmATTACH_FORM, NULL);
+ }
+ showing_tabline = showit;
+ }
+}
+
+/*
+ * Return TRUE when tabline is displayed.
+ */
+ int
+gui_mch_showing_tabline(void)
+{
+ return tabLine != (Widget)0 && showing_tabline;
+}
+
+/*
+ * Update the labels of the tabline.
+ */
+ void
+gui_mch_update_tabline(void)
+{
+ tabpage_T *tp;
+ int nr = 1, n;
+ Arg args[10];
+ int curtabidx = 0, currentpage;
+ Widget tab;
+ XmNotebookPageInfo page_info;
+ XmNotebookPageStatus page_status;
+ int last_page, tab_count;
+ XmString label_str;
+ char *label_cstr;
+ BalloonEval *beval;
+
+ if (tabLine == (Widget)0)
+ return;
+
+ /* Add a label for each tab page. They all contain the same text area. */
+ for (tp = first_tabpage; tp != NULL; tp = tp->tp_next, ++nr)
+ {
+ if (tp == curtab)
+ curtabidx = nr;
+
+ page_status = XmNotebookGetPageInfo(tabLine, nr, &page_info);
+ if (page_status == XmPAGE_INVALID
+ || page_info.major_tab_widget == (Widget)0)
+ {
+ /* Add the tab */
+ n = 0;
+ XtSetArg(args[n], XmNnotebookChildType, XmMAJOR_TAB); n++;
+ XtSetArg(args[n], XmNtraversalOn, False); n++;
+ XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
+ XtSetArg(args[n], XmNhighlightThickness, 1); n++;
+ XtSetArg(args[n], XmNshadowThickness , 1); n++;
+ tab = XmCreatePushButton(tabLine, "-Empty-", args, n);
+ XtManageChild(tab);
+ beval = gui_mch_create_beval_area(tab, NULL, tabline_balloon_cb,
+ NULL);
+ XtVaSetValues(tab, XmNuserData, beval, NULL);
+ }
+ else
+ tab = page_info.major_tab_widget;
+
+ XtVaSetValues(tab, XmNpageNumber, nr, NULL);
+
+ /*
+ * Change the label text only if it is different
+ */
+ XtVaGetValues(tab, XmNlabelString, &label_str, NULL);
+ if (XmStringGetLtoR(label_str, XmSTRING_DEFAULT_CHARSET, &label_cstr))
+ {
+ get_tabline_label(tp, FALSE);
+ if (STRCMP(label_cstr, NameBuff) != 0)
+ {
+ XtVaSetValues(tab, XtVaTypedArg, XmNlabelString, XmRString,
+ NameBuff, STRLEN(NameBuff) + 1, NULL);
+ /*
+ * Force a resize of the tab label button
+ */
+ XtUnmanageChild(tab);
+ XtManageChild(tab);
+ }
+ XtFree(label_cstr);
+ }
+ }
+
+ tab_count = nr - 1;
+
+ XtVaGetValues(tabLine, XmNlastPageNumber, &last_page, NULL);
+
+ /* Remove any old labels. */
+ while (nr <= last_page)
+ {
+ if (XmNotebookGetPageInfo(tabLine, nr, &page_info) != XmPAGE_INVALID
+ && page_info.page_number == nr
+ && page_info.major_tab_widget != (Widget)0)
+ {
+ XtVaGetValues(page_info.major_tab_widget, XmNuserData, &beval, NULL);
+ if (beval != NULL)
+ gui_mch_destroy_beval_area(beval);
+ XtUnmanageChild(page_info.major_tab_widget);
+ XtDestroyWidget(page_info.major_tab_widget);
+ }
+ nr++;
+ }
+
+ XtVaSetValues(tabLine, XmNlastPageNumber, tab_count, NULL);
+
+ XtVaGetValues(tabLine, XmNcurrentPageNumber, &currentpage, NULL);
+ if (currentpage != curtabidx)
+ XtVaSetValues(tabLine, XmNcurrentPageNumber, curtabidx, NULL);
+}
+
+/*
+ * Set the current tab to "nr". First tab is 1.
+ */
+ void
+gui_mch_set_curtab(int nr)
+{
+ int currentpage;
+
+ if (tabLine == (Widget)0)
+ return;
+
+ XtVaGetValues(tabLine, XmNcurrentPageNumber, &currentpage, NULL);
+ if (currentpage != nr)
+ XtVaSetValues(tabLine, XmNcurrentPageNumber, nr, NULL);
+}
+#endif
+
+/*
+ * Set the colors of Widget "id" to the menu colors.
+ */
+ static void
+gui_motif_menu_colors(Widget id)
+{
+ if (gui.menu_bg_pixel != INVALCOLOR)
+#if (XmVersion >= 1002)
+ XmChangeColor(id, gui.menu_bg_pixel);
+#else
+ XtVaSetValues(id, XmNbackground, gui.menu_bg_pixel, NULL);
+#endif
+ if (gui.menu_fg_pixel != INVALCOLOR)
+ XtVaSetValues(id, XmNforeground, gui.menu_fg_pixel, NULL);
+}
+
+/*
+ * Set the colors of Widget "id" to the scrollbar colors.
+ */
+ static void
+gui_motif_scroll_colors(Widget id)
+{
+ if (gui.scroll_bg_pixel != INVALCOLOR)
+#if (XmVersion >= 1002)
+ XmChangeColor(id, gui.scroll_bg_pixel);
+#else
+ XtVaSetValues(id, XmNbackground, gui.scroll_bg_pixel, NULL);
+#endif
+ if (gui.scroll_fg_pixel != INVALCOLOR)
+ XtVaSetValues(id, XmNforeground, gui.scroll_fg_pixel, NULL);
+}
+
+/*
+ * Set the fontlist for Widget "id" to use gui.menu_fontset or gui.menu_font.
+ */
+ void
+gui_motif_menu_fontlist(Widget id UNUSED)
+{
+#ifdef FEAT_MENU
+#ifdef FONTSET_ALWAYS
+ if (gui.menu_fontset != NOFONTSET)
+ {
+ XmFontList fl;
+
+ fl = gui_motif_fontset2fontlist((XFontSet *)&gui.menu_fontset);
+ if (fl != NULL)
+ {
+ if (XtIsManaged(id))
+ {
+ XtUnmanageChild(id);
+ XtVaSetValues(id, XmNfontList, fl, NULL);
+ /* We should force the widget to recalculate its
+ * geometry now. */
+ XtManageChild(id);
+ }
+ else
+ XtVaSetValues(id, XmNfontList, fl, NULL);
+ XmFontListFree(fl);
+ }
+ }
+#else
+ if (gui.menu_font != NOFONT)
+ {
+ XmFontList fl;
+
+ fl = gui_motif_create_fontlist((XFontStruct *)gui.menu_font);
+ if (fl != NULL)
+ {
+ if (XtIsManaged(id))
+ {
+ XtUnmanageChild(id);
+ XtVaSetValues(id, XmNfontList, fl, NULL);
+ /* We should force the widget to recalculate its
+ * geometry now. */
+ XtManageChild(id);
+ }
+ else
+ XtVaSetValues(id, XmNfontList, fl, NULL);
+ XmFontListFree(fl);
+ }
+ }
+#endif
+#endif
+}
+
+
+/*
+ * We don't create it twice for the sake of speed.
+ */
+
+typedef struct _SharedFindReplace
+{
+ Widget dialog; /* the main dialog widget */
+ Widget wword; /* 'Exact match' check button */
+ Widget mcase; /* 'match case' check button */
+ Widget up; /* search direction 'Up' radio button */
+ Widget down; /* search direction 'Down' radio button */
+ Widget what; /* 'Find what' entry text widget */
+ Widget with; /* 'Replace with' entry text widget */
+ Widget find; /* 'Find Next' action button */
+ Widget replace; /* 'Replace With' action button */
+ Widget all; /* 'Replace All' action button */
+ Widget undo; /* 'Undo' action button */
+
+ Widget cancel;
+} SharedFindReplace;
+
+static SharedFindReplace find_widgets = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
+static SharedFindReplace repl_widgets = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
+
+ static void
+find_replace_destroy_callback(
+ Widget w UNUSED,
+ XtPointer client_data,
+ XtPointer call_data UNUSED)
+{
+ SharedFindReplace *cd = (SharedFindReplace *)client_data;
+
+ if (cd != NULL)
+ /* suppress_dialog_mnemonics(cd->dialog); */
+ cd->dialog = (Widget)0;
+}
+
+ static void
+find_replace_dismiss_callback(
+ Widget w UNUSED,
+ XtPointer client_data,
+ XtPointer call_data UNUSED)
+{
+ SharedFindReplace *cd = (SharedFindReplace *)client_data;
+
+ if (cd != NULL)
+ XtUnmanageChild(cd->dialog);
+}
+
+ static void
+entry_activate_callback(
+ Widget w UNUSED,
+ XtPointer client_data,
+ XtPointer call_data UNUSED)
+{
+ XmProcessTraversal((Widget)client_data, XmTRAVERSE_CURRENT);
+}
+
+ static void
+find_replace_callback(
+ Widget w UNUSED,
+ XtPointer client_data,
+ XtPointer call_data UNUSED)
+{
+ long_u flags = (long_u)client_data;
+ char *find_text, *repl_text;
+ Boolean direction_down = TRUE;
+ Boolean wword;
+ Boolean mcase;
+ SharedFindReplace *sfr;
+
+ if (flags == FRD_UNDO)
+ {
+ char_u *save_cpo = p_cpo;
+
+ /* No need to be Vi compatible here. */
+ p_cpo = (char_u *)"";
+ u_undo(1);
+ p_cpo = save_cpo;
+ gui_update_screen();
+ return;
+ }
+
+ /* Get the search/replace strings from the dialog */
+ if (flags == FRD_FINDNEXT)
+ {
+ repl_text = NULL;
+ sfr = &find_widgets;
+ }
+ else
+ {
+ repl_text = XmTextFieldGetString(repl_widgets.with);
+ sfr = &repl_widgets;
+ }
+ find_text = XmTextFieldGetString(sfr->what);
+ XtVaGetValues(sfr->down, XmNset, &direction_down, NULL);
+ XtVaGetValues(sfr->wword, XmNset, &wword, NULL);
+ XtVaGetValues(sfr->mcase, XmNset, &mcase, NULL);
+ if (wword)
+ flags |= FRD_WHOLE_WORD;
+ if (mcase)
+ flags |= FRD_MATCH_CASE;
+
+ (void)gui_do_findrepl((int)flags, (char_u *)find_text, (char_u *)repl_text,
+ direction_down);
+
+ if (find_text != NULL)
+ XtFree(find_text);
+ if (repl_text != NULL)
+ XtFree(repl_text);
+}
+
+ static void
+find_replace_keypress(
+ Widget w UNUSED,
+ SharedFindReplace *frdp,
+ XKeyEvent *event)
+{
+ KeySym keysym;
+
+ if (frdp == NULL)
+ return;
+
+ keysym = XLookupKeysym(event, 0);
+
+ /* the scape key pops the whole dialog down */
+ if (keysym == XK_Escape)
+ XtUnmanageChild(frdp->dialog);
+}
+
+ static void
+set_label(Widget w, char *label)
+{
+ XmString str;
+ char_u *p, *next;
+ KeySym mnemonic = NUL;
+
+ if (!w)
+ return;
+
+ p = vim_strsave((char_u *)label);
+ if (p == NULL)
+ return;
+ for (next = p; *next; ++next)
+ {
+ if (*next == DLG_HOTKEY_CHAR)
+ {
+ int len = STRLEN(next);
+
+ if (len > 0)
+ {
+ mch_memmove(next, next + 1, len);
+ mnemonic = next[0];
+ }
+ }
+ }
+
+ str = XmStringCreateSimple((char *)p);
+ vim_free(p);
+ if (str)
+ {
+ XtVaSetValues(w,
+ XmNlabelString, str,
+ XmNmnemonic, mnemonic,
+ NULL);
+ XmStringFree(str);
+ }
+ gui_motif_menu_fontlist(w);
+}
+
+ static void
+find_replace_dialog_create(char_u *arg, int do_replace)
+{
+ SharedFindReplace *frdp;
+ Widget separator;
+ Widget input_form;
+ Widget button_form;
+ Widget toggle_form;
+ Widget frame;
+ XmString str;
+ int n;
+ Arg args[6];
+ int wword = FALSE;
+ int mcase = !p_ic;
+ Dimension width;
+ Dimension widest;
+ char_u *entry_text;
+
+ frdp = do_replace ? &repl_widgets : &find_widgets;
+
+ /* Get the search string to use. */
+ entry_text = get_find_dialog_text(arg, &wword, &mcase);
+
+ /* If the dialog already exists, just raise it. */
+ if (frdp->dialog)
+ {
+ gui_motif_synch_fonts();
+
+ /* If the window is already up, just pop it to the top */
+ if (XtIsManaged(frdp->dialog))
+ XMapRaised(XtDisplay(frdp->dialog),
+ XtWindow(XtParent(frdp->dialog)));
+ else
+ XtManageChild(frdp->dialog);
+ XtPopup(XtParent(frdp->dialog), XtGrabNone);
+ XmProcessTraversal(frdp->what, XmTRAVERSE_CURRENT);
+
+ if (entry_text != NULL)
+ XmTextFieldSetString(frdp->what, (char *)entry_text);
+ vim_free(entry_text);
+
+ XtVaSetValues(frdp->wword, XmNset, wword, NULL);
+ return;
+ }
+
+ /* Create a fresh new dialog window */
+ if (do_replace)
+ str = XmStringCreateSimple(_("VIM - Search and Replace..."));
+ else
+ str = XmStringCreateSimple(_("VIM - Search..."));
+
+ n = 0;
+ XtSetArg(args[n], XmNautoUnmanage, False); n++;
+ XtSetArg(args[n], XmNnoResize, True); n++;
+ XtSetArg(args[n], XmNdialogTitle, str); n++;
+
+ frdp->dialog = XmCreateFormDialog(vimShell, "findReplaceDialog", args, n);
+ XmStringFree(str);
+ XtAddCallback(frdp->dialog, XmNdestroyCallback,
+ find_replace_destroy_callback, frdp);
+
+ button_form = XtVaCreateWidget("buttonForm",
+ xmFormWidgetClass, frdp->dialog,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNrightOffset, 4,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNtopOffset, 4,
+ XmNbottomAttachment, XmATTACH_FORM,
+ XmNbottomOffset, 4,
+ NULL);
+
+ frdp->find = XtVaCreateManagedWidget("findButton",
+ xmPushButtonWidgetClass, button_form,
+ XmNsensitive, True,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ NULL);
+ set_label(frdp->find, _("Find &Next"));
+
+ XtAddCallback(frdp->find, XmNactivateCallback,
+ find_replace_callback,
+ (do_replace ? (XtPointer)FRD_R_FINDNEXT : (XtPointer)FRD_FINDNEXT));
+
+ if (do_replace)
+ {
+ frdp->replace = XtVaCreateManagedWidget("replaceButton",
+ xmPushButtonWidgetClass, button_form,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, frdp->find,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ NULL);
+ set_label(frdp->replace, _("&Replace"));
+ XtAddCallback(frdp->replace, XmNactivateCallback,
+ find_replace_callback, (XtPointer)FRD_REPLACE);
+
+ frdp->all = XtVaCreateManagedWidget("replaceAllButton",
+ xmPushButtonWidgetClass, button_form,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, frdp->replace,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ NULL);
+ set_label(frdp->all, _("Replace &All"));
+ XtAddCallback(frdp->all, XmNactivateCallback,
+ find_replace_callback, (XtPointer)FRD_REPLACEALL);
+
+ frdp->undo = XtVaCreateManagedWidget("undoButton",
+ xmPushButtonWidgetClass, button_form,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, frdp->all,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ NULL);
+ set_label(frdp->undo, _("&Undo"));
+ XtAddCallback(frdp->undo, XmNactivateCallback,
+ find_replace_callback, (XtPointer)FRD_UNDO);
+ }
+
+ frdp->cancel = XtVaCreateManagedWidget("closeButton",
+ xmPushButtonWidgetClass, button_form,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ NULL);
+ set_label(frdp->cancel, _("&Cancel"));
+ XtAddCallback(frdp->cancel, XmNactivateCallback,
+ find_replace_dismiss_callback, frdp);
+ gui_motif_menu_fontlist(frdp->cancel);
+
+ XtManageChild(button_form);
+
+ n = 0;
+ XtSetArg(args[n], XmNorientation, XmVERTICAL); n++;
+ XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
+ XtSetArg(args[n], XmNrightWidget, button_form); n++;
+ XtSetArg(args[n], XmNrightOffset, 4); n++;
+ XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
+ XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
+ separator = XmCreateSeparatorGadget(frdp->dialog, "separator", args, n);
+ XtManageChild(separator);
+
+ input_form = XtVaCreateWidget("inputForm",
+ xmFormWidgetClass, frdp->dialog,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNleftOffset, 4,
+ XmNrightAttachment, XmATTACH_WIDGET,
+ XmNrightWidget, separator,
+ XmNrightOffset, 4,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNtopOffset, 4,
+ NULL);
+
+ {
+ Widget label_what;
+ Widget label_with = (Widget)0;
+
+ str = XmStringCreateSimple(_("Find what:"));
+ label_what = XtVaCreateManagedWidget("whatLabel",
+ xmLabelGadgetClass, input_form,
+ XmNlabelString, str,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNtopOffset, 4,
+ NULL);
+ XmStringFree(str);
+ gui_motif_menu_fontlist(label_what);
+
+ frdp->what = XtVaCreateManagedWidget("whatText",
+ xmTextFieldWidgetClass, input_form,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+ NULL);
+
+ if (do_replace)
+ {
+ frdp->with = XtVaCreateManagedWidget("withText",
+ xmTextFieldWidgetClass, input_form,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, frdp->what,
+ XmNtopOffset, 4,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ NULL);
+
+ XtAddCallback(frdp->with, XmNactivateCallback,
+ find_replace_callback, (XtPointer) FRD_R_FINDNEXT);
+
+ str = XmStringCreateSimple(_("Replace with:"));
+ label_with = XtVaCreateManagedWidget("withLabel",
+ xmLabelGadgetClass, input_form,
+ XmNlabelString, str,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, frdp->what,
+ XmNtopOffset, 4,
+ XmNbottomAttachment, XmATTACH_FORM,
+ NULL);
+ XmStringFree(str);
+ gui_motif_menu_fontlist(label_with);
+
+ /*
+ * Make the entry activation only change the input focus onto the
+ * with item.
+ */
+ XtAddCallback(frdp->what, XmNactivateCallback,
+ entry_activate_callback, frdp->with);
+ XtAddEventHandler(frdp->with, KeyPressMask, False,
+ (XtEventHandler)find_replace_keypress,
+ (XtPointer) frdp);
+
+ }
+ else
+ {
+ /*
+ * Make the entry activation do the search.
+ */
+ XtAddCallback(frdp->what, XmNactivateCallback,
+ find_replace_callback, (XtPointer)FRD_FINDNEXT);
+ }
+ XtAddEventHandler(frdp->what, KeyPressMask, False,
+ (XtEventHandler)find_replace_keypress,
+ (XtPointer)frdp);
+
+ /* Get the maximum width between the label widgets and line them up.
+ */
+ n = 0;
+ XtSetArg(args[n], XmNwidth, &width); n++;
+ XtGetValues(label_what, args, n);
+ widest = width;
+ if (do_replace)
+ {
+ XtGetValues(label_with, args, n);
+ if (width > widest)
+ widest = width;
+ }
+
+ XtVaSetValues(frdp->what, XmNleftOffset, widest, NULL);
+ if (do_replace)
+ XtVaSetValues(frdp->with, XmNleftOffset, widest, NULL);
+
+ }
+
+ XtManageChild(input_form);
+
+ {
+ Widget radio_box;
+ Widget w;
+
+ frame = XtVaCreateWidget("directionFrame",
+ xmFrameWidgetClass, frdp->dialog,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, input_form,
+ XmNtopOffset, 4,
+ XmNbottomAttachment, XmATTACH_FORM,
+ XmNbottomOffset, 4,
+ XmNrightAttachment, XmATTACH_OPPOSITE_WIDGET,
+ XmNrightWidget, input_form,
+ NULL);
+
+ str = XmStringCreateSimple(_("Direction"));
+ w = XtVaCreateManagedWidget("directionFrameLabel",
+ xmLabelGadgetClass, frame,
+ XmNlabelString, str,
+ XmNchildHorizontalAlignment, XmALIGNMENT_BEGINNING,
+ XmNchildType, XmFRAME_TITLE_CHILD,
+ NULL);
+ XmStringFree(str);
+ gui_motif_menu_fontlist(w);
+
+ radio_box = XmCreateRadioBox(frame, "radioBox",
+ (ArgList)NULL, 0);
+
+ str = XmStringCreateSimple( _("Up"));
+ frdp->up = XtVaCreateManagedWidget("upRadioButton",
+ xmToggleButtonGadgetClass, radio_box,
+ XmNlabelString, str,
+ XmNset, False,
+ NULL);
+ XmStringFree(str);
+ gui_motif_menu_fontlist(frdp->up);
+
+ str = XmStringCreateSimple(_("Down"));
+ frdp->down = XtVaCreateManagedWidget("downRadioButton",
+ xmToggleButtonGadgetClass, radio_box,
+ XmNlabelString, str,
+ XmNset, True,
+ NULL);
+ XmStringFree(str);
+ gui_motif_menu_fontlist(frdp->down);
+
+ XtManageChild(radio_box);
+ XtManageChild(frame);
+ }
+
+ toggle_form = XtVaCreateWidget("toggleForm",
+ xmFormWidgetClass, frdp->dialog,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNleftOffset, 4,
+ XmNrightAttachment, XmATTACH_WIDGET,
+ XmNrightWidget, frame,
+ XmNrightOffset, 4,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, input_form,
+ XmNtopOffset, 4,
+ XmNbottomAttachment, XmATTACH_FORM,
+ XmNbottomOffset, 4,
+ NULL);
+
+ str = XmStringCreateSimple(_("Match whole word only"));
+ frdp->wword = XtVaCreateManagedWidget("wordToggle",
+ xmToggleButtonGadgetClass, toggle_form,
+ XmNlabelString, str,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNtopOffset, 4,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNleftOffset, 4,
+ XmNset, wword,
+ NULL);
+ XmStringFree(str);
+
+ str = XmStringCreateSimple(_("Match case"));
+ frdp->mcase = XtVaCreateManagedWidget("caseToggle",
+ xmToggleButtonGadgetClass, toggle_form,
+ XmNlabelString, str,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNleftOffset, 4,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, frdp->wword,
+ XmNtopOffset, 4,
+ XmNset, mcase,
+ NULL);
+ XmStringFree(str);
+ gui_motif_menu_fontlist(frdp->wword);
+ gui_motif_menu_fontlist(frdp->mcase);
+
+ XtManageChild(toggle_form);
+
+ if (entry_text != NULL)
+ XmTextFieldSetString(frdp->what, (char *)entry_text);
+ vim_free(entry_text);
+
+ gui_motif_synch_fonts();
+
+ manage_centered(frdp->dialog);
+ activate_dialog_mnemonics(frdp->dialog);
+ XmProcessTraversal(frdp->what, XmTRAVERSE_CURRENT);
+}
+
+ void
+gui_mch_find_dialog(exarg_T *eap)
+{
+ if (!gui.in_use)
+ return;
+
+ find_replace_dialog_create(eap->arg, FALSE);
+}
+
+
+ void
+gui_mch_replace_dialog(exarg_T *eap)
+{
+ if (!gui.in_use)
+ return;
+
+ find_replace_dialog_create(eap->arg, TRUE);
+}
+
+/*
+ * Synchronize all gui elements, which are dependant upon the
+ * main text font used. Those are in esp. the find/replace dialogs.
+ * If you don't understand why this should be needed, please try to
+ * search for "pi\xea\xb6\xe6" in iso8859-2.
+ */
+ void
+gui_motif_synch_fonts(void)
+{
+ SharedFindReplace *frdp;
+ int do_replace;
+ XFontStruct *font;
+ XmFontList font_list;
+
+ /* FIXME: Unless we find out how to create a XmFontList from a XFontSet,
+ * we just give up here on font synchronization. */
+ font = (XFontStruct *)gui.norm_font;
+ if (font == NULL)
+ return;
+
+ font_list = gui_motif_create_fontlist(font);
+
+ /* OK this loop is a bit tricky... */
+ for (do_replace = 0; do_replace <= 1; ++do_replace)
+ {
+ frdp = (do_replace) ? (&repl_widgets) : (&find_widgets);
+ if (frdp->dialog)
+ {
+ XtVaSetValues(frdp->what, XmNfontList, font_list, NULL);
+ if (do_replace)
+ XtVaSetValues(frdp->with, XmNfontList, font_list, NULL);
+ }
+ }
+
+ XmFontListFree(font_list);
+}
diff --git a/src/gui_photon.c b/src/gui_photon.c
new file mode 100644
index 0000000..9401228
--- /dev/null
+++ b/src/gui_photon.c
@@ -0,0 +1,2959 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ * Photon GUI support by Julian Kinraid
+ *
+ * Do ":help uganda" in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ *
+ *
+ * Clipboard support is in os_qnx.c
+ * PhAttach() is called in os_qnx.c:qnx_init()
+ */
+
+#include "vim.h"
+
+/* cproto fails on missing include files */
+#ifndef PROTO
+# ifdef FEAT_TOOLBAR
+# include <photon/PxImage.h>
+# endif
+#endif
+
+#if !defined(__QNX__)
+/* Used when generating prototypes. */
+# define PgColor_t int
+# define PhEvent_t int
+# define PhPoint_t int
+# define PtWidget_t int
+# define Pg_BLACK 0
+# define PtCallbackF_t int
+# define PtCallbackInfo_t int
+# define PhTile_t int
+# define PtWidget_t int
+# define PhImage_t int
+#endif
+
+#define ARRAY_LENGTH(a) (sizeof(a) / sizeof(a[0]))
+#define RGB(r, g, b) PgRGB(r, g, b)
+
+#define EVENT_BUFFER_SIZE sizeof(PhEvent_t) + 1000
+
+/* Some defines for gui_mch_mousehide() */
+#define MOUSE_HIDE TRUE
+#define MOUSE_SHOW FALSE
+
+/* Optional support for using a PtPanelGroup widget, needs work */
+#undef USE_PANEL_GROUP
+
+#ifdef USE_PANEL_GROUP
+static char *empty_title = " ";
+static char **panel_titles = NULL;
+static ushort_t num_panels = 0;
+static short pg_margin_left, pg_margin_right, pg_margin_top, pg_margin_bottom;
+#endif
+
+#define GUI_PH_MARGIN 4 /* Size of the bevel */
+
+#define GUI_PH_MOUSE_TYPE Ph_CURSOR_INSERT
+static PgColor_t gui_ph_mouse_color = Pg_BLACK;
+
+static PhPoint_t gui_ph_raw_offset;
+static PtWidget_t *gui_ph_timer_cursor; /* handle cursor blinking */
+static PtWidget_t *gui_ph_timer_timeout; /* used in gui_mch_wait_for_chars */
+static short is_timeout; /* Has the timeout occurred? */
+
+/*
+ * This is set inside the mouse callback for a right mouse
+ * button click, and used for the popup menus
+ */
+static PhPoint_t abs_mouse;
+
+/* Try and avoid redraws while a resize is in progress */
+static int is_ignore_draw = FALSE;
+
+/* Used for converting to/from utf-8 and other charsets */
+static struct PxTransCtrl *charset_translate;
+
+/*
+ * 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
+ */
+static enum {
+ BLINK_NONE,
+ BLINK_OFF,
+ BLINK_ON
+} blink_state = BLINK_NONE;
+
+static long_u blink_waittime = 700;
+static long_u blink_ontime = 400;
+static long_u blink_offtime = 250;
+
+static struct
+{
+ int key_sym;
+ char_u vim_code0;
+ char_u vim_code1;
+} special_keys[] =
+{
+ {Pk_Up, 'k', 'u'},
+ {Pk_Down, 'k', 'd'},
+ {Pk_Left, 'k', 'l'},
+ {Pk_Right, 'k', 'r'},
+
+ {Pk_F1, 'k', '1'},
+ {Pk_F2, 'k', '2'},
+ {Pk_F3, 'k', '3'},
+ {Pk_F4, 'k', '4'},
+ {Pk_F5, 'k', '5'},
+ {Pk_F6, 'k', '6'},
+ {Pk_F7, 'k', '7'},
+ {Pk_F8, 'k', '8'},
+ {Pk_F9, 'k', '9'},
+ {Pk_F10, 'k', ';'},
+
+ {Pk_F11, 'F', '1'},
+ {Pk_F12, 'F', '2'},
+ {Pk_F13, 'F', '3'},
+ {Pk_F14, 'F', '4'},
+ {Pk_F15, 'F', '5'},
+ {Pk_F16, 'F', '6'},
+ {Pk_F17, 'F', '7'},
+ {Pk_F18, 'F', '8'},
+ {Pk_F19, 'F', '9'},
+ {Pk_F20, 'F', 'A'},
+
+ {Pk_F21, 'F', 'B'},
+ {Pk_F22, 'F', 'C'},
+ {Pk_F23, 'F', 'D'},
+ {Pk_F24, 'F', 'E'},
+ {Pk_F25, 'F', 'F'},
+ {Pk_F26, 'F', 'G'},
+ {Pk_F27, 'F', 'H'},
+ {Pk_F28, 'F', 'I'},
+ {Pk_F29, 'F', 'J'},
+
+ {Pk_F30, 'F', 'K'},
+ {Pk_F31, 'F', 'L'},
+ {Pk_F32, 'F', 'M'},
+ {Pk_F33, 'F', 'N'},
+ {Pk_F34, 'F', 'O'},
+ {Pk_F35, 'F', 'P'},
+
+ {Pk_Help, '%', '1'},
+ {Pk_BackSpace, 'k', 'b'},
+ {Pk_Insert, 'k', 'I'},
+ {Pk_Delete, 'k', 'D'},
+ {Pk_Home, 'k', 'h'},
+ {Pk_End, '@', '7'},
+ {Pk_Prior, 'k', 'P'},
+ {Pk_Next, 'k', 'N'},
+ {Pk_Print, '%', '9'},
+
+ {Pk_KP_Add, 'K', '6'},
+ {Pk_KP_Subtract,'K', '7'},
+ {Pk_KP_Divide, 'K', '8'},
+ {Pk_KP_Multiply,'K', '9'},
+ {Pk_KP_Enter, 'K', 'A'},
+
+ {Pk_KP_0, KS_EXTRA, KE_KINS}, /* Insert */
+ {Pk_KP_Decimal, KS_EXTRA, KE_KDEL}, /* Delete */
+
+ {Pk_KP_4, 'k', 'l'}, /* Left */
+ {Pk_KP_6, 'k', 'r'}, /* Right */
+ {Pk_KP_8, 'k', 'u'}, /* Up */
+ {Pk_KP_2, 'k', 'd'}, /* Down */
+
+ {Pk_KP_7, 'K', '1'}, /* Home */
+ {Pk_KP_1, 'K', '4'}, /* End */
+
+ {Pk_KP_9, 'K', '3'}, /* Page Up */
+ {Pk_KP_3, 'K', '5'}, /* Page Down */
+
+ {Pk_KP_5, '&', '8'}, /* Undo */
+
+ /* Keys that we want to be able to use any modifier with: */
+ {Pk_Return, CAR, NUL},
+ {Pk_space, ' ', NUL},
+ {Pk_Tab, TAB, NUL},
+ {Pk_Escape, ESC, NUL},
+ {NL, NL, NUL},
+ {CAR, CAR, NUL},
+
+ /* End of list marker: */
+ {0, 0, 0}
+};
+
+
+/****************************************************************************/
+
+static PtCallbackF_t gui_ph_handle_timer_cursor;
+static PtCallbackF_t gui_ph_handle_timer_timeout;
+
+static PtCallbackF_t gui_ph_handle_window_cb;
+
+static PtCallbackF_t gui_ph_handle_scrollbar;
+static PtCallbackF_t gui_ph_handle_keyboard;
+static PtCallbackF_t gui_ph_handle_mouse;
+static PtCallbackF_t gui_ph_handle_pulldown_menu;
+static PtCallbackF_t gui_ph_handle_menu;
+static PtCallbackF_t gui_ph_handle_focus; /* focus change of text area */
+
+static PtCallbackF_t gui_ph_handle_menu_resize;
+
+/* When a menu is unrealized, give focus back to vimTextArea */
+static PtCallbackF_t gui_ph_handle_menu_unrealized;
+
+#ifdef USE_PANEL_GROUP
+static void gui_ph_get_panelgroup_margins(short*, short*, short*, short*);
+#endif
+
+static void gui_ph_draw_start(void);
+static void gui_ph_draw_end(void);
+
+/* Set the text for the balloon */
+static PtWidget_t * gui_ph_show_tooltip(PtWidget_t *window,
+ PtWidget_t *widget,
+ int position,
+ char *text,
+ char *font,
+ PgColor_t fill_color,
+ PgColor_t text_color);
+
+/****************************************************************************/
+
+static PtWidget_t * gui_ph_show_tooltip(PtWidget_t *window,
+ PtWidget_t *widget,
+ int position,
+ char *text,
+ char *font,
+ PgColor_t fill_color,
+ PgColor_t text_color)
+{
+ PtArg_t arg;
+ vimmenu_T *menu;
+ char_u *tooltip;
+
+ PtSetArg(&arg, Pt_ARG_POINTER, &menu, 0);
+ PtGetResources(widget, 1, &arg);
+
+ /* Override the text and position */
+
+ tooltip = text;
+ if (menu != NULL)
+ {
+ int index = MENU_INDEX_TIP;
+ if (menu->strings[ index ] != NULL)
+ tooltip = menu->strings[ index ];
+ }
+
+ return PtInflateBalloon(
+ window,
+ widget,
+ /* Don't put the balloon at the bottom,
+ * it gets drawn over by gfx done in the PtRaw */
+ Pt_BALLOON_TOP,
+ tooltip,
+ font,
+ fill_color,
+ text_color);
+}
+
+ static void
+gui_ph_resize_container(void)
+{
+ PhArea_t area;
+
+ PtWidgetArea(gui.vimWindow, &area);
+ PtWidgetPos (gui.vimContainer, &area.pos);
+
+ PtSetResource(gui.vimContainer, Pt_ARG_AREA, &area, 0);
+}
+
+ static int
+gui_ph_handle_menu_resize(
+ PtWidget_t *widget,
+ void *other,
+ PtCallbackInfo_t *info)
+{
+ PtContainerCallback_t *sizes = info->cbdata;
+ PtWidget_t *container;
+ PhPoint_t below_menu;
+ int_u height;
+
+ height = sizes->new_dim.h;
+
+ /* Because vim treats the toolbar and menubar separately,
+ * and here they're lumped together into a PtToolbarGroup,
+ * we only need either menu_height or toolbar_height set at once */
+ if (gui.menu_is_active)
+ {
+ gui.menu_height = height;
+ gui.toolbar_height = 0;
+ }
+#ifdef FEAT_TOOLBAR
+ else
+ gui.toolbar_height = height;
+#endif
+
+ below_menu.x = 0;
+ below_menu.y = height;
+
+#ifdef USE_PANEL_GROUP
+ container = gui.vimPanelGroup;
+#else
+ container = gui.vimContainer;
+#endif
+
+ PtSetResource(container, Pt_ARG_POS, &below_menu, 0);
+
+ gui_ph_resize_container();
+
+#ifdef USE_PANEL_GROUP
+ gui_ph_get_panelgroup_margins(
+ &pg_margin_top, &pg_margin_bottom,
+ &pg_margin_left, &pg_margin_right);
+#endif
+ return Pt_CONTINUE;
+}
+
+/*
+ * Pt_ARG_TIMER_REPEAT isn't used because the on & off times
+ * are different
+ */
+ static int
+gui_ph_handle_timer_cursor(
+ PtWidget_t *widget,
+ void *data,
+ PtCallbackInfo_t *info)
+{
+ if (blink_state == BLINK_ON)
+ {
+ gui_undraw_cursor();
+ blink_state = BLINK_OFF;
+ PtSetResource(gui_ph_timer_cursor, Pt_ARG_TIMER_INITIAL,
+ blink_offtime, 0);
+ }
+ else
+ {
+ gui_update_cursor(TRUE, FALSE);
+ blink_state = BLINK_ON;
+ PtSetResource(gui_ph_timer_cursor, Pt_ARG_TIMER_INITIAL,
+ blink_ontime, 0);
+ }
+ return Pt_CONTINUE;
+}
+
+ static int
+gui_ph_handle_timer_timeout(PtWidget_t *widget, void *data, PtCallbackInfo_t *info)
+{
+ is_timeout = TRUE;
+
+ return Pt_CONTINUE;
+}
+
+ static int
+gui_ph_handle_window_cb(PtWidget_t *widget, void *data, PtCallbackInfo_t *info)
+{
+ PhWindowEvent_t *we = info->cbdata;
+ ushort_t *width, *height;
+
+ switch (we->event_f) {
+ case Ph_WM_CLOSE:
+ gui_shell_closed();
+ break;
+
+ case Ph_WM_FOCUS:
+ /* Just in case it's hidden and needs to be shown */
+ gui_mch_mousehide(MOUSE_SHOW);
+
+ if (we->event_state == Ph_WM_EVSTATE_FOCUS)
+ {
+ gui_focus_change(TRUE);
+ gui_mch_start_blink();
+ }
+ else
+ {
+ gui_focus_change(FALSE);
+ gui_mch_stop_blink(TRUE);
+ }
+ break;
+
+ case Ph_WM_RESIZE:
+ PtGetResource(gui.vimWindow, Pt_ARG_WIDTH, &width, 0);
+ PtGetResource(gui.vimWindow, Pt_ARG_HEIGHT, &height, 0);
+#ifdef USE_PANEL_GROUP
+ width -= (pg_margin_left + pg_margin_right);
+ height -= (pg_margin_top + pg_margin_bottom);
+#endif
+ gui_resize_shell(*width, *height);
+ gui_set_shellsize(FALSE, FALSE, RESIZE_BOTH);
+ is_ignore_draw = FALSE;
+ PtEndFlux(gui.vimContainer);
+ PtContainerRelease(gui.vimContainer);
+ break;
+
+ default:
+ break;
+ }
+
+ return Pt_CONTINUE;
+}
+
+ static int
+gui_ph_handle_scrollbar(PtWidget_t *widget, void *data, PtCallbackInfo_t *info)
+{
+ PtScrollbarCallback_t *scroll;
+ scrollbar_T *sb;
+ int value, dragging = FALSE;
+
+ scroll = info->cbdata;
+
+ sb = (scrollbar_T *) data;
+ if (sb != NULL)
+ {
+ value = scroll->position;
+ switch (scroll->action)
+ {
+ case Pt_SCROLL_DRAGGED:
+ dragging = TRUE;
+ break;
+
+ case Pt_SCROLL_SET:
+ /* FIXME: return straight away here? */
+ return Pt_CONTINUE;
+ break;
+ }
+
+ gui_drag_scrollbar(sb, value, dragging);
+ }
+ return Pt_CONTINUE;
+}
+
+ static int
+gui_ph_handle_keyboard(PtWidget_t *widget, void *data, PtCallbackInfo_t *info)
+{
+ PhKeyEvent_t *key;
+ unsigned char string[6];
+ int len, i;
+ int ch, modifiers;
+
+ key = PhGetData(info->event);
+
+ ch = modifiers = len = 0;
+
+ if (p_mh)
+ gui_mch_mousehide(MOUSE_HIDE);
+
+ /* We're a good lil photon program, aren't we? yes we are, yeess wee arrr */
+ if (key->key_flags & Pk_KF_Compose)
+ {
+ return Pt_CONTINUE;
+ }
+
+ if ((key->key_flags & Pk_KF_Cap_Valid) &&
+ PkIsKeyDown(key->key_flags))
+ {
+#ifdef FEAT_MENU
+ /*
+ * Only show the menu if the Alt key is down, and the Shift & Ctrl
+ * keys aren't down, as well as the other conditions
+ */
+ if (((key->key_mods & Pk_KM_Alt) &&
+ !(key->key_mods & Pk_KM_Shift) &&
+ !(key->key_mods & Pk_KM_Ctrl)) &&
+ gui.menu_is_active &&
+ (*p_wak == 'y' ||
+ (*p_wak == 'm' &&
+ gui_is_menu_shortcut(key->key_cap))))
+ {
+ /* Fallthrough and let photon look for the hotkey */
+ return Pt_CONTINUE;
+ }
+#endif
+
+ for (i = 0; special_keys[i].key_sym != 0; i++)
+ {
+ if (special_keys[i].key_sym == key->key_cap)
+ {
+ len = 0;
+ if (special_keys[i].vim_code1 == NUL)
+ ch = special_keys[i].vim_code0;
+ else
+ {
+ /* Detect if a keypad number key has been pressed
+ * and change the key if Num Lock is on */
+ if (key->key_cap >= Pk_KP_Enter && key->key_cap <= Pk_KP_9
+ && (key->key_mods & Pk_KM_Num_Lock))
+ {
+ /* FIXME: For now, just map the key to a ascii value
+ * (see <photon/PkKeyDef.h>) */
+ ch = key->key_cap - 0xf080;
+ }
+ else
+ ch = TO_SPECIAL(special_keys[i].vim_code0,
+ special_keys[i].vim_code1);
+ }
+ break;
+ }
+ }
+
+ if (key->key_mods & Pk_KM_Ctrl)
+ modifiers |= MOD_MASK_CTRL;
+ if (key->key_mods & Pk_KM_Alt)
+ modifiers |= MOD_MASK_ALT;
+ if (key->key_mods & Pk_KM_Shift)
+ modifiers |= MOD_MASK_SHIFT;
+
+ /* Is this not a special key? */
+ if (special_keys[i].key_sym == 0)
+ {
+ ch = PhTo8859_1(key);
+ if (ch == -1 || (enc_utf8 && ch > 127))
+ {
+ len = PhKeyToMb(string, key);
+ if (len > 0)
+ {
+ static char buf[6];
+ int src_taken, dst_made;
+ if (enc_utf8 != TRUE)
+ {
+ PxTranslateFromUTF(
+ charset_translate,
+ string,
+ len,
+ &src_taken,
+ buf,
+ 6,
+ &dst_made);
+
+ add_to_input_buf(buf, dst_made);
+ }
+ else
+ {
+ add_to_input_buf(string, len);
+ }
+
+ return Pt_CONSUME;
+ }
+ len = 0;
+ ch = key->key_cap;
+ if (ch < 0xff)
+ {
+ /* FIXME: is this the right thing to do? */
+ if (modifiers & MOD_MASK_CTRL)
+ {
+ modifiers &= ~MOD_MASK_CTRL;
+
+ if ((ch >= 'a' && ch <= 'z') ||
+ ch == '[' ||
+ ch == ']' ||
+ ch == '\\')
+ ch = Ctrl_chr(ch);
+ else if (ch == '2')
+ ch = NUL;
+ else if (ch == '6')
+ ch = 0x1e;
+ else if (ch == '-')
+ ch = 0x1f;
+ else
+ modifiers |= MOD_MASK_CTRL;
+ }
+
+ if (modifiers & MOD_MASK_ALT)
+ {
+ ch = Meta(ch);
+ modifiers &= ~MOD_MASK_ALT;
+ }
+ }
+ else
+ {
+ return Pt_CONTINUE;
+ }
+ }
+ else
+ modifiers &= ~MOD_MASK_SHIFT;
+ }
+
+ ch = simplify_key(ch, &modifiers);
+ if (modifiers)
+ {
+ string[ len++ ] = CSI;
+ string[ len++ ] = KS_MODIFIER;
+ string[ len++ ] = modifiers;
+ }
+
+ if (IS_SPECIAL(ch))
+ {
+ string[ len++ ] = CSI;
+ string[ len++ ] = K_SECOND(ch);
+ string[ len++ ] = K_THIRD(ch);
+ }
+ else
+ {
+ string[ len++ ] = ch;
+ }
+
+ if (len == 1 && ((ch == Ctrl_C && ctrl_c_interrupts)
+ || ch == intr_char))
+ {
+ trash_input_buf();
+ got_int = TRUE;
+ }
+
+ if (len == 1 && string[0] == CSI)
+ {
+ /* Turn CSI into K_CSI. */
+ string[ len++ ] = KS_EXTRA;
+ string[ len++ ] = KE_CSI;
+ }
+
+ if (len > 0)
+ {
+ add_to_input_buf(string, len);
+ return Pt_CONSUME;
+ }
+ }
+
+ return Pt_CONTINUE;
+}
+
+ static int
+gui_ph_handle_mouse(PtWidget_t *widget, void *data, PtCallbackInfo_t *info)
+{
+ PhPointerEvent_t *pointer;
+ PhRect_t *pos;
+ int button = 0, repeated_click, modifiers = 0x0;
+ short mouse_x, mouse_y;
+
+ pointer = PhGetData(info->event);
+ pos = PhGetRects(info->event);
+
+ gui_mch_mousehide(MOUSE_SHOW);
+
+ /*
+ * Coordinates need to be relative to the base window,
+ * not relative to the vimTextArea widget
+ */
+ mouse_x = pos->ul.x + gui.border_width;
+ mouse_y = pos->ul.y + gui.border_width;
+
+ if (info->event->type == Ph_EV_PTR_MOTION_NOBUTTON)
+ {
+ gui_mouse_moved(mouse_x, mouse_y);
+ return Pt_CONTINUE;
+ }
+
+ if (pointer->key_mods & Pk_KM_Shift)
+ modifiers |= MOUSE_SHIFT;
+ if (pointer->key_mods & Pk_KM_Ctrl)
+ modifiers |= MOUSE_CTRL;
+ if (pointer->key_mods & Pk_KM_Alt)
+ modifiers |= MOUSE_ALT;
+
+ /*
+ * FIXME More than one button may be involved, but for
+ * now just deal with one
+ */
+ if (pointer->buttons & Ph_BUTTON_SELECT)
+ button = MOUSE_LEFT;
+
+ if (pointer->buttons & Ph_BUTTON_MENU)
+ {
+ button = MOUSE_RIGHT;
+ /* Need the absolute coordinates for the popup menu */
+ abs_mouse.x = pointer->pos.x;
+ abs_mouse.y = pointer->pos.y;
+ }
+
+ if (pointer->buttons & Ph_BUTTON_ADJUST)
+ button = MOUSE_MIDDLE;
+
+ /* Catch a real release (not phantom or other releases */
+ if (info->event->type == Ph_EV_BUT_RELEASE)
+ button = MOUSE_RELEASE;
+
+ if (info->event->type & Ph_EV_PTR_MOTION_BUTTON)
+ button = MOUSE_DRAG;
+
+#if 0
+ /* Vim doesn't use button repeats */
+ if (info->event->type & Ph_EV_BUT_REPEAT)
+ button = MOUSE_DRAG;
+#endif
+
+ /* Don't do anything if it is one of the phantom mouse release events */
+ if ((button != MOUSE_RELEASE) ||
+ (info->event->subtype == Ph_EV_RELEASE_REAL))
+ {
+ repeated_click = (pointer->click_count >= 2) ? TRUE : FALSE;
+
+ gui_send_mouse_event(button , mouse_x, mouse_y, repeated_click, modifiers);
+ }
+
+ return Pt_CONTINUE;
+}
+
+/* Handle a focus change of the PtRaw widget */
+ static int
+gui_ph_handle_focus(PtWidget_t *widget, void *data, PtCallbackInfo_t *info)
+{
+ if (info->reason == Pt_CB_LOST_FOCUS)
+ {
+ PtRemoveEventHandler(gui.vimTextArea, Ph_EV_PTR_MOTION_NOBUTTON,
+ gui_ph_handle_mouse, NULL);
+
+ gui_mch_mousehide(MOUSE_SHOW);
+ }
+ else
+ {
+ PtAddEventHandler(gui.vimTextArea, Ph_EV_PTR_MOTION_NOBUTTON,
+ gui_ph_handle_mouse, NULL);
+ }
+ return Pt_CONTINUE;
+}
+
+ static void
+gui_ph_handle_raw_draw(PtWidget_t *widget, PhTile_t *damage)
+{
+ PhRect_t *r;
+ PhPoint_t offset;
+ PhPoint_t translation;
+
+ if (is_ignore_draw == TRUE)
+ return;
+
+ PtSuperClassDraw(PtBasic, widget, damage);
+ PgGetTranslation(&translation);
+ PgClearTranslation();
+
+#if 0
+ /*
+ * This causes some weird problems, with drawing being done from
+ * within this raw drawing function (rather than just simple clearing
+ * and text drawing done by gui_redraw)
+ *
+ * The main problem is when PhBlit is used, and the cursor appearing
+ * in places where it shouldn't
+ */
+ out_flush();
+#endif
+
+ PtWidgetOffset(widget, &offset);
+ PhTranslatePoint(&offset, PtWidgetPos(gui.vimTextArea, NULL));
+
+#if 1
+ /* Redraw individual damage regions */
+ if (damage->next != NULL)
+ damage = damage->next;
+
+ while (damage != NULL)
+ {
+ r = &damage->rect;
+ gui_redraw(
+ r->ul.x - offset.x, r->ul.y - offset.y,
+ r->lr.x - r->ul.x + 1,
+ r->lr.y - r->ul.y + 1);
+ damage = damage->next;
+ }
+#else
+ /* Redraw the rectangle that covers all the damaged regions */
+ r = &damage->rect;
+ gui_redraw(
+ r->ul.x - offset.x, r->ul.y - offset.y,
+ r->lr.x - r->ul.x + 1,
+ r->lr.y - r->ul.y + 1);
+#endif
+
+ PgSetTranslation(&translation, 0);
+}
+
+ static int
+gui_ph_handle_pulldown_menu(
+ PtWidget_t *widget,
+ void *data,
+ PtCallbackInfo_t *info)
+{
+ if (data != NULL)
+ {
+ vimmenu_T *menu = (vimmenu_T *) data;
+
+ PtPositionMenu(menu->submenu_id, NULL);
+ PtRealizeWidget(menu->submenu_id);
+ }
+
+ return Pt_CONTINUE;
+}
+
+/* This is used for pulldown/popup menus and also toolbar buttons */
+ static int
+gui_ph_handle_menu(PtWidget_t *widget, void *data, PtCallbackInfo_t *info)
+{
+ if (data != NULL)
+ {
+ vimmenu_T *menu = (vimmenu_T *) data;
+ gui_menu_cb(menu);
+ }
+ return Pt_CONTINUE;
+}
+
+/* Stop focus from disappearing into the menubar... */
+ static int
+gui_ph_handle_menu_unrealized(
+ PtWidget_t *widget,
+ void *data,
+ PtCallbackInfo_t *info)
+{
+ PtGiveFocus(gui.vimTextArea, NULL);
+ return Pt_CONTINUE;
+}
+
+ static int
+gui_ph_handle_window_open(
+ PtWidget_t *widget,
+ void *data,
+ PtCallbackInfo_t *info)
+{
+ gui_set_shellsize(FALSE, TRUE, RESIZE_BOTH);
+ return Pt_CONTINUE;
+}
+
+/****************************************************************************/
+
+#define DRAW_START gui_ph_draw_start()
+#define DRAW_END gui_ph_draw_end()
+
+/* TODO: Set a clipping rect? */
+ static void
+gui_ph_draw_start(void)
+{
+ PhGC_t *gc;
+
+ gc = PgGetGC();
+ PgSetRegion(PtWidgetRid(PtFindDisjoint(gui.vimTextArea)));
+ PgClearClippingsCx(gc);
+ PgClearTranslationCx(gc);
+
+ PtWidgetOffset(gui.vimTextArea, &gui_ph_raw_offset);
+ PhTranslatePoint(&gui_ph_raw_offset, PtWidgetPos(gui.vimTextArea, NULL));
+
+ PgSetTranslation(&gui_ph_raw_offset, Pg_RELATIVE);
+}
+
+ static void
+gui_ph_draw_end(void)
+{
+ gui_ph_raw_offset.x = -gui_ph_raw_offset.x;
+ gui_ph_raw_offset.y = -gui_ph_raw_offset.y;
+ PgSetTranslation(&gui_ph_raw_offset, Pg_RELATIVE);
+}
+
+#ifdef USE_PANEL_GROUP
+ static vimmenu_T *
+gui_ph_find_buffer_item(char_u *name)
+{
+ vimmenu_T *top_level = root_menu;
+ vimmenu_T *items = NULL;
+
+ while (top_level != NULL &&
+ (STRCMP(top_level->dname, "Buffers") != 0))
+ top_level = top_level->next;
+
+ if (top_level != NULL)
+ {
+ items = top_level->children;
+
+ while (items != NULL &&
+ (STRCMP(items->dname, name) != 0))
+ items = items->next;
+ }
+ return items;
+}
+
+ static void
+gui_ph_pg_set_buffer_num(int_u buf_num)
+{
+ int i;
+ char search[16];
+ char *mark;
+
+ if (gui.vimTextArea == NULL || buf_num == 0)
+ return;
+
+ search[0] = '(';
+ ultoa(buf_num, &search[1], 10);
+ STRCAT(search, ")");
+
+ for (i = 0; i < num_panels; i++)
+ {
+ /* find the last "(" in the panel title and see if the buffer
+ * number in the title matches the one we're looking for */
+ mark = STRRCHR(panel_titles[ i ], '(');
+ if (mark != NULL && STRCMP(mark, search) == 0)
+ {
+ PtSetResource(gui.vimPanelGroup, Pt_ARG_PG_CURRENT_INDEX,
+ i, 0);
+ }
+ }
+}
+
+ static int
+gui_ph_handle_pg_change(
+ PtWidget_t *widget,
+ void *data,
+ PtCallbackInfo_t *info)
+{
+ vimmenu_T *menu;
+ PtPanelGroupCallback_t *panel;
+
+ if (info->event != NULL)
+ {
+ panel = info->cbdata;
+ if (panel->new_panel != NULL)
+ {
+ menu = gui_ph_find_buffer_item(panel->new_panel);
+ if (menu)
+ gui_menu_cb(menu);
+ }
+ }
+ return Pt_CONTINUE;
+}
+
+ static void
+gui_ph_get_panelgroup_margins(
+ short *top,
+ short *bottom,
+ short *left,
+ short *right)
+{
+ unsigned short abs_raw_x, abs_raw_y, abs_panel_x, abs_panel_y;
+ const unsigned short *margin_top, *margin_bottom;
+ const unsigned short *margin_left, *margin_right;
+
+ PtGetAbsPosition(gui.vimTextArea, &abs_raw_x, &abs_raw_y);
+ PtGetAbsPosition(gui.vimPanelGroup, &abs_panel_x, &abs_panel_y);
+
+ PtGetResource(gui.vimPanelGroup, Pt_ARG_MARGIN_RIGHT, &margin_right, 0);
+ PtGetResource(gui.vimPanelGroup, Pt_ARG_MARGIN_BOTTOM, &margin_bottom, 0);
+
+ abs_raw_x -= abs_panel_x;
+ abs_raw_y -= abs_panel_y;
+
+ *top = abs_raw_y;
+ *bottom = *margin_bottom;
+
+ *left = abs_raw_x;
+ *right = *margin_right;
+}
+
+/* Used for the tabs for PtPanelGroup */
+ static int
+gui_ph_is_buffer_item(vimmenu_T *menu, vimmenu_T *parent)
+{
+ char *mark;
+
+ if (STRCMP(parent->dname, "Buffers") == 0)
+ {
+ /* Look for '(' digits ')' */
+ mark = vim_strchr(menu->dname, '(');
+ if (mark != NULL)
+ {
+ mark++;
+ while (isdigit(*mark))
+ mark++;
+
+ if (*mark == ')')
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+ static void
+gui_ph_pg_add_buffer(char *name)
+{
+ char **new_titles = NULL;
+
+ new_titles = (char **) alloc((num_panels + 1) * sizeof(char **));
+ if (new_titles != NULL)
+ {
+ if (num_panels > 0)
+ memcpy(new_titles, panel_titles, num_panels * sizeof(char **));
+
+ new_titles[ num_panels++ ] = name;
+
+ PtSetResource(gui.vimPanelGroup, Pt_ARG_PG_PANEL_TITLES, new_titles,
+ num_panels);
+
+ vim_free(panel_titles);
+ panel_titles = new_titles;
+ }
+}
+
+ static void
+gui_ph_pg_remove_buffer(char *name)
+{
+ int i;
+ char **new_titles = NULL;
+
+ /* If there is only 1 panel, we just use the temporary place holder */
+ if (num_panels > 1)
+ {
+ new_titles = (char **) alloc((num_panels - 1) * sizeof(char **));
+ if (new_titles != NULL)
+ {
+ char **s = new_titles;
+ /* Copy all the titles except the one we're removing */
+ for (i = 0; i < num_panels; i++)
+ {
+ if (STRCMP(panel_titles[ i ], name) != 0)
+ {
+ *s++ = panel_titles[ i ];
+ }
+ }
+ num_panels--;
+
+ PtSetResource(gui.vimPanelGroup, Pt_ARG_PG_PANEL_TITLES, new_titles,
+ num_panels);
+
+ vim_free(panel_titles);
+ panel_titles = new_titles;
+ }
+ }
+ else
+ {
+ num_panels--;
+ PtSetResource(gui.vimPanelGroup, Pt_ARG_PG_PANEL_TITLES, &empty_title,
+ 1);
+
+ VIM_CLEAR(panel_titles);
+ }
+}
+
+/* When a buffer item is deleted from the buffer menu */
+ static int
+gui_ph_handle_buffer_remove(
+ PtWidget_t *widget,
+ void *data,
+ PtCallbackInfo_t *info)
+{
+ vimmenu_T *menu;
+
+ if (data != NULL)
+ {
+ menu = (vimmenu_T *) data;
+ gui_ph_pg_remove_buffer(menu->dname);
+ }
+
+ return Pt_CONTINUE;
+}
+#endif
+
+ static int
+gui_ph_pane_resize(PtWidget_t *widget, void *data, PtCallbackInfo_t *info)
+{
+ if (PtWidgetIsRealized(widget))
+ {
+ is_ignore_draw = TRUE;
+ PtStartFlux(gui.vimContainer);
+ PtContainerHold(gui.vimContainer);
+ }
+
+ return Pt_CONTINUE;
+}
+
+/****************************************************************************/
+
+ void
+gui_ph_encoding_changed(int new_encoding)
+{
+ /* Default encoding is latin1 */
+ char *charset = "latin1";
+ int i;
+
+ struct {
+ int encoding;
+ char *name;
+ } charsets[] = {
+ { DBCS_JPN, "SHIFT_JIS" },
+ { DBCS_KOR, "csEUCKR" },
+ { DBCS_CHT, "big5" },
+ { DBCS_CHS, "gb" }
+ };
+
+ for (i = 0; i < ARRAY_LENGTH(charsets); i++)
+ {
+ if (new_encoding == charsets[ i ].encoding)
+ charset = charsets[ i ].name;
+ }
+
+ charset_translate = PxTranslateSet(charset_translate, charset);
+}
+
+/****************************************************************************/
+/****************************************************************************/
+
+ void
+gui_mch_prepare(int *argc, char **argv)
+{
+ PtInit(NULL);
+}
+
+ int
+gui_mch_init(void)
+{
+ PtArg_t args[10];
+ int flags = 0, n = 0;
+
+ PhDim_t window_size = {100, 100}; /* Arbitrary values */
+ PhPoint_t pos = {0, 0};
+
+ gui.event_buffer = (PhEvent_t *) alloc(EVENT_BUFFER_SIZE);
+ if (gui.event_buffer == NULL)
+ return FAIL;
+
+ /* Get a translation so we can convert from ISO Latin-1 to UTF */
+ charset_translate = PxTranslateSet(NULL, "latin1");
+
+ /* The +2 is for the 1 pixel dark line on each side */
+ gui.border_offset = gui.border_width = GUI_PH_MARGIN + 2;
+
+ /* Handle close events ourselves */
+ PtSetArg(&args[ n++ ], Pt_ARG_WINDOW_MANAGED_FLAGS, Pt_FALSE, Ph_WM_CLOSE);
+ PtSetArg(&args[ n++ ], Pt_ARG_WINDOW_NOTIFY_FLAGS, Pt_TRUE,
+ Ph_WM_CLOSE | Ph_WM_RESIZE | Ph_WM_FOCUS);
+ PtSetArg(&args[ n++ ], Pt_ARG_DIM, &window_size, 0);
+ gui.vimWindow = PtCreateWidget(PtWindow, NULL, n, args);
+ if (gui.vimWindow == NULL)
+ return FAIL;
+
+ PtAddCallback(gui.vimWindow, Pt_CB_WINDOW, gui_ph_handle_window_cb, NULL);
+ PtAddCallback(gui.vimWindow, Pt_CB_WINDOW_OPENING,
+ gui_ph_handle_window_open, NULL);
+
+ n = 0;
+ PtSetArg(&args[ n++ ], Pt_ARG_ANCHOR_FLAGS, Pt_ANCHOR_ALL, Pt_IS_ANCHORED);
+ PtSetArg(&args[ n++ ], Pt_ARG_DIM, &window_size, 0);
+ PtSetArg(&args[ n++ ], Pt_ARG_POS, &pos, 0);
+
+#ifdef USE_PANEL_GROUP
+ /* Put in a temporary place holder title */
+ PtSetArg(&args[ n++ ], Pt_ARG_PG_PANEL_TITLES, &empty_title, 1);
+
+ gui.vimPanelGroup = PtCreateWidget(PtPanelGroup, gui.vimWindow, n, args);
+ if (gui.vimPanelGroup == NULL)
+ return FAIL;
+
+ PtAddCallback(gui.vimPanelGroup, Pt_CB_PG_PANEL_SWITCHING,
+ gui_ph_handle_pg_change, NULL);
+#else
+ /* Turn off all edge decorations */
+ PtSetArg(&args[ n++ ], Pt_ARG_BASIC_FLAGS, Pt_FALSE, Pt_ALL);
+ PtSetArg(&args[ n++ ], Pt_ARG_BEVEL_WIDTH, 0, 0);
+ PtSetArg(&args[ n++ ], Pt_ARG_MARGIN_WIDTH, 0, 0);
+ PtSetArg(&args[ n++ ], Pt_ARG_MARGIN_HEIGHT, 0, 0);
+ PtSetArg(&args[ n++ ], Pt_ARG_CONTAINER_FLAGS, Pt_TRUE, Pt_AUTO_EXTENT);
+
+ gui.vimContainer = PtCreateWidget(PtPane, gui.vimWindow, n, args);
+ if (gui.vimContainer == NULL)
+ return FAIL;
+
+ PtAddCallback(gui.vimContainer, Pt_CB_RESIZE, gui_ph_pane_resize, NULL);
+#endif
+
+ /* Size for the text area is set in gui_mch_set_text_area_pos */
+ n = 0;
+
+ PtSetArg(&args[ n++ ], Pt_ARG_RAW_DRAW_F, gui_ph_handle_raw_draw, 1);
+ PtSetArg(&args[ n++ ], Pt_ARG_BEVEL_WIDTH, GUI_PH_MARGIN, 0);
+ /*
+ * Using focus render also causes the whole widget to be redrawn
+ * whenever it changes focus, which is very annoying :p
+ */
+ PtSetArg(&args[ n++ ], Pt_ARG_FLAGS, Pt_TRUE,
+ Pt_GETS_FOCUS | Pt_HIGHLIGHTED);
+#ifndef FEAT_MOUSESHAPE
+ PtSetArg(&args[ n++ ], Pt_ARG_CURSOR_TYPE, GUI_PH_MOUSE_TYPE, 0);
+ PtSetArg(&args[ n++ ], Pt_ARG_CURSOR_COLOR, gui_ph_mouse_color, 0);
+#endif
+
+ gui.vimTextArea = PtCreateWidget(PtRaw, Pt_DFLT_PARENT, n, args);
+ if (gui.vimTextArea == NULL)
+ return FAIL;
+
+ /* TODO: use PtAddEventHandlers instead? */
+ /* Not using Ph_EV_BUT_REPEAT because vim wouldn't use it anyway */
+ PtAddEventHandler(gui.vimTextArea,
+ Ph_EV_BUT_PRESS | Ph_EV_BUT_RELEASE | Ph_EV_PTR_MOTION_BUTTON,
+ gui_ph_handle_mouse, NULL);
+ PtAddEventHandler(gui.vimTextArea, Ph_EV_KEY,
+ gui_ph_handle_keyboard, NULL);
+ PtAddCallback(gui.vimTextArea, Pt_CB_GOT_FOCUS,
+ gui_ph_handle_focus, NULL);
+ PtAddCallback(gui.vimTextArea, Pt_CB_LOST_FOCUS,
+ gui_ph_handle_focus, NULL);
+
+ /*
+ * Now that the text area widget has been created, set up the colours,
+ * which wil call PtSetResource from gui_mch_new_colors
+ */
+
+ /*
+ * Create the two timers, not as accurate as using the kernel timer
+ * functions, but good enough
+ */
+ gui_ph_timer_cursor = PtCreateWidget(PtTimer, gui.vimWindow, 0, NULL);
+ if (gui_ph_timer_cursor == NULL)
+ return FAIL;
+
+ gui_ph_timer_timeout = PtCreateWidget(PtTimer, gui.vimWindow, 0, NULL);
+ if (gui_ph_timer_timeout == NULL)
+ return FAIL;
+
+ PtAddCallback(gui_ph_timer_cursor, Pt_CB_TIMER_ACTIVATE,
+ gui_ph_handle_timer_cursor, NULL);
+ PtAddCallback(gui_ph_timer_timeout, Pt_CB_TIMER_ACTIVATE,
+ gui_ph_handle_timer_timeout, NULL);
+
+#ifdef FEAT_MENU
+ n = 0;
+ PtSetArg(&args[ n++ ], Pt_ARG_WIDTH, window_size.w, 0);
+ PtSetArg(&args[ n++ ], Pt_ARG_ANCHOR_FLAGS, Pt_ANCHOR_LEFT_RIGHT,
+ Pt_IS_ANCHORED);
+ gui.vimToolBarGroup = PtCreateWidget(PtToolbarGroup, gui.vimWindow,
+ n, args);
+ if (gui.vimToolBarGroup == NULL)
+ return FAIL;
+
+ PtAddCallback(gui.vimToolBarGroup, Pt_CB_RESIZE,
+ gui_ph_handle_menu_resize, NULL);
+
+ n = 0;
+ flags = 0;
+ PtSetArg(&args[ n++ ], Pt_ARG_WIDTH, window_size.w, 0);
+ if (! vim_strchr(p_go, GO_MENUS))
+ {
+ flags |= Pt_DELAY_REALIZE;
+ PtSetArg(&args[ n++ ], Pt_ARG_FLAGS, Pt_TRUE, flags);
+ }
+ gui.vimMenuBar = PtCreateWidget(PtMenuBar, gui.vimToolBarGroup, n, args);
+ if (gui.vimMenuBar == NULL)
+ return FAIL;
+
+# ifdef FEAT_TOOLBAR
+ n = 0;
+
+ PtSetArg(&args[ n++ ], Pt_ARG_ANCHOR_FLAGS,
+ Pt_ANCHOR_LEFT_RIGHT |Pt_TOP_ANCHORED_TOP, Pt_IS_ANCHORED);
+ PtSetArg(&args[ n++ ], Pt_ARG_RESIZE_FLAGS, Pt_TRUE,
+ Pt_RESIZE_Y_AS_REQUIRED);
+ PtSetArg(&args[ n++ ], Pt_ARG_WIDTH, window_size.w, 0);
+
+ flags = Pt_GETS_FOCUS;
+ if (! vim_strchr(p_go, GO_TOOLBAR))
+ flags |= Pt_DELAY_REALIZE;
+
+ PtSetArg(&args[ n++ ], Pt_ARG_FLAGS, Pt_DELAY_REALIZE, flags);
+
+ gui.vimToolBar = PtCreateWidget(PtToolbar, gui.vimToolBarGroup, n, args);
+ if (gui.vimToolBar == NULL)
+ return FAIL;
+
+ /*
+ * Size for the toolbar is fetched in gui_mch_show_toolbar, after
+ * the buttons have been added and the toolbar has resized it's height
+ * for the buttons to fit
+ */
+# endif
+
+#endif
+
+ return OK;
+}
+
+ int
+gui_mch_init_check(void)
+{
+ return (is_photon_available == TRUE) ? OK : FAIL;
+}
+
+ int
+gui_mch_open(void)
+{
+ gui.norm_pixel = Pg_BLACK;
+ gui.back_pixel = Pg_WHITE;
+
+ set_normal_colors();
+
+ gui_check_colors();
+ gui.def_norm_pixel = gui.norm_pixel;
+ gui.def_back_pixel = gui.back_pixel;
+
+ highlight_gui_started();
+
+ if (gui_win_x != -1 && gui_win_y != -1)
+ gui_mch_set_winpos(gui_win_x, gui_win_y);
+
+ return (PtRealizeWidget(gui.vimWindow) == 0) ? OK : FAIL;
+}
+
+ void
+gui_mch_exit(int rc)
+{
+ PtDestroyWidget(gui.vimWindow);
+
+ PxTranslateSet(charset_translate, NULL);
+
+ vim_free(gui.event_buffer);
+
+#ifdef USE_PANEL_GROUPS
+ vim_free(panel_titles);
+#endif
+}
+
+/****************************************************************************/
+/* events */
+
+/* When no events are available, photon will call this function, working is
+ * set to FALSE, and the gui_mch_update loop will exit. */
+ static int
+exit_gui_mch_update(void *data)
+{
+ *(int *)data = FALSE;
+ return Pt_END;
+}
+
+ void
+gui_mch_update(void)
+{
+ int working = TRUE;
+
+ PtAppAddWorkProc(NULL, exit_gui_mch_update, &working);
+ while ((working == TRUE) && !vim_is_input_buf_full())
+ {
+ PtProcessEvent();
+ }
+}
+
+ int
+gui_mch_wait_for_chars(int wtime)
+{
+ is_timeout = FALSE;
+
+ if (wtime >= 0)
+ PtSetResource(gui_ph_timer_timeout, Pt_ARG_TIMER_INITIAL,
+ wtime == 0 ? 1 : wtime, 0);
+
+ while (1)
+ {
+ PtProcessEvent();
+ if (input_available())
+ {
+ PtSetResource(gui_ph_timer_timeout, Pt_ARG_TIMER_INITIAL, 0, 0);
+ return OK;
+ }
+ else if (is_timeout == TRUE)
+ return FAIL;
+ }
+}
+
+#if defined(FEAT_BROWSE) || defined(PROTO)
+/*
+ * Put up a file requester.
+ * Returns the selected name in allocated memory, or NULL for Cancel.
+ * saving, select file to write
+ * title title for the window
+ * default_name default name (well duh!)
+ * ext not used (extension added)
+ * initdir initial directory, NULL for current dir
+ * filter not used (file name filter)
+ */
+ char_u *
+gui_mch_browse(
+ int saving,
+ char_u *title,
+ char_u *default_name,
+ char_u *ext,
+ char_u *initdir,
+ char_u *filter)
+{
+ PtFileSelectionInfo_t file;
+ int flags;
+ char_u *default_path;
+ char_u *open_text = NULL;
+
+ flags = 0;
+ memset(&file, 0, sizeof(file));
+
+ default_path = alloc(MAXPATHL + 1 + NAME_MAX + 1);
+ if (default_path != NULL)
+ {
+ if (saving == TRUE)
+ {
+ /* Don't need Pt_FSR_CONFIRM_EXISTING, vim will ask anyway */
+ flags |= Pt_FSR_NO_FCHECK;
+ open_text = "&Save";
+ }
+
+ /* combine the directory and filename into a single path */
+ if (initdir == NULL || *initdir == NUL)
+ {
+ mch_dirname(default_path, MAXPATHL);
+ initdir = default_path;
+ }
+ else
+ {
+ STRCPY(default_path, initdir);
+ initdir = default_path;
+ }
+
+ if (default_name != NULL)
+ {
+ if (default_path[ STRLEN(default_path) - 1 ] != '/')
+ STRCAT(default_path, "/");
+
+ STRCAT(default_path, default_name);
+ }
+
+ /* TODO: add a filter? */
+ PtFileSelection(
+ gui.vimWindow,
+ NULL,
+ title,
+ default_path,
+ NULL,
+ open_text,
+ NULL,
+ NULL,
+ &file,
+ flags);
+
+ vim_free(default_path);
+
+ if (file.ret == Pt_FSDIALOG_BTN1)
+ return vim_strsave(file.path);
+ }
+ return NULL;
+}
+#endif
+
+#if defined(FEAT_GUI_DIALOG) || defined(PROTO)
+static PtWidget_t *gui_ph_dialog_text = NULL;
+
+ static int
+gui_ph_dialog_close(int button, void *data)
+{
+ PtModalCtrl_t *modal_ctrl = data;
+ char_u *dialog_text, *vim_text;
+
+ if (gui_ph_dialog_text != NULL)
+ {
+ PtGetResource(gui_ph_dialog_text, Pt_ARG_TEXT_STRING, &dialog_text, 0);
+ PtGetResource(gui_ph_dialog_text, Pt_ARG_POINTER, &vim_text, 0);
+ STRNCPY(vim_text, dialog_text, IOSIZE - 1);
+ }
+
+ PtModalUnblock(modal_ctrl, (void *) button);
+
+ return Pt_TRUE;
+}
+
+ static int
+gui_ph_dialog_text_enter(PtWidget_t *widget, void *data, PtCallbackInfo_t *info)
+{
+ if (info->reason_subtype == Pt_EDIT_ACTIVATE)
+ gui_ph_dialog_close(1, data);
+ return Pt_CONTINUE;
+}
+
+ static int
+gui_ph_dialog_esc(PtWidget_t *widget, void *data, PtCallbackInfo_t *info)
+{
+ PhKeyEvent_t *key;
+
+ key = PhGetData(info->event);
+ if ((key->key_flags & Pk_KF_Cap_Valid) && (key->key_cap == Pk_Escape))
+ {
+ gui_ph_dialog_close(0, data);
+ return Pt_CONSUME;
+ }
+ return Pt_PROCESS;
+}
+
+ int
+gui_mch_dialog(
+ int type,
+ char_u *title,
+ char_u *message,
+ char_u *buttons,
+ int default_button,
+ char_u *textfield,
+ int ex_cmd)
+{
+ char_u *str;
+ char_u **button_array;
+ char_u *buttons_copy;
+
+ int button_count;
+ int i, len;
+ int dialog_result = -1;
+
+ /* FIXME: the vertical option in guioptions is blatantly ignored */
+ /* FIXME: so is the type */
+
+ button_count = len = i = 0;
+
+ if (buttons == NULL || *buttons == NUL)
+ return -1;
+
+ /* There is one less separator than buttons, so bump up the button count */
+ button_count = 1;
+
+ /* Count string length and number of separators */
+ for (str = buttons; *str; str++)
+ {
+ len++;
+ if (*str == DLG_BUTTON_SEP)
+ button_count++;
+ }
+
+ if (title == NULL)
+ title = "Vim";
+
+ buttons_copy = alloc(len + 1);
+ button_array = (char_u **) alloc(button_count * sizeof(char_u *));
+ if (buttons_copy != NULL && button_array != NULL)
+ {
+ STRCPY(buttons_copy, buttons);
+
+ /*
+ * Convert DLG_BUTTON_SEP into NUL's and fill in
+ * button_array with the pointer to each NUL terminated string
+ */
+ str = buttons_copy;
+ for (i = 0; i < button_count; i++)
+ {
+ button_array[ i ] = str;
+ for (; *str; str++)
+ {
+ if (*str == DLG_BUTTON_SEP)
+ {
+ *str++ = NUL;
+ break;
+ }
+ }
+ }
+#ifndef FEAT_GUI_TEXTDIALOG
+ dialog_result = PtAlert(
+ gui.vimWindow, NULL,
+ title,
+ NULL,
+ message, NULL,
+ button_count, (const char **) button_array, NULL,
+ default_button, 0, Pt_MODAL);
+#else
+ /* Writing the dialog ourselves lets us add extra features, like
+ * trapping the escape key and returning 0 to vim */
+ {
+ int n;
+ PtArg_t args[5];
+ PtWidget_t *dialog, *pane;
+ PtModalCtrl_t modal_ctrl;
+ PtDialogInfo_t di;
+
+ memset(&di, 0, sizeof(di));
+ memset(&modal_ctrl, 0, sizeof(modal_ctrl));
+
+ n = 0;
+ PtSetArg(&args[n++], Pt_ARG_GROUP_ROWS_COLS, 0, 0);
+ PtSetArg(&args[n++], Pt_ARG_WIDTH, 350, 0);
+ PtSetArg(&args[n++], Pt_ARG_GROUP_ORIENTATION,
+ Pt_GROUP_VERTICAL, 0);
+ PtSetArg(&args[n++], Pt_ARG_GROUP_FLAGS,
+ Pt_TRUE, Pt_GROUP_NO_KEYS | Pt_GROUP_STRETCH_HORIZONTAL);
+ PtSetArg(&args[n++], Pt_ARG_CONTAINER_FLAGS, Pt_FALSE, Pt_TRUE);
+ pane = PtCreateWidget(PtGroup, NULL, n, args);
+
+ n = 0;
+ PtSetArg(&args[n++], Pt_ARG_TEXT_STRING, message, 0);
+ PtCreateWidget(PtLabel, pane, n, args);
+
+ if (textfield != NULL)
+ {
+ n = 0;
+ PtSetArg(&args[n++], Pt_ARG_MAX_LENGTH, IOSIZE - 1, 0);
+ PtSetArg(&args[n++], Pt_ARG_TEXT_STRING, textfield, 0);
+ PtSetArg(&args[n++], Pt_ARG_POINTER, textfield, 0);
+ gui_ph_dialog_text = PtCreateWidget(PtText, pane, n, args);
+ PtAddCallback(gui_ph_dialog_text, Pt_CB_ACTIVATE,
+ gui_ph_dialog_text_enter, &modal_ctrl);
+ }
+
+ di.parent = gui.vimWindow;
+ di.pane = pane;
+ di.title = title;
+ di.buttons = (const char **) button_array;
+ di.nbtns = button_count;
+ di.def_btn = default_button;
+ /* This is just to give the dialog the close button.
+ * We check for the Escape key ourselves and return 0 */
+ di.esc_btn = button_count;
+ di.callback = gui_ph_dialog_close;
+ di.data = &modal_ctrl;
+
+ dialog = PtCreateDialog(&di);
+ PtAddFilterCallback(dialog, Ph_EV_KEY,
+ gui_ph_dialog_esc, &modal_ctrl);
+
+ if (gui_ph_dialog_text != NULL)
+ PtGiveFocus(gui_ph_dialog_text, NULL);
+
+ /* Open dialog, block the vim window and wait for the dialog to close */
+ PtRealizeWidget(dialog);
+ PtMakeModal(dialog, Ph_CURSOR_NOINPUT, Ph_CURSOR_DEFAULT_COLOR);
+ dialog_result = (int) PtModalBlock(&modal_ctrl, 0);
+
+ PtDestroyWidget(dialog);
+ gui_ph_dialog_text = NULL;
+ }
+#endif
+ }
+
+ vim_free(button_array);
+ vim_free(buttons_copy);
+
+ return dialog_result;
+}
+#endif
+/****************************************************************************/
+/* window size/position/state */
+
+ int
+gui_mch_get_winpos(int *x, int *y)
+{
+ PhPoint_t *pos;
+
+ pos = PtWidgetPos(gui.vimWindow, NULL);
+
+ *x = pos->x;
+ *y = pos->y;
+
+ return OK;
+}
+
+ void
+gui_mch_set_winpos(int x, int y)
+{
+ PhPoint_t pos = { x, y };
+
+ PtSetResource(gui.vimWindow, Pt_ARG_POS, &pos, 0);
+}
+
+ void
+gui_mch_set_shellsize(int width, int height,
+ int min_width, int min_height, int base_width, int base_height,
+ int direction)
+{
+ PhDim_t window_size = { width, height };
+ PhDim_t min_size = { min_width, min_height };
+
+#ifdef USE_PANEL_GROUP
+ window_size.w += pg_margin_left + pg_margin_right;
+ window_size.h += pg_margin_top + pg_margin_bottom;
+#endif
+
+ PtSetResource(gui.vimWindow, Pt_ARG_MINIMUM_DIM, &min_size, 0);
+ PtSetResource(gui.vimWindow, Pt_ARG_DIM, &window_size, 0);
+
+ if (! PtWidgetIsRealized(gui.vimWindow))
+ gui_ph_resize_container();
+}
+
+/*
+ * Return the amount of screen space that hasn't been allocated (such as
+ * by the shelf).
+ */
+ void
+gui_mch_get_screen_dimensions(int *screen_w, int *screen_h)
+{
+ PhRect_t console;
+
+ PhWindowQueryVisible(Ph_QUERY_WORKSPACE, 0,
+ PhInputGroup(NULL), &console);
+
+ *screen_w = console.lr.x - console.ul.x + 1;
+ *screen_h = console.lr.y - console.ul.y + 1;
+}
+
+ void
+gui_mch_iconify(void)
+{
+ PhWindowEvent_t event;
+
+ memset(&event, 0, sizeof (event));
+ event.event_f = Ph_WM_HIDE;
+ event.event_state = Ph_WM_EVSTATE_HIDE;
+ event.rid = PtWidgetRid(gui.vimWindow);
+ PtForwardWindowEvent(&event);
+}
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * Bring the Vim window to the foreground.
+ */
+ void
+gui_mch_set_foreground(void)
+{
+ PhWindowEvent_t event;
+
+ memset(&event, 0, sizeof (event));
+ event.event_f = Ph_WM_TOFRONT;
+ event.event_state = Ph_WM_EVSTATE_FFRONT;
+ event.rid = PtWidgetRid(gui.vimWindow);
+ PtForwardWindowEvent(&event);
+}
+#endif
+
+ void
+gui_mch_settitle(char_u *title, char_u *icon)
+{
+#ifdef USE_PANEL_GROUP
+ gui_ph_pg_set_buffer_num(curwin->w_buffer->b_fnum);
+#endif
+ PtSetResource(gui.vimWindow, Pt_ARG_WINDOW_TITLE, title, 0);
+ /* Not sure what to do with the icon text, set balloon text somehow? */
+}
+
+/****************************************************************************/
+/* Scrollbar */
+
+ void
+gui_mch_set_scrollbar_thumb(scrollbar_T *sb, int val, int size, int max)
+{
+ int n = 0;
+ PtArg_t args[3];
+
+ PtSetArg(&args[ n++ ], Pt_ARG_MAXIMUM, max, 0);
+ PtSetArg(&args[ n++ ], Pt_ARG_SLIDER_SIZE, size, 0);
+ PtSetArg(&args[ n++ ], Pt_ARG_GAUGE_VALUE, val, 0);
+ PtSetResources(sb->id, n, args);
+}
+
+ void
+gui_mch_set_scrollbar_pos(scrollbar_T *sb, int x, int y, int w, int h)
+{
+ PhArea_t area = {{ x, y }, { w, h }};
+
+ PtSetResource(sb->id, Pt_ARG_AREA, &area, 0);
+}
+
+ void
+gui_mch_create_scrollbar(scrollbar_T *sb, int orient)
+{
+ int n = 0;
+/* int anchor_flags = 0;*/
+ PtArg_t args[4];
+
+ /*
+ * Stop the scrollbar from being realized when the parent
+ * is realized, so it can be explicitly realized by vim.
+ *
+ * Also, don't let the scrollbar get focus
+ */
+ PtSetArg(&args[ n++ ], Pt_ARG_FLAGS, Pt_DELAY_REALIZE,
+ Pt_DELAY_REALIZE | Pt_GETS_FOCUS);
+ PtSetArg(&args[ n++ ], Pt_ARG_SCROLLBAR_FLAGS, Pt_SCROLLBAR_SHOW_ARROWS, 0);
+#if 0
+ /* Don't need this anchoring for the scrollbars */
+ if (orient == SBAR_HORIZ)
+ {
+ anchor_flags = Pt_BOTTOM_ANCHORED_BOTTOM |
+ Pt_LEFT_ANCHORED_LEFT | Pt_RIGHT_ANCHORED_RIGHT;
+ }
+ else
+ {
+ anchor_flags = Pt_BOTTOM_ANCHORED_BOTTOM | Pt_TOP_ANCHORED_TOP;
+ if (sb->wp != NULL)
+ {
+ if (sb == &sb->wp->w_scrollbars[ SBAR_LEFT ])
+ anchor_flags |= Pt_LEFT_ANCHORED_LEFT;
+ else
+ anchor_flags |= Pt_RIGHT_ANCHORED_RIGHT;
+ }
+ }
+ PtSetArg(&args[ n++ ], Pt_ARG_ANCHOR_FLAGS, anchor_flags, Pt_IS_ANCHORED);
+#endif
+ PtSetArg(&args[ n++ ], Pt_ARG_ORIENTATION,
+ (orient == SBAR_HORIZ) ? Pt_HORIZONTAL : Pt_VERTICAL, 0);
+#ifdef USE_PANEL_GROUP
+ sb->id = PtCreateWidget(PtScrollbar, gui.vimPanelGroup, n, args);
+#else
+ sb->id = PtCreateWidget(PtScrollbar, gui.vimContainer, n, args);
+#endif
+
+ PtAddCallback(sb->id, Pt_CB_SCROLLBAR_MOVE, gui_ph_handle_scrollbar, sb);
+}
+
+ void
+gui_mch_enable_scrollbar(scrollbar_T *sb, int flag)
+{
+ if (flag != 0)
+ PtRealizeWidget(sb->id);
+ else
+ PtUnrealizeWidget(sb->id);
+}
+
+ void
+gui_mch_destroy_scrollbar(scrollbar_T *sb)
+{
+ PtDestroyWidget(sb->id);
+ sb->id = NULL;
+}
+
+/****************************************************************************/
+/* Mouse functions */
+
+#if defined(FEAT_MOUSESHAPE) || defined(PROTO)
+/* The last set mouse pointer shape is remembered, to be used when it goes
+ * from hidden to not hidden. */
+static int last_shape = 0;
+
+/* Table for shape IDs. Keep in sync with the mshape_names[] table in
+ * misc2.c! */
+static int mshape_ids[] =
+{
+ Ph_CURSOR_POINTER, /* arrow */
+ Ph_CURSOR_NONE, /* blank */
+ Ph_CURSOR_INSERT, /* beam */
+ Ph_CURSOR_DRAG_VERTICAL, /* updown */
+ Ph_CURSOR_DRAG_VERTICAL, /* udsizing */
+ Ph_CURSOR_DRAG_HORIZONTAL, /* leftright */
+ Ph_CURSOR_DRAG_HORIZONTAL, /* lrsizing */
+ Ph_CURSOR_WAIT, /* busy */
+ Ph_CURSOR_DONT, /* no */
+ Ph_CURSOR_CROSSHAIR, /* crosshair */
+ Ph_CURSOR_FINGER, /* hand1 */
+ Ph_CURSOR_FINGER, /* hand2 */
+ Ph_CURSOR_FINGER, /* pencil */
+ Ph_CURSOR_QUESTION_POINT, /* question */
+ Ph_CURSOR_POINTER, /* right-arrow */
+ Ph_CURSOR_POINTER, /* up-arrow */
+ Ph_CURSOR_POINTER /* last one */
+};
+
+ void
+mch_set_mouse_shape(int shape)
+{
+ int id;
+
+ if (!gui.in_use)
+ return;
+
+ if (shape == MSHAPE_HIDE || gui.pointer_hidden)
+ PtSetResource(gui.vimTextArea, Pt_ARG_CURSOR_TYPE, Ph_CURSOR_NONE,
+ 0);
+ else
+ {
+ if (shape >= MSHAPE_NUMBERED)
+ id = Ph_CURSOR_POINTER;
+ else
+ id = mshape_ids[shape];
+
+ PtSetResource(gui.vimTextArea, Pt_ARG_CURSOR_TYPE, id, 0);
+ }
+ if (shape != MSHAPE_HIDE)
+ last_shape = shape;
+}
+#endif
+
+ void
+gui_mch_mousehide(int hide)
+{
+ if (gui.pointer_hidden != hide)
+ {
+ gui.pointer_hidden = hide;
+#ifdef FEAT_MOUSESHAPE
+ if (hide)
+ PtSetResource(gui.vimTextArea, Pt_ARG_CURSOR_TYPE,
+ Ph_CURSOR_NONE, 0);
+ else
+ mch_set_mouse_shape(last_shape);
+#else
+ PtSetResource(gui.vimTextArea, Pt_ARG_CURSOR_TYPE,
+ (hide == MOUSE_SHOW) ? GUI_PH_MOUSE_TYPE : Ph_CURSOR_NONE,
+ 0);
+#endif
+ }
+}
+
+ void
+gui_mch_getmouse(int *x, int *y)
+{
+ PhCursorInfo_t info;
+ short ix, iy;
+
+ /* FIXME: does this return the correct position,
+ * with respect to the border? */
+ PhQueryCursor(PhInputGroup(NULL), &info);
+ PtGetAbsPosition(gui.vimTextArea , &ix, &iy);
+
+ *x = info.pos.x - ix;
+ *y = info.pos.y - iy;
+}
+
+ void
+gui_mch_setmouse(int x, int y)
+{
+ short abs_x, abs_y;
+
+ PtGetAbsPosition(gui.vimTextArea, &abs_x, &abs_y);
+ /* Add the border offset? */
+ PhMoveCursorAbs(PhInputGroup(NULL), abs_x + x, abs_y + y);
+}
+
+/****************************************************************************/
+/* Colours */
+
+/*
+ * Return the RGB value of a pixel as a long.
+ */
+ guicolor_T
+gui_mch_get_rgb(guicolor_T pixel)
+{
+ return (guicolor_T)(PgRGB(PgRedValue(pixel),
+ PgGreenValue(pixel), PgBlueValue(pixel)));
+}
+
+ void
+gui_mch_new_colors(void)
+{
+#if 0 /* Don't bother changing the cursor colour */
+ short color_diff;
+
+ /*
+ * If there isn't enough difference between the background colour and
+ * the mouse pointer colour then change the mouse pointer colour
+ */
+ color_diff = gui_get_lightness(gui_ph_mouse_color)
+ - gui_get_lightness(gui.back_pixel);
+
+ if (abs(color_diff) < 64)
+ {
+ short r, g, b;
+ /* not a great algorithm... */
+ r = PgRedValue(gui_ph_mouse_color) ^ 255;
+ g = PgGreenValue(gui_ph_mouse_color) ^ 255;
+ b = PgBlueValue(gui_ph_mouse_color) ^ 255;
+
+#ifndef FEAT_MOUSESHAPE
+ gui_ph_mouse_color = PgRGB(r, g, b);
+ PtSetResource(gui.vimTextArea, Pt_ARG_CURSOR_COLOR,
+ gui_ph_mouse_color, 0);
+#endif
+ }
+#endif
+
+ PtSetResource(gui.vimTextArea, Pt_ARG_FILL_COLOR, gui.back_pixel, 0);
+}
+
+/*
+ * This should be split out into a separate file,
+ * every port does basically the same thing.
+ *
+ * This is the gui_w32.c version (i think..)
+ * Return INVALCOLOR when failed.
+ */
+
+ guicolor_T
+gui_mch_get_color(char_u *name)
+{
+ 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);
+}
+
+ void
+gui_mch_set_fg_color(guicolor_T color)
+{
+ PgSetTextColor(color);
+}
+
+ void
+gui_mch_set_bg_color(guicolor_T color)
+{
+ PgSetFillColor(color);
+}
+
+ void
+gui_mch_set_sp_color(guicolor_T color)
+{
+}
+
+ void
+gui_mch_invert_rectangle(int row, int col, int nr, int nc)
+{
+ PhRect_t rect;
+
+ rect.ul.x = FILL_X(col);
+ rect.ul.y = FILL_Y(row);
+
+ /* FIXME: This has an off by one pixel problem */
+ rect.lr.x = rect.ul.x + nc * gui.char_width;
+ rect.lr.y = rect.ul.y + nr * gui.char_height;
+ if (nc > 0)
+ rect.lr.x -= 1;
+ if (nr > 0)
+ rect.lr.y -= 1;
+
+ DRAW_START;
+ PgSetDrawMode(Pg_DrawModeDSTINVERT);
+ PgDrawRect(&rect, Pg_DRAW_FILL);
+ PgSetDrawMode(Pg_DrawModeSRCCOPY);
+ DRAW_END;
+}
+
+ void
+gui_mch_clear_block(int row1, int col1, int row2, int col2)
+{
+ PhRect_t block = {
+ { FILL_X(col1), FILL_Y(row1) },
+ { FILL_X(col2 + 1) - 1, FILL_Y(row2 + 1) - 1}
+ };
+
+ DRAW_START;
+ gui_mch_set_bg_color(gui.back_pixel);
+ PgDrawRect(&block, Pg_DRAW_FILL);
+ DRAW_END;
+}
+
+ void
+gui_mch_clear_all(void)
+{
+ PhRect_t text_rect = {
+ { gui.border_width, gui.border_width },
+ { Columns * gui.char_width + gui.border_width - 1 ,
+ Rows * gui.char_height + gui.border_width - 1 }
+ };
+
+ if (is_ignore_draw == TRUE)
+ return;
+
+ DRAW_START;
+ gui_mch_set_bg_color(gui.back_pixel);
+ PgDrawRect(&text_rect, Pg_DRAW_FILL);
+ DRAW_END;
+}
+
+ void
+gui_mch_delete_lines(int row, int num_lines)
+{
+ PhRect_t rect;
+ PhPoint_t delta;
+
+ rect.ul.x = FILL_X(gui.scroll_region_left);
+ rect.ul.y = FILL_Y(row + num_lines);
+
+ rect.lr.x = FILL_X(gui.scroll_region_right + 1) - 1;
+ rect.lr.y = FILL_Y(gui.scroll_region_bot + 1) - 1;
+
+ PtWidgetOffset(gui.vimTextArea, &gui_ph_raw_offset);
+ PhTranslatePoint(&gui_ph_raw_offset, PtWidgetPos(gui.vimTextArea, NULL));
+ PhTranslateRect(&rect, &gui_ph_raw_offset);
+
+ delta.x = 0;
+ delta.y = -num_lines * gui.char_height;
+
+ PgFlush();
+
+ PhBlit(PtWidgetRid(PtFindDisjoint(gui.vimTextArea)), &rect, &delta);
+
+ gui_clear_block(
+ gui.scroll_region_bot - num_lines + 1,
+ gui.scroll_region_left,
+ gui.scroll_region_bot,
+ gui.scroll_region_right);
+}
+
+ void
+gui_mch_insert_lines(int row, int num_lines)
+{
+ PhRect_t rect;
+ PhPoint_t delta;
+
+ rect.ul.x = FILL_X(gui.scroll_region_left);
+ rect.ul.y = FILL_Y(row);
+
+ rect.lr.x = FILL_X(gui.scroll_region_right + 1) - 1;
+ rect.lr.y = FILL_Y(gui.scroll_region_bot - num_lines + 1) - 1;
+
+ PtWidgetOffset(gui.vimTextArea, &gui_ph_raw_offset);
+ PhTranslatePoint(&gui_ph_raw_offset, PtWidgetPos(gui.vimTextArea, NULL));
+ PhTranslateRect(&rect, &gui_ph_raw_offset);
+
+ delta.x = 0;
+ delta.y = num_lines * gui.char_height;
+
+ PgFlush();
+
+ PhBlit(PtWidgetRid(PtFindDisjoint(gui.vimTextArea)) , &rect, &delta);
+
+ gui_clear_block(row, gui.scroll_region_left,
+ row + num_lines - 1, gui.scroll_region_right);
+}
+
+ void
+gui_mch_draw_string(int row, int col, char_u *s, int len, int flags)
+{
+ static char *utf8_buffer = NULL;
+ static int utf8_len = 0;
+
+ PhPoint_t pos = { TEXT_X(col), TEXT_Y(row) };
+ PhRect_t rect;
+
+ if (is_ignore_draw == TRUE)
+ return;
+
+ DRAW_START;
+
+ if (!(flags & DRAW_TRANSP))
+ {
+ PgDrawIRect(
+ FILL_X(col), FILL_Y(row),
+ FILL_X(col + len) - 1, FILL_Y(row + 1) - 1,
+ Pg_DRAW_FILL);
+ }
+
+ if (flags & DRAW_UNDERL)
+ PgSetUnderline(gui.norm_pixel, Pg_TRANSPARENT, 0);
+
+ if (charset_translate != NULL && enc_utf8 == 0)
+ {
+ int src_taken, dst_made;
+
+ /* Use a static buffer to avoid large amounts of de/allocations */
+ if (utf8_len < len)
+ {
+ utf8_buffer = realloc(utf8_buffer, len * MB_LEN_MAX);
+ utf8_len = len;
+ }
+
+ PxTranslateToUTF(
+ charset_translate,
+ s,
+ len,
+ &src_taken,
+ utf8_buffer,
+ utf8_len,
+ &dst_made);
+ s = utf8_buffer;
+ len = dst_made;
+ }
+
+ PgDrawText(s, len, &pos, 0);
+
+ if (flags & DRAW_BOLD)
+ {
+ /* FIXME: try and only calculate these values once... */
+ rect.ul.x = FILL_X(col) + 1;
+ rect.ul.y = FILL_Y(row);
+ rect.lr.x = FILL_X(col + len) - 1;
+ rect.lr.y = FILL_Y(row + 1) - 1;
+ /* PgSetUserClip(NULL) causes the scrollbar to not redraw... */
+#if 0
+ pos.x++;
+
+ PgSetUserClip(&rect);
+ PgDrawText(s, len, &pos, 0);
+ PgSetUserClip(NULL);
+#else
+ rect.lr.y -= (p_linespace + 1) / 2;
+ /* XXX: DrawTextArea doesn't work with phditto */
+ PgDrawTextArea(s, len, &rect, Pg_TEXT_BOTTOM);
+#endif
+ }
+
+ if (flags & DRAW_UNDERL)
+ PgSetUnderline(Pg_TRANSPARENT, Pg_TRANSPARENT, 0);
+
+ DRAW_END;
+}
+
+/****************************************************************************/
+/* Cursor */
+
+ void
+gui_mch_draw_hollow_cursor(guicolor_T color)
+{
+ PhRect_t r;
+
+ /* FIXME: Double width characters */
+
+ r.ul.x = FILL_X(gui.col);
+ r.ul.y = FILL_Y(gui.row);
+ r.lr.x = r.ul.x + gui.char_width - 1;
+ r.lr.y = r.ul.y + gui.char_height - 1;
+
+ DRAW_START;
+ PgSetStrokeColor(color);
+ PgDrawRect(&r, Pg_DRAW_STROKE);
+ DRAW_END;
+}
+
+ void
+gui_mch_draw_part_cursor(int w, int h, guicolor_T color)
+{
+ PhRect_t r;
+
+ r.ul.x = FILL_X(gui.col);
+ r.ul.y = FILL_Y(gui.row) + gui.char_height - h;
+ r.lr.x = r.ul.x + w - 1;
+ r.lr.y = r.ul.y + h - 1;
+
+ DRAW_START;
+ gui_mch_set_bg_color(color);
+ PgDrawRect(&r, Pg_DRAW_FILL);
+ DRAW_END;
+}
+
+ int
+gui_mch_is_blinking(void)
+{
+ return blink_state != BLINK_NONE;
+}
+
+ int
+gui_mch_is_blink_off(void)
+{
+ return blink_state == BLINK_OFF;
+}
+
+ void
+gui_mch_set_blinking(long wait, long on, long off)
+{
+ blink_waittime = wait;
+ blink_ontime = on;
+ blink_offtime = off;
+}
+
+ void
+gui_mch_start_blink(void)
+{
+ /* Only turn on the timer on if none of the times are zero */
+ if (blink_waittime && blink_ontime && blink_offtime && gui.in_focus)
+ {
+ PtSetResource(gui_ph_timer_cursor, Pt_ARG_TIMER_INITIAL,
+ blink_waittime, 0);
+ blink_state = BLINK_ON;
+ gui_update_cursor(TRUE, FALSE);
+ }
+}
+
+ void
+gui_mch_stop_blink(int may_call_gui_update_cursor)
+{
+ PtSetResource(gui_ph_timer_cursor, Pt_ARG_TIMER_INITIAL, 0, 0);
+
+ if (blink_state == BLINK_OFF && may_call_gui_update_cursor)
+ gui_update_cursor(TRUE, FALSE);
+
+ blink_state = BLINK_NONE;
+}
+
+/****************************************************************************/
+/* miscellaneous functions */
+
+ void
+gui_mch_beep(void)
+{
+ PtBeep();
+}
+
+ void
+gui_mch_flash(int msec)
+{
+ PgSetFillXORColor(Pg_BLACK, Pg_WHITE);
+ PgSetDrawMode(Pg_DRAWMODE_XOR);
+ gui_mch_clear_all();
+ gui_mch_flush();
+
+ ui_delay((long) msec, TRUE);
+
+ gui_mch_clear_all();
+ PgSetDrawMode(Pg_DRAWMODE_OPAQUE);
+ gui_mch_flush();
+}
+
+ void
+gui_mch_flush(void)
+{
+ PgFlush();
+}
+
+ void
+gui_mch_set_text_area_pos(int x, int y, int w, int h)
+{
+ PhArea_t area = {{x, y}, {w, h}};
+
+ PtSetResource(gui.vimTextArea, Pt_ARG_AREA, &area, 0);
+}
+
+ int
+gui_mch_haskey(char_u *name)
+{
+ int i;
+
+ for (i = 0; special_keys[i].key_sym != 0; i++)
+ if (name[0] == special_keys[i].vim_code0 &&
+ name[1] == special_keys[i].vim_code1)
+ return OK;
+ return FAIL;
+}
+
+/****************************************************************************/
+/* Menu */
+
+#ifdef FEAT_TOOLBAR
+#include "toolbar.phi"
+
+static PhImage_t *gui_ph_toolbar_images[] = {
+ &tb_new_phi,
+ &tb_open_phi,
+ &tb_save_phi,
+ &tb_undo_phi,
+ &tb_redo_phi,
+ &tb_cut_phi,
+ &tb_copy_phi,
+ &tb_paste_phi,
+ &tb_print_phi,
+ &tb_help_phi,
+ &tb_find_phi,
+ &tb_save_all_phi,
+ &tb_save_session_phi,
+ &tb_new_session_phi,
+ &tb_load_session_phi,
+ &tb_macro_phi,
+ &tb_replace_phi,
+ &tb_close_phi,
+ &tb_maximize_phi,
+ &tb_minimize_phi,
+ &tb_split_phi,
+ &tb_shell_phi,
+ &tb_find_prev_phi,
+ &tb_find_next_phi,
+ &tb_find_help_phi,
+ &tb_make_phi,
+ &tb_jump_phi,
+ &tb_ctags_phi,
+ &tb_vsplit_phi,
+ &tb_maxwidth_phi,
+ &tb_minwidth_phi
+};
+
+static PhImage_t *
+gui_ph_toolbar_load_icon(char_u *iconfile)
+{
+ static PhImage_t external_icon;
+ PhImage_t *temp_phi = NULL;
+
+ temp_phi = PxLoadImage(iconfile, NULL);
+ if (temp_phi != NULL)
+ {
+ /* The label widget will free the image/palette/etc. for us when
+ * it's destroyed */
+ temp_phi->flags |= Ph_RELEASE_IMAGE_ALL;
+ memcpy(&external_icon, temp_phi, sizeof(external_icon));
+ free(temp_phi);
+
+ temp_phi = &external_icon;
+ }
+ return temp_phi;
+}
+
+/*
+ * This returns either a builtin icon image, an external image or NULL
+ * if it can't find either. The caller can't and doesn't need to try and
+ * free() the returned image, and it can't store the image pointer.
+ * (When setting the Pt_ARG_LABEL_IMAGE resource, the contents of the
+ * PhImage_t are copied, and the original PhImage_t aren't needed anymore).
+ */
+static PhImage_t *
+gui_ph_toolbar_find_icon(vimmenu_T *menu)
+{
+ char_u full_pathname[ MAXPATHL + 1 ];
+ PhImage_t *icon = NULL;
+
+ if (menu->icon_builtin == FALSE)
+ {
+ if (menu->iconfile != NULL)
+ /* TODO: use gui_find_iconfile() */
+ icon = gui_ph_toolbar_load_icon(menu->iconfile);
+
+ /* TODO: Restrict loading to just .png? Search for any format? */
+ if ((icon == NULL) &&
+ ((gui_find_bitmap(menu->name, full_pathname, "gif") == OK) ||
+ (gui_find_bitmap(menu->name, full_pathname, "png") == OK)))
+ icon = gui_ph_toolbar_load_icon(full_pathname);
+
+ if (icon != NULL)
+ return icon;
+ }
+
+ if (menu->iconidx >= 0 &&
+ (menu->iconidx < ARRAY_LENGTH(gui_ph_toolbar_images)))
+ {
+ return gui_ph_toolbar_images[menu->iconidx];
+ }
+
+ return NULL;
+}
+#endif
+
+#if defined(FEAT_MENU) || defined(PROTO)
+ void
+gui_mch_enable_menu(int flag)
+{
+ if (flag != 0)
+ PtRealizeWidget(gui.vimMenuBar);
+ else
+ PtUnrealizeWidget(gui.vimMenuBar);
+}
+
+ void
+gui_mch_set_menu_pos(int x, int y, int w, int h)
+{
+ /* Nothing */
+}
+
+/* Change the position of a menu button in the parent */
+ static void
+gui_ph_position_menu(PtWidget_t *widget, int priority)
+{
+ PtWidget_t *traverse;
+ vimmenu_T *menu;
+
+ traverse = PtWidgetChildBack(PtWidgetParent(widget));
+
+ /* Iterate through the list of widgets in traverse, until
+ * we find the position we want to insert our widget into */
+ /* TODO: traverse from front to back, possible speedup? */
+ while (traverse != NULL)
+ {
+ PtGetResource(traverse, Pt_ARG_POINTER, &menu, 0);
+
+ if (menu != NULL &&
+ priority < menu->priority &&
+ widget != traverse)
+ {
+ /* Insert the widget before the current traverse widget */
+ PtWidgetInsert(widget, traverse, 1);
+ return;
+ }
+
+ traverse = PtWidgetBrotherInFront(traverse);
+ }
+}
+
+/* the index is ignored because it's not useful for our purposes */
+ void
+gui_mch_add_menu(vimmenu_T *menu, int index)
+{
+ vimmenu_T *parent = menu->parent;
+ char_u *accel_key;
+ char_u mnemonic_str[MB_LEN_MAX];
+ int n;
+ PtArg_t args[5];
+
+ menu->submenu_id = menu->id = NULL;
+
+ if (menu_is_menubar(menu->name))
+ {
+
+ accel_key = vim_strchr(menu->name, '&');
+ if (accel_key != NULL)
+ {
+ mnemonic_str[0] = accel_key[1];
+ mnemonic_str[1] = NUL;
+ }
+
+ /* Create the menu button */
+ n = 0;
+ PtSetArg(&args[ n++ ], Pt_ARG_TEXT_STRING, menu->dname, 0);
+ PtSetArg(&args[ n++ ], Pt_ARG_ACCEL_TEXT, menu->actext, 0);
+ if (accel_key != NULL)
+ PtSetArg(&args[ n++ ], Pt_ARG_ACCEL_KEY, mnemonic_str, 0);
+ PtSetArg(&args[ n++ ], Pt_ARG_POINTER, menu, 0);
+
+ if (parent != NULL)
+ PtSetArg(&args[ n++ ], Pt_ARG_BUTTON_TYPE, Pt_MENU_RIGHT, 0);
+
+ menu->id = PtCreateWidget(PtMenuButton,
+ (parent == NULL) ? gui.vimMenuBar : parent->submenu_id,
+ n, args);
+
+ PtAddCallback(menu->id, Pt_CB_ARM, gui_ph_handle_pulldown_menu, menu);
+
+ /* Create the actual menu */
+ n = 0;
+ if (parent != NULL)
+ PtSetArg(&args[ n++ ], Pt_ARG_MENU_FLAGS, Pt_TRUE, Pt_MENU_CHILD);
+
+ menu->submenu_id = PtCreateWidget(PtMenu, menu->id, n, args);
+
+ if (parent == NULL)
+ {
+ PtAddCallback(menu->submenu_id, Pt_CB_UNREALIZED,
+ gui_ph_handle_menu_unrealized, menu);
+
+ if (menu->mnemonic != 0)
+ {
+ PtAddHotkeyHandler(gui.vimWindow, tolower(menu->mnemonic),
+ Pk_KM_Alt, 0, menu, gui_ph_handle_pulldown_menu);
+ }
+ }
+
+ gui_ph_position_menu(menu->id, menu->priority);
+
+ /* Redraw menubar here instead of gui_mch_draw_menubar */
+ if (gui.menu_is_active)
+ PtRealizeWidget(menu->id);
+ }
+ else if (menu_is_popup(menu->name))
+ {
+ menu->submenu_id = PtCreateWidget(PtMenu, gui.vimWindow, 0, NULL);
+ PtAddCallback(menu->submenu_id, Pt_CB_UNREALIZED,
+ gui_ph_handle_menu_unrealized, menu);
+ }
+}
+
+ void
+gui_mch_add_menu_item(vimmenu_T *menu, int index)
+{
+ vimmenu_T *parent = menu->parent;
+ char_u *accel_key;
+ char_u mnemonic_str[MB_LEN_MAX];
+ int n;
+ PtArg_t args[13];
+
+ n = 0;
+ PtSetArg(&args[ n++ ], Pt_ARG_POINTER, menu, 0);
+
+#ifdef FEAT_TOOLBAR
+ if (menu_is_toolbar(parent->name))
+ {
+ if (menu_is_separator(menu->name))
+ {
+ PtSetArg(&args[ n++ ], Pt_ARG_SEP_FLAGS,
+ Pt_SEP_VERTICAL, Pt_SEP_ORIENTATION);
+ PtSetArg(&args[ n++ ], Pt_ARG_SEP_TYPE, Pt_ETCHED_IN, 0);
+ PtSetArg(&args[ n++ ], Pt_ARG_ANCHOR_FLAGS,
+ Pt_TRUE, Pt_ANCHOR_TOP_BOTTOM);
+ PtSetArg(&args[ n++ ], Pt_ARG_WIDTH, 2, 0);
+ menu->id = PtCreateWidget(PtSeparator, gui.vimToolBar, n, args);
+ }
+ else
+ {
+ if (strstr((const char *) p_toolbar, "text") != NULL)
+ {
+ PtSetArg(&args[ n++ ], Pt_ARG_BALLOON_POSITION,
+ Pt_BALLOON_BOTTOM, 0);
+ PtSetArg(&args[ n++ ], Pt_ARG_TEXT_STRING, menu->dname, 0);
+ PtSetArg(&args[ n++ ], Pt_ARG_TEXT_FONT, "TextFont08", 0);
+ }
+ if ((strstr((const char *) p_toolbar, "icons") != NULL) &&
+ (gui_ph_toolbar_images != NULL))
+ {
+ PtSetArg(&args[ n++ ], Pt_ARG_LABEL_IMAGE,
+ gui_ph_toolbar_find_icon(menu), 0);
+ PtSetArg(&args[ n++ ], Pt_ARG_LABEL_TYPE, Pt_TEXT_IMAGE, 0);
+ PtSetArg(&args[ n++ ], Pt_ARG_TEXT_IMAGE_SPACING, 0, 0);
+ }
+ if (strstr((const char *) p_toolbar, "tooltips") != NULL)
+ {
+ PtSetArg(&args[ n++ ], Pt_ARG_LABEL_BALLOON,
+ gui_ph_show_tooltip, 0);
+ PtSetArg(&args[ n++ ], Pt_ARG_LABEL_FLAGS,
+ Pt_TRUE, Pt_SHOW_BALLOON);
+ }
+ PtSetArg(&args[ n++ ], Pt_ARG_MARGIN_HEIGHT, 1, 0);
+ PtSetArg(&args[ n++ ], Pt_ARG_MARGIN_WIDTH, 1, 0);
+ PtSetArg(&args[ n++ ], Pt_ARG_FLAGS, Pt_FALSE,
+ Pt_HIGHLIGHTED | Pt_GETS_FOCUS);
+ PtSetArg(&args[ n++ ], Pt_ARG_FILL_COLOR, Pg_TRANSPARENT, 0);
+ menu->id = PtCreateWidget(PtButton, gui.vimToolBar, n, args);
+
+ PtAddCallback(menu->id, Pt_CB_ACTIVATE, gui_ph_handle_menu, menu);
+ }
+ /* Update toolbar if it's open */
+ if (PtWidgetIsRealized(gui.vimToolBar))
+ PtRealizeWidget(menu->id);
+ }
+ else
+#endif
+ if (menu_is_separator(menu->name))
+ {
+ menu->id = PtCreateWidget(PtSeparator, parent->submenu_id, n, args);
+ }
+ else
+ {
+ accel_key = vim_strchr(menu->name, '&');
+ if (accel_key != NULL)
+ {
+ mnemonic_str[0] = accel_key[1];
+ mnemonic_str[1] = NUL;
+ }
+
+ PtSetArg(&args[ n++ ], Pt_ARG_TEXT_STRING, menu->dname, 0);
+ if (accel_key != NULL)
+ PtSetArg(&args[ n++ ], Pt_ARG_ACCEL_KEY, mnemonic_str,
+ 0);
+
+ PtSetArg(&args[ n++ ], Pt_ARG_ACCEL_TEXT, menu->actext, 0);
+
+ menu->id = PtCreateWidget(PtMenuButton, parent->submenu_id, n, args);
+
+ PtAddCallback(menu->id, Pt_CB_ACTIVATE, gui_ph_handle_menu, menu);
+
+#ifdef USE_PANEL_GROUP
+ if (gui_ph_is_buffer_item(menu, parent) == TRUE)
+ {
+ PtAddCallback(menu->id, Pt_CB_DESTROYED,
+ gui_ph_handle_buffer_remove, menu);
+ gui_ph_pg_add_buffer(menu->dname);
+ }
+#endif
+ }
+
+ gui_ph_position_menu(menu->id, menu->priority);
+}
+
+ void
+gui_mch_destroy_menu(vimmenu_T *menu)
+{
+ if (menu->submenu_id != NULL)
+ PtDestroyWidget(menu->submenu_id);
+ if (menu->id != NULL)
+ PtDestroyWidget(menu->id);
+
+ menu->submenu_id = NULL;
+ menu->id = NULL;
+}
+
+ void
+gui_mch_menu_grey(vimmenu_T *menu, int grey)
+{
+ long flags, mask, fields;
+
+ if (menu->id == NULL)
+ return;
+
+ flags = PtWidgetFlags(menu->id);
+ if (PtWidgetIsClass(menu->id, PtMenuButton) &&
+ PtWidgetIsClass(PtWidgetParent(menu->id), PtMenu))
+ {
+ fields = Pt_FALSE;
+ mask = Pt_SELECTABLE | Pt_HIGHLIGHTED;
+ }
+ else
+ {
+ fields = Pt_TRUE;
+ mask = Pt_BLOCKED | Pt_GHOST;
+ }
+
+ if (! grey)
+ fields = ~fields;
+
+ PtSetResource(menu->id, Pt_ARG_FLAGS, fields,
+ mask);
+}
+
+ void
+gui_mch_menu_hidden(vimmenu_T *menu, int hidden)
+{
+ /* TODO: [un]realize the widget? */
+}
+
+ void
+gui_mch_draw_menubar(void)
+{
+ /* The only time a redraw is needed is when a menu button
+ * is added to the menubar, and that is detected and the bar
+ * redrawn in gui_mch_add_menu_item
+ */
+}
+
+ void
+gui_mch_show_popupmenu(vimmenu_T *menu)
+{
+ PtSetResource(menu->submenu_id, Pt_ARG_POS, &abs_mouse, 0);
+ PtRealizeWidget(menu->submenu_id);
+}
+
+ void
+gui_mch_toggle_tearoffs(int enable)
+{
+ /* No tearoffs yet */
+}
+
+#endif
+
+#if defined(FEAT_TOOLBAR) || defined(PROTO)
+ void
+gui_mch_show_toolbar(int showit)
+{
+ if (showit)
+ PtRealizeWidget(gui.vimToolBar);
+ else
+ PtUnrealizeWidget(gui.vimToolBar);
+}
+#endif
+
+/****************************************************************************/
+/* Fonts */
+
+ static GuiFont
+gui_ph_get_font(
+ char_u *font_name,
+ int_u font_flags,
+ int_u font_size,
+ /* Check whether the resulting font has the font flags and size that
+ * was asked for */
+ int_u enforce
+ )
+{
+ char_u *font_tag;
+ FontQueryInfo info;
+ int_u style;
+
+ font_tag = alloc(MAX_FONT_TAG);
+ if (font_tag != NULL)
+ {
+ if (PfGenerateFontName(font_name, font_flags, font_size,
+ font_tag) != NULL)
+ {
+ /* Enforce some limits on the font used */
+ style = PHFONT_INFO_FIXED;
+
+ if (enforce & PF_STYLE_BOLD)
+ style |= PHFONT_INFO_BOLD;
+ if (enforce & PF_STYLE_ANTIALIAS)
+ style |= PHFONT_INFO_ALIAS;
+ if (enforce & PF_STYLE_ITALIC)
+ style |= PHFONT_INFO_ITALIC;
+
+ PfQueryFontInfo(font_tag, &info);
+
+ if (info.size == 0)
+ font_size = 0;
+
+ /* Make sure font size matches, and that the font style
+ * at least has the bits we're checking for */
+ if (font_size == info.size &&
+ style == (info.style & style))
+ return (GuiFont)font_tag;
+ }
+ vim_free(font_tag);
+ }
+ return NULL;
+}
+
+/*
+ * Split up the vim font name
+ *
+ * vim_font is in the form of
+ * <name>:s<height>:a:b:i
+ *
+ * a = antialias
+ * b = bold
+ * i = italic
+ *
+ */
+
+ static int
+gui_ph_parse_font_name(
+ char_u *vim_font,
+ char_u **font_name,
+ int_u *font_flags,
+ int_u *font_size)
+{
+ char_u *mark;
+ int_u name_len, size;
+
+ mark = vim_strchr(vim_font, ':');
+ if (mark == NULL)
+ name_len = STRLEN(vim_font);
+ else
+ name_len = (int_u) (mark - vim_font);
+
+ *font_name = vim_strnsave(vim_font, name_len);
+ if (*font_name != NULL)
+ {
+ if (mark != NULL)
+ {
+ while (*mark != NUL && *mark++ == ':')
+ {
+ switch (tolower(*mark++))
+ {
+ case 'a': *font_flags |= PF_STYLE_ANTIALIAS; break;
+ case 'b': *font_flags |= PF_STYLE_BOLD; break;
+ case 'i': *font_flags |= PF_STYLE_ITALIC; break;
+
+ case 's':
+ size = getdigits(&mark);
+ /* Restrict the size to some vague limits */
+ if (size < 1 || size > 100)
+ size = 8;
+
+ *font_size = size;
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+
+ int
+gui_mch_init_font(char_u *vim_font_name, int fontset)
+{
+ char_u *font_tag;
+ char_u *font_name = NULL;
+ int_u font_flags = 0;
+ int_u font_size = 12;
+
+ FontQueryInfo info;
+ PhRect_t extent;
+
+ if (vim_font_name == NULL)
+ {
+ /* Default font */
+ vim_font_name = "PC Terminal";
+ }
+
+ if (STRCMP(vim_font_name, "*") == 0)
+ {
+ font_tag = PtFontSelection(gui.vimWindow, NULL, NULL,
+ "pcterm12", -1, PHFONT_FIXED, NULL);
+
+ if (font_tag == NULL)
+ return FAIL;
+
+ gui_mch_free_font(gui.norm_font);
+ gui.norm_font = font_tag;
+
+ PfQueryFontInfo(font_tag, &info);
+ font_name = vim_strsave(info.font);
+ }
+ else
+ {
+ if (gui_ph_parse_font_name(vim_font_name, &font_name, &font_flags,
+ &font_size) == FALSE)
+ return FAIL;
+
+ font_tag = gui_ph_get_font(font_name, font_flags, font_size, 0);
+ if (font_tag == NULL)
+ {
+ vim_free(font_name);
+ return FAIL;
+ }
+
+ gui_mch_free_font(gui.norm_font);
+ gui.norm_font = font_tag;
+ }
+
+ gui_mch_free_font(gui.bold_font);
+ gui.bold_font = gui_ph_get_font(font_name, font_flags | PF_STYLE_BOLD,
+ font_size, PF_STYLE_BOLD);
+
+ gui_mch_free_font(gui.ital_font);
+ gui.ital_font = gui_ph_get_font(font_name, font_flags | PF_STYLE_ITALIC,
+ font_size, PF_STYLE_ITALIC);
+
+ /* This extent was brought to you by the letter 'g' */
+ PfExtentText(&extent, NULL, font_tag, "g", 1);
+
+ gui.char_width = extent.lr.x - extent.ul.x + 1;
+ gui.char_height = (- extent.ul.y) + extent.lr.y + 1;
+ gui.char_ascent = - extent.ul.y;
+
+ vim_free(font_name);
+ return OK;
+}
+
+/*
+ * Adjust gui.char_height (after 'linespace' was changed).
+ */
+ int
+gui_mch_adjust_charheight(void)
+{
+ FontQueryInfo info;
+
+ PfQueryFontInfo(gui.norm_font, &info);
+
+ gui.char_height = - info.ascender + info.descender + p_linespace;
+ gui.char_ascent = - info.ascender + p_linespace / 2;
+
+ return OK;
+}
+
+ GuiFont
+gui_mch_get_font(char_u *vim_font_name, int report_error)
+{
+ char_u *font_name;
+ char_u *font_tag;
+ int_u font_size = 12;
+ int_u font_flags = 0;
+
+ if (gui_ph_parse_font_name(vim_font_name, &font_name, &font_flags,
+ &font_size) != FALSE)
+ {
+ font_tag = gui_ph_get_font(font_name, font_flags, font_size, -1);
+ vim_free(font_name);
+
+ if (font_tag != NULL)
+ return (GuiFont)font_tag;
+ }
+
+ if (report_error)
+ semsg(e_font, vim_font_name);
+
+ return FAIL;
+}
+
+#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
+
+ void
+gui_mch_set_font(GuiFont font)
+{
+ PgSetFont(font);
+}
+
+ void
+gui_mch_free_font(GuiFont font)
+{
+ vim_free(font);
+}
+
diff --git a/src/gui_w32.c b/src/gui_w32.c
new file mode 100644
index 0000000..ead617a
--- /dev/null
+++ b/src/gui_w32.c
@@ -0,0 +1,8930 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ * GUI support by Robert Webb
+ *
+ * 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.
+ */
+/*
+ * Windows GUI.
+ *
+ * GUI support for Microsoft Windows, aka Win32. Also for Win64.
+ *
+ * George V. Reilly <george@reilly.org> wrote the original Win32 GUI.
+ * Robert Webb reworked it to use the existing GUI stuff and added menu,
+ * scrollbars, etc.
+ *
+ * Note: Clipboard stuff, for cutting and pasting text to other windows, is in
+ * winclip.c. (It can also be done from the terminal version).
+ *
+ * TODO: Some of the function signatures ought to be updated for Win64;
+ * e.g., replace LONG with LONG_PTR, etc.
+ */
+
+#include "vim.h"
+
+#if defined(FEAT_DIRECTX)
+# include "gui_dwrite.h"
+#endif
+
+#if defined(FEAT_DIRECTX)
+static DWriteContext *s_dwc = NULL;
+static int s_directx_enabled = 0;
+static int s_directx_load_attempted = 0;
+# define IS_ENABLE_DIRECTX() (s_directx_enabled && s_dwc != NULL && enc_utf8)
+static int directx_enabled(void);
+static void directx_binddc(void);
+#endif
+
+#ifdef FEAT_MENU
+static int gui_mswin_get_menu_height(int fix_window);
+#endif
+
+#if defined(FEAT_RENDER_OPTIONS) || defined(PROTO)
+ int
+gui_mch_set_rendering_options(char_u *s)
+{
+# ifdef FEAT_DIRECTX
+ char_u *p, *q;
+
+ int dx_enable = 0;
+ int dx_flags = 0;
+ float dx_gamma = 0.0f;
+ float dx_contrast = 0.0f;
+ float dx_level = 0.0f;
+ int dx_geom = 0;
+ int dx_renmode = 0;
+ int dx_taamode = 0;
+
+ /* parse string as rendering options. */
+ for (p = s; p != NULL && *p != NUL; )
+ {
+ char_u item[256];
+ char_u name[128];
+ char_u value[128];
+
+ copy_option_part(&p, item, sizeof(item), ",");
+ if (p == NULL)
+ break;
+ q = &item[0];
+ copy_option_part(&q, name, sizeof(name), ":");
+ if (q == NULL)
+ return FAIL;
+ copy_option_part(&q, value, sizeof(value), ":");
+
+ if (STRCMP(name, "type") == 0)
+ {
+ if (STRCMP(value, "directx") == 0)
+ dx_enable = 1;
+ else
+ return FAIL;
+ }
+ else if (STRCMP(name, "gamma") == 0)
+ {
+ dx_flags |= 1 << 0;
+ dx_gamma = (float)atof((char *)value);
+ }
+ else if (STRCMP(name, "contrast") == 0)
+ {
+ dx_flags |= 1 << 1;
+ dx_contrast = (float)atof((char *)value);
+ }
+ else if (STRCMP(name, "level") == 0)
+ {
+ dx_flags |= 1 << 2;
+ dx_level = (float)atof((char *)value);
+ }
+ else if (STRCMP(name, "geom") == 0)
+ {
+ dx_flags |= 1 << 3;
+ dx_geom = atoi((char *)value);
+ if (dx_geom < 0 || dx_geom > 2)
+ return FAIL;
+ }
+ else if (STRCMP(name, "renmode") == 0)
+ {
+ dx_flags |= 1 << 4;
+ dx_renmode = atoi((char *)value);
+ if (dx_renmode < 0 || dx_renmode > 6)
+ return FAIL;
+ }
+ else if (STRCMP(name, "taamode") == 0)
+ {
+ dx_flags |= 1 << 5;
+ dx_taamode = atoi((char *)value);
+ if (dx_taamode < 0 || dx_taamode > 3)
+ return FAIL;
+ }
+ else if (STRCMP(name, "scrlines") == 0)
+ {
+ /* Deprecated. Simply ignore it. */
+ }
+ else
+ return FAIL;
+ }
+
+ if (!gui.in_use)
+ return OK; /* only checking the syntax of the value */
+
+ /* Enable DirectX/DirectWrite */
+ if (dx_enable)
+ {
+ if (!directx_enabled())
+ return FAIL;
+ DWriteContext_SetRenderingParams(s_dwc, NULL);
+ if (dx_flags)
+ {
+ DWriteRenderingParams param;
+ DWriteContext_GetRenderingParams(s_dwc, &param);
+ if (dx_flags & (1 << 0))
+ param.gamma = dx_gamma;
+ if (dx_flags & (1 << 1))
+ param.enhancedContrast = dx_contrast;
+ if (dx_flags & (1 << 2))
+ param.clearTypeLevel = dx_level;
+ if (dx_flags & (1 << 3))
+ param.pixelGeometry = dx_geom;
+ if (dx_flags & (1 << 4))
+ param.renderingMode = dx_renmode;
+ if (dx_flags & (1 << 5))
+ param.textAntialiasMode = dx_taamode;
+ DWriteContext_SetRenderingParams(s_dwc, &param);
+ }
+ }
+ s_directx_enabled = dx_enable;
+
+ return OK;
+# else
+ return FAIL;
+# endif
+}
+#endif
+
+/*
+ * These are new in Windows ME/XP, only defined in recent compilers.
+ */
+#ifndef HANDLE_WM_XBUTTONUP
+# define HANDLE_WM_XBUTTONUP(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
+#endif
+#ifndef HANDLE_WM_XBUTTONDOWN
+# define HANDLE_WM_XBUTTONDOWN(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), FALSE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
+#endif
+#ifndef HANDLE_WM_XBUTTONDBLCLK
+# define HANDLE_WM_XBUTTONDBLCLK(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), TRUE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
+#endif
+
+
+#include "version.h" /* used by dialog box routine for default title */
+#ifdef DEBUG
+# include <tchar.h>
+#endif
+
+/* cproto fails on missing include files */
+#ifndef PROTO
+
+#ifndef __MINGW32__
+# include <shellapi.h>
+#endif
+#if defined(FEAT_TOOLBAR) || defined(FEAT_BEVAL_GUI) || defined(FEAT_GUI_TABLINE)
+# include <commctrl.h>
+#endif
+#include <windowsx.h>
+
+#ifdef GLOBAL_IME
+# include "glbl_ime.h"
+#endif
+
+#endif /* PROTO */
+
+#ifdef FEAT_MENU
+# define MENUHINTS /* show menu hints in command line */
+#endif
+
+/* Some parameters for dialog boxes. All in pixels. */
+#define DLG_PADDING_X 10
+#define DLG_PADDING_Y 10
+#define DLG_OLD_STYLE_PADDING_X 5
+#define DLG_OLD_STYLE_PADDING_Y 5
+#define DLG_VERT_PADDING_X 4 /* For vertical buttons */
+#define DLG_VERT_PADDING_Y 4
+#define DLG_ICON_WIDTH 34
+#define DLG_ICON_HEIGHT 34
+#define DLG_MIN_WIDTH 150
+#define DLG_FONT_NAME "MS Sans Serif"
+#define DLG_FONT_POINT_SIZE 8
+#define DLG_MIN_MAX_WIDTH 400
+#define DLG_MIN_MAX_HEIGHT 400
+
+#define DLG_NONBUTTON_CONTROL 5000 /* First ID of non-button controls */
+
+#ifndef WM_XBUTTONDOWN /* For Win2K / winME ONLY */
+# define WM_XBUTTONDOWN 0x020B
+# define WM_XBUTTONUP 0x020C
+# define WM_XBUTTONDBLCLK 0x020D
+# define MK_XBUTTON1 0x0020
+# define MK_XBUTTON2 0x0040
+#endif
+
+#ifdef PROTO
+/*
+ * Define a few things for generating prototypes. This is just to avoid
+ * syntax errors, the defines do not need to be correct.
+ */
+# define APIENTRY
+# define CALLBACK
+# define CONST
+# define FAR
+# define NEAR
+# undef _cdecl
+# define _cdecl
+typedef int BOOL;
+typedef int BYTE;
+typedef int DWORD;
+typedef int WCHAR;
+typedef int ENUMLOGFONT;
+typedef int FINDREPLACE;
+typedef int HANDLE;
+typedef int HBITMAP;
+typedef int HBRUSH;
+typedef int HDROP;
+typedef int INT;
+typedef int LOGFONT[];
+typedef int LPARAM;
+typedef int LPCREATESTRUCT;
+typedef int LPCSTR;
+typedef int LPCTSTR;
+typedef int LPRECT;
+typedef int LPSTR;
+typedef int LPWINDOWPOS;
+typedef int LPWORD;
+typedef int LRESULT;
+typedef int HRESULT;
+# undef MSG
+typedef int MSG;
+typedef int NEWTEXTMETRIC;
+typedef int OSVERSIONINFO;
+typedef int PWORD;
+typedef int RECT;
+typedef int UINT;
+typedef int WORD;
+typedef int WPARAM;
+typedef int POINT;
+typedef void *HINSTANCE;
+typedef void *HMENU;
+typedef void *HWND;
+typedef void *HDC;
+typedef void VOID;
+typedef int LPNMHDR;
+typedef int LONG;
+typedef int WNDPROC;
+typedef int UINT_PTR;
+typedef int COLORREF;
+typedef int HCURSOR;
+#endif
+
+#ifndef GET_X_LPARAM
+# define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp))
+#endif
+
+static void _OnPaint( HWND hwnd);
+static void fill_rect(const RECT *rcp, HBRUSH hbr, COLORREF color);
+static void clear_rect(RECT *rcp);
+
+static WORD s_dlgfntheight; /* height of the dialog font */
+static WORD s_dlgfntwidth; /* width of the dialog font */
+
+#ifdef FEAT_MENU
+static HMENU s_menuBar = NULL;
+#endif
+#ifdef FEAT_TEAROFF
+static void rebuild_tearoff(vimmenu_T *menu);
+static HBITMAP s_htearbitmap; /* bitmap used to indicate tearoff */
+#endif
+
+/* Flag that is set while processing a message that must not be interrupted by
+ * processing another message. */
+static int s_busy_processing = FALSE;
+
+static int destroying = FALSE; /* call DestroyWindow() ourselves */
+
+#ifdef MSWIN_FIND_REPLACE
+static UINT s_findrep_msg = 0; /* set in gui_w[16/32].c */
+static FINDREPLACE s_findrep_struct;
+static FINDREPLACEW s_findrep_struct_w;
+static HWND s_findrep_hwnd = NULL;
+static int s_findrep_is_find; /* TRUE for find dialog, FALSE
+ for find/replace dialog */
+#endif
+
+static HINSTANCE s_hinst = NULL;
+#if !defined(FEAT_GUI)
+static
+#endif
+HWND s_hwnd = NULL;
+static HDC s_hdc = NULL;
+static HBRUSH s_brush = NULL;
+
+#ifdef FEAT_TOOLBAR
+static HWND s_toolbarhwnd = NULL;
+static WNDPROC s_toolbar_wndproc = NULL;
+#endif
+
+#ifdef FEAT_GUI_TABLINE
+static HWND s_tabhwnd = NULL;
+static WNDPROC s_tabline_wndproc = NULL;
+static int showing_tabline = 0;
+#endif
+
+static WPARAM s_wParam = 0;
+static LPARAM s_lParam = 0;
+
+static HWND s_textArea = NULL;
+static UINT s_uMsg = 0;
+
+static char_u *s_textfield; /* Used by dialogs to pass back strings */
+
+static int s_need_activate = FALSE;
+
+/* 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;
+
+#ifdef GLOBAL_IME
+# define MyTranslateMessage(x) global_ime_TranslateMessage(x)
+#else
+# define MyTranslateMessage(x) TranslateMessage(x)
+#endif
+
+#if defined(FEAT_DIRECTX)
+ static int
+directx_enabled(void)
+{
+ if (s_dwc != NULL)
+ return 1;
+ else if (s_directx_load_attempted)
+ return 0;
+ /* load DirectX */
+ DWrite_Init();
+ s_directx_load_attempted = 1;
+ s_dwc = DWriteContext_Open();
+ directx_binddc();
+ return s_dwc != NULL ? 1 : 0;
+}
+
+ static void
+directx_binddc(void)
+{
+ if (s_textArea != NULL)
+ {
+ RECT rect;
+ GetClientRect(s_textArea, &rect);
+ DWriteContext_BindDC(s_dwc, s_hdc, &rect);
+ }
+}
+#endif
+
+/* use of WindowProc depends on wide_WindowProc */
+#define MyWindowProc vim_WindowProc
+
+extern int current_font_height; /* this is in os_mswin.c */
+
+static struct
+{
+ UINT 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'},
+ {VK_F16, 'F', '6'},
+ {VK_F17, 'F', '7'},
+ {VK_F18, 'F', '8'},
+ {VK_F19, 'F', '9'},
+ {VK_F20, 'F', 'A'},
+
+ {VK_F21, 'F', 'B'},
+#ifdef FEAT_NETBEANS_INTG
+ {VK_PAUSE, 'F', 'B'}, /* Pause == F21 (see gui_gtk_x11.c) */
+#endif
+ {VK_F22, 'F', 'C'},
+ {VK_F23, 'F', 'D'},
+ {VK_F24, 'F', 'E'}, /* winuser.h defines up to F24 */
+
+ {VK_HELP, '%', '1'},
+ {VK_BACK, 'k', 'b'},
+ {VK_INSERT, 'k', 'I'},
+ {VK_DELETE, 'k', 'D'},
+ {VK_HOME, 'k', 'h'},
+ {VK_END, '@', '7'},
+ {VK_PRIOR, 'k', 'P'},
+ {VK_NEXT, 'k', 'N'},
+ {VK_PRINT, '%', '9'},
+ {VK_ADD, 'K', '6'},
+ {VK_SUBTRACT, 'K', '7'},
+ {VK_DIVIDE, 'K', '8'},
+ {VK_MULTIPLY, 'K', '9'},
+ {VK_SEPARATOR, 'K', 'A'}, /* Keypad Enter */
+ {VK_DECIMAL, 'K', 'B'},
+
+ {VK_NUMPAD0, 'K', 'C'},
+ {VK_NUMPAD1, 'K', 'D'},
+ {VK_NUMPAD2, 'K', 'E'},
+ {VK_NUMPAD3, 'K', 'F'},
+ {VK_NUMPAD4, 'K', 'G'},
+ {VK_NUMPAD5, 'K', 'H'},
+ {VK_NUMPAD6, 'K', 'I'},
+ {VK_NUMPAD7, 'K', 'J'},
+ {VK_NUMPAD8, 'K', 'K'},
+ {VK_NUMPAD9, 'K', 'L'},
+
+ /* Keys that we want to be able to use any modifier with: */
+ {VK_SPACE, ' ', NUL},
+ {VK_TAB, TAB, NUL},
+ {VK_ESCAPE, ESC, NUL},
+ {NL, NL, NUL},
+ {CAR, CAR, NUL},
+
+ /* End of list marker: */
+ {0, 0, 0}
+};
+
+/* Local variables */
+static int s_button_pending = -1;
+
+/* s_getting_focus is set when we got focus but didn't see mouse-up event yet,
+ * so don't reset s_button_pending. */
+static int s_getting_focus = FALSE;
+
+static int s_x_pending;
+static int s_y_pending;
+static UINT s_kFlags_pending;
+static UINT s_wait_timer = 0; // Timer for get char from user
+static int s_timed_out = FALSE;
+static int dead_key = 0; // 0: no dead key, 1: dead key pressed
+static UINT surrogate_pending_ch = 0; // 0: no surrogate pending,
+ // else a high surrogate
+
+#ifdef FEAT_BEVAL_GUI
+/* balloon-eval WM_NOTIFY_HANDLER */
+static void Handle_WM_Notify(HWND hwnd, LPNMHDR pnmh);
+static void TrackUserActivity(UINT uMsg);
+#endif
+
+/*
+ * For control IME.
+ *
+ * These LOGFONT used for IME.
+ */
+#if defined(FEAT_MBYTE_IME) || defined(GLOBAL_IME)
+/* holds LOGFONT for 'guifontwide' if available, otherwise 'guifont' */
+static LOGFONT norm_logfont;
+#endif
+#ifdef FEAT_MBYTE_IME
+/* holds LOGFONT for 'guifont' always. */
+static LOGFONT sub_logfont;
+#endif
+
+#ifdef FEAT_MBYTE_IME
+static LRESULT _OnImeNotify(HWND hWnd, DWORD dwCommand, DWORD dwData);
+#endif
+
+#if defined(FEAT_BROWSE)
+static char_u *convert_filter(char_u *s);
+#endif
+
+#ifdef DEBUG_PRINT_ERROR
+/*
+ * Print out the last Windows error message
+ */
+ static void
+print_windows_error(void)
+{
+ LPVOID lpMsgBuf;
+
+ FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL, GetLastError(),
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR) &lpMsgBuf, 0, NULL);
+ TRACE1("Error: %s\n", lpMsgBuf);
+ LocalFree(lpMsgBuf);
+}
+#endif
+
+/*
+ * 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
+ */
+
+#define BLINK_NONE 0
+#define BLINK_OFF 1
+#define BLINK_ON 2
+
+static int blink_state = BLINK_NONE;
+static long_u blink_waittime = 700;
+static long_u blink_ontime = 400;
+static long_u blink_offtime = 250;
+static UINT blink_timer = 0;
+
+ int
+gui_mch_is_blinking(void)
+{
+ return blink_state != BLINK_NONE;
+}
+
+ int
+gui_mch_is_blink_off(void)
+{
+ return blink_state == BLINK_OFF;
+}
+
+ void
+gui_mch_set_blinking(long wait, long on, long off)
+{
+ blink_waittime = wait;
+ blink_ontime = on;
+ blink_offtime = off;
+}
+
+ static VOID CALLBACK
+_OnBlinkTimer(
+ HWND hwnd,
+ UINT uMsg UNUSED,
+ UINT idEvent,
+ DWORD dwTime UNUSED)
+{
+ MSG msg;
+
+ /*
+ TRACE2("Got timer event, id %d, blink_timer %d\n", idEvent, blink_timer);
+ */
+
+ KillTimer(NULL, idEvent);
+
+ /* Eat spurious WM_TIMER messages */
+ while (pPeekMessage(&msg, hwnd, WM_TIMER, WM_TIMER, PM_REMOVE))
+ ;
+
+ if (blink_state == BLINK_ON)
+ {
+ gui_undraw_cursor();
+ blink_state = BLINK_OFF;
+ blink_timer = (UINT) SetTimer(NULL, 0, (UINT)blink_offtime,
+ (TIMERPROC)_OnBlinkTimer);
+ }
+ else
+ {
+ gui_update_cursor(TRUE, FALSE);
+ blink_state = BLINK_ON;
+ blink_timer = (UINT) SetTimer(NULL, 0, (UINT)blink_ontime,
+ (TIMERPROC)_OnBlinkTimer);
+ }
+ gui_mch_flush();
+}
+
+ static void
+gui_mswin_rm_blink_timer(void)
+{
+ MSG msg;
+
+ if (blink_timer != 0)
+ {
+ KillTimer(NULL, blink_timer);
+ /* Eat spurious WM_TIMER messages */
+ while (pPeekMessage(&msg, s_hwnd, WM_TIMER, WM_TIMER, PM_REMOVE))
+ ;
+ blink_timer = 0;
+ }
+}
+
+/*
+ * Stop the cursor blinking. Show the cursor if it wasn't shown.
+ */
+ void
+gui_mch_stop_blink(int may_call_gui_update_cursor)
+{
+ gui_mswin_rm_blink_timer();
+ if (blink_state == BLINK_OFF && may_call_gui_update_cursor)
+ {
+ gui_update_cursor(TRUE, FALSE);
+ gui_mch_flush();
+ }
+ blink_state = BLINK_NONE;
+}
+
+/*
+ * 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_mswin_rm_blink_timer();
+
+ /* Only switch blinking on if none of the times is zero */
+ if (blink_waittime && blink_ontime && blink_offtime && gui.in_focus)
+ {
+ blink_timer = (UINT)SetTimer(NULL, 0, (UINT)blink_waittime,
+ (TIMERPROC)_OnBlinkTimer);
+ blink_state = BLINK_ON;
+ gui_update_cursor(TRUE, FALSE);
+ gui_mch_flush();
+ }
+}
+
+/*
+ * Call-back routines.
+ */
+
+ static VOID CALLBACK
+_OnTimer(
+ HWND hwnd,
+ UINT uMsg UNUSED,
+ UINT idEvent,
+ DWORD dwTime UNUSED)
+{
+ MSG msg;
+
+ /*
+ TRACE2("Got timer event, id %d, s_wait_timer %d\n", idEvent, s_wait_timer);
+ */
+ KillTimer(NULL, idEvent);
+ s_timed_out = TRUE;
+
+ /* Eat spurious WM_TIMER messages */
+ while (pPeekMessage(&msg, hwnd, WM_TIMER, WM_TIMER, PM_REMOVE))
+ ;
+ if (idEvent == s_wait_timer)
+ s_wait_timer = 0;
+}
+
+ static void
+_OnDeadChar(
+ HWND hwnd UNUSED,
+ UINT ch UNUSED,
+ int cRepeat UNUSED)
+{
+ dead_key = 1;
+}
+
+/*
+ * Convert Unicode character "ch" to bytes in "string[slen]".
+ * When "had_alt" is TRUE the ALT key was included in "ch".
+ * Return the length.
+ * Because the Windows API uses UTF-16, we have to deal with surrogate
+ * pairs; this is where we choose to deal with them: if "ch" is a high
+ * surrogate, it will be stored, and the length returned will be zero; the next
+ * char_to_string call will then include the high surrogate, decoding the pair
+ * of UTF-16 code units to a single Unicode code point, presuming it is the
+ * matching low surrogate.
+ */
+ static int
+char_to_string(int ch, char_u *string, int slen, int had_alt)
+{
+ int len;
+ int i;
+ WCHAR wstring[2];
+ char_u *ws = NULL;
+
+ if (surrogate_pending_ch != 0)
+ {
+ /* We don't guarantee ch is a low surrogate to match the high surrogate
+ * we already have; it should be, but if it isn't, tough luck. */
+ wstring[0] = surrogate_pending_ch;
+ wstring[1] = ch;
+ surrogate_pending_ch = 0;
+ len = 2;
+ }
+ else if (ch >= 0xD800 && ch <= 0xDBFF) /* high surrogate */
+ {
+ /* We don't have the entire code point yet, only the first UTF-16 code
+ * unit; so just remember it and use it in the next call. */
+ surrogate_pending_ch = ch;
+ return 0;
+ }
+ else
+ {
+ wstring[0] = ch;
+ len = 1;
+ }
+
+ /* "ch" is a UTF-16 character. Convert it to a string of bytes. When
+ * "enc_codepage" is non-zero use the standard Win32 function,
+ * otherwise use our own conversion function (e.g., for UTF-8). */
+ if (enc_codepage > 0)
+ {
+ len = WideCharToMultiByte(enc_codepage, 0, wstring, len,
+ (LPSTR)string, slen, 0, NULL);
+ /* If we had included the ALT key into the character but now the
+ * upper bit is no longer set, that probably means the conversion
+ * failed. Convert the original character and set the upper bit
+ * afterwards. */
+ if (had_alt && len == 1 && ch >= 0x80 && string[0] < 0x80)
+ {
+ wstring[0] = ch & 0x7f;
+ len = WideCharToMultiByte(enc_codepage, 0, wstring, len,
+ (LPSTR)string, slen, 0, NULL);
+ if (len == 1) /* safety check */
+ string[0] |= 0x80;
+ }
+ }
+ else
+ {
+ ws = utf16_to_enc(wstring, &len);
+ if (ws == NULL)
+ len = 0;
+ else
+ {
+ if (len > slen) /* just in case */
+ len = slen;
+ mch_memmove(string, ws, len);
+ vim_free(ws);
+ }
+ }
+
+ if (len == 0)
+ {
+ string[0] = ch;
+ len = 1;
+ }
+
+ for (i = 0; i < len; ++i)
+ if (string[i] == CSI && len <= slen - 2)
+ {
+ /* Insert CSI as K_CSI. */
+ mch_memmove(string + i + 3, string + i + 1, len - i - 1);
+ string[++i] = KS_EXTRA;
+ string[++i] = (int)KE_CSI;
+ len += 2;
+ }
+
+ return len;
+}
+
+/*
+ * Key hit, add it to the input buffer.
+ */
+ static void
+_OnChar(
+ HWND hwnd UNUSED,
+ UINT ch,
+ int cRepeat UNUSED)
+{
+ char_u string[40];
+ int len = 0;
+
+ dead_key = 0;
+
+ len = char_to_string(ch, string, 40, FALSE);
+ if (len == 1 && string[0] == Ctrl_C && ctrl_c_interrupts)
+ {
+ trash_input_buf();
+ got_int = TRUE;
+ }
+
+ add_to_input_buf(string, len);
+}
+
+/*
+ * Alt-Key hit, add it to the input buffer.
+ */
+ static void
+_OnSysChar(
+ HWND hwnd UNUSED,
+ UINT cch,
+ int cRepeat UNUSED)
+{
+ char_u string[40]; /* Enough for multibyte character */
+ int len;
+ int modifiers;
+ int ch = cch; /* special keys are negative */
+
+ dead_key = 0;
+
+ /* TRACE("OnSysChar(%d, %c)\n", ch, ch); */
+
+ /* OK, we have a character key (given by ch) which was entered with the
+ * ALT key pressed. Eg, if the user presses Alt-A, then ch == 'A'. Note
+ * that the system distinguishes Alt-a and Alt-A (Alt-Shift-a unless
+ * CAPSLOCK is pressed) at this point.
+ */
+ modifiers = MOD_MASK_ALT;
+ if (GetKeyState(VK_SHIFT) & 0x8000)
+ modifiers |= MOD_MASK_SHIFT;
+ if (GetKeyState(VK_CONTROL) & 0x8000)
+ modifiers |= MOD_MASK_CTRL;
+
+ ch = simplify_key(ch, &modifiers);
+ /* remove the SHIFT modifier for keys where it's already included, e.g.,
+ * '(' and '*' */
+ if (ch < 0x100 && !isalpha(ch) && isprint(ch))
+ modifiers &= ~MOD_MASK_SHIFT;
+
+ /* Interpret the ALT key as making the key META, include SHIFT, etc. */
+ ch = extract_modifiers(ch, &modifiers);
+ if (ch == CSI)
+ ch = K_CSI;
+
+ len = 0;
+ if (modifiers)
+ {
+ string[len++] = CSI;
+ string[len++] = KS_MODIFIER;
+ string[len++] = modifiers;
+ }
+
+ if (IS_SPECIAL((int)ch))
+ {
+ string[len++] = CSI;
+ string[len++] = K_SECOND((int)ch);
+ string[len++] = K_THIRD((int)ch);
+ }
+ else
+ {
+ /* Although the documentation isn't clear about it, we assume "ch" is
+ * a Unicode character. */
+ len += char_to_string(ch, string + len, 40 - len, TRUE);
+ }
+
+ add_to_input_buf(string, len);
+}
+
+ static void
+_OnMouseEvent(
+ int button,
+ int x,
+ int y,
+ int repeated_click,
+ UINT keyFlags)
+{
+ int vim_modifiers = 0x0;
+
+ s_getting_focus = FALSE;
+
+ if (keyFlags & MK_SHIFT)
+ vim_modifiers |= MOUSE_SHIFT;
+ if (keyFlags & MK_CONTROL)
+ vim_modifiers |= MOUSE_CTRL;
+ if (GetKeyState(VK_MENU) & 0x8000)
+ vim_modifiers |= MOUSE_ALT;
+
+ gui_send_mouse_event(button, x, y, repeated_click, vim_modifiers);
+}
+
+ static void
+_OnMouseButtonDown(
+ HWND hwnd UNUSED,
+ BOOL fDoubleClick UNUSED,
+ int x,
+ int y,
+ UINT keyFlags)
+{
+ static LONG s_prevTime = 0;
+
+ LONG currentTime = GetMessageTime();
+ int button = -1;
+ int repeated_click;
+
+ /* Give main window the focus: this is so the cursor isn't hollow. */
+ (void)SetFocus(s_hwnd);
+
+ if (s_uMsg == WM_LBUTTONDOWN || s_uMsg == WM_LBUTTONDBLCLK)
+ button = MOUSE_LEFT;
+ else if (s_uMsg == WM_MBUTTONDOWN || s_uMsg == WM_MBUTTONDBLCLK)
+ button = MOUSE_MIDDLE;
+ else if (s_uMsg == WM_RBUTTONDOWN || s_uMsg == WM_RBUTTONDBLCLK)
+ button = MOUSE_RIGHT;
+ else if (s_uMsg == WM_XBUTTONDOWN || s_uMsg == WM_XBUTTONDBLCLK)
+ {
+#ifndef GET_XBUTTON_WPARAM
+# define GET_XBUTTON_WPARAM(wParam) (HIWORD(wParam))
+#endif
+ button = ((GET_XBUTTON_WPARAM(s_wParam) == 1) ? MOUSE_X1 : MOUSE_X2);
+ }
+ else if (s_uMsg == WM_CAPTURECHANGED)
+ {
+ /* on W95/NT4, somehow you get in here with an odd Msg
+ * if you press one button while holding down the other..*/
+ if (s_button_pending == MOUSE_LEFT)
+ button = MOUSE_RIGHT;
+ else
+ button = MOUSE_LEFT;
+ }
+ if (button >= 0)
+ {
+ repeated_click = ((int)(currentTime - s_prevTime) < p_mouset);
+
+ /*
+ * Holding down the left and right buttons simulates pushing the middle
+ * button.
+ */
+ if (repeated_click
+ && ((button == MOUSE_LEFT && s_button_pending == MOUSE_RIGHT)
+ || (button == MOUSE_RIGHT
+ && s_button_pending == MOUSE_LEFT)))
+ {
+ /*
+ * Hmm, gui.c will ignore more than one button down at a time, so
+ * pretend we let go of it first.
+ */
+ gui_send_mouse_event(MOUSE_RELEASE, x, y, FALSE, 0x0);
+ button = MOUSE_MIDDLE;
+ repeated_click = FALSE;
+ s_button_pending = -1;
+ _OnMouseEvent(button, x, y, repeated_click, keyFlags);
+ }
+ else if ((repeated_click)
+ || (mouse_model_popup() && (button == MOUSE_RIGHT)))
+ {
+ if (s_button_pending > -1)
+ {
+ _OnMouseEvent(s_button_pending, x, y, FALSE, keyFlags);
+ s_button_pending = -1;
+ }
+ /* TRACE("Button down at x %d, y %d\n", x, y); */
+ _OnMouseEvent(button, x, y, repeated_click, keyFlags);
+ }
+ else
+ {
+ /*
+ * If this is the first press (i.e. not a multiple click) don't
+ * action immediately, but store and wait for:
+ * i) button-up
+ * ii) mouse move
+ * iii) another button press
+ * before using it.
+ * This enables us to make left+right simulate middle button,
+ * without left or right being actioned first. The side-effect is
+ * that if you click and hold the mouse without dragging, the
+ * cursor doesn't move until you release the button. In practice
+ * this is hardly a problem.
+ */
+ s_button_pending = button;
+ s_x_pending = x;
+ s_y_pending = y;
+ s_kFlags_pending = keyFlags;
+ }
+
+ s_prevTime = currentTime;
+ }
+}
+
+ static void
+_OnMouseMoveOrRelease(
+ HWND hwnd UNUSED,
+ int x,
+ int y,
+ UINT keyFlags)
+{
+ int button;
+
+ s_getting_focus = FALSE;
+ if (s_button_pending > -1)
+ {
+ /* Delayed action for mouse down event */
+ _OnMouseEvent(s_button_pending, s_x_pending,
+ s_y_pending, FALSE, s_kFlags_pending);
+ s_button_pending = -1;
+ }
+ if (s_uMsg == WM_MOUSEMOVE)
+ {
+ /*
+ * It's only a MOUSE_DRAG if one or more mouse buttons are being held
+ * down.
+ */
+ if (!(keyFlags & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON
+ | MK_XBUTTON1 | MK_XBUTTON2)))
+ {
+ gui_mouse_moved(x, y);
+ return;
+ }
+
+ /*
+ * While button is down, keep grabbing mouse move events when
+ * the mouse goes outside the window
+ */
+ SetCapture(s_textArea);
+ button = MOUSE_DRAG;
+ /* TRACE(" move at x %d, y %d\n", x, y); */
+ }
+ else
+ {
+ ReleaseCapture();
+ button = MOUSE_RELEASE;
+ /* TRACE(" up at x %d, y %d\n", x, y); */
+ }
+
+ _OnMouseEvent(button, x, y, FALSE, keyFlags);
+}
+
+ static void
+_OnSizeTextArea(
+ HWND hwnd UNUSED,
+ UINT state UNUSED,
+ int cx UNUSED,
+ int cy UNUSED)
+{
+#if defined(FEAT_DIRECTX)
+ if (IS_ENABLE_DIRECTX())
+ directx_binddc();
+#endif
+}
+
+#ifdef FEAT_MENU
+/*
+ * Find the vimmenu_T with the given id
+ */
+ static vimmenu_T *
+gui_mswin_find_menu(
+ vimmenu_T *pMenu,
+ int id)
+{
+ vimmenu_T *pChildMenu;
+
+ while (pMenu)
+ {
+ if (pMenu->id == (UINT)id)
+ break;
+ if (pMenu->children != NULL)
+ {
+ pChildMenu = gui_mswin_find_menu(pMenu->children, id);
+ if (pChildMenu)
+ {
+ pMenu = pChildMenu;
+ break;
+ }
+ }
+ pMenu = pMenu->next;
+ }
+ return pMenu;
+}
+
+ static void
+_OnMenu(
+ HWND hwnd UNUSED,
+ int id,
+ HWND hwndCtl UNUSED,
+ UINT codeNotify UNUSED)
+{
+ vimmenu_T *pMenu;
+
+ pMenu = gui_mswin_find_menu(root_menu, id);
+ if (pMenu)
+ gui_menu_cb(pMenu);
+}
+#endif
+
+#ifdef MSWIN_FIND_REPLACE
+/*
+ * copy useful data from structure LPFINDREPLACE to structure LPFINDREPLACEW
+ */
+ static void
+findrep_atow(LPFINDREPLACEW lpfrw, LPFINDREPLACE lpfr)
+{
+ WCHAR *wp;
+
+ lpfrw->hwndOwner = lpfr->hwndOwner;
+ lpfrw->Flags = lpfr->Flags;
+
+ wp = enc_to_utf16((char_u *)lpfr->lpstrFindWhat, NULL);
+ wcsncpy(lpfrw->lpstrFindWhat, wp, lpfrw->wFindWhatLen - 1);
+ vim_free(wp);
+
+ /* the field "lpstrReplaceWith" doesn't need to be copied */
+}
+
+/*
+ * copy useful data from structure LPFINDREPLACEW to structure LPFINDREPLACE
+ */
+ static void
+findrep_wtoa(LPFINDREPLACE lpfr, LPFINDREPLACEW lpfrw)
+{
+ char_u *p;
+
+ lpfr->Flags = lpfrw->Flags;
+
+ p = utf16_to_enc((short_u*)lpfrw->lpstrFindWhat, NULL);
+ vim_strncpy((char_u *)lpfr->lpstrFindWhat, p, lpfr->wFindWhatLen - 1);
+ vim_free(p);
+
+ p = utf16_to_enc((short_u*)lpfrw->lpstrReplaceWith, NULL);
+ vim_strncpy((char_u *)lpfr->lpstrReplaceWith, p, lpfr->wReplaceWithLen - 1);
+ vim_free(p);
+}
+
+/*
+ * Handle a Find/Replace window message.
+ */
+ static void
+_OnFindRepl(void)
+{
+ int flags = 0;
+ int down;
+
+ /* If the OS is Windows NT, and 'encoding' differs from active codepage:
+ * convert text from wide string. */
+ if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+ {
+ findrep_wtoa(&s_findrep_struct, &s_findrep_struct_w);
+ }
+
+ if (s_findrep_struct.Flags & FR_DIALOGTERM)
+ /* Give main window the focus back. */
+ (void)SetFocus(s_hwnd);
+
+ if (s_findrep_struct.Flags & FR_FINDNEXT)
+ {
+ flags = FRD_FINDNEXT;
+
+ /* Give main window the focus back: this is so the cursor isn't
+ * hollow. */
+ (void)SetFocus(s_hwnd);
+ }
+ else if (s_findrep_struct.Flags & FR_REPLACE)
+ {
+ flags = FRD_REPLACE;
+
+ /* Give main window the focus back: this is so the cursor isn't
+ * hollow. */
+ (void)SetFocus(s_hwnd);
+ }
+ else if (s_findrep_struct.Flags & FR_REPLACEALL)
+ {
+ flags = FRD_REPLACEALL;
+ }
+
+ if (flags != 0)
+ {
+ /* Call the generic GUI function to do the actual work. */
+ if (s_findrep_struct.Flags & FR_WHOLEWORD)
+ flags |= FRD_WHOLE_WORD;
+ if (s_findrep_struct.Flags & FR_MATCHCASE)
+ flags |= FRD_MATCH_CASE;
+ down = (s_findrep_struct.Flags & FR_DOWN) != 0;
+ gui_do_findrepl(flags, (char_u *)s_findrep_struct.lpstrFindWhat,
+ (char_u *)s_findrep_struct.lpstrReplaceWith, down);
+ }
+}
+#endif
+
+ static void
+HandleMouseHide(UINT uMsg, LPARAM lParam)
+{
+ static LPARAM last_lParam = 0L;
+
+ /* We sometimes get a mousemove when the mouse didn't move... */
+ if (uMsg == WM_MOUSEMOVE || uMsg == WM_NCMOUSEMOVE)
+ {
+ if (lParam == last_lParam)
+ return;
+ last_lParam = lParam;
+ }
+
+ /* Handle specially, to centralise coding. We need to be sure we catch all
+ * possible events which should cause us to restore the cursor (as it is a
+ * shared resource, we take full responsibility for it).
+ */
+ switch (uMsg)
+ {
+ case WM_KEYUP:
+ case WM_CHAR:
+ /*
+ * blank out the pointer if necessary
+ */
+ if (p_mh)
+ gui_mch_mousehide(TRUE);
+ break;
+
+ case WM_SYSKEYUP: /* show the pointer when a system-key is pressed */
+ case WM_SYSCHAR:
+ case WM_MOUSEMOVE: /* show the pointer on any mouse action */
+ case WM_LBUTTONDOWN:
+ case WM_LBUTTONUP:
+ case WM_MBUTTONDOWN:
+ case WM_MBUTTONUP:
+ case WM_RBUTTONDOWN:
+ case WM_RBUTTONUP:
+ case WM_XBUTTONDOWN:
+ case WM_XBUTTONUP:
+ case WM_NCMOUSEMOVE:
+ case WM_NCLBUTTONDOWN:
+ case WM_NCLBUTTONUP:
+ case WM_NCMBUTTONDOWN:
+ case WM_NCMBUTTONUP:
+ case WM_NCRBUTTONDOWN:
+ case WM_NCRBUTTONUP:
+ case WM_KILLFOCUS:
+ /*
+ * if the pointer is currently hidden, then we should show it.
+ */
+ gui_mch_mousehide(FALSE);
+ break;
+ }
+}
+
+ static LRESULT CALLBACK
+_TextAreaWndProc(
+ HWND hwnd,
+ UINT uMsg,
+ WPARAM wParam,
+ LPARAM lParam)
+{
+ /*
+ TRACE("TextAreaWndProc: hwnd = %08x, msg = %x, wParam = %x, lParam = %x\n",
+ hwnd, uMsg, wParam, lParam);
+ */
+
+ HandleMouseHide(uMsg, lParam);
+
+ s_uMsg = uMsg;
+ s_wParam = wParam;
+ s_lParam = lParam;
+
+#ifdef FEAT_BEVAL_GUI
+ TrackUserActivity(uMsg);
+#endif
+
+ switch (uMsg)
+ {
+ HANDLE_MSG(hwnd, WM_LBUTTONDBLCLK,_OnMouseButtonDown);
+ HANDLE_MSG(hwnd, WM_LBUTTONDOWN,_OnMouseButtonDown);
+ HANDLE_MSG(hwnd, WM_LBUTTONUP, _OnMouseMoveOrRelease);
+ HANDLE_MSG(hwnd, WM_MBUTTONDBLCLK,_OnMouseButtonDown);
+ HANDLE_MSG(hwnd, WM_MBUTTONDOWN,_OnMouseButtonDown);
+ HANDLE_MSG(hwnd, WM_MBUTTONUP, _OnMouseMoveOrRelease);
+ HANDLE_MSG(hwnd, WM_MOUSEMOVE, _OnMouseMoveOrRelease);
+ HANDLE_MSG(hwnd, WM_PAINT, _OnPaint);
+ HANDLE_MSG(hwnd, WM_RBUTTONDBLCLK,_OnMouseButtonDown);
+ HANDLE_MSG(hwnd, WM_RBUTTONDOWN,_OnMouseButtonDown);
+ HANDLE_MSG(hwnd, WM_RBUTTONUP, _OnMouseMoveOrRelease);
+ HANDLE_MSG(hwnd, WM_XBUTTONDBLCLK,_OnMouseButtonDown);
+ HANDLE_MSG(hwnd, WM_XBUTTONDOWN,_OnMouseButtonDown);
+ HANDLE_MSG(hwnd, WM_XBUTTONUP, _OnMouseMoveOrRelease);
+ HANDLE_MSG(hwnd, WM_SIZE, _OnSizeTextArea);
+
+#ifdef FEAT_BEVAL_GUI
+ case WM_NOTIFY: Handle_WM_Notify(hwnd, (LPNMHDR)lParam);
+ return TRUE;
+#endif
+ default:
+ return MyWindowProc(hwnd, uMsg, wParam, lParam);
+ }
+}
+
+#ifdef PROTO
+typedef int WINAPI;
+#endif
+
+ LRESULT WINAPI
+vim_WindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+#ifdef GLOBAL_IME
+ return global_ime_DefWindowProc(hwnd, message, wParam, lParam);
+#else
+ if (wide_WindowProc)
+ return DefWindowProcW(hwnd, message, wParam, lParam);
+ return DefWindowProc(hwnd, message, wParam, lParam);
+#endif
+}
+
+/*
+ * Called when the foreground or background color has been changed.
+ */
+ void
+gui_mch_new_colors(void)
+{
+ /* nothing to do? */
+}
+
+/*
+ * Set the colors to their default values.
+ */
+ void
+gui_mch_def_colors(void)
+{
+ gui.norm_pixel = GetSysColor(COLOR_WINDOWTEXT);
+ gui.back_pixel = GetSysColor(COLOR_WINDOW);
+ gui.def_norm_pixel = gui.norm_pixel;
+ gui.def_back_pixel = gui.back_pixel;
+}
+
+/*
+ * Open the GUI window which was created by a call to gui_mch_init().
+ */
+ int
+gui_mch_open(void)
+{
+#ifndef SW_SHOWDEFAULT
+# define SW_SHOWDEFAULT 10 /* Borland 5.0 doesn't have it */
+#endif
+ /* Actually open the window, if not already visible
+ * (may be done already in gui_mch_set_shellsize) */
+ if (!IsWindowVisible(s_hwnd))
+ ShowWindow(s_hwnd, SW_SHOWDEFAULT);
+
+#ifdef MSWIN_FIND_REPLACE
+ /* Init replace string here, so that we keep it when re-opening the
+ * dialog. */
+ s_findrep_struct.lpstrReplaceWith[0] = NUL;
+#endif
+
+ return OK;
+}
+
+/*
+ * Get the position of the top left corner of the window.
+ */
+ int
+gui_mch_get_winpos(int *x, int *y)
+{
+ RECT rect;
+
+ GetWindowRect(s_hwnd, &rect);
+ *x = rect.left;
+ *y = rect.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)
+{
+ SetWindowPos(s_hwnd, NULL, x, y, 0, 0,
+ SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
+}
+ void
+gui_mch_set_text_area_pos(int x, int y, int w, int h)
+{
+ static int oldx = 0;
+ static int oldy = 0;
+
+ SetWindowPos(s_textArea, NULL, x, y, w, h, SWP_NOZORDER | SWP_NOACTIVATE);
+
+#ifdef FEAT_TOOLBAR
+ if (vim_strchr(p_go, GO_TOOLBAR) != NULL)
+ SendMessage(s_toolbarhwnd, WM_SIZE,
+ (WPARAM)0, (LPARAM)(w + ((long)(TOOLBAR_BUTTON_HEIGHT+8)<<16)));
+#endif
+#if defined(FEAT_GUI_TABLINE)
+ if (showing_tabline)
+ {
+ int top = 0;
+ RECT rect;
+
+# ifdef FEAT_TOOLBAR
+ if (vim_strchr(p_go, GO_TOOLBAR) != NULL)
+ top = TOOLBAR_BUTTON_HEIGHT + TOOLBAR_BORDER_HEIGHT;
+# endif
+ GetClientRect(s_hwnd, &rect);
+ MoveWindow(s_tabhwnd, 0, top, rect.right, gui.tabline_height, TRUE);
+ }
+#endif
+
+ /* When side scroll bar is unshown, the size of window will change.
+ * then, the text area move left or right. thus client rect should be
+ * forcedly redrawn. (Yasuhiro Matsumoto) */
+ if (oldx != x || oldy != y)
+ {
+ InvalidateRect(s_hwnd, NULL, FALSE);
+ oldx = x;
+ oldy = y;
+ }
+}
+
+
+/*
+ * Scrollbar stuff:
+ */
+
+ void
+gui_mch_enable_scrollbar(
+ scrollbar_T *sb,
+ int flag)
+{
+ ShowScrollBar(sb->id, SB_CTL, flag);
+
+ /* TODO: When the window is maximized, the size of the window stays the
+ * same, thus the size of the text area changes. On Win98 it's OK, on Win
+ * NT 4.0 it's not... */
+}
+
+ void
+gui_mch_set_scrollbar_pos(
+ scrollbar_T *sb,
+ int x,
+ int y,
+ int w,
+ int h)
+{
+ SetWindowPos(sb->id, NULL, x, y, w, h,
+ SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW);
+}
+
+ void
+gui_mch_create_scrollbar(
+ scrollbar_T *sb,
+ int orient) /* SBAR_VERT or SBAR_HORIZ */
+{
+ sb->id = CreateWindow(
+ "SCROLLBAR", "Scrollbar",
+ WS_CHILD | ((orient == SBAR_VERT) ? SBS_VERT : SBS_HORZ), 0, 0,
+ 10, /* Any value will do for now */
+ 10, /* Any value will do for now */
+ s_hwnd, NULL,
+ s_hinst, NULL);
+}
+
+/*
+ * Find the scrollbar with the given hwnd.
+ */
+ static scrollbar_T *
+gui_mswin_find_scrollbar(HWND hwnd)
+{
+ win_T *wp;
+
+ if (gui.bottom_sbar.id == hwnd)
+ return &gui.bottom_sbar;
+ FOR_ALL_WINDOWS(wp)
+ {
+ if (wp->w_scrollbars[SBAR_LEFT].id == hwnd)
+ return &wp->w_scrollbars[SBAR_LEFT];
+ if (wp->w_scrollbars[SBAR_RIGHT].id == hwnd)
+ return &wp->w_scrollbars[SBAR_RIGHT];
+ }
+ return NULL;
+}
+
+/*
+ * Get the character size of a font.
+ */
+ static void
+GetFontSize(GuiFont font)
+{
+ HWND hwnd = GetDesktopWindow();
+ HDC hdc = GetWindowDC(hwnd);
+ HFONT hfntOld = SelectFont(hdc, (HFONT)font);
+ TEXTMETRIC tm;
+
+ GetTextMetrics(hdc, &tm);
+ gui.char_width = tm.tmAveCharWidth + tm.tmOverhang;
+
+ gui.char_height = tm.tmHeight + p_linespace;
+
+ SelectFont(hdc, hfntOld);
+
+ ReleaseDC(hwnd, hdc);
+}
+
+/*
+ * Adjust gui.char_height (after 'linespace' was changed).
+ */
+ int
+gui_mch_adjust_charheight(void)
+{
+ GetFontSize(gui.norm_font);
+ return OK;
+}
+
+ static GuiFont
+get_font_handle(LOGFONT *lf)
+{
+ HFONT font = NULL;
+
+ /* Load the font */
+ font = CreateFontIndirect(lf);
+
+ if (font == NULL)
+ return NOFONT;
+
+ return (GuiFont)font;
+}
+
+ static int
+pixels_to_points(int pixels, int vertical)
+{
+ int points;
+ HWND hwnd;
+ HDC hdc;
+
+ hwnd = GetDesktopWindow();
+ hdc = GetWindowDC(hwnd);
+
+ points = MulDiv(pixels, 72,
+ GetDeviceCaps(hdc, vertical ? LOGPIXELSY : LOGPIXELSX));
+
+ ReleaseDC(hwnd, hdc);
+
+ return points;
+}
+
+ GuiFont
+gui_mch_get_font(
+ char_u *name,
+ int giveErrorIfMissing)
+{
+ LOGFONT lf;
+ GuiFont font = NOFONT;
+
+ if (get_logfont(&lf, name, NULL, giveErrorIfMissing) == OK)
+ font = get_font_handle(&lf);
+ if (font == NOFONT && giveErrorIfMissing)
+ semsg(_(e_font), name);
+ 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 UNUSED, char_u *name)
+{
+ if (name == NULL)
+ return NULL;
+ return vim_strsave(name);
+}
+#endif
+
+ void
+gui_mch_free_font(GuiFont font)
+{
+ if (font)
+ DeleteObject((HFONT)font);
+}
+
+/*
+ * Return the Pixel value (color) for the given color name.
+ * Return INVALCOLOR for error.
+ */
+ guicolor_T
+gui_mch_get_color(char_u *name)
+{
+ int i;
+
+ typedef struct SysColorTable
+ {
+ char *name;
+ int color;
+ } SysColorTable;
+
+ static SysColorTable sys_table[] =
+ {
+ {"SYS_3DDKSHADOW", COLOR_3DDKSHADOW},
+ {"SYS_3DHILIGHT", COLOR_3DHILIGHT},
+#ifdef COLOR_3DHIGHLIGHT
+ {"SYS_3DHIGHLIGHT", COLOR_3DHIGHLIGHT},
+#endif
+ {"SYS_BTNHILIGHT", COLOR_BTNHILIGHT},
+ {"SYS_BTNHIGHLIGHT", COLOR_BTNHIGHLIGHT},
+ {"SYS_3DLIGHT", COLOR_3DLIGHT},
+ {"SYS_3DSHADOW", COLOR_3DSHADOW},
+ {"SYS_DESKTOP", COLOR_DESKTOP},
+ {"SYS_INFOBK", COLOR_INFOBK},
+ {"SYS_INFOTEXT", COLOR_INFOTEXT},
+ {"SYS_3DFACE", COLOR_3DFACE},
+ {"SYS_BTNFACE", COLOR_BTNFACE},
+ {"SYS_BTNSHADOW", COLOR_BTNSHADOW},
+ {"SYS_ACTIVEBORDER", COLOR_ACTIVEBORDER},
+ {"SYS_ACTIVECAPTION", COLOR_ACTIVECAPTION},
+ {"SYS_APPWORKSPACE", COLOR_APPWORKSPACE},
+ {"SYS_BACKGROUND", COLOR_BACKGROUND},
+ {"SYS_BTNTEXT", COLOR_BTNTEXT},
+ {"SYS_CAPTIONTEXT", COLOR_CAPTIONTEXT},
+ {"SYS_GRAYTEXT", COLOR_GRAYTEXT},
+ {"SYS_HIGHLIGHT", COLOR_HIGHLIGHT},
+ {"SYS_HIGHLIGHTTEXT", COLOR_HIGHLIGHTTEXT},
+ {"SYS_INACTIVEBORDER", COLOR_INACTIVEBORDER},
+ {"SYS_INACTIVECAPTION", COLOR_INACTIVECAPTION},
+ {"SYS_INACTIVECAPTIONTEXT", COLOR_INACTIVECAPTIONTEXT},
+ {"SYS_MENU", COLOR_MENU},
+ {"SYS_MENUTEXT", COLOR_MENUTEXT},
+ {"SYS_SCROLLBAR", COLOR_SCROLLBAR},
+ {"SYS_WINDOW", COLOR_WINDOW},
+ {"SYS_WINDOWFRAME", COLOR_WINDOWFRAME},
+ {"SYS_WINDOWTEXT", COLOR_WINDOWTEXT}
+ };
+
+ /*
+ * Try to look up a system colour.
+ */
+ for (i = 0; i < sizeof(sys_table) / sizeof(sys_table[0]); i++)
+ if (STRICMP(name, sys_table[i].name) == 0)
+ return GetSysColor(sys_table[i].color);
+
+ 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);
+}
+
+/*
+ * 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].vim_code1 != NUL; 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)
+{
+ MessageBeep(MB_OK);
+}
+/*
+ * 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;
+
+#if defined(FEAT_DIRECTX)
+ if (IS_ENABLE_DIRECTX())
+ DWriteContext_Flush(s_dwc);
+#endif
+
+ /*
+ * 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(s_hdc, &rc);
+}
+
+/*
+ * Iconify the GUI window.
+ */
+ void
+gui_mch_iconify(void)
+{
+ ShowWindow(s_hwnd, SW_MINIMIZE);
+}
+
+/*
+ * Draw a cursor without focus.
+ */
+ void
+gui_mch_draw_hollow_cursor(guicolor_T color)
+{
+ HBRUSH hbr;
+ RECT rc;
+
+#if defined(FEAT_DIRECTX)
+ if (IS_ENABLE_DIRECTX())
+ DWriteContext_Flush(s_dwc);
+#endif
+
+ /*
+ * 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;
+ hbr = CreateSolidBrush(color);
+ FrameRect(s_hdc, &rc, hbr);
+ DeleteBrush(hbr);
+}
+/*
+ * Draw part of a cursor, "w" pixels wide, and "h" pixels high, using
+ * color "color".
+ */
+ void
+gui_mch_draw_part_cursor(
+ int w,
+ int h,
+ guicolor_T color)
+{
+ RECT rc;
+
+ /*
+ * Note: FillRect() excludes right and bottom of rectangle.
+ */
+ rc.left =
+#ifdef FEAT_RIGHTLEFT
+ /* vertical line should be on the right of current point */
+ CURSOR_BAR_RIGHT ? FILL_X(gui.col + 1) - w :
+#endif
+ FILL_X(gui.col);
+ rc.top = FILL_Y(gui.row) + gui.char_height - h;
+ rc.right = rc.left + w;
+ rc.bottom = rc.top + h;
+
+ fill_rect(&rc, NULL, color);
+}
+
+
+/*
+ * Generates a VK_SPACE when the internal dead_key flag is set to output the
+ * dead key's nominal character and re-post the original message.
+ */
+ static void
+outputDeadKey_rePost(MSG originalMsg)
+{
+ static MSG deadCharExpel;
+
+ if (!dead_key)
+ return;
+
+ dead_key = 0;
+
+ /* Make Windows generate the dead key's character */
+ deadCharExpel.message = originalMsg.message;
+ deadCharExpel.hwnd = originalMsg.hwnd;
+ deadCharExpel.wParam = VK_SPACE;
+
+ MyTranslateMessage(&deadCharExpel);
+
+ /* re-generate the current character free of the dead char influence */
+ PostMessage(originalMsg.hwnd, originalMsg.message, originalMsg.wParam,
+ originalMsg.lParam);
+}
+
+
+/*
+ * Process a single Windows message.
+ * If one is not available we hang until one is.
+ */
+ static void
+process_message(void)
+{
+ MSG msg;
+ UINT vk = 0; /* Virtual key */
+ char_u string[40];
+ int i;
+ int modifiers = 0;
+ int key;
+#ifdef FEAT_MENU
+ static char_u k10[] = {K_SPECIAL, 'k', ';', 0};
+#endif
+
+ pGetMessage(&msg, NULL, 0, 0);
+
+#ifdef FEAT_OLE
+ /* Look after OLE Automation commands */
+ if (msg.message == WM_OLE)
+ {
+ char_u *str = (char_u *)msg.lParam;
+ if (str == NULL || *str == NUL)
+ {
+ /* Message can't be ours, forward it. Fixes problem with Ultramon
+ * 3.0.4 */
+ pDispatchMessage(&msg);
+ }
+ else
+ {
+ add_to_input_buf(str, (int)STRLEN(str));
+ vim_free(str); /* was allocated in CVim::SendKeys() */
+ }
+ return;
+ }
+#endif
+
+#ifdef MSWIN_FIND_REPLACE
+ /* Don't process messages used by the dialog */
+ if (s_findrep_hwnd != NULL && pIsDialogMessage(s_findrep_hwnd, &msg))
+ {
+ HandleMouseHide(msg.message, msg.lParam);
+ return;
+ }
+#endif
+
+ /*
+ * Check if it's a special key that we recognise. If not, call
+ * TranslateMessage().
+ */
+ if (msg.message == WM_KEYDOWN || msg.message == WM_SYSKEYDOWN)
+ {
+ vk = (int) msg.wParam;
+
+ /*
+ * Handle dead keys in special conditions in other cases we let Windows
+ * handle them and do not interfere.
+ *
+ * The dead_key flag must be reset on several occasions:
+ * - in _OnChar() (or _OnSysChar()) as any dead key was necessarily
+ * consumed at that point (This is when we let Windows combine the
+ * dead character on its own)
+ *
+ * - Before doing something special such as regenerating keypresses to
+ * expel the dead character as this could trigger an infinite loop if
+ * for some reason MyTranslateMessage() do not trigger a call
+ * immediately to _OnChar() (or _OnSysChar()).
+ */
+ if (dead_key)
+ {
+ /*
+ * If a dead key was pressed and the user presses VK_SPACE,
+ * VK_BACK, or VK_ESCAPE it means that he actually wants to deal
+ * with the dead char now, so do nothing special and let Windows
+ * handle it.
+ *
+ * Note that VK_SPACE combines with the dead_key's character and
+ * only one WM_CHAR will be generated by TranslateMessage(), in
+ * the two other cases two WM_CHAR will be generated: the dead
+ * char and VK_BACK or VK_ESCAPE. That is most likely what the
+ * user expects.
+ */
+ if ((vk == VK_SPACE || vk == VK_BACK || vk == VK_ESCAPE))
+ {
+ dead_key = 0;
+ MyTranslateMessage(&msg);
+ return;
+ }
+ /* In modes where we are not typing, dead keys should behave
+ * normally */
+ else if (!(get_real_state() & (INSERT | CMDLINE | SELECTMODE)))
+ {
+ outputDeadKey_rePost(msg);
+ return;
+ }
+ }
+
+ /* Check for CTRL-BREAK */
+ if (vk == VK_CANCEL)
+ {
+ trash_input_buf();
+ got_int = TRUE;
+ ctrl_break_was_pressed = TRUE;
+ string[0] = Ctrl_C;
+ add_to_input_buf(string, 1);
+ }
+
+ for (i = 0; special_keys[i].key_sym != 0; i++)
+ {
+ /* ignore VK_SPACE when ALT key pressed: system menu */
+ if (special_keys[i].key_sym == vk
+ && (vk != VK_SPACE || !(GetKeyState(VK_MENU) & 0x8000)))
+ {
+ /*
+ * Behave as expected if we have a dead key and the special key
+ * is a key that would normally trigger the dead key nominal
+ * character output (such as a NUMPAD printable character or
+ * the TAB key, etc...).
+ */
+ if (dead_key && (special_keys[i].vim_code0 == 'K'
+ || vk == VK_TAB || vk == CAR))
+ {
+ outputDeadKey_rePost(msg);
+ return;
+ }
+
+#ifdef FEAT_MENU
+ /* Check for <F10>: Windows selects the menu. When <F10> is
+ * mapped we want to use the mapping instead. */
+ if (vk == VK_F10
+ && gui.menu_is_active
+ && check_map(k10, State, FALSE, TRUE, FALSE,
+ NULL, NULL) == NULL)
+ break;
+#endif
+ if (GetKeyState(VK_SHIFT) & 0x8000)
+ modifiers |= MOD_MASK_SHIFT;
+ /*
+ * Don't use caps-lock as shift, because these are special keys
+ * being considered here, and we only want letters to get
+ * shifted -- webb
+ */
+ /*
+ if (GetKeyState(VK_CAPITAL) & 0x0001)
+ modifiers ^= MOD_MASK_SHIFT;
+ */
+ if (GetKeyState(VK_CONTROL) & 0x8000)
+ modifiers |= MOD_MASK_CTRL;
+ if (GetKeyState(VK_MENU) & 0x8000)
+ modifiers |= MOD_MASK_ALT;
+
+ if (special_keys[i].vim_code1 == NUL)
+ key = special_keys[i].vim_code0;
+ else
+ key = TO_SPECIAL(special_keys[i].vim_code0,
+ special_keys[i].vim_code1);
+ key = simplify_key(key, &modifiers);
+ if (key == CSI)
+ key = K_CSI;
+
+ if (modifiers)
+ {
+ string[0] = CSI;
+ string[1] = KS_MODIFIER;
+ string[2] = modifiers;
+ add_to_input_buf(string, 3);
+ }
+
+ if (IS_SPECIAL(key))
+ {
+ string[0] = CSI;
+ string[1] = K_SECOND(key);
+ string[2] = K_THIRD(key);
+ add_to_input_buf(string, 3);
+ }
+ else
+ {
+ int len;
+
+ /* Handle "key" as a Unicode character. */
+ len = char_to_string(key, string, 40, FALSE);
+ add_to_input_buf(string, len);
+ }
+ break;
+ }
+ }
+ if (special_keys[i].key_sym == 0)
+ {
+ /* Some keys need C-S- where they should only need C-.
+ * Ignore 0xff, Windows XP sends it when NUMLOCK has changed since
+ * system startup (Helmut Stiegler, 2003 Oct 3). */
+ if (vk != 0xff
+ && (GetKeyState(VK_CONTROL) & 0x8000)
+ && !(GetKeyState(VK_SHIFT) & 0x8000)
+ && !(GetKeyState(VK_MENU) & 0x8000))
+ {
+ /* CTRL-6 is '^'; Japanese keyboard maps '^' to vk == 0xDE */
+ if (vk == '6' || MapVirtualKey(vk, 2) == (UINT)'^')
+ {
+ string[0] = Ctrl_HAT;
+ add_to_input_buf(string, 1);
+ }
+ /* vk == 0xBD AZERTY for CTRL-'-', but CTRL-[ for * QWERTY! */
+ else if (vk == 0xBD) /* QWERTY for CTRL-'-' */
+ {
+ string[0] = Ctrl__;
+ add_to_input_buf(string, 1);
+ }
+ /* CTRL-2 is '@'; Japanese keyboard maps '@' to vk == 0xC0 */
+ else if (vk == '2' || MapVirtualKey(vk, 2) == (UINT)'@')
+ {
+ string[0] = Ctrl_AT;
+ add_to_input_buf(string, 1);
+ }
+ else
+ MyTranslateMessage(&msg);
+ }
+ else
+ MyTranslateMessage(&msg);
+ }
+ }
+#ifdef FEAT_MBYTE_IME
+ else if (msg.message == WM_IME_NOTIFY)
+ _OnImeNotify(msg.hwnd, (DWORD)msg.wParam, (DWORD)msg.lParam);
+ else if (msg.message == WM_KEYUP && im_get_status())
+ /* added for non-MS IME (Yasuhiro Matsumoto) */
+ MyTranslateMessage(&msg);
+#endif
+#if !defined(FEAT_MBYTE_IME) && defined(GLOBAL_IME)
+/* GIME_TEST */
+ else if (msg.message == WM_IME_STARTCOMPOSITION)
+ {
+ POINT point;
+
+ global_ime_set_font(&norm_logfont);
+ point.x = FILL_X(gui.col);
+ point.y = FILL_Y(gui.row);
+ MapWindowPoints(s_textArea, s_hwnd, &point, 1);
+ global_ime_set_position(&point);
+ }
+#endif
+
+#ifdef FEAT_MENU
+ /* Check for <F10>: Default effect is to select the menu. When <F10> is
+ * mapped we need to stop it here to avoid strange effects (e.g., for the
+ * key-up event) */
+ if (vk != VK_F10 || check_map(k10, State, FALSE, TRUE, FALSE,
+ NULL, NULL) == NULL)
+#endif
+ pDispatchMessage(&msg);
+}
+
+/*
+ * Catch up with any queued events. This may put keyboard input into the
+ * input buffer, call resize call-backs, trigger timers etc. If there is
+ * nothing in the event queue (& no timers pending), then we return
+ * immediately.
+ */
+ void
+gui_mch_update(void)
+{
+ MSG msg;
+
+ if (!s_busy_processing)
+ while (pPeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)
+ && !vim_is_input_buf_full())
+ process_message();
+}
+
+ static void
+remove_any_timer(void)
+{
+ MSG msg;
+
+ if (s_wait_timer != 0 && !s_timed_out)
+ {
+ KillTimer(NULL, s_wait_timer);
+
+ /* Eat spurious WM_TIMER messages */
+ while (pPeekMessage(&msg, s_hwnd, WM_TIMER, WM_TIMER, PM_REMOVE))
+ ;
+ s_wait_timer = 0;
+ }
+}
+
+/*
+ * 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)
+{
+ int focus;
+
+ s_timed_out = FALSE;
+
+ if (wtime >= 0)
+ {
+ // Don't do anything while processing a (scroll) message.
+ if (s_busy_processing)
+ return FAIL;
+
+ // When called with "wtime" zero, just want one msec.
+ s_wait_timer = (UINT)SetTimer(NULL, 0, (UINT)(wtime == 0 ? 1 : wtime),
+ (TIMERPROC)_OnTimer);
+ }
+
+ allow_scrollbar = TRUE;
+
+ focus = gui.in_focus;
+ while (!s_timed_out)
+ {
+ /* Stop or start blinking when focus changes */
+ if (gui.in_focus != focus)
+ {
+ if (gui.in_focus)
+ gui_mch_start_blink();
+ else
+ gui_mch_stop_blink(TRUE);
+ focus = gui.in_focus;
+ }
+
+ if (s_need_activate)
+ {
+ (void)SetForegroundWindow(s_hwnd);
+ s_need_activate = FALSE;
+ }
+
+#ifdef FEAT_TIMERS
+ did_add_timer = FALSE;
+#endif
+#ifdef MESSAGE_QUEUE
+ /* Check channel I/O while waiting for a message. */
+ for (;;)
+ {
+ MSG msg;
+
+ parse_queued_messages();
+
+ if (pPeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
+ {
+ process_message();
+ break;
+ }
+ else if (MsgWaitForMultipleObjects(0, NULL, FALSE, 100, QS_ALLINPUT)
+ != WAIT_TIMEOUT)
+ break;
+ }
+#else
+ /*
+ * Don't use gui_mch_update() because then we will spin-lock until a
+ * char arrives, instead we use GetMessage() 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 -- webb
+ */
+ process_message();
+#endif
+
+ if (input_available())
+ {
+ remove_any_timer();
+ allow_scrollbar = FALSE;
+
+ /* Clear pending mouse button, the release event may have been
+ * taken by the dialog window. But don't do this when getting
+ * focus, we need the mouse-up event then. */
+ if (!s_getting_focus)
+ s_button_pending = -1;
+
+ return OK;
+ }
+
+#ifdef FEAT_TIMERS
+ if (did_add_timer)
+ {
+ /* Need to recompute the waiting time. */
+ remove_any_timer();
+ break;
+ }
+#endif
+ }
+ allow_scrollbar = FALSE;
+ return FAIL;
+}
+
+/*
+ * 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 window border.
+ * Note: FillRect() excludes right and bottom of rectangle.
+ */
+ 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);
+ clear_rect(&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;
+ clear_rect(&rc);
+}
+/*
+ * Menu stuff.
+ */
+
+ void
+gui_mch_enable_menu(int flag)
+{
+#ifdef FEAT_MENU
+ SetMenu(s_hwnd, flag ? s_menuBar : NULL);
+#endif
+}
+
+ void
+gui_mch_set_menu_pos(
+ int x UNUSED,
+ int y UNUSED,
+ int w UNUSED,
+ int h UNUSED)
+{
+ /* It will be in the right place anyway */
+}
+
+#if defined(FEAT_MENU) || defined(PROTO)
+/*
+ * Make menu item hidden or not hidden
+ */
+ void
+gui_mch_menu_hidden(
+ vimmenu_T *menu,
+ int hidden)
+{
+ /*
+ * This doesn't do what we want. Hmm, just grey the menu items for now.
+ */
+ /*
+ if (hidden)
+ EnableMenuItem(s_menuBar, menu->id, MF_BYCOMMAND | MF_DISABLED);
+ else
+ EnableMenuItem(s_menuBar, menu->id, MF_BYCOMMAND | MF_ENABLED);
+ */
+ 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(s_hwnd);
+}
+#endif /*FEAT_MENU*/
+
+#ifndef PROTO
+void
+#ifdef VIMDLL
+_export
+#endif
+_cdecl
+SaveInst(HINSTANCE hInst)
+{
+ s_hinst = hInst;
+}
+#endif
+
+/*
+ * Return the RGB value of a pixel as a long.
+ */
+ guicolor_T
+gui_mch_get_rgb(guicolor_T pixel)
+{
+ return (guicolor_T)((GetRValue(pixel) << 16) + (GetGValue(pixel) << 8)
+ + GetBValue(pixel));
+}
+
+#if defined(FEAT_GUI_DIALOG) || defined(PROTO)
+/* Convert pixels in X to dialog units */
+ static WORD
+PixelToDialogX(int numPixels)
+{
+ return (WORD)((numPixels * 4) / s_dlgfntwidth);
+}
+
+/* Convert pixels in Y to dialog units */
+ static WORD
+PixelToDialogY(int numPixels)
+{
+ return (WORD)((numPixels * 8) / s_dlgfntheight);
+}
+
+/* Return the width in pixels of the given text in the given DC. */
+ static int
+GetTextWidth(HDC hdc, char_u *str, int len)
+{
+ SIZE size;
+
+ GetTextExtentPoint(hdc, (LPCSTR)str, len, &size);
+ return size.cx;
+}
+
+/*
+ * Return the width in pixels of the given text in the given DC, taking care
+ * of 'encoding' to active codepage conversion.
+ */
+ static int
+GetTextWidthEnc(HDC hdc, char_u *str, int len)
+{
+ SIZE size;
+ WCHAR *wstr;
+ int n;
+ int wlen = len;
+
+ if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+ {
+ /* 'encoding' differs from active codepage: convert text and use wide
+ * function */
+ wstr = enc_to_utf16(str, &wlen);
+ if (wstr != NULL)
+ {
+ n = GetTextExtentPointW(hdc, wstr, wlen, &size);
+ vim_free(wstr);
+ if (n)
+ return size.cx;
+ }
+ }
+
+ return GetTextWidth(hdc, str, len);
+}
+
+static void get_work_area(RECT *spi_rect);
+
+/*
+ * A quick little routine that will center one window over another, handy for
+ * dialog boxes. Taken from the Win32SDK samples and modified for multiple
+ * monitors.
+ */
+ static BOOL
+CenterWindow(
+ HWND hwndChild,
+ HWND hwndParent)
+{
+ HMONITOR mon;
+ MONITORINFO moninfo;
+ RECT rChild, rParent, rScreen;
+ int wChild, hChild, wParent, hParent;
+ int xNew, yNew;
+ HDC hdc;
+
+ GetWindowRect(hwndChild, &rChild);
+ wChild = rChild.right - rChild.left;
+ hChild = rChild.bottom - rChild.top;
+
+ /* If Vim is minimized put the window in the middle of the screen. */
+ if (hwndParent == NULL || IsMinimized(hwndParent))
+ get_work_area(&rParent);
+ else
+ GetWindowRect(hwndParent, &rParent);
+ wParent = rParent.right - rParent.left;
+ hParent = rParent.bottom - rParent.top;
+
+ moninfo.cbSize = sizeof(MONITORINFO);
+ mon = MonitorFromWindow(hwndChild, MONITOR_DEFAULTTOPRIMARY);
+ if (mon != NULL && GetMonitorInfo(mon, &moninfo))
+ {
+ rScreen = moninfo.rcWork;
+ }
+ else
+ {
+ hdc = GetDC(hwndChild);
+ rScreen.left = 0;
+ rScreen.top = 0;
+ rScreen.right = GetDeviceCaps(hdc, HORZRES);
+ rScreen.bottom = GetDeviceCaps(hdc, VERTRES);
+ ReleaseDC(hwndChild, hdc);
+ }
+
+ xNew = rParent.left + ((wParent - wChild) / 2);
+ if (xNew < rScreen.left)
+ xNew = rScreen.left;
+ else if ((xNew + wChild) > rScreen.right)
+ xNew = rScreen.right - wChild;
+
+ yNew = rParent.top + ((hParent - hChild) / 2);
+ if (yNew < rScreen.top)
+ yNew = rScreen.top;
+ else if ((yNew + hChild) > rScreen.bottom)
+ yNew = rScreen.bottom - hChild;
+
+ return SetWindowPos(hwndChild, NULL, xNew, yNew, 0, 0,
+ SWP_NOSIZE | SWP_NOZORDER);
+}
+#endif /* FEAT_GUI_DIALOG */
+
+#if defined(FEAT_TOOLBAR) || defined(PROTO)
+ void
+gui_mch_show_toolbar(int showit)
+{
+ if (s_toolbarhwnd == NULL)
+ return;
+
+ if (showit)
+ {
+# ifndef TB_SETUNICODEFORMAT
+ /* For older compilers. We assume this never changes. */
+# define TB_SETUNICODEFORMAT 0x2005
+# endif
+ /* Enable/disable unicode support */
+ int uu = (enc_codepage >= 0 && (int)GetACP() != enc_codepage);
+ SendMessage(s_toolbarhwnd, TB_SETUNICODEFORMAT, (WPARAM)uu, (LPARAM)0);
+ ShowWindow(s_toolbarhwnd, SW_SHOW);
+ }
+ else
+ ShowWindow(s_toolbarhwnd, SW_HIDE);
+}
+
+/* Then number of bitmaps is fixed. Exit is missing! */
+#define TOOLBAR_BITMAP_COUNT 31
+
+#endif
+
+#if defined(FEAT_GUI_TABLINE) || defined(PROTO)
+ static void
+add_tabline_popup_menu_entry(HMENU pmenu, UINT item_id, char_u *item_text)
+{
+ WCHAR *wn = NULL;
+
+ if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+ {
+ /* 'encoding' differs from active codepage: convert menu name
+ * and use wide function */
+ wn = enc_to_utf16(item_text, NULL);
+ if (wn != NULL)
+ {
+ MENUITEMINFOW infow;
+
+ infow.cbSize = sizeof(infow);
+ infow.fMask = MIIM_TYPE | MIIM_ID;
+ infow.wID = item_id;
+ infow.fType = MFT_STRING;
+ infow.dwTypeData = wn;
+ infow.cch = (UINT)wcslen(wn);
+ InsertMenuItemW(pmenu, item_id, FALSE, &infow);
+ vim_free(wn);
+ }
+ }
+
+ if (wn == NULL)
+ {
+ MENUITEMINFO info;
+
+ info.cbSize = sizeof(info);
+ info.fMask = MIIM_TYPE | MIIM_ID;
+ info.wID = item_id;
+ info.fType = MFT_STRING;
+ info.dwTypeData = (LPTSTR)item_text;
+ info.cch = (UINT)STRLEN(item_text);
+ InsertMenuItem(pmenu, item_id, FALSE, &info);
+ }
+}
+
+ static void
+show_tabline_popup_menu(void)
+{
+ HMENU tab_pmenu;
+ long rval;
+ POINT pt;
+
+ /* When ignoring events don't show the menu. */
+ if (hold_gui_events
+# ifdef FEAT_CMDWIN
+ || cmdwin_type != 0
+# endif
+ )
+ return;
+
+ tab_pmenu = CreatePopupMenu();
+ if (tab_pmenu == NULL)
+ return;
+
+ if (first_tabpage->tp_next != NULL)
+ add_tabline_popup_menu_entry(tab_pmenu,
+ TABLINE_MENU_CLOSE, (char_u *)_("Close tab"));
+ add_tabline_popup_menu_entry(tab_pmenu,
+ TABLINE_MENU_NEW, (char_u *)_("New tab"));
+ add_tabline_popup_menu_entry(tab_pmenu,
+ TABLINE_MENU_OPEN, (char_u *)_("Open tab..."));
+
+ GetCursorPos(&pt);
+ rval = TrackPopupMenuEx(tab_pmenu, TPM_RETURNCMD, pt.x, pt.y, s_tabhwnd,
+ NULL);
+
+ DestroyMenu(tab_pmenu);
+
+ /* Add the string cmd into input buffer */
+ if (rval > 0)
+ {
+ TCHITTESTINFO htinfo;
+ int idx;
+
+ if (ScreenToClient(s_tabhwnd, &pt) == 0)
+ return;
+
+ htinfo.pt.x = pt.x;
+ htinfo.pt.y = pt.y;
+ idx = TabCtrl_HitTest(s_tabhwnd, &htinfo);
+ if (idx == -1)
+ idx = 0;
+ else
+ idx += 1;
+
+ send_tabline_menu_event(idx, (int)rval);
+ }
+}
+
+/*
+ * Show or hide the tabline.
+ */
+ void
+gui_mch_show_tabline(int showit)
+{
+ if (s_tabhwnd == NULL)
+ return;
+
+ if (!showit != !showing_tabline)
+ {
+ if (showit)
+ ShowWindow(s_tabhwnd, SW_SHOW);
+ else
+ ShowWindow(s_tabhwnd, SW_HIDE);
+ showing_tabline = showit;
+ }
+}
+
+/*
+ * Return TRUE when tabline is displayed.
+ */
+ int
+gui_mch_showing_tabline(void)
+{
+ return s_tabhwnd != NULL && showing_tabline;
+}
+
+/*
+ * Update the labels of the tabline.
+ */
+ void
+gui_mch_update_tabline(void)
+{
+ tabpage_T *tp;
+ TCITEM tie;
+ int nr = 0;
+ int curtabidx = 0;
+ int tabadded = 0;
+ static int use_unicode = FALSE;
+ int uu;
+ WCHAR *wstr = NULL;
+
+ if (s_tabhwnd == NULL)
+ return;
+
+#ifndef CCM_SETUNICODEFORMAT
+ /* For older compilers. We assume this never changes. */
+# define CCM_SETUNICODEFORMAT 0x2005
+#endif
+ uu = (enc_codepage >= 0 && (int)GetACP() != enc_codepage);
+ if (uu != use_unicode)
+ {
+ /* Enable/disable unicode support */
+ SendMessage(s_tabhwnd, CCM_SETUNICODEFORMAT, (WPARAM)uu, (LPARAM)0);
+ use_unicode = uu;
+ }
+
+ tie.mask = TCIF_TEXT;
+ tie.iImage = -1;
+
+ /* Disable redraw for tab updates to eliminate O(N^2) draws. */
+ SendMessage(s_tabhwnd, WM_SETREDRAW, (WPARAM)FALSE, 0);
+
+ /* Add a label for each tab page. They all contain the same text area. */
+ for (tp = first_tabpage; tp != NULL; tp = tp->tp_next, ++nr)
+ {
+ if (tp == curtab)
+ curtabidx = nr;
+
+ if (nr >= TabCtrl_GetItemCount(s_tabhwnd))
+ {
+ /* Add the tab */
+ tie.pszText = "-Empty-";
+ TabCtrl_InsertItem(s_tabhwnd, nr, &tie);
+ tabadded = 1;
+ }
+
+ get_tabline_label(tp, FALSE);
+ tie.pszText = (LPSTR)NameBuff;
+ wstr = NULL;
+ if (use_unicode)
+ {
+ /* Need to go through Unicode. */
+ wstr = enc_to_utf16(NameBuff, NULL);
+ if (wstr != NULL)
+ {
+ TCITEMW tiw;
+
+ tiw.mask = TCIF_TEXT;
+ tiw.iImage = -1;
+ tiw.pszText = wstr;
+ SendMessage(s_tabhwnd, TCM_SETITEMW, (WPARAM)nr, (LPARAM)&tiw);
+ vim_free(wstr);
+ }
+ }
+ if (wstr == NULL)
+ {
+ TabCtrl_SetItem(s_tabhwnd, nr, &tie);
+ }
+ }
+
+ /* Remove any old labels. */
+ while (nr < TabCtrl_GetItemCount(s_tabhwnd))
+ TabCtrl_DeleteItem(s_tabhwnd, nr);
+
+ if (!tabadded && TabCtrl_GetCurSel(s_tabhwnd) != curtabidx)
+ TabCtrl_SetCurSel(s_tabhwnd, curtabidx);
+
+ /* Re-enable redraw and redraw. */
+ SendMessage(s_tabhwnd, WM_SETREDRAW, (WPARAM)TRUE, 0);
+ RedrawWindow(s_tabhwnd, NULL, NULL,
+ RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
+
+ if (tabadded && TabCtrl_GetCurSel(s_tabhwnd) != curtabidx)
+ TabCtrl_SetCurSel(s_tabhwnd, curtabidx);
+}
+
+/*
+ * Set the current tab to "nr". First tab is 1.
+ */
+ void
+gui_mch_set_curtab(int nr)
+{
+ if (s_tabhwnd == NULL)
+ return;
+
+ if (TabCtrl_GetCurSel(s_tabhwnd) != nr - 1)
+ TabCtrl_SetCurSel(s_tabhwnd, nr - 1);
+}
+
+#endif
+
+/*
+ * ":simalt" command.
+ */
+ void
+ex_simalt(exarg_T *eap)
+{
+ char_u *keys = eap->arg;
+ int fill_typebuf = FALSE;
+ char_u key_name[4];
+
+ PostMessage(s_hwnd, WM_SYSCOMMAND, (WPARAM)SC_KEYMENU, (LPARAM)0);
+ while (*keys)
+ {
+ if (*keys == '~')
+ *keys = ' '; /* for showing system menu */
+ PostMessage(s_hwnd, WM_CHAR, (WPARAM)*keys, (LPARAM)0);
+ keys++;
+ fill_typebuf = TRUE;
+ }
+ if (fill_typebuf)
+ {
+ /* Put a NOP in the typeahead buffer so that the message will get
+ * processed. */
+ key_name[0] = K_SPECIAL;
+ key_name[1] = KS_EXTRA;
+ key_name[2] = KE_NOP;
+ key_name[3] = NUL;
+ typebuf_was_filled = TRUE;
+ (void)ins_typebuf(key_name, REMAP_NONE, 0, TRUE, FALSE);
+ }
+}
+
+/*
+ * Create the find & replace dialogs.
+ * You can't have both at once: ":find" when replace is showing, destroys
+ * the replace dialog first, and the other way around.
+ */
+#ifdef MSWIN_FIND_REPLACE
+ static void
+initialise_findrep(char_u *initial_string)
+{
+ int wword = FALSE;
+ int mcase = !p_ic;
+ char_u *entry_text;
+
+ /* Get the search string to use. */
+ entry_text = get_find_dialog_text(initial_string, &wword, &mcase);
+
+ s_findrep_struct.hwndOwner = s_hwnd;
+ s_findrep_struct.Flags = FR_DOWN;
+ if (mcase)
+ s_findrep_struct.Flags |= FR_MATCHCASE;
+ if (wword)
+ s_findrep_struct.Flags |= FR_WHOLEWORD;
+ if (entry_text != NULL && *entry_text != NUL)
+ vim_strncpy((char_u *)s_findrep_struct.lpstrFindWhat, entry_text,
+ s_findrep_struct.wFindWhatLen - 1);
+ vim_free(entry_text);
+}
+#endif
+
+ static void
+set_window_title(HWND hwnd, char *title)
+{
+ if (title != NULL && enc_codepage >= 0 && enc_codepage != (int)GetACP())
+ {
+ WCHAR *wbuf;
+
+ /* Convert the title from 'encoding' to UTF-16. */
+ wbuf = (WCHAR *)enc_to_utf16((char_u *)title, NULL);
+ if (wbuf != NULL)
+ {
+ SetWindowTextW(hwnd, wbuf);
+ vim_free(wbuf);
+ }
+ return;
+ }
+ (void)SetWindowText(hwnd, (LPCSTR)title);
+}
+
+ void
+gui_mch_find_dialog(exarg_T *eap)
+{
+#ifdef MSWIN_FIND_REPLACE
+ if (s_findrep_msg != 0)
+ {
+ if (IsWindow(s_findrep_hwnd) && !s_findrep_is_find)
+ DestroyWindow(s_findrep_hwnd);
+
+ if (!IsWindow(s_findrep_hwnd))
+ {
+ initialise_findrep(eap->arg);
+ /* If the OS is Windows NT, and 'encoding' differs from active
+ * codepage: convert text and use wide function. */
+ if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+ {
+ findrep_atow(&s_findrep_struct_w, &s_findrep_struct);
+ s_findrep_hwnd = FindTextW(
+ (LPFINDREPLACEW) &s_findrep_struct_w);
+ }
+ else
+ s_findrep_hwnd = FindText((LPFINDREPLACE) &s_findrep_struct);
+ }
+
+ set_window_title(s_findrep_hwnd, _("Find string"));
+ (void)SetFocus(s_findrep_hwnd);
+
+ s_findrep_is_find = TRUE;
+ }
+#endif
+}
+
+
+ void
+gui_mch_replace_dialog(exarg_T *eap)
+{
+#ifdef MSWIN_FIND_REPLACE
+ if (s_findrep_msg != 0)
+ {
+ if (IsWindow(s_findrep_hwnd) && s_findrep_is_find)
+ DestroyWindow(s_findrep_hwnd);
+
+ if (!IsWindow(s_findrep_hwnd))
+ {
+ initialise_findrep(eap->arg);
+ if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+ {
+ findrep_atow(&s_findrep_struct_w, &s_findrep_struct);
+ s_findrep_hwnd = ReplaceTextW(
+ (LPFINDREPLACEW) &s_findrep_struct_w);
+ }
+ else
+ s_findrep_hwnd = ReplaceText(
+ (LPFINDREPLACE) &s_findrep_struct);
+ }
+
+ set_window_title(s_findrep_hwnd, _("Find & Replace"));
+ (void)SetFocus(s_findrep_hwnd);
+
+ s_findrep_is_find = FALSE;
+ }
+#endif
+}
+
+
+/*
+ * Set visibility of the pointer.
+ */
+ void
+gui_mch_mousehide(int hide)
+{
+ if (hide != gui.pointer_hidden)
+ {
+ ShowCursor(!hide);
+ gui.pointer_hidden = hide;
+ }
+}
+
+#ifdef FEAT_MENU
+ static void
+gui_mch_show_popupmenu_at(vimmenu_T *menu, int x, int y)
+{
+ /* Unhide the mouse, we don't get move events here. */
+ gui_mch_mousehide(FALSE);
+
+ (void)TrackPopupMenu(
+ (HMENU)menu->submenu_id,
+ TPM_LEFTALIGN | TPM_LEFTBUTTON,
+ x, y,
+ (int)0, /*reserved param*/
+ s_hwnd,
+ NULL);
+ /*
+ * NOTE: The pop-up menu can eat the mouse up event.
+ * We deal with this in normal.c.
+ */
+}
+#endif
+
+/*
+ * Got a message when the system will go down.
+ */
+ static void
+_OnEndSession(void)
+{
+ getout_preserve_modified(1);
+}
+
+/*
+ * Get this message when the user clicks on the cross in the top right corner
+ * of a Windows95 window.
+ */
+ static void
+_OnClose(HWND hwnd UNUSED)
+{
+ gui_shell_closed();
+}
+
+/*
+ * Get a message when the window is being destroyed.
+ */
+ static void
+_OnDestroy(HWND hwnd)
+{
+ if (!destroying)
+ _OnClose(hwnd);
+}
+
+ static void
+_OnPaint(
+ HWND hwnd)
+{
+ if (!IsMinimized(hwnd))
+ {
+ PAINTSTRUCT ps;
+
+ out_flush(); /* make sure all output has been processed */
+ (void)BeginPaint(hwnd, &ps);
+
+ /* prevent multi-byte characters from misprinting on an invalid
+ * rectangle */
+ if (has_mbyte)
+ {
+ RECT rect;
+
+ GetClientRect(hwnd, &rect);
+ ps.rcPaint.left = rect.left;
+ ps.rcPaint.right = rect.right;
+ }
+
+ if (!IsRectEmpty(&ps.rcPaint))
+ {
+ gui_redraw(ps.rcPaint.left, ps.rcPaint.top,
+ ps.rcPaint.right - ps.rcPaint.left + 1,
+ ps.rcPaint.bottom - ps.rcPaint.top + 1);
+ }
+
+ EndPaint(hwnd, &ps);
+ }
+}
+
+ static void
+_OnSize(
+ HWND hwnd,
+ UINT state UNUSED,
+ int cx,
+ int cy)
+{
+ if (!IsMinimized(hwnd))
+ {
+ gui_resize_shell(cx, cy);
+
+#ifdef FEAT_MENU
+ /* Menu bar may wrap differently now */
+ gui_mswin_get_menu_height(TRUE);
+#endif
+ }
+}
+
+ static void
+_OnSetFocus(
+ HWND hwnd,
+ HWND hwndOldFocus)
+{
+ gui_focus_change(TRUE);
+ s_getting_focus = TRUE;
+ (void)MyWindowProc(hwnd, WM_SETFOCUS, (WPARAM)hwndOldFocus, 0);
+}
+
+ static void
+_OnKillFocus(
+ HWND hwnd,
+ HWND hwndNewFocus)
+{
+ gui_focus_change(FALSE);
+ s_getting_focus = FALSE;
+ (void)MyWindowProc(hwnd, WM_KILLFOCUS, (WPARAM)hwndNewFocus, 0);
+}
+
+/*
+ * Get a message when the user switches back to vim
+ */
+ static LRESULT
+_OnActivateApp(
+ HWND hwnd,
+ BOOL fActivate,
+ DWORD dwThreadId)
+{
+ /* we call gui_focus_change() in _OnSetFocus() */
+ /* gui_focus_change((int)fActivate); */
+ return MyWindowProc(hwnd, WM_ACTIVATEAPP, fActivate, (DWORD)dwThreadId);
+}
+
+ void
+gui_mch_destroy_scrollbar(scrollbar_T *sb)
+{
+ DestroyWindow(sb->id);
+}
+
+/*
+ * Get current mouse coordinates in text window.
+ */
+ void
+gui_mch_getmouse(int *x, int *y)
+{
+ RECT rct;
+ POINT mp;
+
+ (void)GetWindowRect(s_textArea, &rct);
+ (void)GetCursorPos((LPPOINT)&mp);
+ *x = (int)(mp.x - rct.left);
+ *y = (int)(mp.y - rct.top);
+}
+
+/*
+ * Move mouse pointer to character at (x, y).
+ */
+ void
+gui_mch_setmouse(int x, int y)
+{
+ RECT rct;
+
+ (void)GetWindowRect(s_textArea, &rct);
+ (void)SetCursorPos(x + gui.border_offset + rct.left,
+ y + gui.border_offset + rct.top);
+}
+
+ static void
+gui_mswin_get_valid_dimensions(
+ int w,
+ int h,
+ int *valid_w,
+ int *valid_h)
+{
+ int base_width, base_height;
+
+ base_width = gui_get_base_width()
+ + (GetSystemMetrics(SM_CXFRAME) +
+ GetSystemMetrics(SM_CXPADDEDBORDER)) * 2;
+ base_height = gui_get_base_height()
+ + (GetSystemMetrics(SM_CYFRAME) +
+ GetSystemMetrics(SM_CXPADDEDBORDER)) * 2
+ + GetSystemMetrics(SM_CYCAPTION)
+#ifdef FEAT_MENU
+ + gui_mswin_get_menu_height(FALSE)
+#endif
+ ;
+ *valid_w = base_width +
+ ((w - base_width) / gui.char_width) * gui.char_width;
+ *valid_h = base_height +
+ ((h - base_height) / gui.char_height) * gui.char_height;
+}
+
+ void
+gui_mch_flash(int msec)
+{
+ RECT rc;
+
+#if defined(FEAT_DIRECTX)
+ if (IS_ENABLE_DIRECTX())
+ DWriteContext_Flush(s_dwc);
+#endif
+
+ /*
+ * 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(s_hdc, &rc);
+ gui_mch_flush(); /* make sure it's displayed */
+
+ ui_delay((long)msec, TRUE); /* wait for a few msec */
+
+ InvertRect(s_hdc, &rc);
+}
+
+/*
+ * Return flags used for scrolling.
+ * The SW_INVALIDATE is required when part of the window is covered or
+ * off-screen. Refer to MS KB Q75236.
+ */
+ static int
+get_scroll_flags(void)
+{
+ HWND hwnd;
+ RECT rcVim, rcOther, rcDest;
+
+ GetWindowRect(s_hwnd, &rcVim);
+
+ /* Check if the window is partly above or below the screen. We don't care
+ * about partly left or right of the screen, it is not relevant when
+ * scrolling up or down. */
+ if (rcVim.top < 0 || rcVim.bottom > GetSystemMetrics(SM_CYFULLSCREEN))
+ return SW_INVALIDATE;
+
+ /* Check if there is an window (partly) on top of us. */
+ for (hwnd = s_hwnd; (hwnd = GetWindow(hwnd, GW_HWNDPREV)) != (HWND)0; )
+ if (IsWindowVisible(hwnd))
+ {
+ GetWindowRect(hwnd, &rcOther);
+ if (IntersectRect(&rcDest, &rcVim, &rcOther))
+ return SW_INVALIDATE;
+ }
+ return 0;
+}
+
+/*
+ * On some Intel GPUs, the regions drawn just prior to ScrollWindowEx()
+ * may not be scrolled out properly.
+ * For gVim, when _OnScroll() is repeated, the character at the
+ * previous cursor position may be left drawn after scroll.
+ * The problem can be avoided by calling GetPixel() to get a pixel in
+ * the region before ScrollWindowEx().
+ */
+ static void
+intel_gpu_workaround(void)
+{
+ GetPixel(s_hdc, FILL_X(gui.col), FILL_Y(gui.row));
+}
+
+/*
+ * 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;
+
+ 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);
+
+#if defined(FEAT_DIRECTX)
+ if (IS_ENABLE_DIRECTX())
+ {
+ DWriteContext_Scroll(s_dwc, 0, -num_lines * gui.char_height, &rc);
+ DWriteContext_Flush(s_dwc);
+ }
+ else
+#endif
+ {
+ intel_gpu_workaround();
+ ScrollWindowEx(s_textArea, 0, -num_lines * gui.char_height,
+ &rc, &rc, NULL, NULL, get_scroll_flags());
+ UpdateWindow(s_textArea);
+ }
+
+ /* This seems to be required to avoid the cursor disappearing when
+ * scrolling such that the cursor ends up in the top-left character on
+ * the screen... But why? (Webb) */
+ /* It's probably fixed by disabling drawing the cursor while scrolling. */
+ /* gui.cursor_is_valid = FALSE; */
+
+ 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);
+
+#if defined(FEAT_DIRECTX)
+ if (IS_ENABLE_DIRECTX())
+ {
+ DWriteContext_Scroll(s_dwc, 0, num_lines * gui.char_height, &rc);
+ DWriteContext_Flush(s_dwc);
+ }
+ else
+#endif
+ {
+ intel_gpu_workaround();
+ /* The SW_INVALIDATE is required when part of the window is covered or
+ * off-screen. How do we avoid it when it's not needed? */
+ ScrollWindowEx(s_textArea, 0, num_lines * gui.char_height,
+ &rc, &rc, NULL, NULL, get_scroll_flags());
+ UpdateWindow(s_textArea);
+ }
+
+ gui_clear_block(row, gui.scroll_region_left,
+ row + num_lines - 1, gui.scroll_region_right);
+}
+
+
+ void
+gui_mch_exit(int rc UNUSED)
+{
+#if defined(FEAT_DIRECTX)
+ DWriteContext_Close(s_dwc);
+ DWrite_Final();
+ s_dwc = NULL;
+#endif
+
+ ReleaseDC(s_textArea, s_hdc);
+ DeleteObject(s_brush);
+
+#ifdef FEAT_TEAROFF
+ /* Unload the tearoff bitmap */
+ (void)DeleteObject((HGDIOBJ)s_htearbitmap);
+#endif
+
+ /* Destroy our window (if we have one). */
+ if (s_hwnd != NULL)
+ {
+ destroying = TRUE; /* ignore WM_DESTROY message now */
+ DestroyWindow(s_hwnd);
+ }
+
+#ifdef GLOBAL_IME
+ global_ime_end();
+#endif
+}
+
+ static char_u *
+logfont2name(LOGFONT lf)
+{
+ char *p;
+ char *res;
+ char *charset_name;
+ char *quality_name;
+ char *font_name = lf.lfFaceName;
+
+ charset_name = charset_id2name((int)lf.lfCharSet);
+ /* Convert a font name from the current codepage to 'encoding'.
+ * TODO: Use Wide APIs (including LOGFONTW) instead of ANSI APIs. */
+ if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+ {
+ int len;
+ acp_to_enc((char_u *)lf.lfFaceName, (int)strlen(lf.lfFaceName),
+ (char_u **)&font_name, &len);
+ }
+ quality_name = quality_id2name((int)lf.lfQuality);
+
+ res = (char *)alloc((unsigned)(strlen(font_name) + 20
+ + (charset_name == NULL ? 0 : strlen(charset_name) + 2)));
+ if (res != NULL)
+ {
+ p = res;
+ /* make a normal font string out of the lf thing:*/
+ sprintf((char *)p, "%s:h%d", font_name, pixels_to_points(
+ lf.lfHeight < 0 ? -lf.lfHeight : lf.lfHeight, TRUE));
+ while (*p)
+ {
+ if (*p == ' ')
+ *p = '_';
+ ++p;
+ }
+ if (lf.lfItalic)
+ STRCAT(p, ":i");
+ if (lf.lfWeight >= FW_BOLD)
+ STRCAT(p, ":b");
+ if (lf.lfUnderline)
+ STRCAT(p, ":u");
+ if (lf.lfStrikeOut)
+ STRCAT(p, ":s");
+ if (charset_name != NULL)
+ {
+ STRCAT(p, ":c");
+ STRCAT(p, charset_name);
+ }
+ if (quality_name != NULL)
+ {
+ STRCAT(p, ":q");
+ STRCAT(p, quality_name);
+ }
+ }
+
+ if (font_name != lf.lfFaceName)
+ vim_free(font_name);
+ return (char_u *)res;
+}
+
+
+#ifdef FEAT_MBYTE_IME
+/*
+ * Set correct LOGFONT to IME. Use 'guifontwide' if available, otherwise use
+ * 'guifont'
+ */
+ static void
+update_im_font(void)
+{
+ LOGFONT lf_wide;
+
+ if (p_guifontwide != NULL && *p_guifontwide != NUL
+ && gui.wide_font != NOFONT
+ && GetObject((HFONT)gui.wide_font, sizeof(lf_wide), &lf_wide))
+ norm_logfont = lf_wide;
+ else
+ norm_logfont = sub_logfont;
+ im_set_font(&norm_logfont);
+}
+#endif
+
+/*
+ * Handler of gui.wide_font (p_guifontwide) changed notification.
+ */
+ void
+gui_mch_wide_font_changed(void)
+{
+ LOGFONT lf;
+
+#ifdef FEAT_MBYTE_IME
+ update_im_font();
+#endif
+
+ gui_mch_free_font(gui.wide_ital_font);
+ gui.wide_ital_font = NOFONT;
+ gui_mch_free_font(gui.wide_bold_font);
+ gui.wide_bold_font = NOFONT;
+ gui_mch_free_font(gui.wide_boldital_font);
+ gui.wide_boldital_font = NOFONT;
+
+ if (gui.wide_font
+ && GetObject((HFONT)gui.wide_font, sizeof(lf), &lf))
+ {
+ if (!lf.lfItalic)
+ {
+ lf.lfItalic = TRUE;
+ gui.wide_ital_font = get_font_handle(&lf);
+ lf.lfItalic = FALSE;
+ }
+ if (lf.lfWeight < FW_BOLD)
+ {
+ lf.lfWeight = FW_BOLD;
+ gui.wide_bold_font = get_font_handle(&lf);
+ if (!lf.lfItalic)
+ {
+ lf.lfItalic = TRUE;
+ gui.wide_boldital_font = get_font_handle(&lf);
+ }
+ }
+ }
+}
+
+/*
+ * 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 UNUSED)
+{
+ LOGFONT lf;
+ GuiFont font = NOFONT;
+ char_u *p;
+
+ /* Load the font */
+ if (get_logfont(&lf, font_name, NULL, TRUE) == OK)
+ font = get_font_handle(&lf);
+ if (font == NOFONT)
+ return FAIL;
+
+ if (font_name == NULL)
+ font_name = (char_u *)lf.lfFaceName;
+#if defined(FEAT_MBYTE_IME) || defined(GLOBAL_IME)
+ norm_logfont = lf;
+#endif
+#ifdef FEAT_MBYTE_IME
+ sub_logfont = lf;
+#endif
+#ifdef FEAT_MBYTE_IME
+ update_im_font();
+#endif
+ gui_mch_free_font(gui.norm_font);
+ gui.norm_font = font;
+ current_font_height = lf.lfHeight;
+ GetFontSize(font);
+
+ p = logfont2name(lf);
+ if (p != NULL)
+ {
+ hl_set_font_name(p);
+
+ /* When setting 'guifont' to "*" replace it with the actual font name.
+ * */
+ if (STRCMP(font_name, "*") == 0 && STRCMP(p_guifont, "*") == 0)
+ {
+ vim_free(p_guifont);
+ p_guifont = p;
+ }
+ else
+ vim_free(p);
+ }
+
+ gui_mch_free_font(gui.ital_font);
+ gui.ital_font = NOFONT;
+ gui_mch_free_font(gui.bold_font);
+ gui.bold_font = NOFONT;
+ gui_mch_free_font(gui.boldital_font);
+ gui.boldital_font = NOFONT;
+
+ if (!lf.lfItalic)
+ {
+ lf.lfItalic = TRUE;
+ gui.ital_font = get_font_handle(&lf);
+ lf.lfItalic = FALSE;
+ }
+ if (lf.lfWeight < FW_BOLD)
+ {
+ lf.lfWeight = FW_BOLD;
+ gui.bold_font = get_font_handle(&lf);
+ if (!lf.lfItalic)
+ {
+ lf.lfItalic = TRUE;
+ gui.boldital_font = get_font_handle(&lf);
+ }
+ }
+
+ return OK;
+}
+
+#ifndef WPF_RESTORETOMAXIMIZED
+# define WPF_RESTORETOMAXIMIZED 2 /* just in case someone doesn't have it */
+#endif
+
+/*
+ * Return TRUE if the GUI window is maximized, filling the whole screen.
+ */
+ int
+gui_mch_maximized(void)
+{
+ WINDOWPLACEMENT wp;
+
+ wp.length = sizeof(WINDOWPLACEMENT);
+ if (GetWindowPlacement(s_hwnd, &wp))
+ return wp.showCmd == SW_SHOWMAXIMIZED
+ || (wp.showCmd == SW_SHOWMINIMIZED
+ && wp.flags == WPF_RESTORETOMAXIMIZED);
+
+ return 0;
+}
+
+/*
+ * Called when the font changed while the window is maximized or GO_KEEPWINSIZE
+ * is set. Compute the new Rows and Columns. This is like resizing the
+ * window.
+ */
+ void
+gui_mch_newfont(void)
+{
+ RECT rect;
+
+ GetWindowRect(s_hwnd, &rect);
+ if (win_socket_id == 0)
+ {
+ gui_resize_shell(rect.right - rect.left
+ - (GetSystemMetrics(SM_CXFRAME) +
+ GetSystemMetrics(SM_CXPADDEDBORDER)) * 2,
+ rect.bottom - rect.top
+ - (GetSystemMetrics(SM_CYFRAME) +
+ GetSystemMetrics(SM_CXPADDEDBORDER)) * 2
+ - GetSystemMetrics(SM_CYCAPTION)
+#ifdef FEAT_MENU
+ - gui_mswin_get_menu_height(FALSE)
+#endif
+ );
+ }
+ else
+ {
+ /* Inside another window, don't use the frame and border. */
+ gui_resize_shell(rect.right - rect.left,
+ rect.bottom - rect.top
+#ifdef FEAT_MENU
+ - gui_mswin_get_menu_height(FALSE)
+#endif
+ );
+ }
+}
+
+/*
+ * Set the window title
+ */
+ void
+gui_mch_settitle(
+ char_u *title,
+ char_u *icon UNUSED)
+{
+ set_window_title(s_hwnd, (title == NULL ? "VIM" : (char *)title));
+}
+
+#if defined(FEAT_MOUSESHAPE) || defined(PROTO)
+/* Table for shape IDCs. Keep in sync with the mshape_names[] table in
+ * misc2.c! */
+static LPCSTR mshape_idcs[] =
+{
+ IDC_ARROW, /* arrow */
+ MAKEINTRESOURCE(0), /* blank */
+ IDC_IBEAM, /* beam */
+ IDC_SIZENS, /* updown */
+ IDC_SIZENS, /* udsizing */
+ IDC_SIZEWE, /* leftright */
+ IDC_SIZEWE, /* lrsizing */
+ IDC_WAIT, /* busy */
+ IDC_NO, /* no */
+ IDC_ARROW, /* crosshair */
+ IDC_ARROW, /* hand1 */
+ IDC_ARROW, /* hand2 */
+ IDC_ARROW, /* pencil */
+ IDC_ARROW, /* question */
+ IDC_ARROW, /* right-arrow */
+ IDC_UPARROW, /* up-arrow */
+ IDC_ARROW /* last one */
+};
+
+ void
+mch_set_mouse_shape(int shape)
+{
+ LPCSTR idc;
+
+ if (shape == MSHAPE_HIDE)
+ ShowCursor(FALSE);
+ else
+ {
+ if (shape >= MSHAPE_NUMBERED)
+ idc = IDC_ARROW;
+ else
+ idc = mshape_idcs[shape];
+#ifdef SetClassLongPtr
+ SetClassLongPtr(s_textArea, GCLP_HCURSOR, (__int3264)(LONG_PTR)LoadCursor(NULL, idc));
+#else
+ SetClassLong(s_textArea, GCL_HCURSOR, (long_u)LoadCursor(NULL, idc));
+#endif
+ if (!p_mh)
+ {
+ POINT mp;
+
+ /* Set the position to make it redrawn with the new shape. */
+ (void)GetCursorPos((LPPOINT)&mp);
+ (void)SetCursorPos(mp.x, mp.y);
+ ShowCursor(TRUE);
+ }
+ }
+}
+#endif
+
+#if defined(FEAT_BROWSE) || defined(PROTO)
+/*
+ * Wide version of convert_filter().
+ */
+ static WCHAR *
+convert_filterW(char_u *s)
+{
+ char_u *tmp;
+ int len;
+ WCHAR *res;
+
+ tmp = convert_filter(s);
+ if (tmp == NULL)
+ return NULL;
+ len = (int)STRLEN(s) + 3;
+ res = enc_to_utf16(tmp, &len);
+ vim_free(tmp);
+ return res;
+}
+
+/*
+ * 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.
+ */
+ char_u *
+gui_mch_browse(
+ int saving,
+ char_u *title,
+ char_u *dflt,
+ char_u *ext,
+ char_u *initdir,
+ char_u *filter)
+{
+ /* We always use the wide function. This means enc_to_utf16() must work,
+ * otherwise it fails miserably! */
+ OPENFILENAMEW fileStruct;
+ WCHAR fileBuf[MAXPATHL];
+ WCHAR *wp;
+ int i;
+ WCHAR *titlep = NULL;
+ WCHAR *extp = NULL;
+ WCHAR *initdirp = NULL;
+ WCHAR *filterp;
+ char_u *p, *q;
+
+ if (dflt == NULL)
+ fileBuf[0] = NUL;
+ else
+ {
+ wp = enc_to_utf16(dflt, NULL);
+ if (wp == NULL)
+ fileBuf[0] = NUL;
+ else
+ {
+ for (i = 0; wp[i] != NUL && i < MAXPATHL - 1; ++i)
+ fileBuf[i] = wp[i];
+ fileBuf[i] = NUL;
+ vim_free(wp);
+ }
+ }
+
+ /* Convert the filter to Windows format. */
+ filterp = convert_filterW(filter);
+
+ vim_memset(&fileStruct, 0, sizeof(OPENFILENAMEW));
+# ifdef OPENFILENAME_SIZE_VERSION_400W
+ /* be compatible with Windows NT 4.0 */
+ fileStruct.lStructSize = OPENFILENAME_SIZE_VERSION_400W;
+# else
+ fileStruct.lStructSize = sizeof(fileStruct);
+# endif
+
+ if (title != NULL)
+ titlep = enc_to_utf16(title, NULL);
+ fileStruct.lpstrTitle = titlep;
+
+ if (ext != NULL)
+ extp = enc_to_utf16(ext, NULL);
+ fileStruct.lpstrDefExt = extp;
+
+ fileStruct.lpstrFile = fileBuf;
+ fileStruct.nMaxFile = MAXPATHL;
+ fileStruct.lpstrFilter = filterp;
+ fileStruct.hwndOwner = s_hwnd; /* main Vim window is owner*/
+ /* has an initial dir been specified? */
+ if (initdir != NULL && *initdir != NUL)
+ {
+ /* Must have backslashes here, no matter what 'shellslash' says */
+ initdirp = enc_to_utf16(initdir, NULL);
+ if (initdirp != NULL)
+ {
+ for (wp = initdirp; *wp != NUL; ++wp)
+ if (*wp == '/')
+ *wp = '\\';
+ }
+ fileStruct.lpstrInitialDir = initdirp;
+ }
+
+ /*
+ * TODO: Allow selection of multiple files. Needs another arg to this
+ * function to ask for it, and need to use OFN_ALLOWMULTISELECT below.
+ * Also, should we use OFN_FILEMUSTEXIST when opening? Vim can edit on
+ * files that don't exist yet, so I haven't put it in. What about
+ * OFN_PATHMUSTEXIST?
+ * Don't use OFN_OVERWRITEPROMPT, Vim has its own ":confirm" dialog.
+ */
+ fileStruct.Flags = (OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY);
+# ifdef FEAT_SHORTCUT
+ if (curbuf->b_p_bin)
+ fileStruct.Flags |= OFN_NODEREFERENCELINKS;
+# endif
+ if (saving)
+ {
+ if (!GetSaveFileNameW(&fileStruct))
+ return NULL;
+ }
+ else
+ {
+ if (!GetOpenFileNameW(&fileStruct))
+ return NULL;
+ }
+
+ vim_free(filterp);
+ vim_free(initdirp);
+ vim_free(titlep);
+ vim_free(extp);
+
+ /* Convert from UCS2 to 'encoding'. */
+ p = utf16_to_enc(fileBuf, NULL);
+ if (p == NULL)
+ return NULL;
+
+ /* Give focus back to main window (when using MDI). */
+ SetFocus(s_hwnd);
+
+ /* Shorten the file name if possible */
+ q = vim_strsave(shorten_fname1(p));
+ vim_free(p);
+ return q;
+}
+
+
+/*
+ * Convert the string s to the proper format for a filter string by replacing
+ * the \t and \n delimiters with \0.
+ * Returns the converted string in allocated memory.
+ *
+ * Keep in sync with convert_filterW() above!
+ */
+ static char_u *
+convert_filter(char_u *s)
+{
+ char_u *res;
+ unsigned s_len = (unsigned)STRLEN(s);
+ unsigned i;
+
+ res = alloc(s_len + 3);
+ if (res != NULL)
+ {
+ for (i = 0; i < s_len; ++i)
+ if (s[i] == '\t' || s[i] == '\n')
+ res[i] = '\0';
+ else
+ res[i] = s[i];
+ res[s_len] = NUL;
+ /* Add two extra NULs to make sure it's properly terminated. */
+ res[s_len + 1] = NUL;
+ res[s_len + 2] = NUL;
+ }
+ return res;
+}
+
+/*
+ * Select a directory.
+ */
+ char_u *
+gui_mch_browsedir(char_u *title, char_u *initdir)
+{
+ /* We fake this: Use a filter that doesn't select anything and a default
+ * file name that won't be used. */
+ return gui_mch_browse(0, title, (char_u *)_("Not Used"), NULL,
+ initdir, (char_u *)_("Directory\t*.nothing\n"));
+}
+#endif /* FEAT_BROWSE */
+
+ static void
+_OnDropFiles(
+ HWND hwnd UNUSED,
+ HDROP hDrop)
+{
+#define BUFPATHLEN _MAX_PATH
+#define DRAGQVAL 0xFFFFFFFF
+ WCHAR wszFile[BUFPATHLEN];
+ char szFile[BUFPATHLEN];
+ UINT cFiles = DragQueryFile(hDrop, DRAGQVAL, NULL, 0);
+ UINT i;
+ char_u **fnames;
+ POINT pt;
+ int_u modifiers = 0;
+
+ /* TRACE("_OnDropFiles: %d files dropped\n", cFiles); */
+
+ /* Obtain dropped position */
+ DragQueryPoint(hDrop, &pt);
+ MapWindowPoints(s_hwnd, s_textArea, &pt, 1);
+
+ reset_VIsual();
+
+ fnames = (char_u **)alloc(cFiles * sizeof(char_u *));
+
+ if (fnames != NULL)
+ for (i = 0; i < cFiles; ++i)
+ {
+ if (DragQueryFileW(hDrop, i, wszFile, BUFPATHLEN) > 0)
+ fnames[i] = utf16_to_enc(wszFile, NULL);
+ else
+ {
+ DragQueryFile(hDrop, i, szFile, BUFPATHLEN);
+ fnames[i] = vim_strsave((char_u *)szFile);
+ }
+ }
+
+ DragFinish(hDrop);
+
+ if (fnames != NULL)
+ {
+ if ((GetKeyState(VK_SHIFT) & 0x8000) != 0)
+ modifiers |= MOUSE_SHIFT;
+ if ((GetKeyState(VK_CONTROL) & 0x8000) != 0)
+ modifiers |= MOUSE_CTRL;
+ if ((GetKeyState(VK_MENU) & 0x8000) != 0)
+ modifiers |= MOUSE_ALT;
+
+ gui_handle_drop(pt.x, pt.y, modifiers, fnames, cFiles);
+
+ s_need_activate = TRUE;
+ }
+}
+
+ static int
+_OnScroll(
+ HWND hwnd UNUSED,
+ HWND hwndCtl,
+ UINT code,
+ int pos)
+{
+ static UINT prev_code = 0; /* code of previous call */
+ scrollbar_T *sb, *sb_info;
+ long val;
+ int dragging = FALSE;
+ int dont_scroll_save = dont_scroll;
+ SCROLLINFO si;
+
+ si.cbSize = sizeof(si);
+ si.fMask = SIF_POS;
+
+ sb = gui_mswin_find_scrollbar(hwndCtl);
+ if (sb == NULL)
+ return 0;
+
+ 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];
+ }
+ else /* Bottom scrollbar */
+ sb_info = sb;
+ val = sb_info->value;
+
+ switch (code)
+ {
+ case SB_THUMBTRACK:
+ val = pos;
+ dragging = TRUE;
+ if (sb->scroll_shift > 0)
+ val <<= sb->scroll_shift;
+ break;
+ case SB_LINEDOWN:
+ val++;
+ break;
+ case SB_LINEUP:
+ val--;
+ break;
+ case SB_PAGEDOWN:
+ val += (sb_info->size > 2 ? sb_info->size - 2 : 1);
+ break;
+ case SB_PAGEUP:
+ val -= (sb_info->size > 2 ? sb_info->size - 2 : 1);
+ break;
+ case SB_TOP:
+ val = 0;
+ break;
+ case SB_BOTTOM:
+ val = sb_info->max;
+ break;
+ case SB_ENDSCROLL:
+ if (prev_code == SB_THUMBTRACK)
+ {
+ /*
+ * "pos" only gives us 16-bit data. In case of large file,
+ * use GetScrollPos() which returns 32-bit. Unfortunately it
+ * is not valid while the scrollbar is being dragged.
+ */
+ val = GetScrollPos(hwndCtl, SB_CTL);
+ if (sb->scroll_shift > 0)
+ val <<= sb->scroll_shift;
+ }
+ break;
+
+ default:
+ /* TRACE("Unknown scrollbar event %d\n", code); */
+ return 0;
+ }
+ prev_code = code;
+
+ si.nPos = (sb->scroll_shift > 0) ? val >> sb->scroll_shift : val;
+ SetScrollInfo(hwndCtl, SB_CTL, &si, TRUE);
+
+ /*
+ * When moving a vertical scrollbar, move the other vertical scrollbar too.
+ */
+ if (sb->wp != NULL)
+ {
+ scrollbar_T *sba = sb->wp->w_scrollbars;
+ HWND id = sba[ (sb == sba + SBAR_LEFT) ? SBAR_RIGHT : SBAR_LEFT].id;
+
+ SetScrollInfo(id, SB_CTL, &si, TRUE);
+ }
+
+ /* Don't let us be interrupted here by another message. */
+ s_busy_processing = TRUE;
+
+ /* 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;
+
+ mch_disable_flush();
+ gui_drag_scrollbar(sb, val, dragging);
+ mch_enable_flush();
+ gui_may_flush();
+
+ s_busy_processing = FALSE;
+ dont_scroll = dont_scroll_save;
+
+ return 0;
+}
+
+
+/*
+ * Get command line arguments.
+ * Use "prog" as the name of the program and "cmdline" as the arguments.
+ * Copy the arguments to allocated memory.
+ * Return the number of arguments (including program name).
+ * Return pointers to the arguments in "argvp". Memory is allocated with
+ * malloc(), use free() instead of vim_free().
+ * Return pointer to buffer in "tofree".
+ * Returns zero when out of memory.
+ */
+ int
+get_cmd_args(char *prog, char *cmdline, char ***argvp, char **tofree)
+{
+ int i;
+ char *p;
+ char *progp;
+ char *pnew = NULL;
+ char *newcmdline;
+ int inquote;
+ int argc;
+ char **argv = NULL;
+ int round;
+
+ *tofree = NULL;
+
+ /* Try using the Unicode version first, it takes care of conversion when
+ * 'encoding' is changed. */
+ argc = get_cmd_argsW(&argv);
+ if (argc != 0)
+ goto done;
+
+ /* Handle the program name. Remove the ".exe" extension, and find the 1st
+ * non-space. */
+ p = strrchr(prog, '.');
+ if (p != NULL)
+ *p = NUL;
+ for (progp = prog; *progp == ' '; ++progp)
+ ;
+
+ /* The command line is copied to allocated memory, so that we can change
+ * it. Add the size of the string, the separating NUL and a terminating
+ * NUL. */
+ newcmdline = malloc(STRLEN(cmdline) + STRLEN(progp) + 2);
+ if (newcmdline == NULL)
+ return 0;
+
+ /*
+ * First round: count the number of arguments ("pnew" == NULL).
+ * Second round: produce the arguments.
+ */
+ for (round = 1; round <= 2; ++round)
+ {
+ /* First argument is the program name. */
+ if (pnew != NULL)
+ {
+ argv[0] = pnew;
+ strcpy(pnew, progp);
+ pnew += strlen(pnew);
+ *pnew++ = NUL;
+ }
+
+ /*
+ * Isolate each argument and put it in argv[].
+ */
+ p = cmdline;
+ argc = 1;
+ while (*p != NUL)
+ {
+ inquote = FALSE;
+ if (pnew != NULL)
+ argv[argc] = pnew;
+ ++argc;
+ while (*p != NUL && (inquote || (*p != ' ' && *p != '\t')))
+ {
+ /* Backslashes are only special when followed by a double
+ * quote. */
+ i = (int)strspn(p, "\\");
+ if (p[i] == '"')
+ {
+ /* Halve the number of backslashes. */
+ if (i > 1 && pnew != NULL)
+ {
+ vim_memset(pnew, '\\', i / 2);
+ pnew += i / 2;
+ }
+
+ /* Even nr of backslashes toggles quoting, uneven copies
+ * the double quote. */
+ if ((i & 1) == 0)
+ inquote = !inquote;
+ else if (pnew != NULL)
+ *pnew++ = '"';
+ p += i + 1;
+ }
+ else if (i > 0)
+ {
+ /* Copy span of backslashes unmodified. */
+ if (pnew != NULL)
+ {
+ vim_memset(pnew, '\\', i);
+ pnew += i;
+ }
+ p += i;
+ }
+ else
+ {
+ if (pnew != NULL)
+ *pnew++ = *p;
+ /* Can't use mb_* functions, because 'encoding' is not
+ * initialized yet here. */
+ if (IsDBCSLeadByte(*p))
+ {
+ ++p;
+ if (pnew != NULL)
+ *pnew++ = *p;
+ }
+ ++p;
+ }
+ }
+
+ if (pnew != NULL)
+ *pnew++ = NUL;
+ while (*p == ' ' || *p == '\t')
+ ++p; /* advance until a non-space */
+ }
+
+ if (round == 1)
+ {
+ argv = (char **)malloc((argc + 1) * sizeof(char *));
+ if (argv == NULL )
+ {
+ free(newcmdline);
+ return 0; /* malloc error */
+ }
+ pnew = newcmdline;
+ *tofree = newcmdline;
+ }
+ }
+
+done:
+ argv[argc] = NULL; /* NULL-terminated list */
+ *argvp = argv;
+ return argc;
+}
+
+#ifdef FEAT_XPM_W32
+# include "xpm_w32.h"
+#endif
+
+#ifdef PROTO
+# define WINAPI
+#endif
+
+#ifdef __MINGW32__
+/*
+ * Add a lot of missing defines.
+ * They are not always missing, we need the #ifndef's.
+ */
+# ifndef _cdecl
+# define _cdecl
+# endif
+# ifndef IsMinimized
+# define IsMinimized(hwnd) IsIconic(hwnd)
+# endif
+# ifndef IsMaximized
+# define IsMaximized(hwnd) IsZoomed(hwnd)
+# endif
+# ifndef SelectFont
+# define SelectFont(hdc, hfont) ((HFONT)SelectObject((hdc), (HGDIOBJ)(HFONT)(hfont)))
+# endif
+# ifndef GetStockBrush
+# define GetStockBrush(i) ((HBRUSH)GetStockObject(i))
+# endif
+# ifndef DeleteBrush
+# define DeleteBrush(hbr) DeleteObject((HGDIOBJ)(HBRUSH)(hbr))
+# endif
+
+# ifndef HANDLE_WM_RBUTTONDBLCLK
+# define HANDLE_WM_RBUTTONDBLCLK(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), TRUE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
+# endif
+# ifndef HANDLE_WM_MBUTTONUP
+# define HANDLE_WM_MBUTTONUP(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
+# endif
+# ifndef HANDLE_WM_MBUTTONDBLCLK
+# define HANDLE_WM_MBUTTONDBLCLK(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), TRUE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
+# endif
+# ifndef HANDLE_WM_LBUTTONDBLCLK
+# define HANDLE_WM_LBUTTONDBLCLK(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), TRUE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
+# endif
+# ifndef HANDLE_WM_RBUTTONDOWN
+# define HANDLE_WM_RBUTTONDOWN(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), FALSE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
+# endif
+# ifndef HANDLE_WM_MOUSEMOVE
+# define HANDLE_WM_MOUSEMOVE(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
+# endif
+# ifndef HANDLE_WM_RBUTTONUP
+# define HANDLE_WM_RBUTTONUP(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
+# endif
+# ifndef HANDLE_WM_MBUTTONDOWN
+# define HANDLE_WM_MBUTTONDOWN(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), FALSE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
+# endif
+# ifndef HANDLE_WM_LBUTTONUP
+# define HANDLE_WM_LBUTTONUP(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
+# endif
+# ifndef HANDLE_WM_LBUTTONDOWN
+# define HANDLE_WM_LBUTTONDOWN(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), FALSE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
+# endif
+# ifndef HANDLE_WM_SYSCHAR
+# define HANDLE_WM_SYSCHAR(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (TCHAR)(wParam), (int)(short)LOWORD(lParam)), 0L)
+# endif
+# ifndef HANDLE_WM_ACTIVATEAPP
+# define HANDLE_WM_ACTIVATEAPP(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (BOOL)(wParam), (DWORD)(lParam)), 0L)
+# endif
+# ifndef HANDLE_WM_WINDOWPOSCHANGING
+# define HANDLE_WM_WINDOWPOSCHANGING(hwnd, wParam, lParam, fn) \
+ (LRESULT)(DWORD)(BOOL)(fn)((hwnd), (LPWINDOWPOS)(lParam))
+# endif
+# ifndef HANDLE_WM_VSCROLL
+# define HANDLE_WM_VSCROLL(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (HWND)(lParam), (UINT)(LOWORD(wParam)), (int)(short)HIWORD(wParam)), 0L)
+# endif
+# ifndef HANDLE_WM_SETFOCUS
+# define HANDLE_WM_SETFOCUS(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (HWND)(wParam)), 0L)
+# endif
+# ifndef HANDLE_WM_KILLFOCUS
+# define HANDLE_WM_KILLFOCUS(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (HWND)(wParam)), 0L)
+# endif
+# ifndef HANDLE_WM_HSCROLL
+# define HANDLE_WM_HSCROLL(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (HWND)(lParam), (UINT)(LOWORD(wParam)), (int)(short)HIWORD(wParam)), 0L)
+# endif
+# ifndef HANDLE_WM_DROPFILES
+# define HANDLE_WM_DROPFILES(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (HDROP)(wParam)), 0L)
+# endif
+# ifndef HANDLE_WM_CHAR
+# define HANDLE_WM_CHAR(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (TCHAR)(wParam), (int)(short)LOWORD(lParam)), 0L)
+# endif
+# ifndef HANDLE_WM_SYSDEADCHAR
+# define HANDLE_WM_SYSDEADCHAR(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (TCHAR)(wParam), (int)(short)LOWORD(lParam)), 0L)
+# endif
+# ifndef HANDLE_WM_DEADCHAR
+# define HANDLE_WM_DEADCHAR(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (TCHAR)(wParam), (int)(short)LOWORD(lParam)), 0L)
+# endif
+#endif /* __MINGW32__ */
+
+
+/* Some parameters for tearoff menus. All in pixels. */
+#define TEAROFF_PADDING_X 2
+#define TEAROFF_BUTTON_PAD_X 8
+#define TEAROFF_MIN_WIDTH 200
+#define TEAROFF_SUBMENU_LABEL ">>"
+#define TEAROFF_COLUMN_PADDING 3 // # spaces to pad column with.
+
+
+/* For the Intellimouse: */
+#ifndef WM_MOUSEWHEEL
+#define WM_MOUSEWHEEL 0x20a
+#endif
+
+
+#ifdef FEAT_BEVAL_GUI
+# define ID_BEVAL_TOOLTIP 200
+# define BEVAL_TEXT_LEN MAXPATHL
+
+#if (defined(_MSC_VER) && _MSC_VER < 1300) || !defined(MAXULONG_PTR)
+/* Work around old versions of basetsd.h which wrongly declares
+ * UINT_PTR as unsigned long. */
+# undef UINT_PTR
+# define UINT_PTR UINT
+#endif
+
+static BalloonEval *cur_beval = NULL;
+static UINT_PTR BevalTimerId = 0;
+static DWORD LastActivity = 0;
+
+
+/* cproto fails on missing include files */
+#ifndef PROTO
+
+/*
+ * excerpts from headers since this may not be presented
+ * in the extremely old compilers
+ */
+# include <pshpack1.h>
+
+#endif
+
+typedef struct _DllVersionInfo
+{
+ DWORD cbSize;
+ DWORD dwMajorVersion;
+ DWORD dwMinorVersion;
+ DWORD dwBuildNumber;
+ DWORD dwPlatformID;
+} DLLVERSIONINFO;
+
+#ifndef PROTO
+# include <poppack.h>
+#endif
+
+typedef struct tagTOOLINFOA_NEW
+{
+ UINT cbSize;
+ UINT uFlags;
+ HWND hwnd;
+ UINT_PTR uId;
+ RECT rect;
+ HINSTANCE hinst;
+ LPSTR lpszText;
+ LPARAM lParam;
+} TOOLINFO_NEW;
+
+typedef struct tagNMTTDISPINFO_NEW
+{
+ NMHDR hdr;
+ LPSTR lpszText;
+ char szText[80];
+ HINSTANCE hinst;
+ UINT uFlags;
+ LPARAM lParam;
+} NMTTDISPINFO_NEW;
+
+typedef struct tagTOOLINFOW_NEW
+{
+ UINT cbSize;
+ UINT uFlags;
+ HWND hwnd;
+ UINT_PTR uId;
+ RECT rect;
+ HINSTANCE hinst;
+ LPWSTR lpszText;
+ LPARAM lParam;
+ void *lpReserved;
+} TOOLINFOW_NEW;
+
+typedef struct tagNMTTDISPINFOW_NEW
+{
+ NMHDR hdr;
+ LPWSTR lpszText;
+ WCHAR szText[80];
+ HINSTANCE hinst;
+ UINT uFlags;
+ LPARAM lParam;
+} NMTTDISPINFOW_NEW;
+
+
+typedef HRESULT (WINAPI* DLLGETVERSIONPROC)(DLLVERSIONINFO *);
+#ifndef TTM_SETMAXTIPWIDTH
+# define TTM_SETMAXTIPWIDTH (WM_USER+24)
+#endif
+
+#ifndef TTF_DI_SETITEM
+# define TTF_DI_SETITEM 0x8000
+#endif
+
+#ifndef TTN_GETDISPINFO
+# define TTN_GETDISPINFO (TTN_FIRST - 0)
+#endif
+
+#endif /* defined(FEAT_BEVAL_GUI) */
+
+#if defined(FEAT_TOOLBAR) || defined(FEAT_GUI_TABLINE)
+/* Older MSVC compilers don't have LPNMTTDISPINFO[AW] thus we need to define
+ * it here if LPNMTTDISPINFO isn't defined.
+ * MingW doesn't define LPNMTTDISPINFO but typedefs it. Thus we need to check
+ * _MSC_VER. */
+# if !defined(LPNMTTDISPINFO) && defined(_MSC_VER)
+typedef struct tagNMTTDISPINFOA {
+ NMHDR hdr;
+ LPSTR lpszText;
+ char szText[80];
+ HINSTANCE hinst;
+ UINT uFlags;
+ LPARAM lParam;
+} NMTTDISPINFOA, *LPNMTTDISPINFOA;
+# define LPNMTTDISPINFO LPNMTTDISPINFOA
+
+typedef struct tagNMTTDISPINFOW {
+ NMHDR hdr;
+ LPWSTR lpszText;
+ WCHAR szText[80];
+ HINSTANCE hinst;
+ UINT uFlags;
+ LPARAM lParam;
+} NMTTDISPINFOW, *LPNMTTDISPINFOW;
+# endif
+#endif
+
+#ifndef TTN_GETDISPINFOW
+# define TTN_GETDISPINFOW (TTN_FIRST - 10)
+#endif
+
+/* Local variables: */
+
+#ifdef FEAT_MENU
+static UINT s_menu_id = 100;
+#endif
+
+/*
+ * Use the system font for dialogs and tear-off menus. Remove this line to
+ * use DLG_FONT_NAME.
+ */
+#define USE_SYSMENU_FONT
+
+#define VIM_NAME "vim"
+#define VIM_CLASS "Vim"
+#define VIM_CLASSW L"Vim"
+
+/* Initial size for the dialog template. For gui_mch_dialog() it's fixed,
+ * thus there should be room for every dialog. For tearoffs it's made bigger
+ * when needed. */
+#define DLG_ALLOC_SIZE 16 * 1024
+
+/*
+ * stuff for dialogs, menus, tearoffs etc.
+ */
+static PWORD
+add_dialog_element(
+ PWORD p,
+ DWORD lStyle,
+ WORD x,
+ WORD y,
+ WORD w,
+ WORD h,
+ WORD Id,
+ WORD clss,
+ const char *caption);
+static LPWORD lpwAlign(LPWORD);
+static int nCopyAnsiToWideChar(LPWORD, LPSTR, BOOL);
+#if defined(FEAT_MENU) && defined(FEAT_TEAROFF)
+static void gui_mch_tearoff(char_u *title, vimmenu_T *menu, int initX, int initY);
+#endif
+static void get_dialog_font_metrics(void);
+
+static int dialog_default_button = -1;
+
+/* Intellimouse support */
+static int mouse_scroll_lines = 0;
+
+static int s_usenewlook; /* emulate W95/NT4 non-bold dialogs */
+#ifdef FEAT_TOOLBAR
+static void initialise_toolbar(void);
+static LRESULT CALLBACK toolbar_wndproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+static int get_toolbar_bitmap(vimmenu_T *menu);
+#endif
+
+#ifdef FEAT_GUI_TABLINE
+static void initialise_tabline(void);
+static LRESULT CALLBACK tabline_wndproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+#endif
+
+#ifdef FEAT_MBYTE_IME
+static LRESULT _OnImeComposition(HWND hwnd, WPARAM dbcs, LPARAM param);
+static char_u *GetResultStr(HWND hwnd, int GCS, int *lenp);
+#endif
+#if defined(FEAT_MBYTE_IME) && defined(DYNAMIC_IME)
+# ifdef NOIME
+typedef struct tagCOMPOSITIONFORM {
+ DWORD dwStyle;
+ POINT ptCurrentPos;
+ RECT rcArea;
+} COMPOSITIONFORM, *PCOMPOSITIONFORM, NEAR *NPCOMPOSITIONFORM, FAR *LPCOMPOSITIONFORM;
+typedef HANDLE HIMC;
+# endif
+
+static HINSTANCE hLibImm = NULL;
+static LONG (WINAPI *pImmGetCompositionStringA)(HIMC, DWORD, LPVOID, DWORD);
+static LONG (WINAPI *pImmGetCompositionStringW)(HIMC, DWORD, LPVOID, DWORD);
+static HIMC (WINAPI *pImmGetContext)(HWND);
+static HIMC (WINAPI *pImmAssociateContext)(HWND, HIMC);
+static BOOL (WINAPI *pImmReleaseContext)(HWND, HIMC);
+static BOOL (WINAPI *pImmGetOpenStatus)(HIMC);
+static BOOL (WINAPI *pImmSetOpenStatus)(HIMC, BOOL);
+static BOOL (WINAPI *pImmGetCompositionFont)(HIMC, LPLOGFONTA);
+static BOOL (WINAPI *pImmSetCompositionFont)(HIMC, LPLOGFONTA);
+static BOOL (WINAPI *pImmSetCompositionWindow)(HIMC, LPCOMPOSITIONFORM);
+static BOOL (WINAPI *pImmGetConversionStatus)(HIMC, LPDWORD, LPDWORD);
+static BOOL (WINAPI *pImmSetConversionStatus)(HIMC, DWORD, DWORD);
+static void dyn_imm_load(void);
+#else
+# define pImmGetCompositionStringA ImmGetCompositionStringA
+# define pImmGetCompositionStringW ImmGetCompositionStringW
+# define pImmGetContext ImmGetContext
+# define pImmAssociateContext ImmAssociateContext
+# define pImmReleaseContext ImmReleaseContext
+# define pImmGetOpenStatus ImmGetOpenStatus
+# define pImmSetOpenStatus ImmSetOpenStatus
+# define pImmGetCompositionFont ImmGetCompositionFontA
+# define pImmSetCompositionFont ImmSetCompositionFontA
+# define pImmSetCompositionWindow ImmSetCompositionWindow
+# define pImmGetConversionStatus ImmGetConversionStatus
+# define pImmSetConversionStatus ImmSetConversionStatus
+#endif
+
+#ifdef FEAT_MENU
+/*
+ * Figure out how high the menu bar is at the moment.
+ */
+ static int
+gui_mswin_get_menu_height(
+ int fix_window) /* If TRUE, resize window if menu height changed */
+{
+ static int old_menu_height = -1;
+
+ RECT rc1, rc2;
+ int num;
+ int menu_height;
+
+ if (gui.menu_is_active)
+ num = GetMenuItemCount(s_menuBar);
+ else
+ num = 0;
+
+ if (num == 0)
+ menu_height = 0;
+ else if (IsMinimized(s_hwnd))
+ {
+ /* The height of the menu cannot be determined while the window is
+ * minimized. Take the previous height if the menu is changed in that
+ * state, to avoid that Vim's vertical window size accidentally
+ * increases due to the unaccounted-for menu height. */
+ menu_height = old_menu_height == -1 ? 0 : old_menu_height;
+ }
+ else
+ {
+ /*
+ * In case 'lines' is set in _vimrc/_gvimrc window width doesn't
+ * seem to have been set yet, so menu wraps in default window
+ * width which is very narrow. Instead just return height of a
+ * single menu item. Will still be wrong when the menu really
+ * should wrap over more than one line.
+ */
+ GetMenuItemRect(s_hwnd, s_menuBar, 0, &rc1);
+ if (gui.starting)
+ menu_height = rc1.bottom - rc1.top + 1;
+ else
+ {
+ GetMenuItemRect(s_hwnd, s_menuBar, num - 1, &rc2);
+ menu_height = rc2.bottom - rc1.top + 1;
+ }
+ }
+
+ if (fix_window && menu_height != old_menu_height)
+ {
+ gui_set_shellsize(FALSE, FALSE, RESIZE_VERT);
+ }
+ old_menu_height = menu_height;
+
+ return menu_height;
+}
+#endif /*FEAT_MENU*/
+
+
+/*
+ * Setup for the Intellimouse
+ */
+ static void
+init_mouse_wheel(void)
+{
+
+#ifndef SPI_GETWHEELSCROLLLINES
+# define SPI_GETWHEELSCROLLLINES 104
+#endif
+#ifndef SPI_SETWHEELSCROLLLINES
+# define SPI_SETWHEELSCROLLLINES 105
+#endif
+
+#define VMOUSEZ_CLASSNAME "MouseZ" /* hidden wheel window class */
+#define VMOUSEZ_TITLE "Magellan MSWHEEL" /* hidden wheel window title */
+#define VMSH_MOUSEWHEEL "MSWHEEL_ROLLMSG"
+#define VMSH_SCROLL_LINES "MSH_SCROLL_LINES_MSG"
+
+ mouse_scroll_lines = 3; /* reasonable default */
+
+ /* if NT 4.0+ (or Win98) get scroll lines directly from system */
+ SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0,
+ &mouse_scroll_lines, 0);
+}
+
+
+/* Intellimouse wheel handler */
+ static void
+_OnMouseWheel(
+ HWND hwnd,
+ short zDelta)
+{
+/* Treat a mouse wheel event as if it were a scroll request */
+ int i;
+ int size;
+ HWND hwndCtl;
+
+ if (curwin->w_scrollbars[SBAR_RIGHT].id != 0)
+ {
+ hwndCtl = curwin->w_scrollbars[SBAR_RIGHT].id;
+ size = curwin->w_scrollbars[SBAR_RIGHT].size;
+ }
+ else if (curwin->w_scrollbars[SBAR_LEFT].id != 0)
+ {
+ hwndCtl = curwin->w_scrollbars[SBAR_LEFT].id;
+ size = curwin->w_scrollbars[SBAR_LEFT].size;
+ }
+ else
+ return;
+
+ size = curwin->w_height;
+ if (mouse_scroll_lines == 0)
+ init_mouse_wheel();
+
+ mch_disable_flush();
+ if (mouse_scroll_lines > 0
+ && mouse_scroll_lines < (size > 2 ? size - 2 : 1))
+ {
+ for (i = mouse_scroll_lines; i > 0; --i)
+ _OnScroll(hwnd, hwndCtl, zDelta >= 0 ? SB_LINEUP : SB_LINEDOWN, 0);
+ }
+ else
+ _OnScroll(hwnd, hwndCtl, zDelta >= 0 ? SB_PAGEUP : SB_PAGEDOWN, 0);
+ mch_enable_flush();
+ gui_may_flush();
+}
+
+#ifdef USE_SYSMENU_FONT
+/*
+ * Get Menu Font.
+ * Return OK or FAIL.
+ */
+ static int
+gui_w32_get_menu_font(LOGFONT *lf)
+{
+ NONCLIENTMETRICS nm;
+
+ nm.cbSize = sizeof(NONCLIENTMETRICS);
+ if (!SystemParametersInfo(
+ SPI_GETNONCLIENTMETRICS,
+ sizeof(NONCLIENTMETRICS),
+ &nm,
+ 0))
+ return FAIL;
+ *lf = nm.lfMenuFont;
+ return OK;
+}
+#endif
+
+
+#if defined(FEAT_GUI_TABLINE) && defined(USE_SYSMENU_FONT)
+/*
+ * Set the GUI tabline font to the system menu font
+ */
+ static void
+set_tabline_font(void)
+{
+ LOGFONT lfSysmenu;
+ HFONT font;
+ HWND hwnd;
+ HDC hdc;
+ HFONT hfntOld;
+ TEXTMETRIC tm;
+
+ if (gui_w32_get_menu_font(&lfSysmenu) != OK)
+ return;
+
+ font = CreateFontIndirect(&lfSysmenu);
+
+ SendMessage(s_tabhwnd, WM_SETFONT, (WPARAM)font, TRUE);
+
+ /*
+ * Compute the height of the font used for the tab text
+ */
+ hwnd = GetDesktopWindow();
+ hdc = GetWindowDC(hwnd);
+ hfntOld = SelectFont(hdc, font);
+
+ GetTextMetrics(hdc, &tm);
+
+ SelectFont(hdc, hfntOld);
+ ReleaseDC(hwnd, hdc);
+
+ /*
+ * The space used by the tab border and the space between the tab label
+ * and the tab border is included as 7.
+ */
+ gui.tabline_height = tm.tmHeight + tm.tmInternalLeading + 7;
+}
+#endif
+
+/*
+ * Invoked when a setting was changed.
+ */
+ static LRESULT CALLBACK
+_OnSettingChange(UINT n)
+{
+ if (n == SPI_SETWHEELSCROLLLINES)
+ SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0,
+ &mouse_scroll_lines, 0);
+#if defined(FEAT_GUI_TABLINE) && defined(USE_SYSMENU_FONT)
+ if (n == SPI_SETNONCLIENTMETRICS)
+ set_tabline_font();
+#endif
+ return 0;
+}
+
+#ifdef FEAT_NETBEANS_INTG
+ static void
+_OnWindowPosChanged(
+ HWND hwnd,
+ const LPWINDOWPOS lpwpos)
+{
+ static int x = 0, y = 0, cx = 0, cy = 0;
+ extern int WSInitialized;
+
+ if (WSInitialized && (lpwpos->x != x || lpwpos->y != y
+ || lpwpos->cx != cx || lpwpos->cy != cy))
+ {
+ x = lpwpos->x;
+ y = lpwpos->y;
+ cx = lpwpos->cx;
+ cy = lpwpos->cy;
+ netbeans_frame_moved(x, y);
+ }
+ /* Allow to send WM_SIZE and WM_MOVE */
+ FORWARD_WM_WINDOWPOSCHANGED(hwnd, lpwpos, MyWindowProc);
+}
+#endif
+
+ static int
+_DuringSizing(
+ UINT fwSide,
+ LPRECT lprc)
+{
+ int w, h;
+ int valid_w, valid_h;
+ int w_offset, h_offset;
+
+ w = lprc->right - lprc->left;
+ h = lprc->bottom - lprc->top;
+ gui_mswin_get_valid_dimensions(w, h, &valid_w, &valid_h);
+ w_offset = w - valid_w;
+ h_offset = h - valid_h;
+
+ if (fwSide == WMSZ_LEFT || fwSide == WMSZ_TOPLEFT
+ || fwSide == WMSZ_BOTTOMLEFT)
+ lprc->left += w_offset;
+ else if (fwSide == WMSZ_RIGHT || fwSide == WMSZ_TOPRIGHT
+ || fwSide == WMSZ_BOTTOMRIGHT)
+ lprc->right -= w_offset;
+
+ if (fwSide == WMSZ_TOP || fwSide == WMSZ_TOPLEFT
+ || fwSide == WMSZ_TOPRIGHT)
+ lprc->top += h_offset;
+ else if (fwSide == WMSZ_BOTTOM || fwSide == WMSZ_BOTTOMLEFT
+ || fwSide == WMSZ_BOTTOMRIGHT)
+ lprc->bottom -= h_offset;
+ return TRUE;
+}
+
+
+
+ static LRESULT CALLBACK
+_WndProc(
+ HWND hwnd,
+ UINT uMsg,
+ WPARAM wParam,
+ LPARAM lParam)
+{
+ /*
+ TRACE("WndProc: hwnd = %08x, msg = %x, wParam = %x, lParam = %x\n",
+ hwnd, uMsg, wParam, lParam);
+ */
+
+ HandleMouseHide(uMsg, lParam);
+
+ s_uMsg = uMsg;
+ s_wParam = wParam;
+ s_lParam = lParam;
+
+ switch (uMsg)
+ {
+ HANDLE_MSG(hwnd, WM_DEADCHAR, _OnDeadChar);
+ HANDLE_MSG(hwnd, WM_SYSDEADCHAR, _OnDeadChar);
+ /* HANDLE_MSG(hwnd, WM_ACTIVATE, _OnActivate); */
+ HANDLE_MSG(hwnd, WM_CLOSE, _OnClose);
+ /* HANDLE_MSG(hwnd, WM_COMMAND, _OnCommand); */
+ HANDLE_MSG(hwnd, WM_DESTROY, _OnDestroy);
+ HANDLE_MSG(hwnd, WM_DROPFILES, _OnDropFiles);
+ HANDLE_MSG(hwnd, WM_HSCROLL, _OnScroll);
+ HANDLE_MSG(hwnd, WM_KILLFOCUS, _OnKillFocus);
+#ifdef FEAT_MENU
+ HANDLE_MSG(hwnd, WM_COMMAND, _OnMenu);
+#endif
+ /* HANDLE_MSG(hwnd, WM_MOVE, _OnMove); */
+ /* HANDLE_MSG(hwnd, WM_NCACTIVATE, _OnNCActivate); */
+ HANDLE_MSG(hwnd, WM_SETFOCUS, _OnSetFocus);
+ HANDLE_MSG(hwnd, WM_SIZE, _OnSize);
+ /* HANDLE_MSG(hwnd, WM_SYSCOMMAND, _OnSysCommand); */
+ /* HANDLE_MSG(hwnd, WM_SYSKEYDOWN, _OnAltKey); */
+ HANDLE_MSG(hwnd, WM_VSCROLL, _OnScroll);
+ // HANDLE_MSG(hwnd, WM_WINDOWPOSCHANGING, _OnWindowPosChanging);
+ HANDLE_MSG(hwnd, WM_ACTIVATEAPP, _OnActivateApp);
+#ifdef FEAT_NETBEANS_INTG
+ HANDLE_MSG(hwnd, WM_WINDOWPOSCHANGED, _OnWindowPosChanged);
+#endif
+
+#ifdef FEAT_GUI_TABLINE
+ case WM_RBUTTONUP:
+ {
+ if (gui_mch_showing_tabline())
+ {
+ POINT pt;
+ RECT rect;
+
+ /*
+ * If the cursor is on the tabline, display the tab menu
+ */
+ GetCursorPos((LPPOINT)&pt);
+ GetWindowRect(s_textArea, &rect);
+ if (pt.y < rect.top)
+ {
+ show_tabline_popup_menu();
+ return 0L;
+ }
+ }
+ return MyWindowProc(hwnd, uMsg, wParam, lParam);
+ }
+ case WM_LBUTTONDBLCLK:
+ {
+ /*
+ * If the user double clicked the tabline, create a new tab
+ */
+ if (gui_mch_showing_tabline())
+ {
+ POINT pt;
+ RECT rect;
+
+ GetCursorPos((LPPOINT)&pt);
+ GetWindowRect(s_textArea, &rect);
+ if (pt.y < rect.top)
+ send_tabline_menu_event(0, TABLINE_MENU_NEW);
+ }
+ return MyWindowProc(hwnd, uMsg, wParam, lParam);
+ }
+#endif
+
+ case WM_QUERYENDSESSION: /* System wants to go down. */
+ gui_shell_closed(); /* Will exit when no changed buffers. */
+ return FALSE; /* Do NOT allow system to go down. */
+
+ case WM_ENDSESSION:
+ if (wParam) /* system only really goes down when wParam is TRUE */
+ {
+ _OnEndSession();
+ return 0L;
+ }
+ break;
+
+ case WM_CHAR:
+ /* Don't use HANDLE_MSG() for WM_CHAR, it truncates wParam to a single
+ * byte while we want the UTF-16 character value. */
+ _OnChar(hwnd, (UINT)wParam, (int)(short)LOWORD(lParam));
+ return 0L;
+
+ case WM_SYSCHAR:
+ /*
+ * if 'winaltkeys' is "no", or it's "menu" and it's not a menu
+ * shortcut key, handle like a typed ALT key, otherwise call Windows
+ * ALT key handling.
+ */
+#ifdef FEAT_MENU
+ if ( !gui.menu_is_active
+ || p_wak[0] == 'n'
+ || (p_wak[0] == 'm' && !gui_is_menu_shortcut((int)wParam))
+ )
+#endif
+ {
+ _OnSysChar(hwnd, (UINT)wParam, (int)(short)LOWORD(lParam));
+ return 0L;
+ }
+#ifdef FEAT_MENU
+ else
+ return MyWindowProc(hwnd, uMsg, wParam, lParam);
+#endif
+
+ case WM_SYSKEYUP:
+#ifdef FEAT_MENU
+ /* This used to be done only when menu is active: ALT key is used for
+ * that. But that caused problems when menu is disabled and using
+ * Alt-Tab-Esc: get into a strange state where no mouse-moved events
+ * are received, mouse pointer remains hidden. */
+ return MyWindowProc(hwnd, uMsg, wParam, lParam);
+#else
+ return 0L;
+#endif
+
+ case WM_SIZING: /* HANDLE_MSG doesn't seem to handle this one */
+ return _DuringSizing((UINT)wParam, (LPRECT)lParam);
+
+ case WM_MOUSEWHEEL:
+ _OnMouseWheel(hwnd, HIWORD(wParam));
+ return 0L;
+
+ /* Notification for change in SystemParametersInfo() */
+ case WM_SETTINGCHANGE:
+ return _OnSettingChange((UINT)wParam);
+
+#if defined(FEAT_TOOLBAR) || defined(FEAT_GUI_TABLINE)
+ case WM_NOTIFY:
+ switch (((LPNMHDR) lParam)->code)
+ {
+ case TTN_GETDISPINFOW:
+ case TTN_GETDISPINFO:
+ {
+ LPNMHDR hdr = (LPNMHDR)lParam;
+ char_u *str = NULL;
+ static void *tt_text = NULL;
+
+ VIM_CLEAR(tt_text);
+
+# ifdef FEAT_GUI_TABLINE
+ if (gui_mch_showing_tabline()
+ && hdr->hwndFrom == TabCtrl_GetToolTips(s_tabhwnd))
+ {
+ POINT pt;
+ /*
+ * Mouse is over the GUI tabline. Display the
+ * tooltip for the tab under the cursor
+ *
+ * Get the cursor position within the tab control
+ */
+ GetCursorPos(&pt);
+ if (ScreenToClient(s_tabhwnd, &pt) != 0)
+ {
+ TCHITTESTINFO htinfo;
+ int idx;
+
+ /*
+ * Get the tab under the cursor
+ */
+ htinfo.pt.x = pt.x;
+ htinfo.pt.y = pt.y;
+ idx = TabCtrl_HitTest(s_tabhwnd, &htinfo);
+ if (idx != -1)
+ {
+ tabpage_T *tp;
+
+ tp = find_tabpage(idx + 1);
+ if (tp != NULL)
+ {
+ get_tabline_label(tp, TRUE);
+ str = NameBuff;
+ }
+ }
+ }
+ }
+# endif
+# ifdef FEAT_TOOLBAR
+# ifdef FEAT_GUI_TABLINE
+ else
+# endif
+ {
+ UINT idButton;
+ vimmenu_T *pMenu;
+
+ idButton = (UINT) hdr->idFrom;
+ pMenu = gui_mswin_find_menu(root_menu, idButton);
+ if (pMenu)
+ str = pMenu->strings[MENU_INDEX_TIP];
+ }
+# endif
+ if (str != NULL)
+ {
+ if (hdr->code == TTN_GETDISPINFOW)
+ {
+ LPNMTTDISPINFOW lpdi = (LPNMTTDISPINFOW)lParam;
+
+ /* Set the maximum width, this also enables using
+ * \n for line break. */
+ SendMessage(lpdi->hdr.hwndFrom, TTM_SETMAXTIPWIDTH,
+ 0, 500);
+
+ tt_text = enc_to_utf16(str, NULL);
+ lpdi->lpszText = tt_text;
+ /* can't show tooltip if failed */
+ }
+ else
+ {
+ LPNMTTDISPINFO lpdi = (LPNMTTDISPINFO)lParam;
+
+ /* Set the maximum width, this also enables using
+ * \n for line break. */
+ SendMessage(lpdi->hdr.hwndFrom, TTM_SETMAXTIPWIDTH,
+ 0, 500);
+
+ if (STRLEN(str) < sizeof(lpdi->szText)
+ || ((tt_text = vim_strsave(str)) == NULL))
+ vim_strncpy((char_u *)lpdi->szText, str,
+ sizeof(lpdi->szText) - 1);
+ else
+ lpdi->lpszText = tt_text;
+ }
+ }
+ }
+ break;
+# ifdef FEAT_GUI_TABLINE
+ case TCN_SELCHANGE:
+ if (gui_mch_showing_tabline()
+ && ((LPNMHDR)lParam)->hwndFrom == s_tabhwnd)
+ {
+ send_tabline_event(TabCtrl_GetCurSel(s_tabhwnd) + 1);
+ return 0L;
+ }
+ break;
+
+ case NM_RCLICK:
+ if (gui_mch_showing_tabline()
+ && ((LPNMHDR)lParam)->hwndFrom == s_tabhwnd)
+ {
+ show_tabline_popup_menu();
+ return 0L;
+ }
+ break;
+# endif
+ default:
+# ifdef FEAT_GUI_TABLINE
+ if (gui_mch_showing_tabline()
+ && ((LPNMHDR)lParam)->hwndFrom == s_tabhwnd)
+ return MyWindowProc(hwnd, uMsg, wParam, lParam);
+# endif
+ break;
+ }
+ break;
+#endif
+#if defined(MENUHINTS) && defined(FEAT_MENU)
+ case WM_MENUSELECT:
+ if (((UINT) HIWORD(wParam)
+ & (0xffff ^ (MF_MOUSESELECT + MF_BITMAP + MF_POPUP)))
+ == MF_HILITE
+ && (State & CMDLINE) == 0)
+ {
+ UINT idButton;
+ vimmenu_T *pMenu;
+ static int did_menu_tip = FALSE;
+
+ if (did_menu_tip)
+ {
+ msg_clr_cmdline();
+ setcursor();
+ out_flush();
+ did_menu_tip = FALSE;
+ }
+
+ idButton = (UINT)LOWORD(wParam);
+ pMenu = gui_mswin_find_menu(root_menu, idButton);
+ if (pMenu != NULL && pMenu->strings[MENU_INDEX_TIP] != 0
+ && GetMenuState(s_menuBar, pMenu->id, MF_BYCOMMAND) != -1)
+ {
+ ++msg_hist_off;
+ msg((char *)pMenu->strings[MENU_INDEX_TIP]);
+ --msg_hist_off;
+ setcursor();
+ out_flush();
+ did_menu_tip = TRUE;
+ }
+ return 0L;
+ }
+ break;
+#endif
+ case WM_NCHITTEST:
+ {
+ LRESULT result;
+ int x, y;
+ int xPos = GET_X_LPARAM(lParam);
+
+ result = MyWindowProc(hwnd, uMsg, wParam, lParam);
+ if (result == HTCLIENT)
+ {
+#ifdef FEAT_GUI_TABLINE
+ if (gui_mch_showing_tabline())
+ {
+ int yPos = GET_Y_LPARAM(lParam);
+ RECT rct;
+
+ /* If the cursor is on the GUI tabline, don't process this
+ * event */
+ GetWindowRect(s_textArea, &rct);
+ if (yPos < rct.top)
+ return result;
+ }
+#endif
+ (void)gui_mch_get_winpos(&x, &y);
+ xPos -= x;
+
+ if (xPos < 48) /* <VN> TODO should use system metric? */
+ return HTBOTTOMLEFT;
+ else
+ return HTBOTTOMRIGHT;
+ }
+ else
+ return result;
+ }
+ /* break; notreached */
+
+#ifdef FEAT_MBYTE_IME
+ case WM_IME_NOTIFY:
+ if (!_OnImeNotify(hwnd, (DWORD)wParam, (DWORD)lParam))
+ return MyWindowProc(hwnd, uMsg, wParam, lParam);
+ return 1L;
+
+ case WM_IME_COMPOSITION:
+ if (!_OnImeComposition(hwnd, wParam, lParam))
+ return MyWindowProc(hwnd, uMsg, wParam, lParam);
+ return 1L;
+#endif
+
+ default:
+#ifdef MSWIN_FIND_REPLACE
+ if (uMsg == s_findrep_msg && s_findrep_msg != 0)
+ {
+ _OnFindRepl();
+ }
+#endif
+ return MyWindowProc(hwnd, uMsg, wParam, lParam);
+ }
+
+ return DefWindowProc(hwnd, uMsg, wParam, lParam);
+}
+
+/*
+ * End of call-back routines
+ */
+
+/* parent window, if specified with -P */
+HWND vim_parent_hwnd = NULL;
+
+ static BOOL CALLBACK
+FindWindowTitle(HWND hwnd, LPARAM lParam)
+{
+ char buf[2048];
+ char *title = (char *)lParam;
+
+ if (GetWindowText(hwnd, buf, sizeof(buf)))
+ {
+ if (strstr(buf, title) != NULL)
+ {
+ /* Found it. Store the window ref. and quit searching if MDI
+ * works. */
+ vim_parent_hwnd = FindWindowEx(hwnd, NULL, "MDIClient", NULL);
+ if (vim_parent_hwnd != NULL)
+ return FALSE;
+ }
+ }
+ return TRUE; /* continue searching */
+}
+
+/*
+ * Invoked for '-P "title"' argument: search for parent application to open
+ * our window in.
+ */
+ void
+gui_mch_set_parent(char *title)
+{
+ EnumWindows(FindWindowTitle, (LPARAM)title);
+ if (vim_parent_hwnd == NULL)
+ {
+ semsg(_("E671: Cannot find window title \"%s\""), title);
+ mch_exit(2);
+ }
+}
+
+#ifndef FEAT_OLE
+ static void
+ole_error(char *arg)
+{
+ char buf[IOSIZE];
+
+ /* Can't use emsg() here, we have not finished initialisation yet. */
+ vim_snprintf(buf, IOSIZE,
+ _("E243: Argument not supported: \"-%s\"; Use the OLE version."),
+ arg);
+ mch_errmsg(buf);
+}
+#endif
+
+/*
+ * 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)
+{
+ int silent = FALSE;
+ int idx;
+
+ /* Check for special OLE command line parameters */
+ if ((*argc == 2 || *argc == 3) && (argv[1][0] == '-' || argv[1][0] == '/'))
+ {
+ /* Check for a "-silent" argument first. */
+ if (*argc == 3 && STRICMP(argv[1] + 1, "silent") == 0
+ && (argv[2][0] == '-' || argv[2][0] == '/'))
+ {
+ silent = TRUE;
+ idx = 2;
+ }
+ else
+ idx = 1;
+
+ /* Register Vim as an OLE Automation server */
+ if (STRICMP(argv[idx] + 1, "register") == 0)
+ {
+#ifdef FEAT_OLE
+ RegisterMe(silent);
+ mch_exit(0);
+#else
+ if (!silent)
+ ole_error("register");
+ mch_exit(2);
+#endif
+ }
+
+ /* Unregister Vim as an OLE Automation server */
+ if (STRICMP(argv[idx] + 1, "unregister") == 0)
+ {
+#ifdef FEAT_OLE
+ UnregisterMe(!silent);
+ mch_exit(0);
+#else
+ if (!silent)
+ ole_error("unregister");
+ mch_exit(2);
+#endif
+ }
+
+ /* Ignore an -embedding argument. It is only relevant if the
+ * application wants to treat the case when it is started manually
+ * differently from the case where it is started via automation (and
+ * we don't).
+ */
+ if (STRICMP(argv[idx] + 1, "embedding") == 0)
+ {
+#ifdef FEAT_OLE
+ *argc = 1;
+#else
+ ole_error("embedding");
+ mch_exit(2);
+#endif
+ }
+ }
+
+#ifdef FEAT_OLE
+ {
+ int bDoRestart = FALSE;
+
+ InitOLE(&bDoRestart);
+ /* automatically exit after registering */
+ if (bDoRestart)
+ mch_exit(0);
+ }
+#endif
+
+#ifdef FEAT_NETBEANS_INTG
+ {
+ /* stolen from gui_x11.c */
+ int arg;
+
+ for (arg = 1; arg < *argc; arg++)
+ if (strncmp("-nb", argv[arg], 3) == 0)
+ {
+ netbeansArg = argv[arg];
+ mch_memmove(&argv[arg], &argv[arg + 1],
+ (--*argc - arg) * sizeof(char *));
+ argv[*argc] = NULL;
+ break; /* enough? */
+ }
+ }
+#endif
+}
+
+/*
+ * Initialise the GUI. Create all the windows, set up all the call-backs
+ * etc.
+ */
+ int
+gui_mch_init(void)
+{
+ const char szVimWndClass[] = VIM_CLASS;
+ const char szTextAreaClass[] = "VimTextArea";
+ WNDCLASS wndclass;
+ const WCHAR szVimWndClassW[] = VIM_CLASSW;
+ const WCHAR szTextAreaClassW[] = L"VimTextArea";
+ WNDCLASSW wndclassw;
+#ifdef GLOBAL_IME
+ ATOM atom;
+#endif
+
+ /* Return here if the window was already opened (happens when
+ * gui_mch_dialog() is called early). */
+ if (s_hwnd != NULL)
+ goto theend;
+
+ /*
+ * Load the tearoff bitmap
+ */
+#ifdef FEAT_TEAROFF
+ s_htearbitmap = LoadBitmap(s_hinst, "IDB_TEAROFF");
+#endif
+
+ gui.scrollbar_width = GetSystemMetrics(SM_CXVSCROLL);
+ gui.scrollbar_height = GetSystemMetrics(SM_CYHSCROLL);
+#ifdef FEAT_MENU
+ gui.menu_height = 0; /* Windows takes care of this */
+#endif
+ gui.border_width = 0;
+
+ s_brush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
+
+ /* First try using the wide version, so that we can use any title.
+ * Otherwise only characters in the active codepage will work. */
+ if (GetClassInfoW(s_hinst, szVimWndClassW, &wndclassw) == 0)
+ {
+ wndclassw.style = CS_DBLCLKS;
+ wndclassw.lpfnWndProc = _WndProc;
+ wndclassw.cbClsExtra = 0;
+ wndclassw.cbWndExtra = 0;
+ wndclassw.hInstance = s_hinst;
+ wndclassw.hIcon = LoadIcon(wndclassw.hInstance, "IDR_VIM");
+ wndclassw.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wndclassw.hbrBackground = s_brush;
+ wndclassw.lpszMenuName = NULL;
+ wndclassw.lpszClassName = szVimWndClassW;
+
+ if ((
+#ifdef GLOBAL_IME
+ atom =
+#endif
+ RegisterClassW(&wndclassw)) == 0)
+ return FAIL;
+ else
+ wide_WindowProc = TRUE;
+ }
+
+ if (!wide_WindowProc)
+ if (GetClassInfo(s_hinst, szVimWndClass, &wndclass) == 0)
+ {
+ wndclass.style = CS_DBLCLKS;
+ wndclass.lpfnWndProc = _WndProc;
+ wndclass.cbClsExtra = 0;
+ wndclass.cbWndExtra = 0;
+ wndclass.hInstance = s_hinst;
+ wndclass.hIcon = LoadIcon(wndclass.hInstance, "IDR_VIM");
+ wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wndclass.hbrBackground = s_brush;
+ wndclass.lpszMenuName = NULL;
+ wndclass.lpszClassName = szVimWndClass;
+
+ if ((
+#ifdef GLOBAL_IME
+ atom =
+#endif
+ RegisterClass(&wndclass)) == 0)
+ return FAIL;
+ }
+
+ if (vim_parent_hwnd != NULL)
+ {
+#ifdef HAVE_TRY_EXCEPT
+ __try
+ {
+#endif
+ /* Open inside the specified parent window.
+ * TODO: last argument should point to a CLIENTCREATESTRUCT
+ * structure. */
+ s_hwnd = CreateWindowEx(
+ WS_EX_MDICHILD,
+ szVimWndClass, "Vim MSWindows GUI",
+ WS_OVERLAPPEDWINDOW | WS_CHILD
+ | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | 0xC000,
+ gui_win_x == -1 ? CW_USEDEFAULT : gui_win_x,
+ gui_win_y == -1 ? CW_USEDEFAULT : gui_win_y,
+ 100, /* Any value will do */
+ 100, /* Any value will do */
+ vim_parent_hwnd, NULL,
+ s_hinst, NULL);
+#ifdef HAVE_TRY_EXCEPT
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* NOP */
+ }
+#endif
+ if (s_hwnd == NULL)
+ {
+ emsg(_("E672: Unable to open window inside MDI application"));
+ mch_exit(2);
+ }
+ }
+ else
+ {
+ /* If the provided windowid is not valid reset it to zero, so that it
+ * is ignored and we open our own window. */
+ if (IsWindow((HWND)win_socket_id) <= 0)
+ win_socket_id = 0;
+
+ /* Create a window. If win_socket_id is not zero without border and
+ * titlebar, it will be reparented below. */
+ s_hwnd = CreateWindow(
+ szVimWndClass, "Vim MSWindows GUI",
+ (win_socket_id == 0 ? WS_OVERLAPPEDWINDOW : WS_POPUP)
+ | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
+ gui_win_x == -1 ? CW_USEDEFAULT : gui_win_x,
+ gui_win_y == -1 ? CW_USEDEFAULT : gui_win_y,
+ 100, /* Any value will do */
+ 100, /* Any value will do */
+ NULL, NULL,
+ s_hinst, NULL);
+ if (s_hwnd != NULL && win_socket_id != 0)
+ {
+ SetParent(s_hwnd, (HWND)win_socket_id);
+ ShowWindow(s_hwnd, SW_SHOWMAXIMIZED);
+ }
+ }
+
+ if (s_hwnd == NULL)
+ return FAIL;
+
+#ifdef GLOBAL_IME
+ global_ime_init(atom, s_hwnd);
+#endif
+#if defined(FEAT_MBYTE_IME) && defined(DYNAMIC_IME)
+ dyn_imm_load();
+#endif
+
+ /* Create the text area window */
+ if (wide_WindowProc)
+ {
+ if (GetClassInfoW(s_hinst, szTextAreaClassW, &wndclassw) == 0)
+ {
+ wndclassw.style = CS_OWNDC;
+ wndclassw.lpfnWndProc = _TextAreaWndProc;
+ wndclassw.cbClsExtra = 0;
+ wndclassw.cbWndExtra = 0;
+ wndclassw.hInstance = s_hinst;
+ wndclassw.hIcon = NULL;
+ wndclassw.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wndclassw.hbrBackground = NULL;
+ wndclassw.lpszMenuName = NULL;
+ wndclassw.lpszClassName = szTextAreaClassW;
+
+ if (RegisterClassW(&wndclassw) == 0)
+ return FAIL;
+ }
+
+ s_textArea = CreateWindowExW(
+ 0,
+ szTextAreaClassW, L"Vim text area",
+ WS_CHILD | WS_VISIBLE, 0, 0,
+ 100, // Any value will do for now
+ 100, // Any value will do for now
+ s_hwnd, NULL,
+ s_hinst, NULL);
+ }
+ else if (GetClassInfo(s_hinst, szTextAreaClass, &wndclass) == 0)
+ {
+ wndclass.style = CS_OWNDC;
+ wndclass.lpfnWndProc = _TextAreaWndProc;
+ wndclass.cbClsExtra = 0;
+ wndclass.cbWndExtra = 0;
+ wndclass.hInstance = s_hinst;
+ wndclass.hIcon = NULL;
+ wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wndclass.hbrBackground = NULL;
+ wndclass.lpszMenuName = NULL;
+ wndclass.lpszClassName = szTextAreaClass;
+
+ if (RegisterClass(&wndclass) == 0)
+ return FAIL;
+
+ s_textArea = CreateWindowEx(
+ 0,
+ szTextAreaClass, "Vim text area",
+ WS_CHILD | WS_VISIBLE, 0, 0,
+ 100, // Any value will do for now
+ 100, // Any value will do for now
+ s_hwnd, NULL,
+ s_hinst, NULL);
+ }
+
+ if (s_textArea == NULL)
+ return FAIL;
+
+#ifdef FEAT_LIBCALL
+ /* Try loading an icon from $RUNTIMEPATH/bitmaps/vim.ico. */
+ {
+ HANDLE hIcon = NULL;
+
+ if (mch_icon_load(&hIcon) == OK && hIcon != NULL)
+ SendMessage(s_hwnd, WM_SETICON, ICON_SMALL, (LPARAM)hIcon);
+ }
+#endif
+
+#ifdef FEAT_MENU
+ s_menuBar = CreateMenu();
+#endif
+ s_hdc = GetDC(s_textArea);
+
+ DragAcceptFiles(s_hwnd, TRUE);
+
+ /* Do we need to bother with this? */
+ /* m_fMouseAvail = GetSystemMetrics(SM_MOUSEPRESENT); */
+
+ /* Get background/foreground colors from the system */
+ gui_mch_def_colors();
+
+ /* 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();
+
+ /*
+ * Start out by adding the configured border width into the border offset.
+ */
+ gui.border_offset = gui.border_width;
+
+ /*
+ * Set up for Intellimouse processing
+ */
+ init_mouse_wheel();
+
+ /*
+ * compute a couple of metrics used for the dialogs
+ */
+ get_dialog_font_metrics();
+#ifdef FEAT_TOOLBAR
+ /*
+ * Create the toolbar
+ */
+ initialise_toolbar();
+#endif
+#ifdef FEAT_GUI_TABLINE
+ /*
+ * Create the tabline
+ */
+ initialise_tabline();
+#endif
+#ifdef MSWIN_FIND_REPLACE
+ /*
+ * Initialise the dialog box stuff
+ */
+ s_findrep_msg = RegisterWindowMessage(FINDMSGSTRING);
+
+ /* Initialise the struct */
+ s_findrep_struct.lStructSize = sizeof(s_findrep_struct);
+ s_findrep_struct.lpstrFindWhat = (LPSTR)alloc(MSWIN_FR_BUFSIZE);
+ s_findrep_struct.lpstrFindWhat[0] = NUL;
+ s_findrep_struct.lpstrReplaceWith = (LPSTR)alloc(MSWIN_FR_BUFSIZE);
+ s_findrep_struct.lpstrReplaceWith[0] = NUL;
+ s_findrep_struct.wFindWhatLen = MSWIN_FR_BUFSIZE;
+ s_findrep_struct.wReplaceWithLen = MSWIN_FR_BUFSIZE;
+ s_findrep_struct_w.lStructSize = sizeof(s_findrep_struct_w);
+ s_findrep_struct_w.lpstrFindWhat =
+ (LPWSTR)alloc(MSWIN_FR_BUFSIZE * sizeof(WCHAR));
+ s_findrep_struct_w.lpstrFindWhat[0] = NUL;
+ s_findrep_struct_w.lpstrReplaceWith =
+ (LPWSTR)alloc(MSWIN_FR_BUFSIZE * sizeof(WCHAR));
+ s_findrep_struct_w.lpstrReplaceWith[0] = NUL;
+ s_findrep_struct_w.wFindWhatLen = MSWIN_FR_BUFSIZE;
+ s_findrep_struct_w.wReplaceWithLen = MSWIN_FR_BUFSIZE;
+#endif
+
+#ifdef FEAT_EVAL
+# if !defined(_MSC_VER) || (_MSC_VER < 1400)
+/* Define HandleToLong for old MS and non-MS compilers if not defined. */
+# ifndef HandleToLong
+# define HandleToLong(h) ((long)(intptr_t)(h))
+# endif
+# endif
+ /* set the v:windowid variable */
+ set_vim_var_nr(VV_WINDOWID, HandleToLong(s_hwnd));
+#endif
+
+#ifdef FEAT_RENDER_OPTIONS
+ if (p_rop)
+ (void)gui_mch_set_rendering_options(p_rop);
+#endif
+
+theend:
+ /* Display any pending error messages */
+ display_errors();
+
+ return OK;
+}
+
+/*
+ * Get the size of the screen, taking position on multiple monitors into
+ * account (if supported).
+ */
+ static void
+get_work_area(RECT *spi_rect)
+{
+ HMONITOR mon;
+ MONITORINFO moninfo;
+
+ /* work out which monitor the window is on, and get *its* work area */
+ mon = MonitorFromWindow(s_hwnd, MONITOR_DEFAULTTOPRIMARY);
+ if (mon != NULL)
+ {
+ moninfo.cbSize = sizeof(MONITORINFO);
+ if (GetMonitorInfo(mon, &moninfo))
+ {
+ *spi_rect = moninfo.rcWork;
+ return;
+ }
+ }
+ /* this is the old method... */
+ SystemParametersInfo(SPI_GETWORKAREA, 0, spi_rect, 0);
+}
+
+/*
+ * Set the size of the window to the given width and height in pixels.
+ */
+ void
+gui_mch_set_shellsize(
+ int width,
+ int height,
+ int min_width UNUSED,
+ int min_height UNUSED,
+ int base_width UNUSED,
+ int base_height UNUSED,
+ int direction)
+{
+ RECT workarea_rect;
+ int win_width, win_height;
+ WINDOWPLACEMENT wndpl;
+
+ /* Try to keep window completely on screen. */
+ /* Get position of the screen work area. This is the part that is not
+ * used by the taskbar or appbars. */
+ get_work_area(&workarea_rect);
+
+ /* Get current position of our window. Note that the .left and .top are
+ * relative to the work area. */
+ wndpl.length = sizeof(WINDOWPLACEMENT);
+ GetWindowPlacement(s_hwnd, &wndpl);
+
+ /* Resizing a maximized window looks very strange, unzoom it first.
+ * But don't do it when still starting up, it may have been requested in
+ * the shortcut. */
+ if (wndpl.showCmd == SW_SHOWMAXIMIZED && starting == 0)
+ {
+ ShowWindow(s_hwnd, SW_SHOWNORMAL);
+ /* Need to get the settings of the normal window. */
+ GetWindowPlacement(s_hwnd, &wndpl);
+ }
+
+ /* compute the size of the outside of the window */
+ win_width = width + (GetSystemMetrics(SM_CXFRAME) +
+ GetSystemMetrics(SM_CXPADDEDBORDER)) * 2;
+ win_height = height + (GetSystemMetrics(SM_CYFRAME) +
+ GetSystemMetrics(SM_CXPADDEDBORDER)) * 2
+ + GetSystemMetrics(SM_CYCAPTION)
+#ifdef FEAT_MENU
+ + gui_mswin_get_menu_height(FALSE)
+#endif
+ ;
+
+ /* The following should take care of keeping Vim on the same monitor, no
+ * matter if the secondary monitor is left or right of the primary
+ * monitor. */
+ wndpl.rcNormalPosition.right = wndpl.rcNormalPosition.left + win_width;
+ wndpl.rcNormalPosition.bottom = wndpl.rcNormalPosition.top + win_height;
+
+ /* If the window is going off the screen, move it on to the screen. */
+ if ((direction & RESIZE_HOR)
+ && wndpl.rcNormalPosition.right > workarea_rect.right)
+ OffsetRect(&wndpl.rcNormalPosition,
+ workarea_rect.right - wndpl.rcNormalPosition.right, 0);
+
+ if ((direction & RESIZE_HOR)
+ && wndpl.rcNormalPosition.left < workarea_rect.left)
+ OffsetRect(&wndpl.rcNormalPosition,
+ workarea_rect.left - wndpl.rcNormalPosition.left, 0);
+
+ if ((direction & RESIZE_VERT)
+ && wndpl.rcNormalPosition.bottom > workarea_rect.bottom)
+ OffsetRect(&wndpl.rcNormalPosition,
+ 0, workarea_rect.bottom - wndpl.rcNormalPosition.bottom);
+
+ if ((direction & RESIZE_VERT)
+ && wndpl.rcNormalPosition.top < workarea_rect.top)
+ OffsetRect(&wndpl.rcNormalPosition,
+ 0, workarea_rect.top - wndpl.rcNormalPosition.top);
+
+ /* set window position - we should use SetWindowPlacement rather than
+ * SetWindowPos as the MSDN docs say the coord systems returned by
+ * these two are not compatible. */
+ SetWindowPlacement(s_hwnd, &wndpl);
+
+ SetActiveWindow(s_hwnd);
+ SetFocus(s_hwnd);
+
+#ifdef FEAT_MENU
+ /* Menu may wrap differently now */
+ gui_mswin_get_menu_height(!gui.starting);
+#endif
+}
+
+
+ void
+gui_mch_set_scrollbar_thumb(
+ scrollbar_T *sb,
+ long val,
+ long size,
+ long max)
+{
+ SCROLLINFO info;
+
+ sb->scroll_shift = 0;
+ while (max > 32767)
+ {
+ max = (max + 1) >> 1;
+ val >>= 1;
+ size >>= 1;
+ ++sb->scroll_shift;
+ }
+
+ if (sb->scroll_shift > 0)
+ ++size;
+
+ info.cbSize = sizeof(info);
+ info.fMask = SIF_POS | SIF_RANGE | SIF_PAGE;
+ info.nPos = val;
+ info.nMin = 0;
+ info.nMax = max;
+ info.nPage = size;
+ SetScrollInfo(sb->id, SB_CTL, &info, TRUE);
+}
+
+
+/*
+ * Set the current text font.
+ */
+ void
+gui_mch_set_font(GuiFont font)
+{
+ gui.currFont = font;
+}
+
+
+/*
+ * Set the current text foreground color.
+ */
+ void
+gui_mch_set_fg_color(guicolor_T color)
+{
+ gui.currFgColor = color;
+}
+
+/*
+ * Set the current text background color.
+ */
+ void
+gui_mch_set_bg_color(guicolor_T color)
+{
+ gui.currBgColor = color;
+}
+
+/*
+ * Set the current text special color.
+ */
+ void
+gui_mch_set_sp_color(guicolor_T color)
+{
+ gui.currSpColor = color;
+}
+
+#ifdef FEAT_MBYTE_IME
+/*
+ * Multi-byte handling, originally by Sung-Hoon Baek.
+ * First static functions (no prototypes generated).
+ */
+# ifdef _MSC_VER
+# include <ime.h> /* Apparently not needed for Cygwin, MingW or Borland. */
+# endif
+# include <imm.h>
+
+/*
+ * handle WM_IME_NOTIFY message
+ */
+ static LRESULT
+_OnImeNotify(HWND hWnd, DWORD dwCommand, DWORD dwData UNUSED)
+{
+ LRESULT lResult = 0;
+ HIMC hImc;
+
+ if (!pImmGetContext || (hImc = pImmGetContext(hWnd)) == (HIMC)0)
+ return lResult;
+ switch (dwCommand)
+ {
+ case IMN_SETOPENSTATUS:
+ if (pImmGetOpenStatus(hImc))
+ {
+ pImmSetCompositionFont(hImc, &norm_logfont);
+ im_set_position(gui.row, gui.col);
+
+ /* Disable langmap */
+ State &= ~LANGMAP;
+ if (State & INSERT)
+ {
+#if defined(FEAT_KEYMAP)
+ /* Unshown 'keymap' in status lines */
+ if (curbuf->b_p_iminsert == B_IMODE_LMAP)
+ {
+ /* Save cursor position */
+ int old_row = gui.row;
+ int old_col = gui.col;
+
+ // This must be called here before
+ // status_redraw_curbuf(), otherwise the mode
+ // message may appear in the wrong position.
+ showmode();
+ status_redraw_curbuf();
+ update_screen(0);
+ /* Restore cursor position */
+ gui.row = old_row;
+ gui.col = old_col;
+ }
+#endif
+ }
+ }
+ gui_update_cursor(TRUE, FALSE);
+ gui_mch_flush();
+ lResult = 0;
+ break;
+ }
+ pImmReleaseContext(hWnd, hImc);
+ return lResult;
+}
+
+ static LRESULT
+_OnImeComposition(HWND hwnd, WPARAM dbcs UNUSED, LPARAM param)
+{
+ char_u *ret;
+ int len;
+
+ if ((param & GCS_RESULTSTR) == 0) /* Composition unfinished. */
+ return 0;
+
+ ret = GetResultStr(hwnd, GCS_RESULTSTR, &len);
+ if (ret != NULL)
+ {
+ add_to_input_buf_csi(ret, len);
+ vim_free(ret);
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * get the current composition string, in UCS-2; *lenp is the number of
+ * *lenp is the number of Unicode characters.
+ */
+ static short_u *
+GetCompositionString_inUCS2(HIMC hIMC, DWORD GCS, int *lenp)
+{
+ LONG ret;
+ LPWSTR wbuf = NULL;
+ char_u *buf;
+
+ if (!pImmGetContext)
+ return NULL; /* no imm32.dll */
+
+ /* Try Unicode; this'll always work on NT regardless of codepage. */
+ ret = pImmGetCompositionStringW(hIMC, GCS, NULL, 0);
+ if (ret == 0)
+ return NULL; /* empty */
+
+ if (ret > 0)
+ {
+ /* Allocate the requested buffer plus space for the NUL character. */
+ wbuf = (LPWSTR)alloc(ret + sizeof(WCHAR));
+ if (wbuf != NULL)
+ {
+ pImmGetCompositionStringW(hIMC, GCS, wbuf, ret);
+ *lenp = ret / sizeof(WCHAR);
+ }
+ return (short_u *)wbuf;
+ }
+
+ /* ret < 0; we got an error, so try the ANSI version. This'll work
+ * on 9x/ME, but only if the codepage happens to be set to whatever
+ * we're inputting. */
+ ret = pImmGetCompositionStringA(hIMC, GCS, NULL, 0);
+ if (ret <= 0)
+ return NULL; /* empty or error */
+
+ buf = alloc(ret);
+ if (buf == NULL)
+ return NULL;
+ pImmGetCompositionStringA(hIMC, GCS, buf, ret);
+
+ /* convert from codepage to UCS-2 */
+ MultiByteToWideChar_alloc(GetACP(), 0, (LPCSTR)buf, ret, &wbuf, lenp);
+ vim_free(buf);
+
+ return (short_u *)wbuf;
+}
+
+/*
+ * void GetResultStr()
+ *
+ * This handles WM_IME_COMPOSITION with GCS_RESULTSTR flag on.
+ * get complete composition string
+ */
+ static char_u *
+GetResultStr(HWND hwnd, int GCS, int *lenp)
+{
+ HIMC hIMC; /* Input context handle. */
+ short_u *buf = NULL;
+ char_u *convbuf = NULL;
+
+ if (!pImmGetContext || (hIMC = pImmGetContext(hwnd)) == (HIMC)0)
+ return NULL;
+
+ /* Reads in the composition string. */
+ buf = GetCompositionString_inUCS2(hIMC, GCS, lenp);
+ if (buf == NULL)
+ return NULL;
+
+ convbuf = utf16_to_enc(buf, lenp);
+ pImmReleaseContext(hwnd, hIMC);
+ vim_free(buf);
+ return convbuf;
+}
+#endif
+
+/* For global functions we need prototypes. */
+#if defined(FEAT_MBYTE_IME) || defined(PROTO)
+
+/*
+ * set font to IM.
+ */
+ void
+im_set_font(LOGFONT *lf)
+{
+ HIMC hImc;
+
+ if (pImmGetContext && (hImc = pImmGetContext(s_hwnd)) != (HIMC)0)
+ {
+ pImmSetCompositionFont(hImc, lf);
+ pImmReleaseContext(s_hwnd, hImc);
+ }
+}
+
+/*
+ * Notify cursor position to IM.
+ */
+ void
+im_set_position(int row, int col)
+{
+ HIMC hImc;
+
+ if (pImmGetContext && (hImc = pImmGetContext(s_hwnd)) != (HIMC)0)
+ {
+ COMPOSITIONFORM cfs;
+
+ cfs.dwStyle = CFS_POINT;
+ cfs.ptCurrentPos.x = FILL_X(col);
+ cfs.ptCurrentPos.y = FILL_Y(row);
+ MapWindowPoints(s_textArea, s_hwnd, &cfs.ptCurrentPos, 1);
+ pImmSetCompositionWindow(hImc, &cfs);
+
+ pImmReleaseContext(s_hwnd, hImc);
+ }
+}
+
+/*
+ * Set IM status on ("active" is TRUE) or off ("active" is FALSE).
+ */
+ void
+im_set_active(int active)
+{
+ HIMC hImc;
+ static HIMC hImcOld = (HIMC)0;
+
+ if (pImmGetContext) /* if NULL imm32.dll wasn't loaded (yet) */
+ {
+ if (p_imdisable)
+ {
+ if (hImcOld == (HIMC)0)
+ {
+ hImcOld = pImmGetContext(s_hwnd);
+ if (hImcOld)
+ pImmAssociateContext(s_hwnd, (HIMC)0);
+ }
+ active = FALSE;
+ }
+ else if (hImcOld != (HIMC)0)
+ {
+ pImmAssociateContext(s_hwnd, hImcOld);
+ hImcOld = (HIMC)0;
+ }
+
+ hImc = pImmGetContext(s_hwnd);
+ if (hImc)
+ {
+ /*
+ * for Korean ime
+ */
+ HKL hKL = GetKeyboardLayout(0);
+
+ if (LOWORD(hKL) == MAKELANGID(LANG_KOREAN, SUBLANG_KOREAN))
+ {
+ static DWORD dwConversionSaved = 0, dwSentenceSaved = 0;
+ static BOOL bSaved = FALSE;
+
+ if (active)
+ {
+ /* if we have a saved conversion status, restore it */
+ if (bSaved)
+ pImmSetConversionStatus(hImc, dwConversionSaved,
+ dwSentenceSaved);
+ bSaved = FALSE;
+ }
+ else
+ {
+ /* save conversion status and disable korean */
+ if (pImmGetConversionStatus(hImc, &dwConversionSaved,
+ &dwSentenceSaved))
+ {
+ bSaved = TRUE;
+ pImmSetConversionStatus(hImc,
+ dwConversionSaved & ~(IME_CMODE_NATIVE
+ | IME_CMODE_FULLSHAPE),
+ dwSentenceSaved);
+ }
+ }
+ }
+
+ pImmSetOpenStatus(hImc, active);
+ pImmReleaseContext(s_hwnd, hImc);
+ }
+ }
+}
+
+/*
+ * Get IM status. When IM is on, return not 0. Else return 0.
+ */
+ int
+im_get_status(void)
+{
+ int status = 0;
+ HIMC hImc;
+
+ if (pImmGetContext && (hImc = pImmGetContext(s_hwnd)) != (HIMC)0)
+ {
+ status = pImmGetOpenStatus(hImc) ? 1 : 0;
+ pImmReleaseContext(s_hwnd, hImc);
+ }
+ return status;
+}
+
+#endif /* FEAT_MBYTE_IME */
+
+#if !defined(FEAT_MBYTE_IME) && defined(GLOBAL_IME)
+/* Win32 with GLOBAL IME */
+
+/*
+ * Notify cursor position to IM.
+ */
+ void
+im_set_position(int row, int col)
+{
+ /* Win32 with GLOBAL IME */
+ POINT p;
+
+ p.x = FILL_X(col);
+ p.y = FILL_Y(row);
+ MapWindowPoints(s_textArea, s_hwnd, &p, 1);
+ global_ime_set_position(&p);
+}
+
+/*
+ * Set IM status on ("active" is TRUE) or off ("active" is FALSE).
+ */
+ void
+im_set_active(int active)
+{
+ global_ime_set_status(active);
+}
+
+/*
+ * Get IM status. When IM is on, return not 0. Else return 0.
+ */
+ int
+im_get_status(void)
+{
+ return global_ime_get_status();
+}
+#endif
+
+/*
+ * Convert latin9 text "text[len]" to ucs-2 in "unicodebuf".
+ */
+ static void
+latin9_to_ucs(char_u *text, int len, WCHAR *unicodebuf)
+{
+ int c;
+
+ while (--len >= 0)
+ {
+ c = *text++;
+ switch (c)
+ {
+ case 0xa4: c = 0x20ac; break; /* euro */
+ case 0xa6: c = 0x0160; break; /* S hat */
+ case 0xa8: c = 0x0161; break; /* S -hat */
+ case 0xb4: c = 0x017d; break; /* Z hat */
+ case 0xb8: c = 0x017e; break; /* Z -hat */
+ case 0xbc: c = 0x0152; break; /* OE */
+ case 0xbd: c = 0x0153; break; /* oe */
+ case 0xbe: c = 0x0178; break; /* Y */
+ }
+ *unicodebuf++ = c;
+ }
+}
+
+#ifdef FEAT_RIGHTLEFT
+/*
+ * What is this for? In the case where you are using Win98 or Win2K or later,
+ * and you are using a Hebrew font (or Arabic!), Windows does you a favor and
+ * reverses the string sent to the TextOut... family. This sucks, because we
+ * go to a lot of effort to do the right thing, and there doesn't seem to be a
+ * way to tell Windblows not to do this!
+ *
+ * The short of it is that this 'RevOut' only gets called if you are running
+ * one of the new, "improved" MS OSes, and only if you are running in
+ * 'rightleft' mode. It makes display take *slightly* longer, but not
+ * noticeably so.
+ */
+ static void
+RevOut( HDC s_hdc,
+ int col,
+ int row,
+ UINT foptions,
+ CONST RECT *pcliprect,
+ LPCTSTR text,
+ UINT len,
+ CONST INT *padding)
+{
+ int ix;
+
+ for (ix = 0; ix < (int)len; ++ix)
+ ExtTextOut(s_hdc, col + TEXT_X(ix), row, foptions,
+ pcliprect, text + ix, 1, padding);
+}
+#endif
+
+ static void
+draw_line(
+ int x1,
+ int y1,
+ int x2,
+ int y2,
+ COLORREF color)
+{
+#if defined(FEAT_DIRECTX)
+ if (IS_ENABLE_DIRECTX())
+ DWriteContext_DrawLine(s_dwc, x1, y1, x2, y2, color);
+ else
+#endif
+ {
+ HPEN hpen = CreatePen(PS_SOLID, 1, color);
+ HPEN old_pen = SelectObject(s_hdc, hpen);
+ MoveToEx(s_hdc, x1, y1, NULL);
+ /* Note: LineTo() excludes the last pixel in the line. */
+ LineTo(s_hdc, x2, y2);
+ DeleteObject(SelectObject(s_hdc, old_pen));
+ }
+}
+
+ static void
+set_pixel(
+ int x,
+ int y,
+ COLORREF color)
+{
+#if defined(FEAT_DIRECTX)
+ if (IS_ENABLE_DIRECTX())
+ DWriteContext_SetPixel(s_dwc, x, y, color);
+ else
+#endif
+ SetPixel(s_hdc, x, y, color);
+}
+
+ static void
+fill_rect(
+ const RECT *rcp,
+ HBRUSH hbr,
+ COLORREF color)
+{
+#if defined(FEAT_DIRECTX)
+ if (IS_ENABLE_DIRECTX())
+ DWriteContext_FillRect(s_dwc, rcp, color);
+ else
+#endif
+ {
+ HBRUSH hbr2;
+
+ if (hbr == NULL)
+ hbr2 = CreateSolidBrush(color);
+ else
+ hbr2 = hbr;
+ FillRect(s_hdc, rcp, hbr2);
+ if (hbr == NULL)
+ DeleteBrush(hbr2);
+ }
+}
+
+ void
+gui_mch_draw_string(
+ int row,
+ int col,
+ char_u *text,
+ int len,
+ int flags)
+{
+ static int *padding = NULL;
+ static int pad_size = 0;
+ int i;
+ const RECT *pcliprect = NULL;
+ UINT foptions = 0;
+ static WCHAR *unicodebuf = NULL;
+ static int *unicodepdy = NULL;
+ static int unibuflen = 0;
+ int n = 0;
+ int y;
+
+ /*
+ * Italic and bold text seems to have an extra row of pixels at the bottom
+ * (below where the bottom of the character should be). If we draw the
+ * characters with a solid background, the top row of pixels in the
+ * character below will be overwritten. We can fix this by filling in the
+ * background ourselves, to the correct character proportions, and then
+ * writing the character in transparent mode. Still have a problem when
+ * the character is "_", which gets written on to the character below.
+ * New fix: set gui.char_ascent to -1. This shifts all characters up one
+ * pixel in their slots, which fixes the problem with the bottom row of
+ * pixels. We still need this code because otherwise the top row of pixels
+ * becomes a problem. - webb.
+ */
+ static HBRUSH hbr_cache[2] = {NULL, NULL};
+ static guicolor_T brush_color[2] = {INVALCOLOR, INVALCOLOR};
+ static int brush_lru = 0;
+ HBRUSH hbr;
+ RECT rc;
+
+ if (!(flags & DRAW_TRANSP))
+ {
+ /*
+ * Clear background first.
+ * Note: FillRect() excludes right and bottom of rectangle.
+ */
+ rc.left = FILL_X(col);
+ rc.top = FILL_Y(row);
+ if (has_mbyte)
+ {
+ /* Compute the length in display cells. */
+ rc.right = FILL_X(col + mb_string2cells(text, len));
+ }
+ else
+ rc.right = FILL_X(col + len);
+ rc.bottom = FILL_Y(row + 1);
+
+ /* Cache the created brush, that saves a lot of time. We need two:
+ * one for cursor background and one for the normal background. */
+ if (gui.currBgColor == brush_color[0])
+ {
+ hbr = hbr_cache[0];
+ brush_lru = 1;
+ }
+ else if (gui.currBgColor == brush_color[1])
+ {
+ hbr = hbr_cache[1];
+ brush_lru = 0;
+ }
+ else
+ {
+ if (hbr_cache[brush_lru] != NULL)
+ DeleteBrush(hbr_cache[brush_lru]);
+ hbr_cache[brush_lru] = CreateSolidBrush(gui.currBgColor);
+ brush_color[brush_lru] = gui.currBgColor;
+ hbr = hbr_cache[brush_lru];
+ brush_lru = !brush_lru;
+ }
+
+ fill_rect(&rc, hbr, gui.currBgColor);
+
+ SetBkMode(s_hdc, TRANSPARENT);
+
+ /*
+ * When drawing block cursor, prevent inverted character spilling
+ * over character cell (can happen with bold/italic)
+ */
+ if (flags & DRAW_CURSOR)
+ {
+ pcliprect = &rc;
+ foptions = ETO_CLIPPED;
+ }
+ }
+ SetTextColor(s_hdc, gui.currFgColor);
+ SelectFont(s_hdc, gui.currFont);
+
+#ifdef FEAT_DIRECTX
+ if (IS_ENABLE_DIRECTX())
+ DWriteContext_SetFont(s_dwc, (HFONT)gui.currFont);
+#endif
+
+ if (pad_size != Columns || padding == NULL || padding[0] != gui.char_width)
+ {
+ vim_free(padding);
+ pad_size = Columns;
+
+ /* Don't give an out-of-memory message here, it would call us
+ * recursively. */
+ padding = (int *)lalloc(pad_size * sizeof(int), FALSE);
+ if (padding != NULL)
+ for (i = 0; i < pad_size; i++)
+ padding[i] = gui.char_width;
+ }
+
+ /*
+ * We have to provide the padding argument because italic and bold versions
+ * of fixed-width fonts are often one pixel or so wider than their normal
+ * versions.
+ * No check for DRAW_BOLD, Windows will have done it already.
+ */
+
+ /* Check if there are any UTF-8 characters. If not, use normal text
+ * output to speed up output. */
+ if (enc_utf8)
+ for (n = 0; n < len; ++n)
+ if (text[n] >= 0x80)
+ break;
+
+#if defined(FEAT_DIRECTX)
+ /* Quick hack to enable DirectWrite. To use DirectWrite (antialias), it is
+ * required that unicode drawing routine, currently. So this forces it
+ * enabled. */
+ if (IS_ENABLE_DIRECTX())
+ n = 0; /* Keep n < len, to enter block for unicode. */
+#endif
+
+ /* Check if the Unicode buffer exists and is big enough. Create it
+ * with the same length as the multi-byte string, the number of wide
+ * characters is always equal or smaller. */
+ if ((enc_utf8
+ || (enc_codepage > 0 && (int)GetACP() != enc_codepage)
+ || enc_latin9)
+ && (unicodebuf == NULL || len > unibuflen))
+ {
+ vim_free(unicodebuf);
+ unicodebuf = (WCHAR *)lalloc(len * sizeof(WCHAR), FALSE);
+
+ vim_free(unicodepdy);
+ unicodepdy = (int *)lalloc(len * sizeof(int), FALSE);
+
+ unibuflen = len;
+ }
+
+ if (enc_utf8 && n < len && unicodebuf != NULL)
+ {
+ /* Output UTF-8 characters. Composing characters should be
+ * handled here. */
+ int i;
+ int wlen; /* string length in words */
+ int clen; /* string length in characters */
+ int cells; /* cell width of string up to composing char */
+ int cw; /* width of current cell */
+ int c;
+
+ wlen = 0;
+ clen = 0;
+ cells = 0;
+ for (i = 0; i < len; )
+ {
+ c = utf_ptr2char(text + i);
+ if (c >= 0x10000)
+ {
+ /* Turn into UTF-16 encoding. */
+ unicodebuf[wlen++] = ((c - 0x10000) >> 10) + 0xD800;
+ unicodebuf[wlen++] = ((c - 0x10000) & 0x3ff) + 0xDC00;
+ }
+ else
+ {
+ unicodebuf[wlen++] = c;
+ }
+
+ if (utf_iscomposing(c))
+ cw = 0;
+ else
+ {
+ cw = utf_char2cells(c);
+ if (cw > 2) /* don't use 4 for unprintable char */
+ cw = 1;
+ }
+
+ if (unicodepdy != NULL)
+ {
+ /* Use unicodepdy to make characters fit as we expect, even
+ * when the font uses different widths (e.g., bold character
+ * is wider). */
+ if (c >= 0x10000)
+ {
+ unicodepdy[wlen - 2] = cw * gui.char_width;
+ unicodepdy[wlen - 1] = 0;
+ }
+ else
+ unicodepdy[wlen - 1] = cw * gui.char_width;
+ }
+ cells += cw;
+ i += utf_ptr2len_len(text + i, len - i);
+ ++clen;
+ }
+#if defined(FEAT_DIRECTX)
+ if (IS_ENABLE_DIRECTX())
+ {
+ /* Add one to "cells" for italics. */
+ DWriteContext_DrawText(s_dwc, unicodebuf, wlen,
+ TEXT_X(col), TEXT_Y(row), FILL_X(cells + 1), FILL_Y(1),
+ gui.char_width, gui.currFgColor,
+ foptions, pcliprect, unicodepdy);
+ }
+ else
+#endif
+ ExtTextOutW(s_hdc, TEXT_X(col), TEXT_Y(row),
+ foptions, pcliprect, unicodebuf, wlen, unicodepdy);
+ len = cells; /* used for underlining */
+ }
+ else if ((enc_codepage > 0 && (int)GetACP() != enc_codepage) || enc_latin9)
+ {
+ /* If we want to display codepage data, and the current CP is not the
+ * ANSI one, we need to go via Unicode. */
+ if (unicodebuf != NULL)
+ {
+ if (enc_latin9)
+ latin9_to_ucs(text, len, unicodebuf);
+ else
+ len = MultiByteToWideChar(enc_codepage,
+ MB_PRECOMPOSED,
+ (char *)text, len,
+ (LPWSTR)unicodebuf, unibuflen);
+ if (len != 0)
+ {
+ /* Use unicodepdy to make characters fit as we expect, even
+ * when the font uses different widths (e.g., bold character
+ * is wider). */
+ if (unicodepdy != NULL)
+ {
+ int i;
+ int cw;
+
+ for (i = 0; i < len; ++i)
+ {
+ cw = utf_char2cells(unicodebuf[i]);
+ if (cw > 2)
+ cw = 1;
+ unicodepdy[i] = cw * gui.char_width;
+ }
+ }
+ ExtTextOutW(s_hdc, TEXT_X(col), TEXT_Y(row),
+ foptions, pcliprect, unicodebuf, len, unicodepdy);
+ }
+ }
+ }
+ else
+ {
+#ifdef FEAT_RIGHTLEFT
+ /* Windows will mess up RL text, so we have to draw it character by
+ * character. Only do this if RL is on, since it's slow. */
+ if (curwin->w_p_rl)
+ RevOut(s_hdc, TEXT_X(col), TEXT_Y(row),
+ foptions, pcliprect, (char *)text, len, padding);
+ else
+#endif
+ ExtTextOut(s_hdc, TEXT_X(col), TEXT_Y(row),
+ foptions, pcliprect, (char *)text, len, padding);
+ }
+
+ /* Underline */
+ if (flags & DRAW_UNDERL)
+ {
+ /* When p_linespace is 0, overwrite the bottom row of pixels.
+ * Otherwise put the line just below the character. */
+ y = FILL_Y(row + 1) - 1;
+ if (p_linespace > 1)
+ y -= p_linespace - 1;
+ draw_line(FILL_X(col), y, FILL_X(col + len), y, gui.currFgColor);
+ }
+
+ /* Strikethrough */
+ if (flags & DRAW_STRIKE)
+ {
+ y = FILL_Y(row + 1) - gui.char_height/2;
+ draw_line(FILL_X(col), y, FILL_X(col + len), y, gui.currSpColor);
+ }
+
+ /* Undercurl */
+ if (flags & DRAW_UNDERC)
+ {
+ int x;
+ int offset;
+ static const int val[8] = {1, 0, 0, 0, 1, 2, 2, 2 };
+
+ y = FILL_Y(row + 1) - 1;
+ for (x = FILL_X(col); x < FILL_X(col + len); ++x)
+ {
+ offset = val[x % 8];
+ set_pixel(x, y - offset, gui.currSpColor);
+ }
+ }
+}
+
+
+/*
+ * Output routines.
+ */
+
+/* Flush any output to the screen */
+ void
+gui_mch_flush(void)
+{
+# if defined(__BORLANDC__)
+ /*
+ * The GdiFlush declaration (in Borland C 5.01 <wingdi.h>) is not a
+ * prototype declaration.
+ * The compiler complains if __stdcall is not used in both declarations.
+ */
+ BOOL __stdcall GdiFlush(void);
+# endif
+
+#if defined(FEAT_DIRECTX)
+ if (IS_ENABLE_DIRECTX())
+ DWriteContext_Flush(s_dwc);
+#endif
+
+ GdiFlush();
+}
+
+ static void
+clear_rect(RECT *rcp)
+{
+ fill_rect(rcp, NULL, gui.back_pixel);
+}
+
+
+ void
+gui_mch_get_screen_dimensions(int *screen_w, int *screen_h)
+{
+ RECT workarea_rect;
+
+ get_work_area(&workarea_rect);
+
+ *screen_w = workarea_rect.right - workarea_rect.left
+ - (GetSystemMetrics(SM_CXFRAME) +
+ GetSystemMetrics(SM_CXPADDEDBORDER)) * 2;
+
+ /* FIXME: dirty trick: Because the gui_get_base_height() doesn't include
+ * the menubar for MSwin, we subtract it from the screen height, so that
+ * the window size can be made to fit on the screen. */
+ *screen_h = workarea_rect.bottom - workarea_rect.top
+ - (GetSystemMetrics(SM_CYFRAME) +
+ GetSystemMetrics(SM_CXPADDEDBORDER)) * 2
+ - GetSystemMetrics(SM_CYCAPTION)
+#ifdef FEAT_MENU
+ - gui_mswin_get_menu_height(FALSE)
+#endif
+ ;
+}
+
+
+#if defined(FEAT_MENU) || defined(PROTO)
+/*
+ * Add a sub menu to the menu bar.
+ */
+ void
+gui_mch_add_menu(
+ vimmenu_T *menu,
+ int pos)
+{
+ vimmenu_T *parent = menu->parent;
+
+ menu->submenu_id = CreatePopupMenu();
+ menu->id = s_menu_id++;
+
+ if (menu_is_menubar(menu->name))
+ {
+ WCHAR *wn = NULL;
+
+ if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+ {
+ /* 'encoding' differs from active codepage: convert menu name
+ * and use wide function */
+ wn = enc_to_utf16(menu->name, NULL);
+ if (wn != NULL)
+ {
+ MENUITEMINFOW infow;
+
+ infow.cbSize = sizeof(infow);
+ infow.fMask = MIIM_DATA | MIIM_TYPE | MIIM_ID
+ | MIIM_SUBMENU;
+ infow.dwItemData = (long_u)menu;
+ infow.wID = menu->id;
+ infow.fType = MFT_STRING;
+ infow.dwTypeData = wn;
+ infow.cch = (UINT)wcslen(wn);
+ infow.hSubMenu = menu->submenu_id;
+ InsertMenuItemW((parent == NULL)
+ ? s_menuBar : parent->submenu_id,
+ (UINT)pos, TRUE, &infow);
+ vim_free(wn);
+ }
+ }
+
+ if (wn == NULL)
+ {
+ MENUITEMINFO info;
+
+ info.cbSize = sizeof(info);
+ info.fMask = MIIM_DATA | MIIM_TYPE | MIIM_ID | MIIM_SUBMENU;
+ info.dwItemData = (long_u)menu;
+ info.wID = menu->id;
+ info.fType = MFT_STRING;
+ info.dwTypeData = (LPTSTR)menu->name;
+ info.cch = (UINT)STRLEN(menu->name);
+ info.hSubMenu = menu->submenu_id;
+ InsertMenuItem((parent == NULL)
+ ? s_menuBar : parent->submenu_id,
+ (UINT)pos, TRUE, &info);
+ }
+ }
+
+ /* Fix window size if menu may have wrapped */
+ if (parent == NULL)
+ gui_mswin_get_menu_height(!gui.starting);
+#ifdef FEAT_TEAROFF
+ else if (IsWindow(parent->tearoff_handle))
+ rebuild_tearoff(parent);
+#endif
+}
+
+ void
+gui_mch_show_popupmenu(vimmenu_T *menu)
+{
+ POINT mp;
+
+ (void)GetCursorPos((LPPOINT)&mp);
+ gui_mch_show_popupmenu_at(menu, (int)mp.x, (int)mp.y);
+}
+
+ void
+gui_make_popup(char_u *path_name, int mouse_pos)
+{
+ vimmenu_T *menu = gui_find_menu(path_name);
+
+ if (menu != NULL)
+ {
+ POINT p;
+
+ /* Find the position of the current cursor */
+ GetDCOrgEx(s_hdc, &p);
+ if (mouse_pos)
+ {
+ int mx, my;
+
+ gui_mch_getmouse(&mx, &my);
+ p.x += mx;
+ p.y += my;
+ }
+ else if (curwin != NULL)
+ {
+ p.x += TEXT_X(curwin->w_wincol + curwin->w_wcol + 1);
+ p.y += TEXT_Y(W_WINROW(curwin) + curwin->w_wrow + 1);
+ }
+ msg_scroll = FALSE;
+ gui_mch_show_popupmenu_at(menu, (int)p.x, (int)p.y);
+ }
+}
+
+#if defined(FEAT_TEAROFF) || defined(PROTO)
+/*
+ * Given a menu descriptor, e.g. "File.New", find it in the menu hierarchy and
+ * create it as a pseudo-"tearoff menu".
+ */
+ void
+gui_make_tearoff(char_u *path_name)
+{
+ vimmenu_T *menu = gui_find_menu(path_name);
+
+ /* Found the menu, so tear it off. */
+ if (menu != NULL)
+ gui_mch_tearoff(menu->dname, menu, 0xffffL, 0xffffL);
+}
+#endif
+
+/*
+ * Add a menu item to a menu
+ */
+ void
+gui_mch_add_menu_item(
+ vimmenu_T *menu,
+ int idx)
+{
+ vimmenu_T *parent = menu->parent;
+
+ menu->id = s_menu_id++;
+ menu->submenu_id = NULL;
+
+#ifdef FEAT_TEAROFF
+ if (STRNCMP(menu->name, TEAR_STRING, TEAR_LEN) == 0)
+ {
+ InsertMenu(parent->submenu_id, (UINT)idx, MF_BITMAP|MF_BYPOSITION,
+ (UINT)menu->id, (LPCTSTR) s_htearbitmap);
+ }
+ else
+#endif
+#ifdef FEAT_TOOLBAR
+ if (menu_is_toolbar(parent->name))
+ {
+ TBBUTTON newtb;
+
+ vim_memset(&newtb, 0, sizeof(newtb));
+ if (menu_is_separator(menu->name))
+ {
+ newtb.iBitmap = 0;
+ newtb.fsStyle = TBSTYLE_SEP;
+ }
+ else
+ {
+ newtb.iBitmap = get_toolbar_bitmap(menu);
+ newtb.fsStyle = TBSTYLE_BUTTON;
+ }
+ newtb.idCommand = menu->id;
+ newtb.fsState = TBSTATE_ENABLED;
+ newtb.iString = 0;
+ SendMessage(s_toolbarhwnd, TB_INSERTBUTTON, (WPARAM)idx,
+ (LPARAM)&newtb);
+ menu->submenu_id = (HMENU)-1;
+ }
+ else
+#endif
+ {
+ WCHAR *wn = NULL;
+
+ if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+ {
+ /* 'encoding' differs from active codepage: convert menu item name
+ * and use wide function */
+ wn = enc_to_utf16(menu->name, NULL);
+ if (wn != NULL)
+ {
+ InsertMenuW(parent->submenu_id, (UINT)idx,
+ (menu_is_separator(menu->name)
+ ? MF_SEPARATOR : MF_STRING) | MF_BYPOSITION,
+ (UINT)menu->id, wn);
+ vim_free(wn);
+ }
+ }
+ if (wn == NULL)
+ InsertMenu(parent->submenu_id, (UINT)idx,
+ (menu_is_separator(menu->name) ? MF_SEPARATOR : MF_STRING)
+ | MF_BYPOSITION,
+ (UINT)menu->id, (LPCTSTR)menu->name);
+#ifdef FEAT_TEAROFF
+ if (IsWindow(parent->tearoff_handle))
+ rebuild_tearoff(parent);
+#endif
+ }
+}
+
+/*
+ * Destroy the machine specific menu widget.
+ */
+ void
+gui_mch_destroy_menu(vimmenu_T *menu)
+{
+#ifdef FEAT_TOOLBAR
+ /*
+ * is this a toolbar button?
+ */
+ if (menu->submenu_id == (HMENU)-1)
+ {
+ int iButton;
+
+ iButton = (int)SendMessage(s_toolbarhwnd, TB_COMMANDTOINDEX,
+ (WPARAM)menu->id, 0);
+ SendMessage(s_toolbarhwnd, TB_DELETEBUTTON, (WPARAM)iButton, 0);
+ }
+ else
+#endif
+ {
+ if (menu->parent != NULL
+ && menu_is_popup(menu->parent->dname)
+ && menu->parent->submenu_id != NULL)
+ RemoveMenu(menu->parent->submenu_id, menu->id, MF_BYCOMMAND);
+ else
+ RemoveMenu(s_menuBar, menu->id, MF_BYCOMMAND);
+ if (menu->submenu_id != NULL)
+ DestroyMenu(menu->submenu_id);
+#ifdef FEAT_TEAROFF
+ if (IsWindow(menu->tearoff_handle))
+ DestroyWindow(menu->tearoff_handle);
+ if (menu->parent != NULL
+ && menu->parent->children != NULL
+ && IsWindow(menu->parent->tearoff_handle))
+ {
+ /* This menu must not show up when rebuilding the tearoff window. */
+ menu->modes = 0;
+ rebuild_tearoff(menu->parent);
+ }
+#endif
+ }
+}
+
+#ifdef FEAT_TEAROFF
+ static void
+rebuild_tearoff(vimmenu_T *menu)
+{
+ /*hackish*/
+ char_u tbuf[128];
+ RECT trect;
+ RECT rct;
+ RECT roct;
+ int x, y;
+
+ HWND thwnd = menu->tearoff_handle;
+
+ GetWindowText(thwnd, (LPSTR)tbuf, 127);
+ if (GetWindowRect(thwnd, &trect)
+ && GetWindowRect(s_hwnd, &rct)
+ && GetClientRect(s_hwnd, &roct))
+ {
+ x = trect.left - rct.left;
+ y = (trect.top - rct.bottom + roct.bottom);
+ }
+ else
+ {
+ x = y = 0xffffL;
+ }
+ DestroyWindow(thwnd);
+ if (menu->children != NULL)
+ {
+ gui_mch_tearoff(tbuf, menu, x, y);
+ if (IsWindow(menu->tearoff_handle))
+ (void) SetWindowPos(menu->tearoff_handle,
+ NULL,
+ (int)trect.left,
+ (int)trect.top,
+ 0, 0,
+ SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
+ }
+}
+#endif /* FEAT_TEAROFF */
+
+/*
+ * Make a menu either grey or not grey.
+ */
+ void
+gui_mch_menu_grey(
+ vimmenu_T *menu,
+ int grey)
+{
+#ifdef FEAT_TOOLBAR
+ /*
+ * is this a toolbar button?
+ */
+ if (menu->submenu_id == (HMENU)-1)
+ {
+ SendMessage(s_toolbarhwnd, TB_ENABLEBUTTON,
+ (WPARAM)menu->id, (LPARAM) MAKELONG((grey ? FALSE : TRUE), 0) );
+ }
+ else
+#endif
+ (void)EnableMenuItem(menu->parent ? menu->parent->submenu_id : s_menuBar,
+ menu->id, MF_BYCOMMAND | (grey ? MF_GRAYED : MF_ENABLED));
+
+#ifdef FEAT_TEAROFF
+ if ((menu->parent != NULL) && (IsWindow(menu->parent->tearoff_handle)))
+ {
+ WORD menuID;
+ HWND menuHandle;
+
+ /*
+ * A tearoff button has changed state.
+ */
+ if (menu->children == NULL)
+ menuID = (WORD)(menu->id);
+ else
+ menuID = (WORD)((long_u)(menu->submenu_id) | (DWORD)0x8000);
+ menuHandle = GetDlgItem(menu->parent->tearoff_handle, menuID);
+ if (menuHandle)
+ EnableWindow(menuHandle, !grey);
+
+ }
+#endif
+}
+
+#endif /* FEAT_MENU */
+
+
+/* define some macros used to make the dialogue creation more readable */
+
+#define add_string(s) strcpy((LPSTR)p, s); (LPSTR)p += (strlen((LPSTR)p) + 1)
+#define add_word(x) *p++ = (x)
+#define add_long(x) dwp = (DWORD *)p; *dwp++ = (x); p = (WORD *)dwp
+
+#if defined(FEAT_GUI_DIALOG) || defined(PROTO)
+/*
+ * stuff for dialogs
+ */
+
+/*
+ * The callback routine used by all the dialogs. Very simple. First,
+ * acknowledges the INITDIALOG message so that Windows knows to do standard
+ * dialog stuff (Return = default, Esc = cancel....) Second, if a button is
+ * pressed, return that button's ID - IDCANCEL (2), which is the button's
+ * number.
+ */
+ static LRESULT CALLBACK
+dialog_callback(
+ HWND hwnd,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam UNUSED)
+{
+ if (message == WM_INITDIALOG)
+ {
+ CenterWindow(hwnd, GetWindow(hwnd, GW_OWNER));
+ /* Set focus to the dialog. Set the default button, if specified. */
+ (void)SetFocus(hwnd);
+ if (dialog_default_button > IDCANCEL)
+ (void)SetFocus(GetDlgItem(hwnd, dialog_default_button));
+ else
+ /* We don't have a default, set focus on another element of the
+ * dialog window, probably the icon */
+ (void)SetFocus(GetDlgItem(hwnd, DLG_NONBUTTON_CONTROL));
+ return FALSE;
+ }
+
+ if (message == WM_COMMAND)
+ {
+ int button = LOWORD(wParam);
+
+ /* Don't end the dialog if something was selected that was
+ * not a button.
+ */
+ if (button >= DLG_NONBUTTON_CONTROL)
+ return TRUE;
+
+ /* If the edit box exists, copy the string. */
+ if (s_textfield != NULL)
+ {
+ /* If the OS is Windows NT, and 'encoding' differs from active
+ * codepage: use wide function and convert text. */
+ if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+ {
+ WCHAR *wp = (WCHAR *)alloc(IOSIZE * sizeof(WCHAR));
+ char_u *p;
+
+ GetDlgItemTextW(hwnd, DLG_NONBUTTON_CONTROL + 2, wp, IOSIZE);
+ p = utf16_to_enc(wp, NULL);
+ vim_strncpy(s_textfield, p, IOSIZE);
+ vim_free(p);
+ vim_free(wp);
+ }
+ else
+ GetDlgItemText(hwnd, DLG_NONBUTTON_CONTROL + 2,
+ (LPSTR)s_textfield, IOSIZE);
+ }
+
+ /*
+ * Need to check for IDOK because if the user just hits Return to
+ * accept the default value, some reason this is what we get.
+ */
+ if (button == IDOK)
+ {
+ if (dialog_default_button > IDCANCEL)
+ EndDialog(hwnd, dialog_default_button);
+ }
+ else
+ EndDialog(hwnd, button - IDCANCEL);
+ return TRUE;
+ }
+
+ if ((message == WM_SYSCOMMAND) && (wParam == SC_CLOSE))
+ {
+ EndDialog(hwnd, 0);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * Create a dialog dynamically from the parameter strings.
+ * type = type of dialog (question, alert, etc.)
+ * title = dialog title. may be NULL for default title.
+ * message = text to display. Dialog 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.
+ */
+
+static const char *dlg_icons[] = /* must match names in resource file */
+{
+ "IDR_VIM",
+ "IDR_VIM_ERROR",
+ "IDR_VIM_ALERT",
+ "IDR_VIM_INFO",
+ "IDR_VIM_QUESTION"
+};
+
+ int
+gui_mch_dialog(
+ int type,
+ char_u *title,
+ char_u *message,
+ char_u *buttons,
+ int dfltbutton,
+ char_u *textfield,
+ int ex_cmd)
+{
+ WORD *p, *pdlgtemplate, *pnumitems;
+ DWORD *dwp;
+ int numButtons;
+ int *buttonWidths, *buttonPositions;
+ int buttonYpos;
+ int nchar, i;
+ DWORD lStyle;
+ int dlgwidth = 0;
+ int dlgheight;
+ int editboxheight;
+ int horizWidth = 0;
+ int msgheight;
+ char_u *pstart;
+ char_u *pend;
+ char_u *last_white;
+ char_u *tbuffer;
+ RECT rect;
+ HWND hwnd;
+ HDC hdc;
+ HFONT font, oldFont;
+ TEXTMETRIC fontInfo;
+ int fontHeight;
+ int textWidth, minButtonWidth, messageWidth;
+ int maxDialogWidth;
+ int maxDialogHeight;
+ int scroll_flag = 0;
+ int vertical;
+ int dlgPaddingX;
+ int dlgPaddingY;
+#ifdef USE_SYSMENU_FONT
+ LOGFONT lfSysmenu;
+ int use_lfSysmenu = FALSE;
+#endif
+ garray_T ga;
+ int l;
+
+#ifndef NO_CONSOLE
+ /* Don't output anything in silent mode ("ex -s") */
+ if (silent_mode)
+ return dfltbutton; /* return default option */
+#endif
+
+ if (s_hwnd == NULL)
+ get_dialog_font_metrics();
+
+ if ((type < 0) || (type > VIM_LAST_TYPE))
+ type = 0;
+
+ /* allocate some memory for dialog template */
+ /* TODO should compute this really */
+ pdlgtemplate = p = (PWORD)LocalAlloc(LPTR,
+ DLG_ALLOC_SIZE + STRLEN(message) * 2);
+
+ if (p == NULL)
+ return -1;
+
+ /*
+ * make a copy of 'buttons' to fiddle with it. compiler grizzles because
+ * vim_strsave() doesn't take a const arg (why not?), so cast away the
+ * const.
+ */
+ tbuffer = vim_strsave(buttons);
+ if (tbuffer == NULL)
+ return -1;
+
+ --dfltbutton; /* Change from one-based to zero-based */
+
+ /* Count buttons */
+ numButtons = 1;
+ for (i = 0; tbuffer[i] != '\0'; i++)
+ {
+ if (tbuffer[i] == DLG_BUTTON_SEP)
+ numButtons++;
+ }
+ if (dfltbutton >= numButtons)
+ dfltbutton = -1;
+
+ /* Allocate array to hold the width of each button */
+ buttonWidths = (int *)lalloc(numButtons * sizeof(int), TRUE);
+ if (buttonWidths == NULL)
+ return -1;
+
+ /* Allocate array to hold the X position of each button */
+ buttonPositions = (int *)lalloc(numButtons * sizeof(int), TRUE);
+ if (buttonPositions == NULL)
+ return -1;
+
+ /*
+ * Calculate how big the dialog must be.
+ */
+ hwnd = GetDesktopWindow();
+ hdc = GetWindowDC(hwnd);
+#ifdef USE_SYSMENU_FONT
+ if (gui_w32_get_menu_font(&lfSysmenu) == OK)
+ {
+ font = CreateFontIndirect(&lfSysmenu);
+ use_lfSysmenu = TRUE;
+ }
+ else
+#endif
+ font = CreateFont(-DLG_FONT_POINT_SIZE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ VARIABLE_PITCH , DLG_FONT_NAME);
+ if (s_usenewlook)
+ {
+ oldFont = SelectFont(hdc, font);
+ dlgPaddingX = DLG_PADDING_X;
+ dlgPaddingY = DLG_PADDING_Y;
+ }
+ else
+ {
+ oldFont = SelectFont(hdc, GetStockObject(SYSTEM_FONT));
+ dlgPaddingX = DLG_OLD_STYLE_PADDING_X;
+ dlgPaddingY = DLG_OLD_STYLE_PADDING_Y;
+ }
+ GetTextMetrics(hdc, &fontInfo);
+ fontHeight = fontInfo.tmHeight;
+
+ /* Minimum width for horizontal button */
+ minButtonWidth = GetTextWidth(hdc, (char_u *)"Cancel", 6);
+
+ /* Maximum width of a dialog, if possible */
+ if (s_hwnd == NULL)
+ {
+ RECT workarea_rect;
+
+ /* We don't have a window, use the desktop area. */
+ get_work_area(&workarea_rect);
+ maxDialogWidth = workarea_rect.right - workarea_rect.left - 100;
+ if (maxDialogWidth > 600)
+ maxDialogWidth = 600;
+ /* Leave some room for the taskbar. */
+ maxDialogHeight = workarea_rect.bottom - workarea_rect.top - 150;
+ }
+ else
+ {
+ /* Use our own window for the size, unless it's very small. */
+ GetWindowRect(s_hwnd, &rect);
+ maxDialogWidth = rect.right - rect.left
+ - (GetSystemMetrics(SM_CXFRAME) +
+ GetSystemMetrics(SM_CXPADDEDBORDER)) * 2;
+ if (maxDialogWidth < DLG_MIN_MAX_WIDTH)
+ maxDialogWidth = DLG_MIN_MAX_WIDTH;
+
+ maxDialogHeight = rect.bottom - rect.top
+ - (GetSystemMetrics(SM_CYFRAME) +
+ GetSystemMetrics(SM_CXPADDEDBORDER)) * 4
+ - GetSystemMetrics(SM_CYCAPTION);
+ if (maxDialogHeight < DLG_MIN_MAX_HEIGHT)
+ maxDialogHeight = DLG_MIN_MAX_HEIGHT;
+ }
+
+ /* Set dlgwidth to width of message.
+ * Copy the message into "ga", changing NL to CR-NL and inserting line
+ * breaks where needed. */
+ pstart = message;
+ messageWidth = 0;
+ msgheight = 0;
+ ga_init2(&ga, sizeof(char), 500);
+ do
+ {
+ msgheight += fontHeight; /* at least one line */
+
+ /* Need to figure out where to break the string. The system does it
+ * at a word boundary, which would mean we can't compute the number of
+ * wrapped lines. */
+ textWidth = 0;
+ last_white = NULL;
+ for (pend = pstart; *pend != NUL && *pend != '\n'; )
+ {
+ l = (*mb_ptr2len)(pend);
+ if (l == 1 && VIM_ISWHITE(*pend)
+ && textWidth > maxDialogWidth * 3 / 4)
+ last_white = pend;
+ textWidth += GetTextWidthEnc(hdc, pend, l);
+ if (textWidth >= maxDialogWidth)
+ {
+ /* Line will wrap. */
+ messageWidth = maxDialogWidth;
+ msgheight += fontHeight;
+ textWidth = 0;
+
+ if (last_white != NULL)
+ {
+ /* break the line just after a space */
+ ga.ga_len -= (int)(pend - (last_white + 1));
+ pend = last_white + 1;
+ last_white = NULL;
+ }
+ ga_append(&ga, '\r');
+ ga_append(&ga, '\n');
+ continue;
+ }
+
+ while (--l >= 0)
+ ga_append(&ga, *pend++);
+ }
+ if (textWidth > messageWidth)
+ messageWidth = textWidth;
+
+ ga_append(&ga, '\r');
+ ga_append(&ga, '\n');
+ pstart = pend + 1;
+ } while (*pend != NUL);
+
+ if (ga.ga_data != NULL)
+ message = ga.ga_data;
+
+ messageWidth += 10; /* roundoff space */
+
+ /* Add width of icon to dlgwidth, and some space */
+ dlgwidth = messageWidth + DLG_ICON_WIDTH + 3 * dlgPaddingX
+ + GetSystemMetrics(SM_CXVSCROLL);
+
+ if (msgheight < DLG_ICON_HEIGHT)
+ msgheight = DLG_ICON_HEIGHT;
+
+ /*
+ * Check button names. A long one will make the dialog wider.
+ * When called early (-register error message) p_go isn't initialized.
+ */
+ vertical = (p_go != NULL && vim_strchr(p_go, GO_VERTICAL) != NULL);
+ if (!vertical)
+ {
+ // Place buttons horizontally if they fit.
+ horizWidth = dlgPaddingX;
+ pstart = tbuffer;
+ i = 0;
+ do
+ {
+ pend = vim_strchr(pstart, DLG_BUTTON_SEP);
+ if (pend == NULL)
+ pend = pstart + STRLEN(pstart); // Last button name.
+ textWidth = GetTextWidthEnc(hdc, pstart, (int)(pend - pstart));
+ if (textWidth < minButtonWidth)
+ textWidth = minButtonWidth;
+ textWidth += dlgPaddingX; /* Padding within button */
+ buttonWidths[i] = textWidth;
+ buttonPositions[i++] = horizWidth;
+ horizWidth += textWidth + dlgPaddingX; /* Pad between buttons */
+ pstart = pend + 1;
+ } while (*pend != NUL);
+
+ if (horizWidth > maxDialogWidth)
+ vertical = TRUE; // Too wide to fit on the screen.
+ else if (horizWidth > dlgwidth)
+ dlgwidth = horizWidth;
+ }
+
+ if (vertical)
+ {
+ // Stack buttons vertically.
+ pstart = tbuffer;
+ do
+ {
+ pend = vim_strchr(pstart, DLG_BUTTON_SEP);
+ if (pend == NULL)
+ pend = pstart + STRLEN(pstart); // Last button name.
+ textWidth = GetTextWidthEnc(hdc, pstart, (int)(pend - pstart));
+ textWidth += dlgPaddingX; /* Padding within button */
+ textWidth += DLG_VERT_PADDING_X * 2; /* Padding around button */
+ if (textWidth > dlgwidth)
+ dlgwidth = textWidth;
+ pstart = pend + 1;
+ } while (*pend != NUL);
+ }
+
+ if (dlgwidth < DLG_MIN_WIDTH)
+ dlgwidth = DLG_MIN_WIDTH; /* Don't allow a really thin dialog!*/
+
+ /* start to fill in the dlgtemplate information. addressing by WORDs */
+ if (s_usenewlook)
+ lStyle = DS_MODALFRAME | WS_CAPTION |DS_3DLOOK| WS_VISIBLE |DS_SETFONT;
+ else
+ lStyle = DS_MODALFRAME | WS_CAPTION |DS_3DLOOK| WS_VISIBLE;
+
+ add_long(lStyle);
+ add_long(0); // (lExtendedStyle)
+ pnumitems = p; /*save where the number of items must be stored*/
+ add_word(0); // NumberOfItems(will change later)
+ add_word(10); // x
+ add_word(10); // y
+ add_word(PixelToDialogX(dlgwidth)); // cx
+
+ // Dialog height.
+ if (vertical)
+ dlgheight = msgheight + 2 * dlgPaddingY
+ + DLG_VERT_PADDING_Y + 2 * fontHeight * numButtons;
+ else
+ dlgheight = msgheight + 3 * dlgPaddingY + 2 * fontHeight;
+
+ // Dialog needs to be taller if contains an edit box.
+ editboxheight = fontHeight + dlgPaddingY + 4 * DLG_VERT_PADDING_Y;
+ if (textfield != NULL)
+ dlgheight += editboxheight;
+
+ /* Restrict the size to a maximum. Causes a scrollbar to show up. */
+ if (dlgheight > maxDialogHeight)
+ {
+ msgheight = msgheight - (dlgheight - maxDialogHeight);
+ dlgheight = maxDialogHeight;
+ scroll_flag = WS_VSCROLL;
+ /* Make sure scrollbar doesn't appear in the middle of the dialog */
+ messageWidth = dlgwidth - DLG_ICON_WIDTH - 3 * dlgPaddingX;
+ }
+
+ add_word(PixelToDialogY(dlgheight));
+
+ add_word(0); // Menu
+ add_word(0); // Class
+
+ /* copy the title of the dialog */
+ nchar = nCopyAnsiToWideChar(p, (title ? (LPSTR)title
+ : (LPSTR)("Vim "VIM_VERSION_MEDIUM)), TRUE);
+ p += nchar;
+
+ if (s_usenewlook)
+ {
+ /* do the font, since DS_3DLOOK doesn't work properly */
+#ifdef USE_SYSMENU_FONT
+ if (use_lfSysmenu)
+ {
+ /* point size */
+ *p++ = -MulDiv(lfSysmenu.lfHeight, 72,
+ GetDeviceCaps(hdc, LOGPIXELSY));
+ nchar = nCopyAnsiToWideChar(p, lfSysmenu.lfFaceName, FALSE);
+ }
+ else
+#endif
+ {
+ *p++ = DLG_FONT_POINT_SIZE; // point size
+ nchar = nCopyAnsiToWideChar(p, DLG_FONT_NAME, FALSE);
+ }
+ p += nchar;
+ }
+
+ buttonYpos = msgheight + 2 * dlgPaddingY;
+
+ if (textfield != NULL)
+ buttonYpos += editboxheight;
+
+ pstart = tbuffer;
+ if (!vertical)
+ horizWidth = (dlgwidth - horizWidth) / 2; /* Now it's X offset */
+ for (i = 0; i < numButtons; i++)
+ {
+ /* get end of this button. */
+ for ( pend = pstart;
+ *pend && (*pend != DLG_BUTTON_SEP);
+ pend++)
+ ;
+
+ if (*pend)
+ *pend = '\0';
+
+ /*
+ * old NOTE:
+ * setting the BS_DEFPUSHBUTTON style doesn't work because Windows sets
+ * the focus to the first tab-able button and in so doing makes that
+ * the default!! Grrr. Workaround: Make the default button the only
+ * one with WS_TABSTOP style. Means user can't tab between buttons, but
+ * he/she can use arrow keys.
+ *
+ * new NOTE: BS_DEFPUSHBUTTON is required to be able to select the
+ * right button when hitting <Enter>. E.g., for the ":confirm quit"
+ * dialog. Also needed for when the textfield is the default control.
+ * It appears to work now (perhaps not on Win95?).
+ */
+ if (vertical)
+ {
+ p = add_dialog_element(p,
+ (i == dfltbutton
+ ? BS_DEFPUSHBUTTON : BS_PUSHBUTTON) | WS_TABSTOP,
+ PixelToDialogX(DLG_VERT_PADDING_X),
+ PixelToDialogY(buttonYpos /* TBK */
+ + 2 * fontHeight * i),
+ PixelToDialogX(dlgwidth - 2 * DLG_VERT_PADDING_X),
+ (WORD)(PixelToDialogY(2 * fontHeight) - 1),
+ (WORD)(IDCANCEL + 1 + i), (WORD)0x0080, (char *)pstart);
+ }
+ else
+ {
+ p = add_dialog_element(p,
+ (i == dfltbutton
+ ? BS_DEFPUSHBUTTON : BS_PUSHBUTTON) | WS_TABSTOP,
+ PixelToDialogX(horizWidth + buttonPositions[i]),
+ PixelToDialogY(buttonYpos), /* TBK */
+ PixelToDialogX(buttonWidths[i]),
+ (WORD)(PixelToDialogY(2 * fontHeight) - 1),
+ (WORD)(IDCANCEL + 1 + i), (WORD)0x0080, (char *)pstart);
+ }
+ pstart = pend + 1; /*next button*/
+ }
+ *pnumitems += numButtons;
+
+ /* Vim icon */
+ p = add_dialog_element(p, SS_ICON,
+ PixelToDialogX(dlgPaddingX),
+ PixelToDialogY(dlgPaddingY),
+ PixelToDialogX(DLG_ICON_WIDTH),
+ PixelToDialogY(DLG_ICON_HEIGHT),
+ DLG_NONBUTTON_CONTROL + 0, (WORD)0x0082,
+ dlg_icons[type]);
+
+ /* Dialog message */
+ p = add_dialog_element(p, ES_LEFT|scroll_flag|ES_MULTILINE|ES_READONLY,
+ PixelToDialogX(2 * dlgPaddingX + DLG_ICON_WIDTH),
+ PixelToDialogY(dlgPaddingY),
+ (WORD)(PixelToDialogX(messageWidth) + 1),
+ PixelToDialogY(msgheight),
+ DLG_NONBUTTON_CONTROL + 1, (WORD)0x0081, (char *)message);
+
+ /* Edit box */
+ if (textfield != NULL)
+ {
+ p = add_dialog_element(p, ES_LEFT|ES_AUTOHSCROLL|WS_TABSTOP|WS_BORDER,
+ PixelToDialogX(2 * dlgPaddingX),
+ PixelToDialogY(2 * dlgPaddingY + msgheight),
+ PixelToDialogX(dlgwidth - 4 * dlgPaddingX),
+ PixelToDialogY(fontHeight + dlgPaddingY),
+ DLG_NONBUTTON_CONTROL + 2, (WORD)0x0081, (char *)textfield);
+ *pnumitems += 1;
+ }
+
+ *pnumitems += 2;
+
+ SelectFont(hdc, oldFont);
+ DeleteObject(font);
+ ReleaseDC(hwnd, hdc);
+
+ /* Let the dialog_callback() function know which button to make default
+ * If we have an edit box, make that the default. We also need to tell
+ * dialog_callback() if this dialog contains an edit box or not. We do
+ * this by setting s_textfield if it does.
+ */
+ if (textfield != NULL)
+ {
+ dialog_default_button = DLG_NONBUTTON_CONTROL + 2;
+ s_textfield = textfield;
+ }
+ else
+ {
+ dialog_default_button = IDCANCEL + 1 + dfltbutton;
+ s_textfield = NULL;
+ }
+
+ /* show the dialog box modally and get a return value */
+ nchar = (int)DialogBoxIndirect(
+ s_hinst,
+ (LPDLGTEMPLATE)pdlgtemplate,
+ s_hwnd,
+ (DLGPROC)dialog_callback);
+
+ LocalFree(LocalHandle(pdlgtemplate));
+ vim_free(tbuffer);
+ vim_free(buttonWidths);
+ vim_free(buttonPositions);
+ vim_free(ga.ga_data);
+
+ /* Focus back to our window (for when MDI is used). */
+ (void)SetFocus(s_hwnd);
+
+ return nchar;
+}
+
+#endif /* FEAT_GUI_DIALOG */
+
+/*
+ * Put a simple element (basic class) onto a dialog template in memory.
+ * return a pointer to where the next item should be added.
+ *
+ * parameters:
+ * lStyle = additional style flags
+ * (be careful, NT3.51 & Win32s will ignore the new ones)
+ * x,y = x & y positions IN DIALOG UNITS
+ * w,h = width and height IN DIALOG UNITS
+ * Id = ID used in messages
+ * clss = class ID, e.g 0x0080 for a button, 0x0082 for a static
+ * caption = usually text or resource name
+ *
+ * TODO: use the length information noted here to enable the dialog creation
+ * routines to work out more exactly how much memory they need to alloc.
+ */
+ static PWORD
+add_dialog_element(
+ PWORD p,
+ DWORD lStyle,
+ WORD x,
+ WORD y,
+ WORD w,
+ WORD h,
+ WORD Id,
+ WORD clss,
+ const char *caption)
+{
+ int nchar;
+
+ p = lpwAlign(p); /* Align to dword boundary*/
+ lStyle = lStyle | WS_VISIBLE | WS_CHILD;
+ *p++ = LOWORD(lStyle);
+ *p++ = HIWORD(lStyle);
+ *p++ = 0; // LOWORD (lExtendedStyle)
+ *p++ = 0; // HIWORD (lExtendedStyle)
+ *p++ = x;
+ *p++ = y;
+ *p++ = w;
+ *p++ = h;
+ *p++ = Id; //9 or 10 words in all
+
+ *p++ = (WORD)0xffff;
+ *p++ = clss; //2 more here
+
+ nchar = nCopyAnsiToWideChar(p, (LPSTR)caption, TRUE); //strlen(caption)+1
+ p += nchar;
+
+ *p++ = 0; // advance pointer over nExtraStuff WORD - 2 more
+
+ return p; //total = 15+ (strlen(caption)) words
+ // = 30 + 2(strlen(caption) bytes reqd
+}
+
+
+/*
+ * Helper routine. Take an input pointer, return closest pointer that is
+ * aligned on a DWORD (4 byte) boundary. Taken from the Win32SDK samples.
+ */
+ static LPWORD
+lpwAlign(
+ LPWORD lpIn)
+{
+ long_u ul;
+
+ ul = (long_u)lpIn;
+ ul += 3;
+ ul >>= 2;
+ ul <<= 2;
+ return (LPWORD)ul;
+}
+
+/*
+ * Helper routine. Takes second parameter as Ansi string, copies it to first
+ * parameter as wide character (16-bits / char) string, and returns integer
+ * number of wide characters (words) in string (including the trailing wide
+ * char NULL). Partly taken from the Win32SDK samples.
+ * If "use_enc" is TRUE, 'encoding' is used for "lpAnsiIn". If FALSE, current
+ * ACP is used for "lpAnsiIn". */
+ static int
+nCopyAnsiToWideChar(
+ LPWORD lpWCStr,
+ LPSTR lpAnsiIn,
+ BOOL use_enc)
+{
+ int nChar = 0;
+ int len = lstrlen(lpAnsiIn) + 1; /* include NUL character */
+ int i;
+ WCHAR *wn;
+
+ if (use_enc && enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+ {
+ /* Not a codepage, use our own conversion function. */
+ wn = enc_to_utf16((char_u *)lpAnsiIn, NULL);
+ if (wn != NULL)
+ {
+ wcscpy(lpWCStr, wn);
+ nChar = (int)wcslen(wn) + 1;
+ vim_free(wn);
+ }
+ }
+ if (nChar == 0)
+ /* Use Win32 conversion function. */
+ nChar = MultiByteToWideChar(
+ enc_codepage > 0 ? enc_codepage : CP_ACP,
+ MB_PRECOMPOSED,
+ lpAnsiIn, len,
+ lpWCStr, len);
+ for (i = 0; i < nChar; ++i)
+ if (lpWCStr[i] == (WORD)'\t') /* replace tabs with spaces */
+ lpWCStr[i] = (WORD)' ';
+
+ return nChar;
+}
+
+
+#ifdef FEAT_TEAROFF
+/*
+ * Lookup menu handle from "menu_id".
+ */
+ static HMENU
+tearoff_lookup_menuhandle(
+ vimmenu_T *menu,
+ WORD menu_id)
+{
+ for ( ; menu != NULL; menu = menu->next)
+ {
+ if (menu->modes == 0) /* this menu has just been deleted */
+ continue;
+ if (menu_is_separator(menu->dname))
+ continue;
+ if ((WORD)((long_u)(menu->submenu_id) | (DWORD)0x8000) == menu_id)
+ return menu->submenu_id;
+ }
+ return NULL;
+}
+
+/*
+ * The callback function for all the modeless dialogs that make up the
+ * "tearoff menus" Very simple - forward button presses (to fool Vim into
+ * thinking its menus have been clicked), and go away when closed.
+ */
+ static LRESULT CALLBACK
+tearoff_callback(
+ HWND hwnd,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam)
+{
+ if (message == WM_INITDIALOG)
+ {
+ SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR)lParam);
+ return (TRUE);
+ }
+
+ /* May show the mouse pointer again. */
+ HandleMouseHide(message, lParam);
+
+ if (message == WM_COMMAND)
+ {
+ if ((WORD)(LOWORD(wParam)) & 0x8000)
+ {
+ POINT mp;
+ RECT rect;
+
+ if (GetCursorPos(&mp) && GetWindowRect(hwnd, &rect))
+ {
+ vimmenu_T *menu;
+
+ menu = (vimmenu_T*)GetWindowLongPtr(hwnd, DWLP_USER);
+ (void)TrackPopupMenu(
+ tearoff_lookup_menuhandle(menu, LOWORD(wParam)),
+ TPM_LEFTALIGN | TPM_LEFTBUTTON,
+ (int)rect.right - 8,
+ (int)mp.y,
+ (int)0, /*reserved param*/
+ s_hwnd,
+ NULL);
+ /*
+ * NOTE: The pop-up menu can eat the mouse up event.
+ * We deal with this in normal.c.
+ */
+ }
+ }
+ else
+ /* Pass on messages to the main Vim window */
+ PostMessage(s_hwnd, WM_COMMAND, LOWORD(wParam), 0);
+ /*
+ * Give main window the focus back: this is so after
+ * choosing a tearoff button you can start typing again
+ * straight away.
+ */
+ (void)SetFocus(s_hwnd);
+ return TRUE;
+ }
+ if ((message == WM_SYSCOMMAND) && (wParam == SC_CLOSE))
+ {
+ DestroyWindow(hwnd);
+ return TRUE;
+ }
+
+ /* When moved around, give main window the focus back. */
+ if (message == WM_EXITSIZEMOVE)
+ (void)SetActiveWindow(s_hwnd);
+
+ return FALSE;
+}
+#endif
+
+
+/*
+ * Decide whether to use the "new look" (small, non-bold font) or the "old
+ * look" (big, clanky font) for dialogs, and work out a few values for use
+ * later accordingly.
+ */
+ static void
+get_dialog_font_metrics(void)
+{
+ HDC hdc;
+ HFONT hfontTools = 0;
+ DWORD dlgFontSize;
+ SIZE size;
+#ifdef USE_SYSMENU_FONT
+ LOGFONT lfSysmenu;
+#endif
+
+ s_usenewlook = FALSE;
+
+#ifdef USE_SYSMENU_FONT
+ if (gui_w32_get_menu_font(&lfSysmenu) == OK)
+ hfontTools = CreateFontIndirect(&lfSysmenu);
+ else
+#endif
+ hfontTools = CreateFont(-DLG_FONT_POINT_SIZE, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, VARIABLE_PITCH , DLG_FONT_NAME);
+
+ if (hfontTools)
+ {
+ hdc = GetDC(s_hwnd);
+ SelectObject(hdc, hfontTools);
+ /*
+ * GetTextMetrics() doesn't return the right value in
+ * tmAveCharWidth, so we have to figure out the dialog base units
+ * ourselves.
+ */
+ GetTextExtentPoint(hdc,
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
+ 52, &size);
+ ReleaseDC(s_hwnd, hdc);
+
+ s_dlgfntwidth = (WORD)((size.cx / 26 + 1) / 2);
+ s_dlgfntheight = (WORD)size.cy;
+ s_usenewlook = TRUE;
+ }
+
+ if (!s_usenewlook)
+ {
+ dlgFontSize = GetDialogBaseUnits(); /* fall back to big old system*/
+ s_dlgfntwidth = LOWORD(dlgFontSize);
+ s_dlgfntheight = HIWORD(dlgFontSize);
+ }
+}
+
+#if defined(FEAT_MENU) && defined(FEAT_TEAROFF)
+/*
+ * Create a pseudo-"tearoff menu" based on the child
+ * items of a given menu pointer.
+ */
+ static void
+gui_mch_tearoff(
+ char_u *title,
+ vimmenu_T *menu,
+ int initX,
+ int initY)
+{
+ WORD *p, *pdlgtemplate, *pnumitems, *ptrueheight;
+ int template_len;
+ int nchar, textWidth, submenuWidth;
+ DWORD lStyle;
+ DWORD lExtendedStyle;
+ WORD dlgwidth;
+ WORD menuID;
+ vimmenu_T *pmenu;
+ vimmenu_T *top_menu;
+ vimmenu_T *the_menu = menu;
+ HWND hwnd;
+ HDC hdc;
+ HFONT font, oldFont;
+ int col, spaceWidth, len;
+ int columnWidths[2];
+ char_u *label, *text;
+ int acLen = 0;
+ int nameLen;
+ int padding0, padding1, padding2 = 0;
+ int sepPadding=0;
+ int x;
+ int y;
+#ifdef USE_SYSMENU_FONT
+ LOGFONT lfSysmenu;
+ int use_lfSysmenu = FALSE;
+#endif
+
+ /*
+ * If this menu is already torn off, move it to the mouse position.
+ */
+ if (IsWindow(menu->tearoff_handle))
+ {
+ POINT mp;
+ if (GetCursorPos((LPPOINT)&mp))
+ {
+ SetWindowPos(menu->tearoff_handle, NULL, mp.x, mp.y, 0, 0,
+ SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
+ }
+ return;
+ }
+
+ /*
+ * Create a new tearoff.
+ */
+ if (*title == MNU_HIDDEN_CHAR)
+ title++;
+
+ /* Allocate memory to store the dialog template. It's made bigger when
+ * needed. */
+ template_len = DLG_ALLOC_SIZE;
+ pdlgtemplate = p = (WORD *)LocalAlloc(LPTR, template_len);
+ if (p == NULL)
+ return;
+
+ hwnd = GetDesktopWindow();
+ hdc = GetWindowDC(hwnd);
+#ifdef USE_SYSMENU_FONT
+ if (gui_w32_get_menu_font(&lfSysmenu) == OK)
+ {
+ font = CreateFontIndirect(&lfSysmenu);
+ use_lfSysmenu = TRUE;
+ }
+ else
+#endif
+ font = CreateFont(-DLG_FONT_POINT_SIZE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ VARIABLE_PITCH , DLG_FONT_NAME);
+ if (s_usenewlook)
+ oldFont = SelectFont(hdc, font);
+ else
+ oldFont = SelectFont(hdc, GetStockObject(SYSTEM_FONT));
+
+ /* Calculate width of a single space. Used for padding columns to the
+ * right width. */
+ spaceWidth = GetTextWidth(hdc, (char_u *)" ", 1);
+
+ /* Figure out max width of the text column, the accelerator column and the
+ * optional submenu column. */
+ submenuWidth = 0;
+ for (col = 0; col < 2; col++)
+ {
+ columnWidths[col] = 0;
+ for (pmenu = menu->children; pmenu != NULL; pmenu = pmenu->next)
+ {
+ /* Use "dname" here to compute the width of the visible text. */
+ text = (col == 0) ? pmenu->dname : pmenu->actext;
+ if (text != NULL && *text != NUL)
+ {
+ textWidth = GetTextWidthEnc(hdc, text, (int)STRLEN(text));
+ if (textWidth > columnWidths[col])
+ columnWidths[col] = textWidth;
+ }
+ if (pmenu->children != NULL)
+ submenuWidth = TEAROFF_COLUMN_PADDING * spaceWidth;
+ }
+ }
+ if (columnWidths[1] == 0)
+ {
+ /* no accelerators */
+ if (submenuWidth != 0)
+ columnWidths[0] += submenuWidth;
+ else
+ columnWidths[0] += spaceWidth;
+ }
+ else
+ {
+ /* there is an accelerator column */
+ columnWidths[0] += TEAROFF_COLUMN_PADDING * spaceWidth;
+ columnWidths[1] += submenuWidth;
+ }
+
+ /*
+ * Now find the total width of our 'menu'.
+ */
+ textWidth = columnWidths[0] + columnWidths[1];
+ if (submenuWidth != 0)
+ {
+ submenuWidth = GetTextWidth(hdc, (char_u *)TEAROFF_SUBMENU_LABEL,
+ (int)STRLEN(TEAROFF_SUBMENU_LABEL));
+ textWidth += submenuWidth;
+ }
+ dlgwidth = GetTextWidthEnc(hdc, title, (int)STRLEN(title));
+ if (textWidth > dlgwidth)
+ dlgwidth = textWidth;
+ dlgwidth += 2 * TEAROFF_PADDING_X + TEAROFF_BUTTON_PAD_X;
+
+ /* start to fill in the dlgtemplate information. addressing by WORDs */
+ if (s_usenewlook)
+ lStyle = DS_MODALFRAME | WS_CAPTION| WS_SYSMENU |DS_SETFONT| WS_VISIBLE;
+ else
+ lStyle = DS_MODALFRAME | WS_CAPTION| WS_SYSMENU | WS_VISIBLE;
+
+ lExtendedStyle = WS_EX_TOOLWINDOW|WS_EX_STATICEDGE;
+ *p++ = LOWORD(lStyle);
+ *p++ = HIWORD(lStyle);
+ *p++ = LOWORD(lExtendedStyle);
+ *p++ = HIWORD(lExtendedStyle);
+ pnumitems = p; /* save where the number of items must be stored */
+ *p++ = 0; // NumberOfItems(will change later)
+ gui_mch_getmouse(&x, &y);
+ if (initX == 0xffffL)
+ *p++ = PixelToDialogX(x); // x
+ else
+ *p++ = PixelToDialogX(initX); // x
+ if (initY == 0xffffL)
+ *p++ = PixelToDialogY(y); // y
+ else
+ *p++ = PixelToDialogY(initY); // y
+ *p++ = PixelToDialogX(dlgwidth); // cx
+ ptrueheight = p;
+ *p++ = 0; // dialog height: changed later anyway
+ *p++ = 0; // Menu
+ *p++ = 0; // Class
+
+ /* copy the title of the dialog */
+ nchar = nCopyAnsiToWideChar(p, ((*title)
+ ? (LPSTR)title
+ : (LPSTR)("Vim "VIM_VERSION_MEDIUM)), TRUE);
+ p += nchar;
+
+ if (s_usenewlook)
+ {
+ /* do the font, since DS_3DLOOK doesn't work properly */
+#ifdef USE_SYSMENU_FONT
+ if (use_lfSysmenu)
+ {
+ /* point size */
+ *p++ = -MulDiv(lfSysmenu.lfHeight, 72,
+ GetDeviceCaps(hdc, LOGPIXELSY));
+ nchar = nCopyAnsiToWideChar(p, lfSysmenu.lfFaceName, FALSE);
+ }
+ else
+#endif
+ {
+ *p++ = DLG_FONT_POINT_SIZE; // point size
+ nchar = nCopyAnsiToWideChar(p, DLG_FONT_NAME, FALSE);
+ }
+ p += nchar;
+ }
+
+ /*
+ * Loop over all the items in the menu.
+ * But skip over the tearbar.
+ */
+ if (STRCMP(menu->children->name, TEAR_STRING) == 0)
+ menu = menu->children->next;
+ else
+ menu = menu->children;
+ top_menu = menu;
+ for ( ; menu != NULL; menu = menu->next)
+ {
+ if (menu->modes == 0) /* this menu has just been deleted */
+ continue;
+ if (menu_is_separator(menu->dname))
+ {
+ sepPadding += 3;
+ continue;
+ }
+
+ /* Check if there still is plenty of room in the template. Make it
+ * larger when needed. */
+ if (((char *)p - (char *)pdlgtemplate) + 1000 > template_len)
+ {
+ WORD *newp;
+
+ newp = (WORD *)LocalAlloc(LPTR, template_len + 4096);
+ if (newp != NULL)
+ {
+ template_len += 4096;
+ mch_memmove(newp, pdlgtemplate,
+ (char *)p - (char *)pdlgtemplate);
+ p = newp + (p - pdlgtemplate);
+ pnumitems = newp + (pnumitems - pdlgtemplate);
+ ptrueheight = newp + (ptrueheight - pdlgtemplate);
+ LocalFree(LocalHandle(pdlgtemplate));
+ pdlgtemplate = newp;
+ }
+ }
+
+ /* Figure out minimal length of this menu label. Use "name" for the
+ * actual text, "dname" for estimating the displayed size. "name"
+ * has "&a" for mnemonic and includes the accelerator. */
+ len = nameLen = (int)STRLEN(menu->name);
+ padding0 = (columnWidths[0] - GetTextWidthEnc(hdc, menu->dname,
+ (int)STRLEN(menu->dname))) / spaceWidth;
+ len += padding0;
+
+ if (menu->actext != NULL)
+ {
+ acLen = (int)STRLEN(menu->actext);
+ len += acLen;
+ textWidth = GetTextWidthEnc(hdc, menu->actext, acLen);
+ }
+ else
+ textWidth = 0;
+ padding1 = (columnWidths[1] - textWidth) / spaceWidth;
+ len += padding1;
+
+ if (menu->children == NULL)
+ {
+ padding2 = submenuWidth / spaceWidth;
+ len += padding2;
+ menuID = (WORD)(menu->id);
+ }
+ else
+ {
+ len += (int)STRLEN(TEAROFF_SUBMENU_LABEL);
+ menuID = (WORD)((long_u)(menu->submenu_id) | (DWORD)0x8000);
+ }
+
+ /* Allocate menu label and fill it in */
+ text = label = alloc((unsigned)len + 1);
+ if (label == NULL)
+ break;
+
+ vim_strncpy(text, menu->name, nameLen);
+ text = vim_strchr(text, TAB); /* stop at TAB before actext */
+ if (text == NULL)
+ text = label + nameLen; /* no actext, use whole name */
+ while (padding0-- > 0)
+ *text++ = ' ';
+ if (menu->actext != NULL)
+ {
+ STRNCPY(text, menu->actext, acLen);
+ text += acLen;
+ }
+ while (padding1-- > 0)
+ *text++ = ' ';
+ if (menu->children != NULL)
+ {
+ STRCPY(text, TEAROFF_SUBMENU_LABEL);
+ text += STRLEN(TEAROFF_SUBMENU_LABEL);
+ }
+ else
+ {
+ while (padding2-- > 0)
+ *text++ = ' ';
+ }
+ *text = NUL;
+
+ /*
+ * BS_LEFT will just be ignored on Win32s/NT3.5x - on
+ * W95/NT4 it makes the tear-off look more like a menu.
+ */
+ p = add_dialog_element(p,
+ BS_PUSHBUTTON|BS_LEFT,
+ (WORD)PixelToDialogX(TEAROFF_PADDING_X),
+ (WORD)(sepPadding + 1 + 13 * (*pnumitems)),
+ (WORD)PixelToDialogX(dlgwidth - 2 * TEAROFF_PADDING_X),
+ (WORD)12,
+ menuID, (WORD)0x0080, (char *)label);
+ vim_free(label);
+ (*pnumitems)++;
+ }
+
+ *ptrueheight = (WORD)(sepPadding + 1 + 13 * (*pnumitems));
+
+
+ /* show modelessly */
+ the_menu->tearoff_handle = CreateDialogIndirectParam(
+ s_hinst,
+ (LPDLGTEMPLATE)pdlgtemplate,
+ s_hwnd,
+ (DLGPROC)tearoff_callback,
+ (LPARAM)top_menu);
+
+ LocalFree(LocalHandle(pdlgtemplate));
+ SelectFont(hdc, oldFont);
+ DeleteObject(font);
+ ReleaseDC(hwnd, hdc);
+
+ /*
+ * Reassert ourselves as the active window. This is so that after creating
+ * a tearoff, the user doesn't have to click with the mouse just to start
+ * typing again!
+ */
+ (void)SetActiveWindow(s_hwnd);
+
+ /* make sure the right buttons are enabled */
+ force_menu_update = TRUE;
+}
+#endif
+
+#if defined(FEAT_TOOLBAR) || defined(PROTO)
+#include "gui_w32_rc.h"
+
+/* This not defined in older SDKs */
+# ifndef TBSTYLE_FLAT
+# define TBSTYLE_FLAT 0x0800
+# endif
+
+/*
+ * Create the toolbar, initially unpopulated.
+ * (just like the menu, there are no defaults, it's all
+ * set up through menu.vim)
+ */
+ static void
+initialise_toolbar(void)
+{
+ InitCommonControls();
+ s_toolbarhwnd = CreateToolbarEx(
+ s_hwnd,
+ WS_CHILD | TBSTYLE_TOOLTIPS | TBSTYLE_FLAT,
+ 4000, //any old big number
+ 31, //number of images in initial bitmap
+ s_hinst,
+ IDR_TOOLBAR1, // id of initial bitmap
+ NULL,
+ 0, // initial number of buttons
+ TOOLBAR_BUTTON_WIDTH, //api guide is wrong!
+ TOOLBAR_BUTTON_HEIGHT,
+ TOOLBAR_BUTTON_WIDTH,
+ TOOLBAR_BUTTON_HEIGHT,
+ sizeof(TBBUTTON)
+ );
+ s_toolbar_wndproc = SubclassWindow(s_toolbarhwnd, toolbar_wndproc);
+
+ gui_mch_show_toolbar(vim_strchr(p_go, GO_TOOLBAR) != NULL);
+}
+
+ static LRESULT CALLBACK
+toolbar_wndproc(
+ HWND hwnd,
+ UINT uMsg,
+ WPARAM wParam,
+ LPARAM lParam)
+{
+ HandleMouseHide(uMsg, lParam);
+ return CallWindowProc(s_toolbar_wndproc, hwnd, uMsg, wParam, lParam);
+}
+
+ static int
+get_toolbar_bitmap(vimmenu_T *menu)
+{
+ int i = -1;
+
+ /*
+ * Check user bitmaps first, unless builtin is specified.
+ */
+ if (!menu->icon_builtin)
+ {
+ char_u fname[MAXPATHL];
+ HANDLE hbitmap = NULL;
+
+ if (menu->iconfile != NULL)
+ {
+ gui_find_iconfile(menu->iconfile, fname, "bmp");
+ hbitmap = LoadImage(
+ NULL,
+ (LPCSTR)fname,
+ IMAGE_BITMAP,
+ TOOLBAR_BUTTON_WIDTH,
+ TOOLBAR_BUTTON_HEIGHT,
+ LR_LOADFROMFILE |
+ LR_LOADMAP3DCOLORS
+ );
+ }
+
+ /*
+ * If the LoadImage call failed, or the "icon=" file
+ * didn't exist or wasn't specified, try the menu name
+ */
+ if (hbitmap == NULL
+ && (gui_find_bitmap(
+#ifdef FEAT_MULTI_LANG
+ menu->en_dname != NULL ? menu->en_dname :
+#endif
+ menu->dname, fname, "bmp") == OK))
+ hbitmap = LoadImage(
+ NULL,
+ (LPCSTR)fname,
+ IMAGE_BITMAP,
+ TOOLBAR_BUTTON_WIDTH,
+ TOOLBAR_BUTTON_HEIGHT,
+ LR_LOADFROMFILE |
+ LR_LOADMAP3DCOLORS
+ );
+
+ if (hbitmap != NULL)
+ {
+ TBADDBITMAP tbAddBitmap;
+
+ tbAddBitmap.hInst = NULL;
+ tbAddBitmap.nID = (long_u)hbitmap;
+
+ i = (int)SendMessage(s_toolbarhwnd, TB_ADDBITMAP,
+ (WPARAM)1, (LPARAM)&tbAddBitmap);
+ /* i will be set to -1 if it fails */
+ }
+ }
+ if (i == -1 && menu->iconidx >= 0 && menu->iconidx < TOOLBAR_BITMAP_COUNT)
+ i = menu->iconidx;
+
+ return i;
+}
+#endif
+
+#if defined(FEAT_GUI_TABLINE) || defined(PROTO)
+ static void
+initialise_tabline(void)
+{
+ InitCommonControls();
+
+ s_tabhwnd = CreateWindow(WC_TABCONTROL, "Vim tabline",
+ WS_CHILD|TCS_FOCUSNEVER|TCS_TOOLTIPS,
+ CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
+ CW_USEDEFAULT, s_hwnd, NULL, s_hinst, NULL);
+ s_tabline_wndproc = SubclassWindow(s_tabhwnd, tabline_wndproc);
+
+ gui.tabline_height = TABLINE_HEIGHT;
+
+# ifdef USE_SYSMENU_FONT
+ set_tabline_font();
+# endif
+}
+
+/*
+ * Get tabpage_T from POINT.
+ */
+ static tabpage_T *
+GetTabFromPoint(
+ HWND hWnd,
+ POINT pt)
+{
+ tabpage_T *ptp = NULL;
+
+ if (gui_mch_showing_tabline())
+ {
+ TCHITTESTINFO htinfo;
+ htinfo.pt = pt;
+ /* ignore if a window under cusor is not tabcontrol. */
+ if (s_tabhwnd == hWnd)
+ {
+ int idx = TabCtrl_HitTest(s_tabhwnd, &htinfo);
+ if (idx != -1)
+ ptp = find_tabpage(idx + 1);
+ }
+ }
+ return ptp;
+}
+
+static POINT s_pt = {0, 0};
+static HCURSOR s_hCursor = NULL;
+
+ static LRESULT CALLBACK
+tabline_wndproc(
+ HWND hwnd,
+ UINT uMsg,
+ WPARAM wParam,
+ LPARAM lParam)
+{
+ POINT pt;
+ tabpage_T *tp;
+ RECT rect;
+ int nCenter;
+ int idx0;
+ int idx1;
+
+ HandleMouseHide(uMsg, lParam);
+
+ switch (uMsg)
+ {
+ case WM_LBUTTONDOWN:
+ {
+ s_pt.x = GET_X_LPARAM(lParam);
+ s_pt.y = GET_Y_LPARAM(lParam);
+ SetCapture(hwnd);
+ s_hCursor = GetCursor(); /* backup default cursor */
+ break;
+ }
+ case WM_MOUSEMOVE:
+ if (GetCapture() == hwnd
+ && ((wParam & MK_LBUTTON)) != 0)
+ {
+ pt.x = GET_X_LPARAM(lParam);
+ pt.y = s_pt.y;
+ if (abs(pt.x - s_pt.x) > GetSystemMetrics(SM_CXDRAG))
+ {
+ SetCursor(LoadCursor(NULL, IDC_SIZEWE));
+
+ tp = GetTabFromPoint(hwnd, pt);
+ if (tp != NULL)
+ {
+ idx0 = tabpage_index(curtab) - 1;
+ idx1 = tabpage_index(tp) - 1;
+
+ TabCtrl_GetItemRect(hwnd, idx1, &rect);
+ nCenter = rect.left + (rect.right - rect.left) / 2;
+
+ /* Check if the mouse cursor goes over the center of
+ * the next tab to prevent "flickering". */
+ if ((idx0 < idx1) && (nCenter < pt.x))
+ {
+ tabpage_move(idx1 + 1);
+ update_screen(0);
+ }
+ else if ((idx1 < idx0) && (pt.x < nCenter))
+ {
+ tabpage_move(idx1);
+ update_screen(0);
+ }
+ }
+ }
+ }
+ break;
+ case WM_LBUTTONUP:
+ {
+ if (GetCapture() == hwnd)
+ {
+ SetCursor(s_hCursor);
+ ReleaseCapture();
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ return CallWindowProc(s_tabline_wndproc, hwnd, uMsg, wParam, lParam);
+}
+#endif
+
+#if defined(FEAT_OLE) || defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * Make the GUI window come to the foreground.
+ */
+ void
+gui_mch_set_foreground(void)
+{
+ if (IsIconic(s_hwnd))
+ SendMessage(s_hwnd, WM_SYSCOMMAND, SC_RESTORE, 0);
+ SetForegroundWindow(s_hwnd);
+}
+#endif
+
+#if defined(FEAT_MBYTE_IME) && defined(DYNAMIC_IME)
+ static void
+dyn_imm_load(void)
+{
+ hLibImm = vimLoadLib("imm32.dll");
+ if (hLibImm == NULL)
+ return;
+
+ pImmGetCompositionStringA
+ = (void *)GetProcAddress(hLibImm, "ImmGetCompositionStringA");
+ pImmGetCompositionStringW
+ = (void *)GetProcAddress(hLibImm, "ImmGetCompositionStringW");
+ pImmGetContext
+ = (void *)GetProcAddress(hLibImm, "ImmGetContext");
+ pImmAssociateContext
+ = (void *)GetProcAddress(hLibImm, "ImmAssociateContext");
+ pImmReleaseContext
+ = (void *)GetProcAddress(hLibImm, "ImmReleaseContext");
+ pImmGetOpenStatus
+ = (void *)GetProcAddress(hLibImm, "ImmGetOpenStatus");
+ pImmSetOpenStatus
+ = (void *)GetProcAddress(hLibImm, "ImmSetOpenStatus");
+ pImmGetCompositionFont
+ = (void *)GetProcAddress(hLibImm, "ImmGetCompositionFontA");
+ pImmSetCompositionFont
+ = (void *)GetProcAddress(hLibImm, "ImmSetCompositionFontA");
+ pImmSetCompositionWindow
+ = (void *)GetProcAddress(hLibImm, "ImmSetCompositionWindow");
+ pImmGetConversionStatus
+ = (void *)GetProcAddress(hLibImm, "ImmGetConversionStatus");
+ pImmSetConversionStatus
+ = (void *)GetProcAddress(hLibImm, "ImmSetConversionStatus");
+
+ if ( pImmGetCompositionStringA == NULL
+ || pImmGetCompositionStringW == NULL
+ || pImmGetContext == NULL
+ || pImmAssociateContext == NULL
+ || pImmReleaseContext == NULL
+ || pImmGetOpenStatus == NULL
+ || pImmSetOpenStatus == NULL
+ || pImmGetCompositionFont == NULL
+ || pImmSetCompositionFont == NULL
+ || pImmSetCompositionWindow == NULL
+ || pImmGetConversionStatus == NULL
+ || pImmSetConversionStatus == NULL)
+ {
+ FreeLibrary(hLibImm);
+ hLibImm = NULL;
+ pImmGetContext = NULL;
+ return;
+ }
+
+ return;
+}
+
+#endif
+
+#if defined(FEAT_SIGN_ICONS) || defined(PROTO)
+
+# ifdef FEAT_XPM_W32
+# define IMAGE_XPM 100
+# endif
+
+typedef struct _signicon_t
+{
+ HANDLE hImage;
+ UINT uType;
+#ifdef FEAT_XPM_W32
+ HANDLE hShape; /* Mask bitmap handle */
+#endif
+} signicon_t;
+
+ void
+gui_mch_drawsign(int row, int col, int typenr)
+{
+ signicon_t *sign;
+ int x, y, w, h;
+
+ if (!gui.in_use || (sign = (signicon_t *)sign_get_image(typenr)) == NULL)
+ return;
+
+#if defined(FEAT_DIRECTX)
+ if (IS_ENABLE_DIRECTX())
+ DWriteContext_Flush(s_dwc);
+#endif
+
+ x = TEXT_X(col);
+ y = TEXT_Y(row);
+ w = gui.char_width * 2;
+ h = gui.char_height;
+ switch (sign->uType)
+ {
+ case IMAGE_BITMAP:
+ {
+ HDC hdcMem;
+ HBITMAP hbmpOld;
+
+ hdcMem = CreateCompatibleDC(s_hdc);
+ hbmpOld = (HBITMAP)SelectObject(hdcMem, sign->hImage);
+ BitBlt(s_hdc, x, y, w, h, hdcMem, 0, 0, SRCCOPY);
+ SelectObject(hdcMem, hbmpOld);
+ DeleteDC(hdcMem);
+ }
+ break;
+ case IMAGE_ICON:
+ case IMAGE_CURSOR:
+ DrawIconEx(s_hdc, x, y, (HICON)sign->hImage, w, h, 0, NULL, DI_NORMAL);
+ break;
+#ifdef FEAT_XPM_W32
+ case IMAGE_XPM:
+ {
+ HDC hdcMem;
+ HBITMAP hbmpOld;
+
+ hdcMem = CreateCompatibleDC(s_hdc);
+ hbmpOld = (HBITMAP)SelectObject(hdcMem, sign->hShape);
+ /* Make hole */
+ BitBlt(s_hdc, x, y, w, h, hdcMem, 0, 0, SRCAND);
+
+ SelectObject(hdcMem, sign->hImage);
+ /* Paint sign */
+ BitBlt(s_hdc, x, y, w, h, hdcMem, 0, 0, SRCPAINT);
+ SelectObject(hdcMem, hbmpOld);
+ DeleteDC(hdcMem);
+ }
+ break;
+#endif
+ }
+}
+
+ static void
+close_signicon_image(signicon_t *sign)
+{
+ if (sign)
+ switch (sign->uType)
+ {
+ case IMAGE_BITMAP:
+ DeleteObject((HGDIOBJ)sign->hImage);
+ break;
+ case IMAGE_CURSOR:
+ DestroyCursor((HCURSOR)sign->hImage);
+ break;
+ case IMAGE_ICON:
+ DestroyIcon((HICON)sign->hImage);
+ break;
+#ifdef FEAT_XPM_W32
+ case IMAGE_XPM:
+ DeleteObject((HBITMAP)sign->hImage);
+ DeleteObject((HBITMAP)sign->hShape);
+ break;
+#endif
+ }
+}
+
+ void *
+gui_mch_register_sign(char_u *signfile)
+{
+ signicon_t sign, *psign;
+ char_u *ext;
+
+ sign.hImage = NULL;
+ ext = signfile + STRLEN(signfile) - 4; /* get extension */
+ if (ext > signfile)
+ {
+ int do_load = 1;
+
+ if (!STRICMP(ext, ".bmp"))
+ sign.uType = IMAGE_BITMAP;
+ else if (!STRICMP(ext, ".ico"))
+ sign.uType = IMAGE_ICON;
+ else if (!STRICMP(ext, ".cur") || !STRICMP(ext, ".ani"))
+ sign.uType = IMAGE_CURSOR;
+ else
+ do_load = 0;
+
+ if (do_load)
+ sign.hImage = (HANDLE)LoadImage(NULL, (LPCSTR)signfile, sign.uType,
+ gui.char_width * 2, gui.char_height,
+ LR_LOADFROMFILE | LR_CREATEDIBSECTION);
+#ifdef FEAT_XPM_W32
+ if (!STRICMP(ext, ".xpm"))
+ {
+ sign.uType = IMAGE_XPM;
+ LoadXpmImage((char *)signfile, (HBITMAP *)&sign.hImage,
+ (HBITMAP *)&sign.hShape);
+ }
+#endif
+ }
+
+ psign = NULL;
+ if (sign.hImage && (psign = (signicon_t *)alloc(sizeof(signicon_t)))
+ != NULL)
+ *psign = sign;
+
+ if (!psign)
+ {
+ if (sign.hImage)
+ close_signicon_image(&sign);
+ emsg(_(e_signdata));
+ }
+ return (void *)psign;
+
+}
+
+ void
+gui_mch_destroy_sign(void *sign)
+{
+ if (sign)
+ {
+ close_signicon_image((signicon_t *)sign);
+ vim_free(sign);
+ }
+}
+#endif
+
+#if defined(FEAT_BEVAL_GUI) || defined(PROTO)
+
+/* BALLOON-EVAL IMPLEMENTATION FOR WINDOWS.
+ * Added by Sergey Khorev <sergey.khorev@gmail.com>
+ *
+ * The only reused thing is beval.h and get_beval_info()
+ * from gui_beval.c (note it uses x and y of the BalloonEval struct
+ * to get current mouse position).
+ *
+ * Trying to use as more Windows services as possible, and as less
+ * IE version as possible :)).
+ *
+ * 1) Don't create ToolTip in gui_mch_create_beval_area, only initialize
+ * BalloonEval struct.
+ * 2) Enable/Disable simply create/kill BalloonEval Timer
+ * 3) When there was enough inactivity, timer procedure posts
+ * async request to debugger
+ * 4) gui_mch_post_balloon (invoked from netbeans.c) creates tooltip control
+ * and performs some actions to show it ASAP
+ * 5) WM_NOTIFY:TTN_POP destroys created tooltip
+ */
+
+/*
+ * determine whether installed Common Controls support multiline tooltips
+ * (i.e. their version is >= 4.70
+ */
+ int
+multiline_balloon_available(void)
+{
+ HINSTANCE hDll;
+ static char comctl_dll[] = "comctl32.dll";
+ static int multiline_tip = MAYBE;
+
+ if (multiline_tip != MAYBE)
+ return multiline_tip;
+
+ hDll = GetModuleHandle(comctl_dll);
+ if (hDll != NULL)
+ {
+ DLLGETVERSIONPROC pGetVer;
+ pGetVer = (DLLGETVERSIONPROC)GetProcAddress(hDll, "DllGetVersion");
+
+ if (pGetVer != NULL)
+ {
+ DLLVERSIONINFO dvi;
+ HRESULT hr;
+
+ ZeroMemory(&dvi, sizeof(dvi));
+ dvi.cbSize = sizeof(dvi);
+
+ hr = (*pGetVer)(&dvi);
+
+ if (SUCCEEDED(hr)
+ && (dvi.dwMajorVersion > 4
+ || (dvi.dwMajorVersion == 4
+ && dvi.dwMinorVersion >= 70)))
+ {
+ multiline_tip = TRUE;
+ return multiline_tip;
+ }
+ }
+ else
+ {
+ /* there is chance we have ancient CommCtl 4.70
+ which doesn't export DllGetVersion */
+ DWORD dwHandle = 0;
+ DWORD len = GetFileVersionInfoSize(comctl_dll, &dwHandle);
+ if (len > 0)
+ {
+ VS_FIXEDFILEINFO *ver;
+ UINT vlen = 0;
+ void *data = alloc(len);
+
+ if ((data != NULL
+ && GetFileVersionInfo(comctl_dll, 0, len, data)
+ && VerQueryValue(data, "\\", (void **)&ver, &vlen)
+ && vlen
+ && HIWORD(ver->dwFileVersionMS) > 4)
+ || ((HIWORD(ver->dwFileVersionMS) == 4
+ && LOWORD(ver->dwFileVersionMS) >= 70)))
+ {
+ vim_free(data);
+ multiline_tip = TRUE;
+ return multiline_tip;
+ }
+ vim_free(data);
+ }
+ }
+ }
+ multiline_tip = FALSE;
+ return multiline_tip;
+}
+
+ static void
+make_tooltipw(BalloonEval *beval, char *text, POINT pt)
+{
+ TOOLINFOW *pti;
+ int ToolInfoSize;
+
+ if (multiline_balloon_available() == TRUE)
+ ToolInfoSize = sizeof(TOOLINFOW_NEW);
+ else
+ ToolInfoSize = sizeof(TOOLINFOW);
+
+ pti = (TOOLINFOW *)alloc(ToolInfoSize);
+ if (pti == NULL)
+ return;
+
+ beval->balloon = CreateWindowExW(WS_EX_TOPMOST, TOOLTIPS_CLASSW,
+ NULL, WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
+ CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
+ beval->target, NULL, s_hinst, NULL);
+
+ SetWindowPos(beval->balloon, HWND_TOPMOST, 0, 0, 0, 0,
+ SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
+
+ pti->cbSize = ToolInfoSize;
+ pti->uFlags = TTF_SUBCLASS;
+ pti->hwnd = beval->target;
+ pti->hinst = 0; // Don't use string resources
+ pti->uId = ID_BEVAL_TOOLTIP;
+
+ if (multiline_balloon_available() == TRUE)
+ {
+ RECT rect;
+ TOOLINFOW_NEW *ptin = (TOOLINFOW_NEW *)pti;
+ pti->lpszText = LPSTR_TEXTCALLBACKW;
+ beval->tofree = enc_to_utf16((char_u*)text, NULL);
+ ptin->lParam = (LPARAM)beval->tofree;
+ // switch multiline tooltips on
+ if (GetClientRect(s_textArea, &rect))
+ SendMessageW(beval->balloon, TTM_SETMAXTIPWIDTH, 0,
+ (LPARAM)rect.right);
+ }
+ else
+ {
+ // do this old way
+ beval->tofree = enc_to_utf16((char_u*)text, NULL);
+ pti->lpszText = (LPWSTR)beval->tofree;
+ }
+
+ // Limit ballooneval bounding rect to CursorPos neighbourhood.
+ pti->rect.left = pt.x - 3;
+ pti->rect.top = pt.y - 3;
+ pti->rect.right = pt.x + 3;
+ pti->rect.bottom = pt.y + 3;
+
+ SendMessageW(beval->balloon, TTM_ADDTOOLW, 0, (LPARAM)pti);
+ // Make tooltip appear sooner.
+ SendMessageW(beval->balloon, TTM_SETDELAYTIME, TTDT_INITIAL, 10);
+ // I've performed some tests and it seems the longest possible life time
+ // of tooltip is 30 seconds.
+ SendMessageW(beval->balloon, TTM_SETDELAYTIME, TTDT_AUTOPOP, 30000);
+ /*
+ * HACK: force tooltip to appear, because it'll not appear until
+ * first mouse move. D*mn M$
+ * Amazingly moving (2, 2) and then (-1, -1) the mouse doesn't move.
+ */
+ mouse_event(MOUSEEVENTF_MOVE, 2, 2, 0, 0);
+ mouse_event(MOUSEEVENTF_MOVE, (DWORD)-1, (DWORD)-1, 0, 0);
+ vim_free(pti);
+}
+
+ static void
+make_tooltip(BalloonEval *beval, char *text, POINT pt)
+{
+ TOOLINFO *pti;
+ int ToolInfoSize;
+
+ if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+ {
+ make_tooltipw(beval, text, pt);
+ return;
+ }
+
+ if (multiline_balloon_available() == TRUE)
+ ToolInfoSize = sizeof(TOOLINFO_NEW);
+ else
+ ToolInfoSize = sizeof(TOOLINFO);
+
+ pti = (TOOLINFO *)alloc(ToolInfoSize);
+ if (pti == NULL)
+ return;
+
+ beval->balloon = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS,
+ NULL, WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
+ CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
+ beval->target, NULL, s_hinst, NULL);
+
+ SetWindowPos(beval->balloon, HWND_TOPMOST, 0, 0, 0, 0,
+ SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
+
+ pti->cbSize = ToolInfoSize;
+ pti->uFlags = TTF_SUBCLASS;
+ pti->hwnd = beval->target;
+ pti->hinst = 0; /* Don't use string resources */
+ pti->uId = ID_BEVAL_TOOLTIP;
+
+ if (multiline_balloon_available() == TRUE)
+ {
+ RECT rect;
+ TOOLINFO_NEW *ptin = (TOOLINFO_NEW *)pti;
+ pti->lpszText = LPSTR_TEXTCALLBACK;
+ beval->tofree = vim_strsave((char_u*)text);
+ ptin->lParam = (LPARAM)beval->tofree;
+ if (GetClientRect(s_textArea, &rect)) /* switch multiline tooltips on */
+ SendMessage(beval->balloon, TTM_SETMAXTIPWIDTH, 0,
+ (LPARAM)rect.right);
+ }
+ else
+ pti->lpszText = text; /* do this old way */
+
+ /* Limit ballooneval bounding rect to CursorPos neighbourhood */
+ pti->rect.left = pt.x - 3;
+ pti->rect.top = pt.y - 3;
+ pti->rect.right = pt.x + 3;
+ pti->rect.bottom = pt.y + 3;
+
+ SendMessage(beval->balloon, TTM_ADDTOOL, 0, (LPARAM)pti);
+ /* Make tooltip appear sooner */
+ SendMessage(beval->balloon, TTM_SETDELAYTIME, TTDT_INITIAL, 10);
+ /* I've performed some tests and it seems the longest possible life time
+ * of tooltip is 30 seconds */
+ SendMessage(beval->balloon, TTM_SETDELAYTIME, TTDT_AUTOPOP, 30000);
+ /*
+ * HACK: force tooltip to appear, because it'll not appear until
+ * first mouse move. D*mn M$
+ * Amazingly moving (2, 2) and then (-1, -1) the mouse doesn't move.
+ */
+ mouse_event(MOUSEEVENTF_MOVE, 2, 2, 0, 0);
+ mouse_event(MOUSEEVENTF_MOVE, (DWORD)-1, (DWORD)-1, 0, 0);
+ vim_free(pti);
+}
+
+ static void
+delete_tooltip(BalloonEval *beval)
+{
+ PostMessage(beval->balloon, WM_CLOSE, 0, 0);
+}
+
+ static VOID CALLBACK
+BevalTimerProc(
+ HWND hwnd UNUSED,
+ UINT uMsg UNUSED,
+ UINT_PTR idEvent UNUSED,
+ DWORD dwTime)
+{
+ POINT pt;
+ RECT rect;
+
+ if (cur_beval == NULL || cur_beval->showState == ShS_SHOWING || !p_beval)
+ return;
+
+ GetCursorPos(&pt);
+ if (WindowFromPoint(pt) != s_textArea)
+ return;
+
+ ScreenToClient(s_textArea, &pt);
+ GetClientRect(s_textArea, &rect);
+ if (!PtInRect(&rect, pt))
+ return;
+
+ if (LastActivity > 0
+ && (dwTime - LastActivity) >= (DWORD)p_bdlay
+ && (cur_beval->showState != ShS_PENDING
+ || abs(cur_beval->x - pt.x) > 3
+ || abs(cur_beval->y - pt.y) > 3))
+ {
+ /* Pointer resting in one place long enough, it's time to show
+ * the tooltip. */
+ cur_beval->showState = ShS_PENDING;
+ cur_beval->x = pt.x;
+ cur_beval->y = pt.y;
+
+ // TRACE0("BevalTimerProc: sending request");
+
+ if (cur_beval->msgCB != NULL)
+ (*cur_beval->msgCB)(cur_beval, 0);
+ }
+}
+
+ void
+gui_mch_disable_beval_area(BalloonEval *beval UNUSED)
+{
+ // TRACE0("gui_mch_disable_beval_area {{{");
+ KillTimer(s_textArea, BevalTimerId);
+ // TRACE0("gui_mch_disable_beval_area }}}");
+}
+
+ void
+gui_mch_enable_beval_area(BalloonEval *beval)
+{
+ // TRACE0("gui_mch_enable_beval_area |||");
+ if (beval == NULL)
+ return;
+ // TRACE0("gui_mch_enable_beval_area {{{");
+ BevalTimerId = SetTimer(s_textArea, 0, (UINT)(p_bdlay / 2), BevalTimerProc);
+ // TRACE0("gui_mch_enable_beval_area }}}");
+}
+
+ void
+gui_mch_post_balloon(BalloonEval *beval, char_u *mesg)
+{
+ POINT pt;
+
+ // TRACE0("gui_mch_post_balloon {{{");
+ if (beval->showState == ShS_SHOWING)
+ return;
+ GetCursorPos(&pt);
+ ScreenToClient(s_textArea, &pt);
+
+ if (abs(beval->x - pt.x) < 3 && abs(beval->y - pt.y) < 3)
+ {
+ /* cursor is still here */
+ gui_mch_disable_beval_area(cur_beval);
+ beval->showState = ShS_SHOWING;
+ make_tooltip(beval, (char *)mesg, pt);
+ }
+ // TRACE0("gui_mch_post_balloon }}}");
+}
+
+ BalloonEval *
+gui_mch_create_beval_area(
+ void *target, /* ignored, always use s_textArea */
+ char_u *mesg,
+ void (*mesgCB)(BalloonEval *, int),
+ void *clientData)
+{
+ /* partially stolen from gui_beval.c */
+ BalloonEval *beval;
+
+ if (mesg != NULL && mesgCB != NULL)
+ {
+ iemsg(_("E232: Cannot create BalloonEval with both message and callback"));
+ return NULL;
+ }
+
+ beval = (BalloonEval *)alloc_clear(sizeof(BalloonEval));
+ if (beval != NULL)
+ {
+ beval->target = s_textArea;
+
+ beval->showState = ShS_NEUTRAL;
+ beval->msg = mesg;
+ beval->msgCB = mesgCB;
+ beval->clientData = clientData;
+
+ InitCommonControls();
+ cur_beval = beval;
+
+ if (p_beval)
+ gui_mch_enable_beval_area(beval);
+ }
+ return beval;
+}
+
+ static void
+Handle_WM_Notify(HWND hwnd UNUSED, LPNMHDR pnmh)
+{
+ if (pnmh->idFrom != ID_BEVAL_TOOLTIP) /* it is not our tooltip */
+ return;
+
+ if (cur_beval != NULL)
+ {
+ switch (pnmh->code)
+ {
+ case TTN_SHOW:
+ // TRACE0("TTN_SHOW {{{");
+ // TRACE0("TTN_SHOW }}}");
+ break;
+ case TTN_POP: /* Before tooltip disappear */
+ // TRACE0("TTN_POP {{{");
+ delete_tooltip(cur_beval);
+ gui_mch_enable_beval_area(cur_beval);
+ // TRACE0("TTN_POP }}}");
+
+ cur_beval->showState = ShS_NEUTRAL;
+ break;
+ case TTN_GETDISPINFO:
+ {
+ /* if you get there then we have new common controls */
+ NMTTDISPINFO_NEW *info = (NMTTDISPINFO_NEW *)pnmh;
+ info->lpszText = (LPSTR)info->lParam;
+ info->uFlags |= TTF_DI_SETITEM;
+ }
+ break;
+ case TTN_GETDISPINFOW:
+ {
+ // if we get here then we have new common controls
+ NMTTDISPINFOW_NEW *info = (NMTTDISPINFOW_NEW *)pnmh;
+ info->lpszText = (LPWSTR)info->lParam;
+ info->uFlags |= TTF_DI_SETITEM;
+ }
+ break;
+ }
+ }
+}
+
+ static void
+TrackUserActivity(UINT uMsg)
+{
+ if ((uMsg >= WM_MOUSEFIRST && uMsg <= WM_MOUSELAST)
+ || (uMsg >= WM_KEYFIRST && uMsg <= WM_KEYLAST))
+ LastActivity = GetTickCount();
+}
+
+ void
+gui_mch_destroy_beval_area(BalloonEval *beval)
+{
+#ifdef FEAT_VARTABS
+ vim_free(beval->vts);
+#endif
+ vim_free(beval->tofree);
+ vim_free(beval);
+}
+#endif /* FEAT_BEVAL_GUI */
+
+#if defined(FEAT_NETBEANS_INTG) || defined(PROTO)
+/*
+ * We have multiple signs to draw at the same location. Draw the
+ * multi-sign indicator (down-arrow) instead. This is the Win32 version.
+ */
+ void
+netbeans_draw_multisign_indicator(int row)
+{
+ int i;
+ int y;
+ int x;
+
+ if (!netbeans_active())
+ return;
+
+ x = 0;
+ y = TEXT_Y(row);
+
+#if defined(FEAT_DIRECTX)
+ if (IS_ENABLE_DIRECTX())
+ DWriteContext_Flush(s_dwc);
+#endif
+
+ for (i = 0; i < gui.char_height - 3; i++)
+ SetPixel(s_hdc, x+2, y++, gui.currFgColor);
+
+ SetPixel(s_hdc, x+0, y, gui.currFgColor);
+ SetPixel(s_hdc, x+2, y, gui.currFgColor);
+ SetPixel(s_hdc, x+4, y++, gui.currFgColor);
+ SetPixel(s_hdc, x+1, y, gui.currFgColor);
+ SetPixel(s_hdc, x+2, y, gui.currFgColor);
+ SetPixel(s_hdc, x+3, y++, gui.currFgColor);
+ SetPixel(s_hdc, x+2, y, gui.currFgColor);
+}
+#endif
diff --git a/src/gui_w32_rc.h b/src/gui_w32_rc.h
new file mode 100644
index 0000000..6c0d773
--- /dev/null
+++ b/src/gui_w32_rc.h
@@ -0,0 +1,8 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by Script1.rc
+//
+#define IDR_TOOLBAR1 101
+//#define ID_TB_BLOB 40001
+//#define ID_TB_CIRCLE 40002
+
diff --git a/src/gui_x11.c b/src/gui_x11.c
new file mode 100644
index 0000000..ad91a21
--- /dev/null
+++ b/src/gui_x11.c
@@ -0,0 +1,3396 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ * GUI/Motif support by Robert Webb
+ *
+ * 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.
+ */
+/*
+ * Common code for the Motif and Athena GUI.
+ * Not used for GTK.
+ */
+
+#include "vim.h"
+
+#include <X11/keysym.h>
+#include <X11/Xatom.h>
+#include <X11/StringDefs.h>
+#include <X11/Intrinsic.h>
+#include <X11/Shell.h>
+#include <X11/cursorfont.h>
+
+/*
+ * XpmP.h is preferred, because it makes the signs drawn with a transparent
+ * background instead of black.
+ */
+#if defined(HAVE_XM_XPMP_H) && defined(FEAT_GUI_MOTIF) \
+ && !defined(HAVE_X11_XPM_H)
+# include <Xm/XpmP.h>
+#else
+# ifdef HAVE_X11_XPM_H
+# ifdef VMS
+# include <xpm.h>
+# else
+# include <X11/xpm.h>
+# endif
+# endif
+#endif
+
+#ifdef FEAT_XFONTSET
+# ifdef X_LOCALE
+# include <X11/Xlocale.h>
+# else
+# include <locale.h>
+# endif
+#endif
+
+#ifdef HAVE_X11_SUNKEYSYM_H
+# include <X11/Sunkeysym.h>
+#endif
+
+#ifdef HAVE_X11_XMU_EDITRES_H
+# include <X11/Xmu/Editres.h>
+#endif
+
+#define VIM_NAME "vim"
+#define VIM_CLASS "Vim"
+
+/* Default resource values */
+#define DFLT_FONT "7x13"
+#ifdef FONTSET_ALWAYS
+# define DFLT_MENU_FONT XtDefaultFontSet
+#else
+# define DFLT_MENU_FONT XtDefaultFont
+#endif
+#define DFLT_TOOLTIP_FONT XtDefaultFontSet
+
+#ifdef FEAT_GUI_ATHENA
+# define DFLT_MENU_BG_COLOR "gray77"
+# define DFLT_MENU_FG_COLOR "black"
+# define DFLT_SCROLL_BG_COLOR "gray60"
+# define DFLT_SCROLL_FG_COLOR "gray77"
+# define DFLT_TOOLTIP_BG_COLOR "#ffff91"
+# define DFLT_TOOLTIP_FG_COLOR "#000000"
+#else
+/* use the default (CDE) colors */
+# define DFLT_MENU_BG_COLOR ""
+# define DFLT_MENU_FG_COLOR ""
+# define DFLT_SCROLL_BG_COLOR ""
+# define DFLT_SCROLL_FG_COLOR ""
+# define DFLT_TOOLTIP_BG_COLOR "#ffff91"
+# define DFLT_TOOLTIP_FG_COLOR "#000000"
+#endif
+
+Widget vimShell = (Widget)0;
+
+static Atom wm_atoms[2]; /* Window Manager Atoms */
+#define DELETE_WINDOW_IDX 0 /* index in wm_atoms[] for WM_DELETE_WINDOW */
+#define SAVE_YOURSELF_IDX 1 /* index in wm_atoms[] for WM_SAVE_YOURSELF */
+
+#ifdef FEAT_XFONTSET
+/*
+ * We either draw with a fontset (when current_fontset != NULL) or with a
+ * normal font (current_fontset == NULL, use gui.text_gc and gui.back_gc).
+ */
+static XFontSet current_fontset = NULL;
+
+#define XDrawString(dpy, win, gc, x, y, str, n) \
+ do \
+ { \
+ if (current_fontset != NULL) \
+ XmbDrawString(dpy, win, current_fontset, gc, x, y, str, n); \
+ else \
+ XDrawString(dpy, win, gc, x, y, str, n); \
+ } while (0)
+
+#define XDrawString16(dpy, win, gc, x, y, str, n) \
+ do \
+ { \
+ if (current_fontset != NULL) \
+ XwcDrawString(dpy, win, current_fontset, gc, x, y, (wchar_t *)str, n); \
+ else \
+ XDrawString16(dpy, win, gc, x, y, (XChar2b *)str, n); \
+ } while (0)
+
+#define XDrawImageString16(dpy, win, gc, x, y, str, n) \
+ do \
+ { \
+ if (current_fontset != NULL) \
+ XwcDrawImageString(dpy, win, current_fontset, gc, x, y, (wchar_t *)str, n); \
+ else \
+ XDrawImageString16(dpy, win, gc, x, y, (XChar2b *)str, n); \
+ } while (0)
+
+static int check_fontset_sanity(XFontSet fs);
+static int fontset_width(XFontSet fs);
+static int fontset_ascent(XFontSet fs);
+#endif
+
+static guicolor_T prev_fg_color = INVALCOLOR;
+static guicolor_T prev_bg_color = INVALCOLOR;
+static guicolor_T prev_sp_color = INVALCOLOR;
+
+#if defined(FEAT_GUI_MOTIF) && defined(FEAT_MENU)
+static XButtonPressedEvent last_mouse_event;
+#endif
+
+static void gui_x11_check_copy_area(void);
+#ifdef FEAT_CLIENTSERVER
+static void gui_x11_send_event_handler(Widget, XtPointer, XEvent *, Boolean *);
+#endif
+static void gui_x11_wm_protocol_handler(Widget, XtPointer, XEvent *, Boolean *);
+static Cursor gui_x11_create_blank_mouse(void);
+
+
+/*
+ * Keycodes recognized by vim.
+ * NOTE: when changing this, the table in gui_gtk_x11.c probably needs the
+ * same change!
+ */
+static struct specialkey
+{
+ KeySym key_sym;
+ char_u vim_code0;
+ char_u vim_code1;
+} special_keys[] =
+{
+ {XK_Up, 'k', 'u'},
+ {XK_Down, 'k', 'd'},
+ {XK_Left, 'k', 'l'},
+ {XK_Right, 'k', 'r'},
+
+ {XK_F1, 'k', '1'},
+ {XK_F2, 'k', '2'},
+ {XK_F3, 'k', '3'},
+ {XK_F4, 'k', '4'},
+ {XK_F5, 'k', '5'},
+ {XK_F6, 'k', '6'},
+ {XK_F7, 'k', '7'},
+ {XK_F8, 'k', '8'},
+ {XK_F9, 'k', '9'},
+ {XK_F10, 'k', ';'},
+
+ {XK_F11, 'F', '1'},
+ {XK_F12, 'F', '2'},
+ {XK_F13, 'F', '3'},
+ {XK_F14, 'F', '4'},
+ {XK_F15, 'F', '5'},
+ {XK_F16, 'F', '6'},
+ {XK_F17, 'F', '7'},
+ {XK_F18, 'F', '8'},
+ {XK_F19, 'F', '9'},
+ {XK_F20, 'F', 'A'},
+
+ {XK_F21, 'F', 'B'},
+ {XK_F22, 'F', 'C'},
+ {XK_F23, 'F', 'D'},
+ {XK_F24, 'F', 'E'},
+ {XK_F25, 'F', 'F'},
+ {XK_F26, 'F', 'G'},
+ {XK_F27, 'F', 'H'},
+ {XK_F28, 'F', 'I'},
+ {XK_F29, 'F', 'J'},
+ {XK_F30, 'F', 'K'},
+
+ {XK_F31, 'F', 'L'},
+ {XK_F32, 'F', 'M'},
+ {XK_F33, 'F', 'N'},
+ {XK_F34, 'F', 'O'},
+ {XK_F35, 'F', 'P'}, /* keysymdef.h defines up to F35 */
+#ifdef SunXK_F36
+ {SunXK_F36, 'F', 'Q'},
+ {SunXK_F37, 'F', 'R'},
+#endif
+
+ {XK_Help, '%', '1'},
+ {XK_Undo, '&', '8'},
+ {XK_BackSpace, 'k', 'b'},
+ {XK_Insert, 'k', 'I'},
+ {XK_Delete, 'k', 'D'},
+ {XK_Home, 'k', 'h'},
+ {XK_End, '@', '7'},
+ {XK_Prior, 'k', 'P'},
+ {XK_Next, 'k', 'N'},
+ {XK_Print, '%', '9'},
+
+ /* Keypad keys: */
+#ifdef XK_KP_Left
+ {XK_KP_Left, 'k', 'l'},
+ {XK_KP_Right, 'k', 'r'},
+ {XK_KP_Up, 'k', 'u'},
+ {XK_KP_Down, 'k', 'd'},
+ {XK_KP_Insert, KS_EXTRA, (char_u)KE_KINS},
+ {XK_KP_Delete, KS_EXTRA, (char_u)KE_KDEL},
+ {XK_KP_Home, 'K', '1'},
+ {XK_KP_End, 'K', '4'},
+ {XK_KP_Prior, 'K', '3'},
+ {XK_KP_Next, 'K', '5'},
+
+ {XK_KP_Add, 'K', '6'},
+ {XK_KP_Subtract, 'K', '7'},
+ {XK_KP_Divide, 'K', '8'},
+ {XK_KP_Multiply, 'K', '9'},
+ {XK_KP_Enter, 'K', 'A'},
+ {XK_KP_Decimal, 'K', 'B'},
+
+ {XK_KP_0, 'K', 'C'},
+ {XK_KP_1, 'K', 'D'},
+ {XK_KP_2, 'K', 'E'},
+ {XK_KP_3, 'K', 'F'},
+ {XK_KP_4, 'K', 'G'},
+ {XK_KP_5, 'K', 'H'},
+ {XK_KP_6, 'K', 'I'},
+ {XK_KP_7, 'K', 'J'},
+ {XK_KP_8, 'K', 'K'},
+ {XK_KP_9, 'K', 'L'},
+#endif
+
+ /* End of list marker: */
+ {(KeySym)0, 0, 0}
+};
+
+#define XtNboldFont "boldFont"
+#define XtCBoldFont "BoldFont"
+#define XtNitalicFont "italicFont"
+#define XtCItalicFont "ItalicFont"
+#define XtNboldItalicFont "boldItalicFont"
+#define XtCBoldItalicFont "BoldItalicFont"
+#define XtNscrollbarWidth "scrollbarWidth"
+#define XtCScrollbarWidth "ScrollbarWidth"
+#define XtNmenuHeight "menuHeight"
+#define XtCMenuHeight "MenuHeight"
+#define XtNmenuFont "menuFont"
+#define XtCMenuFont "MenuFont"
+#define XtNmenuFontSet "menuFontSet"
+#define XtCMenuFontSet "MenuFontSet"
+
+
+/* Resources for setting the foreground and background colors of menus */
+#define XtNmenuBackground "menuBackground"
+#define XtCMenuBackground "MenuBackground"
+#define XtNmenuForeground "menuForeground"
+#define XtCMenuForeground "MenuForeground"
+
+/* Resources for setting the foreground and background colors of scrollbars */
+#define XtNscrollBackground "scrollBackground"
+#define XtCScrollBackground "ScrollBackground"
+#define XtNscrollForeground "scrollForeground"
+#define XtCScrollForeground "ScrollForeground"
+
+/* Resources for setting the foreground and background colors of tooltip */
+#define XtNtooltipBackground "tooltipBackground"
+#define XtCTooltipBackground "TooltipBackground"
+#define XtNtooltipForeground "tooltipForeground"
+#define XtCTooltipForeground "TooltipForeground"
+#define XtNtooltipFont "tooltipFont"
+#define XtCTooltipFont "TooltipFont"
+
+/*
+ * X Resources:
+ */
+static XtResource vim_resources[] =
+{
+ {
+ XtNforeground,
+ XtCForeground,
+ XtRPixel,
+ sizeof(Pixel),
+ XtOffsetOf(gui_T, def_norm_pixel),
+ XtRString,
+ XtDefaultForeground
+ },
+ {
+ XtNbackground,
+ XtCBackground,
+ XtRPixel,
+ sizeof(Pixel),
+ XtOffsetOf(gui_T, def_back_pixel),
+ XtRString,
+ XtDefaultBackground
+ },
+ {
+ XtNfont,
+ XtCFont,
+ XtRString,
+ sizeof(String *),
+ XtOffsetOf(gui_T, rsrc_font_name),
+ XtRImmediate,
+ XtDefaultFont
+ },
+ {
+ XtNboldFont,
+ XtCBoldFont,
+ XtRString,
+ sizeof(String *),
+ XtOffsetOf(gui_T, rsrc_bold_font_name),
+ XtRImmediate,
+ ""
+ },
+ {
+ XtNitalicFont,
+ XtCItalicFont,
+ XtRString,
+ sizeof(String *),
+ XtOffsetOf(gui_T, rsrc_ital_font_name),
+ XtRImmediate,
+ ""
+ },
+ {
+ XtNboldItalicFont,
+ XtCBoldItalicFont,
+ XtRString,
+ sizeof(String *),
+ XtOffsetOf(gui_T, rsrc_boldital_font_name),
+ XtRImmediate,
+ ""
+ },
+ {
+ XtNgeometry,
+ XtCGeometry,
+ XtRString,
+ sizeof(String *),
+ XtOffsetOf(gui_T, geom),
+ XtRImmediate,
+ ""
+ },
+ {
+ XtNreverseVideo,
+ XtCReverseVideo,
+ XtRBool,
+ sizeof(Bool),
+ XtOffsetOf(gui_T, rsrc_rev_video),
+ XtRImmediate,
+ (XtPointer)False
+ },
+ {
+ XtNborderWidth,
+ XtCBorderWidth,
+ XtRInt,
+ sizeof(int),
+ XtOffsetOf(gui_T, border_width),
+ XtRImmediate,
+ (XtPointer)2
+ },
+ {
+ XtNscrollbarWidth,
+ XtCScrollbarWidth,
+ XtRInt,
+ sizeof(int),
+ XtOffsetOf(gui_T, scrollbar_width),
+ XtRImmediate,
+ (XtPointer)SB_DEFAULT_WIDTH
+ },
+#ifdef FEAT_MENU
+# ifdef FEAT_GUI_ATHENA /* with Motif the height is always computed */
+ {
+ XtNmenuHeight,
+ XtCMenuHeight,
+ XtRInt,
+ sizeof(int),
+ XtOffsetOf(gui_T, menu_height),
+ XtRImmediate,
+ (XtPointer)MENU_DEFAULT_HEIGHT /* Should figure out at run time */
+ },
+# endif
+ {
+# ifdef FONTSET_ALWAYS
+ XtNmenuFontSet,
+ XtCMenuFontSet,
+#else
+ XtNmenuFont,
+ XtCMenuFont,
+#endif
+ XtRString,
+ sizeof(char *),
+ XtOffsetOf(gui_T, rsrc_menu_font_name),
+ XtRString,
+ DFLT_MENU_FONT
+ },
+#endif
+ {
+ XtNmenuForeground,
+ XtCMenuForeground,
+ XtRString,
+ sizeof(char *),
+ XtOffsetOf(gui_T, rsrc_menu_fg_name),
+ XtRString,
+ DFLT_MENU_FG_COLOR
+ },
+ {
+ XtNmenuBackground,
+ XtCMenuBackground,
+ XtRString,
+ sizeof(char *),
+ XtOffsetOf(gui_T, rsrc_menu_bg_name),
+ XtRString,
+ DFLT_MENU_BG_COLOR
+ },
+ {
+ XtNscrollForeground,
+ XtCScrollForeground,
+ XtRString,
+ sizeof(char *),
+ XtOffsetOf(gui_T, rsrc_scroll_fg_name),
+ XtRString,
+ DFLT_SCROLL_FG_COLOR
+ },
+ {
+ XtNscrollBackground,
+ XtCScrollBackground,
+ XtRString,
+ sizeof(char *),
+ XtOffsetOf(gui_T, rsrc_scroll_bg_name),
+ XtRString,
+ DFLT_SCROLL_BG_COLOR
+ },
+#ifdef FEAT_BEVAL_GUI
+ {
+ XtNtooltipForeground,
+ XtCTooltipForeground,
+ XtRString,
+ sizeof(char *),
+ XtOffsetOf(gui_T, rsrc_tooltip_fg_name),
+ XtRString,
+ DFLT_TOOLTIP_FG_COLOR
+ },
+ {
+ XtNtooltipBackground,
+ XtCTooltipBackground,
+ XtRString,
+ sizeof(char *),
+ XtOffsetOf(gui_T, rsrc_tooltip_bg_name),
+ XtRString,
+ DFLT_TOOLTIP_BG_COLOR
+ },
+ {
+ XtNtooltipFont,
+ XtCTooltipFont,
+ XtRString,
+ sizeof(char *),
+ XtOffsetOf(gui_T, rsrc_tooltip_font_name),
+ XtRString,
+ DFLT_TOOLTIP_FONT
+ },
+ /* This one may not be really needed? */
+ {
+ "balloonEvalFontSet",
+ XtCFontSet,
+ XtRFontSet,
+ sizeof(XFontSet),
+ XtOffsetOf(gui_T, tooltip_fontset),
+ XtRImmediate,
+ (XtPointer)NOFONTSET
+ },
+#endif /* FEAT_BEVAL_GUI */
+#ifdef FEAT_XIM
+ {
+ "preeditType",
+ "PreeditType",
+ XtRString,
+ sizeof(char*),
+ XtOffsetOf(gui_T, rsrc_preedit_type_name),
+ XtRString,
+ (XtPointer)"OverTheSpot,OffTheSpot,Root"
+ },
+ {
+ "inputMethod",
+ "InputMethod",
+ XtRString,
+ sizeof(char*),
+ XtOffsetOf(gui_T, rsrc_input_method),
+ XtRString,
+ NULL
+ },
+#endif /* FEAT_XIM */
+};
+
+/*
+ * This table holds all the X GUI command line options allowed. This includes
+ * the standard ones so that we can skip them when vim is started without the
+ * GUI (but the GUI might start up later).
+ * When changing this, also update doc/vim_gui.txt and the usage message!!!
+ */
+static XrmOptionDescRec cmdline_options[] =
+{
+ /* We handle these options ourselves */
+ {"-bg", ".background", XrmoptionSepArg, NULL},
+ {"-background", ".background", XrmoptionSepArg, NULL},
+ {"-fg", ".foreground", XrmoptionSepArg, NULL},
+ {"-foreground", ".foreground", XrmoptionSepArg, NULL},
+ {"-fn", ".font", XrmoptionSepArg, NULL},
+ {"-font", ".font", XrmoptionSepArg, NULL},
+ {"-boldfont", ".boldFont", XrmoptionSepArg, NULL},
+ {"-italicfont", ".italicFont", XrmoptionSepArg, NULL},
+ {"-geom", ".geometry", XrmoptionSepArg, NULL},
+ {"-geometry", ".geometry", XrmoptionSepArg, NULL},
+ {"-reverse", "*reverseVideo", XrmoptionNoArg, "True"},
+ {"-rv", "*reverseVideo", XrmoptionNoArg, "True"},
+ {"+reverse", "*reverseVideo", XrmoptionNoArg, "False"},
+ {"+rv", "*reverseVideo", XrmoptionNoArg, "False"},
+ {"-display", ".display", XrmoptionSepArg, NULL},
+ {"-iconic", ".iconic", XrmoptionNoArg, "True"},
+ {"-name", ".name", XrmoptionSepArg, NULL},
+ {"-bw", ".borderWidth", XrmoptionSepArg, NULL},
+ {"-borderwidth", ".borderWidth", XrmoptionSepArg, NULL},
+ {"-sw", ".scrollbarWidth", XrmoptionSepArg, NULL},
+ {"-scrollbarwidth", ".scrollbarWidth", XrmoptionSepArg, NULL},
+ {"-mh", ".menuHeight", XrmoptionSepArg, NULL},
+ {"-menuheight", ".menuHeight", XrmoptionSepArg, NULL},
+#ifdef FONTSET_ALWAYS
+ {"-mf", ".menuFontSet", XrmoptionSepArg, NULL},
+ {"-menufont", ".menuFontSet", XrmoptionSepArg, NULL},
+ {"-menufontset", ".menuFontSet", XrmoptionSepArg, NULL},
+#else
+ {"-mf", ".menuFont", XrmoptionSepArg, NULL},
+ {"-menufont", ".menuFont", XrmoptionSepArg, NULL},
+#endif
+ {"-xrm", NULL, XrmoptionResArg, NULL}
+};
+
+static int gui_argc = 0;
+static char **gui_argv = NULL;
+
+/*
+ * Call-back routines.
+ */
+
+ static void
+gui_x11_timer_cb(
+ XtPointer timed_out,
+ XtIntervalId *interval_id UNUSED)
+{
+ *((int *)timed_out) = TRUE;
+}
+
+#ifdef FEAT_JOB_CHANNEL
+ static void
+channel_poll_cb(
+ XtPointer client_data,
+ XtIntervalId *interval_id UNUSED)
+{
+ XtIntervalId *channel_timer = (XtIntervalId *)client_data;
+
+ /* Using an event handler for a channel that may be disconnected does
+ * not work, it hangs. Instead poll for messages. */
+ channel_handle_events(TRUE);
+ parse_queued_messages();
+
+ /* repeat */
+ *channel_timer = XtAppAddTimeOut(app_context, (long_u)20,
+ channel_poll_cb, client_data);
+}
+#endif
+
+ static void
+gui_x11_visibility_cb(
+ Widget w UNUSED,
+ XtPointer dud UNUSED,
+ XEvent *event,
+ Boolean *dum UNUSED)
+{
+ if (event->type != VisibilityNotify)
+ return;
+
+ gui.visibility = event->xvisibility.state;
+
+ /*
+ * When we do an XCopyArea(), and the window is partially obscured, we want
+ * to receive an event to tell us whether it worked or not.
+ */
+ XSetGraphicsExposures(gui.dpy, gui.text_gc,
+ gui.visibility != VisibilityUnobscured);
+
+ /* This is needed for when redrawing is slow. */
+ gui_mch_update();
+}
+
+ static void
+gui_x11_expose_cb(
+ Widget w UNUSED,
+ XtPointer dud UNUSED,
+ XEvent *event,
+ Boolean *dum UNUSED)
+{
+ XExposeEvent *gevent;
+ int new_x;
+
+ if (event->type != Expose)
+ return;
+
+ out_flush(); /* make sure all output has been processed */
+
+ gevent = (XExposeEvent *)event;
+ gui_redraw(gevent->x, gevent->y, gevent->width, gevent->height);
+
+ new_x = FILL_X(0);
+
+ /* Clear the border areas if needed */
+ if (gevent->x < new_x)
+ XClearArea(gui.dpy, gui.wid, 0, 0, new_x, 0, False);
+ if (gevent->y < FILL_Y(0))
+ XClearArea(gui.dpy, gui.wid, 0, 0, 0, FILL_Y(0), False);
+ if (gevent->x > FILL_X(Columns))
+ XClearArea(gui.dpy, gui.wid, FILL_X((int)Columns), 0, 0, 0, False);
+ if (gevent->y > FILL_Y(Rows))
+ XClearArea(gui.dpy, gui.wid, 0, FILL_Y((int)Rows), 0, 0, False);
+
+ /* This is needed for when redrawing is slow. */
+ gui_mch_update();
+}
+
+#if (defined(FEAT_NETBEANS_INTG) && defined(FEAT_GUI_MOTIF)) || defined(PROTO)
+/*
+ * This function fills in the XRectangle object with the current x,y
+ * coordinates and height, width so that an XtVaSetValues to the same shell of
+ * those resources will restore the window to its former position and
+ * dimensions.
+ *
+ * Note: This function may fail, in which case the XRectangle will be
+ * unchanged. Be sure to have the XRectangle set with the proper values for a
+ * failed condition prior to calling this function.
+ */
+ static void
+shellRectangle(Widget shell, XRectangle *r)
+{
+ Window rootw, shellw, child, parentw;
+ int absx, absy;
+ XWindowAttributes a;
+ Window *children;
+ unsigned int childrenCount;
+
+ shellw = XtWindow(shell);
+ if (shellw == 0)
+ return;
+ for (;;)
+ {
+ XQueryTree(XtDisplay(shell), shellw, &rootw, &parentw,
+ &children, &childrenCount);
+ XFree(children);
+ if (parentw == rootw)
+ break;
+ shellw = parentw;
+ }
+ XGetWindowAttributes(XtDisplay(shell), shellw, &a);
+ XTranslateCoordinates(XtDisplay(shell), shellw, a.root, 0, 0,
+ &absx, &absy, &child);
+ r->x = absx;
+ r->y = absy;
+ XtVaGetValues(shell, XmNheight, &r->height, XmNwidth, &r->width, NULL);
+}
+#endif
+
+ static void
+gui_x11_resize_window_cb(
+ Widget w UNUSED,
+ XtPointer dud UNUSED,
+ XEvent *event,
+ Boolean *dum UNUSED)
+{
+ static int lastWidth, lastHeight;
+
+ if (event->type != ConfigureNotify)
+ return;
+
+ if (event->xconfigure.width != lastWidth
+ || event->xconfigure.height != lastHeight)
+ {
+ lastWidth = event->xconfigure.width;
+ lastHeight = event->xconfigure.height;
+ gui_resize_shell(event->xconfigure.width, event->xconfigure.height
+#ifdef FEAT_XIM
+ - xim_get_status_area_height()
+#endif
+ );
+ }
+#if defined(FEAT_NETBEANS_INTG) && defined(FEAT_GUI_MOTIF)
+ if (netbeans_active())
+ {
+ XRectangle rec;
+
+ shellRectangle(w, &rec);
+ netbeans_frame_moved(rec.x, rec.y);
+ }
+#endif
+#ifdef FEAT_XIM
+ xim_set_preedit();
+#endif
+}
+
+ static void
+gui_x11_focus_change_cb(
+ Widget w UNUSED,
+ XtPointer data UNUSED,
+ XEvent *event,
+ Boolean *dum UNUSED)
+{
+ gui_focus_change(event->type == FocusIn);
+}
+
+ static void
+gui_x11_enter_cb(
+ Widget w UNUSED,
+ XtPointer data UNUSED,
+ XEvent *event UNUSED,
+ Boolean *dum UNUSED)
+{
+ gui_focus_change(TRUE);
+}
+
+ static void
+gui_x11_leave_cb(
+ Widget w UNUSED,
+ XtPointer data UNUSED,
+ XEvent *event UNUSED,
+ Boolean *dum UNUSED)
+{
+ gui_focus_change(FALSE);
+}
+
+#if defined(X_HAVE_UTF8_STRING)
+# if X_HAVE_UTF8_STRING
+# define USE_UTF8LOOKUP
+# endif
+#endif
+
+ void
+gui_x11_key_hit_cb(
+ Widget w UNUSED,
+ XtPointer dud UNUSED,
+ XEvent *event,
+ Boolean *dum UNUSED)
+{
+ XKeyPressedEvent *ev_press;
+#ifdef FEAT_XIM
+ char_u string2[256];
+ char_u string_shortbuf[256];
+ char_u *string = string_shortbuf;
+ Boolean string_alloced = False;
+ Status status;
+#else
+ char_u string[4], string2[3];
+#endif
+ KeySym key_sym, key_sym2;
+ int len, len2;
+ int i;
+ int modifiers;
+ int key;
+
+ ev_press = (XKeyPressedEvent *)event;
+
+#ifdef FEAT_XIM
+ if (xic)
+ {
+# ifdef USE_UTF8LOOKUP
+ /* XFree86 4.0.2 or newer: Be able to get UTF-8 characters even when
+ * the locale isn't utf-8. */
+ if (enc_utf8)
+ len = Xutf8LookupString(xic, ev_press, (char *)string,
+ sizeof(string_shortbuf), &key_sym, &status);
+ else
+# endif
+ len = XmbLookupString(xic, ev_press, (char *)string,
+ sizeof(string_shortbuf), &key_sym, &status);
+ if (status == XBufferOverflow)
+ {
+ string = (char_u *)XtMalloc(len + 1);
+ string_alloced = True;
+# ifdef USE_UTF8LOOKUP
+ /* XFree86 4.0.2 or newer: Be able to get UTF-8 characters even
+ * when the locale isn't utf-8. */
+ if (enc_utf8)
+ len = Xutf8LookupString(xic, ev_press, (char *)string,
+ len, &key_sym, &status);
+ else
+# endif
+ len = XmbLookupString(xic, ev_press, (char *)string,
+ len, &key_sym, &status);
+ }
+ if (status == XLookupNone || status == XLookupChars)
+ key_sym = XK_VoidSymbol;
+
+ /* Do conversion from 'termencoding' to 'encoding'. When using
+ * Xutf8LookupString() it has already been done. */
+ if (len > 0 && input_conv.vc_type != CONV_NONE
+# ifdef USE_UTF8LOOKUP
+ && !enc_utf8
+# endif
+ )
+ {
+ int maxlen = len * 4 + 40; /* guessed */
+ char_u *p = (char_u *)XtMalloc(maxlen);
+
+ mch_memmove(p, string, len);
+ if (string_alloced)
+ XtFree((char *)string);
+ string = p;
+ string_alloced = True;
+ len = convert_input(p, len, maxlen);
+ }
+
+ /* Translate CSI to K_CSI, otherwise it could be recognized as the
+ * start of a special key. */
+ for (i = 0; i < len; ++i)
+ if (string[i] == CSI)
+ {
+ char_u *p = (char_u *)XtMalloc(len + 3);
+
+ mch_memmove(p, string, i + 1);
+ p[i + 1] = KS_EXTRA;
+ p[i + 2] = (int)KE_CSI;
+ mch_memmove(p + i + 3, string + i + 1, len - i);
+ if (string_alloced)
+ XtFree((char *)string);
+ string = p;
+ string_alloced = True;
+ i += 2;
+ len += 2;
+ }
+ }
+ else
+#endif
+ len = XLookupString(ev_press, (char *)string, sizeof(string),
+ &key_sym, NULL);
+
+#ifdef SunXK_F36
+ /*
+ * These keys have bogus lookup strings, and trapping them here is
+ * easier than trying to XRebindKeysym() on them with every possible
+ * combination of modifiers.
+ */
+ if (key_sym == SunXK_F36 || key_sym == SunXK_F37)
+ len = 0;
+#endif
+
+#ifdef FEAT_HANGULIN
+ if ((key_sym == XK_space) && (ev_press->state & ShiftMask))
+ {
+ hangul_input_state_toggle();
+ goto theend;
+ }
+#endif
+
+ if (key_sym == XK_space)
+ string[0] = ' '; /* Otherwise Ctrl-Space doesn't work */
+
+ /*
+ * Only on some machines ^_ requires Ctrl+Shift+minus. For consistency,
+ * allow just Ctrl+minus too.
+ */
+ if (key_sym == XK_minus && (ev_press->state & ControlMask))
+ string[0] = Ctrl__;
+
+#ifdef XK_ISO_Left_Tab
+ /* why do we get XK_ISO_Left_Tab instead of XK_Tab for shift-tab? */
+ if (key_sym == XK_ISO_Left_Tab)
+ {
+ key_sym = XK_Tab;
+ string[0] = TAB;
+ len = 1;
+ }
+#endif
+
+ /* Check for Alt/Meta key (Mod1Mask), but not for a BS, DEL or character
+ * that already has the 8th bit set. And not when using a double-byte
+ * encoding, setting the 8th bit may make it the lead byte of a
+ * double-byte character. */
+ if (len == 1
+ && (ev_press->state & Mod1Mask)
+ && !(key_sym == XK_BackSpace || key_sym == XK_Delete)
+ && (string[0] & 0x80) == 0
+ && !enc_dbcs)
+ {
+#if defined(FEAT_MENU) && defined(FEAT_GUI_MOTIF)
+ /* Ignore ALT keys when they are used for the menu only */
+ if (gui.menu_is_active
+ && (p_wak[0] == 'y'
+ || (p_wak[0] == 'm' && gui_is_menu_shortcut(string[0]))))
+ goto theend;
+#endif
+ /*
+ * Before we set the 8th bit, check to make sure the user doesn't
+ * already have a mapping defined for this sequence. We determine this
+ * by checking to see if the input would be the same without the
+ * Alt/Meta key.
+ * Don't do this for <S-M-Tab>, that should become K_S_TAB with ALT.
+ */
+ ev_press->state &= ~Mod1Mask;
+ len2 = XLookupString(ev_press, (char *)string2, sizeof(string2),
+ &key_sym2, NULL);
+ if (key_sym2 == XK_space)
+ string2[0] = ' '; /* Otherwise Meta-Ctrl-Space doesn't work */
+ if ( len2 == 1
+ && string[0] == string2[0]
+ && !(key_sym == XK_Tab && (ev_press->state & ShiftMask)))
+ {
+ string[0] |= 0x80;
+ if (enc_utf8) /* convert to utf-8 */
+ {
+ string[1] = string[0] & 0xbf;
+ string[0] = ((unsigned)string[0] >> 6) + 0xc0;
+ if (string[1] == CSI)
+ {
+ string[2] = KS_EXTRA;
+ string[3] = (int)KE_CSI;
+ len = 4;
+ }
+ else
+ len = 2;
+ }
+ }
+ else
+ ev_press->state |= Mod1Mask;
+ }
+
+ if (len == 1 && string[0] == CSI)
+ {
+ string[1] = KS_EXTRA;
+ string[2] = (int)KE_CSI;
+ len = -3;
+ }
+
+ /* Check for special keys. Also do this when len == 1 (key has an ASCII
+ * value) to detect backspace, delete and keypad keys. */
+ if (len == 0 || len == 1)
+ {
+ for (i = 0; special_keys[i].key_sym != (KeySym)0; i++)
+ {
+ if (special_keys[i].key_sym == key_sym)
+ {
+ string[0] = CSI;
+ string[1] = special_keys[i].vim_code0;
+ string[2] = special_keys[i].vim_code1;
+ len = -3;
+ break;
+ }
+ }
+ }
+
+ /* Unrecognised key is ignored. */
+ if (len == 0)
+ goto theend;
+
+ /* Special keys (and a few others) may have modifiers. Also when using a
+ * double-byte encoding (can't set the 8th bit). */
+ if (len == -3 || key_sym == XK_space || key_sym == XK_Tab
+ || key_sym == XK_Return || key_sym == XK_Linefeed
+ || key_sym == XK_Escape
+ || (enc_dbcs && len == 1 && (ev_press->state & Mod1Mask)))
+ {
+ modifiers = 0;
+ if (ev_press->state & ShiftMask)
+ modifiers |= MOD_MASK_SHIFT;
+ if (ev_press->state & ControlMask)
+ modifiers |= MOD_MASK_CTRL;
+ if (ev_press->state & Mod1Mask)
+ modifiers |= MOD_MASK_ALT;
+ if (ev_press->state & Mod4Mask)
+ modifiers |= MOD_MASK_META;
+
+ /*
+ * For some keys a shift modifier is translated into another key
+ * code.
+ */
+ if (len == -3)
+ key = TO_SPECIAL(string[1], string[2]);
+ else
+ key = string[0];
+ key = simplify_key(key, &modifiers);
+ if (key == CSI)
+ key = K_CSI;
+ if (IS_SPECIAL(key))
+ {
+ string[0] = CSI;
+ string[1] = K_SECOND(key);
+ string[2] = K_THIRD(key);
+ len = 3;
+ }
+ else
+ {
+ string[0] = key;
+ len = 1;
+ }
+
+ if (modifiers != 0)
+ {
+ string2[0] = CSI;
+ string2[1] = KS_MODIFIER;
+ string2[2] = modifiers;
+ add_to_input_buf(string2, 3);
+ }
+ }
+
+ if (len == 1 && ((string[0] == Ctrl_C && ctrl_c_interrupts)
+#ifdef UNIX
+ || (intr_char != 0 && string[0] == intr_char)
+#endif
+ ))
+ {
+ trash_input_buf();
+ got_int = TRUE;
+ }
+
+ add_to_input_buf(string, len);
+
+ /*
+ * blank out the pointer if necessary
+ */
+ if (p_mh)
+ gui_mch_mousehide(TRUE);
+
+#if defined(FEAT_BEVAL_TIP)
+ {
+ BalloonEval *be;
+
+ if ((be = gui_mch_currently_showing_beval()) != NULL)
+ gui_mch_unpost_balloon(be);
+ }
+#endif
+theend:
+ {} /* some compilers need a statement here */
+#ifdef FEAT_XIM
+ if (string_alloced)
+ XtFree((char *)string);
+#endif
+}
+
+ static void
+gui_x11_mouse_cb(
+ Widget w UNUSED,
+ XtPointer dud UNUSED,
+ XEvent *event,
+ Boolean *dum UNUSED)
+{
+ static XtIntervalId timer = (XtIntervalId)0;
+ static int timed_out = TRUE;
+
+ int button;
+ int repeated_click = FALSE;
+ int x, y;
+ int_u x_modifiers;
+ int_u vim_modifiers;
+
+ if (event->type == MotionNotify)
+ {
+ /* Get the latest position, avoids lagging behind on a drag. */
+ x = event->xmotion.x;
+ y = event->xmotion.y;
+ x_modifiers = event->xmotion.state;
+ button = (x_modifiers & (Button1Mask | Button2Mask | Button3Mask))
+ ? MOUSE_DRAG : ' ';
+
+ /*
+ * if our pointer is currently hidden, then we should show it.
+ */
+ gui_mch_mousehide(FALSE);
+
+ if (button != MOUSE_DRAG) /* just moving the rodent */
+ {
+#ifdef FEAT_MENU
+ if (dud) /* moved in vimForm */
+ y -= gui.menu_height;
+#endif
+ gui_mouse_moved(x, y);
+ return;
+ }
+ }
+ else
+ {
+ x = event->xbutton.x;
+ y = event->xbutton.y;
+ if (event->type == ButtonPress)
+ {
+ /* Handle multiple clicks */
+ if (!timed_out)
+ {
+ XtRemoveTimeOut(timer);
+ repeated_click = TRUE;
+ }
+ timed_out = FALSE;
+ timer = XtAppAddTimeOut(app_context, (long_u)p_mouset,
+ gui_x11_timer_cb, &timed_out);
+ switch (event->xbutton.button)
+ {
+ /* keep in sync with gui_gtk_x11.c */
+ case Button1: button = MOUSE_LEFT; break;
+ case Button2: button = MOUSE_MIDDLE; break;
+ case Button3: button = MOUSE_RIGHT; break;
+ case Button4: button = MOUSE_4; break;
+ case Button5: button = MOUSE_5; break;
+ case 6: button = MOUSE_7; break;
+ case 7: button = MOUSE_6; break;
+ case 8: button = MOUSE_X1; break;
+ case 9: button = MOUSE_X2; break;
+ default:
+ return; /* Unknown button */
+ }
+ }
+ else if (event->type == ButtonRelease)
+ button = MOUSE_RELEASE;
+ else
+ return; /* Unknown mouse event type */
+
+ x_modifiers = event->xbutton.state;
+#if defined(FEAT_GUI_MOTIF) && defined(FEAT_MENU)
+ last_mouse_event = event->xbutton;
+#endif
+ }
+
+ vim_modifiers = 0x0;
+ if (x_modifiers & ShiftMask)
+ vim_modifiers |= MOUSE_SHIFT;
+ if (x_modifiers & ControlMask)
+ vim_modifiers |= MOUSE_CTRL;
+ if (x_modifiers & Mod1Mask) /* Alt or Meta key */
+ vim_modifiers |= MOUSE_ALT;
+
+ gui_send_mouse_event(button, x, y, repeated_click, vim_modifiers);
+}
+
+/*
+ * End of call-back routines
+ */
+
+/*
+ * 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)
+{
+ int arg;
+ int i;
+
+ /*
+ * Move all the entries in argv which are relevant to X into gui_argv.
+ */
+ gui_argc = 0;
+ gui_argv = (char **)lalloc((long_u)(*argc * sizeof(char *)), FALSE);
+ if (gui_argv == NULL)
+ return;
+ gui_argv[gui_argc++] = argv[0];
+ arg = 1;
+ while (arg < *argc)
+ {
+ /* Look for argv[arg] in cmdline_options[] table */
+ for (i = 0; i < (int)XtNumber(cmdline_options); i++)
+ if (strcmp(argv[arg], cmdline_options[i].option) == 0)
+ break;
+
+ if (i < (int)XtNumber(cmdline_options))
+ {
+ /* Remember finding "-rv" or "-reverse" */
+ if (strcmp("-rv", argv[arg]) == 0
+ || strcmp("-reverse", argv[arg]) == 0)
+ found_reverse_arg = TRUE;
+ else if ((strcmp("-fn", argv[arg]) == 0
+ || strcmp("-font", argv[arg]) == 0)
+ && arg + 1 < *argc)
+ font_argument = argv[arg + 1];
+
+ /* Found match in table, so move it into gui_argv */
+ gui_argv[gui_argc++] = argv[arg];
+ if (--*argc > arg)
+ {
+ mch_memmove(&argv[arg], &argv[arg + 1], (*argc - arg)
+ * sizeof(char *));
+ if (cmdline_options[i].argKind != XrmoptionNoArg)
+ {
+ /* Move the options argument as well */
+ gui_argv[gui_argc++] = argv[arg];
+ if (--*argc > arg)
+ mch_memmove(&argv[arg], &argv[arg + 1], (*argc - arg)
+ * sizeof(char *));
+ }
+ }
+ argv[*argc] = NULL;
+ }
+ else
+#ifdef FEAT_NETBEANS_INTG
+ if (strncmp("-nb", argv[arg], 3) == 0)
+ {
+ gui.dofork = FALSE; /* don't fork() when starting GUI */
+ netbeansArg = argv[arg];
+ mch_memmove(&argv[arg], &argv[arg + 1],
+ (--*argc - arg) * sizeof(char *));
+ argv[*argc] = NULL;
+ }
+ else
+#endif
+ arg++;
+ }
+}
+
+#ifndef XtSpecificationRelease
+# define CARDINAL (Cardinal *)
+#else
+# if XtSpecificationRelease == 4
+# define CARDINAL (Cardinal *)
+# else
+# define CARDINAL (int *)
+# endif
+#endif
+
+/*
+ * Check if the GUI can be started. Called before gvimrc is sourced.
+ * Return OK or FAIL.
+ */
+ int
+gui_mch_init_check(void)
+{
+#ifdef FEAT_XIM
+ XtSetLanguageProc(NULL, NULL, NULL);
+#endif
+ open_app_context();
+ if (app_context != NULL)
+ gui.dpy = XtOpenDisplay(app_context, 0, VIM_NAME, VIM_CLASS,
+ cmdline_options, XtNumber(cmdline_options),
+ CARDINAL &gui_argc, gui_argv);
+
+# if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
+ {
+ /* The call to XtOpenDisplay() may have set the locale from the
+ * environment. Set LC_NUMERIC to "C" to make sure that strtod() uses a
+ * decimal point, not a comma. */
+ char *p = setlocale(LC_NUMERIC, NULL);
+
+ if (p == NULL || strcmp(p, "C") != 0)
+ setlocale(LC_NUMERIC, "C");
+ }
+# endif
+ if (app_context == NULL || gui.dpy == NULL)
+ {
+ gui.dying = TRUE;
+ emsg(_(e_opendisp));
+ return FAIL;
+ }
+ return OK;
+}
+
+
+#ifdef USE_XSMP
+/*
+ * Handle XSMP processing, de-registering the attachment upon error
+ */
+static XtInputId _xsmp_xtinputid;
+
+ static void
+local_xsmp_handle_requests(
+ XtPointer c UNUSED,
+ int *s UNUSED,
+ XtInputId *i UNUSED)
+{
+ if (xsmp_handle_requests() == FAIL)
+ XtRemoveInput(_xsmp_xtinputid);
+}
+#endif
+
+
+/*
+ * Initialise the X GUI. Create all the windows, set up all the call-backs etc.
+ * Returns OK for success, FAIL when the GUI can't be started.
+ */
+ int
+gui_mch_init(void)
+{
+ XtGCMask gc_mask;
+ XGCValues gc_vals;
+ int x, y, mask;
+ unsigned w, h;
+
+#if 0
+ /* Uncomment this to enable synchronous mode for debugging */
+ XSynchronize(gui.dpy, True);
+#endif
+
+ vimShell = XtVaAppCreateShell(VIM_NAME, VIM_CLASS,
+ applicationShellWidgetClass, gui.dpy, NULL);
+
+ /*
+ * Get the application resources
+ */
+ XtVaGetApplicationResources(vimShell, (XtPointer)&gui,
+ vim_resources, XtNumber(vim_resources), NULL);
+
+ gui.scrollbar_height = gui.scrollbar_width;
+
+ /*
+ * Get the colors ourselves. Using the automatic conversion doesn't
+ * handle looking for approximate colors.
+ */
+ /* NOTE: These next few lines are an exact duplicate of gui_athena.c's
+ * gui_mch_def_colors(). Why?
+ */
+ gui.menu_fg_pixel = gui_get_color((char_u *)gui.rsrc_menu_fg_name);
+ gui.menu_bg_pixel = gui_get_color((char_u *)gui.rsrc_menu_bg_name);
+ gui.scroll_fg_pixel = gui_get_color((char_u *)gui.rsrc_scroll_fg_name);
+ gui.scroll_bg_pixel = gui_get_color((char_u *)gui.rsrc_scroll_bg_name);
+#ifdef FEAT_BEVAL_GUI
+ gui.tooltip_fg_pixel = gui_get_color((char_u *)gui.rsrc_tooltip_fg_name);
+ gui.tooltip_bg_pixel = gui_get_color((char_u *)gui.rsrc_tooltip_bg_name);
+#endif
+
+#if defined(FEAT_MENU) && defined(FEAT_GUI_ATHENA)
+ /* If the menu height was set, don't change it at runtime */
+ if (gui.menu_height != MENU_DEFAULT_HEIGHT)
+ gui.menu_height_fixed = TRUE;
+#endif
+
+ /* Set default foreground and background colours */
+ gui.norm_pixel = gui.def_norm_pixel;
+ gui.back_pixel = gui.def_back_pixel;
+
+ /* Check if reverse video needs to be applied (on Sun it's done by X) */
+ if (gui.rsrc_rev_video && gui_get_lightness(gui.back_pixel)
+ > gui_get_lightness(gui.norm_pixel))
+ {
+ gui.norm_pixel = gui.def_back_pixel;
+ gui.back_pixel = gui.def_norm_pixel;
+ gui.def_norm_pixel = gui.norm_pixel;
+ gui.def_back_pixel = gui.back_pixel;
+ }
+
+ /* Get the colors from the "Normal", "Tooltip", "Scrollbar" and "Menu"
+ * 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
+ */
+ gui_check_colors();
+
+ /*
+ * Set up the GCs. The font attributes will be set in gui_init_font().
+ */
+ gc_mask = GCForeground | GCBackground;
+ gc_vals.foreground = gui.norm_pixel;
+ gc_vals.background = gui.back_pixel;
+ gui.text_gc = XtGetGC(vimShell, gc_mask, &gc_vals);
+
+ gc_vals.foreground = gui.back_pixel;
+ gc_vals.background = gui.norm_pixel;
+ gui.back_gc = XtGetGC(vimShell, gc_mask, &gc_vals);
+
+ gc_mask |= GCFunction;
+ gc_vals.foreground = gui.norm_pixel ^ gui.back_pixel;
+ gc_vals.background = gui.norm_pixel ^ gui.back_pixel;
+ gc_vals.function = GXxor;
+ gui.invert_gc = XtGetGC(vimShell, gc_mask, &gc_vals);
+
+ gui.visibility = VisibilityUnobscured;
+ x11_setup_atoms(gui.dpy);
+
+ if (gui_win_x != -1 && gui_win_y != -1)
+ gui_mch_set_winpos(gui_win_x, gui_win_y);
+
+ /* Now adapt the supplied(?) geometry-settings */
+ /* Added by Kjetil Jacobsen <kjetilja@stud.cs.uit.no> */
+ if (gui.geom != NULL && *gui.geom != NUL)
+ {
+ mask = XParseGeometry((char *)gui.geom, &x, &y, &w, &h);
+ if (mask & WidthValue)
+ Columns = w;
+ if (mask & HeightValue)
+ {
+ if (p_window > (long)h - 1 || !option_was_set((char_u *)"window"))
+ p_window = h - 1;
+ Rows = h;
+ }
+ limit_screen_size();
+ /*
+ * Set the (x,y) position of the main window only if specified in the
+ * users geometry, so we get good defaults when they don't. This needs
+ * to be done before the shell is popped up.
+ */
+ if (mask & (XValue|YValue))
+ XtVaSetValues(vimShell, XtNgeometry, gui.geom, NULL);
+ }
+
+ gui_x11_create_widgets();
+
+ /*
+ * Add an icon to Vim (Marcel Douben: 11 May 1998).
+ */
+ if (vim_strchr(p_go, GO_ICON) != NULL)
+ {
+#ifndef HAVE_XPM
+# include "vim_icon.xbm"
+# include "vim_mask.xbm"
+
+ Arg arg[2];
+
+ XtSetArg(arg[0], XtNiconPixmap,
+ XCreateBitmapFromData(gui.dpy,
+ DefaultRootWindow(gui.dpy),
+ (char *)vim_icon_bits,
+ vim_icon_width,
+ vim_icon_height));
+ XtSetArg(arg[1], XtNiconMask,
+ XCreateBitmapFromData(gui.dpy,
+ DefaultRootWindow(gui.dpy),
+ (char *)vim_mask_icon_bits,
+ vim_mask_icon_width,
+ vim_mask_icon_height));
+ XtSetValues(vimShell, arg, (Cardinal)2);
+#else
+/* Use Pixmaps, looking much nicer. */
+
+/* If you get an error message here, you still need to unpack the runtime
+ * archive! */
+# ifdef magick
+# undef magick
+# endif
+# define magick vim32x32
+# include "../runtime/vim32x32.xpm"
+# undef magick
+# define magick vim16x16
+# include "../runtime/vim16x16.xpm"
+# undef magick
+# define magick vim48x48
+# include "../runtime/vim48x48.xpm"
+# undef magick
+
+ static Pixmap icon = 0;
+ static Pixmap icon_mask = 0;
+ static char **magick = vim32x32;
+ Window root_window;
+ XIconSize *size;
+ int number_sizes;
+ Display *dsp;
+ Screen *scr;
+ XpmAttributes attr;
+ Colormap cmap;
+
+ /*
+ * Adjust the icon to the preferences of the actual window manager.
+ */
+ root_window = XRootWindowOfScreen(XtScreen(vimShell));
+ if (XGetIconSizes(XtDisplay(vimShell), root_window,
+ &size, &number_sizes) != 0)
+ {
+ if (number_sizes > 0)
+ {
+ if (size->max_height >= 48 && size->max_width >= 48)
+ magick = vim48x48;
+ else if (size->max_height >= 32 && size->max_width >= 32)
+ magick = vim32x32;
+ else if (size->max_height >= 16 && size->max_width >= 16)
+ magick = vim16x16;
+ }
+ }
+
+ dsp = XtDisplay(vimShell);
+ scr = XtScreen(vimShell);
+
+ cmap = DefaultColormap(dsp, DefaultScreen(dsp));
+ XtVaSetValues(vimShell, XtNcolormap, cmap, NULL);
+
+ attr.valuemask = 0L;
+ attr.valuemask = XpmCloseness | XpmReturnPixels | XpmColormap | XpmDepth;
+ attr.closeness = 65535; /* accuracy isn't crucial */
+ attr.colormap = cmap;
+ attr.depth = DefaultDepthOfScreen(scr);
+
+ if (!icon)
+ {
+ XpmCreatePixmapFromData(dsp, root_window, magick, &icon,
+ &icon_mask, &attr);
+ XpmFreeAttributes(&attr);
+ }
+
+# ifdef FEAT_GUI_ATHENA
+ XtVaSetValues(vimShell, XtNiconPixmap, icon, XtNiconMask, icon_mask, NULL);
+# else
+ XtVaSetValues(vimShell, XmNiconPixmap, icon, XmNiconMask, icon_mask, NULL);
+# endif
+#endif
+ }
+
+ if (gui.color_approx)
+ emsg(_("Vim E458: Cannot allocate colormap entry, some colors may be incorrect"));
+
+#ifdef FEAT_BEVAL_GUI
+ gui_init_tooltip_font();
+#endif
+#ifdef FEAT_MENU
+ gui_init_menu_font();
+#endif
+
+#ifdef USE_XSMP
+ /* Attach listener on ICE connection */
+ if (-1 != xsmp_icefd)
+ _xsmp_xtinputid = XtAppAddInput(app_context, xsmp_icefd,
+ (XtPointer)XtInputReadMask, local_xsmp_handle_requests, NULL);
+#endif
+
+ return OK;
+}
+
+/*
+ * Called when starting the GUI fails after calling gui_mch_init().
+ */
+ void
+gui_mch_uninit(void)
+{
+ gui_x11_destroy_widgets();
+ XtCloseDisplay(gui.dpy);
+ gui.dpy = NULL;
+ vimShell = (Widget)0;
+ VIM_CLEAR(gui_argv);
+}
+
+/*
+ * Called when the foreground or background color has been changed.
+ */
+ void
+gui_mch_new_colors(void)
+{
+ long_u gc_mask;
+ XGCValues gc_vals;
+
+ gc_mask = GCForeground | GCBackground;
+ gc_vals.foreground = gui.norm_pixel;
+ gc_vals.background = gui.back_pixel;
+ if (gui.text_gc != NULL)
+ XChangeGC(gui.dpy, gui.text_gc, gc_mask, &gc_vals);
+
+ gc_vals.foreground = gui.back_pixel;
+ gc_vals.background = gui.norm_pixel;
+ if (gui.back_gc != NULL)
+ XChangeGC(gui.dpy, gui.back_gc, gc_mask, &gc_vals);
+
+ gc_mask |= GCFunction;
+ gc_vals.foreground = gui.norm_pixel ^ gui.back_pixel;
+ gc_vals.background = gui.norm_pixel ^ gui.back_pixel;
+ gc_vals.function = GXxor;
+ if (gui.invert_gc != NULL)
+ XChangeGC(gui.dpy, gui.invert_gc, gc_mask, &gc_vals);
+
+ gui_x11_set_back_color();
+}
+
+/*
+ * Open the GUI window which was created by a call to gui_mch_init().
+ */
+ int
+gui_mch_open(void)
+{
+ /* Actually open the window */
+ XtRealizeWidget(vimShell);
+ XtManageChild(XtNameToWidget(vimShell, "*vimForm"));
+
+ gui.wid = gui_x11_get_wid();
+ gui.blank_pointer = gui_x11_create_blank_mouse();
+
+ /*
+ * Add a callback for the Close item on the window managers menu, and the
+ * save-yourself event.
+ */
+ wm_atoms[SAVE_YOURSELF_IDX] =
+ XInternAtom(gui.dpy, "WM_SAVE_YOURSELF", False);
+ wm_atoms[DELETE_WINDOW_IDX] =
+ XInternAtom(gui.dpy, "WM_DELETE_WINDOW", False);
+ XSetWMProtocols(gui.dpy, XtWindow(vimShell), wm_atoms, 2);
+ XtAddEventHandler(vimShell, NoEventMask, True, gui_x11_wm_protocol_handler,
+ NULL);
+#ifdef HAVE_X11_XMU_EDITRES_H
+ /*
+ * Enable editres protocol (see "man editres").
+ * Usually will need to add -lXmu to the linker line as well.
+ */
+ XtAddEventHandler(vimShell, (EventMask)0, True, _XEditResCheckMessages,
+ (XtPointer)NULL);
+#endif
+
+#ifdef FEAT_CLIENTSERVER
+ if (serverName == NULL && serverDelayedStartName != NULL)
+ {
+ /* This is a :gui command in a plain vim with no previous server */
+ commWindow = XtWindow(vimShell);
+ (void)serverRegisterName(gui.dpy, serverDelayedStartName);
+ }
+ else
+ {
+ /*
+ * Cannot handle "widget-less" windows with XtProcessEvent() we'll
+ * have to change the "server" registration to that of the main window
+ * If we have not registered a name yet, remember the window
+ */
+ serverChangeRegisteredWindow(gui.dpy, XtWindow(vimShell));
+ }
+ XtAddEventHandler(vimShell, PropertyChangeMask, False,
+ gui_x11_send_event_handler, NULL);
+#endif
+
+
+#if defined(FEAT_MENU) && defined(FEAT_GUI_ATHENA)
+ /* The Athena GUI needs this again after opening the window */
+ gui_position_menu();
+# ifdef FEAT_TOOLBAR
+ gui_mch_set_toolbar_pos(0, gui.menu_height, gui.menu_width,
+ gui.toolbar_height);
+# endif
+#endif
+
+ /* Get the colors for the highlight groups (gui_check_colors() might have
+ * changed them) */
+ highlight_gui_started(); /* re-init colors and fonts */
+
+#ifdef FEAT_HANGULIN
+ hangul_keyboard_set();
+#endif
+#ifdef FEAT_XIM
+ xim_init();
+#endif
+
+ return OK;
+}
+
+#if defined(FEAT_BEVAL_GUI) || defined(PROTO)
+/*
+ * Convert the tooltip fontset name to an XFontSet.
+ */
+ void
+gui_init_tooltip_font(void)
+{
+ XrmValue from, to;
+
+ from.addr = (char *)gui.rsrc_tooltip_font_name;
+ from.size = strlen(from.addr);
+ to.addr = (XtPointer)&gui.tooltip_fontset;
+ to.size = sizeof(XFontSet);
+
+ if (XtConvertAndStore(vimShell, XtRString, &from, XtRFontSet, &to) == False)
+ {
+ /* Failed. What to do? */
+ }
+}
+#endif
+
+#if defined(FEAT_MENU) || defined(PROTO)
+/* Convert the menu font/fontset name to an XFontStruct/XFontset */
+ void
+gui_init_menu_font(void)
+{
+ XrmValue from, to;
+
+#ifdef FONTSET_ALWAYS
+ from.addr = (char *)gui.rsrc_menu_font_name;
+ from.size = strlen(from.addr);
+ to.addr = (XtPointer)&gui.menu_fontset;
+ to.size = sizeof(GuiFontset);
+
+ if (XtConvertAndStore(vimShell, XtRString, &from, XtRFontSet, &to) == False)
+ {
+ /* Failed. What to do? */
+ }
+#else
+ from.addr = (char *)gui.rsrc_menu_font_name;
+ from.size = strlen(from.addr);
+ to.addr = (XtPointer)&gui.menu_font;
+ to.size = sizeof(GuiFont);
+
+ if (XtConvertAndStore(vimShell, XtRString, &from, XtRFontStruct, &to) == False)
+ {
+ /* Failed. What to do? */
+ }
+#endif
+}
+#endif
+
+ void
+gui_mch_exit(int rc UNUSED)
+{
+#if 0
+ /* Lesstif gives an error message here, and so does Solaris. The man page
+ * says that this isn't needed when exiting, so just skip it. */
+ XtCloseDisplay(gui.dpy);
+#endif
+ VIM_CLEAR(gui_argv);
+}
+
+/*
+ * Get the position of the top left corner of the window.
+ */
+ int
+gui_mch_get_winpos(int *x, int *y)
+{
+ Dimension xpos, ypos;
+
+ XtVaGetValues(vimShell,
+ XtNx, &xpos,
+ XtNy, &ypos,
+ NULL);
+ *x = xpos;
+ *y = ypos;
+ 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)
+{
+ XtVaSetValues(vimShell,
+ XtNx, x,
+ XtNy, y,
+ NULL);
+}
+
+ void
+gui_mch_set_shellsize(
+ int width,
+ int height,
+ int min_width,
+ int min_height,
+ int base_width,
+ int base_height,
+ int direction UNUSED)
+{
+#ifdef FEAT_XIM
+ height += xim_get_status_area_height(),
+#endif
+ XtVaSetValues(vimShell,
+ XtNwidthInc, gui.char_width,
+ XtNheightInc, gui.char_height,
+#if defined(XtSpecificationRelease) && XtSpecificationRelease >= 4
+ XtNbaseWidth, base_width,
+ XtNbaseHeight, base_height,
+#endif
+ XtNminWidth, min_width,
+ XtNminHeight, min_height,
+ XtNwidth, width,
+ XtNheight, height,
+ NULL);
+}
+
+/*
+ * Allow 10 pixels for horizontal borders, 'guiheadroom' for vertical borders.
+ * Is there no way in X to find out how wide the borders really are?
+ */
+ void
+gui_mch_get_screen_dimensions(
+ int *screen_w,
+ int *screen_h)
+{
+ *screen_w = DisplayWidth(gui.dpy, DefaultScreen(gui.dpy)) - 10;
+ *screen_h = DisplayHeight(gui.dpy, DefaultScreen(gui.dpy)) - p_ghr;
+}
+
+/*
+ * Initialise vim to use the font "font_name". If it's NULL, pick a default
+ * font.
+ * If "fontset" is TRUE, load the "font_name" as a fontset.
+ * Return FAIL if the font could not be loaded, OK otherwise.
+ */
+ int
+gui_mch_init_font(
+ char_u *font_name,
+ int do_fontset UNUSED)
+{
+ XFontStruct *font = NULL;
+
+#ifdef FEAT_XFONTSET
+ XFontSet fontset = NULL;
+#endif
+
+#ifdef FEAT_GUI_MOTIF
+ /* A font name equal "*" is indicating, that we should activate the font
+ * selection dialogue to get a new font name. So let us do it here. */
+ if (font_name != NULL && STRCMP(font_name, "*") == 0)
+ font_name = gui_xm_select_font(hl_get_font_name());
+#endif
+
+#ifdef FEAT_XFONTSET
+ if (do_fontset)
+ {
+ /* If 'guifontset' is set, VIM treats all font specifications as if
+ * they were fontsets, and 'guifontset' becomes the default. */
+ if (font_name != NULL)
+ {
+ fontset = (XFontSet)gui_mch_get_fontset(font_name, FALSE, TRUE);
+ if (fontset == NULL)
+ return FAIL;
+ }
+ }
+ else
+#endif
+ {
+ if (font_name == NULL)
+ {
+ /*
+ * If none of the fonts in 'font' could be loaded, try the one set
+ * in the X resource, and finally just try using DFLT_FONT, which
+ * will hopefully always be there.
+ */
+ font_name = gui.rsrc_font_name;
+ font = (XFontStruct *)gui_mch_get_font(font_name, FALSE);
+ if (font == NULL)
+ font_name = (char_u *)DFLT_FONT;
+ }
+ if (font == NULL)
+ font = (XFontStruct *)gui_mch_get_font(font_name, FALSE);
+ if (font == NULL)
+ return FAIL;
+ }
+
+ gui_mch_free_font(gui.norm_font);
+#ifdef FEAT_XFONTSET
+ gui_mch_free_fontset(gui.fontset);
+
+ if (fontset != NULL)
+ {
+ gui.norm_font = NOFONT;
+ gui.fontset = (GuiFontset)fontset;
+ gui.char_width = fontset_width(fontset);
+ gui.char_height = fontset_height(fontset) + p_linespace;
+ gui.char_ascent = fontset_ascent(fontset) + p_linespace / 2;
+ }
+ else
+#endif
+ {
+ gui.norm_font = (GuiFont)font;
+#ifdef FEAT_XFONTSET
+ gui.fontset = NOFONTSET;
+#endif
+ gui.char_width = font->max_bounds.width;
+ gui.char_height = font->ascent + font->descent + p_linespace;
+ gui.char_ascent = font->ascent + p_linespace / 2;
+ }
+
+ hl_set_font_name(font_name);
+
+ /*
+ * Try to load other fonts for bold, italic, and bold-italic.
+ * We should also try to work out what font to use for these when they are
+ * not specified by X resources, but we don't yet.
+ */
+ if (font_name == gui.rsrc_font_name)
+ {
+ if (gui.bold_font == NOFONT
+ && gui.rsrc_bold_font_name != NULL
+ && *gui.rsrc_bold_font_name != NUL)
+ gui.bold_font = gui_mch_get_font(gui.rsrc_bold_font_name, FALSE);
+ if (gui.ital_font == NOFONT
+ && gui.rsrc_ital_font_name != NULL
+ && *gui.rsrc_ital_font_name != NUL)
+ gui.ital_font = gui_mch_get_font(gui.rsrc_ital_font_name, FALSE);
+ if (gui.boldital_font == NOFONT
+ && gui.rsrc_boldital_font_name != NULL
+ && *gui.rsrc_boldital_font_name != NUL)
+ gui.boldital_font = gui_mch_get_font(gui.rsrc_boldital_font_name,
+ FALSE);
+ }
+ else
+ {
+ /* When not using the font specified by the resources, also don't use
+ * the bold/italic fonts, otherwise setting 'guifont' will look very
+ * strange. */
+ if (gui.bold_font != NOFONT)
+ {
+ XFreeFont(gui.dpy, (XFontStruct *)gui.bold_font);
+ gui.bold_font = NOFONT;
+ }
+ if (gui.ital_font != NOFONT)
+ {
+ XFreeFont(gui.dpy, (XFontStruct *)gui.ital_font);
+ gui.ital_font = NOFONT;
+ }
+ if (gui.boldital_font != NOFONT)
+ {
+ XFreeFont(gui.dpy, (XFontStruct *)gui.boldital_font);
+ gui.boldital_font = NOFONT;
+ }
+ }
+
+#ifdef FEAT_GUI_MOTIF
+ gui_motif_synch_fonts();
+#endif
+
+ return OK;
+}
+
+/*
+ * Get a font structure for highlighting.
+ */
+ GuiFont
+gui_mch_get_font(char_u *name, int giveErrorIfMissing)
+{
+ XFontStruct *font;
+
+ if (!gui.in_use || name == NULL) /* can't do this when GUI not running */
+ return NOFONT;
+
+ font = XLoadQueryFont(gui.dpy, (char *)name);
+
+ if (font == NULL)
+ {
+ if (giveErrorIfMissing)
+ semsg(_(e_font), name);
+ return NOFONT;
+ }
+
+#ifdef DEBUG
+ printf("Font Information for '%s':\n", name);
+ printf(" w = %d, h = %d, ascent = %d, descent = %d\n",
+ font->max_bounds.width, font->ascent + font->descent,
+ font->ascent, font->descent);
+ printf(" max ascent = %d, max descent = %d, max h = %d\n",
+ font->max_bounds.ascent, font->max_bounds.descent,
+ font->max_bounds.ascent + font->max_bounds.descent);
+ printf(" min lbearing = %d, min rbearing = %d\n",
+ font->min_bounds.lbearing, font->min_bounds.rbearing);
+ printf(" max lbearing = %d, max rbearing = %d\n",
+ font->max_bounds.lbearing, font->max_bounds.rbearing);
+ printf(" leftink = %d, rightink = %d\n",
+ (font->min_bounds.lbearing < 0),
+ (font->max_bounds.rbearing > font->max_bounds.width));
+ printf("\n");
+#endif
+
+ if (font->max_bounds.width != font->min_bounds.width)
+ {
+ semsg(_(e_fontwidth), name);
+ XFreeFont(gui.dpy, font);
+ return NOFONT;
+ }
+ return (GuiFont)font;
+}
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * Return the name of font "font" in allocated memory.
+ */
+ char_u *
+gui_mch_get_fontname(GuiFont font, char_u *name)
+{
+ char_u *ret = NULL;
+
+ if (name != NULL && font == NULL)
+ {
+ /* In this case, there's no way other than doing this. */
+ ret = vim_strsave(name);
+ }
+ else if (font != NULL)
+ {
+ /* In this case, try to retrieve the XLFD corresponding to 'font'->fid;
+ * if failed, use 'name' unless it's NULL. */
+ unsigned long value = 0L;
+
+ if (XGetFontProperty(font, XA_FONT, &value))
+ {
+ char *xa_font_name = NULL;
+
+ xa_font_name = XGetAtomName(gui.dpy, value);
+ if (xa_font_name != NULL)
+ {
+ ret = vim_strsave((char_u *)xa_font_name);
+ XFree(xa_font_name);
+ }
+ else if (name != NULL)
+ ret = vim_strsave(name);
+ }
+ else if (name != NULL)
+ ret = vim_strsave(name);
+ }
+ return ret;
+}
+#endif
+
+/*
+ * Adjust gui.char_height (after 'linespace' was changed).
+ */
+ int
+gui_mch_adjust_charheight(void)
+{
+#ifdef FEAT_XFONTSET
+ if (gui.fontset != NOFONTSET)
+ {
+ gui.char_height = fontset_height((XFontSet)gui.fontset) + p_linespace;
+ gui.char_ascent = fontset_ascent((XFontSet)gui.fontset)
+ + p_linespace / 2;
+ }
+ else
+#endif
+ {
+ XFontStruct *font = (XFontStruct *)gui.norm_font;
+
+ gui.char_height = font->ascent + font->descent + p_linespace;
+ gui.char_ascent = font->ascent + p_linespace / 2;
+ }
+ return OK;
+}
+
+/*
+ * Set the current text font.
+ */
+ void
+gui_mch_set_font(GuiFont font)
+{
+ static Font prev_font = (Font)-1;
+ Font fid = ((XFontStruct *)font)->fid;
+
+ if (fid != prev_font)
+ {
+ XSetFont(gui.dpy, gui.text_gc, fid);
+ XSetFont(gui.dpy, gui.back_gc, fid);
+ prev_font = fid;
+ gui.char_ascent = ((XFontStruct *)font)->ascent + p_linespace / 2;
+ }
+#ifdef FEAT_XFONTSET
+ current_fontset = (XFontSet)NULL;
+#endif
+}
+
+#if defined(FEAT_XFONTSET) || defined(PROTO)
+/*
+ * Set the current text fontset.
+ * Adjust the ascent, in case it's different.
+ */
+ void
+gui_mch_set_fontset(GuiFontset fontset)
+{
+ current_fontset = (XFontSet)fontset;
+ gui.char_ascent = fontset_ascent(current_fontset) + p_linespace / 2;
+}
+#endif
+
+/*
+ * If a font is not going to be used, free its structure.
+ */
+ void
+gui_mch_free_font(GuiFont font)
+{
+ if (font != NOFONT)
+ XFreeFont(gui.dpy, (XFontStruct *)font);
+}
+
+#if defined(FEAT_XFONTSET) || defined(PROTO)
+/*
+ * If a fontset is not going to be used, free its structure.
+ */
+ void
+gui_mch_free_fontset(GuiFontset fontset)
+{
+ if (fontset != NOFONTSET)
+ XFreeFontSet(gui.dpy, (XFontSet)fontset);
+}
+
+/*
+ * Load the fontset "name".
+ * Return a reference to the fontset, or NOFONTSET when failing.
+ */
+ GuiFontset
+gui_mch_get_fontset(
+ char_u *name,
+ int giveErrorIfMissing,
+ int fixed_width)
+{
+ XFontSet fontset;
+ char **missing, *def_str;
+ int num_missing;
+
+ if (!gui.in_use || name == NULL)
+ return NOFONTSET;
+
+ fontset = XCreateFontSet(gui.dpy, (char *)name, &missing, &num_missing,
+ &def_str);
+ if (num_missing > 0)
+ {
+ int i;
+
+ if (giveErrorIfMissing)
+ {
+ semsg(_("E250: Fonts for the following charsets are missing in fontset %s:"), name);
+ for (i = 0; i < num_missing; i++)
+ semsg("%s", missing[i]);
+ }
+ XFreeStringList(missing);
+ }
+
+ if (fontset == NULL)
+ {
+ if (giveErrorIfMissing)
+ semsg(_(e_fontset), name);
+ return NOFONTSET;
+ }
+
+ if (fixed_width && check_fontset_sanity(fontset) == FAIL)
+ {
+ XFreeFontSet(gui.dpy, fontset);
+ return NOFONTSET;
+ }
+ return (GuiFontset)fontset;
+}
+
+/*
+ * Check if fontset "fs" is fixed width.
+ */
+ static int
+check_fontset_sanity(XFontSet fs)
+{
+ XFontStruct **xfs;
+ char **font_name;
+ int fn;
+ char *base_name;
+ int i;
+ int min_width;
+ int min_font_idx = 0;
+
+ base_name = XBaseFontNameListOfFontSet(fs);
+ fn = XFontsOfFontSet(fs, &xfs, &font_name);
+ for (i = 0; i < fn; i++)
+ {
+ if (xfs[i]->max_bounds.width != xfs[i]->min_bounds.width)
+ {
+ semsg(_("E252: Fontset name: %s"), base_name);
+ semsg(_("Font '%s' is not fixed-width"), font_name[i]);
+ return FAIL;
+ }
+ }
+ /* scan base font width */
+ min_width = 32767;
+ for (i = 0; i < fn; i++)
+ {
+ if (xfs[i]->max_bounds.width<min_width)
+ {
+ min_width = xfs[i]->max_bounds.width;
+ min_font_idx = i;
+ }
+ }
+ for (i = 0; i < fn; i++)
+ {
+ if ( xfs[i]->max_bounds.width != 2 * min_width
+ && xfs[i]->max_bounds.width != min_width)
+ {
+ semsg(_("E253: Fontset name: %s"), base_name);
+ semsg(_("Font0: %s"), font_name[min_font_idx]);
+ semsg(_("Font%d: %s"), i, font_name[i]);
+ semsg(_("Font%d width is not twice that of font0"), i);
+ semsg(_("Font0 width: %d"),
+ (int)xfs[min_font_idx]->max_bounds.width);
+ semsg(_("Font%d width: %d"), i, (int)xfs[i]->max_bounds.width);
+ return FAIL;
+ }
+ }
+ /* it seems ok. Good Luck!! */
+ return OK;
+}
+
+ static int
+fontset_width(XFontSet fs)
+{
+ return XmbTextEscapement(fs, "Vim", 3) / 3;
+}
+
+ int
+fontset_height(
+ XFontSet fs)
+{
+ XFontSetExtents *extents;
+
+ extents = XExtentsOfFontSet(fs);
+ return extents->max_logical_extent.height;
+}
+
+#if (defined(FONTSET_ALWAYS) && defined(FEAT_GUI_ATHENA) \
+ && defined(FEAT_MENU)) || defined(PROTO)
+/*
+ * Returns the bounding box height around the actual glyph image of all
+ * characters in all fonts of the fontset.
+ */
+ int
+fontset_height2(XFontSet fs)
+{
+ XFontSetExtents *extents;
+
+ extents = XExtentsOfFontSet(fs);
+ return extents->max_ink_extent.height;
+}
+#endif
+
+/* NOT USED YET
+ static int
+fontset_descent(XFontSet fs)
+{
+ XFontSetExtents *extents;
+
+ extents = XExtentsOfFontSet (fs);
+ return extents->max_logical_extent.height + extents->max_logical_extent.y;
+}
+*/
+
+ static int
+fontset_ascent(XFontSet fs)
+{
+ XFontSetExtents *extents;
+
+ extents = XExtentsOfFontSet(fs);
+ return -extents->max_logical_extent.y;
+}
+
+#endif /* FEAT_XFONTSET */
+
+/*
+ * Return the Pixel value (color) for the given color name.
+ * Return INVALCOLOR for error.
+ */
+ guicolor_T
+gui_mch_get_color(char_u *name)
+{
+ guicolor_T requested;
+
+ /* can't do this when GUI not running */
+ if (!gui.in_use || name == NULL || *name == NUL)
+ return INVALCOLOR;
+
+ requested = gui_get_color_cmn(name);
+ if (requested == INVALCOLOR)
+ return INVALCOLOR;
+
+ return gui_mch_get_rgb_color(
+ (requested & 0xff0000) >> 16,
+ (requested & 0xff00) >> 8,
+ requested & 0xff);
+}
+
+/*
+ * Return the Pixel value (color) for the given RGB values.
+ * Return INVALCOLOR for error.
+ */
+ guicolor_T
+gui_mch_get_rgb_color(int r, int g, int b)
+{
+ XColor available;
+ Colormap colormap;
+
+/* Using XParseColor() is very slow, put rgb in XColor directly.
+
+ char spec[8]; // space enough to hold "#RRGGBB"
+ vim_snprintf(spec, sizeof(spec), "#%.2x%.2x%.2x", r, g, b);
+ if (XParseColor(gui.dpy, colormap, (char *)spec, &available) != 0
+ && XAllocColor(gui.dpy, colormap, &available) != 0)
+ return (guicolor_T)available.pixel;
+*/
+ colormap = DefaultColormap(gui.dpy, DefaultScreen(gui.dpy));
+ vim_memset(&available, 0, sizeof(XColor));
+ available.red = r << 8;
+ available.green = g << 8;
+ available.blue = b << 8;
+ if (XAllocColor(gui.dpy, colormap, &available) != 0)
+ return (guicolor_T)available.pixel;
+
+ return INVALCOLOR;
+}
+
+/*
+ * Set the current text foreground color.
+ */
+ void
+gui_mch_set_fg_color(guicolor_T color)
+{
+ if (color != prev_fg_color)
+ {
+ XSetForeground(gui.dpy, gui.text_gc, (Pixel)color);
+ prev_fg_color = color;
+ }
+}
+
+/*
+ * Set the current text background color.
+ */
+ void
+gui_mch_set_bg_color(guicolor_T color)
+{
+ if (color != prev_bg_color)
+ {
+ XSetBackground(gui.dpy, gui.text_gc, (Pixel)color);
+ prev_bg_color = color;
+ }
+}
+
+/*
+ * Set the current text special color.
+ */
+ void
+gui_mch_set_sp_color(guicolor_T color)
+{
+ prev_sp_color = color;
+}
+
+/*
+ * create a mouse pointer that is blank
+ */
+ static Cursor
+gui_x11_create_blank_mouse(void)
+{
+ Pixmap blank_pixmap = XCreatePixmap(gui.dpy, gui.wid, 1, 1, 1);
+ GC gc = XCreateGC(gui.dpy, blank_pixmap, (unsigned long)0, (XGCValues*)0);
+ XDrawPoint(gui.dpy, blank_pixmap, gc, 0, 0);
+ XFreeGC(gui.dpy, gc);
+ return XCreatePixmapCursor(gui.dpy, blank_pixmap, blank_pixmap,
+ (XColor*)&gui.norm_pixel, (XColor*)&gui.norm_pixel, 0, 0);
+}
+
+/*
+ * Draw a curled line at the bottom of the character cell.
+ */
+ static void
+draw_curl(int row, int col, int cells)
+{
+ int i;
+ int offset;
+ static const int val[8] = {1, 0, 0, 0, 1, 2, 2, 2 };
+
+ XSetForeground(gui.dpy, gui.text_gc, prev_sp_color);
+ for (i = FILL_X(col); i < FILL_X(col + cells); ++i)
+ {
+ offset = val[i % 8];
+ XDrawPoint(gui.dpy, gui.wid, gui.text_gc, i,
+ FILL_Y(row + 1) - 1 - offset);
+ }
+ XSetForeground(gui.dpy, gui.text_gc, prev_fg_color);
+}
+
+ void
+gui_mch_draw_string(
+ int row,
+ int col,
+ char_u *s,
+ int len,
+ int flags)
+{
+ int cells = len;
+ static void *buf = NULL;
+ static int buflen = 0;
+ char_u *p;
+ int wlen = 0;
+ int c;
+
+ if (enc_utf8)
+ {
+ /* Convert UTF-8 byte sequence to 16 bit characters for the X
+ * functions. Need a buffer for the 16 bit characters. Keep it
+ * between calls, because allocating it each time is slow. */
+ if (buflen < len)
+ {
+ XtFree((char *)buf);
+ buf = (void *)XtMalloc(len * (sizeof(XChar2b) < sizeof(wchar_t)
+ ? sizeof(wchar_t) : sizeof(XChar2b)));
+ buflen = len;
+ }
+ p = s;
+ cells = 0;
+ while (p < s + len)
+ {
+ c = utf_ptr2char(p);
+#ifdef FEAT_XFONTSET
+ if (current_fontset != NULL)
+ {
+# ifdef SMALL_WCHAR_T
+ if (c >= 0x10000)
+ c = 0xbf; /* show chars > 0xffff as ? */
+# endif
+ ((wchar_t *)buf)[wlen] = c;
+ }
+ else
+#endif
+ {
+ if (c >= 0x10000)
+ c = 0xbf; /* show chars > 0xffff as ? */
+ ((XChar2b *)buf)[wlen].byte1 = (unsigned)c >> 8;
+ ((XChar2b *)buf)[wlen].byte2 = c;
+ }
+ ++wlen;
+ cells += utf_char2cells(c);
+ p += utf_ptr2len(p);
+ }
+ }
+ else if (has_mbyte)
+ {
+ cells = 0;
+ for (p = s; p < s + len; )
+ {
+ cells += ptr2cells(p);
+ p += (*mb_ptr2len)(p);
+ }
+ }
+
+#ifdef FEAT_XFONTSET
+ if (current_fontset != NULL)
+ {
+ /* Setup a clip rectangle to avoid spilling over in the next or
+ * previous line. This is apparently needed for some fonts which are
+ * used in a fontset. */
+ XRectangle clip;
+
+ clip.x = 0;
+ clip.y = 0;
+ clip.height = gui.char_height;
+ clip.width = gui.char_width * cells + 1;
+ XSetClipRectangles(gui.dpy, gui.text_gc, FILL_X(col), FILL_Y(row),
+ &clip, 1, Unsorted);
+ }
+#endif
+
+ if (flags & DRAW_TRANSP)
+ {
+ if (enc_utf8)
+ XDrawString16(gui.dpy, gui.wid, gui.text_gc, TEXT_X(col),
+ TEXT_Y(row), buf, wlen);
+ else
+ XDrawString(gui.dpy, gui.wid, gui.text_gc, TEXT_X(col),
+ TEXT_Y(row), (char *)s, len);
+ }
+ else if (p_linespace != 0
+#ifdef FEAT_XFONTSET
+ || current_fontset != NULL
+#endif
+ )
+ {
+ XSetForeground(gui.dpy, gui.text_gc, prev_bg_color);
+ XFillRectangle(gui.dpy, gui.wid, gui.text_gc, FILL_X(col),
+ FILL_Y(row), gui.char_width * cells, gui.char_height);
+ XSetForeground(gui.dpy, gui.text_gc, prev_fg_color);
+
+ if (enc_utf8)
+ XDrawString16(gui.dpy, gui.wid, gui.text_gc, TEXT_X(col),
+ TEXT_Y(row), buf, wlen);
+ else
+ XDrawString(gui.dpy, gui.wid, gui.text_gc, TEXT_X(col),
+ TEXT_Y(row), (char *)s, len);
+ }
+ else
+ {
+ /* XmbDrawImageString has bug, don't use it for fontset. */
+ if (enc_utf8)
+ XDrawImageString16(gui.dpy, gui.wid, gui.text_gc, TEXT_X(col),
+ TEXT_Y(row), buf, wlen);
+ else
+ XDrawImageString(gui.dpy, gui.wid, gui.text_gc, TEXT_X(col),
+ TEXT_Y(row), (char *)s, len);
+ }
+
+ /* Bold trick: draw the text again with a one-pixel offset. */
+ if (flags & DRAW_BOLD)
+ {
+ if (enc_utf8)
+ XDrawString16(gui.dpy, gui.wid, gui.text_gc, TEXT_X(col) + 1,
+ TEXT_Y(row), buf, wlen);
+ else
+ XDrawString(gui.dpy, gui.wid, gui.text_gc, TEXT_X(col) + 1,
+ TEXT_Y(row), (char *)s, len);
+ }
+
+ /* Undercurl: draw curl at the bottom of the character cell. */
+ if (flags & DRAW_UNDERC)
+ draw_curl(row, col, cells);
+
+ /* Underline: draw a line at the bottom of the character cell. */
+ if (flags & DRAW_UNDERL)
+ {
+ int y = FILL_Y(row + 1) - 1;
+
+ /* When p_linespace is 0, overwrite the bottom row of pixels.
+ * Otherwise put the line just below the character. */
+ if (p_linespace > 1)
+ y -= p_linespace - 1;
+ XDrawLine(gui.dpy, gui.wid, gui.text_gc, FILL_X(col),
+ y, FILL_X(col + cells) - 1, y);
+ }
+
+ if (flags & DRAW_STRIKE)
+ {
+ int y = FILL_Y(row + 1) - gui.char_height/2;
+
+ XSetForeground(gui.dpy, gui.text_gc, prev_sp_color);
+ XDrawLine(gui.dpy, gui.wid, gui.text_gc, FILL_X(col),
+ y, FILL_X(col + cells) - 1, y);
+ XSetForeground(gui.dpy, gui.text_gc, prev_fg_color);
+ }
+
+#ifdef FEAT_XFONTSET
+ if (current_fontset != NULL)
+ XSetClipMask(gui.dpy, gui.text_gc, None);
+#endif
+}
+
+/*
+ * 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;
+}
+
+/*
+ * Return the text window-id and display. Only required for X-based GUI's
+ */
+ int
+gui_get_x11_windis(Window *win, Display **dis)
+{
+ *win = XtWindow(vimShell);
+ *dis = gui.dpy;
+ return OK;
+}
+
+ void
+gui_mch_beep(void)
+{
+ XBell(gui.dpy, 0);
+}
+
+ void
+gui_mch_flash(int msec)
+{
+ /* Do a visual beep by reversing the foreground and background colors */
+ XFillRectangle(gui.dpy, gui.wid, gui.invert_gc, 0, 0,
+ FILL_X((int)Columns) + gui.border_offset,
+ FILL_Y((int)Rows) + gui.border_offset);
+ XSync(gui.dpy, False);
+ ui_delay((long)msec, TRUE); /* wait for a few msec */
+ XFillRectangle(gui.dpy, gui.wid, gui.invert_gc, 0, 0,
+ FILL_X((int)Columns) + gui.border_offset,
+ FILL_Y((int)Rows) + gui.border_offset);
+}
+
+/*
+ * 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)
+{
+ XFillRectangle(gui.dpy, gui.wid, gui.invert_gc,
+ FILL_X(c), FILL_Y(r), (nc) * gui.char_width, (nr) * gui.char_height);
+}
+
+/*
+ * Iconify the GUI window.
+ */
+ void
+gui_mch_iconify(void)
+{
+ XIconifyWindow(gui.dpy, XtWindow(vimShell), DefaultScreen(gui.dpy));
+}
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * Bring the Vim window to the foreground.
+ */
+ void
+gui_mch_set_foreground(void)
+{
+ XMapRaised(gui.dpy, XtWindow(vimShell));
+}
+#endif
+
+/*
+ * Draw a cursor without focus.
+ */
+ void
+gui_mch_draw_hollow_cursor(guicolor_T color)
+{
+ int w = 1;
+
+ if (mb_lefthalve(gui.row, gui.col))
+ w = 2;
+ gui_mch_set_fg_color(color);
+ XDrawRectangle(gui.dpy, gui.wid, gui.text_gc, FILL_X(gui.col),
+ FILL_Y(gui.row), w * gui.char_width - 1, gui.char_height - 1);
+}
+
+/*
+ * Draw part of a cursor, "w" pixels wide, and "h" pixels high, using
+ * color "color".
+ */
+ void
+gui_mch_draw_part_cursor(int w, int h, guicolor_T color)
+{
+ gui_mch_set_fg_color(color);
+
+ XFillRectangle(gui.dpy, gui.wid, gui.text_gc,
+#ifdef FEAT_RIGHTLEFT
+ /* vertical line should be on the right of current point */
+ CURSOR_BAR_RIGHT ? FILL_X(gui.col + 1) - w :
+#endif
+ FILL_X(gui.col),
+ FILL_Y(gui.row) + gui.char_height - h,
+ w, h);
+}
+
+/*
+ * 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)
+{
+ XtInputMask mask, desired;
+
+#ifdef ALT_X_INPUT
+ if (suppress_alternate_input)
+ desired = (XtIMXEvent | XtIMTimer);
+ else
+#endif
+ desired = (XtIMAll);
+ while ((mask = XtAppPending(app_context)) && (mask & desired)
+ && !vim_is_input_buf_full())
+ XtAppProcessEvent(app_context, desired);
+}
+
+/*
+ * 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(long wtime)
+{
+ int focus;
+ int retval = FAIL;
+
+ /*
+ * Make this static, in case gui_x11_timer_cb is called after leaving
+ * this function (otherwise a random value on the stack may be changed).
+ */
+ static int timed_out;
+ XtIntervalId timer = (XtIntervalId)0;
+ XtInputMask desired;
+#ifdef FEAT_JOB_CHANNEL
+ XtIntervalId channel_timer = (XtIntervalId)0;
+#endif
+
+ timed_out = FALSE;
+
+ if (wtime >= 0)
+ timer = XtAppAddTimeOut(app_context,
+ (long_u)(wtime == 0 ? 1L : wtime),
+ gui_x11_timer_cb, &timed_out);
+#ifdef FEAT_JOB_CHANNEL
+ /* If there is a channel with the keep_open flag we need to poll for input
+ * on them. */
+ if (channel_any_keep_open())
+ channel_timer = XtAppAddTimeOut(app_context, (long_u)20,
+ channel_poll_cb, (XtPointer)&channel_timer);
+#endif
+
+ focus = gui.in_focus;
+ desired = (XtIMAll);
+ while (!timed_out)
+ {
+ /* Stop or start blinking when focus changes */
+ if (gui.in_focus != focus)
+ {
+ if (gui.in_focus)
+ gui_mch_start_blink();
+ else
+ gui_mch_stop_blink(TRUE);
+ focus = gui.in_focus;
+ }
+
+#ifdef MESSAGE_QUEUE
+# ifdef FEAT_TIMERS
+ did_add_timer = FALSE;
+# endif
+ parse_queued_messages();
+# ifdef FEAT_TIMERS
+ if (did_add_timer)
+ /* Need to recompute the waiting time. */
+ break;
+# endif
+#endif
+
+ /*
+ * Don't use gui_mch_update() because then we will spin-lock until a
+ * char arrives, instead we use XtAppProcessEvent() 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. Note that
+ * XtAppNextEvent() may not be used because it will not return after a
+ * timer event has arrived -- webb
+ */
+ XtAppProcessEvent(app_context, desired);
+
+ if (input_available())
+ {
+ retval = OK;
+ break;
+ }
+ }
+
+ if (timer != (XtIntervalId)0 && !timed_out)
+ XtRemoveTimeOut(timer);
+#ifdef FEAT_JOB_CHANNEL
+ if (channel_timer != (XtIntervalId)0)
+ XtRemoveTimeOut(channel_timer);
+#endif
+
+ return retval;
+}
+
+/*
+ * Output routines.
+ */
+
+/* Flush any output to the screen */
+ void
+gui_mch_flush(void)
+{
+ XFlush(gui.dpy);
+}
+
+/*
+ * 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)
+{
+ int x;
+
+ x = FILL_X(col1);
+
+ /* Clear one extra pixel at the far right, for when bold characters have
+ * spilled over to the next column. */
+ XFillRectangle(gui.dpy, gui.wid, gui.back_gc, x, FILL_Y(row1),
+ (col2 - col1 + 1) * gui.char_width + (col2 == Columns - 1),
+ (row2 - row1 + 1) * gui.char_height);
+}
+
+ void
+gui_mch_clear_all(void)
+{
+ XClearArea(gui.dpy, gui.wid, 0, 0, 0, 0, False);
+}
+
+/*
+ * 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)
+{
+ if (gui.visibility == VisibilityFullyObscured)
+ return; /* Can't see the window */
+
+ /* copy one extra pixel at the far right, for when bold has spilled
+ * over */
+ XCopyArea(gui.dpy, gui.wid, gui.wid, gui.text_gc,
+ FILL_X(gui.scroll_region_left), FILL_Y(row + num_lines),
+ gui.char_width * (gui.scroll_region_right - gui.scroll_region_left + 1)
+ + (gui.scroll_region_right == Columns - 1),
+ gui.char_height * (gui.scroll_region_bot - row - num_lines + 1),
+ FILL_X(gui.scroll_region_left), FILL_Y(row));
+
+ gui_clear_block(gui.scroll_region_bot - num_lines + 1,
+ gui.scroll_region_left,
+ gui.scroll_region_bot, gui.scroll_region_right);
+ gui_x11_check_copy_area();
+}
+
+/*
+ * 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)
+{
+ if (gui.visibility == VisibilityFullyObscured)
+ return; /* Can't see the window */
+
+ /* copy one extra pixel at the far right, for when bold has spilled
+ * over */
+ XCopyArea(gui.dpy, gui.wid, gui.wid, gui.text_gc,
+ FILL_X(gui.scroll_region_left), FILL_Y(row),
+ gui.char_width * (gui.scroll_region_right - gui.scroll_region_left + 1)
+ + (gui.scroll_region_right == Columns - 1),
+ gui.char_height * (gui.scroll_region_bot - row - num_lines + 1),
+ FILL_X(gui.scroll_region_left), FILL_Y(row + num_lines));
+
+ gui_clear_block(row, gui.scroll_region_left,
+ row + num_lines - 1, gui.scroll_region_right);
+ gui_x11_check_copy_area();
+}
+
+/*
+ * Update the region revealed by scrolling up/down.
+ */
+ static void
+gui_x11_check_copy_area(void)
+{
+ XEvent event;
+ XGraphicsExposeEvent *gevent;
+
+ if (gui.visibility != VisibilityPartiallyObscured)
+ return;
+
+ XFlush(gui.dpy);
+
+ /* Wait to check whether the scroll worked or not */
+ for (;;)
+ {
+ if (XCheckTypedEvent(gui.dpy, NoExpose, &event))
+ return; /* The scroll worked. */
+
+ if (XCheckTypedEvent(gui.dpy, GraphicsExpose, &event))
+ {
+ gevent = (XGraphicsExposeEvent *)&event;
+ gui_redraw(gevent->x, gevent->y, gevent->width, gevent->height);
+ if (gevent->count == 0)
+ return; /* This was the last expose event */
+ }
+ XSync(gui.dpy, False);
+ }
+}
+
+/*
+ * X Selection stuff, for cutting and pasting text to other windows.
+ */
+
+ void
+clip_mch_lose_selection(VimClipboard *cbd)
+{
+ clip_x11_lose_selection(vimShell, cbd);
+}
+
+ int
+clip_mch_own_selection(VimClipboard *cbd)
+{
+ return clip_x11_own_selection(vimShell, cbd);
+}
+
+ void
+clip_mch_request_selection(VimClipboard *cbd)
+{
+ clip_x11_request_selection(vimShell, gui.dpy, cbd);
+}
+
+ void
+clip_mch_set_selection(
+ VimClipboard *cbd)
+{
+ clip_x11_set_selection(cbd);
+}
+
+#if defined(FEAT_MENU) || defined(PROTO)
+/*
+ * Menu stuff.
+ */
+
+/*
+ * Make a menu either grey or not grey.
+ */
+ void
+gui_mch_menu_grey(vimmenu_T *menu, int grey)
+{
+ if (menu->id != (Widget)0)
+ {
+ gui_mch_menu_hidden(menu, False);
+ if (grey
+#ifdef FEAT_GUI_MOTIF
+ || !menu->sensitive
+#endif
+ )
+ XtSetSensitive(menu->id, False);
+ else
+ XtSetSensitive(menu->id, True);
+ }
+}
+
+/*
+ * Make menu item hidden or not hidden
+ */
+ void
+gui_mch_menu_hidden(vimmenu_T *menu, int hidden)
+{
+ if (menu->id != (Widget)0)
+ {
+ if (hidden)
+ XtUnmanageChild(menu->id);
+ else
+ XtManageChild(menu->id);
+ }
+}
+
+/*
+ * This is called after setting all the menus to grey/hidden or not.
+ */
+ void
+gui_mch_draw_menubar(void)
+{
+ /* Nothing to do in X */
+}
+
+ void
+gui_x11_menu_cb(
+ Widget w UNUSED,
+ XtPointer client_data,
+ XtPointer call_data UNUSED)
+{
+ gui_menu_cb((vimmenu_T *)client_data);
+}
+
+#endif /* FEAT_MENU */
+
+
+
+/*
+ * Function called when window closed. Works like ":qa".
+ * Should put up a requester!
+ */
+ static void
+gui_x11_wm_protocol_handler(
+ Widget w UNUSED,
+ XtPointer client_data UNUSED,
+ XEvent *event,
+ Boolean *dum UNUSED)
+{
+ /*
+ * Only deal with Client messages.
+ */
+ if (event->type != ClientMessage)
+ return;
+
+ /*
+ * The WM_SAVE_YOURSELF event arrives when the window manager wants to
+ * exit. That can be cancelled though, thus Vim shouldn't exit here.
+ * Just sync our swap files.
+ */
+ if ((Atom)((XClientMessageEvent *)event)->data.l[0] ==
+ wm_atoms[SAVE_YOURSELF_IDX])
+ {
+ out_flush();
+ ml_sync_all(FALSE, FALSE); /* preserve all swap files */
+
+ /* Set the window's WM_COMMAND property, to let the window manager
+ * know we are done saving ourselves. We don't want to be restarted,
+ * thus set argv to NULL. */
+ XSetCommand(gui.dpy, XtWindow(vimShell), NULL, 0);
+ return;
+ }
+
+ if ((Atom)((XClientMessageEvent *)event)->data.l[0] !=
+ wm_atoms[DELETE_WINDOW_IDX])
+ return;
+
+ gui_shell_closed();
+}
+
+#ifdef FEAT_CLIENTSERVER
+/*
+ * Function called when property changed. Check for incoming commands
+ */
+ static void
+gui_x11_send_event_handler(
+ Widget w UNUSED,
+ XtPointer client_data UNUSED,
+ XEvent *event,
+ Boolean *dum UNUSED)
+{
+ XPropertyEvent *e = (XPropertyEvent *) event;
+
+ if (e->type == PropertyNotify && e->window == commWindow
+ && e->atom == commProperty && e->state == PropertyNewValue)
+ {
+ serverEventProc(gui.dpy, event, 0);
+ }
+}
+#endif
+
+/*
+ * 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
+ */
+
+#define BLINK_NONE 0
+#define BLINK_OFF 1
+#define BLINK_ON 2
+
+static int blink_state = BLINK_NONE;
+static long_u blink_waittime = 700;
+static long_u blink_ontime = 400;
+static long_u blink_offtime = 250;
+static XtIntervalId blink_timer = (XtIntervalId)0;
+
+ int
+gui_mch_is_blinking(void)
+{
+ return blink_state != BLINK_NONE;
+}
+
+ int
+gui_mch_is_blink_off(void)
+{
+ return blink_state == BLINK_OFF;
+}
+
+ void
+gui_mch_set_blinking(long waittime, long on, long off)
+{
+ blink_waittime = waittime;
+ blink_ontime = on;
+ blink_offtime = off;
+}
+
+/*
+ * Stop the cursor blinking. Show the cursor if it wasn't shown.
+ */
+ void
+gui_mch_stop_blink(int may_call_gui_update_cursor)
+{
+ if (blink_timer != (XtIntervalId)0)
+ {
+ XtRemoveTimeOut(blink_timer);
+ blink_timer = (XtIntervalId)0;
+ }
+ if (blink_state == BLINK_OFF && may_call_gui_update_cursor)
+ gui_update_cursor(TRUE, FALSE);
+ blink_state = BLINK_NONE;
+}
+
+ static void
+gui_x11_blink_cb(
+ XtPointer timed_out UNUSED,
+ XtIntervalId *interval_id UNUSED)
+{
+ if (blink_state == BLINK_ON)
+ {
+ gui_undraw_cursor();
+ blink_state = BLINK_OFF;
+ blink_timer = XtAppAddTimeOut(app_context, blink_offtime,
+ gui_x11_blink_cb, NULL);
+ }
+ else
+ {
+ gui_update_cursor(TRUE, FALSE);
+ blink_state = BLINK_ON;
+ blink_timer = XtAppAddTimeOut(app_context, blink_ontime,
+ gui_x11_blink_cb, NULL);
+ }
+}
+
+/*
+ * Start the cursor blinking. If it was already blinking, this restarts the
+ * waiting time and shows the cursor.
+ */
+ void
+gui_mch_start_blink(void)
+{
+ if (blink_timer != (XtIntervalId)0)
+ XtRemoveTimeOut(blink_timer);
+ /* Only switch blinking on if none of the times is zero */
+ if (blink_waittime && blink_ontime && blink_offtime && gui.in_focus)
+ {
+ blink_timer = XtAppAddTimeOut(app_context, blink_waittime,
+ gui_x11_blink_cb, NULL);
+ blink_state = BLINK_ON;
+ gui_update_cursor(TRUE, FALSE);
+ }
+}
+
+/*
+ * Return the RGB value of a pixel as a long.
+ */
+ guicolor_T
+gui_mch_get_rgb(guicolor_T pixel)
+{
+ XColor xc;
+ Colormap colormap;
+
+ colormap = DefaultColormap(gui.dpy, XDefaultScreen(gui.dpy));
+ xc.pixel = pixel;
+ XQueryColor(gui.dpy, colormap, &xc);
+
+ return (guicolor_T)(((xc.red & 0xff00) << 8) + (xc.green & 0xff00)
+ + ((unsigned)xc.blue >> 8));
+}
+
+/*
+ * Add the callback functions.
+ */
+ void
+gui_x11_callbacks(Widget textArea, Widget vimForm)
+{
+ XtAddEventHandler(textArea, VisibilityChangeMask, FALSE,
+ gui_x11_visibility_cb, (XtPointer)0);
+
+ XtAddEventHandler(textArea, ExposureMask, FALSE, gui_x11_expose_cb,
+ (XtPointer)0);
+
+ XtAddEventHandler(vimShell, StructureNotifyMask, FALSE,
+ gui_x11_resize_window_cb, (XtPointer)0);
+
+ XtAddEventHandler(vimShell, FocusChangeMask, FALSE, gui_x11_focus_change_cb,
+ (XtPointer)0);
+ /*
+ * Only install these enter/leave callbacks when 'p' in 'guioptions'.
+ * Only needed for some window managers.
+ */
+ if (vim_strchr(p_go, GO_POINTER) != NULL)
+ {
+ XtAddEventHandler(vimShell, LeaveWindowMask, FALSE, gui_x11_leave_cb,
+ (XtPointer)0);
+ XtAddEventHandler(textArea, LeaveWindowMask, FALSE, gui_x11_leave_cb,
+ (XtPointer)0);
+ XtAddEventHandler(textArea, EnterWindowMask, FALSE, gui_x11_enter_cb,
+ (XtPointer)0);
+ XtAddEventHandler(vimShell, EnterWindowMask, FALSE, gui_x11_enter_cb,
+ (XtPointer)0);
+ }
+
+ XtAddEventHandler(vimForm, KeyPressMask, FALSE, gui_x11_key_hit_cb,
+ (XtPointer)0);
+ XtAddEventHandler(textArea, KeyPressMask, FALSE, gui_x11_key_hit_cb,
+ (XtPointer)0);
+
+ /* get pointer moved events from scrollbar, needed for 'mousefocus' */
+ XtAddEventHandler(vimForm, PointerMotionMask,
+ FALSE, gui_x11_mouse_cb, (XtPointer)1);
+ XtAddEventHandler(textArea, ButtonPressMask | ButtonReleaseMask |
+ ButtonMotionMask | PointerMotionMask,
+ FALSE, gui_x11_mouse_cb, (XtPointer)0);
+}
+
+/*
+ * Get current mouse coordinates in text window.
+ */
+ void
+gui_mch_getmouse(int *x, int *y)
+{
+ int rootx, rooty, winx, winy;
+ Window root, child;
+ unsigned int mask;
+
+ if (gui.wid && XQueryPointer(gui.dpy, gui.wid, &root, &child,
+ &rootx, &rooty, &winx, &winy, &mask)) {
+ *x = winx;
+ *y = winy;
+ } else {
+ *x = -1;
+ *y = -1;
+ }
+}
+
+ void
+gui_mch_setmouse(int x, int y)
+{
+ if (gui.wid)
+ XWarpPointer(gui.dpy, (Window)0, gui.wid, 0, 0, 0, 0, x, y);
+}
+
+#if (defined(FEAT_GUI_MOTIF) && defined(FEAT_MENU)) || defined(PROTO)
+ XButtonPressedEvent *
+gui_x11_get_last_mouse_event(void)
+{
+ return &last_mouse_event;
+}
+#endif
+
+#if defined(FEAT_SIGN_ICONS) || defined(PROTO)
+
+/* Signs are currently always 2 chars wide. Hopefully the font is big enough
+ * to provide room for the bitmap! */
+# define SIGN_WIDTH (gui.char_width * 2)
+
+ void
+gui_mch_drawsign(int row, int col, int typenr)
+{
+ XImage *sign;
+
+ if (gui.in_use && (sign = (XImage *)sign_get_image(typenr)) != NULL)
+ {
+ XClearArea(gui.dpy, gui.wid, TEXT_X(col), TEXT_Y(row) - sign->height,
+ SIGN_WIDTH, gui.char_height, FALSE);
+ XPutImage(gui.dpy, gui.wid, gui.text_gc, sign, 0, 0,
+ TEXT_X(col) + (SIGN_WIDTH - sign->width) / 2,
+ TEXT_Y(row) - sign->height,
+ sign->width, sign->height);
+ }
+}
+
+ void *
+gui_mch_register_sign(char_u *signfile)
+{
+ XpmAttributes attrs;
+ XImage *sign = NULL;
+ int status;
+
+ /*
+ * Setup the color substitution table.
+ */
+ if (signfile[0] != NUL && signfile[0] != '-')
+ {
+ XpmColorSymbol color[5] =
+ {
+ {"none", NULL, 0},
+ {"iconColor1", NULL, 0},
+ {"bottomShadowColor", NULL, 0},
+ {"topShadowColor", NULL, 0},
+ {"selectColor", NULL, 0}
+ };
+ attrs.valuemask = XpmColorSymbols;
+ attrs.numsymbols = 2;
+ attrs.colorsymbols = color;
+ attrs.colorsymbols[0].pixel = gui.back_pixel;
+ attrs.colorsymbols[1].pixel = gui.norm_pixel;
+ status = XpmReadFileToImage(gui.dpy, (char *)signfile,
+ &sign, NULL, &attrs);
+ if (status == 0)
+ {
+ /* Sign width is fixed at two columns now.
+ if (sign->width > gui.sign_width)
+ gui.sign_width = sign->width + 8; */
+ }
+ else
+ emsg(_(e_signdata));
+ }
+
+ return (void *)sign;
+}
+
+ void
+gui_mch_destroy_sign(void *sign)
+{
+ XDestroyImage((XImage*)sign);
+}
+#endif
+
+
+#ifdef FEAT_MOUSESHAPE
+/* The last set mouse pointer shape is remembered, to be used when it goes
+ * from hidden to not hidden. */
+static int last_shape = 0;
+#endif
+
+/*
+ * Use the blank mouse pointer or not.
+ */
+ void
+gui_mch_mousehide(
+ int hide) /* TRUE = use blank ptr, FALSE = use parent ptr */
+{
+ if (gui.pointer_hidden != hide)
+ {
+ gui.pointer_hidden = hide;
+ if (hide)
+ XDefineCursor(gui.dpy, gui.wid, gui.blank_pointer);
+ else
+#ifdef FEAT_MOUSESHAPE
+ mch_set_mouse_shape(last_shape);
+#else
+ XUndefineCursor(gui.dpy, gui.wid);
+#endif
+ }
+}
+
+#if defined(FEAT_MOUSESHAPE) || defined(PROTO)
+
+/* Table for shape IDs. Keep in sync with the mshape_names[] table in
+ * misc2.c! */
+static int mshape_ids[] =
+{
+ XC_left_ptr, /* arrow */
+ 0, /* blank */
+ XC_xterm, /* beam */
+ XC_sb_v_double_arrow, /* updown */
+ XC_sizing, /* udsizing */
+ XC_sb_h_double_arrow, /* leftright */
+ XC_sizing, /* lrsizing */
+ XC_watch, /* busy */
+ XC_X_cursor, /* no */
+ XC_crosshair, /* crosshair */
+ XC_hand1, /* hand1 */
+ XC_hand2, /* hand2 */
+ XC_pencil, /* pencil */
+ XC_question_arrow, /* question */
+ XC_right_ptr, /* right-arrow */
+ XC_center_ptr, /* up-arrow */
+ XC_left_ptr /* last one */
+};
+
+ void
+mch_set_mouse_shape(int shape)
+{
+ int id;
+
+ if (!gui.in_use)
+ return;
+
+ if (shape == MSHAPE_HIDE || gui.pointer_hidden)
+ XDefineCursor(gui.dpy, gui.wid, gui.blank_pointer);
+ else
+ {
+ if (shape >= MSHAPE_NUMBERED)
+ {
+ id = shape - MSHAPE_NUMBERED;
+ if (id >= XC_num_glyphs)
+ id = XC_left_ptr;
+ else
+ id &= ~1; /* they are always even (why?) */
+ }
+ else
+ id = mshape_ids[shape];
+
+ XDefineCursor(gui.dpy, gui.wid, XCreateFontCursor(gui.dpy, id));
+ }
+ if (shape != MSHAPE_HIDE)
+ last_shape = shape;
+}
+#endif
+
+#if (defined(FEAT_TOOLBAR) && defined(FEAT_BEVAL_GUI)) || defined(PROTO)
+/*
+ * Set the balloon-eval used for the tooltip of a toolbar menu item.
+ * The check for a non-toolbar item was added, because there is a crash when
+ * passing a normal menu item here. Can't explain that, but better avoid it.
+ */
+ void
+gui_mch_menu_set_tip(vimmenu_T *menu)
+{
+ if (menu->id != NULL && menu->parent != NULL
+ && menu_is_toolbar(menu->parent->name))
+ {
+ /* Always destroy and create the balloon, in case the string was
+ * changed. */
+ if (menu->tip != NULL)
+ {
+ gui_mch_destroy_beval_area(menu->tip);
+ menu->tip = NULL;
+ }
+ if (menu->strings[MENU_INDEX_TIP] != NULL)
+ menu->tip = gui_mch_create_beval_area(
+ menu->id,
+ menu->strings[MENU_INDEX_TIP],
+ NULL,
+ NULL);
+ }
+}
+#endif
diff --git a/src/gui_x11_pm.h b/src/gui_x11_pm.h
new file mode 100644
index 0000000..24cd2ca
--- /dev/null
+++ b/src/gui_x11_pm.h
@@ -0,0 +1,92 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ * GUI/Motif support by Robert Webb
+ *
+ * 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.
+ */
+
+/*
+ * Icons used by the toolbar code.
+ */
+#include "../pixmaps/tb_new.xpm"
+#include "../pixmaps/tb_open.xpm"
+#include "../pixmaps/tb_close.xpm"
+#include "../pixmaps/tb_save.xpm"
+#include "../pixmaps/tb_print.xpm"
+#include "../pixmaps/tb_cut.xpm"
+#include "../pixmaps/tb_copy.xpm"
+#include "../pixmaps/tb_paste.xpm"
+#include "../pixmaps/tb_find.xpm"
+#include "../pixmaps/tb_find_next.xpm"
+#include "../pixmaps/tb_find_prev.xpm"
+#include "../pixmaps/tb_find_help.xpm"
+#include "../pixmaps/tb_exit.xpm"
+#include "../pixmaps/tb_undo.xpm"
+#include "../pixmaps/tb_redo.xpm"
+#include "../pixmaps/tb_help.xpm"
+#include "../pixmaps/tb_macro.xpm"
+#include "../pixmaps/tb_make.xpm"
+#include "../pixmaps/tb_save_all.xpm"
+#include "../pixmaps/tb_jump.xpm"
+#include "../pixmaps/tb_ctags.xpm"
+#include "../pixmaps/tb_load_session.xpm"
+#include "../pixmaps/tb_save_session.xpm"
+#include "../pixmaps/tb_new_session.xpm"
+#include "../pixmaps/tb_blank.xpm"
+#include "../pixmaps/tb_maximize.xpm"
+#include "../pixmaps/tb_split.xpm"
+#include "../pixmaps/tb_minimize.xpm"
+#include "../pixmaps/tb_shell.xpm"
+#include "../pixmaps/tb_replace.xpm"
+#include "../pixmaps/tb_vsplit.xpm"
+#include "../pixmaps/tb_maxwidth.xpm"
+#include "../pixmaps/tb_minwidth.xpm"
+
+/*
+ * Those are the pixmaps used for the default buttons.
+ */
+static char **(built_in_pixmaps[]) =
+{
+ tb_new_xpm,
+ tb_open_xpm,
+ tb_save_xpm,
+ tb_undo_xpm,
+ tb_redo_xpm,
+ tb_cut_xpm,
+ tb_copy_xpm,
+ tb_paste_xpm,
+ tb_print_xpm,
+ tb_help_xpm,
+ tb_find_xpm,
+ tb_save_all_xpm,
+ tb_save_session_xpm,
+ tb_new_session_xpm,
+ tb_load_session_xpm,
+ tb_macro_xpm,
+ tb_replace_xpm,
+ tb_close_xpm,
+ tb_maximize_xpm,
+ tb_minimize_xpm,
+ tb_split_xpm,
+ tb_shell_xpm,
+ tb_find_prev_xpm,
+ tb_find_next_xpm,
+ tb_find_help_xpm,
+ tb_make_xpm,
+ tb_jump_xpm,
+ tb_ctags_xpm,
+ tb_vsplit_xpm,
+ tb_maxwidth_xpm,
+ tb_minwidth_xpm,
+ tb_exit_xpm
+};
+
+/* Indices for named colors */
+#define BACKGROUND 0
+#define FOREGROUND 1
+#define BOTTOM_SHADOW 2
+#define TOP_SHADOW 3
+#define HIGHLIGHT 4
diff --git a/src/gui_xmdlg.c b/src/gui_xmdlg.c
new file mode 100644
index 0000000..01e536c
--- /dev/null
+++ b/src/gui_xmdlg.c
@@ -0,0 +1,1287 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * (C) 2001,2005 by Marcin Dalecki <martin@dalecki.de>
+ *
+ * Implementation of dialog functions for the Motif GUI variant.
+ *
+ * Note about Lesstif: Apparently lesstif doesn't get the widget layout right,
+ * when using a dynamic scrollbar policy.
+ */
+
+#include "vim.h"
+
+#include <Xm/Form.h>
+#include <Xm/PushBG.h>
+#include <Xm/Text.h>
+#include <Xm/TextF.h>
+#include <Xm/Label.h>
+#include <Xm/Frame.h>
+#include <Xm/LabelG.h>
+#include <Xm/ToggleBG.h>
+#include <Xm/SeparatoG.h>
+#include <Xm/DialogS.h>
+#include <Xm/List.h>
+#include <Xm/RowColumn.h>
+#include <Xm/AtomMgr.h>
+#include <Xm/Protocols.h>
+
+#include <X11/keysym.h>
+#include <X11/Xatom.h>
+#include <X11/StringDefs.h>
+#include <X11/Intrinsic.h>
+
+extern Widget vimShell;
+
+#ifdef FEAT_MENU
+# define apply_fontlist(w) gui_motif_menu_fontlist(w)
+#else
+# define apply_fontlist(w)
+#endif
+
+/****************************************************************************
+ * Font selection dialogue implementation.
+ */
+
+static char wild[3] = "*";
+
+/*
+ * FIXME: This is a generic function, which should be used throughout the whole
+ * application.
+ *
+ * Add close_callback, which will be called when the user selects close from
+ * the window menu. The close menu item usually activates f.kill which sends a
+ * WM_DELETE_WINDOW protocol request for the window.
+ */
+
+ static void
+add_cancel_action(Widget shell, XtCallbackProc close_callback, void *arg)
+{
+ static Atom wmp_atom = 0;
+ static Atom dw_atom = 0;
+ Display *display = XtDisplay(shell);
+
+ /* deactivate the built-in delete response of killing the application */
+ XtVaSetValues(shell, XmNdeleteResponse, XmDO_NOTHING, NULL);
+
+ /* add a delete window protocol callback instead */
+ if (!dw_atom)
+ {
+ wmp_atom = XmInternAtom(display, "WM_PROTOCOLS", True);
+ dw_atom = XmInternAtom(display, "WM_DELETE_WINDOW", True);
+ }
+ XmAddProtocolCallback(shell, wmp_atom, dw_atom, close_callback, arg);
+}
+
+#define MAX_FONTS 65535
+#define MAX_FONT_NAME_LEN 256
+#define MAX_ENTRIES_IN_LIST 5000
+#define MAX_DISPLAY_SIZE 150
+#define TEMP_BUF_SIZE 256
+
+enum ListSpecifier
+{
+ ENCODING,
+ NAME,
+ STYLE,
+ SIZE,
+ NONE
+};
+
+typedef struct _SharedFontSelData
+{
+ Widget dialog;
+ Widget ok;
+ Widget cancel;
+ Widget encoding_pulldown;
+ Widget encoding_menu;
+ Widget list[NONE];
+ Widget name;
+ Widget sample;
+ char **names; /* font name array of arrays */
+ int num; /* number of font names */
+ String sel[NONE]; /* selection category */
+ Boolean in_pixels; /* toggle state - size in pixels */
+ char *font_name; /* current font name */
+ XFontStruct *old; /* font data structure for sample display */
+ XmFontList old_list; /* font data structure for sample display */
+ Boolean exit; /* used for program exit control */
+} SharedFontSelData;
+
+/*
+ * Checking access to the font name array for validity.
+ */
+ static char *
+fn(SharedFontSelData *data, int i)
+{
+ /* Assertion checks: */
+ if (data->num < 0)
+ abort();
+ if (i >= data->num)
+ i = data->num - 1;
+ if (i < 0)
+ i = 0;
+
+ return data->names[i];
+}
+
+/*
+ * Get a specific substring from a font name.
+ */
+ static void
+get_part(char *in, int pos, char *out)
+{
+ int i;
+ int j;
+
+ *out = '\0';
+
+ for (i = 0; (pos > 0) && (in[i] != '\0'); ++i)
+ if (in[i] == '-')
+ pos--;
+
+ if (in[i] == '\0')
+ return;
+
+ for (j = 0; (in[i] != '-') && (in[i] != '\0'); ++i, ++j)
+ out[j] = in[i];
+ out[j] = '\0';
+}
+
+/*
+ * Given a font name this function returns the part used in the first
+ * scroll list.
+ */
+ static void
+name_part(char *font, char *buf)
+{
+ char buf2[TEMP_BUF_SIZE];
+ char buf3[TEMP_BUF_SIZE];
+
+ get_part(font, 2, buf2);
+ get_part(font, 1, buf3);
+
+ if (*buf3 != NUL)
+ vim_snprintf(buf, TEMP_BUF_SIZE, "%s (%s)", buf2, buf3);
+ else
+ vim_snprintf(buf, TEMP_BUF_SIZE, "%s", buf2);
+}
+
+/*
+ * Given a font name this function returns the part used in the second scroll list.
+ */
+ static void
+style_part(char *font, char *buf)
+{
+ char buf2[TEMP_BUF_SIZE];
+ char buf3[TEMP_BUF_SIZE];
+
+ get_part(font, 3, buf3);
+ get_part(font, 5, buf2);
+
+ if (!strcmp(buf2, "normal") && !strcmp(buf2, "Normal")
+ && !strcmp(buf2, "NORMAL"))
+ vim_snprintf(buf, TEMP_BUF_SIZE, "%s %s", buf3, buf2);
+ else
+ strcpy(buf, buf3);
+
+ get_part(font, 6, buf2);
+
+ if (buf2[0] != '\0')
+ vim_snprintf(buf3, TEMP_BUF_SIZE, "%s %s", buf, buf2);
+ else
+ strcpy(buf3, buf);
+
+ get_part(font, 4, buf2);
+
+ if (!strcmp(buf2, "o") || !strcmp(buf2, "O"))
+ vim_snprintf(buf, TEMP_BUF_SIZE, "%s oblique", buf3);
+ else if (!strcmp(buf2, "i") || !strcmp(buf2, "I"))
+ vim_snprintf(buf, TEMP_BUF_SIZE, "%s italic", buf3);
+
+ if (!strcmp(buf, " "))
+ strcpy(buf, "-");
+}
+
+/*
+ * Given a font name this function returns the part used in the third
+ * scroll list.
+ */
+ static void
+size_part(char *font, char *buf, int inPixels)
+{
+ int size;
+ float temp;
+
+ *buf = '\0';
+
+ if (inPixels)
+ {
+ get_part(font, 7, buf);
+ if (*buf != NUL)
+ {
+ size = atoi(buf);
+ sprintf(buf, "%3d", size);
+ }
+ }
+ else
+ {
+ get_part(font, 8, buf);
+ if (*buf != NUL)
+ {
+ size = atoi(buf);
+ temp = (float)size / 10.0;
+ size = temp;
+ if (buf[strlen(buf) - 1] == '0')
+ sprintf(buf, "%3d", size);
+ else
+ sprintf(buf, "%4.1f", temp);
+ }
+ }
+}
+
+/*
+ * Given a font name this function returns the part used in the choice menu.
+ */
+ static void
+encoding_part(char *font, char *buf)
+{
+ char buf1[TEMP_BUF_SIZE];
+ char buf2[TEMP_BUF_SIZE];
+
+ *buf = '\0';
+
+ get_part(font, 13, buf1);
+ get_part(font, 14, buf2);
+
+ if (*buf1 != NUL && *buf2 != NUL)
+ vim_snprintf(buf, TEMP_BUF_SIZE, "%s-%s", buf1, buf2);
+ if (!strcmp(buf, " "))
+ strcpy(buf, "-");
+}
+
+/*
+ * Inserts a string into correct sorted position in a list.
+ */
+ static void
+add_to_list(char **buf, char *item, int *count)
+{
+ int i;
+ int j;
+
+ if (*count == MAX_ENTRIES_IN_LIST)
+ return;
+
+ /* avoid duplication */
+ for (i = 0; i < *count; ++i)
+ {
+ if (!strcmp(buf[i], item))
+ return;
+ }
+
+ /* find order place, but make sure that wild card comes first */
+ if (!strcmp(item, wild))
+ i = 0;
+ else
+ for (i = 0; i < *count; ++i)
+ if (strcmp(buf[i], item) > 0 && strcmp(buf[i], wild))
+ break;
+
+ /* now insert the item */
+ for (j = *count; j > i; --j)
+ buf[j] = buf[j-1];
+ buf[i] = XtNewString(item);
+
+ ++(*count);
+}
+
+/*
+ * True if the font matches some field.
+ */
+ static Boolean
+match(SharedFontSelData *data, enum ListSpecifier l, int i)
+{
+ char buf[TEMP_BUF_SIZE];
+
+ /* An empty selection or a wild card matches anything.
+ */
+ if (!data->sel[l] || !strcmp(data->sel[l], wild))
+ return True;
+
+ /* chunk out the desired part... */
+ switch (l)
+ {
+ case ENCODING:
+ encoding_part(fn(data, i), buf);
+ break;
+
+ case NAME:
+ name_part(fn(data, i), buf);
+ break;
+
+ case STYLE:
+ style_part(fn(data, i), buf);
+ break;
+
+ case SIZE:
+ size_part(fn(data, i), buf, data->in_pixels);
+ break;
+ default:
+ ;
+ }
+
+ /* ...and chew it now */
+
+ return !strcmp(buf, data->sel[l]);
+}
+
+ static Boolean
+proportional(char *font)
+{
+ char buf[TEMP_BUF_SIZE];
+
+ get_part(font, 11, buf);
+
+ return !strcmp(buf, "p") || !strcmp(buf, "P");
+}
+
+
+static void encoding_callback(Widget w, SharedFontSelData *data,
+ XtPointer dummy);
+
+/*
+ * Parse through the fontlist data and set up the three scroll lists. The fix
+ * parameter can be used to exclude a list from any changes. This is used for
+ * updates after selections caused by the users actions.
+ */
+ static void
+fill_lists(enum ListSpecifier fix, SharedFontSelData *data)
+{
+ char *list[NONE][MAX_ENTRIES_IN_LIST];
+ int count[NONE];
+ char buf[TEMP_BUF_SIZE];
+ XmString items[MAX_ENTRIES_IN_LIST];
+ int i;
+ int idx;
+
+ for (idx = (int)ENCODING; idx < (int)NONE; ++idx)
+ count[idx] = 0;
+
+ /* First we insert the wild char into every single list. */
+ if (fix != ENCODING)
+ add_to_list(list[ENCODING], wild, &count[ENCODING]);
+ if (fix != NAME)
+ add_to_list(list[NAME], wild, &count[NAME]);
+ if (fix != STYLE)
+ add_to_list(list[STYLE], wild, &count[STYLE]);
+ if (fix != SIZE)
+ add_to_list(list[SIZE], wild, &count[SIZE]);
+
+ for (i = 0; i < data->num && i < MAX_ENTRIES_IN_LIST; i++)
+ {
+ if (proportional(fn(data, i)))
+ continue;
+
+ if (fix != ENCODING
+ && match(data, NAME, i)
+ && match(data, STYLE, i)
+ && match(data, SIZE, i))
+ {
+ encoding_part(fn(data, i), buf);
+ add_to_list(list[ENCODING], buf, &count[ENCODING]);
+ }
+
+ if (fix != NAME
+ && match(data, ENCODING, i)
+ && match(data, STYLE, i)
+ && match(data, SIZE, i))
+ {
+ name_part(fn(data, i), buf);
+ add_to_list(list[NAME], buf, &count[NAME]);
+ }
+
+ if (fix != STYLE
+ && match(data, ENCODING, i)
+ && match(data, NAME, i)
+ && match(data, SIZE, i))
+ {
+ style_part(fn(data, i), buf);
+ add_to_list(list[STYLE], buf, &count[STYLE]);
+ }
+
+ if (fix != SIZE
+ && match(data, ENCODING, i)
+ && match(data, NAME, i)
+ && match(data, STYLE, i))
+ {
+ size_part(fn(data, i), buf, data->in_pixels);
+ add_to_list(list[SIZE], buf, &count[SIZE]);
+ }
+ }
+
+ /*
+ * And now do the preselection in all lists where there was one:
+ */
+
+ if (fix != ENCODING)
+ {
+ Cardinal n_items;
+ WidgetList children;
+ Widget selected_button = 0;
+
+ /* Get and update the current button list. */
+ XtVaGetValues(data->encoding_pulldown,
+ XmNchildren, &children,
+ XmNnumChildren, &n_items,
+ NULL);
+
+ for (i = 0; i < count[ENCODING]; ++i)
+ {
+ Widget button;
+
+ items[i] = XmStringCreateLocalized(list[ENCODING][i]);
+
+ if (i < (int)n_items)
+ {
+ /* recycle old button */
+ XtVaSetValues(children[i],
+ XmNlabelString, items[i],
+ XmNuserData, i,
+ NULL);
+ button = children[i];
+ }
+ else
+ {
+ /* create a new button */
+ button = XtVaCreateManagedWidget("button",
+ xmPushButtonGadgetClass,
+ data->encoding_pulldown,
+ XmNlabelString, items[i],
+ XmNuserData, i,
+ NULL);
+ XtAddCallback(button, XmNactivateCallback,
+ (XtCallbackProc) encoding_callback, (XtPointer) data);
+ XtManageChild(button);
+ }
+
+ if (data->sel[ENCODING])
+ {
+ if (!strcmp(data->sel[ENCODING], list[ENCODING][i]))
+ selected_button = button;
+ }
+ XtFree(list[ENCODING][i]);
+ }
+
+ /* Destroy all the outstanding menu items.
+ */
+ for (i = count[ENCODING]; i < (int)n_items; ++i)
+ {
+ XtUnmanageChild(children[i]);
+ XtDestroyWidget(children[i]);
+ }
+
+ /* Preserve the current selection visually.
+ */
+ if (selected_button)
+ {
+ XtVaSetValues(data->encoding_menu,
+ XmNmenuHistory, selected_button,
+ NULL);
+ }
+
+ for (i = 0; i < count[ENCODING]; ++i)
+ XmStringFree(items[i]);
+ }
+
+ /*
+ * Now loop trough the remaining lists and set them up.
+ */
+ for (idx = (int)NAME; idx < (int)NONE; ++idx)
+ {
+ Widget w;
+
+ if (fix == (enum ListSpecifier)idx)
+ continue;
+
+ switch ((enum ListSpecifier)idx)
+ {
+ case NAME:
+ w = data->list[NAME];
+ break;
+ case STYLE:
+ w = data->list[STYLE];
+ break;
+ case SIZE:
+ w = data->list[SIZE];
+ break;
+ default:
+ w = (Widget)0; /* for lint */
+ }
+
+ for (i = 0; i < count[idx]; ++i)
+ {
+ items[i] = XmStringCreateLocalized(list[idx][i]);
+ XtFree(list[idx][i]);
+ }
+ XmListDeleteAllItems(w);
+ XmListAddItems(w, items, count[idx], 1);
+ if (data->sel[idx])
+ {
+ XmStringFree(items[0]);
+ items[0] = XmStringCreateLocalized(data->sel[idx]);
+ XmListSelectItem(w, items[0], False);
+ XmListSetBottomItem(w, items[0]);
+ }
+ for (i = 0; i < count[idx]; ++i)
+ XmStringFree(items[i]);
+ }
+}
+
+ static void
+stoggle_callback(Widget w UNUSED,
+ SharedFontSelData *data,
+ XmToggleButtonCallbackStruct *call_data)
+{
+ int i, do_sel;
+ char newSize[TEMP_BUF_SIZE];
+ XmString str;
+
+ if (call_data->reason != (int)XmCR_VALUE_CHANGED)
+ return;
+
+ do_sel = (data->sel[SIZE] != NULL) && strcmp(data->sel[SIZE], wild);
+
+ for (i = 0; do_sel && (i < data->num); i++)
+ if (match(data, ENCODING, i)
+ && match(data, NAME, i)
+ && match(data, STYLE, i)
+ && match(data, SIZE, i))
+ {
+ size_part(fn(data, i), newSize, !data->in_pixels);
+ break;
+ }
+
+ data->in_pixels = !data->in_pixels;
+
+ if (data->sel[SIZE])
+ XtFree(data->sel[SIZE]);
+ data->sel[SIZE] = NULL;
+ fill_lists(NONE, data);
+
+ if (do_sel)
+ {
+ str = XmStringCreateLocalized(newSize);
+ XmListSelectItem(data->list[SIZE], str, True);
+ XmListSetBottomItem(data->list[SIZE], str);
+ XmStringFree(str);
+ }
+}
+
+/*
+ * Show the currently selected font in the sample text label.
+ */
+ static void
+display_sample(SharedFontSelData *data)
+{
+ Arg args[2];
+ int n;
+ XFontStruct * font;
+ XmFontList font_list;
+ Display * display;
+ XmString str;
+
+ display = XtDisplay(data->dialog);
+ font = XLoadQueryFont(display, data->font_name);
+ font_list = gui_motif_create_fontlist(font);
+
+ n = 0;
+ str = XmStringCreateLocalized("AaBbZzYy 0123456789");
+ XtSetArg(args[n], XmNlabelString, str); n++;
+ XtSetArg(args[n], XmNfontList, font_list); n++;
+
+ XtSetValues(data->sample, args, n);
+ XmStringFree(str);
+
+ if (data->old)
+ {
+ XFreeFont(display, data->old);
+ XmFontListFree(data->old_list);
+ }
+ data->old = font;
+ data->old_list = font_list;
+}
+
+
+ static Boolean
+do_choice(Widget w,
+ SharedFontSelData *data,
+ XmListCallbackStruct *call_data,
+ enum ListSpecifier which)
+{
+ char *sel;
+
+ XmStringGetLtoR(call_data->item, XmSTRING_DEFAULT_CHARSET, &sel);
+
+ if (!data->sel[which])
+ data->sel[which] = XtNewString(sel);
+ else
+ {
+ if (!strcmp(data->sel[which], sel))
+ {
+ /* unselecting current selection */
+ XtFree(data->sel[which]);
+ data->sel[which] = NULL;
+ if (w)
+ XmListDeselectItem(w, call_data->item);
+ }
+ else
+ {
+ XtFree(data->sel[which]);
+ data->sel[which] = XtNewString(sel);
+ }
+ }
+ XtFree(sel);
+
+ fill_lists(which, data);
+
+ /* If there is a font selection, we display it. */
+ if (data->sel[ENCODING]
+ && data->sel[NAME]
+ && data->sel[STYLE]
+ && data->sel[SIZE]
+ && strcmp(data->sel[ENCODING], wild)
+ && strcmp(data->sel[NAME], wild)
+ && strcmp(data->sel[STYLE], wild)
+ && strcmp(data->sel[SIZE], wild))
+ {
+ int i;
+
+ if (data->font_name)
+ XtFree(data->font_name);
+ data->font_name = NULL;
+
+ for (i = 0; i < data->num; i++)
+ {
+ if (match(data, ENCODING, i)
+ && match(data, NAME, i)
+ && match(data, STYLE, i)
+ && match(data, SIZE, i))
+ {
+ data->font_name = XtNewString(fn(data, i));
+ break;
+ }
+ }
+
+ if (data->font_name)
+ {
+ XmTextSetString(data->name, data->font_name);
+ display_sample(data);
+ }
+ else
+ do_dialog(VIM_ERROR,
+ (char_u *)_("Error"),
+ (char_u *)_("Invalid font specification"),
+ (char_u *)_("&Dismiss"), 1, NULL, FALSE);
+
+ return True;
+ }
+ else
+ {
+ int n;
+ XmString str;
+ Arg args[4];
+ char *nomatch_msg = _("no specific match");
+
+ n = 0;
+ str = XmStringCreateLocalized(nomatch_msg);
+ XtSetArg(args[n], XmNlabelString, str); ++n;
+ XtSetValues(data->sample, args, n);
+ apply_fontlist(data->sample);
+ XmTextSetString(data->name, nomatch_msg);
+ XmStringFree(str);
+
+ return False;
+ }
+}
+
+ static void
+encoding_callback(Widget w,
+ SharedFontSelData *data,
+ XtPointer dummy UNUSED)
+{
+ XmString str;
+ XmListCallbackStruct fake_data;
+
+ XtVaGetValues(w, XmNlabelString, &str, NULL);
+
+ if (!str)
+ return;
+
+ fake_data.item = str;
+
+ do_choice(0, data, &fake_data, ENCODING);
+}
+
+ static void
+name_callback(Widget w,
+ SharedFontSelData *data,
+ XmListCallbackStruct *call_data)
+{
+ do_choice(w, data, call_data, NAME);
+}
+
+ static void
+style_callback(Widget w,
+ SharedFontSelData *data,
+ XmListCallbackStruct *call_data)
+{
+ do_choice(w, data, call_data, STYLE);
+}
+
+ static void
+size_callback(Widget w,
+ SharedFontSelData *data,
+ XmListCallbackStruct *call_data)
+{
+ do_choice(w, data, call_data, SIZE);
+}
+
+ static void
+cancel_callback(Widget w UNUSED,
+ SharedFontSelData *data,
+ XmListCallbackStruct *call_data UNUSED)
+{
+ if (data->sel[ENCODING])
+ {
+ XtFree(data->sel[ENCODING]);
+ data->sel[ENCODING] = NULL;
+ }
+ if (data->sel[NAME])
+ {
+ XtFree(data->sel[NAME]);
+ data->sel[NAME] = NULL;
+ }
+ if (data->sel[STYLE])
+ {
+ XtFree(data->sel[STYLE]);
+ data->sel[STYLE] = NULL;
+ }
+ if (data->sel[SIZE])
+ {
+ XtFree(data->sel[SIZE]);
+ data->sel[SIZE] = NULL;
+ }
+
+ if (data->font_name)
+ XtFree(data->font_name);
+ data->font_name = NULL;
+
+ data->num = 0;
+ XFreeFontNames(data->names);
+ data->names = NULL;
+ data->exit = True;
+}
+
+ static void
+ok_callback(Widget w UNUSED,
+ SharedFontSelData *data,
+ XmPushButtonCallbackStruct *call_data UNUSED)
+{
+ char *pattern;
+ char **name;
+ int i;
+
+ pattern = XmTextGetString(data->name);
+ name = XListFonts(XtDisplay(data->dialog), pattern, 1, &i);
+ XtFree(pattern);
+
+ if (i != 1)
+ {
+ do_dialog(VIM_ERROR,
+ (char_u *)_("Error"),
+ (char_u *)_("Invalid font specification"),
+ (char_u *)_("&Dismiss"), 1, NULL, FALSE);
+ XFreeFontNames(name);
+ }
+ else
+ {
+ if (data->font_name)
+ XtFree(data->font_name);
+ data->font_name = XtNewString(name[0]);
+
+ if (data->sel[ENCODING])
+ {
+ XtFree(data->sel[ENCODING]);
+ data->sel[ENCODING] = NULL;
+ }
+ if (data->sel[NAME])
+ {
+ XtFree(data->sel[NAME]);
+ data->sel[NAME] = NULL;
+ }
+ if (data->sel[STYLE])
+ {
+ XtFree(data->sel[STYLE]);
+ data->sel[STYLE] = NULL;
+ }
+ if (data->sel[SIZE])
+ {
+ XtFree(data->sel[SIZE]);
+ data->sel[SIZE] = NULL;
+ }
+
+ XFreeFontNames(name);
+
+ data->num = 0;
+ XFreeFontNames(data->names);
+ data->names = NULL;
+ data->exit = True;
+ }
+}
+
+/*
+ * Returns pointer to an ASCII character string that contains the name of the
+ * selected font (in X format for naming fonts); it is the users responsibility
+ * to free the space allocated to this string.
+ */
+ char_u *
+gui_xm_select_font(char_u *current)
+{
+ static SharedFontSelData _data;
+
+ Widget parent;
+ Widget form;
+ Widget separator;
+ Widget sub_form;
+ Widget size_toggle;
+ Widget name;
+ Widget disp_frame;
+ Widget frame;
+ Arg args[64];
+ int n;
+ XmString str;
+ char big_font[MAX_FONT_NAME_LEN];
+ SharedFontSelData *data;
+
+ data = &_data;
+
+ parent = vimShell;
+ data->names = XListFonts(XtDisplay(parent), "-*-*-*-*-*-*-*-*-*-*-*-*-*-*",
+ MAX_FONTS, &data->num);
+
+ /*
+ * Find the name of the biggest font less than the given limit
+ * MAX_DISPLAY_SIZE used to set up the initial height of the display
+ * widget.
+ */
+
+ {
+ int i;
+ int max;
+ int idx = 0;
+ int size;
+ char buf[128];
+
+ for (i = 0, max = 0; i < data->num; i++)
+ {
+ get_part(fn(data, i), 7, buf);
+ size = atoi(buf);
+ if ((size > max) && (size < MAX_DISPLAY_SIZE))
+ {
+ idx = i;
+ max = size;
+ }
+ }
+ strcpy(big_font, fn(data, idx));
+ }
+ data->old = XLoadQueryFont(XtDisplay(parent), big_font);
+ data->old_list = gui_motif_create_fontlist(data->old);
+
+ /* Set the title of the Dialog window. */
+ data->dialog = XmCreateDialogShell(parent, "fontSelector", NULL, 0);
+ str = XmStringCreateLocalized(_("Vim - Font Selector"));
+
+ /* Create form popup dialog widget. */
+ form = XtVaCreateWidget("form",
+ xmFormWidgetClass, data->dialog,
+ XmNdialogTitle, str,
+ XmNautoUnmanage, False,
+ XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL,
+ NULL);
+ XmStringFree(str);
+
+ sub_form = XtVaCreateManagedWidget("subForm",
+ xmFormWidgetClass, form,
+ XmNbottomAttachment, XmATTACH_FORM,
+ XmNbottomOffset, 4,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNrightOffset, 4,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNtopOffset, 4,
+ XmNorientation, XmVERTICAL,
+ NULL);
+
+ data->ok = XtVaCreateManagedWidget(_("OK"),
+ xmPushButtonGadgetClass, sub_form,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNtopOffset, 4,
+ NULL);
+ apply_fontlist(data->ok);
+
+ data->cancel = XtVaCreateManagedWidget(_("Cancel"),
+ xmPushButtonGadgetClass, sub_form,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, data->ok,
+ XmNtopOffset, 4,
+ XmNshowAsDefault, True,
+ NULL);
+ apply_fontlist(data->cancel);
+
+ /* Create the separator for beauty. */
+ n = 0;
+ XtSetArg(args[n], XmNorientation, XmVERTICAL); n++;
+ XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
+ XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
+ XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
+ XtSetArg(args[n], XmNrightWidget, sub_form); n++;
+ XtSetArg(args[n], XmNrightOffset, 4); n++;
+ separator = XmCreateSeparatorGadget(form, "separator", args, n);
+ XtManageChild(separator);
+
+ /* Create font name text widget and the corresponding label. */
+ data->name = XtVaCreateManagedWidget("fontName",
+ xmTextWidgetClass, form,
+ XmNbottomAttachment, XmATTACH_FORM,
+ XmNbottomOffset, 4,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNleftOffset, 4,
+ XmNrightAttachment, XmATTACH_WIDGET,
+ XmNrightWidget, separator,
+ XmNrightOffset, 4,
+ XmNeditable, False,
+ XmNeditMode, XmSINGLE_LINE_EDIT,
+ XmNmaxLength, MAX_FONT_NAME_LEN,
+ XmNcolumns, 60,
+ NULL);
+
+ str = XmStringCreateLocalized(_("Name:"));
+ name = XtVaCreateManagedWidget("fontNameLabel",
+ xmLabelGadgetClass, form,
+ XmNlabelString, str,
+ XmNuserData, data->name,
+ XmNleftAttachment, XmATTACH_OPPOSITE_WIDGET,
+ XmNleftWidget, data->name,
+ XmNbottomAttachment, XmATTACH_WIDGET,
+ XmNbottomWidget, data->name,
+ XmNtopOffset, 1,
+ NULL);
+ XmStringFree(str);
+ apply_fontlist(name);
+
+ /* create sample display label widget */
+ disp_frame = XtVaCreateManagedWidget("sampleFrame",
+ xmFrameWidgetClass, form,
+ XmNshadowType, XmSHADOW_ETCHED_IN,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNleftOffset, 4,
+ XmNbottomAttachment, XmATTACH_WIDGET,
+ XmNbottomWidget, name,
+ XmNrightAttachment, XmATTACH_WIDGET,
+ XmNrightWidget, separator,
+ XmNrightOffset, 4,
+ XmNalignment, XmALIGNMENT_BEGINNING,
+ NULL);
+
+ data->sample = XtVaCreateManagedWidget("sampleLabel",
+ xmLabelWidgetClass, disp_frame,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNalignment, XmALIGNMENT_BEGINNING,
+ XmNrecomputeSize, False,
+ XmNfontList, data->old_list,
+ NULL);
+
+ /* create toggle button */
+ str = XmStringCreateLocalized(_("Show size in Points"));
+ size_toggle = XtVaCreateManagedWidget("sizeToggle",
+ xmToggleButtonGadgetClass, form,
+ XmNlabelString, str,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNleftOffset, 4,
+ XmNbottomAttachment, XmATTACH_WIDGET,
+ XmNbottomWidget, disp_frame,
+ XmNbottomOffset, 4,
+ NULL);
+ XmStringFree(str);
+ apply_fontlist(size_toggle);
+ XtManageChild(size_toggle);
+
+ /* Encoding pulldown menu.
+ */
+
+ data->encoding_pulldown = XmCreatePulldownMenu(form,
+ "encodingPulldown", NULL, 0);
+ str = XmStringCreateLocalized(_("Encoding:"));
+ n = 0;
+ XtSetArg(args[n], XmNsubMenuId, data->encoding_pulldown); ++n;
+ XtSetArg(args[n], XmNlabelString, str); ++n;
+ XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); ++n;
+ XtSetArg(args[n], XmNleftOffset, 4); ++n;
+ XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); ++n;
+ XtSetArg(args[n], XmNbottomWidget, size_toggle); ++n;
+ XtSetArg(args[n], XmNbottomOffset, 4); ++n;
+ XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); ++n;
+ XtSetArg(args[n], XmNrightWidget, separator); ++n;
+ XtSetArg(args[n], XmNrightOffset, 4); ++n;
+ data->encoding_menu = XmCreateOptionMenu(form, "encodingMenu", args, n);
+ XmStringFree(str);
+ XmAddTabGroup(data->encoding_menu);
+
+ /*
+ * Create scroll list widgets in a separate subform used to manage the
+ * different sizes of the lists.
+ */
+
+ sub_form = XtVaCreateManagedWidget("subForm",
+ xmFormWidgetClass, form,
+ XmNbottomAttachment, XmATTACH_WIDGET,
+ XmNbottomWidget, data->encoding_menu,
+ XmNbottomOffset, 4,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNleftOffset, 4,
+ XmNrightAttachment, XmATTACH_WIDGET,
+ XmNrightWidget, separator,
+ XmNrightOffset, 4,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNtopOffset, 2,
+ XmNorientation, XmVERTICAL,
+ NULL);
+
+ /* font list */
+ frame = XtVaCreateManagedWidget("frame", xmFrameWidgetClass, sub_form,
+ XmNshadowThickness, 0,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_POSITION,
+ XmNrightPosition, 50,
+ NULL);
+
+ str = XmStringCreateLocalized(_("Font:"));
+ name = XtVaCreateManagedWidget("nameListLabel", xmLabelGadgetClass, frame,
+ XmNchildType, XmFRAME_TITLE_CHILD,
+ XmNchildVerticalAlignment, XmALIGNMENT_CENTER,
+ XmNchildHorizontalAlignment, XmALIGNMENT_BEGINNING,
+ XmNlabelString, str,
+ NULL);
+ XmStringFree(str);
+ apply_fontlist(name);
+
+ n = 0;
+ XtSetArg(args[n], XmNvisibleItemCount, 8); ++n;
+ XtSetArg(args[n], XmNresizable, True); ++n;
+ XtSetArg(args[n], XmNlistSizePolicy, XmCONSTANT); ++n;
+ XtSetArg(args[n], XmNvisualPolicy, XmVARIABLE); ++n;
+#ifdef LESSTIF_VERSION
+ XtSetArg(args[n], XmNscrollBarDisplayPolicy, XmSTATIC); ++n;
+#endif
+ data->list[NAME] = XmCreateScrolledList(frame, "fontList", args, n);
+ XtVaSetValues(name, XmNuserData, data->list[NAME], NULL);
+
+ /* style list */
+ frame = XtVaCreateManagedWidget("frame", xmFrameWidgetClass, sub_form,
+ XmNshadowThickness, 0,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_POSITION,
+ XmNleftPosition, 50,
+ XmNleftOffset, 4,
+ XmNrightAttachment, XmATTACH_POSITION,
+ XmNrightPosition, 80,
+ NULL);
+
+ str = XmStringCreateLocalized(_("Style:"));
+ name = XtVaCreateManagedWidget("styleListLabel", xmLabelWidgetClass, frame,
+ XmNchildType, XmFRAME_TITLE_CHILD,
+ XmNchildVerticalAlignment, XmALIGNMENT_CENTER,
+ XmNchildHorizontalAlignment, XmALIGNMENT_BEGINNING,
+ XmNlabelString, str,
+ NULL);
+ XmStringFree(str);
+ apply_fontlist(name);
+
+ n = 0;
+ XtSetArg(args[n], XmNvisibleItemCount, 8); ++n;
+ XtSetArg(args[n], XmNresizable, True); ++n;
+ XtSetArg(args[n], XmNlistSizePolicy, XmCONSTANT); ++n;
+ XtSetArg(args[n], XmNvisualPolicy, XmVARIABLE); ++n;
+#ifdef LESSTIF_VERSION
+ XtSetArg(args[n], XmNscrollBarDisplayPolicy, XmSTATIC); ++n;
+#endif
+ data->list[STYLE] = XmCreateScrolledList(frame, "styleList", args, n);
+ XtVaSetValues(name, XmNuserData, data->list[STYLE], NULL);
+
+ /* size list */
+ frame = XtVaCreateManagedWidget("frame", xmFrameWidgetClass, sub_form,
+ XmNshadowThickness, 0,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_POSITION,
+ XmNleftPosition, 80,
+ XmNleftOffset, 4,
+ XmNrightAttachment, XmATTACH_FORM,
+ NULL);
+
+ str = XmStringCreateLocalized(_("Size:"));
+ name = XtVaCreateManagedWidget("sizeListLabel", xmLabelGadgetClass, frame,
+ XmNchildType, XmFRAME_TITLE_CHILD,
+ XmNchildVerticalAlignment, XmALIGNMENT_CENTER,
+ XmNchildHorizontalAlignment, XmALIGNMENT_BEGINNING,
+ XmNlabelString, str,
+ NULL);
+ XmStringFree(str);
+ apply_fontlist(name);
+
+ n = 0;
+ XtSetArg(args[n], XmNvisibleItemCount, 8); ++n;
+ XtSetArg(args[n], XmNresizable, True); ++n;
+ XtSetArg(args[n], XmNlistSizePolicy, XmCONSTANT); ++n;
+ XtSetArg(args[n], XmNvisualPolicy, XmVARIABLE); ++n;
+#ifdef LESSTIF_VERSION
+ XtSetArg(args[n], XmNscrollBarDisplayPolicy, XmSTATIC); ++n;
+#endif
+ data->list[SIZE] = XmCreateScrolledList(frame, "sizeList", args, n);
+ XtVaSetValues(name, XmNuserData, data->list[SIZE], NULL);
+
+ /* update form widgets cancel button */
+ XtVaSetValues(form, XmNcancelButton, data->cancel, NULL);
+
+ XtAddCallback(size_toggle, XmNvalueChangedCallback,
+ (XtCallbackProc)stoggle_callback, (XtPointer)data);
+ XtAddCallback(data->list[NAME], XmNbrowseSelectionCallback,
+ (XtCallbackProc)name_callback, (XtPointer)data);
+ XtAddCallback(data->list[STYLE], XmNbrowseSelectionCallback,
+ (XtCallbackProc)style_callback, (XtPointer)data);
+ XtAddCallback(data->list[SIZE], XmNbrowseSelectionCallback,
+ (XtCallbackProc)size_callback, (XtPointer)data);
+ XtAddCallback(data->ok, XmNactivateCallback,
+ (XtCallbackProc)ok_callback, (XtPointer)data);
+ XtAddCallback(data->cancel, XmNactivateCallback,
+ (XtCallbackProc)cancel_callback, (XtPointer)data);
+
+ XmProcessTraversal(data->list[NAME], XmTRAVERSE_CURRENT);
+
+ /* setup tabgroups */
+
+ XmAddTabGroup(data->list[NAME]);
+ XmAddTabGroup(data->list[STYLE]);
+ XmAddTabGroup(data->list[SIZE]);
+ XmAddTabGroup(size_toggle);
+ XmAddTabGroup(data->name);
+ XmAddTabGroup(data->ok);
+ XmAddTabGroup(data->cancel);
+
+ add_cancel_action(data->dialog, (XtCallbackProc)cancel_callback, data);
+
+ /* Preset selection data. */
+
+ data->exit = False;
+ data->in_pixels= True;
+ data->sel[ENCODING] = NULL;
+ data->sel[NAME] = NULL;
+ data->sel[STYLE] = NULL;
+ data->sel[SIZE] = NULL;
+ data->font_name = NULL;
+
+ /* set up current font parameters */
+ if (current && current[0] != '\0')
+ {
+ int i;
+ char **names;
+
+ names = XListFonts(XtDisplay(form), (char *) current, 1, &i);
+
+ if (i != 0)
+ {
+ char namebuf[TEMP_BUF_SIZE];
+ char stylebuf[TEMP_BUF_SIZE];
+ char sizebuf[TEMP_BUF_SIZE];
+ char encodingbuf[TEMP_BUF_SIZE];
+ char *found;
+
+ found = names[0];
+
+ name_part(found, namebuf);
+ style_part(found, stylebuf);
+ size_part(found, sizebuf, data->in_pixels);
+ encoding_part(found, encodingbuf);
+
+ if (*namebuf != NUL
+ && *stylebuf != NUL
+ && *sizebuf != NUL
+ && *encodingbuf != NUL)
+ {
+ data->sel[NAME] = XtNewString(namebuf);
+ data->sel[STYLE] = XtNewString(stylebuf);
+ data->sel[SIZE] = XtNewString(sizebuf);
+ data->sel[ENCODING] = XtNewString(encodingbuf);
+ data->font_name = XtNewString(names[0]);
+ display_sample(data);
+ XmTextSetString(data->name, data->font_name);
+ }
+ else
+ {
+ /* We can't preset a symbolic name, which isn't a full font
+ * description. Therefore we just behave the same way as if the
+ * user didn't have selected anything thus far.
+ *
+ * Unfortunately there is no known way to expand an abbreviated
+ * font name.
+ */
+
+ data->font_name = NULL;
+ }
+ }
+ XFreeFontNames(names);
+ }
+
+ fill_lists(NONE, data);
+
+ /* Unfortunately LessTif doesn't align the list widget's properly. I don't
+ * have currently any idea how to fix this problem.
+ */
+ XtManageChild(data->list[NAME]);
+ XtManageChild(data->list[STYLE]);
+ XtManageChild(data->list[SIZE]);
+ XtManageChild(data->encoding_menu);
+ manage_centered(form);
+
+ /* modal event loop */
+ while (!data->exit)
+ XtAppProcessEvent(XtWidgetToApplicationContext(data->dialog),
+ (XtInputMask)XtIMAll);
+
+ if (data->old)
+ {
+ XFreeFont(XtDisplay(data->dialog), data->old);
+ XmFontListFree(data->old_list);
+ }
+ XtDestroyWidget(data->dialog);
+
+ gui_motif_synch_fonts();
+
+ return (char_u *) data->font_name;
+}
diff --git a/src/gui_xmebw.c b/src/gui_xmebw.c
new file mode 100644
index 0000000..cd60794
--- /dev/null
+++ b/src/gui_xmebw.c
@@ -0,0 +1,1450 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+/*
+ *
+ * (C) 2002,2005 by Marcin Dalecki <martin@dalecki.de>
+ *
+ * MARCIN DALECKI ASSUMES NO RESPONSIBILITY FOR THE USE OR INABILITY TO USE ANY
+ * OF THIS SOFTWARE . THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
+ * KIND, AND MARCIN DALECKI EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES,
+ * INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/*
+ * Enhanced Motif PushButton widget with move over behavior.
+ */
+
+#include "vim.h"
+
+#ifdef FEAT_TOOLBAR
+
+#include <Xm/XmP.h>
+#include <Xm/DrawP.h>
+#if defined(HAVE_XM_TRAITP_H) && defined(HAVE_XM_MANAGER_H) \
+ && defined(HAVE_XM_UNHIGHLIGHTT_H) && defined(HAVE_XM_XPMP_H)
+# include <Xm/TraitP.h>
+# include <Xm/Manager.h>
+# include <Xm/UnhighlightT.h>
+# include <Xm/XpmP.h>
+# define UNHIGHLIGHTT
+#else
+# ifdef HAVE_X11_XPM_H
+# ifdef VMS
+# include <xpm.h>
+# else
+# include <X11/xpm.h>
+# endif
+# endif
+#endif
+#include <Xm/ManagerP.h>
+#include <Xm/Display.h>
+#include <Xm/DisplayP.h>
+
+#include <X11/Shell.h>
+#include <X11/ShellP.h>
+
+#include "gui_xmebwp.h"
+
+/* Provide some missing wrappers, which are missed from the LessTif
+ * implementation. Also missing in Motif 1.2 and earlier.
+ *
+ * We neither use XmeGetPixmapData or _XmGetPixmapData, since with LessTif the
+ * pixmap will not appear in its caches properly. We cache the interesting
+ * values in XmEnhancedButtonPart instead ourself.
+ */
+#if defined(LESSTIF_VERSION) || (XmVersion <= 1002)
+# ifndef Lab_IsMenupane
+# define Lab_IsMenupane(w) (Lab_MenuType(w) == (int)XmMENU_POPUP || \
+ Lab_MenuType(w) == (int)XmMENU_PULLDOWN)
+# endif
+# define XmeClearBorder _XmClearBorder
+# define XmeDrawShadows _XmDrawShadows
+# define XmeDrawHighlight(a, b, c, d, e, f, g, h) \
+ _XmDrawHighlight(a, b, c, d, e, f, g, h, LineSolid)
+#endif
+
+/*
+ * Motif internals we have to cheat around with.
+ */
+
+/* Hopefully this will never change... */
+#ifndef XmFOCUS_IGNORE
+# define XmFOCUS_IGNORE 1<<1
+#endif
+
+extern Boolean _XmGetInDragMode(Widget widget);
+extern void _XmPrimitiveEnter(Widget wid,
+ XEvent * event,
+ String * params, Cardinal * num_params);
+extern void _XmPrimitiveLeave(Widget wid,
+ XEvent * event,
+ String * params, Cardinal * num_params);
+extern void _XmSetFocusFlag(Widget w, unsigned int mask, Boolean value);
+extern void _XmCalcLabelDimensions(Widget wid);
+
+/*
+ * Declaration of class methods.
+ */
+static void Destroy(Widget w);
+static void Initialize(Widget rq, Widget eb, ArgList args, Cardinal *n);
+static Boolean SetValues(Widget current, Widget request, Widget new, ArgList args, Cardinal *n);
+static void Redisplay(Widget, XEvent *, Region);
+
+/*
+ * Declaration of action methods.
+ */
+static void Enter(Widget, XEvent *, String *, Cardinal *);
+static void Leave(Widget, XEvent *, String *, Cardinal *);
+static void BorderHighlight(Widget);
+static void BorderUnhighlight(Widget);
+
+/*
+ * 4 x 4 stipple for desensitized widgets
+ */
+#define stipple_width 4
+#define stipple_height 4
+static char stipple_bits[] = { 0x0a, 0x05, 0x0a, 0x05 };
+#define STIPPLE_BITMAP xmEnhancedButtonClassRec.enhancedbutton_class.stipple_bitmap
+
+/*
+ * Override actions.
+ */
+static XtActionsRec actionsList[] =
+{
+ {"Enter", Enter},
+ {"Leave", Leave},
+};
+
+static XtResource resources[] =
+{
+ {
+ XmNpixmapData, XmCPixmap, XmRString, sizeof(String),
+ XtOffsetOf(XmEnhancedButtonRec, enhancedbutton.pixmap_data),
+ XmRImmediate, (XtPointer) NULL
+ }, {
+ XmNpixmapFile, XmCPixmap, XmRString, sizeof(String),
+ XtOffsetOf(XmEnhancedButtonRec, enhancedbutton.pixmap_file),
+ XmRImmediate, (XtPointer) NULL
+ }, {
+ XmNspacing, XmCSpacing, XmRHorizontalDimension, sizeof(Dimension),
+ XtOffsetOf(XmEnhancedButtonRec, enhancedbutton.spacing),
+ XmRImmediate, (XtPointer) 2
+ },
+ {
+ XmNlabelLocation, XmCLocation, XmRInt, sizeof(int),
+ XtOffsetOf(XmEnhancedButtonRec, enhancedbutton.label_location),
+ XtRImmediate, (XtPointer) XmRIGHT
+ }
+};
+
+/* This is needed to work around a bug in Lesstif 2, leaving the extension
+ * NULL somehow results in getting it set to an invalid pointer. */
+XmPrimitiveClassExtRec xmEnhancedButtonPrimClassExtRec =
+{
+ /* next_extension */ NULL,
+ /* record_type */ NULLQUARK,
+ /* version */ XmPrimitiveClassExtVersion,
+ /* record_size */ sizeof(XmPrimitiveClassExtRec),
+ /* widget_baseline */ XmInheritBaselineProc,
+ /* widget_display_rect */ XmInheritDisplayRectProc,
+ /* widget_margins */ NULL
+};
+
+XmEnhancedButtonClassRec xmEnhancedButtonClassRec =
+{
+ {
+ /* core_class fields */
+ /* superclass */ (WidgetClass) & xmPushButtonClassRec,
+ /* class_name */ "XmEnhancedButton",
+ /* widget_size */ sizeof(XmEnhancedButtonRec),
+ /* class_initialize */ NULL,
+ /* class_part_initialize */ NULL,
+ /* class_inited */ False,
+ /* initialize */ Initialize,
+ /* initialize_hook */ NULL,
+ /* realize */ XtInheritRealize,
+ /* actions */ actionsList,
+ /* num_actions */ XtNumber(actionsList),
+ /* resources */ resources,
+ /* num_resources */ XtNumber(resources),
+ /* xrm_class */ NULLQUARK,
+ /* compress_motion */ True,
+ /* compress_exposure */ XtExposeCompressMaximal,
+ /* compress_enterleave */ True,
+ /* visible_interest */ False,
+ /* destroy */ Destroy,
+ /* resize */ XtInheritResize,
+ /* expose */ Redisplay,
+ /* set_values */ SetValues,
+ /* set_values_hook */ NULL,
+ /* set_values_almost */ XtInheritSetValuesAlmost,
+ /* get_values_hook */ NULL,
+ /* accept_focus */ XtInheritAcceptFocus,
+ /* version */ XtVersion,
+ /* callback_private */ NULL,
+ /* tm_table */ NULL,
+ /* query_geometry */ NULL,
+ /* display_accelerator */ XtInheritDisplayAccelerator,
+ /* extension */ NULL
+ },
+
+ /* primitive_class fields */
+ {
+ /* border highlight */ BorderHighlight,
+ /* border_unhighlight */ BorderUnhighlight,
+ /* translations */ XtInheritTranslations,
+ /* arm and activate */ XmInheritArmAndActivate,
+ /* synthetic resources */ NULL,
+ /* number of syn res */ 0,
+ /* extension */ (XtPointer)&xmEnhancedButtonPrimClassExtRec,
+ },
+
+ /* label_class fields */
+ {
+ /* setOverrideCallback */ XmInheritSetOverrideCallback,
+ /* menuProcs */ XmInheritMenuProc,
+ /* translations */ XtInheritTranslations,
+ /* extension */ NULL,
+ },
+
+ /* pushbutton_class record */
+ {
+ /* extension */ (XtPointer) NULL,
+ },
+
+ /* enhancedbutton_class fields */
+ {
+ /* stipple_bitmap */ None
+ }
+};
+
+
+WidgetClass xmEnhancedButtonWidgetClass =
+ (WidgetClass)&xmEnhancedButtonClassRec;
+
+
+/*
+ * Create a slightly fainter pixmap to be shown on button entry.
+ */
+ static unsigned short
+bump_color(unsigned short value)
+{
+ int tmp = 2 * (((int) value - 65535) / 3) + 65535;
+
+ return tmp;
+}
+
+ static int
+alloc_color(Display *display,
+ Colormap colormap,
+ char *colorname,
+ XColor *xcolor,
+ void *closure UNUSED)
+{
+ int status;
+
+ if (colorname)
+ if (!XParseColor(display, colormap, colorname, xcolor))
+ return -1;
+
+ xcolor->red = bump_color(xcolor->red);
+ xcolor->green = bump_color(xcolor->green);
+ xcolor->blue = bump_color(xcolor->blue);
+
+ status = XAllocColor(display, colormap, xcolor);
+ return status != 0 ? 1 : 0;
+}
+
+/* XPM */
+static char * blank_xpm[] =
+{
+/* width height ncolors cpp [x_hot y_hot] */
+"12 12 4 1 0 0",
+/* colors */
+" s iconColor1 m black c #000000",
+". s none m none c none",
+"X s topShadowColor m none c #DCDEE5",
+"o s bottomShadowColor m black c #5D6069",
+/* pixels */
+" ..",
+" XXXXXXXX ..",
+" X....... o.",
+" X....... o.",
+" X....... o.",
+" X....... o.",
+" X....... o.",
+" X....... o.",
+" X....... o.",
+" o.",
+"..ooooooooo.",
+"............"};
+
+/*
+ * Set the pixmap.
+ */
+ static void
+set_pixmap(XmEnhancedButtonWidget eb)
+{
+ /* Configure defines XPMATTRIBUTES_TYPE as XpmAttributes or as
+ * XpmAttributes_21, depending on what is in Xm/XpmP.h. */
+ XPMATTRIBUTES_TYPE attr;
+ Pixmap sen_pix;
+ Window root;
+ static XpmColorSymbol color[8] = {
+ {"none", "none", 0},
+ {"None", "none", 0},
+ {"background", NULL, 0},
+ {"foreground", NULL, 0},
+ {"bottomShadowColor", NULL, 0},
+ {"topShadowColor", NULL, 0},
+ {"highlightColor", NULL, 0},
+ {"armColor", NULL, 0}
+ };
+ int scr;
+ Display *dpy = XtDisplay(eb);
+ int x;
+ int y;
+ unsigned int height, width, border, depth;
+ int status = 0;
+ Pixmap mask;
+ Pixmap pix = None;
+ Pixmap arm_pix = None;
+ Pixmap ins_pix = None;
+ Pixmap high_pix = None;
+ char **data = (char **) eb->enhancedbutton.pixmap_data;
+ char *fname = (char *) eb->enhancedbutton.pixmap_file;
+ int shift;
+ GC gc;
+
+ /* Make sure there is a default value for the pixmap.
+ */
+ if (!data)
+ return;
+
+ gc = XtGetGC((Widget)eb, (XtGCMask)0, NULL);
+
+ scr = DefaultScreen(dpy);
+ root = RootWindow(dpy, scr);
+
+ eb->label.pixmap = None;
+
+ eb->enhancedbutton.pixmap_depth = 0;
+ eb->enhancedbutton.pixmap_width = 0;
+ eb->enhancedbutton.pixmap_height = 0;
+ eb->enhancedbutton.normal_pixmap = None;
+ eb->enhancedbutton.armed_pixmap = None;
+ eb->enhancedbutton.highlight_pixmap = None;
+ eb->enhancedbutton.insensitive_pixmap = None;
+
+ /* We use dynamic colors, get them now. */
+ motif_get_toolbar_colors(
+ &eb->core.background_pixel,
+ &eb->primitive.foreground,
+ &eb->primitive.bottom_shadow_color,
+ &eb->primitive.top_shadow_color,
+ &eb->primitive.highlight_color);
+
+ /* Setup color substitution table. */
+ color[0].pixel = eb->core.background_pixel;
+ color[1].pixel = eb->core.background_pixel;
+ color[2].pixel = eb->core.background_pixel;
+ color[3].pixel = eb->primitive.foreground;
+ color[4].pixel = eb->core.background_pixel;
+ color[5].pixel = eb->primitive.top_shadow_color;
+ color[6].pixel = eb->primitive.highlight_color;
+ color[7].pixel = eb->pushbutton.arm_color;
+
+ /* Create the "sensitive" pixmap. */
+ attr.valuemask = XpmColorSymbols | XpmCloseness;
+ attr.closeness = 65535; /* accuracy isn't crucial */
+ attr.colorsymbols = color;
+ attr.numsymbols = XtNumber(color);
+
+ if (fname)
+ status = XpmReadFileToPixmap(dpy, root, fname, &pix, &mask, &attr);
+ if (!fname || status != XpmSuccess)
+ status = XpmCreatePixmapFromData(dpy, root, data, &pix, &mask, &attr);
+
+ /* If something failed, we will fill in the default pixmap. */
+ if (status != XpmSuccess)
+ status = XpmCreatePixmapFromData(dpy, root, blank_xpm, &pix,
+ &mask, &attr);
+
+ XpmFreeAttributes(&attr);
+
+ XGetGeometry(dpy, pix, &root, &x, &y, &width, &height, &border, &depth);
+
+ /* TODO: does the shift depend on label_location somehow? */
+ shift = eb->primitive.shadow_thickness / 2;
+
+ if (shift < 1)
+ shift = 1;
+
+ sen_pix = XCreatePixmap(dpy, root, width + shift, height + shift, depth);
+
+ XSetForeground(dpy, gc, eb->core.background_pixel);
+ XFillRectangle(dpy, sen_pix, gc, 0, 0, width + shift, height + shift);
+ XSetClipMask(dpy, gc, mask);
+ XSetClipOrigin(dpy, gc, shift, shift);
+ XCopyArea(dpy, pix, sen_pix, gc, 0, 0, width, height, shift, shift);
+
+ /* Create the "highlight" pixmap. */
+ color[4].pixel = eb->primitive.bottom_shadow_color;
+#ifdef XpmAllocColor /* SGI doesn't have it */
+ attr.valuemask = XpmColorSymbols | XpmCloseness | XpmAllocColor;
+ attr.alloc_color = alloc_color;
+#else
+ attr.valuemask = XpmColorSymbols | XpmCloseness;
+#endif
+ attr.closeness = 65535; /* accuracy isn't crucial */
+ attr.colorsymbols = color;
+ attr.numsymbols = XtNumber(color);
+
+ status = XpmCreatePixmapFromData(dpy, root, data, &pix, NULL, &attr);
+ XpmFreeAttributes(&attr);
+
+ high_pix = XCreatePixmap(dpy, root, width + shift, height + shift, depth);
+
+#if 1
+ XSetForeground(dpy, gc, eb->core.background_pixel);
+#else
+ XSetForeground(dpy, gc, eb->primitive.top_shadow_color);
+#endif
+ XSetClipMask(dpy, gc, None);
+ XFillRectangle(dpy, high_pix, gc, 0, 0, width + shift, height + shift);
+ XSetClipMask(dpy, gc, mask);
+ XSetClipOrigin(dpy, gc, 0, 0);
+ XCopyArea(dpy, pix, high_pix, gc, 0, 0, width, height, 0, 0);
+
+ arm_pix = XCreatePixmap(dpy, pix, width + shift, height + shift, depth);
+
+ if (eb->pushbutton.fill_on_arm)
+ XSetForeground(dpy, gc, eb->pushbutton.arm_color);
+ else
+ XSetForeground(dpy, gc, eb->core.background_pixel);
+ XSetClipOrigin(dpy, gc, shift, shift);
+ XSetClipMask(dpy, gc, None);
+ XFillRectangle(dpy, arm_pix, gc, 0, 0, width + shift, height + shift);
+ XSetClipMask(dpy, gc, mask);
+ XSetClipOrigin(dpy, gc, 2 * shift, 2 * shift);
+ XCopyArea(dpy, pix, arm_pix, gc, 0, 0, width, height, 2 * shift, 2 * shift);
+
+ XFreePixmap(dpy, pix);
+ XFreePixmap(dpy, mask);
+
+ /* Create the "insensitive" pixmap. */
+ attr.valuemask = XpmColorSymbols | XpmCloseness | XpmColorKey;
+ attr.closeness = 65535; /* accuracy isn't crucial */
+ attr.colorsymbols = color;
+ attr.numsymbols = sizeof(color) / sizeof(color[0]);
+ attr.color_key = XPM_MONO;
+ status = XpmCreatePixmapFromData(dpy, root, data, &pix, &mask, &attr);
+
+ /* Need to create new Pixmaps with the mask applied. */
+
+ ins_pix = XCreatePixmap(dpy, root, width + shift, height + shift, depth);
+
+ XSetForeground(dpy, gc, eb->core.background_pixel);
+ XSetClipOrigin(dpy, gc, 0, 0);
+ XSetClipMask(dpy, gc, None);
+ XFillRectangle(dpy, ins_pix, gc, 0, 0, width + shift, height + shift);
+ XSetClipMask(dpy, gc, mask);
+ XSetForeground(dpy, gc, eb->primitive.top_shadow_color);
+ XSetClipOrigin(dpy, gc, 2 * shift, 2 * shift);
+ XFillRectangle(dpy, ins_pix, gc, 2 * shift, 2 * shift, width, height);
+ XSetForeground(dpy, gc, eb->primitive.bottom_shadow_color);
+ XSetClipOrigin(dpy, gc, shift, shift);
+ XFillRectangle(dpy, ins_pix, gc, 0, 0, width + shift, height + shift);
+ XtReleaseGC((Widget) eb, gc);
+
+ XpmFreeAttributes(&attr);
+
+ eb->enhancedbutton.pixmap_depth = depth;
+ eb->enhancedbutton.pixmap_width = width;
+ eb->enhancedbutton.pixmap_height = height;
+ eb->enhancedbutton.normal_pixmap = sen_pix;
+ eb->enhancedbutton.highlight_pixmap = high_pix;
+ eb->enhancedbutton.insensitive_pixmap = ins_pix;
+ eb->enhancedbutton.armed_pixmap = arm_pix;
+
+ eb->enhancedbutton.doing_setvalues = True;
+ eb->enhancedbutton.doing_setvalues = False;
+
+ XFreePixmap(dpy, pix);
+ XFreePixmap(dpy, mask);
+}
+
+#define BUTTON_MASK ( \
+ Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask \
+)
+
+ static void
+draw_shadows(XmEnhancedButtonWidget eb)
+{
+ GC top_gc;
+ GC bottom_gc;
+ Boolean etched_in;
+
+ if (!eb->primitive.shadow_thickness)
+ return;
+
+ if ((eb->core.width <= 2 * eb->primitive.highlight_thickness)
+ || (eb->core.height <= 2 * eb->primitive.highlight_thickness))
+ return;
+
+#if !defined(LESSTIF_VERSION) && (XmVersion > 1002)
+ {
+ XmDisplay dpy;
+
+ dpy = (XmDisplay) XmGetXmDisplay(XtDisplay(eb));
+ etched_in = dpy->display.enable_etched_in_menu;
+ }
+#else
+ etched_in = False;
+#endif
+ if (!etched_in ^ eb->pushbutton.armed)
+ {
+ top_gc = eb->primitive.top_shadow_GC;
+ bottom_gc = eb->primitive.bottom_shadow_GC;
+ }
+ else
+ {
+ top_gc = eb->primitive.bottom_shadow_GC;
+ bottom_gc = eb->primitive.top_shadow_GC;
+ }
+
+ XmeDrawShadows(XtDisplay(eb), XtWindow(eb),
+ top_gc,
+ bottom_gc,
+ eb->primitive.highlight_thickness,
+ eb->primitive.highlight_thickness,
+ eb->core.width - 2 * eb->primitive.highlight_thickness,
+ eb->core.height - 2 * eb->primitive.highlight_thickness,
+ eb->primitive.shadow_thickness,
+ (unsigned)(etched_in ? XmSHADOW_IN : XmSHADOW_OUT));
+}
+
+ static void
+draw_highlight(XmEnhancedButtonWidget eb)
+{
+ eb->primitive.highlighted = True;
+ eb->primitive.highlight_drawn = True;
+
+ if (!XtWidth(eb) || !XtHeight(eb) || !eb->primitive.highlight_thickness)
+ return;
+
+ XmeDrawHighlight(XtDisplay(eb), XtWindow(eb),
+ eb->primitive.highlight_GC, 0, 0,
+ XtWidth(eb), XtHeight(eb),
+ eb->primitive.highlight_thickness);
+}
+
+ static void
+draw_unhighlight(XmEnhancedButtonWidget eb)
+{
+ GC manager_background_GC;
+
+ eb->primitive.highlighted = False;
+ eb->primitive.highlight_drawn = False;
+
+ if (!XtWidth(eb) || !XtHeight(eb) || !eb->primitive.highlight_thickness)
+ return;
+
+ if (XmIsManager(eb->core.parent))
+ {
+#ifdef UNHIGHLIGHTT
+ XmSpecifyUnhighlightTrait UnhighlightT;
+
+ if (((UnhighlightT = (XmSpecifyUnhighlightTrait) XmeTraitGet((XtPointer)
+ XtClass(eb->core.parent), XmQTspecifyUnhighlight))
+ != NULL) && (UnhighlightT->getUnhighlightGC != NULL))
+ {
+ /* if unhighlight trait in parent use specified GC... */
+ manager_background_GC =
+ UnhighlightT->getUnhighlightGC(eb->core.parent, (Widget) eb);
+ }
+ else
+ {
+ /* ...otherwise, use parent's background GC */
+ manager_background_GC = ((XmManagerWidget)
+ (eb->core.parent))->manager.background_GC;
+ }
+#else
+ manager_background_GC = ((XmManagerWidget)
+ (eb->core.parent))->manager.background_GC;
+#endif
+ XmeDrawHighlight(XtDisplay(eb), XtWindow(eb),
+ manager_background_GC,
+ 0, 0, XtWidth(eb), XtHeight(eb),
+ eb->primitive.highlight_thickness);
+ if (!eb->pushbutton.armed && eb->primitive.shadow_thickness)
+ XmeClearBorder(XtDisplay(eb), XtWindow(eb),
+ eb->primitive.highlight_thickness,
+ eb->primitive.highlight_thickness,
+ eb->core.width - 2 * eb->primitive.highlight_thickness,
+ eb->core.height - 2 * eb->primitive.highlight_thickness,
+ eb->primitive.shadow_thickness);
+ }
+ else
+ XmeClearBorder(XtDisplay(eb), XtWindow(eb), 0, 0, XtWidth(eb),
+ XtHeight(eb), eb->primitive.highlight_thickness);
+}
+
+ static void
+draw_pixmap(XmEnhancedButtonWidget eb,
+ XEvent *event UNUSED,
+ Region region UNUSED)
+{
+ Pixmap pix;
+ GC gc = eb->label.normal_GC;
+ int depth;
+ Cardinal width;
+ Cardinal height;
+ Cardinal w;
+ Cardinal h;
+ int x;
+ int y;
+
+ if (!XtIsSensitive((Widget) eb))
+ pix = eb->enhancedbutton.insensitive_pixmap;
+ else
+ {
+ if (eb->primitive.highlighted && !eb->pushbutton.armed)
+ pix = eb->enhancedbutton.highlight_pixmap;
+ else if (eb->pushbutton.armed)
+ pix = eb->enhancedbutton.armed_pixmap;
+ else
+ pix = eb->enhancedbutton.normal_pixmap;
+ }
+
+ if (pix == None || !eb->enhancedbutton.pixmap_data)
+ return;
+
+ depth = eb->enhancedbutton.pixmap_depth;
+ w = eb->enhancedbutton.pixmap_width;
+ h = eb->enhancedbutton.pixmap_height;
+
+ gc = eb->label.normal_GC;
+ x = eb->primitive.highlight_thickness
+ + eb->primitive.shadow_thickness
+ + eb->label.margin_width;
+ y = eb->primitive.highlight_thickness
+ + eb->primitive.shadow_thickness
+ + eb->label.margin_height;
+ width = eb->core.width - 2 * x;
+ if (w < width)
+ width = w;
+ height = eb->core.height - 2 * y;
+ if (h < height)
+ height = h;
+ if (depth == (int)eb->core.depth)
+ XCopyArea(XtDisplay(eb), pix, XtWindow(eb), gc, 0, 0,
+ width, height, x, y);
+ else if (depth == 1)
+ XCopyPlane(XtDisplay(eb), pix, XtWindow(eb), gc, 0, 0,
+ width, height, x, y, (unsigned long)1);
+}
+
+/*
+ * Draw the label contained in the pushbutton.
+ */
+ static void
+draw_label(XmEnhancedButtonWidget eb, XEvent *event, Region region)
+{
+ GC tmp_gc = NULL;
+ Boolean replaceGC = False;
+ Boolean deadjusted = False;
+#if !defined(LESSTIF_VERSION) && (XmVersion > 1002)
+ XmDisplay dpy = (XmDisplay)XmGetXmDisplay(XtDisplay(eb));
+ Boolean etched_in = dpy->display.enable_etched_in_menu;
+#else
+ Boolean etched_in = False;
+#endif
+
+ if (eb->pushbutton.armed
+ && ((!Lab_IsMenupane(eb) && eb->pushbutton.fill_on_arm)
+ || (Lab_IsMenupane(eb) && etched_in)))
+ {
+ if (eb->label.label_type == (int)XmSTRING
+ && eb->pushbutton.arm_color == eb->primitive.foreground)
+ {
+ tmp_gc = eb->label.normal_GC;
+ eb->label.normal_GC = eb->pushbutton.background_gc;
+ replaceGC = True;
+ }
+ }
+
+ /*
+ * If the button contains a labeled pixmap, we will take it instead of our
+ * own pixmap.
+ */
+
+ if (eb->label.label_type == (int)XmPIXMAP)
+ {
+ if (eb->pushbutton.armed)
+ {
+ if (eb->pushbutton.arm_pixmap != XmUNSPECIFIED_PIXMAP)
+ eb->label.pixmap = eb->pushbutton.arm_pixmap;
+ else
+ eb->label.pixmap = eb->pushbutton.unarm_pixmap;
+ }
+ else
+ /* pushbutton is not armed */
+ eb->label.pixmap = eb->pushbutton.unarm_pixmap;
+ }
+
+ /*
+ * Temporarily remove the Xm3D_ENHANCE_PIXEL hack ("adjustment") from the
+ * margin values, so we don't confuse Label.
+ */
+ if (eb->pushbutton.default_button_shadow_thickness > 0)
+ {
+ deadjusted = True;
+ Lab_MarginLeft(eb) -= Xm3D_ENHANCE_PIXEL;
+ Lab_MarginRight(eb) -= Xm3D_ENHANCE_PIXEL;
+ Lab_MarginTop(eb) -= Xm3D_ENHANCE_PIXEL;
+ Lab_MarginBottom(eb) -= Xm3D_ENHANCE_PIXEL;
+ }
+
+ {
+ XtExposeProc expose;
+
+ XtProcessLock();
+ expose = xmLabelClassRec.core_class.expose;
+ XtProcessUnlock();
+ (*expose)((Widget) eb, event, region);
+ }
+
+ if (deadjusted)
+ {
+ Lab_MarginLeft(eb) += Xm3D_ENHANCE_PIXEL;
+ Lab_MarginRight(eb) += Xm3D_ENHANCE_PIXEL;
+ Lab_MarginTop(eb) += Xm3D_ENHANCE_PIXEL;
+ Lab_MarginBottom(eb) += Xm3D_ENHANCE_PIXEL;
+ }
+
+ if (replaceGC)
+ eb->label.normal_GC = tmp_gc;
+}
+
+ static void
+Enter(Widget wid,
+ XEvent *event,
+ String *params UNUSED,
+ Cardinal *num_params UNUSED)
+{
+ XmEnhancedButtonWidget eb = (XmEnhancedButtonWidget) wid;
+ XmPushButtonCallbackStruct call_value;
+
+ if (Lab_IsMenupane(eb))
+ {
+ if ((((ShellWidget) XtParent(XtParent(eb)))->shell.popped_up)
+ && _XmGetInDragMode((Widget) eb))
+ {
+#if !defined(LESSTIF_VERSION) && (XmVersion > 1002)
+ XmDisplay dpy = (XmDisplay) XmGetXmDisplay(XtDisplay(wid));
+ Boolean etched_in = dpy->display.enable_etched_in_menu;
+#else
+ Boolean etched_in = False;
+#endif
+
+ if (eb->pushbutton.armed)
+ return;
+
+ /* ...so KHelp event is delivered correctly. */
+ _XmSetFocusFlag(XtParent(XtParent(eb)), XmFOCUS_IGNORE, TRUE);
+ XtSetKeyboardFocus(XtParent(XtParent(eb)), (Widget) eb);
+ _XmSetFocusFlag(XtParent(XtParent(eb)), XmFOCUS_IGNORE, FALSE);
+
+ eb->pushbutton.armed = TRUE;
+
+ ((XmManagerWidget) XtParent(wid))->manager.active_child = wid;
+
+ /* etched in menu button */
+ if (etched_in && !XmIsTearOffButton(eb))
+ {
+ XFillRectangle(XtDisplay(eb), XtWindow(eb),
+ eb->pushbutton.fill_gc,
+ 0, 0, eb->core.width, eb->core.height);
+ draw_label(eb, event, NULL);
+ draw_pixmap(eb, event, NULL);
+ }
+
+ if ((eb->core.width > 2 * eb->primitive.highlight_thickness)
+ && (eb->core.height >
+ 2 * eb->primitive.highlight_thickness))
+ {
+ XmeDrawShadows(XtDisplay(eb), XtWindow(eb),
+ eb->primitive.top_shadow_GC,
+ eb->primitive.bottom_shadow_GC,
+ eb->primitive.highlight_thickness,
+ eb->primitive.highlight_thickness,
+ eb->core.width - 2 * eb->primitive.highlight_thickness,
+ eb->core.height - 2 * eb->primitive.highlight_thickness,
+ eb->primitive.shadow_thickness,
+ (unsigned)(etched_in ? XmSHADOW_IN : XmSHADOW_OUT));
+ }
+
+ if (eb->pushbutton.arm_callback)
+ {
+ XFlush(XtDisplay(eb));
+
+ call_value.reason = (int)XmCR_ARM;
+ call_value.event = event;
+ XtCallCallbackList((Widget) eb,
+ eb->pushbutton.arm_callback,
+ &call_value);
+ }
+ }
+ }
+ else
+ {
+ XtExposeProc expose;
+
+ _XmPrimitiveEnter((Widget) eb, event, NULL, NULL);
+ if (eb->pushbutton.armed == TRUE)
+ {
+ XtProcessLock();
+ expose = XtClass(eb)->core_class.expose;
+ XtProcessUnlock();
+ (*expose) (wid, event, (Region) NULL);
+ }
+
+ draw_highlight(eb);
+ draw_shadows(eb);
+ draw_pixmap(eb, event, NULL);
+ }
+}
+
+ static void
+Leave(Widget wid,
+ XEvent *event,
+ String *params UNUSED,
+ Cardinal *num_params UNUSED)
+{
+ XmEnhancedButtonWidget eb = (XmEnhancedButtonWidget)wid;
+ XmPushButtonCallbackStruct call_value;
+
+ if (Lab_IsMenupane(eb))
+ {
+#if !defined(LESSTIF_VERSION) && (XmVersion > 1002)
+ XmDisplay dpy = (XmDisplay) XmGetXmDisplay(XtDisplay(wid));
+ Boolean etched_in = dpy->display.enable_etched_in_menu;
+#else
+ Boolean etched_in = False;
+#endif
+
+ if (_XmGetInDragMode((Widget)eb)
+ && eb->pushbutton.armed
+ && ( /* !ActiveTearOff || */
+ event->xcrossing.mode == NotifyNormal))
+ {
+ eb->pushbutton.armed = FALSE;
+
+ ((XmManagerWidget) XtParent(wid))->manager.active_child = NULL;
+
+ if (etched_in && !XmIsTearOffButton(eb))
+ {
+ XFillRectangle(XtDisplay(eb), XtWindow(eb),
+ eb->pushbutton.background_gc,
+ 0, 0, eb->core.width, eb->core.height);
+ draw_label(eb, event, NULL);
+ draw_pixmap(eb, event, NULL);
+ }
+ else
+ XmeClearBorder
+ (XtDisplay(eb), XtWindow(eb),
+ eb->primitive.highlight_thickness,
+ eb->primitive.highlight_thickness,
+ eb->core.width -
+ 2 * eb->primitive.highlight_thickness,
+ eb->core.height -
+ 2 * eb->primitive.highlight_thickness,
+ eb->primitive.shadow_thickness);
+
+ if (eb->pushbutton.disarm_callback)
+ {
+ XFlush(XtDisplay(eb));
+
+ call_value.reason = (int)XmCR_DISARM;
+ call_value.event = event;
+ XtCallCallbackList((Widget) eb,
+ eb->pushbutton.disarm_callback,
+ &call_value);
+ }
+ }
+ }
+ else
+ {
+ _XmPrimitiveLeave((Widget) eb, event, NULL, NULL);
+
+ if (eb->pushbutton.armed == TRUE)
+ {
+ XtExposeProc expose;
+ eb->pushbutton.armed = FALSE;
+ XtProcessLock();
+ expose = XtClass(eb)->core_class.expose;
+ XtProcessUnlock();
+ (*expose) (wid, event, (Region)NULL);
+ draw_unhighlight(eb);
+ draw_pixmap(eb, event, NULL);
+ eb->pushbutton.armed = TRUE;
+ }
+ else
+ {
+ draw_unhighlight(eb);
+ draw_pixmap(eb, event, NULL);
+ }
+ }
+}
+
+#define IsNull(p) ((p) == XmUNSPECIFIED_PIXMAP)
+
+ static void
+set_size(XmEnhancedButtonWidget newtb)
+{
+ unsigned int w = 0;
+ unsigned int h = 0;
+
+ _XmCalcLabelDimensions((Widget) newtb);
+
+ /* Find out how big the pixmap is */
+ if (newtb->enhancedbutton.pixmap_data
+ && !IsNull(newtb->label.pixmap)
+ && !IsNull(newtb->enhancedbutton.normal_pixmap))
+ {
+ w = newtb->enhancedbutton.pixmap_width;
+ h = newtb->enhancedbutton.pixmap_height;
+ }
+
+ /*
+ * Please note that we manipulate the width only in case of push buttons
+ * not used in the context of a menu pane.
+ */
+ if (Lab_IsMenupane(newtb))
+ {
+ newtb->label.margin_left = w + 2 * (newtb->primitive.shadow_thickness
+ + newtb->primitive.highlight_thickness)
+ + newtb->label.margin_width;
+ }
+ else
+ {
+ newtb->label.margin_left = w;
+ newtb->core.width = w + 2 * (newtb->primitive.shadow_thickness
+ + newtb->primitive.highlight_thickness
+ + newtb->label.margin_width)
+ + newtb->label.TextRect.width;
+
+ if (newtb->label.TextRect.width > 0)
+ {
+ newtb->label.margin_left += newtb->label.margin_width
+ + newtb->primitive.shadow_thickness;
+ newtb->core.width += newtb->label.margin_width
+ + newtb->primitive.shadow_thickness;
+ }
+ }
+ if (newtb->label.TextRect.height < h)
+ {
+ newtb->core.height = h + 2 * (newtb->primitive.shadow_thickness
+ + newtb->primitive.highlight_thickness
+ + newtb->label.margin_height);
+ }
+ else
+ {
+ /* FIXME: We should calculate an drawing offset for the pixmap here to
+ * adjust it. */
+ }
+
+#if 0
+ printf("%d %d %d %d %d %d - %d %d\n", newtb->enhancedbutton.normal_pixmap,
+ h, newtb->core.height,
+ newtb->primitive.shadow_thickness,
+ newtb->primitive.highlight_thickness,
+ newtb->label.margin_height,
+ newtb->core.width,
+ newtb->core.height);
+#endif
+
+ /* Invoke Label's Resize procedure. */
+ {
+ XtWidgetProc resize;
+ XtProcessLock();
+ resize = xmLabelClassRec.core_class.resize;
+ XtProcessUnlock();
+
+ (* resize) ((Widget) newtb);
+ }
+}
+
+ static void
+Initialize(Widget rq, Widget ebw, ArgList args UNUSED, Cardinal *n UNUSED)
+{
+ XmEnhancedButtonWidget request = (XmEnhancedButtonWidget)rq;
+ XmEnhancedButtonWidget eb = (XmEnhancedButtonWidget)ebw;
+ XtWidgetProc resize;
+
+ XtProcessLock();
+ resize = xmLabelClassRec.core_class.resize;
+ XtProcessUnlock();
+
+ /* Create a bitmap for stippling (Drawable resources are cheap). */
+ if (STIPPLE_BITMAP == None)
+ {
+ Display *dpy = XtDisplay((Widget) request);
+ Window rootW = DefaultRootWindow(dpy);
+
+ STIPPLE_BITMAP = XCreateBitmapFromData(dpy, rootW, stipple_bits,
+ stipple_width, stipple_height);
+ }
+ eb->enhancedbutton.doing_setvalues = False;
+
+ /* First see what type of extended label this is.
+ */
+ if (eb->enhancedbutton.pixmap_data)
+ {
+ XmString str;
+ set_pixmap(eb);
+
+ /* FIXME: this is not the perfect way to deal with menus, which do not
+ * have any string set right now. */
+ str = XmStringCreateLocalized("");
+ XtVaSetValues((Widget) eb, XmNlabelString, str, NULL);
+ XmStringFree(str);
+ }
+ eb->label.pixmap = eb->enhancedbutton.normal_pixmap;
+
+ if (request->core.width == 0)
+ eb->core.width = 0;
+ if (request->core.height == 0)
+ eb->core.height = 0;
+ set_size(eb);
+
+ (* resize)((Widget)eb);
+}
+
+ static void
+free_pixmaps(XmEnhancedButtonWidget eb)
+{
+ /*
+ * Clear the old pixmaps.
+ */
+ Pixmap norm_pix = eb->enhancedbutton.normal_pixmap;
+ Pixmap arm_pix = eb->enhancedbutton.armed_pixmap;
+ Pixmap insen_pix = eb->enhancedbutton.insensitive_pixmap;
+ Pixmap high_pix = eb->enhancedbutton.highlight_pixmap;
+
+ if (norm_pix != None && norm_pix != XmUNSPECIFIED_PIXMAP)
+ XFreePixmap(XtDisplay(eb), norm_pix);
+
+ if (arm_pix != None && arm_pix != XmUNSPECIFIED_PIXMAP)
+ XFreePixmap(XtDisplay(eb), arm_pix);
+
+ if (insen_pix != None && insen_pix != XmUNSPECIFIED_PIXMAP)
+ XFreePixmap(XtDisplay(eb), insen_pix);
+
+ if (high_pix != None && high_pix != XmUNSPECIFIED_PIXMAP)
+ XFreePixmap(XtDisplay(eb), high_pix);
+}
+
+ static void
+Destroy(Widget w)
+{
+ if (!XmIsEnhancedButton(w))
+ return;
+
+ free_pixmaps((XmEnhancedButtonWidget)w);
+}
+
+ static Boolean
+SetValues(Widget current,
+ Widget request UNUSED,
+ Widget new,
+ ArgList args UNUSED,
+ Cardinal *n UNUSED)
+{
+ XmEnhancedButtonWidget cur = (XmEnhancedButtonWidget) current;
+ XmEnhancedButtonWidget eb = (XmEnhancedButtonWidget) new;
+ Boolean redraw = False;
+ Boolean change = True;
+ Display *dpy = XtDisplay(current);
+
+#define NOT_EQUAL(field) (cur->field != eb->field)
+
+ /*
+ * Make sure that lost sensitivity is causing the border to vanish as well.
+ */
+ if (NOT_EQUAL(core.sensitive) && !Lab_IsMenupane(current))
+ {
+ if (cur->core.sensitive == True)
+ {
+ draw_unhighlight(eb);
+ }
+ else
+ {
+ int r_x;
+ int r_y;
+ unsigned int r_height;
+ unsigned int r_width;
+ unsigned int r_border;
+ unsigned int r_depth;
+ int root_x;
+ int root_y;
+ int win_x;
+ int win_y;
+ Window root;
+ Window root_q;
+ Window child;
+ unsigned int mask;
+
+ /*
+ * Artificially let the highlight appear if the mouse is over us.
+ */
+ /* Best way to get the root window of object: */
+ XGetGeometry(dpy, XtWindow(cur), &root, &r_x, &r_y, &r_width,
+ &r_height, &r_border, &r_depth);
+ XQueryPointer(XtDisplay(cur), XtWindow(cur), &root_q, &child,
+ &root_x, &root_y, &win_x, &win_y, &mask);
+
+ if (root == root_q)
+ {
+ if ((win_x < 0) || (win_y < 0))
+ return False;
+
+ if ((win_x > (int)r_width) || (win_y > (int)r_height))
+ return False;
+ draw_highlight(eb);
+ draw_shadows(eb);
+ }
+ }
+
+ return True;
+ }
+
+ /*
+ * Check for changed ExtLabelString.
+ */
+ if (NOT_EQUAL(primitive.shadow_thickness))
+ {
+ redraw = True;
+ /* Don't change the pixmaps */
+ change = False;
+ }
+
+ if (NOT_EQUAL(primitive.foreground))
+ redraw = True;
+ if (NOT_EQUAL(core.background_pixel))
+ redraw = True;
+ if (NOT_EQUAL(pushbutton.fill_on_arm))
+ redraw = True;
+ if (NOT_EQUAL(enhancedbutton.spacing))
+ redraw = True;
+ if (NOT_EQUAL(enhancedbutton.label_location))
+ {
+ redraw = True;
+ change = False;
+ }
+ if (NOT_EQUAL(label._label))
+ {
+ redraw = True;
+ set_size(eb);
+ }
+
+ if (redraw == True)
+ {
+ if (change)
+ set_pixmap(eb);
+ if (eb->primitive.highlighted)
+ eb->label.pixmap = eb->enhancedbutton.highlight_pixmap;
+ else
+ eb->label.pixmap = eb->enhancedbutton.normal_pixmap;
+ if (change)
+ set_size(eb);
+ redraw = False;
+ }
+
+ return redraw;
+}
+
+ static void
+Redisplay(Widget w, XEvent *event, Region region)
+{
+ XmEnhancedButtonWidget eb = (XmEnhancedButtonWidget) w;
+#if !defined(LESSTIF_VERSION) && (XmVersion > 1002)
+ XmDisplay dpy;
+ XtEnum default_button_emphasis;
+#endif
+ XRectangle box;
+ int dx;
+ int adjust;
+ short fill = 0;
+
+ if (!XtIsRealized((Widget)eb))
+ return;
+
+#if !defined(LESSTIF_VERSION) && (XmVersion > 1002)
+ dpy = (XmDisplay)XmGetXmDisplay(XtDisplay(eb));
+ default_button_emphasis = dpy->display.default_button_emphasis;
+#endif
+
+ /*
+ * Compute the area allocated to the label of the pushbutton; fill in the
+ * dimensions in the box.
+ */
+
+ if ((eb->pushbutton.arm_color == eb->primitive.top_shadow_color)
+ || (eb->pushbutton.arm_color == eb->primitive.bottom_shadow_color))
+ fill = 1;
+
+ if (eb->pushbutton.compatible)
+ adjust = eb->pushbutton.show_as_default;
+ else
+ adjust = eb->pushbutton.default_button_shadow_thickness;
+
+ if (adjust > 0)
+ {
+ adjust = adjust + eb->primitive.shadow_thickness;
+ adjust = (adjust << 1);
+ dx = eb->primitive.highlight_thickness + adjust + fill;
+ }
+ else
+ dx = (eb->primitive.highlight_thickness
+ + eb->primitive.shadow_thickness + fill);
+
+ box.x = dx;
+ box.y = dx;
+ adjust = (dx << 1);
+ box.width = eb->core.width - adjust;
+ box.height = eb->core.height - adjust;
+
+ /*
+ * Redraw the background.
+ */
+ if (!Lab_IsMenupane(eb))
+ {
+ GC gc;
+
+ /* Don't shade if the button contains a label with a pixmap, since
+ * there is no variant of the label available with the needed
+ * background.
+ */
+ if (eb->pushbutton.armed && eb->pushbutton.fill_on_arm)
+ {
+ if (eb->label.label_type == (int)XmPIXMAP)
+ {
+ if (eb->pushbutton.arm_pixmap != XmUNSPECIFIED_PIXMAP)
+ gc = eb->pushbutton.fill_gc;
+ else
+ gc = eb->pushbutton.background_gc;
+ }
+ else
+ gc = eb->pushbutton.fill_gc;
+ }
+ else
+ gc = eb->pushbutton.background_gc;
+ /* really need to fill with background if not armed ? */
+ if (gc)
+ XFillRectangle(XtDisplay(eb), XtWindow(eb), gc,
+ box.x, box.y, box.width, box.height);
+ }
+
+ draw_label(eb, event, region);
+
+ if (Lab_IsMenupane(eb))
+ {
+ if (eb->pushbutton.armed)
+ (*(((XmPushButtonWidgetClass)XtClass(eb))
+ ->primitive_class.border_highlight))(w);
+ draw_pixmap(eb, event, region);
+ }
+ else
+ {
+ adjust = 0;
+
+#if !defined(LESSTIF_VERSION) && (XmVersion > 1002)
+ /*
+ * NOTE: PushButton has two types of shadows: primitive-shadow and
+ * default-button-shadow. If pushbutton is in a menu only primitive
+ * shadows are drawn.
+ */
+ switch (default_button_emphasis)
+ {
+ case XmEXTERNAL_HIGHLIGHT:
+ adjust = (eb->primitive.highlight_thickness -
+ (eb->pushbutton.default_button_shadow_thickness
+ ? Xm3D_ENHANCE_PIXEL : 0));
+ break;
+
+ case XmINTERNAL_HIGHLIGHT:
+ break;
+
+ default:
+ assert(FALSE);
+ return;
+ }
+#endif
+
+ /*
+ * Clear the area not occupied by label with parents background color.
+ * Label will invoke BorderUnhighlight() on the highlight_thickness
+ * area, which is redundant when XmEXTERNAL_HIGHLIGHT default button
+ * shadow emphasis is used.
+ */
+ if (box.x > adjust)
+ {
+ int borderwidth =box.x - adjust;
+ int rectwidth = eb->core.width - 2 * adjust;
+ int rectheight = eb->core.height - 2 * adjust;
+
+ if (XmIsManager(XtParent(eb)))
+ {
+ XmeDrawHighlight(XtDisplay(eb), XtWindow(eb),
+ XmParentBackgroundGC(eb),
+ adjust, adjust, rectwidth, rectheight, borderwidth);
+ }
+ else
+ {
+ XmeClearBorder(XtDisplay(eb), XtWindow(eb),
+ adjust, adjust, rectwidth, rectheight, borderwidth);
+ }
+
+#if !defined(LESSTIF_VERSION) && (XmVersion > 1002)
+ switch (default_button_emphasis)
+ {
+ case XmINTERNAL_HIGHLIGHT:
+ /* The call above erases the border highlighting. */
+ if (eb->primitive.highlight_drawn)
+ (*(((XmPushButtonWidgetClass) XtClass (eb))
+ ->primitive_class.border_highlight)) ((Widget) eb) ;
+ break;
+
+ default:
+ break;
+ }
+#endif
+ }
+
+ if (eb->pushbutton.default_button_shadow_thickness)
+ {
+ if (eb->pushbutton.show_as_default)
+ {
+ /*
+ * - get the topShadowColor and bottomShadowColor from the
+ * parent; use those colors to construct top and bottom gc;
+ * use these GCs to draw the shadows of the button.
+ *
+ * - Should not be called if pushbutton is in a row column or
+ * in a menu.
+ *
+ * - Should be called only if a defaultbuttonshadow is to be
+ * drawn.
+ */
+ GC top_gc;
+ GC bottom_gc;
+ int default_button_shadow_thickness;
+ int x, y, width, height, delta;
+ Widget parent;
+
+ if (eb->pushbutton.compatible
+ && (eb->pushbutton.show_as_default == 0))
+ return;
+
+ if (!eb->pushbutton.compatible
+ && (eb->pushbutton.default_button_shadow_thickness
+ == 0))
+ return;
+
+ delta = eb->primitive.highlight_thickness;
+
+ /*
+ * May need more complex computation for getting the GCs.
+ */
+ parent = XtParent(eb);
+ if (XmIsManager(parent))
+ {
+ /* Use the parent's GC so monochrome works. */
+ bottom_gc = XmParentTopShadowGC(eb);
+ top_gc = XmParentBottomShadowGC(eb);
+ }
+ else
+ {
+ /* Use your own pixel for drawing. */
+ bottom_gc = eb->primitive.top_shadow_GC;
+ top_gc = eb->primitive.bottom_shadow_GC;
+ }
+
+ if ((bottom_gc == None) || (top_gc == None))
+ return;
+
+
+ if (eb->pushbutton.compatible)
+ default_button_shadow_thickness =
+ eb->pushbutton.show_as_default;
+ else
+ default_button_shadow_thickness =
+ eb->pushbutton.default_button_shadow_thickness;
+
+#if !defined(LESSTIF_VERSION) && (XmVersion > 1002)
+ /*
+ * Compute location of bounding box to contain the
+ * defaultButtonShadow.
+ */
+ switch (default_button_emphasis)
+ {
+ case XmEXTERNAL_HIGHLIGHT:
+ delta = eb->primitive.highlight_thickness;
+ break;
+
+ case XmINTERNAL_HIGHLIGHT:
+ delta = Xm3D_ENHANCE_PIXEL;
+ break;
+
+ default:
+ assert(FALSE);
+ return;
+ }
+#endif
+
+ x = y = delta;
+ width = eb->core.width - 2 * delta;
+ height = eb->core.height - 2 * delta;
+
+ if ((width > 0) && (height > 0))
+ XmeDrawShadows(XtDisplay(eb), XtWindow(eb),
+ top_gc, bottom_gc, x, y, width, height,
+ default_button_shadow_thickness,
+ (unsigned)XmSHADOW_OUT);
+ }
+ }
+
+ if (eb->primitive.highlight_drawn)
+ draw_shadows(eb);
+ draw_pixmap(eb, event, region);
+ }
+}
+
+ static void
+BorderHighlight(Widget w)
+{
+ XmEnhancedButtonWidget eb = (XmEnhancedButtonWidget)w;
+
+ (*(xmPushButtonClassRec.primitive_class.border_highlight))(w);
+ draw_pixmap(eb, NULL, NULL);
+}
+
+ static void
+BorderUnhighlight(Widget w)
+{
+ XmEnhancedButtonWidget eb = (XmEnhancedButtonWidget)w;
+
+ (*(xmPushButtonClassRec.primitive_class.border_unhighlight))(w);
+ draw_pixmap(eb, NULL, NULL);
+}
+
+#endif /* FEAT_TOOLBAR */
diff --git a/src/gui_xmebw.h b/src/gui_xmebw.h
new file mode 100644
index 0000000..aaf5c72
--- /dev/null
+++ b/src/gui_xmebw.h
@@ -0,0 +1,72 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+/*
+ *
+ * (C) 2002,2005 by Marcin Dalecki <martin@dalecki.de>
+ *
+ * MARCIN DALECKI ASSUMES NO RESPONSIBILITY FOR THE USE OR INABILITY TO USE ANY
+ * OF THIS SOFTWARE . THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
+ * KIND, AND MARCIN DALECKI EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES,
+ * INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef EnhancedB_H
+#define EnhancedB_H
+
+/*
+ * New resources for the Extended Pushbutton widget
+ */
+
+#ifndef XmNshift
+# define XmNshift "shift"
+#endif
+#ifndef XmCShift
+# define XmCShift "Shift"
+#endif
+
+#ifndef XmNlabelLocation
+# define XmNlabelLocation "labelLocation"
+#endif
+#ifndef XmCLocation
+# define XmCLocation "Location"
+#endif
+
+#ifndef XmNpixmapData
+# define XmNpixmapData "pixmapData"
+#endif
+
+#ifndef XmNpixmapFile
+# define XmNpixmapFile "pixmapFile"
+#endif
+
+/*
+ * Constants for labelLocation.
+ */
+#ifdef HAVE_XM_JOINSIDET_H
+# include <Xm/JoinSideT.h>
+#else
+# define XmLEFT 1
+# define XmRIGHT 2
+# define XmTOP 3
+# define XmBOTTOM 4
+#endif
+
+#define XmIsEnhancedButton(w) XtIsSubclass(w, xmEnhancedButtonWidgetClass)
+
+/*
+ * Convenience creation function.
+ */
+extern Widget XgCreateEPushButtonWidget(Widget, char *, ArgList, Cardinal);
+
+extern WidgetClass xmEnhancedButtonWidgetClass;
+typedef struct _XmEnhancedButtonClassRec *XmEnhancedButtonWidgetClass;
+typedef struct _XmEnhancedButtonRec *XmEnhancedButtonWidget;
+
+#endif
diff --git a/src/gui_xmebwp.h b/src/gui_xmebwp.h
new file mode 100644
index 0000000..9dcdf31
--- /dev/null
+++ b/src/gui_xmebwp.h
@@ -0,0 +1,88 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+/*
+ *
+ * (C) 2002,2005 by Marcin Dalecki <martin@dalecki.de>
+ *
+ * MARCIN DALECKI ASSUMES NO RESPONSIBILITY FOR THE USE OR INABILITY TO USE ANY
+ * OF THIS SOFTWARE . THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
+ * KIND, AND MARCIN DALECKI EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES,
+ * INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef EnhancedBP_H
+#define EnhancedBP_H
+
+#include <Xm/PushBP.h>
+
+#include "gui_xmebw.h"
+
+
+/*
+ * EnhancedButton class structure.
+ */
+typedef struct _XmEnhancedButtonClassPart
+{
+ Pixmap stipple_bitmap;
+} XmEnhancedButtonClassPart;
+
+/*
+ * Full class record declaration for EnhancedButton class.
+ */
+typedef struct
+{
+ CoreClassPart core_class;
+ XmPrimitiveClassPart primitive_class;
+ XmLabelClassPart label_class;
+ XmPushButtonClassPart pushbutton_class;
+ XmEnhancedButtonClassPart enhancedbutton_class;
+} XmEnhancedButtonClassRec;
+
+
+extern XmEnhancedButtonClassRec xmEnhancedButtonClassRec;
+
+/*
+ * EnhancedButton instance record.
+ */
+typedef struct _XmEnhancedButtonPart
+{
+ /* public resources */
+ String pixmap_data;
+ String pixmap_file;
+ Dimension spacing;
+ int label_location;
+
+ /* private resources */
+ int pixmap_depth;
+ Dimension pixmap_width;
+ Dimension pixmap_height;
+ Pixmap normal_pixmap;
+ Pixmap armed_pixmap;
+ Pixmap insensitive_pixmap;
+ Pixmap highlight_pixmap;
+
+ int doing_setvalues;
+ int doing_destroy;
+} XmEnhancedButtonPart;
+
+
+/*
+ * Full instance record declaration.
+ */
+typedef struct _XmEnhancedButtonRec
+{
+ CorePart core;
+ XmPrimitivePart primitive;
+ XmLabelPart label;
+ XmPushButtonPart pushbutton;
+ XmEnhancedButtonPart enhancedbutton;
+} XmEnhancedButtonRec;
+
+#endif
diff --git a/src/gvim.exe.mnf b/src/gvim.exe.mnf
new file mode 100644
index 0000000..dd8f225
--- /dev/null
+++ b/src/gvim.exe.mnf
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" >
+ <assemblyIdentity
+ processorArchitecture="*"
+ version="8.1.0.0"
+ type="win32"
+ name="Vim"
+ />
+ <description>Vi Improved - A Text Editor</description>
+ <dependency>
+ <dependentAssembly>
+ <assemblyIdentity
+ type="win32"
+ name="Microsoft.Windows.Common-Controls"
+ version="6.0.0.0"
+ publicKeyToken="6595b64144ccf1df"
+ language="*"
+ processorArchitecture="*"
+ />
+ </dependentAssembly>
+ </dependency>
+ <!-- Vista security requirements -->
+ <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
+ <security>
+ <requestedPrivileges>
+ <requestedExecutionLevel
+ level="asInvoker"
+ uiAccess="false"/>
+ </requestedPrivileges>
+ </security>
+ </trustInfo>
+ <!-- Vista High DPI aware -->
+ <asmv3:application>
+ <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
+ <dpiAware>true</dpiAware>
+ </asmv3:windowsSettings>
+ </asmv3:application>
+</assembly>
diff --git a/src/gvimtutor b/src/gvimtutor
new file mode 100644
index 0000000..c452043
--- /dev/null
+++ b/src/gvimtutor
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+# Start GUI Vim on a copy of the tutor file.
+
+# Usage: gvimtutor [xx]
+# See vimtutor for usage.
+
+exec `dirname $0`/vimtutor -g "$@"
diff --git a/src/hangulin.c b/src/hangulin.c
new file mode 100644
index 0000000..e08fe63
--- /dev/null
+++ b/src/hangulin.c
@@ -0,0 +1,1641 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+#include "vim.h"
+
+#ifndef HANGUL_DEFAULT_KEYBOARD
+# define HANGUL_DEFAULT_KEYBOARD 3
+#endif
+
+#define AUTOMATA_NEW 0
+#define AUTOMATA_CORRECT 1
+#define AUTOMATA_SPECIAL 2
+#define AUTOMATA_CORRECT_NEW 3
+#define AUTOMATA_ERROR 4
+#define AUTOMATA_NULL 5
+
+#define F_F 0x1 /* Ãʼº (initial sound) */
+#define F_M 0x2 /* Áß¼º (medial vowel) */
+#define F_L 0x4 /* Á¾¼º (final consonant) */
+#define F_A 0x8 /* ASCII */
+#define F_NULL 1
+#define M_NULL 2
+#define L_NULL 1
+
+static int hangul_input_state = 0;
+static int f=F_NULL, m=M_NULL, l=L_NULL;
+static int sp=0;
+static char_u stack[20] = {0};
+static int last_l = -1, last_ll = -1;
+static int hangul_keyboard_type = HANGUL_DEFAULT_KEYBOARD;
+
+static void convert_ks_to_3(const char_u *src, int *fp, int *mp, int *lp);
+static int convert_3_to_ks(int fv, int mv, int lv, char_u *des);
+
+#define push(x) {stack[ sp++ ] = *(x); stack[sp++] = *((x)+1);}
+#define pop(x) {*((x) + 1) = stack[--sp]; *(x) = stack[--sp];}
+#define query(x) {*((x) + 1) = stack[sp - 1]; *(x) = stack[sp - 2];}
+
+#define convert_3_to_code convert_3_to_ks
+
+
+/**********************************************************************/
+/****** 3 ¹ú½ÄÀÚÆÇÀ» À§ÇÑ ·çƾ (Routines for 3 bulsik keyboard) ******/
+/**********************************************************************/
+
+/* 3 ¹ú½Ä¿¡¼­ ÀÚÆÇ º¯È¯ (3 bulsik keyboard conversion) */
+
+static char_u value_table_for_3[] =
+{
+ 24 , '"' , '#' , '$' , '%' , '&' , /* ! " # $ % & */
+ 18 , '(' , ')' , '*' , '+' , ',' , /* ' ( ) * + , */
+ '-' , '.' , 13 , 17 , 29 , 22 , /* - . / 0 1 2 */
+ 19 , 19 , 26 , 5 , 12 , 28 , /* 3 4 5 6 7 8 */
+ 20 , ':' , 9 , '2' , '=' , '3' , /* 9 : ; < = > */
+ '?' , '@' , 8 , '!' , 11 , 10 , /* ? @ A B C D */
+ 26 , 3 , '/' , 39 , '8' , '4' , /* E F G H I J */
+ '5' , '6' , '1' , '0' , '9' , '>' , /* K L M N O P */
+ 28 , 6 , 7 , ';' , '7' , 16 , /* Q R S T U V */
+ 27 , 20 , '<' , 25 , '[' , 92 , /* W X Y Z [ \ */
+ ']' , '^' , '_' , '`' , 23 , 20 , /* ] ^ _ ` a b */
+ 10 , 29 , 11 , 3 , 27 , 4 , /* c d e f g h */
+ 8 , 13 , 2 , 14 , 20 , 11 , /* i j k l m n */
+ 16 , 19 , 21 , 4 , 5 , 7 , /* o p q r s t */
+ 5 , 13 , 9 , 2 , 7 , 17 , /* u v w x y z */
+};
+
+static short_u kind_table_for_3[] =
+{
+ F_L, F_A, F_A, F_A, F_A, F_A, /* ! " # $ % & */
+ F_F, F_A, F_A, F_A, F_A, F_A, /* ' ( ) * + , */
+ F_A, F_A, F_M, F_F, F_L, F_L, /* - . / 0 1 2 */
+ F_L, F_M, F_M, F_M, F_M, F_M, /* 3 4 5 6 7 8 */
+ F_M, F_A, F_F, F_A, F_A, F_A, /* 9 : ; < = > */
+ F_A, F_A, F_L, F_A, F_L, F_L, /* ? @ A B C D */
+ F_L, F_L, F_A, F_A, F_A, F_A, /* E F G H I J */
+ F_A, F_A, F_A, F_A, F_A, F_A, /* K L M N O P */
+ F_L, F_M, F_L, F_A, F_A, F_L, /* Q R S T U V */
+ F_L, F_L, F_A, F_L, F_A, F_A, /* W X Y Z [ \ */
+ F_A, F_A, F_A, F_A, F_L, F_M, /* ] ^ _ ` a b */
+ F_M, F_M, F_M, F_M, F_M, F_F, /* c d e f g h */
+ F_F, F_F, F_F, F_F, F_F, F_F, /* i j k l m n */
+ F_F, F_F, F_L, F_M, F_L, F_M, /* o p q r s t */
+ F_F, F_M, F_L, F_L, F_F, F_L, /* u v w x y z */
+};
+
+/* 3 ¹ú½Ä¿¡¼­ (ÇöÀçÃʼº, ÀԷ¿µ¹®) -> º¹ÇÕÃʼº ó¸®
+ * 3 bulsik: (current initial sound, input english) -> compound initial sound.
+ */
+
+ static int
+comfcon3(int v, int c)
+{
+ if (v == 2 && c == 2)
+ return 3;
+ if (v == 5 && c == 5)
+ return 6;
+ if (v == 9 && c == 9)
+ return 10;
+ if (v == 11 && c == 11)
+ return 12;
+ if (v == 14 && c == 14)
+ return 15;
+ return 0;
+}
+
+/* 3 ¹ú½Ä¿¡¼­ (ÇöÀç¸ðÀ½, ÀÔ·Â ¿µ¹®) -> º¹ÇÕ ¸ðÀ½ ó¸®
+ * 3 bulsik: (current vowel, input english) -> compound vowel.
+ */
+
+ static int
+comvow3(int v, int c)
+{
+ switch (v)
+ {
+ case 13: /* ¤Ç */
+ switch (c) {
+ case 3: /* ¤Ç¤¿ */
+ return 14;
+ case 4: /* ¤Ç¤À */
+ return 15;
+ case 29: /* ¤Ç¤Ó */
+ return 18;
+ }
+ break;
+
+ case 20: /* ¤Ì */
+ switch (c) {
+ case 7: /* ¤Ì¤Ã */
+ return 21;
+ case 10: /* ¤Ì¤Ä */
+ return 22;
+ case 29: /* ¤Ì¤Ó */
+ return 23;
+ }
+ break;
+
+ /* 3 ¹ú½Ä ÀÚÆÇÀº ¤Ñ¤Ó °¡ ÀÖÀ¸¹Ç·Î ... */
+ }
+ return 0;
+}
+
+/* 3 ¹ú½Ä¿¡¼­ (ÇöÀç ¹Þħ, ¿µ¹®ÀÚ ÀÔ·Â) -> ¹Þħ
+ * 3 bulsik: (current prop(?), input english) -> prop(?).
+ * I want to say, the 'prop' is similar to 'final consonant', but not vowel.
+ * (I cannot find the real english from my dictionary. Sorry!)
+ * VIM: V = initial sound, I = medial vowel, M = final consonant.
+ */
+
+ static int
+comcon3(int k, int c)
+{
+ switch (k)
+ {
+ case 2: /* ¤¡ */
+ switch (c) {
+ case 2:
+ return 3; /* ¤¡¤¡ */
+ case 21:
+ return 4; /* ¤¡¤µ */
+ }
+ break;
+
+ case 5: /* ¤¤ */
+ switch (c) {
+ case 24: /* ¤¤¤¸ */
+ return 6;
+ case 29:
+ return 7; /* ¤¤¤¾ */
+ }
+ break;
+
+ case 9: /* ¤© */
+ switch (c) {
+ case 2: /* ¤©¤¡ */
+ return 10;
+ case 17: /* ¤©¤± */
+ return 11;
+ case 19: /* ¤©¤² */
+ return 12;
+ case 21: /* ¤©¤µ */
+ return 13;
+ case 27: /* ¤©¤¼ */
+ return 14;
+ case 28: /* ¤©¤½ */
+ return 15;
+ case 29: /* ¤©¤¾ */
+ return 16;
+ }
+ break;
+
+ case 19:
+ switch (c) {
+ case 21: /* ¤²¤µ */
+ return 20;
+ }
+ break;
+ }
+ return 0;
+}
+
+/**********************************************************************/
+/****** 2 ¹ú½ÄÀÚÆÇÀ» À§ÇÑ ·çƾ (Routines for 2 bulsik keyboard) ******/
+/**********************************************************************/
+
+ static int
+kind_table_for_2(int c)
+{
+ static char_u table[] =
+ {
+ /* a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s */
+ 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0,
+ /* t, u, v, w, x, y, z */
+ 0, 1, 0, 0, 0, 1, 0
+ };
+
+ if (c <= 'Z')
+ c -= 'A';
+ else
+ c -= 'a';
+
+ return table[c];
+}
+
+/* 2 ¹ú½Ä¿¡¼­ ¿µ¹®ÀÚ -> Á¶ÇÕÇü Ãʼº º¯È¯
+ * (2 bulsik: conversion english char. to initial sound of compound type)
+ * °á°ú: ÃʼºÀÌ ¾Æ´Ï¸é 0 (If it is not initial sound, return 0).
+ */
+ static int
+fcon(int c)
+{
+ static char_u table[] =
+ {
+ /*E */ 6 , /*F */ 0 , /*G */ 0 , /*H */ 0 , /*I */ 0 , /*J */ 0 , /*K */ 0 ,
+ /*L */ 0 , /*M */ 0 , /*N */ 0 , /*O */ 0 , /*P */ 0 , /*Q */ 10, /*R */ 3 ,
+ /*S */ 0 , /*T */ 12, /*U */ 0 , /*V */ 0 , /*W */ 15, /*X */ 0 , /*Y */ 0 ,
+ /*Z */ 0 , /*[ */ 0 , /*\ */ 0 , /*] */ 0 , /*^ */ 0 , /*_ */ 0 , /*` */ 0 ,
+ /*a */ 8 , /*b */ 0 , /*c */ 16, /*d */ 13, /*e */ 5 , /*f */ 7 , /*g */ 20,
+ /*h */ 0 , /*i */ 0 , /*j */ 0 , /*k */ 0 , /*l */ 0 , /*m */ 0 , /*n */ 0 ,
+ /*o */ 0 , /*p */ 0 , /*q */ 9 , /*r */ 2 , /*s */ 4 , /*t */ 11, /*u */ 0 ,
+ /*v */ 19, /*w */ 14, /*x */ 18, /*y */ 0 , /*z */ 17
+ };
+
+ if (c < 'E' || c > 'z')
+ return 0;
+ return table[c - 'E'];
+}
+
+/* 2 ¹ú½Ä¿¡¼­ ¿µ¹®ÀÚ -> Áß¼º º¯È¯
+ * (2 bulsik: conversion english char. to medial vowel)
+ * °á°ú: Áß¼ºÀÌ ¾Æ´Ï¸é 0 (If it is not medial vowel, return 0).
+ */
+ static int
+vow(int c)
+{
+ static char_u table[] =
+ {
+ /*O */ 6 , /*P */ 12, /*Q */ 0 , /*R */ 0 , /*S */ 0 , /*T */ 0 , /*U */ 0 ,
+ /*V */ 0 , /*W */ 0 , /*X */ 0 , /*Y */ 0 , /*Z */ 0 , /*[ */ 0 , /*\ */ 0 ,
+ /*] */ 0 , /*^ */ 0 , /*_ */ 0 , /*` */ 0 , /*a */ 0 , /*b */ 26, /*c */ 0 ,
+ /*d */ 0 , /*e */ 0 , /*f */ 0 , /*g */ 0 , /*h */ 13, /*i */ 5 , /*j */ 7 ,
+ /*k */ 3 , /*l */ 29, /*m */ 27, /*n */ 20, /*o */ 4 , /*p */ 10, /*q */ 0 ,
+ /*r */ 0 , /*s */ 0 , /*t */ 0 , /*u */ 11, /*v */ 0 , /*w */ 0 , /*x */ 0 ,
+ /*y */ 19};
+
+ if (c < 'O' || c > 'y')
+ return 0;
+ return table[c - 'O'];
+}
+
+/* 2¹ú½Ä¿¡¼­ ¿µ¹®ÀÚ -> ¹Þħ º¯È¯
+ * (2 bulsik: conversion english char. to prop)
+ * °á°ú: ¹ÞħÀÌ ¾Æ´Ï¸é 0 (If not prop, return 0)
+ */
+ static int
+lcon(int c)
+{
+ static char_u table[] =
+ {
+ /*R */ 3 , /*S */ 0 , /*T */ 22, /*U */ 0 , /*V */ 0 , /*W */ 0 , /*X */ 0 ,
+ /*Y */ 0 , /*Z */ 0 , /*[ */ 0 , /*\ */ 0 , /*] */ 0 , /*^ */ 0 , /*_ */ 0 ,
+ /*` */ 0 , /*a */ 17, /*b */ 0 , /*c */ 25, /*d */ 23, /*e */ 8 , /*f */ 9 ,
+ /*g */ 29, /*h */ 0 , /*i */ 0 , /*j */ 0 , /*k */ 0 , /*l */ 0 , /*m */ 0 ,
+ /*n */ 0 , /*o */ 0 , /*p */ 0 , /*q */ 19, /*r */ 2 , /*s */ 5 , /*t */ 21,
+ /*u */ 0 , /*v */ 28, /*w */ 24, /*x */ 27, /*y */ 0 , /*z */ 26
+ };
+
+ if (c < 'R' || c > 'z')
+ return 0;
+ return table[c - 'R'];
+}
+
+/* 2 ¹ú½Ä¿¡¼­ (ÇöÀç ¹Þħ, ¿µ¹®ÀÚ ÀÔ·Â) -> ¹Þħ º¯È¯
+ * (2 bulsik: conversion (curr. prop, input english) to prop)
+ */
+
+ static int
+comcon2(int k, int c)
+{
+ switch (k)
+ {
+ case 2: /* ¤¡ */
+ switch (c) {
+ case 't':
+ return 4; /* ¤¡¤µ */
+ }
+ break;
+
+ case 5: /* ¤¤ */
+ switch (c) {
+ case 'w': /* ¤¤¤¸ */
+ return 6;
+ case 'g': /* ¤¤¤¾ */
+ return 7;
+ }
+ break;
+
+ case 9: /* ¤© */
+ switch (c) {
+ case 'r': /* ¤©¤¡ */
+ return 10;
+ case 'a': /* ¤©¤± */
+ return 11;
+ case 'q': /* ¤©¤² */
+ return 12;
+ case 't': /* ¤©¤µ */
+ return 13;
+ case 'x': /* ¤©¤¼ */
+ return 14;
+ case 'v': /* ¤©¤½ */
+ return 15;
+ case 'g': /* ¤©¤¾ */
+ return 16;
+ }
+ break;
+
+ case 19: /* ¤² */
+ switch (c) {
+ case 't': /* ¤²¤µ */
+ return 20;
+ }
+ break;
+ }
+ return 0;
+}
+
+/* 2¹ú½Ä¿¡¼­ (ÇöÀç Áß¼º, ¿µ¹® ÀÔ·Â) -> Áß¼º º¯È¯
+ * (2 bulsik: conversion (curr. medial vowel, input english) to medial
+ * vowel)
+ */
+
+ static int
+comvow2(int v, int c)
+{
+ switch (v)
+ {
+ case 13: /* ¤Ç */
+ switch (c) {
+ case 'k': /* ¤Ç¤¿ */
+ return 14;
+ case 'o': /* ¤Ç¤À */
+ return 15;
+ case 'l': /* ¤Ç¤Ó */
+ return 18;
+ }
+ break;
+
+ case 20: /* ¤Ì */
+ switch (c) {
+ case 'j': /* ¤Ì¤Ã */
+ return 21;
+ case 'p': /* ¤Ì¤Ä */
+ return 22;
+ case 'l': /* ¤Ì¤Ó */
+ return 23;
+ }
+ break;
+
+ case 27: /* ¤Ñ */
+ switch (c) {
+ case 'l': /* ¤Ñ¤Ó */
+ return 28;
+ }
+ break;
+ }
+ return 0;
+}
+
+ int
+hangul_input_state_get(void)
+{
+ return hangul_input_state;
+}
+
+ void
+hangul_input_state_set(int state)
+{
+ hangul_input_state = state;
+ hangul_input_clear();
+}
+
+ int
+im_get_status(void)
+{
+ return hangul_input_state_get();
+}
+
+ void
+hangul_input_state_toggle(void)
+{
+ if (hangul_input_state_get())
+ {
+ hangul_input_state_set(0);
+ if (composing_hangul)
+ {
+ push_raw_key(composing_hangul_buffer, 2);
+ composing_hangul = 0;
+ }
+ }
+ else
+ hangul_input_state_set(1);
+
+ if (showmode())
+ {
+ setcursor();
+ out_flush();
+ }
+
+ gui_update_cursor(TRUE, FALSE);
+}
+
+ static int
+hangul_automata2(char_u *buf, int_u *c)
+{
+ int t,t2;
+
+ if (*c == BS)
+ {
+ if (sp == 0)
+ return AUTOMATA_SPECIAL;
+ else if (sp < 4)
+ {
+ hangul_input_clear();
+ return AUTOMATA_NULL;
+ }
+ pop(buf);
+ query(buf);
+ convert_ks_to_3(buf, &f, &m, &l);
+ last_l = last_ll;
+ last_ll = -1;
+ return AUTOMATA_CORRECT;
+ }
+ if ((!(*c >= 'A' && *c <= 'Z')) && (!(*c >= 'a' && *c <= 'z')))
+ {
+ hangul_input_clear();
+ return AUTOMATA_SPECIAL;
+ }
+ t = *c;
+ switch (kind_table_for_2(t))
+ {
+ case 0: /* ÀÚÀ½ (consonant) */
+ if (f == F_NULL)
+ {
+ if (m != M_NULL)
+ hangul_input_clear();
+ f = fcon(t);
+ convert_3_to_code(f, M_NULL, L_NULL, buf);
+ push(buf);
+ last_ll = last_l = -1;
+ return AUTOMATA_NEW;
+ }
+ if (m == M_NULL)
+ return AUTOMATA_ERROR;
+ if (l == L_NULL)
+ {
+ t2 = lcon(t);
+ if (!t2) /* ¹ÞħÀ¸·Î ÀûÇÕÇÏÁö¾Ê´Ù (cannot use it as a prop) */
+ {
+ hangul_input_clear();
+ last_ll = last_l = -1;
+ f = fcon(t);
+ convert_3_to_code(f, m, l, buf);
+ push(buf);
+ return AUTOMATA_NEW;
+ }
+ if (2 == convert_3_to_code(f, m, t2, buf))
+ {
+ last_ll = -1;
+ last_l = t;
+ l = t2;
+ push(buf);
+ return AUTOMATA_CORRECT;
+ }
+ else /* ¹ÞħÀ¸·Î ¾²·ÁÇÏ¿´À¸³ª code¿¡ ¾ø´Â ±ÛÀÚÀÌ´Ù */
+ { /* cannot find such a prop in the code table */
+ last_ll = last_l = -1;
+ hangul_input_clear();
+ f = fcon(t);
+ convert_3_to_code(f, m, l, buf);
+ push(buf);
+ return AUTOMATA_NEW;
+ }
+ }
+ /* ÃÊ Áß Á¾¼ºÀÌ ¸ðµÎ °®Ãß¾îÁ® ÀÖ´Ù
+ * I have all the 'initial sound' and 'medial vowel' and 'final
+ * consonant'.
+ */
+ t2 = comcon2(l, t);
+ if (t2)
+ {
+ if (2 == convert_3_to_code(f, m, t2, buf))
+ {
+ l = t2;
+ last_ll = last_l;
+ last_l = t;
+ push(buf);
+ return AUTOMATA_CORRECT;
+ }
+ }
+ last_ll = last_l = -1;
+ hangul_input_clear();
+ f = fcon(t);
+ convert_3_to_code(f, m, l, buf);
+ push(buf);
+ return AUTOMATA_NEW;
+
+ case 1:
+ if (f == F_NULL)
+ {
+ hangul_input_clear();
+ m = vow(t);
+ convert_3_to_code (f, m, L_NULL, buf);
+ push (buf);
+ last_ll = last_l = -1;
+ return AUTOMATA_NEW;
+ }
+ if (m == M_NULL)
+ {
+ m = vow(t);
+ if (2 == convert_3_to_code(f, m, L_NULL, buf))
+ {
+ last_ll = last_l = -1;
+ push(buf);
+ return AUTOMATA_CORRECT;
+ }
+ m = M_NULL;
+ return AUTOMATA_ERROR;
+ }
+ if (l == L_NULL)
+ {
+ t2 = comvow2(m, t);
+ if (t2)
+ {
+ if (2 != convert_3_to_code(f, t2, L_NULL, buf))
+ return AUTOMATA_ERROR;
+
+ m = t2;
+ push(buf);
+ last_ll = last_l = -1;
+ return AUTOMATA_CORRECT;
+ }
+ return AUTOMATA_ERROR;
+ }
+ pop(buf);
+ pop(buf);
+ sp = 0;
+ if (last_l == -1)
+ {
+ /* À½... ÀÌ°Ô ÇÊ¿äÇϳª?? (Hmm... Is it needed?) */
+ convert_ks_to_3(buf, &f, &m, &l);
+ }
+ else
+ {
+ char_u tmp[3];
+ f = fcon(last_l);
+ convert_3_to_code (f, M_NULL, L_NULL, tmp);
+ push (tmp);
+ }
+ m = vow(t);
+ l = L_NULL;
+ convert_3_to_code(f, m, l, buf + 2);
+ push(buf + 2);
+ return AUTOMATA_CORRECT_NEW;
+
+ default:
+ iemsg(_("E256: Hangul automata ERROR"));
+ break;
+ }
+ return AUTOMATA_ERROR; /* RrEeAaLlLlYy EeRrRrOoRr */
+}
+
+ static int
+hangul_automata3(char_u *buf, int_u *c)
+{
+ int t, t2;
+
+ if (*c >= '!' && *c <= 'z')
+ {
+ *c -= '!';
+ t = value_table_for_3[*c];
+ switch (kind_table_for_3[*c])
+ {
+ case F_F: /* Ãʼº¹®ÀÚ (char. of an initial sound) */
+ if (m != M_NULL || sp == 0)
+ {
+ /* ÃʼºÀÌ ºñ¾ú°Å³ª ´ÙÀ½ ±ÛÀÚ ¸ðÀ¸±â ½ÃÀÛ
+ * Empty 'initial sound', so starting automata.
+ */
+ hangul_input_clear();
+ f = t;
+ convert_3_to_code(f, M_NULL, L_NULL, buf);
+ push(buf);
+ return AUTOMATA_NEW;
+ }
+ if ((t2 = comfcon3(f,t)) != 0) /* º¹ÀÚÀ½ (double? consonant) */
+ {
+ f=t2;
+ convert_3_to_code(f, M_NULL, L_NULL, buf);
+ push(buf);
+ return AUTOMATA_CORRECT;
+ }
+ return AUTOMATA_ERROR;
+
+ case F_M: /* ¸ðÀ½ (vowel) */
+ if (m == M_NULL)
+ {
+ if (2 != convert_3_to_code(f, t, L_NULL,buf))
+ return AUTOMATA_ERROR;
+
+ m = t;
+ push(buf);
+ if (f == F_NULL)
+ return AUTOMATA_NEW;
+ else
+ return AUTOMATA_CORRECT;
+ }
+ if ((t2 = comvow3(m,t))) /* º¹¸ðÀ½ (a diphthong) */
+ {
+ m = t2;
+ convert_3_to_code(f, m, L_NULL, buf);
+ push(buf);
+ return AUTOMATA_CORRECT;
+ }
+ return AUTOMATA_ERROR;
+
+ case F_L: /* ¹Þħ (prop?) */
+ if (m == M_NULL)
+ return AUTOMATA_ERROR; /* Áß¼º¾ø´Â Á¾¼º */
+ if (l == L_NULL)
+ {
+ if (2 != convert_3_to_code(f, m, t, buf))
+ {
+ l = L_NULL;
+ return AUTOMATA_ERROR;
+ }
+ push(buf);
+ l = t;
+ return AUTOMATA_CORRECT;
+ }
+ if ((t2 = comcon3(l,t)) != 0) /* º¹ ¹Þħ ?? (double prop?) */
+ {
+ if (2 != convert_3_to_code(f, m, t2, buf))
+ return AUTOMATA_ERROR;
+
+ push(buf);
+ l = t2;
+ return AUTOMATA_CORRECT;
+ }
+ return AUTOMATA_ERROR;
+
+ case F_A: /* Ư¼ö¹®ÀÚ³ª ¼ýÀÚ (special char. or number) */
+ hangul_input_clear();
+ *c = t;
+ return AUTOMATA_SPECIAL;
+ }
+ }
+ if (*c == BS)
+ {
+ if (sp >= 4)
+ {
+ pop(buf);
+ pop(buf);
+ convert_ks_to_3(buf, &f, &m, &l);
+ push(buf);
+ return AUTOMATA_CORRECT;
+ }
+ else if (sp == 0)
+ {
+ return AUTOMATA_SPECIAL;
+ }
+ else
+ {
+ hangul_input_clear();
+ return AUTOMATA_NULL;
+ }
+ }
+ hangul_input_clear();
+ return AUTOMATA_SPECIAL;
+}
+
+ void
+hangul_keyboard_set(void)
+{
+ int keyboard;
+ char *s;
+
+ hangul_input_clear();
+
+ if ((s = getenv("VIM_KEYBOARD")) == NULL)
+ s = getenv("HANGUL_KEYBOARD_TYPE");
+
+ if (s)
+ {
+ if (*s == '2')
+ keyboard = 2;
+ else
+ keyboard = 3;
+ hangul_keyboard_type = keyboard;
+ }
+}
+
+ int
+hangul_input_process(char_u *s, int len)
+{
+ int n;
+ unsigned int c;
+ char_u hanbuf[20];
+
+ if (len == 1)
+ /* normal key press */
+ c = *s;
+ else if (len == 3 && s[0] == CSI && s[1] == 'k' && s[2] == 'b')
+ {
+ /* backspace */
+ if (composing_hangul)
+ c = Ctrl_H;
+ else
+ return len;
+ }
+ else
+ {
+ if (composing_hangul)
+ push_raw_key(composing_hangul_buffer, 2);
+ hangul_input_clear();
+ composing_hangul = 0;
+ return len;
+ }
+
+ if (hangul_keyboard_type == 2)
+ n = hangul_automata2(hanbuf, &c);
+ else
+ n = hangul_automata3(hanbuf, &c);
+
+ if (n == AUTOMATA_CORRECT)
+ {
+ STRNCPY(composing_hangul_buffer, hanbuf, 2);
+ gui_update_cursor(TRUE, FALSE);
+ return 0;
+ }
+ else if (n == AUTOMATA_NEW)
+ {
+ if (composing_hangul)
+ push_raw_key(composing_hangul_buffer, 2);
+ STRNCPY(composing_hangul_buffer, hanbuf, 2);
+ composing_hangul = 1;
+ gui_update_cursor(TRUE, FALSE);
+ return 0;
+ }
+ else if (n == AUTOMATA_CORRECT_NEW)
+ {
+ if (composing_hangul)
+ push_raw_key(hanbuf, 2);
+ STRNCPY(composing_hangul_buffer, hanbuf+2, 2);
+ composing_hangul = 1;
+ gui_update_cursor(TRUE, FALSE);
+ return 0;
+ }
+ else if (n == AUTOMATA_NULL)
+ {
+ composing_hangul = 0;
+ gui_redraw_block(gui.cursor_row, gui.cursor_col,
+ gui.cursor_row, gui.cursor_col + 1,
+ GUI_MON_NOCLEAR);
+ gui_update_cursor(TRUE, FALSE);
+ return 0;
+ }
+ else if (n == AUTOMATA_SPECIAL)
+ {
+ if (composing_hangul)
+ {
+ push_raw_key(composing_hangul_buffer, 2);
+ composing_hangul = 0;
+ }
+ *s = c;
+ return 1;
+ }
+ else if (n == AUTOMATA_ERROR)
+ {
+ vim_beep(BO_HANGUL);
+ return 0;
+ }
+ return len;
+}
+
+ void
+hangul_input_clear(void)
+{
+ sp = 0;
+ f = F_NULL;
+ m = M_NULL;
+ l = L_NULL;
+}
+
+#define han_index(h, l) (((h)-0xb0)*(0xff-0xa1)+((l)-0xa1))
+
+static const char_u ks_table1[][3] =
+{
+ { 2, 3, 1}, { 2, 3, 2}, { 2, 3, 5}, { 2, 3, 8},
+ { 2, 3, 9}, { 2, 3, 10}, { 2, 3, 11}, { 2, 3, 17},
+ { 2, 3, 19}, { 2, 3, 20}, { 2, 3, 21}, { 2, 3, 22},
+ { 2, 3, 23}, { 2, 3, 24}, { 2, 3, 25}, { 2, 3, 27},
+ { 2, 3, 28}, { 2, 3, 29}, { 2, 4, 1}, { 2, 4, 2},
+ { 2, 4, 5}, { 2, 4, 9}, { 2, 4, 17}, { 2, 4, 19},
+ { 2, 4, 21}, { 2, 4, 22}, { 2, 4, 23}, { 2, 5, 1},
+ { 2, 5, 2}, { 2, 5, 5}, { 2, 5, 9}, { 2, 5, 21},
+ { 2, 5, 23}, { 2, 6, 1}, { 2, 6, 5}, { 2, 6, 9},
+ { 2, 7, 1}, { 2, 7, 2}, { 2, 7, 5}, { 2, 7, 8},
+ { 2, 7, 9}, { 2, 7, 11}, { 2, 7, 17}, { 2, 7, 19},
+ { 2, 7, 21}, { 2, 7, 22}, { 2, 7, 23}, { 2, 7, 24},
+ { 2, 7, 27}, { 2, 7, 28}, { 2, 7, 29}, { 2, 10, 1},
+ { 2, 10, 5}, { 2, 10, 9}, { 2, 10, 17}, { 2, 10, 19},
+ { 2, 10, 21}, { 2, 10, 22}, { 2, 10, 23}, { 2, 11, 1},
+ { 2, 11, 2}, { 2, 11, 3}, { 2, 11, 5}, { 2, 11, 8},
+ { 2, 11, 9}, { 2, 11, 17}, { 2, 11, 19}, { 2, 11, 21},
+ { 2, 11, 22}, { 2, 11, 23}, { 2, 11, 27}, { 2, 12, 1},
+ { 2, 12, 5}, { 2, 12, 9}, { 2, 12, 19}, { 2, 12, 21},
+ { 2, 13, 1}, { 2, 13, 2}, { 2, 13, 5}, { 2, 13, 8},
+ { 2, 13, 9}, { 2, 13, 11}, { 2, 13, 13}, { 2, 13, 16},
+ { 2, 13, 17}, { 2, 13, 19}, { 2, 13, 21}, { 2, 13, 23},
+ { 2, 13, 24}, { 2, 14, 1}, { 2, 14, 2}, { 2, 14, 5},
+ { 2, 14, 9}, { 2, 14, 11}, { 2, 14, 17}, { 2, 14, 19},
+ { 2, 14, 21}, { 2, 14, 23}, { 2, 15, 1}, { 2, 15, 5},
+ { 2, 15, 9}, { 2, 15, 19}, { 2, 15, 22}, { 2, 15, 23},
+ { 2, 18, 1}, { 2, 18, 2}, { 2, 18, 5}, { 2, 18, 9},
+ { 2, 18, 17}, { 2, 18, 19}, { 2, 18, 21}, { 2, 18, 23},
+ { 2, 19, 1}, { 2, 19, 5}, { 2, 19, 9}, { 2, 19, 19},
+ { 2, 19, 21}, { 2, 20, 1}, { 2, 20, 2}, { 2, 20, 5},
+ { 2, 20, 8}, { 2, 20, 9}, { 2, 20, 10}, { 2, 20, 11},
+ { 2, 20, 16}, { 2, 20, 17}, { 2, 20, 19}, { 2, 20, 21},
+ { 2, 20, 23}, { 2, 20, 24}, { 2, 21, 1}, { 2, 21, 2},
+ { 2, 21, 5}, { 2, 21, 9}, { 2, 21, 22}, { 2, 21, 23},
+ { 2, 22, 1}, { 2, 22, 21}, { 2, 23, 1}, { 2, 23, 2},
+ { 2, 23, 5}, { 2, 23, 9}, { 2, 23, 17}, { 2, 23, 19},
+ { 2, 23, 21}, { 2, 26, 1}, { 2, 26, 5}, { 2, 26, 9},
+ { 2, 27, 1}, { 2, 27, 2}, { 2, 27, 5}, { 2, 27, 8},
+ { 2, 27, 9}, { 2, 27, 10}, { 2, 27, 17}, { 2, 27, 19},
+ { 2, 27, 21}, { 2, 27, 23}, { 2, 28, 1}, { 2, 29, 1},
+ { 2, 29, 2}, { 2, 29, 5}, { 2, 29, 8}, { 2, 29, 9},
+ { 2, 29, 11}, { 2, 29, 17}, { 2, 29, 19}, { 2, 29, 21},
+ { 2, 29, 23}, { 2, 29, 24}, { 2, 29, 28}, { 3, 3, 1},
+ { 3, 3, 2}, { 3, 3, 3}, { 3, 3, 5}, { 3, 3, 9},
+ { 3, 3, 11}, { 3, 3, 17}, { 3, 3, 19}, { 3, 3, 21},
+ { 3, 3, 22}, { 3, 3, 23}, { 3, 3, 27}, { 3, 4, 1},
+ { 3, 4, 2}, { 3, 4, 5}, { 3, 4, 9}, { 3, 4, 17},
+ { 3, 4, 19}, { 3, 4, 21}, { 3, 4, 22}, { 3, 4, 23},
+ { 3, 5, 1}, { 3, 5, 2}, { 3, 5, 9}, { 3, 7, 1},
+ { 3, 7, 2}, { 3, 7, 3}, { 3, 7, 5}, { 3, 7, 9},
+ { 3, 7, 17}, { 3, 7, 19}, { 3, 7, 21}, { 3, 7, 22},
+ { 3, 7, 23}, { 3, 10, 1}, { 3, 10, 2}, { 3, 10, 5},
+ { 3, 10, 17}, { 3, 10, 21}, { 3, 10, 23}, { 3, 11, 1},
+ { 3, 11, 5}, { 3, 11, 9}, { 3, 11, 21}, { 3, 11, 22},
+ { 3, 11, 27}, { 3, 12, 1}, { 3, 13, 1}, { 3, 13, 2},
+ { 3, 13, 5}, { 3, 13, 7}, { 3, 13, 9}, { 3, 13, 17},
+ { 3, 13, 19}, { 3, 13, 21}, { 3, 13, 23}, { 3, 13, 24},
+ { 3, 13, 25}, { 3, 14, 1}, { 3, 14, 2}, { 3, 14, 9},
+ { 3, 14, 22}, { 3, 14, 23}, { 3, 15, 1}, { 3, 15, 2},
+ { 3, 15, 23}, { 3, 18, 1}, { 3, 18, 5}, { 3, 18, 9},
+ { 3, 18, 17}, { 3, 18, 19}, { 3, 18, 23}, { 3, 19, 1},
+ { 3, 20, 1}, { 3, 20, 2}, { 3, 20, 5}, { 3, 20, 9},
+ { 3, 20, 16}, { 3, 20, 17}, { 3, 20, 19}, { 3, 20, 21},
+ { 3, 20, 23}, { 3, 20, 24}, { 3, 21, 1}, { 3, 21, 9},
+ { 3, 21, 22}, { 3, 21, 23}, { 3, 22, 1}, { 3, 22, 2},
+ { 3, 22, 5}, { 3, 22, 9}, { 3, 22, 17}, { 3, 22, 19},
+ { 3, 22, 22}, { 3, 23, 1}, { 3, 23, 5}, { 3, 23, 9},
+ { 3, 23, 17}, { 3, 23, 19}, { 3, 26, 1}, { 3, 27, 1},
+ { 3, 27, 2}, { 3, 27, 5}, { 3, 27, 7}, { 3, 27, 9},
+ { 3, 27, 11}, { 3, 27, 16}, { 3, 27, 17}, { 3, 27, 19},
+ { 3, 27, 21}, { 3, 27, 23}, { 3, 27, 27}, { 3, 29, 1},
+ { 3, 29, 2}, { 3, 29, 5}, { 3, 29, 9}, { 3, 29, 17},
+ { 3, 29, 19}, { 3, 29, 21}, { 3, 29, 23}, { 4, 3, 1},
+ { 4, 3, 2}, { 4, 3, 3}, { 4, 3, 5}, { 4, 3, 8},
+ { 4, 3, 9}, { 4, 3, 10}, { 4, 3, 11}, { 4, 3, 17},
+ { 4, 3, 19}, { 4, 3, 21}, { 4, 3, 22}, { 4, 3, 23},
+ { 4, 3, 24}, { 4, 3, 25}, { 4, 3, 27}, { 4, 3, 29},
+ { 4, 4, 1}, { 4, 4, 2}, { 4, 4, 5}, { 4, 4, 9},
+ { 4, 4, 17}, { 4, 4, 19}, { 4, 4, 21}, { 4, 4, 22},
+ { 4, 4, 23}, { 4, 5, 1}, { 4, 5, 2}, { 4, 5, 5},
+ { 4, 5, 9}, { 4, 5, 17}, { 4, 5, 23}, { 4, 7, 1},
+ { 4, 7, 2}, { 4, 7, 4}, { 4, 7, 5}, { 4, 7, 9},
+ { 4, 7, 11}, { 4, 7, 12}, { 4, 7, 17}, { 4, 7, 19},
+ { 4, 7, 21}, { 4, 7, 22}, { 4, 7, 23}, { 4, 7, 29},
+ { 4, 10, 1}, { 4, 10, 2}, { 4, 10, 5}, { 4, 10, 9},
+ { 4, 10, 17}, { 4, 10, 19}, { 4, 10, 21}, { 4, 10, 22},
+ { 4, 10, 23}, { 4, 11, 1}, { 4, 11, 2}, { 4, 11, 5},
+ { 4, 11, 9}, { 4, 11, 17}, { 4, 11, 19}, { 4, 11, 22},
+ { 4, 11, 23}, { 4, 11, 26}, { 4, 12, 1}, { 4, 12, 5},
+ { 4, 13, 1}, { 4, 13, 2}, { 4, 13, 5}, { 4, 13, 9},
+ { 4, 13, 11}, { 4, 13, 17}, { 4, 13, 19}, { 4, 13, 21},
+ { 4, 13, 23}, { 4, 13, 28}, { 4, 13, 29}, { 4, 14, 1},
+ { 4, 14, 5}, { 4, 14, 9}, { 4, 14, 22}, { 4, 18, 1},
+ { 4, 18, 5}, { 4, 18, 9}, { 4, 18, 17}, { 4, 18, 19},
+ { 4, 18, 21}, { 4, 19, 1}, { 4, 19, 2}, { 4, 19, 5},
+ { 4, 19, 9}, { 4, 19, 19}, { 4, 19, 21}, { 4, 19, 23},
+ { 4, 20, 1}, { 4, 20, 2}, { 4, 20, 5}, { 4, 20, 8},
+ { 4, 20, 9}, { 4, 20, 17}, { 4, 20, 19}, { 4, 20, 21},
+ { 4, 20, 23}, { 4, 21, 1}, { 4, 21, 22}, { 4, 22, 1},
+ { 4, 23, 1}, { 4, 23, 5}, { 4, 23, 9}, { 4, 23, 17},
+ { 4, 23, 19}, { 4, 26, 1}, { 4, 26, 2}, { 4, 26, 9},
+ { 4, 26, 17}, { 4, 26, 19}, { 4, 26, 23}, { 4, 27, 1},
+ { 4, 27, 2}, { 4, 27, 5}, { 4, 27, 9}, { 4, 27, 10},
+ { 4, 27, 11}, { 4, 27, 17}, { 4, 27, 19}, { 4, 27, 21},
+ { 4, 27, 23}, { 4, 27, 24}, { 4, 27, 28}, { 4, 28, 1},
+ { 4, 28, 5}, { 4, 28, 9}, { 4, 29, 1}, { 4, 29, 2},
+ { 4, 29, 5}, { 4, 29, 9}, { 4, 29, 11}, { 4, 29, 17},
+ { 4, 29, 19}, { 4, 29, 21}, { 4, 29, 23}, { 4, 29, 28},
+ { 5, 3, 1}, { 5, 3, 2}, { 5, 3, 3}, { 5, 3, 5},
+ { 5, 3, 8}, { 5, 3, 9}, { 5, 3, 10}, { 5, 3, 11},
+ { 5, 3, 12}, { 5, 3, 16}, { 5, 3, 17}, { 5, 3, 19},
+ { 5, 3, 21}, { 5, 3, 22}, { 5, 3, 23}, { 5, 3, 24},
+ { 5, 3, 25}, { 5, 3, 29}, { 5, 4, 1}, { 5, 4, 2},
+ { 5, 4, 5}, { 5, 4, 9}, { 5, 4, 17}, { 5, 4, 19},
+ { 5, 4, 21}, { 5, 4, 22}, { 5, 4, 23}, { 5, 5, 1},
+ { 5, 7, 1}, { 5, 7, 2}, { 5, 7, 3}, { 5, 7, 5},
+ { 5, 7, 8}, { 5, 7, 9}, { 5, 7, 11}, { 5, 7, 12},
+ { 5, 7, 17}, { 5, 7, 19}, { 5, 7, 21}, { 5, 7, 23},
+ { 5, 7, 25}, { 5, 7, 28}, { 5, 10, 1}, { 5, 10, 2},
+ { 5, 10, 5}, { 5, 10, 9}, { 5, 10, 17}, { 5, 10, 19},
+ { 5, 10, 21}, { 5, 10, 22}, { 5, 10, 23}, { 5, 11, 1},
+ { 5, 11, 5}, { 5, 11, 9}, { 5, 11, 22}, { 5, 11, 23},
+ { 5, 12, 1}, { 5, 12, 5}, { 5, 13, 1}, { 5, 13, 2},
+ { 5, 13, 5}, { 5, 13, 8}, { 5, 13, 9}, { 5, 13, 11},
+ { 5, 13, 13}, { 5, 13, 17}, { 5, 13, 19}, { 5, 13, 21},
+ { 5, 13, 23}, { 5, 13, 25}, { 5, 13, 27}, { 5, 14, 1},
+ { 5, 14, 5}, { 5, 14, 9}, { 5, 15, 1}, { 5, 15, 22},
+ { 5, 18, 1}, { 5, 18, 5}, { 5, 18, 9}, { 5, 18, 17},
+ { 5, 18, 19}, { 5, 18, 21}, { 5, 19, 1}, { 5, 20, 1},
+ { 5, 20, 2}, { 5, 20, 5}, { 5, 20, 9}, { 5, 20, 17},
+ { 5, 20, 19}, { 5, 20, 21}, { 5, 20, 23}, { 5, 21, 1},
+ { 5, 21, 22}, { 5, 22, 1}, { 5, 22, 23}, { 5, 23, 1},
+ { 5, 23, 5}, { 5, 23, 9}, { 5, 23, 19}, { 5, 23, 21},
+ { 5, 23, 23}, { 5, 26, 1}, { 5, 26, 5}, { 5, 26, 9},
+ { 5, 26, 17}, { 5, 26, 23}, { 5, 27, 1}, { 5, 27, 2},
+ { 5, 27, 5}, { 5, 27, 8}, { 5, 27, 9}, { 5, 27, 11},
+ { 5, 27, 17}, { 5, 27, 19}, { 5, 27, 21}, { 5, 27, 23},
+ { 5, 28, 1}, { 5, 29, 1}, { 5, 29, 2}, { 5, 29, 5},
+ { 5, 29, 8}, { 5, 29, 9}, { 5, 29, 17}, { 5, 29, 19},
+ { 5, 29, 21}, { 5, 29, 22}, { 5, 29, 23}, { 5, 29, 24},
+ { 6, 3, 1}, { 6, 3, 2}, { 6, 3, 5}, { 6, 3, 9},
+ { 6, 3, 17}, { 6, 3, 19}, { 6, 3, 21}, { 6, 3, 22},
+ { 6, 3, 23}, { 6, 3, 29}, { 6, 4, 1}, { 6, 4, 2},
+ { 6, 4, 5}, { 6, 4, 9}, { 6, 4, 17}, { 6, 4, 19},
+ { 6, 4, 21}, { 6, 4, 22}, { 6, 4, 23}, { 6, 7, 1},
+ { 6, 7, 2}, { 6, 7, 5}, { 6, 7, 9}, { 6, 7, 11},
+ { 6, 7, 12}, { 6, 7, 17}, { 6, 7, 19}, { 6, 7, 21},
+ { 6, 7, 22}, { 6, 7, 23}, { 6, 7, 29}, { 6, 10, 1},
+ { 6, 10, 2}, { 6, 10, 5}, { 6, 10, 9}, { 6, 10, 17},
+ { 6, 10, 19}, { 6, 10, 21}, { 6, 10, 22}, { 6, 10, 23},
+ { 6, 11, 1}, { 6, 11, 22}, { 6, 13, 1}, { 6, 13, 2},
+ { 6, 13, 5}, { 6, 13, 9}, { 6, 13, 23}, { 6, 14, 1},
+ { 6, 14, 9}, { 6, 15, 1}, { 6, 18, 1}, { 6, 18, 5},
+ { 6, 20, 1}, { 6, 20, 2}, { 6, 20, 5}, { 6, 20, 9},
+ { 6, 20, 16}, { 6, 20, 17}, { 6, 20, 23}, { 6, 22, 1},
+ { 6, 23, 1}, { 6, 23, 5}, { 6, 23, 9}, { 6, 23, 17},
+ { 6, 23, 19}, { 6, 23, 23}, { 6, 27, 1}, { 6, 27, 2},
+ { 6, 27, 5}, { 6, 27, 8}, { 6, 27, 9}, { 6, 27, 17},
+ { 6, 27, 19}, { 6, 27, 21}, { 6, 28, 1}, { 6, 28, 5},
+ { 6, 28, 9}, { 6, 28, 17}, { 6, 28, 19}, { 6, 29, 1},
+ { 6, 29, 5}, { 6, 29, 9}, { 6, 29, 17}, { 6, 29, 19},
+ { 6, 29, 21}, { 6, 29, 23}, { 7, 3, 1}, { 7, 3, 2},
+ { 7, 3, 5}, { 7, 3, 9}, { 7, 3, 17}, { 7, 3, 19},
+ { 7, 3, 21}, { 7, 3, 22}, { 7, 3, 23}, { 7, 3, 24},
+ { 7, 3, 28}, { 7, 3, 29}, { 7, 4, 1}, { 7, 4, 2},
+ { 7, 4, 5}, { 7, 4, 9}, { 7, 4, 17}, { 7, 4, 19},
+ { 7, 4, 21}, { 7, 4, 22}, { 7, 4, 23}, { 7, 5, 1},
+ { 7, 5, 2}, { 7, 5, 5}, { 7, 5, 21}, { 7, 5, 23},
+ { 7, 7, 1}, { 7, 7, 2}, { 7, 7, 5}, { 7, 7, 9},
+ { 7, 7, 17}, { 7, 7, 19}, { 7, 7, 21}, { 7, 7, 22},
+ { 7, 7, 23}, { 7, 7, 29}, { 7, 10, 1}, { 7, 10, 2},
+ { 7, 10, 5}, { 7, 10, 9}, { 7, 10, 17}, { 7, 10, 19},
+ { 7, 10, 21}, { 7, 10, 23}, { 7, 11, 1}, { 7, 11, 2},
+ { 7, 11, 5}, { 7, 11, 9}, { 7, 11, 17}, { 7, 11, 19},
+ { 7, 11, 21}, { 7, 11, 22}, { 7, 11, 23}, { 7, 12, 1},
+ { 7, 12, 5}, { 7, 12, 19}, { 7, 12, 21}, { 7, 13, 1},
+ { 7, 13, 2}, { 7, 13, 5}, { 7, 13, 9}, { 7, 13, 17},
+ { 7, 13, 19}, { 7, 13, 21}, { 7, 13, 23}, { 7, 14, 1},
+ { 7, 14, 5}, { 7, 14, 23}, { 7, 15, 22}, { 7, 18, 1},
+ { 7, 18, 5}, { 7, 18, 9}, { 7, 18, 17}, { 7, 18, 19},
+ { 7, 18, 21}, { 7, 18, 23}, { 7, 19, 1}, { 7, 19, 5},
+ { 7, 19, 9}, { 7, 19, 19}, { 7, 19, 21}, { 7, 19, 23},
+ { 7, 20, 1}, { 7, 20, 2}, { 7, 20, 5}, { 7, 20, 9},
+ { 7, 20, 17}, { 7, 20, 19}, { 7, 20, 21}, { 7, 20, 23},
+ { 7, 21, 1}, { 7, 21, 22}, { 7, 22, 1}, { 7, 23, 1},
+ { 7, 23, 2}, { 7, 23, 5}, { 7, 23, 9}, { 7, 23, 17},
+ { 7, 23, 21}, { 7, 23, 23}, { 7, 26, 1}, { 7, 26, 2},
+ { 7, 26, 5}, { 7, 26, 9}, { 7, 26, 17}, { 7, 26, 19},
+ { 7, 26, 21}, { 7, 26, 23}, { 7, 27, 1}, { 7, 27, 2},
+ { 7, 27, 5}, { 7, 27, 9}, { 7, 27, 17}, { 7, 27, 19},
+ { 7, 27, 21}, { 7, 27, 23}, { 7, 27, 24}, { 7, 27, 27},
+ { 7, 27, 28}, { 7, 29, 1}, { 7, 29, 2}, { 7, 29, 5},
+ { 7, 29, 9}, { 7, 29, 17}, { 7, 29, 19}, { 7, 29, 21},
+ { 7, 29, 23}, { 8, 3, 1}, { 8, 3, 2}, { 8, 3, 5},
+ { 8, 3, 7}, { 8, 3, 8}, { 8, 3, 9}, { 8, 3, 10},
+ { 8, 3, 11}, { 8, 3, 17}, { 8, 3, 19}, { 8, 3, 21},
+ { 8, 3, 23}, { 8, 3, 24}, { 8, 3, 27}, { 8, 3, 29},
+ { 8, 4, 1}, { 8, 4, 2}, { 8, 4, 5}, { 8, 4, 9},
+ { 8, 4, 17}, { 8, 4, 19}, { 8, 4, 21}, { 8, 4, 22},
+ { 8, 4, 23}, { 8, 4, 24}, { 8, 5, 1}, { 8, 5, 2},
+ { 8, 5, 9}, { 8, 5, 23}, { 8, 7, 1}, { 8, 7, 2},
+ { 8, 7, 5}, { 8, 7, 9}, { 8, 7, 11}, { 8, 7, 17},
+ { 8, 7, 19}, { 8, 7, 21}, { 8, 7, 23}, { 8, 7, 24},
+ { 8, 7, 29}, { 8, 10, 1}, { 8, 10, 2}, { 8, 10, 5},
+ { 8, 10, 9}, { 8, 10, 17}, { 8, 10, 19}, { 8, 10, 21},
+ { 8, 10, 22}, { 8, 10, 23}, { 8, 11, 1}, { 8, 11, 2},
+ { 8, 11, 5}, { 8, 11, 9}, { 8, 11, 21}, { 8, 11, 22},
+ { 8, 11, 23}, { 8, 11, 25}, { 8, 12, 1}, { 8, 13, 1},
+ { 8, 13, 2}, { 8, 13, 4}, { 8, 13, 5}, { 8, 13, 9},
+ { 8, 13, 11}, { 8, 13, 17}, { 8, 13, 19}, { 8, 13, 21},
+ { 8, 13, 23}, { 8, 14, 1}, { 8, 14, 5}, { 8, 14, 22},
+ { 8, 14, 23}, { 8, 18, 1}, { 8, 18, 5}, { 8, 18, 9},
+ { 8, 18, 19}, { 8, 18, 21}, { 8, 18, 23}, { 8, 19, 1},
+ { 8, 19, 5}, { 8, 19, 9}, { 8, 19, 19}, { 8, 19, 21},
+ { 8, 20, 1}, { 8, 20, 2}, { 8, 20, 3}, { 8, 20, 5},
+ { 8, 20, 8}, { 8, 20, 9}, { 8, 20, 10}, { 8, 20, 11},
+ { 8, 20, 17}, { 8, 20, 19}, { 8, 20, 21}, { 8, 20, 23},
+ { 8, 20, 27}, { 8, 20, 29}, { 8, 21, 1}, { 8, 21, 5},
+ { 8, 21, 9}, { 8, 21, 19}, { 8, 21, 21}, { 8, 22, 1},
+ { 8, 23, 1}, { 8, 23, 5}, { 8, 23, 9}, { 8, 26, 1},
+ { 8, 26, 5}, { 8, 26, 9}, { 8, 26, 17}, { 8, 26, 21},
+ { 8, 27, 1}, { 8, 27, 5}, { 8, 27, 9}, { 8, 27, 17},
+ { 8, 27, 21}, { 8, 29, 1}, { 8, 29, 2}, { 8, 29, 5},
+ { 8, 29, 8}, { 8, 29, 9}, { 8, 29, 11}, { 8, 29, 17},
+ { 8, 29, 19}, { 8, 29, 21}, { 8, 29, 22}, { 8, 29, 23},
+ { 8, 29, 25}, { 8, 29, 27}, { 9, 3, 1}, { 9, 3, 2},
+ { 9, 3, 3}, { 9, 3, 4}, { 9, 3, 5}, { 9, 3, 8},
+ { 9, 3, 9}, { 9, 3, 10}, { 9, 3, 11}, { 9, 3, 12},
+ { 9, 3, 17}, { 9, 3, 19}, { 9, 3, 21}, { 9, 3, 23},
+ { 9, 3, 27}, { 9, 4, 1}, { 9, 4, 2}, { 9, 4, 5},
+ { 9, 4, 9}, { 9, 4, 17}, { 9, 4, 19}, { 9, 4, 21},
+ { 9, 4, 22}, { 9, 4, 23}, { 9, 4, 27}, { 9, 5, 1},
+ { 9, 5, 2}, { 9, 5, 5}, { 9, 5, 19}, { 9, 7, 1},
+ { 9, 7, 2}, { 9, 7, 5}, { 9, 7, 8}, { 9, 7, 9},
+ { 9, 7, 11}, { 9, 7, 17}, { 9, 7, 19}, { 9, 7, 21},
+ { 9, 7, 23}, { 9, 7, 24}, { 9, 10, 1}, { 9, 10, 2},
+ { 9, 10, 5}, { 9, 10, 8}, { 9, 10, 9}, { 9, 10, 17},
+ { 9, 10, 19}, { 9, 10, 21}, { 9, 10, 22}, { 9, 10, 23},
+ { 9, 11, 1}, { 9, 11, 2}, { 9, 11, 5}, { 9, 11, 9},
+ { 9, 11, 19}, { 9, 11, 21}, { 9, 11, 22}, { 9, 11, 23},
+ { 9, 11, 27}, { 9, 12, 1}, { 9, 12, 5}, { 9, 13, 1},
+ { 9, 13, 2}, { 9, 13, 3}, { 9, 13, 5}, { 9, 13, 9},
+ { 9, 13, 17}, { 9, 13, 19}, { 9, 13, 21}, { 9, 13, 23},
+ { 9, 14, 1}, { 9, 14, 5}, { 9, 14, 22}, { 9, 15, 1},
+ { 9, 15, 22}, { 9, 18, 1}, { 9, 18, 2}, { 9, 18, 5},
+ { 9, 18, 9}, { 9, 18, 17}, { 9, 18, 19}, { 9, 19, 1},
+ { 9, 19, 5}, { 9, 20, 1}, { 9, 20, 2}, { 9, 20, 5},
+ { 9, 20, 8}, { 9, 20, 9}, { 9, 20, 10}, { 9, 20, 11},
+ { 9, 20, 17}, { 9, 20, 19}, { 9, 20, 21}, { 9, 20, 23},
+ { 9, 20, 27}, { 9, 20, 28}, { 9, 21, 1}, { 9, 21, 9},
+ { 9, 21, 22}, { 9, 22, 1}, { 9, 23, 1}, { 9, 23, 2},
+ { 9, 23, 5}, { 9, 23, 9}, { 9, 23, 23}, { 9, 26, 1},
+ { 9, 26, 5}, { 9, 26, 9}, { 9, 26, 17}, { 9, 26, 21},
+ { 9, 26, 23}, { 9, 27, 1}, { 9, 27, 2}, { 9, 27, 5},
+ { 9, 27, 9}, { 9, 27, 17}, { 9, 27, 19}, { 9, 27, 21},
+ { 9, 29, 1}, { 9, 29, 2}, { 9, 29, 5}, { 9, 29, 9},
+ { 9, 29, 11}, { 9, 29, 17}, { 9, 29, 19}, { 9, 29, 21},
+ { 9, 29, 23}, { 9, 29, 24}, { 9, 29, 25}, { 10, 3, 1},
+ { 10, 3, 2}, { 10, 3, 5}, { 10, 3, 9}, { 10, 3, 11},
+ { 10, 3, 17}, { 10, 3, 19}, { 10, 3, 21}, { 10, 3, 22},
+ { 10, 3, 23}, { 10, 3, 29}, { 10, 4, 1}, { 10, 4, 2},
+ { 10, 4, 5}, { 10, 4, 9}, { 10, 4, 17}, { 10, 4, 19},
+ { 10, 4, 21}, { 10, 4, 22}, { 10, 4, 23}, { 10, 5, 1},
+ { 10, 5, 2}, { 10, 5, 17}, { 10, 7, 1}, { 10, 7, 2},
+ { 10, 7, 5}, { 10, 7, 8}, { 10, 7, 9}, { 10, 7, 17},
+ { 10, 7, 21}, { 10, 7, 22}, { 10, 7, 23}, { 10, 10, 1},
+ { 10, 10, 23}, { 10, 11, 1}, { 10, 11, 2}, { 10, 11, 17},
+ { 10, 11, 19}, { 10, 11, 21}, { 10, 11, 22}, { 10, 11, 23},
+ { 10, 13, 1}, { 10, 13, 2}, { 10, 13, 5}, { 10, 13, 9},
+ { 10, 13, 17}, { 10, 13, 19}, { 10, 13, 23}, { 10, 18, 1},
+ { 10, 19, 1}, { 10, 19, 23}, { 10, 20, 1}, { 10, 20, 2},
+ { 10, 20, 5}, { 10, 20, 9}, { 10, 20, 17}, { 10, 20, 21},
+ { 10, 20, 23}, { 10, 26, 1}, { 10, 26, 23}, { 10, 27, 1},
+ { 10, 27, 5}, { 10, 27, 9}, { 10, 27, 17}, { 10, 27, 19},
+ { 10, 29, 1}, { 10, 29, 2}, { 10, 29, 5}, { 10, 29, 9},
+ { 10, 29, 17}, { 10, 29, 19}, { 10, 29, 21}, { 10, 29, 23},
+ { 11, 3, 1}, { 11, 3, 2}, { 11, 3, 4}, { 11, 3, 5},
+ { 11, 3, 8}, { 11, 3, 9}, { 11, 3, 10}, { 11, 3, 11},
+ { 11, 3, 17}, { 11, 3, 19}, { 11, 3, 21}, { 11, 3, 22},
+ { 11, 3, 23}, { 11, 3, 27}, { 11, 4, 1}, { 11, 4, 2},
+ { 11, 4, 5}, { 11, 4, 9}, { 11, 4, 17}, { 11, 4, 19},
+ { 11, 4, 21}, { 11, 4, 22}, { 11, 4, 23}, { 11, 5, 1},
+ { 11, 5, 2}, { 11, 5, 5}, { 11, 5, 9}, { 11, 5, 17},
+ { 11, 5, 19}, { 11, 5, 21}, { 11, 5, 23}, { 11, 6, 1},
+ { 11, 6, 5}, { 11, 6, 9}, { 11, 6, 17}, { 11, 6, 23},
+ { 11, 7, 1}, { 11, 7, 2}, { 11, 7, 3}, { 11, 7, 4},
+ { 11, 7, 5}, { 11, 7, 8}, { 11, 7, 9}, { 11, 7, 11},
+ { 11, 7, 12}, { 11, 7, 17}, { 11, 7, 19}, { 11, 7, 21},
+ { 11, 7, 22}, { 11, 7, 23}, { 11, 7, 28}, { 11, 10, 1},
+ { 11, 10, 2}, { 11, 10, 5}, { 11, 10, 9}, { 11, 10, 17},
+ { 11, 10, 19}, { 11, 10, 21}, { 11, 10, 22}, { 11, 10, 23},
+ { 11, 11, 1}, { 11, 11, 2}, { 11, 11, 5}, { 11, 11, 9},
+ { 11, 11, 17}, { 11, 11, 19}, { 11, 11, 21}, { 11, 11, 22},
+ { 11, 11, 23}, { 11, 12, 1}, { 11, 12, 5}, { 11, 12, 9},
+ { 11, 12, 23}, { 11, 13, 1}, { 11, 13, 2}, { 11, 13, 3},
+ { 11, 13, 5}, { 11, 13, 9}, { 11, 13, 11}, { 11, 13, 17},
+ { 11, 13, 19}, { 11, 13, 21}, { 11, 13, 23}, { 11, 13, 27},
+ { 11, 14, 1}, { 11, 14, 2}, { 11, 14, 5}, { 11, 14, 9},
+ { 11, 14, 23}, { 11, 15, 1}, { 11, 15, 5}, { 11, 15, 9},
+ { 11, 15, 17}, { 11, 15, 21}, { 11, 15, 22}, { 11, 18, 1},
+ { 11, 18, 5}, { 11, 18, 9}, { 11, 18, 17}, { 11, 18, 19},
+ { 11, 18, 21}, { 11, 19, 1}, { 11, 19, 2}, { 11, 19, 5},
+ { 11, 19, 9}, { 11, 19, 17}, { 11, 19, 19}, { 11, 19, 21},
+ { 11, 19, 23}, { 11, 20, 1}, { 11, 20, 2}, { 11, 20, 5},
+ { 11, 20, 8}, { 11, 20, 9}, { 11, 20, 17}, { 11, 20, 19},
+ { 11, 20, 21}, { 11, 20, 23}, { 11, 20, 25}, { 11, 20, 27},
+ { 11, 20, 28}, { 11, 21, 1}, { 11, 21, 22}, { 11, 22, 1},
+ { 11, 22, 2}, { 11, 22, 5}, { 11, 22, 9}, { 11, 22, 17},
+ { 11, 22, 23}, { 11, 23, 1}, { 11, 23, 2}, { 11, 23, 5},
+ { 11, 23, 9}, { 11, 23, 17}, { 11, 23, 19}, { 11, 23, 21},
+ { 11, 23, 23}, { 11, 26, 1}, { 11, 26, 2}, { 11, 26, 9},
+ { 11, 26, 17}, { 11, 26, 21}, { 11, 26, 23}, { 11, 27, 1},
+ { 11, 27, 2}, { 11, 27, 5}, { 11, 27, 9}, { 11, 27, 10},
+ { 11, 27, 17}, { 11, 27, 19}, { 11, 27, 21}, { 11, 27, 23},
+ { 11, 29, 1}, { 11, 29, 2}, { 11, 29, 5}, { 11, 29, 8},
+ { 11, 29, 9}, { 11, 29, 16}, { 11, 29, 17}, { 11, 29, 19},
+ { 11, 29, 21}, { 11, 29, 23}, { 11, 29, 28}, { 12, 3, 1},
+ { 12, 3, 2}, { 12, 3, 4}, { 12, 3, 5}, { 12, 3, 9},
+ { 12, 3, 17}, { 12, 3, 19}, { 12, 3, 22}, { 12, 3, 23},
+ { 12, 3, 29}, { 12, 4, 1}, { 12, 4, 2}, { 12, 4, 5},
+ { 12, 4, 9}, { 12, 4, 17}, { 12, 4, 19}, { 12, 4, 22},
+ { 12, 4, 23}, { 12, 5, 23}, { 12, 7, 1}, { 12, 7, 2},
+ { 12, 7, 5}, { 12, 7, 9}, { 12, 7, 11}, { 12, 7, 17},
+ { 12, 7, 19}, { 12, 7, 22}, { 12, 7, 23}, { 12, 10, 1},
+ { 12, 10, 5}, { 12, 10, 9}, { 12, 12, 5}, { 12, 13, 1},
+ { 12, 13, 2}, { 12, 13, 5}, { 12, 13, 8}, { 12, 13, 9},
+ { 12, 13, 11}, { 12, 13, 17}, { 12, 13, 19}, { 12, 13, 23},
+ { 12, 14, 1}, { 12, 14, 2}, { 12, 14, 5}, { 12, 14, 22},
+ { 12, 15, 1}, { 12, 15, 22}, { 12, 18, 1}, { 12, 18, 5},
+ { 12, 18, 9}, { 12, 18, 17}, { 12, 18, 19}, { 12, 19, 1},
+ { 12, 20, 1}, { 12, 20, 2}, { 12, 20, 5}, { 12, 20, 9},
+ { 12, 20, 17}, { 12, 20, 19}, { 12, 20, 23}, { 12, 21, 1},
+ { 12, 21, 22}, { 12, 22, 1}, { 12, 23, 1}, { 12, 23, 5},
+ { 12, 26, 23}, { 12, 27, 1}, { 12, 27, 2}, { 12, 27, 5},
+ { 12, 27, 9}, { 12, 27, 11}, { 12, 27, 16}, { 12, 27, 17},
+ { 12, 27, 19}, { 12, 28, 1}, { 12, 28, 5}, { 12, 28, 9},
+ { 12, 28, 17}, { 12, 29, 1}, { 12, 29, 2}, { 12, 29, 5},
+ { 12, 29, 9}, { 12, 29, 17}, { 12, 29, 19}, { 12, 29, 21},
+ { 12, 29, 23}, { 13, 3, 1}, { 13, 3, 2}, { 13, 3, 5},
+ { 13, 3, 6}, { 13, 3, 7}, { 13, 3, 9}, { 13, 3, 10},
+ { 13, 3, 11}, { 13, 3, 16}, { 13, 3, 17}, { 13, 3, 19},
+ { 13, 3, 21}, { 13, 3, 22}, { 13, 3, 23}, { 13, 3, 27},
+ { 13, 3, 28}, { 13, 4, 1}, { 13, 4, 2}, { 13, 4, 5},
+ { 13, 4, 9}, { 13, 4, 17}, { 13, 4, 19}, { 13, 4, 21},
+ { 13, 4, 22}, { 13, 4, 23}, { 13, 5, 1}, { 13, 5, 2},
+ { 13, 5, 5}, { 13, 5, 9}, { 13, 5, 12}, { 13, 5, 17},
+ { 13, 5, 19}, { 13, 5, 21}, { 13, 5, 23}, { 13, 5, 27},
+ { 13, 5, 29}, { 13, 6, 1}, { 13, 6, 5}, { 13, 6, 9},
+ { 13, 6, 19}, { 13, 7, 1}, { 13, 7, 2}, { 13, 7, 5},
+ { 13, 7, 6}, { 13, 7, 8}, { 13, 7, 9}, { 13, 7, 10},
+ { 13, 7, 11}, { 13, 7, 17}, { 13, 7, 19}, { 13, 7, 20},
+ { 13, 7, 21}, { 13, 7, 22}, { 13, 7, 23}, { 13, 7, 24},
+ { 13, 7, 26}, { 13, 7, 28}, { 13, 10, 1}, { 13, 10, 2},
+ { 13, 10, 5}, { 13, 10, 9}, { 13, 10, 17}, { 13, 10, 19},
+ { 13, 10, 21}, { 13, 10, 23}, { 13, 11, 1}, { 13, 11, 2},
+ { 13, 11, 3}, { 13, 11, 5}, { 13, 11, 9}, { 13, 11, 11},
+ { 13, 11, 12}, { 13, 11, 17}, { 13, 11, 19}, { 13, 11, 20},
+ { 13, 11, 21}, { 13, 11, 22}, { 13, 11, 23}, { 13, 11, 27},
+ { 13, 11, 28}, { 13, 11, 29}, { 13, 12, 1}, { 13, 12, 5},
+ { 13, 12, 9}, { 13, 12, 17}, { 13, 12, 19}, { 13, 12, 21},
+ { 13, 12, 22}, { 13, 13, 1}, { 13, 13, 2}, { 13, 13, 5},
+ { 13, 13, 9}, { 13, 13, 10}, { 13, 13, 11}, { 13, 13, 13},
+ { 13, 13, 16}, { 13, 13, 17}, { 13, 13, 19}, { 13, 13, 21},
+ { 13, 13, 23}, { 13, 13, 25}, { 13, 14, 1}, { 13, 14, 2},
+ { 13, 14, 5}, { 13, 14, 9}, { 13, 14, 17}, { 13, 14, 19},
+ { 13, 14, 21}, { 13, 14, 22}, { 13, 14, 23}, { 13, 15, 1},
+ { 13, 15, 2}, { 13, 15, 5}, { 13, 15, 17}, { 13, 15, 21},
+ { 13, 15, 23}, { 13, 18, 1}, { 13, 18, 2}, { 13, 18, 5},
+ { 13, 18, 9}, { 13, 18, 17}, { 13, 18, 19}, { 13, 18, 21},
+ { 13, 18, 23}, { 13, 19, 1}, { 13, 19, 2}, { 13, 19, 5},
+ { 13, 19, 9}, { 13, 19, 17}, { 13, 19, 19}, { 13, 19, 21},
+ { 13, 19, 23}, { 13, 20, 1}, { 13, 20, 2}, { 13, 20, 5},
+ { 13, 20, 9}, { 13, 20, 10}, { 13, 20, 11}, { 13, 20, 17},
+ { 13, 20, 19}, { 13, 20, 21}, { 13, 20, 23}, { 13, 21, 1},
+ { 13, 21, 2}, { 13, 21, 5}, { 13, 21, 9}, { 13, 21, 17},
+ { 13, 21, 19}, { 13, 21, 22}, { 13, 21, 23}, { 13, 22, 1},
+ { 13, 22, 2}, { 13, 22, 5}, { 13, 22, 9}, { 13, 22, 17},
+ { 13, 22, 19}, { 13, 22, 23}, { 13, 23, 1}, { 13, 23, 2},
+ { 13, 23, 5}, { 13, 23, 9}, { 13, 23, 17}, { 13, 23, 19},
+ { 13, 23, 21}, { 13, 23, 23}, { 13, 26, 1}, { 13, 26, 2},
+ { 13, 26, 5}, { 13, 26, 9}, { 13, 26, 17}, { 13, 26, 19},
+ { 13, 26, 21}, { 13, 26, 23}, { 13, 26, 25}, { 13, 27, 1},
+ { 13, 27, 2}, { 13, 27, 5}, { 13, 27, 9}, { 13, 27, 15},
+ { 13, 27, 17}, { 13, 27, 19}, { 13, 27, 21}, { 13, 27, 23},
+ { 13, 27, 24}, { 13, 27, 25}, { 13, 27, 26}, { 13, 27, 27},
+ { 13, 27, 28}, { 13, 27, 29}, { 13, 28, 1}, { 13, 28, 5},
+ { 13, 28, 9}, { 13, 28, 17}, { 13, 28, 21}, { 13, 29, 1},
+ { 13, 29, 2}, { 13, 29, 5}, { 13, 29, 9}, { 13, 29, 10},
+ { 13, 29, 11}, { 13, 29, 16}, { 13, 29, 17}, { 13, 29, 19},
+ { 13, 29, 21}, { 13, 29, 22}, { 13, 29, 23}, { 13, 29, 24},
+ { 13, 29, 28}, { 14, 3, 1}, { 14, 3, 2}, { 14, 3, 5},
+ { 14, 3, 7}, { 14, 3, 8}, { 14, 3, 9}, { 14, 3, 11},
+ { 14, 3, 17}, { 14, 3, 19}, { 14, 3, 21}, { 14, 3, 22},
+ { 14, 3, 23}, { 14, 3, 24}, { 14, 4, 1}, { 14, 4, 2},
+ { 14, 4, 5}, { 14, 4, 9}, { 14, 4, 17}, { 14, 4, 19},
+ { 14, 4, 21}, { 14, 4, 22}, { 14, 4, 23}, { 14, 5, 1},
+ { 14, 5, 2}, { 14, 5, 5}, { 14, 5, 7}, { 14, 5, 9},
+ { 14, 5, 17}, { 14, 5, 23}, { 14, 6, 1}, { 14, 6, 5},
+ { 14, 6, 9}, { 14, 7, 1}, { 14, 7, 2}, { 14, 7, 5},
+ { 14, 7, 9}, { 14, 7, 11}, { 14, 7, 17}, { 14, 7, 19},
+ { 14, 7, 21}, { 14, 7, 23}, { 14, 7, 24}, { 14, 10, 1},
+ { 14, 10, 2}, { 14, 10, 5}, { 14, 10, 9}, { 14, 10, 17},
+ { 14, 10, 19}, { 14, 10, 21}, { 14, 10, 23}, { 14, 11, 1},
+ { 14, 11, 5}, { 14, 11, 9}, { 14, 11, 17}, { 14, 11, 19},
+ { 14, 11, 22}, { 14, 11, 23}, { 14, 12, 1}, { 14, 13, 1},
+ { 14, 13, 2}, { 14, 13, 5}, { 14, 13, 9}, { 14, 13, 11},
+ { 14, 13, 17}, { 14, 13, 19}, { 14, 13, 21}, { 14, 13, 23},
+ { 14, 13, 24}, { 14, 13, 25}, { 14, 13, 29}, { 14, 14, 1},
+ { 14, 14, 2}, { 14, 14, 9}, { 14, 14, 19}, { 14, 14, 21},
+ { 14, 14, 23}, { 14, 15, 1}, { 14, 15, 22}, { 14, 15, 23},
+ { 14, 18, 1}, { 14, 18, 5}, { 14, 18, 9}, { 14, 18, 17},
+ { 14, 18, 19}, { 14, 18, 21}, { 14, 18, 23}, { 14, 19, 1},
+ { 14, 19, 2}, { 14, 19, 5}, { 14, 19, 23}, { 14, 20, 1},
+ { 14, 20, 2}, { 14, 20, 5}, { 14, 20, 9}, { 14, 20, 10},
+ { 14, 20, 11}, { 14, 20, 17}, { 14, 20, 19}, { 14, 20, 21},
+ { 14, 20, 23}, { 14, 21, 1}, { 14, 21, 22}, { 14, 22, 1},
+ { 14, 23, 1}, { 14, 23, 2}, { 14, 23, 5}, { 14, 23, 9},
+ { 14, 23, 17}, { 14, 23, 19}, { 14, 23, 21}, { 14, 26, 1},
+ { 14, 26, 5}, { 14, 26, 9}, { 14, 26, 17}, { 14, 27, 1},
+ { 14, 27, 2}, { 14, 27, 5}, { 14, 27, 9}, { 14, 27, 17},
+ { 14, 27, 19}, { 14, 27, 21}, { 14, 27, 23}, { 14, 29, 1},
+ { 14, 29, 2}, { 14, 29, 5}, { 14, 29, 8}, { 14, 29, 9},
+ { 14, 29, 11}, { 14, 29, 17}, { 14, 29, 19}, { 14, 29, 21},
+ { 14, 29, 23}, { 14, 29, 24}, { 14, 29, 27}, { 14, 29, 28},
+ { 15, 3, 1}, { 15, 3, 2}, { 15, 3, 5}, { 15, 3, 7},
+ { 15, 3, 9}, { 15, 3, 12}, { 15, 3, 17}, { 15, 3, 19},
+ { 15, 3, 21}, { 15, 3, 22}, { 15, 3, 23}, { 15, 4, 1},
+ { 15, 4, 2}, { 15, 4, 5}, { 15, 4, 9}, { 15, 4, 17},
+ { 15, 4, 19}, { 15, 4, 21}, { 15, 4, 22}, { 15, 4, 23},
+ { 15, 5, 1}, { 15, 5, 5}, { 15, 5, 23}, { 15, 7, 1},
+ { 15, 7, 2}, { 15, 7, 5}, { 15, 7, 9}, { 15, 7, 17},
+ { 15, 7, 19}, { 15, 7, 21}, { 15, 7, 22}, { 15, 7, 23},
+ { 15, 10, 1}, { 15, 10, 23}, { 15, 11, 1}, { 15, 11, 22},
+ { 15, 13, 1}, { 15, 13, 2}, { 15, 13, 5}, { 15, 13, 9},
+ { 15, 13, 17}, { 15, 13, 19}, { 15, 13, 21}, { 15, 13, 23},
+ { 15, 13, 25}, { 15, 14, 1}, { 15, 14, 2}, { 15, 14, 9},
+ { 15, 14, 22}, { 15, 15, 1}, { 15, 15, 22}, { 15, 18, 1},
+ { 15, 18, 5}, { 15, 18, 9}, { 15, 18, 17}, { 15, 18, 19},
+ { 15, 19, 23}, { 15, 20, 1}, { 15, 20, 2}, { 15, 20, 5},
+ { 15, 20, 9}, { 15, 20, 17}, { 15, 20, 19}, { 15, 20, 23},
+ { 15, 21, 1}, { 15, 21, 22}, { 15, 21, 23}, { 15, 23, 1},
+ { 15, 26, 1}, { 15, 27, 1}, { 15, 27, 17}, { 15, 27, 21},
+ { 15, 27, 23}, { 15, 29, 1}, { 15, 29, 2}, { 15, 29, 5},
+ { 15, 29, 9}, { 15, 29, 17}, { 15, 29, 19}, { 15, 29, 23},
+ { 15, 29, 24}, { 15, 29, 29}, { 16, 3, 1}, { 16, 3, 2},
+ { 16, 3, 5}, { 16, 3, 7}, { 16, 3, 9}, { 16, 3, 17},
+ { 16, 3, 19}, { 16, 3, 21}, { 16, 3, 22}, { 16, 3, 23},
+ { 16, 3, 24}, { 16, 4, 1}, { 16, 4, 2}, { 16, 4, 5},
+ { 16, 4, 9}, { 16, 4, 17}, { 16, 4, 19}, { 16, 4, 21},
+ { 16, 4, 22}, { 16, 4, 23}, { 16, 5, 1}, { 16, 5, 5},
+ { 16, 5, 7}, { 16, 5, 9}, { 16, 5, 17}, { 16, 5, 23},
+ { 16, 7, 1}, { 16, 7, 2}, { 16, 7, 5}, { 16, 7, 9},
+ { 16, 7, 17}, { 16, 7, 19}, { 16, 7, 21}, { 16, 7, 22},
+ { 16, 7, 23}, { 16, 10, 1}, { 16, 10, 2}, { 16, 10, 5},
+ { 16, 10, 9}, { 16, 10, 17}, { 16, 10, 19}, { 16, 10, 21},
+ { 16, 10, 23}, { 16, 11, 1}, { 16, 11, 5}, { 16, 11, 22},
+ { 16, 12, 1}, { 16, 12, 5}, { 16, 12, 23}, { 16, 13, 1},
+ { 16, 13, 2}, { 16, 13, 5}, { 16, 13, 9}, { 16, 13, 17},
+ { 16, 13, 19}, { 16, 13, 21}, { 16, 13, 23}, { 16, 14, 1},
+ { 16, 14, 5}, { 16, 14, 9}, { 16, 14, 23}, { 16, 18, 1},
+ { 16, 18, 5}, { 16, 18, 9}, { 16, 18, 17}, { 16, 18, 19},
+ { 16, 18, 21}, { 16, 18, 23}, { 16, 19, 1}, { 16, 19, 17},
+ { 16, 20, 1}, { 16, 20, 2}, { 16, 20, 5}, { 16, 20, 9},
+ { 16, 20, 17}, { 16, 20, 19}, { 16, 20, 21}, { 16, 20, 23},
+ { 16, 21, 1}, { 16, 21, 22}, { 16, 22, 1}, { 16, 22, 5},
+ { 16, 23, 1}, { 16, 23, 5}, { 16, 23, 9}, { 16, 23, 17},
+ { 16, 23, 19}, { 16, 23, 21}, { 16, 23, 23}, { 16, 26, 1},
+ { 16, 26, 5}, { 16, 26, 9}, { 16, 26, 17}, { 16, 26, 23},
+ { 16, 27, 1}, { 16, 27, 2}, { 16, 27, 5}, { 16, 27, 9},
+ { 16, 27, 17}, { 16, 27, 19}, { 16, 27, 21}, { 16, 27, 23},
+ { 16, 29, 1}, { 16, 29, 2}, { 16, 29, 5}, { 16, 29, 8},
+ { 16, 29, 9}, { 16, 29, 10}, { 16, 29, 17}, { 16, 29, 19},
+ { 16, 29, 21}, { 16, 29, 23}, { 17, 3, 1}, { 17, 3, 2},
+ { 17, 3, 5}, { 17, 3, 9}, { 17, 3, 17}, { 17, 3, 19},
+ { 17, 3, 21}, { 17, 3, 23}, { 17, 4, 1}, { 17, 4, 2},
+ { 17, 4, 5}, { 17, 4, 9}, { 17, 4, 17}, { 17, 4, 19},
+ { 17, 4, 21}, { 17, 4, 22}, { 17, 4, 23}, { 17, 5, 1},
+ { 17, 5, 2}, { 17, 5, 23}, { 17, 7, 1}, { 17, 7, 2},
+ { 17, 7, 5}, { 17, 7, 8}, { 17, 7, 9}, { 17, 7, 17},
+ { 17, 7, 19}, { 17, 7, 21}, { 17, 7, 22}, { 17, 7, 23},
+ { 17, 10, 1}, { 17, 10, 2}, { 17, 10, 5}, { 17, 10, 9},
+ { 17, 10, 17}, { 17, 10, 19}, { 17, 10, 21}, { 17, 10, 23},
+ { 17, 11, 1}, { 17, 11, 5}, { 17, 11, 9}, { 17, 11, 17},
+ { 17, 11, 19}, { 17, 11, 21}, { 17, 11, 22}, { 17, 11, 23},
+ { 17, 12, 1}, { 17, 13, 1}, { 17, 13, 2}, { 17, 13, 5},
+ { 17, 13, 9}, { 17, 13, 17}, { 17, 13, 19}, { 17, 13, 21},
+ { 17, 13, 23}, { 17, 14, 1}, { 17, 14, 2}, { 17, 14, 5},
+ { 17, 14, 9}, { 17, 14, 17}, { 17, 14, 23}, { 17, 15, 1},
+ { 17, 15, 23}, { 17, 18, 1}, { 17, 18, 9}, { 17, 19, 1},
+ { 17, 20, 1}, { 17, 20, 2}, { 17, 20, 5}, { 17, 20, 9},
+ { 17, 20, 17}, { 17, 20, 19}, { 17, 20, 21}, { 17, 20, 23},
+ { 17, 21, 1}, { 17, 21, 5}, { 17, 21, 9}, { 17, 21, 23},
+ { 17, 22, 1}, { 17, 22, 23}, { 17, 23, 1}, { 17, 23, 2},
+ { 17, 23, 5}, { 17, 23, 9}, { 17, 23, 17}, { 17, 23, 19},
+ { 17, 23, 21}, { 17, 23, 23}, { 17, 26, 1}, { 17, 26, 5},
+ { 17, 26, 9}, { 17, 26, 17}, { 17, 27, 1}, { 17, 27, 2},
+ { 17, 27, 5}, { 17, 27, 9}, { 17, 27, 17}, { 17, 27, 19},
+ { 17, 27, 23}, { 17, 29, 1}, { 17, 29, 2}, { 17, 29, 5},
+ { 17, 29, 9}, { 17, 29, 17}, { 17, 29, 19}, { 17, 29, 21},
+ { 17, 29, 23}, { 18, 3, 1}, { 18, 3, 2}, { 18, 3, 5},
+ { 18, 3, 9}, { 18, 3, 10}, { 18, 3, 17}, { 18, 3, 19},
+ { 18, 3, 21}, { 18, 3, 22}, { 18, 3, 23}, { 18, 4, 1},
+ { 18, 4, 2}, { 18, 4, 5}, { 18, 4, 9}, { 18, 4, 17},
+ { 18, 4, 19}, { 18, 4, 21}, { 18, 4, 22}, { 18, 4, 23},
+ { 18, 5, 1}, { 18, 5, 23}, { 18, 7, 1}, { 18, 7, 2},
+ { 18, 7, 5}, { 18, 7, 9}, { 18, 7, 11}, { 18, 7, 17},
+ { 18, 7, 19}, { 18, 7, 21}, { 18, 7, 22}, { 18, 7, 23},
+ { 18, 10, 1}, { 18, 10, 2}, { 18, 10, 5}, { 18, 10, 9},
+ { 18, 10, 17}, { 18, 10, 19}, { 18, 10, 21}, { 18, 10, 23},
+ { 18, 11, 1}, { 18, 11, 5}, { 18, 11, 22}, { 18, 12, 1},
+ { 18, 12, 5}, { 18, 13, 1}, { 18, 13, 2}, { 18, 13, 5},
+ { 18, 13, 9}, { 18, 13, 17}, { 18, 13, 19}, { 18, 13, 21},
+ { 18, 13, 23}, { 18, 13, 28}, { 18, 14, 1}, { 18, 14, 5},
+ { 18, 15, 1}, { 18, 18, 1}, { 18, 18, 5}, { 18, 18, 21},
+ { 18, 18, 23}, { 18, 19, 1}, { 18, 20, 1}, { 18, 20, 2},
+ { 18, 20, 5}, { 18, 20, 9}, { 18, 20, 17}, { 18, 20, 19},
+ { 18, 20, 21}, { 18, 20, 23}, { 18, 21, 1}, { 18, 21, 22},
+ { 18, 22, 1}, { 18, 23, 1}, { 18, 23, 2}, { 18, 23, 5},
+ { 18, 23, 9}, { 18, 23, 17}, { 18, 23, 19}, { 18, 23, 23},
+ { 18, 26, 1}, { 18, 26, 5}, { 18, 26, 9}, { 18, 26, 17},
+ { 18, 26, 23}, { 18, 27, 1}, { 18, 27, 2}, { 18, 27, 5},
+ { 18, 27, 8}, { 18, 27, 9}, { 18, 27, 11}, { 18, 27, 17},
+ { 18, 27, 19}, { 18, 27, 21}, { 18, 28, 1}, { 18, 28, 5},
+ { 18, 28, 9}, { 18, 28, 17}, { 18, 28, 19}, { 18, 29, 1},
+ { 18, 29, 2}, { 18, 29, 5}, { 18, 29, 9}, { 18, 29, 17},
+ { 18, 29, 19}, { 18, 29, 21}, { 18, 29, 23}, { 19, 3, 1},
+ { 19, 3, 2}, { 19, 3, 3}, { 19, 3, 5}, { 19, 3, 9},
+ { 19, 3, 11}, { 19, 3, 17}, { 19, 3, 19}, { 19, 3, 21},
+ { 19, 3, 22}, { 19, 3, 23}, { 19, 3, 27}, { 19, 4, 1},
+ { 19, 4, 2}, { 19, 4, 5}, { 19, 4, 9}, { 19, 4, 17},
+ { 19, 4, 19}, { 19, 4, 21}, { 19, 4, 22}, { 19, 4, 23},
+ { 19, 5, 1}, { 19, 5, 2}, { 19, 7, 1}, { 19, 7, 2},
+ { 19, 7, 5}, { 19, 7, 9}, { 19, 7, 17}, { 19, 7, 19},
+ { 19, 7, 21}, { 19, 7, 22}, { 19, 7, 23}, { 19, 10, 1},
+ { 19, 10, 2}, { 19, 10, 5}, { 19, 10, 9}, { 19, 10, 17},
+ { 19, 10, 19}, { 19, 10, 21}, { 19, 10, 23}, { 19, 11, 1},
+ { 19, 11, 5}, { 19, 11, 9}, { 19, 11, 17}, { 19, 11, 19},
+ { 19, 11, 22}, { 19, 11, 23}, { 19, 12, 1}, { 19, 12, 9},
+ { 19, 12, 19}, { 19, 12, 21}, { 19, 13, 1}, { 19, 13, 2},
+ { 19, 13, 5}, { 19, 13, 9}, { 19, 13, 17}, { 19, 13, 19},
+ { 19, 13, 21}, { 19, 13, 23}, { 19, 14, 1}, { 19, 14, 23},
+ { 19, 18, 1}, { 19, 18, 5}, { 19, 19, 1}, { 19, 19, 5},
+ { 19, 19, 9}, { 19, 19, 19}, { 19, 19, 21}, { 19, 20, 1},
+ { 19, 20, 2}, { 19, 20, 5}, { 19, 20, 8}, { 19, 20, 9},
+ { 19, 20, 11}, { 19, 20, 17}, { 19, 20, 19}, { 19, 20, 21},
+ { 19, 20, 23}, { 19, 21, 1}, { 19, 21, 23}, { 19, 23, 1},
+ { 19, 23, 5}, { 19, 23, 9}, { 19, 23, 17}, { 19, 23, 21},
+ { 19, 26, 1}, { 19, 26, 5}, { 19, 26, 9}, { 19, 26, 17},
+ { 19, 26, 21}, { 19, 26, 23}, { 19, 27, 1}, { 19, 27, 5},
+ { 19, 27, 9}, { 19, 27, 17}, { 19, 27, 19}, { 19, 27, 21},
+ { 19, 29, 1}, { 19, 29, 2}, { 19, 29, 5}, { 19, 29, 9},
+ { 19, 29, 17}, { 19, 29, 19}, { 19, 29, 21}, { 19, 29, 23},
+ { 20, 3, 1}, { 20, 3, 2}, { 20, 3, 5}, { 20, 3, 9},
+ { 20, 3, 14}, { 20, 3, 17}, { 20, 3, 19}, { 20, 3, 21},
+ { 20, 3, 23}, { 20, 4, 1}, { 20, 4, 2}, { 20, 4, 5},
+ { 20, 4, 9}, { 20, 4, 17}, { 20, 4, 19}, { 20, 4, 21},
+ { 20, 4, 22}, { 20, 4, 23}, { 20, 5, 1}, { 20, 5, 23},
+ { 20, 7, 1}, { 20, 7, 2}, { 20, 7, 5}, { 20, 7, 9},
+ { 20, 7, 11}, { 20, 7, 17}, { 20, 7, 19}, { 20, 7, 21},
+ { 20, 7, 23}, { 20, 10, 1}, { 20, 10, 2}, { 20, 10, 5},
+ { 20, 10, 9}, { 20, 10, 17}, { 20, 10, 19}, { 20, 10, 21},
+ { 20, 10, 23}, { 20, 11, 1}, { 20, 11, 2}, { 20, 11, 5},
+ { 20, 11, 9}, { 20, 11, 17}, { 20, 11, 19}, { 20, 11, 21},
+ { 20, 11, 22}, { 20, 11, 23}, { 20, 12, 1}, { 20, 12, 5},
+ { 20, 12, 9}, { 20, 12, 19}, { 20, 13, 1}, { 20, 13, 2},
+ { 20, 13, 5}, { 20, 13, 9}, { 20, 13, 14}, { 20, 13, 17},
+ { 20, 13, 19}, { 20, 13, 21}, { 20, 13, 23}, { 20, 13, 27},
+ { 20, 14, 1}, { 20, 14, 2}, { 20, 14, 5}, { 20, 14, 9},
+ { 20, 14, 21}, { 20, 14, 23}, { 20, 15, 1}, { 20, 15, 2},
+ { 20, 15, 5}, { 20, 15, 21}, { 20, 15, 23}, { 20, 18, 1},
+ { 20, 18, 2}, { 20, 18, 5}, { 20, 18, 9}, { 20, 18, 19},
+ { 20, 18, 21}, { 20, 18, 23}, { 20, 19, 1}, { 20, 19, 5},
+ { 20, 19, 9}, { 20, 19, 19}, { 20, 19, 21}, { 20, 20, 1},
+ { 20, 20, 2}, { 20, 20, 5}, { 20, 20, 9}, { 20, 20, 14},
+ { 20, 20, 17}, { 20, 20, 21}, { 20, 20, 23}, { 20, 21, 1},
+ { 20, 21, 5}, { 20, 21, 9}, { 20, 21, 17}, { 20, 21, 23},
+ { 20, 22, 1}, { 20, 22, 2}, { 20, 22, 5}, { 20, 22, 9},
+ { 20, 22, 23}, { 20, 23, 1}, { 20, 23, 2}, { 20, 23, 5},
+ { 20, 23, 9}, { 20, 23, 17}, { 20, 23, 19}, { 20, 23, 21},
+ { 20, 23, 23}, { 20, 26, 1}, { 20, 26, 2}, { 20, 26, 5},
+ { 20, 26, 9}, { 20, 26, 17}, { 20, 26, 21}, { 20, 26, 23},
+ { 20, 27, 1}, { 20, 27, 2}, { 20, 27, 5}, { 20, 27, 7},
+ { 20, 27, 8}, { 20, 27, 9}, { 20, 27, 10}, { 20, 27, 17},
+ { 20, 27, 19}, { 20, 27, 21}, { 20, 27, 23}, { 20, 27, 27},
+ { 20, 28, 1}, { 20, 28, 5}, { 20, 28, 9}, { 20, 28, 17},
+ { 20, 28, 19}, { 20, 28, 23}, { 20, 29, 1}, { 20, 29, 2},
+ { 20, 29, 5}, { 20, 29, 9}, { 20, 29, 17}, { 20, 29, 19},
+ { 20, 29, 21}, { 20, 29, 23},
+};
+
+
+static const unsigned short ks_table2[][4] =
+{
+ {0xa4bf, 1, 3, 1}, {0xa4c0, 1, 4, 1},
+ {0xa4c1, 1, 5, 1}, {0xa4c2, 1, 6, 1},
+ {0xa4c3, 1, 7, 1}, {0xa4c4, 1, 10, 1},
+ {0xa4c5, 1, 11, 1}, {0xa4c6, 1, 12, 1},
+ {0xa4c7, 1, 13, 1}, {0xa4c8, 1, 14, 1},
+ {0xa4c9, 1, 15, 1}, {0xa4ca, 1, 18, 1},
+ {0xa4cb, 1, 19, 1}, {0xa4cc, 1, 20, 1},
+ {0xa4cd, 1, 21, 1}, {0xa4ce, 1, 22, 1},
+ {0xa4cf, 1, 23, 1}, {0xa4d0, 1, 26, 1},
+ {0xa4d1, 1, 27, 1}, {0xa4d2, 1, 28, 1},
+ {0xa4d3, 1, 29, 1}, {0xa4a1, 2, 2, 1},
+ {0xa4a2, 3, 2, 1}, {0xa4a4, 4, 2, 1},
+ {0xa4a7, 5, 2, 1}, {0xa4a8, 6, 2, 1},
+ {0xa4a9, 7, 2, 1}, {0xa4b1, 8, 2, 1},
+ {0xa4b2, 9, 2, 1}, {0xa4b3, 10, 2, 1},
+ {0xa4b5, 11, 2, 1}, {0xa4b6, 12, 2, 1},
+ {0xa4b7, 13, 2, 1}, {0xa4b8, 14, 2, 1},
+ {0xa4b9, 15, 2, 1}, {0xa4ba, 16, 2, 1},
+ {0xa4bb, 17, 2, 1}, {0xa4bc, 18, 2, 1},
+ {0xa4bd, 19, 2, 1}, {0xa4be, 20, 2, 1},
+};
+
+/* Á¶ÇÕÇü Ãʼº - ¿Ï¼ºÇü ³¹ÀÚ º¯È¯
+ * conversion: initial sound of compound type - ??? of completion type
+ */
+
+static const char_u johab_fcon_to_wan[] =
+{
+ 0,
+ 0xd4, 0xa1, 0xa2, 0xa4, 0xa7, /* (ä¿ò),¤¡,¤¢,¤¤,¤§ */
+ 0xa8, 0xa9, 0xb1, 0xb2, 0xb3, /* ¤¨,¤©,¤±,¤²,¤³ */
+ 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, /* ¤µ,¤¶,¤·,¤¸,¤¹ */
+ 0xba, 0xbb, 0xbc, 0xbd, 0xbe /* ¤º,¤»,¤¼,¤½,¤¾ */
+};
+
+/* Á¶ÇÕÇü Áß¼º -> ¿Ï¼ºÇü ³¹ÀÚ º¯È¯
+ * conversion: medial vowel of compound type - ??? of completion type
+ */
+
+static const char_u johab_vow_to_wan[] =
+{
+ 0, 0,
+ 0xd4, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, /* (ä¿ò),¤¿,¤À,¤Á,¤Â,¤Ã */
+ 0, 0,
+ 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, /* ¤Ä,¤Å,¤Æ,¤Ç,¤Ç¤¿,¤Ç¤À */
+ 0, 0,
+ 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* ¤Ç¤Ó,¤Ë,¤Ì,¤Ì¤Ã,¤Ì¤Ä,¤Ì¤Ó */
+ 0, 0,
+ 0xd0, 0xd1, 0xd2, 0xd3 /* ¤Ð,¤Ñ,¤Ñ¤Ó,¤Ó */
+};
+
+/* Á¶ÇÕÇü Á¾¼º -> ¿Ï¼ºÇü ³¹ÀÚ º¯È¯
+ * conversion: final consonant of compound type - ??? of completion type
+ */
+
+static const char_u johab_lcon_to_wan[] =
+{
+ 0,
+ 0xd4, 0xa1, 0xa2, 0xa3, 0xa4, /* (ä¿ò), ¤¡, ¤¢, ¤¡¤µ, ¤¤ */
+ 0xa5, 0xa6, 0xa7, 0xa9, 0xaa, /* ¤¤¤¸, ¤¤¤¾, ¤§, ¤©, ¤©¤¡ */
+ 0xab, 0xac, 0xad, 0xae, 0xaf, /* ¤©¤±, ¤©¤², ¤©¤µ, ¤©¤¼, ¤©¤½ */
+ 0xb0, 0xb1, 0, 0xb2, 0xb4, /* ¤©¤¾, ¤±, 0, ¤², ¤²¤µ */
+ 0xb5, 0xb6, 0xb7, 0xb8, 0xba, /* ¤µ, ¤¶, ¤·, ¤¸, ¤º */
+ 0xbb, 0xbc, 0xbd, 0xbe /* ¤», ¤¼, ¤½, ¤¾ */
+};
+
+ static void
+convert_ks_to_3(
+ const char_u *src,
+ int *fp,
+ int *mp,
+ int *lp)
+{
+ int h = *src;
+ int low = *(src + 1);
+ int c;
+ int i;
+
+ if ((i = han_index(h, low)) >= 0
+ && i < (int)(sizeof(ks_table1)/sizeof(ks_table1[0])))
+ {
+ *fp = ks_table1[i][0];
+ *mp = ks_table1[i][1];
+ *lp = ks_table1[i][2];
+ }
+ else
+ {
+ c = (h << 8) | low;
+ for (i = 0; i < 40; i++)
+ if (ks_table2[i][0] == c)
+ {
+ *fp = ks_table2[i][1];
+ *mp = ks_table2[i][2];
+ *lp = ks_table2[i][3];
+ return;
+ }
+ *fp = 0xff; /* ±×·¡ÇÈ ÄÚµå (graphic code) */
+ *mp = h;
+ *lp = low;
+ }
+}
+
+ static int
+convert_3_to_ks(
+ int fv,
+ int mv,
+ int lv,
+ char_u *des)
+{
+ char_u key[3];
+ register int hi, lo, mi = 0, result, found;
+
+ if (fv == 0xff)
+ {
+ des[0] = mv;
+ des[1] = lv;
+ return 2;
+ }
+ key[0] = fv;
+ key[1] = mv;
+ key[2] = lv;
+ lo = 0;
+ hi = sizeof(ks_table1)/3 - 1;
+ found = 0;
+ while (lo + 1 < hi)
+ {
+ mi = (lo + hi)/2;
+ result = STRNCMP(ks_table1[mi], key, 3);
+ if (result == 0)
+ {
+ found = 1;
+ break;
+ }
+ else if (result > 0)
+ hi = mi;
+ else
+ lo = mi;
+ }
+ if (!found)
+ {
+ if (!STRNCMP(ks_table1[lo], key, 3))
+ {
+ found = 1;
+ mi = lo;
+ }
+ if (!STRNCMP(ks_table1[hi], key, 3))
+ {
+ found = 1;
+ mi = hi;
+ }
+ }
+ if (!found)
+ {
+ for (mi = 0; mi < 40; mi++)
+ if (ks_table2[mi][1] == fv && ks_table2[mi][2] == mv &&
+ ks_table2[mi][3] == lv)
+ {
+ des[0] = (unsigned)(ks_table2[mi][0]) >> 8;
+ des[1] = ks_table2[mi][0];
+ return 2; /* found */
+ }
+ }
+ else
+ {
+ des[0] = mi / (0xff-0xa1) + 0xb0;
+ des[1] = mi % (0xff-0xa1) + 0xa1;
+ return 2; /* found */
+ }
+
+ /* ¿Ï¼ºÇü Ç¥¿¡ ¾ø´Ù. ``KS C 5601 - 1992 Á¤º¸ ±³È¯¿ë ºÎÈ£ Çؼ³''
+ * 3.3 Àý¿¡ ¼³¸íµÈ ¹æ¹ýÀ¸·Î encoding ÇÑ´Ù.
+ */
+
+ *des++ = 0xa4; /* ä¿ò */
+ *des++ = 0xd4;
+ *des++ = 0xa4; /* ³¹ÀÚ´Â ¸ðµÎ a4 Çà¿¡ ÀÖ´Ù. */
+ *des++ = johab_fcon_to_wan[fv];
+ *des++ = 0xa4;
+ *des++ = johab_vow_to_wan[mv];
+ *des++ = 0xa4;
+ *des++ = johab_lcon_to_wan[lv];
+ return 8;
+}
+
+ char_u *
+hangul_string_convert(char_u *buf, int *p_len)
+{
+ char_u *tmpbuf = NULL;
+ vimconv_T vc;
+
+ if (enc_utf8)
+ {
+ vc.vc_type = CONV_NONE;
+ if (convert_setup(&vc, (char_u *)"euc-kr", p_enc) == OK)
+ {
+ tmpbuf = string_convert(&vc, buf, p_len);
+ convert_setup(&vc, NULL, NULL);
+ }
+ }
+
+ return tmpbuf;
+}
+
+ char_u *
+hangul_composing_buffer_get(int *p_len)
+{
+ char_u *tmpbuf = NULL;
+
+ if (composing_hangul)
+ {
+ int len = 2;
+
+ tmpbuf = hangul_string_convert(composing_hangul_buffer, &len);
+ if (tmpbuf != NULL)
+ {
+ *p_len = len;
+ }
+ else
+ {
+ tmpbuf = vim_strnsave(composing_hangul_buffer, 2);
+ *p_len = 2;
+ }
+ }
+
+ return tmpbuf;
+}
diff --git a/src/hardcopy.c b/src/hardcopy.c
new file mode 100644
index 0000000..1ceed99
--- /dev/null
+++ b/src/hardcopy.c
@@ -0,0 +1,3499 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * hardcopy.c: printing to paper
+ */
+
+#include "vim.h"
+#include "version.h"
+
+#if defined(FEAT_PRINTER) || defined(PROTO)
+/*
+ * To implement printing on a platform, the following functions must be
+ * defined:
+ *
+ * int mch_print_init(prt_settings_T *psettings, char_u *jobname, int forceit)
+ * Called once. Code should display printer dialogue (if appropriate) and
+ * determine printer font and margin settings. Reset has_color if the printer
+ * doesn't support colors at all.
+ * Returns FAIL to abort.
+ *
+ * int mch_print_begin(prt_settings_T *settings)
+ * Called to start the print job.
+ * Return FALSE to abort.
+ *
+ * int mch_print_begin_page(char_u *msg)
+ * Called at the start of each page.
+ * "msg" indicates the progress of the print job, can be NULL.
+ * Return FALSE to abort.
+ *
+ * int mch_print_end_page()
+ * Called at the end of each page.
+ * Return FALSE to abort.
+ *
+ * int mch_print_blank_page()
+ * Called to generate a blank page for collated, duplex, multiple copy
+ * document. Return FALSE to abort.
+ *
+ * void mch_print_end(prt_settings_T *psettings)
+ * Called at normal end of print job.
+ *
+ * void mch_print_cleanup()
+ * Called if print job ends normally or is abandoned. Free any memory, close
+ * devices and handles. Also called when mch_print_begin() fails, but not
+ * when mch_print_init() fails.
+ *
+ * void mch_print_set_font(int Bold, int Italic, int Underline);
+ * Called whenever the font style changes.
+ *
+ * void mch_print_set_bg(long_u bgcol);
+ * Called to set the background color for the following text. Parameter is an
+ * RGB value.
+ *
+ * void mch_print_set_fg(long_u fgcol);
+ * Called to set the foreground color for the following text. Parameter is an
+ * RGB value.
+ *
+ * mch_print_start_line(int margin, int page_line)
+ * Sets the current position at the start of line "page_line".
+ * If margin is TRUE start in the left margin (for header and line number).
+ *
+ * int mch_print_text_out(char_u *p, int len);
+ * Output one character of text p[len] at the current position.
+ * Return TRUE if there is no room for another character in the same line.
+ *
+ * Note that the generic code has no idea of margins. The machine code should
+ * simply make the page look smaller! The header and the line numbers are
+ * printed in the margin.
+ */
+
+#ifdef FEAT_SYN_HL
+static const long_u cterm_color_8[8] =
+{
+ (long_u)0x000000L, (long_u)0xff0000L, (long_u)0x00ff00L, (long_u)0xffff00L,
+ (long_u)0x0000ffL, (long_u)0xff00ffL, (long_u)0x00ffffL, (long_u)0xffffffL
+};
+
+static const long_u cterm_color_16[16] =
+{
+ (long_u)0x000000L, (long_u)0x0000c0L, (long_u)0x008000L, (long_u)0x004080L,
+ (long_u)0xc00000L, (long_u)0xc000c0L, (long_u)0x808000L, (long_u)0xc0c0c0L,
+ (long_u)0x808080L, (long_u)0x6060ffL, (long_u)0x00ff00L, (long_u)0x00ffffL,
+ (long_u)0xff8080L, (long_u)0xff40ffL, (long_u)0xffff00L, (long_u)0xffffffL
+};
+
+static int current_syn_id;
+#endif
+
+#define PRCOLOR_BLACK (long_u)0
+#define PRCOLOR_WHITE (long_u)0xFFFFFFL
+
+static int curr_italic;
+static int curr_bold;
+static int curr_underline;
+static long_u curr_bg;
+static long_u curr_fg;
+static int page_count;
+
+#if defined(FEAT_POSTSCRIPT)
+# define OPT_MBFONT_USECOURIER 0
+# define OPT_MBFONT_ASCII 1
+# define OPT_MBFONT_REGULAR 2
+# define OPT_MBFONT_BOLD 3
+# define OPT_MBFONT_OBLIQUE 4
+# define OPT_MBFONT_BOLDOBLIQUE 5
+# define OPT_MBFONT_NUM_OPTIONS 6
+
+static option_table_T mbfont_opts[OPT_MBFONT_NUM_OPTIONS] =
+{
+ {"c", FALSE, 0, NULL, 0, FALSE},
+ {"a", FALSE, 0, NULL, 0, FALSE},
+ {"r", FALSE, 0, NULL, 0, FALSE},
+ {"b", FALSE, 0, NULL, 0, FALSE},
+ {"i", FALSE, 0, NULL, 0, FALSE},
+ {"o", FALSE, 0, NULL, 0, FALSE},
+};
+#endif
+
+/*
+ * These values determine the print position on a page.
+ */
+typedef struct
+{
+ int lead_spaces; /* remaining spaces for a TAB */
+ int print_pos; /* virtual column for computing TABs */
+ colnr_T column; /* byte column */
+ linenr_T file_line; /* line nr in the buffer */
+ long_u bytes_printed; /* bytes printed so far */
+ int ff; /* seen form feed character */
+} prt_pos_T;
+
+static char *parse_list_options(char_u *option_str, option_table_T *table, int table_size);
+
+static colnr_T hardcopy_line(prt_settings_T *psettings, int page_line, prt_pos_T *ppos);
+
+/*
+ * Parse 'printoptions' and set the flags in "printer_opts".
+ * Returns an error message or NULL;
+ */
+ char *
+parse_printoptions(void)
+{
+ return parse_list_options(p_popt, printer_opts, OPT_PRINT_NUM_OPTIONS);
+}
+
+#if defined(FEAT_POSTSCRIPT) || defined(PROTO)
+/*
+ * Parse 'printmbfont' and set the flags in "mbfont_opts".
+ * Returns an error message or NULL;
+ */
+ char *
+parse_printmbfont(void)
+{
+ return parse_list_options(p_pmfn, mbfont_opts, OPT_MBFONT_NUM_OPTIONS);
+}
+#endif
+
+/*
+ * Parse a list of options in the form
+ * option:value,option:value,option:value
+ *
+ * "value" can start with a number which is parsed out, e.g. margin:12mm
+ *
+ * Returns an error message for an illegal option, NULL otherwise.
+ * Only used for the printer at the moment...
+ */
+ static char *
+parse_list_options(
+ char_u *option_str,
+ option_table_T *table,
+ int table_size)
+{
+ option_table_T *old_opts;
+ char *ret = NULL;
+ char_u *stringp;
+ char_u *colonp;
+ char_u *commap;
+ char_u *p;
+ int idx = 0; /* init for GCC */
+ int len;
+
+ /* Save the old values, so that they can be restored in case of an error. */
+ old_opts = (option_table_T *)alloc(sizeof(option_table_T) * table_size);
+ if (old_opts == NULL)
+ return NULL;
+
+ for (idx = 0; idx < table_size; ++idx)
+ {
+ old_opts[idx] = table[idx];
+ table[idx].present = FALSE;
+ }
+
+ /*
+ * Repeat for all comma separated parts.
+ */
+ stringp = option_str;
+ while (*stringp)
+ {
+ colonp = vim_strchr(stringp, ':');
+ if (colonp == NULL)
+ {
+ ret = N_("E550: Missing colon");
+ break;
+ }
+ commap = vim_strchr(stringp, ',');
+ if (commap == NULL)
+ commap = option_str + STRLEN(option_str);
+
+ len = (int)(colonp - stringp);
+
+ for (idx = 0; idx < table_size; ++idx)
+ if (STRNICMP(stringp, table[idx].name, len) == 0)
+ break;
+
+ if (idx == table_size)
+ {
+ ret = N_("E551: Illegal component");
+ break;
+ }
+ p = colonp + 1;
+ table[idx].present = TRUE;
+
+ if (table[idx].hasnum)
+ {
+ if (!VIM_ISDIGIT(*p))
+ {
+ ret = N_("E552: digit expected");
+ break;
+ }
+
+ table[idx].number = getdigits(&p); /*advances p*/
+ }
+
+ table[idx].string = p;
+ table[idx].strlen = (int)(commap - p);
+
+ stringp = commap;
+ if (*stringp == ',')
+ ++stringp;
+ }
+
+ if (ret != NULL)
+ {
+ /* Restore old options in case of error */
+ for (idx = 0; idx < table_size; ++idx)
+ table[idx] = old_opts[idx];
+ }
+ vim_free(old_opts);
+ return ret;
+}
+
+
+#ifdef FEAT_SYN_HL
+/*
+ * If using a dark background, the colors will probably be too bright to show
+ * up well on white paper, so reduce their brightness.
+ */
+ static long_u
+darken_rgb(long_u rgb)
+{
+ return ((rgb >> 17) << 16)
+ + (((rgb & 0xff00) >> 9) << 8)
+ + ((rgb & 0xff) >> 1);
+}
+
+ static long_u
+prt_get_term_color(int colorindex)
+{
+ /* TODO: Should check for xterm with 88 or 256 colors. */
+ if (t_colors > 8)
+ return cterm_color_16[colorindex % 16];
+ return cterm_color_8[colorindex % 8];
+}
+
+ static void
+prt_get_attr(
+ int hl_id,
+ prt_text_attr_T *pattr,
+ int modec)
+{
+ int colorindex;
+ long_u fg_color;
+ long_u bg_color;
+ char *color;
+
+ pattr->bold = (highlight_has_attr(hl_id, HL_BOLD, modec) != NULL);
+ pattr->italic = (highlight_has_attr(hl_id, HL_ITALIC, modec) != NULL);
+ pattr->underline = (highlight_has_attr(hl_id, HL_UNDERLINE, modec) != NULL);
+ pattr->undercurl = (highlight_has_attr(hl_id, HL_UNDERCURL, modec) != NULL);
+
+# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
+ if (USE_24BIT)
+ {
+ bg_color = highlight_gui_color_rgb(hl_id, FALSE);
+ if (bg_color == PRCOLOR_BLACK)
+ bg_color = PRCOLOR_WHITE;
+
+ fg_color = highlight_gui_color_rgb(hl_id, TRUE);
+ }
+ else
+# endif
+ {
+ bg_color = PRCOLOR_WHITE;
+
+ color = (char *)highlight_color(hl_id, (char_u *)"fg", modec);
+ if (color == NULL)
+ colorindex = 0;
+ else
+ colorindex = atoi(color);
+
+ if (colorindex >= 0 && colorindex < t_colors)
+ fg_color = prt_get_term_color(colorindex);
+ else
+ fg_color = PRCOLOR_BLACK;
+ }
+
+ if (fg_color == PRCOLOR_WHITE)
+ fg_color = PRCOLOR_BLACK;
+ else if (*p_bg == 'd')
+ fg_color = darken_rgb(fg_color);
+
+ pattr->fg_color = fg_color;
+ pattr->bg_color = bg_color;
+}
+#endif /* FEAT_SYN_HL */
+
+ static void
+prt_set_fg(long_u fg)
+{
+ if (fg != curr_fg)
+ {
+ curr_fg = fg;
+ mch_print_set_fg(fg);
+ }
+}
+
+ static void
+prt_set_bg(long_u bg)
+{
+ if (bg != curr_bg)
+ {
+ curr_bg = bg;
+ mch_print_set_bg(bg);
+ }
+}
+
+ static void
+prt_set_font(int bold, int italic, int underline)
+{
+ if (curr_bold != bold
+ || curr_italic != italic
+ || curr_underline != underline)
+ {
+ curr_underline = underline;
+ curr_italic = italic;
+ curr_bold = bold;
+ mch_print_set_font(bold, italic, underline);
+ }
+}
+
+/*
+ * Print the line number in the left margin.
+ */
+ static void
+prt_line_number(
+ prt_settings_T *psettings,
+ int page_line,
+ linenr_T lnum)
+{
+ int i;
+ char_u tbuf[20];
+
+ prt_set_fg(psettings->number.fg_color);
+ prt_set_bg(psettings->number.bg_color);
+ prt_set_font(psettings->number.bold, psettings->number.italic, psettings->number.underline);
+ mch_print_start_line(TRUE, page_line);
+
+ /* Leave two spaces between the number and the text; depends on
+ * PRINT_NUMBER_WIDTH. */
+ sprintf((char *)tbuf, "%6ld", (long)lnum);
+ for (i = 0; i < 6; i++)
+ (void)mch_print_text_out(&tbuf[i], 1);
+
+#ifdef FEAT_SYN_HL
+ if (psettings->do_syntax)
+ /* Set colors for next character. */
+ current_syn_id = -1;
+ else
+#endif
+ {
+ /* Set colors and font back to normal. */
+ prt_set_fg(PRCOLOR_BLACK);
+ prt_set_bg(PRCOLOR_WHITE);
+ prt_set_font(FALSE, FALSE, FALSE);
+ }
+}
+
+/*
+ * Get the currently effective header height.
+ */
+ int
+prt_header_height(void)
+{
+ if (printer_opts[OPT_PRINT_HEADERHEIGHT].present)
+ return printer_opts[OPT_PRINT_HEADERHEIGHT].number;
+ return 2;
+}
+
+/*
+ * Return TRUE if using a line number for printing.
+ */
+ int
+prt_use_number(void)
+{
+ return (printer_opts[OPT_PRINT_NUMBER].present
+ && TOLOWER_ASC(printer_opts[OPT_PRINT_NUMBER].string[0]) == 'y');
+}
+
+/*
+ * Return the unit used in a margin item in 'printoptions'.
+ * Returns PRT_UNIT_NONE if not recognized.
+ */
+ int
+prt_get_unit(int idx)
+{
+ int u = PRT_UNIT_NONE;
+ int i;
+ static char *(units[4]) = PRT_UNIT_NAMES;
+
+ if (printer_opts[idx].present)
+ for (i = 0; i < 4; ++i)
+ if (STRNICMP(printer_opts[idx].string, units[i], 2) == 0)
+ {
+ u = i;
+ break;
+ }
+ return u;
+}
+
+/*
+ * Print the page header.
+ */
+ static void
+prt_header(
+ prt_settings_T *psettings,
+ int pagenum,
+ linenr_T lnum UNUSED)
+{
+ int width = psettings->chars_per_line;
+ int page_line;
+ char_u *tbuf;
+ char_u *p;
+ int l;
+
+ /* Also use the space for the line number. */
+ if (prt_use_number())
+ width += PRINT_NUMBER_WIDTH;
+
+ tbuf = alloc(width + IOSIZE);
+ if (tbuf == NULL)
+ return;
+
+#ifdef FEAT_STL_OPT
+ if (*p_header != NUL)
+ {
+ linenr_T tmp_lnum, tmp_topline, tmp_botline;
+ int use_sandbox = FALSE;
+
+ /*
+ * Need to (temporarily) set current line number and first/last line
+ * number on the 'window'. Since we don't know how long the page is,
+ * set the first and current line number to the top line, and guess
+ * that the page length is 64.
+ */
+ tmp_lnum = curwin->w_cursor.lnum;
+ tmp_topline = curwin->w_topline;
+ tmp_botline = curwin->w_botline;
+ curwin->w_cursor.lnum = lnum;
+ curwin->w_topline = lnum;
+ curwin->w_botline = lnum + 63;
+ printer_page_num = pagenum;
+
+# ifdef FEAT_EVAL
+ use_sandbox = was_set_insecurely((char_u *)"printheader", 0);
+# endif
+ build_stl_str_hl(curwin, tbuf, (size_t)(width + IOSIZE),
+ p_header, use_sandbox,
+ ' ', width, NULL, NULL);
+
+ /* Reset line numbers */
+ curwin->w_cursor.lnum = tmp_lnum;
+ curwin->w_topline = tmp_topline;
+ curwin->w_botline = tmp_botline;
+ }
+ else
+#endif
+ sprintf((char *)tbuf, _("Page %d"), pagenum);
+
+ prt_set_fg(PRCOLOR_BLACK);
+ prt_set_bg(PRCOLOR_WHITE);
+ prt_set_font(TRUE, FALSE, FALSE);
+
+ /* Use a negative line number to indicate printing in the top margin. */
+ page_line = 0 - prt_header_height();
+ mch_print_start_line(TRUE, page_line);
+ for (p = tbuf; *p != NUL; )
+ {
+ if (mch_print_text_out(p, (l = (*mb_ptr2len)(p))))
+ {
+ ++page_line;
+ if (page_line >= 0) /* out of room in header */
+ break;
+ mch_print_start_line(TRUE, page_line);
+ }
+ p += l;
+ }
+
+ vim_free(tbuf);
+
+#ifdef FEAT_SYN_HL
+ if (psettings->do_syntax)
+ /* Set colors for next character. */
+ current_syn_id = -1;
+ else
+#endif
+ {
+ /* Set colors and font back to normal. */
+ prt_set_fg(PRCOLOR_BLACK);
+ prt_set_bg(PRCOLOR_WHITE);
+ prt_set_font(FALSE, FALSE, FALSE);
+ }
+}
+
+/*
+ * Display a print status message.
+ */
+ static void
+prt_message(char_u *s)
+{
+ screen_fill((int)Rows - 1, (int)Rows, 0, (int)Columns, ' ', ' ', 0);
+ screen_puts(s, (int)Rows - 1, 0, HL_ATTR(HLF_R));
+ out_flush();
+}
+
+ void
+ex_hardcopy(exarg_T *eap)
+{
+ linenr_T lnum;
+ int collated_copies, uncollated_copies;
+ prt_settings_T settings;
+ long_u bytes_to_print = 0;
+ int page_line;
+ int jobsplit;
+
+ vim_memset(&settings, 0, sizeof(prt_settings_T));
+ settings.has_color = TRUE;
+
+# ifdef FEAT_POSTSCRIPT
+ if (*eap->arg == '>')
+ {
+ char *errormsg = NULL;
+
+ /* Expand things like "%.ps". */
+ if (expand_filename(eap, eap->cmdlinep, &errormsg) == FAIL)
+ {
+ if (errormsg != NULL)
+ emsg(errormsg);
+ return;
+ }
+ settings.outfile = skipwhite(eap->arg + 1);
+ }
+ else if (*eap->arg != NUL)
+ settings.arguments = eap->arg;
+# endif
+
+ /*
+ * Initialise for printing. Ask the user for settings, unless forceit is
+ * set.
+ * The mch_print_init() code should set up margins if applicable. (It may
+ * not be a real printer - for example the engine might generate HTML or
+ * PS.)
+ */
+ if (mch_print_init(&settings,
+ curbuf->b_fname == NULL
+ ? (char_u *)buf_spname(curbuf)
+ : curbuf->b_sfname == NULL
+ ? curbuf->b_fname
+ : curbuf->b_sfname,
+ eap->forceit) == FAIL)
+ return;
+
+#ifdef FEAT_SYN_HL
+# ifdef FEAT_GUI
+ if (gui.in_use)
+ settings.modec = 'g';
+ else
+# endif
+ if (t_colors > 1)
+ settings.modec = 'c';
+ else
+ settings.modec = 't';
+
+ if (!syntax_present(curwin))
+ settings.do_syntax = FALSE;
+ else if (printer_opts[OPT_PRINT_SYNTAX].present
+ && TOLOWER_ASC(printer_opts[OPT_PRINT_SYNTAX].string[0]) != 'a')
+ settings.do_syntax =
+ (TOLOWER_ASC(printer_opts[OPT_PRINT_SYNTAX].string[0]) == 'y');
+ else
+ settings.do_syntax = settings.has_color;
+#endif
+
+ /* Set up printing attributes for line numbers */
+ settings.number.fg_color = PRCOLOR_BLACK;
+ settings.number.bg_color = PRCOLOR_WHITE;
+ settings.number.bold = FALSE;
+ settings.number.italic = TRUE;
+ settings.number.underline = FALSE;
+#ifdef FEAT_SYN_HL
+ /*
+ * Syntax highlighting of line numbers.
+ */
+ if (prt_use_number() && settings.do_syntax)
+ {
+ int id;
+
+ id = syn_name2id((char_u *)"LineNr");
+ if (id > 0)
+ id = syn_get_final_id(id);
+
+ prt_get_attr(id, &settings.number, settings.modec);
+ }
+#endif
+
+ /*
+ * Estimate the total lines to be printed
+ */
+ for (lnum = eap->line1; lnum <= eap->line2; lnum++)
+ bytes_to_print += (long_u)STRLEN(skipwhite(ml_get(lnum)));
+ if (bytes_to_print == 0)
+ {
+ msg(_("No text to be printed"));
+ goto print_fail_no_begin;
+ }
+
+ /* Set colors and font to normal. */
+ curr_bg = (long_u)0xffffffffL;
+ curr_fg = (long_u)0xffffffffL;
+ curr_italic = MAYBE;
+ curr_bold = MAYBE;
+ curr_underline = MAYBE;
+
+ prt_set_fg(PRCOLOR_BLACK);
+ prt_set_bg(PRCOLOR_WHITE);
+ prt_set_font(FALSE, FALSE, FALSE);
+#ifdef FEAT_SYN_HL
+ current_syn_id = -1;
+#endif
+
+ jobsplit = (printer_opts[OPT_PRINT_JOBSPLIT].present
+ && TOLOWER_ASC(printer_opts[OPT_PRINT_JOBSPLIT].string[0]) == 'y');
+
+ if (!mch_print_begin(&settings))
+ goto print_fail_no_begin;
+
+ /*
+ * Loop over collated copies: 1 2 3, 1 2 3, ...
+ */
+ page_count = 0;
+ for (collated_copies = 0;
+ collated_copies < settings.n_collated_copies;
+ collated_copies++)
+ {
+ prt_pos_T prtpos; /* current print position */
+ prt_pos_T page_prtpos; /* print position at page start */
+ int side;
+
+ vim_memset(&page_prtpos, 0, sizeof(prt_pos_T));
+ page_prtpos.file_line = eap->line1;
+ prtpos = page_prtpos;
+
+ if (jobsplit && collated_copies > 0)
+ {
+ /* Splitting jobs: Stop a previous job and start a new one. */
+ mch_print_end(&settings);
+ if (!mch_print_begin(&settings))
+ goto print_fail_no_begin;
+ }
+
+ /*
+ * Loop over all pages in the print job: 1 2 3 ...
+ */
+ for (page_count = 0; prtpos.file_line <= eap->line2; ++page_count)
+ {
+ /*
+ * Loop over uncollated copies: 1 1 1, 2 2 2, 3 3 3, ...
+ * For duplex: 12 12 12 34 34 34, ...
+ */
+ for (uncollated_copies = 0;
+ uncollated_copies < settings.n_uncollated_copies;
+ uncollated_copies++)
+ {
+ /* Set the print position to the start of this page. */
+ prtpos = page_prtpos;
+
+ /*
+ * Do front and rear side of a page.
+ */
+ for (side = 0; side <= settings.duplex; ++side)
+ {
+ /*
+ * Print one page.
+ */
+
+ /* Check for interrupt character every page. */
+ ui_breakcheck();
+ if (got_int || settings.user_abort)
+ goto print_fail;
+
+ sprintf((char *)IObuff, _("Printing page %d (%d%%)"),
+ page_count + 1 + side,
+ prtpos.bytes_printed > 1000000
+ ? (int)(prtpos.bytes_printed /
+ (bytes_to_print / 100))
+ : (int)((prtpos.bytes_printed * 100)
+ / bytes_to_print));
+ if (!mch_print_begin_page(IObuff))
+ goto print_fail;
+
+ if (settings.n_collated_copies > 1)
+ sprintf((char *)IObuff + STRLEN(IObuff),
+ _(" Copy %d of %d"),
+ collated_copies + 1,
+ settings.n_collated_copies);
+ prt_message(IObuff);
+
+ /*
+ * Output header if required
+ */
+ if (prt_header_height() > 0)
+ prt_header(&settings, page_count + 1 + side,
+ prtpos.file_line);
+
+ for (page_line = 0; page_line < settings.lines_per_page;
+ ++page_line)
+ {
+ prtpos.column = hardcopy_line(&settings,
+ page_line, &prtpos);
+ if (prtpos.column == 0)
+ {
+ /* finished a file line */
+ prtpos.bytes_printed +=
+ STRLEN(skipwhite(ml_get(prtpos.file_line)));
+ if (++prtpos.file_line > eap->line2)
+ break; /* reached the end */
+ }
+ else if (prtpos.ff)
+ {
+ /* Line had a formfeed in it - start new page but
+ * stay on the current line */
+ break;
+ }
+ }
+
+ if (!mch_print_end_page())
+ goto print_fail;
+ if (prtpos.file_line > eap->line2)
+ break; /* reached the end */
+ }
+
+ /*
+ * Extra blank page for duplexing with odd number of pages and
+ * more copies to come.
+ */
+ if (prtpos.file_line > eap->line2 && settings.duplex
+ && side == 0
+ && uncollated_copies + 1 < settings.n_uncollated_copies)
+ {
+ if (!mch_print_blank_page())
+ goto print_fail;
+ }
+ }
+ if (settings.duplex && prtpos.file_line <= eap->line2)
+ ++page_count;
+
+ /* Remember the position where the next page starts. */
+ page_prtpos = prtpos;
+ }
+
+ vim_snprintf((char *)IObuff, IOSIZE, _("Printed: %s"),
+ settings.jobname);
+ prt_message(IObuff);
+ }
+
+print_fail:
+ if (got_int || settings.user_abort)
+ {
+ sprintf((char *)IObuff, "%s", _("Printing aborted"));
+ prt_message(IObuff);
+ }
+ mch_print_end(&settings);
+
+print_fail_no_begin:
+ mch_print_cleanup();
+}
+
+/*
+ * Print one page line.
+ * Return the next column to print, or zero if the line is finished.
+ */
+ static colnr_T
+hardcopy_line(
+ prt_settings_T *psettings,
+ int page_line,
+ prt_pos_T *ppos)
+{
+ colnr_T col;
+ char_u *line;
+ int need_break = FALSE;
+ int outputlen;
+ int tab_spaces;
+ long_u print_pos;
+#ifdef FEAT_SYN_HL
+ prt_text_attr_T attr;
+ int id;
+#endif
+
+ if (ppos->column == 0 || ppos->ff)
+ {
+ print_pos = 0;
+ tab_spaces = 0;
+ if (!ppos->ff && prt_use_number())
+ prt_line_number(psettings, page_line, ppos->file_line);
+ ppos->ff = FALSE;
+ }
+ else
+ {
+ /* left over from wrap halfway a tab */
+ print_pos = ppos->print_pos;
+ tab_spaces = ppos->lead_spaces;
+ }
+
+ mch_print_start_line(0, page_line);
+ line = ml_get(ppos->file_line);
+
+ /*
+ * Loop over the columns until the end of the file line or right margin.
+ */
+ for (col = ppos->column; line[col] != NUL && !need_break; col += outputlen)
+ {
+ outputlen = 1;
+ if (has_mbyte && (outputlen = (*mb_ptr2len)(line + col)) < 1)
+ outputlen = 1;
+#ifdef FEAT_SYN_HL
+ /*
+ * syntax highlighting stuff.
+ */
+ if (psettings->do_syntax)
+ {
+ id = syn_get_id(curwin, ppos->file_line, col, 1, NULL, FALSE);
+ if (id > 0)
+ id = syn_get_final_id(id);
+ else
+ id = 0;
+ /* Get the line again, a multi-line regexp may invalidate it. */
+ line = ml_get(ppos->file_line);
+
+ if (id != current_syn_id)
+ {
+ current_syn_id = id;
+ prt_get_attr(id, &attr, psettings->modec);
+ prt_set_font(attr.bold, attr.italic, attr.underline);
+ prt_set_fg(attr.fg_color);
+ prt_set_bg(attr.bg_color);
+ }
+ }
+#endif
+
+ /*
+ * Appropriately expand any tabs to spaces.
+ */
+ if (line[col] == TAB || tab_spaces != 0)
+ {
+ if (tab_spaces == 0)
+#ifdef FEAT_VARTABS
+ tab_spaces = tabstop_padding(print_pos, curbuf->b_p_ts,
+ curbuf->b_p_vts_array);
+#else
+ tab_spaces = (int)(curbuf->b_p_ts - (print_pos % curbuf->b_p_ts));
+#endif
+
+ while (tab_spaces > 0)
+ {
+ need_break = mch_print_text_out((char_u *)" ", 1);
+ print_pos++;
+ tab_spaces--;
+ if (need_break)
+ break;
+ }
+ /* Keep the TAB if we didn't finish it. */
+ if (need_break && tab_spaces > 0)
+ break;
+ }
+ else if (line[col] == FF
+ && printer_opts[OPT_PRINT_FORMFEED].present
+ && TOLOWER_ASC(printer_opts[OPT_PRINT_FORMFEED].string[0])
+ == 'y')
+ {
+ ppos->ff = TRUE;
+ need_break = 1;
+ }
+ else
+ {
+ need_break = mch_print_text_out(line + col, outputlen);
+ if (has_mbyte)
+ print_pos += (*mb_ptr2cells)(line + col);
+ else
+ print_pos++;
+ }
+ }
+
+ ppos->lead_spaces = tab_spaces;
+ ppos->print_pos = (int)print_pos;
+
+ /*
+ * Start next line of file if we clip lines, or have reached end of the
+ * line, unless we are doing a formfeed.
+ */
+ if (!ppos->ff
+ && (line[col] == NUL
+ || (printer_opts[OPT_PRINT_WRAP].present
+ && TOLOWER_ASC(printer_opts[OPT_PRINT_WRAP].string[0])
+ == 'n')))
+ return 0;
+ return col;
+}
+
+# if defined(FEAT_POSTSCRIPT) || defined(PROTO)
+
+/*
+ * PS printer stuff.
+ *
+ * Sources of information to help maintain the PS printing code:
+ *
+ * 1. PostScript Language Reference, 3rd Edition,
+ * Addison-Wesley, 1999, ISBN 0-201-37922-8
+ * 2. PostScript Language Program Design,
+ * Addison-Wesley, 1988, ISBN 0-201-14396-8
+ * 3. PostScript Tutorial and Cookbook,
+ * Addison Wesley, 1985, ISBN 0-201-10179-3
+ * 4. PostScript Language Document Structuring Conventions Specification,
+ * version 3.0,
+ * Adobe Technote 5001, 25th September 1992
+ * 5. PostScript Printer Description File Format Specification, Version 4.3,
+ * Adobe technote 5003, 9th February 1996
+ * 6. Adobe Font Metrics File Format Specification, Version 4.1,
+ * Adobe Technote 5007, 7th October 1998
+ * 7. Adobe CMap and CIDFont Files Specification, Version 1.0,
+ * Adobe Technote 5014, 8th October 1996
+ * 8. Adobe CJKV Character Collections and CMaps for CID-Keyed Fonts,
+ * Adoboe Technote 5094, 8th September, 2001
+ * 9. CJKV Information Processing, 2nd Edition,
+ * O'Reilly, 2002, ISBN 1-56592-224-7
+ *
+ * Some of these documents can be found in PDF form on Adobe's web site -
+ * http://www.adobe.com
+ */
+
+#define NUM_ELEMENTS(arr) (sizeof(arr)/sizeof((arr)[0]))
+
+#define PRT_PS_DEFAULT_DPI (72) /* Default user space resolution */
+#define PRT_PS_DEFAULT_FONTSIZE (10)
+#define PRT_PS_DEFAULT_BUFFER_SIZE (80)
+
+struct prt_mediasize_S
+{
+ char *name;
+ float width; /* width and height in points for portrait */
+ float height;
+};
+
+#define PRT_MEDIASIZE_LEN (sizeof(prt_mediasize) / sizeof(struct prt_mediasize_S))
+
+static struct prt_mediasize_S prt_mediasize[] =
+{
+ {"A4", 595.0, 842.0},
+ {"letter", 612.0, 792.0},
+ {"10x14", 720.0, 1008.0},
+ {"A3", 842.0, 1191.0},
+ {"A5", 420.0, 595.0},
+ {"B4", 729.0, 1032.0},
+ {"B5", 516.0, 729.0},
+ {"executive", 522.0, 756.0},
+ {"folio", 595.0, 935.0},
+ {"ledger", 1224.0, 792.0}, /* Yes, it is wider than taller! */
+ {"legal", 612.0, 1008.0},
+ {"quarto", 610.0, 780.0},
+ {"statement", 396.0, 612.0},
+ {"tabloid", 792.0, 1224.0}
+};
+
+/* PS font names, must be in Roman, Bold, Italic, Bold-Italic order */
+struct prt_ps_font_S
+{
+ int wx;
+ int uline_offset;
+ int uline_width;
+ int bbox_min_y;
+ int bbox_max_y;
+ char *(ps_fontname[4]);
+};
+
+#define PRT_PS_FONT_ROMAN (0)
+#define PRT_PS_FONT_BOLD (1)
+#define PRT_PS_FONT_OBLIQUE (2)
+#define PRT_PS_FONT_BOLDOBLIQUE (3)
+
+/* Standard font metrics for Courier family */
+static struct prt_ps_font_S prt_ps_courier_font =
+{
+ 600,
+ -100, 50,
+ -250, 805,
+ {"Courier", "Courier-Bold", "Courier-Oblique", "Courier-BoldOblique"}
+};
+
+/* Generic font metrics for multi-byte fonts */
+static struct prt_ps_font_S prt_ps_mb_font =
+{
+ 1000,
+ -100, 50,
+ -250, 805,
+ {NULL, NULL, NULL, NULL}
+};
+
+/* Pointer to current font set being used */
+static struct prt_ps_font_S* prt_ps_font;
+
+/* Structures to map user named encoding and mapping to PS equivalents for
+ * building CID font name */
+struct prt_ps_encoding_S
+{
+ char *encoding;
+ char *cmap_encoding;
+ int needs_charset;
+};
+
+struct prt_ps_charset_S
+{
+ char *charset;
+ char *cmap_charset;
+ int has_charset;
+};
+
+
+#define CS_JIS_C_1978 (0x01)
+#define CS_JIS_X_1983 (0x02)
+#define CS_JIS_X_1990 (0x04)
+#define CS_NEC (0x08)
+#define CS_MSWINDOWS (0x10)
+#define CS_CP932 (0x20)
+#define CS_KANJITALK6 (0x40)
+#define CS_KANJITALK7 (0x80)
+
+/* Japanese encodings and charsets */
+static struct prt_ps_encoding_S j_encodings[] =
+{
+ {"iso-2022-jp", NULL, (CS_JIS_C_1978|CS_JIS_X_1983|CS_JIS_X_1990|
+ CS_NEC)},
+ {"euc-jp", "EUC", (CS_JIS_C_1978|CS_JIS_X_1983|CS_JIS_X_1990)},
+ {"sjis", "RKSJ", (CS_JIS_C_1978|CS_JIS_X_1983|CS_MSWINDOWS|
+ CS_KANJITALK6|CS_KANJITALK7)},
+ {"cp932", "RKSJ", CS_JIS_X_1983},
+ {"ucs-2", "UCS2", CS_JIS_X_1990},
+ {"utf-8", "UTF8" , CS_JIS_X_1990}
+};
+static struct prt_ps_charset_S j_charsets[] =
+{
+ {"JIS_C_1978", "78", CS_JIS_C_1978},
+ {"JIS_X_1983", NULL, CS_JIS_X_1983},
+ {"JIS_X_1990", "Hojo", CS_JIS_X_1990},
+ {"NEC", "Ext", CS_NEC},
+ {"MSWINDOWS", "90ms", CS_MSWINDOWS},
+ {"CP932", "90ms", CS_JIS_X_1983},
+ {"KANJITALK6", "83pv", CS_KANJITALK6},
+ {"KANJITALK7", "90pv", CS_KANJITALK7}
+};
+
+#define CS_GB_2312_80 (0x01)
+#define CS_GBT_12345_90 (0x02)
+#define CS_GBK2K (0x04)
+#define CS_SC_MAC (0x08)
+#define CS_GBT_90_MAC (0x10)
+#define CS_GBK (0x20)
+#define CS_SC_ISO10646 (0x40)
+
+/* Simplified Chinese encodings and charsets */
+static struct prt_ps_encoding_S sc_encodings[] =
+{
+ {"iso-2022", NULL, (CS_GB_2312_80|CS_GBT_12345_90)},
+ {"gb18030", NULL, CS_GBK2K},
+ {"euc-cn", "EUC", (CS_GB_2312_80|CS_GBT_12345_90|CS_SC_MAC|
+ CS_GBT_90_MAC)},
+ {"gbk", "EUC", CS_GBK},
+ {"ucs-2", "UCS2", CS_SC_ISO10646},
+ {"utf-8", "UTF8", CS_SC_ISO10646}
+};
+static struct prt_ps_charset_S sc_charsets[] =
+{
+ {"GB_2312-80", "GB", CS_GB_2312_80},
+ {"GBT_12345-90","GBT", CS_GBT_12345_90},
+ {"MAC", "GBpc", CS_SC_MAC},
+ {"GBT-90_MAC", "GBTpc", CS_GBT_90_MAC},
+ {"GBK", "GBK", CS_GBK},
+ {"GB18030", "GBK2K", CS_GBK2K},
+ {"ISO10646", "UniGB", CS_SC_ISO10646}
+};
+
+#define CS_CNS_PLANE_1 (0x01)
+#define CS_CNS_PLANE_2 (0x02)
+#define CS_CNS_PLANE_1_2 (0x04)
+#define CS_B5 (0x08)
+#define CS_ETEN (0x10)
+#define CS_HK_GCCS (0x20)
+#define CS_HK_SCS (0x40)
+#define CS_HK_SCS_ETEN (0x80)
+#define CS_MTHKL (0x100)
+#define CS_MTHKS (0x200)
+#define CS_DLHKL (0x400)
+#define CS_DLHKS (0x800)
+#define CS_TC_ISO10646 (0x1000)
+
+/* Traditional Chinese encodings and charsets */
+static struct prt_ps_encoding_S tc_encodings[] =
+{
+ {"iso-2022", NULL, (CS_CNS_PLANE_1|CS_CNS_PLANE_2)},
+ {"euc-tw", "EUC", CS_CNS_PLANE_1_2},
+ {"big5", "B5", (CS_B5|CS_ETEN|CS_HK_GCCS|CS_HK_SCS|
+ CS_HK_SCS_ETEN|CS_MTHKL|CS_MTHKS|CS_DLHKL|
+ CS_DLHKS)},
+ {"cp950", "B5", CS_B5},
+ {"ucs-2", "UCS2", CS_TC_ISO10646},
+ {"utf-8", "UTF8", CS_TC_ISO10646},
+ {"utf-16", "UTF16", CS_TC_ISO10646},
+ {"utf-32", "UTF32", CS_TC_ISO10646}
+};
+static struct prt_ps_charset_S tc_charsets[] =
+{
+ {"CNS_1992_1", "CNS1", CS_CNS_PLANE_1},
+ {"CNS_1992_2", "CNS2", CS_CNS_PLANE_2},
+ {"CNS_1993", "CNS", CS_CNS_PLANE_1_2},
+ {"BIG5", NULL, CS_B5},
+ {"CP950", NULL, CS_B5},
+ {"ETEN", "ETen", CS_ETEN},
+ {"HK_GCCS", "HKgccs", CS_HK_GCCS},
+ {"SCS", "HKscs", CS_HK_SCS},
+ {"SCS_ETEN", "ETHK", CS_HK_SCS_ETEN},
+ {"MTHKL", "HKm471", CS_MTHKL},
+ {"MTHKS", "HKm314", CS_MTHKS},
+ {"DLHKL", "HKdla", CS_DLHKL},
+ {"DLHKS", "HKdlb", CS_DLHKS},
+ {"ISO10646", "UniCNS", CS_TC_ISO10646}
+};
+
+#define CS_KR_X_1992 (0x01)
+#define CS_KR_MAC (0x02)
+#define CS_KR_X_1992_MS (0x04)
+#define CS_KR_ISO10646 (0x08)
+
+/* Korean encodings and charsets */
+static struct prt_ps_encoding_S k_encodings[] =
+{
+ {"iso-2022-kr", NULL, CS_KR_X_1992},
+ {"euc-kr", "EUC", (CS_KR_X_1992|CS_KR_MAC)},
+ {"johab", "Johab", CS_KR_X_1992},
+ {"cp1361", "Johab", CS_KR_X_1992},
+ {"uhc", "UHC", CS_KR_X_1992_MS},
+ {"cp949", "UHC", CS_KR_X_1992_MS},
+ {"ucs-2", "UCS2", CS_KR_ISO10646},
+ {"utf-8", "UTF8", CS_KR_ISO10646}
+};
+static struct prt_ps_charset_S k_charsets[] =
+{
+ {"KS_X_1992", "KSC", CS_KR_X_1992},
+ {"CP1361", "KSC", CS_KR_X_1992},
+ {"MAC", "KSCpc", CS_KR_MAC},
+ {"MSWINDOWS", "KSCms", CS_KR_X_1992_MS},
+ {"CP949", "KSCms", CS_KR_X_1992_MS},
+ {"WANSUNG", "KSCms", CS_KR_X_1992_MS},
+ {"ISO10646", "UniKS", CS_KR_ISO10646}
+};
+
+/* Collections of encodings and charsets for multi-byte printing */
+struct prt_ps_mbfont_S
+{
+ int num_encodings;
+ struct prt_ps_encoding_S *encodings;
+ int num_charsets;
+ struct prt_ps_charset_S *charsets;
+ char *ascii_enc;
+ char *defcs;
+};
+
+static struct prt_ps_mbfont_S prt_ps_mbfonts[] =
+{
+ {
+ NUM_ELEMENTS(j_encodings),
+ j_encodings,
+ NUM_ELEMENTS(j_charsets),
+ j_charsets,
+ "jis_roman",
+ "JIS_X_1983"
+ },
+ {
+ NUM_ELEMENTS(sc_encodings),
+ sc_encodings,
+ NUM_ELEMENTS(sc_charsets),
+ sc_charsets,
+ "gb_roman",
+ "GB_2312-80"
+ },
+ {
+ NUM_ELEMENTS(tc_encodings),
+ tc_encodings,
+ NUM_ELEMENTS(tc_charsets),
+ tc_charsets,
+ "cns_roman",
+ "BIG5"
+ },
+ {
+ NUM_ELEMENTS(k_encodings),
+ k_encodings,
+ NUM_ELEMENTS(k_charsets),
+ k_charsets,
+ "ks_roman",
+ "KS_X_1992"
+ }
+};
+
+struct prt_ps_resource_S
+{
+ char_u name[64];
+ char_u filename[MAXPATHL + 1];
+ int type;
+ char_u title[256];
+ char_u version[256];
+};
+
+/* Types of PS resource file currently used */
+#define PRT_RESOURCE_TYPE_PROCSET (0)
+#define PRT_RESOURCE_TYPE_ENCODING (1)
+#define PRT_RESOURCE_TYPE_CMAP (2)
+
+/* The PS prolog file version number has to match - if the prolog file is
+ * updated, increment the number in the file and here. Version checking was
+ * added as of VIM 6.2.
+ * The CID prolog file version number behaves as per PS prolog.
+ * Table of VIM and prolog versions:
+ *
+ * VIM Prolog CIDProlog
+ * 6.2 1.3
+ * 7.0 1.4 1.0
+ */
+#define PRT_PROLOG_VERSION ((char_u *)"1.4")
+#define PRT_CID_PROLOG_VERSION ((char_u *)"1.0")
+
+/* String versions of PS resource types - indexed by constants above so don't
+ * re-order!
+ */
+static char *prt_resource_types[] =
+{
+ "procset",
+ "encoding",
+ "cmap"
+};
+
+/* Strings to look for in a PS resource file */
+#define PRT_RESOURCE_HEADER "%!PS-Adobe-"
+#define PRT_RESOURCE_RESOURCE "Resource-"
+#define PRT_RESOURCE_PROCSET "ProcSet"
+#define PRT_RESOURCE_ENCODING "Encoding"
+#define PRT_RESOURCE_CMAP "CMap"
+
+
+/* Data for table based DSC comment recognition, easy to extend if VIM needs to
+ * read more comments. */
+#define PRT_DSC_MISC_TYPE (-1)
+#define PRT_DSC_TITLE_TYPE (1)
+#define PRT_DSC_VERSION_TYPE (2)
+#define PRT_DSC_ENDCOMMENTS_TYPE (3)
+
+#define PRT_DSC_TITLE "%%Title:"
+#define PRT_DSC_VERSION "%%Version:"
+#define PRT_DSC_ENDCOMMENTS "%%EndComments:"
+
+struct prt_dsc_comment_S
+{
+ char *string;
+ int len;
+ int type;
+};
+
+struct prt_dsc_line_S
+{
+ int type;
+ char_u *string;
+ int len;
+};
+
+
+#define SIZEOF_CSTR(s) (sizeof(s) - 1)
+static struct prt_dsc_comment_S prt_dsc_table[] =
+{
+ {PRT_DSC_TITLE, SIZEOF_CSTR(PRT_DSC_TITLE), PRT_DSC_TITLE_TYPE},
+ {PRT_DSC_VERSION, SIZEOF_CSTR(PRT_DSC_VERSION),
+ PRT_DSC_VERSION_TYPE},
+ {PRT_DSC_ENDCOMMENTS, SIZEOF_CSTR(PRT_DSC_ENDCOMMENTS),
+ PRT_DSC_ENDCOMMENTS_TYPE}
+};
+
+static void prt_write_file_len(char_u *buffer, int bytes);
+static int prt_next_dsc(struct prt_dsc_line_S *p_dsc_line);
+
+/*
+ * Variables for the output PostScript file.
+ */
+static FILE *prt_ps_fd;
+static int prt_file_error;
+static char_u *prt_ps_file_name = NULL;
+
+/*
+ * Various offsets and dimensions in default PostScript user space (points).
+ * Used for text positioning calculations
+ */
+static float prt_page_width;
+static float prt_page_height;
+static float prt_left_margin;
+static float prt_right_margin;
+static float prt_top_margin;
+static float prt_bottom_margin;
+static float prt_line_height;
+static float prt_first_line_height;
+static float prt_char_width;
+static float prt_number_width;
+static float prt_bgcol_offset;
+static float prt_pos_x_moveto = 0.0;
+static float prt_pos_y_moveto = 0.0;
+
+/*
+ * Various control variables used to decide when and how to change the
+ * PostScript graphics state.
+ */
+static int prt_need_moveto;
+static int prt_do_moveto;
+static int prt_need_font;
+static int prt_font;
+static int prt_need_underline;
+static int prt_underline;
+static int prt_do_underline;
+static int prt_need_fgcol;
+static int prt_fgcol;
+static int prt_need_bgcol;
+static int prt_do_bgcol;
+static int prt_bgcol;
+static int prt_new_bgcol;
+static int prt_attribute_change;
+static float prt_text_run;
+static int prt_page_num;
+static int prt_bufsiz;
+
+/*
+ * Variables controlling physical printing.
+ */
+static int prt_media;
+static int prt_portrait;
+static int prt_num_copies;
+static int prt_duplex;
+static int prt_tumble;
+static int prt_collate;
+
+/*
+ * Buffers used when generating PostScript output
+ */
+static char_u prt_line_buffer[257];
+static garray_T prt_ps_buffer;
+
+static int prt_do_conv;
+static vimconv_T prt_conv;
+
+static int prt_out_mbyte;
+static int prt_custom_cmap;
+static char prt_cmap[80];
+static int prt_use_courier;
+static int prt_in_ascii;
+static int prt_half_width;
+static char *prt_ascii_encoding;
+static char_u prt_hexchar[] = "0123456789abcdef";
+
+ static void
+prt_write_file_raw_len(char_u *buffer, int bytes)
+{
+ if (!prt_file_error
+ && fwrite(buffer, sizeof(char_u), bytes, prt_ps_fd)
+ != (size_t)bytes)
+ {
+ emsg(_("E455: Error writing to PostScript output file"));
+ prt_file_error = TRUE;
+ }
+}
+
+ static void
+prt_write_file(char_u *buffer)
+{
+ prt_write_file_len(buffer, (int)STRLEN(buffer));
+}
+
+ static void
+prt_write_file_len(char_u *buffer, int bytes)
+{
+#ifdef EBCDIC
+ ebcdic2ascii(buffer, bytes);
+#endif
+ prt_write_file_raw_len(buffer, bytes);
+}
+
+/*
+ * Write a string.
+ */
+ static void
+prt_write_string(char *s)
+{
+ vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer), "%s", s);
+ prt_write_file(prt_line_buffer);
+}
+
+/*
+ * Write an int and a space.
+ */
+ static void
+prt_write_int(int i)
+{
+ sprintf((char *)prt_line_buffer, "%d ", i);
+ prt_write_file(prt_line_buffer);
+}
+
+/*
+ * Write a boolean and a space.
+ */
+ static void
+prt_write_boolean(int b)
+{
+ sprintf((char *)prt_line_buffer, "%s ", (b ? "T" : "F"));
+ prt_write_file(prt_line_buffer);
+}
+
+/*
+ * Write PostScript to re-encode and define the font.
+ */
+ static void
+prt_def_font(
+ char *new_name,
+ char *encoding,
+ int height,
+ char *font)
+{
+ vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
+ "/_%s /VIM-%s /%s ref\n", new_name, encoding, font);
+ prt_write_file(prt_line_buffer);
+ if (prt_out_mbyte)
+ sprintf((char *)prt_line_buffer, "/%s %d %f /_%s sffs\n",
+ new_name, height, 500./prt_ps_courier_font.wx, new_name);
+ else
+ vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
+ "/%s %d /_%s ffs\n", new_name, height, new_name);
+ prt_write_file(prt_line_buffer);
+}
+
+/*
+ * Write a line to define the CID font.
+ */
+ static void
+prt_def_cidfont(char *new_name, int height, char *cidfont)
+{
+ vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
+ "/_%s /%s[/%s] vim_composefont\n", new_name, prt_cmap, cidfont);
+ prt_write_file(prt_line_buffer);
+ vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
+ "/%s %d /_%s ffs\n", new_name, height, new_name);
+ prt_write_file(prt_line_buffer);
+}
+
+/*
+ * Write a line to define a duplicate of a CID font
+ */
+ static void
+prt_dup_cidfont(char *original_name, char *new_name)
+{
+ vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
+ "/%s %s d\n", new_name, original_name);
+ prt_write_file(prt_line_buffer);
+}
+
+/*
+ * Convert a real value into an integer and fractional part as integers, with
+ * the fractional part being in the range [0,10^precision). The fractional part
+ * is also rounded based on the precision + 1'th fractional digit.
+ */
+ static void
+prt_real_bits(
+ double real,
+ int precision,
+ int *pinteger,
+ int *pfraction)
+{
+ int i;
+ int integer;
+ float fraction;
+
+ integer = (int)real;
+ fraction = (float)(real - integer);
+ if (real < (double)integer)
+ fraction = -fraction;
+ for (i = 0; i < precision; i++)
+ fraction *= 10.0;
+
+ *pinteger = integer;
+ *pfraction = (int)(fraction + 0.5);
+}
+
+/*
+ * Write a real and a space. Save bytes if real value has no fractional part!
+ * We use prt_real_bits() as %f in sprintf uses the locale setting to decide
+ * what decimal point character to use, but PS always requires a '.'.
+ */
+ static void
+prt_write_real(double val, int prec)
+{
+ int integer;
+ int fraction;
+
+ prt_real_bits(val, prec, &integer, &fraction);
+ /* Emit integer part */
+ sprintf((char *)prt_line_buffer, "%d", integer);
+ prt_write_file(prt_line_buffer);
+ /* Only emit fraction if necessary */
+ if (fraction != 0)
+ {
+ /* Remove any trailing zeros */
+ while ((fraction % 10) == 0)
+ {
+ prec--;
+ fraction /= 10;
+ }
+ /* Emit fraction left padded with zeros */
+ sprintf((char *)prt_line_buffer, ".%0*d", prec, fraction);
+ prt_write_file(prt_line_buffer);
+ }
+ sprintf((char *)prt_line_buffer, " ");
+ prt_write_file(prt_line_buffer);
+}
+
+/*
+ * Write a line to define a numeric variable.
+ */
+ static void
+prt_def_var(char *name, double value, int prec)
+{
+ vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
+ "/%s ", name);
+ prt_write_file(prt_line_buffer);
+ prt_write_real(value, prec);
+ sprintf((char *)prt_line_buffer, "d\n");
+ prt_write_file(prt_line_buffer);
+}
+
+/* Convert size from font space to user space at current font scale */
+#define PRT_PS_FONT_TO_USER(scale, size) ((size) * ((scale)/1000.0))
+
+ static void
+prt_flush_buffer(void)
+{
+ if (prt_ps_buffer.ga_len > 0)
+ {
+ /* Any background color must be drawn first */
+ if (prt_do_bgcol && (prt_new_bgcol != PRCOLOR_WHITE))
+ {
+ int r, g, b;
+
+ if (prt_do_moveto)
+ {
+ prt_write_real(prt_pos_x_moveto, 2);
+ prt_write_real(prt_pos_y_moveto, 2);
+ prt_write_string("m\n");
+ prt_do_moveto = FALSE;
+ }
+
+ /* Size of rect of background color on which text is printed */
+ prt_write_real(prt_text_run, 2);
+ prt_write_real(prt_line_height, 2);
+
+ /* Lastly add the color of the background */
+ r = ((unsigned)prt_new_bgcol & 0xff0000) >> 16;
+ g = ((unsigned)prt_new_bgcol & 0xff00) >> 8;
+ b = prt_new_bgcol & 0xff;
+ prt_write_real(r / 255.0, 3);
+ prt_write_real(g / 255.0, 3);
+ prt_write_real(b / 255.0, 3);
+ prt_write_string("bg\n");
+ }
+ /* Draw underlines before the text as it makes it slightly easier to
+ * find the starting point.
+ */
+ if (prt_do_underline)
+ {
+ if (prt_do_moveto)
+ {
+ prt_write_real(prt_pos_x_moveto, 2);
+ prt_write_real(prt_pos_y_moveto, 2);
+ prt_write_string("m\n");
+ prt_do_moveto = FALSE;
+ }
+
+ /* Underline length of text run */
+ prt_write_real(prt_text_run, 2);
+ prt_write_string("ul\n");
+ }
+ /* Draw the text
+ * Note: we write text out raw - EBCDIC conversion is handled in the
+ * PostScript world via the font encoding vector. */
+ if (prt_out_mbyte)
+ prt_write_string("<");
+ else
+ prt_write_string("(");
+ prt_write_file_raw_len(prt_ps_buffer.ga_data, prt_ps_buffer.ga_len);
+ if (prt_out_mbyte)
+ prt_write_string(">");
+ else
+ prt_write_string(")");
+ /* Add a moveto if need be and use the appropriate show procedure */
+ if (prt_do_moveto)
+ {
+ prt_write_real(prt_pos_x_moveto, 2);
+ prt_write_real(prt_pos_y_moveto, 2);
+ /* moveto and a show */
+ prt_write_string("ms\n");
+ prt_do_moveto = FALSE;
+ }
+ else /* Simple show */
+ prt_write_string("s\n");
+
+ ga_clear(&prt_ps_buffer);
+ ga_init2(&prt_ps_buffer, (int)sizeof(char), prt_bufsiz);
+ }
+}
+
+
+ static void
+prt_resource_name(char_u *filename, void *cookie)
+{
+ char_u *resource_filename = cookie;
+
+ if (STRLEN(filename) >= MAXPATHL)
+ *resource_filename = NUL;
+ else
+ STRCPY(resource_filename, filename);
+}
+
+ static int
+prt_find_resource(char *name, struct prt_ps_resource_S *resource)
+{
+ char_u *buffer;
+ int retval;
+
+ buffer = alloc(MAXPATHL + 1);
+ if (buffer == NULL)
+ return FALSE;
+
+ vim_strncpy(resource->name, (char_u *)name, 63);
+ /* Look for named resource file in runtimepath */
+ STRCPY(buffer, "print");
+ add_pathsep(buffer);
+ vim_strcat(buffer, (char_u *)name, MAXPATHL);
+ vim_strcat(buffer, (char_u *)".ps", MAXPATHL);
+ resource->filename[0] = NUL;
+ retval = (do_in_runtimepath(buffer, 0, prt_resource_name,
+ resource->filename)
+ && resource->filename[0] != NUL);
+ vim_free(buffer);
+ return retval;
+}
+
+/* PS CR and LF characters have platform independent values */
+#define PSLF (0x0a)
+#define PSCR (0x0d)
+
+/* Static buffer to read initial comments in a resource file, some can have a
+ * couple of KB of comments! */
+#define PRT_FILE_BUFFER_LEN (2048)
+struct prt_resfile_buffer_S
+{
+ char_u buffer[PRT_FILE_BUFFER_LEN];
+ int len;
+ int line_start;
+ int line_end;
+};
+
+static struct prt_resfile_buffer_S prt_resfile;
+
+ static int
+prt_resfile_next_line(void)
+{
+ int idx;
+
+ /* Move to start of next line and then find end of line */
+ idx = prt_resfile.line_end + 1;
+ while (idx < prt_resfile.len)
+ {
+ if (prt_resfile.buffer[idx] != PSLF && prt_resfile.buffer[idx] != PSCR)
+ break;
+ idx++;
+ }
+ prt_resfile.line_start = idx;
+
+ while (idx < prt_resfile.len)
+ {
+ if (prt_resfile.buffer[idx] == PSLF || prt_resfile.buffer[idx] == PSCR)
+ break;
+ idx++;
+ }
+ prt_resfile.line_end = idx;
+
+ return (idx < prt_resfile.len);
+}
+
+ static int
+prt_resfile_strncmp(int offset, char *string, int len)
+{
+ /* Force not equal if string is longer than remainder of line */
+ if (len > (prt_resfile.line_end - (prt_resfile.line_start + offset)))
+ return 1;
+
+ return STRNCMP(&prt_resfile.buffer[prt_resfile.line_start + offset],
+ string, len);
+}
+
+ static int
+prt_resfile_skip_nonws(int offset)
+{
+ int idx;
+
+ idx = prt_resfile.line_start + offset;
+ while (idx < prt_resfile.line_end)
+ {
+ if (isspace(prt_resfile.buffer[idx]))
+ return idx - prt_resfile.line_start;
+ idx++;
+ }
+ return -1;
+}
+
+ static int
+prt_resfile_skip_ws(int offset)
+{
+ int idx;
+
+ idx = prt_resfile.line_start + offset;
+ while (idx < prt_resfile.line_end)
+ {
+ if (!isspace(prt_resfile.buffer[idx]))
+ return idx - prt_resfile.line_start;
+ idx++;
+ }
+ return -1;
+}
+
+/* prt_next_dsc() - returns detail on next DSC comment line found. Returns true
+ * if a DSC comment is found, else false */
+ static int
+prt_next_dsc(struct prt_dsc_line_S *p_dsc_line)
+{
+ int comment;
+ int offset;
+
+ /* Move to start of next line */
+ if (!prt_resfile_next_line())
+ return FALSE;
+
+ /* DSC comments always start %% */
+ if (prt_resfile_strncmp(0, "%%", 2) != 0)
+ return FALSE;
+
+ /* Find type of DSC comment */
+ for (comment = 0; comment < (int)NUM_ELEMENTS(prt_dsc_table); comment++)
+ if (prt_resfile_strncmp(0, prt_dsc_table[comment].string,
+ prt_dsc_table[comment].len) == 0)
+ break;
+
+ if (comment != NUM_ELEMENTS(prt_dsc_table))
+ {
+ /* Return type of comment */
+ p_dsc_line->type = prt_dsc_table[comment].type;
+ offset = prt_dsc_table[comment].len;
+ }
+ else
+ {
+ /* Unrecognised DSC comment, skip to ws after comment leader */
+ p_dsc_line->type = PRT_DSC_MISC_TYPE;
+ offset = prt_resfile_skip_nonws(0);
+ if (offset == -1)
+ return FALSE;
+ }
+
+ /* Skip ws to comment value */
+ offset = prt_resfile_skip_ws(offset);
+ if (offset == -1)
+ return FALSE;
+
+ p_dsc_line->string = &prt_resfile.buffer[prt_resfile.line_start + offset];
+ p_dsc_line->len = prt_resfile.line_end - (prt_resfile.line_start + offset);
+
+ return TRUE;
+}
+
+/* Improved hand crafted parser to get the type, title, and version number of a
+ * PS resource file so the file details can be added to the DSC header comments.
+ */
+ static int
+prt_open_resource(struct prt_ps_resource_S *resource)
+{
+ int offset;
+ int seen_all;
+ int seen_title;
+ int seen_version;
+ FILE *fd_resource;
+ struct prt_dsc_line_S dsc_line;
+
+ fd_resource = mch_fopen((char *)resource->filename, READBIN);
+ if (fd_resource == NULL)
+ {
+ semsg(_("E624: Can't open file \"%s\""), resource->filename);
+ return FALSE;
+ }
+ vim_memset(prt_resfile.buffer, NUL, PRT_FILE_BUFFER_LEN);
+
+ /* Parse first line to ensure valid resource file */
+ prt_resfile.len = (int)fread((char *)prt_resfile.buffer, sizeof(char_u),
+ PRT_FILE_BUFFER_LEN, fd_resource);
+ if (ferror(fd_resource))
+ {
+ semsg(_("E457: Can't read PostScript resource file \"%s\""),
+ resource->filename);
+ fclose(fd_resource);
+ return FALSE;
+ }
+ fclose(fd_resource);
+
+ prt_resfile.line_end = -1;
+ prt_resfile.line_start = 0;
+ if (!prt_resfile_next_line())
+ return FALSE;
+
+ offset = 0;
+
+ if (prt_resfile_strncmp(offset, PRT_RESOURCE_HEADER,
+ (int)STRLEN(PRT_RESOURCE_HEADER)) != 0)
+ {
+ semsg(_("E618: file \"%s\" is not a PostScript resource file"),
+ resource->filename);
+ return FALSE;
+ }
+
+ /* Skip over any version numbers and following ws */
+ offset += (int)STRLEN(PRT_RESOURCE_HEADER);
+ offset = prt_resfile_skip_nonws(offset);
+ if (offset == -1)
+ return FALSE;
+ offset = prt_resfile_skip_ws(offset);
+ if (offset == -1)
+ return FALSE;
+
+ if (prt_resfile_strncmp(offset, PRT_RESOURCE_RESOURCE,
+ (int)STRLEN(PRT_RESOURCE_RESOURCE)) != 0)
+ {
+ semsg(_("E619: file \"%s\" is not a supported PostScript resource file"),
+ resource->filename);
+ return FALSE;
+ }
+ offset += (int)STRLEN(PRT_RESOURCE_RESOURCE);
+
+ /* Decide type of resource in the file */
+ if (prt_resfile_strncmp(offset, PRT_RESOURCE_PROCSET,
+ (int)STRLEN(PRT_RESOURCE_PROCSET)) == 0)
+ resource->type = PRT_RESOURCE_TYPE_PROCSET;
+ else if (prt_resfile_strncmp(offset, PRT_RESOURCE_ENCODING,
+ (int)STRLEN(PRT_RESOURCE_ENCODING)) == 0)
+ resource->type = PRT_RESOURCE_TYPE_ENCODING;
+ else if (prt_resfile_strncmp(offset, PRT_RESOURCE_CMAP,
+ (int)STRLEN(PRT_RESOURCE_CMAP)) == 0)
+ resource->type = PRT_RESOURCE_TYPE_CMAP;
+ else
+ {
+ semsg(_("E619: file \"%s\" is not a supported PostScript resource file"),
+ resource->filename);
+ return FALSE;
+ }
+
+ /* Look for title and version of resource */
+ resource->title[0] = '\0';
+ resource->version[0] = '\0';
+ seen_title = FALSE;
+ seen_version = FALSE;
+ seen_all = FALSE;
+ while (!seen_all && prt_next_dsc(&dsc_line))
+ {
+ switch (dsc_line.type)
+ {
+ case PRT_DSC_TITLE_TYPE:
+ vim_strncpy(resource->title, dsc_line.string, dsc_line.len);
+ seen_title = TRUE;
+ if (seen_version)
+ seen_all = TRUE;
+ break;
+
+ case PRT_DSC_VERSION_TYPE:
+ vim_strncpy(resource->version, dsc_line.string, dsc_line.len);
+ seen_version = TRUE;
+ if (seen_title)
+ seen_all = TRUE;
+ break;
+
+ case PRT_DSC_ENDCOMMENTS_TYPE:
+ /* Wont find title or resource after this comment, stop searching */
+ seen_all = TRUE;
+ break;
+
+ case PRT_DSC_MISC_TYPE:
+ /* Not interested in whatever comment this line had */
+ break;
+ }
+ }
+
+ if (!seen_title || !seen_version)
+ {
+ semsg(_("E619: file \"%s\" is not a supported PostScript resource file"),
+ resource->filename);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+ static int
+prt_check_resource(struct prt_ps_resource_S *resource, char_u *version)
+{
+ /* Version number m.n should match, the revision number does not matter */
+ if (STRNCMP(resource->version, version, STRLEN(version)))
+ {
+ semsg(_("E621: \"%s\" resource file has wrong version"),
+ resource->name);
+ return FALSE;
+ }
+
+ /* Other checks to be added as needed */
+ return TRUE;
+}
+
+ static void
+prt_dsc_start(void)
+{
+ prt_write_string("%!PS-Adobe-3.0\n");
+}
+
+ static void
+prt_dsc_noarg(char *comment)
+{
+ vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
+ "%%%%%s\n", comment);
+ prt_write_file(prt_line_buffer);
+}
+
+ static void
+prt_dsc_textline(char *comment, char *text)
+{
+ vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
+ "%%%%%s: %s\n", comment, text);
+ prt_write_file(prt_line_buffer);
+}
+
+ static void
+prt_dsc_text(char *comment, char *text)
+{
+ /* TODO - should scan 'text' for any chars needing escaping! */
+ vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
+ "%%%%%s: (%s)\n", comment, text);
+ prt_write_file(prt_line_buffer);
+}
+
+#define prt_dsc_atend(c) prt_dsc_text((c), "atend")
+
+ static void
+prt_dsc_ints(char *comment, int count, int *ints)
+{
+ int i;
+
+ vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
+ "%%%%%s:", comment);
+ prt_write_file(prt_line_buffer);
+
+ for (i = 0; i < count; i++)
+ {
+ sprintf((char *)prt_line_buffer, " %d", ints[i]);
+ prt_write_file(prt_line_buffer);
+ }
+
+ prt_write_string("\n");
+}
+
+ static void
+prt_dsc_resources(
+ char *comment, /* if NULL add to previous */
+ char *type,
+ char *string)
+{
+ if (comment != NULL)
+ vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
+ "%%%%%s: %s", comment, type);
+ else
+ vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
+ "%%%%+ %s", type);
+ prt_write_file(prt_line_buffer);
+
+ vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
+ " %s\n", string);
+ prt_write_file(prt_line_buffer);
+}
+
+ static void
+prt_dsc_font_resource(char *resource, struct prt_ps_font_S *ps_font)
+{
+ int i;
+
+ prt_dsc_resources(resource, "font",
+ ps_font->ps_fontname[PRT_PS_FONT_ROMAN]);
+ for (i = PRT_PS_FONT_BOLD ; i <= PRT_PS_FONT_BOLDOBLIQUE ; i++)
+ if (ps_font->ps_fontname[i] != NULL)
+ prt_dsc_resources(NULL, "font", ps_font->ps_fontname[i]);
+}
+
+ static void
+prt_dsc_requirements(
+ int duplex,
+ int tumble,
+ int collate,
+ int color,
+ int num_copies)
+{
+ /* Only output the comment if we need to.
+ * Note: tumble is ignored if we are not duplexing
+ */
+ if (!(duplex || collate || color || (num_copies > 1)))
+ return;
+
+ sprintf((char *)prt_line_buffer, "%%%%Requirements:");
+ prt_write_file(prt_line_buffer);
+
+ if (duplex)
+ {
+ prt_write_string(" duplex");
+ if (tumble)
+ prt_write_string("(tumble)");
+ }
+ if (collate)
+ prt_write_string(" collate");
+ if (color)
+ prt_write_string(" color");
+ if (num_copies > 1)
+ {
+ prt_write_string(" numcopies(");
+ /* Note: no space wanted so don't use prt_write_int() */
+ sprintf((char *)prt_line_buffer, "%d", num_copies);
+ prt_write_file(prt_line_buffer);
+ prt_write_string(")");
+ }
+ prt_write_string("\n");
+}
+
+ static void
+prt_dsc_docmedia(
+ char *paper_name,
+ double width,
+ double height,
+ double weight,
+ char *colour,
+ char *type)
+{
+ vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
+ "%%%%DocumentMedia: %s ", paper_name);
+ prt_write_file(prt_line_buffer);
+ prt_write_real(width, 2);
+ prt_write_real(height, 2);
+ prt_write_real(weight, 2);
+ if (colour == NULL)
+ prt_write_string("()");
+ else
+ prt_write_string(colour);
+ prt_write_string(" ");
+ if (type == NULL)
+ prt_write_string("()");
+ else
+ prt_write_string(type);
+ prt_write_string("\n");
+}
+
+ void
+mch_print_cleanup(void)
+{
+ if (prt_out_mbyte)
+ {
+ int i;
+
+ /* Free off all CID font names created, but first clear duplicate
+ * pointers to the same string (when the same font is used for more than
+ * one style).
+ */
+ for (i = PRT_PS_FONT_ROMAN; i <= PRT_PS_FONT_BOLDOBLIQUE; i++)
+ {
+ if (prt_ps_mb_font.ps_fontname[i] != NULL)
+ VIM_CLEAR(prt_ps_mb_font.ps_fontname[i]);
+ }
+ }
+
+ if (prt_do_conv)
+ {
+ convert_setup(&prt_conv, NULL, NULL);
+ prt_do_conv = FALSE;
+ }
+ if (prt_ps_fd != NULL)
+ {
+ fclose(prt_ps_fd);
+ prt_ps_fd = NULL;
+ prt_file_error = FALSE;
+ }
+ if (prt_ps_file_name != NULL)
+ VIM_CLEAR(prt_ps_file_name);
+}
+
+ static float
+to_device_units(int idx, double physsize, int def_number)
+{
+ float ret;
+ int u;
+ int nr;
+
+ u = prt_get_unit(idx);
+ if (u == PRT_UNIT_NONE)
+ {
+ u = PRT_UNIT_PERC;
+ nr = def_number;
+ }
+ else
+ nr = printer_opts[idx].number;
+
+ switch (u)
+ {
+ case PRT_UNIT_INCH:
+ ret = (float)(nr * PRT_PS_DEFAULT_DPI);
+ break;
+ case PRT_UNIT_MM:
+ ret = (float)(nr * PRT_PS_DEFAULT_DPI) / (float)25.4;
+ break;
+ case PRT_UNIT_POINT:
+ ret = (float)nr;
+ break;
+ case PRT_UNIT_PERC:
+ default:
+ ret = (float)(physsize * nr) / 100;
+ break;
+ }
+
+ return ret;
+}
+
+/*
+ * Calculate margins for given width and height from printoptions settings.
+ */
+ static void
+prt_page_margins(
+ double width,
+ double height,
+ double *left,
+ double *right,
+ double *top,
+ double *bottom)
+{
+ *left = to_device_units(OPT_PRINT_LEFT, width, 10);
+ *right = width - to_device_units(OPT_PRINT_RIGHT, width, 5);
+ *top = height - to_device_units(OPT_PRINT_TOP, height, 5);
+ *bottom = to_device_units(OPT_PRINT_BOT, height, 5);
+}
+
+ static void
+prt_font_metrics(int font_scale)
+{
+ prt_line_height = (float)font_scale;
+ prt_char_width = (float)PRT_PS_FONT_TO_USER(font_scale, prt_ps_font->wx);
+}
+
+
+ static int
+prt_get_cpl(void)
+{
+ if (prt_use_number())
+ {
+ prt_number_width = PRINT_NUMBER_WIDTH * prt_char_width;
+ /* If we are outputting multi-byte characters then line numbers will be
+ * printed with half width characters
+ */
+ if (prt_out_mbyte)
+ prt_number_width /= 2;
+ prt_left_margin += prt_number_width;
+ }
+ else
+ prt_number_width = 0.0;
+
+ return (int)((prt_right_margin - prt_left_margin) / prt_char_width);
+}
+
+ static int
+prt_build_cid_fontname(int font, char_u *name, int name_len)
+{
+ char *fontname;
+
+ fontname = (char *)alloc(name_len + 1);
+ if (fontname == NULL)
+ return FALSE;
+ vim_strncpy((char_u *)fontname, name, name_len);
+ prt_ps_mb_font.ps_fontname[font] = fontname;
+
+ return TRUE;
+}
+
+/*
+ * Get number of lines of text that fit on a page (excluding the header).
+ */
+ static int
+prt_get_lpp(void)
+{
+ int lpp;
+
+ /*
+ * Calculate offset to lower left corner of background rect based on actual
+ * font height (based on its bounding box) and the line height, handling the
+ * case where the font height can exceed the line height.
+ */
+ prt_bgcol_offset = (float)PRT_PS_FONT_TO_USER(prt_line_height,
+ prt_ps_font->bbox_min_y);
+ if ((prt_ps_font->bbox_max_y - prt_ps_font->bbox_min_y) < 1000.0)
+ {
+ prt_bgcol_offset -= (float)PRT_PS_FONT_TO_USER(prt_line_height,
+ (1000.0 - (prt_ps_font->bbox_max_y -
+ prt_ps_font->bbox_min_y)) / 2);
+ }
+
+ /* Get height for topmost line based on background rect offset. */
+ prt_first_line_height = prt_line_height + prt_bgcol_offset;
+
+ /* Calculate lpp */
+ lpp = (int)((prt_top_margin - prt_bottom_margin) / prt_line_height);
+
+ /* Adjust top margin if there is a header */
+ prt_top_margin -= prt_line_height * prt_header_height();
+
+ return lpp - prt_header_height();
+}
+
+ static int
+prt_match_encoding(
+ char *p_encoding,
+ struct prt_ps_mbfont_S *p_cmap,
+ struct prt_ps_encoding_S **pp_mbenc)
+{
+ int mbenc;
+ int enc_len;
+ struct prt_ps_encoding_S *p_mbenc;
+
+ *pp_mbenc = NULL;
+ /* Look for recognised encoding */
+ enc_len = (int)STRLEN(p_encoding);
+ p_mbenc = p_cmap->encodings;
+ for (mbenc = 0; mbenc < p_cmap->num_encodings; mbenc++)
+ {
+ if (STRNICMP(p_mbenc->encoding, p_encoding, enc_len) == 0)
+ {
+ *pp_mbenc = p_mbenc;
+ return TRUE;
+ }
+ p_mbenc++;
+ }
+ return FALSE;
+}
+
+ static int
+prt_match_charset(
+ char *p_charset,
+ struct prt_ps_mbfont_S *p_cmap,
+ struct prt_ps_charset_S **pp_mbchar)
+{
+ int mbchar;
+ int char_len;
+ struct prt_ps_charset_S *p_mbchar;
+
+ /* Look for recognised character set, using default if one is not given */
+ if (*p_charset == NUL)
+ p_charset = p_cmap->defcs;
+ char_len = (int)STRLEN(p_charset);
+ p_mbchar = p_cmap->charsets;
+ for (mbchar = 0; mbchar < p_cmap->num_charsets; mbchar++)
+ {
+ if (STRNICMP(p_mbchar->charset, p_charset, char_len) == 0)
+ {
+ *pp_mbchar = p_mbchar;
+ return TRUE;
+ }
+ p_mbchar++;
+ }
+ return FALSE;
+}
+
+ int
+mch_print_init(
+ prt_settings_T *psettings,
+ char_u *jobname,
+ int forceit UNUSED)
+{
+ int i;
+ char *paper_name;
+ int paper_strlen;
+ int fontsize;
+ char_u *p;
+ double left;
+ double right;
+ double top;
+ double bottom;
+ int props;
+ int cmap = 0;
+ char_u *p_encoding;
+ struct prt_ps_encoding_S *p_mbenc;
+ struct prt_ps_encoding_S *p_mbenc_first;
+ struct prt_ps_charset_S *p_mbchar = NULL;
+
+#if 0
+ /*
+ * TODO:
+ * If "forceit" is false: pop up a dialog to select:
+ * - printer name
+ * - copies
+ * - collated/uncollated
+ * - duplex off/long side/short side
+ * - paper size
+ * - portrait/landscape
+ * - font size
+ *
+ * If "forceit" is true: use the default printer and settings
+ */
+ if (forceit)
+ s_pd.Flags |= PD_RETURNDEFAULT;
+#endif
+
+ /*
+ * Set up font and encoding.
+ */
+ p_encoding = enc_skip(p_penc);
+ if (*p_encoding == NUL)
+ p_encoding = enc_skip(p_enc);
+
+ /* Look for a multi-byte font that matches the encoding and character set.
+ * Only look if multi-byte character set is defined, or using multi-byte
+ * encoding other than Unicode. This is because a Unicode encoding does not
+ * uniquely identify a CJK character set to use. */
+ p_mbenc = NULL;
+ props = enc_canon_props(p_encoding);
+ if (!(props & ENC_8BIT) && ((*p_pmcs != NUL) || !(props & ENC_UNICODE)))
+ {
+ int cmap_first = 0;
+
+ p_mbenc_first = NULL;
+ for (cmap = 0; cmap < (int)NUM_ELEMENTS(prt_ps_mbfonts); cmap++)
+ if (prt_match_encoding((char *)p_encoding, &prt_ps_mbfonts[cmap],
+ &p_mbenc))
+ {
+ if (p_mbenc_first == NULL)
+ {
+ p_mbenc_first = p_mbenc;
+ cmap_first = cmap;
+ }
+ if (prt_match_charset((char *)p_pmcs, &prt_ps_mbfonts[cmap],
+ &p_mbchar))
+ break;
+ }
+
+ /* Use first encoding matched if no charset matched */
+ if (p_mbchar == NULL && p_mbenc_first != NULL)
+ {
+ p_mbenc = p_mbenc_first;
+ cmap = cmap_first;
+ }
+ }
+
+ prt_out_mbyte = (p_mbenc != NULL);
+ if (prt_out_mbyte)
+ {
+ /* Build CMap name - will be same for all multi-byte fonts used */
+ prt_cmap[0] = NUL;
+
+ prt_custom_cmap = (p_mbchar == NULL);
+ if (!prt_custom_cmap)
+ {
+ /* Check encoding and character set are compatible */
+ if ((p_mbenc->needs_charset & p_mbchar->has_charset) == 0)
+ {
+ emsg(_("E673: Incompatible multi-byte encoding and character set."));
+ return FALSE;
+ }
+
+ /* Add charset name if not empty */
+ if (p_mbchar->cmap_charset != NULL)
+ {
+ vim_strncpy((char_u *)prt_cmap,
+ (char_u *)p_mbchar->cmap_charset, sizeof(prt_cmap) - 3);
+ STRCAT(prt_cmap, "-");
+ }
+ }
+ else
+ {
+ /* Add custom CMap character set name */
+ if (*p_pmcs == NUL)
+ {
+ emsg(_("E674: printmbcharset cannot be empty with multi-byte encoding."));
+ return FALSE;
+ }
+ vim_strncpy((char_u *)prt_cmap, p_pmcs, sizeof(prt_cmap) - 3);
+ STRCAT(prt_cmap, "-");
+ }
+
+ /* CMap name ends with (optional) encoding name and -H for horizontal */
+ if (p_mbenc->cmap_encoding != NULL && STRLEN(prt_cmap)
+ + STRLEN(p_mbenc->cmap_encoding) + 3 < sizeof(prt_cmap))
+ {
+ STRCAT(prt_cmap, p_mbenc->cmap_encoding);
+ STRCAT(prt_cmap, "-");
+ }
+ STRCAT(prt_cmap, "H");
+
+ if (!mbfont_opts[OPT_MBFONT_REGULAR].present)
+ {
+ emsg(_("E675: No default font specified for multi-byte printing."));
+ return FALSE;
+ }
+
+ /* Derive CID font names with fallbacks if not defined */
+ if (!prt_build_cid_fontname(PRT_PS_FONT_ROMAN,
+ mbfont_opts[OPT_MBFONT_REGULAR].string,
+ mbfont_opts[OPT_MBFONT_REGULAR].strlen))
+ return FALSE;
+ if (mbfont_opts[OPT_MBFONT_BOLD].present)
+ if (!prt_build_cid_fontname(PRT_PS_FONT_BOLD,
+ mbfont_opts[OPT_MBFONT_BOLD].string,
+ mbfont_opts[OPT_MBFONT_BOLD].strlen))
+ return FALSE;
+ if (mbfont_opts[OPT_MBFONT_OBLIQUE].present)
+ if (!prt_build_cid_fontname(PRT_PS_FONT_OBLIQUE,
+ mbfont_opts[OPT_MBFONT_OBLIQUE].string,
+ mbfont_opts[OPT_MBFONT_OBLIQUE].strlen))
+ return FALSE;
+ if (mbfont_opts[OPT_MBFONT_BOLDOBLIQUE].present)
+ if (!prt_build_cid_fontname(PRT_PS_FONT_BOLDOBLIQUE,
+ mbfont_opts[OPT_MBFONT_BOLDOBLIQUE].string,
+ mbfont_opts[OPT_MBFONT_BOLDOBLIQUE].strlen))
+ return FALSE;
+
+ /* Check if need to use Courier for ASCII code range, and if so pick up
+ * the encoding to use */
+ prt_use_courier = mbfont_opts[OPT_MBFONT_USECOURIER].present &&
+ (TOLOWER_ASC(mbfont_opts[OPT_MBFONT_USECOURIER].string[0]) == 'y');
+ if (prt_use_courier)
+ {
+ /* Use national ASCII variant unless ASCII wanted */
+ if (mbfont_opts[OPT_MBFONT_ASCII].present &&
+ (TOLOWER_ASC(mbfont_opts[OPT_MBFONT_ASCII].string[0]) == 'y'))
+ prt_ascii_encoding = "ascii";
+ else
+ prt_ascii_encoding = prt_ps_mbfonts[cmap].ascii_enc;
+ }
+
+ prt_ps_font = &prt_ps_mb_font;
+ }
+ else
+ {
+ prt_use_courier = FALSE;
+ prt_ps_font = &prt_ps_courier_font;
+ }
+
+ /*
+ * Find the size of the paper and set the margins.
+ */
+ prt_portrait = (!printer_opts[OPT_PRINT_PORTRAIT].present
+ || TOLOWER_ASC(printer_opts[OPT_PRINT_PORTRAIT].string[0]) == 'y');
+ if (printer_opts[OPT_PRINT_PAPER].present)
+ {
+ paper_name = (char *)printer_opts[OPT_PRINT_PAPER].string;
+ paper_strlen = printer_opts[OPT_PRINT_PAPER].strlen;
+ }
+ else
+ {
+ paper_name = "A4";
+ paper_strlen = 2;
+ }
+ for (i = 0; i < (int)PRT_MEDIASIZE_LEN; ++i)
+ if (STRLEN(prt_mediasize[i].name) == (unsigned)paper_strlen
+ && STRNICMP(prt_mediasize[i].name, paper_name,
+ paper_strlen) == 0)
+ break;
+ if (i == PRT_MEDIASIZE_LEN)
+ i = 0;
+ prt_media = i;
+
+ /*
+ * Set PS pagesize based on media dimensions and print orientation.
+ * Note: Media and page sizes have defined meanings in PostScript and should
+ * be kept distinct. Media is the paper (or transparency, or ...) that is
+ * printed on, whereas the page size is the area that the PostScript
+ * interpreter renders into.
+ */
+ if (prt_portrait)
+ {
+ prt_page_width = prt_mediasize[i].width;
+ prt_page_height = prt_mediasize[i].height;
+ }
+ else
+ {
+ prt_page_width = prt_mediasize[i].height;
+ prt_page_height = prt_mediasize[i].width;
+ }
+
+ /*
+ * Set PS page margins based on the PS pagesize, not the mediasize - this
+ * needs to be done before the cpl and lpp are calculated.
+ */
+ prt_page_margins(prt_page_width, prt_page_height, &left, &right, &top,
+ &bottom);
+ prt_left_margin = (float)left;
+ prt_right_margin = (float)right;
+ prt_top_margin = (float)top;
+ prt_bottom_margin = (float)bottom;
+
+ /*
+ * Set up the font size.
+ */
+ fontsize = PRT_PS_DEFAULT_FONTSIZE;
+ for (p = p_pfn; (p = vim_strchr(p, ':')) != NULL; ++p)
+ if (p[1] == 'h' && VIM_ISDIGIT(p[2]))
+ fontsize = atoi((char *)p + 2);
+ prt_font_metrics(fontsize);
+
+ /*
+ * Return the number of characters per line, and lines per page for the
+ * generic print code.
+ */
+ psettings->chars_per_line = prt_get_cpl();
+ psettings->lines_per_page = prt_get_lpp();
+
+ /* Catch margin settings that leave no space for output! */
+ if (psettings->chars_per_line <= 0 || psettings->lines_per_page <= 0)
+ return FAIL;
+
+ /*
+ * Sort out the number of copies to be printed. PS by default will do
+ * uncollated copies for you, so once we know how many uncollated copies are
+ * wanted cache it away and lie to the generic code that we only want one
+ * uncollated copy.
+ */
+ psettings->n_collated_copies = 1;
+ psettings->n_uncollated_copies = 1;
+ prt_num_copies = 1;
+ prt_collate = (!printer_opts[OPT_PRINT_COLLATE].present
+ || TOLOWER_ASC(printer_opts[OPT_PRINT_COLLATE].string[0]) == 'y');
+ if (prt_collate)
+ {
+ /* TODO: Get number of collated copies wanted. */
+ psettings->n_collated_copies = 1;
+ }
+ else
+ {
+ /* TODO: Get number of uncollated copies wanted and update the cached
+ * count.
+ */
+ prt_num_copies = 1;
+ }
+
+ psettings->jobname = jobname;
+
+ /*
+ * Set up printer duplex and tumble based on Duplex option setting - default
+ * is long sided duplex printing (i.e. no tumble).
+ */
+ prt_duplex = TRUE;
+ prt_tumble = FALSE;
+ psettings->duplex = 1;
+ if (printer_opts[OPT_PRINT_DUPLEX].present)
+ {
+ if (STRNICMP(printer_opts[OPT_PRINT_DUPLEX].string, "off", 3) == 0)
+ {
+ prt_duplex = FALSE;
+ psettings->duplex = 0;
+ }
+ else if (STRNICMP(printer_opts[OPT_PRINT_DUPLEX].string, "short", 5)
+ == 0)
+ prt_tumble = TRUE;
+ }
+
+ /* For now user abort not supported */
+ psettings->user_abort = 0;
+
+ /* If the user didn't specify a file name, use a temp file. */
+ if (psettings->outfile == NULL)
+ {
+ prt_ps_file_name = vim_tempname('p', TRUE);
+ if (prt_ps_file_name == NULL)
+ {
+ emsg(_(e_notmp));
+ return FAIL;
+ }
+ prt_ps_fd = mch_fopen((char *)prt_ps_file_name, WRITEBIN);
+ }
+ else
+ {
+ p = expand_env_save(psettings->outfile);
+ if (p != NULL)
+ {
+ prt_ps_fd = mch_fopen((char *)p, WRITEBIN);
+ vim_free(p);
+ }
+ }
+ if (prt_ps_fd == NULL)
+ {
+ emsg(_("E324: Can't open PostScript output file"));
+ mch_print_cleanup();
+ return FAIL;
+ }
+
+ prt_bufsiz = psettings->chars_per_line;
+ if (prt_out_mbyte)
+ prt_bufsiz *= 2;
+ ga_init2(&prt_ps_buffer, (int)sizeof(char), prt_bufsiz);
+
+ prt_page_num = 0;
+
+ prt_attribute_change = FALSE;
+ prt_need_moveto = FALSE;
+ prt_need_font = FALSE;
+ prt_need_fgcol = FALSE;
+ prt_need_bgcol = FALSE;
+ prt_need_underline = FALSE;
+
+ prt_file_error = FALSE;
+
+ return OK;
+}
+
+ static int
+prt_add_resource(struct prt_ps_resource_S *resource)
+{
+ FILE* fd_resource;
+ char_u resource_buffer[512];
+ size_t bytes_read;
+
+ fd_resource = mch_fopen((char *)resource->filename, READBIN);
+ if (fd_resource == NULL)
+ {
+ semsg(_("E456: Can't open file \"%s\""), resource->filename);
+ return FALSE;
+ }
+ prt_dsc_resources("BeginResource", prt_resource_types[resource->type],
+ (char *)resource->title);
+
+ prt_dsc_textline("BeginDocument", (char *)resource->filename);
+
+ for (;;)
+ {
+ bytes_read = fread((char *)resource_buffer, sizeof(char_u),
+ sizeof(resource_buffer), fd_resource);
+ if (ferror(fd_resource))
+ {
+ semsg(_("E457: Can't read PostScript resource file \"%s\""),
+ resource->filename);
+ fclose(fd_resource);
+ return FALSE;
+ }
+ if (bytes_read == 0)
+ break;
+ prt_write_file_raw_len(resource_buffer, (int)bytes_read);
+ if (prt_file_error)
+ {
+ fclose(fd_resource);
+ return FALSE;
+ }
+ }
+ fclose(fd_resource);
+
+ prt_dsc_noarg("EndDocument");
+
+ prt_dsc_noarg("EndResource");
+
+ return TRUE;
+}
+
+ int
+mch_print_begin(prt_settings_T *psettings)
+{
+ time_t now;
+ int bbox[4];
+ char *p_time;
+ double left;
+ double right;
+ double top;
+ double bottom;
+ struct prt_ps_resource_S *res_prolog;
+ struct prt_ps_resource_S *res_encoding;
+ char buffer[256];
+ char_u *p_encoding;
+ char_u *p;
+ struct prt_ps_resource_S *res_cidfont;
+ struct prt_ps_resource_S *res_cmap;
+ int retval = FALSE;
+
+ res_prolog = (struct prt_ps_resource_S *)
+ alloc(sizeof(struct prt_ps_resource_S));
+ res_encoding = (struct prt_ps_resource_S *)
+ alloc(sizeof(struct prt_ps_resource_S));
+ res_cidfont = (struct prt_ps_resource_S *)
+ alloc(sizeof(struct prt_ps_resource_S));
+ res_cmap = (struct prt_ps_resource_S *)
+ alloc(sizeof(struct prt_ps_resource_S));
+ if (res_prolog == NULL || res_encoding == NULL
+ || res_cidfont == NULL || res_cmap == NULL)
+ goto theend;
+
+ /*
+ * PS DSC Header comments - no PS code!
+ */
+ prt_dsc_start();
+ prt_dsc_textline("Title", (char *)psettings->jobname);
+ if (!get_user_name((char_u *)buffer, 256))
+ STRCPY(buffer, "Unknown");
+ prt_dsc_textline("For", buffer);
+ prt_dsc_textline("Creator", VIM_VERSION_LONG);
+ /* Note: to ensure Clean8bit I don't think we can use LC_TIME */
+ now = time(NULL);
+ p_time = ctime(&now);
+ /* Note: ctime() adds a \n so we have to remove it :-( */
+ p = vim_strchr((char_u *)p_time, '\n');
+ if (p != NULL)
+ *p = NUL;
+ prt_dsc_textline("CreationDate", p_time);
+ prt_dsc_textline("DocumentData", "Clean8Bit");
+ prt_dsc_textline("Orientation", "Portrait");
+ prt_dsc_atend("Pages");
+ prt_dsc_textline("PageOrder", "Ascend");
+ /* The bbox does not change with orientation - it is always in the default
+ * user coordinate system! We have to recalculate right and bottom
+ * coordinates based on the font metrics for the bbox to be accurate. */
+ prt_page_margins(prt_mediasize[prt_media].width,
+ prt_mediasize[prt_media].height,
+ &left, &right, &top, &bottom);
+ bbox[0] = (int)left;
+ if (prt_portrait)
+ {
+ /* In portrait printing the fixed point is the top left corner so we
+ * derive the bbox from that point. We have the expected cpl chars
+ * across the media and lpp lines down the media.
+ */
+ bbox[1] = (int)(top - (psettings->lines_per_page + prt_header_height())
+ * prt_line_height);
+ bbox[2] = (int)(left + psettings->chars_per_line * prt_char_width
+ + 0.5);
+ bbox[3] = (int)(top + 0.5);
+ }
+ else
+ {
+ /* In landscape printing the fixed point is the bottom left corner so we
+ * derive the bbox from that point. We have lpp chars across the media
+ * and cpl lines up the media.
+ */
+ bbox[1] = (int)bottom;
+ bbox[2] = (int)(left + ((psettings->lines_per_page
+ + prt_header_height()) * prt_line_height) + 0.5);
+ bbox[3] = (int)(bottom + psettings->chars_per_line * prt_char_width
+ + 0.5);
+ }
+ prt_dsc_ints("BoundingBox", 4, bbox);
+ /* The media width and height does not change with landscape printing! */
+ prt_dsc_docmedia(prt_mediasize[prt_media].name,
+ prt_mediasize[prt_media].width,
+ prt_mediasize[prt_media].height,
+ (double)0, NULL, NULL);
+ /* Define fonts needed */
+ if (!prt_out_mbyte || prt_use_courier)
+ prt_dsc_font_resource("DocumentNeededResources", &prt_ps_courier_font);
+ if (prt_out_mbyte)
+ {
+ prt_dsc_font_resource((prt_use_courier ? NULL
+ : "DocumentNeededResources"), &prt_ps_mb_font);
+ if (!prt_custom_cmap)
+ prt_dsc_resources(NULL, "cmap", prt_cmap);
+ }
+
+ /* Search for external resources VIM supplies */
+ if (!prt_find_resource("prolog", res_prolog))
+ {
+ emsg(_("E456: Can't find PostScript resource file \"prolog.ps\""));
+ goto theend;
+ }
+ if (!prt_open_resource(res_prolog))
+ goto theend;
+ if (!prt_check_resource(res_prolog, PRT_PROLOG_VERSION))
+ goto theend;
+ if (prt_out_mbyte)
+ {
+ /* Look for required version of multi-byte printing procset */
+ if (!prt_find_resource("cidfont", res_cidfont))
+ {
+ emsg(_("E456: Can't find PostScript resource file \"cidfont.ps\""));
+ goto theend;
+ }
+ if (!prt_open_resource(res_cidfont))
+ goto theend;
+ if (!prt_check_resource(res_cidfont, PRT_CID_PROLOG_VERSION))
+ goto theend;
+ }
+
+ /* Find an encoding to use for printing.
+ * Check 'printencoding'. If not set or not found, then use 'encoding'. If
+ * that cannot be found then default to "latin1".
+ * Note: VIM specific encoding header is always skipped.
+ */
+ if (!prt_out_mbyte)
+ {
+ p_encoding = enc_skip(p_penc);
+ if (*p_encoding == NUL
+ || !prt_find_resource((char *)p_encoding, res_encoding))
+ {
+ /* 'printencoding' not set or not supported - find alternate */
+ int props;
+
+ p_encoding = enc_skip(p_enc);
+ props = enc_canon_props(p_encoding);
+ if (!(props & ENC_8BIT)
+ || !prt_find_resource((char *)p_encoding, res_encoding))
+ /* 8-bit 'encoding' is not supported */
+ {
+ /* Use latin1 as default printing encoding */
+ p_encoding = (char_u *)"latin1";
+ if (!prt_find_resource((char *)p_encoding, res_encoding))
+ {
+ semsg(_("E456: Can't find PostScript resource file \"%s.ps\""),
+ p_encoding);
+ goto theend;
+ }
+ }
+ }
+ if (!prt_open_resource(res_encoding))
+ goto theend;
+ /* For the moment there are no checks on encoding resource files to
+ * perform */
+ }
+ else
+ {
+ p_encoding = enc_skip(p_penc);
+ if (*p_encoding == NUL)
+ p_encoding = enc_skip(p_enc);
+ if (prt_use_courier)
+ {
+ /* Include ASCII range encoding vector */
+ if (!prt_find_resource(prt_ascii_encoding, res_encoding))
+ {
+ semsg(_("E456: Can't find PostScript resource file \"%s.ps\""),
+ prt_ascii_encoding);
+ goto theend;
+ }
+ if (!prt_open_resource(res_encoding))
+ goto theend;
+ /* For the moment there are no checks on encoding resource files to
+ * perform */
+ }
+ }
+
+ prt_conv.vc_type = CONV_NONE;
+ if (!(enc_canon_props(p_enc) & enc_canon_props(p_encoding) & ENC_8BIT)) {
+ /* Set up encoding conversion if required */
+ if (FAIL == convert_setup(&prt_conv, p_enc, p_encoding))
+ {
+ semsg(_("E620: Unable to convert to print encoding \"%s\""),
+ p_encoding);
+ goto theend;
+ }
+ prt_do_conv = TRUE;
+ }
+ prt_do_conv = prt_conv.vc_type != CONV_NONE;
+
+ if (prt_out_mbyte && prt_custom_cmap)
+ {
+ /* Find user supplied CMap */
+ if (!prt_find_resource(prt_cmap, res_cmap))
+ {
+ semsg(_("E456: Can't find PostScript resource file \"%s.ps\""),
+ prt_cmap);
+ goto theend;
+ }
+ if (!prt_open_resource(res_cmap))
+ goto theend;
+ }
+
+ /* List resources supplied */
+ STRCPY(buffer, res_prolog->title);
+ STRCAT(buffer, " ");
+ STRCAT(buffer, res_prolog->version);
+ prt_dsc_resources("DocumentSuppliedResources", "procset", buffer);
+ if (prt_out_mbyte)
+ {
+ STRCPY(buffer, res_cidfont->title);
+ STRCAT(buffer, " ");
+ STRCAT(buffer, res_cidfont->version);
+ prt_dsc_resources(NULL, "procset", buffer);
+
+ if (prt_custom_cmap)
+ {
+ STRCPY(buffer, res_cmap->title);
+ STRCAT(buffer, " ");
+ STRCAT(buffer, res_cmap->version);
+ prt_dsc_resources(NULL, "cmap", buffer);
+ }
+ }
+ if (!prt_out_mbyte || prt_use_courier)
+ {
+ STRCPY(buffer, res_encoding->title);
+ STRCAT(buffer, " ");
+ STRCAT(buffer, res_encoding->version);
+ prt_dsc_resources(NULL, "encoding", buffer);
+ }
+ prt_dsc_requirements(prt_duplex, prt_tumble, prt_collate,
+#ifdef FEAT_SYN_HL
+ psettings->do_syntax
+#else
+ 0
+#endif
+ , prt_num_copies);
+ prt_dsc_noarg("EndComments");
+
+ /*
+ * PS Document page defaults
+ */
+ prt_dsc_noarg("BeginDefaults");
+
+ /* List font resources most likely common to all pages */
+ if (!prt_out_mbyte || prt_use_courier)
+ prt_dsc_font_resource("PageResources", &prt_ps_courier_font);
+ if (prt_out_mbyte)
+ {
+ prt_dsc_font_resource((prt_use_courier ? NULL : "PageResources"),
+ &prt_ps_mb_font);
+ if (!prt_custom_cmap)
+ prt_dsc_resources(NULL, "cmap", prt_cmap);
+ }
+
+ /* Paper will be used for all pages */
+ prt_dsc_textline("PageMedia", prt_mediasize[prt_media].name);
+
+ prt_dsc_noarg("EndDefaults");
+
+ /*
+ * PS Document prolog inclusion - all required procsets.
+ */
+ prt_dsc_noarg("BeginProlog");
+
+ /* Add required procsets - NOTE: order is important! */
+ if (!prt_add_resource(res_prolog))
+ goto theend;
+ if (prt_out_mbyte)
+ {
+ /* Add CID font procset, and any user supplied CMap */
+ if (!prt_add_resource(res_cidfont))
+ goto theend;
+ if (prt_custom_cmap && !prt_add_resource(res_cmap))
+ goto theend;
+ }
+
+ if (!prt_out_mbyte || prt_use_courier)
+ /* There will be only one Roman font encoding to be included in the PS
+ * file. */
+ if (!prt_add_resource(res_encoding))
+ goto theend;
+
+ prt_dsc_noarg("EndProlog");
+
+ /*
+ * PS Document setup - must appear after the prolog
+ */
+ prt_dsc_noarg("BeginSetup");
+
+ /* Device setup - page size and number of uncollated copies */
+ prt_write_int((int)prt_mediasize[prt_media].width);
+ prt_write_int((int)prt_mediasize[prt_media].height);
+ prt_write_int(0);
+ prt_write_string("sps\n");
+ prt_write_int(prt_num_copies);
+ prt_write_string("nc\n");
+ prt_write_boolean(prt_duplex);
+ prt_write_boolean(prt_tumble);
+ prt_write_string("dt\n");
+ prt_write_boolean(prt_collate);
+ prt_write_string("c\n");
+
+ /* Font resource inclusion and definition */
+ if (!prt_out_mbyte || prt_use_courier)
+ {
+ /* When using Courier for ASCII range when printing multi-byte, need to
+ * pick up ASCII encoding to use with it. */
+ if (prt_use_courier)
+ p_encoding = (char_u *)prt_ascii_encoding;
+ prt_dsc_resources("IncludeResource", "font",
+ prt_ps_courier_font.ps_fontname[PRT_PS_FONT_ROMAN]);
+ prt_def_font("F0", (char *)p_encoding, (int)prt_line_height,
+ prt_ps_courier_font.ps_fontname[PRT_PS_FONT_ROMAN]);
+ prt_dsc_resources("IncludeResource", "font",
+ prt_ps_courier_font.ps_fontname[PRT_PS_FONT_BOLD]);
+ prt_def_font("F1", (char *)p_encoding, (int)prt_line_height,
+ prt_ps_courier_font.ps_fontname[PRT_PS_FONT_BOLD]);
+ prt_dsc_resources("IncludeResource", "font",
+ prt_ps_courier_font.ps_fontname[PRT_PS_FONT_OBLIQUE]);
+ prt_def_font("F2", (char *)p_encoding, (int)prt_line_height,
+ prt_ps_courier_font.ps_fontname[PRT_PS_FONT_OBLIQUE]);
+ prt_dsc_resources("IncludeResource", "font",
+ prt_ps_courier_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]);
+ prt_def_font("F3", (char *)p_encoding, (int)prt_line_height,
+ prt_ps_courier_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]);
+ }
+ if (prt_out_mbyte)
+ {
+ /* Define the CID fonts to be used in the job. Typically CJKV fonts do
+ * not have an italic form being a western style, so where no font is
+ * defined for these faces VIM falls back to an existing face.
+ * Note: if using Courier for the ASCII range then the printout will
+ * have bold/italic/bolditalic regardless of the setting of printmbfont.
+ */
+ prt_dsc_resources("IncludeResource", "font",
+ prt_ps_mb_font.ps_fontname[PRT_PS_FONT_ROMAN]);
+ if (!prt_custom_cmap)
+ prt_dsc_resources("IncludeResource", "cmap", prt_cmap);
+ prt_def_cidfont("CF0", (int)prt_line_height,
+ prt_ps_mb_font.ps_fontname[PRT_PS_FONT_ROMAN]);
+
+ if (prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLD] != NULL)
+ {
+ prt_dsc_resources("IncludeResource", "font",
+ prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLD]);
+ if (!prt_custom_cmap)
+ prt_dsc_resources("IncludeResource", "cmap", prt_cmap);
+ prt_def_cidfont("CF1", (int)prt_line_height,
+ prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLD]);
+ }
+ else
+ /* Use ROMAN for BOLD */
+ prt_dup_cidfont("CF0", "CF1");
+
+ if (prt_ps_mb_font.ps_fontname[PRT_PS_FONT_OBLIQUE] != NULL)
+ {
+ prt_dsc_resources("IncludeResource", "font",
+ prt_ps_mb_font.ps_fontname[PRT_PS_FONT_OBLIQUE]);
+ if (!prt_custom_cmap)
+ prt_dsc_resources("IncludeResource", "cmap", prt_cmap);
+ prt_def_cidfont("CF2", (int)prt_line_height,
+ prt_ps_mb_font.ps_fontname[PRT_PS_FONT_OBLIQUE]);
+ }
+ else
+ /* Use ROMAN for OBLIQUE */
+ prt_dup_cidfont("CF0", "CF2");
+
+ if (prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE] != NULL)
+ {
+ prt_dsc_resources("IncludeResource", "font",
+ prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]);
+ if (!prt_custom_cmap)
+ prt_dsc_resources("IncludeResource", "cmap", prt_cmap);
+ prt_def_cidfont("CF3", (int)prt_line_height,
+ prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]);
+ }
+ else
+ /* Use BOLD for BOLDOBLIQUE */
+ prt_dup_cidfont("CF1", "CF3");
+ }
+
+ /* Misc constant vars used for underlining and background rects */
+ prt_def_var("UO", PRT_PS_FONT_TO_USER(prt_line_height,
+ prt_ps_font->uline_offset), 2);
+ prt_def_var("UW", PRT_PS_FONT_TO_USER(prt_line_height,
+ prt_ps_font->uline_width), 2);
+ prt_def_var("BO", prt_bgcol_offset, 2);
+
+ prt_dsc_noarg("EndSetup");
+
+ /* Fail if any problems writing out to the PS file */
+ retval = !prt_file_error;
+
+theend:
+ vim_free(res_prolog);
+ vim_free(res_encoding);
+ vim_free(res_cidfont);
+ vim_free(res_cmap);
+
+ return retval;
+}
+
+ void
+mch_print_end(prt_settings_T *psettings)
+{
+ prt_dsc_noarg("Trailer");
+
+ /*
+ * Output any info we don't know in toto until we finish
+ */
+ prt_dsc_ints("Pages", 1, &prt_page_num);
+
+ prt_dsc_noarg("EOF");
+
+ /* Write CTRL-D to close serial communication link if used.
+ * NOTHING MUST BE WRITTEN AFTER THIS! */
+ prt_write_file((char_u *)IF_EB("\004", "\067"));
+
+ if (!prt_file_error && psettings->outfile == NULL
+ && !got_int && !psettings->user_abort)
+ {
+ /* Close the file first. */
+ if (prt_ps_fd != NULL)
+ {
+ fclose(prt_ps_fd);
+ prt_ps_fd = NULL;
+ }
+ prt_message((char_u *)_("Sending to printer..."));
+
+ /* Not printing to a file: use 'printexpr' to print the file. */
+ if (eval_printexpr(prt_ps_file_name, psettings->arguments) == FAIL)
+ emsg(_("E365: Failed to print PostScript file"));
+ else
+ prt_message((char_u *)_("Print job sent."));
+ }
+
+ mch_print_cleanup();
+}
+
+ int
+mch_print_end_page(void)
+{
+ prt_flush_buffer();
+
+ prt_write_string("re sp\n");
+
+ prt_dsc_noarg("PageTrailer");
+
+ return !prt_file_error;
+}
+
+ int
+mch_print_begin_page(char_u *str UNUSED)
+{
+ int page_num[2];
+
+ prt_page_num++;
+
+ page_num[0] = page_num[1] = prt_page_num;
+ prt_dsc_ints("Page", 2, page_num);
+
+ prt_dsc_noarg("BeginPageSetup");
+
+ prt_write_string("sv\n0 g\n");
+ prt_in_ascii = !prt_out_mbyte;
+ if (prt_out_mbyte)
+ prt_write_string("CF0 sf\n");
+ else
+ prt_write_string("F0 sf\n");
+ prt_fgcol = PRCOLOR_BLACK;
+ prt_bgcol = PRCOLOR_WHITE;
+ prt_font = PRT_PS_FONT_ROMAN;
+
+ /* Set up page transformation for landscape printing. */
+ if (!prt_portrait)
+ {
+ prt_write_int(-((int)prt_mediasize[prt_media].width));
+ prt_write_string("sl\n");
+ }
+
+ prt_dsc_noarg("EndPageSetup");
+
+ /* We have reset the font attributes, force setting them again. */
+ curr_bg = (long_u)0xffffffff;
+ curr_fg = (long_u)0xffffffff;
+ curr_bold = MAYBE;
+
+ return !prt_file_error;
+}
+
+ int
+mch_print_blank_page(void)
+{
+ return (mch_print_begin_page(NULL) ? (mch_print_end_page()) : FALSE);
+}
+
+static float prt_pos_x = 0;
+static float prt_pos_y = 0;
+
+ void
+mch_print_start_line(int margin, int page_line)
+{
+ prt_pos_x = prt_left_margin;
+ if (margin)
+ prt_pos_x -= prt_number_width;
+
+ prt_pos_y = prt_top_margin - prt_first_line_height -
+ page_line * prt_line_height;
+
+ prt_attribute_change = TRUE;
+ prt_need_moveto = TRUE;
+ prt_half_width = FALSE;
+}
+
+ int
+mch_print_text_out(char_u *textp, int len UNUSED)
+{
+ char_u *p = textp;
+ int need_break;
+ char_u ch;
+ char_u ch_buff[8];
+ float char_width;
+ float next_pos;
+ int in_ascii;
+ int half_width;
+ char_u *tofree = NULL;
+
+ char_width = prt_char_width;
+
+ /* Ideally VIM would create a rearranged CID font to combine a Roman and
+ * CJKV font to do what VIM is doing here - use a Roman font for characters
+ * in the ASCII range, and the original CID font for everything else.
+ * The problem is that GhostScript still (as of 8.13) does not support
+ * rearranged fonts even though they have been documented by Adobe for 7
+ * years! If they ever do, a lot of this code will disappear.
+ */
+ if (prt_use_courier)
+ {
+ in_ascii = (len == 1 && *p < 0x80);
+ if (prt_in_ascii)
+ {
+ if (!in_ascii)
+ {
+ /* No longer in ASCII range - need to switch font */
+ prt_in_ascii = FALSE;
+ prt_need_font = TRUE;
+ prt_attribute_change = TRUE;
+ }
+ }
+ else if (in_ascii)
+ {
+ /* Now in ASCII range - need to switch font */
+ prt_in_ascii = TRUE;
+ prt_need_font = TRUE;
+ prt_attribute_change = TRUE;
+ }
+ }
+ if (prt_out_mbyte)
+ {
+ half_width = ((*mb_ptr2cells)(p) == 1);
+ if (half_width)
+ char_width /= 2;
+ if (prt_half_width)
+ {
+ if (!half_width)
+ {
+ prt_half_width = FALSE;
+ prt_pos_x += prt_char_width/4;
+ prt_need_moveto = TRUE;
+ prt_attribute_change = TRUE;
+ }
+ }
+ else if (half_width)
+ {
+ prt_half_width = TRUE;
+ prt_pos_x += prt_char_width/4;
+ prt_need_moveto = TRUE;
+ prt_attribute_change = TRUE;
+ }
+ }
+
+ /* Output any required changes to the graphics state, after flushing any
+ * text buffered so far.
+ */
+ if (prt_attribute_change)
+ {
+ prt_flush_buffer();
+ /* Reset count of number of chars that will be printed */
+ prt_text_run = 0;
+
+ if (prt_need_moveto)
+ {
+ prt_pos_x_moveto = prt_pos_x;
+ prt_pos_y_moveto = prt_pos_y;
+ prt_do_moveto = TRUE;
+
+ prt_need_moveto = FALSE;
+ }
+ if (prt_need_font)
+ {
+ if (!prt_in_ascii)
+ prt_write_string("CF");
+ else
+ prt_write_string("F");
+ prt_write_int(prt_font);
+ prt_write_string("sf\n");
+ prt_need_font = FALSE;
+ }
+ if (prt_need_fgcol)
+ {
+ int r, g, b;
+ r = ((unsigned)prt_fgcol & 0xff0000) >> 16;
+ g = ((unsigned)prt_fgcol & 0xff00) >> 8;
+ b = prt_fgcol & 0xff;
+
+ prt_write_real(r / 255.0, 3);
+ if (r == g && g == b)
+ prt_write_string("g\n");
+ else
+ {
+ prt_write_real(g / 255.0, 3);
+ prt_write_real(b / 255.0, 3);
+ prt_write_string("r\n");
+ }
+ prt_need_fgcol = FALSE;
+ }
+
+ if (prt_bgcol != PRCOLOR_WHITE)
+ {
+ prt_new_bgcol = prt_bgcol;
+ if (prt_need_bgcol)
+ prt_do_bgcol = TRUE;
+ }
+ else
+ prt_do_bgcol = FALSE;
+ prt_need_bgcol = FALSE;
+
+ if (prt_need_underline)
+ prt_do_underline = prt_underline;
+ prt_need_underline = FALSE;
+
+ prt_attribute_change = FALSE;
+ }
+
+ if (prt_do_conv)
+ {
+ /* Convert from multi-byte to 8-bit encoding */
+ tofree = p = string_convert(&prt_conv, p, &len);
+ if (p == NULL)
+ {
+ p = (char_u *)"";
+ len = 0;
+ }
+ }
+
+ if (prt_out_mbyte)
+ {
+ /* Multi-byte character strings are represented more efficiently as hex
+ * strings when outputting clean 8 bit PS.
+ */
+ while (len-- > 0)
+ {
+ ch = prt_hexchar[(unsigned)(*p) >> 4];
+ ga_append(&prt_ps_buffer, ch);
+ ch = prt_hexchar[(*p) & 0xf];
+ ga_append(&prt_ps_buffer, ch);
+ p++;
+ }
+ }
+ else
+ {
+ /* Add next character to buffer of characters to output.
+ * Note: One printed character may require several PS characters to
+ * represent it, but we only count them as one printed character.
+ */
+ ch = *p;
+ if (ch < 32 || ch == '(' || ch == ')' || ch == '\\')
+ {
+ /* Convert non-printing characters to either their escape or octal
+ * sequence, ensures PS sent over a serial line does not interfere
+ * with the comms protocol. Note: For EBCDIC we need to write out
+ * the escape sequences as ASCII codes!
+ * Note 2: Char codes < 32 are identical in EBCDIC and ASCII AFAIK!
+ */
+ ga_append(&prt_ps_buffer, IF_EB('\\', 0134));
+ switch (ch)
+ {
+ case BS: ga_append(&prt_ps_buffer, IF_EB('b', 0142)); break;
+ case TAB: ga_append(&prt_ps_buffer, IF_EB('t', 0164)); break;
+ case NL: ga_append(&prt_ps_buffer, IF_EB('n', 0156)); break;
+ case FF: ga_append(&prt_ps_buffer, IF_EB('f', 0146)); break;
+ case CAR: ga_append(&prt_ps_buffer, IF_EB('r', 0162)); break;
+ case '(': ga_append(&prt_ps_buffer, IF_EB('(', 0050)); break;
+ case ')': ga_append(&prt_ps_buffer, IF_EB(')', 0051)); break;
+ case '\\': ga_append(&prt_ps_buffer, IF_EB('\\', 0134)); break;
+
+ default:
+ sprintf((char *)ch_buff, "%03o", (unsigned int)ch);
+#ifdef EBCDIC
+ ebcdic2ascii(ch_buff, 3);
+#endif
+ ga_append(&prt_ps_buffer, ch_buff[0]);
+ ga_append(&prt_ps_buffer, ch_buff[1]);
+ ga_append(&prt_ps_buffer, ch_buff[2]);
+ break;
+ }
+ }
+ else
+ ga_append(&prt_ps_buffer, ch);
+ }
+
+ /* Need to free any translated characters */
+ vim_free(tofree);
+
+ prt_text_run += char_width;
+ prt_pos_x += char_width;
+
+ /* The downside of fp - use relative error on right margin check */
+ next_pos = prt_pos_x + prt_char_width;
+ need_break = (next_pos > prt_right_margin) &&
+ ((next_pos - prt_right_margin) > (prt_right_margin*1e-5));
+
+ if (need_break)
+ prt_flush_buffer();
+
+ return need_break;
+}
+
+ void
+mch_print_set_font(int iBold, int iItalic, int iUnderline)
+{
+ int font = 0;
+
+ if (iBold)
+ font |= 0x01;
+ if (iItalic)
+ font |= 0x02;
+
+ if (font != prt_font)
+ {
+ prt_font = font;
+ prt_attribute_change = TRUE;
+ prt_need_font = TRUE;
+ }
+ if (prt_underline != iUnderline)
+ {
+ prt_underline = iUnderline;
+ prt_attribute_change = TRUE;
+ prt_need_underline = TRUE;
+ }
+}
+
+ void
+mch_print_set_bg(long_u bgcol)
+{
+ prt_bgcol = (int)bgcol;
+ prt_attribute_change = TRUE;
+ prt_need_bgcol = TRUE;
+}
+
+ void
+mch_print_set_fg(long_u fgcol)
+{
+ if (fgcol != (long_u)prt_fgcol)
+ {
+ prt_fgcol = (int)fgcol;
+ prt_attribute_change = TRUE;
+ prt_need_fgcol = TRUE;
+ }
+}
+
+# endif /*FEAT_POSTSCRIPT*/
+#endif /*FEAT_PRINTER*/
diff --git a/src/hashtab.c b/src/hashtab.c
new file mode 100644
index 0000000..6f2c2ca
--- /dev/null
+++ b/src/hashtab.c
@@ -0,0 +1,482 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * hashtab.c: Handling of a hashtable with Vim-specific properties.
+ *
+ * Each item in a hashtable has a NUL terminated string key. A key can appear
+ * only once in the table.
+ *
+ * A hash number is computed from the key for quick lookup. When the hashes
+ * of two different keys point to the same entry an algorithm is used to
+ * iterate over other entries in the table until the right one is found.
+ * To make the iteration work removed keys are different from entries where a
+ * key was never present.
+ *
+ * The mechanism has been partly based on how Python Dictionaries are
+ * implemented. The algorithm is from Knuth Vol. 3, Sec. 6.4.
+ *
+ * The hashtable grows to accommodate more entries when needed. At least 1/3
+ * of the entries is empty to keep the lookup efficient (at the cost of extra
+ * memory).
+ */
+
+#include "vim.h"
+
+#if 0
+# define HT_DEBUG /* extra checks for table consistency and statistics */
+
+static long hash_count_lookup = 0; /* count number of hashtab lookups */
+static long hash_count_perturb = 0; /* count number of "misses" */
+#endif
+
+/* Magic value for algorithm that walks through the array. */
+#define PERTURB_SHIFT 5
+
+static int hash_may_resize(hashtab_T *ht, int minitems);
+
+#if 0 /* currently not used */
+/*
+ * Create an empty hash table.
+ * Returns NULL when out of memory.
+ */
+ hashtab_T *
+hash_create(void)
+{
+ hashtab_T *ht;
+
+ ht = (hashtab_T *)alloc(sizeof(hashtab_T));
+ if (ht != NULL)
+ hash_init(ht);
+ return ht;
+}
+#endif
+
+/*
+ * Initialize an empty hash table.
+ */
+ void
+hash_init(hashtab_T *ht)
+{
+ /* This zeroes all "ht_" entries and all the "hi_key" in "ht_smallarray". */
+ vim_memset(ht, 0, sizeof(hashtab_T));
+ ht->ht_array = ht->ht_smallarray;
+ ht->ht_mask = HT_INIT_SIZE - 1;
+}
+
+/*
+ * Free the array of a hash table. Does not free the items it contains!
+ * If "ht" is not freed then you should call hash_init() next!
+ */
+ void
+hash_clear(hashtab_T *ht)
+{
+ if (ht->ht_array != ht->ht_smallarray)
+ vim_free(ht->ht_array);
+}
+
+#if defined(FEAT_SPELL) || defined(PROTO)
+/*
+ * Free the array of a hash table and all the keys it contains. The keys must
+ * have been allocated. "off" is the offset from the start of the allocate
+ * memory to the location of the key (it's always positive).
+ */
+ void
+hash_clear_all(hashtab_T *ht, int off)
+{
+ long todo;
+ hashitem_T *hi;
+
+ todo = (long)ht->ht_used;
+ for (hi = ht->ht_array; todo > 0; ++hi)
+ {
+ if (!HASHITEM_EMPTY(hi))
+ {
+ vim_free(hi->hi_key - off);
+ --todo;
+ }
+ }
+ hash_clear(ht);
+}
+#endif
+
+/*
+ * Find "key" in hashtable "ht". "key" must not be NULL.
+ * Always returns a pointer to a hashitem. If the item was not found then
+ * HASHITEM_EMPTY() is TRUE. The pointer is then the place where the key
+ * would be added.
+ * WARNING: The returned pointer becomes invalid when the hashtable is changed
+ * (adding, setting or removing an item)!
+ */
+ hashitem_T *
+hash_find(hashtab_T *ht, char_u *key)
+{
+ return hash_lookup(ht, key, hash_hash(key));
+}
+
+/*
+ * Like hash_find(), but caller computes "hash".
+ */
+ hashitem_T *
+hash_lookup(hashtab_T *ht, char_u *key, hash_T hash)
+{
+ hash_T perturb;
+ hashitem_T *freeitem;
+ hashitem_T *hi;
+ unsigned idx;
+
+#ifdef HT_DEBUG
+ ++hash_count_lookup;
+#endif
+
+ /*
+ * Quickly handle the most common situations:
+ * - return if there is no item at all
+ * - skip over a removed item
+ * - return if the item matches
+ */
+ idx = (unsigned)(hash & ht->ht_mask);
+ hi = &ht->ht_array[idx];
+
+ if (hi->hi_key == NULL)
+ return hi;
+ if (hi->hi_key == HI_KEY_REMOVED)
+ freeitem = hi;
+ else if (hi->hi_hash == hash && STRCMP(hi->hi_key, key) == 0)
+ return hi;
+ else
+ freeitem = NULL;
+
+ /*
+ * Need to search through the table to find the key. The algorithm
+ * to step through the table starts with large steps, gradually becoming
+ * smaller down to (1/4 table size + 1). This means it goes through all
+ * table entries in the end.
+ * When we run into a NULL key it's clear that the key isn't there.
+ * Return the first available slot found (can be a slot of a removed
+ * item).
+ */
+ for (perturb = hash; ; perturb >>= PERTURB_SHIFT)
+ {
+#ifdef HT_DEBUG
+ ++hash_count_perturb; /* count a "miss" for hashtab lookup */
+#endif
+ idx = (unsigned)((idx << 2U) + idx + perturb + 1U);
+ hi = &ht->ht_array[idx & ht->ht_mask];
+ if (hi->hi_key == NULL)
+ return freeitem == NULL ? hi : freeitem;
+ if (hi->hi_hash == hash
+ && hi->hi_key != HI_KEY_REMOVED
+ && STRCMP(hi->hi_key, key) == 0)
+ return hi;
+ if (hi->hi_key == HI_KEY_REMOVED && freeitem == NULL)
+ freeitem = hi;
+ }
+}
+
+#if defined(FEAT_EVAL) || defined(FEAT_SYN_HL) || defined(PROTO)
+/*
+ * Print the efficiency of hashtable lookups.
+ * Useful when trying different hash algorithms.
+ * Called when exiting.
+ */
+ void
+hash_debug_results(void)
+{
+#ifdef HT_DEBUG
+ fprintf(stderr, "\r\n\r\n\r\n\r\n");
+ fprintf(stderr, "Number of hashtable lookups: %ld\r\n", hash_count_lookup);
+ fprintf(stderr, "Number of perturb loops: %ld\r\n", hash_count_perturb);
+ fprintf(stderr, "Percentage of perturb loops: %ld%%\r\n",
+ hash_count_perturb * 100 / hash_count_lookup);
+#endif
+}
+#endif
+
+/*
+ * Add item with key "key" to hashtable "ht".
+ * Returns FAIL when out of memory or the key is already present.
+ */
+ int
+hash_add(hashtab_T *ht, char_u *key)
+{
+ hash_T hash = hash_hash(key);
+ hashitem_T *hi;
+
+ hi = hash_lookup(ht, key, hash);
+ if (!HASHITEM_EMPTY(hi))
+ {
+ internal_error("hash_add()");
+ return FAIL;
+ }
+ return hash_add_item(ht, hi, key, hash);
+}
+
+/*
+ * Add item "hi" with "key" to hashtable "ht". "key" must not be NULL and
+ * "hi" must have been obtained with hash_lookup() and point to an empty item.
+ * "hi" is invalid after this!
+ * Returns OK or FAIL (out of memory).
+ */
+ int
+hash_add_item(
+ hashtab_T *ht,
+ hashitem_T *hi,
+ char_u *key,
+ hash_T hash)
+{
+ /* If resizing failed before and it fails again we can't add an item. */
+ if (ht->ht_error && hash_may_resize(ht, 0) == FAIL)
+ return FAIL;
+
+ ++ht->ht_used;
+ if (hi->hi_key == NULL)
+ ++ht->ht_filled;
+ hi->hi_key = key;
+ hi->hi_hash = hash;
+
+ /* When the space gets low may resize the array. */
+ return hash_may_resize(ht, 0);
+}
+
+#if 0 /* not used */
+/*
+ * Overwrite hashtable item "hi" with "key". "hi" must point to the item that
+ * is to be overwritten. Thus the number of items in the hashtable doesn't
+ * change.
+ * Although the key must be identical, the pointer may be different, thus it's
+ * set anyway (the key is part of an item with that key).
+ * The caller must take care of freeing the old item.
+ * "hi" is invalid after this!
+ */
+ void
+hash_set(hashitem_T *hi, char_u *key)
+{
+ hi->hi_key = key;
+}
+#endif
+
+/*
+ * Remove item "hi" from hashtable "ht". "hi" must have been obtained with
+ * hash_lookup().
+ * The caller must take care of freeing the item itself.
+ */
+ void
+hash_remove(hashtab_T *ht, hashitem_T *hi)
+{
+ --ht->ht_used;
+ hi->hi_key = HI_KEY_REMOVED;
+ hash_may_resize(ht, 0);
+}
+
+/*
+ * Lock a hashtable: prevent that ht_array changes.
+ * Don't use this when items are to be added!
+ * Must call hash_unlock() later.
+ */
+ void
+hash_lock(hashtab_T *ht)
+{
+ ++ht->ht_locked;
+}
+
+#if 0 /* currently not used */
+/*
+ * Lock a hashtable at the specified number of entries.
+ * Caller must make sure no more than "size" entries will be added.
+ * Must call hash_unlock() later.
+ */
+ void
+hash_lock_size(hashtab_T *ht, int size)
+{
+ (void)hash_may_resize(ht, size);
+ ++ht->ht_locked;
+}
+#endif
+
+/*
+ * Unlock a hashtable: allow ht_array changes again.
+ * Table will be resized (shrink) when necessary.
+ * This must balance a call to hash_lock().
+ */
+ void
+hash_unlock(hashtab_T *ht)
+{
+ --ht->ht_locked;
+ (void)hash_may_resize(ht, 0);
+}
+
+/*
+ * Shrink a hashtable when there is too much empty space.
+ * Grow a hashtable when there is not enough empty space.
+ * Returns OK or FAIL (out of memory).
+ */
+ static int
+hash_may_resize(
+ hashtab_T *ht,
+ int minitems) /* minimal number of items */
+{
+ hashitem_T temparray[HT_INIT_SIZE];
+ hashitem_T *oldarray, *newarray;
+ hashitem_T *olditem, *newitem;
+ unsigned newi;
+ int todo;
+ long_u oldsize, newsize;
+ long_u minsize;
+ long_u newmask;
+ hash_T perturb;
+
+ /* Don't resize a locked table. */
+ if (ht->ht_locked > 0)
+ return OK;
+
+#ifdef HT_DEBUG
+ if (ht->ht_used > ht->ht_filled)
+ emsg("hash_may_resize(): more used than filled");
+ if (ht->ht_filled >= ht->ht_mask + 1)
+ emsg("hash_may_resize(): table completely filled");
+#endif
+
+ if (minitems == 0)
+ {
+ /* Return quickly for small tables with at least two NULL items. NULL
+ * items are required for the lookup to decide a key isn't there. */
+ if (ht->ht_filled < HT_INIT_SIZE - 1
+ && ht->ht_array == ht->ht_smallarray)
+ return OK;
+
+ /*
+ * Grow or refill the array when it's more than 2/3 full (including
+ * removed items, so that they get cleaned up).
+ * Shrink the array when it's less than 1/5 full. When growing it is
+ * at least 1/4 full (avoids repeated grow-shrink operations)
+ */
+ oldsize = ht->ht_mask + 1;
+ if (ht->ht_filled * 3 < oldsize * 2 && ht->ht_used > oldsize / 5)
+ return OK;
+
+ if (ht->ht_used > 1000)
+ minsize = ht->ht_used * 2; /* it's big, don't make too much room */
+ else
+ minsize = ht->ht_used * 4; /* make plenty of room */
+ }
+ else
+ {
+ /* Use specified size. */
+ if ((long_u)minitems < ht->ht_used) /* just in case... */
+ minitems = (int)ht->ht_used;
+ minsize = minitems * 3 / 2; /* array is up to 2/3 full */
+ }
+
+ newsize = HT_INIT_SIZE;
+ while (newsize < minsize)
+ {
+ newsize <<= 1; /* make sure it's always a power of 2 */
+ if (newsize == 0)
+ return FAIL; /* overflow */
+ }
+
+ if (newsize == HT_INIT_SIZE)
+ {
+ /* Use the small array inside the hashdict structure. */
+ newarray = ht->ht_smallarray;
+ if (ht->ht_array == newarray)
+ {
+ /* Moving from ht_smallarray to ht_smallarray! Happens when there
+ * are many removed items. Copy the items to be able to clean up
+ * removed items. */
+ mch_memmove(temparray, newarray, sizeof(temparray));
+ oldarray = temparray;
+ }
+ else
+ oldarray = ht->ht_array;
+ }
+ else
+ {
+ /* Allocate an array. */
+ newarray = (hashitem_T *)alloc((unsigned)
+ (sizeof(hashitem_T) * newsize));
+ if (newarray == NULL)
+ {
+ /* Out of memory. When there are NULL items still return OK.
+ * Otherwise set ht_error, because lookup may result in a hang if
+ * we add another item. */
+ if (ht->ht_filled < ht->ht_mask)
+ return OK;
+ ht->ht_error = TRUE;
+ return FAIL;
+ }
+ oldarray = ht->ht_array;
+ }
+ vim_memset(newarray, 0, (size_t)(sizeof(hashitem_T) * newsize));
+
+ /*
+ * Move all the items from the old array to the new one, placing them in
+ * the right spot. The new array won't have any removed items, thus this
+ * is also a cleanup action.
+ */
+ newmask = newsize - 1;
+ todo = (int)ht->ht_used;
+ for (olditem = oldarray; todo > 0; ++olditem)
+ if (!HASHITEM_EMPTY(olditem))
+ {
+ /*
+ * The algorithm to find the spot to add the item is identical to
+ * the algorithm to find an item in hash_lookup(). But we only
+ * need to search for a NULL key, thus it's simpler.
+ */
+ newi = (unsigned)(olditem->hi_hash & newmask);
+ newitem = &newarray[newi];
+
+ if (newitem->hi_key != NULL)
+ for (perturb = olditem->hi_hash; ; perturb >>= PERTURB_SHIFT)
+ {
+ newi = (unsigned)((newi << 2U) + newi + perturb + 1U);
+ newitem = &newarray[newi & newmask];
+ if (newitem->hi_key == NULL)
+ break;
+ }
+ *newitem = *olditem;
+ --todo;
+ }
+
+ if (ht->ht_array != ht->ht_smallarray)
+ vim_free(ht->ht_array);
+ ht->ht_array = newarray;
+ ht->ht_mask = newmask;
+ ht->ht_filled = ht->ht_used;
+ ht->ht_error = FALSE;
+
+ return OK;
+}
+
+/*
+ * Get the hash number for a key.
+ * If you think you know a better hash function: Compile with HT_DEBUG set and
+ * run a script that uses hashtables a lot. Vim will then print statistics
+ * when exiting. Try that with the current hash algorithm and yours. The
+ * lower the percentage the better.
+ */
+ hash_T
+hash_hash(char_u *key)
+{
+ hash_T hash;
+ char_u *p;
+
+ if ((hash = *key) == 0)
+ return (hash_T)0;
+ p = key + 1;
+
+ /* A simplistic algorithm that appears to do very well.
+ * Suggested by George Reilly. */
+ while (*p != NUL)
+ hash = hash * 101 + *p++;
+
+ return hash;
+}
diff --git a/src/if_cscope.c b/src/if_cscope.c
new file mode 100644
index 0000000..4cc053e
--- /dev/null
+++ b/src/if_cscope.c
@@ -0,0 +1,2509 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * CSCOPE support for Vim added by Andy Kahn <kahn@zk3.dec.com>
+ * Ported to Win32 by Sergey Khorev <sergey.khorev@gmail.com>
+ *
+ * The basic idea/structure of cscope for Vim was borrowed from Nvi. There
+ * might be a few lines of code that look similar to what Nvi has.
+ *
+ * See README.txt for an overview of the Vim source code.
+ */
+
+#include "vim.h"
+
+#if defined(FEAT_CSCOPE) || defined(PROTO)
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#if defined(UNIX)
+# include <sys/wait.h>
+#endif
+#include "if_cscope.h"
+
+static int cs_add(exarg_T *eap);
+static int cs_add_common(char *, char *, char *);
+static int cs_check_for_connections(void);
+static int cs_check_for_tags(void);
+static int cs_cnt_connections(void);
+static int cs_create_connection(int i);
+#ifdef FEAT_QUICKFIX
+static void cs_file_results(FILE *, int *);
+#endif
+static void cs_fill_results(char *, int , int *, char ***,
+ char ***, int *);
+static int cs_find(exarg_T *eap);
+static int cs_find_common(char *opt, char *pat, int, int, int, char_u *cmdline);
+static int cs_help(exarg_T *eap);
+static int cs_insert_filelist(char *, char *, char *,
+ stat_T *);
+static int cs_kill(exarg_T *eap);
+static void cs_kill_execute(int, char *);
+static cscmd_T * cs_lookup_cmd(exarg_T *eap);
+static char * cs_make_vim_style_matches(char *, char *,
+ char *, char *);
+static char * cs_manage_matches(char **, char **, int, mcmd_e);
+static void cs_print_tags_priv(char **, char **, int);
+static int cs_read_prompt(int);
+static void cs_release_csp(int, int freefnpp);
+static int cs_reset(exarg_T *eap);
+static char * cs_resolve_file(int, char *);
+static int cs_show(exarg_T *eap);
+
+
+static csinfo_T * csinfo = NULL;
+static int csinfo_size = 0; /* number of items allocated in
+ csinfo[] */
+
+static int eap_arg_len; /* length of eap->arg, set in
+ cs_lookup_cmd() */
+static cscmd_T cs_cmds[] =
+{
+ { "add", cs_add,
+ N_("Add a new database"), "add file|dir [pre-path] [flags]", 0 },
+ { "find", cs_find,
+ N_("Query for a pattern"), "find a|c|d|e|f|g|i|s|t name", 1 },
+ { "help", cs_help,
+ N_("Show this message"), "help", 0 },
+ { "kill", cs_kill,
+ N_("Kill a connection"), "kill #", 0 },
+ { "reset", cs_reset,
+ N_("Reinit all connections"), "reset", 0 },
+ { "show", cs_show,
+ N_("Show connections"), "show", 0 },
+ { NULL, NULL, NULL, NULL, 0 }
+};
+
+ static void
+cs_usage_msg(csid_e x)
+{
+ (void)semsg(_("E560: Usage: cs[cope] %s"), cs_cmds[(int)x].usage);
+}
+
+#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
+
+static enum
+{
+ EXP_CSCOPE_SUBCMD, /* expand ":cscope" sub-commands */
+ EXP_SCSCOPE_SUBCMD, /* expand ":scscope" sub-commands */
+ EXP_CSCOPE_FIND, /* expand ":cscope find" arguments */
+ EXP_CSCOPE_KILL /* expand ":cscope kill" arguments */
+} expand_what;
+
+/*
+ * Function given to ExpandGeneric() to obtain the cscope command
+ * expansion.
+ */
+ char_u *
+get_cscope_name(expand_T *xp UNUSED, int idx)
+{
+ int current_idx;
+ int i;
+
+ switch (expand_what)
+ {
+ case EXP_CSCOPE_SUBCMD:
+ /* Complete with sub-commands of ":cscope":
+ * add, find, help, kill, reset, show */
+ return (char_u *)cs_cmds[idx].name;
+ case EXP_SCSCOPE_SUBCMD:
+ /* Complete with sub-commands of ":scscope": same sub-commands as
+ * ":cscope" but skip commands which don't support split windows */
+ for (i = 0, current_idx = 0; cs_cmds[i].name != NULL; i++)
+ if (cs_cmds[i].cansplit)
+ if (current_idx++ == idx)
+ break;
+ return (char_u *)cs_cmds[i].name;
+ case EXP_CSCOPE_FIND:
+ {
+ const char *query_type[] =
+ {
+ "a", "c", "d", "e", "f", "g", "i", "s", "t", NULL
+ };
+
+ /* Complete with query type of ":cscope find {query_type}".
+ * {query_type} can be letters (c, d, ... a) or numbers (0, 1,
+ * ..., 9) but only complete with letters, since numbers are
+ * redundant. */
+ return (char_u *)query_type[idx];
+ }
+ case EXP_CSCOPE_KILL:
+ {
+ static char connection[5];
+
+ /* ":cscope kill" accepts connection numbers or partial names of
+ * the pathname of the cscope database as argument. Only complete
+ * with connection numbers. -1 can also be used to kill all
+ * connections. */
+ for (i = 0, current_idx = 0; i < csinfo_size; i++)
+ {
+ if (csinfo[i].fname == NULL)
+ continue;
+ if (current_idx++ == idx)
+ {
+ vim_snprintf(connection, sizeof(connection), "%d", i);
+ return (char_u *)connection;
+ }
+ }
+ return (current_idx == idx && idx > 0) ? (char_u *)"-1" : NULL;
+ }
+ default:
+ return NULL;
+ }
+}
+
+/*
+ * Handle command line completion for :cscope command.
+ */
+ void
+set_context_in_cscope_cmd(
+ expand_T *xp,
+ char_u *arg,
+ cmdidx_T cmdidx)
+{
+ char_u *p;
+
+ /* Default: expand subcommands */
+ xp->xp_context = EXPAND_CSCOPE;
+ xp->xp_pattern = arg;
+ expand_what = (cmdidx == CMD_scscope)
+ ? EXP_SCSCOPE_SUBCMD : EXP_CSCOPE_SUBCMD;
+
+ /* (part of) subcommand already typed */
+ if (*arg != NUL)
+ {
+ p = skiptowhite(arg);
+ if (*p != NUL) /* past first word */
+ {
+ xp->xp_pattern = skipwhite(p);
+ if (*skiptowhite(xp->xp_pattern) != NUL)
+ xp->xp_context = EXPAND_NOTHING;
+ else if (STRNICMP(arg, "add", p - arg) == 0)
+ xp->xp_context = EXPAND_FILES;
+ else if (STRNICMP(arg, "kill", p - arg) == 0)
+ expand_what = EXP_CSCOPE_KILL;
+ else if (STRNICMP(arg, "find", p - arg) == 0)
+ expand_what = EXP_CSCOPE_FIND;
+ else
+ xp->xp_context = EXPAND_NOTHING;
+ }
+ }
+}
+
+#endif /* FEAT_CMDL_COMPL */
+
+/*
+ * Find the command, print help if invalid, and then call the corresponding
+ * command function.
+ */
+ static void
+do_cscope_general(
+ exarg_T *eap,
+ int make_split UNUSED) /* whether to split window */
+{
+ cscmd_T *cmdp;
+
+ if ((cmdp = cs_lookup_cmd(eap)) == NULL)
+ {
+ cs_help(eap);
+ return;
+ }
+
+ if (make_split)
+ {
+ if (!cmdp->cansplit)
+ {
+ (void)msg_puts(_("This cscope command does not support splitting the window.\n"));
+ return;
+ }
+ postponed_split = -1;
+ postponed_split_flags = cmdmod.split;
+ postponed_split_tab = cmdmod.tab;
+ }
+
+ cmdp->func(eap);
+
+ postponed_split_flags = 0;
+ postponed_split_tab = 0;
+}
+
+/*
+ * Implementation of ":cscope" and ":lcscope"
+ */
+ void
+ex_cscope(exarg_T *eap)
+{
+ do_cscope_general(eap, FALSE);
+}
+
+/*
+ * Implementation of ":scscope". Same as ex_cscope(), but splits window, too.
+ */
+ void
+ex_scscope(exarg_T *eap)
+{
+ do_cscope_general(eap, TRUE);
+}
+
+/*
+ * Implementation of ":cstag"
+ */
+ void
+ex_cstag(exarg_T *eap)
+{
+ int ret = FALSE;
+
+ if (*eap->arg == NUL)
+ {
+ (void)emsg(_("E562: Usage: cstag <ident>"));
+ return;
+ }
+
+ switch (p_csto)
+ {
+ case 0 :
+ if (cs_check_for_connections())
+ {
+ ret = cs_find_common("g", (char *)(eap->arg), eap->forceit, FALSE,
+ FALSE, *eap->cmdlinep);
+ if (ret == FALSE)
+ {
+ cs_free_tags();
+ if (msg_col)
+ msg_putchar('\n');
+
+ if (cs_check_for_tags())
+ ret = do_tag(eap->arg, DT_JUMP, 0, eap->forceit, FALSE);
+ }
+ }
+ else if (cs_check_for_tags())
+ {
+ ret = do_tag(eap->arg, DT_JUMP, 0, eap->forceit, FALSE);
+ }
+ break;
+ case 1 :
+ if (cs_check_for_tags())
+ {
+ ret = do_tag(eap->arg, DT_JUMP, 0, eap->forceit, FALSE);
+ if (ret == FALSE)
+ {
+ if (msg_col)
+ msg_putchar('\n');
+
+ if (cs_check_for_connections())
+ {
+ ret = cs_find_common("g", (char *)(eap->arg), eap->forceit,
+ FALSE, FALSE, *eap->cmdlinep);
+ if (ret == FALSE)
+ cs_free_tags();
+ }
+ }
+ }
+ else if (cs_check_for_connections())
+ {
+ ret = cs_find_common("g", (char *)(eap->arg), eap->forceit, FALSE,
+ FALSE, *eap->cmdlinep);
+ if (ret == FALSE)
+ cs_free_tags();
+ }
+ break;
+ default :
+ break;
+ }
+
+ if (!ret)
+ {
+ (void)emsg(_("E257: cstag: tag not found"));
+#if defined(FEAT_QUICKFIX)
+ g_do_tagpreview = 0;
+#endif
+ }
+
+}
+
+
+/*
+ * This simulates a vim_fgets(), but for cscope, returns the next line
+ * from the cscope output. should only be called from find_tags()
+ *
+ * returns TRUE if eof, FALSE otherwise
+ */
+ int
+cs_fgets(char_u *buf, int size)
+{
+ char *p;
+
+ if ((p = cs_manage_matches(NULL, NULL, -1, Get)) == NULL)
+ return TRUE;
+ vim_strncpy(buf, (char_u *)p, size - 1);
+
+ return FALSE;
+} /* cs_fgets */
+
+
+/*
+ * Called only from do_tag(), when popping the tag stack.
+ */
+ void
+cs_free_tags(void)
+{
+ cs_manage_matches(NULL, NULL, -1, Free);
+}
+
+
+/*
+ * Called from do_tag().
+ */
+ void
+cs_print_tags(void)
+{
+ cs_manage_matches(NULL, NULL, -1, Print);
+}
+
+
+/*
+ * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
+ *
+ * Checks for the existence of a |cscope| connection. If no
+ * parameters are specified, then the function returns:
+ *
+ * 0, if cscope was not available (not compiled in), or if there
+ * are no cscope connections; or
+ * 1, if there is at least one cscope connection.
+ *
+ * If parameters are specified, then the value of {num}
+ * determines how existence of a cscope connection is checked:
+ *
+ * {num} Description of existence check
+ * ----- ------------------------------
+ * 0 Same as no parameters (e.g., "cscope_connection()").
+ * 1 Ignore {prepend}, and use partial string matches for
+ * {dbpath}.
+ * 2 Ignore {prepend}, and use exact string matches for
+ * {dbpath}.
+ * 3 Use {prepend}, use partial string matches for both
+ * {dbpath} and {prepend}.
+ * 4 Use {prepend}, use exact string matches for both
+ * {dbpath} and {prepend}.
+ *
+ * Note: All string comparisons are case sensitive!
+ */
+#if defined(FEAT_EVAL) || defined(PROTO)
+ int
+cs_connection(int num, char_u *dbpath, char_u *ppath)
+{
+ int i;
+
+ if (num < 0 || num > 4 || (num > 0 && !dbpath))
+ return FALSE;
+
+ for (i = 0; i < csinfo_size; i++)
+ {
+ if (!csinfo[i].fname)
+ continue;
+
+ if (num == 0)
+ return TRUE;
+
+ switch (num)
+ {
+ case 1:
+ if (strstr(csinfo[i].fname, (char *)dbpath))
+ return TRUE;
+ break;
+ case 2:
+ if (strcmp(csinfo[i].fname, (char *)dbpath) == 0)
+ return TRUE;
+ break;
+ case 3:
+ if (strstr(csinfo[i].fname, (char *)dbpath)
+ && ((!ppath && !csinfo[i].ppath)
+ || (ppath
+ && csinfo[i].ppath
+ && strstr(csinfo[i].ppath, (char *)ppath))))
+ return TRUE;
+ break;
+ case 4:
+ if ((strcmp(csinfo[i].fname, (char *)dbpath) == 0)
+ && ((!ppath && !csinfo[i].ppath)
+ || (ppath
+ && csinfo[i].ppath
+ && (strcmp(csinfo[i].ppath, (char *)ppath) == 0))))
+ return TRUE;
+ break;
+ }
+ }
+
+ return FALSE;
+} /* cs_connection */
+#endif
+
+
+/*
+ * PRIVATE functions
+ ****************************************************************************/
+
+/*
+ * Add cscope database or a directory name (to look for cscope.out)
+ * to the cscope connection list.
+ */
+ static int
+cs_add(exarg_T *eap UNUSED)
+{
+ char *fname, *ppath, *flags = NULL;
+
+ if ((fname = strtok((char *)NULL, (const char *)" ")) == NULL)
+ {
+ cs_usage_msg(Add);
+ return CSCOPE_FAILURE;
+ }
+ if ((ppath = strtok((char *)NULL, (const char *)" ")) != NULL)
+ flags = strtok((char *)NULL, (const char *)" ");
+
+ return cs_add_common(fname, ppath, flags);
+}
+
+ static void
+cs_stat_emsg(char *fname)
+{
+ char *stat_emsg = _("E563: stat(%s) error: %d");
+ char *buf = (char *)alloc((unsigned)strlen(stat_emsg) + MAXPATHL + 10);
+
+ if (buf != NULL)
+ {
+ (void)sprintf(buf, stat_emsg, fname, errno);
+ (void)emsg(buf);
+ vim_free(buf);
+ }
+ else
+ (void)emsg(_("E563: stat error"));
+}
+
+
+/*
+ * The common routine to add a new cscope connection. Called by
+ * cs_add() and cs_reset(). I really don't like to do this, but this
+ * routine uses a number of goto statements.
+ */
+ static int
+cs_add_common(
+ char *arg1, /* filename - may contain environment variables */
+ char *arg2, /* prepend path - may contain environment variables */
+ char *flags)
+{
+ stat_T statbuf;
+ int ret;
+ char *fname = NULL;
+ char *fname2 = NULL;
+ char *ppath = NULL;
+ int i;
+#ifdef FEAT_MODIFY_FNAME
+ int len;
+ int usedlen = 0;
+ char_u *fbuf = NULL;
+#endif
+
+ /* get the filename (arg1), expand it, and try to stat it */
+ if ((fname = (char *)alloc(MAXPATHL + 1)) == NULL)
+ goto add_err;
+
+ expand_env((char_u *)arg1, (char_u *)fname, MAXPATHL);
+#ifdef FEAT_MODIFY_FNAME
+ len = (int)STRLEN(fname);
+ fbuf = (char_u *)fname;
+ (void)modify_fname((char_u *)":p", FALSE, &usedlen,
+ (char_u **)&fname, &fbuf, &len);
+ if (fname == NULL)
+ goto add_err;
+ fname = (char *)vim_strnsave((char_u *)fname, len);
+ vim_free(fbuf);
+#endif
+ ret = mch_stat(fname, &statbuf);
+ if (ret < 0)
+ {
+staterr:
+ if (p_csverbose)
+ cs_stat_emsg(fname);
+ goto add_err;
+ }
+
+ /* get the prepend path (arg2), expand it, and try to stat it */
+ if (arg2 != NULL)
+ {
+ stat_T statbuf2;
+
+ if ((ppath = (char *)alloc(MAXPATHL + 1)) == NULL)
+ goto add_err;
+
+ expand_env((char_u *)arg2, (char_u *)ppath, MAXPATHL);
+ ret = mch_stat(ppath, &statbuf2);
+ if (ret < 0)
+ goto staterr;
+ }
+
+ /* if filename is a directory, append the cscope database name to it */
+ if (S_ISDIR(statbuf.st_mode))
+ {
+ fname2 = (char *)alloc((unsigned)(strlen(CSCOPE_DBFILE) + strlen(fname) + 2));
+ if (fname2 == NULL)
+ goto add_err;
+
+ while (fname[strlen(fname)-1] == '/'
+#ifdef WIN32
+ || fname[strlen(fname)-1] == '\\'
+#endif
+ )
+ {
+ fname[strlen(fname)-1] = '\0';
+ if (fname[0] == '\0')
+ break;
+ }
+ if (fname[0] == '\0')
+ (void)sprintf(fname2, "/%s", CSCOPE_DBFILE);
+ else
+ (void)sprintf(fname2, "%s/%s", fname, CSCOPE_DBFILE);
+
+ ret = mch_stat(fname2, &statbuf);
+ if (ret < 0)
+ {
+ if (p_csverbose)
+ cs_stat_emsg(fname2);
+ goto add_err;
+ }
+
+ i = cs_insert_filelist(fname2, ppath, flags, &statbuf);
+ }
+ else if (S_ISREG(statbuf.st_mode) || S_ISLNK(statbuf.st_mode))
+ {
+ i = cs_insert_filelist(fname, ppath, flags, &statbuf);
+ }
+ else
+ {
+ if (p_csverbose)
+ (void)semsg(
+ _("E564: %s is not a directory or a valid cscope database"),
+ fname);
+ goto add_err;
+ }
+
+ if (i != -1)
+ {
+ if (cs_create_connection(i) == CSCOPE_FAILURE
+ || cs_read_prompt(i) == CSCOPE_FAILURE)
+ {
+ cs_release_csp(i, TRUE);
+ goto add_err;
+ }
+
+ if (p_csverbose)
+ {
+ msg_clr_eos();
+ (void)smsg_attr(HL_ATTR(HLF_R),
+ _("Added cscope database %s"),
+ csinfo[i].fname);
+ }
+ }
+
+ vim_free(fname);
+ vim_free(fname2);
+ vim_free(ppath);
+ return CSCOPE_SUCCESS;
+
+add_err:
+ vim_free(fname2);
+ vim_free(fname);
+ vim_free(ppath);
+ return CSCOPE_FAILURE;
+} /* cs_add_common */
+
+
+ static int
+cs_check_for_connections(void)
+{
+ return (cs_cnt_connections() > 0);
+} /* cs_check_for_connections */
+
+
+ static int
+cs_check_for_tags(void)
+{
+ return (p_tags[0] != NUL && curbuf->b_p_tags != NULL);
+} /* cs_check_for_tags */
+
+
+/*
+ * Count the number of cscope connections.
+ */
+ static int
+cs_cnt_connections(void)
+{
+ short i;
+ short cnt = 0;
+
+ for (i = 0; i < csinfo_size; i++)
+ {
+ if (csinfo[i].fname != NULL)
+ cnt++;
+ }
+ return cnt;
+} /* cs_cnt_connections */
+
+ static void
+cs_reading_emsg(
+ int idx) /* connection index */
+{
+ semsg(_("E262: error reading cscope connection %d"), idx);
+}
+
+#define CSREAD_BUFSIZE 2048
+/*
+ * Count the number of matches for a given cscope connection.
+ */
+ static int
+cs_cnt_matches(int idx)
+{
+ char *stok;
+ char *buf;
+ int nlines = 0;
+
+ buf = (char *)alloc(CSREAD_BUFSIZE);
+ if (buf == NULL)
+ return 0;
+ for (;;)
+ {
+ if (!fgets(buf, CSREAD_BUFSIZE, csinfo[idx].fr_fp))
+ {
+ if (feof(csinfo[idx].fr_fp))
+ errno = EIO;
+
+ cs_reading_emsg(idx);
+
+ vim_free(buf);
+ return -1;
+ }
+
+ /*
+ * If the database is out of date, or there's some other problem,
+ * cscope will output error messages before the number-of-lines output.
+ * Display/discard any output that doesn't match what we want.
+ * Accept "\S*cscope: X lines", also matches "mlcscope".
+ * Bail out for the "Unable to search" error.
+ */
+ if (strstr((const char *)buf, "Unable to search database") != NULL)
+ break;
+ if ((stok = strtok(buf, (const char *)" ")) == NULL)
+ continue;
+ if (strstr((const char *)stok, "cscope:") == NULL)
+ continue;
+
+ if ((stok = strtok(NULL, (const char *)" ")) == NULL)
+ continue;
+ nlines = atoi(stok);
+ if (nlines < 0)
+ {
+ nlines = 0;
+ break;
+ }
+
+ if ((stok = strtok(NULL, (const char *)" ")) == NULL)
+ continue;
+ if (strncmp((const char *)stok, "lines", 5))
+ continue;
+
+ break;
+ }
+
+ vim_free(buf);
+ return nlines;
+} /* cs_cnt_matches */
+
+
+/*
+ * Creates the actual cscope command query from what the user entered.
+ */
+ static char *
+cs_create_cmd(char *csoption, char *pattern)
+{
+ char *cmd;
+ short search;
+ char *pat;
+
+ switch (csoption[0])
+ {
+ case '0' : case 's' :
+ search = 0;
+ break;
+ case '1' : case 'g' :
+ search = 1;
+ break;
+ case '2' : case 'd' :
+ search = 2;
+ break;
+ case '3' : case 'c' :
+ search = 3;
+ break;
+ case '4' : case 't' :
+ search = 4;
+ break;
+ case '6' : case 'e' :
+ search = 6;
+ break;
+ case '7' : case 'f' :
+ search = 7;
+ break;
+ case '8' : case 'i' :
+ search = 8;
+ break;
+ case '9' : case 'a' :
+ search = 9;
+ break;
+ default :
+ (void)emsg(_("E561: unknown cscope search type"));
+ cs_usage_msg(Find);
+ return NULL;
+ }
+
+ /* Skip white space before the patter, except for text and pattern search,
+ * they may want to use the leading white space. */
+ pat = pattern;
+ if (search != 4 && search != 6)
+ while VIM_ISWHITE(*pat)
+ ++pat;
+
+ if ((cmd = (char *)alloc((unsigned)(strlen(pat) + 2))) == NULL)
+ return NULL;
+
+ (void)sprintf(cmd, "%d%s", search, pat);
+
+ return cmd;
+} /* cs_create_cmd */
+
+
+/*
+ * This piece of code was taken/adapted from nvi. do we need to add
+ * the BSD license notice?
+ */
+ static int
+cs_create_connection(int i)
+{
+#ifdef UNIX
+ int to_cs[2], from_cs[2];
+#endif
+ int len;
+ char *prog, *cmd, *ppath = NULL;
+#ifdef WIN32
+ int fd;
+ SECURITY_ATTRIBUTES sa;
+ PROCESS_INFORMATION pi;
+ STARTUPINFO si;
+ BOOL pipe_stdin = FALSE, pipe_stdout = FALSE;
+ HANDLE stdin_rd, stdout_rd;
+ HANDLE stdout_wr, stdin_wr;
+ BOOL created;
+# if (defined(_MSC_VER) && (_MSC_VER >= 1300)) || defined(__MINGW32__)
+# define OPEN_OH_ARGTYPE intptr_t
+# else
+# define OPEN_OH_ARGTYPE long
+# endif
+#endif
+
+#if defined(UNIX)
+ /*
+ * Cscope reads from to_cs[0] and writes to from_cs[1]; vi reads from
+ * from_cs[0] and writes to to_cs[1].
+ */
+ to_cs[0] = to_cs[1] = from_cs[0] = from_cs[1] = -1;
+ if (pipe(to_cs) < 0 || pipe(from_cs) < 0)
+ {
+ (void)emsg(_("E566: Could not create cscope pipes"));
+err_closing:
+ if (to_cs[0] != -1)
+ (void)close(to_cs[0]);
+ if (to_cs[1] != -1)
+ (void)close(to_cs[1]);
+ if (from_cs[0] != -1)
+ (void)close(from_cs[0]);
+ if (from_cs[1] != -1)
+ (void)close(from_cs[1]);
+ return CSCOPE_FAILURE;
+ }
+
+ switch (csinfo[i].pid = fork())
+ {
+ case -1:
+ (void)emsg(_("E622: Could not fork for cscope"));
+ goto err_closing;
+ case 0: /* child: run cscope. */
+ if (dup2(to_cs[0], STDIN_FILENO) == -1)
+ PERROR("cs_create_connection 1");
+ if (dup2(from_cs[1], STDOUT_FILENO) == -1)
+ PERROR("cs_create_connection 2");
+ if (dup2(from_cs[1], STDERR_FILENO) == -1)
+ PERROR("cs_create_connection 3");
+
+ /* close unused */
+ (void)close(to_cs[1]);
+ (void)close(from_cs[0]);
+#else
+ /* WIN32 */
+ /* Create pipes to communicate with cscope */
+ sa.nLength = sizeof(SECURITY_ATTRIBUTES);
+ sa.bInheritHandle = TRUE;
+ sa.lpSecurityDescriptor = NULL;
+
+ if (!(pipe_stdin = CreatePipe(&stdin_rd, &stdin_wr, &sa, 0))
+ || !(pipe_stdout = CreatePipe(&stdout_rd, &stdout_wr, &sa, 0)))
+ {
+ (void)emsg(_("E566: Could not create cscope pipes"));
+err_closing:
+ if (pipe_stdin)
+ {
+ CloseHandle(stdin_rd);
+ CloseHandle(stdin_wr);
+ }
+ if (pipe_stdout)
+ {
+ CloseHandle(stdout_rd);
+ CloseHandle(stdout_wr);
+ }
+ return CSCOPE_FAILURE;
+ }
+#endif
+ /* expand the cscope exec for env var's */
+ if ((prog = (char *)alloc(MAXPATHL + 1)) == NULL)
+ {
+#ifdef UNIX
+ return CSCOPE_FAILURE;
+#else
+ /* WIN32 */
+ goto err_closing;
+#endif
+ }
+ expand_env((char_u *)p_csprg, (char_u *)prog, MAXPATHL);
+
+ /* alloc space to hold the cscope command */
+ len = (int)(strlen(prog) + strlen(csinfo[i].fname) + 32);
+ if (csinfo[i].ppath)
+ {
+ /* expand the prepend path for env var's */
+ if ((ppath = (char *)alloc(MAXPATHL + 1)) == NULL)
+ {
+ vim_free(prog);
+#ifdef UNIX
+ return CSCOPE_FAILURE;
+#else
+ /* WIN32 */
+ goto err_closing;
+#endif
+ }
+ expand_env((char_u *)csinfo[i].ppath, (char_u *)ppath, MAXPATHL);
+
+ len += (int)strlen(ppath);
+ }
+
+ if (csinfo[i].flags)
+ len += (int)strlen(csinfo[i].flags);
+
+ if ((cmd = (char *)alloc(len)) == NULL)
+ {
+ vim_free(prog);
+ vim_free(ppath);
+#ifdef UNIX
+ return CSCOPE_FAILURE;
+#else
+ /* WIN32 */
+ goto err_closing;
+#endif
+ }
+
+ /* run the cscope command; is there execl for non-unix systems? */
+#if defined(UNIX)
+ (void)sprintf(cmd, "exec %s -dl -f %s", prog, csinfo[i].fname);
+#else
+ /* WIN32 */
+ (void)sprintf(cmd, "%s -dl -f %s", prog, csinfo[i].fname);
+#endif
+ if (csinfo[i].ppath != NULL)
+ {
+ (void)strcat(cmd, " -P");
+ (void)strcat(cmd, csinfo[i].ppath);
+ }
+ if (csinfo[i].flags != NULL)
+ {
+ (void)strcat(cmd, " ");
+ (void)strcat(cmd, csinfo[i].flags);
+ }
+# ifdef UNIX
+ /* on Win32 we still need prog */
+ vim_free(prog);
+# endif
+ vim_free(ppath);
+
+#if defined(UNIX)
+# if defined(HAVE_SETSID) || defined(HAVE_SETPGID)
+ /* Change our process group to avoid cscope receiving SIGWINCH. */
+# if defined(HAVE_SETSID)
+ (void)setsid();
+# else
+ if (setpgid(0, 0) == -1)
+ PERROR(_("cs_create_connection setpgid failed"));
+# endif
+# endif
+ if (execl("/bin/sh", "sh", "-c", cmd, (char *)NULL) == -1)
+ PERROR(_("cs_create_connection exec failed"));
+
+ exit(127);
+ /* NOTREACHED */
+ default: /* parent. */
+ /*
+ * Save the file descriptors for later duplication, and
+ * reopen as streams.
+ */
+ if ((csinfo[i].to_fp = fdopen(to_cs[1], "w")) == NULL)
+ PERROR(_("cs_create_connection: fdopen for to_fp failed"));
+ if ((csinfo[i].fr_fp = fdopen(from_cs[0], "r")) == NULL)
+ PERROR(_("cs_create_connection: fdopen for fr_fp failed"));
+
+ /* close unused */
+ (void)close(to_cs[0]);
+ (void)close(from_cs[1]);
+
+ break;
+ }
+
+#else
+ /* WIN32 */
+ /* Create a new process to run cscope and use pipes to talk with it */
+ GetStartupInfo(&si);
+ si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
+ si.wShowWindow = SW_HIDE; /* Hide child application window */
+ si.hStdOutput = stdout_wr;
+ si.hStdError = stdout_wr;
+ si.hStdInput = stdin_rd;
+ created = CreateProcess(NULL, cmd, NULL, NULL, TRUE, CREATE_NEW_CONSOLE,
+ NULL, NULL, &si, &pi);
+ vim_free(prog);
+ vim_free(cmd);
+
+ if (!created)
+ {
+ PERROR(_("cs_create_connection exec failed"));
+ (void)emsg(_("E623: Could not spawn cscope process"));
+ goto err_closing;
+ }
+ /* else */
+ csinfo[i].pid = pi.dwProcessId;
+ csinfo[i].hProc = pi.hProcess;
+ CloseHandle(pi.hThread);
+
+ /* TODO - tidy up after failure to create files on pipe handles. */
+ if (((fd = _open_osfhandle((OPEN_OH_ARGTYPE)stdin_wr,
+ _O_TEXT|_O_APPEND)) < 0)
+ || ((csinfo[i].to_fp = _fdopen(fd, "w")) == NULL))
+ PERROR(_("cs_create_connection: fdopen for to_fp failed"));
+ if (((fd = _open_osfhandle((OPEN_OH_ARGTYPE)stdout_rd,
+ _O_TEXT|_O_RDONLY)) < 0)
+ || ((csinfo[i].fr_fp = _fdopen(fd, "r")) == NULL))
+ PERROR(_("cs_create_connection: fdopen for fr_fp failed"));
+
+ /* Close handles for file descriptors inherited by the cscope process */
+ CloseHandle(stdin_rd);
+ CloseHandle(stdout_wr);
+
+#endif /* !UNIX */
+
+ return CSCOPE_SUCCESS;
+} /* cs_create_connection */
+
+
+/*
+ * Query cscope using command line interface. Parse the output and use tselect
+ * to allow choices. Like Nvi, creates a pipe to send to/from query/cscope.
+ *
+ * returns TRUE if we jump to a tag or abort, FALSE if not.
+ */
+ static int
+cs_find(exarg_T *eap)
+{
+ char *opt, *pat;
+ int i;
+
+ if (cs_check_for_connections() == FALSE)
+ {
+ (void)emsg(_("E567: no cscope connections"));
+ return FALSE;
+ }
+
+ if ((opt = strtok((char *)NULL, (const char *)" ")) == NULL)
+ {
+ cs_usage_msg(Find);
+ return FALSE;
+ }
+
+ pat = opt + strlen(opt) + 1;
+ if (pat >= (char *)eap->arg + eap_arg_len)
+ {
+ cs_usage_msg(Find);
+ return FALSE;
+ }
+
+ /*
+ * Let's replace the NULs written by strtok() with spaces - we need the
+ * spaces to correctly display the quickfix/location list window's title.
+ */
+ for (i = 0; i < eap_arg_len; ++i)
+ if (NUL == eap->arg[i])
+ eap->arg[i] = ' ';
+
+ return cs_find_common(opt, pat, eap->forceit, TRUE,
+ eap->cmdidx == CMD_lcscope, *eap->cmdlinep);
+} /* cs_find */
+
+
+/*
+ * Common code for cscope find, shared by cs_find() and ex_cstag().
+ */
+ static int
+cs_find_common(
+ char *opt,
+ char *pat,
+ int forceit,
+ int verbose,
+ int use_ll UNUSED,
+ char_u *cmdline UNUSED)
+{
+ int i;
+ char *cmd;
+ int *nummatches;
+ int totmatches;
+#ifdef FEAT_QUICKFIX
+ char cmdletter;
+ char *qfpos;
+
+ /* get cmd letter */
+ switch (opt[0])
+ {
+ case '0' :
+ cmdletter = 's';
+ break;
+ case '1' :
+ cmdletter = 'g';
+ break;
+ case '2' :
+ cmdletter = 'd';
+ break;
+ case '3' :
+ cmdletter = 'c';
+ break;
+ case '4' :
+ cmdletter = 't';
+ break;
+ case '6' :
+ cmdletter = 'e';
+ break;
+ case '7' :
+ cmdletter = 'f';
+ break;
+ case '8' :
+ cmdletter = 'i';
+ break;
+ case '9' :
+ cmdletter = 'a';
+ break;
+ default :
+ cmdletter = opt[0];
+ }
+
+ qfpos = (char *)vim_strchr(p_csqf, cmdletter);
+ if (qfpos != NULL)
+ {
+ qfpos++;
+ /* next symbol must be + or - */
+ if (strchr(CSQF_FLAGS, *qfpos) == NULL)
+ {
+ char *nf = _("E469: invalid cscopequickfix flag %c for %c");
+ char *buf = (char *)alloc((unsigned)strlen(nf));
+
+ /* strlen will be enough because we use chars */
+ if (buf != NULL)
+ {
+ sprintf(buf, nf, *qfpos, *(qfpos-1));
+ (void)emsg(buf);
+ vim_free(buf);
+ }
+ return FALSE;
+ }
+
+ if (*qfpos != '0'
+ && apply_autocmds(EVENT_QUICKFIXCMDPRE, (char_u *)"cscope",
+ curbuf->b_fname, TRUE, curbuf))
+ {
+# ifdef FEAT_EVAL
+ if (aborting())
+ return FALSE;
+# endif
+ }
+ }
+#endif
+
+ /* create the actual command to send to cscope */
+ cmd = cs_create_cmd(opt, pat);
+ if (cmd == NULL)
+ return FALSE;
+
+ nummatches = (int *)alloc(sizeof(int)*csinfo_size);
+ if (nummatches == NULL)
+ {
+ vim_free(cmd);
+ return FALSE;
+ }
+
+ /* Send query to all open connections, then count the total number
+ * of matches so we can alloc all in one swell foop. */
+ for (i = 0; i < csinfo_size; i++)
+ nummatches[i] = 0;
+ totmatches = 0;
+ for (i = 0; i < csinfo_size; i++)
+ {
+ if (csinfo[i].fname == NULL || csinfo[i].to_fp == NULL)
+ continue;
+
+ /* send cmd to cscope */
+ (void)fprintf(csinfo[i].to_fp, "%s\n", cmd);
+ (void)fflush(csinfo[i].to_fp);
+
+ nummatches[i] = cs_cnt_matches(i);
+
+ if (nummatches[i] > -1)
+ totmatches += nummatches[i];
+
+ if (nummatches[i] == 0)
+ (void)cs_read_prompt(i);
+ }
+ vim_free(cmd);
+
+ if (totmatches == 0)
+ {
+ char *nf = _("E259: no matches found for cscope query %s of %s");
+ char *buf;
+
+ if (!verbose)
+ {
+ vim_free(nummatches);
+ return FALSE;
+ }
+
+ buf = (char *)alloc((unsigned)(strlen(opt) + strlen(pat) + strlen(nf)));
+ if (buf == NULL)
+ (void)emsg(nf);
+ else
+ {
+ sprintf(buf, nf, opt, pat);
+ (void)emsg(buf);
+ vim_free(buf);
+ }
+ vim_free(nummatches);
+ return FALSE;
+ }
+
+#ifdef FEAT_QUICKFIX
+ if (qfpos != NULL && *qfpos != '0' && totmatches > 0)
+ {
+ /* fill error list */
+ FILE *f;
+ char_u *tmp = vim_tempname('c', TRUE);
+ qf_info_T *qi = NULL;
+ win_T *wp = NULL;
+
+ f = mch_fopen((char *)tmp, "w");
+ if (f == NULL)
+ semsg(_(e_notopen), tmp);
+ else
+ {
+ cs_file_results(f, nummatches);
+ fclose(f);
+ if (use_ll) /* Use location list */
+ wp = curwin;
+ /* '-' starts a new error list */
+ if (qf_init(wp, tmp, (char_u *)"%f%*\\t%l%*\\t%m",
+ *qfpos == '-', cmdline, NULL) > 0)
+ {
+ if (postponed_split != 0)
+ {
+ (void)win_split(postponed_split > 0 ? postponed_split : 0,
+ postponed_split_flags);
+ RESET_BINDING(curwin);
+ postponed_split = 0;
+ }
+
+ apply_autocmds(EVENT_QUICKFIXCMDPOST, (char_u *)"cscope",
+ curbuf->b_fname, TRUE, curbuf);
+ if (use_ll)
+ /*
+ * In the location list window, use the displayed location
+ * list. Otherwise, use the location list for the window.
+ */
+ qi = (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL)
+ ? wp->w_llist_ref : wp->w_llist;
+ qf_jump(qi, 0, 0, forceit);
+ }
+ }
+ mch_remove(tmp);
+ vim_free(tmp);
+ vim_free(nummatches);
+ return TRUE;
+ }
+ else
+#endif /* FEAT_QUICKFIX */
+ {
+ char **matches = NULL, **contexts = NULL;
+ int matched = 0;
+
+ /* read output */
+ cs_fill_results((char *)pat, totmatches, nummatches, &matches,
+ &contexts, &matched);
+ vim_free(nummatches);
+ if (matches == NULL)
+ return FALSE;
+
+ (void)cs_manage_matches(matches, contexts, matched, Store);
+
+ return do_tag((char_u *)pat, DT_CSCOPE, 0, forceit, verbose);
+ }
+
+} /* cs_find_common */
+
+/*
+ * Print help.
+ */
+ static int
+cs_help(exarg_T *eap UNUSED)
+{
+ cscmd_T *cmdp = cs_cmds;
+
+ (void)msg_puts(_("cscope commands:\n"));
+ while (cmdp->name != NULL)
+ {
+ char *help = _(cmdp->help);
+ int space_cnt = 30 - vim_strsize((char_u *)help);
+
+ /* Use %*s rather than %30s to ensure proper alignment in utf-8 */
+ if (space_cnt < 0)
+ space_cnt = 0;
+ (void)smsg(_("%-5s: %s%*s (Usage: %s)"),
+ cmdp->name,
+ help, space_cnt, " ",
+ cmdp->usage);
+ if (strcmp(cmdp->name, "find") == 0)
+ msg_puts(_("\n"
+ " a: Find assignments to this symbol\n"
+ " c: Find functions calling this function\n"
+ " d: Find functions called by this function\n"
+ " e: Find this egrep pattern\n"
+ " f: Find this file\n"
+ " g: Find this definition\n"
+ " i: Find files #including this file\n"
+ " s: Find this C symbol\n"
+ " t: Find this text string\n"));
+
+ cmdp++;
+ }
+
+ wait_return(TRUE);
+ return 0;
+} /* cs_help */
+
+
+ static void
+clear_csinfo(int i)
+{
+ csinfo[i].fname = NULL;
+ csinfo[i].ppath = NULL;
+ csinfo[i].flags = NULL;
+#if defined(UNIX)
+ csinfo[i].st_dev = (dev_t)0;
+ csinfo[i].st_ino = (ino_t)0;
+#else
+ csinfo[i].nVolume = 0;
+ csinfo[i].nIndexHigh = 0;
+ csinfo[i].nIndexLow = 0;
+#endif
+ csinfo[i].pid = 0;
+ csinfo[i].fr_fp = NULL;
+ csinfo[i].to_fp = NULL;
+#if defined(WIN32)
+ csinfo[i].hProc = NULL;
+#endif
+}
+
+#ifndef UNIX
+ static char *
+GetWin32Error(void)
+{
+ char *msg = NULL;
+ FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL, GetLastError(), 0, (LPSTR)&msg, 0, NULL);
+ if (msg != NULL)
+ {
+ /* remove trailing \r\n */
+ char *pcrlf = strstr(msg, "\r\n");
+ if (pcrlf != NULL)
+ *pcrlf = '\0';
+ }
+ return msg;
+}
+#endif
+
+/*
+ * Insert a new cscope database filename into the filelist.
+ */
+ static int
+cs_insert_filelist(
+ char *fname,
+ char *ppath,
+ char *flags,
+ stat_T *sb UNUSED)
+{
+ short i, j;
+#ifndef UNIX
+ BY_HANDLE_FILE_INFORMATION bhfi;
+
+ switch (win32_fileinfo((char_u *)fname, &bhfi))
+ {
+ case FILEINFO_ENC_FAIL: /* enc_to_utf16() failed */
+ case FILEINFO_READ_FAIL: /* CreateFile() failed */
+ if (p_csverbose)
+ {
+ char *cant_msg = _("E625: cannot open cscope database: %s");
+ char *winmsg = GetWin32Error();
+
+ if (winmsg != NULL)
+ {
+ (void)semsg(cant_msg, winmsg);
+ LocalFree(winmsg);
+ }
+ else
+ /* subst filename if can't get error text */
+ (void)semsg(cant_msg, fname);
+ }
+ return -1;
+
+ case FILEINFO_INFO_FAIL: /* GetFileInformationByHandle() failed */
+ if (p_csverbose)
+ (void)emsg(_("E626: cannot get cscope database information"));
+ return -1;
+ }
+#endif
+
+ i = -1; /* can be set to the index of an empty item in csinfo */
+ for (j = 0; j < csinfo_size; j++)
+ {
+ if (csinfo[j].fname != NULL
+#if defined(UNIX)
+ && csinfo[j].st_dev == sb->st_dev && csinfo[j].st_ino == sb->st_ino
+#else
+ /* compare pathnames first */
+ && ((fullpathcmp((char_u *)csinfo[j].fname,
+ (char_u *)fname, FALSE) & FPC_SAME)
+ /* test index file attributes too */
+ || (csinfo[j].nVolume == bhfi.dwVolumeSerialNumber
+ && csinfo[j].nIndexHigh == bhfi.nFileIndexHigh
+ && csinfo[j].nIndexLow == bhfi.nFileIndexLow))
+#endif
+ )
+ {
+ if (p_csverbose)
+ (void)emsg(_("E568: duplicate cscope database not added"));
+ return -1;
+ }
+
+ if (csinfo[j].fname == NULL && i == -1)
+ i = j; /* remember first empty entry */
+ }
+
+ if (i == -1)
+ {
+ i = csinfo_size;
+ if (csinfo_size == 0)
+ {
+ /* First time allocation: allocate only 1 connection. It should
+ * be enough for most users. If more is needed, csinfo will be
+ * reallocated. */
+ csinfo_size = 1;
+ csinfo = (csinfo_T *)alloc_clear(sizeof(csinfo_T));
+ }
+ else
+ {
+ csinfo_T *t_csinfo = csinfo;
+
+ /* Reallocate space for more connections. */
+ csinfo_size *= 2;
+ csinfo = vim_realloc(csinfo, sizeof(csinfo_T)*csinfo_size);
+ if (csinfo == NULL)
+ {
+ vim_free(t_csinfo);
+ csinfo_size = 0;
+ }
+ }
+ if (csinfo == NULL)
+ return -1;
+ for (j = csinfo_size/2; j < csinfo_size; j++)
+ clear_csinfo(j);
+ }
+
+ if ((csinfo[i].fname = (char *)alloc((unsigned)strlen(fname)+1)) == NULL)
+ return -1;
+
+ (void)strcpy(csinfo[i].fname, (const char *)fname);
+
+ if (ppath != NULL)
+ {
+ if ((csinfo[i].ppath = (char *)alloc((unsigned)strlen(ppath) + 1)) == NULL)
+ {
+ VIM_CLEAR(csinfo[i].fname);
+ return -1;
+ }
+ (void)strcpy(csinfo[i].ppath, (const char *)ppath);
+ } else
+ csinfo[i].ppath = NULL;
+
+ if (flags != NULL)
+ {
+ if ((csinfo[i].flags = (char *)alloc((unsigned)strlen(flags) + 1)) == NULL)
+ {
+ VIM_CLEAR(csinfo[i].fname);
+ VIM_CLEAR(csinfo[i].ppath);
+ return -1;
+ }
+ (void)strcpy(csinfo[i].flags, (const char *)flags);
+ } else
+ csinfo[i].flags = NULL;
+
+#if defined(UNIX)
+ csinfo[i].st_dev = sb->st_dev;
+ csinfo[i].st_ino = sb->st_ino;
+
+#else
+ csinfo[i].nVolume = bhfi.dwVolumeSerialNumber;
+ csinfo[i].nIndexLow = bhfi.nFileIndexLow;
+ csinfo[i].nIndexHigh = bhfi.nFileIndexHigh;
+#endif
+ return i;
+} /* cs_insert_filelist */
+
+
+/*
+ * Find cscope command in command table.
+ */
+ static cscmd_T *
+cs_lookup_cmd(exarg_T *eap)
+{
+ cscmd_T *cmdp;
+ char *stok;
+ size_t len;
+
+ if (eap->arg == NULL)
+ return NULL;
+
+ /* Store length of eap->arg before it gets modified by strtok(). */
+ eap_arg_len = (int)STRLEN(eap->arg);
+
+ if ((stok = strtok((char *)(eap->arg), (const char *)" ")) == NULL)
+ return NULL;
+
+ len = strlen(stok);
+ for (cmdp = cs_cmds; cmdp->name != NULL; ++cmdp)
+ {
+ if (strncmp((const char *)(stok), cmdp->name, len) == 0)
+ return (cmdp);
+ }
+ return NULL;
+} /* cs_lookup_cmd */
+
+
+/*
+ * Nuke em.
+ */
+ static int
+cs_kill(exarg_T *eap UNUSED)
+{
+ char *stok;
+ short i;
+
+ if ((stok = strtok((char *)NULL, (const char *)" ")) == NULL)
+ {
+ cs_usage_msg(Kill);
+ return CSCOPE_FAILURE;
+ }
+
+ /* only single digit positive and negative integers are allowed */
+ if ((strlen(stok) < 2 && VIM_ISDIGIT((int)(stok[0])))
+ || (strlen(stok) < 3 && stok[0] == '-'
+ && VIM_ISDIGIT((int)(stok[1]))))
+ i = atoi(stok);
+ else
+ {
+ /* It must be part of a name. We will try to find a match
+ * within all the names in the csinfo data structure
+ */
+ for (i = 0; i < csinfo_size; i++)
+ {
+ if (csinfo[i].fname != NULL && strstr(csinfo[i].fname, stok))
+ break;
+ }
+ }
+
+ if ((i != -1) && (i >= csinfo_size || i < -1 || csinfo[i].fname == NULL))
+ {
+ if (p_csverbose)
+ (void)semsg(_("E261: cscope connection %s not found"), stok);
+ }
+ else
+ {
+ if (i == -1)
+ {
+ for (i = 0; i < csinfo_size; i++)
+ {
+ if (csinfo[i].fname)
+ cs_kill_execute(i, csinfo[i].fname);
+ }
+ }
+ else
+ cs_kill_execute(i, stok);
+ }
+
+ return 0;
+} /* cs_kill */
+
+
+/*
+ * Actually kills a specific cscope connection.
+ */
+ static void
+cs_kill_execute(
+ int i, /* cscope table index */
+ char *cname) /* cscope database name */
+{
+ if (p_csverbose)
+ {
+ msg_clr_eos();
+ (void)smsg_attr(HL_ATTR(HLF_R) | MSG_HIST,
+ _("cscope connection %s closed"), cname);
+ }
+ cs_release_csp(i, TRUE);
+}
+
+
+/*
+ * Convert the cscope output into a ctags style entry (as might be found
+ * in a ctags tags file). there's one catch though: cscope doesn't tell you
+ * the type of the tag you are looking for. for example, in Darren Hiebert's
+ * ctags (the one that comes with vim), #define's use a line number to find the
+ * tag in a file while function definitions use a regexp search pattern.
+ *
+ * I'm going to always use the line number because cscope does something
+ * quirky (and probably other things i don't know about):
+ *
+ * if you have "# define" in your source file, which is
+ * perfectly legal, cscope thinks you have "#define". this
+ * will result in a failed regexp search. :(
+ *
+ * Besides, even if this particular case didn't happen, the search pattern
+ * would still have to be modified to escape all the special regular expression
+ * characters to comply with ctags formatting.
+ */
+ static char *
+cs_make_vim_style_matches(
+ char *fname,
+ char *slno,
+ char *search,
+ char *tagstr)
+{
+ /* vim style is ctags:
+ *
+ * <tagstr>\t<filename>\t<linenum_or_search>"\t<extra>
+ *
+ * but as mentioned above, we'll always use the line number and
+ * put the search pattern (if one exists) as "extra"
+ *
+ * buf is used as part of vim's method of handling tags, and
+ * (i think) vim frees it when you pop your tags and get replaced
+ * by new ones on the tag stack.
+ */
+ char *buf;
+ int amt;
+
+ if (search != NULL)
+ {
+ amt = (int)(strlen(fname) + strlen(slno) + strlen(tagstr) + strlen(search)+6);
+ if ((buf = (char *)alloc(amt)) == NULL)
+ return NULL;
+
+ (void)sprintf(buf, "%s\t%s\t%s;\"\t%s", tagstr, fname, slno, search);
+ }
+ else
+ {
+ amt = (int)(strlen(fname) + strlen(slno) + strlen(tagstr) + 5);
+ if ((buf = (char *)alloc(amt)) == NULL)
+ return NULL;
+
+ (void)sprintf(buf, "%s\t%s\t%s;\"", tagstr, fname, slno);
+ }
+
+ return buf;
+} /* cs_make_vim_style_matches */
+
+
+/*
+ * This is kind of hokey, but i don't see an easy way round this.
+ *
+ * Store: keep a ptr to the (malloc'd) memory of matches originally
+ * generated from cs_find(). the matches are originally lines directly
+ * from cscope output, but transformed to look like something out of a
+ * ctags. see cs_make_vim_style_matches for more details.
+ *
+ * Get: used only from cs_fgets(), this simulates a vim_fgets() to return
+ * the next line from the cscope output. it basically keeps track of which
+ * lines have been "used" and returns the next one.
+ *
+ * Free: frees up everything and resets
+ *
+ * Print: prints the tags
+ */
+ static char *
+cs_manage_matches(
+ char **matches,
+ char **contexts,
+ int totmatches,
+ mcmd_e cmd)
+{
+ static char **mp = NULL;
+ static char **cp = NULL;
+ static int cnt = -1;
+ static int next = -1;
+ char *p = NULL;
+
+ switch (cmd)
+ {
+ case Store:
+ assert(matches != NULL);
+ assert(totmatches > 0);
+ if (mp != NULL || cp != NULL)
+ (void)cs_manage_matches(NULL, NULL, -1, Free);
+ mp = matches;
+ cp = contexts;
+ cnt = totmatches;
+ next = 0;
+ break;
+ case Get:
+ if (next >= cnt)
+ return NULL;
+
+ p = mp[next];
+ next++;
+ break;
+ case Free:
+ if (mp != NULL)
+ {
+ if (cnt > 0)
+ while (cnt--)
+ {
+ vim_free(mp[cnt]);
+ if (cp != NULL)
+ vim_free(cp[cnt]);
+ }
+ vim_free(mp);
+ vim_free(cp);
+ }
+ mp = NULL;
+ cp = NULL;
+ cnt = 0;
+ next = 0;
+ break;
+ case Print:
+ cs_print_tags_priv(mp, cp, cnt);
+ break;
+ default: /* should not reach here */
+ iemsg(_("E570: fatal error in cs_manage_matches"));
+ return NULL;
+ }
+
+ return p;
+} /* cs_manage_matches */
+
+
+/*
+ * Parse cscope output.
+ */
+ static char *
+cs_parse_results(
+ int cnumber,
+ char *buf,
+ int bufsize,
+ char **context,
+ char **linenumber,
+ char **search)
+{
+ int ch;
+ char *p;
+ char *name;
+
+ if (fgets(buf, bufsize, csinfo[cnumber].fr_fp) == NULL)
+ {
+ if (feof(csinfo[cnumber].fr_fp))
+ errno = EIO;
+
+ cs_reading_emsg(cnumber);
+
+ return NULL;
+ }
+
+ /* If the line's too long for the buffer, discard it. */
+ if ((p = strchr(buf, '\n')) == NULL)
+ {
+ while ((ch = getc(csinfo[cnumber].fr_fp)) != EOF && ch != '\n')
+ ;
+ return NULL;
+ }
+ *p = '\0';
+
+ /*
+ * cscope output is in the following format:
+ *
+ * <filename> <context> <line number> <pattern>
+ */
+ if ((name = strtok((char *)buf, (const char *)" ")) == NULL)
+ return NULL;
+ if ((*context = strtok(NULL, (const char *)" ")) == NULL)
+ return NULL;
+ if ((*linenumber = strtok(NULL, (const char *)" ")) == NULL)
+ return NULL;
+ *search = *linenumber + strlen(*linenumber) + 1; /* +1 to skip \0 */
+
+ /* --- nvi ---
+ * If the file is older than the cscope database, that is,
+ * the database was built since the file was last modified,
+ * or there wasn't a search string, use the line number.
+ */
+ if (strcmp(*search, "<unknown>") == 0)
+ *search = NULL;
+
+ name = cs_resolve_file(cnumber, name);
+ return name;
+}
+
+#ifdef FEAT_QUICKFIX
+/*
+ * Write cscope find results to file.
+ */
+ static void
+cs_file_results(FILE *f, int *nummatches_a)
+{
+ int i, j;
+ char *buf;
+ char *search, *slno;
+ char *fullname;
+ char *cntx;
+ char *context;
+
+ buf = (char *)alloc(CSREAD_BUFSIZE);
+ if (buf == NULL)
+ return;
+
+ for (i = 0; i < csinfo_size; i++)
+ {
+ if (nummatches_a[i] < 1)
+ continue;
+
+ for (j = 0; j < nummatches_a[i]; j++)
+ {
+ if ((fullname = cs_parse_results(i, buf, CSREAD_BUFSIZE, &cntx,
+ &slno, &search)) == NULL)
+ continue;
+
+ context = (char *)alloc((unsigned)strlen(cntx)+5);
+ if (context == NULL)
+ continue;
+
+ if (strcmp(cntx, "<global>")==0)
+ strcpy(context, "<<global>>");
+ else
+ sprintf(context, "<<%s>>", cntx);
+
+ if (search == NULL)
+ fprintf(f, "%s\t%s\t%s\n", fullname, slno, context);
+ else
+ fprintf(f, "%s\t%s\t%s %s\n", fullname, slno, context, search);
+
+ vim_free(context);
+ vim_free(fullname);
+ } /* for all matches */
+
+ (void)cs_read_prompt(i);
+
+ } /* for all cscope connections */
+ vim_free(buf);
+}
+#endif
+
+/*
+ * Get parsed cscope output and calls cs_make_vim_style_matches to convert
+ * into ctags format.
+ * When there are no matches sets "*matches_p" to NULL.
+ */
+ static void
+cs_fill_results(
+ char *tagstr,
+ int totmatches,
+ int *nummatches_a,
+ char ***matches_p,
+ char ***cntxts_p,
+ int *matched)
+{
+ int i, j;
+ char *buf;
+ char *search, *slno;
+ int totsofar = 0;
+ char **matches = NULL;
+ char **cntxts = NULL;
+ char *fullname;
+ char *cntx;
+
+ assert(totmatches > 0);
+
+ buf = (char *)alloc(CSREAD_BUFSIZE);
+ if (buf == NULL)
+ return;
+
+ if ((matches = (char **)alloc(sizeof(char *) * totmatches)) == NULL)
+ goto parse_out;
+ if ((cntxts = (char **)alloc(sizeof(char *) * totmatches)) == NULL)
+ goto parse_out;
+
+ for (i = 0; i < csinfo_size; i++)
+ {
+ if (nummatches_a[i] < 1)
+ continue;
+
+ for (j = 0; j < nummatches_a[i]; j++)
+ {
+ if ((fullname = cs_parse_results(i, buf, CSREAD_BUFSIZE, &cntx,
+ &slno, &search)) == NULL)
+ continue;
+
+ matches[totsofar] = cs_make_vim_style_matches(fullname, slno,
+ search, tagstr);
+
+ vim_free(fullname);
+
+ if (strcmp(cntx, "<global>") == 0)
+ cntxts[totsofar] = NULL;
+ else
+ /* note: if vim_strsave returns NULL, then the context
+ * will be "<global>", which is misleading.
+ */
+ cntxts[totsofar] = (char *)vim_strsave((char_u *)cntx);
+
+ if (matches[totsofar] != NULL)
+ totsofar++;
+
+ } /* for all matches */
+
+ (void)cs_read_prompt(i);
+
+ } /* for all cscope connections */
+
+parse_out:
+ if (totsofar == 0)
+ {
+ /* No matches, free the arrays and return NULL in "*matches_p". */
+ VIM_CLEAR(matches);
+ VIM_CLEAR(cntxts);
+ }
+ *matched = totsofar;
+ *matches_p = matches;
+ *cntxts_p = cntxts;
+
+ vim_free(buf);
+} /* cs_fill_results */
+
+
+/* get the requested path components */
+ static char *
+cs_pathcomponents(char *path)
+{
+ int i;
+ char *s;
+
+ if (p_cspc == 0)
+ return path;
+
+ s = path + strlen(path) - 1;
+ for (i = 0; i < p_cspc; ++i)
+ while (s > path && *--s != '/'
+#ifdef WIN32
+ && *--s != '\\'
+#endif
+ )
+ ;
+ if ((s > path && *s == '/')
+#ifdef WIN32
+ || (s > path && *s == '\\')
+#endif
+ )
+ ++s;
+ return s;
+}
+
+/*
+ * Called from cs_manage_matches().
+ */
+ static void
+cs_print_tags_priv(char **matches, char **cntxts, int num_matches)
+{
+ char *buf = NULL;
+ char *t_buf;
+ int bufsize = 0; /* Track available bufsize */
+ int newsize = 0;
+ char *ptag;
+ char *fname, *lno, *extra, *tbuf;
+ int i, idx, num;
+ char *globalcntx = "GLOBAL";
+ char *cntxformat = " <<%s>>";
+ char *context;
+ char *cstag_msg = _("Cscope tag: %s");
+ char *csfmt_str = "%4d %6s ";
+
+ assert(num_matches > 0);
+
+ if ((tbuf = (char *)alloc((unsigned)strlen(matches[0]) + 1)) == NULL)
+ return;
+
+ strcpy(tbuf, matches[0]);
+ ptag = strtok(tbuf, "\t");
+ if (ptag == NULL)
+ {
+ vim_free(tbuf);
+ return;
+ }
+
+ newsize = (int)(strlen(cstag_msg) + strlen(ptag));
+ buf = (char *)alloc(newsize);
+ if (buf != NULL)
+ {
+ bufsize = newsize;
+ (void)sprintf(buf, cstag_msg, ptag);
+ msg_puts_attr(buf, HL_ATTR(HLF_T));
+ }
+
+ vim_free(tbuf);
+
+ msg_puts_attr(_("\n # line"), HL_ATTR(HLF_T)); /* strlen is 7 */
+ msg_advance(msg_col + 2);
+ msg_puts_attr(_("filename / context / line\n"), HL_ATTR(HLF_T));
+
+ num = 1;
+ for (i = 0; i < num_matches; i++)
+ {
+ idx = i;
+
+ /* if we really wanted to, we could avoid this malloc and strcpy
+ * by parsing matches[i] on the fly and placing stuff into buf
+ * directly, but that's too much of a hassle
+ */
+ if ((tbuf = (char *)alloc((unsigned)strlen(matches[idx]) + 1)) == NULL)
+ continue;
+ (void)strcpy(tbuf, matches[idx]);
+
+ if (strtok(tbuf, (const char *)"\t") == NULL
+ || (fname = strtok(NULL, (const char *)"\t")) == NULL
+ || (lno = strtok(NULL, (const char *)"\t")) == NULL)
+ {
+ vim_free(tbuf);
+ continue;
+ }
+ extra = strtok(NULL, (const char *)"\t");
+
+ lno[strlen(lno)-2] = '\0'; /* ignore ;" at the end */
+
+ /* hopefully 'num' (num of matches) will be less than 10^16 */
+ newsize = (int)(strlen(csfmt_str) + 16 + strlen(lno));
+ if (bufsize < newsize)
+ {
+ t_buf = buf;
+ buf = (char *)vim_realloc(buf, newsize);
+ if (buf == NULL)
+ {
+ bufsize = 0;
+ vim_free(t_buf);
+ }
+ else
+ bufsize = newsize;
+ }
+ if (buf != NULL)
+ {
+ /* csfmt_str = "%4d %6s "; */
+ (void)sprintf(buf, csfmt_str, num, lno);
+ msg_puts_attr(buf, HL_ATTR(HLF_CM));
+ }
+ msg_outtrans_long_attr((char_u *)cs_pathcomponents(fname),
+ HL_ATTR(HLF_CM));
+
+ /* compute the required space for the context */
+ if (cntxts[idx] != NULL)
+ context = cntxts[idx];
+ else
+ context = globalcntx;
+ newsize = (int)(strlen(context) + strlen(cntxformat));
+
+ if (bufsize < newsize)
+ {
+ t_buf = buf;
+ buf = (char *)vim_realloc(buf, newsize);
+ if (buf == NULL)
+ {
+ bufsize = 0;
+ vim_free(t_buf);
+ }
+ else
+ bufsize = newsize;
+ }
+ if (buf != NULL)
+ {
+ (void)sprintf(buf, cntxformat, context);
+
+ /* print the context only if it fits on the same line */
+ if (msg_col + (int)strlen(buf) >= (int)Columns)
+ msg_putchar('\n');
+ msg_advance(12);
+ msg_outtrans_long_attr((char_u *)buf, 0);
+ msg_putchar('\n');
+ }
+ if (extra != NULL)
+ {
+ msg_advance(13);
+ msg_outtrans_long_attr((char_u *)extra, 0);
+ }
+
+ vim_free(tbuf); /* only after printing extra due to strtok use */
+
+ if (msg_col)
+ msg_putchar('\n');
+
+ ui_breakcheck();
+ if (got_int)
+ {
+ got_int = FALSE; /* don't print any more matches */
+ break;
+ }
+
+ num++;
+ } /* for all matches */
+
+ vim_free(buf);
+} /* cs_print_tags_priv */
+
+
+/*
+ * Read a cscope prompt (basically, skip over the ">> ").
+ */
+ static int
+cs_read_prompt(int i)
+{
+ int ch;
+ char *buf = NULL; /* buffer for possible error message from cscope */
+ int bufpos = 0;
+ char *cs_emsg;
+ int maxlen;
+ static char *eprompt = "Press the RETURN key to continue:";
+ int epromptlen = (int)strlen(eprompt);
+ int n;
+
+ cs_emsg = _("E609: Cscope error: %s");
+ /* compute maximum allowed len for Cscope error message */
+ maxlen = (int)(IOSIZE - strlen(cs_emsg));
+
+ for (;;)
+ {
+ while ((ch = getc(csinfo[i].fr_fp)) != EOF && ch != CSCOPE_PROMPT[0])
+ /* if there is room and char is printable */
+ if (bufpos < maxlen - 1 && vim_isprintc(ch))
+ {
+ if (buf == NULL) /* lazy buffer allocation */
+ buf = (char *)alloc(maxlen);
+ if (buf != NULL)
+ {
+ /* append character to the message */
+ buf[bufpos++] = ch;
+ buf[bufpos] = NUL;
+ if (bufpos >= epromptlen
+ && strcmp(&buf[bufpos - epromptlen], eprompt) == 0)
+ {
+ /* remove eprompt from buf */
+ buf[bufpos - epromptlen] = NUL;
+
+ /* print message to user */
+ (void)semsg(cs_emsg, buf);
+
+ /* send RETURN to cscope */
+ (void)putc('\n', csinfo[i].to_fp);
+ (void)fflush(csinfo[i].to_fp);
+
+ /* clear buf */
+ bufpos = 0;
+ buf[bufpos] = NUL;
+ }
+ }
+ }
+
+ for (n = 0; n < (int)strlen(CSCOPE_PROMPT); ++n)
+ {
+ if (n > 0)
+ ch = getc(csinfo[i].fr_fp);
+ if (ch == EOF)
+ {
+ PERROR("cs_read_prompt EOF");
+ if (buf != NULL && buf[0] != NUL)
+ (void)semsg(cs_emsg, buf);
+ else if (p_csverbose)
+ cs_reading_emsg(i); /* don't have additional information */
+ cs_release_csp(i, TRUE);
+ vim_free(buf);
+ return CSCOPE_FAILURE;
+ }
+
+ if (ch != CSCOPE_PROMPT[n])
+ {
+ ch = EOF;
+ break;
+ }
+ }
+
+ if (ch == EOF)
+ continue; /* didn't find the prompt */
+ break; /* did find the prompt */
+ }
+
+ vim_free(buf);
+ return CSCOPE_SUCCESS;
+}
+
+#if defined(UNIX) && defined(SIGALRM)
+/*
+ * Used to catch and ignore SIGALRM below.
+ */
+ static RETSIGTYPE
+sig_handler SIGDEFARG(sigarg)
+{
+ /* do nothing */
+ SIGRETURN;
+}
+#endif
+
+/*
+ * Does the actual free'ing for the cs ptr with an optional flag of whether
+ * or not to free the filename. Called by cs_kill and cs_reset.
+ */
+ static void
+cs_release_csp(int i, int freefnpp)
+{
+ /*
+ * Trying to exit normally (not sure whether it is fit to UNIX cscope
+ */
+ if (csinfo[i].to_fp != NULL)
+ {
+ (void)fputs("q\n", csinfo[i].to_fp);
+ (void)fflush(csinfo[i].to_fp);
+ }
+#if defined(UNIX)
+ {
+ int waitpid_errno;
+ int pstat;
+ pid_t pid;
+
+# if defined(HAVE_SIGACTION)
+ struct sigaction sa, old;
+
+ /* Use sigaction() to limit the waiting time to two seconds. */
+ sigemptyset(&sa.sa_mask);
+ sa.sa_handler = sig_handler;
+# ifdef SA_NODEFER
+ sa.sa_flags = SA_NODEFER;
+# else
+ sa.sa_flags = 0;
+# endif
+ sigaction(SIGALRM, &sa, &old);
+ alarm(2); /* 2 sec timeout */
+
+ /* Block until cscope exits or until timer expires */
+ pid = waitpid(csinfo[i].pid, &pstat, 0);
+ waitpid_errno = errno;
+
+ /* cancel pending alarm if still there and restore signal */
+ alarm(0);
+ sigaction(SIGALRM, &old, NULL);
+# else
+ int waited;
+
+ /* Can't use sigaction(), loop for two seconds. First yield the CPU
+ * to give cscope a chance to exit quickly. */
+ sleep(0);
+ for (waited = 0; waited < 40; ++waited)
+ {
+ pid = waitpid(csinfo[i].pid, &pstat, WNOHANG);
+ waitpid_errno = errno;
+ if (pid != 0)
+ break; /* break unless the process is still running */
+ mch_delay(50L, FALSE); /* sleep 50 ms */
+ }
+# endif
+ /*
+ * If the cscope process is still running: kill it.
+ * Safety check: If the PID would be zero here, the entire X session
+ * would be killed. -1 and 1 are dangerous as well.
+ */
+ if (pid < 0 && csinfo[i].pid > 1)
+ {
+# ifdef ECHILD
+ int alive = TRUE;
+
+ if (waitpid_errno == ECHILD)
+ {
+ /*
+ * When using 'vim -g', vim is forked and cscope process is
+ * no longer a child process but a sibling. So waitpid()
+ * fails with errno being ECHILD (No child processes).
+ * Don't send SIGKILL to cscope immediately but wait
+ * (polling) for it to exit normally as result of sending
+ * the "q" command, hence giving it a chance to clean up
+ * its temporary files.
+ */
+ int waited;
+
+ sleep(0);
+ for (waited = 0; waited < 40; ++waited)
+ {
+ /* Check whether cscope process is still alive */
+ if (kill(csinfo[i].pid, 0) != 0)
+ {
+ alive = FALSE; /* cscope process no longer exists */
+ break;
+ }
+ mch_delay(50L, FALSE); /* sleep 50ms */
+ }
+ }
+ if (alive)
+# endif
+ {
+ kill(csinfo[i].pid, SIGKILL);
+ (void)waitpid(csinfo[i].pid, &pstat, 0);
+ }
+ }
+ }
+#else /* !UNIX */
+ if (csinfo[i].hProc != NULL)
+ {
+ /* Give cscope a chance to exit normally */
+ if (WaitForSingleObject(csinfo[i].hProc, 1000) == WAIT_TIMEOUT)
+ TerminateProcess(csinfo[i].hProc, 0);
+ CloseHandle(csinfo[i].hProc);
+ }
+#endif
+
+ if (csinfo[i].fr_fp != NULL)
+ (void)fclose(csinfo[i].fr_fp);
+ if (csinfo[i].to_fp != NULL)
+ (void)fclose(csinfo[i].to_fp);
+
+ if (freefnpp)
+ {
+ vim_free(csinfo[i].fname);
+ vim_free(csinfo[i].ppath);
+ vim_free(csinfo[i].flags);
+ }
+
+ clear_csinfo(i);
+} /* cs_release_csp */
+
+
+/*
+ * Calls cs_kill on all cscope connections then reinits.
+ */
+ static int
+cs_reset(exarg_T *eap UNUSED)
+{
+ char **dblist = NULL, **pplist = NULL, **fllist = NULL;
+ int i;
+ char buf[20]; /* for sprintf " (#%d)" */
+
+ if (csinfo_size == 0)
+ return CSCOPE_SUCCESS;
+
+ /* malloc our db and ppath list */
+ dblist = (char **)alloc(csinfo_size * sizeof(char *));
+ pplist = (char **)alloc(csinfo_size * sizeof(char *));
+ fllist = (char **)alloc(csinfo_size * sizeof(char *));
+ if (dblist == NULL || pplist == NULL || fllist == NULL)
+ {
+ vim_free(dblist);
+ vim_free(pplist);
+ vim_free(fllist);
+ return CSCOPE_FAILURE;
+ }
+
+ for (i = 0; i < csinfo_size; i++)
+ {
+ dblist[i] = csinfo[i].fname;
+ pplist[i] = csinfo[i].ppath;
+ fllist[i] = csinfo[i].flags;
+ if (csinfo[i].fname != NULL)
+ cs_release_csp(i, FALSE);
+ }
+
+ /* rebuild the cscope connection list */
+ for (i = 0; i < csinfo_size; i++)
+ {
+ if (dblist[i] != NULL)
+ {
+ cs_add_common(dblist[i], pplist[i], fllist[i]);
+ if (p_csverbose)
+ {
+ /* don't use smsg_attr() because we want to display the
+ * connection number in the same line as
+ * "Added cscope database..."
+ */
+ sprintf(buf, " (#%d)", i);
+ msg_puts_attr(buf, HL_ATTR(HLF_R));
+ }
+ }
+ vim_free(dblist[i]);
+ vim_free(pplist[i]);
+ vim_free(fllist[i]);
+ }
+ vim_free(dblist);
+ vim_free(pplist);
+ vim_free(fllist);
+
+ if (p_csverbose)
+ msg_attr(_("All cscope databases reset"), HL_ATTR(HLF_R) | MSG_HIST);
+ return CSCOPE_SUCCESS;
+} /* cs_reset */
+
+
+/*
+ * Construct the full pathname to a file found in the cscope database.
+ * (Prepends ppath, if there is one and if it's not already prepended,
+ * otherwise just uses the name found.)
+ *
+ * We need to prepend the prefix because on some cscope's (e.g., the one that
+ * ships with Solaris 2.6), the output never has the prefix prepended.
+ * Contrast this with my development system (Digital Unix), which does.
+ */
+ static char *
+cs_resolve_file(int i, char *name)
+{
+ char *fullname;
+ int len;
+ char_u *csdir = NULL;
+
+ /*
+ * Ppath is freed when we destroy the cscope connection.
+ * Fullname is freed after cs_make_vim_style_matches, after it's been
+ * copied into the tag buffer used by Vim.
+ */
+ len = (int)(strlen(name) + 2);
+ if (csinfo[i].ppath != NULL)
+ len += (int)strlen(csinfo[i].ppath);
+ else if (p_csre && csinfo[i].fname != NULL)
+ {
+ /* If 'cscoperelative' is set and ppath is not set, use cscope.out
+ * path in path resolution. */
+ csdir = alloc(MAXPATHL);
+ if (csdir != NULL)
+ {
+ vim_strncpy(csdir, (char_u *)csinfo[i].fname,
+ gettail((char_u *)csinfo[i].fname)
+ - (char_u *)csinfo[i].fname);
+ len += (int)STRLEN(csdir);
+ }
+ }
+
+ /* Note/example: this won't work if the cscope output already starts
+ * "../.." and the prefix path is also "../..". if something like this
+ * happens, you are screwed up and need to fix how you're using cscope. */
+ if (csinfo[i].ppath != NULL
+ && (strncmp(name, csinfo[i].ppath, strlen(csinfo[i].ppath)) != 0)
+ && (name[0] != '/')
+#ifdef WIN32
+ && name[0] != '\\' && name[1] != ':'
+#endif
+ )
+ {
+ if ((fullname = (char *)alloc(len)) != NULL)
+ (void)sprintf(fullname, "%s/%s", csinfo[i].ppath, name);
+ }
+ else if (csdir != NULL && csinfo[i].fname != NULL && *csdir != NUL)
+ {
+ /* Check for csdir to be non empty to avoid empty path concatenated to
+ * cscope output. */
+ fullname = (char *)concat_fnames(csdir, (char_u *)name, TRUE);
+ }
+ else
+ {
+ fullname = (char *)vim_strsave((char_u *)name);
+ }
+
+ vim_free(csdir);
+ return fullname;
+}
+
+
+/*
+ * Show all cscope connections.
+ */
+ static int
+cs_show(exarg_T *eap UNUSED)
+{
+ short i;
+ if (cs_cnt_connections() == 0)
+ msg_puts(_("no cscope connections\n"));
+ else
+ {
+ msg_puts_attr(
+ _(" # pid database name prepend path\n"),
+ HL_ATTR(HLF_T));
+ for (i = 0; i < csinfo_size; i++)
+ {
+ if (csinfo[i].fname == NULL)
+ continue;
+
+ if (csinfo[i].ppath != NULL)
+ (void)smsg("%2d %-5ld %-34s %-32s",
+ i, (long)csinfo[i].pid, csinfo[i].fname, csinfo[i].ppath);
+ else
+ (void)smsg("%2d %-5ld %-34s <none>",
+ i, (long)csinfo[i].pid, csinfo[i].fname);
+ }
+ }
+
+ wait_return(TRUE);
+ return CSCOPE_SUCCESS;
+} /* cs_show */
+
+
+/*
+ * Only called when VIM exits to quit any cscope sessions.
+ */
+ void
+cs_end(void)
+{
+ int i;
+
+ for (i = 0; i < csinfo_size; i++)
+ cs_release_csp(i, TRUE);
+ vim_free(csinfo);
+ csinfo_size = 0;
+}
+
+#endif /* FEAT_CSCOPE */
+
+/* the end */
diff --git a/src/if_cscope.h b/src/if_cscope.h
new file mode 100644
index 0000000..419c469
--- /dev/null
+++ b/src/if_cscope.h
@@ -0,0 +1,73 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * CSCOPE support for Vim added by Andy Kahn <kahn@zk3.dec.com>
+ * Ported to Win32 by Sergey Khorev <sergey.khorev@gmail.com>
+ *
+ * The basic idea/structure of cscope for Vim was borrowed from Nvi.
+ * There might be a few lines of code that look similar to what Nvi
+ * has. If this is a problem and requires inclusion of the annoying
+ * BSD license, then sue me; I'm not worth much anyway.
+ */
+
+#if defined(FEAT_CSCOPE) || defined(PROTO)
+
+#if defined (WIN32)
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+# endif
+# include <windows.h>
+#endif
+
+#define CSCOPE_SUCCESS 0
+#define CSCOPE_FAILURE -1
+
+#define CSCOPE_DBFILE "cscope.out"
+#define CSCOPE_PROMPT ">> "
+
+/*
+ * See ":help cscope-find" for the possible queries.
+ */
+
+typedef struct {
+ char * name;
+ int (*func)(exarg_T *eap);
+ char * help;
+ char * usage;
+ int cansplit; /* if supports splitting window */
+} cscmd_T;
+
+typedef struct csi {
+ char * fname; /* cscope db name */
+ char * ppath; /* path to prepend (the -P option) */
+ char * flags; /* additional cscope flags/options (e.g, -p2) */
+#if defined(UNIX)
+ pid_t pid; /* PID of the connected cscope process. */
+ dev_t st_dev; /* ID of dev containing cscope db */
+ ino_t st_ino; /* inode number of cscope db */
+#else
+# if defined(WIN32)
+ DWORD pid; /* PID of the connected cscope process. */
+ HANDLE hProc; /* cscope process handle */
+ DWORD nVolume; /* Volume serial number, instead of st_dev */
+ DWORD nIndexHigh; /* st_ino has no meaning in the Windows */
+ DWORD nIndexLow;
+# endif
+#endif
+
+ FILE * fr_fp; /* from cscope: FILE. */
+ FILE * to_fp; /* to cscope: FILE. */
+} csinfo_T;
+
+typedef enum { Add, Find, Help, Kill, Reset, Show } csid_e;
+
+typedef enum {
+ Store,
+ Get,
+ Free,
+ Print
+} mcmd_e;
+
+
+#endif /* FEAT_CSCOPE */
+
+/* the end */
diff --git a/src/if_lua.c b/src/if_lua.c
new file mode 100644
index 0000000..e650e5e
--- /dev/null
+++ b/src/if_lua.c
@@ -0,0 +1,2088 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * Lua interface by Luis Carvalho
+ *
+ * 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.
+ */
+
+#include "vim.h"
+
+#include <lua.h>
+#include <lualib.h>
+#include <lauxlib.h>
+
+/* Only do the following when the feature is enabled. Needed for "make
+ * depend". */
+#if defined(FEAT_LUA) || defined(PROTO)
+
+#define LUAVIM_CHUNKNAME "vim chunk"
+#define LUAVIM_NAME "vim"
+#define LUAVIM_EVALNAME "luaeval"
+#define LUAVIM_EVALHEADER "local _A=select(1,...) return "
+
+typedef buf_T *luaV_Buffer;
+typedef win_T *luaV_Window;
+typedef dict_T *luaV_Dict;
+typedef list_T *luaV_List;
+typedef struct {
+ typval_T tv; // funcref
+ typval_T args;
+ dict_T *self; // selfdict
+} luaV_Funcref;
+typedef void (*msgfunc_T)(char_u *);
+
+static const char LUAVIM_DICT[] = "dict";
+static const char LUAVIM_LIST[] = "list";
+static const char LUAVIM_FUNCREF[] = "funcref";
+static const char LUAVIM_BUFFER[] = "buffer";
+static const char LUAVIM_WINDOW[] = "window";
+static const char LUAVIM_FREE[] = "luaV_free";
+static const char LUAVIM_LUAEVAL[] = "luaV_luaeval";
+static const char LUAVIM_SETREF[] = "luaV_setref";
+
+/* most functions are closures with a cache table as first upvalue;
+ * get/setudata manage references to vim userdata in cache table through
+ * object pointers (light userdata) */
+#define luaV_getudata(L, v) \
+ lua_pushlightuserdata((L), (void *) (v)); \
+ lua_rawget((L), lua_upvalueindex(1))
+#define luaV_setudata(L, v) \
+ lua_pushlightuserdata((L), (void *) (v)); \
+ lua_pushvalue((L), -2); \
+ lua_rawset((L), lua_upvalueindex(1))
+#define luaV_getfield(L, s) \
+ lua_pushlightuserdata((L), (void *)(s)); \
+ lua_rawget((L), LUA_REGISTRYINDEX)
+#define luaV_checksandbox(L) \
+ if (sandbox) luaL_error((L), "not allowed in sandbox")
+#define luaV_msg(L) luaV_msgfunc((L), (msgfunc_T) msg)
+#define luaV_emsg(L) luaV_msgfunc((L), (msgfunc_T) emsg)
+#define luaV_checktypval(L, a, v, msg) \
+ do { \
+ if (luaV_totypval(L, a, v) == FAIL) \
+ luaL_error(L, msg ": cannot convert value"); \
+ } while (0)
+
+static luaV_List *luaV_pushlist(lua_State *L, list_T *lis);
+static luaV_Dict *luaV_pushdict(lua_State *L, dict_T *dic);
+static luaV_Funcref *luaV_pushfuncref(lua_State *L, typval_T *tv);
+
+#if LUA_VERSION_NUM <= 501
+#define luaV_openlib(L, l, n) luaL_openlib(L, NULL, l, n)
+#define luaL_typeerror luaL_typerror
+#else
+#define luaV_openlib luaL_setfuncs
+#endif
+
+#ifdef DYNAMIC_LUA
+
+#ifndef WIN3264
+# include <dlfcn.h>
+# define HANDLE void*
+# define load_dll(n) dlopen((n), RTLD_LAZY|RTLD_GLOBAL)
+# define symbol_from_dll dlsym
+# define close_dll dlclose
+#else
+# define load_dll vimLoadLib
+# define symbol_from_dll GetProcAddress
+# define close_dll FreeLibrary
+#endif
+
+/* lauxlib */
+#if LUA_VERSION_NUM <= 501
+#define luaL_register dll_luaL_register
+#define luaL_prepbuffer dll_luaL_prepbuffer
+#define luaL_openlib dll_luaL_openlib
+#define luaL_typerror dll_luaL_typerror
+#define luaL_loadfile dll_luaL_loadfile
+#define luaL_loadbuffer dll_luaL_loadbuffer
+#else
+#define luaL_prepbuffsize dll_luaL_prepbuffsize
+#define luaL_setfuncs dll_luaL_setfuncs
+#define luaL_loadfilex dll_luaL_loadfilex
+#define luaL_loadbufferx dll_luaL_loadbufferx
+#define luaL_argerror dll_luaL_argerror
+#endif
+#define luaL_checkany dll_luaL_checkany
+#define luaL_checklstring dll_luaL_checklstring
+#define luaL_checkinteger dll_luaL_checkinteger
+#define luaL_optinteger dll_luaL_optinteger
+#define luaL_checktype dll_luaL_checktype
+#define luaL_error dll_luaL_error
+#define luaL_newstate dll_luaL_newstate
+#define luaL_buffinit dll_luaL_buffinit
+#define luaL_addlstring dll_luaL_addlstring
+#define luaL_pushresult dll_luaL_pushresult
+/* lua */
+#if LUA_VERSION_NUM <= 501
+#define lua_tonumber dll_lua_tonumber
+#define lua_tointeger dll_lua_tointeger
+#define lua_call dll_lua_call
+#define lua_pcall dll_lua_pcall
+#else
+#define lua_tonumberx dll_lua_tonumberx
+#define lua_tointegerx dll_lua_tointegerx
+#define lua_callk dll_lua_callk
+#define lua_pcallk dll_lua_pcallk
+#define lua_getglobal dll_lua_getglobal
+#define lua_setglobal dll_lua_setglobal
+#endif
+#if LUA_VERSION_NUM <= 502
+#define lua_replace dll_lua_replace
+#define lua_remove dll_lua_remove
+#endif
+#if LUA_VERSION_NUM >= 503
+#define lua_rotate dll_lua_rotate
+#define lua_copy dll_lua_copy
+#endif
+#define lua_typename dll_lua_typename
+#define lua_close dll_lua_close
+#define lua_gettop dll_lua_gettop
+#define lua_settop dll_lua_settop
+#define lua_pushvalue dll_lua_pushvalue
+#define lua_isnumber dll_lua_isnumber
+#define lua_isstring dll_lua_isstring
+#define lua_type dll_lua_type
+#define lua_rawequal dll_lua_rawequal
+#define lua_toboolean dll_lua_toboolean
+#define lua_tolstring dll_lua_tolstring
+#define lua_touserdata dll_lua_touserdata
+#define lua_pushnil dll_lua_pushnil
+#define lua_pushnumber dll_lua_pushnumber
+#define lua_pushinteger dll_lua_pushinteger
+#define lua_pushlstring dll_lua_pushlstring
+#define lua_pushstring dll_lua_pushstring
+#define lua_pushfstring dll_lua_pushfstring
+#define lua_pushcclosure dll_lua_pushcclosure
+#define lua_pushboolean dll_lua_pushboolean
+#define lua_pushlightuserdata dll_lua_pushlightuserdata
+#define lua_getfield dll_lua_getfield
+#define lua_rawget dll_lua_rawget
+#define lua_rawgeti dll_lua_rawgeti
+#define lua_createtable dll_lua_createtable
+#if LUA_VERSION_NUM >= 504
+ #define lua_newuserdatauv dll_lua_newuserdatauv
+#else
+ #define lua_newuserdata dll_lua_newuserdata
+#endif
+#define lua_getmetatable dll_lua_getmetatable
+#define lua_setfield dll_lua_setfield
+#define lua_rawset dll_lua_rawset
+#define lua_rawseti dll_lua_rawseti
+#define lua_setmetatable dll_lua_setmetatable
+#define lua_next dll_lua_next
+/* libs */
+#define luaopen_base dll_luaopen_base
+#define luaopen_table dll_luaopen_table
+#define luaopen_string dll_luaopen_string
+#define luaopen_math dll_luaopen_math
+#define luaopen_io dll_luaopen_io
+#define luaopen_os dll_luaopen_os
+#define luaopen_package dll_luaopen_package
+#define luaopen_debug dll_luaopen_debug
+#define luaL_openlibs dll_luaL_openlibs
+
+/* lauxlib */
+#if LUA_VERSION_NUM <= 501
+void (*dll_luaL_register) (lua_State *L, const char *libname, const luaL_Reg *l);
+char *(*dll_luaL_prepbuffer) (luaL_Buffer *B);
+void (*dll_luaL_openlib) (lua_State *L, const char *libname, const luaL_Reg *l, int nup);
+int (*dll_luaL_typerror) (lua_State *L, int narg, const char *tname);
+int (*dll_luaL_loadfile) (lua_State *L, const char *filename);
+int (*dll_luaL_loadbuffer) (lua_State *L, const char *buff, size_t sz, const char *name);
+#else
+char *(*dll_luaL_prepbuffsize) (luaL_Buffer *B, size_t sz);
+void (*dll_luaL_setfuncs) (lua_State *L, const luaL_Reg *l, int nup);
+int (*dll_luaL_loadfilex) (lua_State *L, const char *filename, const char *mode);
+int (*dll_luaL_loadbufferx) (lua_State *L, const char *buff, size_t sz, const char *name, const char *mode);
+int (*dll_luaL_argerror) (lua_State *L, int numarg, const char *extramsg);
+#endif
+void (*dll_luaL_checkany) (lua_State *L, int narg);
+const char *(*dll_luaL_checklstring) (lua_State *L, int numArg, size_t *l);
+lua_Integer (*dll_luaL_checkinteger) (lua_State *L, int numArg);
+lua_Integer (*dll_luaL_optinteger) (lua_State *L, int nArg, lua_Integer def);
+void (*dll_luaL_checktype) (lua_State *L, int narg, int t);
+int (*dll_luaL_error) (lua_State *L, const char *fmt, ...);
+lua_State *(*dll_luaL_newstate) (void);
+void (*dll_luaL_buffinit) (lua_State *L, luaL_Buffer *B);
+void (*dll_luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l);
+void (*dll_luaL_pushresult) (luaL_Buffer *B);
+/* lua */
+#if LUA_VERSION_NUM <= 501
+lua_Number (*dll_lua_tonumber) (lua_State *L, int idx);
+lua_Integer (*dll_lua_tointeger) (lua_State *L, int idx);
+void (*dll_lua_call) (lua_State *L, int nargs, int nresults);
+int (*dll_lua_pcall) (lua_State *L, int nargs, int nresults, int errfunc);
+#else
+lua_Number (*dll_lua_tonumberx) (lua_State *L, int idx, int *isnum);
+lua_Integer (*dll_lua_tointegerx) (lua_State *L, int idx, int *isnum);
+void (*dll_lua_callk) (lua_State *L, int nargs, int nresults, int ctx,
+ lua_CFunction k);
+int (*dll_lua_pcallk) (lua_State *L, int nargs, int nresults, int errfunc,
+ int ctx, lua_CFunction k);
+void (*dll_lua_getglobal) (lua_State *L, const char *var);
+void (*dll_lua_setglobal) (lua_State *L, const char *var);
+#endif
+#if LUA_VERSION_NUM <= 502
+void (*dll_lua_replace) (lua_State *L, int idx);
+void (*dll_lua_remove) (lua_State *L, int idx);
+#endif
+#if LUA_VERSION_NUM >= 503
+void (*dll_lua_rotate) (lua_State *L, int idx, int n);
+void (*dll_lua_copy) (lua_State *L, int fromidx, int toidx);
+#endif
+const char *(*dll_lua_typename) (lua_State *L, int tp);
+void (*dll_lua_close) (lua_State *L);
+int (*dll_lua_gettop) (lua_State *L);
+void (*dll_lua_settop) (lua_State *L, int idx);
+void (*dll_lua_pushvalue) (lua_State *L, int idx);
+int (*dll_lua_isnumber) (lua_State *L, int idx);
+int (*dll_lua_isstring) (lua_State *L, int idx);
+int (*dll_lua_type) (lua_State *L, int idx);
+int (*dll_lua_rawequal) (lua_State *L, int idx1, int idx2);
+int (*dll_lua_toboolean) (lua_State *L, int idx);
+const char *(*dll_lua_tolstring) (lua_State *L, int idx, size_t *len);
+void *(*dll_lua_touserdata) (lua_State *L, int idx);
+void (*dll_lua_pushnil) (lua_State *L);
+void (*dll_lua_pushnumber) (lua_State *L, lua_Number n);
+void (*dll_lua_pushinteger) (lua_State *L, lua_Integer n);
+void (*dll_lua_pushlstring) (lua_State *L, const char *s, size_t l);
+void (*dll_lua_pushstring) (lua_State *L, const char *s);
+const char *(*dll_lua_pushfstring) (lua_State *L, const char *fmt, ...);
+void (*dll_lua_pushcclosure) (lua_State *L, lua_CFunction fn, int n);
+void (*dll_lua_pushboolean) (lua_State *L, int b);
+void (*dll_lua_pushlightuserdata) (lua_State *L, void *p);
+void (*dll_lua_getfield) (lua_State *L, int idx, const char *k);
+#if LUA_VERSION_NUM <= 502
+void (*dll_lua_rawget) (lua_State *L, int idx);
+void (*dll_lua_rawgeti) (lua_State *L, int idx, int n);
+#else
+int (*dll_lua_rawget) (lua_State *L, int idx);
+int (*dll_lua_rawgeti) (lua_State *L, int idx, lua_Integer n);
+#endif
+void (*dll_lua_createtable) (lua_State *L, int narr, int nrec);
+#if LUA_VERSION_NUM >= 504
+void *(*dll_lua_newuserdatauv) (lua_State *L, size_t sz, int nuvalue);
+#else
+void *(*dll_lua_newuserdata) (lua_State *L, size_t sz);
+#endif
+int (*dll_lua_getmetatable) (lua_State *L, int objindex);
+void (*dll_lua_setfield) (lua_State *L, int idx, const char *k);
+void (*dll_lua_rawset) (lua_State *L, int idx);
+#if LUA_VERSION_NUM <= 502
+void (*dll_lua_rawseti) (lua_State *L, int idx, int n);
+#else
+void (*dll_lua_rawseti) (lua_State *L, int idx, lua_Integer n);
+#endif
+int (*dll_lua_setmetatable) (lua_State *L, int objindex);
+int (*dll_lua_next) (lua_State *L, int idx);
+/* libs */
+int (*dll_luaopen_base) (lua_State *L);
+int (*dll_luaopen_table) (lua_State *L);
+int (*dll_luaopen_string) (lua_State *L);
+int (*dll_luaopen_math) (lua_State *L);
+int (*dll_luaopen_io) (lua_State *L);
+int (*dll_luaopen_os) (lua_State *L);
+int (*dll_luaopen_package) (lua_State *L);
+int (*dll_luaopen_debug) (lua_State *L);
+void (*dll_luaL_openlibs) (lua_State *L);
+
+typedef void **luaV_function;
+typedef struct {
+ const char *name;
+ luaV_function func;
+} luaV_Reg;
+
+static const luaV_Reg luaV_dll[] = {
+ /* lauxlib */
+#if LUA_VERSION_NUM <= 501
+ {"luaL_register", (luaV_function) &dll_luaL_register},
+ {"luaL_prepbuffer", (luaV_function) &dll_luaL_prepbuffer},
+ {"luaL_openlib", (luaV_function) &dll_luaL_openlib},
+ {"luaL_typerror", (luaV_function) &dll_luaL_typerror},
+ {"luaL_loadfile", (luaV_function) &dll_luaL_loadfile},
+ {"luaL_loadbuffer", (luaV_function) &dll_luaL_loadbuffer},
+#else
+ {"luaL_prepbuffsize", (luaV_function) &dll_luaL_prepbuffsize},
+ {"luaL_setfuncs", (luaV_function) &dll_luaL_setfuncs},
+ {"luaL_loadfilex", (luaV_function) &dll_luaL_loadfilex},
+ {"luaL_loadbufferx", (luaV_function) &dll_luaL_loadbufferx},
+ {"luaL_argerror", (luaV_function) &dll_luaL_argerror},
+#endif
+ {"luaL_checkany", (luaV_function) &dll_luaL_checkany},
+ {"luaL_checklstring", (luaV_function) &dll_luaL_checklstring},
+ {"luaL_checkinteger", (luaV_function) &dll_luaL_checkinteger},
+ {"luaL_optinteger", (luaV_function) &dll_luaL_optinteger},
+ {"luaL_checktype", (luaV_function) &dll_luaL_checktype},
+ {"luaL_error", (luaV_function) &dll_luaL_error},
+ {"luaL_newstate", (luaV_function) &dll_luaL_newstate},
+ {"luaL_buffinit", (luaV_function) &dll_luaL_buffinit},
+ {"luaL_addlstring", (luaV_function) &dll_luaL_addlstring},
+ {"luaL_pushresult", (luaV_function) &dll_luaL_pushresult},
+ /* lua */
+#if LUA_VERSION_NUM <= 501
+ {"lua_tonumber", (luaV_function) &dll_lua_tonumber},
+ {"lua_tointeger", (luaV_function) &dll_lua_tointeger},
+ {"lua_call", (luaV_function) &dll_lua_call},
+ {"lua_pcall", (luaV_function) &dll_lua_pcall},
+#else
+ {"lua_tonumberx", (luaV_function) &dll_lua_tonumberx},
+ {"lua_tointegerx", (luaV_function) &dll_lua_tointegerx},
+ {"lua_callk", (luaV_function) &dll_lua_callk},
+ {"lua_pcallk", (luaV_function) &dll_lua_pcallk},
+ {"lua_getglobal", (luaV_function) &dll_lua_getglobal},
+ {"lua_setglobal", (luaV_function) &dll_lua_setglobal},
+#endif
+#if LUA_VERSION_NUM <= 502
+ {"lua_replace", (luaV_function) &dll_lua_replace},
+ {"lua_remove", (luaV_function) &dll_lua_remove},
+#endif
+#if LUA_VERSION_NUM >= 503
+ {"lua_rotate", (luaV_function) &dll_lua_rotate},
+ {"lua_copy", (luaV_function) &dll_lua_copy},
+#endif
+ {"lua_typename", (luaV_function) &dll_lua_typename},
+ {"lua_close", (luaV_function) &dll_lua_close},
+ {"lua_gettop", (luaV_function) &dll_lua_gettop},
+ {"lua_settop", (luaV_function) &dll_lua_settop},
+ {"lua_pushvalue", (luaV_function) &dll_lua_pushvalue},
+ {"lua_isnumber", (luaV_function) &dll_lua_isnumber},
+ {"lua_isstring", (luaV_function) &dll_lua_isstring},
+ {"lua_type", (luaV_function) &dll_lua_type},
+ {"lua_rawequal", (luaV_function) &dll_lua_rawequal},
+ {"lua_toboolean", (luaV_function) &dll_lua_toboolean},
+ {"lua_tolstring", (luaV_function) &dll_lua_tolstring},
+ {"lua_touserdata", (luaV_function) &dll_lua_touserdata},
+ {"lua_pushnil", (luaV_function) &dll_lua_pushnil},
+ {"lua_pushnumber", (luaV_function) &dll_lua_pushnumber},
+ {"lua_pushinteger", (luaV_function) &dll_lua_pushinteger},
+ {"lua_pushlstring", (luaV_function) &dll_lua_pushlstring},
+ {"lua_pushstring", (luaV_function) &dll_lua_pushstring},
+ {"lua_pushfstring", (luaV_function) &dll_lua_pushfstring},
+ {"lua_pushcclosure", (luaV_function) &dll_lua_pushcclosure},
+ {"lua_pushboolean", (luaV_function) &dll_lua_pushboolean},
+ {"lua_pushlightuserdata", (luaV_function) &dll_lua_pushlightuserdata},
+ {"lua_getfield", (luaV_function) &dll_lua_getfield},
+ {"lua_rawget", (luaV_function) &dll_lua_rawget},
+ {"lua_rawgeti", (luaV_function) &dll_lua_rawgeti},
+ {"lua_createtable", (luaV_function) &dll_lua_createtable},
+#if LUA_VERSION_NUM >= 504
+ {"lua_newuserdatauv", (luaV_function) &dll_lua_newuserdatauv},
+#else
+ {"lua_newuserdata", (luaV_function) &dll_lua_newuserdata},
+#endif
+ {"lua_getmetatable", (luaV_function) &dll_lua_getmetatable},
+ {"lua_setfield", (luaV_function) &dll_lua_setfield},
+ {"lua_rawset", (luaV_function) &dll_lua_rawset},
+ {"lua_rawseti", (luaV_function) &dll_lua_rawseti},
+ {"lua_setmetatable", (luaV_function) &dll_lua_setmetatable},
+ {"lua_next", (luaV_function) &dll_lua_next},
+ /* libs */
+ {"luaopen_base", (luaV_function) &dll_luaopen_base},
+ {"luaopen_table", (luaV_function) &dll_luaopen_table},
+ {"luaopen_string", (luaV_function) &dll_luaopen_string},
+ {"luaopen_math", (luaV_function) &dll_luaopen_math},
+ {"luaopen_io", (luaV_function) &dll_luaopen_io},
+ {"luaopen_os", (luaV_function) &dll_luaopen_os},
+ {"luaopen_package", (luaV_function) &dll_luaopen_package},
+ {"luaopen_debug", (luaV_function) &dll_luaopen_debug},
+ {"luaL_openlibs", (luaV_function) &dll_luaL_openlibs},
+ {NULL, NULL}
+};
+
+static HANDLE hinstLua = NULL;
+
+ static void
+end_dynamic_lua(void)
+{
+ if (hinstLua)
+ {
+ close_dll(hinstLua);
+ hinstLua = 0;
+ }
+}
+
+ static int
+lua_link_init(char *libname, int verbose)
+{
+ const luaV_Reg *reg;
+ if (hinstLua) return OK;
+ hinstLua = load_dll(libname);
+ if (!hinstLua)
+ {
+ if (verbose)
+ semsg(_(e_loadlib), libname);
+ return FAIL;
+ }
+ for (reg = luaV_dll; reg->func; reg++)
+ {
+ if ((*reg->func = symbol_from_dll(hinstLua, reg->name)) == NULL)
+ {
+ close_dll(hinstLua);
+ hinstLua = 0;
+ if (verbose)
+ semsg(_(e_loadfunc), reg->name);
+ return FAIL;
+ }
+ }
+ return OK;
+}
+#endif /* DYNAMIC_LUA */
+
+#if defined(DYNAMIC_LUA) || defined(PROTO)
+ int
+lua_enabled(int verbose)
+{
+ return lua_link_init((char *)p_luadll, verbose) == OK;
+}
+#endif
+
+#if LUA_VERSION_NUM > 501
+ static int
+luaL_typeerror (lua_State *L, int narg, const char *tname)
+{
+ const char *msg = lua_pushfstring(L, "%s expected, got %s",
+ tname, luaL_typename(L, narg));
+ return luaL_argerror(L, narg, msg);
+}
+#endif
+
+
+/* ======= Internal ======= */
+
+ static void
+luaV_newmetatable(lua_State *L, const char *tname)
+{
+ lua_newtable(L);
+ lua_pushlightuserdata(L, (void *) tname);
+ lua_pushvalue(L, -2);
+ lua_rawset(L, LUA_REGISTRYINDEX);
+}
+
+ static void *
+luaV_toudata(lua_State *L, int ud, const char *tname)
+{
+ void *p = lua_touserdata(L, ud);
+
+ if (p != NULL) /* value is userdata? */
+ {
+ if (lua_getmetatable(L, ud)) /* does it have a metatable? */
+ {
+ luaV_getfield(L, tname); /* get metatable */
+ if (lua_rawequal(L, -1, -2)) /* MTs match? */
+ {
+ lua_pop(L, 2); /* MTs */
+ return p;
+ }
+ }
+ }
+ return NULL;
+}
+
+ static void *
+luaV_checkcache(lua_State *L, void *p)
+{
+ luaV_getudata(L, p);
+ if (lua_isnil(L, -1)) luaL_error(L, "invalid object");
+ lua_pop(L, 1);
+ return p;
+}
+
+#define luaV_unbox(L,luatyp,ud) (*((luatyp *) lua_touserdata((L),(ud))))
+
+#define luaV_checkvalid(L,luatyp,ud) \
+ luaV_checkcache((L), (void *) luaV_unbox((L),luatyp,(ud)))
+
+ static void *
+luaV_checkudata(lua_State *L, int ud, const char *tname)
+{
+ void *p = luaV_toudata(L, ud, tname);
+ if (p == NULL) luaL_typeerror(L, ud, tname);
+ return p;
+}
+
+ static void
+luaV_pushtypval(lua_State *L, typval_T *tv)
+{
+ if (tv == NULL)
+ {
+ lua_pushnil(L);
+ return;
+ }
+ switch (tv->v_type)
+ {
+ case VAR_STRING:
+ lua_pushstring(L, tv->vval.v_string == NULL
+ ? "" : (char *)tv->vval.v_string);
+ break;
+ case VAR_NUMBER:
+ lua_pushinteger(L, (int) tv->vval.v_number);
+ break;
+#ifdef FEAT_FLOAT
+ case VAR_FLOAT:
+ lua_pushnumber(L, (lua_Number) tv->vval.v_float);
+ break;
+#endif
+ case VAR_LIST:
+ luaV_pushlist(L, tv->vval.v_list);
+ break;
+ case VAR_DICT:
+ luaV_pushdict(L, tv->vval.v_dict);
+ break;
+ case VAR_SPECIAL:
+ if (tv->vval.v_number <= VVAL_TRUE)
+ lua_pushinteger(L, (int) tv->vval.v_number);
+ else
+ lua_pushnil(L);
+ break;
+ case VAR_FUNC:
+ luaV_pushfuncref(L, tv);
+ break;
+ default:
+ lua_pushnil(L);
+ }
+}
+
+/*
+ * Converts lua value at 'pos' to typval 'tv'.
+ * Returns OK or FAIL.
+ */
+ static int
+luaV_totypval(lua_State *L, int pos, typval_T *tv)
+{
+ int status = OK;
+
+ switch (lua_type(L, pos))
+ {
+ case LUA_TBOOLEAN:
+ tv->v_type = VAR_SPECIAL;
+ tv->vval.v_number = (varnumber_T) lua_toboolean(L, pos);
+ break;
+ case LUA_TNIL:
+ tv->v_type = VAR_SPECIAL;
+ tv->vval.v_number = VVAL_NULL;
+ break;
+ case LUA_TSTRING:
+ tv->v_type = VAR_STRING;
+ tv->vval.v_string = vim_strsave((char_u *) lua_tostring(L, pos));
+ break;
+ case LUA_TNUMBER:
+#ifdef FEAT_FLOAT
+ tv->v_type = VAR_FLOAT;
+ tv->vval.v_float = (float_T) lua_tonumber(L, pos);
+#else
+ tv->v_type = VAR_NUMBER;
+ tv->vval.v_number = (varnumber_T) lua_tointeger(L, pos);
+#endif
+ break;
+ case LUA_TUSERDATA:
+ {
+ void *p = lua_touserdata(L, pos);
+
+ if (lua_getmetatable(L, pos)) /* has metatable? */
+ {
+ /* check list */
+ luaV_getfield(L, LUAVIM_LIST);
+ if (lua_rawequal(L, -1, -2))
+ {
+ tv->v_type = VAR_LIST;
+ tv->vval.v_list = *((luaV_List *) p);
+ ++tv->vval.v_list->lv_refcount;
+ lua_pop(L, 2); /* MTs */
+ break;
+ }
+ /* check dict */
+ luaV_getfield(L, LUAVIM_DICT);
+ if (lua_rawequal(L, -1, -3))
+ {
+ tv->v_type = VAR_DICT;
+ tv->vval.v_dict = *((luaV_Dict *) p);
+ ++tv->vval.v_dict->dv_refcount;
+ lua_pop(L, 3); /* MTs */
+ break;
+ }
+ /* check funcref */
+ luaV_getfield(L, LUAVIM_FUNCREF);
+ if (lua_rawequal(L, -1, -4))
+ {
+ luaV_Funcref *f = (luaV_Funcref *) p;
+ copy_tv(&f->tv, tv);
+ lua_pop(L, 4); /* MTs */
+ break;
+ }
+ lua_pop(L, 4); /* MTs */
+ }
+ }
+ /* FALLTHROUGH */
+ default:
+ tv->v_type = VAR_NUMBER;
+ tv->vval.v_number = 0;
+ status = FAIL;
+ }
+ return status;
+}
+
+/* similar to luaL_addlstring, but replaces \0 with \n if toline and
+ * \n with \0 otherwise */
+ static void
+luaV_addlstring(luaL_Buffer *b, const char *s, size_t l, int toline)
+{
+ while (l--)
+ {
+ if (*s == '\0' && toline)
+ luaL_addchar(b, '\n');
+ else if (*s == '\n' && !toline)
+ luaL_addchar(b, '\0');
+ else
+ luaL_addchar(b, *s);
+ s++;
+ }
+}
+
+ static void
+luaV_pushline(lua_State *L, buf_T *buf, linenr_T n)
+{
+ const char *s = (const char *) ml_get_buf(buf, n, FALSE);
+ luaL_Buffer b;
+ luaL_buffinit(L, &b);
+ luaV_addlstring(&b, s, strlen(s), 0);
+ luaL_pushresult(&b);
+}
+
+ static char_u *
+luaV_toline(lua_State *L, int pos)
+{
+ size_t l;
+ const char *s = lua_tolstring(L, pos, &l);
+
+ luaL_Buffer b;
+ luaL_buffinit(L, &b);
+ luaV_addlstring(&b, s, l, 1);
+ luaL_pushresult(&b);
+ return (char_u *) lua_tostring(L, -1);
+}
+
+/* pops a string s from the top of the stack and calls mf(t) for pieces t of
+ * s separated by newlines */
+ static void
+luaV_msgfunc(lua_State *L, msgfunc_T mf)
+{
+ luaL_Buffer b;
+ size_t l;
+ const char *p, *s = lua_tolstring(L, -1, &l);
+ luaL_buffinit(L, &b);
+ luaV_addlstring(&b, s, l, 0);
+ luaL_pushresult(&b);
+ /* break string */
+ p = s = lua_tolstring(L, -1, &l);
+ while (l--)
+ {
+ if (*p++ == '\0') /* break? */
+ {
+ mf((char_u *) s);
+ s = p;
+ }
+ }
+ mf((char_u *) s);
+ lua_pop(L, 2); /* original and modified strings */
+}
+
+#define luaV_newtype(typ,tname,luatyp,luatname) \
+ static luatyp * \
+ luaV_new##tname (lua_State *L, typ *obj) \
+ { \
+ luatyp *o = (luatyp *) lua_newuserdata(L, sizeof(luatyp)); \
+ *o = obj; \
+ luaV_setudata(L, obj); /* cache[obj] = udata */ \
+ luaV_getfield(L, luatname); \
+ lua_setmetatable(L, -2); \
+ return o; \
+ }
+
+#define luaV_pushtype(typ,tname,luatyp) \
+ static luatyp * \
+ luaV_push##tname(lua_State *L, typ *obj) \
+ { \
+ luatyp *o = NULL; \
+ if (obj == NULL) \
+ lua_pushnil(L); \
+ else { \
+ luaV_getudata(L, obj); \
+ if (lua_isnil(L, -1)) /* not interned? */ \
+ { \
+ lua_pop(L, 1); \
+ o = luaV_new##tname(L, obj); \
+ } \
+ else \
+ o = (luatyp *) lua_touserdata(L, -1); \
+ } \
+ return o; \
+ }
+
+#define luaV_type_tostring(tname,luatname) \
+ static int \
+ luaV_##tname##_tostring (lua_State *L) \
+ { \
+ lua_pushfstring(L, "%s: %p", luatname, lua_touserdata(L, 1)); \
+ return 1; \
+ }
+
+/* ======= List type ======= */
+
+ static luaV_List *
+luaV_newlist (lua_State *L, list_T *lis)
+{
+ luaV_List *l = (luaV_List *) lua_newuserdata(L, sizeof(luaV_List));
+ *l = lis;
+ lis->lv_refcount++; /* reference in Lua */
+ luaV_setudata(L, lis); /* cache[lis] = udata */
+ luaV_getfield(L, LUAVIM_LIST);
+ lua_setmetatable(L, -2);
+ return l;
+}
+
+luaV_pushtype(list_T, list, luaV_List)
+luaV_type_tostring(list, LUAVIM_LIST)
+
+ static int
+luaV_list_len (lua_State *L)
+{
+ list_T *l = luaV_unbox(L, luaV_List, 1);
+ lua_pushinteger(L, (l == NULL) ? 0 : (int) l->lv_len);
+ return 1;
+}
+
+ static int
+luaV_list_iter (lua_State *L)
+{
+ listitem_T *li = (listitem_T *) lua_touserdata(L, lua_upvalueindex(2));
+ if (li == NULL) return 0;
+ luaV_pushtypval(L, &li->li_tv);
+ lua_pushlightuserdata(L, (void *) li->li_next);
+ lua_replace(L, lua_upvalueindex(2));
+ return 1;
+}
+
+ static int
+luaV_list_call (lua_State *L)
+{
+ list_T *l = luaV_unbox(L, luaV_List, 1);
+ lua_pushvalue(L, lua_upvalueindex(1)); /* pass cache table along */
+ lua_pushlightuserdata(L, (void *) l->lv_first);
+ lua_pushcclosure(L, luaV_list_iter, 2);
+ return 1;
+}
+
+ static int
+luaV_list_index (lua_State *L)
+{
+ list_T *l = luaV_unbox(L, luaV_List, 1);
+ if (lua_isnumber(L, 2)) /* list item? */
+ {
+ listitem_T *li = list_find(l, (long) luaL_checkinteger(L, 2));
+ if (li == NULL)
+ lua_pushnil(L);
+ else
+ luaV_pushtypval(L, &li->li_tv);
+ }
+ else if (lua_isstring(L, 2)) /* method? */
+ {
+ const char *s = lua_tostring(L, 2);
+ if (strncmp(s, "add", 3) == 0
+ || strncmp(s, "insert", 6) == 0)
+ {
+ lua_getmetatable(L, 1);
+ lua_getfield(L, -1, s);
+ }
+ else
+ lua_pushnil(L);
+ }
+ else
+ lua_pushnil(L);
+ return 1;
+}
+
+ static int
+luaV_list_newindex (lua_State *L)
+{
+ list_T *l = luaV_unbox(L, luaV_List, 1);
+ long n = (long) luaL_checkinteger(L, 2);
+ listitem_T *li;
+ if (l->lv_lock)
+ luaL_error(L, "list is locked");
+ li = list_find(l, n);
+ if (li == NULL) return 0;
+ if (lua_isnil(L, 3)) /* remove? */
+ {
+ vimlist_remove(l, li, li);
+ clear_tv(&li->li_tv);
+ vim_free(li);
+ }
+ else
+ {
+ typval_T v;
+ luaV_checktypval(L, 3, &v, "setting list item");
+ clear_tv(&li->li_tv);
+ copy_tv(&v, &li->li_tv);
+ clear_tv(&v);
+ }
+ return 0;
+}
+
+ static int
+luaV_list_add (lua_State *L)
+{
+ luaV_List *lis = luaV_checkudata(L, 1, LUAVIM_LIST);
+ list_T *l = (list_T *) luaV_checkcache(L, (void *) *lis);
+ typval_T v;
+ if (l->lv_lock)
+ luaL_error(L, "list is locked");
+ lua_settop(L, 2);
+ luaV_checktypval(L, 2, &v, "adding list item");
+ if (list_append_tv(l, &v) == FAIL)
+ {
+ clear_tv(&v);
+ luaL_error(L, "failed to add item to list");
+ }
+ clear_tv(&v);
+ lua_settop(L, 1);
+ return 1;
+}
+
+ static int
+luaV_list_insert (lua_State *L)
+{
+ luaV_List *lis = luaV_checkudata(L, 1, LUAVIM_LIST);
+ list_T *l = (list_T *) luaV_checkcache(L, (void *) *lis);
+ long pos = (long) luaL_optinteger(L, 3, 0);
+ listitem_T *li = NULL;
+ typval_T v;
+ if (l->lv_lock)
+ luaL_error(L, "list is locked");
+ if (pos < l->lv_len)
+ {
+ li = list_find(l, pos);
+ if (li == NULL)
+ luaL_error(L, "invalid position");
+ }
+ lua_settop(L, 2);
+ luaV_checktypval(L, 2, &v, "inserting list item");
+ if (list_insert_tv(l, &v, li) == FAIL)
+ {
+ clear_tv(&v);
+ luaL_error(L, "failed to add item to list");
+ }
+ clear_tv(&v);
+ lua_settop(L, 1);
+ return 1;
+}
+
+static const luaL_Reg luaV_List_mt[] = {
+ {"__tostring", luaV_list_tostring},
+ {"__len", luaV_list_len},
+ {"__call", luaV_list_call},
+ {"__index", luaV_list_index},
+ {"__newindex", luaV_list_newindex},
+ {"add", luaV_list_add},
+ {"insert", luaV_list_insert},
+ {NULL, NULL}
+};
+
+
+/* ======= Dict type ======= */
+
+ static luaV_Dict *
+luaV_newdict (lua_State *L, dict_T *dic)
+{
+ luaV_Dict *d = (luaV_Dict *) lua_newuserdata(L, sizeof(luaV_Dict));
+ *d = dic;
+ dic->dv_refcount++; /* reference in Lua */
+ luaV_setudata(L, dic); /* cache[dic] = udata */
+ luaV_getfield(L, LUAVIM_DICT);
+ lua_setmetatable(L, -2);
+ return d;
+}
+
+luaV_pushtype(dict_T, dict, luaV_Dict)
+luaV_type_tostring(dict, LUAVIM_DICT)
+
+ static int
+luaV_dict_len (lua_State *L)
+{
+ dict_T *d = luaV_unbox(L, luaV_Dict, 1);
+ lua_pushinteger(L, (d == NULL) ? 0 : (int) d->dv_hashtab.ht_used);
+ return 1;
+}
+
+ static int
+luaV_dict_iter (lua_State *L UNUSED)
+{
+#ifdef FEAT_EVAL
+ hashitem_T *hi = (hashitem_T *) lua_touserdata(L, lua_upvalueindex(2));
+ int n = lua_tointeger(L, lua_upvalueindex(3));
+ dictitem_T *di;
+ if (n <= 0) return 0;
+ while (HASHITEM_EMPTY(hi)) hi++;
+ di = dict_lookup(hi);
+ lua_pushstring(L, (char *) hi->hi_key);
+ luaV_pushtypval(L, &di->di_tv);
+ lua_pushlightuserdata(L, (void *) (hi + 1));
+ lua_replace(L, lua_upvalueindex(2));
+ lua_pushinteger(L, n - 1);
+ lua_replace(L, lua_upvalueindex(3));
+ return 2;
+#else
+ return 0;
+#endif
+}
+
+ static int
+luaV_dict_call (lua_State *L)
+{
+ dict_T *d = luaV_unbox(L, luaV_Dict, 1);
+ hashtab_T *ht = &d->dv_hashtab;
+ lua_pushvalue(L, lua_upvalueindex(1)); /* pass cache table along */
+ lua_pushlightuserdata(L, (void *) ht->ht_array);
+ lua_pushinteger(L, ht->ht_used); /* # remaining items */
+ lua_pushcclosure(L, luaV_dict_iter, 3);
+ return 1;
+}
+
+ static int
+luaV_dict_index(lua_State *L)
+{
+ dict_T *d = luaV_unbox(L, luaV_Dict, 1);
+ char_u *key = (char_u *) luaL_checkstring(L, 2);
+ dictitem_T *di = dict_find(d, key, -1);
+
+ if (di == NULL)
+ lua_pushnil(L);
+ else
+ {
+ luaV_pushtypval(L, &di->di_tv);
+ if (di->di_tv.v_type == VAR_FUNC) /* funcref? */
+ {
+ luaV_Funcref *f = (luaV_Funcref *) lua_touserdata(L, -1);
+ f->self = d; /* keep "self" reference */
+ d->dv_refcount++;
+ }
+ }
+ return 1;
+}
+
+ static int
+luaV_dict_newindex(lua_State *L)
+{
+ dict_T *d = luaV_unbox(L, luaV_Dict, 1);
+ char_u *key = (char_u *) luaL_checkstring(L, 2);
+ dictitem_T *di;
+ typval_T v;
+ if (d->dv_lock)
+ luaL_error(L, "dict is locked");
+ if (key == NULL)
+ return 0;
+ if (*key == NUL)
+ luaL_error(L, "empty key");
+ if (!lua_isnil(L, 3)) /* read value? */
+ {
+ luaV_checktypval(L, 3, &v, "setting dict item");
+ if (d->dv_scope == VAR_DEF_SCOPE && v.v_type == VAR_FUNC)
+ luaL_error(L, "cannot assign funcref to builtin scope");
+ }
+ di = dict_find(d, key, -1);
+ if (di == NULL) /* non-existing key? */
+ {
+ if (lua_isnil(L, 3))
+ return 0;
+ di = dictitem_alloc(key);
+ if (di == NULL)
+ return 0;
+ if (dict_add(d, di) == FAIL)
+ {
+ vim_free(di);
+ return 0;
+ }
+ }
+ else
+ clear_tv(&di->di_tv);
+ if (lua_isnil(L, 3)) /* remove? */
+ {
+ hashitem_T *hi = hash_find(&d->dv_hashtab, di->di_key);
+ hash_remove(&d->dv_hashtab, hi);
+ dictitem_free(di);
+ }
+ else
+ {
+ copy_tv(&v, &di->di_tv);
+ clear_tv(&v);
+ }
+ return 0;
+}
+
+static const luaL_Reg luaV_Dict_mt[] = {
+ {"__tostring", luaV_dict_tostring},
+ {"__len", luaV_dict_len},
+ {"__call", luaV_dict_call},
+ {"__index", luaV_dict_index},
+ {"__newindex", luaV_dict_newindex},
+ {NULL, NULL}
+};
+
+
+/* ======= Funcref type ======= */
+
+ static luaV_Funcref *
+luaV_newfuncref(lua_State *L, char_u *name)
+{
+ luaV_Funcref *f = (luaV_Funcref *)lua_newuserdata(L, sizeof(luaV_Funcref));
+
+ if (name != NULL)
+ {
+ func_ref(name); /* as in copy_tv */
+ f->tv.vval.v_string = vim_strsave(name);
+ }
+ f->tv.v_type = VAR_FUNC;
+ f->args.v_type = VAR_LIST;
+ f->self = NULL;
+ luaV_getfield(L, LUAVIM_FUNCREF);
+ lua_setmetatable(L, -2);
+ return f;
+}
+
+ static luaV_Funcref *
+luaV_pushfuncref(lua_State *L, typval_T *tv)
+{
+ luaV_Funcref *f = luaV_newfuncref(L, NULL);
+ copy_tv(tv, &f->tv);
+ clear_tv(tv);
+ return f;
+}
+
+
+luaV_type_tostring(funcref, LUAVIM_FUNCREF)
+
+ static int
+luaV_funcref_gc(lua_State *L)
+{
+ luaV_Funcref *f = (luaV_Funcref *) lua_touserdata(L, 1);
+
+ func_unref(f->tv.vval.v_string);
+ vim_free(f->tv.vval.v_string);
+ dict_unref(f->self);
+ return 0;
+}
+
+/* equivalent to string(funcref) */
+ static int
+luaV_funcref_len(lua_State *L)
+{
+ luaV_Funcref *f = (luaV_Funcref *) lua_touserdata(L, 1);
+
+ lua_pushstring(L, (const char *) f->tv.vval.v_string);
+ return 1;
+}
+
+ static int
+luaV_funcref_call(lua_State *L)
+{
+ luaV_Funcref *f = (luaV_Funcref *) lua_touserdata(L, 1);
+ int i, n = lua_gettop(L) - 1; /* #args */
+ int status;
+ typval_T v, rettv;
+
+ f->args.vval.v_list = list_alloc();
+ rettv.v_type = VAR_UNKNOWN; /* as in clear_tv */
+ if (f->args.vval.v_list == NULL)
+ status = FAIL;
+ else
+ {
+ for (i = 0; i < n; i++)
+ {
+ luaV_checktypval(L, i + 2, &v, "calling funcref");
+ list_append_tv(f->args.vval.v_list, &v);
+ }
+ status = func_call(f->tv.vval.v_string, &f->args,
+ NULL, f->self, &rettv);
+ if (status == OK)
+ luaV_pushtypval(L, &rettv);
+ clear_tv(&f->args);
+ clear_tv(&rettv);
+ }
+ if (status != OK)
+ luaL_error(L, "cannot call funcref");
+ return 1;
+}
+
+static const luaL_Reg luaV_Funcref_mt[] = {
+ {"__tostring", luaV_funcref_tostring},
+ {"__gc", luaV_funcref_gc},
+ {"__len", luaV_funcref_len},
+ {"__call", luaV_funcref_call},
+ {NULL, NULL}
+};
+
+
+/* ======= Buffer type ======= */
+
+luaV_newtype(buf_T, buffer, luaV_Buffer, LUAVIM_BUFFER)
+luaV_pushtype(buf_T, buffer, luaV_Buffer)
+luaV_type_tostring(buffer, LUAVIM_BUFFER)
+
+ static int
+luaV_buffer_len(lua_State *L)
+{
+ buf_T *b = (buf_T *) luaV_checkvalid(L, luaV_Buffer, 1);
+ lua_pushinteger(L, b->b_ml.ml_line_count);
+ return 1;
+}
+
+ static int
+luaV_buffer_call(lua_State *L)
+{
+ buf_T *b = (buf_T *) luaV_checkvalid(L, luaV_Buffer, 1);
+ lua_settop(L, 1);
+ set_curbuf(b, DOBUF_SPLIT);
+ return 1;
+}
+
+ static int
+luaV_buffer_index(lua_State *L)
+{
+ buf_T *b = (buf_T *) luaV_checkvalid(L, luaV_Buffer, 1);
+ linenr_T n = (linenr_T) lua_tointeger(L, 2);
+ if (n > 0 && n <= b->b_ml.ml_line_count)
+ luaV_pushline(L, b, n);
+ else if (lua_isstring(L, 2))
+ {
+ const char *s = lua_tostring(L, 2);
+ if (strncmp(s, "name", 4) == 0)
+ lua_pushstring(L, (b->b_sfname == NULL)
+ ? "" : (char *) b->b_sfname);
+ else if (strncmp(s, "fname", 5) == 0)
+ lua_pushstring(L, (b->b_ffname == NULL)
+ ? "" : (char *) b->b_ffname);
+ else if (strncmp(s, "number", 6) == 0)
+ lua_pushinteger(L, b->b_fnum);
+ /* methods */
+ else if (strncmp(s, "insert", 6) == 0
+ || strncmp(s, "next", 4) == 0
+ || strncmp(s, "previous", 8) == 0
+ || strncmp(s, "isvalid", 7) == 0)
+ {
+ lua_getmetatable(L, 1);
+ lua_getfield(L, -1, s);
+ }
+ else
+ lua_pushnil(L);
+ }
+ else
+ lua_pushnil(L);
+ return 1;
+}
+
+ static int
+luaV_buffer_newindex(lua_State *L)
+{
+ buf_T *b = (buf_T *) luaV_checkvalid(L, luaV_Buffer, 1);
+ linenr_T n = (linenr_T) luaL_checkinteger(L, 2);
+#ifdef HAVE_SANDBOX
+ luaV_checksandbox(L);
+#endif
+ if (n < 1 || n > b->b_ml.ml_line_count)
+ luaL_error(L, "invalid line number");
+ if (lua_isnil(L, 3)) /* delete line */
+ {
+ buf_T *buf = curbuf;
+ curbuf = b;
+ if (u_savedel(n, 1L) == FAIL)
+ {
+ curbuf = buf;
+ luaL_error(L, "cannot save undo information");
+ }
+ else if (ml_delete(n, FALSE) == FAIL)
+ {
+ curbuf = buf;
+ luaL_error(L, "cannot delete line");
+ }
+ else
+ {
+ deleted_lines_mark(n, 1L);
+ if (b == curwin->w_buffer) /* fix cursor in current window? */
+ {
+ if (curwin->w_cursor.lnum >= n)
+ {
+ if (curwin->w_cursor.lnum > n)
+ {
+ curwin->w_cursor.lnum -= 1;
+ check_cursor_col();
+ }
+ else check_cursor();
+ changed_cline_bef_curs();
+ }
+ invalidate_botline();
+ }
+ }
+ curbuf = buf;
+ }
+ else if (lua_isstring(L, 3)) /* update line */
+ {
+ buf_T *buf = curbuf;
+ curbuf = b;
+ if (u_savesub(n) == FAIL)
+ {
+ curbuf = buf;
+ luaL_error(L, "cannot save undo information");
+ }
+ else if (ml_replace(n, luaV_toline(L, 3), TRUE) == FAIL)
+ {
+ curbuf = buf;
+ luaL_error(L, "cannot replace line");
+ }
+ else changed_bytes(n, 0);
+ curbuf = buf;
+ if (b == curwin->w_buffer)
+ check_cursor_col();
+ }
+ else
+ luaL_error(L, "wrong argument to change line");
+ return 0;
+}
+
+ static int
+luaV_buffer_insert(lua_State *L)
+{
+ luaV_Buffer *lb = luaV_checkudata(L, 1, LUAVIM_BUFFER);
+ buf_T *b = (buf_T *) luaV_checkcache(L, (void *) *lb);
+ linenr_T last = b->b_ml.ml_line_count;
+ linenr_T n = (linenr_T) luaL_optinteger(L, 3, last);
+ buf_T *buf;
+ luaL_checktype(L, 2, LUA_TSTRING);
+#ifdef HAVE_SANDBOX
+ luaV_checksandbox(L);
+#endif
+ /* fix insertion line */
+ if (n < 0) n = 0;
+ if (n > last) n = last;
+ /* insert */
+ buf = curbuf;
+ curbuf = b;
+ if (u_save(n, n + 1) == FAIL)
+ {
+ curbuf = buf;
+ luaL_error(L, "cannot save undo information");
+ }
+ else if (ml_append(n, luaV_toline(L, 2), 0, FALSE) == FAIL)
+ {
+ curbuf = buf;
+ luaL_error(L, "cannot insert line");
+ }
+ else
+ appended_lines_mark(n, 1L);
+ curbuf = buf;
+ update_screen(VALID);
+ return 0;
+}
+
+ static int
+luaV_buffer_next(lua_State *L)
+{
+ luaV_Buffer *b = luaV_checkudata(L, 1, LUAVIM_BUFFER);
+ buf_T *buf = (buf_T *) luaV_checkcache(L, (void *) *b);
+ luaV_pushbuffer(L, buf->b_next);
+ return 1;
+}
+
+ static int
+luaV_buffer_previous(lua_State *L)
+{
+ luaV_Buffer *b = luaV_checkudata(L, 1, LUAVIM_BUFFER);
+ buf_T *buf = (buf_T *) luaV_checkcache(L, (void *) *b);
+ luaV_pushbuffer(L, buf->b_prev);
+ return 1;
+}
+
+ static int
+luaV_buffer_isvalid(lua_State *L)
+{
+ luaV_Buffer *b = luaV_checkudata(L, 1, LUAVIM_BUFFER);
+ luaV_getudata(L, *b);
+ lua_pushboolean(L, !lua_isnil(L, -1));
+ return 1;
+}
+
+static const luaL_Reg luaV_Buffer_mt[] = {
+ {"__tostring", luaV_buffer_tostring},
+ {"__len", luaV_buffer_len},
+ {"__call", luaV_buffer_call},
+ {"__index", luaV_buffer_index},
+ {"__newindex", luaV_buffer_newindex},
+ {"insert", luaV_buffer_insert},
+ {"next", luaV_buffer_next},
+ {"previous", luaV_buffer_previous},
+ {"isvalid", luaV_buffer_isvalid},
+ {NULL, NULL}
+};
+
+
+/* ======= Window type ======= */
+
+luaV_newtype(win_T, window, luaV_Window, LUAVIM_WINDOW)
+luaV_pushtype(win_T, window, luaV_Window)
+luaV_type_tostring(window, LUAVIM_WINDOW)
+
+ static int
+luaV_window_call(lua_State *L)
+{
+ win_T *w = (win_T *) luaV_checkvalid(L, luaV_Window, 1);
+ lua_settop(L, 1);
+ win_goto(w);
+ return 1;
+}
+
+ static int
+luaV_window_index(lua_State *L)
+{
+ win_T *w = (win_T *) luaV_checkvalid(L, luaV_Window, 1);
+ const char *s = luaL_checkstring(L, 2);
+ if (strncmp(s, "buffer", 6) == 0)
+ luaV_pushbuffer(L, w->w_buffer);
+ else if (strncmp(s, "line", 4) == 0)
+ lua_pushinteger(L, w->w_cursor.lnum);
+ else if (strncmp(s, "col", 3) == 0)
+ lua_pushinteger(L, w->w_cursor.col + 1);
+ else if (strncmp(s, "width", 5) == 0)
+ lua_pushinteger(L, w->w_width);
+ else if (strncmp(s, "height", 6) == 0)
+ lua_pushinteger(L, w->w_height);
+ /* methods */
+ else if (strncmp(s, "next", 4) == 0
+ || strncmp(s, "previous", 8) == 0
+ || strncmp(s, "isvalid", 7) == 0)
+ {
+ lua_getmetatable(L, 1);
+ lua_getfield(L, -1, s);
+ }
+ else
+ lua_pushnil(L);
+ return 1;
+}
+
+ static int
+luaV_window_newindex (lua_State *L)
+{
+ win_T *w = (win_T *) luaV_checkvalid(L, luaV_Window, 1);
+ const char *s = luaL_checkstring(L, 2);
+ int v = luaL_checkinteger(L, 3);
+ if (strncmp(s, "line", 4) == 0)
+ {
+#ifdef HAVE_SANDBOX
+ luaV_checksandbox(L);
+#endif
+ if (v < 1 || v > w->w_buffer->b_ml.ml_line_count)
+ luaL_error(L, "line out of range");
+ w->w_cursor.lnum = v;
+ update_screen(VALID);
+ }
+ else if (strncmp(s, "col", 3) == 0)
+ {
+#ifdef HAVE_SANDBOX
+ luaV_checksandbox(L);
+#endif
+ w->w_cursor.col = v - 1;
+ w->w_set_curswant = TRUE;
+ update_screen(VALID);
+ }
+ else if (strncmp(s, "width", 5) == 0)
+ {
+ win_T *win = curwin;
+#ifdef FEAT_GUI
+ need_mouse_correct = TRUE;
+#endif
+ curwin = w;
+ win_setwidth(v);
+ curwin = win;
+ }
+ else if (strncmp(s, "height", 6) == 0)
+ {
+ win_T *win = curwin;
+#ifdef FEAT_GUI
+ need_mouse_correct = TRUE;
+#endif
+ curwin = w;
+ win_setheight(v);
+ curwin = win;
+ }
+ else
+ luaL_error(L, "invalid window property: `%s'", s);
+ return 0;
+}
+
+ static int
+luaV_window_next(lua_State *L)
+{
+ luaV_Window *w = luaV_checkudata(L, 1, LUAVIM_WINDOW);
+ win_T *win = (win_T *) luaV_checkcache(L, (void *) *w);
+ luaV_pushwindow(L, win->w_next);
+ return 1;
+}
+
+ static int
+luaV_window_previous(lua_State *L)
+{
+ luaV_Window *w = luaV_checkudata(L, 1, LUAVIM_WINDOW);
+ win_T *win = (win_T *) luaV_checkcache(L, (void *) *w);
+ luaV_pushwindow(L, win->w_prev);
+ return 1;
+}
+
+ static int
+luaV_window_isvalid(lua_State *L)
+{
+ luaV_Window *w = luaV_checkudata(L, 1, LUAVIM_WINDOW);
+ luaV_getudata(L, *w);
+ lua_pushboolean(L, !lua_isnil(L, -1));
+ return 1;
+}
+
+static const luaL_Reg luaV_Window_mt[] = {
+ {"__tostring", luaV_window_tostring},
+ {"__call", luaV_window_call},
+ {"__index", luaV_window_index},
+ {"__newindex", luaV_window_newindex},
+ {"next", luaV_window_next},
+ {"previous", luaV_window_previous},
+ {"isvalid", luaV_window_isvalid},
+ {NULL, NULL}
+};
+
+
+/* ======= Vim module ======= */
+
+ static int
+luaV_print(lua_State *L)
+{
+ int i, n = lua_gettop(L); /* nargs */
+ const char *s;
+ size_t l;
+ luaL_Buffer b;
+ luaL_buffinit(L, &b);
+ lua_getglobal(L, "tostring");
+ for (i = 1; i <= n; i++)
+ {
+ lua_pushvalue(L, -1); /* tostring */
+ lua_pushvalue(L, i); /* arg */
+ lua_call(L, 1, 1);
+ s = lua_tolstring(L, -1, &l);
+ if (s == NULL)
+ return luaL_error(L, "cannot convert to string");
+ if (i > 1) luaL_addchar(&b, ' '); /* use space instead of tab */
+ luaV_addlstring(&b, s, l, 0);
+ lua_pop(L, 1);
+ }
+ luaL_pushresult(&b);
+ luaV_msg(L);
+ return 0;
+}
+
+ static int
+luaV_debug(lua_State *L)
+{
+ lua_settop(L, 0);
+ lua_getglobal(L, "vim");
+ lua_getfield(L, -1, "eval");
+ lua_remove(L, -2); /* vim.eval at position 1 */
+ for (;;)
+ {
+ const char *input;
+ size_t l;
+ lua_pushvalue(L, 1); /* vim.eval */
+ lua_pushliteral(L, "input('lua_debug> ')");
+ lua_call(L, 1, 1); /* return string */
+ input = lua_tolstring(L, -1, &l);
+ if (l == 0 || strcmp(input, "cont") == 0)
+ return 0;
+ msg_putchar('\n'); /* avoid outputting on input line */
+ if (luaL_loadbuffer(L, input, l, "=(debug command)")
+ || lua_pcall(L, 0, 0, 0))
+ luaV_emsg(L);
+ lua_settop(L, 1); /* remove eventual returns, but keep vim.eval */
+ }
+}
+
+ static int
+luaV_command(lua_State *L)
+{
+ do_cmdline_cmd((char_u *) luaL_checkstring(L, 1));
+ update_screen(VALID);
+ return 0;
+}
+
+ static int
+luaV_eval(lua_State *L)
+{
+ typval_T *tv = eval_expr((char_u *) luaL_checkstring(L, 1), NULL);
+ if (tv == NULL) luaL_error(L, "invalid expression");
+ luaV_pushtypval(L, tv);
+ free_tv(tv);
+ return 1;
+}
+
+ static int
+luaV_beep(lua_State *L UNUSED)
+{
+ vim_beep(BO_LANG);
+ return 0;
+}
+
+ static int
+luaV_line(lua_State *L)
+{
+ luaV_pushline(L, curbuf, curwin->w_cursor.lnum);
+ return 1;
+}
+
+ static int
+luaV_list(lua_State *L)
+{
+ list_T *l;
+ int initarg = !lua_isnoneornil(L, 1);
+
+ if (initarg && lua_type(L, 1) != LUA_TTABLE)
+ luaL_error(L, "table expected, got %s", luaL_typename(L, 1));
+ l = list_alloc();
+ if (l == NULL)
+ lua_pushnil(L);
+ else
+ {
+ luaV_newlist(L, l);
+ if (initarg) /* traverse table to init list */
+ {
+ int notnil, i = 0;
+ typval_T v;
+ do
+ {
+ lua_rawgeti(L, 1, ++i);
+ notnil = !lua_isnil(L, -1);
+ if (notnil)
+ {
+ luaV_checktypval(L, -1, &v, "vim.list");
+ list_append_tv(l, &v);
+ }
+ lua_pop(L, 1); /* value */
+ } while (notnil);
+ }
+ }
+ return 1;
+}
+
+ static int
+luaV_dict(lua_State *L)
+{
+ dict_T *d;
+ int initarg = !lua_isnoneornil(L, 1);
+
+ if (initarg && lua_type(L, 1) != LUA_TTABLE)
+ luaL_error(L, "table expected, got %s", luaL_typename(L, 1));
+ d = dict_alloc();
+ if (d == NULL)
+ lua_pushnil(L);
+ else
+ {
+ luaV_newdict(L, d);
+ if (initarg) /* traverse table to init dict */
+ {
+ lua_pushnil(L);
+ while (lua_next(L, 1))
+ {
+ char_u *key;
+ dictitem_T *di;
+ typval_T v;
+
+ lua_pushvalue(L, -2); /* dup key in case it's a number */
+ key = (char_u *) lua_tostring(L, -1);
+ if (key == NULL)
+ {
+ lua_pushnil(L);
+ return 1;
+ }
+ if (*key == NUL)
+ luaL_error(L, "table has empty key");
+ luaV_checktypval(L, -2, &v, "vim.dict"); /* value */
+ di = dictitem_alloc(key);
+ if (di == NULL || dict_add(d, di) == FAIL)
+ {
+ vim_free(di);
+ lua_pushnil(L);
+ return 1;
+ }
+ copy_tv(&v, &di->di_tv);
+ clear_tv(&v);
+ lua_pop(L, 2); /* key copy and value */
+ }
+ }
+ }
+ return 1;
+}
+
+ static int
+luaV_funcref(lua_State *L)
+{
+ const char *name = luaL_checkstring(L, 1);
+ /* note: not checking if function exists (needs function_exists) */
+ if (name == NULL || *name == NUL || VIM_ISDIGIT(*name))
+ luaL_error(L, "invalid function name: %s", name);
+ luaV_newfuncref(L, (char_u *) name);
+ return 1;
+}
+
+ static int
+luaV_buffer(lua_State *L)
+{
+ buf_T *buf;
+ if (lua_isstring(L, 1)) /* get by number or name? */
+ {
+ if (lua_isnumber(L, 1)) /* by number? */
+ {
+ int n = lua_tointeger(L, 1);
+ FOR_ALL_BUFFERS(buf)
+ if (buf->b_fnum == n) break;
+ }
+ else // by name
+ {
+ size_t l;
+ const char *s = lua_tolstring(L, 1, &l);
+ FOR_ALL_BUFFERS(buf)
+ {
+ if (buf->b_ffname == NULL || buf->b_sfname == NULL)
+ {
+ if (l == 0) break;
+ }
+ else if (strncmp(s, (char *)buf->b_ffname, l) == 0
+ || strncmp(s, (char *)buf->b_sfname, l) == 0)
+ break;
+ }
+ }
+ }
+ else
+ buf = (lua_toboolean(L, 1)) ? firstbuf : curbuf; /* first buffer? */
+ luaV_pushbuffer(L, buf);
+ return 1;
+}
+
+ static int
+luaV_window(lua_State *L)
+{
+ win_T *win;
+ if (lua_isnumber(L, 1)) /* get by number? */
+ {
+ int n = lua_tointeger(L, 1);
+ for (win = firstwin; win != NULL; win = win->w_next, n--)
+ if (n == 1) break;
+ }
+ else
+ win = (lua_toboolean(L, 1)) ? firstwin : curwin; /* first window? */
+ luaV_pushwindow(L, win);
+ return 1;
+}
+
+ static int
+luaV_open(lua_State *L)
+{
+ char_u *s = NULL;
+#ifdef HAVE_SANDBOX
+ luaV_checksandbox(L);
+#endif
+ if (lua_isstring(L, 1)) s = (char_u *) lua_tostring(L, 1);
+ luaV_pushbuffer(L, buflist_new(s, NULL, 1L, BLN_LISTED));
+ return 1;
+}
+
+ static int
+luaV_type(lua_State *L)
+{
+ luaL_checkany(L, 1);
+ if (lua_type(L, 1) == LUA_TUSERDATA) /* check vim udata? */
+ {
+ lua_settop(L, 1);
+ if (lua_getmetatable(L, 1))
+ {
+ luaV_getfield(L, LUAVIM_LIST);
+ if (lua_rawequal(L, -1, 2))
+ {
+ lua_pushstring(L, "list");
+ return 1;
+ }
+ luaV_getfield(L, LUAVIM_DICT);
+ if (lua_rawequal(L, -1, 2))
+ {
+ lua_pushstring(L, "dict");
+ return 1;
+ }
+ luaV_getfield(L, LUAVIM_FUNCREF);
+ if (lua_rawequal(L, -1, 2))
+ {
+ lua_pushstring(L, "funcref");
+ return 1;
+ }
+ luaV_getfield(L, LUAVIM_BUFFER);
+ if (lua_rawequal(L, -1, 2))
+ {
+ lua_pushstring(L, "buffer");
+ return 1;
+ }
+ luaV_getfield(L, LUAVIM_WINDOW);
+ if (lua_rawequal(L, -1, 2))
+ {
+ lua_pushstring(L, "window");
+ return 1;
+ }
+ }
+ }
+ lua_pushstring(L, luaL_typename(L, 1)); /* fallback */
+ return 1;
+}
+
+static const luaL_Reg luaV_module[] = {
+ {"command", luaV_command},
+ {"eval", luaV_eval},
+ {"beep", luaV_beep},
+ {"line", luaV_line},
+ {"list", luaV_list},
+ {"dict", luaV_dict},
+ {"funcref", luaV_funcref},
+ {"buffer", luaV_buffer},
+ {"window", luaV_window},
+ {"open", luaV_open},
+ {"type", luaV_type},
+ {NULL, NULL}
+};
+
+/* for freeing list, dict, buffer and window objects; lightuserdata as arg */
+ static int
+luaV_free(lua_State *L)
+{
+ lua_pushnil(L);
+ luaV_setudata(L, lua_touserdata(L, 1));
+ return 0;
+}
+
+ static int
+luaV_luaeval (lua_State *L)
+{
+ luaL_Buffer b;
+ size_t l;
+ const char *str = lua_tolstring(L, 1, &l);
+ typval_T *arg = (typval_T *) lua_touserdata(L, 2);
+ typval_T *rettv = (typval_T *) lua_touserdata(L, 3);
+ luaL_buffinit(L, &b);
+ luaL_addlstring(&b, LUAVIM_EVALHEADER, sizeof(LUAVIM_EVALHEADER) - 1);
+ luaL_addlstring(&b, str, l);
+ luaL_pushresult(&b);
+ str = lua_tolstring(L, -1, &l);
+ if (luaL_loadbuffer(L, str, l, LUAVIM_EVALNAME)) /* compile error? */
+ {
+ luaV_emsg(L);
+ return 0;
+ }
+ luaV_pushtypval(L, arg);
+ if (lua_pcall(L, 1, 1, 0)) /* running error? */
+ {
+ luaV_emsg(L);
+ return 0;
+ }
+ if (luaV_totypval(L, -1, rettv) == FAIL)
+ emsg("luaeval: cannot convert value");
+ return 0;
+}
+
+ static int
+luaV_setref (lua_State *L)
+{
+ int copyID = lua_tointeger(L, 1);
+ int abort = FALSE;
+ typval_T tv;
+
+ luaV_getfield(L, LUAVIM_LIST);
+ luaV_getfield(L, LUAVIM_DICT);
+ lua_pushnil(L);
+ /* traverse cache table */
+ while (!abort && lua_next(L, lua_upvalueindex(1)) != 0)
+ {
+ lua_getmetatable(L, -1);
+ if (lua_rawequal(L, -1, 2)) /* list? */
+ {
+ tv.v_type = VAR_LIST;
+ tv.vval.v_list = (list_T *) lua_touserdata(L, 4); /* key */
+ abort = set_ref_in_item(&tv, copyID, NULL, NULL);
+ }
+ else if (lua_rawequal(L, -1, 3)) /* dict? */
+ {
+ tv.v_type = VAR_DICT;
+ tv.vval.v_dict = (dict_T *) lua_touserdata(L, 4); /* key */
+ abort = set_ref_in_item(&tv, copyID, NULL, NULL);
+ }
+ lua_pop(L, 2); /* metatable and value */
+ }
+ lua_pushinteger(L, abort);
+ return 1;
+}
+
+ static int
+luaopen_vim(lua_State *L)
+{
+ /* set cache table */
+ lua_newtable(L);
+ lua_newtable(L);
+ lua_pushstring(L, "v");
+ lua_setfield(L, -2, "__mode");
+ lua_setmetatable(L, -2); /* cache is weak-valued */
+ /* print */
+ lua_pushcfunction(L, luaV_print);
+ lua_setglobal(L, "print");
+ /* debug.debug */
+ lua_getglobal(L, "debug");
+ lua_pushcfunction(L, luaV_debug);
+ lua_setfield(L, -2, "debug");
+ lua_pop(L, 1);
+ /* free */
+ lua_pushlightuserdata(L, (void *) LUAVIM_FREE);
+ lua_pushvalue(L, 1); /* cache table */
+ lua_pushcclosure(L, luaV_free, 1);
+ lua_rawset(L, LUA_REGISTRYINDEX);
+ /* luaeval */
+ lua_pushlightuserdata(L, (void *) LUAVIM_LUAEVAL);
+ lua_pushvalue(L, 1); /* cache table */
+ lua_pushcclosure(L, luaV_luaeval, 1);
+ lua_rawset(L, LUA_REGISTRYINDEX);
+ /* setref */
+ lua_pushlightuserdata(L, (void *) LUAVIM_SETREF);
+ lua_pushvalue(L, 1); /* cache table */
+ lua_pushcclosure(L, luaV_setref, 1);
+ lua_rawset(L, LUA_REGISTRYINDEX);
+ /* register */
+ luaV_newmetatable(L, LUAVIM_LIST);
+ lua_pushvalue(L, 1);
+ luaV_openlib(L, luaV_List_mt, 1);
+ luaV_newmetatable(L, LUAVIM_DICT);
+ lua_pushvalue(L, 1);
+ luaV_openlib(L, luaV_Dict_mt, 1);
+ luaV_newmetatable(L, LUAVIM_FUNCREF);
+ lua_pushvalue(L, 1);
+ luaV_openlib(L, luaV_Funcref_mt, 1);
+ luaV_newmetatable(L, LUAVIM_BUFFER);
+ lua_pushvalue(L, 1); /* cache table */
+ luaV_openlib(L, luaV_Buffer_mt, 1);
+ luaV_newmetatable(L, LUAVIM_WINDOW);
+ lua_pushvalue(L, 1); /* cache table */
+ luaV_openlib(L, luaV_Window_mt, 1);
+ lua_newtable(L); /* vim table */
+ lua_pushvalue(L, 1); /* cache table */
+ luaV_openlib(L, luaV_module, 1);
+ lua_setglobal(L, LUAVIM_NAME);
+ return 0;
+}
+
+ static lua_State *
+luaV_newstate(void)
+{
+ lua_State *L = luaL_newstate();
+ luaL_openlibs(L); /* core libs */
+ lua_pushcfunction(L, luaopen_vim); /* vim */
+ lua_call(L, 0, 0);
+ return L;
+}
+
+ static void
+luaV_setrange(lua_State *L, int line1, int line2)
+{
+ lua_getglobal(L, LUAVIM_NAME);
+ lua_pushinteger(L, line1);
+ lua_setfield(L, -2, "firstline");
+ lua_pushinteger(L, line2);
+ lua_setfield(L, -2, "lastline");
+ lua_pop(L, 1); /* vim table */
+}
+
+
+/* ======= Interface ======= */
+
+static lua_State *L = NULL;
+
+ static int
+lua_isopen(void)
+{
+ return L != NULL;
+}
+
+ static int
+lua_init(void)
+{
+ if (!lua_isopen())
+ {
+#ifdef DYNAMIC_LUA
+ if (!lua_enabled(TRUE))
+ {
+ emsg(_("Lua library cannot be loaded."));
+ return FAIL;
+ }
+#endif
+ L = luaV_newstate();
+ }
+ return OK;
+}
+
+ void
+lua_end(void)
+{
+ if (lua_isopen())
+ {
+ lua_close(L);
+ L = NULL;
+#ifdef DYNAMIC_LUA
+ end_dynamic_lua();
+#endif
+ }
+}
+
+/* ex commands */
+ void
+ex_lua(exarg_T *eap)
+{
+ char *script;
+ if (lua_init() == FAIL) return;
+ script = (char *) script_get(eap, eap->arg);
+ if (!eap->skip)
+ {
+ char *s = (script) ? script : (char *) eap->arg;
+ luaV_setrange(L, eap->line1, eap->line2);
+ if (luaL_loadbuffer(L, s, strlen(s), LUAVIM_CHUNKNAME)
+ || lua_pcall(L, 0, 0, 0))
+ luaV_emsg(L);
+ }
+ if (script != NULL) vim_free(script);
+}
+
+ void
+ex_luado(exarg_T *eap)
+{
+ linenr_T l;
+ const char *s = (const char *) eap->arg;
+ luaL_Buffer b;
+ size_t len;
+ buf_T *was_curbuf = curbuf;
+
+ if (lua_init() == FAIL) return;
+ if (u_save(eap->line1 - 1, eap->line2 + 1) == FAIL)
+ {
+ emsg(_("cannot save undo information"));
+ return;
+ }
+ luaV_setrange(L, eap->line1, eap->line2);
+ luaL_buffinit(L, &b);
+ luaL_addlstring(&b, "return function(line, linenr) ", 30); /* header */
+ luaL_addlstring(&b, s, strlen(s));
+ luaL_addlstring(&b, " end", 4); /* footer */
+ luaL_pushresult(&b);
+ s = lua_tolstring(L, -1, &len);
+ if (luaL_loadbuffer(L, s, len, LUAVIM_CHUNKNAME))
+ {
+ luaV_emsg(L);
+ lua_pop(L, 1); /* function body */
+ return;
+ }
+ lua_call(L, 0, 1);
+ lua_replace(L, -2); /* function -> body */
+ for (l = eap->line1; l <= eap->line2; l++)
+ {
+ /* Check the line number, the command my have deleted lines. */
+ if (l > curbuf->b_ml.ml_line_count)
+ break;
+
+ lua_pushvalue(L, -1); /* function */
+ luaV_pushline(L, curbuf, l); /* current line as arg */
+ lua_pushinteger(L, l); /* current line number as arg */
+ if (lua_pcall(L, 2, 1, 0))
+ {
+ luaV_emsg(L);
+ break;
+ }
+ /* Catch the command switching to another buffer. */
+ if (curbuf != was_curbuf)
+ break;
+ if (lua_isstring(L, -1)) /* update line? */
+ {
+#ifdef HAVE_SANDBOX
+ luaV_checksandbox(L);
+#endif
+ ml_replace(l, luaV_toline(L, -1), TRUE);
+ changed_bytes(l, 0);
+ lua_pop(L, 1); /* result from luaV_toline */
+ }
+ lua_pop(L, 1); /* line */
+ }
+ lua_pop(L, 1); /* function */
+ check_cursor();
+ update_screen(NOT_VALID);
+}
+
+ void
+ex_luafile(exarg_T *eap)
+{
+ if (lua_init() == FAIL)
+ return;
+ if (!eap->skip)
+ {
+ luaV_setrange(L, eap->line1, eap->line2);
+ if (luaL_loadfile(L, (char *) eap->arg) || lua_pcall(L, 0, 0, 0))
+ luaV_emsg(L);
+ }
+}
+
+#define luaV_freetype(typ,tname) \
+ void \
+ lua_##tname##_free(typ *o) \
+ { \
+ if (!lua_isopen()) return; \
+ luaV_getfield(L, LUAVIM_FREE); \
+ lua_pushlightuserdata(L, (void *) o); \
+ lua_call(L, 1, 0); \
+ }
+
+luaV_freetype(buf_T, buffer)
+luaV_freetype(win_T, window)
+
+ void
+do_luaeval (char_u *str, typval_T *arg, typval_T *rettv)
+{
+ lua_init();
+ luaV_getfield(L, LUAVIM_LUAEVAL);
+ lua_pushstring(L, (char *) str);
+ lua_pushlightuserdata(L, (void *) arg);
+ lua_pushlightuserdata(L, (void *) rettv);
+ lua_call(L, 3, 0);
+}
+
+ int
+set_ref_in_lua (int copyID)
+{
+ int aborted = 0;
+
+ if (lua_isopen())
+ {
+ luaV_getfield(L, LUAVIM_SETREF);
+ /* call the function with 1 arg, getting 1 result back */
+ lua_pushinteger(L, copyID);
+ lua_call(L, 1, 1);
+ /* get the result */
+ aborted = lua_tointeger(L, -1);
+ /* pop result off the stack */
+ lua_pop(L, 1);
+ }
+ return aborted;
+}
+
+#endif
diff --git a/src/if_mzsch.c b/src/if_mzsch.c
new file mode 100644
index 0000000..16c4c88
--- /dev/null
+++ b/src/if_mzsch.c
@@ -0,0 +1,3824 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * MzScheme interface by Sergey Khorev <sergey.khorev@gmail.com>
+ * Based on work by Brent Fulgham <bfulgham@debian.org>
+ * (Based on lots of help from Matthew Flatt)
+ *
+ * This consists of six parts:
+ * 1. MzScheme interpreter main program
+ * 2. Routines that handle the external interface between MzScheme and
+ * Vim.
+ * 3. MzScheme input/output handlers: writes output via [e]msg().
+ * 4. Implementation of the Vim Features for MzScheme
+ * 5. Vim Window-related Manipulation Functions.
+ * 6. Vim Buffer-related Manipulation Functions
+ *
+ * NOTES
+ * 1. Memory, allocated with scheme_malloc*, need not to be freed explicitly,
+ * garbage collector will do it self
+ * 2. Requires at least NORMAL features. I can't imagine why one may want
+ * to build with SMALL or TINY features but with MzScheme interface.
+ * 3. I don't use K&R-style functions. Anyways, MzScheme headers are ANSI.
+ */
+
+#include "vim.h"
+
+#include "if_mzsch.h"
+
+/* Only do the following when the feature is enabled. Needed for "make
+ * depend". */
+#if defined(FEAT_MZSCHEME) || defined(PROTO)
+
+#ifdef PROTO
+typedef int Scheme_Object;
+typedef int Scheme_Closed_Prim;
+typedef int Scheme_Env;
+typedef int Scheme_Hash_Table;
+typedef int Scheme_Type;
+typedef int Scheme_Thread;
+typedef int Scheme_Closed_Prim;
+typedef int mzshort;
+typedef int Scheme_Prim;
+typedef int HINSTANCE;
+#endif
+
+/*
+ * scheme_register_tls_space is only available on 32-bit Windows until
+ * racket-6.3. See
+ * http://docs.racket-lang.org/inside/im_memoryalloc.html?q=scheme_register_tls_space
+ */
+#if MZSCHEME_VERSION_MAJOR >= 500 && defined(WIN32) \
+ && defined(USE_THREAD_LOCAL) \
+ && (!defined(_WIN64) || MZSCHEME_VERSION_MAJOR >= 603)
+# define HAVE_TLS_SPACE 1
+#endif
+
+/*
+ * Since version 4.x precise GC requires trampolined startup.
+ * Futures and places in version 5.x need it too.
+ */
+#if defined(MZ_PRECISE_GC) && MZSCHEME_VERSION_MAJOR >= 400 \
+ || MZSCHEME_VERSION_MAJOR >= 500 \
+ && (defined(MZ_USE_FUTURES) || defined(MZ_USE_PLACES))
+# define TRAMPOLINED_MZVIM_STARTUP
+#endif
+
+/* Base data structures */
+#define SCHEME_VIMBUFFERP(obj) SAME_TYPE(SCHEME_TYPE(obj), mz_buffer_type)
+#define SCHEME_VIMWINDOWP(obj) SAME_TYPE(SCHEME_TYPE(obj), mz_window_type)
+
+typedef struct
+{
+ Scheme_Object so;
+ buf_T *buf;
+} vim_mz_buffer;
+
+#define INVALID_BUFFER_VALUE ((buf_T *)(-1))
+
+typedef struct
+{
+ Scheme_Object so;
+ win_T *win;
+} vim_mz_window;
+
+#define INVALID_WINDOW_VALUE ((win_T *)(-1))
+
+/*
+ * Prims that form MzScheme Vim interface
+ */
+typedef struct
+{
+ Scheme_Closed_Prim *prim;
+ char *name;
+ int mina; /* arity information */
+ int maxa;
+} Vim_Prim;
+
+typedef struct
+{
+ char *name;
+ Scheme_Object *port;
+} Port_Info;
+
+/*
+ *========================================================================
+ * Vim-Control Commands
+ *========================================================================
+ */
+/*
+ *========================================================================
+ * Utility functions for the vim/mzscheme interface
+ *========================================================================
+ */
+#ifdef HAVE_SANDBOX
+static Scheme_Object *sandbox_file_guard(int, Scheme_Object **);
+static Scheme_Object *sandbox_network_guard(int, Scheme_Object **);
+static void sandbox_check(void);
+#endif
+/* Buffer-related commands */
+static Scheme_Object *buffer_new(buf_T *buf);
+static Scheme_Object *get_buffer_by_num(void *, int, Scheme_Object **);
+static vim_mz_buffer *get_vim_curr_buffer(void);
+
+/* Window-related commands */
+static Scheme_Object *window_new(win_T *win);
+static vim_mz_window *get_vim_curr_window(void);
+
+/*
+ *========================================================================
+ * Internal Function Prototypes
+ *========================================================================
+ */
+static int vim_error_check(void);
+static int do_mzscheme_command(exarg_T *, void *, Scheme_Closed_Prim *what);
+static int startup_mzscheme(void);
+static char *string_to_line(Scheme_Object *obj);
+#if MZSCHEME_VERSION_MAJOR >= 501
+# define OUTPUT_LEN_TYPE intptr_t
+#else
+# define OUTPUT_LEN_TYPE long
+#endif
+static void do_output(char *mesg, OUTPUT_LEN_TYPE len);
+static void do_printf(char *format, ...);
+static void do_flush(void);
+static Scheme_Object *_apply_thunk_catch_exceptions(
+ Scheme_Object *, Scheme_Object **);
+static Scheme_Object *extract_exn_message(Scheme_Object *v);
+static Scheme_Object *do_eval(void *, int noargc, Scheme_Object **noargv);
+static Scheme_Object *do_load(void *, int noargc, Scheme_Object **noargv);
+static void register_vim_exn(void);
+static vim_mz_buffer *get_buffer_arg(const char *fname, int argnum,
+ int argc, Scheme_Object **argv);
+static vim_mz_window *get_window_arg(const char *fname, int argnum,
+ int argc, Scheme_Object **argv);
+static int line_in_range(linenr_T, buf_T *);
+static void check_line_range(linenr_T, buf_T *);
+static void mz_fix_cursor(int lo, int hi, int extra);
+
+static int eval_with_exn_handling(void *, Scheme_Closed_Prim *,
+ Scheme_Object **ret);
+static void make_modules(void);
+static void init_exn_catching_apply(void);
+static int mzscheme_env_main(Scheme_Env *env, int argc, char **argv);
+static int mzscheme_init(void);
+#ifdef FEAT_EVAL
+static Scheme_Object *vim_to_mzscheme(typval_T *vim_value);
+static Scheme_Object *vim_to_mzscheme_impl(typval_T *vim_value, int depth,
+ Scheme_Hash_Table *visited);
+static int mzscheme_to_vim(Scheme_Object *obj, typval_T *tv);
+static int mzscheme_to_vim_impl(Scheme_Object *obj, typval_T *tv, int depth,
+ Scheme_Hash_Table *visited);
+static Scheme_Object *vim_funcref(void *data, int argc, Scheme_Object **argv);
+#endif
+
+#ifdef MZ_PRECISE_GC
+static int buffer_size_proc(void *obj UNUSED)
+{
+ return gcBYTES_TO_WORDS(sizeof(vim_mz_buffer));
+}
+static int buffer_mark_proc(void *obj)
+{
+ return buffer_size_proc(obj);
+}
+static int buffer_fixup_proc(void *obj)
+{
+ /* apparently not needed as the object will be uncollectable while
+ * the buffer is alive
+ */
+ /*
+ vim_mz_buffer* buf = (vim_mz_buffer*) obj;
+ buf->buf->b_mzscheme_ref = GC_fixup_self(obj);
+ */
+ return buffer_size_proc(obj);
+}
+static int window_size_proc(void *obj UNUSED)
+{
+ return gcBYTES_TO_WORDS(sizeof(vim_mz_window));
+}
+static int window_mark_proc(void *obj)
+{
+ return window_size_proc(obj);
+}
+static int window_fixup_proc(void *obj)
+{
+ /* apparently not needed as the object will be uncollectable while
+ * the window is alive
+ */
+ /*
+ vim_mz_window* win = (vim_mz_window*) obj;
+ win->win->w_mzscheme_ref = GC_fixup_self(obj);
+ */
+ return window_size_proc(obj);
+}
+/* with precise GC, w_mzscheme_ref and b_mzscheme_ref are immobile boxes
+ * containing pointers to a window/buffer
+ * with conservative GC these are simply pointers*/
+# define WINDOW_REF(win) *(vim_mz_window **)((win)->w_mzscheme_ref)
+# define BUFFER_REF(buf) *(vim_mz_buffer **)((buf)->b_mzscheme_ref)
+#else
+# define WINDOW_REF(win) (vim_mz_window *)((win)->w_mzscheme_ref)
+# define BUFFER_REF(buf) (vim_mz_buffer *)((buf)->b_mzscheme_ref)
+#endif
+
+#if defined(DYNAMIC_MZSCHEME) || defined(PROTO)
+static Scheme_Object *dll_scheme_eof;
+static Scheme_Object *dll_scheme_false;
+static Scheme_Object *dll_scheme_void;
+static Scheme_Object *dll_scheme_null;
+static Scheme_Object *dll_scheme_true;
+
+static Scheme_Thread **dll_scheme_current_thread_ptr;
+
+static void (**dll_scheme_console_printf_ptr)(char *str, ...);
+static void (**dll_scheme_console_output_ptr)(char *str, OUTPUT_LEN_TYPE len);
+static void (**dll_scheme_notify_multithread_ptr)(int on);
+
+static void *(*dll_GC_malloc)(size_t size_in_bytes);
+static void *(*dll_GC_malloc_atomic)(size_t size_in_bytes);
+static Scheme_Env *(*dll_scheme_basic_env)(void);
+static void (*dll_scheme_check_threads)(void);
+static void (*dll_scheme_register_static)(void *ptr, long size);
+static void (*dll_scheme_set_stack_base)(void *base, int no_auto_statics);
+static void (*dll_scheme_add_global)(const char *name, Scheme_Object *val,
+ Scheme_Env *env);
+static void (*dll_scheme_add_global_symbol)(Scheme_Object *name,
+ Scheme_Object *val, Scheme_Env *env);
+static Scheme_Object *(*dll_scheme_apply)(Scheme_Object *rator, int num_rands,
+ Scheme_Object **rands);
+static Scheme_Object *(*dll_scheme_builtin_value)(const char *name);
+# if MZSCHEME_VERSION_MAJOR >= 299
+static Scheme_Object *(*dll_scheme_byte_string_to_char_string)(Scheme_Object *s);
+static Scheme_Object *(*dll_scheme_make_path)(const char *chars);
+# endif
+static void (*dll_scheme_close_input_port)(Scheme_Object *port);
+static void (*dll_scheme_count_lines)(Scheme_Object *port);
+#if MZSCHEME_VERSION_MAJOR < 360
+static Scheme_Object *(*dll_scheme_current_continuation_marks)(void);
+#else
+static Scheme_Object *(*dll_scheme_current_continuation_marks)(Scheme_Object *prompt_tag);
+#endif
+static void (*dll_scheme_display)(Scheme_Object *obj, Scheme_Object *port);
+static char *(*dll_scheme_display_to_string)(Scheme_Object *obj, OUTPUT_LEN_TYPE *len);
+static int (*dll_scheme_eq)(Scheme_Object *obj1, Scheme_Object *obj2);
+static Scheme_Object *(*dll_scheme_do_eval)(Scheme_Object *obj,
+ int _num_rands, Scheme_Object **rands, int val);
+static void (*dll_scheme_dont_gc_ptr)(void *p);
+static Scheme_Object *(*dll_scheme_eval)(Scheme_Object *obj, Scheme_Env *env);
+static Scheme_Object *(*dll_scheme_eval_string)(const char *str,
+ Scheme_Env *env);
+static Scheme_Object *(*dll_scheme_eval_string_all)(const char *str,
+ Scheme_Env *env, int all);
+static void (*dll_scheme_finish_primitive_module)(Scheme_Env *env);
+# if MZSCHEME_VERSION_MAJOR < 299
+static char *(*dll_scheme_format)(char *format, int flen, int argc,
+ Scheme_Object **argv, long *rlen);
+# else
+static char *(*dll_scheme_format_utf8)(char *format, int flen, int argc,
+ Scheme_Object **argv, OUTPUT_LEN_TYPE *rlen);
+static Scheme_Object *(*dll_scheme_get_param)(Scheme_Config *c, int pos);
+# endif
+static void (*dll_scheme_gc_ptr_ok)(void *p);
+# if MZSCHEME_VERSION_MAJOR < 299
+static char *(*dll_scheme_get_sized_string_output)(Scheme_Object *,
+ long *len);
+# else
+static char *(*dll_scheme_get_sized_byte_string_output)(Scheme_Object *,
+ OUTPUT_LEN_TYPE *len);
+# endif
+static Scheme_Object *(*dll_scheme_intern_symbol)(const char *name);
+static Scheme_Object *(*dll_scheme_lookup_global)(Scheme_Object *symbol,
+ Scheme_Env *env);
+static Scheme_Object *(*dll_scheme_make_closed_prim_w_arity)
+ (Scheme_Closed_Prim *prim, void *data, const char *name, mzshort mina,
+ mzshort maxa);
+static Scheme_Object *(*dll_scheme_make_integer_value)(long i);
+static Scheme_Object *(*dll_scheme_make_pair)(Scheme_Object *car,
+ Scheme_Object *cdr);
+static Scheme_Object *(*dll_scheme_make_prim_w_arity)(Scheme_Prim *prim,
+ const char *name, mzshort mina, mzshort maxa);
+# if MZSCHEME_VERSION_MAJOR < 299
+static Scheme_Object *(*dll_scheme_make_string)(const char *chars);
+static Scheme_Object *(*dll_scheme_make_string_output_port)();
+# else
+static Scheme_Object *(*dll_scheme_make_byte_string)(const char *chars);
+static Scheme_Object *(*dll_scheme_make_byte_string_output_port)();
+# endif
+static Scheme_Object *(*dll_scheme_make_struct_instance)(Scheme_Object *stype,
+ int argc, Scheme_Object **argv);
+static Scheme_Object **(*dll_scheme_make_struct_names)(Scheme_Object *base,
+ Scheme_Object *field_names, int flags, int *count_out);
+static Scheme_Object *(*dll_scheme_make_struct_type)(Scheme_Object *base,
+ Scheme_Object *parent, Scheme_Object *inspector, int num_fields,
+ int num_uninit_fields, Scheme_Object *uninit_val,
+ Scheme_Object *properties
+# if MZSCHEME_VERSION_MAJOR >= 299
+ , Scheme_Object *guard
+# endif
+ );
+static Scheme_Object **(*dll_scheme_make_struct_values)(
+ Scheme_Object *struct_type, Scheme_Object **names, int count,
+ int flags);
+static Scheme_Type (*dll_scheme_make_type)(const char *name);
+static Scheme_Object *(*dll_scheme_make_vector)(int size,
+ Scheme_Object *fill);
+static void *(*dll_scheme_malloc_fail_ok)(void *(*f)(size_t), size_t);
+static Scheme_Object *(*dll_scheme_open_input_file)(const char *name,
+ const char *who);
+static Scheme_Env *(*dll_scheme_primitive_module)(Scheme_Object *name,
+ Scheme_Env *for_env);
+static int (*dll_scheme_proper_list_length)(Scheme_Object *list);
+static void (*dll_scheme_raise)(Scheme_Object *exn);
+static Scheme_Object *(*dll_scheme_read)(Scheme_Object *port);
+static void (*dll_scheme_signal_error)(const char *msg, ...);
+static void (*dll_scheme_wrong_type)(const char *name, const char *expected,
+ int which, int argc, Scheme_Object **argv);
+# if MZSCHEME_VERSION_MAJOR >= 299
+static void (*dll_scheme_set_param)(Scheme_Config *c, int pos,
+ Scheme_Object *o);
+static Scheme_Config *(*dll_scheme_current_config)(void);
+static Scheme_Object *(*dll_scheme_char_string_to_byte_string)
+ (Scheme_Object *s);
+static Scheme_Object *(*dll_scheme_char_string_to_path)
+ (Scheme_Object *s);
+static void *(*dll_scheme_set_collects_path)(Scheme_Object *p);
+# endif
+static Scheme_Hash_Table *(*dll_scheme_make_hash_table)(int type);
+static void (*dll_scheme_hash_set)(Scheme_Hash_Table *table,
+ Scheme_Object *key, Scheme_Object *value);
+static Scheme_Object *(*dll_scheme_hash_get)(Scheme_Hash_Table *table,
+ Scheme_Object *key);
+static Scheme_Object *(*dll_scheme_make_double)(double d);
+static Scheme_Object *(*dll_scheme_make_sized_byte_string)(char *chars,
+ long len, int copy);
+static Scheme_Object *(*dll_scheme_namespace_require)(Scheme_Object *req);
+static Scheme_Object *(*dll_scheme_dynamic_wind)(void (*pre)(void *), Scheme_Object *(* volatile act)(void *), void (* volatile post)(void *), Scheme_Object *(*jmp_handler)(void *), void * volatile data);
+# ifdef MZ_PRECISE_GC
+static void *(*dll_GC_malloc_one_tagged)(size_t size_in_bytes);
+static void (*dll_GC_register_traversers)(short tag, Size_Proc size, Mark_Proc mark, Fixup_Proc fixup, int is_constant_size, int is_atomic);
+# endif
+# if MZSCHEME_VERSION_MAJOR >= 400
+static void (*dll_scheme_init_collection_paths)(Scheme_Env *global_env, Scheme_Object *extra_dirs);
+static void **(*dll_scheme_malloc_immobile_box)(void *p);
+static void (*dll_scheme_free_immobile_box)(void **b);
+# endif
+# if MZSCHEME_VERSION_MAJOR >= 500
+# ifdef TRAMPOLINED_MZVIM_STARTUP
+static int (*dll_scheme_main_setup)(int no_auto_statics, Scheme_Env_Main _main, int argc, char **argv);
+# if defined(IMPLEMENT_THREAD_LOCAL_VIA_WIN_TLS) || MZSCHEME_VERSION_MAJOR >= 603
+static void (*dll_scheme_register_tls_space)(void *tls_space, int _tls_index);
+# endif
+# endif
+# if defined(IMPLEMENT_THREAD_LOCAL_VIA_WIN_TLS) || defined(IMPLEMENT_THREAD_LOCAL_EXTERNALLY_VIA_PROC)
+static Thread_Local_Variables *(*dll_scheme_external_get_thread_local_variables)(void);
+# endif
+# endif
+# if MZSCHEME_VERSION_MAJOR >= 600
+static void (*dll_scheme_embedded_load)(intptr_t len, const char *s, int predefined);
+static void (*dll_scheme_register_embedded_load)(intptr_t len, const char *s);
+static void (*dll_scheme_set_config_path)(Scheme_Object *p);
+# endif
+
+#if defined(DYNAMIC_MZSCHEME) /* not when defined(PROTO) */
+
+/* arrays are imported directly */
+# define scheme_eof dll_scheme_eof
+# define scheme_false dll_scheme_false
+# define scheme_void dll_scheme_void
+# define scheme_null dll_scheme_null
+# define scheme_true dll_scheme_true
+
+/* pointers are GetProceAddress'ed as pointers to pointer */
+#if !defined(USE_THREAD_LOCAL) && !defined(LINK_EXTENSIONS_BY_TABLE)
+# define scheme_current_thread (*dll_scheme_current_thread_ptr)
+# endif
+# define scheme_console_printf (*dll_scheme_console_printf_ptr)
+# define scheme_console_output (*dll_scheme_console_output_ptr)
+# define scheme_notify_multithread (*dll_scheme_notify_multithread_ptr)
+
+/* and functions in a usual way */
+# define GC_malloc dll_GC_malloc
+# define GC_malloc_atomic dll_GC_malloc_atomic
+
+# define scheme_add_global dll_scheme_add_global
+# define scheme_add_global_symbol dll_scheme_add_global_symbol
+# define scheme_apply dll_scheme_apply
+# define scheme_basic_env dll_scheme_basic_env
+# define scheme_builtin_value dll_scheme_builtin_value
+# if MZSCHEME_VERSION_MAJOR >= 299
+# define scheme_byte_string_to_char_string dll_scheme_byte_string_to_char_string
+# define scheme_make_path dll_scheme_make_path
+# endif
+# define scheme_check_threads dll_scheme_check_threads
+# define scheme_close_input_port dll_scheme_close_input_port
+# define scheme_count_lines dll_scheme_count_lines
+# define scheme_current_continuation_marks \
+ dll_scheme_current_continuation_marks
+# define scheme_display dll_scheme_display
+# define scheme_display_to_string dll_scheme_display_to_string
+# define scheme_do_eval dll_scheme_do_eval
+# define scheme_dont_gc_ptr dll_scheme_dont_gc_ptr
+# define scheme_eq dll_scheme_eq
+# define scheme_eval dll_scheme_eval
+# define scheme_eval_string dll_scheme_eval_string
+# define scheme_eval_string_all dll_scheme_eval_string_all
+# define scheme_finish_primitive_module dll_scheme_finish_primitive_module
+# if MZSCHEME_VERSION_MAJOR < 299
+# define scheme_format dll_scheme_format
+# else
+# define scheme_format_utf8 dll_scheme_format_utf8
+# endif
+# define scheme_gc_ptr_ok dll_scheme_gc_ptr_ok
+# if MZSCHEME_VERSION_MAJOR < 299
+# define scheme_get_sized_byte_string_output dll_scheme_get_sized_string_output
+# else
+# define scheme_get_sized_byte_string_output \
+ dll_scheme_get_sized_byte_string_output
+# define scheme_get_param dll_scheme_get_param
+# endif
+# define scheme_intern_symbol dll_scheme_intern_symbol
+# define scheme_lookup_global dll_scheme_lookup_global
+# define scheme_make_closed_prim_w_arity dll_scheme_make_closed_prim_w_arity
+# define scheme_make_integer_value dll_scheme_make_integer_value
+# define scheme_make_pair dll_scheme_make_pair
+# define scheme_make_prim_w_arity dll_scheme_make_prim_w_arity
+# if MZSCHEME_VERSION_MAJOR < 299
+# define scheme_make_byte_string dll_scheme_make_string
+# define scheme_make_byte_string_output_port dll_scheme_make_string_output_port
+# else
+# define scheme_make_byte_string dll_scheme_make_byte_string
+# define scheme_make_byte_string_output_port \
+ dll_scheme_make_byte_string_output_port
+# endif
+# define scheme_make_struct_instance dll_scheme_make_struct_instance
+# define scheme_make_struct_names dll_scheme_make_struct_names
+# define scheme_make_struct_type dll_scheme_make_struct_type
+# define scheme_make_struct_values dll_scheme_make_struct_values
+# define scheme_make_type dll_scheme_make_type
+# define scheme_make_vector dll_scheme_make_vector
+# define scheme_malloc_fail_ok dll_scheme_malloc_fail_ok
+# define scheme_open_input_file dll_scheme_open_input_file
+# define scheme_primitive_module dll_scheme_primitive_module
+# define scheme_proper_list_length dll_scheme_proper_list_length
+# define scheme_raise dll_scheme_raise
+# define scheme_read dll_scheme_read
+# define scheme_register_static dll_scheme_register_static
+# define scheme_set_stack_base dll_scheme_set_stack_base
+# define scheme_signal_error dll_scheme_signal_error
+# define scheme_wrong_type dll_scheme_wrong_type
+# if MZSCHEME_VERSION_MAJOR >= 299
+# define scheme_set_param dll_scheme_set_param
+# define scheme_current_config dll_scheme_current_config
+# define scheme_char_string_to_byte_string \
+ dll_scheme_char_string_to_byte_string
+# define scheme_char_string_to_path \
+ dll_scheme_char_string_to_path
+# define scheme_set_collects_path dll_scheme_set_collects_path
+# endif
+# define scheme_make_hash_table dll_scheme_make_hash_table
+# define scheme_hash_set dll_scheme_hash_set
+# define scheme_hash_get dll_scheme_hash_get
+# define scheme_make_double dll_scheme_make_double
+# define scheme_make_sized_byte_string dll_scheme_make_sized_byte_string
+# define scheme_namespace_require dll_scheme_namespace_require
+# define scheme_dynamic_wind dll_scheme_dynamic_wind
+# ifdef MZ_PRECISE_GC
+# define GC_malloc_one_tagged dll_GC_malloc_one_tagged
+# define GC_register_traversers dll_GC_register_traversers
+# endif
+# if MZSCHEME_VERSION_MAJOR >= 400
+# ifdef TRAMPOLINED_MZVIM_STARTUP
+# define scheme_main_setup dll_scheme_main_setup
+# if defined(IMPLEMENT_THREAD_LOCAL_VIA_WIN_TLS) || MZSCHEME_VERSION_MAJOR >= 603
+# define scheme_register_tls_space dll_scheme_register_tls_space
+# endif
+# endif
+# define scheme_init_collection_paths dll_scheme_init_collection_paths
+# define scheme_malloc_immobile_box dll_scheme_malloc_immobile_box
+# define scheme_free_immobile_box dll_scheme_free_immobile_box
+# endif
+# if MZSCHEME_VERSION_MAJOR >= 600
+# define scheme_embedded_load dll_scheme_embedded_load
+# define scheme_register_embedded_load dll_scheme_register_embedded_load
+# define scheme_set_config_path dll_scheme_set_config_path
+# endif
+
+# if MZSCHEME_VERSION_MAJOR >= 500
+# if defined(IMPLEMENT_THREAD_LOCAL_VIA_WIN_TLS) || defined(IMPLEMENT_THREAD_LOCAL_EXTERNALLY_VIA_PROC)
+/* define as function for macro in schthread.h */
+Thread_Local_Variables *
+scheme_external_get_thread_local_variables(void)
+{
+ return dll_scheme_external_get_thread_local_variables();
+}
+# endif
+# endif
+
+#endif
+
+typedef struct
+{
+ char *name;
+ void **ptr;
+} Thunk_Info;
+
+static Thunk_Info mzgc_imports[] = {
+ {"GC_malloc", (void **)&dll_GC_malloc},
+ {"GC_malloc_atomic", (void **)&dll_GC_malloc_atomic},
+ {NULL, NULL}};
+
+static Thunk_Info mzsch_imports[] = {
+ {"scheme_eof", (void **)&dll_scheme_eof},
+ {"scheme_false", (void **)&dll_scheme_false},
+ {"scheme_void", (void **)&dll_scheme_void},
+ {"scheme_null", (void **)&dll_scheme_null},
+ {"scheme_true", (void **)&dll_scheme_true},
+#if !defined(USE_THREAD_LOCAL) && !defined(LINK_EXTENSIONS_BY_TABLE)
+ {"scheme_current_thread", (void **)&dll_scheme_current_thread_ptr},
+#endif
+ {"scheme_console_printf", (void **)&dll_scheme_console_printf_ptr},
+ {"scheme_console_output", (void **)&dll_scheme_console_output_ptr},
+ {"scheme_notify_multithread",
+ (void **)&dll_scheme_notify_multithread_ptr},
+ {"scheme_add_global", (void **)&dll_scheme_add_global},
+ {"scheme_add_global_symbol", (void **)&dll_scheme_add_global_symbol},
+ {"scheme_apply", (void **)&dll_scheme_apply},
+ {"scheme_basic_env", (void **)&dll_scheme_basic_env},
+# if MZSCHEME_VERSION_MAJOR >= 299
+ {"scheme_byte_string_to_char_string", (void **)&dll_scheme_byte_string_to_char_string},
+ {"scheme_make_path", (void **)&dll_scheme_make_path},
+# endif
+ {"scheme_builtin_value", (void **)&dll_scheme_builtin_value},
+ {"scheme_check_threads", (void **)&dll_scheme_check_threads},
+ {"scheme_close_input_port", (void **)&dll_scheme_close_input_port},
+ {"scheme_count_lines", (void **)&dll_scheme_count_lines},
+ {"scheme_current_continuation_marks",
+ (void **)&dll_scheme_current_continuation_marks},
+ {"scheme_display", (void **)&dll_scheme_display},
+ {"scheme_display_to_string", (void **)&dll_scheme_display_to_string},
+ {"scheme_do_eval", (void **)&dll_scheme_do_eval},
+ {"scheme_dont_gc_ptr", (void **)&dll_scheme_dont_gc_ptr},
+ {"scheme_eq", (void **)&dll_scheme_eq},
+ {"scheme_eval", (void **)&dll_scheme_eval},
+ {"scheme_eval_string", (void **)&dll_scheme_eval_string},
+ {"scheme_eval_string_all", (void **)&dll_scheme_eval_string_all},
+ {"scheme_finish_primitive_module",
+ (void **)&dll_scheme_finish_primitive_module},
+# if MZSCHEME_VERSION_MAJOR < 299
+ {"scheme_format", (void **)&dll_scheme_format},
+# else
+ {"scheme_format_utf8", (void **)&dll_scheme_format_utf8},
+ {"scheme_get_param", (void **)&dll_scheme_get_param},
+#endif
+ {"scheme_gc_ptr_ok", (void **)&dll_scheme_gc_ptr_ok},
+# if MZSCHEME_VERSION_MAJOR < 299
+ {"scheme_get_sized_string_output",
+ (void **)&dll_scheme_get_sized_string_output},
+# else
+ {"scheme_get_sized_byte_string_output",
+ (void **)&dll_scheme_get_sized_byte_string_output},
+#endif
+ {"scheme_intern_symbol", (void **)&dll_scheme_intern_symbol},
+ {"scheme_lookup_global", (void **)&dll_scheme_lookup_global},
+ {"scheme_make_closed_prim_w_arity",
+ (void **)&dll_scheme_make_closed_prim_w_arity},
+ {"scheme_make_integer_value", (void **)&dll_scheme_make_integer_value},
+ {"scheme_make_pair", (void **)&dll_scheme_make_pair},
+ {"scheme_make_prim_w_arity", (void **)&dll_scheme_make_prim_w_arity},
+# if MZSCHEME_VERSION_MAJOR < 299
+ {"scheme_make_string", (void **)&dll_scheme_make_string},
+ {"scheme_make_string_output_port",
+ (void **)&dll_scheme_make_string_output_port},
+# else
+ {"scheme_make_byte_string", (void **)&dll_scheme_make_byte_string},
+ {"scheme_make_byte_string_output_port",
+ (void **)&dll_scheme_make_byte_string_output_port},
+# endif
+ {"scheme_make_struct_instance",
+ (void **)&dll_scheme_make_struct_instance},
+ {"scheme_make_struct_names", (void **)&dll_scheme_make_struct_names},
+ {"scheme_make_struct_type", (void **)&dll_scheme_make_struct_type},
+ {"scheme_make_struct_values", (void **)&dll_scheme_make_struct_values},
+ {"scheme_make_type", (void **)&dll_scheme_make_type},
+ {"scheme_make_vector", (void **)&dll_scheme_make_vector},
+ {"scheme_malloc_fail_ok", (void **)&dll_scheme_malloc_fail_ok},
+ {"scheme_open_input_file", (void **)&dll_scheme_open_input_file},
+ {"scheme_primitive_module", (void **)&dll_scheme_primitive_module},
+ {"scheme_proper_list_length", (void **)&dll_scheme_proper_list_length},
+ {"scheme_raise", (void **)&dll_scheme_raise},
+ {"scheme_read", (void **)&dll_scheme_read},
+ {"scheme_register_static", (void **)&dll_scheme_register_static},
+ {"scheme_set_stack_base", (void **)&dll_scheme_set_stack_base},
+ {"scheme_signal_error", (void **)&dll_scheme_signal_error},
+ {"scheme_wrong_type", (void **)&dll_scheme_wrong_type},
+# if MZSCHEME_VERSION_MAJOR >= 299
+ {"scheme_set_param", (void **)&dll_scheme_set_param},
+ {"scheme_current_config", (void **)&dll_scheme_current_config},
+ {"scheme_char_string_to_byte_string",
+ (void **)&dll_scheme_char_string_to_byte_string},
+ {"scheme_char_string_to_path", (void **)&dll_scheme_char_string_to_path},
+ {"scheme_set_collects_path", (void **)&dll_scheme_set_collects_path},
+# endif
+ {"scheme_make_hash_table", (void **)&dll_scheme_make_hash_table},
+ {"scheme_hash_set", (void **)&dll_scheme_hash_set},
+ {"scheme_hash_get", (void **)&dll_scheme_hash_get},
+ {"scheme_make_double", (void **)&dll_scheme_make_double},
+ {"scheme_make_sized_byte_string", (void **)&dll_scheme_make_sized_byte_string},
+ {"scheme_namespace_require", (void **)&dll_scheme_namespace_require},
+ {"scheme_dynamic_wind", (void **)&dll_scheme_dynamic_wind},
+# ifdef MZ_PRECISE_GC
+ {"GC_malloc_one_tagged", (void **)&dll_GC_malloc_one_tagged},
+ {"GC_register_traversers", (void **)&dll_GC_register_traversers},
+# endif
+# if MZSCHEME_VERSION_MAJOR >= 400
+# ifdef TRAMPOLINED_MZVIM_STARTUP
+ {"scheme_main_setup", (void **)&dll_scheme_main_setup},
+# if defined(IMPLEMENT_THREAD_LOCAL_VIA_WIN_TLS) || MZSCHEME_VERSION_MAJOR >= 603
+ {"scheme_register_tls_space", (void **)&dll_scheme_register_tls_space},
+# endif
+# endif
+ {"scheme_init_collection_paths", (void **)&dll_scheme_init_collection_paths},
+ {"scheme_malloc_immobile_box", (void **)&dll_scheme_malloc_immobile_box},
+ {"scheme_free_immobile_box", (void **)&dll_scheme_free_immobile_box},
+# endif
+# if MZSCHEME_VERSION_MAJOR >= 500
+# if defined(IMPLEMENT_THREAD_LOCAL_VIA_WIN_TLS) || defined(IMPLEMENT_THREAD_LOCAL_EXTERNALLY_VIA_PROC)
+ {"scheme_external_get_thread_local_variables", (void **)&dll_scheme_external_get_thread_local_variables},
+# endif
+# endif
+# if MZSCHEME_VERSION_MAJOR >= 600
+ {"scheme_embedded_load", (void **)&dll_scheme_embedded_load},
+ {"scheme_register_embedded_load", (void **)&dll_scheme_register_embedded_load},
+ {"scheme_set_config_path", (void **)&dll_scheme_set_config_path},
+# endif
+ {NULL, NULL}};
+
+static HINSTANCE hMzGC = 0;
+static HINSTANCE hMzSch = 0;
+
+static void dynamic_mzscheme_end(void);
+static int mzscheme_runtime_link_init(char *sch_dll, char *gc_dll,
+ int verbose);
+
+ static int
+mzscheme_runtime_link_init(char *sch_dll, char *gc_dll, int verbose)
+{
+ Thunk_Info *thunk = NULL;
+
+ if (hMzGC && hMzSch)
+ return OK;
+ hMzSch = vimLoadLib(sch_dll);
+ hMzGC = vimLoadLib(gc_dll);
+
+ if (!hMzGC)
+ {
+ if (verbose)
+ semsg(_(e_loadlib), gc_dll);
+ return FAIL;
+ }
+
+ if (!hMzSch)
+ {
+ if (verbose)
+ semsg(_(e_loadlib), sch_dll);
+ return FAIL;
+ }
+
+ for (thunk = mzsch_imports; thunk->name; thunk++)
+ {
+ if ((*thunk->ptr =
+ (void *)GetProcAddress(hMzSch, thunk->name)) == NULL)
+ {
+ FreeLibrary(hMzSch);
+ hMzSch = 0;
+ FreeLibrary(hMzGC);
+ hMzGC = 0;
+ if (verbose)
+ semsg(_(e_loadfunc), thunk->name);
+ return FAIL;
+ }
+ }
+ for (thunk = mzgc_imports; thunk->name; thunk++)
+ {
+ if ((*thunk->ptr =
+ (void *)GetProcAddress(hMzGC, thunk->name)) == NULL)
+ {
+ FreeLibrary(hMzSch);
+ hMzSch = 0;
+ FreeLibrary(hMzGC);
+ hMzGC = 0;
+ if (verbose)
+ semsg(_(e_loadfunc), thunk->name);
+ return FAIL;
+ }
+ }
+ return OK;
+}
+
+ int
+mzscheme_enabled(int verbose)
+{
+ return mzscheme_runtime_link_init(
+ (char *)p_mzschemedll, (char *)p_mzschemegcdll, verbose) == OK;
+}
+
+ static void
+dynamic_mzscheme_end(void)
+{
+ if (hMzSch)
+ {
+ FreeLibrary(hMzSch);
+ hMzSch = 0;
+ }
+ if (hMzGC)
+ {
+ FreeLibrary(hMzGC);
+ hMzGC = 0;
+ }
+}
+#endif /* DYNAMIC_MZSCHEME */
+
+#if MZSCHEME_VERSION_MAJOR < 299
+# define GUARANTEED_STRING_ARG(proc, num) GUARANTEE_STRING(proc, num)
+#else
+ static Scheme_Object *
+guaranteed_byte_string_arg(char *proc, int num, int argc, Scheme_Object **argv)
+{
+ if (SCHEME_BYTE_STRINGP(argv[num]))
+ {
+ return argv[num];
+ }
+ else if (SCHEME_CHAR_STRINGP(argv[num]))
+ {
+ Scheme_Object *tmp = NULL;
+ MZ_GC_DECL_REG(2);
+ MZ_GC_VAR_IN_REG(0, argv[num]);
+ MZ_GC_VAR_IN_REG(1, tmp);
+ MZ_GC_REG();
+ tmp = scheme_char_string_to_byte_string(argv[num]);
+ MZ_GC_UNREG();
+ return tmp;
+ }
+ else
+ scheme_wrong_type(proc, "string", num, argc, argv);
+ /* unreachable */
+ return scheme_void;
+}
+# define GUARANTEED_STRING_ARG(proc, num) guaranteed_byte_string_arg(proc, num, argc, argv)
+#endif
+
+/* need to put it here for dynamic stuff to work */
+#if defined(INCLUDE_MZSCHEME_BASE)
+# include "mzscheme_base.c"
+#endif
+
+/*
+ *========================================================================
+ * 1. MzScheme interpreter startup
+ *========================================================================
+ */
+
+static Scheme_Type mz_buffer_type;
+static Scheme_Type mz_window_type;
+
+static int initialized = FALSE;
+#ifdef DYNAMIC_MZSCHEME
+static int disabled = FALSE;
+#endif
+static int load_base_module_failed = FALSE;
+
+/* global environment */
+static Scheme_Env *environment = NULL;
+/* output/error handlers */
+static Scheme_Object *curout = NULL;
+static Scheme_Object *curerr = NULL;
+/* exn:vim exception */
+static Scheme_Object *exn_catching_apply = NULL;
+static Scheme_Object *exn_p = NULL;
+static Scheme_Object *exn_message = NULL;
+static Scheme_Object *vim_exn = NULL; /* Vim Error exception */
+
+#if !defined(MZ_PRECISE_GC) || MZSCHEME_VERSION_MAJOR < 400
+static void *stack_base = NULL;
+#endif
+
+static long range_start;
+static long range_end;
+
+/* MzScheme threads scheduling stuff */
+static int mz_threads_allow = 0;
+
+#if defined(FEAT_GUI_W32)
+static void CALLBACK timer_proc(HWND, UINT, UINT_PTR, DWORD);
+static UINT timer_id = 0;
+#elif defined(FEAT_GUI_GTK)
+static gboolean timer_proc(gpointer);
+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
+
+#ifndef FEAT_GUI_W32 /* Win32 console and Unix */
+ void
+mzvim_check_threads(void)
+{
+ /* Last time MzScheme threads were scheduled */
+ static time_t mz_last_time = 0;
+
+ if (mz_threads_allow && p_mzq > 0)
+ {
+ time_t now = time(NULL);
+
+ if ((now - mz_last_time) * 1000 > p_mzq)
+ {
+ mz_last_time = now;
+ scheme_check_threads();
+ }
+ }
+}
+#endif
+
+#if defined(MZSCHEME_GUI_THREADS) || defined(PROTO)
+static void setup_timer(void);
+static void remove_timer(void);
+
+/* timers are presented in GUI only */
+# if defined(FEAT_GUI_W32)
+ static void CALLBACK
+timer_proc(HWND hwnd UNUSED, UINT uMsg UNUSED, UINT_PTR idEvent UNUSED, DWORD dwTime UNUSED)
+# elif defined(FEAT_GUI_GTK)
+ static gboolean
+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();
+# if defined(FEAT_GUI_GTK)
+ return TRUE; /* continue receiving notifications */
+# elif defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA)
+ /* renew timeout */
+ if (mz_threads_allow && p_mzq > 0)
+ timer_id = XtAppAddTimeOut(app_context, p_mzq,
+ timer_proc, NULL);
+# endif
+}
+
+ static void
+setup_timer(void)
+{
+# if defined(FEAT_GUI_W32)
+ timer_id = SetTimer(NULL, 0, p_mzq, timer_proc);
+# elif defined(FEAT_GUI_GTK)
+ 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
+}
+
+ static void
+remove_timer(void)
+{
+# if defined(FEAT_GUI_W32)
+ KillTimer(NULL, timer_id);
+# elif defined(FEAT_GUI_GTK)
+ 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;
+}
+
+ void
+mzvim_reset_timer(void)
+{
+ if (timer_id != 0)
+ remove_timer();
+ if (mz_threads_allow && p_mzq > 0 && gui.in_use)
+ setup_timer();
+}
+
+#endif /* MZSCHEME_GUI_THREADS */
+
+ static void
+notify_multithread(int on)
+{
+ mz_threads_allow = on;
+#ifdef MZSCHEME_GUI_THREADS
+ if (on && timer_id == 0 && p_mzq > 0 && gui.in_use)
+ setup_timer();
+ if (!on && timer_id != 0)
+ remove_timer();
+#endif
+}
+
+ void
+mzscheme_end(void)
+{
+ /* We can not unload the DLL. Racket's thread might be still alive. */
+#if 0
+#ifdef DYNAMIC_MZSCHEME
+ dynamic_mzscheme_end();
+#endif
+#endif
+}
+
+#if HAVE_TLS_SPACE
+# if defined(_MSC_VER)
+static __declspec(thread) void *tls_space;
+extern intptr_t _tls_index;
+# elif defined(__MINGW32__)
+static __thread void *tls_space;
+extern intptr_t _tls_index;
+# else
+static THREAD_LOCAL void *tls_space;
+static intptr_t _tls_index = 0;
+# endif
+#endif
+
+/*
+ * mzscheme_main() is called early in main().
+ * We may call scheme_main_setup() which calls mzscheme_env_main() which then
+ * trampolines into vim_main2(), which never returns.
+ */
+ int
+mzscheme_main(void)
+{
+ int argc = 0;
+ char *argv = NULL;
+
+#ifdef DYNAMIC_MZSCHEME
+ /*
+ * Racket requires trampolined startup. We can not load it later.
+ * If dynamic dll loading is failed, disable it.
+ */
+ if (!mzscheme_enabled(FALSE))
+ {
+ disabled = TRUE;
+ return vim_main2();
+ }
+#endif
+#ifdef HAVE_TLS_SPACE
+ scheme_register_tls_space(&tls_space, _tls_index);
+#endif
+#ifdef TRAMPOLINED_MZVIM_STARTUP
+ return scheme_main_setup(TRUE, mzscheme_env_main, argc, &argv);
+#else
+ return mzscheme_env_main(NULL, argc, &argv);
+#endif
+}
+
+ static int
+mzscheme_env_main(Scheme_Env *env, int argc UNUSED, char **argv UNUSED)
+{
+#ifdef TRAMPOLINED_MZVIM_STARTUP
+ /* Scheme has created the environment for us */
+ environment = env;
+#else
+# ifdef MZ_PRECISE_GC
+ Scheme_Object *dummy = NULL;
+ MZ_GC_DECL_REG(1);
+ MZ_GC_VAR_IN_REG(0, dummy);
+
+ stack_base = &__gc_var_stack__;
+# else
+ int dummy = 0;
+ stack_base = (void *)&dummy;
+# endif
+#endif
+
+ vim_main2();
+ /* not reached, vim_main2() will loop until exit() */
+
+ return 0;
+}
+
+ static Scheme_Object*
+load_base_module(void *data)
+{
+ scheme_namespace_require(scheme_intern_symbol((char *)data));
+ return scheme_null;
+}
+
+ static Scheme_Object *
+load_base_module_on_error(void *data UNUSED)
+{
+ load_base_module_failed = TRUE;
+ return scheme_null;
+}
+
+ static int
+startup_mzscheme(void)
+{
+#ifndef TRAMPOLINED_MZVIM_STARTUP
+ scheme_set_stack_base(stack_base, 1);
+#endif
+
+#ifndef TRAMPOLINED_MZVIM_STARTUP
+ /* in newer versions of precise GC the initial env has been created */
+ environment = scheme_basic_env();
+#endif
+
+ MZ_REGISTER_STATIC(environment);
+ MZ_REGISTER_STATIC(curout);
+ MZ_REGISTER_STATIC(curerr);
+ MZ_REGISTER_STATIC(exn_catching_apply);
+ MZ_REGISTER_STATIC(exn_p);
+ MZ_REGISTER_STATIC(exn_message);
+ MZ_REGISTER_STATIC(vim_exn);
+
+ MZ_GC_CHECK();
+
+#ifdef INCLUDE_MZSCHEME_BASE
+ /* invoke function from generated and included mzscheme_base.c */
+ declare_modules(environment);
+#endif
+
+ /* setup 'current-library-collection-paths' parameter */
+# if MZSCHEME_VERSION_MAJOR >= 299
+ {
+ Scheme_Object *coll_path = NULL;
+ int mustfree = FALSE;
+ char_u *s;
+
+ MZ_GC_DECL_REG(1);
+ MZ_GC_VAR_IN_REG(0, coll_path);
+ MZ_GC_REG();
+ /* workaround for dynamic loading on windows */
+ s = vim_getenv((char_u *)"PLTCOLLECTS", &mustfree);
+ if (s != NULL)
+ {
+ coll_path = scheme_make_path((char *)s);
+ MZ_GC_CHECK();
+ if (mustfree)
+ vim_free(s);
+ }
+# ifdef MZSCHEME_COLLECTS
+ if (coll_path == NULL)
+ {
+ coll_path = scheme_make_path(MZSCHEME_COLLECTS);
+ MZ_GC_CHECK();
+ }
+# endif
+ if (coll_path != NULL)
+ {
+ scheme_set_collects_path(coll_path);
+ MZ_GC_CHECK();
+ }
+ MZ_GC_UNREG();
+ }
+# else
+# ifdef MZSCHEME_COLLECTS
+ {
+ Scheme_Object *coll_string = NULL;
+ Scheme_Object *coll_pair = NULL;
+ Scheme_Config *config = NULL;
+
+ MZ_GC_DECL_REG(3);
+ MZ_GC_VAR_IN_REG(0, coll_string);
+ MZ_GC_VAR_IN_REG(1, coll_pair);
+ MZ_GC_VAR_IN_REG(2, config);
+ MZ_GC_REG();
+ coll_string = scheme_make_byte_string(MZSCHEME_COLLECTS);
+ MZ_GC_CHECK();
+ coll_pair = scheme_make_pair(coll_string, scheme_null);
+ MZ_GC_CHECK();
+ config = scheme_current_config();
+ MZ_GC_CHECK();
+ scheme_set_param(config, MZCONFIG_COLLECTION_PATHS, coll_pair);
+ MZ_GC_CHECK();
+ MZ_GC_UNREG();
+ }
+# endif
+#endif
+
+# if MZSCHEME_VERSION_MAJOR >= 600
+ {
+ Scheme_Object *config_path = NULL;
+ int mustfree = FALSE;
+ char_u *s;
+
+ MZ_GC_DECL_REG(1);
+ MZ_GC_VAR_IN_REG(0, config_path);
+ MZ_GC_REG();
+ /* workaround for dynamic loading on windows */
+ s = vim_getenv((char_u *)"PLTCONFIGDIR", &mustfree);
+ if (s != NULL)
+ {
+ config_path = scheme_make_path((char *)s);
+ MZ_GC_CHECK();
+ if (mustfree)
+ vim_free(s);
+ }
+#ifdef MZSCHEME_CONFIGDIR
+ if (config_path == NULL)
+ {
+ config_path = scheme_make_path(MZSCHEME_CONFIGDIR);
+ MZ_GC_CHECK();
+ }
+#endif
+ if (config_path != NULL)
+ {
+ scheme_set_config_path(config_path);
+ MZ_GC_CHECK();
+ }
+ MZ_GC_UNREG();
+ }
+# endif
+
+#if MZSCHEME_VERSION_MAJOR >= 400
+ scheme_init_collection_paths(environment, scheme_null);
+#endif
+
+ /*
+ * versions 4.x do not provide Scheme bindings by default
+ * we need to add them explicitly
+ */
+ {
+ /* use error handler to avoid abort */
+ scheme_dynamic_wind(NULL, load_base_module, NULL,
+ load_base_module_on_error, "racket/base");
+ if (load_base_module_failed)
+ {
+ load_base_module_failed = FALSE;
+ scheme_dynamic_wind(NULL, load_base_module, NULL,
+ load_base_module_on_error, "scheme/base");
+ if (load_base_module_failed)
+ return -1;
+ }
+ }
+
+ register_vim_exn();
+ /* use new environment to initialise exception handling */
+ init_exn_catching_apply();
+
+ /* redirect output */
+ scheme_console_output = do_output;
+ scheme_console_printf = do_printf;
+
+#ifdef HAVE_SANDBOX
+ {
+ Scheme_Object *make_security_guard = NULL;
+ MZ_GC_DECL_REG(1);
+ MZ_GC_VAR_IN_REG(0, make_security_guard);
+ MZ_GC_REG();
+
+#if MZSCHEME_VERSION_MAJOR < 400
+ {
+ Scheme_Object *make_security_guard_symbol = NULL;
+ MZ_GC_DECL_REG(1);
+ MZ_GC_VAR_IN_REG(0, make_security_guard_symbol);
+ MZ_GC_REG();
+ make_security_guard_symbol = scheme_intern_symbol("make-security-guard");
+ MZ_GC_CHECK();
+ make_security_guard = scheme_lookup_global(
+ make_security_guard_symbol, environment);
+ MZ_GC_UNREG();
+ }
+#else
+ make_security_guard = scheme_builtin_value("make-security-guard");
+ MZ_GC_CHECK();
+#endif
+
+ /* setup sandbox guards */
+ if (make_security_guard != NULL)
+ {
+ Scheme_Object *args[3] = {NULL, NULL, NULL};
+ Scheme_Object *guard = NULL;
+ Scheme_Config *config = NULL;
+ MZ_GC_DECL_REG(5);
+ MZ_GC_ARRAY_VAR_IN_REG(0, args, 3);
+ MZ_GC_VAR_IN_REG(3, guard);
+ MZ_GC_VAR_IN_REG(4, config);
+ MZ_GC_REG();
+ config = scheme_current_config();
+ MZ_GC_CHECK();
+ args[0] = scheme_get_param(config, MZCONFIG_SECURITY_GUARD);
+ MZ_GC_CHECK();
+ args[1] = scheme_make_prim_w_arity(sandbox_file_guard,
+ "sandbox-file-guard", 3, 3);
+ args[2] = scheme_make_prim_w_arity(sandbox_network_guard,
+ "sandbox-network-guard", 4, 4);
+ guard = scheme_apply(make_security_guard, 3, args);
+ MZ_GC_CHECK();
+ scheme_set_param(config, MZCONFIG_SECURITY_GUARD, guard);
+ MZ_GC_CHECK();
+ MZ_GC_UNREG();
+ }
+ MZ_GC_UNREG();
+ }
+#endif
+ /* Create buffer and window types for use in Scheme code */
+ mz_buffer_type = scheme_make_type("<vim-buffer>");
+ MZ_GC_CHECK();
+ mz_window_type = scheme_make_type("<vim-window>");
+ MZ_GC_CHECK();
+#ifdef MZ_PRECISE_GC
+ GC_register_traversers(mz_buffer_type,
+ buffer_size_proc, buffer_mark_proc, buffer_fixup_proc,
+ TRUE, TRUE);
+ GC_register_traversers(mz_window_type,
+ window_size_proc, window_mark_proc, window_fixup_proc,
+ TRUE, TRUE);
+#endif
+
+ make_modules();
+
+ /*
+ * setup callback to receive notifications
+ * whether thread scheduling is (or not) required
+ */
+ scheme_notify_multithread = notify_multithread;
+
+ return 0;
+}
+
+/*
+ * This routine is called for each new invocation of MzScheme
+ * to make sure things are properly initialized.
+ */
+ static int
+mzscheme_init(void)
+{
+ if (!initialized)
+ {
+#ifdef DYNAMIC_MZSCHEME
+ if (disabled || !mzscheme_enabled(TRUE))
+ {
+ emsg(_("E815: Sorry, this command is disabled, the MzScheme libraries could not be loaded."));
+ return -1;
+ }
+#endif
+ if (load_base_module_failed || startup_mzscheme())
+ {
+ emsg(_("E895: Sorry, this command is disabled, the MzScheme's racket/base module could not be loaded."));
+ return -1;
+ }
+ initialized = TRUE;
+ }
+ {
+ Scheme_Config *config = NULL;
+ MZ_GC_DECL_REG(1);
+ MZ_GC_VAR_IN_REG(0, config);
+ MZ_GC_REG();
+ config = scheme_current_config();
+ MZ_GC_CHECK();
+ /* recreate ports each call effectively clearing these ones */
+ curout = scheme_make_byte_string_output_port();
+ MZ_GC_CHECK();
+ curerr = scheme_make_byte_string_output_port();
+ MZ_GC_CHECK();
+ scheme_set_param(config, MZCONFIG_OUTPUT_PORT, curout);
+ MZ_GC_CHECK();
+ scheme_set_param(config, MZCONFIG_ERROR_PORT, curerr);
+ MZ_GC_CHECK();
+ MZ_GC_UNREG();
+ }
+
+ return 0;
+}
+
+/*
+ *========================================================================
+ * 2. External Interface
+ *========================================================================
+ */
+
+/*
+ * Evaluate command with exception handling
+ */
+ static int
+eval_with_exn_handling(void *data, Scheme_Closed_Prim *what, Scheme_Object **ret)
+{
+ Scheme_Object *value = NULL;
+ Scheme_Object *exn = NULL;
+ Scheme_Object *prim = NULL;
+
+ MZ_GC_DECL_REG(3);
+ MZ_GC_VAR_IN_REG(0, value);
+ MZ_GC_VAR_IN_REG(1, exn);
+ MZ_GC_VAR_IN_REG(2, prim);
+ MZ_GC_REG();
+
+ prim = scheme_make_closed_prim_w_arity(what, data, "mzvim", 0, 0);
+ MZ_GC_CHECK();
+ value = _apply_thunk_catch_exceptions(prim, &exn);
+ MZ_GC_CHECK();
+
+ if (!value)
+ {
+ value = extract_exn_message(exn);
+ /* Got an exn? */
+ if (value)
+ {
+ scheme_display(value, curerr); /* Send to stderr-vim */
+ MZ_GC_CHECK();
+ do_flush();
+ }
+ MZ_GC_UNREG();
+ /* `raise' was called on some arbitrary value */
+ return FAIL;
+ }
+
+ if (ret != NULL) /* if pointer to retval supported give it up */
+ *ret = value;
+ /* Print any result, as long as it's not a void */
+ else if (!SCHEME_VOIDP(value))
+ {
+ scheme_display(value, curout); /* Send to stdout-vim */
+ MZ_GC_CHECK();
+ }
+
+ do_flush();
+ MZ_GC_UNREG();
+ return OK;
+}
+
+/* :mzscheme */
+ static int
+do_mzscheme_command(exarg_T *eap, void *data, Scheme_Closed_Prim *what)
+{
+ if (mzscheme_init())
+ return FAIL;
+
+ range_start = eap->line1;
+ range_end = eap->line2;
+
+ return eval_with_exn_handling(data, what, NULL);
+}
+
+/*
+ * Routine called by VIM when deleting a buffer
+ */
+ void
+mzscheme_buffer_free(buf_T *buf)
+{
+ if (buf->b_mzscheme_ref)
+ {
+ vim_mz_buffer *bp = NULL;
+ MZ_GC_DECL_REG(1);
+ MZ_GC_VAR_IN_REG(0, bp);
+ MZ_GC_REG();
+
+ bp = BUFFER_REF(buf);
+ bp->buf = INVALID_BUFFER_VALUE;
+#ifndef MZ_PRECISE_GC
+ scheme_gc_ptr_ok(bp);
+#else
+ scheme_free_immobile_box(buf->b_mzscheme_ref);
+#endif
+ buf->b_mzscheme_ref = NULL;
+ MZ_GC_CHECK();
+ MZ_GC_UNREG();
+ }
+}
+
+/*
+ * Routine called by VIM when deleting a Window
+ */
+ void
+mzscheme_window_free(win_T *win)
+{
+ if (win->w_mzscheme_ref)
+ {
+ vim_mz_window *wp = NULL;
+ MZ_GC_DECL_REG(1);
+ MZ_GC_VAR_IN_REG(0, wp);
+ MZ_GC_REG();
+ wp = WINDOW_REF(win);
+ wp->win = INVALID_WINDOW_VALUE;
+#ifndef MZ_PRECISE_GC
+ scheme_gc_ptr_ok(wp);
+#else
+ scheme_free_immobile_box(win->w_mzscheme_ref);
+#endif
+ win->w_mzscheme_ref = NULL;
+ MZ_GC_CHECK();
+ MZ_GC_UNREG();
+ }
+}
+
+/*
+ * ":mzscheme" (or ":mz")
+ */
+ void
+ex_mzscheme(exarg_T *eap)
+{
+ char_u *script;
+
+ script = script_get(eap, eap->arg);
+ if (!eap->skip)
+ {
+ if (script == NULL)
+ do_mzscheme_command(eap, eap->arg, do_eval);
+ else
+ {
+ do_mzscheme_command(eap, script, do_eval);
+ vim_free(script);
+ }
+ }
+}
+
+ static Scheme_Object *
+do_load(void *data, int noargc UNUSED, Scheme_Object **noargv UNUSED)
+{
+ Scheme_Object *expr = NULL;
+ Scheme_Object *result = NULL;
+ char *file = NULL;
+ Port_Info *pinfo = (Port_Info *)data;
+
+ MZ_GC_DECL_REG(3);
+ MZ_GC_VAR_IN_REG(0, expr);
+ MZ_GC_VAR_IN_REG(1, result);
+ MZ_GC_VAR_IN_REG(2, file);
+ MZ_GC_REG();
+
+ file = (char *)scheme_malloc_fail_ok(scheme_malloc_atomic, MAXPATHL + 1);
+ MZ_GC_CHECK();
+
+ /* make Vim expansion */
+ expand_env((char_u *)pinfo->name, (char_u *)file, MAXPATHL);
+ pinfo->port = scheme_open_input_file(file, "mzfile");
+ MZ_GC_CHECK();
+ scheme_count_lines(pinfo->port); /* to get accurate read error location*/
+ MZ_GC_CHECK();
+
+ /* Like REPL but print only last result */
+ while (!SCHEME_EOFP(expr = scheme_read(pinfo->port)))
+ {
+ result = scheme_eval(expr, environment);
+ MZ_GC_CHECK();
+ }
+
+ /* errors will be caught in do_mzscheme_command and ex_mzfile */
+ scheme_close_input_port(pinfo->port);
+ MZ_GC_CHECK();
+ pinfo->port = NULL;
+ MZ_GC_UNREG();
+ return result;
+}
+
+/* :mzfile */
+ void
+ex_mzfile(exarg_T *eap)
+{
+ Port_Info pinfo = {NULL, NULL};
+
+ MZ_GC_DECL_REG(1);
+ MZ_GC_VAR_IN_REG(0, pinfo.port);
+ MZ_GC_REG();
+
+ pinfo.name = (char *)eap->arg;
+ if (do_mzscheme_command(eap, &pinfo, do_load) != OK
+ && pinfo.port != NULL) /* looks like port was not closed */
+ {
+ scheme_close_input_port(pinfo.port);
+ MZ_GC_CHECK();
+ }
+ MZ_GC_UNREG();
+}
+
+
+/*
+ *========================================================================
+ * Exception handling code -- cribbed form the MzScheme sources and
+ * Matthew Flatt's "Inside PLT MzScheme" document.
+ *========================================================================
+ */
+ static void
+init_exn_catching_apply(void)
+{
+ if (!exn_catching_apply)
+ {
+ char *e =
+ "(lambda (thunk) "
+ "(with-handlers ([void (lambda (exn) (cons #f exn))]) "
+ "(cons #t (thunk))))";
+
+ exn_catching_apply = scheme_eval_string(e, environment);
+ MZ_GC_CHECK();
+ exn_p = scheme_builtin_value("exn?");
+ MZ_GC_CHECK();
+ exn_message = scheme_builtin_value("exn-message");
+ MZ_GC_CHECK();
+ }
+}
+
+/*
+ * This function applies a thunk, returning the Scheme value if there's
+ * no exception, otherwise returning NULL and setting *exn to the raised
+ * value (usually an exn structure).
+ */
+ static Scheme_Object *
+_apply_thunk_catch_exceptions(Scheme_Object *f, Scheme_Object **exn)
+{
+ Scheme_Object *v;
+
+ v = _scheme_apply(exn_catching_apply, 1, &f);
+ /* v is a pair: (cons #t value) or (cons #f exn) */
+
+ if (SCHEME_TRUEP(SCHEME_CAR(v)))
+ return SCHEME_CDR(v);
+ else
+ {
+ *exn = SCHEME_CDR(v);
+ return NULL;
+ }
+}
+
+ static Scheme_Object *
+extract_exn_message(Scheme_Object *v)
+{
+ if (SCHEME_TRUEP(_scheme_apply(exn_p, 1, &v)))
+ return _scheme_apply(exn_message, 1, &v);
+ else
+ return NULL; /* Not an exn structure */
+}
+
+ static Scheme_Object *
+do_eval(void *s, int noargc UNUSED, Scheme_Object **noargv UNUSED)
+{
+ return scheme_eval_string_all((char *)s, environment, TRUE);
+}
+
+/*
+ *========================================================================
+ * 3. MzScheme I/O Handlers
+ *========================================================================
+ */
+ static void
+do_intrnl_output(char *mesg, int error)
+{
+ char *p, *prev;
+
+ prev = mesg;
+ p = strchr(prev, '\n');
+ while (p)
+ {
+ *p = '\0';
+ if (error)
+ emsg(prev);
+ else
+ msg(prev);
+ prev = p + 1;
+ p = strchr(prev, '\n');
+ }
+
+ if (error)
+ emsg(prev);
+ else
+ msg(prev);
+}
+
+ static void
+do_output(char *mesg, OUTPUT_LEN_TYPE len UNUSED)
+{
+ /* TODO: use len, the string may not be NUL terminated */
+ do_intrnl_output(mesg, 0);
+}
+
+ static void
+do_err_output(char *mesg)
+{
+ do_intrnl_output(mesg, 1);
+}
+
+ static void
+do_printf(char *format, ...)
+{
+ do_intrnl_output(format, 1);
+}
+
+ static void
+do_flush(void)
+{
+ char *buff;
+ OUTPUT_LEN_TYPE length;
+
+ buff = scheme_get_sized_byte_string_output(curerr, &length);
+ MZ_GC_CHECK();
+ if (length)
+ {
+ do_err_output(buff);
+ return;
+ }
+
+ buff = scheme_get_sized_byte_string_output(curout, &length);
+ MZ_GC_CHECK();
+ if (length)
+ do_output(buff, length);
+}
+
+/*
+ *========================================================================
+ * 4. Implementation of the Vim Features for MzScheme
+ *========================================================================
+ */
+
+/* (command {command-string}) */
+ static Scheme_Object *
+vim_command(void *data, int argc, Scheme_Object **argv)
+{
+ Vim_Prim *prim = (Vim_Prim *)data;
+ Scheme_Object *cmd = NULL;
+ MZ_GC_DECL_REG(1);
+ MZ_GC_VAR_IN_REG(0, cmd);
+ MZ_GC_REG();
+ cmd = GUARANTEED_STRING_ARG(prim->name, 0);
+
+ /* may be use do_cmdline_cmd? */
+ do_cmdline(BYTE_STRING_VALUE(cmd), NULL, NULL, DOCMD_NOWAIT|DOCMD_VERBOSE);
+ update_screen(VALID);
+
+ MZ_GC_UNREG();
+ raise_if_error();
+ return scheme_void;
+}
+
+/* (eval {expr-string}) */
+ static Scheme_Object *
+vim_eval(void *data UNUSED, int argc UNUSED, Scheme_Object **argv UNUSED)
+{
+#ifdef FEAT_EVAL
+ Vim_Prim *prim = (Vim_Prim *)data;
+ Scheme_Object *result = NULL;
+ typval_T *vim_result;
+ Scheme_Object *expr = NULL;
+ MZ_GC_DECL_REG(2);
+ MZ_GC_VAR_IN_REG(0, result);
+ MZ_GC_VAR_IN_REG(1, expr);
+ MZ_GC_REG();
+ expr = GUARANTEED_STRING_ARG(prim->name, 0);
+
+ vim_result = eval_expr(BYTE_STRING_VALUE(expr), NULL);
+
+ if (vim_result == NULL)
+ raise_vim_exn(_("invalid expression"));
+
+ result = vim_to_mzscheme(vim_result);
+ MZ_GC_CHECK();
+ free_tv(vim_result);
+
+ MZ_GC_UNREG();
+ return result;
+#else
+ raise_vim_exn(_("expressions disabled at compile time"));
+ /* unreachable */
+ return scheme_false;
+#endif
+}
+
+/* (range-start) */
+ static Scheme_Object *
+get_range_start(void *data UNUSED, int argc UNUSED, Scheme_Object **argv UNUSED)
+{
+ return scheme_make_integer(range_start);
+}
+
+/* (range-end) */
+ static Scheme_Object *
+get_range_end(void *data UNUSED, int argc UNUSED, Scheme_Object **argv UNUSED)
+{
+ return scheme_make_integer(range_end);
+}
+
+/* (beep) */
+ static Scheme_Object *
+mzscheme_beep(void *data UNUSED, int argc UNUSED, Scheme_Object **argv UNUSED)
+{
+ vim_beep(BO_LANG);
+ return scheme_void;
+}
+
+static Scheme_Object *M_global = NULL;
+
+/* (get-option {option-name}) [buffer/window] */
+ static Scheme_Object *
+get_option(void *data, int argc, Scheme_Object **argv)
+{
+ Vim_Prim *prim = (Vim_Prim *)data;
+ long value;
+ char *strval;
+ int rc;
+ Scheme_Object *rval = NULL;
+ Scheme_Object *name = NULL;
+ int opt_flags = 0;
+ buf_T *save_curb = curbuf;
+ win_T *save_curw = curwin;
+
+ MZ_GC_DECL_REG(2);
+ MZ_GC_VAR_IN_REG(0, rval);
+ MZ_GC_VAR_IN_REG(1, name);
+ MZ_GC_REG();
+
+ name = GUARANTEED_STRING_ARG(prim->name, 0);
+
+ if (argc > 1)
+ {
+ if (M_global == NULL)
+ {
+ MZ_REGISTER_STATIC(M_global);
+ M_global = scheme_intern_symbol("global");
+ MZ_GC_CHECK();
+ }
+
+ if (argv[1] == M_global)
+ opt_flags = OPT_GLOBAL;
+ else if (SCHEME_VIMBUFFERP(argv[1]))
+ {
+ curbuf = get_valid_buffer(argv[1]);
+ opt_flags = OPT_LOCAL;
+ }
+ else if (SCHEME_VIMWINDOWP(argv[1]))
+ {
+ win_T *win = get_valid_window(argv[1]);
+
+ curwin = win;
+ curbuf = win->w_buffer;
+ opt_flags = OPT_LOCAL;
+ }
+ else
+ scheme_wrong_type(prim->name, "vim-buffer/window", 1, argc, argv);
+ }
+
+ rc = get_option_value(BYTE_STRING_VALUE(name), &value, (char_u **)&strval, opt_flags);
+ curbuf = save_curb;
+ curwin = save_curw;
+
+ switch (rc)
+ {
+ case 1:
+ MZ_GC_UNREG();
+ return scheme_make_integer_value(value);
+ case 0:
+ rval = scheme_make_byte_string(strval);
+ MZ_GC_CHECK();
+ vim_free(strval);
+ MZ_GC_UNREG();
+ return rval;
+ case -1:
+ case -2:
+ MZ_GC_UNREG();
+ raise_vim_exn(_("hidden option"));
+ case -3:
+ MZ_GC_UNREG();
+ raise_vim_exn(_("unknown option"));
+ }
+ /* unreachable */
+ return scheme_void;
+}
+
+/* (set-option {option-changing-string} [buffer/window]) */
+ static Scheme_Object *
+set_option(void *data, int argc, Scheme_Object **argv)
+{
+ char_u *command = NULL;
+ int opt_flags = 0;
+ buf_T *save_curb = curbuf;
+ win_T *save_curw = curwin;
+ Vim_Prim *prim = (Vim_Prim *)data;
+ Scheme_Object *cmd = NULL;
+
+ MZ_GC_DECL_REG(1);
+ MZ_GC_VAR_IN_REG(0, cmd);
+ MZ_GC_REG();
+ cmd = GUARANTEED_STRING_ARG(prim->name, 0);
+
+ if (argc > 1)
+ {
+ if (M_global == NULL)
+ {
+ MZ_REGISTER_STATIC(M_global);
+ M_global = scheme_intern_symbol("global");
+ MZ_GC_CHECK();
+ }
+
+ if (argv[1] == M_global)
+ opt_flags = OPT_GLOBAL;
+ else if (SCHEME_VIMBUFFERP(argv[1]))
+ {
+ curbuf = get_valid_buffer(argv[1]);
+ opt_flags = OPT_LOCAL;
+ }
+ else if (SCHEME_VIMWINDOWP(argv[1]))
+ {
+ win_T *win = get_valid_window(argv[1]);
+ curwin = win;
+ curbuf = win->w_buffer;
+ opt_flags = OPT_LOCAL;
+ }
+ else
+ scheme_wrong_type(prim->name, "vim-buffer/window", 1, argc, argv);
+ }
+
+ /* do_set can modify cmd, make copy */
+ command = vim_strsave(BYTE_STRING_VALUE(cmd));
+ MZ_GC_UNREG();
+ do_set(command, opt_flags);
+ vim_free(command);
+ update_screen(NOT_VALID);
+ curbuf = save_curb;
+ curwin = save_curw;
+ raise_if_error();
+ return scheme_void;
+}
+
+/*
+ *===========================================================================
+ * 5. Vim Window-related Manipulation Functions
+ *===========================================================================
+ */
+
+/* (curr-win) */
+ static Scheme_Object *
+get_curr_win(void *data UNUSED, int argc UNUSED, Scheme_Object **argv UNUSED)
+{
+ return (Scheme_Object *)get_vim_curr_window();
+}
+
+/* (win-count) */
+ static Scheme_Object *
+get_window_count(void *data UNUSED, int argc UNUSED, Scheme_Object **argv UNUSED)
+{
+ int n = 0;
+ win_T *w;
+
+ FOR_ALL_WINDOWS(w)
+ ++n;
+ return scheme_make_integer(n);
+}
+
+/* (get-win-list [buffer]) */
+ static Scheme_Object *
+get_window_list(void *data, int argc, Scheme_Object **argv)
+{
+ Vim_Prim *prim = (Vim_Prim *)data;
+ vim_mz_buffer *buf;
+ Scheme_Object *list;
+ win_T *w = firstwin;
+
+ buf = get_buffer_arg(prim->name, 0, argc, argv);
+ list = scheme_null;
+
+ for ( ; w != NULL; w = w->w_next)
+ if (w->w_buffer == buf->buf)
+ {
+ list = scheme_make_pair(window_new(w), list);
+ MZ_GC_CHECK();
+ }
+
+ return list;
+}
+
+ static Scheme_Object *
+window_new(win_T *win)
+{
+ vim_mz_window *self = NULL;
+
+ MZ_GC_DECL_REG(1);
+ MZ_GC_VAR_IN_REG(0, self);
+
+ /* We need to handle deletion of windows underneath us.
+ * If we add a "w_mzscheme_ref" field to the win_T structure,
+ * then we can get at it in win_free() in vim.
+ *
+ * On a win_free() we set the Scheme object's win_T *field
+ * to an invalid value. We trap all uses of a window
+ * object, and reject them if the win_T *field is invalid.
+ */
+ if (win->w_mzscheme_ref != NULL)
+ return (Scheme_Object *)WINDOW_REF(win);
+
+ MZ_GC_REG();
+ self = scheme_malloc_fail_ok(scheme_malloc_tagged, sizeof(vim_mz_window));
+ vim_memset(self, 0, sizeof(vim_mz_window));
+#ifndef MZ_PRECISE_GC
+ scheme_dont_gc_ptr(self); /* because win isn't visible to GC */
+#else
+ win->w_mzscheme_ref = scheme_malloc_immobile_box(NULL);
+#endif
+ MZ_GC_CHECK();
+ WINDOW_REF(win) = self;
+ MZ_GC_CHECK();
+ self->win = win;
+ self->so.type = mz_window_type;
+
+ MZ_GC_UNREG();
+ return (Scheme_Object *)self;
+}
+
+/* (get-win-num [window]) */
+ static Scheme_Object *
+get_window_num(void *data UNUSED, int argc UNUSED, Scheme_Object **argv UNUSED)
+{
+ int nr = 1;
+ Vim_Prim *prim = (Vim_Prim *)data;
+ win_T *win = get_window_arg(prim->name, 0, argc, argv)->win;
+ win_T *wp;
+
+ for (wp = firstwin; wp != win; wp = wp->w_next)
+ ++nr;
+
+ return scheme_make_integer(nr);
+}
+
+/* (get-win-by-num {windownum}) */
+ static Scheme_Object *
+get_window_by_num(void *data, int argc, Scheme_Object **argv)
+{
+ Vim_Prim *prim = (Vim_Prim *)data;
+ win_T *win = firstwin;
+ int fnum;
+
+ fnum = SCHEME_INT_VAL(GUARANTEE_INTEGER(prim->name, 0));
+ if (fnum < 1)
+ scheme_signal_error(_("window index is out of range"));
+
+ for ( ; win != NULL; win = win->w_next, --fnum)
+ if (fnum == 1) /* to be 1-based */
+ return window_new(win);
+
+ return scheme_false;
+}
+
+/* (get-win-buffer [window]) */
+ static Scheme_Object *
+get_window_buffer(void *data, int argc, Scheme_Object **argv)
+{
+ Vim_Prim *prim = (Vim_Prim *)data;
+ vim_mz_window *win = get_window_arg(prim->name, 0, argc, argv);
+
+ return buffer_new(win->win->w_buffer);
+}
+
+/* (get-win-height [window]) */
+ static Scheme_Object *
+get_window_height(void *data, int argc, Scheme_Object **argv)
+{
+ Vim_Prim *prim = (Vim_Prim *)data;
+ vim_mz_window *win = get_window_arg(prim->name, 0, argc, argv);
+
+ return scheme_make_integer(win->win->w_height);
+}
+
+/* (set-win-height {height} [window]) */
+ static Scheme_Object *
+set_window_height(void *data, int argc, Scheme_Object **argv)
+{
+ Vim_Prim *prim = (Vim_Prim *)data;
+ vim_mz_window *win;
+ win_T *savewin;
+ int height;
+
+ win = get_window_arg(prim->name, 1, argc, argv);
+ height = SCHEME_INT_VAL(GUARANTEE_INTEGER(prim->name, 0));
+
+#ifdef FEAT_GUI
+ need_mouse_correct = TRUE;
+#endif
+
+ savewin = curwin;
+ curwin = win->win;
+ win_setheight(height);
+ curwin = savewin;
+
+ raise_if_error();
+ return scheme_void;
+}
+
+/* (get-win-width [window]) */
+ static Scheme_Object *
+get_window_width(void *data, int argc, Scheme_Object **argv)
+{
+ Vim_Prim *prim = (Vim_Prim *)data;
+ vim_mz_window *win = get_window_arg(prim->name, 0, argc, argv);
+
+ return scheme_make_integer(win->win->w_width);
+}
+
+/* (set-win-width {width} [window]) */
+ static Scheme_Object *
+set_window_width(void *data, int argc, Scheme_Object **argv)
+{
+ Vim_Prim *prim = (Vim_Prim *)data;
+ vim_mz_window *win;
+ win_T *savewin;
+ int width = 0;
+
+ win = get_window_arg(prim->name, 1, argc, argv);
+ width = SCHEME_INT_VAL(GUARANTEE_INTEGER(prim->name, 0));
+
+# ifdef FEAT_GUI
+ need_mouse_correct = TRUE;
+# endif
+
+ savewin = curwin;
+ curwin = win->win;
+ win_setwidth(width);
+ curwin = savewin;
+
+ raise_if_error();
+ return scheme_void;
+}
+
+/* (get-cursor [window]) -> (line . col) */
+ static Scheme_Object *
+get_cursor(void *data, int argc, Scheme_Object **argv)
+{
+ Vim_Prim *prim = (Vim_Prim *)data;
+ vim_mz_window *win;
+ pos_T pos;
+
+ win = get_window_arg(prim->name, 0, argc, argv);
+ pos = win->win->w_cursor;
+ return scheme_make_pair(scheme_make_integer_value((long)pos.lnum),
+ scheme_make_integer_value((long)pos.col + 1));
+}
+
+/* (set-cursor (line . col) [window]) */
+ static Scheme_Object *
+set_cursor(void *data, int argc, Scheme_Object **argv)
+{
+ Vim_Prim *prim = (Vim_Prim *)data;
+ vim_mz_window *win;
+ long lnum = 0;
+ long col = 0;
+
+#ifdef HAVE_SANDBOX
+ sandbox_check();
+#endif
+ win = get_window_arg(prim->name, 1, argc, argv);
+ GUARANTEE_PAIR(prim->name, 0);
+
+ if (!SCHEME_INTP(SCHEME_CAR(argv[0]))
+ || !SCHEME_INTP(SCHEME_CDR(argv[0])))
+ scheme_wrong_type(prim->name, "integer pair", 0, argc, argv);
+
+ lnum = SCHEME_INT_VAL(SCHEME_CAR(argv[0]));
+ col = SCHEME_INT_VAL(SCHEME_CDR(argv[0])) - 1;
+
+ check_line_range(lnum, win->win->w_buffer);
+ /* don't know how to catch invalid column value */
+
+ win->win->w_cursor.lnum = lnum;
+ win->win->w_cursor.col = col;
+ win->win->w_set_curswant = TRUE;
+ update_screen(VALID);
+
+ raise_if_error();
+ return scheme_void;
+}
+/*
+ *===========================================================================
+ * 6. Vim Buffer-related Manipulation Functions
+ *===========================================================================
+ */
+
+/* (open-buff {filename}) */
+ static Scheme_Object *
+mzscheme_open_buffer(void *data, int argc, Scheme_Object **argv)
+{
+ Vim_Prim *prim = (Vim_Prim *)data;
+ int num = 0;
+ Scheme_Object *onum = NULL;
+ Scheme_Object *buf = NULL;
+ Scheme_Object *fname;
+
+ MZ_GC_DECL_REG(3);
+ MZ_GC_VAR_IN_REG(0, onum);
+ MZ_GC_VAR_IN_REG(1, buf);
+ MZ_GC_VAR_IN_REG(2, fname);
+ MZ_GC_REG();
+ fname = GUARANTEED_STRING_ARG(prim->name, 0);
+
+#ifdef HAVE_SANDBOX
+ sandbox_check();
+#endif
+ /* TODO make open existing file */
+ num = buflist_add(BYTE_STRING_VALUE(fname), BLN_LISTED | BLN_CURBUF);
+
+ if (num == 0)
+ raise_vim_exn(_("couldn't open buffer"));
+
+ onum = scheme_make_integer(num);
+ buf = get_buffer_by_num(data, 1, &onum);
+ MZ_GC_UNREG();
+ return buf;
+}
+
+/* (get-buff-by-num {buffernum}) */
+ static Scheme_Object *
+get_buffer_by_num(void *data, int argc, Scheme_Object **argv)
+{
+ Vim_Prim *prim = (Vim_Prim *)data;
+ buf_T *buf;
+ int fnum;
+
+ fnum = SCHEME_INT_VAL(GUARANTEE_INTEGER(prim->name, 0));
+
+ FOR_ALL_BUFFERS(buf)
+ if (buf->b_fnum == fnum)
+ return buffer_new(buf);
+
+ return scheme_false;
+}
+
+/* (get-buff-by-name {buffername}) */
+ static Scheme_Object *
+get_buffer_by_name(void *data, int argc, Scheme_Object **argv)
+{
+ Vim_Prim *prim = (Vim_Prim *)data;
+ buf_T *buf;
+ Scheme_Object *buffer = NULL;
+ Scheme_Object *fname = NULL;
+
+ MZ_GC_DECL_REG(2);
+ MZ_GC_VAR_IN_REG(0, buffer);
+ MZ_GC_VAR_IN_REG(1, fname);
+ MZ_GC_REG();
+ fname = GUARANTEED_STRING_ARG(prim->name, 0);
+ buffer = scheme_false;
+
+ FOR_ALL_BUFFERS(buf)
+ {
+ if (buf->b_ffname == NULL || buf->b_sfname == NULL)
+ /* empty string */
+ {
+ if (BYTE_STRING_VALUE(fname)[0] == NUL)
+ buffer = buffer_new(buf);
+ }
+ else if (!fnamecmp(buf->b_ffname, BYTE_STRING_VALUE(fname))
+ || !fnamecmp(buf->b_sfname, BYTE_STRING_VALUE(fname)))
+ {
+ /* either short or long filename matches */
+ buffer = buffer_new(buf);
+ }
+ }
+
+ MZ_GC_UNREG();
+ return buffer;
+}
+
+/* (get-next-buff [buffer]) */
+ static Scheme_Object *
+get_next_buffer(void *data, int argc, Scheme_Object **argv)
+{
+ Vim_Prim *prim = (Vim_Prim *)data;
+ buf_T *buf = get_buffer_arg(prim->name, 0, argc, argv)->buf;
+
+ if (buf->b_next == NULL)
+ return scheme_false;
+ else
+ return buffer_new(buf->b_next);
+}
+
+/* (get-prev-buff [buffer]) */
+ static Scheme_Object *
+get_prev_buffer(void *data, int argc, Scheme_Object **argv)
+{
+ Vim_Prim *prim = (Vim_Prim *)data;
+ buf_T *buf = get_buffer_arg(prim->name, 0, argc, argv)->buf;
+
+ if (buf->b_prev == NULL)
+ return scheme_false;
+ else
+ return buffer_new(buf->b_prev);
+}
+
+/* (get-buff-num [buffer]) */
+ static Scheme_Object *
+get_buffer_num(void *data, int argc, Scheme_Object **argv)
+{
+ Vim_Prim *prim = (Vim_Prim *)data;
+ vim_mz_buffer *buf = get_buffer_arg(prim->name, 0, argc, argv);
+
+ return scheme_make_integer(buf->buf->b_fnum);
+}
+
+/* (buff-count) */
+ static Scheme_Object *
+get_buffer_count(void *data UNUSED, int argc UNUSED, Scheme_Object **argv UNUSED)
+{
+ buf_T *b;
+ int n = 0;
+
+ FOR_ALL_BUFFERS(b) ++n;
+ return scheme_make_integer(n);
+}
+
+/* (get-buff-name [buffer]) */
+ static Scheme_Object *
+get_buffer_name(void *data, int argc, Scheme_Object **argv)
+{
+ Vim_Prim *prim = (Vim_Prim *)data;
+ vim_mz_buffer *buf = get_buffer_arg(prim->name, 0, argc, argv);
+
+ return scheme_make_byte_string((char *)buf->buf->b_ffname);
+}
+
+/* (curr-buff) */
+ static Scheme_Object *
+get_curr_buffer(void *data UNUSED, int argc UNUSED, Scheme_Object **argv UNUSED)
+{
+ return (Scheme_Object *)get_vim_curr_buffer();
+}
+
+ static Scheme_Object *
+buffer_new(buf_T *buf)
+{
+ vim_mz_buffer *self = NULL;
+
+ MZ_GC_DECL_REG(1);
+ MZ_GC_VAR_IN_REG(0, self);
+
+ /* We need to handle deletion of buffers underneath us.
+ * If we add a "b_mzscheme_ref" field to the buf_T structure,
+ * then we can get at it in buf_freeall() in vim.
+ */
+ if (buf->b_mzscheme_ref)
+ return (Scheme_Object *)BUFFER_REF(buf);
+
+ MZ_GC_REG();
+ self = scheme_malloc_fail_ok(scheme_malloc_tagged, sizeof(vim_mz_buffer));
+ vim_memset(self, 0, sizeof(vim_mz_buffer));
+#ifndef MZ_PRECISE_GC
+ scheme_dont_gc_ptr(self); /* because buf isn't visible to GC */
+#else
+ buf->b_mzscheme_ref = scheme_malloc_immobile_box(NULL);
+#endif
+ MZ_GC_CHECK();
+ BUFFER_REF(buf) = self;
+ MZ_GC_CHECK();
+ self->buf = buf;
+ self->so.type = mz_buffer_type;
+
+ MZ_GC_UNREG();
+ return (Scheme_Object *)self;
+}
+
+/*
+ * (get-buff-size [buffer])
+ *
+ * Get the size (number of lines) in the current buffer.
+ */
+ static Scheme_Object *
+get_buffer_size(void *data, int argc, Scheme_Object **argv)
+{
+ Vim_Prim *prim = (Vim_Prim *)data;
+ vim_mz_buffer *buf = get_buffer_arg(prim->name, 0, argc, argv);
+
+ return scheme_make_integer(buf->buf->b_ml.ml_line_count);
+}
+
+/*
+ * (get-buff-line {linenr} [buffer])
+ *
+ * Get a line from the specified buffer. The line number is
+ * in Vim format (1-based). The line is returned as a MzScheme
+ * string object.
+ */
+ static Scheme_Object *
+get_buffer_line(void *data, int argc, Scheme_Object **argv)
+{
+ Vim_Prim *prim = (Vim_Prim *)data;
+ vim_mz_buffer *buf;
+ int linenr;
+ char_u *line;
+
+ buf = get_buffer_arg(prim->name, 1, argc, argv);
+ linenr = SCHEME_INT_VAL(GUARANTEE_INTEGER(prim->name, 0));
+ line = ml_get_buf(buf->buf, (linenr_T)linenr, FALSE);
+
+ raise_if_error();
+ return scheme_make_byte_string((char *)line);
+}
+
+
+/*
+ * (get-buff-line-list {start} {end} [buffer])
+ *
+ * Get a list of lines from the specified buffer. The line numbers
+ * are in Vim format (1-based). The range is from lo up to, but not
+ * including, hi. The list is returned as a list of string objects.
+ */
+ static Scheme_Object *
+get_buffer_line_list(void *data, int argc, Scheme_Object **argv)
+{
+ Vim_Prim *prim = (Vim_Prim *)data;
+ vim_mz_buffer *buf;
+ int i, hi, lo, n;
+ Scheme_Object *list = NULL;
+
+ MZ_GC_DECL_REG(1);
+ MZ_GC_VAR_IN_REG(0, list);
+ MZ_GC_REG();
+
+ buf = get_buffer_arg(prim->name, 2, argc, argv);
+ list = scheme_null;
+ hi = SCHEME_INT_VAL(GUARANTEE_INTEGER(prim->name, 1));
+ lo = SCHEME_INT_VAL(GUARANTEE_INTEGER(prim->name, 0));
+
+ /*
+ * Handle some error conditions
+ */
+ if (lo < 0)
+ lo = 0;
+
+ if (hi < 0)
+ hi = 0;
+ if (hi < lo)
+ hi = lo;
+
+ n = hi - lo;
+
+ for (i = n; i >= 0; --i)
+ {
+ Scheme_Object *str = scheme_make_byte_string(
+ (char *)ml_get_buf(buf->buf, (linenr_T)(lo+i), FALSE));
+ raise_if_error();
+
+ /* Set the list item */
+ list = scheme_make_pair(str, list);
+ MZ_GC_CHECK();
+ }
+ MZ_GC_UNREG();
+ return list;
+}
+
+/*
+ * (set-buff-line {linenr} {string/#f} [buffer])
+ *
+ * Replace a line in the specified buffer. The line number is
+ * in Vim format (1-based). The replacement line is given as
+ * an MzScheme string object. The object is checked for validity
+ * and correct format. An exception is thrown if the values are not
+ * the correct format.
+ *
+ * It returns a Scheme Object that indicates the length of the
+ * string changed.
+ */
+ static Scheme_Object *
+set_buffer_line(void *data, int argc, Scheme_Object **argv)
+{
+ /* First of all, we check the value of the supplied MzScheme object.
+ * There are three cases:
+ * 1. #f - this is a deletion.
+ * 2. A string - this is a replacement.
+ * 3. Anything else - this is an error.
+ */
+ Vim_Prim *prim = (Vim_Prim *)data;
+ vim_mz_buffer *buf;
+ Scheme_Object *line = NULL;
+ char *save;
+ int n;
+
+ MZ_GC_DECL_REG(1);
+ MZ_GC_VAR_IN_REG(0, line);
+ MZ_GC_REG();
+
+#ifdef HAVE_SANDBOX
+ sandbox_check();
+#endif
+ n = SCHEME_INT_VAL(GUARANTEE_INTEGER(prim->name, 0));
+ if (!SCHEME_STRINGP(argv[1]) && !SCHEME_FALSEP(argv[1]))
+ scheme_wrong_type(prim->name, "string or #f", 1, argc, argv);
+ line = argv[1];
+ buf = get_buffer_arg(prim->name, 2, argc, argv);
+
+ check_line_range(n, buf->buf);
+
+ if (SCHEME_FALSEP(line))
+ {
+ buf_T *savebuf = curbuf;
+
+ curbuf = buf->buf;
+
+ if (u_savedel((linenr_T)n, 1L) == FAIL)
+ {
+ curbuf = savebuf;
+ raise_vim_exn(_("cannot save undo information"));
+ }
+ else if (ml_delete((linenr_T)n, FALSE) == FAIL)
+ {
+ curbuf = savebuf;
+ raise_vim_exn(_("cannot delete line"));
+ }
+ if (buf->buf == curwin->w_buffer)
+ mz_fix_cursor(n, n + 1, -1);
+ deleted_lines_mark((linenr_T)n, 1L);
+
+ curbuf = savebuf;
+
+ MZ_GC_UNREG();
+ raise_if_error();
+ return scheme_void;
+ }
+ else
+ {
+ /* Otherwise it's a line */
+ buf_T *savebuf = curbuf;
+
+ save = string_to_line(line);
+
+ curbuf = buf->buf;
+
+ if (u_savesub((linenr_T)n) == FAIL)
+ {
+ curbuf = savebuf;
+ vim_free(save);
+ raise_vim_exn(_("cannot save undo information"));
+ }
+ else if (ml_replace((linenr_T)n, (char_u *)save, TRUE) == FAIL)
+ {
+ curbuf = savebuf;
+ vim_free(save);
+ raise_vim_exn(_("cannot replace line"));
+ }
+ else
+ {
+ vim_free(save);
+ changed_bytes((linenr_T)n, 0);
+ }
+
+ curbuf = savebuf;
+
+ /* Check that the cursor is not beyond the end of the line now. */
+ if (buf->buf == curwin->w_buffer)
+ check_cursor_col();
+
+ MZ_GC_UNREG();
+ raise_if_error();
+ return scheme_void;
+ }
+}
+
+ static void
+free_array(char **array)
+{
+ char **curr = array;
+ while (*curr != NULL)
+ vim_free(*curr++);
+ vim_free(array);
+}
+
+/*
+ * (set-buff-line-list {start} {end} {string-list/#f/null} [buffer])
+ *
+ * Replace a range of lines in the specified buffer. The line numbers are in
+ * Vim format (1-based). The range is from lo up to, but not including, hi.
+ * The replacement lines are given as a Scheme list of string objects. The
+ * list is checked for validity and correct format.
+ *
+ * Errors are returned as a value of FAIL. The return value is OK on success.
+ * If OK is returned and len_change is not NULL, *len_change is set to the
+ * change in the buffer length.
+ */
+ static Scheme_Object *
+set_buffer_line_list(void *data, int argc, Scheme_Object **argv)
+{
+ /* First of all, we check the type of the supplied MzScheme object.
+ * There are three cases:
+ * 1. #f - this is a deletion.
+ * 2. A list - this is a replacement.
+ * 3. Anything else - this is an error.
+ */
+ Vim_Prim *prim = (Vim_Prim *)data;
+ vim_mz_buffer *buf = NULL;
+ Scheme_Object *line_list = NULL;
+ int i, old_len, new_len, hi, lo;
+ long extra;
+
+ MZ_GC_DECL_REG(1);
+ MZ_GC_VAR_IN_REG(0, line_list);
+ MZ_GC_REG();
+
+#ifdef HAVE_SANDBOX
+ sandbox_check();
+#endif
+ lo = SCHEME_INT_VAL(GUARANTEE_INTEGER(prim->name, 0));
+ hi = SCHEME_INT_VAL(GUARANTEE_INTEGER(prim->name, 1));
+ if (!SCHEME_PAIRP(argv[2])
+ && !SCHEME_FALSEP(argv[2]) && !SCHEME_NULLP(argv[2]))
+ scheme_wrong_type(prim->name, "list or #f", 2, argc, argv);
+ line_list = argv[2];
+ buf = get_buffer_arg(prim->name, 3, argc, argv);
+ old_len = hi - lo;
+ if (old_len < 0) /* process inverse values wisely */
+ {
+ i = lo;
+ lo = hi;
+ hi = i;
+ old_len = -old_len;
+ }
+ extra = 0;
+
+ check_line_range(lo, buf->buf); /* inclusive */
+ check_line_range(hi - 1, buf->buf); /* exclusive */
+
+ if (SCHEME_FALSEP(line_list) || SCHEME_NULLP(line_list))
+ {
+ buf_T *savebuf = curbuf;
+ curbuf = buf->buf;
+
+ if (u_savedel((linenr_T)lo, (long)old_len) == FAIL)
+ {
+ curbuf = savebuf;
+ raise_vim_exn(_("cannot save undo information"));
+ }
+ else
+ {
+ for (i = 0; i < old_len; i++)
+ if (ml_delete((linenr_T)lo, FALSE) == FAIL)
+ {
+ curbuf = savebuf;
+ raise_vim_exn(_("cannot delete line"));
+ }
+ if (buf->buf == curwin->w_buffer)
+ mz_fix_cursor(lo, hi, -old_len);
+ deleted_lines_mark((linenr_T)lo, (long)old_len);
+ }
+
+ curbuf = savebuf;
+
+ MZ_GC_UNREG();
+ raise_if_error();
+ return scheme_void;
+ }
+ else
+ {
+ buf_T *savebuf = curbuf;
+
+ /* List */
+ new_len = scheme_proper_list_length(line_list);
+ MZ_GC_CHECK();
+ if (new_len < 0) /* improper or cyclic list */
+ scheme_wrong_type(prim->name, "proper list",
+ 2, argc, argv);
+ else
+ {
+ char **array = NULL;
+ Scheme_Object *line = NULL;
+ Scheme_Object *rest = NULL;
+
+ MZ_GC_DECL_REG(2);
+ MZ_GC_VAR_IN_REG(0, line);
+ MZ_GC_VAR_IN_REG(1, rest);
+ MZ_GC_REG();
+
+ array = (char **)alloc((new_len+1)* sizeof(char *));
+ vim_memset(array, 0, (new_len+1) * sizeof(char *));
+
+ rest = line_list;
+ for (i = 0; i < new_len; ++i)
+ {
+ line = SCHEME_CAR(rest);
+ rest = SCHEME_CDR(rest);
+ if (!SCHEME_STRINGP(line))
+ {
+ free_array(array);
+ scheme_wrong_type(prim->name, "string-list", 2, argc, argv);
+ }
+ array[i] = string_to_line(line);
+ }
+
+ curbuf = buf->buf;
+
+ if (u_save((linenr_T)(lo-1), (linenr_T)hi) == FAIL)
+ {
+ curbuf = savebuf;
+ free_array(array);
+ raise_vim_exn(_("cannot save undo information"));
+ }
+
+ /*
+ * If the size of the range is reducing (ie, new_len < old_len) we
+ * need to delete some old_len. We do this at the start, by
+ * repeatedly deleting line "lo".
+ */
+ for (i = 0; i < old_len - new_len; ++i)
+ {
+ if (ml_delete((linenr_T)lo, FALSE) == FAIL)
+ {
+ curbuf = savebuf;
+ free_array(array);
+ raise_vim_exn(_("cannot delete line"));
+ }
+ extra--;
+ }
+
+ /*
+ * For as long as possible, replace the existing old_len with the
+ * new old_len. This is a more efficient operation, as it requires
+ * less memory allocation and freeing.
+ */
+ for (i = 0; i < old_len && i < new_len; i++)
+ if (ml_replace((linenr_T)(lo+i), (char_u *)array[i], TRUE) == FAIL)
+ {
+ curbuf = savebuf;
+ free_array(array);
+ raise_vim_exn(_("cannot replace line"));
+ }
+
+ /*
+ * Now we may need to insert the remaining new_len. We don't need to
+ * free the string passed back because MzScheme has control of that
+ * memory.
+ */
+ while (i < new_len)
+ {
+ if (ml_append((linenr_T)(lo + i - 1),
+ (char_u *)array[i], 0, FALSE) == FAIL)
+ {
+ curbuf = savebuf;
+ free_array(array);
+ raise_vim_exn(_("cannot insert line"));
+ }
+ ++i;
+ ++extra;
+ }
+ MZ_GC_UNREG();
+ free_array(array);
+ }
+
+ /*
+ * Adjust marks. Invalidate any which lie in the
+ * changed range, and move any in the remainder of the buffer.
+ */
+ mark_adjust((linenr_T)lo, (linenr_T)(hi - 1),
+ (long)MAXLNUM, (long)extra);
+ changed_lines((linenr_T)lo, 0, (linenr_T)hi, (long)extra);
+
+ if (buf->buf == curwin->w_buffer)
+ mz_fix_cursor(lo, hi, extra);
+ curbuf = savebuf;
+
+ MZ_GC_UNREG();
+ raise_if_error();
+ return scheme_void;
+ }
+}
+
+/*
+ * (insert-buff-line-list {linenr} {string/string-list} [buffer])
+ *
+ * Insert a number of lines into the specified buffer after the specified line.
+ * The line number is in Vim format (1-based). The lines to be inserted are
+ * given as an MzScheme list of string objects or as a single string. The lines
+ * to be added are checked for validity and correct format. Errors are
+ * returned as a value of FAIL. The return value is OK on success.
+ * If OK is returned and len_change is not NULL, *len_change
+ * is set to the change in the buffer length.
+ */
+ static Scheme_Object *
+insert_buffer_line_list(void *data, int argc, Scheme_Object **argv)
+{
+ Vim_Prim *prim = (Vim_Prim *)data;
+ vim_mz_buffer *buf = NULL;
+ Scheme_Object *list = NULL;
+ char *str = NULL;
+ int i, n, size;
+
+ MZ_GC_DECL_REG(1);
+ MZ_GC_VAR_IN_REG(0, list);
+ MZ_GC_REG();
+
+#ifdef HAVE_SANDBOX
+ sandbox_check();
+#endif
+ /*
+ * First of all, we check the type of the supplied MzScheme object.
+ * It must be a string or a list, or the call is in error.
+ */
+ n = SCHEME_INT_VAL(GUARANTEE_INTEGER(prim->name, 0));
+ list = argv[1];
+
+ if (!SCHEME_STRINGP(list) && !SCHEME_PAIRP(list))
+ scheme_wrong_type(prim->name, "string or list", 1, argc, argv);
+ buf = get_buffer_arg(prim->name, 2, argc, argv);
+
+ if (n != 0) /* 0 can be used in insert */
+ check_line_range(n, buf->buf);
+ if (SCHEME_STRINGP(list))
+ {
+ buf_T *savebuf = curbuf;
+
+ str = string_to_line(list);
+ curbuf = buf->buf;
+
+ if (u_save((linenr_T)n, (linenr_T)(n+1)) == FAIL)
+ {
+ curbuf = savebuf;
+ vim_free(str);
+ raise_vim_exn(_("cannot save undo information"));
+ }
+ else if (ml_append((linenr_T)n, (char_u *)str, 0, FALSE) == FAIL)
+ {
+ curbuf = savebuf;
+ vim_free(str);
+ raise_vim_exn(_("cannot insert line"));
+ }
+ else
+ {
+ vim_free(str);
+ appended_lines_mark((linenr_T)n, 1L);
+ }
+
+ curbuf = savebuf;
+ update_screen(VALID);
+
+ MZ_GC_UNREG();
+ raise_if_error();
+ return scheme_void;
+ }
+
+ /* List */
+ size = scheme_proper_list_length(list);
+ MZ_GC_CHECK();
+ if (size < 0) /* improper or cyclic list */
+ scheme_wrong_type(prim->name, "proper list",
+ 2, argc, argv);
+ else
+ {
+ Scheme_Object *line = NULL;
+ Scheme_Object *rest = NULL;
+ char **array;
+ buf_T *savebuf = curbuf;
+
+ MZ_GC_DECL_REG(2);
+ MZ_GC_VAR_IN_REG(0, line);
+ MZ_GC_VAR_IN_REG(1, rest);
+ MZ_GC_REG();
+
+ array = (char **)alloc((size+1) * sizeof(char *));
+ vim_memset(array, 0, (size+1) * sizeof(char *));
+
+ rest = list;
+ for (i = 0; i < size; ++i)
+ {
+ line = SCHEME_CAR(rest);
+ rest = SCHEME_CDR(rest);
+ array[i] = string_to_line(line);
+ }
+
+ curbuf = buf->buf;
+
+ if (u_save((linenr_T)n, (linenr_T)(n + 1)) == FAIL)
+ {
+ curbuf = savebuf;
+ free_array(array);
+ raise_vim_exn(_("cannot save undo information"));
+ }
+ else
+ {
+ for (i = 0; i < size; ++i)
+ if (ml_append((linenr_T)(n + i), (char_u *)array[i],
+ 0, FALSE) == FAIL)
+ {
+ curbuf = savebuf;
+ free_array(array);
+ raise_vim_exn(_("cannot insert line"));
+ }
+
+ if (i > 0)
+ appended_lines_mark((linenr_T)n, (long)i);
+ }
+ free_array(array);
+ MZ_GC_UNREG();
+ curbuf = savebuf;
+ update_screen(VALID);
+ }
+
+ MZ_GC_UNREG();
+ raise_if_error();
+ return scheme_void;
+}
+
+/*
+ * Predicates
+ */
+/* (buff? obj) */
+ static Scheme_Object *
+vim_bufferp(void *data UNUSED, int argc UNUSED, Scheme_Object **argv)
+{
+ if (SCHEME_VIMBUFFERP(argv[0]))
+ return scheme_true;
+ else
+ return scheme_false;
+}
+
+/* (win? obj) */
+ static Scheme_Object *
+vim_windowp(void *data UNUSED, int argc UNUSED, Scheme_Object **argv)
+{
+ if (SCHEME_VIMWINDOWP(argv[0]))
+ return scheme_true;
+ else
+ return scheme_false;
+}
+
+/* (buff-valid? obj) */
+ static Scheme_Object *
+vim_buffer_validp(void *data UNUSED, int argc UNUSED, Scheme_Object **argv)
+{
+ if (SCHEME_VIMBUFFERP(argv[0])
+ && ((vim_mz_buffer *)argv[0])->buf != INVALID_BUFFER_VALUE)
+ return scheme_true;
+ else
+ return scheme_false;
+}
+
+/* (win-valid? obj) */
+ static Scheme_Object *
+vim_window_validp(void *data UNUSED, int argc UNUSED, Scheme_Object **argv)
+{
+ if (SCHEME_VIMWINDOWP(argv[0])
+ && ((vim_mz_window *)argv[0])->win != INVALID_WINDOW_VALUE)
+ return scheme_true;
+ else
+ return scheme_false;
+}
+
+/*
+ *===========================================================================
+ * Utilities
+ *===========================================================================
+ */
+
+/*
+ * Convert an MzScheme string into a Vim line.
+ *
+ * All internal nulls are replaced by newline characters.
+ * It is an error for the string to contain newline characters.
+ *
+ * Returns pointer to Vim allocated memory
+ */
+ static char *
+string_to_line(Scheme_Object *obj)
+{
+ char *scheme_str = NULL;
+ char *vim_str = NULL;
+ OUTPUT_LEN_TYPE len;
+ int i;
+
+ scheme_str = scheme_display_to_string(obj, &len);
+
+ /* Error checking: String must not contain newlines, as we
+ * are replacing a single line, and we must replace it with
+ * a single line.
+ */
+ if (memchr(scheme_str, '\n', len))
+ scheme_signal_error(_("string cannot contain newlines"));
+
+ vim_str = (char *)alloc(len + 1);
+
+ /* Create a copy of the string, with internal nulls replaced by
+ * newline characters, as is the vim convention.
+ */
+ for (i = 0; i < len; ++i)
+ {
+ if (scheme_str[i] == '\0')
+ vim_str[i] = '\n';
+ else
+ vim_str[i] = scheme_str[i];
+ }
+
+ vim_str[i] = '\0';
+
+ MZ_GC_CHECK();
+ return vim_str;
+}
+
+#ifdef FEAT_EVAL
+/*
+ * Convert Vim value into MzScheme, adopted from if_python.c
+ */
+ static Scheme_Object *
+vim_to_mzscheme(typval_T *vim_value)
+{
+ Scheme_Object *result = NULL;
+ /* hash table to store visited values to avoid infinite loops */
+ Scheme_Hash_Table *visited = NULL;
+
+ MZ_GC_DECL_REG(2);
+ MZ_GC_VAR_IN_REG(0, result);
+ MZ_GC_VAR_IN_REG(1, visited);
+ MZ_GC_REG();
+
+ visited = scheme_make_hash_table(SCHEME_hash_ptr);
+ MZ_GC_CHECK();
+
+ result = vim_to_mzscheme_impl(vim_value, 1, visited);
+
+ MZ_GC_UNREG();
+ return result;
+}
+
+ static Scheme_Object *
+vim_to_mzscheme_impl(typval_T *vim_value, int depth, Scheme_Hash_Table *visited)
+{
+ Scheme_Object *result = NULL;
+ int new_value = TRUE;
+
+ MZ_GC_DECL_REG(2);
+ MZ_GC_VAR_IN_REG(0, result);
+ MZ_GC_VAR_IN_REG(1, visited);
+ MZ_GC_REG();
+
+ /* Avoid infinite recursion */
+ if (depth > 100)
+ {
+ MZ_GC_UNREG();
+ return scheme_void;
+ }
+
+ /* Check if we run into a recursive loop. The item must be in visited
+ * then and we can use it again.
+ */
+ result = scheme_hash_get(visited, (Scheme_Object *)vim_value);
+ MZ_GC_CHECK();
+ if (result != NULL) /* found, do nothing */
+ new_value = FALSE;
+ else if (vim_value->v_type == VAR_STRING)
+ {
+ result = scheme_make_byte_string((char *)vim_value->vval.v_string);
+ MZ_GC_CHECK();
+ }
+ else if (vim_value->v_type == VAR_NUMBER)
+ {
+ result = scheme_make_integer((long)vim_value->vval.v_number);
+ MZ_GC_CHECK();
+ }
+# ifdef FEAT_FLOAT
+ else if (vim_value->v_type == VAR_FLOAT)
+ {
+ result = scheme_make_double((double)vim_value->vval.v_float);
+ MZ_GC_CHECK();
+ }
+# endif
+ else if (vim_value->v_type == VAR_LIST)
+ {
+ list_T *list = vim_value->vval.v_list;
+ listitem_T *curr;
+
+ if (list == NULL || list->lv_first == NULL)
+ result = scheme_null;
+ else
+ {
+ Scheme_Object *obj = NULL;
+
+ MZ_GC_DECL_REG(1);
+ MZ_GC_VAR_IN_REG(0, obj);
+ MZ_GC_REG();
+
+ curr = list->lv_last;
+ obj = vim_to_mzscheme_impl(&curr->li_tv, depth + 1, visited);
+ result = scheme_make_pair(obj, scheme_null);
+ MZ_GC_CHECK();
+
+ while (curr != list->lv_first)
+ {
+ curr = curr->li_prev;
+ obj = vim_to_mzscheme_impl(&curr->li_tv, depth + 1, visited);
+ result = scheme_make_pair(obj, result);
+ MZ_GC_CHECK();
+ }
+ }
+ MZ_GC_UNREG();
+ }
+ else if (vim_value->v_type == VAR_DICT)
+ {
+ Scheme_Object *key = NULL;
+ Scheme_Object *obj = NULL;
+
+ MZ_GC_DECL_REG(2);
+ MZ_GC_VAR_IN_REG(0, key);
+ MZ_GC_VAR_IN_REG(1, obj);
+ MZ_GC_REG();
+
+ result = (Scheme_Object *)scheme_make_hash_table(SCHEME_hash_ptr);
+ MZ_GC_CHECK();
+ if (vim_value->vval.v_dict != NULL)
+ {
+ hashtab_T *ht = &vim_value->vval.v_dict->dv_hashtab;
+ long_u todo = ht->ht_used;
+ hashitem_T *hi;
+ dictitem_T *di;
+
+ for (hi = ht->ht_array; todo > 0; ++hi)
+ {
+ if (!HASHITEM_EMPTY(hi))
+ {
+ --todo;
+
+ di = dict_lookup(hi);
+ obj = vim_to_mzscheme_impl(&di->di_tv, depth + 1, visited);
+ key = scheme_make_byte_string((char *)hi->hi_key);
+ MZ_GC_CHECK();
+ scheme_hash_set((Scheme_Hash_Table *)result, key, obj);
+ MZ_GC_CHECK();
+ }
+ }
+ }
+ MZ_GC_UNREG();
+ }
+ else if (vim_value->v_type == VAR_FUNC)
+ {
+ Scheme_Object *funcname = NULL;
+
+ MZ_GC_DECL_REG(1);
+ MZ_GC_VAR_IN_REG(0, funcname);
+ MZ_GC_REG();
+
+ /* FIXME: func_ref() and func_unref() are needed. */
+ funcname = scheme_make_byte_string((char *)vim_value->vval.v_string);
+ MZ_GC_CHECK();
+ result = scheme_make_closed_prim_w_arity(vim_funcref, funcname,
+ (const char *)BYTE_STRING_VALUE(funcname), 0, -1);
+ MZ_GC_CHECK();
+
+ MZ_GC_UNREG();
+ }
+ else if (vim_value->v_type == VAR_PARTIAL)
+ {
+ if (vim_value->vval.v_partial == NULL)
+ result = scheme_null;
+ else
+ {
+ Scheme_Object *funcname = NULL;
+
+ MZ_GC_DECL_REG(1);
+ MZ_GC_VAR_IN_REG(0, funcname);
+ MZ_GC_REG();
+
+ /* FIXME: func_ref() and func_unref() are needed. */
+ /* TODO: Support pt_dict and pt_argv. */
+ funcname = scheme_make_byte_string(
+ (char *)partial_name(vim_value->vval.v_partial));
+ MZ_GC_CHECK();
+ result = scheme_make_closed_prim_w_arity(vim_funcref, funcname,
+ (const char *)BYTE_STRING_VALUE(funcname), 0, -1);
+ MZ_GC_CHECK();
+
+ MZ_GC_UNREG();
+ }
+ }
+ else if (vim_value->v_type == VAR_SPECIAL)
+ {
+ if (vim_value->vval.v_number <= VVAL_TRUE)
+ result = scheme_make_integer((long)vim_value->vval.v_number);
+ else
+ result = scheme_null;
+ MZ_GC_CHECK();
+ }
+ else
+ {
+ result = scheme_void;
+ new_value = FALSE;
+ }
+ if (new_value)
+ {
+ scheme_hash_set(visited, (Scheme_Object *)vim_value, result);
+ MZ_GC_CHECK();
+ }
+ MZ_GC_UNREG();
+ return result;
+}
+
+ static int
+mzscheme_to_vim(Scheme_Object *obj, typval_T *tv)
+{
+ int i, status;
+ Scheme_Hash_Table *visited = NULL;
+
+ MZ_GC_DECL_REG(2);
+ MZ_GC_VAR_IN_REG(0, obj);
+ MZ_GC_VAR_IN_REG(1, visited);
+ MZ_GC_REG();
+
+ visited = scheme_make_hash_table(SCHEME_hash_ptr);
+ MZ_GC_CHECK();
+
+ status = mzscheme_to_vim_impl(obj, tv, 1, visited);
+ for (i = 0; i < visited->size; ++i)
+ {
+ /* free up remembered objects */
+ if (visited->vals[i] != NULL)
+ free_tv((typval_T *)visited->vals[i]);
+ }
+
+ MZ_GC_UNREG();
+ return status;
+}
+ static int
+mzscheme_to_vim_impl(Scheme_Object *obj, typval_T *tv, int depth,
+ Scheme_Hash_Table *visited)
+{
+ int status = OK;
+ typval_T *found;
+
+ MZ_GC_DECL_REG(2);
+ MZ_GC_VAR_IN_REG(0, obj);
+ MZ_GC_VAR_IN_REG(1, visited);
+ MZ_GC_REG();
+
+ MZ_GC_CHECK();
+ if (depth > 100) /* limit the deepest recursion level */
+ {
+ tv->v_type = VAR_NUMBER;
+ tv->vval.v_number = 0;
+ return FAIL;
+ }
+
+ found = (typval_T *)scheme_hash_get(visited, obj);
+ if (found != NULL)
+ copy_tv(found, tv);
+ else if (SCHEME_VOIDP(obj))
+ {
+ tv->v_type = VAR_SPECIAL;
+ tv->vval.v_number = VVAL_NULL;
+ }
+ else if (SCHEME_INTP(obj))
+ {
+ tv->v_type = VAR_NUMBER;
+ tv->vval.v_number = SCHEME_INT_VAL(obj);
+ }
+ else if (SCHEME_BOOLP(obj))
+ {
+ tv->v_type = VAR_SPECIAL;
+ tv->vval.v_number = SCHEME_TRUEP(obj);
+ }
+# ifdef FEAT_FLOAT
+ else if (SCHEME_DBLP(obj))
+ {
+ tv->v_type = VAR_FLOAT;
+ tv->vval.v_float = SCHEME_DBL_VAL(obj);
+ }
+# endif
+ else if (SCHEME_BYTE_STRINGP(obj))
+ {
+ tv->v_type = VAR_STRING;
+ tv->vval.v_string = vim_strsave(BYTE_STRING_VALUE(obj));
+ }
+# if MZSCHEME_VERSION_MAJOR >= 299
+ else if (SCHEME_CHAR_STRINGP(obj))
+ {
+ Scheme_Object *tmp = NULL;
+ MZ_GC_DECL_REG(1);
+ MZ_GC_VAR_IN_REG(0, tmp);
+ MZ_GC_REG();
+
+ tmp = scheme_char_string_to_byte_string(obj);
+ tv->v_type = VAR_STRING;
+ tv->vval.v_string = vim_strsave(BYTE_STRING_VALUE(tmp));
+ MZ_GC_UNREG();
+ }
+#endif
+ else if (SCHEME_VECTORP(obj) || SCHEME_NULLP(obj)
+ || SCHEME_PAIRP(obj) || SCHEME_MUTABLE_PAIRP(obj))
+ {
+ list_T *list = list_alloc();
+ if (list == NULL)
+ status = FAIL;
+ else
+ {
+ int i;
+ Scheme_Object *curr = NULL;
+ Scheme_Object *cval = NULL;
+ /* temporary var to hold current element of vectors and pairs */
+ typval_T *v;
+
+ MZ_GC_DECL_REG(2);
+ MZ_GC_VAR_IN_REG(0, curr);
+ MZ_GC_VAR_IN_REG(1, cval);
+ MZ_GC_REG();
+
+ tv->v_type = VAR_LIST;
+ tv->vval.v_list = list;
+ ++list->lv_refcount;
+
+ v = (typval_T *)alloc(sizeof(typval_T));
+ if (v == NULL)
+ status = FAIL;
+ else
+ {
+ /* add the value in advance to allow handling of self-referential
+ * data structures */
+ typval_T *visited_tv = (typval_T *)alloc(sizeof(typval_T));
+ copy_tv(tv, visited_tv);
+ scheme_hash_set(visited, obj, (Scheme_Object *)visited_tv);
+
+ if (SCHEME_VECTORP(obj))
+ {
+ for (i = 0; i < SCHEME_VEC_SIZE(obj); ++i)
+ {
+ cval = SCHEME_VEC_ELS(obj)[i];
+ status = mzscheme_to_vim_impl(cval, v, depth + 1, visited);
+ if (status == FAIL)
+ break;
+ status = list_append_tv(list, v);
+ clear_tv(v);
+ if (status == FAIL)
+ break;
+ }
+ }
+ else if (SCHEME_PAIRP(obj) || SCHEME_MUTABLE_PAIRP(obj))
+ {
+ for (curr = obj;
+ SCHEME_PAIRP(curr) || SCHEME_MUTABLE_PAIRP(curr);
+ curr = SCHEME_CDR(curr))
+ {
+ cval = SCHEME_CAR(curr);
+ status = mzscheme_to_vim_impl(cval, v, depth + 1, visited);
+ if (status == FAIL)
+ break;
+ status = list_append_tv(list, v);
+ clear_tv(v);
+ if (status == FAIL)
+ break;
+ }
+ /* improper list not terminated with null
+ * need to handle the last element */
+ if (status == OK && !SCHEME_NULLP(curr))
+ {
+ status = mzscheme_to_vim_impl(cval, v, depth + 1, visited);
+ if (status == OK)
+ {
+ status = list_append_tv(list, v);
+ clear_tv(v);
+ }
+ }
+ }
+ /* nothing to do for scheme_null */
+ vim_free(v);
+ }
+ MZ_GC_UNREG();
+ }
+ }
+ else if (SCHEME_HASHTP(obj))
+ {
+ int i;
+ dict_T *dict;
+ Scheme_Object *key = NULL;
+ Scheme_Object *val = NULL;
+
+ MZ_GC_DECL_REG(2);
+ MZ_GC_VAR_IN_REG(0, key);
+ MZ_GC_VAR_IN_REG(1, val);
+ MZ_GC_REG();
+
+ dict = dict_alloc();
+ if (dict == NULL)
+ status = FAIL;
+ else
+ {
+ typval_T *visited_tv = (typval_T *)alloc(sizeof(typval_T));
+
+ tv->v_type = VAR_DICT;
+ tv->vval.v_dict = dict;
+ ++dict->dv_refcount;
+
+ copy_tv(tv, visited_tv);
+ scheme_hash_set(visited, obj, (Scheme_Object *)visited_tv);
+
+ for (i = 0; i < ((Scheme_Hash_Table *)obj)->size; ++i)
+ {
+ if (((Scheme_Hash_Table *) obj)->vals[i] != NULL)
+ {
+ /* generate item for `display'ed Scheme key */
+ dictitem_T *item = dictitem_alloc((char_u *)string_to_line(
+ ((Scheme_Hash_Table *) obj)->keys[i]));
+ /* convert Scheme val to Vim and add it to the dict */
+ if (mzscheme_to_vim_impl(((Scheme_Hash_Table *) obj)->vals[i],
+ &item->di_tv, depth + 1, visited) == FAIL
+ || dict_add(dict, item) == FAIL)
+ {
+ dictitem_free(item);
+ status = FAIL;
+ break;
+ }
+ }
+
+ }
+ }
+ MZ_GC_UNREG();
+ }
+ else
+ {
+ /* `display' any other value to string */
+ tv->v_type = VAR_STRING;
+ tv->vval.v_string = (char_u *)string_to_line(obj);
+ }
+ MZ_GC_UNREG();
+ return status;
+}
+
+/* Scheme prim procedure wrapping Vim funcref */
+ static Scheme_Object *
+vim_funcref(void *name, int argc, Scheme_Object **argv)
+{
+ int i;
+ typval_T args;
+ int status = OK;
+ Scheme_Object *result = NULL;
+ list_T *list = list_alloc();
+
+ MZ_GC_DECL_REG(1);
+ MZ_GC_VAR_IN_REG(0, result);
+ MZ_GC_REG();
+
+ result = scheme_void;
+ if (list == NULL)
+ status = FAIL;
+ else
+ {
+ args.v_type = VAR_LIST;
+ args.vval.v_list = list;
+ ++list->lv_refcount;
+ for (i = 0; status == OK && i < argc; ++i)
+ {
+ typval_T *v = (typval_T *)alloc(sizeof(typval_T));
+ if (v == NULL)
+ status = FAIL;
+ else
+ {
+ status = mzscheme_to_vim(argv[i], v);
+ if (status == OK)
+ {
+ status = list_append_tv(list, v);
+ clear_tv(v);
+ }
+ vim_free(v);
+ }
+ }
+ if (status == OK)
+ {
+ typval_T ret;
+ ret.v_type = VAR_UNKNOWN;
+
+ mzscheme_call_vim(BYTE_STRING_VALUE((Scheme_Object *)name), &args, &ret);
+ MZ_GC_CHECK();
+ result = vim_to_mzscheme(&ret);
+ clear_tv(&ret);
+ MZ_GC_CHECK();
+ }
+ }
+ clear_tv(&args);
+ MZ_GC_UNREG();
+ if (status != OK)
+ raise_vim_exn(_("error converting Scheme values to Vim"));
+ else
+ raise_if_error();
+ return result;
+}
+
+ void
+do_mzeval(char_u *str, typval_T *rettv)
+{
+ Scheme_Object *ret = NULL;
+
+ MZ_GC_DECL_REG(1);
+ MZ_GC_VAR_IN_REG(0, ret);
+ MZ_GC_REG();
+
+ if (mzscheme_init())
+ {
+ MZ_GC_UNREG();
+ return;
+ }
+
+ MZ_GC_CHECK();
+ if (eval_with_exn_handling(str, do_eval, &ret) == OK)
+ mzscheme_to_vim(ret, rettv);
+
+ MZ_GC_UNREG();
+}
+#endif
+
+/*
+ * Check to see whether a Vim error has been reported, or a keyboard
+ * interrupt (from vim --> got_int) has been detected.
+ */
+ static int
+vim_error_check(void)
+{
+ return (got_int || did_emsg);
+}
+
+/*
+ * register Scheme exn:vim
+ */
+ static void
+register_vim_exn(void)
+{
+ int nc = 0;
+ int i;
+ Scheme_Object *struct_exn = NULL;
+ Scheme_Object *exn_name = NULL;
+
+ MZ_GC_DECL_REG(2);
+ MZ_GC_VAR_IN_REG(0, struct_exn);
+ MZ_GC_VAR_IN_REG(1, exn_name);
+ MZ_GC_REG();
+
+ exn_name = scheme_intern_symbol("exn:vim");
+ MZ_GC_CHECK();
+ struct_exn = scheme_builtin_value("struct:exn");
+ MZ_GC_CHECK();
+
+ if (vim_exn == NULL)
+ vim_exn = scheme_make_struct_type(exn_name,
+ struct_exn, NULL, 0, 0, NULL, NULL
+#if MZSCHEME_VERSION_MAJOR >= 299
+ , NULL
+#endif
+ );
+
+
+ {
+ Scheme_Object **tmp = NULL;
+ Scheme_Object *exn_names[5] = {NULL, NULL, NULL, NULL, NULL};
+ Scheme_Object *exn_values[5] = {NULL, NULL, NULL, NULL, NULL};
+ MZ_GC_DECL_REG(6);
+ MZ_GC_ARRAY_VAR_IN_REG(0, exn_names, 5);
+ MZ_GC_ARRAY_VAR_IN_REG(3, exn_values, 5);
+ MZ_GC_REG();
+
+ tmp = scheme_make_struct_names(exn_name, scheme_null, 0, &nc);
+ mch_memmove(exn_names, tmp, nc * sizeof(Scheme_Object *));
+ MZ_GC_CHECK();
+
+ tmp = scheme_make_struct_values(vim_exn, exn_names, nc, 0);
+ mch_memmove(exn_values, tmp, nc * sizeof(Scheme_Object *));
+ MZ_GC_CHECK();
+
+ for (i = 0; i < nc; i++)
+ {
+ scheme_add_global_symbol(exn_names[i],
+ exn_values[i], environment);
+ MZ_GC_CHECK();
+ }
+ MZ_GC_UNREG();
+ }
+ MZ_GC_UNREG();
+}
+
+/*
+ * raise exn:vim, may be with additional info string
+ */
+ void
+raise_vim_exn(const char *add_info)
+{
+ char *fmt = _("Vim error: ~a");
+ Scheme_Object *argv[2] = {NULL, NULL};
+ Scheme_Object *exn = NULL;
+ Scheme_Object *byte_string = NULL;
+
+ MZ_GC_DECL_REG(5);
+ MZ_GC_ARRAY_VAR_IN_REG(0, argv, 2);
+ MZ_GC_VAR_IN_REG(3, exn);
+ MZ_GC_VAR_IN_REG(4, byte_string);
+ MZ_GC_REG();
+
+ if (add_info != NULL)
+ {
+ char *c_string = NULL;
+ Scheme_Object *info = NULL;
+
+ MZ_GC_DECL_REG(3);
+ MZ_GC_VAR_IN_REG(0, c_string);
+ MZ_GC_VAR_IN_REG(2, info);
+ MZ_GC_REG();
+
+ info = scheme_make_byte_string(add_info);
+ MZ_GC_CHECK();
+ c_string = scheme_format_utf8(fmt, (int)STRLEN(fmt), 1, &info, NULL);
+ MZ_GC_CHECK();
+ byte_string = scheme_make_byte_string(c_string);
+ MZ_GC_CHECK();
+ argv[0] = scheme_byte_string_to_char_string(byte_string);
+ SCHEME_SET_IMMUTABLE(argv[0]);
+ MZ_GC_UNREG();
+ }
+ else
+ {
+ byte_string = scheme_make_byte_string(_("Vim error"));
+ MZ_GC_CHECK();
+ argv[0] = scheme_byte_string_to_char_string(byte_string);
+ MZ_GC_CHECK();
+ }
+ MZ_GC_CHECK();
+
+#if MZSCHEME_VERSION_MAJOR < 360
+ argv[1] = scheme_current_continuation_marks();
+ MZ_GC_CHECK();
+#else
+ argv[1] = scheme_current_continuation_marks(NULL);
+ MZ_GC_CHECK();
+#endif
+
+ exn = scheme_make_struct_instance(vim_exn, 2, argv);
+ MZ_GC_CHECK();
+ scheme_raise(exn);
+ MZ_GC_UNREG();
+}
+
+ void
+raise_if_error(void)
+{
+ if (vim_error_check())
+ raise_vim_exn(NULL);
+}
+
+/* get buffer:
+ * either current
+ * or passed as argv[argnum] with checks
+ */
+ static vim_mz_buffer *
+get_buffer_arg(const char *fname, int argnum, int argc, Scheme_Object **argv)
+{
+ vim_mz_buffer *b;
+
+ if (argc < argnum + 1)
+ return get_vim_curr_buffer();
+ if (!SCHEME_VIMBUFFERP(argv[argnum]))
+ scheme_wrong_type(fname, "vim-buffer", argnum, argc, argv);
+ b = (vim_mz_buffer *)argv[argnum];
+ (void)get_valid_buffer(argv[argnum]);
+ return b;
+}
+
+/* get window:
+ * either current
+ * or passed as argv[argnum] with checks
+ */
+ static vim_mz_window *
+get_window_arg(const char *fname, int argnum, int argc, Scheme_Object **argv)
+{
+ vim_mz_window *w;
+
+ if (argc < argnum + 1)
+ return get_vim_curr_window();
+ w = (vim_mz_window *)argv[argnum];
+ if (!SCHEME_VIMWINDOWP(argv[argnum]))
+ scheme_wrong_type(fname, "vim-window", argnum, argc, argv);
+ (void)get_valid_window(argv[argnum]);
+ return w;
+}
+
+/* get valid Vim buffer from Scheme_Object* */
+buf_T *get_valid_buffer(void *obj)
+{
+ buf_T *buf = ((vim_mz_buffer *)obj)->buf;
+
+ if (buf == INVALID_BUFFER_VALUE)
+ scheme_signal_error(_("buffer is invalid"));
+ return buf;
+}
+
+/* get valid Vim window from Scheme_Object* */
+win_T *get_valid_window(void *obj)
+{
+ win_T *win = ((vim_mz_window *)obj)->win;
+ if (win == INVALID_WINDOW_VALUE)
+ scheme_signal_error(_("window is invalid"));
+ return win;
+}
+
+ int
+mzthreads_allowed(void)
+{
+ return mz_threads_allow;
+}
+
+ static int
+line_in_range(linenr_T lnum, buf_T *buf)
+{
+ return (lnum > 0 && lnum <= buf->b_ml.ml_line_count);
+}
+
+ static void
+check_line_range(linenr_T lnum, buf_T *buf)
+{
+ if (!line_in_range(lnum, buf))
+ scheme_signal_error(_("linenr out of range"));
+}
+
+/*
+ * Check if deleting lines made the cursor position invalid
+ * (or you'll get msg from Vim about invalid linenr).
+ * Changed the lines from "lo" to "hi" and added "extra" lines (negative if
+ * deleted). Got from if_python.c
+ */
+ static void
+mz_fix_cursor(int lo, int hi, int extra)
+{
+ if (curwin->w_cursor.lnum >= lo)
+ {
+ /* Adjust the cursor position if it's in/after the changed
+ * lines. */
+ if (curwin->w_cursor.lnum >= hi)
+ {
+ curwin->w_cursor.lnum += extra;
+ check_cursor_col();
+ }
+ else if (extra < 0)
+ {
+ curwin->w_cursor.lnum = lo;
+ check_cursor();
+ }
+ else
+ check_cursor_col();
+ changed_cline_bef_curs();
+ }
+ invalidate_botline();
+}
+
+static Vim_Prim prims[]=
+{
+ /*
+ * Buffer-related commands
+ */
+ {get_buffer_line, "get-buff-line", 1, 2},
+ {set_buffer_line, "set-buff-line", 2, 3},
+ {get_buffer_line_list, "get-buff-line-list", 2, 3},
+ {get_buffer_name, "get-buff-name", 0, 1},
+ {get_buffer_num, "get-buff-num", 0, 1},
+ {get_buffer_size, "get-buff-size", 0, 1},
+ {set_buffer_line_list, "set-buff-line-list", 3, 4},
+ {insert_buffer_line_list, "insert-buff-line-list", 2, 3},
+ {get_curr_buffer, "curr-buff", 0, 0},
+ {get_buffer_count, "buff-count", 0, 0},
+ {get_next_buffer, "get-next-buff", 0, 1},
+ {get_prev_buffer, "get-prev-buff", 0, 1},
+ {mzscheme_open_buffer, "open-buff", 1, 1},
+ {get_buffer_by_name, "get-buff-by-name", 1, 1},
+ {get_buffer_by_num, "get-buff-by-num", 1, 1},
+ /*
+ * Window-related commands
+ */
+ {get_curr_win, "curr-win", 0, 0},
+ {get_window_count, "win-count", 0, 0},
+ {get_window_by_num, "get-win-by-num", 1, 1},
+ {get_window_num, "get-win-num", 0, 1},
+ {get_window_buffer, "get-win-buffer", 0, 1},
+ {get_window_height, "get-win-height", 0, 1},
+ {set_window_height, "set-win-height", 1, 2},
+ {get_window_width, "get-win-width", 0, 1},
+ {set_window_width, "set-win-width", 1, 2},
+ {get_cursor, "get-cursor", 0, 1},
+ {set_cursor, "set-cursor", 1, 2},
+ {get_window_list, "get-win-list", 0, 1},
+ /*
+ * Vim-related commands
+ */
+ {vim_command, "command", 1, 1},
+ {vim_eval, "eval", 1, 1},
+ {get_range_start, "range-start", 0, 0},
+ {get_range_end, "range-end", 0, 0},
+ {mzscheme_beep, "beep", 0, 0},
+ {get_option, "get-option", 1, 2},
+ {set_option, "set-option", 1, 2},
+ /*
+ * small utilities
+ */
+ {vim_bufferp, "buff?", 1, 1},
+ {vim_windowp, "win?", 1, 1},
+ {vim_buffer_validp, "buff-valid?", 1, 1},
+ {vim_window_validp, "win-valid?", 1, 1}
+};
+
+/* return MzScheme wrapper for curbuf */
+ static vim_mz_buffer *
+get_vim_curr_buffer(void)
+{
+ if (curbuf->b_mzscheme_ref == NULL)
+ return (vim_mz_buffer *)buffer_new(curbuf);
+ else
+ return BUFFER_REF(curbuf);
+}
+
+/* return MzScheme wrapper for curwin */
+ static vim_mz_window *
+get_vim_curr_window(void)
+{
+ if (curwin->w_mzscheme_ref == NULL)
+ return (vim_mz_window *)window_new(curwin);
+ else
+ return WINDOW_REF(curwin);
+}
+
+ static void
+make_modules(void)
+{
+ int i;
+ Scheme_Env *mod = NULL;
+ Scheme_Object *vimext_symbol = NULL;
+ Scheme_Object *closed_prim = NULL;
+
+ MZ_GC_DECL_REG(3);
+ MZ_GC_VAR_IN_REG(0, mod);
+ MZ_GC_VAR_IN_REG(1, vimext_symbol);
+ MZ_GC_VAR_IN_REG(2, closed_prim);
+ MZ_GC_REG();
+
+ vimext_symbol = scheme_intern_symbol("vimext");
+ MZ_GC_CHECK();
+ mod = scheme_primitive_module(vimext_symbol, environment);
+ MZ_GC_CHECK();
+ /* all prims made closed so they can access their own names */
+ for (i = 0; i < (int)(sizeof(prims)/sizeof(prims[0])); i++)
+ {
+ Vim_Prim *prim = prims + i;
+ closed_prim = scheme_make_closed_prim_w_arity(prim->prim, prim, prim->name,
+ prim->mina, prim->maxa);
+ scheme_add_global(prim->name, closed_prim, mod);
+ MZ_GC_CHECK();
+ }
+ scheme_finish_primitive_module(mod);
+ MZ_GC_CHECK();
+ MZ_GC_UNREG();
+}
+
+#ifdef HAVE_SANDBOX
+static Scheme_Object *M_write = NULL;
+static Scheme_Object *M_read = NULL;
+static Scheme_Object *M_execute = NULL;
+static Scheme_Object *M_delete = NULL;
+
+ static void
+sandbox_check(void)
+{
+ if (sandbox)
+ raise_vim_exn(_("not allowed in the Vim sandbox"));
+}
+
+/* security guards to force Vim's sandbox restrictions on MzScheme level */
+ static Scheme_Object *
+sandbox_file_guard(int argc UNUSED, Scheme_Object **argv)
+{
+ if (sandbox)
+ {
+ Scheme_Object *requested_access = argv[2];
+
+ if (M_write == NULL)
+ {
+ MZ_REGISTER_STATIC(M_write);
+ M_write = scheme_intern_symbol("write");
+ MZ_GC_CHECK();
+ }
+ if (M_read == NULL)
+ {
+ MZ_REGISTER_STATIC(M_read);
+ M_read = scheme_intern_symbol("read");
+ MZ_GC_CHECK();
+ }
+ if (M_execute == NULL)
+ {
+ MZ_REGISTER_STATIC(M_execute);
+ M_execute = scheme_intern_symbol("execute");
+ MZ_GC_CHECK();
+ }
+ if (M_delete == NULL)
+ {
+ MZ_REGISTER_STATIC(M_delete);
+ M_delete = scheme_intern_symbol("delete");
+ MZ_GC_CHECK();
+ }
+
+ while (!SCHEME_NULLP(requested_access))
+ {
+ Scheme_Object *item = SCHEME_CAR(requested_access);
+ if (scheme_eq(item, M_write) || scheme_eq(item, M_read)
+ || scheme_eq(item, M_execute) || scheme_eq(item, M_delete))
+ {
+ raise_vim_exn(_("not allowed in the Vim sandbox"));
+ }
+ requested_access = SCHEME_CDR(requested_access);
+ }
+ }
+ return scheme_void;
+}
+
+ static Scheme_Object *
+sandbox_network_guard(int argc UNUSED, Scheme_Object **argv UNUSED)
+{
+ return scheme_void;
+}
+#endif
+
+#endif
diff --git a/src/if_mzsch.h b/src/if_mzsch.h
new file mode 100644
index 0000000..952b084
--- /dev/null
+++ b/src/if_mzsch.h
@@ -0,0 +1,76 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * MzScheme interface for Vim, wrapper around scheme.h
+ */
+#ifndef _IF_MZSCH_H_
+#define _IF_MZSCH_H_
+#ifdef __MINGW32__
+/* Hack to engage Cygwin-specific settings */
+# define __CYGWIN32__
+# include <stdint.h>
+#endif
+
+#ifdef PROTO
+/* avoid syntax error for defining Thread_Local_Variables. */
+# define __thread /* empty */
+#endif
+
+/* #ifdef needed for "make depend" */
+#ifdef FEAT_MZSCHEME
+# include <schvers.h>
+# include <scheme.h>
+#endif
+
+#ifdef __MINGW32__
+# undef __CYGWIN32__
+#endif
+
+#if MZSCHEME_VERSION_MAJOR >= 299
+# define SCHEME_STRINGP(obj) (SCHEME_BYTE_STRINGP(obj) || SCHEME_CHAR_STRINGP(obj))
+# define BYTE_STRING_VALUE(obj) ((char_u *)SCHEME_BYTE_STR_VAL(obj))
+#else
+/* macros for compatibility with older versions */
+# define scheme_current_config() scheme_config
+# define scheme_make_sized_byte_string scheme_make_sized_string
+# define scheme_format_utf8 scheme_format
+# ifndef DYNAMIC_MZSCHEME
+/* for dynamic MzScheme there will be separate definitions in if_mzsch.c */
+# define scheme_get_sized_byte_string_output scheme_get_sized_string_output
+# define scheme_make_byte_string scheme_make_string
+# define scheme_make_byte_string_output_port scheme_make_string_output_port
+# endif
+
+# define SCHEME_BYTE_STRLEN_VAL SCHEME_STRLEN_VAL
+# define BYTE_STRING_VALUE(obj) ((char_u *)SCHEME_STR_VAL(obj))
+# define scheme_byte_string_to_char_string(obj) (obj)
+# define SCHEME_BYTE_STRINGP SCHEME_STRINGP
+#endif
+
+/* Precise GC macros */
+#ifndef MZ_GC_DECL_REG
+# define MZ_GC_DECL_REG(size) /* empty */
+#endif
+#ifndef MZ_GC_VAR_IN_REG
+# define MZ_GC_VAR_IN_REG(x, v) /* empty */
+#endif
+#ifndef MZ_GC_ARRAY_VAR_IN_REG
+# define MZ_GC_ARRAY_VAR_IN_REG(x, v, l) /* empty */
+#endif
+#ifndef MZ_GC_REG
+# define MZ_GC_REG() /* empty */
+#endif
+#ifndef MZ_GC_UNREG
+# define MZ_GC_UNREG() /* empty */
+#endif
+
+#ifdef MZSCHEME_FORCE_GC
+/*
+ * force garbage collection to check all references are registered
+ * seg faults will indicate not registered refs
+ */
+# define MZ_GC_CHECK() scheme_collect_garbage();
+#else
+# define MZ_GC_CHECK() /* empty */
+#endif
+
+#endif /* _IF_MZSCH_H_ */
diff --git a/src/if_ole.cpp b/src/if_ole.cpp
new file mode 100644
index 0000000..0888883
--- /dev/null
+++ b/src/if_ole.cpp
@@ -0,0 +1,813 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * Do ":help uganda" in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ */
+
+#if defined(FEAT_OLE) && defined(FEAT_GUI_W32)
+/*
+ * OLE server implementation.
+ *
+ * See os_mswin.c for the client side.
+ */
+
+/*
+ * We have some trouble with order of includes here. For Borland it needs to
+ * be different from MSVC...
+ */
+#ifndef __BORLANDC__
+extern "C" {
+# include "vim.h"
+}
+#endif
+
+#include <windows.h>
+#include <oleauto.h>
+
+extern "C" {
+#ifdef __BORLANDC__
+# include "vim.h"
+#endif
+extern HWND s_hwnd;
+extern HWND vim_parent_hwnd;
+}
+
+#if (defined(_MSC_VER) && (_MSC_VER >= 1700)) || (__cplusplus >= 201103L)
+# define FINAL final
+#else
+# define FINAL
+#endif
+
+#if (defined(_MSC_VER) && _MSC_VER < 1300) || !defined(MAXULONG_PTR)
+/* Work around old versions of basetsd.h which wrongly declares
+ * UINT_PTR as unsigned long */
+# undef UINT_PTR
+# define UINT_PTR UINT
+#endif
+
+#include "if_ole.h" // Interface definitions
+#include "iid_ole.c" // UUID definitions (compile here)
+
+/* Supply function prototype to work around bug in Mingw oleauto.h header */
+#ifdef __MINGW32__
+WINOLEAUTAPI UnRegisterTypeLib(REFGUID libID, WORD wVerMajor,
+ WORD wVerMinor, LCID lcid, SYSKIND syskind);
+#endif
+
+/*****************************************************************************
+ 1. Internal definitions for this file
+*****************************************************************************/
+
+class CVim;
+class CVimCF;
+
+/* Internal data */
+// The identifier of the registered class factory
+static unsigned long cf_id = 0;
+
+// The identifier of the running application object
+static unsigned long app_id = 0;
+
+// The single global instance of the class factory
+static CVimCF *cf = 0;
+
+// The single global instance of the application object
+static CVim *app = 0;
+
+/* GUIDs, versions and type library information */
+#define MYCLSID CLSID_Vim
+#define MYLIBID LIBID_Vim
+#define MYIID IID_IVim
+
+#define MAJORVER 1
+#define MINORVER 0
+#define LOCALE 0x0409
+
+#define MYNAME "Vim"
+#define MYPROGID "Vim.Application.1"
+#define MYVIPROGID "Vim.Application"
+
+#define MAX_CLSID_LEN 100
+
+/*****************************************************************************
+ 2. The application object
+*****************************************************************************/
+
+/* Definition
+ * ----------
+ */
+
+class CVim FINAL : public IVim
+{
+public:
+ virtual ~CVim();
+ static CVim *Create(int *pbDoRestart);
+
+ // IUnknown members
+ STDMETHOD(QueryInterface)(REFIID riid, void ** ppv);
+ STDMETHOD_(unsigned long, AddRef)(void);
+ STDMETHOD_(unsigned long, Release)(void);
+
+ // IDispatch members
+ STDMETHOD(GetTypeInfoCount)(UINT *pCount);
+ STDMETHOD(GetTypeInfo)(UINT iTypeInfo, LCID, ITypeInfo **ppITypeInfo);
+ STDMETHOD(GetIDsOfNames)(const IID &iid, OLECHAR **names, UINT n, LCID, DISPID *dispids);
+ STDMETHOD(Invoke)(DISPID member, const IID &iid, LCID, WORD flags, DISPPARAMS *dispparams, VARIANT *result, EXCEPINFO *excepinfo, UINT *argerr);
+
+ // IVim members
+ STDMETHOD(SendKeys)(BSTR keys);
+ STDMETHOD(Eval)(BSTR expr, BSTR *result);
+ STDMETHOD(SetForeground)(void);
+ STDMETHOD(GetHwnd)(UINT_PTR *result);
+
+private:
+ // Constructor is private - create using CVim::Create()
+ CVim() : ref(0), typeinfo(0) {};
+
+ // Reference count
+ unsigned long ref;
+
+ // The object's TypeInfo
+ ITypeInfo *typeinfo;
+};
+
+/* Implementation
+ * --------------
+ */
+
+CVim *CVim::Create(int *pbDoRestart)
+{
+ HRESULT hr;
+ CVim *me = 0;
+ ITypeLib *typelib = 0;
+ ITypeInfo *typeinfo = 0;
+
+ *pbDoRestart = FALSE;
+
+ // Create the object
+ me = new CVim();
+ if (me == NULL)
+ {
+ MessageBox(0, "Cannot create application object", "Vim Initialisation", 0);
+ return NULL;
+ }
+
+ // Load the type library from the registry
+ hr = LoadRegTypeLib(MYLIBID, 1, 0, 0x00, &typelib);
+ if (FAILED(hr))
+ {
+ HKEY hKey;
+
+ // Check we can write to the registry.
+ // RegCreateKeyEx succeeds even if key exists. W.Briscoe W2K 20021011
+ if (RegCreateKeyEx(HKEY_CLASSES_ROOT, MYVIPROGID, 0, NULL,
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS, NULL, &hKey, NULL))
+ {
+ delete me;
+ return NULL; // Unable to write to registry. Quietly fail.
+ }
+ RegCloseKey(hKey);
+
+ if (MessageBox(0, "Cannot load registered type library.\nDo you want to register Vim now?",
+ "Vim Initialisation", MB_YESNO | MB_ICONQUESTION) != IDYES)
+ {
+ delete me;
+ return NULL;
+ }
+
+ RegisterMe(FALSE);
+
+ // Load the type library from the registry
+ hr = LoadRegTypeLib(MYLIBID, 1, 0, 0x00, &typelib);
+ if (FAILED(hr))
+ {
+ MessageBox(0, "You must restart Vim in order for the registration to take effect.",
+ "Vim Initialisation", 0);
+ *pbDoRestart = TRUE;
+ delete me;
+ return NULL;
+ }
+ }
+
+ // Get the type info of the vtable interface
+ hr = typelib->GetTypeInfoOfGuid(MYIID, &typeinfo);
+ typelib->Release();
+
+ if (FAILED(hr))
+ {
+ MessageBox(0, "Cannot get interface type information",
+ "Vim Initialisation", 0);
+ delete me;
+ return NULL;
+ }
+
+ // Save the type information
+ me->typeinfo = typeinfo;
+ return me;
+}
+
+CVim::~CVim()
+{
+ if (typeinfo && vim_parent_hwnd == NULL)
+ typeinfo->Release();
+ typeinfo = 0;
+}
+
+STDMETHODIMP
+CVim::QueryInterface(REFIID riid, void **ppv)
+{
+ if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IDispatch) || IsEqualIID(riid, MYIID))
+ {
+ AddRef();
+ *ppv = this;
+ return S_OK;
+ }
+
+ *ppv = 0;
+ return E_NOINTERFACE;
+}
+
+STDMETHODIMP_(ULONG)
+CVim::AddRef()
+{
+ return ++ref;
+}
+
+STDMETHODIMP_(ULONG)
+CVim::Release()
+{
+ // Don't delete the object when the reference count reaches zero, as there
+ // is only a single application object, and its lifetime is controlled by
+ // the running instance, not by its reference count.
+ if (ref > 0)
+ --ref;
+ return ref;
+}
+
+STDMETHODIMP
+CVim::GetTypeInfoCount(UINT *pCount)
+{
+ *pCount = 1;
+ return S_OK;
+}
+
+STDMETHODIMP
+CVim::GetTypeInfo(UINT iTypeInfo, LCID, ITypeInfo **ppITypeInfo)
+{
+ *ppITypeInfo = 0;
+
+ if (iTypeInfo != 0)
+ return DISP_E_BADINDEX;
+
+ typeinfo->AddRef();
+ *ppITypeInfo = typeinfo;
+ return S_OK;
+}
+
+STDMETHODIMP
+CVim::GetIDsOfNames(
+ const IID &iid,
+ OLECHAR **names,
+ UINT n,
+ LCID,
+ DISPID *dispids)
+{
+ if (iid != IID_NULL)
+ return DISP_E_UNKNOWNINTERFACE;
+
+ return typeinfo->GetIDsOfNames(names, n, dispids);
+}
+
+STDMETHODIMP
+CVim::Invoke(
+ DISPID member,
+ const IID &iid,
+ LCID,
+ WORD flags,
+ DISPPARAMS *dispparams,
+ VARIANT *result,
+ EXCEPINFO *excepinfo,
+ UINT *argerr)
+{
+ if (iid != IID_NULL)
+ return DISP_E_UNKNOWNINTERFACE;
+
+ ::SetErrorInfo(0, NULL);
+ return typeinfo->Invoke(static_cast<IDispatch*>(this),
+ member, flags, dispparams,
+ result, excepinfo, argerr);
+}
+
+STDMETHODIMP
+CVim::GetHwnd(UINT_PTR *result)
+{
+ *result = (UINT_PTR)s_hwnd;
+ return S_OK;
+}
+
+STDMETHODIMP
+CVim::SetForeground(void)
+{
+ /* Make the Vim window come to the foreground */
+ gui_mch_set_foreground();
+ return S_OK;
+}
+
+STDMETHODIMP
+CVim::SendKeys(BSTR keys)
+{
+ int len;
+ char *buffer;
+ char_u *str;
+ char_u *ptr;
+
+ /* Get a suitable buffer */
+ len = WideCharToMultiByte(CP_ACP, 0, keys, -1, 0, 0, 0, 0);
+ buffer = (char *)alloc(len+1);
+
+ if (buffer == NULL)
+ return E_OUTOFMEMORY;
+
+ len = WideCharToMultiByte(CP_ACP, 0, keys, -1, buffer, len, 0, 0);
+
+ if (len == 0)
+ {
+ vim_free(buffer);
+ return E_INVALIDARG;
+ }
+
+ /* Translate key codes like <Esc> */
+ str = replace_termcodes((char_u *)buffer, &ptr, FALSE, TRUE, FALSE);
+
+ /* If ptr was set, then a new buffer was allocated,
+ * so we can free the old one.
+ */
+ if (ptr)
+ vim_free((char_u *)(buffer));
+
+ /* Reject strings too long to fit in the input buffer. Allow 10 bytes
+ * space to cover for the (remote) possibility that characters may enter
+ * the input buffer between now and when the WM_OLE message is actually
+ * processed. If more that 10 characters enter the input buffer in that
+ * time, the WM_OLE processing will simply fail to insert the characters.
+ */
+ if ((int)(STRLEN(str)) > (vim_free_in_input_buf() - 10))
+ {
+ vim_free(str);
+ return E_INVALIDARG;
+ }
+
+ /* Pass the string to the main input loop. The memory will be freed when
+ * the message is processed. Except for an empty message, we don't need
+ * to post it then.
+ */
+ if (*str == NUL)
+ vim_free(str);
+ else
+ PostMessage(NULL, WM_OLE, 0, (LPARAM)str);
+
+ return S_OK;
+}
+
+STDMETHODIMP
+CVim::Eval(BSTR expr, BSTR *result)
+{
+#ifdef FEAT_EVAL
+ int len;
+ char *buffer;
+ char *str;
+ wchar_t *w_buffer;
+
+ /* Get a suitable buffer */
+ len = WideCharToMultiByte(CP_ACP, 0, expr, -1, 0, 0, 0, 0);
+ if (len == 0)
+ return E_INVALIDARG;
+
+ buffer = (char *)alloc((unsigned)len);
+
+ if (buffer == NULL)
+ return E_OUTOFMEMORY;
+
+ /* Convert the (wide character) expression to an ASCII string */
+ len = WideCharToMultiByte(CP_ACP, 0, expr, -1, buffer, len, 0, 0);
+ if (len == 0)
+ return E_INVALIDARG;
+
+ /* Evaluate the expression */
+ ++emsg_skip;
+ str = (char *)eval_to_string((char_u *)buffer, NULL, TRUE);
+ --emsg_skip;
+ vim_free(buffer);
+ if (str == NULL)
+ return E_FAIL;
+
+ /* Convert the result to wide characters */
+ MultiByteToWideChar_alloc(CP_ACP, 0, str, -1, &w_buffer, &len);
+ vim_free(str);
+ if (w_buffer == NULL)
+ return E_OUTOFMEMORY;
+
+ if (len == 0)
+ {
+ vim_free(w_buffer);
+ return E_FAIL;
+ }
+
+ /* Store the result */
+ *result = SysAllocString(w_buffer);
+ vim_free(w_buffer);
+
+ return S_OK;
+#else
+ return E_NOTIMPL;
+#endif
+}
+
+/*****************************************************************************
+ 3. The class factory
+*****************************************************************************/
+
+/* Definition
+ * ----------
+ */
+
+class CVimCF FINAL : public IClassFactory
+{
+public:
+ static CVimCF *Create();
+ virtual ~CVimCF() {};
+
+ STDMETHOD(QueryInterface)(REFIID riid, void ** ppv);
+ STDMETHOD_(unsigned long, AddRef)(void);
+ STDMETHOD_(unsigned long, Release)(void);
+ STDMETHOD(CreateInstance)(IUnknown *punkOuter, REFIID riid, void ** ppv);
+ STDMETHOD(LockServer)(BOOL lock);
+
+private:
+ // Constructor is private - create via Create()
+ CVimCF() : ref(0) {};
+
+ // Reference count
+ unsigned long ref;
+};
+
+/* Implementation
+ * --------------
+ */
+
+CVimCF *CVimCF::Create()
+{
+ CVimCF *me = new CVimCF();
+
+ if (me == NULL)
+ MessageBox(0, "Cannot create class factory", "Vim Initialisation", 0);
+
+ return me;
+}
+
+STDMETHODIMP
+CVimCF::QueryInterface(REFIID riid, void **ppv)
+{
+ if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IClassFactory))
+ {
+ AddRef();
+ *ppv = this;
+ return S_OK;
+ }
+
+ *ppv = 0;
+ return E_NOINTERFACE;
+}
+
+STDMETHODIMP_(ULONG)
+CVimCF::AddRef()
+{
+ return ++ref;
+}
+
+STDMETHODIMP_(ULONG)
+CVimCF::Release()
+{
+ // Don't delete the object when the reference count reaches zero, as there
+ // is only a single application object, and its lifetime is controlled by
+ // the running instance, not by its reference count.
+ if (ref > 0)
+ --ref;
+ return ref;
+}
+
+/*ARGSUSED*/
+STDMETHODIMP
+CVimCF::CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv)
+{
+ return app->QueryInterface(riid, ppv);
+}
+
+/*ARGSUSED*/
+STDMETHODIMP
+CVimCF::LockServer(BOOL lock)
+{
+ return S_OK;
+}
+
+/*****************************************************************************
+ 4. Registry manipulation code
+*****************************************************************************/
+
+// Internal use only
+static void SetKeyAndValue(const char *path, const char *subkey, const char *value);
+static void GUIDtochar(const GUID &guid, char *GUID, int length);
+static void RecursiveDeleteKey(HKEY hKeyParent, const char *child);
+static const int GUID_STRING_SIZE = 39;
+
+// Register the component in the registry
+// When "silent" is TRUE don't give any messages.
+
+extern "C" void RegisterMe(int silent)
+{
+ BOOL ok = TRUE;
+
+ // Get the application startup command
+ char module[MAX_PATH];
+
+ ::GetModuleFileName(NULL, module, MAX_PATH);
+
+ // Unregister first (quietly)
+ UnregisterMe(FALSE);
+
+ // Convert the CLSID into a char
+ char clsid[GUID_STRING_SIZE];
+ GUIDtochar(MYCLSID, clsid, sizeof(clsid));
+
+ // Convert the LIBID into a char
+ char libid[GUID_STRING_SIZE];
+ GUIDtochar(MYLIBID, libid, sizeof(libid));
+
+ // Build the key CLSID\\{...}
+ char Key[MAX_CLSID_LEN];
+ strcpy(Key, "CLSID\\");
+ strcat(Key, clsid);
+
+ // Add the CLSID to the registry
+ SetKeyAndValue(Key, NULL, MYNAME);
+ SetKeyAndValue(Key, "LocalServer32", module);
+ SetKeyAndValue(Key, "ProgID", MYPROGID);
+ SetKeyAndValue(Key, "VersionIndependentProgID", MYVIPROGID);
+ SetKeyAndValue(Key, "TypeLib", libid);
+
+ // Add the version-independent ProgID subkey under HKEY_CLASSES_ROOT
+ SetKeyAndValue(MYVIPROGID, NULL, MYNAME);
+ SetKeyAndValue(MYVIPROGID, "CLSID", clsid);
+ SetKeyAndValue(MYVIPROGID, "CurVer", MYPROGID);
+
+ // Add the versioned ProgID subkey under HKEY_CLASSES_ROOT
+ SetKeyAndValue(MYPROGID, NULL, MYNAME);
+ SetKeyAndValue(MYPROGID, "CLSID", clsid);
+
+ wchar_t w_module[MAX_PATH];
+ MultiByteToWideChar(CP_ACP, 0, module, -1, w_module, MAX_PATH);
+
+ ITypeLib *typelib = NULL;
+ if (LoadTypeLib(w_module, &typelib) != S_OK)
+ {
+ if (!silent)
+ MessageBox(0, "Cannot load type library to register",
+ "Vim Registration", 0);
+ ok = FALSE;
+ }
+ else
+ {
+ if (RegisterTypeLib(typelib, w_module, NULL) != S_OK)
+ {
+ if (!silent)
+ MessageBox(0, "Cannot register type library",
+ "Vim Registration", 0);
+ ok = FALSE;
+ }
+ typelib->Release();
+ }
+
+ if (ok && !silent)
+ MessageBox(0, "Registered successfully", "Vim", 0);
+}
+
+// Remove the component from the registry
+//
+// Note: There is little error checking in this code, to allow incomplete
+// or failed registrations to be undone.
+extern "C" void UnregisterMe(int bNotifyUser)
+{
+ // Unregister the type library
+ ITypeLib *typelib;
+ if (SUCCEEDED(LoadRegTypeLib(MYLIBID, MAJORVER, MINORVER, LOCALE, &typelib)))
+ {
+ TLIBATTR *tla;
+ if (SUCCEEDED(typelib->GetLibAttr(&tla)))
+ {
+ UnRegisterTypeLib(tla->guid, tla->wMajorVerNum, tla->wMinorVerNum,
+ tla->lcid, tla->syskind);
+ typelib->ReleaseTLibAttr(tla);
+ }
+ typelib->Release();
+ }
+
+ // Convert the CLSID into a char
+ char clsid[GUID_STRING_SIZE];
+ GUIDtochar(MYCLSID, clsid, sizeof(clsid));
+
+ // Build the key CLSID\\{...}
+ char Key[MAX_CLSID_LEN];
+ strcpy(Key, "CLSID\\");
+ strcat(Key, clsid);
+
+ // Delete the CLSID Key - CLSID\{...}
+ RecursiveDeleteKey(HKEY_CLASSES_ROOT, Key);
+
+ // Delete the version-independent ProgID Key
+ RecursiveDeleteKey(HKEY_CLASSES_ROOT, MYVIPROGID);
+
+ // Delete the ProgID key
+ RecursiveDeleteKey(HKEY_CLASSES_ROOT, MYPROGID);
+
+ if (bNotifyUser)
+ MessageBox(0, "Unregistered successfully", "Vim", 0);
+}
+
+/****************************************************************************/
+
+// Convert a GUID to a char string
+static void GUIDtochar(const GUID &guid, char *GUID, int length)
+{
+ // Get wide string version
+ LPOLESTR wGUID = NULL;
+ StringFromCLSID(guid, &wGUID);
+
+ // Covert from wide characters to non-wide
+ wcstombs(GUID, wGUID, length);
+
+ // Free memory
+ CoTaskMemFree(wGUID);
+}
+
+// Delete a key and all of its descendants
+static void RecursiveDeleteKey(HKEY hKeyParent, const char *child)
+{
+ // Open the child
+ HKEY hKeyChild;
+ LONG result = RegOpenKeyEx(hKeyParent, child, 0,
+ KEY_ALL_ACCESS, &hKeyChild);
+ if (result != ERROR_SUCCESS)
+ return;
+
+ // Enumerate all of the descendants of this child
+ FILETIME time;
+ char buffer[1024];
+ DWORD size = 1024;
+
+ while (RegEnumKeyEx(hKeyChild, 0, buffer, &size, NULL,
+ NULL, NULL, &time) == S_OK)
+ {
+ // Delete the descendants of this child
+ RecursiveDeleteKey(hKeyChild, buffer);
+ size = 256;
+ }
+
+ // Close the child
+ RegCloseKey(hKeyChild);
+
+ // Delete this child
+ RegDeleteKey(hKeyParent, child);
+}
+
+// Create a key and set its value
+static void SetKeyAndValue(const char *key, const char *subkey, const char *value)
+{
+ HKEY hKey;
+ char buffer[1024];
+
+ strcpy(buffer, key);
+
+ // Add subkey name to buffer.
+ if (subkey)
+ {
+ strcat(buffer, "\\");
+ strcat(buffer, subkey);
+ }
+
+ // Create and open key and subkey.
+ long result = RegCreateKeyEx(HKEY_CLASSES_ROOT,
+ buffer,
+ 0, NULL, REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS, NULL,
+ &hKey, NULL);
+ if (result != ERROR_SUCCESS)
+ return;
+
+ // Set the value
+ if (value)
+ RegSetValueEx(hKey, NULL, 0, REG_SZ, (BYTE *)value,
+ (DWORD)STRLEN(value)+1);
+
+ RegCloseKey(hKey);
+}
+
+/*****************************************************************************
+ 5. OLE Initialisation and shutdown processing
+*****************************************************************************/
+extern "C" void InitOLE(int *pbDoRestart)
+{
+ HRESULT hr;
+
+ *pbDoRestart = FALSE;
+
+ // Initialize the OLE libraries
+ hr = OleInitialize(NULL);
+ if (FAILED(hr))
+ {
+ MessageBox(0, "Cannot initialise OLE", "Vim Initialisation", 0);
+ goto error0;
+ }
+
+ // Create the application object
+ app = CVim::Create(pbDoRestart);
+ if (app == NULL)
+ goto error1;
+
+ // Create the class factory
+ cf = CVimCF::Create();
+ if (cf == NULL)
+ goto error1;
+
+ // Register the class factory
+ hr = CoRegisterClassObject(
+ MYCLSID,
+ cf,
+ CLSCTX_LOCAL_SERVER,
+ REGCLS_MULTIPLEUSE,
+ &cf_id);
+
+ if (FAILED(hr))
+ {
+ MessageBox(0, "Cannot register class factory", "Vim Initialisation", 0);
+ goto error1;
+ }
+
+ // Register the application object as active
+ hr = RegisterActiveObject(
+ app,
+ MYCLSID,
+ 0,
+ &app_id);
+
+ if (FAILED(hr))
+ {
+ MessageBox(0, "Cannot register application object", "Vim Initialisation", 0);
+ goto error1;
+ }
+
+ return;
+
+ // Errors: tidy up as much as needed and return
+error1:
+ UninitOLE();
+error0:
+ return;
+}
+
+extern "C" void UninitOLE()
+{
+ // Unregister the application object
+ if (app_id)
+ {
+ RevokeActiveObject(app_id, NULL);
+ app_id = 0;
+ }
+
+ // Unregister the class factory
+ if (cf_id)
+ {
+ CoRevokeClassObject(cf_id);
+ cf_id = 0;
+ }
+
+ // Shut down the OLE libraries
+ OleUninitialize();
+
+ // Delete the application object
+ if (app)
+ {
+ delete app;
+ app = NULL;
+ }
+
+ // Delete the class factory
+ if (cf)
+ {
+ delete cf;
+ cf = NULL;
+ }
+}
+#endif /* FEAT_OLE */
diff --git a/src/if_ole.h b/src/if_ole.h
new file mode 100644
index 0000000..5749cdb
--- /dev/null
+++ b/src/if_ole.h
@@ -0,0 +1,292 @@
+/* this ALWAYS GENERATED file contains the definitions for the interfaces */
+
+
+/* File created by MIDL compiler version 3.01.75 */
+/* at Wed Jun 06 18:20:37 2001
+ */
+/* Compiler settings for .\if_ole.idl:
+ Os (OptLev=s), W1, Zp8, env=Win32, ms_ext, c_ext
+ error checks: none
+*/
+//@@MIDL_FILE_HEADING( )
+#include "rpc.h"
+#include "rpcndr.h"
+#ifndef COM_NO_WINDOWS_H
+#include "windows.h"
+#include "ole2.h"
+#endif /*COM_NO_WINDOWS_H*/
+
+#ifndef __if_ole_h__
+#define __if_ole_h__
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+/* Forward Declarations */
+
+#ifndef __IVim_FWD_DEFINED__
+#define __IVim_FWD_DEFINED__
+typedef interface IVim IVim;
+#endif /* __IVim_FWD_DEFINED__ */
+
+
+#ifndef __Vim_FWD_DEFINED__
+#define __Vim_FWD_DEFINED__
+
+#ifdef __cplusplus
+typedef class Vim Vim;
+#else
+typedef struct Vim Vim;
+#endif /* __cplusplus */
+
+#endif /* __Vim_FWD_DEFINED__ */
+
+
+/* header files for imported files */
+#include "oaidl.h"
+
+#ifndef __MIDL_user_allocate_free_DEFINED__
+#define __MIDL_user_allocate_free_DEFINED__
+ void __RPC_FAR * __RPC_USER MIDL_user_allocate(size_t);
+ void __RPC_USER MIDL_user_free( void __RPC_FAR * );
+#endif
+
+#ifndef __IVim_INTERFACE_DEFINED__
+#define __IVim_INTERFACE_DEFINED__
+
+/****************************************
+ * Generated header for interface: IVim
+ * at Wed Jun 06 18:20:37 2001
+ * using MIDL 3.01.75
+ ****************************************/
+/* [oleautomation][dual][unique][helpstring][uuid][object] */
+
+
+
+EXTERN_C const IID IID_IVim;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ interface DECLSPEC_UUID("0F0BFAE2-4C90-11d1-82D7-0004AC368519")
+ IVim : public IDispatch
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE SendKeys(
+ /* [in] */ BSTR keys) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Eval(
+ /* [in] */ BSTR expr,
+ /* [retval][out] */ BSTR __RPC_FAR *result) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetForeground( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetHwnd(
+ /* [retval][out] */ UINT_PTR __RPC_FAR *result) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IVimVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE __RPC_FAR *QueryInterface )(
+ IVim __RPC_FAR * This,
+ /* [in] */ REFIID riid,
+ /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE __RPC_FAR *AddRef )(
+ IVim __RPC_FAR * This);
+
+ ULONG ( STDMETHODCALLTYPE __RPC_FAR *Release )(
+ IVim __RPC_FAR * This);
+
+ HRESULT ( STDMETHODCALLTYPE __RPC_FAR *GetTypeInfoCount )(
+ IVim __RPC_FAR * This,
+ /* [out] */ UINT __RPC_FAR *pctinfo);
+
+ HRESULT ( STDMETHODCALLTYPE __RPC_FAR *GetTypeInfo )(
+ IVim __RPC_FAR * This,
+ /* [in] */ UINT iTInfo,
+ /* [in] */ LCID lcid,
+ /* [out] */ ITypeInfo __RPC_FAR *__RPC_FAR *ppTInfo);
+
+ HRESULT ( STDMETHODCALLTYPE __RPC_FAR *GetIDsOfNames )(
+ IVim __RPC_FAR * This,
+ /* [in] */ REFIID riid,
+ /* [size_is][in] */ LPOLESTR __RPC_FAR *rgszNames,
+ /* [in] */ UINT cNames,
+ /* [in] */ LCID lcid,
+ /* [size_is][out] */ DISPID __RPC_FAR *rgDispId);
+
+ /* [local] */ HRESULT ( STDMETHODCALLTYPE __RPC_FAR *Invoke )(
+ IVim __RPC_FAR * This,
+ /* [in] */ DISPID dispIdMember,
+ /* [in] */ REFIID riid,
+ /* [in] */ LCID lcid,
+ /* [in] */ WORD wFlags,
+ /* [out][in] */ DISPPARAMS __RPC_FAR *pDispParams,
+ /* [out] */ VARIANT __RPC_FAR *pVarResult,
+ /* [out] */ EXCEPINFO __RPC_FAR *pExcepInfo,
+ /* [out] */ UINT __RPC_FAR *puArgErr);
+
+ HRESULT ( STDMETHODCALLTYPE __RPC_FAR *SendKeys )(
+ IVim __RPC_FAR * This,
+ /* [in] */ BSTR keys);
+
+ HRESULT ( STDMETHODCALLTYPE __RPC_FAR *Eval )(
+ IVim __RPC_FAR * This,
+ /* [in] */ BSTR expr,
+ /* [retval][out] */ BSTR __RPC_FAR *result);
+
+ HRESULT ( STDMETHODCALLTYPE __RPC_FAR *SetForeground )(
+ IVim __RPC_FAR * This);
+
+ HRESULT ( STDMETHODCALLTYPE __RPC_FAR *GetHwnd )(
+ IVim __RPC_FAR * This,
+ /* [retval][out] */ UINT_PTR __RPC_FAR *result);
+
+ END_INTERFACE
+ } IVimVtbl;
+
+ interface IVim
+ {
+ CONST_VTBL struct IVimVtbl __RPC_FAR *lpVtbl;
+ };
+
+#ifdef COBJMACROS
+
+
+#define IVim_QueryInterface(This,riid,ppvObject) \
+ (This)->lpVtbl -> QueryInterface(This,riid,ppvObject)
+
+#define IVim_AddRef(This) \
+ (This)->lpVtbl -> AddRef(This)
+
+#define IVim_Release(This) \
+ (This)->lpVtbl -> Release(This)
+
+
+#define IVim_GetTypeInfoCount(This,pctinfo) \
+ (This)->lpVtbl -> GetTypeInfoCount(This,pctinfo)
+
+#define IVim_GetTypeInfo(This,iTInfo,lcid,ppTInfo) \
+ (This)->lpVtbl -> GetTypeInfo(This,iTInfo,lcid,ppTInfo)
+
+#define IVim_GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) \
+ (This)->lpVtbl -> GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId)
+
+#define IVim_Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) \
+ (This)->lpVtbl -> Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr)
+
+
+#define IVim_SendKeys(This,keys) \
+ (This)->lpVtbl -> SendKeys(This,keys)
+
+#define IVim_Eval(This,expr,result) \
+ (This)->lpVtbl -> Eval(This,expr,result)
+
+#define IVim_SetForeground(This) \
+ (This)->lpVtbl -> SetForeground(This)
+
+#define IVim_GetHwnd(This,result) \
+ (This)->lpVtbl -> GetHwnd(This,result)
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+HRESULT STDMETHODCALLTYPE IVim_SendKeys_Proxy(
+ IVim __RPC_FAR * This,
+ /* [in] */ BSTR keys);
+
+
+void __RPC_STUB IVim_SendKeys_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+HRESULT STDMETHODCALLTYPE IVim_Eval_Proxy(
+ IVim __RPC_FAR * This,
+ /* [in] */ BSTR expr,
+ /* [retval][out] */ BSTR __RPC_FAR *result);
+
+
+void __RPC_STUB IVim_Eval_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+HRESULT STDMETHODCALLTYPE IVim_SetForeground_Proxy(
+ IVim __RPC_FAR * This);
+
+
+void __RPC_STUB IVim_SetForeground_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+HRESULT STDMETHODCALLTYPE IVim_GetHwnd_Proxy(
+ IVim __RPC_FAR * This,
+ /* [retval][out] */ UINT_PTR __RPC_FAR *result);
+
+
+void __RPC_STUB IVim_GetHwnd_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+
+#endif /* __IVim_INTERFACE_DEFINED__ */
+
+
+
+#ifndef __Vim_LIBRARY_DEFINED__
+#define __Vim_LIBRARY_DEFINED__
+
+/****************************************
+ * Generated header for library: Vim
+ * at Wed Jun 06 18:20:37 2001
+ * using MIDL 3.01.75
+ ****************************************/
+/* [version][helpstring][uuid] */
+
+
+
+EXTERN_C const IID LIBID_Vim;
+
+#ifdef __cplusplus
+EXTERN_C const CLSID CLSID_Vim;
+
+class DECLSPEC_UUID("0F0BFAE1-4C90-11d1-82D7-0004AC368519")
+Vim;
+#endif
+#endif /* __Vim_LIBRARY_DEFINED__ */
+
+/* Additional Prototypes for ALL interfaces */
+
+unsigned long __RPC_USER BSTR_UserSize( unsigned long __RPC_FAR *, unsigned long , BSTR __RPC_FAR * );
+unsigned char __RPC_FAR * __RPC_USER BSTR_UserMarshal( unsigned long __RPC_FAR *, unsigned char __RPC_FAR *, BSTR __RPC_FAR * );
+unsigned char __RPC_FAR * __RPC_USER BSTR_UserUnmarshal(unsigned long __RPC_FAR *, unsigned char __RPC_FAR *, BSTR __RPC_FAR * );
+void __RPC_USER BSTR_UserFree( unsigned long __RPC_FAR *, BSTR __RPC_FAR * );
+
+/* end of Additional Prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/if_ole.idl b/src/if_ole.idl
new file mode 100644
index 0000000..3629faf
--- /dev/null
+++ b/src/if_ole.idl
@@ -0,0 +1,45 @@
+// if_ole.idl - IDL source for the Vim OLE Automation interface
+//
+// Processed by the IDL compiler (MIDL) to generate the type library
+// (Vim.tlb).
+//
+// Command line:
+// MIDL /proxy nul /iid iid_ole.c /h if_ole.h /tlb vim.tlb if_ole.idl
+
+[
+ object,
+ uuid(0F0BFAE2-4C90-11d1-82D7-0004AC368519), // IID_IVim
+ helpstring("IVim"),
+ pointer_default(unique),
+ dual,
+ oleautomation
+]
+interface IVim : IDispatch
+{
+ import "oaidl.idl";
+ HRESULT SendKeys([in]BSTR keys);
+ HRESULT Eval([in]BSTR expr, [out, retval]BSTR* result);
+ HRESULT SetForeground(void);
+ HRESULT GetHwnd([out, retval]UINT_PTR* result);
+};
+
+// Component and type library definitions
+[
+ uuid(0F0BFAE0-4C90-11d1-82D7-0004AC368519), // LIBID_Vim
+ helpstring("Vim OLE Interface 1.1 Type Library"),
+ version(1.1)
+]
+library Vim
+{
+ importlib("stdole32.tlb");
+
+ // Component
+ [
+ uuid(0F0BFAE1-4C90-11d1-82D7-0004AC368519), // CLSID_Vim
+ helpstring("Vim OLE Interface")
+ ]
+ coclass Vim
+ {
+ [default] interface IVim;
+ };
+};
diff --git a/src/if_perl.xs b/src/if_perl.xs
new file mode 100644
index 0000000..203bb6a
--- /dev/null
+++ b/src/if_perl.xs
@@ -0,0 +1,1925 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * Do ":help uganda" in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ */
+/*
+ * if_perl.xs: Main code for Perl interface support.
+ * Mostly written by Sven Verdoolaege.
+ */
+
+#define _memory_h /* avoid memset redeclaration */
+#define IN_PERL_FILE /* don't include if_perl.pro from proto.h */
+
+/*
+ * Currently 32-bit version of ActivePerl is built with VC6 (or MinGW since
+ * ActivePerl 5.18).
+ * (http://community.activestate.com/faq/windows-compilers-perl-modules)
+ * It means that time_t should be 32-bit. However the default size of
+ * time_t is 64-bit since VC8. So we have to define _USE_32BIT_TIME_T.
+ */
+#if defined(WIN32) && !defined(_WIN64)
+# define _USE_32BIT_TIME_T
+#endif
+
+/*
+ * Prevent including winsock.h. perl.h tries to detect whether winsock.h is
+ * already included before including winsock2.h, because winsock2.h isn't
+ * compatible with winsock.h. However the detection doesn't work with some
+ * versions of MinGW. If WIN32_LEAN_AND_MEAN is defined, windows.h will not
+ * include winsock.h.
+ */
+#ifdef WIN32
+# define WIN32_LEAN_AND_MEAN
+#endif
+
+#include "vim.h"
+
+/* Work around for perl-5.18.
+ * Don't include "perl\lib\CORE\inline.h" for now,
+ * include it after Perl_sv_free2 is defined. */
+#ifdef DYNAMIC_PERL
+# define PERL_NO_INLINE_FUNCTIONS
+#endif
+
+/* Work around for using MSVC and ActivePerl 5.18. */
+#ifdef _MSC_VER
+# define __inline__ __inline
+#endif
+
+#ifdef __GNUC__
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wunused-variable"
+#endif
+
+#include <EXTERN.h>
+#include <perl.h>
+#include <XSUB.h>
+#if defined(PERLIO_LAYERS) && !defined(USE_SFIO)
+# include <perliol.h>
+#endif
+
+/* Workaround for perl < 5.8.7 */
+#ifndef PERLIO_FUNCS_DECL
+# ifdef PERLIO_FUNCS_CONST
+# define PERLIO_FUNCS_DECL(funcs) const PerlIO_funcs funcs
+# define PERLIO_FUNCS_CAST(funcs) (PerlIO_funcs*)(funcs)
+# else
+# define PERLIO_FUNCS_DECL(funcs) PerlIO_funcs funcs
+# define PERLIO_FUNCS_CAST(funcs) (funcs)
+# endif
+#endif
+#ifndef SvREFCNT_inc_void_NN
+# define SvREFCNT_inc_void_NN SvREFCNT_inc
+#endif
+
+/*
+ * Work around clashes between Perl and Vim namespace. proto.h doesn't
+ * include if_perl.pro and perlsfio.pro when IN_PERL_FILE is defined, because
+ * we need the CV typedef. proto.h can't be moved to after including
+ * if_perl.h, because we get all sorts of name clashes then.
+ */
+#ifndef PROTO
+# ifndef __MINGW32__
+# include "proto/if_perl.pro"
+# include "proto/if_perlsfio.pro"
+# endif
+#endif
+
+// Perl compatibility stuff. This should ensure compatibility with older
+// versions of Perl.
+#ifndef PERL_VERSION
+# include <patchlevel.h>
+# define PERL_REVISION 5
+# define PERL_VERSION PATCHLEVEL
+# define PERL_SUBVERSION SUBVERSION
+#endif
+
+
+// Work around for ActivePerl 5.20.3+: Avoid generating (g)vim.lib.
+#if defined(ACTIVEPERL_VERSION) && (ACTIVEPERL_VERSION >= 2003) \
+ && defined(WIN32) && defined(USE_DYNAMIC_LOADING)
+# undef XS_EXTERNAL
+# define XS_EXTERNAL(name) XSPROTO(name)
+#endif
+
+/*
+ * Quoting Jan Dubois of Active State:
+ * ActivePerl build 822 still identifies itself as 5.8.8 but already
+ * contains many of the changes from the upcoming Perl 5.8.9 release.
+ *
+ * The changes include addition of two symbols (Perl_sv_2iv_flags,
+ * Perl_newXS_flags) not present in earlier releases.
+ *
+ * Jan Dubois suggested the following guarding scheme.
+ *
+ * Active State defined ACTIVEPERL_VERSION as a string in versions before
+ * 5.8.8; and so the comparison to 822 below needs to be guarded.
+ */
+#if (PERL_REVISION == 5) && (PERL_VERSION == 8) && (PERL_SUBVERSION >= 8)
+# if (ACTIVEPERL_VERSION >= 822) || (PERL_SUBVERSION >= 9)
+# define PERL589_OR_LATER
+# endif
+#endif
+#if (PERL_REVISION == 5) && (PERL_VERSION >= 9)
+# define PERL589_OR_LATER
+#endif
+
+#if (PERL_REVISION == 5) && ((PERL_VERSION > 10) || \
+ (PERL_VERSION == 10) && (PERL_SUBVERSION >= 1))
+# define PERL5101_OR_LATER
+#endif
+
+#ifndef pTHX
+# define pTHX void
+# define pTHX_
+#endif
+
+#ifndef EXTERN_C
+# define EXTERN_C
+#endif
+
+/* Compatibility hacks over */
+
+static PerlInterpreter *perl_interp = NULL;
+static void xs_init(pTHX);
+static void VIM_init(void);
+EXTERN_C void boot_DynaLoader(pTHX_ CV*);
+
+/*
+ * For dynamic linked perl.
+ */
+#if defined(DYNAMIC_PERL) || defined(PROTO)
+
+# ifndef DYNAMIC_PERL /* just generating prototypes */
+# ifdef WIN3264
+typedef int HANDLE;
+# endif
+typedef int XSINIT_t;
+typedef int XSUBADDR_t;
+# endif
+# ifndef USE_ITHREADS
+typedef int perl_key;
+# endif
+
+# ifndef WIN3264
+# include <dlfcn.h>
+# define HANDLE void*
+# define PERL_PROC void*
+# define load_dll(n) dlopen((n), RTLD_LAZY|RTLD_GLOBAL)
+# define symbol_from_dll dlsym
+# define close_dll dlclose
+# else
+# define PERL_PROC FARPROC
+# define load_dll vimLoadLib
+# define symbol_from_dll GetProcAddress
+# define close_dll FreeLibrary
+# endif
+/*
+ * Wrapper defines
+ */
+# define perl_alloc dll_perl_alloc
+# define perl_construct dll_perl_construct
+# define perl_parse dll_perl_parse
+# define perl_run dll_perl_run
+# define perl_destruct dll_perl_destruct
+# define perl_free dll_perl_free
+# define Perl_get_context dll_Perl_get_context
+# define Perl_croak dll_Perl_croak
+# ifdef PERL5101_OR_LATER
+# define Perl_croak_xs_usage dll_Perl_croak_xs_usage
+# endif
+# ifndef PROTO
+# define Perl_croak_nocontext dll_Perl_croak_nocontext
+# define Perl_call_argv dll_Perl_call_argv
+# define Perl_call_pv dll_Perl_call_pv
+# define Perl_eval_sv dll_Perl_eval_sv
+# define Perl_get_sv dll_Perl_get_sv
+# define Perl_eval_pv dll_Perl_eval_pv
+# define Perl_call_method dll_Perl_call_method
+# endif
+# define Perl_dowantarray dll_Perl_dowantarray
+# define Perl_free_tmps dll_Perl_free_tmps
+# define Perl_gv_stashpv dll_Perl_gv_stashpv
+# define Perl_markstack_grow dll_Perl_markstack_grow
+# define Perl_mg_find dll_Perl_mg_find
+# if (PERL_REVISION == 5) && (PERL_VERSION >= 28)
+# define Perl_mg_get dll_Perl_mg_get
+# endif
+# define Perl_newXS dll_Perl_newXS
+# define Perl_newSV dll_Perl_newSV
+# define Perl_newSViv dll_Perl_newSViv
+# define Perl_newSVpv dll_Perl_newSVpv
+# define Perl_pop_scope dll_Perl_pop_scope
+# define Perl_push_scope dll_Perl_push_scope
+# define Perl_save_int dll_Perl_save_int
+# if (PERL_REVISION == 5) && (PERL_VERSION >= 20)
+# define Perl_save_strlen dll_Perl_save_strlen
+# endif
+# define Perl_stack_grow dll_Perl_stack_grow
+# define Perl_set_context dll_Perl_set_context
+# if (PERL_REVISION == 5) && (PERL_VERSION >= 14)
+# define Perl_sv_2bool_flags dll_Perl_sv_2bool_flags
+# if (PERL_REVISION == 5) && (PERL_VERSION < 22)
+# define Perl_xs_apiversion_bootcheck dll_Perl_xs_apiversion_bootcheck
+# endif
+# else
+# define Perl_sv_2bool dll_Perl_sv_2bool
+# endif
+# define Perl_sv_2iv dll_Perl_sv_2iv
+# define Perl_sv_2mortal dll_Perl_sv_2mortal
+# if (PERL_REVISION == 5) && (PERL_VERSION >= 8)
+# define Perl_sv_2pv_flags dll_Perl_sv_2pv_flags
+# define Perl_sv_2pv_nolen dll_Perl_sv_2pv_nolen
+# else
+# define Perl_sv_2pv dll_Perl_sv_2pv
+# endif
+# define Perl_sv_2pvbyte dll_Perl_sv_2pvbyte
+# define Perl_sv_bless dll_Perl_sv_bless
+# if (PERL_REVISION == 5) && (PERL_VERSION >= 8)
+# define Perl_sv_catpvn_flags dll_Perl_sv_catpvn_flags
+# else
+# define Perl_sv_catpvn dll_Perl_sv_catpvn
+# endif
+# ifdef PERL589_OR_LATER
+# define Perl_sv_2iv_flags dll_Perl_sv_2iv_flags
+# define Perl_newXS_flags dll_Perl_newXS_flags
+# endif
+# define Perl_sv_free dll_Perl_sv_free
+# if (PERL_REVISION == 5) && (PERL_VERSION >= 10)
+# define Perl_sv_free2 dll_Perl_sv_free2
+# endif
+# define Perl_sv_isa dll_Perl_sv_isa
+# define Perl_sv_magic dll_Perl_sv_magic
+# define Perl_sv_setiv dll_Perl_sv_setiv
+# define Perl_sv_setpv dll_Perl_sv_setpv
+# define Perl_sv_setpvn dll_Perl_sv_setpvn
+# if (PERL_REVISION == 5) && (PERL_VERSION >= 8)
+# define Perl_sv_setsv_flags dll_Perl_sv_setsv_flags
+# else
+# define Perl_sv_setsv dll_Perl_sv_setsv
+# endif
+# define Perl_sv_upgrade dll_Perl_sv_upgrade
+# define Perl_Tstack_sp_ptr dll_Perl_Tstack_sp_ptr
+# define Perl_Top_ptr dll_Perl_Top_ptr
+# define Perl_Tstack_base_ptr dll_Perl_Tstack_base_ptr
+# define Perl_Tstack_max_ptr dll_Perl_Tstack_max_ptr
+# define Perl_Ttmps_ix_ptr dll_Perl_Ttmps_ix_ptr
+# define Perl_Ttmps_floor_ptr dll_Perl_Ttmps_floor_ptr
+# define Perl_Tmarkstack_ptr_ptr dll_Perl_Tmarkstack_ptr_ptr
+# define Perl_Tmarkstack_max_ptr dll_Perl_Tmarkstack_max_ptr
+# define Perl_TSv_ptr dll_Perl_TSv_ptr
+# define Perl_TXpv_ptr dll_Perl_TXpv_ptr
+# define Perl_Tna_ptr dll_Perl_Tna_ptr
+# define Perl_Idefgv_ptr dll_Perl_Idefgv_ptr
+# define Perl_Ierrgv_ptr dll_Perl_Ierrgv_ptr
+# define Perl_Isv_yes_ptr dll_Perl_Isv_yes_ptr
+# define boot_DynaLoader dll_boot_DynaLoader
+# define Perl_Gthr_key_ptr dll_Perl_Gthr_key_ptr
+
+# define Perl_sys_init dll_Perl_sys_init
+# define Perl_sys_term dll_Perl_sys_term
+# define Perl_ISv_ptr dll_Perl_ISv_ptr
+# define Perl_Istack_max_ptr dll_Perl_Istack_max_ptr
+# define Perl_Istack_base_ptr dll_Perl_Istack_base_ptr
+# define Perl_Itmps_ix_ptr dll_Perl_Itmps_ix_ptr
+# define Perl_Itmps_floor_ptr dll_Perl_Itmps_floor_ptr
+# define Perl_IXpv_ptr dll_Perl_IXpv_ptr
+# define Perl_Ina_ptr dll_Perl_Ina_ptr
+# define Perl_Imarkstack_ptr_ptr dll_Perl_Imarkstack_ptr_ptr
+# define Perl_Imarkstack_max_ptr dll_Perl_Imarkstack_max_ptr
+# define Perl_Istack_sp_ptr dll_Perl_Istack_sp_ptr
+# define Perl_Iop_ptr dll_Perl_Iop_ptr
+# define Perl_call_list dll_Perl_call_list
+# define Perl_Iscopestack_ix_ptr dll_Perl_Iscopestack_ix_ptr
+# define Perl_Iunitcheckav_ptr dll_Perl_Iunitcheckav_ptr
+# if (PERL_REVISION == 5) && (PERL_VERSION >= 22)
+# define Perl_xs_handshake dll_Perl_xs_handshake
+# define Perl_xs_boot_epilog dll_Perl_xs_boot_epilog
+# endif
+# if (PERL_REVISION == 5) && (PERL_VERSION >= 14)
+# ifdef USE_ITHREADS
+# define PL_thr_key *dll_PL_thr_key
+# endif
+# endif
+# define Perl_hv_iternext_flags dll_Perl_hv_iternext_flags
+# define Perl_hv_iterinit dll_Perl_hv_iterinit
+# define Perl_hv_iterkey dll_Perl_hv_iterkey
+# define Perl_hv_iterval dll_Perl_hv_iterval
+# define Perl_av_fetch dll_Perl_av_fetch
+# define Perl_av_len dll_Perl_av_len
+# define Perl_sv_2nv_flags dll_Perl_sv_2nv_flags
+# if defined(PERLIO_LAYERS) && !defined(USE_SFIO)
+# define PerlIOBase_pushed dll_PerlIOBase_pushed
+# define PerlIO_define_layer dll_PerlIO_define_layer
+# endif
+# if (PERL_REVISION == 5) && (PERL_VERSION >= 24)
+# define Perl_savetmps dll_Perl_savetmps
+# endif
+
+/*
+ * Declare HANDLE for perl.dll and function pointers.
+ */
+static HANDLE hPerlLib = NULL;
+
+static PerlInterpreter* (*perl_alloc)();
+static void (*perl_construct)(PerlInterpreter*);
+static void (*perl_destruct)(PerlInterpreter*);
+static void (*perl_free)(PerlInterpreter*);
+static int (*perl_run)(PerlInterpreter*);
+static int (*perl_parse)(PerlInterpreter*, XSINIT_t, int, char**, char**);
+static void* (*Perl_get_context)(void);
+static void (*Perl_croak)(pTHX_ const char*, ...) __attribute__noreturn__;
+# ifdef PERL5101_OR_LATER
+/* Perl-5.18 has a different Perl_croak_xs_usage signature. */
+# if (PERL_REVISION == 5) && (PERL_VERSION >= 18)
+static void (*Perl_croak_xs_usage)(const CV *const, const char *const params)
+ __attribute__noreturn__;
+# else
+static void (*Perl_croak_xs_usage)(pTHX_ const CV *const, const char *const params)
+ __attribute__noreturn__;
+# endif
+# endif
+static void (*Perl_croak_nocontext)(const char*, ...) __attribute__noreturn__;
+static I32 (*Perl_dowantarray)(pTHX);
+static void (*Perl_free_tmps)(pTHX);
+static HV* (*Perl_gv_stashpv)(pTHX_ const char*, I32);
+# if (PERL_REVISION == 5) && (PERL_VERSION >= 22)
+static I32* (*Perl_markstack_grow)(pTHX);
+# else
+static void (*Perl_markstack_grow)(pTHX);
+# endif
+static MAGIC* (*Perl_mg_find)(pTHX_ SV*, int);
+# if (PERL_REVISION == 5) && (PERL_VERSION >= 28)
+static int (*Perl_mg_get)(pTHX_ SV*);
+# endif
+static CV* (*Perl_newXS)(pTHX_ char*, XSUBADDR_t, char*);
+static SV* (*Perl_newSV)(pTHX_ STRLEN);
+static SV* (*Perl_newSViv)(pTHX_ IV);
+static SV* (*Perl_newSVpv)(pTHX_ const char*, STRLEN);
+static I32 (*Perl_call_argv)(pTHX_ const char*, I32, char**);
+static I32 (*Perl_call_pv)(pTHX_ const char*, I32);
+static I32 (*Perl_eval_sv)(pTHX_ SV*, I32);
+static SV* (*Perl_get_sv)(pTHX_ const char*, I32);
+static SV* (*Perl_eval_pv)(pTHX_ const char*, I32);
+static SV* (*Perl_call_method)(pTHX_ const char*, I32);
+static void (*Perl_pop_scope)(pTHX);
+static void (*Perl_push_scope)(pTHX);
+static void (*Perl_save_int)(pTHX_ int*);
+# if (PERL_REVISION == 5) && (PERL_VERSION >= 20)
+static void (*Perl_save_strlen)(pTHX_ STRLEN* ptr);
+# endif
+static SV** (*Perl_stack_grow)(pTHX_ SV**, SV**p, int);
+static SV** (*Perl_set_context)(void*);
+# if (PERL_REVISION == 5) && (PERL_VERSION >= 14)
+static bool (*Perl_sv_2bool_flags)(pTHX_ SV*, I32);
+# if (PERL_REVISION == 5) && (PERL_VERSION < 22)
+static void (*Perl_xs_apiversion_bootcheck)(pTHX_ SV *module, const char *api_p, STRLEN api_len);
+# endif
+# else
+static bool (*Perl_sv_2bool)(pTHX_ SV*);
+# endif
+static IV (*Perl_sv_2iv)(pTHX_ SV*);
+static SV* (*Perl_sv_2mortal)(pTHX_ SV*);
+# if (PERL_REVISION == 5) && (PERL_VERSION >= 8)
+static char* (*Perl_sv_2pv_flags)(pTHX_ SV*, STRLEN*, I32);
+static char* (*Perl_sv_2pv_nolen)(pTHX_ SV*);
+# else
+static char* (*Perl_sv_2pv)(pTHX_ SV*, STRLEN*);
+# endif
+static char* (*Perl_sv_2pvbyte)(pTHX_ SV*, STRLEN*);
+static SV* (*Perl_sv_bless)(pTHX_ SV*, HV*);
+# if (PERL_REVISION == 5) && (PERL_VERSION >= 8)
+static void (*Perl_sv_catpvn_flags)(pTHX_ SV* , const char*, STRLEN, I32);
+# else
+static void (*Perl_sv_catpvn)(pTHX_ SV*, const char*, STRLEN);
+# endif
+# ifdef PERL589_OR_LATER
+static IV (*Perl_sv_2iv_flags)(pTHX_ SV* sv, I32 flags);
+static CV * (*Perl_newXS_flags)(pTHX_ const char *name, XSUBADDR_t subaddr, const char *const filename, const char *const proto, U32 flags);
+# endif
+static void (*Perl_sv_free)(pTHX_ SV*);
+static int (*Perl_sv_isa)(pTHX_ SV*, const char*);
+static void (*Perl_sv_magic)(pTHX_ SV*, SV*, int, const char*, I32);
+static void (*Perl_sv_setiv)(pTHX_ SV*, IV);
+static void (*Perl_sv_setpv)(pTHX_ SV*, const char*);
+static void (*Perl_sv_setpvn)(pTHX_ SV*, const char*, STRLEN);
+# if (PERL_REVISION == 5) && (PERL_VERSION >= 8)
+static void (*Perl_sv_setsv_flags)(pTHX_ SV*, SV*, I32);
+# else
+static void (*Perl_sv_setsv)(pTHX_ SV*, SV*);
+# endif
+static bool (*Perl_sv_upgrade)(pTHX_ SV*, U32);
+# if (PERL_REVISION == 5) && (PERL_VERSION < 10)
+static SV*** (*Perl_Tstack_sp_ptr)(register PerlInterpreter*);
+static OP** (*Perl_Top_ptr)(register PerlInterpreter*);
+static SV*** (*Perl_Tstack_base_ptr)(register PerlInterpreter*);
+static SV*** (*Perl_Tstack_max_ptr)(register PerlInterpreter*);
+static I32* (*Perl_Ttmps_ix_ptr)(register PerlInterpreter*);
+static I32* (*Perl_Ttmps_floor_ptr)(register PerlInterpreter*);
+static I32** (*Perl_Tmarkstack_ptr_ptr)(register PerlInterpreter*);
+static I32** (*Perl_Tmarkstack_max_ptr)(register PerlInterpreter*);
+static SV** (*Perl_TSv_ptr)(register PerlInterpreter*);
+static XPV** (*Perl_TXpv_ptr)(register PerlInterpreter*);
+static STRLEN* (*Perl_Tna_ptr)(register PerlInterpreter*);
+# else
+/* Perl-5.18 has a different Perl_sv_free2 signature. */
+# if (PERL_REVISION == 5) && (PERL_VERSION >= 18)
+static void (*Perl_sv_free2)(pTHX_ SV*, const U32);
+# else
+static void (*Perl_sv_free2)(pTHX_ SV*);
+# endif
+static void (*Perl_sys_init)(int* argc, char*** argv);
+static void (*Perl_sys_term)(void);
+static void (*Perl_call_list)(pTHX_ I32, AV*);
+# if (PERL_REVISION == 5) && (PERL_VERSION >= 14)
+# else
+static SV** (*Perl_ISv_ptr)(register PerlInterpreter*);
+static SV*** (*Perl_Istack_max_ptr)(register PerlInterpreter*);
+static SV*** (*Perl_Istack_base_ptr)(register PerlInterpreter*);
+static XPV** (*Perl_IXpv_ptr)(register PerlInterpreter*);
+static I32* (*Perl_Itmps_ix_ptr)(register PerlInterpreter*);
+static I32* (*Perl_Itmps_floor_ptr)(register PerlInterpreter*);
+static STRLEN* (*Perl_Ina_ptr)(register PerlInterpreter*);
+static I32** (*Perl_Imarkstack_ptr_ptr)(register PerlInterpreter*);
+static I32** (*Perl_Imarkstack_max_ptr)(register PerlInterpreter*);
+static SV*** (*Perl_Istack_sp_ptr)(register PerlInterpreter*);
+static OP** (*Perl_Iop_ptr)(register PerlInterpreter*);
+static I32* (*Perl_Iscopestack_ix_ptr)(register PerlInterpreter*);
+static AV** (*Perl_Iunitcheckav_ptr)(register PerlInterpreter*);
+# endif
+# endif
+# if (PERL_REVISION == 5) && (PERL_VERSION >= 22)
+static I32 (*Perl_xs_handshake)(const U32, void *, const char *, ...);
+static void (*Perl_xs_boot_epilog)(pTHX_ const U32);
+# endif
+
+# if (PERL_REVISION == 5) && (PERL_VERSION >= 14)
+# ifdef USE_ITHREADS
+static perl_key* dll_PL_thr_key;
+# endif
+# else
+static GV** (*Perl_Idefgv_ptr)(register PerlInterpreter*);
+static GV** (*Perl_Ierrgv_ptr)(register PerlInterpreter*);
+static SV* (*Perl_Isv_yes_ptr)(register PerlInterpreter*);
+static perl_key* (*Perl_Gthr_key_ptr)_((pTHX));
+# endif
+static void (*boot_DynaLoader)_((pTHX_ CV*));
+static HE * (*Perl_hv_iternext_flags)(pTHX_ HV *, I32);
+static I32 (*Perl_hv_iterinit)(pTHX_ HV *);
+static char * (*Perl_hv_iterkey)(pTHX_ HE *, I32 *);
+static SV * (*Perl_hv_iterval)(pTHX_ HV *, HE *);
+static SV** (*Perl_av_fetch)(pTHX_ AV *, SSize_t, I32);
+static SSize_t (*Perl_av_len)(pTHX_ AV *);
+static NV (*Perl_sv_2nv_flags)(pTHX_ SV *const, const I32);
+# if defined(PERLIO_LAYERS) && !defined(USE_SFIO)
+static IV (*PerlIOBase_pushed)(pTHX_ PerlIO *, const char *, SV *, PerlIO_funcs *);
+static void (*PerlIO_define_layer)(pTHX_ PerlIO_funcs *);
+# endif
+# if (PERL_REVISION == 5) && (PERL_VERSION >= 24)
+static void (*Perl_savetmps)(pTHX);
+# endif
+
+/*
+ * Table of name to function pointer of perl.
+ */
+static struct {
+ char* name;
+ PERL_PROC* ptr;
+} perl_funcname_table[] = {
+ {"perl_alloc", (PERL_PROC*)&perl_alloc},
+ {"perl_construct", (PERL_PROC*)&perl_construct},
+ {"perl_destruct", (PERL_PROC*)&perl_destruct},
+ {"perl_free", (PERL_PROC*)&perl_free},
+ {"perl_run", (PERL_PROC*)&perl_run},
+ {"perl_parse", (PERL_PROC*)&perl_parse},
+ {"Perl_get_context", (PERL_PROC*)&Perl_get_context},
+ {"Perl_croak", (PERL_PROC*)&Perl_croak},
+# ifdef PERL5101_OR_LATER
+ {"Perl_croak_xs_usage", (PERL_PROC*)&Perl_croak_xs_usage},
+# endif
+# ifdef PERL_IMPLICIT_CONTEXT
+ {"Perl_croak_nocontext", (PERL_PROC*)&Perl_croak_nocontext},
+# endif
+ {"Perl_dowantarray", (PERL_PROC*)&Perl_dowantarray},
+ {"Perl_free_tmps", (PERL_PROC*)&Perl_free_tmps},
+ {"Perl_gv_stashpv", (PERL_PROC*)&Perl_gv_stashpv},
+ {"Perl_markstack_grow", (PERL_PROC*)&Perl_markstack_grow},
+ {"Perl_mg_find", (PERL_PROC*)&Perl_mg_find},
+# if (PERL_REVISION == 5) && (PERL_VERSION >= 28)
+ {"Perl_mg_get", (PERL_PROC*)&Perl_mg_get},
+# endif
+ {"Perl_newXS", (PERL_PROC*)&Perl_newXS},
+ {"Perl_newSV", (PERL_PROC*)&Perl_newSV},
+ {"Perl_newSViv", (PERL_PROC*)&Perl_newSViv},
+ {"Perl_newSVpv", (PERL_PROC*)&Perl_newSVpv},
+ {"Perl_call_argv", (PERL_PROC*)&Perl_call_argv},
+ {"Perl_call_pv", (PERL_PROC*)&Perl_call_pv},
+ {"Perl_eval_sv", (PERL_PROC*)&Perl_eval_sv},
+ {"Perl_get_sv", (PERL_PROC*)&Perl_get_sv},
+ {"Perl_eval_pv", (PERL_PROC*)&Perl_eval_pv},
+ {"Perl_call_method", (PERL_PROC*)&Perl_call_method},
+ {"Perl_pop_scope", (PERL_PROC*)&Perl_pop_scope},
+ {"Perl_push_scope", (PERL_PROC*)&Perl_push_scope},
+ {"Perl_save_int", (PERL_PROC*)&Perl_save_int},
+# if (PERL_REVISION == 5) && (PERL_VERSION >= 20)
+ {"Perl_save_strlen", (PERL_PROC*)&Perl_save_strlen},
+# endif
+ {"Perl_stack_grow", (PERL_PROC*)&Perl_stack_grow},
+ {"Perl_set_context", (PERL_PROC*)&Perl_set_context},
+# if (PERL_REVISION == 5) && (PERL_VERSION >= 14)
+ {"Perl_sv_2bool_flags", (PERL_PROC*)&Perl_sv_2bool_flags},
+# if (PERL_REVISION == 5) && (PERL_VERSION < 22)
+ {"Perl_xs_apiversion_bootcheck",(PERL_PROC*)&Perl_xs_apiversion_bootcheck},
+# endif
+# else
+ {"Perl_sv_2bool", (PERL_PROC*)&Perl_sv_2bool},
+# endif
+ {"Perl_sv_2iv", (PERL_PROC*)&Perl_sv_2iv},
+ {"Perl_sv_2mortal", (PERL_PROC*)&Perl_sv_2mortal},
+# if (PERL_REVISION == 5) && (PERL_VERSION >= 8)
+ {"Perl_sv_2pv_flags", (PERL_PROC*)&Perl_sv_2pv_flags},
+ {"Perl_sv_2pv_nolen", (PERL_PROC*)&Perl_sv_2pv_nolen},
+# else
+ {"Perl_sv_2pv", (PERL_PROC*)&Perl_sv_2pv},
+# endif
+ {"Perl_sv_2pvbyte", (PERL_PROC*)&Perl_sv_2pvbyte},
+# ifdef PERL589_OR_LATER
+ {"Perl_sv_2iv_flags", (PERL_PROC*)&Perl_sv_2iv_flags},
+ {"Perl_newXS_flags", (PERL_PROC*)&Perl_newXS_flags},
+# endif
+ {"Perl_sv_bless", (PERL_PROC*)&Perl_sv_bless},
+# if (PERL_REVISION == 5) && (PERL_VERSION >= 8)
+ {"Perl_sv_catpvn_flags", (PERL_PROC*)&Perl_sv_catpvn_flags},
+# else
+ {"Perl_sv_catpvn", (PERL_PROC*)&Perl_sv_catpvn},
+# endif
+ {"Perl_sv_free", (PERL_PROC*)&Perl_sv_free},
+ {"Perl_sv_isa", (PERL_PROC*)&Perl_sv_isa},
+ {"Perl_sv_magic", (PERL_PROC*)&Perl_sv_magic},
+ {"Perl_sv_setiv", (PERL_PROC*)&Perl_sv_setiv},
+ {"Perl_sv_setpv", (PERL_PROC*)&Perl_sv_setpv},
+ {"Perl_sv_setpvn", (PERL_PROC*)&Perl_sv_setpvn},
+# if (PERL_REVISION == 5) && (PERL_VERSION >= 8)
+ {"Perl_sv_setsv_flags", (PERL_PROC*)&Perl_sv_setsv_flags},
+# else
+ {"Perl_sv_setsv", (PERL_PROC*)&Perl_sv_setsv},
+# endif
+ {"Perl_sv_upgrade", (PERL_PROC*)&Perl_sv_upgrade},
+# if (PERL_REVISION == 5) && (PERL_VERSION < 10)
+ {"Perl_Tstack_sp_ptr", (PERL_PROC*)&Perl_Tstack_sp_ptr},
+ {"Perl_Top_ptr", (PERL_PROC*)&Perl_Top_ptr},
+ {"Perl_Tstack_base_ptr", (PERL_PROC*)&Perl_Tstack_base_ptr},
+ {"Perl_Tstack_max_ptr", (PERL_PROC*)&Perl_Tstack_max_ptr},
+ {"Perl_Ttmps_ix_ptr", (PERL_PROC*)&Perl_Ttmps_ix_ptr},
+ {"Perl_Ttmps_floor_ptr", (PERL_PROC*)&Perl_Ttmps_floor_ptr},
+ {"Perl_Tmarkstack_ptr_ptr", (PERL_PROC*)&Perl_Tmarkstack_ptr_ptr},
+ {"Perl_Tmarkstack_max_ptr", (PERL_PROC*)&Perl_Tmarkstack_max_ptr},
+ {"Perl_TSv_ptr", (PERL_PROC*)&Perl_TSv_ptr},
+ {"Perl_TXpv_ptr", (PERL_PROC*)&Perl_TXpv_ptr},
+ {"Perl_Tna_ptr", (PERL_PROC*)&Perl_Tna_ptr},
+# else
+ {"Perl_sv_free2", (PERL_PROC*)&Perl_sv_free2},
+ {"Perl_sys_init", (PERL_PROC*)&Perl_sys_init},
+ {"Perl_sys_term", (PERL_PROC*)&Perl_sys_term},
+ {"Perl_call_list", (PERL_PROC*)&Perl_call_list},
+# if (PERL_REVISION == 5) && (PERL_VERSION >= 14)
+# else
+ {"Perl_ISv_ptr", (PERL_PROC*)&Perl_ISv_ptr},
+ {"Perl_Istack_max_ptr", (PERL_PROC*)&Perl_Istack_max_ptr},
+ {"Perl_Istack_base_ptr", (PERL_PROC*)&Perl_Istack_base_ptr},
+ {"Perl_IXpv_ptr", (PERL_PROC*)&Perl_IXpv_ptr},
+ {"Perl_Itmps_ix_ptr", (PERL_PROC*)&Perl_Itmps_ix_ptr},
+ {"Perl_Itmps_floor_ptr", (PERL_PROC*)&Perl_Itmps_floor_ptr},
+ {"Perl_Ina_ptr", (PERL_PROC*)&Perl_Ina_ptr},
+ {"Perl_Imarkstack_ptr_ptr", (PERL_PROC*)&Perl_Imarkstack_ptr_ptr},
+ {"Perl_Imarkstack_max_ptr", (PERL_PROC*)&Perl_Imarkstack_max_ptr},
+ {"Perl_Istack_sp_ptr", (PERL_PROC*)&Perl_Istack_sp_ptr},
+ {"Perl_Iop_ptr", (PERL_PROC*)&Perl_Iop_ptr},
+ {"Perl_Iscopestack_ix_ptr", (PERL_PROC*)&Perl_Iscopestack_ix_ptr},
+ {"Perl_Iunitcheckav_ptr", (PERL_PROC*)&Perl_Iunitcheckav_ptr},
+# endif
+# endif
+# if (PERL_REVISION == 5) && (PERL_VERSION >= 22)
+ {"Perl_xs_handshake", (PERL_PROC*)&Perl_xs_handshake},
+ {"Perl_xs_boot_epilog", (PERL_PROC*)&Perl_xs_boot_epilog},
+# endif
+# if (PERL_REVISION == 5) && (PERL_VERSION >= 14)
+# ifdef USE_ITHREADS
+ {"PL_thr_key", (PERL_PROC*)&dll_PL_thr_key},
+# endif
+# else
+ {"Perl_Idefgv_ptr", (PERL_PROC*)&Perl_Idefgv_ptr},
+ {"Perl_Ierrgv_ptr", (PERL_PROC*)&Perl_Ierrgv_ptr},
+ {"Perl_Isv_yes_ptr", (PERL_PROC*)&Perl_Isv_yes_ptr},
+ {"Perl_Gthr_key_ptr", (PERL_PROC*)&Perl_Gthr_key_ptr},
+# endif
+ {"boot_DynaLoader", (PERL_PROC*)&boot_DynaLoader},
+ {"Perl_hv_iternext_flags", (PERL_PROC*)&Perl_hv_iternext_flags},
+ {"Perl_hv_iterinit", (PERL_PROC*)&Perl_hv_iterinit},
+ {"Perl_hv_iterkey", (PERL_PROC*)&Perl_hv_iterkey},
+ {"Perl_hv_iterval", (PERL_PROC*)&Perl_hv_iterval},
+ {"Perl_av_fetch", (PERL_PROC*)&Perl_av_fetch},
+ {"Perl_av_len", (PERL_PROC*)&Perl_av_len},
+ {"Perl_sv_2nv_flags", (PERL_PROC*)&Perl_sv_2nv_flags},
+# if defined(PERLIO_LAYERS) && !defined(USE_SFIO)
+ {"PerlIOBase_pushed", (PERL_PROC*)&PerlIOBase_pushed},
+ {"PerlIO_define_layer", (PERL_PROC*)&PerlIO_define_layer},
+# endif
+# if (PERL_REVISION == 5) && (PERL_VERSION >= 24)
+ {"Perl_savetmps", (PERL_PROC*)&Perl_savetmps},
+# endif
+ {"", NULL},
+};
+
+/* Work around for perl-5.18.
+ * For now, only the definitions of S_SvREFCNT_dec are needed in
+ * "perl\lib\CORE\inline.h". */
+# if (PERL_REVISION == 5) && (PERL_VERSION >= 18)
+static void
+S_SvREFCNT_dec(pTHX_ SV *sv)
+{
+ if (LIKELY(sv != NULL)) {
+ U32 rc = SvREFCNT(sv);
+ if (LIKELY(rc > 1))
+ SvREFCNT(sv) = rc - 1;
+ else
+ Perl_sv_free2(aTHX_ sv, rc);
+ }
+}
+# endif
+
+/* perl-5.26 also needs S_TOPMARK and S_POPMARK. */
+# if (PERL_REVISION == 5) && (PERL_VERSION >= 26)
+PERL_STATIC_INLINE I32
+S_TOPMARK(pTHX)
+{
+ DEBUG_s(DEBUG_v(PerlIO_printf(Perl_debug_log,
+ "MARK top %p %" IVdf "\n",
+ PL_markstack_ptr,
+ (IV)*PL_markstack_ptr)));
+ return *PL_markstack_ptr;
+}
+
+PERL_STATIC_INLINE I32
+S_POPMARK(pTHX)
+{
+ DEBUG_s(DEBUG_v(PerlIO_printf(Perl_debug_log,
+ "MARK pop %p %" IVdf "\n",
+ (PL_markstack_ptr-1),
+ (IV)*(PL_markstack_ptr-1))));
+ assert((PL_markstack_ptr > PL_markstack) || !"MARK underflow");
+ return *PL_markstack_ptr--;
+}
+# endif
+
+/*
+ * Make all runtime-links of perl.
+ *
+ * 1. Get module handle using dlopen() or vimLoadLib().
+ * 2. Get pointer to perl function by GetProcAddress.
+ * 3. Repeat 2, until get all functions will be used.
+ *
+ * Parameter 'libname' provides name of DLL.
+ * Return OK or FAIL.
+ */
+ static int
+perl_runtime_link_init(char *libname, int verbose)
+{
+ int i;
+
+ if (hPerlLib != NULL)
+ return OK;
+ if ((hPerlLib = load_dll(libname)) == NULL)
+ {
+ if (verbose)
+ semsg(_("E370: Could not load library %s"), libname);
+ return FAIL;
+ }
+ for (i = 0; perl_funcname_table[i].ptr; ++i)
+ {
+ if (!(*perl_funcname_table[i].ptr = symbol_from_dll(hPerlLib,
+ perl_funcname_table[i].name)))
+ {
+ close_dll(hPerlLib);
+ hPerlLib = NULL;
+ if (verbose)
+ semsg((const char *)_(e_loadfunc), perl_funcname_table[i].name);
+ return FAIL;
+ }
+ }
+ return OK;
+}
+
+/*
+ * If runtime-link-perl(DLL) was loaded successfully, return TRUE.
+ * There were no DLL loaded, return FALSE.
+ */
+ int
+perl_enabled(int verbose)
+{
+ return perl_runtime_link_init((char *)p_perldll, verbose) == OK;
+}
+#endif /* DYNAMIC_PERL */
+
+#if defined(PERLIO_LAYERS) && !defined(USE_SFIO)
+static void vim_IOLayer_init(void);
+#endif
+
+/*
+ * perl_init(): initialize perl interpreter
+ * We have to call perl_parse to initialize some structures,
+ * there's nothing to actually parse.
+ */
+ static void
+perl_init(void)
+{
+ char *bootargs[] = { "VI", NULL };
+ int argc = 3;
+ static char *argv[] = { "", "-e", "" };
+
+#if (PERL_REVISION == 5) && (PERL_VERSION >= 10)
+ Perl_sys_init(&argc, (char***)&argv);
+#endif
+ perl_interp = perl_alloc();
+ perl_construct(perl_interp);
+ perl_parse(perl_interp, xs_init, argc, argv, 0);
+ perl_call_argv("VIM::bootstrap", (long)G_DISCARD, bootargs);
+ VIM_init();
+#ifdef USE_SFIO
+ sfdisc(PerlIO_stdout(), sfdcnewvim());
+ sfdisc(PerlIO_stderr(), sfdcnewvim());
+ sfsetbuf(PerlIO_stdout(), NULL, 0);
+ sfsetbuf(PerlIO_stderr(), NULL, 0);
+#elif defined(PERLIO_LAYERS)
+ vim_IOLayer_init();
+#endif
+}
+
+/*
+ * perl_end(): clean up after ourselves
+ */
+ void
+perl_end(void)
+{
+ if (perl_interp)
+ {
+ perl_run(perl_interp);
+ perl_destruct(perl_interp);
+ perl_free(perl_interp);
+ perl_interp = NULL;
+#if (PERL_REVISION == 5) && (PERL_VERSION >= 10)
+ Perl_sys_term();
+#endif
+ }
+#ifdef DYNAMIC_PERL
+ if (hPerlLib)
+ {
+ close_dll(hPerlLib);
+ hPerlLib = NULL;
+ }
+#endif
+}
+
+/*
+ * msg_split(): send a message to the message handling routines
+ * split at '\n' first though.
+ */
+ void
+msg_split(
+ char_u *s,
+ int attr) /* highlighting attributes */
+{
+ char *next;
+ char *token = (char *)s;
+
+ while ((next = strchr(token, '\n')) && !got_int)
+ {
+ *next++ = '\0'; /* replace \n with \0 */
+ msg_attr(token, attr);
+ token = next;
+ }
+ if (*token && !got_int)
+ msg_attr(token, attr);
+}
+
+#ifndef FEAT_EVAL
+/*
+ * This stub is needed because an "#ifdef FEAT_EVAL" around Eval() doesn't
+ * work properly.
+ */
+ char_u *
+eval_to_string(
+ char_u *arg UNUSED,
+ char_u **nextcmd UNUSED,
+ int dolist UNUSED)
+{
+ return NULL;
+}
+#endif
+
+/*
+ * Create a new reference to an SV pointing to the SCR structure
+ * The b_perl_private/w_perl_private part of the SCR structure points to the
+ * SV, so there can only be one such SV for a particular SCR structure. When
+ * the last reference has gone (DESTROY is called),
+ * b_perl_private/w_perl_private is reset; When the screen goes away before
+ * all references are gone, the value of the SV is reset;
+ * any subsequent use of any of those reference will produce
+ * a warning. (see typemap)
+ */
+
+ static SV *
+newWINrv(SV *rv, win_T *ptr)
+{
+ sv_upgrade(rv, SVt_RV);
+ if (ptr->w_perl_private == NULL)
+ {
+ ptr->w_perl_private = newSV(0);
+ sv_setiv(ptr->w_perl_private, PTR2IV(ptr));
+ }
+ SvREFCNT_inc_void_NN(ptr->w_perl_private);
+ SvRV(rv) = ptr->w_perl_private;
+ SvROK_on(rv);
+ return sv_bless(rv, gv_stashpv("VIWIN", TRUE));
+}
+
+ static SV *
+newBUFrv(SV *rv, buf_T *ptr)
+{
+ sv_upgrade(rv, SVt_RV);
+ if (ptr->b_perl_private == NULL)
+ {
+ ptr->b_perl_private = newSV(0);
+ sv_setiv(ptr->b_perl_private, PTR2IV(ptr));
+ }
+ SvREFCNT_inc_void_NN(ptr->b_perl_private);
+ SvRV(rv) = ptr->b_perl_private;
+ SvROK_on(rv);
+ return sv_bless(rv, gv_stashpv("VIBUF", TRUE));
+}
+
+#if 0
+SV *__sv_save[1024];
+int __sv_save_ix;
+# define D_Save_Sv(sv) do { if (__sv_save_ix < 1024) __sv_save[__sv_save_ix++] = (sv); } while (0)
+#else
+# define D_Save_Sv(sv) NOOP
+#endif
+
+/*
+ * perl_win_free
+ * Remove all references to the window to be destroyed
+ */
+ void
+perl_win_free(win_T *wp)
+{
+ if (wp->w_perl_private && perl_interp != NULL)
+ {
+ SV *sv = (SV*)wp->w_perl_private;
+ D_Save_Sv(sv);
+ sv_setiv(sv, 0);
+ SvREFCNT_dec(sv);
+ }
+ wp->w_perl_private = NULL;
+}
+
+ void
+perl_buf_free(buf_T *bp)
+{
+ if (bp->b_perl_private && perl_interp != NULL)
+ {
+ SV *sv = (SV *)bp->b_perl_private;
+ D_Save_Sv(sv);
+ sv_setiv(sv, 0);
+ SvREFCNT_dec(sv);
+ }
+ bp->b_perl_private = NULL;
+}
+
+#ifndef PROTO
+# if (PERL_REVISION == 5) && (PERL_VERSION >= 8)
+I32 cur_val(pTHX_ IV iv, SV *sv);
+# else
+I32 cur_val(IV iv, SV *sv);
+# endif
+
+/*
+ * Handler for the magic variables $main::curwin and $main::curbuf.
+ * The handler is put into the magic vtbl for these variables.
+ * (This is effectively a C-level equivalent of a tied variable).
+ * There is no "set" function as the variables are read-only.
+ */
+# if (PERL_REVISION == 5) && (PERL_VERSION >= 8)
+I32 cur_val(pTHX_ IV iv, SV *sv)
+# else
+I32 cur_val(IV iv, SV *sv)
+# endif
+{
+ SV *rv;
+
+ if (iv == 0)
+ rv = newWINrv(newSV(0), curwin);
+ else
+ rv = newBUFrv(newSV(0), curbuf);
+
+ if (SvRV(sv) != SvRV(rv))
+ // XXX: This magic variable is a bit confusing...
+ // Is curently refcounted ?
+ sv_setsv(sv, rv);
+
+ SvREFCNT_dec(rv);
+
+ return 0;
+}
+#endif /* !PROTO */
+
+struct ufuncs cw_funcs = { cur_val, 0, 0 };
+struct ufuncs cb_funcs = { cur_val, 0, 1 };
+
+/*
+ * VIM_init(): Vim-specific initialisation.
+ * Make the magical main::curwin and main::curbuf variables
+ */
+ static void
+VIM_init(void)
+{
+ static char cw[] = "main::curwin";
+ static char cb[] = "main::curbuf";
+ SV *sv;
+
+ sv = perl_get_sv(cw, TRUE);
+ sv_magic(sv, NULL, 'U', (char *)&cw_funcs, sizeof(cw_funcs));
+ SvREADONLY_on(sv);
+
+ sv = perl_get_sv(cb, TRUE);
+ sv_magic(sv, NULL, 'U', (char *)&cb_funcs, sizeof(cb_funcs));
+ SvREADONLY_on(sv);
+
+ /*
+ * Setup the Safe compartment.
+ * It shouldn't be a fatal error if the Safe module is missing.
+ * XXX: Only shares the 'Msg' routine (which has to be called
+ * like 'Msg(...)').
+ */
+ (void)perl_eval_pv( "if ( eval( 'require Safe' ) ) { $VIM::safe = Safe->new(); $VIM::safe->share_from( 'VIM', ['Msg'] ); }", G_DISCARD | G_VOID );
+
+}
+
+#ifdef DYNAMIC_PERL
+static char *e_noperl = N_("Sorry, this command is disabled: the Perl library could not be loaded.");
+#endif
+
+/*
+ * ":perl"
+ */
+ void
+ex_perl(exarg_T *eap)
+{
+ char *err;
+ char *script;
+ STRLEN length;
+ SV *sv;
+#ifdef HAVE_SANDBOX
+ SV *safe;
+#endif
+
+ script = (char *)script_get(eap, eap->arg);
+ if (eap->skip)
+ {
+ vim_free(script);
+ return;
+ }
+
+ if (perl_interp == NULL)
+ {
+#ifdef DYNAMIC_PERL
+ if (!perl_enabled(TRUE))
+ {
+ emsg(_(e_noperl));
+ vim_free(script);
+ return;
+ }
+#endif
+ perl_init();
+ }
+
+ {
+ dSP;
+ ENTER;
+ SAVETMPS;
+
+ if (script == NULL)
+ sv = newSVpv((char *)eap->arg, 0);
+ else
+ {
+ sv = newSVpv(script, 0);
+ vim_free(script);
+ }
+
+#ifdef HAVE_SANDBOX
+ if (sandbox)
+ {
+ safe = perl_get_sv("VIM::safe", FALSE);
+# ifndef MAKE_TEST /* avoid a warning for unreachable code */
+ if (safe == NULL || !SvTRUE(safe))
+ emsg(_("E299: Perl evaluation forbidden in sandbox without the Safe module"));
+ else
+# endif
+ {
+ PUSHMARK(SP);
+ XPUSHs(safe);
+ XPUSHs(sv);
+ PUTBACK;
+ perl_call_method("reval", G_DISCARD);
+ }
+ }
+ else
+#endif
+ perl_eval_sv(sv, G_DISCARD | G_NOARGS);
+
+ SvREFCNT_dec(sv);
+
+ err = SvPV(GvSV(PL_errgv), length);
+
+ FREETMPS;
+ LEAVE;
+
+ if (!length)
+ return;
+
+ msg_split((char_u *)err, highlight_attr[HLF_E]);
+ return;
+ }
+}
+
+ static int
+replace_line(linenr_T *line, linenr_T *end)
+{
+ char *str;
+
+ if (SvOK(GvSV(PL_defgv)))
+ {
+ str = SvPV(GvSV(PL_defgv), PL_na);
+ ml_replace(*line, (char_u *)str, 1);
+ changed_bytes(*line, 0);
+ }
+ else
+ {
+ ml_delete(*line, FALSE);
+ deleted_lines_mark(*line, 1L);
+ --(*end);
+ --(*line);
+ }
+ return OK;
+}
+
+static struct ref_map_S {
+ void *vim_ref;
+ SV *perl_ref;
+ struct ref_map_S *next;
+} *ref_map = NULL;
+
+ static void
+ref_map_free(void)
+{
+ struct ref_map_S *tofree;
+ struct ref_map_S *refs = ref_map;
+
+ while (refs) {
+ tofree = refs;
+ refs = refs->next;
+ vim_free(tofree);
+ }
+ ref_map = NULL;
+}
+
+ static struct ref_map_S *
+ref_map_find_SV(SV *const sv)
+{
+ struct ref_map_S *refs = ref_map;
+ int count = 350;
+
+ while (refs) {
+ if (refs->perl_ref == sv)
+ break;
+ refs = refs->next;
+ count--;
+ }
+
+ if (!refs && count > 0) {
+ refs = (struct ref_map_S *)alloc(sizeof(struct ref_map_S));
+ if (!refs)
+ return NULL;
+ refs->perl_ref = sv;
+ refs->vim_ref = NULL;
+ refs->next = ref_map;
+ ref_map = refs;
+ }
+
+ return refs;
+}
+
+ static int
+perl_to_vim(SV *sv, typval_T *rettv)
+{
+ if (SvROK(sv))
+ sv = SvRV(sv);
+
+ switch (SvTYPE(sv)) {
+ case SVt_NULL:
+ break;
+ case SVt_NV: /* float */
+#ifdef FEAT_FLOAT
+ rettv->v_type = VAR_FLOAT;
+ rettv->vval.v_float = SvNV(sv);
+ break;
+#endif
+ case SVt_IV: /* integer */
+ if (!SvROK(sv)) { /* references should be string */
+ rettv->vval.v_number = SvIV(sv);
+ break;
+ }
+ /* FALLTHROUGH */
+ case SVt_PV: /* string */
+ {
+ size_t len = 0;
+ char * str_from = SvPV(sv, len);
+ char_u *str_to = (char_u*)alloc(
+ (unsigned)(sizeof(char_u) * (len + 1)));
+
+ if (str_to) {
+ str_to[len] = '\0';
+
+ while (len--) {
+ if (str_from[len] == '\0')
+ str_to[len] = '\n';
+ else
+ str_to[len] = str_from[len];
+ }
+ }
+
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = str_to;
+ break;
+ }
+ case SVt_PVAV: /* list */
+ {
+ SSize_t size;
+ listitem_T * item;
+ SV ** item2;
+ list_T * list;
+ struct ref_map_S * refs;
+
+ if ((refs = ref_map_find_SV(sv)) == NULL)
+ return FAIL;
+
+ if (refs->vim_ref)
+ list = (list_T *) refs->vim_ref;
+ else
+ {
+ if ((list = list_alloc()) == NULL)
+ return FAIL;
+ refs->vim_ref = list;
+
+ for (size = av_len((AV*)sv); size >= 0; size--)
+ {
+ if ((item = listitem_alloc()) == NULL)
+ break;
+
+ item->li_tv.v_type = VAR_NUMBER;
+ item->li_tv.v_lock = 0;
+ item->li_tv.vval.v_number = 0;
+ list_insert(list, item, list->lv_first);
+
+ item2 = av_fetch((AV *)sv, size, 0);
+
+ if (item2 == NULL || *item2 == NULL ||
+ perl_to_vim(*item2, &item->li_tv) == FAIL)
+ break;
+ }
+ }
+
+ rettv_list_set(rettv, list);
+ break;
+ }
+ case SVt_PVHV: /* dictionary */
+ {
+ HE * entry;
+ I32 key_len;
+ char * key;
+ dictitem_T * item;
+ SV * item2;
+ dict_T * dict;
+ struct ref_map_S * refs;
+
+ if ((refs = ref_map_find_SV(sv)) == NULL)
+ return FAIL;
+
+ if (refs->vim_ref)
+ dict = (dict_T *) refs->vim_ref;
+ else
+ {
+
+ if ((dict = dict_alloc()) == NULL)
+ return FAIL;
+ refs->vim_ref = dict;
+
+ hv_iterinit((HV *)sv);
+
+ for (entry = hv_iternext((HV *)sv); entry; entry = hv_iternext((HV *)sv))
+ {
+ key_len = 0;
+ key = hv_iterkey(entry, &key_len);
+
+ if (!key || !key_len || strlen(key) < (size_t)key_len) {
+ semsg("Malformed key Dictionary '%s'", key && *key ? key : "(empty)");
+ break;
+ }
+
+ if ((item = dictitem_alloc((char_u *)key)) == NULL)
+ break;
+ item->di_tv.v_type = VAR_NUMBER;
+ item->di_tv.vval.v_number = 0;
+
+ if (dict_add(dict, item) == FAIL) {
+ dictitem_free(item);
+ break;
+ }
+ item2 = hv_iterval((HV *)sv, entry);
+ if (item2 == NULL || perl_to_vim(item2, &item->di_tv) == FAIL)
+ break;
+ }
+ }
+
+ rettv_dict_set(rettv, dict);
+ break;
+ }
+ default: /* not convertible */
+ {
+ char *val = SvPV_nolen(sv);
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = val ? vim_strsave((char_u *)val) : NULL;
+ break;
+ }
+ }
+ return OK;
+}
+
+/*
+ * "perleval()"
+ */
+ void
+do_perleval(char_u *str, typval_T *rettv)
+{
+ char *err = NULL;
+ STRLEN err_len = 0;
+ SV *sv = NULL;
+#ifdef HAVE_SANDBOX
+ SV *safe;
+#endif
+
+ if (perl_interp == NULL)
+ {
+#ifdef DYNAMIC_PERL
+ if (!perl_enabled(TRUE))
+ {
+ emsg(_(e_noperl));
+ return;
+ }
+#endif
+ perl_init();
+ }
+
+ {
+ dSP;
+ ENTER;
+ SAVETMPS;
+
+#ifdef HAVE_SANDBOX
+ if (sandbox)
+ {
+ safe = get_sv("VIM::safe", FALSE);
+# ifndef MAKE_TEST /* avoid a warning for unreachable code */
+ if (safe == NULL || !SvTRUE(safe))
+ emsg(_("E299: Perl evaluation forbidden in sandbox without the Safe module"));
+ else
+# endif
+ {
+ sv = newSVpv((char *)str, 0);
+ PUSHMARK(SP);
+ XPUSHs(safe);
+ XPUSHs(sv);
+ PUTBACK;
+ call_method("reval", G_SCALAR);
+ SPAGAIN;
+ SvREFCNT_dec(sv);
+ sv = POPs;
+ }
+ }
+ else
+#endif /* HAVE_SANDBOX */
+ sv = eval_pv((char *)str, 0);
+
+ if (sv) {
+ perl_to_vim(sv, rettv);
+ ref_map_free();
+ err = SvPV(GvSV(PL_errgv), err_len);
+ }
+ PUTBACK;
+ FREETMPS;
+ LEAVE;
+ }
+ if (err_len)
+ msg_split((char_u *)err, highlight_attr[HLF_E]);
+}
+
+/*
+ * ":perldo".
+ */
+ void
+ex_perldo(exarg_T *eap)
+{
+ STRLEN length;
+ SV *sv;
+ char *str;
+ linenr_T i;
+ buf_T *was_curbuf = curbuf;
+
+ if (BUFEMPTY())
+ return;
+
+ if (perl_interp == NULL)
+ {
+#ifdef DYNAMIC_PERL
+ if (!perl_enabled(TRUE))
+ {
+ emsg(_(e_noperl));
+ return;
+ }
+#endif
+ perl_init();
+ }
+ {
+ dSP;
+ length = strlen((char *)eap->arg);
+ sv = newSV(length + sizeof("sub VIM::perldo {") - 1 + 1);
+ sv_setpvn(sv, "sub VIM::perldo {", sizeof("sub VIM::perldo {") - 1);
+ sv_catpvn(sv, (char *)eap->arg, length);
+ sv_catpvn(sv, "}", 1);
+ perl_eval_sv(sv, G_DISCARD | G_NOARGS);
+ SvREFCNT_dec(sv);
+ str = SvPV(GvSV(PL_errgv), length);
+ if (length)
+ goto err;
+
+ if (u_save(eap->line1 - 1, eap->line2 + 1) != OK)
+ return;
+
+ ENTER;
+ SAVETMPS;
+ for (i = eap->line1; i <= eap->line2; i++)
+ {
+ /* Check the line number, the command my have deleted lines. */
+ if (i > curbuf->b_ml.ml_line_count)
+ break;
+ sv_setpv(GvSV(PL_defgv), (char *)ml_get(i));
+ PUSHMARK(sp);
+ perl_call_pv("VIM::perldo", G_SCALAR | G_EVAL);
+ str = SvPV(GvSV(PL_errgv), length);
+ if (length || curbuf != was_curbuf)
+ break;
+ SPAGAIN;
+ if (SvTRUEx(POPs))
+ {
+ if (replace_line(&i, &eap->line2) != OK)
+ {
+ PUTBACK;
+ break;
+ }
+ }
+ PUTBACK;
+ }
+ FREETMPS;
+ LEAVE;
+ check_cursor();
+ update_screen(NOT_VALID);
+ if (!length)
+ return;
+
+err:
+ msg_split((char_u *)str, highlight_attr[HLF_E]);
+ return;
+ }
+}
+
+#if defined(PERLIO_LAYERS) && !defined(USE_SFIO)
+typedef struct {
+ struct _PerlIO base;
+ int attr;
+} PerlIOVim;
+
+ static IV
+PerlIOVim_pushed(pTHX_ PerlIO *f, const char *mode,
+ SV *arg, PerlIO_funcs *tab)
+{
+ PerlIOVim *s = PerlIOSelf(f, PerlIOVim);
+ s->attr = 0;
+ if (arg && SvPOK(arg))
+ s->attr = syn_name2attr((char_u *)SvPV_nolen(arg));
+ return PerlIOBase_pushed(aTHX_ f, mode, (SV *)NULL, tab);
+}
+
+ static SSize_t
+PerlIOVim_write(pTHX_ PerlIO *f, const void *vbuf, Size_t count)
+{
+ char_u *str;
+ PerlIOVim * s = PerlIOSelf(f, PerlIOVim);
+
+ str = vim_strnsave((char_u *)vbuf, (int)count);
+ if (str == NULL)
+ return 0;
+ msg_split((char_u *)str, s->attr);
+ vim_free(str);
+
+ return (SSize_t)count;
+}
+
+static PERLIO_FUNCS_DECL(PerlIO_Vim) = {
+ sizeof(PerlIO_funcs),
+ "Vim",
+ sizeof(PerlIOVim),
+ PERLIO_K_DUMMY, /* flags */
+ PerlIOVim_pushed,
+ NULL, /* popped */
+ NULL, /* open */
+ NULL, /* binmode */
+ NULL, /* arg */
+ NULL, /* fileno */
+ NULL, /* dup */
+ NULL, /* read */
+ NULL, /* unread */
+ PerlIOVim_write,
+ NULL, /* seek */
+ NULL, /* tell */
+ NULL, /* close */
+ NULL, /* flush */
+ NULL, /* fill */
+ NULL, /* eof */
+ NULL, /* error */
+ NULL, /* clearerr */
+ NULL, /* setlinebuf */
+ NULL, /* get_base */
+ NULL, /* get_bufsiz */
+ NULL, /* get_ptr */
+ NULL, /* get_cnt */
+ NULL /* set_ptrcnt */
+};
+
+/* Use Vim routine for print operator */
+ static void
+vim_IOLayer_init(void)
+{
+ PerlIO_define_layer(aTHX_ PERLIO_FUNCS_CAST(&PerlIO_Vim));
+ (void)eval_pv( "binmode(STDOUT, ':Vim')"
+ " && binmode(STDERR, ':Vim(ErrorMsg)');", 0);
+}
+#endif /* PERLIO_LAYERS && !USE_SFIO */
+
+XS(boot_VIM);
+
+ static void
+xs_init(pTHX)
+{
+ char *file = __FILE__;
+
+ /* DynaLoader is a special case */
+ newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
+ newXS("VIM::bootstrap", boot_VIM, file);
+}
+
+typedef win_T * VIWIN;
+typedef buf_T * VIBUF;
+
+MODULE = VIM PACKAGE = VIM
+
+void
+Msg(text, hl=NULL)
+ char *text;
+ char *hl;
+
+ PREINIT:
+ int attr;
+
+ PPCODE:
+ if (text != NULL)
+ {
+ attr = 0;
+ if (hl != NULL)
+ attr = syn_name2attr((char_u *)hl);
+ msg_split((char_u *)text, attr);
+ }
+
+void
+SetOption(line)
+ char *line;
+
+ PPCODE:
+ if (line != NULL)
+ do_set((char_u *)line, 0);
+ update_screen(NOT_VALID);
+
+void
+DoCommand(line)
+ char *line;
+
+ PPCODE:
+ if (line != NULL)
+ do_cmdline_cmd((char_u *)line);
+
+void
+Eval(str)
+ char *str;
+
+ PREINIT:
+ char_u *value;
+ PPCODE:
+ value = eval_to_string((char_u *)str, (char_u **)0, TRUE);
+ if (value == NULL)
+ {
+ XPUSHs(sv_2mortal(newSViv(0)));
+ XPUSHs(sv_2mortal(newSVpv("", 0)));
+ }
+ else
+ {
+ XPUSHs(sv_2mortal(newSViv(1)));
+ XPUSHs(sv_2mortal(newSVpv((char *)value, 0)));
+ vim_free(value);
+ }
+
+SV*
+Blob(SV* sv)
+ PREINIT:
+ STRLEN len;
+ char *s;
+ unsigned i;
+ char buf[3];
+ SV* newsv;
+
+ CODE:
+ s = SvPVbyte(sv, len);
+ newsv = newSVpv("0z", 2);
+ for (i = 0; i < len; i++)
+ {
+ sprintf(buf, "%02X", s[i]);
+ sv_catpvn(newsv, buf, 2);
+ }
+ RETVAL = newsv;
+ OUTPUT:
+ RETVAL
+
+void
+Buffers(...)
+
+ PREINIT:
+ buf_T *vimbuf;
+ int i, b;
+
+ PPCODE:
+ if (items == 0)
+ {
+ if (GIMME == G_SCALAR)
+ {
+ i = 0;
+ FOR_ALL_BUFFERS(vimbuf)
+ ++i;
+
+ XPUSHs(sv_2mortal(newSViv(i)));
+ }
+ else
+ {
+ FOR_ALL_BUFFERS(vimbuf)
+ XPUSHs(sv_2mortal(newBUFrv(newSV(0), vimbuf)));
+ }
+ }
+ else
+ {
+ for (i = 0; i < items; i++)
+ {
+ SV *sv = ST(i);
+ if (SvIOK(sv))
+ b = (int) SvIV(ST(i));
+ else
+ {
+ char_u *pat;
+ STRLEN len;
+
+ pat = (char_u *)SvPV(sv, len);
+ ++emsg_off;
+ b = buflist_findpat(pat, pat + len, TRUE, FALSE, FALSE);
+ --emsg_off;
+ }
+
+ if (b >= 0)
+ {
+ vimbuf = buflist_findnr(b);
+ if (vimbuf)
+ XPUSHs(sv_2mortal(newBUFrv(newSV(0), vimbuf)));
+ }
+ }
+ }
+
+void
+Windows(...)
+
+ PREINIT:
+ win_T *vimwin;
+ int i, w;
+
+ PPCODE:
+ if (items == 0)
+ {
+ if (GIMME == G_SCALAR)
+ XPUSHs(sv_2mortal(newSViv(win_count())));
+ else
+ {
+ FOR_ALL_WINDOWS(vimwin)
+ XPUSHs(sv_2mortal(newWINrv(newSV(0), vimwin)));
+ }
+ }
+ else
+ {
+ for (i = 0; i < items; i++)
+ {
+ w = (int) SvIV(ST(i));
+ vimwin = win_find_nr(w);
+ if (vimwin)
+ XPUSHs(sv_2mortal(newWINrv(newSV(0), vimwin)));
+ }
+ }
+
+MODULE = VIM PACKAGE = VIWIN
+
+void
+DESTROY(win)
+ VIWIN win
+
+ CODE:
+ if (win_valid(win))
+ win->w_perl_private = 0;
+
+SV *
+Buffer(win)
+ VIWIN win
+
+ CODE:
+ if (!win_valid(win))
+ win = curwin;
+ RETVAL = newBUFrv(newSV(0), win->w_buffer);
+ OUTPUT:
+ RETVAL
+
+void
+SetHeight(win, height)
+ VIWIN win
+ int height;
+
+ PREINIT:
+ win_T *savewin;
+
+ PPCODE:
+ if (!win_valid(win))
+ win = curwin;
+ savewin = curwin;
+ curwin = win;
+ win_setheight(height);
+ curwin = savewin;
+
+void
+Cursor(win, ...)
+ VIWIN win
+
+ PPCODE:
+ if (items == 1)
+ {
+ EXTEND(sp, 2);
+ if (!win_valid(win))
+ win = curwin;
+ PUSHs(sv_2mortal(newSViv(win->w_cursor.lnum)));
+ PUSHs(sv_2mortal(newSViv(win->w_cursor.col)));
+ }
+ else if (items == 3)
+ {
+ int lnum, col;
+
+ if (!win_valid(win))
+ win = curwin;
+ lnum = (int) SvIV(ST(1));
+ col = (int) SvIV(ST(2));
+ win->w_cursor.lnum = lnum;
+ win->w_cursor.col = col;
+ win->w_set_curswant = TRUE;
+ check_cursor(); /* put cursor on an existing line */
+ update_screen(NOT_VALID);
+ }
+
+MODULE = VIM PACKAGE = VIBUF
+
+void
+DESTROY(vimbuf)
+ VIBUF vimbuf;
+
+ CODE:
+ if (buf_valid(vimbuf))
+ vimbuf->b_perl_private = 0;
+
+void
+Name(vimbuf)
+ VIBUF vimbuf;
+
+ PPCODE:
+ if (!buf_valid(vimbuf))
+ vimbuf = curbuf;
+ /* No file name returns an empty string */
+ if (vimbuf->b_fname == NULL)
+ XPUSHs(sv_2mortal(newSVpv("", 0)));
+ else
+ XPUSHs(sv_2mortal(newSVpv((char *)vimbuf->b_fname, 0)));
+
+void
+Number(vimbuf)
+ VIBUF vimbuf;
+
+ PPCODE:
+ if (!buf_valid(vimbuf))
+ vimbuf = curbuf;
+ XPUSHs(sv_2mortal(newSViv(vimbuf->b_fnum)));
+
+void
+Count(vimbuf)
+ VIBUF vimbuf;
+
+ PPCODE:
+ if (!buf_valid(vimbuf))
+ vimbuf = curbuf;
+ XPUSHs(sv_2mortal(newSViv(vimbuf->b_ml.ml_line_count)));
+
+void
+Get(vimbuf, ...)
+ VIBUF vimbuf;
+
+ PREINIT:
+ char_u *line;
+ int i;
+ long lnum;
+ PPCODE:
+ if (buf_valid(vimbuf))
+ {
+ for (i = 1; i < items; i++)
+ {
+ lnum = (long) SvIV(ST(i));
+ if (lnum > 0 && lnum <= vimbuf->b_ml.ml_line_count)
+ {
+ line = ml_get_buf(vimbuf, lnum, FALSE);
+ XPUSHs(sv_2mortal(newSVpv((char *)line, 0)));
+ }
+ }
+ }
+
+void
+Set(vimbuf, ...)
+ VIBUF vimbuf;
+
+ PREINIT:
+ int i;
+ long lnum;
+ char *line;
+ PPCODE:
+ if (buf_valid(vimbuf))
+ {
+ if (items < 3)
+ croak("Usage: VIBUF::Set(vimbuf, lnum, @lines)");
+
+ lnum = (long) SvIV(ST(1));
+ for(i = 2; i < items; i++, lnum++)
+ {
+ line = SvPV(ST(i),PL_na);
+ if (lnum > 0 && lnum <= vimbuf->b_ml.ml_line_count && line != NULL)
+ {
+ aco_save_T aco;
+
+ /* set curwin/curbuf for "vimbuf" and save some things */
+ aucmd_prepbuf(&aco, vimbuf);
+
+ if (u_savesub(lnum) == OK)
+ {
+ ml_replace(lnum, (char_u *)line, TRUE);
+ changed_bytes(lnum, 0);
+ }
+
+ /* restore curwin/curbuf and a few other things */
+ aucmd_restbuf(&aco);
+ /* Careful: autocommands may have made "vimbuf" invalid! */
+ }
+ }
+ }
+
+void
+Delete(vimbuf, ...)
+ VIBUF vimbuf;
+
+ PREINIT:
+ long i, lnum = 0, count = 0;
+ PPCODE:
+ if (buf_valid(vimbuf))
+ {
+ if (items == 2)
+ {
+ lnum = (long) SvIV(ST(1));
+ count = 1;
+ }
+ else if (items == 3)
+ {
+ lnum = (long) SvIV(ST(1));
+ count = (long) 1 + SvIV(ST(2)) - lnum;
+ if (count == 0)
+ count = 1;
+ if (count < 0)
+ {
+ lnum -= count;
+ count = -count;
+ }
+ }
+ if (items >= 2)
+ {
+ for (i = 0; i < count; i++)
+ {
+ if (lnum > 0 && lnum <= vimbuf->b_ml.ml_line_count)
+ {
+ aco_save_T aco;
+
+ /* set curwin/curbuf for "vimbuf" and save some things */
+ aucmd_prepbuf(&aco, vimbuf);
+
+ if (u_savedel(lnum, 1) == OK)
+ {
+ ml_delete(lnum, 0);
+ check_cursor();
+ deleted_lines_mark(lnum, 1L);
+ }
+
+ /* restore curwin/curbuf and a few other things */
+ aucmd_restbuf(&aco);
+ /* Careful: autocommands may have made "vimbuf" invalid! */
+
+ update_curbuf(VALID);
+ }
+ }
+ }
+ }
+
+void
+Append(vimbuf, ...)
+ VIBUF vimbuf;
+
+ PREINIT:
+ int i;
+ long lnum;
+ char *line;
+ PPCODE:
+ if (buf_valid(vimbuf))
+ {
+ if (items < 3)
+ croak("Usage: VIBUF::Append(vimbuf, lnum, @lines)");
+
+ lnum = (long) SvIV(ST(1));
+ for (i = 2; i < items; i++, lnum++)
+ {
+ line = SvPV(ST(i),PL_na);
+ if (lnum >= 0 && lnum <= vimbuf->b_ml.ml_line_count && line != NULL)
+ {
+ aco_save_T aco;
+
+ /* set curwin/curbuf for "vimbuf" and save some things */
+ aucmd_prepbuf(&aco, vimbuf);
+
+ if (u_inssub(lnum + 1) == OK)
+ {
+ ml_append(lnum, (char_u *)line, (colnr_T)0, FALSE);
+ appended_lines_mark(lnum, 1L);
+ }
+
+ /* restore curwin/curbuf and a few other things */
+ aucmd_restbuf(&aco);
+ /* Careful: autocommands may have made "vimbuf" invalid! */
+
+ update_curbuf(VALID);
+ }
+ }
+ }
+
+#ifdef __GNUC__
+# pragma GCC diagnostic pop
+#endif
diff --git a/src/if_perl_msvc/stdbool.h b/src/if_perl_msvc/stdbool.h
new file mode 100644
index 0000000..de89e3b
--- /dev/null
+++ b/src/if_perl_msvc/stdbool.h
@@ -0,0 +1,3 @@
+/* A stub stdbool.h for VC2012 or earlier.
+ * ActivePerl 5.20+ requires stdbool.h but VC2012 doesn't have it. */
+#define bool char
diff --git a/src/if_perlsfio.c b/src/if_perlsfio.c
new file mode 100644
index 0000000..528a1b4
--- /dev/null
+++ b/src/if_perlsfio.c
@@ -0,0 +1,66 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+/*
+ * if_perlsfio.c: Special I/O functions for Perl interface.
+ */
+
+#define _memory_h /* avoid memset redeclaration */
+#define IN_PERL_FILE /* don't include if_perl.pro from prot.h */
+
+#include "vim.h"
+
+#if defined(USE_SFIO) || defined(PROTO)
+
+#ifndef USE_SFIO /* just generating prototypes */
+# define Sfio_t int
+# define Sfdisc_t int
+#endif
+
+#define NIL(type) ((type)0)
+
+ static int
+sfvimwrite(
+ Sfio_t *f, /* stream involved */
+ char *buf, /* buffer to read from */
+ int n, /* number of bytes to write */
+ Sfdisc_t *disc) /* discipline */
+{
+ char_u *str;
+
+ str = vim_strnsave((char_u *)buf, n);
+ if (str == NULL)
+ return 0;
+ msg_split((char *)str);
+ vim_free(str);
+
+ return n;
+}
+
+/*
+ * sfdcnewnvi --
+ * Create Vim discipline
+ */
+ Sfdisc_t *
+sfdcnewvim(void)
+{
+ Sfdisc_t *disc;
+
+ disc = (Sfdisc_t *)alloc((unsigned)sizeof(Sfdisc_t));
+ if (disc == NULL)
+ return NULL;
+
+ disc->readf = (Sfread_f)NULL;
+ disc->writef = sfvimwrite;
+ disc->seekf = (Sfseek_f)NULL;
+ disc->exceptf = (Sfexcept_f)NULL;
+
+ return disc;
+}
+
+#endif /* USE_SFIO */
diff --git a/src/if_py_both.h b/src/if_py_both.h
new file mode 100644
index 0000000..a0c1663
--- /dev/null
+++ b/src/if_py_both.h
@@ -0,0 +1,6951 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+/*
+ * Python extensions by Paul Moore, David Leonard, Roland Puntaier, Nikolay
+ * Pavlov.
+ *
+ * Common code for if_python.c and if_python3.c.
+ */
+
+#ifdef __BORLANDC__
+/* Disable Warning W8060: Possibly incorrect assignment in function ... */
+# pragma warn -8060
+#endif
+
+static char_u e_py_systemexit[] = "E880: Can't handle SystemExit of %s exception in vim";
+
+#if PY_VERSION_HEX < 0x02050000
+typedef int Py_ssize_t; /* Python 2.4 and earlier don't have this type. */
+#endif
+
+#define ENC_OPT ((char *)p_enc)
+#define DOPY_FUNC "_vim_pydo"
+
+static const char *vim_special_path = "_vim_path_";
+
+#define PyErr_SET_STRING(exc, str) PyErr_SetString(exc, _(str))
+#define PyErr_SetVim(str) PyErr_SetString(VimError, str)
+#define PyErr_SET_VIM(str) PyErr_SET_STRING(VimError, str)
+#define PyErr_FORMAT(exc, str, arg) PyErr_Format(exc, _(str), arg)
+#define PyErr_FORMAT2(exc, str, arg1, arg2) PyErr_Format(exc, _(str), arg1,arg2)
+#define PyErr_VIM_FORMAT(str, arg) PyErr_FORMAT(VimError, str, arg)
+
+#define Py_TYPE_NAME(obj) (obj->ob_type->tp_name == NULL \
+ ? "(NULL)" \
+ : obj->ob_type->tp_name)
+
+#define RAISE_NO_EMPTY_KEYS PyErr_SET_STRING(PyExc_ValueError, \
+ N_("empty keys are not allowed"))
+#define RAISE_LOCKED_DICTIONARY PyErr_SET_VIM(N_("dictionary is locked"))
+#define RAISE_LOCKED_LIST PyErr_SET_VIM(N_("list is locked"))
+#define RAISE_UNDO_FAIL PyErr_SET_VIM(N_("cannot save undo information"))
+#define RAISE_DELETE_LINE_FAIL PyErr_SET_VIM(N_("cannot delete line"))
+#define RAISE_INSERT_LINE_FAIL PyErr_SET_VIM(N_("cannot insert line"))
+#define RAISE_REPLACE_LINE_FAIL PyErr_SET_VIM(N_("cannot replace line"))
+#define RAISE_KEY_ADD_FAIL(key) \
+ PyErr_VIM_FORMAT(N_("failed to add key '%s' to dictionary"), key)
+#define RAISE_INVALID_INDEX_TYPE(idx) \
+ PyErr_FORMAT(PyExc_TypeError, N_("index must be int or slice, not %s"), \
+ Py_TYPE_NAME(idx));
+
+#define INVALID_BUFFER_VALUE ((buf_T *)(-1))
+#define INVALID_WINDOW_VALUE ((win_T *)(-1))
+#define INVALID_TABPAGE_VALUE ((tabpage_T *)(-1))
+
+typedef void (*rangeinitializer)(void *);
+typedef void (*runner)(const char *, void *
+#ifdef PY_CAN_RECURSE
+ , PyGILState_STATE *
+#endif
+ );
+
+static int ConvertFromPyObject(PyObject *, typval_T *);
+static int _ConvertFromPyObject(PyObject *, typval_T *, PyObject *);
+static int ConvertFromPyMapping(PyObject *, typval_T *);
+static int ConvertFromPySequence(PyObject *, typval_T *);
+static PyObject *WindowNew(win_T *, tabpage_T *);
+static PyObject *BufferNew (buf_T *);
+static PyObject *LineToString(const char *);
+
+static PyInt RangeStart;
+static PyInt RangeEnd;
+
+static PyObject *globals;
+
+static PyObject *py_chdir;
+static PyObject *py_fchdir;
+static PyObject *py_getcwd;
+static PyObject *vim_module;
+static PyObject *vim_special_path_object;
+
+#if PY_VERSION_HEX >= 0x030700f0
+static PyObject *py_find_spec;
+#else
+static PyObject *py_find_module;
+static PyObject *py_load_module;
+#endif
+
+static PyObject *VimError;
+
+/*
+ * obtain a lock on the Vim data structures
+ */
+ static void
+Python_Lock_Vim(void)
+{
+}
+
+/*
+ * release a lock on the Vim data structures
+ */
+ static void
+Python_Release_Vim(void)
+{
+}
+
+/*
+ * The "todecref" argument holds a pointer to PyObject * that must be
+ * DECREF'ed after returned char_u * is no longer needed or NULL if all what
+ * was needed to generate returned value is object.
+ *
+ * Use Py_XDECREF to decrement reference count.
+ */
+ static char_u *
+StringToChars(PyObject *obj, PyObject **todecref)
+{
+ char_u *str;
+
+ if (PyBytes_Check(obj))
+ {
+
+ if (PyBytes_AsStringAndSize(obj, (char **) &str, NULL) == -1
+ || str == NULL)
+ return NULL;
+
+ *todecref = NULL;
+ }
+ else if (PyUnicode_Check(obj))
+ {
+ PyObject *bytes;
+
+ if (!(bytes = PyUnicode_AsEncodedString(obj, ENC_OPT, NULL)))
+ return NULL;
+
+ if(PyBytes_AsStringAndSize(bytes, (char **) &str, NULL) == -1
+ || str == NULL)
+ {
+ Py_DECREF(bytes);
+ return NULL;
+ }
+
+ *todecref = bytes;
+ }
+ else
+ {
+#if PY_MAJOR_VERSION < 3
+ PyErr_FORMAT(PyExc_TypeError,
+ N_("expected str() or unicode() instance, but got %s"),
+ Py_TYPE_NAME(obj));
+#else
+ PyErr_FORMAT(PyExc_TypeError,
+ N_("expected bytes() or str() instance, but got %s"),
+ Py_TYPE_NAME(obj));
+#endif
+ return NULL;
+ }
+
+ return (char_u *) str;
+}
+
+#define NUMBER_LONG 1
+#define NUMBER_INT 2
+#define NUMBER_NATURAL 4
+#define NUMBER_UNSIGNED 8
+
+ static int
+NumberToLong(PyObject *obj, long *result, int flags)
+{
+#if PY_MAJOR_VERSION < 3
+ if (PyInt_Check(obj))
+ {
+ *result = PyInt_AsLong(obj);
+ if (PyErr_Occurred())
+ return -1;
+ }
+ else
+#endif
+ if (PyLong_Check(obj))
+ {
+ *result = PyLong_AsLong(obj);
+ if (PyErr_Occurred())
+ return -1;
+ }
+ else if (PyNumber_Check(obj))
+ {
+ PyObject *num;
+
+ if (!(num = PyNumber_Long(obj)))
+ return -1;
+
+ *result = PyLong_AsLong(num);
+
+ Py_DECREF(num);
+
+ if (PyErr_Occurred())
+ return -1;
+ }
+ else
+ {
+#if PY_MAJOR_VERSION < 3
+ PyErr_FORMAT(PyExc_TypeError,
+ N_("expected int(), long() or something supporting "
+ "coercing to long(), but got %s"),
+ Py_TYPE_NAME(obj));
+#else
+ PyErr_FORMAT(PyExc_TypeError,
+ N_("expected int() or something supporting coercing to int(), "
+ "but got %s"),
+ Py_TYPE_NAME(obj));
+#endif
+ return -1;
+ }
+
+ if (flags & NUMBER_INT)
+ {
+ if (*result > INT_MAX)
+ {
+ PyErr_SET_STRING(PyExc_OverflowError,
+ N_("value is too large to fit into C int type"));
+ return -1;
+ }
+ else if (*result < INT_MIN)
+ {
+ PyErr_SET_STRING(PyExc_OverflowError,
+ N_("value is too small to fit into C int type"));
+ return -1;
+ }
+ }
+
+ if (flags & NUMBER_NATURAL)
+ {
+ if (*result <= 0)
+ {
+ PyErr_SET_STRING(PyExc_ValueError,
+ N_("number must be greater than zero"));
+ return -1;
+ }
+ }
+ else if (flags & NUMBER_UNSIGNED)
+ {
+ if (*result < 0)
+ {
+ PyErr_SET_STRING(PyExc_ValueError,
+ N_("number must be greater or equal to zero"));
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+ static int
+add_string(PyObject *list, char *s)
+{
+ PyObject *string;
+
+ if (!(string = PyString_FromString(s)))
+ return -1;
+
+ if (PyList_Append(list, string))
+ {
+ Py_DECREF(string);
+ return -1;
+ }
+
+ Py_DECREF(string);
+ return 0;
+}
+
+ static PyObject *
+ObjectDir(PyObject *self, char **attributes)
+{
+ PyMethodDef *method;
+ char **attr;
+ PyObject *ret;
+
+ if (!(ret = PyList_New(0)))
+ return NULL;
+
+ if (self)
+ for (method = self->ob_type->tp_methods ; method->ml_name != NULL ; ++method)
+ if (add_string(ret, (char *)method->ml_name))
+ {
+ Py_DECREF(ret);
+ return NULL;
+ }
+
+ for (attr = attributes ; *attr ; ++attr)
+ if (add_string(ret, *attr))
+ {
+ Py_DECREF(ret);
+ return NULL;
+ }
+
+#if PY_MAJOR_VERSION < 3
+ if (add_string(ret, "__members__"))
+ {
+ Py_DECREF(ret);
+ return NULL;
+ }
+#endif
+
+ return ret;
+}
+
+/* Output buffer management
+ */
+
+/* Function to write a line, points to either msg() or emsg(). */
+typedef void (*writefn)(char_u *);
+
+static PyTypeObject OutputType;
+
+typedef struct
+{
+ PyObject_HEAD
+ long softspace;
+ long error;
+} OutputObject;
+
+static char *OutputAttrs[] = {
+ "softspace",
+ NULL
+};
+
+ static PyObject *
+OutputDir(PyObject *self)
+{
+ return ObjectDir(self, OutputAttrs);
+}
+
+ static int
+OutputSetattr(OutputObject *self, char *name, PyObject *valObject)
+{
+ if (valObject == NULL)
+ {
+ PyErr_SET_STRING(PyExc_AttributeError,
+ N_("can't delete OutputObject attributes"));
+ return -1;
+ }
+
+ if (strcmp(name, "softspace") == 0)
+ {
+ if (NumberToLong(valObject, &(self->softspace), NUMBER_UNSIGNED))
+ return -1;
+ return 0;
+ }
+
+ PyErr_FORMAT(PyExc_AttributeError, N_("invalid attribute: %s"), name);
+ return -1;
+}
+
+/* Buffer IO, we write one whole line at a time. */
+static garray_T io_ga = {0, 0, 1, 80, NULL};
+static writefn old_fn = NULL;
+
+ static void
+PythonIO_Flush(void)
+{
+ if (old_fn != NULL && io_ga.ga_len > 0)
+ {
+ ((char_u *)io_ga.ga_data)[io_ga.ga_len] = NUL;
+ old_fn((char_u *)io_ga.ga_data);
+ }
+ io_ga.ga_len = 0;
+}
+
+ static void
+writer(writefn fn, char_u *str, PyInt n)
+{
+ char_u *ptr;
+
+ /* Flush when switching output function. */
+ if (fn != old_fn)
+ PythonIO_Flush();
+ old_fn = fn;
+
+ /* Write each NL separated line. Text after the last NL is kept for
+ * writing later. */
+ while (n > 0 && (ptr = memchr(str, '\n', n)) != NULL)
+ {
+ PyInt len = ptr - str;
+
+ if (ga_grow(&io_ga, (int)(len + 1)) == FAIL)
+ break;
+
+ mch_memmove(((char *)io_ga.ga_data) + io_ga.ga_len, str, (size_t)len);
+ ((char *)io_ga.ga_data)[io_ga.ga_len + len] = NUL;
+ fn((char_u *)io_ga.ga_data);
+ str = ptr + 1;
+ n -= len + 1;
+ io_ga.ga_len = 0;
+ }
+
+ /* Put the remaining text into io_ga for later printing. */
+ if (n > 0 && ga_grow(&io_ga, (int)(n + 1)) == OK)
+ {
+ mch_memmove(((char *)io_ga.ga_data) + io_ga.ga_len, str, (size_t)n);
+ io_ga.ga_len += (int)n;
+ }
+}
+
+ static int
+write_output(OutputObject *self, PyObject *string)
+{
+ Py_ssize_t len = 0;
+ char *str = NULL;
+ int error = self->error;
+
+ if (!PyArg_Parse(string, "et#", ENC_OPT, &str, &len))
+ return -1;
+
+ Py_BEGIN_ALLOW_THREADS
+ Python_Lock_Vim();
+ writer((writefn)(error ? emsg : msg), (char_u *)str, len);
+ Python_Release_Vim();
+ Py_END_ALLOW_THREADS
+ PyMem_Free(str);
+
+ return 0;
+}
+
+ static PyObject *
+OutputWrite(OutputObject *self, PyObject *string)
+{
+ if (write_output(self, string))
+ return NULL;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+ static PyObject *
+OutputWritelines(OutputObject *self, PyObject *seq)
+{
+ PyObject *iterator;
+ PyObject *item;
+
+ if (!(iterator = PyObject_GetIter(seq)))
+ return NULL;
+
+ while ((item = PyIter_Next(iterator)))
+ {
+ if (write_output(self, item))
+ {
+ Py_DECREF(iterator);
+ Py_DECREF(item);
+ return NULL;
+ }
+ Py_DECREF(item);
+ }
+
+ Py_DECREF(iterator);
+
+ /* Iterator may have finished due to an exception */
+ if (PyErr_Occurred())
+ return NULL;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+ static PyObject *
+AlwaysNone(PyObject *self UNUSED)
+{
+ /* do nothing */
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+ static PyObject *
+AlwaysFalse(PyObject *self UNUSED)
+{
+ /* do nothing */
+ PyObject *ret = Py_False;
+ Py_INCREF(ret);
+ return ret;
+}
+
+ static PyObject *
+AlwaysTrue(PyObject *self UNUSED)
+{
+ /* do nothing */
+ PyObject *ret = Py_True;
+ Py_INCREF(ret);
+ return ret;
+}
+
+/***************/
+
+static struct PyMethodDef OutputMethods[] = {
+ /* name, function, calling, doc */
+ {"write", (PyCFunction)OutputWrite, METH_O, ""},
+ {"writelines", (PyCFunction)OutputWritelines, METH_O, ""},
+ {"flush", (PyCFunction)AlwaysNone, METH_NOARGS, ""},
+ {"close", (PyCFunction)AlwaysNone, METH_NOARGS, ""},
+ {"isatty", (PyCFunction)AlwaysFalse, METH_NOARGS, ""},
+ {"readable", (PyCFunction)AlwaysFalse, METH_NOARGS, ""},
+ {"seekable", (PyCFunction)AlwaysFalse, METH_NOARGS, ""},
+ {"writable", (PyCFunction)AlwaysTrue, METH_NOARGS, ""},
+ {"closed", (PyCFunction)AlwaysFalse, METH_NOARGS, ""},
+ {"__dir__", (PyCFunction)OutputDir, METH_NOARGS, ""},
+ { NULL, NULL, 0, NULL}
+};
+
+static OutputObject Output =
+{
+ PyObject_HEAD_INIT(&OutputType)
+ 0,
+ 0
+};
+
+static OutputObject Error =
+{
+ PyObject_HEAD_INIT(&OutputType)
+ 0,
+ 1
+};
+
+ static int
+PythonIO_Init_io(void)
+{
+ if (PySys_SetObject("stdout", (PyObject *)(void *)&Output))
+ return -1;
+ if (PySys_SetObject("stderr", (PyObject *)(void *)&Error))
+ return -1;
+
+ if (PyErr_Occurred())
+ {
+ emsg(_("E264: Python: Error initialising I/O objects"));
+ return -1;
+ }
+
+ return 0;
+}
+
+#if PY_VERSION_HEX < 0x030700f0
+static PyObject *call_load_module(char *name, int len, PyObject *find_module_result);
+
+typedef struct
+{
+ PyObject_HEAD
+ char *fullname;
+ PyObject *result;
+} LoaderObject;
+static PyTypeObject LoaderType;
+
+ static void
+LoaderDestructor(LoaderObject *self)
+{
+ vim_free(self->fullname);
+ Py_XDECREF(self->result);
+ DESTRUCTOR_FINISH(self);
+}
+
+ static PyObject *
+LoaderLoadModule(LoaderObject *self, PyObject *args UNUSED)
+{
+ char *fullname = self->fullname;
+ PyObject *result = self->result;
+ PyObject *module;
+
+ if (!fullname)
+ {
+ module = result ? result : Py_None;
+ Py_INCREF(module);
+ return module;
+ }
+
+ module = call_load_module(fullname, (int)STRLEN(fullname), result);
+
+ self->fullname = NULL;
+ self->result = module;
+
+ vim_free(fullname);
+ Py_DECREF(result);
+
+ if (!module)
+ {
+ if (PyErr_Occurred())
+ return NULL;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ Py_INCREF(module);
+ return module;
+}
+
+static struct PyMethodDef LoaderMethods[] = {
+ /* name, function, calling, doc */
+ {"load_module", (PyCFunction)LoaderLoadModule, METH_VARARGS, ""},
+ { NULL, NULL, 0, NULL}
+};
+#endif
+
+/* Check to see whether a Vim error has been reported, or a keyboard
+ * interrupt has been detected.
+ */
+
+ static void
+VimTryStart(void)
+{
+ ++trylevel;
+}
+
+ static int
+VimTryEnd(void)
+{
+ --trylevel;
+ /* Without this it stops processing all subsequent Vim script commands and
+ * generates strange error messages if I e.g. try calling Test() in a cycle
+ */
+ did_emsg = FALSE;
+ /* Keyboard interrupt should be preferred over anything else */
+ if (got_int)
+ {
+ if (did_throw)
+ discard_current_exception();
+ got_int = FALSE;
+ PyErr_SetNone(PyExc_KeyboardInterrupt);
+ return -1;
+ }
+ else if (msg_list != NULL && *msg_list != NULL)
+ {
+ int should_free;
+ char *msg;
+
+ msg = get_exception_string(*msg_list, ET_ERROR, NULL, &should_free);
+
+ if (msg == NULL)
+ {
+ PyErr_NoMemory();
+ return -1;
+ }
+
+ PyErr_SetVim(msg);
+
+ free_global_msglist();
+
+ if (should_free)
+ vim_free(msg);
+
+ return -1;
+ }
+ else if (!did_throw)
+ return (PyErr_Occurred() ? -1 : 0);
+ /* Python exception is preferred over vim one; unlikely to occur though */
+ else if (PyErr_Occurred())
+ {
+ discard_current_exception();
+ return -1;
+ }
+ /* Finally transform Vim script exception to python one */
+ else
+ {
+ PyErr_SetVim((char *)current_exception->value);
+ discard_current_exception();
+ return -1;
+ }
+}
+
+ static int
+VimCheckInterrupt(void)
+{
+ if (got_int)
+ {
+ PyErr_SetNone(PyExc_KeyboardInterrupt);
+ return 1;
+ }
+ return 0;
+}
+
+/* Vim module - Implementation
+ */
+
+ static PyObject *
+VimCommand(PyObject *self UNUSED, PyObject *string)
+{
+ char_u *cmd;
+ PyObject *ret;
+ PyObject *todecref;
+
+ if (!(cmd = StringToChars(string, &todecref)))
+ return NULL;
+
+ Py_BEGIN_ALLOW_THREADS
+ Python_Lock_Vim();
+
+ VimTryStart();
+ do_cmdline_cmd(cmd);
+ update_screen(VALID);
+
+ Python_Release_Vim();
+ Py_END_ALLOW_THREADS
+
+ if (VimTryEnd())
+ ret = NULL;
+ else
+ ret = Py_None;
+
+ Py_XINCREF(ret);
+ Py_XDECREF(todecref);
+ return ret;
+}
+
+/*
+ * Function to translate a typval_T into a PyObject; this will recursively
+ * translate lists/dictionaries into their Python equivalents.
+ *
+ * The depth parameter is to avoid infinite recursion, set it to 1 when
+ * you call VimToPython.
+ */
+ static PyObject *
+VimToPython(typval_T *our_tv, int depth, PyObject *lookup_dict)
+{
+ PyObject *ret;
+ PyObject *newObj;
+ char ptrBuf[sizeof(void *) * 2 + 3];
+
+ /* Avoid infinite recursion */
+ if (depth > 100)
+ {
+ Py_INCREF(Py_None);
+ ret = Py_None;
+ return ret;
+ }
+
+ /* Check if we run into a recursive loop. The item must be in lookup_dict
+ * then and we can use it again. */
+ if ((our_tv->v_type == VAR_LIST && our_tv->vval.v_list != NULL)
+ || (our_tv->v_type == VAR_DICT && our_tv->vval.v_dict != NULL))
+ {
+ sprintf(ptrBuf, "%p",
+ our_tv->v_type == VAR_LIST ? (void *)our_tv->vval.v_list
+ : (void *)our_tv->vval.v_dict);
+
+ if ((ret = PyDict_GetItemString(lookup_dict, ptrBuf)))
+ {
+ Py_INCREF(ret);
+ return ret;
+ }
+ }
+
+ if (our_tv->v_type == VAR_STRING)
+ ret = PyString_FromString(our_tv->vval.v_string == NULL
+ ? "" : (char *)our_tv->vval.v_string);
+ else if (our_tv->v_type == VAR_NUMBER)
+ {
+ char buf[NUMBUFLEN];
+
+ /* For backwards compatibility numbers are stored as strings. */
+ sprintf(buf, "%ld", (long)our_tv->vval.v_number);
+ ret = PyString_FromString((char *)buf);
+ }
+# ifdef FEAT_FLOAT
+ else if (our_tv->v_type == VAR_FLOAT)
+ {
+ char buf[NUMBUFLEN];
+
+ sprintf(buf, "%f", our_tv->vval.v_float);
+ ret = PyString_FromString((char *)buf);
+ }
+# endif
+ else if (our_tv->v_type == VAR_LIST)
+ {
+ list_T *list = our_tv->vval.v_list;
+ listitem_T *curr;
+
+ if (list == NULL)
+ return NULL;
+
+ if (!(ret = PyList_New(0)))
+ return NULL;
+
+ if (PyDict_SetItemString(lookup_dict, ptrBuf, ret))
+ {
+ Py_DECREF(ret);
+ return NULL;
+ }
+
+ for (curr = list->lv_first; curr != NULL; curr = curr->li_next)
+ {
+ if (!(newObj = VimToPython(&curr->li_tv, depth + 1, lookup_dict)))
+ {
+ Py_DECREF(ret);
+ return NULL;
+ }
+ if (PyList_Append(ret, newObj))
+ {
+ Py_DECREF(newObj);
+ Py_DECREF(ret);
+ return NULL;
+ }
+ Py_DECREF(newObj);
+ }
+ }
+ else if (our_tv->v_type == VAR_DICT)
+ {
+
+ hashtab_T *ht;
+ long_u todo;
+ hashitem_T *hi;
+ dictitem_T *di;
+
+ if (our_tv->vval.v_dict == NULL)
+ return NULL;
+ ht = &our_tv->vval.v_dict->dv_hashtab;
+
+ if (!(ret = PyDict_New()))
+ return NULL;
+
+ if (PyDict_SetItemString(lookup_dict, ptrBuf, ret))
+ {
+ Py_DECREF(ret);
+ return NULL;
+ }
+
+ todo = ht->ht_used;
+ for (hi = ht->ht_array; todo > 0; ++hi)
+ {
+ if (!HASHITEM_EMPTY(hi))
+ {
+ --todo;
+
+ di = dict_lookup(hi);
+ if (!(newObj = VimToPython(&di->di_tv, depth + 1, lookup_dict)))
+ {
+ Py_DECREF(ret);
+ return NULL;
+ }
+ if (PyDict_SetItemString(ret, (char *)hi->hi_key, newObj))
+ {
+ Py_DECREF(ret);
+ Py_DECREF(newObj);
+ return NULL;
+ }
+ }
+ }
+ }
+ else if (our_tv->v_type == VAR_SPECIAL)
+ {
+ if (our_tv->vval.v_number == VVAL_FALSE)
+ {
+ ret = Py_False;
+ Py_INCREF(ret);
+ }
+ else if (our_tv->vval.v_number == VVAL_TRUE)
+ {
+ ret = Py_True;
+ Py_INCREF(ret);
+ }
+ else
+ {
+ Py_INCREF(Py_None);
+ ret = Py_None;
+ }
+ return ret;
+ }
+ else if (our_tv->v_type == VAR_BLOB)
+ ret = PyBytes_FromStringAndSize(
+ (char*) our_tv->vval.v_blob->bv_ga.ga_data,
+ (Py_ssize_t) our_tv->vval.v_blob->bv_ga.ga_len);
+ else
+ {
+ Py_INCREF(Py_None);
+ ret = Py_None;
+ }
+
+ return ret;
+}
+
+ static PyObject *
+VimEval(PyObject *self UNUSED, PyObject *args)
+{
+ char_u *expr;
+ typval_T *our_tv;
+ PyObject *string;
+ PyObject *todecref;
+ PyObject *ret;
+ PyObject *lookup_dict;
+
+ if (!PyArg_ParseTuple(args, "O", &string))
+ return NULL;
+
+ if (!(expr = StringToChars(string, &todecref)))
+ return NULL;
+
+ Py_BEGIN_ALLOW_THREADS
+ Python_Lock_Vim();
+ VimTryStart();
+ our_tv = eval_expr(expr, NULL);
+ Python_Release_Vim();
+ Py_END_ALLOW_THREADS
+
+ Py_XDECREF(todecref);
+
+ if (VimTryEnd())
+ return NULL;
+
+ if (our_tv == NULL)
+ {
+ PyErr_SET_VIM(N_("invalid expression"));
+ return NULL;
+ }
+
+ /* Convert the Vim type into a Python type. Create a dictionary that's
+ * used to check for recursive loops. */
+ if (!(lookup_dict = PyDict_New()))
+ ret = NULL;
+ else
+ {
+ ret = VimToPython(our_tv, 1, lookup_dict);
+ Py_DECREF(lookup_dict);
+ }
+
+
+ Py_BEGIN_ALLOW_THREADS
+ Python_Lock_Vim();
+ free_tv(our_tv);
+ Python_Release_Vim();
+ Py_END_ALLOW_THREADS
+
+ return ret;
+}
+
+static PyObject *ConvertToPyObject(typval_T *);
+
+ static PyObject *
+VimEvalPy(PyObject *self UNUSED, PyObject *string)
+{
+ typval_T *our_tv;
+ PyObject *ret;
+ char_u *expr;
+ PyObject *todecref;
+
+ if (!(expr = StringToChars(string, &todecref)))
+ return NULL;
+
+ Py_BEGIN_ALLOW_THREADS
+ Python_Lock_Vim();
+ VimTryStart();
+ our_tv = eval_expr(expr, NULL);
+ Python_Release_Vim();
+ Py_END_ALLOW_THREADS
+
+ Py_XDECREF(todecref);
+
+ if (VimTryEnd())
+ return NULL;
+
+ if (our_tv == NULL)
+ {
+ PyErr_SET_VIM(N_("invalid expression"));
+ return NULL;
+ }
+
+ ret = ConvertToPyObject(our_tv);
+ Py_BEGIN_ALLOW_THREADS
+ Python_Lock_Vim();
+ free_tv(our_tv);
+ Python_Release_Vim();
+ Py_END_ALLOW_THREADS
+
+ return ret;
+}
+
+ static PyObject *
+VimStrwidth(PyObject *self UNUSED, PyObject *string)
+{
+ char_u *str;
+ PyObject *todecref;
+ int len;
+
+ if (!(str = StringToChars(string, &todecref)))
+ return NULL;
+
+ len = mb_string2cells(str, (int)STRLEN(str));
+
+ Py_XDECREF(todecref);
+
+ return PyLong_FromLong(len);
+}
+
+ static PyObject *
+_VimChdir(PyObject *_chdir, PyObject *args, PyObject *kwargs)
+{
+ PyObject *ret;
+ PyObject *newwd;
+ PyObject *todecref;
+ char_u *new_dir;
+
+ if (_chdir == NULL)
+ return NULL;
+ if (!(ret = PyObject_Call(_chdir, args, kwargs)))
+ return NULL;
+
+ if (!(newwd = PyObject_CallFunctionObjArgs(py_getcwd, NULL)))
+ {
+ Py_DECREF(ret);
+ return NULL;
+ }
+
+ if (!(new_dir = StringToChars(newwd, &todecref)))
+ {
+ Py_DECREF(ret);
+ Py_DECREF(newwd);
+ return NULL;
+ }
+
+ VimTryStart();
+
+ if (vim_chdir(new_dir))
+ {
+ Py_DECREF(ret);
+ Py_DECREF(newwd);
+ Py_XDECREF(todecref);
+
+ if (VimTryEnd())
+ return NULL;
+
+ PyErr_SET_VIM(N_("failed to change directory"));
+ return NULL;
+ }
+
+ Py_DECREF(newwd);
+ Py_XDECREF(todecref);
+
+ post_chdir(FALSE);
+
+ if (VimTryEnd())
+ {
+ Py_DECREF(ret);
+ return NULL;
+ }
+
+ return ret;
+}
+
+ static PyObject *
+VimChdir(PyObject *self UNUSED, PyObject *args, PyObject *kwargs)
+{
+ return _VimChdir(py_chdir, args, kwargs);
+}
+
+ static PyObject *
+VimFchdir(PyObject *self UNUSED, PyObject *args, PyObject *kwargs)
+{
+ return _VimChdir(py_fchdir, args, kwargs);
+}
+
+typedef struct {
+ PyObject *callable;
+ PyObject *result;
+} map_rtp_data;
+
+ static void
+map_rtp_callback(char_u *path, void *_data)
+{
+ void **data = (void **) _data;
+ PyObject *pathObject;
+ map_rtp_data *mr_data = *((map_rtp_data **) data);
+
+ if (!(pathObject = PyString_FromString((char *)path)))
+ {
+ *data = NULL;
+ return;
+ }
+
+ mr_data->result = PyObject_CallFunctionObjArgs(mr_data->callable,
+ pathObject, NULL);
+
+ Py_DECREF(pathObject);
+
+ if (!mr_data->result || mr_data->result != Py_None)
+ *data = NULL;
+ else
+ {
+ Py_DECREF(mr_data->result);
+ mr_data->result = NULL;
+ }
+}
+
+ static PyObject *
+VimForeachRTP(PyObject *self UNUSED, PyObject *callable)
+{
+ map_rtp_data data;
+
+ data.callable = callable;
+ data.result = NULL;
+
+ do_in_runtimepath(NULL, 0, &map_rtp_callback, &data);
+
+ if (data.result == NULL)
+ {
+ if (PyErr_Occurred())
+ return NULL;
+ else
+ {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ }
+ return data.result;
+}
+
+/*
+ * _vim_runtimepath_ special path implementation.
+ */
+
+ static void
+map_finder_callback(char_u *path, void *_data)
+{
+ void **data = (void **) _data;
+ PyObject *list = *((PyObject **) data);
+ PyObject *pathObject1, *pathObject2;
+ char *pathbuf;
+ size_t pathlen;
+
+ pathlen = STRLEN(path);
+
+#if PY_MAJOR_VERSION < 3
+# define PY_MAIN_DIR_STRING "python2"
+#else
+# define PY_MAIN_DIR_STRING "python3"
+#endif
+#define PY_ALTERNATE_DIR_STRING "pythonx"
+
+#define PYTHONX_STRING_LENGTH 7 /* STRLEN("pythonx") */
+ if (!(pathbuf = PyMem_New(char,
+ pathlen + STRLEN(PATHSEPSTR) + PYTHONX_STRING_LENGTH + 1)))
+ {
+ PyErr_NoMemory();
+ *data = NULL;
+ return;
+ }
+
+ mch_memmove(pathbuf, path, pathlen + 1);
+ add_pathsep((char_u *) pathbuf);
+
+ pathlen = STRLEN(pathbuf);
+ mch_memmove(pathbuf + pathlen, PY_MAIN_DIR_STRING,
+ PYTHONX_STRING_LENGTH + 1);
+
+ if (!(pathObject1 = PyString_FromString(pathbuf)))
+ {
+ *data = NULL;
+ PyMem_Free(pathbuf);
+ return;
+ }
+
+ mch_memmove(pathbuf + pathlen, PY_ALTERNATE_DIR_STRING,
+ PYTHONX_STRING_LENGTH + 1);
+
+ if (!(pathObject2 = PyString_FromString(pathbuf)))
+ {
+ Py_DECREF(pathObject1);
+ PyMem_Free(pathbuf);
+ *data = NULL;
+ return;
+ }
+
+ PyMem_Free(pathbuf);
+
+ if (PyList_Append(list, pathObject1)
+ || PyList_Append(list, pathObject2))
+ *data = NULL;
+
+ Py_DECREF(pathObject1);
+ Py_DECREF(pathObject2);
+}
+
+ static PyObject *
+Vim_GetPaths(PyObject *self UNUSED)
+{
+ PyObject *ret;
+
+ if (!(ret = PyList_New(0)))
+ return NULL;
+
+ do_in_runtimepath(NULL, 0, &map_finder_callback, ret);
+
+ if (PyErr_Occurred())
+ {
+ Py_DECREF(ret);
+ return NULL;
+ }
+
+ return ret;
+}
+
+#if PY_VERSION_HEX >= 0x030700f0
+ static PyObject *
+FinderFindSpec(PyObject *self, PyObject *args)
+{
+ char *fullname;
+ PyObject *paths;
+ PyObject *target = Py_None;
+ PyObject *spec;
+
+ if (!PyArg_ParseTuple(args, "s|O", &fullname, &target))
+ return NULL;
+
+ if (!(paths = Vim_GetPaths(self)))
+ return NULL;
+
+ spec = PyObject_CallFunction(py_find_spec, "sNN", fullname, paths, target);
+
+ Py_DECREF(paths);
+
+ if (!spec)
+ {
+ if (PyErr_Occurred())
+ return NULL;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ return spec;
+}
+#else
+ static PyObject *
+call_load_module(char *name, int len, PyObject *find_module_result)
+{
+ PyObject *fd, *pathname, *description;
+
+ if (!PyTuple_Check(find_module_result))
+ {
+ PyErr_FORMAT(PyExc_TypeError,
+ N_("expected 3-tuple as imp.find_module() result, but got %s"),
+ Py_TYPE_NAME(find_module_result));
+ return NULL;
+ }
+ if (PyTuple_GET_SIZE(find_module_result) != 3)
+ {
+ PyErr_FORMAT(PyExc_TypeError,
+ N_("expected 3-tuple as imp.find_module() result, but got "
+ "tuple of size %d"),
+ (int) PyTuple_GET_SIZE(find_module_result));
+ return NULL;
+ }
+
+ if (!(fd = PyTuple_GET_ITEM(find_module_result, 0))
+ || !(pathname = PyTuple_GET_ITEM(find_module_result, 1))
+ || !(description = PyTuple_GET_ITEM(find_module_result, 2)))
+ {
+ PyErr_SET_STRING(PyExc_RuntimeError,
+ N_("internal error: imp.find_module returned tuple with NULL"));
+ return NULL;
+ }
+
+ return PyObject_CallFunction(py_load_module,
+ "s#OOO", name, len, fd, pathname, description);
+}
+
+ static PyObject *
+find_module(char *fullname, char *tail, PyObject *new_path)
+{
+ PyObject *find_module_result;
+ PyObject *module;
+ char *dot;
+
+ if ((dot = (char *)vim_strchr((char_u *) tail, '.')))
+ {
+ /*
+ * There is a dot in the name: call find_module recursively without the
+ * first component
+ */
+ PyObject *newest_path;
+ int partlen = (int) (dot - 1 - tail);
+
+ if (!(find_module_result = PyObject_CallFunction(py_find_module,
+ "s#O", tail, partlen, new_path)))
+ {
+ if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_ImportError))
+ PyErr_Clear();
+ return NULL;
+ }
+
+ if (!(module = call_load_module(
+ fullname,
+ ((int) (tail - fullname)) + partlen,
+ find_module_result)))
+ {
+ Py_DECREF(find_module_result);
+ return NULL;
+ }
+
+ Py_DECREF(find_module_result);
+
+ if (!(newest_path = PyObject_GetAttrString(module, "__path__")))
+ {
+ Py_DECREF(module);
+ return NULL;
+ }
+
+ Py_DECREF(module);
+
+ find_module_result = find_module(fullname, dot + 1, newest_path);
+
+ Py_DECREF(newest_path);
+
+ return find_module_result;
+ }
+ else
+ {
+ if (!(find_module_result = PyObject_CallFunction(py_find_module,
+ "sO", tail, new_path)))
+ {
+ if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_ImportError))
+ PyErr_Clear();
+ return NULL;
+ }
+
+ return find_module_result;
+ }
+}
+
+ static PyObject *
+FinderFindModule(PyObject *self, PyObject *args)
+{
+ char *fullname;
+ PyObject *result;
+ PyObject *new_path;
+ LoaderObject *loader;
+
+ if (!PyArg_ParseTuple(args, "s", &fullname))
+ return NULL;
+
+ if (!(new_path = Vim_GetPaths(self)))
+ return NULL;
+
+ result = find_module(fullname, fullname, new_path);
+
+ Py_DECREF(new_path);
+
+ if (!result)
+ {
+ if (PyErr_Occurred())
+ return NULL;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ if (!(fullname = (char *)vim_strsave((char_u *)fullname)))
+ {
+ Py_DECREF(result);
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ if (!(loader = PyObject_NEW(LoaderObject, &LoaderType)))
+ {
+ vim_free(fullname);
+ Py_DECREF(result);
+ return NULL;
+ }
+
+ loader->fullname = fullname;
+ loader->result = result;
+
+ return (PyObject *) loader;
+}
+#endif
+
+ static PyObject *
+VimPathHook(PyObject *self UNUSED, PyObject *args)
+{
+ char *path;
+
+ if (PyArg_ParseTuple(args, "s", &path)
+ && STRCMP(path, vim_special_path) == 0)
+ {
+ Py_INCREF(vim_module);
+ return vim_module;
+ }
+
+ PyErr_Clear();
+ PyErr_SetNone(PyExc_ImportError);
+ return NULL;
+}
+
+/*
+ * Vim module - Definitions
+ */
+
+static struct PyMethodDef VimMethods[] = {
+ /* name, function, calling, documentation */
+ {"command", VimCommand, METH_O, "Execute a Vim ex-mode command" },
+ {"eval", VimEval, METH_VARARGS, "Evaluate an expression using Vim evaluator" },
+ {"bindeval", VimEvalPy, METH_O, "Like eval(), but returns objects attached to vim ones"},
+ {"strwidth", VimStrwidth, METH_O, "Screen string width, counts <Tab> as having width 1"},
+ {"chdir", (PyCFunction)VimChdir, METH_VARARGS|METH_KEYWORDS, "Change directory"},
+ {"fchdir", (PyCFunction)VimFchdir, METH_VARARGS|METH_KEYWORDS, "Change directory"},
+ {"foreach_rtp", VimForeachRTP, METH_O, "Call given callable for each path in &rtp"},
+#if PY_VERSION_HEX >= 0x030700f0
+ {"find_spec", FinderFindSpec, METH_VARARGS, "Internal use only, returns spec object for any input it receives"},
+#else
+ {"find_module", FinderFindModule, METH_VARARGS, "Internal use only, returns loader object for any input it receives"},
+#endif
+ {"path_hook", VimPathHook, METH_VARARGS, "Hook function to install in sys.path_hooks"},
+ {"_get_paths", (PyCFunction)Vim_GetPaths, METH_NOARGS, "Get &rtp-based additions to sys.path"},
+ { NULL, NULL, 0, NULL}
+};
+
+/*
+ * Generic iterator object
+ */
+
+static PyTypeObject IterType;
+
+typedef PyObject *(*nextfun)(void **);
+typedef void (*destructorfun)(void *);
+typedef int (*traversefun)(void *, visitproc, void *);
+typedef int (*clearfun)(void **);
+
+/* Main purpose of this object is removing the need for do python
+ * initialization (i.e. PyType_Ready and setting type attributes) for a big
+ * bunch of objects. */
+
+typedef struct
+{
+ PyObject_HEAD
+ void *cur;
+ nextfun next;
+ destructorfun destruct;
+ traversefun traverse;
+ clearfun clear;
+} IterObject;
+
+ static PyObject *
+IterNew(void *start, destructorfun destruct, nextfun next, traversefun traverse,
+ clearfun clear)
+{
+ IterObject *self;
+
+ self = PyObject_GC_New(IterObject, &IterType);
+ self->cur = start;
+ self->next = next;
+ self->destruct = destruct;
+ self->traverse = traverse;
+ self->clear = clear;
+
+ return (PyObject *)(self);
+}
+
+ static void
+IterDestructor(IterObject *self)
+{
+ PyObject_GC_UnTrack((void *)(self));
+ self->destruct(self->cur);
+ PyObject_GC_Del((void *)(self));
+}
+
+ static int
+IterTraverse(IterObject *self, visitproc visit, void *arg)
+{
+ if (self->traverse != NULL)
+ return self->traverse(self->cur, visit, arg);
+ else
+ return 0;
+}
+
+/* Mac OSX defines clear() somewhere. */
+#ifdef clear
+# undef clear
+#endif
+
+ static int
+IterClear(IterObject *self)
+{
+ if (self->clear != NULL)
+ return self->clear(&self->cur);
+ else
+ return 0;
+}
+
+ static PyObject *
+IterNext(IterObject *self)
+{
+ return self->next(&self->cur);
+}
+
+ static PyObject *
+IterIter(PyObject *self)
+{
+ Py_INCREF(self);
+ return self;
+}
+
+typedef struct pylinkedlist_S {
+ struct pylinkedlist_S *pll_next;
+ struct pylinkedlist_S *pll_prev;
+ PyObject *pll_obj;
+} pylinkedlist_T;
+
+static pylinkedlist_T *lastdict = NULL;
+static pylinkedlist_T *lastlist = NULL;
+static pylinkedlist_T *lastfunc = NULL;
+
+ static void
+pyll_remove(pylinkedlist_T *ref, pylinkedlist_T **last)
+{
+ if (ref->pll_prev == NULL)
+ {
+ if (ref->pll_next == NULL)
+ {
+ *last = NULL;
+ return;
+ }
+ }
+ else
+ ref->pll_prev->pll_next = ref->pll_next;
+
+ if (ref->pll_next == NULL)
+ *last = ref->pll_prev;
+ else
+ ref->pll_next->pll_prev = ref->pll_prev;
+}
+
+ static void
+pyll_add(PyObject *self, pylinkedlist_T *ref, pylinkedlist_T **last)
+{
+ if (*last == NULL)
+ ref->pll_prev = NULL;
+ else
+ {
+ (*last)->pll_next = ref;
+ ref->pll_prev = *last;
+ }
+ ref->pll_next = NULL;
+ ref->pll_obj = self;
+ *last = ref;
+}
+
+static PyTypeObject DictionaryType;
+
+typedef struct
+{
+ PyObject_HEAD
+ dict_T *dict;
+ pylinkedlist_T ref;
+} DictionaryObject;
+
+static PyObject *DictionaryUpdate(DictionaryObject *, PyObject *, PyObject *);
+
+#define NEW_DICTIONARY(dict) DictionaryNew(&DictionaryType, dict)
+
+ static PyObject *
+DictionaryNew(PyTypeObject *subtype, dict_T *dict)
+{
+ DictionaryObject *self;
+
+ self = (DictionaryObject *) subtype->tp_alloc(subtype, 0);
+ if (self == NULL)
+ return NULL;
+ self->dict = dict;
+ ++dict->dv_refcount;
+
+ pyll_add((PyObject *)(self), &self->ref, &lastdict);
+
+ return (PyObject *)(self);
+}
+
+ static dict_T *
+py_dict_alloc(void)
+{
+ dict_T *ret;
+
+ if (!(ret = dict_alloc()))
+ {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ ++ret->dv_refcount;
+
+ return ret;
+}
+
+ static PyObject *
+DictionaryConstructor(PyTypeObject *subtype, PyObject *args, PyObject *kwargs)
+{
+ DictionaryObject *self;
+ dict_T *dict;
+
+ if (!(dict = py_dict_alloc()))
+ return NULL;
+
+ self = (DictionaryObject *) DictionaryNew(subtype, dict);
+
+ --dict->dv_refcount;
+
+ if (kwargs || PyTuple_Size(args))
+ {
+ PyObject *tmp;
+ if (!(tmp = DictionaryUpdate(self, args, kwargs)))
+ {
+ Py_DECREF(self);
+ return NULL;
+ }
+
+ Py_DECREF(tmp);
+ }
+
+ return (PyObject *)(self);
+}
+
+ static void
+DictionaryDestructor(DictionaryObject *self)
+{
+ pyll_remove(&self->ref, &lastdict);
+ dict_unref(self->dict);
+
+ DESTRUCTOR_FINISH(self);
+}
+
+static char *DictionaryAttrs[] = {
+ "locked", "scope",
+ NULL
+};
+
+ static PyObject *
+DictionaryDir(PyObject *self)
+{
+ return ObjectDir(self, DictionaryAttrs);
+}
+
+ static int
+DictionarySetattr(DictionaryObject *self, char *name, PyObject *valObject)
+{
+ if (valObject == NULL)
+ {
+ PyErr_SET_STRING(PyExc_AttributeError,
+ N_("cannot delete vim.Dictionary attributes"));
+ return -1;
+ }
+
+ if (strcmp(name, "locked") == 0)
+ {
+ if (self->dict->dv_lock == VAR_FIXED)
+ {
+ PyErr_SET_STRING(PyExc_TypeError,
+ N_("cannot modify fixed dictionary"));
+ return -1;
+ }
+ else
+ {
+ int istrue = PyObject_IsTrue(valObject);
+ if (istrue == -1)
+ return -1;
+ else if (istrue)
+ self->dict->dv_lock = VAR_LOCKED;
+ else
+ self->dict->dv_lock = 0;
+ }
+ return 0;
+ }
+ else
+ {
+ PyErr_FORMAT(PyExc_AttributeError, N_("cannot set attribute %s"), name);
+ return -1;
+ }
+}
+
+ static PyInt
+DictionaryLength(DictionaryObject *self)
+{
+ return ((PyInt) (self->dict->dv_hashtab.ht_used));
+}
+
+#define DICT_FLAG_HAS_DEFAULT 0x01
+#define DICT_FLAG_POP 0x02
+#define DICT_FLAG_NONE_DEFAULT 0x04
+#define DICT_FLAG_RETURN_BOOL 0x08 /* Incompatible with DICT_FLAG_POP */
+#define DICT_FLAG_RETURN_PAIR 0x10
+
+ static PyObject *
+_DictionaryItem(DictionaryObject *self, PyObject *args, int flags)
+{
+ PyObject *keyObject;
+ PyObject *defObject = ((flags & DICT_FLAG_NONE_DEFAULT)? Py_None : NULL);
+ PyObject *ret;
+ char_u *key;
+ dictitem_T *di;
+ dict_T *dict = self->dict;
+ hashitem_T *hi;
+ PyObject *todecref;
+
+ if (flags & DICT_FLAG_HAS_DEFAULT)
+ {
+ if (!PyArg_ParseTuple(args, "O|O", &keyObject, &defObject))
+ return NULL;
+ }
+ else
+ keyObject = args;
+
+ if (flags & DICT_FLAG_RETURN_BOOL)
+ defObject = Py_False;
+
+ if (!(key = StringToChars(keyObject, &todecref)))
+ return NULL;
+
+ if (*key == NUL)
+ {
+ RAISE_NO_EMPTY_KEYS;
+ Py_XDECREF(todecref);
+ return NULL;
+ }
+
+ hi = hash_find(&dict->dv_hashtab, key);
+
+ Py_XDECREF(todecref);
+
+ if (HASHITEM_EMPTY(hi))
+ {
+ if (defObject)
+ {
+ Py_INCREF(defObject);
+ return defObject;
+ }
+ else
+ {
+ PyErr_SetObject(PyExc_KeyError, keyObject);
+ return NULL;
+ }
+ }
+ else if (flags & DICT_FLAG_RETURN_BOOL)
+ {
+ ret = Py_True;
+ Py_INCREF(ret);
+ return ret;
+ }
+
+ di = dict_lookup(hi);
+
+ if (!(ret = ConvertToPyObject(&di->di_tv)))
+ return NULL;
+
+ if (flags & DICT_FLAG_POP)
+ {
+ if (dict->dv_lock)
+ {
+ RAISE_LOCKED_DICTIONARY;
+ Py_DECREF(ret);
+ return NULL;
+ }
+
+ hash_remove(&dict->dv_hashtab, hi);
+ dictitem_free(di);
+ }
+
+ return ret;
+}
+
+ static PyObject *
+DictionaryItem(DictionaryObject *self, PyObject *keyObject)
+{
+ return _DictionaryItem(self, keyObject, 0);
+}
+
+ static int
+DictionaryContains(DictionaryObject *self, PyObject *keyObject)
+{
+ PyObject *rObj = _DictionaryItem(self, keyObject, DICT_FLAG_RETURN_BOOL);
+ int ret;
+
+ if (rObj == NULL)
+ return -1;
+
+ ret = (rObj == Py_True);
+
+ Py_DECREF(rObj);
+
+ return ret;
+}
+
+typedef struct
+{
+ hashitem_T *ht_array;
+ long_u ht_used;
+ hashtab_T *ht;
+ hashitem_T *hi;
+ long_u todo;
+} dictiterinfo_T;
+
+ static PyObject *
+DictionaryIterNext(dictiterinfo_T **dii)
+{
+ PyObject *ret;
+
+ if (!(*dii)->todo)
+ return NULL;
+
+ if ((*dii)->ht->ht_array != (*dii)->ht_array ||
+ (*dii)->ht->ht_used != (*dii)->ht_used)
+ {
+ PyErr_SET_STRING(PyExc_RuntimeError,
+ N_("hashtab changed during iteration"));
+ return NULL;
+ }
+
+ while (((*dii)->todo) && HASHITEM_EMPTY((*dii)->hi))
+ ++((*dii)->hi);
+
+ --((*dii)->todo);
+
+ if (!(ret = PyBytes_FromString((char *)(*dii)->hi->hi_key)))
+ return NULL;
+
+ return ret;
+}
+
+ static PyObject *
+DictionaryIter(DictionaryObject *self)
+{
+ dictiterinfo_T *dii;
+ hashtab_T *ht;
+
+ if (!(dii = PyMem_New(dictiterinfo_T, 1)))
+ {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ ht = &self->dict->dv_hashtab;
+ dii->ht_array = ht->ht_array;
+ dii->ht_used = ht->ht_used;
+ dii->ht = ht;
+ dii->hi = dii->ht_array;
+ dii->todo = dii->ht_used;
+
+ return IterNew(dii,
+ (destructorfun) PyMem_Free, (nextfun) DictionaryIterNext,
+ NULL, NULL);
+}
+
+ static PyInt
+DictionaryAssItem(
+ DictionaryObject *self, PyObject *keyObject, PyObject *valObject)
+{
+ char_u *key;
+ typval_T tv;
+ dict_T *dict = self->dict;
+ dictitem_T *di;
+ PyObject *todecref;
+
+ if (dict->dv_lock)
+ {
+ RAISE_LOCKED_DICTIONARY;
+ return -1;
+ }
+
+ if (!(key = StringToChars(keyObject, &todecref)))
+ return -1;
+
+ if (*key == NUL)
+ {
+ RAISE_NO_EMPTY_KEYS;
+ Py_XDECREF(todecref);
+ return -1;
+ }
+
+ di = dict_find(dict, key, -1);
+
+ if (valObject == NULL)
+ {
+ hashitem_T *hi;
+
+ if (di == NULL)
+ {
+ Py_XDECREF(todecref);
+ PyErr_SetObject(PyExc_KeyError, keyObject);
+ return -1;
+ }
+ hi = hash_find(&dict->dv_hashtab, di->di_key);
+ hash_remove(&dict->dv_hashtab, hi);
+ dictitem_free(di);
+ Py_XDECREF(todecref);
+ return 0;
+ }
+
+ if (ConvertFromPyObject(valObject, &tv) == -1)
+ {
+ Py_XDECREF(todecref);
+ return -1;
+ }
+
+ if (di == NULL)
+ {
+ if (!(di = dictitem_alloc(key)))
+ {
+ Py_XDECREF(todecref);
+ PyErr_NoMemory();
+ return -1;
+ }
+ di->di_tv.v_type = VAR_UNKNOWN;
+
+ if (dict_add(dict, di) == FAIL)
+ {
+ vim_free(di);
+ dictitem_free(di);
+ RAISE_KEY_ADD_FAIL(key);
+ Py_XDECREF(todecref);
+ return -1;
+ }
+ }
+ else
+ clear_tv(&di->di_tv);
+
+ Py_XDECREF(todecref);
+
+ copy_tv(&tv, &di->di_tv);
+ clear_tv(&tv);
+ return 0;
+}
+
+typedef PyObject *(*hi_to_py)(hashitem_T *);
+
+ static PyObject *
+DictionaryListObjects(DictionaryObject *self, hi_to_py hiconvert)
+{
+ dict_T *dict = self->dict;
+ long_u todo = dict->dv_hashtab.ht_used;
+ Py_ssize_t i = 0;
+ PyObject *ret;
+ hashitem_T *hi;
+ PyObject *newObj;
+
+ ret = PyList_New(todo);
+ for (hi = dict->dv_hashtab.ht_array; todo > 0; ++hi)
+ {
+ if (!HASHITEM_EMPTY(hi))
+ {
+ if (!(newObj = hiconvert(hi)))
+ {
+ Py_DECREF(ret);
+ return NULL;
+ }
+ PyList_SET_ITEM(ret, i, newObj);
+ --todo;
+ ++i;
+ }
+ }
+ return ret;
+}
+
+ static PyObject *
+dict_key(hashitem_T *hi)
+{
+ return PyBytes_FromString((char *)(hi->hi_key));
+}
+
+ static PyObject *
+DictionaryListKeys(DictionaryObject *self)
+{
+ return DictionaryListObjects(self, dict_key);
+}
+
+ static PyObject *
+dict_val(hashitem_T *hi)
+{
+ dictitem_T *di;
+
+ di = dict_lookup(hi);
+ return ConvertToPyObject(&di->di_tv);
+}
+
+ static PyObject *
+DictionaryListValues(DictionaryObject *self)
+{
+ return DictionaryListObjects(self, dict_val);
+}
+
+ static PyObject *
+dict_item(hashitem_T *hi)
+{
+ PyObject *keyObject;
+ PyObject *valObject;
+ PyObject *ret;
+
+ if (!(keyObject = dict_key(hi)))
+ return NULL;
+
+ if (!(valObject = dict_val(hi)))
+ {
+ Py_DECREF(keyObject);
+ return NULL;
+ }
+
+ ret = Py_BuildValue("(OO)", keyObject, valObject);
+
+ Py_DECREF(keyObject);
+ Py_DECREF(valObject);
+
+ return ret;
+}
+
+ static PyObject *
+DictionaryListItems(DictionaryObject *self)
+{
+ return DictionaryListObjects(self, dict_item);
+}
+
+ static PyObject *
+DictionaryUpdate(DictionaryObject *self, PyObject *args, PyObject *kwargs)
+{
+ dict_T *dict = self->dict;
+
+ if (dict->dv_lock)
+ {
+ RAISE_LOCKED_DICTIONARY;
+ return NULL;
+ }
+
+ if (kwargs)
+ {
+ typval_T tv;
+
+ if (ConvertFromPyMapping(kwargs, &tv) == -1)
+ return NULL;
+
+ VimTryStart();
+ dict_extend(self->dict, tv.vval.v_dict, (char_u *) "force");
+ clear_tv(&tv);
+ if (VimTryEnd())
+ return NULL;
+ }
+ else
+ {
+ PyObject *obj = NULL;
+
+ if (!PyArg_ParseTuple(args, "|O", &obj))
+ return NULL;
+
+ if (obj == NULL)
+ {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ if (PyObject_HasAttrString(obj, "keys"))
+ return DictionaryUpdate(self, NULL, obj);
+ else
+ {
+ PyObject *iterator;
+ PyObject *item;
+
+ if (!(iterator = PyObject_GetIter(obj)))
+ return NULL;
+
+ while ((item = PyIter_Next(iterator)))
+ {
+ PyObject *fast;
+ PyObject *keyObject;
+ PyObject *valObject;
+ PyObject *todecref;
+ char_u *key;
+ dictitem_T *di;
+ hashitem_T *hi;
+
+ if (!(fast = PySequence_Fast(item, "")))
+ {
+ Py_DECREF(iterator);
+ Py_DECREF(item);
+ return NULL;
+ }
+
+ Py_DECREF(item);
+
+ if (PySequence_Fast_GET_SIZE(fast) != 2)
+ {
+ Py_DECREF(iterator);
+ Py_DECREF(fast);
+ PyErr_FORMAT(PyExc_ValueError,
+ N_("expected sequence element of size 2, "
+ "but got sequence of size %d"),
+ (int) PySequence_Fast_GET_SIZE(fast));
+ return NULL;
+ }
+
+ keyObject = PySequence_Fast_GET_ITEM(fast, 0);
+
+ if (!(key = StringToChars(keyObject, &todecref)))
+ {
+ Py_DECREF(iterator);
+ Py_DECREF(fast);
+ return NULL;
+ }
+
+ di = dictitem_alloc(key);
+
+ Py_XDECREF(todecref);
+
+ if (di == NULL)
+ {
+ Py_DECREF(fast);
+ Py_DECREF(iterator);
+ PyErr_NoMemory();
+ return NULL;
+ }
+ di->di_tv.v_type = VAR_UNKNOWN;
+
+ valObject = PySequence_Fast_GET_ITEM(fast, 1);
+
+ if (ConvertFromPyObject(valObject, &di->di_tv) == -1)
+ {
+ Py_DECREF(iterator);
+ Py_DECREF(fast);
+ dictitem_free(di);
+ return NULL;
+ }
+
+ Py_DECREF(fast);
+
+ hi = hash_find(&dict->dv_hashtab, di->di_key);
+ if (!HASHITEM_EMPTY(hi) || dict_add(dict, di) == FAIL)
+ {
+ RAISE_KEY_ADD_FAIL(di->di_key);
+ Py_DECREF(iterator);
+ dictitem_free(di);
+ return NULL;
+ }
+ }
+
+ Py_DECREF(iterator);
+
+ /* Iterator may have finished due to an exception */
+ if (PyErr_Occurred())
+ return NULL;
+ }
+ }
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+ static PyObject *
+DictionaryGet(DictionaryObject *self, PyObject *args)
+{
+ return _DictionaryItem(self, args,
+ DICT_FLAG_HAS_DEFAULT|DICT_FLAG_NONE_DEFAULT);
+}
+
+ static PyObject *
+DictionaryPop(DictionaryObject *self, PyObject *args)
+{
+ return _DictionaryItem(self, args, DICT_FLAG_HAS_DEFAULT|DICT_FLAG_POP);
+}
+
+ static PyObject *
+DictionaryPopItem(DictionaryObject *self)
+{
+ hashitem_T *hi;
+ PyObject *ret;
+ PyObject *valObject;
+ dictitem_T *di;
+
+ if (self->dict->dv_hashtab.ht_used == 0)
+ {
+ PyErr_SetNone(PyExc_KeyError);
+ return NULL;
+ }
+
+ hi = self->dict->dv_hashtab.ht_array;
+ while (HASHITEM_EMPTY(hi))
+ ++hi;
+
+ di = dict_lookup(hi);
+
+ if (!(valObject = ConvertToPyObject(&di->di_tv)))
+ return NULL;
+
+ if (!(ret = Py_BuildValue("(" Py_bytes_fmt "O)", hi->hi_key, valObject)))
+ {
+ Py_DECREF(valObject);
+ return NULL;
+ }
+
+ hash_remove(&self->dict->dv_hashtab, hi);
+ dictitem_free(di);
+
+ return ret;
+}
+
+ static PyObject *
+DictionaryHasKey(DictionaryObject *self, PyObject *keyObject)
+{
+ return _DictionaryItem(self, keyObject, DICT_FLAG_RETURN_BOOL);
+}
+
+static PySequenceMethods DictionaryAsSeq = {
+ 0, /* sq_length */
+ 0, /* sq_concat */
+ 0, /* sq_repeat */
+ 0, /* sq_item */
+ 0, /* sq_slice */
+ 0, /* sq_ass_item */
+ 0, /* sq_ass_slice */
+ (objobjproc) DictionaryContains, /* sq_contains */
+ 0, /* sq_inplace_concat */
+ 0, /* sq_inplace_repeat */
+};
+
+static PyMappingMethods DictionaryAsMapping = {
+ (lenfunc) DictionaryLength,
+ (binaryfunc) DictionaryItem,
+ (objobjargproc) DictionaryAssItem,
+};
+
+static struct PyMethodDef DictionaryMethods[] = {
+ {"keys", (PyCFunction)DictionaryListKeys, METH_NOARGS, ""},
+ {"values", (PyCFunction)DictionaryListValues, METH_NOARGS, ""},
+ {"items", (PyCFunction)DictionaryListItems, METH_NOARGS, ""},
+ {"update", (PyCFunction)DictionaryUpdate, METH_VARARGS|METH_KEYWORDS, ""},
+ {"get", (PyCFunction)DictionaryGet, METH_VARARGS, ""},
+ {"pop", (PyCFunction)DictionaryPop, METH_VARARGS, ""},
+ {"popitem", (PyCFunction)DictionaryPopItem, METH_NOARGS, ""},
+ {"has_key", (PyCFunction)DictionaryHasKey, METH_O, ""},
+ {"__dir__", (PyCFunction)DictionaryDir, METH_NOARGS, ""},
+ { NULL, NULL, 0, NULL}
+};
+
+static PyTypeObject ListType;
+
+typedef struct
+{
+ PyObject_HEAD
+ list_T *list;
+ pylinkedlist_T ref;
+} ListObject;
+
+#define NEW_LIST(list) ListNew(&ListType, list)
+
+ static PyObject *
+ListNew(PyTypeObject *subtype, list_T *list)
+{
+ ListObject *self;
+
+ self = (ListObject *) subtype->tp_alloc(subtype, 0);
+ if (self == NULL)
+ return NULL;
+ self->list = list;
+ ++list->lv_refcount;
+
+ pyll_add((PyObject *)(self), &self->ref, &lastlist);
+
+ return (PyObject *)(self);
+}
+
+ static list_T *
+py_list_alloc(void)
+{
+ list_T *ret;
+
+ if (!(ret = list_alloc()))
+ {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ ++ret->lv_refcount;
+
+ return ret;
+}
+
+ static int
+list_py_concat(list_T *l, PyObject *obj, PyObject *lookup_dict)
+{
+ PyObject *iterator;
+ PyObject *item;
+ listitem_T *li;
+
+ if (!(iterator = PyObject_GetIter(obj)))
+ return -1;
+
+ while ((item = PyIter_Next(iterator)))
+ {
+ if (!(li = listitem_alloc()))
+ {
+ PyErr_NoMemory();
+ Py_DECREF(item);
+ Py_DECREF(iterator);
+ return -1;
+ }
+ li->li_tv.v_lock = 0;
+ li->li_tv.v_type = VAR_UNKNOWN;
+
+ if (_ConvertFromPyObject(item, &li->li_tv, lookup_dict) == -1)
+ {
+ Py_DECREF(item);
+ Py_DECREF(iterator);
+ listitem_free(li);
+ return -1;
+ }
+
+ Py_DECREF(item);
+
+ list_append(l, li);
+ }
+
+ Py_DECREF(iterator);
+
+ /* Iterator may have finished due to an exception */
+ if (PyErr_Occurred())
+ return -1;
+
+ return 0;
+}
+
+ static PyObject *
+ListConstructor(PyTypeObject *subtype, PyObject *args, PyObject *kwargs)
+{
+ list_T *list;
+ PyObject *obj = NULL;
+
+ if (kwargs)
+ {
+ PyErr_SET_STRING(PyExc_TypeError,
+ N_("list constructor does not accept keyword arguments"));
+ return NULL;
+ }
+
+ if (!PyArg_ParseTuple(args, "|O", &obj))
+ return NULL;
+
+ if (!(list = py_list_alloc()))
+ return NULL;
+
+ if (obj)
+ {
+ PyObject *lookup_dict;
+
+ if (!(lookup_dict = PyDict_New()))
+ {
+ list_unref(list);
+ return NULL;
+ }
+
+ if (list_py_concat(list, obj, lookup_dict) == -1)
+ {
+ Py_DECREF(lookup_dict);
+ list_unref(list);
+ return NULL;
+ }
+
+ Py_DECREF(lookup_dict);
+ }
+
+ return ListNew(subtype, list);
+}
+
+ static void
+ListDestructor(ListObject *self)
+{
+ pyll_remove(&self->ref, &lastlist);
+ list_unref(self->list);
+
+ DESTRUCTOR_FINISH(self);
+}
+
+ static PyInt
+ListLength(ListObject *self)
+{
+ return ((PyInt) (self->list->lv_len));
+}
+
+ static PyObject *
+ListIndex(ListObject *self, Py_ssize_t index)
+{
+ listitem_T *li;
+
+ if (index >= ListLength(self))
+ {
+ PyErr_SET_STRING(PyExc_IndexError, N_("list index out of range"));
+ return NULL;
+ }
+ li = list_find(self->list, (long) index);
+ if (li == NULL)
+ {
+ /* No more suitable format specifications in python-2.3 */
+ PyErr_VIM_FORMAT(N_("internal error: failed to get vim list item %d"),
+ (int) index);
+ return NULL;
+ }
+ return ConvertToPyObject(&li->li_tv);
+}
+
+ static PyObject *
+ListSlice(ListObject *self, Py_ssize_t first, Py_ssize_t step,
+ Py_ssize_t slicelen)
+{
+ PyInt i;
+ PyObject *list;
+
+ if (step == 0)
+ {
+ PyErr_SET_STRING(PyExc_ValueError, N_("slice step cannot be zero"));
+ return NULL;
+ }
+
+ list = PyList_New(slicelen);
+ if (list == NULL)
+ return NULL;
+
+ for (i = 0; i < slicelen; ++i)
+ {
+ PyObject *item;
+
+ item = ListIndex(self, first + i*step);
+ if (item == NULL)
+ {
+ Py_DECREF(list);
+ return NULL;
+ }
+
+ PyList_SET_ITEM(list, i, item);
+ }
+
+ return list;
+}
+
+ static PyObject *
+ListItem(ListObject *self, PyObject* idx)
+{
+#if PY_MAJOR_VERSION < 3
+ if (PyInt_Check(idx))
+ {
+ long _idx = PyInt_AsLong(idx);
+ return ListIndex(self, _idx);
+ }
+ else
+#endif
+ if (PyLong_Check(idx))
+ {
+ long _idx = PyLong_AsLong(idx);
+ return ListIndex(self, _idx);
+ }
+ else if (PySlice_Check(idx))
+ {
+ Py_ssize_t start, stop, step, slicelen;
+
+ if (PySlice_GetIndicesEx((PySliceObject_T *)idx, ListLength(self),
+ &start, &stop, &step, &slicelen) < 0)
+ return NULL;
+ return ListSlice(self, start, step, slicelen);
+ }
+ else
+ {
+ RAISE_INVALID_INDEX_TYPE(idx);
+ return NULL;
+ }
+}
+
+ static void
+list_restore(Py_ssize_t numadded, Py_ssize_t numreplaced, Py_ssize_t slicelen,
+ list_T *l, listitem_T **lis, listitem_T *lastaddedli)
+{
+ while (numreplaced--)
+ {
+ list_insert(l, lis[numreplaced], lis[slicelen + numreplaced]);
+ listitem_remove(l, lis[slicelen + numreplaced]);
+ }
+ while (numadded--)
+ {
+ listitem_T *next;
+
+ next = lastaddedli->li_prev;
+ listitem_remove(l, lastaddedli);
+ lastaddedli = next;
+ }
+}
+
+ static int
+ListAssSlice(ListObject *self, Py_ssize_t first,
+ Py_ssize_t step, Py_ssize_t slicelen, PyObject *obj)
+{
+ PyObject *iterator;
+ PyObject *item;
+ listitem_T *li;
+ listitem_T *lastaddedli = NULL;
+ listitem_T *next;
+ typval_T v;
+ list_T *l = self->list;
+ PyInt i;
+ PyInt j;
+ PyInt numreplaced = 0;
+ PyInt numadded = 0;
+ PyInt size;
+ listitem_T **lis = NULL;
+
+ size = ListLength(self);
+
+ if (l->lv_lock)
+ {
+ RAISE_LOCKED_LIST;
+ return -1;
+ }
+
+ if (step == 0)
+ {
+ PyErr_SET_STRING(PyExc_ValueError, N_("slice step cannot be zero"));
+ return -1;
+ }
+
+ if (step != 1 && slicelen == 0)
+ {
+ /* Nothing to do. Only error out if obj has some items. */
+ int ret = 0;
+
+ if (obj == NULL)
+ return 0;
+
+ if (!(iterator = PyObject_GetIter(obj)))
+ return -1;
+
+ if ((item = PyIter_Next(iterator)))
+ {
+ PyErr_FORMAT(PyExc_ValueError,
+ N_("attempt to assign sequence of size greater than %d "
+ "to extended slice"), 0);
+ Py_DECREF(item);
+ ret = -1;
+ }
+ Py_DECREF(iterator);
+ return ret;
+ }
+
+ if (obj != NULL)
+ /* XXX May allocate zero bytes. */
+ if (!(lis = PyMem_New(listitem_T *, slicelen * 2)))
+ {
+ PyErr_NoMemory();
+ return -1;
+ }
+
+ if (first == size)
+ li = NULL;
+ else
+ {
+ li = list_find(l, (long) first);
+ if (li == NULL)
+ {
+ PyErr_VIM_FORMAT(N_("internal error: no vim list item %d"),
+ (int)first);
+ if (obj != NULL)
+ PyMem_Free(lis);
+ return -1;
+ }
+ i = slicelen;
+ while (i-- && li != NULL)
+ {
+ j = step;
+ next = li;
+ if (step > 0)
+ while (next != NULL && ((next = next->li_next) != NULL) && --j);
+ else
+ while (next != NULL && ((next = next->li_prev) != NULL) && ++j);
+
+ if (obj == NULL)
+ listitem_remove(l, li);
+ else
+ lis[slicelen - i - 1] = li;
+
+ li = next;
+ }
+ if (li == NULL && i != -1)
+ {
+ PyErr_SET_VIM(N_("internal error: not enough list items"));
+ if (obj != NULL)
+ PyMem_Free(lis);
+ return -1;
+ }
+ }
+
+ if (obj == NULL)
+ return 0;
+
+ if (!(iterator = PyObject_GetIter(obj)))
+ {
+ PyMem_Free(lis);
+ return -1;
+ }
+
+ i = 0;
+ while ((item = PyIter_Next(iterator)))
+ {
+ if (ConvertFromPyObject(item, &v) == -1)
+ {
+ Py_DECREF(iterator);
+ Py_DECREF(item);
+ PyMem_Free(lis);
+ return -1;
+ }
+ Py_DECREF(item);
+ if (list_insert_tv(l, &v, numreplaced < slicelen
+ ? lis[numreplaced]
+ : li) == FAIL)
+ {
+ clear_tv(&v);
+ PyErr_SET_VIM(N_("internal error: failed to add item to list"));
+ list_restore(numadded, numreplaced, slicelen, l, lis, lastaddedli);
+ PyMem_Free(lis);
+ return -1;
+ }
+ if (numreplaced < slicelen)
+ {
+ lis[slicelen + numreplaced] = lis[numreplaced]->li_prev;
+ vimlist_remove(l, lis[numreplaced], lis[numreplaced]);
+ numreplaced++;
+ }
+ else
+ {
+ if (li)
+ lastaddedli = li->li_prev;
+ else
+ lastaddedli = l->lv_last;
+ numadded++;
+ }
+ clear_tv(&v);
+ if (step != 1 && i >= slicelen)
+ {
+ Py_DECREF(iterator);
+ PyErr_FORMAT(PyExc_ValueError,
+ N_("attempt to assign sequence of size greater than %d "
+ "to extended slice"), (int) slicelen);
+ list_restore(numadded, numreplaced, slicelen, l, lis, lastaddedli);
+ PyMem_Free(lis);
+ return -1;
+ }
+ ++i;
+ }
+ Py_DECREF(iterator);
+
+ if (step != 1 && i != slicelen)
+ {
+ PyErr_FORMAT2(PyExc_ValueError,
+ N_("attempt to assign sequence of size %d to extended slice "
+ "of size %d"), (int) i, (int) slicelen);
+ list_restore(numadded, numreplaced, slicelen, l, lis, lastaddedli);
+ PyMem_Free(lis);
+ return -1;
+ }
+
+ if (PyErr_Occurred())
+ {
+ list_restore(numadded, numreplaced, slicelen, l, lis, lastaddedli);
+ PyMem_Free(lis);
+ return -1;
+ }
+
+ for (i = 0; i < numreplaced; i++)
+ listitem_free(lis[i]);
+ if (step == 1)
+ for (i = numreplaced; i < slicelen; i++)
+ listitem_remove(l, lis[i]);
+
+ PyMem_Free(lis);
+
+ return 0;
+}
+
+ static int
+ListAssIndex(ListObject *self, Py_ssize_t index, PyObject *obj)
+{
+ typval_T tv;
+ list_T *l = self->list;
+ listitem_T *li;
+ Py_ssize_t length = ListLength(self);
+
+ if (l->lv_lock)
+ {
+ RAISE_LOCKED_LIST;
+ return -1;
+ }
+ if (index > length || (index == length && obj == NULL))
+ {
+ PyErr_SET_STRING(PyExc_IndexError, N_("list index out of range"));
+ return -1;
+ }
+
+ if (obj == NULL)
+ {
+ li = list_find(l, (long) index);
+ vimlist_remove(l, li, li);
+ clear_tv(&li->li_tv);
+ vim_free(li);
+ return 0;
+ }
+
+ if (ConvertFromPyObject(obj, &tv) == -1)
+ return -1;
+
+ if (index == length)
+ {
+ if (list_append_tv(l, &tv) == FAIL)
+ {
+ clear_tv(&tv);
+ PyErr_SET_VIM(N_("failed to add item to list"));
+ return -1;
+ }
+ }
+ else
+ {
+ li = list_find(l, (long) index);
+ clear_tv(&li->li_tv);
+ copy_tv(&tv, &li->li_tv);
+ clear_tv(&tv);
+ }
+ return 0;
+}
+
+ static Py_ssize_t
+ListAssItem(ListObject *self, PyObject *idx, PyObject *obj)
+{
+#if PY_MAJOR_VERSION < 3
+ if (PyInt_Check(idx))
+ {
+ long _idx = PyInt_AsLong(idx);
+ return ListAssIndex(self, _idx, obj);
+ }
+ else
+#endif
+ if (PyLong_Check(idx))
+ {
+ long _idx = PyLong_AsLong(idx);
+ return ListAssIndex(self, _idx, obj);
+ }
+ else if (PySlice_Check(idx))
+ {
+ Py_ssize_t start, stop, step, slicelen;
+
+ if (PySlice_GetIndicesEx((PySliceObject_T *)idx, ListLength(self),
+ &start, &stop, &step, &slicelen) < 0)
+ return -1;
+ return ListAssSlice(self, start, step, slicelen,
+ obj);
+ }
+ else
+ {
+ RAISE_INVALID_INDEX_TYPE(idx);
+ return -1;
+ }
+}
+
+ static PyObject *
+ListConcatInPlace(ListObject *self, PyObject *obj)
+{
+ list_T *l = self->list;
+ PyObject *lookup_dict;
+
+ if (l->lv_lock)
+ {
+ RAISE_LOCKED_LIST;
+ return NULL;
+ }
+
+ if (!(lookup_dict = PyDict_New()))
+ return NULL;
+
+ if (list_py_concat(l, obj, lookup_dict) == -1)
+ {
+ Py_DECREF(lookup_dict);
+ return NULL;
+ }
+ Py_DECREF(lookup_dict);
+
+ Py_INCREF(self);
+ return (PyObject *)(self);
+}
+
+typedef struct
+{
+ listwatch_T lw;
+ list_T *list;
+} listiterinfo_T;
+
+ static void
+ListIterDestruct(listiterinfo_T *lii)
+{
+ list_rem_watch(lii->list, &lii->lw);
+ PyMem_Free(lii);
+}
+
+ static PyObject *
+ListIterNext(listiterinfo_T **lii)
+{
+ PyObject *ret;
+
+ if (!((*lii)->lw.lw_item))
+ return NULL;
+
+ if (!(ret = ConvertToPyObject(&((*lii)->lw.lw_item->li_tv))))
+ return NULL;
+
+ (*lii)->lw.lw_item = (*lii)->lw.lw_item->li_next;
+
+ return ret;
+}
+
+ static PyObject *
+ListIter(ListObject *self)
+{
+ listiterinfo_T *lii;
+ list_T *l = self->list;
+
+ if (!(lii = PyMem_New(listiterinfo_T, 1)))
+ {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ list_add_watch(l, &lii->lw);
+ lii->lw.lw_item = l->lv_first;
+ lii->list = l;
+
+ return IterNew(lii,
+ (destructorfun) ListIterDestruct, (nextfun) ListIterNext,
+ NULL, NULL);
+}
+
+static char *ListAttrs[] = {
+ "locked",
+ NULL
+};
+
+ static PyObject *
+ListDir(PyObject *self)
+{
+ return ObjectDir(self, ListAttrs);
+}
+
+ static int
+ListSetattr(ListObject *self, char *name, PyObject *valObject)
+{
+ if (valObject == NULL)
+ {
+ PyErr_SET_STRING(PyExc_AttributeError,
+ N_("cannot delete vim.List attributes"));
+ return -1;
+ }
+
+ if (strcmp(name, "locked") == 0)
+ {
+ if (self->list->lv_lock == VAR_FIXED)
+ {
+ PyErr_SET_STRING(PyExc_TypeError, N_("cannot modify fixed list"));
+ return -1;
+ }
+ else
+ {
+ int istrue = PyObject_IsTrue(valObject);
+ if (istrue == -1)
+ return -1;
+ else if (istrue)
+ self->list->lv_lock = VAR_LOCKED;
+ else
+ self->list->lv_lock = 0;
+ }
+ return 0;
+ }
+ else
+ {
+ PyErr_FORMAT(PyExc_AttributeError, N_("cannot set attribute %s"), name);
+ return -1;
+ }
+}
+
+static PySequenceMethods ListAsSeq = {
+ (lenfunc) ListLength, /* sq_length, len(x) */
+ (binaryfunc) 0, /* RangeConcat, sq_concat, x+y */
+ 0, /* RangeRepeat, sq_repeat, x*n */
+ (PyIntArgFunc) ListIndex, /* sq_item, x[i] */
+ 0, /* was_sq_slice, x[i:j] */
+ (PyIntObjArgProc) ListAssIndex, /* sq_as_item, x[i]=v */
+ 0, /* was_sq_ass_slice, x[i:j]=v */
+ 0, /* sq_contains */
+ (binaryfunc) ListConcatInPlace,/* sq_inplace_concat */
+ 0, /* sq_inplace_repeat */
+};
+
+static PyMappingMethods ListAsMapping = {
+ /* mp_length */ (lenfunc) ListLength,
+ /* mp_subscript */ (binaryfunc) ListItem,
+ /* mp_ass_subscript */ (objobjargproc) ListAssItem,
+};
+
+static struct PyMethodDef ListMethods[] = {
+ {"extend", (PyCFunction)ListConcatInPlace, METH_O, ""},
+ {"__dir__", (PyCFunction)ListDir, METH_NOARGS, ""},
+ { NULL, NULL, 0, NULL}
+};
+
+typedef struct
+{
+ PyObject_HEAD
+ char_u *name;
+ int argc;
+ typval_T *argv;
+ dict_T *self;
+ pylinkedlist_T ref;
+ int auto_rebind;
+} FunctionObject;
+
+static PyTypeObject FunctionType;
+
+#define NEW_FUNCTION(name, argc, argv, self, pt_auto) \
+ FunctionNew(&FunctionType, (name), (argc), (argv), (self), (pt_auto))
+
+ static PyObject *
+FunctionNew(PyTypeObject *subtype, char_u *name, int argc, typval_T *argv,
+ dict_T *selfdict, int auto_rebind)
+{
+ FunctionObject *self;
+
+ self = (FunctionObject *)subtype->tp_alloc(subtype, 0);
+ if (self == NULL)
+ return NULL;
+
+ if (isdigit(*name))
+ {
+ if (!translated_function_exists(name))
+ {
+ PyErr_FORMAT(PyExc_ValueError,
+ N_("unnamed function %s does not exist"), name);
+ return NULL;
+ }
+ self->name = vim_strsave(name);
+ }
+ else
+ {
+ char_u *p;
+
+ if ((p = get_expanded_name(name,
+ vim_strchr(name, AUTOLOAD_CHAR) == NULL)) == NULL)
+ {
+ PyErr_FORMAT(PyExc_ValueError,
+ N_("function %s does not exist"), name);
+ return NULL;
+ }
+
+ if (p[0] == K_SPECIAL && p[1] == KS_EXTRA && p[2] == (int)KE_SNR)
+ {
+ char_u *np;
+ size_t len = STRLEN(p) + 1;
+
+ if ((np = alloc((int)len + 2)) == NULL)
+ {
+ vim_free(p);
+ return NULL;
+ }
+ mch_memmove(np, "<SNR>", 5);
+ mch_memmove(np + 5, p + 3, len - 3);
+ vim_free(p);
+ self->name = np;
+ }
+ else
+ self->name = p;
+ }
+
+ func_ref(self->name);
+ self->argc = argc;
+ self->argv = argv;
+ self->self = selfdict;
+ self->auto_rebind = selfdict == NULL ? TRUE : auto_rebind;
+
+ if (self->argv || self->self)
+ pyll_add((PyObject *)(self), &self->ref, &lastfunc);
+
+ return (PyObject *)(self);
+}
+
+ static PyObject *
+FunctionConstructor(PyTypeObject *subtype, PyObject *args, PyObject *kwargs)
+{
+ PyObject *self;
+ PyObject *selfdictObject;
+ PyObject *autoRebindObject;
+ PyObject *argsObject = NULL;
+ char_u *name;
+ typval_T selfdicttv;
+ typval_T argstv;
+ list_T *argslist = NULL;
+ dict_T *selfdict = NULL;
+ int argc = 0;
+ int auto_rebind = TRUE;
+ typval_T *argv = NULL;
+ typval_T *curtv;
+ listitem_T *li;
+
+ if (kwargs != NULL)
+ {
+ selfdictObject = PyDict_GetItemString(kwargs, "self");
+ if (selfdictObject != NULL)
+ {
+ if (ConvertFromPyMapping(selfdictObject, &selfdicttv) == -1)
+ return NULL;
+ selfdict = selfdicttv.vval.v_dict;
+ }
+ argsObject = PyDict_GetItemString(kwargs, "args");
+ if (argsObject != NULL)
+ {
+ if (ConvertFromPySequence(argsObject, &argstv) == -1)
+ {
+ dict_unref(selfdict);
+ return NULL;
+ }
+ argslist = argstv.vval.v_list;
+
+ argc = argslist->lv_len;
+ if (argc != 0)
+ {
+ argv = PyMem_New(typval_T, (size_t) argc);
+ if (argv == NULL)
+ {
+ PyErr_NoMemory();
+ dict_unref(selfdict);
+ list_unref(argslist);
+ return NULL;
+ }
+ curtv = argv;
+ for (li = argslist->lv_first; li != NULL; li = li->li_next)
+ copy_tv(&li->li_tv, curtv++);
+ }
+ list_unref(argslist);
+ }
+ if (selfdict != NULL)
+ {
+ auto_rebind = FALSE;
+ autoRebindObject = PyDict_GetItemString(kwargs, "auto_rebind");
+ if (autoRebindObject != NULL)
+ {
+ auto_rebind = PyObject_IsTrue(autoRebindObject);
+ if (auto_rebind == -1)
+ {
+ dict_unref(selfdict);
+ list_unref(argslist);
+ return NULL;
+ }
+ }
+ }
+ }
+
+ if (!PyArg_ParseTuple(args, "et", "ascii", &name))
+ {
+ dict_unref(selfdict);
+ while (argc--)
+ clear_tv(&argv[argc]);
+ PyMem_Free(argv);
+ return NULL;
+ }
+
+ self = FunctionNew(subtype, name, argc, argv, selfdict, auto_rebind);
+
+ PyMem_Free(name);
+
+ return self;
+}
+
+ static void
+FunctionDestructor(FunctionObject *self)
+{
+ int i;
+ func_unref(self->name);
+ vim_free(self->name);
+ for (i = 0; i < self->argc; ++i)
+ clear_tv(&self->argv[i]);
+ PyMem_Free(self->argv);
+ dict_unref(self->self);
+ if (self->argv || self->self)
+ pyll_remove(&self->ref, &lastfunc);
+
+ DESTRUCTOR_FINISH(self);
+}
+
+static char *FunctionAttrs[] = {
+ "softspace", "args", "self", "auto_rebind",
+ NULL
+};
+
+ static PyObject *
+FunctionDir(PyObject *self)
+{
+ return ObjectDir(self, FunctionAttrs);
+}
+
+ static PyObject *
+FunctionAttr(FunctionObject *self, char *name)
+{
+ list_T *list;
+ int i;
+ if (strcmp(name, "name") == 0)
+ return PyString_FromString((char *)(self->name));
+ else if (strcmp(name, "args") == 0)
+ {
+ if (self->argv == NULL || (list = list_alloc()) == NULL)
+ return AlwaysNone(NULL);
+
+ for (i = 0; i < self->argc; ++i)
+ list_append_tv(list, &self->argv[i]);
+ return NEW_LIST(list);
+ }
+ else if (strcmp(name, "self") == 0)
+ return self->self == NULL
+ ? AlwaysNone(NULL)
+ : NEW_DICTIONARY(self->self);
+ else if (strcmp(name, "auto_rebind") == 0)
+ return self->auto_rebind
+ ? AlwaysTrue(NULL)
+ : AlwaysFalse(NULL);
+ else if (strcmp(name, "__members__") == 0)
+ return ObjectDir(NULL, FunctionAttrs);
+ return NULL;
+}
+
+/* Populate partial_T given function object.
+ *
+ * "exported" should be set to true when it is needed to construct a partial
+ * that may be stored in a variable (i.e. may be freed by Vim).
+ */
+ static void
+set_partial(FunctionObject *self, partial_T *pt, int exported)
+{
+ int i;
+
+ pt->pt_name = self->name;
+ if (self->argv)
+ {
+ pt->pt_argc = self->argc;
+ if (exported)
+ {
+ pt->pt_argv = (typval_T *)alloc_clear(
+ sizeof(typval_T) * self->argc);
+ for (i = 0; i < pt->pt_argc; ++i)
+ copy_tv(&self->argv[i], &pt->pt_argv[i]);
+ }
+ else
+ pt->pt_argv = self->argv;
+ }
+ else
+ {
+ pt->pt_argc = 0;
+ pt->pt_argv = NULL;
+ }
+ pt->pt_auto = self->auto_rebind || !exported;
+ pt->pt_dict = self->self;
+ if (exported && self->self)
+ ++pt->pt_dict->dv_refcount;
+ if (exported)
+ pt->pt_name = vim_strsave(pt->pt_name);
+ pt->pt_refcount = 1;
+}
+
+ static PyObject *
+FunctionCall(FunctionObject *self, PyObject *argsObject, PyObject *kwargs)
+{
+ char_u *name = self->name;
+ typval_T args;
+ typval_T selfdicttv;
+ typval_T rettv;
+ dict_T *selfdict = NULL;
+ PyObject *selfdictObject;
+ PyObject *ret;
+ int error;
+ partial_T pt;
+ partial_T *pt_ptr = NULL;
+
+ if (ConvertFromPySequence(argsObject, &args) == -1)
+ return NULL;
+
+ if (kwargs != NULL)
+ {
+ selfdictObject = PyDict_GetItemString(kwargs, "self");
+ if (selfdictObject != NULL)
+ {
+ if (ConvertFromPyMapping(selfdictObject, &selfdicttv) == -1)
+ {
+ clear_tv(&args);
+ return NULL;
+ }
+ selfdict = selfdicttv.vval.v_dict;
+ }
+ }
+
+ if (self->argv || self->self)
+ {
+ vim_memset(&pt, 0, sizeof(partial_T));
+ set_partial(self, &pt, FALSE);
+ pt_ptr = &pt;
+ }
+
+ Py_BEGIN_ALLOW_THREADS
+ Python_Lock_Vim();
+
+ VimTryStart();
+ error = func_call(name, &args, pt_ptr, selfdict, &rettv);
+
+ Python_Release_Vim();
+ Py_END_ALLOW_THREADS
+
+ if (VimTryEnd())
+ ret = NULL;
+ else if (error != OK)
+ {
+ ret = NULL;
+ PyErr_VIM_FORMAT(N_("failed to run function %s"), (char *)name);
+ }
+ else
+ ret = ConvertToPyObject(&rettv);
+
+ clear_tv(&args);
+ clear_tv(&rettv);
+ if (selfdict != NULL)
+ clear_tv(&selfdicttv);
+
+ return ret;
+}
+
+ static PyObject *
+FunctionRepr(FunctionObject *self)
+{
+ PyObject *ret;
+ garray_T repr_ga;
+ int i;
+ char_u *tofree = NULL;
+ typval_T tv;
+ char_u numbuf[NUMBUFLEN];
+
+ ga_init2(&repr_ga, (int)sizeof(char), 70);
+ ga_concat(&repr_ga, (char_u *)"<vim.Function '");
+ if (self->name)
+ ga_concat(&repr_ga, self->name);
+ else
+ ga_concat(&repr_ga, (char_u *)"<NULL>");
+ ga_append(&repr_ga, '\'');
+ if (self->argv)
+ {
+ ga_concat(&repr_ga, (char_u *)", args=[");
+ ++emsg_silent;
+ for (i = 0; i < self->argc; i++)
+ {
+ if (i != 0)
+ ga_concat(&repr_ga, (char_u *)", ");
+ ga_concat(&repr_ga, tv2string(&self->argv[i], &tofree, numbuf,
+ get_copyID()));
+ vim_free(tofree);
+ }
+ --emsg_silent;
+ ga_append(&repr_ga, ']');
+ }
+ if (self->self)
+ {
+ ga_concat(&repr_ga, (char_u *)", self=");
+ tv.v_type = VAR_DICT;
+ tv.vval.v_dict = self->self;
+ ++emsg_silent;
+ ga_concat(&repr_ga, tv2string(&tv, &tofree, numbuf, get_copyID()));
+ --emsg_silent;
+ vim_free(tofree);
+ if (self->auto_rebind)
+ ga_concat(&repr_ga, (char_u *)", auto_rebind=True");
+ }
+ ga_append(&repr_ga, '>');
+ ret = PyString_FromString((char *)repr_ga.ga_data);
+ ga_clear(&repr_ga);
+ return ret;
+}
+
+static struct PyMethodDef FunctionMethods[] = {
+ {"__dir__", (PyCFunction)FunctionDir, METH_NOARGS, ""},
+ { NULL, NULL, 0, NULL}
+};
+
+/*
+ * Options object
+ */
+
+static PyTypeObject OptionsType;
+
+typedef int (*checkfun)(void *);
+
+typedef struct
+{
+ PyObject_HEAD
+ int opt_type;
+ void *from;
+ checkfun Check;
+ PyObject *fromObj;
+} OptionsObject;
+
+ static int
+dummy_check(void *arg UNUSED)
+{
+ return 0;
+}
+
+ static PyObject *
+OptionsNew(int opt_type, void *from, checkfun Check, PyObject *fromObj)
+{
+ OptionsObject *self;
+
+ self = PyObject_GC_New(OptionsObject, &OptionsType);
+ if (self == NULL)
+ return NULL;
+
+ self->opt_type = opt_type;
+ self->from = from;
+ self->Check = Check;
+ self->fromObj = fromObj;
+ if (fromObj)
+ Py_INCREF(fromObj);
+
+ return (PyObject *)(self);
+}
+
+ static void
+OptionsDestructor(OptionsObject *self)
+{
+ PyObject_GC_UnTrack((void *)(self));
+ Py_XDECREF(self->fromObj);
+ PyObject_GC_Del((void *)(self));
+}
+
+ static int
+OptionsTraverse(OptionsObject *self, visitproc visit, void *arg)
+{
+ Py_VISIT(self->fromObj);
+ return 0;
+}
+
+ static int
+OptionsClear(OptionsObject *self)
+{
+ Py_CLEAR(self->fromObj);
+ return 0;
+}
+
+ static PyObject *
+OptionsItem(OptionsObject *self, PyObject *keyObject)
+{
+ char_u *key;
+ int flags;
+ long numval;
+ char_u *stringval;
+ PyObject *todecref;
+
+ if (self->Check(self->from))
+ return NULL;
+
+ if (!(key = StringToChars(keyObject, &todecref)))
+ return NULL;
+
+ if (*key == NUL)
+ {
+ RAISE_NO_EMPTY_KEYS;
+ Py_XDECREF(todecref);
+ return NULL;
+ }
+
+ flags = get_option_value_strict(key, &numval, &stringval,
+ self->opt_type, self->from);
+
+ Py_XDECREF(todecref);
+
+ if (flags == 0)
+ {
+ PyErr_SetObject(PyExc_KeyError, keyObject);
+ return NULL;
+ }
+
+ if (flags & SOPT_UNSET)
+ {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ else if (flags & SOPT_BOOL)
+ {
+ PyObject *ret;
+ ret = numval ? Py_True : Py_False;
+ Py_INCREF(ret);
+ return ret;
+ }
+ else if (flags & SOPT_NUM)
+ return PyInt_FromLong(numval);
+ else if (flags & SOPT_STRING)
+ {
+ if (stringval)
+ {
+ PyObject *ret = PyBytes_FromString((char *)stringval);
+ vim_free(stringval);
+ return ret;
+ }
+ else
+ {
+ PyErr_SET_STRING(PyExc_RuntimeError,
+ N_("unable to get option value"));
+ return NULL;
+ }
+ }
+ else
+ {
+ PyErr_SET_VIM(N_("internal error: unknown option type"));
+ return NULL;
+ }
+}
+
+ static int
+OptionsContains(OptionsObject *self, PyObject *keyObject)
+{
+ char_u *key;
+ PyObject *todecref;
+
+ if (!(key = StringToChars(keyObject, &todecref)))
+ return -1;
+
+ if (*key == NUL)
+ {
+ Py_XDECREF(todecref);
+ return 0;
+ }
+
+ if (get_option_value_strict(key, NULL, NULL, self->opt_type, NULL))
+ {
+ Py_XDECREF(todecref);
+ return 1;
+ }
+ else
+ {
+ Py_XDECREF(todecref);
+ return 0;
+ }
+}
+
+typedef struct
+{
+ void *lastoption;
+ int opt_type;
+} optiterinfo_T;
+
+ static PyObject *
+OptionsIterNext(optiterinfo_T **oii)
+{
+ char_u *name;
+
+ if ((name = option_iter_next(&((*oii)->lastoption), (*oii)->opt_type)))
+ return PyString_FromString((char *)name);
+
+ return NULL;
+}
+
+ static PyObject *
+OptionsIter(OptionsObject *self)
+{
+ optiterinfo_T *oii;
+
+ if (!(oii = PyMem_New(optiterinfo_T, 1)))
+ {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ oii->opt_type = self->opt_type;
+ oii->lastoption = NULL;
+
+ return IterNew(oii,
+ (destructorfun) PyMem_Free, (nextfun) OptionsIterNext,
+ NULL, NULL);
+}
+
+ static int
+set_option_value_err(char_u *key, int numval, char_u *stringval, int opt_flags)
+{
+ char *errmsg;
+
+ if ((errmsg = set_option_value(key, numval, stringval, opt_flags)))
+ {
+ if (VimTryEnd())
+ return FAIL;
+ PyErr_SetVim(errmsg);
+ return FAIL;
+ }
+ return OK;
+}
+
+ static int
+set_option_value_for(
+ char_u *key,
+ int numval,
+ char_u *stringval,
+ int opt_flags,
+ int opt_type,
+ void *from)
+{
+ win_T *save_curwin = NULL;
+ tabpage_T *save_curtab = NULL;
+ bufref_T save_curbuf;
+ int set_ret = 0;
+
+ VimTryStart();
+ switch (opt_type)
+ {
+ case SREQ_WIN:
+ if (switch_win(&save_curwin, &save_curtab, (win_T *)from,
+ win_find_tabpage((win_T *)from), FALSE) == FAIL)
+ {
+ restore_win(save_curwin, save_curtab, TRUE);
+ if (VimTryEnd())
+ return -1;
+ PyErr_SET_VIM(N_("problem while switching windows"));
+ return -1;
+ }
+ set_ret = set_option_value_err(key, numval, stringval, opt_flags);
+ restore_win(save_curwin, save_curtab, TRUE);
+ break;
+ case SREQ_BUF:
+ switch_buffer(&save_curbuf, (buf_T *)from);
+ set_ret = set_option_value_err(key, numval, stringval, opt_flags);
+ restore_buffer(&save_curbuf);
+ break;
+ case SREQ_GLOBAL:
+ set_ret = set_option_value_err(key, numval, stringval, opt_flags);
+ break;
+ }
+ if (set_ret == FAIL)
+ return -1;
+ return VimTryEnd();
+}
+
+ static int
+OptionsAssItem(OptionsObject *self, PyObject *keyObject, PyObject *valObject)
+{
+ char_u *key;
+ int flags;
+ int opt_flags;
+ int ret = 0;
+ PyObject *todecref;
+
+ if (self->Check(self->from))
+ return -1;
+
+ if (!(key = StringToChars(keyObject, &todecref)))
+ return -1;
+
+ if (*key == NUL)
+ {
+ RAISE_NO_EMPTY_KEYS;
+ Py_XDECREF(todecref);
+ return -1;
+ }
+
+ flags = get_option_value_strict(key, NULL, NULL,
+ self->opt_type, self->from);
+
+ if (flags == 0)
+ {
+ PyErr_SetObject(PyExc_KeyError, keyObject);
+ Py_XDECREF(todecref);
+ return -1;
+ }
+
+ if (valObject == NULL)
+ {
+ if (self->opt_type == SREQ_GLOBAL)
+ {
+ PyErr_FORMAT(PyExc_ValueError,
+ N_("unable to unset global option %s"), key);
+ Py_XDECREF(todecref);
+ return -1;
+ }
+ else if (!(flags & SOPT_GLOBAL))
+ {
+ PyErr_FORMAT(PyExc_ValueError,
+ N_("unable to unset option %s "
+ "which does not have global value"), key);
+ Py_XDECREF(todecref);
+ return -1;
+ }
+ else
+ {
+ unset_global_local_option(key, self->from);
+ Py_XDECREF(todecref);
+ return 0;
+ }
+ }
+
+ opt_flags = (self->opt_type ? OPT_LOCAL : OPT_GLOBAL);
+
+ if (flags & SOPT_BOOL)
+ {
+ int istrue = PyObject_IsTrue(valObject);
+
+ if (istrue == -1)
+ ret = -1;
+ else
+ ret = set_option_value_for(key, istrue, NULL,
+ opt_flags, self->opt_type, self->from);
+ }
+ else if (flags & SOPT_NUM)
+ {
+ long val;
+
+ if (NumberToLong(valObject, &val, NUMBER_INT))
+ {
+ Py_XDECREF(todecref);
+ return -1;
+ }
+
+ ret = set_option_value_for(key, (int) val, NULL, opt_flags,
+ self->opt_type, self->from);
+ }
+ else
+ {
+ char_u *val;
+ PyObject *todecref2;
+
+ if ((val = StringToChars(valObject, &todecref2)))
+ {
+ ret = set_option_value_for(key, 0, val, opt_flags,
+ self->opt_type, self->from);
+ Py_XDECREF(todecref2);
+ }
+ else
+ ret = -1;
+ }
+
+ Py_XDECREF(todecref);
+
+ return ret;
+}
+
+static PySequenceMethods OptionsAsSeq = {
+ 0, /* sq_length */
+ 0, /* sq_concat */
+ 0, /* sq_repeat */
+ 0, /* sq_item */
+ 0, /* sq_slice */
+ 0, /* sq_ass_item */
+ 0, /* sq_ass_slice */
+ (objobjproc) OptionsContains, /* sq_contains */
+ 0, /* sq_inplace_concat */
+ 0, /* sq_inplace_repeat */
+};
+
+static PyMappingMethods OptionsAsMapping = {
+ (lenfunc) NULL,
+ (binaryfunc) OptionsItem,
+ (objobjargproc) OptionsAssItem,
+};
+
+/* Tabpage object
+ */
+
+typedef struct
+{
+ PyObject_HEAD
+ tabpage_T *tab;
+} TabPageObject;
+
+static PyObject *WinListNew(TabPageObject *tabObject);
+
+static PyTypeObject TabPageType;
+
+ static int
+CheckTabPage(TabPageObject *self)
+{
+ if (self->tab == INVALID_TABPAGE_VALUE)
+ {
+ PyErr_SET_VIM(N_("attempt to refer to deleted tab page"));
+ return -1;
+ }
+
+ return 0;
+}
+
+ static PyObject *
+TabPageNew(tabpage_T *tab)
+{
+ TabPageObject *self;
+
+ if (TAB_PYTHON_REF(tab))
+ {
+ self = TAB_PYTHON_REF(tab);
+ Py_INCREF(self);
+ }
+ else
+ {
+ self = PyObject_NEW(TabPageObject, &TabPageType);
+ if (self == NULL)
+ return NULL;
+ self->tab = tab;
+ TAB_PYTHON_REF(tab) = self;
+ }
+
+ return (PyObject *)(self);
+}
+
+ static void
+TabPageDestructor(TabPageObject *self)
+{
+ if (self->tab && self->tab != INVALID_TABPAGE_VALUE)
+ TAB_PYTHON_REF(self->tab) = NULL;
+
+ DESTRUCTOR_FINISH(self);
+}
+
+static char *TabPageAttrs[] = {
+ "windows", "number", "vars", "window", "valid",
+ NULL
+};
+
+ static PyObject *
+TabPageDir(PyObject *self)
+{
+ return ObjectDir(self, TabPageAttrs);
+}
+
+ static PyObject *
+TabPageAttrValid(TabPageObject *self, char *name)
+{
+ PyObject *ret;
+
+ if (strcmp(name, "valid") != 0)
+ return NULL;
+
+ ret = ((self->tab == INVALID_TABPAGE_VALUE) ? Py_False : Py_True);
+ Py_INCREF(ret);
+ return ret;
+}
+
+ static PyObject *
+TabPageAttr(TabPageObject *self, char *name)
+{
+ if (strcmp(name, "windows") == 0)
+ return WinListNew(self);
+ else if (strcmp(name, "number") == 0)
+ return PyLong_FromLong((long) get_tab_number(self->tab));
+ else if (strcmp(name, "vars") == 0)
+ return NEW_DICTIONARY(self->tab->tp_vars);
+ else if (strcmp(name, "window") == 0)
+ {
+ /* For current tab window.c does not bother to set or update tp_curwin
+ */
+ if (self->tab == curtab)
+ return WindowNew(curwin, curtab);
+ else
+ return WindowNew(self->tab->tp_curwin, self->tab);
+ }
+ else if (strcmp(name, "__members__") == 0)
+ return ObjectDir(NULL, TabPageAttrs);
+ return NULL;
+}
+
+ static PyObject *
+TabPageRepr(TabPageObject *self)
+{
+ if (self->tab == INVALID_TABPAGE_VALUE)
+ return PyString_FromFormat("<tabpage object (deleted) at %p>", (self));
+ else
+ {
+ int t = get_tab_number(self->tab);
+
+ if (t == 0)
+ return PyString_FromFormat("<tabpage object (unknown) at %p>",
+ (self));
+ else
+ return PyString_FromFormat("<tabpage %d>", t - 1);
+ }
+}
+
+static struct PyMethodDef TabPageMethods[] = {
+ /* name, function, calling, documentation */
+ {"__dir__", (PyCFunction)TabPageDir, METH_NOARGS, ""},
+ { NULL, NULL, 0, NULL}
+};
+
+/*
+ * Window list object
+ */
+
+static PyTypeObject TabListType;
+static PySequenceMethods TabListAsSeq;
+
+typedef struct
+{
+ PyObject_HEAD
+} TabListObject;
+
+ static PyInt
+TabListLength(PyObject *self UNUSED)
+{
+ tabpage_T *tp = first_tabpage;
+ PyInt n = 0;
+
+ while (tp != NULL)
+ {
+ ++n;
+ tp = tp->tp_next;
+ }
+
+ return n;
+}
+
+ static PyObject *
+TabListItem(PyObject *self UNUSED, PyInt n)
+{
+ tabpage_T *tp;
+
+ for (tp = first_tabpage; tp != NULL; tp = tp->tp_next, --n)
+ if (n == 0)
+ return TabPageNew(tp);
+
+ PyErr_SET_STRING(PyExc_IndexError, N_("no such tab page"));
+ return NULL;
+}
+
+/*
+ * Window object
+ */
+
+typedef struct
+{
+ PyObject_HEAD
+ win_T *win;
+ TabPageObject *tabObject;
+} WindowObject;
+
+static PyTypeObject WindowType;
+
+ static int
+CheckWindow(WindowObject *self)
+{
+ if (self->win == INVALID_WINDOW_VALUE)
+ {
+ PyErr_SET_VIM(N_("attempt to refer to deleted window"));
+ return -1;
+ }
+
+ return 0;
+}
+
+ static PyObject *
+WindowNew(win_T *win, tabpage_T *tab)
+{
+ /* We need to handle deletion of windows underneath us.
+ * If we add a "w_python*_ref" field to the win_T structure,
+ * then we can get at it in win_free() in vim. We then
+ * need to create only ONE Python object per window - if
+ * we try to create a second, just INCREF the existing one
+ * and return it. The (single) Python object referring to
+ * the window is stored in "w_python*_ref".
+ * On a win_free() we set the Python object's win_T* field
+ * to an invalid value. We trap all uses of a window
+ * object, and reject them if the win_T* field is invalid.
+ *
+ * Python2 and Python3 get different fields and different objects:
+ * w_python_ref and w_python3_ref fields respectively.
+ */
+
+ WindowObject *self;
+
+ if (WIN_PYTHON_REF(win))
+ {
+ self = WIN_PYTHON_REF(win);
+ Py_INCREF(self);
+ }
+ else
+ {
+ self = PyObject_GC_New(WindowObject, &WindowType);
+ if (self == NULL)
+ return NULL;
+ self->win = win;
+ WIN_PYTHON_REF(win) = self;
+ }
+
+ self->tabObject = ((TabPageObject *)(TabPageNew(tab)));
+
+ return (PyObject *)(self);
+}
+
+ static void
+WindowDestructor(WindowObject *self)
+{
+ PyObject_GC_UnTrack((void *)(self));
+ if (self->win && self->win != INVALID_WINDOW_VALUE)
+ WIN_PYTHON_REF(self->win) = NULL;
+ Py_XDECREF(((PyObject *)(self->tabObject)));
+ PyObject_GC_Del((void *)(self));
+}
+
+ static int
+WindowTraverse(WindowObject *self, visitproc visit, void *arg)
+{
+ Py_VISIT(((PyObject *)(self->tabObject)));
+ return 0;
+}
+
+ static int
+WindowClear(WindowObject *self)
+{
+ Py_CLEAR(self->tabObject);
+ return 0;
+}
+
+ static win_T *
+get_firstwin(TabPageObject *tabObject)
+{
+ if (tabObject)
+ {
+ if (CheckTabPage(tabObject))
+ return NULL;
+ /* For current tab window.c does not bother to set or update tp_firstwin
+ */
+ else if (tabObject->tab == curtab)
+ return firstwin;
+ else
+ return tabObject->tab->tp_firstwin;
+ }
+ else
+ return firstwin;
+}
+
+// Use the same order as in the WindowAttr() function.
+static char *WindowAttrs[] = {
+ "buffer",
+ "cursor",
+ "height",
+ "row",
+ "width",
+ "col",
+ "vars",
+ "options",
+ "number",
+ "tabpage",
+ "valid",
+ NULL
+};
+
+ static PyObject *
+WindowDir(PyObject *self)
+{
+ return ObjectDir(self, WindowAttrs);
+}
+
+ static PyObject *
+WindowAttrValid(WindowObject *self, char *name)
+{
+ PyObject *ret;
+
+ if (strcmp(name, "valid") != 0)
+ return NULL;
+
+ ret = ((self->win == INVALID_WINDOW_VALUE) ? Py_False : Py_True);
+ Py_INCREF(ret);
+ return ret;
+}
+
+ static PyObject *
+WindowAttr(WindowObject *self, char *name)
+{
+ if (strcmp(name, "buffer") == 0)
+ return (PyObject *)BufferNew(self->win->w_buffer);
+ else if (strcmp(name, "cursor") == 0)
+ {
+ pos_T *pos = &self->win->w_cursor;
+
+ return Py_BuildValue("(ll)", (long)(pos->lnum), (long)(pos->col));
+ }
+ else if (strcmp(name, "height") == 0)
+ return PyLong_FromLong((long)(self->win->w_height));
+ else if (strcmp(name, "row") == 0)
+ return PyLong_FromLong((long)(self->win->w_winrow));
+ else if (strcmp(name, "width") == 0)
+ return PyLong_FromLong((long)(self->win->w_width));
+ else if (strcmp(name, "col") == 0)
+ return PyLong_FromLong((long)(self->win->w_wincol));
+ else if (strcmp(name, "vars") == 0)
+ return NEW_DICTIONARY(self->win->w_vars);
+ else if (strcmp(name, "options") == 0)
+ return OptionsNew(SREQ_WIN, self->win, (checkfun) CheckWindow,
+ (PyObject *) self);
+ else if (strcmp(name, "number") == 0)
+ {
+ if (CheckTabPage(self->tabObject))
+ return NULL;
+ return PyLong_FromLong((long)
+ get_win_number(self->win, get_firstwin(self->tabObject)));
+ }
+ else if (strcmp(name, "tabpage") == 0)
+ {
+ Py_INCREF(self->tabObject);
+ return (PyObject *)(self->tabObject);
+ }
+ else if (strcmp(name, "__members__") == 0)
+ return ObjectDir(NULL, WindowAttrs);
+ else
+ return NULL;
+}
+
+ static int
+WindowSetattr(WindowObject *self, char *name, PyObject *valObject)
+{
+ if (CheckWindow(self))
+ return -1;
+
+ if (strcmp(name, "buffer") == 0)
+ {
+ PyErr_SET_STRING(PyExc_TypeError, N_("readonly attribute: buffer"));
+ return -1;
+ }
+ else if (strcmp(name, "cursor") == 0)
+ {
+ long lnum;
+ long col;
+
+ if (!PyArg_Parse(valObject, "(ll)", &lnum, &col))
+ return -1;
+
+ if (lnum <= 0 || lnum > self->win->w_buffer->b_ml.ml_line_count)
+ {
+ PyErr_SET_VIM(N_("cursor position outside buffer"));
+ return -1;
+ }
+
+ /* Check for keyboard interrupts */
+ if (VimCheckInterrupt())
+ return -1;
+
+ self->win->w_cursor.lnum = lnum;
+ self->win->w_cursor.col = col;
+ self->win->w_set_curswant = TRUE;
+ self->win->w_cursor.coladd = 0;
+ /* When column is out of range silently correct it. */
+ check_cursor_col_win(self->win);
+
+ update_screen(VALID);
+ return 0;
+ }
+ else if (strcmp(name, "height") == 0)
+ {
+ long height;
+ win_T *savewin;
+
+ if (NumberToLong(valObject, &height, NUMBER_INT|NUMBER_UNSIGNED))
+ return -1;
+
+#ifdef FEAT_GUI
+ need_mouse_correct = TRUE;
+#endif
+ savewin = curwin;
+ curwin = self->win;
+
+ VimTryStart();
+ win_setheight((int) height);
+ curwin = savewin;
+ if (VimTryEnd())
+ return -1;
+
+ return 0;
+ }
+ else if (strcmp(name, "width") == 0)
+ {
+ long width;
+ win_T *savewin;
+
+ if (NumberToLong(valObject, &width, NUMBER_INT|NUMBER_UNSIGNED))
+ return -1;
+
+#ifdef FEAT_GUI
+ need_mouse_correct = TRUE;
+#endif
+ savewin = curwin;
+ curwin = self->win;
+
+ VimTryStart();
+ win_setwidth((int) width);
+ curwin = savewin;
+ if (VimTryEnd())
+ return -1;
+
+ return 0;
+ }
+ else
+ {
+ PyErr_SetString(PyExc_AttributeError, name);
+ return -1;
+ }
+}
+
+ static PyObject *
+WindowRepr(WindowObject *self)
+{
+ if (self->win == INVALID_WINDOW_VALUE)
+ return PyString_FromFormat("<window object (deleted) at %p>", (self));
+ else
+ {
+ int w = get_win_number(self->win, firstwin);
+
+ if (w == 0)
+ return PyString_FromFormat("<window object (unknown) at %p>",
+ (self));
+ else
+ return PyString_FromFormat("<window %d>", w - 1);
+ }
+}
+
+static struct PyMethodDef WindowMethods[] = {
+ /* name, function, calling, documentation */
+ {"__dir__", (PyCFunction)WindowDir, METH_NOARGS, ""},
+ { NULL, NULL, 0, NULL}
+};
+
+/*
+ * Window list object
+ */
+
+static PyTypeObject WinListType;
+static PySequenceMethods WinListAsSeq;
+
+typedef struct
+{
+ PyObject_HEAD
+ TabPageObject *tabObject;
+} WinListObject;
+
+ static PyObject *
+WinListNew(TabPageObject *tabObject)
+{
+ WinListObject *self;
+
+ self = PyObject_NEW(WinListObject, &WinListType);
+ self->tabObject = tabObject;
+ Py_INCREF(tabObject);
+
+ return (PyObject *)(self);
+}
+
+ static void
+WinListDestructor(WinListObject *self)
+{
+ TabPageObject *tabObject = self->tabObject;
+
+ if (tabObject)
+ {
+ Py_DECREF((PyObject *)(tabObject));
+ }
+
+ DESTRUCTOR_FINISH(self);
+}
+
+ static PyInt
+WinListLength(WinListObject *self)
+{
+ win_T *w;
+ PyInt n = 0;
+
+ if (!(w = get_firstwin(self->tabObject)))
+ return -1;
+
+ while (w != NULL)
+ {
+ ++n;
+ w = W_NEXT(w);
+ }
+
+ return n;
+}
+
+ static PyObject *
+WinListItem(WinListObject *self, PyInt n)
+{
+ win_T *w;
+
+ if (!(w = get_firstwin(self->tabObject)))
+ return NULL;
+
+ for (; w != NULL; w = W_NEXT(w), --n)
+ if (n == 0)
+ return WindowNew(w, self->tabObject? self->tabObject->tab: curtab);
+
+ PyErr_SET_STRING(PyExc_IndexError, N_("no such window"));
+ return NULL;
+}
+
+/* Convert a Python string into a Vim line.
+ *
+ * The result is in allocated memory. All internal nulls are replaced by
+ * newline characters. It is an error for the string to contain newline
+ * characters.
+ *
+ * On errors, the Python exception data is set, and NULL is returned.
+ */
+ static char *
+StringToLine(PyObject *obj)
+{
+ char *str;
+ char *save;
+ PyObject *bytes = NULL;
+ Py_ssize_t len = 0;
+ PyInt i;
+ char *p;
+
+ if (PyBytes_Check(obj))
+ {
+ if (PyBytes_AsStringAndSize(obj, &str, &len) == -1
+ || str == NULL)
+ return NULL;
+ }
+ else if (PyUnicode_Check(obj))
+ {
+ if (!(bytes = PyUnicode_AsEncodedString(obj, ENC_OPT, NULL)))
+ return NULL;
+
+ if (PyBytes_AsStringAndSize(bytes, &str, &len) == -1
+ || str == NULL)
+ {
+ Py_DECREF(bytes);
+ return NULL;
+ }
+ }
+ else
+ {
+#if PY_MAJOR_VERSION < 3
+ PyErr_FORMAT(PyExc_TypeError,
+ N_("expected str() or unicode() instance, but got %s"),
+ Py_TYPE_NAME(obj));
+#else
+ PyErr_FORMAT(PyExc_TypeError,
+ N_("expected bytes() or str() instance, but got %s"),
+ Py_TYPE_NAME(obj));
+#endif
+ return NULL;
+ }
+
+ /*
+ * Error checking: String must not contain newlines, as we
+ * are replacing a single line, and we must replace it with
+ * a single line.
+ * A trailing newline is removed, so that append(f.readlines()) works.
+ */
+ p = memchr(str, '\n', len);
+ if (p != NULL)
+ {
+ if (p == str + len - 1)
+ --len;
+ else
+ {
+ PyErr_SET_VIM(N_("string cannot contain newlines"));
+ Py_XDECREF(bytes);
+ return NULL;
+ }
+ }
+
+ /* Create a copy of the string, with internal nulls replaced by
+ * newline characters, as is the vim convention.
+ */
+ save = (char *)alloc((unsigned)(len+1));
+ if (save == NULL)
+ {
+ PyErr_NoMemory();
+ Py_XDECREF(bytes);
+ return NULL;
+ }
+
+ for (i = 0; i < len; ++i)
+ {
+ if (str[i] == '\0')
+ save[i] = '\n';
+ else
+ save[i] = str[i];
+ }
+
+ save[i] = '\0';
+ Py_XDECREF(bytes); /* Python 2 does nothing here */
+
+ return save;
+}
+
+/* Get a line from the specified buffer. The line number is
+ * in Vim format (1-based). The line is returned as a Python
+ * string object.
+ */
+ static PyObject *
+GetBufferLine(buf_T *buf, PyInt n)
+{
+ return LineToString((char *)ml_get_buf(buf, (linenr_T)n, FALSE));
+}
+
+
+/* Get a list of lines from the specified buffer. The line numbers
+ * are in Vim format (1-based). The range is from lo up to, but not
+ * including, hi. The list is returned as a Python list of string objects.
+ */
+ static PyObject *
+GetBufferLineList(buf_T *buf, PyInt lo, PyInt hi)
+{
+ PyInt i;
+ PyInt n = hi - lo;
+ PyObject *list = PyList_New(n);
+
+ if (list == NULL)
+ return NULL;
+
+ for (i = 0; i < n; ++i)
+ {
+ PyObject *string = LineToString(
+ (char *)ml_get_buf(buf, (linenr_T)(lo+i), FALSE));
+
+ /* Error check - was the Python string creation OK? */
+ if (string == NULL)
+ {
+ Py_DECREF(list);
+ return NULL;
+ }
+
+ PyList_SET_ITEM(list, i, string);
+ }
+
+ /* The ownership of the Python list is passed to the caller (ie,
+ * the caller should Py_DECREF() the object when it is finished
+ * with it).
+ */
+
+ return list;
+}
+
+/*
+ * Check if deleting lines made the cursor position invalid.
+ * Changed the lines from "lo" to "hi" and added "extra" lines (negative if
+ * deleted).
+ */
+ static void
+py_fix_cursor(linenr_T lo, linenr_T hi, linenr_T extra)
+{
+ if (curwin->w_cursor.lnum >= lo)
+ {
+ /* Adjust the cursor position if it's in/after the changed
+ * lines. */
+ if (curwin->w_cursor.lnum >= hi)
+ {
+ curwin->w_cursor.lnum += extra;
+ check_cursor_col();
+ }
+ else if (extra < 0)
+ {
+ curwin->w_cursor.lnum = lo;
+ check_cursor();
+ }
+ else
+ check_cursor_col();
+ changed_cline_bef_curs();
+ }
+ invalidate_botline();
+}
+
+/*
+ * Replace a line in the specified buffer. The line number is
+ * in Vim format (1-based). The replacement line is given as
+ * a Python string object. The object is checked for validity
+ * and correct format. Errors are returned as a value of FAIL.
+ * The return value is OK on success.
+ * If OK is returned and len_change is not NULL, *len_change
+ * is set to the change in the buffer length.
+ */
+ static int
+SetBufferLine(buf_T *buf, PyInt n, PyObject *line, PyInt *len_change)
+{
+ bufref_T save_curbuf = {NULL, 0, 0};
+ win_T *save_curwin = NULL;
+ tabpage_T *save_curtab = NULL;
+
+ /* First of all, we check the type of the supplied Python object.
+ * There are three cases:
+ * 1. NULL, or None - this is a deletion.
+ * 2. A string - this is a replacement.
+ * 3. Anything else - this is an error.
+ */
+ if (line == Py_None || line == NULL)
+ {
+ PyErr_Clear();
+ switch_to_win_for_buf(buf, &save_curwin, &save_curtab, &save_curbuf);
+
+ VimTryStart();
+
+ if (u_savedel((linenr_T)n, 1L) == FAIL)
+ RAISE_UNDO_FAIL;
+ else if (ml_delete((linenr_T)n, FALSE) == FAIL)
+ RAISE_DELETE_LINE_FAIL;
+ else
+ {
+ if (buf == curbuf)
+ py_fix_cursor((linenr_T)n, (linenr_T)n + 1, (linenr_T)-1);
+ if (save_curbuf.br_buf == NULL)
+ /* Only adjust marks if we managed to switch to a window that
+ * holds the buffer, otherwise line numbers will be invalid. */
+ deleted_lines_mark((linenr_T)n, 1L);
+ }
+
+ restore_win_for_buf(save_curwin, save_curtab, &save_curbuf);
+
+ if (VimTryEnd())
+ return FAIL;
+
+ if (len_change)
+ *len_change = -1;
+
+ return OK;
+ }
+ else if (PyBytes_Check(line) || PyUnicode_Check(line))
+ {
+ char *save = StringToLine(line);
+
+ if (save == NULL)
+ return FAIL;
+
+ VimTryStart();
+
+ /* We do not need to free "save" if ml_replace() consumes it. */
+ PyErr_Clear();
+ switch_to_win_for_buf(buf, &save_curwin, &save_curtab, &save_curbuf);
+
+ if (u_savesub((linenr_T)n) == FAIL)
+ {
+ RAISE_UNDO_FAIL;
+ vim_free(save);
+ }
+ else if (ml_replace((linenr_T)n, (char_u *)save, FALSE) == FAIL)
+ {
+ RAISE_REPLACE_LINE_FAIL;
+ vim_free(save);
+ }
+ else
+ changed_bytes((linenr_T)n, 0);
+
+ restore_win_for_buf(save_curwin, save_curtab, &save_curbuf);
+
+ /* Check that the cursor is not beyond the end of the line now. */
+ if (buf == curbuf)
+ check_cursor_col();
+
+ if (VimTryEnd())
+ return FAIL;
+
+ if (len_change)
+ *len_change = 0;
+
+ return OK;
+ }
+ else
+ {
+ PyErr_BadArgument();
+ return FAIL;
+ }
+}
+
+/* Replace a range of lines in the specified buffer. The line numbers are in
+ * Vim format (1-based). The range is from lo up to, but not including, hi.
+ * The replacement lines are given as a Python list of string objects. The
+ * list is checked for validity and correct format. Errors are returned as a
+ * value of FAIL. The return value is OK on success.
+ * If OK is returned and len_change is not NULL, *len_change
+ * is set to the change in the buffer length.
+ */
+ static int
+SetBufferLineList(
+ buf_T *buf,
+ PyInt lo,
+ PyInt hi,
+ PyObject *list,
+ PyInt *len_change)
+{
+ bufref_T save_curbuf = {NULL, 0, 0};
+ win_T *save_curwin = NULL;
+ tabpage_T *save_curtab = NULL;
+
+ /* First of all, we check the type of the supplied Python object.
+ * There are three cases:
+ * 1. NULL, or None - this is a deletion.
+ * 2. A list - this is a replacement.
+ * 3. Anything else - this is an error.
+ */
+ if (list == Py_None || list == NULL)
+ {
+ PyInt i;
+ PyInt n = (int)(hi - lo);
+
+ PyErr_Clear();
+ VimTryStart();
+ switch_to_win_for_buf(buf, &save_curwin, &save_curtab, &save_curbuf);
+
+ if (u_savedel((linenr_T)lo, (long)n) == FAIL)
+ RAISE_UNDO_FAIL;
+ else
+ {
+ for (i = 0; i < n; ++i)
+ {
+ if (ml_delete((linenr_T)lo, FALSE) == FAIL)
+ {
+ RAISE_DELETE_LINE_FAIL;
+ break;
+ }
+ }
+ if (buf == curbuf && (save_curwin != NULL
+ || save_curbuf.br_buf == NULL))
+ /* Using an existing window for the buffer, adjust the cursor
+ * position. */
+ py_fix_cursor((linenr_T)lo, (linenr_T)hi, (linenr_T)-n);
+ if (save_curbuf.br_buf == NULL)
+ /* Only adjust marks if we managed to switch to a window that
+ * holds the buffer, otherwise line numbers will be invalid. */
+ deleted_lines_mark((linenr_T)lo, (long)i);
+ }
+
+ restore_win_for_buf(save_curwin, save_curtab, &save_curbuf);
+
+ if (VimTryEnd())
+ return FAIL;
+
+ if (len_change)
+ *len_change = -n;
+
+ return OK;
+ }
+ else if (PyList_Check(list))
+ {
+ PyInt i;
+ PyInt new_len = PyList_Size(list);
+ PyInt old_len = hi - lo;
+ PyInt extra = 0; /* lines added to text, can be negative */
+ char **array;
+
+ if (new_len == 0) /* avoid allocating zero bytes */
+ array = NULL;
+ else
+ {
+ array = PyMem_New(char *, new_len);
+ if (array == NULL)
+ {
+ PyErr_NoMemory();
+ return FAIL;
+ }
+ }
+
+ for (i = 0; i < new_len; ++i)
+ {
+ PyObject *line;
+
+ if (!(line = PyList_GetItem(list, i)) ||
+ !(array[i] = StringToLine(line)))
+ {
+ while (i)
+ vim_free(array[--i]);
+ PyMem_Free(array);
+ return FAIL;
+ }
+ }
+
+ VimTryStart();
+ PyErr_Clear();
+
+ /* START of region without "return". Must call restore_buffer()! */
+ switch_to_win_for_buf(buf, &save_curwin, &save_curtab, &save_curbuf);
+
+ if (u_save((linenr_T)(lo-1), (linenr_T)hi) == FAIL)
+ RAISE_UNDO_FAIL;
+
+ /* If the size of the range is reducing (ie, new_len < old_len) we
+ * need to delete some old_len. We do this at the start, by
+ * repeatedly deleting line "lo".
+ */
+ if (!PyErr_Occurred())
+ {
+ for (i = 0; i < old_len - new_len; ++i)
+ if (ml_delete((linenr_T)lo, FALSE) == FAIL)
+ {
+ RAISE_DELETE_LINE_FAIL;
+ break;
+ }
+ extra -= i;
+ }
+
+ /* For as long as possible, replace the existing old_len with the
+ * new old_len. This is a more efficient operation, as it requires
+ * less memory allocation and freeing.
+ */
+ if (!PyErr_Occurred())
+ {
+ for (i = 0; i < old_len && i < new_len; ++i)
+ if (ml_replace((linenr_T)(lo+i), (char_u *)array[i], FALSE)
+ == FAIL)
+ {
+ RAISE_REPLACE_LINE_FAIL;
+ break;
+ }
+ }
+ else
+ i = 0;
+
+ /* Now we may need to insert the remaining new old_len. If we do, we
+ * must free the strings as we finish with them (we can't pass the
+ * responsibility to vim in this case).
+ */
+ if (!PyErr_Occurred())
+ {
+ while (i < new_len)
+ {
+ if (ml_append((linenr_T)(lo + i - 1),
+ (char_u *)array[i], 0, FALSE) == FAIL)
+ {
+ RAISE_INSERT_LINE_FAIL;
+ break;
+ }
+ vim_free(array[i]);
+ ++i;
+ ++extra;
+ }
+ }
+
+ /* Free any left-over old_len, as a result of an error */
+ while (i < new_len)
+ {
+ vim_free(array[i]);
+ ++i;
+ }
+
+ /* Free the array of old_len. All of its contents have now
+ * been dealt with (either freed, or the responsibility passed
+ * to vim.
+ */
+ PyMem_Free(array);
+
+ /* Adjust marks. Invalidate any which lie in the
+ * changed range, and move any in the remainder of the buffer.
+ * Only adjust marks if we managed to switch to a window that holds
+ * the buffer, otherwise line numbers will be invalid. */
+ if (save_curbuf.br_buf == NULL)
+ mark_adjust((linenr_T)lo, (linenr_T)(hi - 1),
+ (long)MAXLNUM, (long)extra);
+ changed_lines((linenr_T)lo, 0, (linenr_T)hi, (long)extra);
+
+ if (buf == curbuf)
+ py_fix_cursor((linenr_T)lo, (linenr_T)hi, (linenr_T)extra);
+
+ /* END of region without "return". */
+ restore_win_for_buf(save_curwin, save_curtab, &save_curbuf);
+
+ if (VimTryEnd())
+ return FAIL;
+
+ if (len_change)
+ *len_change = new_len - old_len;
+
+ return OK;
+ }
+ else
+ {
+ PyErr_BadArgument();
+ return FAIL;
+ }
+}
+
+/* Insert a number of lines into the specified buffer after the specified line.
+ * The line number is in Vim format (1-based). The lines to be inserted are
+ * given as a Python list of string objects or as a single string. The lines
+ * to be added are checked for validity and correct format. Errors are
+ * returned as a value of FAIL. The return value is OK on success.
+ * If OK is returned and len_change is not NULL, *len_change
+ * is set to the change in the buffer length.
+ */
+ static int
+InsertBufferLines(buf_T *buf, PyInt n, PyObject *lines, PyInt *len_change)
+{
+ bufref_T save_curbuf = {NULL, 0, 0};
+ win_T *save_curwin = NULL;
+ tabpage_T *save_curtab = NULL;
+
+ /* First of all, we check the type of the supplied Python object.
+ * It must be a string or a list, or the call is in error.
+ */
+ if (PyBytes_Check(lines) || PyUnicode_Check(lines))
+ {
+ char *str = StringToLine(lines);
+
+ if (str == NULL)
+ return FAIL;
+
+ PyErr_Clear();
+ VimTryStart();
+ switch_to_win_for_buf(buf, &save_curwin, &save_curtab, &save_curbuf);
+
+ if (u_save((linenr_T)n, (linenr_T)(n + 1)) == FAIL)
+ RAISE_UNDO_FAIL;
+ else if (ml_append((linenr_T)n, (char_u *)str, 0, FALSE) == FAIL)
+ RAISE_INSERT_LINE_FAIL;
+ else if (save_curbuf.br_buf == NULL)
+ /* Only adjust marks if we managed to switch to a window that
+ * holds the buffer, otherwise line numbers will be invalid. */
+ appended_lines_mark((linenr_T)n, 1L);
+
+ vim_free(str);
+ restore_win_for_buf(save_curwin, save_curtab, &save_curbuf);
+ update_screen(VALID);
+
+ if (VimTryEnd())
+ return FAIL;
+
+ if (len_change)
+ *len_change = 1;
+
+ return OK;
+ }
+ else if (PyList_Check(lines))
+ {
+ PyInt i;
+ PyInt size = PyList_Size(lines);
+ char **array;
+
+ array = PyMem_New(char *, size);
+ if (array == NULL)
+ {
+ PyErr_NoMemory();
+ return FAIL;
+ }
+
+ for (i = 0; i < size; ++i)
+ {
+ PyObject *line;
+
+ if (!(line = PyList_GetItem(lines, i)) ||
+ !(array[i] = StringToLine(line)))
+ {
+ while (i)
+ vim_free(array[--i]);
+ PyMem_Free(array);
+ return FAIL;
+ }
+ }
+
+ PyErr_Clear();
+ VimTryStart();
+ switch_to_win_for_buf(buf, &save_curwin, &save_curtab, &save_curbuf);
+
+ if (u_save((linenr_T)n, (linenr_T)(n + 1)) == FAIL)
+ RAISE_UNDO_FAIL;
+ else
+ {
+ for (i = 0; i < size; ++i)
+ {
+ if (ml_append((linenr_T)(n + i),
+ (char_u *)array[i], 0, FALSE) == FAIL)
+ {
+ RAISE_INSERT_LINE_FAIL;
+
+ /* Free the rest of the lines */
+ while (i < size)
+ vim_free(array[i++]);
+
+ break;
+ }
+ vim_free(array[i]);
+ }
+ if (i > 0 && save_curbuf.br_buf == NULL)
+ /* Only adjust marks if we managed to switch to a window that
+ * holds the buffer, otherwise line numbers will be invalid. */
+ appended_lines_mark((linenr_T)n, (long)i);
+ }
+
+ /* Free the array of lines. All of its contents have now
+ * been freed. */
+ PyMem_Free(array);
+ restore_win_for_buf(save_curwin, save_curtab, &save_curbuf);
+
+ update_screen(VALID);
+
+ if (VimTryEnd())
+ return FAIL;
+
+ if (len_change)
+ *len_change = size;
+
+ return OK;
+ }
+ else
+ {
+ PyErr_BadArgument();
+ return FAIL;
+ }
+}
+
+/*
+ * Common routines for buffers and line ranges
+ * -------------------------------------------
+ */
+
+typedef struct
+{
+ PyObject_HEAD
+ buf_T *buf;
+} BufferObject;
+
+ static int
+CheckBuffer(BufferObject *self)
+{
+ if (self->buf == INVALID_BUFFER_VALUE)
+ {
+ PyErr_SET_VIM(N_("attempt to refer to deleted buffer"));
+ return -1;
+ }
+
+ return 0;
+}
+
+ static PyObject *
+RBItem(BufferObject *self, PyInt n, PyInt start, PyInt end)
+{
+ if (CheckBuffer(self))
+ return NULL;
+
+ if (end == -1)
+ end = self->buf->b_ml.ml_line_count;
+
+ if (n < 0)
+ n += end - start + 1;
+
+ if (n < 0 || n > end - start)
+ {
+ PyErr_SET_STRING(PyExc_IndexError, N_("line number out of range"));
+ return NULL;
+ }
+
+ return GetBufferLine(self->buf, n+start);
+}
+
+ static PyObject *
+RBSlice(BufferObject *self, PyInt lo, PyInt hi, PyInt start, PyInt end)
+{
+ PyInt size;
+
+ if (CheckBuffer(self))
+ return NULL;
+
+ if (end == -1)
+ end = self->buf->b_ml.ml_line_count;
+
+ size = end - start + 1;
+
+ if (lo < 0)
+ lo = 0;
+ else if (lo > size)
+ lo = size;
+ if (hi < 0)
+ hi = 0;
+ if (hi < lo)
+ hi = lo;
+ else if (hi > size)
+ hi = size;
+
+ return GetBufferLineList(self->buf, lo+start, hi+start);
+}
+
+ static PyInt
+RBAsItem(
+ BufferObject *self,
+ PyInt n,
+ PyObject *valObject,
+ PyInt start,
+ PyInt end,
+ PyInt *new_end)
+{
+ PyInt len_change;
+
+ if (CheckBuffer(self))
+ return -1;
+
+ if (end == -1)
+ end = self->buf->b_ml.ml_line_count;
+
+ if (n < 0)
+ n += end - start + 1;
+
+ if (n < 0 || n > end - start)
+ {
+ PyErr_SET_STRING(PyExc_IndexError, N_("line number out of range"));
+ return -1;
+ }
+
+ if (SetBufferLine(self->buf, n+start, valObject, &len_change) == FAIL)
+ return -1;
+
+ if (new_end)
+ *new_end = end + len_change;
+
+ return 0;
+}
+
+ static PyInt
+RBAsSlice(
+ BufferObject *self,
+ PyInt lo,
+ PyInt hi,
+ PyObject *valObject,
+ PyInt start,
+ PyInt end,
+ PyInt *new_end)
+{
+ PyInt size;
+ PyInt len_change;
+
+ /* Self must be a valid buffer */
+ if (CheckBuffer(self))
+ return -1;
+
+ if (end == -1)
+ end = self->buf->b_ml.ml_line_count;
+
+ /* Sort out the slice range */
+ size = end - start + 1;
+
+ if (lo < 0)
+ lo = 0;
+ else if (lo > size)
+ lo = size;
+ if (hi < 0)
+ hi = 0;
+ if (hi < lo)
+ hi = lo;
+ else if (hi > size)
+ hi = size;
+
+ if (SetBufferLineList(self->buf, lo + start, hi + start,
+ valObject, &len_change) == FAIL)
+ return -1;
+
+ if (new_end)
+ *new_end = end + len_change;
+
+ return 0;
+}
+
+
+ static PyObject *
+RBAppend(
+ BufferObject *self,
+ PyObject *args,
+ PyInt start,
+ PyInt end,
+ PyInt *new_end)
+{
+ PyObject *lines;
+ PyInt len_change;
+ PyInt max;
+ PyInt n;
+
+ if (CheckBuffer(self))
+ return NULL;
+
+ if (end == -1)
+ end = self->buf->b_ml.ml_line_count;
+
+ max = n = end - start + 1;
+
+ if (!PyArg_ParseTuple(args, "O|n", &lines, &n))
+ return NULL;
+
+ if (n < 0 || n > max)
+ {
+ PyErr_SET_STRING(PyExc_IndexError, N_("line number out of range"));
+ return NULL;
+ }
+
+ if (InsertBufferLines(self->buf, n + start - 1, lines, &len_change) == FAIL)
+ return NULL;
+
+ if (new_end)
+ *new_end = end + len_change;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+/* Range object
+ */
+
+static PyTypeObject RangeType;
+static PySequenceMethods RangeAsSeq;
+static PyMappingMethods RangeAsMapping;
+
+typedef struct
+{
+ PyObject_HEAD
+ BufferObject *buf;
+ PyInt start;
+ PyInt end;
+} RangeObject;
+
+ static PyObject *
+RangeNew(buf_T *buf, PyInt start, PyInt end)
+{
+ BufferObject *bufr;
+ RangeObject *self;
+ self = PyObject_GC_New(RangeObject, &RangeType);
+ if (self == NULL)
+ return NULL;
+
+ bufr = (BufferObject *)BufferNew(buf);
+ if (bufr == NULL)
+ {
+ Py_DECREF(self);
+ return NULL;
+ }
+ Py_INCREF(bufr);
+
+ self->buf = bufr;
+ self->start = start;
+ self->end = end;
+
+ return (PyObject *)(self);
+}
+
+ static void
+RangeDestructor(RangeObject *self)
+{
+ PyObject_GC_UnTrack((void *)(self));
+ Py_XDECREF(self->buf);
+ PyObject_GC_Del((void *)(self));
+}
+
+ static int
+RangeTraverse(RangeObject *self, visitproc visit, void *arg)
+{
+ Py_VISIT(((PyObject *)(self->buf)));
+ return 0;
+}
+
+ static int
+RangeClear(RangeObject *self)
+{
+ Py_CLEAR(self->buf);
+ return 0;
+}
+
+ static PyInt
+RangeLength(RangeObject *self)
+{
+ /* HOW DO WE SIGNAL AN ERROR FROM THIS FUNCTION? */
+ if (CheckBuffer(self->buf))
+ return -1; /* ??? */
+
+ return (self->end - self->start + 1);
+}
+
+ static PyObject *
+RangeItem(RangeObject *self, PyInt n)
+{
+ return RBItem(self->buf, n, self->start, self->end);
+}
+
+ static PyObject *
+RangeSlice(RangeObject *self, PyInt lo, PyInt hi)
+{
+ return RBSlice(self->buf, lo, hi, self->start, self->end);
+}
+
+static char *RangeAttrs[] = {
+ "start", "end",
+ NULL
+};
+
+ static PyObject *
+RangeDir(PyObject *self)
+{
+ return ObjectDir(self, RangeAttrs);
+}
+
+ static PyObject *
+RangeAppend(RangeObject *self, PyObject *args)
+{
+ return RBAppend(self->buf, args, self->start, self->end, &self->end);
+}
+
+ static PyObject *
+RangeRepr(RangeObject *self)
+{
+ if (self->buf->buf == INVALID_BUFFER_VALUE)
+ return PyString_FromFormat("<range object (for deleted buffer) at %p>",
+ (self));
+ else
+ {
+ char *name = (char *)self->buf->buf->b_fname;
+
+ if (name == NULL)
+ name = "";
+
+ return PyString_FromFormat("<range %s (%d:%d)>",
+ name, (int)self->start, (int)self->end);
+ }
+}
+
+static struct PyMethodDef RangeMethods[] = {
+ /* name, function, calling, documentation */
+ {"append", (PyCFunction)RangeAppend, METH_VARARGS, "Append data to the Vim range" },
+ {"__dir__", (PyCFunction)RangeDir, METH_NOARGS, ""},
+ { NULL, NULL, 0, NULL}
+};
+
+static PyTypeObject BufferType;
+static PySequenceMethods BufferAsSeq;
+static PyMappingMethods BufferAsMapping;
+
+ static PyObject *
+BufferNew(buf_T *buf)
+{
+ /* We need to handle deletion of buffers underneath us.
+ * If we add a "b_python*_ref" field to the buf_T structure,
+ * then we can get at it in buf_freeall() in vim. We then
+ * need to create only ONE Python object per buffer - if
+ * we try to create a second, just INCREF the existing one
+ * and return it. The (single) Python object referring to
+ * the buffer is stored in "b_python*_ref".
+ * Question: what to do on a buf_freeall(). We'll probably
+ * have to either delete the Python object (DECREF it to
+ * zero - a bad idea, as it leaves dangling refs!) or
+ * set the buf_T * value to an invalid value (-1?), which
+ * means we need checks in all access functions... Bah.
+ *
+ * Python2 and Python3 get different fields and different objects:
+ * b_python_ref and b_python3_ref fields respectively.
+ */
+
+ BufferObject *self;
+
+ if (BUF_PYTHON_REF(buf) != NULL)
+ {
+ self = BUF_PYTHON_REF(buf);
+ Py_INCREF(self);
+ }
+ else
+ {
+ self = PyObject_NEW(BufferObject, &BufferType);
+ if (self == NULL)
+ return NULL;
+ self->buf = buf;
+ BUF_PYTHON_REF(buf) = self;
+ }
+
+ return (PyObject *)(self);
+}
+
+ static void
+BufferDestructor(BufferObject *self)
+{
+ if (self->buf && self->buf != INVALID_BUFFER_VALUE)
+ BUF_PYTHON_REF(self->buf) = NULL;
+
+ DESTRUCTOR_FINISH(self);
+}
+
+ static PyInt
+BufferLength(BufferObject *self)
+{
+ /* HOW DO WE SIGNAL AN ERROR FROM THIS FUNCTION? */
+ if (CheckBuffer(self))
+ return -1; /* ??? */
+
+ return (PyInt)(self->buf->b_ml.ml_line_count);
+}
+
+ static PyObject *
+BufferItem(BufferObject *self, PyInt n)
+{
+ return RBItem(self, n, 1, -1);
+}
+
+ static PyObject *
+BufferSlice(BufferObject *self, PyInt lo, PyInt hi)
+{
+ return RBSlice(self, lo, hi, 1, -1);
+}
+
+static char *BufferAttrs[] = {
+ "name", "number", "vars", "options", "valid",
+ NULL
+};
+
+ static PyObject *
+BufferDir(PyObject *self)
+{
+ return ObjectDir(self, BufferAttrs);
+}
+
+ static PyObject *
+BufferAttrValid(BufferObject *self, char *name)
+{
+ PyObject *ret;
+
+ if (strcmp(name, "valid") != 0)
+ return NULL;
+
+ ret = ((self->buf == INVALID_BUFFER_VALUE) ? Py_False : Py_True);
+ Py_INCREF(ret);
+ return ret;
+}
+
+ static PyObject *
+BufferAttr(BufferObject *self, char *name)
+{
+ if (strcmp(name, "name") == 0)
+ return PyString_FromString((self->buf->b_ffname == NULL
+ ? "" : (char *)self->buf->b_ffname));
+ else if (strcmp(name, "number") == 0)
+ return Py_BuildValue(Py_ssize_t_fmt, self->buf->b_fnum);
+ else if (strcmp(name, "vars") == 0)
+ return NEW_DICTIONARY(self->buf->b_vars);
+ else if (strcmp(name, "options") == 0)
+ return OptionsNew(SREQ_BUF, self->buf, (checkfun) CheckBuffer,
+ (PyObject *) self);
+ else if (strcmp(name, "__members__") == 0)
+ return ObjectDir(NULL, BufferAttrs);
+ else
+ return NULL;
+}
+
+ static int
+BufferSetattr(BufferObject *self, char *name, PyObject *valObject)
+{
+ if (CheckBuffer(self))
+ return -1;
+
+ if (strcmp(name, "name") == 0)
+ {
+ char_u *val;
+ aco_save_T aco;
+ int ren_ret;
+ PyObject *todecref;
+
+ if (!(val = StringToChars(valObject, &todecref)))
+ return -1;
+
+ VimTryStart();
+ /* Using aucmd_*: autocommands will be executed by rename_buffer */
+ aucmd_prepbuf(&aco, self->buf);
+ ren_ret = rename_buffer(val);
+ aucmd_restbuf(&aco);
+ Py_XDECREF(todecref);
+ if (VimTryEnd())
+ return -1;
+
+ if (ren_ret == FAIL)
+ {
+ PyErr_SET_VIM(N_("failed to rename buffer"));
+ return -1;
+ }
+ return 0;
+ }
+ else
+ {
+ PyErr_SetString(PyExc_AttributeError, name);
+ return -1;
+ }
+}
+
+ static PyObject *
+BufferAppend(BufferObject *self, PyObject *args)
+{
+ return RBAppend(self, args, 1, -1, NULL);
+}
+
+ static PyObject *
+BufferMark(BufferObject *self, PyObject *pmarkObject)
+{
+ pos_T *posp;
+ char_u *pmark;
+ char_u mark;
+ bufref_T savebuf;
+ PyObject *todecref;
+
+ if (CheckBuffer(self))
+ return NULL;
+
+ if (!(pmark = StringToChars(pmarkObject, &todecref)))
+ return NULL;
+
+ if (pmark[0] == '\0' || pmark[1] != '\0')
+ {
+ PyErr_SET_STRING(PyExc_ValueError,
+ N_("mark name must be a single character"));
+ Py_XDECREF(todecref);
+ return NULL;
+ }
+
+ mark = *pmark;
+
+ Py_XDECREF(todecref);
+
+ VimTryStart();
+ switch_buffer(&savebuf, self->buf);
+ posp = getmark(mark, FALSE);
+ restore_buffer(&savebuf);
+ if (VimTryEnd())
+ return NULL;
+
+ if (posp == NULL)
+ {
+ PyErr_SET_VIM(N_("invalid mark name"));
+ return NULL;
+ }
+
+ if (posp->lnum <= 0)
+ {
+ /* Or raise an error? */
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ return Py_BuildValue("(ll)", (long)(posp->lnum), (long)(posp->col));
+}
+
+ static PyObject *
+BufferRange(BufferObject *self, PyObject *args)
+{
+ PyInt start;
+ PyInt end;
+
+ if (CheckBuffer(self))
+ return NULL;
+
+ if (!PyArg_ParseTuple(args, "nn", &start, &end))
+ return NULL;
+
+ return RangeNew(self->buf, start, end);
+}
+
+ static PyObject *
+BufferRepr(BufferObject *self)
+{
+ if (self->buf == INVALID_BUFFER_VALUE)
+ return PyString_FromFormat("<buffer object (deleted) at %p>", self);
+ else
+ {
+ char *name = (char *)self->buf->b_fname;
+
+ if (name == NULL)
+ name = "";
+
+ return PyString_FromFormat("<buffer %s>", name);
+ }
+}
+
+static struct PyMethodDef BufferMethods[] = {
+ /* name, function, calling, documentation */
+ {"append", (PyCFunction)BufferAppend, METH_VARARGS, "Append data to Vim buffer" },
+ {"mark", (PyCFunction)BufferMark, METH_O, "Return (row,col) representing position of named mark" },
+ {"range", (PyCFunction)BufferRange, METH_VARARGS, "Return a range object which represents the part of the given buffer between line numbers s and e" },
+ {"__dir__", (PyCFunction)BufferDir, METH_NOARGS, ""},
+ { NULL, NULL, 0, NULL}
+};
+
+/*
+ * Buffer list object - Implementation
+ */
+
+static PyTypeObject BufMapType;
+
+typedef struct
+{
+ PyObject_HEAD
+} BufMapObject;
+
+ static PyInt
+BufMapLength(PyObject *self UNUSED)
+{
+ buf_T *b = firstbuf;
+ PyInt n = 0;
+
+ while (b)
+ {
+ ++n;
+ b = b->b_next;
+ }
+
+ return n;
+}
+
+ static PyObject *
+BufMapItem(PyObject *self UNUSED, PyObject *keyObject)
+{
+ buf_T *b;
+ long bnr;
+
+ if (NumberToLong(keyObject, &bnr, NUMBER_INT|NUMBER_NATURAL))
+ return NULL;
+
+ b = buflist_findnr((int) bnr);
+
+ if (b)
+ return BufferNew(b);
+ else
+ {
+ PyErr_SetObject(PyExc_KeyError, keyObject);
+ return NULL;
+ }
+}
+
+ static void
+BufMapIterDestruct(PyObject *buffer)
+{
+ /* Iteration was stopped before all buffers were processed */
+ if (buffer)
+ {
+ Py_DECREF(buffer);
+ }
+}
+
+ static int
+BufMapIterTraverse(PyObject *buffer, visitproc visit, void *arg)
+{
+ if (buffer)
+ Py_VISIT(buffer);
+ return 0;
+}
+
+ static int
+BufMapIterClear(PyObject **buffer)
+{
+ if (*buffer)
+ Py_CLEAR(*buffer);
+ return 0;
+}
+
+ static PyObject *
+BufMapIterNext(PyObject **buffer)
+{
+ PyObject *next;
+ PyObject *ret;
+
+ if (!*buffer)
+ return NULL;
+
+ ret = *buffer;
+
+ if (CheckBuffer((BufferObject *)(ret)))
+ {
+ *buffer = NULL;
+ return NULL;
+ }
+
+ if (!((BufferObject *)(ret))->buf->b_next)
+ next = NULL;
+ else if (!(next = BufferNew(((BufferObject *)(ret))->buf->b_next)))
+ return NULL;
+ *buffer = next;
+ /* Do not increment reference: we no longer hold it (decref), but whoever
+ * on other side will hold (incref). Decref+incref = nothing. */
+ return ret;
+}
+
+ static PyObject *
+BufMapIter(PyObject *self UNUSED)
+{
+ PyObject *buffer;
+
+ buffer = BufferNew(firstbuf);
+ return IterNew(buffer,
+ (destructorfun) BufMapIterDestruct, (nextfun) BufMapIterNext,
+ (traversefun) BufMapIterTraverse, (clearfun) BufMapIterClear);
+}
+
+static PyMappingMethods BufMapAsMapping = {
+ (lenfunc) BufMapLength,
+ (binaryfunc) BufMapItem,
+ (objobjargproc) 0,
+};
+
+/* Current items object
+ */
+
+static char *CurrentAttrs[] = {
+ "buffer", "window", "line", "range", "tabpage",
+ NULL
+};
+
+ static PyObject *
+CurrentDir(PyObject *self)
+{
+ return ObjectDir(self, CurrentAttrs);
+}
+
+ static PyObject *
+CurrentGetattr(PyObject *self UNUSED, char *name)
+{
+ if (strcmp(name, "buffer") == 0)
+ return (PyObject *)BufferNew(curbuf);
+ else if (strcmp(name, "window") == 0)
+ return (PyObject *)WindowNew(curwin, curtab);
+ else if (strcmp(name, "tabpage") == 0)
+ return (PyObject *)TabPageNew(curtab);
+ else if (strcmp(name, "line") == 0)
+ return GetBufferLine(curbuf, (PyInt)curwin->w_cursor.lnum);
+ else if (strcmp(name, "range") == 0)
+ return RangeNew(curbuf, RangeStart, RangeEnd);
+ else if (strcmp(name, "__members__") == 0)
+ return ObjectDir(NULL, CurrentAttrs);
+ else
+#if PY_MAJOR_VERSION < 3
+ return Py_FindMethod(WindowMethods, self, name);
+#else
+ return NULL;
+#endif
+}
+
+ static int
+CurrentSetattr(PyObject *self UNUSED, char *name, PyObject *valObject)
+{
+ if (strcmp(name, "line") == 0)
+ {
+ if (SetBufferLine(curbuf, (PyInt)curwin->w_cursor.lnum, valObject,
+ NULL) == FAIL)
+ return -1;
+
+ return 0;
+ }
+ else if (strcmp(name, "buffer") == 0)
+ {
+ int count;
+
+ if (valObject->ob_type != &BufferType)
+ {
+ PyErr_FORMAT(PyExc_TypeError,
+ N_("expected vim.Buffer object, but got %s"),
+ Py_TYPE_NAME(valObject));
+ return -1;
+ }
+
+ if (CheckBuffer((BufferObject *)(valObject)))
+ return -1;
+ count = ((BufferObject *)(valObject))->buf->b_fnum;
+
+ VimTryStart();
+ if (do_buffer(DOBUF_GOTO, DOBUF_FIRST, FORWARD, count, 0) == FAIL)
+ {
+ if (VimTryEnd())
+ return -1;
+ PyErr_VIM_FORMAT(N_("failed to switch to buffer %d"), count);
+ return -1;
+ }
+
+ return VimTryEnd();
+ }
+ else if (strcmp(name, "window") == 0)
+ {
+ int count;
+
+ if (valObject->ob_type != &WindowType)
+ {
+ PyErr_FORMAT(PyExc_TypeError,
+ N_("expected vim.Window object, but got %s"),
+ Py_TYPE_NAME(valObject));
+ return -1;
+ }
+
+ if (CheckWindow((WindowObject *)(valObject)))
+ return -1;
+ count = get_win_number(((WindowObject *)(valObject))->win, firstwin);
+
+ if (!count)
+ {
+ PyErr_SET_STRING(PyExc_ValueError,
+ N_("failed to find window in the current tab page"));
+ return -1;
+ }
+
+ VimTryStart();
+ win_goto(((WindowObject *)(valObject))->win);
+ if (((WindowObject *)(valObject))->win != curwin)
+ {
+ if (VimTryEnd())
+ return -1;
+ PyErr_SET_STRING(PyExc_RuntimeError,
+ N_("did not switch to the specified window"));
+ return -1;
+ }
+
+ return VimTryEnd();
+ }
+ else if (strcmp(name, "tabpage") == 0)
+ {
+ if (valObject->ob_type != &TabPageType)
+ {
+ PyErr_FORMAT(PyExc_TypeError,
+ N_("expected vim.TabPage object, but got %s"),
+ Py_TYPE_NAME(valObject));
+ return -1;
+ }
+
+ if (CheckTabPage((TabPageObject *)(valObject)))
+ return -1;
+
+ VimTryStart();
+ goto_tabpage_tp(((TabPageObject *)(valObject))->tab, TRUE, TRUE);
+ if (((TabPageObject *)(valObject))->tab != curtab)
+ {
+ if (VimTryEnd())
+ return -1;
+ PyErr_SET_STRING(PyExc_RuntimeError,
+ N_("did not switch to the specified tab page"));
+ return -1;
+ }
+
+ return VimTryEnd();
+ }
+ else
+ {
+ PyErr_SetString(PyExc_AttributeError, name);
+ return -1;
+ }
+}
+
+static struct PyMethodDef CurrentMethods[] = {
+ /* name, function, calling, documentation */
+ {"__dir__", (PyCFunction)CurrentDir, METH_NOARGS, ""},
+ { NULL, NULL, 0, NULL}
+};
+
+ static void
+init_range_cmd(exarg_T *eap)
+{
+ RangeStart = eap->line1;
+ RangeEnd = eap->line2;
+}
+
+ static void
+init_range_eval(typval_T *rettv UNUSED)
+{
+ RangeStart = (PyInt) curwin->w_cursor.lnum;
+ RangeEnd = RangeStart;
+}
+
+ static void
+run_cmd(const char *cmd, void *arg UNUSED
+#ifdef PY_CAN_RECURSE
+ , PyGILState_STATE *pygilstate UNUSED
+#endif
+ )
+{
+ PyObject *run_ret;
+ run_ret = PyRun_String((char *)cmd, Py_file_input, globals, globals);
+ if (run_ret != NULL)
+ {
+ Py_DECREF(run_ret);
+ }
+ else if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_SystemExit))
+ {
+ semsg(_(e_py_systemexit), "python");
+ PyErr_Clear();
+ }
+ else
+ PyErr_PrintEx(1);
+}
+
+static const char *code_hdr = "def " DOPY_FUNC "(line, linenr):\n ";
+static int code_hdr_len = 30;
+
+ static void
+run_do(const char *cmd, void *arg UNUSED
+#ifdef PY_CAN_RECURSE
+ , PyGILState_STATE *pygilstate
+#endif
+ )
+{
+ PyInt lnum;
+ size_t len;
+ char *code;
+ int status;
+ PyObject *pyfunc, *pymain;
+ PyObject *run_ret;
+ buf_T *was_curbuf = curbuf;
+
+ if (u_save((linenr_T)RangeStart - 1, (linenr_T)RangeEnd + 1) != OK)
+ {
+ emsg(_("cannot save undo information"));
+ return;
+ }
+
+ len = code_hdr_len + STRLEN(cmd);
+ code = PyMem_New(char, len + 1);
+ memcpy(code, code_hdr, code_hdr_len);
+ STRCPY(code + code_hdr_len, cmd);
+ run_ret = PyRun_String(code, Py_file_input, globals, globals);
+ status = -1;
+ if (run_ret != NULL)
+ {
+ status = 0;
+ Py_DECREF(run_ret);
+ }
+ else if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_SystemExit))
+ {
+ PyMem_Free(code);
+ semsg(_(e_py_systemexit), "python");
+ PyErr_Clear();
+ return;
+ }
+ else
+ PyErr_PrintEx(1);
+
+ PyMem_Free(code);
+
+ if (status)
+ {
+ emsg(_("failed to run the code"));
+ return;
+ }
+
+ status = 0;
+ pymain = PyImport_AddModule("__main__");
+ pyfunc = PyObject_GetAttrString(pymain, DOPY_FUNC);
+#ifdef PY_CAN_RECURSE
+ PyGILState_Release(*pygilstate);
+#endif
+
+ for (lnum = RangeStart; lnum <= RangeEnd; ++lnum)
+ {
+ PyObject *line;
+ PyObject *linenr;
+ PyObject *ret;
+
+#ifdef PY_CAN_RECURSE
+ *pygilstate = PyGILState_Ensure();
+#endif
+ /* Check the line number, the command my have deleted lines. */
+ if (lnum > curbuf->b_ml.ml_line_count
+ || !(line = GetBufferLine(curbuf, lnum)))
+ goto err;
+ if (!(linenr = PyInt_FromLong((long) lnum)))
+ {
+ Py_DECREF(line);
+ goto err;
+ }
+ ret = PyObject_CallFunctionObjArgs(pyfunc, line, linenr, NULL);
+ Py_DECREF(line);
+ Py_DECREF(linenr);
+ if (!ret)
+ goto err;
+
+ /* Check that the command didn't switch to another buffer. */
+ if (curbuf != was_curbuf)
+ {
+ Py_XDECREF(ret);
+ goto err;
+ }
+
+ if (ret != Py_None)
+ if (SetBufferLine(curbuf, lnum, ret, NULL) == FAIL)
+ {
+ Py_XDECREF(ret);
+ goto err;
+ }
+
+ Py_XDECREF(ret);
+ PythonIO_Flush();
+#ifdef PY_CAN_RECURSE
+ PyGILState_Release(*pygilstate);
+#endif
+ }
+ goto out;
+err:
+#ifdef PY_CAN_RECURSE
+ *pygilstate = PyGILState_Ensure();
+#endif
+ PyErr_PrintEx(0);
+ PythonIO_Flush();
+ status = 1;
+out:
+#ifdef PY_CAN_RECURSE
+ if (!status)
+ *pygilstate = PyGILState_Ensure();
+#endif
+ Py_DECREF(pyfunc);
+ PyObject_SetAttrString(pymain, DOPY_FUNC, NULL);
+ if (status)
+ return;
+ check_cursor();
+ update_curbuf(NOT_VALID);
+}
+
+ static void
+run_eval(const char *cmd, typval_T *rettv
+#ifdef PY_CAN_RECURSE
+ , PyGILState_STATE *pygilstate UNUSED
+#endif
+ )
+{
+ PyObject *run_ret;
+
+ run_ret = PyRun_String((char *)cmd, Py_eval_input, globals, globals);
+ if (run_ret == NULL)
+ {
+ if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_SystemExit))
+ {
+ semsg(_(e_py_systemexit), "python");
+ PyErr_Clear();
+ }
+ else
+ {
+ if (PyErr_Occurred() && !msg_silent)
+ PyErr_PrintEx(0);
+ emsg(_("E858: Eval did not return a valid python object"));
+ }
+ }
+ else
+ {
+ if (ConvertFromPyObject(run_ret, rettv) == -1)
+ emsg(_("E859: Failed to convert returned python object to vim value"));
+ Py_DECREF(run_ret);
+ }
+ PyErr_Clear();
+}
+
+ static int
+set_ref_in_py(const int copyID)
+{
+ pylinkedlist_T *cur;
+ dict_T *dd;
+ list_T *ll;
+ int i;
+ int abort = FALSE;
+ FunctionObject *func;
+
+ if (lastdict != NULL)
+ {
+ for (cur = lastdict ; !abort && cur != NULL ; cur = cur->pll_prev)
+ {
+ dd = ((DictionaryObject *) (cur->pll_obj))->dict;
+ if (dd->dv_copyID != copyID)
+ {
+ dd->dv_copyID = copyID;
+ abort = abort || set_ref_in_ht(&dd->dv_hashtab, copyID, NULL);
+ }
+ }
+ }
+
+ if (lastlist != NULL)
+ {
+ for (cur = lastlist ; !abort && cur != NULL ; cur = cur->pll_prev)
+ {
+ ll = ((ListObject *) (cur->pll_obj))->list;
+ if (ll->lv_copyID != copyID)
+ {
+ ll->lv_copyID = copyID;
+ abort = abort || set_ref_in_list(ll, copyID, NULL);
+ }
+ }
+ }
+
+ if (lastfunc != NULL)
+ {
+ for (cur = lastfunc ; !abort && cur != NULL ; cur = cur->pll_prev)
+ {
+ func = (FunctionObject *) cur->pll_obj;
+ if (func->self != NULL && func->self->dv_copyID != copyID)
+ {
+ func->self->dv_copyID = copyID;
+ abort = abort || set_ref_in_ht(
+ &func->self->dv_hashtab, copyID, NULL);
+ }
+ if (func->argc)
+ for (i = 0; !abort && i < func->argc; ++i)
+ abort = abort
+ || set_ref_in_item(&func->argv[i], copyID, NULL, NULL);
+ }
+ }
+
+ return abort;
+}
+
+ static int
+set_string_copy(char_u *str, typval_T *tv)
+{
+ tv->vval.v_string = vim_strsave(str);
+ if (tv->vval.v_string == NULL)
+ {
+ PyErr_NoMemory();
+ return -1;
+ }
+ return 0;
+}
+
+ static int
+pydict_to_tv(PyObject *obj, typval_T *tv, PyObject *lookup_dict)
+{
+ dict_T *dict;
+ char_u *key;
+ dictitem_T *di;
+ PyObject *keyObject;
+ PyObject *valObject;
+ Py_ssize_t iter = 0;
+
+ if (!(dict = py_dict_alloc()))
+ return -1;
+
+ tv->v_type = VAR_DICT;
+ tv->vval.v_dict = dict;
+
+ while (PyDict_Next(obj, &iter, &keyObject, &valObject))
+ {
+ PyObject *todecref = NULL;
+
+ if (keyObject == NULL || valObject == NULL)
+ {
+ dict_unref(dict);
+ return -1;
+ }
+
+ if (!(key = StringToChars(keyObject, &todecref)))
+ {
+ dict_unref(dict);
+ return -1;
+ }
+
+ if (*key == NUL)
+ {
+ dict_unref(dict);
+ Py_XDECREF(todecref);
+ RAISE_NO_EMPTY_KEYS;
+ return -1;
+ }
+
+ di = dictitem_alloc(key);
+
+ Py_XDECREF(todecref);
+
+ if (di == NULL)
+ {
+ PyErr_NoMemory();
+ dict_unref(dict);
+ return -1;
+ }
+
+ if (_ConvertFromPyObject(valObject, &di->di_tv, lookup_dict) == -1)
+ {
+ vim_free(di);
+ dict_unref(dict);
+ return -1;
+ }
+
+ if (dict_add(dict, di) == FAIL)
+ {
+ RAISE_KEY_ADD_FAIL(di->di_key);
+ clear_tv(&di->di_tv);
+ vim_free(di);
+ dict_unref(dict);
+ return -1;
+ }
+ }
+
+ --dict->dv_refcount;
+ return 0;
+}
+
+ static int
+pymap_to_tv(PyObject *obj, typval_T *tv, PyObject *lookup_dict)
+{
+ dict_T *dict;
+ char_u *key;
+ dictitem_T *di;
+ PyObject *list;
+ PyObject *iterator;
+ PyObject *keyObject;
+ PyObject *valObject;
+
+ if (!(dict = py_dict_alloc()))
+ return -1;
+
+ tv->v_type = VAR_DICT;
+ tv->vval.v_dict = dict;
+
+ if (!(list = PyMapping_Keys(obj)))
+ {
+ dict_unref(dict);
+ return -1;
+ }
+
+ if (!(iterator = PyObject_GetIter(list)))
+ {
+ dict_unref(dict);
+ Py_DECREF(list);
+ return -1;
+ }
+ Py_DECREF(list);
+
+ while ((keyObject = PyIter_Next(iterator)))
+ {
+ PyObject *todecref;
+
+ if (!(key = StringToChars(keyObject, &todecref)))
+ {
+ Py_DECREF(keyObject);
+ Py_DECREF(iterator);
+ dict_unref(dict);
+ return -1;
+ }
+
+ if (*key == NUL)
+ {
+ Py_DECREF(keyObject);
+ Py_DECREF(iterator);
+ Py_XDECREF(todecref);
+ dict_unref(dict);
+ RAISE_NO_EMPTY_KEYS;
+ return -1;
+ }
+
+ if (!(valObject = PyObject_GetItem(obj, keyObject)))
+ {
+ Py_DECREF(keyObject);
+ Py_DECREF(iterator);
+ Py_XDECREF(todecref);
+ dict_unref(dict);
+ return -1;
+ }
+
+ di = dictitem_alloc(key);
+
+ Py_DECREF(keyObject);
+ Py_XDECREF(todecref);
+
+ if (di == NULL)
+ {
+ Py_DECREF(iterator);
+ Py_DECREF(valObject);
+ dict_unref(dict);
+ PyErr_NoMemory();
+ return -1;
+ }
+
+ if (_ConvertFromPyObject(valObject, &di->di_tv, lookup_dict) == -1)
+ {
+ Py_DECREF(iterator);
+ Py_DECREF(valObject);
+ vim_free(di);
+ dict_unref(dict);
+ return -1;
+ }
+
+ Py_DECREF(valObject);
+
+ if (dict_add(dict, di) == FAIL)
+ {
+ RAISE_KEY_ADD_FAIL(di->di_key);
+ Py_DECREF(iterator);
+ dictitem_free(di);
+ dict_unref(dict);
+ return -1;
+ }
+ }
+ Py_DECREF(iterator);
+ --dict->dv_refcount;
+ return 0;
+}
+
+ static int
+pyseq_to_tv(PyObject *obj, typval_T *tv, PyObject *lookup_dict)
+{
+ list_T *l;
+
+ if (!(l = py_list_alloc()))
+ return -1;
+
+ tv->v_type = VAR_LIST;
+ tv->vval.v_list = l;
+
+ if (list_py_concat(l, obj, lookup_dict) == -1)
+ {
+ list_unref(l);
+ return -1;
+ }
+
+ --l->lv_refcount;
+ return 0;
+}
+
+typedef int (*pytotvfunc)(PyObject *, typval_T *, PyObject *);
+
+ static int
+convert_dl(PyObject *obj, typval_T *tv,
+ pytotvfunc py_to_tv, PyObject *lookup_dict)
+{
+ PyObject *capsule;
+ char hexBuf[sizeof(void *) * 2 + 3];
+
+ sprintf(hexBuf, "%p", (void *)obj);
+
+# ifdef PY_USE_CAPSULE
+ capsule = PyDict_GetItemString(lookup_dict, hexBuf);
+# else
+ capsule = (PyObject *)PyDict_GetItemString(lookup_dict, hexBuf);
+# endif
+ if (capsule == NULL)
+ {
+# ifdef PY_USE_CAPSULE
+ capsule = PyCapsule_New(tv, NULL, NULL);
+# else
+ capsule = PyCObject_FromVoidPtr(tv, NULL);
+# endif
+ if (PyDict_SetItemString(lookup_dict, hexBuf, capsule))
+ {
+ Py_DECREF(capsule);
+ tv->v_type = VAR_UNKNOWN;
+ return -1;
+ }
+
+ Py_DECREF(capsule);
+
+ if (py_to_tv(obj, tv, lookup_dict) == -1)
+ {
+ tv->v_type = VAR_UNKNOWN;
+ return -1;
+ }
+ /* As we are not using copy_tv which increments reference count we must
+ * do it ourself. */
+ if (tv->v_type == VAR_DICT)
+ ++tv->vval.v_dict->dv_refcount;
+ else if (tv->v_type == VAR_LIST)
+ ++tv->vval.v_list->lv_refcount;
+ }
+ else
+ {
+ typval_T *v;
+
+# ifdef PY_USE_CAPSULE
+ v = PyCapsule_GetPointer(capsule, NULL);
+# else
+ v = PyCObject_AsVoidPtr(capsule);
+# endif
+ copy_tv(v, tv);
+ }
+ return 0;
+}
+
+ static int
+ConvertFromPyMapping(PyObject *obj, typval_T *tv)
+{
+ PyObject *lookup_dict;
+ int ret;
+
+ if (!(lookup_dict = PyDict_New()))
+ return -1;
+
+ if (PyType_IsSubtype(obj->ob_type, &DictionaryType))
+ {
+ tv->v_type = VAR_DICT;
+ tv->vval.v_dict = (((DictionaryObject *)(obj))->dict);
+ ++tv->vval.v_dict->dv_refcount;
+ ret = 0;
+ }
+ else if (PyDict_Check(obj))
+ ret = convert_dl(obj, tv, pydict_to_tv, lookup_dict);
+ else if (PyMapping_Check(obj))
+ ret = convert_dl(obj, tv, pymap_to_tv, lookup_dict);
+ else
+ {
+ PyErr_FORMAT(PyExc_TypeError,
+ N_("unable to convert %s to vim dictionary"),
+ Py_TYPE_NAME(obj));
+ ret = -1;
+ }
+ Py_DECREF(lookup_dict);
+ return ret;
+}
+
+ static int
+ConvertFromPySequence(PyObject *obj, typval_T *tv)
+{
+ PyObject *lookup_dict;
+ int ret;
+
+ if (!(lookup_dict = PyDict_New()))
+ return -1;
+
+ if (PyType_IsSubtype(obj->ob_type, &ListType))
+ {
+ tv->v_type = VAR_LIST;
+ tv->vval.v_list = (((ListObject *)(obj))->list);
+ ++tv->vval.v_list->lv_refcount;
+ ret = 0;
+ }
+ else if (PyIter_Check(obj) || PySequence_Check(obj))
+ ret = convert_dl(obj, tv, pyseq_to_tv, lookup_dict);
+ else
+ {
+ PyErr_FORMAT(PyExc_TypeError,
+ N_("unable to convert %s to vim list"),
+ Py_TYPE_NAME(obj));
+ ret = -1;
+ }
+ Py_DECREF(lookup_dict);
+ return ret;
+}
+
+ static int
+ConvertFromPyObject(PyObject *obj, typval_T *tv)
+{
+ PyObject *lookup_dict;
+ int ret;
+
+ if (!(lookup_dict = PyDict_New()))
+ return -1;
+ ret = _ConvertFromPyObject(obj, tv, lookup_dict);
+ Py_DECREF(lookup_dict);
+ return ret;
+}
+
+ static int
+_ConvertFromPyObject(PyObject *obj, typval_T *tv, PyObject *lookup_dict)
+{
+ if (PyType_IsSubtype(obj->ob_type, &DictionaryType))
+ {
+ tv->v_type = VAR_DICT;
+ tv->vval.v_dict = (((DictionaryObject *)(obj))->dict);
+ ++tv->vval.v_dict->dv_refcount;
+ }
+ else if (PyType_IsSubtype(obj->ob_type, &ListType))
+ {
+ tv->v_type = VAR_LIST;
+ tv->vval.v_list = (((ListObject *)(obj))->list);
+ ++tv->vval.v_list->lv_refcount;
+ }
+ else if (PyType_IsSubtype(obj->ob_type, &FunctionType))
+ {
+ FunctionObject *func = (FunctionObject *) obj;
+ if (func->self != NULL || func->argv != NULL)
+ {
+ partial_T *pt = (partial_T *)alloc_clear(sizeof(partial_T));
+ set_partial(func, pt, TRUE);
+ tv->vval.v_partial = pt;
+ tv->v_type = VAR_PARTIAL;
+ }
+ else
+ {
+ if (set_string_copy(func->name, tv) == -1)
+ return -1;
+
+ tv->v_type = VAR_FUNC;
+ }
+ func_ref(func->name);
+ }
+ else if (PyBytes_Check(obj))
+ {
+ char_u *str;
+
+ if (PyBytes_AsStringAndSize(obj, (char **) &str, NULL) == -1)
+ return -1;
+ if (str == NULL)
+ return -1;
+
+ if (set_string_copy(str, tv) == -1)
+ return -1;
+
+ tv->v_type = VAR_STRING;
+ }
+ else if (PyUnicode_Check(obj))
+ {
+ PyObject *bytes;
+ char_u *str;
+
+ bytes = PyUnicode_AsEncodedString(obj, ENC_OPT, NULL);
+ if (bytes == NULL)
+ return -1;
+
+ if(PyBytes_AsStringAndSize(bytes, (char **) &str, NULL) == -1)
+ return -1;
+ if (str == NULL)
+ return -1;
+
+ if (set_string_copy(str, tv))
+ {
+ Py_XDECREF(bytes);
+ return -1;
+ }
+ Py_XDECREF(bytes);
+
+ tv->v_type = VAR_STRING;
+ }
+#if PY_MAJOR_VERSION < 3
+ else if (PyInt_Check(obj))
+ {
+ tv->v_type = VAR_NUMBER;
+ tv->vval.v_number = (varnumber_T) PyInt_AsLong(obj);
+ if (PyErr_Occurred())
+ return -1;
+ }
+#endif
+ else if (PyLong_Check(obj))
+ {
+ tv->v_type = VAR_NUMBER;
+ tv->vval.v_number = (varnumber_T) PyLong_AsLong(obj);
+ if (PyErr_Occurred())
+ return -1;
+ }
+ else if (PyDict_Check(obj))
+ return convert_dl(obj, tv, pydict_to_tv, lookup_dict);
+#ifdef FEAT_FLOAT
+ else if (PyFloat_Check(obj))
+ {
+ tv->v_type = VAR_FLOAT;
+ tv->vval.v_float = (float_T) PyFloat_AsDouble(obj);
+ }
+#endif
+ else if (PyObject_HasAttrString(obj, "keys"))
+ return convert_dl(obj, tv, pymap_to_tv, lookup_dict);
+ /* PyObject_GetIter can create built-in iterator for any sequence object */
+ else if (PyIter_Check(obj) || PySequence_Check(obj))
+ return convert_dl(obj, tv, pyseq_to_tv, lookup_dict);
+ else if (PyMapping_Check(obj))
+ return convert_dl(obj, tv, pymap_to_tv, lookup_dict);
+ else if (PyNumber_Check(obj))
+ {
+ PyObject *num;
+
+ if (!(num = PyNumber_Long(obj)))
+ return -1;
+
+ tv->v_type = VAR_NUMBER;
+ tv->vval.v_number = (varnumber_T) PyLong_AsLong(num);
+
+ Py_DECREF(num);
+ }
+ else if (obj == Py_None)
+ {
+ tv->v_type = VAR_SPECIAL;
+ tv->vval.v_number = VVAL_NONE;
+ }
+ else
+ {
+ PyErr_FORMAT(PyExc_TypeError,
+ N_("unable to convert %s to vim structure"),
+ Py_TYPE_NAME(obj));
+ return -1;
+ }
+ return 0;
+}
+
+ static PyObject *
+ConvertToPyObject(typval_T *tv)
+{
+ typval_T *argv;
+ int i;
+ if (tv == NULL)
+ {
+ PyErr_SET_VIM(N_("internal error: NULL reference passed"));
+ return NULL;
+ }
+ switch (tv->v_type)
+ {
+ case VAR_STRING:
+ return PyBytes_FromString(tv->vval.v_string == NULL
+ ? "" : (char *)tv->vval.v_string);
+ case VAR_NUMBER:
+ return PyLong_FromLong((long) tv->vval.v_number);
+#ifdef FEAT_FLOAT
+ case VAR_FLOAT:
+ return PyFloat_FromDouble((double) tv->vval.v_float);
+#endif
+ case VAR_LIST:
+ return NEW_LIST(tv->vval.v_list);
+ case VAR_DICT:
+ return NEW_DICTIONARY(tv->vval.v_dict);
+ case VAR_FUNC:
+ return NEW_FUNCTION(tv->vval.v_string == NULL
+ ? (char_u *)"" : tv->vval.v_string,
+ 0, NULL, NULL, TRUE);
+ case VAR_PARTIAL:
+ if (tv->vval.v_partial->pt_argc)
+ {
+ argv = PyMem_New(typval_T, (size_t)tv->vval.v_partial->pt_argc);
+ for (i = 0; i < tv->vval.v_partial->pt_argc; i++)
+ copy_tv(&tv->vval.v_partial->pt_argv[i], &argv[i]);
+ }
+ else
+ argv = NULL;
+ if (tv->vval.v_partial->pt_dict != NULL)
+ tv->vval.v_partial->pt_dict->dv_refcount++;
+ return NEW_FUNCTION(tv->vval.v_partial == NULL
+ ? (char_u *)"" : partial_name(tv->vval.v_partial),
+ tv->vval.v_partial->pt_argc, argv,
+ tv->vval.v_partial->pt_dict,
+ tv->vval.v_partial->pt_auto);
+ case VAR_BLOB:
+ return PyBytes_FromStringAndSize(
+ (char*) tv->vval.v_blob->bv_ga.ga_data,
+ (Py_ssize_t) tv->vval.v_blob->bv_ga.ga_len);
+ case VAR_UNKNOWN:
+ case VAR_CHANNEL:
+ case VAR_JOB:
+ Py_INCREF(Py_None);
+ return Py_None;
+ case VAR_SPECIAL:
+ switch (tv->vval.v_number)
+ {
+ case VVAL_FALSE: return AlwaysFalse(NULL);
+ case VVAL_TRUE: return AlwaysTrue(NULL);
+ case VVAL_NONE:
+ case VVAL_NULL: return AlwaysNone(NULL);
+ }
+ PyErr_SET_VIM(N_("internal error: invalid value type"));
+ return NULL;
+ }
+ return NULL;
+}
+
+typedef struct
+{
+ PyObject_HEAD
+} CurrentObject;
+static PyTypeObject CurrentType;
+
+ static void
+init_structs(void)
+{
+ vim_memset(&OutputType, 0, sizeof(OutputType));
+ OutputType.tp_name = "vim.message";
+ OutputType.tp_basicsize = sizeof(OutputObject);
+ OutputType.tp_flags = Py_TPFLAGS_DEFAULT;
+ OutputType.tp_doc = "vim message object";
+ OutputType.tp_methods = OutputMethods;
+#if PY_MAJOR_VERSION >= 3
+ OutputType.tp_getattro = (getattrofunc)OutputGetattro;
+ OutputType.tp_setattro = (setattrofunc)OutputSetattro;
+ OutputType.tp_alloc = call_PyType_GenericAlloc;
+ OutputType.tp_new = call_PyType_GenericNew;
+ OutputType.tp_free = call_PyObject_Free;
+ OutputType.tp_base = &PyStdPrinter_Type;
+#else
+ OutputType.tp_getattr = (getattrfunc)OutputGetattr;
+ OutputType.tp_setattr = (setattrfunc)OutputSetattr;
+ // Disabled, because this causes a crash in test86
+ // OutputType.tp_base = &PyFile_Type;
+#endif
+
+ vim_memset(&IterType, 0, sizeof(IterType));
+ IterType.tp_name = "vim.iter";
+ IterType.tp_basicsize = sizeof(IterObject);
+ IterType.tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_GC;
+ IterType.tp_doc = "generic iterator object";
+ IterType.tp_iter = (getiterfunc)IterIter;
+ IterType.tp_iternext = (iternextfunc)IterNext;
+ IterType.tp_dealloc = (destructor)IterDestructor;
+ IterType.tp_traverse = (traverseproc)IterTraverse;
+ IterType.tp_clear = (inquiry)IterClear;
+
+ vim_memset(&BufferType, 0, sizeof(BufferType));
+ BufferType.tp_name = "vim.buffer";
+ BufferType.tp_basicsize = sizeof(BufferType);
+ BufferType.tp_dealloc = (destructor)BufferDestructor;
+ BufferType.tp_repr = (reprfunc)BufferRepr;
+ BufferType.tp_as_sequence = &BufferAsSeq;
+ BufferType.tp_as_mapping = &BufferAsMapping;
+ BufferType.tp_flags = Py_TPFLAGS_DEFAULT;
+ BufferType.tp_doc = "vim buffer object";
+ BufferType.tp_methods = BufferMethods;
+#if PY_MAJOR_VERSION >= 3
+ BufferType.tp_getattro = (getattrofunc)BufferGetattro;
+ BufferType.tp_setattro = (setattrofunc)BufferSetattro;
+ BufferType.tp_alloc = call_PyType_GenericAlloc;
+ BufferType.tp_new = call_PyType_GenericNew;
+ BufferType.tp_free = call_PyObject_Free;
+#else
+ BufferType.tp_getattr = (getattrfunc)BufferGetattr;
+ BufferType.tp_setattr = (setattrfunc)BufferSetattr;
+#endif
+
+ vim_memset(&WindowType, 0, sizeof(WindowType));
+ WindowType.tp_name = "vim.window";
+ WindowType.tp_basicsize = sizeof(WindowObject);
+ WindowType.tp_dealloc = (destructor)WindowDestructor;
+ WindowType.tp_repr = (reprfunc)WindowRepr;
+ WindowType.tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_GC;
+ WindowType.tp_doc = "vim Window object";
+ WindowType.tp_methods = WindowMethods;
+ WindowType.tp_traverse = (traverseproc)WindowTraverse;
+ WindowType.tp_clear = (inquiry)WindowClear;
+#if PY_MAJOR_VERSION >= 3
+ WindowType.tp_getattro = (getattrofunc)WindowGetattro;
+ WindowType.tp_setattro = (setattrofunc)WindowSetattro;
+ WindowType.tp_alloc = call_PyType_GenericAlloc;
+ WindowType.tp_new = call_PyType_GenericNew;
+ WindowType.tp_free = call_PyObject_Free;
+#else
+ WindowType.tp_getattr = (getattrfunc)WindowGetattr;
+ WindowType.tp_setattr = (setattrfunc)WindowSetattr;
+#endif
+
+ vim_memset(&TabPageType, 0, sizeof(TabPageType));
+ TabPageType.tp_name = "vim.tabpage";
+ TabPageType.tp_basicsize = sizeof(TabPageObject);
+ TabPageType.tp_dealloc = (destructor)TabPageDestructor;
+ TabPageType.tp_repr = (reprfunc)TabPageRepr;
+ TabPageType.tp_flags = Py_TPFLAGS_DEFAULT;
+ TabPageType.tp_doc = "vim tab page object";
+ TabPageType.tp_methods = TabPageMethods;
+#if PY_MAJOR_VERSION >= 3
+ TabPageType.tp_getattro = (getattrofunc)TabPageGetattro;
+ TabPageType.tp_alloc = call_PyType_GenericAlloc;
+ TabPageType.tp_new = call_PyType_GenericNew;
+ TabPageType.tp_free = call_PyObject_Free;
+#else
+ TabPageType.tp_getattr = (getattrfunc)TabPageGetattr;
+#endif
+
+ vim_memset(&BufMapType, 0, sizeof(BufMapType));
+ BufMapType.tp_name = "vim.bufferlist";
+ BufMapType.tp_basicsize = sizeof(BufMapObject);
+ BufMapType.tp_as_mapping = &BufMapAsMapping;
+ BufMapType.tp_flags = Py_TPFLAGS_DEFAULT;
+ BufMapType.tp_iter = BufMapIter;
+ BufferType.tp_doc = "vim buffer list";
+
+ vim_memset(&WinListType, 0, sizeof(WinListType));
+ WinListType.tp_name = "vim.windowlist";
+ WinListType.tp_basicsize = sizeof(WinListType);
+ WinListType.tp_as_sequence = &WinListAsSeq;
+ WinListType.tp_flags = Py_TPFLAGS_DEFAULT;
+ WinListType.tp_doc = "vim window list";
+ WinListType.tp_dealloc = (destructor)WinListDestructor;
+
+ vim_memset(&TabListType, 0, sizeof(TabListType));
+ TabListType.tp_name = "vim.tabpagelist";
+ TabListType.tp_basicsize = sizeof(TabListType);
+ TabListType.tp_as_sequence = &TabListAsSeq;
+ TabListType.tp_flags = Py_TPFLAGS_DEFAULT;
+ TabListType.tp_doc = "vim tab page list";
+
+ vim_memset(&RangeType, 0, sizeof(RangeType));
+ RangeType.tp_name = "vim.range";
+ RangeType.tp_basicsize = sizeof(RangeObject);
+ RangeType.tp_dealloc = (destructor)RangeDestructor;
+ RangeType.tp_repr = (reprfunc)RangeRepr;
+ RangeType.tp_as_sequence = &RangeAsSeq;
+ RangeType.tp_as_mapping = &RangeAsMapping;
+ RangeType.tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_GC;
+ RangeType.tp_doc = "vim Range object";
+ RangeType.tp_methods = RangeMethods;
+ RangeType.tp_traverse = (traverseproc)RangeTraverse;
+ RangeType.tp_clear = (inquiry)RangeClear;
+#if PY_MAJOR_VERSION >= 3
+ RangeType.tp_getattro = (getattrofunc)RangeGetattro;
+ RangeType.tp_alloc = call_PyType_GenericAlloc;
+ RangeType.tp_new = call_PyType_GenericNew;
+ RangeType.tp_free = call_PyObject_Free;
+#else
+ RangeType.tp_getattr = (getattrfunc)RangeGetattr;
+#endif
+
+ vim_memset(&CurrentType, 0, sizeof(CurrentType));
+ CurrentType.tp_name = "vim.currentdata";
+ CurrentType.tp_basicsize = sizeof(CurrentObject);
+ CurrentType.tp_flags = Py_TPFLAGS_DEFAULT;
+ CurrentType.tp_doc = "vim current object";
+ CurrentType.tp_methods = CurrentMethods;
+#if PY_MAJOR_VERSION >= 3
+ CurrentType.tp_getattro = (getattrofunc)CurrentGetattro;
+ CurrentType.tp_setattro = (setattrofunc)CurrentSetattro;
+#else
+ CurrentType.tp_getattr = (getattrfunc)CurrentGetattr;
+ CurrentType.tp_setattr = (setattrfunc)CurrentSetattr;
+#endif
+
+ vim_memset(&DictionaryType, 0, sizeof(DictionaryType));
+ DictionaryType.tp_name = "vim.dictionary";
+ DictionaryType.tp_basicsize = sizeof(DictionaryObject);
+ DictionaryType.tp_dealloc = (destructor)DictionaryDestructor;
+ DictionaryType.tp_as_sequence = &DictionaryAsSeq;
+ DictionaryType.tp_as_mapping = &DictionaryAsMapping;
+ DictionaryType.tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE;
+ DictionaryType.tp_doc = "dictionary pushing modifications to vim structure";
+ DictionaryType.tp_methods = DictionaryMethods;
+ DictionaryType.tp_iter = (getiterfunc)DictionaryIter;
+ DictionaryType.tp_new = (newfunc)DictionaryConstructor;
+ DictionaryType.tp_alloc = (allocfunc)PyType_GenericAlloc;
+#if PY_MAJOR_VERSION >= 3
+ DictionaryType.tp_getattro = (getattrofunc)DictionaryGetattro;
+ DictionaryType.tp_setattro = (setattrofunc)DictionarySetattro;
+#else
+ DictionaryType.tp_getattr = (getattrfunc)DictionaryGetattr;
+ DictionaryType.tp_setattr = (setattrfunc)DictionarySetattr;
+#endif
+
+ vim_memset(&ListType, 0, sizeof(ListType));
+ ListType.tp_name = "vim.list";
+ ListType.tp_dealloc = (destructor)ListDestructor;
+ ListType.tp_basicsize = sizeof(ListObject);
+ ListType.tp_as_sequence = &ListAsSeq;
+ ListType.tp_as_mapping = &ListAsMapping;
+ ListType.tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE;
+ ListType.tp_doc = "list pushing modifications to vim structure";
+ ListType.tp_methods = ListMethods;
+ ListType.tp_iter = (getiterfunc)ListIter;
+ ListType.tp_new = (newfunc)ListConstructor;
+ ListType.tp_alloc = (allocfunc)PyType_GenericAlloc;
+#if PY_MAJOR_VERSION >= 3
+ ListType.tp_getattro = (getattrofunc)ListGetattro;
+ ListType.tp_setattro = (setattrofunc)ListSetattro;
+#else
+ ListType.tp_getattr = (getattrfunc)ListGetattr;
+ ListType.tp_setattr = (setattrfunc)ListSetattr;
+#endif
+
+ vim_memset(&FunctionType, 0, sizeof(FunctionType));
+ FunctionType.tp_name = "vim.function";
+ FunctionType.tp_basicsize = sizeof(FunctionObject);
+ FunctionType.tp_dealloc = (destructor)FunctionDestructor;
+ FunctionType.tp_call = (ternaryfunc)FunctionCall;
+ FunctionType.tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE;
+ FunctionType.tp_doc = "object that calls vim function";
+ FunctionType.tp_methods = FunctionMethods;
+ FunctionType.tp_repr = (reprfunc)FunctionRepr;
+ FunctionType.tp_new = (newfunc)FunctionConstructor;
+ FunctionType.tp_alloc = (allocfunc)PyType_GenericAlloc;
+#if PY_MAJOR_VERSION >= 3
+ FunctionType.tp_getattro = (getattrofunc)FunctionGetattro;
+#else
+ FunctionType.tp_getattr = (getattrfunc)FunctionGetattr;
+#endif
+
+ vim_memset(&OptionsType, 0, sizeof(OptionsType));
+ OptionsType.tp_name = "vim.options";
+ OptionsType.tp_basicsize = sizeof(OptionsObject);
+ OptionsType.tp_as_sequence = &OptionsAsSeq;
+ OptionsType.tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_GC;
+ OptionsType.tp_doc = "object for manipulating options";
+ OptionsType.tp_iter = (getiterfunc)OptionsIter;
+ OptionsType.tp_as_mapping = &OptionsAsMapping;
+ OptionsType.tp_dealloc = (destructor)OptionsDestructor;
+ OptionsType.tp_traverse = (traverseproc)OptionsTraverse;
+ OptionsType.tp_clear = (inquiry)OptionsClear;
+
+#if PY_VERSION_HEX < 0x030700f0
+ vim_memset(&LoaderType, 0, sizeof(LoaderType));
+ LoaderType.tp_name = "vim.Loader";
+ LoaderType.tp_basicsize = sizeof(LoaderObject);
+ LoaderType.tp_flags = Py_TPFLAGS_DEFAULT;
+ LoaderType.tp_doc = "vim message object";
+ LoaderType.tp_methods = LoaderMethods;
+ LoaderType.tp_dealloc = (destructor)LoaderDestructor;
+#endif
+
+#if PY_MAJOR_VERSION >= 3
+ vim_memset(&vimmodule, 0, sizeof(vimmodule));
+ vimmodule.m_name = "vim";
+ vimmodule.m_doc = "Vim Python interface\n";
+ vimmodule.m_size = -1;
+ vimmodule.m_methods = VimMethods;
+#endif
+}
+
+#define PYTYPE_READY(type) \
+ if (PyType_Ready(&type)) \
+ return -1;
+
+ static int
+init_types(void)
+{
+ PYTYPE_READY(IterType);
+ PYTYPE_READY(BufferType);
+ PYTYPE_READY(RangeType);
+ PYTYPE_READY(WindowType);
+ PYTYPE_READY(TabPageType);
+ PYTYPE_READY(BufMapType);
+ PYTYPE_READY(WinListType);
+ PYTYPE_READY(TabListType);
+ PYTYPE_READY(CurrentType);
+ PYTYPE_READY(DictionaryType);
+ PYTYPE_READY(ListType);
+ PYTYPE_READY(FunctionType);
+ PYTYPE_READY(OptionsType);
+ PYTYPE_READY(OutputType);
+#if PY_VERSION_HEX < 0x030700f0
+ PYTYPE_READY(LoaderType);
+#endif
+ return 0;
+}
+
+ static int
+init_sys_path(void)
+{
+ PyObject *path;
+ PyObject *path_hook;
+ PyObject *path_hooks;
+
+ if (!(path_hook = PyObject_GetAttrString(vim_module, "path_hook")))
+ return -1;
+
+ if (!(path_hooks = PySys_GetObject("path_hooks")))
+ {
+ PyErr_Clear();
+ path_hooks = PyList_New(1);
+ PyList_SET_ITEM(path_hooks, 0, path_hook);
+ if (PySys_SetObject("path_hooks", path_hooks))
+ {
+ Py_DECREF(path_hooks);
+ return -1;
+ }
+ Py_DECREF(path_hooks);
+ }
+ else if (PyList_Check(path_hooks))
+ {
+ if (PyList_Append(path_hooks, path_hook))
+ {
+ Py_DECREF(path_hook);
+ return -1;
+ }
+ Py_DECREF(path_hook);
+ }
+ else
+ {
+ VimTryStart();
+ emsg(_("Failed to set path hook: sys.path_hooks is not a list\n"
+ "You should now do the following:\n"
+ "- append vim.path_hook to sys.path_hooks\n"
+ "- append vim.VIM_SPECIAL_PATH to sys.path\n"));
+ VimTryEnd(); /* Discard the error */
+ Py_DECREF(path_hook);
+ return 0;
+ }
+
+ if (!(path = PySys_GetObject("path")))
+ {
+ PyErr_Clear();
+ path = PyList_New(1);
+ Py_INCREF(vim_special_path_object);
+ PyList_SET_ITEM(path, 0, vim_special_path_object);
+ if (PySys_SetObject("path", path))
+ {
+ Py_DECREF(path);
+ return -1;
+ }
+ Py_DECREF(path);
+ }
+ else if (PyList_Check(path))
+ {
+ if (PyList_Append(path, vim_special_path_object))
+ return -1;
+ }
+ else
+ {
+ VimTryStart();
+ emsg(_("Failed to set path: sys.path is not a list\n"
+ "You should now append vim.VIM_SPECIAL_PATH to sys.path"));
+ VimTryEnd(); /* Discard the error */
+ }
+
+ return 0;
+}
+
+static BufMapObject TheBufferMap =
+{
+ PyObject_HEAD_INIT(&BufMapType)
+};
+
+static WinListObject TheWindowList =
+{
+ PyObject_HEAD_INIT(&WinListType)
+ NULL
+};
+
+static CurrentObject TheCurrent =
+{
+ PyObject_HEAD_INIT(&CurrentType)
+};
+
+static TabListObject TheTabPageList =
+{
+ PyObject_HEAD_INIT(&TabListType)
+};
+
+static struct numeric_constant {
+ char *name;
+ int val;
+} numeric_constants[] = {
+ {"VAR_LOCKED", VAR_LOCKED},
+ {"VAR_FIXED", VAR_FIXED},
+ {"VAR_SCOPE", VAR_SCOPE},
+ {"VAR_DEF_SCOPE", VAR_DEF_SCOPE},
+};
+
+static struct object_constant {
+ char *name;
+ PyObject *valObject;
+} object_constants[] = {
+ {"buffers", (PyObject *)(void *)&TheBufferMap},
+ {"windows", (PyObject *)(void *)&TheWindowList},
+ {"tabpages", (PyObject *)(void *)&TheTabPageList},
+ {"current", (PyObject *)(void *)&TheCurrent},
+
+ {"Buffer", (PyObject *)&BufferType},
+ {"Range", (PyObject *)&RangeType},
+ {"Window", (PyObject *)&WindowType},
+ {"TabPage", (PyObject *)&TabPageType},
+ {"Dictionary", (PyObject *)&DictionaryType},
+ {"List", (PyObject *)&ListType},
+ {"Function", (PyObject *)&FunctionType},
+ {"Options", (PyObject *)&OptionsType},
+#if PY_VERSION_HEX < 0x030700f0
+ {"_Loader", (PyObject *)&LoaderType},
+#endif
+};
+
+#define ADD_OBJECT(m, name, obj) \
+ if (PyModule_AddObject(m, name, obj)) \
+ return -1;
+
+#define ADD_CHECKED_OBJECT(m, name, obj) \
+ { \
+ PyObject *valObject = obj; \
+ if (!valObject) \
+ return -1; \
+ ADD_OBJECT(m, name, valObject); \
+ }
+
+ static int
+populate_module(PyObject *m)
+{
+ int i;
+ PyObject *other_module;
+ PyObject *attr;
+ PyObject *imp;
+#if PY_VERSION_HEX >= 0x030700f0
+ PyObject *dict;
+ PyObject *cls;
+#endif
+
+ for (i = 0; i < (int)(sizeof(numeric_constants)
+ / sizeof(struct numeric_constant));
+ ++i)
+ ADD_CHECKED_OBJECT(m, numeric_constants[i].name,
+ PyInt_FromLong(numeric_constants[i].val));
+
+ for (i = 0; i < (int)(sizeof(object_constants)
+ / sizeof(struct object_constant));
+ ++i)
+ {
+ PyObject *valObject;
+
+ valObject = object_constants[i].valObject;
+ Py_INCREF(valObject);
+ ADD_OBJECT(m, object_constants[i].name, valObject);
+ }
+
+ if (!(VimError = PyErr_NewException("vim.error", NULL, NULL)))
+ return -1;
+ ADD_OBJECT(m, "error", VimError);
+
+ ADD_CHECKED_OBJECT(m, "vars", NEW_DICTIONARY(&globvardict));
+ ADD_CHECKED_OBJECT(m, "vvars", NEW_DICTIONARY(&vimvardict));
+ ADD_CHECKED_OBJECT(m, "options",
+ OptionsNew(SREQ_GLOBAL, NULL, dummy_check, NULL));
+
+ if (!(other_module = PyImport_ImportModule("os")))
+ return -1;
+ ADD_OBJECT(m, "os", other_module);
+
+#if PY_MAJOR_VERSION >= 3
+ if (!(py_getcwd = PyObject_GetAttrString(other_module, "getcwd")))
+ return -1;
+#else
+ if (!(py_getcwd = PyObject_GetAttrString(other_module, "getcwdu")))
+ return -1;
+#endif
+ ADD_OBJECT(m, "_getcwd", py_getcwd)
+
+ if (!(py_chdir = PyObject_GetAttrString(other_module, "chdir")))
+ return -1;
+ ADD_OBJECT(m, "_chdir", py_chdir);
+ if (!(attr = PyObject_GetAttrString(m, "chdir")))
+ return -1;
+ if (PyObject_SetAttrString(other_module, "chdir", attr))
+ {
+ Py_DECREF(attr);
+ return -1;
+ }
+ Py_DECREF(attr);
+
+ if ((py_fchdir = PyObject_GetAttrString(other_module, "fchdir")))
+ {
+ ADD_OBJECT(m, "_fchdir", py_fchdir);
+ if (!(attr = PyObject_GetAttrString(m, "fchdir")))
+ return -1;
+ if (PyObject_SetAttrString(other_module, "fchdir", attr))
+ {
+ Py_DECREF(attr);
+ return -1;
+ }
+ Py_DECREF(attr);
+ }
+ else
+ PyErr_Clear();
+
+ if (!(vim_special_path_object = PyString_FromString(vim_special_path)))
+ return -1;
+
+ ADD_OBJECT(m, "VIM_SPECIAL_PATH", vim_special_path_object);
+
+#if PY_VERSION_HEX >= 0x030700f0
+ if (!(imp = PyImport_ImportModule("importlib.machinery")))
+ return -1;
+
+ dict = PyModule_GetDict(imp);
+
+ if (!(cls = PyDict_GetItemString(dict, "PathFinder")))
+ {
+ Py_DECREF(imp);
+ return -1;
+ }
+
+ if (!(py_find_spec = PyObject_GetAttrString(cls, "find_spec")))
+ {
+ Py_DECREF(imp);
+ return -1;
+ }
+
+ Py_DECREF(imp);
+
+ ADD_OBJECT(m, "_find_spec", py_find_spec);
+#else
+ if (!(imp = PyImport_ImportModule("imp")))
+ return -1;
+
+ if (!(py_find_module = PyObject_GetAttrString(imp, "find_module")))
+ {
+ Py_DECREF(imp);
+ return -1;
+ }
+
+ if (!(py_load_module = PyObject_GetAttrString(imp, "load_module")))
+ {
+ Py_DECREF(py_find_module);
+ Py_DECREF(imp);
+ return -1;
+ }
+
+ Py_DECREF(imp);
+
+ ADD_OBJECT(m, "_find_module", py_find_module);
+ ADD_OBJECT(m, "_load_module", py_load_module);
+#endif
+
+ return 0;
+}
diff --git a/src/if_python.c b/src/if_python.c
new file mode 100644
index 0000000..3438046
--- /dev/null
+++ b/src/if_python.c
@@ -0,0 +1,1600 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+/*
+ * Python extensions by Paul Moore.
+ * Changes for Unix by David Leonard.
+ *
+ * This consists of four parts:
+ * 1. Python interpreter main program
+ * 2. Python output stream: writes output via [e]msg().
+ * 3. Implementation of the Vim module for Python
+ * 4. Utility functions for handling the interface between Vim and Python.
+ */
+
+#include "vim.h"
+
+#include <limits.h>
+
+/* uncomment this if used with the debug version of python.
+ * Checked on 2.7.4. */
+/* #define Py_DEBUG */
+/* Note: most of time you can add -DPy_DEBUG to CFLAGS in place of uncommenting
+ */
+/* uncomment this if used with the debug version of python, but without its
+ * allocator */
+/* #define Py_DEBUG_NO_PYMALLOC */
+
+/* Python.h defines _POSIX_THREADS itself (if needed) */
+#ifdef _POSIX_THREADS
+# undef _POSIX_THREADS
+#endif
+
+#if defined(_WIN32) && defined(HAVE_FCNTL_H)
+# undef HAVE_FCNTL_H
+#endif
+
+#ifdef _DEBUG
+# undef _DEBUG
+#endif
+
+#ifdef HAVE_STRFTIME
+# undef HAVE_STRFTIME
+#endif
+#ifdef HAVE_STRING_H
+# undef HAVE_STRING_H
+#endif
+#ifdef HAVE_PUTENV
+# undef HAVE_PUTENV
+#endif
+#ifdef HAVE_STDARG_H
+# undef HAVE_STDARG_H /* Python's config.h defines it as well. */
+#endif
+#ifdef _POSIX_C_SOURCE
+# undef _POSIX_C_SOURCE /* pyconfig.h defines it as well. */
+#endif
+#ifdef _XOPEN_SOURCE
+# undef _XOPEN_SOURCE /* pyconfig.h defines it as well. */
+#endif
+
+#define PY_SSIZE_T_CLEAN
+
+#include <Python.h>
+
+#if !defined(PY_VERSION_HEX) || PY_VERSION_HEX < 0x02050000
+# undef PY_SSIZE_T_CLEAN
+#endif
+
+#undef main /* Defined in python.h - aargh */
+#undef HAVE_FCNTL_H /* Clash with os_win32.h */
+
+// Perhaps leave this out for Python 2.6, which supports bytes?
+#define PyBytes_FromString PyString_FromString
+#define PyBytes_Check PyString_Check
+#define PyBytes_AsStringAndSize PyString_AsStringAndSize
+#define PyBytes_FromStringAndSize PyString_FromStringAndSize
+
+#if !defined(FEAT_PYTHON) && defined(PROTO)
+/* Use this to be able to generate prototypes without python being used. */
+# define PyObject Py_ssize_t
+# define PyThreadState Py_ssize_t
+# define PyTypeObject Py_ssize_t
+struct PyMethodDef { Py_ssize_t a; };
+# define PySequenceMethods Py_ssize_t
+#endif
+
+#if defined(PY_VERSION_HEX) && PY_VERSION_HEX >= 0x02070000
+# define PY_USE_CAPSULE
+#endif
+
+#if defined(PY_VERSION_HEX) && PY_VERSION_HEX >= 0x02050000
+# define PyInt Py_ssize_t
+# define PyInquiry lenfunc
+# define PyIntArgFunc ssizeargfunc
+# define PyIntIntArgFunc ssizessizeargfunc
+# define PyIntObjArgProc ssizeobjargproc
+# define PyIntIntObjArgProc ssizessizeobjargproc
+# define Py_ssize_t_fmt "n"
+#else
+# define PyInt int
+# define lenfunc inquiry
+# define PyInquiry inquiry
+# define PyIntArgFunc intargfunc
+# define PyIntIntArgFunc intintargfunc
+# define PyIntObjArgProc intobjargproc
+# define PyIntIntObjArgProc intintobjargproc
+# define Py_ssize_t_fmt "i"
+#endif
+#define Py_bytes_fmt "s"
+
+/* Parser flags */
+#define single_input 256
+#define file_input 257
+#define eval_input 258
+
+#if defined(PY_VERSION_HEX) && PY_VERSION_HEX >= 0x020300F0
+ /* Python 2.3: can invoke ":python" recursively. */
+# define PY_CAN_RECURSE
+#endif
+
+#if defined(DYNAMIC_PYTHON) || defined(PROTO)
+# ifndef DYNAMIC_PYTHON
+# define HINSTANCE long_u /* for generating prototypes */
+# endif
+
+# ifndef WIN3264
+# include <dlfcn.h>
+# define FARPROC void*
+# define HINSTANCE void*
+# if defined(PY_NO_RTLD_GLOBAL) && defined(PY3_NO_RTLD_GLOBAL)
+# define load_dll(n) dlopen((n), RTLD_LAZY)
+# else
+# define load_dll(n) dlopen((n), RTLD_LAZY|RTLD_GLOBAL)
+# endif
+# define close_dll dlclose
+# define symbol_from_dll dlsym
+# else
+# define load_dll vimLoadLib
+# define close_dll FreeLibrary
+# define symbol_from_dll GetProcAddress
+# endif
+
+/* This makes if_python.c compile without warnings against Python 2.5
+ * on Win32 and Win64. */
+# undef PyRun_SimpleString
+# undef PyRun_String
+# undef PyArg_Parse
+# undef PyArg_ParseTuple
+# undef Py_BuildValue
+# undef Py_InitModule4
+# undef Py_InitModule4_64
+# undef PyObject_CallMethod
+# undef PyObject_CallFunction
+
+/*
+ * Wrapper defines
+ */
+# define PyArg_Parse dll_PyArg_Parse
+# define PyArg_ParseTuple dll_PyArg_ParseTuple
+# define PyMem_Free dll_PyMem_Free
+# define PyMem_Malloc dll_PyMem_Malloc
+# define PyDict_SetItemString dll_PyDict_SetItemString
+# define PyErr_BadArgument dll_PyErr_BadArgument
+# define PyErr_NewException dll_PyErr_NewException
+# define PyErr_Clear dll_PyErr_Clear
+# define PyErr_Format dll_PyErr_Format
+# define PyErr_PrintEx dll_PyErr_PrintEx
+# define PyErr_NoMemory dll_PyErr_NoMemory
+# define PyErr_Occurred dll_PyErr_Occurred
+# define PyErr_SetNone dll_PyErr_SetNone
+# define PyErr_SetString dll_PyErr_SetString
+# define PyErr_SetObject dll_PyErr_SetObject
+# define PyErr_ExceptionMatches dll_PyErr_ExceptionMatches
+# define PyEval_InitThreads dll_PyEval_InitThreads
+# define PyEval_RestoreThread dll_PyEval_RestoreThread
+# define PyEval_SaveThread dll_PyEval_SaveThread
+# ifdef PY_CAN_RECURSE
+# define PyGILState_Ensure dll_PyGILState_Ensure
+# define PyGILState_Release dll_PyGILState_Release
+# endif
+# define PyInt_AsLong dll_PyInt_AsLong
+# define PyInt_FromLong dll_PyInt_FromLong
+# define PyLong_AsLong dll_PyLong_AsLong
+# define PyLong_FromLong dll_PyLong_FromLong
+# define PyBool_Type (*dll_PyBool_Type)
+# define PyInt_Type (*dll_PyInt_Type)
+# define PyLong_Type (*dll_PyLong_Type)
+# define PyList_GetItem dll_PyList_GetItem
+# define PyList_Append dll_PyList_Append
+# define PyList_Insert dll_PyList_Insert
+# define PyList_New dll_PyList_New
+# define PyList_SetItem dll_PyList_SetItem
+# define PyList_Size dll_PyList_Size
+# define PyList_Type (*dll_PyList_Type)
+# define PySequence_Check dll_PySequence_Check
+# define PySequence_Size dll_PySequence_Size
+# define PySequence_GetItem dll_PySequence_GetItem
+# define PySequence_Fast dll_PySequence_Fast
+# define PyTuple_Size dll_PyTuple_Size
+# define PyTuple_GetItem dll_PyTuple_GetItem
+# define PyTuple_Type (*dll_PyTuple_Type)
+# define PySlice_GetIndicesEx dll_PySlice_GetIndicesEx
+# define PyImport_ImportModule dll_PyImport_ImportModule
+# define PyDict_New dll_PyDict_New
+# define PyDict_GetItemString dll_PyDict_GetItemString
+# define PyDict_Next dll_PyDict_Next
+# define PyDict_Type (*dll_PyDict_Type)
+# ifdef PyMapping_Keys
+# define PY_NO_MAPPING_KEYS
+# else
+# define PyMapping_Keys dll_PyMapping_Keys
+# endif
+# define PyObject_GetItem dll_PyObject_GetItem
+# define PyObject_CallMethod dll_PyObject_CallMethod
+# define PyMapping_Check dll_PyMapping_Check
+# define PyIter_Next dll_PyIter_Next
+# define PyModule_GetDict dll_PyModule_GetDict
+# define PyModule_AddObject dll_PyModule_AddObject
+# define PyRun_SimpleString dll_PyRun_SimpleString
+# define PyRun_String dll_PyRun_String
+# define PyObject_GetAttrString dll_PyObject_GetAttrString
+# define PyObject_HasAttrString dll_PyObject_HasAttrString
+# define PyObject_SetAttrString dll_PyObject_SetAttrString
+# define PyObject_CallFunctionObjArgs dll_PyObject_CallFunctionObjArgs
+# define PyObject_CallFunction dll_PyObject_CallFunction
+# define PyObject_Call dll_PyObject_Call
+# define PyObject_Repr dll_PyObject_Repr
+# define PyString_AsString dll_PyString_AsString
+# define PyString_AsStringAndSize dll_PyString_AsStringAndSize
+# define PyString_FromString dll_PyString_FromString
+# define PyString_FromFormat dll_PyString_FromFormat
+# define PyString_FromStringAndSize dll_PyString_FromStringAndSize
+# define PyString_Size dll_PyString_Size
+# define PyString_Type (*dll_PyString_Type)
+# define PyUnicode_Type (*dll_PyUnicode_Type)
+# undef PyUnicode_AsEncodedString
+# define PyUnicode_AsEncodedString py_PyUnicode_AsEncodedString
+# define PyFloat_AsDouble dll_PyFloat_AsDouble
+# define PyFloat_FromDouble dll_PyFloat_FromDouble
+# define PyFloat_Type (*dll_PyFloat_Type)
+# define PyNumber_Check dll_PyNumber_Check
+# define PyNumber_Long dll_PyNumber_Long
+# define PyImport_AddModule (*dll_PyImport_AddModule)
+# define PySys_SetObject dll_PySys_SetObject
+# define PySys_GetObject dll_PySys_GetObject
+# define PySys_SetArgv dll_PySys_SetArgv
+# define PyType_Type (*dll_PyType_Type)
+# define PyFile_Type (*dll_PyFile_Type)
+# define PySlice_Type (*dll_PySlice_Type)
+# define PyType_Ready (*dll_PyType_Ready)
+# define PyType_GenericAlloc dll_PyType_GenericAlloc
+# define Py_BuildValue dll_Py_BuildValue
+# define Py_FindMethod dll_Py_FindMethod
+# define Py_InitModule4 dll_Py_InitModule4
+# define Py_SetPythonHome dll_Py_SetPythonHome
+# define Py_Initialize dll_Py_Initialize
+# define Py_Finalize dll_Py_Finalize
+# define Py_IsInitialized dll_Py_IsInitialized
+# define _PyObject_New dll__PyObject_New
+# define _PyObject_GC_New dll__PyObject_GC_New
+# ifdef PyObject_GC_Del
+# define Py_underscore_GC
+# define _PyObject_GC_Del dll__PyObject_GC_Del
+# define _PyObject_GC_UnTrack dll__PyObject_GC_UnTrack
+# else
+# define PyObject_GC_Del dll_PyObject_GC_Del
+# define PyObject_GC_UnTrack dll_PyObject_GC_UnTrack
+# endif
+# if defined(PY_VERSION_HEX) && PY_VERSION_HEX >= 0x02070000
+# define _PyObject_NextNotImplemented (*dll__PyObject_NextNotImplemented)
+# endif
+# define _Py_NoneStruct (*dll__Py_NoneStruct)
+# define _Py_ZeroStruct (*dll__Py_ZeroStruct)
+# define _Py_TrueStruct (*dll__Py_TrueStruct)
+# define PyObject_Init dll__PyObject_Init
+# define PyObject_GetIter dll_PyObject_GetIter
+# define PyObject_IsTrue dll_PyObject_IsTrue
+# if defined(PY_VERSION_HEX) && PY_VERSION_HEX >= 0x02020000
+# define PyType_IsSubtype dll_PyType_IsSubtype
+# ifdef Py_DEBUG
+# define _Py_NegativeRefcount dll__Py_NegativeRefcount
+# define _Py_RefTotal (*dll__Py_RefTotal)
+# define _Py_Dealloc dll__Py_Dealloc
+# endif
+# endif
+# if defined(PY_VERSION_HEX) && PY_VERSION_HEX >= 0x02030000
+# if defined(Py_DEBUG) && !defined(Py_DEBUG_NO_PYMALLOC)
+# define _PyObject_DebugMalloc dll__PyObject_DebugMalloc
+# define _PyObject_DebugFree dll__PyObject_DebugFree
+# else
+# define PyObject_Malloc dll_PyObject_Malloc
+# define PyObject_Free dll_PyObject_Free
+# endif
+# endif
+# ifdef PY_USE_CAPSULE
+# define PyCapsule_New dll_PyCapsule_New
+# define PyCapsule_GetPointer dll_PyCapsule_GetPointer
+# else
+# define PyCObject_FromVoidPtr dll_PyCObject_FromVoidPtr
+# define PyCObject_AsVoidPtr dll_PyCObject_AsVoidPtr
+# endif
+# if defined(PY_VERSION_HEX) && PY_VERSION_HEX >= 0x02070000
+# define Py_NoSiteFlag (*dll_Py_NoSiteFlag)
+# endif
+
+/*
+ * Pointers for dynamic link
+ */
+static int(*dll_PyArg_Parse)(PyObject *, char *, ...);
+static int(*dll_PyArg_ParseTuple)(PyObject *, char *, ...);
+static int(*dll_PyMem_Free)(void *);
+static void* (*dll_PyMem_Malloc)(size_t);
+static int(*dll_PyDict_SetItemString)(PyObject *dp, char *key, PyObject *item);
+static int(*dll_PyErr_BadArgument)(void);
+static PyObject *(*dll_PyErr_NewException)(char *, PyObject *, PyObject *);
+static void(*dll_PyErr_Clear)(void);
+static PyObject*(*dll_PyErr_Format)(PyObject *, const char *, ...);
+static void(*dll_PyErr_PrintEx)(int);
+static PyObject*(*dll_PyErr_NoMemory)(void);
+static PyObject*(*dll_PyErr_Occurred)(void);
+static void(*dll_PyErr_SetNone)(PyObject *);
+static void(*dll_PyErr_SetString)(PyObject *, const char *);
+static void(*dll_PyErr_SetObject)(PyObject *, PyObject *);
+static int(*dll_PyErr_ExceptionMatches)(PyObject *);
+static void(*dll_PyEval_InitThreads)(void);
+static void(*dll_PyEval_RestoreThread)(PyThreadState *);
+static PyThreadState*(*dll_PyEval_SaveThread)(void);
+# ifdef PY_CAN_RECURSE
+static PyGILState_STATE (*dll_PyGILState_Ensure)(void);
+static void (*dll_PyGILState_Release)(PyGILState_STATE);
+# endif
+static long(*dll_PyInt_AsLong)(PyObject *);
+static PyObject*(*dll_PyInt_FromLong)(long);
+static long(*dll_PyLong_AsLong)(PyObject *);
+static PyObject*(*dll_PyLong_FromLong)(long);
+static PyTypeObject* dll_PyBool_Type;
+static PyTypeObject* dll_PyInt_Type;
+static PyTypeObject* dll_PyLong_Type;
+static PyObject*(*dll_PyList_GetItem)(PyObject *, PyInt);
+static int(*dll_PyList_Append)(PyObject *, PyObject *);
+static int(*dll_PyList_Insert)(PyObject *, PyInt, PyObject *);
+static PyObject*(*dll_PyList_New)(PyInt size);
+static int(*dll_PyList_SetItem)(PyObject *, PyInt, PyObject *);
+static PyInt(*dll_PyList_Size)(PyObject *);
+static PyTypeObject* dll_PyList_Type;
+static int (*dll_PySequence_Check)(PyObject *);
+static PyInt(*dll_PySequence_Size)(PyObject *);
+static PyObject*(*dll_PySequence_GetItem)(PyObject *, PyInt);
+static PyObject*(*dll_PySequence_Fast)(PyObject *, const char *);
+static PyInt(*dll_PyTuple_Size)(PyObject *);
+static PyObject*(*dll_PyTuple_GetItem)(PyObject *, PyInt);
+static PyTypeObject* dll_PyTuple_Type;
+static int (*dll_PySlice_GetIndicesEx)(PySliceObject *r, PyInt length,
+ PyInt *start, PyInt *stop, PyInt *step,
+ PyInt *slicelen);
+static PyObject*(*dll_PyImport_ImportModule)(const char *);
+static PyObject*(*dll_PyDict_New)(void);
+static PyObject*(*dll_PyDict_GetItemString)(PyObject *, const char *);
+static int (*dll_PyDict_Next)(PyObject *, PyInt *, PyObject **, PyObject **);
+static PyTypeObject* dll_PyDict_Type;
+# ifndef PY_NO_MAPPING_KEYS
+static PyObject* (*dll_PyMapping_Keys)(PyObject *);
+# endif
+static PyObject* (*dll_PyObject_GetItem)(PyObject *, PyObject *);
+static PyObject* (*dll_PyObject_CallMethod)(PyObject *, char *, PyObject *);
+static int (*dll_PyMapping_Check)(PyObject *);
+static PyObject* (*dll_PyIter_Next)(PyObject *);
+static PyObject*(*dll_PyModule_GetDict)(PyObject *);
+static int(*dll_PyModule_AddObject)(PyObject *, const char *, PyObject *);
+static int(*dll_PyRun_SimpleString)(char *);
+static PyObject *(*dll_PyRun_String)(char *, int, PyObject *, PyObject *);
+static PyObject* (*dll_PyObject_GetAttrString)(PyObject *, const char *);
+static int (*dll_PyObject_HasAttrString)(PyObject *, const char *);
+static int (*dll_PyObject_SetAttrString)(PyObject *, const char *, PyObject *);
+static PyObject* (*dll_PyObject_CallFunctionObjArgs)(PyObject *, ...);
+static PyObject* (*dll_PyObject_CallFunction)(PyObject *, char *, ...);
+static PyObject* (*dll_PyObject_Call)(PyObject *, PyObject *, PyObject *);
+static PyObject* (*dll_PyObject_Repr)(PyObject *);
+static char*(*dll_PyString_AsString)(PyObject *);
+static int(*dll_PyString_AsStringAndSize)(PyObject *, char **, PyInt *);
+static PyObject*(*dll_PyString_FromString)(const char *);
+static PyObject*(*dll_PyString_FromFormat)(const char *, ...);
+static PyObject*(*dll_PyString_FromStringAndSize)(const char *, PyInt);
+static PyInt(*dll_PyString_Size)(PyObject *);
+static PyTypeObject* dll_PyString_Type;
+static PyTypeObject* dll_PyUnicode_Type;
+static PyObject *(*py_PyUnicode_AsEncodedString)(PyObject *, char *, char *);
+static double(*dll_PyFloat_AsDouble)(PyObject *);
+static PyObject*(*dll_PyFloat_FromDouble)(double);
+static PyTypeObject* dll_PyFloat_Type;
+static int(*dll_PyNumber_Check)(PyObject *);
+static PyObject*(*dll_PyNumber_Long)(PyObject *);
+static int(*dll_PySys_SetObject)(char *, PyObject *);
+static PyObject *(*dll_PySys_GetObject)(char *);
+static int(*dll_PySys_SetArgv)(int, char **);
+static PyTypeObject* dll_PyType_Type;
+static PyTypeObject* dll_PyFile_Type;
+static PyTypeObject* dll_PySlice_Type;
+static int (*dll_PyType_Ready)(PyTypeObject *type);
+static PyObject* (*dll_PyType_GenericAlloc)(PyTypeObject *type, PyInt nitems);
+static PyObject*(*dll_Py_BuildValue)(char *, ...);
+static PyObject*(*dll_Py_FindMethod)(struct PyMethodDef[], PyObject *, char *);
+static PyObject*(*dll_Py_InitModule4)(char *, struct PyMethodDef *, char *, PyObject *, int);
+static PyObject*(*dll_PyImport_AddModule)(char *);
+static void(*dll_Py_SetPythonHome)(char *home);
+static void(*dll_Py_Initialize)(void);
+static void(*dll_Py_Finalize)(void);
+static int(*dll_Py_IsInitialized)(void);
+static PyObject*(*dll__PyObject_New)(PyTypeObject *, PyObject *);
+static PyObject*(*dll__PyObject_GC_New)(PyTypeObject *);
+# ifdef Py_underscore_GC
+static void(*dll__PyObject_GC_Del)(void *);
+static void(*dll__PyObject_GC_UnTrack)(void *);
+# else
+static void(*dll_PyObject_GC_Del)(void *);
+static void(*dll_PyObject_GC_UnTrack)(void *);
+# endif
+static PyObject*(*dll__PyObject_Init)(PyObject *, PyTypeObject *);
+static PyObject* (*dll_PyObject_GetIter)(PyObject *);
+static int (*dll_PyObject_IsTrue)(PyObject *);
+# if defined(PY_VERSION_HEX) && PY_VERSION_HEX >= 0x02070000
+static iternextfunc dll__PyObject_NextNotImplemented;
+# endif
+static PyObject* dll__Py_NoneStruct;
+static PyObject* _Py_ZeroStruct;
+static PyObject* dll__Py_TrueStruct;
+# if defined(PY_VERSION_HEX) && PY_VERSION_HEX >= 0x02020000
+static int (*dll_PyType_IsSubtype)(PyTypeObject *, PyTypeObject *);
+# ifdef Py_DEBUG
+static void (*dll__Py_NegativeRefcount)(const char *fname, int lineno, PyObject *op);
+static PyInt* dll__Py_RefTotal;
+static void (*dll__Py_Dealloc)(PyObject *obj);
+# endif
+# endif
+# if defined(PY_VERSION_HEX) && PY_VERSION_HEX >= 0x02030000
+# if defined(Py_DEBUG) && !defined(Py_DEBUG_NO_PYMALLOC)
+static void (*dll__PyObject_DebugFree)(void*);
+static void* (*dll__PyObject_DebugMalloc)(size_t);
+# else
+static void* (*dll_PyObject_Malloc)(size_t);
+static void (*dll_PyObject_Free)(void*);
+# endif
+# endif
+# ifdef PY_USE_CAPSULE
+static PyObject* (*dll_PyCapsule_New)(void *, char *, PyCapsule_Destructor);
+static void* (*dll_PyCapsule_GetPointer)(PyObject *, char *);
+# else
+static PyObject* (*dll_PyCObject_FromVoidPtr)(void *cobj, void (*destr)(void *));
+static void* (*dll_PyCObject_AsVoidPtr)(PyObject *);
+# endif
+# if defined(PY_VERSION_HEX) && PY_VERSION_HEX >= 0x02070000
+static int* dll_Py_NoSiteFlag;
+# endif
+
+static HINSTANCE hinstPython = 0; /* Instance of python.dll */
+
+/* Imported exception objects */
+static PyObject *imp_PyExc_AttributeError;
+static PyObject *imp_PyExc_IndexError;
+static PyObject *imp_PyExc_KeyError;
+static PyObject *imp_PyExc_KeyboardInterrupt;
+static PyObject *imp_PyExc_TypeError;
+static PyObject *imp_PyExc_ValueError;
+static PyObject *imp_PyExc_SystemExit;
+static PyObject *imp_PyExc_RuntimeError;
+static PyObject *imp_PyExc_ImportError;
+static PyObject *imp_PyExc_OverflowError;
+
+# define PyExc_AttributeError imp_PyExc_AttributeError
+# define PyExc_IndexError imp_PyExc_IndexError
+# define PyExc_KeyError imp_PyExc_KeyError
+# define PyExc_KeyboardInterrupt imp_PyExc_KeyboardInterrupt
+# define PyExc_TypeError imp_PyExc_TypeError
+# define PyExc_ValueError imp_PyExc_ValueError
+# define PyExc_SystemExit imp_PyExc_SystemExit
+# define PyExc_RuntimeError imp_PyExc_RuntimeError
+# define PyExc_ImportError imp_PyExc_ImportError
+# define PyExc_OverflowError imp_PyExc_OverflowError
+
+/*
+ * Table of name to function pointer of python.
+ */
+# define PYTHON_PROC FARPROC
+static struct
+{
+ char *name;
+ PYTHON_PROC *ptr;
+} python_funcname_table[] =
+{
+# ifndef PY_SSIZE_T_CLEAN
+ {"PyArg_Parse", (PYTHON_PROC*)&dll_PyArg_Parse},
+ {"PyArg_ParseTuple", (PYTHON_PROC*)&dll_PyArg_ParseTuple},
+ {"Py_BuildValue", (PYTHON_PROC*)&dll_Py_BuildValue},
+# else
+ {"_PyArg_Parse_SizeT", (PYTHON_PROC*)&dll_PyArg_Parse},
+ {"_PyArg_ParseTuple_SizeT", (PYTHON_PROC*)&dll_PyArg_ParseTuple},
+ {"_Py_BuildValue_SizeT", (PYTHON_PROC*)&dll_Py_BuildValue},
+# endif
+ {"PyMem_Free", (PYTHON_PROC*)&dll_PyMem_Free},
+ {"PyMem_Malloc", (PYTHON_PROC*)&dll_PyMem_Malloc},
+ {"PyDict_SetItemString", (PYTHON_PROC*)&dll_PyDict_SetItemString},
+ {"PyErr_BadArgument", (PYTHON_PROC*)&dll_PyErr_BadArgument},
+ {"PyErr_NewException", (PYTHON_PROC*)&dll_PyErr_NewException},
+ {"PyErr_Clear", (PYTHON_PROC*)&dll_PyErr_Clear},
+ {"PyErr_Format", (PYTHON_PROC*)&dll_PyErr_Format},
+ {"PyErr_PrintEx", (PYTHON_PROC*)&dll_PyErr_PrintEx},
+ {"PyErr_NoMemory", (PYTHON_PROC*)&dll_PyErr_NoMemory},
+ {"PyErr_Occurred", (PYTHON_PROC*)&dll_PyErr_Occurred},
+ {"PyErr_SetNone", (PYTHON_PROC*)&dll_PyErr_SetNone},
+ {"PyErr_SetString", (PYTHON_PROC*)&dll_PyErr_SetString},
+ {"PyErr_SetObject", (PYTHON_PROC*)&dll_PyErr_SetObject},
+ {"PyErr_ExceptionMatches", (PYTHON_PROC*)&dll_PyErr_ExceptionMatches},
+ {"PyEval_InitThreads", (PYTHON_PROC*)&dll_PyEval_InitThreads},
+ {"PyEval_RestoreThread", (PYTHON_PROC*)&dll_PyEval_RestoreThread},
+ {"PyEval_SaveThread", (PYTHON_PROC*)&dll_PyEval_SaveThread},
+# ifdef PY_CAN_RECURSE
+ {"PyGILState_Ensure", (PYTHON_PROC*)&dll_PyGILState_Ensure},
+ {"PyGILState_Release", (PYTHON_PROC*)&dll_PyGILState_Release},
+# endif
+ {"PyInt_AsLong", (PYTHON_PROC*)&dll_PyInt_AsLong},
+ {"PyInt_FromLong", (PYTHON_PROC*)&dll_PyInt_FromLong},
+ {"PyLong_AsLong", (PYTHON_PROC*)&dll_PyLong_AsLong},
+ {"PyLong_FromLong", (PYTHON_PROC*)&dll_PyLong_FromLong},
+ {"PyBool_Type", (PYTHON_PROC*)&dll_PyBool_Type},
+ {"PyInt_Type", (PYTHON_PROC*)&dll_PyInt_Type},
+ {"PyLong_Type", (PYTHON_PROC*)&dll_PyLong_Type},
+ {"PyList_GetItem", (PYTHON_PROC*)&dll_PyList_GetItem},
+ {"PyList_Append", (PYTHON_PROC*)&dll_PyList_Append},
+ {"PyList_Insert", (PYTHON_PROC*)&dll_PyList_Insert},
+ {"PyList_New", (PYTHON_PROC*)&dll_PyList_New},
+ {"PyList_SetItem", (PYTHON_PROC*)&dll_PyList_SetItem},
+ {"PyList_Size", (PYTHON_PROC*)&dll_PyList_Size},
+ {"PyList_Type", (PYTHON_PROC*)&dll_PyList_Type},
+ {"PySequence_Size", (PYTHON_PROC*)&dll_PySequence_Size},
+ {"PySequence_Check", (PYTHON_PROC*)&dll_PySequence_Check},
+ {"PySequence_GetItem", (PYTHON_PROC*)&dll_PySequence_GetItem},
+ {"PySequence_Fast", (PYTHON_PROC*)&dll_PySequence_Fast},
+ {"PyTuple_GetItem", (PYTHON_PROC*)&dll_PyTuple_GetItem},
+ {"PyTuple_Size", (PYTHON_PROC*)&dll_PyTuple_Size},
+ {"PyTuple_Type", (PYTHON_PROC*)&dll_PyTuple_Type},
+ {"PySlice_GetIndicesEx", (PYTHON_PROC*)&dll_PySlice_GetIndicesEx},
+ {"PyImport_ImportModule", (PYTHON_PROC*)&dll_PyImport_ImportModule},
+ {"PyDict_GetItemString", (PYTHON_PROC*)&dll_PyDict_GetItemString},
+ {"PyDict_Next", (PYTHON_PROC*)&dll_PyDict_Next},
+ {"PyDict_New", (PYTHON_PROC*)&dll_PyDict_New},
+ {"PyDict_Type", (PYTHON_PROC*)&dll_PyDict_Type},
+# ifndef PY_NO_MAPPING_KEYS
+ {"PyMapping_Keys", (PYTHON_PROC*)&dll_PyMapping_Keys},
+# endif
+ {"PyObject_GetItem", (PYTHON_PROC*)&dll_PyObject_GetItem},
+ {"PyObject_CallMethod", (PYTHON_PROC*)&dll_PyObject_CallMethod},
+ {"PyMapping_Check", (PYTHON_PROC*)&dll_PyMapping_Check},
+ {"PyIter_Next", (PYTHON_PROC*)&dll_PyIter_Next},
+ {"PyModule_GetDict", (PYTHON_PROC*)&dll_PyModule_GetDict},
+ {"PyModule_AddObject", (PYTHON_PROC*)&dll_PyModule_AddObject},
+ {"PyRun_SimpleString", (PYTHON_PROC*)&dll_PyRun_SimpleString},
+ {"PyRun_String", (PYTHON_PROC*)&dll_PyRun_String},
+ {"PyObject_GetAttrString", (PYTHON_PROC*)&dll_PyObject_GetAttrString},
+ {"PyObject_HasAttrString", (PYTHON_PROC*)&dll_PyObject_HasAttrString},
+ {"PyObject_SetAttrString", (PYTHON_PROC*)&dll_PyObject_SetAttrString},
+ {"PyObject_CallFunctionObjArgs", (PYTHON_PROC*)&dll_PyObject_CallFunctionObjArgs},
+ {"PyObject_CallFunction", (PYTHON_PROC*)&dll_PyObject_CallFunction},
+ {"PyObject_Call", (PYTHON_PROC*)&dll_PyObject_Call},
+ {"PyObject_Repr", (PYTHON_PROC*)&dll_PyObject_Repr},
+ {"PyString_AsString", (PYTHON_PROC*)&dll_PyString_AsString},
+ {"PyString_AsStringAndSize", (PYTHON_PROC*)&dll_PyString_AsStringAndSize},
+ {"PyString_FromString", (PYTHON_PROC*)&dll_PyString_FromString},
+ {"PyString_FromFormat", (PYTHON_PROC*)&dll_PyString_FromFormat},
+ {"PyString_FromStringAndSize", (PYTHON_PROC*)&dll_PyString_FromStringAndSize},
+ {"PyString_Size", (PYTHON_PROC*)&dll_PyString_Size},
+ {"PyString_Type", (PYTHON_PROC*)&dll_PyString_Type},
+ {"PyUnicode_Type", (PYTHON_PROC*)&dll_PyUnicode_Type},
+ {"PyFloat_Type", (PYTHON_PROC*)&dll_PyFloat_Type},
+ {"PyFloat_AsDouble", (PYTHON_PROC*)&dll_PyFloat_AsDouble},
+ {"PyFloat_FromDouble", (PYTHON_PROC*)&dll_PyFloat_FromDouble},
+ {"PyImport_AddModule", (PYTHON_PROC*)&dll_PyImport_AddModule},
+ {"PyNumber_Check", (PYTHON_PROC*)&dll_PyNumber_Check},
+ {"PyNumber_Long", (PYTHON_PROC*)&dll_PyNumber_Long},
+ {"PySys_SetObject", (PYTHON_PROC*)&dll_PySys_SetObject},
+ {"PySys_GetObject", (PYTHON_PROC*)&dll_PySys_GetObject},
+ {"PySys_SetArgv", (PYTHON_PROC*)&dll_PySys_SetArgv},
+ {"PyType_Type", (PYTHON_PROC*)&dll_PyType_Type},
+ {"PyFile_Type", (PYTHON_PROC*)&dll_PyFile_Type},
+ {"PySlice_Type", (PYTHON_PROC*)&dll_PySlice_Type},
+ {"PyType_Ready", (PYTHON_PROC*)&dll_PyType_Ready},
+ {"PyType_GenericAlloc", (PYTHON_PROC*)&dll_PyType_GenericAlloc},
+ {"Py_FindMethod", (PYTHON_PROC*)&dll_Py_FindMethod},
+ {"Py_SetPythonHome", (PYTHON_PROC*)&dll_Py_SetPythonHome},
+ {"Py_Initialize", (PYTHON_PROC*)&dll_Py_Initialize},
+ {"Py_Finalize", (PYTHON_PROC*)&dll_Py_Finalize},
+ {"Py_IsInitialized", (PYTHON_PROC*)&dll_Py_IsInitialized},
+ {"_PyObject_New", (PYTHON_PROC*)&dll__PyObject_New},
+ {"_PyObject_GC_New", (PYTHON_PROC*)&dll__PyObject_GC_New},
+# ifdef Py_underscore_GC
+ {"_PyObject_GC_Del", (PYTHON_PROC*)&dll__PyObject_GC_Del},
+ {"_PyObject_GC_UnTrack", (PYTHON_PROC*)&dll__PyObject_GC_UnTrack},
+# else
+ {"PyObject_GC_Del", (PYTHON_PROC*)&dll_PyObject_GC_Del},
+ {"PyObject_GC_UnTrack", (PYTHON_PROC*)&dll_PyObject_GC_UnTrack},
+# endif
+ {"PyObject_Init", (PYTHON_PROC*)&dll__PyObject_Init},
+ {"PyObject_GetIter", (PYTHON_PROC*)&dll_PyObject_GetIter},
+ {"PyObject_IsTrue", (PYTHON_PROC*)&dll_PyObject_IsTrue},
+# if defined(PY_VERSION_HEX) && PY_VERSION_HEX >= 0x02070000
+ {"_PyObject_NextNotImplemented", (PYTHON_PROC*)&dll__PyObject_NextNotImplemented},
+# endif
+ {"_Py_NoneStruct", (PYTHON_PROC*)&dll__Py_NoneStruct},
+ {"_Py_ZeroStruct", (PYTHON_PROC*)&dll__Py_ZeroStruct},
+ {"_Py_TrueStruct", (PYTHON_PROC*)&dll__Py_TrueStruct},
+# if defined(PY_VERSION_HEX) && PY_VERSION_HEX >= 0x02020000
+# ifdef Py_DEBUG
+ {"_Py_NegativeRefcount", (PYTHON_PROC*)&dll__Py_NegativeRefcount},
+ {"_Py_RefTotal", (PYTHON_PROC*)&dll__Py_RefTotal},
+ {"_Py_Dealloc", (PYTHON_PROC*)&dll__Py_Dealloc},
+# endif
+ {"PyType_IsSubtype", (PYTHON_PROC*)&dll_PyType_IsSubtype},
+# endif
+# if defined(PY_VERSION_HEX) && PY_VERSION_HEX >= 0x02030000
+# if defined(Py_DEBUG) && !defined(Py_DEBUG_NO_PYMALLOC)
+ {"_PyObject_DebugFree", (PYTHON_PROC*)&dll__PyObject_DebugFree},
+ {"_PyObject_DebugMalloc", (PYTHON_PROC*)&dll__PyObject_DebugMalloc},
+# else
+ {"PyObject_Malloc", (PYTHON_PROC*)&dll_PyObject_Malloc},
+ {"PyObject_Free", (PYTHON_PROC*)&dll_PyObject_Free},
+# endif
+# endif
+# if defined(PY_VERSION_HEX) && PY_VERSION_HEX >= 0x02050000 \
+ && SIZEOF_SIZE_T != VIM_SIZEOF_INT
+# ifdef Py_DEBUG
+ {"Py_InitModule4TraceRefs_64", (PYTHON_PROC*)&dll_Py_InitModule4},
+# else
+ {"Py_InitModule4_64", (PYTHON_PROC*)&dll_Py_InitModule4},
+# endif
+# else
+# ifdef Py_DEBUG
+ {"Py_InitModule4TraceRefs", (PYTHON_PROC*)&dll_Py_InitModule4},
+# else
+ {"Py_InitModule4", (PYTHON_PROC*)&dll_Py_InitModule4},
+# endif
+# endif
+# ifdef PY_USE_CAPSULE
+ {"PyCapsule_New", (PYTHON_PROC*)&dll_PyCapsule_New},
+ {"PyCapsule_GetPointer", (PYTHON_PROC*)&dll_PyCapsule_GetPointer},
+# else
+ {"PyCObject_FromVoidPtr", (PYTHON_PROC*)&dll_PyCObject_FromVoidPtr},
+ {"PyCObject_AsVoidPtr", (PYTHON_PROC*)&dll_PyCObject_AsVoidPtr},
+# endif
+# if defined(PY_VERSION_HEX) && PY_VERSION_HEX >= 0x02070000
+ {"Py_NoSiteFlag", (PYTHON_PROC*)&dll_Py_NoSiteFlag},
+# endif
+ {"", NULL},
+};
+
+/*
+ * Free python.dll
+ */
+ static void
+end_dynamic_python(void)
+{
+ if (hinstPython)
+ {
+ close_dll(hinstPython);
+ hinstPython = 0;
+ }
+}
+
+/*
+ * Load library and get all pointers.
+ * Parameter 'libname' provides name of DLL.
+ * Return OK or FAIL.
+ */
+ static int
+python_runtime_link_init(char *libname, int verbose)
+{
+ int i;
+ PYTHON_PROC *ucs_as_encoded_string =
+ (PYTHON_PROC*)&py_PyUnicode_AsEncodedString;
+
+# if !(defined(PY_NO_RTLD_GLOBAL) && defined(PY3_NO_RTLD_GLOBAL)) && defined(UNIX) && defined(FEAT_PYTHON3)
+ /* Can't have Python and Python3 loaded at the same time.
+ * It cause a crash, because RTLD_GLOBAL is needed for
+ * standard C extension libraries of one or both python versions. */
+ if (python3_loaded())
+ {
+ if (verbose)
+ emsg(_("E836: This Vim cannot execute :python after using :py3"));
+ return FAIL;
+ }
+# endif
+
+ if (hinstPython)
+ return OK;
+ hinstPython = load_dll(libname);
+ if (!hinstPython)
+ {
+ if (verbose)
+ semsg(_(e_loadlib), libname);
+ return FAIL;
+ }
+
+ for (i = 0; python_funcname_table[i].ptr; ++i)
+ {
+ if ((*python_funcname_table[i].ptr = symbol_from_dll(hinstPython,
+ python_funcname_table[i].name)) == NULL)
+ {
+ close_dll(hinstPython);
+ hinstPython = 0;
+ if (verbose)
+ semsg(_(e_loadfunc), python_funcname_table[i].name);
+ return FAIL;
+ }
+ }
+
+ /* Load unicode functions separately as only the ucs2 or the ucs4 functions
+ * will be present in the library. */
+ *ucs_as_encoded_string = symbol_from_dll(hinstPython,
+ "PyUnicodeUCS2_AsEncodedString");
+ if (*ucs_as_encoded_string == NULL)
+ *ucs_as_encoded_string = symbol_from_dll(hinstPython,
+ "PyUnicodeUCS4_AsEncodedString");
+ if (*ucs_as_encoded_string == NULL)
+ {
+ close_dll(hinstPython);
+ hinstPython = 0;
+ if (verbose)
+ semsg(_(e_loadfunc), "PyUnicode_UCSX_*");
+ return FAIL;
+ }
+
+ return OK;
+}
+
+/*
+ * If python is enabled (there is installed python on Windows system) return
+ * TRUE, else FALSE.
+ */
+ int
+python_enabled(int verbose)
+{
+ return python_runtime_link_init((char *)p_pydll, verbose) == OK;
+}
+
+/*
+ * Load the standard Python exceptions - don't import the symbols from the
+ * DLL, as this can cause errors (importing data symbols is not reliable).
+ */
+ static void
+get_exceptions(void)
+{
+ PyObject *exmod = PyImport_ImportModule("exceptions");
+ PyObject *exdict = PyModule_GetDict(exmod);
+ imp_PyExc_AttributeError = PyDict_GetItemString(exdict, "AttributeError");
+ imp_PyExc_IndexError = PyDict_GetItemString(exdict, "IndexError");
+ imp_PyExc_KeyError = PyDict_GetItemString(exdict, "KeyError");
+ imp_PyExc_KeyboardInterrupt = PyDict_GetItemString(exdict, "KeyboardInterrupt");
+ imp_PyExc_TypeError = PyDict_GetItemString(exdict, "TypeError");
+ imp_PyExc_ValueError = PyDict_GetItemString(exdict, "ValueError");
+ imp_PyExc_SystemExit = PyDict_GetItemString(exdict, "SystemExit");
+ imp_PyExc_RuntimeError = PyDict_GetItemString(exdict, "RuntimeError");
+ imp_PyExc_ImportError = PyDict_GetItemString(exdict, "ImportError");
+ imp_PyExc_OverflowError = PyDict_GetItemString(exdict, "OverflowError");
+ Py_XINCREF(imp_PyExc_AttributeError);
+ Py_XINCREF(imp_PyExc_IndexError);
+ Py_XINCREF(imp_PyExc_KeyError);
+ Py_XINCREF(imp_PyExc_KeyboardInterrupt);
+ Py_XINCREF(imp_PyExc_TypeError);
+ Py_XINCREF(imp_PyExc_ValueError);
+ Py_XINCREF(imp_PyExc_SystemExit);
+ Py_XINCREF(imp_PyExc_RuntimeError);
+ Py_XINCREF(imp_PyExc_ImportError);
+ Py_XINCREF(imp_PyExc_OverflowError);
+ Py_XDECREF(exmod);
+}
+#endif /* DYNAMIC_PYTHON */
+
+static int initialised = 0;
+#define PYINITIALISED initialised
+static int python_end_called = FALSE;
+
+#define DESTRUCTOR_FINISH(self) self->ob_type->tp_free((PyObject*)self);
+
+#define WIN_PYTHON_REF(win) win->w_python_ref
+#define BUF_PYTHON_REF(buf) buf->b_python_ref
+#define TAB_PYTHON_REF(tab) tab->tp_python_ref
+
+static PyObject *OutputGetattr(PyObject *, char *);
+static PyObject *BufferGetattr(PyObject *, char *);
+static PyObject *WindowGetattr(PyObject *, char *);
+static PyObject *TabPageGetattr(PyObject *, char *);
+static PyObject *RangeGetattr(PyObject *, char *);
+static PyObject *DictionaryGetattr(PyObject *, char*);
+static PyObject *ListGetattr(PyObject *, char *);
+static PyObject *FunctionGetattr(PyObject *, char *);
+
+#ifndef Py_VISIT
+# define Py_VISIT(obj) visit(obj, arg)
+#endif
+#ifndef Py_CLEAR
+# define Py_CLEAR(obj) \
+ { \
+ Py_XDECREF(obj); \
+ obj = NULL; \
+ }
+#endif
+
+#if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
+ static void *
+py_memsave(void *p, size_t len)
+{
+ void *r;
+
+ if (!(r = PyMem_Malloc(len)))
+ return NULL;
+ mch_memmove(r, p, len);
+ return r;
+}
+
+# define PY_STRSAVE(s) ((char_u *) py_memsave(s, STRLEN(s) + 1))
+#endif
+
+typedef PySliceObject PySliceObject_T;
+
+/*
+ * Include the code shared with if_python3.c
+ */
+#include "if_py_both.h"
+
+
+/******************************************************
+ * Internal function prototypes.
+ */
+
+static int PythonMod_Init(void);
+
+
+/******************************************************
+ * 1. Python interpreter main program.
+ */
+
+#if PYTHON_API_VERSION < 1007 /* Python 1.4 */
+typedef PyObject PyThreadState;
+#endif
+
+#ifndef PY_CAN_RECURSE
+static PyThreadState *saved_python_thread = NULL;
+
+/*
+ * Suspend a thread of the Python interpreter, other threads are allowed to
+ * run.
+ */
+ static void
+Python_SaveThread(void)
+{
+ saved_python_thread = PyEval_SaveThread();
+}
+
+/*
+ * Restore a thread of the Python interpreter, waits for other threads to
+ * block.
+ */
+ static void
+Python_RestoreThread(void)
+{
+ PyEval_RestoreThread(saved_python_thread);
+ saved_python_thread = NULL;
+}
+#endif
+
+ void
+python_end(void)
+{
+ static int recurse = 0;
+
+ /* If a crash occurs while doing this, don't try again. */
+ if (recurse != 0)
+ return;
+
+ python_end_called = TRUE;
+ ++recurse;
+
+#ifdef DYNAMIC_PYTHON
+ if (hinstPython && Py_IsInitialized())
+ {
+# ifdef PY_CAN_RECURSE
+ PyGILState_Ensure();
+# else
+ Python_RestoreThread(); /* enter python */
+# endif
+ Py_Finalize();
+ }
+ end_dynamic_python();
+#else
+ if (Py_IsInitialized())
+ {
+# ifdef PY_CAN_RECURSE
+ PyGILState_Ensure();
+# else
+ Python_RestoreThread(); /* enter python */
+# endif
+ Py_Finalize();
+ }
+#endif
+
+ --recurse;
+}
+
+#if (defined(DYNAMIC_PYTHON) && defined(FEAT_PYTHON3)) || defined(PROTO)
+ int
+python_loaded(void)
+{
+ return (hinstPython != 0);
+}
+#endif
+
+static char *py_home_buf = NULL;
+
+ static int
+Python_Init(void)
+{
+ if (!initialised)
+ {
+#if defined(PY_VERSION_HEX) && PY_VERSION_HEX >= 0x02070000
+ PyObject *site;
+#endif
+
+#ifdef DYNAMIC_PYTHON
+ if (!python_enabled(TRUE))
+ {
+ emsg(_("E263: Sorry, this command is disabled, the Python library could not be loaded."));
+ goto fail;
+ }
+#endif
+
+ if (*p_pyhome != NUL)
+ {
+ /* The string must not change later, make a copy in static memory. */
+ py_home_buf = (char *)vim_strsave(p_pyhome);
+ if (py_home_buf != NULL)
+ Py_SetPythonHome(py_home_buf);
+ }
+#ifdef PYTHON_HOME
+ else if (mch_getenv((char_u *)"PYTHONHOME") == NULL)
+ Py_SetPythonHome(PYTHON_HOME);
+#endif
+
+ init_structs();
+
+#if defined(PY_VERSION_HEX) && PY_VERSION_HEX >= 0x02070000
+ /* Disable implicit 'import site', because it may cause Vim to exit
+ * when it can't be found. */
+ Py_NoSiteFlag++;
+#endif
+
+ Py_Initialize();
+
+#if defined(PY_VERSION_HEX) && PY_VERSION_HEX >= 0x02070000
+ /* 'import site' explicitly. */
+ site = PyImport_ImportModule("site");
+ if (site == NULL)
+ {
+ emsg(_("E887: Sorry, this command is disabled, the Python's site module could not be loaded."));
+ goto fail;
+ }
+ Py_DECREF(site);
+#endif
+
+ /* Initialise threads, and below save the state using
+ * PyEval_SaveThread. Without the call to PyEval_SaveThread, thread
+ * specific state (such as the system trace hook), will be lost
+ * between invocations of Python code. */
+ PyEval_InitThreads();
+#ifdef DYNAMIC_PYTHON
+ get_exceptions();
+#endif
+
+ if (PythonIO_Init_io())
+ goto fail;
+
+ if (PythonMod_Init())
+ goto fail;
+
+ globals = PyModule_GetDict(PyImport_AddModule("__main__"));
+
+ /* Remove the element from sys.path that was added because of our
+ * argv[0] value in PythonMod_Init(). Previously we used an empty
+ * string, but depending on the OS we then get an empty entry or
+ * the current directory in sys.path. */
+ PyRun_SimpleString("import sys; sys.path = filter(lambda x: x != '/must>not&exist', sys.path)");
+
+ /* lock is created and acquired in PyEval_InitThreads() and thread
+ * state is created in Py_Initialize()
+ * there _PyGILState_NoteThreadState() also sets gilcounter to 1
+ * (python must have threads enabled!)
+ * so the following does both: unlock GIL and save thread state in TLS
+ * without deleting thread state
+ */
+#ifndef PY_CAN_RECURSE
+ saved_python_thread =
+#endif
+ PyEval_SaveThread();
+
+ initialised = 1;
+ }
+
+ return 0;
+
+fail:
+ /* We call PythonIO_Flush() here to print any Python errors.
+ * This is OK, as it is possible to call this function even
+ * if PythonIO_Init_io() has not completed successfully (it will
+ * not do anything in this case).
+ */
+ PythonIO_Flush();
+ return -1;
+}
+
+/*
+ * External interface
+ */
+ static void
+DoPyCommand(const char *cmd, rangeinitializer init_range, runner run, void *arg)
+{
+#ifndef PY_CAN_RECURSE
+ static int recursive = 0;
+#endif
+#if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
+ char *saved_locale;
+#endif
+#ifdef PY_CAN_RECURSE
+ PyGILState_STATE pygilstate;
+#endif
+
+#ifndef PY_CAN_RECURSE
+ if (recursive)
+ {
+ emsg(_("E659: Cannot invoke Python recursively"));
+ return;
+ }
+ ++recursive;
+#endif
+ if (python_end_called)
+ return;
+
+ if (Python_Init())
+ goto theend;
+
+ init_range(arg);
+
+ Python_Release_Vim(); /* leave vim */
+
+#if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
+ /* Python only works properly when the LC_NUMERIC locale is "C". */
+ saved_locale = setlocale(LC_NUMERIC, NULL);
+ if (saved_locale == NULL || STRCMP(saved_locale, "C") == 0)
+ saved_locale = NULL;
+ else
+ {
+ /* Need to make a copy, value may change when setting new locale. */
+ saved_locale = (char *) PY_STRSAVE(saved_locale);
+ (void)setlocale(LC_NUMERIC, "C");
+ }
+#endif
+
+#ifdef PY_CAN_RECURSE
+ pygilstate = PyGILState_Ensure();
+#else
+ Python_RestoreThread(); /* enter python */
+#endif
+
+ run((char *) cmd, arg
+#ifdef PY_CAN_RECURSE
+ , &pygilstate
+#endif
+ );
+
+#ifdef PY_CAN_RECURSE
+ PyGILState_Release(pygilstate);
+#else
+ Python_SaveThread(); /* leave python */
+#endif
+
+#if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
+ if (saved_locale != NULL)
+ {
+ (void)setlocale(LC_NUMERIC, saved_locale);
+ PyMem_Free(saved_locale);
+ }
+#endif
+
+ Python_Lock_Vim(); /* enter vim */
+ PythonIO_Flush();
+
+theend:
+#ifndef PY_CAN_RECURSE
+ --recursive;
+#endif
+ return;
+}
+
+/*
+ * ":python"
+ */
+ void
+ex_python(exarg_T *eap)
+{
+ char_u *script;
+
+ if (p_pyx == 0)
+ p_pyx = 2;
+
+ script = script_get(eap, eap->arg);
+ if (!eap->skip)
+ {
+ DoPyCommand(script == NULL ? (char *) eap->arg : (char *) script,
+ (rangeinitializer) init_range_cmd,
+ (runner) run_cmd,
+ (void *) eap);
+ }
+ vim_free(script);
+}
+
+#define BUFFER_SIZE 1024
+
+/*
+ * ":pyfile"
+ */
+ void
+ex_pyfile(exarg_T *eap)
+{
+ static char buffer[BUFFER_SIZE];
+ const char *file = (char *)eap->arg;
+ char *p;
+
+ if (p_pyx == 0)
+ p_pyx = 2;
+
+ /* Have to do it like this. PyRun_SimpleFile requires you to pass a
+ * stdio file pointer, but Vim and the Python DLL are compiled with
+ * different options under Windows, meaning that stdio pointers aren't
+ * compatible between the two. Yuk.
+ *
+ * Put the string "execfile('file')" into buffer. But, we need to
+ * escape any backslashes or single quotes in the file name, so that
+ * Python won't mangle the file name.
+ */
+ strcpy(buffer, "execfile('");
+ p = buffer + 10; /* size of "execfile('" */
+
+ while (*file && p < buffer + (BUFFER_SIZE - 3))
+ {
+ if (*file == '\\' || *file == '\'')
+ *p++ = '\\';
+ *p++ = *file++;
+ }
+
+ /* If we didn't finish the file name, we hit a buffer overflow */
+ if (*file != '\0')
+ return;
+
+ /* Put in the terminating "')" and a null */
+ *p++ = '\'';
+ *p++ = ')';
+ *p++ = '\0';
+
+ /* Execute the file */
+ DoPyCommand(buffer,
+ (rangeinitializer) init_range_cmd,
+ (runner) run_cmd,
+ (void *) eap);
+}
+
+ void
+ex_pydo(exarg_T *eap)
+{
+ if (p_pyx == 0)
+ p_pyx = 2;
+
+ DoPyCommand((char *)eap->arg,
+ (rangeinitializer) init_range_cmd,
+ (runner)run_do,
+ (void *)eap);
+}
+
+/******************************************************
+ * 2. Python output stream: writes output via [e]msg().
+ */
+
+/* Implementation functions
+ */
+
+ static PyObject *
+OutputGetattr(PyObject *self, char *name)
+{
+ if (strcmp(name, "softspace") == 0)
+ return PyInt_FromLong(((OutputObject *)(self))->softspace);
+ else if (strcmp(name, "__members__") == 0)
+ return ObjectDir(NULL, OutputAttrs);
+ else if (strcmp(name, "errors") == 0)
+ return PyString_FromString("strict");
+ else if (strcmp(name, "encoding") == 0)
+ return PyString_FromString(ENC_OPT);
+ return Py_FindMethod(OutputMethods, self, name);
+}
+
+/******************************************************
+ * 3. Implementation of the Vim module for Python
+ */
+
+/* Window type - Implementation functions
+ * --------------------------------------
+ */
+
+#define WindowType_Check(obj) ((obj)->ob_type == &WindowType)
+
+/* Buffer type - Implementation functions
+ * --------------------------------------
+ */
+
+#define BufferType_Check(obj) ((obj)->ob_type == &BufferType)
+
+static PyInt BufferAssItem(PyObject *, PyInt, PyObject *);
+static PyInt BufferAssSlice(PyObject *, PyInt, PyInt, PyObject *);
+
+/* Line range type - Implementation functions
+ * --------------------------------------
+ */
+
+#define RangeType_Check(obj) ((obj)->ob_type == &RangeType)
+
+static PyInt RangeAssItem(PyObject *, PyInt, PyObject *);
+static PyInt RangeAssSlice(PyObject *, PyInt, PyInt, PyObject *);
+
+/* Current objects type - Implementation functions
+ * -----------------------------------------------
+ */
+
+static PySequenceMethods BufferAsSeq = {
+ (PyInquiry) BufferLength, /* sq_length, len(x) */
+ (binaryfunc) 0, /* BufferConcat, sq_concat, x+y */
+ (PyIntArgFunc) 0, /* BufferRepeat, sq_repeat, x*n */
+ (PyIntArgFunc) BufferItem, /* sq_item, x[i] */
+ (PyIntIntArgFunc) BufferSlice, /* sq_slice, x[i:j] */
+ (PyIntObjArgProc) BufferAssItem, /* sq_ass_item, x[i]=v */
+ (PyIntIntObjArgProc) BufferAssSlice, /* sq_ass_slice, x[i:j]=v */
+ (objobjproc) 0,
+ (binaryfunc) 0,
+ 0,
+};
+
+/* Buffer object - Implementation
+ */
+
+ static PyObject *
+BufferGetattr(PyObject *self, char *name)
+{
+ PyObject *r;
+
+ if ((r = BufferAttrValid((BufferObject *)(self), name)))
+ return r;
+
+ if (CheckBuffer((BufferObject *)(self)))
+ return NULL;
+
+ r = BufferAttr((BufferObject *)(self), name);
+ if (r || PyErr_Occurred())
+ return r;
+ else
+ return Py_FindMethod(BufferMethods, self, name);
+}
+
+/******************/
+
+ static PyInt
+BufferAssItem(PyObject *self, PyInt n, PyObject *val)
+{
+ return RBAsItem((BufferObject *)(self), n, val, 1, -1, NULL);
+}
+
+ static PyInt
+BufferAssSlice(PyObject *self, PyInt lo, PyInt hi, PyObject *val)
+{
+ return RBAsSlice((BufferObject *)(self), lo, hi, val, 1, -1, NULL);
+}
+
+static PySequenceMethods RangeAsSeq = {
+ (PyInquiry) RangeLength, /* sq_length, len(x) */
+ (binaryfunc) 0, /* RangeConcat, */ /* sq_concat, x+y */
+ (PyIntArgFunc) 0, /* RangeRepeat, */ /* sq_repeat, x*n */
+ (PyIntArgFunc) RangeItem, /* sq_item, x[i] */
+ (PyIntIntArgFunc) RangeSlice, /* sq_slice, x[i:j] */
+ (PyIntObjArgProc) RangeAssItem, /* sq_ass_item, x[i]=v */
+ (PyIntIntObjArgProc) RangeAssSlice, /* sq_ass_slice, x[i:j]=v */
+ (objobjproc) 0,
+#if PY_MAJOR_VERSION >= 2
+ (binaryfunc) 0,
+ 0,
+#endif
+};
+
+/* Line range object - Implementation
+ */
+
+ static PyObject *
+RangeGetattr(PyObject *self, char *name)
+{
+ if (strcmp(name, "start") == 0)
+ return Py_BuildValue(Py_ssize_t_fmt, ((RangeObject *)(self))->start - 1);
+ else if (strcmp(name, "end") == 0)
+ return Py_BuildValue(Py_ssize_t_fmt, ((RangeObject *)(self))->end - 1);
+ else if (strcmp(name, "__members__") == 0)
+ return ObjectDir(NULL, RangeAttrs);
+ else
+ return Py_FindMethod(RangeMethods, self, name);
+}
+
+/****************/
+
+ static PyInt
+RangeAssItem(PyObject *self, PyInt n, PyObject *val)
+{
+ return RBAsItem(((RangeObject *)(self))->buf, n, val,
+ ((RangeObject *)(self))->start,
+ ((RangeObject *)(self))->end,
+ &((RangeObject *)(self))->end);
+}
+
+ static PyInt
+RangeAssSlice(PyObject *self, PyInt lo, PyInt hi, PyObject *val)
+{
+ return RBAsSlice(((RangeObject *)(self))->buf, lo, hi, val,
+ ((RangeObject *)(self))->start,
+ ((RangeObject *)(self))->end,
+ &((RangeObject *)(self))->end);
+}
+
+/* TabPage object - Implementation
+ */
+
+ static PyObject *
+TabPageGetattr(PyObject *self, char *name)
+{
+ PyObject *r;
+
+ if ((r = TabPageAttrValid((TabPageObject *)(self), name)))
+ return r;
+
+ if (CheckTabPage((TabPageObject *)(self)))
+ return NULL;
+
+ r = TabPageAttr((TabPageObject *)(self), name);
+ if (r || PyErr_Occurred())
+ return r;
+ else
+ return Py_FindMethod(TabPageMethods, self, name);
+}
+
+/* Window object - Implementation
+ */
+
+ static PyObject *
+WindowGetattr(PyObject *self, char *name)
+{
+ PyObject *r;
+
+ if ((r = WindowAttrValid((WindowObject *)(self), name)))
+ return r;
+
+ if (CheckWindow((WindowObject *)(self)))
+ return NULL;
+
+ r = WindowAttr((WindowObject *)(self), name);
+ if (r || PyErr_Occurred())
+ return r;
+ else
+ return Py_FindMethod(WindowMethods, self, name);
+}
+
+/* Tab page list object - Definitions
+ */
+
+static PySequenceMethods TabListAsSeq = {
+ (PyInquiry) TabListLength, /* sq_length, len(x) */
+ (binaryfunc) 0, /* sq_concat, x+y */
+ (PyIntArgFunc) 0, /* sq_repeat, x*n */
+ (PyIntArgFunc) TabListItem, /* sq_item, x[i] */
+ (PyIntIntArgFunc) 0, /* sq_slice, x[i:j] */
+ (PyIntObjArgProc) 0, /* sq_ass_item, x[i]=v */
+ (PyIntIntObjArgProc) 0, /* sq_ass_slice, x[i:j]=v */
+ (objobjproc) 0,
+#if PY_MAJOR_VERSION >= 2
+ (binaryfunc) 0,
+ 0,
+#endif
+};
+
+/* Window list object - Definitions
+ */
+
+static PySequenceMethods WinListAsSeq = {
+ (PyInquiry) WinListLength, /* sq_length, len(x) */
+ (binaryfunc) 0, /* sq_concat, x+y */
+ (PyIntArgFunc) 0, /* sq_repeat, x*n */
+ (PyIntArgFunc) WinListItem, /* sq_item, x[i] */
+ (PyIntIntArgFunc) 0, /* sq_slice, x[i:j] */
+ (PyIntObjArgProc) 0, /* sq_ass_item, x[i]=v */
+ (PyIntIntObjArgProc) 0, /* sq_ass_slice, x[i:j]=v */
+ (objobjproc) 0,
+#if PY_MAJOR_VERSION >= 2
+ (binaryfunc) 0,
+ 0,
+#endif
+};
+
+/* External interface
+ */
+
+ void
+python_buffer_free(buf_T *buf)
+{
+ if (BUF_PYTHON_REF(buf) != NULL)
+ {
+ BufferObject *bp = BUF_PYTHON_REF(buf);
+ bp->buf = INVALID_BUFFER_VALUE;
+ BUF_PYTHON_REF(buf) = NULL;
+ }
+}
+
+ void
+python_window_free(win_T *win)
+{
+ if (WIN_PYTHON_REF(win) != NULL)
+ {
+ WindowObject *wp = WIN_PYTHON_REF(win);
+ wp->win = INVALID_WINDOW_VALUE;
+ WIN_PYTHON_REF(win) = NULL;
+ }
+}
+
+ void
+python_tabpage_free(tabpage_T *tab)
+{
+ if (TAB_PYTHON_REF(tab) != NULL)
+ {
+ TabPageObject *tp = TAB_PYTHON_REF(tab);
+ tp->tab = INVALID_TABPAGE_VALUE;
+ TAB_PYTHON_REF(tab) = NULL;
+ }
+}
+
+ static int
+PythonMod_Init(void)
+{
+ /* The special value is removed from sys.path in Python_Init(). */
+ static char *(argv[2]) = {"/must>not&exist/foo", NULL};
+
+ if (init_types())
+ return -1;
+
+ /* Set sys.argv[] to avoid a crash in warn(). */
+ PySys_SetArgv(1, argv);
+
+ vim_module = Py_InitModule4("vim", VimMethods, (char *)NULL,
+ (PyObject *)NULL, PYTHON_API_VERSION);
+
+ if (populate_module(vim_module))
+ return -1;
+
+ if (init_sys_path())
+ return -1;
+
+ return 0;
+}
+
+/*************************************************************************
+ * 4. Utility functions for handling the interface between Vim and Python.
+ */
+
+/* Convert a Vim line into a Python string.
+ * All internal newlines are replaced by null characters.
+ *
+ * On errors, the Python exception data is set, and NULL is returned.
+ */
+ static PyObject *
+LineToString(const char *str)
+{
+ PyObject *result;
+ PyInt len = strlen(str);
+ char *p;
+
+ /* Allocate an Python string object, with uninitialised contents. We
+ * must do it this way, so that we can modify the string in place
+ * later. See the Python source, Objects/stringobject.c for details.
+ */
+ result = PyString_FromStringAndSize(NULL, len);
+ if (result == NULL)
+ return NULL;
+
+ p = PyString_AsString(result);
+
+ while (*str)
+ {
+ if (*str == '\n')
+ *p = '\0';
+ else
+ *p = *str;
+
+ ++p;
+ ++str;
+ }
+
+ return result;
+}
+
+ static PyObject *
+DictionaryGetattr(PyObject *self, char *name)
+{
+ DictionaryObject *this = ((DictionaryObject *) (self));
+
+ if (strcmp(name, "locked") == 0)
+ return PyInt_FromLong(this->dict->dv_lock);
+ else if (strcmp(name, "scope") == 0)
+ return PyInt_FromLong(this->dict->dv_scope);
+ else if (strcmp(name, "__members__") == 0)
+ return ObjectDir(NULL, DictionaryAttrs);
+
+ return Py_FindMethod(DictionaryMethods, self, name);
+}
+
+ static PyObject *
+ListGetattr(PyObject *self, char *name)
+{
+ if (strcmp(name, "locked") == 0)
+ return PyInt_FromLong(((ListObject *)(self))->list->lv_lock);
+ else if (strcmp(name, "__members__") == 0)
+ return ObjectDir(NULL, ListAttrs);
+
+ return Py_FindMethod(ListMethods, self, name);
+}
+
+ static PyObject *
+FunctionGetattr(PyObject *self, char *name)
+{
+ PyObject *r;
+
+ r = FunctionAttr((FunctionObject *)(self), name);
+
+ if (r || PyErr_Occurred())
+ return r;
+ else
+ return Py_FindMethod(FunctionMethods, self, name);
+}
+
+ void
+do_pyeval (char_u *str, typval_T *rettv)
+{
+ DoPyCommand((char *) str,
+ (rangeinitializer) init_range_eval,
+ (runner) run_eval,
+ (void *) rettv);
+ switch (rettv->v_type)
+ {
+ case VAR_DICT: ++rettv->vval.v_dict->dv_refcount; break;
+ case VAR_LIST: ++rettv->vval.v_list->lv_refcount; break;
+ case VAR_FUNC: func_ref(rettv->vval.v_string); break;
+ case VAR_PARTIAL: ++rettv->vval.v_partial->pt_refcount; break;
+ case VAR_UNKNOWN:
+ rettv->v_type = VAR_NUMBER;
+ rettv->vval.v_number = 0;
+ break;
+ case VAR_NUMBER:
+ case VAR_STRING:
+ case VAR_FLOAT:
+ case VAR_SPECIAL:
+ case VAR_JOB:
+ case VAR_CHANNEL:
+ case VAR_BLOB:
+ break;
+ }
+}
+
+/* Don't generate a prototype for the next function, it generates an error on
+ * newer Python versions. */
+#if PYTHON_API_VERSION < 1007 /* Python 1.4 */ && !defined(PROTO)
+
+ char *
+Py_GetProgramName(void)
+{
+ return "vim";
+}
+#endif /* Python 1.4 */
+
+ int
+set_ref_in_python (int copyID)
+{
+ return set_ref_in_py(copyID);
+}
diff --git a/src/if_python3.c b/src/if_python3.c
new file mode 100644
index 0000000..4bbbdd1
--- /dev/null
+++ b/src/if_python3.c
@@ -0,0 +1,1696 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+/*
+ * Python extensions by Paul Moore.
+ * Changes for Unix by David Leonard.
+ *
+ * This consists of four parts:
+ * 1. Python interpreter main program
+ * 2. Python output stream: writes output via [e]msg().
+ * 3. Implementation of the Vim module for Python
+ * 4. Utility functions for handling the interface between Vim and Python.
+ */
+
+/*
+ * Roland Puntaier 2009/sept/16:
+ * Adaptations to support both python3.x and python2.x
+ */
+
+/* uncomment this if used with the debug version of python */
+/* #define Py_DEBUG */
+/* Note: most of time you can add -DPy_DEBUG to CFLAGS in place of uncommenting
+ */
+/* uncomment this if used with the debug version of python, but without its
+ * allocator */
+/* #define Py_DEBUG_NO_PYMALLOC */
+
+#include "vim.h"
+
+#include <limits.h>
+
+#if defined(_WIN32) && defined(HAVE_FCNTL_H)
+# undef HAVE_FCNTL_H
+#endif
+
+#ifdef _DEBUG
+# undef _DEBUG
+#endif
+
+#ifdef F_BLANK
+# undef F_BLANK
+#endif
+
+#ifdef HAVE_STRFTIME
+# undef HAVE_STRFTIME
+#endif
+#ifdef HAVE_STRING_H
+# undef HAVE_STRING_H
+#endif
+#ifdef HAVE_PUTENV
+# undef HAVE_PUTENV
+#endif
+#ifdef HAVE_STDARG_H
+# undef HAVE_STDARG_H /* Python's config.h defines it as well. */
+#endif
+#ifdef _POSIX_C_SOURCE /* defined in feature.h */
+# undef _POSIX_C_SOURCE
+#endif
+#ifdef _XOPEN_SOURCE
+# undef _XOPEN_SOURCE /* pyconfig.h defines it as well. */
+#endif
+
+#define PY_SSIZE_T_CLEAN
+
+#include <Python.h>
+
+#undef main /* Defined in python.h - aargh */
+#undef HAVE_FCNTL_H /* Clash with os_win32.h */
+
+/* The "surrogateescape" error handler is new in Python 3.1 */
+#if PY_VERSION_HEX >= 0x030100f0
+# define CODEC_ERROR_HANDLER "surrogateescape"
+#else
+# define CODEC_ERROR_HANDLER NULL
+#endif
+
+/* Python 3 does not support CObjects, always use Capsules */
+#define PY_USE_CAPSULE
+
+#define PyInt Py_ssize_t
+#ifndef PyString_Check
+# define PyString_Check(obj) PyUnicode_Check(obj)
+#endif
+#define PyString_FromString(repr) \
+ PyUnicode_Decode(repr, STRLEN(repr), ENC_OPT, NULL)
+#define PyString_FromFormat PyUnicode_FromFormat
+#ifndef PyInt_Check
+# define PyInt_Check(obj) PyLong_Check(obj)
+#endif
+#define PyInt_FromLong(i) PyLong_FromLong(i)
+#define PyInt_AsLong(obj) PyLong_AsLong(obj)
+#define Py_ssize_t_fmt "n"
+#define Py_bytes_fmt "y"
+
+#define PyIntArgFunc ssizeargfunc
+#define PyIntObjArgProc ssizeobjargproc
+
+/*
+ * PySlice_GetIndicesEx(): first argument type changed from PySliceObject
+ * to PyObject in Python 3.2 or later.
+ */
+#if PY_VERSION_HEX >= 0x030200f0
+typedef PyObject PySliceObject_T;
+#else
+typedef PySliceObject PySliceObject_T;
+#endif
+
+#if defined(DYNAMIC_PYTHON3) || defined(PROTO)
+
+# ifndef WIN3264
+# include <dlfcn.h>
+# define FARPROC void*
+# define HINSTANCE void*
+# if defined(PY_NO_RTLD_GLOBAL) && defined(PY3_NO_RTLD_GLOBAL)
+# define load_dll(n) dlopen((n), RTLD_LAZY)
+# else
+# define load_dll(n) dlopen((n), RTLD_LAZY|RTLD_GLOBAL)
+# endif
+# define close_dll dlclose
+# define symbol_from_dll dlsym
+# else
+# define load_dll vimLoadLib
+# define close_dll FreeLibrary
+# define symbol_from_dll GetProcAddress
+# endif
+/*
+ * Wrapper defines
+ */
+# undef PyArg_Parse
+# define PyArg_Parse py3_PyArg_Parse
+# undef PyArg_ParseTuple
+# define PyArg_ParseTuple py3_PyArg_ParseTuple
+# define PyMem_Free py3_PyMem_Free
+# define PyMem_Malloc py3_PyMem_Malloc
+# define PyDict_SetItemString py3_PyDict_SetItemString
+# define PyErr_BadArgument py3_PyErr_BadArgument
+# define PyErr_Clear py3_PyErr_Clear
+# define PyErr_Format py3_PyErr_Format
+# define PyErr_PrintEx py3_PyErr_PrintEx
+# define PyErr_NoMemory py3_PyErr_NoMemory
+# define PyErr_Occurred py3_PyErr_Occurred
+# define PyErr_SetNone py3_PyErr_SetNone
+# define PyErr_SetString py3_PyErr_SetString
+# define PyErr_SetObject py3_PyErr_SetObject
+# define PyErr_ExceptionMatches py3_PyErr_ExceptionMatches
+# define PyEval_InitThreads py3_PyEval_InitThreads
+# define PyEval_RestoreThread py3_PyEval_RestoreThread
+# define PyEval_SaveThread py3_PyEval_SaveThread
+# define PyGILState_Ensure py3_PyGILState_Ensure
+# define PyGILState_Release py3_PyGILState_Release
+# define PyLong_AsLong py3_PyLong_AsLong
+# define PyLong_FromLong py3_PyLong_FromLong
+# define PyList_GetItem py3_PyList_GetItem
+# define PyList_Append py3_PyList_Append
+# define PyList_Insert py3_PyList_Insert
+# define PyList_New py3_PyList_New
+# define PyList_SetItem py3_PyList_SetItem
+# define PyList_Size py3_PyList_Size
+# define PySequence_Check py3_PySequence_Check
+# define PySequence_Size py3_PySequence_Size
+# define PySequence_GetItem py3_PySequence_GetItem
+# define PySequence_Fast py3_PySequence_Fast
+# define PyTuple_Size py3_PyTuple_Size
+# define PyTuple_GetItem py3_PyTuple_GetItem
+# if PY_VERSION_HEX >= 0x030601f0
+# define PySlice_AdjustIndices py3_PySlice_AdjustIndices
+# define PySlice_Unpack py3_PySlice_Unpack
+# endif
+# undef PySlice_GetIndicesEx
+# define PySlice_GetIndicesEx py3_PySlice_GetIndicesEx
+# define PyImport_ImportModule py3_PyImport_ImportModule
+# define PyObject_Init py3__PyObject_Init
+# define PyDict_New py3_PyDict_New
+# define PyDict_GetItemString py3_PyDict_GetItemString
+# define PyDict_Next py3_PyDict_Next
+# define PyMapping_Check py3_PyMapping_Check
+# ifndef PyMapping_Keys
+# define PyMapping_Keys py3_PyMapping_Keys
+# endif
+# define PyIter_Next py3_PyIter_Next
+# define PyObject_GetIter py3_PyObject_GetIter
+# define PyObject_Repr py3_PyObject_Repr
+# define PyObject_GetItem py3_PyObject_GetItem
+# define PyObject_IsTrue py3_PyObject_IsTrue
+# define PyModule_GetDict py3_PyModule_GetDict
+#undef PyRun_SimpleString
+# define PyRun_SimpleString py3_PyRun_SimpleString
+#undef PyRun_String
+# define PyRun_String py3_PyRun_String
+# define PyObject_GetAttrString py3_PyObject_GetAttrString
+# define PyObject_HasAttrString py3_PyObject_HasAttrString
+# define PyObject_SetAttrString py3_PyObject_SetAttrString
+# define PyObject_CallFunctionObjArgs py3_PyObject_CallFunctionObjArgs
+# define _PyObject_CallFunction_SizeT py3__PyObject_CallFunction_SizeT
+# define PyObject_Call py3_PyObject_Call
+# define PyEval_GetLocals py3_PyEval_GetLocals
+# define PyEval_GetGlobals py3_PyEval_GetGlobals
+# define PySys_SetObject py3_PySys_SetObject
+# define PySys_GetObject py3_PySys_GetObject
+# define PySys_SetArgv py3_PySys_SetArgv
+# define PyType_Ready py3_PyType_Ready
+#undef Py_BuildValue
+# define Py_BuildValue py3_Py_BuildValue
+# define Py_SetPythonHome py3_Py_SetPythonHome
+# define Py_Initialize py3_Py_Initialize
+# define Py_Finalize py3_Py_Finalize
+# define Py_IsInitialized py3_Py_IsInitialized
+# define _Py_NoneStruct (*py3__Py_NoneStruct)
+# define _Py_FalseStruct (*py3__Py_FalseStruct)
+# define _Py_TrueStruct (*py3__Py_TrueStruct)
+# define _PyObject_NextNotImplemented (*py3__PyObject_NextNotImplemented)
+# define PyModule_AddObject py3_PyModule_AddObject
+# define PyImport_AppendInittab py3_PyImport_AppendInittab
+# define PyImport_AddModule py3_PyImport_AddModule
+# if PY_VERSION_HEX >= 0x030300f0
+# undef _PyUnicode_AsString
+# define _PyUnicode_AsString py3_PyUnicode_AsUTF8
+# else
+# define _PyUnicode_AsString py3__PyUnicode_AsString
+# endif
+# undef PyUnicode_AsEncodedString
+# define PyUnicode_AsEncodedString py3_PyUnicode_AsEncodedString
+# undef PyBytes_AsString
+# define PyBytes_AsString py3_PyBytes_AsString
+# ifndef PyBytes_AsStringAndSize
+# define PyBytes_AsStringAndSize py3_PyBytes_AsStringAndSize
+# endif
+# undef PyBytes_FromString
+# define PyBytes_FromString py3_PyBytes_FromString
+# undef PyBytes_FromStringAndSize
+# define PyBytes_FromStringAndSize py3_PyBytes_FromStringAndSize
+# define PyFloat_FromDouble py3_PyFloat_FromDouble
+# define PyFloat_AsDouble py3_PyFloat_AsDouble
+# define PyObject_GenericGetAttr py3_PyObject_GenericGetAttr
+# define PyType_Type (*py3_PyType_Type)
+# define PyStdPrinter_Type (*py3_PyStdPrinter_Type)
+# define PySlice_Type (*py3_PySlice_Type)
+# define PyFloat_Type (*py3_PyFloat_Type)
+# define PyNumber_Check (*py3_PyNumber_Check)
+# define PyNumber_Long (*py3_PyNumber_Long)
+# define PyBool_Type (*py3_PyBool_Type)
+# define PyErr_NewException py3_PyErr_NewException
+# ifdef Py_DEBUG
+# define _Py_NegativeRefcount py3__Py_NegativeRefcount
+# define _Py_RefTotal (*py3__Py_RefTotal)
+# define _Py_Dealloc py3__Py_Dealloc
+# define PyModule_Create2TraceRefs py3_PyModule_Create2TraceRefs
+# else
+# define PyModule_Create2 py3_PyModule_Create2
+# endif
+# if defined(Py_DEBUG) && !defined(Py_DEBUG_NO_PYMALLOC)
+# define _PyObject_DebugMalloc py3__PyObject_DebugMalloc
+# define _PyObject_DebugFree py3__PyObject_DebugFree
+# else
+# define PyObject_Malloc py3_PyObject_Malloc
+# define PyObject_Free py3_PyObject_Free
+# endif
+# define _PyObject_GC_New py3__PyObject_GC_New
+# define PyObject_GC_Del py3_PyObject_GC_Del
+# define PyObject_GC_UnTrack py3_PyObject_GC_UnTrack
+# define PyType_GenericAlloc py3_PyType_GenericAlloc
+# define PyType_GenericNew py3_PyType_GenericNew
+# undef PyUnicode_FromString
+# define PyUnicode_FromString py3_PyUnicode_FromString
+# ifndef PyUnicode_FromFormat
+# define PyUnicode_FromFormat py3_PyUnicode_FromFormat
+# else
+# define Py_UNICODE_USE_UCS_FUNCTIONS
+# ifdef Py_UNICODE_WIDE
+# define PyUnicodeUCS4_FromFormat py3_PyUnicodeUCS4_FromFormat
+# else
+# define PyUnicodeUCS2_FromFormat py3_PyUnicodeUCS2_FromFormat
+# endif
+# endif
+# undef PyUnicode_Decode
+# define PyUnicode_Decode py3_PyUnicode_Decode
+# define PyType_IsSubtype py3_PyType_IsSubtype
+# define PyCapsule_New py3_PyCapsule_New
+# define PyCapsule_GetPointer py3_PyCapsule_GetPointer
+
+# if defined(Py_DEBUG) && !defined(Py_DEBUG_NO_PYMALLOC)
+# undef PyObject_NEW
+# define PyObject_NEW(type, typeobj) \
+( (type *) PyObject_Init( \
+ (PyObject *) _PyObject_DebugMalloc( _PyObject_SIZE(typeobj) ), (typeobj)) )
+# endif
+
+/*
+ * Pointers for dynamic link
+ */
+static int (*py3_PySys_SetArgv)(int, wchar_t **);
+static void (*py3_Py_SetPythonHome)(wchar_t *home);
+static void (*py3_Py_Initialize)(void);
+static PyObject* (*py3_PyList_New)(Py_ssize_t size);
+static PyGILState_STATE (*py3_PyGILState_Ensure)(void);
+static void (*py3_PyGILState_Release)(PyGILState_STATE);
+static int (*py3_PySys_SetObject)(char *, PyObject *);
+static PyObject* (*py3_PySys_GetObject)(char *);
+static int (*py3_PyList_Append)(PyObject *, PyObject *);
+static int (*py3_PyList_Insert)(PyObject *, int, PyObject *);
+static Py_ssize_t (*py3_PyList_Size)(PyObject *);
+static int (*py3_PySequence_Check)(PyObject *);
+static Py_ssize_t (*py3_PySequence_Size)(PyObject *);
+static PyObject* (*py3_PySequence_GetItem)(PyObject *, Py_ssize_t);
+static PyObject* (*py3_PySequence_Fast)(PyObject *, const char *);
+static Py_ssize_t (*py3_PyTuple_Size)(PyObject *);
+static PyObject* (*py3_PyTuple_GetItem)(PyObject *, Py_ssize_t);
+static int (*py3_PyMapping_Check)(PyObject *);
+static PyObject* (*py3_PyMapping_Keys)(PyObject *);
+# if PY_VERSION_HEX >= 0x030601f0
+static int (*py3_PySlice_AdjustIndices)(Py_ssize_t length,
+ Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t step);
+static int (*py3_PySlice_Unpack)(PyObject *slice,
+ Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step);
+# endif
+static int (*py3_PySlice_GetIndicesEx)(PySliceObject_T *r, Py_ssize_t length,
+ Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step,
+ Py_ssize_t *slicelen);
+static PyObject* (*py3_PyErr_NoMemory)(void);
+static void (*py3_Py_Finalize)(void);
+static void (*py3_PyErr_SetString)(PyObject *, const char *);
+static void (*py3_PyErr_SetObject)(PyObject *, PyObject *);
+static int (*py3_PyErr_ExceptionMatches)(PyObject *);
+static int (*py3_PyRun_SimpleString)(char *);
+static PyObject* (*py3_PyRun_String)(char *, int, PyObject *, PyObject *);
+static PyObject* (*py3_PyObject_GetAttrString)(PyObject *, const char *);
+static int (*py3_PyObject_HasAttrString)(PyObject *, const char *);
+static int (*py3_PyObject_SetAttrString)(PyObject *, const char *, PyObject *);
+static PyObject* (*py3_PyObject_CallFunctionObjArgs)(PyObject *, ...);
+static PyObject* (*py3__PyObject_CallFunction_SizeT)(PyObject *, char *, ...);
+static PyObject* (*py3_PyObject_Call)(PyObject *, PyObject *, PyObject *);
+static PyObject* (*py3_PyEval_GetGlobals)();
+static PyObject* (*py3_PyEval_GetLocals)();
+static PyObject* (*py3_PyList_GetItem)(PyObject *, Py_ssize_t);
+static PyObject* (*py3_PyImport_ImportModule)(const char *);
+static PyObject* (*py3_PyImport_AddModule)(const char *);
+static int (*py3_PyErr_BadArgument)(void);
+static PyObject* (*py3_PyErr_Occurred)(void);
+static PyObject* (*py3_PyModule_GetDict)(PyObject *);
+static int (*py3_PyList_SetItem)(PyObject *, Py_ssize_t, PyObject *);
+static PyObject* (*py3_PyDict_GetItemString)(PyObject *, const char *);
+static int (*py3_PyDict_Next)(PyObject *, Py_ssize_t *, PyObject **, PyObject **);
+static PyObject* (*py3_PyLong_FromLong)(long);
+static PyObject* (*py3_PyDict_New)(void);
+static PyObject* (*py3_PyIter_Next)(PyObject *);
+static PyObject* (*py3_PyObject_GetIter)(PyObject *);
+static PyObject* (*py3_PyObject_Repr)(PyObject *);
+static PyObject* (*py3_PyObject_GetItem)(PyObject *, PyObject *);
+static int (*py3_PyObject_IsTrue)(PyObject *);
+static PyObject* (*py3_Py_BuildValue)(char *, ...);
+static int (*py3_PyType_Ready)(PyTypeObject *type);
+static int (*py3_PyDict_SetItemString)(PyObject *dp, char *key, PyObject *item);
+static PyObject* (*py3_PyUnicode_FromString)(const char *u);
+# ifndef Py_UNICODE_USE_UCS_FUNCTIONS
+static PyObject* (*py3_PyUnicode_FromFormat)(const char *u, ...);
+# else
+# ifdef Py_UNICODE_WIDE
+static PyObject* (*py3_PyUnicodeUCS4_FromFormat)(const char *u, ...);
+# else
+static PyObject* (*py3_PyUnicodeUCS2_FromFormat)(const char *u, ...);
+# endif
+# endif
+static PyObject* (*py3_PyUnicode_Decode)(const char *u, Py_ssize_t size,
+ const char *encoding, const char *errors);
+static long (*py3_PyLong_AsLong)(PyObject *);
+static void (*py3_PyErr_SetNone)(PyObject *);
+static void (*py3_PyEval_InitThreads)(void);
+static void(*py3_PyEval_RestoreThread)(PyThreadState *);
+static PyThreadState*(*py3_PyEval_SaveThread)(void);
+static int (*py3_PyArg_Parse)(PyObject *, char *, ...);
+static int (*py3_PyArg_ParseTuple)(PyObject *, char *, ...);
+static int (*py3_PyMem_Free)(void *);
+static void* (*py3_PyMem_Malloc)(size_t);
+static int (*py3_Py_IsInitialized)(void);
+static void (*py3_PyErr_Clear)(void);
+static PyObject* (*py3_PyErr_Format)(PyObject *, const char *, ...);
+static void (*py3_PyErr_PrintEx)(int);
+static PyObject*(*py3__PyObject_Init)(PyObject *, PyTypeObject *);
+static iternextfunc py3__PyObject_NextNotImplemented;
+static PyObject* py3__Py_NoneStruct;
+static PyObject* py3__Py_FalseStruct;
+static PyObject* py3__Py_TrueStruct;
+static int (*py3_PyModule_AddObject)(PyObject *m, const char *name, PyObject *o);
+static int (*py3_PyImport_AppendInittab)(const char *name, PyObject* (*initfunc)(void));
+# if PY_VERSION_HEX >= 0x030300f0
+static char* (*py3_PyUnicode_AsUTF8)(PyObject *unicode);
+# else
+static char* (*py3__PyUnicode_AsString)(PyObject *unicode);
+# endif
+static PyObject* (*py3_PyUnicode_AsEncodedString)(PyObject *unicode, const char* encoding, const char* errors);
+static char* (*py3_PyBytes_AsString)(PyObject *bytes);
+static int (*py3_PyBytes_AsStringAndSize)(PyObject *bytes, char **buffer, Py_ssize_t *length);
+static PyObject* (*py3_PyBytes_FromString)(char *str);
+static PyObject* (*py3_PyBytes_FromStringAndSize)(char *str, Py_ssize_t length);
+static PyObject* (*py3_PyFloat_FromDouble)(double num);
+static double (*py3_PyFloat_AsDouble)(PyObject *);
+static PyObject* (*py3_PyObject_GenericGetAttr)(PyObject *obj, PyObject *name);
+static PyObject* (*py3_PyType_GenericAlloc)(PyTypeObject *type, Py_ssize_t nitems);
+static PyObject* (*py3_PyType_GenericNew)(PyTypeObject *type, PyObject *args, PyObject *kwds);
+static PyTypeObject* py3_PyType_Type;
+static PyTypeObject* py3_PyStdPrinter_Type;
+static PyTypeObject* py3_PySlice_Type;
+static PyTypeObject* py3_PyFloat_Type;
+static PyTypeObject* py3_PyBool_Type;
+static int (*py3_PyNumber_Check)(PyObject *);
+static PyObject* (*py3_PyNumber_Long)(PyObject *);
+static PyObject* (*py3_PyErr_NewException)(char *name, PyObject *base, PyObject *dict);
+static PyObject* (*py3_PyCapsule_New)(void *, char *, PyCapsule_Destructor);
+static void* (*py3_PyCapsule_GetPointer)(PyObject *, char *);
+# ifdef Py_DEBUG
+static void (*py3__Py_NegativeRefcount)(const char *fname, int lineno, PyObject *op);
+static Py_ssize_t* py3__Py_RefTotal;
+static void (*py3__Py_Dealloc)(PyObject *obj);
+static PyObject* (*py3_PyModule_Create2TraceRefs)(struct PyModuleDef* module, int module_api_version);
+# else
+static PyObject* (*py3_PyModule_Create2)(struct PyModuleDef* module, int module_api_version);
+# endif
+# if defined(Py_DEBUG) && !defined(Py_DEBUG_NO_PYMALLOC)
+static void (*py3__PyObject_DebugFree)(void*);
+static void* (*py3__PyObject_DebugMalloc)(size_t);
+# else
+static void (*py3_PyObject_Free)(void*);
+static void* (*py3_PyObject_Malloc)(size_t);
+# endif
+static PyObject*(*py3__PyObject_GC_New)(PyTypeObject *);
+static void(*py3_PyObject_GC_Del)(void *);
+static void(*py3_PyObject_GC_UnTrack)(void *);
+static int (*py3_PyType_IsSubtype)(PyTypeObject *, PyTypeObject *);
+
+static HINSTANCE hinstPy3 = 0; /* Instance of python.dll */
+
+/* Imported exception objects */
+static PyObject *p3imp_PyExc_AttributeError;
+static PyObject *p3imp_PyExc_IndexError;
+static PyObject *p3imp_PyExc_KeyError;
+static PyObject *p3imp_PyExc_KeyboardInterrupt;
+static PyObject *p3imp_PyExc_TypeError;
+static PyObject *p3imp_PyExc_ValueError;
+static PyObject *p3imp_PyExc_SystemExit;
+static PyObject *p3imp_PyExc_RuntimeError;
+static PyObject *p3imp_PyExc_ImportError;
+static PyObject *p3imp_PyExc_OverflowError;
+
+# define PyExc_AttributeError p3imp_PyExc_AttributeError
+# define PyExc_IndexError p3imp_PyExc_IndexError
+# define PyExc_KeyError p3imp_PyExc_KeyError
+# define PyExc_KeyboardInterrupt p3imp_PyExc_KeyboardInterrupt
+# define PyExc_TypeError p3imp_PyExc_TypeError
+# define PyExc_ValueError p3imp_PyExc_ValueError
+# define PyExc_SystemExit p3imp_PyExc_SystemExit
+# define PyExc_RuntimeError p3imp_PyExc_RuntimeError
+# define PyExc_ImportError p3imp_PyExc_ImportError
+# define PyExc_OverflowError p3imp_PyExc_OverflowError
+
+/*
+ * Table of name to function pointer of python.
+ */
+# define PYTHON_PROC FARPROC
+static struct
+{
+ char *name;
+ PYTHON_PROC *ptr;
+} py3_funcname_table[] =
+{
+ {"PySys_SetArgv", (PYTHON_PROC*)&py3_PySys_SetArgv},
+ {"Py_SetPythonHome", (PYTHON_PROC*)&py3_Py_SetPythonHome},
+ {"Py_Initialize", (PYTHON_PROC*)&py3_Py_Initialize},
+ {"_PyArg_ParseTuple_SizeT", (PYTHON_PROC*)&py3_PyArg_ParseTuple},
+ {"_Py_BuildValue_SizeT", (PYTHON_PROC*)&py3_Py_BuildValue},
+ {"PyMem_Free", (PYTHON_PROC*)&py3_PyMem_Free},
+ {"PyMem_Malloc", (PYTHON_PROC*)&py3_PyMem_Malloc},
+ {"PyList_New", (PYTHON_PROC*)&py3_PyList_New},
+ {"PyGILState_Ensure", (PYTHON_PROC*)&py3_PyGILState_Ensure},
+ {"PyGILState_Release", (PYTHON_PROC*)&py3_PyGILState_Release},
+ {"PySys_SetObject", (PYTHON_PROC*)&py3_PySys_SetObject},
+ {"PySys_GetObject", (PYTHON_PROC*)&py3_PySys_GetObject},
+ {"PyList_Append", (PYTHON_PROC*)&py3_PyList_Append},
+ {"PyList_Insert", (PYTHON_PROC*)&py3_PyList_Insert},
+ {"PyList_Size", (PYTHON_PROC*)&py3_PyList_Size},
+ {"PySequence_Check", (PYTHON_PROC*)&py3_PySequence_Check},
+ {"PySequence_Size", (PYTHON_PROC*)&py3_PySequence_Size},
+ {"PySequence_GetItem", (PYTHON_PROC*)&py3_PySequence_GetItem},
+ {"PySequence_Fast", (PYTHON_PROC*)&py3_PySequence_Fast},
+ {"PyTuple_Size", (PYTHON_PROC*)&py3_PyTuple_Size},
+ {"PyTuple_GetItem", (PYTHON_PROC*)&py3_PyTuple_GetItem},
+# if PY_VERSION_HEX >= 0x030601f0
+ {"PySlice_AdjustIndices", (PYTHON_PROC*)&py3_PySlice_AdjustIndices},
+ {"PySlice_Unpack", (PYTHON_PROC*)&py3_PySlice_Unpack},
+# endif
+ {"PySlice_GetIndicesEx", (PYTHON_PROC*)&py3_PySlice_GetIndicesEx},
+ {"PyErr_NoMemory", (PYTHON_PROC*)&py3_PyErr_NoMemory},
+ {"Py_Finalize", (PYTHON_PROC*)&py3_Py_Finalize},
+ {"PyErr_SetString", (PYTHON_PROC*)&py3_PyErr_SetString},
+ {"PyErr_SetObject", (PYTHON_PROC*)&py3_PyErr_SetObject},
+ {"PyErr_ExceptionMatches", (PYTHON_PROC*)&py3_PyErr_ExceptionMatches},
+ {"PyRun_SimpleString", (PYTHON_PROC*)&py3_PyRun_SimpleString},
+ {"PyRun_String", (PYTHON_PROC*)&py3_PyRun_String},
+ {"PyObject_GetAttrString", (PYTHON_PROC*)&py3_PyObject_GetAttrString},
+ {"PyObject_HasAttrString", (PYTHON_PROC*)&py3_PyObject_HasAttrString},
+ {"PyObject_SetAttrString", (PYTHON_PROC*)&py3_PyObject_SetAttrString},
+ {"PyObject_CallFunctionObjArgs", (PYTHON_PROC*)&py3_PyObject_CallFunctionObjArgs},
+ {"_PyObject_CallFunction_SizeT", (PYTHON_PROC*)&py3__PyObject_CallFunction_SizeT},
+ {"PyObject_Call", (PYTHON_PROC*)&py3_PyObject_Call},
+ {"PyEval_GetGlobals", (PYTHON_PROC*)&py3_PyEval_GetGlobals},
+ {"PyEval_GetLocals", (PYTHON_PROC*)&py3_PyEval_GetLocals},
+ {"PyList_GetItem", (PYTHON_PROC*)&py3_PyList_GetItem},
+ {"PyImport_ImportModule", (PYTHON_PROC*)&py3_PyImport_ImportModule},
+ {"PyImport_AddModule", (PYTHON_PROC*)&py3_PyImport_AddModule},
+ {"PyErr_BadArgument", (PYTHON_PROC*)&py3_PyErr_BadArgument},
+ {"PyErr_Occurred", (PYTHON_PROC*)&py3_PyErr_Occurred},
+ {"PyModule_GetDict", (PYTHON_PROC*)&py3_PyModule_GetDict},
+ {"PyList_SetItem", (PYTHON_PROC*)&py3_PyList_SetItem},
+ {"PyDict_GetItemString", (PYTHON_PROC*)&py3_PyDict_GetItemString},
+ {"PyDict_Next", (PYTHON_PROC*)&py3_PyDict_Next},
+ {"PyMapping_Check", (PYTHON_PROC*)&py3_PyMapping_Check},
+ {"PyMapping_Keys", (PYTHON_PROC*)&py3_PyMapping_Keys},
+ {"PyIter_Next", (PYTHON_PROC*)&py3_PyIter_Next},
+ {"PyObject_GetIter", (PYTHON_PROC*)&py3_PyObject_GetIter},
+ {"PyObject_Repr", (PYTHON_PROC*)&py3_PyObject_Repr},
+ {"PyObject_GetItem", (PYTHON_PROC*)&py3_PyObject_GetItem},
+ {"PyObject_IsTrue", (PYTHON_PROC*)&py3_PyObject_IsTrue},
+ {"PyLong_FromLong", (PYTHON_PROC*)&py3_PyLong_FromLong},
+ {"PyDict_New", (PYTHON_PROC*)&py3_PyDict_New},
+ {"PyType_Ready", (PYTHON_PROC*)&py3_PyType_Ready},
+ {"PyDict_SetItemString", (PYTHON_PROC*)&py3_PyDict_SetItemString},
+ {"PyLong_AsLong", (PYTHON_PROC*)&py3_PyLong_AsLong},
+ {"PyErr_SetNone", (PYTHON_PROC*)&py3_PyErr_SetNone},
+ {"PyEval_InitThreads", (PYTHON_PROC*)&py3_PyEval_InitThreads},
+ {"PyEval_RestoreThread", (PYTHON_PROC*)&py3_PyEval_RestoreThread},
+ {"PyEval_SaveThread", (PYTHON_PROC*)&py3_PyEval_SaveThread},
+ {"_PyArg_Parse_SizeT", (PYTHON_PROC*)&py3_PyArg_Parse},
+ {"Py_IsInitialized", (PYTHON_PROC*)&py3_Py_IsInitialized},
+ {"_PyObject_NextNotImplemented", (PYTHON_PROC*)&py3__PyObject_NextNotImplemented},
+ {"_Py_NoneStruct", (PYTHON_PROC*)&py3__Py_NoneStruct},
+ {"_Py_FalseStruct", (PYTHON_PROC*)&py3__Py_FalseStruct},
+ {"_Py_TrueStruct", (PYTHON_PROC*)&py3__Py_TrueStruct},
+ {"PyErr_Clear", (PYTHON_PROC*)&py3_PyErr_Clear},
+ {"PyErr_Format", (PYTHON_PROC*)&py3_PyErr_Format},
+ {"PyErr_PrintEx", (PYTHON_PROC*)&py3_PyErr_PrintEx},
+ {"PyObject_Init", (PYTHON_PROC*)&py3__PyObject_Init},
+ {"PyModule_AddObject", (PYTHON_PROC*)&py3_PyModule_AddObject},
+ {"PyImport_AppendInittab", (PYTHON_PROC*)&py3_PyImport_AppendInittab},
+# if PY_VERSION_HEX >= 0x030300f0
+ {"PyUnicode_AsUTF8", (PYTHON_PROC*)&py3_PyUnicode_AsUTF8},
+# else
+ {"_PyUnicode_AsString", (PYTHON_PROC*)&py3__PyUnicode_AsString},
+# endif
+# ifndef Py_UNICODE_USE_UCS_FUNCTIONS
+ {"PyUnicode_FromFormat", (PYTHON_PROC*)&py3_PyUnicode_FromFormat},
+# else
+# ifdef Py_UNICODE_WIDE
+ {"PyUnicodeUCS4_FromFormat", (PYTHON_PROC*)&py3_PyUnicodeUCS4_FromFormat},
+# else
+ {"PyUnicodeUCS2_FromFormat", (PYTHON_PROC*)&py3_PyUnicodeUCS2_FromFormat},
+# endif
+# endif
+ {"PyBytes_AsString", (PYTHON_PROC*)&py3_PyBytes_AsString},
+ {"PyBytes_AsStringAndSize", (PYTHON_PROC*)&py3_PyBytes_AsStringAndSize},
+ {"PyBytes_FromString", (PYTHON_PROC*)&py3_PyBytes_FromString},
+ {"PyBytes_FromStringAndSize", (PYTHON_PROC*)&py3_PyBytes_FromStringAndSize},
+ {"PyFloat_FromDouble", (PYTHON_PROC*)&py3_PyFloat_FromDouble},
+ {"PyFloat_AsDouble", (PYTHON_PROC*)&py3_PyFloat_AsDouble},
+ {"PyObject_GenericGetAttr", (PYTHON_PROC*)&py3_PyObject_GenericGetAttr},
+ {"PyType_GenericAlloc", (PYTHON_PROC*)&py3_PyType_GenericAlloc},
+ {"PyType_GenericNew", (PYTHON_PROC*)&py3_PyType_GenericNew},
+ {"PyType_Type", (PYTHON_PROC*)&py3_PyType_Type},
+ {"PyStdPrinter_Type", (PYTHON_PROC*)&py3_PyStdPrinter_Type},
+ {"PySlice_Type", (PYTHON_PROC*)&py3_PySlice_Type},
+ {"PyFloat_Type", (PYTHON_PROC*)&py3_PyFloat_Type},
+ {"PyBool_Type", (PYTHON_PROC*)&py3_PyBool_Type},
+ {"PyNumber_Check", (PYTHON_PROC*)&py3_PyNumber_Check},
+ {"PyNumber_Long", (PYTHON_PROC*)&py3_PyNumber_Long},
+ {"PyErr_NewException", (PYTHON_PROC*)&py3_PyErr_NewException},
+# ifdef Py_DEBUG
+ {"_Py_NegativeRefcount", (PYTHON_PROC*)&py3__Py_NegativeRefcount},
+ {"_Py_RefTotal", (PYTHON_PROC*)&py3__Py_RefTotal},
+ {"_Py_Dealloc", (PYTHON_PROC*)&py3__Py_Dealloc},
+ {"PyModule_Create2TraceRefs", (PYTHON_PROC*)&py3_PyModule_Create2TraceRefs},
+# else
+ {"PyModule_Create2", (PYTHON_PROC*)&py3_PyModule_Create2},
+# endif
+# if defined(Py_DEBUG) && !defined(Py_DEBUG_NO_PYMALLOC)
+ {"_PyObject_DebugFree", (PYTHON_PROC*)&py3__PyObject_DebugFree},
+ {"_PyObject_DebugMalloc", (PYTHON_PROC*)&py3__PyObject_DebugMalloc},
+# else
+ {"PyObject_Malloc", (PYTHON_PROC*)&py3_PyObject_Malloc},
+ {"PyObject_Free", (PYTHON_PROC*)&py3_PyObject_Free},
+# endif
+ {"_PyObject_GC_New", (PYTHON_PROC*)&py3__PyObject_GC_New},
+ {"PyObject_GC_Del", (PYTHON_PROC*)&py3_PyObject_GC_Del},
+ {"PyObject_GC_UnTrack", (PYTHON_PROC*)&py3_PyObject_GC_UnTrack},
+ {"PyType_IsSubtype", (PYTHON_PROC*)&py3_PyType_IsSubtype},
+ {"PyCapsule_New", (PYTHON_PROC*)&py3_PyCapsule_New},
+ {"PyCapsule_GetPointer", (PYTHON_PROC*)&py3_PyCapsule_GetPointer},
+ {"", NULL},
+};
+
+/*
+ * Free python.dll
+ */
+ static void
+end_dynamic_python3(void)
+{
+ if (hinstPy3 != 0)
+ {
+ close_dll(hinstPy3);
+ hinstPy3 = 0;
+ }
+}
+
+/*
+ * Load library and get all pointers.
+ * Parameter 'libname' provides name of DLL.
+ * Return OK or FAIL.
+ */
+ static int
+py3_runtime_link_init(char *libname, int verbose)
+{
+ int i;
+ PYTHON_PROC *ucs_from_string = (PYTHON_PROC *)&py3_PyUnicode_FromString;
+ PYTHON_PROC *ucs_decode = (PYTHON_PROC *)&py3_PyUnicode_Decode;
+ PYTHON_PROC *ucs_as_encoded_string =
+ (PYTHON_PROC *)&py3_PyUnicode_AsEncodedString;
+
+# if !(defined(PY_NO_RTLD_GLOBAL) && defined(PY3_NO_RTLD_GLOBAL)) && defined(UNIX) && defined(FEAT_PYTHON)
+ /* Can't have Python and Python3 loaded at the same time.
+ * It cause a crash, because RTLD_GLOBAL is needed for
+ * standard C extension libraries of one or both python versions. */
+ if (python_loaded())
+ {
+ if (verbose)
+ emsg(_("E837: This Vim cannot execute :py3 after using :python"));
+ return FAIL;
+ }
+# endif
+
+ if (hinstPy3 != 0)
+ return OK;
+ hinstPy3 = load_dll(libname);
+
+ if (!hinstPy3)
+ {
+ if (verbose)
+ semsg(_(e_loadlib), libname);
+ return FAIL;
+ }
+
+ for (i = 0; py3_funcname_table[i].ptr; ++i)
+ {
+ if ((*py3_funcname_table[i].ptr = symbol_from_dll(hinstPy3,
+ py3_funcname_table[i].name)) == NULL)
+ {
+ close_dll(hinstPy3);
+ hinstPy3 = 0;
+ if (verbose)
+ semsg(_(e_loadfunc), py3_funcname_table[i].name);
+ return FAIL;
+ }
+ }
+
+ /* Load unicode functions separately as only the ucs2 or the ucs4 functions
+ * will be present in the library. */
+# if PY_VERSION_HEX >= 0x030300f0
+ *ucs_from_string = symbol_from_dll(hinstPy3, "PyUnicode_FromString");
+ *ucs_decode = symbol_from_dll(hinstPy3, "PyUnicode_Decode");
+ *ucs_as_encoded_string = symbol_from_dll(hinstPy3,
+ "PyUnicode_AsEncodedString");
+# else
+ *ucs_from_string = symbol_from_dll(hinstPy3, "PyUnicodeUCS2_FromString");
+ *ucs_decode = symbol_from_dll(hinstPy3,
+ "PyUnicodeUCS2_Decode");
+ *ucs_as_encoded_string = symbol_from_dll(hinstPy3,
+ "PyUnicodeUCS2_AsEncodedString");
+ if (*ucs_from_string == NULL || *ucs_decode == NULL
+ || *ucs_as_encoded_string == NULL)
+ {
+ *ucs_from_string = symbol_from_dll(hinstPy3,
+ "PyUnicodeUCS4_FromString");
+ *ucs_decode = symbol_from_dll(hinstPy3,
+ "PyUnicodeUCS4_Decode");
+ *ucs_as_encoded_string = symbol_from_dll(hinstPy3,
+ "PyUnicodeUCS4_AsEncodedString");
+ }
+# endif
+ if (*ucs_from_string == NULL || *ucs_decode == NULL
+ || *ucs_as_encoded_string == NULL)
+ {
+ close_dll(hinstPy3);
+ hinstPy3 = 0;
+ if (verbose)
+ semsg(_(e_loadfunc), "PyUnicode_UCSX_*");
+ return FAIL;
+ }
+
+ return OK;
+}
+
+/*
+ * If python is enabled (there is installed python on Windows system) return
+ * TRUE, else FALSE.
+ */
+ int
+python3_enabled(int verbose)
+{
+ return py3_runtime_link_init((char *)p_py3dll, verbose) == OK;
+}
+
+/* Load the standard Python exceptions - don't import the symbols from the
+ * DLL, as this can cause errors (importing data symbols is not reliable).
+ */
+ static void
+get_py3_exceptions(void)
+{
+ PyObject *exmod = PyImport_ImportModule("builtins");
+ PyObject *exdict = PyModule_GetDict(exmod);
+ p3imp_PyExc_AttributeError = PyDict_GetItemString(exdict, "AttributeError");
+ p3imp_PyExc_IndexError = PyDict_GetItemString(exdict, "IndexError");
+ p3imp_PyExc_KeyError = PyDict_GetItemString(exdict, "KeyError");
+ p3imp_PyExc_KeyboardInterrupt = PyDict_GetItemString(exdict, "KeyboardInterrupt");
+ p3imp_PyExc_TypeError = PyDict_GetItemString(exdict, "TypeError");
+ p3imp_PyExc_ValueError = PyDict_GetItemString(exdict, "ValueError");
+ p3imp_PyExc_SystemExit = PyDict_GetItemString(exdict, "SystemExit");
+ p3imp_PyExc_RuntimeError = PyDict_GetItemString(exdict, "RuntimeError");
+ p3imp_PyExc_ImportError = PyDict_GetItemString(exdict, "ImportError");
+ p3imp_PyExc_OverflowError = PyDict_GetItemString(exdict, "OverflowError");
+ Py_XINCREF(p3imp_PyExc_AttributeError);
+ Py_XINCREF(p3imp_PyExc_IndexError);
+ Py_XINCREF(p3imp_PyExc_KeyError);
+ Py_XINCREF(p3imp_PyExc_KeyboardInterrupt);
+ Py_XINCREF(p3imp_PyExc_TypeError);
+ Py_XINCREF(p3imp_PyExc_ValueError);
+ Py_XINCREF(p3imp_PyExc_SystemExit);
+ Py_XINCREF(p3imp_PyExc_RuntimeError);
+ Py_XINCREF(p3imp_PyExc_ImportError);
+ Py_XINCREF(p3imp_PyExc_OverflowError);
+ Py_XDECREF(exmod);
+}
+#endif /* DYNAMIC_PYTHON3 */
+
+static int py3initialised = 0;
+#define PYINITIALISED py3initialised
+static int python_end_called = FALSE;
+
+#define DESTRUCTOR_FINISH(self) Py_TYPE(self)->tp_free((PyObject*)self)
+
+#define WIN_PYTHON_REF(win) win->w_python3_ref
+#define BUF_PYTHON_REF(buf) buf->b_python3_ref
+#define TAB_PYTHON_REF(tab) tab->tp_python3_ref
+
+ static void
+call_PyObject_Free(void *p)
+{
+#if defined(Py_DEBUG) && !defined(Py_DEBUG_NO_PYMALLOC)
+ _PyObject_DebugFree(p);
+#else
+ PyObject_Free(p);
+#endif
+}
+
+ static PyObject *
+call_PyType_GenericNew(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ return PyType_GenericNew(type,args,kwds);
+}
+
+ static PyObject *
+call_PyType_GenericAlloc(PyTypeObject *type, Py_ssize_t nitems)
+{
+ return PyType_GenericAlloc(type,nitems);
+}
+
+static PyObject *OutputGetattro(PyObject *, PyObject *);
+static int OutputSetattro(PyObject *, PyObject *, PyObject *);
+static PyObject *BufferGetattro(PyObject *, PyObject *);
+static int BufferSetattro(PyObject *, PyObject *, PyObject *);
+static PyObject *TabPageGetattro(PyObject *, PyObject *);
+static PyObject *WindowGetattro(PyObject *, PyObject *);
+static int WindowSetattro(PyObject *, PyObject *, PyObject *);
+static PyObject *RangeGetattro(PyObject *, PyObject *);
+static PyObject *CurrentGetattro(PyObject *, PyObject *);
+static int CurrentSetattro(PyObject *, PyObject *, PyObject *);
+static PyObject *DictionaryGetattro(PyObject *, PyObject *);
+static int DictionarySetattro(PyObject *, PyObject *, PyObject *);
+static PyObject *ListGetattro(PyObject *, PyObject *);
+static int ListSetattro(PyObject *, PyObject *, PyObject *);
+static PyObject *FunctionGetattro(PyObject *, PyObject *);
+
+static struct PyModuleDef vimmodule;
+
+#define PY_CAN_RECURSE
+
+/*
+ * Include the code shared with if_python.c
+ */
+#include "if_py_both.h"
+
+#define GET_ATTR_STRING(name, nameobj) \
+ char *name = ""; \
+ if (PyUnicode_Check(nameobj)) \
+ name = _PyUnicode_AsString(nameobj)
+
+#define PY3OBJ_DELETED(obj) (obj->ob_base.ob_refcnt<=0)
+
+/******************************************************
+ * Internal function prototypes.
+ */
+
+static PyObject *Py3Init_vim(void);
+
+/******************************************************
+ * 1. Python interpreter main program.
+ */
+
+ void
+python3_end(void)
+{
+ static int recurse = 0;
+
+ /* If a crash occurs while doing this, don't try again. */
+ if (recurse != 0)
+ return;
+
+ python_end_called = TRUE;
+ ++recurse;
+
+#ifdef DYNAMIC_PYTHON3
+ if (hinstPy3)
+#endif
+ if (Py_IsInitialized())
+ {
+ /* acquire lock before finalizing */
+ PyGILState_Ensure();
+
+ Py_Finalize();
+ }
+
+#ifdef DYNAMIC_PYTHON3
+ end_dynamic_python3();
+#endif
+
+ --recurse;
+}
+
+#if (defined(DYNAMIC_PYTHON3) && defined(DYNAMIC_PYTHON) && defined(FEAT_PYTHON) && defined(UNIX)) || defined(PROTO)
+ int
+python3_loaded(void)
+{
+ return (hinstPy3 != 0);
+}
+#endif
+
+static wchar_t *py_home_buf = NULL;
+
+ static int
+Python3_Init(void)
+{
+ if (!py3initialised)
+ {
+#ifdef DYNAMIC_PYTHON3
+ if (!python3_enabled(TRUE))
+ {
+ emsg(_("E263: Sorry, this command is disabled, the Python library could not be loaded."));
+ goto fail;
+ }
+#endif
+
+ init_structs();
+
+ if (*p_py3home != NUL)
+ {
+ size_t len = mbstowcs(NULL, (char *)p_py3home, 0) + 1;
+
+ /* The string must not change later, make a copy in static memory. */
+ py_home_buf = (wchar_t *)alloc(len * sizeof(wchar_t));
+ if (py_home_buf != NULL && mbstowcs(
+ py_home_buf, (char *)p_py3home, len) != (size_t)-1)
+ Py_SetPythonHome(py_home_buf);
+ }
+#ifdef PYTHON3_HOME
+ else if (mch_getenv((char_u *)"PYTHONHOME") == NULL)
+ Py_SetPythonHome(PYTHON3_HOME);
+#endif
+
+ PyImport_AppendInittab("vim", Py3Init_vim);
+
+ Py_Initialize();
+
+ /* Initialise threads, and below save the state using
+ * PyEval_SaveThread. Without the call to PyEval_SaveThread, thread
+ * specific state (such as the system trace hook), will be lost
+ * between invocations of Python code. */
+ PyEval_InitThreads();
+#ifdef DYNAMIC_PYTHON3
+ get_py3_exceptions();
+#endif
+
+ if (PythonIO_Init_io())
+ goto fail;
+
+ globals = PyModule_GetDict(PyImport_AddModule("__main__"));
+
+ /* Remove the element from sys.path that was added because of our
+ * argv[0] value in Py3Init_vim(). Previously we used an empty
+ * string, but depending on the OS we then get an empty entry or
+ * the current directory in sys.path.
+ * Only after vim has been imported, the element does exist in
+ * sys.path.
+ */
+ PyRun_SimpleString("import vim; import sys; sys.path = list(filter(lambda x: not x.endswith('must>not&exist'), sys.path))");
+
+ /* lock is created and acquired in PyEval_InitThreads() and thread
+ * state is created in Py_Initialize()
+ * there _PyGILState_NoteThreadState() also sets gilcounter to 1
+ * (python must have threads enabled!)
+ * so the following does both: unlock GIL and save thread state in TLS
+ * without deleting thread state
+ */
+ PyEval_SaveThread();
+
+ py3initialised = 1;
+ }
+
+ return 0;
+
+fail:
+ /* We call PythonIO_Flush() here to print any Python errors.
+ * This is OK, as it is possible to call this function even
+ * if PythonIO_Init_io() has not completed successfully (it will
+ * not do anything in this case).
+ */
+ PythonIO_Flush();
+ return -1;
+}
+
+/*
+ * External interface
+ */
+ static void
+DoPyCommand(const char *cmd, rangeinitializer init_range, runner run, void *arg)
+{
+#if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
+ char *saved_locale;
+#endif
+ PyObject *cmdstr;
+ PyObject *cmdbytes;
+ PyGILState_STATE pygilstate;
+
+ if (python_end_called)
+ goto theend;
+
+ if (Python3_Init())
+ goto theend;
+
+ init_range(arg);
+
+ Python_Release_Vim(); /* leave vim */
+
+#if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
+ /* Python only works properly when the LC_NUMERIC locale is "C". */
+ saved_locale = setlocale(LC_NUMERIC, NULL);
+ if (saved_locale == NULL || STRCMP(saved_locale, "C") == 0)
+ saved_locale = NULL;
+ else
+ {
+ /* Need to make a copy, value may change when setting new locale. */
+ saved_locale = (char *)vim_strsave((char_u *)saved_locale);
+ (void)setlocale(LC_NUMERIC, "C");
+ }
+#endif
+
+ pygilstate = PyGILState_Ensure();
+
+ /* PyRun_SimpleString expects a UTF-8 string. Wrong encoding may cause
+ * SyntaxError (unicode error). */
+ cmdstr = PyUnicode_Decode(cmd, strlen(cmd),
+ (char *)ENC_OPT, CODEC_ERROR_HANDLER);
+ cmdbytes = PyUnicode_AsEncodedString(cmdstr, "utf-8", CODEC_ERROR_HANDLER);
+ Py_XDECREF(cmdstr);
+
+ run(PyBytes_AsString(cmdbytes), arg, &pygilstate);
+ Py_XDECREF(cmdbytes);
+
+ PyGILState_Release(pygilstate);
+
+#if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
+ if (saved_locale != NULL)
+ {
+ (void)setlocale(LC_NUMERIC, saved_locale);
+ vim_free(saved_locale);
+ }
+#endif
+
+ Python_Lock_Vim(); /* enter vim */
+ PythonIO_Flush();
+
+theend:
+ return; /* keeps lint happy */
+}
+
+/*
+ * ":py3"
+ */
+ void
+ex_py3(exarg_T *eap)
+{
+ char_u *script;
+
+ if (p_pyx == 0)
+ p_pyx = 3;
+
+ script = script_get(eap, eap->arg);
+ if (!eap->skip)
+ {
+ DoPyCommand(script == NULL ? (char *) eap->arg : (char *) script,
+ (rangeinitializer) init_range_cmd,
+ (runner) run_cmd,
+ (void *) eap);
+ }
+ vim_free(script);
+}
+
+#define BUFFER_SIZE 2048
+
+/*
+ * ":py3file"
+ */
+ void
+ex_py3file(exarg_T *eap)
+{
+ static char buffer[BUFFER_SIZE];
+ const char *file;
+ char *p;
+ int i;
+
+ if (p_pyx == 0)
+ p_pyx = 3;
+
+ /* Have to do it like this. PyRun_SimpleFile requires you to pass a
+ * stdio file pointer, but Vim and the Python DLL are compiled with
+ * different options under Windows, meaning that stdio pointers aren't
+ * compatible between the two. Yuk.
+ *
+ * construct: exec(compile(open('a_filename', 'rb').read(), 'a_filename', 'exec'))
+ *
+ * Using bytes so that Python can detect the source encoding as it normally
+ * does. The doc does not say "compile" accept bytes, though.
+ *
+ * We need to escape any backslashes or single quotes in the file name, so that
+ * Python won't mangle the file name.
+ */
+
+ strcpy(buffer, "exec(compile(open('");
+ p = buffer + 19; /* size of "exec(compile(open('" */
+
+ for (i=0; i<2; ++i)
+ {
+ file = (char *)eap->arg;
+ while (*file && p < buffer + (BUFFER_SIZE - 3))
+ {
+ if (*file == '\\' || *file == '\'')
+ *p++ = '\\';
+ *p++ = *file++;
+ }
+ /* If we didn't finish the file name, we hit a buffer overflow */
+ if (*file != '\0')
+ return;
+ if (i==0)
+ {
+ strcpy(p,"','rb').read(),'");
+ p += 16;
+ }
+ else
+ {
+ strcpy(p,"','exec'))");
+ p += 10;
+ }
+ }
+
+
+ /* Execute the file */
+ DoPyCommand(buffer,
+ (rangeinitializer) init_range_cmd,
+ (runner) run_cmd,
+ (void *) eap);
+}
+
+ void
+ex_py3do(exarg_T *eap)
+{
+ if (p_pyx == 0)
+ p_pyx = 3;
+
+ DoPyCommand((char *)eap->arg,
+ (rangeinitializer)init_range_cmd,
+ (runner)run_do,
+ (void *)eap);
+}
+
+/******************************************************
+ * 2. Python output stream: writes output via [e]msg().
+ */
+
+/* Implementation functions
+ */
+
+ static PyObject *
+OutputGetattro(PyObject *self, PyObject *nameobj)
+{
+ GET_ATTR_STRING(name, nameobj);
+
+ if (strcmp(name, "softspace") == 0)
+ return PyLong_FromLong(((OutputObject *)(self))->softspace);
+ else if (strcmp(name, "errors") == 0)
+ return PyString_FromString("strict");
+ else if (strcmp(name, "encoding") == 0)
+ return PyString_FromString(ENC_OPT);
+
+ return PyObject_GenericGetAttr(self, nameobj);
+}
+
+ static int
+OutputSetattro(PyObject *self, PyObject *nameobj, PyObject *val)
+{
+ GET_ATTR_STRING(name, nameobj);
+
+ return OutputSetattr((OutputObject *)(self), name, val);
+}
+
+/******************************************************
+ * 3. Implementation of the Vim module for Python
+ */
+
+/* Window type - Implementation functions
+ * --------------------------------------
+ */
+
+#define WindowType_Check(obj) ((obj)->ob_base.ob_type == &WindowType)
+
+/* Buffer type - Implementation functions
+ * --------------------------------------
+ */
+
+#define BufferType_Check(obj) ((obj)->ob_base.ob_type == &BufferType)
+
+static PyObject* BufferSubscript(PyObject *self, PyObject *idx);
+static Py_ssize_t BufferAsSubscript(PyObject *self, PyObject *idx, PyObject *val);
+
+/* Line range type - Implementation functions
+ * --------------------------------------
+ */
+
+#define RangeType_Check(obj) ((obj)->ob_base.ob_type == &RangeType)
+
+static PyObject* RangeSubscript(PyObject *self, PyObject *idx);
+static Py_ssize_t RangeAsItem(PyObject *, Py_ssize_t, PyObject *);
+static Py_ssize_t RangeAsSubscript(PyObject *self, PyObject *idx, PyObject *val);
+
+/* Current objects type - Implementation functions
+ * -----------------------------------------------
+ */
+
+static PySequenceMethods BufferAsSeq = {
+ (lenfunc) BufferLength, /* sq_length, len(x) */
+ (binaryfunc) 0, /* sq_concat, x+y */
+ (ssizeargfunc) 0, /* sq_repeat, x*n */
+ (ssizeargfunc) BufferItem, /* sq_item, x[i] */
+ 0, /* was_sq_slice, x[i:j] */
+ 0, /* sq_ass_item, x[i]=v */
+ 0, /* sq_ass_slice, x[i:j]=v */
+ 0, /* sq_contains */
+ 0, /* sq_inplace_concat */
+ 0, /* sq_inplace_repeat */
+};
+
+static PyMappingMethods BufferAsMapping = {
+ /* mp_length */ (lenfunc)BufferLength,
+ /* mp_subscript */ (binaryfunc)BufferSubscript,
+ /* mp_ass_subscript */ (objobjargproc)BufferAsSubscript,
+};
+
+
+/* Buffer object
+ */
+
+ static PyObject *
+BufferGetattro(PyObject *self, PyObject *nameobj)
+{
+ PyObject *r;
+
+ GET_ATTR_STRING(name, nameobj);
+
+ if ((r = BufferAttrValid((BufferObject *)(self), name)))
+ return r;
+
+ if (CheckBuffer((BufferObject *)(self)))
+ return NULL;
+
+ r = BufferAttr((BufferObject *)(self), name);
+ if (r || PyErr_Occurred())
+ return r;
+ else
+ return PyObject_GenericGetAttr(self, nameobj);
+}
+
+ static int
+BufferSetattro(PyObject *self, PyObject *nameobj, PyObject *val)
+{
+ GET_ATTR_STRING(name, nameobj);
+
+ return BufferSetattr((BufferObject *)(self), name, val);
+}
+
+/******************/
+
+ static PyObject *
+BufferSubscript(PyObject *self, PyObject* idx)
+{
+ if (PyLong_Check(idx))
+ {
+ long _idx = PyLong_AsLong(idx);
+ return BufferItem((BufferObject *)(self), _idx);
+ } else if (PySlice_Check(idx))
+ {
+ Py_ssize_t start, stop, step, slicelen;
+
+ if (CheckBuffer((BufferObject *) self))
+ return NULL;
+
+ if (PySlice_GetIndicesEx((PySliceObject_T *)idx,
+ (Py_ssize_t)((BufferObject *)(self))->buf->b_ml.ml_line_count,
+ &start, &stop,
+ &step, &slicelen) < 0)
+ {
+ return NULL;
+ }
+ return BufferSlice((BufferObject *)(self), start, stop);
+ }
+ else
+ {
+ RAISE_INVALID_INDEX_TYPE(idx);
+ return NULL;
+ }
+}
+
+ static Py_ssize_t
+BufferAsSubscript(PyObject *self, PyObject* idx, PyObject* val)
+{
+ if (PyLong_Check(idx))
+ {
+ long n = PyLong_AsLong(idx);
+ return RBAsItem((BufferObject *)(self), n, val, 1,
+ (Py_ssize_t)((BufferObject *)(self))->buf->b_ml.ml_line_count,
+ NULL);
+ } else if (PySlice_Check(idx))
+ {
+ Py_ssize_t start, stop, step, slicelen;
+
+ if (CheckBuffer((BufferObject *) self))
+ return -1;
+
+ if (PySlice_GetIndicesEx((PySliceObject_T *)idx,
+ (Py_ssize_t)((BufferObject *)(self))->buf->b_ml.ml_line_count,
+ &start, &stop,
+ &step, &slicelen) < 0)
+ {
+ return -1;
+ }
+ return RBAsSlice((BufferObject *)(self), start, stop, val, 1,
+ (PyInt)((BufferObject *)(self))->buf->b_ml.ml_line_count,
+ NULL);
+ }
+ else
+ {
+ RAISE_INVALID_INDEX_TYPE(idx);
+ return -1;
+ }
+}
+
+static PySequenceMethods RangeAsSeq = {
+ (lenfunc) RangeLength, /* sq_length, len(x) */
+ (binaryfunc) 0, /* RangeConcat, sq_concat, x+y */
+ (ssizeargfunc) 0, /* RangeRepeat, sq_repeat, x*n */
+ (ssizeargfunc) RangeItem, /* sq_item, x[i] */
+ 0, /* was_sq_slice, x[i:j] */
+ (ssizeobjargproc) RangeAsItem, /* sq_as_item, x[i]=v */
+ 0, /* sq_ass_slice, x[i:j]=v */
+ 0, /* sq_contains */
+ 0, /* sq_inplace_concat */
+ 0, /* sq_inplace_repeat */
+};
+
+static PyMappingMethods RangeAsMapping = {
+ /* mp_length */ (lenfunc)RangeLength,
+ /* mp_subscript */ (binaryfunc)RangeSubscript,
+ /* mp_ass_subscript */ (objobjargproc)RangeAsSubscript,
+};
+
+/* Line range object - Implementation
+ */
+
+ static PyObject *
+RangeGetattro(PyObject *self, PyObject *nameobj)
+{
+ GET_ATTR_STRING(name, nameobj);
+
+ if (strcmp(name, "start") == 0)
+ return Py_BuildValue("n", ((RangeObject *)(self))->start - 1);
+ else if (strcmp(name, "end") == 0)
+ return Py_BuildValue("n", ((RangeObject *)(self))->end - 1);
+ else
+ return PyObject_GenericGetAttr(self, nameobj);
+}
+
+/****************/
+
+ static Py_ssize_t
+RangeAsItem(PyObject *self, Py_ssize_t n, PyObject *val)
+{
+ return RBAsItem(((RangeObject *)(self))->buf, n, val,
+ ((RangeObject *)(self))->start,
+ ((RangeObject *)(self))->end,
+ &((RangeObject *)(self))->end);
+}
+
+ static Py_ssize_t
+RangeAsSlice(PyObject *self, Py_ssize_t lo, Py_ssize_t hi, PyObject *val)
+{
+ return RBAsSlice(((RangeObject *)(self))->buf, lo, hi, val,
+ ((RangeObject *)(self))->start,
+ ((RangeObject *)(self))->end,
+ &((RangeObject *)(self))->end);
+}
+
+ static PyObject *
+RangeSubscript(PyObject *self, PyObject* idx)
+{
+ if (PyLong_Check(idx))
+ {
+ long _idx = PyLong_AsLong(idx);
+ return RangeItem((RangeObject *)(self), _idx);
+ } else if (PySlice_Check(idx))
+ {
+ Py_ssize_t start, stop, step, slicelen;
+
+ if (PySlice_GetIndicesEx((PySliceObject_T *)idx,
+ ((RangeObject *)(self))->end-((RangeObject *)(self))->start+1,
+ &start, &stop,
+ &step, &slicelen) < 0)
+ {
+ return NULL;
+ }
+ return RangeSlice((RangeObject *)(self), start, stop);
+ }
+ else
+ {
+ RAISE_INVALID_INDEX_TYPE(idx);
+ return NULL;
+ }
+}
+
+ static Py_ssize_t
+RangeAsSubscript(PyObject *self, PyObject *idx, PyObject *val)
+{
+ if (PyLong_Check(idx))
+ {
+ long n = PyLong_AsLong(idx);
+ return RangeAsItem(self, n, val);
+ } else if (PySlice_Check(idx))
+ {
+ Py_ssize_t start, stop, step, slicelen;
+
+ if (PySlice_GetIndicesEx((PySliceObject_T *)idx,
+ ((RangeObject *)(self))->end-((RangeObject *)(self))->start+1,
+ &start, &stop,
+ &step, &slicelen) < 0)
+ {
+ return -1;
+ }
+ return RangeAsSlice(self, start, stop, val);
+ }
+ else
+ {
+ RAISE_INVALID_INDEX_TYPE(idx);
+ return -1;
+ }
+}
+
+/* TabPage object - Implementation
+ */
+
+ static PyObject *
+TabPageGetattro(PyObject *self, PyObject *nameobj)
+{
+ PyObject *r;
+
+ GET_ATTR_STRING(name, nameobj);
+
+ if ((r = TabPageAttrValid((TabPageObject *)(self), name)))
+ return r;
+
+ if (CheckTabPage((TabPageObject *)(self)))
+ return NULL;
+
+ r = TabPageAttr((TabPageObject *)(self), name);
+ if (r || PyErr_Occurred())
+ return r;
+ else
+ return PyObject_GenericGetAttr(self, nameobj);
+}
+
+/* Window object - Implementation
+ */
+
+ static PyObject *
+WindowGetattro(PyObject *self, PyObject *nameobj)
+{
+ PyObject *r;
+
+ GET_ATTR_STRING(name, nameobj);
+
+ if ((r = WindowAttrValid((WindowObject *)(self), name)))
+ return r;
+
+ if (CheckWindow((WindowObject *)(self)))
+ return NULL;
+
+ r = WindowAttr((WindowObject *)(self), name);
+ if (r || PyErr_Occurred())
+ return r;
+ else
+ return PyObject_GenericGetAttr(self, nameobj);
+}
+
+ static int
+WindowSetattro(PyObject *self, PyObject *nameobj, PyObject *val)
+{
+ GET_ATTR_STRING(name, nameobj);
+
+ return WindowSetattr((WindowObject *)(self), name, val);
+}
+
+/* Tab page list object - Definitions
+ */
+
+static PySequenceMethods TabListAsSeq = {
+ (lenfunc) TabListLength, /* sq_length, len(x) */
+ (binaryfunc) 0, /* sq_concat, x+y */
+ (ssizeargfunc) 0, /* sq_repeat, x*n */
+ (ssizeargfunc) TabListItem, /* sq_item, x[i] */
+ 0, /* sq_slice, x[i:j] */
+ (ssizeobjargproc)0, /* sq_as_item, x[i]=v */
+ 0, /* sq_ass_slice, x[i:j]=v */
+ 0, /* sq_contains */
+ 0, /* sq_inplace_concat */
+ 0, /* sq_inplace_repeat */
+};
+
+/* Window list object - Definitions
+ */
+
+static PySequenceMethods WinListAsSeq = {
+ (lenfunc) WinListLength, /* sq_length, len(x) */
+ (binaryfunc) 0, /* sq_concat, x+y */
+ (ssizeargfunc) 0, /* sq_repeat, x*n */
+ (ssizeargfunc) WinListItem, /* sq_item, x[i] */
+ 0, /* sq_slice, x[i:j] */
+ (ssizeobjargproc)0, /* sq_as_item, x[i]=v */
+ 0, /* sq_ass_slice, x[i:j]=v */
+ 0, /* sq_contains */
+ 0, /* sq_inplace_concat */
+ 0, /* sq_inplace_repeat */
+};
+
+/* Current items object - Implementation
+ */
+ static PyObject *
+CurrentGetattro(PyObject *self, PyObject *nameobj)
+{
+ PyObject *r;
+ GET_ATTR_STRING(name, nameobj);
+ if (!(r = CurrentGetattr(self, name)))
+ return PyObject_GenericGetAttr(self, nameobj);
+ return r;
+}
+
+ static int
+CurrentSetattro(PyObject *self, PyObject *nameobj, PyObject *value)
+{
+ GET_ATTR_STRING(name, nameobj);
+ return CurrentSetattr(self, name, value);
+}
+
+/* Dictionary object - Definitions
+ */
+
+ static PyObject *
+DictionaryGetattro(PyObject *self, PyObject *nameobj)
+{
+ DictionaryObject *this = ((DictionaryObject *) (self));
+
+ GET_ATTR_STRING(name, nameobj);
+
+ if (strcmp(name, "locked") == 0)
+ return PyLong_FromLong(this->dict->dv_lock);
+ else if (strcmp(name, "scope") == 0)
+ return PyLong_FromLong(this->dict->dv_scope);
+
+ return PyObject_GenericGetAttr(self, nameobj);
+}
+
+ static int
+DictionarySetattro(PyObject *self, PyObject *nameobj, PyObject *val)
+{
+ GET_ATTR_STRING(name, nameobj);
+ return DictionarySetattr((DictionaryObject *)(self), name, val);
+}
+
+/* List object - Definitions
+ */
+
+ static PyObject *
+ListGetattro(PyObject *self, PyObject *nameobj)
+{
+ GET_ATTR_STRING(name, nameobj);
+
+ if (strcmp(name, "locked") == 0)
+ return PyLong_FromLong(((ListObject *) (self))->list->lv_lock);
+
+ return PyObject_GenericGetAttr(self, nameobj);
+}
+
+ static int
+ListSetattro(PyObject *self, PyObject *nameobj, PyObject *val)
+{
+ GET_ATTR_STRING(name, nameobj);
+ return ListSetattr((ListObject *)(self), name, val);
+}
+
+/* Function object - Definitions
+ */
+
+ static PyObject *
+FunctionGetattro(PyObject *self, PyObject *nameobj)
+{
+ PyObject *r;
+ FunctionObject *this = (FunctionObject *)(self);
+
+ GET_ATTR_STRING(name, nameobj);
+
+ r = FunctionAttr(this, name);
+ if (r || PyErr_Occurred())
+ return r;
+ else
+ return PyObject_GenericGetAttr(self, nameobj);
+}
+
+/* External interface
+ */
+
+ void
+python3_buffer_free(buf_T *buf)
+{
+ if (BUF_PYTHON_REF(buf) != NULL)
+ {
+ BufferObject *bp = BUF_PYTHON_REF(buf);
+ bp->buf = INVALID_BUFFER_VALUE;
+ BUF_PYTHON_REF(buf) = NULL;
+ }
+}
+
+ void
+python3_window_free(win_T *win)
+{
+ if (WIN_PYTHON_REF(win) != NULL)
+ {
+ WindowObject *wp = WIN_PYTHON_REF(win);
+ wp->win = INVALID_WINDOW_VALUE;
+ WIN_PYTHON_REF(win) = NULL;
+ }
+}
+
+ void
+python3_tabpage_free(tabpage_T *tab)
+{
+ if (TAB_PYTHON_REF(tab) != NULL)
+ {
+ TabPageObject *tp = TAB_PYTHON_REF(tab);
+ tp->tab = INVALID_TABPAGE_VALUE;
+ TAB_PYTHON_REF(tab) = NULL;
+ }
+}
+
+ static PyObject *
+Py3Init_vim(void)
+{
+ /* The special value is removed from sys.path in Python3_Init(). */
+ static wchar_t *(argv[2]) = {L"/must>not&exist/foo", NULL};
+
+ if (init_types())
+ return NULL;
+
+ /* Set sys.argv[] to avoid a crash in warn(). */
+ PySys_SetArgv(1, argv);
+
+ if ((vim_module = PyModule_Create(&vimmodule)) == NULL)
+ return NULL;
+
+ if (populate_module(vim_module))
+ return NULL;
+
+ if (init_sys_path())
+ return NULL;
+
+ return vim_module;
+}
+
+/*************************************************************************
+ * 4. Utility functions for handling the interface between Vim and Python.
+ */
+
+/* Convert a Vim line into a Python string.
+ * All internal newlines are replaced by null characters.
+ *
+ * On errors, the Python exception data is set, and NULL is returned.
+ */
+ static PyObject *
+LineToString(const char *str)
+{
+ PyObject *result;
+ Py_ssize_t len = strlen(str);
+ char *tmp,*p;
+
+ tmp = (char *)alloc((unsigned)(len+1));
+ p = tmp;
+ if (p == NULL)
+ {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ while (*str)
+ {
+ if (*str == '\n')
+ *p = '\0';
+ else
+ *p = *str;
+
+ ++p;
+ ++str;
+ }
+ *p = '\0';
+
+ result = PyUnicode_Decode(tmp, len, (char *)ENC_OPT, CODEC_ERROR_HANDLER);
+
+ vim_free(tmp);
+ return result;
+}
+
+ void
+do_py3eval (char_u *str, typval_T *rettv)
+{
+ DoPyCommand((char *) str,
+ (rangeinitializer) init_range_eval,
+ (runner) run_eval,
+ (void *) rettv);
+ switch(rettv->v_type)
+ {
+ case VAR_DICT: ++rettv->vval.v_dict->dv_refcount; break;
+ case VAR_LIST: ++rettv->vval.v_list->lv_refcount; break;
+ case VAR_FUNC: func_ref(rettv->vval.v_string); break;
+ case VAR_PARTIAL: ++rettv->vval.v_partial->pt_refcount; break;
+ case VAR_UNKNOWN:
+ rettv->v_type = VAR_NUMBER;
+ rettv->vval.v_number = 0;
+ break;
+ case VAR_NUMBER:
+ case VAR_STRING:
+ case VAR_FLOAT:
+ case VAR_SPECIAL:
+ case VAR_JOB:
+ case VAR_CHANNEL:
+ case VAR_BLOB:
+ break;
+ }
+}
+
+ int
+set_ref_in_python3 (int copyID)
+{
+ return set_ref_in_py(copyID);
+}
diff --git a/src/if_ruby.c b/src/if_ruby.c
new file mode 100644
index 0000000..24814a2
--- /dev/null
+++ b/src/if_ruby.c
@@ -0,0 +1,1741 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * Ruby interface by Shugo Maeda
+ * with improvements by SegPhault (Ryan Paul)
+ * with improvements by Jon Maken
+ *
+ * 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.
+ */
+
+#include "protodef.h"
+#ifdef HAVE_CONFIG_H
+# include "auto/config.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#ifdef _WIN32
+# if !defined(DYNAMIC_RUBY_VER) || (DYNAMIC_RUBY_VER < 18)
+# define NT
+# endif
+# ifndef DYNAMIC_RUBY
+# define IMPORT /* For static dll usage __declspec(dllimport) */
+# define RUBYEXTERN __declspec(dllimport)
+# endif
+#endif
+#ifndef RUBYEXTERN
+# define RUBYEXTERN extern
+#endif
+
+#if defined(DYNAMIC_RUBY_VER) && DYNAMIC_RUBY_VER >= 24
+# define USE_RUBY_INTEGER
+#endif
+
+#ifdef DYNAMIC_RUBY
+/*
+ * This is tricky. In ruby.h there is (inline) function rb_class_of()
+ * definition. This function use these variables. But we want function to
+ * use dll_* variables.
+ */
+# define rb_cFalseClass (*dll_rb_cFalseClass)
+# define rb_cFixnum (*dll_rb_cFixnum)
+# if defined(USE_RUBY_INTEGER)
+# define rb_cInteger (*dll_rb_cInteger)
+# endif
+# if defined(DYNAMIC_RUBY_VER) && DYNAMIC_RUBY_VER >= 20
+# define rb_cFloat (*dll_rb_cFloat)
+# endif
+# define rb_cNilClass (*dll_rb_cNilClass)
+# define rb_cString (*dll_rb_cString)
+# define rb_cSymbol (*dll_rb_cSymbol)
+# define rb_cTrueClass (*dll_rb_cTrueClass)
+# if defined(DYNAMIC_RUBY_VER) && DYNAMIC_RUBY_VER >= 18
+/*
+ * On ver 1.8, all Ruby functions are exported with "__declspec(dllimport)"
+ * in ruby.h. But it causes trouble for these variables, because it is
+ * defined in this file. When defined this RUBY_EXPORT it modified to
+ * "extern" and be able to avoid this problem.
+ */
+# define RUBY_EXPORT
+# endif
+
+#if !(defined(WIN32) || defined(_WIN64))
+# include <dlfcn.h>
+# define HINSTANCE void*
+# define RUBY_PROC void*
+# define load_dll(n) dlopen((n), RTLD_LAZY|RTLD_GLOBAL)
+# define symbol_from_dll dlsym
+# define close_dll dlclose
+#else
+# define RUBY_PROC FARPROC
+# define load_dll vimLoadLib
+# define symbol_from_dll GetProcAddress
+# define close_dll FreeLibrary
+#endif
+
+#endif /* ifdef DYNAMIC_RUBY */
+
+/* suggested by Ariya Mizutani */
+#if (_MSC_VER == 1200)
+# undef _WIN32_WINNT
+#endif
+
+#if (defined(RUBY_VERSION) && RUBY_VERSION >= 19) \
+ || (defined(DYNAMIC_RUBY_VER) && DYNAMIC_RUBY_VER >= 19)
+# define RUBY19_OR_LATER 1
+#endif
+
+#if (defined(RUBY_VERSION) && RUBY_VERSION >= 20) \
+ || (defined(DYNAMIC_RUBY_VER) && DYNAMIC_RUBY_VER >= 20)
+# define RUBY20_OR_LATER 1
+#endif
+
+#if (defined(RUBY_VERSION) && RUBY_VERSION >= 21) \
+ || (defined(DYNAMIC_RUBY_VER) && DYNAMIC_RUBY_VER >= 21)
+# define RUBY21_OR_LATER 1
+#endif
+
+#if defined(DYNAMIC_RUBY_VER) && DYNAMIC_RUBY_VER >= 19
+/* Ruby 1.9 defines a number of static functions which use rb_num2long and
+ * rb_int2big */
+# define rb_num2long rb_num2long_stub
+# define rb_int2big rb_int2big_stub
+#endif
+
+#if defined(DYNAMIC_RUBY_VER) && DYNAMIC_RUBY_VER >= 19 \
+ && VIM_SIZEOF_INT < VIM_SIZEOF_LONG
+/* Ruby 1.9 defines a number of static functions which use rb_fix2int and
+ * rb_num2int if VIM_SIZEOF_INT < VIM_SIZEOF_LONG (64bit) */
+# define rb_fix2int rb_fix2int_stub
+# define rb_num2int rb_num2int_stub
+#endif
+
+#if defined(DYNAMIC_RUBY_VER) && DYNAMIC_RUBY_VER == 21
+/* Ruby 2.1 adds new GC called RGenGC and RARRAY_PTR uses
+ * rb_gc_writebarrier_unprotect_promoted if USE_RGENGC */
+# define rb_gc_writebarrier_unprotect_promoted rb_gc_writebarrier_unprotect_promoted_stub
+#endif
+#if defined(DYNAMIC_RUBY_VER) && DYNAMIC_RUBY_VER >= 22
+# define rb_gc_writebarrier_unprotect rb_gc_writebarrier_unprotect_stub
+#endif
+
+#if defined(DYNAMIC_RUBY_VER) && DYNAMIC_RUBY_VER >= 26
+# define rb_ary_detransient rb_ary_detransient_stub
+#endif
+
+#include <ruby.h>
+#ifdef RUBY19_OR_LATER
+# include <ruby/encoding.h>
+#endif
+
+#undef off_t /* ruby defines off_t as _int64, Mingw uses long */
+#undef EXTERN
+#undef _
+
+/* T_DATA defined both by Ruby and Mac header files, hack around it... */
+#if defined(MACOS_X)
+# define __OPENTRANSPORT__
+# define __OPENTRANSPORTPROTOCOL__
+# define __OPENTRANSPORTPROVIDERS__
+#endif
+
+/*
+ * The TypedData_XXX macro family can be used since Ruby 1.9.2 but
+ * rb_data_type_t changed in 1.9.3, therefore require at least 2.0.
+ * The old Data_XXX macro family was deprecated on Ruby 2.2.
+ * Use TypedData_XXX if available.
+ */
+#if defined(TypedData_Wrap_Struct) && defined(RUBY20_OR_LATER)
+# define USE_TYPEDDATA 1
+#endif
+
+/*
+ * Backward compatibility for Ruby 1.8 and earlier.
+ * Ruby 1.9 does not provide STR2CSTR, instead StringValuePtr is provided.
+ * Ruby 1.9 does not provide RXXX(s)->len and RXXX(s)->ptr, instead
+ * RXXX_LEN(s) and RXXX_PTR(s) are provided.
+ */
+#ifndef StringValuePtr
+# define StringValuePtr(s) STR2CSTR(s)
+#endif
+#ifndef RARRAY_LEN
+# define RARRAY_LEN(s) RARRAY(s)->len
+#endif
+#ifndef RARRAY_PTR
+# define RARRAY_PTR(s) RARRAY(s)->ptr
+#endif
+#ifndef RSTRING_LEN
+# define RSTRING_LEN(s) RSTRING(s)->len
+#endif
+#ifndef RSTRING_PTR
+# define RSTRING_PTR(s) RSTRING(s)->ptr
+#endif
+
+#ifdef HAVE_DUP
+# undef HAVE_DUP
+#endif
+
+#include "vim.h"
+#include "version.h"
+
+#if defined(PROTO) && !defined(FEAT_RUBY)
+/* Define these to be able to generate the function prototypes. */
+# define VALUE int
+# define RUBY_DATA_FUNC int
+#endif
+
+static int ruby_initialized = 0;
+static void *ruby_stack_start;
+static VALUE objtbl;
+
+static VALUE mVIM;
+static VALUE cBuffer;
+static VALUE cVimWindow;
+static VALUE eDeletedBufferError;
+static VALUE eDeletedWindowError;
+
+static int ensure_ruby_initialized(void);
+static void error_print(int);
+static void ruby_io_init(void);
+static void ruby_vim_init(void);
+
+#if defined(RUBY19_OR_LATER) || defined(RUBY_INIT_STACK)
+# if defined(__ia64) && !defined(ruby_init_stack)
+# define ruby_init_stack(addr) ruby_init_stack((addr), rb_ia64_bsp())
+# endif
+#endif
+
+#if defined(DYNAMIC_RUBY) || defined(PROTO)
+# if defined(PROTO) && !defined(HINSTANCE)
+# define HINSTANCE int /* for generating prototypes */
+# endif
+
+/*
+ * Wrapper defines
+ */
+# define rb_assoc_new dll_rb_assoc_new
+# define rb_cObject (*dll_rb_cObject)
+# define rb_class_new_instance dll_rb_class_new_instance
+# define rb_check_type dll_rb_check_type
+# ifdef USE_TYPEDDATA
+# define rb_check_typeddata dll_rb_check_typeddata
+# endif
+# define rb_class_path dll_rb_class_path
+# ifdef USE_TYPEDDATA
+# if defined(DYNAMIC_RUBY_VER) && DYNAMIC_RUBY_VER >= 23
+# define rb_data_typed_object_wrap dll_rb_data_typed_object_wrap
+# else
+# define rb_data_typed_object_alloc dll_rb_data_typed_object_alloc
+# endif
+# else
+# define rb_data_object_alloc dll_rb_data_object_alloc
+# endif
+# define rb_define_class_under dll_rb_define_class_under
+# define rb_define_const dll_rb_define_const
+# define rb_define_global_function dll_rb_define_global_function
+# define rb_define_method dll_rb_define_method
+# define rb_define_module dll_rb_define_module
+# define rb_define_module_function dll_rb_define_module_function
+# define rb_define_singleton_method dll_rb_define_singleton_method
+# define rb_define_virtual_variable dll_rb_define_virtual_variable
+# define rb_stdout (*dll_rb_stdout)
+# define rb_stderr (*dll_rb_stderr)
+# define rb_eArgError (*dll_rb_eArgError)
+# define rb_eIndexError (*dll_rb_eIndexError)
+# define rb_eRuntimeError (*dll_rb_eRuntimeError)
+# define rb_eStandardError (*dll_rb_eStandardError)
+# define rb_eval_string_protect dll_rb_eval_string_protect
+# ifdef RUBY21_OR_LATER
+# define rb_funcallv dll_rb_funcallv
+# else
+# define rb_funcall2 dll_rb_funcall2
+# endif
+# define rb_global_variable dll_rb_global_variable
+# define rb_hash_aset dll_rb_hash_aset
+# define rb_hash_new dll_rb_hash_new
+# define rb_inspect dll_rb_inspect
+# define rb_int2inum dll_rb_int2inum
+
+// ruby.h may redefine rb_intern to use RUBY_CONST_ID_CACHE(), but that won't
+// work. Not using the cache appears to be the best solution.
+# undef rb_intern
+# define rb_intern dll_rb_intern
+
+# if VIM_SIZEOF_INT < VIM_SIZEOF_LONG /* 64 bits only */
+# if defined(DYNAMIC_RUBY_VER) && DYNAMIC_RUBY_VER <= 18
+# define rb_fix2int dll_rb_fix2int
+# define rb_num2int dll_rb_num2int
+# endif
+# define rb_num2uint dll_rb_num2uint
+# endif
+# define rb_lastline_get dll_rb_lastline_get
+# define rb_lastline_set dll_rb_lastline_set
+# define rb_protect dll_rb_protect
+# define rb_load dll_rb_load
+# ifndef RUBY19_OR_LATER
+# define rb_num2long dll_rb_num2long
+# endif
+# if defined(DYNAMIC_RUBY_VER) && DYNAMIC_RUBY_VER <= 19
+# define rb_num2ulong dll_rb_num2ulong
+# endif
+# define rb_obj_alloc dll_rb_obj_alloc
+# define rb_obj_as_string dll_rb_obj_as_string
+# define rb_obj_id dll_rb_obj_id
+# define rb_raise dll_rb_raise
+# define rb_str_cat dll_rb_str_cat
+# define rb_str_concat dll_rb_str_concat
+# undef rb_str_new
+# define rb_str_new dll_rb_str_new
+# ifdef rb_str_new2
+/* Ruby may #define rb_str_new2 to use rb_str_new_cstr. */
+# define need_rb_str_new_cstr 1
+/* Ruby's headers #define rb_str_new_cstr to make use of GCC's
+ * __builtin_constant_p extension. */
+# undef rb_str_new_cstr
+# define rb_str_new_cstr dll_rb_str_new_cstr
+# else
+# define rb_str_new2 dll_rb_str_new2
+# endif
+# if defined(DYNAMIC_RUBY_VER) && DYNAMIC_RUBY_VER >= 18
+# define rb_string_value dll_rb_string_value
+# define rb_string_value_ptr dll_rb_string_value_ptr
+# define rb_float_new dll_rb_float_new
+# define rb_ary_new dll_rb_ary_new
+# ifdef rb_ary_new4
+# define RB_ARY_NEW4_MACRO 1
+# undef rb_ary_new4
+# endif
+# define rb_ary_new4 dll_rb_ary_new4
+# define rb_ary_push dll_rb_ary_push
+# if defined(RUBY19_OR_LATER) || defined(RUBY_INIT_STACK)
+# ifdef __ia64
+# define rb_ia64_bsp dll_rb_ia64_bsp
+# undef ruby_init_stack
+# define ruby_init_stack(addr) dll_ruby_init_stack((addr), rb_ia64_bsp())
+# else
+# define ruby_init_stack dll_ruby_init_stack
+# endif
+# endif
+# else
+# define rb_str2cstr dll_rb_str2cstr
+# endif
+# ifdef RUBY19_OR_LATER
+# define rb_errinfo dll_rb_errinfo
+# else
+# define ruby_errinfo (*dll_ruby_errinfo)
+# endif
+# define ruby_init dll_ruby_init
+# define ruby_init_loadpath dll_ruby_init_loadpath
+# ifdef WIN3264
+# ifdef RUBY19_OR_LATER
+# define ruby_sysinit dll_ruby_sysinit
+# else
+# define NtInitialize dll_NtInitialize
+# endif
+# if defined(DYNAMIC_RUBY_VER) && DYNAMIC_RUBY_VER >= 18
+# define rb_w32_snprintf dll_rb_w32_snprintf
+# endif
+# endif
+
+# ifdef RUBY19_OR_LATER
+# define ruby_script dll_ruby_script
+# define rb_enc_find_index dll_rb_enc_find_index
+# define rb_enc_find dll_rb_enc_find
+# undef rb_enc_str_new
+# define rb_enc_str_new dll_rb_enc_str_new
+# define rb_sprintf dll_rb_sprintf
+# define rb_require dll_rb_require
+# define ruby_options dll_ruby_options
+# endif
+
+/*
+ * Pointers for dynamic link
+ */
+static VALUE (*dll_rb_assoc_new) (VALUE, VALUE);
+VALUE *dll_rb_cFalseClass;
+VALUE *dll_rb_cFixnum;
+# if defined(USE_RUBY_INTEGER)
+VALUE *dll_rb_cInteger;
+# endif
+# if defined(DYNAMIC_RUBY_VER) && DYNAMIC_RUBY_VER >= 20
+VALUE *dll_rb_cFloat;
+# endif
+VALUE *dll_rb_cNilClass;
+static VALUE *dll_rb_cObject;
+VALUE *dll_rb_cString;
+VALUE *dll_rb_cSymbol;
+VALUE *dll_rb_cTrueClass;
+static VALUE (*dll_rb_class_new_instance) (int,VALUE*,VALUE);
+static void (*dll_rb_check_type) (VALUE,int);
+# ifdef USE_TYPEDDATA
+static void *(*dll_rb_check_typeddata) (VALUE,const rb_data_type_t *);
+# endif
+static VALUE (*dll_rb_class_path) (VALUE);
+# ifdef USE_TYPEDDATA
+# if defined(DYNAMIC_RUBY_VER) && DYNAMIC_RUBY_VER >= 23
+static VALUE (*dll_rb_data_typed_object_wrap) (VALUE, void*, const rb_data_type_t *);
+# else
+static VALUE (*dll_rb_data_typed_object_alloc) (VALUE, void*, const rb_data_type_t *);
+# endif
+# else
+static VALUE (*dll_rb_data_object_alloc) (VALUE, void*, RUBY_DATA_FUNC, RUBY_DATA_FUNC);
+# endif
+static VALUE (*dll_rb_define_class_under) (VALUE, const char*, VALUE);
+static void (*dll_rb_define_const) (VALUE,const char*,VALUE);
+static void (*dll_rb_define_global_function) (const char*,VALUE(*)(),int);
+static void (*dll_rb_define_method) (VALUE,const char*,VALUE(*)(),int);
+static VALUE (*dll_rb_define_module) (const char*);
+static void (*dll_rb_define_module_function) (VALUE,const char*,VALUE(*)(),int);
+static void (*dll_rb_define_singleton_method) (VALUE,const char*,VALUE(*)(),int);
+static void (*dll_rb_define_virtual_variable) (const char*,VALUE(*)(),void(*)());
+static VALUE *dll_rb_stdout;
+static VALUE *dll_rb_stderr;
+static VALUE *dll_rb_eArgError;
+static VALUE *dll_rb_eIndexError;
+static VALUE *dll_rb_eRuntimeError;
+static VALUE *dll_rb_eStandardError;
+static VALUE (*dll_rb_eval_string_protect) (const char*, int*);
+# ifdef RUBY21_OR_LATER
+static VALUE (*dll_rb_funcallv) (VALUE, ID, int, const VALUE*);
+# else
+static VALUE (*dll_rb_funcall2) (VALUE, ID, int, const VALUE*);
+# endif
+static void (*dll_rb_global_variable) (VALUE*);
+static VALUE (*dll_rb_hash_aset) (VALUE, VALUE, VALUE);
+static VALUE (*dll_rb_hash_new) (void);
+static VALUE (*dll_rb_inspect) (VALUE);
+static VALUE (*dll_rb_int2inum) (long);
+static ID (*dll_rb_intern) (const char*);
+# if VIM_SIZEOF_INT < VIM_SIZEOF_LONG /* 64 bits only */
+static long (*dll_rb_fix2int) (VALUE);
+static long (*dll_rb_num2int) (VALUE);
+static unsigned long (*dll_rb_num2uint) (VALUE);
+# endif
+static VALUE (*dll_rb_lastline_get) (void);
+static void (*dll_rb_lastline_set) (VALUE);
+static VALUE (*dll_rb_protect) (VALUE (*)(VALUE), VALUE, int*);
+static void (*dll_rb_load) (VALUE, int);
+static long (*dll_rb_num2long) (VALUE);
+static unsigned long (*dll_rb_num2ulong) (VALUE);
+static VALUE (*dll_rb_obj_alloc) (VALUE);
+static VALUE (*dll_rb_obj_as_string) (VALUE);
+static VALUE (*dll_rb_obj_id) (VALUE);
+static void (*dll_rb_raise) (VALUE, const char*, ...);
+# if defined(DYNAMIC_RUBY_VER) && DYNAMIC_RUBY_VER >= 18
+static VALUE (*dll_rb_string_value) (volatile VALUE*);
+# else
+static char *(*dll_rb_str2cstr) (VALUE,int*);
+# endif
+static VALUE (*dll_rb_str_cat) (VALUE, const char*, long);
+static VALUE (*dll_rb_str_concat) (VALUE, VALUE);
+static VALUE (*dll_rb_str_new) (const char*, long);
+# ifdef need_rb_str_new_cstr
+/* Ruby may #define rb_str_new2 to use rb_str_new_cstr. */
+static VALUE (*dll_rb_str_new_cstr) (const char*);
+# else
+static VALUE (*dll_rb_str_new2) (const char*);
+# endif
+# ifdef RUBY19_OR_LATER
+static VALUE (*dll_rb_errinfo) (void);
+# else
+static VALUE *dll_ruby_errinfo;
+# endif
+static void (*dll_ruby_init) (void);
+static void (*dll_ruby_init_loadpath) (void);
+# ifdef WIN3264
+# ifdef RUBY19_OR_LATER
+static void (*dll_ruby_sysinit) (int*, char***);
+# else
+static void (*dll_NtInitialize) (int*, char***);
+# endif
+# if defined(DYNAMIC_RUBY_VER) && DYNAMIC_RUBY_VER >= 18
+static int (*dll_rb_w32_snprintf)(char*, size_t, const char*, ...);
+# endif
+# endif
+# if defined(DYNAMIC_RUBY_VER) && DYNAMIC_RUBY_VER >= 18
+static char * (*dll_rb_string_value_ptr) (volatile VALUE*);
+static VALUE (*dll_rb_float_new) (double);
+static VALUE (*dll_rb_ary_new) (void);
+static VALUE (*dll_rb_ary_new4) (long n, const VALUE *elts);
+static VALUE (*dll_rb_ary_push) (VALUE, VALUE);
+# if DYNAMIC_RUBY_VER >= 26
+static void (*dll_rb_ary_detransient) (VALUE);
+# endif
+# if defined(RUBY19_OR_LATER) || defined(RUBY_INIT_STACK)
+# ifdef __ia64
+static void * (*dll_rb_ia64_bsp) (void);
+static void (*dll_ruby_init_stack)(VALUE*, void*);
+# else
+static void (*dll_ruby_init_stack)(VALUE*);
+# endif
+# endif
+# endif
+# ifdef RUBY19_OR_LATER
+static VALUE (*dll_rb_int2big)(SIGNED_VALUE);
+# endif
+
+# ifdef RUBY19_OR_LATER
+static void (*dll_ruby_script) (const char*);
+static int (*dll_rb_enc_find_index) (const char*);
+static rb_encoding* (*dll_rb_enc_find) (const char*);
+static VALUE (*dll_rb_enc_str_new) (const char*, long, rb_encoding*);
+static VALUE (*dll_rb_sprintf) (const char*, ...);
+static VALUE (*dll_rb_require) (const char*);
+static void* (*ruby_options)(int, char**);
+# endif
+
+# if defined(USE_RGENGC) && USE_RGENGC
+# if defined(DYNAMIC_RUBY_VER) && DYNAMIC_RUBY_VER == 21
+static void (*dll_rb_gc_writebarrier_unprotect_promoted)(VALUE);
+# else
+static void (*dll_rb_gc_writebarrier_unprotect)(VALUE obj);
+# endif
+# endif
+
+# if defined(RUBY19_OR_LATER) && !defined(PROTO)
+# if defined(DYNAMIC_RUBY_VER) && DYNAMIC_RUBY_VER >= 22
+long rb_num2long_stub(VALUE x)
+# else
+SIGNED_VALUE rb_num2long_stub(VALUE x)
+# endif
+{
+ return dll_rb_num2long(x);
+}
+# if defined(DYNAMIC_RUBY_VER) && DYNAMIC_RUBY_VER >= 26
+VALUE rb_int2big_stub(intptr_t x)
+# else
+VALUE rb_int2big_stub(SIGNED_VALUE x)
+# endif
+{
+ return dll_rb_int2big(x);
+}
+# if defined(DYNAMIC_RUBY_VER) && DYNAMIC_RUBY_VER >= 19 \
+ && VIM_SIZEOF_INT < VIM_SIZEOF_LONG
+long rb_fix2int_stub(VALUE x)
+{
+ return dll_rb_fix2int(x);
+}
+long rb_num2int_stub(VALUE x)
+{
+ return dll_rb_num2int(x);
+}
+# endif
+# if defined(DYNAMIC_RUBY_VER) && DYNAMIC_RUBY_VER >= 20
+VALUE
+rb_float_new_in_heap(double d)
+{
+ return dll_rb_float_new(d);
+}
+# if defined(DYNAMIC_RUBY_VER) && DYNAMIC_RUBY_VER >= 22
+unsigned long rb_num2ulong(VALUE x)
+# else
+VALUE rb_num2ulong(VALUE x)
+# endif
+{
+ return (long)RSHIFT((SIGNED_VALUE)(x),1);
+}
+# endif
+# endif
+
+ /* Do not generate a prototype here, VALUE isn't always defined. */
+# if defined(USE_RGENGC) && USE_RGENGC && !defined(PROTO)
+# if defined(DYNAMIC_RUBY_VER) && DYNAMIC_RUBY_VER == 21
+void rb_gc_writebarrier_unprotect_promoted_stub(VALUE obj)
+{
+ dll_rb_gc_writebarrier_unprotect_promoted(obj);
+}
+# else
+void rb_gc_writebarrier_unprotect_stub(VALUE obj)
+{
+ dll_rb_gc_writebarrier_unprotect(obj);
+}
+# endif
+# endif
+
+# if defined(DYNAMIC_RUBY_VER) && DYNAMIC_RUBY_VER >= 26
+void rb_ary_detransient_stub(VALUE x)
+{
+ dll_rb_ary_detransient(x);
+}
+# endif
+
+static HINSTANCE hinstRuby = NULL; /* Instance of ruby.dll */
+
+/*
+ * Table of name to function pointer of ruby.
+ */
+static struct
+{
+ char *name;
+ RUBY_PROC *ptr;
+} ruby_funcname_table[] =
+{
+ {"rb_assoc_new", (RUBY_PROC*)&dll_rb_assoc_new},
+ {"rb_cFalseClass", (RUBY_PROC*)&dll_rb_cFalseClass},
+# if defined(USE_RUBY_INTEGER)
+ {"rb_cInteger", (RUBY_PROC*)&dll_rb_cInteger},
+# else
+ {"rb_cFixnum", (RUBY_PROC*)&dll_rb_cFixnum},
+# endif
+# if defined(DYNAMIC_RUBY_VER) && DYNAMIC_RUBY_VER >= 20
+ {"rb_cFloat", (RUBY_PROC*)&dll_rb_cFloat},
+# endif
+ {"rb_cNilClass", (RUBY_PROC*)&dll_rb_cNilClass},
+ {"rb_cObject", (RUBY_PROC*)&dll_rb_cObject},
+ {"rb_cString", (RUBY_PROC*)&dll_rb_cString},
+ {"rb_cSymbol", (RUBY_PROC*)&dll_rb_cSymbol},
+ {"rb_cTrueClass", (RUBY_PROC*)&dll_rb_cTrueClass},
+ {"rb_class_new_instance", (RUBY_PROC*)&dll_rb_class_new_instance},
+ {"rb_check_type", (RUBY_PROC*)&dll_rb_check_type},
+# ifdef USE_TYPEDDATA
+ {"rb_check_typeddata", (RUBY_PROC*)&dll_rb_check_typeddata},
+# endif
+ {"rb_class_path", (RUBY_PROC*)&dll_rb_class_path},
+# ifdef USE_TYPEDDATA
+# if defined(DYNAMIC_RUBY_VER) && DYNAMIC_RUBY_VER >= 23
+ {"rb_data_typed_object_wrap", (RUBY_PROC*)&dll_rb_data_typed_object_wrap},
+# else
+ {"rb_data_typed_object_alloc", (RUBY_PROC*)&dll_rb_data_typed_object_alloc},
+# endif
+# else
+ {"rb_data_object_alloc", (RUBY_PROC*)&dll_rb_data_object_alloc},
+# endif
+ {"rb_define_class_under", (RUBY_PROC*)&dll_rb_define_class_under},
+ {"rb_define_const", (RUBY_PROC*)&dll_rb_define_const},
+ {"rb_define_global_function", (RUBY_PROC*)&dll_rb_define_global_function},
+ {"rb_define_method", (RUBY_PROC*)&dll_rb_define_method},
+ {"rb_define_module", (RUBY_PROC*)&dll_rb_define_module},
+ {"rb_define_module_function", (RUBY_PROC*)&dll_rb_define_module_function},
+ {"rb_define_singleton_method", (RUBY_PROC*)&dll_rb_define_singleton_method},
+ {"rb_define_virtual_variable", (RUBY_PROC*)&dll_rb_define_virtual_variable},
+ {"rb_stdout", (RUBY_PROC*)&dll_rb_stdout},
+ {"rb_stderr", (RUBY_PROC*)&dll_rb_stderr},
+ {"rb_eArgError", (RUBY_PROC*)&dll_rb_eArgError},
+ {"rb_eIndexError", (RUBY_PROC*)&dll_rb_eIndexError},
+ {"rb_eRuntimeError", (RUBY_PROC*)&dll_rb_eRuntimeError},
+ {"rb_eStandardError", (RUBY_PROC*)&dll_rb_eStandardError},
+ {"rb_eval_string_protect", (RUBY_PROC*)&dll_rb_eval_string_protect},
+# ifdef RUBY21_OR_LATER
+ {"rb_funcallv", (RUBY_PROC*)&dll_rb_funcallv},
+# else
+ {"rb_funcall2", (RUBY_PROC*)&dll_rb_funcall2},
+# endif
+ {"rb_global_variable", (RUBY_PROC*)&dll_rb_global_variable},
+ {"rb_hash_aset", (RUBY_PROC*)&dll_rb_hash_aset},
+ {"rb_hash_new", (RUBY_PROC*)&dll_rb_hash_new},
+ {"rb_inspect", (RUBY_PROC*)&dll_rb_inspect},
+ {"rb_int2inum", (RUBY_PROC*)&dll_rb_int2inum},
+ {"rb_intern", (RUBY_PROC*)&dll_rb_intern},
+# if VIM_SIZEOF_INT < VIM_SIZEOF_LONG /* 64 bits only */
+ {"rb_fix2int", (RUBY_PROC*)&dll_rb_fix2int},
+ {"rb_num2int", (RUBY_PROC*)&dll_rb_num2int},
+ {"rb_num2uint", (RUBY_PROC*)&dll_rb_num2uint},
+# endif
+ {"rb_lastline_get", (RUBY_PROC*)&dll_rb_lastline_get},
+ {"rb_lastline_set", (RUBY_PROC*)&dll_rb_lastline_set},
+ {"rb_protect", (RUBY_PROC*)&dll_rb_protect},
+ {"rb_load", (RUBY_PROC*)&dll_rb_load},
+ {"rb_num2long", (RUBY_PROC*)&dll_rb_num2long},
+ {"rb_num2ulong", (RUBY_PROC*)&dll_rb_num2ulong},
+ {"rb_obj_alloc", (RUBY_PROC*)&dll_rb_obj_alloc},
+ {"rb_obj_as_string", (RUBY_PROC*)&dll_rb_obj_as_string},
+ {"rb_obj_id", (RUBY_PROC*)&dll_rb_obj_id},
+ {"rb_raise", (RUBY_PROC*)&dll_rb_raise},
+# if defined(DYNAMIC_RUBY_VER) && DYNAMIC_RUBY_VER >= 18
+ {"rb_string_value", (RUBY_PROC*)&dll_rb_string_value},
+# else
+ {"rb_str2cstr", (RUBY_PROC*)&dll_rb_str2cstr},
+# endif
+ {"rb_str_cat", (RUBY_PROC*)&dll_rb_str_cat},
+ {"rb_str_concat", (RUBY_PROC*)&dll_rb_str_concat},
+ {"rb_str_new", (RUBY_PROC*)&dll_rb_str_new},
+# ifdef need_rb_str_new_cstr
+ {"rb_str_new_cstr", (RUBY_PROC*)&dll_rb_str_new_cstr},
+# else
+ {"rb_str_new2", (RUBY_PROC*)&dll_rb_str_new2},
+# endif
+# ifdef RUBY19_OR_LATER
+ {"rb_errinfo", (RUBY_PROC*)&dll_rb_errinfo},
+# else
+ {"ruby_errinfo", (RUBY_PROC*)&dll_ruby_errinfo},
+# endif
+ {"ruby_init", (RUBY_PROC*)&dll_ruby_init},
+ {"ruby_init_loadpath", (RUBY_PROC*)&dll_ruby_init_loadpath},
+# ifdef WIN3264
+# ifdef RUBY19_OR_LATER
+ {"ruby_sysinit", (RUBY_PROC*)&dll_ruby_sysinit},
+# else
+ {"NtInitialize", (RUBY_PROC*)&dll_NtInitialize},
+# endif
+# if defined(DYNAMIC_RUBY_VER) && DYNAMIC_RUBY_VER >= 18
+ {"rb_w32_snprintf", (RUBY_PROC*)&dll_rb_w32_snprintf},
+# endif
+# endif
+# if defined(DYNAMIC_RUBY_VER) && DYNAMIC_RUBY_VER >= 18
+ {"rb_string_value_ptr", (RUBY_PROC*)&dll_rb_string_value_ptr},
+# if DYNAMIC_RUBY_VER <= 19
+ {"rb_float_new", (RUBY_PROC*)&dll_rb_float_new},
+# else
+ {"rb_float_new_in_heap", (RUBY_PROC*)&dll_rb_float_new},
+# endif
+ {"rb_ary_new", (RUBY_PROC*)&dll_rb_ary_new},
+# ifdef RB_ARY_NEW4_MACRO
+ {"rb_ary_new_from_values", (RUBY_PROC*)&dll_rb_ary_new4},
+# else
+ {"rb_ary_new4", (RUBY_PROC*)&dll_rb_ary_new4},
+# endif
+ {"rb_ary_push", (RUBY_PROC*)&dll_rb_ary_push},
+# if DYNAMIC_RUBY_VER >= 26
+ {"rb_ary_detransient", (RUBY_PROC*)&dll_rb_ary_detransient},
+# endif
+# endif
+# ifdef RUBY19_OR_LATER
+ {"rb_int2big", (RUBY_PROC*)&dll_rb_int2big},
+ {"ruby_script", (RUBY_PROC*)&dll_ruby_script},
+ {"rb_enc_find_index", (RUBY_PROC*)&dll_rb_enc_find_index},
+ {"rb_enc_find", (RUBY_PROC*)&dll_rb_enc_find},
+ {"rb_enc_str_new", (RUBY_PROC*)&dll_rb_enc_str_new},
+ {"rb_sprintf", (RUBY_PROC*)&dll_rb_sprintf},
+ {"rb_require", (RUBY_PROC*)&dll_rb_require},
+ {"ruby_options", (RUBY_PROC*)&dll_ruby_options},
+# endif
+# if defined(RUBY19_OR_LATER) || defined(RUBY_INIT_STACK)
+# ifdef __ia64
+ {"rb_ia64_bsp", (RUBY_PROC*)&dll_rb_ia64_bsp},
+# endif
+ {"ruby_init_stack", (RUBY_PROC*)&dll_ruby_init_stack},
+# endif
+# if defined(USE_RGENGC) && USE_RGENGC
+# if defined(DYNAMIC_RUBY_VER) && DYNAMIC_RUBY_VER == 21
+ {"rb_gc_writebarrier_unprotect_promoted", (RUBY_PROC*)&dll_rb_gc_writebarrier_unprotect_promoted},
+# else
+ {"rb_gc_writebarrier_unprotect", (RUBY_PROC*)&dll_rb_gc_writebarrier_unprotect},
+# endif
+# endif
+ {"", NULL},
+};
+
+/*
+ * Free ruby.dll
+ */
+ static void
+end_dynamic_ruby(void)
+{
+ if (hinstRuby)
+ {
+ close_dll(hinstRuby);
+ hinstRuby = NULL;
+ }
+}
+
+/*
+ * Load library and get all pointers.
+ * Parameter 'libname' provides name of DLL.
+ * Return OK or FAIL.
+ */
+ static int
+ruby_runtime_link_init(char *libname, int verbose)
+{
+ int i;
+
+ if (hinstRuby)
+ return OK;
+ hinstRuby = load_dll(libname);
+ if (!hinstRuby)
+ {
+ if (verbose)
+ semsg(_(e_loadlib), libname);
+ return FAIL;
+ }
+
+ for (i = 0; ruby_funcname_table[i].ptr; ++i)
+ {
+ if (!(*ruby_funcname_table[i].ptr = symbol_from_dll(hinstRuby,
+ ruby_funcname_table[i].name)))
+ {
+ close_dll(hinstRuby);
+ hinstRuby = NULL;
+ if (verbose)
+ semsg(_(e_loadfunc), ruby_funcname_table[i].name);
+ return FAIL;
+ }
+ }
+ return OK;
+}
+
+/*
+ * If ruby is enabled (there is installed ruby on Windows system) return TRUE,
+ * else FALSE.
+ */
+ int
+ruby_enabled(int verbose)
+{
+ return ruby_runtime_link_init((char *)p_rubydll, verbose) == OK;
+}
+#endif /* defined(DYNAMIC_RUBY) || defined(PROTO) */
+
+ void
+ruby_end(void)
+{
+#ifdef DYNAMIC_RUBY
+ end_dynamic_ruby();
+#endif
+}
+
+void ex_ruby(exarg_T *eap)
+{
+ int state;
+ char *script = NULL;
+
+ script = (char *)script_get(eap, eap->arg);
+ if (!eap->skip && ensure_ruby_initialized())
+ {
+ if (script == NULL)
+ rb_eval_string_protect((char *)eap->arg, &state);
+ else
+ rb_eval_string_protect(script, &state);
+ if (state)
+ error_print(state);
+ }
+ vim_free(script);
+}
+
+/*
+ * In Ruby 1.9 or later, ruby String object has encoding.
+ * conversion buffer string of vim to ruby String object using
+ * VIM encoding option.
+ */
+ static VALUE
+vim_str2rb_enc_str(const char *s)
+{
+#ifdef RUBY19_OR_LATER
+ int isnum;
+ long lval;
+ char_u *sval;
+ rb_encoding *enc;
+
+ isnum = get_option_value((char_u *)"enc", &lval, &sval, 0);
+ if (isnum == 0)
+ {
+ enc = rb_enc_find((char *)sval);
+ vim_free(sval);
+ if (enc)
+ {
+ return rb_enc_str_new(s, (long)strlen(s), enc);
+ }
+ }
+#endif
+ return rb_str_new2(s);
+}
+
+ static VALUE
+eval_enc_string_protect(const char *str, int *state)
+{
+#ifdef RUBY19_OR_LATER
+ int isnum;
+ long lval;
+ char_u *sval;
+ rb_encoding *enc;
+ VALUE v;
+
+ isnum = get_option_value((char_u *)"enc", &lval, &sval, 0);
+ if (isnum == 0)
+ {
+ enc = rb_enc_find((char *)sval);
+ vim_free(sval);
+ if (enc)
+ {
+ v = rb_sprintf("#-*- coding:%s -*-\n%s", rb_enc_name(enc), str);
+ return rb_eval_string_protect(StringValuePtr(v), state);
+ }
+ }
+#endif
+ return rb_eval_string_protect(str, state);
+}
+
+void ex_rubydo(exarg_T *eap)
+{
+ int state;
+ linenr_T i;
+ buf_T *was_curbuf = curbuf;
+
+ if (ensure_ruby_initialized())
+ {
+ if (u_save(eap->line1 - 1, eap->line2 + 1) != OK)
+ return;
+ for (i = eap->line1; i <= eap->line2; i++)
+ {
+ VALUE line;
+
+ if (i > curbuf->b_ml.ml_line_count)
+ break;
+ line = vim_str2rb_enc_str((char *)ml_get(i));
+ rb_lastline_set(line);
+ eval_enc_string_protect((char *) eap->arg, &state);
+ if (state)
+ {
+ error_print(state);
+ break;
+ }
+ if (was_curbuf != curbuf)
+ break;
+ line = rb_lastline_get();
+ if (!NIL_P(line))
+ {
+ if (TYPE(line) != T_STRING)
+ {
+ emsg(_("E265: $_ must be an instance of String"));
+ return;
+ }
+ ml_replace(i, (char_u *) StringValuePtr(line), 1);
+ changed();
+#ifdef SYNTAX_HL
+ syn_changed(i); /* recompute syntax hl. for this line */
+#endif
+ }
+ }
+ check_cursor();
+ update_curbuf(NOT_VALID);
+ }
+}
+
+static VALUE rb_load_wrap(VALUE file_to_load)
+{
+ rb_load(file_to_load, 0);
+ return Qnil;
+}
+
+void ex_rubyfile(exarg_T *eap)
+{
+ int state;
+
+ if (ensure_ruby_initialized())
+ {
+ VALUE file_to_load = rb_str_new2((const char *)eap->arg);
+ rb_protect(rb_load_wrap, file_to_load, &state);
+ if (state)
+ error_print(state);
+ }
+}
+
+void ruby_buffer_free(buf_T *buf)
+{
+ if (buf->b_ruby_ref)
+ {
+ rb_hash_aset(objtbl, rb_obj_id((VALUE) buf->b_ruby_ref), Qnil);
+ RDATA(buf->b_ruby_ref)->data = NULL;
+ }
+}
+
+void ruby_window_free(win_T *win)
+{
+ if (win->w_ruby_ref)
+ {
+ rb_hash_aset(objtbl, rb_obj_id((VALUE) win->w_ruby_ref), Qnil);
+ RDATA(win->w_ruby_ref)->data = NULL;
+ }
+}
+
+static int ensure_ruby_initialized(void)
+{
+ if (!ruby_initialized)
+ {
+#ifdef DYNAMIC_RUBY
+ if (ruby_enabled(TRUE))
+ {
+#endif
+#ifdef _WIN32
+ /* suggested by Ariya Mizutani */
+ int argc = 1;
+ char *argv[] = {"gvim.exe"};
+ char **argvp = argv;
+# ifdef RUBY19_OR_LATER
+ ruby_sysinit(&argc, &argvp);
+# else
+ NtInitialize(&argc, &argvp);
+# endif
+#endif
+ {
+#if defined(RUBY19_OR_LATER) || defined(RUBY_INIT_STACK)
+ ruby_init_stack(ruby_stack_start);
+#endif
+ ruby_init();
+ }
+#ifdef RUBY19_OR_LATER
+ {
+ int dummy_argc = 2;
+ char *dummy_argv[] = {"vim-ruby", "-e_=0"};
+ ruby_options(dummy_argc, dummy_argv);
+ }
+ ruby_script("vim-ruby");
+#else
+ ruby_init_loadpath();
+#endif
+ ruby_io_init();
+ ruby_vim_init();
+ ruby_initialized = 1;
+#ifdef DYNAMIC_RUBY
+ }
+ else
+ {
+ emsg(_("E266: Sorry, this command is disabled, the Ruby library could not be loaded."));
+ return 0;
+ }
+#endif
+ }
+ return ruby_initialized;
+}
+
+static void error_print(int state)
+{
+#if !defined(DYNAMIC_RUBY) && !defined(RUBY19_OR_LATER)
+ RUBYEXTERN VALUE ruby_errinfo;
+#endif
+ VALUE error;
+ VALUE eclass;
+ VALUE einfo;
+ VALUE bt;
+ int attr;
+ char buff[BUFSIZ];
+ long i;
+
+#define TAG_RETURN 0x1
+#define TAG_BREAK 0x2
+#define TAG_NEXT 0x3
+#define TAG_RETRY 0x4
+#define TAG_REDO 0x5
+#define TAG_RAISE 0x6
+#define TAG_THROW 0x7
+#define TAG_FATAL 0x8
+#define TAG_MASK 0xf
+
+ switch (state)
+ {
+ case TAG_RETURN:
+ emsg(_("E267: unexpected return"));
+ break;
+ case TAG_NEXT:
+ emsg(_("E268: unexpected next"));
+ break;
+ case TAG_BREAK:
+ emsg(_("E269: unexpected break"));
+ break;
+ case TAG_REDO:
+ emsg(_("E270: unexpected redo"));
+ break;
+ case TAG_RETRY:
+ emsg(_("E271: retry outside of rescue clause"));
+ break;
+ case TAG_RAISE:
+ case TAG_FATAL:
+#ifdef RUBY19_OR_LATER
+ error = rb_errinfo();
+#else
+ error = ruby_errinfo;
+#endif
+ eclass = CLASS_OF(error);
+ einfo = rb_obj_as_string(error);
+ if (eclass == rb_eRuntimeError && RSTRING_LEN(einfo) == 0)
+ {
+ emsg(_("E272: unhandled exception"));
+ }
+ else
+ {
+ VALUE epath;
+ char *p;
+
+ epath = rb_class_path(eclass);
+ vim_snprintf(buff, BUFSIZ, "%s: %s",
+ RSTRING_PTR(epath), RSTRING_PTR(einfo));
+ p = strchr(buff, '\n');
+ if (p) *p = '\0';
+ emsg(buff);
+ }
+
+ attr = syn_name2attr((char_u *)"Error");
+# ifdef RUBY21_OR_LATER
+ bt = rb_funcallv(error, rb_intern("backtrace"), 0, 0);
+ for (i = 0; i < RARRAY_LEN(bt); i++)
+ msg_attr(RSTRING_PTR(RARRAY_AREF(bt, i)), attr);
+# else
+ bt = rb_funcall2(error, rb_intern("backtrace"), 0, 0);
+ for (i = 0; i < RARRAY_LEN(bt); i++)
+ msg_attr(RSTRING_PTR(RARRAY_PTR(bt)[i]), attr);
+# endif
+ break;
+ default:
+ vim_snprintf(buff, BUFSIZ, _("E273: unknown longjmp status %d"), state);
+ emsg(buff);
+ break;
+ }
+}
+
+static VALUE vim_message(VALUE self UNUSED, VALUE str)
+{
+ char *buff, *p;
+
+ str = rb_obj_as_string(str);
+ if (RSTRING_LEN(str) > 0)
+ {
+ /* Only do this when the string isn't empty, alloc(0) causes trouble. */
+ buff = ALLOCA_N(char, RSTRING_LEN(str) + 1);
+ strcpy(buff, RSTRING_PTR(str));
+ p = strchr(buff, '\n');
+ if (p) *p = '\0';
+ msg(buff);
+ }
+ else
+ {
+ msg("");
+ }
+ return Qnil;
+}
+
+static VALUE vim_set_option(VALUE self UNUSED, VALUE str)
+{
+ do_set((char_u *)StringValuePtr(str), 0);
+ update_screen(NOT_VALID);
+ return Qnil;
+}
+
+static VALUE vim_command(VALUE self UNUSED, VALUE str)
+{
+ do_cmdline_cmd((char_u *)StringValuePtr(str));
+ return Qnil;
+}
+
+#ifdef FEAT_EVAL
+static VALUE vim_to_ruby(typval_T *tv)
+{
+ VALUE result = Qnil;
+
+ if (tv->v_type == VAR_STRING)
+ {
+ result = rb_str_new2(tv->vval.v_string == NULL
+ ? "" : (char *)(tv->vval.v_string));
+ }
+ else if (tv->v_type == VAR_NUMBER)
+ {
+ result = INT2NUM(tv->vval.v_number);
+ }
+# ifdef FEAT_FLOAT
+ else if (tv->v_type == VAR_FLOAT)
+ {
+ result = rb_float_new(tv->vval.v_float);
+ }
+# endif
+ else if (tv->v_type == VAR_LIST)
+ {
+ list_T *list = tv->vval.v_list;
+ listitem_T *curr;
+
+ result = rb_ary_new();
+
+ if (list != NULL)
+ {
+ for (curr = list->lv_first; curr != NULL; curr = curr->li_next)
+ {
+ rb_ary_push(result, vim_to_ruby(&curr->li_tv));
+ }
+ }
+ }
+ else if (tv->v_type == VAR_DICT)
+ {
+ result = rb_hash_new();
+
+ if (tv->vval.v_dict != NULL)
+ {
+ hashtab_T *ht = &tv->vval.v_dict->dv_hashtab;
+ long_u todo = ht->ht_used;
+ hashitem_T *hi;
+ dictitem_T *di;
+
+ for (hi = ht->ht_array; todo > 0; ++hi)
+ {
+ if (!HASHITEM_EMPTY(hi))
+ {
+ --todo;
+
+ di = dict_lookup(hi);
+ rb_hash_aset(result, rb_str_new2((char *)hi->hi_key),
+ vim_to_ruby(&di->di_tv));
+ }
+ }
+ }
+ }
+ else if (tv->v_type == VAR_SPECIAL)
+ {
+ if (tv->vval.v_number == VVAL_TRUE)
+ result = Qtrue;
+ else if (tv->vval.v_number == VVAL_FALSE)
+ result = Qfalse;
+ }
+ else if (tv->v_type == VAR_BLOB)
+ {
+ result = rb_str_new(tv->vval.v_blob->bv_ga.ga_data,
+ tv->vval.v_blob->bv_ga.ga_len);
+ }
+ /* else return Qnil; */
+
+ return result;
+}
+#endif
+
+static VALUE vim_evaluate(VALUE self UNUSED, VALUE str)
+{
+#ifdef FEAT_EVAL
+ typval_T *tv;
+ VALUE result;
+
+ tv = eval_expr((char_u *)StringValuePtr(str), NULL);
+ if (tv == NULL)
+ {
+ return Qnil;
+ }
+ result = vim_to_ruby(tv);
+
+ free_tv(tv);
+
+ return result;
+#else
+ return Qnil;
+#endif
+}
+
+#ifdef USE_TYPEDDATA
+static size_t buffer_dsize(const void *buf);
+
+static const rb_data_type_t buffer_type = {
+ "vim_buffer",
+ {0, 0, buffer_dsize, {0, 0}},
+ 0, 0,
+# ifdef RUBY_TYPED_FREE_IMMEDIATELY
+ 0,
+# endif
+};
+
+static size_t buffer_dsize(const void *buf UNUSED)
+{
+ return sizeof(buf_T);
+}
+#endif
+
+static VALUE buffer_new(buf_T *buf)
+{
+ if (buf->b_ruby_ref)
+ {
+ return (VALUE) buf->b_ruby_ref;
+ }
+ else
+ {
+#ifdef USE_TYPEDDATA
+ VALUE obj = TypedData_Wrap_Struct(cBuffer, &buffer_type, buf);
+#else
+ VALUE obj = Data_Wrap_Struct(cBuffer, 0, 0, buf);
+#endif
+ buf->b_ruby_ref = (void *) obj;
+ rb_hash_aset(objtbl, rb_obj_id(obj), obj);
+ return obj;
+ }
+}
+
+static buf_T *get_buf(VALUE obj)
+{
+ buf_T *buf;
+
+#ifdef USE_TYPEDDATA
+ TypedData_Get_Struct(obj, buf_T, &buffer_type, buf);
+#else
+ Data_Get_Struct(obj, buf_T, buf);
+#endif
+ if (buf == NULL)
+ rb_raise(eDeletedBufferError, "attempt to refer to deleted buffer");
+ return buf;
+}
+
+static VALUE vim_blob(VALUE self UNUSED, VALUE str)
+{
+ VALUE result = rb_str_new("0z", 2);
+ char buf[4];
+ int i;
+ for (i = 0; i < RSTRING_LEN(str); i++)
+ {
+ sprintf(buf, "%02X", RSTRING_PTR(str)[i]);
+ rb_str_concat(result, rb_str_new2(buf));
+ }
+ return result;
+}
+
+static VALUE buffer_s_current(void)
+{
+ return buffer_new(curbuf);
+}
+
+static VALUE buffer_s_count(void)
+{
+ buf_T *b;
+ int n = 0;
+
+ FOR_ALL_BUFFERS(b)
+ {
+ /* Deleted buffers should not be counted
+ * SegPhault - 01/07/05 */
+ if (b->b_p_bl)
+ n++;
+ }
+
+ return INT2NUM(n);
+}
+
+static VALUE buffer_s_aref(VALUE self UNUSED, VALUE num)
+{
+ buf_T *b;
+ int n = NUM2INT(num);
+
+ FOR_ALL_BUFFERS(b)
+ {
+ /* Deleted buffers should not be counted
+ * SegPhault - 01/07/05 */
+ if (!b->b_p_bl)
+ continue;
+
+ if (n == 0)
+ return buffer_new(b);
+
+ n--;
+ }
+ return Qnil;
+}
+
+static VALUE buffer_name(VALUE self)
+{
+ buf_T *buf = get_buf(self);
+
+ return buf->b_ffname ? rb_str_new2((char *)buf->b_ffname) : Qnil;
+}
+
+static VALUE buffer_number(VALUE self)
+{
+ buf_T *buf = get_buf(self);
+
+ return INT2NUM(buf->b_fnum);
+}
+
+static VALUE buffer_count(VALUE self)
+{
+ buf_T *buf = get_buf(self);
+
+ return INT2NUM(buf->b_ml.ml_line_count);
+}
+
+static VALUE get_buffer_line(buf_T *buf, linenr_T n)
+{
+ if (n <= 0 || n > buf->b_ml.ml_line_count)
+ rb_raise(rb_eIndexError, "line number %ld out of range", (long)n);
+ return vim_str2rb_enc_str((char *)ml_get_buf(buf, n, FALSE));
+}
+
+static VALUE buffer_aref(VALUE self, VALUE num)
+{
+ buf_T *buf = get_buf(self);
+
+ if (buf != NULL)
+ return get_buffer_line(buf, (linenr_T)NUM2LONG(num));
+ return Qnil; /* For stop warning */
+}
+
+static VALUE set_buffer_line(buf_T *buf, linenr_T n, VALUE str)
+{
+ char *line = StringValuePtr(str);
+ aco_save_T aco;
+
+ if (n > 0 && n <= buf->b_ml.ml_line_count && line != NULL)
+ {
+ /* set curwin/curbuf for "buf" and save some things */
+ aucmd_prepbuf(&aco, buf);
+
+ if (u_savesub(n) == OK)
+ {
+ ml_replace(n, (char_u *)line, TRUE);
+ changed();
+#ifdef SYNTAX_HL
+ syn_changed(n); /* recompute syntax hl. for this line */
+#endif
+ }
+
+ /* restore curwin/curbuf and a few other things */
+ aucmd_restbuf(&aco);
+ /* Careful: autocommands may have made "buf" invalid! */
+
+ update_curbuf(NOT_VALID);
+ }
+ else
+ {
+ rb_raise(rb_eIndexError, "line number %ld out of range", (long)n);
+ }
+ return str;
+}
+
+static VALUE buffer_aset(VALUE self, VALUE num, VALUE str)
+{
+ buf_T *buf = get_buf(self);
+
+ if (buf != NULL)
+ return set_buffer_line(buf, (linenr_T)NUM2LONG(num), str);
+ return str;
+}
+
+static VALUE buffer_delete(VALUE self, VALUE num)
+{
+ buf_T *buf = get_buf(self);
+ long n = NUM2LONG(num);
+ aco_save_T aco;
+
+ if (n > 0 && n <= buf->b_ml.ml_line_count)
+ {
+ /* set curwin/curbuf for "buf" and save some things */
+ aucmd_prepbuf(&aco, buf);
+
+ if (u_savedel(n, 1) == OK)
+ {
+ ml_delete(n, 0);
+
+ /* Changes to non-active buffers should properly refresh
+ * SegPhault - 01/09/05 */
+ deleted_lines_mark(n, 1L);
+
+ changed();
+ }
+
+ /* restore curwin/curbuf and a few other things */
+ aucmd_restbuf(&aco);
+ /* Careful: autocommands may have made "buf" invalid! */
+
+ update_curbuf(NOT_VALID);
+ }
+ else
+ {
+ rb_raise(rb_eIndexError, "line number %ld out of range", n);
+ }
+ return Qnil;
+}
+
+static VALUE buffer_append(VALUE self, VALUE num, VALUE str)
+{
+ buf_T *buf = get_buf(self);
+ char *line = StringValuePtr(str);
+ long n = NUM2LONG(num);
+ aco_save_T aco;
+
+ if (line == NULL)
+ {
+ rb_raise(rb_eIndexError, "NULL line");
+ }
+ else if (n >= 0 && n <= buf->b_ml.ml_line_count)
+ {
+ /* set curwin/curbuf for "buf" and save some things */
+ aucmd_prepbuf(&aco, buf);
+
+ if (u_inssub(n + 1) == OK)
+ {
+ ml_append(n, (char_u *) line, (colnr_T) 0, FALSE);
+
+ /* Changes to non-active buffers should properly refresh screen
+ * SegPhault - 12/20/04 */
+ appended_lines_mark(n, 1L);
+
+ changed();
+ }
+
+ /* restore curwin/curbuf and a few other things */
+ aucmd_restbuf(&aco);
+ /* Careful: autocommands may have made "buf" invalid! */
+
+ update_curbuf(NOT_VALID);
+ }
+ else
+ {
+ rb_raise(rb_eIndexError, "line number %ld out of range", n);
+ }
+ return str;
+}
+
+#ifdef USE_TYPEDDATA
+static size_t window_dsize(const void *buf);
+
+static const rb_data_type_t window_type = {
+ "vim_window",
+ {0, 0, window_dsize, {0, 0}},
+ 0, 0,
+# ifdef RUBY_TYPED_FREE_IMMEDIATELY
+ 0,
+# endif
+};
+
+static size_t window_dsize(const void *win UNUSED)
+{
+ return sizeof(win_T);
+}
+#endif
+
+static VALUE window_new(win_T *win)
+{
+ if (win->w_ruby_ref)
+ {
+ return (VALUE) win->w_ruby_ref;
+ }
+ else
+ {
+#ifdef USE_TYPEDDATA
+ VALUE obj = TypedData_Wrap_Struct(cVimWindow, &window_type, win);
+#else
+ VALUE obj = Data_Wrap_Struct(cVimWindow, 0, 0, win);
+#endif
+ win->w_ruby_ref = (void *) obj;
+ rb_hash_aset(objtbl, rb_obj_id(obj), obj);
+ return obj;
+ }
+}
+
+static win_T *get_win(VALUE obj)
+{
+ win_T *win;
+
+#ifdef USE_TYPEDDATA
+ TypedData_Get_Struct(obj, win_T, &window_type, win);
+#else
+ Data_Get_Struct(obj, win_T, win);
+#endif
+ if (win == NULL)
+ rb_raise(eDeletedWindowError, "attempt to refer to deleted window");
+ return win;
+}
+
+static VALUE window_s_current(void)
+{
+ return window_new(curwin);
+}
+
+/*
+ * Added line manipulation functions
+ * SegPhault - 03/07/05
+ */
+static VALUE line_s_current(void)
+{
+ return get_buffer_line(curbuf, curwin->w_cursor.lnum);
+}
+
+static VALUE set_current_line(VALUE self UNUSED, VALUE str)
+{
+ return set_buffer_line(curbuf, curwin->w_cursor.lnum, str);
+}
+
+static VALUE current_line_number(void)
+{
+ return INT2FIX((int)curwin->w_cursor.lnum);
+}
+
+
+
+static VALUE window_s_count(void)
+{
+ win_T *w;
+ int n = 0;
+
+ FOR_ALL_WINDOWS(w)
+ n++;
+ return INT2NUM(n);
+}
+
+static VALUE window_s_aref(VALUE self UNUSED, VALUE num)
+{
+ win_T *w;
+ int n = NUM2INT(num);
+
+ for (w = firstwin; w != NULL; w = w->w_next, --n)
+ if (n == 0)
+ return window_new(w);
+ return Qnil;
+}
+
+static VALUE window_buffer(VALUE self)
+{
+ win_T *win = get_win(self);
+
+ return buffer_new(win->w_buffer);
+}
+
+static VALUE window_height(VALUE self)
+{
+ win_T *win = get_win(self);
+
+ return INT2NUM(win->w_height);
+}
+
+static VALUE window_set_height(VALUE self, VALUE height)
+{
+ win_T *win = get_win(self);
+ win_T *savewin = curwin;
+
+ curwin = win;
+ win_setheight(NUM2INT(height));
+ curwin = savewin;
+ return height;
+}
+
+static VALUE window_width(VALUE self UNUSED)
+{
+ return INT2NUM(get_win(self)->w_width);
+}
+
+static VALUE window_set_width(VALUE self UNUSED, VALUE width)
+{
+ win_T *win = get_win(self);
+ win_T *savewin = curwin;
+
+ curwin = win;
+ win_setwidth(NUM2INT(width));
+ curwin = savewin;
+ return width;
+}
+
+static VALUE window_cursor(VALUE self)
+{
+ win_T *win = get_win(self);
+
+ return rb_assoc_new(INT2NUM(win->w_cursor.lnum), INT2NUM(win->w_cursor.col));
+}
+
+static VALUE window_set_cursor(VALUE self, VALUE pos)
+{
+ VALUE lnum, col;
+ win_T *win = get_win(self);
+
+ Check_Type(pos, T_ARRAY);
+ if (RARRAY_LEN(pos) != 2)
+ rb_raise(rb_eArgError, "array length must be 2");
+ lnum = RARRAY_PTR(pos)[0];
+ col = RARRAY_PTR(pos)[1];
+ win->w_cursor.lnum = NUM2LONG(lnum);
+ win->w_cursor.col = NUM2UINT(col);
+ win->w_set_curswant = TRUE;
+ check_cursor(); /* put cursor on an existing line */
+ update_screen(NOT_VALID);
+ return Qnil;
+}
+
+static VALUE f_nop(VALUE self UNUSED)
+{
+ return Qnil;
+}
+
+static VALUE f_p(int argc, VALUE *argv, VALUE self UNUSED)
+{
+ int i;
+ VALUE str = rb_str_new("", 0);
+ VALUE ret = Qnil;
+
+ for (i = 0; i < argc; i++)
+ {
+ if (i > 0) rb_str_cat(str, ", ", 2);
+ rb_str_concat(str, rb_inspect(argv[i]));
+ }
+ msg(RSTRING_PTR(str));
+
+ if (argc == 1)
+ ret = argv[0];
+ else if (argc > 1)
+ ret = rb_ary_new4(argc, argv);
+ return ret;
+}
+
+static void ruby_io_init(void)
+{
+#ifndef DYNAMIC_RUBY
+ RUBYEXTERN VALUE rb_stdout;
+ RUBYEXTERN VALUE rb_stderr;
+#endif
+
+ rb_stdout = rb_obj_alloc(rb_cObject);
+ rb_stderr = rb_obj_alloc(rb_cObject);
+ rb_define_singleton_method(rb_stdout, "write", vim_message, 1);
+ rb_define_singleton_method(rb_stdout, "flush", f_nop, 0);
+ rb_define_singleton_method(rb_stderr, "write", vim_message, 1);
+ rb_define_singleton_method(rb_stderr, "flush", f_nop, 0);
+ rb_define_global_function("p", f_p, -1);
+}
+
+static void ruby_vim_init(void)
+{
+ objtbl = rb_hash_new();
+ rb_global_variable(&objtbl);
+
+ /* The Vim module used to be called "VIM", but "Vim" is better. Make an
+ * alias "VIM" for backwards compatibility. */
+ mVIM = rb_define_module("Vim");
+ rb_define_const(rb_cObject, "VIM", mVIM);
+ rb_define_const(mVIM, "VERSION_MAJOR", INT2NUM(VIM_VERSION_MAJOR));
+ rb_define_const(mVIM, "VERSION_MINOR", INT2NUM(VIM_VERSION_MINOR));
+ rb_define_const(mVIM, "VERSION_BUILD", INT2NUM(VIM_VERSION_BUILD));
+ rb_define_const(mVIM, "VERSION_PATCHLEVEL", INT2NUM(VIM_VERSION_PATCHLEVEL));
+ rb_define_const(mVIM, "VERSION_SHORT", rb_str_new2(VIM_VERSION_SHORT));
+ rb_define_const(mVIM, "VERSION_MEDIUM", rb_str_new2(VIM_VERSION_MEDIUM));
+ rb_define_const(mVIM, "VERSION_LONG", rb_str_new2(VIM_VERSION_LONG));
+ rb_define_const(mVIM, "VERSION_LONG_DATE", rb_str_new2(VIM_VERSION_LONG_DATE));
+ rb_define_module_function(mVIM, "message", vim_message, 1);
+ rb_define_module_function(mVIM, "set_option", vim_set_option, 1);
+ rb_define_module_function(mVIM, "command", vim_command, 1);
+ rb_define_module_function(mVIM, "evaluate", vim_evaluate, 1);
+ rb_define_module_function(mVIM, "blob", vim_blob, 1);
+
+ eDeletedBufferError = rb_define_class_under(mVIM, "DeletedBufferError",
+ rb_eStandardError);
+ eDeletedWindowError = rb_define_class_under(mVIM, "DeletedWindowError",
+ rb_eStandardError);
+
+ cBuffer = rb_define_class_under(mVIM, "Buffer", rb_cObject);
+ rb_define_singleton_method(cBuffer, "current", buffer_s_current, 0);
+ rb_define_singleton_method(cBuffer, "count", buffer_s_count, 0);
+ rb_define_singleton_method(cBuffer, "[]", buffer_s_aref, 1);
+ rb_define_method(cBuffer, "name", buffer_name, 0);
+ rb_define_method(cBuffer, "number", buffer_number, 0);
+ rb_define_method(cBuffer, "count", buffer_count, 0);
+ rb_define_method(cBuffer, "length", buffer_count, 0);
+ rb_define_method(cBuffer, "[]", buffer_aref, 1);
+ rb_define_method(cBuffer, "[]=", buffer_aset, 2);
+ rb_define_method(cBuffer, "delete", buffer_delete, 1);
+ rb_define_method(cBuffer, "append", buffer_append, 2);
+
+ /* Added line manipulation functions
+ * SegPhault - 03/07/05 */
+ rb_define_method(cBuffer, "line_number", current_line_number, 0);
+ rb_define_method(cBuffer, "line", line_s_current, 0);
+ rb_define_method(cBuffer, "line=", set_current_line, 1);
+
+
+ cVimWindow = rb_define_class_under(mVIM, "Window", rb_cObject);
+ rb_define_singleton_method(cVimWindow, "current", window_s_current, 0);
+ rb_define_singleton_method(cVimWindow, "count", window_s_count, 0);
+ rb_define_singleton_method(cVimWindow, "[]", window_s_aref, 1);
+ rb_define_method(cVimWindow, "buffer", window_buffer, 0);
+ rb_define_method(cVimWindow, "height", window_height, 0);
+ rb_define_method(cVimWindow, "height=", window_set_height, 1);
+ rb_define_method(cVimWindow, "width", window_width, 0);
+ rb_define_method(cVimWindow, "width=", window_set_width, 1);
+ rb_define_method(cVimWindow, "cursor", window_cursor, 0);
+ rb_define_method(cVimWindow, "cursor=", window_set_cursor, 1);
+
+ rb_define_virtual_variable("$curbuf", buffer_s_current, 0);
+ rb_define_virtual_variable("$curwin", window_s_current, 0);
+}
+
+void vim_ruby_init(void *stack_start)
+{
+ /* should get machine stack start address early in main function */
+ ruby_stack_start = stack_start;
+}
diff --git a/src/if_tcl.c b/src/if_tcl.c
new file mode 100644
index 0000000..eb6684c
--- /dev/null
+++ b/src/if_tcl.c
@@ -0,0 +1,2109 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * Tcl extensions by Ingo Wilken <Ingo.Wilken@informatik.uni-oldenburg.de>
+ * Last modification: Wed May 10 21:28:44 CEST 2000
+ * Requires Tcl 8.0 or higher.
+ *
+ * Variables:
+ * ::vim::current(buffer) # Name of buffer command for current buffer.
+ * ::vim::current(window) # Name of window command for current window.
+ * ::vim::range(start) # Start of current range (line number).
+ * ::vim::range(end) # End of current range (line number).
+ * ::vim::lbase # Start of line/column numbers (1 or 0).
+ *
+ * Commands:
+ * ::vim::command {cmd} # Execute ex command {cmd}.
+ * ::vim::option {opt} [val] # Get/Set option {opt}.
+ * ::vim::expr {expr} # Evaluate {expr} using vim's evaluator.
+ * ::vim::beep # Guess.
+ *
+ * set buf [::vim::buffer {n}] # Create Tcl command for buffer N.
+ * set bl [::vim::buffer list] # Get list of Tcl commands of all buffers.
+ * ::vim::buffer exists {n} # True if buffer {n} exists.
+ *
+ * set wl [::vim::window list] # Get list of Tcl commands of all windows.
+ *
+ * set n [$win height] # Report window height.
+ * $win height {n} # Set window height to {n}.
+ * array set pos [$win cursor] # Get cursor position.
+ * $win cursor {row} {col} # Set cursor position.
+ * $win cursor pos # Set cursor position from array var "pos"
+ * $win delcmd {cmd} # Register callback command for closed window.
+ * $win option {opt} [val] # Get/Set vim option in context of $win.
+ * $win command {cmd} # Execute ex command in context of $win.
+ * $win expr {expr} # Evaluate vim expression in context of $win.
+ * set buf [$win buffer] # Create Tcl command for window's buffer.
+ *
+ * $buf name # Reports file name in buffer.
+ * $buf number # Reports buffer number.
+ * set l [$buf get {n}] # Get buffer line {n} as a string.
+ * set L [$buf get {n} {m}] # Get lines {n} through {m} as a list.
+ * $buf count # Reports number of lines in buffer.
+ * $buf last # Reports number of last line in buffer.
+ * $buf delete {n} # Delete line {n}.
+ * $buf delete {n} {m} # Delete lines {n} through {m}.
+ * $buf set {n} {l} # Set line {n} to string {l}.
+ * $buf set {n} {m} {L} # Set lines {n} through {m} from list {L}.
+ * # Delete/inserts lines as appropriate.
+ * $buf option {opt} [val] # Get/Set vim option in context of $buf.
+ * $buf command {cmd} # Execute ex command in context of $buf
+ * $buf expr {cmd} # Evaluate vim expression in context of $buf.
+ * array set pos [$buf mark {m}] # Get position of mark.
+ * $buf append {n} {str} # Append string {str} to buffer,after line {n}.
+ * $buf insert {n} {str} # Insert string {str} in buffer as line {n}.
+ * $buf delcmd {cmd} # Register callback command for deleted buffer.
+ * set wl [$buf windows] # Get list of Tcl commands for all windows of
+ * # this buffer.
+TODO:
+ * ::vim::buffer new # create new buffer + Tcl command
+ */
+
+#include "vim.h"
+#undef EXTERN /* tcl.h defines it too */
+
+#ifdef DYNAMIC_TCL
+# define USE_TCL_STUBS /* use tcl's stubs mechanism */
+#endif
+
+#include <tcl.h>
+#include <string.h>
+
+typedef struct
+{
+ Tcl_Interp *interp;
+ int exitvalue;
+ int range_start, range_end;
+ int lbase;
+ char *curbuf, *curwin;
+} tcl_info;
+
+static tcl_info tclinfo = { NULL, 0, 0, 0, 0, NULL, NULL };
+
+#define VAR_RANGE1 "::vim::range(start)"
+#define VAR_RANGE2 "::vim::range(begin)"
+#define VAR_RANGE3 "::vim::range(end)"
+#define VAR_CURBUF "::vim::current(buffer)"
+#define VAR_CURWIN "::vim::current(window)"
+#define VAR_LBASE "::vim::lbase"
+#define VAR_CURLINE "line"
+#define VAR_CURLNUM "lnum"
+#define VARNAME_SIZE 64
+
+#define row2tcl(x) ((x) - (tclinfo.lbase==0))
+#define row2vim(x) ((x) + (tclinfo.lbase==0))
+#define col2tcl(x) ((x) + (tclinfo.lbase!=0))
+#define col2vim(x) ((x) - (tclinfo.lbase!=0))
+
+
+#define VIMOUT ((ClientData)1)
+#define VIMERR ((ClientData)2)
+
+/* This appears to be new in Tcl 8.4. */
+#ifndef CONST84
+# define CONST84
+#endif
+
+/*
+ * List of Tcl interpreters who reference a vim window or buffer.
+ * Each buffer and window has its own list in the w_tcl_ref or b_tcl_ref
+ * struct member. We need this because Tcl can create sub-interpreters with
+ * the "interp" command, and each interpreter can reference all windows and
+ * buffers.
+ */
+struct ref
+{
+ struct ref *next;
+
+ Tcl_Interp *interp;
+ Tcl_Command cmd; /* Tcl command that represents this object */
+ Tcl_Obj *delcmd; /* Tcl command to call when object is being del. */
+ void *vimobj; /* Vim window or buffer (win_T* or buf_T*) */
+};
+static char * tclgetbuffer _ANSI_ARGS_((Tcl_Interp *interp, buf_T *buf));
+static char * tclgetwindow _ANSI_ARGS_((Tcl_Interp *interp, win_T *win));
+static int tclsetdelcmd _ANSI_ARGS_((Tcl_Interp *interp, struct ref *reflist, void *vimobj, Tcl_Obj *delcmd));
+static int tclgetlinenum _ANSI_ARGS_ ((Tcl_Interp *interp, Tcl_Obj *obj, int *valueP, buf_T *buf));
+static win_T *tclfindwin _ANSI_ARGS_ ((buf_T *buf));
+static int tcldoexcommand _ANSI_ARGS_ ((Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], int objn));
+static int tclsetoption _ANSI_ARGS_ ((Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], int objn));
+static int tclvimexpr _ANSI_ARGS_ ((Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], int objn));
+static void tcldelthisinterp _ANSI_ARGS_ ((void));
+
+static int vimerror _ANSI_ARGS_((Tcl_Interp *interp));
+static void tclmsg _ANSI_ARGS_((char *text));
+static void tclerrmsg _ANSI_ARGS_((char *text));
+static void tclupdatevars _ANSI_ARGS_((void));
+
+static struct ref refsdeleted; /* dummy object for deleted ref list */
+
+/*****************************************************************************
+ * TCL interface manager
+ ****************************************************************************/
+
+#if defined(DYNAMIC_TCL) || defined(PROTO)
+# ifndef DYNAMIC_TCL_DLL
+# define DYNAMIC_TCL_DLL "tcl83.dll"
+# endif
+# ifndef DYNAMIC_TCL_VER
+# define DYNAMIC_TCL_VER "8.3"
+# endif
+
+# ifndef DYNAMIC_TCL /* Just generating prototypes */
+typedef int HANDLE;
+# endif
+
+# ifndef WIN3264
+# include <dlfcn.h>
+# define HANDLE void*
+# define TCL_PROC void*
+# define load_dll(n) dlopen((n), RTLD_LAZY|RTLD_GLOBAL)
+# define symbol_from_dll dlsym
+# define close_dll dlclose
+# else
+# define TCL_PROC FARPROC
+# define load_dll vimLoadLib
+# define symbol_from_dll GetProcAddress
+# define close_dll FreeLibrary
+# endif
+
+/*
+ * Declare HANDLE for tcl.dll and function pointers.
+ */
+static HANDLE hTclLib = NULL;
+Tcl_Interp* (*dll_Tcl_CreateInterp)();
+void (*dll_Tcl_FindExecutable)(const void *);
+
+/*
+ * Table of name to function pointer of tcl.
+ */
+static struct {
+ char* name;
+ TCL_PROC* ptr;
+} tcl_funcname_table[] = {
+ {"Tcl_CreateInterp", (TCL_PROC*)&dll_Tcl_CreateInterp},
+ {"Tcl_FindExecutable", (TCL_PROC*)&dll_Tcl_FindExecutable},
+ {NULL, NULL},
+};
+
+/*
+ * Make all runtime-links of tcl.
+ *
+ * 1. Get module handle using LoadLibraryEx.
+ * 2. Get pointer to tcl function by GetProcAddress.
+ * 3. Repeat 2, until get all functions will be used.
+ *
+ * Parameter 'libname' provides name of DLL.
+ * Return OK or FAIL.
+ */
+ static int
+tcl_runtime_link_init(char *libname, int verbose)
+{
+ int i;
+
+ if (hTclLib)
+ return OK;
+ if (!(hTclLib = load_dll(libname)))
+ {
+ if (verbose)
+ semsg(_(e_loadlib), libname);
+ return FAIL;
+ }
+ for (i = 0; tcl_funcname_table[i].ptr; ++i)
+ {
+ if (!(*tcl_funcname_table[i].ptr = symbol_from_dll(hTclLib,
+ tcl_funcname_table[i].name)))
+ {
+ close_dll(hTclLib);
+ hTclLib = NULL;
+ if (verbose)
+ semsg(_(e_loadfunc), tcl_funcname_table[i].name);
+ return FAIL;
+ }
+ }
+ return OK;
+}
+#endif /* defined(DYNAMIC_TCL) || defined(PROTO) */
+
+#ifdef DYNAMIC_TCL
+static char *find_executable_arg = NULL;
+#endif
+
+ void
+vim_tcl_init(char *arg)
+{
+#ifndef DYNAMIC_TCL
+ Tcl_FindExecutable(arg);
+#else
+ find_executable_arg = arg;
+#endif
+}
+
+#if defined(DYNAMIC_TCL) || defined(PROTO)
+
+static int stubs_initialized = FALSE;
+
+/*
+ * Return TRUE if the TCL interface can be used.
+ */
+ int
+tcl_enabled(int verbose)
+{
+ if (!stubs_initialized && find_executable_arg != NULL
+ && tcl_runtime_link_init((char *)p_tcldll, verbose) == OK)
+ {
+ Tcl_Interp *interp;
+
+ dll_Tcl_FindExecutable(find_executable_arg);
+
+ if ((interp = dll_Tcl_CreateInterp()) != NULL)
+ {
+ if (Tcl_InitStubs(interp, DYNAMIC_TCL_VER, 0))
+ {
+ Tcl_DeleteInterp(interp);
+ stubs_initialized = TRUE;
+ }
+ /* FIXME: When Tcl_InitStubs() was failed, how delete interp? */
+ }
+ }
+ return stubs_initialized;
+}
+#endif
+
+ void
+tcl_end(void)
+{
+#ifdef DYNAMIC_TCL
+ if (hTclLib)
+ {
+ close_dll(hTclLib);
+ hTclLib = NULL;
+ }
+#endif
+}
+
+/****************************************************************************
+ Tcl commands
+ ****************************************************************************/
+
+/*
+ * Replace standard "exit" command.
+ *
+ * Delete the Tcl interpreter; a new one will be created with the next
+ * :tcl command). The exit code is saved (and retrieved in tclexit()).
+ * Since Tcl's exit is never expected to return and this replacement
+ * does, then (except for a trivial case) additional Tcl commands will
+ * be run. Since the interpreter is now marked as deleted, an error
+ * will be returned -- typically "attempt to call eval in deleted
+ * interpreter". Hopefully, at this point, checks for TCL_ERROR take
+ * place and control percolates back up to Vim -- but with this new error
+ * string in the interpreter's result value. Therefore it would be
+ * useless for this routine to return the exit code via Tcl_SetResult().
+ */
+ static int
+exitcmd(
+ ClientData dummy UNUSED,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[])
+{
+ int value = 0;
+
+ switch (objc)
+ {
+ case 2:
+ if (Tcl_GetIntFromObj(interp, objv[1], &value) != TCL_OK)
+ break;
+ /* FALLTHROUGH */
+ case 1:
+ tclinfo.exitvalue = value;
+
+ Tcl_DeleteInterp(interp);
+ break;
+ default:
+ Tcl_WrongNumArgs(interp, 1, objv, "?returnCode?");
+ }
+ return TCL_ERROR;
+}
+
+/*
+ * "::vim::beep" - what Vi[m] does best :-)
+ */
+ static int
+beepcmd(
+ ClientData dummy UNUSED,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[])
+{
+ if (objc != 1)
+ {
+ Tcl_WrongNumArgs(interp, 1, objv, NULL);
+ return TCL_ERROR;
+ }
+ vim_beep(BO_LANG);
+ return TCL_OK;
+}
+
+/*
+ * "::vim::buffer list" - create a list of buffer commands.
+ * "::vim::buffer {N}" - create buffer command for buffer N.
+ * "::vim::buffer exists {N}" - test if buffer N exists.
+ * "::vim::buffer new" - create a new buffer (not implemented)
+ */
+ static int
+buffercmd(
+ ClientData dummy UNUSED,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[])
+{
+ char *name;
+ buf_T *buf;
+ Tcl_Obj *resobj;
+ int err, n, idx;
+ enum {BCMD_EXISTS, BCMD_LIST};
+ static CONST84 char *bcmdoptions[] =
+ {
+ "exists", "list", (char *)0
+ };
+
+ if (objc < 2)
+ {
+ Tcl_WrongNumArgs(interp, 1, objv, "option");
+ return TCL_ERROR;
+ }
+ err = Tcl_GetIntFromObj(interp, objv[1], &n);
+ if (err == TCL_OK)
+ {
+ if (objc != 2)
+ {
+ Tcl_WrongNumArgs(interp, 1, objv, "bufNumber");
+ return TCL_ERROR;
+ }
+ FOR_ALL_BUFFERS(buf)
+ {
+ if (buf->b_fnum == n)
+ {
+ name = tclgetbuffer(interp, buf);
+ if (name == NULL)
+ return TCL_ERROR;
+ Tcl_SetResult(interp, name, TCL_VOLATILE);
+ return TCL_OK;
+ }
+ }
+ Tcl_SetResult(interp, _("invalid buffer number"), TCL_STATIC);
+ return TCL_ERROR;
+ }
+ Tcl_ResetResult(interp); /* clear error from Tcl_GetIntFromObj */
+
+ err = Tcl_GetIndexFromObj(interp, objv[1], bcmdoptions, "option", 0, &idx);
+ if (err != TCL_OK)
+ return err;
+ switch (idx)
+ {
+ case BCMD_LIST:
+ if (objc != 2)
+ {
+ Tcl_WrongNumArgs(interp, 2, objv, "");
+ err = TCL_ERROR;
+ break;
+ }
+ FOR_ALL_BUFFERS(buf)
+ {
+ name = tclgetbuffer(interp, buf);
+ if (name == NULL)
+ {
+ err = TCL_ERROR;
+ break;
+ }
+ Tcl_AppendElement(interp, name);
+ }
+ break;
+
+ case BCMD_EXISTS:
+ if (objc != 3)
+ {
+ Tcl_WrongNumArgs(interp, 2, objv, "bufNumber");
+ err = TCL_ERROR;
+ break;
+ }
+ err = Tcl_GetIntFromObj(interp, objv[2], &n);
+ if (err == TCL_OK)
+ {
+ buf = buflist_findnr(n);
+ resobj = Tcl_NewIntObj(buf != NULL);
+ Tcl_SetObjResult(interp, resobj);
+ }
+ break;
+
+ default:
+ Tcl_SetResult(interp, _("not implemented yet"), TCL_STATIC);
+ err = TCL_ERROR;
+ }
+ return err;
+}
+
+/*
+ * "::vim::window list" - create list of window commands.
+ */
+ static int
+windowcmd(
+ ClientData dummy UNUSED,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[])
+{
+ char *what, *string;
+ win_T *win;
+
+ if (objc != 2)
+ {
+ Tcl_WrongNumArgs(interp, 1, objv, "option");
+ return TCL_ERROR;
+ }
+ what = Tcl_GetStringFromObj(objv[1], NULL);
+ if (strcmp(what, "list") == 0)
+ {
+ FOR_ALL_WINDOWS(win)
+ {
+ string = tclgetwindow(interp, win);
+ if (string == NULL)
+ return TCL_ERROR;
+ Tcl_AppendElement(interp, string);
+ }
+ return TCL_OK;
+ }
+ Tcl_SetResult(interp, _("unknown option"), TCL_STATIC);
+ return TCL_ERROR;
+}
+
+/*
+ * flags for bufselfcmd and winselfcmd to indicate outstanding actions.
+ */
+#define FL_UPDATE_SCREEN (1<<0)
+#define FL_UPDATE_CURBUF (1<<1)
+#define FL_ADJUST_CURSOR (1<<2)
+
+/*
+ * This function implements the buffer commands.
+ */
+ static int
+bufselfcmd(
+ ClientData ref,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[])
+{
+ int opt, err, idx, flags;
+ int val1, val2, n, i;
+ buf_T *buf, *savebuf;
+ win_T *win, *savewin;
+ Tcl_Obj *resobj;
+ pos_T *pos;
+ char *line;
+
+ enum
+ {
+ BUF_APPEND, BUF_COMMAND, BUF_COUNT, BUF_DELCMD, BUF_DELETE, BUF_EXPR,
+ BUF_GET, BUF_INSERT, BUF_LAST, BUF_MARK, BUF_NAME, BUF_NUMBER,
+ BUF_OPTION, BUF_SET, BUF_WINDOWS
+ };
+ static CONST84 char *bufoptions[] =
+ {
+ "append", "command", "count", "delcmd", "delete", "expr",
+ "get", "insert", "last", "mark", "name", "number",
+ "option", "set", "windows", (char *)0
+ };
+
+ if (objc < 2)
+ {
+ Tcl_WrongNumArgs(interp, 1, objv, "option ?arg ...?");
+ return TCL_ERROR;
+ }
+
+ err = Tcl_GetIndexFromObj(interp, objv[1], bufoptions, "option", 0, &idx);
+ if (err != TCL_OK)
+ return err;
+
+ buf = (buf_T *)((struct ref *)ref)->vimobj;
+ savebuf = curbuf; curbuf = buf;
+ savewin = curwin; curwin = tclfindwin(buf);
+ flags = 0;
+ opt = 0;
+
+ switch (idx)
+ {
+ case BUF_COMMAND:
+ err = tcldoexcommand(interp, objc, objv, 2);
+ flags |= FL_UPDATE_SCREEN;
+ break;
+
+ case BUF_OPTION:
+ err = tclsetoption(interp, objc, objv, 2);
+ flags |= FL_UPDATE_SCREEN;
+ break;
+
+ case BUF_EXPR:
+ err = tclvimexpr(interp, objc, objv, 2);
+ break;
+
+ case BUF_NAME:
+ /*
+ * Get filename of buffer.
+ */
+ if (objc != 2)
+ {
+ Tcl_WrongNumArgs(interp, 2, objv, NULL);
+ err = TCL_ERROR;
+ break;
+ }
+ if (buf->b_ffname)
+ Tcl_SetResult(interp, (char *)buf->b_ffname, TCL_VOLATILE);
+ else
+ Tcl_SetResult(interp, "", TCL_STATIC);
+ break;
+
+ case BUF_LAST:
+ /*
+ * Get line number of last line.
+ */
+ opt = 1;
+ /* fallthrough */
+ case BUF_COUNT:
+ /*
+ * Get number of lines in buffer.
+ */
+ if (objc != 2)
+ {
+ Tcl_WrongNumArgs(interp, 2, objv, NULL);
+ err = TCL_ERROR;
+ break;
+ }
+ val1 = (int)buf->b_ml.ml_line_count;
+ if (opt)
+ val1 = row2tcl(val1);
+
+ resobj = Tcl_NewIntObj(val1);
+ Tcl_SetObjResult(interp, resobj);
+ break;
+
+ case BUF_NUMBER:
+ /*
+ * Get buffer's number.
+ */
+ if (objc != 2)
+ {
+ Tcl_WrongNumArgs(interp, 2, objv, NULL);
+ err = TCL_ERROR;
+ break;
+ }
+ resobj = Tcl_NewIntObj((int)buf->b_fnum);
+ Tcl_SetObjResult(interp, resobj);
+ break;
+
+ case BUF_GET:
+ if (objc != 3 && objc != 4)
+ {
+ Tcl_WrongNumArgs(interp, 2, objv, "lineNumber ?lineNumber?");
+ err = TCL_ERROR;
+ break;
+ }
+ err = tclgetlinenum(interp, objv[2], &val1, buf);
+ if (err != TCL_OK)
+ break;
+ if (objc == 4)
+ {
+ err = tclgetlinenum(interp, objv[3], &val2, buf);
+ if (err != TCL_OK)
+ break;
+ if (val1 > val2)
+ {
+ n = val1; val1 = val2; val2 = n;
+ }
+ Tcl_ResetResult(interp);
+
+ for (n = val1; n <= val2 && err == TCL_OK; n++)
+ {
+ line = (char *)ml_get_buf(buf, (linenr_T)n, FALSE);
+ if (line)
+ Tcl_AppendElement(interp, line);
+ else
+ err = TCL_ERROR;
+ }
+ }
+ else { /* objc == 3 */
+ line = (char *)ml_get_buf(buf, (linenr_T)val1, FALSE);
+ Tcl_SetResult(interp, line, TCL_VOLATILE);
+ }
+ break;
+
+ case BUF_SET:
+ if (objc != 4 && objc != 5)
+ {
+ Tcl_WrongNumArgs(interp, 3, objv, "lineNumber ?lineNumber? stringOrList");
+ err = TCL_ERROR;
+ break;
+ }
+ err = tclgetlinenum(interp, objv[2], &val1, buf);
+ if (err != TCL_OK)
+ return TCL_ERROR;
+ if (objc == 4)
+ {
+ /*
+ * Replace one line with a string.
+ * $buf set {n} {string}
+ */
+ line = Tcl_GetStringFromObj(objv[3], NULL);
+ if (u_savesub((linenr_T)val1) != OK)
+ {
+ Tcl_SetResult(interp, _("cannot save undo information"), TCL_STATIC);
+ err = TCL_ERROR;
+ }
+ else
+ if (ml_replace((linenr_T)val1, (char_u *)line, TRUE) != OK)
+ {
+ Tcl_SetResult(interp, _("cannot replace line"), TCL_STATIC);
+ err = TCL_ERROR;
+ }
+ else
+ {
+ changed_bytes((linenr_T)val1, 0);
+ flags |= FL_UPDATE_CURBUF;
+ }
+ break;
+ }
+ else
+ {
+ /*
+ * Replace several lines with the elements of a Tcl list.
+ * $buf set {n} {m} {list}
+ * If the list contains more than {m}-{n}+1 elements, they
+ * are * inserted after line {m}. If the list contains fewer
+ * elements, * the lines from {n}+length({list}) through {m}
+ * are deleted.
+ */
+ int lc;
+ Tcl_Obj **lv;
+
+ err = tclgetlinenum(interp, objv[3], &val2, buf);
+ if (err != TCL_OK)
+ break;
+ err = Tcl_ListObjGetElements(interp, objv[4], &lc, &lv);
+ if (err != TCL_OK)
+ break;
+ if (val1 > val2)
+ {
+ n = val1;
+ val1 = val2;
+ val2 = n;
+ }
+
+ n = val1;
+ if (u_save((linenr_T)(val1 - 1), (linenr_T)(val2 + 1)) != OK)
+ {
+ Tcl_SetResult(interp, _("cannot save undo information"),
+ TCL_STATIC);
+ err = TCL_ERROR;
+ break;
+ }
+ flags |= FL_UPDATE_CURBUF;
+
+ for (i = 0; i < lc && n <= val2; i++)
+ {
+ line = Tcl_GetStringFromObj(lv[i], NULL);
+ if (ml_replace((linenr_T)n, (char_u *)line, TRUE) != OK)
+ goto setListError;
+ ++n;
+ }
+ if (i < lc)
+ {
+ /* append lines */
+ do
+ {
+ line = Tcl_GetStringFromObj(lv[i], NULL);
+ if (ml_append((linenr_T)(n - 1),
+ (char_u *)line, 0, FALSE) != OK)
+ goto setListError;
+ ++n;
+ ++i;
+ } while (i < lc);
+ }
+ else if (n <= val2)
+ {
+ /* did not replace all lines, delete */
+ i = n;
+ do
+ {
+ if (ml_delete((linenr_T)i, FALSE) != OK)
+ goto setListError;
+ ++n;
+ } while (n <= val2);
+ }
+ lc -= val2 - val1 + 1; /* number of lines to be replaced */
+ mark_adjust((linenr_T)val1, (linenr_T)val2, (long)MAXLNUM,
+ (long)lc);
+ changed_lines((linenr_T)val1, 0, (linenr_T)val2 + 1, (long)lc);
+ break;
+ setListError:
+ u_undo(1); /* ??? */
+ Tcl_SetResult(interp, _("cannot set line(s)"), TCL_STATIC);
+ err = TCL_ERROR;
+ }
+ break;
+
+ case BUF_DELETE:
+ if (objc != 3 && objc != 4)
+ {
+ Tcl_WrongNumArgs(interp, 3, objv, "lineNumber ?lineNumber?");
+ err = TCL_ERROR;
+ break;
+ }
+ err = tclgetlinenum(interp, objv[2], &val1, buf);
+ if (err != TCL_OK)
+ break;
+ val2 = val1;
+ if (objc == 4)
+ {
+ err = tclgetlinenum(interp, objv[3], &val2, buf);
+ if (err != TCL_OK)
+ return err;
+ if (val1 > val2)
+ {
+ i = val1; val1 = val2; val2 = i;
+ }
+ }
+ n = val2 - val1 + 1;
+ if (u_savedel((linenr_T)val1, (long)n) != OK)
+ {
+ Tcl_SetResult(interp, _("cannot save undo information"),
+ TCL_STATIC);
+ err = TCL_ERROR;
+ break;
+ }
+ for (i = 0; i < n; i++)
+ {
+ ml_delete((linenr_T)val1, FALSE);
+ err = vimerror(interp);
+ if (err != TCL_OK)
+ break;
+ }
+ if (i > 0)
+ deleted_lines_mark((linenr_T)val1, (long)i);
+ flags |= FL_ADJUST_CURSOR|FL_UPDATE_SCREEN;
+ break;
+
+ case BUF_MARK:
+ if (objc != 3)
+ {
+ Tcl_WrongNumArgs(interp, 2, objv, "markName");
+ err = TCL_ERROR;
+ break;
+ }
+ line = Tcl_GetStringFromObj(objv[2], NULL);
+
+ pos = NULL;
+ if (line[0] != '\0' && line[1] == '\0')
+ {
+ pos = getmark(line[0], FALSE);
+ }
+ if (pos == NULL)
+ {
+ Tcl_SetResult(interp, _("invalid mark name"), TCL_STATIC);
+ err = TCL_ERROR;
+ break;
+ }
+ err = vimerror(interp);
+ if (err != TCL_OK)
+ break;
+ if (pos->lnum <= 0)
+ {
+ Tcl_SetResult(interp, _("mark not set"), TCL_STATIC);
+ err = TCL_ERROR;
+ }
+ else
+ {
+ char rbuf[64];
+
+ sprintf(rbuf, _("row %d column %d"),
+ (int)row2tcl(pos->lnum), (int)col2tcl(pos->col));
+ Tcl_SetResult(interp, rbuf, TCL_VOLATILE);
+ }
+ break;
+
+ case BUF_INSERT:
+ opt = 1;
+ /* fallthrough */
+ case BUF_APPEND:
+ if (objc != 4)
+ {
+ Tcl_WrongNumArgs(interp, 2, objv, "lineNum text");
+ err = TCL_ERROR;
+ break;
+ }
+ err = tclgetlinenum(interp, objv[2], &val1, buf);
+ if (err != TCL_OK)
+ break;
+ if (opt)
+ --val1;
+ if (u_save((linenr_T)val1, (linenr_T)(val1+1)) != OK)
+ {
+ Tcl_SetResult(interp, _("cannot save undo information"),
+ TCL_STATIC);
+ err = TCL_ERROR;
+ break;
+ }
+
+ line = Tcl_GetStringFromObj(objv[3], NULL);
+ if (ml_append((linenr_T)val1, (char_u *)line, 0, FALSE) != OK)
+ {
+ Tcl_SetResult(interp, _("cannot insert/append line"),
+ TCL_STATIC);
+ err = TCL_ERROR;
+ break;
+ }
+ appended_lines_mark((linenr_T)val1, 1L);
+ flags |= FL_UPDATE_SCREEN;
+ break;
+
+ case BUF_WINDOWS:
+ /*
+ * Return list of window commands.
+ */
+ if (objc != 2)
+ {
+ Tcl_WrongNumArgs(interp, 2, objv, NULL);
+ err = TCL_ERROR;
+ break;
+ }
+ Tcl_ResetResult(interp);
+ FOR_ALL_WINDOWS(win)
+ {
+ if (win->w_buffer == buf)
+ {
+ line = tclgetwindow(interp, win);
+ if (line != NULL)
+ Tcl_AppendElement(interp, line);
+ else
+ {
+ err = TCL_ERROR;
+ break;
+ }
+ }
+ }
+ break;
+
+ case BUF_DELCMD:
+ /*
+ * Register deletion callback.
+ * TODO: Should be able to register multiple callbacks
+ */
+ if (objc != 3)
+ {
+ Tcl_WrongNumArgs(interp, 2, objv, "command");
+ err = TCL_ERROR;
+ break;
+ }
+ err = tclsetdelcmd(interp, buf->b_tcl_ref, (void *)buf, objv[2]);
+ break;
+
+ default:
+ Tcl_SetResult(interp, _("not implemented yet"), TCL_STATIC);
+ err = TCL_ERROR;
+ }
+
+ if (flags & FL_UPDATE_CURBUF)
+ redraw_curbuf_later(NOT_VALID);
+ curbuf = savebuf;
+ curwin = savewin;
+ if (flags & FL_ADJUST_CURSOR)
+ check_cursor();
+ if (flags & (FL_UPDATE_SCREEN | FL_UPDATE_CURBUF))
+ update_screen(NOT_VALID);
+
+ return err;
+}
+
+/*
+ * This function implements the window commands.
+ */
+ static int
+winselfcmd(
+ ClientData ref,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[])
+{
+ int err, idx, flags;
+ int val1, val2;
+ Tcl_Obj *resobj;
+ win_T *savewin, *win;
+ buf_T *savebuf;
+ char *str;
+
+ enum
+ {
+ WIN_BUFFER, WIN_COMMAND, WIN_CURSOR, WIN_DELCMD, WIN_EXPR,
+ WIN_HEIGHT, WIN_OPTION
+ };
+ static CONST84 char *winoptions[] =
+ {
+ "buffer", "command", "cursor", "delcmd", "expr",
+ "height", "option", (char *)0
+ };
+
+ if (objc < 2)
+ {
+ Tcl_WrongNumArgs(interp, 1, objv, "option ?arg ...?");
+ return TCL_ERROR;
+ }
+
+ err = Tcl_GetIndexFromObj(interp, objv[1], winoptions, "option", 0, &idx);
+ if (err != TCL_OK)
+ return TCL_ERROR;
+
+ win = (win_T *)((struct ref *)ref)->vimobj;
+ savewin = curwin; curwin = win;
+ savebuf = curbuf; curbuf = win->w_buffer;
+ flags = 0;
+
+ switch (idx)
+ {
+ case WIN_OPTION:
+ err = tclsetoption(interp, objc, objv, 2);
+ flags |= FL_UPDATE_SCREEN;
+ break;
+
+ case WIN_COMMAND:
+ err = tcldoexcommand(interp, objc, objv, 2);
+ flags |= FL_UPDATE_SCREEN;
+ break;
+
+ case WIN_EXPR:
+ err = tclvimexpr(interp, objc, objv, 2);
+ break;
+
+ case WIN_HEIGHT:
+ if (objc == 3)
+ {
+ err = Tcl_GetIntFromObj(interp, objv[2], &val1);
+ if (err != TCL_OK)
+ break;
+#ifdef FEAT_GUI
+ need_mouse_correct = TRUE;
+#endif
+ win_setheight(val1);
+ err = vimerror(interp);
+ if (err != TCL_OK)
+ break;
+ }
+ else
+ if (objc != 2)
+ {
+ Tcl_WrongNumArgs(interp, 2, objv, "?value?");
+ err = TCL_ERROR;
+ break;
+ }
+
+ resobj = Tcl_NewIntObj((int)(win->w_height));
+ Tcl_SetObjResult(interp, resobj);
+ break;
+
+ case WIN_BUFFER:
+ if (objc != 2)
+ {
+ Tcl_WrongNumArgs(interp, 2, objv, NULL);
+ err = TCL_ERROR;
+ break;
+ }
+ str = tclgetbuffer(interp, win->w_buffer);
+ if (str)
+ Tcl_SetResult(interp, str, TCL_VOLATILE);
+ else
+ err = TCL_ERROR;
+ break;
+
+ case WIN_DELCMD:
+ if (objc != 3)
+ {
+ Tcl_WrongNumArgs(interp, 2, objv, "command");
+ err = TCL_ERROR;
+ break;
+ }
+ err = tclsetdelcmd(interp, win->w_tcl_ref, (void *)win, objv[2]);
+ break;
+
+ case WIN_CURSOR:
+ if (objc > 4)
+ {
+ Tcl_WrongNumArgs(interp, 2, objv, "?arg1 ?arg2??");
+ err = TCL_ERROR;
+ break;
+ }
+ if (objc == 2)
+ {
+ char buf[64];
+
+ sprintf(buf, _("row %d column %d"), (int)row2tcl(win->w_cursor.lnum), (int)col2tcl(win->w_cursor.col));
+ Tcl_SetResult(interp, buf, TCL_VOLATILE);
+ break;
+ }
+ else if (objc == 3)
+ {
+ Tcl_Obj *part, *var;
+
+ part = Tcl_NewStringObj("row", -1);
+ var = Tcl_ObjGetVar2(interp, objv[2], part, TCL_LEAVE_ERR_MSG);
+ if (var == NULL)
+ {
+ err = TCL_ERROR;
+ break;
+ }
+ err = tclgetlinenum(interp, var, &val1, win->w_buffer);
+ if (err != TCL_OK)
+ break;
+ part = Tcl_NewStringObj("column", -1);
+ var = Tcl_ObjGetVar2(interp, objv[2], part, TCL_LEAVE_ERR_MSG);
+ if (var == NULL)
+ {
+ err = TCL_ERROR;
+ break;
+ }
+ err = Tcl_GetIntFromObj(interp, var, &val2);
+ if (err != TCL_OK)
+ break;
+ }
+ else { /* objc == 4 */
+ err = tclgetlinenum(interp, objv[2], &val1, win->w_buffer);
+ if (err != TCL_OK)
+ break;
+ err = Tcl_GetIntFromObj(interp, objv[3], &val2);
+ if (err != TCL_OK)
+ break;
+ }
+ /* TODO: should check column */
+ win->w_cursor.lnum = val1;
+ win->w_cursor.col = col2vim(val2);
+ win->w_set_curswant = TRUE;
+ flags |= FL_UPDATE_SCREEN;
+ break;
+
+ default:
+ Tcl_SetResult(interp, _("not implemented yet"), TCL_STATIC);
+ break;
+ }
+
+ curwin = savewin;
+ curbuf = savebuf;
+ if (flags & FL_UPDATE_SCREEN)
+ update_screen(NOT_VALID);
+
+ return err;
+}
+
+
+ static int
+commandcmd(
+ ClientData dummy UNUSED,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[])
+{
+ int err;
+
+ err = tcldoexcommand(interp, objc, objv, 1);
+ update_screen(VALID);
+ return err;
+}
+
+ static int
+optioncmd(
+ ClientData dummy UNUSED,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[])
+{
+ int err;
+
+ err = tclsetoption(interp, objc, objv, 1);
+ update_screen(VALID);
+ return err;
+}
+
+ static int
+exprcmd(
+ ClientData dummy UNUSED,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[])
+{
+ return tclvimexpr(interp, objc, objv, 1);
+}
+
+/****************************************************************************
+ Support functions for Tcl commands
+ ****************************************************************************/
+
+/*
+ * Get a line number from 'obj' and convert it to vim's range.
+ */
+ static int
+tclgetlinenum(
+ Tcl_Interp *interp,
+ Tcl_Obj *obj,
+ int *valueP,
+ buf_T *buf)
+{
+ int err, i;
+
+ enum { LN_BEGIN, LN_BOTTOM, LN_END, LN_FIRST, LN_LAST, LN_START, LN_TOP };
+
+ static CONST84 char *keyw[] =
+ {
+ "begin", "bottom", "end", "first", "last", "start", "top", (char *)0
+ };
+
+ err = Tcl_GetIndexFromObj(interp, obj, keyw, "", 0, &i);
+ if (err == TCL_OK)
+ {
+ switch (i)
+ {
+ case LN_BEGIN:
+ case LN_FIRST:
+ case LN_START:
+ case LN_TOP:
+ *valueP = 1;
+ break;
+ case LN_BOTTOM:
+ case LN_END:
+ case LN_LAST:
+ *valueP = buf->b_ml.ml_line_count;
+ break;
+ }
+ return TCL_OK;
+ }
+ Tcl_ResetResult(interp);
+
+ err = Tcl_GetIntFromObj(interp, obj, &i);
+ if (err != TCL_OK)
+ return err;
+ i = row2vim(i);
+ if (i < 1 || i > buf->b_ml.ml_line_count)
+ {
+ Tcl_SetResult(interp, _("line number out of range"), TCL_STATIC);
+ return TCL_ERROR;
+ }
+ *valueP = i;
+ return TCL_OK;
+}
+
+/*
+ * Find the first window in the window list that displays the buffer.
+ */
+ static win_T *
+tclfindwin(buf_T *buf)
+{
+ win_T *win;
+
+ FOR_ALL_WINDOWS(win)
+ {
+ if (win->w_buffer == buf)
+ return win;
+ }
+ return curwin; /* keep current window context */
+}
+
+/*
+ * Do-it-all function for "::vim::command", "$buf command" and "$win command".
+ */
+ static int
+tcldoexcommand(
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[],
+ int objn)
+{
+ tcl_info saveinfo;
+ int err, flag, nobjs;
+ char *arg;
+
+ nobjs = objc - objn;
+ if (nobjs < 1 || nobjs > 2)
+ {
+ Tcl_WrongNumArgs(interp, objn, objv, "?-quiet? exCommand");
+ return TCL_ERROR;
+ }
+
+ flag = 0;
+ if (nobjs == 2)
+ {
+ arg = Tcl_GetStringFromObj(objv[objn], NULL);
+ if (strcmp(arg, "-quiet") == 0)
+ flag = 1;
+ else
+ {
+ Tcl_ResetResult(interp);
+ Tcl_AppendResult(interp, _("unknown flag: "), arg, (char *)0);
+ return TCL_ERROR;
+ }
+ ++objn;
+ }
+
+ memcpy(&saveinfo, &tclinfo, sizeof(tcl_info));
+ tclinfo.interp = NULL;
+ tclinfo.curwin = NULL;
+ tclinfo.curbuf = NULL;
+
+ arg = Tcl_GetStringFromObj(objv[objn], NULL);
+ if (flag)
+ ++emsg_off;
+ do_cmdline_cmd((char_u *)arg);
+ if (flag)
+ --emsg_off;
+ err = vimerror(interp);
+
+ /* If the ex command created a new Tcl interpreter, remove it */
+ if (tclinfo.interp)
+ tcldelthisinterp();
+ memcpy(&tclinfo, &saveinfo, sizeof(tcl_info));
+ tclupdatevars();
+
+ return err;
+}
+
+/*
+ * Do-it-all function for "::vim::option", "$buf option" and "$win option".
+ */
+ static int
+tclsetoption(
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[],
+ int objn)
+{
+ int err, nobjs, idx;
+ char_u *option;
+ int isnum;
+ long lval;
+ char_u *sval;
+ Tcl_Obj *resobj;
+
+ enum { OPT_OFF, OPT_ON, OPT_TOGGLE };
+ static CONST84 char *optkw[] = { "off", "on", "toggle", (char *)0 };
+
+ nobjs = objc - objn;
+ if (nobjs != 1 && nobjs != 2)
+ {
+ Tcl_WrongNumArgs(interp, objn, objv, "vimOption ?value?");
+ return TCL_ERROR;
+ }
+
+ option = (char_u *)Tcl_GetStringFromObj(objv[objn], NULL);
+ ++objn;
+ isnum = get_option_value(option, &lval, &sval, 0);
+ err = TCL_OK;
+ switch (isnum)
+ {
+ case 0:
+ Tcl_SetResult(interp, (char *)sval, TCL_VOLATILE);
+ vim_free(sval);
+ break;
+ case 1:
+ resobj = Tcl_NewLongObj(lval);
+ Tcl_SetObjResult(interp, resobj);
+ break;
+ default:
+ Tcl_SetResult(interp, _("unknown vimOption"), TCL_STATIC);
+ return TCL_ERROR;
+ }
+ if (nobjs == 2)
+ {
+ if (isnum)
+ {
+ sval = NULL; /* avoid compiler warning */
+ err = Tcl_GetIndexFromObj(interp, objv[objn], optkw, "", 0, &idx);
+ if (err != TCL_OK)
+ {
+ Tcl_ResetResult(interp);
+ err = Tcl_GetLongFromObj(interp, objv[objn], &lval);
+ }
+ else
+ switch (idx)
+ {
+ case OPT_ON:
+ lval = 1;
+ break;
+ case OPT_OFF:
+ lval = 0;
+ break;
+ case OPT_TOGGLE:
+ lval = !lval;
+ break;
+ }
+ }
+ else
+ sval = (char_u *)Tcl_GetStringFromObj(objv[objn], NULL);
+ if (err == TCL_OK)
+ {
+ set_option_value(option, lval, sval, OPT_LOCAL);
+ err = vimerror(interp);
+ }
+ }
+ return err;
+}
+
+/*
+ * Do-it-all function for "::vim::expr", "$buf expr" and "$win expr".
+ */
+ static int
+tclvimexpr(
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[],
+ int objn)
+{
+#ifdef FEAT_EVAL
+ char *expr, *str;
+#endif
+ int err;
+
+ if (objc - objn != 1)
+ {
+ Tcl_WrongNumArgs(interp, objn, objv, "vimExpr");
+ return TCL_ERROR;
+ }
+
+#ifdef FEAT_EVAL
+ expr = Tcl_GetStringFromObj(objv[objn], NULL);
+ str = (char *)eval_to_string((char_u *)expr, NULL, TRUE);
+ if (str == NULL)
+ Tcl_SetResult(interp, _("invalid expression"), TCL_STATIC);
+ else
+ {
+ Tcl_SetResult(interp, str, TCL_VOLATILE);
+ vim_free(str);
+ }
+ err = vimerror(interp);
+#else
+ Tcl_SetResult(interp, _("expressions disabled at compile time"), TCL_STATIC);
+ err = TCL_ERROR;
+#endif
+
+ return err;
+}
+
+/*
+ * Check for internal vim errors.
+ */
+ static int
+vimerror(Tcl_Interp *interp)
+{
+ if (got_int)
+ {
+ Tcl_SetResult(interp, _("keyboard interrupt"), TCL_STATIC);
+ return TCL_ERROR;
+ }
+ else if (did_emsg)
+ {
+ Tcl_SetResult(interp, _("vim error"), TCL_STATIC);
+ return TCL_ERROR;
+ }
+ return TCL_OK;
+}
+
+/*
+ * Functions that handle the reference lists:
+ * delref() - callback for Tcl's DeleteCommand
+ * tclgetref() - find/create Tcl command for a win_T* or buf_T* object
+ * tclgetwindow() - window frontend for tclgetref()
+ * tclgetbuffer() - buffer frontend for tclgetref()
+ * tclsetdelcmd() - add Tcl callback command to a vim object
+ */
+ static void
+delref(ClientData cref)
+{
+ struct ref *ref = (struct ref *)cref;
+
+ if (ref->delcmd)
+ {
+ Tcl_DecrRefCount(ref->delcmd);
+ ref->delcmd = NULL;
+ }
+ ref->interp = NULL;
+}
+
+ static char *
+tclgetref(
+ Tcl_Interp *interp,
+ void **refstartP, /* ptr to w_tcl_ref/b_tcl-ref member of
+ win_T/buf_T struct */
+ char *prefix, /* "win" or "buf" */
+ void *vimobj, /* win_T* or buf_T* */
+ Tcl_ObjCmdProc *proc) /* winselfcmd or bufselfcmd */
+{
+ struct ref *ref, *unused = NULL;
+ static char name[VARNAME_SIZE];
+ Tcl_Command cmd;
+
+ ref = (struct ref *)(*refstartP);
+ if (ref == &refsdeleted)
+ {
+ Tcl_SetResult(interp, _("cannot create buffer/window command: object is being deleted"), TCL_STATIC);
+ return NULL;
+ }
+
+ while (ref != NULL)
+ {
+ if (ref->interp == interp)
+ break;
+ if (ref->interp == NULL)
+ unused = ref;
+ ref = ref->next;
+ }
+
+ if (ref)
+ vim_snprintf(name, sizeof(name), "::vim::%s",
+ Tcl_GetCommandName(interp, ref->cmd));
+ else
+ {
+ if (unused)
+ ref = unused;
+ else
+ {
+ ref = (struct ref *)Tcl_Alloc(sizeof(struct ref));
+ ref->interp = NULL;
+ ref->next = (struct ref *)(*refstartP);
+ (*refstartP) = (void *)ref;
+ }
+
+ /* This might break on some exotic systems... */
+ vim_snprintf(name, sizeof(name), "::vim::%s_%lx",
+ prefix, (unsigned long)vimobj);
+ cmd = Tcl_CreateObjCommand(interp, name, proc,
+ (ClientData)ref, (Tcl_CmdDeleteProc *)delref);
+ if (!cmd)
+ return NULL;
+
+ ref->interp = interp;
+ ref->cmd = cmd;
+ ref->delcmd = NULL;
+ ref->vimobj = vimobj;
+ }
+ return name;
+}
+
+ static char *
+tclgetwindow(Tcl_Interp *interp, win_T *win)
+{
+ return tclgetref(interp, &(win->w_tcl_ref), "win", (void *)win, winselfcmd);
+}
+
+ static char *
+tclgetbuffer(Tcl_Interp *interp, buf_T *buf)
+{
+ return tclgetref(interp, &(buf->b_tcl_ref), "buf", (void *)buf, bufselfcmd);
+}
+
+ static int
+tclsetdelcmd(
+ Tcl_Interp *interp,
+ struct ref *reflist,
+ void *vimobj,
+ Tcl_Obj *delcmd)
+{
+ if (reflist == &refsdeleted)
+ {
+ Tcl_SetResult(interp, _("cannot register callback command: buffer/window is already being deleted"), TCL_STATIC);
+ return TCL_ERROR;
+ }
+
+ while (reflist != NULL)
+ {
+ if (reflist->interp == interp && reflist->vimobj == vimobj)
+ {
+ if (reflist->delcmd)
+ {
+ Tcl_DecrRefCount(reflist->delcmd);
+ }
+ Tcl_IncrRefCount(delcmd);
+ reflist->delcmd = delcmd;
+ return TCL_OK;
+ }
+ reflist = reflist->next;
+ }
+ /* This should never happen. Famous last word? */
+ emsg(_("E280: TCL FATAL ERROR: reflist corrupt!? Please report this to vim-dev@vim.org"));
+ Tcl_SetResult(interp, _("cannot register callback command: buffer/window reference not found"), TCL_STATIC);
+ return TCL_ERROR;
+}
+
+
+/*******************************************
+ I/O Channel
+********************************************/
+
+ static int
+tcl_channel_close(ClientData instance, Tcl_Interp *interp UNUSED)
+{
+ int err = 0;
+
+ /* currently does nothing */
+
+ if (instance != VIMOUT && instance != VIMERR)
+ {
+ Tcl_SetErrno(EBADF);
+ err = EBADF;
+ }
+ return err;
+}
+
+ static int
+tcl_channel_input(
+ ClientData instance UNUSED,
+ char *buf UNUSED,
+ int bufsiz UNUSED,
+ int *errptr)
+{
+
+ /* input is currently not supported */
+
+ Tcl_SetErrno(EINVAL);
+ if (errptr)
+ *errptr = EINVAL;
+ return -1;
+}
+
+ static int
+tcl_channel_output(
+ ClientData instance,
+ const char *buf,
+ int bufsiz,
+ int *errptr)
+{
+ char_u *str;
+ int result;
+
+ /* The buffer is not guaranteed to be 0-terminated, and we don't if
+ * there is enough room to add a '\0'. So we have to create a copy
+ * of the buffer...
+ */
+ str = vim_strnsave((char_u *)buf, bufsiz);
+ if (!str)
+ {
+ Tcl_SetErrno(ENOMEM);
+ if (errptr)
+ *errptr = ENOMEM;
+ return -1;
+ }
+
+ result = bufsiz;
+ if (instance == VIMOUT)
+ tclmsg((char *)str);
+ else
+ if (instance == VIMERR)
+ tclerrmsg((char *)str);
+ else
+ {
+ Tcl_SetErrno(EBADF);
+ if (errptr)
+ *errptr = EBADF;
+ result = -1;
+ }
+ vim_free(str);
+ return result;
+}
+
+ static void
+tcl_channel_watch(ClientData instance UNUSED, int mask UNUSED)
+{
+ Tcl_SetErrno(EINVAL);
+}
+
+ static int
+tcl_channel_gethandle(
+ ClientData instance UNUSED,
+ int direction UNUSED,
+ ClientData *handleptr UNUSED)
+{
+ Tcl_SetErrno(EINVAL);
+ return EINVAL;
+}
+
+
+static Tcl_ChannelType tcl_channel_type =
+{
+ "vimmessage", /* typeName */
+ TCL_CHANNEL_VERSION_2, /* version */
+ tcl_channel_close, /* closeProc */
+ tcl_channel_input, /* inputProc */
+ tcl_channel_output, /* outputProc */
+ NULL, /* seekProc */
+ NULL, /* setOptionProc */
+ NULL, /* getOptionProc */
+ tcl_channel_watch, /* watchProc */
+ tcl_channel_gethandle, /* getHandleProc */
+ NULL, /* close2Proc */
+ NULL, /* blockModeProc */
+#ifdef TCL_CHANNEL_VERSION_2
+ NULL, /* flushProc */
+ NULL, /* handlerProc */
+#endif
+/* The following should not be necessary since TCL_CHANNEL_VERSION_2 was
+ * set above */
+#ifdef TCL_CHANNEL_VERSION_3
+ NULL, /* wideSeekProc */
+#endif
+#ifdef TCL_CHANNEL_VERSION_4
+ NULL, /* threadActionProc */
+#endif
+#ifdef TCL_CHANNEL_VERSION_5
+ NULL /* truncateProc */
+#endif
+};
+
+/**********************************
+ Interface to vim
+ **********************************/
+
+ static void
+tclupdatevars(void)
+{
+ char varname[VARNAME_SIZE]; /* must be writeable */
+ char *name;
+
+ strcpy(varname, VAR_RANGE1);
+ Tcl_UpdateLinkedVar(tclinfo.interp, varname);
+ strcpy(varname, VAR_RANGE2);
+ Tcl_UpdateLinkedVar(tclinfo.interp, varname);
+ strcpy(varname, VAR_RANGE3);
+ Tcl_UpdateLinkedVar(tclinfo.interp, varname);
+
+ strcpy(varname, VAR_LBASE);
+ Tcl_UpdateLinkedVar(tclinfo.interp, varname);
+
+ name = tclgetbuffer(tclinfo.interp, curbuf);
+ strcpy(tclinfo.curbuf, name);
+ strcpy(varname, VAR_CURBUF);
+ Tcl_UpdateLinkedVar(tclinfo.interp, varname);
+
+ name = tclgetwindow(tclinfo.interp, curwin);
+ strcpy(tclinfo.curwin, name);
+ strcpy(varname, VAR_CURWIN);
+ Tcl_UpdateLinkedVar(tclinfo.interp, varname);
+}
+
+
+ static int
+tclinit(exarg_T *eap)
+{
+ char varname[VARNAME_SIZE]; /* Tcl_LinkVar requires writeable varname */
+ char *name;
+
+#ifdef DYNAMIC_TCL
+ if (!tcl_enabled(TRUE))
+ {
+ emsg(_("E571: Sorry, this command is disabled: the Tcl library could not be loaded."));
+ return FAIL;
+ }
+#endif
+
+ if (!tclinfo.interp)
+ {
+ Tcl_Interp *interp;
+ static Tcl_Channel ch1, ch2;
+
+ /* Create replacement channels for stdout and stderr; this has to be
+ * done each time an interpreter is created since the channels are closed
+ * when the interpreter is deleted */
+ ch1 = Tcl_CreateChannel(&tcl_channel_type, "vimout", VIMOUT, TCL_WRITABLE);
+ ch2 = Tcl_CreateChannel(&tcl_channel_type, "vimerr", VIMERR, TCL_WRITABLE);
+ Tcl_SetStdChannel(ch1, TCL_STDOUT);
+ Tcl_SetStdChannel(ch2, TCL_STDERR);
+
+ interp = Tcl_CreateInterp();
+ Tcl_Preserve(interp);
+ if (Tcl_Init(interp) == TCL_ERROR)
+ {
+ Tcl_Release(interp);
+ Tcl_DeleteInterp(interp);
+ return FAIL;
+ }
+#if 0
+ /* VIM sure is interactive */
+ Tcl_SetVar(interp, "tcl_interactive", "1", TCL_GLOBAL_ONLY);
+#endif
+
+ Tcl_SetChannelOption(interp, ch1, "-buffering", "line");
+#ifdef WIN3264
+ Tcl_SetChannelOption(interp, ch1, "-translation", "lf");
+#endif
+ Tcl_SetChannelOption(interp, ch2, "-buffering", "line");
+#ifdef WIN3264
+ Tcl_SetChannelOption(interp, ch2, "-translation", "lf");
+#endif
+
+ /* replace standard Tcl exit command */
+ Tcl_DeleteCommand(interp, "exit");
+ Tcl_CreateObjCommand(interp, "exit", exitcmd,
+ (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
+
+ /* new commands, in ::vim namespace */
+ Tcl_CreateObjCommand(interp, "::vim::buffer", buffercmd,
+ (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
+ Tcl_CreateObjCommand(interp, "::vim::window", windowcmd,
+ (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
+ Tcl_CreateObjCommand(interp, "::vim::command", commandcmd,
+ (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
+ Tcl_CreateObjCommand(interp, "::vim::beep", beepcmd,
+ (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
+ Tcl_CreateObjCommand(interp, "::vim::option", optioncmd,
+ (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
+ Tcl_CreateObjCommand(interp, "::vim::expr", exprcmd,
+ (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
+
+ /* "lbase" variable */
+ tclinfo.lbase = 1;
+ strcpy(varname, VAR_LBASE);
+ Tcl_LinkVar(interp, varname, (char *)&tclinfo.lbase, TCL_LINK_INT);
+
+ /* "range" variable */
+ tclinfo.range_start = eap->line1;
+ strcpy(varname, VAR_RANGE1);
+ Tcl_LinkVar(interp, varname, (char *)&tclinfo.range_start, TCL_LINK_INT|TCL_LINK_READ_ONLY);
+ strcpy(varname, VAR_RANGE2);
+ Tcl_LinkVar(interp, varname, (char *)&tclinfo.range_start, TCL_LINK_INT|TCL_LINK_READ_ONLY);
+ tclinfo.range_end = eap->line2;
+ strcpy(varname, VAR_RANGE3);
+ Tcl_LinkVar(interp, varname, (char *)&tclinfo.range_end, TCL_LINK_INT|TCL_LINK_READ_ONLY);
+
+ /* "current" variable */
+ tclinfo.curbuf = Tcl_Alloc(VARNAME_SIZE);
+ tclinfo.curwin = Tcl_Alloc(VARNAME_SIZE);
+ name = tclgetbuffer(interp, curbuf);
+ strcpy(tclinfo.curbuf, name);
+ strcpy(varname, VAR_CURBUF);
+ Tcl_LinkVar(interp, varname, (char *)&tclinfo.curbuf, TCL_LINK_STRING|TCL_LINK_READ_ONLY);
+ name = tclgetwindow(interp, curwin);
+ strcpy(tclinfo.curwin, name);
+ strcpy(varname, VAR_CURWIN);
+ Tcl_LinkVar(interp, varname, (char *)&tclinfo.curwin, TCL_LINK_STRING|TCL_LINK_READ_ONLY);
+
+ tclinfo.interp = interp;
+ }
+ else
+ {
+ /* Interpreter already exists, just update variables */
+ tclinfo.range_start = row2tcl(eap->line1);
+ tclinfo.range_end = row2tcl(eap->line2);
+ tclupdatevars();
+ }
+
+ tclinfo.exitvalue = 0;
+ return OK;
+}
+
+ static void
+tclerrmsg(char *text)
+{
+ char *next;
+
+ while ((next=strchr(text, '\n')))
+ {
+ *next++ = '\0';
+ emsg(text);
+ text = next;
+ }
+ if (*text)
+ emsg(text);
+}
+
+ static void
+tclmsg(char *text)
+{
+ char *next;
+
+ while ((next=strchr(text, '\n')))
+ {
+ *next++ = '\0';
+ msg(text);
+ text = next;
+ }
+ if (*text)
+ msg(text);
+}
+
+ static void
+tcldelthisinterp(void)
+{
+ if (!Tcl_InterpDeleted(tclinfo.interp))
+ Tcl_DeleteInterp(tclinfo.interp);
+ Tcl_Release(tclinfo.interp);
+ /* The interpreter is now gets deleted. All registered commands (esp.
+ * window and buffer commands) are deleted, triggering their deletion
+ * callback, which deletes all refs pointing to this interpreter.
+ * We could garbage-collect the unused ref structs in all windows and
+ * buffers, but unless the user creates hundreds of sub-interpreters
+ * all referring to lots of windows and buffers, this is hardly worth
+ * the effort. Unused refs are recycled by other interpreters, and
+ * all refs are free'd when the window/buffer gets closed by vim.
+ */
+
+ tclinfo.interp = NULL;
+ Tcl_Free(tclinfo.curbuf);
+ Tcl_Free(tclinfo.curwin);
+ tclinfo.curbuf = tclinfo.curwin = NULL;
+}
+
+ static int
+tclexit(int error)
+{
+ int newerr = OK;
+
+ if (Tcl_InterpDeleted(tclinfo.interp) /* True if we intercepted Tcl's exit command */
+#if (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION >= 5) || TCL_MAJOR_VERSION > 8
+ || Tcl_LimitExceeded(tclinfo.interp) /* True if the interpreter cannot continue */
+#endif
+ )
+ {
+ char buf[50];
+
+ sprintf(buf, _("E572: exit code %d"), tclinfo.exitvalue);
+ tclerrmsg(buf);
+ if (tclinfo.exitvalue == 0)
+ {
+ did_emsg = 0;
+ newerr = OK;
+ }
+ else
+ newerr = FAIL;
+
+ tcldelthisinterp();
+ }
+ else
+ {
+ char *result;
+
+ result = (char *)Tcl_GetStringResult(tclinfo.interp);
+ if (error == TCL_OK)
+ {
+ tclmsg(result);
+ newerr = OK;
+ }
+ else
+ {
+ tclerrmsg(result);
+ newerr = FAIL;
+ }
+ }
+
+ return newerr;
+}
+
+/*
+ * ":tcl"
+ */
+ void
+ex_tcl(exarg_T *eap)
+{
+ char_u *script;
+ int err;
+
+ script = script_get(eap, eap->arg);
+ if (!eap->skip)
+ {
+ err = tclinit(eap);
+ if (err == OK)
+ {
+ Tcl_AllowExceptions(tclinfo.interp);
+ if (script == NULL)
+ err = Tcl_Eval(tclinfo.interp, (char *)eap->arg);
+ else
+ err = Tcl_Eval(tclinfo.interp, (char *)script);
+ err = tclexit(err);
+ }
+ }
+ vim_free(script);
+}
+
+/*
+ * ":tclfile"
+ */
+ void
+ex_tclfile(exarg_T *eap)
+{
+ char *file = (char *)eap->arg;
+ int err;
+
+ err = tclinit(eap);
+ if (err == OK)
+ {
+ Tcl_AllowExceptions(tclinfo.interp);
+ err = Tcl_EvalFile(tclinfo.interp, file);
+ err = tclexit(err);
+ }
+}
+
+/*
+ * ":tcldo"
+ */
+ void
+ex_tcldo(exarg_T *eap)
+{
+ char *script, *line;
+ int err, rs, re, lnum;
+ char var_lnum[VARNAME_SIZE]; /* must be writeable memory */
+ char var_line[VARNAME_SIZE];
+ linenr_T first_line = 0;
+ linenr_T last_line = 0;
+ buf_T *was_curbuf = curbuf;
+
+ rs = eap->line1;
+ re = eap->line2;
+ script = (char *)eap->arg;
+ strcpy(var_lnum, VAR_CURLNUM);
+ strcpy(var_line, VAR_CURLINE);
+
+ err = tclinit(eap);
+ if (err != OK)
+ return;
+
+ lnum = row2tcl(rs);
+ Tcl_LinkVar(tclinfo.interp, var_lnum, (char *)&lnum, TCL_LINK_INT|TCL_LINK_READ_ONLY);
+ err = TCL_OK;
+ if (u_save((linenr_T)(rs-1), (linenr_T)(re+1)) != OK)
+ {
+ Tcl_SetResult(tclinfo.interp, _("cannot save undo information"), TCL_STATIC);
+ err = TCL_ERROR;
+ }
+ while (err == TCL_OK && rs <= re)
+ {
+ if ((linenr_T)rs > curbuf->b_ml.ml_line_count)
+ break;
+ line = (char *)ml_get_buf(curbuf, (linenr_T)rs, FALSE);
+ if (!line)
+ {
+ Tcl_SetResult(tclinfo.interp, _("cannot get line"), TCL_STATIC);
+ err = TCL_ERROR;
+ break;
+ }
+ Tcl_SetVar(tclinfo.interp, var_line, line, 0);
+ Tcl_AllowExceptions(tclinfo.interp);
+ err = Tcl_Eval(tclinfo.interp, script);
+ if (err != TCL_OK
+ || Tcl_InterpDeleted(tclinfo.interp)
+#if (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION >= 5) || TCL_MAJOR_VERSION > 8
+ || Tcl_LimitExceeded(tclinfo.interp)
+#endif
+ || curbuf != was_curbuf)
+ break;
+ line = (char *)Tcl_GetVar(tclinfo.interp, var_line, 0);
+ if (line)
+ {
+ if (ml_replace((linenr_T)rs, (char_u *)line, TRUE) != OK)
+ {
+ Tcl_SetResult(tclinfo.interp, _("cannot replace line"), TCL_STATIC);
+ err = TCL_ERROR;
+ break;
+ }
+ if (first_line == 0)
+ first_line = rs;
+ last_line = rs;
+ }
+ ++rs;
+ ++lnum;
+ Tcl_UpdateLinkedVar(tclinfo.interp, var_lnum);
+ }
+ if (first_line)
+ changed_lines(first_line, 0, last_line + 1, (long)0);
+
+ Tcl_UnsetVar(tclinfo.interp, var_line, 0);
+ Tcl_UnlinkVar(tclinfo.interp, var_lnum);
+ if (err == TCL_OK)
+ Tcl_ResetResult(tclinfo.interp);
+
+ (void)tclexit(err);
+}
+
+ static void
+tcldelallrefs(struct ref *ref)
+{
+ struct ref *next;
+ int err;
+ char *result;
+
+#ifdef DYNAMIC_TCL
+ /* TODO: this code currently crashes Vim on exit */
+ if (exiting)
+ return;
+#endif
+
+ while (ref != NULL)
+ {
+ next = ref->next;
+ if (ref->interp)
+ {
+ if (ref->delcmd)
+ {
+ err = Tcl_GlobalEvalObj(ref->interp, ref->delcmd);
+ if (err != TCL_OK)
+ {
+ result = (char *)Tcl_GetStringResult(ref->interp);
+ if (result)
+ tclerrmsg(result);
+ }
+ Tcl_DecrRefCount(ref->delcmd);
+ ref->delcmd = NULL;
+ }
+ Tcl_DeleteCommandFromToken(ref->interp, ref->cmd);
+ }
+ Tcl_Free((char *)ref);
+ ref = next;
+ }
+}
+
+ void
+tcl_buffer_free(buf_T *buf)
+{
+ struct ref *reflist;
+
+#ifdef DYNAMIC_TCL
+ if (!stubs_initialized) /* Not using Tcl, nothing to do. */
+ return;
+#endif
+
+ reflist = (struct ref *)(buf->b_tcl_ref);
+ if (reflist != &refsdeleted)
+ {
+ buf->b_tcl_ref = (void *)&refsdeleted;
+ tcldelallrefs(reflist);
+ buf->b_tcl_ref = NULL;
+ }
+}
+
+ void
+tcl_window_free(win_T *win)
+{
+ struct ref *reflist;
+
+#ifdef DYNAMIC_TCL
+ if (!stubs_initialized) /* Not using Tcl, nothing to do. */
+ return;
+#endif
+
+ reflist = (struct ref*)(win->w_tcl_ref);
+ if (reflist != &refsdeleted)
+ {
+ win->w_tcl_ref = (void *)&refsdeleted;
+ tcldelallrefs(reflist);
+ win->w_tcl_ref = NULL;
+ }
+}
+
+/* The End */
diff --git a/src/if_xcmdsrv.c b/src/if_xcmdsrv.c
new file mode 100644
index 0000000..430548e
--- /dev/null
+++ b/src/if_xcmdsrv.c
@@ -0,0 +1,1527 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ * X command server by Flemming Madsen
+ *
+ * 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.
+ *
+ * if_xcmdsrv.c: Functions for passing commands through an X11 display.
+ *
+ */
+
+#include "vim.h"
+#include "version.h"
+
+#if defined(FEAT_CLIENTSERVER) || defined(PROTO)
+
+# ifdef FEAT_X11
+# include <X11/Intrinsic.h>
+# include <X11/Xatom.h>
+# endif
+
+/*
+ * This file provides procedures that implement the command server
+ * functionality of Vim when in contact with an X11 server.
+ *
+ * Adapted from TCL/TK's send command in tkSend.c of the tk 3.6 distribution.
+ * Adapted for use in Vim by Flemming Madsen. Protocol changed to that of tk 4
+ */
+
+/*
+ * Copyright (c) 1989-1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+
+/*
+ * When a result is being awaited from a sent command, one of
+ * the following structures is present on a list of all outstanding
+ * sent commands. The information in the structure is used to
+ * process the result when it arrives. You're probably wondering
+ * how there could ever be multiple outstanding sent commands.
+ * This could happen if Vim instances invoke each other recursively.
+ * It's unlikely, but possible.
+ */
+
+typedef struct PendingCommand
+{
+ int serial; /* Serial number expected in result. */
+ int code; /* Result Code. 0 is OK */
+ char_u *result; /* String result for command (malloc'ed).
+ * NULL means command still pending. */
+ struct PendingCommand *nextPtr;
+ /* Next in list of all outstanding commands.
+ * NULL means end of list. */
+} PendingCommand;
+
+static PendingCommand *pendingCommands = NULL;
+ /* List of all commands currently
+ * being waited for. */
+
+/*
+ * The information below is used for communication between processes
+ * during "send" commands. Each process keeps a private window, never
+ * even mapped, with one property, "Comm". When a command is sent to
+ * an interpreter, the command is appended to the comm property of the
+ * communication window associated with the interp's process. Similarly,
+ * when a result is returned from a sent command, it is also appended
+ * to the comm property.
+ *
+ * Each command and each result takes the form of ASCII text. For a
+ * command, the text consists of a nul character followed by several
+ * nul-terminated ASCII strings. The first string consists of a
+ * single letter:
+ * "c" for an expression
+ * "k" for keystrokes
+ * "r" for reply
+ * "n" for notification.
+ * Subsequent strings have the form "option value" where the following options
+ * are supported:
+ *
+ * -r commWindow serial
+ *
+ * This option means that a response should be sent to the window
+ * whose X identifier is "commWindow" (in hex), and the response should
+ * be identified with the serial number given by "serial" (in decimal).
+ * If this option isn't specified then the send is asynchronous and
+ * no response is sent.
+ *
+ * -n name
+ * "Name" gives the name of the application for which the command is
+ * intended. This option must be present.
+ *
+ * -E encoding
+ * Encoding name used for the text. This is the 'encoding' of the
+ * sender. The receiver may want to do conversion to his 'encoding'.
+ *
+ * -s script
+ * "Script" is the script to be executed. This option must be
+ * present. Taken as a series of keystrokes in a "k" command where
+ * <Key>'s are expanded
+ *
+ * The options may appear in any order. The -n and -s options must be
+ * present, but -r may be omitted for asynchronous RPCs. For compatibility
+ * with future releases that may add new features, there may be additional
+ * options present; as long as they start with a "-" character, they will
+ * be ignored.
+ *
+ * A result also consists of a zero character followed by several null-
+ * terminated ASCII strings. The first string consists of the single
+ * letter "r". Subsequent strings have the form "option value" where
+ * the following options are supported:
+ *
+ * -s serial
+ * Identifies the command for which this is the result. It is the
+ * same as the "serial" field from the -s option in the command. This
+ * option must be present.
+ *
+ * -r result
+ * "Result" is the result string for the script, which may be either
+ * a result or an error message. If this field is omitted then it
+ * defaults to an empty string.
+ *
+ * -c code
+ * 0: for OK. This is the default.
+ * 1: for error: Result is the last error
+ *
+ * -i errorInfo
+ * -e errorCode
+ * Not applicable for Vim
+ *
+ * Options may appear in any order, and only the -s option must be
+ * present. As with commands, there may be additional options besides
+ * these; unknown options are ignored.
+ */
+
+/*
+ * Maximum size property that can be read at one time by
+ * this module:
+ */
+
+#define MAX_PROP_WORDS 100000
+
+struct ServerReply
+{
+ Window id;
+ garray_T strings;
+};
+static garray_T serverReply = { 0, 0, 0, 0, 0 };
+enum ServerReplyOp { SROP_Find, SROP_Add, SROP_Delete };
+
+typedef int (*EndCond)(void *);
+
+struct x_cmdqueue
+{
+ char_u *propInfo;
+ long_u len;
+ struct x_cmdqueue *next;
+ struct x_cmdqueue *prev;
+};
+
+typedef struct x_cmdqueue x_queue_T;
+
+/* dummy node, header for circular queue */
+static x_queue_T head = {NULL, 0, NULL, NULL};
+
+/*
+ * Forward declarations for procedures defined later in this file:
+ */
+
+static Window LookupName(Display *dpy, char_u *name, int delete, char_u **loose);
+static int SendInit(Display *dpy);
+static int DoRegisterName(Display *dpy, char_u *name);
+static void DeleteAnyLingerer(Display *dpy, Window w);
+static int GetRegProp(Display *dpy, char_u **regPropp, long_u *numItemsp, int domsg);
+static int WaitForPend(void *p);
+static int WindowValid(Display *dpy, Window w);
+static void ServerWait(Display *dpy, Window w, EndCond endCond, void *endData, int localLoop, int seconds);
+static int AppendPropCarefully(Display *display, Window window, Atom property, char_u *value, int length);
+static int x_error_check(Display *dpy, XErrorEvent *error_event);
+static int IsSerialName(char_u *name);
+static void save_in_queue(char_u *buf, long_u len);
+static void server_parse_message(Display *dpy, char_u *propInfo, long_u numItems);
+
+/* Private variables for the "server" functionality */
+static Atom registryProperty = None;
+static Atom vimProperty = None;
+static int got_x_error = FALSE;
+
+static char_u *empty_prop = (char_u *)""; /* empty GetRegProp() result */
+
+/*
+ * Associate an ASCII name with Vim. Try real hard to get a unique one.
+ * Returns FAIL or OK.
+ */
+ int
+serverRegisterName(
+ Display *dpy, /* display to register with */
+ char_u *name) /* the name that will be used as a base */
+{
+ int i;
+ int res;
+ char_u *p = NULL;
+
+ res = DoRegisterName(dpy, name);
+ if (res < 0)
+ {
+ i = 1;
+ do
+ {
+ if (res < -1 || i >= 1000)
+ {
+ msg_attr(_("Unable to register a command server name"),
+ HL_ATTR(HLF_W));
+ return FAIL;
+ }
+ if (p == NULL)
+ p = alloc(STRLEN(name) + 10);
+ if (p == NULL)
+ {
+ res = -10;
+ continue;
+ }
+ sprintf((char *)p, "%s%d", name, i++);
+ res = DoRegisterName(dpy, p);
+ }
+ while (res < 0)
+ ;
+ vim_free(p);
+ }
+ return OK;
+}
+
+ static int
+DoRegisterName(Display *dpy, char_u *name)
+{
+ Window w;
+ XErrorHandler old_handler;
+#define MAX_NAME_LENGTH 100
+ char_u propInfo[MAX_NAME_LENGTH + 20];
+
+ if (commProperty == None)
+ {
+ if (SendInit(dpy) < 0)
+ return -2;
+ }
+
+ /*
+ * Make sure the name is unique, and append info about it to
+ * the registry property. It's important to lock the server
+ * here to prevent conflicting changes to the registry property.
+ * WARNING: Do not step through this while debugging, it will hangup the X
+ * server!
+ */
+ XGrabServer(dpy);
+ w = LookupName(dpy, name, FALSE, NULL);
+ if (w != (Window)0)
+ {
+ Status status;
+ int dummyInt;
+ unsigned int dummyUns;
+ Window dummyWin;
+
+ /*
+ * The name is currently registered. See if the commWindow
+ * associated with the name exists. If not, or if the commWindow
+ * is *our* commWindow, then just unregister the old name (this
+ * could happen if an application dies without cleaning up the
+ * registry).
+ */
+ old_handler = XSetErrorHandler(x_error_check);
+ status = XGetGeometry(dpy, w, &dummyWin, &dummyInt, &dummyInt,
+ &dummyUns, &dummyUns, &dummyUns, &dummyUns);
+ (void)XSetErrorHandler(old_handler);
+ if (status != Success && w != commWindow)
+ {
+ XUngrabServer(dpy);
+ XFlush(dpy);
+ return -1;
+ }
+ (void)LookupName(dpy, name, /*delete=*/TRUE, NULL);
+ }
+ sprintf((char *)propInfo, "%x %.*s", (int_u)commWindow,
+ MAX_NAME_LENGTH, name);
+ old_handler = XSetErrorHandler(x_error_check);
+ got_x_error = FALSE;
+ XChangeProperty(dpy, RootWindow(dpy, 0), registryProperty, XA_STRING, 8,
+ PropModeAppend, propInfo, STRLEN(propInfo) + 1);
+ XUngrabServer(dpy);
+ XSync(dpy, False);
+ (void)XSetErrorHandler(old_handler);
+
+ if (!got_x_error)
+ {
+#ifdef FEAT_EVAL
+ set_vim_var_string(VV_SEND_SERVER, name, -1);
+#endif
+ serverName = vim_strsave(name);
+#ifdef FEAT_TITLE
+ need_maketitle = TRUE;
+#endif
+ return 0;
+ }
+ return -2;
+}
+
+#if defined(FEAT_GUI) || defined(PROTO)
+/*
+ * Clean out new ID from registry and set it as comm win.
+ * Change any registered window ID.
+ */
+ void
+serverChangeRegisteredWindow(
+ Display *dpy, /* Display to register with */
+ Window newwin) /* Re-register to this ID */
+{
+ char_u propInfo[MAX_NAME_LENGTH + 20];
+
+ commWindow = newwin;
+
+ /* Always call SendInit() here, to make sure commWindow is marked as a Vim
+ * window. */
+ if (SendInit(dpy) < 0)
+ return;
+
+ /* WARNING: Do not step through this while debugging, it will hangup the X
+ * server! */
+ XGrabServer(dpy);
+ DeleteAnyLingerer(dpy, newwin);
+ if (serverName != NULL)
+ {
+ /* Reinsert name if we was already registered */
+ (void)LookupName(dpy, serverName, /*delete=*/TRUE, NULL);
+ sprintf((char *)propInfo, "%x %.*s",
+ (int_u)newwin, MAX_NAME_LENGTH, serverName);
+ XChangeProperty(dpy, RootWindow(dpy, 0), registryProperty, XA_STRING, 8,
+ PropModeAppend, (char_u *)propInfo,
+ STRLEN(propInfo) + 1);
+ }
+ XUngrabServer(dpy);
+}
+#endif
+
+/*
+ * Send to an instance of Vim via the X display.
+ * Returns 0 for OK, negative for an error.
+ */
+ int
+serverSendToVim(
+ Display *dpy, /* Where to send. */
+ char_u *name, /* Where to send. */
+ char_u *cmd, /* What to send. */
+ char_u **result, /* Result of eval'ed expression */
+ Window *server, /* Actual ID of receiving app */
+ Bool asExpr, /* Interpret as keystrokes or expr ? */
+ int timeout, /* seconds to wait or zero */
+ Bool localLoop, /* Throw away everything but result */
+ int silent) /* don't complain about no server */
+{
+ Window w;
+ char_u *property;
+ int length;
+ int res;
+ static int serial = 0; /* Running count of sent commands.
+ * Used to give each command a
+ * different serial number. */
+ PendingCommand pending;
+ char_u *loosename = NULL;
+
+ if (result != NULL)
+ *result = NULL;
+ if (name == NULL || *name == NUL)
+ name = (char_u *)"GVIM"; /* use a default name */
+
+ if (commProperty == None && dpy != NULL)
+ {
+ if (SendInit(dpy) < 0)
+ return -1;
+ }
+
+ /* Execute locally if no display or target is ourselves */
+ if (dpy == NULL || (serverName != NULL && STRICMP(name, serverName) == 0))
+ return sendToLocalVim(cmd, asExpr, result);
+
+ /*
+ * Bind the server name to a communication window.
+ *
+ * Find any survivor with a serialno attached to the name if the
+ * original registrant of the wanted name is no longer present.
+ *
+ * Delete any lingering names from dead editors.
+ */
+ while (TRUE)
+ {
+ w = LookupName(dpy, name, FALSE, &loosename);
+ /* Check that the window is hot */
+ if (w != None)
+ {
+ if (!WindowValid(dpy, w))
+ {
+ LookupName(dpy, loosename ? loosename : name,
+ /*DELETE=*/TRUE, NULL);
+ vim_free(loosename);
+ continue;
+ }
+ }
+ break;
+ }
+ if (w == None)
+ {
+ if (!silent)
+ semsg(_(e_noserver), name);
+ return -1;
+ }
+ else if (loosename != NULL)
+ name = loosename;
+ if (server != NULL)
+ *server = w;
+
+ /*
+ * Send the command to target interpreter by appending it to the
+ * comm window in the communication window.
+ * Length must be computed exactly!
+ */
+ length = STRLEN(name) + STRLEN(p_enc) + STRLEN(cmd) + 14;
+ property = (char_u *)alloc((unsigned)length + 30);
+
+ sprintf((char *)property, "%c%c%c-n %s%c-E %s%c-s %s",
+ 0, asExpr ? 'c' : 'k', 0, name, 0, p_enc, 0, cmd);
+ if (name == loosename)
+ vim_free(loosename);
+ /* Add a back reference to our comm window */
+ serial++;
+ sprintf((char *)property + length, "%c-r %x %d",
+ 0, (int_u)commWindow, serial);
+ /* Add length of what "-r %x %d" resulted in, skipping the NUL. */
+ length += STRLEN(property + length + 1) + 1;
+
+ res = AppendPropCarefully(dpy, w, commProperty, property, length + 1);
+ vim_free(property);
+ if (res < 0)
+ {
+ emsg(_("E248: Failed to send command to the destination program"));
+ return -1;
+ }
+
+ if (!asExpr) /* There is no answer for this - Keys are sent async */
+ return 0;
+
+ /*
+ * Register the fact that we're waiting for a command to
+ * complete (this is needed by SendEventProc and by
+ * AppendErrorProc to pass back the command's results).
+ */
+ pending.serial = serial;
+ pending.code = 0;
+ pending.result = NULL;
+ pending.nextPtr = pendingCommands;
+ pendingCommands = &pending;
+
+ ServerWait(dpy, w, WaitForPend, &pending, localLoop,
+ timeout > 0 ? timeout : 600);
+
+ /*
+ * Unregister the information about the pending command
+ * and return the result.
+ */
+ if (pendingCommands == &pending)
+ pendingCommands = pending.nextPtr;
+ else
+ {
+ PendingCommand *pcPtr;
+
+ for (pcPtr = pendingCommands; pcPtr != NULL; pcPtr = pcPtr->nextPtr)
+ if (pcPtr->nextPtr == &pending)
+ {
+ pcPtr->nextPtr = pending.nextPtr;
+ break;
+ }
+ }
+ if (result != NULL)
+ *result = pending.result;
+ else
+ vim_free(pending.result);
+
+ return pending.code == 0 ? 0 : -1;
+}
+
+ static int
+WaitForPend(void *p)
+{
+ PendingCommand *pending = (PendingCommand *) p;
+ return pending->result != NULL;
+}
+
+/*
+ * Return TRUE if window "w" exists and has a "Vim" property on it.
+ */
+ static int
+WindowValid(Display *dpy, Window w)
+{
+ XErrorHandler old_handler;
+ Atom *plist;
+ int numProp;
+ int i;
+
+ old_handler = XSetErrorHandler(x_error_check);
+ got_x_error = 0;
+ plist = XListProperties(dpy, w, &numProp);
+ XSync(dpy, False);
+ XSetErrorHandler(old_handler);
+ if (plist == NULL || got_x_error)
+ return FALSE;
+
+ for (i = 0; i < numProp; i++)
+ if (plist[i] == vimProperty)
+ {
+ XFree(plist);
+ return TRUE;
+ }
+ XFree(plist);
+ return FALSE;
+}
+
+/*
+ * Enter a loop processing X events & polling chars until we see a result
+ */
+ static void
+ServerWait(
+ Display *dpy,
+ Window w,
+ EndCond endCond,
+ void *endData,
+ int localLoop,
+ int seconds)
+{
+ time_t start;
+ time_t now;
+ XEvent event;
+
+#define UI_MSEC_DELAY 50
+#define SEND_MSEC_POLL 500
+#ifndef HAVE_SELECT
+ struct pollfd fds;
+
+ fds.fd = ConnectionNumber(dpy);
+ fds.events = POLLIN;
+#else
+ fd_set fds;
+ struct timeval tv;
+
+ tv.tv_sec = 0;
+ tv.tv_usec = SEND_MSEC_POLL * 1000;
+ FD_ZERO(&fds);
+ FD_SET(ConnectionNumber(dpy), &fds);
+#endif
+
+ time(&start);
+ while (TRUE)
+ {
+ while (XCheckWindowEvent(dpy, commWindow, PropertyChangeMask, &event))
+ serverEventProc(dpy, &event, 1);
+ server_parse_messages();
+
+ if (endCond(endData) != 0)
+ break;
+ if (!WindowValid(dpy, w))
+ break;
+ time(&now);
+ if (seconds >= 0 && (now - start) >= seconds)
+ break;
+
+#ifdef FEAT_TIMERS
+ check_due_timer();
+#endif
+
+ /* Just look out for the answer without calling back into Vim */
+ if (localLoop)
+ {
+#ifndef HAVE_SELECT
+ if (poll(&fds, 1, SEND_MSEC_POLL) < 0)
+ break;
+#else
+ if (select(FD_SETSIZE, &fds, NULL, NULL, &tv) < 0)
+ break;
+#endif
+ }
+ else
+ {
+ if (got_int)
+ break;
+ ui_delay((long)UI_MSEC_DELAY, TRUE);
+ ui_breakcheck();
+ }
+ }
+}
+
+
+/*
+ * Fetch a list of all the Vim instance names currently registered for the
+ * display.
+ *
+ * Returns a newline separated list in allocated memory or NULL.
+ */
+ char_u *
+serverGetVimNames(Display *dpy)
+{
+ char_u *regProp;
+ char_u *entry;
+ char_u *p;
+ long_u numItems;
+ int_u w;
+ garray_T ga;
+
+ if (registryProperty == None)
+ {
+ if (SendInit(dpy) < 0)
+ return NULL;
+ }
+
+ /*
+ * Read the registry property.
+ */
+ if (GetRegProp(dpy, &regProp, &numItems, TRUE) == FAIL)
+ return NULL;
+
+ /*
+ * Scan all of the names out of the property.
+ */
+ ga_init2(&ga, 1, 100);
+ for (p = regProp; (long_u)(p - regProp) < numItems; p++)
+ {
+ entry = p;
+ while (*p != 0 && !isspace(*p))
+ p++;
+ if (*p != 0)
+ {
+ w = None;
+ sscanf((char *)entry, "%x", &w);
+ if (WindowValid(dpy, (Window)w))
+ {
+ ga_concat(&ga, p + 1);
+ ga_concat(&ga, (char_u *)"\n");
+ }
+ while (*p != 0)
+ p++;
+ }
+ }
+ if (regProp != empty_prop)
+ XFree(regProp);
+ ga_append(&ga, NUL);
+ return ga.ga_data;
+}
+
+/* ----------------------------------------------------------
+ * Reply stuff
+ */
+
+ static struct ServerReply *
+ServerReplyFind(Window w, enum ServerReplyOp op)
+{
+ struct ServerReply *p;
+ struct ServerReply e;
+ int i;
+
+ p = (struct ServerReply *) serverReply.ga_data;
+ for (i = 0; i < serverReply.ga_len; i++, p++)
+ if (p->id == w)
+ break;
+ if (i >= serverReply.ga_len)
+ p = NULL;
+
+ if (p == NULL && op == SROP_Add)
+ {
+ if (serverReply.ga_growsize == 0)
+ ga_init2(&serverReply, sizeof(struct ServerReply), 1);
+ if (ga_grow(&serverReply, 1) == OK)
+ {
+ p = ((struct ServerReply *) serverReply.ga_data)
+ + serverReply.ga_len;
+ e.id = w;
+ ga_init2(&e.strings, 1, 100);
+ mch_memmove(p, &e, sizeof(e));
+ serverReply.ga_len++;
+ }
+ }
+ else if (p != NULL && op == SROP_Delete)
+ {
+ ga_clear(&p->strings);
+ mch_memmove(p, p + 1, (serverReply.ga_len - i - 1) * sizeof(*p));
+ serverReply.ga_len--;
+ }
+
+ return p;
+}
+
+/*
+ * Convert string to windowid.
+ * Issue an error if the id is invalid.
+ */
+ Window
+serverStrToWin(char_u *str)
+{
+ unsigned id = None;
+
+ sscanf((char *)str, "0x%x", &id);
+ if (id == None)
+ semsg(_("E573: Invalid server id used: %s"), str);
+
+ return (Window)id;
+}
+
+/*
+ * Send a reply string (notification) to client with id "name".
+ * Return -1 if the window is invalid.
+ */
+ int
+serverSendReply(char_u *name, char_u *str)
+{
+ char_u *property;
+ int length;
+ int res;
+ Display *dpy = X_DISPLAY;
+ Window win = serverStrToWin(name);
+
+ if (commProperty == None)
+ {
+ if (SendInit(dpy) < 0)
+ return -2;
+ }
+ if (!WindowValid(dpy, win))
+ return -1;
+
+ length = STRLEN(p_enc) + STRLEN(str) + 14;
+ if ((property = (char_u *)alloc((unsigned)length + 30)) != NULL)
+ {
+ sprintf((char *)property, "%cn%c-E %s%c-n %s%c-w %x",
+ 0, 0, p_enc, 0, str, 0, (unsigned int)commWindow);
+ /* Add length of what "%x" resulted in. */
+ length += STRLEN(property + length);
+ res = AppendPropCarefully(dpy, win, commProperty, property, length + 1);
+ vim_free(property);
+ return res;
+ }
+ return -1;
+}
+
+ static int
+WaitForReply(void *p)
+{
+ Window *w = (Window *) p;
+
+ return ServerReplyFind(*w, SROP_Find) != NULL;
+}
+
+/*
+ * Wait for replies from id (win)
+ * When "timeout" is non-zero wait up to this many seconds.
+ * Return 0 and the malloc'ed string when a reply is available.
+ * Return -1 if the window becomes invalid while waiting.
+ */
+ int
+serverReadReply(
+ Display *dpy,
+ Window win,
+ char_u **str,
+ int localLoop,
+ int timeout)
+{
+ int len;
+ char_u *s;
+ struct ServerReply *p;
+
+ ServerWait(dpy, win, WaitForReply, &win, localLoop,
+ timeout > 0 ? timeout : -1);
+
+ if ((p = ServerReplyFind(win, SROP_Find)) != NULL && p->strings.ga_len > 0)
+ {
+ *str = vim_strsave(p->strings.ga_data);
+ len = STRLEN(*str) + 1;
+ if (len < p->strings.ga_len)
+ {
+ s = (char_u *) p->strings.ga_data;
+ mch_memmove(s, s + len, p->strings.ga_len - len);
+ p->strings.ga_len -= len;
+ }
+ else
+ {
+ /* Last string read. Remove from list */
+ ga_clear(&p->strings);
+ ServerReplyFind(win, SROP_Delete);
+ }
+ return 0;
+ }
+ return -1;
+}
+
+/*
+ * Check for replies from id (win).
+ * Return TRUE and a non-malloc'ed string if there is. Else return FALSE.
+ */
+ int
+serverPeekReply(Display *dpy, Window win, char_u **str)
+{
+ struct ServerReply *p;
+
+ if ((p = ServerReplyFind(win, SROP_Find)) != NULL && p->strings.ga_len > 0)
+ {
+ if (str != NULL)
+ *str = p->strings.ga_data;
+ return 1;
+ }
+ if (!WindowValid(dpy, win))
+ return -1;
+ return 0;
+}
+
+
+/*
+ * Initialize the communication channels for sending commands and receiving
+ * results.
+ */
+ static int
+SendInit(Display *dpy)
+{
+ XErrorHandler old_handler;
+
+ /*
+ * Create the window used for communication, and set up an
+ * event handler for it.
+ */
+ old_handler = XSetErrorHandler(x_error_check);
+ got_x_error = FALSE;
+
+ if (commProperty == None)
+ commProperty = XInternAtom(dpy, "Comm", False);
+ if (vimProperty == None)
+ vimProperty = XInternAtom(dpy, "Vim", False);
+ if (registryProperty == None)
+ registryProperty = XInternAtom(dpy, "VimRegistry", False);
+
+ if (commWindow == None)
+ {
+ commWindow = XCreateSimpleWindow(dpy, XDefaultRootWindow(dpy),
+ getpid(), 0, 10, 10, 0,
+ WhitePixel(dpy, DefaultScreen(dpy)),
+ WhitePixel(dpy, DefaultScreen(dpy)));
+ XSelectInput(dpy, commWindow, PropertyChangeMask);
+ /* WARNING: Do not step through this while debugging, it will hangup
+ * the X server! */
+ XGrabServer(dpy);
+ DeleteAnyLingerer(dpy, commWindow);
+ XUngrabServer(dpy);
+ }
+
+ /* Make window recognizable as a vim window */
+ XChangeProperty(dpy, commWindow, vimProperty, XA_STRING,
+ 8, PropModeReplace, (char_u *)VIM_VERSION_SHORT,
+ (int)STRLEN(VIM_VERSION_SHORT) + 1);
+
+ XSync(dpy, False);
+ (void)XSetErrorHandler(old_handler);
+
+ return got_x_error ? -1 : 0;
+}
+
+/*
+ * Given a server name, see if the name exists in the registry for a
+ * particular display.
+ *
+ * If the given name is registered, return the ID of the window associated
+ * with the name. If the name isn't registered, then return 0.
+ *
+ * Side effects:
+ * If the registry property is improperly formed, then it is deleted.
+ * If "delete" is non-zero, then if the named server is found it is
+ * removed from the registry property.
+ */
+ static Window
+LookupName(
+ Display *dpy, /* Display whose registry to check. */
+ char_u *name, /* Name of a server. */
+ int delete, /* If non-zero, delete info about name. */
+ char_u **loose) /* Do another search matching -999 if not found
+ Return result here if a match is found */
+{
+ char_u *regProp, *entry;
+ char_u *p;
+ long_u numItems;
+ int_u returnValue;
+
+ /*
+ * Read the registry property.
+ */
+ if (GetRegProp(dpy, &regProp, &numItems, FALSE) == FAIL)
+ return 0;
+
+ /*
+ * Scan the property for the desired name.
+ */
+ returnValue = (int_u)None;
+ entry = NULL; /* Not needed, but eliminates compiler warning. */
+ for (p = regProp; (long_u)(p - regProp) < numItems; )
+ {
+ entry = p;
+ while (*p != 0 && !isspace(*p))
+ p++;
+ if (*p != 0 && STRICMP(name, p + 1) == 0)
+ {
+ sscanf((char *)entry, "%x", &returnValue);
+ break;
+ }
+ while (*p != 0)
+ p++;
+ p++;
+ }
+
+ if (loose != NULL && returnValue == (int_u)None && !IsSerialName(name))
+ {
+ for (p = regProp; (long_u)(p - regProp) < numItems; )
+ {
+ entry = p;
+ while (*p != 0 && !isspace(*p))
+ p++;
+ if (*p != 0 && IsSerialName(p + 1)
+ && STRNICMP(name, p + 1, STRLEN(name)) == 0)
+ {
+ sscanf((char *)entry, "%x", &returnValue);
+ *loose = vim_strsave(p + 1);
+ break;
+ }
+ while (*p != 0)
+ p++;
+ p++;
+ }
+ }
+
+ /*
+ * Delete the property, if that is desired (copy down the
+ * remainder of the registry property to overlay the deleted
+ * info, then rewrite the property).
+ */
+ if (delete && returnValue != (int_u)None)
+ {
+ int count;
+
+ while (*p != 0)
+ p++;
+ p++;
+ count = numItems - (p - regProp);
+ if (count > 0)
+ mch_memmove(entry, p, count);
+ XChangeProperty(dpy, RootWindow(dpy, 0), registryProperty, XA_STRING,
+ 8, PropModeReplace, regProp,
+ (int)(numItems - (p - entry)));
+ XSync(dpy, False);
+ }
+
+ if (regProp != empty_prop)
+ XFree(regProp);
+ return (Window)returnValue;
+}
+
+/*
+ * Delete any lingering occurrence of window id. We promise that any
+ * occurrence is not ours since it is not yet put into the registry (by us)
+ *
+ * This is necessary in the following scenario:
+ * 1. There is an old windowid for an exit'ed vim in the registry
+ * 2. We get that id for our commWindow but only want to send, not register.
+ * 3. The window will mistakenly be regarded valid because of own commWindow
+ */
+ static void
+DeleteAnyLingerer(
+ Display *dpy, /* Display whose registry to check. */
+ Window win) /* Window to remove */
+{
+ char_u *regProp, *entry = NULL;
+ char_u *p;
+ long_u numItems;
+ int_u wwin;
+
+ /*
+ * Read the registry property.
+ */
+ if (GetRegProp(dpy, &regProp, &numItems, FALSE) == FAIL)
+ return;
+
+ /* Scan the property for the window id. */
+ for (p = regProp; (long_u)(p - regProp) < numItems; )
+ {
+ if (*p != 0)
+ {
+ sscanf((char *)p, "%x", &wwin);
+ if ((Window)wwin == win)
+ {
+ int lastHalf;
+
+ /* Copy down the remainder to delete entry */
+ entry = p;
+ while (*p != 0)
+ p++;
+ p++;
+ lastHalf = numItems - (p - regProp);
+ if (lastHalf > 0)
+ mch_memmove(entry, p, lastHalf);
+ numItems = (entry - regProp) + lastHalf;
+ p = entry;
+ continue;
+ }
+ }
+ while (*p != 0)
+ p++;
+ p++;
+ }
+
+ if (entry != NULL)
+ {
+ XChangeProperty(dpy, RootWindow(dpy, 0), registryProperty,
+ XA_STRING, 8, PropModeReplace, regProp,
+ (int)(p - regProp));
+ XSync(dpy, False);
+ }
+
+ if (regProp != empty_prop)
+ XFree(regProp);
+}
+
+/*
+ * Read the registry property. Delete it when it's formatted wrong.
+ * Return the property in "regPropp". "empty_prop" is used when it doesn't
+ * exist yet.
+ * Return OK when successful.
+ */
+ static int
+GetRegProp(
+ Display *dpy,
+ char_u **regPropp,
+ long_u *numItemsp,
+ int domsg) /* When TRUE give error message. */
+{
+ int result, actualFormat;
+ long_u bytesAfter;
+ Atom actualType;
+ XErrorHandler old_handler;
+
+ *regPropp = NULL;
+ old_handler = XSetErrorHandler(x_error_check);
+ got_x_error = FALSE;
+
+ result = XGetWindowProperty(dpy, RootWindow(dpy, 0), registryProperty, 0L,
+ (long)MAX_PROP_WORDS, False,
+ XA_STRING, &actualType,
+ &actualFormat, numItemsp, &bytesAfter,
+ regPropp);
+
+ XSync(dpy, FALSE);
+ (void)XSetErrorHandler(old_handler);
+ if (got_x_error)
+ return FAIL;
+
+ if (actualType == None)
+ {
+ /* No prop yet. Logically equal to the empty list */
+ *numItemsp = 0;
+ *regPropp = empty_prop;
+ return OK;
+ }
+
+ /* If the property is improperly formed, then delete it. */
+ if (result != Success || actualFormat != 8 || actualType != XA_STRING)
+ {
+ if (*regPropp != NULL)
+ XFree(*regPropp);
+ XDeleteProperty(dpy, RootWindow(dpy, 0), registryProperty);
+ if (domsg)
+ emsg(_("E251: VIM instance registry property is badly formed. Deleted!"));
+ return FAIL;
+ }
+ return OK;
+}
+
+
+/*
+ * This procedure is invoked by the various X event loops throughout Vims when
+ * a property changes on the communication window. This procedure reads the
+ * property and enqueues command requests and responses. If immediate is true,
+ * it runs the event immediately instead of enqueuing it. Immediate can cause
+ * unintended behavior and should only be used for code that blocks for a
+ * response.
+ */
+ void
+serverEventProc(
+ Display *dpy,
+ XEvent *eventPtr, /* Information about event. */
+ int immediate) /* Run event immediately. Should mostly be 0. */
+{
+ char_u *propInfo;
+ int result, actualFormat;
+ long_u numItems, bytesAfter;
+ Atom actualType;
+
+ if (eventPtr != NULL)
+ {
+ if (eventPtr->xproperty.atom != commProperty
+ || eventPtr->xproperty.state != PropertyNewValue)
+ return;
+ }
+
+ /*
+ * Read the comm property and delete it.
+ */
+ propInfo = NULL;
+ result = XGetWindowProperty(dpy, commWindow, commProperty, 0L,
+ (long)MAX_PROP_WORDS, True,
+ XA_STRING, &actualType,
+ &actualFormat, &numItems, &bytesAfter,
+ &propInfo);
+
+ /* If the property doesn't exist or is improperly formed then ignore it. */
+ if (result != Success || actualType != XA_STRING || actualFormat != 8)
+ {
+ if (propInfo != NULL)
+ XFree(propInfo);
+ return;
+ }
+ if (immediate)
+ server_parse_message(dpy, propInfo, numItems);
+ else
+ save_in_queue(propInfo, numItems);
+}
+
+/*
+ * Saves x clientserver commands in a queue so that they can be called when
+ * vim is idle.
+ */
+ static void
+save_in_queue(char_u *propInfo, long_u len)
+{
+ x_queue_T *node;
+
+ node = (x_queue_T *)alloc(sizeof(x_queue_T));
+ if (node == NULL)
+ return; /* out of memory */
+ node->propInfo = propInfo;
+ node->len = len;
+
+ if (head.next == NULL) /* initialize circular queue */
+ {
+ head.next = &head;
+ head.prev = &head;
+ }
+
+ /* insert node at tail of queue */
+ node->next = &head;
+ node->prev = head.prev;
+ head.prev->next = node;
+ head.prev = node;
+}
+
+/*
+ * Parses queued clientserver messages.
+ */
+ void
+server_parse_messages(void)
+{
+ x_queue_T *node;
+
+ if (!X_DISPLAY)
+ return; /* cannot happen? */
+ while (head.next != NULL && head.next != &head)
+ {
+ node = head.next;
+ head.next = node->next;
+ node->next->prev = node->prev;
+ server_parse_message(X_DISPLAY, node->propInfo, node->len);
+ vim_free(node);
+ }
+}
+
+/*
+ * Returns a non-zero value if there are clientserver messages waiting
+ * int the queue.
+ */
+ int
+server_waiting(void)
+{
+ return head.next != NULL && head.next != &head;
+}
+
+/*
+ * Prases a single clientserver message. A single message may contain multiple
+ * commands.
+ * "propInfo" will be freed.
+ */
+ static void
+server_parse_message(
+ Display *dpy,
+ char_u *propInfo, /* A string containing 0 or more X commands */
+ long_u numItems) /* The size of propInfo in bytes. */
+{
+ char_u *p;
+ int code;
+ char_u *tofree;
+
+ /*
+ * Several commands and results could arrive in the property at
+ * one time; each iteration through the outer loop handles a
+ * single command or result.
+ */
+ for (p = propInfo; (long_u)(p - propInfo) < numItems; )
+ {
+ /*
+ * Ignore leading NULs; each command or result starts with a
+ * NUL so that no matter how badly formed a preceding command
+ * is, we'll be able to tell that a new command/result is
+ * starting.
+ */
+ if (*p == 0)
+ {
+ p++;
+ continue;
+ }
+
+ if ((*p == 'c' || *p == 'k') && (p[1] == 0))
+ {
+ Window resWindow;
+ char_u *name, *script, *serial, *end;
+ Bool asKeys = *p == 'k';
+ char_u *enc;
+
+ /*
+ * This is an incoming command from some other application.
+ * Iterate over all of its options. Stop when we reach
+ * the end of the property or something that doesn't look
+ * like an option.
+ */
+ p += 2;
+ name = NULL;
+ resWindow = None;
+ serial = (char_u *)"";
+ script = NULL;
+ enc = NULL;
+ while ((long_u)(p - propInfo) < numItems && *p == '-')
+ {
+ switch (p[1])
+ {
+ case 'r':
+ end = skipwhite(p + 2);
+ resWindow = 0;
+ while (vim_isxdigit(*end))
+ {
+ resWindow = 16 * resWindow + (long_u)hex2nr(*end);
+ ++end;
+ }
+ if (end == p + 2 || *end != ' ')
+ resWindow = None;
+ else
+ {
+ p = serial = end + 1;
+ clientWindow = resWindow; /* Remember in global */
+ }
+ break;
+ case 'n':
+ if (p[2] == ' ')
+ name = p + 3;
+ break;
+ case 's':
+ if (p[2] == ' ')
+ script = p + 3;
+ break;
+ case 'E':
+ if (p[2] == ' ')
+ enc = p + 3;
+ break;
+ }
+ while (*p != 0)
+ p++;
+ p++;
+ }
+
+ if (script == NULL || name == NULL)
+ continue;
+
+ if (serverName != NULL && STRICMP(name, serverName) == 0)
+ {
+ script = serverConvert(enc, script, &tofree);
+ if (asKeys)
+ server_to_input_buf(script);
+ else
+ {
+ char_u *res;
+
+ res = eval_client_expr_to_string(script);
+ if (resWindow != None)
+ {
+ garray_T reply;
+
+ /* Initialize the result property. */
+ ga_init2(&reply, 1, 100);
+ (void)ga_grow(&reply, 50 + STRLEN(p_enc));
+ sprintf(reply.ga_data, "%cr%c-E %s%c-s %s%c-r ",
+ 0, 0, p_enc, 0, serial, 0);
+ reply.ga_len = 14 + STRLEN(p_enc) + STRLEN(serial);
+
+ /* Evaluate the expression and return the result. */
+ if (res != NULL)
+ ga_concat(&reply, res);
+ else
+ {
+ ga_concat(&reply, (char_u *)_(e_invexprmsg));
+ ga_append(&reply, 0);
+ ga_concat(&reply, (char_u *)"-c 1");
+ }
+ ga_append(&reply, NUL);
+ (void)AppendPropCarefully(dpy, resWindow, commProperty,
+ reply.ga_data, reply.ga_len);
+ ga_clear(&reply);
+ }
+ vim_free(res);
+ }
+ vim_free(tofree);
+ }
+ }
+ else if (*p == 'r' && p[1] == 0)
+ {
+ int serial, gotSerial;
+ char_u *res;
+ PendingCommand *pcPtr;
+ char_u *enc;
+
+ /*
+ * This is a reply to some command that we sent out. Iterate
+ * over all of its options. Stop when we reach the end of the
+ * property or something that doesn't look like an option.
+ */
+ p += 2;
+ gotSerial = 0;
+ res = (char_u *)"";
+ code = 0;
+ enc = NULL;
+ while ((long_u)(p - propInfo) < numItems && *p == '-')
+ {
+ switch (p[1])
+ {
+ case 'r':
+ if (p[2] == ' ')
+ res = p + 3;
+ break;
+ case 'E':
+ if (p[2] == ' ')
+ enc = p + 3;
+ break;
+ case 's':
+ if (sscanf((char *)p + 2, " %d", &serial) == 1)
+ gotSerial = 1;
+ break;
+ case 'c':
+ if (sscanf((char *)p + 2, " %d", &code) != 1)
+ code = 0;
+ break;
+ }
+ while (*p != 0)
+ p++;
+ p++;
+ }
+
+ if (!gotSerial)
+ continue;
+
+ /*
+ * Give the result information to anyone who's
+ * waiting for it.
+ */
+ for (pcPtr = pendingCommands; pcPtr != NULL; pcPtr = pcPtr->nextPtr)
+ {
+ if (serial != pcPtr->serial || pcPtr->result != NULL)
+ continue;
+
+ pcPtr->code = code;
+ res = serverConvert(enc, res, &tofree);
+ if (tofree == NULL)
+ res = vim_strsave(res);
+ pcPtr->result = res;
+ break;
+ }
+ }
+ else if (*p == 'n' && p[1] == 0)
+ {
+ Window win = 0;
+ unsigned int u;
+ int gotWindow;
+ char_u *str;
+ struct ServerReply *r;
+ char_u *enc;
+
+ /*
+ * This is a (n)otification. Sent with serverreply_send in Vim
+ * script. Execute any autocommand and save it for later retrieval
+ */
+ p += 2;
+ gotWindow = 0;
+ str = (char_u *)"";
+ enc = NULL;
+ while ((long_u)(p - propInfo) < numItems && *p == '-')
+ {
+ switch (p[1])
+ {
+ case 'n':
+ if (p[2] == ' ')
+ str = p + 3;
+ break;
+ case 'E':
+ if (p[2] == ' ')
+ enc = p + 3;
+ break;
+ case 'w':
+ if (sscanf((char *)p + 2, " %x", &u) == 1)
+ {
+ win = u;
+ gotWindow = 1;
+ }
+ break;
+ }
+ while (*p != 0)
+ p++;
+ p++;
+ }
+
+ if (!gotWindow)
+ continue;
+ str = serverConvert(enc, str, &tofree);
+ if ((r = ServerReplyFind(win, SROP_Add)) != NULL)
+ {
+ ga_concat(&(r->strings), str);
+ ga_append(&(r->strings), NUL);
+ }
+ {
+ char_u winstr[30];
+
+ sprintf((char *)winstr, "0x%x", (unsigned int)win);
+ apply_autocmds(EVENT_REMOTEREPLY, winstr, str, TRUE, curbuf);
+ }
+ vim_free(tofree);
+ }
+ else
+ {
+ /*
+ * Didn't recognize this thing. Just skip through the next
+ * null character and try again.
+ * Even if we get an 'r'(eply) we will throw it away as we
+ * never specify (and thus expect) one
+ */
+ while (*p != 0)
+ p++;
+ p++;
+ }
+ }
+ XFree(propInfo);
+}
+
+/*
+ * Append a given property to a given window, but set up an X error handler so
+ * that if the append fails this procedure can return an error code rather
+ * than having Xlib panic.
+ * Return: 0 for OK, -1 for error
+ */
+ static int
+AppendPropCarefully(
+ Display *dpy, /* Display on which to operate. */
+ Window window, /* Window whose property is to be modified. */
+ Atom property, /* Name of property. */
+ char_u *value, /* Characters to append to property. */
+ int length) /* How much to append */
+{
+ XErrorHandler old_handler;
+
+ old_handler = XSetErrorHandler(x_error_check);
+ got_x_error = FALSE;
+ XChangeProperty(dpy, window, property, XA_STRING, 8,
+ PropModeAppend, value, length);
+ XSync(dpy, False);
+ (void) XSetErrorHandler(old_handler);
+ return got_x_error ? -1 : 0;
+}
+
+
+/*
+ * Another X Error handler, just used to check for errors.
+ */
+ static int
+x_error_check(Display *dpy UNUSED, XErrorEvent *error_event UNUSED)
+{
+ got_x_error = TRUE;
+ return 0;
+}
+
+/*
+ * Check if "str" looks like it had a serial number appended.
+ * Actually just checks if the name ends in a digit.
+ */
+ static int
+IsSerialName(char_u *str)
+{
+ int len = STRLEN(str);
+
+ return (len > 1 && vim_isdigit(str[len - 1]));
+}
+#endif /* FEAT_CLIENTSERVER */
diff --git a/src/iid_ole.c b/src/iid_ole.c
new file mode 100644
index 0000000..44802d0
--- /dev/null
+++ b/src/iid_ole.c
@@ -0,0 +1,59 @@
+/* this file contains the actual definitions of */
+/* the IIDs and CLSIDs */
+
+/* link this file in with the server and any clients */
+
+
+/* File created by MIDL compiler version 3.00.44 */
+/* at Sat Jan 03 16:34:55 1998
+ */
+/* Compiler settings for if_ole.idl:
+ Os (OptLev=s), W1, Zp8, env=Win32, ms_ext, c_ext
+ error checks: none
+*/
+//@@MIDL_FILE_HEADING( )
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#ifdef __MINGW32__
+# include <w32api.h>
+
+# if __W32API_MAJOR_VERSION == 3 && __W32API_MINOR_VERSION < 10
+ /* This define is missing from older MingW versions of w32api, even though
+ * IID is defined. */
+# define __IID_DEFINED__
+# endif
+#endif
+
+#ifndef __IID_DEFINED__
+# define __IID_DEFINED__
+
+typedef struct _IID
+{
+ unsigned long x;
+ unsigned short s1;
+ unsigned short s2;
+ unsigned char c[8];
+} IID;
+
+#endif
+
+#ifndef CLSID_DEFINED
+# define CLSID_DEFINED
+typedef IID CLSID;
+#endif
+
+const IID IID_IVim = {0x0F0BFAE2,0x4C90,0x11d1,{0x82,0xD7,0x00,0x04,0xAC,0x36,0x85,0x19}};
+
+
+const IID LIBID_Vim = {0x0F0BFAE0,0x4C90,0x11d1,{0x82,0xD7,0x00,0x04,0xAC,0x36,0x85,0x19}};
+
+
+const CLSID CLSID_Vim = {0x0F0BFAE1,0x4C90,0x11d1,{0x82,0xD7,0x00,0x04,0xAC,0x36,0x85,0x19}};
+
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/src/indent.c b/src/indent.c
new file mode 100644
index 0000000..1ffa766
--- /dev/null
+++ b/src/indent.c
@@ -0,0 +1,4460 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * indent.c: Indentation related functions
+ */
+
+#include "vim.h"
+
+#if defined(FEAT_CINDENT) || defined(FEAT_SMARTINDENT)
+
+/*
+ * Return TRUE if the string "line" starts with a word from 'cinwords'.
+ */
+ int
+cin_is_cinword(char_u *line)
+{
+ char_u *cinw;
+ char_u *cinw_buf;
+ int cinw_len;
+ int retval = FALSE;
+ int len;
+
+ cinw_len = (int)STRLEN(curbuf->b_p_cinw) + 1;
+ cinw_buf = alloc((unsigned)cinw_len);
+ if (cinw_buf != NULL)
+ {
+ line = skipwhite(line);
+ for (cinw = curbuf->b_p_cinw; *cinw; )
+ {
+ len = copy_option_part(&cinw, cinw_buf, cinw_len, ",");
+ if (STRNCMP(line, cinw_buf, len) == 0
+ && (!vim_iswordc(line[len]) || !vim_iswordc(line[len - 1])))
+ {
+ retval = TRUE;
+ break;
+ }
+ }
+ vim_free(cinw_buf);
+ }
+ return retval;
+}
+#endif
+
+#if defined(FEAT_CINDENT) || defined(FEAT_SYN_HL)
+
+static char_u *skip_string(char_u *p);
+static pos_T *find_start_rawstring(int ind_maxcomment);
+
+/*
+ * Find the start of a comment, not knowing if we are in a comment right now.
+ * Search starts at w_cursor.lnum and goes backwards.
+ * Return NULL when not inside a comment.
+ */
+ static pos_T *
+ind_find_start_comment(void) // XXX
+{
+ return find_start_comment(curbuf->b_ind_maxcomment);
+}
+
+ pos_T *
+find_start_comment(int ind_maxcomment) // XXX
+{
+ pos_T *pos;
+ char_u *line;
+ char_u *p;
+ int cur_maxcomment = ind_maxcomment;
+
+ for (;;)
+ {
+ pos = findmatchlimit(NULL, '*', FM_BACKWARD, cur_maxcomment);
+ if (pos == NULL)
+ break;
+
+ // Check if the comment start we found is inside a string.
+ // If it is then restrict the search to below this line and try again.
+ line = ml_get(pos->lnum);
+ for (p = line; *p && (colnr_T)(p - line) < pos->col; ++p)
+ p = skip_string(p);
+ if ((colnr_T)(p - line) <= pos->col)
+ break;
+ cur_maxcomment = curwin->w_cursor.lnum - pos->lnum - 1;
+ if (cur_maxcomment <= 0)
+ {
+ pos = NULL;
+ break;
+ }
+ }
+ return pos;
+}
+
+/*
+ * Find the start of a comment or raw string, not knowing if we are in a
+ * comment or raw string right now.
+ * Search starts at w_cursor.lnum and goes backwards.
+ * If is_raw is given and returns start of raw_string, sets it to true.
+ * Return NULL when not inside a comment or raw string.
+ * "CORS" -> Comment Or Raw String
+ */
+ static pos_T *
+ind_find_start_CORS(linenr_T *is_raw) // XXX
+{
+ static pos_T comment_pos_copy;
+ pos_T *comment_pos;
+ pos_T *rs_pos;
+
+ comment_pos = find_start_comment(curbuf->b_ind_maxcomment);
+ if (comment_pos != NULL)
+ {
+ // Need to make a copy of the static pos in findmatchlimit(),
+ // calling find_start_rawstring() may change it.
+ comment_pos_copy = *comment_pos;
+ comment_pos = &comment_pos_copy;
+ }
+ rs_pos = find_start_rawstring(curbuf->b_ind_maxcomment);
+
+ // If comment_pos is before rs_pos the raw string is inside the comment.
+ // If rs_pos is before comment_pos the comment is inside the raw string.
+ if (comment_pos == NULL || (rs_pos != NULL
+ && LT_POS(*rs_pos, *comment_pos)))
+ {
+ if (is_raw != NULL && rs_pos != NULL)
+ *is_raw = rs_pos->lnum;
+ return rs_pos;
+ }
+ return comment_pos;
+}
+
+/*
+ * Find the start of a raw string, not knowing if we are in one right now.
+ * Search starts at w_cursor.lnum and goes backwards.
+ * Return NULL when not inside a raw string.
+ */
+ static pos_T *
+find_start_rawstring(int ind_maxcomment) // XXX
+{
+ pos_T *pos;
+ char_u *line;
+ char_u *p;
+ int cur_maxcomment = ind_maxcomment;
+
+ for (;;)
+ {
+ pos = findmatchlimit(NULL, 'R', FM_BACKWARD, cur_maxcomment);
+ if (pos == NULL)
+ break;
+
+ // Check if the raw string start we found is inside a string.
+ // If it is then restrict the search to below this line and try again.
+ line = ml_get(pos->lnum);
+ for (p = line; *p && (colnr_T)(p - line) < pos->col; ++p)
+ p = skip_string(p);
+ if ((colnr_T)(p - line) <= pos->col)
+ break;
+ cur_maxcomment = curwin->w_cursor.lnum - pos->lnum - 1;
+ if (cur_maxcomment <= 0)
+ {
+ pos = NULL;
+ break;
+ }
+ }
+ return pos;
+}
+
+/*
+ * Skip to the end of a "string" and a 'c' character.
+ * If there is no string or character, return argument unmodified.
+ */
+ static char_u *
+skip_string(char_u *p)
+{
+ int i;
+
+ // We loop, because strings may be concatenated: "date""time".
+ for ( ; ; ++p)
+ {
+ if (p[0] == '\'') // 'c' or '\n' or '\000'
+ {
+ if (!p[1]) // ' at end of line
+ break;
+ i = 2;
+ if (p[1] == '\\') // '\n' or '\000'
+ {
+ ++i;
+ while (vim_isdigit(p[i - 1])) // '\000'
+ ++i;
+ }
+ if (p[i] == '\'') // check for trailing '
+ {
+ p += i;
+ continue;
+ }
+ }
+ else if (p[0] == '"') // start of string
+ {
+ for (++p; p[0]; ++p)
+ {
+ if (p[0] == '\\' && p[1] != NUL)
+ ++p;
+ else if (p[0] == '"') // end of string
+ break;
+ }
+ if (p[0] == '"')
+ continue; // continue for another string
+ }
+ else if (p[0] == 'R' && p[1] == '"')
+ {
+ // Raw string: R"[delim](...)[delim]"
+ char_u *delim = p + 2;
+ char_u *paren = vim_strchr(delim, '(');
+
+ if (paren != NULL)
+ {
+ size_t delim_len = paren - delim;
+
+ for (p += 3; *p; ++p)
+ if (p[0] == ')' && STRNCMP(p + 1, delim, delim_len) == 0
+ && p[delim_len + 1] == '"')
+ {
+ p += delim_len + 1;
+ break;
+ }
+ if (p[0] == '"')
+ continue; // continue for another string
+ }
+ }
+ break; // no string found
+ }
+ if (!*p)
+ --p; // backup from NUL
+ return p;
+}
+#endif // FEAT_CINDENT || FEAT_SYN_HL
+
+#if defined(FEAT_CINDENT) || defined(PROTO)
+
+/*
+ * Return TRUE if C-indenting is on.
+ */
+ int
+cindent_on(void)
+{
+ return (!p_paste && (curbuf->b_p_cin
+# ifdef FEAT_EVAL
+ || *curbuf->b_p_inde != NUL
+# endif
+ ));
+}
+
+// Find result cache for cpp_baseclass
+typedef struct {
+ int found;
+ lpos_T lpos;
+} cpp_baseclass_cache_T;
+
+/*
+ * Functions for C-indenting.
+ * Most of this originally comes from Eric Fischer.
+ */
+/*
+ * Below "XXX" means that this function may unlock the current line.
+ */
+
+static int cin_isdefault(char_u *);
+static int cin_ispreproc(char_u *);
+static int cin_iscomment(char_u *);
+static int cin_islinecomment(char_u *);
+static int cin_isterminated(char_u *, int, int);
+static int cin_iselse(char_u *);
+static int cin_ends_in(char_u *, char_u *, char_u *);
+static int cin_starts_with(char_u *s, char *word);
+static pos_T *find_match_paren(int);
+static pos_T *find_match_char(int c, int ind_maxparen);
+static int find_last_paren(char_u *l, int start, int end);
+static int find_match(int lookfor, linenr_T ourscope);
+
+/*
+ * Skip over white space and C comments within the line.
+ * Also skip over Perl/shell comments if desired.
+ */
+ static char_u *
+cin_skipcomment(char_u *s)
+{
+ while (*s)
+ {
+ char_u *prev_s = s;
+
+ s = skipwhite(s);
+
+ // Perl/shell # comment comment continues until eol. Require a space
+ // before # to avoid recognizing $#array.
+ if (curbuf->b_ind_hash_comment != 0 && s != prev_s && *s == '#')
+ {
+ s += STRLEN(s);
+ break;
+ }
+ if (*s != '/')
+ break;
+ ++s;
+ if (*s == '/') // slash-slash comment continues till eol
+ {
+ s += STRLEN(s);
+ break;
+ }
+ if (*s != '*')
+ break;
+ for (++s; *s; ++s) // skip slash-star comment
+ if (s[0] == '*' && s[1] == '/')
+ {
+ s += 2;
+ break;
+ }
+ }
+ return s;
+}
+
+/*
+ * Return TRUE if there is no code at *s. White space and comments are
+ * not considered code.
+ */
+ static int
+cin_nocode(char_u *s)
+{
+ return *cin_skipcomment(s) == NUL;
+}
+
+/*
+ * Check previous lines for a "//" line comment, skipping over blank lines.
+ */
+ static pos_T *
+find_line_comment(void) // XXX
+{
+ static pos_T pos;
+ char_u *line;
+ char_u *p;
+
+ pos = curwin->w_cursor;
+ while (--pos.lnum > 0)
+ {
+ line = ml_get(pos.lnum);
+ p = skipwhite(line);
+ if (cin_islinecomment(p))
+ {
+ pos.col = (int)(p - line);
+ return &pos;
+ }
+ if (*p != NUL)
+ break;
+ }
+ return NULL;
+}
+
+/*
+ * Return TRUE if "text" starts with "key:".
+ */
+ static int
+cin_has_js_key(char_u *text)
+{
+ char_u *s = skipwhite(text);
+ int quote = -1;
+
+ if (*s == '\'' || *s == '"')
+ {
+ // can be 'key': or "key":
+ quote = *s;
+ ++s;
+ }
+ if (!vim_isIDc(*s)) // need at least one ID character
+ return FALSE;
+
+ while (vim_isIDc(*s))
+ ++s;
+ if (*s == quote)
+ ++s;
+
+ s = cin_skipcomment(s);
+
+ // "::" is not a label, it's C++
+ return (*s == ':' && s[1] != ':');
+}
+
+/*
+ * Check if string matches "label:"; move to character after ':' if true.
+ * "*s" must point to the start of the label, if there is one.
+ */
+ static int
+cin_islabel_skip(char_u **s)
+{
+ if (!vim_isIDc(**s)) // need at least one ID character
+ return FALSE;
+
+ while (vim_isIDc(**s))
+ (*s)++;
+
+ *s = cin_skipcomment(*s);
+
+ // "::" is not a label, it's C++
+ return (**s == ':' && *++*s != ':');
+}
+
+/*
+ * Recognize a label: "label:".
+ * Note: curwin->w_cursor must be where we are looking for the label.
+ */
+ int
+cin_islabel(void) // XXX
+{
+ char_u *s;
+
+ s = cin_skipcomment(ml_get_curline());
+
+ // Exclude "default" from labels, since it should be indented
+ // like a switch label. Same for C++ scope declarations.
+ if (cin_isdefault(s))
+ return FALSE;
+ if (cin_isscopedecl(s))
+ return FALSE;
+
+ if (cin_islabel_skip(&s))
+ {
+ // Only accept a label if the previous line is terminated or is a case
+ // label.
+ pos_T cursor_save;
+ pos_T *trypos;
+ char_u *line;
+
+ cursor_save = curwin->w_cursor;
+ while (curwin->w_cursor.lnum > 1)
+ {
+ --curwin->w_cursor.lnum;
+
+ // If we're in a comment or raw string now, skip to the start of
+ // it.
+ curwin->w_cursor.col = 0;
+ if ((trypos = ind_find_start_CORS(NULL)) != NULL) // XXX
+ curwin->w_cursor = *trypos;
+
+ line = ml_get_curline();
+ if (cin_ispreproc(line)) // ignore #defines, #if, etc.
+ continue;
+ if (*(line = cin_skipcomment(line)) == NUL)
+ continue;
+
+ curwin->w_cursor = cursor_save;
+ if (cin_isterminated(line, TRUE, FALSE)
+ || cin_isscopedecl(line)
+ || cin_iscase(line, TRUE)
+ || (cin_islabel_skip(&line) && cin_nocode(line)))
+ return TRUE;
+ return FALSE;
+ }
+ curwin->w_cursor = cursor_save;
+ return TRUE; // label at start of file???
+ }
+ return FALSE;
+}
+
+/*
+ * Recognize structure initialization and enumerations:
+ * "[typedef] [static|public|protected|private] enum"
+ * "[typedef] [static|public|protected|private] = {"
+ */
+ static int
+cin_isinit(void)
+{
+ char_u *s;
+ static char *skip[] = {"static", "public", "protected", "private"};
+
+ s = cin_skipcomment(ml_get_curline());
+
+ if (cin_starts_with(s, "typedef"))
+ s = cin_skipcomment(s + 7);
+
+ for (;;)
+ {
+ int i, l;
+
+ for (i = 0; i < (int)(sizeof(skip) / sizeof(char *)); ++i)
+ {
+ l = (int)strlen(skip[i]);
+ if (cin_starts_with(s, skip[i]))
+ {
+ s = cin_skipcomment(s + l);
+ l = 0;
+ break;
+ }
+ }
+ if (l != 0)
+ break;
+ }
+
+ if (cin_starts_with(s, "enum"))
+ return TRUE;
+
+ if (cin_ends_in(s, (char_u *)"=", (char_u *)"{"))
+ return TRUE;
+
+ return FALSE;
+}
+
+/*
+ * Recognize a switch label: "case .*:" or "default:".
+ */
+ int
+cin_iscase(
+ char_u *s,
+ int strict) // Allow relaxed check of case statement for JS
+{
+ s = cin_skipcomment(s);
+ if (cin_starts_with(s, "case"))
+ {
+ for (s += 4; *s; ++s)
+ {
+ s = cin_skipcomment(s);
+ if (*s == ':')
+ {
+ if (s[1] == ':') // skip over "::" for C++
+ ++s;
+ else
+ return TRUE;
+ }
+ if (*s == '\'' && s[1] && s[2] == '\'')
+ s += 2; // skip over ':'
+ else if (*s == '/' && (s[1] == '*' || s[1] == '/'))
+ return FALSE; // stop at comment
+ else if (*s == '"')
+ {
+ // JS etc.
+ if (strict)
+ return FALSE; // stop at string
+ else
+ return TRUE;
+ }
+ }
+ return FALSE;
+ }
+
+ if (cin_isdefault(s))
+ return TRUE;
+ return FALSE;
+}
+
+/*
+ * Recognize a "default" switch label.
+ */
+ static int
+cin_isdefault(char_u *s)
+{
+ return (STRNCMP(s, "default", 7) == 0
+ && *(s = cin_skipcomment(s + 7)) == ':'
+ && s[1] != ':');
+}
+
+/*
+ * Recognize a "public/private/protected" scope declaration label.
+ */
+ int
+cin_isscopedecl(char_u *s)
+{
+ int i;
+
+ s = cin_skipcomment(s);
+ if (STRNCMP(s, "public", 6) == 0)
+ i = 6;
+ else if (STRNCMP(s, "protected", 9) == 0)
+ i = 9;
+ else if (STRNCMP(s, "private", 7) == 0)
+ i = 7;
+ else
+ return FALSE;
+ return (*(s = cin_skipcomment(s + i)) == ':' && s[1] != ':');
+}
+
+// Maximum number of lines to search back for a "namespace" line.
+#define FIND_NAMESPACE_LIM 20
+
+/*
+ * Recognize a "namespace" scope declaration.
+ */
+ static int
+cin_is_cpp_namespace(char_u *s)
+{
+ char_u *p;
+ int has_name = FALSE;
+ int has_name_start = FALSE;
+
+ s = cin_skipcomment(s);
+ if (STRNCMP(s, "namespace", 9) == 0 && (s[9] == NUL || !vim_iswordc(s[9])))
+ {
+ p = cin_skipcomment(skipwhite(s + 9));
+ while (*p != NUL)
+ {
+ if (VIM_ISWHITE(*p))
+ {
+ has_name = TRUE; // found end of a name
+ p = cin_skipcomment(skipwhite(p));
+ }
+ else if (*p == '{')
+ {
+ break;
+ }
+ else if (vim_iswordc(*p))
+ {
+ has_name_start = TRUE;
+ if (has_name)
+ return FALSE; // word character after skipping past name
+ ++p;
+ }
+ else if (p[0] == ':' && p[1] == ':' && vim_iswordc(p[2]))
+ {
+ if (!has_name_start || has_name)
+ return FALSE;
+ // C++ 17 nested namespace
+ p += 3;
+ }
+ else
+ {
+ return FALSE;
+ }
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * Recognize a `extern "C"` or `extern "C++"` linkage specifications.
+ */
+ static int
+cin_is_cpp_extern_c(char_u *s)
+{
+ char_u *p;
+ int has_string_literal = FALSE;
+
+ s = cin_skipcomment(s);
+ if (STRNCMP(s, "extern", 6) == 0 && (s[6] == NUL || !vim_iswordc(s[6])))
+ {
+ p = cin_skipcomment(skipwhite(s + 6));
+ while (*p != NUL)
+ {
+ if (VIM_ISWHITE(*p))
+ {
+ p = cin_skipcomment(skipwhite(p));
+ }
+ else if (*p == '{')
+ {
+ break;
+ }
+ else if (p[0] == '"' && p[1] == 'C' && p[2] == '"')
+ {
+ if (has_string_literal)
+ return FALSE;
+ has_string_literal = TRUE;
+ p += 3;
+ }
+ else if (p[0] == '"' && p[1] == 'C' && p[2] == '+' && p[3] == '+'
+ && p[4] == '"')
+ {
+ if (has_string_literal)
+ return FALSE;
+ has_string_literal = TRUE;
+ p += 5;
+ }
+ else
+ {
+ return FALSE;
+ }
+ }
+ return has_string_literal ? TRUE : FALSE;
+ }
+ return FALSE;
+}
+
+/*
+ * Return a pointer to the first non-empty non-comment character after a ':'.
+ * Return NULL if not found.
+ * case 234: a = b;
+ * ^
+ */
+ static char_u *
+after_label(char_u *l)
+{
+ for ( ; *l; ++l)
+ {
+ if (*l == ':')
+ {
+ if (l[1] == ':') // skip over "::" for C++
+ ++l;
+ else if (!cin_iscase(l + 1, FALSE))
+ break;
+ }
+ else if (*l == '\'' && l[1] && l[2] == '\'')
+ l += 2; // skip over 'x'
+ }
+ if (*l == NUL)
+ return NULL;
+ l = cin_skipcomment(l + 1);
+ if (*l == NUL)
+ return NULL;
+ return l;
+}
+
+/*
+ * Get indent of line "lnum", skipping a label.
+ * Return 0 if there is nothing after the label.
+ */
+ static int
+get_indent_nolabel (linenr_T lnum) // XXX
+{
+ char_u *l;
+ pos_T fp;
+ colnr_T col;
+ char_u *p;
+
+ l = ml_get(lnum);
+ p = after_label(l);
+ if (p == NULL)
+ return 0;
+
+ fp.col = (colnr_T)(p - l);
+ fp.lnum = lnum;
+ getvcol(curwin, &fp, &col, NULL, NULL);
+ return (int)col;
+}
+
+/*
+ * Find indent for line "lnum", ignoring any case or jump label.
+ * Also return a pointer to the text (after the label) in "pp".
+ * label: if (asdf && asdfasdf)
+ * ^
+ */
+ static int
+skip_label(linenr_T lnum, char_u **pp)
+{
+ char_u *l;
+ int amount;
+ pos_T cursor_save;
+
+ cursor_save = curwin->w_cursor;
+ curwin->w_cursor.lnum = lnum;
+ l = ml_get_curline();
+ // XXX
+ if (cin_iscase(l, FALSE) || cin_isscopedecl(l) || cin_islabel())
+ {
+ amount = get_indent_nolabel(lnum);
+ l = after_label(ml_get_curline());
+ if (l == NULL) // just in case
+ l = ml_get_curline();
+ }
+ else
+ {
+ amount = get_indent();
+ l = ml_get_curline();
+ }
+ *pp = l;
+
+ curwin->w_cursor = cursor_save;
+ return amount;
+}
+
+/*
+ * Return the indent of the first variable name after a type in a declaration.
+ * int a, indent of "a"
+ * static struct foo b, indent of "b"
+ * enum bla c, indent of "c"
+ * Returns zero when it doesn't look like a declaration.
+ */
+ static int
+cin_first_id_amount(void)
+{
+ char_u *line, *p, *s;
+ int len;
+ pos_T fp;
+ colnr_T col;
+
+ line = ml_get_curline();
+ p = skipwhite(line);
+ len = (int)(skiptowhite(p) - p);
+ if (len == 6 && STRNCMP(p, "static", 6) == 0)
+ {
+ p = skipwhite(p + 6);
+ len = (int)(skiptowhite(p) - p);
+ }
+ if (len == 6 && STRNCMP(p, "struct", 6) == 0)
+ p = skipwhite(p + 6);
+ else if (len == 4 && STRNCMP(p, "enum", 4) == 0)
+ p = skipwhite(p + 4);
+ else if ((len == 8 && STRNCMP(p, "unsigned", 8) == 0)
+ || (len == 6 && STRNCMP(p, "signed", 6) == 0))
+ {
+ s = skipwhite(p + len);
+ if ((STRNCMP(s, "int", 3) == 0 && VIM_ISWHITE(s[3]))
+ || (STRNCMP(s, "long", 4) == 0 && VIM_ISWHITE(s[4]))
+ || (STRNCMP(s, "short", 5) == 0 && VIM_ISWHITE(s[5]))
+ || (STRNCMP(s, "char", 4) == 0 && VIM_ISWHITE(s[4])))
+ p = s;
+ }
+ for (len = 0; vim_isIDc(p[len]); ++len)
+ ;
+ if (len == 0 || !VIM_ISWHITE(p[len]) || cin_nocode(p))
+ return 0;
+
+ p = skipwhite(p + len);
+ fp.lnum = curwin->w_cursor.lnum;
+ fp.col = (colnr_T)(p - line);
+ getvcol(curwin, &fp, &col, NULL, NULL);
+ return (int)col;
+}
+
+/*
+ * Return the indent of the first non-blank after an equal sign.
+ * char *foo = "here";
+ * Return zero if no (useful) equal sign found.
+ * Return -1 if the line above "lnum" ends in a backslash.
+ * foo = "asdf\
+ * asdf\
+ * here";
+ */
+ static int
+cin_get_equal_amount(linenr_T lnum)
+{
+ char_u *line;
+ char_u *s;
+ colnr_T col;
+ pos_T fp;
+
+ if (lnum > 1)
+ {
+ line = ml_get(lnum - 1);
+ if (*line != NUL && line[STRLEN(line) - 1] == '\\')
+ return -1;
+ }
+
+ line = s = ml_get(lnum);
+ while (*s != NUL && vim_strchr((char_u *)"=;{}\"'", *s) == NULL)
+ {
+ if (cin_iscomment(s)) // ignore comments
+ s = cin_skipcomment(s);
+ else
+ ++s;
+ }
+ if (*s != '=')
+ return 0;
+
+ s = skipwhite(s + 1);
+ if (cin_nocode(s))
+ return 0;
+
+ if (*s == '"') // nice alignment for continued strings
+ ++s;
+
+ fp.lnum = lnum;
+ fp.col = (colnr_T)(s - line);
+ getvcol(curwin, &fp, &col, NULL, NULL);
+ return (int)col;
+}
+
+/*
+ * Recognize a preprocessor statement: Any line that starts with '#'.
+ */
+ static int
+cin_ispreproc(char_u *s)
+{
+ if (*skipwhite(s) == '#')
+ return TRUE;
+ return FALSE;
+}
+
+/*
+ * Return TRUE if line "*pp" at "*lnump" is a preprocessor statement or a
+ * continuation line of a preprocessor statement. Decrease "*lnump" to the
+ * start and return the line in "*pp".
+ * Put the amount of indent in "*amount".
+ */
+ static int
+cin_ispreproc_cont(char_u **pp, linenr_T *lnump, int *amount)
+{
+ char_u *line = *pp;
+ linenr_T lnum = *lnump;
+ int retval = FALSE;
+ int candidate_amount = *amount;
+
+ if (*line != NUL && line[STRLEN(line) - 1] == '\\')
+ candidate_amount = get_indent_lnum(lnum);
+
+ for (;;)
+ {
+ if (cin_ispreproc(line))
+ {
+ retval = TRUE;
+ *lnump = lnum;
+ break;
+ }
+ if (lnum == 1)
+ break;
+ line = ml_get(--lnum);
+ if (*line == NUL || line[STRLEN(line) - 1] != '\\')
+ break;
+ }
+
+ if (lnum != *lnump)
+ *pp = ml_get(*lnump);
+ if (retval)
+ *amount = candidate_amount;
+ return retval;
+}
+
+/*
+ * Recognize the start of a C or C++ comment.
+ */
+ static int
+cin_iscomment(char_u *p)
+{
+ return (p[0] == '/' && (p[1] == '*' || p[1] == '/'));
+}
+
+/*
+ * Recognize the start of a "//" comment.
+ */
+ static int
+cin_islinecomment(char_u *p)
+{
+ return (p[0] == '/' && p[1] == '/');
+}
+
+/*
+ * Recognize a line that starts with '{' or '}', or ends with ';', ',', '{' or
+ * '}'.
+ * Don't consider "} else" a terminated line.
+ * If a line begins with an "else", only consider it terminated if no unmatched
+ * opening braces follow (handle "else { foo();" correctly).
+ * Return the character terminating the line (ending char's have precedence if
+ * both apply in order to determine initializations).
+ */
+ static int
+cin_isterminated(
+ char_u *s,
+ int incl_open, // include '{' at the end as terminator
+ int incl_comma) // recognize a trailing comma
+{
+ char_u found_start = 0;
+ unsigned n_open = 0;
+ int is_else = FALSE;
+
+ s = cin_skipcomment(s);
+
+ if (*s == '{' || (*s == '}' && !cin_iselse(s)))
+ found_start = *s;
+
+ if (!found_start)
+ is_else = cin_iselse(s);
+
+ while (*s)
+ {
+ // skip over comments, "" strings and 'c'haracters
+ s = skip_string(cin_skipcomment(s));
+ if (*s == '}' && n_open > 0)
+ --n_open;
+ if ((!is_else || n_open == 0)
+ && (*s == ';' || *s == '}' || (incl_comma && *s == ','))
+ && cin_nocode(s + 1))
+ return *s;
+ else if (*s == '{')
+ {
+ if (incl_open && cin_nocode(s + 1))
+ return *s;
+ else
+ ++n_open;
+ }
+
+ if (*s)
+ s++;
+ }
+ return found_start;
+}
+
+/*
+ * Recognize the basic picture of a function declaration -- it needs to
+ * have an open paren somewhere and a close paren at the end of the line and
+ * no semicolons anywhere.
+ * When a line ends in a comma we continue looking in the next line.
+ * "sp" points to a string with the line. When looking at other lines it must
+ * be restored to the line. When it's NULL fetch lines here.
+ * "first_lnum" is where we start looking.
+ * "min_lnum" is the line before which we will not be looking.
+ */
+ static int
+cin_isfuncdecl(
+ char_u **sp,
+ linenr_T first_lnum,
+ linenr_T min_lnum)
+{
+ char_u *s;
+ linenr_T lnum = first_lnum;
+ linenr_T save_lnum = curwin->w_cursor.lnum;
+ int retval = FALSE;
+ pos_T *trypos;
+ int just_started = TRUE;
+
+ if (sp == NULL)
+ s = ml_get(lnum);
+ else
+ s = *sp;
+
+ curwin->w_cursor.lnum = lnum;
+ if (find_last_paren(s, '(', ')')
+ && (trypos = find_match_paren(curbuf->b_ind_maxparen)) != NULL)
+ {
+ lnum = trypos->lnum;
+ if (lnum < min_lnum)
+ {
+ curwin->w_cursor.lnum = save_lnum;
+ return FALSE;
+ }
+
+ s = ml_get(lnum);
+ }
+ curwin->w_cursor.lnum = save_lnum;
+
+ // Ignore line starting with #.
+ if (cin_ispreproc(s))
+ return FALSE;
+
+ while (*s && *s != '(' && *s != ';' && *s != '\'' && *s != '"')
+ {
+ if (cin_iscomment(s)) // ignore comments
+ s = cin_skipcomment(s);
+ else if (*s == ':')
+ {
+ if (*(s + 1) == ':')
+ s += 2;
+ else
+ // To avoid a mistake in the following situation:
+ // A::A(int a, int b)
+ // : a(0) // <--not a function decl
+ // , b(0)
+ // {...
+ return FALSE;
+ }
+ else
+ ++s;
+ }
+ if (*s != '(')
+ return FALSE; // ';', ' or " before any () or no '('
+
+ while (*s && *s != ';' && *s != '\'' && *s != '"')
+ {
+ if (*s == ')' && cin_nocode(s + 1))
+ {
+ /*
+ * ')' at the end: may have found a match
+ * Check for he previous line not to end in a backslash:
+ * #if defined(x) && \
+ * defined(y)
+ */
+ lnum = first_lnum - 1;
+ s = ml_get(lnum);
+ if (*s == NUL || s[STRLEN(s) - 1] != '\\')
+ retval = TRUE;
+ goto done;
+ }
+ if ((*s == ',' && cin_nocode(s + 1)) || s[1] == NUL || cin_nocode(s))
+ {
+ int comma = (*s == ',');
+
+ // ',' at the end: continue looking in the next line.
+ // At the end: check for ',' in the next line, for this style:
+ // func(arg1
+ // , arg2)
+ for (;;)
+ {
+ if (lnum >= curbuf->b_ml.ml_line_count)
+ break;
+ s = ml_get(++lnum);
+ if (!cin_ispreproc(s))
+ break;
+ }
+ if (lnum >= curbuf->b_ml.ml_line_count)
+ break;
+ // Require a comma at end of the line or a comma or ')' at the
+ // start of next line.
+ s = skipwhite(s);
+ if (!just_started && (!comma && *s != ',' && *s != ')'))
+ break;
+ just_started = FALSE;
+ }
+ else if (cin_iscomment(s)) // ignore comments
+ s = cin_skipcomment(s);
+ else
+ {
+ ++s;
+ just_started = FALSE;
+ }
+ }
+
+done:
+ if (lnum != first_lnum && sp != NULL)
+ *sp = ml_get(first_lnum);
+
+ return retval;
+}
+
+ static int
+cin_isif(char_u *p)
+{
+ return (STRNCMP(p, "if", 2) == 0 && !vim_isIDc(p[2]));
+}
+
+ static int
+cin_iselse(
+ char_u *p)
+{
+ if (*p == '}') // accept "} else"
+ p = cin_skipcomment(p + 1);
+ return (STRNCMP(p, "else", 4) == 0 && !vim_isIDc(p[4]));
+}
+
+ static int
+cin_isdo(char_u *p)
+{
+ return (STRNCMP(p, "do", 2) == 0 && !vim_isIDc(p[2]));
+}
+
+/*
+ * Check if this is a "while" that should have a matching "do".
+ * We only accept a "while (condition) ;", with only white space between the
+ * ')' and ';'. The condition may be spread over several lines.
+ */
+ static int
+cin_iswhileofdo (char_u *p, linenr_T lnum) // XXX
+{
+ pos_T cursor_save;
+ pos_T *trypos;
+ int retval = FALSE;
+
+ p = cin_skipcomment(p);
+ if (*p == '}') // accept "} while (cond);"
+ p = cin_skipcomment(p + 1);
+ if (cin_starts_with(p, "while"))
+ {
+ cursor_save = curwin->w_cursor;
+ curwin->w_cursor.lnum = lnum;
+ curwin->w_cursor.col = 0;
+ p = ml_get_curline();
+ while (*p && *p != 'w') // skip any '}', until the 'w' of the "while"
+ {
+ ++p;
+ ++curwin->w_cursor.col;
+ }
+ if ((trypos = findmatchlimit(NULL, 0, 0,
+ curbuf->b_ind_maxparen)) != NULL
+ && *cin_skipcomment(ml_get_pos(trypos) + 1) == ';')
+ retval = TRUE;
+ curwin->w_cursor = cursor_save;
+ }
+ return retval;
+}
+
+/*
+ * Check whether in "p" there is an "if", "for" or "while" before "*poffset".
+ * Return 0 if there is none.
+ * Otherwise return !0 and update "*poffset" to point to the place where the
+ * string was found.
+ */
+ static int
+cin_is_if_for_while_before_offset(char_u *line, int *poffset)
+{
+ int offset = *poffset;
+
+ if (offset-- < 2)
+ return 0;
+ while (offset > 2 && VIM_ISWHITE(line[offset]))
+ --offset;
+
+ offset -= 1;
+ if (!STRNCMP(line + offset, "if", 2))
+ goto probablyFound;
+
+ if (offset >= 1)
+ {
+ offset -= 1;
+ if (!STRNCMP(line + offset, "for", 3))
+ goto probablyFound;
+
+ if (offset >= 2)
+ {
+ offset -= 2;
+ if (!STRNCMP(line + offset, "while", 5))
+ goto probablyFound;
+ }
+ }
+ return 0;
+
+probablyFound:
+ if (!offset || !vim_isIDc(line[offset - 1]))
+ {
+ *poffset = offset;
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Return TRUE if we are at the end of a do-while.
+ * do
+ * nothing;
+ * while (foo
+ * && bar); <-- here
+ * Adjust the cursor to the line with "while".
+ */
+ static int
+cin_iswhileofdo_end(int terminated)
+{
+ char_u *line;
+ char_u *p;
+ char_u *s;
+ pos_T *trypos;
+ int i;
+
+ if (terminated != ';') // there must be a ';' at the end
+ return FALSE;
+
+ p = line = ml_get_curline();
+ while (*p != NUL)
+ {
+ p = cin_skipcomment(p);
+ if (*p == ')')
+ {
+ s = skipwhite(p + 1);
+ if (*s == ';' && cin_nocode(s + 1))
+ {
+ // Found ");" at end of the line, now check there is "while"
+ // before the matching '('. XXX
+ i = (int)(p - line);
+ curwin->w_cursor.col = i;
+ trypos = find_match_paren(curbuf->b_ind_maxparen);
+ if (trypos != NULL)
+ {
+ s = cin_skipcomment(ml_get(trypos->lnum));
+ if (*s == '}') // accept "} while (cond);"
+ s = cin_skipcomment(s + 1);
+ if (cin_starts_with(s, "while"))
+ {
+ curwin->w_cursor.lnum = trypos->lnum;
+ return TRUE;
+ }
+ }
+
+ // Searching may have made "line" invalid, get it again.
+ line = ml_get_curline();
+ p = line + i;
+ }
+ }
+ if (*p != NUL)
+ ++p;
+ }
+ return FALSE;
+}
+
+ static int
+cin_isbreak(char_u *p)
+{
+ return (STRNCMP(p, "break", 5) == 0 && !vim_isIDc(p[5]));
+}
+
+/*
+ * Find the position of a C++ base-class declaration or
+ * constructor-initialization. eg:
+ *
+ * class MyClass :
+ * baseClass <-- here
+ * class MyClass : public baseClass,
+ * anotherBaseClass <-- here (should probably lineup ??)
+ * MyClass::MyClass(...) :
+ * baseClass(...) <-- here (constructor-initialization)
+ *
+ * This is a lot of guessing. Watch out for "cond ? func() : foo".
+ */
+ static int
+cin_is_cpp_baseclass(
+ cpp_baseclass_cache_T *cached) // input and output
+{
+ lpos_T *pos = &cached->lpos; // find position
+ char_u *s;
+ int class_or_struct, lookfor_ctor_init, cpp_base_class;
+ linenr_T lnum = curwin->w_cursor.lnum;
+ char_u *line = ml_get_curline();
+
+ if (pos->lnum <= lnum)
+ return cached->found; // Use the cached result
+
+ pos->col = 0;
+
+ s = skipwhite(line);
+ if (*s == '#') // skip #define FOO x ? (x) : x
+ return FALSE;
+ s = cin_skipcomment(s);
+ if (*s == NUL)
+ return FALSE;
+
+ cpp_base_class = lookfor_ctor_init = class_or_struct = FALSE;
+
+ // Search for a line starting with '#', empty, ending in ';' or containing
+ // '{' or '}' and start below it. This handles the following situations:
+ // a = cond ?
+ // func() :
+ // asdf;
+ // func::foo()
+ // : something
+ // {}
+ // Foo::Foo (int one, int two)
+ // : something(4),
+ // somethingelse(3)
+ // {}
+ while (lnum > 1)
+ {
+ line = ml_get(lnum - 1);
+ s = skipwhite(line);
+ if (*s == '#' || *s == NUL)
+ break;
+ while (*s != NUL)
+ {
+ s = cin_skipcomment(s);
+ if (*s == '{' || *s == '}'
+ || (*s == ';' && cin_nocode(s + 1)))
+ break;
+ if (*s != NUL)
+ ++s;
+ }
+ if (*s != NUL)
+ break;
+ --lnum;
+ }
+
+ pos->lnum = lnum;
+ line = ml_get(lnum);
+ s = line;
+ for (;;)
+ {
+ if (*s == NUL)
+ {
+ if (lnum == curwin->w_cursor.lnum)
+ break;
+ // Continue in the cursor line.
+ line = ml_get(++lnum);
+ s = line;
+ }
+ if (s == line)
+ {
+ // don't recognize "case (foo):" as a baseclass
+ if (cin_iscase(s, FALSE))
+ break;
+ s = cin_skipcomment(line);
+ if (*s == NUL)
+ continue;
+ }
+
+ if (s[0] == '"' || (s[0] == 'R' && s[1] == '"'))
+ s = skip_string(s) + 1;
+ else if (s[0] == ':')
+ {
+ if (s[1] == ':')
+ {
+ // skip double colon. It can't be a constructor
+ // initialization any more
+ lookfor_ctor_init = FALSE;
+ s = cin_skipcomment(s + 2);
+ }
+ else if (lookfor_ctor_init || class_or_struct)
+ {
+ // we have something found, that looks like the start of
+ // cpp-base-class-declaration or constructor-initialization
+ cpp_base_class = TRUE;
+ lookfor_ctor_init = class_or_struct = FALSE;
+ pos->col = 0;
+ s = cin_skipcomment(s + 1);
+ }
+ else
+ s = cin_skipcomment(s + 1);
+ }
+ else if ((STRNCMP(s, "class", 5) == 0 && !vim_isIDc(s[5]))
+ || (STRNCMP(s, "struct", 6) == 0 && !vim_isIDc(s[6])))
+ {
+ class_or_struct = TRUE;
+ lookfor_ctor_init = FALSE;
+
+ if (*s == 'c')
+ s = cin_skipcomment(s + 5);
+ else
+ s = cin_skipcomment(s + 6);
+ }
+ else
+ {
+ if (s[0] == '{' || s[0] == '}' || s[0] == ';')
+ {
+ cpp_base_class = lookfor_ctor_init = class_or_struct = FALSE;
+ }
+ else if (s[0] == ')')
+ {
+ // Constructor-initialization is assumed if we come across
+ // something like "):"
+ class_or_struct = FALSE;
+ lookfor_ctor_init = TRUE;
+ }
+ else if (s[0] == '?')
+ {
+ // Avoid seeing '() :' after '?' as constructor init.
+ return FALSE;
+ }
+ else if (!vim_isIDc(s[0]))
+ {
+ // if it is not an identifier, we are wrong
+ class_or_struct = FALSE;
+ lookfor_ctor_init = FALSE;
+ }
+ else if (pos->col == 0)
+ {
+ // it can't be a constructor-initialization any more
+ lookfor_ctor_init = FALSE;
+
+ // the first statement starts here: lineup with this one...
+ if (cpp_base_class)
+ pos->col = (colnr_T)(s - line);
+ }
+
+ // When the line ends in a comma don't align with it.
+ if (lnum == curwin->w_cursor.lnum && *s == ',' && cin_nocode(s + 1))
+ pos->col = 0;
+
+ s = cin_skipcomment(s + 1);
+ }
+ }
+
+ cached->found = cpp_base_class;
+ if (cpp_base_class)
+ pos->lnum = lnum;
+ return cpp_base_class;
+}
+
+ static int
+get_baseclass_amount(int col)
+{
+ int amount;
+ colnr_T vcol;
+ pos_T *trypos;
+
+ if (col == 0)
+ {
+ amount = get_indent();
+ if (find_last_paren(ml_get_curline(), '(', ')')
+ && (trypos = find_match_paren(curbuf->b_ind_maxparen)) != NULL)
+ amount = get_indent_lnum(trypos->lnum); // XXX
+ if (!cin_ends_in(ml_get_curline(), (char_u *)",", NULL))
+ amount += curbuf->b_ind_cpp_baseclass;
+ }
+ else
+ {
+ curwin->w_cursor.col = col;
+ getvcol(curwin, &curwin->w_cursor, &vcol, NULL, NULL);
+ amount = (int)vcol;
+ }
+ if (amount < curbuf->b_ind_cpp_baseclass)
+ amount = curbuf->b_ind_cpp_baseclass;
+ return amount;
+}
+
+/*
+ * Return TRUE if string "s" ends with the string "find", possibly followed by
+ * white space and comments. Skip strings and comments.
+ * Ignore "ignore" after "find" if it's not NULL.
+ */
+ static int
+cin_ends_in(char_u *s, char_u *find, char_u *ignore)
+{
+ char_u *p = s;
+ char_u *r;
+ int len = (int)STRLEN(find);
+
+ while (*p != NUL)
+ {
+ p = cin_skipcomment(p);
+ if (STRNCMP(p, find, len) == 0)
+ {
+ r = skipwhite(p + len);
+ if (ignore != NULL && STRNCMP(r, ignore, STRLEN(ignore)) == 0)
+ r = skipwhite(r + STRLEN(ignore));
+ if (cin_nocode(r))
+ return TRUE;
+ }
+ if (*p != NUL)
+ ++p;
+ }
+ return FALSE;
+}
+
+/*
+ * Return TRUE when "s" starts with "word" and then a non-ID character.
+ */
+ static int
+cin_starts_with(char_u *s, char *word)
+{
+ int l = (int)STRLEN(word);
+
+ return (STRNCMP(s, word, l) == 0 && !vim_isIDc(s[l]));
+}
+
+/*
+ * Skip strings, chars and comments until at or past "trypos".
+ * Return the column found.
+ */
+ static int
+cin_skip2pos(pos_T *trypos)
+{
+ char_u *line;
+ char_u *p;
+ char_u *new_p;
+
+ p = line = ml_get(trypos->lnum);
+ while (*p && (colnr_T)(p - line) < trypos->col)
+ {
+ if (cin_iscomment(p))
+ p = cin_skipcomment(p);
+ else
+ {
+ new_p = skip_string(p);
+ if (new_p == p)
+ ++p;
+ else
+ p = new_p;
+ }
+ }
+ return (int)(p - line);
+}
+
+/*
+ * Find the '{' at the start of the block we are in.
+ * Return NULL if no match found.
+ * Ignore a '{' that is in a comment, makes indenting the next three lines
+ * work.
+ */
+/* foo() */
+/* { */
+/* } */
+
+ static pos_T *
+find_start_brace(void) // XXX
+{
+ pos_T cursor_save;
+ pos_T *trypos;
+ pos_T *pos;
+ static pos_T pos_copy;
+
+ cursor_save = curwin->w_cursor;
+ while ((trypos = findmatchlimit(NULL, '{', FM_BLOCKSTOP, 0)) != NULL)
+ {
+ pos_copy = *trypos; // copy pos_T, next findmatch will change it
+ trypos = &pos_copy;
+ curwin->w_cursor = *trypos;
+ pos = NULL;
+ // ignore the { if it's in a // or / * * / comment
+ if ((colnr_T)cin_skip2pos(trypos) == trypos->col
+ && (pos = ind_find_start_CORS(NULL)) == NULL) // XXX
+ break;
+ if (pos != NULL)
+ curwin->w_cursor.lnum = pos->lnum;
+ }
+ curwin->w_cursor = cursor_save;
+ return trypos;
+}
+
+/*
+ * Find the matching '(', ignoring it if it is in a comment.
+ * Return NULL if no match found.
+ */
+ static pos_T *
+find_match_paren(int ind_maxparen) // XXX
+{
+ return find_match_char('(', ind_maxparen);
+}
+
+ static pos_T *
+find_match_char(int c, int ind_maxparen) // XXX
+{
+ pos_T cursor_save;
+ pos_T *trypos;
+ static pos_T pos_copy;
+ int ind_maxp_wk;
+
+ cursor_save = curwin->w_cursor;
+ ind_maxp_wk = ind_maxparen;
+retry:
+ if ((trypos = findmatchlimit(NULL, c, 0, ind_maxp_wk)) != NULL)
+ {
+ // check if the ( is in a // comment
+ if ((colnr_T)cin_skip2pos(trypos) > trypos->col)
+ {
+ ind_maxp_wk = ind_maxparen - (int)(cursor_save.lnum - trypos->lnum);
+ if (ind_maxp_wk > 0)
+ {
+ curwin->w_cursor = *trypos;
+ curwin->w_cursor.col = 0; // XXX
+ goto retry;
+ }
+ trypos = NULL;
+ }
+ else
+ {
+ pos_T *trypos_wk;
+
+ pos_copy = *trypos; // copy trypos, findmatch will change it
+ trypos = &pos_copy;
+ curwin->w_cursor = *trypos;
+ if ((trypos_wk = ind_find_start_CORS(NULL)) != NULL) // XXX
+ {
+ ind_maxp_wk = ind_maxparen - (int)(cursor_save.lnum
+ - trypos_wk->lnum);
+ if (ind_maxp_wk > 0)
+ {
+ curwin->w_cursor = *trypos_wk;
+ goto retry;
+ }
+ trypos = NULL;
+ }
+ }
+ }
+ curwin->w_cursor = cursor_save;
+ return trypos;
+}
+
+/*
+ * Find the matching '(', ignoring it if it is in a comment or before an
+ * unmatched {.
+ * Return NULL if no match found.
+ */
+ static pos_T *
+find_match_paren_after_brace (int ind_maxparen) // XXX
+{
+ pos_T *trypos = find_match_paren(ind_maxparen);
+
+ if (trypos != NULL)
+ {
+ pos_T *tryposBrace = find_start_brace();
+
+ // If both an unmatched '(' and '{' is found. Ignore the '('
+ // position if the '{' is further down.
+ if (tryposBrace != NULL
+ && (trypos->lnum != tryposBrace->lnum
+ ? trypos->lnum < tryposBrace->lnum
+ : trypos->col < tryposBrace->col))
+ trypos = NULL;
+ }
+ return trypos;
+}
+
+/*
+ * Return ind_maxparen corrected for the difference in line number between the
+ * cursor position and "startpos". This makes sure that searching for a
+ * matching paren above the cursor line doesn't find a match because of
+ * looking a few lines further.
+ */
+ static int
+corr_ind_maxparen(pos_T *startpos)
+{
+ long n = (long)startpos->lnum - (long)curwin->w_cursor.lnum;
+
+ if (n > 0 && n < curbuf->b_ind_maxparen / 2)
+ return curbuf->b_ind_maxparen - (int)n;
+ return curbuf->b_ind_maxparen;
+}
+
+/*
+ * Set w_cursor.col to the column number of the last unmatched ')' or '{' in
+ * line "l". "l" must point to the start of the line.
+ */
+ static int
+find_last_paren(char_u *l, int start, int end)
+{
+ int i;
+ int retval = FALSE;
+ int open_count = 0;
+
+ curwin->w_cursor.col = 0; // default is start of line
+
+ for (i = 0; l[i] != NUL; i++)
+ {
+ i = (int)(cin_skipcomment(l + i) - l); // ignore parens in comments
+ i = (int)(skip_string(l + i) - l); // ignore parens in quotes
+ if (l[i] == start)
+ ++open_count;
+ else if (l[i] == end)
+ {
+ if (open_count > 0)
+ --open_count;
+ else
+ {
+ curwin->w_cursor.col = i;
+ retval = TRUE;
+ }
+ }
+ }
+ return retval;
+}
+
+/*
+ * Parse 'cinoptions' and set the values in "curbuf".
+ * Must be called when 'cinoptions', 'shiftwidth' and/or 'tabstop' changes.
+ */
+ void
+parse_cino(buf_T *buf)
+{
+ char_u *p;
+ char_u *l;
+ char_u *digits;
+ int n;
+ int divider;
+ int fraction = 0;
+ int sw = (int)get_sw_value(buf);
+
+ // Set the default values.
+
+ // Spaces from a block's opening brace the prevailing indent for that
+ // block should be.
+ buf->b_ind_level = sw;
+
+ // Spaces from the edge of the line an open brace that's at the end of a
+ // line is imagined to be.
+ buf->b_ind_open_imag = 0;
+
+ // Spaces from the prevailing indent for a line that is not preceded by
+ // an opening brace.
+ buf->b_ind_no_brace = 0;
+
+ // Column where the first { of a function should be located }.
+ buf->b_ind_first_open = 0;
+
+ // Spaces from the prevailing indent a leftmost open brace should be
+ // located.
+ buf->b_ind_open_extra = 0;
+
+ // Spaces from the matching open brace (real location for one at the left
+ // edge; imaginary location from one that ends a line) the matching close
+ // brace should be located.
+ buf->b_ind_close_extra = 0;
+
+ // Spaces from the edge of the line an open brace sitting in the leftmost
+ // column is imagined to be.
+ buf->b_ind_open_left_imag = 0;
+
+ // Spaces jump labels should be shifted to the left if N is non-negative,
+ // otherwise the jump label will be put to column 1.
+ buf->b_ind_jump_label = -1;
+
+ // Spaces from the switch() indent a "case xx" label should be located.
+ buf->b_ind_case = sw;
+
+ // Spaces from the "case xx:" code after a switch() should be located.
+ buf->b_ind_case_code = sw;
+
+ // Lineup break at end of case in switch() with case label.
+ buf->b_ind_case_break = 0;
+
+ // Spaces from the class declaration indent a scope declaration label
+ // should be located.
+ buf->b_ind_scopedecl = sw;
+
+ // Spaces from the scope declaration label code should be located.
+ buf->b_ind_scopedecl_code = sw;
+
+ // Amount K&R-style parameters should be indented.
+ buf->b_ind_param = sw;
+
+ // Amount a function type spec should be indented.
+ buf->b_ind_func_type = sw;
+
+ // Amount a cpp base class declaration or constructor initialization
+ // should be indented.
+ buf->b_ind_cpp_baseclass = sw;
+
+ // additional spaces beyond the prevailing indent a continuation line
+ // should be located.
+ buf->b_ind_continuation = sw;
+
+ // Spaces from the indent of the line with an unclosed parentheses.
+ buf->b_ind_unclosed = sw * 2;
+
+ // Spaces from the indent of the line with an unclosed parentheses, which
+ // itself is also unclosed.
+ buf->b_ind_unclosed2 = sw;
+
+ // Suppress ignoring spaces from the indent of a line starting with an
+ // unclosed parentheses.
+ buf->b_ind_unclosed_noignore = 0;
+
+ // If the opening paren is the last nonwhite character on the line, and
+ // b_ind_unclosed_wrapped is nonzero, use this indent relative to the outer
+ // context (for very long lines).
+ buf->b_ind_unclosed_wrapped = 0;
+
+ // Suppress ignoring white space when lining up with the character after
+ // an unclosed parentheses.
+ buf->b_ind_unclosed_whiteok = 0;
+
+ // Indent a closing parentheses under the line start of the matching
+ // opening parentheses.
+ buf->b_ind_matching_paren = 0;
+
+ // Indent a closing parentheses under the previous line.
+ buf->b_ind_paren_prev = 0;
+
+ // Extra indent for comments.
+ buf->b_ind_comment = 0;
+
+ // Spaces from the comment opener when there is nothing after it.
+ buf->b_ind_in_comment = 3;
+
+ // Boolean: if non-zero, use b_ind_in_comment even if there is something
+ // after the comment opener.
+ buf->b_ind_in_comment2 = 0;
+
+ // Max lines to search for an open paren.
+ buf->b_ind_maxparen = 20;
+
+ // Max lines to search for an open comment.
+ buf->b_ind_maxcomment = 70;
+
+ // Handle braces for java code.
+ buf->b_ind_java = 0;
+
+ // Not to confuse JS object properties with labels.
+ buf->b_ind_js = 0;
+
+ // Handle blocked cases correctly.
+ buf->b_ind_keep_case_label = 0;
+
+ // Handle C++ namespace.
+ buf->b_ind_cpp_namespace = 0;
+
+ // Handle continuation lines containing conditions of if(), for() and
+ // while().
+ buf->b_ind_if_for_while = 0;
+
+ // indentation for # comments
+ buf->b_ind_hash_comment = 0;
+
+ // Handle C++ extern "C" or "C++"
+ buf->b_ind_cpp_extern_c = 0;
+
+ for (p = buf->b_p_cino; *p; )
+ {
+ l = p++;
+ if (*p == '-')
+ ++p;
+ digits = p; // remember where the digits start
+ n = getdigits(&p);
+ divider = 0;
+ if (*p == '.') // ".5s" means a fraction
+ {
+ fraction = atol((char *)++p);
+ while (VIM_ISDIGIT(*p))
+ {
+ ++p;
+ if (divider)
+ divider *= 10;
+ else
+ divider = 10;
+ }
+ }
+ if (*p == 's') // "2s" means two times 'shiftwidth'
+ {
+ if (p == digits)
+ n = sw; // just "s" is one 'shiftwidth'
+ else
+ {
+ n *= sw;
+ if (divider)
+ n += (sw * fraction + divider / 2) / divider;
+ }
+ ++p;
+ }
+ if (l[1] == '-')
+ n = -n;
+
+ // When adding an entry here, also update the default 'cinoptions' in
+ // doc/indent.txt, and add explanation for it!
+ switch (*l)
+ {
+ case '>': buf->b_ind_level = n; break;
+ case 'e': buf->b_ind_open_imag = n; break;
+ case 'n': buf->b_ind_no_brace = n; break;
+ case 'f': buf->b_ind_first_open = n; break;
+ case '{': buf->b_ind_open_extra = n; break;
+ case '}': buf->b_ind_close_extra = n; break;
+ case '^': buf->b_ind_open_left_imag = n; break;
+ case 'L': buf->b_ind_jump_label = n; break;
+ case ':': buf->b_ind_case = n; break;
+ case '=': buf->b_ind_case_code = n; break;
+ case 'b': buf->b_ind_case_break = n; break;
+ case 'p': buf->b_ind_param = n; break;
+ case 't': buf->b_ind_func_type = n; break;
+ case '/': buf->b_ind_comment = n; break;
+ case 'c': buf->b_ind_in_comment = n; break;
+ case 'C': buf->b_ind_in_comment2 = n; break;
+ case 'i': buf->b_ind_cpp_baseclass = n; break;
+ case '+': buf->b_ind_continuation = n; break;
+ case '(': buf->b_ind_unclosed = n; break;
+ case 'u': buf->b_ind_unclosed2 = n; break;
+ case 'U': buf->b_ind_unclosed_noignore = n; break;
+ case 'W': buf->b_ind_unclosed_wrapped = n; break;
+ case 'w': buf->b_ind_unclosed_whiteok = n; break;
+ case 'm': buf->b_ind_matching_paren = n; break;
+ case 'M': buf->b_ind_paren_prev = n; break;
+ case ')': buf->b_ind_maxparen = n; break;
+ case '*': buf->b_ind_maxcomment = n; break;
+ case 'g': buf->b_ind_scopedecl = n; break;
+ case 'h': buf->b_ind_scopedecl_code = n; break;
+ case 'j': buf->b_ind_java = n; break;
+ case 'J': buf->b_ind_js = n; break;
+ case 'l': buf->b_ind_keep_case_label = n; break;
+ case '#': buf->b_ind_hash_comment = n; break;
+ case 'N': buf->b_ind_cpp_namespace = n; break;
+ case 'k': buf->b_ind_if_for_while = n; break;
+ case 'E': buf->b_ind_cpp_extern_c = n; break;
+ }
+ if (*p == ',')
+ ++p;
+ }
+}
+
+/*
+ * Return the desired indent for C code.
+ * Return -1 if the indent should be left alone (inside a raw string).
+ */
+ int
+get_c_indent(void)
+{
+ pos_T cur_curpos;
+ int amount;
+ int scope_amount;
+ int cur_amount = MAXCOL;
+ colnr_T col;
+ char_u *theline;
+ char_u *linecopy;
+ pos_T *trypos;
+ pos_T *comment_pos;
+ pos_T *tryposBrace = NULL;
+ pos_T tryposCopy;
+ pos_T our_paren_pos;
+ char_u *start;
+ int start_brace;
+#define BRACE_IN_COL0 1 // '{' is in column 0
+#define BRACE_AT_START 2 // '{' is at start of line
+#define BRACE_AT_END 3 // '{' is at end of line
+ linenr_T ourscope;
+ char_u *l;
+ char_u *look;
+ char_u terminated;
+ int lookfor;
+#define LOOKFOR_INITIAL 0
+#define LOOKFOR_IF 1
+#define LOOKFOR_DO 2
+#define LOOKFOR_CASE 3
+#define LOOKFOR_ANY 4
+#define LOOKFOR_TERM 5
+#define LOOKFOR_UNTERM 6
+#define LOOKFOR_SCOPEDECL 7
+#define LOOKFOR_NOBREAK 8
+#define LOOKFOR_CPP_BASECLASS 9
+#define LOOKFOR_ENUM_OR_INIT 10
+#define LOOKFOR_JS_KEY 11
+#define LOOKFOR_COMMA 12
+
+ int whilelevel;
+ linenr_T lnum;
+ int n;
+ int iscase;
+ int lookfor_break;
+ int lookfor_cpp_namespace = FALSE;
+ int cont_amount = 0; // amount for continuation line
+ int original_line_islabel;
+ int added_to_amount = 0;
+ int js_cur_has_key = 0;
+ linenr_T raw_string_start = 0;
+ cpp_baseclass_cache_T cache_cpp_baseclass = { FALSE, { MAXLNUM, 0 } };
+
+ // make a copy, value is changed below
+ int ind_continuation = curbuf->b_ind_continuation;
+
+ // remember where the cursor was when we started
+ cur_curpos = curwin->w_cursor;
+
+ // if we are at line 1 zero indent is fine, right?
+ if (cur_curpos.lnum == 1)
+ return 0;
+
+ // Get a copy of the current contents of the line.
+ // This is required, because only the most recent line obtained with
+ // ml_get is valid!
+ linecopy = vim_strsave(ml_get(cur_curpos.lnum));
+ if (linecopy == NULL)
+ return 0;
+
+ // In insert mode and the cursor is on a ')' truncate the line at the
+ // cursor position. We don't want to line up with the matching '(' when
+ // inserting new stuff.
+ // For unknown reasons the cursor might be past the end of the line, thus
+ // check for that.
+ if ((State & INSERT)
+ && curwin->w_cursor.col < (colnr_T)STRLEN(linecopy)
+ && linecopy[curwin->w_cursor.col] == ')')
+ linecopy[curwin->w_cursor.col] = NUL;
+
+ theline = skipwhite(linecopy);
+
+ // move the cursor to the start of the line
+
+ curwin->w_cursor.col = 0;
+
+ original_line_islabel = cin_islabel(); // XXX
+
+ // If we are inside a raw string don't change the indent.
+ // Ignore a raw string inside a comment.
+ comment_pos = ind_find_start_comment();
+ if (comment_pos != NULL)
+ {
+ // findmatchlimit() static pos is overwritten, make a copy
+ tryposCopy = *comment_pos;
+ comment_pos = &tryposCopy;
+ }
+ trypos = find_start_rawstring(curbuf->b_ind_maxcomment);
+ if (trypos != NULL && (comment_pos == NULL
+ || LT_POS(*trypos, *comment_pos)))
+ {
+ amount = -1;
+ goto laterend;
+ }
+
+ // #defines and so on always go at the left when included in 'cinkeys'.
+ if (*theline == '#' && (*linecopy == '#' || in_cinkeys('#', ' ', TRUE)))
+ {
+ amount = curbuf->b_ind_hash_comment;
+ goto theend;
+ }
+
+ // Is it a non-case label? Then that goes at the left margin too unless:
+ // - JS flag is set.
+ // - 'L' item has a positive value.
+ if (original_line_islabel && !curbuf->b_ind_js
+ && curbuf->b_ind_jump_label < 0)
+ {
+ amount = 0;
+ goto theend;
+ }
+
+ // If we're inside a "//" comment and there is a "//" comment in a
+ // previous line, lineup with that one.
+ if (cin_islinecomment(theline)
+ && (trypos = find_line_comment()) != NULL) // XXX
+ {
+ // find how indented the line beginning the comment is
+ getvcol(curwin, trypos, &col, NULL, NULL);
+ amount = col;
+ goto theend;
+ }
+
+ // If we're inside a comment and not looking at the start of the
+ // comment, try using the 'comments' option.
+ if (!cin_iscomment(theline) && comment_pos != NULL) // XXX
+ {
+ int lead_start_len = 2;
+ int lead_middle_len = 1;
+ char_u lead_start[COM_MAX_LEN]; // start-comment string
+ char_u lead_middle[COM_MAX_LEN]; // middle-comment string
+ char_u lead_end[COM_MAX_LEN]; // end-comment string
+ char_u *p;
+ int start_align = 0;
+ int start_off = 0;
+ int done = FALSE;
+
+ // find how indented the line beginning the comment is
+ getvcol(curwin, comment_pos, &col, NULL, NULL);
+ amount = col;
+ *lead_start = NUL;
+ *lead_middle = NUL;
+
+ p = curbuf->b_p_com;
+ while (*p != NUL)
+ {
+ int align = 0;
+ int off = 0;
+ int what = 0;
+
+ while (*p != NUL && *p != ':')
+ {
+ if (*p == COM_START || *p == COM_END || *p == COM_MIDDLE)
+ what = *p++;
+ else if (*p == COM_LEFT || *p == COM_RIGHT)
+ align = *p++;
+ else if (VIM_ISDIGIT(*p) || *p == '-')
+ off = getdigits(&p);
+ else
+ ++p;
+ }
+
+ if (*p == ':')
+ ++p;
+ (void)copy_option_part(&p, lead_end, COM_MAX_LEN, ",");
+ if (what == COM_START)
+ {
+ STRCPY(lead_start, lead_end);
+ lead_start_len = (int)STRLEN(lead_start);
+ start_off = off;
+ start_align = align;
+ }
+ else if (what == COM_MIDDLE)
+ {
+ STRCPY(lead_middle, lead_end);
+ lead_middle_len = (int)STRLEN(lead_middle);
+ }
+ else if (what == COM_END)
+ {
+ // If our line starts with the middle comment string, line it
+ // up with the comment opener per the 'comments' option.
+ if (STRNCMP(theline, lead_middle, lead_middle_len) == 0
+ && STRNCMP(theline, lead_end, STRLEN(lead_end)) != 0)
+ {
+ done = TRUE;
+ if (curwin->w_cursor.lnum > 1)
+ {
+ // If the start comment string matches in the previous
+ // line, use the indent of that line plus offset. If
+ // the middle comment string matches in the previous
+ // line, use the indent of that line. XXX
+ look = skipwhite(ml_get(curwin->w_cursor.lnum - 1));
+ if (STRNCMP(look, lead_start, lead_start_len) == 0)
+ amount = get_indent_lnum(curwin->w_cursor.lnum - 1);
+ else if (STRNCMP(look, lead_middle,
+ lead_middle_len) == 0)
+ {
+ amount = get_indent_lnum(curwin->w_cursor.lnum - 1);
+ break;
+ }
+ // If the start comment string doesn't match with the
+ // start of the comment, skip this entry. XXX
+ else if (STRNCMP(ml_get(comment_pos->lnum) + comment_pos->col,
+ lead_start, lead_start_len) != 0)
+ continue;
+ }
+ if (start_off != 0)
+ amount += start_off;
+ else if (start_align == COM_RIGHT)
+ amount += vim_strsize(lead_start)
+ - vim_strsize(lead_middle);
+ break;
+ }
+
+ // If our line starts with the end comment string, line it up
+ // with the middle comment
+ if (STRNCMP(theline, lead_middle, lead_middle_len) != 0
+ && STRNCMP(theline, lead_end, STRLEN(lead_end)) == 0)
+ {
+ amount = get_indent_lnum(curwin->w_cursor.lnum - 1);
+ // XXX
+ if (off != 0)
+ amount += off;
+ else if (align == COM_RIGHT)
+ amount += vim_strsize(lead_start)
+ - vim_strsize(lead_middle);
+ done = TRUE;
+ break;
+ }
+ }
+ }
+
+ // If our line starts with an asterisk, line up with the
+ // asterisk in the comment opener; otherwise, line up
+ // with the first character of the comment text.
+ if (done)
+ ;
+ else if (theline[0] == '*')
+ amount += 1;
+ else
+ {
+ // If we are more than one line away from the comment opener, take
+ // the indent of the previous non-empty line. If 'cino' has "CO"
+ // and we are just below the comment opener and there are any
+ // white characters after it line up with the text after it;
+ // otherwise, add the amount specified by "c" in 'cino'
+ amount = -1;
+ for (lnum = cur_curpos.lnum - 1; lnum > comment_pos->lnum; --lnum)
+ {
+ if (linewhite(lnum)) // skip blank lines
+ continue;
+ amount = get_indent_lnum(lnum); // XXX
+ break;
+ }
+ if (amount == -1) // use the comment opener
+ {
+ if (!curbuf->b_ind_in_comment2)
+ {
+ start = ml_get(comment_pos->lnum);
+ look = start + comment_pos->col + 2; // skip / and *
+ if (*look != NUL) // if something after it
+ comment_pos->col = (colnr_T)(skipwhite(look) - start);
+ }
+ getvcol(curwin, comment_pos, &col, NULL, NULL);
+ amount = col;
+ if (curbuf->b_ind_in_comment2 || *look == NUL)
+ amount += curbuf->b_ind_in_comment;
+ }
+ }
+ goto theend;
+ }
+
+ // Are we looking at a ']' that has a match?
+ if (*skipwhite(theline) == ']'
+ && (trypos = find_match_char('[', curbuf->b_ind_maxparen)) != NULL)
+ {
+ // align with the line containing the '['.
+ amount = get_indent_lnum(trypos->lnum);
+ goto theend;
+ }
+
+ // Are we inside parentheses or braces? XXX
+ if (((trypos = find_match_paren(curbuf->b_ind_maxparen)) != NULL
+ && curbuf->b_ind_java == 0)
+ || (tryposBrace = find_start_brace()) != NULL
+ || trypos != NULL)
+ {
+ if (trypos != NULL && tryposBrace != NULL)
+ {
+ // Both an unmatched '(' and '{' is found. Use the one which is
+ // closer to the current cursor position, set the other to NULL.
+ if (trypos->lnum != tryposBrace->lnum
+ ? trypos->lnum < tryposBrace->lnum
+ : trypos->col < tryposBrace->col)
+ trypos = NULL;
+ else
+ tryposBrace = NULL;
+ }
+
+ if (trypos != NULL)
+ {
+ // If the matching paren is more than one line away, use the indent of
+ // a previous non-empty line that matches the same paren.
+ if (theline[0] == ')' && curbuf->b_ind_paren_prev)
+ {
+ // Line up with the start of the matching paren line.
+ amount = get_indent_lnum(curwin->w_cursor.lnum - 1); // XXX
+ }
+ else
+ {
+ amount = -1;
+ our_paren_pos = *trypos;
+ for (lnum = cur_curpos.lnum - 1; lnum > our_paren_pos.lnum; --lnum)
+ {
+ l = skipwhite(ml_get(lnum));
+ if (cin_nocode(l)) // skip comment lines
+ continue;
+ if (cin_ispreproc_cont(&l, &lnum, &amount))
+ continue; // ignore #define, #if, etc.
+ curwin->w_cursor.lnum = lnum;
+
+ // Skip a comment or raw string. XXX
+ if ((trypos = ind_find_start_CORS(NULL)) != NULL)
+ {
+ lnum = trypos->lnum + 1;
+ continue;
+ }
+
+ // XXX
+ if ((trypos = find_match_paren(
+ corr_ind_maxparen(&cur_curpos))) != NULL
+ && trypos->lnum == our_paren_pos.lnum
+ && trypos->col == our_paren_pos.col)
+ {
+ amount = get_indent_lnum(lnum); // XXX
+
+ if (theline[0] == ')')
+ {
+ if (our_paren_pos.lnum != lnum
+ && cur_amount > amount)
+ cur_amount = amount;
+ amount = -1;
+ }
+ break;
+ }
+ }
+ }
+
+ // Line up with line where the matching paren is. XXX
+ // If the line starts with a '(' or the indent for unclosed
+ // parentheses is zero, line up with the unclosed parentheses.
+ if (amount == -1)
+ {
+ int ignore_paren_col = 0;
+ int is_if_for_while = 0;
+
+ if (curbuf->b_ind_if_for_while)
+ {
+ // Look for the outermost opening parenthesis on this line
+ // and check whether it belongs to an "if", "for" or "while".
+
+ pos_T cursor_save = curwin->w_cursor;
+ pos_T outermost;
+ char_u *line;
+
+ trypos = &our_paren_pos;
+ do {
+ outermost = *trypos;
+ curwin->w_cursor.lnum = outermost.lnum;
+ curwin->w_cursor.col = outermost.col;
+
+ trypos = find_match_paren(curbuf->b_ind_maxparen);
+ } while (trypos && trypos->lnum == outermost.lnum);
+
+ curwin->w_cursor = cursor_save;
+
+ line = ml_get(outermost.lnum);
+
+ is_if_for_while =
+ cin_is_if_for_while_before_offset(line, &outermost.col);
+ }
+
+ amount = skip_label(our_paren_pos.lnum, &look);
+ look = skipwhite(look);
+ if (*look == '(')
+ {
+ linenr_T save_lnum = curwin->w_cursor.lnum;
+ char_u *line;
+ int look_col;
+
+ // Ignore a '(' in front of the line that has a match before
+ // our matching '('.
+ curwin->w_cursor.lnum = our_paren_pos.lnum;
+ line = ml_get_curline();
+ look_col = (int)(look - line);
+ curwin->w_cursor.col = look_col + 1;
+ if ((trypos = findmatchlimit(NULL, ')', 0,
+ curbuf->b_ind_maxparen))
+ != NULL
+ && trypos->lnum == our_paren_pos.lnum
+ && trypos->col < our_paren_pos.col)
+ ignore_paren_col = trypos->col + 1;
+
+ curwin->w_cursor.lnum = save_lnum;
+ look = ml_get(our_paren_pos.lnum) + look_col;
+ }
+ if (theline[0] == ')' || (curbuf->b_ind_unclosed == 0
+ && is_if_for_while == 0)
+ || (!curbuf->b_ind_unclosed_noignore && *look == '('
+ && ignore_paren_col == 0))
+ {
+ // If we're looking at a close paren, line up right there;
+ // otherwise, line up with the next (non-white) character.
+ // When b_ind_unclosed_wrapped is set and the matching paren is
+ // the last nonwhite character of the line, use either the
+ // indent of the current line or the indentation of the next
+ // outer paren and add b_ind_unclosed_wrapped (for very long
+ // lines).
+ if (theline[0] != ')')
+ {
+ cur_amount = MAXCOL;
+ l = ml_get(our_paren_pos.lnum);
+ if (curbuf->b_ind_unclosed_wrapped
+ && cin_ends_in(l, (char_u *)"(", NULL))
+ {
+ // look for opening unmatched paren, indent one level
+ // for each additional level
+ n = 1;
+ for (col = 0; col < our_paren_pos.col; ++col)
+ {
+ switch (l[col])
+ {
+ case '(':
+ case '{': ++n;
+ break;
+
+ case ')':
+ case '}': if (n > 1)
+ --n;
+ break;
+ }
+ }
+
+ our_paren_pos.col = 0;
+ amount += n * curbuf->b_ind_unclosed_wrapped;
+ }
+ else if (curbuf->b_ind_unclosed_whiteok)
+ our_paren_pos.col++;
+ else
+ {
+ col = our_paren_pos.col + 1;
+ while (VIM_ISWHITE(l[col]))
+ col++;
+ if (l[col] != NUL) // In case of trailing space
+ our_paren_pos.col = col;
+ else
+ our_paren_pos.col++;
+ }
+ }
+
+ // Find how indented the paren is, or the character after it
+ // if we did the above "if".
+ if (our_paren_pos.col > 0)
+ {
+ getvcol(curwin, &our_paren_pos, &col, NULL, NULL);
+ if (cur_amount > (int)col)
+ cur_amount = col;
+ }
+ }
+
+ if (theline[0] == ')' && curbuf->b_ind_matching_paren)
+ {
+ // Line up with the start of the matching paren line.
+ }
+ else if ((curbuf->b_ind_unclosed == 0 && is_if_for_while == 0)
+ || (!curbuf->b_ind_unclosed_noignore
+ && *look == '(' && ignore_paren_col == 0))
+ {
+ if (cur_amount != MAXCOL)
+ amount = cur_amount;
+ }
+ else
+ {
+ // Add b_ind_unclosed2 for each '(' before our matching one,
+ // but ignore (void) before the line (ignore_paren_col).
+ col = our_paren_pos.col;
+ while ((int)our_paren_pos.col > ignore_paren_col)
+ {
+ --our_paren_pos.col;
+ switch (*ml_get_pos(&our_paren_pos))
+ {
+ case '(': amount += curbuf->b_ind_unclosed2;
+ col = our_paren_pos.col;
+ break;
+ case ')': amount -= curbuf->b_ind_unclosed2;
+ col = MAXCOL;
+ break;
+ }
+ }
+
+ // Use b_ind_unclosed once, when the first '(' is not inside
+ // braces
+ if (col == MAXCOL)
+ amount += curbuf->b_ind_unclosed;
+ else
+ {
+ curwin->w_cursor.lnum = our_paren_pos.lnum;
+ curwin->w_cursor.col = col;
+ if (find_match_paren_after_brace(curbuf->b_ind_maxparen)
+ != NULL)
+ amount += curbuf->b_ind_unclosed2;
+ else
+ {
+ if (is_if_for_while)
+ amount += curbuf->b_ind_if_for_while;
+ else
+ amount += curbuf->b_ind_unclosed;
+ }
+ }
+ // For a line starting with ')' use the minimum of the two
+ // positions, to avoid giving it more indent than the previous
+ // lines:
+ // func_long_name( if (x
+ // arg && yy
+ // ) ^ not here ) ^ not here
+ if (cur_amount < amount)
+ amount = cur_amount;
+ }
+ }
+
+ // add extra indent for a comment
+ if (cin_iscomment(theline))
+ amount += curbuf->b_ind_comment;
+ }
+ else
+ {
+ // We are inside braces, there is a { before this line at the position
+ // stored in tryposBrace.
+ // Make a copy of tryposBrace, it may point to pos_copy inside
+ // find_start_brace(), which may be changed somewhere.
+ tryposCopy = *tryposBrace;
+ tryposBrace = &tryposCopy;
+ trypos = tryposBrace;
+ ourscope = trypos->lnum;
+ start = ml_get(ourscope);
+
+ // Now figure out how indented the line is in general.
+ // If the brace was at the start of the line, we use that;
+ // otherwise, check out the indentation of the line as
+ // a whole and then add the "imaginary indent" to that.
+ look = skipwhite(start);
+ if (*look == '{')
+ {
+ getvcol(curwin, trypos, &col, NULL, NULL);
+ amount = col;
+ if (*start == '{')
+ start_brace = BRACE_IN_COL0;
+ else
+ start_brace = BRACE_AT_START;
+ }
+ else
+ {
+ // That opening brace might have been on a continuation
+ // line. if so, find the start of the line.
+ curwin->w_cursor.lnum = ourscope;
+
+ // Position the cursor over the rightmost paren, so that
+ // matching it will take us back to the start of the line.
+ lnum = ourscope;
+ if (find_last_paren(start, '(', ')')
+ && (trypos = find_match_paren(curbuf->b_ind_maxparen))
+ != NULL)
+ lnum = trypos->lnum;
+
+ // It could have been something like
+ // case 1: if (asdf &&
+ // ldfd) {
+ // }
+ if ((curbuf->b_ind_js || curbuf->b_ind_keep_case_label)
+ && cin_iscase(skipwhite(ml_get_curline()), FALSE))
+ amount = get_indent();
+ else if (curbuf->b_ind_js)
+ amount = get_indent_lnum(lnum);
+ else
+ amount = skip_label(lnum, &l);
+
+ start_brace = BRACE_AT_END;
+ }
+
+ // For Javascript check if the line starts with "key:".
+ if (curbuf->b_ind_js)
+ js_cur_has_key = cin_has_js_key(theline);
+
+ // If we're looking at a closing brace, that's where
+ // we want to be. otherwise, add the amount of room
+ // that an indent is supposed to be.
+ if (theline[0] == '}')
+ {
+ // they may want closing braces to line up with something
+ // other than the open brace. indulge them, if so.
+ amount += curbuf->b_ind_close_extra;
+ }
+ else
+ {
+ // If we're looking at an "else", try to find an "if"
+ // to match it with.
+ // If we're looking at a "while", try to find a "do"
+ // to match it with.
+ lookfor = LOOKFOR_INITIAL;
+ if (cin_iselse(theline))
+ lookfor = LOOKFOR_IF;
+ else if (cin_iswhileofdo(theline, cur_curpos.lnum)) // XXX
+ lookfor = LOOKFOR_DO;
+ if (lookfor != LOOKFOR_INITIAL)
+ {
+ curwin->w_cursor.lnum = cur_curpos.lnum;
+ if (find_match(lookfor, ourscope) == OK)
+ {
+ amount = get_indent(); // XXX
+ goto theend;
+ }
+ }
+
+ // We get here if we are not on an "while-of-do" or "else" (or
+ // failed to find a matching "if").
+ // Search backwards for something to line up with.
+ // First set amount for when we don't find anything.
+
+ // if the '{' is _really_ at the left margin, use the imaginary
+ // location of a left-margin brace. Otherwise, correct the
+ // location for b_ind_open_extra.
+
+ if (start_brace == BRACE_IN_COL0) // '{' is in column 0
+ {
+ amount = curbuf->b_ind_open_left_imag;
+ lookfor_cpp_namespace = TRUE;
+ }
+ else if (start_brace == BRACE_AT_START &&
+ lookfor_cpp_namespace) // '{' is at start
+ {
+
+ lookfor_cpp_namespace = TRUE;
+ }
+ else
+ {
+ if (start_brace == BRACE_AT_END) // '{' is at end of line
+ {
+ amount += curbuf->b_ind_open_imag;
+
+ l = skipwhite(ml_get_curline());
+ if (cin_is_cpp_namespace(l))
+ amount += curbuf->b_ind_cpp_namespace;
+ else if (cin_is_cpp_extern_c(l))
+ amount += curbuf->b_ind_cpp_extern_c;
+ }
+ else
+ {
+ // Compensate for adding b_ind_open_extra later.
+ amount -= curbuf->b_ind_open_extra;
+ if (amount < 0)
+ amount = 0;
+ }
+ }
+
+ lookfor_break = FALSE;
+
+ if (cin_iscase(theline, FALSE)) // it's a switch() label
+ {
+ lookfor = LOOKFOR_CASE; // find a previous switch() label
+ amount += curbuf->b_ind_case;
+ }
+ else if (cin_isscopedecl(theline)) // private:, ...
+ {
+ lookfor = LOOKFOR_SCOPEDECL; // class decl is this block
+ amount += curbuf->b_ind_scopedecl;
+ }
+ else
+ {
+ if (curbuf->b_ind_case_break && cin_isbreak(theline))
+ // break; ...
+ lookfor_break = TRUE;
+
+ lookfor = LOOKFOR_INITIAL;
+ // b_ind_level from start of block
+ amount += curbuf->b_ind_level;
+ }
+ scope_amount = amount;
+ whilelevel = 0;
+
+ // Search backwards. If we find something we recognize, line up
+ // with that.
+ //
+ // If we're looking at an open brace, indent
+ // the usual amount relative to the conditional
+ // that opens the block.
+ curwin->w_cursor = cur_curpos;
+ for (;;)
+ {
+ curwin->w_cursor.lnum--;
+ curwin->w_cursor.col = 0;
+
+ // If we went all the way back to the start of our scope, line
+ // up with it.
+ if (curwin->w_cursor.lnum <= ourscope)
+ {
+ // We reached end of scope:
+ // If looking for a enum or structure initialization
+ // go further back:
+ // If it is an initializer (enum xxx or xxx =), then
+ // don't add ind_continuation, otherwise it is a variable
+ // declaration:
+ // int x,
+ // here; <-- add ind_continuation
+ if (lookfor == LOOKFOR_ENUM_OR_INIT)
+ {
+ if (curwin->w_cursor.lnum == 0
+ || curwin->w_cursor.lnum
+ < ourscope - curbuf->b_ind_maxparen)
+ {
+ // nothing found (abuse curbuf->b_ind_maxparen as
+ // limit) assume terminated line (i.e. a variable
+ // initialization)
+ if (cont_amount > 0)
+ amount = cont_amount;
+ else if (!curbuf->b_ind_js)
+ amount += ind_continuation;
+ break;
+ }
+
+ l = ml_get_curline();
+
+ // If we're in a comment or raw string now, skip to
+ // the start of it.
+ trypos = ind_find_start_CORS(NULL);
+ if (trypos != NULL)
+ {
+ curwin->w_cursor.lnum = trypos->lnum + 1;
+ curwin->w_cursor.col = 0;
+ continue;
+ }
+
+ // Skip preprocessor directives and blank lines.
+ if (cin_ispreproc_cont(&l, &curwin->w_cursor.lnum,
+ &amount))
+ continue;
+
+ if (cin_nocode(l))
+ continue;
+
+ terminated = cin_isterminated(l, FALSE, TRUE);
+
+ // If we are at top level and the line looks like a
+ // function declaration, we are done
+ // (it's a variable declaration).
+ if (start_brace != BRACE_IN_COL0
+ || !cin_isfuncdecl(&l, curwin->w_cursor.lnum, 0))
+ {
+ // if the line is terminated with another ','
+ // it is a continued variable initialization.
+ // don't add extra indent.
+ // TODO: does not work, if a function
+ // declaration is split over multiple lines:
+ // cin_isfuncdecl returns FALSE then.
+ if (terminated == ',')
+ break;
+
+ // if it es a enum declaration or an assignment,
+ // we are done.
+ if (terminated != ';' && cin_isinit())
+ break;
+
+ // nothing useful found
+ if (terminated == 0 || terminated == '{')
+ continue;
+ }
+
+ if (terminated != ';')
+ {
+ // Skip parens and braces. Position the cursor
+ // over the rightmost paren, so that matching it
+ // will take us back to the start of the line.
+ // XXX
+ trypos = NULL;
+ if (find_last_paren(l, '(', ')'))
+ trypos = find_match_paren(
+ curbuf->b_ind_maxparen);
+
+ if (trypos == NULL && find_last_paren(l, '{', '}'))
+ trypos = find_start_brace();
+
+ if (trypos != NULL)
+ {
+ curwin->w_cursor.lnum = trypos->lnum + 1;
+ curwin->w_cursor.col = 0;
+ continue;
+ }
+ }
+
+ // it's a variable declaration, add indentation
+ // like in
+ // int a,
+ // b;
+ if (cont_amount > 0)
+ amount = cont_amount;
+ else
+ amount += ind_continuation;
+ }
+ else if (lookfor == LOOKFOR_UNTERM)
+ {
+ if (cont_amount > 0)
+ amount = cont_amount;
+ else
+ amount += ind_continuation;
+ }
+ else
+ {
+ if (lookfor != LOOKFOR_TERM
+ && lookfor != LOOKFOR_CPP_BASECLASS
+ && lookfor != LOOKFOR_COMMA)
+ {
+ amount = scope_amount;
+ if (theline[0] == '{')
+ {
+ amount += curbuf->b_ind_open_extra;
+ added_to_amount = curbuf->b_ind_open_extra;
+ }
+ }
+
+ if (lookfor_cpp_namespace)
+ {
+ // Looking for C++ namespace, need to look further
+ // back.
+ if (curwin->w_cursor.lnum == ourscope)
+ continue;
+
+ if (curwin->w_cursor.lnum == 0
+ || curwin->w_cursor.lnum
+ < ourscope - FIND_NAMESPACE_LIM)
+ break;
+
+ l = ml_get_curline();
+
+ // If we're in a comment or raw string now, skip
+ // to the start of it.
+ trypos = ind_find_start_CORS(NULL);
+ if (trypos != NULL)
+ {
+ curwin->w_cursor.lnum = trypos->lnum + 1;
+ curwin->w_cursor.col = 0;
+ continue;
+ }
+
+ // Skip preprocessor directives and blank lines.
+ if (cin_ispreproc_cont(&l, &curwin->w_cursor.lnum,
+ &amount))
+ continue;
+
+ // Finally the actual check for "namespace".
+ if (cin_is_cpp_namespace(l))
+ {
+ amount += curbuf->b_ind_cpp_namespace
+ - added_to_amount;
+ break;
+ }
+ else if (cin_is_cpp_extern_c(l))
+ {
+ amount += curbuf->b_ind_cpp_extern_c
+ - added_to_amount;
+ break;
+ }
+
+ if (cin_nocode(l))
+ continue;
+ }
+ }
+ break;
+ }
+
+ // If we're in a comment or raw string now, skip to the start
+ // of it. XXX
+ if ((trypos = ind_find_start_CORS(&raw_string_start)) != NULL)
+ {
+ curwin->w_cursor.lnum = trypos->lnum + 1;
+ curwin->w_cursor.col = 0;
+ continue;
+ }
+
+ l = ml_get_curline();
+
+ // If this is a switch() label, may line up relative to that.
+ // If this is a C++ scope declaration, do the same.
+ iscase = cin_iscase(l, FALSE);
+ if (iscase || cin_isscopedecl(l))
+ {
+ // we are only looking for cpp base class
+ // declaration/initialization any longer
+ if (lookfor == LOOKFOR_CPP_BASECLASS)
+ break;
+
+ // When looking for a "do" we are not interested in
+ // labels.
+ if (whilelevel > 0)
+ continue;
+
+ // case xx:
+ // c = 99 + <- this indent plus continuation
+ //-> here;
+ if (lookfor == LOOKFOR_UNTERM
+ || lookfor == LOOKFOR_ENUM_OR_INIT)
+ {
+ if (cont_amount > 0)
+ amount = cont_amount;
+ else
+ amount += ind_continuation;
+ break;
+ }
+
+ // case xx: <- line up with this case
+ // x = 333;
+ // case yy:
+ if ( (iscase && lookfor == LOOKFOR_CASE)
+ || (iscase && lookfor_break)
+ || (!iscase && lookfor == LOOKFOR_SCOPEDECL))
+ {
+ // Check that this case label is not for another
+ // switch() XXX
+ if ((trypos = find_start_brace()) == NULL
+ || trypos->lnum == ourscope)
+ {
+ amount = get_indent(); // XXX
+ break;
+ }
+ continue;
+ }
+
+ n = get_indent_nolabel(curwin->w_cursor.lnum); // XXX
+
+ // case xx: if (cond) <- line up with this if
+ // y = y + 1;
+ // -> s = 99;
+ //
+ // case xx:
+ // if (cond) <- line up with this line
+ // y = y + 1;
+ // -> s = 99;
+ if (lookfor == LOOKFOR_TERM)
+ {
+ if (n)
+ amount = n;
+
+ if (!lookfor_break)
+ break;
+ }
+
+ // case xx: x = x + 1; <- line up with this x
+ // -> y = y + 1;
+ //
+ // case xx: if (cond) <- line up with this if
+ // -> y = y + 1;
+ if (n)
+ {
+ amount = n;
+ l = after_label(ml_get_curline());
+ if (l != NULL && cin_is_cinword(l))
+ {
+ if (theline[0] == '{')
+ amount += curbuf->b_ind_open_extra;
+ else
+ amount += curbuf->b_ind_level
+ + curbuf->b_ind_no_brace;
+ }
+ break;
+ }
+
+ // Try to get the indent of a statement before the switch
+ // label. If nothing is found, line up relative to the
+ // switch label.
+ // break; <- may line up with this line
+ // case xx:
+ // -> y = 1;
+ scope_amount = get_indent() + (iscase // XXX
+ ? curbuf->b_ind_case_code
+ : curbuf->b_ind_scopedecl_code);
+ lookfor = curbuf->b_ind_case_break
+ ? LOOKFOR_NOBREAK : LOOKFOR_ANY;
+ continue;
+ }
+
+ // Looking for a switch() label or C++ scope declaration,
+ // ignore other lines, skip {}-blocks.
+ if (lookfor == LOOKFOR_CASE || lookfor == LOOKFOR_SCOPEDECL)
+ {
+ if (find_last_paren(l, '{', '}')
+ && (trypos = find_start_brace()) != NULL)
+ {
+ curwin->w_cursor.lnum = trypos->lnum + 1;
+ curwin->w_cursor.col = 0;
+ }
+ continue;
+ }
+
+ // Ignore jump labels with nothing after them.
+ if (!curbuf->b_ind_js && cin_islabel())
+ {
+ l = after_label(ml_get_curline());
+ if (l == NULL || cin_nocode(l))
+ continue;
+ }
+
+ // Ignore #defines, #if, etc.
+ // Ignore comment and empty lines.
+ // (need to get the line again, cin_islabel() may have
+ // unlocked it)
+ l = ml_get_curline();
+ if (cin_ispreproc_cont(&l, &curwin->w_cursor.lnum, &amount)
+ || cin_nocode(l))
+ continue;
+
+ // Are we at the start of a cpp base class declaration or
+ // constructor initialization? XXX
+ n = FALSE;
+ if (lookfor != LOOKFOR_TERM && curbuf->b_ind_cpp_baseclass > 0)
+ {
+ n = cin_is_cpp_baseclass(&cache_cpp_baseclass);
+ l = ml_get_curline();
+ }
+ if (n)
+ {
+ if (lookfor == LOOKFOR_UNTERM)
+ {
+ if (cont_amount > 0)
+ amount = cont_amount;
+ else
+ amount += ind_continuation;
+ }
+ else if (theline[0] == '{')
+ {
+ // Need to find start of the declaration.
+ lookfor = LOOKFOR_UNTERM;
+ ind_continuation = 0;
+ continue;
+ }
+ else
+ // XXX
+ amount = get_baseclass_amount(
+ cache_cpp_baseclass.lpos.col);
+ break;
+ }
+ else if (lookfor == LOOKFOR_CPP_BASECLASS)
+ {
+ // only look, whether there is a cpp base class
+ // declaration or initialization before the opening brace.
+ if (cin_isterminated(l, TRUE, FALSE))
+ break;
+ else
+ continue;
+ }
+
+ // What happens next depends on the line being terminated.
+ // If terminated with a ',' only consider it terminating if
+ // there is another unterminated statement behind, eg:
+ // 123,
+ // sizeof
+ // here
+ // Otherwise check whether it is a enumeration or structure
+ // initialisation (not indented) or a variable declaration
+ // (indented).
+ terminated = cin_isterminated(l, FALSE, TRUE);
+
+ if (js_cur_has_key)
+ {
+ js_cur_has_key = 0; // only check the first line
+ if (curbuf->b_ind_js && terminated == ',')
+ {
+ // For Javascript we might be inside an object:
+ // key: something, <- align with this
+ // key: something
+ // or:
+ // key: something + <- align with this
+ // something,
+ // key: something
+ lookfor = LOOKFOR_JS_KEY;
+ }
+ }
+ if (lookfor == LOOKFOR_JS_KEY && cin_has_js_key(l))
+ {
+ amount = get_indent();
+ break;
+ }
+ if (lookfor == LOOKFOR_COMMA)
+ {
+ if (tryposBrace != NULL && tryposBrace->lnum
+ >= curwin->w_cursor.lnum)
+ break;
+ if (terminated == ',')
+ // line below current line is the one that starts a
+ // (possibly broken) line ending in a comma.
+ break;
+ else
+ {
+ amount = get_indent();
+ if (curwin->w_cursor.lnum - 1 == ourscope)
+ // line above is start of the scope, thus current
+ // line is the one that stars a (possibly broken)
+ // line ending in a comma.
+ break;
+ }
+ }
+
+ if (terminated == 0 || (lookfor != LOOKFOR_UNTERM
+ && terminated == ','))
+ {
+ if (lookfor != LOOKFOR_ENUM_OR_INIT &&
+ (*skipwhite(l) == '[' || l[STRLEN(l) - 1] == '['))
+ amount += ind_continuation;
+ // if we're in the middle of a paren thing,
+ // go back to the line that starts it so
+ // we can get the right prevailing indent
+ // if ( foo &&
+ // bar )
+
+ // Position the cursor over the rightmost paren, so that
+ // matching it will take us back to the start of the line.
+ // Ignore a match before the start of the block.
+ (void)find_last_paren(l, '(', ')');
+ trypos = find_match_paren(corr_ind_maxparen(&cur_curpos));
+ if (trypos != NULL && (trypos->lnum < tryposBrace->lnum
+ || (trypos->lnum == tryposBrace->lnum
+ && trypos->col < tryposBrace->col)))
+ trypos = NULL;
+
+ // If we are looking for ',', we also look for matching
+ // braces.
+ if (trypos == NULL && terminated == ','
+ && find_last_paren(l, '{', '}'))
+ trypos = find_start_brace();
+
+ if (trypos != NULL)
+ {
+ // Check if we are on a case label now. This is
+ // handled above.
+ // case xx: if ( asdf &&
+ // asdf)
+ curwin->w_cursor = *trypos;
+ l = ml_get_curline();
+ if (cin_iscase(l, FALSE) || cin_isscopedecl(l))
+ {
+ ++curwin->w_cursor.lnum;
+ curwin->w_cursor.col = 0;
+ continue;
+ }
+ }
+
+ /*
+ * Skip over continuation lines to find the one to get the
+ * indent from
+ * char *usethis = "bla\
+ * bla",
+ * here;
+ */
+ if (terminated == ',')
+ {
+ while (curwin->w_cursor.lnum > 1)
+ {
+ l = ml_get(curwin->w_cursor.lnum - 1);
+ if (*l == NUL || l[STRLEN(l) - 1] != '\\')
+ break;
+ --curwin->w_cursor.lnum;
+ curwin->w_cursor.col = 0;
+ }
+ }
+
+ // Get indent and pointer to text for current line,
+ // ignoring any jump label. XXX
+ if (curbuf->b_ind_js)
+ cur_amount = get_indent();
+ else
+ cur_amount = skip_label(curwin->w_cursor.lnum, &l);
+ // If this is just above the line we are indenting, and it
+ // starts with a '{', line it up with this line.
+ // while (not)
+ // -> {
+ // }
+ if (terminated != ',' && lookfor != LOOKFOR_TERM
+ && theline[0] == '{')
+ {
+ amount = cur_amount;
+ // Only add b_ind_open_extra when the current line
+ // doesn't start with a '{', which must have a match
+ // in the same line (scope is the same). Probably:
+ // { 1, 2 },
+ // -> { 3, 4 }
+ if (*skipwhite(l) != '{')
+ amount += curbuf->b_ind_open_extra;
+
+ if (curbuf->b_ind_cpp_baseclass && !curbuf->b_ind_js)
+ {
+ // have to look back, whether it is a cpp base
+ // class declaration or initialization
+ lookfor = LOOKFOR_CPP_BASECLASS;
+ continue;
+ }
+ break;
+ }
+
+ // Check if we are after an "if", "while", etc.
+ // Also allow " } else".
+ if (cin_is_cinword(l) || cin_iselse(skipwhite(l)))
+ {
+ // Found an unterminated line after an if (), line up
+ // with the last one.
+ // if (cond)
+ // 100 +
+ // -> here;
+ if (lookfor == LOOKFOR_UNTERM
+ || lookfor == LOOKFOR_ENUM_OR_INIT)
+ {
+ if (cont_amount > 0)
+ amount = cont_amount;
+ else
+ amount += ind_continuation;
+ break;
+ }
+
+ // If this is just above the line we are indenting, we
+ // are finished.
+ // while (not)
+ // -> here;
+ // Otherwise this indent can be used when the line
+ // before this is terminated.
+ // yyy;
+ // if (stat)
+ // while (not)
+ // xxx;
+ // -> here;
+ amount = cur_amount;
+ if (theline[0] == '{')
+ amount += curbuf->b_ind_open_extra;
+ if (lookfor != LOOKFOR_TERM)
+ {
+ amount += curbuf->b_ind_level
+ + curbuf->b_ind_no_brace;
+ break;
+ }
+
+ // Special trick: when expecting the while () after a
+ // do, line up with the while()
+ // do
+ // x = 1;
+ // -> here
+ l = skipwhite(ml_get_curline());
+ if (cin_isdo(l))
+ {
+ if (whilelevel == 0)
+ break;
+ --whilelevel;
+ }
+
+ // When searching for a terminated line, don't use the
+ // one between the "if" and the matching "else".
+ // Need to use the scope of this "else". XXX
+ // If whilelevel != 0 continue looking for a "do {".
+ if (cin_iselse(l) && whilelevel == 0)
+ {
+ // If we're looking at "} else", let's make sure we
+ // find the opening brace of the enclosing scope,
+ // not the one from "if () {".
+ if (*l == '}')
+ curwin->w_cursor.col =
+ (colnr_T)(l - ml_get_curline()) + 1;
+
+ if ((trypos = find_start_brace()) == NULL
+ || find_match(LOOKFOR_IF, trypos->lnum)
+ == FAIL)
+ break;
+ }
+ }
+
+ // If we're below an unterminated line that is not an
+ // "if" or something, we may line up with this line or
+ // add something for a continuation line, depending on
+ // the line before this one.
+ else
+ {
+ // Found two unterminated lines on a row, line up with
+ // the last one.
+ // c = 99 +
+ // 100 +
+ // -> here;
+ if (lookfor == LOOKFOR_UNTERM)
+ {
+ // When line ends in a comma add extra indent
+ if (terminated == ',')
+ amount += ind_continuation;
+ break;
+ }
+
+ if (lookfor == LOOKFOR_ENUM_OR_INIT)
+ {
+ // Found two lines ending in ',', lineup with the
+ // lowest one, but check for cpp base class
+ // declaration/initialization, if it is an
+ // opening brace or we are looking just for
+ // enumerations/initializations.
+ if (terminated == ',')
+ {
+ if (curbuf->b_ind_cpp_baseclass == 0)
+ break;
+
+ lookfor = LOOKFOR_CPP_BASECLASS;
+ continue;
+ }
+
+ // Ignore unterminated lines in between, but
+ // reduce indent.
+ if (amount > cur_amount)
+ amount = cur_amount;
+ }
+ else
+ {
+ // Found first unterminated line on a row, may
+ // line up with this line, remember its indent
+ // 100 +
+ // -> here;
+ l = ml_get_curline();
+ amount = cur_amount;
+
+ n = (int)STRLEN(l);
+ if (terminated == ',' && (*skipwhite(l) == ']'
+ || (n >=2 && l[n - 2] == ']')))
+ break;
+
+ // If previous line ends in ',', check whether we
+ // are in an initialization or enum
+ // struct xxx =
+ // {
+ // sizeof a,
+ // 124 };
+ // or a normal possible continuation line.
+ // but only, of no other statement has been found
+ // yet.
+ if (lookfor == LOOKFOR_INITIAL && terminated == ',')
+ {
+ if (curbuf->b_ind_js)
+ {
+ // Search for a line ending in a comma
+ // and line up with the line below it
+ // (could be the current line).
+ // some = [
+ // 1, <- line up here
+ // 2,
+ // some = [
+ // 3 + <- line up here
+ // 4 *
+ // 5,
+ // 6,
+ if (cin_iscomment(skipwhite(l)))
+ break;
+ lookfor = LOOKFOR_COMMA;
+ trypos = find_match_char('[',
+ curbuf->b_ind_maxparen);
+ if (trypos != NULL)
+ {
+ if (trypos->lnum
+ == curwin->w_cursor.lnum - 1)
+ {
+ // Current line is first inside
+ // [], line up with it.
+ break;
+ }
+ ourscope = trypos->lnum;
+ }
+ }
+ else
+ {
+ lookfor = LOOKFOR_ENUM_OR_INIT;
+ cont_amount = cin_first_id_amount();
+ }
+ }
+ else
+ {
+ if (lookfor == LOOKFOR_INITIAL
+ && *l != NUL
+ && l[STRLEN(l) - 1] == '\\')
+ // XXX
+ cont_amount = cin_get_equal_amount(
+ curwin->w_cursor.lnum);
+ if (lookfor != LOOKFOR_TERM
+ && lookfor != LOOKFOR_JS_KEY
+ && lookfor != LOOKFOR_COMMA
+ && raw_string_start != curwin->w_cursor.lnum)
+ lookfor = LOOKFOR_UNTERM;
+ }
+ }
+ }
+ }
+
+ // Check if we are after a while (cond);
+ // If so: Ignore until the matching "do".
+ else if (cin_iswhileofdo_end(terminated)) // XXX
+ {
+ // Found an unterminated line after a while ();, line up
+ // with the last one.
+ // while (cond);
+ // 100 + <- line up with this one
+ // -> here;
+ if (lookfor == LOOKFOR_UNTERM
+ || lookfor == LOOKFOR_ENUM_OR_INIT)
+ {
+ if (cont_amount > 0)
+ amount = cont_amount;
+ else
+ amount += ind_continuation;
+ break;
+ }
+
+ if (whilelevel == 0)
+ {
+ lookfor = LOOKFOR_TERM;
+ amount = get_indent(); // XXX
+ if (theline[0] == '{')
+ amount += curbuf->b_ind_open_extra;
+ }
+ ++whilelevel;
+ }
+
+ // We are after a "normal" statement.
+ // If we had another statement we can stop now and use the
+ // indent of that other statement.
+ // Otherwise the indent of the current statement may be used,
+ // search backwards for the next "normal" statement.
+ else
+ {
+ // Skip single break line, if before a switch label. It
+ // may be lined up with the case label.
+ if (lookfor == LOOKFOR_NOBREAK
+ && cin_isbreak(skipwhite(ml_get_curline())))
+ {
+ lookfor = LOOKFOR_ANY;
+ continue;
+ }
+
+ // Handle "do {" line.
+ if (whilelevel > 0)
+ {
+ l = cin_skipcomment(ml_get_curline());
+ if (cin_isdo(l))
+ {
+ amount = get_indent(); // XXX
+ --whilelevel;
+ continue;
+ }
+ }
+
+ // Found a terminated line above an unterminated line. Add
+ // the amount for a continuation line.
+ // x = 1;
+ // y = foo +
+ // -> here;
+ // or
+ // int x = 1;
+ // int foo,
+ // -> here;
+ if (lookfor == LOOKFOR_UNTERM
+ || lookfor == LOOKFOR_ENUM_OR_INIT)
+ {
+ if (cont_amount > 0)
+ amount = cont_amount;
+ else
+ amount += ind_continuation;
+ break;
+ }
+
+ // Found a terminated line above a terminated line or "if"
+ // etc. line. Use the amount of the line below us.
+ // x = 1; x = 1;
+ // if (asdf) y = 2;
+ // while (asdf) ->here;
+ // here;
+ // ->foo;
+ if (lookfor == LOOKFOR_TERM)
+ {
+ if (!lookfor_break && whilelevel == 0)
+ break;
+ }
+
+ // First line above the one we're indenting is terminated.
+ // To know what needs to be done look further backward for
+ // a terminated line.
+ else
+ {
+ // position the cursor over the rightmost paren, so
+ // that matching it will take us back to the start of
+ // the line. Helps for:
+ // func(asdr,
+ // asdfasdf);
+ // here;
+term_again:
+ l = ml_get_curline();
+ if (find_last_paren(l, '(', ')')
+ && (trypos = find_match_paren(
+ curbuf->b_ind_maxparen)) != NULL)
+ {
+ // Check if we are on a case label now. This is
+ // handled above.
+ // case xx: if ( asdf &&
+ // asdf)
+ curwin->w_cursor = *trypos;
+ l = ml_get_curline();
+ if (cin_iscase(l, FALSE) || cin_isscopedecl(l))
+ {
+ ++curwin->w_cursor.lnum;
+ curwin->w_cursor.col = 0;
+ continue;
+ }
+ }
+
+ // When aligning with the case statement, don't align
+ // with a statement after it.
+ // case 1: { <-- don't use this { position
+ // stat;
+ // }
+ // case 2:
+ // stat;
+ // }
+ iscase = (curbuf->b_ind_keep_case_label
+ && cin_iscase(l, FALSE));
+
+ // Get indent and pointer to text for current line,
+ // ignoring any jump label.
+ amount = skip_label(curwin->w_cursor.lnum, &l);
+
+ if (theline[0] == '{')
+ amount += curbuf->b_ind_open_extra;
+ // See remark above: "Only add b_ind_open_extra.."
+ l = skipwhite(l);
+ if (*l == '{')
+ amount -= curbuf->b_ind_open_extra;
+ lookfor = iscase ? LOOKFOR_ANY : LOOKFOR_TERM;
+
+ // When a terminated line starts with "else" skip to
+ // the matching "if":
+ // else 3;
+ // indent this;
+ // Need to use the scope of this "else". XXX
+ // If whilelevel != 0 continue looking for a "do {".
+ if (lookfor == LOOKFOR_TERM
+ && *l != '}'
+ && cin_iselse(l)
+ && whilelevel == 0)
+ {
+ if ((trypos = find_start_brace()) == NULL
+ || find_match(LOOKFOR_IF, trypos->lnum)
+ == FAIL)
+ break;
+ continue;
+ }
+
+ // If we're at the end of a block, skip to the start of
+ // that block.
+ l = ml_get_curline();
+ if (find_last_paren(l, '{', '}') // XXX
+ && (trypos = find_start_brace()) != NULL)
+ {
+ curwin->w_cursor = *trypos;
+ // if not "else {" check for terminated again
+ // but skip block for "} else {"
+ l = cin_skipcomment(ml_get_curline());
+ if (*l == '}' || !cin_iselse(l))
+ goto term_again;
+ ++curwin->w_cursor.lnum;
+ curwin->w_cursor.col = 0;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // add extra indent for a comment
+ if (cin_iscomment(theline))
+ amount += curbuf->b_ind_comment;
+
+ // subtract extra left-shift for jump labels
+ if (curbuf->b_ind_jump_label > 0 && original_line_islabel)
+ amount -= curbuf->b_ind_jump_label;
+
+ goto theend;
+ }
+
+ // ok -- we're not inside any sort of structure at all!
+ //
+ // This means we're at the top level, and everything should
+ // basically just match where the previous line is, except
+ // for the lines immediately following a function declaration,
+ // which are K&R-style parameters and need to be indented.
+ //
+ // if our line starts with an open brace, forget about any
+ // prevailing indent and make sure it looks like the start
+ // of a function
+
+ if (theline[0] == '{')
+ {
+ amount = curbuf->b_ind_first_open;
+ goto theend;
+ }
+
+ // If the NEXT line is a function declaration, the current
+ // line needs to be indented as a function type spec.
+ // Don't do this if the current line looks like a comment or if the
+ // current line is terminated, ie. ends in ';', or if the current line
+ // contains { or }: "void f() {\n if (1)"
+ if (cur_curpos.lnum < curbuf->b_ml.ml_line_count
+ && !cin_nocode(theline)
+ && vim_strchr(theline, '{') == NULL
+ && vim_strchr(theline, '}') == NULL
+ && !cin_ends_in(theline, (char_u *)":", NULL)
+ && !cin_ends_in(theline, (char_u *)",", NULL)
+ && cin_isfuncdecl(NULL, cur_curpos.lnum + 1,
+ cur_curpos.lnum + 1)
+ && !cin_isterminated(theline, FALSE, TRUE))
+ {
+ amount = curbuf->b_ind_func_type;
+ goto theend;
+ }
+
+ // search backwards until we find something we recognize
+ amount = 0;
+ curwin->w_cursor = cur_curpos;
+ while (curwin->w_cursor.lnum > 1)
+ {
+ curwin->w_cursor.lnum--;
+ curwin->w_cursor.col = 0;
+
+ l = ml_get_curline();
+
+ // If we're in a comment or raw string now, skip to the start
+ // of it. XXX
+ if ((trypos = ind_find_start_CORS(NULL)) != NULL)
+ {
+ curwin->w_cursor.lnum = trypos->lnum + 1;
+ curwin->w_cursor.col = 0;
+ continue;
+ }
+
+ // Are we at the start of a cpp base class declaration or
+ // constructor initialization? XXX
+ n = FALSE;
+ if (curbuf->b_ind_cpp_baseclass != 0 && theline[0] != '{')
+ {
+ n = cin_is_cpp_baseclass(&cache_cpp_baseclass);
+ l = ml_get_curline();
+ }
+ if (n)
+ {
+ // XXX
+ amount = get_baseclass_amount(cache_cpp_baseclass.lpos.col);
+ break;
+ }
+
+ // Skip preprocessor directives and blank lines.
+ if (cin_ispreproc_cont(&l, &curwin->w_cursor.lnum, &amount))
+ continue;
+
+ if (cin_nocode(l))
+ continue;
+
+ // If the previous line ends in ',', use one level of
+ // indentation:
+ // int foo,
+ // bar;
+ // do this before checking for '}' in case of eg.
+ // enum foobar
+ // {
+ // ...
+ // } foo,
+ // bar;
+ n = 0;
+ if (cin_ends_in(l, (char_u *)",", NULL)
+ || (*l != NUL && (n = l[STRLEN(l) - 1]) == '\\'))
+ {
+ // take us back to opening paren
+ if (find_last_paren(l, '(', ')')
+ && (trypos = find_match_paren(
+ curbuf->b_ind_maxparen)) != NULL)
+ curwin->w_cursor = *trypos;
+
+ /*
+ * For a line ending in ',' that is a continuation line go
+ * back to the first line with a backslash:
+ * char *foo = "bla\
+ * bla",
+ * here;
+ */
+ while (n == 0 && curwin->w_cursor.lnum > 1)
+ {
+ l = ml_get(curwin->w_cursor.lnum - 1);
+ if (*l == NUL || l[STRLEN(l) - 1] != '\\')
+ break;
+ --curwin->w_cursor.lnum;
+ curwin->w_cursor.col = 0;
+ }
+
+ amount = get_indent(); // XXX
+
+ if (amount == 0)
+ amount = cin_first_id_amount();
+ if (amount == 0)
+ amount = ind_continuation;
+ break;
+ }
+
+ // If the line looks like a function declaration, and we're
+ // not in a comment, put it the left margin.
+ if (cin_isfuncdecl(NULL, cur_curpos.lnum, 0)) // XXX
+ break;
+ l = ml_get_curline();
+
+ // Finding the closing '}' of a previous function. Put
+ // current line at the left margin. For when 'cino' has "fs".
+ if (*skipwhite(l) == '}')
+ break;
+
+ // (matching {)
+ // If the previous line ends on '};' (maybe followed by
+ // comments) align at column 0. For example:
+ // char *string_array[] = { "foo",
+ // / * x * / "b};ar" }; / * foobar * /
+ if (cin_ends_in(l, (char_u *)"};", NULL))
+ break;
+
+ // If the previous line ends on '[' we are probably in an
+ // array constant:
+ // something = [
+ // 234, <- extra indent
+ if (cin_ends_in(l, (char_u *)"[", NULL))
+ {
+ amount = get_indent() + ind_continuation;
+ break;
+ }
+
+ // Find a line only has a semicolon that belongs to a previous
+ // line ending in '}', e.g. before an #endif. Don't increase
+ // indent then.
+ if (*(look = skipwhite(l)) == ';' && cin_nocode(look + 1))
+ {
+ pos_T curpos_save = curwin->w_cursor;
+
+ while (curwin->w_cursor.lnum > 1)
+ {
+ look = ml_get(--curwin->w_cursor.lnum);
+ if (!(cin_nocode(look) || cin_ispreproc_cont(
+ &look, &curwin->w_cursor.lnum, &amount)))
+ break;
+ }
+ if (curwin->w_cursor.lnum > 0
+ && cin_ends_in(look, (char_u *)"}", NULL))
+ break;
+
+ curwin->w_cursor = curpos_save;
+ }
+
+ // If the PREVIOUS line is a function declaration, the current
+ // line (and the ones that follow) needs to be indented as
+ // parameters.
+ if (cin_isfuncdecl(&l, curwin->w_cursor.lnum, 0))
+ {
+ amount = curbuf->b_ind_param;
+ break;
+ }
+
+ // If the previous line ends in ';' and the line before the
+ // previous line ends in ',' or '\', ident to column zero:
+ // int foo,
+ // bar;
+ // indent_to_0 here;
+ if (cin_ends_in(l, (char_u *)";", NULL))
+ {
+ l = ml_get(curwin->w_cursor.lnum - 1);
+ if (cin_ends_in(l, (char_u *)",", NULL)
+ || (*l != NUL && l[STRLEN(l) - 1] == '\\'))
+ break;
+ l = ml_get_curline();
+ }
+
+ // Doesn't look like anything interesting -- so just
+ // use the indent of this line.
+ //
+ // Position the cursor over the rightmost paren, so that
+ // matching it will take us back to the start of the line.
+ find_last_paren(l, '(', ')');
+
+ if ((trypos = find_match_paren(curbuf->b_ind_maxparen)) != NULL)
+ curwin->w_cursor = *trypos;
+ amount = get_indent(); // XXX
+ break;
+ }
+
+ // add extra indent for a comment
+ if (cin_iscomment(theline))
+ amount += curbuf->b_ind_comment;
+
+ /*
+ * add extra indent if the previous line ended in a backslash:
+ * "asdfasdf\
+ * here";
+ * char *foo = "asdf\
+ * here";
+ */
+ if (cur_curpos.lnum > 1)
+ {
+ l = ml_get(cur_curpos.lnum - 1);
+ if (*l != NUL && l[STRLEN(l) - 1] == '\\')
+ {
+ cur_amount = cin_get_equal_amount(cur_curpos.lnum - 1);
+ if (cur_amount > 0)
+ amount = cur_amount;
+ else if (cur_amount == 0)
+ amount += ind_continuation;
+ }
+ }
+
+theend:
+ if (amount < 0)
+ amount = 0;
+
+laterend:
+ // put the cursor back where it belongs
+ curwin->w_cursor = cur_curpos;
+
+ vim_free(linecopy);
+
+ return amount;
+}
+
+ static int
+find_match(int lookfor, linenr_T ourscope)
+{
+ char_u *look;
+ pos_T *theirscope;
+ char_u *mightbeif;
+ int elselevel;
+ int whilelevel;
+
+ if (lookfor == LOOKFOR_IF)
+ {
+ elselevel = 1;
+ whilelevel = 0;
+ }
+ else
+ {
+ elselevel = 0;
+ whilelevel = 1;
+ }
+
+ curwin->w_cursor.col = 0;
+
+ while (curwin->w_cursor.lnum > ourscope + 1)
+ {
+ curwin->w_cursor.lnum--;
+ curwin->w_cursor.col = 0;
+
+ look = cin_skipcomment(ml_get_curline());
+ if (cin_iselse(look)
+ || cin_isif(look)
+ || cin_isdo(look) // XXX
+ || cin_iswhileofdo(look, curwin->w_cursor.lnum))
+ {
+ // if we've gone outside the braces entirely,
+ // we must be out of scope...
+ theirscope = find_start_brace(); // XXX
+ if (theirscope == NULL)
+ break;
+
+ // and if the brace enclosing this is further
+ // back than the one enclosing the else, we're
+ // out of luck too.
+ if (theirscope->lnum < ourscope)
+ break;
+
+ // and if they're enclosed in a *deeper* brace,
+ // then we can ignore it because it's in a
+ // different scope...
+ if (theirscope->lnum > ourscope)
+ continue;
+
+ // if it was an "else" (that's not an "else if")
+ // then we need to go back to another if, so
+ // increment elselevel
+ look = cin_skipcomment(ml_get_curline());
+ if (cin_iselse(look))
+ {
+ mightbeif = cin_skipcomment(look + 4);
+ if (!cin_isif(mightbeif))
+ ++elselevel;
+ continue;
+ }
+
+ // if it was a "while" then we need to go back to
+ // another "do", so increment whilelevel. XXX
+ if (cin_iswhileofdo(look, curwin->w_cursor.lnum))
+ {
+ ++whilelevel;
+ continue;
+ }
+
+ // If it's an "if" decrement elselevel
+ look = cin_skipcomment(ml_get_curline());
+ if (cin_isif(look))
+ {
+ elselevel--;
+ // When looking for an "if" ignore "while"s that
+ // get in the way.
+ if (elselevel == 0 && lookfor == LOOKFOR_IF)
+ whilelevel = 0;
+ }
+
+ // If it's a "do" decrement whilelevel
+ if (cin_isdo(look))
+ whilelevel--;
+
+ // if we've used up all the elses, then
+ // this must be the if that we want!
+ // match the indent level of that if.
+ if (elselevel <= 0 && whilelevel <= 0)
+ {
+ return OK;
+ }
+ }
+ }
+ return FAIL;
+}
+
+# if defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * Get indent level from 'indentexpr'.
+ */
+ int
+get_expr_indent(void)
+{
+ int indent = -1;
+ char_u *inde_copy;
+ pos_T save_pos;
+ colnr_T save_curswant;
+ int save_set_curswant;
+ int save_State;
+ int use_sandbox = was_set_insecurely((char_u *)"indentexpr",
+ OPT_LOCAL);
+
+ // Save and restore cursor position and curswant, in case it was changed
+ // via :normal commands
+ save_pos = curwin->w_cursor;
+ save_curswant = curwin->w_curswant;
+ save_set_curswant = curwin->w_set_curswant;
+ set_vim_var_nr(VV_LNUM, curwin->w_cursor.lnum);
+ if (use_sandbox)
+ ++sandbox;
+ ++textlock;
+
+ // Need to make a copy, the 'indentexpr' option could be changed while
+ // evaluating it.
+ inde_copy = vim_strsave(curbuf->b_p_inde);
+ if (inde_copy != NULL)
+ {
+ indent = (int)eval_to_number(inde_copy);
+ vim_free(inde_copy);
+ }
+
+ if (use_sandbox)
+ --sandbox;
+ --textlock;
+
+ // Restore the cursor position so that 'indentexpr' doesn't need to.
+ // Pretend to be in Insert mode, allow cursor past end of line for "o"
+ // command.
+ save_State = State;
+ State = INSERT;
+ curwin->w_cursor = save_pos;
+ curwin->w_curswant = save_curswant;
+ curwin->w_set_curswant = save_set_curswant;
+ check_cursor();
+ State = save_State;
+
+ // If there is an error, just keep the current indent.
+ if (indent < 0)
+ indent = get_indent();
+
+ return indent;
+}
+# endif
+
+/*
+ * return TRUE if 'cinkeys' contains the key "keytyped",
+ * when == '*': Only if key is preceded with '*' (indent before insert)
+ * when == '!': Only if key is preceded with '!' (don't insert)
+ * when == ' ': Only if key is not preceded with '*'(indent afterwards)
+ *
+ * "keytyped" can have a few special values:
+ * KEY_OPEN_FORW
+ * KEY_OPEN_BACK
+ * KEY_COMPLETE just finished completion.
+ *
+ * If line_is_empty is TRUE accept keys with '0' before them.
+ */
+ int
+in_cinkeys(
+ int keytyped,
+ int when,
+ int line_is_empty)
+{
+ char_u *look;
+ int try_match;
+ int try_match_word;
+ char_u *p;
+ char_u *line;
+ int icase;
+ int i;
+
+ if (keytyped == NUL)
+ // Can happen with CTRL-Y and CTRL-E on a short line.
+ return FALSE;
+
+#ifdef FEAT_EVAL
+ if (*curbuf->b_p_inde != NUL)
+ look = curbuf->b_p_indk; // 'indentexpr' set: use 'indentkeys'
+ else
+#endif
+ look = curbuf->b_p_cink; // 'indentexpr' empty: use 'cinkeys'
+ while (*look)
+ {
+ // Find out if we want to try a match with this key, depending on
+ // 'when' and a '*' or '!' before the key.
+ switch (when)
+ {
+ case '*': try_match = (*look == '*'); break;
+ case '!': try_match = (*look == '!'); break;
+ default: try_match = (*look != '*'); break;
+ }
+ if (*look == '*' || *look == '!')
+ ++look;
+
+ // If there is a '0', only accept a match if the line is empty.
+ // But may still match when typing last char of a word.
+ if (*look == '0')
+ {
+ try_match_word = try_match;
+ if (!line_is_empty)
+ try_match = FALSE;
+ ++look;
+ }
+ else
+ try_match_word = FALSE;
+
+ // does it look like a control character?
+ if (*look == '^'
+#ifdef EBCDIC
+ && (Ctrl_chr(look[1]) != 0)
+#else
+ && look[1] >= '?' && look[1] <= '_'
+#endif
+ )
+ {
+ if (try_match && keytyped == Ctrl_chr(look[1]))
+ return TRUE;
+ look += 2;
+ }
+ // 'o' means "o" command, open forward.
+ // 'O' means "O" command, open backward.
+ else if (*look == 'o')
+ {
+ if (try_match && keytyped == KEY_OPEN_FORW)
+ return TRUE;
+ ++look;
+ }
+ else if (*look == 'O')
+ {
+ if (try_match && keytyped == KEY_OPEN_BACK)
+ return TRUE;
+ ++look;
+ }
+
+ // 'e' means to check for "else" at start of line and just before the
+ // cursor.
+ else if (*look == 'e')
+ {
+ if (try_match && keytyped == 'e' && curwin->w_cursor.col >= 4)
+ {
+ p = ml_get_curline();
+ if (skipwhite(p) == p + curwin->w_cursor.col - 4 &&
+ STRNCMP(p + curwin->w_cursor.col - 4, "else", 4) == 0)
+ return TRUE;
+ }
+ ++look;
+ }
+
+ // ':' only causes an indent if it is at the end of a label or case
+ // statement, or when it was before typing the ':' (to fix
+ // class::method for C++).
+ else if (*look == ':')
+ {
+ if (try_match && keytyped == ':')
+ {
+ p = ml_get_curline();
+ if (cin_iscase(p, FALSE) || cin_isscopedecl(p) || cin_islabel())
+ return TRUE;
+ // Need to get the line again after cin_islabel().
+ p = ml_get_curline();
+ if (curwin->w_cursor.col > 2
+ && p[curwin->w_cursor.col - 1] == ':'
+ && p[curwin->w_cursor.col - 2] == ':')
+ {
+ p[curwin->w_cursor.col - 1] = ' ';
+ i = (cin_iscase(p, FALSE) || cin_isscopedecl(p)
+ || cin_islabel());
+ p = ml_get_curline();
+ p[curwin->w_cursor.col - 1] = ':';
+ if (i)
+ return TRUE;
+ }
+ }
+ ++look;
+ }
+
+
+ // Is it a key in <>, maybe?
+ else if (*look == '<')
+ {
+ if (try_match)
+ {
+ // make up some named keys <o>, <O>, <e>, <0>, <>>, <<>, <*>,
+ // <:> and <!> so that people can re-indent on o, O, e, 0, <,
+ // >, *, : and ! keys if they really really want to.
+ if (vim_strchr((char_u *)"<>!*oOe0:", look[1]) != NULL
+ && keytyped == look[1])
+ return TRUE;
+
+ if (keytyped == get_special_key_code(look + 1))
+ return TRUE;
+ }
+ while (*look && *look != '>')
+ look++;
+ while (*look == '>')
+ look++;
+ }
+
+ // Is it a word: "=word"?
+ else if (*look == '=' && look[1] != ',' && look[1] != NUL)
+ {
+ ++look;
+ if (*look == '~')
+ {
+ icase = TRUE;
+ ++look;
+ }
+ else
+ icase = FALSE;
+ p = vim_strchr(look, ',');
+ if (p == NULL)
+ p = look + STRLEN(look);
+ if ((try_match || try_match_word)
+ && curwin->w_cursor.col >= (colnr_T)(p - look))
+ {
+ int match = FALSE;
+
+#ifdef FEAT_INS_EXPAND
+ if (keytyped == KEY_COMPLETE)
+ {
+ char_u *s;
+
+ // Just completed a word, check if it starts with "look".
+ // search back for the start of a word.
+ line = ml_get_curline();
+ if (has_mbyte)
+ {
+ char_u *n;
+
+ for (s = line + curwin->w_cursor.col; s > line; s = n)
+ {
+ n = mb_prevptr(line, s);
+ if (!vim_iswordp(n))
+ break;
+ }
+ }
+ else
+ for (s = line + curwin->w_cursor.col; s > line; --s)
+ if (!vim_iswordc(s[-1]))
+ break;
+ if (s + (p - look) <= line + curwin->w_cursor.col
+ && (icase
+ ? MB_STRNICMP(s, look, p - look)
+ : STRNCMP(s, look, p - look)) == 0)
+ match = TRUE;
+ }
+ else
+#endif
+ // TODO: multi-byte
+ if (keytyped == (int)p[-1] || (icase && keytyped < 256
+ && TOLOWER_LOC(keytyped) == TOLOWER_LOC((int)p[-1])))
+ {
+ line = ml_get_cursor();
+ if ((curwin->w_cursor.col == (colnr_T)(p - look)
+ || !vim_iswordc(line[-(p - look) - 1]))
+ && (icase
+ ? MB_STRNICMP(line - (p - look), look, p - look)
+ : STRNCMP(line - (p - look), look, p - look))
+ == 0)
+ match = TRUE;
+ }
+ if (match && try_match_word && !try_match)
+ {
+ // "0=word": Check if there are only blanks before the
+ // word.
+ if (getwhitecols_curline() !=
+ (int)(curwin->w_cursor.col - (p - look)))
+ match = FALSE;
+ }
+ if (match)
+ return TRUE;
+ }
+ look = p;
+ }
+
+ // ok, it's a boring generic character.
+ else
+ {
+ if (try_match && *look == keytyped)
+ return TRUE;
+ if (*look != NUL)
+ ++look;
+ }
+
+ // Skip over ", ".
+ look = skip_to_option_part(look);
+ }
+ return FALSE;
+}
+#endif // FEAT_CINDENT
+
+#if defined(FEAT_LISP) || defined(PROTO)
+
+ static int
+lisp_match(char_u *p)
+{
+ char_u buf[LSIZE];
+ int len;
+ char_u *word = *curbuf->b_p_lw != NUL ? curbuf->b_p_lw : p_lispwords;
+
+ while (*word != NUL)
+ {
+ (void)copy_option_part(&word, buf, LSIZE, ",");
+ len = (int)STRLEN(buf);
+ if (STRNCMP(buf, p, len) == 0 && p[len] == ' ')
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * When 'p' is present in 'cpoptions, a Vi compatible method is used.
+ * The incompatible newer method is quite a bit better at indenting
+ * code in lisp-like languages than the traditional one; it's still
+ * mostly heuristics however -- Dirk van Deun, dirk@rave.org
+ *
+ * TODO:
+ * Findmatch() should be adapted for lisp, also to make showmatch
+ * work correctly: now (v5.3) it seems all C/C++ oriented:
+ * - it does not recognize the #\( and #\) notations as character literals
+ * - it doesn't know about comments starting with a semicolon
+ * - it incorrectly interprets '(' as a character literal
+ * All this messes up get_lisp_indent in some rare cases.
+ * Update from Sergey Khorev:
+ * I tried to fix the first two issues.
+ */
+ int
+get_lisp_indent(void)
+{
+ pos_T *pos, realpos, paren;
+ int amount;
+ char_u *that;
+ colnr_T col;
+ colnr_T firsttry;
+ int parencount, quotecount;
+ int vi_lisp;
+
+ // Set vi_lisp to use the vi-compatible method
+ vi_lisp = (vim_strchr(p_cpo, CPO_LISP) != NULL);
+
+ realpos = curwin->w_cursor;
+ curwin->w_cursor.col = 0;
+
+ if ((pos = findmatch(NULL, '(')) == NULL)
+ pos = findmatch(NULL, '[');
+ else
+ {
+ paren = *pos;
+ pos = findmatch(NULL, '[');
+ if (pos == NULL || LT_POSP(pos, &paren))
+ pos = &paren;
+ }
+ if (pos != NULL)
+ {
+ // Extra trick: Take the indent of the first previous non-white
+ // line that is at the same () level.
+ amount = -1;
+ parencount = 0;
+
+ while (--curwin->w_cursor.lnum >= pos->lnum)
+ {
+ if (linewhite(curwin->w_cursor.lnum))
+ continue;
+ for (that = ml_get_curline(); *that != NUL; ++that)
+ {
+ if (*that == ';')
+ {
+ while (*(that + 1) != NUL)
+ ++that;
+ continue;
+ }
+ if (*that == '\\')
+ {
+ if (*(that + 1) != NUL)
+ ++that;
+ continue;
+ }
+ if (*that == '"' && *(that + 1) != NUL)
+ {
+ while (*++that && *that != '"')
+ {
+ // skipping escaped characters in the string
+ if (*that == '\\')
+ {
+ if (*++that == NUL)
+ break;
+ if (that[1] == NUL)
+ {
+ ++that;
+ break;
+ }
+ }
+ }
+ }
+ if (*that == '(' || *that == '[')
+ ++parencount;
+ else if (*that == ')' || *that == ']')
+ --parencount;
+ }
+ if (parencount == 0)
+ {
+ amount = get_indent();
+ break;
+ }
+ }
+
+ if (amount == -1)
+ {
+ curwin->w_cursor.lnum = pos->lnum;
+ curwin->w_cursor.col = pos->col;
+ col = pos->col;
+
+ that = ml_get_curline();
+
+ if (vi_lisp && get_indent() == 0)
+ amount = 2;
+ else
+ {
+ char_u *line = that;
+
+ amount = 0;
+ while (*that && col)
+ {
+ amount += lbr_chartabsize_adv(line, &that, (colnr_T)amount);
+ col--;
+ }
+
+ // Some keywords require "body" indenting rules (the
+ // non-standard-lisp ones are Scheme special forms):
+ //
+ // (let ((a 1)) instead (let ((a 1))
+ // (...)) of (...))
+
+ if (!vi_lisp && (*that == '(' || *that == '[')
+ && lisp_match(that + 1))
+ amount += 2;
+ else
+ {
+ that++;
+ amount++;
+ firsttry = amount;
+
+ while (VIM_ISWHITE(*that))
+ {
+ amount += lbr_chartabsize(line, that, (colnr_T)amount);
+ ++that;
+ }
+
+ if (*that && *that != ';') // not a comment line
+ {
+ // test *that != '(' to accommodate first let/do
+ // argument if it is more than one line
+ if (!vi_lisp && *that != '(' && *that != '[')
+ firsttry++;
+
+ parencount = 0;
+ quotecount = 0;
+
+ if (vi_lisp
+ || (*that != '"'
+ && *that != '\''
+ && *that != '#'
+ && (*that < '0' || *that > '9')))
+ {
+ while (*that
+ && (!VIM_ISWHITE(*that)
+ || quotecount
+ || parencount)
+ && (!((*that == '(' || *that == '[')
+ && !quotecount
+ && !parencount
+ && vi_lisp)))
+ {
+ if (*that == '"')
+ quotecount = !quotecount;
+ if ((*that == '(' || *that == '[')
+ && !quotecount)
+ ++parencount;
+ if ((*that == ')' || *that == ']')
+ && !quotecount)
+ --parencount;
+ if (*that == '\\' && *(that+1) != NUL)
+ amount += lbr_chartabsize_adv(
+ line, &that, (colnr_T)amount);
+ amount += lbr_chartabsize_adv(
+ line, &that, (colnr_T)amount);
+ }
+ }
+ while (VIM_ISWHITE(*that))
+ {
+ amount += lbr_chartabsize(
+ line, that, (colnr_T)amount);
+ that++;
+ }
+ if (!*that || *that == ';')
+ amount = firsttry;
+ }
+ }
+ }
+ }
+ }
+ else
+ amount = 0; // no matching '(' or '[' found, use zero indent
+
+ curwin->w_cursor = realpos;
+
+ return amount;
+}
+#endif // FEAT_LISP
+
+#if defined(FEAT_CINDENT) || defined(PROTO)
+/*
+ * Do C or expression indenting on the current line.
+ */
+ void
+do_c_expr_indent(void)
+{
+# ifdef FEAT_EVAL
+ if (*curbuf->b_p_inde != NUL)
+ fixthisline(get_expr_indent);
+ else
+# endif
+ fixthisline(get_c_indent);
+}
+#endif
+
+#if defined(FEAT_LISP) || defined(FEAT_CINDENT) || defined(PROTO)
+/*
+ * Re-indent the current line, based on the current contents of it and the
+ * surrounding lines. Fixing the cursor position seems really easy -- I'm very
+ * confused what all the part that handles Control-T is doing that I'm not.
+ * "get_the_indent" should be get_c_indent, get_expr_indent or get_lisp_indent.
+ */
+
+ void
+fixthisline(int (*get_the_indent)(void))
+{
+ int amount = get_the_indent();
+
+ if (amount >= 0)
+ {
+ change_indent(INDENT_SET, amount, FALSE, 0, TRUE);
+ if (linewhite(curwin->w_cursor.lnum))
+ did_ai = TRUE; // delete the indent if the line stays empty
+ }
+}
+
+ void
+fix_indent(void)
+{
+ if (p_paste)
+ return;
+# ifdef FEAT_LISP
+ if (curbuf->b_p_lisp && curbuf->b_p_ai)
+ fixthisline(get_lisp_indent);
+# endif
+# if defined(FEAT_LISP) && defined(FEAT_CINDENT)
+ else
+# endif
+# ifdef FEAT_CINDENT
+ if (cindent_on())
+ do_c_expr_indent();
+# endif
+}
+
+#endif
diff --git a/src/infplist.xml b/src/infplist.xml
new file mode 100644
index 0000000..c58cf74
--- /dev/null
+++ b/src/infplist.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vim:set ts=2 sts=2 sw=2 tw=0: -->
+<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
+<plist version="0.9">
+ <dict>
+
+ <key>CFBundleIdentifier</key>
+ <string>org.vim.Vim-APP_VER</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+
+ <key>CFBundleExecutable</key>
+ <string>APP_EXE</string>
+ <key>CFBundleName</key>
+ <string>APP_NAME</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleVersion</key>
+ <string>APP_VER</string>
+ <key>CFBundleShortVersionString</key>
+ <string>APP_VER</string>
+ <key>CFBundleSignature</key>
+ <string>VIM!</string>
+
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CSResourcesFileMapped</key>
+ <true/>
+ <key>CFBundleIconFile</key>
+ <string>app.icns</string>
+
+ <key>CFBundleDocumentTypes</key>
+ <array>
+ <dict>
+ <key>CFBundleTypeExtensions</key>
+ <array>
+ <string>txt</string>
+ <string>text</string>
+ </array>
+ <key>CFBundleTypeMIMETypes</key>
+ <array>
+ <string>text/plain</string>
+ </array>
+ <key>CFBundleTypeIconFile</key>
+ <string>doc-txt.icns</string>
+ <key>CFBundleTypeName</key>
+ <string>Text File</string>
+ <key>CFBundleTypeRole</key>
+ <string>Editor</string>
+ </dict>
+ <dict>
+ <key>CFBundleTypeExtensions</key>
+ <array>
+ <string>*</string>
+ </array>
+ <key>CFBundleTypeMIMETypes</key>
+ <array>
+ <string>text/*</string>
+ </array>
+ <key>CFBundleTypeIconFile</key>
+ <string>doc.icns</string>
+ <key>CFBundleTypeName</key>
+ <string>File</string>
+ <key>CFBundleTypeOSTypes</key>
+ <array>
+ <string>****</string>
+ </array>
+ <key>CFBundleTypeRole</key>
+ <string>Editor</string>
+ </dict>
+ </array>
+
+ </dict>
+</plist>
diff --git a/src/install-sh b/src/install-sh
new file mode 100644
index 0000000..0b0fdcb
--- /dev/null
+++ b/src/install-sh
@@ -0,0 +1,501 @@
+#!/bin/sh
+# install - install a program, script, or datafile
+
+scriptversion=2013-12-25.23; # UTC
+
+# This originates from X11R5 (mit/util/scripts/install.sh), which was
+# later released in X11R6 (xc/config/util/install.sh) with the
+# following copyright and license.
+#
+# Copyright (C) 1994 X Consortium
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
+# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+# Except as contained in this notice, the name of the X Consortium shall not
+# be used in advertising or otherwise to promote the sale, use or other deal-
+# ings in this Software without prior written authorization from the X Consor-
+# tium.
+#
+#
+# FSF changes to this file are in the public domain.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# 'make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+
+tab=' '
+nl='
+'
+IFS=" $tab$nl"
+
+# Set DOITPROG to "echo" to test this script.
+
+doit=${DOITPROG-}
+doit_exec=${doit:-exec}
+
+# Put in absolute file names if you don't have them in your path;
+# or use environment vars.
+
+chgrpprog=${CHGRPPROG-chgrp}
+chmodprog=${CHMODPROG-chmod}
+chownprog=${CHOWNPROG-chown}
+cmpprog=${CMPPROG-cmp}
+cpprog=${CPPROG-cp}
+mkdirprog=${MKDIRPROG-mkdir}
+mvprog=${MVPROG-mv}
+rmprog=${RMPROG-rm}
+stripprog=${STRIPPROG-strip}
+
+posix_mkdir=
+
+# Desired mode of installed file.
+mode=0755
+
+chgrpcmd=
+chmodcmd=$chmodprog
+chowncmd=
+mvcmd=$mvprog
+rmcmd="$rmprog -f"
+stripcmd=
+
+src=
+dst=
+dir_arg=
+dst_arg=
+
+copy_on_change=false
+is_target_a_directory=possibly
+
+usage="\
+Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
+ or: $0 [OPTION]... SRCFILES... DIRECTORY
+ or: $0 [OPTION]... -t DIRECTORY SRCFILES...
+ or: $0 [OPTION]... -d DIRECTORIES...
+
+In the 1st form, copy SRCFILE to DSTFILE.
+In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
+In the 4th, create DIRECTORIES.
+
+Options:
+ --help display this help and exit.
+ --version display version info and exit.
+
+ -c (ignored)
+ -C install only if different (preserve the last data modification time)
+ -d create directories instead of installing files.
+ -g GROUP $chgrpprog installed files to GROUP.
+ -m MODE $chmodprog installed files to MODE.
+ -o USER $chownprog installed files to USER.
+ -s $stripprog installed files.
+ -t DIRECTORY install into DIRECTORY.
+ -T report an error if DSTFILE is a directory.
+
+Environment variables override the default commands:
+ CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
+ RMPROG STRIPPROG
+"
+
+while test $# -ne 0; do
+ case $1 in
+ -c) ;;
+
+ -C) copy_on_change=true;;
+
+ -d) dir_arg=true;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift;;
+
+ --help) echo "$usage"; exit $?;;
+
+ -m) mode=$2
+ case $mode in
+ *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*)
+ echo "$0: invalid mode: $mode" >&2
+ exit 1;;
+ esac
+ shift;;
+
+ -o) chowncmd="$chownprog $2"
+ shift;;
+
+ -s) stripcmd=$stripprog;;
+
+ -t)
+ is_target_a_directory=always
+ dst_arg=$2
+ # Protect names problematic for 'test' and other utilities.
+ case $dst_arg in
+ -* | [=\(\)!]) dst_arg=./$dst_arg;;
+ esac
+ shift;;
+
+ -T) is_target_a_directory=never;;
+
+ --version) echo "$0 $scriptversion"; exit $?;;
+
+ --) shift
+ break;;
+
+ -*) echo "$0: invalid option: $1" >&2
+ exit 1;;
+
+ *) break;;
+ esac
+ shift
+done
+
+# We allow the use of options -d and -T together, by making -d
+# take the precedence; this is for compatibility with GNU install.
+
+if test -n "$dir_arg"; then
+ if test -n "$dst_arg"; then
+ echo "$0: target directory not allowed when installing a directory." >&2
+ exit 1
+ fi
+fi
+
+if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
+ # When -d is used, all remaining arguments are directories to create.
+ # When -t is used, the destination is already specified.
+ # Otherwise, the last argument is the destination. Remove it from $@.
+ for arg
+ do
+ if test -n "$dst_arg"; then
+ # $@ is not empty: it contains at least $arg.
+ set fnord "$@" "$dst_arg"
+ shift # fnord
+ fi
+ shift # arg
+ dst_arg=$arg
+ # Protect names problematic for 'test' and other utilities.
+ case $dst_arg in
+ -* | [=\(\)!]) dst_arg=./$dst_arg;;
+ esac
+ done
+fi
+
+if test $# -eq 0; then
+ if test -z "$dir_arg"; then
+ echo "$0: no input file specified." >&2
+ exit 1
+ fi
+ # It's OK to call 'install-sh -d' without argument.
+ # This can happen when creating conditional directories.
+ exit 0
+fi
+
+if test -z "$dir_arg"; then
+ if test $# -gt 1 || test "$is_target_a_directory" = always; then
+ if test ! -d "$dst_arg"; then
+ echo "$0: $dst_arg: Is not a directory." >&2
+ exit 1
+ fi
+ fi
+fi
+
+if test -z "$dir_arg"; then
+ do_exit='(exit $ret); exit $ret'
+ trap "ret=129; $do_exit" 1
+ trap "ret=130; $do_exit" 2
+ trap "ret=141; $do_exit" 13
+ trap "ret=143; $do_exit" 15
+
+ # Set umask so as not to create temps with too-generous modes.
+ # However, 'strip' requires both read and write access to temps.
+ case $mode in
+ # Optimize common cases.
+ *644) cp_umask=133;;
+ *755) cp_umask=22;;
+
+ *[0-7])
+ if test -z "$stripcmd"; then
+ u_plus_rw=
+ else
+ u_plus_rw='% 200'
+ fi
+ cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
+ *)
+ if test -z "$stripcmd"; then
+ u_plus_rw=
+ else
+ u_plus_rw=,u+rw
+ fi
+ cp_umask=$mode$u_plus_rw;;
+ esac
+fi
+
+for src
+do
+ # Protect names problematic for 'test' and other utilities.
+ case $src in
+ -* | [=\(\)!]) src=./$src;;
+ esac
+
+ if test -n "$dir_arg"; then
+ dst=$src
+ dstdir=$dst
+ test -d "$dstdir"
+ dstdir_status=$?
+ else
+
+ # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
+ # might cause directories to be created, which would be especially bad
+ # if $src (and thus $dsttmp) contains '*'.
+ if test ! -f "$src" && test ! -d "$src"; then
+ echo "$0: $src does not exist." >&2
+ exit 1
+ fi
+
+ if test -z "$dst_arg"; then
+ echo "$0: no destination specified." >&2
+ exit 1
+ fi
+ dst=$dst_arg
+
+ # If destination is a directory, append the input filename; won't work
+ # if double slashes aren't ignored.
+ if test -d "$dst"; then
+ if test "$is_target_a_directory" = never; then
+ echo "$0: $dst_arg: Is a directory" >&2
+ exit 1
+ fi
+ dstdir=$dst
+ dst=$dstdir/`basename "$src"`
+ dstdir_status=0
+ else
+ dstdir=`dirname "$dst"`
+ test -d "$dstdir"
+ dstdir_status=$?
+ fi
+ fi
+
+ obsolete_mkdir_used=false
+
+ if test $dstdir_status != 0; then
+ case $posix_mkdir in
+ '')
+ # Create intermediate dirs using mode 755 as modified by the umask.
+ # This is like FreeBSD 'install' as of 1997-10-28.
+ umask=`umask`
+ case $stripcmd.$umask in
+ # Optimize common cases.
+ *[2367][2367]) mkdir_umask=$umask;;
+ .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
+
+ *[0-7])
+ mkdir_umask=`expr $umask + 22 \
+ - $umask % 100 % 40 + $umask % 20 \
+ - $umask % 10 % 4 + $umask % 2
+ `;;
+ *) mkdir_umask=$umask,go-w;;
+ esac
+
+ # With -d, create the new directory with the user-specified mode.
+ # Otherwise, rely on $mkdir_umask.
+ if test -n "$dir_arg"; then
+ mkdir_mode=-m$mode
+ else
+ mkdir_mode=
+ fi
+
+ posix_mkdir=false
+ case $umask in
+ *[123567][0-7][0-7])
+ # POSIX mkdir -p sets u+wx bits regardless of umask, which
+ # is incompatible with FreeBSD 'install' when (umask & 300) != 0.
+ ;;
+ *)
+ tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
+ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
+
+ if (umask $mkdir_umask &&
+ exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
+ then
+ if test -z "$dir_arg" || {
+ # Check for POSIX incompatibilities with -m.
+ # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
+ # other-writable bit of parent directory when it shouldn't.
+ # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
+ ls_ld_tmpdir=`ls -ld "$tmpdir"`
+ case $ls_ld_tmpdir in
+ d????-?r-*) different_mode=700;;
+ d????-?--*) different_mode=755;;
+ *) false;;
+ esac &&
+ $mkdirprog -m$different_mode -p -- "$tmpdir" && {
+ ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
+ test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
+ }
+ }
+ then posix_mkdir=:
+ fi
+ rmdir "$tmpdir/d" "$tmpdir"
+ else
+ # Remove any dirs left behind by ancient mkdir implementations.
+ rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
+ fi
+ trap '' 0;;
+ esac;;
+ esac
+
+ if
+ $posix_mkdir && (
+ umask $mkdir_umask &&
+ $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
+ )
+ then :
+ else
+
+ # The umask is ridiculous, or mkdir does not conform to POSIX,
+ # or it failed possibly due to a race condition. Create the
+ # directory the slow way, step by step, checking for races as we go.
+
+ case $dstdir in
+ /*) prefix='/';;
+ [-=\(\)!]*) prefix='./';;
+ *) prefix='';;
+ esac
+
+ oIFS=$IFS
+ IFS=/
+ set -f
+ set fnord $dstdir
+ shift
+ set +f
+ IFS=$oIFS
+
+ prefixes=
+
+ for d
+ do
+ test X"$d" = X && continue
+
+ prefix=$prefix$d
+ if test -d "$prefix"; then
+ prefixes=
+ else
+ if $posix_mkdir; then
+ (umask=$mkdir_umask &&
+ $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
+ # Don't fail if two instances are running concurrently.
+ test -d "$prefix" || exit 1
+ else
+ case $prefix in
+ *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) qprefix=$prefix;;
+ esac
+ prefixes="$prefixes '$qprefix'"
+ fi
+ fi
+ prefix=$prefix/
+ done
+
+ if test -n "$prefixes"; then
+ # Don't fail if two instances are running concurrently.
+ (umask $mkdir_umask &&
+ eval "\$doit_exec \$mkdirprog $prefixes") ||
+ test -d "$dstdir" || exit 1
+ obsolete_mkdir_used=true
+ fi
+ fi
+ fi
+
+ if test -n "$dir_arg"; then
+ { test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
+ { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
+ { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
+ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
+ else
+
+ # Make a couple of temp file names in the proper directory.
+ dsttmp=$dstdir/_inst.$$_
+ rmtmp=$dstdir/_rm.$$_
+
+ # Trap to clean up those temp files at exit.
+ trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
+
+ # Copy the file name to the temp name.
+ (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
+
+ # and set any options; do chmod last to preserve setuid bits.
+ #
+ # If any of these fail, we abort the whole thing. If we want to
+ # ignore errors from any of these, just make sure not to ignore
+ # errors from the above "$doit $cpprog $src $dsttmp" command.
+ #
+ { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
+ { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
+ { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
+ { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
+
+ # If -C, don't bother to copy if it wouldn't change the file.
+ if $copy_on_change &&
+ old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
+ new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
+ set -f &&
+ set X $old && old=:$2:$4:$5:$6 &&
+ set X $new && new=:$2:$4:$5:$6 &&
+ set +f &&
+ test "$old" = "$new" &&
+ $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
+ then
+ rm -f "$dsttmp"
+ else
+ # Rename the file to the real destination.
+ $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
+
+ # The rename failed, perhaps because mv can't rename something else
+ # to itself, or perhaps because mv is so ancient that it does not
+ # support -f.
+ {
+ # Now remove or move aside any old file at destination location.
+ # We try this two ways since rm can't unlink itself on some
+ # systems and the destination file might be busy for other
+ # reasons. In this case, the final cleanup might fail but the new
+ # file should still install successfully.
+ {
+ test ! -f "$dst" ||
+ $doit $rmcmd -f "$dst" 2>/dev/null ||
+ { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
+ { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
+ } ||
+ { echo "$0: cannot unlink or rename $dst" >&2
+ (exit 1); exit 1
+ }
+ } &&
+
+ # Now rename the file to the real destination.
+ $doit $mvcmd "$dsttmp" "$dst"
+ }
+ fi || exit 1
+
+ trap '' 0
+ fi
+done
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/src/installman.sh b/src/installman.sh
new file mode 100755
index 0000000..23fc325
--- /dev/null
+++ b/src/installman.sh
@@ -0,0 +1,124 @@
+#! /bin/sh
+# installman.sh --- install or uninstall manpages for Vim
+#
+# arguments:
+# 1 what: "install", "uninstall" or "xxd"
+# 2 target directory e.g., "/usr/local/man/it/man1"
+# 3 language addition e.g., "" or "-it"
+# 4 vim location as used in manual pages e.g., "/usr/local/share/vim"
+# 5 runtime dir for menu.vim et al. e.g., "/usr/local/share/vim/vim70"
+# 6 runtime dir for global vimrc file e.g., "/usr/local/share/vim"
+# 7 source dir for help files e.g., "../runtime/doc"
+# 8 mode bits for manpages e.g., "644"
+# 9 vim exe name e.g., "vim"
+# 10 name of vimdiff exe e.g., "vimdiff"
+# 11 name of evim exe e.g., "evim"
+
+errstatus=0
+
+what=$1
+destdir=$2
+langadd=$3
+vimloc=$4
+scriptloc=$5
+vimrcloc=$6
+helpsource=$7
+manmod=$8
+exename=$9
+# older shells don't support ${10}
+shift
+vimdiffname=$9
+shift
+evimname=$9
+
+helpsubloc=$scriptloc/doc
+printsubloc=$scriptloc/print
+synsubloc=$scriptloc/syntax
+tutorsubloc=$scriptloc/tutor
+
+if test $what = "install" -o $what = "xxd"; then
+ if test ! -d $destdir; then
+ echo creating $destdir
+ /bin/sh install-sh -c -d $destdir
+ fi
+fi
+
+# Note: setting LC_ALL to C is required to avoid illegal byte errors from sed
+# on some systems.
+
+if test $what = "install"; then
+ # vim.1
+ if test -r $helpsource/vim$langadd.1; then
+ echo installing $destdir/$exename.1
+ LC_ALL=C sed -e s+/usr/local/lib/vim+$vimloc+ \
+ -e s+$vimloc/doc+$helpsubloc+ \
+ -e s+$vimloc/print+$printsubloc+ \
+ -e s+$vimloc/syntax+$synsubloc+ \
+ -e s+$vimloc/tutor+$tutorsubloc+ \
+ -e s+$vimloc/vimrc+$vimrcloc/vimrc+ \
+ -e s+$vimloc/gvimrc+$vimrcloc/gvimrc+ \
+ -e s+$vimloc/menu.vim+$scriptloc/menu.vim+ \
+ -e s+$vimloc/bugreport.vim+$scriptloc/bugreport.vim+ \
+ -e s+$vimloc/filetype.vim+$scriptloc/filetype.vim+ \
+ -e s+$vimloc/scripts.vim+$scriptloc/scripts.vim+ \
+ -e s+$vimloc/optwin.vim+$scriptloc/optwin.vim+ \
+ -e 's+$vimloc/\*.ps+$scriptloc/\*.ps+' \
+ $helpsource/vim$langadd.1 > $destdir/$exename.1
+ chmod $manmod $destdir/$exename.1
+ fi
+
+ # vimtutor.1
+ if test -r $helpsource/vimtutor$langadd.1; then
+ echo installing $destdir/$exename""tutor.1
+ LC_ALL=C sed -e s+/usr/local/lib/vim+$vimloc+ \
+ -e s+$vimloc/tutor+$tutorsubloc+ \
+ $helpsource/vimtutor$langadd.1 > $destdir/$exename""tutor.1
+ chmod $manmod $destdir/$exename""tutor.1
+ fi
+
+ # vimdiff.1
+ if test -r $helpsource/vimdiff$langadd.1; then
+ echo installing $destdir/$vimdiffname.1
+ cp $helpsource/vimdiff$langadd.1 $destdir/$vimdiffname.1
+ chmod $manmod $destdir/$vimdiffname.1
+ fi
+
+ # evim.1
+ if test -r $helpsource/evim$langadd.1; then
+ echo installing $destdir/$evimname.1
+ LC_ALL=C sed -e s+/usr/local/lib/vim+$vimloc+ \
+ -e s+$vimloc/evim.vim+$scriptloc/evim.vim+ \
+ $helpsource/evim$langadd.1 > $destdir/$evimname.1
+ chmod $manmod $destdir/$evimname.1
+ fi
+fi
+
+if test $what = "uninstall"; then
+ echo Checking for Vim manual pages in $destdir...
+ if test -r $destdir/$exename.1; then
+ echo deleting $destdir/$exename.1
+ rm -f $destdir/$exename.1
+ fi
+ if test -r $destdir/$exename""tutor.1; then
+ echo deleting $destdir/$exename""tutor.1
+ rm -f $destdir/$exename""tutor.1
+ fi
+ if test -r $destdir/$vimdiffname.1; then
+ echo deleting $destdir/$vimdiffname.1
+ rm -f $destdir/$vimdiffname.1
+ fi
+ if test -r $destdir/$evimname.1; then
+ echo deleting $destdir/$evimname.1
+ rm -f $destdir/$evimname.1
+ fi
+fi
+
+if test $what = "xxd" -a -r "$helpsource/xxd${langadd}.1"; then
+ echo installing $destdir/xxd.1
+ cp $helpsource/xxd$langadd.1 $destdir/xxd.1
+ chmod $manmod $destdir/xxd.1
+fi
+
+exit $errstatus
+
+# vim: set sw=3 sts=3 :
diff --git a/src/installml.sh b/src/installml.sh
new file mode 100644
index 0000000..8649c6f
--- /dev/null
+++ b/src/installml.sh
@@ -0,0 +1,170 @@
+#! /bin/sh
+# installml.sh --- install or uninstall manpage links for Vim
+#
+# arguments:
+# 1 what: "install" or "uninstall"
+# 2 also do GUI pages: "yes" or ""
+# 3 target directory e.g., "/usr/local/man/it/man1"
+# 4 vim exe name e.g., "vim"
+# 5 vimdiff exe name e.g., "vimdiff"
+# 6 evim exe name e.g., "evim"
+# 7 ex exe name e.g., "ex"
+# 8 view exe name e.g., "view"
+# 9 rvim exe name e.g., "rvim"
+# 10 rview exe name e.g., "rview"
+# 11 gvim exe name e.g., "gvim"
+# 12 gview exe name e.g., "gview"
+# 13 rgvim exe name e.g., "rgvim"
+# 14 rgview exe name e.g., "rgview"
+# 15 gvimdiff exe name e.g., "gvimdiff"
+# 16 eview exe name e.g., "eview"
+
+errstatus=0
+
+what=$1
+gui=$2
+destdir=$3
+vimname=$4
+vimdiffname=$5
+evimname=$6
+exname=$7
+viewname=$8
+rvimname=$9
+# old shells don't understand ${10}
+shift
+rviewname=$9
+shift
+gvimname=$9
+shift
+gviewname=$9
+shift
+rgvimname=$9
+shift
+rgviewname=$9
+shift
+gvimdiffname=$9
+shift
+eviewname=$9
+
+if test $what = "install" -a \( -f $destdir/$vimname.1 -o -f $destdir/$vimdiffname.1 -o -f $destdir/$eviewname.1 \); then
+ if test ! -d $destdir; then
+ echo creating $destdir
+ /bin/sh install-sh -c -d $destdir
+ fi
+
+ # ex
+ if test ! -f $destdir/$exname.1 -a -f $destdir/$vimname.1; then
+ echo creating link $destdir/$exname.1
+ cd $destdir; ln -s $vimname.1 $exname.1
+ fi
+
+ # view
+ if test ! -f $destdir/$viewname.1 -a -f $destdir/$vimname.1; then
+ echo creating link $destdir/$viewname.1
+ cd $destdir; ln -s $vimname.1 $viewname.1
+ fi
+
+ # rvim
+ if test ! -f $destdir/$rvimname.1 -a -f $destdir/$vimname.1; then
+ echo creating link $destdir/$rvimname.1
+ cd $destdir; ln -s $vimname.1 $rvimname.1
+ fi
+
+ # rview
+ if test ! -f $destdir/$rviewname.1 -a -f $destdir/$vimname.1; then
+ echo creating link $destdir/$rviewname.1
+ cd $destdir; ln -s $vimname.1 $rviewname.1
+ fi
+
+ # GUI targets are optional
+ if test "$gui" = "yes"; then
+ # gvim
+ if test ! -f $destdir/$gvimname.1 -a -f $destdir/$vimname.1; then
+ echo creating link $destdir/$gvimname.1
+ cd $destdir; ln -s $vimname.1 $gvimname.1
+ fi
+
+ # gview
+ if test ! -f $destdir/$gviewname.1 -a -f $destdir/$vimname.1; then
+ echo creating link $destdir/$gviewname.1
+ cd $destdir; ln -s $vimname.1 $gviewname.1
+ fi
+
+ # rgvim
+ if test ! -f $destdir/$rgvimname.1 -a -f $destdir/$vimname.1; then
+ echo creating link $destdir/$rgvimname.1
+ cd $destdir; ln -s $vimname.1 $rgvimname.1
+ fi
+
+ # rgview
+ if test ! -f $destdir/$rgviewname.1 -a -f $destdir/$vimname.1; then
+ echo creating link $destdir/$rgviewname.1
+ cd $destdir; ln -s $vimname.1 $rgviewname.1
+ fi
+
+ # gvimdiff
+ if test ! -f $destdir/$gvimdiffname.1 -a -f $destdir/$vimdiffname.1; then
+ echo creating link $destdir/$gvimdiffname.1
+ cd $destdir; ln -s $vimdiffname.1 $gvimdiffname.1
+ fi
+
+ # eview
+ if test ! -f $destdir/$eviewname.1 -a -f $destdir/$evimname.1; then
+ echo creating link $destdir/$eviewname.1
+ cd $destdir; ln -s $evimname.1 $eviewname.1
+ fi
+ fi
+fi
+
+if test $what = "uninstall"; then
+ echo Checking for Vim manual page links in $destdir...
+
+ if test -L $destdir/$exname.1; then
+ echo deleting $destdir/$exname.1
+ rm -f $destdir/$exname.1
+ fi
+ if test -L $destdir/$viewname.1; then
+ echo deleting $destdir/$viewname.1
+ rm -f $destdir/$viewname.1
+ fi
+ if test -L $destdir/$rvimname.1; then
+ echo deleting $destdir/$rvimname.1
+ rm -f $destdir/$rvimname.1
+ fi
+ if test -L $destdir/$rviewname.1; then
+ echo deleting $destdir/$rviewname.1
+ rm -f $destdir/$rviewname.1
+ fi
+
+ # GUI targets are optional
+ if test "$gui" = "yes"; then
+ if test -L $destdir/$gvimname.1; then
+ echo deleting $destdir/$gvimname.1
+ rm -f $destdir/$gvimname.1
+ fi
+ if test -L $destdir/$gviewname.1; then
+ echo deleting $destdir/$gviewname.1
+ rm -f $destdir/$gviewname.1
+ fi
+ if test -L $destdir/$rgvimname.1; then
+ echo deleting $destdir/$rgvimname.1
+ rm -f $destdir/$rgvimname.1
+ fi
+ if test -L $destdir/$rgviewname.1; then
+ echo deleting $destdir/$rgviewname.1
+ rm -f $destdir/$rgviewname.1
+ fi
+ if test -L $destdir/$gvimdiffname.1; then
+ echo deleting $destdir/$gvimdiffname.1
+ rm -f $destdir/$gvimdiffname.1
+ fi
+ if test -L $destdir/$eviewname.1; then
+ echo deleting $destdir/$eviewname.1
+ rm -f $destdir/$eviewname.1
+ fi
+ fi
+fi
+
+exit $errstatus
+
+# vim: set sw=3 :
diff --git a/src/iscygpty.c b/src/iscygpty.c
new file mode 100644
index 0000000..b018a1d
--- /dev/null
+++ b/src/iscygpty.c
@@ -0,0 +1,183 @@
+/*
+ * iscygpty.c -- part of ptycheck
+ * https://github.com/k-takata/ptycheck
+ *
+ * Copyright (c) 2015-2017 K.Takata
+ *
+ * You can redistribute it and/or modify it under the terms of either
+ * the MIT license (as described below) or the Vim license.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifdef _WIN32
+
+#include <ctype.h>
+#include <io.h>
+#include <wchar.h>
+#include <windows.h>
+
+#ifdef USE_FILEEXTD
+/* VC 7.1 or earlier doesn't support SAL. */
+# if !defined(_MSC_VER) || (_MSC_VER < 1400)
+# define __out
+# define __in
+# define __in_opt
+# endif
+/* Win32 FileID API Library:
+ * http://www.microsoft.com/en-us/download/details.aspx?id=22599
+ * Needed for WinXP. */
+# include <fileextd.h>
+#else /* USE_FILEEXTD */
+/* VC 8 or earlier. */
+# if defined(_MSC_VER) && (_MSC_VER < 1500)
+# ifdef ENABLE_STUB_IMPL
+# define STUB_IMPL
+# else
+# error "Win32 FileID API Library is required for VC2005 or earlier."
+# endif
+# endif
+#endif /* USE_FILEEXTD */
+
+
+#include "iscygpty.h"
+
+//#define USE_DYNFILEID
+#ifdef USE_DYNFILEID
+typedef BOOL (WINAPI *pfnGetFileInformationByHandleEx)(
+ HANDLE hFile,
+ FILE_INFO_BY_HANDLE_CLASS FileInformationClass,
+ LPVOID lpFileInformation,
+ DWORD dwBufferSize);
+static pfnGetFileInformationByHandleEx pGetFileInformationByHandleEx = NULL;
+
+# ifndef USE_FILEEXTD
+static BOOL WINAPI stub_GetFileInformationByHandleEx(
+ HANDLE hFile,
+ FILE_INFO_BY_HANDLE_CLASS FileInformationClass,
+ LPVOID lpFileInformation,
+ DWORD dwBufferSize)
+{
+ return FALSE;
+}
+# endif
+
+static void setup_fileid_api(void)
+{
+ if (pGetFileInformationByHandleEx != NULL) {
+ return;
+ }
+ pGetFileInformationByHandleEx = (pfnGetFileInformationByHandleEx)
+ GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")),
+ "GetFileInformationByHandleEx");
+ if (pGetFileInformationByHandleEx == NULL) {
+# ifdef USE_FILEEXTD
+ pGetFileInformationByHandleEx = GetFileInformationByHandleEx;
+# else
+ pGetFileInformationByHandleEx = stub_GetFileInformationByHandleEx;
+# endif
+ }
+}
+#else
+# define pGetFileInformationByHandleEx GetFileInformationByHandleEx
+# define setup_fileid_api()
+#endif
+
+
+#define is_wprefix(s, prefix) \
+ (wcsncmp((s), (prefix), sizeof(prefix) / sizeof(WCHAR) - 1) == 0)
+
+/* Check if the fd is a cygwin/msys's pty. */
+int is_cygpty(int fd)
+{
+#ifdef STUB_IMPL
+ return 0;
+#else
+ HANDLE h;
+ int size = sizeof(FILE_NAME_INFO) + sizeof(WCHAR) * (MAX_PATH - 1);
+ FILE_NAME_INFO *nameinfo;
+ WCHAR *p = NULL;
+
+ setup_fileid_api();
+
+ h = (HANDLE) _get_osfhandle(fd);
+ if (h == INVALID_HANDLE_VALUE) {
+ return 0;
+ }
+ /* Cygwin/msys's pty is a pipe. */
+ if (GetFileType(h) != FILE_TYPE_PIPE) {
+ return 0;
+ }
+ nameinfo = malloc(size + sizeof(WCHAR));
+ if (nameinfo == NULL) {
+ return 0;
+ }
+ /* Check the name of the pipe:
+ * '\{cygwin,msys}-XXXXXXXXXXXXXXXX-ptyN-{from,to}-master' */
+ if (pGetFileInformationByHandleEx(h, FileNameInfo, nameinfo, size)) {
+ nameinfo->FileName[nameinfo->FileNameLength / sizeof(WCHAR)] = L'\0';
+ p = nameinfo->FileName;
+ if (is_wprefix(p, L"\\cygwin-")) { /* Cygwin */
+ p += 8;
+ } else if (is_wprefix(p, L"\\msys-")) { /* MSYS and MSYS2 */
+ p += 6;
+ } else {
+ p = NULL;
+ }
+ if (p != NULL) {
+ while (*p && isxdigit(*p)) /* Skip 16-digit hexadecimal. */
+ ++p;
+ if (is_wprefix(p, L"-pty")) {
+ p += 4;
+ } else {
+ p = NULL;
+ }
+ }
+ if (p != NULL) {
+ while (*p && isdigit(*p)) /* Skip pty number. */
+ ++p;
+ if (is_wprefix(p, L"-from-master")) {
+ //p += 12;
+ } else if (is_wprefix(p, L"-to-master")) {
+ //p += 10;
+ } else {
+ p = NULL;
+ }
+ }
+ }
+ free(nameinfo);
+ return (p != NULL);
+#endif /* STUB_IMPL */
+}
+
+/* Check if at least one cygwin/msys pty is used. */
+int is_cygpty_used(void)
+{
+ int fd, ret = 0;
+
+ for (fd = 0; fd < 3; fd++) {
+ ret |= is_cygpty(fd);
+ }
+ return ret;
+}
+
+#endif /* _WIN32 */
+
+/* vim: set ts=4 sw=4: */
diff --git a/src/iscygpty.h b/src/iscygpty.h
new file mode 100644
index 0000000..82fd0af
--- /dev/null
+++ b/src/iscygpty.h
@@ -0,0 +1,41 @@
+/*
+ * iscygpty.h -- part of ptycheck
+ * https://github.com/k-takata/ptycheck
+ *
+ * Copyright (c) 2015-2017 K.Takata
+ *
+ * You can redistribute it and/or modify it under the terms of either
+ * the MIT license (as described below) or the Vim license.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _ISCYGPTY_H
+#define _ISCYGPTY_H
+
+#ifdef _WIN32
+int is_cygpty(int fd);
+int is_cygpty_used(void);
+#else
+#define is_cygpty(fd) 0
+#define is_cygpty_used() 0
+#endif
+
+#endif /* _ISCYGPTY_H */
diff --git a/src/json.c b/src/json.c
new file mode 100644
index 0000000..d3c4817
--- /dev/null
+++ b/src/json.c
@@ -0,0 +1,1108 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * json.c: Encoding and decoding JSON.
+ *
+ * Follows this standard: https://tools.ietf.org/html/rfc7159.html
+ */
+#define USING_FLOAT_STUFF
+
+#include "vim.h"
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+
+static int json_encode_item(garray_T *gap, typval_T *val, int copyID, int options);
+
+/*
+ * Encode "val" into a JSON format string.
+ * The result is added to "gap"
+ * Returns FAIL on failure and makes gap->ga_data empty.
+ */
+ static int
+json_encode_gap(garray_T *gap, typval_T *val, int options)
+{
+ if (json_encode_item(gap, val, get_copyID(), options) == FAIL)
+ {
+ ga_clear(gap);
+ gap->ga_data = vim_strsave((char_u *)"");
+ return FAIL;
+ }
+ return OK;
+}
+
+/*
+ * Encode "val" into a JSON format string.
+ * The result is in allocated memory.
+ * The result is empty when encoding fails.
+ * "options" can contain JSON_JS, JSON_NO_NONE and JSON_NL.
+ */
+ char_u *
+json_encode(typval_T *val, int options)
+{
+ garray_T ga;
+
+ /* Store bytes in the growarray. */
+ ga_init2(&ga, 1, 4000);
+ json_encode_gap(&ga, val, options);
+ return ga.ga_data;
+}
+
+#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
+/*
+ * Encode ["nr", "val"] into a JSON format string in allocated memory.
+ * "options" can contain JSON_JS, JSON_NO_NONE and JSON_NL.
+ * Returns NULL when out of memory.
+ */
+ char_u *
+json_encode_nr_expr(int nr, typval_T *val, int options)
+{
+ typval_T listtv;
+ typval_T nrtv;
+ garray_T ga;
+
+ nrtv.v_type = VAR_NUMBER;
+ nrtv.vval.v_number = nr;
+ if (rettv_list_alloc(&listtv) == FAIL)
+ return NULL;
+ if (list_append_tv(listtv.vval.v_list, &nrtv) == FAIL
+ || list_append_tv(listtv.vval.v_list, val) == FAIL)
+ {
+ list_unref(listtv.vval.v_list);
+ return NULL;
+ }
+
+ ga_init2(&ga, 1, 4000);
+ if (json_encode_gap(&ga, &listtv, options) == OK && (options & JSON_NL))
+ ga_append(&ga, '\n');
+ list_unref(listtv.vval.v_list);
+ return ga.ga_data;
+}
+#endif
+
+ static void
+write_string(garray_T *gap, char_u *str)
+{
+ char_u *res = str;
+ char_u numbuf[NUMBUFLEN];
+
+ if (res == NULL)
+ ga_concat(gap, (char_u *)"\"\"");
+ else
+ {
+#if defined(USE_ICONV)
+ vimconv_T conv;
+ char_u *converted = NULL;
+
+ if (!enc_utf8)
+ {
+ /* Convert the text from 'encoding' to utf-8, the JSON string is
+ * always utf-8. */
+ conv.vc_type = CONV_NONE;
+ convert_setup(&conv, p_enc, (char_u*)"utf-8");
+ if (conv.vc_type != CONV_NONE)
+ converted = res = string_convert(&conv, res, NULL);
+ convert_setup(&conv, NULL, NULL);
+ }
+#endif
+ ga_append(gap, '"');
+ while (*res != NUL)
+ {
+ int c;
+ /* always use utf-8 encoding, ignore 'encoding' */
+ c = utf_ptr2char(res);
+
+ switch (c)
+ {
+ case 0x08:
+ ga_append(gap, '\\'); ga_append(gap, 'b'); break;
+ case 0x09:
+ ga_append(gap, '\\'); ga_append(gap, 't'); break;
+ case 0x0a:
+ ga_append(gap, '\\'); ga_append(gap, 'n'); break;
+ case 0x0c:
+ ga_append(gap, '\\'); ga_append(gap, 'f'); break;
+ case 0x0d:
+ ga_append(gap, '\\'); ga_append(gap, 'r'); break;
+ case 0x22: /* " */
+ case 0x5c: /* \ */
+ ga_append(gap, '\\');
+ ga_append(gap, c);
+ break;
+ default:
+ if (c >= 0x20)
+ {
+ numbuf[utf_char2bytes(c, numbuf)] = NUL;
+ ga_concat(gap, numbuf);
+ }
+ else
+ {
+ vim_snprintf((char *)numbuf, NUMBUFLEN,
+ "\\u%04lx", (long)c);
+ ga_concat(gap, numbuf);
+ }
+ }
+ res += utf_ptr2len(res);
+ }
+ ga_append(gap, '"');
+#if defined(USE_ICONV)
+ vim_free(converted);
+#endif
+ }
+}
+
+/*
+ * Return TRUE if "key" can be used without quotes.
+ * That is when it starts with a letter and only contains letters, digits and
+ * underscore.
+ */
+ static int
+is_simple_key(char_u *key)
+{
+ char_u *p;
+
+ if (!ASCII_ISALPHA(*key))
+ return FALSE;
+ for (p = key + 1; *p != NUL; ++p)
+ if (!ASCII_ISALPHA(*p) && *p != '_' && !vim_isdigit(*p))
+ return FALSE;
+ return TRUE;
+}
+
+/*
+ * Encode "val" into "gap".
+ * Return FAIL or OK.
+ */
+ static int
+json_encode_item(garray_T *gap, typval_T *val, int copyID, int options)
+{
+ char_u numbuf[NUMBUFLEN];
+ char_u *res;
+ blob_T *b;
+ list_T *l;
+ dict_T *d;
+ int i;
+
+ switch (val->v_type)
+ {
+ case VAR_SPECIAL:
+ switch (val->vval.v_number)
+ {
+ case VVAL_FALSE: ga_concat(gap, (char_u *)"false"); break;
+ case VVAL_TRUE: ga_concat(gap, (char_u *)"true"); break;
+ case VVAL_NONE: if ((options & JSON_JS) != 0
+ && (options & JSON_NO_NONE) == 0)
+ /* empty item */
+ break;
+ /* FALLTHROUGH */
+ case VVAL_NULL: ga_concat(gap, (char_u *)"null"); break;
+ }
+ break;
+
+ case VAR_NUMBER:
+ vim_snprintf((char *)numbuf, NUMBUFLEN, "%lld",
+ (long_long_T)val->vval.v_number);
+ ga_concat(gap, numbuf);
+ break;
+
+ case VAR_STRING:
+ res = val->vval.v_string;
+ write_string(gap, res);
+ break;
+
+ case VAR_FUNC:
+ case VAR_PARTIAL:
+ case VAR_JOB:
+ case VAR_CHANNEL:
+ /* no JSON equivalent TODO: better error */
+ emsg(_(e_invarg));
+ return FAIL;
+
+ case VAR_BLOB:
+ b = val->vval.v_blob;
+ if (b == NULL || b->bv_ga.ga_len == 0)
+ ga_concat(gap, (char_u *)"[]");
+ else
+ {
+ ga_append(gap, '[');
+ for (i = 0; i < b->bv_ga.ga_len; i++)
+ {
+ if (i > 0)
+ ga_concat(gap, (char_u *)",");
+ vim_snprintf((char *)numbuf, NUMBUFLEN, "%d",
+ (int)blob_get(b, i));
+ ga_concat(gap, numbuf);
+ }
+ ga_append(gap, ']');
+ }
+ break;
+
+ case VAR_LIST:
+ l = val->vval.v_list;
+ if (l == NULL)
+ ga_concat(gap, (char_u *)"[]");
+ else
+ {
+ if (l->lv_copyID == copyID)
+ ga_concat(gap, (char_u *)"[]");
+ else
+ {
+ listitem_T *li;
+
+ l->lv_copyID = copyID;
+ ga_append(gap, '[');
+ for (li = l->lv_first; li != NULL && !got_int; )
+ {
+ if (json_encode_item(gap, &li->li_tv, copyID,
+ options & JSON_JS) == FAIL)
+ return FAIL;
+ if ((options & JSON_JS)
+ && li->li_next == NULL
+ && li->li_tv.v_type == VAR_SPECIAL
+ && li->li_tv.vval.v_number == VVAL_NONE)
+ /* add an extra comma if the last item is v:none */
+ ga_append(gap, ',');
+ li = li->li_next;
+ if (li != NULL)
+ ga_append(gap, ',');
+ }
+ ga_append(gap, ']');
+ l->lv_copyID = 0;
+ }
+ }
+ break;
+
+ case VAR_DICT:
+ d = val->vval.v_dict;
+ if (d == NULL)
+ ga_concat(gap, (char_u *)"{}");
+ else
+ {
+ if (d->dv_copyID == copyID)
+ ga_concat(gap, (char_u *)"{}");
+ else
+ {
+ int first = TRUE;
+ int todo = (int)d->dv_hashtab.ht_used;
+ hashitem_T *hi;
+
+ d->dv_copyID = copyID;
+ ga_append(gap, '{');
+
+ for (hi = d->dv_hashtab.ht_array; todo > 0 && !got_int;
+ ++hi)
+ if (!HASHITEM_EMPTY(hi))
+ {
+ --todo;
+ if (first)
+ first = FALSE;
+ else
+ ga_append(gap, ',');
+ if ((options & JSON_JS)
+ && is_simple_key(hi->hi_key))
+ ga_concat(gap, hi->hi_key);
+ else
+ write_string(gap, hi->hi_key);
+ ga_append(gap, ':');
+ if (json_encode_item(gap, &dict_lookup(hi)->di_tv,
+ copyID, options | JSON_NO_NONE) == FAIL)
+ return FAIL;
+ }
+ ga_append(gap, '}');
+ d->dv_copyID = 0;
+ }
+ }
+ break;
+
+ case VAR_FLOAT:
+#ifdef FEAT_FLOAT
+# if defined(HAVE_MATH_H)
+ if (isnan(val->vval.v_float))
+ ga_concat(gap, (char_u *)"NaN");
+ else if (isinf(val->vval.v_float))
+ {
+ if (val->vval.v_float < 0.0)
+ ga_concat(gap, (char_u *)"-Infinity");
+ else
+ ga_concat(gap, (char_u *)"Infinity");
+ }
+ else
+# endif
+ {
+ vim_snprintf((char *)numbuf, NUMBUFLEN, "%g",
+ val->vval.v_float);
+ ga_concat(gap, numbuf);
+ }
+ break;
+#endif
+ case VAR_UNKNOWN:
+ internal_error("json_encode_item()");
+ return FAIL;
+ }
+ return OK;
+}
+
+/*
+ * When "reader" has less than NUMBUFLEN bytes available, call the fill
+ * callback to get more.
+ */
+ static void
+fill_numbuflen(js_read_T *reader)
+{
+ if (reader->js_fill != NULL && (int)(reader->js_end - reader->js_buf)
+ - reader->js_used < NUMBUFLEN)
+ {
+ if (reader->js_fill(reader))
+ reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
+ }
+}
+
+/*
+ * Skip white space in "reader". All characters <= space are considered white
+ * space.
+ * Also tops up readahead when needed.
+ */
+ static void
+json_skip_white(js_read_T *reader)
+{
+ int c;
+
+ for (;;)
+ {
+ c = reader->js_buf[reader->js_used];
+ if (reader->js_fill != NULL && c == NUL)
+ {
+ if (reader->js_fill(reader))
+ {
+ reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
+ continue;
+ }
+ }
+ if (c == NUL || c > ' ')
+ break;
+ ++reader->js_used;
+ }
+ fill_numbuflen(reader);
+}
+
+ static int
+json_decode_string(js_read_T *reader, typval_T *res, int quote)
+{
+ garray_T ga;
+ int len;
+ char_u *p;
+ int c;
+ varnumber_T nr;
+
+ if (res != NULL)
+ ga_init2(&ga, 1, 200);
+
+ p = reader->js_buf + reader->js_used + 1; /* skip over " or ' */
+ while (*p != quote)
+ {
+ /* The JSON is always expected to be utf-8, thus use utf functions
+ * here. The string is converted below if needed. */
+ if (*p == NUL || p[1] == NUL || utf_ptr2len(p) < utf_byte2len(*p))
+ {
+ /* Not enough bytes to make a character or end of the string. Get
+ * more if possible. */
+ if (reader->js_fill == NULL)
+ break;
+ len = (int)(reader->js_end - p);
+ reader->js_used = (int)(p - reader->js_buf);
+ if (!reader->js_fill(reader))
+ break; /* didn't get more */
+ p = reader->js_buf + reader->js_used;
+ reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
+ continue;
+ }
+
+ if (*p == '\\')
+ {
+ c = -1;
+ switch (p[1])
+ {
+ case '\\': c = '\\'; break;
+ case '"': c = '"'; break;
+ case 'b': c = BS; break;
+ case 't': c = TAB; break;
+ case 'n': c = NL; break;
+ case 'f': c = FF; break;
+ case 'r': c = CAR; break;
+ case 'u':
+ if (reader->js_fill != NULL
+ && (int)(reader->js_end - p) < NUMBUFLEN)
+ {
+ reader->js_used = (int)(p - reader->js_buf);
+ if (reader->js_fill(reader))
+ {
+ p = reader->js_buf + reader->js_used;
+ reader->js_end = reader->js_buf
+ + STRLEN(reader->js_buf);
+ }
+ }
+ nr = 0;
+ len = 0;
+ vim_str2nr(p + 2, NULL, &len,
+ STR2NR_HEX + STR2NR_FORCE, &nr, NULL, 4);
+ p += len + 2;
+ if (0xd800 <= nr && nr <= 0xdfff
+ && (int)(reader->js_end - p) >= 6
+ && *p == '\\' && *(p+1) == 'u')
+ {
+ varnumber_T nr2 = 0;
+
+ /* decode surrogate pair: \ud812\u3456 */
+ len = 0;
+ vim_str2nr(p + 2, NULL, &len,
+ STR2NR_HEX + STR2NR_FORCE, &nr2, NULL, 4);
+ if (0xdc00 <= nr2 && nr2 <= 0xdfff)
+ {
+ p += len + 2;
+ nr = (((nr - 0xd800) << 10) |
+ ((nr2 - 0xdc00) & 0x3ff)) + 0x10000;
+ }
+ }
+ if (res != NULL)
+ {
+ char_u buf[NUMBUFLEN];
+ buf[utf_char2bytes((int)nr, buf)] = NUL;
+ ga_concat(&ga, buf);
+ }
+ break;
+ default:
+ /* not a special char, skip over \ */
+ ++p;
+ continue;
+ }
+ if (c > 0)
+ {
+ p += 2;
+ if (res != NULL)
+ ga_append(&ga, c);
+ }
+ }
+ else
+ {
+ len = utf_ptr2len(p);
+ if (res != NULL)
+ {
+ if (ga_grow(&ga, len) == FAIL)
+ {
+ ga_clear(&ga);
+ return FAIL;
+ }
+ mch_memmove((char *)ga.ga_data + ga.ga_len, p, (size_t)len);
+ ga.ga_len += len;
+ }
+ p += len;
+ }
+ }
+
+ reader->js_used = (int)(p - reader->js_buf);
+ if (*p == quote)
+ {
+ ++reader->js_used;
+ if (res != NULL)
+ {
+ ga_append(&ga, NUL);
+ res->v_type = VAR_STRING;
+#if defined(USE_ICONV)
+ if (!enc_utf8)
+ {
+ vimconv_T conv;
+
+ /* Convert the utf-8 string to 'encoding'. */
+ conv.vc_type = CONV_NONE;
+ convert_setup(&conv, (char_u*)"utf-8", p_enc);
+ if (conv.vc_type != CONV_NONE)
+ {
+ res->vval.v_string =
+ string_convert(&conv, ga.ga_data, NULL);
+ vim_free(ga.ga_data);
+ }
+ convert_setup(&conv, NULL, NULL);
+ }
+ else
+#endif
+ res->vval.v_string = ga.ga_data;
+ }
+ return OK;
+ }
+ if (res != NULL)
+ {
+ res->v_type = VAR_SPECIAL;
+ res->vval.v_number = VVAL_NONE;
+ ga_clear(&ga);
+ }
+ return MAYBE;
+}
+
+typedef enum {
+ JSON_ARRAY, /* parsing items in an array */
+ JSON_OBJECT_KEY, /* parsing key of an object */
+ JSON_OBJECT /* parsing item in an object, after the key */
+} json_decode_T;
+
+typedef struct {
+ json_decode_T jd_type;
+ typval_T jd_tv; /* the list or dict */
+ typval_T jd_key_tv;
+ char_u *jd_key;
+} json_dec_item_T;
+
+/*
+ * Decode one item and put it in "res". If "res" is NULL only advance.
+ * Must already have skipped white space.
+ *
+ * Return FAIL for a decoding error (and give an error).
+ * Return MAYBE for an incomplete message.
+ */
+ static int
+json_decode_item(js_read_T *reader, typval_T *res, int options)
+{
+ char_u *p;
+ int len;
+ int retval;
+ garray_T stack;
+ typval_T item;
+ typval_T *cur_item;
+ json_dec_item_T *top_item;
+ char_u key_buf[NUMBUFLEN];
+
+ ga_init2(&stack, sizeof(json_dec_item_T), 100);
+ cur_item = res;
+ init_tv(&item);
+ if (res != NULL)
+ init_tv(res);
+
+ fill_numbuflen(reader);
+ p = reader->js_buf + reader->js_used;
+ for (;;)
+ {
+ top_item = NULL;
+ if (stack.ga_len > 0)
+ {
+ top_item = ((json_dec_item_T *)stack.ga_data) + stack.ga_len - 1;
+ json_skip_white(reader);
+ p = reader->js_buf + reader->js_used;
+ if (*p == NUL)
+ {
+ retval = MAYBE;
+ if (top_item->jd_type == JSON_OBJECT)
+ /* did get the key, clear it */
+ clear_tv(&top_item->jd_key_tv);
+ goto theend;
+ }
+ if (top_item->jd_type == JSON_OBJECT_KEY
+ || top_item->jd_type == JSON_ARRAY)
+ {
+ /* Check for end of object or array. */
+ if (*p == (top_item->jd_type == JSON_ARRAY ? ']' : '}'))
+ {
+ ++reader->js_used; /* consume the ']' or '}' */
+ --stack.ga_len;
+ if (stack.ga_len == 0)
+ {
+ retval = OK;
+ goto theend;
+ }
+ if (cur_item != NULL)
+ cur_item = &top_item->jd_tv;
+ goto item_end;
+ }
+ }
+ }
+
+ if (top_item != NULL && top_item->jd_type == JSON_OBJECT_KEY
+ && (options & JSON_JS)
+ && reader->js_buf[reader->js_used] != '"'
+ && reader->js_buf[reader->js_used] != '\''
+ && reader->js_buf[reader->js_used] != '['
+ && reader->js_buf[reader->js_used] != '{')
+ {
+ char_u *key;
+
+ /* accept an object key that is not in quotes */
+ key = p = reader->js_buf + reader->js_used;
+ while (*p != NUL && *p != ':' && *p > ' ')
+ ++p;
+ if (cur_item != NULL)
+ {
+ cur_item->v_type = VAR_STRING;
+ cur_item->vval.v_string = vim_strnsave(key, (int)(p - key));
+ top_item->jd_key = cur_item->vval.v_string;
+ }
+ reader->js_used += (int)(p - key);
+ }
+ else
+ {
+ switch (*p)
+ {
+ case '[': /* start of array */
+ if (top_item && top_item->jd_type == JSON_OBJECT_KEY)
+ {
+ retval = FAIL;
+ break;
+ }
+ if (ga_grow(&stack, 1) == FAIL)
+ {
+ retval = FAIL;
+ break;
+ }
+ if (cur_item != NULL && rettv_list_alloc(cur_item) == FAIL)
+ {
+ cur_item->v_type = VAR_SPECIAL;
+ cur_item->vval.v_number = VVAL_NONE;
+ retval = FAIL;
+ break;
+ }
+
+ ++reader->js_used; /* consume the '[' */
+ top_item = ((json_dec_item_T *)stack.ga_data)
+ + stack.ga_len;
+ top_item->jd_type = JSON_ARRAY;
+ ++stack.ga_len;
+ if (cur_item != NULL)
+ {
+ top_item->jd_tv = *cur_item;
+ cur_item = &item;
+ }
+ continue;
+
+ case '{': /* start of object */
+ if (top_item && top_item->jd_type == JSON_OBJECT_KEY)
+ {
+ retval = FAIL;
+ break;
+ }
+ if (ga_grow(&stack, 1) == FAIL)
+ {
+ retval = FAIL;
+ break;
+ }
+ if (cur_item != NULL && rettv_dict_alloc(cur_item) == FAIL)
+ {
+ cur_item->v_type = VAR_SPECIAL;
+ cur_item->vval.v_number = VVAL_NONE;
+ retval = FAIL;
+ break;
+ }
+
+ ++reader->js_used; /* consume the '{' */
+ top_item = ((json_dec_item_T *)stack.ga_data)
+ + stack.ga_len;
+ top_item->jd_type = JSON_OBJECT_KEY;
+ ++stack.ga_len;
+ if (cur_item != NULL)
+ {
+ top_item->jd_tv = *cur_item;
+ cur_item = &top_item->jd_key_tv;
+ }
+ continue;
+
+ case '"': /* string */
+ retval = json_decode_string(reader, cur_item, *p);
+ break;
+
+ case '\'':
+ if (options & JSON_JS)
+ retval = json_decode_string(reader, cur_item, *p);
+ else
+ {
+ emsg(_(e_invarg));
+ retval = FAIL;
+ }
+ break;
+
+ case ',': /* comma: empty item */
+ if ((options & JSON_JS) == 0)
+ {
+ emsg(_(e_invarg));
+ retval = FAIL;
+ break;
+ }
+ /* FALLTHROUGH */
+ case NUL: /* empty */
+ if (cur_item != NULL)
+ {
+ cur_item->v_type = VAR_SPECIAL;
+ cur_item->vval.v_number = VVAL_NONE;
+ }
+ retval = OK;
+ break;
+
+ default:
+ if (VIM_ISDIGIT(*p) || (*p == '-' && VIM_ISDIGIT(p[1])))
+ {
+#ifdef FEAT_FLOAT
+ char_u *sp = p;
+
+ if (*sp == '-')
+ {
+ ++sp;
+ if (*sp == NUL)
+ {
+ retval = MAYBE;
+ break;
+ }
+ if (!VIM_ISDIGIT(*sp))
+ {
+ emsg(_(e_invarg));
+ retval = FAIL;
+ break;
+ }
+ }
+ sp = skipdigits(sp);
+ if (*sp == '.' || *sp == 'e' || *sp == 'E')
+ {
+ if (cur_item == NULL)
+ {
+ float_T f;
+
+ len = string2float(p, &f);
+ }
+ else
+ {
+ cur_item->v_type = VAR_FLOAT;
+ len = string2float(p, &cur_item->vval.v_float);
+ }
+ }
+ else
+#endif
+ {
+ varnumber_T nr;
+
+ vim_str2nr(reader->js_buf + reader->js_used,
+ NULL, &len, 0, /* what */
+ &nr, NULL, 0);
+ if (cur_item != NULL)
+ {
+ cur_item->v_type = VAR_NUMBER;
+ cur_item->vval.v_number = nr;
+ }
+ }
+ reader->js_used += len;
+ retval = OK;
+ break;
+ }
+ if (STRNICMP((char *)p, "false", 5) == 0)
+ {
+ reader->js_used += 5;
+ if (cur_item != NULL)
+ {
+ cur_item->v_type = VAR_SPECIAL;
+ cur_item->vval.v_number = VVAL_FALSE;
+ }
+ retval = OK;
+ break;
+ }
+ if (STRNICMP((char *)p, "true", 4) == 0)
+ {
+ reader->js_used += 4;
+ if (cur_item != NULL)
+ {
+ cur_item->v_type = VAR_SPECIAL;
+ cur_item->vval.v_number = VVAL_TRUE;
+ }
+ retval = OK;
+ break;
+ }
+ if (STRNICMP((char *)p, "null", 4) == 0)
+ {
+ reader->js_used += 4;
+ if (cur_item != NULL)
+ {
+ cur_item->v_type = VAR_SPECIAL;
+ cur_item->vval.v_number = VVAL_NULL;
+ }
+ retval = OK;
+ break;
+ }
+#ifdef FEAT_FLOAT
+ if (STRNICMP((char *)p, "NaN", 3) == 0)
+ {
+ reader->js_used += 3;
+ if (cur_item != NULL)
+ {
+ cur_item->v_type = VAR_FLOAT;
+ cur_item->vval.v_float = NAN;
+ }
+ retval = OK;
+ break;
+ }
+ if (STRNICMP((char *)p, "-Infinity", 9) == 0)
+ {
+ reader->js_used += 9;
+ if (cur_item != NULL)
+ {
+ cur_item->v_type = VAR_FLOAT;
+ cur_item->vval.v_float = -INFINITY;
+ }
+ retval = OK;
+ break;
+ }
+ if (STRNICMP((char *)p, "Infinity", 8) == 0)
+ {
+ reader->js_used += 8;
+ if (cur_item != NULL)
+ {
+ cur_item->v_type = VAR_FLOAT;
+ cur_item->vval.v_float = INFINITY;
+ }
+ retval = OK;
+ break;
+ }
+#endif
+ /* check for truncated name */
+ len = (int)(reader->js_end - (reader->js_buf + reader->js_used));
+ if (
+ (len < 5 && STRNICMP((char *)p, "false", len) == 0)
+#ifdef FEAT_FLOAT
+ || (len < 9 && STRNICMP((char *)p, "-Infinity", len) == 0)
+ || (len < 8 && STRNICMP((char *)p, "Infinity", len) == 0)
+ || (len < 3 && STRNICMP((char *)p, "NaN", len) == 0)
+#endif
+ || (len < 4 && (STRNICMP((char *)p, "true", len) == 0
+ || STRNICMP((char *)p, "null", len) == 0)))
+
+ retval = MAYBE;
+ else
+ retval = FAIL;
+ break;
+ }
+
+ /* We are finished when retval is FAIL or MAYBE and when at the
+ * toplevel. */
+ if (retval == FAIL)
+ break;
+ if (retval == MAYBE || stack.ga_len == 0)
+ goto theend;
+
+ if (top_item != NULL && top_item->jd_type == JSON_OBJECT_KEY
+ && cur_item != NULL)
+ {
+ top_item->jd_key = tv_get_string_buf_chk(cur_item, key_buf);
+ if (top_item->jd_key == NULL)
+ {
+ clear_tv(cur_item);
+ emsg(_(e_invarg));
+ retval = FAIL;
+ goto theend;
+ }
+ }
+ }
+
+item_end:
+ top_item = ((json_dec_item_T *)stack.ga_data) + stack.ga_len - 1;
+ switch (top_item->jd_type)
+ {
+ case JSON_ARRAY:
+ if (res != NULL)
+ {
+ listitem_T *li = listitem_alloc();
+
+ if (li == NULL)
+ {
+ clear_tv(cur_item);
+ retval = FAIL;
+ goto theend;
+ }
+ li->li_tv = *cur_item;
+ list_append(top_item->jd_tv.vval.v_list, li);
+ }
+ if (cur_item != NULL)
+ cur_item = &item;
+
+ json_skip_white(reader);
+ p = reader->js_buf + reader->js_used;
+ if (*p == ',')
+ ++reader->js_used;
+ else if (*p != ']')
+ {
+ if (*p == NUL)
+ retval = MAYBE;
+ else
+ {
+ emsg(_(e_invarg));
+ retval = FAIL;
+ }
+ goto theend;
+ }
+ break;
+
+ case JSON_OBJECT_KEY:
+ json_skip_white(reader);
+ p = reader->js_buf + reader->js_used;
+ if (*p != ':')
+ {
+ if (cur_item != NULL)
+ clear_tv(cur_item);
+ if (*p == NUL)
+ retval = MAYBE;
+ else
+ {
+ emsg(_(e_invarg));
+ retval = FAIL;
+ }
+ goto theend;
+ }
+ ++reader->js_used;
+ json_skip_white(reader);
+ top_item->jd_type = JSON_OBJECT;
+ if (cur_item != NULL)
+ cur_item = &item;
+ break;
+
+ case JSON_OBJECT:
+ if (cur_item != NULL
+ && dict_find(top_item->jd_tv.vval.v_dict,
+ top_item->jd_key, -1) != NULL)
+ {
+ semsg(_("E938: Duplicate key in JSON: \"%s\""),
+ top_item->jd_key);
+ clear_tv(&top_item->jd_key_tv);
+ clear_tv(cur_item);
+ retval = FAIL;
+ goto theend;
+ }
+
+ if (cur_item != NULL)
+ {
+ dictitem_T *di = dictitem_alloc(top_item->jd_key);
+
+ clear_tv(&top_item->jd_key_tv);
+ if (di == NULL)
+ {
+ clear_tv(cur_item);
+ retval = FAIL;
+ goto theend;
+ }
+ di->di_tv = *cur_item;
+ di->di_tv.v_lock = 0;
+ if (dict_add(top_item->jd_tv.vval.v_dict, di) == FAIL)
+ {
+ dictitem_free(di);
+ retval = FAIL;
+ goto theend;
+ }
+ }
+
+ json_skip_white(reader);
+ p = reader->js_buf + reader->js_used;
+ if (*p == ',')
+ ++reader->js_used;
+ else if (*p != '}')
+ {
+ if (*p == NUL)
+ retval = MAYBE;
+ else
+ {
+ emsg(_(e_invarg));
+ retval = FAIL;
+ }
+ goto theend;
+ }
+ top_item->jd_type = JSON_OBJECT_KEY;
+ if (cur_item != NULL)
+ cur_item = &top_item->jd_key_tv;
+ break;
+ }
+ }
+
+ /* Get here when parsing failed. */
+ if (res != NULL)
+ {
+ clear_tv(res);
+ res->v_type = VAR_SPECIAL;
+ res->vval.v_number = VVAL_NONE;
+ }
+ emsg(_(e_invarg));
+
+theend:
+ ga_clear(&stack);
+ return retval;
+}
+
+/*
+ * Decode the JSON from "reader" and store the result in "res".
+ * "options" can be JSON_JS or zero;
+ * Return FAIL if not the whole message was consumed.
+ */
+ int
+json_decode_all(js_read_T *reader, typval_T *res, int options)
+{
+ int ret;
+
+ /* We find the end once, to avoid calling strlen() many times. */
+ reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
+ json_skip_white(reader);
+ ret = json_decode_item(reader, res, options);
+ if (ret != OK)
+ {
+ if (ret == MAYBE)
+ emsg(_(e_invarg));
+ return FAIL;
+ }
+ json_skip_white(reader);
+ if (reader->js_buf[reader->js_used] != NUL)
+ {
+ emsg(_(e_trailing));
+ return FAIL;
+ }
+ return OK;
+}
+
+#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
+/*
+ * Decode the JSON from "reader" and store the result in "res".
+ * "options" can be JSON_JS or zero;
+ * Return FAIL for a decoding error.
+ * Return MAYBE for an incomplete message.
+ * Consumes the message anyway.
+ */
+ int
+json_decode(js_read_T *reader, typval_T *res, int options)
+{
+ int ret;
+
+ /* We find the end once, to avoid calling strlen() many times. */
+ reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
+ json_skip_white(reader);
+ ret = json_decode_item(reader, res, options);
+ json_skip_white(reader);
+
+ return ret;
+}
+#endif
+
+/*
+ * Decode the JSON from "reader" to find the end of the message.
+ * "options" can be JSON_JS or zero.
+ * This is only used for testing.
+ * Return FAIL if the message has a decoding error.
+ * Return MAYBE if the message is truncated, need to read more.
+ * This only works reliable if the message contains an object, array or
+ * string. A number might be truncated without knowing.
+ * Does not advance the reader.
+ */
+ int
+json_find_end(js_read_T *reader, int options)
+{
+ int used_save = reader->js_used;
+ int ret;
+
+ /* We find the end once, to avoid calling strlen() many times. */
+ reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
+ json_skip_white(reader);
+ ret = json_decode_item(reader, NULL, options);
+ reader->js_used = used_save;
+ return ret;
+}
+#endif
diff --git a/src/json_test.c b/src/json_test.c
new file mode 100644
index 0000000..47bec8e
--- /dev/null
+++ b/src/json_test.c
@@ -0,0 +1,203 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * json_test.c: Unittests for json.c
+ */
+
+#undef NDEBUG
+#include <assert.h>
+
+/* Must include main.c because it contains much more than just main() */
+#define NO_VIM_MAIN
+#include "main.c"
+
+/* This file has to be included because the tested functions are static */
+#include "json.c"
+
+#if defined(FEAT_EVAL)
+/*
+ * Test json_find_end() with imcomplete items.
+ */
+ static void
+test_decode_find_end(void)
+{
+ js_read_T reader;
+
+ reader.js_fill = NULL;
+ reader.js_used = 0;
+
+ /* string and incomplete string */
+ reader.js_buf = (char_u *)"\"hello\"";
+ assert(json_find_end(&reader, 0) == OK);
+ reader.js_buf = (char_u *)" \"hello\" ";
+ assert(json_find_end(&reader, 0) == OK);
+ reader.js_buf = (char_u *)"\"hello";
+ assert(json_find_end(&reader, 0) == MAYBE);
+
+ /* number and dash (incomplete number) */
+ reader.js_buf = (char_u *)"123";
+ assert(json_find_end(&reader, 0) == OK);
+ reader.js_buf = (char_u *)"-";
+ assert(json_find_end(&reader, 0) == MAYBE);
+
+ /* false, true and null, also incomplete */
+ reader.js_buf = (char_u *)"false";
+ assert(json_find_end(&reader, 0) == OK);
+ reader.js_buf = (char_u *)"f";
+ assert(json_find_end(&reader, 0) == MAYBE);
+ reader.js_buf = (char_u *)"fa";
+ assert(json_find_end(&reader, 0) == MAYBE);
+ reader.js_buf = (char_u *)"fal";
+ assert(json_find_end(&reader, 0) == MAYBE);
+ reader.js_buf = (char_u *)"fals";
+ assert(json_find_end(&reader, 0) == MAYBE);
+
+ reader.js_buf = (char_u *)"true";
+ assert(json_find_end(&reader, 0) == OK);
+ reader.js_buf = (char_u *)"t";
+ assert(json_find_end(&reader, 0) == MAYBE);
+ reader.js_buf = (char_u *)"tr";
+ assert(json_find_end(&reader, 0) == MAYBE);
+ reader.js_buf = (char_u *)"tru";
+ assert(json_find_end(&reader, 0) == MAYBE);
+
+ reader.js_buf = (char_u *)"null";
+ assert(json_find_end(&reader, 0) == OK);
+ reader.js_buf = (char_u *)"n";
+ assert(json_find_end(&reader, 0) == MAYBE);
+ reader.js_buf = (char_u *)"nu";
+ assert(json_find_end(&reader, 0) == MAYBE);
+ reader.js_buf = (char_u *)"nul";
+ assert(json_find_end(&reader, 0) == MAYBE);
+
+ /* object without white space */
+ reader.js_buf = (char_u *)"{\"a\":123}";
+ assert(json_find_end(&reader, 0) == OK);
+ reader.js_buf = (char_u *)"{\"a\":123";
+ assert(json_find_end(&reader, 0) == MAYBE);
+ reader.js_buf = (char_u *)"{\"a\":";
+ assert(json_find_end(&reader, 0) == MAYBE);
+ reader.js_buf = (char_u *)"{\"a\"";
+ assert(json_find_end(&reader, 0) == MAYBE);
+ reader.js_buf = (char_u *)"{\"a";
+ assert(json_find_end(&reader, 0) == MAYBE);
+ reader.js_buf = (char_u *)"{\"";
+ assert(json_find_end(&reader, 0) == MAYBE);
+ reader.js_buf = (char_u *)"{";
+ assert(json_find_end(&reader, 0) == MAYBE);
+
+ /* object with white space */
+ reader.js_buf = (char_u *)" { \"a\" : 123 } ";
+ assert(json_find_end(&reader, 0) == OK);
+ reader.js_buf = (char_u *)" { \"a\" : 123 ";
+ assert(json_find_end(&reader, 0) == MAYBE);
+ reader.js_buf = (char_u *)" { \"a\" : ";
+ assert(json_find_end(&reader, 0) == MAYBE);
+ reader.js_buf = (char_u *)" { \"a\" ";
+ assert(json_find_end(&reader, 0) == MAYBE);
+ reader.js_buf = (char_u *)" { \"a ";
+ assert(json_find_end(&reader, 0) == MAYBE);
+ reader.js_buf = (char_u *)" { ";
+ assert(json_find_end(&reader, 0) == MAYBE);
+
+ /* JS object with white space */
+ reader.js_buf = (char_u *)" { a : 123 } ";
+ assert(json_find_end(&reader, JSON_JS) == OK);
+ reader.js_buf = (char_u *)" { a : ";
+ assert(json_find_end(&reader, JSON_JS) == MAYBE);
+
+ /* array without white space */
+ reader.js_buf = (char_u *)"[\"a\",123]";
+ assert(json_find_end(&reader, 0) == OK);
+ reader.js_buf = (char_u *)"[\"a\",123";
+ assert(json_find_end(&reader, 0) == MAYBE);
+ reader.js_buf = (char_u *)"[\"a\",";
+ assert(json_find_end(&reader, 0) == MAYBE);
+ reader.js_buf = (char_u *)"[\"a\"";
+ assert(json_find_end(&reader, 0) == MAYBE);
+ reader.js_buf = (char_u *)"[\"a";
+ assert(json_find_end(&reader, 0) == MAYBE);
+ reader.js_buf = (char_u *)"[\"";
+ assert(json_find_end(&reader, 0) == MAYBE);
+ reader.js_buf = (char_u *)"[";
+ assert(json_find_end(&reader, 0) == MAYBE);
+
+ /* array with white space */
+ reader.js_buf = (char_u *)" [ \"a\" , 123 ] ";
+ assert(json_find_end(&reader, 0) == OK);
+ reader.js_buf = (char_u *)" [ \"a\" , 123 ";
+ assert(json_find_end(&reader, 0) == MAYBE);
+ reader.js_buf = (char_u *)" [ \"a\" , ";
+ assert(json_find_end(&reader, 0) == MAYBE);
+ reader.js_buf = (char_u *)" [ \"a\" ";
+ assert(json_find_end(&reader, 0) == MAYBE);
+ reader.js_buf = (char_u *)" [ \"a ";
+ assert(json_find_end(&reader, 0) == MAYBE);
+ reader.js_buf = (char_u *)" [ ";
+ assert(json_find_end(&reader, 0) == MAYBE);
+}
+
+ static int
+fill_from_cookie(js_read_T *reader)
+{
+ reader->js_buf = reader->js_cookie;
+ return TRUE;
+}
+
+/*
+ * Test json_find_end with an incomplete array, calling the fill function.
+ */
+ static void
+test_fill_called_on_find_end(void)
+{
+ js_read_T reader;
+
+ reader.js_fill = fill_from_cookie;
+ reader.js_used = 0;
+ reader.js_buf = (char_u *)" [ \"a\" , 123 ";
+ reader.js_cookie = " [ \"a\" , 123 ] ";
+ assert(json_find_end(&reader, 0) == OK);
+ reader.js_buf = (char_u *)" [ \"a\" , ";
+ assert(json_find_end(&reader, 0) == OK);
+ reader.js_buf = (char_u *)" [ \"a\" ";
+ assert(json_find_end(&reader, 0) == OK);
+ reader.js_buf = (char_u *)" [ \"a";
+ assert(json_find_end(&reader, 0) == OK);
+ reader.js_buf = (char_u *)" [ ";
+ assert(json_find_end(&reader, 0) == OK);
+}
+
+/*
+ * Test json_find_end with an incomplete string, calling the fill function.
+ */
+ static void
+test_fill_called_on_string(void)
+{
+ js_read_T reader;
+
+ reader.js_fill = fill_from_cookie;
+ reader.js_used = 0;
+ reader.js_buf = (char_u *)" \"foo";
+ reader.js_end = reader.js_buf + STRLEN(reader.js_buf);
+ reader.js_cookie = " \"foobar\" ";
+ assert(json_decode_string(&reader, NULL, '"') == OK);
+}
+#endif
+
+ int
+main(void)
+{
+#if defined(FEAT_EVAL)
+ test_decode_find_end();
+ test_fill_called_on_find_end();
+ test_fill_called_on_string();
+#endif
+ return 0;
+}
diff --git a/src/keymap.h b/src/keymap.h
new file mode 100644
index 0000000..d6dd5cb
--- /dev/null
+++ b/src/keymap.h
@@ -0,0 +1,507 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * Do ":help uganda" in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ */
+
+/*
+ * Keycode definitions for special keys.
+ *
+ * Any special key code sequences are replaced by these codes.
+ */
+
+/*
+ * For MSDOS some keys produce codes larger than 0xff. They are split into two
+ * chars, the first one is K_NUL (same value used in term.h).
+ */
+#define K_NUL (0xce) /* for MSDOS: special key follows */
+
+/*
+ * K_SPECIAL is the first byte of a special key code and is always followed by
+ * two bytes.
+ * The second byte can have any value. ASCII is used for normal termcap
+ * entries, 0x80 and higher for special keys, see below.
+ * The third byte is guaranteed to be between 0x02 and 0x7f.
+ */
+
+#define K_SPECIAL (0x80)
+
+/*
+ * Positive characters are "normal" characters.
+ * Negative characters are special key codes. Only characters below -0x200
+ * are used to so that the absolute value can't be mistaken for a single-byte
+ * character.
+ */
+#define IS_SPECIAL(c) ((c) < 0)
+
+/*
+ * Characters 0x0100 - 0x01ff have a special meaning for abbreviations.
+ * Multi-byte characters also have ABBR_OFF added, thus are above 0x0200.
+ */
+#define ABBR_OFF 0x100
+
+/*
+ * NUL cannot be in the input string, therefore it is replaced by
+ * K_SPECIAL KS_ZERO KE_FILLER
+ */
+#define KS_ZERO 255
+
+/*
+ * K_SPECIAL cannot be in the input string, therefore it is replaced by
+ * K_SPECIAL KS_SPECIAL KE_FILLER
+ */
+#define KS_SPECIAL 254
+
+/*
+ * KS_EXTRA is used for keys that have no termcap name
+ * K_SPECIAL KS_EXTRA KE_xxx
+ */
+#define KS_EXTRA 253
+
+/*
+ * KS_MODIFIER is used when a modifier is given for a (special) key
+ * K_SPECIAL KS_MODIFIER bitmask
+ */
+#define KS_MODIFIER 252
+
+/*
+ * These are used for the GUI
+ * K_SPECIAL KS_xxx KE_FILLER
+ */
+#define KS_MOUSE 251
+#define KS_MENU 250
+#define KS_VER_SCROLLBAR 249
+#define KS_HOR_SCROLLBAR 248
+
+/*
+ * These are used for DEC mouse
+ */
+#define KS_NETTERM_MOUSE 247
+#define KS_DEC_MOUSE 246
+
+/*
+ * Used for switching Select mode back on after a mapping or menu.
+ */
+#define KS_SELECT 245
+#define K_SELECT_STRING (char_u *)"\200\365X"
+
+/*
+ * Used for tearing off a menu.
+ */
+#define KS_TEAROFF 244
+
+/* Used for JSB term mouse. */
+#define KS_JSBTERM_MOUSE 243
+
+/* Used a termcap entry that produces a normal character. */
+#define KS_KEY 242
+
+/* Used for the qnx pterm mouse. */
+#define KS_PTERM_MOUSE 241
+
+/* Used for click in a tab pages label. */
+#define KS_TABLINE 240
+
+/* Used for menu in a tab pages line. */
+#define KS_TABMENU 239
+
+/* Used for the urxvt mouse. */
+#define KS_URXVT_MOUSE 238
+
+/* Used for the sgr mouse. */
+#define KS_SGR_MOUSE 237
+#define KS_SGR_MOUSE_RELEASE 236
+
+/*
+ * Filler used after KS_SPECIAL and others
+ */
+#define KE_FILLER ('X')
+
+/*
+ * translation of three byte code "K_SPECIAL a b" into int "K_xxx" and back
+ */
+#define TERMCAP2KEY(a, b) (-((a) + ((int)(b) << 8)))
+#define KEY2TERMCAP0(x) ((-(x)) & 0xff)
+#define KEY2TERMCAP1(x) (((unsigned)(-(x)) >> 8) & 0xff)
+
+/*
+ * get second or third byte when translating special key code into three bytes
+ */
+#define K_SECOND(c) ((c) == K_SPECIAL ? KS_SPECIAL : (c) == NUL ? KS_ZERO : KEY2TERMCAP0(c))
+
+#define K_THIRD(c) (((c) == K_SPECIAL || (c) == NUL) ? KE_FILLER : KEY2TERMCAP1(c))
+
+/*
+ * get single int code from second byte after K_SPECIAL
+ */
+#define TO_SPECIAL(a, b) ((a) == KS_SPECIAL ? K_SPECIAL : (a) == KS_ZERO ? K_ZERO : TERMCAP2KEY(a, b))
+
+/*
+ * Codes for keys that do not have a termcap name.
+ * The numbers are fixed to make sure that recorded key sequences remain valid.
+ * Add new entries at the end, not halfway.
+ *
+ * K_SPECIAL KS_EXTRA KE_xxx
+ */
+enum key_extra
+{
+ KE_NAME = 3 /* name of this terminal entry */
+
+ , KE_S_UP = 4 /* shift-up */
+ , KE_S_DOWN = 5 /* shift-down */
+
+ , KE_S_F1 = 6 /* shifted function keys */
+ , KE_S_F2 = 7
+ , KE_S_F3 = 8
+ , KE_S_F4 = 9
+ , KE_S_F5 = 10
+ , KE_S_F6 = 11
+ , KE_S_F7 = 12
+ , KE_S_F8 = 13
+ , KE_S_F9 = 14
+ , KE_S_F10 = 15
+
+ , KE_S_F11 = 16
+ , KE_S_F12 = 17
+ , KE_S_F13 = 18
+ , KE_S_F14 = 19
+ , KE_S_F15 = 20
+ , KE_S_F16 = 21
+ , KE_S_F17 = 22
+ , KE_S_F18 = 23
+ , KE_S_F19 = 24
+ , KE_S_F20 = 25
+
+ , KE_S_F21 = 26
+ , KE_S_F22 = 27
+ , KE_S_F23 = 28
+ , KE_S_F24 = 29
+ , KE_S_F25 = 30
+ , KE_S_F26 = 31
+ , KE_S_F27 = 32
+ , KE_S_F28 = 33
+ , KE_S_F29 = 34
+ , KE_S_F30 = 35
+
+ , KE_S_F31 = 36
+ , KE_S_F32 = 37
+ , KE_S_F33 = 38
+ , KE_S_F34 = 39
+ , KE_S_F35 = 40
+ , KE_S_F36 = 41
+ , KE_S_F37 = 42
+
+ , KE_MOUSE = 43 /* mouse event start */
+
+/*
+ * Symbols for pseudo keys which are translated from the real key symbols
+ * above.
+ */
+ , KE_LEFTMOUSE = 44 /* Left mouse button click */
+ , KE_LEFTDRAG = 45 /* Drag with left mouse button down */
+ , KE_LEFTRELEASE = 46 /* Left mouse button release */
+ , KE_MIDDLEMOUSE = 47 /* Middle mouse button click */
+ , KE_MIDDLEDRAG = 48 /* Drag with middle mouse button down */
+ , KE_MIDDLERELEASE = 49 /* Middle mouse button release */
+ , KE_RIGHTMOUSE = 50 /* Right mouse button click */
+ , KE_RIGHTDRAG = 51 /* Drag with right mouse button down */
+ , KE_RIGHTRELEASE = 52 /* Right mouse button release */
+
+ , KE_IGNORE = 53 /* Ignored mouse drag/release */
+
+ , KE_TAB = 54 /* unshifted TAB key */
+ , KE_S_TAB_OLD = 55 /* shifted TAB key (no longer used) */
+
+ , KE_SNIFF_UNUSED = 56 /* obsolete */
+ , KE_XF1 = 57 /* extra vt100 function keys for xterm */
+ , KE_XF2 = 58
+ , KE_XF3 = 59
+ , KE_XF4 = 60
+ , KE_XEND = 61 /* extra (vt100) end key for xterm */
+ , KE_ZEND = 62 /* extra (vt100) end key for xterm */
+ , KE_XHOME = 63 /* extra (vt100) home key for xterm */
+ , KE_ZHOME = 64 /* extra (vt100) home key for xterm */
+ , KE_XUP = 65 /* extra vt100 cursor keys for xterm */
+ , KE_XDOWN = 66
+ , KE_XLEFT = 67
+ , KE_XRIGHT = 68
+
+ , KE_LEFTMOUSE_NM = 69 /* non-mappable Left mouse button click */
+ , KE_LEFTRELEASE_NM = 70 /* non-mappable left mouse button release */
+
+ , KE_S_XF1 = 71 /* vt100 shifted function keys for xterm */
+ , KE_S_XF2 = 72
+ , KE_S_XF3 = 73
+ , KE_S_XF4 = 74
+
+ /* NOTE: The scroll wheel events are inverted: i.e. UP is the same as
+ * moving the actual scroll wheel down, LEFT is the same as moving the
+ * scroll wheel right. */
+ , KE_MOUSEDOWN = 75 /* scroll wheel pseudo-button Down */
+ , KE_MOUSEUP = 76 /* scroll wheel pseudo-button Up */
+ , KE_MOUSELEFT = 77 /* scroll wheel pseudo-button Left */
+ , KE_MOUSERIGHT = 78 /* scroll wheel pseudo-button Right */
+
+ , KE_KINS = 79 /* keypad Insert key */
+ , KE_KDEL = 80 /* keypad Delete key */
+
+ , KE_CSI = 81 /* CSI typed directly */
+ , KE_SNR = 82 /* <SNR> */
+ , KE_PLUG = 83 /* <Plug> */
+ , KE_CMDWIN = 84 /* open command-line window from Command-line Mode */
+
+ , KE_C_LEFT = 85 /* control-left */
+ , KE_C_RIGHT = 86 /* control-right */
+ , KE_C_HOME = 87 /* control-home */
+ , KE_C_END = 88 /* control-end */
+
+ , KE_X1MOUSE = 89 /* X1/X2 mouse-buttons */
+ , KE_X1DRAG = 90
+ , KE_X1RELEASE = 91
+ , KE_X2MOUSE = 92
+ , KE_X2DRAG = 93
+ , KE_X2RELEASE = 94
+
+ , KE_DROP = 95 /* DnD data is available */
+ , KE_CURSORHOLD = 96 /* CursorHold event */
+ , KE_NOP = 97 /* doesn't do something */
+ , KE_FOCUSGAINED = 98 /* focus gained */
+ , KE_FOCUSLOST = 99 /* focus lost */
+ , KE_MOUSEMOVE = 100 /* mouse moved with no button down */
+ , KE_CANCEL = 101 /* return from vgetc() */
+};
+
+/*
+ * the three byte codes are replaced with the following int when using vgetc()
+ */
+#define K_ZERO TERMCAP2KEY(KS_ZERO, KE_FILLER)
+
+#define K_UP TERMCAP2KEY('k', 'u')
+#define K_DOWN TERMCAP2KEY('k', 'd')
+#define K_LEFT TERMCAP2KEY('k', 'l')
+#define K_RIGHT TERMCAP2KEY('k', 'r')
+#define K_S_UP TERMCAP2KEY(KS_EXTRA, KE_S_UP)
+#define K_S_DOWN TERMCAP2KEY(KS_EXTRA, KE_S_DOWN)
+#define K_S_LEFT TERMCAP2KEY('#', '4')
+#define K_C_LEFT TERMCAP2KEY(KS_EXTRA, KE_C_LEFT)
+#define K_S_RIGHT TERMCAP2KEY('%', 'i')
+#define K_C_RIGHT TERMCAP2KEY(KS_EXTRA, KE_C_RIGHT)
+#define K_S_HOME TERMCAP2KEY('#', '2')
+#define K_C_HOME TERMCAP2KEY(KS_EXTRA, KE_C_HOME)
+#define K_S_END TERMCAP2KEY('*', '7')
+#define K_C_END TERMCAP2KEY(KS_EXTRA, KE_C_END)
+#define K_TAB TERMCAP2KEY(KS_EXTRA, KE_TAB)
+#define K_S_TAB TERMCAP2KEY('k', 'B')
+
+/* extra set of function keys F1-F4, for vt100 compatible xterm */
+#define K_XF1 TERMCAP2KEY(KS_EXTRA, KE_XF1)
+#define K_XF2 TERMCAP2KEY(KS_EXTRA, KE_XF2)
+#define K_XF3 TERMCAP2KEY(KS_EXTRA, KE_XF3)
+#define K_XF4 TERMCAP2KEY(KS_EXTRA, KE_XF4)
+
+/* extra set of cursor keys for vt100 compatible xterm */
+#define K_XUP TERMCAP2KEY(KS_EXTRA, KE_XUP)
+#define K_XDOWN TERMCAP2KEY(KS_EXTRA, KE_XDOWN)
+#define K_XLEFT TERMCAP2KEY(KS_EXTRA, KE_XLEFT)
+#define K_XRIGHT TERMCAP2KEY(KS_EXTRA, KE_XRIGHT)
+
+#define K_F1 TERMCAP2KEY('k', '1') /* function keys */
+#define K_F2 TERMCAP2KEY('k', '2')
+#define K_F3 TERMCAP2KEY('k', '3')
+#define K_F4 TERMCAP2KEY('k', '4')
+#define K_F5 TERMCAP2KEY('k', '5')
+#define K_F6 TERMCAP2KEY('k', '6')
+#define K_F7 TERMCAP2KEY('k', '7')
+#define K_F8 TERMCAP2KEY('k', '8')
+#define K_F9 TERMCAP2KEY('k', '9')
+#define K_F10 TERMCAP2KEY('k', ';')
+
+#define K_F11 TERMCAP2KEY('F', '1')
+#define K_F12 TERMCAP2KEY('F', '2')
+#define K_F13 TERMCAP2KEY('F', '3')
+#define K_F14 TERMCAP2KEY('F', '4')
+#define K_F15 TERMCAP2KEY('F', '5')
+#define K_F16 TERMCAP2KEY('F', '6')
+#define K_F17 TERMCAP2KEY('F', '7')
+#define K_F18 TERMCAP2KEY('F', '8')
+#define K_F19 TERMCAP2KEY('F', '9')
+#define K_F20 TERMCAP2KEY('F', 'A')
+
+#define K_F21 TERMCAP2KEY('F', 'B')
+#define K_F22 TERMCAP2KEY('F', 'C')
+#define K_F23 TERMCAP2KEY('F', 'D')
+#define K_F24 TERMCAP2KEY('F', 'E')
+#define K_F25 TERMCAP2KEY('F', 'F')
+#define K_F26 TERMCAP2KEY('F', 'G')
+#define K_F27 TERMCAP2KEY('F', 'H')
+#define K_F28 TERMCAP2KEY('F', 'I')
+#define K_F29 TERMCAP2KEY('F', 'J')
+#define K_F30 TERMCAP2KEY('F', 'K')
+
+#define K_F31 TERMCAP2KEY('F', 'L')
+#define K_F32 TERMCAP2KEY('F', 'M')
+#define K_F33 TERMCAP2KEY('F', 'N')
+#define K_F34 TERMCAP2KEY('F', 'O')
+#define K_F35 TERMCAP2KEY('F', 'P')
+#define K_F36 TERMCAP2KEY('F', 'Q')
+#define K_F37 TERMCAP2KEY('F', 'R')
+
+/* extra set of shifted function keys F1-F4, for vt100 compatible xterm */
+#define K_S_XF1 TERMCAP2KEY(KS_EXTRA, KE_S_XF1)
+#define K_S_XF2 TERMCAP2KEY(KS_EXTRA, KE_S_XF2)
+#define K_S_XF3 TERMCAP2KEY(KS_EXTRA, KE_S_XF3)
+#define K_S_XF4 TERMCAP2KEY(KS_EXTRA, KE_S_XF4)
+
+#define K_S_F1 TERMCAP2KEY(KS_EXTRA, KE_S_F1) /* shifted func. keys */
+#define K_S_F2 TERMCAP2KEY(KS_EXTRA, KE_S_F2)
+#define K_S_F3 TERMCAP2KEY(KS_EXTRA, KE_S_F3)
+#define K_S_F4 TERMCAP2KEY(KS_EXTRA, KE_S_F4)
+#define K_S_F5 TERMCAP2KEY(KS_EXTRA, KE_S_F5)
+#define K_S_F6 TERMCAP2KEY(KS_EXTRA, KE_S_F6)
+#define K_S_F7 TERMCAP2KEY(KS_EXTRA, KE_S_F7)
+#define K_S_F8 TERMCAP2KEY(KS_EXTRA, KE_S_F8)
+#define K_S_F9 TERMCAP2KEY(KS_EXTRA, KE_S_F9)
+#define K_S_F10 TERMCAP2KEY(KS_EXTRA, KE_S_F10)
+
+#define K_S_F11 TERMCAP2KEY(KS_EXTRA, KE_S_F11)
+#define K_S_F12 TERMCAP2KEY(KS_EXTRA, KE_S_F12)
+/* K_S_F13 to K_S_F37 are currently not used */
+
+#define K_HELP TERMCAP2KEY('%', '1')
+#define K_UNDO TERMCAP2KEY('&', '8')
+
+#define K_BS TERMCAP2KEY('k', 'b')
+
+#define K_INS TERMCAP2KEY('k', 'I')
+#define K_KINS TERMCAP2KEY(KS_EXTRA, KE_KINS)
+#define K_DEL TERMCAP2KEY('k', 'D')
+#define K_KDEL TERMCAP2KEY(KS_EXTRA, KE_KDEL)
+#define K_HOME TERMCAP2KEY('k', 'h')
+#define K_KHOME TERMCAP2KEY('K', '1') /* keypad home (upper left) */
+#define K_XHOME TERMCAP2KEY(KS_EXTRA, KE_XHOME)
+#define K_ZHOME TERMCAP2KEY(KS_EXTRA, KE_ZHOME)
+#define K_END TERMCAP2KEY('@', '7')
+#define K_KEND TERMCAP2KEY('K', '4') /* keypad end (lower left) */
+#define K_XEND TERMCAP2KEY(KS_EXTRA, KE_XEND)
+#define K_ZEND TERMCAP2KEY(KS_EXTRA, KE_ZEND)
+#define K_PAGEUP TERMCAP2KEY('k', 'P')
+#define K_PAGEDOWN TERMCAP2KEY('k', 'N')
+#define K_KPAGEUP TERMCAP2KEY('K', '3') /* keypad pageup (upper R.) */
+#define K_KPAGEDOWN TERMCAP2KEY('K', '5') /* keypad pagedown (lower R.) */
+
+#define K_KPLUS TERMCAP2KEY('K', '6') /* keypad plus */
+#define K_KMINUS TERMCAP2KEY('K', '7') /* keypad minus */
+#define K_KDIVIDE TERMCAP2KEY('K', '8') /* keypad / */
+#define K_KMULTIPLY TERMCAP2KEY('K', '9') /* keypad * */
+#define K_KENTER TERMCAP2KEY('K', 'A') /* keypad Enter */
+#define K_KPOINT TERMCAP2KEY('K', 'B') /* keypad . or ,*/
+#define K_PS TERMCAP2KEY('P', 'S') /* paste start */
+#define K_PE TERMCAP2KEY('P', 'E') /* paste end */
+
+#define K_K0 TERMCAP2KEY('K', 'C') /* keypad 0 */
+#define K_K1 TERMCAP2KEY('K', 'D') /* keypad 1 */
+#define K_K2 TERMCAP2KEY('K', 'E') /* keypad 2 */
+#define K_K3 TERMCAP2KEY('K', 'F') /* keypad 3 */
+#define K_K4 TERMCAP2KEY('K', 'G') /* keypad 4 */
+#define K_K5 TERMCAP2KEY('K', 'H') /* keypad 5 */
+#define K_K6 TERMCAP2KEY('K', 'I') /* keypad 6 */
+#define K_K7 TERMCAP2KEY('K', 'J') /* keypad 7 */
+#define K_K8 TERMCAP2KEY('K', 'K') /* keypad 8 */
+#define K_K9 TERMCAP2KEY('K', 'L') /* keypad 9 */
+
+#define K_MOUSE TERMCAP2KEY(KS_MOUSE, KE_FILLER)
+#define K_MENU TERMCAP2KEY(KS_MENU, KE_FILLER)
+#define K_VER_SCROLLBAR TERMCAP2KEY(KS_VER_SCROLLBAR, KE_FILLER)
+#define K_HOR_SCROLLBAR TERMCAP2KEY(KS_HOR_SCROLLBAR, KE_FILLER)
+
+#define K_NETTERM_MOUSE TERMCAP2KEY(KS_NETTERM_MOUSE, KE_FILLER)
+#define K_DEC_MOUSE TERMCAP2KEY(KS_DEC_MOUSE, KE_FILLER)
+#define K_JSBTERM_MOUSE TERMCAP2KEY(KS_JSBTERM_MOUSE, KE_FILLER)
+#define K_PTERM_MOUSE TERMCAP2KEY(KS_PTERM_MOUSE, KE_FILLER)
+#define K_URXVT_MOUSE TERMCAP2KEY(KS_URXVT_MOUSE, KE_FILLER)
+#define K_SGR_MOUSE TERMCAP2KEY(KS_SGR_MOUSE, KE_FILLER)
+#define K_SGR_MOUSERELEASE TERMCAP2KEY(KS_SGR_MOUSE_RELEASE, KE_FILLER)
+
+#define K_SELECT TERMCAP2KEY(KS_SELECT, KE_FILLER)
+#define K_TEAROFF TERMCAP2KEY(KS_TEAROFF, KE_FILLER)
+
+#define K_TABLINE TERMCAP2KEY(KS_TABLINE, KE_FILLER)
+#define K_TABMENU TERMCAP2KEY(KS_TABMENU, KE_FILLER)
+
+/*
+ * Symbols for pseudo keys which are translated from the real key symbols
+ * above.
+ */
+#define K_LEFTMOUSE TERMCAP2KEY(KS_EXTRA, KE_LEFTMOUSE)
+#define K_LEFTMOUSE_NM TERMCAP2KEY(KS_EXTRA, KE_LEFTMOUSE_NM)
+#define K_LEFTDRAG TERMCAP2KEY(KS_EXTRA, KE_LEFTDRAG)
+#define K_LEFTRELEASE TERMCAP2KEY(KS_EXTRA, KE_LEFTRELEASE)
+#define K_LEFTRELEASE_NM TERMCAP2KEY(KS_EXTRA, KE_LEFTRELEASE_NM)
+#define K_MOUSEMOVE TERMCAP2KEY(KS_EXTRA, KE_MOUSEMOVE)
+#define K_MIDDLEMOUSE TERMCAP2KEY(KS_EXTRA, KE_MIDDLEMOUSE)
+#define K_MIDDLEDRAG TERMCAP2KEY(KS_EXTRA, KE_MIDDLEDRAG)
+#define K_MIDDLERELEASE TERMCAP2KEY(KS_EXTRA, KE_MIDDLERELEASE)
+#define K_RIGHTMOUSE TERMCAP2KEY(KS_EXTRA, KE_RIGHTMOUSE)
+#define K_RIGHTDRAG TERMCAP2KEY(KS_EXTRA, KE_RIGHTDRAG)
+#define K_RIGHTRELEASE TERMCAP2KEY(KS_EXTRA, KE_RIGHTRELEASE)
+#define K_X1MOUSE TERMCAP2KEY(KS_EXTRA, KE_X1MOUSE)
+#define K_X1MOUSE TERMCAP2KEY(KS_EXTRA, KE_X1MOUSE)
+#define K_X1DRAG TERMCAP2KEY(KS_EXTRA, KE_X1DRAG)
+#define K_X1RELEASE TERMCAP2KEY(KS_EXTRA, KE_X1RELEASE)
+#define K_X2MOUSE TERMCAP2KEY(KS_EXTRA, KE_X2MOUSE)
+#define K_X2DRAG TERMCAP2KEY(KS_EXTRA, KE_X2DRAG)
+#define K_X2RELEASE TERMCAP2KEY(KS_EXTRA, KE_X2RELEASE)
+
+#define K_IGNORE TERMCAP2KEY(KS_EXTRA, KE_IGNORE)
+#define K_NOP TERMCAP2KEY(KS_EXTRA, KE_NOP)
+#define K_CANCEL TERMCAP2KEY(KS_EXTRA, KE_CANCEL)
+
+#define K_MOUSEDOWN TERMCAP2KEY(KS_EXTRA, KE_MOUSEDOWN)
+#define K_MOUSEUP TERMCAP2KEY(KS_EXTRA, KE_MOUSEUP)
+#define K_MOUSELEFT TERMCAP2KEY(KS_EXTRA, KE_MOUSELEFT)
+#define K_MOUSERIGHT TERMCAP2KEY(KS_EXTRA, KE_MOUSERIGHT)
+
+#define K_CSI TERMCAP2KEY(KS_EXTRA, KE_CSI)
+#define K_SNR TERMCAP2KEY(KS_EXTRA, KE_SNR)
+#define K_PLUG TERMCAP2KEY(KS_EXTRA, KE_PLUG)
+#define K_CMDWIN TERMCAP2KEY(KS_EXTRA, KE_CMDWIN)
+
+#define K_DROP TERMCAP2KEY(KS_EXTRA, KE_DROP)
+#define K_FOCUSGAINED TERMCAP2KEY(KS_EXTRA, KE_FOCUSGAINED)
+#define K_FOCUSLOST TERMCAP2KEY(KS_EXTRA, KE_FOCUSLOST)
+
+#define K_CURSORHOLD TERMCAP2KEY(KS_EXTRA, KE_CURSORHOLD)
+
+/* Bits for modifier mask */
+/* 0x01 cannot be used, because the modifier must be 0x02 or higher */
+#define MOD_MASK_SHIFT 0x02
+#define MOD_MASK_CTRL 0x04
+#define MOD_MASK_ALT 0x08 /* aka META */
+#define MOD_MASK_META 0x10 /* META when it's different from ALT */
+#define MOD_MASK_2CLICK 0x20 /* use MOD_MASK_MULTI_CLICK */
+#define MOD_MASK_3CLICK 0x40 /* use MOD_MASK_MULTI_CLICK */
+#define MOD_MASK_4CLICK 0x60 /* use MOD_MASK_MULTI_CLICK */
+#ifdef MACOS_X
+# define MOD_MASK_CMD 0x80
+#endif
+
+#define MOD_MASK_MULTI_CLICK (MOD_MASK_2CLICK|MOD_MASK_3CLICK|MOD_MASK_4CLICK)
+
+/*
+ * The length of the longest special key name, including modifiers.
+ * Current longest is <M-C-S-T-D-A-4-ScrollWheelRight> (length includes '<' and
+ * '>').
+ */
+#define MAX_KEY_NAME_LEN 32
+
+/* Maximum length of a special key event as tokens. This includes modifiers.
+ * The longest event is something like <M-C-S-T-4-LeftDrag> which would be the
+ * following string of tokens:
+ *
+ * <K_SPECIAL> <KS_MODIFIER> bitmask <K_SPECIAL> <KS_EXTRA> <KT_LEFTDRAG>.
+ *
+ * This is a total of 6 tokens, and is currently the longest one possible.
+ */
+#define MAX_KEY_CODE_LEN 6
diff --git a/src/kword_test.c b/src/kword_test.c
new file mode 100644
index 0000000..927c4fd
--- /dev/null
+++ b/src/kword_test.c
@@ -0,0 +1,81 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * kword_test.c: Unittests for vim_iswordc() and vim_iswordp().
+ */
+
+#undef NDEBUG
+#include <assert.h>
+
+/* Must include main.c because it contains much more than just main() */
+#define NO_VIM_MAIN
+#include "main.c"
+
+/* This file has to be included because the tested functions are static */
+#include "charset.c"
+
+/*
+ * Test the results of vim_iswordc() and vim_iswordp() are matched.
+ */
+ static void
+test_isword_funcs_utf8(void)
+{
+ buf_T buf;
+ int c;
+
+ vim_memset(&buf, 0, sizeof(buf));
+ p_enc = (char_u *)"utf-8";
+ p_isi = (char_u *)"";
+ p_isp = (char_u *)"";
+ p_isf = (char_u *)"";
+ buf.b_p_isk = (char_u *)"@,48-57,_,128-167,224-235";
+
+ curbuf = &buf;
+ mb_init(); /* calls init_chartab() */
+
+ for (c = 0; c < 0x10000; ++c)
+ {
+ char_u p[4] = {0};
+ int c1;
+ int retc;
+ int retp;
+
+ utf_char2bytes(c, p);
+ c1 = utf_ptr2char(p);
+ if (c != c1)
+ {
+ fprintf(stderr, "Failed: ");
+ fprintf(stderr,
+ "[c = %#04x, p = {%#02x, %#02x, %#02x}] ",
+ c, p[0], p[1], p[2]);
+ fprintf(stderr, "c != utf_ptr2char(p) (=%#04x)\n", c1);
+ abort();
+ }
+ retc = vim_iswordc_buf(c, &buf);
+ retp = vim_iswordp_buf(p, &buf);
+ if (retc != retp)
+ {
+ fprintf(stderr, "Failed: ");
+ fprintf(stderr,
+ "[c = %#04x, p = {%#02x, %#02x, %#02x}] ",
+ c, p[0], p[1], p[2]);
+ fprintf(stderr, "vim_iswordc(c) (=%d) != vim_iswordp(p) (=%d)\n",
+ retc, retp);
+ abort();
+ }
+ }
+}
+
+ int
+main(void)
+{
+ test_isword_funcs_utf8();
+ return 0;
+}
diff --git a/src/libvterm/.bzrignore b/src/libvterm/.bzrignore
new file mode 100644
index 0000000..e58c036
--- /dev/null
+++ b/src/libvterm/.bzrignore
@@ -0,0 +1,13 @@
+.libs
+*.lo
+*.la
+
+bin/*
+!bin/*.c
+
+pangoterm
+t/test
+t/suites.h
+t/externs.h
+t/harness
+src/encoding/*.inc
diff --git a/src/libvterm/.gitignore b/src/libvterm/.gitignore
new file mode 100644
index 0000000..5e5e308
--- /dev/null
+++ b/src/libvterm/.gitignore
@@ -0,0 +1,17 @@
+*~
+*.swp
+
+tags
+src/*.o
+src/*.lo
+
+libvterm.la
+bin/unterm
+bin/vterm-ctrl
+bin/vterm-dump
+
+t/harness
+t/harness.lo
+t/harness.o
+
+.libs/
diff --git a/src/libvterm/LICENSE b/src/libvterm/LICENSE
new file mode 100644
index 0000000..0d05163
--- /dev/null
+++ b/src/libvterm/LICENSE
@@ -0,0 +1,23 @@
+
+
+The MIT License
+
+Copyright (c) 2008 Paul Evans <leonerd@leonerd.org.uk>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/src/libvterm/Makefile b/src/libvterm/Makefile
new file mode 100644
index 0000000..2fca6ad
--- /dev/null
+++ b/src/libvterm/Makefile
@@ -0,0 +1,141 @@
+ifeq ($(shell uname),Darwin)
+ LIBTOOL ?= glibtool
+else
+ LIBTOOL ?= libtool
+endif
+
+ifneq ($(VERBOSE),1)
+ LIBTOOL +=--quiet
+endif
+
+override CFLAGS +=-Wall -Iinclude -std=c99 -Wpedantic -DINLINE=""
+
+ifeq ($(shell uname),SunOS)
+ override CFLAGS +=-D__EXTENSIONS__ -D_XPG6 -D__XOPEN_OR_POSIX
+endif
+
+ifeq ($(DEBUG),1)
+ override CFLAGS +=-ggdb -DDEBUG
+endif
+
+ifeq ($(PROFILE),1)
+ override CFLAGS +=-pg
+ override LDFLAGS+=-pg
+endif
+
+CFILES=$(sort $(wildcard src/*.c))
+HFILES=$(sort $(wildcard include/*.h))
+OBJECTS=$(CFILES:.c=.lo)
+LIBRARY=libvterm.la
+
+BINFILES_SRC=$(sort $(wildcard bin/*.c))
+BINFILES=$(BINFILES_SRC:.c=)
+
+TBLFILES=$(sort $(wildcard src/encoding/*.tbl))
+INCFILES=$(TBLFILES:.tbl=.inc)
+
+HFILES_INT=$(sort $(wildcard src/*.h)) $(HFILES)
+
+VERSION_MAJOR=0
+VERSION_MINOR=0
+
+VERSION_CURRENT=0
+VERSION_REVISION=0
+VERSION_AGE=0
+
+VERSION=0
+
+PREFIX=/usr/local
+BINDIR=$(PREFIX)/bin
+LIBDIR=$(PREFIX)/lib
+INCDIR=$(PREFIX)/include
+MANDIR=$(PREFIX)/share/man
+MAN3DIR=$(MANDIR)/man3
+
+# Uncomment to check for memory access errors with valgrind.
+# VALGRIND=1
+
+all: $(LIBRARY) $(BINFILES)
+
+$(LIBRARY): $(OBJECTS)
+ $(LIBTOOL) --mode=link --tag=CC $(CC) -rpath $(LIBDIR) -version-info $(VERSION_CURRENT):$(VERSION_REVISION):$(VERSION_AGE) -o $@ $^ $(LDFLAGS)
+
+src/%.lo: src/%.c $(HFILES_INT)
+ $(LIBTOOL) --mode=compile --tag=CC $(CC) $(CFLAGS) -o $@ -c $<
+
+src/encoding/%.inc: src/encoding/%.tbl
+ perl -CSD tbl2inc_c.pl $< >$@
+
+src/encoding.lo: $(INCFILES)
+
+bin/%: bin/%.c $(LIBRARY)
+ $(LIBTOOL) --mode=link --tag=CC $(CC) $(CFLAGS) -o $@ $< -lvterm $(LDFLAGS)
+
+t/harness.lo: t/harness.c $(HFILES)
+ $(LIBTOOL) --mode=compile --tag=CC $(CC) $(CFLAGS) -o $@ -c $<
+
+t/harness: t/harness.lo $(LIBRARY)
+ $(LIBTOOL) --mode=link --tag=CC $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
+
+.PHONY: test
+test: $(LIBRARY) t/harness
+ for T in `ls t/[0-9]*.test`; do echo "** $$T **"; perl t/run-test.pl $$T $(if $(VALGRIND),--valgrind) || exit 1; done
+
+.PHONY: clean
+clean:
+ $(LIBTOOL) --mode=clean rm -f $(OBJECTS) $(INCFILES)
+ $(LIBTOOL) --mode=clean rm -f t/harness.lo t/harness
+ $(LIBTOOL) --mode=clean rm -f $(LIBRARY) $(BINFILES)
+
+.PHONY: install
+install: install-inc install-lib install-bin
+
+install-inc:
+ install -d $(DESTDIR)$(INCDIR)
+ install -m644 $(HFILES) $(DESTDIR)$(INCDIR)
+ install -d $(DESTDIR)$(LIBDIR)/pkgconfig
+ sed -e "s,@PREFIX@,$(PREFIX)," -e "s,@LIBDIR@,$(LIBDIR)," -e "s,@VERSION@,$(VERSION)," <vterm.pc.in >$(DESTDIR)$(LIBDIR)/pkgconfig/vterm.pc
+
+install-lib: $(LIBRARY)
+ install -d $(DESTDIR)$(LIBDIR)
+ $(LIBTOOL) --mode=install install $(LIBRARY) $(DESTDIR)$(LIBDIR)/$(LIBRARY)
+ $(LIBTOOL) --mode=finish $(DESTDIR)$(LIBDIR)
+
+install-bin: $(BINFILES)
+ install -d $(DESTDIR)$(BINDIR)
+ $(LIBTOOL) --mode=install install $(BINFILES) $(DESTDIR)$(BINDIR)/
+
+# DIST CUT
+
+VERSION=$(VERSION_MAJOR).$(VERSION_MINOR)
+
+DISTDIR=libvterm-$(VERSION)
+
+distdir: $(INCFILES)
+ mkdir __distdir
+ cp LICENSE __distdir
+ mkdir __distdir/src
+ cp src/*.c src/*.h __distdir/src
+ mkdir __distdir/src/encoding
+ cp src/encoding/*.inc __distdir/src/encoding
+ mkdir __distdir/include
+ cp include/*.h __distdir/include
+ mkdir __distdir/bin
+ cp bin/*.c __distdir/bin
+ mkdir __distdir/t
+ cp t/*.test t/harness.c t/run-test.pl __distdir/t
+ sed "s,@VERSION@,$(VERSION)," <vterm.pc.in >__distdir/vterm.pc.in
+ sed "/^# DIST CUT/Q" <Makefile >__distdir/Makefile
+ mv __distdir $(DISTDIR)
+
+TARBALL=$(DISTDIR).tar.gz
+
+dist: distdir
+ tar -czf $(TARBALL) $(DISTDIR)
+ rm -rf $(DISTDIR)
+
+dist+bzr:
+ $(MAKE) dist VERSION=$(VERSION)+bzr`bzr revno`
+
+distdir+bzr:
+ $(MAKE) distdir VERSION=$(VERSION)+bzr`bzr revno`
diff --git a/src/libvterm/README b/src/libvterm/README
new file mode 100644
index 0000000..208066b
--- /dev/null
+++ b/src/libvterm/README
@@ -0,0 +1,30 @@
+This is a MODIFIED version of libvterm.
+
+The original can be found:
+- on the original site (tar archive and Bazaar repository):
+ http://www.leonerd.org.uk/code/libvterm/
+- cloned on Github:
+ https://github.com/neovim/libvterm
+
+Modifications:
+- Add a .gitignore file.
+- Convert from C99 to C90.
+- Other changes to support embedding in Vim.
+
+
+To merge in changes from Github, do this:
+- Commit any pending changes.
+- Setup the merge tool:
+ git config merge.tool vimdiff
+ git config merge.conflictstyle diff3
+ git config mergetool.prompt false
+- Run the merge tool:
+ git mergetool
+ This will open a four-way diff between:
+ LOCAL - your current version
+ BASE - version as it was at your last sync
+ REMOTE - version at head on Github
+ MERGED - best-effort merge of LOCAL and REMOTE
+ Now find places where automatic merge didn't work, they are marked with
+ <<<<<<<<, ======= and >>>>>>>
+ Fix those places in MERGED, remove the markers, and save the file :wqall.
diff --git a/src/libvterm/bin/unterm.c b/src/libvterm/bin/unterm.c
new file mode 100644
index 0000000..5c310d7
--- /dev/null
+++ b/src/libvterm/bin/unterm.c
@@ -0,0 +1,288 @@
+#include <stdio.h>
+#include <string.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <unistd.h>
+
+#include "vterm.h"
+
+#define DEFINE_INLINES
+#include "../src/utf8.h" // fill_utf8
+
+#define streq(a,b) (!strcmp(a,b))
+
+static VTerm *vt;
+static VTermScreen *vts;
+
+static int cols;
+static int rows;
+
+static enum {
+ FORMAT_PLAIN,
+ FORMAT_SGR,
+} format = FORMAT_PLAIN;
+
+static int col2index(VTermColor target)
+{
+ int index;
+
+ for(index = 0; index < 256; index++) {
+ VTermColor col;
+ vterm_state_get_palette_color(NULL, index, &col);
+ if(col.red == target.red && col.green == target.green && col.blue == target.blue)
+ return index;
+ }
+ return -1;
+}
+
+static void dump_cell(const VTermScreenCell *cell, const VTermScreenCell *prevcell)
+{
+ switch(format) {
+ case FORMAT_PLAIN:
+ break;
+ case FORMAT_SGR:
+ {
+ // If all 7 attributes change, that means 7 SGRs max
+ // Each colour could consume up to 3
+ int sgr[7 + 2*3]; int sgri = 0;
+
+ if(!prevcell->attrs.bold && cell->attrs.bold)
+ sgr[sgri++] = 1;
+ if(prevcell->attrs.bold && !cell->attrs.bold)
+ sgr[sgri++] = 22;
+
+ if(!prevcell->attrs.underline && cell->attrs.underline)
+ sgr[sgri++] = 4;
+ if(prevcell->attrs.underline && !cell->attrs.underline)
+ sgr[sgri++] = 24;
+
+ if(!prevcell->attrs.italic && cell->attrs.italic)
+ sgr[sgri++] = 3;
+ if(prevcell->attrs.italic && !cell->attrs.italic)
+ sgr[sgri++] = 23;
+
+ if(!prevcell->attrs.blink && cell->attrs.blink)
+ sgr[sgri++] = 5;
+ if(prevcell->attrs.blink && !cell->attrs.blink)
+ sgr[sgri++] = 25;
+
+ if(!prevcell->attrs.reverse && cell->attrs.reverse)
+ sgr[sgri++] = 7;
+ if(prevcell->attrs.reverse && !cell->attrs.reverse)
+ sgr[sgri++] = 27;
+
+ if(!prevcell->attrs.strike && cell->attrs.strike)
+ sgr[sgri++] = 9;
+ if(prevcell->attrs.strike && !cell->attrs.strike)
+ sgr[sgri++] = 29;
+
+ if(!prevcell->attrs.font && cell->attrs.font)
+ sgr[sgri++] = 10 + cell->attrs.font;
+ if(prevcell->attrs.font && !cell->attrs.font)
+ sgr[sgri++] = 10;
+
+ if(prevcell->fg.red != cell->fg.red ||
+ prevcell->fg.green != cell->fg.green ||
+ prevcell->fg.blue != cell->fg.blue) {
+ int index = col2index(cell->fg);
+ if(index == -1)
+ sgr[sgri++] = 39;
+ else if(index < 8)
+ sgr[sgri++] = 30 + index;
+ else if(index < 16)
+ sgr[sgri++] = 90 + (index - 8);
+ else {
+ sgr[sgri++] = 38;
+ sgr[sgri++] = 5 | CSI_ARG_FLAG_MORE;
+ sgr[sgri++] = index | CSI_ARG_FLAG_MORE;
+ }
+ }
+
+ if(prevcell->bg.red != cell->bg.red ||
+ prevcell->bg.green != cell->bg.green ||
+ prevcell->bg.blue != cell->bg.blue) {
+ int index = col2index(cell->bg);
+ if(index == -1)
+ sgr[sgri++] = 49;
+ else if(index < 8)
+ sgr[sgri++] = 40 + index;
+ else if(index < 16)
+ sgr[sgri++] = 100 + (index - 8);
+ else {
+ sgr[sgri++] = 48;
+ sgr[sgri++] = 5 | CSI_ARG_FLAG_MORE;
+ sgr[sgri++] = index | CSI_ARG_FLAG_MORE;
+ }
+ }
+
+ if(!sgri)
+ break;
+
+ printf("\x1b[");
+ {
+ int i;
+ for(i = 0; i < sgri; i++)
+ printf(!i ? "%d" :
+ CSI_ARG_HAS_MORE(sgr[i]) ? ":%d" :
+ ";%d",
+ CSI_ARG(sgr[i]));
+ }
+ printf("m");
+ }
+ break;
+ }
+
+ {
+ int i;
+ for(i = 0; i < VTERM_MAX_CHARS_PER_CELL && cell->chars[i]; i++) {
+ char bytes[6];
+ bytes[fill_utf8(cell->chars[i], bytes)] = 0;
+ printf("%s", bytes);
+ }
+ }
+}
+
+static void dump_eol(const VTermScreenCell *prevcell)
+{
+ switch(format) {
+ case FORMAT_PLAIN:
+ break;
+ case FORMAT_SGR:
+ if(prevcell->attrs.bold || prevcell->attrs.underline || prevcell->attrs.italic ||
+ prevcell->attrs.blink || prevcell->attrs.reverse || prevcell->attrs.strike ||
+ prevcell->attrs.font)
+ printf("\x1b[m");
+ break;
+ }
+
+ printf("\n");
+}
+
+void dump_row(int row)
+{
+ VTermPos pos;
+ VTermScreenCell prevcell;
+ pos.row = row;
+ pos.col = 0;
+ memset(&prevcell, 0, sizeof(prevcell));
+ vterm_state_get_default_colors(vterm_obtain_state(vt), &prevcell.fg, &prevcell.bg);
+
+ while(pos.col < cols) {
+ VTermScreenCell cell;
+ vterm_screen_get_cell(vts, pos, &cell);
+
+ dump_cell(&cell, &prevcell);
+
+ pos.col += cell.width;
+ prevcell = cell;
+ }
+
+ dump_eol(&prevcell);
+}
+
+static int screen_sb_pushline(int cols, const VTermScreenCell *cells, void *user)
+{
+ VTermScreenCell prevcell;
+ int col;
+
+ memset(&prevcell, 0, sizeof(prevcell));
+ vterm_state_get_default_colors(vterm_obtain_state(vt), &prevcell.fg, &prevcell.bg);
+
+ for(col = 0; col < cols; col++) {
+ dump_cell(cells + col, &prevcell);
+ prevcell = cells[col];
+ }
+
+ dump_eol(&prevcell);
+
+ return 1;
+}
+
+static int screen_resize(int new_rows, int new_cols, void *user)
+{
+ rows = new_rows;
+ cols = new_cols;
+ return 1;
+}
+
+static VTermScreenCallbacks cb_screen = {
+ NULL, /* damage */
+ NULL, /* moverect */
+ NULL, /* movecursor */
+ NULL, /* settermprop */
+ NULL, /* bell */
+ &screen_resize, /* resize */
+ &screen_sb_pushline, /* sb_pushline */
+ NULL, /* popline */
+};
+
+int main(int argc, char *argv[])
+{
+ int opt;
+ const char *file;
+ int fd;
+ int len;
+ char buffer[1024];
+ int row;
+
+ rows = 25;
+ cols = 80;
+
+ while((opt = getopt(argc, argv, "f:l:c:")) != -1) {
+ switch(opt) {
+ case 'f':
+ if(streq(optarg, "plain"))
+ format = FORMAT_PLAIN;
+ else if(streq(optarg, "sgr"))
+ format = FORMAT_SGR;
+ else {
+ fprintf(stderr, "Unrecognised format '%s'\n", optarg);
+ exit(1);
+ }
+ break;
+
+ case 'l':
+ rows = atoi(optarg);
+ if(!rows)
+ rows = 25;
+ break;
+
+ case 'c':
+ cols = atoi(optarg);
+ if(!cols)
+ cols = 80;
+ break;
+ }
+ }
+
+ file = argv[optind++];
+ fd = open(file, O_RDONLY);
+ if(fd == -1) {
+ fprintf(stderr, "Cannot open %s - %s\n", file, strerror(errno));
+ exit(1);
+ }
+
+ vt = vterm_new(rows, cols);
+ vterm_set_utf8(vt, TRUE);
+
+ vts = vterm_obtain_screen(vt);
+ vterm_screen_set_callbacks(vts, &cb_screen, NULL);
+
+ vterm_screen_reset(vts, 1);
+
+ while((len = read(fd, buffer, sizeof(buffer))) > 0) {
+ vterm_input_write(vt, buffer, len);
+ }
+
+ for(row = 0; row < rows; row++) {
+ dump_row(row);
+ }
+
+ close(fd);
+
+ vterm_free(vt);
+
+ return 0;
+}
diff --git a/src/libvterm/bin/vterm-ctrl.c b/src/libvterm/bin/vterm-ctrl.c
new file mode 100644
index 0000000..7c08fe1
--- /dev/null
+++ b/src/libvterm/bin/vterm-ctrl.c
@@ -0,0 +1,368 @@
+#define _XOPEN_SOURCE 500 /* strdup */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#define streq(a,b) (strcmp(a,b)==0)
+#define TRUE 1
+#define FALSE 0
+
+#include <termios.h>
+
+static char *getvalue(int *argip, int argc, char *argv[])
+{
+ if(*argip >= argc) {
+ fprintf(stderr, "Expected an option value\n");
+ exit(1);
+ }
+
+ return argv[(*argip)++];
+}
+
+static int getchoice(int *argip, int argc, char *argv[], const char *options[])
+{
+ const char *arg = getvalue(argip, argc, argv);
+
+ int value = -1;
+ while(options[++value])
+ if(streq(arg, options[value]))
+ return value;
+
+ fprintf(stderr, "Unrecognised option value %s\n", arg);
+ exit(1);
+}
+
+typedef enum {
+ OFF,
+ ON,
+ QUERY,
+} BoolQuery;
+
+static BoolQuery getboolq(int *argip, int argc, char *argv[])
+{
+ const char *choices[] = {"off", "on", "query", NULL};
+ return getchoice(argip, argc, argv, choices);
+}
+
+static char *helptext[] = {
+ "reset",
+ "s8c1t [off|on]",
+ "keypad [app|num]",
+ "screen [off|on|query]",
+ "cursor [off|on|query]",
+ "curblink [off|on|query]",
+ "curshape [block|under|bar|query]",
+ "mouse [off|click|clickdrag|motion]",
+ "reportfocus [off|on|query]",
+ "altscreen [off|on|query]",
+ "bracketpaste [off|on|query]",
+ "icontitle [STR]",
+ "icon [STR]",
+ "title [STR]",
+ NULL
+};
+
+static int seticanon(int icanon, int echo)
+{
+ struct termios termios;
+ int ret;
+
+ tcgetattr(0, &termios);
+
+ ret = (termios.c_lflag & ICANON);
+
+ if(icanon) termios.c_lflag |= ICANON;
+ else termios.c_lflag &= ~ICANON;
+
+ if(echo) termios.c_lflag |= ECHO;
+ else termios.c_lflag &= ~ECHO;
+
+ tcsetattr(0, TCSANOW, &termios);
+
+ return ret;
+}
+
+static void await_c1(unsigned char c1)
+{
+ unsigned char c;
+
+ /* await CSI - 8bit or 2byte 7bit form */
+ int in_esc = FALSE;
+ while((c = getchar())) {
+ if(c == c1)
+ break;
+ if(in_esc && c == (char)(c1 - 0x40))
+ break;
+ if(!in_esc && c == 0x1b)
+ in_esc = TRUE;
+ else
+ in_esc = FALSE;
+ }
+}
+
+static char *read_csi()
+{
+ unsigned char csi[32];
+ int i = 0;
+
+ await_c1(0x9B); // CSI
+
+ /* TODO: This really should be a more robust CSI parser
+ */
+ for(; i < sizeof(csi)-1; i++) {
+ int c = csi[i] = getchar();
+ if(c >= 0x40 && c <= 0x7e)
+ break;
+ }
+ csi[++i] = 0;
+
+ // TODO: returns longer than 32?
+
+ return strdup((char *)csi);
+}
+
+static char *read_dcs()
+{
+ unsigned char dcs[32];
+ int in_esc = FALSE;
+ int i;
+
+ await_c1(0x90);
+
+ for(i = 0; i < sizeof(dcs)-1; ) {
+ char c = getchar();
+ if(c == 0x9c) // ST
+ break;
+ if(in_esc && c == 0x5c)
+ break;
+ if(!in_esc && c == 0x1b)
+ in_esc = TRUE;
+ else {
+ dcs[i++] = c;
+ in_esc = FALSE;
+ }
+ }
+ dcs[++i] = 0;
+
+ return strdup((char *)dcs);
+}
+
+static void usage(int exitcode)
+{
+ char **p;
+
+ fprintf(stderr, "Control a libvterm-based terminal\n"
+ "\n"
+ "Options:\n");
+
+ for(p = helptext; *p; p++)
+ fprintf(stderr, " %s\n", *p);
+
+ exit(exitcode);
+}
+
+static int query_dec_mode(int mode)
+{
+ char *s = NULL;
+
+ printf("\x1b[?%d$p", mode);
+
+ do {
+ int reply_mode, reply_value;
+ char reply_cmd;
+
+ if(s)
+ free(s);
+ s = read_csi();
+
+ /* expect "?" mode ";" value "$y" */
+
+ /* If the sscanf format string ends in a literal, we can't tell from
+ * its return value if it matches. Hence we'll %c the cmd and check it
+ * explicitly
+ */
+ if(sscanf(s, "?%d;%d$%c", &reply_mode, &reply_value, &reply_cmd) < 3)
+ continue;
+ if(reply_cmd != 'y')
+ continue;
+
+ if(reply_mode != mode)
+ continue;
+
+ free(s);
+
+ if(reply_value == 1 || reply_value == 3)
+ return TRUE;
+ if(reply_value == 2 || reply_value == 4)
+ return FALSE;
+
+ printf("Unrecognised reply to DECRQM: %d\n", reply_value);
+ return FALSE;
+ } while(1);
+}
+
+static void do_dec_mode(int mode, BoolQuery val, const char *name)
+{
+ switch(val) {
+ case OFF:
+ case ON:
+ printf("\x1b[?%d%c", mode, val == ON ? 'h' : 'l');
+ break;
+
+ case QUERY:
+ if(query_dec_mode(mode))
+ printf("%s on\n", name);
+ else
+ printf("%s off\n", name);
+ break;
+ }
+}
+
+static int query_rqss_numeric(char *cmd)
+{
+ char *s = NULL;
+
+ printf("\x1bP$q%s\x1b\\", cmd);
+
+ do {
+ int num;
+
+ if(s)
+ free(s);
+ s = read_dcs();
+
+ if(!s)
+ return -1;
+ if(strlen(s) < strlen(cmd))
+ return -1;
+ if(strcmp(s + strlen(s) - strlen(cmd), cmd) != 0) {
+ printf("No match\n");
+ continue;
+ }
+
+ if(s[0] != '1' || s[1] != '$' || s[2] != 'r')
+ return -1;
+
+ if(sscanf(s + 3, "%d", &num) != 1)
+ return -1;
+
+ return num;
+ } while(1);
+}
+
+int wasicanon;
+
+void restoreicanon(void)
+{
+ seticanon(wasicanon, TRUE);
+}
+
+int main(int argc, char *argv[])
+{
+ int argi = 1;
+
+ if(argc == 1)
+ usage(0);
+
+ wasicanon = seticanon(FALSE, FALSE);
+ atexit(restoreicanon);
+
+ while(argi < argc) {
+ const char *arg = argv[argi++];
+
+ if(streq(arg, "reset")) {
+ printf("\x1b" "c");
+ }
+ else if(streq(arg, "s8c1t")) {
+ const char *choices[] = {"off", "on", NULL};
+ switch(getchoice(&argi, argc, argv, choices)) {
+ case 0:
+ printf("\x1b F"); break;
+ case 1:
+ printf("\x1b G"); break;
+ }
+ }
+ else if(streq(arg, "keypad")) {
+ const char *choices[] = {"app", "num", NULL};
+ switch(getchoice(&argi, argc, argv, choices)) {
+ case 0:
+ printf("\x1b="); break;
+ case 1:
+ printf("\x1b>"); break;
+ }
+ }
+ else if(streq(arg, "screen")) {
+ do_dec_mode(5, getboolq(&argi, argc, argv), "screen");
+ }
+ else if(streq(arg, "cursor")) {
+ do_dec_mode(25, getboolq(&argi, argc, argv), "cursor");
+ }
+ else if(streq(arg, "curblink")) {
+ do_dec_mode(12, getboolq(&argi, argc, argv), "curblink");
+ }
+ else if(streq(arg, "curshape")) {
+ // TODO: This ought to query the current value of DECSCUSR because it
+ // may need blinking on or off
+ const char *choices[] = {"block", "under", "bar", "query", NULL};
+ int shape = getchoice(&argi, argc, argv, choices);
+ switch(shape) {
+ case 3: // query
+ shape = query_rqss_numeric(" q");
+ switch(shape) {
+ case 1: case 2:
+ printf("curshape block\n");
+ break;
+ case 3: case 4:
+ printf("curshape under\n");
+ break;
+ case 5: case 6:
+ printf("curshape bar\n");
+ break;
+ }
+ break;
+
+ case 0:
+ case 1:
+ case 2:
+ printf("\x1b[%d q", 1 + (shape * 2));
+ break;
+ }
+ }
+ else if(streq(arg, "mouse")) {
+ const char *choices[] = {"off", "click", "clickdrag", "motion", NULL};
+ switch(getchoice(&argi, argc, argv, choices)) {
+ case 0:
+ printf("\x1b[?1000l"); break;
+ case 1:
+ printf("\x1b[?1000h"); break;
+ case 2:
+ printf("\x1b[?1002h"); break;
+ case 3:
+ printf("\x1b[?1003h"); break;
+ }
+ }
+ else if(streq(arg, "reportfocus")) {
+ do_dec_mode(1004, getboolq(&argi, argc, argv), "reportfocus");
+ }
+ else if(streq(arg, "altscreen")) {
+ do_dec_mode(1049, getboolq(&argi, argc, argv), "altscreen");
+ }
+ else if(streq(arg, "bracketpaste")) {
+ do_dec_mode(2004, getboolq(&argi, argc, argv), "bracketpaste");
+ }
+ else if(streq(arg, "icontitle")) {
+ printf("\x1b]0;%s\a", getvalue(&argi, argc, argv));
+ }
+ else if(streq(arg, "icon")) {
+ printf("\x1b]1;%s\a", getvalue(&argi, argc, argv));
+ }
+ else if(streq(arg, "title")) {
+ printf("\x1b]2;%s\a", getvalue(&argi, argc, argv));
+ }
+ else {
+ fprintf(stderr, "Unrecognised command %s\n", arg);
+ exit(1);
+ }
+ }
+ return 0;
+}
diff --git a/src/libvterm/bin/vterm-dump.c b/src/libvterm/bin/vterm-dump.c
new file mode 100644
index 0000000..a299d9c
--- /dev/null
+++ b/src/libvterm/bin/vterm-dump.c
@@ -0,0 +1,232 @@
+// Require getopt(3)
+#define _XOPEN_SOURCE
+
+#include <stdio.h>
+#include <string.h>
+#define streq(a,b) (strcmp(a,b)==0)
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "vterm.h"
+
+static const char *special_begin = "{";
+static const char *special_end = "}";
+
+static int parser_text(const char bytes[], size_t len, void *user)
+{
+ unsigned char *b = (unsigned char *)bytes;
+
+ int i;
+ for(i = 0; i < len; /* none */) {
+ if(b[i] < 0x20) // C0
+ break;
+ else if(b[i] < 0x80) // ASCII
+ i++;
+ else if(b[i] < 0xa0) // C1
+ break;
+ else if(b[i] < 0xc0) // UTF-8 continuation
+ break;
+ else if(b[i] < 0xe0) { // UTF-8 2-byte
+ // 2-byte UTF-8
+ if(len < i+2) break;
+ i += 2;
+ }
+ else if(b[i] < 0xf0) { // UTF-8 3-byte
+ if(len < i+3) break;
+ i += 3;
+ }
+ else if(b[i] < 0xf8) { // UTF-8 4-byte
+ if(len < i+4) break;
+ i += 4;
+ }
+ else // otherwise invalid
+ break;
+ }
+
+ printf("%.*s", i, b);
+ return i;
+}
+
+/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
+static const char *name_c0[] = {
+ "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL", "BS", "HT", "LF", "VT", "FF", "CR", "LS0", "LS1",
+ "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB", "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US",
+};
+static const char *name_c1[] = {
+ NULL, NULL, "BPH", "NBH", NULL, "NEL", "SSA", "ESA", "HTS", "HTJ", "VTS", "PLD", "PLU", "RI", "SS2", "SS3",
+ "DCS", "PU1", "PU2", "STS", "CCH", "MW", "SPA", "EPA", "SOS", NULL, "SCI", "CSI", "ST", "OSC", "PM", "APC",
+};
+
+static int parser_control(unsigned char control, void *user)
+{
+ if(control < 0x20)
+ printf("%s%s%s", special_begin, name_c0[control], special_end);
+ else if(control >= 0x80 && control < 0xa0 && name_c1[control - 0x80])
+ printf("%s%s%s", special_begin, name_c1[control - 0x80], special_end);
+ else
+ printf("%sCONTROL 0x%02x%s", special_begin, control, special_end);
+
+ if(control == 0x0a)
+ printf("\n");
+ return 1;
+}
+
+static int parser_escape(const char bytes[], size_t len, void *user)
+{
+ if(bytes[0] >= 0x20 && bytes[0] < 0x30) {
+ if(len < 2)
+ return -1;
+ len = 2;
+ }
+ else {
+ len = 1;
+ }
+
+ printf("%sESC %.*s%s", special_begin, (int)len, bytes, special_end);
+
+ return len;
+}
+
+/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
+static const char *name_csi_plain[] = {
+ "ICH", "CUU", "CUD", "CUF", "CUB", "CNL", "CPL", "CHA", "CUP", "CHT", "ED", "EL", "IL", "DL", "EF", "EA",
+ "DCH", "SSE", "CPR", "SU", "SD", "NP", "PP", "CTC", "ECH", "CVT", "CBT", "SRS", "PTX", "SDS", "SIMD",NULL,
+ "HPA", "HPR", "REP", "DA", "VPA", "VPR", "HVP", "TBC", "SM", "MC", "HPB", "VPB", "RM", "SGR", "DSR", "DAQ",
+};
+
+/*0 4 8 B */
+static const int newline_csi_plain[] = {
+ 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0,
+};
+
+static int parser_csi(const char *leader, const long args[], int argcount, const char *intermed, char command, void *user)
+{
+ const char *name = NULL;
+ if(!leader && !intermed && command < 0x70)
+ name = name_csi_plain[command - 0x40];
+ else if(leader && streq(leader, "?") && !intermed) {
+ /* DEC */
+ switch(command) {
+ case 'h': name = "DECSM"; break;
+ case 'l': name = "DECRM"; break;
+ }
+ if(name)
+ leader = NULL;
+ }
+
+ if(!leader && !intermed && command < 0x70 && newline_csi_plain[command - 0x40])
+ printf("\n");
+
+ if(name)
+ printf("%s%s", special_begin, name);
+ else
+ printf("%sCSI", special_begin);
+
+ if(leader && leader[0])
+ printf(" %s", leader);
+
+ {
+ int i;
+ for(i = 0; i < argcount; i++) {
+ printf(i ? "," : " ");
+ }
+
+ if(args[i] == CSI_ARG_MISSING)
+ printf("*");
+ else {
+ while(CSI_ARG_HAS_MORE(args[i]))
+ printf("%ld+", CSI_ARG(args[i++]));
+ printf("%ld", CSI_ARG(args[i]));
+ }
+ }
+
+ if(intermed && intermed[0])
+ printf(" %s", intermed);
+
+ if(name)
+ printf("%s", special_end);
+ else
+ printf(" %c%s", command, special_end);
+
+ return 1;
+}
+
+static int parser_osc(const char *command, size_t cmdlen, void *user)
+{
+ printf("%sOSC %.*s%s", special_begin, (int)cmdlen, command, special_end);
+
+ return 1;
+}
+
+static int parser_dcs(const char *command, size_t cmdlen, void *user)
+{
+ printf("%sDCS %.*s%s", special_begin, (int)cmdlen, command, special_end);
+
+ return 1;
+}
+
+static VTermParserCallbacks parser_cbs = {
+ &parser_text, /* text */
+ &parser_control, /* control */
+ &parser_escape, /* escape */
+ &parser_csi, /* csi */
+ &parser_osc, /* osc */
+ &parser_dcs, /* dcs */
+ NULL /* resize */
+};
+
+int main(int argc, char *argv[])
+{
+ int use_colour = isatty(1);
+ const char *file;
+ int fd;
+ VTerm *vt;
+ int len;
+ char buffer[1024];
+
+ int opt;
+ while((opt = getopt(argc, argv, "c")) != -1) {
+ switch(opt) {
+ case 'c': use_colour = 1; break;
+ }
+ }
+
+ file = argv[optind++];
+
+ if(!file || streq(file, "-"))
+ fd = 0; // stdin
+ else {
+ fd = open(file, O_RDONLY);
+ if(fd == -1) {
+ fprintf(stderr, "Cannot open %s - %s\n", file, strerror(errno));
+ exit(1);
+ }
+ }
+
+ if(use_colour) {
+ special_begin = "\x1b[7m{";
+ special_end = "}\x1b[m";
+ }
+
+ /* Size matters not for the parser */
+ vt = vterm_new(25, 80);
+ vterm_set_utf8(vt, 1);
+ vterm_parser_set_callbacks(vt, &parser_cbs, NULL);
+
+ while((len = read(fd, buffer, sizeof(buffer))) > 0) {
+ vterm_input_write(vt, buffer, len);
+ }
+
+ printf("\n");
+
+ close(fd);
+ vterm_free(vt);
+
+ return 0;
+}
diff --git a/src/libvterm/doc/URLs b/src/libvterm/doc/URLs
new file mode 100644
index 0000000..8380f5c
--- /dev/null
+++ b/src/libvterm/doc/URLs
@@ -0,0 +1,14 @@
+ECMA-48:
+ http://www.ecma-international.org/publications/standards/Ecma-048.htm
+
+Xterm Control Sequences:
+ http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
+
+Digital VT100 User Guide:
+ http://vt100.net/docs/vt100-ug/
+
+Digital VT220 Programmer Reference Manual
+ http://vt100.net/docs/vt220-rm/
+
+Summary of ANSI standards for ASCII terminals
+ http://www.inwap.com/pdp10/ansicode.txt
diff --git a/src/libvterm/doc/seqs.txt b/src/libvterm/doc/seqs.txt
new file mode 100644
index 0000000..c26dc44
--- /dev/null
+++ b/src/libvterm/doc/seqs.txt
@@ -0,0 +1,227 @@
+Sequences documented in parens are implicit ones from parser.c, which move
+between states.
+
+1 = VT100
+2 = VT220
+3 = VT320
+
+ C0 controls
+
+123 0x00 = NUL
+123 0x07 = BEL
+123 0x08 = BS
+123 0x09 = HT
+123 0x0A = LF
+123 0x0B = VT
+123 0x0C = FF
+123 0x0D = CR
+123 0x0E = LS1
+123 0x0F = LS0
+ (0x18 = CAN)
+ (0x1A = SUB)
+ (0x1B = ESC)
+
+123 0x7f = DEL (ignored)
+
+ C1 controls
+
+123 0x84 = IND
+123 0x85 = NEL
+123 0x88 = HTS
+123 0x8D = RI
+ 23 0x8e = SS2
+ 23 0x8f = SS3
+ (0x90 = DCS)
+ (0x9B = CSI)
+ (0x9C = ST)
+ (0x9D = OSC)
+
+ Escape sequences
+ - excluding sequences that are C1 aliases
+
+123 ESC () = SCS, select character set (G0, G1)
+ 23 ESC *+ = SCS, select character set (G2, G3)
+123 ESC 7 = DECSC - save cursor
+123 ESC 8 = DECRC - restore cursor
+123 ESC # 3 = DECDHL, double-height line (top half)
+123 ESC # 4 = DECDHL, double-height line (bottom half)
+123 ESC # 5 = DECSWL, single-width single-height line
+123 ESC # 6 = DECDWL, double-width single-height line
+123 ESC # 8 = DECALN
+123 ESC < = Ignored (used by VT100 to exit VT52 mode)
+123 ESC = = DECKPAM, keypad application mode
+123 ESC > = DECKPNM, keypad numeric mode
+ 23 ESC Sp F = S7C1T
+ 23 ESC Sp G = S8C1T
+ (ESC P = DCS)
+ (ESC [ = CSI)
+ (ESC \ = ST)
+ (ESC ] = OSC)
+123 ESC c = RIS, reset initial state
+ 3 ESC n = LS2
+ 3 ESC o = LS3
+ 3 ESC ~ = LS1R
+ 3 ESC } = LS2R
+ 3 ESC | = LS3R
+
+ DCSes
+
+ 3 DCS $ q ST = DECRQSS
+ 3 m = Request SGR
+ Sp q = Request DECSCUSR
+ 3 " q = Request DECSCA
+ 3 r = Request DECSTBM
+ s = Request DECSLRM
+
+ CSIs
+ 23 CSI @ = ICH
+123 CSI A = CUU
+123 CSI B = CUD
+123 CSI C = CUF
+123 CSI D = CUB
+ CSI E = CNL
+ CSI F = CPL
+ CSI G = CHA
+123 CSI H = CUP
+ CSI I = CHT
+123 CSI J = ED
+ 23 CSI ? J = DECSED, selective erase in display
+123 CSI K = EL
+ 23 CSI ? K = DECSEL, selective erase in line
+ 23 CSI L = IL
+ 23 CSI M = DL
+ 23 CSI P = DCH
+ CSI S = SU
+ CSI T = SD
+ 23 CSI X = ECH
+ CSI Z = CBT
+ CSI ` = HPA
+ CSI a = HPR
+123 CSI c = DA, device attributes
+123 0 = DA
+ 23 CSI > c = DECSDA
+ 23 0 = SDA
+ CSI d = VPA
+ CSI e = VPR
+123 CSI f = HVP
+123 CSI g = TBC
+123 CSI h = SM, Set mode
+123 CSI ? h = DECSM, DEC set mode
+ CSI j = HPB
+ CSI k = VPB
+123 CSI l = RM, Reset mode
+123 CSI ? l = DECRM, DEC reset mode
+123 CSI m = SGR, Set Graphic Rendition
+123 CSI n = DSR, Device Status Report
+ 23 5 = operating status
+ 23 6 = CPR = cursor position
+ 23 CSI ? n = DECDSR; behaves as DSR but uses CSI ? instead of CSI to respond
+ 23 CSI ! p = DECSTR, soft terminal reset
+ 3 CSI ? $ p = DECRQM, request mode
+ CSI Sp q = DECSCUSR (odd numbers blink, even numbers solid)
+ 1 or 2 = block
+ 3 or 4 = underline
+ 5 or 6 = I-beam to left
+ 23 CSI " q = DECSCA, select character attributes
+123 CSI r = DECSTBM
+ CSI s = DECSLRM
+ CSI ' } = DECIC
+ CSI ' ~ = DECDC
+
+ OSCs
+
+ OSC 0; = Set icon name and title
+ OSC 1; = Set icon name
+ OSC 2; = Set title
+
+ Standard modes
+
+ 23 SM 4 = IRM
+123 SM 20 = NLM, linefeed/newline
+
+ DEC modes
+
+123 DECSM 1 = DECCKM, cursor keys
+123 DECSM 5 = DECSCNM, screen
+123 DECSM 6 = DECOM, origin
+123 DECSM 7 = DECAWM, autowrap
+ DECSM 12 = Cursor blink
+ 23 DECSM 25 = DECTCEM, text cursor enable
+ DECSM 69 = DECVSSM, vertical screen split
+ DECSM 1000 = Mouse click/release tracking
+ DECSM 1002 = Mouse click/release/drag tracking
+ DECSM 1003 = Mouse all movements tracking
+ DECSM 1004 = Focus in/out reporting
+ DECSM 1005 = Mouse protocol extended (UTF-8) - not recommended
+ DECSM 1006 = Mouse protocol SGR
+ DECSM 1015 = Mouse protocol rxvt
+ DECSM 1047 = Altscreen
+ DECSM 1048 = Save cursor
+ DECSM 1049 = 1047 + 1048
+ DECSM 2004 = Bracketed paste
+
+ Graphic Renditions
+
+123 SGR 0 = Reset
+123 SGR 1 = Bold on
+ SGR 3 = Italic on
+123 SGR 4 = Underline single
+123 SGR 5 = Blink on
+123 SGR 7 = Reverse on
+ SGR 9 = Strikethrough on
+ SGR 10-19 = Select font
+ SGR 21 = Underline double
+ 23 SGR 22 = Bold off
+ SGR 23 = Italic off
+ 23 SGR 24 = Underline off
+ 23 SGR 25 = Blink off
+ 23 SGR 27 = Reverse off
+ SGR 29 = Strikethrough off
+ SGR 30-37 = Foreground ANSI
+ SGR 38 = Foreground alternative palette
+ SGR 39 = Foreground default
+ SGR 40-47 = Background ANSI
+ SGR 48 = Background alternative palette
+ SGR 49 = Background default
+ SGR 90-97 = Foreground ANSI high-intensity
+ SGR 100-107 = Background ANSI high-intensity
+
+The state storage used by ESC 7 and DECSM 1048/1049 is shared.
+
+ Unimplemented sequences:
+
+The following sequences are not recognised by libvterm.
+
+123 0x05 = ENQ
+ 3 0x11 = DC1 (XON)
+ 3 0x13 = DC3 (XOFF)
+12 ESC Z = DECID, identify terminal
+ DCS $ q = [DECRQSS]
+ 3 " p = Request DECSCL
+ 3 $ } = Request DECSASD
+ 3 $ ~ = Request DECSSDT
+ 23 DCS { = DECDLD, down-line-loadable character set
+ 23 DCS | = DECUDK, user-defined key
+ 23 CSI i = DEC printer control
+ 23 CSI " p = DECSCL, set compatibility level
+1 CSI q = DECLL, load LEDs
+ 3 CSI $ u = DECRQTSR, request terminal state report
+ 3 1 = terminal state report
+ 3 CSI & u = DECRQUPSS, request user-preferred supplemental set
+ 3 CSI $ w = DECRQPSR, request presentation state report
+ 3 1 = cursor information report
+ 3 2 = tab stop report
+1 CSI x = DECREQTPARM, request terminal parameters
+123 CSI y = DECTST, invoke confidence test
+ 3 CSI $ } = DECSASD, select active status display
+ 3 CSI $ ~ = DECSSDT, select status line type
+ 23 SM 2 = KAM, keyboard action
+123 SM 12 = SRM, send/receive
+123 DECSM 2 = DECANM, ANSI/VT52
+123 DECSM 3 = DECCOLM, 132 column
+123 DECSM 4 = DECSCLM, scrolling
+123 DECSM 8 = DECARM, auto-repeat
+12 DECSM 9 = DECINLM, interlace
+ 23 DECSM 18 = DECPFF, print form feed
+ 23 DECSM 19 = DECPEX, print extent
+ 23 DECSM 42 = DECNRCM, national/multinational character
diff --git a/src/libvterm/include/vterm.h b/src/libvterm/include/vterm.h
new file mode 100644
index 0000000..3b77cd2
--- /dev/null
+++ b/src/libvterm/include/vterm.h
@@ -0,0 +1,435 @@
+/*
+ * NOTE: This is a MODIFIED version of libvterm, see the README file.
+ */
+#ifndef __VTERM_H__
+#define __VTERM_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdlib.h>
+
+#include "vterm_keycodes.h"
+
+#define TRUE 1
+#define FALSE 0
+
+/* from stdint.h */
+typedef unsigned char uint8_t;
+typedef unsigned int uint32_t;
+
+typedef struct VTerm VTerm;
+typedef struct VTermState VTermState;
+typedef struct VTermScreen VTermScreen;
+
+/* Specifies a screen point. */
+typedef struct {
+ int row;
+ int col;
+} VTermPos;
+
+/*
+ * Some small utility functions; we can just keep these static here.
+ */
+
+/*
+ * Order points by on-screen flow order:
+ * Return < 0 if "a" is before "b"
+ * Return 0 if "a" and "b" are equal
+ * Return > 0 if "a" is after "b".
+ */
+int vterm_pos_cmp(VTermPos a, VTermPos b);
+
+#if defined(DEFINE_INLINES) || USE_INLINE
+INLINE int vterm_pos_cmp(VTermPos a, VTermPos b)
+{
+ return (a.row == b.row) ? a.col - b.col : a.row - b.row;
+}
+#endif
+
+/* Specifies a rectangular screen area. */
+typedef struct {
+ int start_row;
+ int end_row;
+ int start_col;
+ int end_col;
+} VTermRect;
+
+/* Return true if the rect "r" contains the point "p". */
+int vterm_rect_contains(VTermRect r, VTermPos p);
+
+#if defined(DEFINE_INLINES) || USE_INLINE
+INLINE int vterm_rect_contains(VTermRect r, VTermPos p)
+{
+ return p.row >= r.start_row && p.row < r.end_row &&
+ p.col >= r.start_col && p.col < r.end_col;
+}
+#endif
+
+/* Move "rect" "row_delta" down and "col_delta" right.
+ * Does not check boundaries. */
+void vterm_rect_move(VTermRect *rect, int row_delta, int col_delta);
+
+#if defined(DEFINE_INLINES) || USE_INLINE
+INLINE void vterm_rect_move(VTermRect *rect, int row_delta, int col_delta)
+{
+ rect->start_row += row_delta; rect->end_row += row_delta;
+ rect->start_col += col_delta; rect->end_col += col_delta;
+}
+#endif
+
+/* The ansi_index is used for the lower 16 colors, which can be set to any
+ * color. */
+#define VTERM_ANSI_INDEX_DEFAULT 0 /* color cleared */
+#define VTERM_ANSI_INDEX_MIN 1
+#define VTERM_ANSI_INDEX_MAX 16
+#define VTERM_ANSI_INDEX_NONE 255 /* non-ANSI color, use red/green/blue */
+
+typedef struct {
+ uint8_t red, green, blue;
+ uint8_t ansi_index;
+} VTermColor;
+
+typedef enum {
+ /* VTERM_VALUETYPE_NONE = 0 */
+ VTERM_VALUETYPE_BOOL = 1,
+ VTERM_VALUETYPE_INT,
+ VTERM_VALUETYPE_STRING,
+ VTERM_VALUETYPE_COLOR,
+
+ VTERM_N_VALUETYPES
+} VTermValueType;
+
+typedef union {
+ int boolean;
+ int number;
+ char *string;
+ VTermColor color;
+} VTermValue;
+
+typedef enum {
+ /* VTERM_ATTR_NONE = 0 */
+ VTERM_ATTR_BOLD = 1, // bool: 1, 22
+ VTERM_ATTR_UNDERLINE, // number: 4, 21, 24
+ VTERM_ATTR_ITALIC, // bool: 3, 23
+ VTERM_ATTR_BLINK, // bool: 5, 25
+ VTERM_ATTR_REVERSE, // bool: 7, 27
+ VTERM_ATTR_STRIKE, // bool: 9, 29
+ VTERM_ATTR_FONT, // number: 10-19
+ VTERM_ATTR_FOREGROUND, // color: 30-39 90-97
+ VTERM_ATTR_BACKGROUND, // color: 40-49 100-107
+
+ VTERM_N_ATTRS
+} VTermAttr;
+
+typedef enum {
+ /* VTERM_PROP_NONE = 0 */
+ VTERM_PROP_CURSORVISIBLE = 1, // bool
+ VTERM_PROP_CURSORBLINK, // bool
+ VTERM_PROP_ALTSCREEN, // bool
+ VTERM_PROP_TITLE, // string
+ VTERM_PROP_ICONNAME, // string
+ VTERM_PROP_REVERSE, // bool
+ VTERM_PROP_CURSORSHAPE, // number
+ VTERM_PROP_MOUSE, // number
+ VTERM_PROP_CURSORCOLOR, // string
+
+ VTERM_N_PROPS
+} VTermProp;
+
+enum {
+ VTERM_PROP_CURSORSHAPE_BLOCK = 1,
+ VTERM_PROP_CURSORSHAPE_UNDERLINE,
+ VTERM_PROP_CURSORSHAPE_BAR_LEFT,
+
+ VTERM_N_PROP_CURSORSHAPES
+};
+
+enum {
+ VTERM_PROP_MOUSE_NONE = 0,
+ VTERM_PROP_MOUSE_CLICK,
+ VTERM_PROP_MOUSE_DRAG,
+ VTERM_PROP_MOUSE_MOVE,
+
+ VTERM_N_PROP_MOUSES
+};
+
+typedef struct {
+ const uint32_t *chars;
+ int width;
+ unsigned int protected_cell:1; /* DECSCA-protected against DECSEL/DECSED */
+ unsigned int dwl:1; /* DECDWL or DECDHL double-width line */
+ unsigned int dhl:2; /* DECDHL double-height line (1=top 2=bottom) */
+} VTermGlyphInfo;
+
+typedef struct {
+ unsigned int doublewidth:1; /* DECDWL or DECDHL line */
+ unsigned int doubleheight:2; /* DECDHL line (1=top 2=bottom) */
+} VTermLineInfo;
+
+typedef struct {
+ /* libvterm relies on the allocated memory to be zeroed out before it is
+ * returned by the allocator. */
+ void *(*malloc)(size_t size, void *allocdata);
+ void (*free)(void *ptr, void *allocdata);
+} VTermAllocatorFunctions;
+
+/* Allocate and initialize a new terminal with default allocators. */
+VTerm *vterm_new(int rows, int cols);
+
+/* Allocate and initialize a new terminal with specified allocators. */
+VTerm *vterm_new_with_allocator(int rows, int cols, VTermAllocatorFunctions *funcs, void *allocdata);
+
+/* Free and cleanup a terminal and all its data. */
+void vterm_free(VTerm* vt);
+
+/* Get the current size of the terminal and store in "rowsp" and "colsp". */
+void vterm_get_size(const VTerm *vt, int *rowsp, int *colsp);
+
+void vterm_set_size(VTerm *vt, int rows, int cols);
+
+int vterm_get_utf8(const VTerm *vt);
+void vterm_set_utf8(VTerm *vt, int is_utf8);
+
+size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len);
+
+size_t vterm_output_get_buffer_size(const VTerm *vt);
+size_t vterm_output_get_buffer_current(const VTerm *vt);
+size_t vterm_output_get_buffer_remaining(const VTerm *vt);
+
+size_t vterm_output_read(VTerm *vt, char *buffer, size_t len);
+
+void vterm_keyboard_unichar(VTerm *vt, uint32_t c, VTermModifier mod);
+void vterm_keyboard_key(VTerm *vt, VTermKey key, VTermModifier mod);
+
+void vterm_keyboard_start_paste(VTerm *vt);
+void vterm_keyboard_end_paste(VTerm *vt);
+
+void vterm_mouse_move(VTerm *vt, int row, int col, VTermModifier mod);
+/* "button" is 1 for left, 2 for middle, 3 for right.
+ * Button 4 is scroll wheel down, button 5 is scroll wheel up. */
+void vterm_mouse_button(VTerm *vt, int button, int pressed, VTermModifier mod);
+
+// ------------
+// Parser layer
+// ------------
+
+/* Flag to indicate non-final subparameters in a single CSI parameter.
+ * Consider
+ * CSI 1;2:3:4;5a
+ * 1 4 and 5 are final.
+ * 2 and 3 are non-final and will have this bit set
+ *
+ * Don't confuse this with the final byte of the CSI escape; 'a' in this case.
+ */
+#define CSI_ARG_FLAG_MORE (1U<<31)
+#define CSI_ARG_MASK (~(1U<<31))
+
+#define CSI_ARG_HAS_MORE(a) ((a) & CSI_ARG_FLAG_MORE)
+#define CSI_ARG(a) ((a) & CSI_ARG_MASK)
+
+/* Can't use -1 to indicate a missing argument; use this instead */
+#define CSI_ARG_MISSING ((1<<30)-1)
+
+#define CSI_ARG_IS_MISSING(a) (CSI_ARG(a) == CSI_ARG_MISSING)
+#define CSI_ARG_OR(a,def) (CSI_ARG(a) == CSI_ARG_MISSING ? (def) : CSI_ARG(a))
+#define CSI_ARG_COUNT(a) (CSI_ARG(a) == CSI_ARG_MISSING || CSI_ARG(a) == 0 ? 1 : CSI_ARG(a))
+
+typedef struct {
+ int (*text)(const char *bytes, size_t len, void *user);
+ int (*control)(unsigned char control, void *user);
+ int (*escape)(const char *bytes, size_t len, void *user);
+ int (*csi)(const char *leader, const long args[], int argcount, const char *intermed, char command, void *user);
+ int (*osc)(const char *command, size_t cmdlen, void *user);
+ int (*dcs)(const char *command, size_t cmdlen, void *user);
+ int (*resize)(int rows, int cols, void *user);
+} VTermParserCallbacks;
+
+void vterm_parser_set_callbacks(VTerm *vt, const VTermParserCallbacks *callbacks, void *user);
+void *vterm_parser_get_cbdata(VTerm *vt);
+
+// -----------
+// State layer
+// -----------
+
+typedef struct {
+ int (*putglyph)(VTermGlyphInfo *info, VTermPos pos, void *user);
+ int (*movecursor)(VTermPos pos, VTermPos oldpos, int visible, void *user);
+ int (*scrollrect)(VTermRect rect, int downward, int rightward, void *user);
+ int (*moverect)(VTermRect dest, VTermRect src, void *user);
+ int (*erase)(VTermRect rect, int selective, void *user);
+ int (*initpen)(void *user);
+ int (*setpenattr)(VTermAttr attr, VTermValue *val, void *user);
+ /* Callback for setting various properties. Must return 1 if the property
+ * was accepted, 0 otherwise. */
+ int (*settermprop)(VTermProp prop, VTermValue *val, void *user);
+ int (*bell)(void *user);
+ int (*resize)(int rows, int cols, VTermPos *delta, void *user);
+ int (*setlineinfo)(int row, const VTermLineInfo *newinfo, const VTermLineInfo *oldinfo, void *user);
+} VTermStateCallbacks;
+
+typedef struct {
+ VTermPos pos;
+ int buttons;
+#define MOUSE_BUTTON_LEFT 0x01
+#define MOUSE_BUTTON_MIDDLE 0x02
+#define MOUSE_BUTTON_RIGHT 0x04
+ int flags;
+#define MOUSE_WANT_CLICK 0x01
+#define MOUSE_WANT_DRAG 0x02
+#define MOUSE_WANT_MOVE 0x04
+ /* useful to add protocol? */
+} VTermMouseState;
+
+VTermState *vterm_obtain_state(VTerm *vt);
+
+void vterm_state_set_callbacks(VTermState *state, const VTermStateCallbacks *callbacks, void *user);
+void *vterm_state_get_cbdata(VTermState *state);
+
+// Only invokes control, csi, osc, dcs
+void vterm_state_set_unrecognised_fallbacks(VTermState *state, const VTermParserCallbacks *fallbacks, void *user);
+void *vterm_state_get_unrecognised_fbdata(VTermState *state);
+
+/* Initialize the state. */
+void vterm_state_reset(VTermState *state, int hard);
+
+void vterm_state_get_cursorpos(const VTermState *state, VTermPos *cursorpos);
+void vterm_state_get_mousestate(const VTermState *state, VTermMouseState *mousestate);
+void vterm_state_get_default_colors(const VTermState *state, VTermColor *default_fg, VTermColor *default_bg);
+void vterm_state_get_palette_color(const VTermState *state, int index, VTermColor *col);
+void vterm_state_set_default_colors(VTermState *state, const VTermColor *default_fg, const VTermColor *default_bg);
+void vterm_state_set_palette_color(VTermState *state, int index, const VTermColor *col);
+void vterm_state_set_bold_highbright(VTermState *state, int bold_is_highbright);
+int vterm_state_get_penattr(const VTermState *state, VTermAttr attr, VTermValue *val);
+int vterm_state_set_termprop(VTermState *state, VTermProp prop, VTermValue *val);
+void vterm_state_focus_in(VTermState *state);
+void vterm_state_focus_out(VTermState *state);
+const VTermLineInfo *vterm_state_get_lineinfo(const VTermState *state, int row);
+
+// ------------
+// Screen layer
+// ------------
+
+typedef struct {
+ unsigned int bold : 1;
+ unsigned int underline : 2;
+ unsigned int italic : 1;
+ unsigned int blink : 1;
+ unsigned int reverse : 1;
+ unsigned int strike : 1;
+ unsigned int font : 4; /* 0 to 9 */
+ unsigned int dwl : 1; /* On a DECDWL or DECDHL line */
+ unsigned int dhl : 2; /* On a DECDHL line (1=top 2=bottom) */
+} VTermScreenCellAttrs;
+
+typedef struct {
+#define VTERM_MAX_CHARS_PER_CELL 6
+ uint32_t chars[VTERM_MAX_CHARS_PER_CELL];
+ char width;
+ VTermScreenCellAttrs attrs;
+ VTermColor fg, bg;
+} VTermScreenCell;
+
+/* All fields are optional, NULL when not used. */
+typedef struct {
+ int (*damage)(VTermRect rect, void *user);
+ int (*moverect)(VTermRect dest, VTermRect src, void *user);
+ int (*movecursor)(VTermPos pos, VTermPos oldpos, int visible, void *user);
+ int (*settermprop)(VTermProp prop, VTermValue *val, void *user);
+ int (*bell)(void *user);
+ int (*resize)(int rows, int cols, void *user);
+ /* A line was pushed off the top of the window.
+ * "cells[cols]" contains the cells of that line.
+ * Return value is unused. */
+ int (*sb_pushline)(int cols, const VTermScreenCell *cells, void *user);
+ int (*sb_popline)(int cols, VTermScreenCell *cells, void *user);
+} VTermScreenCallbacks;
+
+/* Return the screen of the vterm. */
+VTermScreen *vterm_obtain_screen(VTerm *vt);
+
+/*
+ * Install screen callbacks. These are invoked when the screen contents is
+ * changed. "user" is passed into to the callback.
+ */
+void vterm_screen_set_callbacks(VTermScreen *screen, const VTermScreenCallbacks *callbacks, void *user);
+void *vterm_screen_get_cbdata(VTermScreen *screen);
+
+// Only invokes control, csi, osc, dcs
+void vterm_screen_set_unrecognised_fallbacks(VTermScreen *screen, const VTermParserCallbacks *fallbacks, void *user);
+void *vterm_screen_get_unrecognised_fbdata(VTermScreen *screen);
+
+/* Enable support for using the alternate screen if "altscreen" is non-zero.
+ * Before that switching to the alternate screen won't work.
+ * Calling with "altscreen" zero has no effect. */
+void vterm_screen_enable_altscreen(VTermScreen *screen, int altscreen);
+
+typedef enum {
+ VTERM_DAMAGE_CELL, /* every cell */
+ VTERM_DAMAGE_ROW, /* entire rows */
+ VTERM_DAMAGE_SCREEN, /* entire screen */
+ VTERM_DAMAGE_SCROLL, /* entire screen + scrollrect */
+
+ VTERM_N_DAMAGES
+} VTermDamageSize;
+
+/* Invoke the relevant callbacks to update the screen. */
+void vterm_screen_flush_damage(VTermScreen *screen);
+
+void vterm_screen_set_damage_merge(VTermScreen *screen, VTermDamageSize size);
+
+/*
+ * Reset the screen. Also invokes vterm_state_reset().
+ * Must be called before the terminal can be used.
+ */
+void vterm_screen_reset(VTermScreen *screen, int hard);
+
+/* Neither of these functions NUL-terminate the buffer */
+size_t vterm_screen_get_chars(const VTermScreen *screen, uint32_t *chars, size_t len, const VTermRect rect);
+size_t vterm_screen_get_text(const VTermScreen *screen, char *str, size_t len, const VTermRect rect);
+
+typedef enum {
+ VTERM_ATTR_BOLD_MASK = 1 << 0,
+ VTERM_ATTR_UNDERLINE_MASK = 1 << 1,
+ VTERM_ATTR_ITALIC_MASK = 1 << 2,
+ VTERM_ATTR_BLINK_MASK = 1 << 3,
+ VTERM_ATTR_REVERSE_MASK = 1 << 4,
+ VTERM_ATTR_STRIKE_MASK = 1 << 5,
+ VTERM_ATTR_FONT_MASK = 1 << 6,
+ VTERM_ATTR_FOREGROUND_MASK = 1 << 7,
+ VTERM_ATTR_BACKGROUND_MASK = 1 << 8,
+
+ VTERM_ALL_ATTRS_MASK = (1 << 9) - 1
+} VTermAttrMask;
+
+int vterm_screen_get_attrs_extent(const VTermScreen *screen, VTermRect *extent, VTermPos pos, VTermAttrMask attrs);
+
+int vterm_screen_get_cell(const VTermScreen *screen, VTermPos pos, VTermScreenCell *cell);
+
+int vterm_screen_is_eol(const VTermScreen *screen, VTermPos pos);
+
+// ---------
+// Utilities
+// ---------
+
+VTermValueType vterm_get_attr_type(VTermAttr attr);
+VTermValueType vterm_get_prop_type(VTermProp prop);
+
+void vterm_scroll_rect(VTermRect rect,
+ int downward,
+ int rightward,
+ int (*moverect)(VTermRect src, VTermRect dest, void *user),
+ int (*eraserect)(VTermRect rect, int selective, void *user),
+ void *user);
+
+void vterm_copy_cells(VTermRect dest,
+ VTermRect src,
+ void (*copycell)(VTermPos dest, VTermPos src, void *user),
+ void *user);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/libvterm/include/vterm_keycodes.h b/src/libvterm/include/vterm_keycodes.h
new file mode 100644
index 0000000..22bdf91
--- /dev/null
+++ b/src/libvterm/include/vterm_keycodes.h
@@ -0,0 +1,64 @@
+#ifndef __VTERM_INPUT_H__
+#define __VTERM_INPUT_H__
+
+typedef enum {
+ VTERM_MOD_NONE = 0x00,
+ VTERM_MOD_SHIFT = 0x01,
+ VTERM_MOD_ALT = 0x02,
+ VTERM_MOD_CTRL = 0x04,
+
+ VTERM_ALL_MODS_MASK = 0x07
+} VTermModifier;
+
+/* The order here must match keycodes[] in src/keyboard.c! */
+typedef enum {
+ VTERM_KEY_NONE,
+
+ VTERM_KEY_ENTER,
+ VTERM_KEY_TAB,
+ VTERM_KEY_BACKSPACE,
+ VTERM_KEY_ESCAPE,
+
+ VTERM_KEY_UP,
+ VTERM_KEY_DOWN,
+ VTERM_KEY_LEFT,
+ VTERM_KEY_RIGHT,
+
+ VTERM_KEY_INS,
+ VTERM_KEY_DEL,
+ VTERM_KEY_HOME,
+ VTERM_KEY_END,
+ VTERM_KEY_PAGEUP,
+ VTERM_KEY_PAGEDOWN,
+
+ /* F1 is VTERM_KEY_FUNCTION(1), F2 VTERM_KEY_FUNCTION(2), etc. */
+ VTERM_KEY_FUNCTION_0 = 256,
+ VTERM_KEY_FUNCTION_MAX = VTERM_KEY_FUNCTION_0 + 255,
+
+ /* keypad keys */
+ VTERM_KEY_KP_0,
+ VTERM_KEY_KP_1,
+ VTERM_KEY_KP_2,
+ VTERM_KEY_KP_3,
+ VTERM_KEY_KP_4,
+ VTERM_KEY_KP_5,
+ VTERM_KEY_KP_6,
+ VTERM_KEY_KP_7,
+ VTERM_KEY_KP_8,
+ VTERM_KEY_KP_9,
+ VTERM_KEY_KP_MULT,
+ VTERM_KEY_KP_PLUS,
+ VTERM_KEY_KP_COMMA,
+ VTERM_KEY_KP_MINUS,
+ VTERM_KEY_KP_PERIOD,
+ VTERM_KEY_KP_DIVIDE,
+ VTERM_KEY_KP_ENTER,
+ VTERM_KEY_KP_EQUAL,
+
+ VTERM_KEY_MAX, // Must be last
+ VTERM_N_KEYS = VTERM_KEY_MAX
+} VTermKey;
+
+#define VTERM_KEY_FUNCTION(n) (VTERM_KEY_FUNCTION_0+(n))
+
+#endif
diff --git a/src/libvterm/src/encoding.c b/src/libvterm/src/encoding.c
new file mode 100644
index 0000000..dbe129c
--- /dev/null
+++ b/src/libvterm/src/encoding.c
@@ -0,0 +1,234 @@
+#include "vterm_internal.h"
+
+#define UNICODE_INVALID 0xFFFD
+
+#if defined(DEBUG) && DEBUG > 1
+# define DEBUG_PRINT_UTF8
+#endif
+
+struct UTF8DecoderData {
+ // number of bytes remaining in this codepoint
+ int bytes_remaining;
+
+ // number of bytes total in this codepoint once it's finished
+ // (for detecting overlongs)
+ int bytes_total;
+
+ int this_cp;
+};
+
+static void init_utf8(VTermEncoding *enc UNUSED, void *data_)
+{
+ struct UTF8DecoderData *data = data_;
+
+ data->bytes_remaining = 0;
+ data->bytes_total = 0;
+}
+
+static void decode_utf8(VTermEncoding *enc UNUSED, void *data_,
+ uint32_t cp[], int *cpi, int cplen,
+ const char bytes[], size_t *pos, size_t bytelen)
+{
+ struct UTF8DecoderData *data = data_;
+
+#ifdef DEBUG_PRINT_UTF8
+ printf("BEGIN UTF-8\n");
+#endif
+
+ for(; *pos < bytelen && *cpi < cplen; (*pos)++) {
+ unsigned char c = bytes[*pos];
+
+#ifdef DEBUG_PRINT_UTF8
+ printf(" pos=%zd c=%02x rem=%d\n", *pos, c, data->bytes_remaining);
+#endif
+
+ if(c < 0x20) // C0
+ return;
+
+ else if(c >= 0x20 && c < 0x7f) {
+ if(data->bytes_remaining) {
+ data->bytes_remaining = 0;
+ cp[(*cpi)++] = UNICODE_INVALID;
+ if (*cpi >= cplen)
+ break;
+ }
+ cp[(*cpi)++] = c;
+#ifdef DEBUG_PRINT_UTF8
+ printf(" UTF-8 char: U+%04x\n", c);
+#endif
+ }
+
+ else if(c == 0x7f) // DEL
+ return;
+
+ else if(c >= 0x80 && c < 0xc0) {
+ if(!data->bytes_remaining) {
+ cp[(*cpi)++] = UNICODE_INVALID;
+ continue;
+ }
+
+ data->this_cp <<= 6;
+ data->this_cp |= c & 0x3f;
+ data->bytes_remaining--;
+
+ if(!data->bytes_remaining) {
+#ifdef DEBUG_PRINT_UTF8
+ printf(" UTF-8 raw char U+%04x bytelen=%d ", data->this_cp, data->bytes_total);
+#endif
+ // Check for overlong sequences
+ switch(data->bytes_total) {
+ case 2:
+ if(data->this_cp < 0x0080) data->this_cp = UNICODE_INVALID;
+ break;
+ case 3:
+ if(data->this_cp < 0x0800) data->this_cp = UNICODE_INVALID;
+ break;
+ case 4:
+ if(data->this_cp < 0x10000) data->this_cp = UNICODE_INVALID;
+ break;
+ case 5:
+ if(data->this_cp < 0x200000) data->this_cp = UNICODE_INVALID;
+ break;
+ case 6:
+ if(data->this_cp < 0x4000000) data->this_cp = UNICODE_INVALID;
+ break;
+ }
+ // Now look for plain invalid ones
+ if((data->this_cp >= 0xD800 && data->this_cp <= 0xDFFF) ||
+ data->this_cp == 0xFFFE ||
+ data->this_cp == 0xFFFF)
+ data->this_cp = UNICODE_INVALID;
+#ifdef DEBUG_PRINT_UTF8
+ printf(" char: U+%04x\n", data->this_cp);
+#endif
+ cp[(*cpi)++] = data->this_cp;
+ }
+ }
+
+ else if(c >= 0xc0 && c < 0xe0) {
+ if(data->bytes_remaining)
+ cp[(*cpi)++] = UNICODE_INVALID;
+
+ data->this_cp = c & 0x1f;
+ data->bytes_total = 2;
+ data->bytes_remaining = 1;
+ }
+
+ else if(c >= 0xe0 && c < 0xf0) {
+ if(data->bytes_remaining)
+ cp[(*cpi)++] = UNICODE_INVALID;
+
+ data->this_cp = c & 0x0f;
+ data->bytes_total = 3;
+ data->bytes_remaining = 2;
+ }
+
+ else if(c >= 0xf0 && c < 0xf8) {
+ if(data->bytes_remaining)
+ cp[(*cpi)++] = UNICODE_INVALID;
+
+ data->this_cp = c & 0x07;
+ data->bytes_total = 4;
+ data->bytes_remaining = 3;
+ }
+
+ else if(c >= 0xf8 && c < 0xfc) {
+ if(data->bytes_remaining)
+ cp[(*cpi)++] = UNICODE_INVALID;
+
+ data->this_cp = c & 0x03;
+ data->bytes_total = 5;
+ data->bytes_remaining = 4;
+ }
+
+ else if(c >= 0xfc && c < 0xfe) {
+ if(data->bytes_remaining)
+ cp[(*cpi)++] = UNICODE_INVALID;
+
+ data->this_cp = c & 0x01;
+ data->bytes_total = 6;
+ data->bytes_remaining = 5;
+ }
+
+ else {
+ cp[(*cpi)++] = UNICODE_INVALID;
+ }
+ }
+}
+
+static VTermEncoding encoding_utf8 = {
+ &init_utf8, /* init */
+ &decode_utf8 /* decode */
+};
+
+static void decode_usascii(VTermEncoding *enc UNUSED, void *data UNUSED,
+ uint32_t cp[], int *cpi, int cplen,
+ const char bytes[], size_t *pos, size_t bytelen)
+{
+ int is_gr = bytes[*pos] & 0x80;
+
+ for(; *pos < bytelen && *cpi < cplen; (*pos)++) {
+ unsigned char c = bytes[*pos] ^ is_gr;
+
+ if(c < 0x20 || c == 0x7f || c >= 0x80)
+ return;
+
+ cp[(*cpi)++] = c;
+ }
+}
+
+static VTermEncoding encoding_usascii = {
+ NULL, /* init */
+ &decode_usascii /* decode */
+};
+
+struct StaticTableEncoding {
+ const VTermEncoding enc;
+ const uint32_t chars[128];
+};
+
+static void decode_table(VTermEncoding *enc, void *data UNUSED,
+ uint32_t cp[], int *cpi, int cplen,
+ const char bytes[], size_t *pos, size_t bytelen)
+{
+ struct StaticTableEncoding *table = (struct StaticTableEncoding *)enc;
+ int is_gr = bytes[*pos] & 0x80;
+
+ for(; *pos < bytelen && *cpi < cplen; (*pos)++) {
+ unsigned char c = bytes[*pos] ^ is_gr;
+
+ if(c < 0x20 || c == 0x7f || c >= 0x80)
+ return;
+
+ if(table->chars[c])
+ cp[(*cpi)++] = table->chars[c];
+ else
+ cp[(*cpi)++] = c;
+ }
+}
+
+#include "encoding/DECdrawing.inc"
+#include "encoding/uk.inc"
+
+static struct {
+ VTermEncodingType type;
+ char designation;
+ VTermEncoding *enc;
+}
+encodings[] = {
+ { ENC_UTF8, 'u', &encoding_utf8 },
+ { ENC_SINGLE_94, '0', (VTermEncoding*)&encoding_DECdrawing },
+ { ENC_SINGLE_94, 'A', (VTermEncoding*)&encoding_uk },
+ { ENC_SINGLE_94, 'B', &encoding_usascii },
+ { 0, 0, NULL },
+};
+
+/* This ought to be INTERNAL but isn't because it's used by unit testing */
+VTermEncoding *vterm_lookup_encoding(VTermEncodingType type, char designation)
+{
+ int i;
+ for(i = 0; encodings[i].designation; i++)
+ if(encodings[i].type == type && encodings[i].designation == designation)
+ return encodings[i].enc;
+ return NULL;
+}
diff --git a/src/libvterm/src/encoding/DECdrawing.inc b/src/libvterm/src/encoding/DECdrawing.inc
new file mode 100644
index 0000000..978f98c
--- /dev/null
+++ b/src/libvterm/src/encoding/DECdrawing.inc
@@ -0,0 +1,136 @@
+static const struct StaticTableEncoding encoding_DECdrawing = {
+ {
+ NULL, /* init */
+ &decode_table /* decode */
+ },
+ {
+ 0x0, /* 0 */
+ 0x0, /* 1 */
+ 0x0, /* 2 */
+ 0x0, /* 3 */
+ 0x0, /* 4 */
+ 0x0, /* 5 */
+ 0x0, /* 6 */
+ 0x0, /* 7 */
+ 0x0, /* 8 */
+ 0x0, /* 9 */
+ 0x0, /* 10 */
+ 0x0, /* 11 */
+ 0x0, /* 12 */
+ 0x0, /* 13 */
+ 0x0, /* 14 */
+ 0x0, /* 15 */
+ 0x0, /* 16 */
+ 0x0, /* 17 */
+ 0x0, /* 18 */
+ 0x0, /* 19 */
+ 0x0, /* 20 */
+ 0x0, /* 21 */
+ 0x0, /* 22 */
+ 0x0, /* 23 */
+ 0x0, /* 24 */
+ 0x0, /* 25 */
+ 0x0, /* 26 */
+ 0x0, /* 27 */
+ 0x0, /* 28 */
+ 0x0, /* 29 */
+ 0x0, /* 30 */
+ 0x0, /* 31 */
+ 0x0, /* 32 */
+ 0x0, /* 33 */
+ 0x0, /* 34 */
+ 0x0, /* 35 */
+ 0x0, /* 36 */
+ 0x0, /* 37 */
+ 0x0, /* 38 */
+ 0x0, /* 39 */
+ 0x0, /* 40 */
+ 0x0, /* 41 */
+ 0x0, /* 42 */
+ 0x0, /* 43 */
+ 0x0, /* 44 */
+ 0x0, /* 45 */
+ 0x0, /* 46 */
+ 0x0, /* 47 */
+ 0x0, /* 48 */
+ 0x0, /* 49 */
+ 0x0, /* 50 */
+ 0x0, /* 51 */
+ 0x0, /* 52 */
+ 0x0, /* 53 */
+ 0x0, /* 54 */
+ 0x0, /* 55 */
+ 0x0, /* 56 */
+ 0x0, /* 57 */
+ 0x0, /* 58 */
+ 0x0, /* 59 */
+ 0x0, /* 60 */
+ 0x0, /* 61 */
+ 0x0, /* 62 */
+ 0x0, /* 63 */
+ 0x0, /* 64 */
+ 0x0, /* 65 */
+ 0x0, /* 66 */
+ 0x0, /* 67 */
+ 0x0, /* 68 */
+ 0x0, /* 69 */
+ 0x0, /* 70 */
+ 0x0, /* 71 */
+ 0x0, /* 72 */
+ 0x0, /* 73 */
+ 0x0, /* 74 */
+ 0x0, /* 75 */
+ 0x0, /* 76 */
+ 0x0, /* 77 */
+ 0x0, /* 78 */
+ 0x0, /* 79 */
+ 0x0, /* 80 */
+ 0x0, /* 81 */
+ 0x0, /* 82 */
+ 0x0, /* 83 */
+ 0x0, /* 84 */
+ 0x0, /* 85 */
+ 0x0, /* 86 */
+ 0x0, /* 87 */
+ 0x0, /* 88 */
+ 0x0, /* 89 */
+ 0x0, /* 90 */
+ 0x0, /* 91 */
+ 0x0, /* 92 */
+ 0x0, /* 93 */
+ 0x0, /* 94 */
+ 0x0, /* 95 */
+ 0x25C6, /* 96 */
+ 0x2592, /* 97 */
+ 0x2409, /* 98 */
+ 0x240C, /* 99 */
+ 0x240D, /* 100 */
+ 0x240A, /* 101 */
+ 0x00B0, /* 102 */
+ 0x00B1, /* 103 */
+ 0x2424, /* 104 */
+ 0x240B, /* 105 */
+ 0x2518, /* 106 */
+ 0x2510, /* 107 */
+ 0x250C, /* 108 */
+ 0x2514, /* 109 */
+ 0x253C, /* 110 */
+ 0x23BA, /* 111 */
+ 0x23BB, /* 112 */
+ 0x2500, /* 113 */
+ 0x23BC, /* 114 */
+ 0x23BD, /* 115 */
+ 0x251C, /* 116 */
+ 0x2524, /* 117 */
+ 0x2534, /* 118 */
+ 0x252C, /* 119 */
+ 0x2502, /* 120 */
+ 0x2A7D, /* 121 */
+ 0x2A7E, /* 122 */
+ 0x03C0, /* 123 */
+ 0x2260, /* 124 */
+ 0x00A3, /* 125 */
+ 0x00B7, /* 126 */
+ 0x0, /* 127 */
+ }
+};
diff --git a/src/libvterm/src/encoding/DECdrawing.tbl b/src/libvterm/src/encoding/DECdrawing.tbl
new file mode 100644
index 0000000..6e19c50
--- /dev/null
+++ b/src/libvterm/src/encoding/DECdrawing.tbl
@@ -0,0 +1,31 @@
+6/0 = U+25C6 # BLACK DIAMOND
+6/1 = U+2592 # MEDIUM SHADE (checkerboard)
+6/2 = U+2409 # SYMBOL FOR HORIZONTAL TAB
+6/3 = U+240C # SYMBOL FOR FORM FEED
+6/4 = U+240D # SYMBOL FOR CARRIAGE RETURN
+6/5 = U+240A # SYMBOL FOR LINE FEED
+6/6 = U+00B0 # DEGREE SIGN
+6/7 = U+00B1 # PLUS-MINUS SIGN (plus or minus)
+6/8 = U+2424 # SYMBOL FOR NEW LINE
+6/9 = U+240B # SYMBOL FOR VERTICAL TAB
+6/10 = U+2518 # BOX DRAWINGS LIGHT UP AND LEFT (bottom-right corner)
+6/11 = U+2510 # BOX DRAWINGS LIGHT DOWN AND LEFT (top-right corner)
+6/12 = U+250C # BOX DRAWINGS LIGHT DOWN AND RIGHT (top-left corner)
+6/13 = U+2514 # BOX DRAWINGS LIGHT UP AND RIGHT (bottom-left corner)
+6/14 = U+253C # BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL (crossing lines)
+6/15 = U+23BA # HORIZONTAL SCAN LINE-1
+7/0 = U+23BB # HORIZONTAL SCAN LINE-3
+7/1 = U+2500 # BOX DRAWINGS LIGHT HORIZONTAL
+7/2 = U+23BC # HORIZONTAL SCAN LINE-7
+7/3 = U+23BD # HORIZONTAL SCAN LINE-9
+7/4 = U+251C # BOX DRAWINGS LIGHT VERTICAL AND RIGHT
+7/5 = U+2524 # BOX DRAWINGS LIGHT VERTICAL AND LEFT
+7/6 = U+2534 # BOX DRAWINGS LIGHT UP AND HORIZONTAL
+7/7 = U+252C # BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
+7/8 = U+2502 # BOX DRAWINGS LIGHT VERTICAL
+7/9 = U+2A7D # LESS-THAN OR SLANTED EQUAL-TO
+7/10 = U+2A7E # GREATER-THAN OR SLANTED EQUAL-TO
+7/11 = U+03C0 # GREEK SMALL LETTER PI
+7/12 = U+2260 # NOT EQUAL TO
+7/13 = U+00A3 # POUND SIGN
+7/14 = U+00B7 # MIDDLE DOT
diff --git a/src/libvterm/src/encoding/uk.inc b/src/libvterm/src/encoding/uk.inc
new file mode 100644
index 0000000..49ced5a
--- /dev/null
+++ b/src/libvterm/src/encoding/uk.inc
@@ -0,0 +1,136 @@
+static const struct StaticTableEncoding encoding_uk = {
+ {
+ NULL, /* init */
+ &decode_table /* decode */
+ },
+ {
+ 0x0, /* 0 */
+ 0x0, /* 1 */
+ 0x0, /* 2 */
+ 0x0, /* 3 */
+ 0x0, /* 4 */
+ 0x0, /* 5 */
+ 0x0, /* 6 */
+ 0x0, /* 7 */
+ 0x0, /* 8 */
+ 0x0, /* 9 */
+ 0x0, /* 10 */
+ 0x0, /* 11 */
+ 0x0, /* 12 */
+ 0x0, /* 13 */
+ 0x0, /* 14 */
+ 0x0, /* 15 */
+ 0x0, /* 16 */
+ 0x0, /* 17 */
+ 0x0, /* 18 */
+ 0x0, /* 19 */
+ 0x0, /* 20 */
+ 0x0, /* 21 */
+ 0x0, /* 22 */
+ 0x0, /* 23 */
+ 0x0, /* 24 */
+ 0x0, /* 25 */
+ 0x0, /* 26 */
+ 0x0, /* 27 */
+ 0x0, /* 28 */
+ 0x0, /* 29 */
+ 0x0, /* 30 */
+ 0x0, /* 31 */
+ 0x0, /* 32 */
+ 0x0, /* 33 */
+ 0x0, /* 34 */
+ 0x00a3, /* 35 */
+ 0x0, /* 36 */
+ 0x0, /* 37 */
+ 0x0, /* 38 */
+ 0x0, /* 39 */
+ 0x0, /* 40 */
+ 0x0, /* 41 */
+ 0x0, /* 42 */
+ 0x0, /* 43 */
+ 0x0, /* 44 */
+ 0x0, /* 45 */
+ 0x0, /* 46 */
+ 0x0, /* 47 */
+ 0x0, /* 48 */
+ 0x0, /* 49 */
+ 0x0, /* 50 */
+ 0x0, /* 51 */
+ 0x0, /* 52 */
+ 0x0, /* 53 */
+ 0x0, /* 54 */
+ 0x0, /* 55 */
+ 0x0, /* 56 */
+ 0x0, /* 57 */
+ 0x0, /* 58 */
+ 0x0, /* 59 */
+ 0x0, /* 60 */
+ 0x0, /* 61 */
+ 0x0, /* 62 */
+ 0x0, /* 63 */
+ 0x0, /* 64 */
+ 0x0, /* 65 */
+ 0x0, /* 66 */
+ 0x0, /* 67 */
+ 0x0, /* 68 */
+ 0x0, /* 69 */
+ 0x0, /* 70 */
+ 0x0, /* 71 */
+ 0x0, /* 72 */
+ 0x0, /* 73 */
+ 0x0, /* 74 */
+ 0x0, /* 75 */
+ 0x0, /* 76 */
+ 0x0, /* 77 */
+ 0x0, /* 78 */
+ 0x0, /* 79 */
+ 0x0, /* 80 */
+ 0x0, /* 81 */
+ 0x0, /* 82 */
+ 0x0, /* 83 */
+ 0x0, /* 84 */
+ 0x0, /* 85 */
+ 0x0, /* 86 */
+ 0x0, /* 87 */
+ 0x0, /* 88 */
+ 0x0, /* 89 */
+ 0x0, /* 90 */
+ 0x0, /* 91 */
+ 0x0, /* 92 */
+ 0x0, /* 93 */
+ 0x0, /* 94 */
+ 0x0, /* 95 */
+ 0x0, /* 96 */
+ 0x0, /* 97 */
+ 0x0, /* 98 */
+ 0x0, /* 99 */
+ 0x0, /* 100 */
+ 0x0, /* 101 */
+ 0x0, /* 102 */
+ 0x0, /* 103 */
+ 0x0, /* 104 */
+ 0x0, /* 105 */
+ 0x0, /* 106 */
+ 0x0, /* 107 */
+ 0x0, /* 108 */
+ 0x0, /* 109 */
+ 0x0, /* 110 */
+ 0x0, /* 111 */
+ 0x0, /* 112 */
+ 0x0, /* 113 */
+ 0x0, /* 114 */
+ 0x0, /* 115 */
+ 0x0, /* 116 */
+ 0x0, /* 117 */
+ 0x0, /* 118 */
+ 0x0, /* 119 */
+ 0x0, /* 120 */
+ 0x0, /* 121 */
+ 0x0, /* 122 */
+ 0x0, /* 123 */
+ 0x0, /* 124 */
+ 0x0, /* 125 */
+ 0x0, /* 126 */
+ 0x0, /* 127 */
+ }
+};
diff --git a/src/libvterm/src/encoding/uk.tbl b/src/libvterm/src/encoding/uk.tbl
new file mode 100644
index 0000000..b27b1a2
--- /dev/null
+++ b/src/libvterm/src/encoding/uk.tbl
@@ -0,0 +1 @@
+2/3 = "£"
diff --git a/src/libvterm/src/keyboard.c b/src/libvterm/src/keyboard.c
new file mode 100644
index 0000000..8cc781f
--- /dev/null
+++ b/src/libvterm/src/keyboard.c
@@ -0,0 +1,229 @@
+#include "vterm_internal.h"
+
+#include <stdio.h>
+
+#include "utf8.h"
+
+void vterm_keyboard_unichar(VTerm *vt, uint32_t c, VTermModifier mod)
+{
+ int needs_CSIu;
+
+ /* The shift modifier is never important for Unicode characters
+ * apart from Space
+ */
+ if(c != ' ')
+ mod &= ~VTERM_MOD_SHIFT;
+
+ if(mod == 0) {
+ // Normal text - ignore just shift
+ char str[6];
+ int seqlen = fill_utf8(c, str);
+ vterm_push_output_bytes(vt, str, seqlen);
+ return;
+ }
+
+ switch(c) {
+ /* Special Ctrl- letters that can't be represented elsewise */
+ case 'i': case 'j': case 'm': case '[':
+ needs_CSIu = 1;
+ break;
+ /* Ctrl-\ ] ^ _ don't need CSUu */
+ case '\\': case ']': case '^': case '_':
+ needs_CSIu = 0;
+ break;
+ /* Shift-space needs CSIu */
+ case ' ':
+ needs_CSIu = !!(mod & VTERM_MOD_SHIFT);
+ break;
+ /* All other characters needs CSIu except for letters a-z */
+ default:
+ needs_CSIu = (c < 'a' || c > 'z');
+ }
+
+ /* ALT we can just prefix with ESC; anything else requires CSI u */
+ if(needs_CSIu && (mod & ~VTERM_MOD_ALT)) {
+ vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%d;%du", c, mod+1);
+ return;
+ }
+
+ if(mod & VTERM_MOD_CTRL)
+ c &= 0x1f;
+
+ vterm_push_output_sprintf(vt, "%s%c", mod & VTERM_MOD_ALT ? ESC_S : "", c);
+}
+
+typedef struct {
+ enum {
+ KEYCODE_NONE,
+ KEYCODE_LITERAL,
+ KEYCODE_TAB,
+ KEYCODE_ENTER,
+ KEYCODE_SS3,
+ KEYCODE_CSI,
+ KEYCODE_CSI_CURSOR,
+ KEYCODE_CSINUM,
+ KEYCODE_KEYPAD,
+ } type;
+ char literal;
+ int csinum;
+} keycodes_s;
+
+/* Order here must be exactly the same as VTermKey enum! */
+static keycodes_s keycodes[] = {
+ { KEYCODE_NONE, 0, 0 }, // NONE
+
+ { KEYCODE_ENTER, '\r', 0 }, // ENTER
+ { KEYCODE_TAB, '\t', 0 }, // TAB
+ { KEYCODE_LITERAL, '\x7f', 0 }, // BACKSPACE == ASCII DEL
+ { KEYCODE_LITERAL, '\x1b', 0 }, // ESCAPE
+
+ { KEYCODE_CSI_CURSOR, 'A', 0 }, // UP
+ { KEYCODE_CSI_CURSOR, 'B', 0 }, // DOWN
+ { KEYCODE_CSI_CURSOR, 'D', 0 }, // LEFT
+ { KEYCODE_CSI_CURSOR, 'C', 0 }, // RIGHT
+
+ { KEYCODE_CSINUM, '~', 2 }, // INS
+ { KEYCODE_CSINUM, '~', 3 }, // DEL
+ { KEYCODE_CSI_CURSOR, 'H', 0 }, // HOME
+ { KEYCODE_CSI_CURSOR, 'F', 0 }, // END
+ { KEYCODE_CSINUM, '~', 5 }, // PAGEUP
+ { KEYCODE_CSINUM, '~', 6 }, // PAGEDOWN
+};
+
+static keycodes_s keycodes_fn[] = {
+ { KEYCODE_NONE, 0, 0 }, // F0 - shouldn't happen
+ { KEYCODE_CSI_CURSOR, 'P', 0 }, // F1
+ { KEYCODE_CSI_CURSOR, 'Q', 0 }, // F2
+ { KEYCODE_CSI_CURSOR, 'R', 0 }, // F3
+ { KEYCODE_CSI_CURSOR, 'S', 0 }, // F4
+ { KEYCODE_CSINUM, '~', 15 }, // F5
+ { KEYCODE_CSINUM, '~', 17 }, // F6
+ { KEYCODE_CSINUM, '~', 18 }, // F7
+ { KEYCODE_CSINUM, '~', 19 }, // F8
+ { KEYCODE_CSINUM, '~', 20 }, // F9
+ { KEYCODE_CSINUM, '~', 21 }, // F10
+ { KEYCODE_CSINUM, '~', 23 }, // F11
+ { KEYCODE_CSINUM, '~', 24 }, // F12
+};
+
+static keycodes_s keycodes_kp[] = {
+ { KEYCODE_KEYPAD, '0', 'p' }, // KP_0
+ { KEYCODE_KEYPAD, '1', 'q' }, // KP_1
+ { KEYCODE_KEYPAD, '2', 'r' }, // KP_2
+ { KEYCODE_KEYPAD, '3', 's' }, // KP_3
+ { KEYCODE_KEYPAD, '4', 't' }, // KP_4
+ { KEYCODE_KEYPAD, '5', 'u' }, // KP_5
+ { KEYCODE_KEYPAD, '6', 'v' }, // KP_6
+ { KEYCODE_KEYPAD, '7', 'w' }, // KP_7
+ { KEYCODE_KEYPAD, '8', 'x' }, // KP_8
+ { KEYCODE_KEYPAD, '9', 'y' }, // KP_9
+ { KEYCODE_KEYPAD, '*', 'j' }, // KP_MULT
+ { KEYCODE_KEYPAD, '+', 'k' }, // KP_PLUS
+ { KEYCODE_KEYPAD, ',', 'l' }, // KP_COMMA
+ { KEYCODE_KEYPAD, '-', 'm' }, // KP_MINUS
+ { KEYCODE_KEYPAD, '.', 'n' }, // KP_PERIOD
+ { KEYCODE_KEYPAD, '/', 'o' }, // KP_DIVIDE
+ { KEYCODE_KEYPAD, '\n', 'M' }, // KP_ENTER
+ { KEYCODE_KEYPAD, '=', 'X' }, // KP_EQUAL
+};
+
+void vterm_keyboard_key(VTerm *vt, VTermKey key, VTermModifier mod)
+{
+ keycodes_s k;
+
+ if(key == VTERM_KEY_NONE)
+ return;
+
+ if(key < VTERM_KEY_FUNCTION_0) {
+ if(key >= sizeof(keycodes)/sizeof(keycodes[0]))
+ return;
+ k = keycodes[key];
+ }
+ else if(key >= VTERM_KEY_FUNCTION_0 && key <= VTERM_KEY_FUNCTION_MAX) {
+ if((key - VTERM_KEY_FUNCTION_0) >= sizeof(keycodes_fn)/sizeof(keycodes_fn[0]))
+ return;
+ k = keycodes_fn[key - VTERM_KEY_FUNCTION_0];
+ }
+ else if(key >= VTERM_KEY_KP_0) {
+ if((key - VTERM_KEY_KP_0) >= sizeof(keycodes_kp)/sizeof(keycodes_kp[0]))
+ return;
+ k = keycodes_kp[key - VTERM_KEY_KP_0];
+ }
+
+ switch(k.type) {
+ case KEYCODE_NONE:
+ break;
+
+ case KEYCODE_TAB:
+ /* Shift-Tab is CSI Z but plain Tab is 0x09 */
+ if(mod == VTERM_MOD_SHIFT)
+ vterm_push_output_sprintf_ctrl(vt, C1_CSI, "Z");
+ else if(mod & VTERM_MOD_SHIFT)
+ vterm_push_output_sprintf_ctrl(vt, C1_CSI, "1;%dZ", mod+1);
+ else
+ goto case_LITERAL;
+ break;
+
+ case KEYCODE_ENTER:
+ /* Enter is CRLF in newline mode, but just LF in linefeed */
+ if(vt->state->mode.newline)
+ vterm_push_output_sprintf(vt, "\r\n");
+ else
+ goto case_LITERAL;
+ break;
+
+ case KEYCODE_LITERAL: case_LITERAL:
+ if(mod & (VTERM_MOD_SHIFT|VTERM_MOD_CTRL))
+ vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%d;%du", k.literal, mod+1);
+ else
+ vterm_push_output_sprintf(vt, mod & VTERM_MOD_ALT ? ESC_S "%c" : "%c", k.literal);
+ break;
+
+ case KEYCODE_SS3: case_SS3:
+ if(mod == 0)
+ vterm_push_output_sprintf_ctrl(vt, C1_SS3, "%c", k.literal);
+ else
+ goto case_CSI;
+ break;
+
+ case KEYCODE_CSI: case_CSI:
+ if(mod == 0)
+ vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%c", k.literal);
+ else
+ vterm_push_output_sprintf_ctrl(vt, C1_CSI, "1;%d%c", mod + 1, k.literal);
+ break;
+
+ case KEYCODE_CSINUM:
+ if(mod == 0)
+ vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%d%c", k.csinum, k.literal);
+ else
+ vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%d;%d%c", k.csinum, mod + 1, k.literal);
+ break;
+
+ case KEYCODE_CSI_CURSOR:
+ if(vt->state->mode.cursor)
+ goto case_SS3;
+ else
+ goto case_CSI;
+
+ case KEYCODE_KEYPAD:
+ if(vt->state->mode.keypad) {
+ k.literal = k.csinum;
+ goto case_SS3;
+ }
+ else
+ goto case_LITERAL;
+ }
+}
+
+void vterm_keyboard_start_paste(VTerm *vt)
+{
+ if(vt->state->mode.bracketpaste)
+ vterm_push_output_sprintf_ctrl(vt, C1_CSI, "200~");
+}
+
+void vterm_keyboard_end_paste(VTerm *vt)
+{
+ if(vt->state->mode.bracketpaste)
+ vterm_push_output_sprintf_ctrl(vt, C1_CSI, "201~");
+}
diff --git a/src/libvterm/src/mouse.c b/src/libvterm/src/mouse.c
new file mode 100644
index 0000000..4e36313
--- /dev/null
+++ b/src/libvterm/src/mouse.c
@@ -0,0 +1,98 @@
+#include "vterm_internal.h"
+
+#include "utf8.h"
+
+static void output_mouse(VTermState *state, int code, int pressed, int modifiers, int col, int row)
+{
+ modifiers <<= 2;
+
+ switch(state->mouse_protocol) {
+ case MOUSE_X10:
+ if(col + 0x21 > 0xff)
+ col = 0xff - 0x21;
+ if(row + 0x21 > 0xff)
+ row = 0xff - 0x21;
+
+ if(!pressed)
+ code = 3;
+
+ vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "M%c%c%c",
+ (code | modifiers) + 0x20, col + 0x21, row + 0x21);
+ break;
+
+ case MOUSE_UTF8:
+ {
+ char utf8[18]; size_t len = 0;
+
+ if(!pressed)
+ code = 3;
+
+ len += fill_utf8((code | modifiers) + 0x20, utf8 + len);
+ len += fill_utf8(col + 0x21, utf8 + len);
+ len += fill_utf8(row + 0x21, utf8 + len);
+ utf8[len] = 0;
+
+ vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "M%s", utf8);
+ }
+ break;
+
+ case MOUSE_SGR:
+ vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "<%d;%d;%d%c",
+ code | modifiers, col + 1, row + 1, pressed ? 'M' : 'm');
+ break;
+
+ case MOUSE_RXVT:
+ if(!pressed)
+ code = 3;
+
+ vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "%d;%d;%dM",
+ code | modifiers, col + 1, row + 1);
+ break;
+ }
+}
+
+void vterm_mouse_move(VTerm *vt, int row, int col, VTermModifier mod)
+{
+ VTermState *state = vt->state;
+
+ if(col == state->mouse_col && row == state->mouse_row)
+ return;
+
+ state->mouse_col = col;
+ state->mouse_row = row;
+
+ if((state->mouse_flags & MOUSE_WANT_DRAG && state->mouse_buttons) ||
+ (state->mouse_flags & MOUSE_WANT_MOVE)) {
+ int button = state->mouse_buttons & MOUSE_BUTTON_LEFT ? 1 :
+ state->mouse_buttons & MOUSE_BUTTON_MIDDLE ? 2 :
+ state->mouse_buttons & MOUSE_BUTTON_RIGHT ? 3 : 4;
+ output_mouse(state, button-1 + 0x20, 1, mod, col, row);
+ }
+}
+
+void vterm_mouse_button(VTerm *vt, int button, int pressed, VTermModifier mod)
+{
+ VTermState *state = vt->state;
+
+ int old_buttons = state->mouse_buttons;
+
+ if(button > 0 && button <= 3) {
+ if(pressed)
+ state->mouse_buttons |= (1 << (button-1));
+ else
+ state->mouse_buttons &= ~(1 << (button-1));
+ }
+
+ /* Most of the time we don't get button releases from 4/5 */
+ if(state->mouse_buttons == old_buttons && button < 4)
+ return;
+ if (!(state->mouse_flags & MOUSE_WANT_CLICK))
+ return;
+
+ if(button < 4) {
+ output_mouse(state, button-1, pressed, mod, state->mouse_col, state->mouse_row);
+ }
+ else if(button < 6) {
+ output_mouse(state, button-4 + 0x40, pressed, mod, state->mouse_col, state->mouse_row);
+ }
+}
diff --git a/src/libvterm/src/parser.c b/src/libvterm/src/parser.c
new file mode 100644
index 0000000..db45692
--- /dev/null
+++ b/src/libvterm/src/parser.c
@@ -0,0 +1,346 @@
+#include "vterm_internal.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#undef DEBUG_PARSER
+
+static int is_intermed(unsigned char c)
+{
+ return c >= 0x20 && c <= 0x2f;
+}
+
+static void do_control(VTerm *vt, unsigned char control)
+{
+ if(vt->parser.callbacks && vt->parser.callbacks->control)
+ if((*vt->parser.callbacks->control)(control, vt->parser.cbdata))
+ return;
+
+ DEBUG_LOG1("libvterm: Unhandled control 0x%02x\n", control);
+}
+
+static void do_csi(VTerm *vt, char command)
+{
+#ifdef DEBUG_PARSER
+ printf("Parsed CSI args as:\n", arglen, args);
+ printf(" leader: %s\n", vt->parser.csi_leader);
+ for(int argi = 0; argi < vt->parser.csi_argi; argi++) {
+ printf(" %lu", CSI_ARG(vt->parser.csi_args[argi]));
+ if(!CSI_ARG_HAS_MORE(vt->parser.csi_args[argi]))
+ printf("\n");
+ printf(" intermed: %s\n", vt->parser.intermed);
+ }
+#endif
+
+ if(vt->parser.callbacks && vt->parser.callbacks->csi)
+ if((*vt->parser.callbacks->csi)(
+ vt->parser.csi_leaderlen ? vt->parser.csi_leader : NULL,
+ vt->parser.csi_args,
+ vt->parser.csi_argi,
+ vt->parser.intermedlen ? vt->parser.intermed : NULL,
+ command,
+ vt->parser.cbdata))
+ return;
+
+ DEBUG_LOG1("libvterm: Unhandled CSI %c\n", command);
+}
+
+static void do_escape(VTerm *vt, char command)
+{
+ char seq[INTERMED_MAX+1];
+
+ size_t len = vt->parser.intermedlen;
+ strncpy(seq, vt->parser.intermed, len);
+ seq[len++] = command;
+ seq[len] = 0;
+
+ if(vt->parser.callbacks && vt->parser.callbacks->escape)
+ if((*vt->parser.callbacks->escape)(seq, len, vt->parser.cbdata))
+ return;
+
+ DEBUG_LOG1("libvterm: Unhandled escape ESC 0x%02x\n", command);
+}
+
+static void append_strbuffer(VTerm *vt, const char *str, size_t len)
+{
+ if(len > vt->parser.strbuffer_len - vt->parser.strbuffer_cur) {
+ len = vt->parser.strbuffer_len - vt->parser.strbuffer_cur;
+ DEBUG_LOG1("Truncating strbuffer preserve to %zd bytes\n", len);
+ }
+
+ if(len > 0) {
+ strncpy(vt->parser.strbuffer + vt->parser.strbuffer_cur, str, len);
+ vt->parser.strbuffer_cur += len;
+ }
+}
+
+static void start_string(VTerm *vt, VTermParserStringType type)
+{
+ vt->parser.stringtype = type;
+
+ vt->parser.strbuffer_cur = 0;
+}
+
+static void more_string(VTerm *vt, const char *str, size_t len)
+{
+ append_strbuffer(vt, str, len);
+}
+
+static void done_string(VTerm *vt, const char *str, size_t len)
+{
+ if(vt->parser.strbuffer_cur) {
+ if(str)
+ append_strbuffer(vt, str, len);
+
+ str = vt->parser.strbuffer;
+ len = vt->parser.strbuffer_cur;
+ }
+ else if(!str) {
+ DEBUG_LOG("parser.c: TODO: No strbuffer _and_ no final fragment???\n");
+ len = 0;
+ }
+
+ switch(vt->parser.stringtype) {
+ case VTERM_PARSER_OSC:
+ if(vt->parser.callbacks && vt->parser.callbacks->osc)
+ if((*vt->parser.callbacks->osc)(str, len, vt->parser.cbdata))
+ return;
+
+ DEBUG_LOG2("libvterm: Unhandled OSC %.*s\n", (int)len, str);
+ return;
+
+ case VTERM_PARSER_DCS:
+ if(vt->parser.callbacks && vt->parser.callbacks->dcs)
+ if((*vt->parser.callbacks->dcs)(str, len, vt->parser.cbdata))
+ return;
+
+ DEBUG_LOG2("libvterm: Unhandled DCS %.*s\n", (int)len, str);
+ return;
+
+ case VTERM_N_PARSER_TYPES:
+ return;
+ }
+}
+
+size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len)
+{
+ size_t pos = 0;
+ const char *string_start = NULL; /* init to avoid gcc warning */
+
+ switch(vt->parser.state) {
+ case NORMAL:
+ case CSI_LEADER:
+ case CSI_ARGS:
+ case CSI_INTERMED:
+ case ESC:
+ string_start = NULL;
+ break;
+ case STRING:
+ case ESC_IN_STRING:
+ string_start = bytes;
+ break;
+ }
+
+#define ENTER_STRING_STATE() do { vt->parser.state = STRING; string_start = bytes + pos + 1; } while(0)
+#define ENTER_STATE(st) do { vt->parser.state = st; string_start = NULL; } while(0)
+#define ENTER_NORMAL_STATE() ENTER_STATE(NORMAL)
+
+ for( ; pos < len; pos++) {
+ unsigned char c = bytes[pos];
+
+ if(c == 0x00 || c == 0x7f) { // NUL, DEL
+ if(vt->parser.state >= STRING) {
+ more_string(vt, string_start, bytes + pos - string_start);
+ string_start = bytes + pos + 1;
+ }
+ continue;
+ }
+ if(c == 0x18 || c == 0x1a) { // CAN, SUB
+ ENTER_NORMAL_STATE();
+ continue;
+ }
+ else if(c == 0x1b) { // ESC
+ vt->parser.intermedlen = 0;
+ if(vt->parser.state == STRING)
+ vt->parser.state = ESC_IN_STRING;
+ else
+ ENTER_STATE(ESC);
+ continue;
+ }
+ else if(c == 0x07 && // BEL, can stand for ST in OSC or DCS state
+ vt->parser.state == STRING) {
+ // fallthrough
+ }
+ else if(c < 0x20) { // other C0
+ if(vt->parser.state >= STRING)
+ more_string(vt, string_start, bytes + pos - string_start);
+ do_control(vt, c);
+ if(vt->parser.state >= STRING)
+ string_start = bytes + pos + 1;
+ continue;
+ }
+ // else fallthrough
+
+ switch(vt->parser.state) {
+ case ESC_IN_STRING:
+ if(c == 0x5c) { // ST
+ vt->parser.state = STRING;
+ done_string(vt, string_start, bytes + pos - string_start - 1);
+ ENTER_NORMAL_STATE();
+ break;
+ }
+ vt->parser.state = ESC;
+ // else fallthrough
+
+ case ESC:
+ switch(c) {
+ case 0x50: // DCS
+ start_string(vt, VTERM_PARSER_DCS);
+ ENTER_STRING_STATE();
+ break;
+ case 0x5b: // CSI
+ vt->parser.csi_leaderlen = 0;
+ ENTER_STATE(CSI_LEADER);
+ break;
+ case 0x5d: // OSC
+ start_string(vt, VTERM_PARSER_OSC);
+ ENTER_STRING_STATE();
+ break;
+ default:
+ if(is_intermed(c)) {
+ if(vt->parser.intermedlen < INTERMED_MAX-1)
+ vt->parser.intermed[vt->parser.intermedlen++] = c;
+ }
+ else if(!vt->parser.intermedlen && c >= 0x40 && c < 0x60) {
+ do_control(vt, c + 0x40);
+ ENTER_NORMAL_STATE();
+ }
+ else if(c >= 0x30 && c < 0x7f) {
+ do_escape(vt, c);
+ ENTER_NORMAL_STATE();
+ }
+ else {
+ DEBUG_LOG1("TODO: Unhandled byte %02x in Escape\n", c);
+ }
+ }
+ break;
+
+ case CSI_LEADER:
+ /* Extract leader bytes 0x3c to 0x3f */
+ if(c >= 0x3c && c <= 0x3f) {
+ if(vt->parser.csi_leaderlen < CSI_LEADER_MAX-1)
+ vt->parser.csi_leader[vt->parser.csi_leaderlen++] = c;
+ break;
+ }
+
+ /* else fallthrough */
+ vt->parser.csi_leader[vt->parser.csi_leaderlen] = 0;
+
+ vt->parser.csi_argi = 0;
+ vt->parser.csi_args[0] = CSI_ARG_MISSING;
+ vt->parser.state = CSI_ARGS;
+
+ /* fallthrough */
+ case CSI_ARGS:
+ /* Numerical value of argument */
+ if(c >= '0' && c <= '9') {
+ if(vt->parser.csi_args[vt->parser.csi_argi] == CSI_ARG_MISSING)
+ vt->parser.csi_args[vt->parser.csi_argi] = 0;
+ vt->parser.csi_args[vt->parser.csi_argi] *= 10;
+ vt->parser.csi_args[vt->parser.csi_argi] += c - '0';
+ break;
+ }
+ if(c == ':') {
+ vt->parser.csi_args[vt->parser.csi_argi] |= CSI_ARG_FLAG_MORE;
+ c = ';';
+ }
+ if(c == ';') {
+ vt->parser.csi_argi++;
+ vt->parser.csi_args[vt->parser.csi_argi] = CSI_ARG_MISSING;
+ break;
+ }
+
+ /* else fallthrough */
+ vt->parser.csi_argi++;
+ vt->parser.intermedlen = 0;
+ vt->parser.state = CSI_INTERMED;
+ /* fallthrough */
+ case CSI_INTERMED:
+ if(is_intermed(c)) {
+ if(vt->parser.intermedlen < INTERMED_MAX-1)
+ vt->parser.intermed[vt->parser.intermedlen++] = c;
+ break;
+ }
+ else if(c == 0x1b) {
+ /* ESC in CSI cancels */
+ }
+ else if(c >= 0x40 && c <= 0x7e) {
+ vt->parser.intermed[vt->parser.intermedlen] = 0;
+ do_csi(vt, c);
+ }
+ /* else was invalid CSI */
+
+ ENTER_NORMAL_STATE();
+ break;
+
+ case STRING:
+ if(c == 0x07 || (c == 0x9c && !vt->mode.utf8)) {
+ done_string(vt, string_start, bytes + pos - string_start);
+ ENTER_NORMAL_STATE();
+ }
+ else if (pos + 1 == len) {
+ /* end of input but OSC string isn't finished yet, copy it to
+ * vt->parser.strbuffer to continue it later */
+ more_string(vt, string_start, bytes + pos + 1 - string_start);
+ }
+ break;
+
+ case NORMAL:
+ if(c >= 0x80 && c < 0xa0 && !vt->mode.utf8) {
+ switch(c) {
+ case 0x90: // DCS
+ start_string(vt, VTERM_PARSER_DCS);
+ ENTER_STRING_STATE();
+ break;
+ case 0x9b: // CSI
+ ENTER_STATE(CSI_LEADER);
+ break;
+ case 0x9d: // OSC
+ start_string(vt, VTERM_PARSER_OSC);
+ ENTER_STRING_STATE();
+ break;
+ default:
+ do_control(vt, c);
+ break;
+ }
+ }
+ else {
+ size_t eaten = 0;
+ if(vt->parser.callbacks && vt->parser.callbacks->text)
+ eaten = (*vt->parser.callbacks->text)(bytes + pos, len - pos, vt->parser.cbdata);
+
+ if(!eaten) {
+ DEBUG_LOG("libvterm: Text callback did not consume any input\n");
+ /* force it to make progress */
+ eaten = 1;
+ }
+
+ pos += (eaten - 1); // we'll ++ it again in a moment
+ }
+ break;
+ }
+ }
+
+ return len;
+}
+
+void vterm_parser_set_callbacks(VTerm *vt, const VTermParserCallbacks *callbacks, void *user)
+{
+ vt->parser.callbacks = callbacks;
+ vt->parser.cbdata = user;
+}
+
+void *vterm_parser_get_cbdata(VTerm *vt)
+{
+ return vt->parser.cbdata;
+}
diff --git a/src/libvterm/src/pen.c b/src/libvterm/src/pen.c
new file mode 100644
index 0000000..b780095
--- /dev/null
+++ b/src/libvterm/src/pen.c
@@ -0,0 +1,516 @@
+#include "vterm_internal.h"
+
+#include <stdio.h>
+
+static const VTermColor ansi_colors[] = {
+ /* R G B index */
+ { 0, 0, 0, 1 }, // black
+ { 224, 0, 0, 2 }, // red
+ { 0, 224, 0, 3 }, // green
+ { 224, 224, 0, 4 }, // yellow
+ { 0, 0, 224, 5 }, // blue
+ { 224, 0, 224, 6 }, // magenta
+ { 0, 224, 224, 7 }, // cyan
+ { 224, 224, 224, 8 }, // white == light grey
+
+ // high intensity
+ { 128, 128, 128, 9 }, // black
+ { 255, 64, 64, 10 }, // red
+ { 64, 255, 64, 11 }, // green
+ { 255, 255, 64, 12 }, // yellow
+ { 64, 64, 255, 13 }, // blue
+ { 255, 64, 255, 14 }, // magenta
+ { 64, 255, 255, 15 }, // cyan
+ { 255, 255, 255, 16 }, // white for real
+};
+
+static int ramp6[] = {
+ 0x00, 0x5F, 0x87, 0xAF, 0xD7, 0xFF,
+};
+
+/* Use 0x81 instead of 0x80 to be able to distinguish from ansi black */
+static int ramp24[] = {
+ 0x08, 0x12, 0x1C, 0x26, 0x30, 0x3A, 0x44, 0x4E, 0x58, 0x62, 0x6C, 0x76,
+ 0x81, 0x8A, 0x94, 0x9E, 0xA8, 0xB2, 0xBC, 0xC6, 0xD0, 0xDA, 0xE4, 0xEE,
+};
+
+static int lookup_colour_ansi(const VTermState *state, long index, VTermColor *col)
+{
+ if(index >= 0 && index < 16) {
+ *col = state->colors[index];
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static int lookup_colour_palette(const VTermState *state, long index, VTermColor *col)
+{
+ if(index >= 0 && index < 16) {
+ // Normal 8 colours or high intensity - parse as palette 0
+ return lookup_colour_ansi(state, index, col);
+ }
+ else if(index >= 16 && index < 232) {
+ // 216-colour cube
+ index -= 16;
+
+ col->blue = ramp6[index % 6];
+ col->green = ramp6[index/6 % 6];
+ col->red = ramp6[index/6/6 % 6];
+ col->ansi_index = VTERM_ANSI_INDEX_NONE;
+
+ return TRUE;
+ }
+ else if(index >= 232 && index < 256) {
+ // 24 greyscales
+ index -= 232;
+
+ col->blue = ramp24[index];
+ col->green = ramp24[index];
+ col->red = ramp24[index];
+ col->ansi_index = VTERM_ANSI_INDEX_NONE;
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static int lookup_colour(const VTermState *state, int palette, const long args[], int argcount, VTermColor *col, int *index)
+{
+ switch(palette) {
+ case 2: // RGB mode - 3 args contain colour values directly
+ if(argcount < 3)
+ return argcount;
+
+ col->red = (uint8_t)CSI_ARG(args[0]);
+ col->green = (uint8_t)CSI_ARG(args[1]);
+ col->blue = (uint8_t)CSI_ARG(args[2]);
+ col->ansi_index = VTERM_ANSI_INDEX_NONE;
+
+ return 3;
+
+ case 5: // XTerm 256-colour mode
+ if(index)
+ *index = CSI_ARG_OR(args[0], -1);
+
+ lookup_colour_palette(state, argcount ? CSI_ARG_OR(args[0], -1) : -1, col);
+
+ return argcount ? 1 : 0;
+
+ default:
+ DEBUG_LOG1("Unrecognised colour palette %d\n", palette);
+ return 0;
+ }
+}
+
+// Some conveniences
+
+static void setpenattr(VTermState *state, VTermAttr attr, VTermValueType type UNUSED, VTermValue *val)
+{
+#ifdef DEBUG
+ if(type != vterm_get_attr_type(attr)) {
+ DEBUG_LOG3("Cannot set attr %d as it has type %d, not type %d\n",
+ attr, vterm_get_attr_type(attr), type);
+ return;
+ }
+#endif
+ if(state->callbacks && state->callbacks->setpenattr)
+ (*state->callbacks->setpenattr)(attr, val, state->cbdata);
+}
+
+static void setpenattr_bool(VTermState *state, VTermAttr attr, int boolean)
+{
+ VTermValue val;
+ val.boolean = boolean;
+ setpenattr(state, attr, VTERM_VALUETYPE_BOOL, &val);
+}
+
+static void setpenattr_int(VTermState *state, VTermAttr attr, int number)
+{
+ VTermValue val;
+ val.number = number;
+ setpenattr(state, attr, VTERM_VALUETYPE_INT, &val);
+}
+
+static void setpenattr_col(VTermState *state, VTermAttr attr, VTermColor color)
+{
+ VTermValue val;
+ val.color = color;
+ setpenattr(state, attr, VTERM_VALUETYPE_COLOR, &val);
+}
+
+static void set_pen_col_ansi(VTermState *state, VTermAttr attr, long col)
+{
+ VTermColor *colp = (attr == VTERM_ATTR_BACKGROUND) ? &state->pen.bg : &state->pen.fg;
+
+ lookup_colour_ansi(state, col, colp);
+
+ setpenattr_col(state, attr, *colp);
+}
+
+INTERNAL void vterm_state_newpen(VTermState *state)
+{
+ int col;
+
+ // 90% grey so that pure white is brighter
+ state->default_fg.red = state->default_fg.green = state->default_fg.blue = 240;
+ state->default_fg.ansi_index = VTERM_ANSI_INDEX_DEFAULT;
+ state->default_bg.red = state->default_bg.green = state->default_bg.blue = 0;
+ state->default_bg.ansi_index = VTERM_ANSI_INDEX_DEFAULT;
+
+ for(col = 0; col < 16; col++)
+ state->colors[col] = ansi_colors[col];
+}
+
+INTERNAL void vterm_state_resetpen(VTermState *state)
+{
+ state->pen.bold = 0; setpenattr_bool(state, VTERM_ATTR_BOLD, 0);
+ state->pen.underline = 0; setpenattr_int( state, VTERM_ATTR_UNDERLINE, 0);
+ state->pen.italic = 0; setpenattr_bool(state, VTERM_ATTR_ITALIC, 0);
+ state->pen.blink = 0; setpenattr_bool(state, VTERM_ATTR_BLINK, 0);
+ state->pen.reverse = 0; setpenattr_bool(state, VTERM_ATTR_REVERSE, 0);
+ state->pen.strike = 0; setpenattr_bool(state, VTERM_ATTR_STRIKE, 0);
+ state->pen.font = 0; setpenattr_int( state, VTERM_ATTR_FONT, 0);
+
+ state->fg_index = -1;
+ state->bg_index = -1;
+ state->pen.fg = state->default_fg; setpenattr_col(state, VTERM_ATTR_FOREGROUND, state->default_fg);
+ state->pen.bg = state->default_bg; setpenattr_col(state, VTERM_ATTR_BACKGROUND, state->default_bg);
+}
+
+INTERNAL void vterm_state_savepen(VTermState *state, int save)
+{
+ if(save) {
+ state->saved.pen = state->pen;
+ }
+ else {
+ state->pen = state->saved.pen;
+
+ setpenattr_bool(state, VTERM_ATTR_BOLD, state->pen.bold);
+ setpenattr_int( state, VTERM_ATTR_UNDERLINE, state->pen.underline);
+ setpenattr_bool(state, VTERM_ATTR_ITALIC, state->pen.italic);
+ setpenattr_bool(state, VTERM_ATTR_BLINK, state->pen.blink);
+ setpenattr_bool(state, VTERM_ATTR_REVERSE, state->pen.reverse);
+ setpenattr_bool(state, VTERM_ATTR_STRIKE, state->pen.strike);
+ setpenattr_int( state, VTERM_ATTR_FONT, state->pen.font);
+ setpenattr_col( state, VTERM_ATTR_FOREGROUND, state->pen.fg);
+ setpenattr_col( state, VTERM_ATTR_BACKGROUND, state->pen.bg);
+ }
+}
+
+void vterm_state_get_default_colors(const VTermState *state, VTermColor *default_fg, VTermColor *default_bg)
+{
+ *default_fg = state->default_fg;
+ *default_bg = state->default_bg;
+}
+
+void vterm_state_get_palette_color(const VTermState *state, int index, VTermColor *col)
+{
+ lookup_colour_palette(state, index, col);
+}
+
+void vterm_state_set_default_colors(VTermState *state, const VTermColor *default_fg, const VTermColor *default_bg)
+{
+ state->default_fg = *default_fg;
+ state->default_bg = *default_bg;
+}
+
+void vterm_state_set_palette_color(VTermState *state, int index, const VTermColor *col)
+{
+ if(index >= 0 && index < 16)
+ {
+ state->colors[index] = *col;
+ state->colors[index].ansi_index = index + VTERM_ANSI_INDEX_MIN;
+ }
+}
+
+void vterm_state_set_bold_highbright(VTermState *state, int bold_is_highbright)
+{
+ state->bold_is_highbright = bold_is_highbright;
+}
+
+INTERNAL void vterm_state_setpen(VTermState *state, const long args[], int argcount)
+{
+ // SGR - ECMA-48 8.3.117
+
+ int argi = 0;
+ int value;
+
+ while(argi < argcount) {
+ // This logic is easier to do 'done' backwards; set it true, and make it
+ // false again in the 'default' case
+ int done = 1;
+
+ long arg;
+ switch(arg = CSI_ARG(args[argi])) {
+ case CSI_ARG_MISSING:
+ case 0: // Reset
+ vterm_state_resetpen(state);
+ break;
+
+ case 1: // Bold on
+ state->pen.bold = 1;
+ setpenattr_bool(state, VTERM_ATTR_BOLD, 1);
+ if(state->fg_index > -1 && state->fg_index < 8 && state->bold_is_highbright)
+ set_pen_col_ansi(state, VTERM_ATTR_FOREGROUND, state->fg_index + (state->pen.bold ? 8 : 0));
+ break;
+
+ case 3: // Italic on
+ state->pen.italic = 1;
+ setpenattr_bool(state, VTERM_ATTR_ITALIC, 1);
+ break;
+
+ case 4: // Underline single
+ state->pen.underline = 1;
+ setpenattr_int(state, VTERM_ATTR_UNDERLINE, 1);
+ break;
+
+ case 5: // Blink
+ state->pen.blink = 1;
+ setpenattr_bool(state, VTERM_ATTR_BLINK, 1);
+ break;
+
+ case 7: // Reverse on
+ state->pen.reverse = 1;
+ setpenattr_bool(state, VTERM_ATTR_REVERSE, 1);
+ break;
+
+ case 9: // Strikethrough on
+ state->pen.strike = 1;
+ setpenattr_bool(state, VTERM_ATTR_STRIKE, 1);
+ break;
+
+ case 10: case 11: case 12: case 13: case 14:
+ case 15: case 16: case 17: case 18: case 19: // Select font
+ state->pen.font = CSI_ARG(args[argi]) - 10;
+ setpenattr_int(state, VTERM_ATTR_FONT, state->pen.font);
+ break;
+
+ case 21: // Underline double
+ state->pen.underline = 2;
+ setpenattr_int(state, VTERM_ATTR_UNDERLINE, 2);
+ break;
+
+ case 22: // Bold off
+ state->pen.bold = 0;
+ setpenattr_bool(state, VTERM_ATTR_BOLD, 0);
+ break;
+
+ case 23: // Italic and Gothic (currently unsupported) off
+ state->pen.italic = 0;
+ setpenattr_bool(state, VTERM_ATTR_ITALIC, 0);
+ break;
+
+ case 24: // Underline off
+ state->pen.underline = 0;
+ setpenattr_int(state, VTERM_ATTR_UNDERLINE, 0);
+ break;
+
+ case 25: // Blink off
+ state->pen.blink = 0;
+ setpenattr_bool(state, VTERM_ATTR_BLINK, 0);
+ break;
+
+ case 27: // Reverse off
+ state->pen.reverse = 0;
+ setpenattr_bool(state, VTERM_ATTR_REVERSE, 0);
+ break;
+
+ case 29: // Strikethrough off
+ state->pen.strike = 0;
+ setpenattr_bool(state, VTERM_ATTR_STRIKE, 0);
+ break;
+
+ case 30: case 31: case 32: case 33:
+ case 34: case 35: case 36: case 37: // Foreground colour palette
+ value = CSI_ARG(args[argi]) - 30;
+ state->fg_index = value;
+ if(state->pen.bold && state->bold_is_highbright)
+ value += 8;
+ set_pen_col_ansi(state, VTERM_ATTR_FOREGROUND, value);
+ break;
+
+ case 38: // Foreground colour alternative palette
+ state->fg_index = -1;
+ if(argcount - argi < 1)
+ return;
+ argi += 1 + lookup_colour(state, CSI_ARG(args[argi+1]), args+argi+2, argcount-argi-2, &state->pen.fg, &state->fg_index);
+ setpenattr_col(state, VTERM_ATTR_FOREGROUND, state->pen.fg);
+ break;
+
+ case 39: // Foreground colour default
+ state->fg_index = -1;
+ state->pen.fg = state->default_fg;
+ setpenattr_col(state, VTERM_ATTR_FOREGROUND, state->pen.fg);
+ break;
+
+ case 40: case 41: case 42: case 43:
+ case 44: case 45: case 46: case 47: // Background colour palette
+ value = CSI_ARG(args[argi]) - 40;
+ state->bg_index = value;
+ set_pen_col_ansi(state, VTERM_ATTR_BACKGROUND, value);
+ break;
+
+ case 48: // Background colour alternative palette
+ state->bg_index = -1;
+ if(argcount - argi < 1)
+ return;
+ argi += 1 + lookup_colour(state, CSI_ARG(args[argi+1]), args+argi+2, argcount-argi-2, &state->pen.bg, &state->bg_index);
+ setpenattr_col(state, VTERM_ATTR_BACKGROUND, state->pen.bg);
+ break;
+
+ case 49: // Default background
+ state->bg_index = -1;
+ state->pen.bg = state->default_bg;
+ setpenattr_col(state, VTERM_ATTR_BACKGROUND, state->pen.bg);
+ break;
+
+ case 90: case 91: case 92: case 93:
+ case 94: case 95: case 96: case 97: // Foreground colour high-intensity palette
+ value = CSI_ARG(args[argi]) - 90 + 8;
+ state->fg_index = value;
+ set_pen_col_ansi(state, VTERM_ATTR_FOREGROUND, value);
+ break;
+
+ case 100: case 101: case 102: case 103:
+ case 104: case 105: case 106: case 107: // Background colour high-intensity palette
+ value = CSI_ARG(args[argi]) - 100 + 8;
+ state->bg_index = value;
+ set_pen_col_ansi(state, VTERM_ATTR_BACKGROUND, value);
+ break;
+
+ default:
+ done = 0;
+ break;
+ }
+
+ if(!done)
+ {
+ DEBUG_LOG1("libvterm: Unhandled CSI SGR %lu\n", arg);
+ }
+
+ while(CSI_ARG_HAS_MORE(args[argi++]));
+ }
+}
+
+INTERNAL int vterm_state_getpen(VTermState *state, long args[], int argcount UNUSED)
+{
+ int argi = 0;
+
+ if(state->pen.bold)
+ args[argi++] = 1;
+
+ if(state->pen.italic)
+ args[argi++] = 3;
+
+ if(state->pen.underline == 1)
+ args[argi++] = 4;
+
+ if(state->pen.blink)
+ args[argi++] = 5;
+
+ if(state->pen.reverse)
+ args[argi++] = 7;
+
+ if(state->pen.strike)
+ args[argi++] = 9;
+
+ if(state->pen.font)
+ args[argi++] = 10 + state->pen.font;
+
+ if(state->pen.underline == 2)
+ args[argi++] = 21;
+
+ if(state->fg_index >= 0 && state->fg_index < 8)
+ args[argi++] = 30 + state->fg_index;
+ else if(state->fg_index >= 8 && state->fg_index < 16)
+ args[argi++] = 90 + state->fg_index - 8;
+ else if(state->fg_index >= 16 && state->fg_index < 256) {
+ args[argi++] = CSI_ARG_FLAG_MORE|38;
+ args[argi++] = CSI_ARG_FLAG_MORE|5;
+ args[argi++] = state->fg_index;
+ }
+ else if(state->fg_index == -1) {
+ // Send palette 2 if the actual FG colour is not default
+ if(state->pen.fg.red != state->default_fg.red ||
+ state->pen.fg.green != state->default_fg.green ||
+ state->pen.fg.blue != state->default_fg.blue ) {
+ args[argi++] = CSI_ARG_FLAG_MORE|38;
+ args[argi++] = CSI_ARG_FLAG_MORE|2;
+ args[argi++] = CSI_ARG_FLAG_MORE | state->pen.fg.red;
+ args[argi++] = CSI_ARG_FLAG_MORE | state->pen.fg.green;
+ args[argi++] = state->pen.fg.blue;
+ }
+ }
+
+ if(state->bg_index >= 0 && state->bg_index < 8)
+ args[argi++] = 40 + state->bg_index;
+ else if(state->bg_index >= 8 && state->bg_index < 16)
+ args[argi++] = 100 + state->bg_index - 8;
+ else if(state->bg_index >= 16 && state->bg_index < 256) {
+ args[argi++] = CSI_ARG_FLAG_MORE|48;
+ args[argi++] = CSI_ARG_FLAG_MORE|5;
+ args[argi++] = state->bg_index;
+ }
+ else if(state->bg_index == -1) {
+ // Send palette 2 if the actual BG colour is not default
+ if(state->pen.bg.red != state->default_bg.red ||
+ state->pen.bg.green != state->default_bg.green ||
+ state->pen.bg.blue != state->default_bg.blue ) {
+ args[argi++] = CSI_ARG_FLAG_MORE|48;
+ args[argi++] = CSI_ARG_FLAG_MORE|2;
+ args[argi++] = CSI_ARG_FLAG_MORE | state->pen.bg.red;
+ args[argi++] = CSI_ARG_FLAG_MORE | state->pen.bg.green;
+ args[argi++] = state->pen.bg.blue;
+ }
+ }
+
+ return argi;
+}
+
+int vterm_state_get_penattr(const VTermState *state, VTermAttr attr, VTermValue *val)
+{
+ switch(attr) {
+ case VTERM_ATTR_BOLD:
+ val->boolean = state->pen.bold;
+ return 1;
+
+ case VTERM_ATTR_UNDERLINE:
+ val->number = state->pen.underline;
+ return 1;
+
+ case VTERM_ATTR_ITALIC:
+ val->boolean = state->pen.italic;
+ return 1;
+
+ case VTERM_ATTR_BLINK:
+ val->boolean = state->pen.blink;
+ return 1;
+
+ case VTERM_ATTR_REVERSE:
+ val->boolean = state->pen.reverse;
+ return 1;
+
+ case VTERM_ATTR_STRIKE:
+ val->boolean = state->pen.strike;
+ return 1;
+
+ case VTERM_ATTR_FONT:
+ val->number = state->pen.font;
+ return 1;
+
+ case VTERM_ATTR_FOREGROUND:
+ val->color = state->pen.fg;
+ return 1;
+
+ case VTERM_ATTR_BACKGROUND:
+ val->color = state->pen.bg;
+ return 1;
+
+ case VTERM_N_ATTRS:
+ return 0;
+ }
+
+ return 0;
+}
diff --git a/src/libvterm/src/rect.h b/src/libvterm/src/rect.h
new file mode 100644
index 0000000..2114f24
--- /dev/null
+++ b/src/libvterm/src/rect.h
@@ -0,0 +1,56 @@
+/*
+ * Some utility functions on VTermRect structures
+ */
+
+#define STRFrect "(%d,%d-%d,%d)"
+#define ARGSrect(r) (r).start_row, (r).start_col, (r).end_row, (r).end_col
+
+/* Expand dst to contain src as well */
+static void rect_expand(VTermRect *dst, VTermRect *src)
+{
+ if(dst->start_row > src->start_row) dst->start_row = src->start_row;
+ if(dst->start_col > src->start_col) dst->start_col = src->start_col;
+ if(dst->end_row < src->end_row) dst->end_row = src->end_row;
+ if(dst->end_col < src->end_col) dst->end_col = src->end_col;
+}
+
+/* Clip the dst to ensure it does not step outside of bounds */
+static void rect_clip(VTermRect *dst, VTermRect *bounds)
+{
+ if(dst->start_row < bounds->start_row) dst->start_row = bounds->start_row;
+ if(dst->start_col < bounds->start_col) dst->start_col = bounds->start_col;
+ if(dst->end_row > bounds->end_row) dst->end_row = bounds->end_row;
+ if(dst->end_col > bounds->end_col) dst->end_col = bounds->end_col;
+ /* Ensure it doesn't end up negatively-sized */
+ if(dst->end_row < dst->start_row) dst->end_row = dst->start_row;
+ if(dst->end_col < dst->start_col) dst->end_col = dst->start_col;
+}
+
+/* True if the two rectangles are equal */
+static int rect_equal(VTermRect *a, VTermRect *b)
+{
+ return (a->start_row == b->start_row) &&
+ (a->start_col == b->start_col) &&
+ (a->end_row == b->end_row) &&
+ (a->end_col == b->end_col);
+}
+
+/* True if small is contained entirely within big */
+static int rect_contains(VTermRect *big, VTermRect *small)
+{
+ if(small->start_row < big->start_row) return 0;
+ if(small->start_col < big->start_col) return 0;
+ if(small->end_row > big->end_row) return 0;
+ if(small->end_col > big->end_col) return 0;
+ return 1;
+}
+
+/* True if the rectangles overlap at all */
+static int rect_intersects(VTermRect *a, VTermRect *b)
+{
+ if(a->start_row > b->end_row || b->start_row > a->end_row)
+ return 0;
+ if(a->start_col > b->end_col || b->start_col > a->end_col)
+ return 0;
+ return 1;
+}
diff --git a/src/libvterm/src/state.c b/src/libvterm/src/state.c
new file mode 100644
index 0000000..8b02093
--- /dev/null
+++ b/src/libvterm/src/state.c
@@ -0,0 +1,1925 @@
+#include "vterm_internal.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#define strneq(a,b,n) (strncmp(a,b,n)==0)
+
+#if defined(DEBUG) && DEBUG > 1
+# define DEBUG_GLYPH_COMBINE
+#endif
+
+static int on_resize(int rows, int cols, void *user);
+
+/* Some convenient wrappers to make callback functions easier */
+
+static void putglyph(VTermState *state, const uint32_t chars[], int width, VTermPos pos)
+{
+ VTermGlyphInfo info;
+ info.chars = chars;
+ info.width = width;
+ info.protected_cell = state->protected_cell;
+ info.dwl = state->lineinfo[pos.row].doublewidth;
+ info.dhl = state->lineinfo[pos.row].doubleheight;
+
+ if(state->callbacks && state->callbacks->putglyph)
+ if((*state->callbacks->putglyph)(&info, pos, state->cbdata))
+ return;
+
+ DEBUG_LOG3("libvterm: Unhandled putglyph U+%04x at (%d,%d)\n", chars[0], pos.col, pos.row);
+}
+
+static void updatecursor(VTermState *state, VTermPos *oldpos, int cancel_phantom)
+{
+ if(state->pos.col == oldpos->col && state->pos.row == oldpos->row)
+ return;
+
+ if(cancel_phantom)
+ state->at_phantom = 0;
+
+ if(state->callbacks && state->callbacks->movecursor)
+ if((*state->callbacks->movecursor)(state->pos, *oldpos, state->mode.cursor_visible, state->cbdata))
+ return;
+}
+
+static void erase(VTermState *state, VTermRect rect, int selective)
+{
+ if(state->callbacks && state->callbacks->erase)
+ if((*state->callbacks->erase)(rect, selective, state->cbdata))
+ return;
+}
+
+static VTermState *vterm_state_new(VTerm *vt)
+{
+ VTermState *state = vterm_allocator_malloc(vt, sizeof(VTermState));
+
+ if (state == NULL)
+ return NULL;
+ state->vt = vt;
+
+ state->rows = vt->rows;
+ state->cols = vt->cols;
+
+ state->mouse_col = 0;
+ state->mouse_row = 0;
+ state->mouse_buttons = 0;
+
+ state->mouse_protocol = MOUSE_X10;
+
+ state->callbacks = NULL;
+ state->cbdata = NULL;
+
+ vterm_state_newpen(state);
+
+ state->bold_is_highbright = 0;
+
+ return state;
+}
+
+INTERNAL void vterm_state_free(VTermState *state)
+{
+ vterm_allocator_free(state->vt, state->tabstops);
+ vterm_allocator_free(state->vt, state->lineinfo);
+ vterm_allocator_free(state->vt, state->combine_chars);
+ vterm_allocator_free(state->vt, state);
+}
+
+static void scroll(VTermState *state, VTermRect rect, int downward, int rightward)
+{
+ int rows;
+ int cols;
+ if(!downward && !rightward)
+ return;
+
+ rows = rect.end_row - rect.start_row;
+ if(downward > rows)
+ downward = rows;
+ else if(downward < -rows)
+ downward = -rows;
+
+ cols = rect.end_col - rect.start_col;
+ if(rightward > cols)
+ rightward = cols;
+ else if(rightward < -cols)
+ rightward = -cols;
+
+ // Update lineinfo if full line
+ if(rect.start_col == 0 && rect.end_col == state->cols && rightward == 0) {
+ int height = rect.end_row - rect.start_row - abs(downward);
+
+ if(downward > 0)
+ memmove(state->lineinfo + rect.start_row,
+ state->lineinfo + rect.start_row + downward,
+ height * sizeof(state->lineinfo[0]));
+ else
+ memmove(state->lineinfo + rect.start_row - downward,
+ state->lineinfo + rect.start_row,
+ height * sizeof(state->lineinfo[0]));
+ }
+
+ if(state->callbacks && state->callbacks->scrollrect)
+ if((*state->callbacks->scrollrect)(rect, downward, rightward, state->cbdata))
+ return;
+
+ if(state->callbacks)
+ vterm_scroll_rect(rect, downward, rightward,
+ state->callbacks->moverect, state->callbacks->erase, state->cbdata);
+}
+
+static void linefeed(VTermState *state)
+{
+ if(state->pos.row == SCROLLREGION_BOTTOM(state) - 1) {
+ VTermRect rect;
+ rect.start_row = state->scrollregion_top;
+ rect.end_row = SCROLLREGION_BOTTOM(state);
+ rect.start_col = SCROLLREGION_LEFT(state);
+ rect.end_col = SCROLLREGION_RIGHT(state);
+
+ scroll(state, rect, 1, 0);
+ }
+ else if(state->pos.row < state->rows-1)
+ state->pos.row++;
+}
+
+static void grow_combine_buffer(VTermState *state)
+{
+ size_t new_size = state->combine_chars_size * 2;
+ uint32_t *new_chars = vterm_allocator_malloc(state->vt, new_size * sizeof(new_chars[0]));
+
+ memcpy(new_chars, state->combine_chars, state->combine_chars_size * sizeof(new_chars[0]));
+
+ vterm_allocator_free(state->vt, state->combine_chars);
+
+ state->combine_chars = new_chars;
+ state->combine_chars_size = new_size;
+}
+
+static void set_col_tabstop(VTermState *state, int col)
+{
+ unsigned char mask = 1 << (col & 7);
+ state->tabstops[col >> 3] |= mask;
+}
+
+static void clear_col_tabstop(VTermState *state, int col)
+{
+ unsigned char mask = 1 << (col & 7);
+ state->tabstops[col >> 3] &= ~mask;
+}
+
+static int is_col_tabstop(VTermState *state, int col)
+{
+ unsigned char mask = 1 << (col & 7);
+ return state->tabstops[col >> 3] & mask;
+}
+
+static int is_cursor_in_scrollregion(const VTermState *state)
+{
+ if(state->pos.row < state->scrollregion_top ||
+ state->pos.row >= SCROLLREGION_BOTTOM(state))
+ return 0;
+ if(state->pos.col < SCROLLREGION_LEFT(state) ||
+ state->pos.col >= SCROLLREGION_RIGHT(state))
+ return 0;
+
+ return 1;
+}
+
+static void tab(VTermState *state, int count, int direction)
+{
+ while(count > 0) {
+ if(direction > 0) {
+ if(state->pos.col >= THISROWWIDTH(state)-1)
+ return;
+
+ state->pos.col++;
+ }
+ else if(direction < 0) {
+ if(state->pos.col < 1)
+ return;
+
+ state->pos.col--;
+ }
+
+ if(is_col_tabstop(state, state->pos.col))
+ count--;
+ }
+}
+
+#define NO_FORCE 0
+#define FORCE 1
+
+#define DWL_OFF 0
+#define DWL_ON 1
+
+#define DHL_OFF 0
+#define DHL_TOP 1
+#define DHL_BOTTOM 2
+
+static void set_lineinfo(VTermState *state, int row, int force, int dwl, int dhl)
+{
+ VTermLineInfo info = state->lineinfo[row];
+
+ if(dwl == DWL_OFF)
+ info.doublewidth = DWL_OFF;
+ else if(dwl == DWL_ON)
+ info.doublewidth = DWL_ON;
+ // else -1 to ignore
+
+ if(dhl == DHL_OFF)
+ info.doubleheight = DHL_OFF;
+ else if(dhl == DHL_TOP)
+ info.doubleheight = DHL_TOP;
+ else if(dhl == DHL_BOTTOM)
+ info.doubleheight = DHL_BOTTOM;
+
+ if((state->callbacks &&
+ state->callbacks->setlineinfo &&
+ (*state->callbacks->setlineinfo)(row, &info, state->lineinfo + row, state->cbdata))
+ || force)
+ state->lineinfo[row] = info;
+}
+
+static int on_text(const char bytes[], size_t len, void *user)
+{
+ VTermState *state = user;
+ uint32_t *codepoints;
+ int npoints = 0;
+ size_t eaten = 0;
+ VTermEncodingInstance *encoding;
+ int i = 0;
+
+ VTermPos oldpos = state->pos;
+
+ // We'll have at most len codepoints, plus one from a previous incomplete
+ // sequence.
+ codepoints = vterm_allocator_malloc(state->vt, (len + 1) * sizeof(uint32_t));
+
+ encoding =
+ state->gsingle_set ? &state->encoding[state->gsingle_set] :
+ !(bytes[eaten] & 0x80) ? &state->encoding[state->gl_set] :
+ state->vt->mode.utf8 ? &state->encoding_utf8 :
+ &state->encoding[state->gr_set];
+
+ (*encoding->enc->decode)(encoding->enc, encoding->data,
+ codepoints, &npoints, state->gsingle_set ? 1 : (int)len,
+ bytes, &eaten, len);
+
+ /* There's a chance an encoding (e.g. UTF-8) hasn't found enough bytes yet
+ * for even a single codepoint
+ */
+ if(!npoints)
+ {
+ vterm_allocator_free(state->vt, codepoints);
+ return (int)eaten;
+ }
+
+ if(state->gsingle_set && npoints)
+ state->gsingle_set = 0;
+
+ /* This is a combining char. that needs to be merged with the previous
+ * glyph output */
+ if(vterm_unicode_is_combining(codepoints[i])) {
+ /* See if the cursor has moved since */
+ if(state->pos.row == state->combine_pos.row && state->pos.col == state->combine_pos.col + state->combine_width) {
+#ifdef DEBUG_GLYPH_COMBINE
+ int printpos;
+ printf("DEBUG: COMBINING SPLIT GLYPH of chars {");
+ for(printpos = 0; state->combine_chars[printpos]; printpos++)
+ printf("U+%04x ", state->combine_chars[printpos]);
+ printf("} + {");
+#endif
+
+ /* Find where we need to append these combining chars */
+ int saved_i = 0;
+ while(state->combine_chars[saved_i])
+ saved_i++;
+
+ /* Add extra ones */
+ while(i < npoints && vterm_unicode_is_combining(codepoints[i])) {
+ if(saved_i >= (int)state->combine_chars_size)
+ grow_combine_buffer(state);
+ state->combine_chars[saved_i++] = codepoints[i++];
+ }
+ if(saved_i >= (int)state->combine_chars_size)
+ grow_combine_buffer(state);
+ state->combine_chars[saved_i] = 0;
+
+#ifdef DEBUG_GLYPH_COMBINE
+ for(; state->combine_chars[printpos]; printpos++)
+ printf("U+%04x ", state->combine_chars[printpos]);
+ printf("}\n");
+#endif
+
+ /* Now render it */
+ putglyph(state, state->combine_chars, state->combine_width, state->combine_pos);
+ }
+ else {
+ DEBUG_LOG("libvterm: TODO: Skip over split char+combining\n");
+ }
+ }
+
+ for(; i < npoints; i++) {
+ // Try to find combining characters following this
+ int glyph_starts = i;
+ int glyph_ends;
+ int width = 0;
+ uint32_t *chars;
+
+ for(glyph_ends = i + 1; glyph_ends < npoints; glyph_ends++)
+ if(!vterm_unicode_is_combining(codepoints[glyph_ends]))
+ break;
+
+ chars = vterm_allocator_malloc(state->vt, (glyph_ends - glyph_starts + 1) * sizeof(uint32_t));
+
+ for( ; i < glyph_ends; i++) {
+ int this_width;
+ chars[i - glyph_starts] = codepoints[i];
+ this_width = vterm_unicode_width(codepoints[i]);
+#ifdef DEBUG
+ if(this_width < 0) {
+ fprintf(stderr, "Text with negative-width codepoint U+%04x\n", codepoints[i]);
+ abort();
+ }
+#endif
+ width += this_width;
+ }
+
+ chars[glyph_ends - glyph_starts] = 0;
+ i--;
+
+#ifdef DEBUG_GLYPH_COMBINE
+ int printpos;
+ printf("DEBUG: COMBINED GLYPH of %d chars {", glyph_ends - glyph_starts);
+ for(printpos = 0; printpos < glyph_ends - glyph_starts; printpos++)
+ printf("U+%04x ", chars[printpos]);
+ printf("}, onscreen width %d\n", width);
+#endif
+
+ if(state->at_phantom || state->pos.col + width > THISROWWIDTH(state)) {
+ linefeed(state);
+ state->pos.col = 0;
+ state->at_phantom = 0;
+ }
+
+ if(state->mode.insert) {
+ /* TODO: This will be a little inefficient for large bodies of text, as
+ * it'll have to 'ICH' effectively before every glyph. We should scan
+ * ahead and ICH as many times as required
+ */
+ VTermRect rect;
+ rect.start_row = state->pos.row;
+ rect.end_row = state->pos.row + 1;
+ rect.start_col = state->pos.col;
+ rect.end_col = THISROWWIDTH(state);
+ scroll(state, rect, 0, -1);
+ }
+
+ putglyph(state, chars, width, state->pos);
+
+ if(i == npoints - 1) {
+ /* End of the buffer. Save the chars in case we have to combine with
+ * more on the next call */
+ int save_i;
+ for(save_i = 0; chars[save_i]; save_i++) {
+ if(save_i >= (int)state->combine_chars_size)
+ grow_combine_buffer(state);
+ state->combine_chars[save_i] = chars[save_i];
+ }
+ if(save_i >= (int)state->combine_chars_size)
+ grow_combine_buffer(state);
+ state->combine_chars[save_i] = 0;
+ state->combine_width = width;
+ state->combine_pos = state->pos;
+ }
+
+ if(state->pos.col + width >= THISROWWIDTH(state)) {
+ if(state->mode.autowrap)
+ state->at_phantom = 1;
+ }
+ else {
+ state->pos.col += width;
+ }
+ vterm_allocator_free(state->vt, chars);
+ }
+
+ updatecursor(state, &oldpos, 0);
+
+#ifdef DEBUG
+ if(state->pos.row < 0 || state->pos.row >= state->rows ||
+ state->pos.col < 0 || state->pos.col >= state->cols) {
+ fprintf(stderr, "Position out of bounds after text: (%d,%d)\n",
+ state->pos.row, state->pos.col);
+ abort();
+ }
+#endif
+
+ vterm_allocator_free(state->vt, codepoints);
+ return (int)eaten;
+}
+
+static int on_control(unsigned char control, void *user)
+{
+ VTermState *state = user;
+
+ VTermPos oldpos = state->pos;
+
+ switch(control) {
+ case 0x07: // BEL - ECMA-48 8.3.3
+ if(state->callbacks && state->callbacks->bell)
+ (*state->callbacks->bell)(state->cbdata);
+ break;
+
+ case 0x08: // BS - ECMA-48 8.3.5
+ if(state->pos.col > 0)
+ state->pos.col--;
+ break;
+
+ case 0x09: // HT - ECMA-48 8.3.60
+ tab(state, 1, +1);
+ break;
+
+ case 0x0a: // LF - ECMA-48 8.3.74
+ case 0x0b: // VT
+ case 0x0c: // FF
+ linefeed(state);
+ if(state->mode.newline)
+ state->pos.col = 0;
+ break;
+
+ case 0x0d: // CR - ECMA-48 8.3.15
+ state->pos.col = 0;
+ break;
+
+ case 0x0e: // LS1 - ECMA-48 8.3.76
+ state->gl_set = 1;
+ break;
+
+ case 0x0f: // LS0 - ECMA-48 8.3.75
+ state->gl_set = 0;
+ break;
+
+ case 0x84: // IND - DEPRECATED but implemented for completeness
+ linefeed(state);
+ break;
+
+ case 0x85: // NEL - ECMA-48 8.3.86
+ linefeed(state);
+ state->pos.col = 0;
+ break;
+
+ case 0x88: // HTS - ECMA-48 8.3.62
+ set_col_tabstop(state, state->pos.col);
+ break;
+
+ case 0x8d: // RI - ECMA-48 8.3.104
+ if(state->pos.row == state->scrollregion_top) {
+ VTermRect rect;
+ rect.start_row = state->scrollregion_top;
+ rect.end_row = SCROLLREGION_BOTTOM(state);
+ rect.start_col = SCROLLREGION_LEFT(state);
+ rect.end_col = SCROLLREGION_RIGHT(state);
+
+ scroll(state, rect, -1, 0);
+ }
+ else if(state->pos.row > 0)
+ state->pos.row--;
+ break;
+
+ case 0x8e: // SS2 - ECMA-48 8.3.141
+ state->gsingle_set = 2;
+ break;
+
+ case 0x8f: // SS3 - ECMA-48 8.3.142
+ state->gsingle_set = 3;
+ break;
+
+ default:
+ if(state->fallbacks && state->fallbacks->control)
+ if((*state->fallbacks->control)(control, state->fbdata))
+ return 1;
+
+ return 0;
+ }
+
+ updatecursor(state, &oldpos, 1);
+
+#ifdef DEBUG
+ if(state->pos.row < 0 || state->pos.row >= state->rows ||
+ state->pos.col < 0 || state->pos.col >= state->cols) {
+ fprintf(stderr, "Position out of bounds after Ctrl %02x: (%d,%d)\n",
+ control, state->pos.row, state->pos.col);
+ abort();
+ }
+#endif
+
+ return 1;
+}
+
+static int settermprop_bool(VTermState *state, VTermProp prop, int v)
+{
+ VTermValue val;
+ val.boolean = v;
+ return vterm_state_set_termprop(state, prop, &val);
+}
+
+static int settermprop_int(VTermState *state, VTermProp prop, int v)
+{
+ VTermValue val;
+ val.number = v;
+ return vterm_state_set_termprop(state, prop, &val);
+}
+
+static int settermprop_string(VTermState *state, VTermProp prop, const char *str, size_t len)
+{
+ char *strvalue;
+ int r;
+ VTermValue val;
+ strvalue = vterm_allocator_malloc(state->vt, (len+1) * sizeof(char));
+ strncpy(strvalue, str, len);
+ strvalue[len] = 0;
+
+ val.string = strvalue;
+ r = vterm_state_set_termprop(state, prop, &val);
+ vterm_allocator_free(state->vt, strvalue);
+ return r;
+}
+
+static void savecursor(VTermState *state, int save)
+{
+ if(save) {
+ state->saved.pos = state->pos;
+ state->saved.mode.cursor_visible = state->mode.cursor_visible;
+ state->saved.mode.cursor_blink = state->mode.cursor_blink;
+ state->saved.mode.cursor_shape = state->mode.cursor_shape;
+
+ vterm_state_savepen(state, 1);
+ }
+ else {
+ VTermPos oldpos = state->pos;
+
+ state->pos = state->saved.pos;
+
+ settermprop_bool(state, VTERM_PROP_CURSORVISIBLE, state->saved.mode.cursor_visible);
+ settermprop_bool(state, VTERM_PROP_CURSORBLINK, state->saved.mode.cursor_blink);
+ settermprop_int (state, VTERM_PROP_CURSORSHAPE, state->saved.mode.cursor_shape);
+
+ vterm_state_savepen(state, 0);
+
+ updatecursor(state, &oldpos, 1);
+ }
+}
+
+static int on_escape(const char *bytes, size_t len, void *user)
+{
+ VTermState *state = user;
+
+ /* Easier to decode this from the first byte, even though the final
+ * byte terminates it
+ */
+ switch(bytes[0]) {
+ case ' ':
+ if(len != 2)
+ return 0;
+
+ switch(bytes[1]) {
+ case 'F': // S7C1T
+ state->vt->mode.ctrl8bit = 0;
+ break;
+
+ case 'G': // S8C1T
+ state->vt->mode.ctrl8bit = 1;
+ break;
+
+ default:
+ return 0;
+ }
+ return 2;
+
+ case '#':
+ if(len != 2)
+ return 0;
+
+ switch(bytes[1]) {
+ case '3': // DECDHL top
+ if(state->mode.leftrightmargin)
+ break;
+ set_lineinfo(state, state->pos.row, NO_FORCE, DWL_ON, DHL_TOP);
+ break;
+
+ case '4': // DECDHL bottom
+ if(state->mode.leftrightmargin)
+ break;
+ set_lineinfo(state, state->pos.row, NO_FORCE, DWL_ON, DHL_BOTTOM);
+ break;
+
+ case '5': // DECSWL
+ if(state->mode.leftrightmargin)
+ break;
+ set_lineinfo(state, state->pos.row, NO_FORCE, DWL_OFF, DHL_OFF);
+ break;
+
+ case '6': // DECDWL
+ if(state->mode.leftrightmargin)
+ break;
+ set_lineinfo(state, state->pos.row, NO_FORCE, DWL_ON, DHL_OFF);
+ break;
+
+ case '8': // DECALN
+ {
+ VTermPos pos;
+ uint32_t E[] = { 'E', 0 };
+ for(pos.row = 0; pos.row < state->rows; pos.row++)
+ for(pos.col = 0; pos.col < ROWWIDTH(state, pos.row); pos.col++)
+ putglyph(state, E, 1, pos);
+ break;
+ }
+
+ default:
+ return 0;
+ }
+ return 2;
+
+ case '(': case ')': case '*': case '+': // SCS
+ if(len != 2)
+ return 0;
+
+ {
+ int setnum = bytes[0] - 0x28;
+ VTermEncoding *newenc = vterm_lookup_encoding(ENC_SINGLE_94, bytes[1]);
+
+ if(newenc) {
+ state->encoding[setnum].enc = newenc;
+
+ if(newenc->init)
+ (*newenc->init)(newenc, state->encoding[setnum].data);
+ }
+ }
+
+ return 2;
+
+ case '7': // DECSC
+ savecursor(state, 1);
+ return 1;
+
+ case '8': // DECRC
+ savecursor(state, 0);
+ return 1;
+
+ case '<': // Ignored by VT100. Used in VT52 mode to switch up to VT100
+ return 1;
+
+ case '=': // DECKPAM
+ state->mode.keypad = 1;
+ return 1;
+
+ case '>': // DECKPNM
+ state->mode.keypad = 0;
+ return 1;
+
+ case 'c': // RIS - ECMA-48 8.3.105
+ {
+ VTermPos oldpos = state->pos;
+ vterm_state_reset(state, 1);
+ if(state->callbacks && state->callbacks->movecursor)
+ (*state->callbacks->movecursor)(state->pos, oldpos, state->mode.cursor_visible, state->cbdata);
+ return 1;
+ }
+
+ case 'n': // LS2 - ECMA-48 8.3.78
+ state->gl_set = 2;
+ return 1;
+
+ case 'o': // LS3 - ECMA-48 8.3.80
+ state->gl_set = 3;
+ return 1;
+
+ case '~': // LS1R - ECMA-48 8.3.77
+ state->gr_set = 1;
+ return 1;
+
+ case '}': // LS2R - ECMA-48 8.3.79
+ state->gr_set = 2;
+ return 1;
+
+ case '|': // LS3R - ECMA-48 8.3.81
+ state->gr_set = 3;
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+static void set_mode(VTermState *state, int num, int val)
+{
+ switch(num) {
+ case 4: // IRM - ECMA-48 7.2.10
+ state->mode.insert = val;
+ break;
+
+ case 20: // LNM - ANSI X3.4-1977
+ state->mode.newline = val;
+ break;
+
+ default:
+ DEBUG_LOG1("libvterm: Unknown mode %d\n", num);
+ return;
+ }
+}
+
+static void set_dec_mode(VTermState *state, int num, int val)
+{
+ switch(num) {
+ case 1:
+ state->mode.cursor = val;
+ break;
+
+ case 5: // DECSCNM - screen mode
+ settermprop_bool(state, VTERM_PROP_REVERSE, val);
+ break;
+
+ case 6: // DECOM - origin mode
+ {
+ VTermPos oldpos = state->pos;
+ state->mode.origin = val;
+ state->pos.row = state->mode.origin ? state->scrollregion_top : 0;
+ state->pos.col = state->mode.origin ? SCROLLREGION_LEFT(state) : 0;
+ updatecursor(state, &oldpos, 1);
+ }
+ break;
+
+ case 7:
+ state->mode.autowrap = val;
+ break;
+
+ case 12:
+ settermprop_bool(state, VTERM_PROP_CURSORBLINK, val);
+ break;
+
+ case 25:
+ settermprop_bool(state, VTERM_PROP_CURSORVISIBLE, val);
+ break;
+
+ case 69: // DECVSSM - vertical split screen mode
+ // DECLRMM - left/right margin mode
+ state->mode.leftrightmargin = val;
+ if(val) {
+ int row;
+
+ // Setting DECVSSM must clear doublewidth/doubleheight state of every line
+ for(row = 0; row < state->rows; row++)
+ set_lineinfo(state, row, FORCE, DWL_OFF, DHL_OFF);
+ }
+
+ break;
+
+ case 1000:
+ case 1002:
+ case 1003:
+ settermprop_int(state, VTERM_PROP_MOUSE,
+ !val ? VTERM_PROP_MOUSE_NONE :
+ (num == 1000) ? VTERM_PROP_MOUSE_CLICK :
+ (num == 1002) ? VTERM_PROP_MOUSE_DRAG :
+ VTERM_PROP_MOUSE_MOVE);
+ break;
+
+ case 1004:
+ state->mode.report_focus = val;
+ break;
+
+ case 1005:
+ state->mouse_protocol = val ? MOUSE_UTF8 : MOUSE_X10;
+ break;
+
+ case 1006:
+ state->mouse_protocol = val ? MOUSE_SGR : MOUSE_X10;
+ break;
+
+ case 1015:
+ state->mouse_protocol = val ? MOUSE_RXVT : MOUSE_X10;
+ break;
+
+ case 1047:
+ settermprop_bool(state, VTERM_PROP_ALTSCREEN, val);
+ break;
+
+ case 1048:
+ savecursor(state, val);
+ break;
+
+ case 1049:
+ settermprop_bool(state, VTERM_PROP_ALTSCREEN, val);
+ savecursor(state, val);
+ break;
+
+ case 2004:
+ state->mode.bracketpaste = val;
+ break;
+
+ default:
+ DEBUG_LOG1("libvterm: Unknown DEC mode %d\n", num);
+ return;
+ }
+}
+
+static void request_dec_mode(VTermState *state, int num)
+{
+ int reply;
+
+ switch(num) {
+ case 1:
+ reply = state->mode.cursor;
+ break;
+
+ case 5:
+ reply = state->mode.screen;
+ break;
+
+ case 6:
+ reply = state->mode.origin;
+ break;
+
+ case 7:
+ reply = state->mode.autowrap;
+ break;
+
+ case 12:
+ reply = state->mode.cursor_blink;
+ break;
+
+ case 25:
+ reply = state->mode.cursor_visible;
+ break;
+
+ case 69:
+ reply = state->mode.leftrightmargin;
+ break;
+
+ case 1000:
+ reply = state->mouse_flags == MOUSE_WANT_CLICK;
+ break;
+
+ case 1002:
+ reply = state->mouse_flags == (MOUSE_WANT_CLICK|MOUSE_WANT_DRAG);
+ break;
+
+ case 1003:
+ reply = state->mouse_flags == (MOUSE_WANT_CLICK|MOUSE_WANT_MOVE);
+ break;
+
+ case 1004:
+ reply = state->mode.report_focus;
+ break;
+
+ case 1005:
+ reply = state->mouse_protocol == MOUSE_UTF8;
+ break;
+
+ case 1006:
+ reply = state->mouse_protocol == MOUSE_SGR;
+ break;
+
+ case 1015:
+ reply = state->mouse_protocol == MOUSE_RXVT;
+ break;
+
+ case 1047:
+ reply = state->mode.alt_screen;
+ break;
+
+ case 2004:
+ reply = state->mode.bracketpaste;
+ break;
+
+ default:
+ vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "?%d;%d$y", num, 0);
+ return;
+ }
+
+ vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "?%d;%d$y", num, reply ? 1 : 2);
+}
+
+static int on_csi(const char *leader, const long args[], int argcount, const char *intermed, char command, void *user)
+{
+ VTermState *state = user;
+ int leader_byte = 0;
+ int intermed_byte = 0;
+ VTermPos oldpos = state->pos;
+
+ /* Some temporaries for later code */
+ int count, val;
+ int row, col;
+ VTermRect rect;
+ int selective;
+
+ if(leader && leader[0]) {
+ if(leader[1]) // longer than 1 char
+ return 0;
+
+ switch(leader[0]) {
+ case '?':
+ case '>':
+ leader_byte = leader[0];
+ break;
+ default:
+ return 0;
+ }
+ }
+
+ if(intermed && intermed[0]) {
+ if(intermed[1]) // longer than 1 char
+ return 0;
+
+ switch(intermed[0]) {
+ case ' ':
+ case '"':
+ case '$':
+ case '\'':
+ intermed_byte = intermed[0];
+ break;
+ default:
+ return 0;
+ }
+ }
+
+ oldpos = state->pos;
+
+#define LBOUND(v,min) if((v) < (min)) (v) = (min)
+#define UBOUND(v,max) if((v) > (max)) (v) = (max)
+
+#define LEADER(l,b) ((l << 8) | b)
+#define INTERMED(i,b) ((i << 16) | b)
+
+ switch(intermed_byte << 16 | leader_byte << 8 | command) {
+ case 0x40: // ICH - ECMA-48 8.3.64
+ count = CSI_ARG_COUNT(args[0]);
+
+ if(!is_cursor_in_scrollregion(state))
+ break;
+
+ rect.start_row = state->pos.row;
+ rect.end_row = state->pos.row + 1;
+ rect.start_col = state->pos.col;
+ if(state->mode.leftrightmargin)
+ rect.end_col = SCROLLREGION_RIGHT(state);
+ else
+ rect.end_col = THISROWWIDTH(state);
+
+ scroll(state, rect, 0, -count);
+
+ break;
+
+ case 0x41: // CUU - ECMA-48 8.3.22
+ count = CSI_ARG_COUNT(args[0]);
+ state->pos.row -= count;
+ state->at_phantom = 0;
+ break;
+
+ case 0x42: // CUD - ECMA-48 8.3.19
+ count = CSI_ARG_COUNT(args[0]);
+ state->pos.row += count;
+ state->at_phantom = 0;
+ break;
+
+ case 0x43: // CUF - ECMA-48 8.3.20
+ count = CSI_ARG_COUNT(args[0]);
+ state->pos.col += count;
+ state->at_phantom = 0;
+ break;
+
+ case 0x44: // CUB - ECMA-48 8.3.18
+ count = CSI_ARG_COUNT(args[0]);
+ state->pos.col -= count;
+ state->at_phantom = 0;
+ break;
+
+ case 0x45: // CNL - ECMA-48 8.3.12
+ count = CSI_ARG_COUNT(args[0]);
+ state->pos.col = 0;
+ state->pos.row += count;
+ state->at_phantom = 0;
+ break;
+
+ case 0x46: // CPL - ECMA-48 8.3.13
+ count = CSI_ARG_COUNT(args[0]);
+ state->pos.col = 0;
+ state->pos.row -= count;
+ state->at_phantom = 0;
+ break;
+
+ case 0x47: // CHA - ECMA-48 8.3.9
+ val = CSI_ARG_OR(args[0], 1);
+ state->pos.col = val-1;
+ state->at_phantom = 0;
+ break;
+
+ case 0x48: // CUP - ECMA-48 8.3.21
+ row = CSI_ARG_OR(args[0], 1);
+ col = argcount < 2 || CSI_ARG_IS_MISSING(args[1]) ? 1 : CSI_ARG(args[1]);
+ // zero-based
+ state->pos.row = row-1;
+ state->pos.col = col-1;
+ if(state->mode.origin) {
+ state->pos.row += state->scrollregion_top;
+ state->pos.col += SCROLLREGION_LEFT(state);
+ }
+ state->at_phantom = 0;
+ break;
+
+ case 0x49: // CHT - ECMA-48 8.3.10
+ count = CSI_ARG_COUNT(args[0]);
+ tab(state, count, +1);
+ break;
+
+ case 0x4a: // ED - ECMA-48 8.3.39
+ case LEADER('?', 0x4a): // DECSED - Selective Erase in Display
+ selective = (leader_byte == '?');
+ switch(CSI_ARG(args[0])) {
+ case CSI_ARG_MISSING:
+ case 0:
+ rect.start_row = state->pos.row; rect.end_row = state->pos.row + 1;
+ rect.start_col = state->pos.col; rect.end_col = state->cols;
+ if(rect.end_col > rect.start_col)
+ erase(state, rect, selective);
+
+ rect.start_row = state->pos.row + 1; rect.end_row = state->rows;
+ rect.start_col = 0;
+ for(row = rect.start_row; row < rect.end_row; row++)
+ set_lineinfo(state, row, FORCE, DWL_OFF, DHL_OFF);
+ if(rect.end_row > rect.start_row)
+ erase(state, rect, selective);
+ break;
+
+ case 1:
+ rect.start_row = 0; rect.end_row = state->pos.row;
+ rect.start_col = 0; rect.end_col = state->cols;
+ for(row = rect.start_row; row < rect.end_row; row++)
+ set_lineinfo(state, row, FORCE, DWL_OFF, DHL_OFF);
+ if(rect.end_col > rect.start_col)
+ erase(state, rect, selective);
+
+ rect.start_row = state->pos.row; rect.end_row = state->pos.row + 1;
+ rect.end_col = state->pos.col + 1;
+ if(rect.end_row > rect.start_row)
+ erase(state, rect, selective);
+ break;
+
+ case 2:
+ rect.start_row = 0; rect.end_row = state->rows;
+ rect.start_col = 0; rect.end_col = state->cols;
+ for(row = rect.start_row; row < rect.end_row; row++)
+ set_lineinfo(state, row, FORCE, DWL_OFF, DHL_OFF);
+ erase(state, rect, selective);
+ break;
+ }
+ break;
+
+ case 0x4b: // EL - ECMA-48 8.3.41
+ case LEADER('?', 0x4b): // DECSEL - Selective Erase in Line
+ selective = (leader_byte == '?');
+ rect.start_row = state->pos.row;
+ rect.end_row = state->pos.row + 1;
+
+ switch(CSI_ARG(args[0])) {
+ case CSI_ARG_MISSING:
+ case 0:
+ rect.start_col = state->pos.col; rect.end_col = THISROWWIDTH(state); break;
+ case 1:
+ rect.start_col = 0; rect.end_col = state->pos.col + 1; break;
+ case 2:
+ rect.start_col = 0; rect.end_col = THISROWWIDTH(state); break;
+ default:
+ return 0;
+ }
+
+ if(rect.end_col > rect.start_col)
+ erase(state, rect, selective);
+
+ break;
+
+ case 0x4c: // IL - ECMA-48 8.3.67
+ count = CSI_ARG_COUNT(args[0]);
+
+ if(!is_cursor_in_scrollregion(state))
+ break;
+
+ rect.start_row = state->pos.row;
+ rect.end_row = SCROLLREGION_BOTTOM(state);
+ rect.start_col = SCROLLREGION_LEFT(state);
+ rect.end_col = SCROLLREGION_RIGHT(state);
+
+ scroll(state, rect, -count, 0);
+
+ break;
+
+ case 0x4d: // DL - ECMA-48 8.3.32
+ count = CSI_ARG_COUNT(args[0]);
+
+ if(!is_cursor_in_scrollregion(state))
+ break;
+
+ rect.start_row = state->pos.row;
+ rect.end_row = SCROLLREGION_BOTTOM(state);
+ rect.start_col = SCROLLREGION_LEFT(state);
+ rect.end_col = SCROLLREGION_RIGHT(state);
+
+ scroll(state, rect, count, 0);
+
+ break;
+
+ case 0x50: // DCH - ECMA-48 8.3.26
+ count = CSI_ARG_COUNT(args[0]);
+
+ if(!is_cursor_in_scrollregion(state))
+ break;
+
+ rect.start_row = state->pos.row;
+ rect.end_row = state->pos.row + 1;
+ rect.start_col = state->pos.col;
+ if(state->mode.leftrightmargin)
+ rect.end_col = SCROLLREGION_RIGHT(state);
+ else
+ rect.end_col = THISROWWIDTH(state);
+
+ scroll(state, rect, 0, count);
+
+ break;
+
+ case 0x53: // SU - ECMA-48 8.3.147
+ count = CSI_ARG_COUNT(args[0]);
+
+ rect.start_row = state->scrollregion_top;
+ rect.end_row = SCROLLREGION_BOTTOM(state);
+ rect.start_col = SCROLLREGION_LEFT(state);
+ rect.end_col = SCROLLREGION_RIGHT(state);
+
+ scroll(state, rect, count, 0);
+
+ break;
+
+ case 0x54: // SD - ECMA-48 8.3.113
+ count = CSI_ARG_COUNT(args[0]);
+
+ rect.start_row = state->scrollregion_top;
+ rect.end_row = SCROLLREGION_BOTTOM(state);
+ rect.start_col = SCROLLREGION_LEFT(state);
+ rect.end_col = SCROLLREGION_RIGHT(state);
+
+ scroll(state, rect, -count, 0);
+
+ break;
+
+ case 0x58: // ECH - ECMA-48 8.3.38
+ count = CSI_ARG_COUNT(args[0]);
+
+ rect.start_row = state->pos.row;
+ rect.end_row = state->pos.row + 1;
+ rect.start_col = state->pos.col;
+ rect.end_col = state->pos.col + count;
+ UBOUND(rect.end_col, THISROWWIDTH(state));
+
+ erase(state, rect, 0);
+ break;
+
+ case 0x5a: // CBT - ECMA-48 8.3.7
+ count = CSI_ARG_COUNT(args[0]);
+ tab(state, count, -1);
+ break;
+
+ case 0x60: // HPA - ECMA-48 8.3.57
+ col = CSI_ARG_OR(args[0], 1);
+ state->pos.col = col-1;
+ state->at_phantom = 0;
+ break;
+
+ case 0x61: // HPR - ECMA-48 8.3.59
+ count = CSI_ARG_COUNT(args[0]);
+ state->pos.col += count;
+ state->at_phantom = 0;
+ break;
+
+ case 0x63: // DA - ECMA-48 8.3.24
+ val = CSI_ARG_OR(args[0], 0);
+ if(val == 0)
+ // DEC VT100 response
+ vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "?1;2c");
+ break;
+
+ case LEADER('>', 0x63): // DEC secondary Device Attributes
+ // This returns xterm version number 100.
+ vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, ">%d;%d;%dc", 0, 100, 0);
+ break;
+
+ case 0x64: // VPA - ECMA-48 8.3.158
+ row = CSI_ARG_OR(args[0], 1);
+ state->pos.row = row-1;
+ if(state->mode.origin)
+ state->pos.row += state->scrollregion_top;
+ state->at_phantom = 0;
+ break;
+
+ case 0x65: // VPR - ECMA-48 8.3.160
+ count = CSI_ARG_COUNT(args[0]);
+ state->pos.row += count;
+ state->at_phantom = 0;
+ break;
+
+ case 0x66: // HVP - ECMA-48 8.3.63
+ row = CSI_ARG_OR(args[0], 1);
+ col = argcount < 2 || CSI_ARG_IS_MISSING(args[1]) ? 1 : CSI_ARG(args[1]);
+ // zero-based
+ state->pos.row = row-1;
+ state->pos.col = col-1;
+ if(state->mode.origin) {
+ state->pos.row += state->scrollregion_top;
+ state->pos.col += SCROLLREGION_LEFT(state);
+ }
+ state->at_phantom = 0;
+ break;
+
+ case 0x67: // TBC - ECMA-48 8.3.154
+ val = CSI_ARG_OR(args[0], 0);
+
+ switch(val) {
+ case 0:
+ clear_col_tabstop(state, state->pos.col);
+ break;
+ case 3:
+ case 5:
+ for(col = 0; col < state->cols; col++)
+ clear_col_tabstop(state, col);
+ break;
+ case 1:
+ case 2:
+ case 4:
+ break;
+ /* TODO: 1, 2 and 4 aren't meaningful yet without line tab stops */
+ default:
+ return 0;
+ }
+ break;
+
+ case 0x68: // SM - ECMA-48 8.3.125
+ if(!CSI_ARG_IS_MISSING(args[0]))
+ set_mode(state, CSI_ARG(args[0]), 1);
+ break;
+
+ case LEADER('?', 0x68): // DEC private mode set
+ if(!CSI_ARG_IS_MISSING(args[0]))
+ set_dec_mode(state, CSI_ARG(args[0]), 1);
+ break;
+
+ case 0x6a: // HPB - ECMA-48 8.3.58
+ count = CSI_ARG_COUNT(args[0]);
+ state->pos.col -= count;
+ state->at_phantom = 0;
+ break;
+
+ case 0x6b: // VPB - ECMA-48 8.3.159
+ count = CSI_ARG_COUNT(args[0]);
+ state->pos.row -= count;
+ state->at_phantom = 0;
+ break;
+
+ case 0x6c: // RM - ECMA-48 8.3.106
+ if(!CSI_ARG_IS_MISSING(args[0]))
+ set_mode(state, CSI_ARG(args[0]), 0);
+ break;
+
+ case LEADER('?', 0x6c): // DEC private mode reset
+ if(!CSI_ARG_IS_MISSING(args[0]))
+ set_dec_mode(state, CSI_ARG(args[0]), 0);
+ break;
+
+ case 0x6d: // SGR - ECMA-48 8.3.117
+ vterm_state_setpen(state, args, argcount);
+ break;
+
+ case 0x6e: // DSR - ECMA-48 8.3.35
+ case LEADER('?', 0x6e): // DECDSR
+ val = CSI_ARG_OR(args[0], 0);
+
+ {
+ char *qmark = (leader_byte == '?') ? "?" : "";
+
+ switch(val) {
+ case 0: case 1: case 2: case 3: case 4:
+ // ignore - these are replies
+ break;
+ case 5:
+ vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "%s0n", qmark);
+ break;
+ case 6: // CPR - cursor position report
+ vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "%s%d;%dR", qmark, state->pos.row + 1, state->pos.col + 1);
+ break;
+ }
+ }
+ break;
+
+
+ case LEADER('!', 0x70): // DECSTR - DEC soft terminal reset
+ vterm_state_reset(state, 0);
+ break;
+
+ case LEADER('?', INTERMED('$', 0x70)):
+ request_dec_mode(state, CSI_ARG(args[0]));
+ break;
+
+ case INTERMED(' ', 0x71): // DECSCUSR - DEC set cursor shape
+ val = CSI_ARG_OR(args[0], 1);
+
+ switch(val) {
+ case 0: case 1:
+ settermprop_bool(state, VTERM_PROP_CURSORBLINK, 1);
+ settermprop_int (state, VTERM_PROP_CURSORSHAPE, VTERM_PROP_CURSORSHAPE_BLOCK);
+ break;
+ case 2:
+ settermprop_bool(state, VTERM_PROP_CURSORBLINK, 0);
+ settermprop_int (state, VTERM_PROP_CURSORSHAPE, VTERM_PROP_CURSORSHAPE_BLOCK);
+ break;
+ case 3:
+ settermprop_bool(state, VTERM_PROP_CURSORBLINK, 1);
+ settermprop_int (state, VTERM_PROP_CURSORSHAPE, VTERM_PROP_CURSORSHAPE_UNDERLINE);
+ break;
+ case 4:
+ settermprop_bool(state, VTERM_PROP_CURSORBLINK, 0);
+ settermprop_int (state, VTERM_PROP_CURSORSHAPE, VTERM_PROP_CURSORSHAPE_UNDERLINE);
+ break;
+ case 5:
+ settermprop_bool(state, VTERM_PROP_CURSORBLINK, 1);
+ settermprop_int (state, VTERM_PROP_CURSORSHAPE, VTERM_PROP_CURSORSHAPE_BAR_LEFT);
+ break;
+ case 6:
+ settermprop_bool(state, VTERM_PROP_CURSORBLINK, 0);
+ settermprop_int (state, VTERM_PROP_CURSORSHAPE, VTERM_PROP_CURSORSHAPE_BAR_LEFT);
+ break;
+ }
+
+ break;
+
+ case INTERMED('"', 0x71): // DECSCA - DEC select character protection attribute
+ val = CSI_ARG_OR(args[0], 0);
+
+ switch(val) {
+ case 0: case 2:
+ state->protected_cell = 0;
+ break;
+ case 1:
+ state->protected_cell = 1;
+ break;
+ }
+
+ break;
+
+ case 0x72: // DECSTBM - DEC custom
+ state->scrollregion_top = CSI_ARG_OR(args[0], 1) - 1;
+ state->scrollregion_bottom = argcount < 2 || CSI_ARG_IS_MISSING(args[1]) ? -1 : CSI_ARG(args[1]);
+ LBOUND(state->scrollregion_top, 0);
+ UBOUND(state->scrollregion_top, state->rows);
+ LBOUND(state->scrollregion_bottom, -1);
+ if(state->scrollregion_top == 0 && state->scrollregion_bottom == state->rows)
+ state->scrollregion_bottom = -1;
+ else
+ UBOUND(state->scrollregion_bottom, state->rows);
+
+ if(SCROLLREGION_BOTTOM(state) <= state->scrollregion_top) {
+ // Invalid
+ state->scrollregion_top = 0;
+ state->scrollregion_bottom = -1;
+ }
+
+ break;
+
+ case 0x73: // DECSLRM - DEC custom
+ // Always allow setting these margins, just they won't take effect without DECVSSM
+ state->scrollregion_left = CSI_ARG_OR(args[0], 1) - 1;
+ state->scrollregion_right = argcount < 2 || CSI_ARG_IS_MISSING(args[1]) ? -1 : CSI_ARG(args[1]);
+ LBOUND(state->scrollregion_left, 0);
+ UBOUND(state->scrollregion_left, state->cols);
+ LBOUND(state->scrollregion_right, -1);
+ if(state->scrollregion_left == 0 && state->scrollregion_right == state->cols)
+ state->scrollregion_right = -1;
+ else
+ UBOUND(state->scrollregion_right, state->cols);
+
+ if(state->scrollregion_right > -1 &&
+ state->scrollregion_right <= state->scrollregion_left) {
+ // Invalid
+ state->scrollregion_left = 0;
+ state->scrollregion_right = -1;
+ }
+
+ break;
+
+ case 0x74:
+ switch(CSI_ARG(args[0])) {
+ case 8: /* CSI 8 ; rows ; cols t set size */
+ if (argcount == 3)
+ on_resize(CSI_ARG(args[1]), CSI_ARG(args[2]), state);
+ }
+ break;
+
+ case INTERMED('\'', 0x7D): // DECIC
+ count = CSI_ARG_COUNT(args[0]);
+
+ if(!is_cursor_in_scrollregion(state))
+ break;
+
+ rect.start_row = state->scrollregion_top;
+ rect.end_row = SCROLLREGION_BOTTOM(state);
+ rect.start_col = state->pos.col;
+ rect.end_col = SCROLLREGION_RIGHT(state);
+
+ scroll(state, rect, 0, -count);
+
+ break;
+
+ case INTERMED('\'', 0x7E): // DECDC
+ count = CSI_ARG_COUNT(args[0]);
+
+ if(!is_cursor_in_scrollregion(state))
+ break;
+
+ rect.start_row = state->scrollregion_top;
+ rect.end_row = SCROLLREGION_BOTTOM(state);
+ rect.start_col = state->pos.col;
+ rect.end_col = SCROLLREGION_RIGHT(state);
+
+ scroll(state, rect, 0, count);
+
+ break;
+
+ default:
+ if(state->fallbacks && state->fallbacks->csi)
+ if((*state->fallbacks->csi)(leader, args, argcount, intermed, command, state->fbdata))
+ return 1;
+
+ return 0;
+ }
+
+ if(state->mode.origin) {
+ LBOUND(state->pos.row, state->scrollregion_top);
+ UBOUND(state->pos.row, SCROLLREGION_BOTTOM(state)-1);
+ LBOUND(state->pos.col, SCROLLREGION_LEFT(state));
+ UBOUND(state->pos.col, SCROLLREGION_RIGHT(state)-1);
+ }
+ else {
+ LBOUND(state->pos.row, 0);
+ UBOUND(state->pos.row, state->rows-1);
+ LBOUND(state->pos.col, 0);
+ UBOUND(state->pos.col, THISROWWIDTH(state)-1);
+ }
+
+ updatecursor(state, &oldpos, 1);
+
+#ifdef DEBUG
+ if(state->pos.row < 0 || state->pos.row >= state->rows ||
+ state->pos.col < 0 || state->pos.col >= state->cols) {
+ fprintf(stderr, "Position out of bounds after CSI %c: (%d,%d)\n",
+ command, state->pos.row, state->pos.col);
+ abort();
+ }
+
+ if(SCROLLREGION_BOTTOM(state) <= state->scrollregion_top) {
+ fprintf(stderr, "Scroll region height out of bounds after CSI %c: %d <= %d\n",
+ command, SCROLLREGION_BOTTOM(state), state->scrollregion_top);
+ abort();
+ }
+
+ if(SCROLLREGION_RIGHT(state) <= SCROLLREGION_LEFT(state)) {
+ fprintf(stderr, "Scroll region width out of bounds after CSI %c: %d <= %d\n",
+ command, SCROLLREGION_RIGHT(state), SCROLLREGION_LEFT(state));
+ abort();
+ }
+#endif
+
+ return 1;
+}
+
+static int on_osc(const char *command, size_t cmdlen, void *user)
+{
+ VTermState *state = user;
+
+ if(cmdlen < 2)
+ return 0;
+
+ if(strneq(command, "0;", 2)) {
+ settermprop_string(state, VTERM_PROP_ICONNAME, command + 2, cmdlen - 2);
+ settermprop_string(state, VTERM_PROP_TITLE, command + 2, cmdlen - 2);
+ return 1;
+ }
+ else if(strneq(command, "1;", 2)) {
+ settermprop_string(state, VTERM_PROP_ICONNAME, command + 2, cmdlen - 2);
+ return 1;
+ }
+ else if(strneq(command, "2;", 2)) {
+ settermprop_string(state, VTERM_PROP_TITLE, command + 2, cmdlen - 2);
+ return 1;
+ }
+ else if(strneq(command, "10;", 3)) {
+ /* request foreground color: <Esc>]10;?<0x07> */
+ int red = state->default_fg.red;
+ int blue = state->default_fg.blue;
+ int green = state->default_fg.green;
+ vterm_push_output_sprintf_ctrl(state->vt, C1_OSC, "10;rgb:%02x%02x/%02x%02x/%02x%02x\x07", red, red, green, green, blue, blue);
+ return 1;
+ }
+ else if(strneq(command, "11;", 3)) {
+ /* request background color: <Esc>]11;?<0x07> */
+ int red = state->default_bg.red;
+ int blue = state->default_bg.blue;
+ int green = state->default_bg.green;
+ vterm_push_output_sprintf_ctrl(state->vt, C1_OSC, "11;rgb:%02x%02x/%02x%02x/%02x%02x\x07", red, red, green, green, blue, blue);
+ return 1;
+ }
+ else if(strneq(command, "12;", 3)) {
+ settermprop_string(state, VTERM_PROP_CURSORCOLOR, command + 3, cmdlen - 3);
+ return 1;
+ }
+ else if(state->fallbacks && state->fallbacks->osc)
+ if((*state->fallbacks->osc)(command, cmdlen, state->fbdata))
+ return 1;
+
+ return 0;
+}
+
+static void request_status_string(VTermState *state, const char *command, size_t cmdlen)
+{
+ if(cmdlen == 1)
+ switch(command[0]) {
+ case 'm': // Query SGR
+ {
+ long args[20];
+ int argc = vterm_state_getpen(state, args, sizeof(args)/sizeof(args[0]));
+ int argi;
+ vterm_push_output_sprintf_ctrl(state->vt, C1_DCS, "1$r");
+ for(argi = 0; argi < argc; argi++)
+ vterm_push_output_sprintf(state->vt,
+ argi == argc - 1 ? "%d" :
+ CSI_ARG_HAS_MORE(args[argi]) ? "%d:" :
+ "%d;",
+ CSI_ARG(args[argi]));
+ vterm_push_output_sprintf(state->vt, "m");
+ vterm_push_output_sprintf_ctrl(state->vt, C1_ST, "");
+ }
+ return;
+ case 'r': // Query DECSTBM
+ vterm_push_output_sprintf_dcs(state->vt, "1$r%d;%dr", state->scrollregion_top+1, SCROLLREGION_BOTTOM(state));
+ return;
+ case 's': // Query DECSLRM
+ vterm_push_output_sprintf_dcs(state->vt, "1$r%d;%ds", SCROLLREGION_LEFT(state)+1, SCROLLREGION_RIGHT(state));
+ return;
+ }
+
+ if(cmdlen == 2) {
+ if(strneq(command, " q", 2)) {
+ int reply;
+ switch(state->mode.cursor_shape) {
+ case VTERM_PROP_CURSORSHAPE_BLOCK: reply = 2; break;
+ case VTERM_PROP_CURSORSHAPE_UNDERLINE: reply = 4; break;
+ default: /* VTERM_PROP_CURSORSHAPE_BAR_LEFT */ reply = 6; break;
+ }
+ if(state->mode.cursor_blink)
+ reply--;
+ vterm_push_output_sprintf_dcs(state->vt, "1$r%d q", reply);
+ return;
+ }
+ else if(strneq(command, "\"q", 2)) {
+ vterm_push_output_sprintf_dcs(state->vt, "1$r%d\"q", state->protected_cell ? 1 : 2);
+ return;
+ }
+ }
+
+ vterm_push_output_sprintf_dcs(state->vt, "0$r%.s", (int)cmdlen, command);
+}
+
+static int on_dcs(const char *command, size_t cmdlen, void *user)
+{
+ VTermState *state = user;
+
+ if(cmdlen >= 2 && strneq(command, "$q", 2)) {
+ request_status_string(state, command+2, cmdlen-2);
+ return 1;
+ }
+ else if(state->fallbacks && state->fallbacks->dcs)
+ if((*state->fallbacks->dcs)(command, cmdlen, state->fbdata))
+ return 1;
+
+ return 0;
+}
+
+static int on_resize(int rows, int cols, void *user)
+{
+ VTermState *state = user;
+ VTermPos oldpos = state->pos;
+ VTermPos delta = { 0, 0 };
+
+ if(cols != state->cols) {
+ unsigned char *newtabstops = vterm_allocator_malloc(state->vt, (cols + 7) / 8);
+
+ /* TODO: This can all be done much more efficiently bytewise */
+ int col;
+ for(col = 0; col < state->cols && col < cols; col++) {
+ unsigned char mask = 1 << (col & 7);
+ if(state->tabstops[col >> 3] & mask)
+ newtabstops[col >> 3] |= mask;
+ else
+ newtabstops[col >> 3] &= ~mask;
+ }
+
+ for( ; col < cols; col++) {
+ unsigned char mask = 1 << (col & 7);
+ if(col % 8 == 0)
+ newtabstops[col >> 3] |= mask;
+ else
+ newtabstops[col >> 3] &= ~mask;
+ }
+
+ vterm_allocator_free(state->vt, state->tabstops);
+ state->tabstops = newtabstops;
+ }
+
+ if(rows != state->rows) {
+ VTermLineInfo *newlineinfo = vterm_allocator_malloc(state->vt, rows * sizeof(VTermLineInfo));
+
+ int row;
+ for(row = 0; row < state->rows && row < rows; row++) {
+ newlineinfo[row] = state->lineinfo[row];
+ }
+
+ for( ; row < rows; row++) {
+ newlineinfo[row].doublewidth = 0;
+ newlineinfo[row].doubleheight = 0;
+ }
+
+ vterm_allocator_free(state->vt, state->lineinfo);
+ state->lineinfo = newlineinfo;
+ }
+
+ state->rows = rows;
+ state->cols = cols;
+
+ if(state->scrollregion_bottom > -1)
+ UBOUND(state->scrollregion_bottom, state->rows);
+ if(state->scrollregion_right > -1)
+ UBOUND(state->scrollregion_right, state->cols);
+
+ if(state->callbacks && state->callbacks->resize)
+ (*state->callbacks->resize)(rows, cols, &delta, state->cbdata);
+
+ if(state->at_phantom && state->pos.col < cols-1) {
+ state->at_phantom = 0;
+ state->pos.col++;
+ }
+
+ state->pos.row += delta.row;
+ state->pos.col += delta.col;
+
+ if(state->pos.row >= rows)
+ state->pos.row = rows - 1;
+ if(state->pos.col >= cols)
+ state->pos.col = cols - 1;
+
+ updatecursor(state, &oldpos, 1);
+
+ return 1;
+}
+
+static const VTermParserCallbacks parser_callbacks = {
+ on_text, /* text */
+ on_control, /* control */
+ on_escape, /* escape */
+ on_csi, /* csi */
+ on_osc, /* osc */
+ on_dcs, /* dcs */
+ on_resize /* resize */
+};
+
+/*
+ * Return the existing state or create a new one.
+ * Returns NULL when out of memory.
+ */
+VTermState *vterm_obtain_state(VTerm *vt)
+{
+ VTermState *state;
+ if(vt->state)
+ return vt->state;
+
+ state = vterm_state_new(vt);
+ if (state == NULL)
+ return NULL;
+ vt->state = state;
+
+ state->combine_chars_size = 16;
+ state->combine_chars = vterm_allocator_malloc(state->vt, state->combine_chars_size * sizeof(state->combine_chars[0]));
+
+ state->tabstops = vterm_allocator_malloc(state->vt, (state->cols + 7) / 8);
+
+ state->lineinfo = vterm_allocator_malloc(state->vt, state->rows * sizeof(VTermLineInfo));
+
+ state->encoding_utf8.enc = vterm_lookup_encoding(ENC_UTF8, 'u');
+ if(*state->encoding_utf8.enc->init != NULL)
+ (*state->encoding_utf8.enc->init)(state->encoding_utf8.enc, state->encoding_utf8.data);
+
+ vterm_parser_set_callbacks(vt, &parser_callbacks, state);
+
+ return state;
+}
+
+void vterm_state_reset(VTermState *state, int hard)
+{
+ VTermEncoding *default_enc;
+
+ state->scrollregion_top = 0;
+ state->scrollregion_bottom = -1;
+ state->scrollregion_left = 0;
+ state->scrollregion_right = -1;
+
+ state->mode.keypad = 0;
+ state->mode.cursor = 0;
+ state->mode.autowrap = 1;
+ state->mode.insert = 0;
+ state->mode.newline = 0;
+ state->mode.alt_screen = 0;
+ state->mode.origin = 0;
+ state->mode.leftrightmargin = 0;
+ state->mode.bracketpaste = 0;
+ state->mode.report_focus = 0;
+
+ state->vt->mode.ctrl8bit = 0;
+
+ {
+ int col;
+ for(col = 0; col < state->cols; col++)
+ if(col % 8 == 0)
+ set_col_tabstop(state, col);
+ else
+ clear_col_tabstop(state, col);
+ }
+
+ {
+ int row;
+ for(row = 0; row < state->rows; row++)
+ set_lineinfo(state, row, FORCE, DWL_OFF, DHL_OFF);
+ }
+
+ if(state->callbacks && state->callbacks->initpen)
+ (*state->callbacks->initpen)(state->cbdata);
+
+ vterm_state_resetpen(state);
+
+ default_enc = state->vt->mode.utf8 ?
+ vterm_lookup_encoding(ENC_UTF8, 'u') :
+ vterm_lookup_encoding(ENC_SINGLE_94, 'B');
+
+ {
+ int i;
+ for(i = 0; i < 4; i++) {
+ state->encoding[i].enc = default_enc;
+ if(default_enc->init)
+ (*default_enc->init)(default_enc, state->encoding[i].data);
+ }
+ }
+
+ state->gl_set = 0;
+ state->gr_set = 1;
+ state->gsingle_set = 0;
+
+ state->protected_cell = 0;
+
+ // Initialise the props
+ settermprop_bool(state, VTERM_PROP_CURSORVISIBLE, 1);
+ settermprop_bool(state, VTERM_PROP_CURSORBLINK, 1);
+ settermprop_int (state, VTERM_PROP_CURSORSHAPE, VTERM_PROP_CURSORSHAPE_BLOCK);
+
+ if(hard) {
+ VTermRect rect = { 0, 0, 0, 0 };
+
+ state->pos.row = 0;
+ state->pos.col = 0;
+ state->at_phantom = 0;
+
+ rect.end_row = state->rows;
+ rect.end_col = state->cols;
+ erase(state, rect, 0);
+ }
+}
+
+void vterm_state_get_cursorpos(const VTermState *state, VTermPos *cursorpos)
+{
+ *cursorpos = state->pos;
+}
+
+void vterm_state_get_mousestate(const VTermState *state, VTermMouseState *mousestate)
+{
+ mousestate->pos.col = state->mouse_col;
+ mousestate->pos.row = state->mouse_row;
+ mousestate->buttons = state->mouse_buttons;
+ mousestate->flags = state->mouse_flags;
+}
+
+void vterm_state_set_callbacks(VTermState *state, const VTermStateCallbacks *callbacks, void *user)
+{
+ if(callbacks) {
+ state->callbacks = callbacks;
+ state->cbdata = user;
+
+ if(state->callbacks && state->callbacks->initpen)
+ (*state->callbacks->initpen)(state->cbdata);
+ }
+ else {
+ state->callbacks = NULL;
+ state->cbdata = NULL;
+ }
+}
+
+void *vterm_state_get_cbdata(VTermState *state)
+{
+ return state->cbdata;
+}
+
+void vterm_state_set_unrecognised_fallbacks(VTermState *state, const VTermParserCallbacks *fallbacks, void *user)
+{
+ if(fallbacks) {
+ state->fallbacks = fallbacks;
+ state->fbdata = user;
+ }
+ else {
+ state->fallbacks = NULL;
+ state->fbdata = NULL;
+ }
+}
+
+void *vterm_state_get_unrecognised_fbdata(VTermState *state)
+{
+ return state->fbdata;
+}
+
+int vterm_state_set_termprop(VTermState *state, VTermProp prop, VTermValue *val)
+{
+ /* Only store the new value of the property if usercode said it was happy.
+ * This is especially important for altscreen switching */
+ if(state->callbacks && state->callbacks->settermprop)
+ if(!(*state->callbacks->settermprop)(prop, val, state->cbdata))
+ return 0;
+
+ switch(prop) {
+ case VTERM_PROP_TITLE:
+ case VTERM_PROP_ICONNAME:
+ case VTERM_PROP_CURSORCOLOR:
+ // we don't store these, just transparently pass through
+ return 1;
+ case VTERM_PROP_CURSORVISIBLE:
+ state->mode.cursor_visible = val->boolean;
+ return 1;
+ case VTERM_PROP_CURSORBLINK:
+ state->mode.cursor_blink = val->boolean;
+ return 1;
+ case VTERM_PROP_CURSORSHAPE:
+ state->mode.cursor_shape = val->number;
+ return 1;
+ case VTERM_PROP_REVERSE:
+ state->mode.screen = val->boolean;
+ return 1;
+ case VTERM_PROP_ALTSCREEN:
+ state->mode.alt_screen = val->boolean;
+ if(state->mode.alt_screen) {
+ VTermRect rect = {0, 0, 0, 0};
+ rect.end_row = state->rows;
+ rect.end_col = state->cols;
+ erase(state, rect, 0);
+ }
+ return 1;
+ case VTERM_PROP_MOUSE:
+ state->mouse_flags = 0;
+ if(val->number)
+ state->mouse_flags |= MOUSE_WANT_CLICK;
+ if(val->number == VTERM_PROP_MOUSE_DRAG)
+ state->mouse_flags |= MOUSE_WANT_DRAG;
+ if(val->number == VTERM_PROP_MOUSE_MOVE)
+ state->mouse_flags |= MOUSE_WANT_MOVE;
+ return 1;
+
+ case VTERM_N_PROPS:
+ return 0;
+ }
+
+ return 0;
+}
+
+void vterm_state_focus_in(VTermState *state)
+{
+ if(state->mode.report_focus)
+ vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "I");
+}
+
+void vterm_state_focus_out(VTermState *state)
+{
+ if(state->mode.report_focus)
+ vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "O");
+}
+
+const VTermLineInfo *vterm_state_get_lineinfo(const VTermState *state, int row)
+{
+ return state->lineinfo + row;
+}
diff --git a/src/libvterm/src/termscreen.c b/src/libvterm/src/termscreen.c
new file mode 100644
index 0000000..0cd31ce
--- /dev/null
+++ b/src/libvterm/src/termscreen.c
@@ -0,0 +1,939 @@
+#include "vterm_internal.h"
+
+/* vim: set sw=2 : */
+#include <stdio.h>
+#include <string.h>
+
+#include "rect.h"
+#include "utf8.h"
+
+#define UNICODE_SPACE 0x20
+#define UNICODE_LINEFEED 0x0a
+
+/* State of the pen at some moment in time, also used in a cell */
+typedef struct
+{
+ /* After the bitfield */
+ VTermColor fg, bg;
+
+ unsigned int bold : 1;
+ unsigned int underline : 2;
+ unsigned int italic : 1;
+ unsigned int blink : 1;
+ unsigned int reverse : 1;
+ unsigned int strike : 1;
+ unsigned int font : 4; /* 0 to 9 */
+
+ /* Extra state storage that isn't strictly pen-related */
+ unsigned int protected_cell : 1;
+ unsigned int dwl : 1; /* on a DECDWL or DECDHL line */
+ unsigned int dhl : 2; /* on a DECDHL line (1=top 2=bottom) */
+} ScreenPen;
+
+/* Internal representation of a screen cell */
+typedef struct
+{
+ uint32_t chars[VTERM_MAX_CHARS_PER_CELL];
+ ScreenPen pen;
+} ScreenCell;
+
+static int vterm_screen_set_cell(VTermScreen *screen, VTermPos pos, const VTermScreenCell *cell);
+
+struct VTermScreen
+{
+ VTerm *vt;
+ VTermState *state;
+
+ const VTermScreenCallbacks *callbacks;
+ void *cbdata;
+
+ VTermDamageSize damage_merge;
+ /* start_row == -1 => no damage */
+ VTermRect damaged;
+ VTermRect pending_scrollrect;
+ int pending_scroll_downward, pending_scroll_rightward;
+
+ int rows;
+ int cols;
+ int global_reverse;
+
+ /* Primary and Altscreen. buffers[1] is lazily allocated as needed */
+ ScreenCell *buffers[2];
+
+ /* buffer will == buffers[0] or buffers[1], depending on altscreen */
+ ScreenCell *buffer;
+
+ /* buffer for a single screen row used in scrollback storage callbacks */
+ VTermScreenCell *sb_buffer;
+
+ ScreenPen pen;
+};
+
+static ScreenCell *getcell(const VTermScreen *screen, int row, int col)
+{
+ if(row < 0 || row >= screen->rows)
+ return NULL;
+ if(col < 0 || col >= screen->cols)
+ return NULL;
+ return screen->buffer + (screen->cols * row) + col;
+}
+
+static ScreenCell *realloc_buffer(VTermScreen *screen, ScreenCell *buffer, int new_rows, int new_cols)
+{
+ ScreenCell *new_buffer = vterm_allocator_malloc(screen->vt, sizeof(ScreenCell) * new_rows * new_cols);
+ int row, col;
+
+ for(row = 0; row < new_rows; row++) {
+ for(col = 0; col < new_cols; col++) {
+ ScreenCell *new_cell = new_buffer + row*new_cols + col;
+
+ if(buffer && row < screen->rows && col < screen->cols)
+ *new_cell = buffer[row * screen->cols + col];
+ else {
+ new_cell->chars[0] = 0;
+ new_cell->pen = screen->pen;
+ }
+ }
+ }
+
+ vterm_allocator_free(screen->vt, buffer);
+
+ return new_buffer;
+}
+
+static void damagerect(VTermScreen *screen, VTermRect rect)
+{
+ VTermRect emit;
+
+ switch(screen->damage_merge) {
+ case VTERM_DAMAGE_CELL:
+ /* Always emit damage event */
+ emit = rect;
+ break;
+
+ case VTERM_DAMAGE_ROW:
+ /* Emit damage longer than one row. Try to merge with existing damage in
+ * the same row */
+ if(rect.end_row > rect.start_row + 1) {
+ // Bigger than 1 line - flush existing, emit this
+ vterm_screen_flush_damage(screen);
+ emit = rect;
+ }
+ else if(screen->damaged.start_row == -1) {
+ // None stored yet
+ screen->damaged = rect;
+ return;
+ }
+ else if(rect.start_row == screen->damaged.start_row) {
+ // Merge with the stored line
+ if(screen->damaged.start_col > rect.start_col)
+ screen->damaged.start_col = rect.start_col;
+ if(screen->damaged.end_col < rect.end_col)
+ screen->damaged.end_col = rect.end_col;
+ return;
+ }
+ else {
+ // Emit the currently stored line, store a new one
+ emit = screen->damaged;
+ screen->damaged = rect;
+ }
+ break;
+
+ case VTERM_DAMAGE_SCREEN:
+ case VTERM_DAMAGE_SCROLL:
+ /* Never emit damage event */
+ if(screen->damaged.start_row == -1)
+ screen->damaged = rect;
+ else {
+ rect_expand(&screen->damaged, &rect);
+ }
+ return;
+
+ default:
+ DEBUG_LOG1("TODO: Maybe merge damage for level %d\n", screen->damage_merge);
+ return;
+ }
+
+ if(screen->callbacks && screen->callbacks->damage)
+ (*screen->callbacks->damage)(emit, screen->cbdata);
+}
+
+static void damagescreen(VTermScreen *screen)
+{
+ VTermRect rect = {0,0,0,0};
+ rect.end_row = screen->rows;
+ rect.end_col = screen->cols;
+
+ damagerect(screen, rect);
+}
+
+static int putglyph(VTermGlyphInfo *info, VTermPos pos, void *user)
+{
+ int i;
+ int col;
+ VTermRect rect;
+
+ VTermScreen *screen = user;
+ ScreenCell *cell = getcell(screen, pos.row, pos.col);
+
+ if(!cell)
+ return 0;
+
+ for(i = 0; i < VTERM_MAX_CHARS_PER_CELL && info->chars[i]; i++) {
+ cell->chars[i] = info->chars[i];
+ cell->pen = screen->pen;
+ }
+ if(i < VTERM_MAX_CHARS_PER_CELL)
+ cell->chars[i] = 0;
+
+ for(col = 1; col < info->width; col++)
+ getcell(screen, pos.row, pos.col + col)->chars[0] = (uint32_t)-1;
+
+ rect.start_row = pos.row;
+ rect.end_row = pos.row+1;
+ rect.start_col = pos.col;
+ rect.end_col = pos.col+info->width;
+
+ cell->pen.protected_cell = info->protected_cell;
+ cell->pen.dwl = info->dwl;
+ cell->pen.dhl = info->dhl;
+
+ damagerect(screen, rect);
+
+ return 1;
+}
+
+static int moverect_internal(VTermRect dest, VTermRect src, void *user)
+{
+ VTermScreen *screen = user;
+
+ if(screen->callbacks && screen->callbacks->sb_pushline &&
+ dest.start_row == 0 && dest.start_col == 0 && // starts top-left corner
+ dest.end_col == screen->cols && // full width
+ screen->buffer == screen->buffers[0]) { // not altscreen
+ VTermPos pos;
+ for(pos.row = 0; pos.row < src.start_row; pos.row++) {
+ for(pos.col = 0; pos.col < screen->cols; pos.col++)
+ (void)vterm_screen_get_cell(screen, pos, screen->sb_buffer + pos.col);
+
+ (screen->callbacks->sb_pushline)(screen->cols, screen->sb_buffer, screen->cbdata);
+ }
+ }
+
+ {
+ int cols = src.end_col - src.start_col;
+ int downward = src.start_row - dest.start_row;
+ int init_row, test_row, inc_row;
+ int row;
+
+ if(downward < 0) {
+ init_row = dest.end_row - 1;
+ test_row = dest.start_row - 1;
+ inc_row = -1;
+ }
+ else {
+ init_row = dest.start_row;
+ test_row = dest.end_row;
+ inc_row = +1;
+ }
+
+ for(row = init_row; row != test_row; row += inc_row)
+ memmove(getcell(screen, row, dest.start_col),
+ getcell(screen, row + downward, src.start_col),
+ cols * sizeof(ScreenCell));
+ }
+
+ return 1;
+}
+
+static int moverect_user(VTermRect dest, VTermRect src, void *user)
+{
+ VTermScreen *screen = user;
+
+ if(screen->callbacks && screen->callbacks->moverect) {
+ if(screen->damage_merge != VTERM_DAMAGE_SCROLL)
+ // Avoid an infinite loop
+ vterm_screen_flush_damage(screen);
+
+ if((*screen->callbacks->moverect)(dest, src, screen->cbdata))
+ return 1;
+ }
+
+ damagerect(screen, dest);
+
+ return 1;
+}
+
+static int erase_internal(VTermRect rect, int selective, void *user)
+{
+ VTermScreen *screen = user;
+ int row, col;
+
+ for(row = rect.start_row; row < screen->state->rows && row < rect.end_row; row++) {
+ const VTermLineInfo *info = vterm_state_get_lineinfo(screen->state, row);
+
+ for(col = rect.start_col; col < rect.end_col; col++) {
+ ScreenCell *cell = getcell(screen, row, col);
+
+ if(selective && cell->pen.protected_cell)
+ continue;
+
+ cell->chars[0] = 0;
+ cell->pen = screen->pen;
+ cell->pen.dwl = info->doublewidth;
+ cell->pen.dhl = info->doubleheight;
+ }
+ }
+
+ return 1;
+}
+
+static int erase_user(VTermRect rect, int selective UNUSED, void *user)
+{
+ VTermScreen *screen = user;
+
+ damagerect(screen, rect);
+
+ return 1;
+}
+
+static int erase(VTermRect rect, int selective, void *user)
+{
+ erase_internal(rect, selective, user);
+ return erase_user(rect, 0, user);
+}
+
+static int scrollrect(VTermRect rect, int downward, int rightward, void *user)
+{
+ VTermScreen *screen = user;
+
+ if(screen->damage_merge != VTERM_DAMAGE_SCROLL) {
+ vterm_scroll_rect(rect, downward, rightward,
+ moverect_internal, erase_internal, screen);
+
+ vterm_screen_flush_damage(screen);
+
+ vterm_scroll_rect(rect, downward, rightward,
+ moverect_user, erase_user, screen);
+
+ return 1;
+ }
+
+ if(screen->damaged.start_row != -1 &&
+ !rect_intersects(&rect, &screen->damaged)) {
+ vterm_screen_flush_damage(screen);
+ }
+
+ if(screen->pending_scrollrect.start_row == -1) {
+ screen->pending_scrollrect = rect;
+ screen->pending_scroll_downward = downward;
+ screen->pending_scroll_rightward = rightward;
+ }
+ else if(rect_equal(&screen->pending_scrollrect, &rect) &&
+ ((screen->pending_scroll_downward == 0 && downward == 0) ||
+ (screen->pending_scroll_rightward == 0 && rightward == 0))) {
+ screen->pending_scroll_downward += downward;
+ screen->pending_scroll_rightward += rightward;
+ }
+ else {
+ vterm_screen_flush_damage(screen);
+
+ screen->pending_scrollrect = rect;
+ screen->pending_scroll_downward = downward;
+ screen->pending_scroll_rightward = rightward;
+ }
+
+ vterm_scroll_rect(rect, downward, rightward,
+ moverect_internal, erase_internal, screen);
+
+ if(screen->damaged.start_row == -1)
+ return 1;
+
+ if(rect_contains(&rect, &screen->damaged)) {
+ /* Scroll region entirely contains the damage; just move it */
+ vterm_rect_move(&screen->damaged, -downward, -rightward);
+ rect_clip(&screen->damaged, &rect);
+ }
+ /* There are a number of possible cases here, but lets restrict this to only
+ * the common case where we might actually gain some performance by
+ * optimising it. Namely, a vertical scroll that neatly cuts the damage
+ * region in half.
+ */
+ else if(rect.start_col <= screen->damaged.start_col &&
+ rect.end_col >= screen->damaged.end_col &&
+ rightward == 0) {
+ if(screen->damaged.start_row >= rect.start_row &&
+ screen->damaged.start_row < rect.end_row) {
+ screen->damaged.start_row -= downward;
+ if(screen->damaged.start_row < rect.start_row)
+ screen->damaged.start_row = rect.start_row;
+ if(screen->damaged.start_row > rect.end_row)
+ screen->damaged.start_row = rect.end_row;
+ }
+ if(screen->damaged.end_row >= rect.start_row &&
+ screen->damaged.end_row < rect.end_row) {
+ screen->damaged.end_row -= downward;
+ if(screen->damaged.end_row < rect.start_row)
+ screen->damaged.end_row = rect.start_row;
+ if(screen->damaged.end_row > rect.end_row)
+ screen->damaged.end_row = rect.end_row;
+ }
+ }
+ else {
+ DEBUG_LOG2("TODO: Just flush and redo damaged=" STRFrect " rect=" STRFrect "\n",
+ ARGSrect(screen->damaged), ARGSrect(rect));
+ }
+
+ return 1;
+}
+
+static int movecursor(VTermPos pos, VTermPos oldpos, int visible, void *user)
+{
+ VTermScreen *screen = user;
+
+ if(screen->callbacks && screen->callbacks->movecursor)
+ return (*screen->callbacks->movecursor)(pos, oldpos, visible, screen->cbdata);
+
+ return 0;
+}
+
+static int setpenattr(VTermAttr attr, VTermValue *val, void *user)
+{
+ VTermScreen *screen = user;
+
+ switch(attr) {
+ case VTERM_ATTR_BOLD:
+ screen->pen.bold = val->boolean;
+ return 1;
+ case VTERM_ATTR_UNDERLINE:
+ screen->pen.underline = val->number;
+ return 1;
+ case VTERM_ATTR_ITALIC:
+ screen->pen.italic = val->boolean;
+ return 1;
+ case VTERM_ATTR_BLINK:
+ screen->pen.blink = val->boolean;
+ return 1;
+ case VTERM_ATTR_REVERSE:
+ screen->pen.reverse = val->boolean;
+ return 1;
+ case VTERM_ATTR_STRIKE:
+ screen->pen.strike = val->boolean;
+ return 1;
+ case VTERM_ATTR_FONT:
+ screen->pen.font = val->number;
+ return 1;
+ case VTERM_ATTR_FOREGROUND:
+ screen->pen.fg = val->color;
+ return 1;
+ case VTERM_ATTR_BACKGROUND:
+ screen->pen.bg = val->color;
+ return 1;
+
+ case VTERM_N_ATTRS:
+ return 0;
+ }
+
+ return 0;
+}
+
+static int settermprop(VTermProp prop, VTermValue *val, void *user)
+{
+ VTermScreen *screen = user;
+
+ switch(prop) {
+ case VTERM_PROP_ALTSCREEN:
+ if(val->boolean && !screen->buffers[1])
+ return 0;
+
+ screen->buffer = val->boolean ? screen->buffers[1] : screen->buffers[0];
+ /* only send a damage event on disable; because during enable there's an
+ * erase that sends a damage anyway
+ */
+ if(!val->boolean)
+ damagescreen(screen);
+ break;
+ case VTERM_PROP_REVERSE:
+ screen->global_reverse = val->boolean;
+ damagescreen(screen);
+ break;
+ default:
+ ; /* ignore */
+ }
+
+ if(screen->callbacks && screen->callbacks->settermprop)
+ return (*screen->callbacks->settermprop)(prop, val, screen->cbdata);
+
+ return 1;
+}
+
+static int bell(void *user)
+{
+ VTermScreen *screen = user;
+
+ if(screen->callbacks && screen->callbacks->bell)
+ return (*screen->callbacks->bell)(screen->cbdata);
+
+ return 0;
+}
+
+static int resize(int new_rows, int new_cols, VTermPos *delta, void *user)
+{
+ VTermScreen *screen = user;
+
+ int is_altscreen = (screen->buffers[1] && screen->buffer == screen->buffers[1]);
+
+ int old_rows = screen->rows;
+ int old_cols = screen->cols;
+ int first_blank_row;
+
+ if(!is_altscreen && new_rows < old_rows) {
+ // Fewer rows - determine if we're going to scroll at all, and if so, push
+ // those lines to scrollback
+ VTermPos pos = { 0, 0 };
+ VTermPos cursor = screen->state->pos;
+ // Find the first blank row after the cursor.
+ for(pos.row = old_rows - 1; pos.row >= new_rows; pos.row--)
+ if(!vterm_screen_is_eol(screen, pos) || cursor.row == pos.row)
+ break;
+
+ first_blank_row = pos.row + 1;
+ if(first_blank_row > new_rows) {
+ VTermRect rect = {0,0,0,0};
+ rect.end_row = old_rows;
+ rect.end_col = old_cols;
+ scrollrect(rect, first_blank_row - new_rows, 0, user);
+ vterm_screen_flush_damage(screen);
+
+ delta->row -= first_blank_row - new_rows;
+ }
+ }
+
+ screen->buffers[0] = realloc_buffer(screen, screen->buffers[0], new_rows, new_cols);
+ if(screen->buffers[1])
+ screen->buffers[1] = realloc_buffer(screen, screen->buffers[1], new_rows, new_cols);
+
+ screen->buffer = is_altscreen ? screen->buffers[1] : screen->buffers[0];
+
+ screen->rows = new_rows;
+ screen->cols = new_cols;
+
+ vterm_allocator_free(screen->vt, screen->sb_buffer);
+
+ screen->sb_buffer = vterm_allocator_malloc(screen->vt, sizeof(VTermScreenCell) * new_cols);
+
+ if(new_cols > old_cols) {
+ VTermRect rect;
+ rect.start_row = 0;
+ rect.end_row = old_rows;
+ rect.start_col = old_cols;
+ rect.end_col = new_cols;
+ damagerect(screen, rect);
+ }
+
+ if(new_rows > old_rows) {
+ if(!is_altscreen && screen->callbacks && screen->callbacks->sb_popline) {
+ int rows = new_rows - old_rows;
+ while(rows) {
+ VTermRect rect = {0,0,0,0};
+ VTermPos pos = { 0, 0 };
+ if(!(screen->callbacks->sb_popline(screen->cols, screen->sb_buffer, screen->cbdata)))
+ break;
+
+ rect.end_row = screen->rows;
+ rect.end_col = screen->cols;
+ scrollrect(rect, -1, 0, user);
+
+ for(pos.col = 0; pos.col < screen->cols; pos.col += screen->sb_buffer[pos.col].width)
+ vterm_screen_set_cell(screen, pos, screen->sb_buffer + pos.col);
+
+ rect.end_row = 1;
+ damagerect(screen, rect);
+
+ vterm_screen_flush_damage(screen);
+
+ rows--;
+ delta->row++;
+ }
+ }
+
+ {
+ VTermRect rect;
+ rect.start_row = old_rows;
+ rect.end_row = new_rows;
+ rect.start_col = 0;
+ rect.end_col = new_cols;
+ damagerect(screen, rect);
+ }
+ }
+
+ if(screen->callbacks && screen->callbacks->resize)
+ return (*screen->callbacks->resize)(new_rows, new_cols, screen->cbdata);
+
+ return 1;
+}
+
+static int setlineinfo(int row, const VTermLineInfo *newinfo, const VTermLineInfo *oldinfo, void *user)
+{
+ VTermScreen *screen = user;
+ int col;
+ VTermRect rect;
+
+ if(newinfo->doublewidth != oldinfo->doublewidth ||
+ newinfo->doubleheight != oldinfo->doubleheight) {
+ for(col = 0; col < screen->cols; col++) {
+ ScreenCell *cell = getcell(screen, row, col);
+ cell->pen.dwl = newinfo->doublewidth;
+ cell->pen.dhl = newinfo->doubleheight;
+ }
+
+ rect.start_row = row;
+ rect.end_row = row + 1;
+ rect.start_col = 0;
+ rect.end_col = newinfo->doublewidth ? screen->cols / 2 : screen->cols;
+ damagerect(screen, rect);
+
+ if(newinfo->doublewidth) {
+ rect.start_col = screen->cols / 2;
+ rect.end_col = screen->cols;
+
+ erase_internal(rect, 0, user);
+ }
+ }
+
+ return 1;
+}
+
+static VTermStateCallbacks state_cbs = {
+ &putglyph, /* putglyph */
+ &movecursor, /* movecursor */
+ &scrollrect, /* scrollrect */
+ NULL, /* moverect */
+ &erase, /* erase */
+ NULL, /* initpen */
+ &setpenattr, /* setpenattr */
+ &settermprop, /* settermprop */
+ &bell, /* bell */
+ &resize, /* resize */
+ &setlineinfo /* setlineinfo */
+};
+
+/*
+ * Allocate a new screen and return it.
+ * Return NULL when out of memory.
+ */
+static VTermScreen *screen_new(VTerm *vt)
+{
+ VTermState *state = vterm_obtain_state(vt);
+ VTermScreen *screen;
+ int rows, cols;
+
+ if (state == NULL)
+ return NULL;
+ screen = vterm_allocator_malloc(vt, sizeof(VTermScreen));
+ if (screen == NULL)
+ return NULL;
+
+ vterm_get_size(vt, &rows, &cols);
+
+ screen->vt = vt;
+ screen->state = state;
+
+ screen->damage_merge = VTERM_DAMAGE_CELL;
+ screen->damaged.start_row = -1;
+ screen->pending_scrollrect.start_row = -1;
+
+ screen->rows = rows;
+ screen->cols = cols;
+
+ screen->callbacks = NULL;
+ screen->cbdata = NULL;
+
+ screen->buffers[0] = realloc_buffer(screen, NULL, rows, cols);
+ screen->buffer = screen->buffers[0];
+ screen->sb_buffer = vterm_allocator_malloc(screen->vt, sizeof(VTermScreenCell) * cols);
+ if (screen->buffer == NULL || screen->sb_buffer == NULL)
+ {
+ vterm_screen_free(screen);
+ return NULL;
+ }
+
+ vterm_state_set_callbacks(screen->state, &state_cbs, screen);
+
+ return screen;
+}
+
+INTERNAL void vterm_screen_free(VTermScreen *screen)
+{
+ vterm_allocator_free(screen->vt, screen->buffers[0]);
+ vterm_allocator_free(screen->vt, screen->buffers[1]);
+ vterm_allocator_free(screen->vt, screen->sb_buffer);
+ vterm_allocator_free(screen->vt, screen);
+}
+
+void vterm_screen_reset(VTermScreen *screen, int hard)
+{
+ screen->damaged.start_row = -1;
+ screen->pending_scrollrect.start_row = -1;
+ vterm_state_reset(screen->state, hard);
+ vterm_screen_flush_damage(screen);
+}
+
+static size_t _get_chars(const VTermScreen *screen, const int utf8, void *buffer, size_t len, const VTermRect rect)
+{
+ size_t outpos = 0;
+ int padding = 0;
+ int row, col;
+
+#define PUT(c) \
+ if(utf8) { \
+ size_t thislen = utf8_seqlen(c); \
+ if(buffer && outpos + thislen <= len) \
+ outpos += fill_utf8((c), (char *)buffer + outpos); \
+ else \
+ outpos += thislen; \
+ } \
+ else { \
+ if(buffer && outpos + 1 <= len) \
+ ((uint32_t*)buffer)[outpos++] = (c); \
+ else \
+ outpos++; \
+ }
+
+ for(row = rect.start_row; row < rect.end_row; row++) {
+ for(col = rect.start_col; col < rect.end_col; col++) {
+ ScreenCell *cell = getcell(screen, row, col);
+ int i;
+
+ if(cell->chars[0] == 0)
+ // Erased cell, might need a space
+ padding++;
+ else if(cell->chars[0] == (uint32_t)-1)
+ // Gap behind a double-width char, do nothing
+ ;
+ else {
+ while(padding) {
+ PUT(UNICODE_SPACE);
+ padding--;
+ }
+ for(i = 0; i < VTERM_MAX_CHARS_PER_CELL && cell->chars[i]; i++) {
+ PUT(cell->chars[i]);
+ }
+ }
+ }
+
+ if(row < rect.end_row - 1) {
+ PUT(UNICODE_LINEFEED);
+ padding = 0;
+ }
+ }
+
+ return outpos;
+}
+
+size_t vterm_screen_get_chars(const VTermScreen *screen, uint32_t *chars, size_t len, const VTermRect rect)
+{
+ return _get_chars(screen, 0, chars, len, rect);
+}
+
+size_t vterm_screen_get_text(const VTermScreen *screen, char *str, size_t len, const VTermRect rect)
+{
+ return _get_chars(screen, 1, str, len, rect);
+}
+
+/* Copy internal to external representation of a screen cell */
+int vterm_screen_get_cell(const VTermScreen *screen, VTermPos pos, VTermScreenCell *cell)
+{
+ ScreenCell *intcell = getcell(screen, pos.row, pos.col);
+ int i;
+
+ if(!intcell)
+ return 0;
+
+ for(i = 0; ; i++) {
+ cell->chars[i] = intcell->chars[i];
+ if(!intcell->chars[i])
+ break;
+ }
+
+ cell->attrs.bold = intcell->pen.bold;
+ cell->attrs.underline = intcell->pen.underline;
+ cell->attrs.italic = intcell->pen.italic;
+ cell->attrs.blink = intcell->pen.blink;
+ cell->attrs.reverse = intcell->pen.reverse ^ screen->global_reverse;
+ cell->attrs.strike = intcell->pen.strike;
+ cell->attrs.font = intcell->pen.font;
+
+ cell->attrs.dwl = intcell->pen.dwl;
+ cell->attrs.dhl = intcell->pen.dhl;
+
+ cell->fg = intcell->pen.fg;
+ cell->bg = intcell->pen.bg;
+
+ if(pos.col < (screen->cols - 1) &&
+ getcell(screen, pos.row, pos.col + 1)->chars[0] == (uint32_t)-1)
+ cell->width = 2;
+ else
+ cell->width = 1;
+
+ return 1;
+}
+
+/* Copy external to internal representation of a screen cell */
+/* static because it's only used internally for sb_popline during resize */
+static int vterm_screen_set_cell(VTermScreen *screen, VTermPos pos, const VTermScreenCell *cell)
+{
+ ScreenCell *intcell = getcell(screen, pos.row, pos.col);
+ int i;
+
+ if(!intcell)
+ return 0;
+
+ for(i = 0; ; i++) {
+ intcell->chars[i] = cell->chars[i];
+ if(!cell->chars[i])
+ break;
+ }
+
+ intcell->pen.bold = cell->attrs.bold;
+ intcell->pen.underline = cell->attrs.underline;
+ intcell->pen.italic = cell->attrs.italic;
+ intcell->pen.blink = cell->attrs.blink;
+ intcell->pen.reverse = cell->attrs.reverse ^ screen->global_reverse;
+ intcell->pen.strike = cell->attrs.strike;
+ intcell->pen.font = cell->attrs.font;
+
+ intcell->pen.fg = cell->fg;
+ intcell->pen.bg = cell->bg;
+
+ if(cell->width == 2)
+ getcell(screen, pos.row, pos.col + 1)->chars[0] = (uint32_t)-1;
+
+ return 1;
+}
+
+int vterm_screen_is_eol(const VTermScreen *screen, VTermPos pos)
+{
+ /* This cell is EOL if this and every cell to the right is black */
+ for(; pos.col < screen->cols; pos.col++) {
+ ScreenCell *cell = getcell(screen, pos.row, pos.col);
+ if(cell->chars[0] != 0)
+ return 0;
+ }
+
+ return 1;
+}
+
+VTermScreen *vterm_obtain_screen(VTerm *vt)
+{
+ if(!vt->screen)
+ vt->screen = screen_new(vt);
+ return vt->screen;
+}
+
+void vterm_screen_enable_altscreen(VTermScreen *screen, int altscreen)
+{
+
+ if(!screen->buffers[1] && altscreen) {
+ int rows, cols;
+ vterm_get_size(screen->vt, &rows, &cols);
+
+ screen->buffers[1] = realloc_buffer(screen, NULL, rows, cols);
+ }
+}
+
+void vterm_screen_set_callbacks(VTermScreen *screen, const VTermScreenCallbacks *callbacks, void *user)
+{
+ screen->callbacks = callbacks;
+ screen->cbdata = user;
+}
+
+void *vterm_screen_get_cbdata(VTermScreen *screen)
+{
+ return screen->cbdata;
+}
+
+void vterm_screen_set_unrecognised_fallbacks(VTermScreen *screen, const VTermParserCallbacks *fallbacks, void *user)
+{
+ vterm_state_set_unrecognised_fallbacks(screen->state, fallbacks, user);
+}
+
+void *vterm_screen_get_unrecognised_fbdata(VTermScreen *screen)
+{
+ return vterm_state_get_unrecognised_fbdata(screen->state);
+}
+
+void vterm_screen_flush_damage(VTermScreen *screen)
+{
+ if(screen->pending_scrollrect.start_row != -1) {
+ vterm_scroll_rect(screen->pending_scrollrect, screen->pending_scroll_downward, screen->pending_scroll_rightward,
+ moverect_user, erase_user, screen);
+
+ screen->pending_scrollrect.start_row = -1;
+ }
+
+ if(screen->damaged.start_row != -1) {
+ if(screen->callbacks && screen->callbacks->damage)
+ (*screen->callbacks->damage)(screen->damaged, screen->cbdata);
+
+ screen->damaged.start_row = -1;
+ }
+}
+
+void vterm_screen_set_damage_merge(VTermScreen *screen, VTermDamageSize size)
+{
+ vterm_screen_flush_damage(screen);
+ screen->damage_merge = size;
+}
+
+static int attrs_differ(VTermAttrMask attrs, ScreenCell *a, ScreenCell *b)
+{
+ if((attrs & VTERM_ATTR_BOLD_MASK) && (a->pen.bold != b->pen.bold))
+ return 1;
+ if((attrs & VTERM_ATTR_UNDERLINE_MASK) && (a->pen.underline != b->pen.underline))
+ return 1;
+ if((attrs & VTERM_ATTR_ITALIC_MASK) && (a->pen.italic != b->pen.italic))
+ return 1;
+ if((attrs & VTERM_ATTR_BLINK_MASK) && (a->pen.blink != b->pen.blink))
+ return 1;
+ if((attrs & VTERM_ATTR_REVERSE_MASK) && (a->pen.reverse != b->pen.reverse))
+ return 1;
+ if((attrs & VTERM_ATTR_STRIKE_MASK) && (a->pen.strike != b->pen.strike))
+ return 1;
+ if((attrs & VTERM_ATTR_FONT_MASK) && (a->pen.font != b->pen.font))
+ return 1;
+ if((attrs & VTERM_ATTR_FOREGROUND_MASK) && !vterm_color_equal(a->pen.fg, b->pen.fg))
+ return 1;
+ if((attrs & VTERM_ATTR_BACKGROUND_MASK) && !vterm_color_equal(a->pen.bg, b->pen.bg))
+ return 1;
+
+ return 0;
+}
+
+int vterm_screen_get_attrs_extent(const VTermScreen *screen, VTermRect *extent, VTermPos pos, VTermAttrMask attrs)
+{
+ int col;
+
+ ScreenCell *target = getcell(screen, pos.row, pos.col);
+
+ // TODO: bounds check
+ extent->start_row = pos.row;
+ extent->end_row = pos.row + 1;
+
+ if(extent->start_col < 0)
+ extent->start_col = 0;
+ if(extent->end_col < 0)
+ extent->end_col = screen->cols;
+
+ for(col = pos.col - 1; col >= extent->start_col; col--)
+ if(attrs_differ(attrs, target, getcell(screen, pos.row, col)))
+ break;
+ extent->start_col = col + 1;
+
+ for(col = pos.col + 1; col < extent->end_col; col++)
+ if(attrs_differ(attrs, target, getcell(screen, pos.row, col)))
+ break;
+ extent->end_col = col - 1;
+
+ return 1;
+}
diff --git a/src/libvterm/src/unicode.c b/src/libvterm/src/unicode.c
new file mode 100644
index 0000000..48d4a85
--- /dev/null
+++ b/src/libvterm/src/unicode.c
@@ -0,0 +1,349 @@
+#include "vterm_internal.h"
+
+// ### The following from http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
+// With modifications:
+// made functions static
+// moved 'combining' table to file scope, so other functions can see it
+// ###################################################################
+
+/*
+ * This is an implementation of wcwidth() and wcswidth() (defined in
+ * IEEE Std 1002.1-2001) for Unicode.
+ *
+ * http://www.opengroup.org/onlinepubs/007904975/functions/wcwidth.html
+ * http://www.opengroup.org/onlinepubs/007904975/functions/wcswidth.html
+ *
+ * In fixed-width output devices, Latin characters all occupy a single
+ * "cell" position of equal width, whereas ideographic CJK characters
+ * occupy two such cells. Interoperability between terminal-line
+ * applications and (teletype-style) character terminals using the
+ * UTF-8 encoding requires agreement on which character should advance
+ * the cursor by how many cell positions. No established formal
+ * standards exist at present on which Unicode character shall occupy
+ * how many cell positions on character terminals. These routines are
+ * a first attempt of defining such behavior based on simple rules
+ * applied to data provided by the Unicode Consortium.
+ *
+ * For some graphical characters, the Unicode standard explicitly
+ * defines a character-cell width via the definition of the East Asian
+ * FullWidth (F), Wide (W), Half-width (H), and Narrow (Na) classes.
+ * In all these cases, there is no ambiguity about which width a
+ * terminal shall use. For characters in the East Asian Ambiguous (A)
+ * class, the width choice depends purely on a preference of backward
+ * compatibility with either historic CJK or Western practice.
+ * Choosing single-width for these characters is easy to justify as
+ * the appropriate long-term solution, as the CJK practice of
+ * displaying these characters as double-width comes from historic
+ * implementation simplicity (8-bit encoded characters were displayed
+ * single-width and 16-bit ones double-width, even for Greek,
+ * Cyrillic, etc.) and not any typographic considerations.
+ *
+ * Much less clear is the choice of width for the Not East Asian
+ * (Neutral) class. Existing practice does not dictate a width for any
+ * of these characters. It would nevertheless make sense
+ * typographically to allocate two character cells to characters such
+ * as for instance EM SPACE or VOLUME INTEGRAL, which cannot be
+ * represented adequately with a single-width glyph. The following
+ * routines at present merely assign a single-cell width to all
+ * neutral characters, in the interest of simplicity. This is not
+ * entirely satisfactory and should be reconsidered before
+ * establishing a formal standard in this area. At the moment, the
+ * decision which Not East Asian (Neutral) characters should be
+ * represented by double-width glyphs cannot yet be answered by
+ * applying a simple rule from the Unicode database content. Setting
+ * up a proper standard for the behavior of UTF-8 character terminals
+ * will require a careful analysis not only of each Unicode character,
+ * but also of each presentation form, something the author of these
+ * routines has avoided to do so far.
+ *
+ * http://www.unicode.org/unicode/reports/tr11/
+ *
+ * Markus Kuhn -- 2007-05-26 (Unicode 5.0)
+ *
+ * Permission to use, copy, modify, and distribute this software
+ * for any purpose and without fee is hereby granted. The author
+ * disclaims all warranties with regard to this software.
+ *
+ * Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
+ */
+
+#if !defined(IS_COMBINING_FUNCTION) || !defined(WCWIDTH_FUNCTION)
+struct interval {
+ int first;
+ int last;
+};
+
+/* sorted list of non-overlapping intervals of non-spacing characters */
+/* generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" */
+static const struct interval combining[] = {
+ { 0x0300, 0x036F }, { 0x0483, 0x0486 }, { 0x0488, 0x0489 },
+ { 0x0591, 0x05BD }, { 0x05BF, 0x05BF }, { 0x05C1, 0x05C2 },
+ { 0x05C4, 0x05C5 }, { 0x05C7, 0x05C7 }, { 0x0600, 0x0603 },
+ { 0x0610, 0x0615 }, { 0x064B, 0x065E }, { 0x0670, 0x0670 },
+ { 0x06D6, 0x06E4 }, { 0x06E7, 0x06E8 }, { 0x06EA, 0x06ED },
+ { 0x070F, 0x070F }, { 0x0711, 0x0711 }, { 0x0730, 0x074A },
+ { 0x07A6, 0x07B0 }, { 0x07EB, 0x07F3 }, { 0x0901, 0x0902 },
+ { 0x093C, 0x093C }, { 0x0941, 0x0948 }, { 0x094D, 0x094D },
+ { 0x0951, 0x0954 }, { 0x0962, 0x0963 }, { 0x0981, 0x0981 },
+ { 0x09BC, 0x09BC }, { 0x09C1, 0x09C4 }, { 0x09CD, 0x09CD },
+ { 0x09E2, 0x09E3 }, { 0x0A01, 0x0A02 }, { 0x0A3C, 0x0A3C },
+ { 0x0A41, 0x0A42 }, { 0x0A47, 0x0A48 }, { 0x0A4B, 0x0A4D },
+ { 0x0A70, 0x0A71 }, { 0x0A81, 0x0A82 }, { 0x0ABC, 0x0ABC },
+ { 0x0AC1, 0x0AC5 }, { 0x0AC7, 0x0AC8 }, { 0x0ACD, 0x0ACD },
+ { 0x0AE2, 0x0AE3 }, { 0x0B01, 0x0B01 }, { 0x0B3C, 0x0B3C },
+ { 0x0B3F, 0x0B3F }, { 0x0B41, 0x0B43 }, { 0x0B4D, 0x0B4D },
+ { 0x0B56, 0x0B56 }, { 0x0B82, 0x0B82 }, { 0x0BC0, 0x0BC0 },
+ { 0x0BCD, 0x0BCD }, { 0x0C3E, 0x0C40 }, { 0x0C46, 0x0C48 },
+ { 0x0C4A, 0x0C4D }, { 0x0C55, 0x0C56 }, { 0x0CBC, 0x0CBC },
+ { 0x0CBF, 0x0CBF }, { 0x0CC6, 0x0CC6 }, { 0x0CCC, 0x0CCD },
+ { 0x0CE2, 0x0CE3 }, { 0x0D41, 0x0D43 }, { 0x0D4D, 0x0D4D },
+ { 0x0DCA, 0x0DCA }, { 0x0DD2, 0x0DD4 }, { 0x0DD6, 0x0DD6 },
+ { 0x0E31, 0x0E31 }, { 0x0E34, 0x0E3A }, { 0x0E47, 0x0E4E },
+ { 0x0EB1, 0x0EB1 }, { 0x0EB4, 0x0EB9 }, { 0x0EBB, 0x0EBC },
+ { 0x0EC8, 0x0ECD }, { 0x0F18, 0x0F19 }, { 0x0F35, 0x0F35 },
+ { 0x0F37, 0x0F37 }, { 0x0F39, 0x0F39 }, { 0x0F71, 0x0F7E },
+ { 0x0F80, 0x0F84 }, { 0x0F86, 0x0F87 }, { 0x0F90, 0x0F97 },
+ { 0x0F99, 0x0FBC }, { 0x0FC6, 0x0FC6 }, { 0x102D, 0x1030 },
+ { 0x1032, 0x1032 }, { 0x1036, 0x1037 }, { 0x1039, 0x1039 },
+ { 0x1058, 0x1059 }, { 0x1160, 0x11FF }, { 0x135F, 0x135F },
+ { 0x1712, 0x1714 }, { 0x1732, 0x1734 }, { 0x1752, 0x1753 },
+ { 0x1772, 0x1773 }, { 0x17B4, 0x17B5 }, { 0x17B7, 0x17BD },
+ { 0x17C6, 0x17C6 }, { 0x17C9, 0x17D3 }, { 0x17DD, 0x17DD },
+ { 0x180B, 0x180D }, { 0x18A9, 0x18A9 }, { 0x1920, 0x1922 },
+ { 0x1927, 0x1928 }, { 0x1932, 0x1932 }, { 0x1939, 0x193B },
+ { 0x1A17, 0x1A18 }, { 0x1B00, 0x1B03 }, { 0x1B34, 0x1B34 },
+ { 0x1B36, 0x1B3A }, { 0x1B3C, 0x1B3C }, { 0x1B42, 0x1B42 },
+ { 0x1B6B, 0x1B73 }, { 0x1DC0, 0x1DCA }, { 0x1DFE, 0x1DFF },
+ { 0x200B, 0x200F }, { 0x202A, 0x202E }, { 0x2060, 0x2063 },
+ { 0x206A, 0x206F }, { 0x20D0, 0x20EF }, { 0x302A, 0x302F },
+ { 0x3099, 0x309A }, { 0xA806, 0xA806 }, { 0xA80B, 0xA80B },
+ { 0xA825, 0xA826 }, { 0xFB1E, 0xFB1E }, { 0xFE00, 0xFE0F },
+ { 0xFE20, 0xFE23 }, { 0xFEFF, 0xFEFF }, { 0xFFF9, 0xFFFB },
+ { 0x10A01, 0x10A03 }, { 0x10A05, 0x10A06 }, { 0x10A0C, 0x10A0F },
+ { 0x10A38, 0x10A3A }, { 0x10A3F, 0x10A3F }, { 0x1D167, 0x1D169 },
+ { 0x1D173, 0x1D182 }, { 0x1D185, 0x1D18B }, { 0x1D1AA, 0x1D1AD },
+ { 0x1D242, 0x1D244 }, { 0xE0001, 0xE0001 }, { 0xE0020, 0xE007F },
+ { 0xE0100, 0xE01EF }
+};
+
+/* auxiliary function for binary search in interval table */
+static int bisearch(uint32_t ucs, const struct interval *table, int max) {
+ int min = 0;
+ int mid;
+
+ if ((int)ucs < table[0].first || (int)ucs > table[max].last)
+ return 0;
+ while (max >= min) {
+ mid = (min + max) / 2;
+ if ((int)ucs > table[mid].last)
+ min = mid + 1;
+ else if ((int)ucs < table[mid].first)
+ max = mid - 1;
+ else
+ return 1;
+ }
+
+ return 0;
+}
+#endif
+
+
+/* The following two functions define the column width of an ISO 10646
+ * character as follows:
+ *
+ * - The null character (U+0000) has a column width of 0.
+ *
+ * - Other C0/C1 control characters and DEL will lead to a return
+ * value of -1.
+ *
+ * - Non-spacing and enclosing combining characters (general
+ * category code Mn or Me in the Unicode database) have a
+ * column width of 0.
+ *
+ * - SOFT HYPHEN (U+00AD) has a column width of 1.
+ *
+ * - Other format characters (general category code Cf in the Unicode
+ * database) and ZERO WIDTH SPACE (U+200B) have a column width of 0.
+ *
+ * - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF)
+ * have a column width of 0.
+ *
+ * - Spacing characters in the East Asian Wide (W) or East Asian
+ * Full-width (F) category as defined in Unicode Technical
+ * Report #11 have a column width of 2.
+ *
+ * - All remaining characters (including all printable
+ * ISO 8859-1 and WGL4 characters, Unicode control characters,
+ * etc.) have a column width of 1.
+ *
+ * This implementation assumes that uint32_t characters are encoded
+ * in ISO 10646.
+ */
+
+#ifdef WCWIDTH_FUNCTION
+/* use a provided wcwidth() function */
+int WCWIDTH_FUNCTION(uint32_t ucs);
+#else
+# define WCWIDTH_FUNCTION mk_wcwidth
+
+static int mk_wcwidth(uint32_t ucs)
+{
+ /* test for 8-bit control characters */
+ if (ucs == 0)
+ return 0;
+ if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0))
+ return -1;
+
+ /* binary search in table of non-spacing characters */
+ if (bisearch(ucs, combining,
+ sizeof(combining) / sizeof(struct interval) - 1))
+ return 0;
+
+ /* if we arrive here, ucs is not a combining or C0/C1 control character */
+
+ return 1 +
+ (ucs >= 0x1100 &&
+ (ucs <= 0x115f || /* Hangul Jamo init. consonants */
+ ucs == 0x2329 || ucs == 0x232a ||
+ (ucs >= 0x2e80 && ucs <= 0xa4cf &&
+ ucs != 0x303f) || /* CJK ... Yi */
+ (ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */
+ (ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility Ideographs */
+ (ucs >= 0xfe10 && ucs <= 0xfe19) || /* Vertical forms */
+ (ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */
+ (ucs >= 0xff00 && ucs <= 0xff60) || /* Fullwidth Forms */
+ (ucs >= 0xffe0 && ucs <= 0xffe6) ||
+ (ucs >= 0x20000 && ucs <= 0x2fffd) ||
+ (ucs >= 0x30000 && ucs <= 0x3fffd)));
+}
+#endif
+
+#if 0 /* unused */
+static int mk_wcswidth(const uint32_t *pwcs, size_t n)
+{
+ int w, width = 0;
+
+ for (;*pwcs && n-- > 0; pwcs++)
+ if ((w = mk_wcwidth(*pwcs)) < 0)
+ return -1;
+ else
+ width += w;
+
+ return width;
+}
+
+
+/*
+ * The following functions are the same as mk_wcwidth() and
+ * mk_wcswidth(), except that spacing characters in the East Asian
+ * Ambiguous (A) category as defined in Unicode Technical Report #11
+ * have a column width of 2. This variant might be useful for users of
+ * CJK legacy encodings who want to migrate to UCS without changing
+ * the traditional terminal character-width behaviour. It is not
+ * otherwise recommended for general use.
+ */
+static int mk_wcwidth_cjk(uint32_t ucs)
+{
+ /* sorted list of non-overlapping intervals of East Asian Ambiguous
+ * characters, generated by "uniset +WIDTH-A -cat=Me -cat=Mn -cat=Cf c" */
+ static const struct interval ambiguous[] = {
+ { 0x00A1, 0x00A1 }, { 0x00A4, 0x00A4 }, { 0x00A7, 0x00A8 },
+ { 0x00AA, 0x00AA }, { 0x00AE, 0x00AE }, { 0x00B0, 0x00B4 },
+ { 0x00B6, 0x00BA }, { 0x00BC, 0x00BF }, { 0x00C6, 0x00C6 },
+ { 0x00D0, 0x00D0 }, { 0x00D7, 0x00D8 }, { 0x00DE, 0x00E1 },
+ { 0x00E6, 0x00E6 }, { 0x00E8, 0x00EA }, { 0x00EC, 0x00ED },
+ { 0x00F0, 0x00F0 }, { 0x00F2, 0x00F3 }, { 0x00F7, 0x00FA },
+ { 0x00FC, 0x00FC }, { 0x00FE, 0x00FE }, { 0x0101, 0x0101 },
+ { 0x0111, 0x0111 }, { 0x0113, 0x0113 }, { 0x011B, 0x011B },
+ { 0x0126, 0x0127 }, { 0x012B, 0x012B }, { 0x0131, 0x0133 },
+ { 0x0138, 0x0138 }, { 0x013F, 0x0142 }, { 0x0144, 0x0144 },
+ { 0x0148, 0x014B }, { 0x014D, 0x014D }, { 0x0152, 0x0153 },
+ { 0x0166, 0x0167 }, { 0x016B, 0x016B }, { 0x01CE, 0x01CE },
+ { 0x01D0, 0x01D0 }, { 0x01D2, 0x01D2 }, { 0x01D4, 0x01D4 },
+ { 0x01D6, 0x01D6 }, { 0x01D8, 0x01D8 }, { 0x01DA, 0x01DA },
+ { 0x01DC, 0x01DC }, { 0x0251, 0x0251 }, { 0x0261, 0x0261 },
+ { 0x02C4, 0x02C4 }, { 0x02C7, 0x02C7 }, { 0x02C9, 0x02CB },
+ { 0x02CD, 0x02CD }, { 0x02D0, 0x02D0 }, { 0x02D8, 0x02DB },
+ { 0x02DD, 0x02DD }, { 0x02DF, 0x02DF }, { 0x0391, 0x03A1 },
+ { 0x03A3, 0x03A9 }, { 0x03B1, 0x03C1 }, { 0x03C3, 0x03C9 },
+ { 0x0401, 0x0401 }, { 0x0410, 0x044F }, { 0x0451, 0x0451 },
+ { 0x2010, 0x2010 }, { 0x2013, 0x2016 }, { 0x2018, 0x2019 },
+ { 0x201C, 0x201D }, { 0x2020, 0x2022 }, { 0x2024, 0x2027 },
+ { 0x2030, 0x2030 }, { 0x2032, 0x2033 }, { 0x2035, 0x2035 },
+ { 0x203B, 0x203B }, { 0x203E, 0x203E }, { 0x2074, 0x2074 },
+ { 0x207F, 0x207F }, { 0x2081, 0x2084 }, { 0x20AC, 0x20AC },
+ { 0x2103, 0x2103 }, { 0x2105, 0x2105 }, { 0x2109, 0x2109 },
+ { 0x2113, 0x2113 }, { 0x2116, 0x2116 }, { 0x2121, 0x2122 },
+ { 0x2126, 0x2126 }, { 0x212B, 0x212B }, { 0x2153, 0x2154 },
+ { 0x215B, 0x215E }, { 0x2160, 0x216B }, { 0x2170, 0x2179 },
+ { 0x2190, 0x2199 }, { 0x21B8, 0x21B9 }, { 0x21D2, 0x21D2 },
+ { 0x21D4, 0x21D4 }, { 0x21E7, 0x21E7 }, { 0x2200, 0x2200 },
+ { 0x2202, 0x2203 }, { 0x2207, 0x2208 }, { 0x220B, 0x220B },
+ { 0x220F, 0x220F }, { 0x2211, 0x2211 }, { 0x2215, 0x2215 },
+ { 0x221A, 0x221A }, { 0x221D, 0x2220 }, { 0x2223, 0x2223 },
+ { 0x2225, 0x2225 }, { 0x2227, 0x222C }, { 0x222E, 0x222E },
+ { 0x2234, 0x2237 }, { 0x223C, 0x223D }, { 0x2248, 0x2248 },
+ { 0x224C, 0x224C }, { 0x2252, 0x2252 }, { 0x2260, 0x2261 },
+ { 0x2264, 0x2267 }, { 0x226A, 0x226B }, { 0x226E, 0x226F },
+ { 0x2282, 0x2283 }, { 0x2286, 0x2287 }, { 0x2295, 0x2295 },
+ { 0x2299, 0x2299 }, { 0x22A5, 0x22A5 }, { 0x22BF, 0x22BF },
+ { 0x2312, 0x2312 }, { 0x2460, 0x24E9 }, { 0x24EB, 0x254B },
+ { 0x2550, 0x2573 }, { 0x2580, 0x258F }, { 0x2592, 0x2595 },
+ { 0x25A0, 0x25A1 }, { 0x25A3, 0x25A9 }, { 0x25B2, 0x25B3 },
+ { 0x25B6, 0x25B7 }, { 0x25BC, 0x25BD }, { 0x25C0, 0x25C1 },
+ { 0x25C6, 0x25C8 }, { 0x25CB, 0x25CB }, { 0x25CE, 0x25D1 },
+ { 0x25E2, 0x25E5 }, { 0x25EF, 0x25EF }, { 0x2605, 0x2606 },
+ { 0x2609, 0x2609 }, { 0x260E, 0x260F }, { 0x2614, 0x2615 },
+ { 0x261C, 0x261C }, { 0x261E, 0x261E }, { 0x2640, 0x2640 },
+ { 0x2642, 0x2642 }, { 0x2660, 0x2661 }, { 0x2663, 0x2665 },
+ { 0x2667, 0x266A }, { 0x266C, 0x266D }, { 0x266F, 0x266F },
+ { 0x273D, 0x273D }, { 0x2776, 0x277F }, { 0xE000, 0xF8FF },
+ { 0xFFFD, 0xFFFD }, { 0xF0000, 0xFFFFD }, { 0x100000, 0x10FFFD }
+ };
+
+ /* binary search in table of non-spacing characters */
+ if (bisearch(ucs, ambiguous,
+ sizeof(ambiguous) / sizeof(struct interval) - 1))
+ return 2;
+
+ return mk_wcwidth(ucs);
+}
+
+static int mk_wcswidth_cjk(const uint32_t *pwcs, size_t n)
+{
+ int w, width = 0;
+
+ for (;*pwcs && n-- > 0; pwcs++)
+ if ((w = mk_wcwidth_cjk(*pwcs)) < 0)
+ return -1;
+ else
+ width += w;
+
+ return width;
+}
+#endif
+
+#ifdef IS_COMBINING_FUNCTION
+/* Use a provided is_combining() function. */
+int IS_COMBINING_FUNCTION(uint32_t codepoint);
+#else
+# define IS_COMBINING_FUNCTION vterm_is_combining
+ static int
+vterm_is_combining(uint32_t codepoint)
+{
+ return bisearch(codepoint, combining, sizeof(combining) / sizeof(struct interval) - 1);
+}
+#endif
+
+// ################################
+// ### The rest added by Paul Evans
+
+INTERNAL int vterm_unicode_width(uint32_t codepoint)
+{
+ return WCWIDTH_FUNCTION(codepoint);
+}
+
+INTERNAL int vterm_unicode_is_combining(uint32_t codepoint)
+{
+ return IS_COMBINING_FUNCTION(codepoint);
+}
diff --git a/src/libvterm/src/utf8.h b/src/libvterm/src/utf8.h
new file mode 100644
index 0000000..886a1ca
--- /dev/null
+++ b/src/libvterm/src/utf8.h
@@ -0,0 +1,47 @@
+/* The following functions copied and adapted from libtermkey
+ *
+ * http://www.leonerd.org.uk/code/libtermkey/
+ */
+unsigned int utf8_seqlen(long codepoint);
+
+#if defined(DEFINE_INLINES) || USE_INLINE
+INLINE unsigned int utf8_seqlen(long codepoint)
+{
+ if(codepoint < 0x0000080) return 1;
+ if(codepoint < 0x0000800) return 2;
+ if(codepoint < 0x0010000) return 3;
+ if(codepoint < 0x0200000) return 4;
+ if(codepoint < 0x4000000) return 5;
+ return 6;
+}
+#endif
+
+/* Does NOT NUL-terminate the buffer */
+int fill_utf8(long codepoint, char *str);
+
+#if defined(DEFINE_INLINES) || USE_INLINE
+INLINE int fill_utf8(long codepoint, char *str)
+{
+ int nbytes = utf8_seqlen(codepoint);
+
+ // This is easier done backwards
+ int b = nbytes;
+ while(b > 1) {
+ b--;
+ str[b] = 0x80 | (codepoint & 0x3f);
+ codepoint >>= 6;
+ }
+
+ switch(nbytes) {
+ case 1: str[0] = (codepoint & 0x7f); break;
+ case 2: str[0] = 0xc0 | (codepoint & 0x1f); break;
+ case 3: str[0] = 0xe0 | (codepoint & 0x0f); break;
+ case 4: str[0] = 0xf0 | (codepoint & 0x07); break;
+ case 5: str[0] = 0xf8 | (codepoint & 0x03); break;
+ case 6: str[0] = 0xfc | (codepoint & 0x01); break;
+ }
+
+ return nbytes;
+}
+#endif
+/* end copy */
diff --git a/src/libvterm/src/vterm.c b/src/libvterm/src/vterm.c
new file mode 100644
index 0000000..5e4722c
--- /dev/null
+++ b/src/libvterm/src/vterm.c
@@ -0,0 +1,425 @@
+#define DEFINE_INLINES
+
+/* vim: set sw=2 : */
+#include "vterm_internal.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "utf8.h"
+
+/*****************
+ * API functions *
+ *****************/
+
+static void *default_malloc(size_t size, void *allocdata UNUSED)
+{
+ void *ptr = malloc(size);
+ if(ptr)
+ memset(ptr, 0, size);
+ return ptr;
+}
+
+static void default_free(void *ptr, void *allocdata UNUSED)
+{
+ free(ptr);
+}
+
+static VTermAllocatorFunctions default_allocator = {
+ &default_malloc, // malloc
+ &default_free // free
+};
+
+VTerm *vterm_new(int rows, int cols)
+{
+ return vterm_new_with_allocator(rows, cols, &default_allocator, NULL);
+}
+
+VTerm *vterm_new_with_allocator(int rows, int cols, VTermAllocatorFunctions *funcs, void *allocdata)
+{
+ /* Need to bootstrap using the allocator function directly */
+ VTerm *vt = (*funcs->malloc)(sizeof(VTerm), allocdata);
+
+ if (vt == NULL)
+ return NULL;
+ vt->allocator = funcs;
+ vt->allocdata = allocdata;
+
+ vt->rows = rows;
+ vt->cols = cols;
+
+ vt->parser.state = NORMAL;
+
+ vt->parser.callbacks = NULL;
+ vt->parser.cbdata = NULL;
+
+ vt->parser.strbuffer_len = 500; /* should be able to hold an OSC string */
+ vt->parser.strbuffer_cur = 0;
+ vt->parser.strbuffer = vterm_allocator_malloc(vt, vt->parser.strbuffer_len);
+ if (vt->parser.strbuffer == NULL)
+ {
+ vterm_allocator_free(vt, vt);
+ return NULL;
+ }
+
+ vt->outbuffer_len = 200;
+ vt->outbuffer_cur = 0;
+ vt->outbuffer = vterm_allocator_malloc(vt, vt->outbuffer_len);
+ if (vt->outbuffer == NULL)
+ {
+ vterm_allocator_free(vt, vt->parser.strbuffer);
+ vterm_allocator_free(vt, vt);
+ return NULL;
+ }
+
+ return vt;
+}
+
+void vterm_free(VTerm *vt)
+{
+ if(vt->screen)
+ vterm_screen_free(vt->screen);
+
+ if(vt->state)
+ vterm_state_free(vt->state);
+
+ vterm_allocator_free(vt, vt->parser.strbuffer);
+ vterm_allocator_free(vt, vt->outbuffer);
+
+ vterm_allocator_free(vt, vt);
+}
+
+INTERNAL void *vterm_allocator_malloc(VTerm *vt, size_t size)
+{
+ return (*vt->allocator->malloc)(size, vt->allocdata);
+}
+
+/*
+ * Free "ptr" unless it is NULL.
+ */
+INTERNAL void vterm_allocator_free(VTerm *vt, void *ptr)
+{
+ if (ptr)
+ (*vt->allocator->free)(ptr, vt->allocdata);
+}
+
+void vterm_get_size(const VTerm *vt, int *rowsp, int *colsp)
+{
+ if(rowsp)
+ *rowsp = vt->rows;
+ if(colsp)
+ *colsp = vt->cols;
+}
+
+void vterm_set_size(VTerm *vt, int rows, int cols)
+{
+ vt->rows = rows;
+ vt->cols = cols;
+
+ if(vt->parser.callbacks && vt->parser.callbacks->resize)
+ (*vt->parser.callbacks->resize)(rows, cols, vt->parser.cbdata);
+}
+
+int vterm_get_utf8(const VTerm *vt)
+{
+ return vt->mode.utf8;
+}
+
+void vterm_set_utf8(VTerm *vt, int is_utf8)
+{
+ vt->mode.utf8 = is_utf8;
+}
+
+INTERNAL void vterm_push_output_bytes(VTerm *vt, const char *bytes, size_t len)
+{
+ if(len > vt->outbuffer_len - vt->outbuffer_cur) {
+ DEBUG_LOG("vterm_push_output(): buffer overflow; truncating output\n");
+ len = vt->outbuffer_len - vt->outbuffer_cur;
+ }
+
+ memcpy(vt->outbuffer + vt->outbuffer_cur, bytes, len);
+ vt->outbuffer_cur += len;
+}
+
+static int outbuffer_is_full(VTerm *vt)
+{
+ return vt->outbuffer_cur >= vt->outbuffer_len - 1;
+}
+
+#if (defined(_XOPEN_SOURCE) && _XOPEN_SOURCE >= 500) \
+ || defined(_ISOC99_SOURCE) || defined(_BSD_SOURCE)
+# undef VSNPRINTF
+# define VSNPRINTF vsnprintf
+#else
+# ifdef VSNPRINTF
+/* Use a provided vsnprintf() function. */
+int VSNPRINTF(char *str, size_t str_m, const char *fmt, va_list ap);
+# endif
+#endif
+
+
+INTERNAL void vterm_push_output_vsprintf(VTerm *vt, const char *format, va_list args)
+{
+ int written;
+#ifndef VSNPRINTF
+ /* When vsnprintf() is not available (C90) fall back to vsprintf(). */
+ char buffer[1024]; /* 1Kbyte is enough for everybody, right? */
+#endif
+
+ if(outbuffer_is_full(vt)) {
+ DEBUG_LOG("vterm_push_output(): buffer overflow; truncating output\n");
+ return;
+ }
+
+#ifdef VSNPRINTF
+ written = VSNPRINTF(vt->outbuffer + vt->outbuffer_cur,
+ vt->outbuffer_len - vt->outbuffer_cur,
+ format, args);
+
+ if(written == (int)(vt->outbuffer_len - vt->outbuffer_cur)) {
+ /* output was truncated */
+ vt->outbuffer_cur = vt->outbuffer_len - 1;
+ }
+ else
+ vt->outbuffer_cur += written;
+#else
+ written = vsprintf(buffer, format, args);
+
+ if(written >= (int)(vt->outbuffer_len - vt->outbuffer_cur - 1)) {
+ /* output was truncated */
+ written = vt->outbuffer_len - vt->outbuffer_cur - 1;
+ }
+ if (written > 0)
+ {
+ strncpy(vt->outbuffer + vt->outbuffer_cur, buffer, written + 1);
+ vt->outbuffer_cur += written;
+ }
+#endif
+}
+
+INTERNAL void vterm_push_output_sprintf(VTerm *vt, const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ vterm_push_output_vsprintf(vt, format, args);
+ va_end(args);
+}
+
+INTERNAL void vterm_push_output_sprintf_ctrl(VTerm *vt, unsigned char ctrl, const char *fmt, ...)
+{
+ size_t orig_cur = vt->outbuffer_cur;
+ va_list args;
+
+ if(ctrl >= 0x80 && !vt->mode.ctrl8bit)
+ vterm_push_output_sprintf(vt, ESC_S "%c", ctrl - 0x40);
+ else
+ vterm_push_output_sprintf(vt, "%c", ctrl);
+
+ va_start(args, fmt);
+ vterm_push_output_vsprintf(vt, fmt, args);
+ va_end(args);
+
+ if(outbuffer_is_full(vt))
+ vt->outbuffer_cur = orig_cur;
+}
+
+INTERNAL void vterm_push_output_sprintf_dcs(VTerm *vt, const char *fmt, ...)
+{
+ size_t orig_cur = vt->outbuffer_cur;
+ va_list args;
+
+ if(!vt->mode.ctrl8bit)
+ vterm_push_output_sprintf(vt, ESC_S "%c", C1_DCS - 0x40);
+ else
+ vterm_push_output_sprintf(vt, "%c", C1_DCS);
+
+ va_start(args, fmt);
+ vterm_push_output_vsprintf(vt, fmt, args);
+ va_end(args);
+
+ vterm_push_output_sprintf_ctrl(vt, C1_ST, "");
+
+ if(outbuffer_is_full(vt))
+ vt->outbuffer_cur = orig_cur;
+}
+
+size_t vterm_output_get_buffer_size(const VTerm *vt)
+{
+ return vt->outbuffer_len;
+}
+
+size_t vterm_output_get_buffer_current(const VTerm *vt)
+{
+ return vt->outbuffer_cur;
+}
+
+size_t vterm_output_get_buffer_remaining(const VTerm *vt)
+{
+ return vt->outbuffer_len - vt->outbuffer_cur;
+}
+
+size_t vterm_output_read(VTerm *vt, char *buffer, size_t len)
+{
+ if(len > vt->outbuffer_cur)
+ len = vt->outbuffer_cur;
+
+ memcpy(buffer, vt->outbuffer, len);
+
+ if(len < vt->outbuffer_cur)
+ memmove(vt->outbuffer, vt->outbuffer + len, vt->outbuffer_cur - len);
+
+ vt->outbuffer_cur -= len;
+
+ return len;
+}
+
+VTermValueType vterm_get_attr_type(VTermAttr attr)
+{
+ switch(attr) {
+ case VTERM_ATTR_BOLD: return VTERM_VALUETYPE_BOOL;
+ case VTERM_ATTR_UNDERLINE: return VTERM_VALUETYPE_INT;
+ case VTERM_ATTR_ITALIC: return VTERM_VALUETYPE_BOOL;
+ case VTERM_ATTR_BLINK: return VTERM_VALUETYPE_BOOL;
+ case VTERM_ATTR_REVERSE: return VTERM_VALUETYPE_BOOL;
+ case VTERM_ATTR_STRIKE: return VTERM_VALUETYPE_BOOL;
+ case VTERM_ATTR_FONT: return VTERM_VALUETYPE_INT;
+ case VTERM_ATTR_FOREGROUND: return VTERM_VALUETYPE_COLOR;
+ case VTERM_ATTR_BACKGROUND: return VTERM_VALUETYPE_COLOR;
+
+ case VTERM_N_ATTRS: return 0;
+ }
+ return 0; /* UNREACHABLE */
+}
+
+VTermValueType vterm_get_prop_type(VTermProp prop)
+{
+ switch(prop) {
+ case VTERM_PROP_CURSORVISIBLE: return VTERM_VALUETYPE_BOOL;
+ case VTERM_PROP_CURSORBLINK: return VTERM_VALUETYPE_BOOL;
+ case VTERM_PROP_ALTSCREEN: return VTERM_VALUETYPE_BOOL;
+ case VTERM_PROP_TITLE: return VTERM_VALUETYPE_STRING;
+ case VTERM_PROP_ICONNAME: return VTERM_VALUETYPE_STRING;
+ case VTERM_PROP_REVERSE: return VTERM_VALUETYPE_BOOL;
+ case VTERM_PROP_CURSORSHAPE: return VTERM_VALUETYPE_INT;
+ case VTERM_PROP_MOUSE: return VTERM_VALUETYPE_INT;
+ case VTERM_PROP_CURSORCOLOR: return VTERM_VALUETYPE_STRING;
+
+ case VTERM_N_PROPS: return 0;
+ }
+ return 0; /* UNREACHABLE */
+}
+
+void vterm_scroll_rect(VTermRect rect,
+ int downward,
+ int rightward,
+ int (*moverect)(VTermRect src, VTermRect dest, void *user),
+ int (*eraserect)(VTermRect rect, int selective, void *user),
+ void *user)
+{
+ VTermRect src;
+ VTermRect dest;
+
+ if(abs(downward) >= rect.end_row - rect.start_row ||
+ abs(rightward) >= rect.end_col - rect.start_col) {
+ /* Scroll more than area; just erase the lot */
+ (*eraserect)(rect, 0, user);
+ return;
+ }
+
+ if(rightward >= 0) {
+ /* rect: [XXX................]
+ * src: [----------------]
+ * dest: [----------------]
+ */
+ dest.start_col = rect.start_col;
+ dest.end_col = rect.end_col - rightward;
+ src.start_col = rect.start_col + rightward;
+ src.end_col = rect.end_col;
+ }
+ else {
+ /* rect: [................XXX]
+ * src: [----------------]
+ * dest: [----------------]
+ */
+ int leftward = -rightward;
+ dest.start_col = rect.start_col + leftward;
+ dest.end_col = rect.end_col;
+ src.start_col = rect.start_col;
+ src.end_col = rect.end_col - leftward;
+ }
+
+ if(downward >= 0) {
+ dest.start_row = rect.start_row;
+ dest.end_row = rect.end_row - downward;
+ src.start_row = rect.start_row + downward;
+ src.end_row = rect.end_row;
+ }
+ else {
+ int upward = -downward;
+ dest.start_row = rect.start_row + upward;
+ dest.end_row = rect.end_row;
+ src.start_row = rect.start_row;
+ src.end_row = rect.end_row - upward;
+ }
+
+ if(moverect)
+ (*moverect)(dest, src, user);
+
+ if(downward > 0)
+ rect.start_row = rect.end_row - downward;
+ else if(downward < 0)
+ rect.end_row = rect.start_row - downward;
+
+ if(rightward > 0)
+ rect.start_col = rect.end_col - rightward;
+ else if(rightward < 0)
+ rect.end_col = rect.start_col - rightward;
+
+ (*eraserect)(rect, 0, user);
+}
+
+void vterm_copy_cells(VTermRect dest,
+ VTermRect src,
+ void (*copycell)(VTermPos dest, VTermPos src, void *user),
+ void *user)
+{
+ int downward = src.start_row - dest.start_row;
+ int rightward = src.start_col - dest.start_col;
+
+ int init_row, test_row, init_col, test_col;
+ int inc_row, inc_col;
+
+ VTermPos pos;
+
+ if(downward < 0) {
+ init_row = dest.end_row - 1;
+ test_row = dest.start_row - 1;
+ inc_row = -1;
+ }
+ else /* downward >= 0 */ {
+ init_row = dest.start_row;
+ test_row = dest.end_row;
+ inc_row = +1;
+ }
+
+ if(rightward < 0) {
+ init_col = dest.end_col - 1;
+ test_col = dest.start_col - 1;
+ inc_col = -1;
+ }
+ else /* rightward >= 0 */ {
+ init_col = dest.start_col;
+ test_col = dest.end_col;
+ inc_col = +1;
+ }
+
+ for(pos.row = init_row; pos.row != test_row; pos.row += inc_row)
+ for(pos.col = init_col; pos.col != test_col; pos.col += inc_col) {
+ VTermPos srcpos;
+ srcpos.row = pos.row + downward;
+ srcpos.col = pos.col + rightward;
+ (*copycell)(pos, srcpos, user);
+ }
+}
diff --git a/src/libvterm/src/vterm_internal.h b/src/libvterm/src/vterm_internal.h
new file mode 100644
index 0000000..2ef358c
--- /dev/null
+++ b/src/libvterm/src/vterm_internal.h
@@ -0,0 +1,263 @@
+#ifndef __VTERM_INTERNAL_H__
+#define __VTERM_INTERNAL_H__
+
+#include "vterm.h"
+
+#include <stdarg.h>
+
+#if defined(__GNUC__) && !defined(__MINGW32__)
+# define INTERNAL __attribute__((visibility("internal")))
+# define UNUSED __attribute__((unused))
+#else
+# define INTERNAL
+# define UNUSED
+#endif
+
+#ifdef DEBUG
+# define DEBUG_LOG(s) fprintf(stderr, s)
+# define DEBUG_LOG1(s, a) fprintf(stderr, s, a)
+# define DEBUG_LOG2(s, a, b) fprintf(stderr, s, a, b)
+# define DEBUG_LOG3(s, a, b, c) fprintf(stderr, s, a, b, c)
+#else
+# define DEBUG_LOG(s)
+# define DEBUG_LOG1(s, a)
+# define DEBUG_LOG2(s, a, b)
+# define DEBUG_LOG3(s, a, b, c)
+#endif
+
+#define ESC_S "\x1b"
+
+#define INTERMED_MAX 16
+
+#define CSI_ARGS_MAX 16
+#define CSI_LEADER_MAX 16
+
+typedef struct VTermEncoding VTermEncoding;
+
+typedef struct {
+ VTermEncoding *enc;
+
+ // This size should be increased if required by other stateful encodings
+ char data[4*sizeof(uint32_t)];
+} VTermEncodingInstance;
+
+struct VTermPen
+{
+ VTermColor fg;
+ VTermColor bg;
+ unsigned int bold:1;
+ unsigned int underline:2;
+ unsigned int italic:1;
+ unsigned int blink:1;
+ unsigned int reverse:1;
+ unsigned int strike:1;
+ unsigned int font:4; /* To store 0-9 */
+};
+
+int vterm_color_equal(VTermColor a, VTermColor b);
+
+#if defined(DEFINE_INLINES) || USE_INLINE
+INLINE int vterm_color_equal(VTermColor a, VTermColor b)
+{
+ return a.red == b.red && a.green == b.green && a.blue == b.blue;
+}
+#endif
+
+struct VTermState
+{
+ VTerm *vt;
+
+ const VTermStateCallbacks *callbacks;
+ void *cbdata;
+
+ const VTermParserCallbacks *fallbacks;
+ void *fbdata;
+
+ int rows;
+ int cols;
+
+ /* Current cursor position */
+ VTermPos pos;
+
+ int at_phantom; /* True if we're on the "81st" phantom column to defer a wraparound */
+
+ int scrollregion_top;
+ int scrollregion_bottom; /* -1 means unbounded */
+#define SCROLLREGION_BOTTOM(state) ((state)->scrollregion_bottom > -1 ? (state)->scrollregion_bottom : (state)->rows)
+ int scrollregion_left;
+#define SCROLLREGION_LEFT(state) ((state)->mode.leftrightmargin ? (state)->scrollregion_left : 0)
+ int scrollregion_right; /* -1 means unbounded */
+#define SCROLLREGION_RIGHT(state) ((state)->mode.leftrightmargin && (state)->scrollregion_right > -1 ? (state)->scrollregion_right : (state)->cols)
+
+ /* Bitvector of tab stops */
+ unsigned char *tabstops;
+
+ VTermLineInfo *lineinfo;
+#define ROWWIDTH(state,row) ((state)->lineinfo[(row)].doublewidth ? ((state)->cols / 2) : (state)->cols)
+#define THISROWWIDTH(state) ROWWIDTH(state, (state)->pos.row)
+
+ /* Mouse state */
+ int mouse_col, mouse_row;
+ int mouse_buttons;
+ int mouse_flags;
+
+ enum { MOUSE_X10, MOUSE_UTF8, MOUSE_SGR, MOUSE_RXVT } mouse_protocol;
+
+ /* Last glyph output, for Unicode recombining purposes */
+ uint32_t *combine_chars;
+ size_t combine_chars_size; // Number of ELEMENTS in the above
+ int combine_width; // The width of the glyph above
+ VTermPos combine_pos; // Position before movement
+
+ struct {
+ unsigned int keypad:1;
+ unsigned int cursor:1;
+ unsigned int autowrap:1;
+ unsigned int insert:1;
+ unsigned int newline:1;
+ unsigned int cursor_visible:1;
+ unsigned int cursor_blink:1;
+ unsigned int cursor_shape:2;
+ unsigned int alt_screen:1;
+ unsigned int origin:1;
+ unsigned int screen:1;
+ unsigned int leftrightmargin:1;
+ unsigned int bracketpaste:1;
+ unsigned int report_focus:1;
+ } mode;
+
+ VTermEncodingInstance encoding[4], encoding_utf8;
+ int gl_set, gr_set, gsingle_set;
+
+ struct VTermPen pen;
+
+ VTermColor default_fg;
+ VTermColor default_bg;
+ VTermColor colors[16]; // Store the 8 ANSI and the 8 ANSI high-brights only
+
+ int fg_index;
+ int bg_index;
+ int bold_is_highbright;
+
+ unsigned int protected_cell : 1;
+
+ /* Saved state under DEC mode 1048/1049 */
+ struct {
+ VTermPos pos;
+ struct VTermPen pen;
+
+ struct {
+ unsigned int cursor_visible:1;
+ unsigned int cursor_blink:1;
+ unsigned int cursor_shape:2;
+ } mode;
+ } saved;
+};
+
+typedef enum {
+ VTERM_PARSER_OSC,
+ VTERM_PARSER_DCS,
+
+ VTERM_N_PARSER_TYPES
+} VTermParserStringType;
+
+struct VTerm
+{
+ VTermAllocatorFunctions *allocator;
+ void *allocdata;
+
+ int rows;
+ int cols;
+
+ struct {
+ unsigned int utf8:1;
+ unsigned int ctrl8bit:1;
+ } mode;
+
+ struct {
+ enum VTermParserState {
+ NORMAL,
+ CSI_LEADER,
+ CSI_ARGS,
+ CSI_INTERMED,
+ ESC,
+ /* below here are the "string states" */
+ STRING,
+ ESC_IN_STRING,
+ } state;
+
+ int intermedlen;
+ char intermed[INTERMED_MAX];
+
+ int csi_leaderlen;
+ char csi_leader[CSI_LEADER_MAX];
+
+ int csi_argi;
+ long csi_args[CSI_ARGS_MAX];
+
+ const VTermParserCallbacks *callbacks;
+ void *cbdata;
+
+ VTermParserStringType stringtype;
+ char *strbuffer;
+ size_t strbuffer_len;
+ size_t strbuffer_cur;
+ } parser;
+
+ /* len == malloc()ed size; cur == number of valid bytes */
+
+ char *outbuffer;
+ size_t outbuffer_len;
+ size_t outbuffer_cur;
+
+ VTermState *state;
+ VTermScreen *screen;
+};
+
+struct VTermEncoding {
+ void (*init) (VTermEncoding *enc, void *data);
+ void (*decode)(VTermEncoding *enc, void *data,
+ uint32_t cp[], int *cpi, int cplen,
+ const char bytes[], size_t *pos, size_t len);
+};
+
+typedef enum {
+ ENC_UTF8,
+ ENC_SINGLE_94
+} VTermEncodingType;
+
+void *vterm_allocator_malloc(VTerm *vt, size_t size);
+void vterm_allocator_free(VTerm *vt, void *ptr);
+
+void vterm_push_output_bytes(VTerm *vt, const char *bytes, size_t len);
+void vterm_push_output_vsprintf(VTerm *vt, const char *format, va_list args);
+void vterm_push_output_sprintf(VTerm *vt, const char *format, ...);
+void vterm_push_output_sprintf_ctrl(VTerm *vt, unsigned char ctrl, const char *fmt, ...);
+void vterm_push_output_sprintf_dcs(VTerm *vt, const char *fmt, ...);
+
+void vterm_state_free(VTermState *state);
+
+void vterm_state_newpen(VTermState *state);
+void vterm_state_resetpen(VTermState *state);
+void vterm_state_setpen(VTermState *state, const long args[], int argcount);
+int vterm_state_getpen(VTermState *state, long args[], int argcount);
+void vterm_state_savepen(VTermState *state, int save);
+
+enum {
+ C1_SS3 = 0x8f,
+ C1_DCS = 0x90,
+ C1_CSI = 0x9b,
+ C1_ST = 0x9c,
+ C1_OSC = 0x9d,
+};
+
+void vterm_state_push_output_sprintf_CSI(VTermState *vts, const char *format, ...);
+
+void vterm_screen_free(VTermScreen *screen);
+
+VTermEncoding *vterm_lookup_encoding(VTermEncodingType type, char designation);
+
+int vterm_unicode_width(uint32_t codepoint);
+int vterm_unicode_is_combining(uint32_t codepoint);
+
+#endif
diff --git a/src/libvterm/t/02parser.test b/src/libvterm/t/02parser.test
new file mode 100644
index 0000000..66d487d
--- /dev/null
+++ b/src/libvterm/t/02parser.test
@@ -0,0 +1,200 @@
+INIT
+UTF8 0
+WANTPARSER
+
+!Basic text
+PUSH "hello"
+ text 0x68, 0x65, 0x6c, 0x6c, 0x6f
+
+!C0
+PUSH "\x03"
+ control 3
+
+PUSH "\x1f"
+ control 0x1f
+
+!C1 8bit
+PUSH "\x83"
+ control 0x83
+
+PUSH "\x9f"
+ control 0x9f
+
+!C1 7bit
+PUSH "\e\x43"
+ control 0x83
+
+PUSH "\e\x5f"
+ control 0x9f
+
+!High bytes
+PUSH "\xa0\xcc\xfe"
+ text 0xa0, 0xcc, 0xfe
+
+!Mixed
+PUSH "1\n2"
+ text 0x31
+ control 10
+ text 0x32
+
+!Escape
+PUSH "\e="
+ escape "="
+
+!Escape 2-byte
+PUSH "\e(X"
+ escape "(X"
+
+!Split write Escape
+PUSH "\e("
+PUSH "Y"
+ escape "(Y"
+
+!Escape cancels Escape, starts another
+PUSH "\e(\e)Z"
+ escape ")Z"
+
+!CAN cancels Escape, returns to normal mode
+PUSH "\e(\x{18}AB"
+ text 0x41, 0x42
+
+!C0 in Escape interrupts and continues
+PUSH "\e(\nX"
+ control 10
+ escape "(X"
+
+!CSI 0 args
+PUSH "\e[a"
+ csi 0x61 *
+
+!CSI 1 arg
+PUSH "\e[9b"
+ csi 0x62 9
+
+!CSI 2 args
+PUSH "\e[3;4c"
+ csi 0x63 3,4
+
+!CSI 1 arg 1 sub
+PUSH "\e[1:2c"
+ csi 0x63 1+,2
+
+!CSI many digits
+PUSH "\e[678d"
+ csi 0x64 678
+
+!CSI leading zero
+PUSH "\e[007e"
+ csi 0x65 7
+
+!CSI qmark
+PUSH "\e[?2;7f"
+ csi 0x66 L=3f 2,7
+
+!CSI greater
+PUSH "\e[>c"
+ csi 0x63 L=3e *
+
+!CSI SP
+PUSH "\e[12 q"
+ csi 0x71 12 I=20
+
+!Mixed CSI
+PUSH "A\e[8mB"
+ text 0x41
+ csi 0x6d 8
+ text 0x42
+
+!Split write
+PUSH "\e"
+PUSH "[a"
+ csi 0x61 *
+PUSH "foo\e["
+ text 0x66, 0x6f, 0x6f
+PUSH "4b"
+ csi 0x62 4
+PUSH "\e[12;"
+PUSH "3c"
+ csi 0x63 12,3
+
+!Escape cancels CSI, starts Escape
+PUSH "\e[123\e9"
+ escape "9"
+
+!CAN cancels CSI, returns to normal mode
+PUSH "\e[12\x{18}AB"
+ text 0x41, 0x42
+
+!C0 in Escape interrupts and continues
+PUSH "\e[12\n;3X"
+ control 10
+ csi 0x58 12,3
+
+!OSC BEL
+PUSH "\e]1;Hello\x07"
+ osc "1;Hello"
+
+!OSC ST (7bit)
+PUSH "\e]1;Hello\e\\"
+ osc "1;Hello"
+
+!OSC ST (8bit)
+PUSH "\x{9d}1;Hello\x9c"
+ osc "1;Hello"
+
+!Escape cancels OSC, starts Escape
+PUSH "\e]Something\e9"
+ escape "9"
+
+!CAN cancels OSC, returns to normal mode
+PUSH "\e]12\x{18}AB"
+ text 0x41, 0x42
+
+!C0 in OSC interrupts and continues
+PUSH "\e]2;\nBye\x07"
+ control 10
+ osc "2;Bye"
+
+!DCS BEL
+PUSH "\ePHello\x07"
+ dcs "Hello"
+
+!DCS ST (7bit)
+PUSH "\ePHello\e\\"
+ dcs "Hello"
+
+!DCS ST (8bit)
+PUSH "\x{90}Hello\x9c"
+ dcs "Hello"
+
+!Escape cancels DCS, starts Escape
+PUSH "\ePSomething\e9"
+ escape "9"
+
+!CAN cancels DCS, returns to normal mode
+PUSH "\eP12\x{18}AB"
+ text 0x41, 0x42
+
+!C0 in OSC interrupts and continues
+PUSH "\ePBy\ne\x07"
+ control 10
+ dcs "Bye"
+
+!NUL ignored
+PUSH "\x{00}"
+
+!NUL ignored within CSI
+PUSH "\e[12\x{00}3m"
+ csi 0x6d 123
+
+!DEL ignored
+PUSH "\x{7f}"
+
+!DEL ignored within CSI
+PUSH "\e[12\x{7f}3m"
+ csi 0x6d 123
+
+!DEL inside text"
+PUSH "AB\x{7f}C"
+ text 0x41,0x42
+ text 0x43
diff --git a/src/libvterm/t/03encoding_utf8.test b/src/libvterm/t/03encoding_utf8.test
new file mode 100644
index 0000000..7ee16ac
--- /dev/null
+++ b/src/libvterm/t/03encoding_utf8.test
@@ -0,0 +1,122 @@
+INIT
+WANTENCODING
+
+!Low
+ENCIN "123"
+ encout 0x31,0x32,0x33
+
+# We want to prove the UTF-8 parser correctly handles all the sequences.
+# Easy way to do this is to check it does low/high boundary cases, as that
+# leaves only two for each sequence length
+#
+# These ranges are therefore:
+#
+# Two bytes:
+# U+0080 = 000 10000000 => 00010 000000
+# => 11000010 10000000 = C2 80
+# U+07FF = 111 11111111 => 11111 111111
+# => 11011111 10111111 = DF BF
+#
+# Three bytes:
+# U+0800 = 00001000 00000000 => 0000 100000 000000
+# => 11100000 10100000 10000000 = E0 A0 80
+# U+FFFD = 11111111 11111101 => 1111 111111 111101
+# => 11101111 10111111 10111101 = EF BF BD
+# (We avoid U+FFFE and U+FFFF as they're invalid codepoints)
+#
+# Four bytes:
+# U+10000 = 00001 00000000 00000000 => 000 010000 000000 000000
+# => 11110000 10010000 10000000 10000000 = F0 90 80 80
+# U+1FFFFF = 11111 11111111 11111111 => 111 111111 111111 111111
+# => 11110111 10111111 10111111 10111111 = F7 BF BF BF
+
+!2 byte
+ENCIN "\xC2\x80\xDF\xBF"
+ encout 0x0080, 0x07FF
+
+!3 byte
+ENCIN "\xE0\xA0\x80\xEF\xBF\xBD"
+ encout 0x0800,0xFFFD
+
+!4 byte
+ENCIN "\xF0\x90\x80\x80\xF7\xBF\xBF\xBF"
+ encout 0x10000,0x1fffff
+
+# Next up, we check some invalid sequences
+# + Early termination (back to low bytes too soon)
+# + Early restart (another sequence introduction before the previous one was finished)
+
+!Early termination
+ENCIN "\xC2!"
+ encout 0xfffd,0x21
+
+ENCIN "\xE0!\xE0\xA0!"
+ encout 0xfffd,0x21,0xfffd,0x21
+
+ENCIN "\xF0!\xF0\x90!\xF0\x90\x80!"
+ encout 0xfffd,0x21,0xfffd,0x21,0xfffd,0x21
+
+!Early restart
+ENCIN "\xC2\xC2\x90"
+ encout 0xfffd,0x0090
+
+ENCIN "\xE0\xC2\x90\xE0\xA0\xC2\x90"
+ encout 0xfffd,0x0090,0xfffd,0x0090
+
+ENCIN "\xF0\xC2\x90\xF0\x90\xC2\x90\xF0\x90\x80\xC2\x90"
+ encout 0xfffd,0x0090,0xfffd,0x0090,0xfffd,0x0090
+
+# Test the overlong sequences by giving an overlong encoding of U+0000 and
+# an encoding of the highest codepoint still too short
+#
+# Two bytes:
+# U+0000 = C0 80
+# U+007F = 000 01111111 => 00001 111111 =>
+# => 11000001 10111111 => C1 BF
+#
+# Three bytes:
+# U+0000 = E0 80 80
+# U+07FF = 00000111 11111111 => 0000 011111 111111
+# => 11100000 10011111 10111111 = E0 9F BF
+#
+# Four bytes:
+# U+0000 = F0 80 80 80
+# U+FFFF = 11111111 11111111 => 000 001111 111111 111111
+# => 11110000 10001111 10111111 10111111 = F0 8F BF BF
+
+!Overlong
+ENCIN "\xC0\x80\xC1\xBF"
+ encout 0xfffd,0xfffd
+
+ENCIN "\xE0\x80\x80\xE0\x9F\xBF"
+ encout 0xfffd,0xfffd
+
+ENCIN "\xF0\x80\x80\x80\xF0\x8F\xBF\xBF"
+ encout 0xfffd,0xfffd
+
+# UTF-16 surrogates U+D800 and U+DFFF
+!UTF-16 Surrogates
+ENCIN "\xED\xA0\x80\xED\xBF\xBF"
+ encout 0xfffd,0xfffd
+
+!Split write
+ENCIN "\xC2"
+ENCIN "\xA0"
+ encout 0x000A0
+
+ENCIN "\xE0"
+ENCIN "\xA0\x80"
+ encout 0x00800
+ENCIN "\xE0\xA0"
+ENCIN "\x80"
+ encout 0x00800
+
+ENCIN "\xF0"
+ENCIN "\x90\x80\x80"
+ encout 0x10000
+ENCIN "\xF0\x90"
+ENCIN "\x80\x80"
+ encout 0x10000
+ENCIN "\xF0\x90\x80"
+ENCIN "\x80"
+ encout 0x10000
diff --git a/src/libvterm/t/10state_putglyph.test b/src/libvterm/t/10state_putglyph.test
new file mode 100644
index 0000000..6d5d56a
--- /dev/null
+++ b/src/libvterm/t/10state_putglyph.test
@@ -0,0 +1,61 @@
+INIT
+UTF8 1
+WANTSTATE g
+
+!Low
+RESET
+PUSH "ABC"
+ putglyph 0x41 1 0,0
+ putglyph 0x42 1 0,1
+ putglyph 0x43 1 0,2
+
+!UTF-8 1 char
+# U+00C1 = 0xC3 0x81 name: LATIN CAPITAL LETTER A WITH ACUTE
+# U+00E9 = 0xC3 0xA9 name: LATIN SMALL LETTER E WITH ACUTE
+RESET
+PUSH "\xC3\x81\xC3\xA9"
+ putglyph 0xc1 1 0,0
+ putglyph 0xe9 1 0,1
+
+!UTF-8 split writes
+RESET
+PUSH "\xC3"
+PUSH "\x81"
+ putglyph 0xc1 1 0,0
+
+!UTF-8 wide char
+# U+FF10 = 0xEF 0xBC 0x90 name: FULLWIDTH DIGIT ZERO
+RESET
+PUSH "\xEF\xBC\x90 "
+ putglyph 0xff10 2 0,0
+ putglyph 0x20 1 0,2
+
+!UTF-8 combining chars
+# U+0301 = 0xCC 0x81 name: COMBINING ACUTE
+RESET
+PUSH "e\xCC\x81Z"
+ putglyph 0x65,0x301 1 0,0
+ putglyph 0x5a 1 0,1
+
+!Combining across buffers
+RESET
+PUSH "e"
+ putglyph 0x65 1 0,0
+PUSH "\xCC\x81Z"
+ putglyph 0x65,0x301 1 0,0
+ putglyph 0x5a 1 0,1
+
+RESET
+PUSH "e"
+ putglyph 0x65 1 0,0
+PUSH "\xCC\x81"
+ putglyph 0x65,0x301 1 0,0
+PUSH "\xCC\x82"
+ putglyph 0x65,0x301,0x302 1 0,0
+
+!DECSCA protected
+RESET
+PUSH "A\e[1\"qB\e[2\"qC"
+ putglyph 0x41 1 0,0
+ putglyph 0x42 1 0,1 prot
+ putglyph 0x43 1 0,2
diff --git a/src/libvterm/t/11state_movecursor.test b/src/libvterm/t/11state_movecursor.test
new file mode 100644
index 0000000..c1d72b2
--- /dev/null
+++ b/src/libvterm/t/11state_movecursor.test
@@ -0,0 +1,224 @@
+INIT
+UTF8 1
+WANTSTATE
+
+!Implicit
+PUSH "ABC"
+ ?cursor = 0,3
+!Backspace
+PUSH "\b"
+ ?cursor = 0,2
+!Horizontal Tab
+PUSH "\t"
+ ?cursor = 0,8
+!Carriage Return
+PUSH "\r"
+ ?cursor = 0,0
+!Linefeed
+PUSH "\n"
+ ?cursor = 1,0
+
+!Backspace bounded by lefthand edge
+PUSH "\e[4;2H"
+ ?cursor = 3,1
+PUSH "\b"
+ ?cursor = 3,0
+PUSH "\b"
+ ?cursor = 3,0
+
+!Backspace cancels phantom
+PUSH "\e[4;80H"
+ ?cursor = 3,79
+PUSH "X"
+ ?cursor = 3,79
+PUSH "\b"
+ ?cursor = 3,78
+
+!HT bounded by righthand edge
+PUSH "\e[1;78H"
+ ?cursor = 0,77
+PUSH "\t"
+ ?cursor = 0,79
+PUSH "\t"
+ ?cursor = 0,79
+
+RESET
+
+!Index
+PUSH "ABC\eD"
+ ?cursor = 1,3
+!Reverse Index
+PUSH "\eM"
+ ?cursor = 0,3
+!Newline
+PUSH "\eE"
+ ?cursor = 1,0
+
+RESET
+
+!Cursor Forward
+PUSH "\e[B"
+ ?cursor = 1,0
+PUSH "\e[3B"
+ ?cursor = 4,0
+PUSH "\e[0B"
+ ?cursor = 5,0
+
+!Cursor Down
+PUSH "\e[C"
+ ?cursor = 5,1
+PUSH "\e[3C"
+ ?cursor = 5,4
+PUSH "\e[0C"
+ ?cursor = 5,5
+
+!Cursor Up
+PUSH "\e[A"
+ ?cursor = 4,5
+PUSH "\e[3A"
+ ?cursor = 1,5
+PUSH "\e[0A"
+ ?cursor = 0,5
+
+!Cursor Backward
+PUSH "\e[D"
+ ?cursor = 0,4
+PUSH "\e[3D"
+ ?cursor = 0,1
+PUSH "\e[0D"
+ ?cursor = 0,0
+
+!Cursor Next Line
+PUSH " "
+ ?cursor = 0,3
+PUSH "\e[E"
+ ?cursor = 1,0
+PUSH " "
+ ?cursor = 1,3
+PUSH "\e[2E"
+ ?cursor = 3,0
+PUSH "\e[0E"
+ ?cursor = 4,0
+
+!Cursor Previous Line
+PUSH " "
+ ?cursor = 4,3
+PUSH "\e[F"
+ ?cursor = 3,0
+PUSH " "
+ ?cursor = 3,3
+PUSH "\e[2F"
+ ?cursor = 1,0
+PUSH "\e[0F"
+ ?cursor = 0,0
+
+!Cursor Horizonal Absolute
+PUSH "\n"
+ ?cursor = 1,0
+PUSH "\e[20G"
+ ?cursor = 1,19
+PUSH "\e[G"
+ ?cursor = 1,0
+
+!Cursor Position
+PUSH "\e[10;5H"
+ ?cursor = 9,4
+PUSH "\e[8H"
+ ?cursor = 7,0
+PUSH "\e[H"
+ ?cursor = 0,0
+
+!Cursor Position cancels phantom
+PUSH "\e[10;78H"
+ ?cursor = 9,77
+PUSH "ABC"
+ ?cursor = 9,79
+PUSH "\e[10;80H"
+PUSH "C"
+ ?cursor = 9,79
+PUSH "X"
+ ?cursor = 10,1
+
+RESET
+
+!Bounds Checking
+PUSH "\e[A"
+ ?cursor = 0,0
+PUSH "\e[D"
+ ?cursor = 0,0
+PUSH "\e[25;80H"
+ ?cursor = 24,79
+PUSH "\e[B"
+ ?cursor = 24,79
+PUSH "\e[C"
+ ?cursor = 24,79
+PUSH "\e[E"
+ ?cursor = 24,0
+PUSH "\e[H"
+ ?cursor = 0,0
+PUSH "\e[F"
+ ?cursor = 0,0
+PUSH "\e[999G"
+ ?cursor = 0,79
+PUSH "\e[99;99H"
+ ?cursor = 24,79
+
+RESET
+
+!Horizontal Position Absolute
+PUSH "\e[5`"
+ ?cursor = 0,4
+
+!Horizontal Position Relative
+PUSH "\e[3a"
+ ?cursor = 0,7
+
+!Horizontal Position Backward
+PUSH "\e[3j"
+ ?cursor = 0,4
+
+!Horizontal and Vertical Position
+PUSH "\e[3;3f"
+ ?cursor = 2,2
+
+!Vertical Position Absolute
+PUSH "\e[5d"
+ ?cursor = 4,2
+
+!Vertical Position Relative
+PUSH "\e[2e"
+ ?cursor = 6,2
+
+!Vertical Position Backward
+PUSH "\e[2k"
+ ?cursor = 4,2
+
+RESET
+
+!Horizontal Tab
+PUSH "\t"
+ ?cursor = 0,8
+PUSH " "
+ ?cursor = 0,11
+PUSH "\t"
+ ?cursor = 0,16
+PUSH " "
+ ?cursor = 0,23
+PUSH "\t"
+ ?cursor = 0,24
+PUSH " "
+ ?cursor = 0,32
+PUSH "\t"
+ ?cursor = 0,40
+
+!Cursor Horizontal Tab
+PUSH "\e[I"
+ ?cursor = 0,48
+PUSH "\e[2I"
+ ?cursor = 0,64
+
+!Cursor Backward Tab
+PUSH "\e[Z"
+ ?cursor = 0,56
+PUSH "\e[2Z"
+ ?cursor = 0,40
diff --git a/src/libvterm/t/12state_scroll.test b/src/libvterm/t/12state_scroll.test
new file mode 100644
index 0000000..ca305d4
--- /dev/null
+++ b/src/libvterm/t/12state_scroll.test
@@ -0,0 +1,150 @@
+INIT
+UTF8 1
+WANTSTATE s
+
+!Linefeed
+PUSH "\n"x24
+ ?cursor = 24,0
+PUSH "\n"
+ scrollrect 0..25,0..80 => +1,+0
+ ?cursor = 24,0
+
+RESET
+
+!Index
+PUSH "\e[25H"
+PUSH "\eD"
+ scrollrect 0..25,0..80 => +1,+0
+
+RESET
+
+!Reverse Index
+PUSH "\eM"
+ scrollrect 0..25,0..80 => -1,+0
+
+RESET
+
+!Linefeed in DECSTBM
+PUSH "\e[1;10r"
+ ?cursor = 0,0
+PUSH "\n"x9
+ ?cursor = 9,0
+PUSH "\n"
+ scrollrect 0..10,0..80 => +1,+0
+ ?cursor = 9,0
+
+!Linefeed outside DECSTBM
+PUSH "\e[20H"
+ ?cursor = 19,0
+PUSH "\n"
+ ?cursor = 20,0
+
+!Index in DECSTBM
+PUSH "\e[10H"
+PUSH "\e[9;10r"
+PUSH "\eM"
+ ?cursor = 8,0
+PUSH "\eM"
+ scrollrect 8..10,0..80 => -1,+0
+
+!Reverse Index in DECSTBM
+PUSH "\e[25H"
+ ?cursor = 24,0
+PUSH "\n"
+ # no scrollrect
+ ?cursor = 24,0
+
+!Linefeed in DECSTBM+DECSLRM
+PUSH "\e[?69h"
+PUSH "\e[3;10r\e[10;40s"
+PUSH "\e[10;10H\n"
+ scrollrect 2..10,9..40 => +1,+0
+
+!IND/RI in DECSTBM+DECSLRM
+PUSH "\eD"
+ scrollrect 2..10,9..40 => +1,+0
+PUSH "\e[3;10H\eM"
+ scrollrect 2..10,9..40 => -1,+0
+
+!DECRQSS on DECSTBM
+PUSH "\eP\$qr\e\\"
+ output "\eP1\$r3;10r\e\\"
+
+!DECRQSS on DECSLRM
+PUSH "\eP\$qs\e\\"
+ output "\eP1\$r10;40s\e\\"
+
+!Setting invalid DECSLRM with !DECVSSM is still rejected
+PUSH "\e[?69l\e[;0s\e[?69h"
+
+RESET
+
+!Scroll Down
+PUSH "\e[S"
+ scrollrect 0..25,0..80 => +1,+0
+ ?cursor = 0,0
+PUSH "\e[2S"
+ scrollrect 0..25,0..80 => +2,+0
+ ?cursor = 0,0
+PUSH "\e[100S"
+ scrollrect 0..25,0..80 => +25,+0
+
+!Scroll Up
+PUSH "\e[T"
+ scrollrect 0..25,0..80 => -1,+0
+ ?cursor = 0,0
+PUSH "\e[2T"
+ scrollrect 0..25,0..80 => -2,+0
+ ?cursor = 0,0
+PUSH "\e[100T"
+ scrollrect 0..25,0..80 => -25,+0
+
+!SD/SU in DECSTBM
+PUSH "\e[5;20r"
+PUSH "\e[S"
+ scrollrect 4..20,0..80 => +1,+0
+PUSH "\e[T"
+ scrollrect 4..20,0..80 => -1,+0
+
+RESET
+
+!SD/SU in DECSTBM+DECSLRM
+PUSH "\e[?69h"
+PUSH "\e[3;10r\e[10;40s"
+ ?cursor = 0,0
+PUSH "\e[3;10H"
+ ?cursor = 2,9
+PUSH "\e[S"
+ scrollrect 2..10,9..40 => +1,+0
+PUSH "\e[?69l"
+PUSH "\e[S"
+ scrollrect 2..10,0..80 => +1,+0
+
+!Invalid boundaries
+RESET
+
+PUSH "\e[100;105r\eD"
+PUSH "\e[5;2r\eD"
+
+RESET
+WANTSTATE -s+me
+
+!Scroll Down move+erase emulation
+PUSH "\e[S"
+ moverect 1..25,0..80 -> 0..24,0..80
+ erase 24..25,0..80
+ ?cursor = 0,0
+PUSH "\e[2S"
+ moverect 2..25,0..80 -> 0..23,0..80
+ erase 23..25,0..80
+ ?cursor = 0,0
+
+!Scroll Up move+erase emulation
+PUSH "\e[T"
+ moverect 0..24,0..80 -> 1..25,0..80
+ erase 0..1,0..80
+ ?cursor = 0,0
+PUSH "\e[2T"
+ moverect 0..23,0..80 -> 2..25,0..80
+ erase 0..2,0..80
+ ?cursor = 0,0
diff --git a/src/libvterm/t/13state_edit.test b/src/libvterm/t/13state_edit.test
new file mode 100644
index 0000000..b435655
--- /dev/null
+++ b/src/libvterm/t/13state_edit.test
@@ -0,0 +1,300 @@
+INIT
+UTF8 1
+WANTSTATE se
+
+!ICH
+RESET
+ erase 0..25,0..80
+ ?cursor = 0,0
+PUSH "ACD"
+PUSH "\e[2D"
+ ?cursor = 0,1
+PUSH "\e[@"
+ scrollrect 0..1,1..80 => +0,-1
+ ?cursor = 0,1
+PUSH "B"
+ ?cursor = 0,2
+PUSH "\e[3@"
+ scrollrect 0..1,2..80 => +0,-3
+
+!ICH with DECSLRM
+PUSH "\e[?69h"
+PUSH "\e[;50s"
+PUSH "\e[20G\e[@"
+ scrollrect 0..1,19..50 => +0,-1
+
+!ICH outside DECSLRM
+PUSH "\e[70G\e[@"
+ # nothing happens
+
+!DCH
+RESET
+ erase 0..25,0..80
+ ?cursor = 0,0
+PUSH "ABBC"
+PUSH "\e[3D"
+ ?cursor = 0,1
+PUSH "\e[P"
+ scrollrect 0..1,1..80 => +0,+1
+ ?cursor = 0,1
+PUSH "\e[3P"
+ scrollrect 0..1,1..80 => +0,+3
+ ?cursor = 0,1
+
+!DCH with DECSLRM
+PUSH "\e[?69h"
+PUSH "\e[;50s"
+PUSH "\e[20G\e[P"
+ scrollrect 0..1,19..50 => +0,+1
+
+!DCH outside DECSLRM
+PUSH "\e[70G\e[P"
+ # nothing happens
+
+!ECH
+RESET
+ erase 0..25,0..80
+ ?cursor = 0,0
+PUSH "ABC"
+PUSH "\e[2D"
+ ?cursor = 0,1
+PUSH "\e[X"
+ erase 0..1,1..2
+ ?cursor = 0,1
+PUSH "\e[3X"
+ erase 0..1,1..4
+ ?cursor = 0,1
+# ECH more columns than there are should be bounded
+PUSH "\e[100X"
+ erase 0..1,1..80
+
+!IL
+RESET
+ erase 0..25,0..80
+ ?cursor = 0,0
+PUSH "A\r\nC"
+ ?cursor = 1,1
+PUSH "\e[L"
+ scrollrect 1..25,0..80 => -1,+0
+ # TODO: ECMA-48 says we should move to line home, but neither xterm nor
+ # xfce4-terminal do this
+ ?cursor = 1,1
+PUSH "\rB"
+ ?cursor = 1,1
+PUSH "\e[3L"
+ scrollrect 1..25,0..80 => -3,+0
+
+!IL with DECSTBM
+PUSH "\e[5;15r"
+PUSH "\e[5H\e[L"
+ scrollrect 4..15,0..80 => -1,+0
+
+!IL outside DECSTBM
+PUSH "\e[20H\e[L"
+ # nothing happens
+
+!IL with DECSTBM+DECSLRM
+PUSH "\e[?69h"
+PUSH "\e[10;50s"
+PUSH "\e[5;10H\e[L"
+ scrollrect 4..15,9..50 => -1,+0
+
+!DL
+RESET
+ erase 0..25,0..80
+ ?cursor = 0,0
+PUSH "A\r\nB\r\nB\r\nC"
+ ?cursor = 3,1
+PUSH "\e[2H"
+ ?cursor = 1,0
+PUSH "\e[M"
+ scrollrect 1..25,0..80 => +1,+0
+ ?cursor = 1,0
+PUSH "\e[3M"
+ scrollrect 1..25,0..80 => +3,+0
+ ?cursor = 1,0
+
+!DL with DECSTBM
+PUSH "\e[5;15r"
+PUSH "\e[5H\e[M"
+ scrollrect 4..15,0..80 => +1,+0
+
+!DL outside DECSTBM
+PUSH "\e[20H\e[M"
+ # nothing happens
+
+!DL with DECSTBM+DECSLRM
+PUSH "\e[?69h"
+PUSH "\e[10;50s"
+PUSH "\e[5;10H\e[M"
+ scrollrect 4..15,9..50 => +1,+0
+
+!DECIC
+RESET
+ erase 0..25,0..80
+PUSH "\e[20G\e[5'}"
+ scrollrect 0..25,19..80 => +0,-5
+
+!DECIC with DECSTBM+DECSLRM
+PUSH "\e[?69h"
+PUSH "\e[4;20r\e[20;60s"
+PUSH "\e[4;20H\e[3'}"
+ scrollrect 3..20,19..60 => +0,-3
+
+!DECIC outside DECSLRM
+PUSH "\e[70G\e['}"
+ # nothing happens
+
+!DECDC
+RESET
+ erase 0..25,0..80
+PUSH "\e[20G\e[5'~"
+ scrollrect 0..25,19..80 => +0,+5
+
+!DECDC with DECSTBM+DECSLRM
+PUSH "\e[?69h"
+PUSH "\e[4;20r\e[20;60s"
+PUSH "\e[4;20H\e[3'~"
+ scrollrect 3..20,19..60 => +0,+3
+
+!DECDC outside DECSLRM
+PUSH "\e[70G\e['~"
+ # nothing happens
+
+!EL 0
+RESET
+ erase 0..25,0..80
+ ?cursor = 0,0
+PUSH "ABCDE"
+PUSH "\e[3D"
+ ?cursor = 0,2
+PUSH "\e[0K"
+ erase 0..1,2..80
+ ?cursor = 0,2
+
+!EL 1
+RESET
+ erase 0..25,0..80
+ ?cursor = 0,0
+PUSH "ABCDE"
+PUSH "\e[3D"
+ ?cursor = 0,2
+PUSH "\e[1K"
+ erase 0..1,0..3
+ ?cursor = 0,2
+
+!EL 2
+RESET
+ erase 0..25,0..80
+ ?cursor = 0,0
+PUSH "ABCDE"
+PUSH "\e[3D"
+ ?cursor = 0,2
+PUSH "\e[2K"
+ erase 0..1,0..80
+ ?cursor = 0,2
+
+!SEL
+RESET
+ erase 0..25,0..80
+ ?cursor = 0,0
+PUSH "\e[11G"
+ ?cursor = 0,10
+PUSH "\e[?0K"
+ erase 0..1,10..80 selective
+ ?cursor = 0,10
+PUSH "\e[?1K"
+ erase 0..1,0..11 selective
+ ?cursor = 0,10
+PUSH "\e[?2K"
+ erase 0..1,0..80 selective
+ ?cursor = 0,10
+
+!ED 0
+RESET
+ erase 0..25,0..80
+ ?cursor = 0,0
+PUSH "\e[2;2H"
+ ?cursor = 1,1
+PUSH "\e[0J"
+ erase 1..2,1..80
+ erase 2..25,0..80
+ ?cursor = 1,1
+
+!ED 1
+RESET
+ erase 0..25,0..80
+ ?cursor = 0,0
+PUSH "\e[2;2H"
+ ?cursor = 1,1
+PUSH "\e[1J"
+ erase 0..1,0..80
+ erase 1..2,0..2
+ ?cursor = 1,1
+
+!ED 2
+RESET
+ erase 0..25,0..80
+ ?cursor = 0,0
+PUSH "\e[2;2H"
+ ?cursor = 1,1
+PUSH "\e[2J"
+ erase 0..25,0..80
+ ?cursor = 1,1
+
+!SED
+RESET
+ erase 0..25,0..80
+PUSH "\e[5;5H"
+ ?cursor = 4,4
+PUSH "\e[?0J"
+ erase 4..5,4..80 selective
+ erase 5..25,0..80 selective
+ ?cursor = 4,4
+PUSH "\e[?1J"
+ erase 0..4,0..80 selective
+ erase 4..5,0..5 selective
+ ?cursor = 4,4
+PUSH "\e[?2J"
+ erase 0..25,0..80 selective
+ ?cursor = 4,4
+
+!DECRQSS on DECSCA
+PUSH "\e[2\"q"
+PUSH "\eP\$q\"q\e\\"
+ output "\eP1\$r2\"q\e\\"
+
+WANTSTATE -s+m
+
+!ICH move+erase emuation
+RESET
+ erase 0..25,0..80
+ ?cursor = 0,0
+PUSH "ACD"
+PUSH "\e[2D"
+ ?cursor = 0,1
+PUSH "\e[@"
+ moverect 0..1,1..79 -> 0..1,2..80
+ erase 0..1,1..2
+ ?cursor = 0,1
+PUSH "B"
+ ?cursor = 0,2
+PUSH "\e[3@"
+ moverect 0..1,2..77 -> 0..1,5..80
+ erase 0..1,2..5
+
+!DCH move+erase emulation
+RESET
+ erase 0..25,0..80
+ ?cursor = 0,0
+PUSH "ABBC"
+PUSH "\e[3D"
+ ?cursor = 0,1
+PUSH "\e[P"
+ moverect 0..1,2..80 -> 0..1,1..79
+ erase 0..1,79..80
+ ?cursor = 0,1
+PUSH "\e[3P"
+ moverect 0..1,4..80 -> 0..1,1..77
+ erase 0..1,77..80
+ ?cursor = 0,1
diff --git a/src/libvterm/t/14state_encoding.test b/src/libvterm/t/14state_encoding.test
new file mode 100644
index 0000000..b1f5d69
--- /dev/null
+++ b/src/libvterm/t/14state_encoding.test
@@ -0,0 +1,105 @@
+INIT
+WANTSTATE g
+
+!Default
+RESET
+PUSH "#"
+ putglyph 0x23 1 0,0
+
+!Designate G0=UK
+RESET
+PUSH "\e(A"
+PUSH "#"
+ putglyph 0x00a3 1 0,0
+
+!Designate G0=DEC drawing
+RESET
+PUSH "\e(0"
+PUSH "a"
+ putglyph 0x2592 1 0,0
+
+!Designate G1 + LS1
+RESET
+PUSH "\e)0"
+PUSH "a"
+ putglyph 0x61 1 0,0
+PUSH "\x0e"
+PUSH "a"
+ putglyph 0x2592 1 0,1
+!LS0
+PUSH "\x0f"
+PUSH "a"
+ putglyph 0x61 1 0,2
+
+!Designate G2 + LS2
+PUSH "\e*0"
+PUSH "a"
+ putglyph 0x61 1 0,3
+PUSH "\en"
+PUSH "a"
+ putglyph 0x2592 1 0,4
+PUSH "\x0f"
+PUSH "a"
+ putglyph 0x61 1 0,5
+
+!Designate G3 + LS3
+PUSH "\e+0"
+PUSH "a"
+ putglyph 0x61 1 0,6
+PUSH "\eo"
+PUSH "a"
+ putglyph 0x2592 1 0,7
+PUSH "\x0f"
+PUSH "a"
+ putglyph 0x61 1 0,8
+
+!SS2
+PUSH "a\x{8e}aa"
+ putglyph 0x61 1 0,9
+ putglyph 0x2592 1 0,10
+ putglyph 0x61 1 0,11
+
+!SS3
+PUSH "a\x{8f}aa"
+ putglyph 0x61 1 0,12
+ putglyph 0x2592 1 0,13
+ putglyph 0x61 1 0,14
+
+!LS1R
+RESET
+PUSH "\e~"
+PUSH "\xe1"
+ putglyph 0x61 1 0,0
+PUSH "\e)0"
+PUSH "\xe1"
+ putglyph 0x2592 1 0,1
+
+!LS2R
+RESET
+PUSH "\e}"
+PUSH "\xe1"
+ putglyph 0x61 1 0,0
+PUSH "\e*0"
+PUSH "\xe1"
+ putglyph 0x2592 1 0,1
+
+!LS3R
+RESET
+PUSH "\e|"
+PUSH "\xe1"
+ putglyph 0x61 1 0,0
+PUSH "\e+0"
+PUSH "\xe1"
+ putglyph 0x2592 1 0,1
+
+UTF8 1
+
+!Mixed US-ASCII and UTF-8
+# U+0108 == 0xc4 0x88
+RESET
+PUSH "\e(B"
+PUSH "AB\xc4\x88D"
+ putglyph 0x0041 1 0,0
+ putglyph 0x0042 1 0,1
+ putglyph 0x0108 1 0,2
+ putglyph 0x0044 1 0,3
diff --git a/src/libvterm/t/15state_mode.test b/src/libvterm/t/15state_mode.test
new file mode 100644
index 0000000..b7917ad
--- /dev/null
+++ b/src/libvterm/t/15state_mode.test
@@ -0,0 +1,86 @@
+INIT
+UTF8 1
+WANTSTATE gme
+
+!Insert/Replace Mode
+RESET
+ erase 0..25,0..80
+ ?cursor = 0,0
+PUSH "AC\e[DB"
+ putglyph 0x41 1 0,0
+ putglyph 0x43 1 0,1
+ putglyph 0x42 1 0,1
+PUSH "\e[4h"
+PUSH "\e[G"
+PUSH "AC\e[DB"
+ moverect 0..1,0..79 -> 0..1,1..80
+ erase 0..1,0..1
+ putglyph 0x41 1 0,0
+ moverect 0..1,1..79 -> 0..1,2..80
+ erase 0..1,1..2
+ putglyph 0x43 1 0,1
+ moverect 0..1,1..79 -> 0..1,2..80
+ erase 0..1,1..2
+ putglyph 0x42 1 0,1
+
+!Insert mode only happens once for UTF-8 combining
+PUSH "e"
+ moverect 0..1,2..79 -> 0..1,3..80
+ erase 0..1,2..3
+ putglyph 0x65 1 0,2
+PUSH "\xCC\x81"
+ putglyph 0x65,0x301 1 0,2
+
+!Newline/Linefeed mode
+RESET
+ erase 0..25,0..80
+ ?cursor = 0,0
+PUSH "\e[5G\n"
+ ?cursor = 1,4
+PUSH "\e[20h"
+PUSH "\e[5G\n"
+ ?cursor = 2,0
+
+!DEC origin mode
+RESET
+ erase 0..25,0..80
+ ?cursor = 0,0
+PUSH "\e[5;15r"
+PUSH "\e[H"
+ ?cursor = 0,0
+PUSH "\e[3;3H"
+ ?cursor = 2,2
+PUSH "\e[?6h"
+PUSH "\e[H"
+ ?cursor = 4,0
+PUSH "\e[3;3H"
+ ?cursor = 6,2
+
+!DECRQM on DECOM
+PUSH "\e[?6h"
+PUSH "\e[?6\$p"
+ output "\e[?6;1\$y"
+PUSH "\e[?6l"
+PUSH "\e[?6\$p"
+ output "\e[?6;2\$y"
+
+!Origin mode with DECSLRM
+PUSH "\e[?6h"
+PUSH "\e[?69h"
+PUSH "\e[20;60s"
+PUSH "\e[H"
+ ?cursor = 4,19
+
+PUSH "\e[?69l"
+
+!Origin mode bounds cursor to scrolling region
+PUSH "\e[H"
+PUSH "\e[10A"
+ ?cursor = 4,0
+PUSH "\e[20B"
+ ?cursor = 14,0
+
+!Origin mode without scroll region
+PUSH "\e[?6l"
+PUSH "\e[r\e[?6h"
+ ?cursor = 0,0
diff --git a/src/libvterm/t/16state_resize.test b/src/libvterm/t/16state_resize.test
new file mode 100644
index 0000000..42c77c7
--- /dev/null
+++ b/src/libvterm/t/16state_resize.test
@@ -0,0 +1,48 @@
+INIT
+WANTSTATE g
+
+!Placement
+RESET
+PUSH "AB\e[79GCDE"
+ putglyph 0x41 1 0,0
+ putglyph 0x42 1 0,1
+ putglyph 0x43 1 0,78
+ putglyph 0x44 1 0,79
+ putglyph 0x45 1 1,0
+
+!Resize
+RESET
+RESIZE 27,85
+PUSH "AB\e[79GCDE"
+ putglyph 0x41 1 0,0
+ putglyph 0x42 1 0,1
+ putglyph 0x43 1 0,78
+ putglyph 0x44 1 0,79
+ putglyph 0x45 1 0,80
+ ?cursor = 0,81
+
+!Resize without reset
+RESIZE 28,90
+ ?cursor = 0,81
+PUSH "FGHI"
+ putglyph 0x46 1 0,81
+ putglyph 0x47 1 0,82
+ putglyph 0x48 1 0,83
+ putglyph 0x49 1 0,84
+ ?cursor = 0,85
+
+!Resize shrink moves cursor
+RESIZE 25,80
+ ?cursor = 0,79
+
+!Resize grow doesn't cancel phantom
+RESET
+PUSH "\e[79GAB"
+ putglyph 0x41 1 0,78
+ putglyph 0x42 1 0,79
+ ?cursor = 0,79
+RESIZE 30,100
+ ?cursor = 0,80
+PUSH "C"
+ putglyph 0x43 1 0,80
+ ?cursor = 0,81
diff --git a/src/libvterm/t/17state_mouse.test b/src/libvterm/t/17state_mouse.test
new file mode 100644
index 0000000..c39f56b
--- /dev/null
+++ b/src/libvterm/t/17state_mouse.test
@@ -0,0 +1,172 @@
+INIT
+WANTSTATE p
+
+!DECRQM on with mouse off
+PUSH "\e[?1000\$p"
+ output "\e[?1000;2\$y"
+PUSH "\e[?1002\$p"
+ output "\e[?1002;2\$y"
+PUSH "\e[?1003\$p"
+ output "\e[?1003;2\$y"
+
+!Mouse in simple button report mode
+RESET
+ settermprop 1 true
+ settermprop 2 true
+ settermprop 7 1
+PUSH "\e[?1000h"
+ settermprop 8 1
+
+!Press 1
+MOUSEMOVE 0,0 0
+MOUSEBTN d 1 0
+ output "\e[M\x20\x21\x21"
+
+!Release 1
+MOUSEBTN u 1 0
+ output "\e[M\x23\x21\x21"
+
+!Ctrl-Press 1
+MOUSEBTN d 1 C
+ output "\e[M\x30\x21\x21"
+MOUSEBTN u 1 C
+ output "\e[M\x33\x21\x21"
+
+!Button 2
+MOUSEBTN d 2 0
+ output "\e[M\x21\x21\x21"
+MOUSEBTN u 2 0
+ output "\e[M\x23\x21\x21"
+
+!Position
+MOUSEMOVE 10,20 0
+MOUSEBTN d 1 0
+ output "\e[M\x20\x35\x2b"
+
+MOUSEBTN u 1 0
+ output "\e[M\x23\x35\x2b"
+MOUSEMOVE 10,21 0
+ # no output
+
+!Wheel events
+MOUSEBTN d 4 0
+ output "\e[M\x60\x36\x2b"
+MOUSEBTN d 4 0
+ output "\e[M\x60\x36\x2b"
+MOUSEBTN d 5 0
+ output "\e[M\x61\x36\x2b"
+
+!DECRQM on mouse button mode
+PUSH "\e[?1000\$p"
+ output "\e[?1000;1\$y"
+PUSH "\e[?1002\$p"
+ output "\e[?1002;2\$y"
+PUSH "\e[?1003\$p"
+ output "\e[?1003;2\$y"
+
+!Drag events
+RESET
+ settermprop 1 true
+ settermprop 2 true
+ settermprop 7 1
+PUSH "\e[?1002h"
+ settermprop 8 2
+
+MOUSEMOVE 5,5 0
+MOUSEBTN d 1 0
+ output "\e[M\x20\x26\x26"
+MOUSEMOVE 5,6 0
+ output "\e[M\x40\x27\x26"
+MOUSEMOVE 6,6 0
+ output "\e[M\x40\x27\x27"
+MOUSEMOVE 6,6 0
+ # no output
+MOUSEBTN u 1 0
+ output "\e[M\x23\x27\x27"
+MOUSEMOVE 6,7
+ # no output
+
+!DECRQM on mouse drag mode
+PUSH "\e[?1000\$p"
+ output "\e[?1000;2\$y"
+PUSH "\e[?1002\$p"
+ output "\e[?1002;1\$y"
+PUSH "\e[?1003\$p"
+ output "\e[?1003;2\$y"
+
+!Non-drag motion events
+PUSH "\e[?1003h"
+ settermprop 8 3
+
+MOUSEMOVE 6,8 0
+ output "\e[M\x43\x29\x27"
+
+!DECRQM on mouse motion mode
+PUSH "\e[?1000\$p"
+ output "\e[?1000;2\$y"
+PUSH "\e[?1002\$p"
+ output "\e[?1002;2\$y"
+PUSH "\e[?1003\$p"
+ output "\e[?1003;1\$y"
+
+!Bounds checking
+MOUSEMOVE 300,300 0
+ output "\e[M\x43\xff\xff"
+MOUSEBTN d 1 0
+ output "\e[M\x20\xff\xff"
+MOUSEBTN u 1 0
+ output "\e[M\x23\xff\xff"
+
+!DECRQM on standard encoding mode
+PUSH "\e[?1005\$p"
+ output "\e[?1005;2\$y"
+PUSH "\e[?1006\$p"
+ output "\e[?1006;2\$y"
+PUSH "\e[?1015\$p"
+ output "\e[?1015;2\$y"
+
+!UTF-8 extended encoding mode
+# 300 + 32 + 1 = 333 = U+014d = \xc5\x8d
+PUSH "\e[?1005h"
+MOUSEBTN d 1 0
+ output "\e[M\x20\xc5\x8d\xc5\x8d"
+MOUSEBTN u 1 0
+ output "\e[M\x23\xc5\x8d\xc5\x8d"
+
+!DECRQM on UTF-8 extended encoding mode
+PUSH "\e[?1005\$p"
+ output "\e[?1005;1\$y"
+PUSH "\e[?1006\$p"
+ output "\e[?1006;2\$y"
+PUSH "\e[?1015\$p"
+ output "\e[?1015;2\$y"
+
+!SGR extended encoding mode
+PUSH "\e[?1006h"
+MOUSEBTN d 1 0
+ output "\e[<0;301;301M"
+MOUSEBTN u 1 0
+ output "\e[<0;301;301m"
+
+!DECRQM on SGR extended encoding mode
+PUSH "\e[?1005\$p"
+ output "\e[?1005;2\$y"
+PUSH "\e[?1006\$p"
+ output "\e[?1006;1\$y"
+PUSH "\e[?1015\$p"
+ output "\e[?1015;2\$y"
+
+!rxvt extended encoding mode
+PUSH "\e[?1015h"
+MOUSEBTN d 1 0
+ output "\e[0;301;301M"
+MOUSEBTN u 1 0
+ output "\e[3;301;301M"
+
+!DECRQM on rxvt extended encoding mode
+PUSH "\e[?1005\$p"
+ output "\e[?1005;2\$y"
+PUSH "\e[?1006\$p"
+ output "\e[?1006;2\$y"
+PUSH "\e[?1015\$p"
+ output "\e[?1015;1\$y"
diff --git a/src/libvterm/t/18state_termprops.test b/src/libvterm/t/18state_termprops.test
new file mode 100644
index 0000000..9e6928a
--- /dev/null
+++ b/src/libvterm/t/18state_termprops.test
@@ -0,0 +1,36 @@
+INIT
+WANTSTATE p
+
+RESET
+ settermprop 1 true
+ settermprop 2 true
+ settermprop 7 1
+
+!Cursor visibility
+PUSH "\e[?25h"
+ settermprop 1 true
+PUSH "\e[?25\$p"
+ output "\e[?25;1\$y"
+PUSH "\e[?25l"
+ settermprop 1 false
+PUSH "\e[?25\$p"
+ output "\e[?25;2\$y"
+
+!Cursor blink
+PUSH "\e[?12h"
+ settermprop 2 true
+PUSH "\e[?12\$p"
+ output "\e[?12;1\$y"
+PUSH "\e[?12l"
+ settermprop 2 false
+PUSH "\e[?12\$p"
+ output "\e[?12;2\$y"
+
+!Cursor shape
+PUSH "\e[3 q"
+ settermprop 2 true
+ settermprop 7 2
+
+!Title
+PUSH "\e]2;Here is my title\a"
+ settermprop 4 "Here is my title"
diff --git a/src/libvterm/t/20state_wrapping.test b/src/libvterm/t/20state_wrapping.test
new file mode 100644
index 0000000..606fa06
--- /dev/null
+++ b/src/libvterm/t/20state_wrapping.test
@@ -0,0 +1,69 @@
+INIT
+UTF8 1
+WANTSTATE gm
+
+!79th Column
+PUSH "\e[75G"
+PUSH "A"x5
+ putglyph 0x41 1 0,74
+ putglyph 0x41 1 0,75
+ putglyph 0x41 1 0,76
+ putglyph 0x41 1 0,77
+ putglyph 0x41 1 0,78
+ ?cursor = 0,79
+
+!80th Column Phantom
+PUSH "A"
+ putglyph 0x41 1 0,79
+ ?cursor = 0,79
+
+!Line Wraparound
+PUSH "B"
+ putglyph 0x42 1 1,0
+ ?cursor = 1,1
+
+!Line Wraparound during combined write
+PUSH "\e[78G"
+PUSH "BBBCC"
+ putglyph 0x42 1 1,77
+ putglyph 0x42 1 1,78
+ putglyph 0x42 1 1,79
+ putglyph 0x43 1 2,0
+ putglyph 0x43 1 2,1
+ ?cursor = 2,2
+
+!DEC Auto Wrap Mode
+RESET
+PUSH "\e[?7l"
+PUSH "\e[75G"
+PUSH "D"x6
+ putglyph 0x44 1 0,74
+ putglyph 0x44 1 0,75
+ putglyph 0x44 1 0,76
+ putglyph 0x44 1 0,77
+ putglyph 0x44 1 0,78
+ putglyph 0x44 1 0,79
+ ?cursor = 0,79
+PUSH "D"
+ putglyph 0x44 1 0,79
+ ?cursor = 0,79
+PUSH "\e[?7h"
+
+!80th column causes linefeed on wraparound
+PUSH "\e[25;78HABC"
+ putglyph 0x41 1 24,77
+ putglyph 0x42 1 24,78
+ putglyph 0x43 1 24,79
+ ?cursor = 24,79
+PUSH "D"
+ moverect 1..25,0..80 -> 0..24,0..80
+ putglyph 0x44 1 24,0
+
+!80th column phantom linefeed phantom cancelled by explicit cursor move
+PUSH "\e[25;78HABC"
+ putglyph 0x41 1 24,77
+ putglyph 0x42 1 24,78
+ putglyph 0x43 1 24,79
+ ?cursor = 24,79
+PUSH "\e[25;1HD"
+ putglyph 0x44 1 24,0
diff --git a/src/libvterm/t/21state_tabstops.test b/src/libvterm/t/21state_tabstops.test
new file mode 100644
index 0000000..df4a589
--- /dev/null
+++ b/src/libvterm/t/21state_tabstops.test
@@ -0,0 +1,60 @@
+INIT
+WANTSTATE g
+
+!Initial
+RESET
+PUSH "\tX"
+ putglyph 0x58 1 0,8
+PUSH "\tX"
+ putglyph 0x58 1 0,16
+ ?cursor = 0,17
+
+!HTS
+PUSH "\e[5G\eH"
+PUSH "\e[G\tX"
+ putglyph 0x58 1 0,4
+ ?cursor = 0,5
+
+!TBC 0
+PUSH "\e[9G\e[g"
+PUSH "\e[G\tX\tX"
+ putglyph 0x58 1 0,4
+ putglyph 0x58 1 0,16
+ ?cursor = 0,17
+
+!TBC 3
+PUSH "\e[3g\e[50G\eH\e[G"
+ ?cursor = 0,0
+PUSH "\tX"
+ putglyph 0x58 1 0,49
+ ?cursor = 0,50
+
+!Tabstops after resize
+RESET
+RESIZE 30,100
+# Should be 100/8 = 12 tabstops
+PUSH "\tX"
+ putglyph 0x58 1 0,8
+PUSH "\tX"
+ putglyph 0x58 1 0,16
+PUSH "\tX"
+ putglyph 0x58 1 0,24
+PUSH "\tX"
+ putglyph 0x58 1 0,32
+PUSH "\tX"
+ putglyph 0x58 1 0,40
+PUSH "\tX"
+ putglyph 0x58 1 0,48
+PUSH "\tX"
+ putglyph 0x58 1 0,56
+PUSH "\tX"
+ putglyph 0x58 1 0,64
+PUSH "\tX"
+ putglyph 0x58 1 0,72
+PUSH "\tX"
+ putglyph 0x58 1 0,80
+PUSH "\tX"
+ putglyph 0x58 1 0,88
+PUSH "\tX"
+ putglyph 0x58 1 0,96
+ ?cursor = 0,97
diff --git a/src/libvterm/t/22state_save.test b/src/libvterm/t/22state_save.test
new file mode 100644
index 0000000..81e9226
--- /dev/null
+++ b/src/libvterm/t/22state_save.test
@@ -0,0 +1,64 @@
+INIT
+WANTSTATE p
+
+RESET
+ settermprop 1 true
+ settermprop 2 true
+ settermprop 7 1
+
+!Set up state
+PUSH "\e[2;2H"
+ ?cursor = 1,1
+PUSH "\e[1m"
+ ?pen bold = on
+
+!Save
+PUSH "\e[?1048h"
+
+!Change state
+PUSH "\e[5;5H"
+ ?cursor = 4,4
+PUSH "\e[4 q"
+ settermprop 2 false
+ settermprop 7 2
+PUSH "\e[22;4m"
+ ?pen bold = off
+ ?pen underline = 1
+
+!Restore
+PUSH "\e[?1048l"
+ settermprop 1 true
+ settermprop 2 true
+ settermprop 7 1
+ ?cursor = 1,1
+ ?pen bold = on
+ ?pen underline = 0
+
+!Save/restore using DECSC/DECRC
+PUSH "\e[2;2H\e7"
+ ?cursor = 1,1
+
+PUSH "\e[5;5H"
+ ?cursor = 4,4
+PUSH "\e8"
+ settermprop 1 true
+ settermprop 2 true
+ settermprop 7 1
+ ?cursor = 1,1
+
+!Save twice, restore twice happens on both edge transitions
+PUSH "\e[2;10H\e[?1048h\e[6;10H\e[?1048h"
+PUSH "\e[H"
+ ?cursor = 0,0
+PUSH "\e[?1048l"
+ settermprop 1 true
+ settermprop 2 true
+ settermprop 7 1
+ ?cursor = 5,9
+PUSH "\e[H"
+ ?cursor = 0,0
+PUSH "\e[?1048l"
+ settermprop 1 true
+ settermprop 2 true
+ settermprop 7 1
+ ?cursor = 5,9
diff --git a/src/libvterm/t/25state_input.test b/src/libvterm/t/25state_input.test
new file mode 100644
index 0000000..a5119fb
--- /dev/null
+++ b/src/libvterm/t/25state_input.test
@@ -0,0 +1,143 @@
+INIT
+WANTSTATE
+
+!Unmodified ASCII
+INCHAR 0 41
+ output "A"
+INCHAR 0 61
+ output "a"
+
+!Ctrl modifier on ASCII letters
+INCHAR C 41
+ output "\e[65;5u"
+INCHAR C 61
+ output "\x01"
+
+!Alt modifier on ASCII letters
+INCHAR A 41
+ output "\eA"
+INCHAR A 61
+ output "\ea"
+
+!Ctrl-Alt modifier on ASCII letters
+INCHAR CA 41
+ output "\e[65;7u"
+INCHAR CA 61
+ output "\e\x01"
+
+!Special handling of Ctrl-I
+INCHAR 0 49
+ output "I"
+INCHAR 0 69
+ output "i"
+INCHAR C 49
+ output "\e[73;5u"
+INCHAR C 69
+ output "\e[105;5u"
+INCHAR A 49
+ output "\eI"
+INCHAR A 69
+ output "\ei"
+INCHAR CA 49
+ output "\e[73;7u"
+INCHAR CA 69
+ output "\e[105;7u"
+
+!Special handling of Space
+INCHAR 0 20
+ output " "
+INCHAR S 20
+ output "\e[32;2u"
+INCHAR C 20
+ output "\0"
+INCHAR SC 20
+ output "\e[32;6u"
+INCHAR A 20
+ output "\e "
+INCHAR SA 20
+ output "\e[32;4u"
+INCHAR CA 20
+ output "\e\0"
+INCHAR SCA 20
+ output "\e[32;8u"
+
+!Cursor keys in reset (cursor) mode
+INKEY 0 Up
+ output "\e[A"
+INKEY S Up
+ output "\e[1;2A"
+INKEY C Up
+ output "\e[1;5A"
+INKEY SC Up
+ output "\e[1;6A"
+INKEY A Up
+ output "\e[1;3A"
+INKEY SA Up
+ output "\e[1;4A"
+INKEY CA Up
+ output "\e[1;7A"
+INKEY SCA Up
+ output "\e[1;8A"
+
+!Cursor keys in application mode
+PUSH "\e[?1h"
+# Plain "Up" should be SS3 A now
+INKEY 0 Up
+ output "\eOA"
+# Modified keys should still use CSI
+INKEY S Up
+ output "\e[1;2A"
+INKEY C Up
+ output "\e[1;5A"
+
+!Shift-Tab should be different
+INKEY 0 Tab
+ output "\x09"
+INKEY S Tab
+ output "\e[Z"
+INKEY C Tab
+ output "\e[9;5u"
+INKEY A Tab
+ output "\e\x09"
+INKEY CA Tab
+ output "\e[9;7u"
+
+!Enter in linefeed mode
+INKEY 0 Enter
+ output "\x0d"
+
+!Enter in newline mode
+PUSH "\e[20h"
+INKEY 0 Enter
+ output "\x0d\x0a"
+
+!Keypad in DECKPNM
+INKEY 0 KP0
+ output "0"
+
+!Keypad in DECKPAM
+PUSH "\e="
+INKEY 0 KP0
+ output "\eOp"
+
+!Bracketed paste mode off
+PASTE START
+PASTE END
+
+!Bracketed paste mode on
+PUSH "\e[?2004h"
+PASTE START
+ output "\e[200~"
+PASTE END
+ output "\e[201~"
+
+!Focus reporting disabled
+FOCUS IN
+FOCUS OUT
+
+!Focus reporting enabled
+PUSH "\e[?1004h"
+FOCUS IN
+ output "\e[I"
+FOCUS OUT
+ output "\e[O"
diff --git a/src/libvterm/t/26state_query.test b/src/libvterm/t/26state_query.test
new file mode 100644
index 0000000..3ace2d5
--- /dev/null
+++ b/src/libvterm/t/26state_query.test
@@ -0,0 +1,62 @@
+INIT
+WANTSTATE
+
+!DA
+RESET
+PUSH "\e[c"
+ output "\e[?1;2c"
+
+!DSR
+RESET
+PUSH "\e[5n"
+ output "\e[0n"
+
+!CPR
+PUSH "\e[6n"
+ output "\e[1;1R"
+PUSH "\e[10;10H\e[6n"
+ output "\e[10;10R"
+
+!DECCPR
+PUSH "\e[?6n"
+ output "\e[?10;10R"
+
+!DECRQSS on DECSCUSR
+PUSH "\e[3 q"
+PUSH "\eP\$q q\e\\"
+ output "\eP1\$r3 q\e\\"
+
+!DECRQSS on SGR
+PUSH "\e[1;5;7m"
+PUSH "\eP\$qm\e\\"
+ output "\eP1\$r1;5;7m\e\\"
+
+!DECRQSS on SGR ANSI colours
+PUSH "\e[0;31;42m"
+PUSH "\eP\$qm\e\\"
+ output "\eP1\$r31;42m\e\\"
+
+!DECRQSS on SGR ANSI hi-bright colours
+PUSH "\e[0;93;104m"
+PUSH "\eP\$qm\e\\"
+ output "\eP1\$r93;104m\e\\"
+
+!DECRQSS on SGR 256-palette colours
+PUSH "\e[0;38:5:56;48:5:78m"
+PUSH "\eP\$qm\e\\"
+ output "\eP1\$r38:5:56;48:5:78m\e\\"
+
+!DECRQSS on SGR RGB8 colours
+PUSH "\e[0;38:2:24:68:112;48:2:13:57:101m"
+PUSH "\eP\$qm\e\\"
+ output "\eP1\$r38:2:24:68:112;48:2:13:57:101m\e\\"
+
+!S8C1T on DSR
+PUSH "\e G"
+PUSH "\e[5n"
+ output "\x{9b}0n"
+PUSH "\e F"
+
+!Truncation on attempted buffer overflow
+PUSH "\e[6n" x 30
+ output "\e[10;10R" x 24
diff --git a/src/libvterm/t/27state_reset.test b/src/libvterm/t/27state_reset.test
new file mode 100644
index 0000000..254f994
--- /dev/null
+++ b/src/libvterm/t/27state_reset.test
@@ -0,0 +1,32 @@
+INIT
+WANTSTATE
+
+RESET
+
+!RIS homes cursor
+PUSH "\e[5;5H"
+ ?cursor = 4,4
+WANTSTATE +m
+PUSH "\ec"
+ ?cursor = 0,0
+WANTSTATE -m
+
+!RIS cancels scrolling region
+PUSH "\e[5;10r"
+WANTSTATE +s
+PUSH "\ec\e[25H\n"
+ scrollrect 0..25,0..80 => +1,+0
+WANTSTATE -s
+
+!RIS erases screen
+PUSH "ABCDE"
+WANTSTATE +e
+PUSH "\ec"
+ erase 0..25,0..80
+WANTSTATE -e
+
+!RIS clears tabstops
+PUSH "\e[5G\eH\e[G\t"
+ ?cursor = 0,4
+PUSH "\ec\t"
+ ?cursor = 0,8
diff --git a/src/libvterm/t/28state_dbl_wh.test b/src/libvterm/t/28state_dbl_wh.test
new file mode 100644
index 0000000..596194d
--- /dev/null
+++ b/src/libvterm/t/28state_dbl_wh.test
@@ -0,0 +1,61 @@
+INIT
+WANTSTATE g
+
+!Single Width, Single Height
+RESET
+PUSH "\e#5"
+PUSH "Hello"
+ putglyph 0x48 1 0,0
+ putglyph 0x65 1 0,1
+ putglyph 0x6c 1 0,2
+ putglyph 0x6c 1 0,3
+ putglyph 0x6f 1 0,4
+
+!Double Width, Single Height
+RESET
+PUSH "\e#6"
+PUSH "Hello"
+ putglyph 0x48 1 0,0 dwl
+ putglyph 0x65 1 0,1 dwl
+ putglyph 0x6c 1 0,2 dwl
+ putglyph 0x6c 1 0,3 dwl
+ putglyph 0x6f 1 0,4 dwl
+ ?cursor = 0,5
+PUSH "\e[40GAB"
+ putglyph 0x41 1 0,39 dwl
+ putglyph 0x42 1 1,0
+ ?cursor = 1,1
+
+!Double Height
+RESET
+PUSH "\e#3"
+PUSH "Hello"
+ putglyph 0x48 1 0,0 dwl dhl-top
+ putglyph 0x65 1 0,1 dwl dhl-top
+ putglyph 0x6c 1 0,2 dwl dhl-top
+ putglyph 0x6c 1 0,3 dwl dhl-top
+ putglyph 0x6f 1 0,4 dwl dhl-top
+ ?cursor = 0,5
+PUSH "\r\n\e#4"
+PUSH "Hello"
+ putglyph 0x48 1 1,0 dwl dhl-bottom
+ putglyph 0x65 1 1,1 dwl dhl-bottom
+ putglyph 0x6c 1 1,2 dwl dhl-bottom
+ putglyph 0x6c 1 1,3 dwl dhl-bottom
+ putglyph 0x6f 1 1,4 dwl dhl-bottom
+ ?cursor = 1,5
+
+!Double Width scrolling
+RESET
+PUSH "\e[20H\e#6ABC"
+ putglyph 0x41 1 19,0 dwl
+ putglyph 0x42 1 19,1 dwl
+ putglyph 0x43 1 19,2 dwl
+PUSH "\e[25H\n"
+PUSH "\e[19;4HDE"
+ putglyph 0x44 1 18,3 dwl
+ putglyph 0x45 1 18,4 dwl
+PUSH "\e[H\eM"
+PUSH "\e[20;6HFG"
+ putglyph 0x46 1 19,5 dwl
+ putglyph 0x47 1 19,6 dwl
diff --git a/src/libvterm/t/29state_fallback.test b/src/libvterm/t/29state_fallback.test
new file mode 100644
index 0000000..adf1c23
--- /dev/null
+++ b/src/libvterm/t/29state_fallback.test
@@ -0,0 +1,19 @@
+INIT
+WANTSTATE f
+RESET
+
+!Unrecognised control
+PUSH "\x03"
+ control 03
+
+!Unrecognised CSI
+PUSH "\e[?15;2z"
+ csi 0x7a L=3f 15,2
+
+!Unrecognised OSC
+PUSH "\e]27;Something\e\\"
+ osc "27;Something"
+
+!Unrecognised DCS
+PUSH "\ePz123\e\\"
+ dcs "z123"
diff --git a/src/libvterm/t/30pen.test b/src/libvterm/t/30pen.test
new file mode 100644
index 0000000..7a671e7
--- /dev/null
+++ b/src/libvterm/t/30pen.test
@@ -0,0 +1,106 @@
+INIT
+UTF8 1
+WANTSTATE
+
+!Reset
+PUSH "\e[m"
+ ?pen bold = off
+ ?pen underline = 0
+ ?pen italic = off
+ ?pen blink = off
+ ?pen reverse = off
+ ?pen font = 0
+ ?pen foreground = rgb(240,240,240)
+ ?pen background = rgb(0,0,0)
+
+!Bold
+PUSH "\e[1m"
+ ?pen bold = on
+PUSH "\e[22m"
+ ?pen bold = off
+PUSH "\e[1m\e[m"
+ ?pen bold = off
+
+!Underline
+PUSH "\e[4m"
+ ?pen underline = 1
+PUSH "\e[21m"
+ ?pen underline = 2
+PUSH "\e[24m"
+ ?pen underline = 0
+PUSH "\e[4m\e[m"
+ ?pen underline = 0
+
+!Italic
+PUSH "\e[3m"
+ ?pen italic = on
+PUSH "\e[23m"
+ ?pen italic = off
+PUSH "\e[3m\e[m"
+ ?pen italic = off
+
+!Blink
+PUSH "\e[5m"
+ ?pen blink = on
+PUSH "\e[25m"
+ ?pen blink = off
+PUSH "\e[5m\e[m"
+ ?pen blink = off
+
+!Reverse
+PUSH "\e[7m"
+ ?pen reverse = on
+PUSH "\e[27m"
+ ?pen reverse = off
+PUSH "\e[7m\e[m"
+ ?pen reverse = off
+
+!Font Selection
+PUSH "\e[11m"
+ ?pen font = 1
+PUSH "\e[19m"
+ ?pen font = 9
+PUSH "\e[10m"
+ ?pen font = 0
+PUSH "\e[11m\e[m"
+ ?pen font = 0
+
+!Foreground
+PUSH "\e[31m"
+ ?pen foreground = rgb(224,0,0)
+PUSH "\e[32m"
+ ?pen foreground = rgb(0,224,0)
+PUSH "\e[34m"
+ ?pen foreground = rgb(0,0,224)
+PUSH "\e[91m"
+ ?pen foreground = rgb(255,64,64)
+PUSH "\e[38:2:10:20:30m"
+ ?pen foreground = rgb(10,20,30)
+PUSH "\e[38:5:1m"
+ ?pen foreground = rgb(224,0,0)
+PUSH "\e[39m"
+ ?pen foreground = rgb(240,240,240)
+
+!Background
+PUSH "\e[41m"
+ ?pen background = rgb(224,0,0)
+PUSH "\e[42m"
+ ?pen background = rgb(0,224,0)
+PUSH "\e[44m"
+ ?pen background = rgb(0,0,224)
+PUSH "\e[101m"
+ ?pen background = rgb(255,64,64)
+PUSH "\e[48:2:10:20:30m"
+ ?pen background = rgb(10,20,30)
+PUSH "\e[48:5:1m"
+ ?pen background = rgb(224,0,0)
+PUSH "\e[49m"
+ ?pen background = rgb(0,0,0)
+
+!Bold+ANSI colour == highbright
+PUSH "\e[m\e[1;37m"
+ ?pen bold = on
+ ?pen foreground = rgb(255,255,255)
+PUSH "\e[m\e[37;1m"
+ ?pen bold = on
+ ?pen foreground = rgb(255,255,255)
diff --git a/src/libvterm/t/40screen_ascii.test b/src/libvterm/t/40screen_ascii.test
new file mode 100644
index 0000000..c2f48fa
--- /dev/null
+++ b/src/libvterm/t/40screen_ascii.test
@@ -0,0 +1,69 @@
+INIT
+WANTSCREEN c
+
+!Get
+RESET
+PUSH "ABC"
+ movecursor 0,3
+ ?screen_chars 0,0,1,3 = 0x41,0x42,0x43
+ ?screen_chars 0,0,1,80 = 0x41,0x42,0x43
+ ?screen_text 0,0,1,3 = 0x41,0x42,0x43
+ ?screen_text 0,0,1,80 = 0x41,0x42,0x43
+ ?screen_cell 0,0 = {0x41} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)
+ ?screen_cell 0,1 = {0x42} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)
+ ?screen_cell 0,2 = {0x43} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)
+ ?screen_row 0 = "ABC"
+ ?screen_eol 0,0 = 0
+ ?screen_eol 0,2 = 0
+ ?screen_eol 0,3 = 1
+PUSH "\e[H"
+ movecursor 0,0
+ ?screen_chars 0,0,1,80 = 0x41,0x42,0x43
+ ?screen_text 0,0,1,80 = 0x41,0x42,0x43
+PUSH "E"
+ movecursor 0,1
+ ?screen_chars 0,0,1,80 = 0x45,0x42,0x43
+ ?screen_text 0,0,1,80 = 0x45,0x42,0x43
+
+WANTSCREEN -c
+
+!Erase
+RESET
+PUSH "ABCDE\e[H\e[K"
+ ?screen_chars 0,0,1,80 =
+ ?screen_text 0,0,1,80 =
+
+!Copycell
+RESET
+PUSH "ABC\e[H\e[@"
+PUSH "1"
+ ?screen_chars 0,0,1,80 = 0x31,0x41,0x42,0x43
+
+RESET
+PUSH "ABC\e[H\e[P"
+ ?screen_chars 0,0,1,1 = 0x42
+ ?screen_chars 0,1,1,2 = 0x43
+ ?screen_chars 0,0,1,80 = 0x42,0x43
+
+!Space padding
+RESET
+PUSH "Hello\e[CWorld"
+ ?screen_chars 0,0,1,80 = 0x48,0x65,0x6c,0x6c,0x6f,0x20,0x57,0x6f,0x72,0x6c,0x64
+ ?screen_text 0,0,1,80 = 0x48,0x65,0x6c,0x6c,0x6f,0x20,0x57,0x6f,0x72,0x6c,0x64
+
+!Linefeed padding
+RESET
+PUSH "Hello\r\nWorld"
+ ?screen_chars 0,0,2,80 = 0x48,0x65,0x6c,0x6c,0x6f,0x0a,0x57,0x6f,0x72,0x6c,0x64
+ ?screen_text 0,0,2,80 = 0x48,0x65,0x6c,0x6c,0x6f,0x0a,0x57,0x6f,0x72,0x6c,0x64
+
+!Altscreen
+RESET
+PUSH "P"
+ ?screen_chars 0,0,1,80 = 0x50
+PUSH "\e[?1049h"
+ ?screen_chars 0,0,1,80 =
+PUSH "\e[2K\e[HA"
+ ?screen_chars 0,0,1,80 = 0x41
+PUSH "\e[?1049l"
+ ?screen_chars 0,0,1,80 = 0x50
diff --git a/src/libvterm/t/41screen_unicode.test b/src/libvterm/t/41screen_unicode.test
new file mode 100644
index 0000000..79dcb68
--- /dev/null
+++ b/src/libvterm/t/41screen_unicode.test
@@ -0,0 +1,47 @@
+INIT
+UTF8 1
+WANTSCREEN
+
+!Single width UTF-8
+# U+00C1 = 0xC3 0x81 name: LATIN CAPITAL LETTER A WITH ACUTE
+# U+00E9 = 0xC3 0xA9 name: LATIN SMALL LETTER E WITH ACUTE
+RESET
+PUSH "\xC3\x81\xC3\xA9"
+ ?screen_chars 0,0,1,80 = 0xc1,0xe9
+ ?screen_text 0,0,1,80 = 0xc3,0x81,0xc3,0xa9
+ ?screen_cell 0,0 = {0xc1} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)
+
+!Wide char
+# U+FF10 = 0xEF 0xBC 0x90 name: FULLWIDTH DIGIT ZERO
+RESET
+PUSH "0123\e[H"
+PUSH "\xEF\xBC\x90"
+ ?screen_chars 0,0,1,80 = 0xff10,0x32,0x33
+ ?screen_text 0,0,1,80 = 0xef,0xbc,0x90,0x32,0x33
+ ?screen_cell 0,0 = {0xff10} width=2 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)
+
+!Combining char
+# U+0301 = 0xCC 0x81 name: COMBINING ACUTE
+RESET
+PUSH "0123\e[H"
+PUSH "e\xCC\x81"
+ ?screen_chars 0,0,1,80 = 0x65,0x301,0x31,0x32,0x33
+ ?screen_text 0,0,1,80 = 0x65,0xcc,0x81,0x31,0x32,0x33
+ ?screen_cell 0,0 = {0x65,0x301} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)
+
+!10 combining accents should not crash
+RESET
+PUSH "e\xCC\x81\xCC\x82\xCC\x83\xCC\x84\xCC\x85\xCC\x86\xCC\x87\xCC\x88\xCC\x89\xCC\x8A"
+ ?screen_cell 0,0 = {0x65,0x301,0x302,0x303,0x304,0x305} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)
+
+!40 combining accents in two split writes of 20 should not crash
+RESET
+PUSH "e\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81"
+PUSH "\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81"
+ ?screen_cell 0,0 = {0x65,0x301,0x301,0x301,0x301,0x301} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)
+
+!Outputing CJK doublewidth in 80th column should wraparound to next line and not crash"
+RESET
+PUSH "\e[80G\xEF\xBC\x90"
+ ?screen_cell 0,79 = {} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)
+ ?screen_cell 1,0 = {0xff10} width=2 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)
diff --git a/src/libvterm/t/42screen_damage.test b/src/libvterm/t/42screen_damage.test
new file mode 100644
index 0000000..791a96c
--- /dev/null
+++ b/src/libvterm/t/42screen_damage.test
@@ -0,0 +1,155 @@
+INIT
+WANTSCREEN Db
+
+!Putglyph
+RESET
+ damage 0..25,0..80
+PUSH "123"
+ damage 0..1,0..1 = 0<31>
+ damage 0..1,1..2 = 0<32>
+ damage 0..1,2..3 = 0<33>
+
+!Erase
+PUSH "\e[H"
+PUSH "\e[3X"
+ damage 0..1,0..3
+
+!Scroll damages entire line in two chunks
+PUSH "\e[H\e[5@"
+ damage 0..1,5..80
+ damage 0..1,0..5
+
+!Scroll down damages entire screen in two chunks
+PUSH "\e[T"
+ damage 1..25,0..80
+ damage 0..1,0..80
+
+!Altscreen damages entire area
+PUSH "\e[?1049h"
+ damage 0..25,0..80
+PUSH "\e[?1049l"
+ damage 0..25,0..80
+
+WANTSCREEN m
+
+!Scroll invokes moverect but not damage
+PUSH "\e[5@"
+ moverect 0..1,0..75 -> 0..1,5..80
+ damage 0..1,0..5
+
+WANTSCREEN -m
+
+!Merge to cells
+RESET
+ damage 0..25,0..80
+DAMAGEMERGE CELL
+
+PUSH "A"
+ damage 0..1,0..1 = 0<41>
+PUSH "B"
+ damage 0..1,1..2 = 0<42>
+PUSH "C"
+ damage 0..1,2..3 = 0<43>
+
+!Merge entire rows
+RESET
+ damage 0..25,0..80
+DAMAGEMERGE ROW
+
+PUSH "ABCDE\r\nEFGH"
+ damage 0..1,0..5 = 0<41 42 43 44 45>
+DAMAGEFLUSH
+ damage 1..2,0..4 = 1<45 46 47 48>
+PUSH "\e[3;6r\e[6H\eD"
+ damage 2..5,0..80
+DAMAGEFLUSH
+ damage 5..6,0..80
+
+!Merge entire screen
+RESET
+ damage 0..25,0..80
+DAMAGEMERGE SCREEN
+
+PUSH "ABCDE\r\nEFGH"
+DAMAGEFLUSH
+ damage 0..2,0..5 = 0<41 42 43 44 45> 1<45 46 47 48>
+PUSH "\e[3;6r\e[6H\eD"
+DAMAGEFLUSH
+ damage 2..6,0..80
+
+!Merge entire screen with moverect
+WANTSCREEN m
+
+RESET
+ damage 0..25,0..80
+DAMAGEMERGE SCREEN
+
+PUSH "ABCDE\r\nEFGH"
+PUSH "\e[3;6r\e[6H\eD"
+ damage 0..2,0..5 = 0<41 42 43 44 45> 1<45 46 47 48>
+ moverect 3..6,0..80 -> 2..5,0..80
+DAMAGEFLUSH
+ damage 5..6,0..80
+
+!Merge scroll
+RESET
+ damage 0..25,0..80
+DAMAGEMERGE SCROLL
+
+PUSH "\e[H1\r\n2\r\n3"
+PUSH "\e[25H\n\n\n"
+ sb_pushline 80 = 31
+ sb_pushline 80 = 32
+ sb_pushline 80 = 33
+DAMAGEFLUSH
+ moverect 3..25,0..80 -> 0..22,0..80
+ damage 0..25,0..80
+
+!Merge scroll with damage
+PUSH "\e[25H"
+PUSH "ABCDE\r\nEFGH\r\n"
+ sb_pushline 80 =
+ sb_pushline 80 =
+DAMAGEFLUSH
+ moverect 2..25,0..80 -> 0..23,0..80
+ damage 22..25,0..80 = 22<41 42 43 44 45> 23<45 46 47 48>
+
+!Merge scroll with damage past region
+PUSH "\e[3;6r\e[6H1\r\n2\r\n3\r\n4\r\n5"
+DAMAGEFLUSH
+ damage 2..6,0..80 = 2<32> 3<33> 4<34> 5<35>
+
+!Damage entirely outside scroll region
+PUSH "\e[HABC\e[3;6r\e[6H\r\n6"
+ damage 0..1,0..3 = 0<41 42 43>
+DAMAGEFLUSH
+ moverect 3..6,0..80 -> 2..5,0..80
+ damage 5..6,0..80 = 5<36>
+
+!Damage overlapping scroll region
+PUSH "\e[H\e[2J"
+DAMAGEFLUSH
+ damage 0..25,0..80
+
+PUSH "\e[HABCD\r\nEFGH\r\nIJKL\e[2;5r\e[5H\r\nMNOP"
+DAMAGEFLUSH
+ moverect 2..5,0..80 -> 1..4,0..80
+ damage 0..5,0..80 = 0<41 42 43 44> 1<49 4A 4B 4C>
+ ## TODO: is this right?
+
+!Merge scroll*2 with damage
+RESET
+ damage 0..25,0..80
+DAMAGEMERGE SCROLL
+
+PUSH "\e[25H\r\nABCDE\b\b\b\e[2P\r\n"
+ sb_pushline 80 =
+ moverect 1..25,0..80 -> 0..24,0..80
+ damage 24..25,0..80 = 24<41 42 43 44 45>
+ moverect 24..25,4..80 -> 24..25,2..78
+ damage 24..25,78..80
+ sb_pushline 80 =
+DAMAGEFLUSH
+ moverect 1..25,0..80 -> 0..24,0..80
+ damage 24..25,0..80
+ ?screen_chars 23,0,24,5 = 0x41,0x42,0x45
diff --git a/src/libvterm/t/43screen_resize.test b/src/libvterm/t/43screen_resize.test
new file mode 100644
index 0000000..9e5e5b2
--- /dev/null
+++ b/src/libvterm/t/43screen_resize.test
@@ -0,0 +1,90 @@
+INIT
+WANTSTATE
+WANTSCREEN
+
+!Resize wider preserves cells
+RESET
+RESIZE 25,80
+PUSH "AB\r\nCD"
+ ?screen_chars 0,0,1,80 = 0x41,0x42
+ ?screen_chars 1,0,2,80 = 0x43,0x44
+RESIZE 25,100
+ ?screen_chars 0,0,1,100 = 0x41,0x42
+ ?screen_chars 1,0,2,100 = 0x43,0x44
+
+!Resize wider allows print in new area
+RESET
+RESIZE 25,80
+PUSH "AB\e[79GCD"
+ ?screen_chars 0,0,1,2 = 0x41,0x42
+ ?screen_chars 0,78,1,80 = 0x43,0x44
+RESIZE 25,100
+ ?screen_chars 0,0,1,2 = 0x41,0x42
+ ?screen_chars 0,78,1,80 = 0x43,0x44
+PUSH "E"
+ ?screen_chars 0,78,1,81 = 0x43,0x44,0x45
+
+!Resize shorter with blanks just truncates
+RESET
+RESIZE 25,80
+PUSH "Top\e[10HLine 10"
+ ?screen_chars 0,0,1,80 = 0x54,0x6f,0x70
+ ?screen_chars 9,0,10,80 = 0x4c,0x69,0x6e,0x65,0x20,0x31,0x30
+ ?cursor = 9,7
+RESIZE 20,80
+ ?screen_chars 0,0,1,80 = 0x54,0x6f,0x70
+ ?screen_chars 9,0,10,80 = 0x4c,0x69,0x6e,0x65,0x20,0x31,0x30
+ ?cursor = 9,7
+
+!Resize shorter with content must scroll
+RESET
+RESIZE 25,80
+PUSH "Top\e[25HLine 25\e[15H"
+ ?screen_chars 0,0,1,80 = 0x54,0x6f,0x70
+ ?screen_chars 24,0,25,80 = 0x4c,0x69,0x6e,0x65,0x20,0x32,0x35
+ ?cursor = 14,0
+WANTSCREEN b
+RESIZE 20,80
+ sb_pushline 80 = 54 6F 70
+ sb_pushline 80 =
+ sb_pushline 80 =
+ sb_pushline 80 =
+ sb_pushline 80 =
+ ?screen_chars 0,0,1,80 =
+ ?screen_chars 19,0,20,80 = 0x4c,0x69,0x6e,0x65,0x20,0x32,0x35
+ ?cursor = 9,0
+
+!Resize shorter does not lose line with cursor
+# See also https://github.com/neovim/libvterm/commit/1b745d29d45623aa8d22a7b9288c7b0e331c7088
+RESET
+WANTSCREEN -b
+RESIZE 25,80
+WANTSCREEN b
+PUSH "\e[24HLine 24\r\nLine 25\r\n"
+ sb_pushline 80 =
+ ?screen_chars 23,0,24,10 = 0x4c,0x69,0x6e,0x65,0x20,0x32,0x35
+ ?cursor = 24,0
+RESIZE 24,80
+ sb_pushline 80 =
+ ?screen_chars 22,0,23,10 = 0x4c,0x69,0x6e,0x65,0x20,0x32,0x35
+ ?cursor = 23,0
+
+!Resize taller attempts to pop scrollback
+RESET
+WANTSCREEN -b
+RESIZE 25,80
+PUSH "Line 1\e[25HBottom\e[15H"
+ ?screen_chars 0,0,1,80 = 0x4c,0x69,0x6e,0x65,0x20,0x31
+ ?screen_chars 24,0,25,80 = 0x42,0x6f,0x74,0x74,0x6f,0x6d
+ ?cursor = 14,0
+WANTSCREEN b
+RESIZE 30,80
+ sb_popline 80
+ sb_popline 80
+ sb_popline 80
+ sb_popline 80
+ sb_popline 80
+ ?screen_chars 0,0,1,80 = 0x41,0x42,0x43,0x44,0x45
+ ?screen_chars 5,0,6,80 = 0x4c,0x69,0x6e,0x65,0x20,0x31
+ ?screen_chars 29,0,30,80 = 0x42,0x6f,0x74,0x74,0x6f,0x6d
+ ?cursor = 19,0
diff --git a/src/libvterm/t/44screen_pen.test b/src/libvterm/t/44screen_pen.test
new file mode 100644
index 0000000..f1ee639
--- /dev/null
+++ b/src/libvterm/t/44screen_pen.test
@@ -0,0 +1,55 @@
+INIT
+WANTSCREEN
+
+RESET
+
+!Plain
+PUSH "A"
+ ?screen_cell 0,0 = {0x41} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)
+
+!Bold
+PUSH "\e[1mB"
+ ?screen_cell 0,1 = {0x42} width=1 attrs={B} fg=rgb(240,240,240) bg=rgb(0,0,0)
+
+!Italic
+PUSH "\e[3mC"
+ ?screen_cell 0,2 = {0x43} width=1 attrs={BI} fg=rgb(240,240,240) bg=rgb(0,0,0)
+
+!Underline
+PUSH "\e[4mD"
+ ?screen_cell 0,3 = {0x44} width=1 attrs={BU1I} fg=rgb(240,240,240) bg=rgb(0,0,0)
+
+!Reset
+PUSH "\e[mE"
+ ?screen_cell 0,4 = {0x45} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)
+
+!Font
+PUSH "\e[11mF\e[m"
+ ?screen_cell 0,5 = {0x46} width=1 attrs={F1} fg=rgb(240,240,240) bg=rgb(0,0,0)
+
+!Foreground
+PUSH "\e[31mG\e[m"
+ ?screen_cell 0,6 = {0x47} width=1 attrs={} fg=rgb(224,0,0) bg=rgb(0,0,0)
+
+!Background
+PUSH "\e[42mH\e[m"
+ ?screen_cell 0,7 = {0x48} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,224,0)
+
+!EL sets reverse and colours to end of line
+PUSH "\e[H\e[7;33;44m\e[K"
+ ?screen_cell 0,0 = {} width=1 attrs={R} fg=rgb(224,224,0) bg=rgb(0,0,224)
+ ?screen_cell 0,79 = {} width=1 attrs={R} fg=rgb(224,224,0) bg=rgb(0,0,224)
+
+!DECSCNM xors reverse for entire screen
+PUSH "\e[?5h"
+ ?screen_cell 0,0 = {} width=1 attrs={} fg=rgb(224,224,0) bg=rgb(0,0,224)
+ ?screen_cell 0,79 = {} width=1 attrs={} fg=rgb(224,224,0) bg=rgb(0,0,224)
+ ?screen_cell 1,0 = {} width=1 attrs={R} fg=rgb(240,240,240) bg=rgb(0,0,0)
+PUSH "\e[?5\$p"
+ output "\e[?5;1\$y"
+PUSH "\e[?5l"
+ ?screen_cell 0,0 = {} width=1 attrs={R} fg=rgb(224,224,0) bg=rgb(0,0,224)
+ ?screen_cell 0,79 = {} width=1 attrs={R} fg=rgb(224,224,0) bg=rgb(0,0,224)
+ ?screen_cell 1,0 = {} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)
+PUSH "\e[?5\$p"
+ output "\e[?5;2\$y"
diff --git a/src/libvterm/t/45screen_protect.test b/src/libvterm/t/45screen_protect.test
new file mode 100644
index 0000000..718f853
--- /dev/null
+++ b/src/libvterm/t/45screen_protect.test
@@ -0,0 +1,16 @@
+INIT
+WANTSCREEN
+
+!Selective erase
+RESET
+PUSH "A\e[1\"qB\e[\"qC"
+ ?screen_chars 0,0,1,3 = 0x41,0x42,0x43
+PUSH "\e[G\e[?J"
+ ?screen_chars 0,0,1,3 = 0x20,0x42
+
+!Non-selective erase
+RESET
+PUSH "A\e[1\"qB\e[\"qC"
+ ?screen_chars 0,0,1,3 = 0x41,0x42,0x43
+PUSH "\e[G\e[J"
+ ?screen_chars 0,0,1,3 =
diff --git a/src/libvterm/t/46screen_extent.test b/src/libvterm/t/46screen_extent.test
new file mode 100644
index 0000000..a126cec
--- /dev/null
+++ b/src/libvterm/t/46screen_extent.test
@@ -0,0 +1,11 @@
+INIT
+WANTSCREEN
+
+!Bold extent
+RESET
+PUSH "AB\e[1mCD\e[mE"
+ ?screen_attrs_extent 0,0 = 0,0-1,1
+ ?screen_attrs_extent 0,1 = 0,0-1,1
+ ?screen_attrs_extent 0,2 = 0,2-1,3
+ ?screen_attrs_extent 0,3 = 0,2-1,3
+ ?screen_attrs_extent 0,4 = 0,4-1,79
diff --git a/src/libvterm/t/47screen_dbl_wh.test b/src/libvterm/t/47screen_dbl_wh.test
new file mode 100644
index 0000000..7d17d9a
--- /dev/null
+++ b/src/libvterm/t/47screen_dbl_wh.test
@@ -0,0 +1,32 @@
+INIT
+WANTSCREEN
+
+RESET
+
+!Single Width, Single Height
+RESET
+PUSH "\e#5"
+PUSH "abcde"
+ ?screen_cell 0,0 = {0x61} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)
+
+!Double Width, Single Height
+RESET
+PUSH "\e#6"
+PUSH "abcde"
+ ?screen_cell 0,0 = {0x61} width=1 attrs={} dwl fg=rgb(240,240,240) bg=rgb(0,0,0)
+
+!Double Height
+RESET
+PUSH "\e#3"
+PUSH "abcde"
+PUSH "\r\n\e#4"
+PUSH "abcde"
+ ?screen_cell 0,0 = {0x61} width=1 attrs={} dwl dhl-top fg=rgb(240,240,240) bg=rgb(0,0,0)
+ ?screen_cell 1,0 = {0x61} width=1 attrs={} dwl dhl-bottom fg=rgb(240,240,240) bg=rgb(0,0,0)
+
+!Late change
+RESET
+PUSH "abcde"
+ ?screen_cell 0,0 = {0x61} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)
+PUSH "\e#6"
+ ?screen_cell 0,0 = {0x61} width=1 attrs={} dwl fg=rgb(240,240,240) bg=rgb(0,0,0)
diff --git a/src/libvterm/t/48screen_termprops.test b/src/libvterm/t/48screen_termprops.test
new file mode 100644
index 0000000..adf7ec2
--- /dev/null
+++ b/src/libvterm/t/48screen_termprops.test
@@ -0,0 +1,17 @@
+INIT
+WANTSCREEN p
+
+RESET
+ settermprop 1 true
+ settermprop 2 true
+ settermprop 7 1
+
+!Cursor visibility
+PUSH "\e[?25h"
+ settermprop 1 true
+PUSH "\e[?25l"
+ settermprop 1 false
+
+!Title
+PUSH "\e]2;Here is my title\a"
+ settermprop 4 "Here is my title"
diff --git a/src/libvterm/t/90vttest_01-movement-1.test b/src/libvterm/t/90vttest_01-movement-1.test
new file mode 100644
index 0000000..c1a8cb9
--- /dev/null
+++ b/src/libvterm/t/90vttest_01-movement-1.test
@@ -0,0 +1,87 @@
+INIT
+WANTSTATE
+WANTSCREEN
+
+RESET
+
+PUSH "\e#8"
+
+PUSH "\e[9;10H\e[1J"
+PUSH "\e[18;60H\e[0J\e[1K"
+PUSH "\e[9;71H\e[0K"
+
+$SEQ 10 16: PUSH "\e[\#;10H\e[1K\e[\#;71H\e[0K"
+
+PUSH "\e[17;30H\e[2K"
+
+$SEQ 1 80: PUSH "\e[24;\#f*\e[1;\#f*"
+
+PUSH "\e[2;2H"
+
+$REP 22: PUSH "+\e[1D\eD"
+
+PUSH "\e[23;79H"
+$REP 22: PUSH "+\e[1D\eM"
+
+PUSH "\e[2;1H"
+$SEQ 2 23: PUSH "*\e[\#;80H*\e[10D\eE"
+
+PUSH "\e[2;10H\e[42D\e[2C"
+$REP 76: PUSH "+\e[0C\e[2D\e[1C"
+
+PUSH "\e[23;70H\e[42C\e[2D"
+
+$REP 76: PUSH "+\e[1D\e[1C\e[0D\b"
+
+PUSH "\e[1;1H"
+PUSH "\e[10A"
+PUSH "\e[1A"
+PUSH "\e[0A"
+PUSH "\e[24;80H"
+PUSH "\e[10B"
+PUSH "\e[1B"
+PUSH "\e[0B"
+PUSH "\e[10;12H"
+
+$REP 58: PUSH " "
+PUSH "\e[1B\e[58D"
+
+$REP 58: PUSH " "
+PUSH "\e[1B\e[58D"
+
+$REP 58: PUSH " "
+PUSH "\e[1B\e[58D"
+
+$REP 58: PUSH " "
+PUSH "\e[1B\e[58D"
+
+$REP 58: PUSH " "
+PUSH "\e[1B\e[58D"
+
+$REP 58: PUSH " "
+PUSH "\e[1B\e[58D"
+
+PUSH "\e[5A\e[1CThe screen should be cleared, and have an unbroken bor-"
+PUSH "\e[12;13Hder of *'s and +'s around the edge, and exactly in the"
+PUSH "\e[13;13Hmiddle there should be a frame of E's around this text"
+PUSH "\e[14;13Hwith one (1) free position around it. Push <RETURN>"
+
+# And the result is...
+
+!Output
+ ?screen_row 0 = "********************************************************************************"
+ ?screen_row 1 = "*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*"
+$SEQ 2 7: ?screen_row \# = "*+ +*"
+ ?screen_row 8 = "*+ EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE +*"
+ ?screen_row 9 = "*+ E E +*"
+ ?screen_row 10 = "*+ E The screen should be cleared, and have an unbroken bor- E +*"
+ ?screen_row 11 = "*+ E der of *'s and +'s around the edge, and exactly in the E +*"
+ ?screen_row 12 = "*+ E middle there should be a frame of E's around this text E +*"
+ ?screen_row 13 = "*+ E with one (1) free position around it. Push <RETURN> E +*"
+ ?screen_row 14 = "*+ E E +*"
+ ?screen_row 15 = "*+ EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE +*"
+$SEQ 16 21: ?screen_row \# = "*+ +*"
+ ?screen_row 22 = "*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*"
+ ?screen_row 23 = "********************************************************************************"
+
+?cursor = 13,67
diff --git a/src/libvterm/t/90vttest_01-movement-2.test b/src/libvterm/t/90vttest_01-movement-2.test
new file mode 100644
index 0000000..3a515e3
--- /dev/null
+++ b/src/libvterm/t/90vttest_01-movement-2.test
@@ -0,0 +1,40 @@
+INIT
+WANTSTATE
+WANTSCREEN
+
+RESET
+
+PUSH "\e[3;21r"
+PUSH "\e[?6h"
+
+PUSH "\e[19;1HA\e[19;80Ha\x0a\e[18;80HaB\e[19;80HB\b b\x0a\e[19;80HC\b\b\t\tc\e[19;2H\bC\x0a\e[19;80H\x0a\e[18;1HD\e[18;80Hd"
+PUSH "\e[19;1HE\e[19;80He\x0a\e[18;80HeF\e[19;80HF\b f\x0a\e[19;80HG\b\b\t\tg\e[19;2H\bG\x0a\e[19;80H\x0a\e[18;1HH\e[18;80Hh"
+PUSH "\e[19;1HI\e[19;80Hi\x0a\e[18;80HiJ\e[19;80HJ\b j\x0a\e[19;80HK\b\b\t\tk\e[19;2H\bK\x0a\e[19;80H\x0a\e[18;1HL\e[18;80Hl"
+PUSH "\e[19;1HM\e[19;80Hm\x0a\e[18;80HmN\e[19;80HN\b n\x0a\e[19;80HO\b\b\t\to\e[19;2H\bO\x0a\e[19;80H\x0a\e[18;1HP\e[18;80Hp"
+PUSH "\e[19;1HQ\e[19;80Hq\x0a\e[18;80HqR\e[19;80HR\b r\x0a\e[19;80HS\b\b\t\ts\e[19;2H\bS\x0a\e[19;80H\x0a\e[18;1HT\e[18;80Ht"
+PUSH "\e[19;1HU\e[19;80Hu\x0a\e[18;80HuV\e[19;80HV\b v\x0a\e[19;80HW\b\b\t\tw\e[19;2H\bW\x0a\e[19;80H\x0a\e[18;1HX\e[18;80Hx"
+PUSH "\e[19;1HY\e[19;80Hy\x0a\e[18;80HyZ\e[19;80HZ\b z\x0a"
+
+!Output
+
+?screen_row 2 = "I i"
+?screen_row 3 = "J j"
+?screen_row 4 = "K k"
+?screen_row 5 = "L l"
+?screen_row 6 = "M m"
+?screen_row 7 = "N n"
+?screen_row 8 = "O o"
+?screen_row 9 = "P p"
+?screen_row 10 = "Q q"
+?screen_row 11 = "R r"
+?screen_row 12 = "S s"
+?screen_row 13 = "T t"
+?screen_row 14 = "U u"
+?screen_row 15 = "V v"
+?screen_row 16 = "W w"
+?screen_row 17 = "X x"
+?screen_row 18 = "Y y"
+?screen_row 19 = "Z z"
+?screen_row 20 = ""
+
+?cursor = 20,79
diff --git a/src/libvterm/t/90vttest_01-movement-3.test b/src/libvterm/t/90vttest_01-movement-3.test
new file mode 100644
index 0000000..f9a99bf
--- /dev/null
+++ b/src/libvterm/t/90vttest_01-movement-3.test
@@ -0,0 +1,21 @@
+# Test of cursor-control characters inside ESC sequences
+INIT
+WANTSTATE
+WANTSCREEN
+
+RESET
+
+PUSH "A B C D E F G H I"
+PUSH "\x0d\x0a"
+PUSH "A\e[2\bCB\e[2\bCC\e[2\bCD\e[2\bCE\e[2\bCF\e[2\bCG\e[2\bCH\e[2\bCI"
+PUSH "\x0d\x0a"
+PUSH "A \e[\x0d2CB\e[\x0d4CC\e[\x0d6CD\e[\x0d8CE\e[\x0d10CF\e[\x0d12CG\e[\x0d14CH\e[\x0d16CI"
+PUSH "\x0d\x0a"
+PUSH "A \e[1\x0bAB \e[1\x0bAC \e[1\x0bAD \e[1\x0bAE \e[1\x0bAF \e[1\x0bAG \e[1\x0bAH \e[1\x0bAI \e[1\x0bA"
+
+!Output
+
+$SEQ 0 2: ?screen_row \# = "A B C D E F G H I"
+ ?screen_row 3 = "A B C D E F G H I "
+
+?cursor = 3,18
diff --git a/src/libvterm/t/90vttest_01-movement-4.test b/src/libvterm/t/90vttest_01-movement-4.test
new file mode 100644
index 0000000..0dab3c7
--- /dev/null
+++ b/src/libvterm/t/90vttest_01-movement-4.test
@@ -0,0 +1,36 @@
+# Test of leading zeroes in ESC sequences
+INIT
+WANTSCREEN
+
+RESET
+
+PUSH "\e[00000000004;000000001HT"
+PUSH "\e[00000000004;000000002Hh"
+PUSH "\e[00000000004;000000003Hi"
+PUSH "\e[00000000004;000000004Hs"
+PUSH "\e[00000000004;000000005H "
+PUSH "\e[00000000004;000000006Hi"
+PUSH "\e[00000000004;000000007Hs"
+PUSH "\e[00000000004;000000008H "
+PUSH "\e[00000000004;000000009Ha"
+PUSH "\e[00000000004;0000000010H "
+PUSH "\e[00000000004;0000000011Hc"
+PUSH "\e[00000000004;0000000012Ho"
+PUSH "\e[00000000004;0000000013Hr"
+PUSH "\e[00000000004;0000000014Hr"
+PUSH "\e[00000000004;0000000015He"
+PUSH "\e[00000000004;0000000016Hc"
+PUSH "\e[00000000004;0000000017Ht"
+PUSH "\e[00000000004;0000000018H "
+PUSH "\e[00000000004;0000000019Hs"
+PUSH "\e[00000000004;0000000020He"
+PUSH "\e[00000000004;0000000021Hn"
+PUSH "\e[00000000004;0000000022Ht"
+PUSH "\e[00000000004;0000000023He"
+PUSH "\e[00000000004;0000000024Hn"
+PUSH "\e[00000000004;0000000025Hc"
+PUSH "\e[00000000004;0000000026He"
+
+!Output
+
+?screen_row 3 = "This is a correct sentence"
diff --git a/src/libvterm/t/90vttest_02-screen-1.test b/src/libvterm/t/90vttest_02-screen-1.test
new file mode 100644
index 0000000..003d56f
--- /dev/null
+++ b/src/libvterm/t/90vttest_02-screen-1.test
@@ -0,0 +1,18 @@
+# Test of WRAP AROUND mode setting.
+INIT
+WANTSCREEN
+
+RESET
+
+PUSH "\e[?7h"
+$REP 170: PUSH "*"
+
+PUSH "\e[?7l\e[3;1H"
+$REP 177: PUSH "*"
+
+PUSH "\e[?7h\e[5;1HOK"
+
+!Output
+$SEQ 0 2: ?screen_row \# = "********************************************************************************"
+ ?screen_row 3 = ""
+ ?screen_row 4 = "OK"
diff --git a/src/libvterm/t/90vttest_02-screen-2.test b/src/libvterm/t/90vttest_02-screen-2.test
new file mode 100644
index 0000000..1c3a6a7
--- /dev/null
+++ b/src/libvterm/t/90vttest_02-screen-2.test
@@ -0,0 +1,29 @@
+# TAB setting/resetting
+INIT
+WANTSTATE
+WANTSCREEN
+
+RESET
+
+PUSH "\e[2J\e[3g"
+
+PUSH "\e[1;1H"
+$REP 26: PUSH "\e[3C\eH"
+
+PUSH "\e[1;4H"
+$REP 13: PUSH "\e[0g\e[6C"
+
+PUSH "\e[1;7H"
+PUSH "\e[1g\e[2g"
+
+PUSH "\e[1;1H"
+$REP 13: PUSH "\t*"
+
+PUSH "\e[2;2H"
+$REP 13: PUSH " *"
+
+!Output
+?screen_row 0 = " * * * * * * * * * * * * *"
+?screen_row 1 = " * * * * * * * * * * * * *"
+
+?cursor = 1,79
diff --git a/src/libvterm/t/90vttest_02-screen-3.test b/src/libvterm/t/90vttest_02-screen-3.test
new file mode 100644
index 0000000..8cdf8df
--- /dev/null
+++ b/src/libvterm/t/90vttest_02-screen-3.test
@@ -0,0 +1,16 @@
+# Origin mode
+INIT
+WANTSCREEN
+
+RESET
+
+PUSH "\e[?6h"
+PUSH "\e[23;24r"
+PUSH "\n"
+PUSH "Bottom"
+PUSH "\e[1;1H"
+PUSH "Above"
+
+!Output
+?screen_row 22 = "Above"
+?screen_row 23 = "Bottom"
diff --git a/src/libvterm/t/90vttest_02-screen-4.test b/src/libvterm/t/90vttest_02-screen-4.test
new file mode 100644
index 0000000..44d51f1
--- /dev/null
+++ b/src/libvterm/t/90vttest_02-screen-4.test
@@ -0,0 +1,17 @@
+# Origin mode (2)
+INIT
+WANTSCREEN
+
+RESET
+
+PUSH "\e[?6l"
+PUSH "\e[23;24r"
+PUSH "\e[24;1H"
+PUSH "Bottom"
+PUSH "\e[1;1H"
+PUSH "Top"
+
+!Output
+?screen_row 23 = "Bottom"
+?screen_row 0 = "Top"
+
diff --git a/src/libvterm/t/92lp1640917.test b/src/libvterm/t/92lp1640917.test
new file mode 100644
index 0000000..70de439
--- /dev/null
+++ b/src/libvterm/t/92lp1640917.test
@@ -0,0 +1,13 @@
+INIT
+WANTSTATE
+
+!Mouse reporting should not break by idempotent DECSM 1002
+PUSH "\e[?1002h"
+MOUSEMOVE 0,0 0
+MOUSEBTN d 1 0
+ output "\e[M\x20\x21\x21"
+MOUSEMOVE 1,0 0
+ output "\e[M\x40\x21\x22"
+PUSH "\e[?1002h"
+MOUSEMOVE 2,0 0
+ output "\e[M\x40\x21\x23"
diff --git a/src/libvterm/t/harness.c b/src/libvterm/t/harness.c
new file mode 100644
index 0000000..e2c7295
--- /dev/null
+++ b/src/libvterm/t/harness.c
@@ -0,0 +1,945 @@
+#include "vterm.h"
+#include "../src/vterm_internal.h" /* We pull in some internal bits too */
+
+#include <stdio.h>
+#include <string.h>
+
+#define streq(a,b) (!strcmp(a,b))
+#define strstartswith(a,b) (!strncmp(a,b,strlen(b)))
+
+static size_t inplace_hex2bytes(char *s)
+{
+ char *inpos = s, *outpos = s;
+
+ while(*inpos) {
+ unsigned int ch;
+ sscanf(inpos, "%2x", &ch);
+ *outpos = ch;
+ outpos += 1; inpos += 2;
+ }
+
+ return outpos - s;
+}
+
+static VTermModifier strpe_modifiers(char **strp)
+{
+ VTermModifier state = 0;
+
+ while((*strp)[0]) {
+ switch(((*strp)++)[0]) {
+ case 'S': state |= VTERM_MOD_SHIFT; break;
+ case 'C': state |= VTERM_MOD_CTRL; break;
+ case 'A': state |= VTERM_MOD_ALT; break;
+ default: return state;
+ }
+ }
+
+ return state;
+}
+
+static VTermKey strp_key(char *str)
+{
+ static struct {
+ char *name;
+ VTermKey key;
+ } keys[] = {
+ { "Up", VTERM_KEY_UP },
+ { "Tab", VTERM_KEY_TAB },
+ { "Enter", VTERM_KEY_ENTER },
+ { "KP0", VTERM_KEY_KP_0 },
+ { NULL, VTERM_KEY_NONE },
+ };
+ int i;
+
+ for(i = 0; keys[i].name; i++) {
+ if(streq(str, keys[i].name))
+ return keys[i].key;
+ }
+
+ return VTERM_KEY_NONE;
+}
+
+static VTerm *vt;
+static VTermState *state;
+static VTermScreen *screen;
+
+static VTermEncodingInstance encoding;
+
+static int parser_text(const char bytes[], size_t len, void *user)
+{
+ int i;
+
+ printf("text ");
+ for(i = 0; i < len; i++) {
+ unsigned char b = bytes[i];
+ if(b < 0x20 || b == 0x7f || (b >= 0x80 && b < 0xa0))
+ break;
+ printf(i ? ",%x" : "%x", b);
+ }
+ printf("\n");
+
+ return i;
+}
+
+static int parser_control(unsigned char control, void *user)
+{
+ printf("control %02x\n", control);
+
+ return 1;
+}
+
+static int parser_escape(const char bytes[], size_t len, void *user)
+{
+ int i;
+
+ if(bytes[0] >= 0x20 && bytes[0] < 0x30) {
+ if(len < 2)
+ return -1;
+ len = 2;
+ }
+ else {
+ len = 1;
+ }
+
+ printf("escape ");
+ for(i = 0; i < len; i++)
+ printf("%02x", bytes[i]);
+ printf("\n");
+
+ return len;
+}
+
+static int parser_csi(const char *leader, const long args[], int argcount, const char *intermed, char command, void *user)
+{
+ int i;
+ printf("csi %02x", command);
+
+ if(leader && leader[0]) {
+ printf(" L=");
+ for(i = 0; leader[i]; i++)
+ printf("%02x", leader[i]);
+ }
+
+ for(i = 0; i < argcount; i++) {
+ char sep = i ? ',' : ' ';
+
+ if(args[i] == CSI_ARG_MISSING)
+ printf("%c*", sep);
+ else
+ printf("%c%ld%s", sep, CSI_ARG(args[i]), CSI_ARG_HAS_MORE(args[i]) ? "+" : "");
+ }
+
+ if(intermed && intermed[0]) {
+ printf(" I=");
+ for(i = 0; intermed[i]; i++)
+ printf("%02x", intermed[i]);
+ }
+
+ printf("\n");
+
+ return 1;
+}
+
+static int parser_osc(const char *command, size_t cmdlen, void *user)
+{
+ int i;
+ printf("osc ");
+ for(i = 0; i < cmdlen; i++)
+ printf("%02x", command[i]);
+ printf("\n");
+
+ return 1;
+}
+
+static int parser_dcs(const char *command, size_t cmdlen, void *user)
+{
+ int i;
+ printf("dcs ");
+ for(i = 0; i < cmdlen; i++)
+ printf("%02x", command[i]);
+ printf("\n");
+
+ return 1;
+}
+
+static VTermParserCallbacks parser_cbs = {
+ parser_text, /* text */
+ parser_control, /* control */
+ parser_escape, /* escape */
+ parser_csi, /* csi */
+ parser_osc, /* osc */
+ parser_dcs, /* dcs */
+ NULL /* resize */
+};
+
+/* These callbacks are shared by State and Screen */
+
+static int want_movecursor = 0;
+static VTermPos state_pos;
+static int movecursor(VTermPos pos, VTermPos oldpos, int visible, void *user)
+{
+ state_pos = pos;
+
+ if(want_movecursor)
+ printf("movecursor %d,%d\n", pos.row, pos.col);
+
+ return 1;
+}
+
+static int want_scrollrect = 0;
+static int scrollrect(VTermRect rect, int downward, int rightward, void *user)
+{
+ if(!want_scrollrect)
+ return 0;
+
+ printf("scrollrect %d..%d,%d..%d => %+d,%+d\n",
+ rect.start_row, rect.end_row, rect.start_col, rect.end_col,
+ downward, rightward);
+
+ return 1;
+}
+
+static int want_moverect = 0;
+static int moverect(VTermRect dest, VTermRect src, void *user)
+{
+ if(!want_moverect)
+ return 0;
+
+ printf("moverect %d..%d,%d..%d -> %d..%d,%d..%d\n",
+ src.start_row, src.end_row, src.start_col, src.end_col,
+ dest.start_row, dest.end_row, dest.start_col, dest.end_col);
+
+ return 1;
+}
+
+static int want_settermprop = 0;
+static int settermprop(VTermProp prop, VTermValue *val, void *user)
+{
+ VTermValueType type;
+ if(!want_settermprop)
+ return 1;
+
+ type = vterm_get_prop_type(prop);
+ switch(type) {
+ case VTERM_VALUETYPE_BOOL:
+ printf("settermprop %d %s\n", prop, val->boolean ? "true" : "false");
+ return 1;
+ case VTERM_VALUETYPE_INT:
+ printf("settermprop %d %d\n", prop, val->number);
+ return 1;
+ case VTERM_VALUETYPE_STRING:
+ printf("settermprop %d \"%s\"\n", prop, val->string);
+ return 1;
+ case VTERM_VALUETYPE_COLOR:
+ printf("settermprop %d rgb(%d,%d,%d)\n", prop, val->color.red, val->color.green, val->color.blue);
+ return 1;
+
+ case VTERM_N_VALUETYPES:
+ return 0;
+ }
+
+ return 0;
+}
+
+/* These callbacks are for State */
+
+static int want_state_putglyph = 0;
+static int state_putglyph(VTermGlyphInfo *info, VTermPos pos, void *user)
+{
+ int i;
+ if(!want_state_putglyph)
+ return 1;
+
+ printf("putglyph ");
+ for(i = 0; info->chars[i]; i++)
+ printf(i ? ",%x" : "%x", info->chars[i]);
+ printf(" %d %d,%d", info->width, pos.row, pos.col);
+ if(info->protected_cell)
+ printf(" prot");
+ if(info->dwl)
+ printf(" dwl");
+ if(info->dhl)
+ printf(" dhl-%s", info->dhl == 1 ? "top" : info->dhl == 2 ? "bottom" : "?" );
+ printf("\n");
+
+ return 1;
+}
+
+static int want_state_erase = 0;
+static int state_erase(VTermRect rect, int selective, void *user)
+{
+ if(!want_state_erase)
+ return 1;
+
+ printf("erase %d..%d,%d..%d%s\n",
+ rect.start_row, rect.end_row, rect.start_col, rect.end_col,
+ selective ? " selective" : "");
+
+ return 1;
+}
+
+static struct {
+ int bold;
+ int underline;
+ int italic;
+ int blink;
+ int reverse;
+ int strike;
+ int font;
+ VTermColor foreground;
+ VTermColor background;
+} state_pen;
+static int state_setpenattr(VTermAttr attr, VTermValue *val, void *user)
+{
+ switch(attr) {
+ case VTERM_ATTR_BOLD:
+ state_pen.bold = val->boolean;
+ break;
+ case VTERM_ATTR_UNDERLINE:
+ state_pen.underline = val->number;
+ break;
+ case VTERM_ATTR_ITALIC:
+ state_pen.italic = val->boolean;
+ break;
+ case VTERM_ATTR_BLINK:
+ state_pen.blink = val->boolean;
+ break;
+ case VTERM_ATTR_REVERSE:
+ state_pen.reverse = val->boolean;
+ break;
+ case VTERM_ATTR_STRIKE:
+ state_pen.strike = val->boolean;
+ break;
+ case VTERM_ATTR_FONT:
+ state_pen.font = val->number;
+ break;
+ case VTERM_ATTR_FOREGROUND:
+ state_pen.foreground = val->color;
+ break;
+ case VTERM_ATTR_BACKGROUND:
+ state_pen.background = val->color;
+ break;
+
+ case VTERM_N_ATTRS:
+ return 0;
+ }
+
+ return 1;
+}
+
+static int state_setlineinfo(int row, const VTermLineInfo *newinfo, const VTermLineInfo *oldinfo, void *user)
+{
+ return 1;
+}
+
+VTermStateCallbacks state_cbs = {
+ state_putglyph, /* putglyph */
+ movecursor, /* movecursor */
+ scrollrect, /* scrollrect */
+ moverect, /* moverect */
+ state_erase, /* erase */
+ NULL, /* initpen */
+ state_setpenattr, /* setpenattr */
+ settermprop, /* settermprop */
+ NULL, /* bell */
+ NULL, /* resize */
+ state_setlineinfo, /* setlineinfo */
+};
+
+static int want_screen_damage = 0;
+static int want_screen_damage_cells = 0;
+static int screen_damage(VTermRect rect, void *user)
+{
+ if(!want_screen_damage)
+ return 1;
+
+ printf("damage %d..%d,%d..%d",
+ rect.start_row, rect.end_row, rect.start_col, rect.end_col);
+
+ if(want_screen_damage_cells) {
+ int equals = FALSE;
+ int row;
+ int col;
+
+ for(row = rect.start_row; row < rect.end_row; row++) {
+ int eol = rect.end_col;
+ while(eol > rect.start_col) {
+ VTermScreenCell cell;
+ VTermPos pos;
+ pos.row = row;
+ pos.col = eol-1;
+ vterm_screen_get_cell(screen, pos, &cell);
+ if(cell.chars[0])
+ break;
+
+ eol--;
+ }
+
+ if(eol == rect.start_col)
+ break;
+
+ if(!equals)
+ printf(" ="), equals = TRUE;
+
+ printf(" %d<", row);
+ for(col = rect.start_col; col < eol; col++) {
+ VTermScreenCell cell;
+ VTermPos pos;
+ pos.row = row;
+ pos.col = col;
+ vterm_screen_get_cell(screen, pos, &cell);
+ printf(col == rect.start_col ? "%02X" : " %02X", cell.chars[0]);
+ }
+ printf(">");
+ }
+ }
+
+ printf("\n");
+
+ return 1;
+}
+
+static int want_screen_scrollback = 0;
+static int screen_sb_pushline(int cols, const VTermScreenCell *cells, void *user)
+{
+ int eol;
+ int c;
+
+ if(!want_screen_scrollback)
+ return 1;
+
+ eol = cols;
+ while(eol && !cells[eol-1].chars[0])
+ eol--;
+
+ printf("sb_pushline %d =", cols);
+ for(c = 0; c < eol; c++)
+ printf(" %02X", cells[c].chars[0]);
+ printf("\n");
+
+ return 1;
+}
+
+static int screen_sb_popline(int cols, VTermScreenCell *cells, void *user)
+{
+ int col;
+
+ if(!want_screen_scrollback)
+ return 0;
+
+ /* All lines of scrollback contain "ABCDE" */
+ for(col = 0; col < cols; col++) {
+ if(col < 5)
+ cells[col].chars[0] = 'A' + col;
+ else
+ cells[col].chars[0] = 0;
+
+ cells[col].width = 1;
+ }
+
+ printf("sb_popline %d\n", cols);
+ return 1;
+}
+
+VTermScreenCallbacks screen_cbs = {
+ screen_damage, /* damage */
+ moverect, /* moverect */
+ movecursor, /* movecursor */
+ settermprop, /* settermprop */
+ NULL, /* bell */
+ NULL, /* resize */
+ screen_sb_pushline, /* sb_pushline */
+ screen_sb_popline /* sb_popline */
+};
+
+int main(int argc, char **argv)
+{
+ char line[1024] = {0};
+ int flag;
+
+ int err;
+
+ setvbuf(stdout, NULL, _IONBF, 0);
+
+ while(fgets(line, sizeof line, stdin)) {
+ char *nl;
+ size_t outlen;
+ err = 0;
+
+ if((nl = strchr(line, '\n')))
+ *nl = '\0';
+
+ if(streq(line, "INIT")) {
+ if(!vt)
+ vt = vterm_new(25, 80);
+ }
+
+ else if(streq(line, "WANTPARSER")) {
+ vterm_parser_set_callbacks(vt, &parser_cbs, NULL);
+ }
+
+ else if(strstartswith(line, "WANTSTATE") && (line[9] == '\0' || line[9] == ' ')) {
+ int i = 9;
+ int sense = 1;
+ if(!state) {
+ state = vterm_obtain_state(vt);
+ vterm_state_set_callbacks(state, &state_cbs, NULL);
+ vterm_state_set_bold_highbright(state, 1);
+ vterm_state_reset(state, 1);
+ }
+
+ while(line[i] == ' ')
+ i++;
+ for( ; line[i]; i++)
+ switch(line[i]) {
+ case '+':
+ sense = 1;
+ break;
+ case '-':
+ sense = 0;
+ break;
+ case 'g':
+ want_state_putglyph = sense;
+ break;
+ case 's':
+ want_scrollrect = sense;
+ break;
+ case 'm':
+ want_moverect = sense;
+ break;
+ case 'e':
+ want_state_erase = sense;
+ break;
+ case 'p':
+ want_settermprop = sense;
+ break;
+ case 'f':
+ vterm_state_set_unrecognised_fallbacks(state, sense ? &parser_cbs : NULL, NULL);
+ break;
+ default:
+ fprintf(stderr, "Unrecognised WANTSTATE flag '%c'\n", line[i]);
+ }
+ }
+
+ else if(strstartswith(line, "WANTSCREEN") && (line[10] == '\0' || line[10] == ' ')) {
+ int i = 10;
+ int sense = 1;
+ if(!screen)
+ screen = vterm_obtain_screen(vt);
+ vterm_screen_enable_altscreen(screen, 1);
+ vterm_screen_set_callbacks(screen, &screen_cbs, NULL);
+
+ while(line[i] == ' ')
+ i++;
+ for( ; line[i]; i++)
+ switch(line[i]) {
+ case '-':
+ sense = 0;
+ break;
+ case 'd':
+ want_screen_damage = sense;
+ break;
+ case 'D':
+ want_screen_damage = sense;
+ want_screen_damage_cells = sense;
+ break;
+ case 'm':
+ want_moverect = sense;
+ break;
+ case 'c':
+ want_movecursor = sense;
+ break;
+ case 'p':
+ want_settermprop = 1;
+ break;
+ case 'b':
+ want_screen_scrollback = sense;
+ break;
+ default:
+ fprintf(stderr, "Unrecognised WANTSCREEN flag '%c'\n", line[i]);
+ }
+ }
+
+ else if(sscanf(line, "UTF8 %d", &flag)) {
+ vterm_set_utf8(vt, flag);
+ }
+
+ else if(streq(line, "RESET")) {
+ if(state) {
+ vterm_state_reset(state, 1);
+ vterm_state_get_cursorpos(state, &state_pos);
+ }
+ if(screen) {
+ vterm_screen_reset(screen, 1);
+ }
+ }
+
+ else if(strstartswith(line, "RESIZE ")) {
+ int rows, cols;
+ char *linep = line + 7;
+ while(linep[0] == ' ')
+ linep++;
+ sscanf(linep, "%d, %d", &rows, &cols);
+ vterm_set_size(vt, rows, cols);
+ }
+
+ else if(strstartswith(line, "PUSH ")) {
+ char *bytes = line + 5;
+ size_t len = inplace_hex2bytes(bytes);
+ size_t written = vterm_input_write(vt, bytes, len);
+ if(written < len)
+ fprintf(stderr, "! short write\n");
+ }
+
+ else if(streq(line, "WANTENCODING")) {
+ /* This isn't really external API but it's hard to get this out any
+ * other way
+ */
+ encoding.enc = vterm_lookup_encoding(ENC_UTF8, 'u');
+ if(encoding.enc->init)
+ (*encoding.enc->init)(encoding.enc, encoding.data);
+ }
+
+ else if(strstartswith(line, "ENCIN ")) {
+ char *bytes = line + 6;
+ size_t len = inplace_hex2bytes(bytes);
+
+ uint32_t cp[1024];
+ int cpi = 0;
+ size_t pos = 0;
+
+ (*encoding.enc->decode)(encoding.enc, encoding.data,
+ cp, &cpi, len, bytes, &pos, len);
+
+ if(cpi > 0) {
+ int i;
+ printf("encout ");
+ for(i = 0; i < cpi; i++) {
+ printf(i ? ",%x" : "%x", cp[i]);
+ }
+ printf("\n");
+ }
+ }
+
+ else if(strstartswith(line, "INCHAR ")) {
+ char *linep = line + 7;
+ unsigned int c = 0;
+ VTermModifier mod;
+ while(linep[0] == ' ')
+ linep++;
+ mod = strpe_modifiers(&linep);
+ sscanf(linep, " %x", &c);
+
+ vterm_keyboard_unichar(vt, c, mod);
+ }
+
+ else if(strstartswith(line, "INKEY ")) {
+ VTermModifier mod;
+ VTermKey key;
+ char *linep = line + 6;
+ while(linep[0] == ' ')
+ linep++;
+ mod = strpe_modifiers(&linep);
+ while(linep[0] == ' ')
+ linep++;
+ key = strp_key(linep);
+
+ vterm_keyboard_key(vt, key, mod);
+ }
+
+ else if(strstartswith(line, "PASTE ")) {
+ char *linep = line + 6;
+ if(streq(linep, "START"))
+ vterm_keyboard_start_paste(vt);
+ else if(streq(linep, "END"))
+ vterm_keyboard_end_paste(vt);
+ else
+ goto abort_line;
+ }
+
+ else if(strstartswith(line, "FOCUS ")) {
+ char *linep = line + 6;
+ if(streq(linep, "IN"))
+ vterm_state_focus_in(state);
+ else if(streq(linep, "OUT"))
+ vterm_state_focus_out(state);
+ else
+ goto abort_line;
+ }
+
+ else if(strstartswith(line, "MOUSEMOVE ")) {
+ char *linep = line + 10;
+ int row, col, len;
+ VTermModifier mod;
+ while(linep[0] == ' ')
+ linep++;
+ sscanf(linep, "%d,%d%n", &row, &col, &len);
+ linep += len;
+ while(linep[0] == ' ')
+ linep++;
+ mod = strpe_modifiers(&linep);
+ vterm_mouse_move(vt, row, col, mod);
+ }
+
+ else if(strstartswith(line, "MOUSEBTN ")) {
+ char *linep = line + 9;
+ char press;
+ int button, len;
+ VTermModifier mod;
+ while(linep[0] == ' ')
+ linep++;
+ sscanf(linep, "%c %d%n", &press, &button, &len);
+ linep += len;
+ while(linep[0] == ' ')
+ linep++;
+ mod = strpe_modifiers(&linep);
+ vterm_mouse_button(vt, button, (press == 'd' || press == 'D'), mod);
+ }
+
+ else if(strstartswith(line, "DAMAGEMERGE ")) {
+ char *linep = line + 12;
+ while(linep[0] == ' ')
+ linep++;
+ if(streq(linep, "CELL"))
+ vterm_screen_set_damage_merge(screen, VTERM_DAMAGE_CELL);
+ else if(streq(linep, "ROW"))
+ vterm_screen_set_damage_merge(screen, VTERM_DAMAGE_ROW);
+ else if(streq(linep, "SCREEN"))
+ vterm_screen_set_damage_merge(screen, VTERM_DAMAGE_SCREEN);
+ else if(streq(linep, "SCROLL"))
+ vterm_screen_set_damage_merge(screen, VTERM_DAMAGE_SCROLL);
+ }
+
+ else if(strstartswith(line, "DAMAGEFLUSH")) {
+ vterm_screen_flush_damage(screen);
+ }
+
+ else if(line[0] == '?') {
+ if(streq(line, "?cursor")) {
+ VTermPos pos;
+ vterm_state_get_cursorpos(state, &pos);
+ if(pos.row != state_pos.row)
+ printf("! row mismatch: state=%d,%d event=%d,%d\n",
+ pos.row, pos.col, state_pos.row, state_pos.col);
+ else if(pos.col != state_pos.col)
+ printf("! col mismatch: state=%d,%d event=%d,%d\n",
+ pos.row, pos.col, state_pos.row, state_pos.col);
+ else
+ printf("%d,%d\n", state_pos.row, state_pos.col);
+ }
+ else if(strstartswith(line, "?pen ")) {
+ VTermValue val;
+ char *linep = line + 5;
+ while(linep[0] == ' ')
+ linep++;
+
+#define BOOLSTR(v) ((v) ? "on" : "off")
+
+ if(streq(linep, "bold")) {
+ vterm_state_get_penattr(state, VTERM_ATTR_BOLD, &val);
+ if(val.boolean != state_pen.bold)
+ printf("! pen bold mismatch; state=%s, event=%s\n",
+ BOOLSTR(val.boolean), BOOLSTR(state_pen.bold));
+ else
+ printf("%s\n", BOOLSTR(state_pen.bold));
+ }
+ else if(streq(linep, "underline")) {
+ vterm_state_get_penattr(state, VTERM_ATTR_UNDERLINE, &val);
+ if(val.boolean != state_pen.underline)
+ printf("! pen underline mismatch; state=%d, event=%d\n",
+ val.boolean, state_pen.underline);
+ else
+ printf("%d\n", state_pen.underline);
+ }
+ else if(streq(linep, "italic")) {
+ vterm_state_get_penattr(state, VTERM_ATTR_ITALIC, &val);
+ if(val.boolean != state_pen.italic)
+ printf("! pen italic mismatch; state=%s, event=%s\n",
+ BOOLSTR(val.boolean), BOOLSTR(state_pen.italic));
+ else
+ printf("%s\n", BOOLSTR(state_pen.italic));
+ }
+ else if(streq(linep, "blink")) {
+ vterm_state_get_penattr(state, VTERM_ATTR_BLINK, &val);
+ if(val.boolean != state_pen.blink)
+ printf("! pen blink mismatch; state=%s, event=%s\n",
+ BOOLSTR(val.boolean), BOOLSTR(state_pen.blink));
+ else
+ printf("%s\n", BOOLSTR(state_pen.blink));
+ }
+ else if(streq(linep, "reverse")) {
+ vterm_state_get_penattr(state, VTERM_ATTR_REVERSE, &val);
+ if(val.boolean != state_pen.reverse)
+ printf("! pen reverse mismatch; state=%s, event=%s\n",
+ BOOLSTR(val.boolean), BOOLSTR(state_pen.reverse));
+ else
+ printf("%s\n", BOOLSTR(state_pen.reverse));
+ }
+ else if(streq(linep, "font")) {
+ vterm_state_get_penattr(state, VTERM_ATTR_FONT, &val);
+ if(val.boolean != state_pen.font)
+ printf("! pen font mismatch; state=%d, event=%d\n",
+ val.boolean, state_pen.font);
+ else
+ printf("%d\n", state_pen.font);
+ }
+ else if(streq(linep, "foreground")) {
+ printf("rgb(%d,%d,%d)\n", state_pen.foreground.red, state_pen.foreground.green, state_pen.foreground.blue);
+ }
+ else if(streq(linep, "background")) {
+ printf("rgb(%d,%d,%d)\n", state_pen.background.red, state_pen.background.green, state_pen.background.blue);
+ }
+ else
+ printf("?\n");
+ }
+ else if(strstartswith(line, "?screen_chars ")) {
+ char *linep = line + 13;
+ VTermRect rect;
+ size_t len;
+ while(linep[0] == ' ')
+ linep++;
+ if(sscanf(linep, "%d,%d,%d,%d", &rect.start_row, &rect.start_col, &rect.end_row, &rect.end_col) < 4) {
+ printf("! screen_chars unrecognised input\n");
+ goto abort_line;
+ }
+ len = vterm_screen_get_chars(screen, NULL, 0, rect);
+ if(len == (size_t)-1)
+ printf("! screen_chars error\n");
+ else if(len == 0)
+ printf("\n");
+ else {
+ uint32_t *chars = malloc(sizeof(uint32_t) * len);
+ size_t i;
+ vterm_screen_get_chars(screen, chars, len, rect);
+ for(i = 0; i < len; i++) {
+ printf("0x%02x%s", chars[i], i < len-1 ? "," : "\n");
+ }
+ free(chars);
+ }
+ }
+ else if(strstartswith(line, "?screen_text ")) {
+ char *linep = line + 12;
+ VTermRect rect;
+ size_t len;
+ while(linep[0] == ' ')
+ linep++;
+ if(sscanf(linep, "%d,%d,%d,%d", &rect.start_row, &rect.start_col, &rect.end_row, &rect.end_col) < 4) {
+ printf("! screen_text unrecognised input\n");
+ goto abort_line;
+ }
+ len = vterm_screen_get_text(screen, NULL, 0, rect);
+ if(len == (size_t)-1)
+ printf("! screen_text error\n");
+ else if(len == 0)
+ printf("\n");
+ else {
+ /* Put an overwrite guard at both ends of the buffer */
+ unsigned char *buffer = malloc(len + 4);
+ unsigned char *text = buffer + 2;
+ text[-2] = 0x55; text[-1] = 0xAA;
+ text[len] = 0x55; text[len+1] = 0xAA;
+
+ vterm_screen_get_text(screen, (char *)text, len, rect);
+
+ if(text[-2] != 0x55 || text[-1] != 0xAA)
+ printf("! screen_get_text buffer overrun left [%02x,%02x]\n", text[-2], text[-1]);
+ else if(text[len] != 0x55 || text[len+1] != 0xAA)
+ printf("! screen_get_text buffer overrun right [%02x,%02x]\n", text[len], text[len+1]);
+ else
+ {
+ size_t i;
+ for(i = 0; i < len; i++) {
+ printf("0x%02x%s", text[i], i < len-1 ? "," : "\n");
+ }
+ }
+
+ free(buffer);
+ }
+ }
+ else if(strstartswith(line, "?screen_cell ")) {
+ char *linep = line + 12;
+ int i;
+ VTermPos pos;
+ VTermScreenCell cell;
+ while(linep[0] == ' ')
+ linep++;
+ if(sscanf(linep, "%d,%d\n", &pos.row, &pos.col) < 2) {
+ printf("! screen_cell unrecognised input\n");
+ goto abort_line;
+ }
+ if(!vterm_screen_get_cell(screen, pos, &cell))
+ goto abort_line;
+ printf("{");
+ for(i = 0; i < VTERM_MAX_CHARS_PER_CELL && cell.chars[i]; i++) {
+ printf("%s0x%x", i ? "," : "", cell.chars[i]);
+ }
+ printf("} width=%d attrs={", cell.width);
+ if(cell.attrs.bold) printf("B");
+ if(cell.attrs.underline) printf("U%d", cell.attrs.underline);
+ if(cell.attrs.italic) printf("I");
+ if(cell.attrs.blink) printf("K");
+ if(cell.attrs.reverse) printf("R");
+ if(cell.attrs.font) printf("F%d", cell.attrs.font);
+ printf("} ");
+ if(cell.attrs.dwl) printf("dwl ");
+ if(cell.attrs.dhl) printf("dhl-%s ", cell.attrs.dhl == 2 ? "bottom" : "top");
+ printf("fg=rgb(%d,%d,%d) ", cell.fg.red, cell.fg.green, cell.fg.blue);
+ printf("bg=rgb(%d,%d,%d)\n", cell.bg.red, cell.bg.green, cell.bg.blue);
+ }
+ else if(strstartswith(line, "?screen_eol ")) {
+ VTermPos pos;
+ char *linep = line + 12;
+ while(linep[0] == ' ')
+ linep++;
+ if(sscanf(linep, "%d,%d\n", &pos.row, &pos.col) < 2) {
+ printf("! screen_eol unrecognised input\n");
+ goto abort_line;
+ }
+ printf("%d\n", vterm_screen_is_eol(screen, pos));
+ }
+ else if(strstartswith(line, "?screen_attrs_extent ")) {
+ VTermPos pos;
+ VTermRect rect;
+ char *linep = line + 21;
+ while(linep[0] == ' ')
+ linep++;
+ if(sscanf(linep, "%d,%d\n", &pos.row, &pos.col) < 2) {
+ printf("! screen_attrs_extent unrecognised input\n");
+ goto abort_line;
+ }
+ rect.start_col = 0;
+ rect.end_col = -1;
+ if(!vterm_screen_get_attrs_extent(screen, &rect, pos, ~0)) {
+ printf("! screen_attrs_extent failed\n");
+ goto abort_line;
+ }
+ printf("%d,%d-%d,%d\n", rect.start_row, rect.start_col, rect.end_row, rect.end_col);
+ }
+ else
+ printf("?\n");
+
+ memset(line, 0, sizeof line);
+ continue;
+ }
+
+ else
+ abort_line: err = 1;
+
+ outlen = vterm_output_get_buffer_current(vt);
+ if(outlen > 0) {
+ int i;
+ char outbuff[1024];
+ vterm_output_read(vt, outbuff, outlen);
+
+ printf("output ");
+ for(i = 0; i < outlen; i++)
+ printf("%x%s", (unsigned char)outbuff[i], i < outlen-1 ? "," : "\n");
+ }
+
+ printf(err ? "?\n" : "DONE\n");
+ }
+
+ vterm_free(vt);
+
+ return 0;
+}
diff --git a/src/libvterm/t/run-test.pl b/src/libvterm/t/run-test.pl
new file mode 100644
index 0000000..12e1180
--- /dev/null
+++ b/src/libvterm/t/run-test.pl
@@ -0,0 +1,196 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+use Getopt::Long;
+use IO::Handle;
+use IPC::Open2 qw( open2 );
+use POSIX qw( WIFEXITED WEXITSTATUS WIFSIGNALED WTERMSIG );
+
+my $VALGRIND = 0;
+GetOptions(
+ 'valgrind|v+' => \$VALGRIND,
+) or exit 1;
+
+my ( $hin, $hout, $hpid );
+{
+ local $ENV{LD_LIBRARY_PATH} = ".libs";
+ my @command = "t/.libs/harness";
+ unshift @command, "valgrind", "--tool=memcheck", "--leak-check=yes", "--num-callers=25", "--log-file=valgrind.out", "--error-exitcode=126" if $VALGRIND;
+
+ $hpid = open2 $hout, $hin, @command or die "Cannot open2 harness - $!";
+}
+
+my $exitcode = 0;
+
+my $command;
+my @expect;
+
+sub do_onetest
+{
+ $hin->print( "$command\n" );
+ undef $command;
+
+ my $fail_printed = 0;
+
+ while( my $outline = <$hout> ) {
+ last if $outline eq "DONE\n" or $outline eq "?\n";
+
+ chomp $outline;
+
+ if( !@expect ) {
+ print "# Test failed\n" unless $fail_printed++;
+ print "# expected nothing more\n" .
+ "# Actual: $outline\n";
+ next;
+ }
+
+ my $expectation = shift @expect;
+
+ next if $expectation eq $outline;
+
+ print "# Test failed\n" unless $fail_printed++;
+ print "# Expected: $expectation\n" .
+ "# Actual: $outline\n";
+ }
+
+ if( @expect ) {
+ print "# Test failed\n" unless $fail_printed++;
+ print "# Expected: $_\n" .
+ "# didn't happen\n" for @expect;
+ }
+
+ $exitcode = 1 if $fail_printed;
+}
+
+sub do_line
+{
+ my ( $line ) = @_;
+
+ if( $line =~ m/^!(.*)/ ) {
+ do_onetest if defined $command;
+ print "> $1\n";
+ }
+
+ # Commands have capitals
+ elsif( $line =~ m/^([A-Z]+)/ ) {
+ # Some convenience formatting
+ if( $line =~ m/^(PUSH|ENCIN) (.*)$/ ) {
+ # we're evil
+ my $string = eval($2);
+ $line = "$1 " . unpack "H*", $string;
+ }
+
+ do_onetest if defined $command;
+
+ $command = $line;
+ undef @expect;
+ }
+ # Expectations have lowercase
+ elsif( $line =~ m/^([a-z]+)/ ) {
+ # Convenience formatting
+ if( $line =~ m/^(text|encout) (.*)$/ ) {
+ $line = "$1 " . join ",", map sprintf("%x", $_), eval($2);
+ }
+ elsif( $line =~ m/^(output) (.*)$/ ) {
+ $line = "$1 " . join ",", map sprintf("%x", $_), unpack "C*", eval($2);
+ }
+ elsif( $line =~ m/^control (.*)$/ ) {
+ $line = sprintf "control %02x", eval($1);
+ }
+ elsif( $line =~ m/^csi (\S+) (.*)$/ ) {
+ $line = sprintf "csi %02x %s", eval($1), $2; # TODO
+ }
+ elsif( $line =~ m/^(escape|osc|dcs) (.*)$/ ) {
+ $line = "$1 " . join "", map sprintf("%02x", $_), unpack "C*", eval($2);
+ }
+ elsif( $line =~ m/^putglyph (\S+) (.*)$/ ) {
+ $line = "putglyph " . join( ",", map sprintf("%x", $_), eval($1) ) . " $2";
+ }
+ elsif( $line =~ m/^(?:movecursor|scrollrect|moverect|erase|damage|sb_pushline|sb_popline|settermprop|setmousefunc) / ) {
+ # no conversion
+ }
+ else {
+ warn "Unrecognised test expectation '$line'\n";
+ }
+
+ push @expect, $line;
+ }
+ # ?screen_row assertion is emulated here
+ elsif( $line =~ s/^\?screen_row\s+(\d+)\s*=\s*// ) {
+ my $row = $1;
+ my $row1 = $row + 1;
+ my $want = eval($line);
+
+ do_onetest if defined $command;
+
+ # TODO: may not be 80
+ $hin->print( "\?screen_chars $row,0,$row1,80\n" );
+ my $response = <$hout>;
+ chomp $response;
+
+ $response = pack "C*", map hex, split m/,/, $response;
+ if( $response ne $want ) {
+ print "# Assert ?screen_row $row failed:\n" .
+ "# Expected: $want\n" .
+ "# Actual: $response\n";
+ $exitcode = 1;
+ }
+ }
+ # Assertions start with '?'
+ elsif( $line =~ s/^\?([a-z]+.*?=)\s+// ) {
+ do_onetest if defined $command;
+
+ my ( $assertion ) = $1 =~ m/^(.*)\s+=/;
+
+ $hin->print( "\?$assertion\n" );
+ my $response = <$hout>; defined $response or wait, die "Test harness failed - $?\n";
+ chomp $response;
+
+ if( $response ne $line ) {
+ print "# Assert $assertion failed:\n" .
+ "# Expected: $line\n" .
+ "# Actual: $response\n";
+ $exitcode = 1;
+ }
+ }
+ # Test controls start with '$'
+ elsif( $line =~ s/\$SEQ\s+(\d+)\s+(\d+):\s*// ) {
+ my ( $low, $high ) = ( $1, $2 );
+ foreach my $val ( $low .. $high ) {
+ ( my $inner = $line ) =~ s/\\#/$val/g;
+ do_line( $inner );
+ }
+ }
+ elsif( $line =~ s/\$REP\s+(\d+):\s*// ) {
+ my $count = $1;
+ do_line( $line ) for 1 .. $count;
+ }
+ else {
+ die "Unrecognised TEST line $line\n";
+ }
+}
+
+open my $test, "<", $ARGV[0] or die "Cannot open test script $ARGV[0] - $!";
+
+while( my $line = <$test> ) {
+ $line =~ s/^\s+//;
+ next if $line =~ m/^(?:#|$)/;
+
+ chomp $line;
+ do_line( $line );
+}
+
+do_onetest if defined $command;
+
+close $hin;
+close $hout;
+
+waitpid $hpid, 0;
+if( $? ) {
+ printf STDERR "Harness exited %d\n", WEXITSTATUS($?) if WIFEXITED($?);
+ printf STDERR "Harness exit signal %d\n", WTERMSIG($?) if WIFSIGNALED($?);
+ $exitcode = WIFEXITED($?) ? WEXITSTATUS($?) : 125;
+}
+
+exit $exitcode;
diff --git a/src/libvterm/tbl2inc_c.pl b/src/libvterm/tbl2inc_c.pl
new file mode 100644
index 0000000..527fc98
--- /dev/null
+++ b/src/libvterm/tbl2inc_c.pl
@@ -0,0 +1,51 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+my ( $encname ) = $ARGV[0] =~ m{/([^/.]+).tbl}
+ or die "Cannot parse encoding name out of $ARGV[0]\n";
+
+print <<"EOF";
+static const struct StaticTableEncoding encoding_$encname = {
+ {
+ NULL, /* init */
+ &decode_table /* decode */
+ },
+ {
+EOF
+
+my $row = 0;
+while( <> ) {
+ s/\s*#.*//; # strip comment
+
+ if ($_ =~ m{^\d+/\d+}) {
+ my ($up, $low) = ($_ =~ m{^(\d+)/(\d+)});
+ my $thisrow = $up * 16 + $low;
+ while ($row < $thisrow) {
+ print " 0x0, /* $row */\n";
+ ++$row;
+ }
+ }
+
+ s{^(\d+)/(\d+)}{""}e; # Remove 3/1
+ s{ = }{""}e; # Remove " = "
+ s{"(.)"}{sprintf "0x%04x", ord $1}e; # Convert "A" to 0x41
+ s{U\+}{0x}; # Convert U+0041 to 0x0041
+
+ s{$}{, /* $row */}; # append comma and index
+
+ print " $_";
+
+ ++$row;
+}
+
+while ($row < 128) {
+ print " 0x0, /* $row */\n";
+ ++$row;
+}
+
+print <<"EOF";
+ }
+};
+EOF
diff --git a/src/libvterm/vterm.pc.in b/src/libvterm/vterm.pc.in
new file mode 100644
index 0000000..c64c72d
--- /dev/null
+++ b/src/libvterm/vterm.pc.in
@@ -0,0 +1,9 @@
+prefix=@PREFIX@
+libdir=@LIBDIR@
+includedir=${prefix}/include
+
+Name: vterm
+Description: Abstract VT220/Xterm/ECMA-48 emulation library
+Version: @VERSION@
+Libs: -L${libdir} -lvterm
+Cflags: -I${includedir}
diff --git a/src/link.390 b/src/link.390
new file mode 100644
index 0000000..76edc04
--- /dev/null
+++ b/src/link.390
@@ -0,0 +1,7 @@
+s%-lXext *%%g
+s%-lXmu *%%g
+s%-lXm *%/usr/lib/Xm.x %g
+s%-lX11 *%/usr/lib/X11.x %g
+s%-lXt *%%g
+s%-lSM *%/usr/lib/SM.x %g
+s%-lICE *%/usr/lib/ICE.x %g
diff --git a/src/link.sh b/src/link.sh
new file mode 100755
index 0000000..71ee061
--- /dev/null
+++ b/src/link.sh
@@ -0,0 +1,151 @@
+#! /bin/sh
+#
+# link.sh -- try linking Vim with different sets of libraries, finding the
+# minimal set for fastest startup. The problem is that configure adds a few
+# libraries when they exist, but this doesn't mean they are needed for Vim.
+#
+# Author: Bram Moolenaar
+# Last change: 2010 Nov 03
+# License: Public domain
+#
+# Warning: This fails miserably if the linker doesn't return an error code!
+#
+# Otherwise this script is fail-safe, falling back to the original full link
+# command if anything fails.
+
+echo "$LINK " >link.cmd
+exit_value=0
+
+if test "$LINK_AS_NEEDED" = yes; then
+ echo "link.sh: \$LINK_AS_NEEDED set to 'yes': invoking linker directly."
+ cat link.cmd
+ if sh link.cmd; then
+ exit_value=0
+ echo "link.sh: Linked fine"
+ else
+ exit_value=$?
+ echo "link.sh: Linking failed"
+ fi
+else
+ if test -f auto/link.sed; then
+
+#
+# If auto/link.sed already exists, use it. We assume a previous run of
+# link.sh has found the correct set of libraries.
+#
+ echo "link.sh: The file 'auto/link.sed' exists, which is going to be used now."
+ echo "link.sh: If linking fails, try deleting the auto/link.sed file."
+ echo "link.sh: If this fails too, try creating an empty auto/link.sed file."
+else
+
+# If linking works with the full link command, try removing some libraries,
+# that are known not to be needed on at least one system.
+# Remove auto/pathdef.c if there is a new link command and compile it again.
+# There is a loop to remove libraries that appear several times.
+#
+# Notes:
+# - Can't remove Xext; It links fine but will give an error when running gvim
+# with Motif.
+# - Don't remove the last -lm: On HP-UX Vim links OK but crashes when the GTK
+# GUI is started, because the "floor" symbol could not be resolved.
+#
+ cat link.cmd
+ if sh link.cmd; then
+ touch auto/link.sed
+ cp link.cmd linkit.sh
+ for libname in SM ICE nsl dnet dnet_stub inet socket dir elf iconv Xt Xmu Xp Xpm X11 Xdmcp x w perl dl pthread thread readline m crypt attr; do
+ cont=yes
+ while test -n "$cont"; do
+ if grep "l$libname " linkit.sh >/dev/null; then
+ if test ! -f link1.sed; then
+ echo "link.sh: OK, linking works, let's try omitting a few libraries."
+ echo "link.sh: See auto/link.log for details."
+ rm -f auto/link.log
+ fi
+ echo "s/-l$libname *//" >link1.sed
+ sed -f auto/link.sed <link.cmd >linkit2.sh
+ sed -f link1.sed <linkit2.sh >linkit.sh
+ # keep the last -lm
+ if test $libname != "m" || grep "lm " linkit.sh >/dev/null; then
+ echo "link.sh: Trying to omit the $libname library..."
+ cat linkit.sh >>auto/link.log
+ # Redirect this link output, it may contain error messages which
+ # should be ignored.
+ if sh linkit.sh >>auto/link.log 2>&1; then
+ echo "link.sh: Vim doesn't need the $libname library!"
+ cat link1.sed >>auto/link.sed
+ rm -f auto/pathdef.c
+ else
+ echo "link.sh: Vim DOES need the $libname library."
+ cont=
+ cp link.cmd linkit.sh
+ fi
+ else
+ cont=
+ cp link.cmd linkit.sh
+ fi
+ else
+ cont=
+ cp link.cmd linkit.sh
+ fi
+ done
+ done
+ if test ! -f auto/pathdef.c; then
+ $MAKE objects/pathdef.o
+ fi
+ if test ! -f link1.sed; then
+ echo "link.sh: Linked fine, no libraries can be omitted"
+ touch link3.sed
+ fi
+ else
+ exit_value=$?
+ fi
+fi
+
+#
+# Now do the real linking.
+#
+if test -s auto/link.sed; then
+ echo "link.sh: Using auto/link.sed file to omit a few libraries"
+ sed -f auto/link.sed <link.cmd >linkit.sh
+ cat linkit.sh
+ if sh linkit.sh; then
+ exit_value=0
+ echo "link.sh: Linked fine with a few libraries omitted"
+ else
+ exit_value=$?
+ echo "link.sh: Linking failed, making auto/link.sed empty and trying again"
+ mv -f auto/link.sed link2.sed
+ touch auto/link.sed
+ rm -f auto/pathdef.c
+ $MAKE objects/pathdef.o
+ fi
+fi
+if test -f auto/link.sed -a ! -s auto/link.sed -a ! -f link3.sed; then
+ echo "link.sh: Using unmodified link command"
+ cat link.cmd
+ if sh link.cmd; then
+ exit_value=0
+ echo "link.sh: Linked OK"
+ else
+ exit_value=$?
+ if test -f link2.sed; then
+ echo "link.sh: Linking doesn't work at all, removing auto/link.sed"
+ rm -f auto/link.sed
+ fi
+ fi
+fi
+
+fi
+
+#
+# cleanup
+#
+rm -f link.cmd linkit.sh link1.sed link2.sed link3.sed linkit2.sh
+
+#
+# return an error code if something went wrong
+#
+exit $exit_value
+
+# vim:set sw=2 et:
diff --git a/src/list.c b/src/list.c
new file mode 100644
index 0000000..0c21c41
--- /dev/null
+++ b/src/list.c
@@ -0,0 +1,1010 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * list.c: List support
+ */
+
+#include "vim.h"
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+
+/* List heads for garbage collection. */
+static list_T *first_list = NULL; /* list of all lists */
+
+/*
+ * Add a watcher to a list.
+ */
+ void
+list_add_watch(list_T *l, listwatch_T *lw)
+{
+ lw->lw_next = l->lv_watch;
+ l->lv_watch = lw;
+}
+
+/*
+ * Remove a watcher from a list.
+ * No warning when it isn't found...
+ */
+ void
+list_rem_watch(list_T *l, listwatch_T *lwrem)
+{
+ listwatch_T *lw, **lwp;
+
+ lwp = &l->lv_watch;
+ for (lw = l->lv_watch; lw != NULL; lw = lw->lw_next)
+ {
+ if (lw == lwrem)
+ {
+ *lwp = lw->lw_next;
+ break;
+ }
+ lwp = &lw->lw_next;
+ }
+}
+
+/*
+ * Just before removing an item from a list: advance watchers to the next
+ * item.
+ */
+ void
+list_fix_watch(list_T *l, listitem_T *item)
+{
+ listwatch_T *lw;
+
+ for (lw = l->lv_watch; lw != NULL; lw = lw->lw_next)
+ if (lw->lw_item == item)
+ lw->lw_item = item->li_next;
+}
+
+/*
+ * Allocate an empty header for a list.
+ * Caller should take care of the reference count.
+ */
+ list_T *
+list_alloc(void)
+{
+ list_T *l;
+
+ l = (list_T *)alloc_clear(sizeof(list_T));
+ if (l != NULL)
+ {
+ /* Prepend the list to the list of lists for garbage collection. */
+ if (first_list != NULL)
+ first_list->lv_used_prev = l;
+ l->lv_used_prev = NULL;
+ l->lv_used_next = first_list;
+ first_list = l;
+ }
+ return l;
+}
+
+/*
+ * list_alloc() with an ID for alloc_fail().
+ */
+ list_T *
+list_alloc_id(alloc_id_T id UNUSED)
+{
+#ifdef FEAT_EVAL
+ if (alloc_fail_id == id && alloc_does_fail((long_u)sizeof(list_T)))
+ return NULL;
+#endif
+ return (list_alloc());
+}
+
+/*
+ * Allocate an empty list for a return value, with reference count set.
+ * Returns OK or FAIL.
+ */
+ int
+rettv_list_alloc(typval_T *rettv)
+{
+ list_T *l = list_alloc();
+
+ if (l == NULL)
+ return FAIL;
+
+ rettv->v_lock = 0;
+ rettv_list_set(rettv, l);
+ return OK;
+}
+
+/*
+ * Same as rettv_list_alloc() but uses an allocation id for testing.
+ */
+ int
+rettv_list_alloc_id(typval_T *rettv, alloc_id_T id UNUSED)
+{
+#ifdef FEAT_EVAL
+ if (alloc_fail_id == id && alloc_does_fail((long_u)sizeof(list_T)))
+ return FAIL;
+#endif
+ return rettv_list_alloc(rettv);
+}
+
+
+/*
+ * Set a list as the return value
+ */
+ void
+rettv_list_set(typval_T *rettv, list_T *l)
+{
+ rettv->v_type = VAR_LIST;
+ rettv->vval.v_list = l;
+ if (l != NULL)
+ ++l->lv_refcount;
+}
+
+/*
+ * Unreference a list: decrement the reference count and free it when it
+ * becomes zero.
+ */
+ void
+list_unref(list_T *l)
+{
+ if (l != NULL && --l->lv_refcount <= 0)
+ list_free(l);
+}
+
+/*
+ * Free a list, including all non-container items it points to.
+ * Ignores the reference count.
+ */
+ static void
+list_free_contents(list_T *l)
+{
+ listitem_T *item;
+
+ for (item = l->lv_first; item != NULL; item = l->lv_first)
+ {
+ /* Remove the item before deleting it. */
+ l->lv_first = item->li_next;
+ clear_tv(&item->li_tv);
+ vim_free(item);
+ }
+}
+
+/*
+ * Go through the list of lists and free items without the copyID.
+ * But don't free a list that has a watcher (used in a for loop), these
+ * are not referenced anywhere.
+ */
+ int
+list_free_nonref(int copyID)
+{
+ list_T *ll;
+ int did_free = FALSE;
+
+ for (ll = first_list; ll != NULL; ll = ll->lv_used_next)
+ if ((ll->lv_copyID & COPYID_MASK) != (copyID & COPYID_MASK)
+ && ll->lv_watch == NULL)
+ {
+ /* Free the List and ordinary items it contains, but don't recurse
+ * into Lists and Dictionaries, they will be in the list of dicts
+ * or list of lists. */
+ list_free_contents(ll);
+ did_free = TRUE;
+ }
+ return did_free;
+}
+
+ static void
+list_free_list(list_T *l)
+{
+ /* Remove the list from the list of lists for garbage collection. */
+ if (l->lv_used_prev == NULL)
+ first_list = l->lv_used_next;
+ else
+ l->lv_used_prev->lv_used_next = l->lv_used_next;
+ if (l->lv_used_next != NULL)
+ l->lv_used_next->lv_used_prev = l->lv_used_prev;
+
+ vim_free(l);
+}
+
+ void
+list_free_items(int copyID)
+{
+ list_T *ll, *ll_next;
+
+ for (ll = first_list; ll != NULL; ll = ll_next)
+ {
+ ll_next = ll->lv_used_next;
+ if ((ll->lv_copyID & COPYID_MASK) != (copyID & COPYID_MASK)
+ && ll->lv_watch == NULL)
+ {
+ /* Free the List and ordinary items it contains, but don't recurse
+ * into Lists and Dictionaries, they will be in the list of dicts
+ * or list of lists. */
+ list_free_list(ll);
+ }
+ }
+}
+
+ void
+list_free(list_T *l)
+{
+ if (!in_free_unref_items)
+ {
+ list_free_contents(l);
+ list_free_list(l);
+ }
+}
+
+/*
+ * Allocate a list item.
+ * It is not initialized, don't forget to set v_lock.
+ */
+ listitem_T *
+listitem_alloc(void)
+{
+ return (listitem_T *)alloc(sizeof(listitem_T));
+}
+
+/*
+ * Free a list item. Also clears the value. Does not notify watchers.
+ */
+ void
+listitem_free(listitem_T *item)
+{
+ clear_tv(&item->li_tv);
+ vim_free(item);
+}
+
+/*
+ * Remove a list item from a List and free it. Also clears the value.
+ */
+ void
+listitem_remove(list_T *l, listitem_T *item)
+{
+ vimlist_remove(l, item, item);
+ listitem_free(item);
+}
+
+/*
+ * Get the number of items in a list.
+ */
+ long
+list_len(list_T *l)
+{
+ if (l == NULL)
+ return 0L;
+ return l->lv_len;
+}
+
+/*
+ * Return TRUE when two lists have exactly the same values.
+ */
+ int
+list_equal(
+ list_T *l1,
+ list_T *l2,
+ int ic, /* ignore case for strings */
+ int recursive) /* TRUE when used recursively */
+{
+ listitem_T *item1, *item2;
+
+ if (l1 == NULL || l2 == NULL)
+ return FALSE;
+ if (l1 == l2)
+ return TRUE;
+ if (list_len(l1) != list_len(l2))
+ return FALSE;
+
+ for (item1 = l1->lv_first, item2 = l2->lv_first;
+ item1 != NULL && item2 != NULL;
+ item1 = item1->li_next, item2 = item2->li_next)
+ if (!tv_equal(&item1->li_tv, &item2->li_tv, ic, recursive))
+ return FALSE;
+ return item1 == NULL && item2 == NULL;
+}
+
+/*
+ * Locate item with index "n" in list "l" and return it.
+ * A negative index is counted from the end; -1 is the last item.
+ * Returns NULL when "n" is out of range.
+ */
+ listitem_T *
+list_find(list_T *l, long n)
+{
+ listitem_T *item;
+ long idx;
+
+ if (l == NULL)
+ return NULL;
+
+ /* Negative index is relative to the end. */
+ if (n < 0)
+ n = l->lv_len + n;
+
+ /* Check for index out of range. */
+ if (n < 0 || n >= l->lv_len)
+ return NULL;
+
+ /* When there is a cached index may start search from there. */
+ if (l->lv_idx_item != NULL)
+ {
+ if (n < l->lv_idx / 2)
+ {
+ /* closest to the start of the list */
+ item = l->lv_first;
+ idx = 0;
+ }
+ else if (n > (l->lv_idx + l->lv_len) / 2)
+ {
+ /* closest to the end of the list */
+ item = l->lv_last;
+ idx = l->lv_len - 1;
+ }
+ else
+ {
+ /* closest to the cached index */
+ item = l->lv_idx_item;
+ idx = l->lv_idx;
+ }
+ }
+ else
+ {
+ if (n < l->lv_len / 2)
+ {
+ /* closest to the start of the list */
+ item = l->lv_first;
+ idx = 0;
+ }
+ else
+ {
+ /* closest to the end of the list */
+ item = l->lv_last;
+ idx = l->lv_len - 1;
+ }
+ }
+
+ while (n > idx)
+ {
+ /* search forward */
+ item = item->li_next;
+ ++idx;
+ }
+ while (n < idx)
+ {
+ /* search backward */
+ item = item->li_prev;
+ --idx;
+ }
+
+ /* cache the used index */
+ l->lv_idx = idx;
+ l->lv_idx_item = item;
+
+ return item;
+}
+
+/*
+ * Get list item "l[idx]" as a number.
+ */
+ long
+list_find_nr(
+ list_T *l,
+ long idx,
+ int *errorp) /* set to TRUE when something wrong */
+{
+ listitem_T *li;
+
+ li = list_find(l, idx);
+ if (li == NULL)
+ {
+ if (errorp != NULL)
+ *errorp = TRUE;
+ return -1L;
+ }
+ return (long)tv_get_number_chk(&li->li_tv, errorp);
+}
+
+/*
+ * Get list item "l[idx - 1]" as a string. Returns NULL for failure.
+ */
+ char_u *
+list_find_str(list_T *l, long idx)
+{
+ listitem_T *li;
+
+ li = list_find(l, idx - 1);
+ if (li == NULL)
+ {
+ semsg(_(e_listidx), idx);
+ return NULL;
+ }
+ return tv_get_string(&li->li_tv);
+}
+
+/*
+ * Locate "item" list "l" and return its index.
+ * Returns -1 when "item" is not in the list.
+ */
+ long
+list_idx_of_item(list_T *l, listitem_T *item)
+{
+ long idx = 0;
+ listitem_T *li;
+
+ if (l == NULL)
+ return -1;
+ idx = 0;
+ for (li = l->lv_first; li != NULL && li != item; li = li->li_next)
+ ++idx;
+ if (li == NULL)
+ return -1;
+ return idx;
+}
+
+/*
+ * Append item "item" to the end of list "l".
+ */
+ void
+list_append(list_T *l, listitem_T *item)
+{
+ if (l->lv_last == NULL)
+ {
+ /* empty list */
+ l->lv_first = item;
+ l->lv_last = item;
+ item->li_prev = NULL;
+ }
+ else
+ {
+ l->lv_last->li_next = item;
+ item->li_prev = l->lv_last;
+ l->lv_last = item;
+ }
+ ++l->lv_len;
+ item->li_next = NULL;
+}
+
+/*
+ * Append typval_T "tv" to the end of list "l".
+ * Return FAIL when out of memory.
+ */
+ int
+list_append_tv(list_T *l, typval_T *tv)
+{
+ listitem_T *li = listitem_alloc();
+
+ if (li == NULL)
+ return FAIL;
+ copy_tv(tv, &li->li_tv);
+ list_append(l, li);
+ return OK;
+}
+
+/*
+ * Add a dictionary to a list. Used by getqflist().
+ * Return FAIL when out of memory.
+ */
+ int
+list_append_dict(list_T *list, dict_T *dict)
+{
+ listitem_T *li = listitem_alloc();
+
+ if (li == NULL)
+ return FAIL;
+ li->li_tv.v_type = VAR_DICT;
+ li->li_tv.v_lock = 0;
+ li->li_tv.vval.v_dict = dict;
+ list_append(list, li);
+ ++dict->dv_refcount;
+ return OK;
+}
+
+/*
+ * Append list2 to list1.
+ * Return FAIL when out of memory.
+ */
+ int
+list_append_list(list_T *list1, list_T *list2)
+{
+ listitem_T *li = listitem_alloc();
+
+ if (li == NULL)
+ return FAIL;
+ li->li_tv.v_type = VAR_LIST;
+ li->li_tv.v_lock = 0;
+ li->li_tv.vval.v_list = list2;
+ list_append(list1, li);
+ ++list2->lv_refcount;
+ return OK;
+}
+
+/*
+ * Make a copy of "str" and append it as an item to list "l".
+ * When "len" >= 0 use "str[len]".
+ * Returns FAIL when out of memory.
+ */
+ int
+list_append_string(list_T *l, char_u *str, int len)
+{
+ listitem_T *li = listitem_alloc();
+
+ if (li == NULL)
+ return FAIL;
+ list_append(l, li);
+ li->li_tv.v_type = VAR_STRING;
+ li->li_tv.v_lock = 0;
+ if (str == NULL)
+ li->li_tv.vval.v_string = NULL;
+ else if ((li->li_tv.vval.v_string = (len >= 0 ? vim_strnsave(str, len)
+ : vim_strsave(str))) == NULL)
+ return FAIL;
+ return OK;
+}
+
+/*
+ * Append "n" to list "l".
+ * Returns FAIL when out of memory.
+ */
+ int
+list_append_number(list_T *l, varnumber_T n)
+{
+ listitem_T *li;
+
+ li = listitem_alloc();
+ if (li == NULL)
+ return FAIL;
+ li->li_tv.v_type = VAR_NUMBER;
+ li->li_tv.v_lock = 0;
+ li->li_tv.vval.v_number = n;
+ list_append(l, li);
+ return OK;
+}
+
+/*
+ * Insert typval_T "tv" in list "l" before "item".
+ * If "item" is NULL append at the end.
+ * Return FAIL when out of memory.
+ */
+ int
+list_insert_tv(list_T *l, typval_T *tv, listitem_T *item)
+{
+ listitem_T *ni = listitem_alloc();
+
+ if (ni == NULL)
+ return FAIL;
+ copy_tv(tv, &ni->li_tv);
+ list_insert(l, ni, item);
+ return OK;
+}
+
+ void
+list_insert(list_T *l, listitem_T *ni, listitem_T *item)
+{
+ if (item == NULL)
+ /* Append new item at end of list. */
+ list_append(l, ni);
+ else
+ {
+ /* Insert new item before existing item. */
+ ni->li_prev = item->li_prev;
+ ni->li_next = item;
+ if (item->li_prev == NULL)
+ {
+ l->lv_first = ni;
+ ++l->lv_idx;
+ }
+ else
+ {
+ item->li_prev->li_next = ni;
+ l->lv_idx_item = NULL;
+ }
+ item->li_prev = ni;
+ ++l->lv_len;
+ }
+}
+
+/*
+ * Extend "l1" with "l2".
+ * If "bef" is NULL append at the end, otherwise insert before this item.
+ * Returns FAIL when out of memory.
+ */
+ int
+list_extend(list_T *l1, list_T *l2, listitem_T *bef)
+{
+ listitem_T *item;
+ int todo = l2->lv_len;
+
+ /* We also quit the loop when we have inserted the original item count of
+ * the list, avoid a hang when we extend a list with itself. */
+ for (item = l2->lv_first; item != NULL && --todo >= 0; item = item->li_next)
+ if (list_insert_tv(l1, &item->li_tv, bef) == FAIL)
+ return FAIL;
+ return OK;
+}
+
+/*
+ * Concatenate lists "l1" and "l2" into a new list, stored in "tv".
+ * Return FAIL when out of memory.
+ */
+ int
+list_concat(list_T *l1, list_T *l2, typval_T *tv)
+{
+ list_T *l;
+
+ if (l1 == NULL || l2 == NULL)
+ return FAIL;
+
+ /* make a copy of the first list. */
+ l = list_copy(l1, FALSE, 0);
+ if (l == NULL)
+ return FAIL;
+ tv->v_type = VAR_LIST;
+ tv->vval.v_list = l;
+
+ /* append all items from the second list */
+ return list_extend(l, l2, NULL);
+}
+
+/*
+ * Make a copy of list "orig". Shallow if "deep" is FALSE.
+ * The refcount of the new list is set to 1.
+ * See item_copy() for "copyID".
+ * Returns NULL when out of memory.
+ */
+ list_T *
+list_copy(list_T *orig, int deep, int copyID)
+{
+ list_T *copy;
+ listitem_T *item;
+ listitem_T *ni;
+
+ if (orig == NULL)
+ return NULL;
+
+ copy = list_alloc();
+ if (copy != NULL)
+ {
+ if (copyID != 0)
+ {
+ /* Do this before adding the items, because one of the items may
+ * refer back to this list. */
+ orig->lv_copyID = copyID;
+ orig->lv_copylist = copy;
+ }
+ for (item = orig->lv_first; item != NULL && !got_int;
+ item = item->li_next)
+ {
+ ni = listitem_alloc();
+ if (ni == NULL)
+ break;
+ if (deep)
+ {
+ if (item_copy(&item->li_tv, &ni->li_tv, deep, copyID) == FAIL)
+ {
+ vim_free(ni);
+ break;
+ }
+ }
+ else
+ copy_tv(&item->li_tv, &ni->li_tv);
+ list_append(copy, ni);
+ }
+ ++copy->lv_refcount;
+ if (item != NULL)
+ {
+ list_unref(copy);
+ copy = NULL;
+ }
+ }
+
+ return copy;
+}
+
+/*
+ * Remove items "item" to "item2" from list "l".
+ * Does not free the listitem or the value!
+ * This used to be called list_remove, but that conflicts with a Sun header
+ * file.
+ */
+ void
+vimlist_remove(list_T *l, listitem_T *item, listitem_T *item2)
+{
+ listitem_T *ip;
+
+ /* notify watchers */
+ for (ip = item; ip != NULL; ip = ip->li_next)
+ {
+ --l->lv_len;
+ list_fix_watch(l, ip);
+ if (ip == item2)
+ break;
+ }
+
+ if (item2->li_next == NULL)
+ l->lv_last = item->li_prev;
+ else
+ item2->li_next->li_prev = item->li_prev;
+ if (item->li_prev == NULL)
+ l->lv_first = item2->li_next;
+ else
+ item->li_prev->li_next = item2->li_next;
+ l->lv_idx_item = NULL;
+}
+
+/*
+ * Return an allocated string with the string representation of a list.
+ * May return NULL.
+ */
+ char_u *
+list2string(typval_T *tv, int copyID, int restore_copyID)
+{
+ garray_T ga;
+
+ if (tv->vval.v_list == NULL)
+ return NULL;
+ ga_init2(&ga, (int)sizeof(char), 80);
+ ga_append(&ga, '[');
+ if (list_join(&ga, tv->vval.v_list, (char_u *)", ",
+ FALSE, restore_copyID, copyID) == FAIL)
+ {
+ vim_free(ga.ga_data);
+ return NULL;
+ }
+ ga_append(&ga, ']');
+ ga_append(&ga, NUL);
+ return (char_u *)ga.ga_data;
+}
+
+typedef struct join_S {
+ char_u *s;
+ char_u *tofree;
+} join_T;
+
+ static int
+list_join_inner(
+ garray_T *gap, /* to store the result in */
+ list_T *l,
+ char_u *sep,
+ int echo_style,
+ int restore_copyID,
+ int copyID,
+ garray_T *join_gap) /* to keep each list item string */
+{
+ int i;
+ join_T *p;
+ int len;
+ int sumlen = 0;
+ int first = TRUE;
+ char_u *tofree;
+ char_u numbuf[NUMBUFLEN];
+ listitem_T *item;
+ char_u *s;
+
+ /* Stringify each item in the list. */
+ for (item = l->lv_first; item != NULL && !got_int; item = item->li_next)
+ {
+ s = echo_string_core(&item->li_tv, &tofree, numbuf, copyID,
+ echo_style, restore_copyID, !echo_style);
+ if (s == NULL)
+ return FAIL;
+
+ len = (int)STRLEN(s);
+ sumlen += len;
+
+ (void)ga_grow(join_gap, 1);
+ p = ((join_T *)join_gap->ga_data) + (join_gap->ga_len++);
+ if (tofree != NULL || s != numbuf)
+ {
+ p->s = s;
+ p->tofree = tofree;
+ }
+ else
+ {
+ p->s = vim_strnsave(s, len);
+ p->tofree = p->s;
+ }
+
+ line_breakcheck();
+ if (did_echo_string_emsg) /* recursion error, bail out */
+ break;
+ }
+
+ /* Allocate result buffer with its total size, avoid re-allocation and
+ * multiple copy operations. Add 2 for a tailing ']' and NUL. */
+ if (join_gap->ga_len >= 2)
+ sumlen += (int)STRLEN(sep) * (join_gap->ga_len - 1);
+ if (ga_grow(gap, sumlen + 2) == FAIL)
+ return FAIL;
+
+ for (i = 0; i < join_gap->ga_len && !got_int; ++i)
+ {
+ if (first)
+ first = FALSE;
+ else
+ ga_concat(gap, sep);
+ p = ((join_T *)join_gap->ga_data) + i;
+
+ if (p->s != NULL)
+ ga_concat(gap, p->s);
+ line_breakcheck();
+ }
+
+ return OK;
+}
+
+/*
+ * Join list "l" into a string in "*gap", using separator "sep".
+ * When "echo_style" is TRUE use String as echoed, otherwise as inside a List.
+ * Return FAIL or OK.
+ */
+ int
+list_join(
+ garray_T *gap,
+ list_T *l,
+ char_u *sep,
+ int echo_style,
+ int restore_copyID,
+ int copyID)
+{
+ garray_T join_ga;
+ int retval;
+ join_T *p;
+ int i;
+
+ if (l->lv_len < 1)
+ return OK; /* nothing to do */
+ ga_init2(&join_ga, (int)sizeof(join_T), l->lv_len);
+ retval = list_join_inner(gap, l, sep, echo_style, restore_copyID,
+ copyID, &join_ga);
+
+ /* Dispose each item in join_ga. */
+ if (join_ga.ga_data != NULL)
+ {
+ p = (join_T *)join_ga.ga_data;
+ for (i = 0; i < join_ga.ga_len; ++i)
+ {
+ vim_free(p->tofree);
+ ++p;
+ }
+ ga_clear(&join_ga);
+ }
+
+ return retval;
+}
+
+/*
+ * Allocate a variable for a List and fill it from "*arg".
+ * Return OK or FAIL.
+ */
+ int
+get_list_tv(char_u **arg, typval_T *rettv, int evaluate)
+{
+ list_T *l = NULL;
+ typval_T tv;
+ listitem_T *item;
+
+ if (evaluate)
+ {
+ l = list_alloc();
+ if (l == NULL)
+ return FAIL;
+ }
+
+ *arg = skipwhite(*arg + 1);
+ while (**arg != ']' && **arg != NUL)
+ {
+ if (eval1(arg, &tv, evaluate) == FAIL) /* recursive! */
+ goto failret;
+ if (evaluate)
+ {
+ item = listitem_alloc();
+ if (item != NULL)
+ {
+ item->li_tv = tv;
+ item->li_tv.v_lock = 0;
+ list_append(l, item);
+ }
+ else
+ clear_tv(&tv);
+ }
+
+ if (**arg == ']')
+ break;
+ if (**arg != ',')
+ {
+ semsg(_("E696: Missing comma in List: %s"), *arg);
+ goto failret;
+ }
+ *arg = skipwhite(*arg + 1);
+ }
+
+ if (**arg != ']')
+ {
+ semsg(_("E697: Missing end of List ']': %s"), *arg);
+failret:
+ if (evaluate)
+ list_free(l);
+ return FAIL;
+ }
+
+ *arg = skipwhite(*arg + 1);
+ if (evaluate)
+ rettv_list_set(rettv, l);
+
+ return OK;
+}
+
+/*
+ * Write "list" of strings to file "fd".
+ */
+ int
+write_list(FILE *fd, list_T *list, int binary)
+{
+ listitem_T *li;
+ int c;
+ int ret = OK;
+ char_u *s;
+
+ for (li = list->lv_first; li != NULL; li = li->li_next)
+ {
+ for (s = tv_get_string(&li->li_tv); *s != NUL; ++s)
+ {
+ if (*s == '\n')
+ c = putc(NUL, fd);
+ else
+ c = putc(*s, fd);
+ if (c == EOF)
+ {
+ ret = FAIL;
+ break;
+ }
+ }
+ if (!binary || li->li_next != NULL)
+ if (putc('\n', fd) == EOF)
+ {
+ ret = FAIL;
+ break;
+ }
+ if (ret == FAIL)
+ {
+ emsg(_(e_write));
+ break;
+ }
+ }
+ return ret;
+}
+
+/*
+ * Initialize a static list with 10 items.
+ */
+ void
+init_static_list(staticList10_T *sl)
+{
+ list_T *l = &sl->sl_list;
+ int i;
+
+ memset(sl, 0, sizeof(staticList10_T));
+ l->lv_first = &sl->sl_items[0];
+ l->lv_last = &sl->sl_items[9];
+ l->lv_refcount = DO_NOT_FREE_CNT;
+ l->lv_lock = VAR_FIXED;
+ sl->sl_list.lv_len = 10;
+
+ for (i = 0; i < 10; ++i)
+ {
+ listitem_T *li = &sl->sl_items[i];
+
+ if (i == 0)
+ li->li_prev = NULL;
+ else
+ li->li_prev = li - 1;
+ if (i == 9)
+ li->li_next = NULL;
+ else
+ li->li_next = li + 1;
+ }
+}
+
+#endif /* defined(FEAT_EVAL) */
diff --git a/src/macros.h b/src/macros.h
new file mode 100644
index 0000000..29607db
--- /dev/null
+++ b/src/macros.h
@@ -0,0 +1,336 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * Do ":help uganda" in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ */
+
+/*
+ * macros.h: macro definitions for often used code
+ *
+ * Macros should be ALL_CAPS. An exception is for where a function is
+ * replaced and an argument is not used more than once.
+ */
+
+/*
+ * PBYTE(lp, c) - put byte 'c' at position 'lp'
+ */
+#define PBYTE(lp, c) (*(ml_get_buf(curbuf, (lp).lnum, TRUE) + (lp).col) = (c))
+
+/*
+ * Position comparisons
+ */
+#define LT_POS(a, b) (((a).lnum != (b).lnum) \
+ ? (a).lnum < (b).lnum \
+ : (a).col != (b).col \
+ ? (a).col < (b).col \
+ : (a).coladd < (b).coladd)
+#define LT_POSP(a, b) (((a)->lnum != (b)->lnum) \
+ ? (a)->lnum < (b)->lnum \
+ : (a)->col != (b)->col \
+ ? (a)->col < (b)->col \
+ : (a)->coladd < (b)->coladd)
+#define EQUAL_POS(a, b) (((a).lnum == (b).lnum) && ((a).col == (b).col) && ((a).coladd == (b).coladd))
+#define CLEAR_POS(a) {(a)->lnum = 0; (a)->col = 0; (a)->coladd = 0;}
+
+#define LTOREQ_POS(a, b) (LT_POS(a, b) || EQUAL_POS(a, b))
+
+/*
+ * VIM_ISWHITE() is used for "^" and the like. It differs from isspace()
+ * because it doesn't include <CR> and <LF> and the like.
+ */
+#define VIM_ISWHITE(x) ((x) == ' ' || (x) == '\t')
+
+/*
+ * LINEEMPTY() - return TRUE if the line is empty
+ */
+#define LINEEMPTY(p) (*ml_get(p) == NUL)
+
+/*
+ * BUFEMPTY() - return TRUE if the current buffer is empty
+ */
+#define BUFEMPTY() (curbuf->b_ml.ml_line_count == 1 && *ml_get((linenr_T)1) == NUL)
+
+/*
+ * toupper() and tolower() that use the current locale.
+ * On some systems toupper()/tolower() only work on lower/uppercase
+ * characters, first use islower() or isupper() then.
+ * Careful: Only call TOUPPER_LOC() and TOLOWER_LOC() with a character in the
+ * range 0 - 255. toupper()/tolower() on some systems can't handle others.
+ * Note: It is often better to use MB_TOLOWER() and MB_TOUPPER(), because many
+ * toupper() and tolower() implementations only work for ASCII.
+ */
+#ifdef MSWIN
+# define TOUPPER_LOC(c) toupper_tab[(c) & 255]
+# define TOLOWER_LOC(c) tolower_tab[(c) & 255]
+#else
+# ifdef BROKEN_TOUPPER
+# define TOUPPER_LOC(c) (islower(c) ? toupper(c) : (c))
+# define TOLOWER_LOC(c) (isupper(c) ? tolower(c) : (c))
+# else
+# define TOUPPER_LOC toupper
+# define TOLOWER_LOC tolower
+# endif
+#endif
+
+/* toupper() and tolower() for ASCII only and ignore the current locale. */
+#ifdef EBCDIC
+# define TOUPPER_ASC(c) (islower(c) ? toupper(c) : (c))
+# define TOLOWER_ASC(c) (isupper(c) ? tolower(c) : (c))
+#else
+# define TOUPPER_ASC(c) (((c) < 'a' || (c) > 'z') ? (c) : (c) - ('a' - 'A'))
+# define TOLOWER_ASC(c) (((c) < 'A' || (c) > 'Z') ? (c) : (c) + ('a' - 'A'))
+#endif
+
+/*
+ * MB_ISLOWER() and MB_ISUPPER() are to be used on multi-byte characters. But
+ * don't use them for negative values!
+ */
+#define MB_ISLOWER(c) vim_islower(c)
+#define MB_ISUPPER(c) vim_isupper(c)
+#define MB_TOLOWER(c) vim_tolower(c)
+#define MB_TOUPPER(c) vim_toupper(c)
+
+/* Use our own isdigit() replacement, because on MS-Windows isdigit() returns
+ * non-zero for superscript 1. Also avoids that isdigit() crashes for numbers
+ * below 0 and above 255. */
+#define VIM_ISDIGIT(c) ((unsigned)(c) - '0' < 10)
+
+/* Like isalpha() but reject non-ASCII characters. Can't be used with a
+ * special key (negative value). */
+#ifdef EBCDIC
+# define ASCII_ISALPHA(c) isalpha(c)
+# define ASCII_ISALNUM(c) isalnum(c)
+# define ASCII_ISLOWER(c) islower(c)
+# define ASCII_ISUPPER(c) isupper(c)
+#else
+# define ASCII_ISLOWER(c) ((unsigned)(c) - 'a' < 26)
+# define ASCII_ISUPPER(c) ((unsigned)(c) - 'A' < 26)
+# define ASCII_ISALPHA(c) (ASCII_ISUPPER(c) || ASCII_ISLOWER(c))
+# define ASCII_ISALNUM(c) (ASCII_ISALPHA(c) || VIM_ISDIGIT(c))
+#endif
+
+/* Returns empty string if it is NULL. */
+#define EMPTY_IF_NULL(x) ((x) ? (x) : (char_u *)"")
+
+#ifdef FEAT_LANGMAP
+/*
+ * Adjust chars in a language according to 'langmap' option.
+ * NOTE that there is no noticeable overhead if 'langmap' is not set.
+ * When set the overhead for characters < 256 is small.
+ * Don't apply 'langmap' if the character comes from the Stuff buffer or from
+ * a mapping and the langnoremap option was set.
+ * The do-while is just to ignore a ';' after the macro.
+ */
+# define LANGMAP_ADJUST(c, condition) \
+ do { \
+ if (*p_langmap \
+ && (condition) \
+ && (p_lrm || (!p_lrm && KeyTyped)) \
+ && !KeyStuffed \
+ && (c) >= 0) \
+ { \
+ if ((c) < 256) \
+ c = langmap_mapchar[c]; \
+ else \
+ c = langmap_adjust_mb(c); \
+ } \
+ } while (0)
+#else
+# define LANGMAP_ADJUST(c, condition) /* nop */
+#endif
+
+/*
+ * VIM_ISBREAK() is used very often if 'linebreak' is set, use a macro to make
+ * it work fast. Only works for single byte characters!
+ */
+#define VIM_ISBREAK(c) ((c) < 256 && breakat_flags[(char_u)(c)])
+
+/*
+ * On VMS file names are different and require a translation.
+ * On the Mac open() has only two arguments.
+ */
+#ifdef VMS
+# define mch_access(n, p) access(vms_fixfilename(n), (p))
+ /* see mch_open() comment */
+# define mch_fopen(n, p) fopen(vms_fixfilename(n), (p))
+# define mch_fstat(n, p) fstat(vms_fixfilename(n), (p))
+ /* VMS does not have lstat() */
+# define mch_stat(n, p) stat(vms_fixfilename(n), (p))
+# define mch_rmdir(n) rmdir(vms_fixfilename(n))
+#else
+# ifndef WIN32
+# define mch_access(n, p) access((n), (p))
+# endif
+# define mch_fstat(n, p) fstat((n), (p))
+# ifdef MSWIN /* has its own mch_stat() function */
+# define mch_stat(n, p) vim_stat((n), (p))
+# else
+# ifdef STAT_IGNORES_SLASH
+# define mch_stat(n, p) vim_stat((n), (p))
+# else
+# define mch_stat(n, p) stat((n), (p))
+# endif
+# endif
+#endif
+
+#ifdef HAVE_LSTAT
+# define mch_lstat(n, p) lstat((n), (p))
+#else
+# define mch_lstat(n, p) mch_stat((n), (p))
+#endif
+
+#ifdef VMS
+/*
+ * It is possible to force some record format with:
+ * # define mch_open(n, m, p) open(vms_fixfilename(n), (m), (p)), "rat=cr", "rfm=stmlf", "mrs=0")
+ * but it is not recommended, because it can destroy indexes etc.
+ */
+# define mch_open(n, m, p) open(vms_fixfilename(n), (m), (p))
+#endif
+
+/* mch_open_rw(): invoke mch_open() with third argument for user R/W. */
+#if defined(UNIX) || defined(VMS) /* open in rw------- mode */
+# define mch_open_rw(n, f) mch_open((n), (f), (mode_t)0600)
+#else
+# if defined(MSWIN) /* open read/write */
+# define mch_open_rw(n, f) mch_open((n), (f), S_IREAD | S_IWRITE)
+# else
+# define mch_open_rw(n, f) mch_open((n), (f), 0)
+# endif
+#endif
+
+#ifdef STARTUPTIME
+# define TIME_MSG(s) do { if (time_fd != NULL) time_msg(s, NULL); } while (0)
+#else
+# define TIME_MSG(s) do { /**/ } while (0)
+#endif
+
+#define REPLACE_NORMAL(s) (((s) & REPLACE_FLAG) && !((s) & VREPLACE_FLAG))
+
+#ifdef FEAT_ARABIC
+# define UTF_COMPOSINGLIKE(p1, p2) utf_composinglike((p1), (p2))
+#else
+# define UTF_COMPOSINGLIKE(p1, p2) utf_iscomposing(utf_ptr2char(p2))
+#endif
+
+#ifdef FEAT_RIGHTLEFT
+ /* Whether to draw the vertical bar on the right side of the cell. */
+# define CURSOR_BAR_RIGHT (curwin->w_p_rl && (!(State & CMDLINE) || cmdmsg_rl))
+#endif
+
+/*
+ * MB_PTR_ADV(): advance a pointer to the next character, taking care of
+ * multi-byte characters if needed.
+ * MB_PTR_BACK(): backup a pointer to the previous character, taking care of
+ * multi-byte characters if needed.
+ * MB_COPY_CHAR(f, t): copy one char from "f" to "t" and advance the pointers.
+ * PTR2CHAR(): get character from pointer.
+ */
+/* Get the length of the character p points to, including composing chars */
+#define MB_PTR2LEN(p) (has_mbyte ? (*mb_ptr2len)(p) : 1)
+/* Advance multi-byte pointer, skip over composing chars. */
+#define MB_PTR_ADV(p) p += has_mbyte ? (*mb_ptr2len)(p) : 1
+/* Advance multi-byte pointer, do not skip over composing chars. */
+#define MB_CPTR_ADV(p) p += enc_utf8 ? utf_ptr2len(p) : has_mbyte ? (*mb_ptr2len)(p) : 1
+/* Backup multi-byte pointer. Only use with "p" > "s" ! */
+#define MB_PTR_BACK(s, p) p -= has_mbyte ? ((*mb_head_off)(s, p - 1) + 1) : 1
+/* get length of multi-byte char, not including composing chars */
+#define MB_CPTR2LEN(p) (enc_utf8 ? utf_ptr2len(p) : (*mb_ptr2len)(p))
+
+#define MB_COPY_CHAR(f, t) if (has_mbyte) mb_copy_char(&f, &t); else *t++ = *f++
+#define MB_CHARLEN(p) (has_mbyte ? mb_charlen(p) : (int)STRLEN(p))
+#define MB_CHAR2LEN(c) (has_mbyte ? mb_char2len(c) : 1)
+#define PTR2CHAR(p) (has_mbyte ? mb_ptr2char(p) : (int)*(p))
+
+#ifdef FEAT_AUTOCHDIR
+# define DO_AUTOCHDIR do { if (p_acd) do_autochdir(); } while (0)
+#else
+# define DO_AUTOCHDIR do { /**/ } while (0)
+#endif
+
+#define RESET_BINDING(wp) (wp)->w_p_scb = FALSE; (wp)->w_p_crb = FALSE
+
+#ifdef FEAT_DIFF
+# define PLINES_NOFILL(x) plines_nofill(x)
+#else
+# define PLINES_NOFILL(x) plines(x)
+#endif
+
+#if defined(FEAT_JOB_CHANNEL) || defined(FEAT_CLIENTSERVER)
+# define MESSAGE_QUEUE
+#endif
+
+#if defined(FEAT_EVAL) && defined(FEAT_FLOAT)
+# include <float.h>
+# if defined(HAVE_MATH_H)
+ /* for isnan() and isinf() */
+# include <math.h>
+# endif
+# ifdef USING_FLOAT_STUFF
+# if defined(WIN32)
+# ifndef isnan
+# define isnan(x) _isnan(x)
+ static __inline int isinf(double x) { return !_finite(x) && !_isnan(x); }
+# endif
+# else
+# ifndef HAVE_ISNAN
+ static inline int isnan(double x) { return x != x; }
+# endif
+# ifndef HAVE_ISINF
+ static inline int isinf(double x) { return !isnan(x) && isnan(x - x); }
+# endif
+# endif
+# if !defined(INFINITY)
+# if defined(DBL_MAX)
+# ifdef VMS
+# define INFINITY DBL_MAX
+# else
+# define INFINITY (DBL_MAX+DBL_MAX)
+# endif
+# else
+# define INFINITY (1.0 / 0.0)
+# endif
+# endif
+# if !defined(NAN)
+# define NAN (INFINITY-INFINITY)
+# endif
+# if !defined(DBL_EPSILON)
+# define DBL_EPSILON 2.2204460492503131e-16
+# endif
+# endif
+#endif
+
+/*
+ * In a hashtab item "hi_key" points to "di_key" in a dictitem.
+ * This avoids adding a pointer to the hashtab item.
+ * DI2HIKEY() converts a dictitem pointer to a hashitem key pointer.
+ * HIKEY2DI() converts a hashitem key pointer to a dictitem pointer.
+ * HI2DI() converts a hashitem pointer to a dictitem pointer.
+ */
+#define DI2HIKEY(di) ((di)->di_key)
+#define HIKEY2DI(p) ((dictitem_T *)(p - offsetof(dictitem_T, di_key)))
+#define HI2DI(hi) HIKEY2DI((hi)->hi_key)
+
+/*
+ * Flush control functions.
+ */
+#ifdef FEAT_GUI
+# define mch_enable_flush() gui_enable_flush()
+# define mch_disable_flush() gui_disable_flush()
+#else
+# define mch_enable_flush()
+# define mch_disable_flush()
+#endif
+
+/*
+ * Like vim_free(), and also set the pointer to NULL.
+ */
+#define VIM_CLEAR(p) \
+ do { \
+ if ((p) != NULL) { \
+ vim_free(p); \
+ (p) = NULL; \
+ } \
+ } while (0)
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..df204bc
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,4296 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+#define EXTERN
+#include "vim.h"
+
+#ifdef __CYGWIN__
+# ifndef WIN32
+# include <cygwin/version.h>
+# include <sys/cygwin.h> /* for cygwin_conv_to_posix_path() and/or
+ * cygwin_conv_path() */
+# endif
+# include <limits.h>
+#endif
+
+#if defined(WIN3264) && !defined(FEAT_GUI_W32)
+# include "iscygpty.h"
+#endif
+
+/* Values for edit_type. */
+#define EDIT_NONE 0 /* no edit type yet */
+#define EDIT_FILE 1 /* file name argument[s] given, use argument list */
+#define EDIT_STDIN 2 /* read file from stdin */
+#define EDIT_TAG 3 /* tag name argument given, use tagname */
+#define EDIT_QF 4 /* start in quickfix mode */
+
+#if (defined(UNIX) || defined(VMS)) && !defined(NO_VIM_MAIN)
+static int file_owned(char *fname);
+#endif
+static void mainerr(int, char_u *);
+# if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
+static void init_locale(void);
+# endif
+static void early_arg_scan(mparm_T *parmp);
+#ifndef NO_VIM_MAIN
+static void usage(void);
+static void parse_command_name(mparm_T *parmp);
+static void command_line_scan(mparm_T *parmp);
+static void check_tty(mparm_T *parmp);
+static void read_stdin(void);
+static void create_windows(mparm_T *parmp);
+static void edit_buffers(mparm_T *parmp, char_u *cwd);
+static void exe_pre_commands(mparm_T *parmp);
+static void exe_commands(mparm_T *parmp);
+static void source_startup_scripts(mparm_T *parmp);
+static void main_start_gui(void);
+# if defined(HAS_SWAP_EXISTS_ACTION)
+static void check_swap_exists_action(void);
+# endif
+# ifdef FEAT_EVAL
+static void set_progpath(char_u *argv0);
+# endif
+# if defined(FEAT_CLIENTSERVER) || defined(PROTO)
+static void exec_on_server(mparm_T *parmp);
+static void prepare_server(mparm_T *parmp);
+static void cmdsrv_main(int *argc, char **argv, char_u *serverName_arg, char_u **serverStr);
+static char_u *serverMakeName(char_u *arg, char *cmd);
+# endif
+#endif
+
+
+/*
+ * Different types of error messages.
+ */
+static char *(main_errors[]) =
+{
+ N_("Unknown option argument"),
+#define ME_UNKNOWN_OPTION 0
+ N_("Too many edit arguments"),
+#define ME_TOO_MANY_ARGS 1
+ N_("Argument missing after"),
+#define ME_ARG_MISSING 2
+ N_("Garbage after option argument"),
+#define ME_GARBAGE 3
+ N_("Too many \"+command\", \"-c command\" or \"--cmd command\" arguments"),
+#define ME_EXTRA_CMD 4
+ N_("Invalid argument for"),
+#define ME_INVALID_ARG 5
+};
+
+#ifndef PROTO /* don't want a prototype for main() */
+
+/* Various parameters passed between main() and other functions. */
+static mparm_T params;
+
+#ifndef NO_VIM_MAIN /* skip this for unittests */
+
+static char_u *start_dir = NULL; /* current working dir on startup */
+
+static int has_dash_c_arg = FALSE;
+
+ int
+# ifdef VIMDLL
+_export
+# endif
+# ifdef FEAT_GUI_MSWIN
+# ifdef __BORLANDC__
+_cdecl
+# endif
+VimMain
+# else
+main
+# endif
+(int argc, char **argv)
+{
+#if defined(STARTUPTIME) || defined(CLEAN_RUNTIMEPATH)
+ int i;
+#endif
+
+ /*
+ * Do any system-specific initialisations. These can NOT use IObuff or
+ * NameBuff. Thus emsg2() cannot be called!
+ */
+ mch_early_init();
+
+#if defined(WIN32)
+ /*
+ * MinGW expands command line arguments, which confuses our code to
+ * convert when 'encoding' changes. Get the unexpanded arguments.
+ */
+ argc = get_cmd_argsW(&argv);
+#endif
+
+ /* Many variables are in "params" so that we can pass them to invoked
+ * functions without a lot of arguments. "argc" and "argv" are also
+ * copied, so that they can be changed. */
+ vim_memset(&params, 0, sizeof(params));
+ params.argc = argc;
+ params.argv = argv;
+ params.want_full_screen = TRUE;
+#ifdef FEAT_EVAL
+ params.use_debug_break_level = -1;
+#endif
+ params.window_count = -1;
+
+#ifdef FEAT_RUBY
+ {
+ int ruby_stack_start;
+ vim_ruby_init((void *)&ruby_stack_start);
+ }
+#endif
+
+#ifdef FEAT_TCL
+ vim_tcl_init(params.argv[0]);
+#endif
+
+#ifdef MEM_PROFILE
+ atexit(vim_mem_profile_dump);
+#endif
+
+#ifdef STARTUPTIME
+ /* Need to find "--startuptime" before actually parsing arguments. */
+ for (i = 1; i < argc - 1; ++i)
+ if (STRICMP(argv[i], "--startuptime") == 0)
+ {
+ time_fd = mch_fopen(argv[i + 1], "a");
+ TIME_MSG("--- VIM STARTING ---");
+ break;
+ }
+#endif
+ starttime = time(NULL);
+
+#ifdef CLEAN_RUNTIMEPATH
+ /* Need to find "--clean" before actually parsing arguments. */
+ for (i = 1; i < argc; ++i)
+ if (STRICMP(argv[i], "--clean") == 0)
+ {
+ params.clean = TRUE;
+ break;
+ }
+#endif
+ common_init(&params);
+
+#ifdef FEAT_CLIENTSERVER
+ /*
+ * Do the client-server stuff, unless "--servername ''" was used.
+ * This may exit Vim if the command was sent to the server.
+ */
+ exec_on_server(&params);
+#endif
+
+ /*
+ * Figure out the way to work from the command name argv[0].
+ * "vimdiff" starts diff mode, "rvim" sets "restricted", etc.
+ */
+ parse_command_name(&params);
+
+ /*
+ * Process the command line arguments. File names are put in the global
+ * argument list "global_alist".
+ */
+ command_line_scan(&params);
+ TIME_MSG("parsing arguments");
+
+ /*
+ * On some systems, when we compile with the GUI, we always use it. On Mac
+ * there is no terminal version, and on Windows we can't fork one off with
+ * :gui.
+ */
+#ifdef ALWAYS_USE_GUI
+ gui.starting = TRUE;
+#else
+# if defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK)
+ /*
+ * Check if the GUI can be started. Reset gui.starting if not.
+ * Don't know about other systems, stay on the safe side and don't check.
+ */
+ if (gui.starting)
+ {
+ if (gui_init_check() == FAIL)
+ {
+ gui.starting = FALSE;
+
+ /* When running "evim" or "gvim -y" we need the menus, exit if we
+ * don't have them. */
+ if (params.evim_mode)
+ mch_exit(1);
+ }
+ }
+# endif
+#endif
+
+ if (GARGCOUNT > 0)
+ {
+#ifdef EXPAND_FILENAMES
+ /*
+ * Expand wildcards in file names.
+ */
+ if (!params.literal)
+ {
+ start_dir = alloc(MAXPATHL);
+ if (start_dir != NULL)
+ mch_dirname(start_dir, MAXPATHL);
+ /* Temporarily add '(' and ')' to 'isfname'. These are valid
+ * filename characters but are excluded from 'isfname' to make
+ * "gf" work on a file name in parenthesis (e.g.: see vim.h). */
+ do_cmdline_cmd((char_u *)":set isf+=(,)");
+ alist_expand(NULL, 0);
+ do_cmdline_cmd((char_u *)":set isf&");
+ if (start_dir != NULL)
+ mch_chdir((char *)start_dir);
+ }
+#endif
+ params.fname = alist_name(&GARGLIST[0]);
+ }
+
+#if defined(WIN32)
+ {
+ extern void set_alist_count(void);
+
+ /* Remember the number of entries in the argument list. If it changes
+ * we don't react on setting 'encoding'. */
+ set_alist_count();
+ }
+#endif
+
+#ifdef MSWIN
+ if (GARGCOUNT == 1 && params.full_path)
+ {
+ /*
+ * If there is one filename, fully qualified, we have very probably
+ * been invoked from explorer, so change to the file's directory.
+ * Hint: to avoid this when typing a command use a forward slash.
+ * If the cd fails, it doesn't matter.
+ */
+ (void)vim_chdirfile(params.fname, "drop");
+ if (start_dir != NULL)
+ mch_dirname(start_dir, MAXPATHL);
+ }
+#endif
+ TIME_MSG("expanding arguments");
+
+#ifdef FEAT_DIFF
+ if (params.diff_mode && params.window_count == -1)
+ params.window_count = 0; /* open up to 3 windows */
+#endif
+
+ /* Don't redraw until much later. */
+ ++RedrawingDisabled;
+
+ /*
+ * When listing swap file names, don't do cursor positioning et. al.
+ */
+ if (recoverymode && params.fname == NULL)
+ params.want_full_screen = FALSE;
+
+ /*
+ * When certain to start the GUI, don't check capabilities of terminal.
+ * For GTK we can't be sure, but when started from the desktop it doesn't
+ * make sense to try using a terminal.
+ */
+#if defined(ALWAYS_USE_GUI) || defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK)
+ if (gui.starting
+# ifdef FEAT_GUI_GTK
+ && !isatty(2)
+# endif
+ )
+ 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.
+ * Note that we may use mch_exit() before mch_init()!
+ */
+ mch_init();
+ TIME_MSG("shell init");
+
+#ifdef USE_XSMP
+ /*
+ * For want of anywhere else to do it, try to connect to xsmp here.
+ * Fitting it in after gui_mch_init, but before gui_init (via termcapinit).
+ * Hijacking -X 'no X connection' to also disable XSMP connection as that
+ * has a similar delay upon failure.
+ * Only try if SESSION_MANAGER is set to something non-null.
+ */
+ if (!x_no_connect)
+ {
+ char *p = getenv("SESSION_MANAGER");
+
+ if (p != NULL && *p != NUL)
+ {
+ xsmp_init();
+ TIME_MSG("xsmp init");
+ }
+ }
+#endif
+
+ /*
+ * Print a warning if stdout is not a terminal.
+ */
+ check_tty(&params);
+
+#ifdef _IOLBF
+ /* Ensure output works usefully without a tty: buffer lines instead of
+ * fully buffered. */
+ if (silent_mode)
+ setvbuf(stdout, NULL, _IOLBF, 0);
+#endif
+
+ /* This message comes before term inits, but after setting "silent_mode"
+ * when the input is not a tty. */
+ if (GARGCOUNT > 1 && !silent_mode)
+ printf(_("%d files to edit\n"), GARGCOUNT);
+
+ if (params.want_full_screen && !silent_mode)
+ {
+ termcapinit(params.term); /* set terminal name and get terminal
+ capabilities (will set full_screen) */
+ screen_start(); /* don't know where cursor is now */
+ TIME_MSG("Termcap init");
+ }
+
+ /*
+ * Set the default values for the options that use Rows and Columns.
+ */
+ ui_get_shellsize(); /* inits Rows and Columns */
+ win_init_size();
+#ifdef FEAT_DIFF
+ /* Set the 'diff' option now, so that it can be checked for in a .vimrc
+ * file. There is no buffer yet though. */
+ if (params.diff_mode)
+ diff_win_options(firstwin, FALSE);
+#endif
+
+ cmdline_row = Rows - p_ch;
+ msg_row = cmdline_row;
+ screenalloc(FALSE); /* allocate screen buffers */
+ set_init_2();
+ TIME_MSG("inits 2");
+
+ msg_scroll = TRUE;
+ no_wait_return = TRUE;
+
+ init_mappings(); /* set up initial mappings */
+
+ init_highlight(TRUE, FALSE); /* set the default highlight groups */
+ TIME_MSG("init highlight");
+
+#ifdef FEAT_EVAL
+ /* Set the break level after the terminal is initialized. */
+ debug_break_level = params.use_debug_break_level;
+#endif
+
+ /* Reset 'loadplugins' for "-u NONE" before "--cmd" arguments.
+ * Allows for setting 'loadplugins' there. */
+ if (params.use_vimrc != NULL
+ && (STRCMP(params.use_vimrc, "NONE") == 0
+ || STRCMP(params.use_vimrc, "DEFAULTS") == 0))
+ p_lpl = FALSE;
+
+ /* Execute --cmd arguments. */
+ exe_pre_commands(&params);
+
+ /* Source startup scripts. */
+ source_startup_scripts(&params);
+
+#ifdef FEAT_MZSCHEME
+ /*
+ * Newer version of MzScheme (Racket) require earlier (trampolined)
+ * initialisation via scheme_main_setup.
+ * Implement this by initialising it as early as possible
+ * and splitting off remaining Vim main into vim_main2().
+ * Do source startup scripts, so that 'mzschemedll' can be set.
+ */
+ return mzscheme_main();
+#else
+ return vim_main2();
+#endif
+}
+#endif /* NO_VIM_MAIN */
+#endif /* PROTO */
+
+/*
+ * vim_main2() is needed for FEAT_MZSCHEME, but we define it always to keep
+ * things simple.
+ * It is also defined when NO_VIM_MAIN is defined, but then it's empty.
+ */
+ int
+vim_main2(void)
+{
+#ifndef NO_VIM_MAIN
+#ifdef FEAT_EVAL
+ /*
+ * Read all the plugin files.
+ * Only when compiled with +eval, since most plugins need it.
+ */
+ if (p_lpl)
+ {
+ char_u *rtp_copy = NULL;
+
+ /* First add all package directories to 'runtimepath', so that their
+ * autoload directories can be found. Only if not done already with a
+ * :packloadall command.
+ * Make a copy of 'runtimepath', so that source_runtime does not use
+ * the pack directories. */
+ if (!did_source_packages)
+ {
+ rtp_copy = vim_strsave(p_rtp);
+ add_pack_start_dirs();
+ }
+
+ source_in_path(rtp_copy == NULL ? p_rtp : rtp_copy,
+# ifdef VMS /* Somehow VMS doesn't handle the "**". */
+ (char_u *)"plugin/*.vim",
+# else
+ (char_u *)"plugin/**/*.vim",
+# endif
+ DIP_ALL | DIP_NOAFTER);
+ TIME_MSG("loading plugins");
+ vim_free(rtp_copy);
+
+ /* Only source "start" packages if not done already with a :packloadall
+ * command. */
+ if (!did_source_packages)
+ load_start_packages();
+ TIME_MSG("loading packages");
+
+# ifdef VMS /* Somehow VMS doesn't handle the "**". */
+ source_runtime((char_u *)"plugin/*.vim", DIP_ALL | DIP_AFTER);
+# else
+ source_runtime((char_u *)"plugin/**/*.vim", DIP_ALL | DIP_AFTER);
+# endif
+ TIME_MSG("loading after plugins");
+
+ }
+#endif
+
+#ifdef FEAT_DIFF
+ /* Decide about window layout for diff mode after reading vimrc. */
+ if (params.diff_mode && params.window_layout == 0)
+ {
+ if (diffopt_horizontal())
+ params.window_layout = WIN_HOR; /* use horizontal split */
+ else
+ params.window_layout = WIN_VER; /* use vertical split */
+ }
+#endif
+
+ /*
+ * Recovery mode without a file name: List swap files.
+ * This uses the 'dir' option, therefore it must be after the
+ * initializations.
+ */
+ if (recoverymode && params.fname == NULL)
+ {
+ recover_names(NULL, TRUE, 0, NULL);
+ mch_exit(0);
+ }
+
+ /*
+ * Set a few option defaults after reading .vimrc files:
+ * 'title' and 'icon', Unix: 'shellpipe' and 'shellredir'.
+ */
+ set_init_3();
+ TIME_MSG("inits 3");
+
+ /*
+ * "-n" argument: Disable swap file by setting 'updatecount' to 0.
+ * Note that this overrides anything from a vimrc file.
+ */
+ if (params.no_swap_file)
+ p_uc = 0;
+
+#ifdef FEAT_FKMAP
+ if (curwin->w_p_rl && p_altkeymap)
+ {
+ p_hkmap = FALSE; /* Reset the Hebrew keymap mode */
+# ifdef FEAT_ARABIC
+ curwin->w_p_arab = FALSE; /* Reset the Arabic keymap mode */
+# endif
+ p_fkmap = TRUE; /* Set the Farsi keymap mode */
+ }
+#endif
+
+#ifdef FEAT_GUI
+ if (gui.starting)
+ {
+#if defined(UNIX) || defined(VMS)
+ /* When something caused a message from a vimrc script, need to output
+ * an extra newline before the shell prompt. */
+ if (did_emsg || msg_didout)
+ putchar('\n');
+#endif
+
+ gui_start(); /* will set full_screen to TRUE */
+ TIME_MSG("starting GUI");
+
+ /* When running "evim" or "gvim -y" we need the menus, exit if we
+ * don't have them. */
+ if (!gui.in_use && params.evim_mode)
+ mch_exit(1);
+ }
+#endif
+
+#ifdef FEAT_VIMINFO
+ /*
+ * Read in registers, history etc, but not marks, from the viminfo file.
+ * This is where v:oldfiles gets filled.
+ */
+ if (*p_viminfo != NUL)
+ {
+ read_viminfo(NULL, VIF_WANT_INFO | VIF_GET_OLDFILES);
+ TIME_MSG("reading viminfo");
+ }
+#endif
+#ifdef FEAT_EVAL
+ /* It's better to make v:oldfiles an empty list than NULL. */
+ if (get_vim_var_list(VV_OLDFILES) == NULL)
+ set_vim_var_list(VV_OLDFILES, list_alloc());
+#endif
+
+#ifdef FEAT_QUICKFIX
+ /*
+ * "-q errorfile": Load the error file now.
+ * If the error file can't be read, exit before doing anything else.
+ */
+ if (params.edit_type == EDIT_QF)
+ {
+ char_u *enc = NULL;
+
+ enc = p_menc;
+ if (params.use_ef != NULL)
+ set_string_option_direct((char_u *)"ef", -1,
+ params.use_ef, OPT_FREE, SID_CARG);
+ vim_snprintf((char *)IObuff, IOSIZE, "cfile %s", p_ef);
+ if (qf_init(NULL, p_ef, p_efm, TRUE, IObuff, enc) < 0)
+ {
+ out_char('\n');
+ mch_exit(3);
+ }
+ TIME_MSG("reading errorfile");
+ }
+#endif
+
+ /*
+ * Start putting things on the screen.
+ * Scroll screen down before drawing over it
+ * Clear screen now, so file message will not be cleared.
+ */
+ starting = NO_BUFFERS;
+ no_wait_return = FALSE;
+ if (!exmode_active)
+ msg_scroll = FALSE;
+
+#ifdef FEAT_GUI
+ /*
+ * This seems to be required to make callbacks to be called now, instead
+ * of after things have been put on the screen, which then may be deleted
+ * when getting a resize callback.
+ * For the Mac this handles putting files dropped on the Vim icon to
+ * global_alist.
+ */
+ if (gui.in_use)
+ {
+ gui_wait_for_chars(50L, typebuf.tb_change_cnt);
+ TIME_MSG("GUI delay");
+ }
+#endif
+
+#if defined(FEAT_GUI_PHOTON) && defined(FEAT_CLIPBOARD)
+ qnx_clip_init();
+#endif
+
+#if defined(MACOS_X) && defined(FEAT_CLIPBOARD)
+ clip_init(TRUE);
+#endif
+
+#ifdef FEAT_XCLIPBOARD
+ /* Start using the X clipboard, unless the GUI was started. */
+# ifdef FEAT_GUI
+ if (!gui.in_use)
+# endif
+ {
+ setup_term_clip();
+ TIME_MSG("setup clipboard");
+ }
+#endif
+
+#ifdef FEAT_CLIENTSERVER
+ /* Prepare for being a Vim server. */
+ prepare_server(&params);
+#endif
+
+ /*
+ * If "-" argument given: Read file from stdin.
+ * Do this before starting Raw mode, because it may change things that the
+ * writing end of the pipe doesn't like, e.g., in case stdin and stderr
+ * are the same terminal: "cat | vim -".
+ * Using autocommands here may cause trouble...
+ */
+ if (params.edit_type == EDIT_STDIN && !recoverymode)
+ read_stdin();
+
+#if defined(UNIX) || defined(VMS)
+ /* When switching screens and something caused a message from a vimrc
+ * script, need to output an extra newline on exit. */
+ if ((did_emsg || msg_didout) && *T_TI != NUL)
+ newline_on_exit = TRUE;
+#endif
+
+ /*
+ * When done something that is not allowed or error message call
+ * wait_return. This must be done before starttermcap(), because it may
+ * switch to another screen. It must be done after settmode(TMODE_RAW),
+ * because we want to react on a single key stroke.
+ * Call settmode and starttermcap here, so the T_KS and T_TI may be
+ * defined by termcapinit and redefined in .exrc.
+ */
+ settmode(TMODE_RAW);
+ TIME_MSG("setting raw mode");
+
+ if (need_wait_return || msg_didany)
+ {
+ wait_return(TRUE);
+ TIME_MSG("waiting for return");
+ }
+
+ starttermcap(); /* start termcap if not done by wait_return() */
+ TIME_MSG("start termcap");
+
+#ifdef FEAT_MOUSE
+ setmouse(); /* may start using the mouse */
+#endif
+ if (scroll_region)
+ scroll_region_reset(); /* In case Rows changed */
+ scroll_start(); /* may scroll the screen to the right position */
+
+#if defined(FEAT_TITLE) && (defined(UNIX) || defined(VMS) || defined(MACOS_X))
+ term_push_title(SAVE_RESTORE_BOTH);
+#endif
+
+ /*
+ * Don't clear the screen when starting in Ex mode, unless using the GUI.
+ */
+ if (exmode_active
+#ifdef FEAT_GUI
+ && !gui.in_use
+#endif
+ )
+ must_redraw = CLEAR;
+ else
+ {
+ screenclear(); /* clear screen */
+ TIME_MSG("clearing screen");
+ }
+
+#ifdef FEAT_CRYPT
+ if (params.ask_for_key)
+ {
+ crypt_check_current_method();
+ (void)crypt_get_key(TRUE, TRUE);
+ TIME_MSG("getting crypt key");
+ }
+#endif
+
+ no_wait_return = TRUE;
+
+ /*
+ * Create the requested number of windows and edit buffers in them.
+ * Also does recovery if "recoverymode" set.
+ */
+ create_windows(&params);
+ TIME_MSG("opening buffers");
+
+#ifdef FEAT_EVAL
+ /* clear v:swapcommand */
+ set_vim_var_string(VV_SWAPCOMMAND, NULL, -1);
+#endif
+
+ /* Ex starts at last line of the file */
+ if (exmode_active)
+ curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
+
+ apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf);
+ TIME_MSG("BufEnter autocommands");
+ setpcmark();
+
+#ifdef FEAT_QUICKFIX
+ /*
+ * When started with "-q errorfile" jump to first error now.
+ */
+ if (params.edit_type == EDIT_QF)
+ {
+ qf_jump(NULL, 0, 0, FALSE);
+ TIME_MSG("jump to first error");
+ }
+#endif
+
+ /*
+ * If opened more than one window, start editing files in the other
+ * windows.
+ */
+ edit_buffers(&params, start_dir);
+ vim_free(start_dir);
+
+#ifdef FEAT_DIFF
+ if (params.diff_mode)
+ {
+ win_T *wp;
+
+ /* set options in each window for "vimdiff". */
+ FOR_ALL_WINDOWS(wp)
+ diff_win_options(wp, TRUE);
+ }
+#endif
+
+ /*
+ * Shorten any of the filenames, but only when absolute.
+ */
+ shorten_fnames(FALSE);
+
+ /*
+ * Need to jump to the tag before executing the '-c command'.
+ * Makes "vim -c '/return' -t main" work.
+ */
+ if (params.tagname != NULL)
+ {
+#if defined(HAS_SWAP_EXISTS_ACTION)
+ swap_exists_did_quit = FALSE;
+#endif
+
+ vim_snprintf((char *)IObuff, IOSIZE, "ta %s", params.tagname);
+ do_cmdline_cmd(IObuff);
+ TIME_MSG("jumping to tag");
+
+#if defined(HAS_SWAP_EXISTS_ACTION)
+ /* If the user doesn't want to edit the file then we quit here. */
+ if (swap_exists_did_quit)
+ getout(1);
+#endif
+ }
+
+ /* Execute any "+", "-c" and "-S" arguments. */
+ if (params.n_commands > 0)
+ exe_commands(&params);
+
+ /* Must come before the may_req_ calls. */
+ starting = 0;
+
+#if defined(FEAT_TERMRESPONSE)
+ /* Must be done before redrawing, puts a few characters on the screen. */
+ may_req_ambiguous_char_width();
+#endif
+
+ RedrawingDisabled = 0;
+ redraw_all_later(NOT_VALID);
+ no_wait_return = FALSE;
+
+ /* 'autochdir' has been postponed */
+ DO_AUTOCHDIR;
+
+#ifdef FEAT_TERMRESPONSE
+ /* Requesting the termresponse is postponed until here, so that a "-c q"
+ * argument doesn't make it appear in the shell Vim was started from. */
+ may_req_termresponse();
+
+ may_req_bg_color();
+#endif
+
+ /* start in insert mode */
+ if (p_im)
+ need_start_insertmode = TRUE;
+
+#ifdef FEAT_EVAL
+ set_vim_var_nr(VV_VIM_DID_ENTER, 1L);
+#endif
+ apply_autocmds(EVENT_VIMENTER, NULL, NULL, FALSE, curbuf);
+ TIME_MSG("VimEnter autocommands");
+
+#if defined(FEAT_EVAL) && defined(FEAT_CLIPBOARD)
+ /* Adjust default register name for "unnamed" in 'clipboard'. Can only be
+ * done after the clipboard is available and all initial commands that may
+ * modify the 'clipboard' setting have run; i.e. just before entering the
+ * main loop. */
+ {
+ int default_regname = 0;
+
+ adjust_clip_reg(&default_regname);
+ set_reg_var(default_regname);
+ }
+#endif
+
+#if defined(FEAT_DIFF)
+ /* When a startup script or session file setup for diff'ing and
+ * scrollbind, sync the scrollbind now. */
+ if (curwin->w_p_diff && curwin->w_p_scb)
+ {
+ update_topline();
+ check_scrollbind((linenr_T)0, 0L);
+ TIME_MSG("diff scrollbinding");
+ }
+#endif
+
+#if defined(WIN3264) && !defined(FEAT_GUI_W32)
+ mch_set_winsize_now(); /* Allow winsize changes from now on */
+#endif
+
+#if defined(FEAT_GUI)
+ /* When tab pages were created, may need to update the tab pages line and
+ * scrollbars. This is skipped while creating them. */
+ if (first_tabpage->tp_next != NULL)
+ {
+ out_flush();
+ gui_init_which_components(NULL);
+ gui_update_scrollbars(TRUE);
+ }
+ need_mouse_correct = TRUE;
+#endif
+
+ /* If ":startinsert" command used, stuff a dummy command to be able to
+ * call normal_cmd(), which will then start Insert mode. */
+ if (restart_edit != 0)
+ stuffcharReadbuff(K_NOP);
+
+#ifdef FEAT_NETBEANS_INTG
+ if (netbeansArg != NULL && strncmp("-nb", netbeansArg, 3) == 0)
+ {
+# ifdef FEAT_GUI
+# if !defined(FEAT_GUI_X11) && !defined(FEAT_GUI_GTK) \
+ && !defined(FEAT_GUI_W32)
+ if (gui.in_use)
+ {
+ mch_errmsg(_("netbeans is not supported with this GUI\n"));
+ mch_exit(2);
+ }
+# endif
+# endif
+ /* Tell the client that it can start sending commands. */
+ netbeans_open(netbeansArg + 3, TRUE);
+ }
+#endif
+
+ TIME_MSG("before starting main loop");
+
+ /*
+ * Call the main command loop. This never returns.
+ */
+ main_loop(FALSE, FALSE);
+
+#endif /* NO_VIM_MAIN */
+
+ return 0;
+}
+
+/*
+ * Initialisation shared by main() and some tests.
+ */
+ void
+common_init(mparm_T *paramp)
+{
+ cmdline_init();
+
+ (void)mb_init(); /* init mb_bytelen_tab[] to ones */
+#ifdef FEAT_EVAL
+ eval_init(); /* init global variables */
+#endif
+
+#ifdef __QNXNTO__
+ qnx_init(); /* PhAttach() for clipboard, (and gui) */
+#endif
+
+ /* Init the table of Normal mode commands. */
+ init_normal_cmds();
+
+ /*
+ * Allocate space for the generic buffers (needed for set_init_1() and
+ * emsg()).
+ */
+ if ((IObuff = alloc(IOSIZE)) == NULL
+ || (NameBuff = alloc(MAXPATHL)) == NULL)
+ mch_exit(0);
+ TIME_MSG("Allocated generic buffers");
+
+#ifdef NBDEBUG
+ /* Wait a moment for debugging NetBeans. Must be after allocating
+ * NameBuff. */
+ nbdebug_log_init("SPRO_GVIM_DEBUG", "SPRO_GVIM_DLEVEL");
+ nbdebug_wait(WT_ENV | WT_WAIT | WT_STOP, "SPRO_GVIM_WAIT", 20);
+ TIME_MSG("NetBeans debug wait");
+#endif
+
+#if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
+ /*
+ * Setup to use the current locale (for ctype() and many other things).
+ * NOTE: Translated messages with encodings other than latin1 will not
+ * work until set_init_1() has been called!
+ */
+ init_locale();
+ TIME_MSG("locale set");
+#endif
+
+#ifdef FEAT_GUI
+ gui.dofork = TRUE; /* default is to use fork() */
+#endif
+
+ /*
+ * Do a first scan of the arguments in "argv[]":
+ * -display or --display
+ * --server...
+ * --socketid
+ * --windowid
+ */
+ early_arg_scan(paramp);
+
+#if defined(FEAT_GUI)
+ /* Prepare for possibly starting GUI sometime */
+ gui_prepare(&paramp->argc, paramp->argv);
+ TIME_MSG("GUI prepared");
+#endif
+
+#ifdef FEAT_CLIPBOARD
+ clip_init(FALSE); /* Initialise clipboard stuff */
+ TIME_MSG("clipboard setup");
+#endif
+
+ /*
+ * Check if we have an interactive window.
+ * On the Amiga: If there is no window, we open one with a newcli command
+ * (needed for :! to * work). mch_check_win() will also handle the -d or
+ * -dev argument.
+ */
+ stdout_isatty = (mch_check_win(paramp->argc, paramp->argv) != FAIL);
+ TIME_MSG("window checked");
+
+ /*
+ * Allocate the first window and buffer.
+ * Can't do anything without it, exit when it fails.
+ */
+ if (win_alloc_first() == FAIL)
+ mch_exit(0);
+
+ init_yank(); /* init yank buffers */
+
+ alist_init(&global_alist); /* Init the argument list to empty. */
+ global_alist.id = 0;
+
+ /*
+ * Set the default values for the options.
+ * NOTE: Non-latin1 translated messages are working only after this,
+ * because this is where "has_mbyte" will be set, which is used by
+ * msg_outtrans_len_attr().
+ * First find out the home directory, needed to expand "~" in options.
+ */
+ init_homedir(); /* find real value of $HOME */
+ set_init_1(paramp->clean);
+ TIME_MSG("inits 1");
+
+#ifdef FEAT_EVAL
+ set_lang_var(); /* set v:lang and v:ctype */
+#endif
+
+#ifdef FEAT_SIGNS
+ init_signs();
+#endif
+}
+
+/*
+ * Return TRUE when the --not-a-term argument was found.
+ */
+ int
+is_not_a_term()
+{
+ return params.not_a_term;
+}
+
+/*
+ * Main loop: Execute Normal mode commands until exiting Vim.
+ * Also used to handle commands in the command-line window, until the window
+ * is closed.
+ * Also used to handle ":visual" command after ":global": execute Normal mode
+ * commands, return when entering Ex mode. "noexmode" is TRUE then.
+ */
+ void
+main_loop(
+ int cmdwin, /* TRUE when working in the command-line window */
+ int noexmode) /* TRUE when return on entering Ex mode */
+{
+ oparg_T oa; /* operator arguments */
+ volatile int previous_got_int = FALSE; /* "got_int" was TRUE */
+#ifdef FEAT_CONCEAL
+ /* these are static to avoid a compiler warning */
+ static linenr_T conceal_old_cursor_line = 0;
+ static linenr_T conceal_new_cursor_line = 0;
+ static int conceal_update_lines = FALSE;
+#endif
+
+#if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
+ /* Setup to catch a terminating error from the X server. Just ignore
+ * it, restore the state and continue. This might not always work
+ * properly, but at least we don't exit unexpectedly when the X server
+ * exits while Vim is running in a console. */
+ if (!cmdwin && !noexmode && SETJMP(x_jump_env))
+ {
+ State = NORMAL;
+ VIsual_active = FALSE;
+ got_int = TRUE;
+ need_wait_return = FALSE;
+ global_busy = FALSE;
+ exmode_active = 0;
+ skip_redraw = FALSE;
+ RedrawingDisabled = 0;
+ no_wait_return = 0;
+ vgetc_busy = 0;
+# ifdef FEAT_EVAL
+ emsg_skip = 0;
+# endif
+ emsg_off = 0;
+# ifdef FEAT_MOUSE
+ setmouse();
+# endif
+ settmode(TMODE_RAW);
+ starttermcap();
+ scroll_start();
+ redraw_later_clear();
+ }
+#endif
+
+ clear_oparg(&oa);
+ while (!cmdwin
+#ifdef FEAT_CMDWIN
+ || cmdwin_result == 0
+#endif
+ )
+ {
+ if (stuff_empty())
+ {
+ did_check_timestamps = FALSE;
+ if (need_check_timestamps)
+ check_timestamps(FALSE);
+ if (need_wait_return) /* if wait_return still needed ... */
+ wait_return(FALSE); /* ... call it now */
+ if (need_start_insertmode && goto_im() && !VIsual_active)
+ {
+ need_start_insertmode = FALSE;
+ stuffReadbuff((char_u *)"i"); /* start insert mode next */
+ /* skip the fileinfo message now, because it would be shown
+ * after insert mode finishes! */
+ need_fileinfo = FALSE;
+ }
+ }
+
+ /* Reset "got_int" now that we got back to the main loop. Except when
+ * inside a ":g/pat/cmd" command, then the "got_int" needs to abort
+ * the ":g" command.
+ * For ":g/pat/vi" we reset "got_int" when used once. When used
+ * a second time we go back to Ex mode and abort the ":g" command. */
+ if (got_int)
+ {
+ if (noexmode && global_busy && !exmode_active && previous_got_int)
+ {
+ /* Typed two CTRL-C in a row: go back to ex mode as if "Q" was
+ * used and keep "got_int" set, so that it aborts ":g". */
+ exmode_active = EXMODE_NORMAL;
+ State = NORMAL;
+ }
+ else if (!global_busy || !exmode_active)
+ {
+ if (!quit_more)
+ (void)vgetc(); /* flush all buffers */
+ got_int = FALSE;
+ }
+ previous_got_int = TRUE;
+ }
+ else
+ previous_got_int = FALSE;
+
+ if (!exmode_active)
+ msg_scroll = FALSE;
+ quit_more = FALSE;
+
+ /*
+ * If skip redraw is set (for ":" in wait_return()), don't redraw now.
+ * If there is nothing in the stuff_buffer or do_redraw is TRUE,
+ * update cursor and redraw.
+ */
+ if (skip_redraw || exmode_active)
+ skip_redraw = FALSE;
+ else if (do_redraw || stuff_empty())
+ {
+#ifdef FEAT_GUI
+ // If ui_breakcheck() was used a resize may have been postponed.
+ gui_may_resize_shell();
+#endif
+#ifdef HAVE_DROP_FILE
+ // If files were dropped while text was locked or the curbuf was
+ // locked, this would be a good time to handle the drop.
+ handle_any_postponed_drop();
+#endif
+#ifdef FEAT_CONCEAL
+ if (curwin->w_p_cole == 0)
+ conceal_update_lines = FALSE;
+#endif
+
+ /* Trigger CursorMoved if the cursor moved. */
+ if (!finish_op && (
+ has_cursormoved()
+#ifdef FEAT_CONCEAL
+ || curwin->w_p_cole > 0
+#endif
+ )
+ && !EQUAL_POS(last_cursormoved, curwin->w_cursor))
+ {
+ if (has_cursormoved())
+ apply_autocmds(EVENT_CURSORMOVED, NULL, NULL,
+ FALSE, curbuf);
+# ifdef FEAT_CONCEAL
+ if (curwin->w_p_cole > 0)
+ {
+ conceal_old_cursor_line = last_cursormoved.lnum;
+ conceal_new_cursor_line = curwin->w_cursor.lnum;
+ conceal_update_lines = TRUE;
+ }
+# endif
+ last_cursormoved = curwin->w_cursor;
+ }
+
+#if defined(FEAT_CONCEAL)
+ if (conceal_update_lines
+ && (conceal_old_cursor_line != conceal_new_cursor_line
+ || conceal_cursor_line(curwin)
+ || need_cursor_line_redraw))
+ {
+ if (conceal_old_cursor_line != conceal_new_cursor_line
+ && conceal_old_cursor_line != 0
+ && conceal_old_cursor_line
+ <= curbuf->b_ml.ml_line_count)
+ redrawWinline(curwin, conceal_old_cursor_line);
+ redrawWinline(curwin, conceal_new_cursor_line);
+ curwin->w_valid &= ~VALID_CROW;
+ need_cursor_line_redraw = FALSE;
+ }
+#endif
+
+ /* Trigger TextChanged if b:changedtick differs. */
+ if (!finish_op && has_textchanged()
+ && curbuf->b_last_changedtick != CHANGEDTICK(curbuf))
+ {
+ apply_autocmds(EVENT_TEXTCHANGED, NULL, NULL, FALSE, curbuf);
+ curbuf->b_last_changedtick = CHANGEDTICK(curbuf);
+ }
+
+#if defined(FEAT_DIFF)
+ // Updating diffs from changed() does not always work properly,
+ // esp. updating folds. Do an update just before redrawing if
+ // needed.
+ if (curtab->tp_diff_update || curtab->tp_diff_invalid)
+ {
+ ex_diffupdate(NULL);
+ curtab->tp_diff_update = FALSE;
+ }
+
+ /* Scroll-binding for diff mode may have been postponed until
+ * here. Avoids doing it for every change. */
+ if (diff_need_scrollbind)
+ {
+ check_scrollbind((linenr_T)0, 0L);
+ diff_need_scrollbind = FALSE;
+ }
+#endif
+#if defined(FEAT_FOLDING)
+ /* Include a closed fold completely in the Visual area. */
+ foldAdjustVisual();
+#endif
+#ifdef FEAT_FOLDING
+ /*
+ * When 'foldclose' is set, apply 'foldlevel' to folds that don't
+ * contain the cursor.
+ * When 'foldopen' is "all", open the fold(s) under the cursor.
+ * This may mark the window for redrawing.
+ */
+ if (hasAnyFolding(curwin) && !char_avail())
+ {
+ foldCheckClose();
+ if (fdo_flags & FDO_ALL)
+ foldOpenCursor();
+ }
+#endif
+
+ /*
+ * Before redrawing, make sure w_topline is correct, and w_leftcol
+ * if lines don't wrap, and w_skipcol if lines wrap.
+ */
+ update_topline();
+ validate_cursor();
+
+ if (VIsual_active)
+ update_curbuf(INVERTED);/* update inverted part */
+ else if (must_redraw)
+ {
+ mch_disable_flush(); /* Stop issuing gui_mch_flush(). */
+ update_screen(0);
+ mch_enable_flush();
+ }
+ else if (redraw_cmdline || clear_cmdline)
+ showmode();
+ redraw_statuslines();
+#ifdef FEAT_TITLE
+ if (need_maketitle)
+ maketitle();
+#endif
+#ifdef FEAT_VIMINFO
+ curbuf->b_last_used = vim_time();
+#endif
+ /* display message after redraw */
+ if (keep_msg != NULL)
+ {
+ char_u *p;
+
+ /* msg_attr_keep() will set keep_msg to NULL, must free the
+ * string here. Don't reset keep_msg, msg_attr_keep() uses it
+ * to check for duplicates. */
+ p = keep_msg;
+ msg_attr((char *)p, keep_msg_attr);
+ vim_free(p);
+ }
+ if (need_fileinfo) /* show file info after redraw */
+ {
+ fileinfo(FALSE, TRUE, FALSE);
+ need_fileinfo = FALSE;
+ }
+
+ emsg_on_display = FALSE; /* can delete error message now */
+ did_emsg = FALSE;
+ msg_didany = FALSE; /* reset lines_left in msg_start() */
+ may_clear_sb_text(); /* clear scroll-back text on next msg */
+ showruler(FALSE);
+
+ setcursor();
+ cursor_on();
+
+ do_redraw = FALSE;
+
+#ifdef STARTUPTIME
+ /* Now that we have drawn the first screen all the startup stuff
+ * has been done, close any file for startup messages. */
+ if (time_fd != NULL)
+ {
+ TIME_MSG("first screen update");
+ TIME_MSG("--- VIM STARTED ---");
+ fclose(time_fd);
+ time_fd = NULL;
+ }
+#endif
+ }
+#ifdef FEAT_GUI
+ if (need_mouse_correct)
+ gui_mouse_correct();
+#endif
+
+ /*
+ * Update w_curswant if w_set_curswant has been set.
+ * Postponed until here to avoid computing w_virtcol too often.
+ */
+ update_curswant();
+
+#ifdef FEAT_EVAL
+ /*
+ * May perform garbage collection when waiting for a character, but
+ * only at the very toplevel. Otherwise we may be using a List or
+ * Dict internally somewhere.
+ * "may_garbage_collect" is reset in vgetc() which is invoked through
+ * do_exmode() and normal_cmd().
+ */
+ may_garbage_collect = (!cmdwin && !noexmode);
+#endif
+ /*
+ * If we're invoked as ex, do a round of ex commands.
+ * Otherwise, get and execute a normal mode command.
+ */
+ if (exmode_active)
+ {
+ if (noexmode) /* End of ":global/path/visual" commands */
+ return;
+ do_exmode(exmode_active == EXMODE_VIM);
+ }
+ else
+ {
+#ifdef FEAT_TERMINAL
+ if (term_use_loop()
+ && oa.op_type == OP_NOP && oa.regname == NUL
+ && !VIsual_active
+ && !skip_term_loop)
+ {
+ /* If terminal_loop() returns OK we got a key that is handled
+ * in Normal model. With FAIL we first need to position the
+ * cursor and the screen needs to be redrawn. */
+ if (terminal_loop(TRUE) == OK)
+ normal_cmd(&oa, TRUE);
+ }
+ else
+#endif
+ {
+#ifdef FEAT_TERMINAL
+ skip_term_loop = FALSE;
+#endif
+ normal_cmd(&oa, TRUE);
+ }
+ }
+ }
+}
+
+
+#if defined(USE_XSMP) || defined(FEAT_GUI) || defined(PROTO)
+/*
+ * Exit, but leave behind swap files for modified buffers.
+ */
+ void
+getout_preserve_modified(int exitval)
+{
+# if defined(SIGHUP) && defined(SIG_IGN)
+ /* Ignore SIGHUP, because a dropped connection causes a read error, which
+ * makes Vim exit and then handling SIGHUP causes various reentrance
+ * problems. */
+ signal(SIGHUP, SIG_IGN);
+# endif
+
+ ml_close_notmod(); /* close all not-modified buffers */
+ ml_sync_all(FALSE, FALSE); /* preserve all swap files */
+ ml_close_all(FALSE); /* close all memfiles, without deleting */
+ getout(exitval); /* exit Vim properly */
+}
+#endif
+
+
+/*
+ * Exit properly.
+ */
+ void
+getout(int exitval)
+{
+ exiting = TRUE;
+#if defined(FEAT_JOB_CHANNEL)
+ ch_log(NULL, "Exiting...");
+#endif
+
+ /* When running in Ex mode an error causes us to exit with a non-zero exit
+ * code. POSIX requires this, although it's not 100% clear from the
+ * standard. */
+ if (exmode_active)
+ exitval += ex_exitval;
+
+ /* Position the cursor on the last screen line, below all the text */
+#ifdef FEAT_GUI
+ if (!gui.in_use)
+#endif
+ windgoto((int)Rows - 1, 0);
+
+#if defined(FEAT_EVAL) || defined(FEAT_SYN_HL)
+ /* Optionally print hashtable efficiency. */
+ hash_debug_results();
+#endif
+
+#ifdef FEAT_GUI
+ msg_didany = FALSE;
+#endif
+
+ if (v_dying <= 1)
+ {
+ tabpage_T *tp;
+ tabpage_T *next_tp;
+ buf_T *buf;
+ win_T *wp;
+
+ /* Trigger BufWinLeave for all windows, but only once per buffer. */
+ for (tp = first_tabpage; tp != NULL; tp = next_tp)
+ {
+ next_tp = tp->tp_next;
+ FOR_ALL_WINDOWS_IN_TAB(tp, wp)
+ {
+ if (wp->w_buffer == NULL)
+ /* Autocmd must have close the buffer already, skip. */
+ continue;
+ buf = wp->w_buffer;
+ if (CHANGEDTICK(buf) != -1)
+ {
+ bufref_T bufref;
+
+ set_bufref(&bufref, buf);
+ apply_autocmds(EVENT_BUFWINLEAVE, buf->b_fname,
+ buf->b_fname, FALSE, buf);
+ if (bufref_valid(&bufref))
+ CHANGEDTICK(buf) = -1; /* note we did it already */
+
+ /* start all over, autocommands may mess up the lists */
+ next_tp = first_tabpage;
+ break;
+ }
+ }
+ }
+
+ /* Trigger BufUnload for buffers that are loaded */
+ FOR_ALL_BUFFERS(buf)
+ if (buf->b_ml.ml_mfp != NULL)
+ {
+ bufref_T bufref;
+
+ set_bufref(&bufref, buf);
+ apply_autocmds(EVENT_BUFUNLOAD, buf->b_fname, buf->b_fname,
+ FALSE, buf);
+ if (!bufref_valid(&bufref))
+ /* autocmd deleted the buffer */
+ break;
+ }
+ apply_autocmds(EVENT_VIMLEAVEPRE, NULL, NULL, FALSE, curbuf);
+ }
+
+#ifdef FEAT_VIMINFO
+ if (*p_viminfo != NUL)
+ /* Write out the registers, history, marks etc, to the viminfo file */
+ write_viminfo(NULL, FALSE);
+#endif
+
+ if (v_dying <= 1)
+ apply_autocmds(EVENT_VIMLEAVE, NULL, NULL, FALSE, curbuf);
+
+#ifdef FEAT_PROFILE
+ profile_dump();
+#endif
+
+ if (did_emsg
+#ifdef FEAT_GUI
+ || (gui.in_use && msg_didany && p_verbose > 0)
+#endif
+ )
+ {
+ /* give the user a chance to read the (error) message */
+ no_wait_return = FALSE;
+ wait_return(FALSE);
+ }
+
+ /* Position the cursor again, the autocommands may have moved it */
+#ifdef FEAT_GUI
+ if (!gui.in_use)
+#endif
+ windgoto((int)Rows - 1, 0);
+
+#ifdef FEAT_JOB_CHANNEL
+ job_stop_on_exit();
+#endif
+#ifdef FEAT_LUA
+ lua_end();
+#endif
+#ifdef FEAT_MZSCHEME
+ mzscheme_end();
+#endif
+#ifdef FEAT_TCL
+ tcl_end();
+#endif
+#ifdef FEAT_RUBY
+ ruby_end();
+#endif
+#ifdef FEAT_PYTHON
+ python_end();
+#endif
+#ifdef FEAT_PYTHON3
+ python3_end();
+#endif
+#ifdef FEAT_PERL
+ perl_end();
+#endif
+#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
+ iconv_end();
+#endif
+#ifdef FEAT_NETBEANS_INTG
+ netbeans_end();
+#endif
+#ifdef FEAT_CSCOPE
+ cs_end();
+#endif
+#ifdef FEAT_EVAL
+ if (garbage_collect_at_exit)
+ garbage_collect(FALSE);
+#endif
+#if defined(WIN32)
+ free_cmd_argsW();
+#endif
+
+ mch_exit(exitval);
+}
+
+#if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
+/*
+ * Setup to use the current locale (for ctype() and many other things).
+ */
+ static void
+init_locale(void)
+{
+ setlocale(LC_ALL, "");
+
+# ifdef FEAT_GUI_GTK
+ /* Tell Gtk not to change our locale settings. */
+ gtk_disable_setlocale();
+# endif
+# if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
+ /* Make sure strtod() uses a decimal point, not a comma. */
+ setlocale(LC_NUMERIC, "C");
+# endif
+
+# ifdef WIN32
+ /* Apparently MS-Windows printf() may cause a crash when we give it 8-bit
+ * text while it's expecting text in the current locale. This call avoids
+ * that. */
+ setlocale(LC_CTYPE, "C");
+# endif
+
+# ifdef FEAT_GETTEXT
+ {
+ int mustfree = FALSE;
+ char_u *p;
+
+# ifdef DYNAMIC_GETTEXT
+ /* Initialize the gettext library */
+ dyn_libintl_init();
+# endif
+ /* expand_env() doesn't work yet, because g_chartab[] is not
+ * initialized yet, call vim_getenv() directly */
+ p = vim_getenv((char_u *)"VIMRUNTIME", &mustfree);
+ if (p != NULL && *p != NUL)
+ {
+ vim_snprintf((char *)NameBuff, MAXPATHL, "%s/lang", p);
+ bindtextdomain(VIMPACKAGE, (char *)NameBuff);
+ }
+ if (mustfree)
+ vim_free(p);
+ textdomain(VIMPACKAGE);
+ }
+# endif
+}
+#endif
+
+/*
+ * Get the name of the display, before gui_prepare() removes it from
+ * argv[]. Used for the xterm-clipboard display.
+ *
+ * Also find the --server... arguments and --socketid and --windowid
+ */
+ static void
+early_arg_scan(mparm_T *parmp UNUSED)
+{
+#if defined(FEAT_XCLIPBOARD) || defined(FEAT_CLIENTSERVER) \
+ || !defined(FEAT_NETBEANS_INTG)
+ int argc = parmp->argc;
+ char **argv = parmp->argv;
+ int i;
+
+ for (i = 1; i < argc; i++)
+ {
+ if (STRCMP(argv[i], "--") == 0)
+ break;
+# ifdef FEAT_XCLIPBOARD
+ else if (STRICMP(argv[i], "-display") == 0
+# if defined(FEAT_GUI_GTK)
+ || STRICMP(argv[i], "--display") == 0
+# endif
+ )
+ {
+ if (i == argc - 1)
+ mainerr_arg_missing((char_u *)argv[i]);
+ xterm_display = argv[++i];
+ }
+# endif
+# ifdef FEAT_CLIENTSERVER
+ else if (STRICMP(argv[i], "--servername") == 0)
+ {
+ if (i == argc - 1)
+ mainerr_arg_missing((char_u *)argv[i]);
+ parmp->serverName_arg = (char_u *)argv[++i];
+ }
+ else if (STRICMP(argv[i], "--serverlist") == 0)
+ parmp->serverArg = TRUE;
+ else if (STRNICMP(argv[i], "--remote", 8) == 0)
+ {
+ parmp->serverArg = TRUE;
+# ifdef FEAT_GUI
+ if (strstr(argv[i], "-wait") != 0)
+ /* don't fork() when starting the GUI to edit files ourself */
+ gui.dofork = FALSE;
+# endif
+ }
+# endif
+
+# if defined(FEAT_GUI_GTK) || defined(FEAT_GUI_W32)
+# ifdef FEAT_GUI_W32
+ else if (STRICMP(argv[i], "--windowid") == 0)
+# else
+ else if (STRICMP(argv[i], "--socketid") == 0)
+# endif
+ {
+ long_u id;
+ int count;
+
+ if (i == argc - 1)
+ mainerr_arg_missing((char_u *)argv[i]);
+ if (STRNICMP(argv[i+1], "0x", 2) == 0)
+ count = sscanf(&(argv[i + 1][2]), SCANF_HEX_LONG_U, &id);
+ else
+ count = sscanf(argv[i + 1], SCANF_DECIMAL_LONG_U, &id);
+ if (count != 1)
+ mainerr(ME_INVALID_ARG, (char_u *)argv[i]);
+ else
+# ifdef FEAT_GUI_W32
+ win_socket_id = id;
+# else
+ gtk_socket_id = id;
+# endif
+ i++;
+ }
+# endif
+# ifdef FEAT_GUI_GTK
+ else if (STRICMP(argv[i], "--echo-wid") == 0)
+ echo_wid_arg = TRUE;
+# endif
+# ifndef FEAT_NETBEANS_INTG
+ else if (strncmp(argv[i], "-nb", (size_t)3) == 0)
+ {
+ mch_errmsg(_("'-nb' cannot be used: not enabled at compile time\n"));
+ mch_exit(2);
+ }
+# endif
+
+ }
+#endif
+}
+
+#ifndef NO_VIM_MAIN
+/*
+ * Get a (optional) count for a Vim argument.
+ */
+ static int
+get_number_arg(
+ char_u *p, /* pointer to argument */
+ int *idx, /* index in argument, is incremented */
+ int def) /* default value */
+{
+ if (vim_isdigit(p[*idx]))
+ {
+ def = atoi((char *)&(p[*idx]));
+ while (vim_isdigit(p[*idx]))
+ *idx = *idx + 1;
+ }
+ return def;
+}
+
+/*
+ * Check for: [r][e][g][vi|vim|view][diff][ex[im]] (sort of)
+ * If the executable name starts with "r" we disable shell commands.
+ * If the next character is "e" we run in Easy mode.
+ * If the next character is "g" we run the GUI version.
+ * If the next characters are "view" we start in readonly mode.
+ * If the next characters are "diff" or "vimdiff" we start in diff mode.
+ * If the next characters are "ex" we start in Ex mode. If it's followed
+ * by "im" use improved Ex mode.
+ */
+ static void
+parse_command_name(mparm_T *parmp)
+{
+ char_u *initstr;
+
+ 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]);
+#endif
+
+ if (TOLOWER_ASC(initstr[0]) == 'r')
+ {
+ restricted = TRUE;
+ ++initstr;
+ }
+
+ /* Use evim mode for "evim" and "egvim", not for "editor". */
+ if (TOLOWER_ASC(initstr[0]) == 'e'
+ && (TOLOWER_ASC(initstr[1]) == 'v'
+ || TOLOWER_ASC(initstr[1]) == 'g'))
+ {
+#ifdef FEAT_GUI
+ gui.starting = TRUE;
+#endif
+ parmp->evim_mode = TRUE;
+ ++initstr;
+ }
+
+ /* "gvim" starts the GUI. Also accept "Gvim" for MS-Windows. */
+ if (TOLOWER_ASC(initstr[0]) == 'g')
+ {
+ main_start_gui();
+#ifdef FEAT_GUI
+ ++initstr;
+#endif
+ }
+
+ if (STRNICMP(initstr, "view", 4) == 0)
+ {
+ readonlymode = TRUE;
+ curbuf->b_p_ro = TRUE;
+ p_uc = 10000; /* don't update very often */
+ initstr += 4;
+ }
+ else if (STRNICMP(initstr, "vim", 3) == 0)
+ initstr += 3;
+
+ // Catch "[r][g]vimdiff" and "[r][g]viewdiff".
+ if (STRICMP(initstr, "diff") == 0)
+ {
+#ifdef FEAT_DIFF
+ parmp->diff_mode = TRUE;
+#else
+ mch_errmsg(_("This Vim was not compiled with the diff feature."));
+ mch_errmsg("\n");
+ mch_exit(2);
+#endif
+ }
+
+ // Checking for "ex" here may catch some weir names, such as "vimex" or
+ // "viewex", we assume the user knows that.
+ if (STRNICMP(initstr, "ex", 2) == 0)
+ {
+ if (STRNICMP(initstr + 2, "im", 2) == 0)
+ exmode_active = EXMODE_VIM;
+ else
+ exmode_active = EXMODE_NORMAL;
+ change_compatible(TRUE); // set 'compatible'
+ }
+}
+
+/*
+ * Scan the command line arguments.
+ */
+ static void
+command_line_scan(mparm_T *parmp)
+{
+ int argc = parmp->argc;
+ char **argv = parmp->argv;
+ int argv_idx; /* index in argv[n][] */
+ int had_minmin = FALSE; /* found "--" argument */
+ int want_argument; /* option argument with argument */
+ int c;
+ char_u *p = NULL;
+ long n;
+
+ --argc;
+ ++argv;
+ argv_idx = 1; /* active option letter is argv[0][argv_idx] */
+ while (argc > 0)
+ {
+ /*
+ * "+" or "+{number}" or "+/{pat}" or "+{command}" argument.
+ */
+ if (argv[0][0] == '+' && !had_minmin)
+ {
+ if (parmp->n_commands >= MAX_ARG_CMDS)
+ mainerr(ME_EXTRA_CMD, NULL);
+ argv_idx = -1; /* skip to next argument */
+ if (argv[0][1] == NUL)
+ parmp->commands[parmp->n_commands++] = (char_u *)"$";
+ else
+ parmp->commands[parmp->n_commands++] = (char_u *)&(argv[0][1]);
+ }
+
+ /*
+ * Optional argument.
+ */
+ else if (argv[0][0] == '-' && !had_minmin)
+ {
+ want_argument = FALSE;
+ c = argv[0][argv_idx++];
+#ifdef VMS
+ /*
+ * VMS only uses upper case command lines. Interpret "-X" as "-x"
+ * and "-/X" as "-X".
+ */
+ if (c == '/')
+ {
+ c = argv[0][argv_idx++];
+ c = TOUPPER_ASC(c);
+ }
+ else
+ c = TOLOWER_ASC(c);
+#endif
+ switch (c)
+ {
+ case NUL: /* "vim -" read from stdin */
+ /* "ex -" silent mode */
+ if (exmode_active)
+ silent_mode = TRUE;
+ else
+ {
+ if (parmp->edit_type != EDIT_NONE)
+ mainerr(ME_TOO_MANY_ARGS, (char_u *)argv[0]);
+ parmp->edit_type = EDIT_STDIN;
+ read_cmd_fd = 2; /* read from stderr instead of stdin */
+ }
+ argv_idx = -1; /* skip to next argument */
+ break;
+
+ case '-': /* "--" don't take any more option arguments */
+ /* "--help" give help message */
+ /* "--version" give version message */
+ /* "--clean" clean context */
+ /* "--literal" take files literally */
+ /* "--nofork" don't fork */
+ /* "--not-a-term" don't warn for not a term */
+ /* "--ttyfail" exit if not a term */
+ /* "--noplugin[s]" skip plugins */
+ /* "--cmd <cmd>" execute cmd before vimrc */
+ if (STRICMP(argv[0] + argv_idx, "help") == 0)
+ usage();
+ else if (STRICMP(argv[0] + argv_idx, "version") == 0)
+ {
+ Columns = 80; /* need to init Columns */
+ info_message = TRUE; /* use mch_msg(), not mch_errmsg() */
+ list_version();
+ msg_putchar('\n');
+ msg_didout = FALSE;
+ mch_exit(0);
+ }
+ else if (STRNICMP(argv[0] + argv_idx, "clean", 5) == 0)
+ {
+ parmp->use_vimrc = (char_u *)"DEFAULTS";
+#ifdef FEAT_GUI
+ use_gvimrc = (char_u *)"NONE";
+#endif
+ parmp->clean = TRUE;
+ set_option_value((char_u *)"vif", 0L, (char_u *)"NONE", 0);
+ }
+ else if (STRNICMP(argv[0] + argv_idx, "literal", 7) == 0)
+ {
+#ifdef EXPAND_FILENAMES
+ parmp->literal = TRUE;
+#endif
+ }
+ else if (STRNICMP(argv[0] + argv_idx, "nofork", 6) == 0)
+ {
+#ifdef FEAT_GUI
+ gui.dofork = FALSE; /* don't fork() when starting GUI */
+#endif
+ }
+ else if (STRNICMP(argv[0] + argv_idx, "noplugin", 8) == 0)
+ p_lpl = FALSE;
+ else if (STRNICMP(argv[0] + argv_idx, "not-a-term", 10) == 0)
+ parmp->not_a_term = TRUE;
+ else if (STRNICMP(argv[0] + argv_idx, "ttyfail", 7) == 0)
+ parmp->tty_fail = TRUE;
+ else if (STRNICMP(argv[0] + argv_idx, "cmd", 3) == 0)
+ {
+ want_argument = TRUE;
+ argv_idx += 3;
+ }
+ else if (STRNICMP(argv[0] + argv_idx, "startuptime", 11) == 0)
+ {
+ want_argument = TRUE;
+ argv_idx += 11;
+ }
+#ifdef FEAT_CLIENTSERVER
+ else if (STRNICMP(argv[0] + argv_idx, "serverlist", 10) == 0)
+ ; /* already processed -- no arg */
+ else if (STRNICMP(argv[0] + argv_idx, "servername", 10) == 0
+ || STRNICMP(argv[0] + argv_idx, "serversend", 10) == 0)
+ {
+ /* already processed -- snatch the following arg */
+ if (argc > 1)
+ {
+ --argc;
+ ++argv;
+ }
+ }
+#endif
+#if defined(FEAT_GUI_GTK) || defined(FEAT_GUI_W32)
+# ifdef FEAT_GUI_GTK
+ else if (STRNICMP(argv[0] + argv_idx, "socketid", 8) == 0)
+# else
+ else if (STRNICMP(argv[0] + argv_idx, "windowid", 8) == 0)
+# endif
+ {
+ /* already processed -- snatch the following arg */
+ if (argc > 1)
+ {
+ --argc;
+ ++argv;
+ }
+ }
+#endif
+#ifdef FEAT_GUI_GTK
+ else if (STRNICMP(argv[0] + argv_idx, "echo-wid", 8) == 0)
+ {
+ /* already processed, skip */
+ }
+#endif
+ else
+ {
+ if (argv[0][argv_idx])
+ mainerr(ME_UNKNOWN_OPTION, (char_u *)argv[0]);
+ had_minmin = TRUE;
+ }
+ if (!want_argument)
+ argv_idx = -1; /* skip to next argument */
+ break;
+
+ case 'A': /* "-A" start in Arabic mode */
+#ifdef FEAT_ARABIC
+ set_option_value((char_u *)"arabic", 1L, NULL, 0);
+#else
+ mch_errmsg(_(e_noarabic));
+ mch_exit(2);
+#endif
+ break;
+
+ case 'b': /* "-b" binary mode */
+ /* Needs to be effective before expanding file names, because
+ * for Win32 this makes us edit a shortcut file itself,
+ * instead of the file it links to. */
+ set_options_bin(curbuf->b_p_bin, 1, 0);
+ curbuf->b_p_bin = 1; /* binary file I/O */
+ break;
+
+ case 'C': /* "-C" Compatible */
+ change_compatible(TRUE);
+ has_dash_c_arg = TRUE;
+ break;
+
+ case 'e': /* "-e" Ex mode */
+ exmode_active = EXMODE_NORMAL;
+ break;
+
+ case 'E': /* "-E" Improved Ex mode */
+ exmode_active = EXMODE_VIM;
+ break;
+
+ case 'f': /* "-f" GUI: run in foreground. Amiga: open
+ window directly, not with newcli */
+#ifdef FEAT_GUI
+ gui.dofork = FALSE; /* don't fork() when starting GUI */
+#endif
+ break;
+
+ case 'g': /* "-g" start GUI */
+ main_start_gui();
+ break;
+
+ case 'F': /* "-F" start in Farsi mode: rl + fkmap set */
+#ifdef FEAT_FKMAP
+ p_fkmap = TRUE;
+ set_option_value((char_u *)"rl", 1L, NULL, 0);
+#else
+ mch_errmsg(_(e_nofarsi));
+ mch_exit(2);
+#endif
+ break;
+
+ case '?': /* "-?" give help message (for MS-Windows) */
+ case 'h': /* "-h" give help message */
+#ifdef FEAT_GUI_GNOME
+ /* Tell usage() to exit for "gvim". */
+ gui.starting = FALSE;
+#endif
+ usage();
+ break;
+
+ case 'H': /* "-H" start in Hebrew mode: rl + hkmap set */
+#ifdef FEAT_RIGHTLEFT
+ p_hkmap = TRUE;
+ set_option_value((char_u *)"rl", 1L, NULL, 0);
+#else
+ mch_errmsg(_(e_nohebrew));
+ mch_exit(2);
+#endif
+ break;
+
+ case 'l': /* "-l" lisp mode, 'lisp' and 'showmatch' on */
+#ifdef FEAT_LISP
+ set_option_value((char_u *)"lisp", 1L, NULL, 0);
+ p_sm = TRUE;
+#endif
+ break;
+
+ case 'M': /* "-M" no changes or writing of files */
+ reset_modifiable();
+ /* FALLTHROUGH */
+
+ case 'm': /* "-m" no writing of files */
+ p_write = FALSE;
+ break;
+
+ case 'y': /* "-y" easy mode */
+#ifdef FEAT_GUI
+ gui.starting = TRUE; /* start GUI a bit later */
+#endif
+ parmp->evim_mode = TRUE;
+ break;
+
+ case 'N': /* "-N" Nocompatible */
+ change_compatible(FALSE);
+ break;
+
+ case 'n': /* "-n" no swap file */
+#ifdef FEAT_NETBEANS_INTG
+ /* checking for "-nb", netbeans parameters */
+ if (argv[0][argv_idx] == 'b')
+ {
+ netbeansArg = argv[0];
+ argv_idx = -1; /* skip to next argument */
+ }
+ else
+#endif
+ parmp->no_swap_file = TRUE;
+ break;
+
+ case 'p': /* "-p[N]" open N tab pages */
+#ifdef TARGET_API_MAC_OSX
+ /* For some reason on MacOS X, an argument like:
+ -psn_0_10223617 is passed in when invoke from Finder
+ or with the 'open' command */
+ if (argv[0][argv_idx] == 's')
+ {
+ argv_idx = -1; /* bypass full -psn */
+ main_start_gui();
+ break;
+ }
+#endif
+ /* default is 0: open window for each file */
+ parmp->window_count = get_number_arg((char_u *)argv[0],
+ &argv_idx, 0);
+ parmp->window_layout = WIN_TABS;
+ break;
+
+ case 'o': /* "-o[N]" open N horizontal split windows */
+ /* default is 0: open window for each file */
+ parmp->window_count = get_number_arg((char_u *)argv[0],
+ &argv_idx, 0);
+ parmp->window_layout = WIN_HOR;
+ break;
+
+ case 'O': /* "-O[N]" open N vertical split windows */
+ /* default is 0: open window for each file */
+ parmp->window_count = get_number_arg((char_u *)argv[0],
+ &argv_idx, 0);
+ parmp->window_layout = WIN_VER;
+ break;
+
+#ifdef FEAT_QUICKFIX
+ case 'q': /* "-q" QuickFix mode */
+ if (parmp->edit_type != EDIT_NONE)
+ mainerr(ME_TOO_MANY_ARGS, (char_u *)argv[0]);
+ parmp->edit_type = EDIT_QF;
+ if (argv[0][argv_idx]) /* "-q{errorfile}" */
+ {
+ parmp->use_ef = (char_u *)argv[0] + argv_idx;
+ argv_idx = -1;
+ }
+ else if (argc > 1) /* "-q {errorfile}" */
+ want_argument = TRUE;
+ break;
+#endif
+
+ case 'R': /* "-R" readonly mode */
+ readonlymode = TRUE;
+ curbuf->b_p_ro = TRUE;
+ p_uc = 10000; /* don't update very often */
+ break;
+
+ case 'r': /* "-r" recovery mode */
+ case 'L': /* "-L" recovery mode */
+ recoverymode = 1;
+ break;
+
+ case 's':
+ if (exmode_active) /* "-s" silent (batch) mode */
+ silent_mode = TRUE;
+ else /* "-s {scriptin}" read from script file */
+ want_argument = TRUE;
+ break;
+
+ case 't': /* "-t {tag}" or "-t{tag}" jump to tag */
+ if (parmp->edit_type != EDIT_NONE)
+ mainerr(ME_TOO_MANY_ARGS, (char_u *)argv[0]);
+ parmp->edit_type = EDIT_TAG;
+ if (argv[0][argv_idx]) /* "-t{tag}" */
+ {
+ parmp->tagname = (char_u *)argv[0] + argv_idx;
+ argv_idx = -1;
+ }
+ else /* "-t {tag}" */
+ want_argument = TRUE;
+ break;
+
+#ifdef FEAT_EVAL
+ case 'D': /* "-D" Debugging */
+ parmp->use_debug_break_level = 9999;
+ break;
+#endif
+#ifdef FEAT_DIFF
+ case 'd': /* "-d" 'diff' */
+# ifdef AMIGA
+ /* check for "-dev {device}" */
+ if (argv[0][argv_idx] == 'e' && argv[0][argv_idx + 1] == 'v')
+ want_argument = TRUE;
+ else
+# endif
+ parmp->diff_mode = TRUE;
+ break;
+#endif
+ case 'V': /* "-V{N}" Verbose level */
+ /* default is 10: a little bit verbose */
+ p_verbose = get_number_arg((char_u *)argv[0], &argv_idx, 10);
+ if (argv[0][argv_idx] != NUL)
+ {
+ set_option_value((char_u *)"verbosefile", 0L,
+ (char_u *)argv[0] + argv_idx, 0);
+ argv_idx = (int)STRLEN(argv[0]);
+ }
+ break;
+
+ case 'v': /* "-v" Vi-mode (as if called "vi") */
+ exmode_active = 0;
+#ifdef FEAT_GUI
+ gui.starting = FALSE; /* don't start GUI */
+#endif
+ break;
+
+ case 'w': /* "-w{number}" set window height */
+ /* "-w {scriptout}" write to script */
+ if (vim_isdigit(((char_u *)argv[0])[argv_idx]))
+ {
+ n = get_number_arg((char_u *)argv[0], &argv_idx, 10);
+ set_option_value((char_u *)"window", n, NULL, 0);
+ break;
+ }
+ want_argument = TRUE;
+ break;
+
+#ifdef FEAT_CRYPT
+ case 'x': /* "-x" encrypted reading/writing of files */
+ parmp->ask_for_key = TRUE;
+ break;
+#endif
+
+ case 'X': /* "-X" don't connect to X server */
+#if (defined(UNIX) || defined(VMS)) && defined(FEAT_X11)
+ x_no_connect = TRUE;
+#endif
+ break;
+
+ case 'Z': /* "-Z" restricted mode */
+ restricted = TRUE;
+ break;
+
+ case 'c': /* "-c{command}" or "-c {command}" execute
+ command */
+ if (argv[0][argv_idx] != NUL)
+ {
+ if (parmp->n_commands >= MAX_ARG_CMDS)
+ mainerr(ME_EXTRA_CMD, NULL);
+ parmp->commands[parmp->n_commands++] = (char_u *)argv[0]
+ + argv_idx;
+ argv_idx = -1;
+ break;
+ }
+ /* FALLTHROUGH */
+ case 'S': /* "-S {file}" execute Vim script */
+ case 'i': /* "-i {viminfo}" use for viminfo */
+#ifndef FEAT_DIFF
+ case 'd': /* "-d {device}" device (for Amiga) */
+#endif
+ case 'T': /* "-T {terminal}" terminal name */
+ case 'u': /* "-u {vimrc}" vim inits file */
+ case 'U': /* "-U {gvimrc}" gvim inits file */
+ case 'W': /* "-W {scriptout}" overwrite */
+#ifdef FEAT_GUI_W32
+ case 'P': /* "-P {parent title}" MDI parent */
+#endif
+ want_argument = TRUE;
+ break;
+
+ default:
+ mainerr(ME_UNKNOWN_OPTION, (char_u *)argv[0]);
+ }
+
+ /*
+ * Handle option arguments with argument.
+ */
+ if (want_argument)
+ {
+ /*
+ * Check for garbage immediately after the option letter.
+ */
+ if (argv[0][argv_idx] != NUL)
+ mainerr(ME_GARBAGE, (char_u *)argv[0]);
+
+ --argc;
+ if (argc < 1 && c != 'S') /* -S has an optional argument */
+ mainerr_arg_missing((char_u *)argv[0]);
+ ++argv;
+ argv_idx = -1;
+
+ switch (c)
+ {
+ case 'c': /* "-c {command}" execute command */
+ case 'S': /* "-S {file}" execute Vim script */
+ if (parmp->n_commands >= MAX_ARG_CMDS)
+ mainerr(ME_EXTRA_CMD, NULL);
+ if (c == 'S')
+ {
+ char *a;
+
+ if (argc < 1)
+ /* "-S" without argument: use default session file
+ * name. */
+ a = SESSION_FILE;
+ else if (argv[0][0] == '-')
+ {
+ /* "-S" followed by another option: use default
+ * session file name. */
+ a = SESSION_FILE;
+ ++argc;
+ --argv;
+ }
+ else
+ a = argv[0];
+ p = alloc((unsigned)(STRLEN(a) + 4));
+ if (p == NULL)
+ mch_exit(2);
+ sprintf((char *)p, "so %s", a);
+ parmp->cmds_tofree[parmp->n_commands] = TRUE;
+ parmp->commands[parmp->n_commands++] = p;
+ }
+ else
+ parmp->commands[parmp->n_commands++] =
+ (char_u *)argv[0];
+ break;
+
+ case '-':
+ if (argv[-1][2] == 'c')
+ {
+ /* "--cmd {command}" execute command */
+ if (parmp->n_pre_commands >= MAX_ARG_CMDS)
+ mainerr(ME_EXTRA_CMD, NULL);
+ parmp->pre_commands[parmp->n_pre_commands++] =
+ (char_u *)argv[0];
+ }
+ /* "--startuptime <file>" already handled */
+ break;
+
+ /* case 'd': -d {device} is handled in mch_check_win() for the
+ * Amiga */
+
+#ifdef FEAT_QUICKFIX
+ case 'q': /* "-q {errorfile}" QuickFix mode */
+ parmp->use_ef = (char_u *)argv[0];
+ break;
+#endif
+
+ case 'i': /* "-i {viminfo}" use for viminfo */
+ set_option_value((char_u *)"vif", 0L, (char_u *)argv[0], 0);
+ break;
+
+ case 's': /* "-s {scriptin}" read from script file */
+ if (scriptin[0] != NULL)
+ {
+scripterror:
+ mch_errmsg(_("Attempt to open script file again: \""));
+ mch_errmsg(argv[-1]);
+ mch_errmsg(" ");
+ mch_errmsg(argv[0]);
+ mch_errmsg("\"\n");
+ mch_exit(2);
+ }
+ if ((scriptin[0] = mch_fopen(argv[0], READBIN)) == NULL)
+ {
+ mch_errmsg(_("Cannot open for reading: \""));
+ mch_errmsg(argv[0]);
+ mch_errmsg("\"\n");
+ mch_exit(2);
+ }
+ if (save_typebuf() == FAIL)
+ mch_exit(2); /* out of memory */
+ break;
+
+ case 't': /* "-t {tag}" */
+ parmp->tagname = (char_u *)argv[0];
+ break;
+
+ case 'T': /* "-T {terminal}" terminal name */
+ /*
+ * The -T term argument is always available and when
+ * HAVE_TERMLIB is supported it overrides the environment
+ * variable TERM.
+ */
+#ifdef FEAT_GUI
+ if (term_is_gui((char_u *)argv[0]))
+ gui.starting = TRUE; /* start GUI a bit later */
+ else
+#endif
+ parmp->term = (char_u *)argv[0];
+ break;
+
+ case 'u': /* "-u {vimrc}" vim inits file */
+ parmp->use_vimrc = (char_u *)argv[0];
+ break;
+
+ case 'U': /* "-U {gvimrc}" gvim inits file */
+#ifdef FEAT_GUI
+ use_gvimrc = (char_u *)argv[0];
+#endif
+ break;
+
+ case 'w': /* "-w {nr}" 'window' value */
+ /* "-w {scriptout}" append to script file */
+ if (vim_isdigit(*((char_u *)argv[0])))
+ {
+ argv_idx = 0;
+ n = get_number_arg((char_u *)argv[0], &argv_idx, 10);
+ set_option_value((char_u *)"window", n, NULL, 0);
+ argv_idx = -1;
+ break;
+ }
+ /* FALLTHROUGH */
+ case 'W': /* "-W {scriptout}" overwrite script file */
+ if (scriptout != NULL)
+ goto scripterror;
+ if ((scriptout = mch_fopen(argv[0],
+ c == 'w' ? APPENDBIN : WRITEBIN)) == NULL)
+ {
+ mch_errmsg(_("Cannot open for script output: \""));
+ mch_errmsg(argv[0]);
+ mch_errmsg("\"\n");
+ mch_exit(2);
+ }
+ break;
+
+#ifdef FEAT_GUI_W32
+ case 'P': /* "-P {parent title}" MDI parent */
+ gui_mch_set_parent(argv[0]);
+ break;
+#endif
+ }
+ }
+ }
+
+ /*
+ * File name argument.
+ */
+ else
+ {
+ argv_idx = -1; /* skip to next argument */
+
+ /* Check for only one type of editing. */
+ if (parmp->edit_type != EDIT_NONE && parmp->edit_type != EDIT_FILE)
+ mainerr(ME_TOO_MANY_ARGS, (char_u *)argv[0]);
+ parmp->edit_type = EDIT_FILE;
+
+#ifdef MSWIN
+ /* Remember if the argument was a full path before changing
+ * slashes to backslashes. */
+ if (argv[0][0] != NUL && argv[0][1] == ':' && argv[0][2] == '\\')
+ parmp->full_path = TRUE;
+#endif
+
+ /* Add the file to the global argument list. */
+ if (ga_grow(&global_alist.al_ga, 1) == FAIL
+ || (p = vim_strsave((char_u *)argv[0])) == NULL)
+ mch_exit(2);
+#ifdef FEAT_DIFF
+ if (parmp->diff_mode && mch_isdir(p) && GARGCOUNT > 0
+ && !mch_isdir(alist_name(&GARGLIST[0])))
+ {
+ char_u *r;
+
+ r = concat_fnames(p, gettail(alist_name(&GARGLIST[0])), TRUE);
+ if (r != NULL)
+ {
+ vim_free(p);
+ p = r;
+ }
+ }
+#endif
+#if defined(__CYGWIN32__) && !defined(WIN32)
+ /*
+ * If vim is invoked by non-Cygwin tools, convert away any
+ * DOS paths, so things like .swp files are created correctly.
+ * Look for evidence of non-Cygwin paths before we bother.
+ * This is only for when using the Unix files.
+ */
+ if (vim_strpbrk(p, "\\:") != NULL && !path_with_url(p))
+ {
+ char posix_path[MAXPATHL];
+
+# if CYGWIN_VERSION_DLL_MAJOR >= 1007
+ cygwin_conv_path(CCP_WIN_A_TO_POSIX, p, posix_path, MAXPATHL);
+# else
+ cygwin_conv_to_posix_path(p, posix_path);
+# endif
+ vim_free(p);
+ p = vim_strsave((char_u *)posix_path);
+ if (p == NULL)
+ mch_exit(2);
+ }
+#endif
+
+#ifdef USE_FNAME_CASE
+ /* Make the case of the file name match the actual file. */
+ fname_case(p, 0);
+#endif
+
+ alist_add(&global_alist, p,
+#ifdef EXPAND_FILENAMES
+ parmp->literal ? 2 : 0 /* add buffer nr after exp. */
+#else
+ 2 /* add buffer number now and use curbuf */
+#endif
+ );
+
+#if defined(WIN32)
+ {
+ /* Remember this argument has been added to the argument list.
+ * Needed when 'encoding' is changed. */
+ used_file_arg(argv[0], parmp->literal, parmp->full_path,
+# ifdef FEAT_DIFF
+ parmp->diff_mode
+# else
+ FALSE
+# endif
+ );
+ }
+#endif
+ }
+
+ /*
+ * If there are no more letters after the current "-", go to next
+ * argument. argv_idx is set to -1 when the current argument is to be
+ * skipped.
+ */
+ if (argv_idx <= 0 || argv[0][argv_idx] == NUL)
+ {
+ --argc;
+ ++argv;
+ argv_idx = 1;
+ }
+ }
+
+#ifdef FEAT_EVAL
+ /* If there is a "+123" or "-c" command, set v:swapcommand to the first
+ * one. */
+ if (parmp->n_commands > 0)
+ {
+ p = alloc((unsigned)STRLEN(parmp->commands[0]) + 3);
+ if (p != NULL)
+ {
+ sprintf((char *)p, ":%s\r", parmp->commands[0]);
+ set_vim_var_string(VV_SWAPCOMMAND, p, -1);
+ vim_free(p);
+ }
+ }
+#endif
+}
+
+/*
+ * Print a warning if stdout is not a terminal.
+ * When starting in Ex mode and commands come from a file, set silent_mode.
+ */
+ static void
+check_tty(mparm_T *parmp)
+{
+ int input_isatty; /* is active input a terminal? */
+
+ input_isatty = mch_input_isatty();
+ if (exmode_active)
+ {
+ if (!input_isatty)
+ silent_mode = TRUE;
+ }
+ else if (parmp->want_full_screen && (!stdout_isatty || !input_isatty)
+#ifdef FEAT_GUI
+ /* don't want the delay when started from the desktop */
+ && !gui.starting
+#endif
+ && !parmp->not_a_term)
+ {
+#ifdef NBDEBUG
+ /*
+ * This shouldn't be necessary. But if I run netbeans with the log
+ * output coming to the console and XOpenDisplay fails, I get vim
+ * trying to start with input/output to my console tty. This fills my
+ * input buffer so fast I can't even kill the process in under 2
+ * minutes (and it beeps continuously the whole time :-)
+ */
+ if (netbeans_active() && (!stdout_isatty || !input_isatty))
+ {
+ mch_errmsg(_("Vim: Error: Failure to start gvim from NetBeans\n"));
+ exit(1);
+ }
+#endif
+#if defined(WIN3264) && !defined(FEAT_GUI_W32)
+ if (is_cygpty_used())
+ {
+# if defined(HAVE_BIND_TEXTDOMAIN_CODESET) \
+ && defined(FEAT_GETTEXT)
+ char *s, *tofree = NULL;
+
+ /* Set the encoding of the error message based on $LC_ALL or
+ * other environment variables instead of 'encoding'.
+ * Note that the message is shown on a Cygwin terminal (e.g.
+ * mintty) which encoding is based on $LC_ALL or etc., not the
+ * current codepage used by normal Win32 console programs. */
+ tofree = s = (char *)enc_locale_env(NULL);
+ if (s == NULL)
+ s = "utf-8"; /* Use "utf-8" by default. */
+ (void)bind_textdomain_codeset(VIMPACKAGE, s);
+ vim_free(tofree);
+# endif
+ mch_errmsg(_("Vim: Error: This version of Vim does not run in a Cygwin terminal\n"));
+ exit(1);
+ }
+#endif
+ if (!stdout_isatty)
+ mch_errmsg(_("Vim: Warning: Output is not to a terminal\n"));
+ if (!input_isatty)
+ mch_errmsg(_("Vim: Warning: Input is not from a terminal\n"));
+ out_flush();
+ if (parmp->tty_fail && (!stdout_isatty || !input_isatty))
+ exit(1);
+ if (scriptin[0] == NULL)
+ ui_delay(2000L, TRUE);
+ TIME_MSG("Warning delay");
+ }
+}
+
+/*
+ * Read text from stdin.
+ */
+ static void
+read_stdin(void)
+{
+ int i;
+
+#if defined(HAS_SWAP_EXISTS_ACTION)
+ /* When getting the ATTENTION prompt here, use a dialog */
+ swap_exists_action = SEA_DIALOG;
+#endif
+ no_wait_return = TRUE;
+ i = msg_didany;
+ set_buflisted(TRUE);
+ (void)open_buffer(TRUE, NULL, 0); /* create memfile and read file */
+ no_wait_return = FALSE;
+ msg_didany = i;
+ TIME_MSG("reading stdin");
+#if defined(HAS_SWAP_EXISTS_ACTION)
+ check_swap_exists_action();
+#endif
+#if !(defined(AMIGA) || defined(MACOS_X))
+ /*
+ * Close stdin and dup it from stderr. Required for GPM to work
+ * properly, and for running external commands.
+ * Is there any other system that cannot do this?
+ */
+ close(0);
+ vim_ignored = dup(2);
+#endif
+}
+
+/*
+ * Create the requested number of windows and edit buffers in them.
+ * Also does recovery if "recoverymode" set.
+ */
+ static void
+create_windows(mparm_T *parmp UNUSED)
+{
+ int dorewind;
+ int done = 0;
+
+ /*
+ * Create the number of windows that was requested.
+ */
+ if (parmp->window_count == -1) /* was not set */
+ parmp->window_count = 1;
+ if (parmp->window_count == 0)
+ parmp->window_count = GARGCOUNT;
+ if (parmp->window_count > 1)
+ {
+ /* Don't change the windows if there was a command in .vimrc that
+ * already split some windows */
+ if (parmp->window_layout == 0)
+ parmp->window_layout = WIN_HOR;
+ if (parmp->window_layout == WIN_TABS)
+ {
+ parmp->window_count = make_tabpages(parmp->window_count);
+ TIME_MSG("making tab pages");
+ }
+ else if (firstwin->w_next == NULL)
+ {
+ parmp->window_count = make_windows(parmp->window_count,
+ parmp->window_layout == WIN_VER);
+ TIME_MSG("making windows");
+ }
+ else
+ parmp->window_count = win_count();
+ }
+ else
+ parmp->window_count = 1;
+
+ if (recoverymode) /* do recover */
+ {
+ msg_scroll = TRUE; /* scroll message up */
+ ml_recover();
+ if (curbuf->b_ml.ml_mfp == NULL) /* failed */
+ getout(1);
+ do_modelines(0); /* do modelines */
+ }
+ else
+ {
+ /*
+ * Open a buffer for windows that don't have one yet.
+ * Commands in the .vimrc might have loaded a file or split the window.
+ * Watch out for autocommands that delete a window.
+ */
+ /*
+ * Don't execute Win/Buf Enter/Leave autocommands here
+ */
+ ++autocmd_no_enter;
+ ++autocmd_no_leave;
+ dorewind = TRUE;
+ while (done++ < 1000)
+ {
+ if (dorewind)
+ {
+ if (parmp->window_layout == WIN_TABS)
+ goto_tabpage(1);
+ else
+ curwin = firstwin;
+ }
+ else if (parmp->window_layout == WIN_TABS)
+ {
+ if (curtab->tp_next == NULL)
+ break;
+ goto_tabpage(0);
+ }
+ else
+ {
+ if (curwin->w_next == NULL)
+ break;
+ curwin = curwin->w_next;
+ }
+ dorewind = FALSE;
+ curbuf = curwin->w_buffer;
+ if (curbuf->b_ml.ml_mfp == NULL)
+ {
+#ifdef FEAT_FOLDING
+ /* Set 'foldlevel' to 'foldlevelstart' if it's not negative. */
+ if (p_fdls >= 0)
+ curwin->w_p_fdl = p_fdls;
+#endif
+#if defined(HAS_SWAP_EXISTS_ACTION)
+ /* When getting the ATTENTION prompt here, use a dialog */
+ swap_exists_action = SEA_DIALOG;
+#endif
+ set_buflisted(TRUE);
+
+ /* create memfile, read file */
+ (void)open_buffer(FALSE, NULL, 0);
+
+#if defined(HAS_SWAP_EXISTS_ACTION)
+ if (swap_exists_action == SEA_QUIT)
+ {
+ if (got_int || only_one_window())
+ {
+ /* abort selected or quit and only one window */
+ did_emsg = FALSE; /* avoid hit-enter prompt */
+ getout(1);
+ }
+ /* We can't close the window, it would disturb what
+ * happens next. Clear the file name and set the arg
+ * index to -1 to delete it later. */
+ setfname(curbuf, NULL, NULL, FALSE);
+ curwin->w_arg_idx = -1;
+ swap_exists_action = SEA_NONE;
+ }
+ else
+ handle_swap_exists(NULL);
+#endif
+ dorewind = TRUE; /* start again */
+ }
+ ui_breakcheck();
+ if (got_int)
+ {
+ (void)vgetc(); /* only break the file loading, not the rest */
+ break;
+ }
+ }
+ if (parmp->window_layout == WIN_TABS)
+ goto_tabpage(1);
+ else
+ curwin = firstwin;
+ curbuf = curwin->w_buffer;
+ --autocmd_no_enter;
+ --autocmd_no_leave;
+ }
+}
+
+ /*
+ * If opened more than one window, start editing files in the other
+ * windows. make_windows() has already opened the windows.
+ */
+ static void
+edit_buffers(
+ mparm_T *parmp,
+ char_u *cwd) /* current working dir */
+{
+ int arg_idx; /* index in argument list */
+ int i;
+ int advance = TRUE;
+ win_T *win;
+
+ /*
+ * Don't execute Win/Buf Enter/Leave autocommands here
+ */
+ ++autocmd_no_enter;
+ ++autocmd_no_leave;
+
+ /* When w_arg_idx is -1 remove the window (see create_windows()). */
+ if (curwin->w_arg_idx == -1)
+ {
+ win_close(curwin, TRUE);
+ advance = FALSE;
+ }
+
+ arg_idx = 1;
+ for (i = 1; i < parmp->window_count; ++i)
+ {
+ if (cwd != NULL)
+ mch_chdir((char *)cwd);
+ /* When w_arg_idx is -1 remove the window (see create_windows()). */
+ if (curwin->w_arg_idx == -1)
+ {
+ ++arg_idx;
+ win_close(curwin, TRUE);
+ advance = FALSE;
+ continue;
+ }
+
+ if (advance)
+ {
+ if (parmp->window_layout == WIN_TABS)
+ {
+ if (curtab->tp_next == NULL) /* just checking */
+ break;
+ goto_tabpage(0);
+ }
+ else
+ {
+ if (curwin->w_next == NULL) /* just checking */
+ break;
+ win_enter(curwin->w_next, FALSE);
+ }
+ }
+ advance = TRUE;
+
+ /* Only open the file if there is no file in this window yet (that can
+ * happen when .vimrc contains ":sall"). */
+ if (curbuf == firstwin->w_buffer || curbuf->b_ffname == NULL)
+ {
+ curwin->w_arg_idx = arg_idx;
+ /* Edit file from arg list, if there is one. When "Quit" selected
+ * at the ATTENTION prompt close the window. */
+# ifdef HAS_SWAP_EXISTS_ACTION
+ swap_exists_did_quit = FALSE;
+# endif
+ (void)do_ecmd(0, arg_idx < GARGCOUNT
+ ? alist_name(&GARGLIST[arg_idx]) : NULL,
+ NULL, NULL, ECMD_LASTL, ECMD_HIDE, curwin);
+# ifdef HAS_SWAP_EXISTS_ACTION
+ if (swap_exists_did_quit)
+ {
+ /* abort or quit selected */
+ if (got_int || only_one_window())
+ {
+ /* abort selected and only one window */
+ did_emsg = FALSE; /* avoid hit-enter prompt */
+ getout(1);
+ }
+ win_close(curwin, TRUE);
+ advance = FALSE;
+ }
+# endif
+ if (arg_idx == GARGCOUNT - 1)
+ arg_had_last = TRUE;
+ ++arg_idx;
+ }
+ ui_breakcheck();
+ if (got_int)
+ {
+ (void)vgetc(); /* only break the file loading, not the rest */
+ break;
+ }
+ }
+
+ if (parmp->window_layout == WIN_TABS)
+ goto_tabpage(1);
+ --autocmd_no_enter;
+
+ /* make the first window the current window */
+ win = firstwin;
+#if defined(FEAT_QUICKFIX)
+ /* Avoid making a preview window the current window. */
+ while (win->w_p_pvw)
+ {
+ win = win->w_next;
+ if (win == NULL)
+ {
+ win = firstwin;
+ break;
+ }
+ }
+#endif
+ win_enter(win, FALSE);
+
+ --autocmd_no_leave;
+ TIME_MSG("editing files in windows");
+ if (parmp->window_count > 1 && parmp->window_layout != WIN_TABS)
+ win_equal(curwin, FALSE, 'b'); /* adjust heights */
+}
+
+/*
+ * Execute the commands from --cmd arguments "cmds[cnt]".
+ */
+ static void
+exe_pre_commands(mparm_T *parmp)
+{
+ char_u **cmds = parmp->pre_commands;
+ int cnt = parmp->n_pre_commands;
+ int i;
+
+ if (cnt > 0)
+ {
+ curwin->w_cursor.lnum = 0; /* just in case.. */
+ sourcing_name = (char_u *)_("pre-vimrc command line");
+# ifdef FEAT_EVAL
+ current_sctx.sc_sid = SID_CMDARG;
+# endif
+ for (i = 0; i < cnt; ++i)
+ do_cmdline_cmd(cmds[i]);
+ sourcing_name = NULL;
+# ifdef FEAT_EVAL
+ current_sctx.sc_sid = 0;
+# endif
+ TIME_MSG("--cmd commands");
+ }
+}
+
+/*
+ * Execute "+", "-c" and "-S" arguments.
+ */
+ static void
+exe_commands(mparm_T *parmp)
+{
+ int i;
+
+ /*
+ * We start commands on line 0, make "vim +/pat file" match a
+ * pattern on line 1. But don't move the cursor when an autocommand
+ * with g`" was used.
+ */
+ msg_scroll = TRUE;
+ if (parmp->tagname == NULL && curwin->w_cursor.lnum <= 1)
+ curwin->w_cursor.lnum = 0;
+ sourcing_name = (char_u *)"command line";
+#ifdef FEAT_EVAL
+ current_sctx.sc_sid = SID_CARG;
+ current_sctx.sc_seq = 0;
+#endif
+ for (i = 0; i < parmp->n_commands; ++i)
+ {
+ do_cmdline_cmd(parmp->commands[i]);
+ if (parmp->cmds_tofree[i])
+ vim_free(parmp->commands[i]);
+ }
+ sourcing_name = NULL;
+#ifdef FEAT_EVAL
+ current_sctx.sc_sid = 0;
+#endif
+ if (curwin->w_cursor.lnum == 0)
+ curwin->w_cursor.lnum = 1;
+
+ if (!exmode_active)
+ msg_scroll = FALSE;
+
+#ifdef FEAT_QUICKFIX
+ /* When started with "-q errorfile" jump to first error again. */
+ if (parmp->edit_type == EDIT_QF)
+ qf_jump(NULL, 0, 0, FALSE);
+#endif
+ TIME_MSG("executing command arguments");
+}
+
+/*
+ * Source startup scripts.
+ */
+ static void
+source_startup_scripts(mparm_T *parmp)
+{
+ int i;
+
+ /*
+ * For "evim" source evim.vim first of all, so that the user can overrule
+ * any things he doesn't like.
+ */
+ if (parmp->evim_mode)
+ {
+ (void)do_source((char_u *)EVIM_FILE, FALSE, DOSO_NONE);
+ TIME_MSG("source evim file");
+ }
+
+ /*
+ * If -u argument given, use only the initializations from that file and
+ * nothing else.
+ */
+ if (parmp->use_vimrc != NULL)
+ {
+ if (STRCMP(parmp->use_vimrc, "DEFAULTS") == 0)
+ do_source((char_u *)VIM_DEFAULTS_FILE, FALSE, DOSO_NONE);
+ else if (STRCMP(parmp->use_vimrc, "NONE") == 0
+ || STRCMP(parmp->use_vimrc, "NORC") == 0)
+ {
+#ifdef FEAT_GUI
+ if (use_gvimrc == NULL) /* don't load gvimrc either */
+ use_gvimrc = parmp->use_vimrc;
+#endif
+ }
+ else
+ {
+ if (do_source(parmp->use_vimrc, FALSE, DOSO_NONE) != OK)
+ semsg(_("E282: Cannot read from \"%s\""), parmp->use_vimrc);
+ }
+ }
+ else if (!silent_mode)
+ {
+#ifdef AMIGA
+ struct Process *proc = (struct Process *)FindTask(0L);
+ APTR save_winptr = proc->pr_WindowPtr;
+
+ /* Avoid a requester here for a volume that doesn't exist. */
+ proc->pr_WindowPtr = (APTR)-1L;
+#endif
+
+ /*
+ * Get system wide defaults, if the file name is defined.
+ */
+#ifdef SYS_VIMRC_FILE
+ (void)do_source((char_u *)SYS_VIMRC_FILE, FALSE, DOSO_NONE);
+#endif
+#ifdef MACOS_X
+ (void)do_source((char_u *)"$VIMRUNTIME/macmap.vim", FALSE, DOSO_NONE);
+#endif
+
+ /*
+ * Try to read initialization commands from the following places:
+ * - environment variable VIMINIT
+ * - user vimrc file (s:.vimrc for Amiga, ~/.vimrc otherwise)
+ * - second user vimrc file ($VIM/.vimrc for Dos)
+ * - environment variable EXINIT
+ * - user exrc file (s:.exrc for Amiga, ~/.exrc otherwise)
+ * - second user exrc file ($VIM/.exrc for Dos)
+ * The first that exists is used, the rest is ignored.
+ */
+ if (process_env((char_u *)"VIMINIT", TRUE) != OK)
+ {
+ if (do_source((char_u *)USR_VIMRC_FILE, TRUE, DOSO_VIMRC) == FAIL
+#ifdef USR_VIMRC_FILE2
+ && do_source((char_u *)USR_VIMRC_FILE2, TRUE,
+ DOSO_VIMRC) == FAIL
+#endif
+#ifdef USR_VIMRC_FILE3
+ && do_source((char_u *)USR_VIMRC_FILE3, TRUE,
+ DOSO_VIMRC) == FAIL
+#endif
+#ifdef USR_VIMRC_FILE4
+ && do_source((char_u *)USR_VIMRC_FILE4, TRUE,
+ DOSO_VIMRC) == FAIL
+#endif
+ && process_env((char_u *)"EXINIT", FALSE) == FAIL
+ && do_source((char_u *)USR_EXRC_FILE, FALSE, DOSO_NONE) == FAIL
+#ifdef USR_EXRC_FILE2
+ && do_source((char_u *)USR_EXRC_FILE2, FALSE, DOSO_NONE) == FAIL
+#endif
+ && !has_dash_c_arg)
+ {
+ /* When no .vimrc file was found: source defaults.vim. */
+ do_source((char_u *)VIM_DEFAULTS_FILE, FALSE, DOSO_NONE);
+ }
+ }
+
+ /*
+ * Read initialization commands from ".vimrc" or ".exrc" in current
+ * directory. This is only done if the 'exrc' option is set.
+ * Because of security reasons we disallow shell and write commands
+ * now, except for Unix if the file is owned by the user or 'secure'
+ * option has been reset in environment of global ".exrc" or ".vimrc".
+ * Only do this if VIMRC_FILE is not the same as USR_VIMRC_FILE or
+ * SYS_VIMRC_FILE.
+ */
+ if (p_exrc)
+ {
+#if defined(UNIX) || defined(VMS)
+ /* If ".vimrc" file is not owned by user, set 'secure' mode. */
+ if (!file_owned(VIMRC_FILE))
+#endif
+ secure = p_secure;
+
+ i = FAIL;
+ if (fullpathcmp((char_u *)USR_VIMRC_FILE,
+ (char_u *)VIMRC_FILE, FALSE) != FPC_SAME
+#ifdef USR_VIMRC_FILE2
+ && fullpathcmp((char_u *)USR_VIMRC_FILE2,
+ (char_u *)VIMRC_FILE, FALSE) != FPC_SAME
+#endif
+#ifdef USR_VIMRC_FILE3
+ && fullpathcmp((char_u *)USR_VIMRC_FILE3,
+ (char_u *)VIMRC_FILE, FALSE) != FPC_SAME
+#endif
+#ifdef SYS_VIMRC_FILE
+ && fullpathcmp((char_u *)SYS_VIMRC_FILE,
+ (char_u *)VIMRC_FILE, FALSE) != FPC_SAME
+#endif
+ )
+ i = do_source((char_u *)VIMRC_FILE, TRUE, DOSO_VIMRC);
+
+ if (i == FAIL)
+ {
+#if defined(UNIX) || defined(VMS)
+ /* if ".exrc" is not owned by user set 'secure' mode */
+ if (!file_owned(EXRC_FILE))
+ secure = p_secure;
+ else
+ secure = 0;
+#endif
+ if ( fullpathcmp((char_u *)USR_EXRC_FILE,
+ (char_u *)EXRC_FILE, FALSE) != FPC_SAME
+#ifdef USR_EXRC_FILE2
+ && fullpathcmp((char_u *)USR_EXRC_FILE2,
+ (char_u *)EXRC_FILE, FALSE) != FPC_SAME
+#endif
+ )
+ (void)do_source((char_u *)EXRC_FILE, FALSE, DOSO_NONE);
+ }
+ }
+ if (secure == 2)
+ need_wait_return = TRUE;
+ secure = 0;
+#ifdef AMIGA
+ proc->pr_WindowPtr = save_winptr;
+#endif
+ }
+ TIME_MSG("sourcing vimrc file(s)");
+}
+
+/*
+ * Setup to start using the GUI. Exit with an error when not available.
+ */
+ static void
+main_start_gui(void)
+{
+#ifdef FEAT_GUI
+ gui.starting = TRUE; /* start GUI a bit later */
+#else
+ mch_errmsg(_(e_nogvim));
+ mch_errmsg("\n");
+ mch_exit(2);
+#endif
+}
+
+#endif /* NO_VIM_MAIN */
+
+/*
+ * Get an environment variable, and execute it as Ex commands.
+ * Returns FAIL if the environment variable was not executed, OK otherwise.
+ */
+ int
+process_env(
+ char_u *env,
+ int is_viminit) /* when TRUE, called for VIMINIT */
+{
+ char_u *initstr;
+ char_u *save_sourcing_name;
+ linenr_T save_sourcing_lnum;
+#ifdef FEAT_EVAL
+ sctx_T save_current_sctx;
+#endif
+
+ if ((initstr = mch_getenv(env)) != NULL && *initstr != NUL)
+ {
+ if (is_viminit)
+ vimrc_found(NULL, NULL);
+ save_sourcing_name = sourcing_name;
+ save_sourcing_lnum = sourcing_lnum;
+ sourcing_name = env;
+ sourcing_lnum = 0;
+#ifdef FEAT_EVAL
+ save_current_sctx = current_sctx;
+ current_sctx.sc_sid = SID_ENV;
+ current_sctx.sc_seq = 0;
+ current_sctx.sc_lnum = 0;
+#endif
+ do_cmdline_cmd(initstr);
+ sourcing_name = save_sourcing_name;
+ sourcing_lnum = save_sourcing_lnum;
+#ifdef FEAT_EVAL
+ current_sctx = save_current_sctx;
+#endif
+ return OK;
+ }
+ return FAIL;
+}
+
+#if (defined(UNIX) || defined(VMS)) && !defined(NO_VIM_MAIN)
+/*
+ * Return TRUE if we are certain the user owns the file "fname".
+ * Used for ".vimrc" and ".exrc".
+ * Use both stat() and lstat() for extra security.
+ */
+ static int
+file_owned(char *fname)
+{
+ stat_T s;
+# ifdef UNIX
+ uid_t uid = getuid();
+# else /* VMS */
+ uid_t uid = ((getgid() << 16) | getuid());
+# endif
+
+ return !(mch_stat(fname, &s) != 0 || s.st_uid != uid
+# ifdef HAVE_LSTAT
+ || mch_lstat(fname, &s) != 0 || s.st_uid != uid
+# endif
+ );
+}
+#endif
+
+/*
+ * Give an error message main_errors["n"] and exit.
+ */
+ static void
+mainerr(
+ int n, /* one of the ME_ defines */
+ char_u *str) /* extra argument or NULL */
+{
+#if defined(UNIX) || defined(VMS)
+ reset_signals(); /* kill us with CTRL-C here, if you like */
+#endif
+
+ init_longVersion();
+ mch_errmsg(longVersion);
+ mch_errmsg("\n");
+ mch_errmsg(_(main_errors[n]));
+ if (str != NULL)
+ {
+ mch_errmsg(": \"");
+ mch_errmsg((char *)str);
+ mch_errmsg("\"");
+ }
+ mch_errmsg(_("\nMore info with: \"vim -h\"\n"));
+
+ mch_exit(1);
+}
+
+ void
+mainerr_arg_missing(char_u *str)
+{
+ mainerr(ME_ARG_MISSING, str);
+}
+
+#ifndef NO_VIM_MAIN
+/*
+ * print a message with three spaces prepended and '\n' appended.
+ */
+ static void
+main_msg(char *s)
+{
+ mch_msg(" ");
+ mch_msg(s);
+ mch_msg("\n");
+}
+
+/*
+ * Print messages for "vim -h" or "vim --help" and exit.
+ */
+ static void
+usage(void)
+{
+ int i;
+ static char *(use[]) =
+ {
+ N_("[file ..] edit specified file(s)"),
+ N_("- read text from stdin"),
+ N_("-t tag edit file where tag is defined"),
+#ifdef FEAT_QUICKFIX
+ N_("-q [errorfile] edit file with first error")
+#endif
+ };
+
+#if defined(UNIX) || defined(VMS)
+ reset_signals(); /* kill us with CTRL-C here, if you like */
+#endif
+
+ init_longVersion();
+ mch_msg(longVersion);
+ mch_msg(_("\n\nUsage:"));
+ for (i = 0; ; ++i)
+ {
+ mch_msg(_(" vim [arguments] "));
+ mch_msg(_(use[i]));
+ if (i == (sizeof(use) / sizeof(char_u *)) - 1)
+ break;
+ mch_msg(_("\n or:"));
+ }
+#ifdef VMS
+ mch_msg(_("\nWhere case is ignored prepend / to make flag upper case"));
+#endif
+
+ mch_msg(_("\n\nArguments:\n"));
+ main_msg(_("--\t\t\tOnly file names after this"));
+#ifdef EXPAND_FILENAMES
+ main_msg(_("--literal\t\tDon't expand wildcards"));
+#endif
+#ifdef FEAT_OLE
+ main_msg(_("-register\t\tRegister this gvim for OLE"));
+ main_msg(_("-unregister\t\tUnregister gvim for OLE"));
+#endif
+#ifdef FEAT_GUI
+ main_msg(_("-g\t\t\tRun using GUI (like \"gvim\")"));
+ main_msg(_("-f or --nofork\tForeground: Don't fork when starting GUI"));
+#endif
+ main_msg(_("-v\t\t\tVi mode (like \"vi\")"));
+ main_msg(_("-e\t\t\tEx mode (like \"ex\")"));
+ main_msg(_("-E\t\t\tImproved Ex mode"));
+ main_msg(_("-s\t\t\tSilent (batch) mode (only for \"ex\")"));
+#ifdef FEAT_DIFF
+ main_msg(_("-d\t\t\tDiff mode (like \"vimdiff\")"));
+#endif
+ main_msg(_("-y\t\t\tEasy mode (like \"evim\", modeless)"));
+ main_msg(_("-R\t\t\tReadonly mode (like \"view\")"));
+ main_msg(_("-Z\t\t\tRestricted mode (like \"rvim\")"));
+ main_msg(_("-m\t\t\tModifications (writing files) not allowed"));
+ main_msg(_("-M\t\t\tModifications in text not allowed"));
+ main_msg(_("-b\t\t\tBinary mode"));
+#ifdef FEAT_LISP
+ main_msg(_("-l\t\t\tLisp mode"));
+#endif
+ main_msg(_("-C\t\t\tCompatible with Vi: 'compatible'"));
+ main_msg(_("-N\t\t\tNot fully Vi compatible: 'nocompatible'"));
+ main_msg(_("-V[N][fname]\t\tBe verbose [level N] [log messages to fname]"));
+#ifdef FEAT_EVAL
+ main_msg(_("-D\t\t\tDebugging mode"));
+#endif
+ main_msg(_("-n\t\t\tNo swap file, use memory only"));
+ main_msg(_("-r\t\t\tList swap files and exit"));
+ main_msg(_("-r (with file name)\tRecover crashed session"));
+ main_msg(_("-L\t\t\tSame as -r"));
+#ifdef AMIGA
+ main_msg(_("-f\t\t\tDon't use newcli to open window"));
+ main_msg(_("-dev <device>\t\tUse <device> for I/O"));
+#endif
+#ifdef FEAT_ARABIC
+ main_msg(_("-A\t\t\tStart in Arabic mode"));
+#endif
+#ifdef FEAT_RIGHTLEFT
+ main_msg(_("-H\t\t\tStart in Hebrew mode"));
+#endif
+#ifdef FEAT_FKMAP
+ main_msg(_("-F\t\t\tStart in Farsi mode"));
+#endif
+ main_msg(_("-T <terminal>\tSet terminal type to <terminal>"));
+ main_msg(_("--not-a-term\t\tSkip warning for input/output not being a terminal"));
+ main_msg(_("--ttyfail\t\tExit if input or output is not a terminal"));
+ main_msg(_("-u <vimrc>\t\tUse <vimrc> instead of any .vimrc"));
+#ifdef FEAT_GUI
+ main_msg(_("-U <gvimrc>\t\tUse <gvimrc> instead of any .gvimrc"));
+#endif
+ main_msg(_("--noplugin\t\tDon't load plugin scripts"));
+ main_msg(_("-p[N]\t\tOpen N tab pages (default: one for each file)"));
+ main_msg(_("-o[N]\t\tOpen N windows (default: one for each file)"));
+ main_msg(_("-O[N]\t\tLike -o but split vertically"));
+ main_msg(_("+\t\t\tStart at end of file"));
+ main_msg(_("+<lnum>\t\tStart at line <lnum>"));
+ main_msg(_("--cmd <command>\tExecute <command> before loading any vimrc file"));
+ main_msg(_("-c <command>\t\tExecute <command> after loading the first file"));
+ main_msg(_("-S <session>\t\tSource file <session> after loading the first file"));
+ main_msg(_("-s <scriptin>\tRead Normal mode commands from file <scriptin>"));
+ main_msg(_("-w <scriptout>\tAppend all typed commands to file <scriptout>"));
+ main_msg(_("-W <scriptout>\tWrite all typed commands to file <scriptout>"));
+#ifdef FEAT_CRYPT
+ main_msg(_("-x\t\t\tEdit encrypted files"));
+#endif
+#if (defined(UNIX) || defined(VMS)) && defined(FEAT_X11)
+# if defined(FEAT_GUI_X11) && !defined(FEAT_GUI_GTK)
+ main_msg(_("-display <display>\tConnect vim to this particular X-server"));
+# endif
+ main_msg(_("-X\t\t\tDo not connect to X server"));
+#endif
+#ifdef FEAT_CLIENTSERVER
+ main_msg(_("--remote <files>\tEdit <files> in a Vim server if possible"));
+ main_msg(_("--remote-silent <files> Same, don't complain if there is no server"));
+ main_msg(_("--remote-wait <files> As --remote but wait for files to have been edited"));
+ main_msg(_("--remote-wait-silent <files> Same, don't complain if there is no server"));
+ main_msg(_("--remote-tab[-wait][-silent] <files> As --remote but use tab page per file"));
+ main_msg(_("--remote-send <keys>\tSend <keys> to a Vim server and exit"));
+ main_msg(_("--remote-expr <expr>\tEvaluate <expr> in a Vim server and print result"));
+ main_msg(_("--serverlist\t\tList available Vim server names and exit"));
+ main_msg(_("--servername <name>\tSend to/become the Vim server <name>"));
+#endif
+#ifdef STARTUPTIME
+ main_msg(_("--startuptime <file>\tWrite startup timing messages to <file>"));
+#endif
+#ifdef FEAT_VIMINFO
+ main_msg(_("-i <viminfo>\t\tUse <viminfo> instead of .viminfo"));
+#endif
+ main_msg(_("--clean\t\t'nocompatible', Vim defaults, no plugins, no viminfo"));
+ main_msg(_("-h or --help\tPrint Help (this message) and exit"));
+ main_msg(_("--version\t\tPrint version information and exit"));
+
+#ifdef FEAT_GUI_X11
+# ifdef FEAT_GUI_MOTIF
+ mch_msg(_("\nArguments recognised by gvim (Motif version):\n"));
+# else
+# ifdef FEAT_GUI_ATHENA
+# ifdef FEAT_GUI_NEXTAW
+ mch_msg(_("\nArguments recognised by gvim (neXtaw version):\n"));
+# else
+ mch_msg(_("\nArguments recognised by gvim (Athena version):\n"));
+# endif
+# endif
+# endif
+ main_msg(_("-display <display>\tRun vim on <display>"));
+ main_msg(_("-iconic\t\tStart vim iconified"));
+ main_msg(_("-background <color>\tUse <color> for the background (also: -bg)"));
+ main_msg(_("-foreground <color>\tUse <color> for normal text (also: -fg)"));
+ main_msg(_("-font <font>\t\tUse <font> for normal text (also: -fn)"));
+ main_msg(_("-boldfont <font>\tUse <font> for bold text"));
+ main_msg(_("-italicfont <font>\tUse <font> for italic text"));
+ main_msg(_("-geometry <geom>\tUse <geom> for initial geometry (also: -geom)"));
+ main_msg(_("-borderwidth <width>\tUse a border width of <width> (also: -bw)"));
+ main_msg(_("-scrollbarwidth <width> Use a scrollbar width of <width> (also: -sw)"));
+# ifdef FEAT_GUI_ATHENA
+ main_msg(_("-menuheight <height>\tUse a menu bar height of <height> (also: -mh)"));
+# endif
+ main_msg(_("-reverse\t\tUse reverse video (also: -rv)"));
+ main_msg(_("+reverse\t\tDon't use reverse video (also: +rv)"));
+ main_msg(_("-xrm <resource>\tSet the specified resource"));
+#endif /* FEAT_GUI_X11 */
+#ifdef FEAT_GUI_GTK
+ mch_msg(_("\nArguments recognised by gvim (GTK+ version):\n"));
+ main_msg(_("-font <font>\t\tUse <font> for normal text (also: -fn)"));
+ main_msg(_("-geometry <geom>\tUse <geom> for initial geometry (also: -geom)"));
+ main_msg(_("-reverse\t\tUse reverse video (also: -rv)"));
+ main_msg(_("-display <display>\tRun vim on <display> (also: --display)"));
+ main_msg(_("--role <role>\tSet a unique role to identify the main window"));
+ main_msg(_("--socketid <xid>\tOpen Vim inside another GTK widget"));
+ main_msg(_("--echo-wid\t\tMake gvim echo the Window ID on stdout"));
+#endif
+#ifdef FEAT_GUI_W32
+ main_msg(_("-P <parent title>\tOpen Vim inside parent application"));
+ main_msg(_("--windowid <HWND>\tOpen Vim inside another win32 widget"));
+#endif
+
+#ifdef FEAT_GUI_GNOME
+ /* Gnome gives extra messages for --help if we continue, but not for -h. */
+ if (gui.starting)
+ {
+ mch_msg("\n");
+ gui.dofork = FALSE;
+ }
+ else
+#endif
+ mch_exit(0);
+}
+
+#if defined(HAS_SWAP_EXISTS_ACTION)
+/*
+ * Check the result of the ATTENTION dialog:
+ * When "Quit" selected, exit Vim.
+ * When "Recover" selected, recover the file.
+ */
+ static void
+check_swap_exists_action(void)
+{
+ if (swap_exists_action == SEA_QUIT)
+ getout(1);
+ handle_swap_exists(NULL);
+}
+#endif
+
+#endif /* NO_VIM_MAIN */
+
+#if defined(STARTUPTIME) || defined(PROTO)
+static struct timeval prev_timeval;
+
+# ifdef WIN3264
+/*
+ * Windows doesn't have gettimeofday(), although it does have struct timeval.
+ */
+ static int
+gettimeofday(struct timeval *tv, char *dummy)
+{
+ long t = clock();
+ tv->tv_sec = t / CLOCKS_PER_SEC;
+ tv->tv_usec = (t - tv->tv_sec * CLOCKS_PER_SEC) * 1000000 / CLOCKS_PER_SEC;
+ return 0;
+}
+# endif
+
+/*
+ * Save the previous time before doing something that could nest.
+ * set "*tv_rel" to the time elapsed so far.
+ */
+ void
+time_push(void *tv_rel, void *tv_start)
+{
+ *((struct timeval *)tv_rel) = prev_timeval;
+ gettimeofday(&prev_timeval, NULL);
+ ((struct timeval *)tv_rel)->tv_usec = prev_timeval.tv_usec
+ - ((struct timeval *)tv_rel)->tv_usec;
+ ((struct timeval *)tv_rel)->tv_sec = prev_timeval.tv_sec
+ - ((struct timeval *)tv_rel)->tv_sec;
+ if (((struct timeval *)tv_rel)->tv_usec < 0)
+ {
+ ((struct timeval *)tv_rel)->tv_usec += 1000000;
+ --((struct timeval *)tv_rel)->tv_sec;
+ }
+ *(struct timeval *)tv_start = prev_timeval;
+}
+
+/*
+ * Compute the previous time after doing something that could nest.
+ * Subtract "*tp" from prev_timeval;
+ * Note: The arguments are (void *) to avoid trouble with systems that don't
+ * have struct timeval.
+ */
+ void
+time_pop(
+ void *tp) /* actually (struct timeval *) */
+{
+ prev_timeval.tv_usec -= ((struct timeval *)tp)->tv_usec;
+ prev_timeval.tv_sec -= ((struct timeval *)tp)->tv_sec;
+ if (prev_timeval.tv_usec < 0)
+ {
+ prev_timeval.tv_usec += 1000000;
+ --prev_timeval.tv_sec;
+ }
+}
+
+ static void
+time_diff(struct timeval *then, struct timeval *now)
+{
+ long usec;
+ long msec;
+
+ usec = now->tv_usec - then->tv_usec;
+ msec = (now->tv_sec - then->tv_sec) * 1000L + usec / 1000L,
+ usec = usec % 1000L;
+ fprintf(time_fd, "%03ld.%03ld", msec, usec >= 0 ? usec : usec + 1000L);
+}
+
+ void
+time_msg(
+ char *mesg,
+ void *tv_start) /* only for do_source: start time; actually
+ (struct timeval *) */
+{
+ static struct timeval start;
+ struct timeval now;
+
+ if (time_fd != NULL)
+ {
+ if (strstr(mesg, "STARTING") != NULL)
+ {
+ gettimeofday(&start, NULL);
+ prev_timeval = start;
+ fprintf(time_fd, "\n\ntimes in msec\n");
+ fprintf(time_fd, " clock self+sourced self: sourced script\n");
+ fprintf(time_fd, " clock elapsed: other lines\n\n");
+ }
+ gettimeofday(&now, NULL);
+ time_diff(&start, &now);
+ if (((struct timeval *)tv_start) != NULL)
+ {
+ fprintf(time_fd, " ");
+ time_diff(((struct timeval *)tv_start), &now);
+ }
+ fprintf(time_fd, " ");
+ time_diff(&prev_timeval, &now);
+ prev_timeval = now;
+ fprintf(time_fd, ": %s\n", mesg);
+ }
+}
+
+#endif
+
+#if !defined(NO_VIM_MAIN) && defined(FEAT_EVAL)
+ static void
+set_progpath(char_u *argv0)
+{
+ char_u *val = argv0;
+
+# if defined(WIN32)
+ /* A relative path containing a "/" will become invalid when using ":cd",
+ * turn it into a full path.
+ * On MS-Windows "vim" should be expanded to "vim.exe", thus always do
+ * this. */
+ char_u *path = NULL;
+
+ if (mch_can_exe(argv0, &path, FALSE) && path != NULL)
+ val = path;
+# else
+ char_u buf[MAXPATHL + 1];
+# ifdef PROC_EXE_LINK
+ char linkbuf[MAXPATHL + 1];
+ ssize_t len;
+
+ len = readlink(PROC_EXE_LINK, linkbuf, MAXPATHL);
+ if (len > 0)
+ {
+ linkbuf[len] = NUL;
+ val = (char_u *)linkbuf;
+ }
+# endif
+
+ if (!mch_isFullName(val))
+ {
+ if (gettail(val) != val
+ && vim_FullName(val, buf, MAXPATHL, TRUE) != FAIL)
+ val = buf;
+ }
+# endif
+
+ set_vim_var_string(VV_PROGPATH, val, -1);
+
+# ifdef WIN32
+ vim_free(path);
+# endif
+}
+
+#endif /* NO_VIM_MAIN */
+
+#if (defined(FEAT_CLIENTSERVER) && !defined(NO_VIM_MAIN)) || defined(PROTO)
+
+/*
+ * Common code for the X command server and the Win32 command server.
+ */
+
+static char_u *build_drop_cmd(int filec, char **filev, int tabs, int sendReply);
+
+/*
+ * Do the client-server stuff, unless "--servername ''" was used.
+ */
+ static void
+exec_on_server(mparm_T *parmp)
+{
+ if (parmp->serverName_arg == NULL || *parmp->serverName_arg != NUL)
+ {
+# ifdef WIN32
+ /* Initialise the client/server messaging infrastructure. */
+ serverInitMessaging();
+# endif
+
+ /*
+ * When a command server argument was found, execute it. This may
+ * exit Vim when it was successful. Otherwise it's executed further
+ * on. Remember the encoding used here in "serverStrEnc".
+ */
+ if (parmp->serverArg)
+ {
+ cmdsrv_main(&parmp->argc, parmp->argv,
+ parmp->serverName_arg, &parmp->serverStr);
+ parmp->serverStrEnc = vim_strsave(p_enc);
+ }
+
+ /* If we're still running, get the name to register ourselves.
+ * On Win32 can register right now, for X11 need to setup the
+ * clipboard first, it's further down. */
+ parmp->servername = serverMakeName(parmp->serverName_arg,
+ parmp->argv[0]);
+# ifdef WIN32
+ if (parmp->servername != NULL)
+ {
+ serverSetName(parmp->servername);
+ vim_free(parmp->servername);
+ }
+# endif
+ }
+}
+
+/*
+ * Prepare for running as a Vim server.
+ */
+ static void
+prepare_server(mparm_T *parmp)
+{
+# if defined(FEAT_X11)
+ /*
+ * Register for remote command execution with :serversend and --remote
+ * unless there was a -X or a --servername '' on the command line.
+ * Only register nongui-vim's with an explicit --servername argument,
+ * or when compiling with autoservername.
+ * When running as root --servername is also required.
+ */
+ if (X_DISPLAY != NULL && parmp->servername != NULL && (
+# if defined(FEAT_AUTOSERVERNAME) || defined(FEAT_GUI)
+ (
+# if defined(FEAT_AUTOSERVERNAME)
+ 1
+# else
+ gui.in_use
+# endif
+# ifdef UNIX
+ && getuid() != ROOT_UID
+# endif
+ ) ||
+# endif
+ parmp->serverName_arg != NULL))
+ {
+ (void)serverRegisterName(X_DISPLAY, parmp->servername);
+ vim_free(parmp->servername);
+ TIME_MSG("register server name");
+ }
+ else
+ serverDelayedStartName = parmp->servername;
+# endif
+
+ /*
+ * Execute command ourselves if we're here because the send failed (or
+ * else we would have exited above).
+ */
+ if (parmp->serverStr != NULL)
+ {
+ char_u *p;
+
+ server_to_input_buf(serverConvert(parmp->serverStrEnc,
+ parmp->serverStr, &p));
+ vim_free(p);
+ }
+}
+
+ static void
+cmdsrv_main(
+ int *argc,
+ char **argv,
+ char_u *serverName_arg,
+ char_u **serverStr)
+{
+ char_u *res;
+ int i;
+ char_u *sname;
+ int ret;
+ int didone = FALSE;
+ int exiterr = 0;
+ char **newArgV = argv + 1;
+ int newArgC = 1,
+ Argc = *argc;
+ int argtype;
+#define ARGTYPE_OTHER 0
+#define ARGTYPE_EDIT 1
+#define ARGTYPE_EDIT_WAIT 2
+#define ARGTYPE_SEND 3
+ int silent = FALSE;
+ int tabs = FALSE;
+# ifndef FEAT_X11
+ HWND srv;
+# else
+ Window srv;
+
+ setup_term_clip();
+# endif
+
+ sname = serverMakeName(serverName_arg, argv[0]);
+ if (sname == NULL)
+ return;
+
+ /*
+ * Execute the command server related arguments and remove them
+ * from the argc/argv array; We may have to return into main()
+ */
+ for (i = 1; i < Argc; i++)
+ {
+ res = NULL;
+ if (STRCMP(argv[i], "--") == 0) /* end of option arguments */
+ {
+ for (; i < *argc; i++)
+ {
+ *newArgV++ = argv[i];
+ newArgC++;
+ }
+ break;
+ }
+
+ if (STRICMP(argv[i], "--remote-send") == 0)
+ argtype = ARGTYPE_SEND;
+ else if (STRNICMP(argv[i], "--remote", 8) == 0)
+ {
+ char *p = argv[i] + 8;
+
+ argtype = ARGTYPE_EDIT;
+ while (*p != NUL)
+ {
+ if (STRNICMP(p, "-wait", 5) == 0)
+ {
+ argtype = ARGTYPE_EDIT_WAIT;
+ p += 5;
+ }
+ else if (STRNICMP(p, "-silent", 7) == 0)
+ {
+ silent = TRUE;
+ p += 7;
+ }
+ else if (STRNICMP(p, "-tab", 4) == 0)
+ {
+ tabs = TRUE;
+ p += 4;
+ }
+ else
+ {
+ argtype = ARGTYPE_OTHER;
+ break;
+ }
+ }
+ }
+ else
+ argtype = ARGTYPE_OTHER;
+
+ if (argtype != ARGTYPE_OTHER)
+ {
+ if (i == *argc - 1)
+ mainerr_arg_missing((char_u *)argv[i]);
+ if (argtype == ARGTYPE_SEND)
+ {
+ *serverStr = (char_u *)argv[i + 1];
+ i++;
+ }
+ else
+ {
+ *serverStr = build_drop_cmd(*argc - i - 1, argv + i + 1,
+ tabs, argtype == ARGTYPE_EDIT_WAIT);
+ if (*serverStr == NULL)
+ {
+ /* Probably out of memory, exit. */
+ didone = TRUE;
+ exiterr = 1;
+ break;
+ }
+ Argc = i;
+ }
+# ifdef FEAT_X11
+ if (xterm_dpy == NULL)
+ {
+ mch_errmsg(_("No display"));
+ ret = -1;
+ }
+ else
+ ret = serverSendToVim(xterm_dpy, sname, *serverStr,
+ NULL, &srv, 0, 0, 0, silent);
+# else
+ /* Win32 always works? */
+ ret = serverSendToVim(sname, *serverStr, NULL, &srv, 0, 0, silent);
+# endif
+ if (ret < 0)
+ {
+ if (argtype == ARGTYPE_SEND)
+ {
+ /* Failed to send, abort. */
+ mch_errmsg(_(": Send failed.\n"));
+ didone = TRUE;
+ exiterr = 1;
+ }
+ else if (!silent)
+ /* Let vim start normally. */
+ mch_errmsg(_(": Send failed. Trying to execute locally\n"));
+ break;
+ }
+
+# ifdef FEAT_GUI_W32
+ /* Guess that when the server name starts with "g" it's a GUI
+ * server, which we can bring to the foreground here.
+ * Foreground() in the server doesn't work very well. */
+ if (argtype != ARGTYPE_SEND && TOUPPER_ASC(*sname) == 'G')
+ SetForegroundWindow(srv);
+# endif
+
+ /*
+ * For --remote-wait: Wait until the server did edit each
+ * file. Also detect that the server no longer runs.
+ */
+ if (ret >= 0 && argtype == ARGTYPE_EDIT_WAIT)
+ {
+ int numFiles = *argc - i - 1;
+ int j;
+ char_u *done = alloc(numFiles);
+ char_u *p;
+# ifdef FEAT_GUI_W32
+ NOTIFYICONDATA ni;
+ int count = 0;
+ extern HWND message_window;
+# endif
+
+ if (numFiles > 0 && argv[i + 1][0] == '+')
+ /* Skip "+cmd" argument, don't wait for it to be edited. */
+ --numFiles;
+
+# ifdef FEAT_GUI_W32
+ ni.cbSize = sizeof(ni);
+ ni.hWnd = message_window;
+ ni.uID = 0;
+ ni.uFlags = NIF_ICON|NIF_TIP;
+ ni.hIcon = LoadIcon((HINSTANCE)GetModuleHandle(0), "IDR_VIM");
+ sprintf(ni.szTip, _("%d of %d edited"), count, numFiles);
+ Shell_NotifyIcon(NIM_ADD, &ni);
+# endif
+
+ /* Wait for all files to unload in remote */
+ vim_memset(done, 0, numFiles);
+ while (memchr(done, 0, numFiles) != NULL)
+ {
+# ifdef WIN32
+ p = serverGetReply(srv, NULL, TRUE, TRUE, 0);
+ if (p == NULL)
+ break;
+# else
+ if (serverReadReply(xterm_dpy, srv, &p, TRUE, -1) < 0)
+ break;
+# endif
+ j = atoi((char *)p);
+ if (j >= 0 && j < numFiles)
+ {
+# ifdef FEAT_GUI_W32
+ ++count;
+ sprintf(ni.szTip, _("%d of %d edited"),
+ count, numFiles);
+ Shell_NotifyIcon(NIM_MODIFY, &ni);
+# endif
+ done[j] = 1;
+ }
+ }
+# ifdef FEAT_GUI_W32
+ Shell_NotifyIcon(NIM_DELETE, &ni);
+# endif
+ }
+ }
+ else if (STRICMP(argv[i], "--remote-expr") == 0)
+ {
+ if (i == *argc - 1)
+ mainerr_arg_missing((char_u *)argv[i]);
+# ifdef WIN32
+ /* Win32 always works? */
+ if (serverSendToVim(sname, (char_u *)argv[i + 1],
+ &res, NULL, 1, 0, FALSE) < 0)
+# else
+ if (xterm_dpy == NULL)
+ mch_errmsg(_("No display: Send expression failed.\n"));
+ else if (serverSendToVim(xterm_dpy, sname, (char_u *)argv[i + 1],
+ &res, NULL, 1, 0, 1, FALSE) < 0)
+# endif
+ {
+ if (res != NULL && *res != NUL)
+ {
+ /* Output error from remote */
+ mch_errmsg((char *)res);
+ VIM_CLEAR(res);
+ }
+ mch_errmsg(_(": Send expression failed.\n"));
+ }
+ }
+ else if (STRICMP(argv[i], "--serverlist") == 0)
+ {
+# ifdef WIN32
+ /* Win32 always works? */
+ res = serverGetVimNames();
+# else
+ if (xterm_dpy != NULL)
+ res = serverGetVimNames(xterm_dpy);
+# endif
+ if (called_emsg)
+ mch_errmsg("\n");
+ }
+ else if (STRICMP(argv[i], "--servername") == 0)
+ {
+ /* Already processed. Take it out of the command line */
+ i++;
+ continue;
+ }
+ else
+ {
+ *newArgV++ = argv[i];
+ newArgC++;
+ continue;
+ }
+ didone = TRUE;
+ if (res != NULL && *res != NUL)
+ {
+ mch_msg((char *)res);
+ if (res[STRLEN(res) - 1] != '\n')
+ mch_msg("\n");
+ }
+ vim_free(res);
+ }
+
+ if (didone)
+ {
+ display_errors(); /* display any collected messages */
+ exit(exiterr); /* Mission accomplished - get out */
+ }
+
+ /* Return back into main() */
+ *argc = newArgC;
+ vim_free(sname);
+}
+
+/*
+ * Build a ":drop" command to send to a Vim server.
+ */
+ static char_u *
+build_drop_cmd(
+ int filec,
+ char **filev,
+ int tabs, /* Use ":tab drop" instead of ":drop". */
+ int sendReply)
+{
+ garray_T ga;
+ int i;
+ char_u *inicmd = NULL;
+ char_u *p;
+ char_u *cdp;
+ char_u *cwd;
+
+ if (filec > 0 && filev[0][0] == '+')
+ {
+ inicmd = (char_u *)filev[0] + 1;
+ filev++;
+ filec--;
+ }
+ /* Check if we have at least one argument. */
+ if (filec <= 0)
+ mainerr_arg_missing((char_u *)filev[-1]);
+
+ /* Temporarily cd to the current directory to handle relative file names. */
+ cwd = alloc(MAXPATHL);
+ if (cwd == NULL)
+ return NULL;
+ if (mch_dirname(cwd, MAXPATHL) != OK)
+ {
+ vim_free(cwd);
+ return NULL;
+ }
+ cdp = vim_strsave_escaped_ext(cwd,
+#ifdef BACKSLASH_IN_FILENAME
+ (char_u *)"", /* rem_backslash() will tell what chars to escape */
+#else
+ PATH_ESC_CHARS,
+#endif
+ '\\', TRUE);
+ vim_free(cwd);
+ if (cdp == NULL)
+ return NULL;
+ ga_init2(&ga, 1, 100);
+ ga_concat(&ga, (char_u *)"<C-\\><C-N>:cd ");
+ ga_concat(&ga, cdp);
+
+ /* Call inputsave() so that a prompt for an encryption key works. */
+ ga_concat(&ga, (char_u *)"<CR>:if exists('*inputsave')|call inputsave()|endif|");
+ if (tabs)
+ ga_concat(&ga, (char_u *)"tab ");
+ ga_concat(&ga, (char_u *)"drop");
+ for (i = 0; i < filec; i++)
+ {
+ /* On Unix the shell has already expanded the wildcards, don't want to
+ * do it again in the Vim server. On MS-Windows only escape
+ * non-wildcard characters. */
+ p = vim_strsave_escaped((char_u *)filev[i],
+#ifdef UNIX
+ PATH_ESC_CHARS
+#else
+ (char_u *)" \t%#"
+#endif
+ );
+ if (p == NULL)
+ {
+ vim_free(ga.ga_data);
+ return NULL;
+ }
+ ga_concat(&ga, (char_u *)" ");
+ ga_concat(&ga, p);
+ vim_free(p);
+ }
+ ga_concat(&ga, (char_u *)"|if exists('*inputrestore')|call inputrestore()|endif<CR>");
+
+ /* The :drop commands goes to Insert mode when 'insertmode' is set, use
+ * CTRL-\ CTRL-N again. */
+ ga_concat(&ga, (char_u *)"<C-\\><C-N>");
+
+ /* Switch back to the correct current directory (prior to temporary path
+ * switch) unless 'autochdir' is set, in which case it will already be
+ * correct after the :drop command. With line breaks and spaces:
+ * if !exists('+acd') || !&acd
+ * if haslocaldir()
+ * cd -
+ * lcd -
+ * elseif getcwd() ==# 'current path'
+ * cd -
+ * endif
+ * endif
+ */
+ ga_concat(&ga, (char_u *)":if !exists('+acd')||!&acd|if haslocaldir()|");
+ ga_concat(&ga, (char_u *)"cd -|lcd -|elseif getcwd() ==# '");
+ ga_concat(&ga, cdp);
+ ga_concat(&ga, (char_u *)"'|cd -|endif|endif<CR>");
+ vim_free(cdp);
+
+ if (sendReply)
+ ga_concat(&ga, (char_u *)":call SetupRemoteReplies()<CR>");
+ ga_concat(&ga, (char_u *)":");
+ if (inicmd != NULL)
+ {
+ /* Can't use <CR> after "inicmd", because an "startinsert" would cause
+ * the following commands to be inserted as text. Use a "|",
+ * hopefully "inicmd" does allow this... */
+ ga_concat(&ga, inicmd);
+ ga_concat(&ga, (char_u *)"|");
+ }
+ /* Bring the window to the foreground, goto Insert mode when 'im' set and
+ * clear command line. */
+ ga_concat(&ga, (char_u *)"cal foreground()|if &im|star|en|redr|f<CR>");
+ ga_append(&ga, NUL);
+ return ga.ga_data;
+}
+
+/*
+ * Make our basic server name: use the specified "arg" if given, otherwise use
+ * the tail of the command "cmd" we were started with.
+ * Return the name in allocated memory. This doesn't include a serial number.
+ */
+ static char_u *
+serverMakeName(char_u *arg, char *cmd)
+{
+ char_u *p;
+
+ if (arg != NULL && *arg != NUL)
+ p = vim_strsave_up(arg);
+ else
+ {
+ p = vim_strsave_up(gettail((char_u *)cmd));
+ /* Remove .exe or .bat from the name. */
+ if (p != NULL && vim_strchr(p, '.') != NULL)
+ *vim_strchr(p, '.') = NUL;
+ }
+ return p;
+}
+#endif /* FEAT_CLIENTSERVER */
+
+#if defined(FEAT_CLIENTSERVER) || defined(PROTO)
+/*
+ * Replace termcodes such as <CR> and insert as key presses if there is room.
+ */
+ void
+server_to_input_buf(char_u *str)
+{
+ char_u *ptr = NULL;
+ char_u *cpo_save = p_cpo;
+
+ /* Set 'cpoptions' the way we want it.
+ * B set - backslashes are *not* treated specially
+ * k set - keycodes are *not* reverse-engineered
+ * < unset - <Key> sequences *are* interpreted
+ * The last but one parameter of replace_termcodes() is TRUE so that the
+ * <lt> sequence is recognised - needed for a real backslash.
+ */
+ p_cpo = (char_u *)"Bk";
+ str = replace_termcodes((char_u *)str, &ptr, FALSE, TRUE, FALSE);
+ p_cpo = cpo_save;
+
+ if (*ptr != NUL) /* trailing CTRL-V results in nothing */
+ {
+ /*
+ * Add the string to the input stream.
+ * Can't use add_to_input_buf() here, we now have K_SPECIAL bytes.
+ *
+ * First clear typed characters from the typeahead buffer, there could
+ * be half a mapping there. Then append to the existing string, so
+ * that multiple commands from a client are concatenated.
+ */
+ if (typebuf.tb_maplen < typebuf.tb_len)
+ del_typebuf(typebuf.tb_len - typebuf.tb_maplen, typebuf.tb_maplen);
+ (void)ins_typebuf(str, REMAP_NONE, typebuf.tb_len, TRUE, FALSE);
+
+ /* Let input_available() know we inserted text in the typeahead
+ * buffer. */
+ typebuf_was_filled = TRUE;
+ }
+ vim_free((char_u *)ptr);
+}
+
+/*
+ * Evaluate an expression that the client sent to a string.
+ */
+ char_u *
+eval_client_expr_to_string(char_u *expr)
+{
+ char_u *res;
+ int save_dbl = debug_break_level;
+ int save_ro = redir_off;
+ funccal_entry_T funccal_entry;
+ int did_save_funccal = FALSE;
+
+ /* Evaluate the expression at the toplevel, don't use variables local to
+ * the calling function. Except when in debug mode. */
+ if (!debug_mode)
+ {
+ save_funccal(&funccal_entry);
+ did_save_funccal = TRUE;
+ }
+
+ /* Disable debugging, otherwise Vim hangs, waiting for "cont" to be
+ * typed. */
+ debug_break_level = -1;
+ redir_off = 0;
+ /* Do not display error message, otherwise Vim hangs, waiting for "cont"
+ * to be typed. Do generate errors so that try/catch works. */
+ ++emsg_silent;
+
+ res = eval_to_string(expr, NULL, TRUE);
+
+ debug_break_level = save_dbl;
+ redir_off = save_ro;
+ --emsg_silent;
+ if (emsg_silent < 0)
+ emsg_silent = 0;
+ if (did_save_funccal)
+ restore_funccal();
+
+ /* A client can tell us to redraw, but not to display the cursor, so do
+ * that here. */
+ setcursor();
+ out_flush_cursor(FALSE, FALSE);
+
+ return res;
+}
+
+/*
+ * Evaluate a command or expression sent to ourselves.
+ */
+ int
+sendToLocalVim(char_u *cmd, int asExpr, char_u **result)
+{
+ if (asExpr)
+ {
+ char_u *ret;
+
+ ret = eval_client_expr_to_string(cmd);
+ if (result != NULL)
+ {
+ if (ret == NULL)
+ {
+ char *err = _(e_invexprmsg);
+ size_t len = STRLEN(cmd) + STRLEN(err) + 5;
+ char_u *msg;
+
+ msg = alloc((unsigned)len);
+ if (msg != NULL)
+ vim_snprintf((char *)msg, len, "%s: \"%s\"", err, cmd);
+ *result = msg;
+ }
+ else
+ *result = ret;
+ }
+ else
+ vim_free(ret);
+ return ret == NULL ? -1 : 0;
+ }
+ server_to_input_buf(cmd);
+ return 0;
+}
+
+/*
+ * If conversion is needed, convert "data" from "client_enc" to 'encoding' and
+ * return an allocated string. Otherwise return "data".
+ * "*tofree" is set to the result when it needs to be freed later.
+ */
+ char_u *
+serverConvert(
+ char_u *client_enc UNUSED,
+ char_u *data,
+ char_u **tofree)
+{
+ char_u *res = data;
+
+ *tofree = NULL;
+ if (client_enc != NULL && p_enc != NULL)
+ {
+ vimconv_T vimconv;
+
+ vimconv.vc_type = CONV_NONE;
+ if (convert_setup(&vimconv, client_enc, p_enc) != FAIL
+ && vimconv.vc_type != CONV_NONE)
+ {
+ res = string_convert(&vimconv, data, NULL);
+ if (res == NULL)
+ res = data;
+ else
+ *tofree = res;
+ }
+ convert_setup(&vimconv, NULL, NULL);
+ }
+ return res;
+}
+#endif
diff --git a/src/mark.c b/src/mark.c
new file mode 100644
index 0000000..6a7ab00
--- /dev/null
+++ b/src/mark.c
@@ -0,0 +1,2215 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * mark.c: functions for setting marks and jumping to them
+ */
+
+#include "vim.h"
+
+/*
+ * This file contains routines to maintain and manipulate marks.
+ */
+
+/*
+ * If a named file mark's lnum is non-zero, it is valid.
+ * If a named file mark's fnum is non-zero, it is for an existing buffer,
+ * otherwise it is from .viminfo and namedfm[n].fname is the file name.
+ * There are marks 'A - 'Z (set by user) and '0 to '9 (set when writing
+ * viminfo).
+ */
+#define EXTRA_MARKS 10 /* marks 0-9 */
+static xfmark_T namedfm[NMARKS + EXTRA_MARKS]; /* marks with file nr */
+
+static void fmarks_check_one(xfmark_T *fm, char_u *name, buf_T *buf);
+static char_u *mark_line(pos_T *mp, int lead_len);
+static void show_one_mark(int, char_u *, pos_T *, char_u *, int current);
+#ifdef FEAT_VIMINFO
+static void write_one_filemark(FILE *fp, xfmark_T *fm, int c1, int c2);
+#endif
+static void mark_adjust_internal(linenr_T line1, linenr_T line2, long amount,
+ long amount_after, int adjust_folds);
+
+/*
+ * Set named mark "c" at current cursor position.
+ * Returns OK on success, FAIL if bad name given.
+ */
+ int
+setmark(int c)
+{
+ return setmark_pos(c, &curwin->w_cursor, curbuf->b_fnum);
+}
+
+/*
+ * Set named mark "c" to position "pos".
+ * When "c" is upper case use file "fnum".
+ * Returns OK on success, FAIL if bad name given.
+ */
+ int
+setmark_pos(int c, pos_T *pos, int fnum)
+{
+ int i;
+ buf_T *buf;
+
+ /* Check for a special key (may cause islower() to crash). */
+ if (c < 0)
+ return FAIL;
+
+ if (c == '\'' || c == '`')
+ {
+ if (pos == &curwin->w_cursor)
+ {
+ setpcmark();
+ /* keep it even when the cursor doesn't move */
+ curwin->w_prev_pcmark = curwin->w_pcmark;
+ }
+ else
+ curwin->w_pcmark = *pos;
+ return OK;
+ }
+
+ buf = buflist_findnr(fnum);
+ if (buf == NULL)
+ return FAIL;
+
+ if (c == '"')
+ {
+ buf->b_last_cursor = *pos;
+ return OK;
+ }
+
+ /* Allow setting '[ and '] for an autocommand that simulates reading a
+ * file. */
+ if (c == '[')
+ {
+ buf->b_op_start = *pos;
+ return OK;
+ }
+ if (c == ']')
+ {
+ buf->b_op_end = *pos;
+ return OK;
+ }
+
+ if (c == '<' || c == '>')
+ {
+ if (c == '<')
+ buf->b_visual.vi_start = *pos;
+ else
+ buf->b_visual.vi_end = *pos;
+ if (buf->b_visual.vi_mode == NUL)
+ /* Visual_mode has not yet been set, use a sane default. */
+ buf->b_visual.vi_mode = 'v';
+ return OK;
+ }
+
+ if (ASCII_ISLOWER(c))
+ {
+ i = c - 'a';
+ buf->b_namedm[i] = *pos;
+ return OK;
+ }
+ if (ASCII_ISUPPER(c) || VIM_ISDIGIT(c))
+ {
+ if (VIM_ISDIGIT(c))
+ i = c - '0' + NMARKS;
+ else
+ i = c - 'A';
+ namedfm[i].fmark.mark = *pos;
+ namedfm[i].fmark.fnum = fnum;
+ VIM_CLEAR(namedfm[i].fname);
+#ifdef FEAT_VIMINFO
+ namedfm[i].time_set = vim_time();
+#endif
+ return OK;
+ }
+ return FAIL;
+}
+
+/*
+ * Set the previous context mark to the current position and add it to the
+ * jump list.
+ */
+ void
+setpcmark(void)
+{
+#ifdef FEAT_JUMPLIST
+ int i;
+ xfmark_T *fm;
+#endif
+#ifdef JUMPLIST_ROTATE
+ xfmark_T tempmark;
+#endif
+
+ /* for :global the mark is set only once */
+ if (global_busy || listcmd_busy || cmdmod.keepjumps)
+ return;
+
+ curwin->w_prev_pcmark = curwin->w_pcmark;
+ curwin->w_pcmark = curwin->w_cursor;
+
+#ifdef FEAT_JUMPLIST
+# ifdef JUMPLIST_ROTATE
+ /*
+ * If last used entry is not at the top, put it at the top by rotating
+ * the stack until it is (the newer entries will be at the bottom).
+ * Keep one entry (the last used one) at the top.
+ */
+ if (curwin->w_jumplistidx < curwin->w_jumplistlen)
+ ++curwin->w_jumplistidx;
+ while (curwin->w_jumplistidx < curwin->w_jumplistlen)
+ {
+ tempmark = curwin->w_jumplist[curwin->w_jumplistlen - 1];
+ for (i = curwin->w_jumplistlen - 1; i > 0; --i)
+ curwin->w_jumplist[i] = curwin->w_jumplist[i - 1];
+ curwin->w_jumplist[0] = tempmark;
+ ++curwin->w_jumplistidx;
+ }
+# endif
+
+ /* If jumplist is full: remove oldest entry */
+ if (++curwin->w_jumplistlen > JUMPLISTSIZE)
+ {
+ curwin->w_jumplistlen = JUMPLISTSIZE;
+ vim_free(curwin->w_jumplist[0].fname);
+ for (i = 1; i < JUMPLISTSIZE; ++i)
+ curwin->w_jumplist[i - 1] = curwin->w_jumplist[i];
+ }
+ curwin->w_jumplistidx = curwin->w_jumplistlen;
+ fm = &curwin->w_jumplist[curwin->w_jumplistlen - 1];
+
+ fm->fmark.mark = curwin->w_pcmark;
+ fm->fmark.fnum = curbuf->b_fnum;
+ fm->fname = NULL;
+# ifdef FEAT_VIMINFO
+ fm->time_set = vim_time();
+# endif
+#endif
+}
+
+/*
+ * To change context, call setpcmark(), then move the current position to
+ * where ever, then call checkpcmark(). This ensures that the previous
+ * context will only be changed if the cursor moved to a different line.
+ * If pcmark was deleted (with "dG") the previous mark is restored.
+ */
+ void
+checkpcmark(void)
+{
+ if (curwin->w_prev_pcmark.lnum != 0
+ && (EQUAL_POS(curwin->w_pcmark, curwin->w_cursor)
+ || curwin->w_pcmark.lnum == 0))
+ {
+ curwin->w_pcmark = curwin->w_prev_pcmark;
+ curwin->w_prev_pcmark.lnum = 0; /* Show it has been checked */
+ }
+}
+
+#if defined(FEAT_JUMPLIST) || defined(PROTO)
+/*
+ * move "count" positions in the jump list (count may be negative)
+ */
+ pos_T *
+movemark(int count)
+{
+ pos_T *pos;
+ xfmark_T *jmp;
+
+ cleanup_jumplist(curwin, TRUE);
+
+ if (curwin->w_jumplistlen == 0) /* nothing to jump to */
+ return (pos_T *)NULL;
+
+ for (;;)
+ {
+ if (curwin->w_jumplistidx + count < 0
+ || curwin->w_jumplistidx + count >= curwin->w_jumplistlen)
+ return (pos_T *)NULL;
+
+ /*
+ * if first CTRL-O or CTRL-I command after a jump, add cursor position
+ * to list. Careful: If there are duplicates (CTRL-O immediately after
+ * starting Vim on a file), another entry may have been removed.
+ */
+ if (curwin->w_jumplistidx == curwin->w_jumplistlen)
+ {
+ setpcmark();
+ --curwin->w_jumplistidx; /* skip the new entry */
+ if (curwin->w_jumplistidx + count < 0)
+ return (pos_T *)NULL;
+ }
+
+ curwin->w_jumplistidx += count;
+
+ jmp = curwin->w_jumplist + curwin->w_jumplistidx;
+ if (jmp->fmark.fnum == 0)
+ fname2fnum(jmp);
+ if (jmp->fmark.fnum != curbuf->b_fnum)
+ {
+ /* jump to other file */
+ if (buflist_findnr(jmp->fmark.fnum) == NULL)
+ { /* Skip this one .. */
+ count += count < 0 ? -1 : 1;
+ continue;
+ }
+ if (buflist_getfile(jmp->fmark.fnum, jmp->fmark.mark.lnum,
+ 0, FALSE) == FAIL)
+ return (pos_T *)NULL;
+ /* Set lnum again, autocommands my have changed it */
+ curwin->w_cursor = jmp->fmark.mark;
+ pos = (pos_T *)-1;
+ }
+ else
+ pos = &(jmp->fmark.mark);
+ return pos;
+ }
+}
+
+/*
+ * Move "count" positions in the changelist (count may be negative).
+ */
+ pos_T *
+movechangelist(int count)
+{
+ int n;
+
+ if (curbuf->b_changelistlen == 0) /* nothing to jump to */
+ return (pos_T *)NULL;
+
+ n = curwin->w_changelistidx;
+ if (n + count < 0)
+ {
+ if (n == 0)
+ return (pos_T *)NULL;
+ n = 0;
+ }
+ else if (n + count >= curbuf->b_changelistlen)
+ {
+ if (n == curbuf->b_changelistlen - 1)
+ return (pos_T *)NULL;
+ n = curbuf->b_changelistlen - 1;
+ }
+ else
+ n += count;
+ curwin->w_changelistidx = n;
+ return curbuf->b_changelist + n;
+}
+#endif
+
+/*
+ * Find mark "c" in buffer pointed to by "buf".
+ * If "changefile" is TRUE it's allowed to edit another file for '0, 'A, etc.
+ * If "fnum" is not NULL store the fnum there for '0, 'A etc., don't edit
+ * another file.
+ * Returns:
+ * - pointer to pos_T if found. lnum is 0 when mark not set, -1 when mark is
+ * in another file which can't be gotten. (caller needs to check lnum!)
+ * - NULL if there is no mark called 'c'.
+ * - -1 if mark is in other file and jumped there (only if changefile is TRUE)
+ */
+ pos_T *
+getmark_buf(buf_T *buf, int c, int changefile)
+{
+ return getmark_buf_fnum(buf, c, changefile, NULL);
+}
+
+ pos_T *
+getmark(int c, int changefile)
+{
+ return getmark_buf_fnum(curbuf, c, changefile, NULL);
+}
+
+ pos_T *
+getmark_buf_fnum(
+ buf_T *buf,
+ int c,
+ int changefile,
+ int *fnum)
+{
+ pos_T *posp;
+ pos_T *startp, *endp;
+ static pos_T pos_copy;
+
+ posp = NULL;
+
+ /* Check for special key, can't be a mark name and might cause islower()
+ * to crash. */
+ if (c < 0)
+ return posp;
+#ifndef EBCDIC
+ if (c > '~') /* check for islower()/isupper() */
+ ;
+ else
+#endif
+ if (c == '\'' || c == '`') /* previous context mark */
+ {
+ pos_copy = curwin->w_pcmark; /* need to make a copy because */
+ posp = &pos_copy; /* w_pcmark may be changed soon */
+ }
+ else if (c == '"') /* to pos when leaving buffer */
+ posp = &(buf->b_last_cursor);
+ else if (c == '^') /* to where Insert mode stopped */
+ posp = &(buf->b_last_insert);
+ else if (c == '.') /* to where last change was made */
+ posp = &(buf->b_last_change);
+ else if (c == '[') /* to start of previous operator */
+ posp = &(buf->b_op_start);
+ else if (c == ']') /* to end of previous operator */
+ posp = &(buf->b_op_end);
+ else if (c == '{' || c == '}') /* to previous/next paragraph */
+ {
+ pos_T pos;
+ oparg_T oa;
+ int slcb = listcmd_busy;
+
+ pos = curwin->w_cursor;
+ listcmd_busy = TRUE; /* avoid that '' is changed */
+ if (findpar(&oa.inclusive,
+ c == '}' ? FORWARD : BACKWARD, 1L, NUL, FALSE))
+ {
+ pos_copy = curwin->w_cursor;
+ posp = &pos_copy;
+ }
+ curwin->w_cursor = pos;
+ listcmd_busy = slcb;
+ }
+ else if (c == '(' || c == ')') /* to previous/next sentence */
+ {
+ pos_T pos;
+ int slcb = listcmd_busy;
+
+ pos = curwin->w_cursor;
+ listcmd_busy = TRUE; /* avoid that '' is changed */
+ if (findsent(c == ')' ? FORWARD : BACKWARD, 1L))
+ {
+ pos_copy = curwin->w_cursor;
+ posp = &pos_copy;
+ }
+ curwin->w_cursor = pos;
+ listcmd_busy = slcb;
+ }
+ else if (c == '<' || c == '>') /* start/end of visual area */
+ {
+ startp = &buf->b_visual.vi_start;
+ endp = &buf->b_visual.vi_end;
+ if (((c == '<') == LT_POS(*startp, *endp) || endp->lnum == 0)
+ && startp->lnum != 0)
+ posp = startp;
+ else
+ posp = endp;
+ /*
+ * For Visual line mode, set mark at begin or end of line
+ */
+ if (buf->b_visual.vi_mode == 'V')
+ {
+ pos_copy = *posp;
+ posp = &pos_copy;
+ if (c == '<')
+ pos_copy.col = 0;
+ else
+ pos_copy.col = MAXCOL;
+ pos_copy.coladd = 0;
+ }
+ }
+ else if (ASCII_ISLOWER(c)) /* normal named mark */
+ {
+ posp = &(buf->b_namedm[c - 'a']);
+ }
+ else if (ASCII_ISUPPER(c) || VIM_ISDIGIT(c)) /* named file mark */
+ {
+ if (VIM_ISDIGIT(c))
+ c = c - '0' + NMARKS;
+ else
+ c -= 'A';
+ posp = &(namedfm[c].fmark.mark);
+
+ if (namedfm[c].fmark.fnum == 0)
+ fname2fnum(&namedfm[c]);
+
+ if (fnum != NULL)
+ *fnum = namedfm[c].fmark.fnum;
+ else if (namedfm[c].fmark.fnum != buf->b_fnum)
+ {
+ /* mark is in another file */
+ posp = &pos_copy;
+
+ if (namedfm[c].fmark.mark.lnum != 0
+ && changefile && namedfm[c].fmark.fnum)
+ {
+ if (buflist_getfile(namedfm[c].fmark.fnum,
+ (linenr_T)1, GETF_SETMARK, FALSE) == OK)
+ {
+ /* Set the lnum now, autocommands could have changed it */
+ curwin->w_cursor = namedfm[c].fmark.mark;
+ return (pos_T *)-1;
+ }
+ pos_copy.lnum = -1; /* can't get file */
+ }
+ else
+ pos_copy.lnum = 0; /* mark exists, but is not valid in
+ current buffer */
+ }
+ }
+
+ return posp;
+}
+
+/*
+ * Search for the next named mark in the current file.
+ *
+ * Returns pointer to pos_T of the next mark or NULL if no mark is found.
+ */
+ pos_T *
+getnextmark(
+ pos_T *startpos, /* where to start */
+ int dir, /* direction for search */
+ int begin_line)
+{
+ int i;
+ pos_T *result = NULL;
+ pos_T pos;
+
+ pos = *startpos;
+
+ /* When searching backward and leaving the cursor on the first non-blank,
+ * position must be in a previous line.
+ * When searching forward and leaving the cursor on the first non-blank,
+ * position must be in a next line. */
+ if (dir == BACKWARD && begin_line)
+ pos.col = 0;
+ else if (dir == FORWARD && begin_line)
+ pos.col = MAXCOL;
+
+ for (i = 0; i < NMARKS; i++)
+ {
+ if (curbuf->b_namedm[i].lnum > 0)
+ {
+ if (dir == FORWARD)
+ {
+ if ((result == NULL || LT_POS(curbuf->b_namedm[i], *result))
+ && LT_POS(pos, curbuf->b_namedm[i]))
+ result = &curbuf->b_namedm[i];
+ }
+ else
+ {
+ if ((result == NULL || LT_POS(*result, curbuf->b_namedm[i]))
+ && LT_POS(curbuf->b_namedm[i], pos))
+ result = &curbuf->b_namedm[i];
+ }
+ }
+ }
+
+ return result;
+}
+
+/*
+ * For an xtended filemark: set the fnum from the fname.
+ * This is used for marks obtained from the .viminfo file. It's postponed
+ * until the mark is used to avoid a long startup delay.
+ */
+ void
+fname2fnum(xfmark_T *fm)
+{
+ char_u *p;
+
+ if (fm->fname != NULL)
+ {
+ /*
+ * First expand "~/" in the file name to the home directory.
+ * Don't expand the whole name, it may contain other '~' chars.
+ */
+ if (fm->fname[0] == '~' && (fm->fname[1] == '/'
+#ifdef BACKSLASH_IN_FILENAME
+ || fm->fname[1] == '\\'
+#endif
+ ))
+ {
+ int len;
+
+ expand_env((char_u *)"~/", NameBuff, MAXPATHL);
+ len = (int)STRLEN(NameBuff);
+ vim_strncpy(NameBuff + len, fm->fname + 2, MAXPATHL - len - 1);
+ }
+ else
+ vim_strncpy(NameBuff, fm->fname, MAXPATHL - 1);
+
+ /* Try to shorten the file name. */
+ mch_dirname(IObuff, IOSIZE);
+ p = shorten_fname(NameBuff, IObuff);
+
+ /* buflist_new() will call fmarks_check_names() */
+ (void)buflist_new(NameBuff, p, (linenr_T)1, 0);
+ }
+}
+
+/*
+ * Check all file marks for a name that matches the file name in buf.
+ * May replace the name with an fnum.
+ * Used for marks that come from the .viminfo file.
+ */
+ void
+fmarks_check_names(buf_T *buf)
+{
+ char_u *name;
+ int i;
+#ifdef FEAT_JUMPLIST
+ win_T *wp;
+#endif
+
+ if (buf->b_ffname == NULL)
+ return;
+
+ name = home_replace_save(buf, buf->b_ffname);
+ if (name == NULL)
+ return;
+
+ for (i = 0; i < NMARKS + EXTRA_MARKS; ++i)
+ fmarks_check_one(&namedfm[i], name, buf);
+
+#ifdef FEAT_JUMPLIST
+ FOR_ALL_WINDOWS(wp)
+ {
+ for (i = 0; i < wp->w_jumplistlen; ++i)
+ fmarks_check_one(&wp->w_jumplist[i], name, buf);
+ }
+#endif
+
+ vim_free(name);
+}
+
+ static void
+fmarks_check_one(xfmark_T *fm, char_u *name, buf_T *buf)
+{
+ if (fm->fmark.fnum == 0
+ && fm->fname != NULL
+ && fnamecmp(name, fm->fname) == 0)
+ {
+ fm->fmark.fnum = buf->b_fnum;
+ VIM_CLEAR(fm->fname);
+ }
+}
+
+/*
+ * Check a if a position from a mark is valid.
+ * Give and error message and return FAIL if not.
+ */
+ int
+check_mark(pos_T *pos)
+{
+ if (pos == NULL)
+ {
+ emsg(_(e_umark));
+ return FAIL;
+ }
+ if (pos->lnum <= 0)
+ {
+ /* lnum is negative if mark is in another file can can't get that
+ * file, error message already give then. */
+ if (pos->lnum == 0)
+ emsg(_(e_marknotset));
+ return FAIL;
+ }
+ if (pos->lnum > curbuf->b_ml.ml_line_count)
+ {
+ emsg(_(e_markinval));
+ return FAIL;
+ }
+ return OK;
+}
+
+/*
+ * clrallmarks() - clear all marks in the buffer 'buf'
+ *
+ * Used mainly when trashing the entire buffer during ":e" type commands
+ */
+ void
+clrallmarks(buf_T *buf)
+{
+ static int i = -1;
+
+ if (i == -1) /* first call ever: initialize */
+ for (i = 0; i < NMARKS + 1; i++)
+ {
+ namedfm[i].fmark.mark.lnum = 0;
+ namedfm[i].fname = NULL;
+#ifdef FEAT_VIMINFO
+ namedfm[i].time_set = 0;
+#endif
+ }
+
+ for (i = 0; i < NMARKS; i++)
+ buf->b_namedm[i].lnum = 0;
+ buf->b_op_start.lnum = 0; /* start/end op mark cleared */
+ buf->b_op_end.lnum = 0;
+ buf->b_last_cursor.lnum = 1; /* '" mark cleared */
+ buf->b_last_cursor.col = 0;
+ buf->b_last_cursor.coladd = 0;
+ buf->b_last_insert.lnum = 0; /* '^ mark cleared */
+ buf->b_last_change.lnum = 0; /* '. mark cleared */
+#ifdef FEAT_JUMPLIST
+ buf->b_changelistlen = 0;
+#endif
+}
+
+/*
+ * Get name of file from a filemark.
+ * When it's in the current buffer, return the text at the mark.
+ * Returns an allocated string.
+ */
+ char_u *
+fm_getname(fmark_T *fmark, int lead_len)
+{
+ if (fmark->fnum == curbuf->b_fnum) /* current buffer */
+ return mark_line(&(fmark->mark), lead_len);
+ return buflist_nr2name(fmark->fnum, FALSE, TRUE);
+}
+
+/*
+ * Return the line at mark "mp". Truncate to fit in window.
+ * The returned string has been allocated.
+ */
+ static char_u *
+mark_line(pos_T *mp, int lead_len)
+{
+ char_u *s, *p;
+ int len;
+
+ if (mp->lnum == 0 || mp->lnum > curbuf->b_ml.ml_line_count)
+ return vim_strsave((char_u *)"-invalid-");
+ // Allow for up to 5 bytes per character.
+ s = vim_strnsave(skipwhite(ml_get(mp->lnum)), (int)Columns * 5);
+ if (s == NULL)
+ return NULL;
+ // Truncate the line to fit it in the window.
+ len = 0;
+ for (p = s; *p != NUL; MB_PTR_ADV(p))
+ {
+ len += ptr2cells(p);
+ if (len >= Columns - lead_len)
+ break;
+ }
+ *p = NUL;
+ return s;
+}
+
+/*
+ * print the marks
+ */
+ void
+do_marks(exarg_T *eap)
+{
+ char_u *arg = eap->arg;
+ int i;
+ char_u *name;
+
+ if (arg != NULL && *arg == NUL)
+ arg = NULL;
+
+ show_one_mark('\'', arg, &curwin->w_pcmark, NULL, TRUE);
+ for (i = 0; i < NMARKS; ++i)
+ show_one_mark(i + 'a', arg, &curbuf->b_namedm[i], NULL, TRUE);
+ for (i = 0; i < NMARKS + EXTRA_MARKS; ++i)
+ {
+ if (namedfm[i].fmark.fnum != 0)
+ name = fm_getname(&namedfm[i].fmark, 15);
+ else
+ name = namedfm[i].fname;
+ if (name != NULL)
+ {
+ show_one_mark(i >= NMARKS ? i - NMARKS + '0' : i + 'A',
+ arg, &namedfm[i].fmark.mark, name,
+ namedfm[i].fmark.fnum == curbuf->b_fnum);
+ if (namedfm[i].fmark.fnum != 0)
+ vim_free(name);
+ }
+ }
+ show_one_mark('"', arg, &curbuf->b_last_cursor, NULL, TRUE);
+ show_one_mark('[', arg, &curbuf->b_op_start, NULL, TRUE);
+ show_one_mark(']', arg, &curbuf->b_op_end, NULL, TRUE);
+ show_one_mark('^', arg, &curbuf->b_last_insert, NULL, TRUE);
+ show_one_mark('.', arg, &curbuf->b_last_change, NULL, TRUE);
+ show_one_mark('<', arg, &curbuf->b_visual.vi_start, NULL, TRUE);
+ show_one_mark('>', arg, &curbuf->b_visual.vi_end, NULL, TRUE);
+ show_one_mark(-1, arg, NULL, NULL, FALSE);
+}
+
+ static void
+show_one_mark(
+ int c,
+ char_u *arg,
+ pos_T *p,
+ char_u *name,
+ int current) /* in current file */
+{
+ static int did_title = FALSE;
+ int mustfree = FALSE;
+
+ if (c == -1) /* finish up */
+ {
+ if (did_title)
+ did_title = FALSE;
+ else
+ {
+ if (arg == NULL)
+ msg(_("No marks set"));
+ else
+ semsg(_("E283: No marks matching \"%s\""), arg);
+ }
+ }
+ /* don't output anything if 'q' typed at --more-- prompt */
+ else if (!got_int
+ && (arg == NULL || vim_strchr(arg, c) != NULL)
+ && p->lnum != 0)
+ {
+ if (!did_title)
+ {
+ /* Highlight title */
+ msg_puts_title(_("\nmark line col file/text"));
+ did_title = TRUE;
+ }
+ msg_putchar('\n');
+ if (!got_int)
+ {
+ sprintf((char *)IObuff, " %c %6ld %4d ", c, p->lnum, p->col);
+ msg_outtrans(IObuff);
+ if (name == NULL && current)
+ {
+ name = mark_line(p, 15);
+ mustfree = TRUE;
+ }
+ if (name != NULL)
+ {
+ msg_outtrans_attr(name, current ? HL_ATTR(HLF_D) : 0);
+ if (mustfree)
+ vim_free(name);
+ }
+ }
+ out_flush(); /* show one line at a time */
+ }
+}
+
+/*
+ * ":delmarks[!] [marks]"
+ */
+ void
+ex_delmarks(exarg_T *eap)
+{
+ char_u *p;
+ int from, to;
+ int i;
+ int lower;
+ int digit;
+ int n;
+
+ if (*eap->arg == NUL && eap->forceit)
+ /* clear all marks */
+ clrallmarks(curbuf);
+ else if (eap->forceit)
+ emsg(_(e_invarg));
+ else if (*eap->arg == NUL)
+ emsg(_(e_argreq));
+ else
+ {
+ /* clear specified marks only */
+ for (p = eap->arg; *p != NUL; ++p)
+ {
+ lower = ASCII_ISLOWER(*p);
+ digit = VIM_ISDIGIT(*p);
+ if (lower || digit || ASCII_ISUPPER(*p))
+ {
+ if (p[1] == '-')
+ {
+ /* clear range of marks */
+ from = *p;
+ to = p[2];
+ if (!(lower ? ASCII_ISLOWER(p[2])
+ : (digit ? VIM_ISDIGIT(p[2])
+ : ASCII_ISUPPER(p[2])))
+ || to < from)
+ {
+ semsg(_(e_invarg2), p);
+ return;
+ }
+ p += 2;
+ }
+ else
+ /* clear one lower case mark */
+ from = to = *p;
+
+ for (i = from; i <= to; ++i)
+ {
+ if (lower)
+ curbuf->b_namedm[i - 'a'].lnum = 0;
+ else
+ {
+ if (digit)
+ n = i - '0' + NMARKS;
+ else
+ n = i - 'A';
+ namedfm[n].fmark.mark.lnum = 0;
+ VIM_CLEAR(namedfm[n].fname);
+#ifdef FEAT_VIMINFO
+ namedfm[n].time_set = 0;
+#endif
+ }
+ }
+ }
+ else
+ switch (*p)
+ {
+ case '"': curbuf->b_last_cursor.lnum = 0; break;
+ case '^': curbuf->b_last_insert.lnum = 0; break;
+ case '.': curbuf->b_last_change.lnum = 0; break;
+ case '[': curbuf->b_op_start.lnum = 0; break;
+ case ']': curbuf->b_op_end.lnum = 0; break;
+ case '<': curbuf->b_visual.vi_start.lnum = 0; break;
+ case '>': curbuf->b_visual.vi_end.lnum = 0; break;
+ case ' ': break;
+ default: semsg(_(e_invarg2), p);
+ return;
+ }
+ }
+ }
+}
+
+#if defined(FEAT_JUMPLIST) || defined(PROTO)
+/*
+ * print the jumplist
+ */
+ void
+ex_jumps(exarg_T *eap UNUSED)
+{
+ int i;
+ char_u *name;
+
+ cleanup_jumplist(curwin, TRUE);
+
+ /* Highlight title */
+ msg_puts_title(_("\n jump line col file/text"));
+ for (i = 0; i < curwin->w_jumplistlen && !got_int; ++i)
+ {
+ if (curwin->w_jumplist[i].fmark.mark.lnum != 0)
+ {
+ name = fm_getname(&curwin->w_jumplist[i].fmark, 16);
+
+ // apply :filter /pat/ or file name not available
+ if (name == NULL || message_filtered(name))
+ {
+ vim_free(name);
+ continue;
+ }
+
+ msg_putchar('\n');
+ if (got_int)
+ {
+ vim_free(name);
+ break;
+ }
+ sprintf((char *)IObuff, "%c %2d %5ld %4d ",
+ i == curwin->w_jumplistidx ? '>' : ' ',
+ i > curwin->w_jumplistidx ? i - curwin->w_jumplistidx
+ : curwin->w_jumplistidx - i,
+ curwin->w_jumplist[i].fmark.mark.lnum,
+ curwin->w_jumplist[i].fmark.mark.col);
+ msg_outtrans(IObuff);
+ msg_outtrans_attr(name,
+ curwin->w_jumplist[i].fmark.fnum == curbuf->b_fnum
+ ? HL_ATTR(HLF_D) : 0);
+ vim_free(name);
+ ui_breakcheck();
+ }
+ out_flush();
+ }
+ if (curwin->w_jumplistidx == curwin->w_jumplistlen)
+ msg_puts("\n>");
+}
+
+ void
+ex_clearjumps(exarg_T *eap UNUSED)
+{
+ free_jumplist(curwin);
+ curwin->w_jumplistlen = 0;
+ curwin->w_jumplistidx = 0;
+}
+
+/*
+ * print the changelist
+ */
+ void
+ex_changes(exarg_T *eap UNUSED)
+{
+ int i;
+ char_u *name;
+
+ /* Highlight title */
+ msg_puts_title(_("\nchange line col text"));
+
+ for (i = 0; i < curbuf->b_changelistlen && !got_int; ++i)
+ {
+ if (curbuf->b_changelist[i].lnum != 0)
+ {
+ msg_putchar('\n');
+ if (got_int)
+ break;
+ sprintf((char *)IObuff, "%c %3d %5ld %4d ",
+ i == curwin->w_changelistidx ? '>' : ' ',
+ i > curwin->w_changelistidx ? i - curwin->w_changelistidx
+ : curwin->w_changelistidx - i,
+ (long)curbuf->b_changelist[i].lnum,
+ curbuf->b_changelist[i].col);
+ msg_outtrans(IObuff);
+ name = mark_line(&curbuf->b_changelist[i], 17);
+ if (name == NULL)
+ break;
+ msg_outtrans_attr(name, HL_ATTR(HLF_D));
+ vim_free(name);
+ ui_breakcheck();
+ }
+ out_flush();
+ }
+ if (curwin->w_changelistidx == curbuf->b_changelistlen)
+ msg_puts("\n>");
+}
+#endif
+
+#define one_adjust(add) \
+ { \
+ lp = add; \
+ if (*lp >= line1 && *lp <= line2) \
+ { \
+ if (amount == MAXLNUM) \
+ *lp = 0; \
+ else \
+ *lp += amount; \
+ } \
+ else if (amount_after && *lp > line2) \
+ *lp += amount_after; \
+ }
+
+/* don't delete the line, just put at first deleted line */
+#define one_adjust_nodel(add) \
+ { \
+ lp = add; \
+ if (*lp >= line1 && *lp <= line2) \
+ { \
+ if (amount == MAXLNUM) \
+ *lp = line1; \
+ else \
+ *lp += amount; \
+ } \
+ else if (amount_after && *lp > line2) \
+ *lp += amount_after; \
+ }
+
+/*
+ * Adjust marks between line1 and line2 (inclusive) to move 'amount' lines.
+ * Must be called before changed_*(), appended_lines() or deleted_lines().
+ * May be called before or after changing the text.
+ * When deleting lines line1 to line2, use an 'amount' of MAXLNUM: The marks
+ * within this range are made invalid.
+ * If 'amount_after' is non-zero adjust marks after line2.
+ * Example: Delete lines 34 and 35: mark_adjust(34, 35, MAXLNUM, -2);
+ * Example: Insert two lines below 55: mark_adjust(56, MAXLNUM, 2, 0);
+ * or: mark_adjust(56, 55, MAXLNUM, 2);
+ */
+ void
+mark_adjust(
+ linenr_T line1,
+ linenr_T line2,
+ long amount,
+ long amount_after)
+{
+ mark_adjust_internal(line1, line2, amount, amount_after, TRUE);
+}
+
+ void
+mark_adjust_nofold(
+ linenr_T line1,
+ linenr_T line2,
+ long amount,
+ long amount_after)
+{
+ mark_adjust_internal(line1, line2, amount, amount_after, FALSE);
+}
+
+ static void
+mark_adjust_internal(
+ linenr_T line1,
+ linenr_T line2,
+ long amount,
+ long amount_after,
+ int adjust_folds UNUSED)
+{
+ int i;
+ int fnum = curbuf->b_fnum;
+ linenr_T *lp;
+ win_T *win;
+ tabpage_T *tab;
+ static pos_T initpos = {1, 0, 0};
+
+ if (line2 < line1 && amount_after == 0L) /* nothing to do */
+ return;
+
+ if (!cmdmod.lockmarks)
+ {
+ /* named marks, lower case and upper case */
+ for (i = 0; i < NMARKS; i++)
+ {
+ one_adjust(&(curbuf->b_namedm[i].lnum));
+ if (namedfm[i].fmark.fnum == fnum)
+ one_adjust_nodel(&(namedfm[i].fmark.mark.lnum));
+ }
+ for (i = NMARKS; i < NMARKS + EXTRA_MARKS; i++)
+ {
+ if (namedfm[i].fmark.fnum == fnum)
+ one_adjust_nodel(&(namedfm[i].fmark.mark.lnum));
+ }
+
+ /* last Insert position */
+ one_adjust(&(curbuf->b_last_insert.lnum));
+
+ /* last change position */
+ one_adjust(&(curbuf->b_last_change.lnum));
+
+ /* last cursor position, if it was set */
+ if (!EQUAL_POS(curbuf->b_last_cursor, initpos))
+ one_adjust(&(curbuf->b_last_cursor.lnum));
+
+
+#ifdef FEAT_JUMPLIST
+ /* list of change positions */
+ for (i = 0; i < curbuf->b_changelistlen; ++i)
+ one_adjust_nodel(&(curbuf->b_changelist[i].lnum));
+#endif
+
+ /* Visual area */
+ one_adjust_nodel(&(curbuf->b_visual.vi_start.lnum));
+ one_adjust_nodel(&(curbuf->b_visual.vi_end.lnum));
+
+#ifdef FEAT_QUICKFIX
+ /* quickfix marks */
+ qf_mark_adjust(NULL, line1, line2, amount, amount_after);
+ /* location lists */
+ FOR_ALL_TAB_WINDOWS(tab, win)
+ qf_mark_adjust(win, line1, line2, amount, amount_after);
+#endif
+
+#ifdef FEAT_SIGNS
+ sign_mark_adjust(line1, line2, amount, amount_after);
+#endif
+ }
+
+ /* previous context mark */
+ one_adjust(&(curwin->w_pcmark.lnum));
+
+ /* previous pcmark */
+ one_adjust(&(curwin->w_prev_pcmark.lnum));
+
+ /* saved cursor for formatting */
+ if (saved_cursor.lnum != 0)
+ one_adjust_nodel(&(saved_cursor.lnum));
+
+ /*
+ * Adjust items in all windows related to the current buffer.
+ */
+ FOR_ALL_TAB_WINDOWS(tab, win)
+ {
+#ifdef FEAT_JUMPLIST
+ if (!cmdmod.lockmarks)
+ /* Marks in the jumplist. When deleting lines, this may create
+ * duplicate marks in the jumplist, they will be removed later. */
+ for (i = 0; i < win->w_jumplistlen; ++i)
+ if (win->w_jumplist[i].fmark.fnum == fnum)
+ one_adjust_nodel(&(win->w_jumplist[i].fmark.mark.lnum));
+#endif
+
+ if (win->w_buffer == curbuf)
+ {
+ if (!cmdmod.lockmarks)
+ /* marks in the tag stack */
+ for (i = 0; i < win->w_tagstacklen; i++)
+ if (win->w_tagstack[i].fmark.fnum == fnum)
+ one_adjust_nodel(&(win->w_tagstack[i].fmark.mark.lnum));
+
+ /* the displayed Visual area */
+ if (win->w_old_cursor_lnum != 0)
+ {
+ one_adjust_nodel(&(win->w_old_cursor_lnum));
+ one_adjust_nodel(&(win->w_old_visual_lnum));
+ }
+
+ /* topline and cursor position for windows with the same buffer
+ * other than the current window */
+ if (win != curwin)
+ {
+ if (win->w_topline >= line1 && win->w_topline <= line2)
+ {
+ if (amount == MAXLNUM) /* topline is deleted */
+ {
+ if (line1 <= 1)
+ win->w_topline = 1;
+ else
+ win->w_topline = line1 - 1;
+ }
+ else /* keep topline on the same line */
+ win->w_topline += amount;
+#ifdef FEAT_DIFF
+ win->w_topfill = 0;
+#endif
+ }
+ else if (amount_after && win->w_topline > line2)
+ {
+ win->w_topline += amount_after;
+#ifdef FEAT_DIFF
+ win->w_topfill = 0;
+#endif
+ }
+ if (win->w_cursor.lnum >= line1 && win->w_cursor.lnum <= line2)
+ {
+ if (amount == MAXLNUM) /* line with cursor is deleted */
+ {
+ if (line1 <= 1)
+ win->w_cursor.lnum = 1;
+ else
+ win->w_cursor.lnum = line1 - 1;
+ win->w_cursor.col = 0;
+ }
+ else /* keep cursor on the same line */
+ win->w_cursor.lnum += amount;
+ }
+ else if (amount_after && win->w_cursor.lnum > line2)
+ win->w_cursor.lnum += amount_after;
+ }
+
+#ifdef FEAT_FOLDING
+ /* adjust folds */
+ if (adjust_folds)
+ foldMarkAdjust(win, line1, line2, amount, amount_after);
+#endif
+ }
+ }
+
+#ifdef FEAT_DIFF
+ /* adjust diffs */
+ diff_mark_adjust(line1, line2, amount, amount_after);
+#endif
+}
+
+/* This code is used often, needs to be fast. */
+#define col_adjust(pp) \
+ { \
+ posp = pp; \
+ if (posp->lnum == lnum && posp->col >= mincol) \
+ { \
+ posp->lnum += lnum_amount; \
+ if (col_amount < 0 && posp->col <= (colnr_T)-col_amount) \
+ posp->col = 0; \
+ else if (posp->col < spaces_removed) \
+ posp->col = col_amount + spaces_removed; \
+ else \
+ posp->col += col_amount; \
+ } \
+ }
+
+/*
+ * Adjust marks in line "lnum" at column "mincol" and further: add
+ * "lnum_amount" to the line number and add "col_amount" to the column
+ * position.
+ * "spaces_removed" is the number of spaces that were removed, matters when the
+ * cursor is inside them.
+ */
+ void
+mark_col_adjust(
+ linenr_T lnum,
+ colnr_T mincol,
+ long lnum_amount,
+ long col_amount,
+ int spaces_removed)
+{
+ int i;
+ int fnum = curbuf->b_fnum;
+ win_T *win;
+ pos_T *posp;
+
+ if ((col_amount == 0L && lnum_amount == 0L) || cmdmod.lockmarks)
+ return; /* nothing to do */
+
+ /* named marks, lower case and upper case */
+ for (i = 0; i < NMARKS; i++)
+ {
+ col_adjust(&(curbuf->b_namedm[i]));
+ if (namedfm[i].fmark.fnum == fnum)
+ col_adjust(&(namedfm[i].fmark.mark));
+ }
+ for (i = NMARKS; i < NMARKS + EXTRA_MARKS; i++)
+ {
+ if (namedfm[i].fmark.fnum == fnum)
+ col_adjust(&(namedfm[i].fmark.mark));
+ }
+
+ /* last Insert position */
+ col_adjust(&(curbuf->b_last_insert));
+
+ /* last change position */
+ col_adjust(&(curbuf->b_last_change));
+
+#ifdef FEAT_JUMPLIST
+ /* list of change positions */
+ for (i = 0; i < curbuf->b_changelistlen; ++i)
+ col_adjust(&(curbuf->b_changelist[i]));
+#endif
+
+ /* Visual area */
+ col_adjust(&(curbuf->b_visual.vi_start));
+ col_adjust(&(curbuf->b_visual.vi_end));
+
+ /* previous context mark */
+ col_adjust(&(curwin->w_pcmark));
+
+ /* previous pcmark */
+ col_adjust(&(curwin->w_prev_pcmark));
+
+ /* saved cursor for formatting */
+ col_adjust(&saved_cursor);
+
+ /*
+ * Adjust items in all windows related to the current buffer.
+ */
+ FOR_ALL_WINDOWS(win)
+ {
+#ifdef FEAT_JUMPLIST
+ /* marks in the jumplist */
+ for (i = 0; i < win->w_jumplistlen; ++i)
+ if (win->w_jumplist[i].fmark.fnum == fnum)
+ col_adjust(&(win->w_jumplist[i].fmark.mark));
+#endif
+
+ if (win->w_buffer == curbuf)
+ {
+ /* marks in the tag stack */
+ for (i = 0; i < win->w_tagstacklen; i++)
+ if (win->w_tagstack[i].fmark.fnum == fnum)
+ col_adjust(&(win->w_tagstack[i].fmark.mark));
+
+ /* cursor position for other windows with the same buffer */
+ if (win != curwin)
+ col_adjust(&win->w_cursor);
+ }
+ }
+}
+
+#ifdef FEAT_JUMPLIST
+/*
+ * When deleting lines, this may create duplicate marks in the
+ * jumplist. They will be removed here for the specified window.
+ * When "loadfiles" is TRUE first ensure entries have the "fnum" field set
+ * (this may be a bit slow).
+ */
+ void
+cleanup_jumplist(win_T *wp, int loadfiles)
+{
+ int i;
+ int from, to;
+
+ if (loadfiles)
+ {
+ /* If specified, load all the files from the jump list. This is
+ * needed to properly clean up duplicate entries, but will take some
+ * time. */
+ for (i = 0; i < wp->w_jumplistlen; ++i)
+ {
+ if ((wp->w_jumplist[i].fmark.fnum == 0) &&
+ (wp->w_jumplist[i].fmark.mark.lnum != 0))
+ fname2fnum(&wp->w_jumplist[i]);
+ }
+ }
+
+ to = 0;
+ for (from = 0; from < wp->w_jumplistlen; ++from)
+ {
+ if (wp->w_jumplistidx == from)
+ wp->w_jumplistidx = to;
+ for (i = from + 1; i < wp->w_jumplistlen; ++i)
+ if (wp->w_jumplist[i].fmark.fnum
+ == wp->w_jumplist[from].fmark.fnum
+ && wp->w_jumplist[from].fmark.fnum != 0
+ && wp->w_jumplist[i].fmark.mark.lnum
+ == wp->w_jumplist[from].fmark.mark.lnum)
+ break;
+ if (i >= wp->w_jumplistlen) /* no duplicate */
+ wp->w_jumplist[to++] = wp->w_jumplist[from];
+ else
+ vim_free(wp->w_jumplist[from].fname);
+ }
+ if (wp->w_jumplistidx == wp->w_jumplistlen)
+ wp->w_jumplistidx = to;
+ wp->w_jumplistlen = to;
+}
+
+/*
+ * Copy the jumplist from window "from" to window "to".
+ */
+ void
+copy_jumplist(win_T *from, win_T *to)
+{
+ int i;
+
+ for (i = 0; i < from->w_jumplistlen; ++i)
+ {
+ to->w_jumplist[i] = from->w_jumplist[i];
+ if (from->w_jumplist[i].fname != NULL)
+ to->w_jumplist[i].fname = vim_strsave(from->w_jumplist[i].fname);
+ }
+ to->w_jumplistlen = from->w_jumplistlen;
+ to->w_jumplistidx = from->w_jumplistidx;
+}
+
+/*
+ * Free items in the jumplist of window "wp".
+ */
+ void
+free_jumplist(win_T *wp)
+{
+ int i;
+
+ for (i = 0; i < wp->w_jumplistlen; ++i)
+ vim_free(wp->w_jumplist[i].fname);
+}
+#endif /* FEAT_JUMPLIST */
+
+ void
+set_last_cursor(win_T *win)
+{
+ if (win->w_buffer != NULL)
+ win->w_buffer->b_last_cursor = win->w_cursor;
+}
+
+#if defined(EXITFREE) || defined(PROTO)
+ void
+free_all_marks(void)
+{
+ int i;
+
+ for (i = 0; i < NMARKS + EXTRA_MARKS; i++)
+ if (namedfm[i].fmark.mark.lnum != 0)
+ vim_free(namedfm[i].fname);
+}
+#endif
+
+#if defined(FEAT_VIMINFO) || defined(PROTO)
+ int
+read_viminfo_filemark(vir_T *virp, int force)
+{
+ char_u *str;
+ xfmark_T *fm;
+ int i;
+
+ /* We only get here if line[0] == '\'' or '-'.
+ * Illegal mark names are ignored (for future expansion). */
+ str = virp->vir_line + 1;
+ if (
+#ifndef EBCDIC
+ *str <= 127 &&
+#endif
+ ((*virp->vir_line == '\'' && (VIM_ISDIGIT(*str) || isupper(*str)))
+ || (*virp->vir_line == '-' && *str == '\'')))
+ {
+ if (*str == '\'')
+ {
+#ifdef FEAT_JUMPLIST
+ /* If the jumplist isn't full insert fmark as oldest entry */
+ if (curwin->w_jumplistlen == JUMPLISTSIZE)
+ fm = NULL;
+ else
+ {
+ for (i = curwin->w_jumplistlen; i > 0; --i)
+ curwin->w_jumplist[i] = curwin->w_jumplist[i - 1];
+ ++curwin->w_jumplistidx;
+ ++curwin->w_jumplistlen;
+ fm = &curwin->w_jumplist[0];
+ fm->fmark.mark.lnum = 0;
+ fm->fname = NULL;
+ }
+#else
+ fm = NULL;
+#endif
+ }
+ else if (VIM_ISDIGIT(*str))
+ fm = &namedfm[*str - '0' + NMARKS];
+ else
+ fm = &namedfm[*str - 'A'];
+ if (fm != NULL && (fm->fmark.mark.lnum == 0 || force))
+ {
+ str = skipwhite(str + 1);
+ fm->fmark.mark.lnum = getdigits(&str);
+ str = skipwhite(str);
+ fm->fmark.mark.col = getdigits(&str);
+ fm->fmark.mark.coladd = 0;
+ fm->fmark.fnum = 0;
+ str = skipwhite(str);
+ vim_free(fm->fname);
+ fm->fname = viminfo_readstring(virp, (int)(str - virp->vir_line),
+ FALSE);
+ fm->time_set = 0;
+ }
+ }
+ return vim_fgets(virp->vir_line, LSIZE, virp->vir_fd);
+}
+
+static xfmark_T *vi_namedfm = NULL;
+#ifdef FEAT_JUMPLIST
+static xfmark_T *vi_jumplist = NULL;
+static int vi_jumplist_len = 0;
+#endif
+
+/*
+ * Prepare for reading viminfo marks when writing viminfo later.
+ */
+ void
+prepare_viminfo_marks(void)
+{
+ vi_namedfm = (xfmark_T *)alloc_clear((NMARKS + EXTRA_MARKS)
+ * (int)sizeof(xfmark_T));
+#ifdef FEAT_JUMPLIST
+ vi_jumplist = (xfmark_T *)alloc_clear(JUMPLISTSIZE
+ * (int)sizeof(xfmark_T));
+ vi_jumplist_len = 0;
+#endif
+}
+
+ void
+finish_viminfo_marks(void)
+{
+ int i;
+
+ if (vi_namedfm != NULL)
+ {
+ for (i = 0; i < NMARKS + EXTRA_MARKS; ++i)
+ vim_free(vi_namedfm[i].fname);
+ VIM_CLEAR(vi_namedfm);
+ }
+#ifdef FEAT_JUMPLIST
+ if (vi_jumplist != NULL)
+ {
+ for (i = 0; i < vi_jumplist_len; ++i)
+ vim_free(vi_jumplist[i].fname);
+ VIM_CLEAR(vi_jumplist);
+ }
+#endif
+}
+
+/*
+ * Accept a new style mark line from the viminfo, store it when it's new.
+ */
+ void
+handle_viminfo_mark(garray_T *values, int force)
+{
+ bval_T *vp = (bval_T *)values->ga_data;
+ int name;
+ linenr_T lnum;
+ colnr_T col;
+ time_t timestamp;
+ xfmark_T *fm = NULL;
+
+ /* Check the format:
+ * |{bartype},{name},{lnum},{col},{timestamp},{filename} */
+ if (values->ga_len < 5
+ || vp[0].bv_type != BVAL_NR
+ || vp[1].bv_type != BVAL_NR
+ || vp[2].bv_type != BVAL_NR
+ || vp[3].bv_type != BVAL_NR
+ || vp[4].bv_type != BVAL_STRING)
+ return;
+
+ name = vp[0].bv_nr;
+ if (name != '\'' && !VIM_ISDIGIT(name) && !ASCII_ISUPPER(name))
+ return;
+ lnum = vp[1].bv_nr;
+ col = vp[2].bv_nr;
+ if (lnum <= 0 || col < 0)
+ return;
+ timestamp = (time_t)vp[3].bv_nr;
+
+ if (name == '\'')
+ {
+#ifdef FEAT_JUMPLIST
+ if (vi_jumplist != NULL)
+ {
+ if (vi_jumplist_len < JUMPLISTSIZE)
+ fm = &vi_jumplist[vi_jumplist_len++];
+ }
+ else
+ {
+ int idx;
+ int i;
+
+ /* If we have a timestamp insert it in the right place. */
+ if (timestamp != 0)
+ {
+ for (idx = curwin->w_jumplistlen - 1; idx >= 0; --idx)
+ if (curwin->w_jumplist[idx].time_set < timestamp)
+ {
+ ++idx;
+ break;
+ }
+ /* idx cannot be zero now */
+ if (idx < 0 && curwin->w_jumplistlen < JUMPLISTSIZE)
+ /* insert as the oldest entry */
+ idx = 0;
+ }
+ else if (curwin->w_jumplistlen < JUMPLISTSIZE)
+ /* insert as oldest entry */
+ idx = 0;
+ else
+ idx = -1;
+
+ if (idx >= 0)
+ {
+ if (curwin->w_jumplistlen == JUMPLISTSIZE)
+ {
+ /* Drop the oldest entry. */
+ --idx;
+ vim_free(curwin->w_jumplist[0].fname);
+ for (i = 0; i < idx; ++i)
+ curwin->w_jumplist[i] = curwin->w_jumplist[i + 1];
+ }
+ else
+ {
+ /* Move newer entries forward. */
+ for (i = curwin->w_jumplistlen; i > idx; --i)
+ curwin->w_jumplist[i] = curwin->w_jumplist[i - 1];
+ ++curwin->w_jumplistidx;
+ ++curwin->w_jumplistlen;
+ }
+ fm = &curwin->w_jumplist[idx];
+ fm->fmark.mark.lnum = 0;
+ fm->fname = NULL;
+ fm->time_set = 0;
+ }
+ }
+#endif
+ }
+ else
+ {
+ int idx;
+
+ if (VIM_ISDIGIT(name))
+ {
+ if (vi_namedfm != NULL)
+ idx = name - '0' + NMARKS;
+ else
+ {
+ int i;
+
+ /* Do not use the name from the viminfo file, insert in time
+ * order. */
+ for (idx = NMARKS; idx < NMARKS + EXTRA_MARKS; ++idx)
+ if (namedfm[idx].time_set < timestamp)
+ break;
+ if (idx == NMARKS + EXTRA_MARKS)
+ /* All existing entries are newer. */
+ return;
+ i = NMARKS + EXTRA_MARKS - 1;
+
+ vim_free(namedfm[i].fname);
+ for ( ; i > idx; --i)
+ namedfm[i] = namedfm[i - 1];
+ namedfm[idx].fname = NULL;
+ }
+ }
+ else
+ idx = name - 'A';
+ if (vi_namedfm != NULL)
+ fm = &vi_namedfm[idx];
+ else
+ fm = &namedfm[idx];
+ }
+
+ if (fm != NULL)
+ {
+ if (vi_namedfm != NULL || fm->fmark.mark.lnum == 0
+ || fm->time_set < timestamp || force)
+ {
+ fm->fmark.mark.lnum = lnum;
+ fm->fmark.mark.col = col;
+ fm->fmark.mark.coladd = 0;
+ fm->fmark.fnum = 0;
+ vim_free(fm->fname);
+ if (vp[4].bv_allocated)
+ {
+ fm->fname = vp[4].bv_string;
+ vp[4].bv_string = NULL;
+ }
+ else
+ fm->fname = vim_strsave(vp[4].bv_string);
+ fm->time_set = timestamp;
+ }
+ }
+}
+
+/*
+ * Return TRUE if marks for "buf" should not be written.
+ */
+ static int
+skip_for_viminfo(buf_T *buf)
+{
+ return
+#ifdef FEAT_TERMINAL
+ bt_terminal(buf) ||
+#endif
+ removable(buf->b_ffname);
+}
+
+ void
+write_viminfo_filemarks(FILE *fp)
+{
+ int i;
+ char_u *name;
+ buf_T *buf;
+ xfmark_T *fm;
+ int vi_idx;
+ int idx;
+
+ if (get_viminfo_parameter('f') == 0)
+ return;
+
+ fputs(_("\n# File marks:\n"), fp);
+
+ /* Write the filemarks 'A - 'Z */
+ for (i = 0; i < NMARKS; i++)
+ {
+ if (vi_namedfm != NULL && (vi_namedfm[i].time_set > namedfm[i].time_set
+ || namedfm[i].fmark.mark.lnum == 0))
+ fm = &vi_namedfm[i];
+ else
+ fm = &namedfm[i];
+ write_one_filemark(fp, fm, '\'', i + 'A');
+ }
+
+ /*
+ * Find a mark that is the same file and position as the cursor.
+ * That one, or else the last one is deleted.
+ * Move '0 to '1, '1 to '2, etc. until the matching one or '9
+ * Set the '0 mark to current cursor position.
+ */
+ if (curbuf->b_ffname != NULL && !skip_for_viminfo(curbuf))
+ {
+ name = buflist_nr2name(curbuf->b_fnum, TRUE, FALSE);
+ for (i = NMARKS; i < NMARKS + EXTRA_MARKS - 1; ++i)
+ if (namedfm[i].fmark.mark.lnum == curwin->w_cursor.lnum
+ && (namedfm[i].fname == NULL
+ ? namedfm[i].fmark.fnum == curbuf->b_fnum
+ : (name != NULL
+ && STRCMP(name, namedfm[i].fname) == 0)))
+ break;
+ vim_free(name);
+
+ vim_free(namedfm[i].fname);
+ for ( ; i > NMARKS; --i)
+ namedfm[i] = namedfm[i - 1];
+ namedfm[NMARKS].fmark.mark = curwin->w_cursor;
+ namedfm[NMARKS].fmark.fnum = curbuf->b_fnum;
+ namedfm[NMARKS].fname = NULL;
+ namedfm[NMARKS].time_set = vim_time();
+ }
+
+ /* Write the filemarks '0 - '9. Newest (highest timestamp) first. */
+ vi_idx = NMARKS;
+ idx = NMARKS;
+ for (i = NMARKS; i < NMARKS + EXTRA_MARKS; i++)
+ {
+ xfmark_T *vi_fm = vi_namedfm != NULL ? &vi_namedfm[vi_idx] : NULL;
+
+ if (vi_fm != NULL
+ && vi_fm->fmark.mark.lnum != 0
+ && (vi_fm->time_set > namedfm[idx].time_set
+ || namedfm[idx].fmark.mark.lnum == 0))
+ {
+ fm = vi_fm;
+ ++vi_idx;
+ }
+ else
+ {
+ fm = &namedfm[idx++];
+ if (vi_fm != NULL
+ && vi_fm->fmark.mark.lnum == fm->fmark.mark.lnum
+ && vi_fm->time_set == fm->time_set
+ && ((vi_fm->fmark.fnum != 0
+ && vi_fm->fmark.fnum == fm->fmark.fnum)
+ || (vi_fm->fname != NULL
+ && fm->fname != NULL
+ && STRCMP(vi_fm->fname, fm->fname) == 0)))
+ ++vi_idx; /* skip duplicate */
+ }
+ write_one_filemark(fp, fm, '\'', i - NMARKS + '0');
+ }
+
+#ifdef FEAT_JUMPLIST
+ /* Write the jumplist with -' */
+ fputs(_("\n# Jumplist (newest first):\n"), fp);
+ setpcmark(); /* add current cursor position */
+ cleanup_jumplist(curwin, FALSE);
+ vi_idx = 0;
+ idx = curwin->w_jumplistlen - 1;
+ for (i = 0; i < JUMPLISTSIZE; ++i)
+ {
+ xfmark_T *vi_fm;
+
+ fm = idx >= 0 ? &curwin->w_jumplist[idx] : NULL;
+ vi_fm = vi_idx < vi_jumplist_len ? &vi_jumplist[vi_idx] : NULL;
+ if (fm == NULL && vi_fm == NULL)
+ break;
+ if (fm == NULL || (vi_fm != NULL && fm->time_set < vi_fm->time_set))
+ {
+ fm = vi_fm;
+ ++vi_idx;
+ }
+ else
+ --idx;
+ if (fm->fmark.fnum == 0
+ || ((buf = buflist_findnr(fm->fmark.fnum)) != NULL
+ && !skip_for_viminfo(buf)))
+ write_one_filemark(fp, fm, '-', '\'');
+ }
+#endif
+}
+
+ static void
+write_one_filemark(
+ FILE *fp,
+ xfmark_T *fm,
+ int c1,
+ int c2)
+{
+ char_u *name;
+
+ if (fm->fmark.mark.lnum == 0) /* not set */
+ return;
+
+ if (fm->fmark.fnum != 0) /* there is a buffer */
+ name = buflist_nr2name(fm->fmark.fnum, TRUE, FALSE);
+ else
+ name = fm->fname; /* use name from .viminfo */
+ if (name != NULL && *name != NUL)
+ {
+ fprintf(fp, "%c%c %ld %ld ", c1, c2, (long)fm->fmark.mark.lnum,
+ (long)fm->fmark.mark.col);
+ viminfo_writestring(fp, name);
+
+ /* Barline: |{bartype},{name},{lnum},{col},{timestamp},{filename}
+ * size up to filename: 8 + 3 * 20 */
+ fprintf(fp, "|%d,%d,%ld,%ld,%ld,", BARTYPE_MARK, c2,
+ (long)fm->fmark.mark.lnum, (long)fm->fmark.mark.col,
+ (long)fm->time_set);
+ barline_writestring(fp, name, LSIZE - 70);
+ putc('\n', fp);
+ }
+
+ if (fm->fmark.fnum != 0)
+ vim_free(name);
+}
+
+/*
+ * Return TRUE if "name" is on removable media (depending on 'viminfo').
+ */
+ int
+removable(char_u *name)
+{
+ char_u *p;
+ char_u part[51];
+ int retval = FALSE;
+ size_t n;
+
+ name = home_replace_save(NULL, name);
+ if (name != NULL)
+ {
+ for (p = p_viminfo; *p; )
+ {
+ copy_option_part(&p, part, 51, ", ");
+ if (part[0] == 'r')
+ {
+ n = STRLEN(part + 1);
+ if (MB_STRNICMP(part + 1, name, n) == 0)
+ {
+ retval = TRUE;
+ break;
+ }
+ }
+ }
+ vim_free(name);
+ }
+ return retval;
+}
+
+ static void
+write_one_mark(FILE *fp_out, int c, pos_T *pos)
+{
+ if (pos->lnum != 0)
+ fprintf(fp_out, "\t%c\t%ld\t%d\n", c, (long)pos->lnum, (int)pos->col);
+}
+
+
+ static void
+write_buffer_marks(buf_T *buf, FILE *fp_out)
+{
+ int i;
+ pos_T pos;
+
+ home_replace(NULL, buf->b_ffname, IObuff, IOSIZE, TRUE);
+ fprintf(fp_out, "\n> ");
+ viminfo_writestring(fp_out, IObuff);
+
+ /* Write the last used timestamp as the lnum of the non-existing mark '*'.
+ * Older Vims will ignore it and/or copy it. */
+ pos.lnum = (linenr_T)buf->b_last_used;
+ pos.col = 0;
+ write_one_mark(fp_out, '*', &pos);
+
+ write_one_mark(fp_out, '"', &buf->b_last_cursor);
+ write_one_mark(fp_out, '^', &buf->b_last_insert);
+ write_one_mark(fp_out, '.', &buf->b_last_change);
+#ifdef FEAT_JUMPLIST
+ /* changelist positions are stored oldest first */
+ for (i = 0; i < buf->b_changelistlen; ++i)
+ {
+ /* skip duplicates */
+ if (i == 0 || !EQUAL_POS(buf->b_changelist[i - 1],
+ buf->b_changelist[i]))
+ write_one_mark(fp_out, '+', &buf->b_changelist[i]);
+ }
+#endif
+ for (i = 0; i < NMARKS; i++)
+ write_one_mark(fp_out, 'a' + i, &buf->b_namedm[i]);
+}
+
+/*
+ * Write all the named marks for all buffers.
+ * When "buflist" is not NULL fill it with the buffers for which marks are to
+ * be written.
+ */
+ void
+write_viminfo_marks(FILE *fp_out, garray_T *buflist)
+{
+ buf_T *buf;
+ int is_mark_set;
+ int i;
+ win_T *win;
+ tabpage_T *tp;
+
+ /*
+ * Set b_last_cursor for the all buffers that have a window.
+ */
+ FOR_ALL_TAB_WINDOWS(tp, win)
+ set_last_cursor(win);
+
+ fputs(_("\n# History of marks within files (newest to oldest):\n"), fp_out);
+ FOR_ALL_BUFFERS(buf)
+ {
+ /*
+ * Only write something if buffer has been loaded and at least one
+ * mark is set.
+ */
+ if (buf->b_marks_read)
+ {
+ if (buf->b_last_cursor.lnum != 0)
+ is_mark_set = TRUE;
+ else
+ {
+ is_mark_set = FALSE;
+ for (i = 0; i < NMARKS; i++)
+ if (buf->b_namedm[i].lnum != 0)
+ {
+ is_mark_set = TRUE;
+ break;
+ }
+ }
+ if (is_mark_set && buf->b_ffname != NULL
+ && buf->b_ffname[0] != NUL
+ && !skip_for_viminfo(buf))
+ {
+ if (buflist == NULL)
+ write_buffer_marks(buf, fp_out);
+ else if (ga_grow(buflist, 1) == OK)
+ ((buf_T **)buflist->ga_data)[buflist->ga_len++] = buf;
+ }
+ }
+ }
+}
+
+/*
+ * Compare functions for qsort() below, that compares b_last_used.
+ */
+ static int
+#ifdef __BORLANDC__
+_RTLENTRYF
+#endif
+buf_compare(const void *s1, const void *s2)
+{
+ buf_T *buf1 = *(buf_T **)s1;
+ buf_T *buf2 = *(buf_T **)s2;
+
+ if (buf1->b_last_used == buf2->b_last_used)
+ return 0;
+ return buf1->b_last_used > buf2->b_last_used ? -1 : 1;
+}
+
+/*
+ * Handle marks in the viminfo file:
+ * fp_out != NULL: copy marks, in time order with buffers in "buflist".
+ * fp_out == NULL && (flags & VIF_WANT_MARKS): read marks for curbuf only
+ * fp_out == NULL && (flags & VIF_GET_OLDFILES | VIF_FORCEIT): fill v:oldfiles
+ */
+ void
+copy_viminfo_marks(
+ vir_T *virp,
+ FILE *fp_out,
+ garray_T *buflist,
+ int eof,
+ int flags)
+{
+ char_u *line = virp->vir_line;
+ buf_T *buf;
+ int num_marked_files;
+ int load_marks;
+ int copy_marks_out;
+ char_u *str;
+ int i;
+ char_u *p;
+ char_u *name_buf;
+ pos_T pos;
+#ifdef FEAT_EVAL
+ list_T *list = NULL;
+#endif
+ int count = 0;
+ int buflist_used = 0;
+ buf_T *buflist_buf = NULL;
+
+ if ((name_buf = alloc(LSIZE)) == NULL)
+ return;
+ *name_buf = NUL;
+
+ if (fp_out != NULL && buflist->ga_len > 0)
+ {
+ /* Sort the list of buffers on b_last_used. */
+ qsort(buflist->ga_data, (size_t)buflist->ga_len,
+ sizeof(buf_T *), buf_compare);
+ buflist_buf = ((buf_T **)buflist->ga_data)[0];
+ }
+
+#ifdef FEAT_EVAL
+ if (fp_out == NULL && (flags & (VIF_GET_OLDFILES | VIF_FORCEIT)))
+ {
+ list = list_alloc();
+ if (list != NULL)
+ set_vim_var_list(VV_OLDFILES, list);
+ }
+#endif
+
+ num_marked_files = get_viminfo_parameter('\'');
+ while (!eof && (count < num_marked_files || fp_out == NULL))
+ {
+ if (line[0] != '>')
+ {
+ if (line[0] != '\n' && line[0] != '\r' && line[0] != '#')
+ {
+ if (viminfo_error("E576: ", _("Missing '>'"), line))
+ break; /* too many errors, return now */
+ }
+ eof = vim_fgets(line, LSIZE, virp->vir_fd);
+ continue; /* Skip this dud line */
+ }
+
+ /*
+ * Handle long line and translate escaped characters.
+ * Find file name, set str to start.
+ * Ignore leading and trailing white space.
+ */
+ str = skipwhite(line + 1);
+ str = viminfo_readstring(virp, (int)(str - virp->vir_line), FALSE);
+ if (str == NULL)
+ continue;
+ p = str + STRLEN(str);
+ while (p != str && (*p == NUL || vim_isspace(*p)))
+ p--;
+ if (*p)
+ p++;
+ *p = NUL;
+
+#ifdef FEAT_EVAL
+ if (list != NULL)
+ list_append_string(list, str, -1);
+#endif
+
+ /*
+ * If fp_out == NULL, load marks for current buffer.
+ * If fp_out != NULL, copy marks for buffers not in buflist.
+ */
+ load_marks = copy_marks_out = FALSE;
+ if (fp_out == NULL)
+ {
+ if ((flags & VIF_WANT_MARKS) && curbuf->b_ffname != NULL)
+ {
+ if (*name_buf == NUL) /* only need to do this once */
+ home_replace(NULL, curbuf->b_ffname, name_buf, LSIZE, TRUE);
+ if (fnamecmp(str, name_buf) == 0)
+ load_marks = TRUE;
+ }
+ }
+ else /* fp_out != NULL */
+ {
+ /* This is slow if there are many buffers!! */
+ FOR_ALL_BUFFERS(buf)
+ if (buf->b_ffname != NULL)
+ {
+ home_replace(NULL, buf->b_ffname, name_buf, LSIZE, TRUE);
+ if (fnamecmp(str, name_buf) == 0)
+ break;
+ }
+
+ /*
+ * Copy marks if the buffer has not been loaded.
+ */
+ if (buf == NULL || !buf->b_marks_read)
+ {
+ int did_read_line = FALSE;
+
+ if (buflist_buf != NULL)
+ {
+ /* Read the next line. If it has the "*" mark compare the
+ * time stamps. Write entries from "buflist" that are
+ * newer. */
+ if (!(eof = viminfo_readline(virp)) && line[0] == TAB)
+ {
+ did_read_line = TRUE;
+ if (line[1] == '*')
+ {
+ long ltime;
+
+ sscanf((char *)line + 2, "%ld ", &ltime);
+ while ((time_T)ltime < buflist_buf->b_last_used)
+ {
+ write_buffer_marks(buflist_buf, fp_out);
+ if (++count >= num_marked_files)
+ break;
+ if (++buflist_used == buflist->ga_len)
+ {
+ buflist_buf = NULL;
+ break;
+ }
+ buflist_buf =
+ ((buf_T **)buflist->ga_data)[buflist_used];
+ }
+ }
+ else
+ {
+ /* No timestamp, must be written by an older Vim.
+ * Assume all remaining buffers are older then
+ * ours. */
+ while (count < num_marked_files
+ && buflist_used < buflist->ga_len)
+ {
+ buflist_buf = ((buf_T **)buflist->ga_data)
+ [buflist_used++];
+ write_buffer_marks(buflist_buf, fp_out);
+ ++count;
+ }
+ buflist_buf = NULL;
+ }
+
+ if (count >= num_marked_files)
+ {
+ vim_free(str);
+ break;
+ }
+ }
+ }
+
+ fputs("\n> ", fp_out);
+ viminfo_writestring(fp_out, str);
+ if (did_read_line)
+ fputs((char *)line, fp_out);
+
+ count++;
+ copy_marks_out = TRUE;
+ }
+ }
+ vim_free(str);
+
+ pos.coladd = 0;
+ while (!(eof = viminfo_readline(virp)) && line[0] == TAB)
+ {
+ if (load_marks)
+ {
+ if (line[1] != NUL)
+ {
+ unsigned u;
+
+ sscanf((char *)line + 2, "%ld %u", &pos.lnum, &u);
+ pos.col = u;
+ switch (line[1])
+ {
+ case '"': curbuf->b_last_cursor = pos; break;
+ case '^': curbuf->b_last_insert = pos; break;
+ case '.': curbuf->b_last_change = pos; break;
+ case '+':
+#ifdef FEAT_JUMPLIST
+ /* changelist positions are stored oldest
+ * first */
+ if (curbuf->b_changelistlen == JUMPLISTSIZE)
+ /* list is full, remove oldest entry */
+ mch_memmove(curbuf->b_changelist,
+ curbuf->b_changelist + 1,
+ sizeof(pos_T) * (JUMPLISTSIZE - 1));
+ else
+ ++curbuf->b_changelistlen;
+ curbuf->b_changelist[
+ curbuf->b_changelistlen - 1] = pos;
+#endif
+ break;
+
+ /* Using the line number for the last-used
+ * timestamp. */
+ case '*': curbuf->b_last_used = pos.lnum; break;
+
+ default: if ((i = line[1] - 'a') >= 0 && i < NMARKS)
+ curbuf->b_namedm[i] = pos;
+ }
+ }
+ }
+ else if (copy_marks_out)
+ fputs((char *)line, fp_out);
+ }
+
+ if (load_marks)
+ {
+#ifdef FEAT_JUMPLIST
+ win_T *wp;
+
+ FOR_ALL_WINDOWS(wp)
+ {
+ if (wp->w_buffer == curbuf)
+ wp->w_changelistidx = curbuf->b_changelistlen;
+ }
+#endif
+ break;
+ }
+ }
+
+ if (fp_out != NULL)
+ /* Write any remaining entries from buflist. */
+ while (count < num_marked_files && buflist_used < buflist->ga_len)
+ {
+ buflist_buf = ((buf_T **)buflist->ga_data)[buflist_used++];
+ write_buffer_marks(buflist_buf, fp_out);
+ ++count;
+ }
+
+ vim_free(name_buf);
+}
+#endif /* FEAT_VIMINFO */
diff --git a/src/mbyte.c b/src/mbyte.c
new file mode 100644
index 0000000..aa10d5e
--- /dev/null
+++ b/src/mbyte.c
@@ -0,0 +1,6936 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ * Multibyte extensions partly by Sung-Hoon Baek
+ *
+ * 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.
+ */
+/*
+ * mbyte.c: Code specifically for handling multi-byte characters.
+ *
+ * The encoding used in the core is set with 'encoding'. When 'encoding' is
+ * changed, the following four variables are set (for speed).
+ * Currently these types of character encodings are supported:
+ *
+ * "enc_dbcs" When non-zero it tells the type of double byte character
+ * encoding (Chinese, Korean, Japanese, etc.).
+ * The cell width on the display is equal to the number of
+ * bytes. (exception: DBCS_JPNU with first byte 0x8e)
+ * Recognizing the first or second byte is difficult, it
+ * requires checking a byte sequence from the start.
+ * "enc_utf8" When TRUE use Unicode characters in UTF-8 encoding.
+ * The cell width on the display needs to be determined from
+ * the character value.
+ * Recognizing bytes is easy: 0xxx.xxxx is a single-byte
+ * char, 10xx.xxxx is a trailing byte, 11xx.xxxx is a leading
+ * byte of a multi-byte character.
+ * To make things complicated, up to six composing characters
+ * are allowed. These are drawn on top of the first char.
+ * For most editing the sequence of bytes with composing
+ * characters included is considered to be one character.
+ * "enc_unicode" When 2 use 16-bit Unicode characters (or UTF-16).
+ * When 4 use 32-but Unicode characters.
+ * Internally characters are stored in UTF-8 encoding to
+ * avoid NUL bytes. Conversion happens when doing I/O.
+ * "enc_utf8" will also be TRUE.
+ *
+ * "has_mbyte" is set when "enc_dbcs" or "enc_utf8" is non-zero.
+ *
+ * If none of these is TRUE, 8-bit bytes are used for a character. The
+ * encoding isn't currently specified (TODO).
+ *
+ * 'encoding' specifies the encoding used in the core. This is in registers,
+ * text manipulation, buffers, etc. Conversion has to be done when characters
+ * in another encoding are received or send:
+ *
+ * clipboard
+ * ^
+ * | (2)
+ * V
+ * +---------------+
+ * (1) | | (3)
+ * keyboard ----->| core |-----> display
+ * | |
+ * +---------------+
+ * ^
+ * | (4)
+ * V
+ * file
+ *
+ * (1) Typed characters arrive in the current locale. Conversion is to be
+ * done when 'encoding' is different from 'termencoding'.
+ * (2) Text will be made available with the encoding specified with
+ * 'encoding'. If this is not sufficient, system-specific conversion
+ * might be required.
+ * (3) For the GUI the correct font must be selected, no conversion done.
+ * Otherwise, conversion is to be done when 'encoding' differs from
+ * 'termencoding'. (Different in the GTK+ 2 port -- 'termencoding'
+ * is always used for both input and output and must always be set to
+ * "utf-8". gui_mch_init() does this automatically.)
+ * (4) The encoding of the file is specified with 'fileencoding'. Conversion
+ * is to be done when it's different from 'encoding'.
+ *
+ * The viminfo file is a special case: Only text is converted, not file names.
+ * Vim scripts may contain an ":encoding" command. This has an effect for
+ * some commands, like ":menutrans"
+ */
+
+#include "vim.h"
+
+#ifdef WIN32UNIX
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+# endif
+# if defined(FEAT_GUI) || defined(FEAT_XCLIPBOARD)
+# include <X11/Xwindows.h>
+# define WINBYTE wBYTE
+# else
+# include <windows.h>
+# define WINBYTE BYTE
+# endif
+# ifdef WIN32
+# undef WIN32 /* Some windows.h define WIN32, we don't want that here. */
+# endif
+#else
+# define WINBYTE BYTE
+#endif
+
+#if (defined(WIN3264) || defined(WIN32UNIX)) && !defined(__MINGW32__)
+# include <winnls.h>
+#endif
+
+#ifdef FEAT_GUI_X11
+# include <X11/Intrinsic.h>
+#endif
+#ifdef X_LOCALE
+# include <X11/Xlocale.h>
+# if !defined(HAVE_MBLEN) && !defined(mblen)
+# define mblen _Xmblen
+# endif
+#endif
+
+#if defined(FEAT_GUI_GTK) && defined(FEAT_XIM)
+# if GTK_CHECK_VERSION(3,0,0)
+# include <gdk/gdkkeysyms-compat.h>
+# else
+# include <gdk/gdkkeysyms.h>
+# endif
+# ifdef WIN3264
+# include <gdk/gdkwin32.h>
+# else
+# include <gdk/gdkx.h>
+# endif
+#endif
+
+#ifdef HAVE_WCHAR_H
+# include <wchar.h>
+#endif
+
+#if 0
+/* This has been disabled, because several people reported problems with the
+ * wcwidth() and iswprint() library functions, esp. for Hebrew. */
+# ifdef __STDC_ISO_10646__
+# define USE_WCHAR_FUNCTIONS
+# endif
+#endif
+
+static int dbcs_char2len(int c);
+static int dbcs_char2bytes(int c, char_u *buf);
+static int dbcs_ptr2len(char_u *p);
+static int dbcs_ptr2len_len(char_u *p, int size);
+static int utf_ptr2cells_len(char_u *p, int size);
+static int dbcs_char2cells(int c);
+static int dbcs_ptr2cells_len(char_u *p, int size);
+static int dbcs_ptr2char(char_u *p);
+
+/*
+ * Lookup table to quickly get the length in bytes of a UTF-8 character from
+ * the first byte of a UTF-8 string.
+ * Bytes which are illegal when used as the first byte have a 1.
+ * The NUL byte has length 1.
+ */
+static char utf8len_tab[256] =
+{
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+ 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1,
+};
+
+/*
+ * Like utf8len_tab above, but using a zero for illegal lead bytes.
+ */
+static char utf8len_tab_zero[256] =
+{
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+ 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,0,0,
+};
+
+/*
+ * XIM often causes trouble. Define XIM_DEBUG to get a log of XIM callbacks
+ * in the "xim.log" file.
+ */
+/* #define XIM_DEBUG */
+#ifdef XIM_DEBUG
+ static void
+xim_log(char *s, ...)
+{
+ va_list arglist;
+ static FILE *fd = NULL;
+
+ if (fd == (FILE *)-1)
+ return;
+ if (fd == NULL)
+ {
+ fd = mch_fopen("xim.log", "w");
+ if (fd == NULL)
+ {
+ emsg("Cannot open xim.log");
+ fd = (FILE *)-1;
+ return;
+ }
+ }
+
+ va_start(arglist, s);
+ vfprintf(fd, s, arglist);
+ va_end(arglist);
+}
+#endif
+
+
+/*
+ * Canonical encoding names and their properties.
+ * "iso-8859-n" is handled by enc_canonize() directly.
+ */
+static struct
+{ char *name; int prop; int codepage;}
+enc_canon_table[] =
+{
+#define IDX_LATIN_1 0
+ {"latin1", ENC_8BIT + ENC_LATIN1, 1252},
+#define IDX_ISO_2 1
+ {"iso-8859-2", ENC_8BIT, 0},
+#define IDX_ISO_3 2
+ {"iso-8859-3", ENC_8BIT, 0},
+#define IDX_ISO_4 3
+ {"iso-8859-4", ENC_8BIT, 0},
+#define IDX_ISO_5 4
+ {"iso-8859-5", ENC_8BIT, 0},
+#define IDX_ISO_6 5
+ {"iso-8859-6", ENC_8BIT, 0},
+#define IDX_ISO_7 6
+ {"iso-8859-7", ENC_8BIT, 0},
+#define IDX_ISO_8 7
+ {"iso-8859-8", ENC_8BIT, 0},
+#define IDX_ISO_9 8
+ {"iso-8859-9", ENC_8BIT, 0},
+#define IDX_ISO_10 9
+ {"iso-8859-10", ENC_8BIT, 0},
+#define IDX_ISO_11 10
+ {"iso-8859-11", ENC_8BIT, 0},
+#define IDX_ISO_13 11
+ {"iso-8859-13", ENC_8BIT, 0},
+#define IDX_ISO_14 12
+ {"iso-8859-14", ENC_8BIT, 0},
+#define IDX_ISO_15 13
+ {"iso-8859-15", ENC_8BIT + ENC_LATIN9, 0},
+#define IDX_KOI8_R 14
+ {"koi8-r", ENC_8BIT, 0},
+#define IDX_KOI8_U 15
+ {"koi8-u", ENC_8BIT, 0},
+#define IDX_UTF8 16
+ {"utf-8", ENC_UNICODE, 0},
+#define IDX_UCS2 17
+ {"ucs-2", ENC_UNICODE + ENC_ENDIAN_B + ENC_2BYTE, 0},
+#define IDX_UCS2LE 18
+ {"ucs-2le", ENC_UNICODE + ENC_ENDIAN_L + ENC_2BYTE, 0},
+#define IDX_UTF16 19
+ {"utf-16", ENC_UNICODE + ENC_ENDIAN_B + ENC_2WORD, 0},
+#define IDX_UTF16LE 20
+ {"utf-16le", ENC_UNICODE + ENC_ENDIAN_L + ENC_2WORD, 0},
+#define IDX_UCS4 21
+ {"ucs-4", ENC_UNICODE + ENC_ENDIAN_B + ENC_4BYTE, 0},
+#define IDX_UCS4LE 22
+ {"ucs-4le", ENC_UNICODE + ENC_ENDIAN_L + ENC_4BYTE, 0},
+
+ /* For debugging DBCS encoding on Unix. */
+#define IDX_DEBUG 23
+ {"debug", ENC_DBCS, DBCS_DEBUG},
+#define IDX_EUC_JP 24
+ {"euc-jp", ENC_DBCS, DBCS_JPNU},
+#define IDX_SJIS 25
+ {"sjis", ENC_DBCS, DBCS_JPN},
+#define IDX_EUC_KR 26
+ {"euc-kr", ENC_DBCS, DBCS_KORU},
+#define IDX_EUC_CN 27
+ {"euc-cn", ENC_DBCS, DBCS_CHSU},
+#define IDX_EUC_TW 28
+ {"euc-tw", ENC_DBCS, DBCS_CHTU},
+#define IDX_BIG5 29
+ {"big5", ENC_DBCS, DBCS_CHT},
+
+ /* MS-DOS and MS-Windows codepages are included here, so that they can be
+ * used on Unix too. Most of them are similar to ISO-8859 encodings, but
+ * not exactly the same. */
+#define IDX_CP437 30
+ {"cp437", ENC_8BIT, 437}, /* like iso-8859-1 */
+#define IDX_CP737 31
+ {"cp737", ENC_8BIT, 737}, /* like iso-8859-7 */
+#define IDX_CP775 32
+ {"cp775", ENC_8BIT, 775}, /* Baltic */
+#define IDX_CP850 33
+ {"cp850", ENC_8BIT, 850}, /* like iso-8859-4 */
+#define IDX_CP852 34
+ {"cp852", ENC_8BIT, 852}, /* like iso-8859-1 */
+#define IDX_CP855 35
+ {"cp855", ENC_8BIT, 855}, /* like iso-8859-2 */
+#define IDX_CP857 36
+ {"cp857", ENC_8BIT, 857}, /* like iso-8859-5 */
+#define IDX_CP860 37
+ {"cp860", ENC_8BIT, 860}, /* like iso-8859-9 */
+#define IDX_CP861 38
+ {"cp861", ENC_8BIT, 861}, /* like iso-8859-1 */
+#define IDX_CP862 39
+ {"cp862", ENC_8BIT, 862}, /* like iso-8859-1 */
+#define IDX_CP863 40
+ {"cp863", ENC_8BIT, 863}, /* like iso-8859-8 */
+#define IDX_CP865 41
+ {"cp865", ENC_8BIT, 865}, /* like iso-8859-1 */
+#define IDX_CP866 42
+ {"cp866", ENC_8BIT, 866}, /* like iso-8859-5 */
+#define IDX_CP869 43
+ {"cp869", ENC_8BIT, 869}, /* like iso-8859-7 */
+#define IDX_CP874 44
+ {"cp874", ENC_8BIT, 874}, /* Thai */
+#define IDX_CP932 45
+ {"cp932", ENC_DBCS, DBCS_JPN},
+#define IDX_CP936 46
+ {"cp936", ENC_DBCS, DBCS_CHS},
+#define IDX_CP949 47
+ {"cp949", ENC_DBCS, DBCS_KOR},
+#define IDX_CP950 48
+ {"cp950", ENC_DBCS, DBCS_CHT},
+#define IDX_CP1250 49
+ {"cp1250", ENC_8BIT, 1250}, /* Czech, Polish, etc. */
+#define IDX_CP1251 50
+ {"cp1251", ENC_8BIT, 1251}, /* Cyrillic */
+ /* cp1252 is considered to be equal to latin1 */
+#define IDX_CP1253 51
+ {"cp1253", ENC_8BIT, 1253}, /* Greek */
+#define IDX_CP1254 52
+ {"cp1254", ENC_8BIT, 1254}, /* Turkish */
+#define IDX_CP1255 53
+ {"cp1255", ENC_8BIT, 1255}, /* Hebrew */
+#define IDX_CP1256 54
+ {"cp1256", ENC_8BIT, 1256}, /* Arabic */
+#define IDX_CP1257 55
+ {"cp1257", ENC_8BIT, 1257}, /* Baltic */
+#define IDX_CP1258 56
+ {"cp1258", ENC_8BIT, 1258}, /* Vietnamese */
+
+#define IDX_MACROMAN 57
+ {"macroman", ENC_8BIT + ENC_MACROMAN, 0}, /* Mac OS */
+#define IDX_DECMCS 58
+ {"dec-mcs", ENC_8BIT, 0}, /* DEC MCS */
+#define IDX_HPROMAN8 59
+ {"hp-roman8", ENC_8BIT, 0}, /* HP Roman8 */
+#define IDX_COUNT 60
+};
+
+/*
+ * Aliases for encoding names.
+ */
+static struct
+{ char *name; int canon;}
+enc_alias_table[] =
+{
+ {"ansi", IDX_LATIN_1},
+ {"iso-8859-1", IDX_LATIN_1},
+ {"latin2", IDX_ISO_2},
+ {"latin3", IDX_ISO_3},
+ {"latin4", IDX_ISO_4},
+ {"cyrillic", IDX_ISO_5},
+ {"arabic", IDX_ISO_6},
+ {"greek", IDX_ISO_7},
+#ifdef WIN3264
+ {"hebrew", IDX_CP1255},
+#else
+ {"hebrew", IDX_ISO_8},
+#endif
+ {"latin5", IDX_ISO_9},
+ {"turkish", IDX_ISO_9}, /* ? */
+ {"latin6", IDX_ISO_10},
+ {"nordic", IDX_ISO_10}, /* ? */
+ {"thai", IDX_ISO_11}, /* ? */
+ {"latin7", IDX_ISO_13},
+ {"latin8", IDX_ISO_14},
+ {"latin9", IDX_ISO_15},
+ {"utf8", IDX_UTF8},
+ {"unicode", IDX_UCS2},
+ {"ucs2", IDX_UCS2},
+ {"ucs2be", IDX_UCS2},
+ {"ucs-2be", IDX_UCS2},
+ {"ucs2le", IDX_UCS2LE},
+ {"utf16", IDX_UTF16},
+ {"utf16be", IDX_UTF16},
+ {"utf-16be", IDX_UTF16},
+ {"utf16le", IDX_UTF16LE},
+ {"ucs4", IDX_UCS4},
+ {"ucs4be", IDX_UCS4},
+ {"ucs-4be", IDX_UCS4},
+ {"ucs4le", IDX_UCS4LE},
+ {"utf32", IDX_UCS4},
+ {"utf-32", IDX_UCS4},
+ {"utf32be", IDX_UCS4},
+ {"utf-32be", IDX_UCS4},
+ {"utf32le", IDX_UCS4LE},
+ {"utf-32le", IDX_UCS4LE},
+ {"932", IDX_CP932},
+ {"949", IDX_CP949},
+ {"936", IDX_CP936},
+ {"gbk", IDX_CP936},
+ {"950", IDX_CP950},
+ {"eucjp", IDX_EUC_JP},
+ {"unix-jis", IDX_EUC_JP},
+ {"ujis", IDX_EUC_JP},
+ {"shift-jis", IDX_SJIS},
+ {"pck", IDX_SJIS}, /* Sun: PCK */
+ {"euckr", IDX_EUC_KR},
+ {"5601", IDX_EUC_KR}, /* Sun: KS C 5601 */
+ {"euccn", IDX_EUC_CN},
+ {"gb2312", IDX_EUC_CN},
+ {"euctw", IDX_EUC_TW},
+#if defined(WIN3264) || defined(WIN32UNIX) || defined(MACOS_X)
+ {"japan", IDX_CP932},
+ {"korea", IDX_CP949},
+ {"prc", IDX_CP936},
+ {"chinese", IDX_CP936},
+ {"taiwan", IDX_CP950},
+ {"big5", IDX_CP950},
+#else
+ {"japan", IDX_EUC_JP},
+ {"korea", IDX_EUC_KR},
+ {"prc", IDX_EUC_CN},
+ {"chinese", IDX_EUC_CN},
+ {"taiwan", IDX_EUC_TW},
+ {"cp950", IDX_BIG5},
+ {"950", IDX_BIG5},
+#endif
+ {"mac", IDX_MACROMAN},
+ {"mac-roman", IDX_MACROMAN},
+ {NULL, 0}
+};
+
+#ifndef CP_UTF8
+# define CP_UTF8 65001 /* magic number from winnls.h */
+#endif
+
+/*
+ * Find encoding "name" in the list of canonical encoding names.
+ * Returns -1 if not found.
+ */
+ static int
+enc_canon_search(char_u *name)
+{
+ int i;
+
+ for (i = 0; i < IDX_COUNT; ++i)
+ if (STRCMP(name, enc_canon_table[i].name) == 0)
+ return i;
+ return -1;
+}
+
+
+/*
+ * Find canonical encoding "name" in the list and return its properties.
+ * Returns 0 if not found.
+ */
+ int
+enc_canon_props(char_u *name)
+{
+ int i;
+
+ i = enc_canon_search(name);
+ if (i >= 0)
+ return enc_canon_table[i].prop;
+#ifdef WIN3264
+ if (name[0] == 'c' && name[1] == 'p' && VIM_ISDIGIT(name[2]))
+ {
+ CPINFO cpinfo;
+
+ /* Get info on this codepage to find out what it is. */
+ if (GetCPInfo(atoi((char *)name + 2), &cpinfo) != 0)
+ {
+ if (cpinfo.MaxCharSize == 1) /* some single-byte encoding */
+ return ENC_8BIT;
+ if (cpinfo.MaxCharSize == 2
+ && (cpinfo.LeadByte[0] != 0 || cpinfo.LeadByte[1] != 0))
+ /* must be a DBCS encoding */
+ return ENC_DBCS;
+ }
+ return 0;
+ }
+#endif
+ if (STRNCMP(name, "2byte-", 6) == 0)
+ return ENC_DBCS;
+ if (STRNCMP(name, "8bit-", 5) == 0 || STRNCMP(name, "iso-8859-", 9) == 0)
+ return ENC_8BIT;
+ return 0;
+}
+
+/*
+ * Set up for using multi-byte characters.
+ * Called in three cases:
+ * - by main() to initialize (p_enc == NULL)
+ * - by set_init_1() after 'encoding' was set to its default.
+ * - by do_set() when 'encoding' has been set.
+ * p_enc must have been passed through enc_canonize() already.
+ * Sets the "enc_unicode", "enc_utf8", "enc_dbcs" and "has_mbyte" flags.
+ * Fills mb_bytelen_tab[] and returns NULL when there are no problems.
+ * When there is something wrong: Returns an error message and doesn't change
+ * anything.
+ */
+ char *
+mb_init(void)
+{
+ int i;
+ int idx;
+ int n;
+ int enc_dbcs_new = 0;
+#if defined(USE_ICONV) && !defined(WIN3264) && !defined(WIN32UNIX) \
+ && !defined(MACOS_CONVERT)
+# define LEN_FROM_CONV
+ vimconv_T vimconv;
+ char_u *p;
+#endif
+
+ if (p_enc == NULL)
+ {
+ /* Just starting up: set the whole table to one's. */
+ for (i = 0; i < 256; ++i)
+ mb_bytelen_tab[i] = 1;
+ input_conv.vc_type = CONV_NONE;
+ input_conv.vc_factor = 1;
+ output_conv.vc_type = CONV_NONE;
+ return NULL;
+ }
+
+#ifdef WIN3264
+ if (p_enc[0] == 'c' && p_enc[1] == 'p' && VIM_ISDIGIT(p_enc[2]))
+ {
+ CPINFO cpinfo;
+
+ /* Get info on this codepage to find out what it is. */
+ if (GetCPInfo(atoi((char *)p_enc + 2), &cpinfo) != 0)
+ {
+ if (cpinfo.MaxCharSize == 1)
+ {
+ /* some single-byte encoding */
+ enc_unicode = 0;
+ enc_utf8 = FALSE;
+ }
+ else if (cpinfo.MaxCharSize == 2
+ && (cpinfo.LeadByte[0] != 0 || cpinfo.LeadByte[1] != 0))
+ {
+ /* must be a DBCS encoding, check below */
+ enc_dbcs_new = atoi((char *)p_enc + 2);
+ }
+ else
+ goto codepage_invalid;
+ }
+ else if (GetLastError() == ERROR_INVALID_PARAMETER)
+ {
+codepage_invalid:
+ return N_("E543: Not a valid codepage");
+ }
+ }
+#endif
+ else if (STRNCMP(p_enc, "8bit-", 5) == 0
+ || STRNCMP(p_enc, "iso-8859-", 9) == 0)
+ {
+ /* Accept any "8bit-" or "iso-8859-" name. */
+ enc_unicode = 0;
+ enc_utf8 = FALSE;
+ }
+ else if (STRNCMP(p_enc, "2byte-", 6) == 0)
+ {
+#ifdef WIN3264
+ /* Windows: accept only valid codepage numbers, check below. */
+ if (p_enc[6] != 'c' || p_enc[7] != 'p'
+ || (enc_dbcs_new = atoi((char *)p_enc + 8)) == 0)
+ return e_invarg;
+#else
+ /* Unix: accept any "2byte-" name, assume current locale. */
+ enc_dbcs_new = DBCS_2BYTE;
+#endif
+ }
+ else if ((idx = enc_canon_search(p_enc)) >= 0)
+ {
+ i = enc_canon_table[idx].prop;
+ if (i & ENC_UNICODE)
+ {
+ /* Unicode */
+ enc_utf8 = TRUE;
+ if (i & (ENC_2BYTE | ENC_2WORD))
+ enc_unicode = 2;
+ else if (i & ENC_4BYTE)
+ enc_unicode = 4;
+ else
+ enc_unicode = 0;
+ }
+ else if (i & ENC_DBCS)
+ {
+ /* 2byte, handle below */
+ enc_dbcs_new = enc_canon_table[idx].codepage;
+ }
+ else
+ {
+ /* Must be 8-bit. */
+ enc_unicode = 0;
+ enc_utf8 = FALSE;
+ }
+ }
+ else /* Don't know what encoding this is, reject it. */
+ return e_invarg;
+
+ if (enc_dbcs_new != 0)
+ {
+#ifdef WIN3264
+ /* Check if the DBCS code page is OK. */
+ if (!IsValidCodePage(enc_dbcs_new))
+ goto codepage_invalid;
+#endif
+ enc_unicode = 0;
+ enc_utf8 = FALSE;
+ }
+ enc_dbcs = enc_dbcs_new;
+ has_mbyte = (enc_dbcs != 0 || enc_utf8);
+
+#if defined(WIN3264) || defined(FEAT_CYGWIN_WIN32_CLIPBOARD)
+ enc_codepage = encname2codepage(p_enc);
+ enc_latin9 = (STRCMP(p_enc, "iso-8859-15") == 0);
+#endif
+
+ /* Detect an encoding that uses latin1 characters. */
+ enc_latin1like = (enc_utf8 || STRCMP(p_enc, "latin1") == 0
+ || STRCMP(p_enc, "iso-8859-15") == 0);
+
+ /*
+ * Set the function pointers.
+ */
+ if (enc_utf8)
+ {
+ mb_ptr2len = utfc_ptr2len;
+ mb_ptr2len_len = utfc_ptr2len_len;
+ mb_char2len = utf_char2len;
+ mb_char2bytes = utf_char2bytes;
+ mb_ptr2cells = utf_ptr2cells;
+ mb_ptr2cells_len = utf_ptr2cells_len;
+ mb_char2cells = utf_char2cells;
+ mb_off2cells = utf_off2cells;
+ mb_ptr2char = utf_ptr2char;
+ mb_head_off = utf_head_off;
+ }
+ else if (enc_dbcs != 0)
+ {
+ mb_ptr2len = dbcs_ptr2len;
+ mb_ptr2len_len = dbcs_ptr2len_len;
+ mb_char2len = dbcs_char2len;
+ mb_char2bytes = dbcs_char2bytes;
+ mb_ptr2cells = dbcs_ptr2cells;
+ mb_ptr2cells_len = dbcs_ptr2cells_len;
+ mb_char2cells = dbcs_char2cells;
+ mb_off2cells = dbcs_off2cells;
+ mb_ptr2char = dbcs_ptr2char;
+ mb_head_off = dbcs_head_off;
+ }
+ else
+ {
+ mb_ptr2len = latin_ptr2len;
+ mb_ptr2len_len = latin_ptr2len_len;
+ mb_char2len = latin_char2len;
+ mb_char2bytes = latin_char2bytes;
+ mb_ptr2cells = latin_ptr2cells;
+ mb_ptr2cells_len = latin_ptr2cells_len;
+ mb_char2cells = latin_char2cells;
+ mb_off2cells = latin_off2cells;
+ mb_ptr2char = latin_ptr2char;
+ mb_head_off = latin_head_off;
+ }
+
+ /*
+ * Fill the mb_bytelen_tab[] for MB_BYTE2LEN().
+ */
+#ifdef LEN_FROM_CONV
+ /* When 'encoding' is different from the current locale mblen() won't
+ * work. Use conversion to "utf-8" instead. */
+ vimconv.vc_type = CONV_NONE;
+ if (enc_dbcs)
+ {
+ p = enc_locale();
+ if (p == NULL || STRCMP(p, p_enc) != 0)
+ {
+ convert_setup(&vimconv, p_enc, (char_u *)"utf-8");
+ vimconv.vc_fail = TRUE;
+ }
+ vim_free(p);
+ }
+#endif
+
+ for (i = 0; i < 256; ++i)
+ {
+ /* Our own function to reliably check the length of UTF-8 characters,
+ * independent of mblen(). */
+ if (enc_utf8)
+ n = utf8len_tab[i];
+ else if (enc_dbcs == 0)
+ n = 1;
+ else
+ {
+#if defined(WIN3264) || defined(WIN32UNIX)
+ /* enc_dbcs is set by setting 'fileencoding'. It becomes a Windows
+ * CodePage identifier, which we can pass directly in to Windows
+ * API */
+ n = IsDBCSLeadByteEx(enc_dbcs, (WINBYTE)i) ? 2 : 1;
+#else
+# if defined(__amigaos4__) || defined(__ANDROID__) || \
+ !(defined(HAVE_MBLEN) || defined(X_LOCALE))
+ /*
+ * if mblen() is not available, character which MSB is turned on
+ * are treated as leading byte character. (note : This assumption
+ * is not always true.)
+ */
+ n = (i & 0x80) ? 2 : 1;
+# else
+ char buf[MB_MAXBYTES + 1];
+
+ if (i == NUL) /* just in case mblen() can't handle "" */
+ n = 1;
+ else
+ {
+ buf[0] = i;
+ buf[1] = 0;
+# ifdef LEN_FROM_CONV
+ if (vimconv.vc_type != CONV_NONE)
+ {
+ /*
+ * string_convert() should fail when converting the first
+ * byte of a double-byte character.
+ */
+ p = string_convert(&vimconv, (char_u *)buf, NULL);
+ if (p != NULL)
+ {
+ vim_free(p);
+ n = 1;
+ }
+ else
+ n = 2;
+ }
+ else
+# endif
+ {
+ /*
+ * mblen() should return -1 for invalid (means the leading
+ * multibyte) character. However there are some platforms
+ * where mblen() returns 0 for invalid character.
+ * Therefore, following condition includes 0.
+ */
+ vim_ignored = mblen(NULL, 0); // First reset the state.
+ if (mblen(buf, (size_t)1) <= 0)
+ n = 2;
+ else
+ n = 1;
+ }
+ }
+# endif
+#endif
+ }
+
+ mb_bytelen_tab[i] = n;
+ }
+
+#ifdef LEN_FROM_CONV
+ convert_setup(&vimconv, NULL, NULL);
+#endif
+
+ /* The cell width depends on the type of multi-byte characters. */
+ (void)init_chartab();
+
+ /* When enc_utf8 is set or reset, (de)allocate ScreenLinesUC[] */
+ screenalloc(FALSE);
+
+ /* When using Unicode, set default for 'fileencodings'. */
+ if (enc_utf8 && !option_was_set((char_u *)"fencs"))
+ set_string_option_direct((char_u *)"fencs", -1,
+ (char_u *)"ucs-bom,utf-8,default,latin1", OPT_FREE, 0);
+
+#if defined(HAVE_BIND_TEXTDOMAIN_CODESET) && defined(FEAT_GETTEXT)
+ /* GNU gettext 0.10.37 supports this feature: set the codeset used for
+ * translated messages independently from the current locale. */
+ (void)bind_textdomain_codeset(VIMPACKAGE,
+ enc_utf8 ? "utf-8" : (char *)p_enc);
+#endif
+
+#ifdef WIN32
+ /* When changing 'encoding' while starting up, then convert the command
+ * line arguments from the active codepage to 'encoding'. */
+ if (starting != 0)
+ fix_arg_enc();
+#endif
+
+ /* Fire an autocommand to let people do custom font setup. This must be
+ * after Vim has been setup for the new encoding. */
+ apply_autocmds(EVENT_ENCODINGCHANGED, NULL, (char_u *)"", FALSE, curbuf);
+
+#ifdef FEAT_SPELL
+ /* Need to reload spell dictionaries */
+ spell_reload();
+#endif
+
+ return NULL;
+}
+
+/*
+ * Return the size of the BOM for the current buffer:
+ * 0 - no BOM
+ * 2 - UCS-2 or UTF-16 BOM
+ * 4 - UCS-4 BOM
+ * 3 - UTF-8 BOM
+ */
+ int
+bomb_size(void)
+{
+ int n = 0;
+
+ if (curbuf->b_p_bomb && !curbuf->b_p_bin)
+ {
+ if (*curbuf->b_p_fenc == NUL)
+ {
+ if (enc_utf8)
+ {
+ if (enc_unicode != 0)
+ n = enc_unicode;
+ else
+ n = 3;
+ }
+ }
+ else if (STRCMP(curbuf->b_p_fenc, "utf-8") == 0)
+ n = 3;
+ else if (STRNCMP(curbuf->b_p_fenc, "ucs-2", 5) == 0
+ || STRNCMP(curbuf->b_p_fenc, "utf-16", 6) == 0)
+ n = 2;
+ else if (STRNCMP(curbuf->b_p_fenc, "ucs-4", 5) == 0)
+ n = 4;
+ }
+ return n;
+}
+
+#if defined(FEAT_QUICKFIX) || defined(PROTO)
+/*
+ * Remove all BOM from "s" by moving remaining text.
+ */
+ void
+remove_bom(char_u *s)
+{
+ if (enc_utf8)
+ {
+ char_u *p = s;
+
+ while ((p = vim_strbyte(p, 0xef)) != NULL)
+ {
+ if (p[1] == 0xbb && p[2] == 0xbf)
+ STRMOVE(p, p + 3);
+ else
+ ++p;
+ }
+ }
+}
+#endif
+
+/*
+ * Get class of pointer:
+ * 0 for blank or NUL
+ * 1 for punctuation
+ * 2 for an (ASCII) word character
+ * >2 for other word characters
+ */
+ int
+mb_get_class(char_u *p)
+{
+ return mb_get_class_buf(p, curbuf);
+}
+
+ int
+mb_get_class_buf(char_u *p, buf_T *buf)
+{
+ if (MB_BYTE2LEN(p[0]) == 1)
+ {
+ if (p[0] == NUL || VIM_ISWHITE(p[0]))
+ return 0;
+ if (vim_iswordc_buf(p[0], buf))
+ return 2;
+ return 1;
+ }
+ if (enc_dbcs != 0 && p[0] != NUL && p[1] != NUL)
+ return dbcs_class(p[0], p[1]);
+ if (enc_utf8)
+ return utf_class_buf(utf_ptr2char(p), buf);
+ return 0;
+}
+
+/*
+ * Get class of a double-byte character. This always returns 3 or bigger.
+ * TODO: Should return 1 for punctuation.
+ */
+ int
+dbcs_class(unsigned lead, unsigned trail)
+{
+ switch (enc_dbcs)
+ {
+ /* please add classify routine for your language in here */
+
+ case DBCS_JPNU: /* ? */
+ case DBCS_JPN:
+ {
+ /* JIS code classification */
+ unsigned char lb = lead;
+ unsigned char tb = trail;
+
+ /* convert process code to JIS */
+# if defined(WIN3264) || defined(WIN32UNIX) || defined(MACOS_X)
+ /* process code is SJIS */
+ if (lb <= 0x9f)
+ lb = (lb - 0x81) * 2 + 0x21;
+ else
+ lb = (lb - 0xc1) * 2 + 0x21;
+ if (tb <= 0x7e)
+ tb -= 0x1f;
+ else if (tb <= 0x9e)
+ tb -= 0x20;
+ else
+ {
+ tb -= 0x7e;
+ lb += 1;
+ }
+# else
+ /*
+ * XXX: Code page identification can not use with all
+ * system! So, some other encoding information
+ * will be needed.
+ * In japanese: SJIS,EUC,UNICODE,(JIS)
+ * Note that JIS-code system don't use as
+ * process code in most system because it uses
+ * escape sequences(JIS is context depend encoding).
+ */
+ /* assume process code is JAPANESE-EUC */
+ lb &= 0x7f;
+ tb &= 0x7f;
+# endif
+ /* exceptions */
+ switch (lb << 8 | tb)
+ {
+ case 0x2121: /* ZENKAKU space */
+ return 0;
+ case 0x2122: /* TOU-TEN (Japanese comma) */
+ case 0x2123: /* KU-TEN (Japanese period) */
+ case 0x2124: /* ZENKAKU comma */
+ case 0x2125: /* ZENKAKU period */
+ return 1;
+ case 0x213c: /* prolongedsound handled as KATAKANA */
+ return 13;
+ }
+ /* sieved by KU code */
+ switch (lb)
+ {
+ case 0x21:
+ case 0x22:
+ /* special symbols */
+ return 10;
+ case 0x23:
+ /* alpha-numeric */
+ return 11;
+ case 0x24:
+ /* hiragana */
+ return 12;
+ case 0x25:
+ /* katakana */
+ return 13;
+ case 0x26:
+ /* greek */
+ return 14;
+ case 0x27:
+ /* russian */
+ return 15;
+ case 0x28:
+ /* lines */
+ return 16;
+ default:
+ /* kanji */
+ return 17;
+ }
+ }
+
+ case DBCS_KORU: /* ? */
+ case DBCS_KOR:
+ {
+ /* KS code classification */
+ unsigned char c1 = lead;
+ unsigned char c2 = trail;
+
+ /*
+ * 20 : Hangul
+ * 21 : Hanja
+ * 22 : Symbols
+ * 23 : Alpha-numeric/Roman Letter (Full width)
+ * 24 : Hangul Letter(Alphabet)
+ * 25 : Roman Numeral/Greek Letter
+ * 26 : Box Drawings
+ * 27 : Unit Symbols
+ * 28 : Circled/Parenthesized Letter
+ * 29 : Hiragana/Katakana
+ * 30 : Cyrillic Letter
+ */
+
+ if (c1 >= 0xB0 && c1 <= 0xC8)
+ /* Hangul */
+ return 20;
+#if defined(WIN3264) || defined(WIN32UNIX)
+ else if (c1 <= 0xA0 || c2 <= 0xA0)
+ /* Extended Hangul Region : MS UHC(Unified Hangul Code) */
+ /* c1: 0x81-0xA0 with c2: 0x41-0x5A, 0x61-0x7A, 0x81-0xFE
+ * c1: 0xA1-0xC6 with c2: 0x41-0x5A, 0x61-0x7A, 0x81-0xA0
+ */
+ return 20;
+#endif
+
+ else if (c1 >= 0xCA && c1 <= 0xFD)
+ /* Hanja */
+ return 21;
+ else switch (c1)
+ {
+ case 0xA1:
+ case 0xA2:
+ /* Symbols */
+ return 22;
+ case 0xA3:
+ /* Alpha-numeric */
+ return 23;
+ case 0xA4:
+ /* Hangul Letter(Alphabet) */
+ return 24;
+ case 0xA5:
+ /* Roman Numeral/Greek Letter */
+ return 25;
+ case 0xA6:
+ /* Box Drawings */
+ return 26;
+ case 0xA7:
+ /* Unit Symbols */
+ return 27;
+ case 0xA8:
+ case 0xA9:
+ if (c2 <= 0xAF)
+ return 25; /* Roman Letter */
+ else if (c2 >= 0xF6)
+ return 22; /* Symbols */
+ else
+ /* Circled/Parenthesized Letter */
+ return 28;
+ case 0xAA:
+ case 0xAB:
+ /* Hiragana/Katakana */
+ return 29;
+ case 0xAC:
+ /* Cyrillic Letter */
+ return 30;
+ }
+ }
+ default:
+ break;
+ }
+ return 3;
+}
+
+/*
+ * mb_char2len() function pointer.
+ * Return length in bytes of character "c".
+ * Returns 1 for a single-byte character.
+ */
+ int
+latin_char2len(int c UNUSED)
+{
+ return 1;
+}
+
+ static int
+dbcs_char2len(
+ int c)
+{
+ if (c >= 0x100)
+ return 2;
+ return 1;
+}
+
+/*
+ * mb_char2bytes() function pointer.
+ * Convert a character to its bytes.
+ * Returns the length in bytes.
+ */
+ int
+latin_char2bytes(int c, char_u *buf)
+{
+ buf[0] = c;
+ return 1;
+}
+
+ static int
+dbcs_char2bytes(int c, char_u *buf)
+{
+ if (c >= 0x100)
+ {
+ buf[0] = (unsigned)c >> 8;
+ buf[1] = c;
+ /* Never use a NUL byte, it causes lots of trouble. It's an invalid
+ * character anyway. */
+ if (buf[1] == NUL)
+ buf[1] = '\n';
+ return 2;
+ }
+ buf[0] = c;
+ return 1;
+}
+
+/*
+ * mb_ptr2len() function pointer.
+ * Get byte length of character at "*p" but stop at a NUL.
+ * For UTF-8 this includes following composing characters.
+ * Returns 0 when *p is NUL.
+ */
+ int
+latin_ptr2len(char_u *p)
+{
+ return MB_BYTE2LEN(*p);
+}
+
+ static int
+dbcs_ptr2len(
+ char_u *p)
+{
+ int len;
+
+ /* Check if second byte is not missing. */
+ len = MB_BYTE2LEN(*p);
+ if (len == 2 && p[1] == NUL)
+ len = 1;
+ return len;
+}
+
+/*
+ * mb_ptr2len_len() function pointer.
+ * Like mb_ptr2len(), but limit to read "size" bytes.
+ * Returns 0 for an empty string.
+ * Returns 1 for an illegal char or an incomplete byte sequence.
+ */
+ int
+latin_ptr2len_len(char_u *p, int size)
+{
+ if (size < 1 || *p == NUL)
+ return 0;
+ return 1;
+}
+
+ static int
+dbcs_ptr2len_len(char_u *p, int size)
+{
+ int len;
+
+ if (size < 1 || *p == NUL)
+ return 0;
+ if (size == 1)
+ return 1;
+ /* Check that second byte is not missing. */
+ len = MB_BYTE2LEN(*p);
+ if (len == 2 && p[1] == NUL)
+ len = 1;
+ return len;
+}
+
+struct interval
+{
+ long first;
+ long last;
+};
+
+/*
+ * Return TRUE if "c" is in "table[size / sizeof(struct interval)]".
+ */
+ static int
+intable(struct interval *table, size_t size, int c)
+{
+ int mid, bot, top;
+
+ /* first quick check for Latin1 etc. characters */
+ if (c < table[0].first)
+ return FALSE;
+
+ /* binary search in table */
+ bot = 0;
+ top = (int)(size / sizeof(struct interval) - 1);
+ while (top >= bot)
+ {
+ mid = (bot + top) / 2;
+ if (table[mid].last < c)
+ bot = mid + 1;
+ else if (table[mid].first > c)
+ top = mid - 1;
+ else
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/* Sorted list of non-overlapping intervals of East Asian Ambiguous
+ * characters, generated with ../runtime/tools/unicode.vim. */
+static struct interval ambiguous[] =
+{
+ {0x00a1, 0x00a1},
+ {0x00a4, 0x00a4},
+ {0x00a7, 0x00a8},
+ {0x00aa, 0x00aa},
+ {0x00ad, 0x00ae},
+ {0x00b0, 0x00b4},
+ {0x00b6, 0x00ba},
+ {0x00bc, 0x00bf},
+ {0x00c6, 0x00c6},
+ {0x00d0, 0x00d0},
+ {0x00d7, 0x00d8},
+ {0x00de, 0x00e1},
+ {0x00e6, 0x00e6},
+ {0x00e8, 0x00ea},
+ {0x00ec, 0x00ed},
+ {0x00f0, 0x00f0},
+ {0x00f2, 0x00f3},
+ {0x00f7, 0x00fa},
+ {0x00fc, 0x00fc},
+ {0x00fe, 0x00fe},
+ {0x0101, 0x0101},
+ {0x0111, 0x0111},
+ {0x0113, 0x0113},
+ {0x011b, 0x011b},
+ {0x0126, 0x0127},
+ {0x012b, 0x012b},
+ {0x0131, 0x0133},
+ {0x0138, 0x0138},
+ {0x013f, 0x0142},
+ {0x0144, 0x0144},
+ {0x0148, 0x014b},
+ {0x014d, 0x014d},
+ {0x0152, 0x0153},
+ {0x0166, 0x0167},
+ {0x016b, 0x016b},
+ {0x01ce, 0x01ce},
+ {0x01d0, 0x01d0},
+ {0x01d2, 0x01d2},
+ {0x01d4, 0x01d4},
+ {0x01d6, 0x01d6},
+ {0x01d8, 0x01d8},
+ {0x01da, 0x01da},
+ {0x01dc, 0x01dc},
+ {0x0251, 0x0251},
+ {0x0261, 0x0261},
+ {0x02c4, 0x02c4},
+ {0x02c7, 0x02c7},
+ {0x02c9, 0x02cb},
+ {0x02cd, 0x02cd},
+ {0x02d0, 0x02d0},
+ {0x02d8, 0x02db},
+ {0x02dd, 0x02dd},
+ {0x02df, 0x02df},
+ {0x0300, 0x036f},
+ {0x0391, 0x03a1},
+ {0x03a3, 0x03a9},
+ {0x03b1, 0x03c1},
+ {0x03c3, 0x03c9},
+ {0x0401, 0x0401},
+ {0x0410, 0x044f},
+ {0x0451, 0x0451},
+ {0x2010, 0x2010},
+ {0x2013, 0x2016},
+ {0x2018, 0x2019},
+ {0x201c, 0x201d},
+ {0x2020, 0x2022},
+ {0x2024, 0x2027},
+ {0x2030, 0x2030},
+ {0x2032, 0x2033},
+ {0x2035, 0x2035},
+ {0x203b, 0x203b},
+ {0x203e, 0x203e},
+ {0x2074, 0x2074},
+ {0x207f, 0x207f},
+ {0x2081, 0x2084},
+ {0x20ac, 0x20ac},
+ {0x2103, 0x2103},
+ {0x2105, 0x2105},
+ {0x2109, 0x2109},
+ {0x2113, 0x2113},
+ {0x2116, 0x2116},
+ {0x2121, 0x2122},
+ {0x2126, 0x2126},
+ {0x212b, 0x212b},
+ {0x2153, 0x2154},
+ {0x215b, 0x215e},
+ {0x2160, 0x216b},
+ {0x2170, 0x2179},
+ {0x2189, 0x2189},
+ {0x2190, 0x2199},
+ {0x21b8, 0x21b9},
+ {0x21d2, 0x21d2},
+ {0x21d4, 0x21d4},
+ {0x21e7, 0x21e7},
+ {0x2200, 0x2200},
+ {0x2202, 0x2203},
+ {0x2207, 0x2208},
+ {0x220b, 0x220b},
+ {0x220f, 0x220f},
+ {0x2211, 0x2211},
+ {0x2215, 0x2215},
+ {0x221a, 0x221a},
+ {0x221d, 0x2220},
+ {0x2223, 0x2223},
+ {0x2225, 0x2225},
+ {0x2227, 0x222c},
+ {0x222e, 0x222e},
+ {0x2234, 0x2237},
+ {0x223c, 0x223d},
+ {0x2248, 0x2248},
+ {0x224c, 0x224c},
+ {0x2252, 0x2252},
+ {0x2260, 0x2261},
+ {0x2264, 0x2267},
+ {0x226a, 0x226b},
+ {0x226e, 0x226f},
+ {0x2282, 0x2283},
+ {0x2286, 0x2287},
+ {0x2295, 0x2295},
+ {0x2299, 0x2299},
+ {0x22a5, 0x22a5},
+ {0x22bf, 0x22bf},
+ {0x2312, 0x2312},
+ {0x2460, 0x24e9},
+ {0x24eb, 0x254b},
+ {0x2550, 0x2573},
+ {0x2580, 0x258f},
+ {0x2592, 0x2595},
+ {0x25a0, 0x25a1},
+ {0x25a3, 0x25a9},
+ {0x25b2, 0x25b3},
+ {0x25b6, 0x25b7},
+ {0x25bc, 0x25bd},
+ {0x25c0, 0x25c1},
+ {0x25c6, 0x25c8},
+ {0x25cb, 0x25cb},
+ {0x25ce, 0x25d1},
+ {0x25e2, 0x25e5},
+ {0x25ef, 0x25ef},
+ {0x2605, 0x2606},
+ {0x2609, 0x2609},
+ {0x260e, 0x260f},
+ {0x261c, 0x261c},
+ {0x261e, 0x261e},
+ {0x2640, 0x2640},
+ {0x2642, 0x2642},
+ {0x2660, 0x2661},
+ {0x2663, 0x2665},
+ {0x2667, 0x266a},
+ {0x266c, 0x266d},
+ {0x266f, 0x266f},
+ {0x269e, 0x269f},
+ {0x26bf, 0x26bf},
+ {0x26c6, 0x26cd},
+ {0x26cf, 0x26d3},
+ {0x26d5, 0x26e1},
+ {0x26e3, 0x26e3},
+ {0x26e8, 0x26e9},
+ {0x26eb, 0x26f1},
+ {0x26f4, 0x26f4},
+ {0x26f6, 0x26f9},
+ {0x26fb, 0x26fc},
+ {0x26fe, 0x26ff},
+ {0x273d, 0x273d},
+ {0x2776, 0x277f},
+ {0x2b56, 0x2b59},
+ {0x3248, 0x324f},
+ {0xe000, 0xf8ff},
+ {0xfe00, 0xfe0f},
+ {0xfffd, 0xfffd},
+ {0x1f100, 0x1f10a},
+ {0x1f110, 0x1f12d},
+ {0x1f130, 0x1f169},
+ {0x1f170, 0x1f18d},
+ {0x1f18f, 0x1f190},
+ {0x1f19b, 0x1f1ac},
+ {0xe0100, 0xe01ef},
+ {0xf0000, 0xffffd},
+ {0x100000, 0x10fffd}
+};
+
+#if defined(FEAT_TERMINAL) || defined(PROTO)
+/*
+ * utf_char2cells() with different argument type for libvterm.
+ */
+ int
+utf_uint2cells(UINT32_T c)
+{
+ if (c >= 0x100 && utf_iscomposing((int)c))
+ return 0;
+ return utf_char2cells((int)c);
+}
+#endif
+
+/*
+ * For UTF-8 character "c" return 2 for a double-width character, 1 for others.
+ * Returns 4 or 6 for an unprintable character.
+ * Is only correct for characters >= 0x80.
+ * When p_ambw is "double", return 2 for a character with East Asian Width
+ * class 'A'(mbiguous).
+ */
+ int
+utf_char2cells(int c)
+{
+ /* Sorted list of non-overlapping intervals of East Asian double width
+ * characters, generated with ../runtime/tools/unicode.vim. */
+ static struct interval doublewidth[] =
+ {
+ {0x1100, 0x115f},
+ {0x231a, 0x231b},
+ {0x2329, 0x232a},
+ {0x23e9, 0x23ec},
+ {0x23f0, 0x23f0},
+ {0x23f3, 0x23f3},
+ {0x25fd, 0x25fe},
+ {0x2614, 0x2615},
+ {0x2648, 0x2653},
+ {0x267f, 0x267f},
+ {0x2693, 0x2693},
+ {0x26a1, 0x26a1},
+ {0x26aa, 0x26ab},
+ {0x26bd, 0x26be},
+ {0x26c4, 0x26c5},
+ {0x26ce, 0x26ce},
+ {0x26d4, 0x26d4},
+ {0x26ea, 0x26ea},
+ {0x26f2, 0x26f3},
+ {0x26f5, 0x26f5},
+ {0x26fa, 0x26fa},
+ {0x26fd, 0x26fd},
+ {0x2705, 0x2705},
+ {0x270a, 0x270b},
+ {0x2728, 0x2728},
+ {0x274c, 0x274c},
+ {0x274e, 0x274e},
+ {0x2753, 0x2755},
+ {0x2757, 0x2757},
+ {0x2795, 0x2797},
+ {0x27b0, 0x27b0},
+ {0x27bf, 0x27bf},
+ {0x2b1b, 0x2b1c},
+ {0x2b50, 0x2b50},
+ {0x2b55, 0x2b55},
+ {0x2e80, 0x2e99},
+ {0x2e9b, 0x2ef3},
+ {0x2f00, 0x2fd5},
+ {0x2ff0, 0x2ffb},
+ {0x3000, 0x303e},
+ {0x3041, 0x3096},
+ {0x3099, 0x30ff},
+ {0x3105, 0x312f},
+ {0x3131, 0x318e},
+ {0x3190, 0x31ba},
+ {0x31c0, 0x31e3},
+ {0x31f0, 0x321e},
+ {0x3220, 0x3247},
+ {0x3250, 0x32fe},
+ {0x3300, 0x4dbf},
+ {0x4e00, 0xa48c},
+ {0xa490, 0xa4c6},
+ {0xa960, 0xa97c},
+ {0xac00, 0xd7a3},
+ {0xf900, 0xfaff},
+ {0xfe10, 0xfe19},
+ {0xfe30, 0xfe52},
+ {0xfe54, 0xfe66},
+ {0xfe68, 0xfe6b},
+ {0xff01, 0xff60},
+ {0xffe0, 0xffe6},
+ {0x16fe0, 0x16fe1},
+ {0x17000, 0x187f1},
+ {0x18800, 0x18af2},
+ {0x1b000, 0x1b11e},
+ {0x1b170, 0x1b2fb},
+ {0x1f004, 0x1f004},
+ {0x1f0cf, 0x1f0cf},
+ {0x1f18e, 0x1f18e},
+ {0x1f191, 0x1f19a},
+ {0x1f200, 0x1f202},
+ {0x1f210, 0x1f23b},
+ {0x1f240, 0x1f248},
+ {0x1f250, 0x1f251},
+ {0x1f260, 0x1f265},
+ {0x1f300, 0x1f320},
+ {0x1f32d, 0x1f335},
+ {0x1f337, 0x1f37c},
+ {0x1f37e, 0x1f393},
+ {0x1f3a0, 0x1f3ca},
+ {0x1f3cf, 0x1f3d3},
+ {0x1f3e0, 0x1f3f0},
+ {0x1f3f4, 0x1f3f4},
+ {0x1f3f8, 0x1f43e},
+ {0x1f440, 0x1f440},
+ {0x1f442, 0x1f4fc},
+ {0x1f4ff, 0x1f53d},
+ {0x1f54b, 0x1f54e},
+ {0x1f550, 0x1f567},
+ {0x1f57a, 0x1f57a},
+ {0x1f595, 0x1f596},
+ {0x1f5a4, 0x1f5a4},
+ {0x1f5fb, 0x1f64f},
+ {0x1f680, 0x1f6c5},
+ {0x1f6cc, 0x1f6cc},
+ {0x1f6d0, 0x1f6d2},
+ {0x1f6eb, 0x1f6ec},
+ {0x1f6f4, 0x1f6f9},
+ {0x1f910, 0x1f93e},
+ {0x1f940, 0x1f970},
+ {0x1f973, 0x1f976},
+ {0x1f97a, 0x1f97a},
+ {0x1f97c, 0x1f9a2},
+ {0x1f9b0, 0x1f9b9},
+ {0x1f9c0, 0x1f9c2},
+ {0x1f9d0, 0x1f9ff},
+ {0x20000, 0x2fffd},
+ {0x30000, 0x3fffd}
+ };
+
+ /* Sorted list of non-overlapping intervals of Emoji characters that don't
+ * have ambiguous or double width,
+ * based on http://unicode.org/emoji/charts/emoji-list.html */
+ static struct interval emoji_width[] =
+ {
+ {0x1f1e6, 0x1f1ff},
+ {0x1f321, 0x1f321},
+ {0x1f324, 0x1f32c},
+ {0x1f336, 0x1f336},
+ {0x1f37d, 0x1f37d},
+ {0x1f396, 0x1f397},
+ {0x1f399, 0x1f39b},
+ {0x1f39e, 0x1f39f},
+ {0x1f3cb, 0x1f3ce},
+ {0x1f3d4, 0x1f3df},
+ {0x1f3f3, 0x1f3f5},
+ {0x1f3f7, 0x1f3f7},
+ {0x1f43f, 0x1f43f},
+ {0x1f441, 0x1f441},
+ {0x1f4fd, 0x1f4fd},
+ {0x1f549, 0x1f54a},
+ {0x1f56f, 0x1f570},
+ {0x1f573, 0x1f579},
+ {0x1f587, 0x1f587},
+ {0x1f58a, 0x1f58d},
+ {0x1f590, 0x1f590},
+ {0x1f5a5, 0x1f5a5},
+ {0x1f5a8, 0x1f5a8},
+ {0x1f5b1, 0x1f5b2},
+ {0x1f5bc, 0x1f5bc},
+ {0x1f5c2, 0x1f5c4},
+ {0x1f5d1, 0x1f5d3},
+ {0x1f5dc, 0x1f5de},
+ {0x1f5e1, 0x1f5e1},
+ {0x1f5e3, 0x1f5e3},
+ {0x1f5e8, 0x1f5e8},
+ {0x1f5ef, 0x1f5ef},
+ {0x1f5f3, 0x1f5f3},
+ {0x1f5fa, 0x1f5fa},
+ {0x1f6cb, 0x1f6cf},
+ {0x1f6e0, 0x1f6e5},
+ {0x1f6e9, 0x1f6e9},
+ {0x1f6f0, 0x1f6f0},
+ {0x1f6f3, 0x1f6f3}
+ };
+
+ if (c >= 0x100)
+ {
+#ifdef USE_WCHAR_FUNCTIONS
+ /*
+ * Assume the library function wcwidth() works better than our own
+ * stuff. It should return 1 for ambiguous width chars!
+ */
+ int n = wcwidth(c);
+
+ if (n < 0)
+ return 6; /* unprintable, displays <xxxx> */
+ if (n > 1)
+ return n;
+#else
+ if (!utf_printable(c))
+ return 6; /* unprintable, displays <xxxx> */
+ if (intable(doublewidth, sizeof(doublewidth), c))
+ return 2;
+#endif
+ if (p_emoji && intable(emoji_width, sizeof(emoji_width), c))
+ return 2;
+ }
+
+ /* Characters below 0x100 are influenced by 'isprint' option */
+ else if (c >= 0x80 && !vim_isprintc(c))
+ return 4; /* unprintable, displays <xx> */
+
+ if (c >= 0x80 && *p_ambw == 'd' && intable(ambiguous, sizeof(ambiguous), c))
+ return 2;
+
+ return 1;
+}
+
+/*
+ * mb_ptr2cells() function pointer.
+ * Return the number of display cells character at "*p" occupies.
+ * This doesn't take care of unprintable characters, use ptr2cells() for that.
+ */
+ int
+latin_ptr2cells(char_u *p UNUSED)
+{
+ return 1;
+}
+
+ int
+utf_ptr2cells(
+ char_u *p)
+{
+ int c;
+
+ /* Need to convert to a wide character. */
+ if (*p >= 0x80)
+ {
+ c = utf_ptr2char(p);
+ /* An illegal byte is displayed as <xx>. */
+ if (utf_ptr2len(p) == 1 || c == NUL)
+ return 4;
+ /* If the char is ASCII it must be an overlong sequence. */
+ if (c < 0x80)
+ return char2cells(c);
+ return utf_char2cells(c);
+ }
+ return 1;
+}
+
+ int
+dbcs_ptr2cells(char_u *p)
+{
+ /* Number of cells is equal to number of bytes, except for euc-jp when
+ * the first byte is 0x8e. */
+ if (enc_dbcs == DBCS_JPNU && *p == 0x8e)
+ return 1;
+ return MB_BYTE2LEN(*p);
+}
+
+/*
+ * mb_ptr2cells_len() function pointer.
+ * Like mb_ptr2cells(), but limit string length to "size".
+ * For an empty string or truncated character returns 1.
+ */
+ int
+latin_ptr2cells_len(char_u *p UNUSED, int size UNUSED)
+{
+ return 1;
+}
+
+ static int
+utf_ptr2cells_len(char_u *p, int size)
+{
+ int c;
+
+ /* Need to convert to a wide character. */
+ if (size > 0 && *p >= 0x80)
+ {
+ if (utf_ptr2len_len(p, size) < utf8len_tab[*p])
+ return 1; /* truncated */
+ c = utf_ptr2char(p);
+ /* An illegal byte is displayed as <xx>. */
+ if (utf_ptr2len(p) == 1 || c == NUL)
+ return 4;
+ /* If the char is ASCII it must be an overlong sequence. */
+ if (c < 0x80)
+ return char2cells(c);
+ return utf_char2cells(c);
+ }
+ return 1;
+}
+
+ static int
+dbcs_ptr2cells_len(char_u *p, int size)
+{
+ /* Number of cells is equal to number of bytes, except for euc-jp when
+ * the first byte is 0x8e. */
+ if (size <= 1 || (enc_dbcs == DBCS_JPNU && *p == 0x8e))
+ return 1;
+ return MB_BYTE2LEN(*p);
+}
+
+/*
+ * mb_char2cells() function pointer.
+ * Return the number of display cells character "c" occupies.
+ * Only takes care of multi-byte chars, not "^C" and such.
+ */
+ int
+latin_char2cells(int c UNUSED)
+{
+ return 1;
+}
+
+ static int
+dbcs_char2cells(int c)
+{
+ /* Number of cells is equal to number of bytes, except for euc-jp when
+ * the first byte is 0x8e. */
+ if (enc_dbcs == DBCS_JPNU && ((unsigned)c >> 8) == 0x8e)
+ return 1;
+ /* use the first byte */
+ return MB_BYTE2LEN((unsigned)c >> 8);
+}
+
+/*
+ * Return the number of cells occupied by string "p".
+ * Stop at a NUL character. When "len" >= 0 stop at character "p[len]".
+ */
+ int
+mb_string2cells(char_u *p, int len)
+{
+ int i;
+ int clen = 0;
+
+ for (i = 0; (len < 0 || i < len) && p[i] != NUL; i += (*mb_ptr2len)(p + i))
+ clen += (*mb_ptr2cells)(p + i);
+ return clen;
+}
+
+/*
+ * mb_off2cells() function pointer.
+ * Return number of display cells for char at ScreenLines[off].
+ * We make sure that the offset used is less than "max_off".
+ */
+ int
+latin_off2cells(unsigned off UNUSED, unsigned max_off UNUSED)
+{
+ return 1;
+}
+
+ int
+dbcs_off2cells(unsigned off, unsigned max_off)
+{
+ /* never check beyond end of the line */
+ if (off >= max_off)
+ return 1;
+
+ /* Number of cells is equal to number of bytes, except for euc-jp when
+ * the first byte is 0x8e. */
+ if (enc_dbcs == DBCS_JPNU && ScreenLines[off] == 0x8e)
+ return 1;
+ return MB_BYTE2LEN(ScreenLines[off]);
+}
+
+ int
+utf_off2cells(unsigned off, unsigned max_off)
+{
+ return (off + 1 < max_off && ScreenLines[off + 1] == 0) ? 2 : 1;
+}
+
+/*
+ * mb_ptr2char() function pointer.
+ * Convert a byte sequence into a character.
+ */
+ int
+latin_ptr2char(char_u *p)
+{
+ return *p;
+}
+
+ static int
+dbcs_ptr2char(char_u *p)
+{
+ if (MB_BYTE2LEN(*p) > 1 && p[1] != NUL)
+ return (p[0] << 8) + p[1];
+ return *p;
+}
+
+/*
+ * Convert a UTF-8 byte sequence to a wide character.
+ * If the sequence is illegal or truncated by a NUL the first byte is
+ * returned.
+ * For an overlong sequence this may return zero.
+ * Does not include composing characters, of course.
+ */
+ int
+utf_ptr2char(char_u *p)
+{
+ int len;
+
+ if (p[0] < 0x80) /* be quick for ASCII */
+ return p[0];
+
+ len = utf8len_tab_zero[p[0]];
+ if (len > 1 && (p[1] & 0xc0) == 0x80)
+ {
+ if (len == 2)
+ return ((p[0] & 0x1f) << 6) + (p[1] & 0x3f);
+ if ((p[2] & 0xc0) == 0x80)
+ {
+ if (len == 3)
+ return ((p[0] & 0x0f) << 12) + ((p[1] & 0x3f) << 6)
+ + (p[2] & 0x3f);
+ if ((p[3] & 0xc0) == 0x80)
+ {
+ if (len == 4)
+ return ((p[0] & 0x07) << 18) + ((p[1] & 0x3f) << 12)
+ + ((p[2] & 0x3f) << 6) + (p[3] & 0x3f);
+ if ((p[4] & 0xc0) == 0x80)
+ {
+ if (len == 5)
+ return ((p[0] & 0x03) << 24) + ((p[1] & 0x3f) << 18)
+ + ((p[2] & 0x3f) << 12) + ((p[3] & 0x3f) << 6)
+ + (p[4] & 0x3f);
+ if ((p[5] & 0xc0) == 0x80 && len == 6)
+ return ((p[0] & 0x01) << 30) + ((p[1] & 0x3f) << 24)
+ + ((p[2] & 0x3f) << 18) + ((p[3] & 0x3f) << 12)
+ + ((p[4] & 0x3f) << 6) + (p[5] & 0x3f);
+ }
+ }
+ }
+ }
+ /* Illegal value, just return the first byte */
+ return p[0];
+}
+
+/*
+ * Convert a UTF-8 byte sequence to a wide character.
+ * String is assumed to be terminated by NUL or after "n" bytes, whichever
+ * comes first.
+ * The function is safe in the sense that it never accesses memory beyond the
+ * first "n" bytes of "s".
+ *
+ * On success, returns decoded codepoint, advances "s" to the beginning of
+ * next character and decreases "n" accordingly.
+ *
+ * If end of string was reached, returns 0 and, if "n" > 0, advances "s" past
+ * NUL byte.
+ *
+ * If byte sequence is illegal or incomplete, returns -1 and does not advance
+ * "s".
+ */
+ static int
+utf_safe_read_char_adv(char_u **s, size_t *n)
+{
+ int c, k;
+
+ if (*n == 0) /* end of buffer */
+ return 0;
+
+ k = utf8len_tab_zero[**s];
+
+ if (k == 1)
+ {
+ /* ASCII character or NUL */
+ (*n)--;
+ return *(*s)++;
+ }
+
+ if ((size_t)k <= *n)
+ {
+ /* We have a multibyte sequence and it isn't truncated by buffer
+ * limits so utf_ptr2char() is safe to use. Or the first byte is
+ * illegal (k=0), and it's also safe to use utf_ptr2char(). */
+ c = utf_ptr2char(*s);
+
+ /* On failure, utf_ptr2char() returns the first byte, so here we
+ * check equality with the first byte. The only non-ASCII character
+ * which equals the first byte of its own UTF-8 representation is
+ * U+00C3 (UTF-8: 0xC3 0x83), so need to check that special case too.
+ * It's safe even if n=1, else we would have k=2 > n. */
+ if (c != (int)(**s) || (c == 0xC3 && (*s)[1] == 0x83))
+ {
+ /* byte sequence was successfully decoded */
+ *s += k;
+ *n -= k;
+ return c;
+ }
+ }
+
+ /* byte sequence is incomplete or illegal */
+ return -1;
+}
+
+/*
+ * Get character at **pp and advance *pp to the next character.
+ * Note: composing characters are skipped!
+ */
+ int
+mb_ptr2char_adv(char_u **pp)
+{
+ int c;
+
+ c = (*mb_ptr2char)(*pp);
+ *pp += (*mb_ptr2len)(*pp);
+ return c;
+}
+
+/*
+ * Get character at **pp and advance *pp to the next character.
+ * Note: composing characters are returned as separate characters.
+ */
+ int
+mb_cptr2char_adv(char_u **pp)
+{
+ int c;
+
+ c = (*mb_ptr2char)(*pp);
+ if (enc_utf8)
+ *pp += utf_ptr2len(*pp);
+ else
+ *pp += (*mb_ptr2len)(*pp);
+ return c;
+}
+
+#if defined(FEAT_ARABIC) || defined(PROTO)
+/*
+ * Check whether we are dealing with Arabic combining characters.
+ * Note: these are NOT really composing characters!
+ */
+ int
+arabic_combine(
+ int one, /* first character */
+ int two) /* character just after "one" */
+{
+ if (one == a_LAM)
+ return arabic_maycombine(two);
+ return FALSE;
+}
+
+/*
+ * Check whether we are dealing with a character that could be regarded as an
+ * Arabic combining character, need to check the character before this.
+ */
+ int
+arabic_maycombine(int two)
+{
+ if (p_arshape && !p_tbidi)
+ return (two == a_ALEF_MADDA
+ || two == a_ALEF_HAMZA_ABOVE
+ || two == a_ALEF_HAMZA_BELOW
+ || two == a_ALEF);
+ return FALSE;
+}
+
+/*
+ * Check if the character pointed to by "p2" is a composing character when it
+ * comes after "p1". For Arabic sometimes "ab" is replaced with "c", which
+ * behaves like a composing character.
+ */
+ int
+utf_composinglike(char_u *p1, char_u *p2)
+{
+ int c2;
+
+ c2 = utf_ptr2char(p2);
+ if (utf_iscomposing(c2))
+ return TRUE;
+ if (!arabic_maycombine(c2))
+ return FALSE;
+ return arabic_combine(utf_ptr2char(p1), c2);
+}
+#endif
+
+/*
+ * Convert a UTF-8 byte string to a wide character. Also get up to MAX_MCO
+ * composing characters.
+ */
+ int
+utfc_ptr2char(
+ char_u *p,
+ int *pcc) /* return: composing chars, last one is 0 */
+{
+ int len;
+ int c;
+ int cc;
+ int i = 0;
+
+ c = utf_ptr2char(p);
+ len = utf_ptr2len(p);
+
+ /* Only accept a composing char when the first char isn't illegal. */
+ if ((len > 1 || *p < 0x80)
+ && p[len] >= 0x80
+ && UTF_COMPOSINGLIKE(p, p + len))
+ {
+ cc = utf_ptr2char(p + len);
+ for (;;)
+ {
+ pcc[i++] = cc;
+ if (i == MAX_MCO)
+ break;
+ len += utf_ptr2len(p + len);
+ if (p[len] < 0x80 || !utf_iscomposing(cc = utf_ptr2char(p + len)))
+ break;
+ }
+ }
+
+ if (i < MAX_MCO) /* last composing char must be 0 */
+ pcc[i] = 0;
+
+ return c;
+}
+
+/*
+ * Convert a UTF-8 byte string to a wide character. Also get up to MAX_MCO
+ * composing characters. Use no more than p[maxlen].
+ */
+ int
+utfc_ptr2char_len(
+ char_u *p,
+ int *pcc, /* return: composing chars, last one is 0 */
+ int maxlen)
+{
+ int len;
+ int c;
+ int cc;
+ int i = 0;
+
+ c = utf_ptr2char(p);
+ len = utf_ptr2len_len(p, maxlen);
+ /* Only accept a composing char when the first char isn't illegal. */
+ if ((len > 1 || *p < 0x80)
+ && len < maxlen
+ && p[len] >= 0x80
+ && UTF_COMPOSINGLIKE(p, p + len))
+ {
+ cc = utf_ptr2char(p + len);
+ for (;;)
+ {
+ pcc[i++] = cc;
+ if (i == MAX_MCO)
+ break;
+ len += utf_ptr2len_len(p + len, maxlen - len);
+ if (len >= maxlen
+ || p[len] < 0x80
+ || !utf_iscomposing(cc = utf_ptr2char(p + len)))
+ break;
+ }
+ }
+
+ if (i < MAX_MCO) /* last composing char must be 0 */
+ pcc[i] = 0;
+
+ return c;
+}
+
+/*
+ * Convert the character at screen position "off" to a sequence of bytes.
+ * Includes the composing characters.
+ * "buf" must at least have the length MB_MAXBYTES + 1.
+ * Only to be used when ScreenLinesUC[off] != 0.
+ * Returns the produced number of bytes.
+ */
+ int
+utfc_char2bytes(int off, char_u *buf)
+{
+ int len;
+ int i;
+
+ len = utf_char2bytes(ScreenLinesUC[off], buf);
+ for (i = 0; i < Screen_mco; ++i)
+ {
+ if (ScreenLinesC[i][off] == 0)
+ break;
+ len += utf_char2bytes(ScreenLinesC[i][off], buf + len);
+ }
+ return len;
+}
+
+/*
+ * Get the length of a UTF-8 byte sequence, not including any following
+ * composing characters.
+ * Returns 0 for "".
+ * Returns 1 for an illegal byte sequence.
+ */
+ int
+utf_ptr2len(char_u *p)
+{
+ int len;
+ int i;
+
+ if (*p == NUL)
+ return 0;
+ len = utf8len_tab[*p];
+ for (i = 1; i < len; ++i)
+ if ((p[i] & 0xc0) != 0x80)
+ return 1;
+ return len;
+}
+
+/*
+ * Return length of UTF-8 character, obtained from the first byte.
+ * "b" must be between 0 and 255!
+ * Returns 1 for an invalid first byte value.
+ */
+ int
+utf_byte2len(int b)
+{
+ return utf8len_tab[b];
+}
+
+/*
+ * Get the length of UTF-8 byte sequence "p[size]". Does not include any
+ * following composing characters.
+ * Returns 1 for "".
+ * Returns 1 for an illegal byte sequence (also in incomplete byte seq.).
+ * Returns number > "size" for an incomplete byte sequence.
+ * Never returns zero.
+ */
+ int
+utf_ptr2len_len(char_u *p, int size)
+{
+ int len;
+ int i;
+ int m;
+
+ len = utf8len_tab[*p];
+ if (len == 1)
+ return 1; /* NUL, ascii or illegal lead byte */
+ if (len > size)
+ m = size; /* incomplete byte sequence. */
+ else
+ m = len;
+ for (i = 1; i < m; ++i)
+ if ((p[i] & 0xc0) != 0x80)
+ return 1;
+ return len;
+}
+
+/*
+ * Return the number of bytes the UTF-8 encoding of the character at "p" takes.
+ * This includes following composing characters.
+ */
+ int
+utfc_ptr2len(char_u *p)
+{
+ int len;
+ int b0 = *p;
+#ifdef FEAT_ARABIC
+ int prevlen;
+#endif
+
+ if (b0 == NUL)
+ return 0;
+ if (b0 < 0x80 && p[1] < 0x80) /* be quick for ASCII */
+ return 1;
+
+ /* Skip over first UTF-8 char, stopping at a NUL byte. */
+ len = utf_ptr2len(p);
+
+ /* Check for illegal byte. */
+ if (len == 1 && b0 >= 0x80)
+ return 1;
+
+ /*
+ * Check for composing characters. We can handle only the first six, but
+ * skip all of them (otherwise the cursor would get stuck).
+ */
+#ifdef FEAT_ARABIC
+ prevlen = 0;
+#endif
+ for (;;)
+ {
+ if (p[len] < 0x80 || !UTF_COMPOSINGLIKE(p + prevlen, p + len))
+ return len;
+
+ /* Skip over composing char */
+#ifdef FEAT_ARABIC
+ prevlen = len;
+#endif
+ len += utf_ptr2len(p + len);
+ }
+}
+
+/*
+ * Return the number of bytes the UTF-8 encoding of the character at "p[size]"
+ * takes. This includes following composing characters.
+ * Returns 0 for an empty string.
+ * Returns 1 for an illegal char or an incomplete byte sequence.
+ */
+ int
+utfc_ptr2len_len(char_u *p, int size)
+{
+ int len;
+#ifdef FEAT_ARABIC
+ int prevlen;
+#endif
+
+ if (size < 1 || *p == NUL)
+ return 0;
+ if (p[0] < 0x80 && (size == 1 || p[1] < 0x80)) /* be quick for ASCII */
+ return 1;
+
+ /* Skip over first UTF-8 char, stopping at a NUL byte. */
+ len = utf_ptr2len_len(p, size);
+
+ /* Check for illegal byte and incomplete byte sequence. */
+ if ((len == 1 && p[0] >= 0x80) || len > size)
+ return 1;
+
+ /*
+ * Check for composing characters. We can handle only the first six, but
+ * skip all of them (otherwise the cursor would get stuck).
+ */
+#ifdef FEAT_ARABIC
+ prevlen = 0;
+#endif
+ while (len < size)
+ {
+ int len_next_char;
+
+ if (p[len] < 0x80)
+ break;
+
+ /*
+ * Next character length should not go beyond size to ensure that
+ * UTF_COMPOSINGLIKE(...) does not read beyond size.
+ */
+ len_next_char = utf_ptr2len_len(p + len, size - len);
+ if (len_next_char > size - len)
+ break;
+
+ if (!UTF_COMPOSINGLIKE(p + prevlen, p + len))
+ break;
+
+ /* Skip over composing char */
+#ifdef FEAT_ARABIC
+ prevlen = len;
+#endif
+ len += len_next_char;
+ }
+ return len;
+}
+
+/*
+ * Return the number of bytes the UTF-8 encoding of character "c" takes.
+ * This does not include composing characters.
+ */
+ int
+utf_char2len(int c)
+{
+ if (c < 0x80)
+ return 1;
+ if (c < 0x800)
+ return 2;
+ if (c < 0x10000)
+ return 3;
+ if (c < 0x200000)
+ return 4;
+ if (c < 0x4000000)
+ return 5;
+ return 6;
+}
+
+/*
+ * Convert Unicode character "c" to UTF-8 string in "buf[]".
+ * Returns the number of bytes.
+ */
+ int
+utf_char2bytes(int c, char_u *buf)
+{
+ if (c < 0x80) /* 7 bits */
+ {
+ buf[0] = c;
+ return 1;
+ }
+ if (c < 0x800) /* 11 bits */
+ {
+ buf[0] = 0xc0 + ((unsigned)c >> 6);
+ buf[1] = 0x80 + (c & 0x3f);
+ return 2;
+ }
+ if (c < 0x10000) /* 16 bits */
+ {
+ buf[0] = 0xe0 + ((unsigned)c >> 12);
+ buf[1] = 0x80 + (((unsigned)c >> 6) & 0x3f);
+ buf[2] = 0x80 + (c & 0x3f);
+ return 3;
+ }
+ if (c < 0x200000) /* 21 bits */
+ {
+ buf[0] = 0xf0 + ((unsigned)c >> 18);
+ buf[1] = 0x80 + (((unsigned)c >> 12) & 0x3f);
+ buf[2] = 0x80 + (((unsigned)c >> 6) & 0x3f);
+ buf[3] = 0x80 + (c & 0x3f);
+ return 4;
+ }
+ if (c < 0x4000000) /* 26 bits */
+ {
+ buf[0] = 0xf8 + ((unsigned)c >> 24);
+ buf[1] = 0x80 + (((unsigned)c >> 18) & 0x3f);
+ buf[2] = 0x80 + (((unsigned)c >> 12) & 0x3f);
+ buf[3] = 0x80 + (((unsigned)c >> 6) & 0x3f);
+ buf[4] = 0x80 + (c & 0x3f);
+ return 5;
+ }
+ /* 31 bits */
+ buf[0] = 0xfc + ((unsigned)c >> 30);
+ buf[1] = 0x80 + (((unsigned)c >> 24) & 0x3f);
+ buf[2] = 0x80 + (((unsigned)c >> 18) & 0x3f);
+ buf[3] = 0x80 + (((unsigned)c >> 12) & 0x3f);
+ buf[4] = 0x80 + (((unsigned)c >> 6) & 0x3f);
+ buf[5] = 0x80 + (c & 0x3f);
+ return 6;
+}
+
+#if defined(FEAT_TERMINAL) || defined(PROTO)
+/*
+ * utf_iscomposing() with different argument type for libvterm.
+ */
+ int
+utf_iscomposing_uint(UINT32_T c)
+{
+ return utf_iscomposing((int)c);
+}
+#endif
+
+/*
+ * Return TRUE if "c" is a composing UTF-8 character. This means it will be
+ * drawn on top of the preceding character.
+ * Based on code from Markus Kuhn.
+ */
+ int
+utf_iscomposing(int c)
+{
+ /* Sorted list of non-overlapping intervals.
+ * Generated by ../runtime/tools/unicode.vim. */
+ static struct interval combining[] =
+ {
+ {0x0300, 0x036f},
+ {0x0483, 0x0489},
+ {0x0591, 0x05bd},
+ {0x05bf, 0x05bf},
+ {0x05c1, 0x05c2},
+ {0x05c4, 0x05c5},
+ {0x05c7, 0x05c7},
+ {0x0610, 0x061a},
+ {0x064b, 0x065f},
+ {0x0670, 0x0670},
+ {0x06d6, 0x06dc},
+ {0x06df, 0x06e4},
+ {0x06e7, 0x06e8},
+ {0x06ea, 0x06ed},
+ {0x0711, 0x0711},
+ {0x0730, 0x074a},
+ {0x07a6, 0x07b0},
+ {0x07eb, 0x07f3},
+ {0x07fd, 0x07fd},
+ {0x0816, 0x0819},
+ {0x081b, 0x0823},
+ {0x0825, 0x0827},
+ {0x0829, 0x082d},
+ {0x0859, 0x085b},
+ {0x08d3, 0x08e1},
+ {0x08e3, 0x0903},
+ {0x093a, 0x093c},
+ {0x093e, 0x094f},
+ {0x0951, 0x0957},
+ {0x0962, 0x0963},
+ {0x0981, 0x0983},
+ {0x09bc, 0x09bc},
+ {0x09be, 0x09c4},
+ {0x09c7, 0x09c8},
+ {0x09cb, 0x09cd},
+ {0x09d7, 0x09d7},
+ {0x09e2, 0x09e3},
+ {0x09fe, 0x09fe},
+ {0x0a01, 0x0a03},
+ {0x0a3c, 0x0a3c},
+ {0x0a3e, 0x0a42},
+ {0x0a47, 0x0a48},
+ {0x0a4b, 0x0a4d},
+ {0x0a51, 0x0a51},
+ {0x0a70, 0x0a71},
+ {0x0a75, 0x0a75},
+ {0x0a81, 0x0a83},
+ {0x0abc, 0x0abc},
+ {0x0abe, 0x0ac5},
+ {0x0ac7, 0x0ac9},
+ {0x0acb, 0x0acd},
+ {0x0ae2, 0x0ae3},
+ {0x0afa, 0x0aff},
+ {0x0b01, 0x0b03},
+ {0x0b3c, 0x0b3c},
+ {0x0b3e, 0x0b44},
+ {0x0b47, 0x0b48},
+ {0x0b4b, 0x0b4d},
+ {0x0b56, 0x0b57},
+ {0x0b62, 0x0b63},
+ {0x0b82, 0x0b82},
+ {0x0bbe, 0x0bc2},
+ {0x0bc6, 0x0bc8},
+ {0x0bca, 0x0bcd},
+ {0x0bd7, 0x0bd7},
+ {0x0c00, 0x0c04},
+ {0x0c3e, 0x0c44},
+ {0x0c46, 0x0c48},
+ {0x0c4a, 0x0c4d},
+ {0x0c55, 0x0c56},
+ {0x0c62, 0x0c63},
+ {0x0c81, 0x0c83},
+ {0x0cbc, 0x0cbc},
+ {0x0cbe, 0x0cc4},
+ {0x0cc6, 0x0cc8},
+ {0x0cca, 0x0ccd},
+ {0x0cd5, 0x0cd6},
+ {0x0ce2, 0x0ce3},
+ {0x0d00, 0x0d03},
+ {0x0d3b, 0x0d3c},
+ {0x0d3e, 0x0d44},
+ {0x0d46, 0x0d48},
+ {0x0d4a, 0x0d4d},
+ {0x0d57, 0x0d57},
+ {0x0d62, 0x0d63},
+ {0x0d82, 0x0d83},
+ {0x0dca, 0x0dca},
+ {0x0dcf, 0x0dd4},
+ {0x0dd6, 0x0dd6},
+ {0x0dd8, 0x0ddf},
+ {0x0df2, 0x0df3},
+ {0x0e31, 0x0e31},
+ {0x0e34, 0x0e3a},
+ {0x0e47, 0x0e4e},
+ {0x0eb1, 0x0eb1},
+ {0x0eb4, 0x0eb9},
+ {0x0ebb, 0x0ebc},
+ {0x0ec8, 0x0ecd},
+ {0x0f18, 0x0f19},
+ {0x0f35, 0x0f35},
+ {0x0f37, 0x0f37},
+ {0x0f39, 0x0f39},
+ {0x0f3e, 0x0f3f},
+ {0x0f71, 0x0f84},
+ {0x0f86, 0x0f87},
+ {0x0f8d, 0x0f97},
+ {0x0f99, 0x0fbc},
+ {0x0fc6, 0x0fc6},
+ {0x102b, 0x103e},
+ {0x1056, 0x1059},
+ {0x105e, 0x1060},
+ {0x1062, 0x1064},
+ {0x1067, 0x106d},
+ {0x1071, 0x1074},
+ {0x1082, 0x108d},
+ {0x108f, 0x108f},
+ {0x109a, 0x109d},
+ {0x135d, 0x135f},
+ {0x1712, 0x1714},
+ {0x1732, 0x1734},
+ {0x1752, 0x1753},
+ {0x1772, 0x1773},
+ {0x17b4, 0x17d3},
+ {0x17dd, 0x17dd},
+ {0x180b, 0x180d},
+ {0x1885, 0x1886},
+ {0x18a9, 0x18a9},
+ {0x1920, 0x192b},
+ {0x1930, 0x193b},
+ {0x1a17, 0x1a1b},
+ {0x1a55, 0x1a5e},
+ {0x1a60, 0x1a7c},
+ {0x1a7f, 0x1a7f},
+ {0x1ab0, 0x1abe},
+ {0x1b00, 0x1b04},
+ {0x1b34, 0x1b44},
+ {0x1b6b, 0x1b73},
+ {0x1b80, 0x1b82},
+ {0x1ba1, 0x1bad},
+ {0x1be6, 0x1bf3},
+ {0x1c24, 0x1c37},
+ {0x1cd0, 0x1cd2},
+ {0x1cd4, 0x1ce8},
+ {0x1ced, 0x1ced},
+ {0x1cf2, 0x1cf4},
+ {0x1cf7, 0x1cf9},
+ {0x1dc0, 0x1df9},
+ {0x1dfb, 0x1dff},
+ {0x20d0, 0x20f0},
+ {0x2cef, 0x2cf1},
+ {0x2d7f, 0x2d7f},
+ {0x2de0, 0x2dff},
+ {0x302a, 0x302f},
+ {0x3099, 0x309a},
+ {0xa66f, 0xa672},
+ {0xa674, 0xa67d},
+ {0xa69e, 0xa69f},
+ {0xa6f0, 0xa6f1},
+ {0xa802, 0xa802},
+ {0xa806, 0xa806},
+ {0xa80b, 0xa80b},
+ {0xa823, 0xa827},
+ {0xa880, 0xa881},
+ {0xa8b4, 0xa8c5},
+ {0xa8e0, 0xa8f1},
+ {0xa8ff, 0xa8ff},
+ {0xa926, 0xa92d},
+ {0xa947, 0xa953},
+ {0xa980, 0xa983},
+ {0xa9b3, 0xa9c0},
+ {0xa9e5, 0xa9e5},
+ {0xaa29, 0xaa36},
+ {0xaa43, 0xaa43},
+ {0xaa4c, 0xaa4d},
+ {0xaa7b, 0xaa7d},
+ {0xaab0, 0xaab0},
+ {0xaab2, 0xaab4},
+ {0xaab7, 0xaab8},
+ {0xaabe, 0xaabf},
+ {0xaac1, 0xaac1},
+ {0xaaeb, 0xaaef},
+ {0xaaf5, 0xaaf6},
+ {0xabe3, 0xabea},
+ {0xabec, 0xabed},
+ {0xfb1e, 0xfb1e},
+ {0xfe00, 0xfe0f},
+ {0xfe20, 0xfe2f},
+ {0x101fd, 0x101fd},
+ {0x102e0, 0x102e0},
+ {0x10376, 0x1037a},
+ {0x10a01, 0x10a03},
+ {0x10a05, 0x10a06},
+ {0x10a0c, 0x10a0f},
+ {0x10a38, 0x10a3a},
+ {0x10a3f, 0x10a3f},
+ {0x10ae5, 0x10ae6},
+ {0x10d24, 0x10d27},
+ {0x10f46, 0x10f50},
+ {0x11000, 0x11002},
+ {0x11038, 0x11046},
+ {0x1107f, 0x11082},
+ {0x110b0, 0x110ba},
+ {0x11100, 0x11102},
+ {0x11127, 0x11134},
+ {0x11145, 0x11146},
+ {0x11173, 0x11173},
+ {0x11180, 0x11182},
+ {0x111b3, 0x111c0},
+ {0x111c9, 0x111cc},
+ {0x1122c, 0x11237},
+ {0x1123e, 0x1123e},
+ {0x112df, 0x112ea},
+ {0x11300, 0x11303},
+ {0x1133b, 0x1133c},
+ {0x1133e, 0x11344},
+ {0x11347, 0x11348},
+ {0x1134b, 0x1134d},
+ {0x11357, 0x11357},
+ {0x11362, 0x11363},
+ {0x11366, 0x1136c},
+ {0x11370, 0x11374},
+ {0x11435, 0x11446},
+ {0x1145e, 0x1145e},
+ {0x114b0, 0x114c3},
+ {0x115af, 0x115b5},
+ {0x115b8, 0x115c0},
+ {0x115dc, 0x115dd},
+ {0x11630, 0x11640},
+ {0x116ab, 0x116b7},
+ {0x1171d, 0x1172b},
+ {0x1182c, 0x1183a},
+ {0x11a01, 0x11a0a},
+ {0x11a33, 0x11a39},
+ {0x11a3b, 0x11a3e},
+ {0x11a47, 0x11a47},
+ {0x11a51, 0x11a5b},
+ {0x11a8a, 0x11a99},
+ {0x11c2f, 0x11c36},
+ {0x11c38, 0x11c3f},
+ {0x11c92, 0x11ca7},
+ {0x11ca9, 0x11cb6},
+ {0x11d31, 0x11d36},
+ {0x11d3a, 0x11d3a},
+ {0x11d3c, 0x11d3d},
+ {0x11d3f, 0x11d45},
+ {0x11d47, 0x11d47},
+ {0x11d8a, 0x11d8e},
+ {0x11d90, 0x11d91},
+ {0x11d93, 0x11d97},
+ {0x11ef3, 0x11ef6},
+ {0x16af0, 0x16af4},
+ {0x16b30, 0x16b36},
+ {0x16f51, 0x16f7e},
+ {0x16f8f, 0x16f92},
+ {0x1bc9d, 0x1bc9e},
+ {0x1d165, 0x1d169},
+ {0x1d16d, 0x1d172},
+ {0x1d17b, 0x1d182},
+ {0x1d185, 0x1d18b},
+ {0x1d1aa, 0x1d1ad},
+ {0x1d242, 0x1d244},
+ {0x1da00, 0x1da36},
+ {0x1da3b, 0x1da6c},
+ {0x1da75, 0x1da75},
+ {0x1da84, 0x1da84},
+ {0x1da9b, 0x1da9f},
+ {0x1daa1, 0x1daaf},
+ {0x1e000, 0x1e006},
+ {0x1e008, 0x1e018},
+ {0x1e01b, 0x1e021},
+ {0x1e023, 0x1e024},
+ {0x1e026, 0x1e02a},
+ {0x1e8d0, 0x1e8d6},
+ {0x1e944, 0x1e94a},
+ {0xe0100, 0xe01ef}
+ };
+
+ return intable(combining, sizeof(combining), c);
+}
+
+/*
+ * Return TRUE for characters that can be displayed in a normal way.
+ * Only for characters of 0x100 and above!
+ */
+ int
+utf_printable(int c)
+{
+#ifdef USE_WCHAR_FUNCTIONS
+ /*
+ * Assume the iswprint() library function works better than our own stuff.
+ */
+ return iswprint(c);
+#else
+ /* Sorted list of non-overlapping intervals.
+ * 0xd800-0xdfff is reserved for UTF-16, actually illegal. */
+ static struct interval nonprint[] =
+ {
+ {0x070f, 0x070f}, {0x180b, 0x180e}, {0x200b, 0x200f}, {0x202a, 0x202e},
+ {0x206a, 0x206f}, {0xd800, 0xdfff}, {0xfeff, 0xfeff}, {0xfff9, 0xfffb},
+ {0xfffe, 0xffff}
+ };
+
+ return !intable(nonprint, sizeof(nonprint), c);
+#endif
+}
+
+/* Sorted list of non-overlapping intervals of all Emoji characters,
+ * based on http://unicode.org/emoji/charts/emoji-list.html */
+static struct interval emoji_all[] =
+{
+ {0x203c, 0x203c},
+ {0x2049, 0x2049},
+ {0x2122, 0x2122},
+ {0x2139, 0x2139},
+ {0x2194, 0x2199},
+ {0x21a9, 0x21aa},
+ {0x231a, 0x231b},
+ {0x2328, 0x2328},
+ {0x23cf, 0x23cf},
+ {0x23e9, 0x23f3},
+ {0x23f8, 0x23fa},
+ {0x24c2, 0x24c2},
+ {0x25aa, 0x25ab},
+ {0x25b6, 0x25b6},
+ {0x25c0, 0x25c0},
+ {0x25fb, 0x25fe},
+ {0x2600, 0x2604},
+ {0x260e, 0x260e},
+ {0x2611, 0x2611},
+ {0x2614, 0x2615},
+ {0x2618, 0x2618},
+ {0x261d, 0x261d},
+ {0x2620, 0x2620},
+ {0x2622, 0x2623},
+ {0x2626, 0x2626},
+ {0x262a, 0x262a},
+ {0x262e, 0x262f},
+ {0x2638, 0x263a},
+ {0x2640, 0x2640},
+ {0x2642, 0x2642},
+ {0x2648, 0x2653},
+ {0x265f, 0x2660},
+ {0x2663, 0x2663},
+ {0x2665, 0x2666},
+ {0x2668, 0x2668},
+ {0x267b, 0x267b},
+ {0x267e, 0x267f},
+ {0x2692, 0x2697},
+ {0x2699, 0x2699},
+ {0x269b, 0x269c},
+ {0x26a0, 0x26a1},
+ {0x26aa, 0x26ab},
+ {0x26b0, 0x26b1},
+ {0x26bd, 0x26be},
+ {0x26c4, 0x26c5},
+ {0x26c8, 0x26c8},
+ {0x26ce, 0x26cf},
+ {0x26d1, 0x26d1},
+ {0x26d3, 0x26d4},
+ {0x26e9, 0x26ea},
+ {0x26f0, 0x26f5},
+ {0x26f7, 0x26fa},
+ {0x26fd, 0x26fd},
+ {0x2702, 0x2702},
+ {0x2705, 0x2705},
+ {0x2708, 0x270d},
+ {0x270f, 0x270f},
+ {0x2712, 0x2712},
+ {0x2714, 0x2714},
+ {0x2716, 0x2716},
+ {0x271d, 0x271d},
+ {0x2721, 0x2721},
+ {0x2728, 0x2728},
+ {0x2733, 0x2734},
+ {0x2744, 0x2744},
+ {0x2747, 0x2747},
+ {0x274c, 0x274c},
+ {0x274e, 0x274e},
+ {0x2753, 0x2755},
+ {0x2757, 0x2757},
+ {0x2763, 0x2764},
+ {0x2795, 0x2797},
+ {0x27a1, 0x27a1},
+ {0x27b0, 0x27b0},
+ {0x27bf, 0x27bf},
+ {0x2934, 0x2935},
+ {0x2b05, 0x2b07},
+ {0x2b1b, 0x2b1c},
+ {0x2b50, 0x2b50},
+ {0x2b55, 0x2b55},
+ {0x3030, 0x3030},
+ {0x303d, 0x303d},
+ {0x3297, 0x3297},
+ {0x3299, 0x3299},
+ {0x1f004, 0x1f004},
+ {0x1f0cf, 0x1f0cf},
+ {0x1f170, 0x1f171},
+ {0x1f17e, 0x1f17f},
+ {0x1f18e, 0x1f18e},
+ {0x1f191, 0x1f19a},
+ {0x1f1e6, 0x1f1ff},
+ {0x1f201, 0x1f202},
+ {0x1f21a, 0x1f21a},
+ {0x1f22f, 0x1f22f},
+ {0x1f232, 0x1f23a},
+ {0x1f250, 0x1f251},
+ {0x1f300, 0x1f321},
+ {0x1f324, 0x1f393},
+ {0x1f396, 0x1f397},
+ {0x1f399, 0x1f39b},
+ {0x1f39e, 0x1f3f0},
+ {0x1f3f3, 0x1f3f5},
+ {0x1f3f7, 0x1f4fd},
+ {0x1f4ff, 0x1f53d},
+ {0x1f549, 0x1f54e},
+ {0x1f550, 0x1f567},
+ {0x1f56f, 0x1f570},
+ {0x1f573, 0x1f57a},
+ {0x1f587, 0x1f587},
+ {0x1f58a, 0x1f58d},
+ {0x1f590, 0x1f590},
+ {0x1f595, 0x1f596},
+ {0x1f5a4, 0x1f5a5},
+ {0x1f5a8, 0x1f5a8},
+ {0x1f5b1, 0x1f5b2},
+ {0x1f5bc, 0x1f5bc},
+ {0x1f5c2, 0x1f5c4},
+ {0x1f5d1, 0x1f5d3},
+ {0x1f5dc, 0x1f5de},
+ {0x1f5e1, 0x1f5e1},
+ {0x1f5e3, 0x1f5e3},
+ {0x1f5e8, 0x1f5e8},
+ {0x1f5ef, 0x1f5ef},
+ {0x1f5f3, 0x1f5f3},
+ {0x1f5fa, 0x1f64f},
+ {0x1f680, 0x1f6c5},
+ {0x1f6cb, 0x1f6d2},
+ {0x1f6e0, 0x1f6e5},
+ {0x1f6e9, 0x1f6e9},
+ {0x1f6eb, 0x1f6ec},
+ {0x1f6f0, 0x1f6f0},
+ {0x1f6f3, 0x1f6f9},
+ {0x1f910, 0x1f93a},
+ {0x1f93c, 0x1f93e},
+ {0x1f940, 0x1f945},
+ {0x1f947, 0x1f970},
+ {0x1f973, 0x1f976},
+ {0x1f97a, 0x1f97a},
+ {0x1f97c, 0x1f9a2},
+ {0x1f9b0, 0x1f9b9},
+ {0x1f9c0, 0x1f9c2},
+ {0x1f9d0, 0x1f9ff}
+};
+
+/*
+ * Get class of a Unicode character.
+ * 0: white space
+ * 1: punctuation
+ * 2 or bigger: some class of word character.
+ */
+ int
+utf_class(int c)
+{
+ return utf_class_buf(c, curbuf);
+}
+
+ int
+utf_class_buf(int c, buf_T *buf)
+{
+ /* sorted list of non-overlapping intervals */
+ static struct clinterval
+ {
+ unsigned int first;
+ unsigned int last;
+ unsigned int class;
+ } classes[] =
+ {
+ {0x037e, 0x037e, 1}, /* Greek question mark */
+ {0x0387, 0x0387, 1}, /* Greek ano teleia */
+ {0x055a, 0x055f, 1}, /* Armenian punctuation */
+ {0x0589, 0x0589, 1}, /* Armenian full stop */
+ {0x05be, 0x05be, 1},
+ {0x05c0, 0x05c0, 1},
+ {0x05c3, 0x05c3, 1},
+ {0x05f3, 0x05f4, 1},
+ {0x060c, 0x060c, 1},
+ {0x061b, 0x061b, 1},
+ {0x061f, 0x061f, 1},
+ {0x066a, 0x066d, 1},
+ {0x06d4, 0x06d4, 1},
+ {0x0700, 0x070d, 1}, /* Syriac punctuation */
+ {0x0964, 0x0965, 1},
+ {0x0970, 0x0970, 1},
+ {0x0df4, 0x0df4, 1},
+ {0x0e4f, 0x0e4f, 1},
+ {0x0e5a, 0x0e5b, 1},
+ {0x0f04, 0x0f12, 1},
+ {0x0f3a, 0x0f3d, 1},
+ {0x0f85, 0x0f85, 1},
+ {0x104a, 0x104f, 1}, /* Myanmar punctuation */
+ {0x10fb, 0x10fb, 1}, /* Georgian punctuation */
+ {0x1361, 0x1368, 1}, /* Ethiopic punctuation */
+ {0x166d, 0x166e, 1}, /* Canadian Syl. punctuation */
+ {0x1680, 0x1680, 0},
+ {0x169b, 0x169c, 1},
+ {0x16eb, 0x16ed, 1},
+ {0x1735, 0x1736, 1},
+ {0x17d4, 0x17dc, 1}, /* Khmer punctuation */
+ {0x1800, 0x180a, 1}, /* Mongolian punctuation */
+ {0x2000, 0x200b, 0}, /* spaces */
+ {0x200c, 0x2027, 1}, /* punctuation and symbols */
+ {0x2028, 0x2029, 0},
+ {0x202a, 0x202e, 1}, /* punctuation and symbols */
+ {0x202f, 0x202f, 0},
+ {0x2030, 0x205e, 1}, /* punctuation and symbols */
+ {0x205f, 0x205f, 0},
+ {0x2060, 0x27ff, 1}, /* punctuation and symbols */
+ {0x2070, 0x207f, 0x2070}, /* superscript */
+ {0x2080, 0x2094, 0x2080}, /* subscript */
+ {0x20a0, 0x27ff, 1}, /* all kinds of symbols */
+ {0x2800, 0x28ff, 0x2800}, /* braille */
+ {0x2900, 0x2998, 1}, /* arrows, brackets, etc. */
+ {0x29d8, 0x29db, 1},
+ {0x29fc, 0x29fd, 1},
+ {0x2e00, 0x2e7f, 1}, /* supplemental punctuation */
+ {0x3000, 0x3000, 0}, /* ideographic space */
+ {0x3001, 0x3020, 1}, /* ideographic punctuation */
+ {0x3030, 0x3030, 1},
+ {0x303d, 0x303d, 1},
+ {0x3040, 0x309f, 0x3040}, /* Hiragana */
+ {0x30a0, 0x30ff, 0x30a0}, /* Katakana */
+ {0x3300, 0x9fff, 0x4e00}, /* CJK Ideographs */
+ {0xac00, 0xd7a3, 0xac00}, /* Hangul Syllables */
+ {0xf900, 0xfaff, 0x4e00}, /* CJK Ideographs */
+ {0xfd3e, 0xfd3f, 1},
+ {0xfe30, 0xfe6b, 1}, /* punctuation forms */
+ {0xff00, 0xff0f, 1}, /* half/fullwidth ASCII */
+ {0xff1a, 0xff20, 1}, /* half/fullwidth ASCII */
+ {0xff3b, 0xff40, 1}, /* half/fullwidth ASCII */
+ {0xff5b, 0xff65, 1}, /* half/fullwidth ASCII */
+ {0x20000, 0x2a6df, 0x4e00}, /* CJK Ideographs */
+ {0x2a700, 0x2b73f, 0x4e00}, /* CJK Ideographs */
+ {0x2b740, 0x2b81f, 0x4e00}, /* CJK Ideographs */
+ {0x2f800, 0x2fa1f, 0x4e00}, /* CJK Ideographs */
+ };
+
+ int bot = 0;
+ int top = sizeof(classes) / sizeof(struct clinterval) - 1;
+ int mid;
+
+ /* First quick check for Latin1 characters, use 'iskeyword'. */
+ if (c < 0x100)
+ {
+ if (c == ' ' || c == '\t' || c == NUL || c == 0xa0)
+ return 0; /* blank */
+ if (vim_iswordc_buf(c, buf))
+ return 2; /* word character */
+ return 1; /* punctuation */
+ }
+
+ /* binary search in table */
+ while (top >= bot)
+ {
+ mid = (bot + top) / 2;
+ if (classes[mid].last < (unsigned int)c)
+ bot = mid + 1;
+ else if (classes[mid].first > (unsigned int)c)
+ top = mid - 1;
+ else
+ return (int)classes[mid].class;
+ }
+
+ /* emoji */
+ if (intable(emoji_all, sizeof(emoji_all), c))
+ return 3;
+
+ /* most other characters are "word" characters */
+ return 2;
+}
+
+ int
+utf_ambiguous_width(int c)
+{
+ return c >= 0x80 && (intable(ambiguous, sizeof(ambiguous), c)
+ || intable(emoji_all, sizeof(emoji_all), c));
+}
+
+/*
+ * Code for Unicode case-dependent operations. Based on notes in
+ * http://www.unicode.org/Public/UNIDATA/CaseFolding.txt
+ * This code uses simple case folding, not full case folding.
+ * Last updated for Unicode 5.2.
+ */
+
+/*
+ * The following tables are built by ../runtime/tools/unicode.vim.
+ * They must be in numeric order, because we use binary search.
+ * An entry such as {0x41,0x5a,1,32} means that Unicode characters in the
+ * range from 0x41 to 0x5a inclusive, stepping by 1, are changed to
+ * folded/upper/lower by adding 32.
+ */
+typedef struct
+{
+ int rangeStart;
+ int rangeEnd;
+ int step;
+ int offset;
+} convertStruct;
+
+static convertStruct foldCase[] =
+{
+ {0x41,0x5a,1,32},
+ {0xb5,0xb5,-1,775},
+ {0xc0,0xd6,1,32},
+ {0xd8,0xde,1,32},
+ {0x100,0x12e,2,1},
+ {0x132,0x136,2,1},
+ {0x139,0x147,2,1},
+ {0x14a,0x176,2,1},
+ {0x178,0x178,-1,-121},
+ {0x179,0x17d,2,1},
+ {0x17f,0x17f,-1,-268},
+ {0x181,0x181,-1,210},
+ {0x182,0x184,2,1},
+ {0x186,0x186,-1,206},
+ {0x187,0x187,-1,1},
+ {0x189,0x18a,1,205},
+ {0x18b,0x18b,-1,1},
+ {0x18e,0x18e,-1,79},
+ {0x18f,0x18f,-1,202},
+ {0x190,0x190,-1,203},
+ {0x191,0x191,-1,1},
+ {0x193,0x193,-1,205},
+ {0x194,0x194,-1,207},
+ {0x196,0x196,-1,211},
+ {0x197,0x197,-1,209},
+ {0x198,0x198,-1,1},
+ {0x19c,0x19c,-1,211},
+ {0x19d,0x19d,-1,213},
+ {0x19f,0x19f,-1,214},
+ {0x1a0,0x1a4,2,1},
+ {0x1a6,0x1a6,-1,218},
+ {0x1a7,0x1a7,-1,1},
+ {0x1a9,0x1a9,-1,218},
+ {0x1ac,0x1ac,-1,1},
+ {0x1ae,0x1ae,-1,218},
+ {0x1af,0x1af,-1,1},
+ {0x1b1,0x1b2,1,217},
+ {0x1b3,0x1b5,2,1},
+ {0x1b7,0x1b7,-1,219},
+ {0x1b8,0x1bc,4,1},
+ {0x1c4,0x1c4,-1,2},
+ {0x1c5,0x1c5,-1,1},
+ {0x1c7,0x1c7,-1,2},
+ {0x1c8,0x1c8,-1,1},
+ {0x1ca,0x1ca,-1,2},
+ {0x1cb,0x1db,2,1},
+ {0x1de,0x1ee,2,1},
+ {0x1f1,0x1f1,-1,2},
+ {0x1f2,0x1f4,2,1},
+ {0x1f6,0x1f6,-1,-97},
+ {0x1f7,0x1f7,-1,-56},
+ {0x1f8,0x21e,2,1},
+ {0x220,0x220,-1,-130},
+ {0x222,0x232,2,1},
+ {0x23a,0x23a,-1,10795},
+ {0x23b,0x23b,-1,1},
+ {0x23d,0x23d,-1,-163},
+ {0x23e,0x23e,-1,10792},
+ {0x241,0x241,-1,1},
+ {0x243,0x243,-1,-195},
+ {0x244,0x244,-1,69},
+ {0x245,0x245,-1,71},
+ {0x246,0x24e,2,1},
+ {0x345,0x345,-1,116},
+ {0x370,0x372,2,1},
+ {0x376,0x376,-1,1},
+ {0x37f,0x37f,-1,116},
+ {0x386,0x386,-1,38},
+ {0x388,0x38a,1,37},
+ {0x38c,0x38c,-1,64},
+ {0x38e,0x38f,1,63},
+ {0x391,0x3a1,1,32},
+ {0x3a3,0x3ab,1,32},
+ {0x3c2,0x3c2,-1,1},
+ {0x3cf,0x3cf,-1,8},
+ {0x3d0,0x3d0,-1,-30},
+ {0x3d1,0x3d1,-1,-25},
+ {0x3d5,0x3d5,-1,-15},
+ {0x3d6,0x3d6,-1,-22},
+ {0x3d8,0x3ee,2,1},
+ {0x3f0,0x3f0,-1,-54},
+ {0x3f1,0x3f1,-1,-48},
+ {0x3f4,0x3f4,-1,-60},
+ {0x3f5,0x3f5,-1,-64},
+ {0x3f7,0x3f7,-1,1},
+ {0x3f9,0x3f9,-1,-7},
+ {0x3fa,0x3fa,-1,1},
+ {0x3fd,0x3ff,1,-130},
+ {0x400,0x40f,1,80},
+ {0x410,0x42f,1,32},
+ {0x460,0x480,2,1},
+ {0x48a,0x4be,2,1},
+ {0x4c0,0x4c0,-1,15},
+ {0x4c1,0x4cd,2,1},
+ {0x4d0,0x52e,2,1},
+ {0x531,0x556,1,48},
+ {0x10a0,0x10c5,1,7264},
+ {0x10c7,0x10cd,6,7264},
+ {0x13f8,0x13fd,1,-8},
+ {0x1c80,0x1c80,-1,-6222},
+ {0x1c81,0x1c81,-1,-6221},
+ {0x1c82,0x1c82,-1,-6212},
+ {0x1c83,0x1c84,1,-6210},
+ {0x1c85,0x1c85,-1,-6211},
+ {0x1c86,0x1c86,-1,-6204},
+ {0x1c87,0x1c87,-1,-6180},
+ {0x1c88,0x1c88,-1,35267},
+ {0x1c90,0x1cba,1,-3008},
+ {0x1cbd,0x1cbf,1,-3008},
+ {0x1e00,0x1e94,2,1},
+ {0x1e9b,0x1e9b,-1,-58},
+ {0x1e9e,0x1e9e,-1,-7615},
+ {0x1ea0,0x1efe,2,1},
+ {0x1f08,0x1f0f,1,-8},
+ {0x1f18,0x1f1d,1,-8},
+ {0x1f28,0x1f2f,1,-8},
+ {0x1f38,0x1f3f,1,-8},
+ {0x1f48,0x1f4d,1,-8},
+ {0x1f59,0x1f5f,2,-8},
+ {0x1f68,0x1f6f,1,-8},
+ {0x1f88,0x1f8f,1,-8},
+ {0x1f98,0x1f9f,1,-8},
+ {0x1fa8,0x1faf,1,-8},
+ {0x1fb8,0x1fb9,1,-8},
+ {0x1fba,0x1fbb,1,-74},
+ {0x1fbc,0x1fbc,-1,-9},
+ {0x1fbe,0x1fbe,-1,-7173},
+ {0x1fc8,0x1fcb,1,-86},
+ {0x1fcc,0x1fcc,-1,-9},
+ {0x1fd8,0x1fd9,1,-8},
+ {0x1fda,0x1fdb,1,-100},
+ {0x1fe8,0x1fe9,1,-8},
+ {0x1fea,0x1feb,1,-112},
+ {0x1fec,0x1fec,-1,-7},
+ {0x1ff8,0x1ff9,1,-128},
+ {0x1ffa,0x1ffb,1,-126},
+ {0x1ffc,0x1ffc,-1,-9},
+ {0x2126,0x2126,-1,-7517},
+ {0x212a,0x212a,-1,-8383},
+ {0x212b,0x212b,-1,-8262},
+ {0x2132,0x2132,-1,28},
+ {0x2160,0x216f,1,16},
+ {0x2183,0x2183,-1,1},
+ {0x24b6,0x24cf,1,26},
+ {0x2c00,0x2c2e,1,48},
+ {0x2c60,0x2c60,-1,1},
+ {0x2c62,0x2c62,-1,-10743},
+ {0x2c63,0x2c63,-1,-3814},
+ {0x2c64,0x2c64,-1,-10727},
+ {0x2c67,0x2c6b,2,1},
+ {0x2c6d,0x2c6d,-1,-10780},
+ {0x2c6e,0x2c6e,-1,-10749},
+ {0x2c6f,0x2c6f,-1,-10783},
+ {0x2c70,0x2c70,-1,-10782},
+ {0x2c72,0x2c75,3,1},
+ {0x2c7e,0x2c7f,1,-10815},
+ {0x2c80,0x2ce2,2,1},
+ {0x2ceb,0x2ced,2,1},
+ {0x2cf2,0xa640,31054,1},
+ {0xa642,0xa66c,2,1},
+ {0xa680,0xa69a,2,1},
+ {0xa722,0xa72e,2,1},
+ {0xa732,0xa76e,2,1},
+ {0xa779,0xa77b,2,1},
+ {0xa77d,0xa77d,-1,-35332},
+ {0xa77e,0xa786,2,1},
+ {0xa78b,0xa78b,-1,1},
+ {0xa78d,0xa78d,-1,-42280},
+ {0xa790,0xa792,2,1},
+ {0xa796,0xa7a8,2,1},
+ {0xa7aa,0xa7aa,-1,-42308},
+ {0xa7ab,0xa7ab,-1,-42319},
+ {0xa7ac,0xa7ac,-1,-42315},
+ {0xa7ad,0xa7ad,-1,-42305},
+ {0xa7ae,0xa7ae,-1,-42308},
+ {0xa7b0,0xa7b0,-1,-42258},
+ {0xa7b1,0xa7b1,-1,-42282},
+ {0xa7b2,0xa7b2,-1,-42261},
+ {0xa7b3,0xa7b3,-1,928},
+ {0xa7b4,0xa7b8,2,1},
+ {0xab70,0xabbf,1,-38864},
+ {0xff21,0xff3a,1,32},
+ {0x10400,0x10427,1,40},
+ {0x104b0,0x104d3,1,40},
+ {0x10c80,0x10cb2,1,64},
+ {0x118a0,0x118bf,1,32},
+ {0x16e40,0x16e5f,1,32},
+ {0x1e900,0x1e921,1,34}
+};
+
+/*
+ * Generic conversion function for case operations.
+ * Return the converted equivalent of "a", which is a UCS-4 character. Use
+ * the given conversion "table". Uses binary search on "table".
+ */
+ static int
+utf_convert(
+ int a,
+ convertStruct table[],
+ int tableSize)
+{
+ int start, mid, end; /* indices into table */
+ int entries = tableSize / sizeof(convertStruct);
+
+ start = 0;
+ end = entries;
+ while (start < end)
+ {
+ /* need to search further */
+ mid = (end + start) / 2;
+ if (table[mid].rangeEnd < a)
+ start = mid + 1;
+ else
+ end = mid;
+ }
+ if (start < entries
+ && table[start].rangeStart <= a
+ && a <= table[start].rangeEnd
+ && (a - table[start].rangeStart) % table[start].step == 0)
+ return (a + table[start].offset);
+ else
+ return a;
+}
+
+/*
+ * Return the folded-case equivalent of "a", which is a UCS-4 character. Uses
+ * simple case folding.
+ */
+ int
+utf_fold(int a)
+{
+ if (a < 0x80)
+ /* be fast for ASCII */
+ return a >= 0x41 && a <= 0x5a ? a + 32 : a;
+ return utf_convert(a, foldCase, (int)sizeof(foldCase));
+}
+
+static convertStruct toLower[] =
+{
+ {0x41,0x5a,1,32},
+ {0xc0,0xd6,1,32},
+ {0xd8,0xde,1,32},
+ {0x100,0x12e,2,1},
+ {0x130,0x130,-1,-199},
+ {0x132,0x136,2,1},
+ {0x139,0x147,2,1},
+ {0x14a,0x176,2,1},
+ {0x178,0x178,-1,-121},
+ {0x179,0x17d,2,1},
+ {0x181,0x181,-1,210},
+ {0x182,0x184,2,1},
+ {0x186,0x186,-1,206},
+ {0x187,0x187,-1,1},
+ {0x189,0x18a,1,205},
+ {0x18b,0x18b,-1,1},
+ {0x18e,0x18e,-1,79},
+ {0x18f,0x18f,-1,202},
+ {0x190,0x190,-1,203},
+ {0x191,0x191,-1,1},
+ {0x193,0x193,-1,205},
+ {0x194,0x194,-1,207},
+ {0x196,0x196,-1,211},
+ {0x197,0x197,-1,209},
+ {0x198,0x198,-1,1},
+ {0x19c,0x19c,-1,211},
+ {0x19d,0x19d,-1,213},
+ {0x19f,0x19f,-1,214},
+ {0x1a0,0x1a4,2,1},
+ {0x1a6,0x1a6,-1,218},
+ {0x1a7,0x1a7,-1,1},
+ {0x1a9,0x1a9,-1,218},
+ {0x1ac,0x1ac,-1,1},
+ {0x1ae,0x1ae,-1,218},
+ {0x1af,0x1af,-1,1},
+ {0x1b1,0x1b2,1,217},
+ {0x1b3,0x1b5,2,1},
+ {0x1b7,0x1b7,-1,219},
+ {0x1b8,0x1bc,4,1},
+ {0x1c4,0x1c4,-1,2},
+ {0x1c5,0x1c5,-1,1},
+ {0x1c7,0x1c7,-1,2},
+ {0x1c8,0x1c8,-1,1},
+ {0x1ca,0x1ca,-1,2},
+ {0x1cb,0x1db,2,1},
+ {0x1de,0x1ee,2,1},
+ {0x1f1,0x1f1,-1,2},
+ {0x1f2,0x1f4,2,1},
+ {0x1f6,0x1f6,-1,-97},
+ {0x1f7,0x1f7,-1,-56},
+ {0x1f8,0x21e,2,1},
+ {0x220,0x220,-1,-130},
+ {0x222,0x232,2,1},
+ {0x23a,0x23a,-1,10795},
+ {0x23b,0x23b,-1,1},
+ {0x23d,0x23d,-1,-163},
+ {0x23e,0x23e,-1,10792},
+ {0x241,0x241,-1,1},
+ {0x243,0x243,-1,-195},
+ {0x244,0x244,-1,69},
+ {0x245,0x245,-1,71},
+ {0x246,0x24e,2,1},
+ {0x370,0x372,2,1},
+ {0x376,0x376,-1,1},
+ {0x37f,0x37f,-1,116},
+ {0x386,0x386,-1,38},
+ {0x388,0x38a,1,37},
+ {0x38c,0x38c,-1,64},
+ {0x38e,0x38f,1,63},
+ {0x391,0x3a1,1,32},
+ {0x3a3,0x3ab,1,32},
+ {0x3cf,0x3cf,-1,8},
+ {0x3d8,0x3ee,2,1},
+ {0x3f4,0x3f4,-1,-60},
+ {0x3f7,0x3f7,-1,1},
+ {0x3f9,0x3f9,-1,-7},
+ {0x3fa,0x3fa,-1,1},
+ {0x3fd,0x3ff,1,-130},
+ {0x400,0x40f,1,80},
+ {0x410,0x42f,1,32},
+ {0x460,0x480,2,1},
+ {0x48a,0x4be,2,1},
+ {0x4c0,0x4c0,-1,15},
+ {0x4c1,0x4cd,2,1},
+ {0x4d0,0x52e,2,1},
+ {0x531,0x556,1,48},
+ {0x10a0,0x10c5,1,7264},
+ {0x10c7,0x10cd,6,7264},
+ {0x13a0,0x13ef,1,38864},
+ {0x13f0,0x13f5,1,8},
+ {0x1c90,0x1cba,1,-3008},
+ {0x1cbd,0x1cbf,1,-3008},
+ {0x1e00,0x1e94,2,1},
+ {0x1e9e,0x1e9e,-1,-7615},
+ {0x1ea0,0x1efe,2,1},
+ {0x1f08,0x1f0f,1,-8},
+ {0x1f18,0x1f1d,1,-8},
+ {0x1f28,0x1f2f,1,-8},
+ {0x1f38,0x1f3f,1,-8},
+ {0x1f48,0x1f4d,1,-8},
+ {0x1f59,0x1f5f,2,-8},
+ {0x1f68,0x1f6f,1,-8},
+ {0x1f88,0x1f8f,1,-8},
+ {0x1f98,0x1f9f,1,-8},
+ {0x1fa8,0x1faf,1,-8},
+ {0x1fb8,0x1fb9,1,-8},
+ {0x1fba,0x1fbb,1,-74},
+ {0x1fbc,0x1fbc,-1,-9},
+ {0x1fc8,0x1fcb,1,-86},
+ {0x1fcc,0x1fcc,-1,-9},
+ {0x1fd8,0x1fd9,1,-8},
+ {0x1fda,0x1fdb,1,-100},
+ {0x1fe8,0x1fe9,1,-8},
+ {0x1fea,0x1feb,1,-112},
+ {0x1fec,0x1fec,-1,-7},
+ {0x1ff8,0x1ff9,1,-128},
+ {0x1ffa,0x1ffb,1,-126},
+ {0x1ffc,0x1ffc,-1,-9},
+ {0x2126,0x2126,-1,-7517},
+ {0x212a,0x212a,-1,-8383},
+ {0x212b,0x212b,-1,-8262},
+ {0x2132,0x2132,-1,28},
+ {0x2160,0x216f,1,16},
+ {0x2183,0x2183,-1,1},
+ {0x24b6,0x24cf,1,26},
+ {0x2c00,0x2c2e,1,48},
+ {0x2c60,0x2c60,-1,1},
+ {0x2c62,0x2c62,-1,-10743},
+ {0x2c63,0x2c63,-1,-3814},
+ {0x2c64,0x2c64,-1,-10727},
+ {0x2c67,0x2c6b,2,1},
+ {0x2c6d,0x2c6d,-1,-10780},
+ {0x2c6e,0x2c6e,-1,-10749},
+ {0x2c6f,0x2c6f,-1,-10783},
+ {0x2c70,0x2c70,-1,-10782},
+ {0x2c72,0x2c75,3,1},
+ {0x2c7e,0x2c7f,1,-10815},
+ {0x2c80,0x2ce2,2,1},
+ {0x2ceb,0x2ced,2,1},
+ {0x2cf2,0xa640,31054,1},
+ {0xa642,0xa66c,2,1},
+ {0xa680,0xa69a,2,1},
+ {0xa722,0xa72e,2,1},
+ {0xa732,0xa76e,2,1},
+ {0xa779,0xa77b,2,1},
+ {0xa77d,0xa77d,-1,-35332},
+ {0xa77e,0xa786,2,1},
+ {0xa78b,0xa78b,-1,1},
+ {0xa78d,0xa78d,-1,-42280},
+ {0xa790,0xa792,2,1},
+ {0xa796,0xa7a8,2,1},
+ {0xa7aa,0xa7aa,-1,-42308},
+ {0xa7ab,0xa7ab,-1,-42319},
+ {0xa7ac,0xa7ac,-1,-42315},
+ {0xa7ad,0xa7ad,-1,-42305},
+ {0xa7ae,0xa7ae,-1,-42308},
+ {0xa7b0,0xa7b0,-1,-42258},
+ {0xa7b1,0xa7b1,-1,-42282},
+ {0xa7b2,0xa7b2,-1,-42261},
+ {0xa7b3,0xa7b3,-1,928},
+ {0xa7b4,0xa7b8,2,1},
+ {0xff21,0xff3a,1,32},
+ {0x10400,0x10427,1,40},
+ {0x104b0,0x104d3,1,40},
+ {0x10c80,0x10cb2,1,64},
+ {0x118a0,0x118bf,1,32},
+ {0x16e40,0x16e5f,1,32},
+ {0x1e900,0x1e921,1,34}
+};
+
+static convertStruct toUpper[] =
+{
+ {0x61,0x7a,1,-32},
+ {0xb5,0xb5,-1,743},
+ {0xe0,0xf6,1,-32},
+ {0xf8,0xfe,1,-32},
+ {0xff,0xff,-1,121},
+ {0x101,0x12f,2,-1},
+ {0x131,0x131,-1,-232},
+ {0x133,0x137,2,-1},
+ {0x13a,0x148,2,-1},
+ {0x14b,0x177,2,-1},
+ {0x17a,0x17e,2,-1},
+ {0x17f,0x17f,-1,-300},
+ {0x180,0x180,-1,195},
+ {0x183,0x185,2,-1},
+ {0x188,0x18c,4,-1},
+ {0x192,0x192,-1,-1},
+ {0x195,0x195,-1,97},
+ {0x199,0x199,-1,-1},
+ {0x19a,0x19a,-1,163},
+ {0x19e,0x19e,-1,130},
+ {0x1a1,0x1a5,2,-1},
+ {0x1a8,0x1ad,5,-1},
+ {0x1b0,0x1b4,4,-1},
+ {0x1b6,0x1b9,3,-1},
+ {0x1bd,0x1bd,-1,-1},
+ {0x1bf,0x1bf,-1,56},
+ {0x1c5,0x1c5,-1,-1},
+ {0x1c6,0x1c6,-1,-2},
+ {0x1c8,0x1c8,-1,-1},
+ {0x1c9,0x1c9,-1,-2},
+ {0x1cb,0x1cb,-1,-1},
+ {0x1cc,0x1cc,-1,-2},
+ {0x1ce,0x1dc,2,-1},
+ {0x1dd,0x1dd,-1,-79},
+ {0x1df,0x1ef,2,-1},
+ {0x1f2,0x1f2,-1,-1},
+ {0x1f3,0x1f3,-1,-2},
+ {0x1f5,0x1f9,4,-1},
+ {0x1fb,0x21f,2,-1},
+ {0x223,0x233,2,-1},
+ {0x23c,0x23c,-1,-1},
+ {0x23f,0x240,1,10815},
+ {0x242,0x247,5,-1},
+ {0x249,0x24f,2,-1},
+ {0x250,0x250,-1,10783},
+ {0x251,0x251,-1,10780},
+ {0x252,0x252,-1,10782},
+ {0x253,0x253,-1,-210},
+ {0x254,0x254,-1,-206},
+ {0x256,0x257,1,-205},
+ {0x259,0x259,-1,-202},
+ {0x25b,0x25b,-1,-203},
+ {0x25c,0x25c,-1,42319},
+ {0x260,0x260,-1,-205},
+ {0x261,0x261,-1,42315},
+ {0x263,0x263,-1,-207},
+ {0x265,0x265,-1,42280},
+ {0x266,0x266,-1,42308},
+ {0x268,0x268,-1,-209},
+ {0x269,0x269,-1,-211},
+ {0x26a,0x26a,-1,42308},
+ {0x26b,0x26b,-1,10743},
+ {0x26c,0x26c,-1,42305},
+ {0x26f,0x26f,-1,-211},
+ {0x271,0x271,-1,10749},
+ {0x272,0x272,-1,-213},
+ {0x275,0x275,-1,-214},
+ {0x27d,0x27d,-1,10727},
+ {0x280,0x283,3,-218},
+ {0x287,0x287,-1,42282},
+ {0x288,0x288,-1,-218},
+ {0x289,0x289,-1,-69},
+ {0x28a,0x28b,1,-217},
+ {0x28c,0x28c,-1,-71},
+ {0x292,0x292,-1,-219},
+ {0x29d,0x29d,-1,42261},
+ {0x29e,0x29e,-1,42258},
+ {0x345,0x345,-1,84},
+ {0x371,0x373,2,-1},
+ {0x377,0x377,-1,-1},
+ {0x37b,0x37d,1,130},
+ {0x3ac,0x3ac,-1,-38},
+ {0x3ad,0x3af,1,-37},
+ {0x3b1,0x3c1,1,-32},
+ {0x3c2,0x3c2,-1,-31},
+ {0x3c3,0x3cb,1,-32},
+ {0x3cc,0x3cc,-1,-64},
+ {0x3cd,0x3ce,1,-63},
+ {0x3d0,0x3d0,-1,-62},
+ {0x3d1,0x3d1,-1,-57},
+ {0x3d5,0x3d5,-1,-47},
+ {0x3d6,0x3d6,-1,-54},
+ {0x3d7,0x3d7,-1,-8},
+ {0x3d9,0x3ef,2,-1},
+ {0x3f0,0x3f0,-1,-86},
+ {0x3f1,0x3f1,-1,-80},
+ {0x3f2,0x3f2,-1,7},
+ {0x3f3,0x3f3,-1,-116},
+ {0x3f5,0x3f5,-1,-96},
+ {0x3f8,0x3fb,3,-1},
+ {0x430,0x44f,1,-32},
+ {0x450,0x45f,1,-80},
+ {0x461,0x481,2,-1},
+ {0x48b,0x4bf,2,-1},
+ {0x4c2,0x4ce,2,-1},
+ {0x4cf,0x4cf,-1,-15},
+ {0x4d1,0x52f,2,-1},
+ {0x561,0x586,1,-48},
+ {0x10d0,0x10fa,1,3008},
+ {0x10fd,0x10ff,1,3008},
+ {0x13f8,0x13fd,1,-8},
+ {0x1c80,0x1c80,-1,-6254},
+ {0x1c81,0x1c81,-1,-6253},
+ {0x1c82,0x1c82,-1,-6244},
+ {0x1c83,0x1c84,1,-6242},
+ {0x1c85,0x1c85,-1,-6243},
+ {0x1c86,0x1c86,-1,-6236},
+ {0x1c87,0x1c87,-1,-6181},
+ {0x1c88,0x1c88,-1,35266},
+ {0x1d79,0x1d79,-1,35332},
+ {0x1d7d,0x1d7d,-1,3814},
+ {0x1e01,0x1e95,2,-1},
+ {0x1e9b,0x1e9b,-1,-59},
+ {0x1ea1,0x1eff,2,-1},
+ {0x1f00,0x1f07,1,8},
+ {0x1f10,0x1f15,1,8},
+ {0x1f20,0x1f27,1,8},
+ {0x1f30,0x1f37,1,8},
+ {0x1f40,0x1f45,1,8},
+ {0x1f51,0x1f57,2,8},
+ {0x1f60,0x1f67,1,8},
+ {0x1f70,0x1f71,1,74},
+ {0x1f72,0x1f75,1,86},
+ {0x1f76,0x1f77,1,100},
+ {0x1f78,0x1f79,1,128},
+ {0x1f7a,0x1f7b,1,112},
+ {0x1f7c,0x1f7d,1,126},
+ {0x1f80,0x1f87,1,8},
+ {0x1f90,0x1f97,1,8},
+ {0x1fa0,0x1fa7,1,8},
+ {0x1fb0,0x1fb1,1,8},
+ {0x1fb3,0x1fb3,-1,9},
+ {0x1fbe,0x1fbe,-1,-7205},
+ {0x1fc3,0x1fc3,-1,9},
+ {0x1fd0,0x1fd1,1,8},
+ {0x1fe0,0x1fe1,1,8},
+ {0x1fe5,0x1fe5,-1,7},
+ {0x1ff3,0x1ff3,-1,9},
+ {0x214e,0x214e,-1,-28},
+ {0x2170,0x217f,1,-16},
+ {0x2184,0x2184,-1,-1},
+ {0x24d0,0x24e9,1,-26},
+ {0x2c30,0x2c5e,1,-48},
+ {0x2c61,0x2c61,-1,-1},
+ {0x2c65,0x2c65,-1,-10795},
+ {0x2c66,0x2c66,-1,-10792},
+ {0x2c68,0x2c6c,2,-1},
+ {0x2c73,0x2c76,3,-1},
+ {0x2c81,0x2ce3,2,-1},
+ {0x2cec,0x2cee,2,-1},
+ {0x2cf3,0x2cf3,-1,-1},
+ {0x2d00,0x2d25,1,-7264},
+ {0x2d27,0x2d2d,6,-7264},
+ {0xa641,0xa66d,2,-1},
+ {0xa681,0xa69b,2,-1},
+ {0xa723,0xa72f,2,-1},
+ {0xa733,0xa76f,2,-1},
+ {0xa77a,0xa77c,2,-1},
+ {0xa77f,0xa787,2,-1},
+ {0xa78c,0xa791,5,-1},
+ {0xa793,0xa797,4,-1},
+ {0xa799,0xa7a9,2,-1},
+ {0xa7b5,0xa7b9,2,-1},
+ {0xab53,0xab53,-1,-928},
+ {0xab70,0xabbf,1,-38864},
+ {0xff41,0xff5a,1,-32},
+ {0x10428,0x1044f,1,-40},
+ {0x104d8,0x104fb,1,-40},
+ {0x10cc0,0x10cf2,1,-64},
+ {0x118c0,0x118df,1,-32},
+ {0x16e60,0x16e7f,1,-32},
+ {0x1e922,0x1e943,1,-34}
+};
+
+/*
+ * Return the upper-case equivalent of "a", which is a UCS-4 character. Use
+ * simple case folding.
+ */
+ int
+utf_toupper(int a)
+{
+ /* If 'casemap' contains "keepascii" use ASCII style toupper(). */
+ if (a < 128 && (cmp_flags & CMP_KEEPASCII))
+ return TOUPPER_ASC(a);
+
+#if defined(HAVE_TOWUPPER) && defined(__STDC_ISO_10646__)
+ /* If towupper() is available and handles Unicode, use it. */
+ if (!(cmp_flags & CMP_INTERNAL))
+ return towupper(a);
+#endif
+
+ /* For characters below 128 use locale sensitive toupper(). */
+ if (a < 128)
+ return TOUPPER_LOC(a);
+
+ /* For any other characters use the above mapping table. */
+ return utf_convert(a, toUpper, (int)sizeof(toUpper));
+}
+
+ int
+utf_islower(int a)
+{
+ /* German sharp s is lower case but has no upper case equivalent. */
+ return (utf_toupper(a) != a) || a == 0xdf;
+}
+
+/*
+ * Return the lower-case equivalent of "a", which is a UCS-4 character. Use
+ * simple case folding.
+ */
+ int
+utf_tolower(int a)
+{
+ /* If 'casemap' contains "keepascii" use ASCII style tolower(). */
+ if (a < 128 && (cmp_flags & CMP_KEEPASCII))
+ return TOLOWER_ASC(a);
+
+#if defined(HAVE_TOWLOWER) && defined(__STDC_ISO_10646__)
+ /* If towlower() is available and handles Unicode, use it. */
+ if (!(cmp_flags & CMP_INTERNAL))
+ return towlower(a);
+#endif
+
+ /* For characters below 128 use locale sensitive tolower(). */
+ if (a < 128)
+ return TOLOWER_LOC(a);
+
+ /* For any other characters use the above mapping table. */
+ return utf_convert(a, toLower, (int)sizeof(toLower));
+}
+
+ int
+utf_isupper(int a)
+{
+ return (utf_tolower(a) != a);
+}
+
+ static int
+utf_strnicmp(
+ char_u *s1,
+ char_u *s2,
+ size_t n1,
+ size_t n2)
+{
+ int c1, c2, cdiff;
+ char_u buffer[6];
+
+ for (;;)
+ {
+ c1 = utf_safe_read_char_adv(&s1, &n1);
+ c2 = utf_safe_read_char_adv(&s2, &n2);
+
+ if (c1 <= 0 || c2 <= 0)
+ break;
+
+ if (c1 == c2)
+ continue;
+
+ cdiff = utf_fold(c1) - utf_fold(c2);
+ if (cdiff != 0)
+ return cdiff;
+ }
+
+ /* some string ended or has an incomplete/illegal character sequence */
+
+ if (c1 == 0 || c2 == 0)
+ {
+ /* some string ended. shorter string is smaller */
+ if (c1 == 0 && c2 == 0)
+ return 0;
+ return c1 == 0 ? -1 : 1;
+ }
+
+ /* Continue with bytewise comparison to produce some result that
+ * would make comparison operations involving this function transitive.
+ *
+ * If only one string had an error, comparison should be made with
+ * folded version of the other string. In this case it is enough
+ * to fold just one character to determine the result of comparison. */
+
+ if (c1 != -1 && c2 == -1)
+ {
+ n1 = utf_char2bytes(utf_fold(c1), buffer);
+ s1 = buffer;
+ }
+ else if (c2 != -1 && c1 == -1)
+ {
+ n2 = utf_char2bytes(utf_fold(c2), buffer);
+ s2 = buffer;
+ }
+
+ while (n1 > 0 && n2 > 0 && *s1 != NUL && *s2 != NUL)
+ {
+ cdiff = (int)(*s1) - (int)(*s2);
+ if (cdiff != 0)
+ return cdiff;
+
+ s1++;
+ s2++;
+ n1--;
+ n2--;
+ }
+
+ if (n1 > 0 && *s1 == NUL)
+ n1 = 0;
+ if (n2 > 0 && *s2 == NUL)
+ n2 = 0;
+
+ if (n1 == 0 && n2 == 0)
+ return 0;
+ return n1 == 0 ? -1 : 1;
+}
+
+/*
+ * Version of strnicmp() that handles multi-byte characters.
+ * Needed for Big5, Shift-JIS and UTF-8 encoding. Other DBCS encodings can
+ * probably use strnicmp(), because there are no ASCII characters in the
+ * second byte.
+ * Returns zero if s1 and s2 are equal (ignoring case), the difference between
+ * two characters otherwise.
+ */
+ int
+mb_strnicmp(char_u *s1, char_u *s2, size_t nn)
+{
+ int i, l;
+ int cdiff;
+ int n = (int)nn;
+
+ if (enc_utf8)
+ {
+ return utf_strnicmp(s1, s2, nn, nn);
+ }
+ else
+ {
+ for (i = 0; i < n; i += l)
+ {
+ if (s1[i] == NUL && s2[i] == NUL) /* both strings end */
+ return 0;
+
+ l = (*mb_ptr2len)(s1 + i);
+ if (l <= 1)
+ {
+ /* Single byte: first check normally, then with ignore case. */
+ if (s1[i] != s2[i])
+ {
+ cdiff = MB_TOLOWER(s1[i]) - MB_TOLOWER(s2[i]);
+ if (cdiff != 0)
+ return cdiff;
+ }
+ }
+ else
+ {
+ /* For non-Unicode multi-byte don't ignore case. */
+ if (l > n - i)
+ l = n - i;
+ cdiff = STRNCMP(s1 + i, s2 + i, l);
+ if (cdiff != 0)
+ return cdiff;
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ * "g8": show bytes of the UTF-8 char under the cursor. Doesn't matter what
+ * 'encoding' has been set to.
+ */
+ void
+show_utf8(void)
+{
+ int len;
+ int rlen = 0;
+ char_u *line;
+ int clen;
+ int i;
+
+ /* Get the byte length of the char under the cursor, including composing
+ * characters. */
+ line = ml_get_cursor();
+ len = utfc_ptr2len(line);
+ if (len == 0)
+ {
+ msg("NUL");
+ return;
+ }
+
+ clen = 0;
+ for (i = 0; i < len; ++i)
+ {
+ if (clen == 0)
+ {
+ /* start of (composing) character, get its length */
+ if (i > 0)
+ {
+ STRCPY(IObuff + rlen, "+ ");
+ rlen += 2;
+ }
+ clen = utf_ptr2len(line + i);
+ }
+ sprintf((char *)IObuff + rlen, "%02x ",
+ (line[i] == NL) ? NUL : line[i]); /* NUL is stored as NL */
+ --clen;
+ rlen += (int)STRLEN(IObuff + rlen);
+ if (rlen > IOSIZE - 20)
+ break;
+ }
+
+ msg((char *)IObuff);
+}
+
+/*
+ * mb_head_off() function pointer.
+ * Return offset from "p" to the first byte of the character it points into.
+ * If "p" points to the NUL at the end of the string return 0.
+ * Returns 0 when already at the first byte of a character.
+ */
+ int
+latin_head_off(char_u *base UNUSED, char_u *p UNUSED)
+{
+ return 0;
+}
+
+ int
+dbcs_head_off(char_u *base, char_u *p)
+{
+ char_u *q;
+
+ /* It can't be a trailing byte when not using DBCS, at the start of the
+ * string or the previous byte can't start a double-byte. */
+ if (p <= base || MB_BYTE2LEN(p[-1]) == 1 || *p == NUL)
+ return 0;
+
+ /* This is slow: need to start at the base and go forward until the
+ * byte we are looking for. Return 1 when we went past it, 0 otherwise. */
+ q = base;
+ while (q < p)
+ q += dbcs_ptr2len(q);
+ return (q == p) ? 0 : 1;
+}
+
+/*
+ * Special version of dbcs_head_off() that works for ScreenLines[], where
+ * single-width DBCS_JPNU characters are stored separately.
+ */
+ int
+dbcs_screen_head_off(char_u *base, char_u *p)
+{
+ char_u *q;
+
+ /* It can't be a trailing byte when not using DBCS, at the start of the
+ * string or the previous byte can't start a double-byte.
+ * For euc-jp an 0x8e byte in the previous cell always means we have a
+ * lead byte in the current cell. */
+ if (p <= base
+ || (enc_dbcs == DBCS_JPNU && p[-1] == 0x8e)
+ || MB_BYTE2LEN(p[-1]) == 1
+ || *p == NUL)
+ return 0;
+
+ /* This is slow: need to start at the base and go forward until the
+ * byte we are looking for. Return 1 when we went past it, 0 otherwise.
+ * For DBCS_JPNU look out for 0x8e, which means the second byte is not
+ * stored as the next byte. */
+ q = base;
+ while (q < p)
+ {
+ if (enc_dbcs == DBCS_JPNU && *q == 0x8e)
+ ++q;
+ else
+ q += dbcs_ptr2len(q);
+ }
+ return (q == p) ? 0 : 1;
+}
+
+ int
+utf_head_off(char_u *base, char_u *p)
+{
+ char_u *q;
+ char_u *s;
+ int c;
+ int len;
+#ifdef FEAT_ARABIC
+ char_u *j;
+#endif
+
+ if (*p < 0x80) /* be quick for ASCII */
+ return 0;
+
+ /* Skip backwards over trailing bytes: 10xx.xxxx
+ * Skip backwards again if on a composing char. */
+ for (q = p; ; --q)
+ {
+ /* Move s to the last byte of this char. */
+ for (s = q; (s[1] & 0xc0) == 0x80; ++s)
+ ;
+ /* Move q to the first byte of this char. */
+ while (q > base && (*q & 0xc0) == 0x80)
+ --q;
+ /* Check for illegal sequence. Do allow an illegal byte after where we
+ * started. */
+ len = utf8len_tab[*q];
+ if (len != (int)(s - q + 1) && len != (int)(p - q + 1))
+ return 0;
+
+ if (q <= base)
+ break;
+
+ c = utf_ptr2char(q);
+ if (utf_iscomposing(c))
+ continue;
+
+#ifdef FEAT_ARABIC
+ if (arabic_maycombine(c))
+ {
+ /* Advance to get a sneak-peak at the next char */
+ j = q;
+ --j;
+ /* Move j to the first byte of this char. */
+ while (j > base && (*j & 0xc0) == 0x80)
+ --j;
+ if (arabic_combine(utf_ptr2char(j), c))
+ continue;
+ }
+#endif
+ break;
+ }
+
+ return (int)(p - q);
+}
+
+/*
+ * Copy a character from "*fp" to "*tp" and advance the pointers.
+ */
+ void
+mb_copy_char(char_u **fp, char_u **tp)
+{
+ int l = (*mb_ptr2len)(*fp);
+
+ mch_memmove(*tp, *fp, (size_t)l);
+ *tp += l;
+ *fp += l;
+}
+
+/*
+ * Return the offset from "p" to the first byte of a character. When "p" is
+ * at the start of a character 0 is returned, otherwise the offset to the next
+ * character. Can start anywhere in a stream of bytes.
+ */
+ int
+mb_off_next(char_u *base, char_u *p)
+{
+ int i;
+ int j;
+
+ if (enc_utf8)
+ {
+ if (*p < 0x80) /* be quick for ASCII */
+ return 0;
+
+ /* Find the next character that isn't 10xx.xxxx */
+ for (i = 0; (p[i] & 0xc0) == 0x80; ++i)
+ ;
+ if (i > 0)
+ {
+ /* Check for illegal sequence. */
+ for (j = 0; p - j > base; ++j)
+ if ((p[-j] & 0xc0) != 0x80)
+ break;
+ if (utf8len_tab[p[-j]] != i + j)
+ return 0;
+ }
+ return i;
+ }
+
+ /* Only need to check if we're on a trail byte, it doesn't matter if we
+ * want the offset to the next or current character. */
+ return (*mb_head_off)(base, p);
+}
+
+/*
+ * Return the offset from "p" to the last byte of the character it points
+ * into. Can start anywhere in a stream of bytes.
+ */
+ int
+mb_tail_off(char_u *base, char_u *p)
+{
+ int i;
+ int j;
+
+ if (*p == NUL)
+ return 0;
+
+ if (enc_utf8)
+ {
+ /* Find the last character that is 10xx.xxxx */
+ for (i = 0; (p[i + 1] & 0xc0) == 0x80; ++i)
+ ;
+ /* Check for illegal sequence. */
+ for (j = 0; p - j > base; ++j)
+ if ((p[-j] & 0xc0) != 0x80)
+ break;
+ if (utf8len_tab[p[-j]] != i + j + 1)
+ return 0;
+ return i;
+ }
+
+ /* It can't be the first byte if a double-byte when not using DBCS, at the
+ * end of the string or the byte can't start a double-byte. */
+ if (enc_dbcs == 0 || p[1] == NUL || MB_BYTE2LEN(*p) == 1)
+ return 0;
+
+ /* Return 1 when on the lead byte, 0 when on the tail byte. */
+ return 1 - dbcs_head_off(base, p);
+}
+
+/*
+ * Find the next illegal byte sequence.
+ */
+ void
+utf_find_illegal(void)
+{
+ pos_T pos = curwin->w_cursor;
+ char_u *p;
+ int len;
+ vimconv_T vimconv;
+ char_u *tofree = NULL;
+
+ vimconv.vc_type = CONV_NONE;
+ if (enc_utf8 && (enc_canon_props(curbuf->b_p_fenc) & ENC_8BIT))
+ {
+ /* 'encoding' is "utf-8" but we are editing a 8-bit encoded file,
+ * possibly a utf-8 file with illegal bytes. Setup for conversion
+ * from utf-8 to 'fileencoding'. */
+ convert_setup(&vimconv, p_enc, curbuf->b_p_fenc);
+ }
+
+ curwin->w_cursor.coladd = 0;
+ for (;;)
+ {
+ p = ml_get_cursor();
+ if (vimconv.vc_type != CONV_NONE)
+ {
+ vim_free(tofree);
+ tofree = string_convert(&vimconv, p, NULL);
+ if (tofree == NULL)
+ break;
+ p = tofree;
+ }
+
+ while (*p != NUL)
+ {
+ /* Illegal means that there are not enough trail bytes (checked by
+ * utf_ptr2len()) or too many of them (overlong sequence). */
+ len = utf_ptr2len(p);
+ if (*p >= 0x80 && (len == 1
+ || utf_char2len(utf_ptr2char(p)) != len))
+ {
+ if (vimconv.vc_type == CONV_NONE)
+ curwin->w_cursor.col += (colnr_T)(p - ml_get_cursor());
+ else
+ {
+ int l;
+
+ len = (int)(p - tofree);
+ for (p = ml_get_cursor(); *p != NUL && len-- > 0; p += l)
+ {
+ l = utf_ptr2len(p);
+ curwin->w_cursor.col += l;
+ }
+ }
+ goto theend;
+ }
+ p += len;
+ }
+ if (curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count)
+ break;
+ ++curwin->w_cursor.lnum;
+ curwin->w_cursor.col = 0;
+ }
+
+ /* didn't find it: don't move and beep */
+ curwin->w_cursor = pos;
+ beep_flush();
+
+theend:
+ vim_free(tofree);
+ convert_setup(&vimconv, NULL, NULL);
+}
+
+#if defined(FEAT_GUI_GTK) || defined(PROTO)
+/*
+ * Return TRUE if string "s" is a valid utf-8 string.
+ * When "end" is NULL stop at the first NUL.
+ * When "end" is positive stop there.
+ */
+ int
+utf_valid_string(char_u *s, char_u *end)
+{
+ int l;
+ char_u *p = s;
+
+ while (end == NULL ? *p != NUL : p < end)
+ {
+ l = utf8len_tab_zero[*p];
+ if (l == 0)
+ return FALSE; /* invalid lead byte */
+ if (end != NULL && p + l > end)
+ return FALSE; /* incomplete byte sequence */
+ ++p;
+ while (--l > 0)
+ if ((*p++ & 0xc0) != 0x80)
+ return FALSE; /* invalid trail byte */
+ }
+ return TRUE;
+}
+#endif
+
+#if defined(FEAT_GUI) || defined(PROTO)
+/*
+ * Special version of mb_tail_off() for use in ScreenLines[].
+ */
+ int
+dbcs_screen_tail_off(char_u *base, char_u *p)
+{
+ /* It can't be the first byte if a double-byte when not using DBCS, at the
+ * end of the string or the byte can't start a double-byte.
+ * For euc-jp an 0x8e byte always means we have a lead byte in the current
+ * cell. */
+ if (*p == NUL || p[1] == NUL
+ || (enc_dbcs == DBCS_JPNU && *p == 0x8e)
+ || MB_BYTE2LEN(*p) == 1)
+ return 0;
+
+ /* Return 1 when on the lead byte, 0 when on the tail byte. */
+ return 1 - dbcs_screen_head_off(base, p);
+}
+#endif
+
+/*
+ * If the cursor moves on an trail byte, set the cursor on the lead byte.
+ * Thus it moves left if necessary.
+ * Return TRUE when the cursor was adjusted.
+ */
+ void
+mb_adjust_cursor(void)
+{
+ mb_adjustpos(curbuf, &curwin->w_cursor);
+}
+
+/*
+ * Adjust position "*lp" to point to the first byte of a multi-byte character.
+ * If it points to a tail byte it's moved backwards to the head byte.
+ */
+ void
+mb_adjustpos(buf_T *buf, pos_T *lp)
+{
+ char_u *p;
+
+ if (lp->col > 0 || lp->coladd > 1)
+ {
+ p = ml_get_buf(buf, lp->lnum, FALSE);
+ if (*p == NUL || (int)STRLEN(p) < lp->col)
+ lp->col = 0;
+ else
+ lp->col -= (*mb_head_off)(p, p + lp->col);
+ /* Reset "coladd" when the cursor would be on the right half of a
+ * double-wide character. */
+ if (lp->coladd == 1
+ && p[lp->col] != TAB
+ && vim_isprintc((*mb_ptr2char)(p + lp->col))
+ && ptr2cells(p + lp->col) > 1)
+ lp->coladd = 0;
+ }
+}
+
+/*
+ * Return a pointer to the character before "*p", if there is one.
+ */
+ char_u *
+mb_prevptr(
+ char_u *line, /* start of the string */
+ char_u *p)
+{
+ if (p > line)
+ MB_PTR_BACK(line, p);
+ return p;
+}
+
+/*
+ * Return the character length of "str". Each multi-byte character (with
+ * following composing characters) counts as one.
+ */
+ int
+mb_charlen(char_u *str)
+{
+ char_u *p = str;
+ int count;
+
+ if (p == NULL)
+ return 0;
+
+ for (count = 0; *p != NUL; count++)
+ p += (*mb_ptr2len)(p);
+
+ return count;
+}
+
+#if defined(FEAT_SPELL) || defined(PROTO)
+/*
+ * Like mb_charlen() but for a string with specified length.
+ */
+ int
+mb_charlen_len(char_u *str, int len)
+{
+ char_u *p = str;
+ int count;
+
+ for (count = 0; *p != NUL && p < str + len; count++)
+ p += (*mb_ptr2len)(p);
+
+ return count;
+}
+#endif
+
+/*
+ * Try to un-escape a multi-byte character.
+ * Used for the "to" and "from" part of a mapping.
+ * Return the un-escaped string if it is a multi-byte character, and advance
+ * "pp" to just after the bytes that formed it.
+ * Return NULL if no multi-byte char was found.
+ */
+ char_u *
+mb_unescape(char_u **pp)
+{
+ static char_u buf[6];
+ int n;
+ int m = 0;
+ char_u *str = *pp;
+
+ /* Must translate K_SPECIAL KS_SPECIAL KE_FILLER to K_SPECIAL and CSI
+ * KS_EXTRA KE_CSI to CSI.
+ * Maximum length of a utf-8 character is 4 bytes. */
+ for (n = 0; str[n] != NUL && m < 4; ++n)
+ {
+ if (str[n] == K_SPECIAL
+ && str[n + 1] == KS_SPECIAL
+ && str[n + 2] == KE_FILLER)
+ {
+ buf[m++] = K_SPECIAL;
+ n += 2;
+ }
+ else if ((str[n] == K_SPECIAL
+# ifdef FEAT_GUI
+ || str[n] == CSI
+# endif
+ )
+ && str[n + 1] == KS_EXTRA
+ && str[n + 2] == (int)KE_CSI)
+ {
+ buf[m++] = CSI;
+ n += 2;
+ }
+ else if (str[n] == K_SPECIAL
+# ifdef FEAT_GUI
+ || str[n] == CSI
+# endif
+ )
+ break; /* a special key can't be a multibyte char */
+ else
+ buf[m++] = str[n];
+ buf[m] = NUL;
+
+ /* Return a multi-byte character if it's found. An illegal sequence
+ * will result in a 1 here. */
+ if ((*mb_ptr2len)(buf) > 1)
+ {
+ *pp = str + n + 1;
+ return buf;
+ }
+
+ /* Bail out quickly for ASCII. */
+ if (buf[0] < 128)
+ break;
+ }
+ return NULL;
+}
+
+/*
+ * Return TRUE if the character at "row"/"col" on the screen is the left side
+ * of a double-width character.
+ * Caller must make sure "row" and "col" are not invalid!
+ */
+ int
+mb_lefthalve(int row, int col)
+{
+#ifdef FEAT_HANGULIN
+ if (composing_hangul)
+ return TRUE;
+#endif
+ return (*mb_off2cells)(LineOffset[row] + col,
+ LineOffset[row] + screen_Columns) > 1;
+}
+
+/*
+ * Correct a position on the screen, if it's the right half of a double-wide
+ * char move it to the left half. Returns the corrected column.
+ */
+ int
+mb_fix_col(int col, int row)
+{
+ col = check_col(col);
+ row = check_row(row);
+ if (has_mbyte && ScreenLines != NULL && col > 0
+ && ((enc_dbcs
+ && ScreenLines[LineOffset[row] + col] != NUL
+ && dbcs_screen_head_off(ScreenLines + LineOffset[row],
+ ScreenLines + LineOffset[row] + col))
+ || (enc_utf8 && ScreenLines[LineOffset[row] + col] == 0)))
+ return col - 1;
+ return col;
+}
+
+static int enc_alias_search(char_u *name);
+
+/*
+ * Skip the Vim specific head of a 'encoding' name.
+ */
+ char_u *
+enc_skip(char_u *p)
+{
+ if (STRNCMP(p, "2byte-", 6) == 0)
+ return p + 6;
+ if (STRNCMP(p, "8bit-", 5) == 0)
+ return p + 5;
+ return p;
+}
+
+/*
+ * Find the canonical name for encoding "enc".
+ * When the name isn't recognized, returns "enc" itself, but with all lower
+ * case characters and '_' replaced with '-'.
+ * Returns an allocated string. NULL for out-of-memory.
+ */
+ char_u *
+enc_canonize(char_u *enc)
+{
+ char_u *r;
+ char_u *p, *s;
+ int i;
+
+ if (STRCMP(enc, "default") == 0)
+ {
+ /* Use the default encoding as it's found by set_init_1(). */
+ r = get_encoding_default();
+ if (r == NULL)
+ r = (char_u *)"latin1";
+ return vim_strsave(r);
+ }
+
+ /* copy "enc" to allocated memory, with room for two '-' */
+ r = alloc((unsigned)(STRLEN(enc) + 3));
+ if (r != NULL)
+ {
+ /* Make it all lower case and replace '_' with '-'. */
+ p = r;
+ for (s = enc; *s != NUL; ++s)
+ {
+ if (*s == '_')
+ *p++ = '-';
+ else
+ *p++ = TOLOWER_ASC(*s);
+ }
+ *p = NUL;
+
+ /* Skip "2byte-" and "8bit-". */
+ p = enc_skip(r);
+
+ /* Change "microsoft-cp" to "cp". Used in some spell files. */
+ if (STRNCMP(p, "microsoft-cp", 12) == 0)
+ STRMOVE(p, p + 10);
+
+ /* "iso8859" -> "iso-8859" */
+ if (STRNCMP(p, "iso8859", 7) == 0)
+ {
+ STRMOVE(p + 4, p + 3);
+ p[3] = '-';
+ }
+
+ /* "iso-8859n" -> "iso-8859-n" */
+ if (STRNCMP(p, "iso-8859", 8) == 0 && p[8] != '-')
+ {
+ STRMOVE(p + 9, p + 8);
+ p[8] = '-';
+ }
+
+ /* "latin-N" -> "latinN" */
+ if (STRNCMP(p, "latin-", 6) == 0)
+ STRMOVE(p + 5, p + 6);
+
+ if (enc_canon_search(p) >= 0)
+ {
+ /* canonical name can be used unmodified */
+ if (p != r)
+ STRMOVE(r, p);
+ }
+ else if ((i = enc_alias_search(p)) >= 0)
+ {
+ /* alias recognized, get canonical name */
+ vim_free(r);
+ r = vim_strsave((char_u *)enc_canon_table[i].name);
+ }
+ }
+ return r;
+}
+
+/*
+ * Search for an encoding alias of "name".
+ * Returns -1 when not found.
+ */
+ static int
+enc_alias_search(char_u *name)
+{
+ int i;
+
+ for (i = 0; enc_alias_table[i].name != NULL; ++i)
+ if (STRCMP(name, enc_alias_table[i].name) == 0)
+ return enc_alias_table[i].canon;
+ return -1;
+}
+
+
+#ifdef HAVE_LANGINFO_H
+# include <langinfo.h>
+#endif
+
+#ifndef FEAT_GUI_W32
+/*
+ * Get the canonicalized encoding from the specified locale string "locale"
+ * or from the environment variables LC_ALL, LC_CTYPE and LANG.
+ * Returns an allocated string when successful, NULL when not.
+ */
+ char_u *
+enc_locale_env(char *locale)
+{
+ char *s = locale;
+ char *p;
+ int i;
+ char buf[50];
+
+ if (s == NULL || *s == NUL)
+ if ((s = getenv("LC_ALL")) == NULL || *s == NUL)
+ if ((s = getenv("LC_CTYPE")) == NULL || *s == NUL)
+ s = getenv("LANG");
+
+ if (s == NULL || *s == NUL)
+ return NULL;
+
+ /* The most generic locale format is:
+ * language[_territory][.codeset][@modifier][+special][,[sponsor][_revision]]
+ * If there is a '.' remove the part before it.
+ * if there is something after the codeset, remove it.
+ * Make the name lowercase and replace '_' with '-'.
+ * Exception: "ja_JP.EUC" == "euc-jp", "zh_CN.EUC" = "euc-cn",
+ * "ko_KR.EUC" == "euc-kr"
+ */
+ if ((p = (char *)vim_strchr((char_u *)s, '.')) != NULL)
+ {
+ if (p > s + 2 && STRNICMP(p + 1, "EUC", 3) == 0
+ && !isalnum((int)p[4]) && p[4] != '-' && p[-3] == '_')
+ {
+ /* copy "XY.EUC" to "euc-XY" to buf[10] */
+ STRCPY(buf + 10, "euc-");
+ buf[14] = p[-2];
+ buf[15] = p[-1];
+ buf[16] = 0;
+ s = buf + 10;
+ }
+ else
+ s = p + 1;
+ }
+ for (i = 0; i < (int)sizeof(buf) - 1 && s[i] != NUL; ++i)
+ {
+ if (s[i] == '_' || s[i] == '-')
+ buf[i] = '-';
+ else if (isalnum((int)s[i]))
+ buf[i] = TOLOWER_ASC(s[i]);
+ else
+ break;
+ }
+ buf[i] = NUL;
+
+ return enc_canonize((char_u *)buf);
+}
+#endif
+
+/*
+ * Get the canonicalized encoding of the current locale.
+ * Returns an allocated string when successful, NULL when not.
+ */
+ char_u *
+enc_locale(void)
+{
+#ifdef WIN3264
+ char buf[50];
+ long acp = GetACP();
+
+ if (acp == 1200)
+ STRCPY(buf, "ucs-2le");
+ else if (acp == 1252) /* cp1252 is used as latin1 */
+ STRCPY(buf, "latin1");
+ else
+ sprintf(buf, "cp%ld", acp);
+
+ return enc_canonize((char_u *)buf);
+#else
+ char *s;
+
+# ifdef HAVE_NL_LANGINFO_CODESET
+ if ((s = nl_langinfo(CODESET)) == NULL || *s == NUL)
+# endif
+# if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
+ if ((s = setlocale(LC_CTYPE, NULL)) == NULL || *s == NUL)
+# endif
+ s = NULL;
+
+ return enc_locale_env(s);
+#endif
+}
+
+# if defined(WIN3264) || defined(PROTO) || defined(FEAT_CYGWIN_WIN32_CLIPBOARD)
+/*
+ * Convert an encoding name to an MS-Windows codepage.
+ * Returns zero if no codepage can be figured out.
+ */
+ int
+encname2codepage(char_u *name)
+{
+ int cp;
+ char_u *p = name;
+ int idx;
+
+ if (STRNCMP(p, "8bit-", 5) == 0)
+ p += 5;
+ else if (STRNCMP(p_enc, "2byte-", 6) == 0)
+ p += 6;
+
+ if (p[0] == 'c' && p[1] == 'p')
+ cp = atoi((char *)p + 2);
+ else if ((idx = enc_canon_search(p)) >= 0)
+ cp = enc_canon_table[idx].codepage;
+ else
+ return 0;
+ if (IsValidCodePage(cp))
+ return cp;
+ return 0;
+}
+# endif
+
+# if defined(USE_ICONV) || defined(PROTO)
+
+/*
+ * Call iconv_open() with a check if iconv() works properly (there are broken
+ * versions).
+ * Returns (void *)-1 if failed.
+ * (should return iconv_t, but that causes problems with prototypes).
+ */
+ void *
+my_iconv_open(char_u *to, char_u *from)
+{
+ iconv_t fd;
+#define ICONV_TESTLEN 400
+ char_u tobuf[ICONV_TESTLEN];
+ char *p;
+ size_t tolen;
+ static int iconv_ok = -1;
+
+ if (iconv_ok == FALSE)
+ return (void *)-1; /* detected a broken iconv() previously */
+
+#ifdef DYNAMIC_ICONV
+ /* Check if the iconv.dll can be found. */
+ if (!iconv_enabled(TRUE))
+ return (void *)-1;
+#endif
+
+ fd = iconv_open((char *)enc_skip(to), (char *)enc_skip(from));
+
+ if (fd != (iconv_t)-1 && iconv_ok == -1)
+ {
+ /*
+ * Do a dummy iconv() call to check if it actually works. There is a
+ * version of iconv() on Linux that is broken. We can't ignore it,
+ * because it's wide-spread. The symptoms are that after outputting
+ * the initial shift state the "to" pointer is NULL and conversion
+ * stops for no apparent reason after about 8160 characters.
+ */
+ p = (char *)tobuf;
+ tolen = ICONV_TESTLEN;
+ (void)iconv(fd, NULL, NULL, &p, &tolen);
+ if (p == NULL)
+ {
+ iconv_ok = FALSE;
+ iconv_close(fd);
+ fd = (iconv_t)-1;
+ }
+ else
+ iconv_ok = TRUE;
+ }
+
+ return (void *)fd;
+}
+
+/*
+ * Convert the string "str[slen]" with iconv().
+ * If "unconvlenp" is not NULL handle the string ending in an incomplete
+ * sequence and set "*unconvlenp" to the length of it.
+ * Returns the converted string in allocated memory. NULL for an error.
+ * If resultlenp is not NULL, sets it to the result length in bytes.
+ */
+ static char_u *
+iconv_string(
+ vimconv_T *vcp,
+ char_u *str,
+ int slen,
+ int *unconvlenp,
+ int *resultlenp)
+{
+ const char *from;
+ size_t fromlen;
+ char *to;
+ size_t tolen;
+ size_t len = 0;
+ size_t done = 0;
+ char_u *result = NULL;
+ char_u *p;
+ int l;
+
+ from = (char *)str;
+ fromlen = slen;
+ for (;;)
+ {
+ if (len == 0 || ICONV_ERRNO == ICONV_E2BIG)
+ {
+ /* Allocate enough room for most conversions. When re-allocating
+ * increase the buffer size. */
+ len = len + fromlen * 2 + 40;
+ p = alloc((unsigned)len);
+ if (p != NULL && done > 0)
+ mch_memmove(p, result, done);
+ vim_free(result);
+ result = p;
+ if (result == NULL) /* out of memory */
+ break;
+ }
+
+ to = (char *)result + done;
+ tolen = len - done - 2;
+ /* Avoid a warning for systems with a wrong iconv() prototype by
+ * casting the second argument to void *. */
+ if (iconv(vcp->vc_fd, (void *)&from, &fromlen, &to, &tolen)
+ != (size_t)-1)
+ {
+ /* Finished, append a NUL. */
+ *to = NUL;
+ break;
+ }
+
+ /* Check both ICONV_EINVAL and EINVAL, because the dynamically loaded
+ * iconv library may use one of them. */
+ if (!vcp->vc_fail && unconvlenp != NULL
+ && (ICONV_ERRNO == ICONV_EINVAL || ICONV_ERRNO == EINVAL))
+ {
+ /* Handle an incomplete sequence at the end. */
+ *to = NUL;
+ *unconvlenp = (int)fromlen;
+ break;
+ }
+
+ /* Check both ICONV_EILSEQ and EILSEQ, because the dynamically loaded
+ * iconv library may use one of them. */
+ else if (!vcp->vc_fail
+ && (ICONV_ERRNO == ICONV_EILSEQ || ICONV_ERRNO == EILSEQ
+ || ICONV_ERRNO == ICONV_EINVAL || ICONV_ERRNO == EINVAL))
+ {
+ /* Can't convert: insert a '?' and skip a character. This assumes
+ * conversion from 'encoding' to something else. In other
+ * situations we don't know what to skip anyway. */
+ *to++ = '?';
+ if ((*mb_ptr2cells)((char_u *)from) > 1)
+ *to++ = '?';
+ if (enc_utf8)
+ l = utfc_ptr2len_len((char_u *)from, (int)fromlen);
+ else
+ {
+ l = (*mb_ptr2len)((char_u *)from);
+ if (l > (int)fromlen)
+ l = (int)fromlen;
+ }
+ from += l;
+ fromlen -= l;
+ }
+ else if (ICONV_ERRNO != ICONV_E2BIG)
+ {
+ /* conversion failed */
+ VIM_CLEAR(result);
+ break;
+ }
+ /* Not enough room or skipping illegal sequence. */
+ done = to - (char *)result;
+ }
+
+ if (resultlenp != NULL && result != NULL)
+ *resultlenp = (int)(to - (char *)result);
+ return result;
+}
+
+# if defined(DYNAMIC_ICONV) || defined(PROTO)
+/*
+ * Dynamically load the "iconv.dll" on Win32.
+ */
+
+# ifndef DYNAMIC_ICONV /* must be generating prototypes */
+# define HINSTANCE int
+# endif
+static HINSTANCE hIconvDLL = 0;
+static HINSTANCE hMsvcrtDLL = 0;
+
+# ifndef DYNAMIC_ICONV_DLL
+# define DYNAMIC_ICONV_DLL "iconv.dll"
+# define DYNAMIC_ICONV_DLL_ALT1 "libiconv.dll"
+# define DYNAMIC_ICONV_DLL_ALT2 "libiconv2.dll"
+# define DYNAMIC_ICONV_DLL_ALT3 "libiconv-2.dll"
+# endif
+# ifndef DYNAMIC_MSVCRT_DLL
+# define DYNAMIC_MSVCRT_DLL "msvcrt.dll"
+# endif
+
+/*
+ * Try opening the iconv.dll and return TRUE if iconv() can be used.
+ */
+ int
+iconv_enabled(int verbose)
+{
+ if (hIconvDLL != 0 && hMsvcrtDLL != 0)
+ return TRUE;
+
+ /* The iconv DLL file goes under different names, try them all.
+ * Do the "2" version first, it's newer. */
+#ifdef DYNAMIC_ICONV_DLL_ALT2
+ if (hIconvDLL == 0)
+ hIconvDLL = vimLoadLib(DYNAMIC_ICONV_DLL_ALT2);
+#endif
+#ifdef DYNAMIC_ICONV_DLL_ALT3
+ if (hIconvDLL == 0)
+ hIconvDLL = vimLoadLib(DYNAMIC_ICONV_DLL_ALT3);
+#endif
+ if (hIconvDLL == 0)
+ hIconvDLL = vimLoadLib(DYNAMIC_ICONV_DLL);
+#ifdef DYNAMIC_ICONV_DLL_ALT1
+ if (hIconvDLL == 0)
+ hIconvDLL = vimLoadLib(DYNAMIC_ICONV_DLL_ALT1);
+#endif
+
+ if (hIconvDLL != 0)
+ hMsvcrtDLL = vimLoadLib(DYNAMIC_MSVCRT_DLL);
+ if (hIconvDLL == 0 || hMsvcrtDLL == 0)
+ {
+ /* Only give the message when 'verbose' is set, otherwise it might be
+ * done whenever a conversion is attempted. */
+ if (verbose && p_verbose > 0)
+ {
+ verbose_enter();
+ semsg(_(e_loadlib),
+ hIconvDLL == 0 ? DYNAMIC_ICONV_DLL : DYNAMIC_MSVCRT_DLL);
+ verbose_leave();
+ }
+ iconv_end();
+ return FALSE;
+ }
+
+ iconv = (void *)GetProcAddress(hIconvDLL, "libiconv");
+ iconv_open = (void *)GetProcAddress(hIconvDLL, "libiconv_open");
+ iconv_close = (void *)GetProcAddress(hIconvDLL, "libiconv_close");
+ iconvctl = (void *)GetProcAddress(hIconvDLL, "libiconvctl");
+ iconv_errno = get_dll_import_func(hIconvDLL, "_errno");
+ if (iconv_errno == NULL)
+ iconv_errno = (void *)GetProcAddress(hMsvcrtDLL, "_errno");
+ if (iconv == NULL || iconv_open == NULL || iconv_close == NULL
+ || iconvctl == NULL || iconv_errno == NULL)
+ {
+ iconv_end();
+ if (verbose && p_verbose > 0)
+ {
+ verbose_enter();
+ semsg(_(e_loadfunc), "for libiconv");
+ verbose_leave();
+ }
+ return FALSE;
+ }
+ return TRUE;
+}
+
+ void
+iconv_end(void)
+{
+ /* Don't use iconv() when inputting or outputting characters. */
+ if (input_conv.vc_type == CONV_ICONV)
+ convert_setup(&input_conv, NULL, NULL);
+ if (output_conv.vc_type == CONV_ICONV)
+ convert_setup(&output_conv, NULL, NULL);
+
+ if (hIconvDLL != 0)
+ FreeLibrary(hIconvDLL);
+ if (hMsvcrtDLL != 0)
+ FreeLibrary(hMsvcrtDLL);
+ hIconvDLL = 0;
+ hMsvcrtDLL = 0;
+}
+# endif /* DYNAMIC_ICONV */
+# endif /* USE_ICONV */
+
+
+#ifdef FEAT_GUI
+# define USE_IMACTIVATEFUNC (!gui.in_use && *p_imaf != NUL)
+# define USE_IMSTATUSFUNC (!gui.in_use && *p_imsf != NUL)
+#else
+# define USE_IMACTIVATEFUNC (*p_imaf != NUL)
+# define USE_IMSTATUSFUNC (*p_imsf != NUL)
+#endif
+
+#if defined(FEAT_EVAL) && (defined(FEAT_XIM) || defined(IME_WITHOUT_XIM))
+ static void
+call_imactivatefunc(int active)
+{
+ typval_T argv[2];
+
+ argv[0].v_type = VAR_NUMBER;
+ argv[0].vval.v_number = active ? 1 : 0;
+ argv[1].v_type = VAR_UNKNOWN;
+ (void)call_func_retnr(p_imaf, 1, argv);
+}
+
+ static int
+call_imstatusfunc(void)
+{
+ int is_active;
+
+ /* FIXME: Don't execute user function in unsafe situation. */
+ if (exiting || is_autocmd_blocked())
+ return FALSE;
+ /* FIXME: :py print 'xxx' is shown duplicate result.
+ * Use silent to avoid it. */
+ ++msg_silent;
+ is_active = call_func_retnr(p_imsf, 0, NULL);
+ --msg_silent;
+ return (is_active > 0);
+}
+#endif
+
+#if defined(FEAT_XIM) || defined(PROTO)
+
+# if defined(FEAT_GUI_GTK) || defined(PROTO)
+static int xim_has_preediting INIT(= FALSE); /* IM current status */
+
+/*
+ * Set preedit_start_col to the current cursor position.
+ */
+ static void
+init_preedit_start_col(void)
+{
+ if (State & CMDLINE)
+ preedit_start_col = cmdline_getvcol_cursor();
+ else if (curwin != NULL && curwin->w_buffer != NULL)
+ getvcol(curwin, &curwin->w_cursor, &preedit_start_col, NULL, NULL);
+ /* Prevent that preediting marks the buffer as changed. */
+ xim_changed_while_preediting = curbuf->b_changed;
+}
+
+static int im_is_active = FALSE; /* IM is enabled for current mode */
+static int preedit_is_active = FALSE;
+static int im_preedit_cursor = 0; /* cursor offset in characters */
+static int im_preedit_trailing = 0; /* number of characters after cursor */
+
+static unsigned long im_commit_handler_id = 0;
+static unsigned int im_activatekey_keyval = GDK_VoidSymbol;
+static unsigned int im_activatekey_state = 0;
+
+static GtkWidget *preedit_window = NULL;
+static GtkWidget *preedit_label = NULL;
+
+static void im_preedit_window_set_position(void);
+
+ void
+im_set_active(int active)
+{
+ int was_active;
+
+ was_active = !!im_get_status();
+ im_is_active = (active && !p_imdisable);
+
+ if (im_is_active != was_active)
+ xim_reset();
+}
+
+ void
+xim_set_focus(int focus)
+{
+ if (xic != NULL)
+ {
+ if (focus)
+ gtk_im_context_focus_in(xic);
+ else
+ gtk_im_context_focus_out(xic);
+ }
+}
+
+ void
+im_set_position(int row, int col)
+{
+ if (xic != NULL)
+ {
+ GdkRectangle area;
+
+ area.x = FILL_X(col);
+ area.y = FILL_Y(row);
+ area.width = gui.char_width * (mb_lefthalve(row, col) ? 2 : 1);
+ area.height = gui.char_height;
+
+ gtk_im_context_set_cursor_location(xic, &area);
+
+ if (p_imst == IM_OVER_THE_SPOT)
+ im_preedit_window_set_position();
+ }
+}
+
+# if 0 || defined(PROTO) /* apparently only used in gui_x11.c */
+ void
+xim_set_preedit(void)
+{
+ im_set_position(gui.row, gui.col);
+}
+# endif
+
+ static void
+im_add_to_input(char_u *str, int len)
+{
+ /* Convert from 'termencoding' (always "utf-8") to 'encoding' */
+ if (input_conv.vc_type != CONV_NONE)
+ {
+ str = string_convert(&input_conv, str, &len);
+ g_return_if_fail(str != NULL);
+ }
+
+ add_to_input_buf_csi(str, len);
+
+ if (input_conv.vc_type != CONV_NONE)
+ vim_free(str);
+
+ if (p_mh) /* blank out the pointer if necessary */
+ gui_mch_mousehide(TRUE);
+}
+
+ static void
+im_preedit_window_set_position(void)
+{
+ int x, y, width, height;
+ int screen_x, screen_y, screen_width, screen_height;
+
+ if (preedit_window == NULL)
+ return;
+
+ gui_gtk_get_screen_geom_of_win(gui.drawarea,
+ &screen_x, &screen_y, &screen_width, &screen_height);
+ gdk_window_get_origin(gtk_widget_get_window(gui.drawarea), &x, &y);
+ gtk_window_get_size(GTK_WINDOW(preedit_window), &width, &height);
+ x = x + FILL_X(gui.col);
+ y = y + FILL_Y(gui.row);
+ if (x + width > screen_x + screen_width)
+ x = screen_x + screen_width - width;
+ if (y + height > screen_y + screen_height)
+ y = screen_y + screen_height - height;
+ gtk_window_move(GTK_WINDOW(preedit_window), x, y);
+}
+
+ static void
+im_preedit_window_open()
+{
+ char *preedit_string;
+#if !GTK_CHECK_VERSION(3,16,0)
+ char buf[8];
+#endif
+ PangoAttrList *attr_list;
+ PangoLayout *layout;
+#if GTK_CHECK_VERSION(3,0,0)
+# if !GTK_CHECK_VERSION(3,16,0)
+ GdkRGBA color;
+# endif
+#else
+ GdkColor color;
+#endif
+ gint w, h;
+
+ if (preedit_window == NULL)
+ {
+ preedit_window = gtk_window_new(GTK_WINDOW_POPUP);
+ gtk_window_set_transient_for(GTK_WINDOW(preedit_window),
+ GTK_WINDOW(gui.mainwin));
+ preedit_label = gtk_label_new("");
+ gtk_widget_set_name(preedit_label, "vim-gui-preedit-area");
+ gtk_container_add(GTK_CONTAINER(preedit_window), preedit_label);
+ }
+
+#if GTK_CHECK_VERSION(3,16,0)
+ {
+ GtkStyleContext * const context
+ = gtk_widget_get_style_context(gui.drawarea);
+ GtkCssProvider * const provider = gtk_css_provider_new();
+ gchar *css = NULL;
+ const char * const fontname
+ = pango_font_description_get_family(gui.norm_font);
+ gint fontsize
+ = pango_font_description_get_size(gui.norm_font) / PANGO_SCALE;
+ gchar *fontsize_propval = NULL;
+
+ if (!pango_font_description_get_size_is_absolute(gui.norm_font))
+ {
+ /* fontsize was given in points. Convert it into that in pixels
+ * to use with CSS. */
+ GdkScreen * const screen
+ = gdk_window_get_screen(gtk_widget_get_window(gui.mainwin));
+ const gdouble dpi = gdk_screen_get_resolution(screen);
+ fontsize = dpi * fontsize / 72;
+ }
+ if (fontsize > 0)
+ fontsize_propval = g_strdup_printf("%dpx", fontsize);
+ else
+ fontsize_propval = g_strdup_printf("inherit");
+
+ css = g_strdup_printf(
+ "widget#vim-gui-preedit-area {\n"
+ " font-family: %s,monospace;\n"
+ " font-size: %s;\n"
+ " color: #%.2lx%.2lx%.2lx;\n"
+ " background-color: #%.2lx%.2lx%.2lx;\n"
+ "}\n",
+ fontname != NULL ? fontname : "inherit",
+ fontsize_propval,
+ (gui.norm_pixel >> 16) & 0xff,
+ (gui.norm_pixel >> 8) & 0xff,
+ gui.norm_pixel & 0xff,
+ (gui.back_pixel >> 16) & 0xff,
+ (gui.back_pixel >> 8) & 0xff,
+ gui.back_pixel & 0xff);
+
+ gtk_css_provider_load_from_data(provider, css, -1, NULL);
+ gtk_style_context_add_provider(context,
+ GTK_STYLE_PROVIDER(provider), G_MAXUINT);
+
+ g_free(css);
+ g_free(fontsize_propval);
+ g_object_unref(provider);
+ }
+#elif GTK_CHECK_VERSION(3,0,0)
+ gtk_widget_override_font(preedit_label, gui.norm_font);
+
+ vim_snprintf(buf, sizeof(buf), "#%06X", gui.norm_pixel);
+ gdk_rgba_parse(&color, buf);
+ gtk_widget_override_color(preedit_label, GTK_STATE_FLAG_NORMAL, &color);
+
+ vim_snprintf(buf, sizeof(buf), "#%06X", gui.back_pixel);
+ gdk_rgba_parse(&color, buf);
+ gtk_widget_override_background_color(preedit_label, GTK_STATE_FLAG_NORMAL,
+ &color);
+#else
+ gtk_widget_modify_font(preedit_label, gui.norm_font);
+
+ vim_snprintf(buf, sizeof(buf), "#%06X", (unsigned)gui.norm_pixel);
+ gdk_color_parse(buf, &color);
+ gtk_widget_modify_fg(preedit_label, GTK_STATE_NORMAL, &color);
+
+ vim_snprintf(buf, sizeof(buf), "#%06X", (unsigned)gui.back_pixel);
+ gdk_color_parse(buf, &color);
+ gtk_widget_modify_bg(preedit_window, GTK_STATE_NORMAL, &color);
+#endif
+
+ gtk_im_context_get_preedit_string(xic, &preedit_string, &attr_list, NULL);
+
+ if (preedit_string[0] != NUL)
+ {
+ gtk_label_set_text(GTK_LABEL(preedit_label), preedit_string);
+ gtk_label_set_attributes(GTK_LABEL(preedit_label), attr_list);
+
+ layout = gtk_label_get_layout(GTK_LABEL(preedit_label));
+ pango_layout_get_pixel_size(layout, &w, &h);
+ h = MAX(h, gui.char_height);
+ gtk_window_resize(GTK_WINDOW(preedit_window), w, h);
+
+ gtk_widget_show_all(preedit_window);
+
+ im_preedit_window_set_position();
+ }
+
+ g_free(preedit_string);
+ pango_attr_list_unref(attr_list);
+}
+
+ static void
+im_preedit_window_close()
+{
+ if (preedit_window != NULL)
+ gtk_widget_hide(preedit_window);
+}
+
+ static void
+im_show_preedit()
+{
+ im_preedit_window_open();
+
+ if (p_mh) /* blank out the pointer if necessary */
+ gui_mch_mousehide(TRUE);
+}
+
+ static void
+im_delete_preedit(void)
+{
+ char_u bskey[] = {CSI, 'k', 'b'};
+ char_u delkey[] = {CSI, 'k', 'D'};
+
+ if (p_imst == IM_OVER_THE_SPOT)
+ {
+ im_preedit_window_close();
+ return;
+ }
+
+ if (State & NORMAL
+#ifdef FEAT_TERMINAL
+ && !term_use_loop()
+#endif
+ )
+ {
+ im_preedit_cursor = 0;
+ return;
+ }
+ for (; im_preedit_cursor > 0; --im_preedit_cursor)
+ add_to_input_buf(bskey, (int)sizeof(bskey));
+
+ for (; im_preedit_trailing > 0; --im_preedit_trailing)
+ add_to_input_buf(delkey, (int)sizeof(delkey));
+}
+
+/*
+ * Move the cursor left by "num_move_back" characters.
+ * Note that ins_left() checks im_is_preediting() to avoid breaking undo for
+ * these K_LEFT keys.
+ */
+ static void
+im_correct_cursor(int num_move_back)
+{
+ char_u backkey[] = {CSI, 'k', 'l'};
+
+ if (State & NORMAL)
+ return;
+# ifdef FEAT_RIGHTLEFT
+ if ((State & CMDLINE) == 0 && curwin != NULL && curwin->w_p_rl)
+ backkey[2] = 'r';
+# endif
+ for (; num_move_back > 0; --num_move_back)
+ add_to_input_buf(backkey, (int)sizeof(backkey));
+}
+
+static int xim_expected_char = NUL;
+static int xim_ignored_char = FALSE;
+
+/*
+ * Update the mode and cursor while in an IM callback.
+ */
+ static void
+im_show_info(void)
+{
+ int old_vgetc_busy;
+
+ old_vgetc_busy = vgetc_busy;
+ vgetc_busy = TRUE;
+ showmode();
+ vgetc_busy = old_vgetc_busy;
+ if ((State & NORMAL) || (State & INSERT))
+ setcursor();
+ out_flush();
+}
+
+/*
+ * Callback invoked when the user finished preediting.
+ * Put the final string into the input buffer.
+ */
+ static void
+im_commit_cb(GtkIMContext *context UNUSED,
+ const gchar *str,
+ gpointer data UNUSED)
+{
+ int slen = (int)STRLEN(str);
+ int add_to_input = TRUE;
+ int clen;
+ int len = slen;
+ int commit_with_preedit = TRUE;
+ char_u *im_str;
+
+#ifdef XIM_DEBUG
+ xim_log("im_commit_cb(): %s\n", str);
+#endif
+
+ if (p_imst == IM_ON_THE_SPOT)
+ {
+ /* The imhangul module doesn't reset the preedit string before
+ * committing. Call im_delete_preedit() to work around that. */
+ im_delete_preedit();
+
+ /* Indicate that preediting has finished. */
+ if (preedit_start_col == MAXCOL)
+ {
+ init_preedit_start_col();
+ commit_with_preedit = FALSE;
+ }
+
+ /* The thing which setting "preedit_start_col" to MAXCOL means that
+ * "preedit_start_col" will be set forcedly when calling
+ * preedit_changed_cb() next time.
+ * "preedit_start_col" should not reset with MAXCOL on this part. Vim
+ * is simulating the preediting by using add_to_input_str(). when
+ * preedit begin immediately before committed, the typebuf is not
+ * flushed to screen, then it can't get correct "preedit_start_col".
+ * Thus, it should calculate the cells by adding cells of the committed
+ * string. */
+ if (input_conv.vc_type != CONV_NONE)
+ {
+ im_str = string_convert(&input_conv, (char_u *)str, &len);
+ g_return_if_fail(im_str != NULL);
+ }
+ else
+ im_str = (char_u *)str;
+
+ clen = mb_string2cells(im_str, len);
+
+ if (input_conv.vc_type != CONV_NONE)
+ vim_free(im_str);
+ preedit_start_col += clen;
+ }
+
+ /* Is this a single character that matches a keypad key that's just
+ * been pressed? If so, we don't want it to be entered as such - let
+ * us carry on processing the raw keycode so that it may be used in
+ * mappings as <kSomething>. */
+ if (xim_expected_char != NUL)
+ {
+ /* We're currently processing a keypad or other special key */
+ if (slen == 1 && str[0] == xim_expected_char)
+ {
+ /* It's a match - don't do it here */
+ xim_ignored_char = TRUE;
+ add_to_input = FALSE;
+ }
+ else
+ {
+ /* Not a match */
+ xim_ignored_char = FALSE;
+ }
+ }
+
+ if (add_to_input)
+ im_add_to_input((char_u *)str, slen);
+
+ if (p_imst == IM_ON_THE_SPOT)
+ {
+ /* Inserting chars while "im_is_active" is set does not cause a
+ * change of buffer. When the chars are committed the buffer must be
+ * marked as changed. */
+ if (!commit_with_preedit)
+ preedit_start_col = MAXCOL;
+
+ /* This flag is used in changed() at next call. */
+ xim_changed_while_preediting = TRUE;
+ }
+
+ if (gtk_main_level() > 0)
+ gtk_main_quit();
+}
+
+/*
+ * Callback invoked after start to the preedit.
+ */
+ static void
+im_preedit_start_cb(GtkIMContext *context UNUSED, gpointer data UNUSED)
+{
+#ifdef XIM_DEBUG
+ xim_log("im_preedit_start_cb()\n");
+#endif
+
+ im_is_active = TRUE;
+ preedit_is_active = TRUE;
+ gui_update_cursor(TRUE, FALSE);
+ im_show_info();
+}
+
+/*
+ * Callback invoked after end to the preedit.
+ */
+ static void
+im_preedit_end_cb(GtkIMContext *context UNUSED, gpointer data UNUSED)
+{
+#ifdef XIM_DEBUG
+ xim_log("im_preedit_end_cb()\n");
+#endif
+ im_delete_preedit();
+
+ /* Indicate that preediting has finished */
+ if (p_imst == IM_ON_THE_SPOT)
+ preedit_start_col = MAXCOL;
+ xim_has_preediting = FALSE;
+
+#if 0
+ /* Removal of this line suggested by Takuhiro Nishioka. Fixes that IM was
+ * switched off unintentionally. We now use preedit_is_active (added by
+ * SungHyun Nam). */
+ im_is_active = FALSE;
+#endif
+ preedit_is_active = FALSE;
+ gui_update_cursor(TRUE, FALSE);
+ im_show_info();
+}
+
+/*
+ * Callback invoked after changes to the preedit string. If the preedit
+ * string was empty before, remember the preedit start column so we know
+ * where to apply feedback attributes. Delete the previous preedit string
+ * if there was one, save the new preedit cursor offset, and put the new
+ * string into the input buffer.
+ *
+ * TODO: The pragmatic "put into input buffer" approach used here has
+ * several fundamental problems:
+ *
+ * - The characters in the preedit string are subject to remapping.
+ * That's broken, only the finally committed string should be remapped.
+ *
+ * - There is a race condition involved: The retrieved value for the
+ * current cursor position will be wrong if any unprocessed characters
+ * are still queued in the input buffer.
+ *
+ * - Due to the lack of synchronization between the file buffer in memory
+ * and any typed characters, it's practically impossible to implement the
+ * "retrieve_surrounding" and "delete_surrounding" signals reliably. IM
+ * modules for languages such as Thai are likely to rely on this feature
+ * for proper operation.
+ *
+ * Conclusions: I think support for preediting needs to be moved to the
+ * core parts of Vim. Ideally, until it has been committed, the preediting
+ * string should only be displayed and not affect the buffer content at all.
+ * The question how to deal with the synchronization issue still remains.
+ * Circumventing the input buffer is probably not desirable. Anyway, I think
+ * implementing "retrieve_surrounding" is the only hard problem.
+ *
+ * One way to solve all of this in a clean manner would be to queue all key
+ * press/release events "as is" in the input buffer, and apply the IM filtering
+ * at the receiving end of the queue. This, however, would have a rather large
+ * impact on the code base. If there is an easy way to force processing of all
+ * remaining input from within the "retrieve_surrounding" signal handler, this
+ * might not be necessary. Gotta ask on vim-dev for opinions.
+ */
+ static void
+im_preedit_changed_cb(GtkIMContext *context, gpointer data UNUSED)
+{
+ char *preedit_string = NULL;
+ int cursor_index = 0;
+ int num_move_back = 0;
+ char_u *str;
+ char_u *p;
+ int i;
+
+ if (p_imst == IM_ON_THE_SPOT)
+ gtk_im_context_get_preedit_string(context,
+ &preedit_string, NULL,
+ &cursor_index);
+ else
+ gtk_im_context_get_preedit_string(context,
+ &preedit_string, NULL,
+ NULL);
+
+#ifdef XIM_DEBUG
+ xim_log("im_preedit_changed_cb(): %s\n", preedit_string);
+#endif
+
+ g_return_if_fail(preedit_string != NULL); /* just in case */
+
+ if (p_imst == IM_OVER_THE_SPOT)
+ {
+ if (preedit_string[0] == NUL)
+ {
+ xim_has_preediting = FALSE;
+ im_delete_preedit();
+ }
+ else
+ {
+ xim_has_preediting = TRUE;
+ im_show_preedit();
+ }
+ }
+ else
+ {
+ /* If preedit_start_col is MAXCOL set it to the current cursor position. */
+ if (preedit_start_col == MAXCOL && preedit_string[0] != '\0')
+ {
+ xim_has_preediting = TRUE;
+
+ /* Urgh, this breaks if the input buffer isn't empty now */
+ init_preedit_start_col();
+ }
+ else if (cursor_index == 0 && preedit_string[0] == '\0')
+ {
+ xim_has_preediting = FALSE;
+
+ /* If at the start position (after typing backspace)
+ * preedit_start_col must be reset. */
+ preedit_start_col = MAXCOL;
+ }
+
+ im_delete_preedit();
+
+ /*
+ * Compute the end of the preediting area: "preedit_end_col".
+ * According to the documentation of gtk_im_context_get_preedit_string(),
+ * the cursor_pos output argument returns the offset in bytes. This is
+ * unfortunately not true -- real life shows the offset is in characters,
+ * and the GTK+ source code agrees with me. Will file a bug later.
+ */
+ if (preedit_start_col != MAXCOL)
+ preedit_end_col = preedit_start_col;
+ str = (char_u *)preedit_string;
+ for (p = str, i = 0; *p != NUL; p += utf_byte2len(*p), ++i)
+ {
+ int is_composing;
+
+ is_composing = ((*p & 0x80) != 0 && utf_iscomposing(utf_ptr2char(p)));
+ /*
+ * These offsets are used as counters when generating <BS> and <Del>
+ * to delete the preedit string. So don't count composing characters
+ * unless 'delcombine' is enabled.
+ */
+ if (!is_composing || p_deco)
+ {
+ if (i < cursor_index)
+ ++im_preedit_cursor;
+ else
+ ++im_preedit_trailing;
+ }
+ if (!is_composing && i >= cursor_index)
+ {
+ /* This is essentially the same as im_preedit_trailing, except
+ * composing characters are not counted even if p_deco is set. */
+ ++num_move_back;
+ }
+ if (preedit_start_col != MAXCOL)
+ preedit_end_col += utf_ptr2cells(p);
+ }
+
+ if (p > str)
+ {
+ im_add_to_input(str, (int)(p - str));
+ im_correct_cursor(num_move_back);
+ }
+ }
+
+ g_free(preedit_string);
+
+ if (gtk_main_level() > 0)
+ gtk_main_quit();
+}
+
+/*
+ * Translate the Pango attributes at iter to Vim highlighting attributes.
+ * Ignore attributes not supported by Vim highlighting. This shouldn't have
+ * too much impact -- right now we handle even more attributes than necessary
+ * for the IM modules I tested with.
+ */
+ static int
+translate_pango_attributes(PangoAttrIterator *iter)
+{
+ PangoAttribute *attr;
+ int char_attr = HL_NORMAL;
+
+ attr = pango_attr_iterator_get(iter, PANGO_ATTR_UNDERLINE);
+ if (attr != NULL && ((PangoAttrInt *)attr)->value
+ != (int)PANGO_UNDERLINE_NONE)
+ char_attr |= HL_UNDERLINE;
+
+ attr = pango_attr_iterator_get(iter, PANGO_ATTR_WEIGHT);
+ if (attr != NULL && ((PangoAttrInt *)attr)->value >= (int)PANGO_WEIGHT_BOLD)
+ char_attr |= HL_BOLD;
+
+ attr = pango_attr_iterator_get(iter, PANGO_ATTR_STYLE);
+ if (attr != NULL && ((PangoAttrInt *)attr)->value
+ != (int)PANGO_STYLE_NORMAL)
+ char_attr |= HL_ITALIC;
+
+ attr = pango_attr_iterator_get(iter, PANGO_ATTR_BACKGROUND);
+ if (attr != NULL)
+ {
+ const PangoColor *color = &((PangoAttrColor *)attr)->color;
+
+ /* Assume inverse if black background is requested */
+ if ((color->red | color->green | color->blue) == 0)
+ char_attr |= HL_INVERSE;
+ }
+
+ return char_attr;
+}
+
+/*
+ * Retrieve the highlighting attributes at column col in the preedit string.
+ * Return -1 if not in preediting mode or if col is out of range.
+ */
+ int
+im_get_feedback_attr(int col)
+{
+ char *preedit_string = NULL;
+ PangoAttrList *attr_list = NULL;
+ int char_attr = -1;
+
+ if (xic == NULL)
+ return char_attr;
+
+ gtk_im_context_get_preedit_string(xic, &preedit_string, &attr_list, NULL);
+
+ if (preedit_string != NULL && attr_list != NULL)
+ {
+ int idx;
+
+ /* Get the byte index as used by PangoAttrIterator */
+ for (idx = 0; col > 0 && preedit_string[idx] != '\0'; --col)
+ idx += utfc_ptr2len((char_u *)preedit_string + idx);
+
+ if (preedit_string[idx] != '\0')
+ {
+ PangoAttrIterator *iter;
+ int start, end;
+
+ char_attr = HL_NORMAL;
+ iter = pango_attr_list_get_iterator(attr_list);
+
+ /* Extract all relevant attributes from the list. */
+ do
+ {
+ pango_attr_iterator_range(iter, &start, &end);
+
+ if (idx >= start && idx < end)
+ char_attr |= translate_pango_attributes(iter);
+ }
+ while (pango_attr_iterator_next(iter));
+
+ pango_attr_iterator_destroy(iter);
+ }
+ }
+
+ if (attr_list != NULL)
+ pango_attr_list_unref(attr_list);
+ g_free(preedit_string);
+
+ return char_attr;
+}
+
+ void
+xim_init(void)
+{
+#ifdef XIM_DEBUG
+ xim_log("xim_init()\n");
+#endif
+
+ g_return_if_fail(gui.drawarea != NULL);
+ g_return_if_fail(gtk_widget_get_window(gui.drawarea) != NULL);
+
+ xic = gtk_im_multicontext_new();
+ g_object_ref(xic);
+
+ im_commit_handler_id = g_signal_connect(G_OBJECT(xic), "commit",
+ G_CALLBACK(&im_commit_cb), NULL);
+ g_signal_connect(G_OBJECT(xic), "preedit_changed",
+ G_CALLBACK(&im_preedit_changed_cb), NULL);
+ g_signal_connect(G_OBJECT(xic), "preedit_start",
+ G_CALLBACK(&im_preedit_start_cb), NULL);
+ g_signal_connect(G_OBJECT(xic), "preedit_end",
+ G_CALLBACK(&im_preedit_end_cb), NULL);
+
+ gtk_im_context_set_client_window(xic, gtk_widget_get_window(gui.drawarea));
+}
+
+ void
+im_shutdown(void)
+{
+#ifdef XIM_DEBUG
+ xim_log("im_shutdown()\n");
+#endif
+
+ if (xic != NULL)
+ {
+ gtk_im_context_focus_out(xic);
+ g_object_unref(xic);
+ xic = NULL;
+ }
+ im_is_active = FALSE;
+ im_commit_handler_id = 0;
+ if (p_imst == IM_ON_THE_SPOT)
+ preedit_start_col = MAXCOL;
+ xim_has_preediting = FALSE;
+}
+
+/*
+ * Convert the string argument to keyval and state for GdkEventKey.
+ * If str is valid return TRUE, otherwise FALSE.
+ *
+ * See 'imactivatekey' for documentation of the format.
+ */
+ static int
+im_string_to_keyval(const char *str, unsigned int *keyval, unsigned int *state)
+{
+ const char *mods_end;
+ unsigned tmp_keyval;
+ unsigned tmp_state = 0;
+
+ mods_end = strrchr(str, '-');
+ mods_end = (mods_end != NULL) ? mods_end + 1 : str;
+
+ /* Parse modifier keys */
+ while (str < mods_end)
+ switch (*str++)
+ {
+ case '-': break;
+ case 'S': case 's': tmp_state |= (unsigned)GDK_SHIFT_MASK; break;
+ case 'L': case 'l': tmp_state |= (unsigned)GDK_LOCK_MASK; break;
+ case 'C': case 'c': tmp_state |= (unsigned)GDK_CONTROL_MASK;break;
+ case '1': tmp_state |= (unsigned)GDK_MOD1_MASK; break;
+ case '2': tmp_state |= (unsigned)GDK_MOD2_MASK; break;
+ case '3': tmp_state |= (unsigned)GDK_MOD3_MASK; break;
+ case '4': tmp_state |= (unsigned)GDK_MOD4_MASK; break;
+ case '5': tmp_state |= (unsigned)GDK_MOD5_MASK; break;
+ default:
+ return FALSE;
+ }
+
+ tmp_keyval = gdk_keyval_from_name(str);
+
+ if (tmp_keyval == 0 || tmp_keyval == GDK_VoidSymbol)
+ return FALSE;
+
+ if (keyval != NULL)
+ *keyval = tmp_keyval;
+ if (state != NULL)
+ *state = tmp_state;
+
+ return TRUE;
+}
+
+/*
+ * Return TRUE if p_imak is valid, otherwise FALSE. As a special case, an
+ * empty string is also regarded as valid.
+ *
+ * Note: The numerical key value of p_imak is cached if it was valid; thus
+ * boldly assuming im_xim_isvalid_imactivate() will always be called whenever
+ * 'imak' changes. This is currently the case but not obvious -- should
+ * probably rename the function for clarity.
+ */
+ int
+im_xim_isvalid_imactivate(void)
+{
+ if (p_imak[0] == NUL)
+ {
+ im_activatekey_keyval = GDK_VoidSymbol;
+ im_activatekey_state = 0;
+ return TRUE;
+ }
+
+ return im_string_to_keyval((const char *)p_imak,
+ &im_activatekey_keyval,
+ &im_activatekey_state);
+}
+
+ static void
+im_synthesize_keypress(unsigned int keyval, unsigned int state)
+{
+ GdkEventKey *event;
+
+ event = (GdkEventKey *)gdk_event_new(GDK_KEY_PRESS);
+ g_object_ref(gtk_widget_get_window(gui.drawarea));
+ /* unreffed by gdk_event_free() */
+ event->window = gtk_widget_get_window(gui.drawarea);
+ event->send_event = TRUE;
+ event->time = GDK_CURRENT_TIME;
+ event->state = state;
+ event->keyval = keyval;
+ event->hardware_keycode = /* needed for XIM */
+ XKeysymToKeycode(GDK_WINDOW_XDISPLAY(event->window), (KeySym)keyval);
+ event->length = 0;
+ event->string = NULL;
+
+ gtk_im_context_filter_keypress(xic, event);
+
+ /* For consistency, also send the corresponding release event. */
+ event->type = GDK_KEY_RELEASE;
+ event->send_event = FALSE;
+ gtk_im_context_filter_keypress(xic, event);
+
+ gdk_event_free((GdkEvent *)event);
+}
+
+ void
+xim_reset(void)
+{
+# ifdef FEAT_EVAL
+ if (USE_IMACTIVATEFUNC)
+ call_imactivatefunc(im_is_active);
+ else
+# endif
+ if (xic != NULL)
+ {
+ gtk_im_context_reset(xic);
+
+ if (p_imdisable)
+ im_shutdown();
+ else
+ {
+ xim_set_focus(gui.in_focus);
+
+ if (im_activatekey_keyval != GDK_VoidSymbol)
+ {
+ if (im_is_active)
+ {
+ g_signal_handler_block(xic, im_commit_handler_id);
+ im_synthesize_keypress(im_activatekey_keyval,
+ im_activatekey_state);
+ g_signal_handler_unblock(xic, im_commit_handler_id);
+ }
+ }
+ else
+ {
+ im_shutdown();
+ xim_init();
+ xim_set_focus(gui.in_focus);
+ }
+ }
+ }
+
+ if (p_imst == IM_ON_THE_SPOT)
+ preedit_start_col = MAXCOL;
+ xim_has_preediting = FALSE;
+}
+
+ int
+xim_queue_key_press_event(GdkEventKey *event, int down)
+{
+ if (down)
+ {
+ /*
+ * Workaround GTK2 XIM 'feature' that always converts keypad keys to
+ * chars., even when not part of an IM sequence (ref. feature of
+ * gdk/gdkkeyuni.c).
+ * Flag any keypad keys that might represent a single char.
+ * If this (on its own - i.e., not part of an IM sequence) is
+ * committed while we're processing one of these keys, we can ignore
+ * that commit and go ahead & process it ourselves. That way we can
+ * still distinguish keypad keys for use in mappings.
+ * Also add GDK_space to make <S-Space> work.
+ */
+ switch (event->keyval)
+ {
+ case GDK_KP_Add: xim_expected_char = '+'; break;
+ case GDK_KP_Subtract: xim_expected_char = '-'; break;
+ case GDK_KP_Divide: xim_expected_char = '/'; break;
+ case GDK_KP_Multiply: xim_expected_char = '*'; break;
+ case GDK_KP_Decimal: xim_expected_char = '.'; break;
+ case GDK_KP_Equal: xim_expected_char = '='; break;
+ case GDK_KP_0: xim_expected_char = '0'; break;
+ case GDK_KP_1: xim_expected_char = '1'; break;
+ case GDK_KP_2: xim_expected_char = '2'; break;
+ case GDK_KP_3: xim_expected_char = '3'; break;
+ case GDK_KP_4: xim_expected_char = '4'; break;
+ case GDK_KP_5: xim_expected_char = '5'; break;
+ case GDK_KP_6: xim_expected_char = '6'; break;
+ case GDK_KP_7: xim_expected_char = '7'; break;
+ case GDK_KP_8: xim_expected_char = '8'; break;
+ case GDK_KP_9: xim_expected_char = '9'; break;
+ case GDK_space: xim_expected_char = ' '; break;
+ default: xim_expected_char = NUL;
+ }
+ xim_ignored_char = FALSE;
+ }
+
+ /*
+ * When typing fFtT, XIM may be activated. Thus it must pass
+ * gtk_im_context_filter_keypress() in Normal mode.
+ * And while doing :sh too.
+ */
+ if (xic != NULL && !p_imdisable
+ && (State & (INSERT | CMDLINE | NORMAL | EXTERNCMD)) != 0)
+ {
+ /*
+ * Filter 'imactivatekey' and map it to CTRL-^. This way, Vim is
+ * always aware of the current status of IM, and can even emulate
+ * the activation key for modules that don't support one.
+ */
+ if (event->keyval == im_activatekey_keyval
+ && (event->state & im_activatekey_state) == im_activatekey_state)
+ {
+ unsigned int state_mask;
+
+ /* Require the state of the 3 most used modifiers to match exactly.
+ * Otherwise e.g. <S-C-space> would be unusable for other purposes
+ * if the IM activate key is <S-space>. */
+ state_mask = im_activatekey_state;
+ state_mask |= ((int)GDK_SHIFT_MASK | (int)GDK_CONTROL_MASK
+ | (int)GDK_MOD1_MASK);
+
+ if ((event->state & state_mask) != im_activatekey_state)
+ return FALSE;
+
+ /* Don't send it a second time on GDK_KEY_RELEASE. */
+ if (event->type != GDK_KEY_PRESS)
+ return TRUE;
+
+ if (map_to_exists_mode((char_u *)"", LANGMAP, FALSE))
+ {
+ im_set_active(FALSE);
+
+ /* ":lmap" mappings exists, toggle use of mappings. */
+ State ^= LANGMAP;
+ if (State & LANGMAP)
+ {
+ curbuf->b_p_iminsert = B_IMODE_NONE;
+ State &= ~LANGMAP;
+ }
+ else
+ {
+ curbuf->b_p_iminsert = B_IMODE_LMAP;
+ State |= LANGMAP;
+ }
+ return TRUE;
+ }
+
+ return gtk_im_context_filter_keypress(xic, event);
+ }
+
+ /* Don't filter events through the IM context if IM isn't active
+ * right now. Unlike with GTK+ 1.2 we cannot rely on the IM module
+ * not doing anything before the activation key was sent. */
+ if (im_activatekey_keyval == GDK_VoidSymbol || im_is_active)
+ {
+ int imresult = gtk_im_context_filter_keypress(xic, event);
+
+ if (p_imst == IM_ON_THE_SPOT)
+ {
+ /* Some XIM send following sequence:
+ * 1. preedited string.
+ * 2. committed string.
+ * 3. line changed key.
+ * 4. preedited string.
+ * 5. remove preedited string.
+ * if 3, Vim can't move back the above line for 5.
+ * thus, this part should not parse the key. */
+ if (!imresult && preedit_start_col != MAXCOL
+ && event->keyval == GDK_Return)
+ {
+ im_synthesize_keypress(GDK_Return, 0U);
+ return FALSE;
+ }
+ }
+
+ /* If XIM tried to commit a keypad key as a single char.,
+ * ignore it so we can use the keypad key 'raw', for mappings. */
+ if (xim_expected_char != NUL && xim_ignored_char)
+ /* We had a keypad key, and XIM tried to thieve it */
+ return FALSE;
+
+ /* This is supposed to fix a problem with iBus, that space
+ * characters don't work in input mode. */
+ xim_expected_char = NUL;
+
+ /* Normal processing */
+ return imresult;
+ }
+ }
+
+ return FALSE;
+}
+
+ int
+im_get_status(void)
+{
+# ifdef FEAT_EVAL
+ if (USE_IMSTATUSFUNC)
+ return call_imstatusfunc();
+# endif
+ return im_is_active;
+}
+
+ int
+preedit_get_status(void)
+{
+ return preedit_is_active;
+}
+
+ int
+im_is_preediting(void)
+{
+ return xim_has_preediting;
+}
+
+# else /* !FEAT_GUI_GTK */
+
+static int xim_is_active = FALSE; /* XIM should be active in the current
+ mode */
+static int xim_has_focus = FALSE; /* XIM is really being used for Vim */
+# ifdef FEAT_GUI_X11
+static XIMStyle input_style;
+static int status_area_enabled = TRUE;
+# endif
+
+/*
+ * Switch using XIM on/off. This is used by the code that changes "State".
+ * When 'imactivatefunc' is defined use that function instead.
+ */
+ void
+im_set_active(int active_arg)
+{
+ int active = active_arg;
+
+ /* If 'imdisable' is set, XIM is never active. */
+ if (p_imdisable)
+ active = FALSE;
+ else if (input_style & XIMPreeditPosition)
+ /* There is a problem in switching XIM off when preediting is used,
+ * and it is not clear how this can be solved. For now, keep XIM on
+ * all the time, like it was done in Vim 5.8. */
+ active = TRUE;
+
+# if defined(FEAT_EVAL)
+ if (USE_IMACTIVATEFUNC)
+ {
+ if (active != im_get_status())
+ {
+ call_imactivatefunc(active);
+ xim_has_focus = active;
+ }
+ return;
+ }
+# endif
+
+ if (xic == NULL)
+ return;
+
+ /* Remember the active state, it is needed when Vim gets keyboard focus. */
+ xim_is_active = active;
+ xim_set_preedit();
+}
+
+/*
+ * Adjust using XIM for gaining or losing keyboard focus. Also called when
+ * "xim_is_active" changes.
+ */
+ void
+xim_set_focus(int focus)
+{
+ if (xic == NULL)
+ return;
+
+ /*
+ * XIM only gets focus when the Vim window has keyboard focus and XIM has
+ * been set active for the current mode.
+ */
+ if (focus && xim_is_active)
+ {
+ if (!xim_has_focus)
+ {
+ xim_has_focus = TRUE;
+ XSetICFocus(xic);
+ }
+ }
+ else
+ {
+ if (xim_has_focus)
+ {
+ xim_has_focus = FALSE;
+ XUnsetICFocus(xic);
+ }
+ }
+}
+
+ void
+im_set_position(int row UNUSED, int col UNUSED)
+{
+ xim_set_preedit();
+}
+
+/*
+ * Set the XIM to the current cursor position.
+ */
+ void
+xim_set_preedit(void)
+{
+ XVaNestedList attr_list;
+ XRectangle spot_area;
+ XPoint over_spot;
+ int line_space;
+
+ if (xic == NULL)
+ return;
+
+ xim_set_focus(TRUE);
+
+ if (!xim_has_focus)
+ {
+ /* hide XIM cursor */
+ over_spot.x = 0;
+ over_spot.y = -100; /* arbitrary invisible position */
+ attr_list = (XVaNestedList) XVaCreateNestedList(0,
+ XNSpotLocation,
+ &over_spot,
+ NULL);
+ XSetICValues(xic, XNPreeditAttributes, attr_list, NULL);
+ XFree(attr_list);
+ return;
+ }
+
+ if (input_style & XIMPreeditPosition)
+ {
+ if (xim_fg_color == INVALCOLOR)
+ {
+ xim_fg_color = gui.def_norm_pixel;
+ xim_bg_color = gui.def_back_pixel;
+ }
+ over_spot.x = TEXT_X(gui.col);
+ over_spot.y = TEXT_Y(gui.row);
+ spot_area.x = 0;
+ spot_area.y = 0;
+ spot_area.height = gui.char_height * Rows;
+ spot_area.width = gui.char_width * Columns;
+ line_space = gui.char_height;
+ attr_list = (XVaNestedList) XVaCreateNestedList(0,
+ XNSpotLocation, &over_spot,
+ XNForeground, (Pixel) xim_fg_color,
+ XNBackground, (Pixel) xim_bg_color,
+ XNArea, &spot_area,
+ XNLineSpace, line_space,
+ NULL);
+ if (XSetICValues(xic, XNPreeditAttributes, attr_list, NULL))
+ emsg(_("E284: Cannot set IC values"));
+ XFree(attr_list);
+ }
+}
+
+# if defined(FEAT_GUI_X11)
+static char e_xim[] = N_("E285: Failed to create input context");
+# endif
+
+# if defined(FEAT_GUI_X11) || defined(PROTO)
+# if defined(XtSpecificationRelease) && XtSpecificationRelease >= 6 && !defined(SUN_SYSTEM)
+# define USE_X11R6_XIM
+# endif
+
+static int xim_real_init(Window x11_window, Display *x11_display);
+
+
+# ifdef USE_X11R6_XIM
+ static void
+xim_instantiate_cb(
+ Display *display,
+ XPointer client_data UNUSED,
+ XPointer call_data UNUSED)
+{
+ Window x11_window;
+ Display *x11_display;
+
+# ifdef XIM_DEBUG
+ xim_log("xim_instantiate_cb()\n");
+# endif
+
+ gui_get_x11_windis(&x11_window, &x11_display);
+ if (display != x11_display)
+ return;
+
+ xim_real_init(x11_window, x11_display);
+ gui_set_shellsize(FALSE, FALSE, RESIZE_BOTH);
+ if (xic != NULL)
+ XUnregisterIMInstantiateCallback(x11_display, NULL, NULL, NULL,
+ xim_instantiate_cb, NULL);
+}
+
+ static void
+xim_destroy_cb(
+ XIM im UNUSED,
+ XPointer client_data UNUSED,
+ XPointer call_data UNUSED)
+{
+ Window x11_window;
+ Display *x11_display;
+
+# ifdef XIM_DEBUG
+ xim_log("xim_destroy_cb()\n");
+ #endif
+ gui_get_x11_windis(&x11_window, &x11_display);
+
+ xic = NULL;
+ status_area_enabled = FALSE;
+
+ gui_set_shellsize(FALSE, FALSE, RESIZE_BOTH);
+
+ XRegisterIMInstantiateCallback(x11_display, NULL, NULL, NULL,
+ xim_instantiate_cb, NULL);
+}
+# endif
+
+ void
+xim_init(void)
+{
+ Window x11_window;
+ Display *x11_display;
+
+# ifdef XIM_DEBUG
+ xim_log("xim_init()\n");
+# endif
+
+ gui_get_x11_windis(&x11_window, &x11_display);
+
+ xic = NULL;
+
+ if (xim_real_init(x11_window, x11_display))
+ return;
+
+ gui_set_shellsize(FALSE, FALSE, RESIZE_BOTH);
+
+# ifdef USE_X11R6_XIM
+ XRegisterIMInstantiateCallback(x11_display, NULL, NULL, NULL,
+ xim_instantiate_cb, NULL);
+# endif
+}
+
+ static int
+xim_real_init(Window x11_window, Display *x11_display)
+{
+ int i;
+ char *p,
+ *s,
+ *ns,
+ *end,
+ tmp[1024];
+# define IMLEN_MAX 40
+ char buf[IMLEN_MAX + 7];
+ XIM xim = NULL;
+ XIMStyles *xim_styles;
+ XIMStyle this_input_style = 0;
+ Boolean found;
+ XPoint over_spot;
+ XVaNestedList preedit_list, status_list;
+
+ input_style = 0;
+ status_area_enabled = FALSE;
+
+ if (xic != NULL)
+ return FALSE;
+
+ if (gui.rsrc_input_method != NULL && *gui.rsrc_input_method != NUL)
+ {
+ strcpy(tmp, gui.rsrc_input_method);
+ for (ns = s = tmp; ns != NULL && *s != NUL;)
+ {
+ s = (char *)skipwhite((char_u *)s);
+ if (*s == NUL)
+ break;
+ if ((ns = end = strchr(s, ',')) == NULL)
+ end = s + strlen(s);
+ while (isspace(((char_u *)end)[-1]))
+ end--;
+ *end = NUL;
+
+ if (strlen(s) <= IMLEN_MAX)
+ {
+ strcpy(buf, "@im=");
+ strcat(buf, s);
+ if ((p = XSetLocaleModifiers(buf)) != NULL && *p != NUL
+ && (xim = XOpenIM(x11_display, NULL, NULL, NULL))
+ != NULL)
+ break;
+ }
+
+ s = ns + 1;
+ }
+ }
+
+ if (xim == NULL && (p = XSetLocaleModifiers("")) != NULL && *p != NUL)
+ xim = XOpenIM(x11_display, NULL, NULL, NULL);
+
+ /* This is supposed to be useful to obtain characters through
+ * XmbLookupString() without really using a XIM. */
+ if (xim == NULL && (p = XSetLocaleModifiers("@im=none")) != NULL
+ && *p != NUL)
+ xim = XOpenIM(x11_display, NULL, NULL, NULL);
+
+ if (xim == NULL)
+ {
+ /* Only give this message when verbose is set, because too many people
+ * got this message when they didn't want to use a XIM. */
+ if (p_verbose > 0)
+ {
+ verbose_enter();
+ emsg(_("E286: Failed to open input method"));
+ verbose_leave();
+ }
+ return FALSE;
+ }
+
+# ifdef USE_X11R6_XIM
+ {
+ XIMCallback destroy_cb;
+
+ destroy_cb.callback = xim_destroy_cb;
+ destroy_cb.client_data = NULL;
+ if (XSetIMValues(xim, XNDestroyCallback, &destroy_cb, NULL))
+ emsg(_("E287: Warning: Could not set destroy callback to IM"));
+ }
+# endif
+
+ if (XGetIMValues(xim, XNQueryInputStyle, &xim_styles, NULL) || !xim_styles)
+ {
+ emsg(_("E288: input method doesn't support any style"));
+ XCloseIM(xim);
+ return FALSE;
+ }
+
+ found = False;
+ strcpy(tmp, gui.rsrc_preedit_type_name);
+ for (s = tmp; s && !found; )
+ {
+ while (*s && isspace((unsigned char)*s))
+ s++;
+ if (!*s)
+ break;
+ if ((ns = end = strchr(s, ',')) != 0)
+ ns++;
+ else
+ end = s + strlen(s);
+ while (isspace((unsigned char)*end))
+ end--;
+ *end = '\0';
+
+ if (!strcmp(s, "OverTheSpot"))
+ this_input_style = (XIMPreeditPosition | XIMStatusArea);
+ else if (!strcmp(s, "OffTheSpot"))
+ this_input_style = (XIMPreeditArea | XIMStatusArea);
+ else if (!strcmp(s, "Root"))
+ this_input_style = (XIMPreeditNothing | XIMStatusNothing);
+
+ for (i = 0; (unsigned short)i < xim_styles->count_styles; i++)
+ {
+ if (this_input_style == xim_styles->supported_styles[i])
+ {
+ found = True;
+ break;
+ }
+ }
+ if (!found)
+ for (i = 0; (unsigned short)i < xim_styles->count_styles; i++)
+ {
+ if ((xim_styles->supported_styles[i] & this_input_style)
+ == (this_input_style & ~XIMStatusArea))
+ {
+ this_input_style &= ~XIMStatusArea;
+ found = True;
+ break;
+ }
+ }
+
+ s = ns;
+ }
+ XFree(xim_styles);
+
+ if (!found)
+ {
+ /* Only give this message when verbose is set, because too many people
+ * got this message when they didn't want to use a XIM. */
+ if (p_verbose > 0)
+ {
+ verbose_enter();
+ emsg(_("E289: input method doesn't support my preedit type"));
+ verbose_leave();
+ }
+ XCloseIM(xim);
+ return FALSE;
+ }
+
+ over_spot.x = TEXT_X(gui.col);
+ over_spot.y = TEXT_Y(gui.row);
+ input_style = this_input_style;
+
+ /* A crash was reported when trying to pass gui.norm_font as XNFontSet,
+ * thus that has been removed. Hopefully the default works... */
+# ifdef FEAT_XFONTSET
+ if (gui.fontset != NOFONTSET)
+ {
+ preedit_list = XVaCreateNestedList(0,
+ XNSpotLocation, &over_spot,
+ XNForeground, (Pixel)gui.def_norm_pixel,
+ XNBackground, (Pixel)gui.def_back_pixel,
+ XNFontSet, (XFontSet)gui.fontset,
+ NULL);
+ status_list = XVaCreateNestedList(0,
+ XNForeground, (Pixel)gui.def_norm_pixel,
+ XNBackground, (Pixel)gui.def_back_pixel,
+ XNFontSet, (XFontSet)gui.fontset,
+ NULL);
+ }
+ else
+# endif
+ {
+ preedit_list = XVaCreateNestedList(0,
+ XNSpotLocation, &over_spot,
+ XNForeground, (Pixel)gui.def_norm_pixel,
+ XNBackground, (Pixel)gui.def_back_pixel,
+ NULL);
+ status_list = XVaCreateNestedList(0,
+ XNForeground, (Pixel)gui.def_norm_pixel,
+ XNBackground, (Pixel)gui.def_back_pixel,
+ NULL);
+ }
+
+ xic = XCreateIC(xim,
+ XNInputStyle, input_style,
+ XNClientWindow, x11_window,
+ XNFocusWindow, gui.wid,
+ XNPreeditAttributes, preedit_list,
+ XNStatusAttributes, status_list,
+ NULL);
+ XFree(status_list);
+ XFree(preedit_list);
+ if (xic != NULL)
+ {
+ if (input_style & XIMStatusArea)
+ {
+ xim_set_status_area();
+ status_area_enabled = TRUE;
+ }
+ else
+ gui_set_shellsize(FALSE, FALSE, RESIZE_BOTH);
+ }
+ else
+ {
+ if (!is_not_a_term())
+ emsg(_(e_xim));
+ XCloseIM(xim);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+# endif /* FEAT_GUI_X11 */
+
+/*
+ * Get IM status. When IM is on, return TRUE. Else return FALSE.
+ * FIXME: This doesn't work correctly: Having focus doesn't always mean XIM is
+ * active, when not having focus XIM may still be active (e.g., when using a
+ * tear-off menu item).
+ */
+ int
+im_get_status(void)
+{
+# ifdef FEAT_EVAL
+ if (USE_IMSTATUSFUNC)
+ return call_imstatusfunc();
+# endif
+ return xim_has_focus;
+}
+
+# endif /* !FEAT_GUI_GTK */
+
+# if !defined(FEAT_GUI_GTK) || defined(PROTO)
+/*
+ * Set up the status area.
+ *
+ * This should use a separate Widget, but that seems not possible, because
+ * preedit_area and status_area should be set to the same window as for the
+ * text input. Unfortunately this means the status area pollutes the text
+ * window...
+ */
+ void
+xim_set_status_area(void)
+{
+ XVaNestedList preedit_list = 0, status_list = 0, list = 0;
+ XRectangle pre_area, status_area;
+
+ if (xic == NULL)
+ return;
+
+ if (input_style & XIMStatusArea)
+ {
+ if (input_style & XIMPreeditArea)
+ {
+ XRectangle *needed_rect;
+
+ /* to get status_area width */
+ status_list = XVaCreateNestedList(0, XNAreaNeeded,
+ &needed_rect, NULL);
+ XGetICValues(xic, XNStatusAttributes, status_list, NULL);
+ XFree(status_list);
+
+ status_area.width = needed_rect->width;
+ }
+ else
+ status_area.width = gui.char_width * Columns;
+
+ status_area.x = 0;
+ status_area.y = gui.char_height * Rows + gui.border_offset;
+ if (gui.which_scrollbars[SBAR_BOTTOM])
+ status_area.y += gui.scrollbar_height;
+#ifdef FEAT_MENU
+ if (gui.menu_is_active)
+ status_area.y += gui.menu_height;
+#endif
+ status_area.height = gui.char_height;
+ status_list = XVaCreateNestedList(0, XNArea, &status_area, NULL);
+ }
+ else
+ {
+ status_area.x = 0;
+ status_area.y = gui.char_height * Rows + gui.border_offset;
+ if (gui.which_scrollbars[SBAR_BOTTOM])
+ status_area.y += gui.scrollbar_height;
+#ifdef FEAT_MENU
+ if (gui.menu_is_active)
+ status_area.y += gui.menu_height;
+#endif
+ status_area.width = 0;
+ status_area.height = gui.char_height;
+ }
+
+ if (input_style & XIMPreeditArea) /* off-the-spot */
+ {
+ pre_area.x = status_area.x + status_area.width;
+ pre_area.y = gui.char_height * Rows + gui.border_offset;
+ pre_area.width = gui.char_width * Columns - pre_area.x;
+ if (gui.which_scrollbars[SBAR_BOTTOM])
+ pre_area.y += gui.scrollbar_height;
+#ifdef FEAT_MENU
+ if (gui.menu_is_active)
+ pre_area.y += gui.menu_height;
+#endif
+ pre_area.height = gui.char_height;
+ preedit_list = XVaCreateNestedList(0, XNArea, &pre_area, NULL);
+ }
+ else if (input_style & XIMPreeditPosition) /* over-the-spot */
+ {
+ pre_area.x = 0;
+ pre_area.y = 0;
+ pre_area.height = gui.char_height * Rows;
+ pre_area.width = gui.char_width * Columns;
+ preedit_list = XVaCreateNestedList(0, XNArea, &pre_area, NULL);
+ }
+
+ if (preedit_list && status_list)
+ list = XVaCreateNestedList(0, XNPreeditAttributes, preedit_list,
+ XNStatusAttributes, status_list, NULL);
+ else if (preedit_list)
+ list = XVaCreateNestedList(0, XNPreeditAttributes, preedit_list,
+ NULL);
+ else if (status_list)
+ list = XVaCreateNestedList(0, XNStatusAttributes, status_list,
+ NULL);
+ else
+ list = NULL;
+
+ if (list)
+ {
+ XSetICValues(xic, XNVaNestedList, list, NULL);
+ XFree(list);
+ }
+ if (status_list)
+ XFree(status_list);
+ if (preedit_list)
+ XFree(preedit_list);
+}
+
+ int
+xim_get_status_area_height(void)
+{
+ if (status_area_enabled)
+ return gui.char_height;
+ return 0;
+}
+# endif
+
+#else /* !defined(FEAT_XIM) */
+
+# ifdef IME_WITHOUT_XIM
+static int im_was_set_active = FALSE;
+
+ int
+im_get_status(void)
+{
+# if defined(FEAT_EVAL)
+ if (USE_IMSTATUSFUNC)
+ return call_imstatusfunc();
+# endif
+ return im_was_set_active;
+}
+
+ void
+im_set_active(int active_arg)
+{
+# if defined(FEAT_EVAL)
+ int active = !p_imdisable && active_arg;
+
+ if (USE_IMACTIVATEFUNC && active != im_get_status())
+ {
+ call_imactivatefunc(active);
+ im_was_set_active = active;
+ }
+# endif
+}
+
+# ifdef FEAT_GUI
+ void
+im_set_position(int row UNUSED, int col UNUSED)
+{
+}
+# endif
+# endif
+
+#endif /* FEAT_XIM */
+
+
+/*
+ * Setup "vcp" for conversion from "from" to "to".
+ * The names must have been made canonical with enc_canonize().
+ * vcp->vc_type must have been initialized to CONV_NONE.
+ * Note: cannot be used for conversion from/to ucs-2 and ucs-4 (will use utf-8
+ * instead).
+ * Afterwards invoke with "from" and "to" equal to NULL to cleanup.
+ * Return FAIL when conversion is not supported, OK otherwise.
+ */
+ int
+convert_setup(vimconv_T *vcp, char_u *from, char_u *to)
+{
+ return convert_setup_ext(vcp, from, TRUE, to, TRUE);
+}
+
+/*
+ * As convert_setup(), but only when from_unicode_is_utf8 is TRUE will all
+ * "from" unicode charsets be considered utf-8. Same for "to".
+ */
+ int
+convert_setup_ext(
+ vimconv_T *vcp,
+ char_u *from,
+ int from_unicode_is_utf8,
+ char_u *to,
+ int to_unicode_is_utf8)
+{
+ int from_prop;
+ int to_prop;
+ int from_is_utf8;
+ int to_is_utf8;
+
+ /* Reset to no conversion. */
+#ifdef USE_ICONV
+ if (vcp->vc_type == CONV_ICONV && vcp->vc_fd != (iconv_t)-1)
+ iconv_close(vcp->vc_fd);
+#endif
+ vcp->vc_type = CONV_NONE;
+ vcp->vc_factor = 1;
+ vcp->vc_fail = FALSE;
+
+ /* No conversion when one of the names is empty or they are equal. */
+ if (from == NULL || *from == NUL || to == NULL || *to == NUL
+ || STRCMP(from, to) == 0)
+ return OK;
+
+ from_prop = enc_canon_props(from);
+ to_prop = enc_canon_props(to);
+ if (from_unicode_is_utf8)
+ from_is_utf8 = from_prop & ENC_UNICODE;
+ else
+ from_is_utf8 = from_prop == ENC_UNICODE;
+ if (to_unicode_is_utf8)
+ to_is_utf8 = to_prop & ENC_UNICODE;
+ else
+ to_is_utf8 = to_prop == ENC_UNICODE;
+
+ if ((from_prop & ENC_LATIN1) && to_is_utf8)
+ {
+ /* Internal latin1 -> utf-8 conversion. */
+ vcp->vc_type = CONV_TO_UTF8;
+ vcp->vc_factor = 2; /* up to twice as long */
+ }
+ else if ((from_prop & ENC_LATIN9) && to_is_utf8)
+ {
+ /* Internal latin9 -> utf-8 conversion. */
+ vcp->vc_type = CONV_9_TO_UTF8;
+ vcp->vc_factor = 3; /* up to three as long (euro sign) */
+ }
+ else if (from_is_utf8 && (to_prop & ENC_LATIN1))
+ {
+ /* Internal utf-8 -> latin1 conversion. */
+ vcp->vc_type = CONV_TO_LATIN1;
+ }
+ else if (from_is_utf8 && (to_prop & ENC_LATIN9))
+ {
+ /* Internal utf-8 -> latin9 conversion. */
+ vcp->vc_type = CONV_TO_LATIN9;
+ }
+#ifdef WIN3264
+ /* Win32-specific codepage <-> codepage conversion without iconv. */
+ else if ((from_is_utf8 || encname2codepage(from) > 0)
+ && (to_is_utf8 || encname2codepage(to) > 0))
+ {
+ vcp->vc_type = CONV_CODEPAGE;
+ vcp->vc_factor = 2; /* up to twice as long */
+ vcp->vc_cpfrom = from_is_utf8 ? 0 : encname2codepage(from);
+ vcp->vc_cpto = to_is_utf8 ? 0 : encname2codepage(to);
+ }
+#endif
+#ifdef MACOS_CONVERT
+ else if ((from_prop & ENC_MACROMAN) && (to_prop & ENC_LATIN1))
+ {
+ vcp->vc_type = CONV_MAC_LATIN1;
+ }
+ else if ((from_prop & ENC_MACROMAN) && to_is_utf8)
+ {
+ vcp->vc_type = CONV_MAC_UTF8;
+ vcp->vc_factor = 2; /* up to twice as long */
+ }
+ else if ((from_prop & ENC_LATIN1) && (to_prop & ENC_MACROMAN))
+ {
+ vcp->vc_type = CONV_LATIN1_MAC;
+ }
+ else if (from_is_utf8 && (to_prop & ENC_MACROMAN))
+ {
+ vcp->vc_type = CONV_UTF8_MAC;
+ }
+#endif
+#ifdef USE_ICONV
+ else
+ {
+ /* Use iconv() for conversion. */
+ vcp->vc_fd = (iconv_t)my_iconv_open(
+ to_is_utf8 ? (char_u *)"utf-8" : to,
+ from_is_utf8 ? (char_u *)"utf-8" : from);
+ if (vcp->vc_fd != (iconv_t)-1)
+ {
+ vcp->vc_type = CONV_ICONV;
+ vcp->vc_factor = 4; /* could be longer too... */
+ }
+ }
+#endif
+ if (vcp->vc_type == CONV_NONE)
+ return FAIL;
+
+ return OK;
+}
+
+#if defined(FEAT_GUI) || defined(AMIGA) || defined(WIN3264) \
+ || defined(PROTO)
+/*
+ * Do conversion on typed input characters in-place.
+ * The input and output are not NUL terminated!
+ * Returns the length after conversion.
+ */
+ int
+convert_input(char_u *ptr, int len, int maxlen)
+{
+ return convert_input_safe(ptr, len, maxlen, NULL, NULL);
+}
+#endif
+
+/*
+ * Like convert_input(), but when there is an incomplete byte sequence at the
+ * end return that as an allocated string in "restp" and set "*restlenp" to
+ * the length. If "restp" is NULL it is not used.
+ */
+ int
+convert_input_safe(
+ char_u *ptr,
+ int len,
+ int maxlen,
+ char_u **restp,
+ int *restlenp)
+{
+ char_u *d;
+ int dlen = len;
+ int unconvertlen = 0;
+
+ d = string_convert_ext(&input_conv, ptr, &dlen,
+ restp == NULL ? NULL : &unconvertlen);
+ if (d != NULL)
+ {
+ if (dlen <= maxlen)
+ {
+ if (unconvertlen > 0)
+ {
+ /* Move the unconverted characters to allocated memory. */
+ *restp = alloc(unconvertlen);
+ if (*restp != NULL)
+ mch_memmove(*restp, ptr + len - unconvertlen, unconvertlen);
+ *restlenp = unconvertlen;
+ }
+ mch_memmove(ptr, d, dlen);
+ }
+ else
+ /* result is too long, keep the unconverted text (the caller must
+ * have done something wrong!) */
+ dlen = len;
+ vim_free(d);
+ }
+ return dlen;
+}
+
+/*
+ * Convert text "ptr[*lenp]" according to "vcp".
+ * Returns the result in allocated memory and sets "*lenp".
+ * When "lenp" is NULL, use NUL terminated strings.
+ * Illegal chars are often changed to "?", unless vcp->vc_fail is set.
+ * When something goes wrong, NULL is returned and "*lenp" is unchanged.
+ */
+ char_u *
+string_convert(
+ vimconv_T *vcp,
+ char_u *ptr,
+ int *lenp)
+{
+ return string_convert_ext(vcp, ptr, lenp, NULL);
+}
+
+/*
+ * Like string_convert(), but when "unconvlenp" is not NULL and there are is
+ * an incomplete sequence at the end it is not converted and "*unconvlenp" is
+ * set to the number of remaining bytes.
+ */
+ char_u *
+string_convert_ext(
+ vimconv_T *vcp,
+ char_u *ptr,
+ int *lenp,
+ int *unconvlenp)
+{
+ char_u *retval = NULL;
+ char_u *d;
+ int len;
+ int i;
+ int l;
+ int c;
+
+ if (lenp == NULL)
+ len = (int)STRLEN(ptr);
+ else
+ len = *lenp;
+ if (len == 0)
+ return vim_strsave((char_u *)"");
+
+ switch (vcp->vc_type)
+ {
+ case CONV_TO_UTF8: /* latin1 to utf-8 conversion */
+ retval = alloc(len * 2 + 1);
+ if (retval == NULL)
+ break;
+ d = retval;
+ for (i = 0; i < len; ++i)
+ {
+ c = ptr[i];
+ if (c < 0x80)
+ *d++ = c;
+ else
+ {
+ *d++ = 0xc0 + ((unsigned)c >> 6);
+ *d++ = 0x80 + (c & 0x3f);
+ }
+ }
+ *d = NUL;
+ if (lenp != NULL)
+ *lenp = (int)(d - retval);
+ break;
+
+ case CONV_9_TO_UTF8: /* latin9 to utf-8 conversion */
+ retval = alloc(len * 3 + 1);
+ if (retval == NULL)
+ break;
+ d = retval;
+ for (i = 0; i < len; ++i)
+ {
+ c = ptr[i];
+ switch (c)
+ {
+ case 0xa4: c = 0x20ac; break; /* euro */
+ case 0xa6: c = 0x0160; break; /* S hat */
+ case 0xa8: c = 0x0161; break; /* S -hat */
+ case 0xb4: c = 0x017d; break; /* Z hat */
+ case 0xb8: c = 0x017e; break; /* Z -hat */
+ case 0xbc: c = 0x0152; break; /* OE */
+ case 0xbd: c = 0x0153; break; /* oe */
+ case 0xbe: c = 0x0178; break; /* Y */
+ }
+ d += utf_char2bytes(c, d);
+ }
+ *d = NUL;
+ if (lenp != NULL)
+ *lenp = (int)(d - retval);
+ break;
+
+ case CONV_TO_LATIN1: /* utf-8 to latin1 conversion */
+ case CONV_TO_LATIN9: /* utf-8 to latin9 conversion */
+ retval = alloc(len + 1);
+ if (retval == NULL)
+ break;
+ d = retval;
+ for (i = 0; i < len; ++i)
+ {
+ l = utf_ptr2len_len(ptr + i, len - i);
+ if (l == 0)
+ *d++ = NUL;
+ else if (l == 1)
+ {
+ int l_w = utf8len_tab_zero[ptr[i]];
+
+ if (l_w == 0)
+ {
+ /* Illegal utf-8 byte cannot be converted */
+ vim_free(retval);
+ return NULL;
+ }
+ if (unconvlenp != NULL && l_w > len - i)
+ {
+ /* Incomplete sequence at the end. */
+ *unconvlenp = len - i;
+ break;
+ }
+ *d++ = ptr[i];
+ }
+ else
+ {
+ c = utf_ptr2char(ptr + i);
+ if (vcp->vc_type == CONV_TO_LATIN9)
+ switch (c)
+ {
+ case 0x20ac: c = 0xa4; break; /* euro */
+ case 0x0160: c = 0xa6; break; /* S hat */
+ case 0x0161: c = 0xa8; break; /* S -hat */
+ case 0x017d: c = 0xb4; break; /* Z hat */
+ case 0x017e: c = 0xb8; break; /* Z -hat */
+ case 0x0152: c = 0xbc; break; /* OE */
+ case 0x0153: c = 0xbd; break; /* oe */
+ case 0x0178: c = 0xbe; break; /* Y */
+ case 0xa4:
+ case 0xa6:
+ case 0xa8:
+ case 0xb4:
+ case 0xb8:
+ case 0xbc:
+ case 0xbd:
+ case 0xbe: c = 0x100; break; /* not in latin9 */
+ }
+ if (!utf_iscomposing(c)) /* skip composing chars */
+ {
+ if (c < 0x100)
+ *d++ = c;
+ else if (vcp->vc_fail)
+ {
+ vim_free(retval);
+ return NULL;
+ }
+ else
+ {
+ *d++ = 0xbf;
+ if (utf_char2cells(c) > 1)
+ *d++ = '?';
+ }
+ }
+ i += l - 1;
+ }
+ }
+ *d = NUL;
+ if (lenp != NULL)
+ *lenp = (int)(d - retval);
+ break;
+
+# ifdef MACOS_CONVERT
+ case CONV_MAC_LATIN1:
+ retval = mac_string_convert(ptr, len, lenp, vcp->vc_fail,
+ 'm', 'l', unconvlenp);
+ break;
+
+ case CONV_LATIN1_MAC:
+ retval = mac_string_convert(ptr, len, lenp, vcp->vc_fail,
+ 'l', 'm', unconvlenp);
+ break;
+
+ case CONV_MAC_UTF8:
+ retval = mac_string_convert(ptr, len, lenp, vcp->vc_fail,
+ 'm', 'u', unconvlenp);
+ break;
+
+ case CONV_UTF8_MAC:
+ retval = mac_string_convert(ptr, len, lenp, vcp->vc_fail,
+ 'u', 'm', unconvlenp);
+ break;
+# endif
+
+# ifdef USE_ICONV
+ case CONV_ICONV: /* conversion with output_conv.vc_fd */
+ retval = iconv_string(vcp, ptr, len, unconvlenp, lenp);
+ break;
+# endif
+# ifdef WIN3264
+ case CONV_CODEPAGE: /* codepage -> codepage */
+ {
+ int retlen;
+ int tmp_len;
+ short_u *tmp;
+
+ /* 1. codepage/UTF-8 -> ucs-2. */
+ if (vcp->vc_cpfrom == 0)
+ tmp_len = utf8_to_utf16(ptr, len, NULL, NULL);
+ else
+ {
+ tmp_len = MultiByteToWideChar(vcp->vc_cpfrom,
+ unconvlenp ? MB_ERR_INVALID_CHARS : 0,
+ (char *)ptr, len, 0, 0);
+ if (tmp_len == 0
+ && GetLastError() == ERROR_NO_UNICODE_TRANSLATION)
+ {
+ if (lenp != NULL)
+ *lenp = 0;
+ if (unconvlenp != NULL)
+ *unconvlenp = len;
+ retval = alloc(1);
+ if (retval)
+ retval[0] = NUL;
+ return retval;
+ }
+ }
+ tmp = (short_u *)alloc(sizeof(short_u) * tmp_len);
+ if (tmp == NULL)
+ break;
+ if (vcp->vc_cpfrom == 0)
+ utf8_to_utf16(ptr, len, tmp, unconvlenp);
+ else
+ MultiByteToWideChar(vcp->vc_cpfrom, 0,
+ (char *)ptr, len, tmp, tmp_len);
+
+ /* 2. ucs-2 -> codepage/UTF-8. */
+ if (vcp->vc_cpto == 0)
+ retlen = utf16_to_utf8(tmp, tmp_len, NULL);
+ else
+ retlen = WideCharToMultiByte(vcp->vc_cpto, 0,
+ tmp, tmp_len, 0, 0, 0, 0);
+ retval = alloc(retlen + 1);
+ if (retval != NULL)
+ {
+ if (vcp->vc_cpto == 0)
+ utf16_to_utf8(tmp, tmp_len, retval);
+ else
+ WideCharToMultiByte(vcp->vc_cpto, 0,
+ tmp, tmp_len,
+ (char *)retval, retlen, 0, 0);
+ retval[retlen] = NUL;
+ if (lenp != NULL)
+ *lenp = retlen;
+ }
+ vim_free(tmp);
+ break;
+ }
+# endif
+ }
+
+ return retval;
+}
diff --git a/src/memfile.c b/src/memfile.c
new file mode 100644
index 0000000..f2e774a
--- /dev/null
+++ b/src/memfile.c
@@ -0,0 +1,1491 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * memfile.c: Contains the functions for handling blocks of memory which can
+ * be stored in a file. This is the implementation of a sort of virtual memory.
+ *
+ * A memfile consists of a sequence of blocks. The blocks numbered from 0
+ * upwards have been assigned a place in the actual file. The block number
+ * is equal to the page number in the file. The
+ * blocks with negative numbers are currently in memory only. They can be
+ * assigned a place in the file when too much memory is being used. At that
+ * moment they get a new, positive, number. A list is used for translation of
+ * negative to positive numbers.
+ *
+ * The size of a block is a multiple of a page size, normally the page size of
+ * the device the file is on. Most blocks are 1 page long. A Block of multiple
+ * pages is used for a line that does not fit in a single page.
+ *
+ * Each block can be in memory and/or in a file. The block stays in memory
+ * as long as it is locked. If it is no longer locked it can be swapped out to
+ * the file. It is only written to the file if it has been changed.
+ *
+ * Under normal operation the file is created when opening the memory file and
+ * deleted when closing the memory file. Only with recovery an existing memory
+ * file is opened.
+ */
+
+#include "vim.h"
+
+/*
+ * Some systems have the page size in statfs.f_bsize, some in stat.st_blksize
+ */
+#ifdef HAVE_ST_BLKSIZE
+# define STATFS stat
+# define F_BSIZE st_blksize
+# define fstatfs(fd, buf, len, nul) mch_fstat((fd), (buf))
+#else
+# ifdef HAVE_SYS_STATFS_H
+# include <sys/statfs.h>
+# define STATFS statfs
+# define F_BSIZE f_bsize
+# ifdef __MINT__ /* do we still need this? */
+# define fstatfs(fd, buf, len, nul) mch_fstat((fd), (buf))
+# endif
+# endif
+#endif
+
+/*
+ * for Amiga Dos 2.0x we use Flush
+ */
+#ifdef AMIGA
+# ifdef FEAT_ARP
+extern int dos2; /* this is in os_amiga.c */
+# endif
+# ifdef SASC
+# include <proto/dos.h>
+# include <ios1.h> /* for chkufb() */
+# endif
+#endif
+
+#define MEMFILE_PAGE_SIZE 4096 /* default page size */
+
+static long_u total_mem_used = 0; /* total memory used for memfiles */
+
+static void mf_ins_hash(memfile_T *, bhdr_T *);
+static void mf_rem_hash(memfile_T *, bhdr_T *);
+static bhdr_T *mf_find_hash(memfile_T *, blocknr_T);
+static void mf_ins_used(memfile_T *, bhdr_T *);
+static void mf_rem_used(memfile_T *, bhdr_T *);
+static bhdr_T *mf_release(memfile_T *, int);
+static bhdr_T *mf_alloc_bhdr(memfile_T *, int);
+static void mf_free_bhdr(bhdr_T *);
+static void mf_ins_free(memfile_T *, bhdr_T *);
+static bhdr_T *mf_rem_free(memfile_T *);
+static int mf_read(memfile_T *, bhdr_T *);
+static int mf_write(memfile_T *, bhdr_T *);
+static int mf_write_block(memfile_T *mfp, bhdr_T *hp, off_T offset, unsigned size);
+static int mf_trans_add(memfile_T *, bhdr_T *);
+static void mf_do_open(memfile_T *, char_u *, int);
+static void mf_hash_init(mf_hashtab_T *);
+static void mf_hash_free(mf_hashtab_T *);
+static void mf_hash_free_all(mf_hashtab_T *);
+static mf_hashitem_T *mf_hash_find(mf_hashtab_T *, blocknr_T);
+static void mf_hash_add_item(mf_hashtab_T *, mf_hashitem_T *);
+static void mf_hash_rem_item(mf_hashtab_T *, mf_hashitem_T *);
+static int mf_hash_grow(mf_hashtab_T *);
+
+/*
+ * The functions for using a memfile:
+ *
+ * mf_open() open a new or existing memfile
+ * mf_open_file() open a swap file for an existing memfile
+ * mf_close() close (and delete) a memfile
+ * mf_new() create a new block in a memfile and lock it
+ * mf_get() get an existing block and lock it
+ * mf_put() unlock a block, may be marked for writing
+ * mf_free() remove a block
+ * mf_sync() sync changed parts of memfile to disk
+ * mf_release_all() release as much memory as possible
+ * mf_trans_del() may translate negative to positive block number
+ * mf_fullname() make file name full path (use before first :cd)
+ */
+
+/*
+ * Open an existing or new memory block file.
+ *
+ * fname: name of file to use (NULL means no file at all)
+ * Note: fname must have been allocated, it is not copied!
+ * If opening the file fails, fname is freed.
+ * flags: flags for open() call
+ *
+ * If fname != NULL and file cannot be opened, fail.
+ *
+ * return value: identifier for this memory block file.
+ */
+ memfile_T *
+mf_open(char_u *fname, int flags)
+{
+ memfile_T *mfp;
+ off_T size;
+#if defined(STATFS) && defined(UNIX) && !defined(__QNX__) && !defined(__minix)
+# define USE_FSTATFS
+ struct STATFS stf;
+#endif
+
+ if ((mfp = (memfile_T *)alloc((unsigned)sizeof(memfile_T))) == NULL)
+ return NULL;
+
+ if (fname == NULL) /* no file for this memfile, use memory only */
+ {
+ mfp->mf_fname = NULL;
+ mfp->mf_ffname = NULL;
+ mfp->mf_fd = -1;
+ }
+ else
+ {
+ mf_do_open(mfp, fname, flags); /* try to open the file */
+
+ /* if the file cannot be opened, return here */
+ if (mfp->mf_fd < 0)
+ {
+ vim_free(mfp);
+ return NULL;
+ }
+ }
+
+ mfp->mf_free_first = NULL; /* free list is empty */
+ mfp->mf_used_first = NULL; /* used list is empty */
+ mfp->mf_used_last = NULL;
+ mfp->mf_dirty = FALSE;
+ mfp->mf_used_count = 0;
+ mf_hash_init(&mfp->mf_hash);
+ mf_hash_init(&mfp->mf_trans);
+ mfp->mf_page_size = MEMFILE_PAGE_SIZE;
+#ifdef FEAT_CRYPT
+ mfp->mf_old_key = NULL;
+#endif
+
+#ifdef USE_FSTATFS
+ /*
+ * Try to set the page size equal to the block size of the device.
+ * Speeds up I/O a lot.
+ * When recovering, the actual block size will be retrieved from block 0
+ * in ml_recover(). The size used here may be wrong, therefore
+ * mf_blocknr_max must be rounded up.
+ */
+ if (mfp->mf_fd >= 0
+ && fstatfs(mfp->mf_fd, &stf, sizeof(struct statfs), 0) == 0
+ && stf.F_BSIZE >= MIN_SWAP_PAGE_SIZE
+ && stf.F_BSIZE <= MAX_SWAP_PAGE_SIZE)
+ mfp->mf_page_size = stf.F_BSIZE;
+#endif
+
+ if (mfp->mf_fd < 0 || (flags & (O_TRUNC|O_EXCL))
+ || (size = vim_lseek(mfp->mf_fd, (off_T)0L, SEEK_END)) <= 0)
+ mfp->mf_blocknr_max = 0; /* no file or empty file */
+ else
+ mfp->mf_blocknr_max = (blocknr_T)((size + mfp->mf_page_size - 1)
+ / mfp->mf_page_size);
+ mfp->mf_blocknr_min = -1;
+ mfp->mf_neg_count = 0;
+ mfp->mf_infile_count = mfp->mf_blocknr_max;
+
+ /*
+ * Compute maximum number of pages ('maxmem' is in Kbyte):
+ * 'mammem' * 1Kbyte / page-size-in-bytes.
+ * Avoid overflow by first reducing page size as much as possible.
+ */
+ {
+ int shift = 10;
+ unsigned page_size = mfp->mf_page_size;
+
+ while (shift > 0 && (page_size & 1) == 0)
+ {
+ page_size = page_size >> 1;
+ --shift;
+ }
+ mfp->mf_used_count_max = (p_mm << shift) / page_size;
+ if (mfp->mf_used_count_max < 10)
+ mfp->mf_used_count_max = 10;
+ }
+
+ return mfp;
+}
+
+/*
+ * Open a file for an existing memfile. Used when updatecount set from 0 to
+ * some value.
+ * If the file already exists, this fails.
+ * "fname" is the name of file to use (NULL means no file at all)
+ * Note: "fname" must have been allocated, it is not copied! If opening the
+ * file fails, "fname" is freed.
+ *
+ * return value: FAIL if file could not be opened, OK otherwise
+ */
+ int
+mf_open_file(memfile_T *mfp, char_u *fname)
+{
+ mf_do_open(mfp, fname, O_RDWR|O_CREAT|O_EXCL); /* try to open the file */
+
+ if (mfp->mf_fd < 0)
+ return FAIL;
+
+ mfp->mf_dirty = TRUE;
+ return OK;
+}
+
+/*
+ * Close a memory file and delete the associated file if 'del_file' is TRUE.
+ */
+ void
+mf_close(memfile_T *mfp, int del_file)
+{
+ bhdr_T *hp, *nextp;
+
+ if (mfp == NULL) /* safety check */
+ return;
+ if (mfp->mf_fd >= 0)
+ {
+ if (close(mfp->mf_fd) < 0)
+ emsg(_(e_swapclose));
+ }
+ if (del_file && mfp->mf_fname != NULL)
+ mch_remove(mfp->mf_fname);
+ /* free entries in used list */
+ for (hp = mfp->mf_used_first; hp != NULL; hp = nextp)
+ {
+ total_mem_used -= hp->bh_page_count * mfp->mf_page_size;
+ nextp = hp->bh_next;
+ mf_free_bhdr(hp);
+ }
+ while (mfp->mf_free_first != NULL) /* free entries in free list */
+ vim_free(mf_rem_free(mfp));
+ mf_hash_free(&mfp->mf_hash);
+ mf_hash_free_all(&mfp->mf_trans); /* free hashtable and its items */
+ vim_free(mfp->mf_fname);
+ vim_free(mfp->mf_ffname);
+ vim_free(mfp);
+}
+
+/*
+ * Close the swap file for a memfile. Used when 'swapfile' is reset.
+ */
+ void
+mf_close_file(
+ buf_T *buf,
+ int getlines) /* get all lines into memory? */
+{
+ memfile_T *mfp;
+ linenr_T lnum;
+
+ mfp = buf->b_ml.ml_mfp;
+ if (mfp == NULL || mfp->mf_fd < 0) /* nothing to close */
+ return;
+
+ if (getlines)
+ {
+ /* get all blocks in memory by accessing all lines (clumsy!) */
+ mf_dont_release = TRUE;
+ for (lnum = 1; lnum <= buf->b_ml.ml_line_count; ++lnum)
+ (void)ml_get_buf(buf, lnum, FALSE);
+ mf_dont_release = FALSE;
+ /* TODO: should check if all blocks are really in core */
+ }
+
+ if (close(mfp->mf_fd) < 0) /* close the file */
+ emsg(_(e_swapclose));
+ mfp->mf_fd = -1;
+
+ if (mfp->mf_fname != NULL)
+ {
+ mch_remove(mfp->mf_fname); /* delete the swap file */
+ VIM_CLEAR(mfp->mf_fname);
+ VIM_CLEAR(mfp->mf_ffname);
+ }
+}
+
+/*
+ * Set new size for a memfile. Used when block 0 of a swapfile has been read
+ * and the size it indicates differs from what was guessed.
+ */
+ void
+mf_new_page_size(memfile_T *mfp, unsigned new_size)
+{
+ /* Correct the memory used for block 0 to the new size, because it will be
+ * freed with that size later on. */
+ total_mem_used += new_size - mfp->mf_page_size;
+ mfp->mf_page_size = new_size;
+}
+
+/*
+ * get a new block
+ *
+ * negative: TRUE if negative block number desired (data block)
+ */
+ bhdr_T *
+mf_new(memfile_T *mfp, int negative, int page_count)
+{
+ bhdr_T *hp; /* new bhdr_T */
+ bhdr_T *freep; /* first block in free list */
+ char_u *p;
+
+ /*
+ * If we reached the maximum size for the used memory blocks, release one
+ * If a bhdr_T is returned, use it and adjust the page_count if necessary.
+ */
+ hp = mf_release(mfp, page_count);
+
+/*
+ * Decide on the number to use:
+ * If there is a free block, use its number.
+ * Otherwise use mf_block_min for a negative number, mf_block_max for
+ * a positive number.
+ */
+ freep = mfp->mf_free_first;
+ if (!negative && freep != NULL && freep->bh_page_count >= page_count)
+ {
+ /*
+ * If the block in the free list has more pages, take only the number
+ * of pages needed and allocate a new bhdr_T with data
+ *
+ * If the number of pages matches and mf_release() did not return a
+ * bhdr_T, use the bhdr_T from the free list and allocate the data
+ *
+ * If the number of pages matches and mf_release() returned a bhdr_T,
+ * just use the number and free the bhdr_T from the free list
+ */
+ if (freep->bh_page_count > page_count)
+ {
+ if (hp == NULL && (hp = mf_alloc_bhdr(mfp, page_count)) == NULL)
+ return NULL;
+ hp->bh_bnum = freep->bh_bnum;
+ freep->bh_bnum += page_count;
+ freep->bh_page_count -= page_count;
+ }
+ else if (hp == NULL) /* need to allocate memory for this block */
+ {
+ if ((p = (char_u *)alloc(mfp->mf_page_size * page_count)) == NULL)
+ return NULL;
+ hp = mf_rem_free(mfp);
+ hp->bh_data = p;
+ }
+ else /* use the number, remove entry from free list */
+ {
+ freep = mf_rem_free(mfp);
+ hp->bh_bnum = freep->bh_bnum;
+ vim_free(freep);
+ }
+ }
+ else /* get a new number */
+ {
+ if (hp == NULL && (hp = mf_alloc_bhdr(mfp, page_count)) == NULL)
+ return NULL;
+ if (negative)
+ {
+ hp->bh_bnum = mfp->mf_blocknr_min--;
+ mfp->mf_neg_count++;
+ }
+ else
+ {
+ hp->bh_bnum = mfp->mf_blocknr_max;
+ mfp->mf_blocknr_max += page_count;
+ }
+ }
+ hp->bh_flags = BH_LOCKED | BH_DIRTY; /* new block is always dirty */
+ mfp->mf_dirty = TRUE;
+ hp->bh_page_count = page_count;
+ mf_ins_used(mfp, hp);
+ mf_ins_hash(mfp, hp);
+
+ /*
+ * Init the data to all zero, to avoid reading uninitialized data.
+ * This also avoids that the passwd file ends up in the swap file!
+ */
+ (void)vim_memset((char *)(hp->bh_data), 0,
+ (size_t)mfp->mf_page_size * page_count);
+
+ return hp;
+}
+
+/*
+ * Get existing block "nr" with "page_count" pages.
+ *
+ * Note: The caller should first check a negative nr with mf_trans_del()
+ */
+ bhdr_T *
+mf_get(memfile_T *mfp, blocknr_T nr, int page_count)
+{
+ bhdr_T *hp;
+ /* doesn't exist */
+ if (nr >= mfp->mf_blocknr_max || nr <= mfp->mf_blocknr_min)
+ return NULL;
+
+ /*
+ * see if it is in the cache
+ */
+ hp = mf_find_hash(mfp, nr);
+ if (hp == NULL) /* not in the hash list */
+ {
+ if (nr < 0 || nr >= mfp->mf_infile_count) /* can't be in the file */
+ return NULL;
+
+ /* could check here if the block is in the free list */
+
+ /*
+ * Check if we need to flush an existing block.
+ * If so, use that block.
+ * If not, allocate a new block.
+ */
+ hp = mf_release(mfp, page_count);
+ if (hp == NULL && (hp = mf_alloc_bhdr(mfp, page_count)) == NULL)
+ return NULL;
+
+ hp->bh_bnum = nr;
+ hp->bh_flags = 0;
+ hp->bh_page_count = page_count;
+ if (mf_read(mfp, hp) == FAIL) /* cannot read the block! */
+ {
+ mf_free_bhdr(hp);
+ return NULL;
+ }
+ }
+ else
+ {
+ mf_rem_used(mfp, hp); /* remove from list, insert in front below */
+ mf_rem_hash(mfp, hp);
+ }
+
+ hp->bh_flags |= BH_LOCKED;
+ mf_ins_used(mfp, hp); /* put in front of used list */
+ mf_ins_hash(mfp, hp); /* put in front of hash list */
+
+ return hp;
+}
+
+/*
+ * release the block *hp
+ *
+ * dirty: Block must be written to file later
+ * infile: Block should be in file (needed for recovery)
+ *
+ * no return value, function cannot fail
+ */
+ void
+mf_put(
+ memfile_T *mfp,
+ bhdr_T *hp,
+ int dirty,
+ int infile)
+{
+ int flags;
+
+ flags = hp->bh_flags;
+
+ if ((flags & BH_LOCKED) == 0)
+ iemsg(_("E293: block was not locked"));
+ flags &= ~BH_LOCKED;
+ if (dirty)
+ {
+ flags |= BH_DIRTY;
+ mfp->mf_dirty = TRUE;
+ }
+ hp->bh_flags = flags;
+ if (infile)
+ mf_trans_add(mfp, hp); /* may translate negative in positive nr */
+}
+
+/*
+ * block *hp is no longer in used, may put it in the free list of memfile *mfp
+ */
+ void
+mf_free(memfile_T *mfp, bhdr_T *hp)
+{
+ vim_free(hp->bh_data); /* free the memory */
+ mf_rem_hash(mfp, hp); /* get *hp out of the hash list */
+ mf_rem_used(mfp, hp); /* get *hp out of the used list */
+ if (hp->bh_bnum < 0)
+ {
+ vim_free(hp); /* don't want negative numbers in free list */
+ mfp->mf_neg_count--;
+ }
+ else
+ mf_ins_free(mfp, hp); /* put *hp in the free list */
+}
+
+#if defined(__MORPHOS__) && defined(__libnix__)
+/* function is missing in MorphOS libnix version */
+extern unsigned long *__stdfiledes;
+
+ static unsigned long
+fdtofh(int filedescriptor)
+{
+ return __stdfiledes[filedescriptor];
+}
+#endif
+
+/*
+ * Sync the memory file *mfp to disk.
+ * Flags:
+ * MFS_ALL If not given, blocks with negative numbers are not synced,
+ * even when they are dirty!
+ * MFS_STOP Stop syncing when a character becomes available, but sync at
+ * least one block.
+ * MFS_FLUSH Make sure buffers are flushed to disk, so they will survive a
+ * system crash.
+ * MFS_ZERO Only write block 0.
+ *
+ * Return FAIL for failure, OK otherwise
+ */
+ int
+mf_sync(memfile_T *mfp, int flags)
+{
+ int status;
+ bhdr_T *hp;
+ int got_int_save = got_int;
+
+ if (mfp->mf_fd < 0) /* there is no file, nothing to do */
+ {
+ mfp->mf_dirty = FALSE;
+ return FAIL;
+ }
+
+ /* Only a CTRL-C while writing will break us here, not one typed
+ * previously. */
+ got_int = FALSE;
+
+ /*
+ * sync from last to first (may reduce the probability of an inconsistent
+ * file) If a write fails, it is very likely caused by a full filesystem.
+ * Then we only try to write blocks within the existing file. If that also
+ * fails then we give up.
+ */
+ status = OK;
+ for (hp = mfp->mf_used_last; hp != NULL; hp = hp->bh_prev)
+ if (((flags & MFS_ALL) || hp->bh_bnum >= 0)
+ && (hp->bh_flags & BH_DIRTY)
+ && (status == OK || (hp->bh_bnum >= 0
+ && hp->bh_bnum < mfp->mf_infile_count)))
+ {
+ if ((flags & MFS_ZERO) && hp->bh_bnum != 0)
+ continue;
+ if (mf_write(mfp, hp) == FAIL)
+ {
+ if (status == FAIL) /* double error: quit syncing */
+ break;
+ status = FAIL;
+ }
+ if (flags & MFS_STOP)
+ {
+ /* Stop when char available now. */
+ if (ui_char_avail())
+ break;
+ }
+ else
+ ui_breakcheck();
+ if (got_int)
+ break;
+ }
+
+ /*
+ * If the whole list is flushed, the memfile is not dirty anymore.
+ * In case of an error this flag is also set, to avoid trying all the time.
+ */
+ if (hp == NULL || status == FAIL)
+ mfp->mf_dirty = FALSE;
+
+ if ((flags & MFS_FLUSH) && *p_sws != NUL)
+ {
+#if defined(UNIX)
+# ifdef HAVE_FSYNC
+ /*
+ * most Unixes have the very useful fsync() function, just what we need.
+ */
+ if (STRCMP(p_sws, "fsync") == 0)
+ {
+ if (fsync(mfp->mf_fd))
+ status = FAIL;
+ }
+ else
+# endif
+ /* OpenNT is strictly POSIX (Benzinger) */
+ /* Tandem/Himalaya NSK-OSS doesn't have sync() */
+ /* No sync() on Stratus VOS */
+# if defined(__OPENNT) || defined(__TANDEM) || defined(__VOS__)
+ fflush(NULL);
+# else
+ sync();
+# endif
+#endif
+#ifdef VMS
+ if (STRCMP(p_sws, "fsync") == 0)
+ {
+ if (fsync(mfp->mf_fd))
+ status = FAIL;
+ }
+#endif
+#ifdef WIN32
+ if (_commit(mfp->mf_fd))
+ status = FAIL;
+#endif
+#ifdef AMIGA
+# if defined(__AROS__) || defined(__amigaos4__)
+ if (fsync(mfp->mf_fd) != 0)
+ status = FAIL;
+# else
+ /*
+ * Flush() only exists for AmigaDos 2.0.
+ * For 1.3 it should be done with close() + open(), but then the risk
+ * is that the open() may fail and lose the file....
+ */
+# ifdef FEAT_ARP
+ if (dos2)
+# endif
+# ifdef SASC
+ {
+ struct UFB *fp = chkufb(mfp->mf_fd);
+
+ if (fp != NULL)
+ Flush(fp->ufbfh);
+ }
+# else
+# if defined(_DCC) || defined(__GNUC__) || defined(__MORPHOS__)
+ {
+# if defined(__GNUC__) && !defined(__MORPHOS__) && defined(__libnix__)
+ /* Have function (in libnix at least),
+ * but ain't got no prototype anywhere. */
+ extern unsigned long fdtofh(int filedescriptor);
+# endif
+# if !defined(__libnix__)
+ fflush(NULL);
+# else
+ BPTR fh = (BPTR)fdtofh(mfp->mf_fd);
+
+ if (fh != 0)
+ Flush(fh);
+# endif
+ }
+# else /* assume Manx */
+ Flush(_devtab[mfp->mf_fd].fd);
+# endif
+# endif
+# endif
+#endif /* AMIGA */
+ }
+
+ got_int |= got_int_save;
+
+ return status;
+}
+
+/*
+ * For all blocks in memory file *mfp that have a positive block number set
+ * the dirty flag. These are blocks that need to be written to a newly
+ * created swapfile.
+ */
+ void
+mf_set_dirty(memfile_T *mfp)
+{
+ bhdr_T *hp;
+
+ for (hp = mfp->mf_used_last; hp != NULL; hp = hp->bh_prev)
+ if (hp->bh_bnum > 0)
+ hp->bh_flags |= BH_DIRTY;
+ mfp->mf_dirty = TRUE;
+}
+
+/*
+ * insert block *hp in front of hashlist of memfile *mfp
+ */
+ static void
+mf_ins_hash(memfile_T *mfp, bhdr_T *hp)
+{
+ mf_hash_add_item(&mfp->mf_hash, (mf_hashitem_T *)hp);
+}
+
+/*
+ * remove block *hp from hashlist of memfile list *mfp
+ */
+ static void
+mf_rem_hash(memfile_T *mfp, bhdr_T *hp)
+{
+ mf_hash_rem_item(&mfp->mf_hash, (mf_hashitem_T *)hp);
+}
+
+/*
+ * look in hash lists of memfile *mfp for block header with number 'nr'
+ */
+ static bhdr_T *
+mf_find_hash(memfile_T *mfp, blocknr_T nr)
+{
+ return (bhdr_T *)mf_hash_find(&mfp->mf_hash, nr);
+}
+
+/*
+ * insert block *hp in front of used list of memfile *mfp
+ */
+ static void
+mf_ins_used(memfile_T *mfp, bhdr_T *hp)
+{
+ hp->bh_next = mfp->mf_used_first;
+ mfp->mf_used_first = hp;
+ hp->bh_prev = NULL;
+ if (hp->bh_next == NULL) /* list was empty, adjust last pointer */
+ mfp->mf_used_last = hp;
+ else
+ hp->bh_next->bh_prev = hp;
+ mfp->mf_used_count += hp->bh_page_count;
+ total_mem_used += hp->bh_page_count * mfp->mf_page_size;
+}
+
+/*
+ * remove block *hp from used list of memfile *mfp
+ */
+ static void
+mf_rem_used(memfile_T *mfp, bhdr_T *hp)
+{
+ if (hp->bh_next == NULL) /* last block in used list */
+ mfp->mf_used_last = hp->bh_prev;
+ else
+ hp->bh_next->bh_prev = hp->bh_prev;
+ if (hp->bh_prev == NULL) /* first block in used list */
+ mfp->mf_used_first = hp->bh_next;
+ else
+ hp->bh_prev->bh_next = hp->bh_next;
+ mfp->mf_used_count -= hp->bh_page_count;
+ total_mem_used -= hp->bh_page_count * mfp->mf_page_size;
+}
+
+/*
+ * Release the least recently used block from the used list if the number
+ * of used memory blocks gets to big.
+ *
+ * Return the block header to the caller, including the memory block, so
+ * it can be re-used. Make sure the page_count is right.
+ *
+ * Returns NULL if no block is released.
+ */
+ static bhdr_T *
+mf_release(memfile_T *mfp, int page_count)
+{
+ bhdr_T *hp;
+ int need_release;
+ buf_T *buf;
+
+ /* don't release while in mf_close_file() */
+ if (mf_dont_release)
+ return NULL;
+
+ /*
+ * Need to release a block if the number of blocks for this memfile is
+ * higher than the maximum or total memory used is over 'maxmemtot'
+ */
+ need_release = ((mfp->mf_used_count >= mfp->mf_used_count_max)
+ || (total_mem_used >> 10) >= (long_u)p_mmt);
+
+ /*
+ * Try to create a swap file if the amount of memory used is getting too
+ * high.
+ */
+ if (mfp->mf_fd < 0 && need_release && p_uc)
+ {
+ /* find for which buffer this memfile is */
+ FOR_ALL_BUFFERS(buf)
+ if (buf->b_ml.ml_mfp == mfp)
+ break;
+ if (buf != NULL && buf->b_may_swap)
+ ml_open_file(buf);
+ }
+
+ /*
+ * don't release a block if
+ * there is no file for this memfile
+ * or
+ * the number of blocks for this memfile is lower than the maximum
+ * and
+ * total memory used is not up to 'maxmemtot'
+ */
+ if (mfp->mf_fd < 0 || !need_release)
+ return NULL;
+
+ for (hp = mfp->mf_used_last; hp != NULL; hp = hp->bh_prev)
+ if (!(hp->bh_flags & BH_LOCKED))
+ break;
+ if (hp == NULL) /* not a single one that can be released */
+ return NULL;
+
+ /*
+ * If the block is dirty, write it.
+ * If the write fails we don't free it.
+ */
+ if ((hp->bh_flags & BH_DIRTY) && mf_write(mfp, hp) == FAIL)
+ return NULL;
+
+ mf_rem_used(mfp, hp);
+ mf_rem_hash(mfp, hp);
+
+ /*
+ * If a bhdr_T is returned, make sure that the page_count of bh_data is
+ * right
+ */
+ if (hp->bh_page_count != page_count)
+ {
+ vim_free(hp->bh_data);
+ if ((hp->bh_data = alloc(mfp->mf_page_size * page_count)) == NULL)
+ {
+ vim_free(hp);
+ return NULL;
+ }
+ hp->bh_page_count = page_count;
+ }
+ return hp;
+}
+
+/*
+ * release as many blocks as possible
+ * Used in case of out of memory
+ *
+ * return TRUE if any memory was released
+ */
+ int
+mf_release_all(void)
+{
+ buf_T *buf;
+ memfile_T *mfp;
+ bhdr_T *hp;
+ int retval = FALSE;
+
+ FOR_ALL_BUFFERS(buf)
+ {
+ mfp = buf->b_ml.ml_mfp;
+ if (mfp != NULL)
+ {
+ /* If no swap file yet, may open one */
+ if (mfp->mf_fd < 0 && buf->b_may_swap)
+ ml_open_file(buf);
+
+ /* only if there is a swapfile */
+ if (mfp->mf_fd >= 0)
+ {
+ for (hp = mfp->mf_used_last; hp != NULL; )
+ {
+ if (!(hp->bh_flags & BH_LOCKED)
+ && (!(hp->bh_flags & BH_DIRTY)
+ || mf_write(mfp, hp) != FAIL))
+ {
+ mf_rem_used(mfp, hp);
+ mf_rem_hash(mfp, hp);
+ mf_free_bhdr(hp);
+ hp = mfp->mf_used_last; /* re-start, list was changed */
+ retval = TRUE;
+ }
+ else
+ hp = hp->bh_prev;
+ }
+ }
+ }
+ }
+ return retval;
+}
+
+/*
+ * Allocate a block header and a block of memory for it
+ */
+ static bhdr_T *
+mf_alloc_bhdr(memfile_T *mfp, int page_count)
+{
+ bhdr_T *hp;
+
+ if ((hp = (bhdr_T *)alloc((unsigned)sizeof(bhdr_T))) != NULL)
+ {
+ if ((hp->bh_data = (char_u *)alloc(mfp->mf_page_size * page_count))
+ == NULL)
+ {
+ vim_free(hp); /* not enough memory */
+ return NULL;
+ }
+ hp->bh_page_count = page_count;
+ }
+ return hp;
+}
+
+/*
+ * Free a block header and the block of memory for it
+ */
+ static void
+mf_free_bhdr(bhdr_T *hp)
+{
+ vim_free(hp->bh_data);
+ vim_free(hp);
+}
+
+/*
+ * insert entry *hp in the free list
+ */
+ static void
+mf_ins_free(memfile_T *mfp, bhdr_T *hp)
+{
+ hp->bh_next = mfp->mf_free_first;
+ mfp->mf_free_first = hp;
+}
+
+/*
+ * remove the first entry from the free list and return a pointer to it
+ * Note: caller must check that mfp->mf_free_first is not NULL!
+ */
+ static bhdr_T *
+mf_rem_free(memfile_T *mfp)
+{
+ bhdr_T *hp;
+
+ hp = mfp->mf_free_first;
+ mfp->mf_free_first = hp->bh_next;
+ return hp;
+}
+
+/*
+ * read a block from disk
+ *
+ * Return FAIL for failure, OK otherwise
+ */
+ static int
+mf_read(memfile_T *mfp, bhdr_T *hp)
+{
+ off_T offset;
+ unsigned page_size;
+ unsigned size;
+
+ if (mfp->mf_fd < 0) /* there is no file, can't read */
+ return FAIL;
+
+ page_size = mfp->mf_page_size;
+ offset = (off_T)page_size * hp->bh_bnum;
+ size = page_size * hp->bh_page_count;
+ if (vim_lseek(mfp->mf_fd, offset, SEEK_SET) != offset)
+ {
+ PERROR(_("E294: Seek error in swap file read"));
+ return FAIL;
+ }
+ if ((unsigned)read_eintr(mfp->mf_fd, hp->bh_data, size) != size)
+ {
+ PERROR(_("E295: Read error in swap file"));
+ return FAIL;
+ }
+
+#ifdef FEAT_CRYPT
+ /* Decrypt if 'key' is set and this is a data block. And when changing the
+ * key. */
+ if (*mfp->mf_buffer->b_p_key != NUL || mfp->mf_old_key != NULL)
+ ml_decrypt_data(mfp, hp->bh_data, offset, size);
+#endif
+
+ return OK;
+}
+
+/*
+ * write a block to disk
+ *
+ * Return FAIL for failure, OK otherwise
+ */
+ static int
+mf_write(memfile_T *mfp, bhdr_T *hp)
+{
+ off_T offset; /* offset in the file */
+ blocknr_T nr; /* block nr which is being written */
+ bhdr_T *hp2;
+ unsigned page_size; /* number of bytes in a page */
+ unsigned page_count; /* number of pages written */
+ unsigned size; /* number of bytes written */
+
+ if (mfp->mf_fd < 0) /* there is no file, can't write */
+ return FAIL;
+
+ if (hp->bh_bnum < 0) /* must assign file block number */
+ if (mf_trans_add(mfp, hp) == FAIL)
+ return FAIL;
+
+ page_size = mfp->mf_page_size;
+
+ /*
+ * We don't want gaps in the file. Write the blocks in front of *hp
+ * to extend the file.
+ * If block 'mf_infile_count' is not in the hash list, it has been
+ * freed. Fill the space in the file with data from the current block.
+ */
+ for (;;)
+ {
+ nr = hp->bh_bnum;
+ if (nr > mfp->mf_infile_count) /* beyond end of file */
+ {
+ nr = mfp->mf_infile_count;
+ hp2 = mf_find_hash(mfp, nr); /* NULL caught below */
+ }
+ else
+ hp2 = hp;
+
+ offset = (off_T)page_size * nr;
+ if (vim_lseek(mfp->mf_fd, offset, SEEK_SET) != offset)
+ {
+ PERROR(_("E296: Seek error in swap file write"));
+ return FAIL;
+ }
+ if (hp2 == NULL) /* freed block, fill with dummy data */
+ page_count = 1;
+ else
+ page_count = hp2->bh_page_count;
+ size = page_size * page_count;
+ if (mf_write_block(mfp, hp2 == NULL ? hp : hp2, offset, size) == FAIL)
+ {
+ /*
+ * Avoid repeating the error message, this mostly happens when the
+ * disk is full. We give the message again only after a successful
+ * write or when hitting a key. We keep on trying, in case some
+ * space becomes available.
+ */
+ if (!did_swapwrite_msg)
+ emsg(_("E297: Write error in swap file"));
+ did_swapwrite_msg = TRUE;
+ return FAIL;
+ }
+ did_swapwrite_msg = FALSE;
+ if (hp2 != NULL) /* written a non-dummy block */
+ hp2->bh_flags &= ~BH_DIRTY;
+ /* appended to the file */
+ if (nr + (blocknr_T)page_count > mfp->mf_infile_count)
+ mfp->mf_infile_count = nr + page_count;
+ if (nr == hp->bh_bnum) /* written the desired block */
+ break;
+ }
+ return OK;
+}
+
+/*
+ * Write block "hp" with data size "size" to file "mfp->mf_fd".
+ * Takes care of encryption.
+ * Return FAIL or OK.
+ */
+ static int
+mf_write_block(
+ memfile_T *mfp,
+ bhdr_T *hp,
+ off_T offset UNUSED,
+ unsigned size)
+{
+ char_u *data = hp->bh_data;
+ int result = OK;
+
+#ifdef FEAT_CRYPT
+ /* Encrypt if 'key' is set and this is a data block. */
+ if (*mfp->mf_buffer->b_p_key != NUL)
+ {
+ data = ml_encrypt_data(mfp, data, offset, size);
+ if (data == NULL)
+ return FAIL;
+ }
+#endif
+
+ if ((unsigned)write_eintr(mfp->mf_fd, data, size) != size)
+ result = FAIL;
+
+#ifdef FEAT_CRYPT
+ if (data != hp->bh_data)
+ vim_free(data);
+#endif
+
+ return result;
+}
+
+/*
+ * Make block number for *hp positive and add it to the translation list
+ *
+ * Return FAIL for failure, OK otherwise
+ */
+ static int
+mf_trans_add(memfile_T *mfp, bhdr_T *hp)
+{
+ bhdr_T *freep;
+ blocknr_T new_bnum;
+ NR_TRANS *np;
+ int page_count;
+
+ if (hp->bh_bnum >= 0) /* it's already positive */
+ return OK;
+
+ if ((np = (NR_TRANS *)alloc((unsigned)sizeof(NR_TRANS))) == NULL)
+ return FAIL;
+
+/*
+ * Get a new number for the block.
+ * If the first item in the free list has sufficient pages, use its number
+ * Otherwise use mf_blocknr_max.
+ */
+ freep = mfp->mf_free_first;
+ page_count = hp->bh_page_count;
+ if (freep != NULL && freep->bh_page_count >= page_count)
+ {
+ new_bnum = freep->bh_bnum;
+ /*
+ * If the page count of the free block was larger, reduce it.
+ * If the page count matches, remove the block from the free list
+ */
+ if (freep->bh_page_count > page_count)
+ {
+ freep->bh_bnum += page_count;
+ freep->bh_page_count -= page_count;
+ }
+ else
+ {
+ freep = mf_rem_free(mfp);
+ vim_free(freep);
+ }
+ }
+ else
+ {
+ new_bnum = mfp->mf_blocknr_max;
+ mfp->mf_blocknr_max += page_count;
+ }
+
+ np->nt_old_bnum = hp->bh_bnum; /* adjust number */
+ np->nt_new_bnum = new_bnum;
+
+ mf_rem_hash(mfp, hp); /* remove from old hash list */
+ hp->bh_bnum = new_bnum;
+ mf_ins_hash(mfp, hp); /* insert in new hash list */
+
+ /* Insert "np" into "mf_trans" hashtable with key "np->nt_old_bnum" */
+ mf_hash_add_item(&mfp->mf_trans, (mf_hashitem_T *)np);
+
+ return OK;
+}
+
+/*
+ * Lookup a translation from the trans lists and delete the entry.
+ *
+ * Return the positive new number when found, the old number when not found
+ */
+ blocknr_T
+mf_trans_del(memfile_T *mfp, blocknr_T old_nr)
+{
+ NR_TRANS *np;
+ blocknr_T new_bnum;
+
+ np = (NR_TRANS *)mf_hash_find(&mfp->mf_trans, old_nr);
+
+ if (np == NULL) /* not found */
+ return old_nr;
+
+ mfp->mf_neg_count--;
+ new_bnum = np->nt_new_bnum;
+
+ /* remove entry from the trans list */
+ mf_hash_rem_item(&mfp->mf_trans, (mf_hashitem_T *)np);
+
+ vim_free(np);
+
+ return new_bnum;
+}
+
+/*
+ * Set mfp->mf_ffname according to mfp->mf_fname and some other things.
+ * Only called when creating or renaming the swapfile. Either way it's a new
+ * name so we must work out the full path name.
+ */
+ void
+mf_set_ffname(memfile_T *mfp)
+{
+ mfp->mf_ffname = FullName_save(mfp->mf_fname, FALSE);
+}
+
+/*
+ * Make the name of the file used for the memfile a full path.
+ * Used before doing a :cd
+ */
+ void
+mf_fullname(memfile_T *mfp)
+{
+ if (mfp != NULL && mfp->mf_fname != NULL && mfp->mf_ffname != NULL)
+ {
+ vim_free(mfp->mf_fname);
+ mfp->mf_fname = mfp->mf_ffname;
+ mfp->mf_ffname = NULL;
+ }
+}
+
+/*
+ * return TRUE if there are any translations pending for 'mfp'
+ */
+ int
+mf_need_trans(memfile_T *mfp)
+{
+ return (mfp->mf_fname != NULL && mfp->mf_neg_count > 0);
+}
+
+/*
+ * Open a swap file for a memfile.
+ * The "fname" must be in allocated memory, and is consumed (also when an
+ * error occurs).
+ */
+ static void
+mf_do_open(
+ memfile_T *mfp,
+ char_u *fname,
+ int flags) /* flags for open() */
+{
+#ifdef HAVE_LSTAT
+ stat_T sb;
+#endif
+
+ mfp->mf_fname = fname;
+
+ /*
+ * Get the full path name before the open, because this is
+ * not possible after the open on the Amiga.
+ * fname cannot be NameBuff, because it must have been allocated.
+ */
+ mf_set_ffname(mfp);
+#if defined(MSWIN)
+ /*
+ * A ":!cd e:xxx" may change the directory without us knowing, use the
+ * full pathname always. Careful: This frees fname!
+ */
+ mf_fullname(mfp);
+#endif
+
+#ifdef HAVE_LSTAT
+ /*
+ * Extra security check: When creating a swap file it really shouldn't
+ * exist yet. If there is a symbolic link, this is most likely an attack.
+ */
+ if ((flags & O_CREAT) && mch_lstat((char *)mfp->mf_fname, &sb) >= 0)
+ {
+ mfp->mf_fd = -1;
+ emsg(_("E300: Swap file already exists (symlink attack?)"));
+ }
+ else
+#endif
+ {
+ /*
+ * try to open the file
+ */
+ flags |= O_EXTRA | O_NOFOLLOW;
+#ifdef WIN32
+ /* Prevent handle inheritance that cause problems with Cscope
+ * (swap file may not be deleted if cscope connection was open after
+ * the file) */
+ flags |= O_NOINHERIT;
+#endif
+ mfp->mf_fd = mch_open_rw((char *)mfp->mf_fname, flags);
+ }
+
+ /*
+ * If the file cannot be opened, use memory only
+ */
+ if (mfp->mf_fd < 0)
+ {
+ VIM_CLEAR(mfp->mf_fname);
+ VIM_CLEAR(mfp->mf_ffname);
+ }
+ else
+ {
+#ifdef HAVE_FD_CLOEXEC
+ int fdflags = fcntl(mfp->mf_fd, F_GETFD);
+ if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
+ (void)fcntl(mfp->mf_fd, F_SETFD, fdflags | FD_CLOEXEC);
+#endif
+#if defined(HAVE_SELINUX) || defined(HAVE_SMACK)
+ mch_copy_sec(fname, mfp->mf_fname);
+#endif
+ mch_hide(mfp->mf_fname); /* try setting the 'hidden' flag */
+ }
+}
+
+/*
+ * Implementation of mf_hashtab_T follows.
+ */
+
+/*
+ * The number of buckets in the hashtable is increased by a factor of
+ * MHT_GROWTH_FACTOR when the average number of items per bucket
+ * exceeds 2 ^ MHT_LOG_LOAD_FACTOR.
+ */
+#define MHT_LOG_LOAD_FACTOR 6
+#define MHT_GROWTH_FACTOR 2 /* must be a power of two */
+
+/*
+ * Initialize an empty hash table.
+ */
+ static void
+mf_hash_init(mf_hashtab_T *mht)
+{
+ vim_memset(mht, 0, sizeof(mf_hashtab_T));
+ mht->mht_buckets = mht->mht_small_buckets;
+ mht->mht_mask = MHT_INIT_SIZE - 1;
+}
+
+/*
+ * Free the array of a hash table. Does not free the items it contains!
+ * The hash table must not be used again without another mf_hash_init() call.
+ */
+ static void
+mf_hash_free(mf_hashtab_T *mht)
+{
+ if (mht->mht_buckets != mht->mht_small_buckets)
+ vim_free(mht->mht_buckets);
+}
+
+/*
+ * Free the array of a hash table and all the items it contains.
+ */
+ static void
+mf_hash_free_all(mf_hashtab_T *mht)
+{
+ long_u idx;
+ mf_hashitem_T *mhi;
+ mf_hashitem_T *next;
+
+ for (idx = 0; idx <= mht->mht_mask; idx++)
+ for (mhi = mht->mht_buckets[idx]; mhi != NULL; mhi = next)
+ {
+ next = mhi->mhi_next;
+ vim_free(mhi);
+ }
+
+ mf_hash_free(mht);
+}
+
+/*
+ * Find "key" in hashtable "mht".
+ * Returns a pointer to a mf_hashitem_T or NULL if the item was not found.
+ */
+ static mf_hashitem_T *
+mf_hash_find(mf_hashtab_T *mht, blocknr_T key)
+{
+ mf_hashitem_T *mhi;
+
+ mhi = mht->mht_buckets[key & mht->mht_mask];
+ while (mhi != NULL && mhi->mhi_key != key)
+ mhi = mhi->mhi_next;
+
+ return mhi;
+}
+
+/*
+ * Add item "mhi" to hashtable "mht".
+ * "mhi" must not be NULL.
+ */
+ static void
+mf_hash_add_item(mf_hashtab_T *mht, mf_hashitem_T *mhi)
+{
+ long_u idx;
+
+ idx = mhi->mhi_key & mht->mht_mask;
+ mhi->mhi_next = mht->mht_buckets[idx];
+ mhi->mhi_prev = NULL;
+ if (mhi->mhi_next != NULL)
+ mhi->mhi_next->mhi_prev = mhi;
+ mht->mht_buckets[idx] = mhi;
+
+ mht->mht_count++;
+
+ /*
+ * Grow hashtable when we have more thank 2^MHT_LOG_LOAD_FACTOR
+ * items per bucket on average
+ */
+ if (mht->mht_fixed == 0
+ && (mht->mht_count >> MHT_LOG_LOAD_FACTOR) > mht->mht_mask)
+ {
+ if (mf_hash_grow(mht) == FAIL)
+ {
+ /* stop trying to grow after first failure to allocate memory */
+ mht->mht_fixed = 1;
+ }
+ }
+}
+
+/*
+ * Remove item "mhi" from hashtable "mht".
+ * "mhi" must not be NULL and must have been inserted into "mht".
+ */
+ static void
+mf_hash_rem_item(mf_hashtab_T *mht, mf_hashitem_T *mhi)
+{
+ if (mhi->mhi_prev == NULL)
+ mht->mht_buckets[mhi->mhi_key & mht->mht_mask] = mhi->mhi_next;
+ else
+ mhi->mhi_prev->mhi_next = mhi->mhi_next;
+
+ if (mhi->mhi_next != NULL)
+ mhi->mhi_next->mhi_prev = mhi->mhi_prev;
+
+ mht->mht_count--;
+
+ /* We could shrink the table here, but it typically takes little memory,
+ * so why bother? */
+}
+
+/*
+ * Increase number of buckets in the hashtable by MHT_GROWTH_FACTOR and
+ * rehash items.
+ * Returns FAIL when out of memory.
+ */
+ static int
+mf_hash_grow(mf_hashtab_T *mht)
+{
+ long_u i, j;
+ int shift;
+ mf_hashitem_T *mhi;
+ mf_hashitem_T *tails[MHT_GROWTH_FACTOR];
+ mf_hashitem_T **buckets;
+ size_t size;
+
+ size = (mht->mht_mask + 1) * MHT_GROWTH_FACTOR * sizeof(void *);
+ buckets = (mf_hashitem_T **)lalloc_clear(size, FALSE);
+ if (buckets == NULL)
+ return FAIL;
+
+ shift = 0;
+ while ((mht->mht_mask >> shift) != 0)
+ shift++;
+
+ for (i = 0; i <= mht->mht_mask; i++)
+ {
+ /*
+ * Traverse the items in the i-th original bucket and move them into
+ * MHT_GROWTH_FACTOR new buckets, preserving their relative order
+ * within each new bucket. Preserving the order is important because
+ * mf_get() tries to keep most recently used items at the front of
+ * each bucket.
+ *
+ * Here we strongly rely on the fact the hashes are computed modulo
+ * a power of two.
+ */
+
+ vim_memset(tails, 0, sizeof(tails));
+
+ for (mhi = mht->mht_buckets[i]; mhi != NULL; mhi = mhi->mhi_next)
+ {
+ j = (mhi->mhi_key >> shift) & (MHT_GROWTH_FACTOR - 1);
+ if (tails[j] == NULL)
+ {
+ buckets[i + (j << shift)] = mhi;
+ tails[j] = mhi;
+ mhi->mhi_prev = NULL;
+ }
+ else
+ {
+ tails[j]->mhi_next = mhi;
+ mhi->mhi_prev = tails[j];
+ tails[j] = mhi;
+ }
+ }
+
+ for (j = 0; j < MHT_GROWTH_FACTOR; j++)
+ if (tails[j] != NULL)
+ tails[j]->mhi_next = NULL;
+ }
+
+ if (mht->mht_buckets != mht->mht_small_buckets)
+ vim_free(mht->mht_buckets);
+
+ mht->mht_buckets = buckets;
+ mht->mht_mask = (mht->mht_mask + 1) * MHT_GROWTH_FACTOR - 1;
+
+ return OK;
+}
diff --git a/src/memfile_test.c b/src/memfile_test.c
new file mode 100644
index 0000000..0fa1e14
--- /dev/null
+++ b/src/memfile_test.c
@@ -0,0 +1,143 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * memfile_test.c: Unittests for memfile.c
+ * Mostly by Ivan Krasilnikov.
+ */
+
+#undef NDEBUG
+#include <assert.h>
+
+/* Must include main.c because it contains much more than just main() */
+#define NO_VIM_MAIN
+#include "main.c"
+
+/* This file has to be included because the tested functions are static */
+#include "memfile.c"
+
+#define index_to_key(i) ((i) ^ 15167)
+#define TEST_COUNT 50000
+
+/*
+ * Test mf_hash_*() functions.
+ */
+ static void
+test_mf_hash(void)
+{
+ mf_hashtab_T ht;
+ mf_hashitem_T *item;
+ blocknr_T key;
+ long_u i;
+ long_u num_buckets;
+
+ mf_hash_init(&ht);
+
+ /* insert some items and check invariants */
+ for (i = 0; i < TEST_COUNT; i++)
+ {
+ assert(ht.mht_count == i);
+
+ /* check that number of buckets is a power of 2 */
+ num_buckets = ht.mht_mask + 1;
+ assert(num_buckets > 0 && (num_buckets & (num_buckets - 1)) == 0);
+
+ /* check load factor */
+ assert(ht.mht_count <= (num_buckets << MHT_LOG_LOAD_FACTOR));
+
+ if (i < (MHT_INIT_SIZE << MHT_LOG_LOAD_FACTOR))
+ {
+ /* first expansion shouldn't have occurred yet */
+ assert(num_buckets == MHT_INIT_SIZE);
+ assert(ht.mht_buckets == ht.mht_small_buckets);
+ }
+ else
+ {
+ assert(num_buckets > MHT_INIT_SIZE);
+ assert(ht.mht_buckets != ht.mht_small_buckets);
+ }
+
+ key = index_to_key(i);
+ assert(mf_hash_find(&ht, key) == NULL);
+
+ /* allocate and add new item */
+ item = (mf_hashitem_T *)lalloc_clear(sizeof(mf_hashtab_T), FALSE);
+ assert(item != NULL);
+ item->mhi_key = key;
+ mf_hash_add_item(&ht, item);
+
+ assert(mf_hash_find(&ht, key) == item);
+
+ if (ht.mht_mask + 1 != num_buckets)
+ {
+ /* hash table was expanded */
+ assert(ht.mht_mask + 1 == num_buckets * MHT_GROWTH_FACTOR);
+ assert(i + 1 == (num_buckets << MHT_LOG_LOAD_FACTOR));
+ }
+ }
+
+ /* check presence of inserted items */
+ for (i = 0; i < TEST_COUNT; i++)
+ {
+ key = index_to_key(i);
+ item = mf_hash_find(&ht, key);
+ assert(item != NULL);
+ assert(item->mhi_key == key);
+ }
+
+ /* delete some items */
+ for (i = 0; i < TEST_COUNT; i++)
+ {
+ if (i % 100 < 70)
+ {
+ key = index_to_key(i);
+ item = mf_hash_find(&ht, key);
+ assert(item != NULL);
+ assert(item->mhi_key == key);
+
+ mf_hash_rem_item(&ht, item);
+ assert(mf_hash_find(&ht, key) == NULL);
+
+ mf_hash_add_item(&ht, item);
+ assert(mf_hash_find(&ht, key) == item);
+
+ mf_hash_rem_item(&ht, item);
+ assert(mf_hash_find(&ht, key) == NULL);
+
+ vim_free(item);
+ }
+ }
+
+ /* check again */
+ for (i = 0; i < TEST_COUNT; i++)
+ {
+ key = index_to_key(i);
+ item = mf_hash_find(&ht, key);
+
+ if (i % 100 < 70)
+ {
+ assert(item == NULL);
+ }
+ else
+ {
+ assert(item != NULL);
+ assert(item->mhi_key == key);
+ }
+ }
+
+ /* free hash table and all remaining items */
+ mf_hash_free_all(&ht);
+}
+
+ int
+main(void)
+{
+ test_mf_hash();
+ return 0;
+}
diff --git a/src/memline.c b/src/memline.c
new file mode 100644
index 0000000..c62ea5f
--- /dev/null
+++ b/src/memline.c
@@ -0,0 +1,5679 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/* for debugging */
+/* #define CHECK(c, s) do { if (c) emsg((s)); } while (0) */
+#define CHECK(c, s) do { /**/ } while (0)
+
+/*
+ * memline.c: Contains the functions for appending, deleting and changing the
+ * text lines. The memfile functions are used to store the information in
+ * blocks of memory, backed up by a file. The structure of the information is
+ * a tree. The root of the tree is a pointer block. The leaves of the tree
+ * are data blocks. In between may be several layers of pointer blocks,
+ * forming branches.
+ *
+ * Three types of blocks are used:
+ * - Block nr 0 contains information for recovery
+ * - Pointer blocks contain list of pointers to other blocks.
+ * - Data blocks contain the actual text.
+ *
+ * Block nr 0 contains the block0 structure (see below).
+ *
+ * Block nr 1 is the first pointer block. It is the root of the tree.
+ * Other pointer blocks are branches.
+ *
+ * If a line is too big to fit in a single page, the block containing that
+ * line is made big enough to hold the line. It may span several pages.
+ * Otherwise all blocks are one page.
+ *
+ * A data block that was filled when starting to edit a file and was not
+ * changed since then, can have a negative block number. This means that it
+ * has not yet been assigned a place in the file. When recovering, the lines
+ * in this data block can be read from the original file. When the block is
+ * changed (lines appended/deleted/changed) or when it is flushed it gets a
+ * positive number. Use mf_trans_del() to get the new number, before calling
+ * mf_get().
+ */
+
+#include "vim.h"
+
+#ifndef UNIX /* it's in os_unix.h for Unix */
+# include <time.h>
+#endif
+
+#if defined(SASC) || defined(__amigaos4__)
+# include <proto/dos.h> /* for Open() and Close() */
+#endif
+
+typedef struct block0 ZERO_BL; /* contents of the first block */
+typedef struct pointer_block PTR_BL; /* contents of a pointer block */
+typedef struct data_block DATA_BL; /* contents of a data block */
+typedef struct pointer_entry PTR_EN; /* block/line-count pair */
+
+#define DATA_ID (('d' << 8) + 'a') /* data block id */
+#define PTR_ID (('p' << 8) + 't') /* pointer block id */
+#define BLOCK0_ID0 'b' /* block 0 id 0 */
+#define BLOCK0_ID1 '0' /* block 0 id 1 */
+#define BLOCK0_ID1_C0 'c' /* block 0 id 1 'cm' 0 */
+#define BLOCK0_ID1_C1 'C' /* block 0 id 1 'cm' 1 */
+#define BLOCK0_ID1_C2 'd' /* block 0 id 1 'cm' 2 */
+
+#if defined(FEAT_CRYPT)
+static int id1_codes[] = {
+ BLOCK0_ID1_C0, /* CRYPT_M_ZIP */
+ BLOCK0_ID1_C1, /* CRYPT_M_BF */
+ BLOCK0_ID1_C2, /* CRYPT_M_BF2 */
+};
+#endif
+
+/*
+ * pointer to a block, used in a pointer block
+ */
+struct pointer_entry
+{
+ blocknr_T pe_bnum; /* block number */
+ linenr_T pe_line_count; /* number of lines in this branch */
+ linenr_T pe_old_lnum; /* lnum for this block (for recovery) */
+ int pe_page_count; /* number of pages in block pe_bnum */
+};
+
+/*
+ * A pointer block contains a list of branches in the tree.
+ */
+struct pointer_block
+{
+ short_u pb_id; /* ID for pointer block: PTR_ID */
+ short_u pb_count; /* number of pointers in this block */
+ short_u pb_count_max; /* maximum value for pb_count */
+ PTR_EN pb_pointer[1]; /* list of pointers to blocks (actually longer)
+ * followed by empty space until end of page */
+};
+
+/*
+ * A data block is a leaf in the tree.
+ *
+ * The text of the lines is at the end of the block. The text of the first line
+ * in the block is put at the end, the text of the second line in front of it,
+ * etc. Thus the order of the lines is the opposite of the line number.
+ */
+struct data_block
+{
+ short_u db_id; /* ID for data block: DATA_ID */
+ unsigned db_free; /* free space available */
+ unsigned db_txt_start; /* byte where text starts */
+ unsigned db_txt_end; /* byte just after data block */
+ linenr_T db_line_count; /* number of lines in this block */
+ unsigned db_index[1]; /* index for start of line (actually bigger)
+ * followed by empty space upto db_txt_start
+ * followed by the text in the lines until
+ * end of page */
+};
+
+/*
+ * The low bits of db_index hold the actual index. The topmost bit is
+ * used for the global command to be able to mark a line.
+ * This method is not clean, but otherwise there would be at least one extra
+ * byte used for each line.
+ * The mark has to be in this place to keep it with the correct line when other
+ * lines are inserted or deleted.
+ */
+#define DB_MARKED ((unsigned)1 << ((sizeof(unsigned) * 8) - 1))
+#define DB_INDEX_MASK (~DB_MARKED)
+
+#define INDEX_SIZE (sizeof(unsigned)) /* size of one db_index entry */
+#define HEADER_SIZE (sizeof(DATA_BL) - INDEX_SIZE) /* size of data block header */
+
+#define B0_FNAME_SIZE_ORG 900 /* what it was in older versions */
+#define B0_FNAME_SIZE_NOCRYPT 898 /* 2 bytes used for other things */
+#define B0_FNAME_SIZE_CRYPT 890 /* 10 bytes used for other things */
+#define B0_UNAME_SIZE 40
+#define B0_HNAME_SIZE 40
+/*
+ * Restrict the numbers to 32 bits, otherwise most compilers will complain.
+ * This won't detect a 64 bit machine that only swaps a byte in the top 32
+ * bits, but that is crazy anyway.
+ */
+#define B0_MAGIC_LONG 0x30313233L
+#define B0_MAGIC_INT 0x20212223L
+#define B0_MAGIC_SHORT 0x10111213L
+#define B0_MAGIC_CHAR 0x55
+
+/*
+ * Block zero holds all info about the swap file.
+ *
+ * NOTE: DEFINITION OF BLOCK 0 SHOULD NOT CHANGE! It would make all existing
+ * swap files unusable!
+ *
+ * If size of block0 changes anyway, adjust MIN_SWAP_PAGE_SIZE in vim.h!!
+ *
+ * This block is built up of single bytes, to make it portable across
+ * different machines. b0_magic_* is used to check the byte order and size of
+ * variables, because the rest of the swap file is not portable.
+ */
+struct block0
+{
+ char_u b0_id[2]; /* id for block 0: BLOCK0_ID0 and BLOCK0_ID1,
+ * BLOCK0_ID1_C0, BLOCK0_ID1_C1, etc. */
+ char_u b0_version[10]; /* Vim version string */
+ char_u b0_page_size[4];/* number of bytes per page */
+ char_u b0_mtime[4]; /* last modification time of file */
+ char_u b0_ino[4]; /* inode of b0_fname */
+ char_u b0_pid[4]; /* process id of creator (or 0) */
+ char_u b0_uname[B0_UNAME_SIZE]; /* name of user (uid if no name) */
+ char_u b0_hname[B0_HNAME_SIZE]; /* host name (if it has a name) */
+ char_u b0_fname[B0_FNAME_SIZE_ORG]; /* name of file being edited */
+ long b0_magic_long; /* check for byte order of long */
+ int b0_magic_int; /* check for byte order of int */
+ short b0_magic_short; /* check for byte order of short */
+ char_u b0_magic_char; /* check for last char */
+};
+
+/*
+ * Note: b0_dirty and b0_flags are put at the end of the file name. For very
+ * long file names in older versions of Vim they are invalid.
+ * The 'fileencoding' comes before b0_flags, with a NUL in front. But only
+ * when there is room, for very long file names it's omitted.
+ */
+#define B0_DIRTY 0x55
+#define b0_dirty b0_fname[B0_FNAME_SIZE_ORG - 1]
+
+/*
+ * The b0_flags field is new in Vim 7.0.
+ */
+#define b0_flags b0_fname[B0_FNAME_SIZE_ORG - 2]
+
+/*
+ * Crypt seed goes here, 8 bytes. New in Vim 7.3.
+ * Without encryption these bytes may be used for 'fenc'.
+ */
+#define b0_seed b0_fname[B0_FNAME_SIZE_ORG - 2 - MF_SEED_LEN]
+
+/* The lowest two bits contain the fileformat. Zero means it's not set
+ * (compatible with Vim 6.x), otherwise it's EOL_UNIX + 1, EOL_DOS + 1 or
+ * EOL_MAC + 1. */
+#define B0_FF_MASK 3
+
+/* Swap file is in directory of edited file. Used to find the file from
+ * different mount points. */
+#define B0_SAME_DIR 4
+
+/* The 'fileencoding' is at the end of b0_fname[], with a NUL in front of it.
+ * When empty there is only the NUL. */
+#define B0_HAS_FENC 8
+
+#define STACK_INCR 5 /* nr of entries added to ml_stack at a time */
+
+/*
+ * The line number where the first mark may be is remembered.
+ * If it is 0 there are no marks at all.
+ * (always used for the current buffer only, no buffer change possible while
+ * executing a global command).
+ */
+static linenr_T lowest_marked = 0;
+
+/*
+ * arguments for ml_find_line()
+ */
+#define ML_DELETE 0x11 /* delete line */
+#define ML_INSERT 0x12 /* insert line */
+#define ML_FIND 0x13 /* just find the line */
+#define ML_FLUSH 0x02 /* flush locked block */
+#define ML_SIMPLE(x) (x & 0x10) /* DEL, INS or FIND */
+
+/* argument for ml_upd_block0() */
+typedef enum {
+ UB_FNAME = 0 /* update timestamp and filename */
+ , UB_SAME_DIR /* update the B0_SAME_DIR flag */
+ , UB_CRYPT /* update crypt key */
+} upd_block0_T;
+
+#ifdef FEAT_CRYPT
+static void ml_set_b0_crypt(buf_T *buf, ZERO_BL *b0p);
+#endif
+static void ml_upd_block0(buf_T *buf, upd_block0_T what);
+static void set_b0_fname(ZERO_BL *, buf_T *buf);
+static void set_b0_dir_flag(ZERO_BL *b0p, buf_T *buf);
+static void add_b0_fenc(ZERO_BL *b0p, buf_T *buf);
+static time_t swapfile_info(char_u *);
+static int recov_file_names(char_u **, char_u *, int prepend_dot);
+static int ml_append_int(buf_T *, linenr_T, char_u *, colnr_T, int, int);
+static int ml_delete_int(buf_T *, linenr_T, int);
+static char_u *findswapname(buf_T *, char_u **, char_u *);
+static void ml_flush_line(buf_T *);
+static bhdr_T *ml_new_data(memfile_T *, int, int);
+static bhdr_T *ml_new_ptr(memfile_T *);
+static bhdr_T *ml_find_line(buf_T *, linenr_T, int);
+static int ml_add_stack(buf_T *);
+static void ml_lineadd(buf_T *, int);
+static int b0_magic_wrong(ZERO_BL *);
+#ifdef CHECK_INODE
+static int fnamecmp_ino(char_u *, char_u *, long);
+#endif
+static void long_to_char(long, char_u *);
+static long char_to_long(char_u *);
+#ifdef FEAT_CRYPT
+static cryptstate_T *ml_crypt_prepare(memfile_T *mfp, off_T offset, int reading);
+#endif
+#ifdef FEAT_BYTEOFF
+static void ml_updatechunk(buf_T *buf, long line, long len, int updtype);
+#endif
+
+/*
+ * Open a new memline for "buf".
+ *
+ * Return FAIL for failure, OK otherwise.
+ */
+ int
+ml_open(buf_T *buf)
+{
+ memfile_T *mfp;
+ bhdr_T *hp = NULL;
+ ZERO_BL *b0p;
+ PTR_BL *pp;
+ DATA_BL *dp;
+
+ /*
+ * init fields in memline struct
+ */
+ buf->b_ml.ml_stack_size = 0; /* no stack yet */
+ buf->b_ml.ml_stack = NULL; /* no stack yet */
+ buf->b_ml.ml_stack_top = 0; /* nothing in the stack */
+ buf->b_ml.ml_locked = NULL; /* no cached block */
+ buf->b_ml.ml_line_lnum = 0; /* no cached line */
+#ifdef FEAT_BYTEOFF
+ buf->b_ml.ml_chunksize = NULL;
+#endif
+
+ if (cmdmod.noswapfile)
+ buf->b_p_swf = FALSE;
+
+ /*
+ * When 'updatecount' is non-zero swap file may be opened later.
+ */
+ if (p_uc && buf->b_p_swf)
+ buf->b_may_swap = TRUE;
+ else
+ buf->b_may_swap = FALSE;
+
+ /*
+ * Open the memfile. No swap file is created yet.
+ */
+ mfp = mf_open(NULL, 0);
+ if (mfp == NULL)
+ goto error;
+
+ buf->b_ml.ml_mfp = mfp;
+#ifdef FEAT_CRYPT
+ mfp->mf_buffer = buf;
+#endif
+ buf->b_ml.ml_flags = ML_EMPTY;
+ buf->b_ml.ml_line_count = 1;
+#ifdef FEAT_LINEBREAK
+ curwin->w_nrwidth_line_count = 0;
+#endif
+
+/*
+ * fill block0 struct and write page 0
+ */
+ if ((hp = mf_new(mfp, FALSE, 1)) == NULL)
+ goto error;
+ if (hp->bh_bnum != 0)
+ {
+ iemsg(_("E298: Didn't get block nr 0?"));
+ goto error;
+ }
+ b0p = (ZERO_BL *)(hp->bh_data);
+
+ b0p->b0_id[0] = BLOCK0_ID0;
+ b0p->b0_id[1] = BLOCK0_ID1;
+ b0p->b0_magic_long = (long)B0_MAGIC_LONG;
+ b0p->b0_magic_int = (int)B0_MAGIC_INT;
+ b0p->b0_magic_short = (short)B0_MAGIC_SHORT;
+ b0p->b0_magic_char = B0_MAGIC_CHAR;
+ mch_memmove(b0p->b0_version, "VIM ", 4);
+ STRNCPY(b0p->b0_version + 4, Version, 6);
+ long_to_char((long)mfp->mf_page_size, b0p->b0_page_size);
+
+#ifdef FEAT_SPELL
+ if (!buf->b_spell)
+#endif
+ {
+ b0p->b0_dirty = buf->b_changed ? B0_DIRTY : 0;
+ b0p->b0_flags = get_fileformat(buf) + 1;
+ set_b0_fname(b0p, buf);
+ (void)get_user_name(b0p->b0_uname, B0_UNAME_SIZE);
+ b0p->b0_uname[B0_UNAME_SIZE - 1] = NUL;
+ mch_get_host_name(b0p->b0_hname, B0_HNAME_SIZE);
+ b0p->b0_hname[B0_HNAME_SIZE - 1] = NUL;
+ long_to_char(mch_get_pid(), b0p->b0_pid);
+#ifdef FEAT_CRYPT
+ ml_set_b0_crypt(buf, b0p);
+#endif
+ }
+
+ /*
+ * Always sync block number 0 to disk, so we can check the file name in
+ * the swap file in findswapname(). Don't do this for a help files or
+ * a spell buffer though.
+ * Only works when there's a swapfile, otherwise it's done when the file
+ * is created.
+ */
+ mf_put(mfp, hp, TRUE, FALSE);
+ if (!buf->b_help && !B_SPELL(buf))
+ (void)mf_sync(mfp, 0);
+
+ /*
+ * Fill in root pointer block and write page 1.
+ */
+ if ((hp = ml_new_ptr(mfp)) == NULL)
+ goto error;
+ if (hp->bh_bnum != 1)
+ {
+ iemsg(_("E298: Didn't get block nr 1?"));
+ goto error;
+ }
+ pp = (PTR_BL *)(hp->bh_data);
+ pp->pb_count = 1;
+ pp->pb_pointer[0].pe_bnum = 2;
+ pp->pb_pointer[0].pe_page_count = 1;
+ pp->pb_pointer[0].pe_old_lnum = 1;
+ pp->pb_pointer[0].pe_line_count = 1; /* line count after insertion */
+ mf_put(mfp, hp, TRUE, FALSE);
+
+ /*
+ * Allocate first data block and create an empty line 1.
+ */
+ if ((hp = ml_new_data(mfp, FALSE, 1)) == NULL)
+ goto error;
+ if (hp->bh_bnum != 2)
+ {
+ iemsg(_("E298: Didn't get block nr 2?"));
+ goto error;
+ }
+
+ dp = (DATA_BL *)(hp->bh_data);
+ dp->db_index[0] = --dp->db_txt_start; /* at end of block */
+ dp->db_free -= 1 + INDEX_SIZE;
+ dp->db_line_count = 1;
+ *((char_u *)dp + dp->db_txt_start) = NUL; /* empty line */
+
+ return OK;
+
+error:
+ if (mfp != NULL)
+ {
+ if (hp)
+ mf_put(mfp, hp, FALSE, FALSE);
+ mf_close(mfp, TRUE); /* will also free(mfp->mf_fname) */
+ }
+ buf->b_ml.ml_mfp = NULL;
+ return FAIL;
+}
+
+#if defined(FEAT_CRYPT) || defined(PROTO)
+/*
+ * Prepare encryption for "buf" for the current key and method.
+ */
+ static void
+ml_set_mfp_crypt(buf_T *buf)
+{
+ if (*buf->b_p_key != NUL)
+ {
+ int method_nr = crypt_get_method_nr(buf);
+
+ if (method_nr > CRYPT_M_ZIP)
+ {
+ /* Generate a seed and store it in the memfile. */
+ sha2_seed(buf->b_ml.ml_mfp->mf_seed, MF_SEED_LEN, NULL, 0);
+ }
+ }
+}
+
+/*
+ * Prepare encryption for "buf" with block 0 "b0p".
+ */
+ static void
+ml_set_b0_crypt(buf_T *buf, ZERO_BL *b0p)
+{
+ if (*buf->b_p_key == NUL)
+ b0p->b0_id[1] = BLOCK0_ID1;
+ else
+ {
+ int method_nr = crypt_get_method_nr(buf);
+
+ b0p->b0_id[1] = id1_codes[method_nr];
+ if (method_nr > CRYPT_M_ZIP)
+ {
+ /* Generate a seed and store it in block 0 and in the memfile. */
+ sha2_seed(&b0p->b0_seed, MF_SEED_LEN, NULL, 0);
+ mch_memmove(buf->b_ml.ml_mfp->mf_seed, &b0p->b0_seed, MF_SEED_LEN);
+ }
+ }
+}
+
+/*
+ * Called after the crypt key or 'cryptmethod' was changed for "buf".
+ * Will apply this to the swapfile.
+ * "old_key" is the previous key. It is equal to buf->b_p_key when
+ * 'cryptmethod' is changed.
+ * "old_cm" is the previous 'cryptmethod'. It is equal to the current
+ * 'cryptmethod' when 'key' is changed.
+ */
+ void
+ml_set_crypt_key(
+ buf_T *buf,
+ char_u *old_key,
+ char_u *old_cm)
+{
+ memfile_T *mfp = buf->b_ml.ml_mfp;
+ bhdr_T *hp;
+ int page_count;
+ int idx;
+ long error;
+ infoptr_T *ip;
+ PTR_BL *pp;
+ DATA_BL *dp;
+ blocknr_T bnum;
+ int top;
+ int old_method;
+
+ if (mfp == NULL)
+ return; /* no memfile yet, nothing to do */
+ old_method = crypt_method_nr_from_name(old_cm);
+
+ /* First make sure the swapfile is in a consistent state, using the old
+ * key and method. */
+ {
+ char_u *new_key = buf->b_p_key;
+ char_u *new_buf_cm = buf->b_p_cm;
+
+ buf->b_p_key = old_key;
+ buf->b_p_cm = old_cm;
+ ml_preserve(buf, FALSE);
+ buf->b_p_key = new_key;
+ buf->b_p_cm = new_buf_cm;
+ }
+
+ /* Set the key, method and seed to be used for reading, these must be the
+ * old values. */
+ mfp->mf_old_key = old_key;
+ mfp->mf_old_cm = old_method;
+ if (old_method > 0 && *old_key != NUL)
+ mch_memmove(mfp->mf_old_seed, mfp->mf_seed, MF_SEED_LEN);
+
+ /* Update block 0 with the crypt flag and may set a new seed. */
+ ml_upd_block0(buf, UB_CRYPT);
+
+ if (mfp->mf_infile_count > 2)
+ {
+ /*
+ * Need to read back all data blocks from disk, decrypt them with the
+ * old key/method and mark them to be written. The algorithm is
+ * similar to what happens in ml_recover(), but we skip negative block
+ * numbers.
+ */
+ ml_flush_line(buf); /* flush buffered line */
+ (void)ml_find_line(buf, (linenr_T)0, ML_FLUSH); /* flush locked block */
+
+ hp = NULL;
+ bnum = 1; /* start with block 1 */
+ page_count = 1; /* which is 1 page */
+ idx = 0; /* start with first index in block 1 */
+ error = 0;
+ buf->b_ml.ml_stack_top = 0;
+ VIM_CLEAR(buf->b_ml.ml_stack);
+ buf->b_ml.ml_stack_size = 0; /* no stack yet */
+
+ for ( ; !got_int; line_breakcheck())
+ {
+ if (hp != NULL)
+ mf_put(mfp, hp, FALSE, FALSE); /* release previous block */
+
+ /* get the block (pointer or data) */
+ if ((hp = mf_get(mfp, (blocknr_T)bnum, page_count)) == NULL)
+ {
+ if (bnum == 1)
+ break;
+ ++error;
+ }
+ else
+ {
+ pp = (PTR_BL *)(hp->bh_data);
+ if (pp->pb_id == PTR_ID) /* it is a pointer block */
+ {
+ if (pp->pb_count == 0)
+ {
+ /* empty block? */
+ ++error;
+ }
+ else if (idx < (int)pp->pb_count) /* go a block deeper */
+ {
+ if (pp->pb_pointer[idx].pe_bnum < 0)
+ {
+ /* Skip data block with negative block number.
+ * Should not happen, because of the ml_preserve()
+ * above. Get same block again for next index. */
+ ++idx;
+ continue;
+ }
+
+ /* going one block deeper in the tree, new entry in
+ * stack */
+ if ((top = ml_add_stack(buf)) < 0)
+ {
+ ++error;
+ break; /* out of memory */
+ }
+ ip = &(buf->b_ml.ml_stack[top]);
+ ip->ip_bnum = bnum;
+ ip->ip_index = idx;
+
+ bnum = pp->pb_pointer[idx].pe_bnum;
+ page_count = pp->pb_pointer[idx].pe_page_count;
+ idx = 0;
+ continue;
+ }
+ }
+ else /* not a pointer block */
+ {
+ dp = (DATA_BL *)(hp->bh_data);
+ if (dp->db_id != DATA_ID) /* block id wrong */
+ ++error;
+ else
+ {
+ /* It is a data block, need to write it back to disk. */
+ mf_put(mfp, hp, TRUE, FALSE);
+ hp = NULL;
+ }
+ }
+ }
+
+ if (buf->b_ml.ml_stack_top == 0) /* finished */
+ break;
+
+ /* go one block up in the tree */
+ ip = &(buf->b_ml.ml_stack[--(buf->b_ml.ml_stack_top)]);
+ bnum = ip->ip_bnum;
+ idx = ip->ip_index + 1; /* go to next index */
+ page_count = 1;
+ }
+ if (hp != NULL)
+ mf_put(mfp, hp, FALSE, FALSE); /* release previous block */
+
+ if (error > 0)
+ emsg(_("E843: Error while updating swap file crypt"));
+ }
+
+ mfp->mf_old_key = NULL;
+}
+#endif
+
+/*
+ * ml_setname() is called when the file name of "buf" has been changed.
+ * It may rename the swap file.
+ */
+ void
+ml_setname(buf_T *buf)
+{
+ int success = FALSE;
+ memfile_T *mfp;
+ char_u *fname;
+ char_u *dirp;
+#if defined(MSWIN)
+ char_u *p;
+#endif
+
+ mfp = buf->b_ml.ml_mfp;
+ if (mfp->mf_fd < 0) /* there is no swap file yet */
+ {
+ /*
+ * When 'updatecount' is 0 and 'noswapfile' there is no swap file.
+ * For help files we will make a swap file now.
+ */
+ if (p_uc != 0 && !cmdmod.noswapfile)
+ ml_open_file(buf); /* create a swap file */
+ return;
+ }
+
+ /*
+ * Try all directories in the 'directory' option.
+ */
+ dirp = p_dir;
+ for (;;)
+ {
+ if (*dirp == NUL) /* tried all directories, fail */
+ break;
+ fname = findswapname(buf, &dirp, mfp->mf_fname);
+ /* alloc's fname */
+ if (dirp == NULL) /* out of memory */
+ break;
+ if (fname == NULL) /* no file name found for this dir */
+ continue;
+
+#if defined(MSWIN)
+ /*
+ * Set full pathname for swap file now, because a ":!cd dir" may
+ * change directory without us knowing it.
+ */
+ p = FullName_save(fname, FALSE);
+ vim_free(fname);
+ fname = p;
+ if (fname == NULL)
+ continue;
+#endif
+ /* if the file name is the same we don't have to do anything */
+ if (fnamecmp(fname, mfp->mf_fname) == 0)
+ {
+ vim_free(fname);
+ success = TRUE;
+ break;
+ }
+ /* need to close the swap file before renaming */
+ if (mfp->mf_fd >= 0)
+ {
+ close(mfp->mf_fd);
+ mfp->mf_fd = -1;
+ }
+
+ /* try to rename the swap file */
+ if (vim_rename(mfp->mf_fname, fname) == 0)
+ {
+ success = TRUE;
+ vim_free(mfp->mf_fname);
+ mfp->mf_fname = fname;
+ vim_free(mfp->mf_ffname);
+#if defined(MSWIN)
+ mfp->mf_ffname = NULL; /* mf_fname is full pathname already */
+#else
+ mf_set_ffname(mfp);
+#endif
+ ml_upd_block0(buf, UB_SAME_DIR);
+ break;
+ }
+ vim_free(fname); /* this fname didn't work, try another */
+ }
+
+ if (mfp->mf_fd == -1) /* need to (re)open the swap file */
+ {
+ mfp->mf_fd = mch_open((char *)mfp->mf_fname, O_RDWR | O_EXTRA, 0);
+ if (mfp->mf_fd < 0)
+ {
+ /* could not (re)open the swap file, what can we do???? */
+ emsg(_("E301: Oops, lost the swap file!!!"));
+ return;
+ }
+#ifdef HAVE_FD_CLOEXEC
+ {
+ int fdflags = fcntl(mfp->mf_fd, F_GETFD);
+ if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
+ (void)fcntl(mfp->mf_fd, F_SETFD, fdflags | FD_CLOEXEC);
+ }
+#endif
+ }
+ if (!success)
+ emsg(_("E302: Could not rename swap file"));
+}
+
+/*
+ * Open a file for the memfile for all buffers that are not readonly or have
+ * been modified.
+ * Used when 'updatecount' changes from zero to non-zero.
+ */
+ void
+ml_open_files(void)
+{
+ buf_T *buf;
+
+ FOR_ALL_BUFFERS(buf)
+ if (!buf->b_p_ro || buf->b_changed)
+ ml_open_file(buf);
+}
+
+/*
+ * Open a swap file for an existing memfile, if there is no swap file yet.
+ * If we are unable to find a file name, mf_fname will be NULL
+ * and the memfile will be in memory only (no recovery possible).
+ */
+ void
+ml_open_file(buf_T *buf)
+{
+ memfile_T *mfp;
+ char_u *fname;
+ char_u *dirp;
+
+ mfp = buf->b_ml.ml_mfp;
+ if (mfp == NULL || mfp->mf_fd >= 0 || !buf->b_p_swf || cmdmod.noswapfile)
+ return; /* nothing to do */
+
+#ifdef FEAT_SPELL
+ /* For a spell buffer use a temp file name. */
+ if (buf->b_spell)
+ {
+ fname = vim_tempname('s', FALSE);
+ if (fname != NULL)
+ (void)mf_open_file(mfp, fname); /* consumes fname! */
+ buf->b_may_swap = FALSE;
+ return;
+ }
+#endif
+
+ /*
+ * Try all directories in 'directory' option.
+ */
+ dirp = p_dir;
+ for (;;)
+ {
+ if (*dirp == NUL)
+ break;
+ /* There is a small chance that between choosing the swap file name
+ * and creating it, another Vim creates the file. In that case the
+ * creation will fail and we will use another directory. */
+ fname = findswapname(buf, &dirp, NULL); /* allocates fname */
+ if (dirp == NULL)
+ break; /* out of memory */
+ if (fname == NULL)
+ continue;
+ if (mf_open_file(mfp, fname) == OK) /* consumes fname! */
+ {
+#if defined(MSWIN)
+ /*
+ * set full pathname for swap file now, because a ":!cd dir" may
+ * change directory without us knowing it.
+ */
+ mf_fullname(mfp);
+#endif
+ ml_upd_block0(buf, UB_SAME_DIR);
+
+ /* Flush block zero, so others can read it */
+ if (mf_sync(mfp, MFS_ZERO) == OK)
+ {
+ /* Mark all blocks that should be in the swapfile as dirty.
+ * Needed for when the 'swapfile' option was reset, so that
+ * the swap file was deleted, and then on again. */
+ mf_set_dirty(mfp);
+ break;
+ }
+ /* Writing block 0 failed: close the file and try another dir */
+ mf_close_file(buf, FALSE);
+ }
+ }
+
+ if (mfp->mf_fname == NULL) /* Failed! */
+ {
+ need_wait_return = TRUE; /* call wait_return later */
+ ++no_wait_return;
+ (void)semsg(_("E303: Unable to open swap file for \"%s\", recovery impossible"),
+ buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname);
+ --no_wait_return;
+ }
+
+ /* don't try to open a swap file again */
+ buf->b_may_swap = FALSE;
+}
+
+/*
+ * If still need to create a swap file, and starting to edit a not-readonly
+ * file, or reading into an existing buffer, create a swap file now.
+ */
+ void
+check_need_swap(
+ int newfile) // reading file into new buffer
+{
+ int old_msg_silent = msg_silent; // might be reset by an E325 message
+
+ if (curbuf->b_may_swap && (!curbuf->b_p_ro || !newfile))
+ ml_open_file(curbuf);
+ msg_silent = old_msg_silent;
+}
+
+/*
+ * Close memline for buffer 'buf'.
+ * If 'del_file' is TRUE, delete the swap file
+ */
+ void
+ml_close(buf_T *buf, int del_file)
+{
+ if (buf->b_ml.ml_mfp == NULL) /* not open */
+ return;
+ mf_close(buf->b_ml.ml_mfp, del_file); /* close the .swp file */
+ if (buf->b_ml.ml_line_lnum != 0 && (buf->b_ml.ml_flags & ML_LINE_DIRTY))
+ vim_free(buf->b_ml.ml_line_ptr);
+ vim_free(buf->b_ml.ml_stack);
+#ifdef FEAT_BYTEOFF
+ VIM_CLEAR(buf->b_ml.ml_chunksize);
+#endif
+ buf->b_ml.ml_mfp = NULL;
+
+ /* Reset the "recovered" flag, give the ATTENTION prompt the next time
+ * this buffer is loaded. */
+ buf->b_flags &= ~BF_RECOVERED;
+}
+
+/*
+ * Close all existing memlines and memfiles.
+ * Only used when exiting.
+ * When 'del_file' is TRUE, delete the memfiles.
+ * But don't delete files that were ":preserve"d when we are POSIX compatible.
+ */
+ void
+ml_close_all(int del_file)
+{
+ buf_T *buf;
+
+ FOR_ALL_BUFFERS(buf)
+ ml_close(buf, del_file && ((buf->b_flags & BF_PRESERVED) == 0
+ || vim_strchr(p_cpo, CPO_PRESERVE) == NULL));
+#ifdef FEAT_SPELL
+ spell_delete_wordlist(); /* delete the internal wordlist */
+#endif
+#ifdef TEMPDIRNAMES
+ vim_deltempdir(); /* delete created temp directory */
+#endif
+}
+
+/*
+ * Close all memfiles for not modified buffers.
+ * Only use just before exiting!
+ */
+ void
+ml_close_notmod(void)
+{
+ buf_T *buf;
+
+ FOR_ALL_BUFFERS(buf)
+ if (!bufIsChanged(buf))
+ ml_close(buf, TRUE); /* close all not-modified buffers */
+}
+
+/*
+ * Update the timestamp in the .swp file.
+ * Used when the file has been written.
+ */
+ void
+ml_timestamp(buf_T *buf)
+{
+ ml_upd_block0(buf, UB_FNAME);
+}
+
+/*
+ * Return FAIL when the ID of "b0p" is wrong.
+ */
+ static int
+ml_check_b0_id(ZERO_BL *b0p)
+{
+ if (b0p->b0_id[0] != BLOCK0_ID0
+ || (b0p->b0_id[1] != BLOCK0_ID1
+ && b0p->b0_id[1] != BLOCK0_ID1_C0
+ && b0p->b0_id[1] != BLOCK0_ID1_C1
+ && b0p->b0_id[1] != BLOCK0_ID1_C2)
+ )
+ return FAIL;
+ return OK;
+}
+
+/*
+ * Update the timestamp or the B0_SAME_DIR flag of the .swp file.
+ */
+ static void
+ml_upd_block0(buf_T *buf, upd_block0_T what)
+{
+ memfile_T *mfp;
+ bhdr_T *hp;
+ ZERO_BL *b0p;
+
+ mfp = buf->b_ml.ml_mfp;
+ if (mfp == NULL)
+ return;
+ hp = mf_get(mfp, (blocknr_T)0, 1);
+ if (hp == NULL)
+ {
+#ifdef FEAT_CRYPT
+ /* Possibly update the seed in the memfile before there is a block0. */
+ if (what == UB_CRYPT)
+ ml_set_mfp_crypt(buf);
+#endif
+ return;
+ }
+
+ b0p = (ZERO_BL *)(hp->bh_data);
+ if (ml_check_b0_id(b0p) == FAIL)
+ iemsg(_("E304: ml_upd_block0(): Didn't get block 0??"));
+ else
+ {
+ if (what == UB_FNAME)
+ set_b0_fname(b0p, buf);
+#ifdef FEAT_CRYPT
+ else if (what == UB_CRYPT)
+ ml_set_b0_crypt(buf, b0p);
+#endif
+ else /* what == UB_SAME_DIR */
+ set_b0_dir_flag(b0p, buf);
+ }
+ mf_put(mfp, hp, TRUE, FALSE);
+}
+
+/*
+ * Write file name and timestamp into block 0 of a swap file.
+ * Also set buf->b_mtime.
+ * Don't use NameBuff[]!!!
+ */
+ static void
+set_b0_fname(ZERO_BL *b0p, buf_T *buf)
+{
+ stat_T st;
+
+ if (buf->b_ffname == NULL)
+ b0p->b0_fname[0] = NUL;
+ else
+ {
+#if defined(MSWIN) || defined(AMIGA)
+ /* Systems that cannot translate "~user" back into a path: copy the
+ * file name unmodified. Do use slashes instead of backslashes for
+ * portability. */
+ vim_strncpy(b0p->b0_fname, buf->b_ffname, B0_FNAME_SIZE_CRYPT - 1);
+# ifdef BACKSLASH_IN_FILENAME
+ forward_slash(b0p->b0_fname);
+# endif
+#else
+ size_t flen, ulen;
+ char_u uname[B0_UNAME_SIZE];
+
+ /*
+ * For a file under the home directory of the current user, we try to
+ * replace the home directory path with "~user". This helps when
+ * editing the same file on different machines over a network.
+ * First replace home dir path with "~/" with home_replace().
+ * Then insert the user name to get "~user/".
+ */
+ home_replace(NULL, buf->b_ffname, b0p->b0_fname,
+ B0_FNAME_SIZE_CRYPT, TRUE);
+ if (b0p->b0_fname[0] == '~')
+ {
+ flen = STRLEN(b0p->b0_fname);
+ /* If there is no user name or it is too long, don't use "~/" */
+ if (get_user_name(uname, B0_UNAME_SIZE) == FAIL
+ || (ulen = STRLEN(uname)) + flen > B0_FNAME_SIZE_CRYPT - 1)
+ vim_strncpy(b0p->b0_fname, buf->b_ffname,
+ B0_FNAME_SIZE_CRYPT - 1);
+ else
+ {
+ mch_memmove(b0p->b0_fname + ulen + 1, b0p->b0_fname + 1, flen);
+ mch_memmove(b0p->b0_fname + 1, uname, ulen);
+ }
+ }
+#endif
+ if (mch_stat((char *)buf->b_ffname, &st) >= 0)
+ {
+ long_to_char((long)st.st_mtime, b0p->b0_mtime);
+#ifdef CHECK_INODE
+ long_to_char((long)st.st_ino, b0p->b0_ino);
+#endif
+ buf_store_time(buf, &st, buf->b_ffname);
+ buf->b_mtime_read = buf->b_mtime;
+ }
+ else
+ {
+ long_to_char(0L, b0p->b0_mtime);
+#ifdef CHECK_INODE
+ long_to_char(0L, b0p->b0_ino);
+#endif
+ buf->b_mtime = 0;
+ buf->b_mtime_read = 0;
+ buf->b_orig_size = 0;
+ buf->b_orig_mode = 0;
+ }
+ }
+
+ /* Also add the 'fileencoding' if there is room. */
+ add_b0_fenc(b0p, curbuf);
+}
+
+/*
+ * Update the B0_SAME_DIR flag of the swap file. It's set if the file and the
+ * swapfile for "buf" are in the same directory.
+ * This is fail safe: if we are not sure the directories are equal the flag is
+ * not set.
+ */
+ static void
+set_b0_dir_flag(ZERO_BL *b0p, buf_T *buf)
+{
+ if (same_directory(buf->b_ml.ml_mfp->mf_fname, buf->b_ffname))
+ b0p->b0_flags |= B0_SAME_DIR;
+ else
+ b0p->b0_flags &= ~B0_SAME_DIR;
+}
+
+/*
+ * When there is room, add the 'fileencoding' to block zero.
+ */
+ static void
+add_b0_fenc(
+ ZERO_BL *b0p,
+ buf_T *buf)
+{
+ int n;
+ int size = B0_FNAME_SIZE_NOCRYPT;
+
+#ifdef FEAT_CRYPT
+ /* Without encryption use the same offset as in Vim 7.2 to be compatible.
+ * With encryption it's OK to move elsewhere, the swap file is not
+ * compatible anyway. */
+ if (*buf->b_p_key != NUL)
+ size = B0_FNAME_SIZE_CRYPT;
+#endif
+
+ n = (int)STRLEN(buf->b_p_fenc);
+ if ((int)STRLEN(b0p->b0_fname) + n + 1 > size)
+ b0p->b0_flags &= ~B0_HAS_FENC;
+ else
+ {
+ mch_memmove((char *)b0p->b0_fname + size - n,
+ (char *)buf->b_p_fenc, (size_t)n);
+ *(b0p->b0_fname + size - n - 1) = NUL;
+ b0p->b0_flags |= B0_HAS_FENC;
+ }
+}
+
+
+/*
+ * Try to recover curbuf from the .swp file.
+ */
+ void
+ml_recover(void)
+{
+ buf_T *buf = NULL;
+ memfile_T *mfp = NULL;
+ char_u *fname;
+ char_u *fname_used = NULL;
+ bhdr_T *hp = NULL;
+ ZERO_BL *b0p;
+ int b0_ff;
+ char_u *b0_fenc = NULL;
+#ifdef FEAT_CRYPT
+ int b0_cm = -1;
+#endif
+ PTR_BL *pp;
+ DATA_BL *dp;
+ infoptr_T *ip;
+ blocknr_T bnum;
+ int page_count;
+ stat_T org_stat, swp_stat;
+ int len;
+ int directly;
+ linenr_T lnum;
+ char_u *p;
+ int i;
+ long error;
+ int cannot_open;
+ linenr_T line_count;
+ int has_error;
+ int idx;
+ int top;
+ int txt_start;
+ off_T size;
+ int called_from_main;
+ int serious_error = TRUE;
+ long mtime;
+ int attr;
+ int orig_file_status = NOTDONE;
+
+ recoverymode = TRUE;
+ called_from_main = (curbuf->b_ml.ml_mfp == NULL);
+ attr = HL_ATTR(HLF_E);
+
+ /*
+ * If the file name ends in ".s[a-w][a-z]" we assume this is the swap file.
+ * Otherwise a search is done to find the swap file(s).
+ */
+ fname = curbuf->b_fname;
+ if (fname == NULL) /* When there is no file name */
+ fname = (char_u *)"";
+ len = (int)STRLEN(fname);
+ if (len >= 4 &&
+#if defined(VMS)
+ STRNICMP(fname + len - 4, "_s", 2)
+#else
+ STRNICMP(fname + len - 4, ".s", 2)
+#endif
+ == 0
+ && vim_strchr((char_u *)"abcdefghijklmnopqrstuvw",
+ TOLOWER_ASC(fname[len - 2])) != NULL
+ && ASCII_ISALPHA(fname[len - 1]))
+ {
+ directly = TRUE;
+ fname_used = vim_strsave(fname); /* make a copy for mf_open() */
+ }
+ else
+ {
+ directly = FALSE;
+
+ /* count the number of matching swap files */
+ len = recover_names(fname, FALSE, 0, NULL);
+ if (len == 0) /* no swap files found */
+ {
+ semsg(_("E305: No swap file found for %s"), fname);
+ goto theend;
+ }
+ if (len == 1) /* one swap file found, use it */
+ i = 1;
+ else /* several swap files found, choose */
+ {
+ /* list the names of the swap files */
+ (void)recover_names(fname, TRUE, 0, NULL);
+ msg_putchar('\n');
+ msg_puts(_("Enter number of swap file to use (0 to quit): "));
+ i = get_number(FALSE, NULL);
+ if (i < 1 || i > len)
+ goto theend;
+ }
+ /* get the swap file name that will be used */
+ (void)recover_names(fname, FALSE, i, &fname_used);
+ }
+ if (fname_used == NULL)
+ goto theend; /* out of memory */
+
+ /* When called from main() still need to initialize storage structure */
+ if (called_from_main && ml_open(curbuf) == FAIL)
+ getout(1);
+
+ /*
+ * Allocate a buffer structure for the swap file that is used for recovery.
+ * Only the memline and crypt information in it are really used.
+ */
+ buf = (buf_T *)alloc((unsigned)sizeof(buf_T));
+ if (buf == NULL)
+ goto theend;
+
+ /*
+ * init fields in memline struct
+ */
+ buf->b_ml.ml_stack_size = 0; /* no stack yet */
+ buf->b_ml.ml_stack = NULL; /* no stack yet */
+ buf->b_ml.ml_stack_top = 0; /* nothing in the stack */
+ buf->b_ml.ml_line_lnum = 0; /* no cached line */
+ buf->b_ml.ml_locked = NULL; /* no locked block */
+ buf->b_ml.ml_flags = 0;
+#ifdef FEAT_CRYPT
+ buf->b_p_key = empty_option;
+ buf->b_p_cm = empty_option;
+#endif
+
+ /*
+ * open the memfile from the old swap file
+ */
+ p = vim_strsave(fname_used); /* save "fname_used" for the message:
+ mf_open() will consume "fname_used"! */
+ mfp = mf_open(fname_used, O_RDONLY);
+ fname_used = p;
+ if (mfp == NULL || mfp->mf_fd < 0)
+ {
+ if (fname_used != NULL)
+ semsg(_("E306: Cannot open %s"), fname_used);
+ goto theend;
+ }
+ buf->b_ml.ml_mfp = mfp;
+#ifdef FEAT_CRYPT
+ mfp->mf_buffer = buf;
+#endif
+
+ /*
+ * The page size set in mf_open() might be different from the page size
+ * used in the swap file, we must get it from block 0. But to read block
+ * 0 we need a page size. Use the minimal size for block 0 here, it will
+ * be set to the real value below.
+ */
+ mfp->mf_page_size = MIN_SWAP_PAGE_SIZE;
+
+ /*
+ * try to read block 0
+ */
+ if ((hp = mf_get(mfp, (blocknr_T)0, 1)) == NULL)
+ {
+ msg_start();
+ msg_puts_attr(_("Unable to read block 0 from "), attr | MSG_HIST);
+ msg_outtrans_attr(mfp->mf_fname, attr | MSG_HIST);
+ msg_puts_attr(_("\nMaybe no changes were made or Vim did not update the swap file."),
+ attr | MSG_HIST);
+ msg_end();
+ goto theend;
+ }
+ b0p = (ZERO_BL *)(hp->bh_data);
+ if (STRNCMP(b0p->b0_version, "VIM 3.0", 7) == 0)
+ {
+ msg_start();
+ msg_outtrans_attr(mfp->mf_fname, MSG_HIST);
+ msg_puts_attr(_(" cannot be used with this version of Vim.\n"),
+ MSG_HIST);
+ msg_puts_attr(_("Use Vim version 3.0.\n"), MSG_HIST);
+ msg_end();
+ goto theend;
+ }
+ if (ml_check_b0_id(b0p) == FAIL)
+ {
+ semsg(_("E307: %s does not look like a Vim swap file"), mfp->mf_fname);
+ goto theend;
+ }
+ if (b0_magic_wrong(b0p))
+ {
+ msg_start();
+ msg_outtrans_attr(mfp->mf_fname, attr | MSG_HIST);
+#if defined(MSWIN)
+ if (STRNCMP(b0p->b0_hname, "PC ", 3) == 0)
+ msg_puts_attr(_(" cannot be used with this version of Vim.\n"),
+ attr | MSG_HIST);
+ else
+#endif
+ msg_puts_attr(_(" cannot be used on this computer.\n"),
+ attr | MSG_HIST);
+ msg_puts_attr(_("The file was created on "), attr | MSG_HIST);
+ /* avoid going past the end of a corrupted hostname */
+ b0p->b0_fname[0] = NUL;
+ msg_puts_attr((char *)b0p->b0_hname, attr | MSG_HIST);
+ msg_puts_attr(_(",\nor the file has been damaged."), attr | MSG_HIST);
+ msg_end();
+ goto theend;
+ }
+
+#ifdef FEAT_CRYPT
+ for (i = 0; i < (int)(sizeof(id1_codes) / sizeof(int)); ++i)
+ if (id1_codes[i] == b0p->b0_id[1])
+ b0_cm = i;
+ if (b0_cm > 0)
+ mch_memmove(mfp->mf_seed, &b0p->b0_seed, MF_SEED_LEN);
+ crypt_set_cm_option(buf, b0_cm < 0 ? 0 : b0_cm);
+#else
+ if (b0p->b0_id[1] != BLOCK0_ID1)
+ {
+ semsg(_("E833: %s is encrypted and this version of Vim does not support encryption"), mfp->mf_fname);
+ goto theend;
+ }
+#endif
+
+ /*
+ * If we guessed the wrong page size, we have to recalculate the
+ * highest block number in the file.
+ */
+ if (mfp->mf_page_size != (unsigned)char_to_long(b0p->b0_page_size))
+ {
+ unsigned previous_page_size = mfp->mf_page_size;
+
+ mf_new_page_size(mfp, (unsigned)char_to_long(b0p->b0_page_size));
+ if (mfp->mf_page_size < previous_page_size)
+ {
+ msg_start();
+ msg_outtrans_attr(mfp->mf_fname, attr | MSG_HIST);
+ msg_puts_attr(_(" has been damaged (page size is smaller than minimum value).\n"),
+ attr | MSG_HIST);
+ msg_end();
+ goto theend;
+ }
+ if ((size = vim_lseek(mfp->mf_fd, (off_T)0L, SEEK_END)) <= 0)
+ mfp->mf_blocknr_max = 0; /* no file or empty file */
+ else
+ mfp->mf_blocknr_max = (blocknr_T)(size / mfp->mf_page_size);
+ mfp->mf_infile_count = mfp->mf_blocknr_max;
+
+ /* need to reallocate the memory used to store the data */
+ p = alloc(mfp->mf_page_size);
+ if (p == NULL)
+ goto theend;
+ mch_memmove(p, hp->bh_data, previous_page_size);
+ vim_free(hp->bh_data);
+ hp->bh_data = p;
+ b0p = (ZERO_BL *)(hp->bh_data);
+ }
+
+ /*
+ * If .swp file name given directly, use name from swap file for buffer.
+ */
+ if (directly)
+ {
+ expand_env(b0p->b0_fname, NameBuff, MAXPATHL);
+ if (setfname(curbuf, NameBuff, NULL, TRUE) == FAIL)
+ goto theend;
+ }
+
+ home_replace(NULL, mfp->mf_fname, NameBuff, MAXPATHL, TRUE);
+ smsg(_("Using swap file \"%s\""), NameBuff);
+
+ if (buf_spname(curbuf) != NULL)
+ vim_strncpy(NameBuff, buf_spname(curbuf), MAXPATHL - 1);
+ else
+ home_replace(NULL, curbuf->b_ffname, NameBuff, MAXPATHL, TRUE);
+ smsg(_("Original file \"%s\""), NameBuff);
+ msg_putchar('\n');
+
+ /*
+ * check date of swap file and original file
+ */
+ mtime = char_to_long(b0p->b0_mtime);
+ if (curbuf->b_ffname != NULL
+ && mch_stat((char *)curbuf->b_ffname, &org_stat) != -1
+ && ((mch_stat((char *)mfp->mf_fname, &swp_stat) != -1
+ && org_stat.st_mtime > swp_stat.st_mtime)
+ || org_stat.st_mtime != mtime))
+ {
+ emsg(_("E308: Warning: Original file may have been changed"));
+ }
+ out_flush();
+
+ /* Get the 'fileformat' and 'fileencoding' from block zero. */
+ b0_ff = (b0p->b0_flags & B0_FF_MASK);
+ if (b0p->b0_flags & B0_HAS_FENC)
+ {
+ int fnsize = B0_FNAME_SIZE_NOCRYPT;
+
+#ifdef FEAT_CRYPT
+ /* Use the same size as in add_b0_fenc(). */
+ if (b0p->b0_id[1] != BLOCK0_ID1)
+ fnsize = B0_FNAME_SIZE_CRYPT;
+#endif
+ for (p = b0p->b0_fname + fnsize; p > b0p->b0_fname && p[-1] != NUL; --p)
+ ;
+ b0_fenc = vim_strnsave(p, (int)(b0p->b0_fname + fnsize - p));
+ }
+
+ mf_put(mfp, hp, FALSE, FALSE); /* release block 0 */
+ hp = NULL;
+
+ /*
+ * Now that we are sure that the file is going to be recovered, clear the
+ * contents of the current buffer.
+ */
+ while (!(curbuf->b_ml.ml_flags & ML_EMPTY))
+ ml_delete((linenr_T)1, FALSE);
+
+ /*
+ * Try reading the original file to obtain the values of 'fileformat',
+ * 'fileencoding', etc. Ignore errors. The text itself is not used.
+ * When the file is encrypted the user is asked to enter the key.
+ */
+ if (curbuf->b_ffname != NULL)
+ orig_file_status = readfile(curbuf->b_ffname, NULL, (linenr_T)0,
+ (linenr_T)0, (linenr_T)MAXLNUM, NULL, READ_NEW);
+
+#ifdef FEAT_CRYPT
+ if (b0_cm >= 0)
+ {
+ /* Need to ask the user for the crypt key. If this fails we continue
+ * without a key, will probably get garbage text. */
+ if (*curbuf->b_p_key != NUL)
+ {
+ smsg(_("Swap file is encrypted: \"%s\""), fname_used);
+ msg_puts(_("\nIf you entered a new crypt key but did not write the text file,"));
+ msg_puts(_("\nenter the new crypt key."));
+ msg_puts(_("\nIf you wrote the text file after changing the crypt key press enter"));
+ msg_puts(_("\nto use the same key for text file and swap file"));
+ }
+ else
+ smsg(_(need_key_msg), fname_used);
+ buf->b_p_key = crypt_get_key(FALSE, FALSE);
+ if (buf->b_p_key == NULL)
+ buf->b_p_key = curbuf->b_p_key;
+ else if (*buf->b_p_key == NUL)
+ {
+ vim_free(buf->b_p_key);
+ buf->b_p_key = curbuf->b_p_key;
+ }
+ if (buf->b_p_key == NULL)
+ buf->b_p_key = empty_option;
+ }
+#endif
+
+ /* Use the 'fileformat' and 'fileencoding' as stored in the swap file. */
+ if (b0_ff != 0)
+ set_fileformat(b0_ff - 1, OPT_LOCAL);
+ if (b0_fenc != NULL)
+ {
+ set_option_value((char_u *)"fenc", 0L, b0_fenc, OPT_LOCAL);
+ vim_free(b0_fenc);
+ }
+ unchanged(curbuf, TRUE);
+
+ bnum = 1; /* start with block 1 */
+ page_count = 1; /* which is 1 page */
+ lnum = 0; /* append after line 0 in curbuf */
+ line_count = 0;
+ idx = 0; /* start with first index in block 1 */
+ error = 0;
+ buf->b_ml.ml_stack_top = 0;
+ buf->b_ml.ml_stack = NULL;
+ buf->b_ml.ml_stack_size = 0; /* no stack yet */
+
+ if (curbuf->b_ffname == NULL)
+ cannot_open = TRUE;
+ else
+ cannot_open = FALSE;
+
+ serious_error = FALSE;
+ for ( ; !got_int; line_breakcheck())
+ {
+ if (hp != NULL)
+ mf_put(mfp, hp, FALSE, FALSE); /* release previous block */
+
+ /*
+ * get block
+ */
+ if ((hp = mf_get(mfp, (blocknr_T)bnum, page_count)) == NULL)
+ {
+ if (bnum == 1)
+ {
+ semsg(_("E309: Unable to read block 1 from %s"), mfp->mf_fname);
+ goto theend;
+ }
+ ++error;
+ ml_append(lnum++, (char_u *)_("???MANY LINES MISSING"),
+ (colnr_T)0, TRUE);
+ }
+ else /* there is a block */
+ {
+ pp = (PTR_BL *)(hp->bh_data);
+ if (pp->pb_id == PTR_ID) /* it is a pointer block */
+ {
+ /* check line count when using pointer block first time */
+ if (idx == 0 && line_count != 0)
+ {
+ for (i = 0; i < (int)pp->pb_count; ++i)
+ line_count -= pp->pb_pointer[i].pe_line_count;
+ if (line_count != 0)
+ {
+ ++error;
+ ml_append(lnum++, (char_u *)_("???LINE COUNT WRONG"),
+ (colnr_T)0, TRUE);
+ }
+ }
+
+ if (pp->pb_count == 0)
+ {
+ ml_append(lnum++, (char_u *)_("???EMPTY BLOCK"),
+ (colnr_T)0, TRUE);
+ ++error;
+ }
+ else if (idx < (int)pp->pb_count) /* go a block deeper */
+ {
+ if (pp->pb_pointer[idx].pe_bnum < 0)
+ {
+ /*
+ * Data block with negative block number.
+ * Try to read lines from the original file.
+ * This is slow, but it works.
+ */
+ if (!cannot_open)
+ {
+ line_count = pp->pb_pointer[idx].pe_line_count;
+ if (readfile(curbuf->b_ffname, NULL, lnum,
+ pp->pb_pointer[idx].pe_old_lnum - 1,
+ line_count, NULL, 0) != OK)
+ cannot_open = TRUE;
+ else
+ lnum += line_count;
+ }
+ if (cannot_open)
+ {
+ ++error;
+ ml_append(lnum++, (char_u *)_("???LINES MISSING"),
+ (colnr_T)0, TRUE);
+ }
+ ++idx; /* get same block again for next index */
+ continue;
+ }
+
+ /*
+ * going one block deeper in the tree
+ */
+ if ((top = ml_add_stack(buf)) < 0) /* new entry in stack */
+ {
+ ++error;
+ break; /* out of memory */
+ }
+ ip = &(buf->b_ml.ml_stack[top]);
+ ip->ip_bnum = bnum;
+ ip->ip_index = idx;
+
+ bnum = pp->pb_pointer[idx].pe_bnum;
+ line_count = pp->pb_pointer[idx].pe_line_count;
+ page_count = pp->pb_pointer[idx].pe_page_count;
+ idx = 0;
+ continue;
+ }
+ }
+ else /* not a pointer block */
+ {
+ dp = (DATA_BL *)(hp->bh_data);
+ if (dp->db_id != DATA_ID) /* block id wrong */
+ {
+ if (bnum == 1)
+ {
+ semsg(_("E310: Block 1 ID wrong (%s not a .swp file?)"),
+ mfp->mf_fname);
+ goto theend;
+ }
+ ++error;
+ ml_append(lnum++, (char_u *)_("???BLOCK MISSING"),
+ (colnr_T)0, TRUE);
+ }
+ else
+ {
+ /*
+ * it is a data block
+ * Append all the lines in this block
+ */
+ has_error = FALSE;
+ /*
+ * check length of block
+ * if wrong, use length in pointer block
+ */
+ if (page_count * mfp->mf_page_size != dp->db_txt_end)
+ {
+ ml_append(lnum++, (char_u *)_("??? from here until ???END lines may be messed up"),
+ (colnr_T)0, TRUE);
+ ++error;
+ has_error = TRUE;
+ dp->db_txt_end = page_count * mfp->mf_page_size;
+ }
+
+ /* make sure there is a NUL at the end of the block */
+ *((char_u *)dp + dp->db_txt_end - 1) = NUL;
+
+ /*
+ * check number of lines in block
+ * if wrong, use count in data block
+ */
+ if (line_count != dp->db_line_count)
+ {
+ ml_append(lnum++, (char_u *)_("??? from here until ???END lines may have been inserted/deleted"),
+ (colnr_T)0, TRUE);
+ ++error;
+ has_error = TRUE;
+ }
+
+ for (i = 0; i < dp->db_line_count; ++i)
+ {
+ txt_start = (dp->db_index[i] & DB_INDEX_MASK);
+ if (txt_start <= (int)HEADER_SIZE
+ || txt_start >= (int)dp->db_txt_end)
+ {
+ p = (char_u *)"???";
+ ++error;
+ }
+ else
+ p = (char_u *)dp + txt_start;
+ ml_append(lnum++, p, (colnr_T)0, TRUE);
+ }
+ if (has_error)
+ ml_append(lnum++, (char_u *)_("???END"),
+ (colnr_T)0, TRUE);
+ }
+ }
+ }
+
+ if (buf->b_ml.ml_stack_top == 0) /* finished */
+ break;
+
+ /*
+ * go one block up in the tree
+ */
+ ip = &(buf->b_ml.ml_stack[--(buf->b_ml.ml_stack_top)]);
+ bnum = ip->ip_bnum;
+ idx = ip->ip_index + 1; /* go to next index */
+ page_count = 1;
+ }
+
+ /*
+ * Compare the buffer contents with the original file. When they differ
+ * set the 'modified' flag.
+ * Lines 1 - lnum are the new contents.
+ * Lines lnum + 1 to ml_line_count are the original contents.
+ * Line ml_line_count + 1 in the dummy empty line.
+ */
+ if (orig_file_status != OK || curbuf->b_ml.ml_line_count != lnum * 2 + 1)
+ {
+ /* Recovering an empty file results in two lines and the first line is
+ * empty. Don't set the modified flag then. */
+ if (!(curbuf->b_ml.ml_line_count == 2 && *ml_get(1) == NUL))
+ {
+ changed_int();
+ ++CHANGEDTICK(curbuf);
+ }
+ }
+ else
+ {
+ for (idx = 1; idx <= lnum; ++idx)
+ {
+ /* Need to copy one line, fetching the other one may flush it. */
+ p = vim_strsave(ml_get(idx));
+ i = STRCMP(p, ml_get(idx + lnum));
+ vim_free(p);
+ if (i != 0)
+ {
+ changed_int();
+ ++CHANGEDTICK(curbuf);
+ break;
+ }
+ }
+ }
+
+ /*
+ * Delete the lines from the original file and the dummy line from the
+ * empty buffer. These will now be after the last line in the buffer.
+ */
+ while (curbuf->b_ml.ml_line_count > lnum
+ && !(curbuf->b_ml.ml_flags & ML_EMPTY))
+ ml_delete(curbuf->b_ml.ml_line_count, FALSE);
+ curbuf->b_flags |= BF_RECOVERED;
+
+ recoverymode = FALSE;
+ if (got_int)
+ emsg(_("E311: Recovery Interrupted"));
+ else if (error)
+ {
+ ++no_wait_return;
+ msg(">>>>>>>>>>>>>");
+ emsg(_("E312: Errors detected while recovering; look for lines starting with ???"));
+ --no_wait_return;
+ msg(_("See \":help E312\" for more information."));
+ msg(">>>>>>>>>>>>>");
+ }
+ else
+ {
+ if (curbuf->b_changed)
+ {
+ msg(_("Recovery completed. You should check if everything is OK."));
+ msg_puts(_("\n(You might want to write out this file under another name\n"));
+ msg_puts(_("and run diff with the original file to check for changes)"));
+ }
+ else
+ msg(_("Recovery completed. Buffer contents equals file contents."));
+ msg_puts(_("\nYou may want to delete the .swp file now.\n\n"));
+ cmdline_row = msg_row;
+ }
+#ifdef FEAT_CRYPT
+ if (*buf->b_p_key != NUL && STRCMP(curbuf->b_p_key, buf->b_p_key) != 0)
+ {
+ msg_puts(_("Using crypt key from swap file for the text file.\n"));
+ set_option_value((char_u *)"key", 0L, buf->b_p_key, OPT_LOCAL);
+ }
+#endif
+ redraw_curbuf_later(NOT_VALID);
+
+theend:
+ vim_free(fname_used);
+ recoverymode = FALSE;
+ if (mfp != NULL)
+ {
+ if (hp != NULL)
+ mf_put(mfp, hp, FALSE, FALSE);
+ mf_close(mfp, FALSE); /* will also vim_free(mfp->mf_fname) */
+ }
+ if (buf != NULL)
+ {
+#ifdef FEAT_CRYPT
+ if (buf->b_p_key != curbuf->b_p_key)
+ free_string_option(buf->b_p_key);
+ free_string_option(buf->b_p_cm);
+#endif
+ vim_free(buf->b_ml.ml_stack);
+ vim_free(buf);
+ }
+ if (serious_error && called_from_main)
+ ml_close(curbuf, TRUE);
+ else
+ {
+ apply_autocmds(EVENT_BUFREADPOST, NULL, curbuf->b_fname, FALSE, curbuf);
+ apply_autocmds(EVENT_BUFWINENTER, NULL, curbuf->b_fname, FALSE, curbuf);
+ }
+ return;
+}
+
+/*
+ * Find the names of swap files in current directory and the directory given
+ * with the 'directory' option.
+ *
+ * Used to:
+ * - list the swap files for "vim -r"
+ * - count the number of swap files when recovering
+ * - list the swap files when recovering
+ * - find the name of the n'th swap file when recovering
+ */
+ int
+recover_names(
+ char_u *fname, /* base for swap file name */
+ int list, /* when TRUE, list the swap file names */
+ int nr, /* when non-zero, return nr'th swap file name */
+ char_u **fname_out) /* result when "nr" > 0 */
+{
+ int num_names;
+ char_u *(names[6]);
+ char_u *tail;
+ char_u *p;
+ int num_files;
+ int file_count = 0;
+ char_u **files;
+ int i;
+ char_u *dirp;
+ char_u *dir_name;
+ char_u *fname_res = NULL;
+#ifdef HAVE_READLINK
+ char_u fname_buf[MAXPATHL];
+#endif
+
+ if (fname != NULL)
+ {
+#ifdef HAVE_READLINK
+ /* Expand symlink in the file name, because the swap file is created
+ * with the actual file instead of with the symlink. */
+ if (resolve_symlink(fname, fname_buf) == OK)
+ fname_res = fname_buf;
+ else
+#endif
+ fname_res = fname;
+ }
+
+ if (list)
+ {
+ /* use msg() to start the scrolling properly */
+ msg(_("Swap files found:"));
+ msg_putchar('\n');
+ }
+
+ /*
+ * Do the loop for every directory in 'directory'.
+ * First allocate some memory to put the directory name in.
+ */
+ dir_name = alloc((unsigned)STRLEN(p_dir) + 1);
+ dirp = p_dir;
+ while (dir_name != NULL && *dirp)
+ {
+ /*
+ * Isolate a directory name from *dirp and put it in dir_name (we know
+ * it is large enough, so use 31000 for length).
+ * Advance dirp to next directory name.
+ */
+ (void)copy_option_part(&dirp, dir_name, 31000, ",");
+
+ if (dir_name[0] == '.' && dir_name[1] == NUL) /* check current dir */
+ {
+ if (fname == NULL)
+ {
+#ifdef VMS
+ names[0] = vim_strsave((char_u *)"*_sw%");
+#else
+ names[0] = vim_strsave((char_u *)"*.sw?");
+#endif
+#if defined(UNIX) || defined(WIN3264)
+ /* For Unix names starting with a dot are special. MS-Windows
+ * supports this too, on some file systems. */
+ names[1] = vim_strsave((char_u *)".*.sw?");
+ names[2] = vim_strsave((char_u *)".sw?");
+ num_names = 3;
+#else
+# ifdef VMS
+ names[1] = vim_strsave((char_u *)".*_sw%");
+ num_names = 2;
+# else
+ num_names = 1;
+# endif
+#endif
+ }
+ else
+ num_names = recov_file_names(names, fname_res, TRUE);
+ }
+ else /* check directory dir_name */
+ {
+ if (fname == NULL)
+ {
+#ifdef VMS
+ names[0] = concat_fnames(dir_name, (char_u *)"*_sw%", TRUE);
+#else
+ names[0] = concat_fnames(dir_name, (char_u *)"*.sw?", TRUE);
+#endif
+#if defined(UNIX) || defined(WIN3264)
+ /* For Unix names starting with a dot are special. MS-Windows
+ * supports this too, on some file systems. */
+ names[1] = concat_fnames(dir_name, (char_u *)".*.sw?", TRUE);
+ names[2] = concat_fnames(dir_name, (char_u *)".sw?", TRUE);
+ num_names = 3;
+#else
+# ifdef VMS
+ names[1] = concat_fnames(dir_name, (char_u *)".*_sw%", TRUE);
+ num_names = 2;
+# else
+ num_names = 1;
+# endif
+#endif
+ }
+ else
+ {
+#if defined(UNIX) || defined(WIN3264)
+ int len = (int)STRLEN(dir_name);
+
+ p = dir_name + len;
+ if (after_pathsep(dir_name, p) && len > 1 && p[-1] == p[-2])
+ {
+ /* Ends with '//', Use Full path for swap name */
+ tail = make_percent_swname(dir_name, fname_res);
+ }
+ else
+#endif
+ {
+ tail = gettail(fname_res);
+ tail = concat_fnames(dir_name, tail, TRUE);
+ }
+ if (tail == NULL)
+ num_names = 0;
+ else
+ {
+ num_names = recov_file_names(names, tail, FALSE);
+ vim_free(tail);
+ }
+ }
+ }
+
+ /* check for out-of-memory */
+ for (i = 0; i < num_names; ++i)
+ {
+ if (names[i] == NULL)
+ {
+ for (i = 0; i < num_names; ++i)
+ vim_free(names[i]);
+ num_names = 0;
+ }
+ }
+ if (num_names == 0)
+ num_files = 0;
+ else if (expand_wildcards(num_names, names, &num_files, &files,
+ EW_KEEPALL|EW_FILE|EW_SILENT) == FAIL)
+ num_files = 0;
+
+ /*
+ * When no swap file found, wildcard expansion might have failed (e.g.
+ * not able to execute the shell).
+ * Try finding a swap file by simply adding ".swp" to the file name.
+ */
+ if (*dirp == NUL && file_count + num_files == 0 && fname != NULL)
+ {
+ stat_T st;
+ char_u *swapname;
+
+ swapname = modname(fname_res,
+#if defined(VMS)
+ (char_u *)"_swp", FALSE
+#else
+ (char_u *)".swp", TRUE
+#endif
+ );
+ if (swapname != NULL)
+ {
+ if (mch_stat((char *)swapname, &st) != -1) /* It exists! */
+ {
+ files = (char_u **)alloc((unsigned)sizeof(char_u *));
+ if (files != NULL)
+ {
+ files[0] = swapname;
+ swapname = NULL;
+ num_files = 1;
+ }
+ }
+ vim_free(swapname);
+ }
+ }
+
+ /*
+ * remove swapfile name of the current buffer, it must be ignored
+ */
+ if (curbuf->b_ml.ml_mfp != NULL
+ && (p = curbuf->b_ml.ml_mfp->mf_fname) != NULL)
+ {
+ for (i = 0; i < num_files; ++i)
+ if (fullpathcmp(p, files[i], TRUE) & FPC_SAME)
+ {
+ /* Remove the name from files[i]. Move further entries
+ * down. When the array becomes empty free it here, since
+ * FreeWild() won't be called below. */
+ vim_free(files[i]);
+ if (--num_files == 0)
+ vim_free(files);
+ else
+ for ( ; i < num_files; ++i)
+ files[i] = files[i + 1];
+ }
+ }
+ if (nr > 0)
+ {
+ file_count += num_files;
+ if (nr <= file_count)
+ {
+ *fname_out = vim_strsave(
+ files[nr - 1 + num_files - file_count]);
+ dirp = (char_u *)""; /* stop searching */
+ }
+ }
+ else if (list)
+ {
+ if (dir_name[0] == '.' && dir_name[1] == NUL)
+ {
+ if (fname == NULL)
+ msg_puts(_(" In current directory:\n"));
+ else
+ msg_puts(_(" Using specified name:\n"));
+ }
+ else
+ {
+ msg_puts(_(" In directory "));
+ msg_home_replace(dir_name);
+ msg_puts(":\n");
+ }
+
+ if (num_files)
+ {
+ for (i = 0; i < num_files; ++i)
+ {
+ /* print the swap file name */
+ msg_outnum((long)++file_count);
+ msg_puts(". ");
+ msg_puts((char *)gettail(files[i]));
+ msg_putchar('\n');
+ (void)swapfile_info(files[i]);
+ }
+ }
+ else
+ msg_puts(_(" -- none --\n"));
+ out_flush();
+ }
+ else
+ file_count += num_files;
+
+ for (i = 0; i < num_names; ++i)
+ vim_free(names[i]);
+ if (num_files > 0)
+ FreeWild(num_files, files);
+ }
+ vim_free(dir_name);
+ return file_count;
+}
+
+#if defined(UNIX) || defined(WIN3264) || defined(PROTO)
+/*
+ * Need _very_ long file names.
+ * Append the full path to name with path separators made into percent
+ * signs, to dir. An unnamed buffer is handled as "" (<currentdir>/"")
+ */
+ char_u *
+make_percent_swname(char_u *dir, char_u *name)
+{
+ char_u *d = NULL, *s, *f;
+
+ f = fix_fname(name != NULL ? name : (char_u *)"");
+ if (f != NULL)
+ {
+ s = alloc((unsigned)(STRLEN(f) + 1));
+ if (s != NULL)
+ {
+ STRCPY(s, f);
+ for (d = s; *d != NUL; MB_PTR_ADV(d))
+ if (vim_ispathsep(*d))
+ *d = '%';
+ d = concat_fnames(dir, s, TRUE);
+ vim_free(s);
+ }
+ vim_free(f);
+ }
+ return d;
+}
+#endif
+
+#if (defined(UNIX) || defined(VMS)) && (defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG))
+static int process_still_running;
+#endif
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * Return information found in swapfile "fname" in dictionary "d".
+ * This is used by the swapinfo() function.
+ */
+ void
+get_b0_dict(char_u *fname, dict_T *d)
+{
+ int fd;
+ struct block0 b0;
+
+ if ((fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0)) >= 0)
+ {
+ if (read_eintr(fd, &b0, sizeof(b0)) == sizeof(b0))
+ {
+ if (ml_check_b0_id(&b0) == FAIL)
+ dict_add_string(d, "error", (char_u *)"Not a swap file");
+ else if (b0_magic_wrong(&b0))
+ dict_add_string(d, "error", (char_u *)"Magic number mismatch");
+ else
+ {
+ /* we have swap information */
+ dict_add_string_len(d, "version", b0.b0_version, 10);
+ dict_add_string_len(d, "user", b0.b0_uname, B0_UNAME_SIZE);
+ dict_add_string_len(d, "host", b0.b0_hname, B0_HNAME_SIZE);
+ dict_add_string_len(d, "fname", b0.b0_fname, B0_FNAME_SIZE_ORG);
+
+ dict_add_number(d, "pid", char_to_long(b0.b0_pid));
+ dict_add_number(d, "mtime", char_to_long(b0.b0_mtime));
+ dict_add_number(d, "dirty", b0.b0_dirty ? 1 : 0);
+# ifdef CHECK_INODE
+ dict_add_number(d, "inode", char_to_long(b0.b0_ino));
+# endif
+ }
+ }
+ else
+ dict_add_string(d, "error", (char_u *)"Cannot read file");
+ close(fd);
+ }
+ else
+ dict_add_string(d, "error", (char_u *)"Cannot open file");
+}
+#endif
+
+/*
+ * Give information about an existing swap file.
+ * Returns timestamp (0 when unknown).
+ */
+ static time_t
+swapfile_info(char_u *fname)
+{
+ stat_T st;
+ int fd;
+ struct block0 b0;
+ time_t x = (time_t)0;
+ char *p;
+#ifdef UNIX
+ char_u uname[B0_UNAME_SIZE];
+#endif
+
+ /* print the swap file date */
+ if (mch_stat((char *)fname, &st) != -1)
+ {
+#ifdef UNIX
+ /* print name of owner of the file */
+ if (mch_get_uname(st.st_uid, uname, B0_UNAME_SIZE) == OK)
+ {
+ msg_puts(_(" owned by: "));
+ msg_outtrans(uname);
+ msg_puts(_(" dated: "));
+ }
+ else
+#endif
+ msg_puts(_(" dated: "));
+ x = st.st_mtime; /* Manx C can't do &st.st_mtime */
+ p = ctime(&x); /* includes '\n' */
+ if (p == NULL)
+ msg_puts("(invalid)\n");
+ else
+ msg_puts(p);
+ }
+
+ /*
+ * print the original file name
+ */
+ fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0);
+ if (fd >= 0)
+ {
+ if (read_eintr(fd, &b0, sizeof(b0)) == sizeof(b0))
+ {
+ if (STRNCMP(b0.b0_version, "VIM 3.0", 7) == 0)
+ {
+ msg_puts(_(" [from Vim version 3.0]"));
+ }
+ else if (ml_check_b0_id(&b0) == FAIL)
+ {
+ msg_puts(_(" [does not look like a Vim swap file]"));
+ }
+ else
+ {
+ msg_puts(_(" file name: "));
+ if (b0.b0_fname[0] == NUL)
+ msg_puts(_("[No Name]"));
+ else
+ msg_outtrans(b0.b0_fname);
+
+ msg_puts(_("\n modified: "));
+ msg_puts(b0.b0_dirty ? _("YES") : _("no"));
+
+ if (*(b0.b0_uname) != NUL)
+ {
+ msg_puts(_("\n user name: "));
+ msg_outtrans(b0.b0_uname);
+ }
+
+ if (*(b0.b0_hname) != NUL)
+ {
+ if (*(b0.b0_uname) != NUL)
+ msg_puts(_(" host name: "));
+ else
+ msg_puts(_("\n host name: "));
+ msg_outtrans(b0.b0_hname);
+ }
+
+ if (char_to_long(b0.b0_pid) != 0L)
+ {
+ msg_puts(_("\n process ID: "));
+ msg_outnum(char_to_long(b0.b0_pid));
+#if defined(UNIX)
+ /* EMX kill() not working correctly, it seems */
+ if (kill((pid_t)char_to_long(b0.b0_pid), 0) == 0)
+ {
+ msg_puts(_(" (STILL RUNNING)"));
+# if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
+ process_still_running = TRUE;
+# endif
+ }
+#endif
+ }
+
+ if (b0_magic_wrong(&b0))
+ {
+#if defined(MSWIN)
+ if (STRNCMP(b0.b0_hname, "PC ", 3) == 0)
+ msg_puts(_("\n [not usable with this version of Vim]"));
+ else
+#endif
+ msg_puts(_("\n [not usable on this computer]"));
+ }
+ }
+ }
+ else
+ msg_puts(_(" [cannot be read]"));
+ close(fd);
+ }
+ else
+ msg_puts(_(" [cannot be opened]"));
+ msg_putchar('\n');
+
+ return x;
+}
+
+ static int
+recov_file_names(char_u **names, char_u *path, int prepend_dot)
+{
+ int num_names;
+
+ /*
+ * (Win32 and Win64) never short names, but do prepend a dot.
+ * (Not MS-DOS or Win32 or Win64) maybe short name, maybe not: Try both.
+ * Only use the short name if it is different.
+ */
+ char_u *p;
+ int i;
+# ifndef WIN3264
+ int shortname = curbuf->b_shortname;
+
+ curbuf->b_shortname = FALSE;
+# endif
+
+ num_names = 0;
+
+ /*
+ * May also add the file name with a dot prepended, for swap file in same
+ * dir as original file.
+ */
+ if (prepend_dot)
+ {
+ names[num_names] = modname(path, (char_u *)".sw?", TRUE);
+ if (names[num_names] == NULL)
+ goto end;
+ ++num_names;
+ }
+
+ /*
+ * Form the normal swap file name pattern by appending ".sw?".
+ */
+#ifdef VMS
+ names[num_names] = concat_fnames(path, (char_u *)"_sw%", FALSE);
+#else
+ names[num_names] = concat_fnames(path, (char_u *)".sw?", FALSE);
+#endif
+ if (names[num_names] == NULL)
+ goto end;
+ if (num_names >= 1) /* check if we have the same name twice */
+ {
+ p = names[num_names - 1];
+ i = (int)STRLEN(names[num_names - 1]) - (int)STRLEN(names[num_names]);
+ if (i > 0)
+ p += i; /* file name has been expanded to full path */
+
+ if (STRCMP(p, names[num_names]) != 0)
+ ++num_names;
+ else
+ vim_free(names[num_names]);
+ }
+ else
+ ++num_names;
+
+# ifndef WIN3264
+ /*
+ * Also try with 'shortname' set, in case the file is on a DOS filesystem.
+ */
+ curbuf->b_shortname = TRUE;
+#ifdef VMS
+ names[num_names] = modname(path, (char_u *)"_sw%", FALSE);
+#else
+ names[num_names] = modname(path, (char_u *)".sw?", FALSE);
+#endif
+ if (names[num_names] == NULL)
+ goto end;
+
+ /*
+ * Remove the one from 'shortname', if it's the same as with 'noshortname'.
+ */
+ p = names[num_names];
+ i = STRLEN(names[num_names]) - STRLEN(names[num_names - 1]);
+ if (i > 0)
+ p += i; /* file name has been expanded to full path */
+ if (STRCMP(names[num_names - 1], p) == 0)
+ vim_free(names[num_names]);
+ else
+ ++num_names;
+# endif
+
+end:
+# ifndef WIN3264
+ curbuf->b_shortname = shortname;
+# endif
+
+ return num_names;
+}
+
+/*
+ * sync all memlines
+ *
+ * If 'check_file' is TRUE, check if original file exists and was not changed.
+ * If 'check_char' is TRUE, stop syncing when character becomes available, but
+ * always sync at least one block.
+ */
+ void
+ml_sync_all(int check_file, int check_char)
+{
+ buf_T *buf;
+ stat_T st;
+
+ FOR_ALL_BUFFERS(buf)
+ {
+ if (buf->b_ml.ml_mfp == NULL || buf->b_ml.ml_mfp->mf_fname == NULL)
+ continue; /* no file */
+
+ ml_flush_line(buf); /* flush buffered line */
+ /* flush locked block */
+ (void)ml_find_line(buf, (linenr_T)0, ML_FLUSH);
+ if (bufIsChanged(buf) && check_file && mf_need_trans(buf->b_ml.ml_mfp)
+ && buf->b_ffname != NULL)
+ {
+ /*
+ * If the original file does not exist anymore or has been changed
+ * call ml_preserve() to get rid of all negative numbered blocks.
+ */
+ if (mch_stat((char *)buf->b_ffname, &st) == -1
+ || st.st_mtime != buf->b_mtime_read
+ || st.st_size != buf->b_orig_size)
+ {
+ ml_preserve(buf, FALSE);
+ did_check_timestamps = FALSE;
+ need_check_timestamps = TRUE; /* give message later */
+ }
+ }
+ if (buf->b_ml.ml_mfp->mf_dirty)
+ {
+ (void)mf_sync(buf->b_ml.ml_mfp, (check_char ? MFS_STOP : 0)
+ | (bufIsChanged(buf) ? MFS_FLUSH : 0));
+ if (check_char && ui_char_avail()) /* character available now */
+ break;
+ }
+ }
+}
+
+/*
+ * sync one buffer, including negative blocks
+ *
+ * after this all the blocks are in the swap file
+ *
+ * Used for the :preserve command and when the original file has been
+ * changed or deleted.
+ *
+ * when message is TRUE the success of preserving is reported
+ */
+ void
+ml_preserve(buf_T *buf, int message)
+{
+ bhdr_T *hp;
+ linenr_T lnum;
+ memfile_T *mfp = buf->b_ml.ml_mfp;
+ int status;
+ int got_int_save = got_int;
+
+ if (mfp == NULL || mfp->mf_fname == NULL)
+ {
+ if (message)
+ emsg(_("E313: Cannot preserve, there is no swap file"));
+ return;
+ }
+
+ /* We only want to stop when interrupted here, not when interrupted
+ * before. */
+ got_int = FALSE;
+
+ ml_flush_line(buf); /* flush buffered line */
+ (void)ml_find_line(buf, (linenr_T)0, ML_FLUSH); /* flush locked block */
+ status = mf_sync(mfp, MFS_ALL | MFS_FLUSH);
+
+ /* stack is invalid after mf_sync(.., MFS_ALL) */
+ buf->b_ml.ml_stack_top = 0;
+
+ /*
+ * Some of the data blocks may have been changed from negative to
+ * positive block number. In that case the pointer blocks need to be
+ * updated.
+ *
+ * We don't know in which pointer block the references are, so we visit
+ * all data blocks until there are no more translations to be done (or
+ * we hit the end of the file, which can only happen in case a write fails,
+ * e.g. when file system if full).
+ * ml_find_line() does the work by translating the negative block numbers
+ * when getting the first line of each data block.
+ */
+ if (mf_need_trans(mfp) && !got_int)
+ {
+ lnum = 1;
+ while (mf_need_trans(mfp) && lnum <= buf->b_ml.ml_line_count)
+ {
+ hp = ml_find_line(buf, lnum, ML_FIND);
+ if (hp == NULL)
+ {
+ status = FAIL;
+ goto theend;
+ }
+ CHECK(buf->b_ml.ml_locked_low != lnum, "low != lnum");
+ lnum = buf->b_ml.ml_locked_high + 1;
+ }
+ (void)ml_find_line(buf, (linenr_T)0, ML_FLUSH); /* flush locked block */
+ /* sync the updated pointer blocks */
+ if (mf_sync(mfp, MFS_ALL | MFS_FLUSH) == FAIL)
+ status = FAIL;
+ buf->b_ml.ml_stack_top = 0; /* stack is invalid now */
+ }
+theend:
+ got_int |= got_int_save;
+
+ if (message)
+ {
+ if (status == OK)
+ msg(_("File preserved"));
+ else
+ emsg(_("E314: Preserve failed"));
+ }
+}
+
+/*
+ * NOTE: The pointer returned by the ml_get_*() functions only remains valid
+ * until the next call!
+ * line1 = ml_get(1);
+ * line2 = ml_get(2); // line1 is now invalid!
+ * Make a copy of the line if necessary.
+ */
+/*
+ * Return a pointer to a (read-only copy of a) line.
+ *
+ * On failure an error message is given and IObuff is returned (to avoid
+ * having to check for error everywhere).
+ */
+ char_u *
+ml_get(linenr_T lnum)
+{
+ return ml_get_buf(curbuf, lnum, FALSE);
+}
+
+/*
+ * Return pointer to position "pos".
+ */
+ char_u *
+ml_get_pos(pos_T *pos)
+{
+ return (ml_get_buf(curbuf, pos->lnum, FALSE) + pos->col);
+}
+
+/*
+ * Return pointer to cursor line.
+ */
+ char_u *
+ml_get_curline(void)
+{
+ return ml_get_buf(curbuf, curwin->w_cursor.lnum, FALSE);
+}
+
+/*
+ * Return pointer to cursor position.
+ */
+ char_u *
+ml_get_cursor(void)
+{
+ return (ml_get_buf(curbuf, curwin->w_cursor.lnum, FALSE) +
+ curwin->w_cursor.col);
+}
+
+/*
+ * Return a pointer to a line in a specific buffer
+ *
+ * "will_change": if TRUE mark the buffer dirty (chars in the line will be
+ * changed)
+ */
+ char_u *
+ml_get_buf(
+ buf_T *buf,
+ linenr_T lnum,
+ int will_change) /* line will be changed */
+{
+ bhdr_T *hp;
+ DATA_BL *dp;
+ static int recursive = 0;
+
+ if (lnum > buf->b_ml.ml_line_count) /* invalid line number */
+ {
+ if (recursive == 0)
+ {
+ /* Avoid giving this message for a recursive call, may happen when
+ * the GUI redraws part of the text. */
+ ++recursive;
+ siemsg(_("E315: ml_get: invalid lnum: %ld"), lnum);
+ --recursive;
+ }
+errorret:
+ STRCPY(IObuff, "???");
+ return IObuff;
+ }
+ if (lnum <= 0) /* pretend line 0 is line 1 */
+ lnum = 1;
+
+ if (buf->b_ml.ml_mfp == NULL) /* there are no lines */
+ return (char_u *)"";
+
+ /*
+ * See if it is the same line as requested last time.
+ * Otherwise may need to flush last used line.
+ * Don't use the last used line when 'swapfile' is reset, need to load all
+ * blocks.
+ */
+ if (buf->b_ml.ml_line_lnum != lnum || mf_dont_release)
+ {
+ unsigned start, end;
+ colnr_T len;
+ int idx;
+
+ ml_flush_line(buf);
+
+ /*
+ * Find the data block containing the line.
+ * This also fills the stack with the blocks from the root to the data
+ * block and releases any locked block.
+ */
+ if ((hp = ml_find_line(buf, lnum, ML_FIND)) == NULL)
+ {
+ if (recursive == 0)
+ {
+ /* Avoid giving this message for a recursive call, may happen
+ * when the GUI redraws part of the text. */
+ ++recursive;
+ siemsg(_("E316: ml_get: cannot find line %ld"), lnum);
+ --recursive;
+ }
+ goto errorret;
+ }
+
+ dp = (DATA_BL *)(hp->bh_data);
+
+ idx = lnum - buf->b_ml.ml_locked_low;
+ start = ((dp->db_index[idx]) & DB_INDEX_MASK);
+ // The text ends where the previous line starts. The first line ends
+ // at the end of the block.
+ if (idx == 0)
+ end = dp->db_txt_end;
+ else
+ end = ((dp->db_index[idx - 1]) & DB_INDEX_MASK);
+ len = end - start;
+
+ buf->b_ml.ml_line_ptr = (char_u *)dp + start;
+ buf->b_ml.ml_line_len = len;
+ buf->b_ml.ml_line_lnum = lnum;
+ buf->b_ml.ml_flags &= ~ML_LINE_DIRTY;
+ }
+ if (will_change)
+ buf->b_ml.ml_flags |= (ML_LOCKED_DIRTY | ML_LOCKED_POS);
+
+ return buf->b_ml.ml_line_ptr;
+}
+
+/*
+ * Check if a line that was just obtained by a call to ml_get
+ * is in allocated memory.
+ */
+ int
+ml_line_alloced(void)
+{
+ return (curbuf->b_ml.ml_flags & ML_LINE_DIRTY);
+}
+
+#ifdef FEAT_TEXT_PROP
+ static void
+add_text_props_for_append(
+ buf_T *buf,
+ linenr_T lnum,
+ char_u **line,
+ int *len,
+ char_u **tofree)
+{
+ int round;
+ int new_prop_count = 0;
+ int count;
+ int n;
+ char_u *props;
+ int new_len;
+ char_u *new_line;
+ textprop_T prop;
+
+ // Make two rounds:
+ // 1. calculate the extra space needed
+ // 2. allocate the space and fill it
+ for (round = 1; round <= 2; ++round)
+ {
+ if (round == 2)
+ {
+ if (new_prop_count == 0)
+ return; // nothing to do
+ new_len = *len + new_prop_count * sizeof(textprop_T);
+ new_line = alloc((unsigned)new_len);
+ if (new_line == NULL)
+ return;
+ mch_memmove(new_line, *line, *len);
+ new_prop_count = 0;
+ }
+
+ // Get the line above to find any props that continue in the next
+ // line.
+ count = get_text_props(buf, lnum, &props, FALSE);
+ for (n = 0; n < count; ++n)
+ {
+ mch_memmove(&prop, props + n * sizeof(textprop_T), sizeof(textprop_T));
+ if (prop.tp_flags & TP_FLAG_CONT_NEXT)
+ {
+ if (round == 2)
+ {
+ prop.tp_flags |= TP_FLAG_CONT_PREV;
+ prop.tp_col = 1;
+ prop.tp_len = *len;
+ mch_memmove(new_line + *len + new_prop_count * sizeof(textprop_T), &prop, sizeof(textprop_T));
+ }
+ ++new_prop_count;
+ }
+ }
+ }
+ *line = new_line;
+ *tofree = new_line;
+ *len = new_len;
+}
+#endif
+
+/*
+ * Append a line after lnum (may be 0 to insert a line in front of the file).
+ * "line" does not need to be allocated, but can't be another line in a
+ * buffer, unlocking may make it invalid.
+ *
+ * newfile: TRUE when starting to edit a new file, meaning that pe_old_lnum
+ * will be set for recovery
+ * Check: The caller of this function should probably also call
+ * appended_lines().
+ *
+ * return FAIL for failure, OK otherwise
+ */
+ int
+ml_append(
+ linenr_T lnum, /* append after this line (can be 0) */
+ char_u *line, /* text of the new line */
+ colnr_T len, /* length of new line, including NUL, or 0 */
+ int newfile) /* flag, see above */
+{
+ /* When starting up, we might still need to create the memfile */
+ if (curbuf->b_ml.ml_mfp == NULL && open_buffer(FALSE, NULL, 0) == FAIL)
+ return FAIL;
+
+ if (curbuf->b_ml.ml_line_lnum != 0)
+ ml_flush_line(curbuf);
+ return ml_append_int(curbuf, lnum, line, len, newfile, FALSE);
+}
+
+#if defined(FEAT_SPELL) || defined(FEAT_QUICKFIX) || defined(PROTO)
+/*
+ * Like ml_append() but for an arbitrary buffer. The buffer must already have
+ * a memline.
+ */
+ int
+ml_append_buf(
+ buf_T *buf,
+ linenr_T lnum, /* append after this line (can be 0) */
+ char_u *line, /* text of the new line */
+ colnr_T len, /* length of new line, including NUL, or 0 */
+ int newfile) /* flag, see above */
+{
+ if (buf->b_ml.ml_mfp == NULL)
+ return FAIL;
+
+ if (buf->b_ml.ml_line_lnum != 0)
+ ml_flush_line(buf);
+ return ml_append_int(buf, lnum, line, len, newfile, FALSE);
+}
+#endif
+
+ static int
+ml_append_int(
+ buf_T *buf,
+ linenr_T lnum, // append after this line (can be 0)
+ char_u *line_arg, // text of the new line
+ colnr_T len_arg, // length of line, including NUL, or 0
+ int newfile, // flag, see above
+ int mark) // mark the new line
+{
+ char_u *line = line_arg;
+ colnr_T len = len_arg;
+ int i;
+ int line_count; // number of indexes in current block
+ int offset;
+ int from, to;
+ int space_needed; // space needed for new line
+ int page_size;
+ int page_count;
+ int db_idx; // index for lnum in data block
+ bhdr_T *hp;
+ memfile_T *mfp;
+ DATA_BL *dp;
+ PTR_BL *pp;
+ infoptr_T *ip;
+#ifdef FEAT_TEXT_PROP
+ char_u *tofree = NULL;
+#endif
+ int ret = FAIL;
+
+ if (lnum > buf->b_ml.ml_line_count || buf->b_ml.ml_mfp == NULL)
+ return FAIL; // lnum out of range
+
+ if (lowest_marked && lowest_marked > lnum)
+ lowest_marked = lnum + 1;
+
+ if (len == 0)
+ len = (colnr_T)STRLEN(line) + 1; // space needed for the text
+
+#ifdef FEAT_TEXT_PROP
+ if (curbuf->b_has_textprop && lnum > 0)
+ // Add text properties that continue from the previous line.
+ add_text_props_for_append(buf, lnum, &line, &len, &tofree);
+#endif
+
+ space_needed = len + INDEX_SIZE; // space needed for text + index
+
+ mfp = buf->b_ml.ml_mfp;
+ page_size = mfp->mf_page_size;
+
+/*
+ * find the data block containing the previous line
+ * This also fills the stack with the blocks from the root to the data block
+ * This also releases any locked block.
+ */
+ if ((hp = ml_find_line(buf, lnum == 0 ? (linenr_T)1 : lnum,
+ ML_INSERT)) == NULL)
+ goto theend;
+
+ buf->b_ml.ml_flags &= ~ML_EMPTY;
+
+ if (lnum == 0) /* got line one instead, correct db_idx */
+ db_idx = -1; /* careful, it is negative! */
+ else
+ db_idx = lnum - buf->b_ml.ml_locked_low;
+ /* get line count before the insertion */
+ line_count = buf->b_ml.ml_locked_high - buf->b_ml.ml_locked_low;
+
+ dp = (DATA_BL *)(hp->bh_data);
+
+/*
+ * If
+ * - there is not enough room in the current block
+ * - appending to the last line in the block
+ * - not appending to the last line in the file
+ * insert in front of the next block.
+ */
+ if ((int)dp->db_free < space_needed && db_idx == line_count - 1
+ && lnum < buf->b_ml.ml_line_count)
+ {
+ /*
+ * Now that the line is not going to be inserted in the block that we
+ * expected, the line count has to be adjusted in the pointer blocks
+ * by using ml_locked_lineadd.
+ */
+ --(buf->b_ml.ml_locked_lineadd);
+ --(buf->b_ml.ml_locked_high);
+ if ((hp = ml_find_line(buf, lnum + 1, ML_INSERT)) == NULL)
+ goto theend;
+
+ db_idx = -1; /* careful, it is negative! */
+ /* get line count before the insertion */
+ line_count = buf->b_ml.ml_locked_high - buf->b_ml.ml_locked_low;
+ CHECK(buf->b_ml.ml_locked_low != lnum + 1, "locked_low != lnum + 1");
+
+ dp = (DATA_BL *)(hp->bh_data);
+ }
+
+ ++buf->b_ml.ml_line_count;
+
+ if ((int)dp->db_free >= space_needed) /* enough room in data block */
+ {
+ /*
+ * Insert the new line in an existing data block, or in the data block
+ * allocated above.
+ */
+ dp->db_txt_start -= len;
+ dp->db_free -= space_needed;
+ ++(dp->db_line_count);
+
+ /*
+ * move the text of the lines that follow to the front
+ * adjust the indexes of the lines that follow
+ */
+ if (line_count > db_idx + 1) /* if there are following lines */
+ {
+ /*
+ * Offset is the start of the previous line.
+ * This will become the character just after the new line.
+ */
+ if (db_idx < 0)
+ offset = dp->db_txt_end;
+ else
+ offset = ((dp->db_index[db_idx]) & DB_INDEX_MASK);
+ mch_memmove((char *)dp + dp->db_txt_start,
+ (char *)dp + dp->db_txt_start + len,
+ (size_t)(offset - (dp->db_txt_start + len)));
+ for (i = line_count - 1; i > db_idx; --i)
+ dp->db_index[i + 1] = dp->db_index[i] - len;
+ dp->db_index[db_idx + 1] = offset - len;
+ }
+ else
+ // add line at the end (which is the start of the text)
+ dp->db_index[db_idx + 1] = dp->db_txt_start;
+
+ /*
+ * copy the text into the block
+ */
+ mch_memmove((char *)dp + dp->db_index[db_idx + 1], line, (size_t)len);
+ if (mark)
+ dp->db_index[db_idx + 1] |= DB_MARKED;
+
+ /*
+ * Mark the block dirty.
+ */
+ buf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
+ if (!newfile)
+ buf->b_ml.ml_flags |= ML_LOCKED_POS;
+ }
+ else /* not enough space in data block */
+ {
+ long line_count_left, line_count_right;
+ int page_count_left, page_count_right;
+ bhdr_T *hp_left;
+ bhdr_T *hp_right;
+ bhdr_T *hp_new;
+ int lines_moved;
+ int data_moved = 0; /* init to shut up gcc */
+ int total_moved = 0; /* init to shut up gcc */
+ DATA_BL *dp_right, *dp_left;
+ int stack_idx;
+ int in_left;
+ int lineadd;
+ blocknr_T bnum_left, bnum_right;
+ linenr_T lnum_left, lnum_right;
+ int pb_idx;
+ PTR_BL *pp_new;
+
+ /*
+ * There is not enough room, we have to create a new data block and
+ * copy some lines into it.
+ * Then we have to insert an entry in the pointer block.
+ * If this pointer block also is full, we go up another block, and so
+ * on, up to the root if necessary.
+ * The line counts in the pointer blocks have already been adjusted by
+ * ml_find_line().
+ *
+ * We are going to allocate a new data block. Depending on the
+ * situation it will be put to the left or right of the existing
+ * block. If possible we put the new line in the left block and move
+ * the lines after it to the right block. Otherwise the new line is
+ * also put in the right block. This method is more efficient when
+ * inserting a lot of lines at one place.
+ */
+ if (db_idx < 0) /* left block is new, right block is existing */
+ {
+ lines_moved = 0;
+ in_left = TRUE;
+ /* space_needed does not change */
+ }
+ else /* left block is existing, right block is new */
+ {
+ lines_moved = line_count - db_idx - 1;
+ if (lines_moved == 0)
+ in_left = FALSE; /* put new line in right block */
+ /* space_needed does not change */
+ else
+ {
+ data_moved = ((dp->db_index[db_idx]) & DB_INDEX_MASK) -
+ dp->db_txt_start;
+ total_moved = data_moved + lines_moved * INDEX_SIZE;
+ if ((int)dp->db_free + total_moved >= space_needed)
+ {
+ in_left = TRUE; /* put new line in left block */
+ space_needed = total_moved;
+ }
+ else
+ {
+ in_left = FALSE; /* put new line in right block */
+ space_needed += total_moved;
+ }
+ }
+ }
+
+ page_count = ((space_needed + HEADER_SIZE) + page_size - 1) / page_size;
+ if ((hp_new = ml_new_data(mfp, newfile, page_count)) == NULL)
+ {
+ /* correct line counts in pointer blocks */
+ --(buf->b_ml.ml_locked_lineadd);
+ --(buf->b_ml.ml_locked_high);
+ goto theend;
+ }
+ if (db_idx < 0) /* left block is new */
+ {
+ hp_left = hp_new;
+ hp_right = hp;
+ line_count_left = 0;
+ line_count_right = line_count;
+ }
+ else /* right block is new */
+ {
+ hp_left = hp;
+ hp_right = hp_new;
+ line_count_left = line_count;
+ line_count_right = 0;
+ }
+ dp_right = (DATA_BL *)(hp_right->bh_data);
+ dp_left = (DATA_BL *)(hp_left->bh_data);
+ bnum_left = hp_left->bh_bnum;
+ bnum_right = hp_right->bh_bnum;
+ page_count_left = hp_left->bh_page_count;
+ page_count_right = hp_right->bh_page_count;
+
+ /*
+ * May move the new line into the right/new block.
+ */
+ if (!in_left)
+ {
+ dp_right->db_txt_start -= len;
+ dp_right->db_free -= len + INDEX_SIZE;
+ dp_right->db_index[0] = dp_right->db_txt_start;
+ if (mark)
+ dp_right->db_index[0] |= DB_MARKED;
+
+ mch_memmove((char *)dp_right + dp_right->db_txt_start,
+ line, (size_t)len);
+ ++line_count_right;
+ }
+ /*
+ * may move lines from the left/old block to the right/new one.
+ */
+ if (lines_moved)
+ {
+ /*
+ */
+ dp_right->db_txt_start -= data_moved;
+ dp_right->db_free -= total_moved;
+ mch_memmove((char *)dp_right + dp_right->db_txt_start,
+ (char *)dp_left + dp_left->db_txt_start,
+ (size_t)data_moved);
+ offset = dp_right->db_txt_start - dp_left->db_txt_start;
+ dp_left->db_txt_start += data_moved;
+ dp_left->db_free += total_moved;
+
+ /*
+ * update indexes in the new block
+ */
+ for (to = line_count_right, from = db_idx + 1;
+ from < line_count_left; ++from, ++to)
+ dp_right->db_index[to] = dp->db_index[from] + offset;
+ line_count_right += lines_moved;
+ line_count_left -= lines_moved;
+ }
+
+ /*
+ * May move the new line into the left (old or new) block.
+ */
+ if (in_left)
+ {
+ dp_left->db_txt_start -= len;
+ dp_left->db_free -= len + INDEX_SIZE;
+ dp_left->db_index[line_count_left] = dp_left->db_txt_start;
+ if (mark)
+ dp_left->db_index[line_count_left] |= DB_MARKED;
+ mch_memmove((char *)dp_left + dp_left->db_txt_start,
+ line, (size_t)len);
+ ++line_count_left;
+ }
+
+ if (db_idx < 0) /* left block is new */
+ {
+ lnum_left = lnum + 1;
+ lnum_right = 0;
+ }
+ else /* right block is new */
+ {
+ lnum_left = 0;
+ if (in_left)
+ lnum_right = lnum + 2;
+ else
+ lnum_right = lnum + 1;
+ }
+ dp_left->db_line_count = line_count_left;
+ dp_right->db_line_count = line_count_right;
+
+ /*
+ * release the two data blocks
+ * The new one (hp_new) already has a correct blocknumber.
+ * The old one (hp, in ml_locked) gets a positive blocknumber if
+ * we changed it and we are not editing a new file.
+ */
+ if (lines_moved || in_left)
+ buf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
+ if (!newfile && db_idx >= 0 && in_left)
+ buf->b_ml.ml_flags |= ML_LOCKED_POS;
+ mf_put(mfp, hp_new, TRUE, FALSE);
+
+ /*
+ * flush the old data block
+ * set ml_locked_lineadd to 0, because the updating of the
+ * pointer blocks is done below
+ */
+ lineadd = buf->b_ml.ml_locked_lineadd;
+ buf->b_ml.ml_locked_lineadd = 0;
+ ml_find_line(buf, (linenr_T)0, ML_FLUSH); /* flush data block */
+
+ /*
+ * update pointer blocks for the new data block
+ */
+ for (stack_idx = buf->b_ml.ml_stack_top - 1; stack_idx >= 0;
+ --stack_idx)
+ {
+ ip = &(buf->b_ml.ml_stack[stack_idx]);
+ pb_idx = ip->ip_index;
+ if ((hp = mf_get(mfp, ip->ip_bnum, 1)) == NULL)
+ goto theend;
+ pp = (PTR_BL *)(hp->bh_data); /* must be pointer block */
+ if (pp->pb_id != PTR_ID)
+ {
+ iemsg(_("E317: pointer block id wrong 3"));
+ mf_put(mfp, hp, FALSE, FALSE);
+ goto theend;
+ }
+ /*
+ * TODO: If the pointer block is full and we are adding at the end
+ * try to insert in front of the next block
+ */
+ /* block not full, add one entry */
+ if (pp->pb_count < pp->pb_count_max)
+ {
+ if (pb_idx + 1 < (int)pp->pb_count)
+ mch_memmove(&pp->pb_pointer[pb_idx + 2],
+ &pp->pb_pointer[pb_idx + 1],
+ (size_t)(pp->pb_count - pb_idx - 1) * sizeof(PTR_EN));
+ ++pp->pb_count;
+ pp->pb_pointer[pb_idx].pe_line_count = line_count_left;
+ pp->pb_pointer[pb_idx].pe_bnum = bnum_left;
+ pp->pb_pointer[pb_idx].pe_page_count = page_count_left;
+ pp->pb_pointer[pb_idx + 1].pe_line_count = line_count_right;
+ pp->pb_pointer[pb_idx + 1].pe_bnum = bnum_right;
+ pp->pb_pointer[pb_idx + 1].pe_page_count = page_count_right;
+
+ if (lnum_left != 0)
+ pp->pb_pointer[pb_idx].pe_old_lnum = lnum_left;
+ if (lnum_right != 0)
+ pp->pb_pointer[pb_idx + 1].pe_old_lnum = lnum_right;
+
+ mf_put(mfp, hp, TRUE, FALSE);
+ buf->b_ml.ml_stack_top = stack_idx + 1; /* truncate stack */
+
+ if (lineadd)
+ {
+ --(buf->b_ml.ml_stack_top);
+ /* fix line count for rest of blocks in the stack */
+ ml_lineadd(buf, lineadd);
+ /* fix stack itself */
+ buf->b_ml.ml_stack[buf->b_ml.ml_stack_top].ip_high +=
+ lineadd;
+ ++(buf->b_ml.ml_stack_top);
+ }
+
+ /*
+ * We are finished, break the loop here.
+ */
+ break;
+ }
+ else /* pointer block full */
+ {
+ /*
+ * split the pointer block
+ * allocate a new pointer block
+ * move some of the pointer into the new block
+ * prepare for updating the parent block
+ */
+ for (;;) /* do this twice when splitting block 1 */
+ {
+ hp_new = ml_new_ptr(mfp);
+ if (hp_new == NULL) /* TODO: try to fix tree */
+ goto theend;
+ pp_new = (PTR_BL *)(hp_new->bh_data);
+
+ if (hp->bh_bnum != 1)
+ break;
+
+ /*
+ * if block 1 becomes full the tree is given an extra level
+ * The pointers from block 1 are moved into the new block.
+ * block 1 is updated to point to the new block
+ * then continue to split the new block
+ */
+ mch_memmove(pp_new, pp, (size_t)page_size);
+ pp->pb_count = 1;
+ pp->pb_pointer[0].pe_bnum = hp_new->bh_bnum;
+ pp->pb_pointer[0].pe_line_count = buf->b_ml.ml_line_count;
+ pp->pb_pointer[0].pe_old_lnum = 1;
+ pp->pb_pointer[0].pe_page_count = 1;
+ mf_put(mfp, hp, TRUE, FALSE); /* release block 1 */
+ hp = hp_new; /* new block is to be split */
+ pp = pp_new;
+ CHECK(stack_idx != 0, _("stack_idx should be 0"));
+ ip->ip_index = 0;
+ ++stack_idx; /* do block 1 again later */
+ }
+ /*
+ * move the pointers after the current one to the new block
+ * If there are none, the new entry will be in the new block.
+ */
+ total_moved = pp->pb_count - pb_idx - 1;
+ if (total_moved)
+ {
+ mch_memmove(&pp_new->pb_pointer[0],
+ &pp->pb_pointer[pb_idx + 1],
+ (size_t)(total_moved) * sizeof(PTR_EN));
+ pp_new->pb_count = total_moved;
+ pp->pb_count -= total_moved - 1;
+ pp->pb_pointer[pb_idx + 1].pe_bnum = bnum_right;
+ pp->pb_pointer[pb_idx + 1].pe_line_count = line_count_right;
+ pp->pb_pointer[pb_idx + 1].pe_page_count = page_count_right;
+ if (lnum_right)
+ pp->pb_pointer[pb_idx + 1].pe_old_lnum = lnum_right;
+ }
+ else
+ {
+ pp_new->pb_count = 1;
+ pp_new->pb_pointer[0].pe_bnum = bnum_right;
+ pp_new->pb_pointer[0].pe_line_count = line_count_right;
+ pp_new->pb_pointer[0].pe_page_count = page_count_right;
+ pp_new->pb_pointer[0].pe_old_lnum = lnum_right;
+ }
+ pp->pb_pointer[pb_idx].pe_bnum = bnum_left;
+ pp->pb_pointer[pb_idx].pe_line_count = line_count_left;
+ pp->pb_pointer[pb_idx].pe_page_count = page_count_left;
+ if (lnum_left)
+ pp->pb_pointer[pb_idx].pe_old_lnum = lnum_left;
+ lnum_left = 0;
+ lnum_right = 0;
+
+ /*
+ * recompute line counts
+ */
+ line_count_right = 0;
+ for (i = 0; i < (int)pp_new->pb_count; ++i)
+ line_count_right += pp_new->pb_pointer[i].pe_line_count;
+ line_count_left = 0;
+ for (i = 0; i < (int)pp->pb_count; ++i)
+ line_count_left += pp->pb_pointer[i].pe_line_count;
+
+ bnum_left = hp->bh_bnum;
+ bnum_right = hp_new->bh_bnum;
+ page_count_left = 1;
+ page_count_right = 1;
+ mf_put(mfp, hp, TRUE, FALSE);
+ mf_put(mfp, hp_new, TRUE, FALSE);
+ }
+ }
+
+ /*
+ * Safety check: fallen out of for loop?
+ */
+ if (stack_idx < 0)
+ {
+ iemsg(_("E318: Updated too many blocks?"));
+ buf->b_ml.ml_stack_top = 0; /* invalidate stack */
+ }
+ }
+
+#ifdef FEAT_BYTEOFF
+ /* The line was inserted below 'lnum' */
+ ml_updatechunk(buf, lnum + 1, (long)len, ML_CHNK_ADDLINE);
+#endif
+#ifdef FEAT_NETBEANS_INTG
+ if (netbeans_active())
+ {
+ if (STRLEN(line) > 0)
+ netbeans_inserted(buf, lnum+1, (colnr_T)0, line, (int)STRLEN(line));
+ netbeans_inserted(buf, lnum+1, (colnr_T)STRLEN(line),
+ (char_u *)"\n", 1);
+ }
+#endif
+#ifdef FEAT_JOB_CHANNEL
+ if (buf->b_write_to_channel)
+ channel_write_new_lines(buf);
+#endif
+ ret = OK;
+
+theend:
+#ifdef FEAT_TEXT_PROP
+ vim_free(tofree);
+#endif
+ return ret;
+}
+
+/*
+ * Replace line lnum, with buffering, in current buffer.
+ *
+ * If "copy" is TRUE, make a copy of the line, otherwise the line has been
+ * copied to allocated memory already.
+ *
+ * Check: The caller of this function should probably also call
+ * changed_lines(), unless update_screen(NOT_VALID) is used.
+ *
+ * return FAIL for failure, OK otherwise
+ */
+ int
+ml_replace(linenr_T lnum, char_u *line, int copy)
+{
+ colnr_T len = -1;
+
+ if (line != NULL)
+ len = (colnr_T)STRLEN(line);
+ return ml_replace_len(lnum, line, len, FALSE, copy);
+}
+
+/*
+ * Replace a line for the current buffer. Like ml_replace() with:
+ * "len_arg" is the length of the text, excluding NUL.
+ * If "has_props" is TRUE then "line_arg" includes the text properties and
+ * "len_arg" includes the NUL of the text.
+ */
+ int
+ml_replace_len(
+ linenr_T lnum,
+ char_u *line_arg,
+ colnr_T len_arg,
+ int has_props,
+ int copy)
+{
+ char_u *line = line_arg;
+ colnr_T len = len_arg;
+
+ if (line == NULL) /* just checking... */
+ return FAIL;
+
+ /* When starting up, we might still need to create the memfile */
+ if (curbuf->b_ml.ml_mfp == NULL && open_buffer(FALSE, NULL, 0) == FAIL)
+ return FAIL;
+
+ if (!has_props)
+ ++len; // include the NUL after the text
+ if (copy)
+ {
+ // copy the line to allocated memory
+#ifdef FEAT_TEXT_PROP
+ if (has_props)
+ line = vim_memsave(line, len);
+ else
+#endif
+ line = vim_strnsave(line, len - 1);
+ if (line == NULL)
+ return FAIL;
+ }
+
+#ifdef FEAT_NETBEANS_INTG
+ if (netbeans_active())
+ {
+ netbeans_removed(curbuf, lnum, 0, (long)STRLEN(ml_get(lnum)));
+ netbeans_inserted(curbuf, lnum, 0, line, (int)STRLEN(line));
+ }
+#endif
+ if (curbuf->b_ml.ml_line_lnum != lnum)
+ {
+ // another line is buffered, flush it
+ ml_flush_line(curbuf);
+ curbuf->b_ml.ml_flags &= ~ML_LINE_DIRTY;
+
+#ifdef FEAT_TEXT_PROP
+ if (curbuf->b_has_textprop && !has_props)
+ // Need to fetch the old line to copy over any text properties.
+ ml_get_buf(curbuf, lnum, TRUE);
+#endif
+ }
+
+#ifdef FEAT_TEXT_PROP
+ if (curbuf->b_has_textprop && !has_props)
+ {
+ size_t oldtextlen = STRLEN(curbuf->b_ml.ml_line_ptr) + 1;
+
+ if (oldtextlen < (size_t)curbuf->b_ml.ml_line_len)
+ {
+ char_u *newline;
+ size_t textproplen = curbuf->b_ml.ml_line_len - oldtextlen;
+
+ // Need to copy over text properties, stored after the text.
+ newline = alloc(len + (int)textproplen);
+ if (newline != NULL)
+ {
+ mch_memmove(newline, line, len);
+ mch_memmove(newline + len, curbuf->b_ml.ml_line_ptr + oldtextlen, textproplen);
+ vim_free(line);
+ line = newline;
+ len += (colnr_T)textproplen;
+ }
+ }
+ }
+#endif
+
+ if (curbuf->b_ml.ml_flags & ML_LINE_DIRTY) // same line allocated
+ vim_free(curbuf->b_ml.ml_line_ptr); // free it
+
+ curbuf->b_ml.ml_line_ptr = line;
+ curbuf->b_ml.ml_line_len = len;
+ curbuf->b_ml.ml_line_lnum = lnum;
+ curbuf->b_ml.ml_flags = (curbuf->b_ml.ml_flags | ML_LINE_DIRTY) & ~ML_EMPTY;
+
+ return OK;
+}
+
+#ifdef FEAT_TEXT_PROP
+/*
+ * Adjust text properties in line "lnum" for a deleted line.
+ * When "above" is true this is the line above the deleted line.
+ * "del_props" are the properties of the deleted line.
+ */
+ static void
+adjust_text_props_for_delete(
+ buf_T *buf,
+ linenr_T lnum,
+ char_u *del_props,
+ int del_props_len,
+ int above)
+{
+ int did_get_line = FALSE;
+ int done_del;
+ int done_this;
+ textprop_T prop_del;
+ textprop_T prop_this;
+ bhdr_T *hp;
+ DATA_BL *dp;
+ int idx;
+ int line_start;
+ long line_size;
+ int this_props_len;
+ char_u *text;
+ size_t textlen;
+ int found;
+
+ for (done_del = 0; done_del < del_props_len; done_del += sizeof(textprop_T))
+ {
+ mch_memmove(&prop_del, del_props + done_del, sizeof(textprop_T));
+ if ((above && (prop_del.tp_flags & TP_FLAG_CONT_PREV)
+ && !(prop_del.tp_flags & TP_FLAG_CONT_NEXT))
+ || (!above && (prop_del.tp_flags & TP_FLAG_CONT_NEXT)
+ && !(prop_del.tp_flags & TP_FLAG_CONT_PREV)))
+ {
+ if (!did_get_line)
+ {
+ did_get_line = TRUE;
+ if ((hp = ml_find_line(buf, lnum, ML_FIND)) == NULL)
+ return;
+
+ dp = (DATA_BL *)(hp->bh_data);
+ idx = lnum - buf->b_ml.ml_locked_low;
+ line_start = ((dp->db_index[idx]) & DB_INDEX_MASK);
+ if (idx == 0) // first line in block, text at the end
+ line_size = dp->db_txt_end - line_start;
+ else
+ line_size = ((dp->db_index[idx - 1]) & DB_INDEX_MASK) - line_start;
+ text = (char_u *)dp + line_start;
+ textlen = STRLEN(text) + 1;
+ if ((long)textlen >= line_size)
+ {
+ if (above)
+ internal_error("no text property above deleted line");
+ else
+ internal_error("no text property below deleted line");
+ return;
+ }
+ this_props_len = line_size - (int)textlen;
+ }
+
+ found = FALSE;
+ for (done_this = 0; done_this < this_props_len; done_this += sizeof(textprop_T))
+ {
+ mch_memmove(&prop_this, text + textlen + done_del, sizeof(textprop_T));
+ if (prop_del.tp_id == prop_this.tp_id
+ && prop_del.tp_type == prop_this.tp_type)
+ {
+ int flag = above ? TP_FLAG_CONT_NEXT : TP_FLAG_CONT_PREV;
+
+ found = TRUE;
+ if (prop_this.tp_flags & flag)
+ {
+ prop_this.tp_flags &= ~flag;
+ mch_memmove(text + textlen + done_del, &prop_this, sizeof(textprop_T));
+ }
+ else if (above)
+ internal_error("text property above deleted line does not continue");
+ else
+ internal_error("text property below deleted line does not continue");
+ }
+ }
+ if (!found)
+ {
+ if (above)
+ internal_error("text property above deleted line not found");
+ else
+ internal_error("text property below deleted line not found");
+ }
+
+ buf->b_ml.ml_flags |= (ML_LOCKED_DIRTY | ML_LOCKED_POS);
+ }
+ }
+}
+#endif
+
+/*
+ * Delete line "lnum" in the current buffer.
+ * When "message" is TRUE may give a "No lines in buffer" message.
+ *
+ * Check: The caller of this function should probably also call
+ * deleted_lines() after this.
+ *
+ * return FAIL for failure, OK otherwise
+ */
+ int
+ml_delete(linenr_T lnum, int message)
+{
+ ml_flush_line(curbuf);
+ return ml_delete_int(curbuf, lnum, message);
+}
+
+ static int
+ml_delete_int(buf_T *buf, linenr_T lnum, int message)
+{
+ bhdr_T *hp;
+ memfile_T *mfp;
+ DATA_BL *dp;
+ PTR_BL *pp;
+ infoptr_T *ip;
+ int count; /* number of entries in block */
+ int idx;
+ int stack_idx;
+ int text_start;
+ int line_start;
+ long line_size;
+ int i;
+ int ret = FAIL;
+#ifdef FEAT_TEXT_PROP
+ char_u *textprop_save = NULL;
+ int textprop_save_len;
+#endif
+
+ if (lnum < 1 || lnum > buf->b_ml.ml_line_count)
+ return FAIL;
+
+ if (lowest_marked && lowest_marked > lnum)
+ lowest_marked--;
+
+/*
+ * If the file becomes empty the last line is replaced by an empty line.
+ */
+ if (buf->b_ml.ml_line_count == 1) /* file becomes empty */
+ {
+ if (message
+#ifdef FEAT_NETBEANS_INTG
+ && !netbeansSuppressNoLines
+#endif
+ )
+ set_keep_msg((char_u *)_(no_lines_msg), 0);
+
+ /* FEAT_BYTEOFF already handled in there, don't worry 'bout it below */
+ i = ml_replace((linenr_T)1, (char_u *)"", TRUE);
+ buf->b_ml.ml_flags |= ML_EMPTY;
+
+ return i;
+ }
+
+/*
+ * Find the data block containing the line.
+ * This also fills the stack with the blocks from the root to the data block.
+ * This also releases any locked block..
+ */
+ mfp = buf->b_ml.ml_mfp;
+ if (mfp == NULL)
+ return FAIL;
+
+ if ((hp = ml_find_line(buf, lnum, ML_DELETE)) == NULL)
+ return FAIL;
+
+ dp = (DATA_BL *)(hp->bh_data);
+ /* compute line count before the delete */
+ count = (long)(buf->b_ml.ml_locked_high)
+ - (long)(buf->b_ml.ml_locked_low) + 2;
+ idx = lnum - buf->b_ml.ml_locked_low;
+
+ --buf->b_ml.ml_line_count;
+
+ line_start = ((dp->db_index[idx]) & DB_INDEX_MASK);
+ if (idx == 0) /* first line in block, text at the end */
+ line_size = dp->db_txt_end - line_start;
+ else
+ line_size = ((dp->db_index[idx - 1]) & DB_INDEX_MASK) - line_start;
+
+#ifdef FEAT_NETBEANS_INTG
+ if (netbeans_active())
+ netbeans_removed(buf, lnum, 0, (long)line_size);
+#endif
+#ifdef FEAT_TEXT_PROP
+ // If there are text properties, make a copy, so that we can update
+ // properties in preceding and following lines.
+ if (buf->b_has_textprop)
+ {
+ size_t textlen = STRLEN((char_u *)dp + line_start) + 1;
+
+ if ((long)textlen < line_size)
+ {
+ textprop_save_len = line_size - (int)textlen;
+ textprop_save = vim_memsave((char_u *)dp + line_start + textlen,
+ textprop_save_len);
+ }
+ }
+#endif
+
+/*
+ * special case: If there is only one line in the data block it becomes empty.
+ * Then we have to remove the entry, pointing to this data block, from the
+ * pointer block. If this pointer block also becomes empty, we go up another
+ * block, and so on, up to the root if necessary.
+ * The line counts in the pointer blocks have already been adjusted by
+ * ml_find_line().
+ */
+ if (count == 1)
+ {
+ mf_free(mfp, hp); /* free the data block */
+ buf->b_ml.ml_locked = NULL;
+
+ for (stack_idx = buf->b_ml.ml_stack_top - 1; stack_idx >= 0;
+ --stack_idx)
+ {
+ buf->b_ml.ml_stack_top = 0; /* stack is invalid when failing */
+ ip = &(buf->b_ml.ml_stack[stack_idx]);
+ idx = ip->ip_index;
+ if ((hp = mf_get(mfp, ip->ip_bnum, 1)) == NULL)
+ goto theend;
+ pp = (PTR_BL *)(hp->bh_data); /* must be pointer block */
+ if (pp->pb_id != PTR_ID)
+ {
+ iemsg(_("E317: pointer block id wrong 4"));
+ mf_put(mfp, hp, FALSE, FALSE);
+ goto theend;
+ }
+ count = --(pp->pb_count);
+ if (count == 0) /* the pointer block becomes empty! */
+ mf_free(mfp, hp);
+ else
+ {
+ if (count != idx) /* move entries after the deleted one */
+ mch_memmove(&pp->pb_pointer[idx], &pp->pb_pointer[idx + 1],
+ (size_t)(count - idx) * sizeof(PTR_EN));
+ mf_put(mfp, hp, TRUE, FALSE);
+
+ buf->b_ml.ml_stack_top = stack_idx; /* truncate stack */
+ /* fix line count for rest of blocks in the stack */
+ if (buf->b_ml.ml_locked_lineadd != 0)
+ {
+ ml_lineadd(buf, buf->b_ml.ml_locked_lineadd);
+ buf->b_ml.ml_stack[buf->b_ml.ml_stack_top].ip_high +=
+ buf->b_ml.ml_locked_lineadd;
+ }
+ ++(buf->b_ml.ml_stack_top);
+
+ break;
+ }
+ }
+ CHECK(stack_idx < 0, _("deleted block 1?"));
+ }
+ else
+ {
+ /*
+ * delete the text by moving the next lines forwards
+ */
+ text_start = dp->db_txt_start;
+ mch_memmove((char *)dp + text_start + line_size,
+ (char *)dp + text_start, (size_t)(line_start - text_start));
+
+ /*
+ * delete the index by moving the next indexes backwards
+ * Adjust the indexes for the text movement.
+ */
+ for (i = idx; i < count - 1; ++i)
+ dp->db_index[i] = dp->db_index[i + 1] + line_size;
+
+ dp->db_free += line_size + INDEX_SIZE;
+ dp->db_txt_start += line_size;
+ --(dp->db_line_count);
+
+ /*
+ * mark the block dirty and make sure it is in the file (for recovery)
+ */
+ buf->b_ml.ml_flags |= (ML_LOCKED_DIRTY | ML_LOCKED_POS);
+ }
+
+#ifdef FEAT_BYTEOFF
+ ml_updatechunk(buf, lnum, line_size, ML_CHNK_DELLINE);
+#endif
+ ret = OK;
+
+theend:
+#ifdef FEAT_TEXT_PROP
+ if (textprop_save != NULL)
+ {
+ // Adjust text properties in the line above and below.
+ if (lnum > 1)
+ adjust_text_props_for_delete(buf, lnum - 1, textprop_save, textprop_save_len, TRUE);
+ if (lnum <= buf->b_ml.ml_line_count)
+ adjust_text_props_for_delete(buf, lnum, textprop_save, textprop_save_len, FALSE);
+ }
+ vim_free(textprop_save);
+#endif
+ return ret;
+}
+
+/*
+ * set the DB_MARKED flag for line 'lnum'
+ */
+ void
+ml_setmarked(linenr_T lnum)
+{
+ bhdr_T *hp;
+ DATA_BL *dp;
+ /* invalid line number */
+ if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count
+ || curbuf->b_ml.ml_mfp == NULL)
+ return; /* give error message? */
+
+ if (lowest_marked == 0 || lowest_marked > lnum)
+ lowest_marked = lnum;
+
+ /*
+ * find the data block containing the line
+ * This also fills the stack with the blocks from the root to the data block
+ * This also releases any locked block.
+ */
+ if ((hp = ml_find_line(curbuf, lnum, ML_FIND)) == NULL)
+ return; /* give error message? */
+
+ dp = (DATA_BL *)(hp->bh_data);
+ dp->db_index[lnum - curbuf->b_ml.ml_locked_low] |= DB_MARKED;
+ curbuf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
+}
+
+/*
+ * find the first line with its DB_MARKED flag set
+ */
+ linenr_T
+ml_firstmarked(void)
+{
+ bhdr_T *hp;
+ DATA_BL *dp;
+ linenr_T lnum;
+ int i;
+
+ if (curbuf->b_ml.ml_mfp == NULL)
+ return (linenr_T) 0;
+
+ /*
+ * The search starts with lowest_marked line. This is the last line where
+ * a mark was found, adjusted by inserting/deleting lines.
+ */
+ for (lnum = lowest_marked; lnum <= curbuf->b_ml.ml_line_count; )
+ {
+ /*
+ * Find the data block containing the line.
+ * This also fills the stack with the blocks from the root to the data
+ * block This also releases any locked block.
+ */
+ if ((hp = ml_find_line(curbuf, lnum, ML_FIND)) == NULL)
+ return (linenr_T)0; /* give error message? */
+
+ dp = (DATA_BL *)(hp->bh_data);
+
+ for (i = lnum - curbuf->b_ml.ml_locked_low;
+ lnum <= curbuf->b_ml.ml_locked_high; ++i, ++lnum)
+ if ((dp->db_index[i]) & DB_MARKED)
+ {
+ (dp->db_index[i]) &= DB_INDEX_MASK;
+ curbuf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
+ lowest_marked = lnum + 1;
+ return lnum;
+ }
+ }
+
+ return (linenr_T) 0;
+}
+
+/*
+ * clear all DB_MARKED flags
+ */
+ void
+ml_clearmarked(void)
+{
+ bhdr_T *hp;
+ DATA_BL *dp;
+ linenr_T lnum;
+ int i;
+
+ if (curbuf->b_ml.ml_mfp == NULL) /* nothing to do */
+ return;
+
+ /*
+ * The search starts with line lowest_marked.
+ */
+ for (lnum = lowest_marked; lnum <= curbuf->b_ml.ml_line_count; )
+ {
+ /*
+ * Find the data block containing the line.
+ * This also fills the stack with the blocks from the root to the data
+ * block and releases any locked block.
+ */
+ if ((hp = ml_find_line(curbuf, lnum, ML_FIND)) == NULL)
+ return; /* give error message? */
+
+ dp = (DATA_BL *)(hp->bh_data);
+
+ for (i = lnum - curbuf->b_ml.ml_locked_low;
+ lnum <= curbuf->b_ml.ml_locked_high; ++i, ++lnum)
+ if ((dp->db_index[i]) & DB_MARKED)
+ {
+ (dp->db_index[i]) &= DB_INDEX_MASK;
+ curbuf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
+ }
+ }
+
+ lowest_marked = 0;
+ return;
+}
+
+/*
+ * flush ml_line if necessary
+ */
+ static void
+ml_flush_line(buf_T *buf)
+{
+ bhdr_T *hp;
+ DATA_BL *dp;
+ linenr_T lnum;
+ char_u *new_line;
+ char_u *old_line;
+ colnr_T new_len;
+ int old_len;
+ int extra;
+ int idx;
+ int start;
+ int count;
+ int i;
+ static int entered = FALSE;
+
+ if (buf->b_ml.ml_line_lnum == 0 || buf->b_ml.ml_mfp == NULL)
+ return; /* nothing to do */
+
+ if (buf->b_ml.ml_flags & ML_LINE_DIRTY)
+ {
+ /* This code doesn't work recursively, but Netbeans may call back here
+ * when obtaining the cursor position. */
+ if (entered)
+ return;
+ entered = TRUE;
+
+ lnum = buf->b_ml.ml_line_lnum;
+ new_line = buf->b_ml.ml_line_ptr;
+
+ hp = ml_find_line(buf, lnum, ML_FIND);
+ if (hp == NULL)
+ siemsg(_("E320: Cannot find line %ld"), lnum);
+ else
+ {
+ dp = (DATA_BL *)(hp->bh_data);
+ idx = lnum - buf->b_ml.ml_locked_low;
+ start = ((dp->db_index[idx]) & DB_INDEX_MASK);
+ old_line = (char_u *)dp + start;
+ if (idx == 0) /* line is last in block */
+ old_len = dp->db_txt_end - start;
+ else /* text of previous line follows */
+ old_len = (dp->db_index[idx - 1] & DB_INDEX_MASK) - start;
+ new_len = buf->b_ml.ml_line_len;
+ extra = new_len - old_len; /* negative if lines gets smaller */
+
+ /*
+ * if new line fits in data block, replace directly
+ */
+ if ((int)dp->db_free >= extra)
+ {
+ /* if the length changes and there are following lines */
+ count = buf->b_ml.ml_locked_high - buf->b_ml.ml_locked_low + 1;
+ if (extra != 0 && idx < count - 1)
+ {
+ /* move text of following lines */
+ mch_memmove((char *)dp + dp->db_txt_start - extra,
+ (char *)dp + dp->db_txt_start,
+ (size_t)(start - dp->db_txt_start));
+
+ /* adjust pointers of this and following lines */
+ for (i = idx + 1; i < count; ++i)
+ dp->db_index[i] -= extra;
+ }
+ dp->db_index[idx] -= extra;
+
+ /* adjust free space */
+ dp->db_free -= extra;
+ dp->db_txt_start -= extra;
+
+ /* copy new line into the data block */
+ mch_memmove(old_line - extra, new_line, (size_t)new_len);
+ buf->b_ml.ml_flags |= (ML_LOCKED_DIRTY | ML_LOCKED_POS);
+#ifdef FEAT_BYTEOFF
+ /* The else case is already covered by the insert and delete */
+ ml_updatechunk(buf, lnum, (long)extra, ML_CHNK_UPDLINE);
+#endif
+ }
+ else
+ {
+ /*
+ * Cannot do it in one data block: Delete and append.
+ * Append first, because ml_delete_int() cannot delete the
+ * last line in a buffer, which causes trouble for a buffer
+ * that has only one line.
+ * Don't forget to copy the mark!
+ */
+ /* How about handling errors??? */
+ (void)ml_append_int(buf, lnum, new_line, new_len, FALSE,
+ (dp->db_index[idx] & DB_MARKED));
+ (void)ml_delete_int(buf, lnum, FALSE);
+ }
+ }
+ vim_free(new_line);
+
+ entered = FALSE;
+ }
+
+ buf->b_ml.ml_line_lnum = 0;
+}
+
+/*
+ * create a new, empty, data block
+ */
+ static bhdr_T *
+ml_new_data(memfile_T *mfp, int negative, int page_count)
+{
+ bhdr_T *hp;
+ DATA_BL *dp;
+
+ if ((hp = mf_new(mfp, negative, page_count)) == NULL)
+ return NULL;
+
+ dp = (DATA_BL *)(hp->bh_data);
+ dp->db_id = DATA_ID;
+ dp->db_txt_start = dp->db_txt_end = page_count * mfp->mf_page_size;
+ dp->db_free = dp->db_txt_start - HEADER_SIZE;
+ dp->db_line_count = 0;
+
+ return hp;
+}
+
+/*
+ * create a new, empty, pointer block
+ */
+ static bhdr_T *
+ml_new_ptr(memfile_T *mfp)
+{
+ bhdr_T *hp;
+ PTR_BL *pp;
+
+ if ((hp = mf_new(mfp, FALSE, 1)) == NULL)
+ return NULL;
+
+ pp = (PTR_BL *)(hp->bh_data);
+ pp->pb_id = PTR_ID;
+ pp->pb_count = 0;
+ pp->pb_count_max = (short_u)((mfp->mf_page_size - sizeof(PTR_BL))
+ / sizeof(PTR_EN) + 1);
+
+ return hp;
+}
+
+/*
+ * Lookup line 'lnum' in a memline.
+ *
+ * action: if ML_DELETE or ML_INSERT the line count is updated while searching
+ * if ML_FLUSH only flush a locked block
+ * if ML_FIND just find the line
+ *
+ * If the block was found it is locked and put in ml_locked.
+ * The stack is updated to lead to the locked block. The ip_high field in
+ * the stack is updated to reflect the last line in the block AFTER the
+ * insert or delete, also if the pointer block has not been updated yet. But
+ * if ml_locked != NULL ml_locked_lineadd must be added to ip_high.
+ *
+ * return: NULL for failure, pointer to block header otherwise
+ */
+ static bhdr_T *
+ml_find_line(buf_T *buf, linenr_T lnum, int action)
+{
+ DATA_BL *dp;
+ PTR_BL *pp;
+ infoptr_T *ip;
+ bhdr_T *hp;
+ memfile_T *mfp;
+ linenr_T t;
+ blocknr_T bnum, bnum2;
+ int dirty;
+ linenr_T low, high;
+ int top;
+ int page_count;
+ int idx;
+
+ mfp = buf->b_ml.ml_mfp;
+
+ /*
+ * If there is a locked block check if the wanted line is in it.
+ * If not, flush and release the locked block.
+ * Don't do this for ML_INSERT_SAME, because the stack need to be updated.
+ * Don't do this for ML_FLUSH, because we want to flush the locked block.
+ * Don't do this when 'swapfile' is reset, we want to load all the blocks.
+ */
+ if (buf->b_ml.ml_locked)
+ {
+ if (ML_SIMPLE(action)
+ && buf->b_ml.ml_locked_low <= lnum
+ && buf->b_ml.ml_locked_high >= lnum
+ && !mf_dont_release)
+ {
+ /* remember to update pointer blocks and stack later */
+ if (action == ML_INSERT)
+ {
+ ++(buf->b_ml.ml_locked_lineadd);
+ ++(buf->b_ml.ml_locked_high);
+ }
+ else if (action == ML_DELETE)
+ {
+ --(buf->b_ml.ml_locked_lineadd);
+ --(buf->b_ml.ml_locked_high);
+ }
+ return (buf->b_ml.ml_locked);
+ }
+
+ mf_put(mfp, buf->b_ml.ml_locked, buf->b_ml.ml_flags & ML_LOCKED_DIRTY,
+ buf->b_ml.ml_flags & ML_LOCKED_POS);
+ buf->b_ml.ml_locked = NULL;
+
+ /*
+ * If lines have been added or deleted in the locked block, need to
+ * update the line count in pointer blocks.
+ */
+ if (buf->b_ml.ml_locked_lineadd != 0)
+ ml_lineadd(buf, buf->b_ml.ml_locked_lineadd);
+ }
+
+ if (action == ML_FLUSH) /* nothing else to do */
+ return NULL;
+
+ bnum = 1; /* start at the root of the tree */
+ page_count = 1;
+ low = 1;
+ high = buf->b_ml.ml_line_count;
+
+ if (action == ML_FIND) /* first try stack entries */
+ {
+ for (top = buf->b_ml.ml_stack_top - 1; top >= 0; --top)
+ {
+ ip = &(buf->b_ml.ml_stack[top]);
+ if (ip->ip_low <= lnum && ip->ip_high >= lnum)
+ {
+ bnum = ip->ip_bnum;
+ low = ip->ip_low;
+ high = ip->ip_high;
+ buf->b_ml.ml_stack_top = top; /* truncate stack at prev entry */
+ break;
+ }
+ }
+ if (top < 0)
+ buf->b_ml.ml_stack_top = 0; /* not found, start at the root */
+ }
+ else /* ML_DELETE or ML_INSERT */
+ buf->b_ml.ml_stack_top = 0; /* start at the root */
+
+/*
+ * search downwards in the tree until a data block is found
+ */
+ for (;;)
+ {
+ if ((hp = mf_get(mfp, bnum, page_count)) == NULL)
+ goto error_noblock;
+
+ /*
+ * update high for insert/delete
+ */
+ if (action == ML_INSERT)
+ ++high;
+ else if (action == ML_DELETE)
+ --high;
+
+ dp = (DATA_BL *)(hp->bh_data);
+ if (dp->db_id == DATA_ID) /* data block */
+ {
+ buf->b_ml.ml_locked = hp;
+ buf->b_ml.ml_locked_low = low;
+ buf->b_ml.ml_locked_high = high;
+ buf->b_ml.ml_locked_lineadd = 0;
+ buf->b_ml.ml_flags &= ~(ML_LOCKED_DIRTY | ML_LOCKED_POS);
+ return hp;
+ }
+
+ pp = (PTR_BL *)(dp); /* must be pointer block */
+ if (pp->pb_id != PTR_ID)
+ {
+ iemsg(_("E317: pointer block id wrong"));
+ goto error_block;
+ }
+
+ if ((top = ml_add_stack(buf)) < 0) /* add new entry to stack */
+ goto error_block;
+ ip = &(buf->b_ml.ml_stack[top]);
+ ip->ip_bnum = bnum;
+ ip->ip_low = low;
+ ip->ip_high = high;
+ ip->ip_index = -1; /* index not known yet */
+
+ dirty = FALSE;
+ for (idx = 0; idx < (int)pp->pb_count; ++idx)
+ {
+ t = pp->pb_pointer[idx].pe_line_count;
+ CHECK(t == 0, _("pe_line_count is zero"));
+ if ((low += t) > lnum)
+ {
+ ip->ip_index = idx;
+ bnum = pp->pb_pointer[idx].pe_bnum;
+ page_count = pp->pb_pointer[idx].pe_page_count;
+ high = low - 1;
+ low -= t;
+
+ /*
+ * a negative block number may have been changed
+ */
+ if (bnum < 0)
+ {
+ bnum2 = mf_trans_del(mfp, bnum);
+ if (bnum != bnum2)
+ {
+ bnum = bnum2;
+ pp->pb_pointer[idx].pe_bnum = bnum;
+ dirty = TRUE;
+ }
+ }
+
+ break;
+ }
+ }
+ if (idx >= (int)pp->pb_count) /* past the end: something wrong! */
+ {
+ if (lnum > buf->b_ml.ml_line_count)
+ siemsg(_("E322: line number out of range: %ld past the end"),
+ lnum - buf->b_ml.ml_line_count);
+
+ else
+ siemsg(_("E323: line count wrong in block %ld"), bnum);
+ goto error_block;
+ }
+ if (action == ML_DELETE)
+ {
+ pp->pb_pointer[idx].pe_line_count--;
+ dirty = TRUE;
+ }
+ else if (action == ML_INSERT)
+ {
+ pp->pb_pointer[idx].pe_line_count++;
+ dirty = TRUE;
+ }
+ mf_put(mfp, hp, dirty, FALSE);
+ }
+
+error_block:
+ mf_put(mfp, hp, FALSE, FALSE);
+error_noblock:
+ /*
+ * If action is ML_DELETE or ML_INSERT we have to correct the tree for
+ * the incremented/decremented line counts, because there won't be a line
+ * inserted/deleted after all.
+ */
+ if (action == ML_DELETE)
+ ml_lineadd(buf, 1);
+ else if (action == ML_INSERT)
+ ml_lineadd(buf, -1);
+ buf->b_ml.ml_stack_top = 0;
+ return NULL;
+}
+
+/*
+ * add an entry to the info pointer stack
+ *
+ * return -1 for failure, number of the new entry otherwise
+ */
+ static int
+ml_add_stack(buf_T *buf)
+{
+ int top;
+ infoptr_T *newstack;
+
+ top = buf->b_ml.ml_stack_top;
+
+ /* may have to increase the stack size */
+ if (top == buf->b_ml.ml_stack_size)
+ {
+ CHECK(top > 0, _("Stack size increases")); /* more than 5 levels??? */
+
+ newstack = (infoptr_T *)alloc((unsigned)sizeof(infoptr_T) *
+ (buf->b_ml.ml_stack_size + STACK_INCR));
+ if (newstack == NULL)
+ return -1;
+ if (top > 0)
+ mch_memmove(newstack, buf->b_ml.ml_stack,
+ (size_t)top * sizeof(infoptr_T));
+ vim_free(buf->b_ml.ml_stack);
+ buf->b_ml.ml_stack = newstack;
+ buf->b_ml.ml_stack_size += STACK_INCR;
+ }
+
+ buf->b_ml.ml_stack_top++;
+ return top;
+}
+
+/*
+ * Update the pointer blocks on the stack for inserted/deleted lines.
+ * The stack itself is also updated.
+ *
+ * When a insert/delete line action fails, the line is not inserted/deleted,
+ * but the pointer blocks have already been updated. That is fixed here by
+ * walking through the stack.
+ *
+ * Count is the number of lines added, negative if lines have been deleted.
+ */
+ static void
+ml_lineadd(buf_T *buf, int count)
+{
+ int idx;
+ infoptr_T *ip;
+ PTR_BL *pp;
+ memfile_T *mfp = buf->b_ml.ml_mfp;
+ bhdr_T *hp;
+
+ for (idx = buf->b_ml.ml_stack_top - 1; idx >= 0; --idx)
+ {
+ ip = &(buf->b_ml.ml_stack[idx]);
+ if ((hp = mf_get(mfp, ip->ip_bnum, 1)) == NULL)
+ break;
+ pp = (PTR_BL *)(hp->bh_data); /* must be pointer block */
+ if (pp->pb_id != PTR_ID)
+ {
+ mf_put(mfp, hp, FALSE, FALSE);
+ iemsg(_("E317: pointer block id wrong 2"));
+ break;
+ }
+ pp->pb_pointer[ip->ip_index].pe_line_count += count;
+ ip->ip_high += count;
+ mf_put(mfp, hp, TRUE, FALSE);
+ }
+}
+
+#if defined(HAVE_READLINK) || defined(PROTO)
+/*
+ * Resolve a symlink in the last component of a file name.
+ * Note that f_resolve() does it for every part of the path, we don't do that
+ * here.
+ * If it worked returns OK and the resolved link in "buf[MAXPATHL]".
+ * Otherwise returns FAIL.
+ */
+ int
+resolve_symlink(char_u *fname, char_u *buf)
+{
+ char_u tmp[MAXPATHL];
+ int ret;
+ int depth = 0;
+
+ if (fname == NULL)
+ return FAIL;
+
+ /* Put the result so far in tmp[], starting with the original name. */
+ vim_strncpy(tmp, fname, MAXPATHL - 1);
+
+ for (;;)
+ {
+ /* Limit symlink depth to 100, catch recursive loops. */
+ if (++depth == 100)
+ {
+ semsg(_("E773: Symlink loop for \"%s\""), fname);
+ return FAIL;
+ }
+
+ ret = readlink((char *)tmp, (char *)buf, MAXPATHL - 1);
+ if (ret <= 0)
+ {
+ if (errno == EINVAL || errno == ENOENT)
+ {
+ /* Found non-symlink or not existing file, stop here.
+ * When at the first level use the unmodified name, skip the
+ * call to vim_FullName(). */
+ if (depth == 1)
+ return FAIL;
+
+ /* Use the resolved name in tmp[]. */
+ break;
+ }
+
+ /* There must be some error reading links, use original name. */
+ return FAIL;
+ }
+ buf[ret] = NUL;
+
+ /*
+ * Check whether the symlink is relative or absolute.
+ * If it's relative, build a new path based on the directory
+ * portion of the filename (if any) and the path the symlink
+ * points to.
+ */
+ if (mch_isFullName(buf))
+ STRCPY(tmp, buf);
+ else
+ {
+ char_u *tail;
+
+ tail = gettail(tmp);
+ if (STRLEN(tail) + STRLEN(buf) >= MAXPATHL)
+ return FAIL;
+ STRCPY(tail, buf);
+ }
+ }
+
+ /*
+ * Try to resolve the full name of the file so that the swapfile name will
+ * be consistent even when opening a relative symlink from different
+ * working directories.
+ */
+ return vim_FullName(tmp, buf, MAXPATHL, TRUE);
+}
+#endif
+
+/*
+ * Make swap file name out of the file name and a directory name.
+ * Returns pointer to allocated memory or NULL.
+ */
+ char_u *
+makeswapname(
+ char_u *fname,
+ char_u *ffname UNUSED,
+ buf_T *buf,
+ char_u *dir_name)
+{
+ char_u *r, *s;
+ char_u *fname_res = fname;
+#ifdef HAVE_READLINK
+ char_u fname_buf[MAXPATHL];
+#endif
+
+#if defined(UNIX) || defined(WIN3264) /* Need _very_ long file names */
+ int len = (int)STRLEN(dir_name);
+
+ s = dir_name + len;
+ if (after_pathsep(dir_name, s) && len > 1 && s[-1] == s[-2])
+ { /* Ends with '//', Use Full path */
+ r = NULL;
+ if ((s = make_percent_swname(dir_name, fname)) != NULL)
+ {
+ r = modname(s, (char_u *)".swp", FALSE);
+ vim_free(s);
+ }
+ return r;
+ }
+#endif
+
+#ifdef HAVE_READLINK
+ /* Expand symlink in the file name, so that we put the swap file with the
+ * actual file instead of with the symlink. */
+ if (resolve_symlink(fname, fname_buf) == OK)
+ fname_res = fname_buf;
+#endif
+
+ r = buf_modname(
+ (buf->b_p_sn || buf->b_shortname),
+ fname_res,
+ (char_u *)
+#if defined(VMS)
+ "_swp",
+#else
+ ".swp",
+#endif
+ /* Prepend a '.' to the swap file name for the current directory. */
+ dir_name[0] == '.' && dir_name[1] == NUL);
+ if (r == NULL) /* out of memory */
+ return NULL;
+
+ s = get_file_in_dir(r, dir_name);
+ vim_free(r);
+ return s;
+}
+
+/*
+ * Get file name to use for swap file or backup file.
+ * Use the name of the edited file "fname" and an entry in the 'dir' or 'bdir'
+ * option "dname".
+ * - If "dname" is ".", return "fname" (swap file in dir of file).
+ * - If "dname" starts with "./", insert "dname" in "fname" (swap file
+ * relative to dir of file).
+ * - Otherwise, prepend "dname" to the tail of "fname" (swap file in specific
+ * dir).
+ *
+ * The return value is an allocated string and can be NULL.
+ */
+ char_u *
+get_file_in_dir(
+ char_u *fname,
+ char_u *dname) /* don't use "dirname", it is a global for Alpha */
+{
+ char_u *t;
+ char_u *tail;
+ char_u *retval;
+ int save_char;
+
+ tail = gettail(fname);
+
+ if (dname[0] == '.' && dname[1] == NUL)
+ retval = vim_strsave(fname);
+ else if (dname[0] == '.' && vim_ispathsep(dname[1]))
+ {
+ if (tail == fname) /* no path before file name */
+ retval = concat_fnames(dname + 2, tail, TRUE);
+ else
+ {
+ save_char = *tail;
+ *tail = NUL;
+ t = concat_fnames(fname, dname + 2, TRUE);
+ *tail = save_char;
+ if (t == NULL) /* out of memory */
+ retval = NULL;
+ else
+ {
+ retval = concat_fnames(t, tail, TRUE);
+ vim_free(t);
+ }
+ }
+ }
+ else
+ retval = concat_fnames(dname, tail, TRUE);
+
+#ifdef WIN3264
+ if (retval != NULL)
+ for (t = gettail(retval); *t != NUL; MB_PTR_ADV(t))
+ if (*t == ':')
+ *t = '%';
+#endif
+
+ return retval;
+}
+
+/*
+ * Print the ATTENTION message: info about an existing swap file.
+ */
+ static void
+attention_message(
+ buf_T *buf, /* buffer being edited */
+ char_u *fname) /* swap file name */
+{
+ stat_T st;
+ time_t x, sx;
+ char *p;
+
+ ++no_wait_return;
+ (void)emsg(_("E325: ATTENTION"));
+ msg_puts(_("\nFound a swap file by the name \""));
+ msg_home_replace(fname);
+ msg_puts("\"\n");
+ sx = swapfile_info(fname);
+ msg_puts(_("While opening file \""));
+ msg_outtrans(buf->b_fname);
+ msg_puts("\"\n");
+ if (mch_stat((char *)buf->b_fname, &st) == -1)
+ {
+ msg_puts(_(" CANNOT BE FOUND"));
+ }
+ else
+ {
+ msg_puts(_(" dated: "));
+ x = st.st_mtime; /* Manx C can't do &st.st_mtime */
+ p = ctime(&x); /* includes '\n' */
+ if (p == NULL)
+ msg_puts("(invalid)\n");
+ else
+ msg_puts(p);
+ if (sx != 0 && x > sx)
+ msg_puts(_(" NEWER than swap file!\n"));
+ }
+ /* Some of these messages are long to allow translation to
+ * other languages. */
+ msg_puts(_("\n(1) Another program may be editing the same file. If this is the case,\n be careful not to end up with two different instances of the same\n file when making changes. Quit, or continue with caution.\n"));
+ msg_puts(_("(2) An edit session for this file crashed.\n"));
+ msg_puts(_(" If this is the case, use \":recover\" or \"vim -r "));
+ msg_outtrans(buf->b_fname);
+ msg_puts(_("\"\n to recover the changes (see \":help recovery\").\n"));
+ msg_puts(_(" If you did this already, delete the swap file \""));
+ msg_outtrans(fname);
+ msg_puts(_("\"\n to avoid this message.\n"));
+ cmdline_row = msg_row;
+ --no_wait_return;
+}
+
+#if defined(FEAT_EVAL)
+/*
+ * Trigger the SwapExists autocommands.
+ * Returns a value for equivalent to do_dialog() (see below):
+ * 0: still need to ask for a choice
+ * 1: open read-only
+ * 2: edit anyway
+ * 3: recover
+ * 4: delete it
+ * 5: quit
+ * 6: abort
+ */
+ static int
+do_swapexists(buf_T *buf, char_u *fname)
+{
+ set_vim_var_string(VV_SWAPNAME, fname, -1);
+ set_vim_var_string(VV_SWAPCHOICE, NULL, -1);
+
+ /* Trigger SwapExists autocommands with <afile> set to the file being
+ * edited. Disallow changing directory here. */
+ ++allbuf_lock;
+ apply_autocmds(EVENT_SWAPEXISTS, buf->b_fname, NULL, FALSE, NULL);
+ --allbuf_lock;
+
+ set_vim_var_string(VV_SWAPNAME, NULL, -1);
+
+ switch (*get_vim_var_str(VV_SWAPCHOICE))
+ {
+ case 'o': return 1;
+ case 'e': return 2;
+ case 'r': return 3;
+ case 'd': return 4;
+ case 'q': return 5;
+ case 'a': return 6;
+ }
+
+ return 0;
+}
+#endif
+
+/*
+ * Find out what name to use for the swap file for buffer 'buf'.
+ *
+ * Several names are tried to find one that does not exist
+ * Returns the name in allocated memory or NULL.
+ * When out of memory "dirp" is set to NULL.
+ *
+ * Note: If BASENAMELEN is not correct, you will get error messages for
+ * not being able to open the swap or undo file
+ * Note: May trigger SwapExists autocmd, pointers may change!
+ */
+ static char_u *
+findswapname(
+ buf_T *buf,
+ char_u **dirp, /* pointer to list of directories */
+ char_u *old_fname) /* don't give warning for this file name */
+{
+ char_u *fname;
+ int n;
+ char_u *dir_name;
+#ifdef AMIGA
+ BPTR fh;
+#endif
+ int r;
+ char_u *buf_fname = buf->b_fname;
+
+#if !defined(UNIX)
+# define CREATE_DUMMY_FILE
+ FILE *dummyfd = NULL;
+
+# ifdef WIN3264
+ if (buf_fname != NULL && !mch_isFullName(buf_fname)
+ && vim_strchr(gettail(buf_fname), ':'))
+ {
+ char_u *t;
+
+ buf_fname = vim_strsave(buf_fname);
+ if (buf_fname == NULL)
+ buf_fname = buf->b_fname;
+ else
+ for (t = gettail(buf_fname); *t != NUL; MB_PTR_ADV(t))
+ if (*t == ':')
+ *t = '%';
+ }
+# endif
+
+ /*
+ * If we start editing a new file, e.g. "test.doc", which resides on an
+ * MSDOS compatible filesystem, it is possible that the file
+ * "test.doc.swp" which we create will be exactly the same file. To avoid
+ * this problem we temporarily create "test.doc". Don't do this when the
+ * check below for a 8.3 file name is used.
+ */
+ if (!(buf->b_p_sn || buf->b_shortname) && buf_fname != NULL
+ && mch_getperm(buf_fname) < 0)
+ dummyfd = mch_fopen((char *)buf_fname, "w");
+#endif
+
+ /*
+ * Isolate a directory name from *dirp and put it in dir_name.
+ * First allocate some memory to put the directory name in.
+ */
+ dir_name = alloc((unsigned)STRLEN(*dirp) + 1);
+ if (dir_name == NULL)
+ *dirp = NULL;
+ else
+ (void)copy_option_part(dirp, dir_name, 31000, ",");
+
+ /*
+ * we try different names until we find one that does not exist yet
+ */
+ if (dir_name == NULL) /* out of memory */
+ fname = NULL;
+ else
+ fname = makeswapname(buf_fname, buf->b_ffname, buf, dir_name);
+
+ for (;;)
+ {
+ if (fname == NULL) /* must be out of memory */
+ break;
+ if ((n = (int)STRLEN(fname)) == 0) /* safety check */
+ {
+ VIM_CLEAR(fname);
+ break;
+ }
+#if defined(UNIX)
+/*
+ * Some systems have a MS-DOS compatible filesystem that use 8.3 character
+ * file names. If this is the first try and the swap file name does not fit in
+ * 8.3, detect if this is the case, set shortname and try again.
+ */
+ if (fname[n - 2] == 'w' && fname[n - 1] == 'p'
+ && !(buf->b_p_sn || buf->b_shortname))
+ {
+ char_u *tail;
+ char_u *fname2;
+ stat_T s1, s2;
+ int f1, f2;
+ int created1 = FALSE, created2 = FALSE;
+ int same = FALSE;
+
+ /*
+ * Check if swapfile name does not fit in 8.3:
+ * It either contains two dots, is longer than 8 chars, or starts
+ * with a dot.
+ */
+ tail = gettail(buf_fname);
+ if ( vim_strchr(tail, '.') != NULL
+ || STRLEN(tail) > (size_t)8
+ || *gettail(fname) == '.')
+ {
+ fname2 = alloc(n + 2);
+ if (fname2 != NULL)
+ {
+ STRCPY(fname2, fname);
+ /* if fname == "xx.xx.swp", fname2 = "xx.xx.swx"
+ * if fname == ".xx.swp", fname2 = ".xx.swpx"
+ * if fname == "123456789.swp", fname2 = "12345678x.swp"
+ */
+ if (vim_strchr(tail, '.') != NULL)
+ fname2[n - 1] = 'x';
+ else if (*gettail(fname) == '.')
+ {
+ fname2[n] = 'x';
+ fname2[n + 1] = NUL;
+ }
+ else
+ fname2[n - 5] += 1;
+ /*
+ * may need to create the files to be able to use mch_stat()
+ */
+ f1 = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0);
+ if (f1 < 0)
+ {
+ f1 = mch_open_rw((char *)fname,
+ O_RDWR|O_CREAT|O_EXCL|O_EXTRA);
+ created1 = TRUE;
+ }
+ if (f1 >= 0)
+ {
+ f2 = mch_open((char *)fname2, O_RDONLY | O_EXTRA, 0);
+ if (f2 < 0)
+ {
+ f2 = mch_open_rw((char *)fname2,
+ O_RDWR|O_CREAT|O_EXCL|O_EXTRA);
+ created2 = TRUE;
+ }
+ if (f2 >= 0)
+ {
+ /*
+ * Both files exist now. If mch_stat() returns the
+ * same device and inode they are the same file.
+ */
+ if (mch_fstat(f1, &s1) != -1
+ && mch_fstat(f2, &s2) != -1
+ && s1.st_dev == s2.st_dev
+ && s1.st_ino == s2.st_ino)
+ same = TRUE;
+ close(f2);
+ if (created2)
+ mch_remove(fname2);
+ }
+ close(f1);
+ if (created1)
+ mch_remove(fname);
+ }
+ vim_free(fname2);
+ if (same)
+ {
+ buf->b_shortname = TRUE;
+ vim_free(fname);
+ fname = makeswapname(buf_fname, buf->b_ffname,
+ buf, dir_name);
+ continue; /* try again with b_shortname set */
+ }
+ }
+ }
+ }
+#endif
+ /*
+ * check if the swapfile already exists
+ */
+ if (mch_getperm(fname) < 0) /* it does not exist */
+ {
+#ifdef HAVE_LSTAT
+ stat_T sb;
+
+ /*
+ * Extra security check: When a swap file is a symbolic link, this
+ * is most likely a symlink attack.
+ */
+ if (mch_lstat((char *)fname, &sb) < 0)
+#else
+# ifdef AMIGA
+ fh = Open((UBYTE *)fname, (long)MODE_NEWFILE);
+ /*
+ * on the Amiga mch_getperm() will return -1 when the file exists
+ * but is being used by another program. This happens if you edit
+ * a file twice.
+ */
+ if (fh != (BPTR)NULL) /* can open file, OK */
+ {
+ Close(fh);
+ mch_remove(fname);
+ break;
+ }
+ if (IoErr() != ERROR_OBJECT_IN_USE
+ && IoErr() != ERROR_OBJECT_EXISTS)
+# endif
+#endif
+ break;
+ }
+
+ /*
+ * A file name equal to old_fname is OK to use.
+ */
+ if (old_fname != NULL && fnamecmp(fname, old_fname) == 0)
+ break;
+
+ /*
+ * get here when file already exists
+ */
+ if (fname[n - 2] == 'w' && fname[n - 1] == 'p') /* first try */
+ {
+ /*
+ * on MS-DOS compatible filesystems (e.g. messydos) file.doc.swp
+ * and file.doc are the same file. To guess if this problem is
+ * present try if file.doc.swx exists. If it does, we set
+ * buf->b_shortname and try file_doc.swp (dots replaced by
+ * underscores for this file), and try again. If it doesn't we
+ * assume that "file.doc.swp" already exists.
+ */
+ if (!(buf->b_p_sn || buf->b_shortname)) /* not tried yet */
+ {
+ fname[n - 1] = 'x';
+ r = mch_getperm(fname); /* try "file.swx" */
+ fname[n - 1] = 'p';
+ if (r >= 0) /* "file.swx" seems to exist */
+ {
+ buf->b_shortname = TRUE;
+ vim_free(fname);
+ fname = makeswapname(buf_fname, buf->b_ffname,
+ buf, dir_name);
+ continue; /* try again with '.' replaced with '_' */
+ }
+ }
+ /*
+ * If we get here the ".swp" file really exists.
+ * Give an error message, unless recovering, no file name, we are
+ * viewing a help file or when the path of the file is different
+ * (happens when all .swp files are in one directory).
+ */
+ if (!recoverymode && buf_fname != NULL
+ && !buf->b_help && !(buf->b_flags & BF_DUMMY))
+ {
+ int fd;
+ struct block0 b0;
+ int differ = FALSE;
+
+ /*
+ * Try to read block 0 from the swap file to get the original
+ * file name (and inode number).
+ */
+ fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0);
+ if (fd >= 0)
+ {
+ if (read_eintr(fd, &b0, sizeof(b0)) == sizeof(b0))
+ {
+ /*
+ * If the swapfile has the same directory as the
+ * buffer don't compare the directory names, they can
+ * have a different mountpoint.
+ */
+ if (b0.b0_flags & B0_SAME_DIR)
+ {
+ if (fnamecmp(gettail(buf->b_ffname),
+ gettail(b0.b0_fname)) != 0
+ || !same_directory(fname, buf->b_ffname))
+ {
+#ifdef CHECK_INODE
+ /* Symlinks may point to the same file even
+ * when the name differs, need to check the
+ * inode too. */
+ expand_env(b0.b0_fname, NameBuff, MAXPATHL);
+ if (fnamecmp_ino(buf->b_ffname, NameBuff,
+ char_to_long(b0.b0_ino)))
+#endif
+ differ = TRUE;
+ }
+ }
+ else
+ {
+ /*
+ * The name in the swap file may be
+ * "~user/path/file". Expand it first.
+ */
+ expand_env(b0.b0_fname, NameBuff, MAXPATHL);
+#ifdef CHECK_INODE
+ if (fnamecmp_ino(buf->b_ffname, NameBuff,
+ char_to_long(b0.b0_ino)))
+ differ = TRUE;
+#else
+ if (fnamecmp(NameBuff, buf->b_ffname) != 0)
+ differ = TRUE;
+#endif
+ }
+ }
+ close(fd);
+ }
+
+ /* give the ATTENTION message when there is an old swap file
+ * for the current file, and the buffer was not recovered. */
+ if (differ == FALSE && !(curbuf->b_flags & BF_RECOVERED)
+ && vim_strchr(p_shm, SHM_ATTENTION) == NULL)
+ {
+#if defined(HAS_SWAP_EXISTS_ACTION)
+ int choice = 0;
+#endif
+#ifdef CREATE_DUMMY_FILE
+ int did_use_dummy = FALSE;
+
+ /* Avoid getting a warning for the file being created
+ * outside of Vim, it was created at the start of this
+ * function. Delete the file now, because Vim might exit
+ * here if the window is closed. */
+ if (dummyfd != NULL)
+ {
+ fclose(dummyfd);
+ dummyfd = NULL;
+ mch_remove(buf_fname);
+ did_use_dummy = TRUE;
+ }
+#endif
+
+#if (defined(UNIX) || defined(VMS)) && (defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG))
+ process_still_running = FALSE;
+#endif
+#if defined(FEAT_EVAL)
+ /*
+ * If there is an SwapExists autocommand and we can handle
+ * the response, trigger it. It may return 0 to ask the
+ * user anyway.
+ */
+ if (swap_exists_action != SEA_NONE
+ && has_autocmd(EVENT_SWAPEXISTS, buf_fname, buf))
+ choice = do_swapexists(buf, fname);
+
+ if (choice == 0)
+#endif
+ {
+#ifdef FEAT_GUI
+ // If we are supposed to start the GUI but it wasn't
+ // completely started yet, start it now. This makes
+ // the messages displayed in the Vim window when
+ // loading a session from the .gvimrc file.
+ if (gui.starting && !gui.in_use)
+ gui_start();
+#endif
+ // Show info about the existing swap file.
+ attention_message(buf, fname);
+
+ // We don't want a 'q' typed at the more-prompt
+ // interrupt loading a file.
+ got_int = FALSE;
+
+ // If vimrc has "simalt ~x" we don't want it to
+ // interfere with the prompt here.
+ flush_buffers(FLUSH_TYPEAHEAD);
+ }
+
+#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
+ if (swap_exists_action != SEA_NONE && choice == 0)
+ {
+ char_u *name;
+
+ name = alloc((unsigned)(STRLEN(fname)
+ + STRLEN(_("Swap file \""))
+ + STRLEN(_("\" already exists!")) + 5));
+ if (name != NULL)
+ {
+ STRCPY(name, _("Swap file \""));
+ home_replace(NULL, fname, name + STRLEN(name),
+ 1000, TRUE);
+ STRCAT(name, _("\" already exists!"));
+ }
+ choice = do_dialog(VIM_WARNING,
+ (char_u *)_("VIM - ATTENTION"),
+ name == NULL
+ ? (char_u *)_("Swap file already exists!")
+ : name,
+# if defined(UNIX) || defined(VMS)
+ process_still_running
+ ? (char_u *)_("&Open Read-Only\n&Edit anyway\n&Recover\n&Quit\n&Abort") :
+# endif
+ (char_u *)_("&Open Read-Only\n&Edit anyway\n&Recover\n&Delete it\n&Quit\n&Abort"), 1, NULL, FALSE);
+
+# if defined(UNIX) || defined(VMS)
+ if (process_still_running && choice >= 4)
+ choice++; /* Skip missing "Delete it" button */
+# endif
+ vim_free(name);
+
+ /* pretend screen didn't scroll, need redraw anyway */
+ msg_scrolled = 0;
+ redraw_all_later(NOT_VALID);
+ }
+#endif
+
+#if defined(HAS_SWAP_EXISTS_ACTION)
+ if (choice > 0)
+ {
+ switch (choice)
+ {
+ case 1:
+ buf->b_p_ro = TRUE;
+ break;
+ case 2:
+ break;
+ case 3:
+ swap_exists_action = SEA_RECOVER;
+ break;
+ case 4:
+ mch_remove(fname);
+ break;
+ case 5:
+ swap_exists_action = SEA_QUIT;
+ break;
+ case 6:
+ swap_exists_action = SEA_QUIT;
+ got_int = TRUE;
+ break;
+ }
+
+ /* If the file was deleted this fname can be used. */
+ if (mch_getperm(fname) < 0)
+ break;
+ }
+ else
+#endif
+ {
+ msg_puts("\n");
+ if (msg_silent == 0)
+ /* call wait_return() later */
+ need_wait_return = TRUE;
+ }
+
+#ifdef CREATE_DUMMY_FILE
+ /* Going to try another name, need the dummy file again. */
+ if (did_use_dummy)
+ dummyfd = mch_fopen((char *)buf_fname, "w");
+#endif
+ }
+ }
+ }
+
+ /*
+ * Change the ".swp" extension to find another file that can be used.
+ * First decrement the last char: ".swo", ".swn", etc.
+ * If that still isn't enough decrement the last but one char: ".svz"
+ * Can happen when editing many "No Name" buffers.
+ */
+ if (fname[n - 1] == 'a') /* ".s?a" */
+ {
+ if (fname[n - 2] == 'a') /* ".saa": tried enough, give up */
+ {
+ emsg(_("E326: Too many swap files found"));
+ VIM_CLEAR(fname);
+ break;
+ }
+ --fname[n - 2]; /* ".svz", ".suz", etc. */
+ fname[n - 1] = 'z' + 1;
+ }
+ --fname[n - 1]; /* ".swo", ".swn", etc. */
+ }
+
+ vim_free(dir_name);
+#ifdef CREATE_DUMMY_FILE
+ if (dummyfd != NULL) /* file has been created temporarily */
+ {
+ fclose(dummyfd);
+ mch_remove(buf_fname);
+ }
+#endif
+#ifdef WIN3264
+ if (buf_fname != buf->b_fname)
+ vim_free(buf_fname);
+#endif
+ return fname;
+}
+
+ static int
+b0_magic_wrong(ZERO_BL *b0p)
+{
+ return (b0p->b0_magic_long != (long)B0_MAGIC_LONG
+ || b0p->b0_magic_int != (int)B0_MAGIC_INT
+ || b0p->b0_magic_short != (short)B0_MAGIC_SHORT
+ || b0p->b0_magic_char != B0_MAGIC_CHAR);
+}
+
+#ifdef CHECK_INODE
+/*
+ * Compare current file name with file name from swap file.
+ * Try to use inode numbers when possible.
+ * Return non-zero when files are different.
+ *
+ * When comparing file names a few things have to be taken into consideration:
+ * - When working over a network the full path of a file depends on the host.
+ * We check the inode number if possible. It is not 100% reliable though,
+ * because the device number cannot be used over a network.
+ * - When a file does not exist yet (editing a new file) there is no inode
+ * number.
+ * - The file name in a swap file may not be valid on the current host. The
+ * "~user" form is used whenever possible to avoid this.
+ *
+ * This is getting complicated, let's make a table:
+ *
+ * ino_c ino_s fname_c fname_s differ =
+ *
+ * both files exist -> compare inode numbers:
+ * != 0 != 0 X X ino_c != ino_s
+ *
+ * inode number(s) unknown, file names available -> compare file names
+ * == 0 X OK OK fname_c != fname_s
+ * X == 0 OK OK fname_c != fname_s
+ *
+ * current file doesn't exist, file for swap file exist, file name(s) not
+ * available -> probably different
+ * == 0 != 0 FAIL X TRUE
+ * == 0 != 0 X FAIL TRUE
+ *
+ * current file exists, inode for swap unknown, file name(s) not
+ * available -> probably different
+ * != 0 == 0 FAIL X TRUE
+ * != 0 == 0 X FAIL TRUE
+ *
+ * current file doesn't exist, inode for swap unknown, one file name not
+ * available -> probably different
+ * == 0 == 0 FAIL OK TRUE
+ * == 0 == 0 OK FAIL TRUE
+ *
+ * current file doesn't exist, inode for swap unknown, both file names not
+ * available -> compare file names
+ * == 0 == 0 FAIL FAIL fname_c != fname_s
+ *
+ * Note that when the ino_t is 64 bits, only the last 32 will be used. This
+ * can't be changed without making the block 0 incompatible with 32 bit
+ * versions.
+ */
+
+ static int
+fnamecmp_ino(
+ char_u *fname_c, /* current file name */
+ char_u *fname_s, /* file name from swap file */
+ long ino_block0)
+{
+ stat_T st;
+ ino_t ino_c = 0; /* ino of current file */
+ ino_t ino_s; /* ino of file from swap file */
+ char_u buf_c[MAXPATHL]; /* full path of fname_c */
+ char_u buf_s[MAXPATHL]; /* full path of fname_s */
+ int retval_c; /* flag: buf_c valid */
+ int retval_s; /* flag: buf_s valid */
+
+ if (mch_stat((char *)fname_c, &st) == 0)
+ ino_c = (ino_t)st.st_ino;
+
+ /*
+ * First we try to get the inode from the file name, because the inode in
+ * the swap file may be outdated. If that fails (e.g. this path is not
+ * valid on this machine), use the inode from block 0.
+ */
+ if (mch_stat((char *)fname_s, &st) == 0)
+ ino_s = (ino_t)st.st_ino;
+ else
+ ino_s = (ino_t)ino_block0;
+
+ if (ino_c && ino_s)
+ return (ino_c != ino_s);
+
+ /*
+ * One of the inode numbers is unknown, try a forced vim_FullName() and
+ * compare the file names.
+ */
+ retval_c = vim_FullName(fname_c, buf_c, MAXPATHL, TRUE);
+ retval_s = vim_FullName(fname_s, buf_s, MAXPATHL, TRUE);
+ if (retval_c == OK && retval_s == OK)
+ return STRCMP(buf_c, buf_s) != 0;
+
+ /*
+ * Can't compare inodes or file names, guess that the files are different,
+ * unless both appear not to exist at all, then compare with the file name
+ * in the swap file.
+ */
+ if (ino_s == 0 && ino_c == 0 && retval_c == FAIL && retval_s == FAIL)
+ return STRCMP(fname_c, fname_s) != 0;
+ return TRUE;
+}
+#endif /* CHECK_INODE */
+
+/*
+ * Move a long integer into a four byte character array.
+ * Used for machine independency in block zero.
+ */
+ static void
+long_to_char(long n, char_u *s)
+{
+ s[0] = (char_u)(n & 0xff);
+ n = (unsigned)n >> 8;
+ s[1] = (char_u)(n & 0xff);
+ n = (unsigned)n >> 8;
+ s[2] = (char_u)(n & 0xff);
+ n = (unsigned)n >> 8;
+ s[3] = (char_u)(n & 0xff);
+}
+
+ static long
+char_to_long(char_u *s)
+{
+ long retval;
+
+ retval = s[3];
+ retval <<= 8;
+ retval |= s[2];
+ retval <<= 8;
+ retval |= s[1];
+ retval <<= 8;
+ retval |= s[0];
+
+ return retval;
+}
+
+/*
+ * Set the flags in the first block of the swap file:
+ * - file is modified or not: buf->b_changed
+ * - 'fileformat'
+ * - 'fileencoding'
+ */
+ void
+ml_setflags(buf_T *buf)
+{
+ bhdr_T *hp;
+ ZERO_BL *b0p;
+
+ if (!buf->b_ml.ml_mfp)
+ return;
+ for (hp = buf->b_ml.ml_mfp->mf_used_last; hp != NULL; hp = hp->bh_prev)
+ {
+ if (hp->bh_bnum == 0)
+ {
+ b0p = (ZERO_BL *)(hp->bh_data);
+ b0p->b0_dirty = buf->b_changed ? B0_DIRTY : 0;
+ b0p->b0_flags = (b0p->b0_flags & ~B0_FF_MASK)
+ | (get_fileformat(buf) + 1);
+ add_b0_fenc(b0p, buf);
+ hp->bh_flags |= BH_DIRTY;
+ mf_sync(buf->b_ml.ml_mfp, MFS_ZERO);
+ break;
+ }
+ }
+}
+
+#if defined(FEAT_CRYPT) || defined(PROTO)
+/*
+ * If "data" points to a data block encrypt the text in it and return a copy
+ * in allocated memory. Return NULL when out of memory.
+ * Otherwise return "data".
+ */
+ char_u *
+ml_encrypt_data(
+ memfile_T *mfp,
+ char_u *data,
+ off_T offset,
+ unsigned size)
+{
+ DATA_BL *dp = (DATA_BL *)data;
+ char_u *head_end;
+ char_u *text_start;
+ char_u *new_data;
+ int text_len;
+ cryptstate_T *state;
+
+ if (dp->db_id != DATA_ID)
+ return data;
+
+ state = ml_crypt_prepare(mfp, offset, FALSE);
+ if (state == NULL)
+ return data;
+
+ new_data = (char_u *)alloc(size);
+ if (new_data == NULL)
+ return NULL;
+ head_end = (char_u *)(&dp->db_index[dp->db_line_count]);
+ text_start = (char_u *)dp + dp->db_txt_start;
+ text_len = size - dp->db_txt_start;
+
+ /* Copy the header and the text. */
+ mch_memmove(new_data, dp, head_end - (char_u *)dp);
+
+ /* Encrypt the text. */
+ crypt_encode(state, text_start, text_len, new_data + dp->db_txt_start);
+ crypt_free_state(state);
+
+ /* Clear the gap. */
+ if (head_end < text_start)
+ vim_memset(new_data + (head_end - data), 0, text_start - head_end);
+
+ return new_data;
+}
+
+/*
+ * Decrypt the text in "data" if it points to an encrypted data block.
+ */
+ void
+ml_decrypt_data(
+ memfile_T *mfp,
+ char_u *data,
+ off_T offset,
+ unsigned size)
+{
+ DATA_BL *dp = (DATA_BL *)data;
+ char_u *head_end;
+ char_u *text_start;
+ int text_len;
+ cryptstate_T *state;
+
+ if (dp->db_id == DATA_ID)
+ {
+ head_end = (char_u *)(&dp->db_index[dp->db_line_count]);
+ text_start = (char_u *)dp + dp->db_txt_start;
+ text_len = dp->db_txt_end - dp->db_txt_start;
+
+ if (head_end > text_start || dp->db_txt_start > size
+ || dp->db_txt_end > size)
+ return; /* data was messed up */
+
+ state = ml_crypt_prepare(mfp, offset, TRUE);
+ if (state != NULL)
+ {
+ /* Decrypt the text in place. */
+ crypt_decode_inplace(state, text_start, text_len);
+ crypt_free_state(state);
+ }
+ }
+}
+
+/*
+ * Prepare for encryption/decryption, using the key, seed and offset.
+ * Return an allocated cryptstate_T *.
+ */
+ static cryptstate_T *
+ml_crypt_prepare(memfile_T *mfp, off_T offset, int reading)
+{
+ buf_T *buf = mfp->mf_buffer;
+ char_u salt[50];
+ int method_nr;
+ char_u *key;
+ char_u *seed;
+
+ if (reading && mfp->mf_old_key != NULL)
+ {
+ /* Reading back blocks with the previous key/method/seed. */
+ method_nr = mfp->mf_old_cm;
+ key = mfp->mf_old_key;
+ seed = mfp->mf_old_seed;
+ }
+ else
+ {
+ method_nr = crypt_get_method_nr(buf);
+ key = buf->b_p_key;
+ seed = mfp->mf_seed;
+ }
+ if (*key == NUL)
+ return NULL;
+
+ if (method_nr == CRYPT_M_ZIP)
+ {
+ /* For PKzip: Append the offset to the key, so that we use a different
+ * key for every block. */
+ vim_snprintf((char *)salt, sizeof(salt), "%s%ld", key, (long)offset);
+ return crypt_create(method_nr, salt, NULL, 0, NULL, 0);
+ }
+
+ /* Using blowfish or better: add salt and seed. We use the byte offset
+ * of the block for the salt. */
+ vim_snprintf((char *)salt, sizeof(salt), "%ld", (long)offset);
+ return crypt_create(method_nr, key, salt, (int)STRLEN(salt),
+ seed, MF_SEED_LEN);
+}
+
+#endif
+
+
+#if defined(FEAT_BYTEOFF) || defined(PROTO)
+
+#define MLCS_MAXL 800 /* max no of lines in chunk */
+#define MLCS_MINL 400 /* should be half of MLCS_MAXL */
+
+/*
+ * Keep information for finding byte offset of a line, updtype may be one of:
+ * ML_CHNK_ADDLINE: Add len to parent chunk, possibly splitting it
+ * Careful: ML_CHNK_ADDLINE may cause ml_find_line() to be called.
+ * ML_CHNK_DELLINE: Subtract len from parent chunk, possibly deleting it
+ * ML_CHNK_UPDLINE: Add len to parent chunk, as a signed entity.
+ */
+ static void
+ml_updatechunk(
+ buf_T *buf,
+ linenr_T line,
+ long len,
+ int updtype)
+{
+ static buf_T *ml_upd_lastbuf = NULL;
+ static linenr_T ml_upd_lastline;
+ static linenr_T ml_upd_lastcurline;
+ static int ml_upd_lastcurix;
+
+ linenr_T curline = ml_upd_lastcurline;
+ int curix = ml_upd_lastcurix;
+ long size;
+ chunksize_T *curchnk;
+ int rest;
+ bhdr_T *hp;
+ DATA_BL *dp;
+
+ if (buf->b_ml.ml_usedchunks == -1 || len == 0)
+ return;
+ if (buf->b_ml.ml_chunksize == NULL)
+ {
+ buf->b_ml.ml_chunksize = (chunksize_T *)
+ alloc((unsigned)sizeof(chunksize_T) * 100);
+ if (buf->b_ml.ml_chunksize == NULL)
+ {
+ buf->b_ml.ml_usedchunks = -1;
+ return;
+ }
+ buf->b_ml.ml_numchunks = 100;
+ buf->b_ml.ml_usedchunks = 1;
+ buf->b_ml.ml_chunksize[0].mlcs_numlines = 1;
+ buf->b_ml.ml_chunksize[0].mlcs_totalsize = 1;
+ }
+
+ if (updtype == ML_CHNK_UPDLINE && buf->b_ml.ml_line_count == 1)
+ {
+ /*
+ * First line in empty buffer from ml_flush_line() -- reset
+ */
+ buf->b_ml.ml_usedchunks = 1;
+ buf->b_ml.ml_chunksize[0].mlcs_numlines = 1;
+ buf->b_ml.ml_chunksize[0].mlcs_totalsize = (long)buf->b_ml.ml_line_len;
+ return;
+ }
+
+ /*
+ * Find chunk that our line belongs to, curline will be at start of the
+ * chunk.
+ */
+ if (buf != ml_upd_lastbuf || line != ml_upd_lastline + 1
+ || updtype != ML_CHNK_ADDLINE)
+ {
+ for (curline = 1, curix = 0;
+ curix < buf->b_ml.ml_usedchunks - 1
+ && line >= curline + buf->b_ml.ml_chunksize[curix].mlcs_numlines;
+ curix++)
+ {
+ curline += buf->b_ml.ml_chunksize[curix].mlcs_numlines;
+ }
+ }
+ else if (curix < buf->b_ml.ml_usedchunks - 1
+ && line >= curline + buf->b_ml.ml_chunksize[curix].mlcs_numlines)
+ {
+ /* Adjust cached curix & curline */
+ curline += buf->b_ml.ml_chunksize[curix].mlcs_numlines;
+ curix++;
+ }
+ curchnk = buf->b_ml.ml_chunksize + curix;
+
+ if (updtype == ML_CHNK_DELLINE)
+ len = -len;
+ curchnk->mlcs_totalsize += len;
+ if (updtype == ML_CHNK_ADDLINE)
+ {
+ curchnk->mlcs_numlines++;
+
+ /* May resize here so we don't have to do it in both cases below */
+ if (buf->b_ml.ml_usedchunks + 1 >= buf->b_ml.ml_numchunks)
+ {
+ chunksize_T *t_chunksize = buf->b_ml.ml_chunksize;
+
+ buf->b_ml.ml_numchunks = buf->b_ml.ml_numchunks * 3 / 2;
+ buf->b_ml.ml_chunksize = (chunksize_T *)
+ vim_realloc(buf->b_ml.ml_chunksize,
+ sizeof(chunksize_T) * buf->b_ml.ml_numchunks);
+ if (buf->b_ml.ml_chunksize == NULL)
+ {
+ /* Hmmmm, Give up on offset for this buffer */
+ vim_free(t_chunksize);
+ buf->b_ml.ml_usedchunks = -1;
+ return;
+ }
+ }
+
+ if (buf->b_ml.ml_chunksize[curix].mlcs_numlines >= MLCS_MAXL)
+ {
+ int count; /* number of entries in block */
+ int idx;
+ int end_idx;
+ int text_end;
+ int linecnt;
+
+ mch_memmove(buf->b_ml.ml_chunksize + curix + 1,
+ buf->b_ml.ml_chunksize + curix,
+ (buf->b_ml.ml_usedchunks - curix) *
+ sizeof(chunksize_T));
+ /* Compute length of first half of lines in the split chunk */
+ size = 0;
+ linecnt = 0;
+ while (curline < buf->b_ml.ml_line_count
+ && linecnt < MLCS_MINL)
+ {
+ if ((hp = ml_find_line(buf, curline, ML_FIND)) == NULL)
+ {
+ buf->b_ml.ml_usedchunks = -1;
+ return;
+ }
+ dp = (DATA_BL *)(hp->bh_data);
+ count = (long)(buf->b_ml.ml_locked_high) -
+ (long)(buf->b_ml.ml_locked_low) + 1;
+ idx = curline - buf->b_ml.ml_locked_low;
+ curline = buf->b_ml.ml_locked_high + 1;
+
+ // compute index of last line to use in this MEMLINE
+ rest = count - idx;
+ if (linecnt + rest > MLCS_MINL)
+ {
+ end_idx = idx + MLCS_MINL - linecnt - 1;
+ linecnt = MLCS_MINL;
+ }
+ else
+ {
+ end_idx = count - 1;
+ linecnt += rest;
+ }
+#ifdef FEAT_TEXT_PROP
+ if (buf->b_has_textprop)
+ {
+ int i;
+
+ // We cannot use the text pointers to get the text length,
+ // the text prop info would also be counted. Go over the
+ // lines.
+ for (i = end_idx; i < idx; ++i)
+ size += (int)STRLEN((char_u *)dp + (dp->db_index[i] & DB_INDEX_MASK)) + 1;
+ }
+ else
+#endif
+ {
+ if (idx == 0)/* first line in block, text at the end */
+ text_end = dp->db_txt_end;
+ else
+ text_end = ((dp->db_index[idx - 1]) & DB_INDEX_MASK);
+ size += text_end - ((dp->db_index[end_idx]) & DB_INDEX_MASK);
+ }
+ }
+ buf->b_ml.ml_chunksize[curix].mlcs_numlines = linecnt;
+ buf->b_ml.ml_chunksize[curix + 1].mlcs_numlines -= linecnt;
+ buf->b_ml.ml_chunksize[curix].mlcs_totalsize = size;
+ buf->b_ml.ml_chunksize[curix + 1].mlcs_totalsize -= size;
+ buf->b_ml.ml_usedchunks++;
+ ml_upd_lastbuf = NULL; /* Force recalc of curix & curline */
+ return;
+ }
+ else if (buf->b_ml.ml_chunksize[curix].mlcs_numlines >= MLCS_MINL
+ && curix == buf->b_ml.ml_usedchunks - 1
+ && buf->b_ml.ml_line_count - line <= 1)
+ {
+ /*
+ * We are in the last chunk and it is cheap to crate a new one
+ * after this. Do it now to avoid the loop above later on
+ */
+ curchnk = buf->b_ml.ml_chunksize + curix + 1;
+ buf->b_ml.ml_usedchunks++;
+ if (line == buf->b_ml.ml_line_count)
+ {
+ curchnk->mlcs_numlines = 0;
+ curchnk->mlcs_totalsize = 0;
+ }
+ else
+ {
+ /*
+ * Line is just prior to last, move count for last
+ * This is the common case when loading a new file
+ */
+ hp = ml_find_line(buf, buf->b_ml.ml_line_count, ML_FIND);
+ if (hp == NULL)
+ {
+ buf->b_ml.ml_usedchunks = -1;
+ return;
+ }
+ dp = (DATA_BL *)(hp->bh_data);
+ if (dp->db_line_count == 1)
+ rest = dp->db_txt_end - dp->db_txt_start;
+ else
+ rest =
+ ((dp->db_index[dp->db_line_count - 2]) & DB_INDEX_MASK)
+ - dp->db_txt_start;
+ curchnk->mlcs_totalsize = rest;
+ curchnk->mlcs_numlines = 1;
+ curchnk[-1].mlcs_totalsize -= rest;
+ curchnk[-1].mlcs_numlines -= 1;
+ }
+ }
+ }
+ else if (updtype == ML_CHNK_DELLINE)
+ {
+ curchnk->mlcs_numlines--;
+ ml_upd_lastbuf = NULL; /* Force recalc of curix & curline */
+ if (curix < (buf->b_ml.ml_usedchunks - 1)
+ && (curchnk->mlcs_numlines + curchnk[1].mlcs_numlines)
+ <= MLCS_MINL)
+ {
+ curix++;
+ curchnk = buf->b_ml.ml_chunksize + curix;
+ }
+ else if (curix == 0 && curchnk->mlcs_numlines <= 0)
+ {
+ buf->b_ml.ml_usedchunks--;
+ mch_memmove(buf->b_ml.ml_chunksize, buf->b_ml.ml_chunksize + 1,
+ buf->b_ml.ml_usedchunks * sizeof(chunksize_T));
+ return;
+ }
+ else if (curix == 0 || (curchnk->mlcs_numlines > 10
+ && (curchnk->mlcs_numlines + curchnk[-1].mlcs_numlines)
+ > MLCS_MINL))
+ {
+ return;
+ }
+
+ /* Collapse chunks */
+ curchnk[-1].mlcs_numlines += curchnk->mlcs_numlines;
+ curchnk[-1].mlcs_totalsize += curchnk->mlcs_totalsize;
+ buf->b_ml.ml_usedchunks--;
+ if (curix < buf->b_ml.ml_usedchunks)
+ {
+ mch_memmove(buf->b_ml.ml_chunksize + curix,
+ buf->b_ml.ml_chunksize + curix + 1,
+ (buf->b_ml.ml_usedchunks - curix) *
+ sizeof(chunksize_T));
+ }
+ return;
+ }
+ ml_upd_lastbuf = buf;
+ ml_upd_lastline = line;
+ ml_upd_lastcurline = curline;
+ ml_upd_lastcurix = curix;
+}
+
+/*
+ * Find offset for line or line with offset.
+ * Find line with offset if "lnum" is 0; return remaining offset in offp
+ * Find offset of line if "lnum" > 0
+ * return -1 if information is not available
+ */
+ long
+ml_find_line_or_offset(buf_T *buf, linenr_T lnum, long *offp)
+{
+ linenr_T curline;
+ int curix;
+ long size;
+ bhdr_T *hp;
+ DATA_BL *dp;
+ int count; /* number of entries in block */
+ int idx;
+ int start_idx;
+ int text_end;
+ long offset;
+ int len;
+ int ffdos = (get_fileformat(buf) == EOL_DOS);
+ int extra = 0;
+
+ /* take care of cached line first */
+ ml_flush_line(curbuf);
+
+ if (buf->b_ml.ml_usedchunks == -1
+ || buf->b_ml.ml_chunksize == NULL
+ || lnum < 0)
+ return -1;
+
+ if (offp == NULL)
+ offset = 0;
+ else
+ offset = *offp;
+ if (lnum == 0 && offset <= 0)
+ return 1; /* Not a "find offset" and offset 0 _must_ be in line 1 */
+ /*
+ * Find the last chunk before the one containing our line. Last chunk is
+ * special because it will never qualify
+ */
+ curline = 1;
+ curix = size = 0;
+ while (curix < buf->b_ml.ml_usedchunks - 1
+ && ((lnum != 0
+ && lnum >= curline + buf->b_ml.ml_chunksize[curix].mlcs_numlines)
+ || (offset != 0
+ && offset > size + buf->b_ml.ml_chunksize[curix].mlcs_totalsize
+ + ffdos * buf->b_ml.ml_chunksize[curix].mlcs_numlines)))
+ {
+ curline += buf->b_ml.ml_chunksize[curix].mlcs_numlines;
+ size += buf->b_ml.ml_chunksize[curix].mlcs_totalsize;
+ if (offset && ffdos)
+ size += buf->b_ml.ml_chunksize[curix].mlcs_numlines;
+ curix++;
+ }
+
+ while ((lnum != 0 && curline < lnum) || (offset != 0 && size < offset))
+ {
+ if (curline > buf->b_ml.ml_line_count
+ || (hp = ml_find_line(buf, curline, ML_FIND)) == NULL)
+ return -1;
+ dp = (DATA_BL *)(hp->bh_data);
+ count = (long)(buf->b_ml.ml_locked_high) -
+ (long)(buf->b_ml.ml_locked_low) + 1;
+ start_idx = idx = curline - buf->b_ml.ml_locked_low;
+ if (idx == 0)/* first line in block, text at the end */
+ text_end = dp->db_txt_end;
+ else
+ text_end = ((dp->db_index[idx - 1]) & DB_INDEX_MASK);
+ /* Compute index of last line to use in this MEMLINE */
+ if (lnum != 0)
+ {
+ if (curline + (count - idx) >= lnum)
+ idx += lnum - curline - 1;
+ else
+ idx = count - 1;
+ }
+ else
+ {
+ extra = 0;
+ while (offset >= size
+ + text_end - (int)((dp->db_index[idx]) & DB_INDEX_MASK)
+ + ffdos)
+ {
+ if (ffdos)
+ size++;
+ if (idx == count - 1)
+ {
+ extra = 1;
+ break;
+ }
+ idx++;
+ }
+ }
+#ifdef FEAT_TEXT_PROP
+ if (buf->b_has_textprop)
+ {
+ int i;
+
+ // cannot use the db_index pointer, need to get the actual text
+ // lengths.
+ len = 0;
+ for (i = start_idx; i <= idx; ++i)
+ len += (int)STRLEN((char_u *)dp + ((dp->db_index[i]) & DB_INDEX_MASK)) + 1;
+ }
+ else
+#endif
+ len = text_end - ((dp->db_index[idx]) & DB_INDEX_MASK);
+ size += len;
+ if (offset != 0 && size >= offset)
+ {
+ if (size + ffdos == offset)
+ *offp = 0;
+ else if (idx == start_idx)
+ *offp = offset - size + len;
+ else
+ *offp = offset - size + len
+ - (text_end - ((dp->db_index[idx - 1]) & DB_INDEX_MASK));
+ curline += idx - start_idx + extra;
+ if (curline > buf->b_ml.ml_line_count)
+ return -1; /* exactly one byte beyond the end */
+ return curline;
+ }
+ curline = buf->b_ml.ml_locked_high + 1;
+ }
+
+ if (lnum != 0)
+ {
+ /* Count extra CR characters. */
+ if (ffdos)
+ size += lnum - 1;
+
+ /* Don't count the last line break if 'noeol' and ('bin' or
+ * 'nofixeol'). */
+ if ((!buf->b_p_fixeol || buf->b_p_bin) && !buf->b_p_eol
+ && lnum > buf->b_ml.ml_line_count)
+ size -= ffdos + 1;
+ }
+
+ return size;
+}
+
+/*
+ * Goto byte in buffer with offset 'cnt'.
+ */
+ void
+goto_byte(long cnt)
+{
+ long boff = cnt;
+ linenr_T lnum;
+
+ ml_flush_line(curbuf); /* cached line may be dirty */
+ setpcmark();
+ if (boff)
+ --boff;
+ lnum = ml_find_line_or_offset(curbuf, (linenr_T)0, &boff);
+ if (lnum < 1) /* past the end */
+ {
+ curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
+ curwin->w_curswant = MAXCOL;
+ coladvance((colnr_T)MAXCOL);
+ }
+ else
+ {
+ curwin->w_cursor.lnum = lnum;
+ curwin->w_cursor.col = (colnr_T)boff;
+ curwin->w_cursor.coladd = 0;
+ curwin->w_set_curswant = TRUE;
+ }
+ check_cursor();
+
+ /* Make sure the cursor is on the first byte of a multi-byte char. */
+ if (has_mbyte)
+ mb_adjust_cursor();
+}
+#endif
diff --git a/src/menu.c b/src/menu.c
new file mode 100644
index 0000000..085d0e7
--- /dev/null
+++ b/src/menu.c
@@ -0,0 +1,2778 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ * GUI/Motif support by Robert Webb
+ *
+ * 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.
+ */
+
+/*
+ * Code for menus. Used for the GUI and 'wildmenu'.
+ */
+
+#include "vim.h"
+
+#if defined(FEAT_MENU) || defined(PROTO)
+
+#define MENUDEPTH 10 /* maximum depth of menus */
+
+#ifdef FEAT_GUI_W32
+static int add_menu_path(char_u *, vimmenu_T *, int *, char_u *, int);
+#else
+static int add_menu_path(char_u *, vimmenu_T *, int *, char_u *);
+#endif
+static int menu_nable_recurse(vimmenu_T *menu, char_u *name, int modes, int enable);
+static int remove_menu(vimmenu_T **, char_u *, int, int silent);
+static void free_menu(vimmenu_T **menup);
+static void free_menu_string(vimmenu_T *, int);
+static int show_menus(char_u *, int);
+static void show_menus_recursive(vimmenu_T *, int, int);
+static int menu_name_equal(char_u *name, vimmenu_T *menu);
+static int menu_namecmp(char_u *name, char_u *mname);
+static int get_menu_cmd_modes(char_u *, int, int *, int *);
+static char_u *popup_mode_name(char_u *name, int idx);
+static char_u *menu_text(char_u *text, int *mnemonic, char_u **actext);
+
+#if defined(FEAT_GUI_W32) && defined(FEAT_TEAROFF)
+static void gui_create_tearoffs_recurse(vimmenu_T *menu, const char_u *pname, int *pri_tab, int pri_idx);
+static void gui_add_tearoff(char_u *tearpath, int *pri_tab, int pri_idx);
+static void gui_destroy_tearoffs_recurse(vimmenu_T *menu);
+static int s_tearoffs = FALSE;
+#endif
+
+static int menu_is_hidden(char_u *name);
+#if defined(FEAT_CMDL_COMPL) || (defined(FEAT_GUI_W32) && defined(FEAT_TEAROFF))
+static int menu_is_tearoff(char_u *name);
+#endif
+
+#if defined(FEAT_MULTI_LANG) || defined(FEAT_TOOLBAR)
+static char_u *menu_skip_part(char_u *p);
+#endif
+#ifdef FEAT_MULTI_LANG
+static char_u *menutrans_lookup(char_u *name, int len);
+static void menu_unescape_name(char_u *p);
+#endif
+
+static char_u *menu_translate_tab_and_shift(char_u *arg_start);
+
+/* The character for each menu mode */
+static char *menu_mode_chars[] = {"n", "v", "s", "o", "i", "c", "tl", "t"};
+
+static char_u e_notsubmenu[] = N_("E327: Part of menu-item path is not sub-menu");
+static char_u e_nomenu[] = N_("E329: No menu \"%s\"");
+
+#ifdef FEAT_TOOLBAR
+static const char *toolbar_names[] =
+{
+ /* 0 */ "New", "Open", "Save", "Undo", "Redo",
+ /* 5 */ "Cut", "Copy", "Paste", "Print", "Help",
+ /* 10 */ "Find", "SaveAll", "SaveSesn", "NewSesn", "LoadSesn",
+ /* 15 */ "RunScript", "Replace", "WinClose", "WinMax", "WinMin",
+ /* 20 */ "WinSplit", "Shell", "FindPrev", "FindNext", "FindHelp",
+ /* 25 */ "Make", "TagJump", "RunCtags", "WinVSplit", "WinMaxWidth",
+ /* 30 */ "WinMinWidth", "Exit"
+};
+# define TOOLBAR_NAME_COUNT (sizeof(toolbar_names) / sizeof(char *))
+#endif
+
+/*
+ * Return TRUE if "name" is a window toolbar menu name.
+ */
+ static int
+menu_is_winbar(char_u *name)
+{
+ return (STRNCMP(name, "WinBar", 6) == 0);
+}
+
+ int
+winbar_height(win_T *wp)
+{
+ if (wp->w_winbar != NULL && wp->w_winbar->children != NULL)
+ return 1;
+ return 0;
+}
+
+ static vimmenu_T **
+get_root_menu(char_u *name)
+{
+ if (menu_is_winbar(name))
+ return &curwin->w_winbar;
+ return &root_menu;
+}
+
+/*
+ * Do the :menu command and relatives.
+ */
+ void
+ex_menu(
+ exarg_T *eap) /* Ex command arguments */
+{
+ char_u *menu_path;
+ int modes;
+ char_u *map_to;
+ int noremap;
+ int silent = FALSE;
+ int special = FALSE;
+ int unmenu;
+ char_u *map_buf;
+ char_u *arg;
+ char_u *p;
+ int i;
+#if defined(FEAT_GUI) && !defined(FEAT_GUI_GTK)
+ int old_menu_height;
+# if defined(FEAT_TOOLBAR) && !defined(FEAT_GUI_W32)
+ int old_toolbar_height;
+# endif
+#endif
+ int pri_tab[MENUDEPTH + 1];
+ int enable = MAYBE; /* TRUE for "menu enable", FALSE for "menu
+ * disable */
+#ifdef FEAT_TOOLBAR
+ char_u *icon = NULL;
+#endif
+ vimmenu_T menuarg;
+ vimmenu_T **root_menu_ptr;
+
+ modes = get_menu_cmd_modes(eap->cmd, eap->forceit, &noremap, &unmenu);
+ arg = eap->arg;
+
+ for (;;)
+ {
+ if (STRNCMP(arg, "<script>", 8) == 0)
+ {
+ noremap = REMAP_SCRIPT;
+ arg = skipwhite(arg + 8);
+ continue;
+ }
+ if (STRNCMP(arg, "<silent>", 8) == 0)
+ {
+ silent = TRUE;
+ arg = skipwhite(arg + 8);
+ continue;
+ }
+ if (STRNCMP(arg, "<special>", 9) == 0)
+ {
+ special = TRUE;
+ arg = skipwhite(arg + 9);
+ continue;
+ }
+ break;
+ }
+
+
+ /* Locate an optional "icon=filename" argument. */
+ if (STRNCMP(arg, "icon=", 5) == 0)
+ {
+ arg += 5;
+#ifdef FEAT_TOOLBAR
+ icon = arg;
+#endif
+ while (*arg != NUL && *arg != ' ')
+ {
+ if (*arg == '\\')
+ STRMOVE(arg, arg + 1);
+ MB_PTR_ADV(arg);
+ }
+ if (*arg != NUL)
+ {
+ *arg++ = NUL;
+ arg = skipwhite(arg);
+ }
+ }
+
+ /*
+ * Fill in the priority table.
+ */
+ for (p = arg; *p; ++p)
+ if (!VIM_ISDIGIT(*p) && *p != '.')
+ break;
+ if (VIM_ISWHITE(*p))
+ {
+ for (i = 0; i < MENUDEPTH && !VIM_ISWHITE(*arg); ++i)
+ {
+ pri_tab[i] = getdigits(&arg);
+ if (pri_tab[i] == 0)
+ pri_tab[i] = 500;
+ if (*arg == '.')
+ ++arg;
+ }
+ arg = skipwhite(arg);
+ }
+ else if (eap->addr_count && eap->line2 != 0)
+ {
+ pri_tab[0] = eap->line2;
+ i = 1;
+ }
+ else
+ i = 0;
+ while (i < MENUDEPTH)
+ pri_tab[i++] = 500;
+ pri_tab[MENUDEPTH] = -1; /* mark end of the table */
+
+ /*
+ * Check for "disable" or "enable" argument.
+ */
+ if (STRNCMP(arg, "enable", 6) == 0 && VIM_ISWHITE(arg[6]))
+ {
+ enable = TRUE;
+ arg = skipwhite(arg + 6);
+ }
+ else if (STRNCMP(arg, "disable", 7) == 0 && VIM_ISWHITE(arg[7]))
+ {
+ enable = FALSE;
+ arg = skipwhite(arg + 7);
+ }
+
+ /*
+ * If there is no argument, display all menus.
+ */
+ if (*arg == NUL)
+ {
+ show_menus(arg, modes);
+ return;
+ }
+
+#ifdef FEAT_TOOLBAR
+ /*
+ * Need to get the toolbar icon index before doing the translation.
+ */
+ menuarg.iconidx = -1;
+ menuarg.icon_builtin = FALSE;
+ if (menu_is_toolbar(arg))
+ {
+ menu_path = menu_skip_part(arg);
+ if (*menu_path == '.')
+ {
+ p = menu_skip_part(++menu_path);
+ if (STRNCMP(menu_path, "BuiltIn", 7) == 0)
+ {
+ if (skipdigits(menu_path + 7) == p)
+ {
+ menuarg.iconidx = atoi((char *)menu_path + 7);
+ if (menuarg.iconidx >= (int)TOOLBAR_NAME_COUNT)
+ menuarg.iconidx = -1;
+ else
+ menuarg.icon_builtin = TRUE;
+ }
+ }
+ else
+ {
+ for (i = 0; i < (int)TOOLBAR_NAME_COUNT; ++i)
+ if (STRNCMP(toolbar_names[i], menu_path, p - menu_path)
+ == 0)
+ {
+ menuarg.iconidx = i;
+ break;
+ }
+ }
+ }
+ }
+#endif
+
+ menu_path = arg;
+ if (*menu_path == '.')
+ {
+ semsg(_(e_invarg2), menu_path);
+ goto theend;
+ }
+
+ map_to = menu_translate_tab_and_shift(arg);
+
+ /*
+ * If there is only a menu name, display menus with that name.
+ */
+ if (*map_to == NUL && !unmenu && enable == MAYBE)
+ {
+ show_menus(menu_path, modes);
+ goto theend;
+ }
+ else if (*map_to != NUL && (unmenu || enable != MAYBE))
+ {
+ emsg(_(e_trailing));
+ goto theend;
+ }
+#if defined(FEAT_GUI) && !(defined(FEAT_GUI_GTK) || defined(FEAT_GUI_PHOTON))
+ old_menu_height = gui.menu_height;
+# if defined(FEAT_TOOLBAR) && !defined(FEAT_GUI_W32)
+ old_toolbar_height = gui.toolbar_height;
+# endif
+#endif
+
+ root_menu_ptr = get_root_menu(menu_path);
+ if (root_menu_ptr == &curwin->w_winbar)
+ /* Assume the window toolbar menu will change. */
+ redraw_later(NOT_VALID);
+
+ if (enable != MAYBE)
+ {
+ /*
+ * Change sensitivity of the menu.
+ * For the PopUp menu, remove a menu for each mode separately.
+ * Careful: menu_nable_recurse() changes menu_path.
+ */
+ if (STRCMP(menu_path, "*") == 0) /* meaning: do all menus */
+ menu_path = (char_u *)"";
+
+ if (menu_is_popup(menu_path))
+ {
+ for (i = 0; i < MENU_INDEX_TIP; ++i)
+ if (modes & (1 << i))
+ {
+ p = popup_mode_name(menu_path, i);
+ if (p != NULL)
+ {
+ menu_nable_recurse(*root_menu_ptr, p, MENU_ALL_MODES,
+ enable);
+ vim_free(p);
+ }
+ }
+ }
+ menu_nable_recurse(*root_menu_ptr, menu_path, modes, enable);
+ }
+ else if (unmenu)
+ {
+ /*
+ * Delete menu(s).
+ */
+ if (STRCMP(menu_path, "*") == 0) /* meaning: remove all menus */
+ menu_path = (char_u *)"";
+
+ /*
+ * For the PopUp menu, remove a menu for each mode separately.
+ */
+ if (menu_is_popup(menu_path))
+ {
+ for (i = 0; i < MENU_INDEX_TIP; ++i)
+ if (modes & (1 << i))
+ {
+ p = popup_mode_name(menu_path, i);
+ if (p != NULL)
+ {
+ remove_menu(root_menu_ptr, p, MENU_ALL_MODES, TRUE);
+ vim_free(p);
+ }
+ }
+ }
+
+ /* Careful: remove_menu() changes menu_path */
+ remove_menu(root_menu_ptr, menu_path, modes, FALSE);
+ }
+ else
+ {
+ /*
+ * Add menu(s).
+ * Replace special key codes.
+ */
+ if (STRICMP(map_to, "<nop>") == 0) /* "<Nop>" means nothing */
+ {
+ map_to = (char_u *)"";
+ map_buf = NULL;
+ }
+ else if (modes & MENU_TIP_MODE)
+ map_buf = NULL; /* Menu tips are plain text. */
+ else
+ map_to = replace_termcodes(map_to, &map_buf, FALSE, TRUE, special);
+ menuarg.modes = modes;
+#ifdef FEAT_TOOLBAR
+ menuarg.iconfile = icon;
+#endif
+ menuarg.noremap[0] = noremap;
+ menuarg.silent[0] = silent;
+ add_menu_path(menu_path, &menuarg, pri_tab, map_to
+#ifdef FEAT_GUI_W32
+ , TRUE
+#endif
+ );
+
+ /*
+ * For the PopUp menu, add a menu for each mode separately.
+ */
+ if (menu_is_popup(menu_path))
+ {
+ for (i = 0; i < MENU_INDEX_TIP; ++i)
+ if (modes & (1 << i))
+ {
+ p = popup_mode_name(menu_path, i);
+ if (p != NULL)
+ {
+ /* Include all modes, to make ":amenu" work */
+ menuarg.modes = modes;
+#ifdef FEAT_TOOLBAR
+ menuarg.iconfile = NULL;
+ menuarg.iconidx = -1;
+ menuarg.icon_builtin = FALSE;
+#endif
+ add_menu_path(p, &menuarg, pri_tab, map_to
+#ifdef FEAT_GUI_W32
+ , TRUE
+#endif
+ );
+ vim_free(p);
+ }
+ }
+ }
+
+ vim_free(map_buf);
+ }
+
+#if defined(FEAT_GUI) && !(defined(FEAT_GUI_GTK))
+ /* If the menubar height changed, resize the window */
+ if (gui.in_use
+ && (gui.menu_height != old_menu_height
+# if defined(FEAT_TOOLBAR) && !defined(FEAT_GUI_W32)
+ || gui.toolbar_height != old_toolbar_height
+# endif
+ ))
+ gui_set_shellsize(FALSE, FALSE, RESIZE_VERT);
+#endif
+ if (root_menu_ptr == &curwin->w_winbar)
+ {
+ int h = winbar_height(curwin);
+
+ if (h != curwin->w_winbar_height)
+ {
+ if (h == 0)
+ ++curwin->w_height;
+ else if (curwin->w_height > 0)
+ --curwin->w_height;
+ curwin->w_winbar_height = h;
+ }
+ }
+
+theend:
+ ;
+}
+
+/*
+ * Add the menu with the given name to the menu hierarchy
+ */
+ static int
+add_menu_path(
+ char_u *menu_path,
+ vimmenu_T *menuarg, /* passes modes, iconfile, iconidx,
+ icon_builtin, silent[0], noremap[0] */
+ int *pri_tab,
+ char_u *call_data
+#ifdef FEAT_GUI_W32
+ , int addtearoff /* may add tearoff item */
+#endif
+ )
+{
+ char_u *path_name;
+ int modes = menuarg->modes;
+ vimmenu_T **menup;
+ vimmenu_T *menu = NULL;
+ vimmenu_T *parent;
+ vimmenu_T **lower_pri;
+ char_u *p;
+ char_u *name;
+ char_u *dname;
+ char_u *next_name;
+ int i;
+ int c;
+ int d;
+#ifdef FEAT_GUI
+ int idx;
+ int new_idx;
+#endif
+ int pri_idx = 0;
+ int old_modes = 0;
+ int amenu;
+#ifdef FEAT_MULTI_LANG
+ char_u *en_name;
+ char_u *map_to = NULL;
+#endif
+ vimmenu_T **root_menu_ptr;
+
+ /* Make a copy so we can stuff around with it, since it could be const */
+ path_name = vim_strsave(menu_path);
+ if (path_name == NULL)
+ return FAIL;
+ root_menu_ptr = get_root_menu(menu_path);
+ menup = root_menu_ptr;
+ parent = NULL;
+ name = path_name;
+ while (*name)
+ {
+ /* Get name of this element in the menu hierarchy, and the simplified
+ * name (without mnemonic and accelerator text). */
+ next_name = menu_name_skip(name);
+#ifdef FEAT_MULTI_LANG
+ map_to = menutrans_lookup(name, (int)STRLEN(name));
+ if (map_to != NULL)
+ {
+ en_name = name;
+ name = map_to;
+ }
+ else
+ en_name = NULL;
+#endif
+ dname = menu_text(name, NULL, NULL);
+ if (dname == NULL)
+ goto erret;
+ if (*dname == NUL)
+ {
+ /* Only a mnemonic or accelerator is not valid. */
+ emsg(_("E792: Empty menu name"));
+ goto erret;
+ }
+
+ /* See if it's already there */
+ lower_pri = menup;
+#ifdef FEAT_GUI
+ idx = 0;
+ new_idx = 0;
+#endif
+ menu = *menup;
+ while (menu != NULL)
+ {
+ if (menu_name_equal(name, menu) || menu_name_equal(dname, menu))
+ {
+ if (*next_name == NUL && menu->children != NULL)
+ {
+ if (!sys_menu)
+ emsg(_("E330: Menu path must not lead to a sub-menu"));
+ goto erret;
+ }
+ if (*next_name != NUL && menu->children == NULL
+#ifdef FEAT_GUI_W32
+ && addtearoff
+#endif
+ )
+ {
+ if (!sys_menu)
+ emsg(_(e_notsubmenu));
+ goto erret;
+ }
+ break;
+ }
+ menup = &menu->next;
+
+ /* Count menus, to find where this one needs to be inserted.
+ * Ignore menus that are not in the menubar (PopUp and Toolbar) */
+ if (parent != NULL || menu_is_menubar(menu->name))
+ {
+#ifdef FEAT_GUI
+ ++idx;
+#endif
+ if (menu->priority <= pri_tab[pri_idx])
+ {
+ lower_pri = menup;
+#ifdef FEAT_GUI
+ new_idx = idx;
+#endif
+ }
+ }
+ menu = menu->next;
+ }
+
+ if (menu == NULL)
+ {
+ if (*next_name == NUL && parent == NULL)
+ {
+ emsg(_("E331: Must not add menu items directly to menu bar"));
+ goto erret;
+ }
+
+ if (menu_is_separator(dname) && *next_name != NUL)
+ {
+ emsg(_("E332: Separator cannot be part of a menu path"));
+ goto erret;
+ }
+
+ /* Not already there, so lets add it */
+ menu = (vimmenu_T *)alloc_clear((unsigned)sizeof(vimmenu_T));
+ if (menu == NULL)
+ goto erret;
+
+ menu->modes = modes;
+ menu->enabled = MENU_ALL_MODES;
+ menu->name = vim_strsave(name);
+ /* separate mnemonic and accelerator text from actual menu name */
+ menu->dname = menu_text(name, &menu->mnemonic, &menu->actext);
+#ifdef FEAT_MULTI_LANG
+ if (en_name != NULL)
+ {
+ menu->en_name = vim_strsave(en_name);
+ menu->en_dname = menu_text(en_name, NULL, NULL);
+ }
+ else
+ {
+ menu->en_name = NULL;
+ menu->en_dname = NULL;
+ }
+#endif
+ menu->priority = pri_tab[pri_idx];
+ menu->parent = parent;
+#ifdef FEAT_GUI_MOTIF
+ menu->sensitive = TRUE; /* the default */
+#endif
+#ifdef FEAT_BEVAL_TIP
+ menu->tip = NULL;
+#endif
+#ifdef FEAT_GUI_ATHENA
+ menu->image = None; /* X-Windows definition for NULL*/
+#endif
+
+ /*
+ * Add after menu that has lower priority.
+ */
+ menu->next = *lower_pri;
+ *lower_pri = menu;
+
+ old_modes = 0;
+
+#ifdef FEAT_TOOLBAR
+ menu->iconidx = menuarg->iconidx;
+ menu->icon_builtin = menuarg->icon_builtin;
+ if (*next_name == NUL && menuarg->iconfile != NULL)
+ menu->iconfile = vim_strsave(menuarg->iconfile);
+#endif
+#if defined(FEAT_GUI_W32) && defined(FEAT_TEAROFF)
+ /* the tearoff item must be present in the modes of each item. */
+ if (parent != NULL && menu_is_tearoff(parent->children->dname))
+ parent->children->modes |= modes;
+#endif
+ }
+ else
+ {
+ old_modes = menu->modes;
+
+ /*
+ * If this menu option was previously only available in other
+ * modes, then make sure it's available for this one now
+ * Also enable a menu when it's created or changed.
+ */
+#ifdef FEAT_GUI_W32
+ /* If adding a tearbar (addtearoff == FALSE) don't update modes */
+ if (addtearoff)
+#endif
+ {
+ menu->modes |= modes;
+ menu->enabled |= modes;
+ }
+ }
+
+#ifdef FEAT_GUI
+ /*
+ * Add the menu item when it's used in one of the modes, but not when
+ * only a tooltip is defined.
+ */
+ if ((old_modes & MENU_ALL_MODES) == 0
+ && (menu->modes & MENU_ALL_MODES) != 0)
+ {
+ if (gui.in_use) /* Otherwise it will be added when GUI starts */
+ {
+ if (*next_name == NUL)
+ {
+ /* Real menu item, not sub-menu */
+ gui_mch_add_menu_item(menu, new_idx);
+
+ /* Want to update menus now even if mode not changed */
+ force_menu_update = TRUE;
+ }
+ else
+ {
+ /* Sub-menu (not at end of path yet) */
+ gui_mch_add_menu(menu, new_idx);
+ }
+ }
+
+# if defined(FEAT_GUI_W32) & defined(FEAT_TEAROFF)
+ /* When adding a new submenu, may add a tearoff item */
+ if ( addtearoff
+ && *next_name
+ && vim_strchr(p_go, GO_TEAROFF) != NULL
+ && menu_is_menubar(name))
+ {
+ char_u *tearpath;
+
+ /*
+ * The pointers next_name & path_name refer to a string with
+ * \'s and ^V's stripped out. But menu_path is a "raw"
+ * string, so we must correct for special characters.
+ */
+ tearpath = alloc((unsigned int)STRLEN(menu_path) + TEAR_LEN + 2);
+ if (tearpath != NULL)
+ {
+ char_u *s;
+ int idx;
+
+ STRCPY(tearpath, menu_path);
+ idx = (int)(next_name - path_name - 1);
+ for (s = tearpath; *s && s < tearpath + idx; MB_PTR_ADV(s))
+ {
+ if ((*s == '\\' || *s == Ctrl_V) && s[1])
+ {
+ ++idx;
+ ++s;
+ }
+ }
+ tearpath[idx] = NUL;
+ gui_add_tearoff(tearpath, pri_tab, pri_idx);
+ vim_free(tearpath);
+ }
+ }
+# endif
+ }
+#endif /* FEAT_GUI */
+
+ menup = &menu->children;
+ parent = menu;
+ name = next_name;
+ VIM_CLEAR(dname);
+ if (pri_tab[pri_idx + 1] != -1)
+ ++pri_idx;
+ }
+ vim_free(path_name);
+
+ /*
+ * Only add system menu items which have not been defined yet.
+ * First check if this was an ":amenu".
+ */
+ amenu = ((modes & (MENU_NORMAL_MODE | MENU_INSERT_MODE)) ==
+ (MENU_NORMAL_MODE | MENU_INSERT_MODE));
+ if (sys_menu)
+ modes &= ~old_modes;
+
+ if (menu != NULL && modes)
+ {
+#ifdef FEAT_GUI
+ menu->cb = gui_menu_cb;
+#endif
+ p = (call_data == NULL) ? NULL : vim_strsave(call_data);
+
+ /* loop over all modes, may add more than one */
+ for (i = 0; i < MENU_MODES; ++i)
+ {
+ if (modes & (1 << i))
+ {
+ /* free any old menu */
+ free_menu_string(menu, i);
+
+ /* For "amenu", may insert an extra character.
+ * Don't do this if adding a tearbar (addtearoff == FALSE).
+ * Don't do this for "<Nop>". */
+ c = 0;
+ d = 0;
+ if (amenu && call_data != NULL && *call_data != NUL
+#ifdef FEAT_GUI_W32
+ && addtearoff
+#endif
+ )
+ {
+ switch (1 << i)
+ {
+ case MENU_VISUAL_MODE:
+ case MENU_SELECT_MODE:
+ case MENU_OP_PENDING_MODE:
+ case MENU_CMDLINE_MODE:
+ c = Ctrl_C;
+ break;
+ case MENU_INSERT_MODE:
+ c = Ctrl_BSL;
+ d = Ctrl_O;
+ break;
+ }
+ }
+
+ if (c != 0)
+ {
+ menu->strings[i] = alloc((unsigned)(STRLEN(call_data) + 5 ));
+ if (menu->strings[i] != NULL)
+ {
+ menu->strings[i][0] = c;
+ if (d == 0)
+ STRCPY(menu->strings[i] + 1, call_data);
+ else
+ {
+ menu->strings[i][1] = d;
+ STRCPY(menu->strings[i] + 2, call_data);
+ }
+ if (c == Ctrl_C)
+ {
+ int len = (int)STRLEN(menu->strings[i]);
+
+ /* Append CTRL-\ CTRL-G to obey 'insertmode'. */
+ menu->strings[i][len] = Ctrl_BSL;
+ menu->strings[i][len + 1] = Ctrl_G;
+ menu->strings[i][len + 2] = NUL;
+ }
+ }
+ }
+ else
+ menu->strings[i] = p;
+ menu->noremap[i] = menuarg->noremap[0];
+ menu->silent[i] = menuarg->silent[0];
+ }
+ }
+#if defined(FEAT_TOOLBAR) && !defined(FEAT_GUI_W32) \
+ && (defined(FEAT_BEVAL_GUI) || defined(FEAT_GUI_GTK))
+ /* Need to update the menu tip. */
+ if (modes & MENU_TIP_MODE)
+ gui_mch_menu_set_tip(menu);
+#endif
+ }
+ return OK;
+
+erret:
+ vim_free(path_name);
+ vim_free(dname);
+
+ /* Delete any empty submenu we added before discovering the error. Repeat
+ * for higher levels. */
+ while (parent != NULL && parent->children == NULL)
+ {
+ if (parent->parent == NULL)
+ menup = root_menu_ptr;
+ else
+ menup = &parent->parent->children;
+ for ( ; *menup != NULL && *menup != parent; menup = &((*menup)->next))
+ ;
+ if (*menup == NULL) /* safety check */
+ break;
+ parent = parent->parent;
+ free_menu(menup);
+ }
+ return FAIL;
+}
+
+/*
+ * Set the (sub)menu with the given name to enabled or disabled.
+ * Called recursively.
+ */
+ static int
+menu_nable_recurse(
+ vimmenu_T *menu,
+ char_u *name,
+ int modes,
+ int enable)
+{
+ char_u *p;
+
+ if (menu == NULL)
+ return OK; /* Got to bottom of hierarchy */
+
+ /* Get name of this element in the menu hierarchy */
+ p = menu_name_skip(name);
+
+ /* Find the menu */
+ while (menu != NULL)
+ {
+ if (*name == NUL || *name == '*' || menu_name_equal(name, menu))
+ {
+ if (*p != NUL)
+ {
+ if (menu->children == NULL)
+ {
+ emsg(_(e_notsubmenu));
+ return FAIL;
+ }
+ if (menu_nable_recurse(menu->children, p, modes, enable)
+ == FAIL)
+ return FAIL;
+ }
+ else
+ if (enable)
+ menu->enabled |= modes;
+ else
+ menu->enabled &= ~modes;
+
+ /*
+ * When name is empty, we are doing all menu items for the given
+ * modes, so keep looping, otherwise we are just doing the named
+ * menu item (which has been found) so break here.
+ */
+ if (*name != NUL && *name != '*')
+ break;
+ }
+ menu = menu->next;
+ }
+ if (*name != NUL && *name != '*' && menu == NULL)
+ {
+ semsg(_(e_nomenu), name);
+ return FAIL;
+ }
+
+#ifdef FEAT_GUI
+ /* Want to update menus now even if mode not changed */
+ force_menu_update = TRUE;
+#endif
+
+ return OK;
+}
+
+/*
+ * Remove the (sub)menu with the given name from the menu hierarchy
+ * Called recursively.
+ */
+ static int
+remove_menu(
+ vimmenu_T **menup,
+ char_u *name,
+ int modes,
+ int silent) /* don't give error messages */
+{
+ vimmenu_T *menu;
+ vimmenu_T *child;
+ char_u *p;
+
+ if (*menup == NULL)
+ return OK; /* Got to bottom of hierarchy */
+
+ /* Get name of this element in the menu hierarchy */
+ p = menu_name_skip(name);
+
+ /* Find the menu */
+ while ((menu = *menup) != NULL)
+ {
+ if (*name == NUL || menu_name_equal(name, menu))
+ {
+ if (*p != NUL && menu->children == NULL)
+ {
+ if (!silent)
+ emsg(_(e_notsubmenu));
+ return FAIL;
+ }
+ if ((menu->modes & modes) != 0x0)
+ {
+#if defined(FEAT_GUI_W32) & defined(FEAT_TEAROFF)
+ /*
+ * If we are removing all entries for this menu,MENU_ALL_MODES,
+ * Then kill any tearoff before we start
+ */
+ if (*p == NUL && modes == MENU_ALL_MODES)
+ {
+ if (IsWindow(menu->tearoff_handle))
+ DestroyWindow(menu->tearoff_handle);
+ }
+#endif
+ if (remove_menu(&menu->children, p, modes, silent) == FAIL)
+ return FAIL;
+ }
+ else if (*name != NUL)
+ {
+ if (!silent)
+ emsg(_(e_menuothermode));
+ return FAIL;
+ }
+
+ /*
+ * When name is empty, we are removing all menu items for the given
+ * modes, so keep looping, otherwise we are just removing the named
+ * menu item (which has been found) so break here.
+ */
+ if (*name != NUL)
+ break;
+
+ /* Remove the menu item for the given mode[s]. If the menu item
+ * is no longer valid in ANY mode, delete it */
+ menu->modes &= ~modes;
+ if (modes & MENU_TIP_MODE)
+ free_menu_string(menu, MENU_INDEX_TIP);
+ if ((menu->modes & MENU_ALL_MODES) == 0)
+ free_menu(menup);
+ else
+ menup = &menu->next;
+ }
+ else
+ menup = &menu->next;
+ }
+ if (*name != NUL)
+ {
+ if (menu == NULL)
+ {
+ if (!silent)
+ semsg(_(e_nomenu), name);
+ return FAIL;
+ }
+
+
+ /* Recalculate modes for menu based on the new updated children */
+ menu->modes &= ~modes;
+#if defined(FEAT_GUI_W32) & defined(FEAT_TEAROFF)
+ if ((s_tearoffs) && (menu->children != NULL)) /* there's a tear bar.. */
+ child = menu->children->next; /* don't count tearoff bar */
+ else
+#endif
+ child = menu->children;
+ for ( ; child != NULL; child = child->next)
+ menu->modes |= child->modes;
+ if (modes & MENU_TIP_MODE)
+ {
+ free_menu_string(menu, MENU_INDEX_TIP);
+#if defined(FEAT_TOOLBAR) && !defined(FEAT_GUI_W32) \
+ && (defined(FEAT_BEVAL_GUI) || defined(FEAT_GUI_GTK))
+ /* Need to update the menu tip. */
+ if (gui.in_use)
+ gui_mch_menu_set_tip(menu);
+#endif
+ }
+ if ((menu->modes & MENU_ALL_MODES) == 0)
+ {
+ /* The menu item is no longer valid in ANY mode, so delete it */
+#if defined(FEAT_GUI_W32) & defined(FEAT_TEAROFF)
+ if (s_tearoffs && menu->children != NULL) /* there's a tear bar.. */
+ free_menu(&menu->children);
+#endif
+ *menup = menu;
+ free_menu(menup);
+ }
+ }
+
+ return OK;
+}
+
+/*
+ * Remove the WinBar menu from window "wp".
+ */
+ void
+remove_winbar(win_T *wp)
+{
+ remove_menu(&wp->w_winbar, (char_u *)"", MENU_ALL_MODES, TRUE);
+ vim_free(wp->w_winbar_items);
+}
+
+/*
+ * Free the given menu structure and remove it from the linked list.
+ */
+ static void
+free_menu(vimmenu_T **menup)
+{
+ int i;
+ vimmenu_T *menu;
+
+ menu = *menup;
+
+#ifdef FEAT_GUI
+ /* Free machine specific menu structures (only when already created) */
+ /* Also may rebuild a tearoff'ed menu */
+ if (gui.in_use)
+ gui_mch_destroy_menu(menu);
+#endif
+
+ /* Don't change *menup until after calling gui_mch_destroy_menu(). The
+ * MacOS code needs the original structure to properly delete the menu. */
+ *menup = menu->next;
+ vim_free(menu->name);
+ vim_free(menu->dname);
+#ifdef FEAT_MULTI_LANG
+ vim_free(menu->en_name);
+ vim_free(menu->en_dname);
+#endif
+ vim_free(menu->actext);
+#ifdef FEAT_TOOLBAR
+ vim_free(menu->iconfile);
+# ifdef FEAT_GUI_MOTIF
+ vim_free(menu->xpm_fname);
+# endif
+#endif
+ for (i = 0; i < MENU_MODES; i++)
+ free_menu_string(menu, i);
+ vim_free(menu);
+
+#ifdef FEAT_GUI
+ /* Want to update menus now even if mode not changed */
+ force_menu_update = TRUE;
+#endif
+}
+
+/*
+ * Free the menu->string with the given index.
+ */
+ static void
+free_menu_string(vimmenu_T *menu, int idx)
+{
+ int count = 0;
+ int i;
+
+ for (i = 0; i < MENU_MODES; i++)
+ if (menu->strings[i] == menu->strings[idx])
+ count++;
+ if (count == 1)
+ vim_free(menu->strings[idx]);
+ menu->strings[idx] = NULL;
+}
+
+/*
+ * Show the mapping associated with a menu item or hierarchy in a sub-menu.
+ */
+ static int
+show_menus(char_u *path_name, int modes)
+{
+ char_u *p;
+ char_u *name;
+ vimmenu_T *menu;
+ vimmenu_T *parent = NULL;
+
+ name = path_name = vim_strsave(path_name);
+ if (path_name == NULL)
+ return FAIL;
+ menu = *get_root_menu(path_name);
+
+ /* First, find the (sub)menu with the given name */
+ while (*name)
+ {
+ p = menu_name_skip(name);
+ while (menu != NULL)
+ {
+ if (menu_name_equal(name, menu))
+ {
+ /* Found menu */
+ if (*p != NUL && menu->children == NULL)
+ {
+ emsg(_(e_notsubmenu));
+ vim_free(path_name);
+ return FAIL;
+ }
+ else if ((menu->modes & modes) == 0x0)
+ {
+ emsg(_(e_menuothermode));
+ vim_free(path_name);
+ return FAIL;
+ }
+ break;
+ }
+ menu = menu->next;
+ }
+ if (menu == NULL)
+ {
+ semsg(_(e_nomenu), name);
+ vim_free(path_name);
+ return FAIL;
+ }
+ name = p;
+ parent = menu;
+ menu = menu->children;
+ }
+ vim_free(path_name);
+
+ /* Now we have found the matching menu, and we list the mappings */
+ /* Highlight title */
+ msg_puts_title(_("\n--- Menus ---"));
+
+ show_menus_recursive(parent, modes, 0);
+ return OK;
+}
+
+/*
+ * Recursively show the mappings associated with the menus under the given one
+ */
+ static void
+show_menus_recursive(vimmenu_T *menu, int modes, int depth)
+{
+ int i;
+ int bit;
+
+ if (menu != NULL && (menu->modes & modes) == 0x0)
+ return;
+
+ if (menu != NULL)
+ {
+ msg_putchar('\n');
+ if (got_int) /* "q" hit for "--more--" */
+ return;
+ for (i = 0; i < depth; i++)
+ msg_puts(" ");
+ if (menu->priority)
+ {
+ msg_outnum((long)menu->priority);
+ msg_puts(" ");
+ }
+ /* Same highlighting as for directories!? */
+ msg_outtrans_attr(menu->name, HL_ATTR(HLF_D));
+ }
+
+ if (menu != NULL && menu->children == NULL)
+ {
+ for (bit = 0; bit < MENU_MODES; bit++)
+ if ((menu->modes & modes & (1 << bit)) != 0)
+ {
+ msg_putchar('\n');
+ if (got_int) /* "q" hit for "--more--" */
+ return;
+ for (i = 0; i < depth + 2; i++)
+ msg_puts(" ");
+ msg_puts(menu_mode_chars[bit]);
+ if (menu->noremap[bit] == REMAP_NONE)
+ msg_putchar('*');
+ else if (menu->noremap[bit] == REMAP_SCRIPT)
+ msg_putchar('&');
+ else
+ msg_putchar(' ');
+ if (menu->silent[bit])
+ msg_putchar('s');
+ else
+ msg_putchar(' ');
+ if ((menu->modes & menu->enabled & (1 << bit)) == 0)
+ msg_putchar('-');
+ else
+ msg_putchar(' ');
+ msg_puts(" ");
+ if (*menu->strings[bit] == NUL)
+ msg_puts_attr("<Nop>", HL_ATTR(HLF_8));
+ else
+ msg_outtrans_special(menu->strings[bit], FALSE);
+ }
+ }
+ else
+ {
+ if (menu == NULL)
+ {
+ menu = root_menu;
+ depth--;
+ }
+ else
+ menu = menu->children;
+
+ /* recursively show all children. Skip PopUp[nvoci]. */
+ for (; menu != NULL && !got_int; menu = menu->next)
+ if (!menu_is_hidden(menu->dname))
+ show_menus_recursive(menu, modes, depth + 1);
+ }
+}
+
+#ifdef FEAT_CMDL_COMPL
+
+/*
+ * Used when expanding menu names.
+ */
+static vimmenu_T *expand_menu = NULL;
+static vimmenu_T *expand_menu_alt = NULL;
+static int expand_modes = 0x0;
+static int expand_emenu; /* TRUE for ":emenu" command */
+
+/*
+ * Work out what to complete when doing command line completion of menu names.
+ */
+ char_u *
+set_context_in_menu_cmd(
+ expand_T *xp,
+ char_u *cmd,
+ char_u *arg,
+ int forceit)
+{
+ char_u *after_dot;
+ char_u *p;
+ char_u *path_name = NULL;
+ char_u *name;
+ int unmenu;
+ vimmenu_T *menu;
+ int expand_menus;
+
+ xp->xp_context = EXPAND_UNSUCCESSFUL;
+
+
+ /* Check for priority numbers, enable and disable */
+ for (p = arg; *p; ++p)
+ if (!VIM_ISDIGIT(*p) && *p != '.')
+ break;
+
+ if (!VIM_ISWHITE(*p))
+ {
+ if (STRNCMP(arg, "enable", 6) == 0
+ && (arg[6] == NUL || VIM_ISWHITE(arg[6])))
+ p = arg + 6;
+ else if (STRNCMP(arg, "disable", 7) == 0
+ && (arg[7] == NUL || VIM_ISWHITE(arg[7])))
+ p = arg + 7;
+ else
+ p = arg;
+ }
+
+ while (*p != NUL && VIM_ISWHITE(*p))
+ ++p;
+
+ arg = after_dot = p;
+
+ for (; *p && !VIM_ISWHITE(*p); ++p)
+ {
+ if ((*p == '\\' || *p == Ctrl_V) && p[1] != NUL)
+ p++;
+ else if (*p == '.')
+ after_dot = p + 1;
+ }
+
+ /* ":tearoff" and ":popup" only use menus, not entries */
+ expand_menus = !((*cmd == 't' && cmd[1] == 'e') || *cmd == 'p');
+ expand_emenu = (*cmd == 'e');
+ if (expand_menus && VIM_ISWHITE(*p))
+ return NULL; /* TODO: check for next command? */
+ if (*p == NUL) /* Complete the menu name */
+ {
+ int try_alt_menu = TRUE;
+
+ /*
+ * With :unmenu, you only want to match menus for the appropriate mode.
+ * With :menu though you might want to add a menu with the same name as
+ * one in another mode, so match menus from other modes too.
+ */
+ expand_modes = get_menu_cmd_modes(cmd, forceit, NULL, &unmenu);
+ if (!unmenu)
+ expand_modes = MENU_ALL_MODES;
+
+ menu = root_menu;
+ if (after_dot != arg)
+ {
+ path_name = alloc((unsigned)(after_dot - arg));
+ if (path_name == NULL)
+ return NULL;
+ vim_strncpy(path_name, arg, after_dot - arg - 1);
+ }
+ name = path_name;
+ while (name != NULL && *name)
+ {
+ p = menu_name_skip(name);
+ while (menu != NULL)
+ {
+ if (menu_name_equal(name, menu))
+ {
+ /* Found menu */
+ if ((*p != NUL && menu->children == NULL)
+ || ((menu->modes & expand_modes) == 0x0))
+ {
+ /*
+ * Menu path continues, but we have reached a leaf.
+ * Or menu exists only in another mode.
+ */
+ vim_free(path_name);
+ return NULL;
+ }
+ break;
+ }
+ menu = menu->next;
+ if (menu == NULL && try_alt_menu)
+ {
+ menu = curwin->w_winbar;
+ try_alt_menu = FALSE;
+ }
+ }
+ if (menu == NULL)
+ {
+ /* No menu found with the name we were looking for */
+ vim_free(path_name);
+ return NULL;
+ }
+ name = p;
+ menu = menu->children;
+ try_alt_menu = FALSE;
+ }
+ vim_free(path_name);
+
+ xp->xp_context = expand_menus ? EXPAND_MENUNAMES : EXPAND_MENUS;
+ xp->xp_pattern = after_dot;
+ expand_menu = menu;
+ if (expand_menu == root_menu)
+ expand_menu_alt = curwin->w_winbar;
+ else
+ expand_menu_alt = NULL;
+ }
+ else /* We're in the mapping part */
+ xp->xp_context = EXPAND_NOTHING;
+ return NULL;
+}
+
+/*
+ * Function given to ExpandGeneric() to obtain the list of (sub)menus (not
+ * entries).
+ */
+ char_u *
+get_menu_name(expand_T *xp UNUSED, int idx)
+{
+ static vimmenu_T *menu = NULL;
+ static int did_alt_menu = FALSE;
+ char_u *str;
+#ifdef FEAT_MULTI_LANG
+ static int should_advance = FALSE;
+#endif
+
+ if (idx == 0) /* first call: start at first item */
+ {
+ menu = expand_menu;
+ did_alt_menu = FALSE;
+#ifdef FEAT_MULTI_LANG
+ should_advance = FALSE;
+#endif
+ }
+
+ /* Skip PopUp[nvoci]. */
+ while (menu != NULL && (menu_is_hidden(menu->dname)
+ || menu_is_separator(menu->dname)
+ || menu_is_tearoff(menu->dname)
+ || menu->children == NULL))
+ {
+ menu = menu->next;
+ if (menu == NULL && !did_alt_menu)
+ {
+ menu = expand_menu_alt;
+ did_alt_menu = TRUE;
+ }
+ }
+
+ if (menu == NULL) /* at end of linked list */
+ return NULL;
+
+ if (menu->modes & expand_modes)
+#ifdef FEAT_MULTI_LANG
+ if (should_advance)
+ str = menu->en_dname;
+ else
+ {
+#endif
+ str = menu->dname;
+#ifdef FEAT_MULTI_LANG
+ if (menu->en_dname == NULL)
+ should_advance = TRUE;
+ }
+#endif
+ else
+ str = (char_u *)"";
+
+#ifdef FEAT_MULTI_LANG
+ if (should_advance)
+#endif
+ {
+ /* Advance to next menu entry. */
+ menu = menu->next;
+ if (menu == NULL && !did_alt_menu)
+ {
+ menu = expand_menu_alt;
+ did_alt_menu = TRUE;
+ }
+ }
+
+#ifdef FEAT_MULTI_LANG
+ should_advance = !should_advance;
+#endif
+
+ return str;
+}
+
+/*
+ * Function given to ExpandGeneric() to obtain the list of menus and menu
+ * entries.
+ */
+ char_u *
+get_menu_names(expand_T *xp UNUSED, int idx)
+{
+ static vimmenu_T *menu = NULL;
+ static int did_alt_menu = FALSE;
+#define TBUFFER_LEN 256
+ static char_u tbuffer[TBUFFER_LEN]; /*hack*/
+ char_u *str;
+#ifdef FEAT_MULTI_LANG
+ static int should_advance = FALSE;
+#endif
+
+ if (idx == 0) /* first call: start at first item */
+ {
+ menu = expand_menu;
+ did_alt_menu = FALSE;
+#ifdef FEAT_MULTI_LANG
+ should_advance = FALSE;
+#endif
+ }
+
+ /* Skip Browse-style entries, popup menus and separators. */
+ while (menu != NULL
+ && ( menu_is_hidden(menu->dname)
+ || (expand_emenu && menu_is_separator(menu->dname))
+ || menu_is_tearoff(menu->dname)
+#ifndef FEAT_BROWSE
+ || menu->dname[STRLEN(menu->dname) - 1] == '.'
+#endif
+ ))
+ {
+ menu = menu->next;
+ if (menu == NULL && !did_alt_menu)
+ {
+ menu = expand_menu_alt;
+ did_alt_menu = TRUE;
+ }
+ }
+
+ if (menu == NULL) /* at end of linked list */
+ return NULL;
+
+ if (menu->modes & expand_modes)
+ {
+ if (menu->children != NULL)
+ {
+#ifdef FEAT_MULTI_LANG
+ if (should_advance)
+ vim_strncpy(tbuffer, menu->en_dname, TBUFFER_LEN - 2);
+ else
+ {
+#endif
+ vim_strncpy(tbuffer, menu->dname, TBUFFER_LEN - 2);
+#ifdef FEAT_MULTI_LANG
+ if (menu->en_dname == NULL)
+ should_advance = TRUE;
+ }
+#endif
+ /* hack on menu separators: use a 'magic' char for the separator
+ * so that '.' in names gets escaped properly */
+ STRCAT(tbuffer, "\001");
+ str = tbuffer;
+ }
+ else
+#ifdef FEAT_MULTI_LANG
+ {
+ if (should_advance)
+ str = menu->en_dname;
+ else
+ {
+#endif
+ str = menu->dname;
+#ifdef FEAT_MULTI_LANG
+ if (menu->en_dname == NULL)
+ should_advance = TRUE;
+ }
+ }
+#endif
+ }
+ else
+ str = (char_u *)"";
+
+#ifdef FEAT_MULTI_LANG
+ if (should_advance)
+#endif
+ {
+ /* Advance to next menu entry. */
+ menu = menu->next;
+ if (menu == NULL && !did_alt_menu)
+ {
+ menu = expand_menu_alt;
+ did_alt_menu = TRUE;
+ }
+ }
+
+#ifdef FEAT_MULTI_LANG
+ should_advance = !should_advance;
+#endif
+
+ return str;
+}
+#endif /* FEAT_CMDL_COMPL */
+
+/*
+ * Skip over this element of the menu path and return the start of the next
+ * element. Any \ and ^Vs are removed from the current element.
+ * "name" may be modified.
+ */
+ char_u *
+menu_name_skip(char_u *name)
+{
+ char_u *p;
+
+ for (p = name; *p && *p != '.'; MB_PTR_ADV(p))
+ {
+ if (*p == '\\' || *p == Ctrl_V)
+ {
+ STRMOVE(p, p + 1);
+ if (*p == NUL)
+ break;
+ }
+ }
+ if (*p)
+ *p++ = NUL;
+ return p;
+}
+
+/*
+ * Return TRUE when "name" matches with menu "menu". The name is compared in
+ * two ways: raw menu name and menu name without '&'. ignore part after a TAB.
+ */
+ static int
+menu_name_equal(char_u *name, vimmenu_T *menu)
+{
+#ifdef FEAT_MULTI_LANG
+ if (menu->en_name != NULL
+ && (menu_namecmp(name, menu->en_name)
+ || menu_namecmp(name, menu->en_dname)))
+ return TRUE;
+#endif
+ return menu_namecmp(name, menu->name) || menu_namecmp(name, menu->dname);
+}
+
+ static int
+menu_namecmp(char_u *name, char_u *mname)
+{
+ int i;
+
+ for (i = 0; name[i] != NUL && name[i] != TAB; ++i)
+ if (name[i] != mname[i])
+ break;
+ return ((name[i] == NUL || name[i] == TAB)
+ && (mname[i] == NUL || mname[i] == TAB));
+}
+
+/*
+ * Return the modes specified by the given menu command (eg :menu! returns
+ * MENU_CMDLINE_MODE | MENU_INSERT_MODE).
+ * If "noremap" is not NULL, then the flag it points to is set according to
+ * whether the command is a "nore" command.
+ * If "unmenu" is not NULL, then the flag it points to is set according to
+ * whether the command is an "unmenu" command.
+ */
+ static int
+get_menu_cmd_modes(
+ char_u *cmd,
+ int forceit, /* Was there a "!" after the command? */
+ int *noremap,
+ int *unmenu)
+{
+ int modes;
+
+ switch (*cmd++)
+ {
+ case 'v': /* vmenu, vunmenu, vnoremenu */
+ modes = MENU_VISUAL_MODE | MENU_SELECT_MODE;
+ break;
+ case 'x': /* xmenu, xunmenu, xnoremenu */
+ modes = MENU_VISUAL_MODE;
+ break;
+ case 's': /* smenu, sunmenu, snoremenu */
+ modes = MENU_SELECT_MODE;
+ break;
+ case 'o': /* omenu */
+ modes = MENU_OP_PENDING_MODE;
+ break;
+ case 'i': /* imenu */
+ modes = MENU_INSERT_MODE;
+ break;
+ case 't':
+ if (*cmd == 'l') /* tlmenu, tlunmenu, tlnoremenu */
+ {
+ modes = MENU_TERMINAL_MODE;
+ ++cmd;
+ break;
+ }
+ modes = MENU_TIP_MODE; /* tmenu */
+ break;
+ case 'c': /* cmenu */
+ modes = MENU_CMDLINE_MODE;
+ break;
+ case 'a': /* amenu */
+ modes = MENU_INSERT_MODE | MENU_CMDLINE_MODE | MENU_NORMAL_MODE
+ | MENU_VISUAL_MODE | MENU_SELECT_MODE
+ | MENU_OP_PENDING_MODE;
+ break;
+ case 'n':
+ if (*cmd != 'o') /* nmenu, not noremenu */
+ {
+ modes = MENU_NORMAL_MODE;
+ break;
+ }
+ /* FALLTHROUGH */
+ default:
+ --cmd;
+ if (forceit) /* menu!! */
+ modes = MENU_INSERT_MODE | MENU_CMDLINE_MODE;
+ else /* menu */
+ modes = MENU_NORMAL_MODE | MENU_VISUAL_MODE | MENU_SELECT_MODE
+ | MENU_OP_PENDING_MODE;
+ }
+
+ if (noremap != NULL)
+ *noremap = (*cmd == 'n' ? REMAP_NONE : REMAP_YES);
+ if (unmenu != NULL)
+ *unmenu = (*cmd == 'u');
+ return modes;
+}
+
+/*
+ * Modify a menu name starting with "PopUp" to include the mode character.
+ * Returns the name in allocated memory (NULL for failure).
+ */
+ static char_u *
+popup_mode_name(char_u *name, int idx)
+{
+ char_u *p;
+ int len = (int)STRLEN(name);
+ char *mode_chars = menu_mode_chars[idx];
+ int mode_chars_len = (int)strlen(mode_chars);
+ int i;
+
+ p = vim_strnsave(name, len + mode_chars_len);
+ if (p != NULL)
+ {
+ mch_memmove(p + 5 + mode_chars_len, p + 5, (size_t)(len - 4));
+ for (i = 0; i < mode_chars_len; ++i)
+ {
+ p[5 + i] = menu_mode_chars[idx][i];
+ }
+ }
+ return p;
+}
+
+#if defined(FEAT_GUI) || defined(PROTO)
+/*
+ * Return the index into the menu->strings or menu->noremap arrays for the
+ * current state. Returns MENU_INDEX_INVALID if there is no mapping for the
+ * given menu in the current mode.
+ */
+ int
+get_menu_index(vimmenu_T *menu, int state)
+{
+ int idx;
+
+ if ((state & INSERT))
+ idx = MENU_INDEX_INSERT;
+ else if (state & CMDLINE)
+ idx = MENU_INDEX_CMDLINE;
+#ifdef FEAT_TERMINAL
+ else if (term_use_loop())
+ idx = MENU_INDEX_TERMINAL;
+#endif
+ else if (VIsual_active)
+ {
+ if (VIsual_select)
+ idx = MENU_INDEX_SELECT;
+ else
+ idx = MENU_INDEX_VISUAL;
+ }
+ else if (state == HITRETURN || state == ASKMORE)
+ idx = MENU_INDEX_CMDLINE;
+ else if (finish_op)
+ idx = MENU_INDEX_OP_PENDING;
+ else if ((state & NORMAL))
+ idx = MENU_INDEX_NORMAL;
+ else
+ idx = MENU_INDEX_INVALID;
+
+ if (idx != MENU_INDEX_INVALID && menu->strings[idx] == NULL)
+ idx = MENU_INDEX_INVALID;
+ return idx;
+}
+#endif
+
+/*
+ * Duplicate the menu item text and then process to see if a mnemonic key
+ * and/or accelerator text has been identified.
+ * Returns a pointer to allocated memory, or NULL for failure.
+ * If mnemonic != NULL, *mnemonic is set to the character after the first '&'.
+ * If actext != NULL, *actext is set to the text after the first TAB.
+ */
+ static char_u *
+menu_text(char_u *str, int *mnemonic, char_u **actext)
+{
+ char_u *p;
+ char_u *text;
+
+ /* Locate accelerator text, after the first TAB */
+ p = vim_strchr(str, TAB);
+ if (p != NULL)
+ {
+ if (actext != NULL)
+ *actext = vim_strsave(p + 1);
+ text = vim_strnsave(str, (int)(p - str));
+ }
+ else
+ text = vim_strsave(str);
+
+ /* Find mnemonic characters "&a" and reduce "&&" to "&". */
+ for (p = text; p != NULL; )
+ {
+ p = vim_strchr(p, '&');
+ if (p != NULL)
+ {
+ if (p[1] == NUL) /* trailing "&" */
+ break;
+ if (mnemonic != NULL && p[1] != '&')
+#if !defined(__MVS__) || defined(MOTIF390_MNEMONIC_FIXED)
+ *mnemonic = p[1];
+#else
+ {
+ /*
+ * Well there is a bug in the Motif libraries on OS390 Unix.
+ * The mnemonic keys needs to be converted to ASCII values
+ * first.
+ * This behavior has been seen in 2.8 and 2.9.
+ */
+ char c = p[1];
+ __etoa_l(&c, 1);
+ *mnemonic = c;
+ }
+#endif
+ STRMOVE(p, p + 1);
+ p = p + 1;
+ }
+ }
+ return text;
+}
+
+/*
+ * Return TRUE if "name" can be a menu in the MenuBar.
+ */
+ int
+menu_is_menubar(char_u *name)
+{
+ return (!menu_is_popup(name)
+ && !menu_is_toolbar(name)
+ && !menu_is_winbar(name)
+ && *name != MNU_HIDDEN_CHAR);
+}
+
+/*
+ * Return TRUE if "name" is a popup menu name.
+ */
+ int
+menu_is_popup(char_u *name)
+{
+ return (STRNCMP(name, "PopUp", 5) == 0);
+}
+
+#if (defined(FEAT_GUI_MOTIF) && (XmVersion <= 1002)) || defined(PROTO)
+/*
+ * Return TRUE if "name" is part of a popup menu.
+ */
+ int
+menu_is_child_of_popup(vimmenu_T *menu)
+{
+ while (menu->parent != NULL)
+ menu = menu->parent;
+ return menu_is_popup(menu->name);
+}
+#endif
+
+/*
+ * Return TRUE if "name" is a toolbar menu name.
+ */
+ int
+menu_is_toolbar(char_u *name)
+{
+ return (STRNCMP(name, "ToolBar", 7) == 0);
+}
+
+/*
+ * Return TRUE if the name is a menu separator identifier: Starts and ends
+ * with '-'
+ */
+ int
+menu_is_separator(char_u *name)
+{
+ return (name[0] == '-' && name[STRLEN(name) - 1] == '-');
+}
+
+/*
+ * Return TRUE if the menu is hidden: Starts with ']'
+ */
+ static int
+menu_is_hidden(char_u *name)
+{
+ return (name[0] == ']') || (menu_is_popup(name) && name[5] != NUL);
+}
+
+#if defined(FEAT_CMDL_COMPL) \
+ || (defined(FEAT_GUI_W32) && defined(FEAT_TEAROFF))
+/*
+ * Return TRUE if the menu is the tearoff menu.
+ */
+ static int
+menu_is_tearoff(char_u *name UNUSED)
+{
+#ifdef FEAT_GUI
+ return (STRCMP(name, TEAR_STRING) == 0);
+#else
+ return FALSE;
+#endif
+}
+#endif
+
+#if defined(FEAT_GUI) || defined(FEAT_TERM_POPUP_MENU) || defined(PROTO)
+
+ static int
+get_menu_mode(void)
+{
+#ifdef FEAT_TERMINAL
+ if (term_use_loop())
+ {
+ return MENU_INDEX_TERMINAL;
+ }
+#endif
+ if (VIsual_active)
+ {
+ if (VIsual_select)
+ return MENU_INDEX_SELECT;
+ return MENU_INDEX_VISUAL;
+ }
+ if (State & INSERT)
+ return MENU_INDEX_INSERT;
+ if ((State & CMDLINE) || State == ASKMORE || State == HITRETURN)
+ return MENU_INDEX_CMDLINE;
+ if (finish_op)
+ return MENU_INDEX_OP_PENDING;
+ if (State & NORMAL)
+ return MENU_INDEX_NORMAL;
+ if (State & LANGMAP) /* must be a "r" command, like Insert mode */
+ return MENU_INDEX_INSERT;
+ return MENU_INDEX_INVALID;
+}
+
+ int
+get_menu_mode_flag(void)
+{
+ int mode = get_menu_mode();
+
+ if (mode == MENU_INDEX_INVALID)
+ return 0;
+ return 1 << mode;
+}
+
+/*
+ * Display the Special "PopUp" menu as a pop-up at the current mouse
+ * position. The "PopUpn" menu is for Normal mode, "PopUpi" for Insert mode,
+ * etc.
+ */
+ void
+show_popupmenu(void)
+{
+ vimmenu_T *menu;
+ int menu_mode;
+ char* mode;
+ int mode_len;
+
+ menu_mode = get_menu_mode();
+ if (menu_mode == MENU_INDEX_INVALID)
+ return;
+ mode = menu_mode_chars[menu_mode];
+ mode_len = (int)strlen(mode);
+
+ apply_autocmds(EVENT_MENUPOPUP, (char_u*)mode, NULL, FALSE, curbuf);
+
+ for (menu = root_menu; menu != NULL; menu = menu->next)
+ if (STRNCMP("PopUp", menu->name, 5) == 0 && STRNCMP(menu->name + 5, mode, mode_len) == 0)
+ break;
+
+ /* Only show a popup when it is defined and has entries */
+ if (menu != NULL && menu->children != NULL)
+ {
+# if defined(FEAT_GUI)
+ if (gui.in_use)
+ {
+ /* Update the menus now, in case the MenuPopup autocommand did
+ * anything. */
+ gui_update_menus(0);
+ gui_mch_show_popupmenu(menu);
+ }
+# endif
+# if defined(FEAT_GUI) && defined(FEAT_TERM_POPUP_MENU)
+ else
+# endif
+# if defined(FEAT_TERM_POPUP_MENU)
+ pum_show_popupmenu(menu);
+# endif
+ }
+}
+#endif
+
+#if defined(FEAT_GUI) || defined(PROTO)
+
+/*
+ * Check that a pointer appears in the menu tree. Used to protect from using
+ * a menu that was deleted after it was selected but before the event was
+ * handled.
+ * Return OK or FAIL. Used recursively.
+ */
+ int
+check_menu_pointer(vimmenu_T *root, vimmenu_T *menu_to_check)
+{
+ vimmenu_T *p;
+
+ for (p = root; p != NULL; p = p->next)
+ if (p == menu_to_check
+ || (p->children != NULL
+ && check_menu_pointer(p->children, menu_to_check) == OK))
+ return OK;
+ return FAIL;
+}
+
+/*
+ * After we have started the GUI, then we can create any menus that have been
+ * defined. This is done once here. add_menu_path() may have already been
+ * called to define these menus, and may be called again. This function calls
+ * itself recursively. Should be called at the top level with:
+ * gui_create_initial_menus(root_menu);
+ */
+ void
+gui_create_initial_menus(vimmenu_T *menu)
+{
+ int idx = 0;
+
+ while (menu != NULL)
+ {
+ /* Don't add a menu when only a tip was defined. */
+ if (menu->modes & MENU_ALL_MODES)
+ {
+ if (menu->children != NULL)
+ {
+ gui_mch_add_menu(menu, idx);
+ gui_create_initial_menus(menu->children);
+ }
+ else
+ gui_mch_add_menu_item(menu, idx);
+ }
+ menu = menu->next;
+ ++idx;
+ }
+}
+
+/*
+ * Used recursively by gui_update_menus (see below)
+ */
+ static void
+gui_update_menus_recurse(vimmenu_T *menu, int mode)
+{
+ int grey;
+
+ while (menu)
+ {
+ if ((menu->modes & menu->enabled & mode)
+# if defined(FEAT_GUI_W32) && defined(FEAT_TEAROFF)
+ || menu_is_tearoff(menu->dname)
+# endif
+ )
+ grey = FALSE;
+ else
+ grey = TRUE;
+# ifdef FEAT_GUI_ATHENA
+ /* Hiding menus doesn't work for Athena, it can cause a crash. */
+ gui_mch_menu_grey(menu, grey);
+# else
+ /* Never hide a toplevel menu, it may make the menubar resize or
+ * disappear. Same problem for ToolBar items. */
+ if (vim_strchr(p_go, GO_GREY) != NULL || menu->parent == NULL
+# ifdef FEAT_TOOLBAR
+ || menu_is_toolbar(menu->parent->name)
+# endif
+ )
+ gui_mch_menu_grey(menu, grey);
+ else
+ gui_mch_menu_hidden(menu, grey);
+# endif
+ gui_update_menus_recurse(menu->children, mode);
+ menu = menu->next;
+ }
+}
+
+/*
+ * Make sure only the valid menu items appear for this mode. If
+ * force_menu_update is not TRUE, then we only do this if the mode has changed
+ * since last time. If "modes" is not 0, then we use these modes instead.
+ */
+ void
+gui_update_menus(int modes)
+{
+ static int prev_mode = -1;
+ int mode = 0;
+
+ if (modes != 0x0)
+ mode = modes;
+ else
+ mode = get_menu_mode_flag();
+
+ if (force_menu_update || mode != prev_mode)
+ {
+ gui_update_menus_recurse(root_menu, mode);
+ gui_mch_draw_menubar();
+ prev_mode = mode;
+ force_menu_update = FALSE;
+ }
+}
+
+# if defined(FEAT_GUI_MSWIN) || defined(FEAT_GUI_MOTIF) \
+ || defined(FEAT_GUI_GTK) || defined(FEAT_GUI_PHOTON) || defined(PROTO)
+/*
+ * Check if a key is used as a mnemonic for a toplevel menu.
+ * Case of the key is ignored.
+ */
+ int
+gui_is_menu_shortcut(int key)
+{
+ vimmenu_T *menu;
+
+ if (key < 256)
+ key = TOLOWER_LOC(key);
+ for (menu = root_menu; menu != NULL; menu = menu->next)
+ if (menu->mnemonic == key
+ || (menu->mnemonic < 256 && TOLOWER_LOC(menu->mnemonic) == key))
+ return TRUE;
+ return FALSE;
+}
+# endif
+#endif /* FEAT_GUI */
+
+#if (defined(FEAT_GUI_W32) && defined(FEAT_TEAROFF)) || defined(PROTO)
+
+/*
+ * Deal with tearoff items that are added like a menu item.
+ * Currently only for Win32 GUI. Others may follow later.
+ */
+
+ void
+gui_mch_toggle_tearoffs(int enable)
+{
+ int pri_tab[MENUDEPTH + 1];
+ int i;
+
+ if (enable)
+ {
+ for (i = 0; i < MENUDEPTH; ++i)
+ pri_tab[i] = 500;
+ pri_tab[MENUDEPTH] = -1;
+ gui_create_tearoffs_recurse(root_menu, (char_u *)"", pri_tab, 0);
+ }
+ else
+ gui_destroy_tearoffs_recurse(root_menu);
+ s_tearoffs = enable;
+}
+
+/*
+ * Recursively add tearoff items
+ */
+ static void
+gui_create_tearoffs_recurse(
+ vimmenu_T *menu,
+ const char_u *pname,
+ int *pri_tab,
+ int pri_idx)
+{
+ char_u *newpname = NULL;
+ int len;
+ char_u *s;
+ char_u *d;
+
+ if (pri_tab[pri_idx + 1] != -1)
+ ++pri_idx;
+ while (menu != NULL)
+ {
+ if (menu->children != NULL && menu_is_menubar(menu->name))
+ {
+ /* Add the menu name to the menu path. Insert a backslash before
+ * dots (it's used to separate menu names). */
+ len = (int)STRLEN(pname) + (int)STRLEN(menu->name);
+ for (s = menu->name; *s; ++s)
+ if (*s == '.' || *s == '\\')
+ ++len;
+ newpname = alloc(len + TEAR_LEN + 2);
+ if (newpname != NULL)
+ {
+ STRCPY(newpname, pname);
+ d = newpname + STRLEN(newpname);
+ for (s = menu->name; *s; ++s)
+ {
+ if (*s == '.' || *s == '\\')
+ *d++ = '\\';
+ *d++ = *s;
+ }
+ *d = NUL;
+
+ /* check if tearoff already exists */
+ if (STRCMP(menu->children->name, TEAR_STRING) != 0)
+ {
+ gui_add_tearoff(newpname, pri_tab, pri_idx - 1);
+ *d = NUL; /* remove TEAR_STRING */
+ }
+
+ STRCAT(newpname, ".");
+ gui_create_tearoffs_recurse(menu->children, newpname,
+ pri_tab, pri_idx);
+ vim_free(newpname);
+ }
+ }
+ menu = menu->next;
+ }
+}
+
+/*
+ * Add tear-off menu item for a submenu.
+ * "tearpath" is the menu path, and must have room to add TEAR_STRING.
+ */
+ static void
+gui_add_tearoff(char_u *tearpath, int *pri_tab, int pri_idx)
+{
+ char_u *tbuf;
+ int t;
+ vimmenu_T menuarg;
+
+ tbuf = alloc(5 + (unsigned int)STRLEN(tearpath));
+ if (tbuf != NULL)
+ {
+ tbuf[0] = K_SPECIAL;
+ tbuf[1] = K_SECOND(K_TEAROFF);
+ tbuf[2] = K_THIRD(K_TEAROFF);
+ STRCPY(tbuf + 3, tearpath);
+ STRCAT(tbuf + 3, "\r");
+
+ STRCAT(tearpath, ".");
+ STRCAT(tearpath, TEAR_STRING);
+
+ /* Priority of tear-off is always 1 */
+ t = pri_tab[pri_idx + 1];
+ pri_tab[pri_idx + 1] = 1;
+
+#ifdef FEAT_TOOLBAR
+ menuarg.iconfile = NULL;
+ menuarg.iconidx = -1;
+ menuarg.icon_builtin = FALSE;
+#endif
+ menuarg.noremap[0] = REMAP_NONE;
+ menuarg.silent[0] = TRUE;
+
+ menuarg.modes = MENU_ALL_MODES;
+ add_menu_path(tearpath, &menuarg, pri_tab, tbuf, FALSE);
+
+ menuarg.modes = MENU_TIP_MODE;
+ add_menu_path(tearpath, &menuarg, pri_tab,
+ (char_u *)_("Tear off this menu"), FALSE);
+
+ pri_tab[pri_idx + 1] = t;
+ vim_free(tbuf);
+ }
+}
+
+/*
+ * Recursively destroy tearoff items
+ */
+ static void
+gui_destroy_tearoffs_recurse(vimmenu_T *menu)
+{
+ while (menu)
+ {
+ if (menu->children)
+ {
+ /* check if tearoff exists */
+ if (STRCMP(menu->children->name, TEAR_STRING) == 0)
+ {
+ /* Disconnect the item and free the memory */
+ free_menu(&menu->children);
+ }
+ if (menu->children != NULL) /* if not the last one */
+ gui_destroy_tearoffs_recurse(menu->children);
+ }
+ menu = menu->next;
+ }
+}
+
+#endif /* FEAT_GUI_W32 && FEAT_TEAROFF */
+
+/*
+ * Execute "menu". Use by ":emenu" and the window toolbar.
+ * "eap" is NULL for the window toolbar.
+ * "mode_idx" specifies a MENU_INDEX_ value, use -1 to depend on the current
+ * state.
+ */
+ void
+execute_menu(exarg_T *eap, vimmenu_T *menu, int mode_idx)
+{
+ int idx = mode_idx;
+
+ if (idx < 0)
+ {
+ /* Use the Insert mode entry when returning to Insert mode. */
+ if (restart_edit
+#ifdef FEAT_EVAL
+ && !current_sctx.sc_sid
+#endif
+ )
+ {
+ idx = MENU_INDEX_INSERT;
+ }
+#ifdef FEAT_TERMINAL
+ else if (term_use_loop())
+ {
+ idx = MENU_INDEX_TERMINAL;
+ }
+#endif
+ else if (VIsual_active)
+ {
+ idx = MENU_INDEX_VISUAL;
+ }
+ else if (eap != NULL && eap->addr_count)
+ {
+ pos_T tpos;
+
+ idx = MENU_INDEX_VISUAL;
+
+ /* GEDDES: This is not perfect - but it is a
+ * quick way of detecting whether we are doing this from a
+ * selection - see if the range matches up with the visual
+ * select start and end. */
+ if ((curbuf->b_visual.vi_start.lnum == eap->line1)
+ && (curbuf->b_visual.vi_end.lnum) == eap->line2)
+ {
+ /* Set it up for visual mode - equivalent to gv. */
+ VIsual_mode = curbuf->b_visual.vi_mode;
+ tpos = curbuf->b_visual.vi_end;
+ curwin->w_cursor = curbuf->b_visual.vi_start;
+ curwin->w_curswant = curbuf->b_visual.vi_curswant;
+ }
+ else
+ {
+ /* Set it up for line-wise visual mode */
+ VIsual_mode = 'V';
+ curwin->w_cursor.lnum = eap->line1;
+ curwin->w_cursor.col = 1;
+ tpos.lnum = eap->line2;
+ tpos.col = MAXCOL;
+ tpos.coladd = 0;
+ }
+
+ /* Activate visual mode */
+ VIsual_active = TRUE;
+ VIsual_reselect = TRUE;
+ check_cursor();
+ VIsual = curwin->w_cursor;
+ curwin->w_cursor = tpos;
+
+ check_cursor();
+
+ /* Adjust the cursor to make sure it is in the correct pos
+ * for exclusive mode */
+ if (*p_sel == 'e' && gchar_cursor() != NUL)
+ ++curwin->w_cursor.col;
+ }
+ }
+
+ /* For the WinBar menu always use the Normal mode menu. */
+ if (idx == -1 || eap == NULL)
+ idx = MENU_INDEX_NORMAL;
+
+ if (idx != MENU_INDEX_INVALID && menu->strings[idx] != NULL)
+ {
+ /* When executing a script or function execute the commands right now.
+ * Also for the window toolbar.
+ * Otherwise put them in the typeahead buffer. */
+ if (eap == NULL
+#ifdef FEAT_EVAL
+ || current_sctx.sc_sid != 0
+#endif
+ )
+ {
+ save_state_T save_state;
+
+ ++ex_normal_busy;
+ if (save_current_state(&save_state))
+ exec_normal_cmd(menu->strings[idx], menu->noremap[idx],
+ menu->silent[idx]);
+ restore_current_state(&save_state);
+ --ex_normal_busy;
+ }
+ else
+ ins_typebuf(menu->strings[idx], menu->noremap[idx], 0,
+ TRUE, menu->silent[idx]);
+ }
+ else if (eap != NULL)
+ {
+ char_u *mode;
+
+ switch (idx)
+ {
+ case MENU_INDEX_VISUAL:
+ mode = (char_u *)"Visual";
+ break;
+ case MENU_INDEX_SELECT:
+ mode = (char_u *)"Select";
+ break;
+ case MENU_INDEX_OP_PENDING:
+ mode = (char_u *)"Op-pending";
+ break;
+ case MENU_INDEX_TERMINAL:
+ mode = (char_u *)"Terminal";
+ break;
+ case MENU_INDEX_INSERT:
+ mode = (char_u *)"Insert";
+ break;
+ case MENU_INDEX_CMDLINE:
+ mode = (char_u *)"Cmdline";
+ break;
+ // case MENU_INDEX_TIP: cannot happen
+ default:
+ mode = (char_u *)"Normal";
+ }
+ semsg(_("E335: Menu not defined for %s mode"), mode);
+ }
+}
+
+/*
+ * Given a menu descriptor, e.g. "File.New", find it in the menu hierarchy and
+ * execute it.
+ */
+ void
+ex_emenu(exarg_T *eap)
+{
+ vimmenu_T *menu;
+ char_u *name;
+ char_u *saved_name;
+ char_u *arg = eap->arg;
+ char_u *p;
+ int gave_emsg = FALSE;
+ int mode_idx = -1;
+
+ if (arg[0] && VIM_ISWHITE(arg[1]))
+ {
+ switch (arg[0])
+ {
+ case 'n': mode_idx = MENU_INDEX_NORMAL; break;
+ case 'v': mode_idx = MENU_INDEX_VISUAL; break;
+ case 's': mode_idx = MENU_INDEX_SELECT; break;
+ case 'o': mode_idx = MENU_INDEX_OP_PENDING; break;
+ case 't': mode_idx = MENU_INDEX_TERMINAL; break;
+ case 'i': mode_idx = MENU_INDEX_INSERT; break;
+ case 'c': mode_idx = MENU_INDEX_CMDLINE; break;
+ default: semsg(_(e_invarg2), arg);
+ return;
+ }
+ arg = skipwhite(arg + 2);
+ }
+
+ saved_name = vim_strsave(arg);
+ if (saved_name == NULL)
+ return;
+
+ menu = *get_root_menu(saved_name);
+ name = saved_name;
+ while (*name)
+ {
+ /* Find in the menu hierarchy */
+ p = menu_name_skip(name);
+
+ while (menu != NULL)
+ {
+ if (menu_name_equal(name, menu))
+ {
+ if (*p == NUL && menu->children != NULL)
+ {
+ emsg(_("E333: Menu path must lead to a menu item"));
+ gave_emsg = TRUE;
+ menu = NULL;
+ }
+ else if (*p != NUL && menu->children == NULL)
+ {
+ emsg(_(e_notsubmenu));
+ menu = NULL;
+ }
+ break;
+ }
+ menu = menu->next;
+ }
+ if (menu == NULL || *p == NUL)
+ break;
+ menu = menu->children;
+ name = p;
+ }
+ vim_free(saved_name);
+ if (menu == NULL)
+ {
+ if (!gave_emsg)
+ semsg(_("E334: Menu not found: %s"), arg);
+ return;
+ }
+
+ // Found the menu, so execute.
+ execute_menu(eap, menu, mode_idx);
+}
+
+/*
+ * Handle a click in the window toolbar of "wp" at column "col".
+ */
+ void
+winbar_click(win_T *wp, int col)
+{
+ int idx;
+
+ if (wp->w_winbar_items == NULL)
+ return;
+ for (idx = 0; wp->w_winbar_items[idx].wb_menu != NULL; ++idx)
+ {
+ winbar_item_T *item = &wp->w_winbar_items[idx];
+
+ if (col >= item->wb_startcol && col <= item->wb_endcol)
+ {
+ win_T *save_curwin = NULL;
+ pos_T save_visual = VIsual;
+ int save_visual_active = VIsual_active;
+ int save_visual_select = VIsual_select;
+ int save_visual_reselect = VIsual_reselect;
+ int save_visual_mode = VIsual_mode;
+
+ if (wp != curwin)
+ {
+ /* Clicking in the window toolbar of a not-current window.
+ * Make that window the current one and save Visual mode. */
+ save_curwin = curwin;
+ VIsual_active = FALSE;
+ curwin = wp;
+ curbuf = curwin->w_buffer;
+ check_cursor();
+ }
+
+ execute_menu(NULL, item->wb_menu, -1);
+
+ if (save_curwin != NULL)
+ {
+ curwin = save_curwin;
+ curbuf = curwin->w_buffer;
+ VIsual = save_visual;
+ VIsual_active = save_visual_active;
+ VIsual_select = save_visual_select;
+ VIsual_reselect = save_visual_reselect;
+ VIsual_mode = save_visual_mode;
+ }
+ }
+ }
+}
+
+#if defined(FEAT_GUI_MSWIN) || defined(FEAT_GUI_GTK) \
+ || defined(FEAT_TERM_POPUP_MENU) \
+ || defined(FEAT_BEVAL_TIP) || defined(PROTO)
+/*
+ * Given a menu descriptor, e.g. "File.New", find it in the menu hierarchy.
+ */
+ vimmenu_T *
+gui_find_menu(char_u *path_name)
+{
+ vimmenu_T *menu = NULL;
+ char_u *name;
+ char_u *saved_name;
+ char_u *p;
+
+ menu = *get_root_menu(path_name);
+
+ saved_name = vim_strsave(path_name);
+ if (saved_name == NULL)
+ return NULL;
+
+ name = saved_name;
+ while (*name)
+ {
+ /* find the end of one dot-separated name and put a NUL at the dot */
+ p = menu_name_skip(name);
+
+ while (menu != NULL)
+ {
+ if (menu_name_equal(name, menu))
+ {
+ if (menu->children == NULL)
+ {
+ /* found a menu item instead of a sub-menu */
+ if (*p == NUL)
+ emsg(_("E336: Menu path must lead to a sub-menu"));
+ else
+ emsg(_(e_notsubmenu));
+ menu = NULL;
+ goto theend;
+ }
+ if (*p == NUL) /* found a full match */
+ goto theend;
+ break;
+ }
+ menu = menu->next;
+ }
+ if (menu == NULL) /* didn't find it */
+ break;
+
+ /* Found a match, search the sub-menu. */
+ menu = menu->children;
+ name = p;
+ }
+
+ if (menu == NULL)
+ emsg(_("E337: Menu not found - check menu names"));
+theend:
+ vim_free(saved_name);
+ return menu;
+}
+#endif
+
+#ifdef FEAT_MULTI_LANG
+/*
+ * Translation of menu names. Just a simple lookup table.
+ */
+
+typedef struct
+{
+ char_u *from; /* English name */
+ char_u *from_noamp; /* same, without '&' */
+ char_u *to; /* translated name */
+} menutrans_T;
+
+static garray_T menutrans_ga = {0, 0, 0, 0, NULL};
+#endif
+
+/*
+ * ":menutrans".
+ * This function is also defined without the +multi_lang feature, in which
+ * case the commands are ignored.
+ */
+ void
+ex_menutranslate(exarg_T *eap UNUSED)
+{
+#ifdef FEAT_MULTI_LANG
+ char_u *arg = eap->arg;
+ menutrans_T *tp;
+ int i;
+ char_u *from, *from_noamp, *to;
+
+ if (menutrans_ga.ga_itemsize == 0)
+ ga_init2(&menutrans_ga, (int)sizeof(menutrans_T), 5);
+
+ /*
+ * ":menutrans clear": clear all translations.
+ */
+ if (STRNCMP(arg, "clear", 5) == 0 && ends_excmd(*skipwhite(arg + 5)))
+ {
+ tp = (menutrans_T *)menutrans_ga.ga_data;
+ for (i = 0; i < menutrans_ga.ga_len; ++i)
+ {
+ vim_free(tp[i].from);
+ vim_free(tp[i].from_noamp);
+ vim_free(tp[i].to);
+ }
+ ga_clear(&menutrans_ga);
+# ifdef FEAT_EVAL
+ /* Delete all "menutrans_" global variables. */
+ del_menutrans_vars();
+# endif
+ }
+ else
+ {
+ /* ":menutrans from to": add translation */
+ from = arg;
+ arg = menu_skip_part(arg);
+ to = skipwhite(arg);
+ *arg = NUL;
+ arg = menu_skip_part(to);
+ if (arg == to)
+ emsg(_(e_invarg));
+ else
+ {
+ if (ga_grow(&menutrans_ga, 1) == OK)
+ {
+ tp = (menutrans_T *)menutrans_ga.ga_data;
+ from = vim_strsave(from);
+ if (from != NULL)
+ {
+ from_noamp = menu_text(from, NULL, NULL);
+ to = vim_strnsave(to, (int)(arg - to));
+ if (from_noamp != NULL && to != NULL)
+ {
+ menu_translate_tab_and_shift(from);
+ menu_translate_tab_and_shift(to);
+ menu_unescape_name(from);
+ menu_unescape_name(to);
+ tp[menutrans_ga.ga_len].from = from;
+ tp[menutrans_ga.ga_len].from_noamp = from_noamp;
+ tp[menutrans_ga.ga_len].to = to;
+ ++menutrans_ga.ga_len;
+ }
+ else
+ {
+ vim_free(from);
+ vim_free(from_noamp);
+ vim_free(to);
+ }
+ }
+ }
+ }
+ }
+#endif
+}
+
+#if defined(FEAT_MULTI_LANG) || defined(FEAT_TOOLBAR)
+/*
+ * Find the character just after one part of a menu name.
+ */
+ static char_u *
+menu_skip_part(char_u *p)
+{
+ while (*p != NUL && *p != '.' && !VIM_ISWHITE(*p))
+ {
+ if ((*p == '\\' || *p == Ctrl_V) && p[1] != NUL)
+ ++p;
+ ++p;
+ }
+ return p;
+}
+#endif
+
+#ifdef FEAT_MULTI_LANG
+/*
+ * Lookup part of a menu name in the translations.
+ * Return a pointer to the translation or NULL if not found.
+ */
+ static char_u *
+menutrans_lookup(char_u *name, int len)
+{
+ menutrans_T *tp = (menutrans_T *)menutrans_ga.ga_data;
+ int i;
+ char_u *dname;
+
+ for (i = 0; i < menutrans_ga.ga_len; ++i)
+ if (STRNICMP(name, tp[i].from, len) == 0 && tp[i].from[len] == NUL)
+ return tp[i].to;
+
+ /* Now try again while ignoring '&' characters. */
+ i = name[len];
+ name[len] = NUL;
+ dname = menu_text(name, NULL, NULL);
+ name[len] = i;
+ if (dname != NULL)
+ {
+ for (i = 0; i < menutrans_ga.ga_len; ++i)
+ if (STRICMP(dname, tp[i].from_noamp) == 0)
+ {
+ vim_free(dname);
+ return tp[i].to;
+ }
+ vim_free(dname);
+ }
+
+ return NULL;
+}
+
+/*
+ * Unescape the name in the translate dictionary table.
+ */
+ static void
+menu_unescape_name(char_u *name)
+{
+ char_u *p;
+
+ for (p = name; *p && *p != '.'; MB_PTR_ADV(p))
+ if (*p == '\\')
+ STRMOVE(p, p + 1);
+}
+#endif /* FEAT_MULTI_LANG */
+
+/*
+ * Isolate the menu name.
+ * Skip the menu name, and translate <Tab> into a real TAB.
+ */
+ static char_u *
+menu_translate_tab_and_shift(char_u *arg_start)
+{
+ char_u *arg = arg_start;
+
+ while (*arg && !VIM_ISWHITE(*arg))
+ {
+ if ((*arg == '\\' || *arg == Ctrl_V) && arg[1] != NUL)
+ arg++;
+ else if (STRNICMP(arg, "<TAB>", 5) == 0)
+ {
+ *arg = TAB;
+ STRMOVE(arg + 1, arg + 5);
+ }
+ arg++;
+ }
+ if (*arg != NUL)
+ *arg++ = NUL;
+ arg = skipwhite(arg);
+
+ return arg;
+}
+
+#endif /* FEAT_MENU */
diff --git a/src/message.c b/src/message.c
new file mode 100644
index 0000000..063fada
--- /dev/null
+++ b/src/message.c
@@ -0,0 +1,5161 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * message.c: functions for displaying messages on the command line
+ */
+
+#define MESSAGE_FILE /* don't include prototype for smsg() */
+#define USING_FLOAT_STUFF
+
+#include "vim.h"
+
+static void add_msg_hist(char_u *s, int len, int attr);
+static void hit_return_msg(void);
+static void msg_home_replace_attr(char_u *fname, int attr);
+static void msg_puts_attr_len(char *str, int maxlen, int attr);
+static void msg_puts_display(char_u *str, int maxlen, int attr, int recurse);
+static void msg_scroll_up(void);
+static void inc_msg_scrolled(void);
+static void store_sb_text(char_u **sb_str, char_u *s, int attr, int *sb_col, int finish);
+static void t_puts(int *t_col, char_u *t_s, char_u *s, int attr);
+static void msg_puts_printf(char_u *str, int maxlen);
+static int do_more_prompt(int typed_char);
+static void msg_screen_putchar(int c, int attr);
+static int msg_check_screen(void);
+static void redir_write(char_u *s, int maxlen);
+#ifdef FEAT_CON_DIALOG
+static char_u *msg_show_console_dialog(char_u *message, char_u *buttons, int dfltbutton);
+static int confirm_msg_used = FALSE; /* displaying confirm_msg */
+static char_u *confirm_msg = NULL; /* ":confirm" message */
+static char_u *confirm_msg_tail; /* tail of confirm_msg */
+#endif
+#ifdef FEAT_JOB_CHANNEL
+static int emsg_to_channel_log = FALSE;
+#endif
+
+struct msg_hist
+{
+ struct msg_hist *next;
+ char_u *msg;
+ int attr;
+};
+
+static struct msg_hist *first_msg_hist = NULL;
+static struct msg_hist *last_msg_hist = NULL;
+static int msg_hist_len = 0;
+
+static FILE *verbose_fd = NULL;
+static int verbose_did_open = FALSE;
+
+/*
+ * When writing messages to the screen, there are many different situations.
+ * A number of variables is used to remember the current state:
+ * msg_didany TRUE when messages were written since the last time the
+ * user reacted to a prompt.
+ * Reset: After hitting a key for the hit-return prompt,
+ * hitting <CR> for the command line or input().
+ * Set: When any message is written to the screen.
+ * msg_didout TRUE when something was written to the current line.
+ * Reset: When advancing to the next line, when the current
+ * text can be overwritten.
+ * Set: When any message is written to the screen.
+ * msg_nowait No extra delay for the last drawn message.
+ * Used in normal_cmd() before the mode message is drawn.
+ * emsg_on_display There was an error message recently. Indicates that there
+ * should be a delay before redrawing.
+ * msg_scroll The next message should not overwrite the current one.
+ * msg_scrolled How many lines the screen has been scrolled (because of
+ * messages). Used in update_screen() to scroll the screen
+ * back. Incremented each time the screen scrolls a line.
+ * msg_scrolled_ign TRUE when msg_scrolled is non-zero and msg_puts_attr()
+ * writes something without scrolling should not make
+ * need_wait_return to be set. This is a hack to make ":ts"
+ * work without an extra prompt.
+ * lines_left Number of lines available for messages before the
+ * more-prompt is to be given. -1 when not set.
+ * need_wait_return TRUE when the hit-return prompt is needed.
+ * Reset: After giving the hit-return prompt, when the user
+ * has answered some other prompt.
+ * Set: When the ruler or typeahead display is overwritten,
+ * scrolling the screen for some message.
+ * keep_msg Message to be displayed after redrawing the screen, in
+ * main_loop().
+ * This is an allocated string or NULL when not used.
+ */
+
+/*
+ * msg(s) - displays the string 's' on the status line
+ * When terminal not initialized (yet) mch_errmsg(..) is used.
+ * return TRUE if wait_return not called
+ */
+ int
+msg(char *s)
+{
+ return msg_attr_keep(s, 0, FALSE);
+}
+
+#if defined(FEAT_EVAL) || defined(FEAT_X11) || defined(USE_XSMP) \
+ || defined(FEAT_GUI_GTK) || defined(PROTO)
+/*
+ * Like msg() but keep it silent when 'verbosefile' is set.
+ */
+ int
+verb_msg(char *s)
+{
+ int n;
+
+ verbose_enter();
+ n = msg_attr_keep(s, 0, FALSE);
+ verbose_leave();
+
+ return n;
+}
+#endif
+
+ int
+msg_attr(char *s, int attr)
+{
+ return msg_attr_keep(s, attr, FALSE);
+}
+
+ int
+msg_attr_keep(
+ char *s,
+ int attr,
+ int keep) /* TRUE: set keep_msg if it doesn't scroll */
+{
+ static int entered = 0;
+ int retval;
+ char_u *buf = NULL;
+
+ /* Skip messages not matching ":filter pattern".
+ * Don't filter when there is an error. */
+ if (!emsg_on_display && message_filtered((char_u *)s))
+ return TRUE;
+
+#ifdef FEAT_EVAL
+ if (attr == 0)
+ set_vim_var_string(VV_STATUSMSG, (char_u *)s, -1);
+#endif
+
+ /*
+ * It is possible that displaying a messages causes a problem (e.g.,
+ * when redrawing the window), which causes another message, etc.. To
+ * break this loop, limit the recursiveness to 3 levels.
+ */
+ if (entered >= 3)
+ return TRUE;
+ ++entered;
+
+ /* Add message to history (unless it's a repeated kept message or a
+ * truncated message) */
+ if ((char_u *)s != keep_msg
+ || (*s != '<'
+ && last_msg_hist != NULL
+ && last_msg_hist->msg != NULL
+ && STRCMP(s, last_msg_hist->msg)))
+ add_msg_hist((char_u *)s, -1, attr);
+
+#ifdef FEAT_JOB_CHANNEL
+ if (emsg_to_channel_log)
+ /* Write message in the channel log. */
+ ch_log(NULL, "ERROR: %s", (char *)s);
+#endif
+
+ /* When displaying keep_msg, don't let msg_start() free it, caller must do
+ * that. */
+ if ((char_u *)s == keep_msg)
+ keep_msg = NULL;
+
+ /* Truncate the message if needed. */
+ msg_start();
+ buf = msg_strtrunc((char_u *)s, FALSE);
+ if (buf != NULL)
+ s = (char *)buf;
+
+ msg_outtrans_attr((char_u *)s, attr);
+ msg_clr_eos();
+ retval = msg_end();
+
+ if (keep && retval && vim_strsize((char_u *)s)
+ < (int)(Rows - cmdline_row - 1) * Columns + sc_col)
+ set_keep_msg((char_u *)s, 0);
+
+ vim_free(buf);
+ --entered;
+ return retval;
+}
+
+/*
+ * Truncate a string such that it can be printed without causing a scroll.
+ * Returns an allocated string or NULL when no truncating is done.
+ */
+ char_u *
+msg_strtrunc(
+ char_u *s,
+ int force) /* always truncate */
+{
+ char_u *buf = NULL;
+ int len;
+ int room;
+
+ /* May truncate message to avoid a hit-return prompt */
+ if ((!msg_scroll && !need_wait_return && shortmess(SHM_TRUNCALL)
+ && !exmode_active && msg_silent == 0) || force)
+ {
+ len = vim_strsize(s);
+ if (msg_scrolled != 0)
+ /* Use all the columns. */
+ room = (int)(Rows - msg_row) * Columns - 1;
+ else
+ /* Use up to 'showcmd' column. */
+ room = (int)(Rows - msg_row - 1) * Columns + sc_col - 1;
+ if (len > room && room > 0)
+ {
+ if (enc_utf8)
+ /* may have up to 18 bytes per cell (6 per char, up to two
+ * composing chars) */
+ len = (room + 2) * 18;
+ else if (enc_dbcs == DBCS_JPNU)
+ /* may have up to 2 bytes per cell for euc-jp */
+ len = (room + 2) * 2;
+ else
+ len = room + 2;
+ buf = alloc(len);
+ if (buf != NULL)
+ trunc_string(s, buf, room, len);
+ }
+ }
+ return buf;
+}
+
+/*
+ * Truncate a string "s" to "buf" with cell width "room".
+ * "s" and "buf" may be equal.
+ */
+ void
+trunc_string(
+ char_u *s,
+ char_u *buf,
+ int room_in,
+ int buflen)
+{
+ size_t room = room_in - 3; /* "..." takes 3 chars */
+ size_t half;
+ size_t len = 0;
+ int e;
+ int i;
+ int n;
+
+ if (room_in < 3)
+ room = 0;
+ half = room / 2;
+
+ /* First part: Start of the string. */
+ for (e = 0; len < half && e < buflen; ++e)
+ {
+ if (s[e] == NUL)
+ {
+ /* text fits without truncating! */
+ buf[e] = NUL;
+ return;
+ }
+ n = ptr2cells(s + e);
+ if (len + n > half)
+ break;
+ len += n;
+ buf[e] = s[e];
+ if (has_mbyte)
+ for (n = (*mb_ptr2len)(s + e); --n > 0; )
+ {
+ if (++e == buflen)
+ break;
+ buf[e] = s[e];
+ }
+ }
+
+ /* Last part: End of the string. */
+ i = e;
+ if (enc_dbcs != 0)
+ {
+ /* For DBCS going backwards in a string is slow, but
+ * computing the cell width isn't too slow: go forward
+ * until the rest fits. */
+ n = vim_strsize(s + i);
+ while (len + n > room)
+ {
+ n -= ptr2cells(s + i);
+ i += (*mb_ptr2len)(s + i);
+ }
+ }
+ else if (enc_utf8)
+ {
+ /* For UTF-8 we can go backwards easily. */
+ half = i = (int)STRLEN(s);
+ for (;;)
+ {
+ do
+ half = half - utf_head_off(s, s + half - 1) - 1;
+ while (half > 0 && utf_iscomposing(utf_ptr2char(s + half)));
+ n = ptr2cells(s + half);
+ if (len + n > room || half == 0)
+ break;
+ len += n;
+ i = (int)half;
+ }
+ }
+ else
+ {
+ for (i = (int)STRLEN(s); len + (n = ptr2cells(s + i - 1)) <= room; --i)
+ len += n;
+ }
+
+
+ if (i <= e + 3)
+ {
+ /* text fits without truncating */
+ if (s != buf)
+ {
+ len = STRLEN(s);
+ if (len >= (size_t)buflen)
+ len = buflen - 1;
+ len = len - e + 1;
+ if (len < 1)
+ buf[e - 1] = NUL;
+ else
+ mch_memmove(buf + e, s + e, len);
+ }
+ }
+ else if (e + 3 < buflen)
+ {
+ /* set the middle and copy the last part */
+ mch_memmove(buf + e, "...", (size_t)3);
+ len = STRLEN(s + i) + 1;
+ if (len >= (size_t)buflen - e - 3)
+ len = buflen - e - 3 - 1;
+ mch_memmove(buf + e + 3, s + i, len);
+ buf[e + 3 + len - 1] = NUL;
+ }
+ else
+ {
+ /* can't fit in the "...", just truncate it */
+ buf[e - 1] = NUL;
+ }
+}
+
+/*
+ * Automatic prototype generation does not understand this function.
+ * Note: Caller of smsg() and smsg_attr() must check the resulting string is
+ * shorter than IOSIZE!!!
+ */
+#ifndef PROTO
+
+int vim_snprintf(char *str, size_t str_m, const char *fmt, ...);
+
+ int
+# ifdef __BORLANDC__
+_RTLENTRYF
+# endif
+smsg(const char *s, ...)
+{
+ va_list arglist;
+
+ va_start(arglist, s);
+ vim_vsnprintf((char *)IObuff, IOSIZE, s, arglist);
+ va_end(arglist);
+ return msg((char *)IObuff);
+}
+
+ int
+# ifdef __BORLANDC__
+_RTLENTRYF
+# endif
+smsg_attr(int attr, const char *s, ...)
+{
+ va_list arglist;
+
+ va_start(arglist, s);
+ vim_vsnprintf((char *)IObuff, IOSIZE, s, arglist);
+ va_end(arglist);
+ return msg_attr((char *)IObuff, attr);
+}
+
+ int
+# ifdef __BORLANDC__
+_RTLENTRYF
+# endif
+smsg_attr_keep(int attr, const char *s, ...)
+{
+ va_list arglist;
+
+ va_start(arglist, s);
+ vim_vsnprintf((char *)IObuff, IOSIZE, s, arglist);
+ va_end(arglist);
+ return msg_attr_keep((char *)IObuff, attr, TRUE);
+}
+
+#endif
+
+/*
+ * Remember the last sourcing name/lnum used in an error message, so that it
+ * isn't printed each time when it didn't change.
+ */
+static int last_sourcing_lnum = 0;
+static char_u *last_sourcing_name = NULL;
+
+/*
+ * Reset the last used sourcing name/lnum. Makes sure it is displayed again
+ * for the next error message;
+ */
+ void
+reset_last_sourcing(void)
+{
+ VIM_CLEAR(last_sourcing_name);
+ last_sourcing_lnum = 0;
+}
+
+/*
+ * Return TRUE if "sourcing_name" differs from "last_sourcing_name".
+ */
+ static int
+other_sourcing_name(void)
+{
+ if (sourcing_name != NULL)
+ {
+ if (last_sourcing_name != NULL)
+ return STRCMP(sourcing_name, last_sourcing_name) != 0;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * Get the message about the source, as used for an error message.
+ * Returns an allocated string with room for one more character.
+ * Returns NULL when no message is to be given.
+ */
+ static char_u *
+get_emsg_source(void)
+{
+ char_u *Buf, *p;
+
+ if (sourcing_name != NULL && other_sourcing_name())
+ {
+ p = (char_u *)_("Error detected while processing %s:");
+ Buf = alloc((unsigned)(STRLEN(sourcing_name) + STRLEN(p)));
+ if (Buf != NULL)
+ sprintf((char *)Buf, (char *)p, sourcing_name);
+ return Buf;
+ }
+ return NULL;
+}
+
+/*
+ * Get the message about the source lnum, as used for an error message.
+ * Returns an allocated string with room for one more character.
+ * Returns NULL when no message is to be given.
+ */
+ static char_u *
+get_emsg_lnum(void)
+{
+ char_u *Buf, *p;
+
+ /* lnum is 0 when executing a command from the command line
+ * argument, we don't want a line number then */
+ if (sourcing_name != NULL
+ && (other_sourcing_name() || sourcing_lnum != last_sourcing_lnum)
+ && sourcing_lnum != 0)
+ {
+ p = (char_u *)_("line %4ld:");
+ Buf = alloc((unsigned)(STRLEN(p) + 20));
+ if (Buf != NULL)
+ sprintf((char *)Buf, (char *)p, (long)sourcing_lnum);
+ return Buf;
+ }
+ return NULL;
+}
+
+/*
+ * Display name and line number for the source of an error.
+ * Remember the file name and line number, so that for the next error the info
+ * is only displayed if it changed.
+ */
+ void
+msg_source(int attr)
+{
+ char_u *p;
+
+ ++no_wait_return;
+ p = get_emsg_source();
+ if (p != NULL)
+ {
+ msg_attr((char *)p, attr);
+ vim_free(p);
+ }
+ p = get_emsg_lnum();
+ if (p != NULL)
+ {
+ msg_attr((char *)p, HL_ATTR(HLF_N));
+ vim_free(p);
+ last_sourcing_lnum = sourcing_lnum; /* only once for each line */
+ }
+
+ /* remember the last sourcing name printed, also when it's empty */
+ if (sourcing_name == NULL || other_sourcing_name())
+ {
+ vim_free(last_sourcing_name);
+ if (sourcing_name == NULL)
+ last_sourcing_name = NULL;
+ else
+ last_sourcing_name = vim_strsave(sourcing_name);
+ }
+ --no_wait_return;
+}
+
+/*
+ * Return TRUE if not giving error messages right now:
+ * If "emsg_off" is set: no error messages at the moment.
+ * If "msg" is in 'debug': do error message but without side effects.
+ * If "emsg_skip" is set: never do error messages.
+ */
+ int
+emsg_not_now(void)
+{
+ if ((emsg_off > 0 && vim_strchr(p_debug, 'm') == NULL
+ && vim_strchr(p_debug, 't') == NULL)
+#ifdef FEAT_EVAL
+ || emsg_skip > 0
+#endif
+ )
+ return TRUE;
+ return FALSE;
+}
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+static garray_T ignore_error_list = GA_EMPTY;
+
+ void
+ignore_error_for_testing(char_u *error)
+{
+ if (ignore_error_list.ga_itemsize == 0)
+ ga_init2(&ignore_error_list, sizeof(char_u *), 1);
+
+ if (STRCMP("RESET", error) == 0)
+ ga_clear_strings(&ignore_error_list);
+ else
+ ga_add_string(&ignore_error_list, error);
+}
+
+ static int
+ignore_error(char_u *msg)
+{
+ int i;
+
+ for (i = 0; i < ignore_error_list.ga_len; ++i)
+ if (strstr((char *)msg,
+ (char *)((char_u **)(ignore_error_list.ga_data))[i]) != NULL)
+ return TRUE;
+ return FALSE;
+}
+#endif
+
+#if !defined(HAVE_STRERROR) || defined(PROTO)
+/*
+ * Replacement for perror() that behaves more or less like emsg() was called.
+ * v:errmsg will be set and called_emsg will be set.
+ */
+ void
+do_perror(char *msg)
+{
+ perror(msg);
+ ++emsg_silent;
+ emsg(msg);
+ --emsg_silent;
+}
+#endif
+
+/*
+ * emsg_core() - display an error message
+ *
+ * Rings the bell, if appropriate, and calls message() to do the real work
+ * When terminal not initialized (yet) mch_errmsg(..) is used.
+ *
+ * Return TRUE if wait_return not called.
+ * Note: caller must check 'emsg_not_now()' before calling this.
+ */
+ static int
+emsg_core(char_u *s)
+{
+ int attr;
+ char_u *p;
+ int r;
+#ifdef FEAT_EVAL
+ int ignore = FALSE;
+ int severe;
+#endif
+
+#ifdef FEAT_EVAL
+ /* When testing some errors are turned into a normal message. */
+ if (ignore_error(s))
+ /* don't call msg() if it results in a dialog */
+ return msg_use_printf() ? FALSE : msg((char *)s);
+#endif
+
+ called_emsg = TRUE;
+
+#ifdef FEAT_EVAL
+ /* If "emsg_severe" is TRUE: When an error exception is to be thrown,
+ * prefer this message over previous messages for the same command. */
+ severe = emsg_severe;
+ emsg_severe = FALSE;
+#endif
+
+ if (!emsg_off || vim_strchr(p_debug, 't') != NULL)
+ {
+#ifdef FEAT_EVAL
+ /*
+ * Cause a throw of an error exception if appropriate. Don't display
+ * the error message in this case. (If no matching catch clause will
+ * be found, the message will be displayed later on.) "ignore" is set
+ * when the message should be ignored completely (used for the
+ * interrupt message).
+ */
+ if (cause_errthrow(s, severe, &ignore) == TRUE)
+ {
+ if (!ignore)
+ ++did_emsg;
+ return TRUE;
+ }
+
+ /* set "v:errmsg", also when using ":silent! cmd" */
+ set_vim_var_string(VV_ERRMSG, s, -1);
+#endif
+
+ /*
+ * When using ":silent! cmd" ignore error messages.
+ * But do write it to the redirection file.
+ */
+ if (emsg_silent != 0)
+ {
+ if (emsg_noredir == 0)
+ {
+ msg_start();
+ p = get_emsg_source();
+ if (p != NULL)
+ {
+ STRCAT(p, "\n");
+ redir_write(p, -1);
+ vim_free(p);
+ }
+ p = get_emsg_lnum();
+ if (p != NULL)
+ {
+ STRCAT(p, "\n");
+ redir_write(p, -1);
+ vim_free(p);
+ }
+ redir_write(s, -1);
+ }
+#ifdef FEAT_JOB_CHANNEL
+ ch_log(NULL, "ERROR: %s", (char *)s);
+#endif
+ return TRUE;
+ }
+
+ ex_exitval = 1;
+
+ /* Reset msg_silent, an error causes messages to be switched back on.
+ */
+ msg_silent = 0;
+ cmd_silent = FALSE;
+
+ if (global_busy) /* break :global command */
+ ++global_busy;
+
+ if (p_eb)
+ beep_flush(); /* also includes flush_buffers() */
+ else
+ flush_buffers(FLUSH_MINIMAL); // flush internal buffers
+ ++did_emsg; // flag for DoOneCmd()
+#ifdef FEAT_EVAL
+ did_uncaught_emsg = TRUE;
+#endif
+ }
+
+ emsg_on_display = TRUE; /* remember there is an error message */
+ ++msg_scroll; /* don't overwrite a previous message */
+ attr = HL_ATTR(HLF_E); /* set highlight mode for error messages */
+ if (msg_scrolled != 0)
+ need_wait_return = TRUE; /* needed in case emsg() is called after
+ * wait_return has reset need_wait_return
+ * and a redraw is expected because
+ * msg_scrolled is non-zero */
+
+#ifdef FEAT_JOB_CHANNEL
+ emsg_to_channel_log = TRUE;
+#endif
+ /*
+ * Display name and line number for the source of the error.
+ */
+ msg_source(attr);
+
+ /*
+ * Display the error message itself.
+ */
+ msg_nowait = FALSE; /* wait for this msg */
+ r = msg_attr((char *)s, attr);
+
+#ifdef FEAT_JOB_CHANNEL
+ emsg_to_channel_log = FALSE;
+#endif
+ return r;
+}
+
+/*
+ * Print an error message.
+ */
+ int
+emsg(char *s)
+{
+ /* Skip this if not giving error messages at the moment. */
+ if (!emsg_not_now())
+ return emsg_core((char_u *)s);
+ return TRUE; /* no error messages at the moment */
+}
+
+/*
+ * Print an error message with format string and variable arguments.
+ * Note: caller must not pass 'IObuff' as 1st argument.
+ */
+ int
+semsg(const char *s, ...)
+{
+ /* Skip this if not giving error messages at the moment. */
+ if (!emsg_not_now())
+ {
+ va_list ap;
+
+ va_start(ap, s);
+ vim_vsnprintf((char *)IObuff, IOSIZE, s, ap);
+ va_end(ap);
+ return emsg_core(IObuff);
+ }
+ return TRUE; /* no error messages at the moment */
+}
+
+/*
+ * Same as emsg(...), but abort on error when ABORT_ON_INTERNAL_ERROR is
+ * defined. It is used for internal errors only, so that they can be
+ * detected when fuzzing vim.
+ */
+ void
+iemsg(char *s)
+{
+ if (!emsg_not_now())
+ emsg_core((char_u *)s);
+#ifdef ABORT_ON_INTERNAL_ERROR
+ abort();
+#endif
+}
+
+/*
+ * Same as semsg(...) but abort on error when ABORT_ON_INTERNAL_ERROR is
+ * defined. It is used for internal errors only, so that they can be
+ * detected when fuzzing vim.
+ * Note: caller must not pass 'IObuff' as 1st argument.
+ */
+ void
+siemsg(const char *s, ...)
+{
+ if (!emsg_not_now())
+ {
+ va_list ap;
+
+ va_start(ap, s);
+ vim_vsnprintf((char *)IObuff, IOSIZE, s, ap);
+ va_end(ap);
+ emsg_core(IObuff);
+ }
+#ifdef ABORT_ON_INTERNAL_ERROR
+ abort();
+#endif
+}
+
+/*
+ * Give an "Internal error" message.
+ */
+ void
+internal_error(char *where)
+{
+ siemsg(_(e_intern2), where);
+}
+
+/* emsg3() and emsgn() are in misc2.c to avoid warnings for the prototypes. */
+
+ void
+emsg_invreg(int name)
+{
+ semsg(_("E354: Invalid register name: '%s'"), transchar(name));
+}
+
+/*
+ * Like msg(), but truncate to a single line if p_shm contains 't', or when
+ * "force" is TRUE. This truncates in another way as for normal messages.
+ * Careful: The string may be changed by msg_may_trunc()!
+ * Returns a pointer to the printed message, if wait_return() not called.
+ */
+ char *
+msg_trunc_attr(char *s, int force, int attr)
+{
+ int n;
+ char *ts;
+
+ /* Add message to history before truncating */
+ add_msg_hist((char_u *)s, -1, attr);
+
+ ts = (char *)msg_may_trunc(force, (char_u *)s);
+
+ msg_hist_off = TRUE;
+ n = msg_attr(ts, attr);
+ msg_hist_off = FALSE;
+
+ if (n)
+ return ts;
+ return NULL;
+}
+
+/*
+ * Check if message "s" should be truncated at the start (for filenames).
+ * Return a pointer to where the truncated message starts.
+ * Note: May change the message by replacing a character with '<'.
+ */
+ char_u *
+msg_may_trunc(int force, char_u *s)
+{
+ int n;
+ int room;
+
+ room = (int)(Rows - cmdline_row - 1) * Columns + sc_col - 1;
+ if ((force || (shortmess(SHM_TRUNC) && !exmode_active))
+ && (n = (int)STRLEN(s) - room) > 0)
+ {
+ if (has_mbyte)
+ {
+ int size = vim_strsize(s);
+
+ /* There may be room anyway when there are multibyte chars. */
+ if (size <= room)
+ return s;
+
+ for (n = 0; size >= room; )
+ {
+ size -= (*mb_ptr2cells)(s + n);
+ n += (*mb_ptr2len)(s + n);
+ }
+ --n;
+ }
+ s += n;
+ *s = '<';
+ }
+ return s;
+}
+
+ static void
+add_msg_hist(
+ char_u *s,
+ int len, /* -1 for undetermined length */
+ int attr)
+{
+ struct msg_hist *p;
+
+ if (msg_hist_off || msg_silent != 0)
+ return;
+
+ /* Don't let the message history get too big */
+ while (msg_hist_len > MAX_MSG_HIST_LEN)
+ (void)delete_first_msg();
+
+ /* allocate an entry and add the message at the end of the history */
+ p = (struct msg_hist *)alloc((int)sizeof(struct msg_hist));
+ if (p != NULL)
+ {
+ if (len < 0)
+ len = (int)STRLEN(s);
+ /* remove leading and trailing newlines */
+ while (len > 0 && *s == '\n')
+ {
+ ++s;
+ --len;
+ }
+ while (len > 0 && s[len - 1] == '\n')
+ --len;
+ p->msg = vim_strnsave(s, len);
+ p->next = NULL;
+ p->attr = attr;
+ if (last_msg_hist != NULL)
+ last_msg_hist->next = p;
+ last_msg_hist = p;
+ if (first_msg_hist == NULL)
+ first_msg_hist = last_msg_hist;
+ ++msg_hist_len;
+ }
+}
+
+/*
+ * Delete the first (oldest) message from the history.
+ * Returns FAIL if there are no messages.
+ */
+ int
+delete_first_msg(void)
+{
+ struct msg_hist *p;
+
+ if (msg_hist_len <= 0)
+ return FAIL;
+ p = first_msg_hist;
+ first_msg_hist = p->next;
+ if (first_msg_hist == NULL)
+ last_msg_hist = NULL; /* history is empty */
+ vim_free(p->msg);
+ vim_free(p);
+ --msg_hist_len;
+ return OK;
+}
+
+/*
+ * ":messages" command.
+ */
+ void
+ex_messages(exarg_T *eap)
+{
+ struct msg_hist *p;
+ char_u *s;
+ int c = 0;
+
+ if (STRCMP(eap->arg, "clear") == 0)
+ {
+ int keep = eap->addr_count == 0 ? 0 : eap->line2;
+
+ while (msg_hist_len > keep)
+ (void)delete_first_msg();
+ return;
+ }
+
+ if (*eap->arg != NUL)
+ {
+ emsg(_(e_invarg));
+ return;
+ }
+
+ msg_hist_off = TRUE;
+
+ p = first_msg_hist;
+ if (eap->addr_count != 0)
+ {
+ /* Count total messages */
+ for (; p != NULL && !got_int; p = p->next)
+ c++;
+
+ c -= eap->line2;
+
+ /* Skip without number of messages specified */
+ for (p = first_msg_hist; p != NULL && !got_int && c > 0;
+ p = p->next, c--);
+ }
+
+ if (p == first_msg_hist)
+ {
+ s = mch_getenv((char_u *)"LANG");
+ if (s != NULL && *s != NUL)
+ // The next comment is extracted by xgettext and put in po file for
+ // translators to read.
+ msg_attr(
+ // Translator: Please replace the name and email address
+ // with the appropriate text for your translation.
+ _("Messages maintainer: Bram Moolenaar <Bram@vim.org>"),
+ HL_ATTR(HLF_T));
+ }
+
+ /* Display what was not skipped. */
+ for (; p != NULL && !got_int; p = p->next)
+ if (p->msg != NULL)
+ msg_attr((char *)p->msg, p->attr);
+
+ msg_hist_off = FALSE;
+}
+
+#if defined(FEAT_CON_DIALOG) || defined(FIND_REPLACE_DIALOG) || defined(PROTO)
+/*
+ * Call this after prompting the user. This will avoid a hit-return message
+ * and a delay.
+ */
+ void
+msg_end_prompt(void)
+{
+ need_wait_return = FALSE;
+ emsg_on_display = FALSE;
+ cmdline_row = msg_row;
+ msg_col = 0;
+ msg_clr_eos();
+ lines_left = -1;
+}
+#endif
+
+/*
+ * Wait for the user to hit a key (normally Enter).
+ * If "redraw" is TRUE, clear and redraw the screen.
+ * If "redraw" is FALSE, just redraw the screen.
+ * If "redraw" is -1, don't redraw at all.
+ */
+ void
+wait_return(int redraw)
+{
+ int c;
+ int oldState;
+ int tmpState;
+ int had_got_int;
+ int save_reg_recording;
+ FILE *save_scriptout;
+
+ if (redraw == TRUE)
+ must_redraw = CLEAR;
+
+ /* If using ":silent cmd", don't wait for a return. Also don't set
+ * need_wait_return to do it later. */
+ if (msg_silent != 0)
+ return;
+
+ /*
+ * When inside vgetc(), we can't wait for a typed character at all.
+ * With the global command (and some others) we only need one return at
+ * the end. Adjust cmdline_row to avoid the next message overwriting the
+ * last one.
+ */
+ if (vgetc_busy > 0)
+ return;
+ need_wait_return = TRUE;
+ if (no_wait_return)
+ {
+ if (!exmode_active)
+ cmdline_row = msg_row;
+ return;
+ }
+
+ redir_off = TRUE; /* don't redirect this message */
+ oldState = State;
+ if (quit_more)
+ {
+ c = CAR; /* just pretend CR was hit */
+ quit_more = FALSE;
+ got_int = FALSE;
+ }
+ else if (exmode_active)
+ {
+ msg_puts(" "); /* make sure the cursor is on the right line */
+ c = CAR; /* no need for a return in ex mode */
+ got_int = FALSE;
+ }
+ else
+ {
+ /* Make sure the hit-return prompt is on screen when 'guioptions' was
+ * just changed. */
+ screenalloc(FALSE);
+
+ State = HITRETURN;
+#ifdef FEAT_MOUSE
+ setmouse();
+#endif
+#ifdef USE_ON_FLY_SCROLL
+ dont_scroll = TRUE; /* disallow scrolling here */
+#endif
+ cmdline_row = msg_row;
+
+ /* Avoid the sequence that the user types ":" at the hit-return prompt
+ * to start an Ex command, but the file-changed dialog gets in the
+ * way. */
+ if (need_check_timestamps)
+ check_timestamps(FALSE);
+
+ hit_return_msg();
+
+ do
+ {
+ /* Remember "got_int", if it is set vgetc() probably returns a
+ * CTRL-C, but we need to loop then. */
+ had_got_int = got_int;
+
+ /* Don't do mappings here, we put the character back in the
+ * typeahead buffer. */
+ ++no_mapping;
+ ++allow_keys;
+
+ /* Temporarily disable Recording. If Recording is active, the
+ * character will be recorded later, since it will be added to the
+ * typebuf after the loop */
+ save_reg_recording = reg_recording;
+ save_scriptout = scriptout;
+ reg_recording = 0;
+ scriptout = NULL;
+ c = safe_vgetc();
+ if (had_got_int && !global_busy)
+ got_int = FALSE;
+ --no_mapping;
+ --allow_keys;
+ reg_recording = save_reg_recording;
+ scriptout = save_scriptout;
+
+#ifdef FEAT_CLIPBOARD
+ /* Strange way to allow copying (yanking) a modeless selection at
+ * the hit-enter prompt. Use CTRL-Y, because the same is used in
+ * Cmdline-mode and it's harmless when there is no selection. */
+ if (c == Ctrl_Y && clip_star.state == SELECT_DONE)
+ {
+ clip_copy_modeless_selection(TRUE);
+ c = K_IGNORE;
+ }
+#endif
+
+ /*
+ * Allow scrolling back in the messages.
+ * Also accept scroll-down commands when messages fill the screen,
+ * to avoid that typing one 'j' too many makes the messages
+ * disappear.
+ */
+ if (p_more && !p_cp)
+ {
+ if (c == 'b' || c == 'k' || c == 'u' || c == 'g'
+ || c == K_UP || c == K_PAGEUP)
+ {
+ if (msg_scrolled > Rows)
+ /* scroll back to show older messages */
+ do_more_prompt(c);
+ else
+ {
+ msg_didout = FALSE;
+ c = K_IGNORE;
+ msg_col =
+#ifdef FEAT_RIGHTLEFT
+ cmdmsg_rl ? Columns - 1 :
+#endif
+ 0;
+ }
+ if (quit_more)
+ {
+ c = CAR; /* just pretend CR was hit */
+ quit_more = FALSE;
+ got_int = FALSE;
+ }
+ else if (c != K_IGNORE)
+ {
+ c = K_IGNORE;
+ hit_return_msg();
+ }
+ }
+ else if (msg_scrolled > Rows - 2
+ && (c == 'j' || c == 'd' || c == 'f'
+ || c == K_DOWN || c == K_PAGEDOWN))
+ c = K_IGNORE;
+ }
+ } while ((had_got_int && c == Ctrl_C)
+ || c == K_IGNORE
+#ifdef FEAT_GUI
+ || c == K_VER_SCROLLBAR || c == K_HOR_SCROLLBAR
+#endif
+#ifdef FEAT_MOUSE
+ || c == K_LEFTDRAG || c == K_LEFTRELEASE
+ || c == K_MIDDLEDRAG || c == K_MIDDLERELEASE
+ || c == K_RIGHTDRAG || c == K_RIGHTRELEASE
+ || c == K_MOUSELEFT || c == K_MOUSERIGHT
+ || c == K_MOUSEDOWN || c == K_MOUSEUP
+ || c == K_MOUSEMOVE
+ || (!mouse_has(MOUSE_RETURN)
+ && mouse_row < msg_row
+ && (c == K_LEFTMOUSE
+ || c == K_MIDDLEMOUSE
+ || c == K_RIGHTMOUSE
+ || c == K_X1MOUSE
+ || c == K_X2MOUSE))
+#endif
+ );
+ ui_breakcheck();
+#ifdef FEAT_MOUSE
+ /*
+ * Avoid that the mouse-up event causes visual mode to start.
+ */
+ if (c == K_LEFTMOUSE || c == K_MIDDLEMOUSE || c == K_RIGHTMOUSE
+ || c == K_X1MOUSE || c == K_X2MOUSE)
+ (void)jump_to_mouse(MOUSE_SETPOS, NULL, 0);
+ else
+#endif
+ if (vim_strchr((char_u *)"\r\n ", c) == NULL && c != Ctrl_C)
+ {
+ /* Put the character back in the typeahead buffer. Don't use the
+ * stuff buffer, because lmaps wouldn't work. */
+ ins_char_typebuf(c);
+ do_redraw = TRUE; /* need a redraw even though there is
+ typeahead */
+ }
+ }
+ redir_off = FALSE;
+
+ /*
+ * If the user hits ':', '?' or '/' we get a command line from the next
+ * line.
+ */
+ if (c == ':' || c == '?' || c == '/')
+ {
+ if (!exmode_active)
+ cmdline_row = msg_row;
+ skip_redraw = TRUE; /* skip redraw once */
+ do_redraw = FALSE;
+#ifdef FEAT_TERMINAL
+ skip_term_loop = TRUE;
+#endif
+ }
+
+ /*
+ * If the window size changed set_shellsize() will redraw the screen.
+ * Otherwise the screen is only redrawn if 'redraw' is set and no ':'
+ * typed.
+ */
+ tmpState = State;
+ State = oldState; /* restore State before set_shellsize */
+#ifdef FEAT_MOUSE
+ setmouse();
+#endif
+ msg_check();
+
+#if defined(UNIX) || defined(VMS)
+ /*
+ * When switching screens, we need to output an extra newline on exit.
+ */
+ if (swapping_screen() && !termcap_active)
+ newline_on_exit = TRUE;
+#endif
+
+ need_wait_return = FALSE;
+ did_wait_return = TRUE;
+ emsg_on_display = FALSE; /* can delete error message now */
+ lines_left = -1; /* reset lines_left at next msg_start() */
+ reset_last_sourcing();
+ if (keep_msg != NULL && vim_strsize(keep_msg) >=
+ (Rows - cmdline_row - 1) * Columns + sc_col)
+ VIM_CLEAR(keep_msg); /* don't redisplay message, it's too long */
+
+ if (tmpState == SETWSIZE) /* got resize event while in vgetc() */
+ {
+ starttermcap(); /* start termcap before redrawing */
+ shell_resized();
+ }
+ else if (!skip_redraw
+ && (redraw == TRUE || (msg_scrolled != 0 && redraw != -1)))
+ {
+ starttermcap(); /* start termcap before redrawing */
+ redraw_later(VALID);
+ }
+}
+
+/*
+ * Write the hit-return prompt.
+ */
+ static void
+hit_return_msg(void)
+{
+ int save_p_more = p_more;
+
+ p_more = FALSE; /* don't want see this message when scrolling back */
+ if (msg_didout) /* start on a new line */
+ msg_putchar('\n');
+ if (got_int)
+ msg_puts(_("Interrupt: "));
+
+ msg_puts_attr(_("Press ENTER or type command to continue"), HL_ATTR(HLF_R));
+ if (!msg_use_printf())
+ msg_clr_eos();
+ p_more = save_p_more;
+}
+
+/*
+ * Set "keep_msg" to "s". Free the old value and check for NULL pointer.
+ */
+ void
+set_keep_msg(char_u *s, int attr)
+{
+ vim_free(keep_msg);
+ if (s != NULL && msg_silent == 0)
+ keep_msg = vim_strsave(s);
+ else
+ keep_msg = NULL;
+ keep_msg_more = FALSE;
+ keep_msg_attr = attr;
+}
+
+#if defined(FEAT_TERMRESPONSE) || defined(PROTO)
+/*
+ * If there currently is a message being displayed, set "keep_msg" to it, so
+ * that it will be displayed again after redraw.
+ */
+ void
+set_keep_msg_from_hist(void)
+{
+ if (keep_msg == NULL && last_msg_hist != NULL && msg_scrolled == 0
+ && (State & NORMAL))
+ set_keep_msg(last_msg_hist->msg, last_msg_hist->attr);
+}
+#endif
+
+/*
+ * Prepare for outputting characters in the command line.
+ */
+ void
+msg_start(void)
+{
+ int did_return = FALSE;
+
+ if (!msg_silent)
+ VIM_CLEAR(keep_msg);
+
+#ifdef FEAT_EVAL
+ if (need_clr_eos)
+ {
+ /* Halfway an ":echo" command and getting an (error) message: clear
+ * any text from the command. */
+ need_clr_eos = FALSE;
+ msg_clr_eos();
+ }
+#endif
+
+ if (!msg_scroll && full_screen) /* overwrite last message */
+ {
+ msg_row = cmdline_row;
+ msg_col =
+#ifdef FEAT_RIGHTLEFT
+ cmdmsg_rl ? Columns - 1 :
+#endif
+ 0;
+ }
+ else if (msg_didout) /* start message on next line */
+ {
+ msg_putchar('\n');
+ did_return = TRUE;
+ if (exmode_active != EXMODE_NORMAL)
+ cmdline_row = msg_row;
+ }
+ if (!msg_didany || lines_left < 0)
+ msg_starthere();
+ if (msg_silent == 0)
+ {
+ msg_didout = FALSE; /* no output on current line yet */
+ cursor_off();
+ }
+
+ /* when redirecting, may need to start a new line. */
+ if (!did_return)
+ redir_write((char_u *)"\n", -1);
+}
+
+/*
+ * Note that the current msg position is where messages start.
+ */
+ void
+msg_starthere(void)
+{
+ lines_left = cmdline_row;
+ msg_didany = FALSE;
+}
+
+ void
+msg_putchar(int c)
+{
+ msg_putchar_attr(c, 0);
+}
+
+ void
+msg_putchar_attr(int c, int attr)
+{
+ char_u buf[MB_MAXBYTES + 1];
+
+ if (IS_SPECIAL(c))
+ {
+ buf[0] = K_SPECIAL;
+ buf[1] = K_SECOND(c);
+ buf[2] = K_THIRD(c);
+ buf[3] = NUL;
+ }
+ else
+ buf[(*mb_char2bytes)(c, buf)] = NUL;
+ msg_puts_attr((char *)buf, attr);
+}
+
+ void
+msg_outnum(long n)
+{
+ char buf[20];
+
+ sprintf(buf, "%ld", n);
+ msg_puts(buf);
+}
+
+ void
+msg_home_replace(char_u *fname)
+{
+ msg_home_replace_attr(fname, 0);
+}
+
+#if defined(FEAT_FIND_ID) || defined(PROTO)
+ void
+msg_home_replace_hl(char_u *fname)
+{
+ msg_home_replace_attr(fname, HL_ATTR(HLF_D));
+}
+#endif
+
+ static void
+msg_home_replace_attr(char_u *fname, int attr)
+{
+ char_u *name;
+
+ name = home_replace_save(NULL, fname);
+ if (name != NULL)
+ msg_outtrans_attr(name, attr);
+ vim_free(name);
+}
+
+/*
+ * Output 'len' characters in 'str' (including NULs) with translation
+ * if 'len' is -1, output upto a NUL character.
+ * Use attributes 'attr'.
+ * Return the number of characters it takes on the screen.
+ */
+ int
+msg_outtrans(char_u *str)
+{
+ return msg_outtrans_attr(str, 0);
+}
+
+ int
+msg_outtrans_attr(char_u *str, int attr)
+{
+ return msg_outtrans_len_attr(str, (int)STRLEN(str), attr);
+}
+
+ int
+msg_outtrans_len(char_u *str, int len)
+{
+ return msg_outtrans_len_attr(str, len, 0);
+}
+
+/*
+ * Output one character at "p". Return pointer to the next character.
+ * Handles multi-byte characters.
+ */
+ char_u *
+msg_outtrans_one(char_u *p, int attr)
+{
+ int l;
+
+ if (has_mbyte && (l = (*mb_ptr2len)(p)) > 1)
+ {
+ msg_outtrans_len_attr(p, l, attr);
+ return p + l;
+ }
+ msg_puts_attr((char *)transchar_byte(*p), attr);
+ return p + 1;
+}
+
+ int
+msg_outtrans_len_attr(char_u *msgstr, int len, int attr)
+{
+ int retval = 0;
+ char_u *str = msgstr;
+ char_u *plain_start = msgstr;
+ char_u *s;
+ int mb_l;
+ int c;
+
+ /* if MSG_HIST flag set, add message to history */
+ if (attr & MSG_HIST)
+ {
+ add_msg_hist(str, len, attr);
+ attr &= ~MSG_HIST;
+ }
+
+ /* If the string starts with a composing character first draw a space on
+ * which the composing char can be drawn. */
+ if (enc_utf8 && utf_iscomposing(utf_ptr2char(msgstr)))
+ msg_puts_attr(" ", attr);
+
+ /*
+ * Go over the string. Special characters are translated and printed.
+ * Normal characters are printed several at a time.
+ */
+ while (--len >= 0)
+ {
+ if (enc_utf8)
+ /* Don't include composing chars after the end. */
+ mb_l = utfc_ptr2len_len(str, len + 1);
+ else if (has_mbyte)
+ mb_l = (*mb_ptr2len)(str);
+ else
+ mb_l = 1;
+ if (has_mbyte && mb_l > 1)
+ {
+ c = (*mb_ptr2char)(str);
+ if (vim_isprintc(c))
+ /* printable multi-byte char: count the cells. */
+ retval += (*mb_ptr2cells)(str);
+ else
+ {
+ /* unprintable multi-byte char: print the printable chars so
+ * far and the translation of the unprintable char. */
+ if (str > plain_start)
+ msg_puts_attr_len((char *)plain_start,
+ (int)(str - plain_start), attr);
+ plain_start = str + mb_l;
+ msg_puts_attr((char *)transchar(c),
+ attr == 0 ? HL_ATTR(HLF_8) : attr);
+ retval += char2cells(c);
+ }
+ len -= mb_l - 1;
+ str += mb_l;
+ }
+ else
+ {
+ s = transchar_byte(*str);
+ if (s[1] != NUL)
+ {
+ /* unprintable char: print the printable chars so far and the
+ * translation of the unprintable char. */
+ if (str > plain_start)
+ msg_puts_attr_len((char *)plain_start,
+ (int)(str - plain_start), attr);
+ plain_start = str + 1;
+ msg_puts_attr((char *)s, attr == 0 ? HL_ATTR(HLF_8) : attr);
+ retval += (int)STRLEN(s);
+ }
+ else
+ ++retval;
+ ++str;
+ }
+ }
+
+ if (str > plain_start)
+ /* print the printable chars at the end */
+ msg_puts_attr_len((char *)plain_start, (int)(str - plain_start), attr);
+
+ return retval;
+}
+
+#if defined(FEAT_QUICKFIX) || defined(PROTO)
+ void
+msg_make(char_u *arg)
+{
+ int i;
+ static char_u *str = (char_u *)"eeffoc", *rs = (char_u *)"Plon#dqg#vxjduB";
+
+ arg = skipwhite(arg);
+ for (i = 5; *arg && i >= 0; --i)
+ if (*arg++ != str[i])
+ break;
+ if (i < 0)
+ {
+ msg_putchar('\n');
+ for (i = 0; rs[i]; ++i)
+ msg_putchar(rs[i] - 3);
+ }
+}
+#endif
+
+/*
+ * Output the string 'str' upto a NUL character.
+ * Return the number of characters it takes on the screen.
+ *
+ * If K_SPECIAL is encountered, then it is taken in conjunction with the
+ * following character and shown as <F1>, <S-Up> etc. Any other character
+ * which is not printable shown in <> form.
+ * If 'from' is TRUE (lhs of a mapping), a space is shown as <Space>.
+ * If a character is displayed in one of these special ways, is also
+ * highlighted (its highlight name is '8' in the p_hl variable).
+ * Otherwise characters are not highlighted.
+ * This function is used to show mappings, where we want to see how to type
+ * the character/string -- webb
+ */
+ int
+msg_outtrans_special(
+ char_u *strstart,
+ int from) /* TRUE for lhs of a mapping */
+{
+ char_u *str = strstart;
+ int retval = 0;
+ char *text;
+ int attr;
+ int len;
+
+ attr = HL_ATTR(HLF_8);
+ while (*str != NUL)
+ {
+ /* Leading and trailing spaces need to be displayed in <> form. */
+ if ((str == strstart || str[1] == NUL) && *str == ' ')
+ {
+ text = "<Space>";
+ ++str;
+ }
+ else
+ text = (char *)str2special(&str, from);
+ len = vim_strsize((char_u *)text);
+ /* Highlight special keys */
+ msg_puts_attr(text, len > 1
+ && (*mb_ptr2len)((char_u *)text) <= 1 ? attr : 0);
+ retval += len;
+ }
+ return retval;
+}
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * Return the lhs or rhs of a mapping, with the key codes turned into printable
+ * strings, in an allocated string.
+ */
+ char_u *
+str2special_save(
+ char_u *str,
+ int is_lhs) /* TRUE for lhs, FALSE for rhs */
+{
+ garray_T ga;
+ char_u *p = str;
+
+ ga_init2(&ga, 1, 40);
+ while (*p != NUL)
+ ga_concat(&ga, str2special(&p, is_lhs));
+ ga_append(&ga, NUL);
+ return (char_u *)ga.ga_data;
+}
+#endif
+
+/*
+ * Return the printable string for the key codes at "*sp".
+ * Used for translating the lhs or rhs of a mapping to printable chars.
+ * Advances "sp" to the next code.
+ */
+ char_u *
+str2special(
+ char_u **sp,
+ int from) /* TRUE for lhs of mapping */
+{
+ int c;
+ static char_u buf[7];
+ char_u *str = *sp;
+ int modifiers = 0;
+ int special = FALSE;
+
+ if (has_mbyte)
+ {
+ char_u *p;
+
+ /* Try to un-escape a multi-byte character. Return the un-escaped
+ * string if it is a multi-byte character. */
+ p = mb_unescape(sp);
+ if (p != NULL)
+ return p;
+ }
+
+ c = *str;
+ if (c == K_SPECIAL && str[1] != NUL && str[2] != NUL)
+ {
+ if (str[1] == KS_MODIFIER)
+ {
+ modifiers = str[2];
+ str += 3;
+ c = *str;
+ }
+ if (c == K_SPECIAL && str[1] != NUL && str[2] != NUL)
+ {
+ c = TO_SPECIAL(str[1], str[2]);
+ str += 2;
+ }
+ if (IS_SPECIAL(c) || modifiers) /* special key */
+ special = TRUE;
+ }
+
+ if (has_mbyte && !IS_SPECIAL(c))
+ {
+ int len = (*mb_ptr2len)(str);
+
+ /* For multi-byte characters check for an illegal byte. */
+ if (has_mbyte && MB_BYTE2LEN(*str) > len)
+ {
+ transchar_nonprint(buf, c);
+ *sp = str + 1;
+ return buf;
+ }
+ /* Since 'special' is TRUE the multi-byte character 'c' will be
+ * processed by get_special_key_name() */
+ c = (*mb_ptr2char)(str);
+ *sp = str + len;
+ }
+ else
+ *sp = str + 1;
+
+ /* Make unprintable characters in <> form, also <M-Space> and <Tab>.
+ * Use <Space> only for lhs of a mapping. */
+ if (special || char2cells(c) > 1 || (from && c == ' '))
+ return get_special_key_name(c, modifiers);
+ buf[0] = c;
+ buf[1] = NUL;
+ return buf;
+}
+
+/*
+ * Translate a key sequence into special key names.
+ */
+ void
+str2specialbuf(char_u *sp, char_u *buf, int len)
+{
+ char_u *s;
+
+ *buf = NUL;
+ while (*sp)
+ {
+ s = str2special(&sp, FALSE);
+ if ((int)(STRLEN(s) + STRLEN(buf)) < len)
+ STRCAT(buf, s);
+ }
+}
+
+/*
+ * print line for :print or :list command
+ */
+ void
+msg_prt_line(char_u *s, int list)
+{
+ int c;
+ int col = 0;
+ int n_extra = 0;
+ int c_extra = 0;
+ int c_final = 0;
+ char_u *p_extra = NULL; /* init to make SASC shut up */
+ int n;
+ int attr = 0;
+ char_u *trail = NULL;
+ int l;
+ char_u buf[MB_MAXBYTES + 1];
+
+ if (curwin->w_p_list)
+ list = TRUE;
+
+ /* find start of trailing whitespace */
+ if (list && lcs_trail)
+ {
+ trail = s + STRLEN(s);
+ while (trail > s && VIM_ISWHITE(trail[-1]))
+ --trail;
+ }
+
+ /* output a space for an empty line, otherwise the line will be
+ * overwritten */
+ if (*s == NUL && !(list && lcs_eol != NUL))
+ msg_putchar(' ');
+
+ while (!got_int)
+ {
+ if (n_extra > 0)
+ {
+ --n_extra;
+ if (n_extra == 0 && c_final)
+ c = c_final;
+ else if (c_extra)
+ c = c_extra;
+ else
+ c = *p_extra++;
+ }
+ else if (has_mbyte && (l = (*mb_ptr2len)(s)) > 1)
+ {
+ col += (*mb_ptr2cells)(s);
+ if (lcs_nbsp != NUL && list
+ && (mb_ptr2char(s) == 160
+ || mb_ptr2char(s) == 0x202f))
+ {
+ mb_char2bytes(lcs_nbsp, buf);
+ buf[(*mb_ptr2len)(buf)] = NUL;
+ }
+ else
+ {
+ mch_memmove(buf, s, (size_t)l);
+ buf[l] = NUL;
+ }
+ msg_puts((char *)buf);
+ s += l;
+ continue;
+ }
+ else
+ {
+ attr = 0;
+ c = *s++;
+ if (c == TAB && (!list || lcs_tab1))
+ {
+ /* tab amount depends on current column */
+#ifdef FEAT_VARTABS
+ n_extra = tabstop_padding(col, curbuf->b_p_ts,
+ curbuf->b_p_vts_array) - 1;
+#else
+ n_extra = curbuf->b_p_ts - col % curbuf->b_p_ts - 1;
+#endif
+ if (!list)
+ {
+ c = ' ';
+ c_extra = ' ';
+ c_final = NUL;
+ }
+ else
+ {
+ c = (n_extra == 0 && lcs_tab3) ? lcs_tab3 : lcs_tab1;
+ c_extra = lcs_tab2;
+ c_final = lcs_tab3;
+ attr = HL_ATTR(HLF_8);
+ }
+ }
+ else if (c == 160 && list && lcs_nbsp != NUL)
+ {
+ c = lcs_nbsp;
+ attr = HL_ATTR(HLF_8);
+ }
+ else if (c == NUL && list && lcs_eol != NUL)
+ {
+ p_extra = (char_u *)"";
+ c_extra = NUL;
+ c_final = NUL;
+ n_extra = 1;
+ c = lcs_eol;
+ attr = HL_ATTR(HLF_AT);
+ --s;
+ }
+ else if (c != NUL && (n = byte2cells(c)) > 1)
+ {
+ n_extra = n - 1;
+ p_extra = transchar_byte(c);
+ c_extra = NUL;
+ c_final = NUL;
+ c = *p_extra++;
+ /* Use special coloring to be able to distinguish <hex> from
+ * the same in plain text. */
+ attr = HL_ATTR(HLF_8);
+ }
+ else if (c == ' ' && trail != NULL && s > trail)
+ {
+ c = lcs_trail;
+ attr = HL_ATTR(HLF_8);
+ }
+ else if (c == ' ' && list && lcs_space != NUL)
+ {
+ c = lcs_space;
+ attr = HL_ATTR(HLF_8);
+ }
+ }
+
+ if (c == NUL)
+ break;
+
+ msg_putchar_attr(c, attr);
+ col++;
+ }
+ msg_clr_eos();
+}
+
+/*
+ * Use screen_puts() to output one multi-byte character.
+ * Return the pointer "s" advanced to the next character.
+ */
+ static char_u *
+screen_puts_mbyte(char_u *s, int l, int attr)
+{
+ int cw;
+
+ msg_didout = TRUE; /* remember that line is not empty */
+ cw = (*mb_ptr2cells)(s);
+ if (cw > 1 && (
+#ifdef FEAT_RIGHTLEFT
+ cmdmsg_rl ? msg_col <= 1 :
+#endif
+ msg_col == Columns - 1))
+ {
+ /* Doesn't fit, print a highlighted '>' to fill it up. */
+ msg_screen_putchar('>', HL_ATTR(HLF_AT));
+ return s;
+ }
+
+ screen_puts_len(s, l, msg_row, msg_col, attr);
+#ifdef FEAT_RIGHTLEFT
+ if (cmdmsg_rl)
+ {
+ msg_col -= cw;
+ if (msg_col == 0)
+ {
+ msg_col = Columns;
+ ++msg_row;
+ }
+ }
+ else
+#endif
+ {
+ msg_col += cw;
+ if (msg_col >= Columns)
+ {
+ msg_col = 0;
+ ++msg_row;
+ }
+ }
+ return s + l;
+}
+
+/*
+ * Output a string to the screen at position msg_row, msg_col.
+ * Update msg_row and msg_col for the next message.
+ */
+ void
+msg_puts(char *s)
+{
+ msg_puts_attr(s, 0);
+}
+
+ void
+msg_puts_title(char *s)
+{
+ msg_puts_attr(s, HL_ATTR(HLF_T));
+}
+
+/*
+ * Show a message in such a way that it always fits in the line. Cut out a
+ * part in the middle and replace it with "..." when necessary.
+ * Does not handle multi-byte characters!
+ */
+ void
+msg_outtrans_long_attr(char_u *longstr, int attr)
+{
+ msg_outtrans_long_len_attr(longstr, (int)STRLEN(longstr), attr);
+}
+
+ void
+msg_outtrans_long_len_attr(char_u *longstr, int len, int attr)
+{
+ int slen = len;
+ int room;
+
+ room = Columns - msg_col;
+ if (len > room && room >= 20)
+ {
+ slen = (room - 3) / 2;
+ msg_outtrans_len_attr(longstr, slen, attr);
+ msg_puts_attr("...", HL_ATTR(HLF_8));
+ }
+ msg_outtrans_len_attr(longstr + len - slen, slen, attr);
+}
+
+/*
+ * Basic function for writing a message with highlight attributes.
+ */
+ void
+msg_puts_attr(char *s, int attr)
+{
+ msg_puts_attr_len(s, -1, attr);
+}
+
+/*
+ * Like msg_puts_attr(), but with a maximum length "maxlen" (in bytes).
+ * When "maxlen" is -1 there is no maximum length.
+ * When "maxlen" is >= 0 the message is not put in the history.
+ */
+ static void
+msg_puts_attr_len(char *str, int maxlen, int attr)
+{
+ /*
+ * If redirection is on, also write to the redirection file.
+ */
+ redir_write((char_u *)str, maxlen);
+
+ /*
+ * Don't print anything when using ":silent cmd".
+ */
+ if (msg_silent != 0)
+ return;
+
+ /* if MSG_HIST flag set, add message to history */
+ if ((attr & MSG_HIST) && maxlen < 0)
+ {
+ add_msg_hist((char_u *)str, -1, attr);
+ attr &= ~MSG_HIST;
+ }
+
+ /*
+ * When writing something to the screen after it has scrolled, requires a
+ * wait-return prompt later. Needed when scrolling, resetting
+ * need_wait_return after some prompt, and then outputting something
+ * without scrolling
+ */
+ if (msg_scrolled != 0 && !msg_scrolled_ign)
+ need_wait_return = TRUE;
+ msg_didany = TRUE; /* remember that something was outputted */
+
+ /*
+ * If there is no valid screen, use fprintf so we can see error messages.
+ * If termcap is not active, we may be writing in an alternate console
+ * window, cursor positioning may not work correctly (window size may be
+ * different, e.g. for Win32 console) or we just don't know where the
+ * cursor is.
+ */
+ if (msg_use_printf())
+ msg_puts_printf((char_u *)str, maxlen);
+ else
+ msg_puts_display((char_u *)str, maxlen, attr, FALSE);
+}
+
+/*
+ * The display part of msg_puts_attr_len().
+ * May be called recursively to display scroll-back text.
+ */
+ static void
+msg_puts_display(
+ char_u *str,
+ int maxlen,
+ int attr,
+ int recurse)
+{
+ char_u *s = str;
+ char_u *t_s = str; /* string from "t_s" to "s" is still todo */
+ int t_col = 0; /* screen cells todo, 0 when "t_s" not used */
+ int l;
+ int cw;
+ char_u *sb_str = str;
+ int sb_col = msg_col;
+ int wrap;
+ int did_last_char;
+
+ did_wait_return = FALSE;
+ while ((maxlen < 0 || (int)(s - str) < maxlen) && *s != NUL)
+ {
+ /*
+ * We are at the end of the screen line when:
+ * - When outputting a newline.
+ * - When outputting a character in the last column.
+ */
+ if (!recurse && msg_row >= Rows - 1 && (*s == '\n' || (
+#ifdef FEAT_RIGHTLEFT
+ cmdmsg_rl
+ ? (
+ msg_col <= 1
+ || (*s == TAB && msg_col <= 7)
+ || (has_mbyte && (*mb_ptr2cells)(s) > 1 && msg_col <= 2))
+ :
+#endif
+ (msg_col + t_col >= Columns - 1
+ || (*s == TAB && msg_col + t_col >= ((Columns - 1) & ~7))
+ || (has_mbyte && (*mb_ptr2cells)(s) > 1
+ && msg_col + t_col >= Columns - 2)))))
+ {
+ /*
+ * The screen is scrolled up when at the last row (some terminals
+ * scroll automatically, some don't. To avoid problems we scroll
+ * ourselves).
+ */
+ if (t_col > 0)
+ /* output postponed text */
+ t_puts(&t_col, t_s, s, attr);
+
+ /* When no more prompt and no more room, truncate here */
+ if (msg_no_more && lines_left == 0)
+ break;
+
+ /* Scroll the screen up one line. */
+ msg_scroll_up();
+
+ msg_row = Rows - 2;
+ if (msg_col >= Columns) /* can happen after screen resize */
+ msg_col = Columns - 1;
+
+ /* Display char in last column before showing more-prompt. */
+ if (*s >= ' '
+#ifdef FEAT_RIGHTLEFT
+ && !cmdmsg_rl
+#endif
+ )
+ {
+ if (has_mbyte)
+ {
+ if (enc_utf8 && maxlen >= 0)
+ /* avoid including composing chars after the end */
+ l = utfc_ptr2len_len(s, (int)((str + maxlen) - s));
+ else
+ l = (*mb_ptr2len)(s);
+ s = screen_puts_mbyte(s, l, attr);
+ }
+ else
+ msg_screen_putchar(*s++, attr);
+ did_last_char = TRUE;
+ }
+ else
+ did_last_char = FALSE;
+
+ if (p_more)
+ /* store text for scrolling back */
+ store_sb_text(&sb_str, s, attr, &sb_col, TRUE);
+
+ inc_msg_scrolled();
+ need_wait_return = TRUE; /* may need wait_return in main() */
+ redraw_cmdline = TRUE;
+ if (cmdline_row > 0 && !exmode_active)
+ --cmdline_row;
+
+ /*
+ * If screen is completely filled and 'more' is set then wait
+ * for a character.
+ */
+ if (lines_left > 0)
+ --lines_left;
+ if (p_more && lines_left == 0 && State != HITRETURN
+ && !msg_no_more && !exmode_active)
+ {
+#ifdef FEAT_CON_DIALOG
+ if (do_more_prompt(NUL))
+ s = confirm_msg_tail;
+#else
+ (void)do_more_prompt(NUL);
+#endif
+ if (quit_more)
+ return;
+ }
+
+ /* When we displayed a char in last column need to check if there
+ * is still more. */
+ if (did_last_char)
+ continue;
+ }
+
+ wrap = *s == '\n'
+ || msg_col + t_col >= Columns
+ || (has_mbyte && (*mb_ptr2cells)(s) > 1
+ && msg_col + t_col >= Columns - 1);
+ if (t_col > 0 && (wrap || *s == '\r' || *s == '\b'
+ || *s == '\t' || *s == BELL))
+ /* output any postponed text */
+ t_puts(&t_col, t_s, s, attr);
+
+ if (wrap && p_more && !recurse)
+ /* store text for scrolling back */
+ store_sb_text(&sb_str, s, attr, &sb_col, TRUE);
+
+ if (*s == '\n') /* go to next line */
+ {
+ msg_didout = FALSE; /* remember that line is empty */
+#ifdef FEAT_RIGHTLEFT
+ if (cmdmsg_rl)
+ msg_col = Columns - 1;
+ else
+#endif
+ msg_col = 0;
+ if (++msg_row >= Rows) /* safety check */
+ msg_row = Rows - 1;
+ }
+ else if (*s == '\r') /* go to column 0 */
+ {
+ msg_col = 0;
+ }
+ else if (*s == '\b') /* go to previous char */
+ {
+ if (msg_col)
+ --msg_col;
+ }
+ else if (*s == TAB) /* translate Tab into spaces */
+ {
+ do
+ msg_screen_putchar(' ', attr);
+ while (msg_col & 7);
+ }
+ else if (*s == BELL) /* beep (from ":sh") */
+ vim_beep(BO_SH);
+ else
+ {
+ if (has_mbyte)
+ {
+ cw = (*mb_ptr2cells)(s);
+ if (enc_utf8 && maxlen >= 0)
+ /* avoid including composing chars after the end */
+ l = utfc_ptr2len_len(s, (int)((str + maxlen) - s));
+ else
+ l = (*mb_ptr2len)(s);
+ }
+ else
+ {
+ cw = 1;
+ l = 1;
+ }
+
+ /* When drawing from right to left or when a double-wide character
+ * doesn't fit, draw a single character here. Otherwise collect
+ * characters and draw them all at once later. */
+ if (
+# ifdef FEAT_RIGHTLEFT
+ cmdmsg_rl ||
+# endif
+ (cw > 1 && msg_col + t_col >= Columns - 1))
+ {
+ if (l > 1)
+ s = screen_puts_mbyte(s, l, attr) - 1;
+ else
+ msg_screen_putchar(*s, attr);
+ }
+ else
+ {
+ /* postpone this character until later */
+ if (t_col == 0)
+ t_s = s;
+ t_col += cw;
+ s += l - 1;
+ }
+ }
+ ++s;
+ }
+
+ /* output any postponed text */
+ if (t_col > 0)
+ t_puts(&t_col, t_s, s, attr);
+ if (p_more && !recurse)
+ store_sb_text(&sb_str, s, attr, &sb_col, FALSE);
+
+ msg_check();
+}
+
+/*
+ * Return TRUE when ":filter pattern" was used and "msg" does not match
+ * "pattern".
+ */
+ int
+message_filtered(char_u *msg)
+{
+ int match;
+
+ if (cmdmod.filter_regmatch.regprog == NULL)
+ return FALSE;
+ match = vim_regexec(&cmdmod.filter_regmatch, msg, (colnr_T)0);
+ return cmdmod.filter_force ? match : !match;
+}
+
+/*
+ * Scroll the screen up one line for displaying the next message line.
+ */
+ static void
+msg_scroll_up(void)
+{
+#ifdef FEAT_GUI
+ /* Remove the cursor before scrolling, ScreenLines[] is going
+ * to become invalid. */
+ if (gui.in_use)
+ gui_undraw_cursor();
+#endif
+ /* scrolling up always works */
+ mch_disable_flush();
+ screen_del_lines(0, 0, 1, (int)Rows, TRUE, 0, NULL);
+ mch_enable_flush();
+
+ if (!can_clear((char_u *)" "))
+ {
+ /* Scrolling up doesn't result in the right background. Set the
+ * background here. It's not efficient, but avoids that we have to do
+ * it all over the code. */
+ screen_fill((int)Rows - 1, (int)Rows, 0, (int)Columns, ' ', ' ', 0);
+
+ /* Also clear the last char of the last but one line if it was not
+ * cleared before to avoid a scroll-up. */
+ if (ScreenAttrs[LineOffset[Rows - 2] + Columns - 1] == (sattr_T)-1)
+ screen_fill((int)Rows - 2, (int)Rows - 1,
+ (int)Columns - 1, (int)Columns, ' ', ' ', 0);
+ }
+}
+
+/*
+ * Increment "msg_scrolled".
+ */
+ static void
+inc_msg_scrolled(void)
+{
+#ifdef FEAT_EVAL
+ if (*get_vim_var_str(VV_SCROLLSTART) == NUL)
+ {
+ char_u *p = sourcing_name;
+ char_u *tofree = NULL;
+ int len;
+
+ /* v:scrollstart is empty, set it to the script/function name and line
+ * number */
+ if (p == NULL)
+ p = (char_u *)_("Unknown");
+ else
+ {
+ len = (int)STRLEN(p) + 40;
+ tofree = alloc(len);
+ if (tofree != NULL)
+ {
+ vim_snprintf((char *)tofree, len, _("%s line %ld"),
+ p, (long)sourcing_lnum);
+ p = tofree;
+ }
+ }
+ set_vim_var_string(VV_SCROLLSTART, p, -1);
+ vim_free(tofree);
+ }
+#endif
+ ++msg_scrolled;
+ if (must_redraw < VALID)
+ must_redraw = VALID;
+}
+
+/*
+ * To be able to scroll back at the "more" and "hit-enter" prompts we need to
+ * store the displayed text and remember where screen lines start.
+ */
+typedef struct msgchunk_S msgchunk_T;
+struct msgchunk_S
+{
+ msgchunk_T *sb_next;
+ msgchunk_T *sb_prev;
+ char sb_eol; /* TRUE when line ends after this text */
+ int sb_msg_col; /* column in which text starts */
+ int sb_attr; /* text attributes */
+ char_u sb_text[1]; /* text to be displayed, actually longer */
+};
+
+static msgchunk_T *last_msgchunk = NULL; /* last displayed text */
+
+static msgchunk_T *msg_sb_start(msgchunk_T *mps);
+
+typedef enum {
+ SB_CLEAR_NONE = 0,
+ SB_CLEAR_ALL,
+ SB_CLEAR_CMDLINE_BUSY,
+ SB_CLEAR_CMDLINE_DONE
+} sb_clear_T;
+
+/* When to clear text on next msg. */
+static sb_clear_T do_clear_sb_text = SB_CLEAR_NONE;
+
+/*
+ * Store part of a printed message for displaying when scrolling back.
+ */
+ static void
+store_sb_text(
+ char_u **sb_str, /* start of string */
+ char_u *s, /* just after string */
+ int attr,
+ int *sb_col,
+ int finish) /* line ends */
+{
+ msgchunk_T *mp;
+
+ if (do_clear_sb_text == SB_CLEAR_ALL
+ || do_clear_sb_text == SB_CLEAR_CMDLINE_DONE)
+ {
+ clear_sb_text(do_clear_sb_text == SB_CLEAR_ALL);
+ do_clear_sb_text = SB_CLEAR_NONE;
+ }
+
+ if (s > *sb_str)
+ {
+ mp = (msgchunk_T *)alloc((int)(sizeof(msgchunk_T) + (s - *sb_str)));
+ if (mp != NULL)
+ {
+ mp->sb_eol = finish;
+ mp->sb_msg_col = *sb_col;
+ mp->sb_attr = attr;
+ vim_strncpy(mp->sb_text, *sb_str, s - *sb_str);
+
+ if (last_msgchunk == NULL)
+ {
+ last_msgchunk = mp;
+ mp->sb_prev = NULL;
+ }
+ else
+ {
+ mp->sb_prev = last_msgchunk;
+ last_msgchunk->sb_next = mp;
+ last_msgchunk = mp;
+ }
+ mp->sb_next = NULL;
+ }
+ }
+ else if (finish && last_msgchunk != NULL)
+ last_msgchunk->sb_eol = TRUE;
+
+ *sb_str = s;
+ *sb_col = 0;
+}
+
+/*
+ * Finished showing messages, clear the scroll-back text on the next message.
+ */
+ void
+may_clear_sb_text(void)
+{
+ do_clear_sb_text = SB_CLEAR_ALL;
+}
+
+/*
+ * Starting to edit the command line, do not clear messages now.
+ */
+ void
+sb_text_start_cmdline(void)
+{
+ do_clear_sb_text = SB_CLEAR_CMDLINE_BUSY;
+ msg_sb_eol();
+}
+
+/*
+ * Ending to edit the command line. Clear old lines but the last one later.
+ */
+ void
+sb_text_end_cmdline(void)
+{
+ do_clear_sb_text = SB_CLEAR_CMDLINE_DONE;
+}
+
+/*
+ * Clear any text remembered for scrolling back.
+ * When "all" is FALSE keep the last line.
+ * Called when redrawing the screen.
+ */
+ void
+clear_sb_text(int all)
+{
+ msgchunk_T *mp;
+ msgchunk_T **lastp;
+
+ if (all)
+ lastp = &last_msgchunk;
+ else
+ {
+ if (last_msgchunk == NULL)
+ return;
+ lastp = &last_msgchunk->sb_prev;
+ }
+
+ while (*lastp != NULL)
+ {
+ mp = (*lastp)->sb_prev;
+ vim_free(*lastp);
+ *lastp = mp;
+ }
+}
+
+/*
+ * "g<" command.
+ */
+ void
+show_sb_text(void)
+{
+ msgchunk_T *mp;
+
+ /* Only show something if there is more than one line, otherwise it looks
+ * weird, typing a command without output results in one line. */
+ mp = msg_sb_start(last_msgchunk);
+ if (mp == NULL || mp->sb_prev == NULL)
+ vim_beep(BO_MESS);
+ else
+ {
+ do_more_prompt('G');
+ wait_return(FALSE);
+ }
+}
+
+/*
+ * Move to the start of screen line in already displayed text.
+ */
+ static msgchunk_T *
+msg_sb_start(msgchunk_T *mps)
+{
+ msgchunk_T *mp = mps;
+
+ while (mp != NULL && mp->sb_prev != NULL && !mp->sb_prev->sb_eol)
+ mp = mp->sb_prev;
+ return mp;
+}
+
+/*
+ * Mark the last message chunk as finishing the line.
+ */
+ void
+msg_sb_eol(void)
+{
+ if (last_msgchunk != NULL)
+ last_msgchunk->sb_eol = TRUE;
+}
+
+/*
+ * Display a screen line from previously displayed text at row "row".
+ * Returns a pointer to the text for the next line (can be NULL).
+ */
+ static msgchunk_T *
+disp_sb_line(int row, msgchunk_T *smp)
+{
+ msgchunk_T *mp = smp;
+ char_u *p;
+
+ for (;;)
+ {
+ msg_row = row;
+ msg_col = mp->sb_msg_col;
+ p = mp->sb_text;
+ if (*p == '\n') /* don't display the line break */
+ ++p;
+ msg_puts_display(p, -1, mp->sb_attr, TRUE);
+ if (mp->sb_eol || mp->sb_next == NULL)
+ break;
+ mp = mp->sb_next;
+ }
+ return mp->sb_next;
+}
+
+/*
+ * Output any postponed text for msg_puts_attr_len().
+ */
+ static void
+t_puts(
+ int *t_col,
+ char_u *t_s,
+ char_u *s,
+ int attr)
+{
+ /* output postponed text */
+ msg_didout = TRUE; /* remember that line is not empty */
+ screen_puts_len(t_s, (int)(s - t_s), msg_row, msg_col, attr);
+ msg_col += *t_col;
+ *t_col = 0;
+ /* If the string starts with a composing character don't increment the
+ * column position for it. */
+ if (enc_utf8 && utf_iscomposing(utf_ptr2char(t_s)))
+ --msg_col;
+ if (msg_col >= Columns)
+ {
+ msg_col = 0;
+ ++msg_row;
+ }
+}
+
+/*
+ * Returns TRUE when messages should be printed with mch_errmsg().
+ * This is used when there is no valid screen, so we can see error messages.
+ * If termcap is not active, we may be writing in an alternate console
+ * window, cursor positioning may not work correctly (window size may be
+ * different, e.g. for Win32 console) or we just don't know where the
+ * cursor is.
+ */
+ int
+msg_use_printf(void)
+{
+ return (!msg_check_screen()
+#if defined(WIN3264) && !defined(FEAT_GUI_MSWIN)
+ || !termcap_active
+#endif
+ || (swapping_screen() && !termcap_active)
+ );
+}
+
+/*
+ * Print a message when there is no valid screen.
+ */
+ static void
+msg_puts_printf(char_u *str, int maxlen)
+{
+ char_u *s = str;
+ char_u buf[4];
+ char_u *p;
+#ifdef WIN3264
+# if !defined(FEAT_GUI_MSWIN)
+ char_u *ccp = NULL;
+
+# endif
+ if (!(silent_mode && p_verbose == 0))
+ mch_settmode(TMODE_COOK); /* handle '\r' and '\n' correctly */
+
+# if !defined(FEAT_GUI_MSWIN)
+ if (enc_codepage >= 0 && (int)GetConsoleCP() != enc_codepage)
+ {
+ int inlen = (int)STRLEN(str);
+ int outlen;
+ WCHAR *widestr = (WCHAR *)enc_to_utf16(str, &inlen);
+
+ if (widestr != NULL)
+ {
+ WideCharToMultiByte_alloc(GetConsoleCP(), 0, widestr, inlen,
+ (LPSTR *)&ccp, &outlen, 0, 0);
+ vim_free(widestr);
+ s = str = ccp;
+ }
+ }
+# endif
+#endif
+ while ((maxlen < 0 || (int)(s - str) < maxlen) && *s != NUL)
+ {
+ if (!(silent_mode && p_verbose == 0))
+ {
+ /* NL --> CR NL translation (for Unix, not for "--version") */
+ p = &buf[0];
+ if (*s == '\n' && !info_message)
+ *p++ = '\r';
+#if defined(USE_CR)
+ else
+#endif
+ *p++ = *s;
+ *p = '\0';
+ if (info_message) /* informative message, not an error */
+ mch_msg((char *)buf);
+ else
+ mch_errmsg((char *)buf);
+ }
+
+ /* primitive way to compute the current column */
+#ifdef FEAT_RIGHTLEFT
+ if (cmdmsg_rl)
+ {
+ if (*s == '\r' || *s == '\n')
+ msg_col = Columns - 1;
+ else
+ --msg_col;
+ }
+ else
+#endif
+ {
+ if (*s == '\r' || *s == '\n')
+ msg_col = 0;
+ else
+ ++msg_col;
+ }
+ ++s;
+ }
+ msg_didout = TRUE; /* assume that line is not empty */
+
+#ifdef WIN3264
+# if !defined(FEAT_GUI_MSWIN)
+ vim_free(ccp);
+# endif
+ if (!(silent_mode && p_verbose == 0))
+ mch_settmode(TMODE_RAW);
+#endif
+}
+
+/*
+ * Show the more-prompt and handle the user response.
+ * This takes care of scrolling back and displaying previously displayed text.
+ * When at hit-enter prompt "typed_char" is the already typed character,
+ * otherwise it's NUL.
+ * Returns TRUE when jumping ahead to "confirm_msg_tail".
+ */
+ static int
+do_more_prompt(int typed_char)
+{
+ static int entered = FALSE;
+ int used_typed_char = typed_char;
+ int oldState = State;
+ int c;
+#ifdef FEAT_CON_DIALOG
+ int retval = FALSE;
+#endif
+ int toscroll;
+ msgchunk_T *mp_last = NULL;
+ msgchunk_T *mp;
+ int i;
+
+ /* We get called recursively when a timer callback outputs a message. In
+ * that case don't show another prompt. Also when at the hit-Enter prompt
+ * and nothing was typed. */
+ if (entered || (State == HITRETURN && typed_char == 0))
+ return FALSE;
+ entered = TRUE;
+
+ if (typed_char == 'G')
+ {
+ /* "g<": Find first line on the last page. */
+ mp_last = msg_sb_start(last_msgchunk);
+ for (i = 0; i < Rows - 2 && mp_last != NULL
+ && mp_last->sb_prev != NULL; ++i)
+ mp_last = msg_sb_start(mp_last->sb_prev);
+ }
+
+ State = ASKMORE;
+#ifdef FEAT_MOUSE
+ setmouse();
+#endif
+ if (typed_char == NUL)
+ msg_moremsg(FALSE);
+ for (;;)
+ {
+ /*
+ * Get a typed character directly from the user.
+ */
+ if (used_typed_char != NUL)
+ {
+ c = used_typed_char; /* was typed at hit-enter prompt */
+ used_typed_char = NUL;
+ }
+ else
+ c = get_keystroke();
+
+#if defined(FEAT_MENU) && defined(FEAT_GUI)
+ if (c == K_MENU)
+ {
+ int idx = get_menu_index(current_menu, ASKMORE);
+
+ /* Used a menu. If it starts with CTRL-Y, it must
+ * be a "Copy" for the clipboard. Otherwise
+ * assume that we end */
+ if (idx == MENU_INDEX_INVALID)
+ continue;
+ c = *current_menu->strings[idx];
+ if (c != NUL && current_menu->strings[idx][1] != NUL)
+ ins_typebuf(current_menu->strings[idx] + 1,
+ current_menu->noremap[idx], 0, TRUE,
+ current_menu->silent[idx]);
+ }
+#endif
+
+ toscroll = 0;
+ switch (c)
+ {
+ case BS: /* scroll one line back */
+ case K_BS:
+ case 'k':
+ case K_UP:
+ toscroll = -1;
+ break;
+
+ case CAR: /* one extra line */
+ case NL:
+ case 'j':
+ case K_DOWN:
+ toscroll = 1;
+ break;
+
+ case 'u': /* Up half a page */
+ toscroll = -(Rows / 2);
+ break;
+
+ case 'd': /* Down half a page */
+ toscroll = Rows / 2;
+ break;
+
+ case 'b': /* one page back */
+ case K_PAGEUP:
+ toscroll = -(Rows - 1);
+ break;
+
+ case ' ': /* one extra page */
+ case 'f':
+ case K_PAGEDOWN:
+ case K_LEFTMOUSE:
+ toscroll = Rows - 1;
+ break;
+
+ case 'g': /* all the way back to the start */
+ toscroll = -999999;
+ break;
+
+ case 'G': /* all the way to the end */
+ toscroll = 999999;
+ lines_left = 999999;
+ break;
+
+ case ':': /* start new command line */
+#ifdef FEAT_CON_DIALOG
+ if (!confirm_msg_used)
+#endif
+ {
+ /* Since got_int is set all typeahead will be flushed, but we
+ * want to keep this ':', remember that in a special way. */
+ typeahead_noflush(':');
+#ifdef FEAT_TERMINAL
+ skip_term_loop = TRUE;
+#endif
+ cmdline_row = Rows - 1; /* put ':' on this line */
+ skip_redraw = TRUE; /* skip redraw once */
+ need_wait_return = FALSE; /* don't wait in main() */
+ }
+ /* FALLTHROUGH */
+ case 'q': /* quit */
+ case Ctrl_C:
+ case ESC:
+#ifdef FEAT_CON_DIALOG
+ if (confirm_msg_used)
+ {
+ /* Jump to the choices of the dialog. */
+ retval = TRUE;
+ }
+ else
+#endif
+ {
+ got_int = TRUE;
+ quit_more = TRUE;
+ }
+ /* When there is some more output (wrapping line) display that
+ * without another prompt. */
+ lines_left = Rows - 1;
+ break;
+
+#ifdef FEAT_CLIPBOARD
+ case Ctrl_Y:
+ /* Strange way to allow copying (yanking) a modeless
+ * selection at the more prompt. Use CTRL-Y,
+ * because the same is used in Cmdline-mode and at the
+ * hit-enter prompt. However, scrolling one line up
+ * might be expected... */
+ if (clip_star.state == SELECT_DONE)
+ clip_copy_modeless_selection(TRUE);
+ continue;
+#endif
+ default: /* no valid response */
+ msg_moremsg(TRUE);
+ continue;
+ }
+
+ if (toscroll != 0)
+ {
+ if (toscroll < 0)
+ {
+ /* go to start of last line */
+ if (mp_last == NULL)
+ mp = msg_sb_start(last_msgchunk);
+ else if (mp_last->sb_prev != NULL)
+ mp = msg_sb_start(mp_last->sb_prev);
+ else
+ mp = NULL;
+
+ /* go to start of line at top of the screen */
+ for (i = 0; i < Rows - 2 && mp != NULL && mp->sb_prev != NULL;
+ ++i)
+ mp = msg_sb_start(mp->sb_prev);
+
+ if (mp != NULL && mp->sb_prev != NULL)
+ {
+ /* Find line to be displayed at top. */
+ for (i = 0; i > toscroll; --i)
+ {
+ if (mp == NULL || mp->sb_prev == NULL)
+ break;
+ mp = msg_sb_start(mp->sb_prev);
+ if (mp_last == NULL)
+ mp_last = msg_sb_start(last_msgchunk);
+ else
+ mp_last = msg_sb_start(mp_last->sb_prev);
+ }
+
+ if (toscroll == -1 && screen_ins_lines(0, 0, 1,
+ (int)Rows, 0, NULL) == OK)
+ {
+ /* display line at top */
+ (void)disp_sb_line(0, mp);
+ }
+ else
+ {
+ /* redisplay all lines */
+ screenclear();
+ for (i = 0; mp != NULL && i < Rows - 1; ++i)
+ {
+ mp = disp_sb_line(i, mp);
+ ++msg_scrolled;
+ }
+ }
+ toscroll = 0;
+ }
+ }
+ else
+ {
+ /* First display any text that we scrolled back. */
+ while (toscroll > 0 && mp_last != NULL)
+ {
+ /* scroll up, display line at bottom */
+ msg_scroll_up();
+ inc_msg_scrolled();
+ screen_fill((int)Rows - 2, (int)Rows - 1, 0,
+ (int)Columns, ' ', ' ', 0);
+ mp_last = disp_sb_line((int)Rows - 2, mp_last);
+ --toscroll;
+ }
+ }
+
+ if (toscroll <= 0)
+ {
+ /* displayed the requested text, more prompt again */
+ screen_fill((int)Rows - 1, (int)Rows, 0,
+ (int)Columns, ' ', ' ', 0);
+ msg_moremsg(FALSE);
+ continue;
+ }
+
+ /* display more text, return to caller */
+ lines_left = toscroll;
+ }
+
+ break;
+ }
+
+ /* clear the --more-- message */
+ screen_fill((int)Rows - 1, (int)Rows, 0, (int)Columns, ' ', ' ', 0);
+ State = oldState;
+#ifdef FEAT_MOUSE
+ setmouse();
+#endif
+ if (quit_more)
+ {
+ msg_row = Rows - 1;
+ msg_col = 0;
+ }
+#ifdef FEAT_RIGHTLEFT
+ else if (cmdmsg_rl)
+ msg_col = Columns - 1;
+#endif
+
+ entered = FALSE;
+#ifdef FEAT_CON_DIALOG
+ return retval;
+#else
+ return FALSE;
+#endif
+}
+
+#if defined(USE_MCH_ERRMSG) || defined(PROTO)
+
+#ifdef mch_errmsg
+# undef mch_errmsg
+#endif
+#ifdef mch_msg
+# undef mch_msg
+#endif
+
+/*
+ * Give an error message. To be used when the screen hasn't been initialized
+ * yet. When stderr can't be used, collect error messages until the GUI has
+ * started and they can be displayed in a message box.
+ */
+ void
+mch_errmsg(char *str)
+{
+ int len;
+
+#if (defined(UNIX) || defined(FEAT_GUI)) && !defined(ALWAYS_USE_GUI)
+ /* On Unix use stderr if it's a tty.
+ * When not going to start the GUI also use stderr.
+ * On Mac, when started from Finder, stderr is the console. */
+ if (
+# ifdef UNIX
+# ifdef MACOS_X
+ (isatty(2) && strcmp("/dev/console", ttyname(2)) != 0)
+# else
+ isatty(2)
+# endif
+# ifdef FEAT_GUI
+ ||
+# endif
+# endif
+# ifdef FEAT_GUI
+ !(gui.in_use || gui.starting)
+# endif
+ )
+ {
+ fprintf(stderr, "%s", str);
+ return;
+ }
+#endif
+
+ /* avoid a delay for a message that isn't there */
+ emsg_on_display = FALSE;
+
+ len = (int)STRLEN(str) + 1;
+ if (error_ga.ga_growsize == 0)
+ {
+ error_ga.ga_growsize = 80;
+ error_ga.ga_itemsize = 1;
+ }
+ if (ga_grow(&error_ga, len) == OK)
+ {
+ mch_memmove((char_u *)error_ga.ga_data + error_ga.ga_len,
+ (char_u *)str, len);
+#ifdef UNIX
+ /* remove CR characters, they are displayed */
+ {
+ char_u *p;
+
+ p = (char_u *)error_ga.ga_data + error_ga.ga_len;
+ for (;;)
+ {
+ p = vim_strchr(p, '\r');
+ if (p == NULL)
+ break;
+ *p = ' ';
+ }
+ }
+#endif
+ --len; /* don't count the NUL at the end */
+ error_ga.ga_len += len;
+ }
+}
+
+/*
+ * Give a message. To be used when the screen hasn't been initialized yet.
+ * When there is no tty, collect messages until the GUI has started and they
+ * can be displayed in a message box.
+ */
+ void
+mch_msg(char *str)
+{
+#if (defined(UNIX) || defined(FEAT_GUI)) && !defined(ALWAYS_USE_GUI)
+ /* On Unix use stdout if we have a tty. This allows "vim -h | more" and
+ * uses mch_errmsg() when started from the desktop.
+ * When not going to start the GUI also use stdout.
+ * On Mac, when started from Finder, stderr is the console. */
+ if (
+# ifdef UNIX
+# ifdef MACOS_X
+ (isatty(2) && strcmp("/dev/console", ttyname(2)) != 0)
+# else
+ isatty(2)
+# endif
+# ifdef FEAT_GUI
+ ||
+# endif
+# endif
+# ifdef FEAT_GUI
+ !(gui.in_use || gui.starting)
+# endif
+ )
+ {
+ printf("%s", str);
+ return;
+ }
+# endif
+ mch_errmsg(str);
+}
+#endif /* USE_MCH_ERRMSG */
+
+/*
+ * Put a character on the screen at the current message position and advance
+ * to the next position. Only for printable ASCII!
+ */
+ static void
+msg_screen_putchar(int c, int attr)
+{
+ msg_didout = TRUE; /* remember that line is not empty */
+ screen_putchar(c, msg_row, msg_col, attr);
+#ifdef FEAT_RIGHTLEFT
+ if (cmdmsg_rl)
+ {
+ if (--msg_col == 0)
+ {
+ msg_col = Columns;
+ ++msg_row;
+ }
+ }
+ else
+#endif
+ {
+ if (++msg_col >= Columns)
+ {
+ msg_col = 0;
+ ++msg_row;
+ }
+ }
+}
+
+ void
+msg_moremsg(int full)
+{
+ int attr;
+ char_u *s = (char_u *)_("-- More --");
+
+ attr = HL_ATTR(HLF_M);
+ screen_puts(s, (int)Rows - 1, 0, attr);
+ if (full)
+ screen_puts((char_u *)
+ _(" SPACE/d/j: screen/page/line down, b/u/k: up, q: quit "),
+ (int)Rows - 1, vim_strsize(s), attr);
+}
+
+/*
+ * Repeat the message for the current mode: ASKMORE, EXTERNCMD, CONFIRM or
+ * exmode_active.
+ */
+ void
+repeat_message(void)
+{
+ if (State == ASKMORE)
+ {
+ msg_moremsg(TRUE); /* display --more-- message again */
+ msg_row = Rows - 1;
+ }
+#ifdef FEAT_CON_DIALOG
+ else if (State == CONFIRM)
+ {
+ display_confirm_msg(); /* display ":confirm" message again */
+ msg_row = Rows - 1;
+ }
+#endif
+ else if (State == EXTERNCMD)
+ {
+ windgoto(msg_row, msg_col); /* put cursor back */
+ }
+ else if (State == HITRETURN || State == SETWSIZE)
+ {
+ if (msg_row == Rows - 1)
+ {
+ /* Avoid drawing the "hit-enter" prompt below the previous one,
+ * overwrite it. Esp. useful when regaining focus and a
+ * FocusGained autocmd exists but didn't draw anything. */
+ msg_didout = FALSE;
+ msg_col = 0;
+ msg_clr_eos();
+ }
+ hit_return_msg();
+ msg_row = Rows - 1;
+ }
+}
+
+/*
+ * msg_check_screen - check if the screen is initialized.
+ * Also check msg_row and msg_col, if they are too big it may cause a crash.
+ * While starting the GUI the terminal codes will be set for the GUI, but the
+ * output goes to the terminal. Don't use the terminal codes then.
+ */
+ static int
+msg_check_screen(void)
+{
+ if (!full_screen || !screen_valid(FALSE))
+ return FALSE;
+
+ if (msg_row >= Rows)
+ msg_row = Rows - 1;
+ if (msg_col >= Columns)
+ msg_col = Columns - 1;
+ return TRUE;
+}
+
+/*
+ * Clear from current message position to end of screen.
+ * Skip this when ":silent" was used, no need to clear for redirection.
+ */
+ void
+msg_clr_eos(void)
+{
+ if (msg_silent == 0)
+ msg_clr_eos_force();
+}
+
+/*
+ * Clear from current message position to end of screen.
+ * Note: msg_col is not updated, so we remember the end of the message
+ * for msg_check().
+ */
+ void
+msg_clr_eos_force(void)
+{
+ if (msg_use_printf())
+ {
+ if (full_screen) /* only when termcap codes are valid */
+ {
+ if (*T_CD)
+ out_str(T_CD); /* clear to end of display */
+ else if (*T_CE)
+ out_str(T_CE); /* clear to end of line */
+ }
+ }
+ else
+ {
+#ifdef FEAT_RIGHTLEFT
+ if (cmdmsg_rl)
+ {
+ screen_fill(msg_row, msg_row + 1, 0, msg_col + 1, ' ', ' ', 0);
+ screen_fill(msg_row + 1, (int)Rows, 0, (int)Columns, ' ', ' ', 0);
+ }
+ else
+#endif
+ {
+ screen_fill(msg_row, msg_row + 1, msg_col, (int)Columns,
+ ' ', ' ', 0);
+ screen_fill(msg_row + 1, (int)Rows, 0, (int)Columns, ' ', ' ', 0);
+ }
+ }
+}
+
+/*
+ * Clear the command line.
+ */
+ void
+msg_clr_cmdline(void)
+{
+ msg_row = cmdline_row;
+ msg_col = 0;
+ msg_clr_eos_force();
+}
+
+/*
+ * end putting a message on the screen
+ * call wait_return if the message does not fit in the available space
+ * return TRUE if wait_return not called.
+ */
+ int
+msg_end(void)
+{
+ /*
+ * If the string is larger than the window,
+ * or the ruler option is set and we run into it,
+ * we have to redraw the window.
+ * Do not do this if we are abandoning the file or editing the command line.
+ */
+ if (!exiting && need_wait_return && !(State & CMDLINE))
+ {
+ wait_return(FALSE);
+ return FALSE;
+ }
+ out_flush();
+ return TRUE;
+}
+
+/*
+ * If the written message runs into the shown command or ruler, we have to
+ * wait for hit-return and redraw the window later.
+ */
+ void
+msg_check(void)
+{
+ if (msg_row == Rows - 1 && msg_col >= sc_col)
+ {
+ need_wait_return = TRUE;
+ redraw_cmdline = TRUE;
+ }
+}
+
+/*
+ * May write a string to the redirection file.
+ * When "maxlen" is -1 write the whole string, otherwise up to "maxlen" bytes.
+ */
+ static void
+redir_write(char_u *str, int maxlen)
+{
+ char_u *s = str;
+ static int cur_col = 0;
+
+ /* Don't do anything for displaying prompts and the like. */
+ if (redir_off)
+ return;
+
+ /* If 'verbosefile' is set prepare for writing in that file. */
+ if (*p_vfile != NUL && verbose_fd == NULL)
+ verbose_open();
+
+ if (redirecting())
+ {
+ /* If the string doesn't start with CR or NL, go to msg_col */
+ if (*s != '\n' && *s != '\r')
+ {
+ while (cur_col < msg_col)
+ {
+#ifdef FEAT_EVAL
+ if (redir_execute)
+ execute_redir_str((char_u *)" ", -1);
+ else if (redir_reg)
+ write_reg_contents(redir_reg, (char_u *)" ", -1, TRUE);
+ else if (redir_vname)
+ var_redir_str((char_u *)" ", -1);
+ else
+#endif
+ if (redir_fd != NULL)
+ fputs(" ", redir_fd);
+ if (verbose_fd != NULL)
+ fputs(" ", verbose_fd);
+ ++cur_col;
+ }
+ }
+
+#ifdef FEAT_EVAL
+ if (redir_execute)
+ execute_redir_str(s, maxlen);
+ else if (redir_reg)
+ write_reg_contents(redir_reg, s, maxlen, TRUE);
+ else if (redir_vname)
+ var_redir_str(s, maxlen);
+#endif
+
+ /* Write and adjust the current column. */
+ while (*s != NUL && (maxlen < 0 || (int)(s - str) < maxlen))
+ {
+#ifdef FEAT_EVAL
+ if (!redir_reg && !redir_vname && !redir_execute)
+#endif
+ if (redir_fd != NULL)
+ putc(*s, redir_fd);
+ if (verbose_fd != NULL)
+ putc(*s, verbose_fd);
+ if (*s == '\r' || *s == '\n')
+ cur_col = 0;
+ else if (*s == '\t')
+ cur_col += (8 - cur_col % 8);
+ else
+ ++cur_col;
+ ++s;
+ }
+
+ if (msg_silent != 0) /* should update msg_col */
+ msg_col = cur_col;
+ }
+}
+
+ int
+redirecting(void)
+{
+ return redir_fd != NULL || *p_vfile != NUL
+#ifdef FEAT_EVAL
+ || redir_reg || redir_vname || redir_execute
+#endif
+ ;
+}
+
+/*
+ * Before giving verbose message.
+ * Must always be called paired with verbose_leave()!
+ */
+ void
+verbose_enter(void)
+{
+ if (*p_vfile != NUL)
+ ++msg_silent;
+}
+
+/*
+ * After giving verbose message.
+ * Must always be called paired with verbose_enter()!
+ */
+ void
+verbose_leave(void)
+{
+ if (*p_vfile != NUL)
+ if (--msg_silent < 0)
+ msg_silent = 0;
+}
+
+/*
+ * Like verbose_enter() and set msg_scroll when displaying the message.
+ */
+ void
+verbose_enter_scroll(void)
+{
+ if (*p_vfile != NUL)
+ ++msg_silent;
+ else
+ /* always scroll up, don't overwrite */
+ msg_scroll = TRUE;
+}
+
+/*
+ * Like verbose_leave() and set cmdline_row when displaying the message.
+ */
+ void
+verbose_leave_scroll(void)
+{
+ if (*p_vfile != NUL)
+ {
+ if (--msg_silent < 0)
+ msg_silent = 0;
+ }
+ else
+ cmdline_row = msg_row;
+}
+
+/*
+ * Called when 'verbosefile' is set: stop writing to the file.
+ */
+ void
+verbose_stop(void)
+{
+ if (verbose_fd != NULL)
+ {
+ fclose(verbose_fd);
+ verbose_fd = NULL;
+ }
+ verbose_did_open = FALSE;
+}
+
+/*
+ * Open the file 'verbosefile'.
+ * Return FAIL or OK.
+ */
+ int
+verbose_open(void)
+{
+ if (verbose_fd == NULL && !verbose_did_open)
+ {
+ /* Only give the error message once. */
+ verbose_did_open = TRUE;
+
+ verbose_fd = mch_fopen((char *)p_vfile, "a");
+ if (verbose_fd == NULL)
+ {
+ semsg(_(e_notopen), p_vfile);
+ return FAIL;
+ }
+ }
+ return OK;
+}
+
+/*
+ * Give a warning message (for searching).
+ * Use 'w' highlighting and may repeat the message after redrawing
+ */
+ void
+give_warning(char_u *message, int hl)
+{
+ /* Don't do this for ":silent". */
+ if (msg_silent != 0)
+ return;
+
+ /* Don't want a hit-enter prompt here. */
+ ++no_wait_return;
+
+#ifdef FEAT_EVAL
+ set_vim_var_string(VV_WARNINGMSG, message, -1);
+#endif
+ VIM_CLEAR(keep_msg);
+ if (hl)
+ keep_msg_attr = HL_ATTR(HLF_W);
+ else
+ keep_msg_attr = 0;
+ if (msg_attr((char *)message, keep_msg_attr) && msg_scrolled == 0)
+ set_keep_msg(message, keep_msg_attr);
+ msg_didout = FALSE; /* overwrite this message */
+ msg_nowait = TRUE; /* don't wait for this message */
+ msg_col = 0;
+
+ --no_wait_return;
+}
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+ void
+give_warning2(char_u *message, char_u *a1, int hl)
+{
+ vim_snprintf((char *)IObuff, IOSIZE, (char *)message, a1);
+ give_warning(IObuff, hl);
+}
+#endif
+
+/*
+ * Advance msg cursor to column "col".
+ */
+ void
+msg_advance(int col)
+{
+ if (msg_silent != 0) /* nothing to advance to */
+ {
+ msg_col = col; /* for redirection, may fill it up later */
+ return;
+ }
+ if (col >= Columns) /* not enough room */
+ col = Columns - 1;
+#ifdef FEAT_RIGHTLEFT
+ if (cmdmsg_rl)
+ while (msg_col > Columns - col)
+ msg_putchar(' ');
+ else
+#endif
+ while (msg_col < col)
+ msg_putchar(' ');
+}
+
+#if defined(FEAT_CON_DIALOG) || defined(PROTO)
+/*
+ * Used for "confirm()" function, and the :confirm command prefix.
+ * Versions which haven't got flexible dialogs yet, and console
+ * versions, get this generic handler which uses the command line.
+ *
+ * type = one of:
+ * VIM_QUESTION, VIM_INFO, VIM_WARNING, VIM_ERROR or VIM_GENERIC
+ * title = title string (can be NULL for default)
+ * (neither used in console dialogs at the moment)
+ *
+ * Format of the "buttons" string:
+ * "Button1Name\nButton2Name\nButton3Name"
+ * The first button should normally be the default/accept
+ * The second button should be the 'Cancel' button
+ * Other buttons- use your imagination!
+ * A '&' in a button name becomes a shortcut, so each '&' should be before a
+ * different letter.
+ */
+ int
+do_dialog(
+ int type UNUSED,
+ char_u *title UNUSED,
+ char_u *message,
+ char_u *buttons,
+ int dfltbutton,
+ char_u *textfield UNUSED, /* IObuff for inputdialog(), NULL
+ otherwise */
+ int ex_cmd) /* when TRUE pressing : accepts default and starts
+ Ex command */
+{
+ int oldState;
+ int retval = 0;
+ char_u *hotkeys;
+ int c;
+ int i;
+
+#ifndef NO_CONSOLE
+ /* Don't output anything in silent mode ("ex -s") */
+ if (silent_mode)
+ return dfltbutton; /* return default option */
+#endif
+
+#ifdef FEAT_GUI_DIALOG
+ /* When GUI is running and 'c' not in 'guioptions', use the GUI dialog */
+ if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
+ {
+ c = gui_mch_dialog(type, title, message, buttons, dfltbutton,
+ textfield, ex_cmd);
+ /* avoid a hit-enter prompt without clearing the cmdline */
+ need_wait_return = FALSE;
+ emsg_on_display = FALSE;
+ cmdline_row = msg_row;
+
+ /* Flush output to avoid that further messages and redrawing is done
+ * in the wrong order. */
+ out_flush();
+ gui_mch_update();
+
+ return c;
+ }
+#endif
+
+ oldState = State;
+ State = CONFIRM;
+#ifdef FEAT_MOUSE
+ setmouse();
+#endif
+
+ /*
+ * Since we wait for a keypress, don't make the
+ * user press RETURN as well afterwards.
+ */
+ ++no_wait_return;
+ hotkeys = msg_show_console_dialog(message, buttons, dfltbutton);
+
+ if (hotkeys != NULL)
+ {
+ for (;;)
+ {
+ /* Get a typed character directly from the user. */
+ c = get_keystroke();
+ switch (c)
+ {
+ case CAR: /* User accepts default option */
+ case NL:
+ retval = dfltbutton;
+ break;
+ case Ctrl_C: /* User aborts/cancels */
+ case ESC:
+ retval = 0;
+ break;
+ default: /* Could be a hotkey? */
+ if (c < 0) /* special keys are ignored here */
+ continue;
+ if (c == ':' && ex_cmd)
+ {
+ retval = dfltbutton;
+ ins_char_typebuf(':');
+ break;
+ }
+
+ /* Make the character lowercase, as chars in "hotkeys" are. */
+ c = MB_TOLOWER(c);
+ retval = 1;
+ for (i = 0; hotkeys[i]; ++i)
+ {
+ if (has_mbyte)
+ {
+ if ((*mb_ptr2char)(hotkeys + i) == c)
+ break;
+ i += (*mb_ptr2len)(hotkeys + i) - 1;
+ }
+ else
+ if (hotkeys[i] == c)
+ break;
+ ++retval;
+ }
+ if (hotkeys[i])
+ break;
+ /* No hotkey match, so keep waiting */
+ continue;
+ }
+ break;
+ }
+
+ vim_free(hotkeys);
+ }
+
+ State = oldState;
+#ifdef FEAT_MOUSE
+ setmouse();
+#endif
+ --no_wait_return;
+ msg_end_prompt();
+
+ return retval;
+}
+
+/*
+ * Copy one character from "*from" to "*to", taking care of multi-byte
+ * characters. Return the length of the character in bytes.
+ */
+ static int
+copy_char(
+ char_u *from,
+ char_u *to,
+ int lowercase) /* make character lower case */
+{
+ int len;
+ int c;
+
+ if (has_mbyte)
+ {
+ if (lowercase)
+ {
+ c = MB_TOLOWER((*mb_ptr2char)(from));
+ return (*mb_char2bytes)(c, to);
+ }
+ else
+ {
+ len = (*mb_ptr2len)(from);
+ mch_memmove(to, from, (size_t)len);
+ return len;
+ }
+ }
+ else
+ {
+ if (lowercase)
+ *to = (char_u)TOLOWER_LOC(*from);
+ else
+ *to = *from;
+ return 1;
+ }
+}
+
+/*
+ * Format the dialog string, and display it at the bottom of
+ * the screen. Return a string of hotkey chars (if defined) for
+ * each 'button'. If a button has no hotkey defined, the first character of
+ * the button is used.
+ * The hotkeys can be multi-byte characters, but without combining chars.
+ *
+ * Returns an allocated string with hotkeys, or NULL for error.
+ */
+ static char_u *
+msg_show_console_dialog(
+ char_u *message,
+ char_u *buttons,
+ int dfltbutton)
+{
+ int len = 0;
+#define HOTK_LEN (has_mbyte ? MB_MAXBYTES : 1)
+ int lenhotkey = HOTK_LEN; /* count first button */
+ char_u *hotk = NULL;
+ char_u *msgp = NULL;
+ char_u *hotkp = NULL;
+ char_u *r;
+ int copy;
+#define HAS_HOTKEY_LEN 30
+ char_u has_hotkey[HAS_HOTKEY_LEN];
+ int first_hotkey = FALSE; /* first char of button is hotkey */
+ int idx;
+
+ has_hotkey[0] = FALSE;
+
+ /*
+ * First loop: compute the size of memory to allocate.
+ * Second loop: copy to the allocated memory.
+ */
+ for (copy = 0; copy <= 1; ++copy)
+ {
+ r = buttons;
+ idx = 0;
+ while (*r)
+ {
+ if (*r == DLG_BUTTON_SEP)
+ {
+ if (copy)
+ {
+ *msgp++ = ',';
+ *msgp++ = ' '; /* '\n' -> ', ' */
+
+ /* advance to next hotkey and set default hotkey */
+ if (has_mbyte)
+ hotkp += STRLEN(hotkp);
+ else
+ ++hotkp;
+ hotkp[copy_char(r + 1, hotkp, TRUE)] = NUL;
+ if (dfltbutton)
+ --dfltbutton;
+
+ /* If no hotkey is specified first char is used. */
+ if (idx < HAS_HOTKEY_LEN - 1 && !has_hotkey[++idx])
+ first_hotkey = TRUE;
+ }
+ else
+ {
+ len += 3; /* '\n' -> ', '; 'x' -> '(x)' */
+ lenhotkey += HOTK_LEN; /* each button needs a hotkey */
+ if (idx < HAS_HOTKEY_LEN - 1)
+ has_hotkey[++idx] = FALSE;
+ }
+ }
+ else if (*r == DLG_HOTKEY_CHAR || first_hotkey)
+ {
+ if (*r == DLG_HOTKEY_CHAR)
+ ++r;
+ first_hotkey = FALSE;
+ if (copy)
+ {
+ if (*r == DLG_HOTKEY_CHAR) /* '&&a' -> '&a' */
+ *msgp++ = *r;
+ else
+ {
+ /* '&a' -> '[a]' */
+ *msgp++ = (dfltbutton == 1) ? '[' : '(';
+ msgp += copy_char(r, msgp, FALSE);
+ *msgp++ = (dfltbutton == 1) ? ']' : ')';
+
+ /* redefine hotkey */
+ hotkp[copy_char(r, hotkp, TRUE)] = NUL;
+ }
+ }
+ else
+ {
+ ++len; /* '&a' -> '[a]' */
+ if (idx < HAS_HOTKEY_LEN - 1)
+ has_hotkey[idx] = TRUE;
+ }
+ }
+ else
+ {
+ /* everything else copy literally */
+ if (copy)
+ msgp += copy_char(r, msgp, FALSE);
+ }
+
+ /* advance to the next character */
+ MB_PTR_ADV(r);
+ }
+
+ if (copy)
+ {
+ *msgp++ = ':';
+ *msgp++ = ' ';
+ *msgp = NUL;
+ }
+ else
+ {
+ len += (int)(STRLEN(message)
+ + 2 /* for the NL's */
+ + STRLEN(buttons)
+ + 3); /* for the ": " and NUL */
+ lenhotkey++; /* for the NUL */
+
+ /* If no hotkey is specified first char is used. */
+ if (!has_hotkey[0])
+ {
+ first_hotkey = TRUE;
+ len += 2; /* "x" -> "[x]" */
+ }
+
+ /*
+ * Now allocate and load the strings
+ */
+ vim_free(confirm_msg);
+ confirm_msg = alloc(len);
+ if (confirm_msg == NULL)
+ return NULL;
+ *confirm_msg = NUL;
+ hotk = alloc(lenhotkey);
+ if (hotk == NULL)
+ return NULL;
+
+ *confirm_msg = '\n';
+ STRCPY(confirm_msg + 1, message);
+
+ msgp = confirm_msg + 1 + STRLEN(message);
+ hotkp = hotk;
+
+ /* Define first default hotkey. Keep the hotkey string NUL
+ * terminated to avoid reading past the end. */
+ hotkp[copy_char(buttons, hotkp, TRUE)] = NUL;
+
+ /* Remember where the choices start, displaying starts here when
+ * "hotkp" typed at the more prompt. */
+ confirm_msg_tail = msgp;
+ *msgp++ = '\n';
+ }
+ }
+
+ display_confirm_msg();
+ return hotk;
+}
+
+/*
+ * Display the ":confirm" message. Also called when screen resized.
+ */
+ void
+display_confirm_msg(void)
+{
+ /* avoid that 'q' at the more prompt truncates the message here */
+ ++confirm_msg_used;
+ if (confirm_msg != NULL)
+ msg_puts_attr((char *)confirm_msg, HL_ATTR(HLF_M));
+ --confirm_msg_used;
+}
+
+#endif /* FEAT_CON_DIALOG */
+
+#if defined(FEAT_CON_DIALOG) || defined(FEAT_GUI_DIALOG)
+
+ int
+vim_dialog_yesno(
+ int type,
+ char_u *title,
+ char_u *message,
+ int dflt)
+{
+ if (do_dialog(type,
+ title == NULL ? (char_u *)_("Question") : title,
+ message,
+ (char_u *)_("&Yes\n&No"), dflt, NULL, FALSE) == 1)
+ return VIM_YES;
+ return VIM_NO;
+}
+
+ int
+vim_dialog_yesnocancel(
+ int type,
+ char_u *title,
+ char_u *message,
+ int dflt)
+{
+ switch (do_dialog(type,
+ title == NULL ? (char_u *)_("Question") : title,
+ message,
+ (char_u *)_("&Yes\n&No\n&Cancel"), dflt, NULL, FALSE))
+ {
+ case 1: return VIM_YES;
+ case 2: return VIM_NO;
+ }
+ return VIM_CANCEL;
+}
+
+ int
+vim_dialog_yesnoallcancel(
+ int type,
+ char_u *title,
+ char_u *message,
+ int dflt)
+{
+ switch (do_dialog(type,
+ title == NULL ? (char_u *)"Question" : title,
+ message,
+ (char_u *)_("&Yes\n&No\nSave &All\n&Discard All\n&Cancel"),
+ dflt, NULL, FALSE))
+ {
+ case 1: return VIM_YES;
+ case 2: return VIM_NO;
+ case 3: return VIM_ALL;
+ case 4: return VIM_DISCARDALL;
+ }
+ return VIM_CANCEL;
+}
+
+#endif /* FEAT_GUI_DIALOG || FEAT_CON_DIALOG */
+
+#if defined(FEAT_BROWSE) || defined(PROTO)
+/*
+ * Generic browse function. Calls gui_mch_browse() when possible.
+ * Later this may pop-up a non-GUI file selector (external command?).
+ */
+ char_u *
+do_browse(
+ int flags, /* BROWSE_SAVE and BROWSE_DIR */
+ char_u *title, /* title for the window */
+ char_u *dflt, /* default file name (may include directory) */
+ char_u *ext, /* extension added */
+ char_u *initdir, /* initial directory, NULL for current dir or
+ when using path from "dflt" */
+ char_u *filter, /* file name filter */
+ buf_T *buf) /* buffer to read/write for */
+{
+ char_u *fname;
+ static char_u *last_dir = NULL; /* last used directory */
+ char_u *tofree = NULL;
+ int save_browse = cmdmod.browse;
+
+ /* Must turn off browse to avoid that autocommands will get the
+ * flag too! */
+ cmdmod.browse = FALSE;
+
+ if (title == NULL || *title == NUL)
+ {
+ if (flags & BROWSE_DIR)
+ title = (char_u *)_("Select Directory dialog");
+ else if (flags & BROWSE_SAVE)
+ title = (char_u *)_("Save File dialog");
+ else
+ title = (char_u *)_("Open File dialog");
+ }
+
+ /* When no directory specified, use default file name, default dir, buffer
+ * dir, last dir or current dir */
+ if ((initdir == NULL || *initdir == NUL) && dflt != NULL && *dflt != NUL)
+ {
+ if (mch_isdir(dflt)) /* default file name is a directory */
+ {
+ initdir = dflt;
+ dflt = NULL;
+ }
+ else if (gettail(dflt) != dflt) /* default file name includes a path */
+ {
+ tofree = vim_strsave(dflt);
+ if (tofree != NULL)
+ {
+ initdir = tofree;
+ *gettail(initdir) = NUL;
+ dflt = gettail(dflt);
+ }
+ }
+ }
+
+ if (initdir == NULL || *initdir == NUL)
+ {
+ /* When 'browsedir' is a directory, use it */
+ if (STRCMP(p_bsdir, "last") != 0
+ && STRCMP(p_bsdir, "buffer") != 0
+ && STRCMP(p_bsdir, "current") != 0
+ && mch_isdir(p_bsdir))
+ initdir = p_bsdir;
+ /* When saving or 'browsedir' is "buffer", use buffer fname */
+ else if (((flags & BROWSE_SAVE) || *p_bsdir == 'b')
+ && buf != NULL && buf->b_ffname != NULL)
+ {
+ if (dflt == NULL || *dflt == NUL)
+ dflt = gettail(curbuf->b_ffname);
+ tofree = vim_strsave(curbuf->b_ffname);
+ if (tofree != NULL)
+ {
+ initdir = tofree;
+ *gettail(initdir) = NUL;
+ }
+ }
+ /* When 'browsedir' is "last", use dir from last browse */
+ else if (*p_bsdir == 'l')
+ initdir = last_dir;
+ /* When 'browsedir is "current", use current directory. This is the
+ * default already, leave initdir empty. */
+ }
+
+# ifdef FEAT_GUI
+ if (gui.in_use) /* when this changes, also adjust f_has()! */
+ {
+ if (filter == NULL
+# ifdef FEAT_EVAL
+ && (filter = get_var_value((char_u *)"b:browsefilter")) == NULL
+ && (filter = get_var_value((char_u *)"g:browsefilter")) == NULL
+# endif
+ )
+ filter = BROWSE_FILTER_DEFAULT;
+ if (flags & BROWSE_DIR)
+ {
+# if defined(FEAT_GUI_GTK) || defined(WIN3264)
+ /* For systems that have a directory dialog. */
+ fname = gui_mch_browsedir(title, initdir);
+# else
+ /* Generic solution for selecting a directory: select a file and
+ * remove the file name. */
+ fname = gui_mch_browse(0, title, dflt, ext, initdir, (char_u *)"");
+# endif
+# if !defined(FEAT_GUI_GTK)
+ /* Win32 adds a dummy file name, others return an arbitrary file
+ * name. GTK+ 2 returns only the directory, */
+ if (fname != NULL && *fname != NUL && !mch_isdir(fname))
+ {
+ /* Remove the file name. */
+ char_u *tail = gettail_sep(fname);
+
+ if (tail == fname)
+ *tail++ = '.'; /* use current dir */
+ *tail = NUL;
+ }
+# endif
+ }
+ else
+ fname = gui_mch_browse(flags & BROWSE_SAVE,
+ title, dflt, ext, initdir, (char_u *)_(filter));
+
+ /* We hang around in the dialog for a while, the user might do some
+ * things to our files. The Win32 dialog allows deleting or renaming
+ * a file, check timestamps. */
+ need_check_timestamps = TRUE;
+ did_check_timestamps = FALSE;
+ }
+ else
+# endif
+ {
+ /* TODO: non-GUI file selector here */
+ emsg(_("E338: Sorry, no file browser in console mode"));
+ fname = NULL;
+ }
+
+ /* keep the directory for next time */
+ if (fname != NULL)
+ {
+ vim_free(last_dir);
+ last_dir = vim_strsave(fname);
+ if (last_dir != NULL && !(flags & BROWSE_DIR))
+ {
+ *gettail(last_dir) = NUL;
+ if (*last_dir == NUL)
+ {
+ /* filename only returned, must be in current dir */
+ vim_free(last_dir);
+ last_dir = alloc(MAXPATHL);
+ if (last_dir != NULL)
+ mch_dirname(last_dir, MAXPATHL);
+ }
+ }
+ }
+
+ vim_free(tofree);
+ cmdmod.browse = save_browse;
+
+ return fname;
+}
+#endif
+
+#if defined(FEAT_EVAL)
+static char *e_printf = N_("E766: Insufficient arguments for printf()");
+
+/*
+ * Get number argument from "idxp" entry in "tvs". First entry is 1.
+ */
+ static varnumber_T
+tv_nr(typval_T *tvs, int *idxp)
+{
+ int idx = *idxp - 1;
+ varnumber_T n = 0;
+ int err = FALSE;
+
+ if (tvs[idx].v_type == VAR_UNKNOWN)
+ emsg(_(e_printf));
+ else
+ {
+ ++*idxp;
+ n = tv_get_number_chk(&tvs[idx], &err);
+ if (err)
+ n = 0;
+ }
+ return n;
+}
+
+/*
+ * Get string argument from "idxp" entry in "tvs". First entry is 1.
+ * If "tofree" is NULL tv_get_string_chk() is used. Some types (e.g. List)
+ * are not converted to a string.
+ * If "tofree" is not NULL echo_string() is used. All types are converted to
+ * a string with the same format as ":echo". The caller must free "*tofree".
+ * Returns NULL for an error.
+ */
+ static char *
+tv_str(typval_T *tvs, int *idxp, char_u **tofree)
+{
+ int idx = *idxp - 1;
+ char *s = NULL;
+ static char_u numbuf[NUMBUFLEN];
+
+ if (tvs[idx].v_type == VAR_UNKNOWN)
+ emsg(_(e_printf));
+ else
+ {
+ ++*idxp;
+ if (tofree != NULL)
+ s = (char *)echo_string(&tvs[idx], tofree, numbuf, get_copyID());
+ else
+ s = (char *)tv_get_string_chk(&tvs[idx]);
+ }
+ return s;
+}
+
+# ifdef FEAT_FLOAT
+/*
+ * Get float argument from "idxp" entry in "tvs". First entry is 1.
+ */
+ static double
+tv_float(typval_T *tvs, int *idxp)
+{
+ int idx = *idxp - 1;
+ double f = 0;
+
+ if (tvs[idx].v_type == VAR_UNKNOWN)
+ emsg(_(e_printf));
+ else
+ {
+ ++*idxp;
+ if (tvs[idx].v_type == VAR_FLOAT)
+ f = tvs[idx].vval.v_float;
+ else if (tvs[idx].v_type == VAR_NUMBER)
+ f = (double)tvs[idx].vval.v_number;
+ else
+ emsg(_("E807: Expected Float argument for printf()"));
+ }
+ return f;
+}
+# endif
+#endif
+
+#ifdef FEAT_FLOAT
+/*
+ * Return the representation of infinity for printf() function:
+ * "-inf", "inf", "+inf", " inf", "-INF", "INF", "+INF" or " INF".
+ */
+ static const char *
+infinity_str(int positive,
+ char fmt_spec,
+ int force_sign,
+ int space_for_positive)
+{
+ static const char *table[] =
+ {
+ "-inf", "inf", "+inf", " inf",
+ "-INF", "INF", "+INF", " INF"
+ };
+ int idx = positive * (1 + force_sign + force_sign * space_for_positive);
+
+ if (ASCII_ISUPPER(fmt_spec))
+ idx += 4;
+ return table[idx];
+}
+#endif
+
+/*
+ * This code was included to provide a portable vsnprintf() and snprintf().
+ * Some systems may provide their own, but we always use this one for
+ * consistency.
+ *
+ * This code is based on snprintf.c - a portable implementation of snprintf
+ * by Mark Martinec <mark.martinec@ijs.si>, Version 2.2, 2000-10-06.
+ * Included with permission. It was heavily modified to fit in Vim.
+ * The original code, including useful comments, can be found here:
+ * http://www.ijs.si/software/snprintf/
+ *
+ * This snprintf() only supports the following conversion specifiers:
+ * s, c, d, u, o, x, X, p (and synonyms: i, D, U, O - see below)
+ * with flags: '-', '+', ' ', '0' and '#'.
+ * An asterisk is supported for field width as well as precision.
+ *
+ * Limited support for floating point was added: 'f', 'F', 'e', 'E', 'g', 'G'.
+ *
+ * Length modifiers 'h' (short int) and 'l' (long int) and 'll' (long long int)
+ * are supported.
+ *
+ * The locale is not used, the string is used as a byte string. This is only
+ * relevant for double-byte encodings where the second byte may be '%'.
+ *
+ * It is permitted for "str_m" to be zero, and it is permitted to specify NULL
+ * pointer for resulting string argument if "str_m" is zero (as per ISO C99).
+ *
+ * The return value is the number of characters which would be generated
+ * for the given input, excluding the trailing NUL. If this value
+ * is greater or equal to "str_m", not all characters from the result
+ * have been stored in str, output bytes beyond the ("str_m"-1) -th character
+ * are discarded. If "str_m" is greater than zero it is guaranteed
+ * the resulting string will be NUL-terminated.
+ */
+
+/*
+ * When va_list is not supported we only define vim_snprintf().
+ *
+ * vim_vsnprintf_typval() can be invoked with either "va_list" or a list of
+ * "typval_T". When the latter is not used it must be NULL.
+ */
+
+/* When generating prototypes all of this is skipped, cproto doesn't
+ * understand this. */
+#ifndef PROTO
+
+/* Like vim_vsnprintf() but append to the string. */
+ int
+vim_snprintf_add(char *str, size_t str_m, const char *fmt, ...)
+{
+ va_list ap;
+ int str_l;
+ size_t len = STRLEN(str);
+ size_t space;
+
+ if (str_m <= len)
+ space = 0;
+ else
+ space = str_m - len;
+ va_start(ap, fmt);
+ str_l = vim_vsnprintf(str + len, space, fmt, ap);
+ va_end(ap);
+ return str_l;
+}
+
+ int
+vim_snprintf(char *str, size_t str_m, const char *fmt, ...)
+{
+ va_list ap;
+ int str_l;
+
+ va_start(ap, fmt);
+ str_l = vim_vsnprintf(str, str_m, fmt, ap);
+ va_end(ap);
+ return str_l;
+}
+
+ int
+vim_vsnprintf(
+ char *str,
+ size_t str_m,
+ const char *fmt,
+ va_list ap)
+{
+ return vim_vsnprintf_typval(str, str_m, fmt, ap, NULL);
+}
+
+ int
+vim_vsnprintf_typval(
+ char *str,
+ size_t str_m,
+ const char *fmt,
+ va_list ap,
+ typval_T *tvs)
+{
+ size_t str_l = 0;
+ const char *p = fmt;
+ int arg_idx = 1;
+
+ if (p == NULL)
+ p = "";
+ while (*p != NUL)
+ {
+ if (*p != '%')
+ {
+ char *q = strchr(p + 1, '%');
+ size_t n = (q == NULL) ? STRLEN(p) : (size_t)(q - p);
+
+ /* Copy up to the next '%' or NUL without any changes. */
+ if (str_l < str_m)
+ {
+ size_t avail = str_m - str_l;
+
+ mch_memmove(str + str_l, p, n > avail ? avail : n);
+ }
+ p += n;
+ str_l += n;
+ }
+ else
+ {
+ size_t min_field_width = 0, precision = 0;
+ int zero_padding = 0, precision_specified = 0, justify_left = 0;
+ int alternate_form = 0, force_sign = 0;
+
+ /* If both the ' ' and '+' flags appear, the ' ' flag should be
+ * ignored. */
+ int space_for_positive = 1;
+
+ /* allowed values: \0, h, l, L */
+ char length_modifier = '\0';
+
+ /* temporary buffer for simple numeric->string conversion */
+# if defined(FEAT_FLOAT)
+# define TMP_LEN 350 /* On my system 1e308 is the biggest number possible.
+ * That sounds reasonable to use as the maximum
+ * printable. */
+# elif defined(FEAT_NUM64)
+# define TMP_LEN 66
+# else
+# define TMP_LEN 34
+# endif
+ char tmp[TMP_LEN];
+
+ /* string address in case of string argument */
+ const char *str_arg = NULL;
+
+ /* natural field width of arg without padding and sign */
+ size_t str_arg_l;
+
+ /* unsigned char argument value - only defined for c conversion.
+ * N.B. standard explicitly states the char argument for the c
+ * conversion is unsigned */
+ unsigned char uchar_arg;
+
+ /* number of zeros to be inserted for numeric conversions as
+ * required by the precision or minimal field width */
+ size_t number_of_zeros_to_pad = 0;
+
+ /* index into tmp where zero padding is to be inserted */
+ size_t zero_padding_insertion_ind = 0;
+
+ /* current conversion specifier character */
+ char fmt_spec = '\0';
+
+ /* buffer for 's' and 'S' specs */
+ char_u *tofree = NULL;
+
+
+ p++; /* skip '%' */
+
+ /* parse flags */
+ while (*p == '0' || *p == '-' || *p == '+' || *p == ' '
+ || *p == '#' || *p == '\'')
+ {
+ switch (*p)
+ {
+ case '0': zero_padding = 1; break;
+ case '-': justify_left = 1; break;
+ case '+': force_sign = 1; space_for_positive = 0; break;
+ case ' ': force_sign = 1;
+ /* If both the ' ' and '+' flags appear, the ' '
+ * flag should be ignored */
+ break;
+ case '#': alternate_form = 1; break;
+ case '\'': break;
+ }
+ p++;
+ }
+ /* If the '0' and '-' flags both appear, the '0' flag should be
+ * ignored. */
+
+ /* parse field width */
+ if (*p == '*')
+ {
+ int j;
+
+ p++;
+ j =
+# if defined(FEAT_EVAL)
+ tvs != NULL ? tv_nr(tvs, &arg_idx) :
+# endif
+ va_arg(ap, int);
+ if (j >= 0)
+ min_field_width = j;
+ else
+ {
+ min_field_width = -j;
+ justify_left = 1;
+ }
+ }
+ else if (VIM_ISDIGIT((int)(*p)))
+ {
+ /* size_t could be wider than unsigned int; make sure we treat
+ * argument like common implementations do */
+ unsigned int uj = *p++ - '0';
+
+ while (VIM_ISDIGIT((int)(*p)))
+ uj = 10 * uj + (unsigned int)(*p++ - '0');
+ min_field_width = uj;
+ }
+
+ /* parse precision */
+ if (*p == '.')
+ {
+ p++;
+ precision_specified = 1;
+ if (*p == '*')
+ {
+ int j;
+
+ j =
+# if defined(FEAT_EVAL)
+ tvs != NULL ? tv_nr(tvs, &arg_idx) :
+# endif
+ va_arg(ap, int);
+ p++;
+ if (j >= 0)
+ precision = j;
+ else
+ {
+ precision_specified = 0;
+ precision = 0;
+ }
+ }
+ else if (VIM_ISDIGIT((int)(*p)))
+ {
+ /* size_t could be wider than unsigned int; make sure we
+ * treat argument like common implementations do */
+ unsigned int uj = *p++ - '0';
+
+ while (VIM_ISDIGIT((int)(*p)))
+ uj = 10 * uj + (unsigned int)(*p++ - '0');
+ precision = uj;
+ }
+ }
+
+ /* parse 'h', 'l' and 'll' length modifiers */
+ if (*p == 'h' || *p == 'l')
+ {
+ length_modifier = *p;
+ p++;
+ if (length_modifier == 'l' && *p == 'l')
+ {
+ /* double l = long long */
+# ifdef FEAT_NUM64
+ length_modifier = 'L';
+# else
+ length_modifier = 'l'; /* treat it as a single 'l' */
+# endif
+ p++;
+ }
+ }
+ fmt_spec = *p;
+
+ /* common synonyms: */
+ switch (fmt_spec)
+ {
+ case 'i': fmt_spec = 'd'; break;
+ case 'D': fmt_spec = 'd'; length_modifier = 'l'; break;
+ case 'U': fmt_spec = 'u'; length_modifier = 'l'; break;
+ case 'O': fmt_spec = 'o'; length_modifier = 'l'; break;
+ default: break;
+ }
+
+# if defined(FEAT_EVAL) && defined(FEAT_NUM64)
+ switch (fmt_spec)
+ {
+ case 'd': case 'u': case 'o': case 'x': case 'X':
+ if (tvs != NULL && length_modifier == '\0')
+ length_modifier = 'L';
+ }
+# endif
+
+ /* get parameter value, do initial processing */
+ switch (fmt_spec)
+ {
+ /* '%' and 'c' behave similar to 's' regarding flags and field
+ * widths */
+ case '%':
+ case 'c':
+ case 's':
+ case 'S':
+ length_modifier = '\0';
+ str_arg_l = 1;
+ switch (fmt_spec)
+ {
+ case '%':
+ str_arg = p;
+ break;
+
+ case 'c':
+ {
+ int j;
+
+ j =
+# if defined(FEAT_EVAL)
+ tvs != NULL ? tv_nr(tvs, &arg_idx) :
+# endif
+ va_arg(ap, int);
+ /* standard demands unsigned char */
+ uchar_arg = (unsigned char)j;
+ str_arg = (char *)&uchar_arg;
+ break;
+ }
+
+ case 's':
+ case 'S':
+ str_arg =
+# if defined(FEAT_EVAL)
+ tvs != NULL ? tv_str(tvs, &arg_idx, &tofree) :
+# endif
+ va_arg(ap, char *);
+ if (str_arg == NULL)
+ {
+ str_arg = "[NULL]";
+ str_arg_l = 6;
+ }
+ /* make sure not to address string beyond the specified
+ * precision !!! */
+ else if (!precision_specified)
+ str_arg_l = strlen(str_arg);
+ /* truncate string if necessary as requested by precision */
+ else if (precision == 0)
+ str_arg_l = 0;
+ else
+ {
+ /* Don't put the #if inside memchr(), it can be a
+ * macro. */
+ /* memchr on HP does not like n > 2^31 !!! */
+ char *q = memchr(str_arg, '\0',
+ precision <= (size_t)0x7fffffffL ? precision
+ : (size_t)0x7fffffffL);
+ str_arg_l = (q == NULL) ? precision
+ : (size_t)(q - str_arg);
+ }
+ if (fmt_spec == 'S')
+ {
+ if (min_field_width != 0)
+ min_field_width += STRLEN(str_arg)
+ - mb_string2cells((char_u *)str_arg, -1);
+ if (precision)
+ {
+ char_u *p1 = (char_u *)str_arg;
+ size_t i;
+
+ for (i = 0; i < precision && *p1; i++)
+ p1 += mb_ptr2len(p1);
+
+ str_arg_l = precision = p1 - (char_u *)str_arg;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case 'd': case 'u':
+ case 'b': case 'B':
+ case 'o':
+ case 'x': case 'X':
+ case 'p':
+ {
+ /* NOTE: the u, b, o, x, X and p conversion specifiers
+ * imply the value is unsigned; d implies a signed
+ * value */
+
+ /* 0 if numeric argument is zero (or if pointer is
+ * NULL for 'p'), +1 if greater than zero (or nonzero
+ * for unsigned arguments), -1 if negative (unsigned
+ * argument is never negative) */
+ int arg_sign = 0;
+
+ /* only defined for length modifier h, or for no
+ * length modifiers */
+ int int_arg = 0;
+ unsigned int uint_arg = 0;
+
+ /* only defined for length modifier l */
+ long int long_arg = 0;
+ unsigned long int ulong_arg = 0;
+
+# ifdef FEAT_NUM64
+ /* only defined for length modifier ll */
+ varnumber_T llong_arg = 0;
+ uvarnumber_T ullong_arg = 0;
+# endif
+
+ /* only defined for b conversion */
+ uvarnumber_T bin_arg = 0;
+
+ /* pointer argument value -only defined for p
+ * conversion */
+ void *ptr_arg = NULL;
+
+ if (fmt_spec == 'p')
+ {
+ length_modifier = '\0';
+ ptr_arg =
+# if defined(FEAT_EVAL)
+ tvs != NULL ? (void *)tv_str(tvs, &arg_idx,
+ NULL) :
+# endif
+ va_arg(ap, void *);
+ if (ptr_arg != NULL)
+ arg_sign = 1;
+ }
+ else if (fmt_spec == 'b' || fmt_spec == 'B')
+ {
+ bin_arg =
+# if defined(FEAT_EVAL)
+ tvs != NULL ?
+ (uvarnumber_T)tv_nr(tvs, &arg_idx) :
+# endif
+ va_arg(ap, uvarnumber_T);
+ if (bin_arg != 0)
+ arg_sign = 1;
+ }
+ else if (fmt_spec == 'd')
+ {
+ /* signed */
+ switch (length_modifier)
+ {
+ case '\0':
+ case 'h':
+ /* char and short arguments are passed as int. */
+ int_arg =
+# if defined(FEAT_EVAL)
+ tvs != NULL ? tv_nr(tvs, &arg_idx) :
+# endif
+ va_arg(ap, int);
+ if (int_arg > 0)
+ arg_sign = 1;
+ else if (int_arg < 0)
+ arg_sign = -1;
+ break;
+ case 'l':
+ long_arg =
+# if defined(FEAT_EVAL)
+ tvs != NULL ? tv_nr(tvs, &arg_idx) :
+# endif
+ va_arg(ap, long int);
+ if (long_arg > 0)
+ arg_sign = 1;
+ else if (long_arg < 0)
+ arg_sign = -1;
+ break;
+# ifdef FEAT_NUM64
+ case 'L':
+ llong_arg =
+# if defined(FEAT_EVAL)
+ tvs != NULL ? tv_nr(tvs, &arg_idx) :
+# endif
+ va_arg(ap, varnumber_T);
+ if (llong_arg > 0)
+ arg_sign = 1;
+ else if (llong_arg < 0)
+ arg_sign = -1;
+ break;
+# endif
+ }
+ }
+ else
+ {
+ /* unsigned */
+ switch (length_modifier)
+ {
+ case '\0':
+ case 'h':
+ uint_arg =
+# if defined(FEAT_EVAL)
+ tvs != NULL ? (unsigned)
+ tv_nr(tvs, &arg_idx) :
+# endif
+ va_arg(ap, unsigned int);
+ if (uint_arg != 0)
+ arg_sign = 1;
+ break;
+ case 'l':
+ ulong_arg =
+# if defined(FEAT_EVAL)
+ tvs != NULL ? (unsigned long)
+ tv_nr(tvs, &arg_idx) :
+# endif
+ va_arg(ap, unsigned long int);
+ if (ulong_arg != 0)
+ arg_sign = 1;
+ break;
+# ifdef FEAT_NUM64
+ case 'L':
+ ullong_arg =
+# if defined(FEAT_EVAL)
+ tvs != NULL ? (uvarnumber_T)
+ tv_nr(tvs, &arg_idx) :
+# endif
+ va_arg(ap, uvarnumber_T);
+ if (ullong_arg != 0)
+ arg_sign = 1;
+ break;
+# endif
+ }
+ }
+
+ str_arg = tmp;
+ str_arg_l = 0;
+
+ /* NOTE:
+ * For d, i, u, o, x, and X conversions, if precision is
+ * specified, the '0' flag should be ignored. This is so
+ * with Solaris 2.6, Digital UNIX 4.0, HPUX 10, Linux,
+ * FreeBSD, NetBSD; but not with Perl.
+ */
+ if (precision_specified)
+ zero_padding = 0;
+ if (fmt_spec == 'd')
+ {
+ if (force_sign && arg_sign >= 0)
+ tmp[str_arg_l++] = space_for_positive ? ' ' : '+';
+ /* leave negative numbers for sprintf to handle, to
+ * avoid handling tricky cases like (short int)-32768 */
+ }
+ else if (alternate_form)
+ {
+ if (arg_sign != 0
+ && (fmt_spec == 'b' || fmt_spec == 'B'
+ || fmt_spec == 'x' || fmt_spec == 'X') )
+ {
+ tmp[str_arg_l++] = '0';
+ tmp[str_arg_l++] = fmt_spec;
+ }
+ /* alternate form should have no effect for p
+ * conversion, but ... */
+ }
+
+ zero_padding_insertion_ind = str_arg_l;
+ if (!precision_specified)
+ precision = 1; /* default precision is 1 */
+ if (precision == 0 && arg_sign == 0)
+ {
+ /* When zero value is formatted with an explicit
+ * precision 0, the resulting formatted string is
+ * empty (d, i, u, b, B, o, x, X, p). */
+ }
+ else
+ {
+ char f[6];
+ int f_l = 0;
+
+ /* construct a simple format string for sprintf */
+ f[f_l++] = '%';
+ if (!length_modifier)
+ ;
+ else if (length_modifier == 'L')
+ {
+# ifdef FEAT_NUM64
+# ifdef WIN3264
+ f[f_l++] = 'I';
+ f[f_l++] = '6';
+ f[f_l++] = '4';
+# else
+ f[f_l++] = 'l';
+ f[f_l++] = 'l';
+# endif
+# else
+ f[f_l++] = 'l';
+# endif
+ }
+ else
+ f[f_l++] = length_modifier;
+ f[f_l++] = fmt_spec;
+ f[f_l++] = '\0';
+
+ if (fmt_spec == 'p')
+ str_arg_l += sprintf(tmp + str_arg_l, f, ptr_arg);
+ else if (fmt_spec == 'b' || fmt_spec == 'B')
+ {
+ char b[8 * sizeof(uvarnumber_T)];
+ size_t b_l = 0;
+ uvarnumber_T bn = bin_arg;
+
+ do
+ {
+ b[sizeof(b) - ++b_l] = '0' + (bn & 0x1);
+ bn >>= 1;
+ }
+ while (bn != 0);
+
+ memcpy(tmp + str_arg_l, b + sizeof(b) - b_l, b_l);
+ str_arg_l += b_l;
+ }
+ else if (fmt_spec == 'd')
+ {
+ /* signed */
+ switch (length_modifier)
+ {
+ case '\0':
+ case 'h': str_arg_l += sprintf(
+ tmp + str_arg_l, f, int_arg);
+ break;
+ case 'l': str_arg_l += sprintf(
+ tmp + str_arg_l, f, long_arg);
+ break;
+# ifdef FEAT_NUM64
+ case 'L': str_arg_l += sprintf(
+ tmp + str_arg_l, f, llong_arg);
+ break;
+# endif
+ }
+ }
+ else
+ {
+ /* unsigned */
+ switch (length_modifier)
+ {
+ case '\0':
+ case 'h': str_arg_l += sprintf(
+ tmp + str_arg_l, f, uint_arg);
+ break;
+ case 'l': str_arg_l += sprintf(
+ tmp + str_arg_l, f, ulong_arg);
+ break;
+# ifdef FEAT_NUM64
+ case 'L': str_arg_l += sprintf(
+ tmp + str_arg_l, f, ullong_arg);
+ break;
+# endif
+ }
+ }
+
+ /* include the optional minus sign and possible
+ * "0x" in the region before the zero padding
+ * insertion point */
+ if (zero_padding_insertion_ind < str_arg_l
+ && tmp[zero_padding_insertion_ind] == '-')
+ zero_padding_insertion_ind++;
+ if (zero_padding_insertion_ind + 1 < str_arg_l
+ && tmp[zero_padding_insertion_ind] == '0'
+ && (tmp[zero_padding_insertion_ind + 1] == 'x'
+ || tmp[zero_padding_insertion_ind + 1] == 'X'))
+ zero_padding_insertion_ind += 2;
+ }
+
+ {
+ size_t num_of_digits = str_arg_l
+ - zero_padding_insertion_ind;
+
+ if (alternate_form && fmt_spec == 'o'
+ /* unless zero is already the first
+ * character */
+ && !(zero_padding_insertion_ind < str_arg_l
+ && tmp[zero_padding_insertion_ind] == '0'))
+ {
+ /* assure leading zero for alternate-form
+ * octal numbers */
+ if (!precision_specified
+ || precision < num_of_digits + 1)
+ {
+ /* precision is increased to force the
+ * first character to be zero, except if a
+ * zero value is formatted with an
+ * explicit precision of zero */
+ precision = num_of_digits + 1;
+ precision_specified = 1;
+ }
+ }
+ /* zero padding to specified precision? */
+ if (num_of_digits < precision)
+ number_of_zeros_to_pad = precision - num_of_digits;
+ }
+ /* zero padding to specified minimal field width? */
+ if (!justify_left && zero_padding)
+ {
+ int n = (int)(min_field_width - (str_arg_l
+ + number_of_zeros_to_pad));
+ if (n > 0)
+ number_of_zeros_to_pad += n;
+ }
+ break;
+ }
+
+# ifdef FEAT_FLOAT
+ case 'f':
+ case 'F':
+ case 'e':
+ case 'E':
+ case 'g':
+ case 'G':
+ {
+ /* Floating point. */
+ double f;
+ double abs_f;
+ char format[40];
+ int l;
+ int remove_trailing_zeroes = FALSE;
+
+ f =
+# if defined(FEAT_EVAL)
+ tvs != NULL ? tv_float(tvs, &arg_idx) :
+# endif
+ va_arg(ap, double);
+ abs_f = f < 0 ? -f : f;
+
+ if (fmt_spec == 'g' || fmt_spec == 'G')
+ {
+ /* Would be nice to use %g directly, but it prints
+ * "1.0" as "1", we don't want that. */
+ if ((abs_f >= 0.001 && abs_f < 10000000.0)
+ || abs_f == 0.0)
+ fmt_spec = ASCII_ISUPPER(fmt_spec) ? 'F' : 'f';
+ else
+ fmt_spec = fmt_spec == 'g' ? 'e' : 'E';
+ remove_trailing_zeroes = TRUE;
+ }
+
+ if ((fmt_spec == 'f' || fmt_spec == 'F') &&
+# ifdef VAX
+ abs_f > 1.0e38
+# else
+ abs_f > 1.0e307
+# endif
+ )
+ {
+ /* Avoid a buffer overflow */
+ STRCPY(tmp, infinity_str(f > 0.0, fmt_spec,
+ force_sign, space_for_positive));
+ str_arg_l = STRLEN(tmp);
+ zero_padding = 0;
+ }
+ else
+ {
+ if (isnan(f))
+ {
+ /* Not a number: nan or NAN */
+ STRCPY(tmp, ASCII_ISUPPER(fmt_spec) ? "NAN"
+ : "nan");
+ str_arg_l = 3;
+ zero_padding = 0;
+ }
+ else if (isinf(f))
+ {
+ STRCPY(tmp, infinity_str(f > 0.0, fmt_spec,
+ force_sign, space_for_positive));
+ str_arg_l = STRLEN(tmp);
+ zero_padding = 0;
+ }
+ else
+ {
+ /* Regular float number */
+ format[0] = '%';
+ l = 1;
+ if (force_sign)
+ format[l++] = space_for_positive ? ' ' : '+';
+ if (precision_specified)
+ {
+ size_t max_prec = TMP_LEN - 10;
+
+ /* Make sure we don't get more digits than we
+ * have room for. */
+ if ((fmt_spec == 'f' || fmt_spec == 'F')
+ && abs_f > 1.0)
+ max_prec -= (size_t)log10(abs_f);
+ if (precision > max_prec)
+ precision = max_prec;
+ l += sprintf(format + l, ".%d", (int)precision);
+ }
+ format[l] = fmt_spec == 'F' ? 'f' : fmt_spec;
+ format[l + 1] = NUL;
+
+ str_arg_l = sprintf(tmp, format, f);
+ }
+
+ if (remove_trailing_zeroes)
+ {
+ int i;
+ char *tp;
+
+ /* Using %g or %G: remove superfluous zeroes. */
+ if (fmt_spec == 'f' || fmt_spec == 'F')
+ tp = tmp + str_arg_l - 1;
+ else
+ {
+ tp = (char *)vim_strchr((char_u *)tmp,
+ fmt_spec == 'e' ? 'e' : 'E');
+ if (tp != NULL)
+ {
+ /* Remove superfluous '+' and leading
+ * zeroes from the exponent. */
+ if (tp[1] == '+')
+ {
+ /* Change "1.0e+07" to "1.0e07" */
+ STRMOVE(tp + 1, tp + 2);
+ --str_arg_l;
+ }
+ i = (tp[1] == '-') ? 2 : 1;
+ while (tp[i] == '0')
+ {
+ /* Change "1.0e07" to "1.0e7" */
+ STRMOVE(tp + i, tp + i + 1);
+ --str_arg_l;
+ }
+ --tp;
+ }
+ }
+
+ if (tp != NULL && !precision_specified)
+ /* Remove trailing zeroes, but keep the one
+ * just after a dot. */
+ while (tp > tmp + 2 && *tp == '0'
+ && tp[-1] != '.')
+ {
+ STRMOVE(tp, tp + 1);
+ --tp;
+ --str_arg_l;
+ }
+ }
+ else
+ {
+ char *tp;
+
+ /* Be consistent: some printf("%e") use 1.0e+12
+ * and some 1.0e+012. Remove one zero in the last
+ * case. */
+ tp = (char *)vim_strchr((char_u *)tmp,
+ fmt_spec == 'e' ? 'e' : 'E');
+ if (tp != NULL && (tp[1] == '+' || tp[1] == '-')
+ && tp[2] == '0'
+ && vim_isdigit(tp[3])
+ && vim_isdigit(tp[4]))
+ {
+ STRMOVE(tp + 2, tp + 3);
+ --str_arg_l;
+ }
+ }
+ }
+ if (zero_padding && min_field_width > str_arg_l
+ && (tmp[0] == '-' || force_sign))
+ {
+ /* padding 0's should be inserted after the sign */
+ number_of_zeros_to_pad = min_field_width - str_arg_l;
+ zero_padding_insertion_ind = 1;
+ }
+ str_arg = tmp;
+ break;
+ }
+# endif
+
+ default:
+ /* unrecognized conversion specifier, keep format string
+ * as-is */
+ zero_padding = 0; /* turn zero padding off for non-numeric
+ conversion */
+ justify_left = 1;
+ min_field_width = 0; /* reset flags */
+
+ /* discard the unrecognized conversion, just keep *
+ * the unrecognized conversion character */
+ str_arg = p;
+ str_arg_l = 0;
+ if (*p != NUL)
+ str_arg_l++; /* include invalid conversion specifier
+ unchanged if not at end-of-string */
+ break;
+ }
+
+ if (*p != NUL)
+ p++; /* step over the just processed conversion specifier */
+
+ /* insert padding to the left as requested by min_field_width;
+ * this does not include the zero padding in case of numerical
+ * conversions*/
+ if (!justify_left)
+ {
+ /* left padding with blank or zero */
+ int pn = (int)(min_field_width - (str_arg_l + number_of_zeros_to_pad));
+
+ if (pn > 0)
+ {
+ if (str_l < str_m)
+ {
+ size_t avail = str_m - str_l;
+
+ vim_memset(str + str_l, zero_padding ? '0' : ' ',
+ (size_t)pn > avail ? avail
+ : (size_t)pn);
+ }
+ str_l += pn;
+ }
+ }
+
+ /* zero padding as requested by the precision or by the minimal
+ * field width for numeric conversions required? */
+ if (number_of_zeros_to_pad == 0)
+ {
+ /* will not copy first part of numeric right now, *
+ * force it to be copied later in its entirety */
+ zero_padding_insertion_ind = 0;
+ }
+ else
+ {
+ /* insert first part of numerics (sign or '0x') before zero
+ * padding */
+ int zn = (int)zero_padding_insertion_ind;
+
+ if (zn > 0)
+ {
+ if (str_l < str_m)
+ {
+ size_t avail = str_m - str_l;
+
+ mch_memmove(str + str_l, str_arg,
+ (size_t)zn > avail ? avail
+ : (size_t)zn);
+ }
+ str_l += zn;
+ }
+
+ /* insert zero padding as requested by the precision or min
+ * field width */
+ zn = (int)number_of_zeros_to_pad;
+ if (zn > 0)
+ {
+ if (str_l < str_m)
+ {
+ size_t avail = str_m - str_l;
+
+ vim_memset(str + str_l, '0',
+ (size_t)zn > avail ? avail
+ : (size_t)zn);
+ }
+ str_l += zn;
+ }
+ }
+
+ /* insert formatted string
+ * (or as-is conversion specifier for unknown conversions) */
+ {
+ int sn = (int)(str_arg_l - zero_padding_insertion_ind);
+
+ if (sn > 0)
+ {
+ if (str_l < str_m)
+ {
+ size_t avail = str_m - str_l;
+
+ mch_memmove(str + str_l,
+ str_arg + zero_padding_insertion_ind,
+ (size_t)sn > avail ? avail : (size_t)sn);
+ }
+ str_l += sn;
+ }
+ }
+
+ /* insert right padding */
+ if (justify_left)
+ {
+ /* right blank padding to the field width */
+ int pn = (int)(min_field_width
+ - (str_arg_l + number_of_zeros_to_pad));
+
+ if (pn > 0)
+ {
+ if (str_l < str_m)
+ {
+ size_t avail = str_m - str_l;
+
+ vim_memset(str + str_l, ' ',
+ (size_t)pn > avail ? avail
+ : (size_t)pn);
+ }
+ str_l += pn;
+ }
+ }
+ vim_free(tofree);
+ }
+ }
+
+ if (str_m > 0)
+ {
+ /* make sure the string is nul-terminated even at the expense of
+ * overwriting the last character (shouldn't happen, but just in case)
+ * */
+ str[str_l <= str_m - 1 ? str_l : str_m - 1] = '\0';
+ }
+
+ if (tvs != NULL && tvs[arg_idx - 1].v_type != VAR_UNKNOWN)
+ emsg(_("E767: Too many arguments to printf()"));
+
+ /* Return the number of characters formatted (excluding trailing nul
+ * character), that is, the number of characters that would have been
+ * written to the buffer if it were large enough. */
+ return (int)str_l;
+}
+
+#endif /* PROTO */
diff --git a/src/message_test.c b/src/message_test.c
new file mode 100644
index 0000000..55ca814
--- /dev/null
+++ b/src/message_test.c
@@ -0,0 +1,107 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * message_test.c: Unittests for message.c
+ */
+
+#undef NDEBUG
+#include <assert.h>
+
+/* Must include main.c because it contains much more than just main() */
+#define NO_VIM_MAIN
+#include "main.c"
+
+/* This file has to be included because some of the tested functions are
+ * static. */
+#include "message.c"
+
+/*
+ * Test trunc_string().
+ */
+ static void
+test_trunc_string(void)
+{
+ char_u *buf; /*allocated every time to find uninit errors */
+ char_u *s;
+
+ /* in place */
+ buf = alloc(40);
+ STRCPY(buf, "text");
+ trunc_string(buf, buf, 20, 40);
+ assert(STRCMP(buf, "text") == 0);
+ vim_free(buf);
+
+ buf = alloc(40);
+ STRCPY(buf, "a short text");
+ trunc_string(buf, buf, 20, 40);
+ assert(STRCMP(buf, "a short text") == 0);
+ vim_free(buf);
+
+ buf = alloc(40);
+ STRCPY(buf, "a text tha just fits");
+ trunc_string(buf, buf, 20, 40);
+ assert(STRCMP(buf, "a text tha just fits") == 0);
+ vim_free(buf);
+
+ buf = alloc(40);
+ STRCPY(buf, "a text that nott fits");
+ trunc_string(buf, buf, 20, 40);
+ assert(STRCMP(buf, "a text t...nott fits") == 0);
+ vim_free(buf);
+
+ /* copy from string to buf */
+ buf = alloc(40);
+ s = vim_strsave((char_u *)"text");
+ trunc_string(s, buf, 20, 40);
+ assert(STRCMP(buf, "text") == 0);
+ vim_free(buf);
+ vim_free(s);
+
+ buf = alloc(40);
+ s = vim_strsave((char_u *)"a text that fits");
+ trunc_string(s, buf, 34, 40);
+ assert(STRCMP(buf, "a text that fits") == 0);
+ vim_free(buf);
+ vim_free(s);
+
+ buf = alloc(40);
+ s = vim_strsave((char_u *)"a short text");
+ trunc_string(s, buf, 20, 40);
+ assert(STRCMP(buf, "a short text") == 0);
+ vim_free(buf);
+ vim_free(s);
+
+ buf = alloc(40);
+ s = vim_strsave((char_u *)"a text tha just fits");
+ trunc_string(s, buf, 20, 40);
+ assert(STRCMP(buf, "a text tha just fits") == 0);
+ vim_free(buf);
+ vim_free(s);
+
+ buf = alloc(40);
+ s = vim_strsave((char_u *)"a text that nott fits");
+ trunc_string(s, buf, 20, 40);
+ assert(STRCMP(buf, "a text t...nott fits") == 0);
+ vim_free(buf);
+ vim_free(s);
+}
+
+ int
+main(int argc, char **argv)
+{
+ vim_memset(&params, 0, sizeof(params));
+ params.argc = argc;
+ params.argv = argv;
+ common_init(&params);
+ init_chartab();
+
+ test_trunc_string();
+ return 0;
+}
diff --git a/src/misc1.c b/src/misc1.c
new file mode 100644
index 0000000..26b570b
--- /dev/null
+++ b/src/misc1.c
@@ -0,0 +1,7122 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * misc1.c: functions that didn't seem to fit elsewhere
+ */
+
+#include "vim.h"
+#include "version.h"
+
+#if defined(FEAT_CMDL_COMPL) && defined(WIN3264)
+# include <lm.h>
+#endif
+
+static char_u *vim_version_dir(char_u *vimdir);
+static char_u *remove_tail(char_u *p, char_u *pend, char_u *name);
+
+/* All user names (for ~user completion as done by shell). */
+#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
+static garray_T ga_users;
+#endif
+
+/*
+ * Count the size (in window cells) of the indent in the current line.
+ */
+ int
+get_indent(void)
+{
+#ifdef FEAT_VARTABS
+ return get_indent_str_vtab(ml_get_curline(), (int)curbuf->b_p_ts,
+ curbuf->b_p_vts_array, FALSE);
+#else
+ return get_indent_str(ml_get_curline(), (int)curbuf->b_p_ts, FALSE);
+#endif
+}
+
+/*
+ * Count the size (in window cells) of the indent in line "lnum".
+ */
+ int
+get_indent_lnum(linenr_T lnum)
+{
+#ifdef FEAT_VARTABS
+ return get_indent_str_vtab(ml_get(lnum), (int)curbuf->b_p_ts,
+ curbuf->b_p_vts_array, FALSE);
+#else
+ return get_indent_str(ml_get(lnum), (int)curbuf->b_p_ts, FALSE);
+#endif
+}
+
+#if defined(FEAT_FOLDING) || defined(PROTO)
+/*
+ * Count the size (in window cells) of the indent in line "lnum" of buffer
+ * "buf".
+ */
+ int
+get_indent_buf(buf_T *buf, linenr_T lnum)
+{
+#ifdef FEAT_VARTABS
+ return get_indent_str_vtab(ml_get_buf(buf, lnum, FALSE),
+ (int)curbuf->b_p_ts, buf->b_p_vts_array, FALSE);
+#else
+ return get_indent_str(ml_get_buf(buf, lnum, FALSE), (int)buf->b_p_ts, FALSE);
+#endif
+}
+#endif
+
+/*
+ * count the size (in window cells) of the indent in line "ptr", with
+ * 'tabstop' at "ts"
+ */
+ int
+get_indent_str(
+ char_u *ptr,
+ int ts,
+ int list) /* if TRUE, count only screen size for tabs */
+{
+ int count = 0;
+
+ for ( ; *ptr; ++ptr)
+ {
+ if (*ptr == TAB)
+ {
+ if (!list || lcs_tab1) /* count a tab for what it is worth */
+ count += ts - (count % ts);
+ else
+ /* In list mode, when tab is not set, count screen char width
+ * for Tab, displays: ^I */
+ count += ptr2cells(ptr);
+ }
+ else if (*ptr == ' ')
+ ++count; /* count a space for one */
+ else
+ break;
+ }
+ return count;
+}
+
+#ifdef FEAT_VARTABS
+/*
+ * Count the size (in window cells) of the indent in line "ptr", using
+ * variable tabstops.
+ * if "list" is TRUE, count only screen size for tabs.
+ */
+ int
+get_indent_str_vtab(char_u *ptr, int ts, int *vts, int list)
+{
+ int count = 0;
+
+ for ( ; *ptr; ++ptr)
+ {
+ if (*ptr == TAB) /* count a tab for what it is worth */
+ {
+ if (!list || lcs_tab1)
+ count += tabstop_padding(count, ts, vts);
+ else
+ /* In list mode, when tab is not set, count screen char width
+ * for Tab, displays: ^I */
+ count += ptr2cells(ptr);
+ }
+ else if (*ptr == ' ')
+ ++count; /* count a space for one */
+ else
+ break;
+ }
+ return count;
+}
+#endif
+
+/*
+ * Set the indent of the current line.
+ * Leaves the cursor on the first non-blank in the line.
+ * Caller must take care of undo.
+ * "flags":
+ * SIN_CHANGED: call changed_bytes() if the line was changed.
+ * SIN_INSERT: insert the indent in front of the line.
+ * SIN_UNDO: save line for undo before changing it.
+ * Returns TRUE if the line was changed.
+ */
+ int
+set_indent(
+ int size, /* measured in spaces */
+ int flags)
+{
+ char_u *p;
+ char_u *newline;
+ char_u *oldline;
+ char_u *s;
+ int todo;
+ int ind_len; /* measured in characters */
+ int line_len;
+ int doit = FALSE;
+ int ind_done = 0; /* measured in spaces */
+#ifdef FEAT_VARTABS
+ int ind_col = 0;
+#endif
+ int tab_pad;
+ int retval = FALSE;
+ int orig_char_len = -1; /* number of initial whitespace chars when
+ 'et' and 'pi' are both set */
+
+ /*
+ * First check if there is anything to do and compute the number of
+ * characters needed for the indent.
+ */
+ todo = size;
+ ind_len = 0;
+ p = oldline = ml_get_curline();
+
+ /* Calculate the buffer size for the new indent, and check to see if it
+ * isn't already set */
+
+ /* if 'expandtab' isn't set: use TABs; if both 'expandtab' and
+ * 'preserveindent' are set count the number of characters at the
+ * beginning of the line to be copied */
+ if (!curbuf->b_p_et || (!(flags & SIN_INSERT) && curbuf->b_p_pi))
+ {
+ /* If 'preserveindent' is set then reuse as much as possible of
+ * the existing indent structure for the new indent */
+ if (!(flags & SIN_INSERT) && curbuf->b_p_pi)
+ {
+ ind_done = 0;
+
+ /* count as many characters as we can use */
+ while (todo > 0 && VIM_ISWHITE(*p))
+ {
+ if (*p == TAB)
+ {
+#ifdef FEAT_VARTABS
+ tab_pad = tabstop_padding(ind_done, curbuf->b_p_ts,
+ curbuf->b_p_vts_array);
+#else
+ tab_pad = (int)curbuf->b_p_ts
+ - (ind_done % (int)curbuf->b_p_ts);
+#endif
+ /* stop if this tab will overshoot the target */
+ if (todo < tab_pad)
+ break;
+ todo -= tab_pad;
+ ++ind_len;
+ ind_done += tab_pad;
+ }
+ else
+ {
+ --todo;
+ ++ind_len;
+ ++ind_done;
+ }
+ ++p;
+ }
+
+#ifdef FEAT_VARTABS
+ /* These diverge from this point. */
+ ind_col = ind_done;
+#endif
+ /* Set initial number of whitespace chars to copy if we are
+ * preserving indent but expandtab is set */
+ if (curbuf->b_p_et)
+ orig_char_len = ind_len;
+
+ /* Fill to next tabstop with a tab, if possible */
+#ifdef FEAT_VARTABS
+ tab_pad = tabstop_padding(ind_done, curbuf->b_p_ts,
+ curbuf->b_p_vts_array);
+#else
+ tab_pad = (int)curbuf->b_p_ts - (ind_done % (int)curbuf->b_p_ts);
+#endif
+ if (todo >= tab_pad && orig_char_len == -1)
+ {
+ doit = TRUE;
+ todo -= tab_pad;
+ ++ind_len;
+ /* ind_done += tab_pad; */
+#ifdef FEAT_VARTABS
+ ind_col += tab_pad;
+#endif
+ }
+ }
+
+ /* count tabs required for indent */
+#ifdef FEAT_VARTABS
+ for (;;)
+ {
+ tab_pad = tabstop_padding(ind_col, curbuf->b_p_ts,
+ curbuf->b_p_vts_array);
+ if (todo < tab_pad)
+ break;
+ if (*p != TAB)
+ doit = TRUE;
+ else
+ ++p;
+ todo -= tab_pad;
+ ++ind_len;
+ ind_col += tab_pad;
+ }
+#else
+ while (todo >= (int)curbuf->b_p_ts)
+ {
+ if (*p != TAB)
+ doit = TRUE;
+ else
+ ++p;
+ todo -= (int)curbuf->b_p_ts;
+ ++ind_len;
+ /* ind_done += (int)curbuf->b_p_ts; */
+ }
+#endif
+ }
+ /* count spaces required for indent */
+ while (todo > 0)
+ {
+ if (*p != ' ')
+ doit = TRUE;
+ else
+ ++p;
+ --todo;
+ ++ind_len;
+ /* ++ind_done; */
+ }
+
+ /* Return if the indent is OK already. */
+ if (!doit && !VIM_ISWHITE(*p) && !(flags & SIN_INSERT))
+ return FALSE;
+
+ /* Allocate memory for the new line. */
+ if (flags & SIN_INSERT)
+ p = oldline;
+ else
+ p = skipwhite(p);
+ line_len = (int)STRLEN(p) + 1;
+
+ /* If 'preserveindent' and 'expandtab' are both set keep the original
+ * characters and allocate accordingly. We will fill the rest with spaces
+ * after the if (!curbuf->b_p_et) below. */
+ if (orig_char_len != -1)
+ {
+ newline = alloc(orig_char_len + size - ind_done + line_len);
+ if (newline == NULL)
+ return FALSE;
+ todo = size - ind_done;
+ ind_len = orig_char_len + todo; /* Set total length of indent in
+ * characters, which may have been
+ * undercounted until now */
+ p = oldline;
+ s = newline;
+ while (orig_char_len > 0)
+ {
+ *s++ = *p++;
+ orig_char_len--;
+ }
+
+ /* Skip over any additional white space (useful when newindent is less
+ * than old) */
+ while (VIM_ISWHITE(*p))
+ ++p;
+
+ }
+ else
+ {
+ todo = size;
+ newline = alloc(ind_len + line_len);
+ if (newline == NULL)
+ return FALSE;
+ s = newline;
+ }
+
+ /* Put the characters in the new line. */
+ /* if 'expandtab' isn't set: use TABs */
+ if (!curbuf->b_p_et)
+ {
+ /* If 'preserveindent' is set then reuse as much as possible of
+ * the existing indent structure for the new indent */
+ if (!(flags & SIN_INSERT) && curbuf->b_p_pi)
+ {
+ p = oldline;
+ ind_done = 0;
+
+ while (todo > 0 && VIM_ISWHITE(*p))
+ {
+ if (*p == TAB)
+ {
+#ifdef FEAT_VARTABS
+ tab_pad = tabstop_padding(ind_done, curbuf->b_p_ts,
+ curbuf->b_p_vts_array);
+#else
+ tab_pad = (int)curbuf->b_p_ts
+ - (ind_done % (int)curbuf->b_p_ts);
+#endif
+ /* stop if this tab will overshoot the target */
+ if (todo < tab_pad)
+ break;
+ todo -= tab_pad;
+ ind_done += tab_pad;
+ }
+ else
+ {
+ --todo;
+ ++ind_done;
+ }
+ *s++ = *p++;
+ }
+
+ /* Fill to next tabstop with a tab, if possible */
+#ifdef FEAT_VARTABS
+ tab_pad = tabstop_padding(ind_done, curbuf->b_p_ts,
+ curbuf->b_p_vts_array);
+#else
+ tab_pad = (int)curbuf->b_p_ts - (ind_done % (int)curbuf->b_p_ts);
+#endif
+ if (todo >= tab_pad)
+ {
+ *s++ = TAB;
+ todo -= tab_pad;
+#ifdef FEAT_VARTABS
+ ind_done += tab_pad;
+#endif
+ }
+
+ p = skipwhite(p);
+ }
+
+#ifdef FEAT_VARTABS
+ for (;;)
+ {
+ tab_pad = tabstop_padding(ind_done, curbuf->b_p_ts,
+ curbuf->b_p_vts_array);
+ if (todo < tab_pad)
+ break;
+ *s++ = TAB;
+ todo -= tab_pad;
+ ind_done += tab_pad;
+ }
+#else
+ while (todo >= (int)curbuf->b_p_ts)
+ {
+ *s++ = TAB;
+ todo -= (int)curbuf->b_p_ts;
+ }
+#endif
+ }
+ while (todo > 0)
+ {
+ *s++ = ' ';
+ --todo;
+ }
+ mch_memmove(s, p, (size_t)line_len);
+
+ // Replace the line (unless undo fails).
+ if (!(flags & SIN_UNDO) || u_savesub(curwin->w_cursor.lnum) == OK)
+ {
+ ml_replace(curwin->w_cursor.lnum, newline, FALSE);
+ if (flags & SIN_CHANGED)
+ changed_bytes(curwin->w_cursor.lnum, 0);
+
+ // Correct saved cursor position if it is in this line.
+ if (saved_cursor.lnum == curwin->w_cursor.lnum)
+ {
+ if (saved_cursor.col >= (colnr_T)(p - oldline))
+ // cursor was after the indent, adjust for the number of
+ // bytes added/removed
+ saved_cursor.col += ind_len - (colnr_T)(p - oldline);
+ else if (saved_cursor.col >= (colnr_T)(s - newline))
+ // cursor was in the indent, and is now after it, put it back
+ // at the start of the indent (replacing spaces with TAB)
+ saved_cursor.col = (colnr_T)(s - newline);
+ }
+#ifdef FEAT_TEXT_PROP
+ adjust_prop_columns(curwin->w_cursor.lnum, (colnr_T)(p - oldline),
+ ind_len - (colnr_T)(p - oldline));
+#endif
+ retval = TRUE;
+ }
+ else
+ vim_free(newline);
+
+ curwin->w_cursor.col = ind_len;
+ return retval;
+}
+
+/*
+ * Copy the indent from ptr to the current line (and fill to size)
+ * Leaves the cursor on the first non-blank in the line.
+ * Returns TRUE if the line was changed.
+ */
+ static int
+copy_indent(int size, char_u *src)
+{
+ char_u *p = NULL;
+ char_u *line = NULL;
+ char_u *s;
+ int todo;
+ int ind_len;
+ int line_len = 0;
+ int tab_pad;
+ int ind_done;
+ int round;
+#ifdef FEAT_VARTABS
+ int ind_col;
+#endif
+
+ /* Round 1: compute the number of characters needed for the indent
+ * Round 2: copy the characters. */
+ for (round = 1; round <= 2; ++round)
+ {
+ todo = size;
+ ind_len = 0;
+ ind_done = 0;
+#ifdef FEAT_VARTABS
+ ind_col = 0;
+#endif
+ s = src;
+
+ /* Count/copy the usable portion of the source line */
+ while (todo > 0 && VIM_ISWHITE(*s))
+ {
+ if (*s == TAB)
+ {
+#ifdef FEAT_VARTABS
+ tab_pad = tabstop_padding(ind_done, curbuf->b_p_ts,
+ curbuf->b_p_vts_array);
+#else
+ tab_pad = (int)curbuf->b_p_ts
+ - (ind_done % (int)curbuf->b_p_ts);
+#endif
+ /* Stop if this tab will overshoot the target */
+ if (todo < tab_pad)
+ break;
+ todo -= tab_pad;
+ ind_done += tab_pad;
+#ifdef FEAT_VARTABS
+ ind_col += tab_pad;
+#endif
+ }
+ else
+ {
+ --todo;
+ ++ind_done;
+#ifdef FEAT_VARTABS
+ ++ind_col;
+#endif
+ }
+ ++ind_len;
+ if (p != NULL)
+ *p++ = *s;
+ ++s;
+ }
+
+ /* Fill to next tabstop with a tab, if possible */
+#ifdef FEAT_VARTABS
+ tab_pad = tabstop_padding(ind_done, curbuf->b_p_ts,
+ curbuf->b_p_vts_array);
+#else
+ tab_pad = (int)curbuf->b_p_ts - (ind_done % (int)curbuf->b_p_ts);
+#endif
+ if (todo >= tab_pad && !curbuf->b_p_et)
+ {
+ todo -= tab_pad;
+ ++ind_len;
+#ifdef FEAT_VARTABS
+ ind_col += tab_pad;
+#endif
+ if (p != NULL)
+ *p++ = TAB;
+ }
+
+ /* Add tabs required for indent */
+ if (!curbuf->b_p_et)
+ {
+#ifdef FEAT_VARTABS
+ for (;;)
+ {
+ tab_pad = tabstop_padding(ind_col, curbuf->b_p_ts,
+ curbuf->b_p_vts_array);
+ if (todo < tab_pad)
+ break;
+ todo -= tab_pad;
+ ++ind_len;
+ ind_col += tab_pad;
+ if (p != NULL)
+ *p++ = TAB;
+ }
+#else
+ while (todo >= (int)curbuf->b_p_ts)
+ {
+ todo -= (int)curbuf->b_p_ts;
+ ++ind_len;
+ if (p != NULL)
+ *p++ = TAB;
+ }
+#endif
+ }
+
+ /* Count/add spaces required for indent */
+ while (todo > 0)
+ {
+ --todo;
+ ++ind_len;
+ if (p != NULL)
+ *p++ = ' ';
+ }
+
+ if (p == NULL)
+ {
+ /* Allocate memory for the result: the copied indent, new indent
+ * and the rest of the line. */
+ line_len = (int)STRLEN(ml_get_curline()) + 1;
+ line = alloc(ind_len + line_len);
+ if (line == NULL)
+ return FALSE;
+ p = line;
+ }
+ }
+
+ /* Append the original line */
+ mch_memmove(p, ml_get_curline(), (size_t)line_len);
+
+ /* Replace the line */
+ ml_replace(curwin->w_cursor.lnum, line, FALSE);
+
+ /* Put the cursor after the indent. */
+ curwin->w_cursor.col = ind_len;
+ return TRUE;
+}
+
+/*
+ * Return the indent of the current line after a number. Return -1 if no
+ * number was found. Used for 'n' in 'formatoptions': numbered list.
+ * Since a pattern is used it can actually handle more than numbers.
+ */
+ int
+get_number_indent(linenr_T lnum)
+{
+ colnr_T col;
+ pos_T pos;
+
+ regmatch_T regmatch;
+ int lead_len = 0; /* length of comment leader */
+
+ if (lnum > curbuf->b_ml.ml_line_count)
+ return -1;
+ pos.lnum = 0;
+
+#ifdef FEAT_COMMENTS
+ /* In format_lines() (i.e. not insert mode), fo+=q is needed too... */
+ if ((State & INSERT) || has_format_option(FO_Q_COMS))
+ lead_len = get_leader_len(ml_get(lnum), NULL, FALSE, TRUE);
+#endif
+ regmatch.regprog = vim_regcomp(curbuf->b_p_flp, RE_MAGIC);
+ if (regmatch.regprog != NULL)
+ {
+ regmatch.rm_ic = FALSE;
+
+ /* vim_regexec() expects a pointer to a line. This lets us
+ * start matching for the flp beyond any comment leader... */
+ if (vim_regexec(&regmatch, ml_get(lnum) + lead_len, (colnr_T)0))
+ {
+ pos.lnum = lnum;
+ pos.col = (colnr_T)(*regmatch.endp - ml_get(lnum));
+ pos.coladd = 0;
+ }
+ vim_regfree(regmatch.regprog);
+ }
+
+ if (pos.lnum == 0 || *ml_get_pos(&pos) == NUL)
+ return -1;
+ getvcol(curwin, &pos, &col, NULL, NULL);
+ return (int)col;
+}
+
+#if defined(FEAT_LINEBREAK) || defined(PROTO)
+/*
+ * Return appropriate space number for breakindent, taking influencing
+ * parameters into account. Window must be specified, since it is not
+ * necessarily always the current one.
+ */
+ int
+get_breakindent_win(
+ win_T *wp,
+ char_u *line) /* start of the line */
+{
+ static int prev_indent = 0; /* cached indent value */
+ static long prev_ts = 0L; /* cached tabstop value */
+ static char_u *prev_line = NULL; /* cached pointer to line */
+ static varnumber_T prev_tick = 0; /* changedtick of cached value */
+#ifdef FEAT_VARTABS
+ static int *prev_vts = NULL; /* cached vartabs values */
+#endif
+ int bri = 0;
+ /* window width minus window margin space, i.e. what rests for text */
+ const int eff_wwidth = wp->w_width
+ - ((wp->w_p_nu || wp->w_p_rnu)
+ && (vim_strchr(p_cpo, CPO_NUMCOL) == NULL)
+ ? number_width(wp) + 1 : 0);
+
+ /* used cached indent, unless pointer or 'tabstop' changed */
+ if (prev_line != line || prev_ts != wp->w_buffer->b_p_ts
+ || prev_tick != CHANGEDTICK(wp->w_buffer)
+#ifdef FEAT_VARTABS
+ || prev_vts != wp->w_buffer->b_p_vts_array
+#endif
+ )
+ {
+ prev_line = line;
+ prev_ts = wp->w_buffer->b_p_ts;
+ prev_tick = CHANGEDTICK(wp->w_buffer);
+#ifdef FEAT_VARTABS
+ prev_vts = wp->w_buffer->b_p_vts_array;
+ prev_indent = get_indent_str_vtab(line,
+ (int)wp->w_buffer->b_p_ts,
+ wp->w_buffer->b_p_vts_array, wp->w_p_list);
+#else
+ prev_indent = get_indent_str(line,
+ (int)wp->w_buffer->b_p_ts, wp->w_p_list);
+#endif
+ }
+ bri = prev_indent + wp->w_p_brishift;
+
+ /* indent minus the length of the showbreak string */
+ if (wp->w_p_brisbr)
+ bri -= vim_strsize(p_sbr);
+
+ /* Add offset for number column, if 'n' is in 'cpoptions' */
+ bri += win_col_off2(wp);
+
+ /* never indent past left window margin */
+ if (bri < 0)
+ bri = 0;
+ /* always leave at least bri_min characters on the left,
+ * if text width is sufficient */
+ else if (bri > eff_wwidth - wp->w_p_brimin)
+ bri = (eff_wwidth - wp->w_p_brimin < 0)
+ ? 0 : eff_wwidth - wp->w_p_brimin;
+
+ return bri;
+}
+#endif
+
+
+/*
+ * open_line: Add a new line below or above the current line.
+ *
+ * For VREPLACE mode, we only add a new line when we get to the end of the
+ * file, otherwise we just start replacing the next line.
+ *
+ * Caller must take care of undo. Since VREPLACE may affect any number of
+ * lines however, it may call u_save_cursor() again when starting to change a
+ * new line.
+ * "flags": OPENLINE_DELSPACES delete spaces after cursor
+ * OPENLINE_DO_COM format comments
+ * OPENLINE_KEEPTRAIL keep trailing spaces
+ * OPENLINE_MARKFIX adjust mark positions after the line break
+ * OPENLINE_COM_LIST format comments with list or 2nd line indent
+ *
+ * "second_line_indent": indent for after ^^D in Insert mode or if flag
+ * OPENLINE_COM_LIST
+ *
+ * Return OK for success, FAIL for failure
+ */
+ int
+open_line(
+ int dir, /* FORWARD or BACKWARD */
+ int flags,
+ int second_line_indent)
+{
+ char_u *saved_line; /* copy of the original line */
+ char_u *next_line = NULL; /* copy of the next line */
+ char_u *p_extra = NULL; /* what goes to next line */
+ int less_cols = 0; /* less columns for mark in new line */
+ int less_cols_off = 0; /* columns to skip for mark adjust */
+ pos_T old_cursor; /* old cursor position */
+ int newcol = 0; /* new cursor column */
+ int newindent = 0; /* auto-indent of the new line */
+ int n;
+ int trunc_line = FALSE; /* truncate current line afterwards */
+ int retval = FAIL; /* return value */
+#ifdef FEAT_COMMENTS
+ int extra_len = 0; /* length of p_extra string */
+ int lead_len; /* length of comment leader */
+ char_u *lead_flags; /* position in 'comments' for comment leader */
+ char_u *leader = NULL; /* copy of comment leader */
+#endif
+ char_u *allocated = NULL; /* allocated memory */
+ char_u *p;
+ int saved_char = NUL; /* init for GCC */
+#if defined(FEAT_SMARTINDENT) || defined(FEAT_COMMENTS)
+ pos_T *pos;
+#endif
+#ifdef FEAT_SMARTINDENT
+ int do_si = (!p_paste && curbuf->b_p_si
+# ifdef FEAT_CINDENT
+ && !curbuf->b_p_cin
+# endif
+# ifdef FEAT_EVAL
+ && *curbuf->b_p_inde == NUL
+# endif
+ );
+ int no_si = FALSE; /* reset did_si afterwards */
+ int first_char = NUL; /* init for GCC */
+#endif
+#if defined(FEAT_LISP) || defined(FEAT_CINDENT)
+ int vreplace_mode;
+#endif
+ int did_append; /* appended a new line */
+ int saved_pi = curbuf->b_p_pi; /* copy of preserveindent setting */
+
+ /*
+ * make a copy of the current line so we can mess with it
+ */
+ saved_line = vim_strsave(ml_get_curline());
+ if (saved_line == NULL) /* out of memory! */
+ return FALSE;
+
+ if (State & VREPLACE_FLAG)
+ {
+ /*
+ * With VREPLACE we make a copy of the next line, which we will be
+ * starting to replace. First make the new line empty and let vim play
+ * with the indenting and comment leader to its heart's content. Then
+ * we grab what it ended up putting on the new line, put back the
+ * original line, and call ins_char() to put each new character onto
+ * the line, replacing what was there before and pushing the right
+ * stuff onto the replace stack. -- webb.
+ */
+ if (curwin->w_cursor.lnum < orig_line_count)
+ next_line = vim_strsave(ml_get(curwin->w_cursor.lnum + 1));
+ else
+ next_line = vim_strsave((char_u *)"");
+ if (next_line == NULL) /* out of memory! */
+ goto theend;
+
+ /*
+ * In VREPLACE mode, a NL replaces the rest of the line, and starts
+ * replacing the next line, so push all of the characters left on the
+ * line onto the replace stack. We'll push any other characters that
+ * might be replaced at the start of the next line (due to autoindent
+ * etc) a bit later.
+ */
+ replace_push(NUL); /* Call twice because BS over NL expects it */
+ replace_push(NUL);
+ p = saved_line + curwin->w_cursor.col;
+ while (*p != NUL)
+ {
+ if (has_mbyte)
+ p += replace_push_mb(p);
+ else
+ replace_push(*p++);
+ }
+ saved_line[curwin->w_cursor.col] = NUL;
+ }
+
+ if ((State & INSERT) && !(State & VREPLACE_FLAG))
+ {
+ p_extra = saved_line + curwin->w_cursor.col;
+#ifdef FEAT_SMARTINDENT
+ if (do_si) /* need first char after new line break */
+ {
+ p = skipwhite(p_extra);
+ first_char = *p;
+ }
+#endif
+#ifdef FEAT_COMMENTS
+ extra_len = (int)STRLEN(p_extra);
+#endif
+ saved_char = *p_extra;
+ *p_extra = NUL;
+ }
+
+ u_clearline(); /* cannot do "U" command when adding lines */
+#ifdef FEAT_SMARTINDENT
+ did_si = FALSE;
+#endif
+ ai_col = 0;
+
+ /*
+ * If we just did an auto-indent, then we didn't type anything on
+ * the prior line, and it should be truncated. Do this even if 'ai' is not
+ * set because automatically inserting a comment leader also sets did_ai.
+ */
+ if (dir == FORWARD && did_ai)
+ trunc_line = TRUE;
+
+ /*
+ * If 'autoindent' and/or 'smartindent' is set, try to figure out what
+ * indent to use for the new line.
+ */
+ if (curbuf->b_p_ai
+#ifdef FEAT_SMARTINDENT
+ || do_si
+#endif
+ )
+ {
+ /*
+ * count white space on current line
+ */
+#ifdef FEAT_VARTABS
+ newindent = get_indent_str_vtab(saved_line, curbuf->b_p_ts,
+ curbuf->b_p_vts_array, FALSE);
+#else
+ newindent = get_indent_str(saved_line, (int)curbuf->b_p_ts, FALSE);
+#endif
+ if (newindent == 0 && !(flags & OPENLINE_COM_LIST))
+ newindent = second_line_indent; /* for ^^D command in insert mode */
+
+#ifdef FEAT_SMARTINDENT
+ /*
+ * Do smart indenting.
+ * In insert/replace mode (only when dir == FORWARD)
+ * we may move some text to the next line. If it starts with '{'
+ * don't add an indent. Fixes inserting a NL before '{' in line
+ * "if (condition) {"
+ */
+ if (!trunc_line && do_si && *saved_line != NUL
+ && (p_extra == NULL || first_char != '{'))
+ {
+ char_u *ptr;
+ char_u last_char;
+
+ old_cursor = curwin->w_cursor;
+ ptr = saved_line;
+# ifdef FEAT_COMMENTS
+ if (flags & OPENLINE_DO_COM)
+ lead_len = get_leader_len(ptr, NULL, FALSE, TRUE);
+ else
+ lead_len = 0;
+# endif
+ if (dir == FORWARD)
+ {
+ /*
+ * Skip preprocessor directives, unless they are
+ * recognised as comments.
+ */
+ if (
+# ifdef FEAT_COMMENTS
+ lead_len == 0 &&
+# endif
+ ptr[0] == '#')
+ {
+ while (ptr[0] == '#' && curwin->w_cursor.lnum > 1)
+ ptr = ml_get(--curwin->w_cursor.lnum);
+ newindent = get_indent();
+ }
+# ifdef FEAT_COMMENTS
+ if (flags & OPENLINE_DO_COM)
+ lead_len = get_leader_len(ptr, NULL, FALSE, TRUE);
+ else
+ lead_len = 0;
+ if (lead_len > 0)
+ {
+ /*
+ * This case gets the following right:
+ * \*
+ * * A comment (read '\' as '/').
+ * *\
+ * #define IN_THE_WAY
+ * This should line up here;
+ */
+ p = skipwhite(ptr);
+ if (p[0] == '/' && p[1] == '*')
+ p++;
+ if (p[0] == '*')
+ {
+ for (p++; *p; p++)
+ {
+ if (p[0] == '/' && p[-1] == '*')
+ {
+ /*
+ * End of C comment, indent should line up
+ * with the line containing the start of
+ * the comment
+ */
+ curwin->w_cursor.col = (colnr_T)(p - ptr);
+ if ((pos = findmatch(NULL, NUL)) != NULL)
+ {
+ curwin->w_cursor.lnum = pos->lnum;
+ newindent = get_indent();
+ }
+ }
+ }
+ }
+ }
+ else /* Not a comment line */
+# endif
+ {
+ /* Find last non-blank in line */
+ p = ptr + STRLEN(ptr) - 1;
+ while (p > ptr && VIM_ISWHITE(*p))
+ --p;
+ last_char = *p;
+
+ /*
+ * find the character just before the '{' or ';'
+ */
+ if (last_char == '{' || last_char == ';')
+ {
+ if (p > ptr)
+ --p;
+ while (p > ptr && VIM_ISWHITE(*p))
+ --p;
+ }
+ /*
+ * Try to catch lines that are split over multiple
+ * lines. eg:
+ * if (condition &&
+ * condition) {
+ * Should line up here!
+ * }
+ */
+ if (*p == ')')
+ {
+ curwin->w_cursor.col = (colnr_T)(p - ptr);
+ if ((pos = findmatch(NULL, '(')) != NULL)
+ {
+ curwin->w_cursor.lnum = pos->lnum;
+ newindent = get_indent();
+ ptr = ml_get_curline();
+ }
+ }
+ /*
+ * If last character is '{' do indent, without
+ * checking for "if" and the like.
+ */
+ if (last_char == '{')
+ {
+ did_si = TRUE; /* do indent */
+ no_si = TRUE; /* don't delete it when '{' typed */
+ }
+ /*
+ * Look for "if" and the like, use 'cinwords'.
+ * Don't do this if the previous line ended in ';' or
+ * '}'.
+ */
+ else if (last_char != ';' && last_char != '}'
+ && cin_is_cinword(ptr))
+ did_si = TRUE;
+ }
+ }
+ else /* dir == BACKWARD */
+ {
+ /*
+ * Skip preprocessor directives, unless they are
+ * recognised as comments.
+ */
+ if (
+# ifdef FEAT_COMMENTS
+ lead_len == 0 &&
+# endif
+ ptr[0] == '#')
+ {
+ int was_backslashed = FALSE;
+
+ while ((ptr[0] == '#' || was_backslashed) &&
+ curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
+ {
+ if (*ptr && ptr[STRLEN(ptr) - 1] == '\\')
+ was_backslashed = TRUE;
+ else
+ was_backslashed = FALSE;
+ ptr = ml_get(++curwin->w_cursor.lnum);
+ }
+ if (was_backslashed)
+ newindent = 0; /* Got to end of file */
+ else
+ newindent = get_indent();
+ }
+ p = skipwhite(ptr);
+ if (*p == '}') /* if line starts with '}': do indent */
+ did_si = TRUE;
+ else /* can delete indent when '{' typed */
+ can_si_back = TRUE;
+ }
+ curwin->w_cursor = old_cursor;
+ }
+ if (do_si)
+ can_si = TRUE;
+#endif /* FEAT_SMARTINDENT */
+
+ did_ai = TRUE;
+ }
+
+#ifdef FEAT_COMMENTS
+ /*
+ * Find out if the current line starts with a comment leader.
+ * This may then be inserted in front of the new line.
+ */
+ end_comment_pending = NUL;
+ if (flags & OPENLINE_DO_COM)
+ lead_len = get_leader_len(saved_line, &lead_flags, dir == BACKWARD, TRUE);
+ else
+ lead_len = 0;
+ if (lead_len > 0)
+ {
+ char_u *lead_repl = NULL; /* replaces comment leader */
+ int lead_repl_len = 0; /* length of *lead_repl */
+ char_u lead_middle[COM_MAX_LEN]; /* middle-comment string */
+ char_u lead_end[COM_MAX_LEN]; /* end-comment string */
+ char_u *comment_end = NULL; /* where lead_end has been found */
+ int extra_space = FALSE; /* append extra space */
+ int current_flag;
+ int require_blank = FALSE; /* requires blank after middle */
+ char_u *p2;
+
+ /*
+ * If the comment leader has the start, middle or end flag, it may not
+ * be used or may be replaced with the middle leader.
+ */
+ for (p = lead_flags; *p && *p != ':'; ++p)
+ {
+ if (*p == COM_BLANK)
+ {
+ require_blank = TRUE;
+ continue;
+ }
+ if (*p == COM_START || *p == COM_MIDDLE)
+ {
+ current_flag = *p;
+ if (*p == COM_START)
+ {
+ /*
+ * Doing "O" on a start of comment does not insert leader.
+ */
+ if (dir == BACKWARD)
+ {
+ lead_len = 0;
+ break;
+ }
+
+ /* find start of middle part */
+ (void)copy_option_part(&p, lead_middle, COM_MAX_LEN, ",");
+ require_blank = FALSE;
+ }
+
+ /*
+ * Isolate the strings of the middle and end leader.
+ */
+ while (*p && p[-1] != ':') /* find end of middle flags */
+ {
+ if (*p == COM_BLANK)
+ require_blank = TRUE;
+ ++p;
+ }
+ (void)copy_option_part(&p, lead_middle, COM_MAX_LEN, ",");
+
+ while (*p && p[-1] != ':') /* find end of end flags */
+ {
+ /* Check whether we allow automatic ending of comments */
+ if (*p == COM_AUTO_END)
+ end_comment_pending = -1; /* means we want to set it */
+ ++p;
+ }
+ n = copy_option_part(&p, lead_end, COM_MAX_LEN, ",");
+
+ if (end_comment_pending == -1) /* we can set it now */
+ end_comment_pending = lead_end[n - 1];
+
+ /*
+ * If the end of the comment is in the same line, don't use
+ * the comment leader.
+ */
+ if (dir == FORWARD)
+ {
+ for (p = saved_line + lead_len; *p; ++p)
+ if (STRNCMP(p, lead_end, n) == 0)
+ {
+ comment_end = p;
+ lead_len = 0;
+ break;
+ }
+ }
+
+ /*
+ * Doing "o" on a start of comment inserts the middle leader.
+ */
+ if (lead_len > 0)
+ {
+ if (current_flag == COM_START)
+ {
+ lead_repl = lead_middle;
+ lead_repl_len = (int)STRLEN(lead_middle);
+ }
+
+ /*
+ * If we have hit RETURN immediately after the start
+ * comment leader, then put a space after the middle
+ * comment leader on the next line.
+ */
+ if (!VIM_ISWHITE(saved_line[lead_len - 1])
+ && ((p_extra != NULL
+ && (int)curwin->w_cursor.col == lead_len)
+ || (p_extra == NULL
+ && saved_line[lead_len] == NUL)
+ || require_blank))
+ extra_space = TRUE;
+ }
+ break;
+ }
+ if (*p == COM_END)
+ {
+ /*
+ * Doing "o" on the end of a comment does not insert leader.
+ * Remember where the end is, might want to use it to find the
+ * start (for C-comments).
+ */
+ if (dir == FORWARD)
+ {
+ comment_end = skipwhite(saved_line);
+ lead_len = 0;
+ break;
+ }
+
+ /*
+ * Doing "O" on the end of a comment inserts the middle leader.
+ * Find the string for the middle leader, searching backwards.
+ */
+ while (p > curbuf->b_p_com && *p != ',')
+ --p;
+ for (lead_repl = p; lead_repl > curbuf->b_p_com
+ && lead_repl[-1] != ':'; --lead_repl)
+ ;
+ lead_repl_len = (int)(p - lead_repl);
+
+ /* We can probably always add an extra space when doing "O" on
+ * the comment-end */
+ extra_space = TRUE;
+
+ /* Check whether we allow automatic ending of comments */
+ for (p2 = p; *p2 && *p2 != ':'; p2++)
+ {
+ if (*p2 == COM_AUTO_END)
+ end_comment_pending = -1; /* means we want to set it */
+ }
+ if (end_comment_pending == -1)
+ {
+ /* Find last character in end-comment string */
+ while (*p2 && *p2 != ',')
+ p2++;
+ end_comment_pending = p2[-1];
+ }
+ break;
+ }
+ if (*p == COM_FIRST)
+ {
+ /*
+ * Comment leader for first line only: Don't repeat leader
+ * when using "O", blank out leader when using "o".
+ */
+ if (dir == BACKWARD)
+ lead_len = 0;
+ else
+ {
+ lead_repl = (char_u *)"";
+ lead_repl_len = 0;
+ }
+ break;
+ }
+ }
+ if (lead_len)
+ {
+ /* allocate buffer (may concatenate p_extra later) */
+ leader = alloc(lead_len + lead_repl_len + extra_space + extra_len
+ + (second_line_indent > 0 ? second_line_indent : 0) + 1);
+ allocated = leader; /* remember to free it later */
+
+ if (leader == NULL)
+ lead_len = 0;
+ else
+ {
+ vim_strncpy(leader, saved_line, lead_len);
+
+ /*
+ * Replace leader with lead_repl, right or left adjusted
+ */
+ if (lead_repl != NULL)
+ {
+ int c = 0;
+ int off = 0;
+
+ for (p = lead_flags; *p != NUL && *p != ':'; )
+ {
+ if (*p == COM_RIGHT || *p == COM_LEFT)
+ c = *p++;
+ else if (VIM_ISDIGIT(*p) || *p == '-')
+ off = getdigits(&p);
+ else
+ ++p;
+ }
+ if (c == COM_RIGHT) /* right adjusted leader */
+ {
+ /* find last non-white in the leader to line up with */
+ for (p = leader + lead_len - 1; p > leader
+ && VIM_ISWHITE(*p); --p)
+ ;
+ ++p;
+
+ /* Compute the length of the replaced characters in
+ * screen characters, not bytes. */
+ {
+ int repl_size = vim_strnsize(lead_repl,
+ lead_repl_len);
+ int old_size = 0;
+ char_u *endp = p;
+ int l;
+
+ while (old_size < repl_size && p > leader)
+ {
+ MB_PTR_BACK(leader, p);
+ old_size += ptr2cells(p);
+ }
+ l = lead_repl_len - (int)(endp - p);
+ if (l != 0)
+ mch_memmove(endp + l, endp,
+ (size_t)((leader + lead_len) - endp));
+ lead_len += l;
+ }
+ mch_memmove(p, lead_repl, (size_t)lead_repl_len);
+ if (p + lead_repl_len > leader + lead_len)
+ p[lead_repl_len] = NUL;
+
+ /* blank-out any other chars from the old leader. */
+ while (--p >= leader)
+ {
+ int l = mb_head_off(leader, p);
+
+ if (l > 1)
+ {
+ p -= l;
+ if (ptr2cells(p) > 1)
+ {
+ p[1] = ' ';
+ --l;
+ }
+ mch_memmove(p + 1, p + l + 1,
+ (size_t)((leader + lead_len) - (p + l + 1)));
+ lead_len -= l;
+ *p = ' ';
+ }
+ else if (!VIM_ISWHITE(*p))
+ *p = ' ';
+ }
+ }
+ else /* left adjusted leader */
+ {
+ p = skipwhite(leader);
+
+ /* Compute the length of the replaced characters in
+ * screen characters, not bytes. Move the part that is
+ * not to be overwritten. */
+ {
+ int repl_size = vim_strnsize(lead_repl,
+ lead_repl_len);
+ int i;
+ int l;
+
+ for (i = 0; i < lead_len && p[i] != NUL; i += l)
+ {
+ l = (*mb_ptr2len)(p + i);
+ if (vim_strnsize(p, i + l) > repl_size)
+ break;
+ }
+ if (i != lead_repl_len)
+ {
+ mch_memmove(p + lead_repl_len, p + i,
+ (size_t)(lead_len - i - (p - leader)));
+ lead_len += lead_repl_len - i;
+ }
+ }
+ mch_memmove(p, lead_repl, (size_t)lead_repl_len);
+
+ /* Replace any remaining non-white chars in the old
+ * leader by spaces. Keep Tabs, the indent must
+ * remain the same. */
+ for (p += lead_repl_len; p < leader + lead_len; ++p)
+ if (!VIM_ISWHITE(*p))
+ {
+ /* Don't put a space before a TAB. */
+ if (p + 1 < leader + lead_len && p[1] == TAB)
+ {
+ --lead_len;
+ mch_memmove(p, p + 1,
+ (leader + lead_len) - p);
+ }
+ else
+ {
+ int l = (*mb_ptr2len)(p);
+
+ if (l > 1)
+ {
+ if (ptr2cells(p) > 1)
+ {
+ /* Replace a double-wide char with
+ * two spaces */
+ --l;
+ *p++ = ' ';
+ }
+ mch_memmove(p + 1, p + l,
+ (leader + lead_len) - p);
+ lead_len -= l - 1;
+ }
+ *p = ' ';
+ }
+ }
+ *p = NUL;
+ }
+
+ /* Recompute the indent, it may have changed. */
+ if (curbuf->b_p_ai
+#ifdef FEAT_SMARTINDENT
+ || do_si
+#endif
+ )
+#ifdef FEAT_VARTABS
+ newindent = get_indent_str_vtab(leader, curbuf->b_p_ts,
+ curbuf->b_p_vts_array, FALSE);
+#else
+ newindent = get_indent_str(leader,
+ (int)curbuf->b_p_ts, FALSE);
+#endif
+
+ /* Add the indent offset */
+ if (newindent + off < 0)
+ {
+ off = -newindent;
+ newindent = 0;
+ }
+ else
+ newindent += off;
+
+ /* Correct trailing spaces for the shift, so that
+ * alignment remains equal. */
+ while (off > 0 && lead_len > 0
+ && leader[lead_len - 1] == ' ')
+ {
+ /* Don't do it when there is a tab before the space */
+ if (vim_strchr(skipwhite(leader), '\t') != NULL)
+ break;
+ --lead_len;
+ --off;
+ }
+
+ /* If the leader ends in white space, don't add an
+ * extra space */
+ if (lead_len > 0 && VIM_ISWHITE(leader[lead_len - 1]))
+ extra_space = FALSE;
+ leader[lead_len] = NUL;
+ }
+
+ if (extra_space)
+ {
+ leader[lead_len++] = ' ';
+ leader[lead_len] = NUL;
+ }
+
+ newcol = lead_len;
+
+ /*
+ * if a new indent will be set below, remove the indent that
+ * is in the comment leader
+ */
+ if (newindent
+#ifdef FEAT_SMARTINDENT
+ || did_si
+#endif
+ )
+ {
+ while (lead_len && VIM_ISWHITE(*leader))
+ {
+ --lead_len;
+ --newcol;
+ ++leader;
+ }
+ }
+
+ }
+#ifdef FEAT_SMARTINDENT
+ did_si = can_si = FALSE;
+#endif
+ }
+ else if (comment_end != NULL)
+ {
+ /*
+ * We have finished a comment, so we don't use the leader.
+ * If this was a C-comment and 'ai' or 'si' is set do a normal
+ * indent to align with the line containing the start of the
+ * comment.
+ */
+ if (comment_end[0] == '*' && comment_end[1] == '/' &&
+ (curbuf->b_p_ai
+#ifdef FEAT_SMARTINDENT
+ || do_si
+#endif
+ ))
+ {
+ old_cursor = curwin->w_cursor;
+ curwin->w_cursor.col = (colnr_T)(comment_end - saved_line);
+ if ((pos = findmatch(NULL, NUL)) != NULL)
+ {
+ curwin->w_cursor.lnum = pos->lnum;
+ newindent = get_indent();
+ }
+ curwin->w_cursor = old_cursor;
+ }
+ }
+ }
+#endif
+
+ /* (State == INSERT || State == REPLACE), only when dir == FORWARD */
+ if (p_extra != NULL)
+ {
+ *p_extra = saved_char; /* restore char that NUL replaced */
+
+ /*
+ * When 'ai' set or "flags" has OPENLINE_DELSPACES, skip to the first
+ * non-blank.
+ *
+ * When in REPLACE mode, put the deleted blanks on the replace stack,
+ * preceded by a NUL, so they can be put back when a BS is entered.
+ */
+ if (REPLACE_NORMAL(State))
+ replace_push(NUL); /* end of extra blanks */
+ if (curbuf->b_p_ai || (flags & OPENLINE_DELSPACES))
+ {
+ while ((*p_extra == ' ' || *p_extra == '\t')
+ && (!enc_utf8
+ || !utf_iscomposing(utf_ptr2char(p_extra + 1))))
+ {
+ if (REPLACE_NORMAL(State))
+ replace_push(*p_extra);
+ ++p_extra;
+ ++less_cols_off;
+ }
+ }
+ if (*p_extra != NUL)
+ did_ai = FALSE; /* append some text, don't truncate now */
+
+ /* columns for marks adjusted for removed columns */
+ less_cols = (int)(p_extra - saved_line);
+ }
+
+ if (p_extra == NULL)
+ p_extra = (char_u *)""; /* append empty line */
+
+#ifdef FEAT_COMMENTS
+ /* concatenate leader and p_extra, if there is a leader */
+ if (lead_len)
+ {
+ if (flags & OPENLINE_COM_LIST && second_line_indent > 0)
+ {
+ int i;
+ int padding = second_line_indent
+ - (newindent + (int)STRLEN(leader));
+
+ /* Here whitespace is inserted after the comment char.
+ * Below, set_indent(newindent, SIN_INSERT) will insert the
+ * whitespace needed before the comment char. */
+ for (i = 0; i < padding; i++)
+ {
+ STRCAT(leader, " ");
+ less_cols--;
+ newcol++;
+ }
+ }
+ STRCAT(leader, p_extra);
+ p_extra = leader;
+ did_ai = TRUE; /* So truncating blanks works with comments */
+ less_cols -= lead_len;
+ }
+ else
+ end_comment_pending = NUL; /* turns out there was no leader */
+#endif
+
+ old_cursor = curwin->w_cursor;
+ if (dir == BACKWARD)
+ --curwin->w_cursor.lnum;
+ if (!(State & VREPLACE_FLAG) || old_cursor.lnum >= orig_line_count)
+ {
+ if (ml_append(curwin->w_cursor.lnum, p_extra, (colnr_T)0, FALSE)
+ == FAIL)
+ goto theend;
+ /* Postpone calling changed_lines(), because it would mess up folding
+ * with markers.
+ * Skip mark_adjust when adding a line after the last one, there can't
+ * be marks there. But still needed in diff mode. */
+ if (curwin->w_cursor.lnum + 1 < curbuf->b_ml.ml_line_count
+#ifdef FEAT_DIFF
+ || curwin->w_p_diff
+#endif
+ )
+ mark_adjust(curwin->w_cursor.lnum + 1, (linenr_T)MAXLNUM, 1L, 0L);
+ did_append = TRUE;
+ }
+ else
+ {
+ /*
+ * In VREPLACE mode we are starting to replace the next line.
+ */
+ curwin->w_cursor.lnum++;
+ if (curwin->w_cursor.lnum >= Insstart.lnum + vr_lines_changed)
+ {
+ /* In case we NL to a new line, BS to the previous one, and NL
+ * again, we don't want to save the new line for undo twice.
+ */
+ (void)u_save_cursor(); /* errors are ignored! */
+ vr_lines_changed++;
+ }
+ ml_replace(curwin->w_cursor.lnum, p_extra, TRUE);
+ changed_bytes(curwin->w_cursor.lnum, 0);
+ curwin->w_cursor.lnum--;
+ did_append = FALSE;
+ }
+
+ if (newindent
+#ifdef FEAT_SMARTINDENT
+ || did_si
+#endif
+ )
+ {
+ ++curwin->w_cursor.lnum;
+#ifdef FEAT_SMARTINDENT
+ if (did_si)
+ {
+ int sw = (int)get_sw_value(curbuf);
+
+ if (p_sr)
+ newindent -= newindent % sw;
+ newindent += sw;
+ }
+#endif
+ /* Copy the indent */
+ if (curbuf->b_p_ci)
+ {
+ (void)copy_indent(newindent, saved_line);
+
+ /*
+ * Set the 'preserveindent' option so that any further screwing
+ * with the line doesn't entirely destroy our efforts to preserve
+ * it. It gets restored at the function end.
+ */
+ curbuf->b_p_pi = TRUE;
+ }
+ else
+ (void)set_indent(newindent, SIN_INSERT);
+ less_cols -= curwin->w_cursor.col;
+
+ ai_col = curwin->w_cursor.col;
+
+ /*
+ * In REPLACE mode, for each character in the new indent, there must
+ * be a NUL on the replace stack, for when it is deleted with BS
+ */
+ if (REPLACE_NORMAL(State))
+ for (n = 0; n < (int)curwin->w_cursor.col; ++n)
+ replace_push(NUL);
+ newcol += curwin->w_cursor.col;
+#ifdef FEAT_SMARTINDENT
+ if (no_si)
+ did_si = FALSE;
+#endif
+ }
+
+#ifdef FEAT_COMMENTS
+ /*
+ * In REPLACE mode, for each character in the extra leader, there must be
+ * a NUL on the replace stack, for when it is deleted with BS.
+ */
+ if (REPLACE_NORMAL(State))
+ while (lead_len-- > 0)
+ replace_push(NUL);
+#endif
+
+ curwin->w_cursor = old_cursor;
+
+ if (dir == FORWARD)
+ {
+ if (trunc_line || (State & INSERT))
+ {
+ /* truncate current line at cursor */
+ saved_line[curwin->w_cursor.col] = NUL;
+ /* Remove trailing white space, unless OPENLINE_KEEPTRAIL used. */
+ if (trunc_line && !(flags & OPENLINE_KEEPTRAIL))
+ truncate_spaces(saved_line);
+ ml_replace(curwin->w_cursor.lnum, saved_line, FALSE);
+ saved_line = NULL;
+ if (did_append)
+ {
+ changed_lines(curwin->w_cursor.lnum, curwin->w_cursor.col,
+ curwin->w_cursor.lnum + 1, 1L);
+ did_append = FALSE;
+
+ /* Move marks after the line break to the new line. */
+ if (flags & OPENLINE_MARKFIX)
+ mark_col_adjust(curwin->w_cursor.lnum,
+ curwin->w_cursor.col + less_cols_off,
+ 1L, (long)-less_cols, 0);
+ }
+ else
+ changed_bytes(curwin->w_cursor.lnum, curwin->w_cursor.col);
+ }
+
+ /*
+ * Put the cursor on the new line. Careful: the scrollup() above may
+ * have moved w_cursor, we must use old_cursor.
+ */
+ curwin->w_cursor.lnum = old_cursor.lnum + 1;
+ }
+ if (did_append)
+ changed_lines(curwin->w_cursor.lnum, 0, curwin->w_cursor.lnum, 1L);
+
+ curwin->w_cursor.col = newcol;
+ curwin->w_cursor.coladd = 0;
+
+#if defined(FEAT_LISP) || defined(FEAT_CINDENT)
+ /*
+ * In VREPLACE mode, we are handling the replace stack ourselves, so stop
+ * fixthisline() from doing it (via change_indent()) by telling it we're in
+ * normal INSERT mode.
+ */
+ if (State & VREPLACE_FLAG)
+ {
+ vreplace_mode = State; /* So we know to put things right later */
+ State = INSERT;
+ }
+ else
+ vreplace_mode = 0;
+#endif
+#ifdef FEAT_LISP
+ /*
+ * May do lisp indenting.
+ */
+ if (!p_paste
+# ifdef FEAT_COMMENTS
+ && leader == NULL
+# endif
+ && curbuf->b_p_lisp
+ && curbuf->b_p_ai)
+ {
+ fixthisline(get_lisp_indent);
+ ai_col = (colnr_T)getwhitecols_curline();
+ }
+#endif
+#ifdef FEAT_CINDENT
+ /*
+ * May do indenting after opening a new line.
+ */
+ if (!p_paste
+ && (curbuf->b_p_cin
+# ifdef FEAT_EVAL
+ || *curbuf->b_p_inde != NUL
+# endif
+ )
+ && in_cinkeys(dir == FORWARD
+ ? KEY_OPEN_FORW
+ : KEY_OPEN_BACK, ' ', linewhite(curwin->w_cursor.lnum)))
+ {
+ do_c_expr_indent();
+ ai_col = (colnr_T)getwhitecols_curline();
+ }
+#endif
+#if defined(FEAT_LISP) || defined(FEAT_CINDENT)
+ if (vreplace_mode != 0)
+ State = vreplace_mode;
+#endif
+
+ /*
+ * Finally, VREPLACE gets the stuff on the new line, then puts back the
+ * original line, and inserts the new stuff char by char, pushing old stuff
+ * onto the replace stack (via ins_char()).
+ */
+ if (State & VREPLACE_FLAG)
+ {
+ /* Put new line in p_extra */
+ p_extra = vim_strsave(ml_get_curline());
+ if (p_extra == NULL)
+ goto theend;
+
+ /* Put back original line */
+ ml_replace(curwin->w_cursor.lnum, next_line, FALSE);
+
+ /* Insert new stuff into line again */
+ curwin->w_cursor.col = 0;
+ curwin->w_cursor.coladd = 0;
+ ins_bytes(p_extra); /* will call changed_bytes() */
+ vim_free(p_extra);
+ next_line = NULL;
+ }
+
+ retval = OK; /* success! */
+theend:
+ curbuf->b_p_pi = saved_pi;
+ vim_free(saved_line);
+ vim_free(next_line);
+ vim_free(allocated);
+ return retval;
+}
+
+#if defined(FEAT_COMMENTS) || defined(PROTO)
+/*
+ * get_leader_len() returns the length in bytes of the prefix of the given
+ * string which introduces a comment. If this string is not a comment then
+ * 0 is returned.
+ * When "flags" is not NULL, it is set to point to the flags of the recognized
+ * comment leader.
+ * "backward" must be true for the "O" command.
+ * If "include_space" is set, include trailing whitespace while calculating the
+ * length.
+ */
+ int
+get_leader_len(
+ char_u *line,
+ char_u **flags,
+ int backward,
+ int include_space)
+{
+ int i, j;
+ int result;
+ int got_com = FALSE;
+ int found_one;
+ char_u part_buf[COM_MAX_LEN]; /* buffer for one option part */
+ char_u *string; /* pointer to comment string */
+ char_u *list;
+ int middle_match_len = 0;
+ char_u *prev_list;
+ char_u *saved_flags = NULL;
+
+ result = i = 0;
+ while (VIM_ISWHITE(line[i])) /* leading white space is ignored */
+ ++i;
+
+ /*
+ * Repeat to match several nested comment strings.
+ */
+ while (line[i] != NUL)
+ {
+ /*
+ * scan through the 'comments' option for a match
+ */
+ found_one = FALSE;
+ for (list = curbuf->b_p_com; *list; )
+ {
+ /* Get one option part into part_buf[]. Advance "list" to next
+ * one. Put "string" at start of string. */
+ if (!got_com && flags != NULL)
+ *flags = list; /* remember where flags started */
+ prev_list = list;
+ (void)copy_option_part(&list, part_buf, COM_MAX_LEN, ",");
+ string = vim_strchr(part_buf, ':');
+ if (string == NULL) /* missing ':', ignore this part */
+ continue;
+ *string++ = NUL; /* isolate flags from string */
+
+ /* If we found a middle match previously, use that match when this
+ * is not a middle or end. */
+ if (middle_match_len != 0
+ && vim_strchr(part_buf, COM_MIDDLE) == NULL
+ && vim_strchr(part_buf, COM_END) == NULL)
+ break;
+
+ /* When we already found a nested comment, only accept further
+ * nested comments. */
+ if (got_com && vim_strchr(part_buf, COM_NEST) == NULL)
+ continue;
+
+ /* When 'O' flag present and using "O" command skip this one. */
+ if (backward && vim_strchr(part_buf, COM_NOBACK) != NULL)
+ continue;
+
+ /* Line contents and string must match.
+ * When string starts with white space, must have some white space
+ * (but the amount does not need to match, there might be a mix of
+ * TABs and spaces). */
+ if (VIM_ISWHITE(string[0]))
+ {
+ if (i == 0 || !VIM_ISWHITE(line[i - 1]))
+ continue; /* missing white space */
+ while (VIM_ISWHITE(string[0]))
+ ++string;
+ }
+ for (j = 0; string[j] != NUL && string[j] == line[i + j]; ++j)
+ ;
+ if (string[j] != NUL)
+ continue; /* string doesn't match */
+
+ /* When 'b' flag used, there must be white space or an
+ * end-of-line after the string in the line. */
+ if (vim_strchr(part_buf, COM_BLANK) != NULL
+ && !VIM_ISWHITE(line[i + j]) && line[i + j] != NUL)
+ continue;
+
+ /* We have found a match, stop searching unless this is a middle
+ * comment. The middle comment can be a substring of the end
+ * comment in which case it's better to return the length of the
+ * end comment and its flags. Thus we keep searching with middle
+ * and end matches and use an end match if it matches better. */
+ if (vim_strchr(part_buf, COM_MIDDLE) != NULL)
+ {
+ if (middle_match_len == 0)
+ {
+ middle_match_len = j;
+ saved_flags = prev_list;
+ }
+ continue;
+ }
+ if (middle_match_len != 0 && j > middle_match_len)
+ /* Use this match instead of the middle match, since it's a
+ * longer thus better match. */
+ middle_match_len = 0;
+
+ if (middle_match_len == 0)
+ i += j;
+ found_one = TRUE;
+ break;
+ }
+
+ if (middle_match_len != 0)
+ {
+ /* Use the previously found middle match after failing to find a
+ * match with an end. */
+ if (!got_com && flags != NULL)
+ *flags = saved_flags;
+ i += middle_match_len;
+ found_one = TRUE;
+ }
+
+ /* No match found, stop scanning. */
+ if (!found_one)
+ break;
+
+ result = i;
+
+ /* Include any trailing white space. */
+ while (VIM_ISWHITE(line[i]))
+ ++i;
+
+ if (include_space)
+ result = i;
+
+ /* If this comment doesn't nest, stop here. */
+ got_com = TRUE;
+ if (vim_strchr(part_buf, COM_NEST) == NULL)
+ break;
+ }
+ return result;
+}
+
+/*
+ * Return the offset at which the last comment in line starts. If there is no
+ * comment in the whole line, -1 is returned.
+ *
+ * When "flags" is not null, it is set to point to the flags describing the
+ * recognized comment leader.
+ */
+ int
+get_last_leader_offset(char_u *line, char_u **flags)
+{
+ int result = -1;
+ int i, j;
+ int lower_check_bound = 0;
+ char_u *string;
+ char_u *com_leader;
+ char_u *com_flags;
+ char_u *list;
+ int found_one;
+ char_u part_buf[COM_MAX_LEN]; /* buffer for one option part */
+
+ /*
+ * Repeat to match several nested comment strings.
+ */
+ i = (int)STRLEN(line);
+ while (--i >= lower_check_bound)
+ {
+ /*
+ * scan through the 'comments' option for a match
+ */
+ found_one = FALSE;
+ for (list = curbuf->b_p_com; *list; )
+ {
+ char_u *flags_save = list;
+
+ /*
+ * Get one option part into part_buf[]. Advance list to next one.
+ * put string at start of string.
+ */
+ (void)copy_option_part(&list, part_buf, COM_MAX_LEN, ",");
+ string = vim_strchr(part_buf, ':');
+ if (string == NULL) /* If everything is fine, this cannot actually
+ * happen. */
+ {
+ continue;
+ }
+ *string++ = NUL; /* Isolate flags from string. */
+ com_leader = string;
+
+ /*
+ * Line contents and string must match.
+ * When string starts with white space, must have some white space
+ * (but the amount does not need to match, there might be a mix of
+ * TABs and spaces).
+ */
+ if (VIM_ISWHITE(string[0]))
+ {
+ if (i == 0 || !VIM_ISWHITE(line[i - 1]))
+ continue;
+ while (VIM_ISWHITE(*string))
+ ++string;
+ }
+ for (j = 0; string[j] != NUL && string[j] == line[i + j]; ++j)
+ /* do nothing */;
+ if (string[j] != NUL)
+ continue;
+
+ /*
+ * When 'b' flag used, there must be white space or an
+ * end-of-line after the string in the line.
+ */
+ if (vim_strchr(part_buf, COM_BLANK) != NULL
+ && !VIM_ISWHITE(line[i + j]) && line[i + j] != NUL)
+ continue;
+
+ if (vim_strchr(part_buf, COM_MIDDLE) != NULL)
+ {
+ // For a middlepart comment, only consider it to match if
+ // everything before the current position in the line is
+ // whitespace. Otherwise we would think we are inside a
+ // comment if the middle part appears somewhere in the middle
+ // of the line. E.g. for C the "*" appears often.
+ for (j = 0; VIM_ISWHITE(line[j]) && j <= i; j++)
+ ;
+ if (j < i)
+ continue;
+ }
+
+ /*
+ * We have found a match, stop searching.
+ */
+ found_one = TRUE;
+
+ if (flags)
+ *flags = flags_save;
+ com_flags = flags_save;
+
+ break;
+ }
+
+ if (found_one)
+ {
+ char_u part_buf2[COM_MAX_LEN]; /* buffer for one option part */
+ int len1, len2, off;
+
+ result = i;
+ /*
+ * If this comment nests, continue searching.
+ */
+ if (vim_strchr(part_buf, COM_NEST) != NULL)
+ continue;
+
+ lower_check_bound = i;
+
+ /* Let's verify whether the comment leader found is a substring
+ * of other comment leaders. If it is, let's adjust the
+ * lower_check_bound so that we make sure that we have determined
+ * the comment leader correctly.
+ */
+
+ while (VIM_ISWHITE(*com_leader))
+ ++com_leader;
+ len1 = (int)STRLEN(com_leader);
+
+ for (list = curbuf->b_p_com; *list; )
+ {
+ char_u *flags_save = list;
+
+ (void)copy_option_part(&list, part_buf2, COM_MAX_LEN, ",");
+ if (flags_save == com_flags)
+ continue;
+ string = vim_strchr(part_buf2, ':');
+ ++string;
+ while (VIM_ISWHITE(*string))
+ ++string;
+ len2 = (int)STRLEN(string);
+ if (len2 == 0)
+ continue;
+
+ /* Now we have to verify whether string ends with a substring
+ * beginning the com_leader. */
+ for (off = (len2 > i ? i : len2); off > 0 && off + len1 > len2;)
+ {
+ --off;
+ if (!STRNCMP(string + off, com_leader, len2 - off))
+ {
+ if (i - off < lower_check_bound)
+ lower_check_bound = i - off;
+ }
+ }
+ }
+ }
+ }
+ return result;
+}
+#endif
+
+/*
+ * Return the number of window lines occupied by buffer line "lnum".
+ */
+ int
+plines(linenr_T lnum)
+{
+ return plines_win(curwin, lnum, TRUE);
+}
+
+ int
+plines_win(
+ win_T *wp,
+ linenr_T lnum,
+ int winheight) /* when TRUE limit to window height */
+{
+#if defined(FEAT_DIFF) || defined(PROTO)
+ /* Check for filler lines above this buffer line. When folded the result
+ * is one line anyway. */
+ return plines_win_nofill(wp, lnum, winheight) + diff_check_fill(wp, lnum);
+}
+
+ int
+plines_nofill(linenr_T lnum)
+{
+ return plines_win_nofill(curwin, lnum, TRUE);
+}
+
+ int
+plines_win_nofill(
+ win_T *wp,
+ linenr_T lnum,
+ int winheight) /* when TRUE limit to window height */
+{
+#endif
+ int lines;
+
+ if (!wp->w_p_wrap)
+ return 1;
+
+ if (wp->w_width == 0)
+ return 1;
+
+#ifdef FEAT_FOLDING
+ /* A folded lines is handled just like an empty line. */
+ /* NOTE: Caller must handle lines that are MAYBE folded. */
+ if (lineFolded(wp, lnum) == TRUE)
+ return 1;
+#endif
+
+ lines = plines_win_nofold(wp, lnum);
+ if (winheight > 0 && lines > wp->w_height)
+ return (int)wp->w_height;
+ return lines;
+}
+
+/*
+ * Return number of window lines physical line "lnum" will occupy in window
+ * "wp". Does not care about folding, 'wrap' or 'diff'.
+ */
+ int
+plines_win_nofold(win_T *wp, linenr_T lnum)
+{
+ char_u *s;
+ long col;
+ int width;
+
+ s = ml_get_buf(wp->w_buffer, lnum, FALSE);
+ if (*s == NUL) /* empty line */
+ return 1;
+ col = win_linetabsize(wp, s, (colnr_T)MAXCOL);
+
+ /*
+ * If list mode is on, then the '$' at the end of the line may take up one
+ * extra column.
+ */
+ if (wp->w_p_list && lcs_eol != NUL)
+ col += 1;
+
+ /*
+ * Add column offset for 'number', 'relativenumber' and 'foldcolumn'.
+ */
+ width = wp->w_width - win_col_off(wp);
+ if (width <= 0)
+ return 32000;
+ if (col <= width)
+ return 1;
+ col -= width;
+ width += win_col_off2(wp);
+ return (col + (width - 1)) / width + 1;
+}
+
+/*
+ * Like plines_win(), but only reports the number of physical screen lines
+ * used from the start of the line to the given column number.
+ */
+ int
+plines_win_col(win_T *wp, linenr_T lnum, long column)
+{
+ long col;
+ char_u *s;
+ int lines = 0;
+ int width;
+ char_u *line;
+
+#ifdef FEAT_DIFF
+ /* Check for filler lines above this buffer line. When folded the result
+ * is one line anyway. */
+ lines = diff_check_fill(wp, lnum);
+#endif
+
+ if (!wp->w_p_wrap)
+ return lines + 1;
+
+ if (wp->w_width == 0)
+ return lines + 1;
+
+ line = s = ml_get_buf(wp->w_buffer, lnum, FALSE);
+
+ col = 0;
+ while (*s != NUL && --column >= 0)
+ {
+ col += win_lbr_chartabsize(wp, line, s, (colnr_T)col, NULL);
+ MB_PTR_ADV(s);
+ }
+
+ /*
+ * If *s is a TAB, and the TAB is not displayed as ^I, and we're not in
+ * INSERT mode, then col must be adjusted so that it represents the last
+ * screen position of the TAB. This only fixes an error when the TAB wraps
+ * from one screen line to the next (when 'columns' is not a multiple of
+ * 'ts') -- webb.
+ */
+ if (*s == TAB && (State & NORMAL) && (!wp->w_p_list || lcs_tab1))
+ col += win_lbr_chartabsize(wp, line, s, (colnr_T)col, NULL) - 1;
+
+ /*
+ * Add column offset for 'number', 'relativenumber', 'foldcolumn', etc.
+ */
+ width = wp->w_width - win_col_off(wp);
+ if (width <= 0)
+ return 9999;
+
+ lines += 1;
+ if (col > width)
+ lines += (col - width) / (width + win_col_off2(wp)) + 1;
+ return lines;
+}
+
+ int
+plines_m_win(win_T *wp, linenr_T first, linenr_T last)
+{
+ int count = 0;
+
+ while (first <= last)
+ {
+#ifdef FEAT_FOLDING
+ int x;
+
+ /* Check if there are any really folded lines, but also included lines
+ * that are maybe folded. */
+ x = foldedCount(wp, first, NULL);
+ if (x > 0)
+ {
+ ++count; /* count 1 for "+-- folded" line */
+ first += x;
+ }
+ else
+#endif
+ {
+#ifdef FEAT_DIFF
+ if (first == wp->w_topline)
+ count += plines_win_nofill(wp, first, TRUE) + wp->w_topfill;
+ else
+#endif
+ count += plines_win(wp, first, TRUE);
+ ++first;
+ }
+ }
+ return (count);
+}
+
+/*
+ * Insert string "p" at the cursor position. Stops at a NUL byte.
+ * Handles Replace mode and multi-byte characters.
+ */
+ void
+ins_bytes(char_u *p)
+{
+ ins_bytes_len(p, (int)STRLEN(p));
+}
+
+/*
+ * Insert string "p" with length "len" at the cursor position.
+ * Handles Replace mode and multi-byte characters.
+ */
+ void
+ins_bytes_len(char_u *p, int len)
+{
+ int i;
+ int n;
+
+ if (has_mbyte)
+ for (i = 0; i < len; i += n)
+ {
+ if (enc_utf8)
+ // avoid reading past p[len]
+ n = utfc_ptr2len_len(p + i, len - i);
+ else
+ n = (*mb_ptr2len)(p + i);
+ ins_char_bytes(p + i, n);
+ }
+ else
+ for (i = 0; i < len; ++i)
+ ins_char(p[i]);
+}
+
+/*
+ * Insert or replace a single character at the cursor position.
+ * When in REPLACE or VREPLACE mode, replace any existing character.
+ * Caller must have prepared for undo.
+ * For multi-byte characters we get the whole character, the caller must
+ * convert bytes to a character.
+ */
+ void
+ins_char(int c)
+{
+ char_u buf[MB_MAXBYTES + 1];
+ int n = (*mb_char2bytes)(c, buf);
+
+ /* When "c" is 0x100, 0x200, etc. we don't want to insert a NUL byte.
+ * Happens for CTRL-Vu9900. */
+ if (buf[0] == 0)
+ buf[0] = '\n';
+
+ ins_char_bytes(buf, n);
+}
+
+ void
+ins_char_bytes(char_u *buf, int charlen)
+{
+ int c = buf[0];
+ int newlen; // nr of bytes inserted
+ int oldlen; // nr of bytes deleted (0 when not replacing)
+ char_u *p;
+ char_u *newp;
+ char_u *oldp;
+ int linelen; // length of old line including NUL
+ colnr_T col;
+ linenr_T lnum = curwin->w_cursor.lnum;
+ int i;
+
+ /* Break tabs if needed. */
+ if (virtual_active() && curwin->w_cursor.coladd > 0)
+ coladvance_force(getviscol());
+
+ col = curwin->w_cursor.col;
+ oldp = ml_get(lnum);
+ linelen = (int)STRLEN(oldp) + 1;
+
+ /* The lengths default to the values for when not replacing. */
+ oldlen = 0;
+ newlen = charlen;
+
+ if (State & REPLACE_FLAG)
+ {
+ if (State & VREPLACE_FLAG)
+ {
+ colnr_T new_vcol = 0; /* init for GCC */
+ colnr_T vcol;
+ int old_list;
+
+ /*
+ * Disable 'list' temporarily, unless 'cpo' contains the 'L' flag.
+ * Returns the old value of list, so when finished,
+ * curwin->w_p_list should be set back to this.
+ */
+ old_list = curwin->w_p_list;
+ if (old_list && vim_strchr(p_cpo, CPO_LISTWM) == NULL)
+ curwin->w_p_list = FALSE;
+
+ /*
+ * In virtual replace mode each character may replace one or more
+ * characters (zero if it's a TAB). Count the number of bytes to
+ * be deleted to make room for the new character, counting screen
+ * cells. May result in adding spaces to fill a gap.
+ */
+ getvcol(curwin, &curwin->w_cursor, NULL, &vcol, NULL);
+ new_vcol = vcol + chartabsize(buf, vcol);
+ while (oldp[col + oldlen] != NUL && vcol < new_vcol)
+ {
+ vcol += chartabsize(oldp + col + oldlen, vcol);
+ /* Don't need to remove a TAB that takes us to the right
+ * position. */
+ if (vcol > new_vcol && oldp[col + oldlen] == TAB)
+ break;
+ oldlen += (*mb_ptr2len)(oldp + col + oldlen);
+ /* Deleted a bit too much, insert spaces. */
+ if (vcol > new_vcol)
+ newlen += vcol - new_vcol;
+ }
+ curwin->w_p_list = old_list;
+ }
+ else if (oldp[col] != NUL)
+ {
+ /* normal replace */
+ oldlen = (*mb_ptr2len)(oldp + col);
+ }
+
+
+ /* Push the replaced bytes onto the replace stack, so that they can be
+ * put back when BS is used. The bytes of a multi-byte character are
+ * done the other way around, so that the first byte is popped off
+ * first (it tells the byte length of the character). */
+ replace_push(NUL);
+ for (i = 0; i < oldlen; ++i)
+ {
+ if (has_mbyte)
+ i += replace_push_mb(oldp + col + i) - 1;
+ else
+ replace_push(oldp[col + i]);
+ }
+ }
+
+ newp = alloc_check((unsigned)(linelen + newlen - oldlen));
+ if (newp == NULL)
+ return;
+
+ /* Copy bytes before the cursor. */
+ if (col > 0)
+ mch_memmove(newp, oldp, (size_t)col);
+
+ /* Copy bytes after the changed character(s). */
+ p = newp + col;
+ if (linelen > col + oldlen)
+ mch_memmove(p + newlen, oldp + col + oldlen,
+ (size_t)(linelen - col - oldlen));
+
+ /* Insert or overwrite the new character. */
+ mch_memmove(p, buf, charlen);
+ i = charlen;
+
+ /* Fill with spaces when necessary. */
+ while (i < newlen)
+ p[i++] = ' ';
+
+ // Replace the line in the buffer.
+ ml_replace(lnum, newp, FALSE);
+
+ // mark the buffer as changed and prepare for displaying
+ inserted_bytes(lnum, col, newlen - oldlen);
+
+ /*
+ * If we're in Insert or Replace mode and 'showmatch' is set, then briefly
+ * show the match for right parens and braces.
+ */
+ if (p_sm && (State & INSERT)
+ && msg_silent == 0
+#ifdef FEAT_INS_EXPAND
+ && !ins_compl_active()
+#endif
+ )
+ {
+ if (has_mbyte)
+ showmatch(mb_ptr2char(buf));
+ else
+ showmatch(c);
+ }
+
+#ifdef FEAT_RIGHTLEFT
+ if (!p_ri || (State & REPLACE_FLAG))
+#endif
+ {
+ /* Normal insert: move cursor right */
+ curwin->w_cursor.col += charlen;
+ }
+ /*
+ * TODO: should try to update w_row here, to avoid recomputing it later.
+ */
+}
+
+/*
+ * Insert a string at the cursor position.
+ * Note: Does NOT handle Replace mode.
+ * Caller must have prepared for undo.
+ */
+ void
+ins_str(char_u *s)
+{
+ char_u *oldp, *newp;
+ int newlen = (int)STRLEN(s);
+ int oldlen;
+ colnr_T col;
+ linenr_T lnum = curwin->w_cursor.lnum;
+
+ if (virtual_active() && curwin->w_cursor.coladd > 0)
+ coladvance_force(getviscol());
+
+ col = curwin->w_cursor.col;
+ oldp = ml_get(lnum);
+ oldlen = (int)STRLEN(oldp);
+
+ newp = alloc_check((unsigned)(oldlen + newlen + 1));
+ if (newp == NULL)
+ return;
+ if (col > 0)
+ mch_memmove(newp, oldp, (size_t)col);
+ mch_memmove(newp + col, s, (size_t)newlen);
+ mch_memmove(newp + col + newlen, oldp + col, (size_t)(oldlen - col + 1));
+ ml_replace(lnum, newp, FALSE);
+ inserted_bytes(lnum, col, newlen);
+ curwin->w_cursor.col += newlen;
+}
+
+/*
+ * Delete one character under the cursor.
+ * If "fixpos" is TRUE, don't leave the cursor on the NUL after the line.
+ * Caller must have prepared for undo.
+ *
+ * return FAIL for failure, OK otherwise
+ */
+ int
+del_char(int fixpos)
+{
+ if (has_mbyte)
+ {
+ /* Make sure the cursor is at the start of a character. */
+ mb_adjust_cursor();
+ if (*ml_get_cursor() == NUL)
+ return FAIL;
+ return del_chars(1L, fixpos);
+ }
+ return del_bytes(1L, fixpos, TRUE);
+}
+
+/*
+ * Like del_bytes(), but delete characters instead of bytes.
+ */
+ int
+del_chars(long count, int fixpos)
+{
+ long bytes = 0;
+ long i;
+ char_u *p;
+ int l;
+
+ p = ml_get_cursor();
+ for (i = 0; i < count && *p != NUL; ++i)
+ {
+ l = (*mb_ptr2len)(p);
+ bytes += l;
+ p += l;
+ }
+ return del_bytes(bytes, fixpos, TRUE);
+}
+
+/*
+ * Delete "count" bytes under the cursor.
+ * If "fixpos" is TRUE, don't leave the cursor on the NUL after the line.
+ * Caller must have prepared for undo.
+ *
+ * Return FAIL for failure, OK otherwise.
+ */
+ int
+del_bytes(
+ long count,
+ int fixpos_arg,
+ int use_delcombine UNUSED) /* 'delcombine' option applies */
+{
+ char_u *oldp, *newp;
+ colnr_T oldlen;
+ colnr_T newlen;
+ linenr_T lnum = curwin->w_cursor.lnum;
+ colnr_T col = curwin->w_cursor.col;
+ int alloc_newp;
+ long movelen;
+ int fixpos = fixpos_arg;
+
+ oldp = ml_get(lnum);
+ oldlen = (int)STRLEN(oldp);
+
+ /* Can't do anything when the cursor is on the NUL after the line. */
+ if (col >= oldlen)
+ return FAIL;
+
+ /* If "count" is zero there is nothing to do. */
+ if (count == 0)
+ return OK;
+
+ /* If "count" is negative the caller must be doing something wrong. */
+ if (count < 1)
+ {
+ siemsg("E950: Invalid count for del_bytes(): %ld", count);
+ return FAIL;
+ }
+
+ /* If 'delcombine' is set and deleting (less than) one character, only
+ * delete the last combining character. */
+ if (p_deco && use_delcombine && enc_utf8
+ && utfc_ptr2len(oldp + col) >= count)
+ {
+ int cc[MAX_MCO];
+ int n;
+
+ (void)utfc_ptr2char(oldp + col, cc);
+ if (cc[0] != NUL)
+ {
+ /* Find the last composing char, there can be several. */
+ n = col;
+ do
+ {
+ col = n;
+ count = utf_ptr2len(oldp + n);
+ n += count;
+ } while (UTF_COMPOSINGLIKE(oldp + col, oldp + n));
+ fixpos = 0;
+ }
+ }
+
+ /*
+ * When count is too big, reduce it.
+ */
+ movelen = (long)oldlen - (long)col - count + 1; /* includes trailing NUL */
+ if (movelen <= 1)
+ {
+ /*
+ * If we just took off the last character of a non-blank line, and
+ * fixpos is TRUE, we don't want to end up positioned at the NUL,
+ * unless "restart_edit" is set or 'virtualedit' contains "onemore".
+ */
+ if (col > 0 && fixpos && restart_edit == 0
+ && (ve_flags & VE_ONEMORE) == 0)
+ {
+ --curwin->w_cursor.col;
+ curwin->w_cursor.coladd = 0;
+ if (has_mbyte)
+ curwin->w_cursor.col -=
+ (*mb_head_off)(oldp, oldp + curwin->w_cursor.col);
+ }
+ count = oldlen - col;
+ movelen = 1;
+ }
+ newlen = oldlen - count;
+
+ /*
+ * If the old line has been allocated the deletion can be done in the
+ * existing line. Otherwise a new line has to be allocated
+ * Can't do this when using Netbeans, because we would need to invoke
+ * netbeans_removed(), which deallocates the line. Let ml_replace() take
+ * care of notifying Netbeans.
+ */
+#ifdef FEAT_NETBEANS_INTG
+ if (netbeans_active())
+ alloc_newp = TRUE;
+ else
+#endif
+ alloc_newp = !ml_line_alloced(); // check if oldp was allocated
+ if (!alloc_newp)
+ newp = oldp; // use same allocated memory
+ else
+ { // need to allocate a new line
+ newp = alloc((unsigned)(newlen + 1));
+ if (newp == NULL)
+ return FAIL;
+ mch_memmove(newp, oldp, (size_t)col);
+ }
+ mch_memmove(newp + col, oldp + col + count, (size_t)movelen);
+ if (alloc_newp)
+ ml_replace(lnum, newp, FALSE);
+#ifdef FEAT_TEXT_PROP
+ else
+ {
+ // Also move any following text properties.
+ if (oldlen + 1 < curbuf->b_ml.ml_line_len)
+ mch_memmove(newp + newlen + 1, oldp + oldlen + 1,
+ (size_t)curbuf->b_ml.ml_line_len - oldlen - 1);
+ curbuf->b_ml.ml_line_len -= count;
+ }
+#endif
+
+ // mark the buffer as changed and prepare for displaying
+ inserted_bytes(lnum, curwin->w_cursor.col, -count);
+
+ return OK;
+}
+
+/*
+ * Delete from cursor to end of line.
+ * Caller must have prepared for undo.
+ *
+ * return FAIL for failure, OK otherwise
+ */
+ int
+truncate_line(
+ int fixpos) /* if TRUE fix the cursor position when done */
+{
+ char_u *newp;
+ linenr_T lnum = curwin->w_cursor.lnum;
+ colnr_T col = curwin->w_cursor.col;
+
+ if (col == 0)
+ newp = vim_strsave((char_u *)"");
+ else
+ newp = vim_strnsave(ml_get(lnum), col);
+
+ if (newp == NULL)
+ return FAIL;
+
+ ml_replace(lnum, newp, FALSE);
+
+ /* mark the buffer as changed and prepare for displaying */
+ changed_bytes(lnum, curwin->w_cursor.col);
+
+ /*
+ * If "fixpos" is TRUE we don't want to end up positioned at the NUL.
+ */
+ if (fixpos && curwin->w_cursor.col > 0)
+ --curwin->w_cursor.col;
+
+ return OK;
+}
+
+/*
+ * Delete "nlines" lines at the cursor.
+ * Saves the lines for undo first if "undo" is TRUE.
+ */
+ void
+del_lines(
+ long nlines, /* number of lines to delete */
+ int undo) /* if TRUE, prepare for undo */
+{
+ long n;
+ linenr_T first = curwin->w_cursor.lnum;
+
+ if (nlines <= 0)
+ return;
+
+ /* save the deleted lines for undo */
+ if (undo && u_savedel(first, nlines) == FAIL)
+ return;
+
+ for (n = 0; n < nlines; )
+ {
+ if (curbuf->b_ml.ml_flags & ML_EMPTY) /* nothing to delete */
+ break;
+
+ ml_delete(first, TRUE);
+ ++n;
+
+ /* If we delete the last line in the file, stop */
+ if (first > curbuf->b_ml.ml_line_count)
+ break;
+ }
+
+ /* Correct the cursor position before calling deleted_lines_mark(), it may
+ * trigger a callback to display the cursor. */
+ curwin->w_cursor.col = 0;
+ check_cursor_lnum();
+
+ /* adjust marks, mark the buffer as changed and prepare for displaying */
+ deleted_lines_mark(first, n);
+}
+
+ int
+gchar_pos(pos_T *pos)
+{
+ char_u *ptr;
+
+ /* When searching columns is sometimes put at the end of a line. */
+ if (pos->col == MAXCOL)
+ return NUL;
+ ptr = ml_get_pos(pos);
+ if (has_mbyte)
+ return (*mb_ptr2char)(ptr);
+ return (int)*ptr;
+}
+
+ int
+gchar_cursor(void)
+{
+ if (has_mbyte)
+ return (*mb_ptr2char)(ml_get_cursor());
+ return (int)*ml_get_cursor();
+}
+
+/*
+ * Write a character at the current cursor position.
+ * It is directly written into the block.
+ */
+ void
+pchar_cursor(int c)
+{
+ *(ml_get_buf(curbuf, curwin->w_cursor.lnum, TRUE)
+ + curwin->w_cursor.col) = c;
+}
+
+/*
+ * When extra == 0: Return TRUE if the cursor is before or on the first
+ * non-blank in the line.
+ * When extra == 1: Return TRUE if the cursor is before the first non-blank in
+ * the line.
+ */
+ int
+inindent(int extra)
+{
+ char_u *ptr;
+ colnr_T col;
+
+ for (col = 0, ptr = ml_get_curline(); VIM_ISWHITE(*ptr); ++col)
+ ++ptr;
+ if (col >= curwin->w_cursor.col + extra)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+/*
+ * Skip to next part of an option argument: Skip space and comma.
+ */
+ char_u *
+skip_to_option_part(char_u *p)
+{
+ if (*p == ',')
+ ++p;
+ while (*p == ' ')
+ ++p;
+ return p;
+}
+
+/*
+ * Call this function when something in the current buffer is changed.
+ *
+ * Most often called through changed_bytes() and changed_lines(), which also
+ * mark the area of the display to be redrawn.
+ *
+ * Careful: may trigger autocommands that reload the buffer.
+ */
+ void
+changed(void)
+{
+#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
+ if (p_imst == IM_ON_THE_SPOT)
+ {
+ /* The text of the preediting area is inserted, but this doesn't
+ * mean a change of the buffer yet. That is delayed until the
+ * text is committed. (this means preedit becomes empty) */
+ if (im_is_preediting() && !xim_changed_while_preediting)
+ return;
+ xim_changed_while_preediting = FALSE;
+ }
+#endif
+
+ if (!curbuf->b_changed)
+ {
+ int save_msg_scroll = msg_scroll;
+
+ /* Give a warning about changing a read-only file. This may also
+ * check-out the file, thus change "curbuf"! */
+ change_warning(0);
+
+ /* Create a swap file if that is wanted.
+ * Don't do this for "nofile" and "nowrite" buffer types. */
+ if (curbuf->b_may_swap
+#ifdef FEAT_QUICKFIX
+ && !bt_dontwrite(curbuf)
+#endif
+ )
+ {
+ int save_need_wait_return = need_wait_return;
+
+ need_wait_return = FALSE;
+ ml_open_file(curbuf);
+
+ /* The ml_open_file() can cause an ATTENTION message.
+ * Wait two seconds, to make sure the user reads this unexpected
+ * message. Since we could be anywhere, call wait_return() now,
+ * and don't let the emsg() set msg_scroll. */
+ if (need_wait_return && emsg_silent == 0)
+ {
+ out_flush();
+ ui_delay(2000L, TRUE);
+ wait_return(TRUE);
+ msg_scroll = save_msg_scroll;
+ }
+ else
+ need_wait_return = save_need_wait_return;
+ }
+ changed_int();
+ }
+ ++CHANGEDTICK(curbuf);
+}
+
+/*
+ * Internal part of changed(), no user interaction.
+ */
+ void
+changed_int(void)
+{
+ curbuf->b_changed = TRUE;
+ ml_setflags(curbuf);
+ check_status(curbuf);
+ redraw_tabline = TRUE;
+#ifdef FEAT_TITLE
+ need_maketitle = TRUE; /* set window title later */
+#endif
+}
+
+static void changedOneline(buf_T *buf, linenr_T lnum);
+static void changed_lines_buf(buf_T *buf, linenr_T lnum, linenr_T lnume, long xtra);
+static void changed_common(linenr_T lnum, colnr_T col, linenr_T lnume, long xtra);
+
+/*
+ * Changed bytes within a single line for the current buffer.
+ * - marks the windows on this buffer to be redisplayed
+ * - marks the buffer changed by calling changed()
+ * - invalidates cached values
+ * Careful: may trigger autocommands that reload the buffer.
+ */
+ void
+changed_bytes(linenr_T lnum, colnr_T col)
+{
+ changedOneline(curbuf, lnum);
+ changed_common(lnum, col, lnum + 1, 0L);
+
+#ifdef FEAT_DIFF
+ /* Diff highlighting in other diff windows may need to be updated too. */
+ if (curwin->w_p_diff)
+ {
+ win_T *wp;
+ linenr_T wlnum;
+
+ FOR_ALL_WINDOWS(wp)
+ if (wp->w_p_diff && wp != curwin)
+ {
+ redraw_win_later(wp, VALID);
+ wlnum = diff_lnum_win(lnum, wp);
+ if (wlnum > 0)
+ changedOneline(wp->w_buffer, wlnum);
+ }
+ }
+#endif
+}
+
+/*
+ * Like changed_bytes() but also adjust text properties for "added" bytes.
+ * When "added" is negative text was deleted.
+ */
+ void
+inserted_bytes(linenr_T lnum, colnr_T col, int added UNUSED)
+{
+ changed_bytes(lnum, col);
+
+#ifdef FEAT_TEXT_PROP
+ if (curbuf->b_has_textprop && added != 0)
+ adjust_prop_columns(lnum, col, added);
+#endif
+}
+
+ static void
+changedOneline(buf_T *buf, linenr_T lnum)
+{
+ if (buf->b_mod_set)
+ {
+ /* find the maximum area that must be redisplayed */
+ if (lnum < buf->b_mod_top)
+ buf->b_mod_top = lnum;
+ else if (lnum >= buf->b_mod_bot)
+ buf->b_mod_bot = lnum + 1;
+ }
+ else
+ {
+ /* set the area that must be redisplayed to one line */
+ buf->b_mod_set = TRUE;
+ buf->b_mod_top = lnum;
+ buf->b_mod_bot = lnum + 1;
+ buf->b_mod_xlines = 0;
+ }
+}
+
+/*
+ * Appended "count" lines below line "lnum" in the current buffer.
+ * Must be called AFTER the change and after mark_adjust().
+ * Takes care of marking the buffer to be redrawn and sets the changed flag.
+ */
+ void
+appended_lines(linenr_T lnum, long count)
+{
+ changed_lines(lnum + 1, 0, lnum + 1, count);
+}
+
+/*
+ * Like appended_lines(), but adjust marks first.
+ */
+ void
+appended_lines_mark(linenr_T lnum, long count)
+{
+ /* Skip mark_adjust when adding a line after the last one, there can't
+ * be marks there. But it's still needed in diff mode. */
+ if (lnum + count < curbuf->b_ml.ml_line_count
+#ifdef FEAT_DIFF
+ || curwin->w_p_diff
+#endif
+ )
+ mark_adjust(lnum + 1, (linenr_T)MAXLNUM, count, 0L);
+ changed_lines(lnum + 1, 0, lnum + 1, count);
+}
+
+/*
+ * Deleted "count" lines at line "lnum" in the current buffer.
+ * Must be called AFTER the change and after mark_adjust().
+ * Takes care of marking the buffer to be redrawn and sets the changed flag.
+ */
+ void
+deleted_lines(linenr_T lnum, long count)
+{
+ changed_lines(lnum, 0, lnum + count, -count);
+}
+
+/*
+ * Like deleted_lines(), but adjust marks first.
+ * Make sure the cursor is on a valid line before calling, a GUI callback may
+ * be triggered to display the cursor.
+ */
+ void
+deleted_lines_mark(linenr_T lnum, long count)
+{
+ mark_adjust(lnum, (linenr_T)(lnum + count - 1), (long)MAXLNUM, -count);
+ changed_lines(lnum, 0, lnum + count, -count);
+}
+
+/*
+ * Changed lines for the current buffer.
+ * Must be called AFTER the change and after mark_adjust().
+ * - mark the buffer changed by calling changed()
+ * - mark the windows on this buffer to be redisplayed
+ * - invalidate cached values
+ * "lnum" is the first line that needs displaying, "lnume" the first line
+ * below the changed lines (BEFORE the change).
+ * When only inserting lines, "lnum" and "lnume" are equal.
+ * Takes care of calling changed() and updating b_mod_*.
+ * Careful: may trigger autocommands that reload the buffer.
+ */
+ void
+changed_lines(
+ linenr_T lnum, /* first line with change */
+ colnr_T col, /* column in first line with change */
+ linenr_T lnume, /* line below last changed line */
+ long xtra) /* number of extra lines (negative when deleting) */
+{
+ changed_lines_buf(curbuf, lnum, lnume, xtra);
+
+#ifdef FEAT_DIFF
+ if (xtra == 0 && curwin->w_p_diff && !diff_internal())
+ {
+ /* When the number of lines doesn't change then mark_adjust() isn't
+ * called and other diff buffers still need to be marked for
+ * displaying. */
+ win_T *wp;
+ linenr_T wlnum;
+
+ FOR_ALL_WINDOWS(wp)
+ if (wp->w_p_diff && wp != curwin)
+ {
+ redraw_win_later(wp, VALID);
+ wlnum = diff_lnum_win(lnum, wp);
+ if (wlnum > 0)
+ changed_lines_buf(wp->w_buffer, wlnum,
+ lnume - lnum + wlnum, 0L);
+ }
+ }
+#endif
+
+ changed_common(lnum, col, lnume, xtra);
+}
+
+ static void
+changed_lines_buf(
+ buf_T *buf,
+ linenr_T lnum, /* first line with change */
+ linenr_T lnume, /* line below last changed line */
+ long xtra) /* number of extra lines (negative when deleting) */
+{
+ if (buf->b_mod_set)
+ {
+ /* find the maximum area that must be redisplayed */
+ if (lnum < buf->b_mod_top)
+ buf->b_mod_top = lnum;
+ if (lnum < buf->b_mod_bot)
+ {
+ /* adjust old bot position for xtra lines */
+ buf->b_mod_bot += xtra;
+ if (buf->b_mod_bot < lnum)
+ buf->b_mod_bot = lnum;
+ }
+ if (lnume + xtra > buf->b_mod_bot)
+ buf->b_mod_bot = lnume + xtra;
+ buf->b_mod_xlines += xtra;
+ }
+ else
+ {
+ /* set the area that must be redisplayed */
+ buf->b_mod_set = TRUE;
+ buf->b_mod_top = lnum;
+ buf->b_mod_bot = lnume + xtra;
+ buf->b_mod_xlines = xtra;
+ }
+}
+
+/*
+ * Common code for when a change is was made.
+ * See changed_lines() for the arguments.
+ * Careful: may trigger autocommands that reload the buffer.
+ */
+ static void
+changed_common(
+ linenr_T lnum,
+ colnr_T col,
+ linenr_T lnume,
+ long xtra)
+{
+ win_T *wp;
+ tabpage_T *tp;
+ int i;
+#ifdef FEAT_JUMPLIST
+ int cols;
+ pos_T *p;
+ int add;
+#endif
+
+ /* mark the buffer as modified */
+ changed();
+
+#ifdef FEAT_DIFF
+ if (curwin->w_p_diff && diff_internal())
+ curtab->tp_diff_update = TRUE;
+#endif
+
+ /* set the '. mark */
+ if (!cmdmod.keepjumps)
+ {
+ curbuf->b_last_change.lnum = lnum;
+ curbuf->b_last_change.col = col;
+
+#ifdef FEAT_JUMPLIST
+ /* Create a new entry if a new undo-able change was started or we
+ * don't have an entry yet. */
+ if (curbuf->b_new_change || curbuf->b_changelistlen == 0)
+ {
+ if (curbuf->b_changelistlen == 0)
+ add = TRUE;
+ else
+ {
+ /* Don't create a new entry when the line number is the same
+ * as the last one and the column is not too far away. Avoids
+ * creating many entries for typing "xxxxx". */
+ p = &curbuf->b_changelist[curbuf->b_changelistlen - 1];
+ if (p->lnum != lnum)
+ add = TRUE;
+ else
+ {
+ cols = comp_textwidth(FALSE);
+ if (cols == 0)
+ cols = 79;
+ add = (p->col + cols < col || col + cols < p->col);
+ }
+ }
+ if (add)
+ {
+ /* This is the first of a new sequence of undo-able changes
+ * and it's at some distance of the last change. Use a new
+ * position in the changelist. */
+ curbuf->b_new_change = FALSE;
+
+ if (curbuf->b_changelistlen == JUMPLISTSIZE)
+ {
+ /* changelist is full: remove oldest entry */
+ curbuf->b_changelistlen = JUMPLISTSIZE - 1;
+ mch_memmove(curbuf->b_changelist, curbuf->b_changelist + 1,
+ sizeof(pos_T) * (JUMPLISTSIZE - 1));
+ FOR_ALL_TAB_WINDOWS(tp, wp)
+ {
+ /* Correct position in changelist for other windows on
+ * this buffer. */
+ if (wp->w_buffer == curbuf && wp->w_changelistidx > 0)
+ --wp->w_changelistidx;
+ }
+ }
+ FOR_ALL_TAB_WINDOWS(tp, wp)
+ {
+ /* For other windows, if the position in the changelist is
+ * at the end it stays at the end. */
+ if (wp->w_buffer == curbuf
+ && wp->w_changelistidx == curbuf->b_changelistlen)
+ ++wp->w_changelistidx;
+ }
+ ++curbuf->b_changelistlen;
+ }
+ }
+ curbuf->b_changelist[curbuf->b_changelistlen - 1] =
+ curbuf->b_last_change;
+ /* The current window is always after the last change, so that "g,"
+ * takes you back to it. */
+ curwin->w_changelistidx = curbuf->b_changelistlen;
+#endif
+ }
+
+ FOR_ALL_TAB_WINDOWS(tp, wp)
+ {
+ if (wp->w_buffer == curbuf)
+ {
+ /* Mark this window to be redrawn later. */
+ if (wp->w_redr_type < VALID)
+ wp->w_redr_type = VALID;
+
+ /* Check if a change in the buffer has invalidated the cached
+ * values for the cursor. */
+#ifdef FEAT_FOLDING
+ /*
+ * Update the folds for this window. Can't postpone this, because
+ * a following operator might work on the whole fold: ">>dd".
+ */
+ foldUpdate(wp, lnum, lnume + xtra - 1);
+
+ /* The change may cause lines above or below the change to become
+ * included in a fold. Set lnum/lnume to the first/last line that
+ * might be displayed differently.
+ * Set w_cline_folded here as an efficient way to update it when
+ * inserting lines just above a closed fold. */
+ i = hasFoldingWin(wp, lnum, &lnum, NULL, FALSE, NULL);
+ if (wp->w_cursor.lnum == lnum)
+ wp->w_cline_folded = i;
+ i = hasFoldingWin(wp, lnume, NULL, &lnume, FALSE, NULL);
+ if (wp->w_cursor.lnum == lnume)
+ wp->w_cline_folded = i;
+
+ /* If the changed line is in a range of previously folded lines,
+ * compare with the first line in that range. */
+ if (wp->w_cursor.lnum <= lnum)
+ {
+ i = find_wl_entry(wp, lnum);
+ if (i >= 0 && wp->w_cursor.lnum > wp->w_lines[i].wl_lnum)
+ changed_line_abv_curs_win(wp);
+ }
+#endif
+
+ if (wp->w_cursor.lnum > lnum)
+ changed_line_abv_curs_win(wp);
+ else if (wp->w_cursor.lnum == lnum && wp->w_cursor.col >= col)
+ changed_cline_bef_curs_win(wp);
+ if (wp->w_botline >= lnum)
+ {
+ /* Assume that botline doesn't change (inserted lines make
+ * other lines scroll down below botline). */
+ approximate_botline_win(wp);
+ }
+
+ /* Check if any w_lines[] entries have become invalid.
+ * For entries below the change: Correct the lnums for
+ * inserted/deleted lines. Makes it possible to stop displaying
+ * after the change. */
+ for (i = 0; i < wp->w_lines_valid; ++i)
+ if (wp->w_lines[i].wl_valid)
+ {
+ if (wp->w_lines[i].wl_lnum >= lnum)
+ {
+ if (wp->w_lines[i].wl_lnum < lnume)
+ {
+ /* line included in change */
+ wp->w_lines[i].wl_valid = FALSE;
+ }
+ else if (xtra != 0)
+ {
+ /* line below change */
+ wp->w_lines[i].wl_lnum += xtra;
+#ifdef FEAT_FOLDING
+ wp->w_lines[i].wl_lastlnum += xtra;
+#endif
+ }
+ }
+#ifdef FEAT_FOLDING
+ else if (wp->w_lines[i].wl_lastlnum >= lnum)
+ {
+ /* change somewhere inside this range of folded lines,
+ * may need to be redrawn */
+ wp->w_lines[i].wl_valid = FALSE;
+ }
+#endif
+ }
+
+#ifdef FEAT_FOLDING
+ /* Take care of side effects for setting w_topline when folds have
+ * changed. Esp. when the buffer was changed in another window. */
+ if (hasAnyFolding(wp))
+ set_topline(wp, wp->w_topline);
+#endif
+ /* relative numbering may require updating more */
+ if (wp->w_p_rnu)
+ redraw_win_later(wp, SOME_VALID);
+ }
+ }
+
+ /* Call update_screen() later, which checks out what needs to be redrawn,
+ * since it notices b_mod_set and then uses b_mod_*. */
+ if (must_redraw < VALID)
+ must_redraw = VALID;
+
+ /* when the cursor line is changed always trigger CursorMoved */
+ if (lnum <= curwin->w_cursor.lnum
+ && lnume + (xtra < 0 ? -xtra : xtra) > curwin->w_cursor.lnum)
+ last_cursormoved.lnum = 0;
+}
+
+/*
+ * unchanged() is called when the changed flag must be reset for buffer 'buf'
+ */
+ void
+unchanged(
+ buf_T *buf,
+ int ff) /* also reset 'fileformat' */
+{
+ if (buf->b_changed || (ff && file_ff_differs(buf, FALSE)))
+ {
+ buf->b_changed = 0;
+ ml_setflags(buf);
+ if (ff)
+ save_file_ff(buf);
+ check_status(buf);
+ redraw_tabline = TRUE;
+#ifdef FEAT_TITLE
+ need_maketitle = TRUE; /* set window title later */
+#endif
+ }
+ ++CHANGEDTICK(buf);
+#ifdef FEAT_NETBEANS_INTG
+ netbeans_unmodified(buf);
+#endif
+}
+
+/*
+ * check_status: called when the status bars for the buffer 'buf'
+ * need to be updated
+ */
+ void
+check_status(buf_T *buf)
+{
+ win_T *wp;
+
+ FOR_ALL_WINDOWS(wp)
+ if (wp->w_buffer == buf && wp->w_status_height)
+ {
+ wp->w_redr_status = TRUE;
+ if (must_redraw < VALID)
+ must_redraw = VALID;
+ }
+}
+
+/*
+ * If the file is readonly, give a warning message with the first change.
+ * Don't do this for autocommands.
+ * Don't use emsg(), because it flushes the macro buffer.
+ * If we have undone all changes b_changed will be FALSE, but "b_did_warn"
+ * will be TRUE.
+ * Careful: may trigger autocommands that reload the buffer.
+ */
+ void
+change_warning(
+ int col) /* column for message; non-zero when in insert
+ mode and 'showmode' is on */
+{
+ static char *w_readonly = N_("W10: Warning: Changing a readonly file");
+
+ if (curbuf->b_did_warn == FALSE
+ && curbufIsChanged() == 0
+ && !autocmd_busy
+ && curbuf->b_p_ro)
+ {
+ ++curbuf_lock;
+ apply_autocmds(EVENT_FILECHANGEDRO, NULL, NULL, FALSE, curbuf);
+ --curbuf_lock;
+ if (!curbuf->b_p_ro)
+ return;
+ /*
+ * Do what msg() does, but with a column offset if the warning should
+ * be after the mode message.
+ */
+ msg_start();
+ if (msg_row == Rows - 1)
+ msg_col = col;
+ msg_source(HL_ATTR(HLF_W));
+ msg_puts_attr(_(w_readonly), HL_ATTR(HLF_W) | MSG_HIST);
+#ifdef FEAT_EVAL
+ set_vim_var_string(VV_WARNINGMSG, (char_u *)_(w_readonly), -1);
+#endif
+ msg_clr_eos();
+ (void)msg_end();
+ if (msg_silent == 0 && !silent_mode
+#ifdef FEAT_EVAL
+ && time_for_testing != 1
+#endif
+ )
+ {
+ out_flush();
+ ui_delay(1000L, TRUE); /* give the user time to think about it */
+ }
+ curbuf->b_did_warn = TRUE;
+ redraw_cmdline = FALSE; /* don't redraw and erase the message */
+ if (msg_row < Rows - 1)
+ showmode();
+ }
+}
+
+/*
+ * Ask for a reply from the user, a 'y' or a 'n'.
+ * No other characters are accepted, the message is repeated until a valid
+ * reply is entered or CTRL-C is hit.
+ * If direct is TRUE, don't use vgetc() but ui_inchar(), don't get characters
+ * from any buffers but directly from the user.
+ *
+ * return the 'y' or 'n'
+ */
+ int
+ask_yesno(char_u *str, int direct)
+{
+ int r = ' ';
+ int save_State = State;
+
+ if (exiting) /* put terminal in raw mode for this question */
+ settmode(TMODE_RAW);
+ ++no_wait_return;
+#ifdef USE_ON_FLY_SCROLL
+ dont_scroll = TRUE; /* disallow scrolling here */
+#endif
+ State = CONFIRM; /* mouse behaves like with :confirm */
+#ifdef FEAT_MOUSE
+ setmouse(); /* disables mouse for xterm */
+#endif
+ ++no_mapping;
+ ++allow_keys; /* no mapping here, but recognize keys */
+
+ while (r != 'y' && r != 'n')
+ {
+ /* same highlighting as for wait_return */
+ smsg_attr(HL_ATTR(HLF_R), "%s (y/n)?", str);
+ if (direct)
+ r = get_keystroke();
+ else
+ r = plain_vgetc();
+ if (r == Ctrl_C || r == ESC)
+ r = 'n';
+ msg_putchar(r); /* show what you typed */
+ out_flush();
+ }
+ --no_wait_return;
+ State = save_State;
+#ifdef FEAT_MOUSE
+ setmouse();
+#endif
+ --no_mapping;
+ --allow_keys;
+
+ return r;
+}
+
+#if defined(FEAT_MOUSE) || defined(PROTO)
+/*
+ * Return TRUE if "c" is a mouse key.
+ */
+ int
+is_mouse_key(int c)
+{
+ return c == K_LEFTMOUSE
+ || c == K_LEFTMOUSE_NM
+ || c == K_LEFTDRAG
+ || c == K_LEFTRELEASE
+ || c == K_LEFTRELEASE_NM
+ || c == K_MOUSEMOVE
+ || c == K_MIDDLEMOUSE
+ || c == K_MIDDLEDRAG
+ || c == K_MIDDLERELEASE
+ || c == K_RIGHTMOUSE
+ || c == K_RIGHTDRAG
+ || c == K_RIGHTRELEASE
+ || c == K_MOUSEDOWN
+ || c == K_MOUSEUP
+ || c == K_MOUSELEFT
+ || c == K_MOUSERIGHT
+ || c == K_X1MOUSE
+ || c == K_X1DRAG
+ || c == K_X1RELEASE
+ || c == K_X2MOUSE
+ || c == K_X2DRAG
+ || c == K_X2RELEASE;
+}
+#endif
+
+/*
+ * Get a key stroke directly from the user.
+ * Ignores mouse clicks and scrollbar events, except a click for the left
+ * button (used at the more prompt).
+ * Doesn't use vgetc(), because it syncs undo and eats mapped characters.
+ * Disadvantage: typeahead is ignored.
+ * Translates the interrupt character for unix to ESC.
+ */
+ int
+get_keystroke(void)
+{
+ char_u *buf = NULL;
+ int buflen = 150;
+ int maxlen;
+ int len = 0;
+ int n;
+ int save_mapped_ctrl_c = mapped_ctrl_c;
+ int waited = 0;
+
+ mapped_ctrl_c = FALSE; /* mappings are not used here */
+ for (;;)
+ {
+ cursor_on();
+ out_flush();
+
+ /* Leave some room for check_termcode() to insert a key code into (max
+ * 5 chars plus NUL). And fix_input_buffer() can triple the number of
+ * bytes. */
+ maxlen = (buflen - 6 - len) / 3;
+ if (buf == NULL)
+ buf = alloc(buflen);
+ else if (maxlen < 10)
+ {
+ char_u *t_buf = buf;
+
+ /* Need some more space. This might happen when receiving a long
+ * escape sequence. */
+ buflen += 100;
+ buf = vim_realloc(buf, buflen);
+ if (buf == NULL)
+ vim_free(t_buf);
+ maxlen = (buflen - 6 - len) / 3;
+ }
+ if (buf == NULL)
+ {
+ do_outofmem_msg((long_u)buflen);
+ return ESC; /* panic! */
+ }
+
+ /* First time: blocking wait. Second time: wait up to 100ms for a
+ * terminal code to complete. */
+ n = ui_inchar(buf + len, maxlen, len == 0 ? -1L : 100L, 0);
+ if (n > 0)
+ {
+ /* Replace zero and CSI by a special key code. */
+ n = fix_input_buffer(buf + len, n);
+ len += n;
+ waited = 0;
+ }
+ else if (len > 0)
+ ++waited; /* keep track of the waiting time */
+
+ /* Incomplete termcode and not timed out yet: get more characters */
+ if ((n = check_termcode(1, buf, buflen, &len)) < 0
+ && (!p_ttimeout || waited * 100L < (p_ttm < 0 ? p_tm : p_ttm)))
+ continue;
+
+ if (n == KEYLEN_REMOVED) /* key code removed */
+ {
+ if (must_redraw != 0 && !need_wait_return && (State & CMDLINE) == 0)
+ {
+ /* Redrawing was postponed, do it now. */
+ update_screen(0);
+ setcursor(); /* put cursor back where it belongs */
+ }
+ continue;
+ }
+ if (n > 0) /* found a termcode: adjust length */
+ len = n;
+ if (len == 0) /* nothing typed yet */
+ continue;
+
+ /* Handle modifier and/or special key code. */
+ n = buf[0];
+ if (n == K_SPECIAL)
+ {
+ n = TO_SPECIAL(buf[1], buf[2]);
+ if (buf[1] == KS_MODIFIER
+ || n == K_IGNORE
+#ifdef FEAT_MOUSE
+ || (is_mouse_key(n) && n != K_LEFTMOUSE)
+#endif
+#ifdef FEAT_GUI
+ || n == K_VER_SCROLLBAR
+ || n == K_HOR_SCROLLBAR
+#endif
+ )
+ {
+ if (buf[1] == KS_MODIFIER)
+ mod_mask = buf[2];
+ len -= 3;
+ if (len > 0)
+ mch_memmove(buf, buf + 3, (size_t)len);
+ continue;
+ }
+ break;
+ }
+ if (has_mbyte)
+ {
+ if (MB_BYTE2LEN(n) > len)
+ continue; /* more bytes to get */
+ buf[len >= buflen ? buflen - 1 : len] = NUL;
+ n = (*mb_ptr2char)(buf);
+ }
+#ifdef UNIX
+ if (n == intr_char)
+ n = ESC;
+#endif
+ break;
+ }
+ vim_free(buf);
+
+ mapped_ctrl_c = save_mapped_ctrl_c;
+ return n;
+}
+
+/*
+ * Get a number from the user.
+ * When "mouse_used" is not NULL allow using the mouse.
+ */
+ int
+get_number(
+ int colon, /* allow colon to abort */
+ int *mouse_used)
+{
+ int n = 0;
+ int c;
+ int typed = 0;
+
+ if (mouse_used != NULL)
+ *mouse_used = FALSE;
+
+ /* When not printing messages, the user won't know what to type, return a
+ * zero (as if CR was hit). */
+ if (msg_silent != 0)
+ return 0;
+
+#ifdef USE_ON_FLY_SCROLL
+ dont_scroll = TRUE; /* disallow scrolling here */
+#endif
+ ++no_mapping;
+ ++allow_keys; /* no mapping here, but recognize keys */
+ for (;;)
+ {
+ windgoto(msg_row, msg_col);
+ c = safe_vgetc();
+ if (VIM_ISDIGIT(c))
+ {
+ n = n * 10 + c - '0';
+ msg_putchar(c);
+ ++typed;
+ }
+ else if (c == K_DEL || c == K_KDEL || c == K_BS || c == Ctrl_H)
+ {
+ if (typed > 0)
+ {
+ msg_puts("\b \b");
+ --typed;
+ }
+ n /= 10;
+ }
+#ifdef FEAT_MOUSE
+ else if (mouse_used != NULL && c == K_LEFTMOUSE)
+ {
+ *mouse_used = TRUE;
+ n = mouse_row + 1;
+ break;
+ }
+#endif
+ else if (n == 0 && c == ':' && colon)
+ {
+ stuffcharReadbuff(':');
+ if (!exmode_active)
+ cmdline_row = msg_row;
+ skip_redraw = TRUE; /* skip redraw once */
+ do_redraw = FALSE;
+ break;
+ }
+ else if (c == CAR || c == NL || c == Ctrl_C || c == ESC)
+ break;
+ }
+ --no_mapping;
+ --allow_keys;
+ return n;
+}
+
+/*
+ * Ask the user to enter a number.
+ * When "mouse_used" is not NULL allow using the mouse and in that case return
+ * the line number.
+ */
+ int
+prompt_for_number(int *mouse_used)
+{
+ int i;
+ int save_cmdline_row;
+ int save_State;
+
+ /* When using ":silent" assume that <CR> was entered. */
+ if (mouse_used != NULL)
+ msg_puts(_("Type number and <Enter> or click with mouse (empty cancels): "));
+ else
+ msg_puts(_("Type number and <Enter> (empty cancels): "));
+
+ // Set the state such that text can be selected/copied/pasted and we still
+ // get mouse events. redraw_after_callback() will not redraw if cmdline_row
+ // is zero.
+ save_cmdline_row = cmdline_row;
+ cmdline_row = 0;
+ save_State = State;
+ State = CMDLINE;
+#ifdef FEAT_MOUSE
+ // May show different mouse shape.
+ setmouse();
+#endif
+
+ i = get_number(TRUE, mouse_used);
+ if (KeyTyped)
+ {
+ /* don't call wait_return() now */
+ /* msg_putchar('\n'); */
+ cmdline_row = msg_row - 1;
+ need_wait_return = FALSE;
+ msg_didany = FALSE;
+ msg_didout = FALSE;
+ }
+ else
+ cmdline_row = save_cmdline_row;
+ State = save_State;
+#ifdef FEAT_MOUSE
+ // May need to restore mouse shape.
+ setmouse();
+#endif
+
+ return i;
+}
+
+ void
+msgmore(long n)
+{
+ long pn;
+
+ if (global_busy /* no messages now, wait until global is finished */
+ || !messaging()) /* 'lazyredraw' set, don't do messages now */
+ return;
+
+ /* We don't want to overwrite another important message, but do overwrite
+ * a previous "more lines" or "fewer lines" message, so that "5dd" and
+ * then "put" reports the last action. */
+ if (keep_msg != NULL && !keep_msg_more)
+ return;
+
+ if (n > 0)
+ pn = n;
+ else
+ pn = -n;
+
+ if (pn > p_report)
+ {
+ if (n > 0)
+ vim_snprintf(msg_buf, MSG_BUF_LEN,
+ NGETTEXT("%ld more line", "%ld more lines", pn), pn);
+ else
+ vim_snprintf(msg_buf, MSG_BUF_LEN,
+ NGETTEXT("%ld line less", "%ld fewer lines", pn), pn);
+ if (got_int)
+ vim_strcat((char_u *)msg_buf, (char_u *)_(" (Interrupted)"),
+ MSG_BUF_LEN);
+ if (msg(msg_buf))
+ {
+ set_keep_msg((char_u *)msg_buf, 0);
+ keep_msg_more = TRUE;
+ }
+ }
+}
+
+/*
+ * flush map and typeahead buffers and give a warning for an error
+ */
+ void
+beep_flush(void)
+{
+ if (emsg_silent == 0)
+ {
+ flush_buffers(FLUSH_MINIMAL);
+ vim_beep(BO_ERROR);
+ }
+}
+
+/*
+ * Give a warning for an error.
+ */
+ void
+vim_beep(
+ unsigned val) /* one of the BO_ values, e.g., BO_OPER */
+{
+#ifdef FEAT_EVAL
+ called_vim_beep = TRUE;
+#endif
+
+ if (emsg_silent == 0)
+ {
+ if (!((bo_flags & val) || (bo_flags & BO_ALL)))
+ {
+#ifdef ELAPSED_FUNC
+ static int did_init = FALSE;
+ static elapsed_T start_tv;
+
+ /* Only beep once per half a second, otherwise a sequence of beeps
+ * would freeze Vim. */
+ if (!did_init || ELAPSED_FUNC(start_tv) > 500)
+ {
+ did_init = TRUE;
+ ELAPSED_INIT(start_tv);
+#endif
+ if (p_vb
+#ifdef FEAT_GUI
+ /* While the GUI is starting up the termcap is set for
+ * the GUI but the output still goes to a terminal. */
+ && !(gui.in_use && gui.starting)
+#endif
+ )
+ {
+ out_str_cf(T_VB);
+#ifdef FEAT_VTP
+ /* No restore color information, refresh the screen. */
+ if (has_vtp_working() != 0
+# ifdef FEAT_TERMGUICOLORS
+ && (p_tgc || (!p_tgc && t_colors >= 256))
+# endif
+ )
+ {
+ redraw_later(CLEAR);
+ update_screen(0);
+ redrawcmd();
+ }
+#endif
+ }
+ else
+ out_char(BELL);
+#ifdef ELAPSED_FUNC
+ }
+#endif
+ }
+
+ /* When 'debug' contains "beep" produce a message. If we are sourcing
+ * a script or executing a function give the user a hint where the beep
+ * comes from. */
+ if (vim_strchr(p_debug, 'e') != NULL)
+ {
+ msg_source(HL_ATTR(HLF_W));
+ msg_attr(_("Beep!"), HL_ATTR(HLF_W));
+ }
+ }
+}
+
+/*
+ * To get the "real" home directory:
+ * - get value of $HOME
+ * For Unix:
+ * - go to that directory
+ * - do mch_dirname() to get the real name of that directory.
+ * This also works with mounts and links.
+ * Don't do this for MS-DOS, it will change the "current dir" for a drive.
+ * For Windows:
+ * This code is duplicated in init_homedir() in dosinst.c. Keep in sync!
+ */
+static char_u *homedir = NULL;
+
+ void
+init_homedir(void)
+{
+ char_u *var;
+
+ /* In case we are called a second time (when 'encoding' changes). */
+ VIM_CLEAR(homedir);
+
+#ifdef VMS
+ var = mch_getenv((char_u *)"SYS$LOGIN");
+#else
+ var = mch_getenv((char_u *)"HOME");
+#endif
+
+#ifdef WIN3264
+ /*
+ * Typically, $HOME is not defined on Windows, unless the user has
+ * specifically defined it for Vim's sake. However, on Windows NT
+ * platforms, $HOMEDRIVE and $HOMEPATH are automatically defined for
+ * each user. Try constructing $HOME from these.
+ */
+ if (var == NULL || *var == NUL)
+ {
+ char_u *homedrive, *homepath;
+
+ homedrive = mch_getenv((char_u *)"HOMEDRIVE");
+ homepath = mch_getenv((char_u *)"HOMEPATH");
+ if (homepath == NULL || *homepath == NUL)
+ homepath = (char_u *)"\\";
+ if (homedrive != NULL
+ && STRLEN(homedrive) + STRLEN(homepath) < MAXPATHL)
+ {
+ sprintf((char *)NameBuff, "%s%s", homedrive, homepath);
+ if (NameBuff[0] != NUL)
+ var = NameBuff;
+ }
+ }
+
+ if (var == NULL)
+ var = mch_getenv((char_u *)"USERPROFILE");
+
+ /*
+ * Weird but true: $HOME may contain an indirect reference to another
+ * variable, esp. "%USERPROFILE%". Happens when $USERPROFILE isn't set
+ * when $HOME is being set.
+ */
+ if (var != NULL && *var == '%')
+ {
+ char_u *p;
+ char_u *exp;
+
+ p = vim_strchr(var + 1, '%');
+ if (p != NULL)
+ {
+ vim_strncpy(NameBuff, var + 1, p - (var + 1));
+ exp = mch_getenv(NameBuff);
+ if (exp != NULL && *exp != NUL
+ && STRLEN(exp) + STRLEN(p) < MAXPATHL)
+ {
+ vim_snprintf((char *)NameBuff, MAXPATHL, "%s%s", exp, p + 1);
+ var = NameBuff;
+ }
+ }
+ }
+
+ if (var != NULL && *var == NUL) /* empty is same as not set */
+ var = NULL;
+
+ if (enc_utf8 && var != NULL)
+ {
+ int len;
+ char_u *pp = NULL;
+
+ /* Convert from active codepage to UTF-8. Other conversions are
+ * not done, because they would fail for non-ASCII characters. */
+ acp_to_enc(var, (int)STRLEN(var), &pp, &len);
+ if (pp != NULL)
+ {
+ homedir = pp;
+ return;
+ }
+ }
+
+ /*
+ * Default home dir is C:/
+ * Best assumption we can make in such a situation.
+ */
+ if (var == NULL)
+ var = (char_u *)"C:/";
+#endif
+
+ if (var != NULL)
+ {
+#ifdef UNIX
+ /*
+ * Change to the directory and get the actual path. This resolves
+ * links. Don't do it when we can't return.
+ */
+ if (mch_dirname(NameBuff, MAXPATHL) == OK
+ && mch_chdir((char *)NameBuff) == 0)
+ {
+ if (!mch_chdir((char *)var) && mch_dirname(IObuff, IOSIZE) == OK)
+ var = IObuff;
+ if (mch_chdir((char *)NameBuff) != 0)
+ emsg(_(e_prev_dir));
+ }
+#endif
+ homedir = vim_strsave(var);
+ }
+}
+
+#if defined(EXITFREE) || defined(PROTO)
+ void
+free_homedir(void)
+{
+ vim_free(homedir);
+}
+
+# ifdef FEAT_CMDL_COMPL
+ void
+free_users(void)
+{
+ ga_clear_strings(&ga_users);
+}
+# endif
+#endif
+
+/*
+ * Call expand_env() and store the result in an allocated string.
+ * This is not very memory efficient, this expects the result to be freed
+ * again soon.
+ */
+ char_u *
+expand_env_save(char_u *src)
+{
+ return expand_env_save_opt(src, FALSE);
+}
+
+/*
+ * Idem, but when "one" is TRUE handle the string as one file name, only
+ * expand "~" at the start.
+ */
+ char_u *
+expand_env_save_opt(char_u *src, int one)
+{
+ char_u *p;
+
+ p = alloc(MAXPATHL);
+ if (p != NULL)
+ expand_env_esc(src, p, MAXPATHL, FALSE, one, NULL);
+ return p;
+}
+
+/*
+ * Expand environment variable with path name.
+ * "~/" is also expanded, using $HOME. For Unix "~user/" is expanded.
+ * Skips over "\ ", "\~" and "\$" (not for Win32 though).
+ * If anything fails no expansion is done and dst equals src.
+ */
+ void
+expand_env(
+ char_u *src, /* input string e.g. "$HOME/vim.hlp" */
+ char_u *dst, /* where to put the result */
+ int dstlen) /* maximum length of the result */
+{
+ expand_env_esc(src, dst, dstlen, FALSE, FALSE, NULL);
+}
+
+ void
+expand_env_esc(
+ char_u *srcp, /* input string e.g. "$HOME/vim.hlp" */
+ char_u *dst, /* where to put the result */
+ int dstlen, /* maximum length of the result */
+ int esc, /* escape spaces in expanded variables */
+ int one, /* "srcp" is one file name */
+ char_u *startstr) /* start again after this (can be NULL) */
+{
+ char_u *src;
+ char_u *tail;
+ int c;
+ char_u *var;
+ int copy_char;
+ int mustfree; /* var was allocated, need to free it later */
+ int at_start = TRUE; /* at start of a name */
+ int startstr_len = 0;
+
+ if (startstr != NULL)
+ startstr_len = (int)STRLEN(startstr);
+
+ src = skipwhite(srcp);
+ --dstlen; /* leave one char space for "\," */
+ while (*src && dstlen > 0)
+ {
+#ifdef FEAT_EVAL
+ /* Skip over `=expr`. */
+ if (src[0] == '`' && src[1] == '=')
+ {
+ size_t len;
+
+ var = src;
+ src += 2;
+ (void)skip_expr(&src);
+ if (*src == '`')
+ ++src;
+ len = src - var;
+ if (len > (size_t)dstlen)
+ len = dstlen;
+ vim_strncpy(dst, var, len);
+ dst += len;
+ dstlen -= (int)len;
+ continue;
+ }
+#endif
+ copy_char = TRUE;
+ if ((*src == '$'
+#ifdef VMS
+ && at_start
+#endif
+ )
+#if defined(MSWIN)
+ || *src == '%'
+#endif
+ || (*src == '~' && at_start))
+ {
+ mustfree = FALSE;
+
+ /*
+ * The variable name is copied into dst temporarily, because it may
+ * be a string in read-only memory and a NUL needs to be appended.
+ */
+ if (*src != '~') /* environment var */
+ {
+ tail = src + 1;
+ var = dst;
+ c = dstlen - 1;
+
+#ifdef UNIX
+ /* Unix has ${var-name} type environment vars */
+ if (*tail == '{' && !vim_isIDc('{'))
+ {
+ tail++; /* ignore '{' */
+ while (c-- > 0 && *tail && *tail != '}')
+ *var++ = *tail++;
+ }
+ else
+#endif
+ {
+ while (c-- > 0 && *tail != NUL && ((vim_isIDc(*tail))
+#if defined(MSWIN)
+ || (*src == '%' && *tail != '%')
+#endif
+ ))
+ {
+ *var++ = *tail++;
+ }
+ }
+
+#if defined(MSWIN) || defined(UNIX)
+# ifdef UNIX
+ if (src[1] == '{' && *tail != '}')
+# else
+ if (*src == '%' && *tail != '%')
+# endif
+ var = NULL;
+ else
+ {
+# ifdef UNIX
+ if (src[1] == '{')
+# else
+ if (*src == '%')
+#endif
+ ++tail;
+#endif
+ *var = NUL;
+ var = vim_getenv(dst, &mustfree);
+#if defined(MSWIN) || defined(UNIX)
+ }
+#endif
+ }
+ /* home directory */
+ else if ( src[1] == NUL
+ || vim_ispathsep(src[1])
+ || vim_strchr((char_u *)" ,\t\n", src[1]) != NULL)
+ {
+ var = homedir;
+ tail = src + 1;
+ }
+ else /* user directory */
+ {
+#if defined(UNIX) || (defined(VMS) && defined(USER_HOME))
+ /*
+ * Copy ~user to dst[], so we can put a NUL after it.
+ */
+ tail = src;
+ var = dst;
+ c = dstlen - 1;
+ while ( c-- > 0
+ && *tail
+ && vim_isfilec(*tail)
+ && !vim_ispathsep(*tail))
+ *var++ = *tail++;
+ *var = NUL;
+# ifdef UNIX
+ /*
+ * If the system supports getpwnam(), use it.
+ * Otherwise, or if getpwnam() fails, the shell is used to
+ * expand ~user. This is slower and may fail if the shell
+ * does not support ~user (old versions of /bin/sh).
+ */
+# if defined(HAVE_GETPWNAM) && defined(HAVE_PWD_H)
+ {
+ /* Note: memory allocated by getpwnam() is never freed.
+ * Calling endpwent() apparently doesn't help. */
+ struct passwd *pw = (*dst == NUL)
+ ? NULL : getpwnam((char *)dst + 1);
+
+ var = (pw == NULL) ? NULL : (char_u *)pw->pw_dir;
+ }
+ if (var == NULL)
+# endif
+ {
+ expand_T xpc;
+
+ ExpandInit(&xpc);
+ xpc.xp_context = EXPAND_FILES;
+ var = ExpandOne(&xpc, dst, NULL,
+ WILD_ADD_SLASH|WILD_SILENT, WILD_EXPAND_FREE);
+ mustfree = TRUE;
+ }
+
+# else /* !UNIX, thus VMS */
+ /*
+ * USER_HOME is a comma-separated list of
+ * directories to search for the user account in.
+ */
+ {
+ char_u test[MAXPATHL], paths[MAXPATHL];
+ char_u *path, *next_path, *ptr;
+ stat_T st;
+
+ STRCPY(paths, USER_HOME);
+ next_path = paths;
+ while (*next_path)
+ {
+ for (path = next_path; *next_path && *next_path != ',';
+ next_path++);
+ if (*next_path)
+ *next_path++ = NUL;
+ STRCPY(test, path);
+ STRCAT(test, "/");
+ STRCAT(test, dst + 1);
+ if (mch_stat(test, &st) == 0)
+ {
+ var = alloc(STRLEN(test) + 1);
+ STRCPY(var, test);
+ mustfree = TRUE;
+ break;
+ }
+ }
+ }
+# endif /* UNIX */
+#else
+ /* cannot expand user's home directory, so don't try */
+ var = NULL;
+ tail = (char_u *)""; /* for gcc */
+#endif /* UNIX || VMS */
+ }
+
+#ifdef BACKSLASH_IN_FILENAME
+ /* If 'shellslash' is set change backslashes to forward slashes.
+ * Can't use slash_adjust(), p_ssl may be set temporarily. */
+ if (p_ssl && var != NULL && vim_strchr(var, '\\') != NULL)
+ {
+ char_u *p = vim_strsave(var);
+
+ if (p != NULL)
+ {
+ if (mustfree)
+ vim_free(var);
+ var = p;
+ mustfree = TRUE;
+ forward_slash(var);
+ }
+ }
+#endif
+
+ /* If "var" contains white space, escape it with a backslash.
+ * Required for ":e ~/tt" when $HOME includes a space. */
+ if (esc && var != NULL && vim_strpbrk(var, (char_u *)" \t") != NULL)
+ {
+ char_u *p = vim_strsave_escaped(var, (char_u *)" \t");
+
+ if (p != NULL)
+ {
+ if (mustfree)
+ vim_free(var);
+ var = p;
+ mustfree = TRUE;
+ }
+ }
+
+ if (var != NULL && *var != NUL
+ && (STRLEN(var) + STRLEN(tail) + 1 < (unsigned)dstlen))
+ {
+ STRCPY(dst, var);
+ dstlen -= (int)STRLEN(var);
+ c = (int)STRLEN(var);
+ /* if var[] ends in a path separator and tail[] starts
+ * with it, skip a character */
+ if (*var != NUL && after_pathsep(dst, dst + c)
+#if defined(BACKSLASH_IN_FILENAME) || defined(AMIGA)
+ && dst[-1] != ':'
+#endif
+ && vim_ispathsep(*tail))
+ ++tail;
+ dst += c;
+ src = tail;
+ copy_char = FALSE;
+ }
+ if (mustfree)
+ vim_free(var);
+ }
+
+ if (copy_char) /* copy at least one char */
+ {
+ /*
+ * Recognize the start of a new name, for '~'.
+ * Don't do this when "one" is TRUE, to avoid expanding "~" in
+ * ":edit foo ~ foo".
+ */
+ at_start = FALSE;
+ if (src[0] == '\\' && src[1] != NUL)
+ {
+ *dst++ = *src++;
+ --dstlen;
+ }
+ else if ((src[0] == ' ' || src[0] == ',') && !one)
+ at_start = TRUE;
+ if (dstlen > 0)
+ {
+ *dst++ = *src++;
+ --dstlen;
+
+ if (startstr != NULL && src - startstr_len >= srcp
+ && STRNCMP(src - startstr_len, startstr,
+ startstr_len) == 0)
+ at_start = TRUE;
+ }
+ }
+
+ }
+ *dst = NUL;
+}
+
+/*
+ * Vim's version of getenv().
+ * Special handling of $HOME, $VIM and $VIMRUNTIME.
+ * Also does ACP to 'enc' conversion for Win32.
+ * "mustfree" is set to TRUE when returned is allocated, it must be
+ * initialized to FALSE by the caller.
+ */
+ char_u *
+vim_getenv(char_u *name, int *mustfree)
+{
+ char_u *p;
+ char_u *pend;
+ int vimruntime;
+
+#if defined(MSWIN)
+ /* use "C:/" when $HOME is not set */
+ if (STRCMP(name, "HOME") == 0)
+ return homedir;
+#endif
+
+ p = mch_getenv(name);
+ if (p != NULL && *p == NUL) /* empty is the same as not set */
+ p = NULL;
+
+ if (p != NULL)
+ {
+#if defined(WIN3264)
+ if (enc_utf8)
+ {
+ int len;
+ char_u *pp = NULL;
+
+ /* Convert from active codepage to UTF-8. Other conversions are
+ * not done, because they would fail for non-ASCII characters. */
+ acp_to_enc(p, (int)STRLEN(p), &pp, &len);
+ if (pp != NULL)
+ {
+ p = pp;
+ *mustfree = TRUE;
+ }
+ }
+#endif
+ return p;
+ }
+
+ vimruntime = (STRCMP(name, "VIMRUNTIME") == 0);
+ if (!vimruntime && STRCMP(name, "VIM") != 0)
+ return NULL;
+
+ /*
+ * When expanding $VIMRUNTIME fails, try using $VIM/vim<version> or $VIM.
+ * Don't do this when default_vimruntime_dir is non-empty.
+ */
+ if (vimruntime
+#ifdef HAVE_PATHDEF
+ && *default_vimruntime_dir == NUL
+#endif
+ )
+ {
+ p = mch_getenv((char_u *)"VIM");
+ if (p != NULL && *p == NUL) /* empty is the same as not set */
+ p = NULL;
+ if (p != NULL)
+ {
+ p = vim_version_dir(p);
+ if (p != NULL)
+ *mustfree = TRUE;
+ else
+ p = mch_getenv((char_u *)"VIM");
+
+#if defined(WIN3264)
+ if (enc_utf8)
+ {
+ int len;
+ char_u *pp = NULL;
+
+ /* Convert from active codepage to UTF-8. Other conversions
+ * are not done, because they would fail for non-ASCII
+ * characters. */
+ acp_to_enc(p, (int)STRLEN(p), &pp, &len);
+ if (pp != NULL)
+ {
+ if (*mustfree)
+ vim_free(p);
+ p = pp;
+ *mustfree = TRUE;
+ }
+ }
+#endif
+ }
+ }
+
+ /*
+ * When expanding $VIM or $VIMRUNTIME fails, try using:
+ * - the directory name from 'helpfile' (unless it contains '$')
+ * - the executable name from argv[0]
+ */
+ if (p == NULL)
+ {
+ if (p_hf != NULL && vim_strchr(p_hf, '$') == NULL)
+ p = p_hf;
+#ifdef USE_EXE_NAME
+ /*
+ * Use the name of the executable, obtained from argv[0].
+ */
+ else
+ p = exe_name;
+#endif
+ if (p != NULL)
+ {
+ /* remove the file name */
+ pend = gettail(p);
+
+ /* remove "doc/" from 'helpfile', if present */
+ if (p == p_hf)
+ pend = remove_tail(p, pend, (char_u *)"doc");
+
+#ifdef USE_EXE_NAME
+# ifdef MACOS_X
+ /* remove "MacOS" from exe_name and add "Resources/vim" */
+ if (p == exe_name)
+ {
+ char_u *pend1;
+ char_u *pnew;
+
+ pend1 = remove_tail(p, pend, (char_u *)"MacOS");
+ if (pend1 != pend)
+ {
+ pnew = alloc((unsigned)(pend1 - p) + 15);
+ if (pnew != NULL)
+ {
+ STRNCPY(pnew, p, (pend1 - p));
+ STRCPY(pnew + (pend1 - p), "Resources/vim");
+ p = pnew;
+ pend = p + STRLEN(p);
+ }
+ }
+ }
+# endif
+ /* remove "src/" from exe_name, if present */
+ if (p == exe_name)
+ pend = remove_tail(p, pend, (char_u *)"src");
+#endif
+
+ /* for $VIM, remove "runtime/" or "vim54/", if present */
+ if (!vimruntime)
+ {
+ pend = remove_tail(p, pend, (char_u *)RUNTIME_DIRNAME);
+ pend = remove_tail(p, pend, (char_u *)VIM_VERSION_NODOT);
+ }
+
+ /* remove trailing path separator */
+ if (pend > p && after_pathsep(p, pend))
+ --pend;
+
+#ifdef MACOS_X
+ if (p == exe_name || p == p_hf)
+#endif
+ /* check that the result is a directory name */
+ p = vim_strnsave(p, (int)(pend - p));
+
+ if (p != NULL && !mch_isdir(p))
+ VIM_CLEAR(p);
+ else
+ {
+#ifdef USE_EXE_NAME
+ /* may add "/vim54" or "/runtime" if it exists */
+ if (vimruntime && (pend = vim_version_dir(p)) != NULL)
+ {
+ vim_free(p);
+ p = pend;
+ }
+#endif
+ *mustfree = TRUE;
+ }
+ }
+ }
+
+#ifdef HAVE_PATHDEF
+ /* When there is a pathdef.c file we can use default_vim_dir and
+ * default_vimruntime_dir */
+ if (p == NULL)
+ {
+ /* Only use default_vimruntime_dir when it is not empty */
+ if (vimruntime && *default_vimruntime_dir != NUL)
+ {
+ p = default_vimruntime_dir;
+ *mustfree = FALSE;
+ }
+ else if (*default_vim_dir != NUL)
+ {
+ if (vimruntime && (p = vim_version_dir(default_vim_dir)) != NULL)
+ *mustfree = TRUE;
+ else
+ {
+ p = default_vim_dir;
+ *mustfree = FALSE;
+ }
+ }
+ }
+#endif
+
+ /*
+ * Set the environment variable, so that the new value can be found fast
+ * next time, and others can also use it (e.g. Perl).
+ */
+ if (p != NULL)
+ {
+ if (vimruntime)
+ {
+ vim_setenv((char_u *)"VIMRUNTIME", p);
+ didset_vimruntime = TRUE;
+ }
+ else
+ {
+ vim_setenv((char_u *)"VIM", p);
+ didset_vim = TRUE;
+ }
+ }
+ return p;
+}
+
+/*
+ * Check if the directory "vimdir/<version>" or "vimdir/runtime" exists.
+ * Return NULL if not, return its name in allocated memory otherwise.
+ */
+ static char_u *
+vim_version_dir(char_u *vimdir)
+{
+ char_u *p;
+
+ if (vimdir == NULL || *vimdir == NUL)
+ return NULL;
+ p = concat_fnames(vimdir, (char_u *)VIM_VERSION_NODOT, TRUE);
+ if (p != NULL && mch_isdir(p))
+ return p;
+ vim_free(p);
+ p = concat_fnames(vimdir, (char_u *)RUNTIME_DIRNAME, TRUE);
+ if (p != NULL && mch_isdir(p))
+ return p;
+ vim_free(p);
+ return NULL;
+}
+
+/*
+ * If the string between "p" and "pend" ends in "name/", return "pend" minus
+ * the length of "name/". Otherwise return "pend".
+ */
+ static char_u *
+remove_tail(char_u *p, char_u *pend, char_u *name)
+{
+ int len = (int)STRLEN(name) + 1;
+ char_u *newend = pend - len;
+
+ if (newend >= p
+ && fnamencmp(newend, name, len - 1) == 0
+ && (newend == p || after_pathsep(p, newend)))
+ return newend;
+ return pend;
+}
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+ void
+vim_unsetenv(char_u *var)
+{
+#ifdef HAVE_UNSETENV
+ unsetenv((char *)var);
+#else
+ vim_setenv(var, (char_u *)"");
+#endif
+}
+#endif
+
+
+/*
+ * Our portable version of setenv.
+ */
+ void
+vim_setenv(char_u *name, char_u *val)
+{
+#ifdef HAVE_SETENV
+ mch_setenv((char *)name, (char *)val, 1);
+#else
+ char_u *envbuf;
+
+ /*
+ * Putenv does not copy the string, it has to remain
+ * valid. The allocated memory will never be freed.
+ */
+ envbuf = alloc((unsigned)(STRLEN(name) + STRLEN(val) + 2));
+ if (envbuf != NULL)
+ {
+ sprintf((char *)envbuf, "%s=%s", name, val);
+ putenv((char *)envbuf);
+ }
+#endif
+#ifdef FEAT_GETTEXT
+ /*
+ * When setting $VIMRUNTIME adjust the directory to find message
+ * translations to $VIMRUNTIME/lang.
+ */
+ if (*val != NUL && STRICMP(name, "VIMRUNTIME") == 0)
+ {
+ char_u *buf = concat_str(val, (char_u *)"/lang");
+
+ if (buf != NULL)
+ {
+ bindtextdomain(VIMPACKAGE, (char *)buf);
+ vim_free(buf);
+ }
+ }
+#endif
+}
+
+#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
+/*
+ * Function given to ExpandGeneric() to obtain an environment variable name.
+ */
+ char_u *
+get_env_name(
+ expand_T *xp UNUSED,
+ int idx)
+{
+# if defined(AMIGA)
+ /*
+ * No environ[] on the Amiga.
+ */
+ return NULL;
+# else
+# ifndef __WIN32__
+ /* Borland C++ 5.2 has this in a header file. */
+ extern char **environ;
+# endif
+# define ENVNAMELEN 100
+ static char_u name[ENVNAMELEN];
+ char_u *str;
+ int n;
+
+ str = (char_u *)environ[idx];
+ if (str == NULL)
+ return NULL;
+
+ for (n = 0; n < ENVNAMELEN - 1; ++n)
+ {
+ if (str[n] == '=' || str[n] == NUL)
+ break;
+ name[n] = str[n];
+ }
+ name[n] = NUL;
+ return name;
+# endif
+}
+
+/*
+ * Add a user name to the list of users in ga_users.
+ * Do nothing if user name is NULL or empty.
+ */
+ static void
+add_user(char_u *user, int need_copy)
+{
+ char_u *user_copy = (user != NULL && need_copy)
+ ? vim_strsave(user) : user;
+
+ if (user_copy == NULL || *user_copy == NUL || ga_grow(&ga_users, 1) == FAIL)
+ {
+ if (need_copy)
+ vim_free(user);
+ return;
+ }
+ ((char_u **)(ga_users.ga_data))[ga_users.ga_len++] = user_copy;
+}
+
+/*
+ * Find all user names for user completion.
+ * Done only once and then cached.
+ */
+ static void
+init_users(void)
+{
+ static int lazy_init_done = FALSE;
+
+ if (lazy_init_done)
+ return;
+
+ lazy_init_done = TRUE;
+ ga_init2(&ga_users, sizeof(char_u *), 20);
+
+# if defined(HAVE_GETPWENT) && defined(HAVE_PWD_H)
+ {
+ struct passwd* pw;
+
+ setpwent();
+ while ((pw = getpwent()) != NULL)
+ add_user((char_u *)pw->pw_name, TRUE);
+ endpwent();
+ }
+# elif defined(WIN3264)
+ {
+ DWORD nusers = 0, ntotal = 0, i;
+ PUSER_INFO_0 uinfo;
+
+ if (NetUserEnum(NULL, 0, 0, (LPBYTE *) &uinfo, MAX_PREFERRED_LENGTH,
+ &nusers, &ntotal, NULL) == NERR_Success)
+ {
+ for (i = 0; i < nusers; i++)
+ add_user(utf16_to_enc(uinfo[i].usri0_name, NULL), FALSE);
+
+ NetApiBufferFree(uinfo);
+ }
+ }
+# endif
+# if defined(HAVE_GETPWNAM)
+ {
+ char_u *user_env = mch_getenv((char_u *)"USER");
+
+ // The $USER environment variable may be a valid remote user name (NIS,
+ // LDAP) not already listed by getpwent(), as getpwent() only lists
+ // local user names. If $USER is not already listed, check whether it
+ // is a valid remote user name using getpwnam() and if it is, add it to
+ // the list of user names.
+
+ if (user_env != NULL && *user_env != NUL)
+ {
+ int i;
+
+ for (i = 0; i < ga_users.ga_len; i++)
+ {
+ char_u *local_user = ((char_u **)ga_users.ga_data)[i];
+
+ if (STRCMP(local_user, user_env) == 0)
+ break;
+ }
+
+ if (i == ga_users.ga_len)
+ {
+ struct passwd *pw = getpwnam((char *)user_env);
+
+ if (pw != NULL)
+ add_user((char_u *)pw->pw_name, TRUE);
+ }
+ }
+ }
+# endif
+}
+
+/*
+ * Function given to ExpandGeneric() to obtain an user names.
+ */
+ char_u*
+get_users(expand_T *xp UNUSED, int idx)
+{
+ init_users();
+ if (idx < ga_users.ga_len)
+ return ((char_u **)ga_users.ga_data)[idx];
+ return NULL;
+}
+
+/*
+ * Check whether name matches a user name. Return:
+ * 0 if name does not match any user name.
+ * 1 if name partially matches the beginning of a user name.
+ * 2 is name fully matches a user name.
+ */
+ int
+match_user(char_u *name)
+{
+ int i;
+ int n = (int)STRLEN(name);
+ int result = 0;
+
+ init_users();
+ for (i = 0; i < ga_users.ga_len; i++)
+ {
+ if (STRCMP(((char_u **)ga_users.ga_data)[i], name) == 0)
+ return 2; /* full match */
+ if (STRNCMP(((char_u **)ga_users.ga_data)[i], name, n) == 0)
+ result = 1; /* partial match */
+ }
+ return result;
+}
+#endif
+
+/*
+ * Replace home directory by "~" in each space or comma separated file name in
+ * 'src'.
+ * If anything fails (except when out of space) dst equals src.
+ */
+ void
+home_replace(
+ buf_T *buf, /* when not NULL, check for help files */
+ char_u *src, /* input file name */
+ char_u *dst, /* where to put the result */
+ int dstlen, /* maximum length of the result */
+ int one) /* if TRUE, only replace one file name, include
+ spaces and commas in the file name. */
+{
+ size_t dirlen = 0, envlen = 0;
+ size_t len;
+ char_u *homedir_env, *homedir_env_orig;
+ char_u *p;
+
+ if (src == NULL)
+ {
+ *dst = NUL;
+ return;
+ }
+
+ /*
+ * If the file is a help file, remove the path completely.
+ */
+ if (buf != NULL && buf->b_help)
+ {
+ vim_snprintf((char *)dst, dstlen, "%s", gettail(src));
+ return;
+ }
+
+ /*
+ * We check both the value of the $HOME environment variable and the
+ * "real" home directory.
+ */
+ if (homedir != NULL)
+ dirlen = STRLEN(homedir);
+
+#ifdef VMS
+ homedir_env_orig = homedir_env = mch_getenv((char_u *)"SYS$LOGIN");
+#else
+ homedir_env_orig = homedir_env = mch_getenv((char_u *)"HOME");
+#endif
+#ifdef WIN3264
+ if (homedir_env == NULL)
+ homedir_env_orig = homedir_env = mch_getenv((char_u *)"USERPROFILE");
+#endif
+ /* Empty is the same as not set. */
+ if (homedir_env != NULL && *homedir_env == NUL)
+ homedir_env = NULL;
+
+#if defined(FEAT_MODIFY_FNAME) || defined(FEAT_EVAL)
+ if (homedir_env != NULL && *homedir_env == '~')
+ {
+ int usedlen = 0;
+ int flen;
+ char_u *fbuf = NULL;
+
+ flen = (int)STRLEN(homedir_env);
+ (void)modify_fname((char_u *)":p", FALSE, &usedlen,
+ &homedir_env, &fbuf, &flen);
+ flen = (int)STRLEN(homedir_env);
+ if (flen > 0 && vim_ispathsep(homedir_env[flen - 1]))
+ /* Remove the trailing / that is added to a directory. */
+ homedir_env[flen - 1] = NUL;
+ }
+#endif
+
+ if (homedir_env != NULL)
+ envlen = STRLEN(homedir_env);
+
+ if (!one)
+ src = skipwhite(src);
+ while (*src && dstlen > 0)
+ {
+ /*
+ * Here we are at the beginning of a file name.
+ * First, check to see if the beginning of the file name matches
+ * $HOME or the "real" home directory. Check that there is a '/'
+ * after the match (so that if e.g. the file is "/home/pieter/bla",
+ * and the home directory is "/home/piet", the file does not end up
+ * as "~er/bla" (which would seem to indicate the file "bla" in user
+ * er's home directory)).
+ */
+ p = homedir;
+ len = dirlen;
+ for (;;)
+ {
+ if ( len
+ && fnamencmp(src, p, len) == 0
+ && (vim_ispathsep(src[len])
+ || (!one && (src[len] == ',' || src[len] == ' '))
+ || src[len] == NUL))
+ {
+ src += len;
+ if (--dstlen > 0)
+ *dst++ = '~';
+
+ /*
+ * If it's just the home directory, add "/".
+ */
+ if (!vim_ispathsep(src[0]) && --dstlen > 0)
+ *dst++ = '/';
+ break;
+ }
+ if (p == homedir_env)
+ break;
+ p = homedir_env;
+ len = envlen;
+ }
+
+ /* if (!one) skip to separator: space or comma */
+ while (*src && (one || (*src != ',' && *src != ' ')) && --dstlen > 0)
+ *dst++ = *src++;
+ /* skip separator */
+ while ((*src == ' ' || *src == ',') && --dstlen > 0)
+ *dst++ = *src++;
+ }
+ /* if (dstlen == 0) out of space, what to do??? */
+
+ *dst = NUL;
+
+ if (homedir_env != homedir_env_orig)
+ vim_free(homedir_env);
+}
+
+/*
+ * Like home_replace, store the replaced string in allocated memory.
+ * When something fails, NULL is returned.
+ */
+ char_u *
+home_replace_save(
+ buf_T *buf, /* when not NULL, check for help files */
+ char_u *src) /* input file name */
+{
+ char_u *dst;
+ unsigned len;
+
+ len = 3; /* space for "~/" and trailing NUL */
+ if (src != NULL) /* just in case */
+ len += (unsigned)STRLEN(src);
+ dst = alloc(len);
+ if (dst != NULL)
+ home_replace(buf, src, dst, len, TRUE);
+ return dst;
+}
+
+/*
+ * Compare two file names and return:
+ * FPC_SAME if they both exist and are the same file.
+ * FPC_SAMEX if they both don't exist and have the same file name.
+ * FPC_DIFF if they both exist and are different files.
+ * FPC_NOTX if they both don't exist.
+ * FPC_DIFFX if one of them doesn't exist.
+ * For the first name environment variables are expanded
+ */
+ int
+fullpathcmp(
+ char_u *s1,
+ char_u *s2,
+ int checkname) /* when both don't exist, check file names */
+{
+#ifdef UNIX
+ char_u exp1[MAXPATHL];
+ char_u full1[MAXPATHL];
+ char_u full2[MAXPATHL];
+ stat_T st1, st2;
+ int r1, r2;
+
+ expand_env(s1, exp1, MAXPATHL);
+ r1 = mch_stat((char *)exp1, &st1);
+ r2 = mch_stat((char *)s2, &st2);
+ if (r1 != 0 && r2 != 0)
+ {
+ /* if mch_stat() doesn't work, may compare the names */
+ if (checkname)
+ {
+ if (fnamecmp(exp1, s2) == 0)
+ return FPC_SAMEX;
+ r1 = vim_FullName(exp1, full1, MAXPATHL, FALSE);
+ r2 = vim_FullName(s2, full2, MAXPATHL, FALSE);
+ if (r1 == OK && r2 == OK && fnamecmp(full1, full2) == 0)
+ return FPC_SAMEX;
+ }
+ return FPC_NOTX;
+ }
+ if (r1 != 0 || r2 != 0)
+ return FPC_DIFFX;
+ if (st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino)
+ return FPC_SAME;
+ return FPC_DIFF;
+#else
+ char_u *exp1; /* expanded s1 */
+ char_u *full1; /* full path of s1 */
+ char_u *full2; /* full path of s2 */
+ int retval = FPC_DIFF;
+ int r1, r2;
+
+ /* allocate one buffer to store three paths (alloc()/free() is slow!) */
+ if ((exp1 = alloc(MAXPATHL * 3)) != NULL)
+ {
+ full1 = exp1 + MAXPATHL;
+ full2 = full1 + MAXPATHL;
+
+ expand_env(s1, exp1, MAXPATHL);
+ r1 = vim_FullName(exp1, full1, MAXPATHL, FALSE);
+ r2 = vim_FullName(s2, full2, MAXPATHL, FALSE);
+
+ /* If vim_FullName() fails, the file probably doesn't exist. */
+ if (r1 != OK && r2 != OK)
+ {
+ if (checkname && fnamecmp(exp1, s2) == 0)
+ retval = FPC_SAMEX;
+ else
+ retval = FPC_NOTX;
+ }
+ else if (r1 != OK || r2 != OK)
+ retval = FPC_DIFFX;
+ else if (fnamecmp(full1, full2))
+ retval = FPC_DIFF;
+ else
+ retval = FPC_SAME;
+ vim_free(exp1);
+ }
+ return retval;
+#endif
+}
+
+/*
+ * Get the tail of a path: the file name.
+ * When the path ends in a path separator the tail is the NUL after it.
+ * Fail safe: never returns NULL.
+ */
+ char_u *
+gettail(char_u *fname)
+{
+ char_u *p1, *p2;
+
+ if (fname == NULL)
+ return (char_u *)"";
+ for (p1 = p2 = get_past_head(fname); *p2; ) /* find last part of path */
+ {
+ if (vim_ispathsep_nocolon(*p2))
+ p1 = p2 + 1;
+ MB_PTR_ADV(p2);
+ }
+ return p1;
+}
+
+#if defined(FEAT_SEARCHPATH)
+/*
+ * Return the end of the directory name, on the first path
+ * separator:
+ * "/path/file", "/path/dir/", "/path//dir", "/file"
+ * ^ ^ ^ ^
+ */
+ static char_u *
+gettail_dir(char_u *fname)
+{
+ char_u *dir_end = fname;
+ char_u *next_dir_end = fname;
+ int look_for_sep = TRUE;
+ char_u *p;
+
+ for (p = fname; *p != NUL; )
+ {
+ if (vim_ispathsep(*p))
+ {
+ if (look_for_sep)
+ {
+ next_dir_end = p;
+ look_for_sep = FALSE;
+ }
+ }
+ else
+ {
+ if (!look_for_sep)
+ dir_end = next_dir_end;
+ look_for_sep = TRUE;
+ }
+ MB_PTR_ADV(p);
+ }
+ return dir_end;
+}
+#endif
+
+/*
+ * Get pointer to tail of "fname", including path separators. Putting a NUL
+ * here leaves the directory name. Takes care of "c:/" and "//".
+ * Always returns a valid pointer.
+ */
+ char_u *
+gettail_sep(char_u *fname)
+{
+ char_u *p;
+ char_u *t;
+
+ p = get_past_head(fname); /* don't remove the '/' from "c:/file" */
+ t = gettail(fname);
+ while (t > p && after_pathsep(fname, t))
+ --t;
+#ifdef VMS
+ /* path separator is part of the path */
+ ++t;
+#endif
+ return t;
+}
+
+/*
+ * get the next path component (just after the next path separator).
+ */
+ char_u *
+getnextcomp(char_u *fname)
+{
+ while (*fname && !vim_ispathsep(*fname))
+ MB_PTR_ADV(fname);
+ if (*fname)
+ ++fname;
+ return fname;
+}
+
+/*
+ * Get a pointer to one character past the head of a path name.
+ * Unix: after "/"; DOS: after "c:\"; Amiga: after "disk:/"; Mac: no head.
+ * If there is no head, path is returned.
+ */
+ char_u *
+get_past_head(char_u *path)
+{
+ char_u *retval;
+
+#if defined(MSWIN)
+ /* may skip "c:" */
+ if (isalpha(path[0]) && path[1] == ':')
+ retval = path + 2;
+ else
+ retval = path;
+#else
+# if defined(AMIGA)
+ /* may skip "label:" */
+ retval = vim_strchr(path, ':');
+ if (retval == NULL)
+ retval = path;
+# else /* Unix */
+ retval = path;
+# endif
+#endif
+
+ while (vim_ispathsep(*retval))
+ ++retval;
+
+ return retval;
+}
+
+/*
+ * Return TRUE if 'c' is a path separator.
+ * Note that for MS-Windows this includes the colon.
+ */
+ int
+vim_ispathsep(int c)
+{
+#ifdef UNIX
+ return (c == '/'); /* UNIX has ':' inside file names */
+#else
+# ifdef BACKSLASH_IN_FILENAME
+ return (c == ':' || c == '/' || c == '\\');
+# else
+# ifdef VMS
+ /* server"user passwd"::device:[full.path.name]fname.extension;version" */
+ return (c == ':' || c == '[' || c == ']' || c == '/'
+ || c == '<' || c == '>' || c == '"' );
+# else
+ return (c == ':' || c == '/');
+# endif /* VMS */
+# endif
+#endif
+}
+
+/*
+ * Like vim_ispathsep(c), but exclude the colon for MS-Windows.
+ */
+ int
+vim_ispathsep_nocolon(int c)
+{
+ return vim_ispathsep(c)
+#ifdef BACKSLASH_IN_FILENAME
+ && c != ':'
+#endif
+ ;
+}
+
+#if defined(FEAT_SEARCHPATH) || defined(PROTO)
+/*
+ * return TRUE if 'c' is a path list separator.
+ */
+ int
+vim_ispathlistsep(int c)
+{
+#ifdef UNIX
+ return (c == ':');
+#else
+ return (c == ';'); /* might not be right for every system... */
+#endif
+}
+#endif
+
+/*
+ * Shorten the path of a file from "~/foo/../.bar/fname" to "~/f/../.b/fname"
+ * It's done in-place.
+ */
+ void
+shorten_dir(char_u *str)
+{
+ char_u *tail, *s, *d;
+ int skip = FALSE;
+
+ tail = gettail(str);
+ d = str;
+ for (s = str; ; ++s)
+ {
+ if (s >= tail) /* copy the whole tail */
+ {
+ *d++ = *s;
+ if (*s == NUL)
+ break;
+ }
+ else if (vim_ispathsep(*s)) /* copy '/' and next char */
+ {
+ *d++ = *s;
+ skip = FALSE;
+ }
+ else if (!skip)
+ {
+ *d++ = *s; /* copy next char */
+ if (*s != '~' && *s != '.') /* and leading "~" and "." */
+ skip = TRUE;
+ if (has_mbyte)
+ {
+ int l = mb_ptr2len(s);
+
+ while (--l > 0)
+ *d++ = *++s;
+ }
+ }
+ }
+}
+
+/*
+ * Return TRUE if the directory of "fname" exists, FALSE otherwise.
+ * Also returns TRUE if there is no directory name.
+ * "fname" must be writable!.
+ */
+ int
+dir_of_file_exists(char_u *fname)
+{
+ char_u *p;
+ int c;
+ int retval;
+
+ p = gettail_sep(fname);
+ if (p == fname)
+ return TRUE;
+ c = *p;
+ *p = NUL;
+ retval = mch_isdir(fname);
+ *p = c;
+ return retval;
+}
+
+/*
+ * Versions of fnamecmp() and fnamencmp() that handle '/' and '\' equally
+ * and deal with 'fileignorecase'.
+ */
+ int
+vim_fnamecmp(char_u *x, char_u *y)
+{
+#ifdef BACKSLASH_IN_FILENAME
+ return vim_fnamencmp(x, y, MAXPATHL);
+#else
+ if (p_fic)
+ return MB_STRICMP(x, y);
+ return STRCMP(x, y);
+#endif
+}
+
+ int
+vim_fnamencmp(char_u *x, char_u *y, size_t len)
+{
+#ifdef BACKSLASH_IN_FILENAME
+ char_u *px = x;
+ char_u *py = y;
+ int cx = NUL;
+ int cy = NUL;
+
+ while (len > 0)
+ {
+ cx = PTR2CHAR(px);
+ cy = PTR2CHAR(py);
+ if (cx == NUL || cy == NUL
+ || ((p_fic ? MB_TOLOWER(cx) != MB_TOLOWER(cy) : cx != cy)
+ && !(cx == '/' && cy == '\\')
+ && !(cx == '\\' && cy == '/')))
+ break;
+ len -= MB_PTR2LEN(px);
+ px += MB_PTR2LEN(px);
+ py += MB_PTR2LEN(py);
+ }
+ if (len == 0)
+ return 0;
+ return (cx - cy);
+#else
+ if (p_fic)
+ return MB_STRNICMP(x, y, len);
+ return STRNCMP(x, y, len);
+#endif
+}
+
+/*
+ * Concatenate file names fname1 and fname2 into allocated memory.
+ * Only add a '/' or '\\' when 'sep' is TRUE and it is necessary.
+ */
+ char_u *
+concat_fnames(char_u *fname1, char_u *fname2, int sep)
+{
+ char_u *dest;
+
+ dest = alloc((unsigned)(STRLEN(fname1) + STRLEN(fname2) + 3));
+ if (dest != NULL)
+ {
+ STRCPY(dest, fname1);
+ if (sep)
+ add_pathsep(dest);
+ STRCAT(dest, fname2);
+ }
+ return dest;
+}
+
+/*
+ * Concatenate two strings and return the result in allocated memory.
+ * Returns NULL when out of memory.
+ */
+ char_u *
+concat_str(char_u *str1, char_u *str2)
+{
+ char_u *dest;
+ size_t l = STRLEN(str1);
+
+ dest = alloc((unsigned)(l + STRLEN(str2) + 1L));
+ if (dest != NULL)
+ {
+ STRCPY(dest, str1);
+ STRCPY(dest + l, str2);
+ }
+ return dest;
+}
+
+/*
+ * Add a path separator to a file name, unless it already ends in a path
+ * separator.
+ */
+ void
+add_pathsep(char_u *p)
+{
+ if (*p != NUL && !after_pathsep(p, p + STRLEN(p)))
+ STRCAT(p, PATHSEPSTR);
+}
+
+/*
+ * FullName_save - Make an allocated copy of a full file name.
+ * Returns NULL when out of memory.
+ */
+ char_u *
+FullName_save(
+ char_u *fname,
+ int force) /* force expansion, even when it already looks
+ * like a full path name */
+{
+ char_u *buf;
+ char_u *new_fname = NULL;
+
+ if (fname == NULL)
+ return NULL;
+
+ buf = alloc((unsigned)MAXPATHL);
+ if (buf != NULL)
+ {
+ if (vim_FullName(fname, buf, MAXPATHL, force) != FAIL)
+ new_fname = vim_strsave(buf);
+ else
+ new_fname = vim_strsave(fname);
+ vim_free(buf);
+ }
+ return new_fname;
+}
+
+ void
+prepare_to_exit(void)
+{
+#if defined(SIGHUP) && defined(SIG_IGN)
+ /* Ignore SIGHUP, because a dropped connection causes a read error, which
+ * makes Vim exit and then handling SIGHUP causes various reentrance
+ * problems. */
+ signal(SIGHUP, SIG_IGN);
+#endif
+
+#ifdef FEAT_GUI
+ if (gui.in_use)
+ {
+ gui.dying = TRUE;
+ out_trash(); /* trash any pending output */
+ }
+ else
+#endif
+ {
+ windgoto((int)Rows - 1, 0);
+
+ /*
+ * Switch terminal mode back now, so messages end up on the "normal"
+ * screen (if there are two screens).
+ */
+ settmode(TMODE_COOK);
+ stoptermcap();
+ out_flush();
+ }
+}
+
+/*
+ * Preserve files and exit.
+ * When called IObuff must contain a message.
+ * NOTE: This may be called from deathtrap() in a signal handler, avoid unsafe
+ * functions, such as allocating memory.
+ */
+ void
+preserve_exit(void)
+{
+ buf_T *buf;
+
+ prepare_to_exit();
+
+ /* Setting this will prevent free() calls. That avoids calling free()
+ * recursively when free() was invoked with a bad pointer. */
+ really_exiting = TRUE;
+
+ out_str(IObuff);
+ screen_start(); /* don't know where cursor is now */
+ out_flush();
+
+ ml_close_notmod(); /* close all not-modified buffers */
+
+ FOR_ALL_BUFFERS(buf)
+ {
+ if (buf->b_ml.ml_mfp != NULL && buf->b_ml.ml_mfp->mf_fname != NULL)
+ {
+ OUT_STR("Vim: preserving files...\n");
+ screen_start(); /* don't know where cursor is now */
+ out_flush();
+ ml_sync_all(FALSE, FALSE); /* preserve all swap files */
+ break;
+ }
+ }
+
+ ml_close_all(FALSE); /* close all memfiles, without deleting */
+
+ OUT_STR("Vim: Finished.\n");
+
+ getout(1);
+}
+
+/*
+ * return TRUE if "fname" exists.
+ */
+ int
+vim_fexists(char_u *fname)
+{
+ stat_T st;
+
+ if (mch_stat((char *)fname, &st))
+ return FALSE;
+ return TRUE;
+}
+
+/*
+ * Check for CTRL-C pressed, but only once in a while.
+ * Should be used instead of ui_breakcheck() for functions that check for
+ * each line in the file. Calling ui_breakcheck() each time takes too much
+ * time, because it can be a system call.
+ */
+
+#ifndef BREAKCHECK_SKIP
+# ifdef FEAT_GUI /* assume the GUI only runs on fast computers */
+# define BREAKCHECK_SKIP 200
+# else
+# define BREAKCHECK_SKIP 32
+# endif
+#endif
+
+static int breakcheck_count = 0;
+
+ void
+line_breakcheck(void)
+{
+ if (++breakcheck_count >= BREAKCHECK_SKIP)
+ {
+ breakcheck_count = 0;
+ ui_breakcheck();
+ }
+}
+
+/*
+ * Like line_breakcheck() but check 10 times less often.
+ */
+ void
+fast_breakcheck(void)
+{
+ if (++breakcheck_count >= BREAKCHECK_SKIP * 10)
+ {
+ breakcheck_count = 0;
+ ui_breakcheck();
+ }
+}
+
+/*
+ * Invoke expand_wildcards() for one pattern.
+ * Expand items like "%:h" before the expansion.
+ * Returns OK or FAIL.
+ */
+ int
+expand_wildcards_eval(
+ char_u **pat, /* pointer to input pattern */
+ int *num_file, /* resulting number of files */
+ char_u ***file, /* array of resulting files */
+ int flags) /* EW_DIR, etc. */
+{
+ int ret = FAIL;
+ char_u *eval_pat = NULL;
+ char_u *exp_pat = *pat;
+ char *ignored_msg;
+ int usedlen;
+
+ if (*exp_pat == '%' || *exp_pat == '#' || *exp_pat == '<')
+ {
+ ++emsg_off;
+ eval_pat = eval_vars(exp_pat, exp_pat, &usedlen,
+ NULL, &ignored_msg, NULL);
+ --emsg_off;
+ if (eval_pat != NULL)
+ exp_pat = concat_str(eval_pat, exp_pat + usedlen);
+ }
+
+ if (exp_pat != NULL)
+ ret = expand_wildcards(1, &exp_pat, num_file, file, flags);
+
+ if (eval_pat != NULL)
+ {
+ vim_free(exp_pat);
+ vim_free(eval_pat);
+ }
+
+ return ret;
+}
+
+/*
+ * Expand wildcards. Calls gen_expand_wildcards() and removes files matching
+ * 'wildignore'.
+ * Returns OK or FAIL. When FAIL then "num_files" won't be set.
+ */
+ int
+expand_wildcards(
+ int num_pat, /* number of input patterns */
+ char_u **pat, /* array of input patterns */
+ int *num_files, /* resulting number of files */
+ char_u ***files, /* array of resulting files */
+ int flags) /* EW_DIR, etc. */
+{
+ int retval;
+ int i, j;
+ char_u *p;
+ int non_suf_match; /* number without matching suffix */
+
+ retval = gen_expand_wildcards(num_pat, pat, num_files, files, flags);
+
+ /* When keeping all matches, return here */
+ if ((flags & EW_KEEPALL) || retval == FAIL)
+ return retval;
+
+#ifdef FEAT_WILDIGN
+ /*
+ * Remove names that match 'wildignore'.
+ */
+ if (*p_wig)
+ {
+ char_u *ffname;
+
+ /* check all files in (*files)[] */
+ for (i = 0; i < *num_files; ++i)
+ {
+ ffname = FullName_save((*files)[i], FALSE);
+ if (ffname == NULL) /* out of memory */
+ break;
+# ifdef VMS
+ vms_remove_version(ffname);
+# endif
+ if (match_file_list(p_wig, (*files)[i], ffname))
+ {
+ /* remove this matching file from the list */
+ vim_free((*files)[i]);
+ for (j = i; j + 1 < *num_files; ++j)
+ (*files)[j] = (*files)[j + 1];
+ --*num_files;
+ --i;
+ }
+ vim_free(ffname);
+ }
+
+ /* If the number of matches is now zero, we fail. */
+ if (*num_files == 0)
+ {
+ VIM_CLEAR(*files);
+ return FAIL;
+ }
+ }
+#endif
+
+ /*
+ * Move the names where 'suffixes' match to the end.
+ */
+ if (*num_files > 1)
+ {
+ non_suf_match = 0;
+ for (i = 0; i < *num_files; ++i)
+ {
+ if (!match_suffix((*files)[i]))
+ {
+ /*
+ * Move the name without matching suffix to the front
+ * of the list.
+ */
+ p = (*files)[i];
+ for (j = i; j > non_suf_match; --j)
+ (*files)[j] = (*files)[j - 1];
+ (*files)[non_suf_match++] = p;
+ }
+ }
+ }
+
+ return retval;
+}
+
+/*
+ * Return TRUE if "fname" matches with an entry in 'suffixes'.
+ */
+ int
+match_suffix(char_u *fname)
+{
+ int fnamelen, setsuflen;
+ char_u *setsuf;
+#define MAXSUFLEN 30 /* maximum length of a file suffix */
+ char_u suf_buf[MAXSUFLEN];
+
+ fnamelen = (int)STRLEN(fname);
+ setsuflen = 0;
+ for (setsuf = p_su; *setsuf; )
+ {
+ setsuflen = copy_option_part(&setsuf, suf_buf, MAXSUFLEN, ".,");
+ if (setsuflen == 0)
+ {
+ char_u *tail = gettail(fname);
+
+ /* empty entry: match name without a '.' */
+ if (vim_strchr(tail, '.') == NULL)
+ {
+ setsuflen = 1;
+ break;
+ }
+ }
+ else
+ {
+ if (fnamelen >= setsuflen
+ && fnamencmp(suf_buf, fname + fnamelen - setsuflen,
+ (size_t)setsuflen) == 0)
+ break;
+ setsuflen = 0;
+ }
+ }
+ return (setsuflen != 0);
+}
+
+#if !defined(NO_EXPANDPATH) || defined(PROTO)
+
+# ifdef VIM_BACKTICK
+static int vim_backtick(char_u *p);
+static int expand_backtick(garray_T *gap, char_u *pat, int flags);
+# endif
+
+# if defined(WIN3264)
+/*
+ * File name expansion code for MS-DOS, Win16 and Win32. It's here because
+ * it's shared between these systems.
+ */
+# if defined(PROTO)
+# define _cdecl
+# else
+# ifdef __BORLANDC__
+# define _cdecl _RTLENTRYF
+# endif
+# endif
+
+/*
+ * comparison function for qsort in dos_expandpath()
+ */
+ static int _cdecl
+pstrcmp(const void *a, const void *b)
+{
+ return (pathcmp(*(char **)a, *(char **)b, -1));
+}
+
+/*
+ * Recursively expand one path component into all matching files and/or
+ * directories. Adds matches to "gap". Handles "*", "?", "[a-z]", "**", etc.
+ * Return the number of matches found.
+ * "path" has backslashes before chars that are not to be expanded, starting
+ * at "path[wildoff]".
+ * Return the number of matches found.
+ * NOTE: much of this is identical to unix_expandpath(), keep in sync!
+ */
+ static int
+dos_expandpath(
+ garray_T *gap,
+ char_u *path,
+ int wildoff,
+ int flags, /* EW_* flags */
+ int didstar) /* expanded "**" once already */
+{
+ char_u *buf;
+ char_u *path_end;
+ char_u *p, *s, *e;
+ int start_len = gap->ga_len;
+ char_u *pat;
+ regmatch_T regmatch;
+ int starts_with_dot;
+ int matches;
+ int len;
+ int starstar = FALSE;
+ static int stardepth = 0; /* depth for "**" expansion */
+ WIN32_FIND_DATA fb;
+ HANDLE hFind = (HANDLE)0;
+ WIN32_FIND_DATAW wfb;
+ WCHAR *wn = NULL; /* UCS-2 name, NULL when not used. */
+ char_u *matchname;
+ int ok;
+
+ /* Expanding "**" may take a long time, check for CTRL-C. */
+ if (stardepth > 0)
+ {
+ ui_breakcheck();
+ if (got_int)
+ return 0;
+ }
+
+ // Make room for file name. When doing encoding conversion the actual
+ // length may be quite a bit longer, thus use the maximum possible length.
+ buf = alloc((int)MAXPATHL);
+ if (buf == NULL)
+ return 0;
+
+ /*
+ * Find the first part in the path name that contains a wildcard or a ~1.
+ * Copy it into buf, including the preceding characters.
+ */
+ p = buf;
+ s = buf;
+ e = NULL;
+ path_end = path;
+ while (*path_end != NUL)
+ {
+ /* May ignore a wildcard that has a backslash before it; it will
+ * be removed by rem_backslash() or file_pat_to_reg_pat() below. */
+ if (path_end >= path + wildoff && rem_backslash(path_end))
+ *p++ = *path_end++;
+ else if (*path_end == '\\' || *path_end == ':' || *path_end == '/')
+ {
+ if (e != NULL)
+ break;
+ s = p + 1;
+ }
+ else if (path_end >= path + wildoff
+ && vim_strchr((char_u *)"*?[~", *path_end) != NULL)
+ e = p;
+ if (has_mbyte)
+ {
+ len = (*mb_ptr2len)(path_end);
+ STRNCPY(p, path_end, len);
+ p += len;
+ path_end += len;
+ }
+ else
+ *p++ = *path_end++;
+ }
+ e = p;
+ *e = NUL;
+
+ /* now we have one wildcard component between s and e */
+ /* Remove backslashes between "wildoff" and the start of the wildcard
+ * component. */
+ for (p = buf + wildoff; p < s; ++p)
+ if (rem_backslash(p))
+ {
+ STRMOVE(p, p + 1);
+ --e;
+ --s;
+ }
+
+ /* Check for "**" between "s" and "e". */
+ for (p = s; p < e; ++p)
+ if (p[0] == '*' && p[1] == '*')
+ starstar = TRUE;
+
+ starts_with_dot = *s == '.';
+ pat = file_pat_to_reg_pat(s, e, NULL, FALSE);
+ if (pat == NULL)
+ {
+ vim_free(buf);
+ return 0;
+ }
+
+ /* compile the regexp into a program */
+ if (flags & (EW_NOERROR | EW_NOTWILD))
+ ++emsg_silent;
+ regmatch.rm_ic = TRUE; /* Always ignore case */
+ regmatch.regprog = vim_regcomp(pat, RE_MAGIC);
+ if (flags & (EW_NOERROR | EW_NOTWILD))
+ --emsg_silent;
+ vim_free(pat);
+
+ if (regmatch.regprog == NULL && (flags & EW_NOTWILD) == 0)
+ {
+ vim_free(buf);
+ return 0;
+ }
+
+ /* remember the pattern or file name being looked for */
+ matchname = vim_strsave(s);
+
+ /* If "**" is by itself, this is the first time we encounter it and more
+ * is following then find matches without any directory. */
+ if (!didstar && stardepth < 100 && starstar && e - s == 2
+ && *path_end == '/')
+ {
+ STRCPY(s, path_end + 1);
+ ++stardepth;
+ (void)dos_expandpath(gap, buf, (int)(s - buf), flags, TRUE);
+ --stardepth;
+ }
+
+ /* Scan all files in the directory with "dir/ *.*" */
+ STRCPY(s, "*.*");
+ if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+ {
+ /* The active codepage differs from 'encoding'. Attempt using the
+ * wide function. If it fails because it is not implemented fall back
+ * to the non-wide version (for Windows 98) */
+ wn = enc_to_utf16(buf, NULL);
+ if (wn != NULL)
+ {
+ hFind = FindFirstFileW(wn, &wfb);
+ if (hFind == INVALID_HANDLE_VALUE
+ && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
+ VIM_CLEAR(wn);
+ }
+ }
+
+ if (wn == NULL)
+ hFind = FindFirstFile((LPCSTR)buf, &fb);
+ ok = (hFind != INVALID_HANDLE_VALUE);
+
+ while (ok)
+ {
+ if (wn != NULL)
+ p = utf16_to_enc(wfb.cFileName, NULL); /* p is allocated here */
+ else
+ p = (char_u *)fb.cFileName;
+ /* Ignore entries starting with a dot, unless when asked for. Accept
+ * all entries found with "matchname". */
+ if ((p[0] != '.' || starts_with_dot
+ || ((flags & EW_DODOT)
+ && p[1] != NUL && (p[1] != '.' || p[2] != NUL)))
+ && (matchname == NULL
+ || (regmatch.regprog != NULL
+ && vim_regexec(&regmatch, p, (colnr_T)0))
+ || ((flags & EW_NOTWILD)
+ && fnamencmp(path + (s - buf), p, e - s) == 0)))
+ {
+ STRCPY(s, p);
+ len = (int)STRLEN(buf);
+
+ if (starstar && stardepth < 100)
+ {
+ /* For "**" in the pattern first go deeper in the tree to
+ * find matches. */
+ STRCPY(buf + len, "/**");
+ STRCPY(buf + len + 3, path_end);
+ ++stardepth;
+ (void)dos_expandpath(gap, buf, len + 1, flags, TRUE);
+ --stardepth;
+ }
+
+ STRCPY(buf + len, path_end);
+ if (mch_has_exp_wildcard(path_end))
+ {
+ /* need to expand another component of the path */
+ /* remove backslashes for the remaining components only */
+ (void)dos_expandpath(gap, buf, len + 1, flags, FALSE);
+ }
+ else
+ {
+ /* no more wildcards, check if there is a match */
+ /* remove backslashes for the remaining components only */
+ if (*path_end != 0)
+ backslash_halve(buf + len + 1);
+ if (mch_getperm(buf) >= 0) /* add existing file */
+ addfile(gap, buf, flags);
+ }
+ }
+
+ if (wn != NULL)
+ {
+ vim_free(p);
+ ok = FindNextFileW(hFind, &wfb);
+ }
+ else
+ ok = FindNextFile(hFind, &fb);
+
+ /* If no more matches and no match was used, try expanding the name
+ * itself. Finds the long name of a short filename. */
+ if (!ok && matchname != NULL && gap->ga_len == start_len)
+ {
+ STRCPY(s, matchname);
+ FindClose(hFind);
+ if (wn != NULL)
+ {
+ vim_free(wn);
+ wn = enc_to_utf16(buf, NULL);
+ if (wn != NULL)
+ hFind = FindFirstFileW(wn, &wfb);
+ }
+ if (wn == NULL)
+ hFind = FindFirstFile((LPCSTR)buf, &fb);
+ ok = (hFind != INVALID_HANDLE_VALUE);
+ VIM_CLEAR(matchname);
+ }
+ }
+
+ FindClose(hFind);
+ vim_free(wn);
+ vim_free(buf);
+ vim_regfree(regmatch.regprog);
+ vim_free(matchname);
+
+ matches = gap->ga_len - start_len;
+ if (matches > 0)
+ qsort(((char_u **)gap->ga_data) + start_len, (size_t)matches,
+ sizeof(char_u *), pstrcmp);
+ return matches;
+}
+
+ int
+mch_expandpath(
+ garray_T *gap,
+ char_u *path,
+ int flags) /* EW_* flags */
+{
+ return dos_expandpath(gap, path, 0, flags, FALSE);
+}
+# endif /* WIN3264 */
+
+#if (defined(UNIX) && !defined(VMS)) || defined(USE_UNIXFILENAME) \
+ || defined(PROTO)
+/*
+ * Unix style wildcard expansion code.
+ * It's here because it's used both for Unix and Mac.
+ */
+ static int
+pstrcmp(const void *a, const void *b)
+{
+ return (pathcmp(*(char **)a, *(char **)b, -1));
+}
+
+/*
+ * Recursively expand one path component into all matching files and/or
+ * directories. Adds matches to "gap". Handles "*", "?", "[a-z]", "**", etc.
+ * "path" has backslashes before chars that are not to be expanded, starting
+ * at "path + wildoff".
+ * Return the number of matches found.
+ * NOTE: much of this is identical to dos_expandpath(), keep in sync!
+ */
+ int
+unix_expandpath(
+ garray_T *gap,
+ char_u *path,
+ int wildoff,
+ int flags, /* EW_* flags */
+ int didstar) /* expanded "**" once already */
+{
+ char_u *buf;
+ char_u *path_end;
+ char_u *p, *s, *e;
+ int start_len = gap->ga_len;
+ char_u *pat;
+ regmatch_T regmatch;
+ int starts_with_dot;
+ int matches;
+ int len;
+ int starstar = FALSE;
+ static int stardepth = 0; /* depth for "**" expansion */
+
+ DIR *dirp;
+ struct dirent *dp;
+
+ /* Expanding "**" may take a long time, check for CTRL-C. */
+ if (stardepth > 0)
+ {
+ ui_breakcheck();
+ if (got_int)
+ return 0;
+ }
+
+ /* make room for file name */
+ buf = alloc((int)STRLEN(path) + BASENAMELEN + 5);
+ if (buf == NULL)
+ return 0;
+
+ /*
+ * Find the first part in the path name that contains a wildcard.
+ * When EW_ICASE is set every letter is considered to be a wildcard.
+ * Copy it into "buf", including the preceding characters.
+ */
+ p = buf;
+ s = buf;
+ e = NULL;
+ path_end = path;
+ while (*path_end != NUL)
+ {
+ /* May ignore a wildcard that has a backslash before it; it will
+ * be removed by rem_backslash() or file_pat_to_reg_pat() below. */
+ if (path_end >= path + wildoff && rem_backslash(path_end))
+ *p++ = *path_end++;
+ else if (*path_end == '/')
+ {
+ if (e != NULL)
+ break;
+ s = p + 1;
+ }
+ else if (path_end >= path + wildoff
+ && (vim_strchr((char_u *)"*?[{~$", *path_end) != NULL
+ || (!p_fic && (flags & EW_ICASE)
+ && isalpha(PTR2CHAR(path_end)))))
+ e = p;
+ if (has_mbyte)
+ {
+ len = (*mb_ptr2len)(path_end);
+ STRNCPY(p, path_end, len);
+ p += len;
+ path_end += len;
+ }
+ else
+ *p++ = *path_end++;
+ }
+ e = p;
+ *e = NUL;
+
+ /* Now we have one wildcard component between "s" and "e". */
+ /* Remove backslashes between "wildoff" and the start of the wildcard
+ * component. */
+ for (p = buf + wildoff; p < s; ++p)
+ if (rem_backslash(p))
+ {
+ STRMOVE(p, p + 1);
+ --e;
+ --s;
+ }
+
+ /* Check for "**" between "s" and "e". */
+ for (p = s; p < e; ++p)
+ if (p[0] == '*' && p[1] == '*')
+ starstar = TRUE;
+
+ /* convert the file pattern to a regexp pattern */
+ starts_with_dot = *s == '.';
+ pat = file_pat_to_reg_pat(s, e, NULL, FALSE);
+ if (pat == NULL)
+ {
+ vim_free(buf);
+ return 0;
+ }
+
+ /* compile the regexp into a program */
+ if (flags & EW_ICASE)
+ regmatch.rm_ic = TRUE; /* 'wildignorecase' set */
+ else
+ regmatch.rm_ic = p_fic; /* ignore case when 'fileignorecase' is set */
+ if (flags & (EW_NOERROR | EW_NOTWILD))
+ ++emsg_silent;
+ regmatch.regprog = vim_regcomp(pat, RE_MAGIC);
+ if (flags & (EW_NOERROR | EW_NOTWILD))
+ --emsg_silent;
+ vim_free(pat);
+
+ if (regmatch.regprog == NULL && (flags & EW_NOTWILD) == 0)
+ {
+ vim_free(buf);
+ return 0;
+ }
+
+ /* If "**" is by itself, this is the first time we encounter it and more
+ * is following then find matches without any directory. */
+ if (!didstar && stardepth < 100 && starstar && e - s == 2
+ && *path_end == '/')
+ {
+ STRCPY(s, path_end + 1);
+ ++stardepth;
+ (void)unix_expandpath(gap, buf, (int)(s - buf), flags, TRUE);
+ --stardepth;
+ }
+
+ /* open the directory for scanning */
+ *s = NUL;
+ dirp = opendir(*buf == NUL ? "." : (char *)buf);
+
+ /* Find all matching entries */
+ if (dirp != NULL)
+ {
+ for (;;)
+ {
+ dp = readdir(dirp);
+ if (dp == NULL)
+ break;
+ if ((dp->d_name[0] != '.' || starts_with_dot
+ || ((flags & EW_DODOT)
+ && dp->d_name[1] != NUL
+ && (dp->d_name[1] != '.' || dp->d_name[2] != NUL)))
+ && ((regmatch.regprog != NULL && vim_regexec(&regmatch,
+ (char_u *)dp->d_name, (colnr_T)0))
+ || ((flags & EW_NOTWILD)
+ && fnamencmp(path + (s - buf), dp->d_name, e - s) == 0)))
+ {
+ STRCPY(s, dp->d_name);
+ len = STRLEN(buf);
+
+ if (starstar && stardepth < 100)
+ {
+ /* For "**" in the pattern first go deeper in the tree to
+ * find matches. */
+ STRCPY(buf + len, "/**");
+ STRCPY(buf + len + 3, path_end);
+ ++stardepth;
+ (void)unix_expandpath(gap, buf, len + 1, flags, TRUE);
+ --stardepth;
+ }
+
+ STRCPY(buf + len, path_end);
+ if (mch_has_exp_wildcard(path_end)) /* handle more wildcards */
+ {
+ /* need to expand another component of the path */
+ /* remove backslashes for the remaining components only */
+ (void)unix_expandpath(gap, buf, len + 1, flags, FALSE);
+ }
+ else
+ {
+ stat_T sb;
+
+ /* no more wildcards, check if there is a match */
+ /* remove backslashes for the remaining components only */
+ if (*path_end != NUL)
+ backslash_halve(buf + len + 1);
+ /* add existing file or symbolic link */
+ if ((flags & EW_ALLLINKS) ? mch_lstat((char *)buf, &sb) >= 0
+ : mch_getperm(buf) >= 0)
+ {
+#ifdef MACOS_CONVERT
+ size_t precomp_len = STRLEN(buf)+1;
+ char_u *precomp_buf =
+ mac_precompose_path(buf, precomp_len, &precomp_len);
+
+ if (precomp_buf)
+ {
+ mch_memmove(buf, precomp_buf, precomp_len);
+ vim_free(precomp_buf);
+ }
+#endif
+ addfile(gap, buf, flags);
+ }
+ }
+ }
+ }
+
+ closedir(dirp);
+ }
+
+ vim_free(buf);
+ vim_regfree(regmatch.regprog);
+
+ matches = gap->ga_len - start_len;
+ if (matches > 0)
+ qsort(((char_u **)gap->ga_data) + start_len, matches,
+ sizeof(char_u *), pstrcmp);
+ return matches;
+}
+#endif
+
+#if defined(FEAT_SEARCHPATH)
+/*
+ * Moves "*psep" back to the previous path separator in "path".
+ * Returns FAIL is "*psep" ends up at the beginning of "path".
+ */
+ static int
+find_previous_pathsep(char_u *path, char_u **psep)
+{
+ /* skip the current separator */
+ if (*psep > path && vim_ispathsep(**psep))
+ --*psep;
+
+ /* find the previous separator */
+ while (*psep > path)
+ {
+ if (vim_ispathsep(**psep))
+ return OK;
+ MB_PTR_BACK(path, *psep);
+ }
+
+ return FAIL;
+}
+
+/*
+ * Returns TRUE if "maybe_unique" is unique wrt other_paths in "gap".
+ * "maybe_unique" is the end portion of "((char_u **)gap->ga_data)[i]".
+ */
+ static int
+is_unique(char_u *maybe_unique, garray_T *gap, int i)
+{
+ int j;
+ int candidate_len;
+ int other_path_len;
+ char_u **other_paths = (char_u **)gap->ga_data;
+ char_u *rival;
+
+ for (j = 0; j < gap->ga_len; j++)
+ {
+ if (j == i)
+ continue; /* don't compare it with itself */
+
+ candidate_len = (int)STRLEN(maybe_unique);
+ other_path_len = (int)STRLEN(other_paths[j]);
+ if (other_path_len < candidate_len)
+ continue; /* it's different when it's shorter */
+
+ rival = other_paths[j] + other_path_len - candidate_len;
+ if (fnamecmp(maybe_unique, rival) == 0
+ && (rival == other_paths[j] || vim_ispathsep(*(rival - 1))))
+ return FALSE; /* match */
+ }
+
+ return TRUE; /* no match found */
+}
+
+/*
+ * Split the 'path' option into an array of strings in garray_T. Relative
+ * paths are expanded to their equivalent fullpath. This includes the "."
+ * (relative to current buffer directory) and empty path (relative to current
+ * directory) notations.
+ *
+ * TODO: handle upward search (;) and path limiter (**N) notations by
+ * expanding each into their equivalent path(s).
+ */
+ static void
+expand_path_option(char_u *curdir, garray_T *gap)
+{
+ char_u *path_option = *curbuf->b_p_path == NUL
+ ? p_path : curbuf->b_p_path;
+ char_u *buf;
+ char_u *p;
+ int len;
+
+ if ((buf = alloc((int)MAXPATHL)) == NULL)
+ return;
+
+ while (*path_option != NUL)
+ {
+ copy_option_part(&path_option, buf, MAXPATHL, " ,");
+
+ if (buf[0] == '.' && (buf[1] == NUL || vim_ispathsep(buf[1])))
+ {
+ /* Relative to current buffer:
+ * "/path/file" + "." -> "/path/"
+ * "/path/file" + "./subdir" -> "/path/subdir" */
+ if (curbuf->b_ffname == NULL)
+ continue;
+ p = gettail(curbuf->b_ffname);
+ len = (int)(p - curbuf->b_ffname);
+ if (len + (int)STRLEN(buf) >= MAXPATHL)
+ continue;
+ if (buf[1] == NUL)
+ buf[len] = NUL;
+ else
+ STRMOVE(buf + len, buf + 2);
+ mch_memmove(buf, curbuf->b_ffname, len);
+ simplify_filename(buf);
+ }
+ else if (buf[0] == NUL)
+ /* relative to current directory */
+ STRCPY(buf, curdir);
+ else if (path_with_url(buf))
+ /* URL can't be used here */
+ continue;
+ else if (!mch_isFullName(buf))
+ {
+ /* Expand relative path to their full path equivalent */
+ len = (int)STRLEN(curdir);
+ if (len + (int)STRLEN(buf) + 3 > MAXPATHL)
+ continue;
+ STRMOVE(buf + len + 1, buf);
+ STRCPY(buf, curdir);
+ buf[len] = PATHSEP;
+ simplify_filename(buf);
+ }
+
+ if (ga_grow(gap, 1) == FAIL)
+ break;
+
+# if defined(MSWIN)
+ /* Avoid the path ending in a backslash, it fails when a comma is
+ * appended. */
+ len = (int)STRLEN(buf);
+ if (buf[len - 1] == '\\')
+ buf[len - 1] = '/';
+# endif
+
+ p = vim_strsave(buf);
+ if (p == NULL)
+ break;
+ ((char_u **)gap->ga_data)[gap->ga_len++] = p;
+ }
+
+ vim_free(buf);
+}
+
+/*
+ * Returns a pointer to the file or directory name in "fname" that matches the
+ * longest path in "ga"p, or NULL if there is no match. For example:
+ *
+ * path: /foo/bar/baz
+ * fname: /foo/bar/baz/quux.txt
+ * returns: ^this
+ */
+ static char_u *
+get_path_cutoff(char_u *fname, garray_T *gap)
+{
+ int i;
+ int maxlen = 0;
+ char_u **path_part = (char_u **)gap->ga_data;
+ char_u *cutoff = NULL;
+
+ for (i = 0; i < gap->ga_len; i++)
+ {
+ int j = 0;
+
+ while ((fname[j] == path_part[i][j]
+# if defined(MSWIN)
+ || (vim_ispathsep(fname[j]) && vim_ispathsep(path_part[i][j]))
+#endif
+ ) && fname[j] != NUL && path_part[i][j] != NUL)
+ j++;
+ if (j > maxlen)
+ {
+ maxlen = j;
+ cutoff = &fname[j];
+ }
+ }
+
+ /* skip to the file or directory name */
+ if (cutoff != NULL)
+ while (vim_ispathsep(*cutoff))
+ MB_PTR_ADV(cutoff);
+
+ return cutoff;
+}
+
+/*
+ * Sorts, removes duplicates and modifies all the fullpath names in "gap" so
+ * that they are unique with respect to each other while conserving the part
+ * that matches the pattern. Beware, this is at least O(n^2) wrt "gap->ga_len".
+ */
+ static void
+uniquefy_paths(garray_T *gap, char_u *pattern)
+{
+ int i;
+ int len;
+ char_u **fnames = (char_u **)gap->ga_data;
+ int sort_again = FALSE;
+ char_u *pat;
+ char_u *file_pattern;
+ char_u *curdir;
+ regmatch_T regmatch;
+ garray_T path_ga;
+ char_u **in_curdir = NULL;
+ char_u *short_name;
+
+ remove_duplicates(gap);
+ ga_init2(&path_ga, (int)sizeof(char_u *), 1);
+
+ /*
+ * We need to prepend a '*' at the beginning of file_pattern so that the
+ * regex matches anywhere in the path. FIXME: is this valid for all
+ * possible patterns?
+ */
+ len = (int)STRLEN(pattern);
+ file_pattern = alloc(len + 2);
+ if (file_pattern == NULL)
+ return;
+ file_pattern[0] = '*';
+ file_pattern[1] = NUL;
+ STRCAT(file_pattern, pattern);
+ pat = file_pat_to_reg_pat(file_pattern, NULL, NULL, TRUE);
+ vim_free(file_pattern);
+ if (pat == NULL)
+ return;
+
+ regmatch.rm_ic = TRUE; /* always ignore case */
+ regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
+ vim_free(pat);
+ if (regmatch.regprog == NULL)
+ return;
+
+ if ((curdir = alloc((int)(MAXPATHL))) == NULL)
+ goto theend;
+ mch_dirname(curdir, MAXPATHL);
+ expand_path_option(curdir, &path_ga);
+
+ in_curdir = (char_u **)alloc_clear(gap->ga_len * sizeof(char_u *));
+ if (in_curdir == NULL)
+ goto theend;
+
+ for (i = 0; i < gap->ga_len && !got_int; i++)
+ {
+ char_u *path = fnames[i];
+ int is_in_curdir;
+ char_u *dir_end = gettail_dir(path);
+ char_u *pathsep_p;
+ char_u *path_cutoff;
+
+ len = (int)STRLEN(path);
+ is_in_curdir = fnamencmp(curdir, path, dir_end - path) == 0
+ && curdir[dir_end - path] == NUL;
+ if (is_in_curdir)
+ in_curdir[i] = vim_strsave(path);
+
+ /* Shorten the filename while maintaining its uniqueness */
+ path_cutoff = get_path_cutoff(path, &path_ga);
+
+ /* Don't assume all files can be reached without path when search
+ * pattern starts with star star slash, so only remove path_cutoff
+ * when possible. */
+ if (pattern[0] == '*' && pattern[1] == '*'
+ && vim_ispathsep_nocolon(pattern[2])
+ && path_cutoff != NULL
+ && vim_regexec(&regmatch, path_cutoff, (colnr_T)0)
+ && is_unique(path_cutoff, gap, i))
+ {
+ sort_again = TRUE;
+ mch_memmove(path, path_cutoff, STRLEN(path_cutoff) + 1);
+ }
+ else
+ {
+ /* Here all files can be reached without path, so get shortest
+ * unique path. We start at the end of the path. */
+ pathsep_p = path + len - 1;
+
+ while (find_previous_pathsep(path, &pathsep_p))
+ if (vim_regexec(&regmatch, pathsep_p + 1, (colnr_T)0)
+ && is_unique(pathsep_p + 1, gap, i)
+ && path_cutoff != NULL && pathsep_p + 1 >= path_cutoff)
+ {
+ sort_again = TRUE;
+ mch_memmove(path, pathsep_p + 1, STRLEN(pathsep_p));
+ break;
+ }
+ }
+
+ if (mch_isFullName(path))
+ {
+ /*
+ * Last resort: shorten relative to curdir if possible.
+ * 'possible' means:
+ * 1. It is under the current directory.
+ * 2. The result is actually shorter than the original.
+ *
+ * Before curdir After
+ * /foo/bar/file.txt /foo/bar ./file.txt
+ * c:\foo\bar\file.txt c:\foo\bar .\file.txt
+ * /file.txt / /file.txt
+ * c:\file.txt c:\ .\file.txt
+ */
+ short_name = shorten_fname(path, curdir);
+ if (short_name != NULL && short_name > path + 1
+#if defined(MSWIN)
+ /* On windows,
+ * shorten_fname("c:\a\a.txt", "c:\a\b")
+ * returns "\a\a.txt", which is not really the short
+ * name, hence: */
+ && !vim_ispathsep(*short_name)
+#endif
+ )
+ {
+ STRCPY(path, ".");
+ add_pathsep(path);
+ STRMOVE(path + STRLEN(path), short_name);
+ }
+ }
+ ui_breakcheck();
+ }
+
+ /* Shorten filenames in /in/current/directory/{filename} */
+ for (i = 0; i < gap->ga_len && !got_int; i++)
+ {
+ char_u *rel_path;
+ char_u *path = in_curdir[i];
+
+ if (path == NULL)
+ continue;
+
+ /* If the {filename} is not unique, change it to ./{filename}.
+ * Else reduce it to {filename} */
+ short_name = shorten_fname(path, curdir);
+ if (short_name == NULL)
+ short_name = path;
+ if (is_unique(short_name, gap, i))
+ {
+ STRCPY(fnames[i], short_name);
+ continue;
+ }
+
+ rel_path = alloc((int)(STRLEN(short_name) + STRLEN(PATHSEPSTR) + 2));
+ if (rel_path == NULL)
+ goto theend;
+ STRCPY(rel_path, ".");
+ add_pathsep(rel_path);
+ STRCAT(rel_path, short_name);
+
+ vim_free(fnames[i]);
+ fnames[i] = rel_path;
+ sort_again = TRUE;
+ ui_breakcheck();
+ }
+
+theend:
+ vim_free(curdir);
+ if (in_curdir != NULL)
+ {
+ for (i = 0; i < gap->ga_len; i++)
+ vim_free(in_curdir[i]);
+ vim_free(in_curdir);
+ }
+ ga_clear_strings(&path_ga);
+ vim_regfree(regmatch.regprog);
+
+ if (sort_again)
+ remove_duplicates(gap);
+}
+
+/*
+ * Calls globpath() with 'path' values for the given pattern and stores the
+ * result in "gap".
+ * Returns the total number of matches.
+ */
+ static int
+expand_in_path(
+ garray_T *gap,
+ char_u *pattern,
+ int flags) /* EW_* flags */
+{
+ char_u *curdir;
+ garray_T path_ga;
+ char_u *paths = NULL;
+ int glob_flags = 0;
+
+ if ((curdir = alloc((unsigned)MAXPATHL)) == NULL)
+ return 0;
+ mch_dirname(curdir, MAXPATHL);
+
+ ga_init2(&path_ga, (int)sizeof(char_u *), 1);
+ expand_path_option(curdir, &path_ga);
+ vim_free(curdir);
+ if (path_ga.ga_len == 0)
+ return 0;
+
+ paths = ga_concat_strings(&path_ga, ",");
+ ga_clear_strings(&path_ga);
+ if (paths == NULL)
+ return 0;
+
+ if (flags & EW_ICASE)
+ glob_flags |= WILD_ICASE;
+ if (flags & EW_ADDSLASH)
+ glob_flags |= WILD_ADD_SLASH;
+ globpath(paths, pattern, gap, glob_flags);
+ vim_free(paths);
+
+ return gap->ga_len;
+}
+#endif
+
+#if defined(FEAT_SEARCHPATH) || defined(FEAT_CMDL_COMPL) || defined(PROTO)
+/*
+ * Sort "gap" and remove duplicate entries. "gap" is expected to contain a
+ * list of file names in allocated memory.
+ */
+ void
+remove_duplicates(garray_T *gap)
+{
+ int i;
+ int j;
+ char_u **fnames = (char_u **)gap->ga_data;
+
+ sort_strings(fnames, gap->ga_len);
+ for (i = gap->ga_len - 1; i > 0; --i)
+ if (fnamecmp(fnames[i - 1], fnames[i]) == 0)
+ {
+ vim_free(fnames[i]);
+ for (j = i + 1; j < gap->ga_len; ++j)
+ fnames[j - 1] = fnames[j];
+ --gap->ga_len;
+ }
+}
+#endif
+
+/*
+ * Return TRUE if "p" contains what looks like an environment variable.
+ * Allowing for escaping.
+ */
+ static int
+has_env_var(char_u *p)
+{
+ for ( ; *p; MB_PTR_ADV(p))
+ {
+ if (*p == '\\' && p[1] != NUL)
+ ++p;
+ else if (vim_strchr((char_u *)
+#if defined(MSWIN)
+ "$%"
+#else
+ "$"
+#endif
+ , *p) != NULL)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+#ifdef SPECIAL_WILDCHAR
+/*
+ * Return TRUE if "p" contains a special wildcard character, one that Vim
+ * cannot expand, requires using a shell.
+ */
+ static int
+has_special_wildchar(char_u *p)
+{
+ for ( ; *p; MB_PTR_ADV(p))
+ {
+ /* Allow for escaping. */
+ if (*p == '\\' && p[1] != NUL)
+ ++p;
+ else if (vim_strchr((char_u *)SPECIAL_WILDCHAR, *p) != NULL)
+ return TRUE;
+ }
+ return FALSE;
+}
+#endif
+
+/*
+ * Generic wildcard expansion code.
+ *
+ * Characters in "pat" that should not be expanded must be preceded with a
+ * backslash. E.g., "/path\ with\ spaces/my\*star*"
+ *
+ * Return FAIL when no single file was found. In this case "num_file" is not
+ * set, and "file" may contain an error message.
+ * Return OK when some files found. "num_file" is set to the number of
+ * matches, "file" to the array of matches. Call FreeWild() later.
+ */
+ int
+gen_expand_wildcards(
+ int num_pat, /* number of input patterns */
+ char_u **pat, /* array of input patterns */
+ int *num_file, /* resulting number of files */
+ char_u ***file, /* array of resulting files */
+ int flags) /* EW_* flags */
+{
+ int i;
+ garray_T ga;
+ char_u *p;
+ static int recursive = FALSE;
+ int add_pat;
+ int retval = OK;
+#if defined(FEAT_SEARCHPATH)
+ int did_expand_in_path = FALSE;
+#endif
+
+ /*
+ * expand_env() is called to expand things like "~user". If this fails,
+ * it calls ExpandOne(), which brings us back here. In this case, always
+ * call the machine specific expansion function, if possible. Otherwise,
+ * return FAIL.
+ */
+ if (recursive)
+#ifdef SPECIAL_WILDCHAR
+ return mch_expand_wildcards(num_pat, pat, num_file, file, flags);
+#else
+ return FAIL;
+#endif
+
+#ifdef SPECIAL_WILDCHAR
+ /*
+ * If there are any special wildcard characters which we cannot handle
+ * here, call machine specific function for all the expansion. This
+ * avoids starting the shell for each argument separately.
+ * For `=expr` do use the internal function.
+ */
+ for (i = 0; i < num_pat; i++)
+ {
+ if (has_special_wildchar(pat[i])
+# ifdef VIM_BACKTICK
+ && !(vim_backtick(pat[i]) && pat[i][1] == '=')
+# endif
+ )
+ return mch_expand_wildcards(num_pat, pat, num_file, file, flags);
+ }
+#endif
+
+ recursive = TRUE;
+
+ /*
+ * The matching file names are stored in a growarray. Init it empty.
+ */
+ ga_init2(&ga, (int)sizeof(char_u *), 30);
+
+ for (i = 0; i < num_pat; ++i)
+ {
+ add_pat = -1;
+ p = pat[i];
+
+#ifdef VIM_BACKTICK
+ if (vim_backtick(p))
+ {
+ add_pat = expand_backtick(&ga, p, flags);
+ if (add_pat == -1)
+ retval = FAIL;
+ }
+ else
+#endif
+ {
+ /*
+ * First expand environment variables, "~/" and "~user/".
+ */
+ if (has_env_var(p) || *p == '~')
+ {
+ p = expand_env_save_opt(p, TRUE);
+ if (p == NULL)
+ p = pat[i];
+#ifdef UNIX
+ /*
+ * On Unix, if expand_env() can't expand an environment
+ * variable, use the shell to do that. Discard previously
+ * found file names and start all over again.
+ */
+ else if (has_env_var(p) || *p == '~')
+ {
+ vim_free(p);
+ ga_clear_strings(&ga);
+ i = mch_expand_wildcards(num_pat, pat, num_file, file,
+ flags|EW_KEEPDOLLAR);
+ recursive = FALSE;
+ return i;
+ }
+#endif
+ }
+
+ /*
+ * If there are wildcards: Expand file names and add each match to
+ * the list. If there is no match, and EW_NOTFOUND is given, add
+ * the pattern.
+ * If there are no wildcards: Add the file name if it exists or
+ * when EW_NOTFOUND is given.
+ */
+ if (mch_has_exp_wildcard(p))
+ {
+#if defined(FEAT_SEARCHPATH)
+ if ((flags & EW_PATH)
+ && !mch_isFullName(p)
+ && !(p[0] == '.'
+ && (vim_ispathsep(p[1])
+ || (p[1] == '.' && vim_ispathsep(p[2]))))
+ )
+ {
+ /* :find completion where 'path' is used.
+ * Recursiveness is OK here. */
+ recursive = FALSE;
+ add_pat = expand_in_path(&ga, p, flags);
+ recursive = TRUE;
+ did_expand_in_path = TRUE;
+ }
+ else
+#endif
+ add_pat = mch_expandpath(&ga, p, flags);
+ }
+ }
+
+ if (add_pat == -1 || (add_pat == 0 && (flags & EW_NOTFOUND)))
+ {
+ char_u *t = backslash_halve_save(p);
+
+ /* When EW_NOTFOUND is used, always add files and dirs. Makes
+ * "vim c:/" work. */
+ if (flags & EW_NOTFOUND)
+ addfile(&ga, t, flags | EW_DIR | EW_FILE);
+ else
+ addfile(&ga, t, flags);
+ vim_free(t);
+ }
+
+#if defined(FEAT_SEARCHPATH)
+ if (did_expand_in_path && ga.ga_len > 0 && (flags & EW_PATH))
+ uniquefy_paths(&ga, p);
+#endif
+ if (p != pat[i])
+ vim_free(p);
+ }
+
+ *num_file = ga.ga_len;
+ *file = (ga.ga_data != NULL) ? (char_u **)ga.ga_data : (char_u **)"";
+
+ recursive = FALSE;
+
+ return ((flags & EW_EMPTYOK) || ga.ga_data != NULL) ? retval : FAIL;
+}
+
+# ifdef VIM_BACKTICK
+
+/*
+ * Return TRUE if we can expand this backtick thing here.
+ */
+ static int
+vim_backtick(char_u *p)
+{
+ return (*p == '`' && *(p + 1) != NUL && *(p + STRLEN(p) - 1) == '`');
+}
+
+/*
+ * Expand an item in `backticks` by executing it as a command.
+ * Currently only works when pat[] starts and ends with a `.
+ * Returns number of file names found, -1 if an error is encountered.
+ */
+ static int
+expand_backtick(
+ garray_T *gap,
+ char_u *pat,
+ int flags) /* EW_* flags */
+{
+ char_u *p;
+ char_u *cmd;
+ char_u *buffer;
+ int cnt = 0;
+ int i;
+
+ /* Create the command: lop off the backticks. */
+ cmd = vim_strnsave(pat + 1, (int)STRLEN(pat) - 2);
+ if (cmd == NULL)
+ return -1;
+
+#ifdef FEAT_EVAL
+ if (*cmd == '=') /* `={expr}`: Expand expression */
+ buffer = eval_to_string(cmd + 1, &p, TRUE);
+ else
+#endif
+ buffer = get_cmd_output(cmd, NULL,
+ (flags & EW_SILENT) ? SHELL_SILENT : 0, NULL);
+ vim_free(cmd);
+ if (buffer == NULL)
+ return -1;
+
+ cmd = buffer;
+ while (*cmd != NUL)
+ {
+ cmd = skipwhite(cmd); /* skip over white space */
+ p = cmd;
+ while (*p != NUL && *p != '\r' && *p != '\n') /* skip over entry */
+ ++p;
+ /* add an entry if it is not empty */
+ if (p > cmd)
+ {
+ i = *p;
+ *p = NUL;
+ addfile(gap, cmd, flags);
+ *p = i;
+ ++cnt;
+ }
+ cmd = p;
+ while (*cmd != NUL && (*cmd == '\r' || *cmd == '\n'))
+ ++cmd;
+ }
+
+ vim_free(buffer);
+ return cnt;
+}
+# endif /* VIM_BACKTICK */
+
+/*
+ * Add a file to a file list. Accepted flags:
+ * EW_DIR add directories
+ * EW_FILE add files
+ * EW_EXEC add executable files
+ * EW_NOTFOUND add even when it doesn't exist
+ * EW_ADDSLASH add slash after directory name
+ * EW_ALLLINKS add symlink also when the referred file does not exist
+ */
+ void
+addfile(
+ garray_T *gap,
+ char_u *f, /* filename */
+ int flags)
+{
+ char_u *p;
+ int isdir;
+ stat_T sb;
+
+ /* if the file/dir/link doesn't exist, may not add it */
+ if (!(flags & EW_NOTFOUND) && ((flags & EW_ALLLINKS)
+ ? mch_lstat((char *)f, &sb) < 0 : mch_getperm(f) < 0))
+ return;
+
+#ifdef FNAME_ILLEGAL
+ /* if the file/dir contains illegal characters, don't add it */
+ if (vim_strpbrk(f, (char_u *)FNAME_ILLEGAL) != NULL)
+ return;
+#endif
+
+ isdir = mch_isdir(f);
+ if ((isdir && !(flags & EW_DIR)) || (!isdir && !(flags & EW_FILE)))
+ return;
+
+ /* If the file isn't executable, may not add it. Do accept directories.
+ * When invoked from expand_shellcmd() do not use $PATH. */
+ if (!isdir && (flags & EW_EXEC)
+ && !mch_can_exe(f, NULL, !(flags & EW_SHELLCMD)))
+ return;
+
+ /* Make room for another item in the file list. */
+ if (ga_grow(gap, 1) == FAIL)
+ return;
+
+ p = alloc((unsigned)(STRLEN(f) + 1 + isdir));
+ if (p == NULL)
+ return;
+
+ STRCPY(p, f);
+#ifdef BACKSLASH_IN_FILENAME
+ slash_adjust(p);
+#endif
+ /*
+ * Append a slash or backslash after directory names if none is present.
+ */
+#ifndef DONT_ADD_PATHSEP_TO_DIR
+ if (isdir && (flags & EW_ADDSLASH))
+ add_pathsep(p);
+#endif
+ ((char_u **)gap->ga_data)[gap->ga_len++] = p;
+}
+#endif /* !NO_EXPANDPATH */
+
+#if defined(VIM_BACKTICK) || defined(FEAT_EVAL) || defined(PROTO)
+
+#ifndef SEEK_SET
+# define SEEK_SET 0
+#endif
+#ifndef SEEK_END
+# define SEEK_END 2
+#endif
+
+/*
+ * Get the stdout of an external command.
+ * If "ret_len" is NULL replace NUL characters with NL. When "ret_len" is not
+ * NULL store the length there.
+ * Returns an allocated string, or NULL for error.
+ */
+ char_u *
+get_cmd_output(
+ char_u *cmd,
+ char_u *infile, /* optional input file name */
+ int flags, /* can be SHELL_SILENT */
+ int *ret_len)
+{
+ char_u *tempname;
+ char_u *command;
+ char_u *buffer = NULL;
+ int len;
+ int i = 0;
+ FILE *fd;
+
+ if (check_restricted() || check_secure())
+ return NULL;
+
+ /* get a name for the temp file */
+ if ((tempname = vim_tempname('o', FALSE)) == NULL)
+ {
+ emsg(_(e_notmp));
+ return NULL;
+ }
+
+ /* Add the redirection stuff */
+ command = make_filter_cmd(cmd, infile, tempname);
+ if (command == NULL)
+ goto done;
+
+ /*
+ * Call the shell to execute the command (errors are ignored).
+ * Don't check timestamps here.
+ */
+ ++no_check_timestamps;
+ call_shell(command, SHELL_DOOUT | SHELL_EXPAND | flags);
+ --no_check_timestamps;
+
+ vim_free(command);
+
+ /*
+ * read the names from the file into memory
+ */
+# ifdef VMS
+ /* created temporary file is not always readable as binary */
+ fd = mch_fopen((char *)tempname, "r");
+# else
+ fd = mch_fopen((char *)tempname, READBIN);
+# endif
+
+ if (fd == NULL)
+ {
+ semsg(_(e_notopen), tempname);
+ goto done;
+ }
+
+ fseek(fd, 0L, SEEK_END);
+ len = ftell(fd); /* get size of temp file */
+ fseek(fd, 0L, SEEK_SET);
+
+ buffer = alloc(len + 1);
+ if (buffer != NULL)
+ i = (int)fread((char *)buffer, (size_t)1, (size_t)len, fd);
+ fclose(fd);
+ mch_remove(tempname);
+ if (buffer == NULL)
+ goto done;
+#ifdef VMS
+ len = i; /* VMS doesn't give us what we asked for... */
+#endif
+ if (i != len)
+ {
+ semsg(_(e_notread), tempname);
+ VIM_CLEAR(buffer);
+ }
+ else if (ret_len == NULL)
+ {
+ /* Change NUL into SOH, otherwise the string is truncated. */
+ for (i = 0; i < len; ++i)
+ if (buffer[i] == NUL)
+ buffer[i] = 1;
+
+ buffer[len] = NUL; /* make sure the buffer is terminated */
+ }
+ else
+ *ret_len = len;
+
+done:
+ vim_free(tempname);
+ return buffer;
+}
+#endif
+
+/*
+ * Free the list of files returned by expand_wildcards() or other expansion
+ * functions.
+ */
+ void
+FreeWild(int count, char_u **files)
+{
+ if (count <= 0 || files == NULL)
+ return;
+ while (count--)
+ vim_free(files[count]);
+ vim_free(files);
+}
+
+/*
+ * Return TRUE when need to go to Insert mode because of 'insertmode'.
+ * Don't do this when still processing a command or a mapping.
+ * Don't do this when inside a ":normal" command.
+ */
+ int
+goto_im(void)
+{
+ return (p_im && stuff_empty() && typebuf_typed());
+}
+
+/*
+ * Returns the isolated name of the shell in allocated memory:
+ * - Skip beyond any path. E.g., "/usr/bin/csh -f" -> "csh -f".
+ * - Remove any argument. E.g., "csh -f" -> "csh".
+ * But don't allow a space in the path, so that this works:
+ * "/usr/bin/csh --rcfile ~/.cshrc"
+ * But don't do that for Windows, it's common to have a space in the path.
+ */
+ char_u *
+get_isolated_shell_name(void)
+{
+ char_u *p;
+
+#ifdef WIN3264
+ p = gettail(p_sh);
+ p = vim_strnsave(p, (int)(skiptowhite(p) - p));
+#else
+ p = skiptowhite(p_sh);
+ if (*p == NUL)
+ {
+ /* No white space, use the tail. */
+ p = vim_strsave(gettail(p_sh));
+ }
+ else
+ {
+ char_u *p1, *p2;
+
+ /* Find the last path separator before the space. */
+ p1 = p_sh;
+ for (p2 = p_sh; p2 < p; MB_PTR_ADV(p2))
+ if (vim_ispathsep(*p2))
+ p1 = p2 + 1;
+ p = vim_strnsave(p1, (int)(p - p1));
+ }
+#endif
+ return p;
+}
diff --git a/src/misc2.c b/src/misc2.c
new file mode 100644
index 0000000..278cc33
--- /dev/null
+++ b/src/misc2.c
@@ -0,0 +1,6579 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * misc2.c: Various functions.
+ */
+#include "vim.h"
+
+static char_u *username = NULL; /* cached result of mch_get_user_name() */
+
+static char_u *ff_expand_buffer = NULL; /* used for expanding filenames */
+
+static int coladvance2(pos_T *pos, int addspaces, int finetune, colnr_T wcol);
+
+/*
+ * Return TRUE if in the current mode we need to use virtual.
+ */
+ int
+virtual_active(void)
+{
+ /* While an operator is being executed we return "virtual_op", because
+ * VIsual_active has already been reset, thus we can't check for "block"
+ * being used. */
+ if (virtual_op != MAYBE)
+ return virtual_op;
+ return (ve_flags == VE_ALL
+ || ((ve_flags & VE_BLOCK) && VIsual_active && VIsual_mode == Ctrl_V)
+ || ((ve_flags & VE_INSERT) && (State & INSERT)));
+}
+
+/*
+ * Get the screen position of the cursor.
+ */
+ int
+getviscol(void)
+{
+ colnr_T x;
+
+ getvvcol(curwin, &curwin->w_cursor, &x, NULL, NULL);
+ return (int)x;
+}
+
+/*
+ * Go to column "wcol", and add/insert white space as necessary to get the
+ * cursor in that column.
+ * The caller must have saved the cursor line for undo!
+ */
+ int
+coladvance_force(colnr_T wcol)
+{
+ int rc = coladvance2(&curwin->w_cursor, TRUE, FALSE, wcol);
+
+ if (wcol == MAXCOL)
+ curwin->w_valid &= ~VALID_VIRTCOL;
+ else
+ {
+ /* Virtcol is valid */
+ curwin->w_valid |= VALID_VIRTCOL;
+ curwin->w_virtcol = wcol;
+ }
+ return rc;
+}
+
+/*
+ * Get the screen position of character col with a coladd in the cursor line.
+ */
+ int
+getviscol2(colnr_T col, colnr_T coladd UNUSED)
+{
+ colnr_T x;
+ pos_T pos;
+
+ pos.lnum = curwin->w_cursor.lnum;
+ pos.col = col;
+ pos.coladd = coladd;
+ getvvcol(curwin, &pos, &x, NULL, NULL);
+ return (int)x;
+}
+
+/*
+ * Try to advance the Cursor to the specified screen column.
+ * If virtual editing: fine tune the cursor position.
+ * Note that all virtual positions off the end of a line should share
+ * a curwin->w_cursor.col value (n.b. this is equal to STRLEN(line)),
+ * beginning at coladd 0.
+ *
+ * return OK if desired column is reached, FAIL if not
+ */
+ int
+coladvance(colnr_T wcol)
+{
+ int rc = getvpos(&curwin->w_cursor, wcol);
+
+ if (wcol == MAXCOL || rc == FAIL)
+ curwin->w_valid &= ~VALID_VIRTCOL;
+ else if (*ml_get_cursor() != TAB)
+ {
+ /* Virtcol is valid when not on a TAB */
+ curwin->w_valid |= VALID_VIRTCOL;
+ curwin->w_virtcol = wcol;
+ }
+ return rc;
+}
+
+/*
+ * Return in "pos" the position of the cursor advanced to screen column "wcol".
+ * return OK if desired column is reached, FAIL if not
+ */
+ int
+getvpos(pos_T *pos, colnr_T wcol)
+{
+ return coladvance2(pos, FALSE, virtual_active(), wcol);
+}
+
+ static int
+coladvance2(
+ pos_T *pos,
+ int addspaces, /* change the text to achieve our goal? */
+ int finetune, /* change char offset for the exact column */
+ colnr_T wcol) /* column to move to */
+{
+ int idx;
+ char_u *ptr;
+ char_u *line;
+ colnr_T col = 0;
+ int csize = 0;
+ int one_more;
+#ifdef FEAT_LINEBREAK
+ int head = 0;
+#endif
+
+ one_more = (State & INSERT)
+ || restart_edit != NUL
+ || (VIsual_active && *p_sel != 'o')
+ || ((ve_flags & VE_ONEMORE) && wcol < MAXCOL) ;
+ line = ml_get_buf(curbuf, pos->lnum, FALSE);
+
+ if (wcol >= MAXCOL)
+ {
+ idx = (int)STRLEN(line) - 1 + one_more;
+ col = wcol;
+
+ if ((addspaces || finetune) && !VIsual_active)
+ {
+ curwin->w_curswant = linetabsize(line) + one_more;
+ if (curwin->w_curswant > 0)
+ --curwin->w_curswant;
+ }
+ }
+ else
+ {
+ int width = curwin->w_width - win_col_off(curwin);
+
+ if (finetune
+ && curwin->w_p_wrap
+ && curwin->w_width != 0
+ && wcol >= (colnr_T)width)
+ {
+ csize = linetabsize(line);
+ if (csize > 0)
+ csize--;
+
+ if (wcol / width > (colnr_T)csize / width
+ && ((State & INSERT) == 0 || (int)wcol > csize + 1))
+ {
+ /* In case of line wrapping don't move the cursor beyond the
+ * right screen edge. In Insert mode allow going just beyond
+ * the last character (like what happens when typing and
+ * reaching the right window edge). */
+ wcol = (csize / width + 1) * width - 1;
+ }
+ }
+
+ ptr = line;
+ while (col <= wcol && *ptr != NUL)
+ {
+ /* Count a tab for what it's worth (if list mode not on) */
+#ifdef FEAT_LINEBREAK
+ csize = win_lbr_chartabsize(curwin, line, ptr, col, &head);
+ MB_PTR_ADV(ptr);
+#else
+ csize = lbr_chartabsize_adv(line, &ptr, col);
+#endif
+ col += csize;
+ }
+ idx = (int)(ptr - line);
+ /*
+ * Handle all the special cases. The virtual_active() check
+ * is needed to ensure that a virtual position off the end of
+ * a line has the correct indexing. The one_more comparison
+ * replaces an explicit add of one_more later on.
+ */
+ if (col > wcol || (!virtual_active() && one_more == 0))
+ {
+ idx -= 1;
+# ifdef FEAT_LINEBREAK
+ /* Don't count the chars from 'showbreak'. */
+ csize -= head;
+# endif
+ col -= csize;
+ }
+
+ if (virtual_active()
+ && addspaces
+ && ((col != wcol && col != wcol + 1) || csize > 1))
+ {
+ /* 'virtualedit' is set: The difference between wcol and col is
+ * filled with spaces. */
+
+ if (line[idx] == NUL)
+ {
+ /* Append spaces */
+ int correct = wcol - col;
+ char_u *newline = alloc(idx + correct + 1);
+ int t;
+
+ if (newline == NULL)
+ return FAIL;
+
+ for (t = 0; t < idx; ++t)
+ newline[t] = line[t];
+
+ for (t = 0; t < correct; ++t)
+ newline[t + idx] = ' ';
+
+ newline[idx + correct] = NUL;
+
+ ml_replace(pos->lnum, newline, FALSE);
+ changed_bytes(pos->lnum, (colnr_T)idx);
+ idx += correct;
+ col = wcol;
+ }
+ else
+ {
+ /* Break a tab */
+ int linelen = (int)STRLEN(line);
+ int correct = wcol - col - csize + 1; /* negative!! */
+ char_u *newline;
+ int t, s = 0;
+ int v;
+
+ if (-correct > csize)
+ return FAIL;
+
+ newline = alloc(linelen + csize);
+ if (newline == NULL)
+ return FAIL;
+
+ for (t = 0; t < linelen; t++)
+ {
+ if (t != idx)
+ newline[s++] = line[t];
+ else
+ for (v = 0; v < csize; v++)
+ newline[s++] = ' ';
+ }
+
+ newline[linelen + csize - 1] = NUL;
+
+ ml_replace(pos->lnum, newline, FALSE);
+ changed_bytes(pos->lnum, idx);
+ idx += (csize - 1 + correct);
+ col += correct;
+ }
+ }
+ }
+
+ if (idx < 0)
+ pos->col = 0;
+ else
+ pos->col = idx;
+
+ pos->coladd = 0;
+
+ if (finetune)
+ {
+ if (wcol == MAXCOL)
+ {
+ /* The width of the last character is used to set coladd. */
+ if (!one_more)
+ {
+ colnr_T scol, ecol;
+
+ getvcol(curwin, pos, &scol, NULL, &ecol);
+ pos->coladd = ecol - scol;
+ }
+ }
+ else
+ {
+ int b = (int)wcol - (int)col;
+
+ /* The difference between wcol and col is used to set coladd. */
+ if (b > 0 && b < (MAXCOL - 2 * curwin->w_width))
+ pos->coladd = b;
+
+ col += b;
+ }
+ }
+
+ /* prevent from moving onto a trail byte */
+ if (has_mbyte)
+ mb_adjustpos(curbuf, pos);
+
+ if (col < wcol)
+ return FAIL;
+ return OK;
+}
+
+/*
+ * Increment the cursor position. See inc() for return values.
+ */
+ int
+inc_cursor(void)
+{
+ return inc(&curwin->w_cursor);
+}
+
+/*
+ * Increment the line pointer "lp" crossing line boundaries as necessary.
+ * Return 1 when going to the next line.
+ * Return 2 when moving forward onto a NUL at the end of the line).
+ * Return -1 when at the end of file.
+ * Return 0 otherwise.
+ */
+ int
+inc(pos_T *lp)
+{
+ char_u *p;
+
+ /* when searching position may be set to end of a line */
+ if (lp->col != MAXCOL)
+ {
+ p = ml_get_pos(lp);
+ if (*p != NUL) /* still within line, move to next char (may be NUL) */
+ {
+ if (has_mbyte)
+ {
+ int l = (*mb_ptr2len)(p);
+
+ lp->col += l;
+ return ((p[l] != NUL) ? 0 : 2);
+ }
+ lp->col++;
+ lp->coladd = 0;
+ return ((p[1] != NUL) ? 0 : 2);
+ }
+ }
+ if (lp->lnum != curbuf->b_ml.ml_line_count) /* there is a next line */
+ {
+ lp->col = 0;
+ lp->lnum++;
+ lp->coladd = 0;
+ return 1;
+ }
+ return -1;
+}
+
+/*
+ * incl(lp): same as inc(), but skip the NUL at the end of non-empty lines
+ */
+ int
+incl(pos_T *lp)
+{
+ int r;
+
+ if ((r = inc(lp)) >= 1 && lp->col)
+ r = inc(lp);
+ return r;
+}
+
+/*
+ * dec(p)
+ *
+ * Decrement the line pointer 'p' crossing line boundaries as necessary.
+ * Return 1 when crossing a line, -1 when at start of file, 0 otherwise.
+ */
+ int
+dec_cursor(void)
+{
+ return dec(&curwin->w_cursor);
+}
+
+ int
+dec(pos_T *lp)
+{
+ char_u *p;
+
+ lp->coladd = 0;
+ if (lp->col == MAXCOL)
+ {
+ /* past end of line */
+ p = ml_get(lp->lnum);
+ lp->col = (colnr_T)STRLEN(p);
+ if (has_mbyte)
+ lp->col -= (*mb_head_off)(p, p + lp->col);
+ return 0;
+ }
+
+ if (lp->col > 0)
+ {
+ /* still within line */
+ lp->col--;
+ if (has_mbyte)
+ {
+ p = ml_get(lp->lnum);
+ lp->col -= (*mb_head_off)(p, p + lp->col);
+ }
+ return 0;
+ }
+
+ if (lp->lnum > 1)
+ {
+ /* there is a prior line */
+ lp->lnum--;
+ p = ml_get(lp->lnum);
+ lp->col = (colnr_T)STRLEN(p);
+ if (has_mbyte)
+ lp->col -= (*mb_head_off)(p, p + lp->col);
+ return 1;
+ }
+
+ /* at start of file */
+ return -1;
+}
+
+/*
+ * decl(lp): same as dec(), but skip the NUL at the end of non-empty lines
+ */
+ int
+decl(pos_T *lp)
+{
+ int r;
+
+ if ((r = dec(lp)) == 1 && lp->col)
+ r = dec(lp);
+ return r;
+}
+
+/*
+ * Get the line number relative to the current cursor position, i.e. the
+ * difference between line number and cursor position. Only look for lines that
+ * can be visible, folded lines don't count.
+ */
+ linenr_T
+get_cursor_rel_lnum(
+ win_T *wp,
+ linenr_T lnum) /* line number to get the result for */
+{
+ linenr_T cursor = wp->w_cursor.lnum;
+ linenr_T retval = 0;
+
+#ifdef FEAT_FOLDING
+ if (hasAnyFolding(wp))
+ {
+ if (lnum > cursor)
+ {
+ while (lnum > cursor)
+ {
+ (void)hasFoldingWin(wp, lnum, &lnum, NULL, TRUE, NULL);
+ /* if lnum and cursor are in the same fold,
+ * now lnum <= cursor */
+ if (lnum > cursor)
+ retval++;
+ lnum--;
+ }
+ }
+ else if (lnum < cursor)
+ {
+ while (lnum < cursor)
+ {
+ (void)hasFoldingWin(wp, lnum, NULL, &lnum, TRUE, NULL);
+ /* if lnum and cursor are in the same fold,
+ * now lnum >= cursor */
+ if (lnum < cursor)
+ retval--;
+ lnum++;
+ }
+ }
+ /* else if (lnum == cursor)
+ * retval = 0;
+ */
+ }
+ else
+#endif
+ retval = lnum - cursor;
+
+ return retval;
+}
+
+/*
+ * Make sure "pos.lnum" and "pos.col" are valid in "buf".
+ * This allows for the col to be on the NUL byte.
+ */
+ void
+check_pos(buf_T *buf, pos_T *pos)
+{
+ char_u *line;
+ colnr_T len;
+
+ if (pos->lnum > buf->b_ml.ml_line_count)
+ pos->lnum = buf->b_ml.ml_line_count;
+
+ if (pos->col > 0)
+ {
+ line = ml_get_buf(buf, pos->lnum, FALSE);
+ len = (colnr_T)STRLEN(line);
+ if (pos->col > len)
+ pos->col = len;
+ }
+}
+
+/*
+ * Make sure curwin->w_cursor.lnum is valid.
+ */
+ void
+check_cursor_lnum(void)
+{
+ if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
+ {
+#ifdef FEAT_FOLDING
+ /* If there is a closed fold at the end of the file, put the cursor in
+ * its first line. Otherwise in the last line. */
+ if (!hasFolding(curbuf->b_ml.ml_line_count,
+ &curwin->w_cursor.lnum, NULL))
+#endif
+ curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
+ }
+ if (curwin->w_cursor.lnum <= 0)
+ curwin->w_cursor.lnum = 1;
+}
+
+/*
+ * Make sure curwin->w_cursor.col is valid.
+ */
+ void
+check_cursor_col(void)
+{
+ check_cursor_col_win(curwin);
+}
+
+/*
+ * Make sure win->w_cursor.col is valid.
+ */
+ void
+check_cursor_col_win(win_T *win)
+{
+ colnr_T len;
+ colnr_T oldcol = win->w_cursor.col;
+ colnr_T oldcoladd = win->w_cursor.col + win->w_cursor.coladd;
+
+ len = (colnr_T)STRLEN(ml_get_buf(win->w_buffer, win->w_cursor.lnum, FALSE));
+ if (len == 0)
+ win->w_cursor.col = 0;
+ else if (win->w_cursor.col >= len)
+ {
+ /* Allow cursor past end-of-line when:
+ * - in Insert mode or restarting Insert mode
+ * - in Visual mode and 'selection' isn't "old"
+ * - 'virtualedit' is set */
+ if ((State & INSERT) || restart_edit
+ || (VIsual_active && *p_sel != 'o')
+ || (ve_flags & VE_ONEMORE)
+ || virtual_active())
+ win->w_cursor.col = len;
+ else
+ {
+ win->w_cursor.col = len - 1;
+ /* Move the cursor to the head byte. */
+ if (has_mbyte)
+ mb_adjustpos(win->w_buffer, &win->w_cursor);
+ }
+ }
+ else if (win->w_cursor.col < 0)
+ win->w_cursor.col = 0;
+
+ /* If virtual editing is on, we can leave the cursor on the old position,
+ * only we must set it to virtual. But don't do it when at the end of the
+ * line. */
+ if (oldcol == MAXCOL)
+ win->w_cursor.coladd = 0;
+ else if (ve_flags == VE_ALL)
+ {
+ if (oldcoladd > win->w_cursor.col)
+ {
+ win->w_cursor.coladd = oldcoladd - win->w_cursor.col;
+
+ /* Make sure that coladd is not more than the char width.
+ * Not for the last character, coladd is then used when the cursor
+ * is actually after the last character. */
+ if (win->w_cursor.col + 1 < len && win->w_cursor.coladd > 0)
+ {
+ int cs, ce;
+
+ getvcol(win, &win->w_cursor, &cs, NULL, &ce);
+ if (win->w_cursor.coladd > ce - cs)
+ win->w_cursor.coladd = ce - cs;
+ }
+ }
+ else
+ /* avoid weird number when there is a miscalculation or overflow */
+ win->w_cursor.coladd = 0;
+ }
+}
+
+/*
+ * make sure curwin->w_cursor in on a valid character
+ */
+ void
+check_cursor(void)
+{
+ check_cursor_lnum();
+ check_cursor_col();
+}
+
+#if defined(FEAT_TEXTOBJ) || defined(PROTO)
+/*
+ * Make sure curwin->w_cursor is not on the NUL at the end of the line.
+ * Allow it when in Visual mode and 'selection' is not "old".
+ */
+ void
+adjust_cursor_col(void)
+{
+ if (curwin->w_cursor.col > 0
+ && (!VIsual_active || *p_sel == 'o')
+ && gchar_cursor() == NUL)
+ --curwin->w_cursor.col;
+}
+#endif
+
+/*
+ * When curwin->w_leftcol has changed, adjust the cursor position.
+ * Return TRUE if the cursor was moved.
+ */
+ int
+leftcol_changed(void)
+{
+ long lastcol;
+ colnr_T s, e;
+ int retval = FALSE;
+ long siso = get_sidescrolloff_value();
+
+ changed_cline_bef_curs();
+ lastcol = curwin->w_leftcol + curwin->w_width - curwin_col_off() - 1;
+ validate_virtcol();
+
+ /*
+ * If the cursor is right or left of the screen, move it to last or first
+ * character.
+ */
+ if (curwin->w_virtcol > (colnr_T)(lastcol - siso))
+ {
+ retval = TRUE;
+ coladvance((colnr_T)(lastcol - siso));
+ }
+ else if (curwin->w_virtcol < curwin->w_leftcol + siso)
+ {
+ retval = TRUE;
+ (void)coladvance((colnr_T)(curwin->w_leftcol + siso));
+ }
+
+ /*
+ * If the start of the character under the cursor is not on the screen,
+ * advance the cursor one more char. If this fails (last char of the
+ * line) adjust the scrolling.
+ */
+ getvvcol(curwin, &curwin->w_cursor, &s, NULL, &e);
+ if (e > (colnr_T)lastcol)
+ {
+ retval = TRUE;
+ coladvance(s - 1);
+ }
+ else if (s < curwin->w_leftcol)
+ {
+ retval = TRUE;
+ if (coladvance(e + 1) == FAIL) /* there isn't another character */
+ {
+ curwin->w_leftcol = s; /* adjust w_leftcol instead */
+ changed_cline_bef_curs();
+ }
+ }
+
+ if (retval)
+ curwin->w_set_curswant = TRUE;
+ redraw_later(NOT_VALID);
+ return retval;
+}
+
+/**********************************************************************
+ * Various routines dealing with allocation and deallocation of memory.
+ */
+
+#if defined(MEM_PROFILE) || defined(PROTO)
+
+# define MEM_SIZES 8200
+static long_u mem_allocs[MEM_SIZES];
+static long_u mem_frees[MEM_SIZES];
+static long_u mem_allocated;
+static long_u mem_freed;
+static long_u mem_peak;
+static long_u num_alloc;
+static long_u num_freed;
+
+ static void
+mem_pre_alloc_s(size_t *sizep)
+{
+ *sizep += sizeof(size_t);
+}
+
+ static void
+mem_pre_alloc_l(long_u *sizep)
+{
+ *sizep += sizeof(size_t);
+}
+
+ static void
+mem_post_alloc(
+ void **pp,
+ size_t size)
+{
+ if (*pp == NULL)
+ return;
+ size -= sizeof(size_t);
+ *(long_u *)*pp = size;
+ if (size <= MEM_SIZES-1)
+ mem_allocs[size-1]++;
+ else
+ mem_allocs[MEM_SIZES-1]++;
+ mem_allocated += size;
+ if (mem_allocated - mem_freed > mem_peak)
+ mem_peak = mem_allocated - mem_freed;
+ num_alloc++;
+ *pp = (void *)((char *)*pp + sizeof(size_t));
+}
+
+ static void
+mem_pre_free(void **pp)
+{
+ long_u size;
+
+ *pp = (void *)((char *)*pp - sizeof(size_t));
+ size = *(size_t *)*pp;
+ if (size <= MEM_SIZES-1)
+ mem_frees[size-1]++;
+ else
+ mem_frees[MEM_SIZES-1]++;
+ mem_freed += size;
+ num_freed++;
+}
+
+/*
+ * called on exit via atexit()
+ */
+ void
+vim_mem_profile_dump(void)
+{
+ int i, j;
+
+ printf("\r\n");
+ j = 0;
+ for (i = 0; i < MEM_SIZES - 1; i++)
+ {
+ if (mem_allocs[i] || mem_frees[i])
+ {
+ if (mem_frees[i] > mem_allocs[i])
+ printf("\r\n%s", _("ERROR: "));
+ printf("[%4d / %4lu-%-4lu] ", i + 1, mem_allocs[i], mem_frees[i]);
+ j++;
+ if (j > 3)
+ {
+ j = 0;
+ printf("\r\n");
+ }
+ }
+ }
+
+ i = MEM_SIZES - 1;
+ if (mem_allocs[i])
+ {
+ printf("\r\n");
+ if (mem_frees[i] > mem_allocs[i])
+ puts(_("ERROR: "));
+ printf("[>%d / %4lu-%-4lu]", i, mem_allocs[i], mem_frees[i]);
+ }
+
+ printf(_("\n[bytes] total alloc-freed %lu-%lu, in use %lu, peak use %lu\n"),
+ mem_allocated, mem_freed, mem_allocated - mem_freed, mem_peak);
+ printf(_("[calls] total re/malloc()'s %lu, total free()'s %lu\n\n"),
+ num_alloc, num_freed);
+}
+
+#endif /* MEM_PROFILE */
+
+#ifdef FEAT_EVAL
+ int
+alloc_does_fail(long_u size)
+{
+ if (alloc_fail_countdown == 0)
+ {
+ if (--alloc_fail_repeat <= 0)
+ alloc_fail_id = 0;
+ do_outofmem_msg(size);
+ return TRUE;
+ }
+ --alloc_fail_countdown;
+ return FALSE;
+}
+#endif
+
+/*
+ * Some memory is reserved for error messages and for being able to
+ * call mf_release_all(), which needs some memory for mf_trans_add().
+ */
+#define KEEP_ROOM (2 * 8192L)
+#define KEEP_ROOM_KB (KEEP_ROOM / 1024L)
+
+/*
+ * Note: if unsigned is 16 bits we can only allocate up to 64K with alloc().
+ * Use lalloc for larger blocks.
+ */
+ char_u *
+alloc(unsigned size)
+{
+ return (lalloc((long_u)size, TRUE));
+}
+
+/*
+ * alloc() with an ID for alloc_fail().
+ */
+ char_u *
+alloc_id(unsigned size, alloc_id_T id UNUSED)
+{
+#ifdef FEAT_EVAL
+ if (alloc_fail_id == id && alloc_does_fail((long_u)size))
+ return NULL;
+#endif
+ return (lalloc((long_u)size, TRUE));
+}
+
+/*
+ * Allocate memory and set all bytes to zero.
+ */
+ char_u *
+alloc_clear(unsigned size)
+{
+ char_u *p;
+
+ p = lalloc((long_u)size, TRUE);
+ if (p != NULL)
+ (void)vim_memset(p, 0, (size_t)size);
+ return p;
+}
+
+/*
+ * Same as alloc_clear() but with allocation id for testing
+ */
+ char_u *
+alloc_clear_id(unsigned size, alloc_id_T id UNUSED)
+{
+#ifdef FEAT_EVAL
+ if (alloc_fail_id == id && alloc_does_fail((long_u)size))
+ return NULL;
+#endif
+ return alloc_clear(size);
+}
+
+/*
+ * alloc() with check for maximum line length
+ */
+ char_u *
+alloc_check(unsigned size)
+{
+#if !defined(UNIX)
+ if (sizeof(int) == 2 && size > 0x7fff)
+ {
+ /* Don't hide this message */
+ emsg_silent = 0;
+ emsg(_("E340: Line is becoming too long"));
+ return NULL;
+ }
+#endif
+ return (lalloc((long_u)size, TRUE));
+}
+
+/*
+ * Allocate memory like lalloc() and set all bytes to zero.
+ */
+ char_u *
+lalloc_clear(long_u size, int message)
+{
+ char_u *p;
+
+ p = (lalloc(size, message));
+ if (p != NULL)
+ (void)vim_memset(p, 0, (size_t)size);
+ return p;
+}
+
+/*
+ * Low level memory allocation function.
+ * This is used often, KEEP IT FAST!
+ */
+ char_u *
+lalloc(long_u size, int message)
+{
+ char_u *p; /* pointer to new storage space */
+ static int releasing = FALSE; /* don't do mf_release_all() recursive */
+ int try_again;
+#if defined(HAVE_AVAIL_MEM)
+ static long_u allocated = 0; /* allocated since last avail check */
+#endif
+
+ /* Safety check for allocating zero bytes */
+ if (size == 0)
+ {
+ /* Don't hide this message */
+ emsg_silent = 0;
+ siemsg(_("E341: Internal error: lalloc(%ld, )"), size);
+ return NULL;
+ }
+
+#ifdef MEM_PROFILE
+ mem_pre_alloc_l(&size);
+#endif
+
+ /*
+ * Loop when out of memory: Try to release some memfile blocks and
+ * if some blocks are released call malloc again.
+ */
+ for (;;)
+ {
+ /*
+ * Handle three kind of systems:
+ * 1. No check for available memory: Just return.
+ * 2. Slow check for available memory: call mch_avail_mem() after
+ * allocating KEEP_ROOM amount of memory.
+ * 3. Strict check for available memory: call mch_avail_mem()
+ */
+ if ((p = (char_u *)malloc((size_t)size)) != NULL)
+ {
+#ifndef HAVE_AVAIL_MEM
+ /* 1. No check for available memory: Just return. */
+ goto theend;
+#else
+ /* 2. Slow check for available memory: call mch_avail_mem() after
+ * allocating (KEEP_ROOM / 2) amount of memory. */
+ allocated += size;
+ if (allocated < KEEP_ROOM / 2)
+ goto theend;
+ allocated = 0;
+
+ /* 3. check for available memory: call mch_avail_mem() */
+ if (mch_avail_mem(TRUE) < KEEP_ROOM_KB && !releasing)
+ {
+ free((char *)p); /* System is low... no go! */
+ p = NULL;
+ }
+ else
+ goto theend;
+#endif
+ }
+ /*
+ * Remember that mf_release_all() is being called to avoid an endless
+ * loop, because mf_release_all() may call alloc() recursively.
+ */
+ if (releasing)
+ break;
+ releasing = TRUE;
+
+ clear_sb_text(TRUE); /* free any scrollback text */
+ try_again = mf_release_all(); /* release as many blocks as possible */
+
+ releasing = FALSE;
+ if (!try_again)
+ break;
+ }
+
+ if (message && p == NULL)
+ do_outofmem_msg(size);
+
+theend:
+#ifdef MEM_PROFILE
+ mem_post_alloc((void **)&p, (size_t)size);
+#endif
+ return p;
+}
+
+/*
+ * lalloc() with an ID for alloc_fail().
+ */
+#if defined(FEAT_SIGNS) || defined(PROTO)
+ char_u *
+lalloc_id(long_u size, int message, alloc_id_T id UNUSED)
+{
+#ifdef FEAT_EVAL
+ if (alloc_fail_id == id && alloc_does_fail(size))
+ return NULL;
+#endif
+ return (lalloc((long_u)size, message));
+}
+#endif
+
+#if defined(MEM_PROFILE) || defined(PROTO)
+/*
+ * realloc() with memory profiling.
+ */
+ void *
+mem_realloc(void *ptr, size_t size)
+{
+ void *p;
+
+ mem_pre_free(&ptr);
+ mem_pre_alloc_s(&size);
+
+ p = realloc(ptr, size);
+
+ mem_post_alloc(&p, size);
+
+ return p;
+}
+#endif
+
+/*
+* Avoid repeating the error message many times (they take 1 second each).
+* Did_outofmem_msg is reset when a character is read.
+*/
+ void
+do_outofmem_msg(long_u size)
+{
+ if (!did_outofmem_msg)
+ {
+ /* Don't hide this message */
+ emsg_silent = 0;
+
+ /* Must come first to avoid coming back here when printing the error
+ * message fails, e.g. when setting v:errmsg. */
+ did_outofmem_msg = TRUE;
+
+ semsg(_("E342: Out of memory! (allocating %lu bytes)"), size);
+ }
+}
+
+#if defined(EXITFREE) || defined(PROTO)
+
+# if defined(FEAT_SEARCHPATH)
+static void free_findfile(void);
+# endif
+
+/*
+ * Free everything that we allocated.
+ * Can be used to detect memory leaks, e.g., with ccmalloc.
+ * NOTE: This is tricky! Things are freed that functions depend on. Don't be
+ * surprised if Vim crashes...
+ * Some things can't be freed, esp. things local to a library function.
+ */
+ void
+free_all_mem(void)
+{
+ buf_T *buf, *nextbuf;
+
+ /* When we cause a crash here it is caught and Vim tries to exit cleanly.
+ * Don't try freeing everything again. */
+ if (entered_free_all_mem)
+ return;
+ entered_free_all_mem = TRUE;
+
+ /* Don't want to trigger autocommands from here on. */
+ block_autocmds();
+
+ /* Close all tabs and windows. Reset 'equalalways' to avoid redraws. */
+ p_ea = FALSE;
+ if (first_tabpage->tp_next != NULL)
+ do_cmdline_cmd((char_u *)"tabonly!");
+ if (!ONE_WINDOW)
+ do_cmdline_cmd((char_u *)"only!");
+
+# if defined(FEAT_SPELL)
+ /* Free all spell info. */
+ spell_free_all();
+# endif
+
+#if defined(FEAT_INS_EXPAND) && defined(FEAT_BEVAL_TERM)
+ ui_remove_balloon();
+# endif
+
+# if defined(FEAT_USR_CMDS)
+ /* Clear user commands (before deleting buffers). */
+ ex_comclear(NULL);
+# endif
+
+# ifdef FEAT_MENU
+ /* Clear menus. */
+ do_cmdline_cmd((char_u *)"aunmenu *");
+# ifdef FEAT_MULTI_LANG
+ do_cmdline_cmd((char_u *)"menutranslate clear");
+# endif
+# endif
+
+ /* Clear mappings, abbreviations, breakpoints. */
+ do_cmdline_cmd((char_u *)"lmapclear");
+ do_cmdline_cmd((char_u *)"xmapclear");
+ do_cmdline_cmd((char_u *)"mapclear");
+ do_cmdline_cmd((char_u *)"mapclear!");
+ do_cmdline_cmd((char_u *)"abclear");
+# if defined(FEAT_EVAL)
+ do_cmdline_cmd((char_u *)"breakdel *");
+# endif
+# if defined(FEAT_PROFILE)
+ do_cmdline_cmd((char_u *)"profdel *");
+# endif
+# if defined(FEAT_KEYMAP)
+ do_cmdline_cmd((char_u *)"set keymap=");
+#endif
+
+# ifdef FEAT_TITLE
+ free_titles();
+# endif
+# if defined(FEAT_SEARCHPATH)
+ free_findfile();
+# endif
+
+ /* Obviously named calls. */
+ free_all_autocmds();
+ clear_termcodes();
+ free_all_marks();
+ alist_clear(&global_alist);
+ free_homedir();
+# if defined(FEAT_CMDL_COMPL)
+ free_users();
+# endif
+ free_search_patterns();
+ free_old_sub();
+ free_last_insert();
+ free_prev_shellcmd();
+ free_regexp_stuff();
+ free_tag_stuff();
+ free_cd_dir();
+# ifdef FEAT_SIGNS
+ free_signs();
+# endif
+# ifdef FEAT_EVAL
+ set_expr_line(NULL);
+# endif
+# ifdef FEAT_DIFF
+ diff_clear(curtab);
+# endif
+ clear_sb_text(TRUE); /* free any scrollback text */
+
+ /* Free some global vars. */
+ vim_free(username);
+# ifdef FEAT_CLIPBOARD
+ vim_regfree(clip_exclude_prog);
+# endif
+ vim_free(last_cmdline);
+# ifdef FEAT_CMDHIST
+ vim_free(new_last_cmdline);
+# endif
+ set_keep_msg(NULL, 0);
+ vim_free(ff_expand_buffer);
+
+ /* Clear cmdline history. */
+ p_hi = 0;
+# ifdef FEAT_CMDHIST
+ init_history();
+# endif
+#ifdef FEAT_TEXT_PROP
+ clear_global_prop_types();
+#endif
+
+#ifdef FEAT_QUICKFIX
+ {
+ win_T *win;
+ tabpage_T *tab;
+
+ qf_free_all(NULL);
+ /* Free all location lists */
+ FOR_ALL_TAB_WINDOWS(tab, win)
+ qf_free_all(win);
+ }
+#endif
+
+ /* Close all script inputs. */
+ close_all_scripts();
+
+ /* Destroy all windows. Must come before freeing buffers. */
+ win_free_all();
+
+ /* Free all option values. Must come after closing windows. */
+ free_all_options();
+
+ /* Free all buffers. Reset 'autochdir' to avoid accessing things that
+ * were freed already. */
+#ifdef FEAT_AUTOCHDIR
+ p_acd = FALSE;
+#endif
+ for (buf = firstbuf; buf != NULL; )
+ {
+ bufref_T bufref;
+
+ set_bufref(&bufref, buf);
+ nextbuf = buf->b_next;
+ close_buffer(NULL, buf, DOBUF_WIPE, FALSE);
+ if (bufref_valid(&bufref))
+ buf = nextbuf; /* didn't work, try next one */
+ else
+ buf = firstbuf;
+ }
+
+# ifdef FEAT_ARABIC
+ free_cmdline_buf();
+# endif
+
+ /* Clear registers. */
+ clear_registers();
+ ResetRedobuff();
+ ResetRedobuff();
+
+# if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
+ vim_free(serverDelayedStartName);
+# endif
+
+ /* highlight info */
+ free_highlight();
+
+ reset_last_sourcing();
+
+ free_tabpage(first_tabpage);
+ first_tabpage = NULL;
+
+# ifdef UNIX
+ /* Machine-specific free. */
+ mch_free_mem();
+# endif
+
+ /* message history */
+ for (;;)
+ if (delete_first_msg() == FAIL)
+ break;
+
+# ifdef FEAT_JOB_CHANNEL
+ channel_free_all();
+# endif
+# ifdef FEAT_TIMERS
+ timer_free_all();
+# endif
+# ifdef FEAT_EVAL
+ /* must be after channel_free_all() with unrefs partials */
+ eval_clear();
+# endif
+# ifdef FEAT_JOB_CHANNEL
+ /* must be after eval_clear() with unrefs jobs */
+ job_free_all();
+# endif
+
+ free_termoptions();
+
+ /* screenlines (can't display anything now!) */
+ free_screenlines();
+
+# if defined(USE_XSMP)
+ xsmp_close();
+# endif
+# ifdef FEAT_GUI_GTK
+ gui_mch_free_all();
+# endif
+ clear_hl_tables();
+
+ vim_free(IObuff);
+ vim_free(NameBuff);
+# ifdef FEAT_QUICKFIX
+ check_quickfix_busy();
+# endif
+}
+#endif
+
+/*
+ * Copy "string" into newly allocated memory.
+ */
+ char_u *
+vim_strsave(char_u *string)
+{
+ char_u *p;
+ unsigned len;
+
+ len = (unsigned)STRLEN(string) + 1;
+ p = alloc(len);
+ if (p != NULL)
+ mch_memmove(p, string, (size_t)len);
+ return p;
+}
+
+/*
+ * Copy up to "len" bytes of "string" into newly allocated memory and
+ * terminate with a NUL.
+ * The allocated memory always has size "len + 1", also when "string" is
+ * shorter.
+ */
+ char_u *
+vim_strnsave(char_u *string, int len)
+{
+ char_u *p;
+
+ p = alloc((unsigned)(len + 1));
+ if (p != NULL)
+ {
+ STRNCPY(p, string, len);
+ p[len] = NUL;
+ }
+ return p;
+}
+
+/*
+ * Copy "p[len]" into allocated memory, ignoring NUL characters.
+ * Returns NULL when out of memory.
+ */
+ char_u *
+vim_memsave(char_u *p, int len)
+{
+ char_u *ret = alloc((unsigned)len);
+
+ if (ret != NULL)
+ mch_memmove(ret, p, (size_t)len);
+ return ret;
+}
+
+/*
+ * Same as vim_strsave(), but any characters found in esc_chars are preceded
+ * by a backslash.
+ */
+ char_u *
+vim_strsave_escaped(char_u *string, char_u *esc_chars)
+{
+ return vim_strsave_escaped_ext(string, esc_chars, '\\', FALSE);
+}
+
+/*
+ * Same as vim_strsave_escaped(), but when "bsl" is TRUE also escape
+ * characters where rem_backslash() would remove the backslash.
+ * Escape the characters with "cc".
+ */
+ char_u *
+vim_strsave_escaped_ext(
+ char_u *string,
+ char_u *esc_chars,
+ int cc,
+ int bsl)
+{
+ char_u *p;
+ char_u *p2;
+ char_u *escaped_string;
+ unsigned length;
+ int l;
+
+ /*
+ * First count the number of backslashes required.
+ * Then allocate the memory and insert them.
+ */
+ length = 1; /* count the trailing NUL */
+ for (p = string; *p; p++)
+ {
+ if (has_mbyte && (l = (*mb_ptr2len)(p)) > 1)
+ {
+ length += l; /* count a multibyte char */
+ p += l - 1;
+ continue;
+ }
+ if (vim_strchr(esc_chars, *p) != NULL || (bsl && rem_backslash(p)))
+ ++length; /* count a backslash */
+ ++length; /* count an ordinary char */
+ }
+ escaped_string = alloc(length);
+ if (escaped_string != NULL)
+ {
+ p2 = escaped_string;
+ for (p = string; *p; p++)
+ {
+ if (has_mbyte && (l = (*mb_ptr2len)(p)) > 1)
+ {
+ mch_memmove(p2, p, (size_t)l);
+ p2 += l;
+ p += l - 1; /* skip multibyte char */
+ continue;
+ }
+ if (vim_strchr(esc_chars, *p) != NULL || (bsl && rem_backslash(p)))
+ *p2++ = cc;
+ *p2++ = *p;
+ }
+ *p2 = NUL;
+ }
+ return escaped_string;
+}
+
+/*
+ * Return TRUE when 'shell' has "csh" in the tail.
+ */
+ int
+csh_like_shell(void)
+{
+ return (strstr((char *)gettail(p_sh), "csh") != NULL);
+}
+
+/*
+ * Escape "string" for use as a shell argument with system().
+ * This uses single quotes, except when we know we need to use double quotes
+ * (MS-DOS and MS-Windows without 'shellslash' set).
+ * Escape a newline, depending on the 'shell' option.
+ * When "do_special" is TRUE also replace "!", "%", "#" and things starting
+ * with "<" like "<cfile>".
+ * When "do_newline" is FALSE do not escape newline unless it is csh shell.
+ * Returns the result in allocated memory, NULL if we have run out.
+ */
+ char_u *
+vim_strsave_shellescape(char_u *string, int do_special, int do_newline)
+{
+ unsigned length;
+ char_u *p;
+ char_u *d;
+ char_u *escaped_string;
+ int l;
+ int csh_like;
+
+ /* Only csh and similar shells expand '!' within single quotes. For sh and
+ * the like we must not put a backslash before it, it will be taken
+ * literally. If do_special is set the '!' will be escaped twice.
+ * Csh also needs to have "\n" escaped twice when do_special is set. */
+ csh_like = csh_like_shell();
+
+ /* First count the number of extra bytes required. */
+ length = (unsigned)STRLEN(string) + 3; /* two quotes and a trailing NUL */
+ for (p = string; *p != NUL; MB_PTR_ADV(p))
+ {
+# ifdef WIN32
+ if (!p_ssl)
+ {
+ if (*p == '"')
+ ++length; /* " -> "" */
+ }
+ else
+# endif
+ if (*p == '\'')
+ length += 3; /* ' => '\'' */
+ if ((*p == '\n' && (csh_like || do_newline))
+ || (*p == '!' && (csh_like || do_special)))
+ {
+ ++length; /* insert backslash */
+ if (csh_like && do_special)
+ ++length; /* insert backslash */
+ }
+ if (do_special && find_cmdline_var(p, &l) >= 0)
+ {
+ ++length; /* insert backslash */
+ p += l - 1;
+ }
+ }
+
+ /* Allocate memory for the result and fill it. */
+ escaped_string = alloc(length);
+ if (escaped_string != NULL)
+ {
+ d = escaped_string;
+
+ /* add opening quote */
+# ifdef WIN32
+ if (!p_ssl)
+ *d++ = '"';
+ else
+# endif
+ *d++ = '\'';
+
+ for (p = string; *p != NUL; )
+ {
+# ifdef WIN32
+ if (!p_ssl)
+ {
+ if (*p == '"')
+ {
+ *d++ = '"';
+ *d++ = '"';
+ ++p;
+ continue;
+ }
+ }
+ else
+# endif
+ if (*p == '\'')
+ {
+ *d++ = '\'';
+ *d++ = '\\';
+ *d++ = '\'';
+ *d++ = '\'';
+ ++p;
+ continue;
+ }
+ if ((*p == '\n' && (csh_like || do_newline))
+ || (*p == '!' && (csh_like || do_special)))
+ {
+ *d++ = '\\';
+ if (csh_like && do_special)
+ *d++ = '\\';
+ *d++ = *p++;
+ continue;
+ }
+ if (do_special && find_cmdline_var(p, &l) >= 0)
+ {
+ *d++ = '\\'; /* insert backslash */
+ while (--l >= 0) /* copy the var */
+ *d++ = *p++;
+ continue;
+ }
+
+ MB_COPY_CHAR(p, d);
+ }
+
+ /* add terminating quote and finish with a NUL */
+# ifdef WIN32
+ if (!p_ssl)
+ *d++ = '"';
+ else
+# endif
+ *d++ = '\'';
+ *d = NUL;
+ }
+
+ return escaped_string;
+}
+
+/*
+ * Like vim_strsave(), but make all characters uppercase.
+ * This uses ASCII lower-to-upper case translation, language independent.
+ */
+ char_u *
+vim_strsave_up(char_u *string)
+{
+ char_u *p1;
+
+ p1 = vim_strsave(string);
+ vim_strup(p1);
+ return p1;
+}
+
+/*
+ * Like vim_strnsave(), but make all characters uppercase.
+ * This uses ASCII lower-to-upper case translation, language independent.
+ */
+ char_u *
+vim_strnsave_up(char_u *string, int len)
+{
+ char_u *p1;
+
+ p1 = vim_strnsave(string, len);
+ vim_strup(p1);
+ return p1;
+}
+
+/*
+ * ASCII lower-to-upper case translation, language independent.
+ */
+ void
+vim_strup(
+ char_u *p)
+{
+ char_u *p2;
+ int c;
+
+ if (p != NULL)
+ {
+ p2 = p;
+ while ((c = *p2) != NUL)
+#ifdef EBCDIC
+ *p2++ = isalpha(c) ? toupper(c) : c;
+#else
+ *p2++ = (c < 'a' || c > 'z') ? c : (c - 0x20);
+#endif
+ }
+}
+
+#if defined(FEAT_EVAL) || defined(FEAT_SPELL) || defined(PROTO)
+/*
+ * Make string "s" all upper-case and return it in allocated memory.
+ * Handles multi-byte characters as well as possible.
+ * Returns NULL when out of memory.
+ */
+ char_u *
+strup_save(char_u *orig)
+{
+ char_u *p;
+ char_u *res;
+
+ res = p = vim_strsave(orig);
+
+ if (res != NULL)
+ while (*p != NUL)
+ {
+ int l;
+
+ if (enc_utf8)
+ {
+ int c, uc;
+ int newl;
+ char_u *s;
+
+ c = utf_ptr2char(p);
+ l = utf_ptr2len(p);
+ if (c == 0)
+ {
+ /* overlong sequence, use only the first byte */
+ c = *p;
+ l = 1;
+ }
+ uc = utf_toupper(c);
+
+ /* Reallocate string when byte count changes. This is rare,
+ * thus it's OK to do another malloc()/free(). */
+ newl = utf_char2len(uc);
+ if (newl != l)
+ {
+ s = alloc((unsigned)STRLEN(res) + 1 + newl - l);
+ if (s == NULL)
+ {
+ vim_free(res);
+ return NULL;
+ }
+ mch_memmove(s, res, p - res);
+ STRCPY(s + (p - res) + newl, p + l);
+ p = s + (p - res);
+ vim_free(res);
+ res = s;
+ }
+
+ utf_char2bytes(uc, p);
+ p += newl;
+ }
+ else if (has_mbyte && (l = (*mb_ptr2len)(p)) > 1)
+ p += l; /* skip multi-byte character */
+ else
+ {
+ *p = TOUPPER_LOC(*p); /* note that toupper() can be a macro */
+ p++;
+ }
+ }
+
+ return res;
+}
+
+/*
+ * Make string "s" all lower-case and return it in allocated memory.
+ * Handles multi-byte characters as well as possible.
+ * Returns NULL when out of memory.
+ */
+ char_u *
+strlow_save(char_u *orig)
+{
+ char_u *p;
+ char_u *res;
+
+ res = p = vim_strsave(orig);
+
+ if (res != NULL)
+ while (*p != NUL)
+ {
+ int l;
+
+ if (enc_utf8)
+ {
+ int c, lc;
+ int newl;
+ char_u *s;
+
+ c = utf_ptr2char(p);
+ l = utf_ptr2len(p);
+ if (c == 0)
+ {
+ /* overlong sequence, use only the first byte */
+ c = *p;
+ l = 1;
+ }
+ lc = utf_tolower(c);
+
+ /* Reallocate string when byte count changes. This is rare,
+ * thus it's OK to do another malloc()/free(). */
+ newl = utf_char2len(lc);
+ if (newl != l)
+ {
+ s = alloc((unsigned)STRLEN(res) + 1 + newl - l);
+ if (s == NULL)
+ {
+ vim_free(res);
+ return NULL;
+ }
+ mch_memmove(s, res, p - res);
+ STRCPY(s + (p - res) + newl, p + l);
+ p = s + (p - res);
+ vim_free(res);
+ res = s;
+ }
+
+ utf_char2bytes(lc, p);
+ p += newl;
+ }
+ else if (has_mbyte && (l = (*mb_ptr2len)(p)) > 1)
+ p += l; /* skip multi-byte character */
+ else
+ {
+ *p = TOLOWER_LOC(*p); /* note that tolower() can be a macro */
+ p++;
+ }
+ }
+
+ return res;
+}
+#endif
+
+/*
+ * delete spaces at the end of a string
+ */
+ void
+del_trailing_spaces(char_u *ptr)
+{
+ char_u *q;
+
+ q = ptr + STRLEN(ptr);
+ while (--q > ptr && VIM_ISWHITE(q[0]) && q[-1] != '\\' && q[-1] != Ctrl_V)
+ *q = NUL;
+}
+
+/*
+ * Like strncpy(), but always terminate the result with one NUL.
+ * "to" must be "len + 1" long!
+ */
+ void
+vim_strncpy(char_u *to, char_u *from, size_t len)
+{
+ STRNCPY(to, from, len);
+ to[len] = NUL;
+}
+
+/*
+ * Like strcat(), but make sure the result fits in "tosize" bytes and is
+ * always NUL terminated. "from" and "to" may overlap.
+ */
+ void
+vim_strcat(char_u *to, char_u *from, size_t tosize)
+{
+ size_t tolen = STRLEN(to);
+ size_t fromlen = STRLEN(from);
+
+ if (tolen + fromlen + 1 > tosize)
+ {
+ mch_memmove(to + tolen, from, tosize - tolen - 1);
+ to[tosize - 1] = NUL;
+ }
+ else
+ mch_memmove(to + tolen, from, fromlen + 1);
+}
+
+/*
+ * Isolate one part of a string option where parts are separated with
+ * "sep_chars".
+ * The part is copied into "buf[maxlen]".
+ * "*option" is advanced to the next part.
+ * The length is returned.
+ */
+ int
+copy_option_part(
+ char_u **option,
+ char_u *buf,
+ int maxlen,
+ char *sep_chars)
+{
+ int len = 0;
+ char_u *p = *option;
+
+ /* skip '.' at start of option part, for 'suffixes' */
+ if (*p == '.')
+ buf[len++] = *p++;
+ while (*p != NUL && vim_strchr((char_u *)sep_chars, *p) == NULL)
+ {
+ /*
+ * Skip backslash before a separator character and space.
+ */
+ if (p[0] == '\\' && vim_strchr((char_u *)sep_chars, p[1]) != NULL)
+ ++p;
+ if (len < maxlen - 1)
+ buf[len++] = *p;
+ ++p;
+ }
+ buf[len] = NUL;
+
+ if (*p != NUL && *p != ',') /* skip non-standard separator */
+ ++p;
+ p = skip_to_option_part(p); /* p points to next file name */
+
+ *option = p;
+ return len;
+}
+
+/*
+ * Replacement for free() that ignores NULL pointers.
+ * Also skip free() when exiting for sure, this helps when we caught a deadly
+ * signal that was caused by a crash in free().
+ * If you want to set NULL after calling this function, you should use
+ * VIM_CLEAR() instead.
+ */
+ void
+vim_free(void *x)
+{
+ if (x != NULL && !really_exiting)
+ {
+#ifdef MEM_PROFILE
+ mem_pre_free(&x);
+#endif
+ free(x);
+ }
+}
+
+#ifndef HAVE_MEMSET
+ void *
+vim_memset(void *ptr, int c, size_t size)
+{
+ char *p = ptr;
+
+ while (size-- > 0)
+ *p++ = c;
+ return ptr;
+}
+#endif
+
+#if (!defined(HAVE_STRCASECMP) && !defined(HAVE_STRICMP)) || defined(PROTO)
+/*
+ * Compare two strings, ignoring case, using current locale.
+ * Doesn't work for multi-byte characters.
+ * return 0 for match, < 0 for smaller, > 0 for bigger
+ */
+ int
+vim_stricmp(char *s1, char *s2)
+{
+ int i;
+
+ for (;;)
+ {
+ i = (int)TOLOWER_LOC(*s1) - (int)TOLOWER_LOC(*s2);
+ if (i != 0)
+ return i; /* this character different */
+ if (*s1 == NUL)
+ break; /* strings match until NUL */
+ ++s1;
+ ++s2;
+ }
+ return 0; /* strings match */
+}
+#endif
+
+#if (!defined(HAVE_STRNCASECMP) && !defined(HAVE_STRNICMP)) || defined(PROTO)
+/*
+ * Compare two strings, for length "len", ignoring case, using current locale.
+ * Doesn't work for multi-byte characters.
+ * return 0 for match, < 0 for smaller, > 0 for bigger
+ */
+ int
+vim_strnicmp(char *s1, char *s2, size_t len)
+{
+ int i;
+
+ while (len > 0)
+ {
+ i = (int)TOLOWER_LOC(*s1) - (int)TOLOWER_LOC(*s2);
+ if (i != 0)
+ return i; /* this character different */
+ if (*s1 == NUL)
+ break; /* strings match until NUL */
+ ++s1;
+ ++s2;
+ --len;
+ }
+ return 0; /* strings match */
+}
+#endif
+
+/*
+ * Version of strchr() and strrchr() that handle unsigned char strings
+ * with characters from 128 to 255 correctly. It also doesn't return a
+ * pointer to the NUL at the end of the string.
+ */
+ char_u *
+vim_strchr(char_u *string, int c)
+{
+ char_u *p;
+ int b;
+
+ p = string;
+ if (enc_utf8 && c >= 0x80)
+ {
+ while (*p != NUL)
+ {
+ int l = utfc_ptr2len(p);
+
+ /* Avoid matching an illegal byte here. */
+ if (utf_ptr2char(p) == c && l > 1)
+ return p;
+ p += l;
+ }
+ return NULL;
+ }
+ if (enc_dbcs != 0 && c > 255)
+ {
+ int n2 = c & 0xff;
+
+ c = ((unsigned)c >> 8) & 0xff;
+ while ((b = *p) != NUL)
+ {
+ if (b == c && p[1] == n2)
+ return p;
+ p += (*mb_ptr2len)(p);
+ }
+ return NULL;
+ }
+ if (has_mbyte)
+ {
+ while ((b = *p) != NUL)
+ {
+ if (b == c)
+ return p;
+ p += (*mb_ptr2len)(p);
+ }
+ return NULL;
+ }
+ while ((b = *p) != NUL)
+ {
+ if (b == c)
+ return p;
+ ++p;
+ }
+ return NULL;
+}
+
+/*
+ * Version of strchr() that only works for bytes and handles unsigned char
+ * strings with characters above 128 correctly. It also doesn't return a
+ * pointer to the NUL at the end of the string.
+ */
+ char_u *
+vim_strbyte(char_u *string, int c)
+{
+ char_u *p = string;
+
+ while (*p != NUL)
+ {
+ if (*p == c)
+ return p;
+ ++p;
+ }
+ return NULL;
+}
+
+/*
+ * Search for last occurrence of "c" in "string".
+ * Return NULL if not found.
+ * Does not handle multi-byte char for "c"!
+ */
+ char_u *
+vim_strrchr(char_u *string, int c)
+{
+ char_u *retval = NULL;
+ char_u *p = string;
+
+ while (*p)
+ {
+ if (*p == c)
+ retval = p;
+ MB_PTR_ADV(p);
+ }
+ return retval;
+}
+
+/*
+ * Vim's version of strpbrk(), in case it's missing.
+ * Don't generate a prototype for this, causes problems when it's not used.
+ */
+#ifndef PROTO
+# ifndef HAVE_STRPBRK
+# ifdef vim_strpbrk
+# undef vim_strpbrk
+# endif
+ char_u *
+vim_strpbrk(char_u *s, char_u *charset)
+{
+ while (*s)
+ {
+ if (vim_strchr(charset, *s) != NULL)
+ return s;
+ MB_PTR_ADV(s);
+ }
+ return NULL;
+}
+# endif
+#endif
+
+/*
+ * Vim has its own isspace() function, because on some machines isspace()
+ * can't handle characters above 128.
+ */
+ int
+vim_isspace(int x)
+{
+ return ((x >= 9 && x <= 13) || x == ' ');
+}
+
+/************************************************************************
+ * Functions for handling growing arrays.
+ */
+
+/*
+ * Clear an allocated growing array.
+ */
+ void
+ga_clear(garray_T *gap)
+{
+ vim_free(gap->ga_data);
+ ga_init(gap);
+}
+
+/*
+ * Clear a growing array that contains a list of strings.
+ */
+ void
+ga_clear_strings(garray_T *gap)
+{
+ int i;
+
+ for (i = 0; i < gap->ga_len; ++i)
+ vim_free(((char_u **)(gap->ga_data))[i]);
+ ga_clear(gap);
+}
+
+/*
+ * Initialize a growing array. Don't forget to set ga_itemsize and
+ * ga_growsize! Or use ga_init2().
+ */
+ void
+ga_init(garray_T *gap)
+{
+ gap->ga_data = NULL;
+ gap->ga_maxlen = 0;
+ gap->ga_len = 0;
+}
+
+ void
+ga_init2(garray_T *gap, int itemsize, int growsize)
+{
+ ga_init(gap);
+ gap->ga_itemsize = itemsize;
+ gap->ga_growsize = growsize;
+}
+
+/*
+ * Make room in growing array "gap" for at least "n" items.
+ * Return FAIL for failure, OK otherwise.
+ */
+ int
+ga_grow(garray_T *gap, int n)
+{
+ size_t old_len;
+ size_t new_len;
+ char_u *pp;
+
+ if (gap->ga_maxlen - gap->ga_len < n)
+ {
+ if (n < gap->ga_growsize)
+ n = gap->ga_growsize;
+ new_len = gap->ga_itemsize * (gap->ga_len + n);
+ pp = (gap->ga_data == NULL)
+ ? alloc((unsigned)new_len) : vim_realloc(gap->ga_data, new_len);
+ if (pp == NULL)
+ return FAIL;
+ old_len = gap->ga_itemsize * gap->ga_maxlen;
+ vim_memset(pp + old_len, 0, new_len - old_len);
+ gap->ga_maxlen = gap->ga_len + n;
+ gap->ga_data = pp;
+ }
+ return OK;
+}
+
+#if defined(FEAT_EVAL) || defined(FEAT_SEARCHPATH) || defined(PROTO)
+/*
+ * For a growing array that contains a list of strings: concatenate all the
+ * strings with a separating "sep".
+ * Returns NULL when out of memory.
+ */
+ char_u *
+ga_concat_strings(garray_T *gap, char *sep)
+{
+ int i;
+ int len = 0;
+ int sep_len = (int)STRLEN(sep);
+ char_u *s;
+ char_u *p;
+
+ for (i = 0; i < gap->ga_len; ++i)
+ len += (int)STRLEN(((char_u **)(gap->ga_data))[i]) + sep_len;
+
+ s = alloc(len + 1);
+ if (s != NULL)
+ {
+ *s = NUL;
+ p = s;
+ for (i = 0; i < gap->ga_len; ++i)
+ {
+ if (p != s)
+ {
+ STRCPY(p, sep);
+ p += sep_len;
+ }
+ STRCPY(p, ((char_u **)(gap->ga_data))[i]);
+ p += STRLEN(p);
+ }
+ }
+ return s;
+}
+#endif
+
+#if defined(FEAT_VIMINFO) || defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * Make a copy of string "p" and add it to "gap".
+ * When out of memory nothing changes.
+ */
+ void
+ga_add_string(garray_T *gap, char_u *p)
+{
+ char_u *cp = vim_strsave(p);
+
+ if (cp != NULL)
+ {
+ if (ga_grow(gap, 1) == OK)
+ ((char_u **)(gap->ga_data))[gap->ga_len++] = cp;
+ else
+ vim_free(cp);
+ }
+}
+#endif
+
+/*
+ * Concatenate a string to a growarray which contains bytes.
+ * When "s" is NULL does not do anything.
+ * Note: Does NOT copy the NUL at the end!
+ */
+ void
+ga_concat(garray_T *gap, char_u *s)
+{
+ int len;
+
+ if (s == NULL || *s == NUL)
+ return;
+ len = (int)STRLEN(s);
+ if (ga_grow(gap, len) == OK)
+ {
+ mch_memmove((char *)gap->ga_data + gap->ga_len, s, (size_t)len);
+ gap->ga_len += len;
+ }
+}
+
+/*
+ * Append one byte to a growarray which contains bytes.
+ */
+ void
+ga_append(garray_T *gap, int c)
+{
+ if (ga_grow(gap, 1) == OK)
+ {
+ *((char *)gap->ga_data + gap->ga_len) = c;
+ ++gap->ga_len;
+ }
+}
+
+#if (defined(UNIX) && !defined(USE_SYSTEM)) || defined(WIN3264) \
+ || defined(PROTO)
+/*
+ * Append the text in "gap" below the cursor line and clear "gap".
+ */
+ void
+append_ga_line(garray_T *gap)
+{
+ /* Remove trailing CR. */
+ if (gap->ga_len > 0
+ && !curbuf->b_p_bin
+ && ((char_u *)gap->ga_data)[gap->ga_len - 1] == CAR)
+ --gap->ga_len;
+ ga_append(gap, NUL);
+ ml_append(curwin->w_cursor.lnum++, gap->ga_data, 0, FALSE);
+ gap->ga_len = 0;
+}
+#endif
+
+/************************************************************************
+ * functions that use lookup tables for various things, generally to do with
+ * special key codes.
+ */
+
+/*
+ * Some useful tables.
+ */
+
+static struct modmasktable
+{
+ short mod_mask; /* Bit-mask for particular key modifier */
+ short mod_flag; /* Bit(s) for particular key modifier */
+ char_u name; /* Single letter name of modifier */
+} mod_mask_table[] =
+{
+ {MOD_MASK_ALT, MOD_MASK_ALT, (char_u)'M'},
+ {MOD_MASK_META, MOD_MASK_META, (char_u)'T'},
+ {MOD_MASK_CTRL, MOD_MASK_CTRL, (char_u)'C'},
+ {MOD_MASK_SHIFT, MOD_MASK_SHIFT, (char_u)'S'},
+ {MOD_MASK_MULTI_CLICK, MOD_MASK_2CLICK, (char_u)'2'},
+ {MOD_MASK_MULTI_CLICK, MOD_MASK_3CLICK, (char_u)'3'},
+ {MOD_MASK_MULTI_CLICK, MOD_MASK_4CLICK, (char_u)'4'},
+#ifdef MACOS_X
+ {MOD_MASK_CMD, MOD_MASK_CMD, (char_u)'D'},
+#endif
+ /* 'A' must be the last one */
+ {MOD_MASK_ALT, MOD_MASK_ALT, (char_u)'A'},
+ {0, 0, NUL}
+ /* NOTE: when adding an entry, update MAX_KEY_NAME_LEN! */
+};
+
+/*
+ * Shifted key terminal codes and their unshifted equivalent.
+ * Don't add mouse codes here, they are handled separately!
+ */
+#define MOD_KEYS_ENTRY_SIZE 5
+
+static char_u modifier_keys_table[] =
+{
+/* mod mask with modifier without modifier */
+ MOD_MASK_SHIFT, '&', '9', '@', '1', /* begin */
+ MOD_MASK_SHIFT, '&', '0', '@', '2', /* cancel */
+ MOD_MASK_SHIFT, '*', '1', '@', '4', /* command */
+ MOD_MASK_SHIFT, '*', '2', '@', '5', /* copy */
+ MOD_MASK_SHIFT, '*', '3', '@', '6', /* create */
+ MOD_MASK_SHIFT, '*', '4', 'k', 'D', /* delete char */
+ MOD_MASK_SHIFT, '*', '5', 'k', 'L', /* delete line */
+ MOD_MASK_SHIFT, '*', '7', '@', '7', /* end */
+ MOD_MASK_CTRL, KS_EXTRA, (int)KE_C_END, '@', '7', /* end */
+ MOD_MASK_SHIFT, '*', '9', '@', '9', /* exit */
+ MOD_MASK_SHIFT, '*', '0', '@', '0', /* find */
+ MOD_MASK_SHIFT, '#', '1', '%', '1', /* help */
+ MOD_MASK_SHIFT, '#', '2', 'k', 'h', /* home */
+ MOD_MASK_CTRL, KS_EXTRA, (int)KE_C_HOME, 'k', 'h', /* home */
+ MOD_MASK_SHIFT, '#', '3', 'k', 'I', /* insert */
+ MOD_MASK_SHIFT, '#', '4', 'k', 'l', /* left arrow */
+ MOD_MASK_CTRL, KS_EXTRA, (int)KE_C_LEFT, 'k', 'l', /* left arrow */
+ MOD_MASK_SHIFT, '%', 'a', '%', '3', /* message */
+ MOD_MASK_SHIFT, '%', 'b', '%', '4', /* move */
+ MOD_MASK_SHIFT, '%', 'c', '%', '5', /* next */
+ MOD_MASK_SHIFT, '%', 'd', '%', '7', /* options */
+ MOD_MASK_SHIFT, '%', 'e', '%', '8', /* previous */
+ MOD_MASK_SHIFT, '%', 'f', '%', '9', /* print */
+ MOD_MASK_SHIFT, '%', 'g', '%', '0', /* redo */
+ MOD_MASK_SHIFT, '%', 'h', '&', '3', /* replace */
+ MOD_MASK_SHIFT, '%', 'i', 'k', 'r', /* right arr. */
+ MOD_MASK_CTRL, KS_EXTRA, (int)KE_C_RIGHT, 'k', 'r', /* right arr. */
+ MOD_MASK_SHIFT, '%', 'j', '&', '5', /* resume */
+ MOD_MASK_SHIFT, '!', '1', '&', '6', /* save */
+ MOD_MASK_SHIFT, '!', '2', '&', '7', /* suspend */
+ MOD_MASK_SHIFT, '!', '3', '&', '8', /* undo */
+ MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_UP, 'k', 'u', /* up arrow */
+ MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_DOWN, 'k', 'd', /* down arrow */
+
+ /* vt100 F1 */
+ MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_XF1, KS_EXTRA, (int)KE_XF1,
+ MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_XF2, KS_EXTRA, (int)KE_XF2,
+ MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_XF3, KS_EXTRA, (int)KE_XF3,
+ MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_XF4, KS_EXTRA, (int)KE_XF4,
+
+ MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F1, 'k', '1', /* F1 */
+ MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F2, 'k', '2',
+ MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F3, 'k', '3',
+ MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F4, 'k', '4',
+ MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F5, 'k', '5',
+ MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F6, 'k', '6',
+ MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F7, 'k', '7',
+ MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F8, 'k', '8',
+ MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F9, 'k', '9',
+ MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F10, 'k', ';', /* F10 */
+
+ MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F11, 'F', '1',
+ MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F12, 'F', '2',
+ MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F13, 'F', '3',
+ MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F14, 'F', '4',
+ MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F15, 'F', '5',
+ MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F16, 'F', '6',
+ MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F17, 'F', '7',
+ MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F18, 'F', '8',
+ MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F19, 'F', '9',
+ MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F20, 'F', 'A',
+
+ MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F21, 'F', 'B',
+ MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F22, 'F', 'C',
+ MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F23, 'F', 'D',
+ MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F24, 'F', 'E',
+ MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F25, 'F', 'F',
+ MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F26, 'F', 'G',
+ MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F27, 'F', 'H',
+ MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F28, 'F', 'I',
+ MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F29, 'F', 'J',
+ MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F30, 'F', 'K',
+
+ MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F31, 'F', 'L',
+ MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F32, 'F', 'M',
+ MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F33, 'F', 'N',
+ MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F34, 'F', 'O',
+ MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F35, 'F', 'P',
+ MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F36, 'F', 'Q',
+ MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F37, 'F', 'R',
+
+ /* TAB pseudo code*/
+ MOD_MASK_SHIFT, 'k', 'B', KS_EXTRA, (int)KE_TAB,
+
+ NUL
+};
+
+static struct key_name_entry
+{
+ int key; /* Special key code or ascii value */
+ char_u *name; /* Name of key */
+} key_names_table[] =
+{
+ {' ', (char_u *)"Space"},
+ {TAB, (char_u *)"Tab"},
+ {K_TAB, (char_u *)"Tab"},
+ {NL, (char_u *)"NL"},
+ {NL, (char_u *)"NewLine"}, /* Alternative name */
+ {NL, (char_u *)"LineFeed"}, /* Alternative name */
+ {NL, (char_u *)"LF"}, /* Alternative name */
+ {CAR, (char_u *)"CR"},
+ {CAR, (char_u *)"Return"}, /* Alternative name */
+ {CAR, (char_u *)"Enter"}, /* Alternative name */
+ {K_BS, (char_u *)"BS"},
+ {K_BS, (char_u *)"BackSpace"}, /* Alternative name */
+ {ESC, (char_u *)"Esc"},
+ {CSI, (char_u *)"CSI"},
+ {K_CSI, (char_u *)"xCSI"},
+ {'|', (char_u *)"Bar"},
+ {'\\', (char_u *)"Bslash"},
+ {K_DEL, (char_u *)"Del"},
+ {K_DEL, (char_u *)"Delete"}, /* Alternative name */
+ {K_KDEL, (char_u *)"kDel"},
+ {K_UP, (char_u *)"Up"},
+ {K_DOWN, (char_u *)"Down"},
+ {K_LEFT, (char_u *)"Left"},
+ {K_RIGHT, (char_u *)"Right"},
+ {K_XUP, (char_u *)"xUp"},
+ {K_XDOWN, (char_u *)"xDown"},
+ {K_XLEFT, (char_u *)"xLeft"},
+ {K_XRIGHT, (char_u *)"xRight"},
+ {K_PS, (char_u *)"PasteStart"},
+ {K_PE, (char_u *)"PasteEnd"},
+
+ {K_F1, (char_u *)"F1"},
+ {K_F2, (char_u *)"F2"},
+ {K_F3, (char_u *)"F3"},
+ {K_F4, (char_u *)"F4"},
+ {K_F5, (char_u *)"F5"},
+ {K_F6, (char_u *)"F6"},
+ {K_F7, (char_u *)"F7"},
+ {K_F8, (char_u *)"F8"},
+ {K_F9, (char_u *)"F9"},
+ {K_F10, (char_u *)"F10"},
+
+ {K_F11, (char_u *)"F11"},
+ {K_F12, (char_u *)"F12"},
+ {K_F13, (char_u *)"F13"},
+ {K_F14, (char_u *)"F14"},
+ {K_F15, (char_u *)"F15"},
+ {K_F16, (char_u *)"F16"},
+ {K_F17, (char_u *)"F17"},
+ {K_F18, (char_u *)"F18"},
+ {K_F19, (char_u *)"F19"},
+ {K_F20, (char_u *)"F20"},
+
+ {K_F21, (char_u *)"F21"},
+ {K_F22, (char_u *)"F22"},
+ {K_F23, (char_u *)"F23"},
+ {K_F24, (char_u *)"F24"},
+ {K_F25, (char_u *)"F25"},
+ {K_F26, (char_u *)"F26"},
+ {K_F27, (char_u *)"F27"},
+ {K_F28, (char_u *)"F28"},
+ {K_F29, (char_u *)"F29"},
+ {K_F30, (char_u *)"F30"},
+
+ {K_F31, (char_u *)"F31"},
+ {K_F32, (char_u *)"F32"},
+ {K_F33, (char_u *)"F33"},
+ {K_F34, (char_u *)"F34"},
+ {K_F35, (char_u *)"F35"},
+ {K_F36, (char_u *)"F36"},
+ {K_F37, (char_u *)"F37"},
+
+ {K_XF1, (char_u *)"xF1"},
+ {K_XF2, (char_u *)"xF2"},
+ {K_XF3, (char_u *)"xF3"},
+ {K_XF4, (char_u *)"xF4"},
+
+ {K_HELP, (char_u *)"Help"},
+ {K_UNDO, (char_u *)"Undo"},
+ {K_INS, (char_u *)"Insert"},
+ {K_INS, (char_u *)"Ins"}, /* Alternative name */
+ {K_KINS, (char_u *)"kInsert"},
+ {K_HOME, (char_u *)"Home"},
+ {K_KHOME, (char_u *)"kHome"},
+ {K_XHOME, (char_u *)"xHome"},
+ {K_ZHOME, (char_u *)"zHome"},
+ {K_END, (char_u *)"End"},
+ {K_KEND, (char_u *)"kEnd"},
+ {K_XEND, (char_u *)"xEnd"},
+ {K_ZEND, (char_u *)"zEnd"},
+ {K_PAGEUP, (char_u *)"PageUp"},
+ {K_PAGEDOWN, (char_u *)"PageDown"},
+ {K_KPAGEUP, (char_u *)"kPageUp"},
+ {K_KPAGEDOWN, (char_u *)"kPageDown"},
+
+ {K_KPLUS, (char_u *)"kPlus"},
+ {K_KMINUS, (char_u *)"kMinus"},
+ {K_KDIVIDE, (char_u *)"kDivide"},
+ {K_KMULTIPLY, (char_u *)"kMultiply"},
+ {K_KENTER, (char_u *)"kEnter"},
+ {K_KPOINT, (char_u *)"kPoint"},
+
+ {K_K0, (char_u *)"k0"},
+ {K_K1, (char_u *)"k1"},
+ {K_K2, (char_u *)"k2"},
+ {K_K3, (char_u *)"k3"},
+ {K_K4, (char_u *)"k4"},
+ {K_K5, (char_u *)"k5"},
+ {K_K6, (char_u *)"k6"},
+ {K_K7, (char_u *)"k7"},
+ {K_K8, (char_u *)"k8"},
+ {K_K9, (char_u *)"k9"},
+
+ {'<', (char_u *)"lt"},
+
+ {K_MOUSE, (char_u *)"Mouse"},
+#ifdef FEAT_MOUSE_NET
+ {K_NETTERM_MOUSE, (char_u *)"NetMouse"},
+#endif
+#ifdef FEAT_MOUSE_DEC
+ {K_DEC_MOUSE, (char_u *)"DecMouse"},
+#endif
+#ifdef FEAT_MOUSE_JSB
+ {K_JSBTERM_MOUSE, (char_u *)"JsbMouse"},
+#endif
+#ifdef FEAT_MOUSE_PTERM
+ {K_PTERM_MOUSE, (char_u *)"PtermMouse"},
+#endif
+#ifdef FEAT_MOUSE_URXVT
+ {K_URXVT_MOUSE, (char_u *)"UrxvtMouse"},
+#endif
+#ifdef FEAT_MOUSE_SGR
+ {K_SGR_MOUSE, (char_u *)"SgrMouse"},
+ {K_SGR_MOUSERELEASE, (char_u *)"SgrMouseRelelase"},
+#endif
+ {K_LEFTMOUSE, (char_u *)"LeftMouse"},
+ {K_LEFTMOUSE_NM, (char_u *)"LeftMouseNM"},
+ {K_LEFTDRAG, (char_u *)"LeftDrag"},
+ {K_LEFTRELEASE, (char_u *)"LeftRelease"},
+ {K_LEFTRELEASE_NM, (char_u *)"LeftReleaseNM"},
+ {K_MOUSEMOVE, (char_u *)"MouseMove"},
+ {K_MIDDLEMOUSE, (char_u *)"MiddleMouse"},
+ {K_MIDDLEDRAG, (char_u *)"MiddleDrag"},
+ {K_MIDDLERELEASE, (char_u *)"MiddleRelease"},
+ {K_RIGHTMOUSE, (char_u *)"RightMouse"},
+ {K_RIGHTDRAG, (char_u *)"RightDrag"},
+ {K_RIGHTRELEASE, (char_u *)"RightRelease"},
+ {K_MOUSEDOWN, (char_u *)"ScrollWheelUp"},
+ {K_MOUSEUP, (char_u *)"ScrollWheelDown"},
+ {K_MOUSELEFT, (char_u *)"ScrollWheelRight"},
+ {K_MOUSERIGHT, (char_u *)"ScrollWheelLeft"},
+ {K_MOUSEDOWN, (char_u *)"MouseDown"}, /* OBSOLETE: Use */
+ {K_MOUSEUP, (char_u *)"MouseUp"}, /* ScrollWheelXXX instead */
+ {K_X1MOUSE, (char_u *)"X1Mouse"},
+ {K_X1DRAG, (char_u *)"X1Drag"},
+ {K_X1RELEASE, (char_u *)"X1Release"},
+ {K_X2MOUSE, (char_u *)"X2Mouse"},
+ {K_X2DRAG, (char_u *)"X2Drag"},
+ {K_X2RELEASE, (char_u *)"X2Release"},
+ {K_DROP, (char_u *)"Drop"},
+ {K_ZERO, (char_u *)"Nul"},
+#ifdef FEAT_EVAL
+ {K_SNR, (char_u *)"SNR"},
+#endif
+ {K_PLUG, (char_u *)"Plug"},
+ {K_CURSORHOLD, (char_u *)"CursorHold"},
+ {0, NULL}
+ /* NOTE: When adding a long name update MAX_KEY_NAME_LEN. */
+};
+
+#define KEY_NAMES_TABLE_LEN (sizeof(key_names_table) / sizeof(struct key_name_entry))
+
+#ifdef FEAT_MOUSE
+static struct mousetable
+{
+ int pseudo_code; /* Code for pseudo mouse event */
+ int button; /* Which mouse button is it? */
+ int is_click; /* Is it a mouse button click event? */
+ int is_drag; /* Is it a mouse drag event? */
+} mouse_table[] =
+{
+ {(int)KE_LEFTMOUSE, MOUSE_LEFT, TRUE, FALSE},
+#ifdef FEAT_GUI
+ {(int)KE_LEFTMOUSE_NM, MOUSE_LEFT, TRUE, FALSE},
+#endif
+ {(int)KE_LEFTDRAG, MOUSE_LEFT, FALSE, TRUE},
+ {(int)KE_LEFTRELEASE, MOUSE_LEFT, FALSE, FALSE},
+#ifdef FEAT_GUI
+ {(int)KE_LEFTRELEASE_NM, MOUSE_LEFT, FALSE, FALSE},
+#endif
+ {(int)KE_MIDDLEMOUSE, MOUSE_MIDDLE, TRUE, FALSE},
+ {(int)KE_MIDDLEDRAG, MOUSE_MIDDLE, FALSE, TRUE},
+ {(int)KE_MIDDLERELEASE, MOUSE_MIDDLE, FALSE, FALSE},
+ {(int)KE_RIGHTMOUSE, MOUSE_RIGHT, TRUE, FALSE},
+ {(int)KE_RIGHTDRAG, MOUSE_RIGHT, FALSE, TRUE},
+ {(int)KE_RIGHTRELEASE, MOUSE_RIGHT, FALSE, FALSE},
+ {(int)KE_X1MOUSE, MOUSE_X1, TRUE, FALSE},
+ {(int)KE_X1DRAG, MOUSE_X1, FALSE, TRUE},
+ {(int)KE_X1RELEASE, MOUSE_X1, FALSE, FALSE},
+ {(int)KE_X2MOUSE, MOUSE_X2, TRUE, FALSE},
+ {(int)KE_X2DRAG, MOUSE_X2, FALSE, TRUE},
+ {(int)KE_X2RELEASE, MOUSE_X2, FALSE, FALSE},
+ /* DRAG without CLICK */
+ {(int)KE_MOUSEMOVE, MOUSE_RELEASE, FALSE, TRUE},
+ /* RELEASE without CLICK */
+ {(int)KE_IGNORE, MOUSE_RELEASE, FALSE, FALSE},
+ {0, 0, 0, 0},
+};
+#endif /* FEAT_MOUSE */
+
+/*
+ * Return the modifier mask bit (MOD_MASK_*) which corresponds to the given
+ * modifier name ('S' for Shift, 'C' for Ctrl etc).
+ */
+ int
+name_to_mod_mask(int c)
+{
+ int i;
+
+ c = TOUPPER_ASC(c);
+ for (i = 0; mod_mask_table[i].mod_mask != 0; i++)
+ if (c == mod_mask_table[i].name)
+ return mod_mask_table[i].mod_flag;
+ return 0;
+}
+
+/*
+ * Check if if there is a special key code for "key" that includes the
+ * modifiers specified.
+ */
+ int
+simplify_key(int key, int *modifiers)
+{
+ int i;
+ int key0;
+ int key1;
+
+ if (*modifiers & (MOD_MASK_SHIFT | MOD_MASK_CTRL | MOD_MASK_ALT))
+ {
+ /* TAB is a special case */
+ if (key == TAB && (*modifiers & MOD_MASK_SHIFT))
+ {
+ *modifiers &= ~MOD_MASK_SHIFT;
+ return K_S_TAB;
+ }
+ key0 = KEY2TERMCAP0(key);
+ key1 = KEY2TERMCAP1(key);
+ for (i = 0; modifier_keys_table[i] != NUL; i += MOD_KEYS_ENTRY_SIZE)
+ if (key0 == modifier_keys_table[i + 3]
+ && key1 == modifier_keys_table[i + 4]
+ && (*modifiers & modifier_keys_table[i]))
+ {
+ *modifiers &= ~modifier_keys_table[i];
+ return TERMCAP2KEY(modifier_keys_table[i + 1],
+ modifier_keys_table[i + 2]);
+ }
+ }
+ return key;
+}
+
+/*
+ * Change <xHome> to <Home>, <xUp> to <Up>, etc.
+ */
+ int
+handle_x_keys(int key)
+{
+ switch (key)
+ {
+ case K_XUP: return K_UP;
+ case K_XDOWN: return K_DOWN;
+ case K_XLEFT: return K_LEFT;
+ case K_XRIGHT: return K_RIGHT;
+ case K_XHOME: return K_HOME;
+ case K_ZHOME: return K_HOME;
+ case K_XEND: return K_END;
+ case K_ZEND: return K_END;
+ case K_XF1: return K_F1;
+ case K_XF2: return K_F2;
+ case K_XF3: return K_F3;
+ case K_XF4: return K_F4;
+ case K_S_XF1: return K_S_F1;
+ case K_S_XF2: return K_S_F2;
+ case K_S_XF3: return K_S_F3;
+ case K_S_XF4: return K_S_F4;
+ }
+ return key;
+}
+
+/*
+ * Return a string which contains the name of the given key when the given
+ * modifiers are down.
+ */
+ char_u *
+get_special_key_name(int c, int modifiers)
+{
+ static char_u string[MAX_KEY_NAME_LEN + 1];
+
+ int i, idx;
+ int table_idx;
+ char_u *s;
+
+ string[0] = '<';
+ idx = 1;
+
+ /* Key that stands for a normal character. */
+ if (IS_SPECIAL(c) && KEY2TERMCAP0(c) == KS_KEY)
+ c = KEY2TERMCAP1(c);
+
+ /*
+ * Translate shifted special keys into unshifted keys and set modifier.
+ * Same for CTRL and ALT modifiers.
+ */
+ if (IS_SPECIAL(c))
+ {
+ for (i = 0; modifier_keys_table[i] != 0; i += MOD_KEYS_ENTRY_SIZE)
+ if ( KEY2TERMCAP0(c) == (int)modifier_keys_table[i + 1]
+ && (int)KEY2TERMCAP1(c) == (int)modifier_keys_table[i + 2])
+ {
+ modifiers |= modifier_keys_table[i];
+ c = TERMCAP2KEY(modifier_keys_table[i + 3],
+ modifier_keys_table[i + 4]);
+ break;
+ }
+ }
+
+ /* try to find the key in the special key table */
+ table_idx = find_special_key_in_table(c);
+
+ /*
+ * When not a known special key, and not a printable character, try to
+ * extract modifiers.
+ */
+ if (c > 0 && (*mb_char2len)(c) == 1)
+ {
+ if (table_idx < 0
+ && (!vim_isprintc(c) || (c & 0x7f) == ' ')
+ && (c & 0x80))
+ {
+ c &= 0x7f;
+ modifiers |= MOD_MASK_ALT;
+ /* try again, to find the un-alted key in the special key table */
+ table_idx = find_special_key_in_table(c);
+ }
+ if (table_idx < 0 && !vim_isprintc(c) && c < ' ')
+ {
+#ifdef EBCDIC
+ c = CtrlChar(c);
+#else
+ c += '@';
+#endif
+ modifiers |= MOD_MASK_CTRL;
+ }
+ }
+
+ /* translate the modifier into a string */
+ for (i = 0; mod_mask_table[i].name != 'A'; i++)
+ if ((modifiers & mod_mask_table[i].mod_mask)
+ == mod_mask_table[i].mod_flag)
+ {
+ string[idx++] = mod_mask_table[i].name;
+ string[idx++] = (char_u)'-';
+ }
+
+ if (table_idx < 0) /* unknown special key, may output t_xx */
+ {
+ if (IS_SPECIAL(c))
+ {
+ string[idx++] = 't';
+ string[idx++] = '_';
+ string[idx++] = KEY2TERMCAP0(c);
+ string[idx++] = KEY2TERMCAP1(c);
+ }
+ /* Not a special key, only modifiers, output directly */
+ else
+ {
+ if (has_mbyte && (*mb_char2len)(c) > 1)
+ idx += (*mb_char2bytes)(c, string + idx);
+ else if (vim_isprintc(c))
+ string[idx++] = c;
+ else
+ {
+ s = transchar(c);
+ while (*s)
+ string[idx++] = *s++;
+ }
+ }
+ }
+ else /* use name of special key */
+ {
+ size_t len = STRLEN(key_names_table[table_idx].name);
+
+ if (len + idx + 2 <= MAX_KEY_NAME_LEN)
+ {
+ STRCPY(string + idx, key_names_table[table_idx].name);
+ idx += (int)len;
+ }
+ }
+ string[idx++] = '>';
+ string[idx] = NUL;
+ return string;
+}
+
+/*
+ * Try translating a <> name at (*srcp)[] to dst[].
+ * Return the number of characters added to dst[], zero for no match.
+ * If there is a match, srcp is advanced to after the <> name.
+ * dst[] must be big enough to hold the result (up to six characters)!
+ */
+ int
+trans_special(
+ char_u **srcp,
+ char_u *dst,
+ int keycode, /* prefer key code, e.g. K_DEL instead of DEL */
+ int in_string) /* TRUE when inside a double quoted string */
+{
+ int modifiers = 0;
+ int key;
+ int dlen = 0;
+
+ key = find_special_key(srcp, &modifiers, keycode, FALSE, in_string);
+ if (key == 0)
+ return 0;
+
+ /* Put the appropriate modifier in a string */
+ if (modifiers != 0)
+ {
+ dst[dlen++] = K_SPECIAL;
+ dst[dlen++] = KS_MODIFIER;
+ dst[dlen++] = modifiers;
+ }
+
+ if (IS_SPECIAL(key))
+ {
+ dst[dlen++] = K_SPECIAL;
+ dst[dlen++] = KEY2TERMCAP0(key);
+ dst[dlen++] = KEY2TERMCAP1(key);
+ }
+ else if (has_mbyte && !keycode)
+ dlen += (*mb_char2bytes)(key, dst + dlen);
+ else if (keycode)
+ dlen = (int)(add_char2buf(key, dst + dlen) - dst);
+ else
+ dst[dlen++] = key;
+
+ return dlen;
+}
+
+/*
+ * Try translating a <> name at (*srcp)[], return the key and modifiers.
+ * srcp is advanced to after the <> name.
+ * returns 0 if there is no match.
+ */
+ int
+find_special_key(
+ char_u **srcp,
+ int *modp,
+ int keycode, /* prefer key code, e.g. K_DEL instead of DEL */
+ int keep_x_key, /* don't translate xHome to Home key */
+ int in_string) /* TRUE in string, double quote is escaped */
+{
+ char_u *last_dash;
+ char_u *end_of_name;
+ char_u *src;
+ char_u *bp;
+ int modifiers;
+ int bit;
+ int key;
+ uvarnumber_T n;
+ int l;
+
+ src = *srcp;
+ if (src[0] != '<')
+ return 0;
+
+ /* Find end of modifier list */
+ last_dash = src;
+ for (bp = src + 1; *bp == '-' || vim_isIDc(*bp); bp++)
+ {
+ if (*bp == '-')
+ {
+ last_dash = bp;
+ if (bp[1] != NUL)
+ {
+ if (has_mbyte)
+ l = mb_ptr2len(bp + 1);
+ else
+ l = 1;
+ /* Anything accepted, like <C-?>.
+ * <C-"> or <M-"> are not special in strings as " is
+ * the string delimiter. With a backslash it works: <M-\"> */
+ if (!(in_string && bp[1] == '"') && bp[2] == '>')
+ bp += l;
+ else if (in_string && bp[1] == '\\' && bp[2] == '"'
+ && bp[3] == '>')
+ bp += 2;
+ }
+ }
+ if (bp[0] == 't' && bp[1] == '_' && bp[2] && bp[3])
+ bp += 3; /* skip t_xx, xx may be '-' or '>' */
+ else if (STRNICMP(bp, "char-", 5) == 0)
+ {
+ vim_str2nr(bp + 5, NULL, &l, STR2NR_ALL, NULL, NULL, 0);
+ bp += l + 5;
+ break;
+ }
+ }
+
+ if (*bp == '>') /* found matching '>' */
+ {
+ end_of_name = bp + 1;
+
+ /* Which modifiers are given? */
+ modifiers = 0x0;
+ for (bp = src + 1; bp < last_dash; bp++)
+ {
+ if (*bp != '-')
+ {
+ bit = name_to_mod_mask(*bp);
+ if (bit == 0x0)
+ break; /* Illegal modifier name */
+ modifiers |= bit;
+ }
+ }
+
+ /*
+ * Legal modifier name.
+ */
+ if (bp >= last_dash)
+ {
+ if (STRNICMP(last_dash + 1, "char-", 5) == 0
+ && VIM_ISDIGIT(last_dash[6]))
+ {
+ /* <Char-123> or <Char-033> or <Char-0x33> */
+ vim_str2nr(last_dash + 6, NULL, NULL, STR2NR_ALL, NULL, &n, 0);
+ key = (int)n;
+ }
+ else
+ {
+ int off = 1;
+
+ /* Modifier with single letter, or special key name. */
+ if (in_string && last_dash[1] == '\\' && last_dash[2] == '"')
+ off = 2;
+ if (has_mbyte)
+ l = mb_ptr2len(last_dash + off);
+ else
+ l = 1;
+ if (modifiers != 0 && last_dash[l + off] == '>')
+ key = PTR2CHAR(last_dash + off);
+ else
+ {
+ key = get_special_key_code(last_dash + off);
+ if (!keep_x_key)
+ key = handle_x_keys(key);
+ }
+ }
+
+ /*
+ * get_special_key_code() may return NUL for invalid
+ * special key name.
+ */
+ if (key != NUL)
+ {
+ /*
+ * Only use a modifier when there is no special key code that
+ * includes the modifier.
+ */
+ key = simplify_key(key, &modifiers);
+
+ if (!keycode)
+ {
+ /* don't want keycode, use single byte code */
+ if (key == K_BS)
+ key = BS;
+ else if (key == K_DEL || key == K_KDEL)
+ key = DEL;
+ }
+
+ /*
+ * Normal Key with modifier: Try to make a single byte code.
+ */
+ if (!IS_SPECIAL(key))
+ key = extract_modifiers(key, &modifiers);
+
+ *modp = modifiers;
+ *srcp = end_of_name;
+ return key;
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ * Try to include modifiers in the key.
+ * Changes "Shift-a" to 'A', "Alt-A" to 0xc0, etc.
+ */
+ int
+extract_modifiers(int key, int *modp)
+{
+ int modifiers = *modp;
+
+#ifdef MACOS_X
+ /* Command-key really special, no fancynest */
+ if (!(modifiers & MOD_MASK_CMD))
+#endif
+ if ((modifiers & MOD_MASK_SHIFT) && ASCII_ISALPHA(key))
+ {
+ key = TOUPPER_ASC(key);
+ modifiers &= ~MOD_MASK_SHIFT;
+ }
+ if ((modifiers & MOD_MASK_CTRL)
+#ifdef EBCDIC
+ /* * TODO: EBCDIC Better use:
+ * && (Ctrl_chr(key) || key == '?')
+ * ??? */
+ && strchr("?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_", key)
+ != NULL
+#else
+ && ((key >= '?' && key <= '_') || ASCII_ISALPHA(key))
+#endif
+ )
+ {
+ key = Ctrl_chr(key);
+ modifiers &= ~MOD_MASK_CTRL;
+ /* <C-@> is <Nul> */
+ if (key == 0)
+ key = K_ZERO;
+ }
+#ifdef MACOS_X
+ /* Command-key really special, no fancynest */
+ if (!(modifiers & MOD_MASK_CMD))
+#endif
+ if ((modifiers & MOD_MASK_ALT) && key < 0x80
+ && !enc_dbcs) // avoid creating a lead byte
+ {
+ key |= 0x80;
+ modifiers &= ~MOD_MASK_ALT; /* remove the META modifier */
+ }
+
+ *modp = modifiers;
+ return key;
+}
+
+/*
+ * Try to find key "c" in the special key table.
+ * Return the index when found, -1 when not found.
+ */
+ int
+find_special_key_in_table(int c)
+{
+ int i;
+
+ for (i = 0; key_names_table[i].name != NULL; i++)
+ if (c == key_names_table[i].key)
+ break;
+ if (key_names_table[i].name == NULL)
+ i = -1;
+ return i;
+}
+
+/*
+ * Find the special key with the given name (the given string does not have to
+ * end with NUL, the name is assumed to end before the first non-idchar).
+ * If the name starts with "t_" the next two characters are interpreted as a
+ * termcap name.
+ * Return the key code, or 0 if not found.
+ */
+ int
+get_special_key_code(char_u *name)
+{
+ char_u *table_name;
+ char_u string[3];
+ int i, j;
+
+ /*
+ * If it's <t_xx> we get the code for xx from the termcap
+ */
+ if (name[0] == 't' && name[1] == '_' && name[2] != NUL && name[3] != NUL)
+ {
+ string[0] = name[2];
+ string[1] = name[3];
+ string[2] = NUL;
+ if (add_termcap_entry(string, FALSE) == OK)
+ return TERMCAP2KEY(name[2], name[3]);
+ }
+ else
+ for (i = 0; key_names_table[i].name != NULL; i++)
+ {
+ table_name = key_names_table[i].name;
+ for (j = 0; vim_isIDc(name[j]) && table_name[j] != NUL; j++)
+ if (TOLOWER_ASC(table_name[j]) != TOLOWER_ASC(name[j]))
+ break;
+ if (!vim_isIDc(name[j]) && table_name[j] == NUL)
+ return key_names_table[i].key;
+ }
+ return 0;
+}
+
+#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
+ char_u *
+get_key_name(int i)
+{
+ if (i >= (int)KEY_NAMES_TABLE_LEN)
+ return NULL;
+ return key_names_table[i].name;
+}
+#endif
+
+#if defined(FEAT_MOUSE) || defined(PROTO)
+/*
+ * Look up the given mouse code to return the relevant information in the other
+ * arguments. Return which button is down or was released.
+ */
+ int
+get_mouse_button(int code, int *is_click, int *is_drag)
+{
+ int i;
+
+ for (i = 0; mouse_table[i].pseudo_code; i++)
+ if (code == mouse_table[i].pseudo_code)
+ {
+ *is_click = mouse_table[i].is_click;
+ *is_drag = mouse_table[i].is_drag;
+ return mouse_table[i].button;
+ }
+ return 0; /* Shouldn't get here */
+}
+
+/*
+ * Return the appropriate pseudo mouse event token (KE_LEFTMOUSE etc) based on
+ * the given information about which mouse button is down, and whether the
+ * mouse was clicked, dragged or released.
+ */
+ int
+get_pseudo_mouse_code(
+ int button, /* eg MOUSE_LEFT */
+ int is_click,
+ int is_drag)
+{
+ int i;
+
+ for (i = 0; mouse_table[i].pseudo_code; i++)
+ if (button == mouse_table[i].button
+ && is_click == mouse_table[i].is_click
+ && is_drag == mouse_table[i].is_drag)
+ {
+#ifdef FEAT_GUI
+ /* Trick: a non mappable left click and release has mouse_col -1
+ * or added MOUSE_COLOFF. Used for 'mousefocus' in
+ * gui_mouse_moved() */
+ if (mouse_col < 0 || mouse_col > MOUSE_COLOFF)
+ {
+ if (mouse_col < 0)
+ mouse_col = 0;
+ else
+ mouse_col -= MOUSE_COLOFF;
+ if (mouse_table[i].pseudo_code == (int)KE_LEFTMOUSE)
+ return (int)KE_LEFTMOUSE_NM;
+ if (mouse_table[i].pseudo_code == (int)KE_LEFTRELEASE)
+ return (int)KE_LEFTRELEASE_NM;
+ }
+#endif
+ return mouse_table[i].pseudo_code;
+ }
+ return (int)KE_IGNORE; /* not recognized, ignore it */
+}
+#endif /* FEAT_MOUSE */
+
+/*
+ * Return the current end-of-line type: EOL_DOS, EOL_UNIX or EOL_MAC.
+ */
+ int
+get_fileformat(buf_T *buf)
+{
+ int c = *buf->b_p_ff;
+
+ if (buf->b_p_bin || c == 'u')
+ return EOL_UNIX;
+ if (c == 'm')
+ return EOL_MAC;
+ return EOL_DOS;
+}
+
+/*
+ * Like get_fileformat(), but override 'fileformat' with "p" for "++opt=val"
+ * argument.
+ */
+ int
+get_fileformat_force(
+ buf_T *buf,
+ exarg_T *eap) /* can be NULL! */
+{
+ int c;
+
+ if (eap != NULL && eap->force_ff != 0)
+ c = eap->force_ff;
+ else
+ {
+ if ((eap != NULL && eap->force_bin != 0)
+ ? (eap->force_bin == FORCE_BIN) : buf->b_p_bin)
+ return EOL_UNIX;
+ c = *buf->b_p_ff;
+ }
+ if (c == 'u')
+ return EOL_UNIX;
+ if (c == 'm')
+ return EOL_MAC;
+ return EOL_DOS;
+}
+
+/*
+ * Set the current end-of-line type to EOL_DOS, EOL_UNIX or EOL_MAC.
+ * Sets both 'textmode' and 'fileformat'.
+ * Note: Does _not_ set global value of 'textmode'!
+ */
+ void
+set_fileformat(
+ int t,
+ int opt_flags) /* OPT_LOCAL and/or OPT_GLOBAL */
+{
+ char *p = NULL;
+
+ switch (t)
+ {
+ case EOL_DOS:
+ p = FF_DOS;
+ curbuf->b_p_tx = TRUE;
+ break;
+ case EOL_UNIX:
+ p = FF_UNIX;
+ curbuf->b_p_tx = FALSE;
+ break;
+ case EOL_MAC:
+ p = FF_MAC;
+ curbuf->b_p_tx = FALSE;
+ break;
+ }
+ if (p != NULL)
+ set_string_option_direct((char_u *)"ff", -1, (char_u *)p,
+ OPT_FREE | opt_flags, 0);
+
+ /* This may cause the buffer to become (un)modified. */
+ check_status(curbuf);
+ redraw_tabline = TRUE;
+#ifdef FEAT_TITLE
+ need_maketitle = TRUE; /* set window title later */
+#endif
+}
+
+/*
+ * Return the default fileformat from 'fileformats'.
+ */
+ int
+default_fileformat(void)
+{
+ switch (*p_ffs)
+ {
+ case 'm': return EOL_MAC;
+ case 'd': return EOL_DOS;
+ }
+ return EOL_UNIX;
+}
+
+/*
+ * Call shell. Calls mch_call_shell, with 'shellxquote' added.
+ */
+ int
+call_shell(char_u *cmd, int opt)
+{
+ char_u *ncmd;
+ int retval;
+#ifdef FEAT_PROFILE
+ proftime_T wait_time;
+#endif
+
+ if (p_verbose > 3)
+ {
+ verbose_enter();
+ smsg(_("Calling shell to execute: \"%s\""),
+ cmd == NULL ? p_sh : cmd);
+ out_char('\n');
+ cursor_on();
+ verbose_leave();
+ }
+
+#ifdef FEAT_PROFILE
+ if (do_profiling == PROF_YES)
+ prof_child_enter(&wait_time);
+#endif
+
+ if (*p_sh == NUL)
+ {
+ emsg(_(e_shellempty));
+ retval = -1;
+ }
+ else
+ {
+#ifdef FEAT_GUI_MSWIN
+ /* Don't hide the pointer while executing a shell command. */
+ gui_mch_mousehide(FALSE);
+#endif
+#ifdef FEAT_GUI
+ ++hold_gui_events;
+#endif
+ /* The external command may update a tags file, clear cached tags. */
+ tag_freematch();
+
+ if (cmd == NULL || *p_sxq == NUL)
+ retval = mch_call_shell(cmd, opt);
+ else
+ {
+ char_u *ecmd = cmd;
+
+ if (*p_sxe != NUL && STRCMP(p_sxq, "(") == 0)
+ {
+ ecmd = vim_strsave_escaped_ext(cmd, p_sxe, '^', FALSE);
+ if (ecmd == NULL)
+ ecmd = cmd;
+ }
+ ncmd = alloc((unsigned)(STRLEN(ecmd) + STRLEN(p_sxq) * 2 + 1));
+ if (ncmd != NULL)
+ {
+ STRCPY(ncmd, p_sxq);
+ STRCAT(ncmd, ecmd);
+ /* When 'shellxquote' is ( append ).
+ * When 'shellxquote' is "( append )". */
+ STRCAT(ncmd, STRCMP(p_sxq, "(") == 0 ? (char_u *)")"
+ : STRCMP(p_sxq, "\"(") == 0 ? (char_u *)")\""
+ : p_sxq);
+ retval = mch_call_shell(ncmd, opt);
+ vim_free(ncmd);
+ }
+ else
+ retval = -1;
+ if (ecmd != cmd)
+ vim_free(ecmd);
+ }
+#ifdef FEAT_GUI
+ --hold_gui_events;
+#endif
+ /*
+ * Check the window size, in case it changed while executing the
+ * external command.
+ */
+ shell_resized_check();
+ }
+
+#ifdef FEAT_EVAL
+ set_vim_var_nr(VV_SHELL_ERROR, (long)retval);
+# ifdef FEAT_PROFILE
+ if (do_profiling == PROF_YES)
+ prof_child_exit(&wait_time);
+# endif
+#endif
+
+ return retval;
+}
+
+/*
+ * VISUAL, SELECTMODE and OP_PENDING State are never set, they are equal to
+ * NORMAL State with a condition. This function returns the real State.
+ */
+ int
+get_real_state(void)
+{
+ if (State & NORMAL)
+ {
+ if (VIsual_active)
+ {
+ if (VIsual_select)
+ return SELECTMODE;
+ return VISUAL;
+ }
+ else if (finish_op)
+ return OP_PENDING;
+ }
+ return State;
+}
+
+/*
+ * Return TRUE if "p" points to just after a path separator.
+ * Takes care of multi-byte characters.
+ * "b" must point to the start of the file name
+ */
+ int
+after_pathsep(char_u *b, char_u *p)
+{
+ return p > b && vim_ispathsep(p[-1])
+ && (!has_mbyte || (*mb_head_off)(b, p - 1) == 0);
+}
+
+/*
+ * Return TRUE if file names "f1" and "f2" are in the same directory.
+ * "f1" may be a short name, "f2" must be a full path.
+ */
+ int
+same_directory(char_u *f1, char_u *f2)
+{
+ char_u ffname[MAXPATHL];
+ char_u *t1;
+ char_u *t2;
+
+ /* safety check */
+ if (f1 == NULL || f2 == NULL)
+ return FALSE;
+
+ (void)vim_FullName(f1, ffname, MAXPATHL, FALSE);
+ t1 = gettail_sep(ffname);
+ t2 = gettail_sep(f2);
+ return (t1 - ffname == t2 - f2
+ && pathcmp((char *)ffname, (char *)f2, (int)(t1 - ffname)) == 0);
+}
+
+#if defined(FEAT_SESSION) || defined(FEAT_AUTOCHDIR) \
+ || defined(MSWIN) || defined(FEAT_GUI_MAC) || defined(FEAT_GUI_GTK) \
+ || defined(FEAT_NETBEANS_INTG) \
+ || defined(PROTO)
+/*
+ * Change to a file's directory.
+ * Caller must call shorten_fnames()!
+ * Return OK or FAIL.
+ */
+ int
+vim_chdirfile(char_u *fname, char *trigger_autocmd)
+{
+ char_u old_dir[MAXPATHL];
+ char_u new_dir[MAXPATHL];
+ int res;
+
+ if (mch_dirname(old_dir, MAXPATHL) != OK)
+ *old_dir = NUL;
+
+ vim_strncpy(new_dir, fname, MAXPATHL - 1);
+ *gettail_sep(new_dir) = NUL;
+
+ if (pathcmp((char *)old_dir, (char *)new_dir, -1) == 0)
+ // nothing to do
+ res = OK;
+ else
+ {
+ res = mch_chdir((char *)new_dir) == 0 ? OK : FAIL;
+
+ if (res == OK && trigger_autocmd != NULL)
+ apply_autocmds(EVENT_DIRCHANGED, (char_u *)trigger_autocmd,
+ new_dir, FALSE, curbuf);
+ }
+ return res;
+}
+#endif
+
+#if defined(STAT_IGNORES_SLASH) || defined(PROTO)
+/*
+ * Check if "name" ends in a slash and is not a directory.
+ * Used for systems where stat() ignores a trailing slash on a file name.
+ * The Vim code assumes a trailing slash is only ignored for a directory.
+ */
+ static int
+illegal_slash(const char *name)
+{
+ if (name[0] == NUL)
+ return FALSE; /* no file name is not illegal */
+ if (name[strlen(name) - 1] != '/')
+ return FALSE; /* no trailing slash */
+ if (mch_isdir((char_u *)name))
+ return FALSE; /* trailing slash for a directory */
+ return TRUE;
+}
+
+/*
+ * Special implementation of mch_stat() for Solaris.
+ */
+ int
+vim_stat(const char *name, stat_T *stp)
+{
+ /* On Solaris stat() accepts "file/" as if it was "file". Return -1 if
+ * the name ends in "/" and it's not a directory. */
+ return illegal_slash(name) ? -1 : stat(name, stp);
+}
+#endif
+
+#if defined(CURSOR_SHAPE) || defined(PROTO)
+
+/*
+ * Handling of cursor and mouse pointer shapes in various modes.
+ */
+
+cursorentry_T shape_table[SHAPE_IDX_COUNT] =
+{
+ /* The values will be filled in from the 'guicursor' and 'mouseshape'
+ * defaults when Vim starts.
+ * Adjust the SHAPE_IDX_ defines when making changes! */
+ {0, 0, 0, 700L, 400L, 250L, 0, 0, "n", SHAPE_CURSOR+SHAPE_MOUSE},
+ {0, 0, 0, 700L, 400L, 250L, 0, 0, "v", SHAPE_CURSOR+SHAPE_MOUSE},
+ {0, 0, 0, 700L, 400L, 250L, 0, 0, "i", SHAPE_CURSOR+SHAPE_MOUSE},
+ {0, 0, 0, 700L, 400L, 250L, 0, 0, "r", SHAPE_CURSOR+SHAPE_MOUSE},
+ {0, 0, 0, 700L, 400L, 250L, 0, 0, "c", SHAPE_CURSOR+SHAPE_MOUSE},
+ {0, 0, 0, 700L, 400L, 250L, 0, 0, "ci", SHAPE_CURSOR+SHAPE_MOUSE},
+ {0, 0, 0, 700L, 400L, 250L, 0, 0, "cr", SHAPE_CURSOR+SHAPE_MOUSE},
+ {0, 0, 0, 700L, 400L, 250L, 0, 0, "o", SHAPE_CURSOR+SHAPE_MOUSE},
+ {0, 0, 0, 700L, 400L, 250L, 0, 0, "ve", SHAPE_CURSOR+SHAPE_MOUSE},
+ {0, 0, 0, 0L, 0L, 0L, 0, 0, "e", SHAPE_MOUSE},
+ {0, 0, 0, 0L, 0L, 0L, 0, 0, "s", SHAPE_MOUSE},
+ {0, 0, 0, 0L, 0L, 0L, 0, 0, "sd", SHAPE_MOUSE},
+ {0, 0, 0, 0L, 0L, 0L, 0, 0, "vs", SHAPE_MOUSE},
+ {0, 0, 0, 0L, 0L, 0L, 0, 0, "vd", SHAPE_MOUSE},
+ {0, 0, 0, 0L, 0L, 0L, 0, 0, "m", SHAPE_MOUSE},
+ {0, 0, 0, 0L, 0L, 0L, 0, 0, "ml", SHAPE_MOUSE},
+ {0, 0, 0, 100L, 100L, 100L, 0, 0, "sm", SHAPE_CURSOR},
+};
+
+#ifdef FEAT_MOUSESHAPE
+/*
+ * Table with names for mouse shapes. Keep in sync with all the tables for
+ * mch_set_mouse_shape()!.
+ */
+static char * mshape_names[] =
+{
+ "arrow", /* default, must be the first one */
+ "blank", /* hidden */
+ "beam",
+ "updown",
+ "udsizing",
+ "leftright",
+ "lrsizing",
+ "busy",
+ "no",
+ "crosshair",
+ "hand1",
+ "hand2",
+ "pencil",
+ "question",
+ "rightup-arrow",
+ "up-arrow",
+ NULL
+};
+#endif
+
+/*
+ * Parse the 'guicursor' option ("what" is SHAPE_CURSOR) or 'mouseshape'
+ * ("what" is SHAPE_MOUSE).
+ * Returns error message for an illegal option, NULL otherwise.
+ */
+ char *
+parse_shape_opt(int what)
+{
+ char_u *modep;
+ char_u *colonp;
+ char_u *commap;
+ char_u *slashp;
+ char_u *p, *endp;
+ int idx = 0; /* init for GCC */
+ int all_idx;
+ int len;
+ int i;
+ long n;
+ int found_ve = FALSE; /* found "ve" flag */
+ int round;
+
+ /*
+ * First round: check for errors; second round: do it for real.
+ */
+ for (round = 1; round <= 2; ++round)
+ {
+ /*
+ * Repeat for all comma separated parts.
+ */
+#ifdef FEAT_MOUSESHAPE
+ if (what == SHAPE_MOUSE)
+ modep = p_mouseshape;
+ else
+#endif
+ modep = p_guicursor;
+ while (*modep != NUL)
+ {
+ colonp = vim_strchr(modep, ':');
+ commap = vim_strchr(modep, ',');
+
+ if (colonp == NULL || (commap != NULL && commap < colonp))
+ return N_("E545: Missing colon");
+ if (colonp == modep)
+ return N_("E546: Illegal mode");
+
+ /*
+ * Repeat for all mode's before the colon.
+ * For the 'a' mode, we loop to handle all the modes.
+ */
+ all_idx = -1;
+ while (modep < colonp || all_idx >= 0)
+ {
+ if (all_idx < 0)
+ {
+ /* Find the mode. */
+ if (modep[1] == '-' || modep[1] == ':')
+ len = 1;
+ else
+ len = 2;
+ if (len == 1 && TOLOWER_ASC(modep[0]) == 'a')
+ all_idx = SHAPE_IDX_COUNT - 1;
+ else
+ {
+ for (idx = 0; idx < SHAPE_IDX_COUNT; ++idx)
+ if (STRNICMP(modep, shape_table[idx].name, len)
+ == 0)
+ break;
+ if (idx == SHAPE_IDX_COUNT
+ || (shape_table[idx].used_for & what) == 0)
+ return N_("E546: Illegal mode");
+ if (len == 2 && modep[0] == 'v' && modep[1] == 'e')
+ found_ve = TRUE;
+ }
+ modep += len + 1;
+ }
+
+ if (all_idx >= 0)
+ idx = all_idx--;
+ else if (round == 2)
+ {
+#ifdef FEAT_MOUSESHAPE
+ if (what == SHAPE_MOUSE)
+ {
+ /* Set the default, for the missing parts */
+ shape_table[idx].mshape = 0;
+ }
+ else
+#endif
+ {
+ /* Set the defaults, for the missing parts */
+ shape_table[idx].shape = SHAPE_BLOCK;
+ shape_table[idx].blinkwait = 700L;
+ shape_table[idx].blinkon = 400L;
+ shape_table[idx].blinkoff = 250L;
+ }
+ }
+
+ /* Parse the part after the colon */
+ for (p = colonp + 1; *p && *p != ','; )
+ {
+#ifdef FEAT_MOUSESHAPE
+ if (what == SHAPE_MOUSE)
+ {
+ for (i = 0; ; ++i)
+ {
+ if (mshape_names[i] == NULL)
+ {
+ if (!VIM_ISDIGIT(*p))
+ return N_("E547: Illegal mouseshape");
+ if (round == 2)
+ shape_table[idx].mshape =
+ getdigits(&p) + MSHAPE_NUMBERED;
+ else
+ (void)getdigits(&p);
+ break;
+ }
+ len = (int)STRLEN(mshape_names[i]);
+ if (STRNICMP(p, mshape_names[i], len) == 0)
+ {
+ if (round == 2)
+ shape_table[idx].mshape = i;
+ p += len;
+ break;
+ }
+ }
+ }
+ else /* if (what == SHAPE_MOUSE) */
+#endif
+ {
+ /*
+ * First handle the ones with a number argument.
+ */
+ i = *p;
+ len = 0;
+ if (STRNICMP(p, "ver", 3) == 0)
+ len = 3;
+ else if (STRNICMP(p, "hor", 3) == 0)
+ len = 3;
+ else if (STRNICMP(p, "blinkwait", 9) == 0)
+ len = 9;
+ else if (STRNICMP(p, "blinkon", 7) == 0)
+ len = 7;
+ else if (STRNICMP(p, "blinkoff", 8) == 0)
+ len = 8;
+ if (len != 0)
+ {
+ p += len;
+ if (!VIM_ISDIGIT(*p))
+ return N_("E548: digit expected");
+ n = getdigits(&p);
+ if (len == 3) /* "ver" or "hor" */
+ {
+ if (n == 0)
+ return N_("E549: Illegal percentage");
+ if (round == 2)
+ {
+ if (TOLOWER_ASC(i) == 'v')
+ shape_table[idx].shape = SHAPE_VER;
+ else
+ shape_table[idx].shape = SHAPE_HOR;
+ shape_table[idx].percentage = n;
+ }
+ }
+ else if (round == 2)
+ {
+ if (len == 9)
+ shape_table[idx].blinkwait = n;
+ else if (len == 7)
+ shape_table[idx].blinkon = n;
+ else
+ shape_table[idx].blinkoff = n;
+ }
+ }
+ else if (STRNICMP(p, "block", 5) == 0)
+ {
+ if (round == 2)
+ shape_table[idx].shape = SHAPE_BLOCK;
+ p += 5;
+ }
+ else /* must be a highlight group name then */
+ {
+ endp = vim_strchr(p, '-');
+ if (commap == NULL) /* last part */
+ {
+ if (endp == NULL)
+ endp = p + STRLEN(p); /* find end of part */
+ }
+ else if (endp > commap || endp == NULL)
+ endp = commap;
+ slashp = vim_strchr(p, '/');
+ if (slashp != NULL && slashp < endp)
+ {
+ /* "group/langmap_group" */
+ i = syn_check_group(p, (int)(slashp - p));
+ p = slashp + 1;
+ }
+ if (round == 2)
+ {
+ shape_table[idx].id = syn_check_group(p,
+ (int)(endp - p));
+ shape_table[idx].id_lm = shape_table[idx].id;
+ if (slashp != NULL && slashp < endp)
+ shape_table[idx].id = i;
+ }
+ p = endp;
+ }
+ } /* if (what != SHAPE_MOUSE) */
+
+ if (*p == '-')
+ ++p;
+ }
+ }
+ modep = p;
+ if (*modep == ',')
+ ++modep;
+ }
+ }
+
+ /* If the 's' flag is not given, use the 'v' cursor for 's' */
+ if (!found_ve)
+ {
+#ifdef FEAT_MOUSESHAPE
+ if (what == SHAPE_MOUSE)
+ {
+ shape_table[SHAPE_IDX_VE].mshape = shape_table[SHAPE_IDX_V].mshape;
+ }
+ else
+#endif
+ {
+ shape_table[SHAPE_IDX_VE].shape = shape_table[SHAPE_IDX_V].shape;
+ shape_table[SHAPE_IDX_VE].percentage =
+ shape_table[SHAPE_IDX_V].percentage;
+ shape_table[SHAPE_IDX_VE].blinkwait =
+ shape_table[SHAPE_IDX_V].blinkwait;
+ shape_table[SHAPE_IDX_VE].blinkon =
+ shape_table[SHAPE_IDX_V].blinkon;
+ shape_table[SHAPE_IDX_VE].blinkoff =
+ shape_table[SHAPE_IDX_V].blinkoff;
+ shape_table[SHAPE_IDX_VE].id = shape_table[SHAPE_IDX_V].id;
+ shape_table[SHAPE_IDX_VE].id_lm = shape_table[SHAPE_IDX_V].id_lm;
+ }
+ }
+
+ return NULL;
+}
+
+# if defined(MCH_CURSOR_SHAPE) || defined(FEAT_GUI) \
+ || defined(FEAT_MOUSESHAPE) || defined(PROTO)
+/*
+ * Return the index into shape_table[] for the current mode.
+ * When "mouse" is TRUE, consider indexes valid for the mouse pointer.
+ */
+ int
+get_shape_idx(int mouse)
+{
+#ifdef FEAT_MOUSESHAPE
+ if (mouse && (State == HITRETURN || State == ASKMORE))
+ {
+# ifdef FEAT_GUI
+ int x, y;
+ gui_mch_getmouse(&x, &y);
+ if (Y_2_ROW(y) == Rows - 1)
+ return SHAPE_IDX_MOREL;
+# endif
+ return SHAPE_IDX_MORE;
+ }
+ if (mouse && drag_status_line)
+ return SHAPE_IDX_SDRAG;
+ if (mouse && drag_sep_line)
+ return SHAPE_IDX_VDRAG;
+#endif
+ if (!mouse && State == SHOWMATCH)
+ return SHAPE_IDX_SM;
+ if (State & VREPLACE_FLAG)
+ return SHAPE_IDX_R;
+ if (State & REPLACE_FLAG)
+ return SHAPE_IDX_R;
+ if (State & INSERT)
+ return SHAPE_IDX_I;
+ if (State & CMDLINE)
+ {
+ if (cmdline_at_end())
+ return SHAPE_IDX_C;
+ if (cmdline_overstrike())
+ return SHAPE_IDX_CR;
+ return SHAPE_IDX_CI;
+ }
+ if (finish_op)
+ return SHAPE_IDX_O;
+ if (VIsual_active)
+ {
+ if (*p_sel == 'e')
+ return SHAPE_IDX_VE;
+ else
+ return SHAPE_IDX_V;
+ }
+ return SHAPE_IDX_N;
+}
+#endif
+
+# if defined(FEAT_MOUSESHAPE) || defined(PROTO)
+static int old_mouse_shape = 0;
+
+/*
+ * Set the mouse shape:
+ * If "shape" is -1, use shape depending on the current mode,
+ * depending on the current state.
+ * If "shape" is -2, only update the shape when it's CLINE or STATUS (used
+ * when the mouse moves off the status or command line).
+ */
+ void
+update_mouseshape(int shape_idx)
+{
+ int new_mouse_shape;
+
+ /* Only works in GUI mode. */
+ if (!gui.in_use || gui.starting)
+ return;
+
+ /* Postpone the updating when more is to come. Speeds up executing of
+ * mappings. */
+ if (shape_idx == -1 && char_avail())
+ {
+ postponed_mouseshape = TRUE;
+ return;
+ }
+
+ /* When ignoring the mouse don't change shape on the statusline. */
+ if (*p_mouse == NUL
+ && (shape_idx == SHAPE_IDX_CLINE
+ || shape_idx == SHAPE_IDX_STATUS
+ || shape_idx == SHAPE_IDX_VSEP))
+ shape_idx = -2;
+
+ if (shape_idx == -2
+ && old_mouse_shape != shape_table[SHAPE_IDX_CLINE].mshape
+ && old_mouse_shape != shape_table[SHAPE_IDX_STATUS].mshape
+ && old_mouse_shape != shape_table[SHAPE_IDX_VSEP].mshape)
+ return;
+ if (shape_idx < 0)
+ new_mouse_shape = shape_table[get_shape_idx(TRUE)].mshape;
+ else
+ new_mouse_shape = shape_table[shape_idx].mshape;
+ if (new_mouse_shape != old_mouse_shape)
+ {
+ mch_set_mouse_shape(new_mouse_shape);
+ old_mouse_shape = new_mouse_shape;
+ }
+ postponed_mouseshape = FALSE;
+}
+# endif
+
+#endif /* CURSOR_SHAPE */
+
+
+/* TODO: make some #ifdef for this */
+/*--------[ file searching ]-------------------------------------------------*/
+/*
+ * File searching functions for 'path', 'tags' and 'cdpath' options.
+ * External visible functions:
+ * vim_findfile_init() creates/initialises the search context
+ * vim_findfile_free_visited() free list of visited files/dirs of search
+ * context
+ * vim_findfile() find a file in the search context
+ * vim_findfile_cleanup() cleanup/free search context created by
+ * vim_findfile_init()
+ *
+ * All static functions and variables start with 'ff_'
+ *
+ * In general it works like this:
+ * First you create yourself a search context by calling vim_findfile_init().
+ * It is possible to give a search context from a previous call to
+ * vim_findfile_init(), so it can be reused. After this you call vim_findfile()
+ * until you are satisfied with the result or it returns NULL. On every call it
+ * returns the next file which matches the conditions given to
+ * vim_findfile_init(). If it doesn't find a next file it returns NULL.
+ *
+ * It is possible to call vim_findfile_init() again to reinitialise your search
+ * with some new parameters. Don't forget to pass your old search context to
+ * it, so it can reuse it and especially reuse the list of already visited
+ * directories. If you want to delete the list of already visited directories
+ * simply call vim_findfile_free_visited().
+ *
+ * When you are done call vim_findfile_cleanup() to free the search context.
+ *
+ * The function vim_findfile_init() has a long comment, which describes the
+ * needed parameters.
+ *
+ *
+ *
+ * ATTENTION:
+ * ==========
+ * Also we use an allocated search context here, this functions are NOT
+ * thread-safe!!!!!
+ *
+ * To minimize parameter passing (or because I'm to lazy), only the
+ * external visible functions get a search context as a parameter. This is
+ * then assigned to a static global, which is used throughout the local
+ * functions.
+ */
+
+/*
+ * type for the directory search stack
+ */
+typedef struct ff_stack
+{
+ struct ff_stack *ffs_prev;
+
+ /* the fix part (no wildcards) and the part containing the wildcards
+ * of the search path
+ */
+ char_u *ffs_fix_path;
+#ifdef FEAT_PATH_EXTRA
+ char_u *ffs_wc_path;
+#endif
+
+ /* files/dirs found in the above directory, matched by the first wildcard
+ * of wc_part
+ */
+ char_u **ffs_filearray;
+ int ffs_filearray_size;
+ char_u ffs_filearray_cur; /* needed for partly handled dirs */
+
+ /* to store status of partly handled directories
+ * 0: we work on this directory for the first time
+ * 1: this directory was partly searched in an earlier step
+ */
+ int ffs_stage;
+
+ /* How deep are we in the directory tree?
+ * Counts backward from value of level parameter to vim_findfile_init
+ */
+ int ffs_level;
+
+ /* Did we already expand '**' to an empty string? */
+ int ffs_star_star_empty;
+} ff_stack_T;
+
+/*
+ * type for already visited directories or files.
+ */
+typedef struct ff_visited
+{
+ struct ff_visited *ffv_next;
+
+#ifdef FEAT_PATH_EXTRA
+ /* Visited directories are different if the wildcard string are
+ * different. So we have to save it.
+ */
+ char_u *ffv_wc_path;
+#endif
+ /* for unix use inode etc for comparison (needed because of links), else
+ * use filename.
+ */
+#ifdef UNIX
+ int ffv_dev_valid; /* ffv_dev and ffv_ino were set */
+ dev_t ffv_dev; /* device number */
+ ino_t ffv_ino; /* inode number */
+#endif
+ /* The memory for this struct is allocated according to the length of
+ * ffv_fname.
+ */
+ char_u ffv_fname[1]; /* actually longer */
+} ff_visited_T;
+
+/*
+ * We might have to manage several visited lists during a search.
+ * This is especially needed for the tags option. If tags is set to:
+ * "./++/tags,./++/TAGS,++/tags" (replace + with *)
+ * So we have to do 3 searches:
+ * 1) search from the current files directory downward for the file "tags"
+ * 2) search from the current files directory downward for the file "TAGS"
+ * 3) search from Vims current directory downwards for the file "tags"
+ * As you can see, the first and the third search are for the same file, so for
+ * the third search we can use the visited list of the first search. For the
+ * second search we must start from a empty visited list.
+ * The struct ff_visited_list_hdr is used to manage a linked list of already
+ * visited lists.
+ */
+typedef struct ff_visited_list_hdr
+{
+ struct ff_visited_list_hdr *ffvl_next;
+
+ /* the filename the attached visited list is for */
+ char_u *ffvl_filename;
+
+ ff_visited_T *ffvl_visited_list;
+
+} ff_visited_list_hdr_T;
+
+
+/*
+ * '**' can be expanded to several directory levels.
+ * Set the default maximum depth.
+ */
+#define FF_MAX_STAR_STAR_EXPAND ((char_u)30)
+
+/*
+ * The search context:
+ * ffsc_stack_ptr: the stack for the dirs to search
+ * ffsc_visited_list: the currently active visited list
+ * ffsc_dir_visited_list: the currently active visited list for search dirs
+ * ffsc_visited_lists_list: the list of all visited lists
+ * ffsc_dir_visited_lists_list: the list of all visited lists for search dirs
+ * ffsc_file_to_search: the file to search for
+ * ffsc_start_dir: the starting directory, if search path was relative
+ * ffsc_fix_path: the fix part of the given path (without wildcards)
+ * Needed for upward search.
+ * ffsc_wc_path: the part of the given path containing wildcards
+ * ffsc_level: how many levels of dirs to search downwards
+ * ffsc_stopdirs_v: array of stop directories for upward search
+ * ffsc_find_what: FINDFILE_BOTH, FINDFILE_DIR or FINDFILE_FILE
+ * ffsc_tagfile: searching for tags file, don't use 'suffixesadd'
+ */
+typedef struct ff_search_ctx_T
+{
+ ff_stack_T *ffsc_stack_ptr;
+ ff_visited_list_hdr_T *ffsc_visited_list;
+ ff_visited_list_hdr_T *ffsc_dir_visited_list;
+ ff_visited_list_hdr_T *ffsc_visited_lists_list;
+ ff_visited_list_hdr_T *ffsc_dir_visited_lists_list;
+ char_u *ffsc_file_to_search;
+ char_u *ffsc_start_dir;
+ char_u *ffsc_fix_path;
+#ifdef FEAT_PATH_EXTRA
+ char_u *ffsc_wc_path;
+ int ffsc_level;
+ char_u **ffsc_stopdirs_v;
+#endif
+ int ffsc_find_what;
+ int ffsc_tagfile;
+} ff_search_ctx_T;
+
+/* locally needed functions */
+#ifdef FEAT_PATH_EXTRA
+static int ff_check_visited(ff_visited_T **, char_u *, char_u *);
+#else
+static int ff_check_visited(ff_visited_T **, char_u *);
+#endif
+static void vim_findfile_free_visited_list(ff_visited_list_hdr_T **list_headp);
+static void ff_free_visited_list(ff_visited_T *vl);
+static ff_visited_list_hdr_T* ff_get_visited_list(char_u *, ff_visited_list_hdr_T **list_headp);
+
+static void ff_push(ff_search_ctx_T *search_ctx, ff_stack_T *stack_ptr);
+static ff_stack_T *ff_pop(ff_search_ctx_T *search_ctx);
+static void ff_clear(ff_search_ctx_T *search_ctx);
+static void ff_free_stack_element(ff_stack_T *stack_ptr);
+#ifdef FEAT_PATH_EXTRA
+static ff_stack_T *ff_create_stack_element(char_u *, char_u *, int, int);
+#else
+static ff_stack_T *ff_create_stack_element(char_u *, int, int);
+#endif
+#ifdef FEAT_PATH_EXTRA
+static int ff_path_in_stoplist(char_u *, int, char_u **);
+#endif
+
+static char_u e_pathtoolong[] = N_("E854: path too long for completion");
+
+#if 0
+/*
+ * if someone likes findfirst/findnext, here are the functions
+ * NOT TESTED!!
+ */
+
+static void *ff_fn_search_context = NULL;
+
+ char_u *
+vim_findfirst(char_u *path, char_u *filename, int level)
+{
+ ff_fn_search_context =
+ vim_findfile_init(path, filename, NULL, level, TRUE, FALSE,
+ ff_fn_search_context, rel_fname);
+ if (NULL == ff_fn_search_context)
+ return NULL;
+ else
+ return vim_findnext()
+}
+
+ char_u *
+vim_findnext(void)
+{
+ char_u *ret = vim_findfile(ff_fn_search_context);
+
+ if (NULL == ret)
+ {
+ vim_findfile_cleanup(ff_fn_search_context);
+ ff_fn_search_context = NULL;
+ }
+ return ret;
+}
+#endif
+
+/*
+ * Initialization routine for vim_findfile().
+ *
+ * Returns the newly allocated search context or NULL if an error occurred.
+ *
+ * Don't forget to clean up by calling vim_findfile_cleanup() if you are done
+ * with the search context.
+ *
+ * Find the file 'filename' in the directory 'path'.
+ * The parameter 'path' may contain wildcards. If so only search 'level'
+ * directories deep. The parameter 'level' is the absolute maximum and is
+ * not related to restricts given to the '**' wildcard. If 'level' is 100
+ * and you use '**200' vim_findfile() will stop after 100 levels.
+ *
+ * 'filename' cannot contain wildcards! It is used as-is, no backslashes to
+ * escape special characters.
+ *
+ * If 'stopdirs' is not NULL and nothing is found downward, the search is
+ * restarted on the next higher directory level. This is repeated until the
+ * start-directory of a search is contained in 'stopdirs'. 'stopdirs' has the
+ * format ";*<dirname>*\(;<dirname>\)*;\=$".
+ *
+ * If the 'path' is relative, the starting dir for the search is either VIM's
+ * current dir or if the path starts with "./" the current files dir.
+ * If the 'path' is absolute, the starting dir is that part of the path before
+ * the first wildcard.
+ *
+ * Upward search is only done on the starting dir.
+ *
+ * If 'free_visited' is TRUE the list of already visited files/directories is
+ * cleared. Set this to FALSE if you just want to search from another
+ * directory, but want to be sure that no directory from a previous search is
+ * searched again. This is useful if you search for a file at different places.
+ * The list of visited files/dirs can also be cleared with the function
+ * vim_findfile_free_visited().
+ *
+ * Set the parameter 'find_what' to FINDFILE_DIR if you want to search for
+ * directories only, FINDFILE_FILE for files only, FINDFILE_BOTH for both.
+ *
+ * A search context returned by a previous call to vim_findfile_init() can be
+ * passed in the parameter "search_ctx_arg". This context is reused and
+ * reinitialized with the new parameters. The list of already visited
+ * directories from this context is only deleted if the parameter
+ * "free_visited" is true. Be aware that the passed "search_ctx_arg" is freed
+ * if the reinitialization fails.
+ *
+ * If you don't have a search context from a previous call "search_ctx_arg"
+ * must be NULL.
+ *
+ * This function silently ignores a few errors, vim_findfile() will have
+ * limited functionality then.
+ */
+ void *
+vim_findfile_init(
+ char_u *path,
+ char_u *filename,
+ char_u *stopdirs UNUSED,
+ int level,
+ int free_visited,
+ int find_what,
+ void *search_ctx_arg,
+ int tagfile, /* expanding names of tags files */
+ char_u *rel_fname) /* file name to use for "." */
+{
+#ifdef FEAT_PATH_EXTRA
+ char_u *wc_part;
+#endif
+ ff_stack_T *sptr;
+ ff_search_ctx_T *search_ctx;
+
+ /* If a search context is given by the caller, reuse it, else allocate a
+ * new one.
+ */
+ if (search_ctx_arg != NULL)
+ search_ctx = search_ctx_arg;
+ else
+ {
+ search_ctx = (ff_search_ctx_T*)alloc((unsigned)sizeof(ff_search_ctx_T));
+ if (search_ctx == NULL)
+ goto error_return;
+ vim_memset(search_ctx, 0, sizeof(ff_search_ctx_T));
+ }
+ search_ctx->ffsc_find_what = find_what;
+ search_ctx->ffsc_tagfile = tagfile;
+
+ /* clear the search context, but NOT the visited lists */
+ ff_clear(search_ctx);
+
+ /* clear visited list if wanted */
+ if (free_visited == TRUE)
+ vim_findfile_free_visited(search_ctx);
+ else
+ {
+ /* Reuse old visited lists. Get the visited list for the given
+ * filename. If no list for the current filename exists, creates a new
+ * one. */
+ search_ctx->ffsc_visited_list = ff_get_visited_list(filename,
+ &search_ctx->ffsc_visited_lists_list);
+ if (search_ctx->ffsc_visited_list == NULL)
+ goto error_return;
+ search_ctx->ffsc_dir_visited_list = ff_get_visited_list(filename,
+ &search_ctx->ffsc_dir_visited_lists_list);
+ if (search_ctx->ffsc_dir_visited_list == NULL)
+ goto error_return;
+ }
+
+ if (ff_expand_buffer == NULL)
+ {
+ ff_expand_buffer = (char_u*)alloc(MAXPATHL);
+ if (ff_expand_buffer == NULL)
+ goto error_return;
+ }
+
+ /* Store information on starting dir now if path is relative.
+ * If path is absolute, we do that later. */
+ if (path[0] == '.'
+ && (vim_ispathsep(path[1]) || path[1] == NUL)
+ && (!tagfile || vim_strchr(p_cpo, CPO_DOTTAG) == NULL)
+ && rel_fname != NULL)
+ {
+ int len = (int)(gettail(rel_fname) - rel_fname);
+
+ if (!vim_isAbsName(rel_fname) && len + 1 < MAXPATHL)
+ {
+ /* Make the start dir an absolute path name. */
+ vim_strncpy(ff_expand_buffer, rel_fname, len);
+ search_ctx->ffsc_start_dir = FullName_save(ff_expand_buffer, FALSE);
+ }
+ else
+ search_ctx->ffsc_start_dir = vim_strnsave(rel_fname, len);
+ if (search_ctx->ffsc_start_dir == NULL)
+ goto error_return;
+ if (*++path != NUL)
+ ++path;
+ }
+ else if (*path == NUL || !vim_isAbsName(path))
+ {
+#ifdef BACKSLASH_IN_FILENAME
+ /* "c:dir" needs "c:" to be expanded, otherwise use current dir */
+ if (*path != NUL && path[1] == ':')
+ {
+ char_u drive[3];
+
+ drive[0] = path[0];
+ drive[1] = ':';
+ drive[2] = NUL;
+ if (vim_FullName(drive, ff_expand_buffer, MAXPATHL, TRUE) == FAIL)
+ goto error_return;
+ path += 2;
+ }
+ else
+#endif
+ if (mch_dirname(ff_expand_buffer, MAXPATHL) == FAIL)
+ goto error_return;
+
+ search_ctx->ffsc_start_dir = vim_strsave(ff_expand_buffer);
+ if (search_ctx->ffsc_start_dir == NULL)
+ goto error_return;
+
+#ifdef BACKSLASH_IN_FILENAME
+ /* A path that starts with "/dir" is relative to the drive, not to the
+ * directory (but not for "//machine/dir"). Only use the drive name. */
+ if ((*path == '/' || *path == '\\')
+ && path[1] != path[0]
+ && search_ctx->ffsc_start_dir[1] == ':')
+ search_ctx->ffsc_start_dir[2] = NUL;
+#endif
+ }
+
+#ifdef FEAT_PATH_EXTRA
+ /*
+ * If stopdirs are given, split them into an array of pointers.
+ * If this fails (mem allocation), there is no upward search at all or a
+ * stop directory is not recognized -> continue silently.
+ * If stopdirs just contains a ";" or is empty,
+ * search_ctx->ffsc_stopdirs_v will only contain a NULL pointer. This
+ * is handled as unlimited upward search. See function
+ * ff_path_in_stoplist() for details.
+ */
+ if (stopdirs != NULL)
+ {
+ char_u *walker = stopdirs;
+ int dircount;
+
+ while (*walker == ';')
+ walker++;
+
+ dircount = 1;
+ search_ctx->ffsc_stopdirs_v =
+ (char_u **)alloc((unsigned)sizeof(char_u *));
+
+ if (search_ctx->ffsc_stopdirs_v != NULL)
+ {
+ do
+ {
+ char_u *helper;
+ void *ptr;
+
+ helper = walker;
+ ptr = vim_realloc(search_ctx->ffsc_stopdirs_v,
+ (dircount + 1) * sizeof(char_u *));
+ if (ptr)
+ search_ctx->ffsc_stopdirs_v = ptr;
+ else
+ /* ignore, keep what we have and continue */
+ break;
+ walker = vim_strchr(walker, ';');
+ if (walker)
+ {
+ search_ctx->ffsc_stopdirs_v[dircount-1] =
+ vim_strnsave(helper, (int)(walker - helper));
+ walker++;
+ }
+ else
+ /* this might be "", which means ascent till top
+ * of directory tree.
+ */
+ search_ctx->ffsc_stopdirs_v[dircount-1] =
+ vim_strsave(helper);
+
+ dircount++;
+
+ } while (walker != NULL);
+ search_ctx->ffsc_stopdirs_v[dircount-1] = NULL;
+ }
+ }
+#endif
+
+#ifdef FEAT_PATH_EXTRA
+ search_ctx->ffsc_level = level;
+
+ /* split into:
+ * -fix path
+ * -wildcard_stuff (might be NULL)
+ */
+ wc_part = vim_strchr(path, '*');
+ if (wc_part != NULL)
+ {
+ int llevel;
+ int len;
+ char *errpt;
+
+ /* save the fix part of the path */
+ search_ctx->ffsc_fix_path = vim_strnsave(path, (int)(wc_part - path));
+
+ /*
+ * copy wc_path and add restricts to the '**' wildcard.
+ * The octet after a '**' is used as a (binary) counter.
+ * So '**3' is transposed to '**^C' ('^C' is ASCII value 3)
+ * or '**76' is transposed to '**N'( 'N' is ASCII value 76).
+ * For EBCDIC you get different character values.
+ * If no restrict is given after '**' the default is used.
+ * Due to this technique the path looks awful if you print it as a
+ * string.
+ */
+ len = 0;
+ while (*wc_part != NUL)
+ {
+ if (len + 5 >= MAXPATHL)
+ {
+ emsg(_(e_pathtoolong));
+ break;
+ }
+ if (STRNCMP(wc_part, "**", 2) == 0)
+ {
+ ff_expand_buffer[len++] = *wc_part++;
+ ff_expand_buffer[len++] = *wc_part++;
+
+ llevel = strtol((char *)wc_part, &errpt, 10);
+ if ((char_u *)errpt != wc_part && llevel > 0 && llevel < 255)
+ ff_expand_buffer[len++] = llevel;
+ else if ((char_u *)errpt != wc_part && llevel == 0)
+ /* restrict is 0 -> remove already added '**' */
+ len -= 2;
+ else
+ ff_expand_buffer[len++] = FF_MAX_STAR_STAR_EXPAND;
+ wc_part = (char_u *)errpt;
+ if (*wc_part != NUL && !vim_ispathsep(*wc_part))
+ {
+ semsg(_("E343: Invalid path: '**[number]' must be at the end of the path or be followed by '%s'."), PATHSEPSTR);
+ goto error_return;
+ }
+ }
+ else
+ ff_expand_buffer[len++] = *wc_part++;
+ }
+ ff_expand_buffer[len] = NUL;
+ search_ctx->ffsc_wc_path = vim_strsave(ff_expand_buffer);
+
+ if (search_ctx->ffsc_wc_path == NULL)
+ goto error_return;
+ }
+ else
+#endif
+ search_ctx->ffsc_fix_path = vim_strsave(path);
+
+ if (search_ctx->ffsc_start_dir == NULL)
+ {
+ /* store the fix part as startdir.
+ * This is needed if the parameter path is fully qualified.
+ */
+ search_ctx->ffsc_start_dir = vim_strsave(search_ctx->ffsc_fix_path);
+ if (search_ctx->ffsc_start_dir == NULL)
+ goto error_return;
+ search_ctx->ffsc_fix_path[0] = NUL;
+ }
+
+ /* create an absolute path */
+ if (STRLEN(search_ctx->ffsc_start_dir)
+ + STRLEN(search_ctx->ffsc_fix_path) + 3 >= MAXPATHL)
+ {
+ emsg(_(e_pathtoolong));
+ goto error_return;
+ }
+ STRCPY(ff_expand_buffer, search_ctx->ffsc_start_dir);
+ add_pathsep(ff_expand_buffer);
+ {
+ int eb_len = (int)STRLEN(ff_expand_buffer);
+ char_u *buf = alloc(eb_len
+ + (int)STRLEN(search_ctx->ffsc_fix_path) + 1);
+
+ STRCPY(buf, ff_expand_buffer);
+ STRCPY(buf + eb_len, search_ctx->ffsc_fix_path);
+ if (mch_isdir(buf))
+ {
+ STRCAT(ff_expand_buffer, search_ctx->ffsc_fix_path);
+ add_pathsep(ff_expand_buffer);
+ }
+#ifdef FEAT_PATH_EXTRA
+ else
+ {
+ char_u *p = gettail(search_ctx->ffsc_fix_path);
+ char_u *wc_path = NULL;
+ char_u *temp = NULL;
+ int len = 0;
+
+ if (p > search_ctx->ffsc_fix_path)
+ {
+ len = (int)(p - search_ctx->ffsc_fix_path) - 1;
+ STRNCAT(ff_expand_buffer, search_ctx->ffsc_fix_path, len);
+ add_pathsep(ff_expand_buffer);
+ }
+ else
+ len = (int)STRLEN(search_ctx->ffsc_fix_path);
+
+ if (search_ctx->ffsc_wc_path != NULL)
+ {
+ wc_path = vim_strsave(search_ctx->ffsc_wc_path);
+ temp = alloc((int)(STRLEN(search_ctx->ffsc_wc_path)
+ + STRLEN(search_ctx->ffsc_fix_path + len)
+ + 1));
+ if (temp == NULL || wc_path == NULL)
+ {
+ vim_free(buf);
+ vim_free(temp);
+ vim_free(wc_path);
+ goto error_return;
+ }
+
+ STRCPY(temp, search_ctx->ffsc_fix_path + len);
+ STRCAT(temp, search_ctx->ffsc_wc_path);
+ vim_free(search_ctx->ffsc_wc_path);
+ vim_free(wc_path);
+ search_ctx->ffsc_wc_path = temp;
+ }
+ }
+#endif
+ vim_free(buf);
+ }
+
+ sptr = ff_create_stack_element(ff_expand_buffer,
+#ifdef FEAT_PATH_EXTRA
+ search_ctx->ffsc_wc_path,
+#endif
+ level, 0);
+
+ if (sptr == NULL)
+ goto error_return;
+
+ ff_push(search_ctx, sptr);
+
+ search_ctx->ffsc_file_to_search = vim_strsave(filename);
+ if (search_ctx->ffsc_file_to_search == NULL)
+ goto error_return;
+
+ return search_ctx;
+
+error_return:
+ /*
+ * We clear the search context now!
+ * Even when the caller gave us a (perhaps valid) context we free it here,
+ * as we might have already destroyed it.
+ */
+ vim_findfile_cleanup(search_ctx);
+ return NULL;
+}
+
+#if defined(FEAT_PATH_EXTRA) || defined(PROTO)
+/*
+ * Get the stopdir string. Check that ';' is not escaped.
+ */
+ char_u *
+vim_findfile_stopdir(char_u *buf)
+{
+ char_u *r_ptr = buf;
+
+ while (*r_ptr != NUL && *r_ptr != ';')
+ {
+ if (r_ptr[0] == '\\' && r_ptr[1] == ';')
+ {
+ /* Overwrite the escape char,
+ * use STRLEN(r_ptr) to move the trailing '\0'. */
+ STRMOVE(r_ptr, r_ptr + 1);
+ r_ptr++;
+ }
+ r_ptr++;
+ }
+ if (*r_ptr == ';')
+ {
+ *r_ptr = 0;
+ r_ptr++;
+ }
+ else if (*r_ptr == NUL)
+ r_ptr = NULL;
+ return r_ptr;
+}
+#endif
+
+/*
+ * Clean up the given search context. Can handle a NULL pointer.
+ */
+ void
+vim_findfile_cleanup(void *ctx)
+{
+ if (ctx == NULL)
+ return;
+
+ vim_findfile_free_visited(ctx);
+ ff_clear(ctx);
+ vim_free(ctx);
+}
+
+/*
+ * Find a file in a search context.
+ * The search context was created with vim_findfile_init() above.
+ * Return a pointer to an allocated file name or NULL if nothing found.
+ * To get all matching files call this function until you get NULL.
+ *
+ * If the passed search_context is NULL, NULL is returned.
+ *
+ * The search algorithm is depth first. To change this replace the
+ * stack with a list (don't forget to leave partly searched directories on the
+ * top of the list).
+ */
+ char_u *
+vim_findfile(void *search_ctx_arg)
+{
+ char_u *file_path;
+#ifdef FEAT_PATH_EXTRA
+ char_u *rest_of_wildcards;
+ char_u *path_end = NULL;
+#endif
+ ff_stack_T *stackp;
+#if defined(FEAT_SEARCHPATH) || defined(FEAT_PATH_EXTRA)
+ int len;
+#endif
+ int i;
+ char_u *p;
+#ifdef FEAT_SEARCHPATH
+ char_u *suf;
+#endif
+ ff_search_ctx_T *search_ctx;
+
+ if (search_ctx_arg == NULL)
+ return NULL;
+
+ search_ctx = (ff_search_ctx_T *)search_ctx_arg;
+
+ /*
+ * filepath is used as buffer for various actions and as the storage to
+ * return a found filename.
+ */
+ if ((file_path = alloc((int)MAXPATHL)) == NULL)
+ return NULL;
+
+#ifdef FEAT_PATH_EXTRA
+ /* store the end of the start dir -- needed for upward search */
+ if (search_ctx->ffsc_start_dir != NULL)
+ path_end = &search_ctx->ffsc_start_dir[
+ STRLEN(search_ctx->ffsc_start_dir)];
+#endif
+
+#ifdef FEAT_PATH_EXTRA
+ /* upward search loop */
+ for (;;)
+ {
+#endif
+ /* downward search loop */
+ for (;;)
+ {
+ /* check if user user wants to stop the search*/
+ ui_breakcheck();
+ if (got_int)
+ break;
+
+ /* get directory to work on from stack */
+ stackp = ff_pop(search_ctx);
+ if (stackp == NULL)
+ break;
+
+ /*
+ * TODO: decide if we leave this test in
+ *
+ * GOOD: don't search a directory(-tree) twice.
+ * BAD: - check linked list for every new directory entered.
+ * - check for double files also done below
+ *
+ * Here we check if we already searched this directory.
+ * We already searched a directory if:
+ * 1) The directory is the same.
+ * 2) We would use the same wildcard string.
+ *
+ * Good if you have links on same directory via several ways
+ * or you have selfreferences in directories (e.g. SuSE Linux 6.3:
+ * /etc/rc.d/init.d is linked to /etc/rc.d -> endless loop)
+ *
+ * This check is only needed for directories we work on for the
+ * first time (hence stackp->ff_filearray == NULL)
+ */
+ if (stackp->ffs_filearray == NULL
+ && ff_check_visited(&search_ctx->ffsc_dir_visited_list
+ ->ffvl_visited_list,
+ stackp->ffs_fix_path
+#ifdef FEAT_PATH_EXTRA
+ , stackp->ffs_wc_path
+#endif
+ ) == FAIL)
+ {
+#ifdef FF_VERBOSE
+ if (p_verbose >= 5)
+ {
+ verbose_enter_scroll();
+ smsg("Already Searched: %s (%s)",
+ stackp->ffs_fix_path, stackp->ffs_wc_path);
+ /* don't overwrite this either */
+ msg_puts("\n");
+ verbose_leave_scroll();
+ }
+#endif
+ ff_free_stack_element(stackp);
+ continue;
+ }
+#ifdef FF_VERBOSE
+ else if (p_verbose >= 5)
+ {
+ verbose_enter_scroll();
+ smsg("Searching: %s (%s)",
+ stackp->ffs_fix_path, stackp->ffs_wc_path);
+ /* don't overwrite this either */
+ msg_puts("\n");
+ verbose_leave_scroll();
+ }
+#endif
+
+ /* check depth */
+ if (stackp->ffs_level <= 0)
+ {
+ ff_free_stack_element(stackp);
+ continue;
+ }
+
+ file_path[0] = NUL;
+
+ /*
+ * If no filearray till now expand wildcards
+ * The function expand_wildcards() can handle an array of paths
+ * and all possible expands are returned in one array. We use this
+ * to handle the expansion of '**' into an empty string.
+ */
+ if (stackp->ffs_filearray == NULL)
+ {
+ char_u *dirptrs[2];
+
+ /* we use filepath to build the path expand_wildcards() should
+ * expand.
+ */
+ dirptrs[0] = file_path;
+ dirptrs[1] = NULL;
+
+ /* if we have a start dir copy it in */
+ if (!vim_isAbsName(stackp->ffs_fix_path)
+ && search_ctx->ffsc_start_dir)
+ {
+ if (STRLEN(search_ctx->ffsc_start_dir) + 1 < MAXPATHL)
+ {
+ STRCPY(file_path, search_ctx->ffsc_start_dir);
+ add_pathsep(file_path);
+ }
+ else
+ {
+ ff_free_stack_element(stackp);
+ goto fail;
+ }
+ }
+
+ /* append the fix part of the search path */
+ if (STRLEN(file_path) + STRLEN(stackp->ffs_fix_path) + 1 < MAXPATHL)
+ {
+ STRCAT(file_path, stackp->ffs_fix_path);
+ add_pathsep(file_path);
+ }
+ else
+ {
+ ff_free_stack_element(stackp);
+ goto fail;
+ }
+
+#ifdef FEAT_PATH_EXTRA
+ rest_of_wildcards = stackp->ffs_wc_path;
+ if (*rest_of_wildcards != NUL)
+ {
+ len = (int)STRLEN(file_path);
+ if (STRNCMP(rest_of_wildcards, "**", 2) == 0)
+ {
+ /* pointer to the restrict byte
+ * The restrict byte is not a character!
+ */
+ p = rest_of_wildcards + 2;
+
+ if (*p > 0)
+ {
+ (*p)--;
+ if (len + 1 < MAXPATHL)
+ file_path[len++] = '*';
+ else
+ {
+ ff_free_stack_element(stackp);
+ goto fail;
+ }
+ }
+
+ if (*p == 0)
+ {
+ /* remove '**<numb> from wildcards */
+ STRMOVE(rest_of_wildcards, rest_of_wildcards + 3);
+ }
+ else
+ rest_of_wildcards += 3;
+
+ if (stackp->ffs_star_star_empty == 0)
+ {
+ /* if not done before, expand '**' to empty */
+ stackp->ffs_star_star_empty = 1;
+ dirptrs[1] = stackp->ffs_fix_path;
+ }
+ }
+
+ /*
+ * Here we copy until the next path separator or the end of
+ * the path. If we stop at a path separator, there is
+ * still something else left. This is handled below by
+ * pushing every directory returned from expand_wildcards()
+ * on the stack again for further search.
+ */
+ while (*rest_of_wildcards
+ && !vim_ispathsep(*rest_of_wildcards))
+ if (len + 1 < MAXPATHL)
+ file_path[len++] = *rest_of_wildcards++;
+ else
+ {
+ ff_free_stack_element(stackp);
+ goto fail;
+ }
+
+ file_path[len] = NUL;
+ if (vim_ispathsep(*rest_of_wildcards))
+ rest_of_wildcards++;
+ }
+#endif
+
+ /*
+ * Expand wildcards like "*" and "$VAR".
+ * If the path is a URL don't try this.
+ */
+ if (path_with_url(dirptrs[0]))
+ {
+ stackp->ffs_filearray = (char_u **)
+ alloc((unsigned)sizeof(char *));
+ if (stackp->ffs_filearray != NULL
+ && (stackp->ffs_filearray[0]
+ = vim_strsave(dirptrs[0])) != NULL)
+ stackp->ffs_filearray_size = 1;
+ else
+ stackp->ffs_filearray_size = 0;
+ }
+ else
+ /* Add EW_NOTWILD because the expanded path may contain
+ * wildcard characters that are to be taken literally.
+ * This is a bit of a hack. */
+ expand_wildcards((dirptrs[1] == NULL) ? 1 : 2, dirptrs,
+ &stackp->ffs_filearray_size,
+ &stackp->ffs_filearray,
+ EW_DIR|EW_ADDSLASH|EW_SILENT|EW_NOTWILD);
+
+ stackp->ffs_filearray_cur = 0;
+ stackp->ffs_stage = 0;
+ }
+#ifdef FEAT_PATH_EXTRA
+ else
+ rest_of_wildcards = &stackp->ffs_wc_path[
+ STRLEN(stackp->ffs_wc_path)];
+#endif
+
+ if (stackp->ffs_stage == 0)
+ {
+ /* this is the first time we work on this directory */
+#ifdef FEAT_PATH_EXTRA
+ if (*rest_of_wildcards == NUL)
+#endif
+ {
+ /*
+ * We don't have further wildcards to expand, so we have to
+ * check for the final file now.
+ */
+ for (i = stackp->ffs_filearray_cur;
+ i < stackp->ffs_filearray_size; ++i)
+ {
+ if (!path_with_url(stackp->ffs_filearray[i])
+ && !mch_isdir(stackp->ffs_filearray[i]))
+ continue; /* not a directory */
+
+ /* prepare the filename to be checked for existence
+ * below */
+ if (STRLEN(stackp->ffs_filearray[i]) + 1
+ + STRLEN(search_ctx->ffsc_file_to_search) < MAXPATHL)
+ {
+ STRCPY(file_path, stackp->ffs_filearray[i]);
+ add_pathsep(file_path);
+ STRCAT(file_path, search_ctx->ffsc_file_to_search);
+ }
+ else
+ {
+ ff_free_stack_element(stackp);
+ goto fail;
+ }
+
+ /*
+ * Try without extra suffix and then with suffixes
+ * from 'suffixesadd'.
+ */
+#ifdef FEAT_SEARCHPATH
+ len = (int)STRLEN(file_path);
+ if (search_ctx->ffsc_tagfile)
+ suf = (char_u *)"";
+ else
+ suf = curbuf->b_p_sua;
+ for (;;)
+#endif
+ {
+ /* if file exists and we didn't already find it */
+ if ((path_with_url(file_path)
+ || (mch_getperm(file_path) >= 0
+ && (search_ctx->ffsc_find_what
+ == FINDFILE_BOTH
+ || ((search_ctx->ffsc_find_what
+ == FINDFILE_DIR)
+ == mch_isdir(file_path)))))
+#ifndef FF_VERBOSE
+ && (ff_check_visited(
+ &search_ctx->ffsc_visited_list->ffvl_visited_list,
+ file_path
+#ifdef FEAT_PATH_EXTRA
+ , (char_u *)""
+#endif
+ ) == OK)
+#endif
+ )
+ {
+#ifdef FF_VERBOSE
+ if (ff_check_visited(
+ &search_ctx->ffsc_visited_list->ffvl_visited_list,
+ file_path
+#ifdef FEAT_PATH_EXTRA
+ , (char_u *)""
+#endif
+ ) == FAIL)
+ {
+ if (p_verbose >= 5)
+ {
+ verbose_enter_scroll();
+ smsg("Already: %s",
+ file_path);
+ /* don't overwrite this either */
+ msg_puts("\n");
+ verbose_leave_scroll();
+ }
+ continue;
+ }
+#endif
+
+ /* push dir to examine rest of subdirs later */
+ stackp->ffs_filearray_cur = i + 1;
+ ff_push(search_ctx, stackp);
+
+ if (!path_with_url(file_path))
+ simplify_filename(file_path);
+ if (mch_dirname(ff_expand_buffer, MAXPATHL)
+ == OK)
+ {
+ p = shorten_fname(file_path,
+ ff_expand_buffer);
+ if (p != NULL)
+ STRMOVE(file_path, p);
+ }
+#ifdef FF_VERBOSE
+ if (p_verbose >= 5)
+ {
+ verbose_enter_scroll();
+ smsg("HIT: %s", file_path);
+ /* don't overwrite this either */
+ msg_puts("\n");
+ verbose_leave_scroll();
+ }
+#endif
+ return file_path;
+ }
+
+#ifdef FEAT_SEARCHPATH
+ /* Not found or found already, try next suffix. */
+ if (*suf == NUL)
+ break;
+ copy_option_part(&suf, file_path + len,
+ MAXPATHL - len, ",");
+#endif
+ }
+ }
+ }
+#ifdef FEAT_PATH_EXTRA
+ else
+ {
+ /*
+ * still wildcards left, push the directories for further
+ * search
+ */
+ for (i = stackp->ffs_filearray_cur;
+ i < stackp->ffs_filearray_size; ++i)
+ {
+ if (!mch_isdir(stackp->ffs_filearray[i]))
+ continue; /* not a directory */
+
+ ff_push(search_ctx,
+ ff_create_stack_element(
+ stackp->ffs_filearray[i],
+ rest_of_wildcards,
+ stackp->ffs_level - 1, 0));
+ }
+ }
+#endif
+ stackp->ffs_filearray_cur = 0;
+ stackp->ffs_stage = 1;
+ }
+
+#ifdef FEAT_PATH_EXTRA
+ /*
+ * if wildcards contains '**' we have to descent till we reach the
+ * leaves of the directory tree.
+ */
+ if (STRNCMP(stackp->ffs_wc_path, "**", 2) == 0)
+ {
+ for (i = stackp->ffs_filearray_cur;
+ i < stackp->ffs_filearray_size; ++i)
+ {
+ if (fnamecmp(stackp->ffs_filearray[i],
+ stackp->ffs_fix_path) == 0)
+ continue; /* don't repush same directory */
+ if (!mch_isdir(stackp->ffs_filearray[i]))
+ continue; /* not a directory */
+ ff_push(search_ctx,
+ ff_create_stack_element(stackp->ffs_filearray[i],
+ stackp->ffs_wc_path, stackp->ffs_level - 1, 1));
+ }
+ }
+#endif
+
+ /* we are done with the current directory */
+ ff_free_stack_element(stackp);
+
+ }
+
+#ifdef FEAT_PATH_EXTRA
+ /* If we reached this, we didn't find anything downwards.
+ * Let's check if we should do an upward search.
+ */
+ if (search_ctx->ffsc_start_dir
+ && search_ctx->ffsc_stopdirs_v != NULL && !got_int)
+ {
+ ff_stack_T *sptr;
+
+ /* is the last starting directory in the stop list? */
+ if (ff_path_in_stoplist(search_ctx->ffsc_start_dir,
+ (int)(path_end - search_ctx->ffsc_start_dir),
+ search_ctx->ffsc_stopdirs_v) == TRUE)
+ break;
+
+ /* cut of last dir */
+ while (path_end > search_ctx->ffsc_start_dir
+ && vim_ispathsep(*path_end))
+ path_end--;
+ while (path_end > search_ctx->ffsc_start_dir
+ && !vim_ispathsep(path_end[-1]))
+ path_end--;
+ *path_end = 0;
+ path_end--;
+
+ if (*search_ctx->ffsc_start_dir == 0)
+ break;
+
+ if (STRLEN(search_ctx->ffsc_start_dir) + 1
+ + STRLEN(search_ctx->ffsc_fix_path) < MAXPATHL)
+ {
+ STRCPY(file_path, search_ctx->ffsc_start_dir);
+ add_pathsep(file_path);
+ STRCAT(file_path, search_ctx->ffsc_fix_path);
+ }
+ else
+ goto fail;
+
+ /* create a new stack entry */
+ sptr = ff_create_stack_element(file_path,
+ search_ctx->ffsc_wc_path, search_ctx->ffsc_level, 0);
+ if (sptr == NULL)
+ break;
+ ff_push(search_ctx, sptr);
+ }
+ else
+ break;
+ }
+#endif
+
+fail:
+ vim_free(file_path);
+ return NULL;
+}
+
+/*
+ * Free the list of lists of visited files and directories
+ * Can handle it if the passed search_context is NULL;
+ */
+ void
+vim_findfile_free_visited(void *search_ctx_arg)
+{
+ ff_search_ctx_T *search_ctx;
+
+ if (search_ctx_arg == NULL)
+ return;
+
+ search_ctx = (ff_search_ctx_T *)search_ctx_arg;
+ vim_findfile_free_visited_list(&search_ctx->ffsc_visited_lists_list);
+ vim_findfile_free_visited_list(&search_ctx->ffsc_dir_visited_lists_list);
+}
+
+ static void
+vim_findfile_free_visited_list(ff_visited_list_hdr_T **list_headp)
+{
+ ff_visited_list_hdr_T *vp;
+
+ while (*list_headp != NULL)
+ {
+ vp = (*list_headp)->ffvl_next;
+ ff_free_visited_list((*list_headp)->ffvl_visited_list);
+
+ vim_free((*list_headp)->ffvl_filename);
+ vim_free(*list_headp);
+ *list_headp = vp;
+ }
+ *list_headp = NULL;
+}
+
+ static void
+ff_free_visited_list(ff_visited_T *vl)
+{
+ ff_visited_T *vp;
+
+ while (vl != NULL)
+ {
+ vp = vl->ffv_next;
+#ifdef FEAT_PATH_EXTRA
+ vim_free(vl->ffv_wc_path);
+#endif
+ vim_free(vl);
+ vl = vp;
+ }
+ vl = NULL;
+}
+
+/*
+ * Returns the already visited list for the given filename. If none is found it
+ * allocates a new one.
+ */
+ static ff_visited_list_hdr_T*
+ff_get_visited_list(
+ char_u *filename,
+ ff_visited_list_hdr_T **list_headp)
+{
+ ff_visited_list_hdr_T *retptr = NULL;
+
+ /* check if a visited list for the given filename exists */
+ if (*list_headp != NULL)
+ {
+ retptr = *list_headp;
+ while (retptr != NULL)
+ {
+ if (fnamecmp(filename, retptr->ffvl_filename) == 0)
+ {
+#ifdef FF_VERBOSE
+ if (p_verbose >= 5)
+ {
+ verbose_enter_scroll();
+ smsg("ff_get_visited_list: FOUND list for %s",
+ filename);
+ /* don't overwrite this either */
+ msg_puts("\n");
+ verbose_leave_scroll();
+ }
+#endif
+ return retptr;
+ }
+ retptr = retptr->ffvl_next;
+ }
+ }
+
+#ifdef FF_VERBOSE
+ if (p_verbose >= 5)
+ {
+ verbose_enter_scroll();
+ smsg("ff_get_visited_list: new list for %s", filename);
+ /* don't overwrite this either */
+ msg_puts("\n");
+ verbose_leave_scroll();
+ }
+#endif
+
+ /*
+ * if we reach this we didn't find a list and we have to allocate new list
+ */
+ retptr = (ff_visited_list_hdr_T*)alloc((unsigned)sizeof(*retptr));
+ if (retptr == NULL)
+ return NULL;
+
+ retptr->ffvl_visited_list = NULL;
+ retptr->ffvl_filename = vim_strsave(filename);
+ if (retptr->ffvl_filename == NULL)
+ {
+ vim_free(retptr);
+ return NULL;
+ }
+ retptr->ffvl_next = *list_headp;
+ *list_headp = retptr;
+
+ return retptr;
+}
+
+#ifdef FEAT_PATH_EXTRA
+/*
+ * check if two wildcard paths are equal. Returns TRUE or FALSE.
+ * They are equal if:
+ * - both paths are NULL
+ * - they have the same length
+ * - char by char comparison is OK
+ * - the only differences are in the counters behind a '**', so
+ * '**\20' is equal to '**\24'
+ */
+ static int
+ff_wc_equal(char_u *s1, char_u *s2)
+{
+ int i, j;
+ int c1 = NUL;
+ int c2 = NUL;
+ int prev1 = NUL;
+ int prev2 = NUL;
+
+ if (s1 == s2)
+ return TRUE;
+
+ if (s1 == NULL || s2 == NULL)
+ return FALSE;
+
+ for (i = 0, j = 0; s1[i] != NUL && s2[j] != NUL;)
+ {
+ c1 = PTR2CHAR(s1 + i);
+ c2 = PTR2CHAR(s2 + j);
+
+ if ((p_fic ? MB_TOLOWER(c1) != MB_TOLOWER(c2) : c1 != c2)
+ && (prev1 != '*' || prev2 != '*'))
+ return FALSE;
+ prev2 = prev1;
+ prev1 = c1;
+
+ i += MB_PTR2LEN(s1 + i);
+ j += MB_PTR2LEN(s2 + j);
+ }
+ return s1[i] == s2[j];
+}
+#endif
+
+/*
+ * maintains the list of already visited files and dirs
+ * returns FAIL if the given file/dir is already in the list
+ * returns OK if it is newly added
+ *
+ * TODO: What to do on memory allocation problems?
+ * -> return TRUE - Better the file is found several times instead of
+ * never.
+ */
+ static int
+ff_check_visited(
+ ff_visited_T **visited_list,
+ char_u *fname
+#ifdef FEAT_PATH_EXTRA
+ , char_u *wc_path
+#endif
+ )
+{
+ ff_visited_T *vp;
+#ifdef UNIX
+ stat_T st;
+ int url = FALSE;
+#endif
+
+ /* For an URL we only compare the name, otherwise we compare the
+ * device/inode (unix) or the full path name (not Unix). */
+ if (path_with_url(fname))
+ {
+ vim_strncpy(ff_expand_buffer, fname, MAXPATHL - 1);
+#ifdef UNIX
+ url = TRUE;
+#endif
+ }
+ else
+ {
+ ff_expand_buffer[0] = NUL;
+#ifdef UNIX
+ if (mch_stat((char *)fname, &st) < 0)
+#else
+ if (vim_FullName(fname, ff_expand_buffer, MAXPATHL, TRUE) == FAIL)
+#endif
+ return FAIL;
+ }
+
+ /* check against list of already visited files */
+ for (vp = *visited_list; vp != NULL; vp = vp->ffv_next)
+ {
+ if (
+#ifdef UNIX
+ !url ? (vp->ffv_dev_valid && vp->ffv_dev == st.st_dev
+ && vp->ffv_ino == st.st_ino)
+ :
+#endif
+ fnamecmp(vp->ffv_fname, ff_expand_buffer) == 0
+ )
+ {
+#ifdef FEAT_PATH_EXTRA
+ /* are the wildcard parts equal */
+ if (ff_wc_equal(vp->ffv_wc_path, wc_path) == TRUE)
+#endif
+ /* already visited */
+ return FAIL;
+ }
+ }
+
+ /*
+ * New file/dir. Add it to the list of visited files/dirs.
+ */
+ vp = (ff_visited_T *)alloc((unsigned)(sizeof(ff_visited_T)
+ + STRLEN(ff_expand_buffer)));
+
+ if (vp != NULL)
+ {
+#ifdef UNIX
+ if (!url)
+ {
+ vp->ffv_dev_valid = TRUE;
+ vp->ffv_ino = st.st_ino;
+ vp->ffv_dev = st.st_dev;
+ vp->ffv_fname[0] = NUL;
+ }
+ else
+ {
+ vp->ffv_dev_valid = FALSE;
+#endif
+ STRCPY(vp->ffv_fname, ff_expand_buffer);
+#ifdef UNIX
+ }
+#endif
+#ifdef FEAT_PATH_EXTRA
+ if (wc_path != NULL)
+ vp->ffv_wc_path = vim_strsave(wc_path);
+ else
+ vp->ffv_wc_path = NULL;
+#endif
+
+ vp->ffv_next = *visited_list;
+ *visited_list = vp;
+ }
+
+ return OK;
+}
+
+/*
+ * create stack element from given path pieces
+ */
+ static ff_stack_T *
+ff_create_stack_element(
+ char_u *fix_part,
+#ifdef FEAT_PATH_EXTRA
+ char_u *wc_part,
+#endif
+ int level,
+ int star_star_empty)
+{
+ ff_stack_T *new;
+
+ new = (ff_stack_T *)alloc((unsigned)sizeof(ff_stack_T));
+ if (new == NULL)
+ return NULL;
+
+ new->ffs_prev = NULL;
+ new->ffs_filearray = NULL;
+ new->ffs_filearray_size = 0;
+ new->ffs_filearray_cur = 0;
+ new->ffs_stage = 0;
+ new->ffs_level = level;
+ new->ffs_star_star_empty = star_star_empty;
+
+ /* the following saves NULL pointer checks in vim_findfile */
+ if (fix_part == NULL)
+ fix_part = (char_u *)"";
+ new->ffs_fix_path = vim_strsave(fix_part);
+
+#ifdef FEAT_PATH_EXTRA
+ if (wc_part == NULL)
+ wc_part = (char_u *)"";
+ new->ffs_wc_path = vim_strsave(wc_part);
+#endif
+
+ if (new->ffs_fix_path == NULL
+#ifdef FEAT_PATH_EXTRA
+ || new->ffs_wc_path == NULL
+#endif
+ )
+ {
+ ff_free_stack_element(new);
+ new = NULL;
+ }
+
+ return new;
+}
+
+/*
+ * Push a dir on the directory stack.
+ */
+ static void
+ff_push(ff_search_ctx_T *search_ctx, ff_stack_T *stack_ptr)
+{
+ /* check for NULL pointer, not to return an error to the user, but
+ * to prevent a crash */
+ if (stack_ptr != NULL)
+ {
+ stack_ptr->ffs_prev = search_ctx->ffsc_stack_ptr;
+ search_ctx->ffsc_stack_ptr = stack_ptr;
+ }
+}
+
+/*
+ * Pop a dir from the directory stack.
+ * Returns NULL if stack is empty.
+ */
+ static ff_stack_T *
+ff_pop(ff_search_ctx_T *search_ctx)
+{
+ ff_stack_T *sptr;
+
+ sptr = search_ctx->ffsc_stack_ptr;
+ if (search_ctx->ffsc_stack_ptr != NULL)
+ search_ctx->ffsc_stack_ptr = search_ctx->ffsc_stack_ptr->ffs_prev;
+
+ return sptr;
+}
+
+/*
+ * free the given stack element
+ */
+ static void
+ff_free_stack_element(ff_stack_T *stack_ptr)
+{
+ /* vim_free handles possible NULL pointers */
+ vim_free(stack_ptr->ffs_fix_path);
+#ifdef FEAT_PATH_EXTRA
+ vim_free(stack_ptr->ffs_wc_path);
+#endif
+
+ if (stack_ptr->ffs_filearray != NULL)
+ FreeWild(stack_ptr->ffs_filearray_size, stack_ptr->ffs_filearray);
+
+ vim_free(stack_ptr);
+}
+
+/*
+ * Clear the search context, but NOT the visited list.
+ */
+ static void
+ff_clear(ff_search_ctx_T *search_ctx)
+{
+ ff_stack_T *sptr;
+
+ /* clear up stack */
+ while ((sptr = ff_pop(search_ctx)) != NULL)
+ ff_free_stack_element(sptr);
+
+ vim_free(search_ctx->ffsc_file_to_search);
+ vim_free(search_ctx->ffsc_start_dir);
+ vim_free(search_ctx->ffsc_fix_path);
+#ifdef FEAT_PATH_EXTRA
+ vim_free(search_ctx->ffsc_wc_path);
+#endif
+
+#ifdef FEAT_PATH_EXTRA
+ if (search_ctx->ffsc_stopdirs_v != NULL)
+ {
+ int i = 0;
+
+ while (search_ctx->ffsc_stopdirs_v[i] != NULL)
+ {
+ vim_free(search_ctx->ffsc_stopdirs_v[i]);
+ i++;
+ }
+ vim_free(search_ctx->ffsc_stopdirs_v);
+ }
+ search_ctx->ffsc_stopdirs_v = NULL;
+#endif
+
+ /* reset everything */
+ search_ctx->ffsc_file_to_search = NULL;
+ search_ctx->ffsc_start_dir = NULL;
+ search_ctx->ffsc_fix_path = NULL;
+#ifdef FEAT_PATH_EXTRA
+ search_ctx->ffsc_wc_path = NULL;
+ search_ctx->ffsc_level = 0;
+#endif
+}
+
+#ifdef FEAT_PATH_EXTRA
+/*
+ * check if the given path is in the stopdirs
+ * returns TRUE if yes else FALSE
+ */
+ static int
+ff_path_in_stoplist(char_u *path, int path_len, char_u **stopdirs_v)
+{
+ int i = 0;
+
+ /* eat up trailing path separators, except the first */
+ while (path_len > 1 && vim_ispathsep(path[path_len - 1]))
+ path_len--;
+
+ /* if no path consider it as match */
+ if (path_len == 0)
+ return TRUE;
+
+ for (i = 0; stopdirs_v[i] != NULL; i++)
+ {
+ if ((int)STRLEN(stopdirs_v[i]) > path_len)
+ {
+ /* match for parent directory. So '/home' also matches
+ * '/home/rks'. Check for PATHSEP in stopdirs_v[i], else
+ * '/home/r' would also match '/home/rks'
+ */
+ if (fnamencmp(stopdirs_v[i], path, path_len) == 0
+ && vim_ispathsep(stopdirs_v[i][path_len]))
+ return TRUE;
+ }
+ else
+ {
+ if (fnamecmp(stopdirs_v[i], path) == 0)
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+#endif
+
+#if defined(FEAT_SEARCHPATH) || defined(PROTO)
+/*
+ * Find the file name "ptr[len]" in the path. Also finds directory names.
+ *
+ * On the first call set the parameter 'first' to TRUE to initialize
+ * the search. For repeating calls to FALSE.
+ *
+ * Repeating calls will return other files called 'ptr[len]' from the path.
+ *
+ * Only on the first call 'ptr' and 'len' are used. For repeating calls they
+ * don't need valid values.
+ *
+ * If nothing found on the first call the option FNAME_MESS will issue the
+ * message:
+ * 'Can't find file "<file>" in path'
+ * On repeating calls:
+ * 'No more file "<file>" found in path'
+ *
+ * options:
+ * FNAME_MESS give error message when not found
+ *
+ * Uses NameBuff[]!
+ *
+ * Returns an allocated string for the file name. NULL for error.
+ *
+ */
+ char_u *
+find_file_in_path(
+ char_u *ptr, /* file name */
+ int len, /* length of file name */
+ int options,
+ int first, /* use count'th matching file name */
+ char_u *rel_fname) /* file name searching relative to */
+{
+ return find_file_in_path_option(ptr, len, options, first,
+ *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path,
+ FINDFILE_BOTH, rel_fname, curbuf->b_p_sua);
+}
+
+static char_u *ff_file_to_find = NULL;
+static void *fdip_search_ctx = NULL;
+
+#if defined(EXITFREE)
+ static void
+free_findfile(void)
+{
+ vim_free(ff_file_to_find);
+ vim_findfile_cleanup(fdip_search_ctx);
+}
+#endif
+
+/*
+ * Find the directory name "ptr[len]" in the path.
+ *
+ * options:
+ * FNAME_MESS give error message when not found
+ * FNAME_UNESC unescape backslashes.
+ *
+ * Uses NameBuff[]!
+ *
+ * Returns an allocated string for the file name. NULL for error.
+ */
+ char_u *
+find_directory_in_path(
+ char_u *ptr, /* file name */
+ int len, /* length of file name */
+ int options,
+ char_u *rel_fname) /* file name searching relative to */
+{
+ return find_file_in_path_option(ptr, len, options, TRUE, p_cdpath,
+ FINDFILE_DIR, rel_fname, (char_u *)"");
+}
+
+ char_u *
+find_file_in_path_option(
+ char_u *ptr, /* file name */
+ int len, /* length of file name */
+ int options,
+ int first, /* use count'th matching file name */
+ char_u *path_option, /* p_path or p_cdpath */
+ int find_what, /* FINDFILE_FILE, _DIR or _BOTH */
+ char_u *rel_fname, /* file name we are looking relative to. */
+ char_u *suffixes) /* list of suffixes, 'suffixesadd' option */
+{
+ static char_u *dir;
+ static int did_findfile_init = FALSE;
+ char_u save_char;
+ char_u *file_name = NULL;
+ char_u *buf = NULL;
+ int rel_to_curdir;
+#ifdef AMIGA
+ struct Process *proc = (struct Process *)FindTask(0L);
+ APTR save_winptr = proc->pr_WindowPtr;
+
+ /* Avoid a requester here for a volume that doesn't exist. */
+ proc->pr_WindowPtr = (APTR)-1L;
+#endif
+
+ if (first == TRUE)
+ {
+ /* copy file name into NameBuff, expanding environment variables */
+ save_char = ptr[len];
+ ptr[len] = NUL;
+ expand_env_esc(ptr, NameBuff, MAXPATHL, FALSE, TRUE, NULL);
+ ptr[len] = save_char;
+
+ vim_free(ff_file_to_find);
+ ff_file_to_find = vim_strsave(NameBuff);
+ if (ff_file_to_find == NULL) /* out of memory */
+ {
+ file_name = NULL;
+ goto theend;
+ }
+ if (options & FNAME_UNESC)
+ {
+ /* Change all "\ " to " ". */
+ for (ptr = ff_file_to_find; *ptr != NUL; ++ptr)
+ if (ptr[0] == '\\' && ptr[1] == ' ')
+ mch_memmove(ptr, ptr + 1, STRLEN(ptr));
+ }
+ }
+
+ rel_to_curdir = (ff_file_to_find[0] == '.'
+ && (ff_file_to_find[1] == NUL
+ || vim_ispathsep(ff_file_to_find[1])
+ || (ff_file_to_find[1] == '.'
+ && (ff_file_to_find[2] == NUL
+ || vim_ispathsep(ff_file_to_find[2])))));
+ if (vim_isAbsName(ff_file_to_find)
+ /* "..", "../path", "." and "./path": don't use the path_option */
+ || rel_to_curdir
+#if defined(MSWIN)
+ /* handle "\tmp" as absolute path */
+ || vim_ispathsep(ff_file_to_find[0])
+ /* handle "c:name" as absolute path */
+ || (ff_file_to_find[0] != NUL && ff_file_to_find[1] == ':')
+#endif
+#ifdef AMIGA
+ /* handle ":tmp" as absolute path */
+ || ff_file_to_find[0] == ':'
+#endif
+ )
+ {
+ /*
+ * Absolute path, no need to use "path_option".
+ * If this is not a first call, return NULL. We already returned a
+ * filename on the first call.
+ */
+ if (first == TRUE)
+ {
+ int l;
+ int run;
+
+ if (path_with_url(ff_file_to_find))
+ {
+ file_name = vim_strsave(ff_file_to_find);
+ goto theend;
+ }
+
+ /* When FNAME_REL flag given first use the directory of the file.
+ * Otherwise or when this fails use the current directory. */
+ for (run = 1; run <= 2; ++run)
+ {
+ l = (int)STRLEN(ff_file_to_find);
+ if (run == 1
+ && rel_to_curdir
+ && (options & FNAME_REL)
+ && rel_fname != NULL
+ && STRLEN(rel_fname) + l < MAXPATHL)
+ {
+ STRCPY(NameBuff, rel_fname);
+ STRCPY(gettail(NameBuff), ff_file_to_find);
+ l = (int)STRLEN(NameBuff);
+ }
+ else
+ {
+ STRCPY(NameBuff, ff_file_to_find);
+ run = 2;
+ }
+
+ /* When the file doesn't exist, try adding parts of
+ * 'suffixesadd'. */
+ buf = suffixes;
+ for (;;)
+ {
+ if (mch_getperm(NameBuff) >= 0
+ && (find_what == FINDFILE_BOTH
+ || ((find_what == FINDFILE_DIR)
+ == mch_isdir(NameBuff))))
+ {
+ file_name = vim_strsave(NameBuff);
+ goto theend;
+ }
+ if (*buf == NUL)
+ break;
+ copy_option_part(&buf, NameBuff + l, MAXPATHL - l, ",");
+ }
+ }
+ }
+ }
+ else
+ {
+ /*
+ * Loop over all paths in the 'path' or 'cdpath' option.
+ * When "first" is set, first setup to the start of the option.
+ * Otherwise continue to find the next match.
+ */
+ if (first == TRUE)
+ {
+ /* vim_findfile_free_visited can handle a possible NULL pointer */
+ vim_findfile_free_visited(fdip_search_ctx);
+ dir = path_option;
+ did_findfile_init = FALSE;
+ }
+
+ for (;;)
+ {
+ if (did_findfile_init)
+ {
+ file_name = vim_findfile(fdip_search_ctx);
+ if (file_name != NULL)
+ break;
+
+ did_findfile_init = FALSE;
+ }
+ else
+ {
+ char_u *r_ptr;
+
+ if (dir == NULL || *dir == NUL)
+ {
+ /* We searched all paths of the option, now we can
+ * free the search context. */
+ vim_findfile_cleanup(fdip_search_ctx);
+ fdip_search_ctx = NULL;
+ break;
+ }
+
+ if ((buf = alloc((int)(MAXPATHL))) == NULL)
+ break;
+
+ /* copy next path */
+ buf[0] = 0;
+ copy_option_part(&dir, buf, MAXPATHL, " ,");
+
+#ifdef FEAT_PATH_EXTRA
+ /* get the stopdir string */
+ r_ptr = vim_findfile_stopdir(buf);
+#else
+ r_ptr = NULL;
+#endif
+ fdip_search_ctx = vim_findfile_init(buf, ff_file_to_find,
+ r_ptr, 100, FALSE, find_what,
+ fdip_search_ctx, FALSE, rel_fname);
+ if (fdip_search_ctx != NULL)
+ did_findfile_init = TRUE;
+ vim_free(buf);
+ }
+ }
+ }
+ if (file_name == NULL && (options & FNAME_MESS))
+ {
+ if (first == TRUE)
+ {
+ if (find_what == FINDFILE_DIR)
+ semsg(_("E344: Can't find directory \"%s\" in cdpath"),
+ ff_file_to_find);
+ else
+ semsg(_("E345: Can't find file \"%s\" in path"),
+ ff_file_to_find);
+ }
+ else
+ {
+ if (find_what == FINDFILE_DIR)
+ semsg(_("E346: No more directory \"%s\" found in cdpath"),
+ ff_file_to_find);
+ else
+ semsg(_("E347: No more file \"%s\" found in path"),
+ ff_file_to_find);
+ }
+ }
+
+theend:
+#ifdef AMIGA
+ proc->pr_WindowPtr = save_winptr;
+#endif
+ return file_name;
+}
+
+#endif /* FEAT_SEARCHPATH */
+
+/*
+ * Change directory to "new_dir". If FEAT_SEARCHPATH is defined, search
+ * 'cdpath' for relative directory names, otherwise just mch_chdir().
+ */
+ int
+vim_chdir(char_u *new_dir)
+{
+#ifndef FEAT_SEARCHPATH
+ return mch_chdir((char *)new_dir);
+#else
+ char_u *dir_name;
+ int r;
+
+ dir_name = find_directory_in_path(new_dir, (int)STRLEN(new_dir),
+ FNAME_MESS, curbuf->b_ffname);
+ if (dir_name == NULL)
+ return -1;
+ r = mch_chdir((char *)dir_name);
+ vim_free(dir_name);
+ return r;
+#endif
+}
+
+/*
+ * Get user name from machine-specific function.
+ * Returns the user name in "buf[len]".
+ * Some systems are quite slow in obtaining the user name (Windows NT), thus
+ * cache the result.
+ * Returns OK or FAIL.
+ */
+ int
+get_user_name(char_u *buf, int len)
+{
+ if (username == NULL)
+ {
+ if (mch_get_user_name(buf, len) == FAIL)
+ return FAIL;
+ username = vim_strsave(buf);
+ }
+ else
+ vim_strncpy(buf, username, len - 1);
+ return OK;
+}
+
+#ifndef HAVE_QSORT
+/*
+ * Our own qsort(), for systems that don't have it.
+ * It's simple and slow. From the K&R C book.
+ */
+ void
+qsort(
+ void *base,
+ size_t elm_count,
+ size_t elm_size,
+ int (*cmp)(const void *, const void *))
+{
+ char_u *buf;
+ char_u *p1;
+ char_u *p2;
+ int i, j;
+ int gap;
+
+ buf = alloc((unsigned)elm_size);
+ if (buf == NULL)
+ return;
+
+ for (gap = elm_count / 2; gap > 0; gap /= 2)
+ for (i = gap; i < elm_count; ++i)
+ for (j = i - gap; j >= 0; j -= gap)
+ {
+ /* Compare the elements. */
+ p1 = (char_u *)base + j * elm_size;
+ p2 = (char_u *)base + (j + gap) * elm_size;
+ if ((*cmp)((void *)p1, (void *)p2) <= 0)
+ break;
+ /* Exchange the elements. */
+ mch_memmove(buf, p1, elm_size);
+ mch_memmove(p1, p2, elm_size);
+ mch_memmove(p2, buf, elm_size);
+ }
+
+ vim_free(buf);
+}
+#endif
+
+/*
+ * Sort an array of strings.
+ */
+static int
+#ifdef __BORLANDC__
+_RTLENTRYF
+#endif
+sort_compare(const void *s1, const void *s2);
+
+ static int
+#ifdef __BORLANDC__
+_RTLENTRYF
+#endif
+sort_compare(const void *s1, const void *s2)
+{
+ return STRCMP(*(char **)s1, *(char **)s2);
+}
+
+ void
+sort_strings(
+ char_u **files,
+ int count)
+{
+ qsort((void *)files, (size_t)count, sizeof(char_u *), sort_compare);
+}
+
+#if !defined(NO_EXPANDPATH) || defined(PROTO)
+/*
+ * Compare path "p[]" to "q[]".
+ * If "maxlen" >= 0 compare "p[maxlen]" to "q[maxlen]"
+ * Return value like strcmp(p, q), but consider path separators.
+ */
+ int
+pathcmp(const char *p, const char *q, int maxlen)
+{
+ int i, j;
+ int c1, c2;
+ const char *s = NULL;
+
+ for (i = 0, j = 0; maxlen < 0 || (i < maxlen && j < maxlen);)
+ {
+ c1 = PTR2CHAR((char_u *)p + i);
+ c2 = PTR2CHAR((char_u *)q + j);
+
+ /* End of "p": check if "q" also ends or just has a slash. */
+ if (c1 == NUL)
+ {
+ if (c2 == NUL) /* full match */
+ return 0;
+ s = q;
+ i = j;
+ break;
+ }
+
+ /* End of "q": check if "p" just has a slash. */
+ if (c2 == NUL)
+ {
+ s = p;
+ break;
+ }
+
+ if ((p_fic ? MB_TOUPPER(c1) != MB_TOUPPER(c2) : c1 != c2)
+#ifdef BACKSLASH_IN_FILENAME
+ /* consider '/' and '\\' to be equal */
+ && !((c1 == '/' && c2 == '\\')
+ || (c1 == '\\' && c2 == '/'))
+#endif
+ )
+ {
+ if (vim_ispathsep(c1))
+ return -1;
+ if (vim_ispathsep(c2))
+ return 1;
+ return p_fic ? MB_TOUPPER(c1) - MB_TOUPPER(c2)
+ : c1 - c2; /* no match */
+ }
+
+ i += MB_PTR2LEN((char_u *)p + i);
+ j += MB_PTR2LEN((char_u *)q + j);
+ }
+ if (s == NULL) /* "i" or "j" ran into "maxlen" */
+ return 0;
+
+ c1 = PTR2CHAR((char_u *)s + i);
+ c2 = PTR2CHAR((char_u *)s + i + MB_PTR2LEN((char_u *)s + i));
+ /* ignore a trailing slash, but not "//" or ":/" */
+ if (c2 == NUL
+ && i > 0
+ && !after_pathsep((char_u *)s, (char_u *)s + i)
+#ifdef BACKSLASH_IN_FILENAME
+ && (c1 == '/' || c1 == '\\')
+#else
+ && c1 == '/'
+#endif
+ )
+ return 0; /* match with trailing slash */
+ if (s == q)
+ return -1; /* no match */
+ return 1;
+}
+#endif
+
+/*
+ * The putenv() implementation below comes from the "screen" program.
+ * Included with permission from Juergen Weigert.
+ * See pty.c for the copyright notice.
+ */
+
+/*
+ * putenv -- put value into environment
+ *
+ * Usage: i = putenv (string)
+ * int i;
+ * char *string;
+ *
+ * where string is of the form <name>=<value>.
+ * Putenv returns 0 normally, -1 on error (not enough core for malloc).
+ *
+ * Putenv may need to add a new name into the environment, or to
+ * associate a value longer than the current value with a particular
+ * name. So, to make life simpler, putenv() copies your entire
+ * environment into the heap (i.e. malloc()) from the stack
+ * (i.e. where it resides when your process is initiated) the first
+ * time you call it.
+ *
+ * (history removed, not very interesting. See the "screen" sources.)
+ */
+
+#if !defined(HAVE_SETENV) && !defined(HAVE_PUTENV)
+
+#define EXTRASIZE 5 /* increment to add to env. size */
+
+static int envsize = -1; /* current size of environment */
+extern char **environ; /* the global which is your env. */
+
+static int findenv(char *name); /* look for a name in the env. */
+static int newenv(void); /* copy env. from stack to heap */
+static int moreenv(void); /* incr. size of env. */
+
+ int
+putenv(const char *string)
+{
+ int i;
+ char *p;
+
+ if (envsize < 0)
+ { /* first time putenv called */
+ if (newenv() < 0) /* copy env. to heap */
+ return -1;
+ }
+
+ i = findenv((char *)string); /* look for name in environment */
+
+ if (i < 0)
+ { /* name must be added */
+ for (i = 0; environ[i]; i++);
+ if (i >= (envsize - 1))
+ { /* need new slot */
+ if (moreenv() < 0)
+ return -1;
+ }
+ p = (char *)alloc((unsigned)(strlen(string) + 1));
+ if (p == NULL) /* not enough core */
+ return -1;
+ environ[i + 1] = 0; /* new end of env. */
+ }
+ else
+ { /* name already in env. */
+ p = vim_realloc(environ[i], strlen(string) + 1);
+ if (p == NULL)
+ return -1;
+ }
+ sprintf(p, "%s", string); /* copy into env. */
+ environ[i] = p;
+
+ return 0;
+}
+
+ static int
+findenv(char *name)
+{
+ char *namechar, *envchar;
+ int i, found;
+
+ found = 0;
+ for (i = 0; environ[i] && !found; i++)
+ {
+ envchar = environ[i];
+ namechar = name;
+ while (*namechar && *namechar != '=' && (*namechar == *envchar))
+ {
+ namechar++;
+ envchar++;
+ }
+ found = ((*namechar == '\0' || *namechar == '=') && *envchar == '=');
+ }
+ return found ? i - 1 : -1;
+}
+
+ static int
+newenv(void)
+{
+ char **env, *elem;
+ int i, esize;
+
+ for (i = 0; environ[i]; i++)
+ ;
+
+ esize = i + EXTRASIZE + 1;
+ env = (char **)alloc((unsigned)(esize * sizeof (elem)));
+ if (env == NULL)
+ return -1;
+
+ for (i = 0; environ[i]; i++)
+ {
+ elem = (char *)alloc((unsigned)(strlen(environ[i]) + 1));
+ if (elem == NULL)
+ return -1;
+ env[i] = elem;
+ strcpy(elem, environ[i]);
+ }
+
+ env[i] = 0;
+ environ = env;
+ envsize = esize;
+ return 0;
+}
+
+ static int
+moreenv(void)
+{
+ int esize;
+ char **env;
+
+ esize = envsize + EXTRASIZE;
+ env = (char **)vim_realloc((char *)environ, esize * sizeof (*env));
+ if (env == 0)
+ return -1;
+ environ = env;
+ envsize = esize;
+ return 0;
+}
+
+# ifdef USE_VIMPTY_GETENV
+/*
+ * Used for mch_getenv() for Mac.
+ */
+ char_u *
+vimpty_getenv(const char_u *string)
+{
+ int i;
+ char_u *p;
+
+ if (envsize < 0)
+ return NULL;
+
+ i = findenv((char *)string);
+
+ if (i < 0)
+ return NULL;
+
+ p = vim_strchr((char_u *)environ[i], '=');
+ return (p + 1);
+}
+# endif
+
+#endif /* !defined(HAVE_SETENV) && !defined(HAVE_PUTENV) */
+
+#if defined(FEAT_EVAL) || defined(FEAT_SPELL) || defined(PROTO)
+/*
+ * Return 0 for not writable, 1 for writable file, 2 for a dir which we have
+ * rights to write into.
+ */
+ int
+filewritable(char_u *fname)
+{
+ int retval = 0;
+#if defined(UNIX) || defined(VMS)
+ int perm = 0;
+#endif
+
+#if defined(UNIX) || defined(VMS)
+ perm = mch_getperm(fname);
+#endif
+ if (
+# ifdef WIN3264
+ mch_writable(fname) &&
+# else
+# if defined(UNIX) || defined(VMS)
+ (perm & 0222) &&
+# endif
+# endif
+ mch_access((char *)fname, W_OK) == 0
+ )
+ {
+ ++retval;
+ if (mch_isdir(fname))
+ ++retval;
+ }
+ return retval;
+}
+#endif
+
+#if defined(FEAT_SPELL) || defined(FEAT_PERSISTENT_UNDO) || defined(PROTO)
+/*
+ * Read 2 bytes from "fd" and turn them into an int, MSB first.
+ * Returns -1 when encountering EOF.
+ */
+ int
+get2c(FILE *fd)
+{
+ int c, n;
+
+ n = getc(fd);
+ if (n == EOF) return -1;
+ c = getc(fd);
+ if (c == EOF) return -1;
+ return (n << 8) + c;
+}
+
+/*
+ * Read 3 bytes from "fd" and turn them into an int, MSB first.
+ * Returns -1 when encountering EOF.
+ */
+ int
+get3c(FILE *fd)
+{
+ int c, n;
+
+ n = getc(fd);
+ if (n == EOF) return -1;
+ c = getc(fd);
+ if (c == EOF) return -1;
+ n = (n << 8) + c;
+ c = getc(fd);
+ if (c == EOF) return -1;
+ return (n << 8) + c;
+}
+
+/*
+ * Read 4 bytes from "fd" and turn them into an int, MSB first.
+ * Returns -1 when encountering EOF.
+ */
+ int
+get4c(FILE *fd)
+{
+ int c;
+ /* Use unsigned rather than int otherwise result is undefined
+ * when left-shift sets the MSB. */
+ unsigned n;
+
+ c = getc(fd);
+ if (c == EOF) return -1;
+ n = (unsigned)c;
+ c = getc(fd);
+ if (c == EOF) return -1;
+ n = (n << 8) + (unsigned)c;
+ c = getc(fd);
+ if (c == EOF) return -1;
+ n = (n << 8) + (unsigned)c;
+ c = getc(fd);
+ if (c == EOF) return -1;
+ n = (n << 8) + (unsigned)c;
+ return (int)n;
+}
+
+/*
+ * Read 8 bytes from "fd" and turn them into a time_T, MSB first.
+ * Returns -1 when encountering EOF.
+ */
+ time_T
+get8ctime(FILE *fd)
+{
+ int c;
+ time_T n = 0;
+ int i;
+
+ for (i = 0; i < 8; ++i)
+ {
+ c = getc(fd);
+ if (c == EOF) return -1;
+ n = (n << 8) + c;
+ }
+ return n;
+}
+
+/*
+ * Read a string of length "cnt" from "fd" into allocated memory.
+ * Returns NULL when out of memory or unable to read that many bytes.
+ */
+ char_u *
+read_string(FILE *fd, int cnt)
+{
+ char_u *str;
+ int i;
+ int c;
+
+ /* allocate memory */
+ str = alloc((unsigned)cnt + 1);
+ if (str != NULL)
+ {
+ /* Read the string. Quit when running into the EOF. */
+ for (i = 0; i < cnt; ++i)
+ {
+ c = getc(fd);
+ if (c == EOF)
+ {
+ vim_free(str);
+ return NULL;
+ }
+ str[i] = c;
+ }
+ str[i] = NUL;
+ }
+ return str;
+}
+
+/*
+ * Write a number to file "fd", MSB first, in "len" bytes.
+ */
+ int
+put_bytes(FILE *fd, long_u nr, int len)
+{
+ int i;
+
+ for (i = len - 1; i >= 0; --i)
+ if (putc((int)(nr >> (i * 8)), fd) == EOF)
+ return FAIL;
+ return OK;
+}
+
+#ifdef _MSC_VER
+# if (_MSC_VER <= 1200)
+/* This line is required for VC6 without the service pack. Also see the
+ * matching #pragma below. */
+ # pragma optimize("", off)
+# endif
+#endif
+
+/*
+ * Write time_T to file "fd" in 8 bytes.
+ * Returns FAIL when the write failed.
+ */
+ int
+put_time(FILE *fd, time_T the_time)
+{
+ char_u buf[8];
+
+ time_to_bytes(the_time, buf);
+ return fwrite(buf, (size_t)8, (size_t)1, fd) == 1 ? OK : FAIL;
+}
+
+/*
+ * Write time_T to "buf[8]".
+ */
+ void
+time_to_bytes(time_T the_time, char_u *buf)
+{
+ int c;
+ int i;
+ int bi = 0;
+ time_T wtime = the_time;
+
+ /* time_T can be up to 8 bytes in size, more than long_u, thus we
+ * can't use put_bytes() here.
+ * Another problem is that ">>" may do an arithmetic shift that keeps the
+ * sign. This happens for large values of wtime. A cast to long_u may
+ * truncate if time_T is 8 bytes. So only use a cast when it is 4 bytes,
+ * it's safe to assume that long_u is 4 bytes or more and when using 8
+ * bytes the top bit won't be set. */
+ for (i = 7; i >= 0; --i)
+ {
+ if (i + 1 > (int)sizeof(time_T))
+ /* ">>" doesn't work well when shifting more bits than avail */
+ buf[bi++] = 0;
+ else
+ {
+#if defined(SIZEOF_TIME_T) && SIZEOF_TIME_T > 4
+ c = (int)(wtime >> (i * 8));
+#else
+ c = (int)((long_u)wtime >> (i * 8));
+#endif
+ buf[bi++] = c;
+ }
+ }
+}
+
+#ifdef _MSC_VER
+# if (_MSC_VER <= 1200)
+ # pragma optimize("", on)
+# endif
+#endif
+
+#endif
+
+#if defined(FEAT_QUICKFIX) || defined(FEAT_SPELL) || defined(PROTO)
+/*
+ * Return TRUE if string "s" contains a non-ASCII character (128 or higher).
+ * When "s" is NULL FALSE is returned.
+ */
+ int
+has_non_ascii(char_u *s)
+{
+ char_u *p;
+
+ if (s != NULL)
+ for (p = s; *p != NUL; ++p)
+ if (*p >= 128)
+ return TRUE;
+ return FALSE;
+}
+#endif
+
+#if defined(MESSAGE_QUEUE) || defined(PROTO)
+# define MAX_REPEAT_PARSE 8
+
+/*
+ * Process messages that have been queued for netbeans or clientserver.
+ * Also check if any jobs have ended.
+ * These functions can call arbitrary vimscript and should only be called when
+ * it is safe to do so.
+ */
+ void
+parse_queued_messages(void)
+{
+ win_T *old_curwin = curwin;
+ int i;
+
+ // Do not handle messages while redrawing, because it may cause buffers to
+ // change or be wiped while they are being redrawn.
+ if (updating_screen)
+ return;
+
+ // Loop when a job ended, but don't keep looping forever.
+ for (i = 0; i < MAX_REPEAT_PARSE; ++i)
+ {
+ // For Win32 mch_breakcheck() does not check for input, do it here.
+# if defined(WIN32) && defined(FEAT_JOB_CHANNEL)
+ channel_handle_events(FALSE);
+# endif
+
+# ifdef FEAT_NETBEANS_INTG
+ // Process the queued netbeans messages.
+ netbeans_parse_messages();
+# endif
+# ifdef FEAT_JOB_CHANNEL
+ // Write any buffer lines still to be written.
+ channel_write_any_lines();
+
+ // Process the messages queued on channels.
+ channel_parse_messages();
+# endif
+# if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
+ // Process the queued clientserver messages.
+ server_parse_messages();
+# endif
+# ifdef FEAT_JOB_CHANNEL
+ // Check if any jobs have ended. If so, repeat the above to handle
+ // changes, e.g. stdin may have been closed.
+ if (job_check_ended())
+ continue;
+# endif
+# ifdef FEAT_TERMINAL
+ free_unused_terminals();
+# endif
+ break;
+ }
+
+ // If the current window changed we need to bail out of the waiting loop.
+ // E.g. when a job exit callback closes the terminal window.
+ if (curwin != old_curwin)
+ ins_char_typebuf(K_IGNORE);
+}
+#endif
+
+#ifndef PROTO /* proto is defined in vim.h */
+# ifdef ELAPSED_TIMEVAL
+/*
+ * Return time in msec since "start_tv".
+ */
+ long
+elapsed(struct timeval *start_tv)
+{
+ struct timeval now_tv;
+
+ gettimeofday(&now_tv, NULL);
+ return (now_tv.tv_sec - start_tv->tv_sec) * 1000L
+ + (now_tv.tv_usec - start_tv->tv_usec) / 1000L;
+}
+# endif
+
+# ifdef ELAPSED_TICKCOUNT
+/*
+ * Return time in msec since "start_tick".
+ */
+ long
+elapsed(DWORD start_tick)
+{
+ DWORD now = GetTickCount();
+
+ return (long)now - (long)start_tick;
+}
+# endif
+#endif
+
+#if defined(FEAT_JOB_CHANNEL) \
+ || (defined(UNIX) && (!defined(USE_SYSTEM) \
+ || (defined(FEAT_GUI) && defined(FEAT_TERMINAL)))) \
+ || defined(PROTO)
+/*
+ * Parse "cmd" and put the white-separated parts in "argv".
+ * "argv" is an allocated array with "argc" entries and room for 4 more.
+ * Returns FAIL when out of memory.
+ */
+ int
+mch_parse_cmd(char_u *cmd, int use_shcf, char ***argv, int *argc)
+{
+ int i;
+ char_u *p, *d;
+ int inquote;
+
+ /*
+ * Do this loop twice:
+ * 1: find number of arguments
+ * 2: separate them and build argv[]
+ */
+ for (i = 0; i < 2; ++i)
+ {
+ p = skipwhite(cmd);
+ inquote = FALSE;
+ *argc = 0;
+ for (;;)
+ {
+ if (i == 1)
+ (*argv)[*argc] = (char *)p;
+ ++*argc;
+ d = p;
+ while (*p != NUL && (inquote || (*p != ' ' && *p != TAB)))
+ {
+ if (p[0] == '"')
+ // quotes surrounding an argument and are dropped
+ inquote = !inquote;
+ else
+ {
+ if (rem_backslash(p))
+ {
+ // First pass: skip over "\ " and "\"".
+ // Second pass: Remove the backslash.
+ ++p;
+ }
+ if (i == 1)
+ *d++ = *p;
+ }
+ ++p;
+ }
+ if (*p == NUL)
+ {
+ if (i == 1)
+ *d++ = NUL;
+ break;
+ }
+ if (i == 1)
+ *d++ = NUL;
+ p = skipwhite(p + 1);
+ }
+ if (*argv == NULL)
+ {
+ if (use_shcf)
+ {
+ /* Account for possible multiple args in p_shcf. */
+ p = p_shcf;
+ for (;;)
+ {
+ p = skiptowhite(p);
+ if (*p == NUL)
+ break;
+ ++*argc;
+ p = skipwhite(p);
+ }
+ }
+
+ *argv = (char **)alloc((unsigned)((*argc + 4) * sizeof(char *)));
+ if (*argv == NULL) /* out of memory */
+ return FAIL;
+ }
+ }
+ return OK;
+}
+
+# if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
+/*
+ * Build "argv[argc]" from the string "cmd".
+ * "argv[argc]" is set to NULL;
+ * Return FAIL when out of memory.
+ */
+ int
+build_argv_from_string(char_u *cmd, char ***argv, int *argc)
+{
+ char_u *cmd_copy;
+ int i;
+
+ /* Make a copy, parsing will modify "cmd". */
+ cmd_copy = vim_strsave(cmd);
+ if (cmd_copy == NULL
+ || mch_parse_cmd(cmd_copy, FALSE, argv, argc) == FAIL)
+ {
+ vim_free(cmd_copy);
+ return FAIL;
+ }
+ for (i = 0; i < *argc; i++)
+ (*argv)[i] = (char *)vim_strsave((char_u *)(*argv)[i]);
+ (*argv)[*argc] = NULL;
+ vim_free(cmd_copy);
+ return OK;
+}
+
+/*
+ * Build "argv[argc]" from the list "l".
+ * "argv[argc]" is set to NULL;
+ * Return FAIL when out of memory.
+ */
+ int
+build_argv_from_list(list_T *l, char ***argv, int *argc)
+{
+ listitem_T *li;
+ char_u *s;
+
+ /* Pass argv[] to mch_call_shell(). */
+ *argv = (char **)alloc(sizeof(char *) * (l->lv_len + 1));
+ if (*argv == NULL)
+ return FAIL;
+ *argc = 0;
+ for (li = l->lv_first; li != NULL; li = li->li_next)
+ {
+ s = tv_get_string_chk(&li->li_tv);
+ if (s == NULL)
+ {
+ int i;
+
+ for (i = 0; i < *argc; ++i)
+ vim_free((*argv)[i]);
+ return FAIL;
+ }
+ (*argv)[*argc] = (char *)vim_strsave(s);
+ *argc += 1;
+ }
+ (*argv)[*argc] = NULL;
+ return OK;
+}
+# endif
+#endif
diff --git a/src/move.c b/src/move.c
new file mode 100644
index 0000000..da29b36
--- /dev/null
+++ b/src/move.c
@@ -0,0 +1,2864 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+/*
+ * move.c: Functions for moving the cursor and scrolling text.
+ *
+ * There are two ways to move the cursor:
+ * 1. Move the cursor directly, the text is scrolled to keep the cursor in the
+ * window.
+ * 2. Scroll the text, the cursor is moved into the text visible in the
+ * window.
+ * The 'scrolloff' option makes this a bit complicated.
+ */
+
+#include "vim.h"
+
+static int scrolljump_value(void);
+static int check_top_offset(void);
+static void curs_rows(win_T *wp);
+
+typedef struct
+{
+ linenr_T lnum; /* line number */
+#ifdef FEAT_DIFF
+ int fill; /* filler lines */
+#endif
+ int height; /* height of added line */
+} lineoff_T;
+
+static void topline_back(lineoff_T *lp);
+static void botline_forw(lineoff_T *lp);
+
+/*
+ * Compute wp->w_botline for the current wp->w_topline. Can be called after
+ * wp->w_topline changed.
+ */
+ static void
+comp_botline(win_T *wp)
+{
+ int n;
+ linenr_T lnum;
+ int done;
+#ifdef FEAT_FOLDING
+ linenr_T last;
+ int folded;
+#endif
+
+ /*
+ * If w_cline_row is valid, start there.
+ * Otherwise have to start at w_topline.
+ */
+ check_cursor_moved(wp);
+ if (wp->w_valid & VALID_CROW)
+ {
+ lnum = wp->w_cursor.lnum;
+ done = wp->w_cline_row;
+ }
+ else
+ {
+ lnum = wp->w_topline;
+ done = 0;
+ }
+
+ for ( ; lnum <= wp->w_buffer->b_ml.ml_line_count; ++lnum)
+ {
+#ifdef FEAT_FOLDING
+ last = lnum;
+ folded = FALSE;
+ if (hasFoldingWin(wp, lnum, NULL, &last, TRUE, NULL))
+ {
+ n = 1;
+ folded = TRUE;
+ }
+ else
+#endif
+#ifdef FEAT_DIFF
+ if (lnum == wp->w_topline)
+ n = plines_win_nofill(wp, lnum, TRUE) + wp->w_topfill;
+ else
+#endif
+ n = plines_win(wp, lnum, TRUE);
+ if (
+#ifdef FEAT_FOLDING
+ lnum <= wp->w_cursor.lnum && last >= wp->w_cursor.lnum
+#else
+ lnum == wp->w_cursor.lnum
+#endif
+ )
+ {
+ wp->w_cline_row = done;
+ wp->w_cline_height = n;
+#ifdef FEAT_FOLDING
+ wp->w_cline_folded = folded;
+#endif
+ redraw_for_cursorline(wp);
+ wp->w_valid |= (VALID_CROW|VALID_CHEIGHT);
+ }
+ if (done + n > wp->w_height)
+ break;
+ done += n;
+#ifdef FEAT_FOLDING
+ lnum = last;
+#endif
+ }
+
+ /* wp->w_botline is the line that is just below the window */
+ wp->w_botline = lnum;
+ wp->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP;
+
+ set_empty_rows(wp, done);
+}
+
+#ifdef FEAT_SYN_HL
+ void
+reset_cursorline(void)
+{
+ curwin->w_last_cursorline = 0;
+}
+#endif
+
+/*
+ * Redraw when w_cline_row changes and 'relativenumber' or 'cursorline' is
+ * set.
+ */
+ void
+redraw_for_cursorline(win_T *wp)
+{
+ if ((wp->w_p_rnu
+#ifdef FEAT_SYN_HL
+ || wp->w_p_cul
+#endif
+ )
+ && (wp->w_valid & VALID_CROW) == 0
+#ifdef FEAT_INS_EXPAND
+ && !pum_visible()
+#endif
+ )
+ {
+ if (wp->w_p_rnu)
+ // win_line() will redraw the number column only.
+ redraw_win_later(wp, VALID);
+#ifdef FEAT_SYN_HL
+ if (wp->w_p_cul)
+ {
+ if (wp->w_redr_type <= VALID && wp->w_last_cursorline != 0)
+ {
+ // "w_last_cursorline" may be outdated, worst case we redraw
+ // too much. This is optimized for moving the cursor around in
+ // the current window.
+ redrawWinline(wp, wp->w_last_cursorline);
+ redrawWinline(wp, wp->w_cursor.lnum);
+ }
+ else
+ redraw_win_later(wp, SOME_VALID);
+ }
+#endif
+ }
+}
+
+/*
+ * Update curwin->w_topline and redraw if necessary.
+ * Used to update the screen before printing a message.
+ */
+ void
+update_topline_redraw(void)
+{
+ update_topline();
+ if (must_redraw)
+ update_screen(0);
+}
+
+/*
+ * Update curwin->w_topline to move the cursor onto the screen.
+ */
+ void
+update_topline(void)
+{
+ long line_count;
+ int halfheight;
+ int n;
+ linenr_T old_topline;
+#ifdef FEAT_DIFF
+ int old_topfill;
+#endif
+#ifdef FEAT_FOLDING
+ linenr_T lnum;
+#endif
+ int check_topline = FALSE;
+ int check_botline = FALSE;
+ long *so_ptr = curwin->w_p_so >= 0 ? &curwin->w_p_so : &p_so;
+#ifdef FEAT_MOUSE
+ int save_so = *so_ptr;
+#endif
+
+ /* If there is no valid screen and when the window height is zero just use
+ * the cursor line. */
+ if (!screen_valid(TRUE) || curwin->w_height == 0)
+ {
+ curwin->w_topline = curwin->w_cursor.lnum;
+ curwin->w_botline = curwin->w_topline;
+ curwin->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP;
+ curwin->w_scbind_pos = 1;
+ return;
+ }
+
+ check_cursor_moved(curwin);
+ if (curwin->w_valid & VALID_TOPLINE)
+ return;
+
+#ifdef FEAT_MOUSE
+ /* When dragging with the mouse, don't scroll that quickly */
+ if (mouse_dragging > 0)
+ *so_ptr = mouse_dragging - 1;
+#endif
+
+ old_topline = curwin->w_topline;
+#ifdef FEAT_DIFF
+ old_topfill = curwin->w_topfill;
+#endif
+
+ /*
+ * If the buffer is empty, always set topline to 1.
+ */
+ if (BUFEMPTY()) /* special case - file is empty */
+ {
+ if (curwin->w_topline != 1)
+ redraw_later(NOT_VALID);
+ curwin->w_topline = 1;
+ curwin->w_botline = 2;
+ curwin->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP;
+ curwin->w_scbind_pos = 1;
+ }
+
+ /*
+ * If the cursor is above or near the top of the window, scroll the window
+ * to show the line the cursor is in, with 'scrolloff' context.
+ */
+ else
+ {
+ if (curwin->w_topline > 1)
+ {
+ /* If the cursor is above topline, scrolling is always needed.
+ * If the cursor is far below topline and there is no folding,
+ * scrolling down is never needed. */
+ if (curwin->w_cursor.lnum < curwin->w_topline)
+ check_topline = TRUE;
+ else if (check_top_offset())
+ check_topline = TRUE;
+ }
+#ifdef FEAT_DIFF
+ /* Check if there are more filler lines than allowed. */
+ if (!check_topline && curwin->w_topfill > diff_check_fill(curwin,
+ curwin->w_topline))
+ check_topline = TRUE;
+#endif
+
+ if (check_topline)
+ {
+ halfheight = curwin->w_height / 2 - 1;
+ if (halfheight < 2)
+ halfheight = 2;
+
+#ifdef FEAT_FOLDING
+ if (hasAnyFolding(curwin))
+ {
+ /* Count the number of logical lines between the cursor and
+ * topline + scrolloff (approximation of how much will be
+ * scrolled). */
+ n = 0;
+ for (lnum = curwin->w_cursor.lnum;
+ lnum < curwin->w_topline + *so_ptr; ++lnum)
+ {
+ ++n;
+ /* stop at end of file or when we know we are far off */
+ if (lnum >= curbuf->b_ml.ml_line_count || n >= halfheight)
+ break;
+ (void)hasFolding(lnum, NULL, &lnum);
+ }
+ }
+ else
+#endif
+ n = curwin->w_topline + *so_ptr - curwin->w_cursor.lnum;
+
+ /* If we weren't very close to begin with, we scroll to put the
+ * cursor in the middle of the window. Otherwise put the cursor
+ * near the top of the window. */
+ if (n >= halfheight)
+ scroll_cursor_halfway(FALSE);
+ else
+ {
+ scroll_cursor_top(scrolljump_value(), FALSE);
+ check_botline = TRUE;
+ }
+ }
+
+ else
+ {
+#ifdef FEAT_FOLDING
+ /* Make sure topline is the first line of a fold. */
+ (void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
+#endif
+ check_botline = TRUE;
+ }
+ }
+
+ /*
+ * If the cursor is below the bottom of the window, scroll the window
+ * to put the cursor on the window.
+ * When w_botline is invalid, recompute it first, to avoid a redraw later.
+ * If w_botline was approximated, we might need a redraw later in a few
+ * cases, but we don't want to spend (a lot of) time recomputing w_botline
+ * for every small change.
+ */
+ if (check_botline)
+ {
+ if (!(curwin->w_valid & VALID_BOTLINE_AP))
+ validate_botline();
+
+ if (curwin->w_botline <= curbuf->b_ml.ml_line_count)
+ {
+ if (curwin->w_cursor.lnum < curwin->w_botline)
+ {
+ if (((long)curwin->w_cursor.lnum
+ >= (long)curwin->w_botline - *so_ptr
+#ifdef FEAT_FOLDING
+ || hasAnyFolding(curwin)
+#endif
+ ))
+ {
+ lineoff_T loff;
+
+ /* Cursor is (a few lines) above botline, check if there are
+ * 'scrolloff' window lines below the cursor. If not, need to
+ * scroll. */
+ n = curwin->w_empty_rows;
+ loff.lnum = curwin->w_cursor.lnum;
+#ifdef FEAT_FOLDING
+ /* In a fold go to its last line. */
+ (void)hasFolding(loff.lnum, NULL, &loff.lnum);
+#endif
+#ifdef FEAT_DIFF
+ loff.fill = 0;
+ n += curwin->w_filler_rows;
+#endif
+ loff.height = 0;
+ while (loff.lnum < curwin->w_botline
+#ifdef FEAT_DIFF
+ && (loff.lnum + 1 < curwin->w_botline || loff.fill == 0)
+#endif
+ )
+ {
+ n += loff.height;
+ if (n >= *so_ptr)
+ break;
+ botline_forw(&loff);
+ }
+ if (n >= *so_ptr)
+ /* sufficient context, no need to scroll */
+ check_botline = FALSE;
+ }
+ else
+ /* sufficient context, no need to scroll */
+ check_botline = FALSE;
+ }
+ if (check_botline)
+ {
+#ifdef FEAT_FOLDING
+ if (hasAnyFolding(curwin))
+ {
+ /* Count the number of logical lines between the cursor and
+ * botline - scrolloff (approximation of how much will be
+ * scrolled). */
+ line_count = 0;
+ for (lnum = curwin->w_cursor.lnum;
+ lnum >= curwin->w_botline - *so_ptr; --lnum)
+ {
+ ++line_count;
+ /* stop at end of file or when we know we are far off */
+ if (lnum <= 0 || line_count > curwin->w_height + 1)
+ break;
+ (void)hasFolding(lnum, &lnum, NULL);
+ }
+ }
+ else
+#endif
+ line_count = curwin->w_cursor.lnum - curwin->w_botline
+ + 1 + *so_ptr;
+ if (line_count <= curwin->w_height + 1)
+ scroll_cursor_bot(scrolljump_value(), FALSE);
+ else
+ scroll_cursor_halfway(FALSE);
+ }
+ }
+ }
+ curwin->w_valid |= VALID_TOPLINE;
+
+ /*
+ * Need to redraw when topline changed.
+ */
+ if (curwin->w_topline != old_topline
+#ifdef FEAT_DIFF
+ || curwin->w_topfill != old_topfill
+#endif
+ )
+ {
+ dollar_vcol = -1;
+ if (curwin->w_skipcol != 0)
+ {
+ curwin->w_skipcol = 0;
+ redraw_later(NOT_VALID);
+ }
+ else
+ redraw_later(VALID);
+ /* May need to set w_skipcol when cursor in w_topline. */
+ if (curwin->w_cursor.lnum == curwin->w_topline)
+ validate_cursor();
+ }
+
+#ifdef FEAT_MOUSE
+ *so_ptr = save_so;
+#endif
+}
+
+/*
+ * Return the scrolljump value to use for the current window.
+ * When 'scrolljump' is positive use it as-is.
+ * When 'scrolljump' is negative use it as a percentage of the window height.
+ */
+ static int
+scrolljump_value(void)
+{
+ if (p_sj >= 0)
+ return (int)p_sj;
+ return (curwin->w_height * -p_sj) / 100;
+}
+
+/*
+ * Return TRUE when there are not 'scrolloff' lines above the cursor for the
+ * current window.
+ */
+ static int
+check_top_offset(void)
+{
+ lineoff_T loff;
+ int n;
+ long so = get_scrolloff_value();
+
+ if (curwin->w_cursor.lnum < curwin->w_topline + so
+#ifdef FEAT_FOLDING
+ || hasAnyFolding(curwin)
+#endif
+ )
+ {
+ loff.lnum = curwin->w_cursor.lnum;
+#ifdef FEAT_DIFF
+ loff.fill = 0;
+ n = curwin->w_topfill; /* always have this context */
+#else
+ n = 0;
+#endif
+ /* Count the visible screen lines above the cursor line. */
+ while (n < so)
+ {
+ topline_back(&loff);
+ /* Stop when included a line above the window. */
+ if (loff.lnum < curwin->w_topline
+#ifdef FEAT_DIFF
+ || (loff.lnum == curwin->w_topline && loff.fill > 0)
+#endif
+ )
+ break;
+ n += loff.height;
+ }
+ if (n < so)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+ void
+update_curswant(void)
+{
+ if (curwin->w_set_curswant)
+ {
+ validate_virtcol();
+ curwin->w_curswant = curwin->w_virtcol;
+ curwin->w_set_curswant = FALSE;
+ }
+}
+
+/*
+ * Check if the cursor has moved. Set the w_valid flag accordingly.
+ */
+ void
+check_cursor_moved(win_T *wp)
+{
+ if (wp->w_cursor.lnum != wp->w_valid_cursor.lnum)
+ {
+ wp->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL
+ |VALID_CHEIGHT|VALID_CROW|VALID_TOPLINE);
+ wp->w_valid_cursor = wp->w_cursor;
+ wp->w_valid_leftcol = wp->w_leftcol;
+ }
+ else if (wp->w_cursor.col != wp->w_valid_cursor.col
+ || wp->w_leftcol != wp->w_valid_leftcol
+ || wp->w_cursor.coladd != wp->w_valid_cursor.coladd)
+ {
+ wp->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL);
+ wp->w_valid_cursor.col = wp->w_cursor.col;
+ wp->w_valid_leftcol = wp->w_leftcol;
+ wp->w_valid_cursor.coladd = wp->w_cursor.coladd;
+ }
+}
+
+/*
+ * Call this function when some window settings have changed, which require
+ * the cursor position, botline and topline to be recomputed and the window to
+ * be redrawn. E.g, when changing the 'wrap' option or folding.
+ */
+ void
+changed_window_setting(void)
+{
+ changed_window_setting_win(curwin);
+}
+
+ void
+changed_window_setting_win(win_T *wp)
+{
+ wp->w_lines_valid = 0;
+ changed_line_abv_curs_win(wp);
+ wp->w_valid &= ~(VALID_BOTLINE|VALID_BOTLINE_AP|VALID_TOPLINE);
+ redraw_win_later(wp, NOT_VALID);
+}
+
+/*
+ * Set wp->w_topline to a certain number.
+ */
+ void
+set_topline(win_T *wp, linenr_T lnum)
+{
+#ifdef FEAT_FOLDING
+ /* go to first of folded lines */
+ (void)hasFoldingWin(wp, lnum, &lnum, NULL, TRUE, NULL);
+#endif
+ /* Approximate the value of w_botline */
+ wp->w_botline += lnum - wp->w_topline;
+ wp->w_topline = lnum;
+ wp->w_topline_was_set = TRUE;
+#ifdef FEAT_DIFF
+ wp->w_topfill = 0;
+#endif
+ wp->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_TOPLINE);
+ /* Don't set VALID_TOPLINE here, 'scrolloff' needs to be checked. */
+ redraw_later(VALID);
+}
+
+/*
+ * Call this function when the length of the cursor line (in screen
+ * characters) has changed, and the change is before the cursor.
+ * Need to take care of w_botline separately!
+ */
+ void
+changed_cline_bef_curs(void)
+{
+ curwin->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL
+ |VALID_CHEIGHT|VALID_TOPLINE);
+}
+
+ void
+changed_cline_bef_curs_win(win_T *wp)
+{
+ wp->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL
+ |VALID_CHEIGHT|VALID_TOPLINE);
+}
+
+/*
+ * Call this function when the length of a line (in screen characters) above
+ * the cursor have changed.
+ * Need to take care of w_botline separately!
+ */
+ void
+changed_line_abv_curs(void)
+{
+ curwin->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL|VALID_CROW
+ |VALID_CHEIGHT|VALID_TOPLINE);
+}
+
+ void
+changed_line_abv_curs_win(win_T *wp)
+{
+ wp->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL|VALID_CROW
+ |VALID_CHEIGHT|VALID_TOPLINE);
+}
+
+/*
+ * Make sure the value of curwin->w_botline is valid.
+ */
+ void
+validate_botline(void)
+{
+ if (!(curwin->w_valid & VALID_BOTLINE))
+ comp_botline(curwin);
+}
+
+/*
+ * Mark curwin->w_botline as invalid (because of some change in the buffer).
+ */
+ void
+invalidate_botline(void)
+{
+ curwin->w_valid &= ~(VALID_BOTLINE|VALID_BOTLINE_AP);
+}
+
+ void
+invalidate_botline_win(win_T *wp)
+{
+ wp->w_valid &= ~(VALID_BOTLINE|VALID_BOTLINE_AP);
+}
+
+ void
+approximate_botline_win(
+ win_T *wp)
+{
+ wp->w_valid &= ~VALID_BOTLINE;
+}
+
+/*
+ * Return TRUE if curwin->w_wrow and curwin->w_wcol are valid.
+ */
+ int
+cursor_valid(void)
+{
+ check_cursor_moved(curwin);
+ return ((curwin->w_valid & (VALID_WROW|VALID_WCOL)) ==
+ (VALID_WROW|VALID_WCOL));
+}
+
+/*
+ * Validate cursor position. Makes sure w_wrow and w_wcol are valid.
+ * w_topline must be valid, you may need to call update_topline() first!
+ */
+ void
+validate_cursor(void)
+{
+ check_cursor_moved(curwin);
+ if ((curwin->w_valid & (VALID_WCOL|VALID_WROW)) != (VALID_WCOL|VALID_WROW))
+ curs_columns(TRUE);
+}
+
+#if defined(FEAT_GUI) || defined(PROTO)
+/*
+ * validate w_cline_row.
+ */
+ void
+validate_cline_row(void)
+{
+ /*
+ * First make sure that w_topline is valid (after moving the cursor).
+ */
+ update_topline();
+ check_cursor_moved(curwin);
+ if (!(curwin->w_valid & VALID_CROW))
+ curs_rows(curwin);
+}
+#endif
+
+/*
+ * Compute wp->w_cline_row and wp->w_cline_height, based on the current value
+ * of wp->w_topline.
+ */
+ static void
+curs_rows(win_T *wp)
+{
+ linenr_T lnum;
+ int i;
+ int all_invalid;
+ int valid;
+#ifdef FEAT_FOLDING
+ long fold_count;
+#endif
+
+ /* Check if wp->w_lines[].wl_size is invalid */
+ all_invalid = (!redrawing()
+ || wp->w_lines_valid == 0
+ || wp->w_lines[0].wl_lnum > wp->w_topline);
+ i = 0;
+ wp->w_cline_row = 0;
+ for (lnum = wp->w_topline; lnum < wp->w_cursor.lnum; ++i)
+ {
+ valid = FALSE;
+ if (!all_invalid && i < wp->w_lines_valid)
+ {
+ if (wp->w_lines[i].wl_lnum < lnum || !wp->w_lines[i].wl_valid)
+ continue; /* skip changed or deleted lines */
+ if (wp->w_lines[i].wl_lnum == lnum)
+ {
+#ifdef FEAT_FOLDING
+ /* Check for newly inserted lines below this row, in which
+ * case we need to check for folded lines. */
+ if (!wp->w_buffer->b_mod_set
+ || wp->w_lines[i].wl_lastlnum < wp->w_cursor.lnum
+ || wp->w_buffer->b_mod_top
+ > wp->w_lines[i].wl_lastlnum + 1)
+#endif
+ valid = TRUE;
+ }
+ else if (wp->w_lines[i].wl_lnum > lnum)
+ --i; /* hold at inserted lines */
+ }
+ if (valid
+#ifdef FEAT_DIFF
+ && (lnum != wp->w_topline || !wp->w_p_diff)
+#endif
+ )
+ {
+#ifdef FEAT_FOLDING
+ lnum = wp->w_lines[i].wl_lastlnum + 1;
+ /* Cursor inside folded lines, don't count this row */
+ if (lnum > wp->w_cursor.lnum)
+ break;
+#else
+ ++lnum;
+#endif
+ wp->w_cline_row += wp->w_lines[i].wl_size;
+ }
+ else
+ {
+#ifdef FEAT_FOLDING
+ fold_count = foldedCount(wp, lnum, NULL);
+ if (fold_count)
+ {
+ lnum += fold_count;
+ if (lnum > wp->w_cursor.lnum)
+ break;
+ ++wp->w_cline_row;
+ }
+ else
+#endif
+#ifdef FEAT_DIFF
+ if (lnum == wp->w_topline)
+ wp->w_cline_row += plines_win_nofill(wp, lnum++, TRUE)
+ + wp->w_topfill;
+ else
+#endif
+ wp->w_cline_row += plines_win(wp, lnum++, TRUE);
+ }
+ }
+
+ check_cursor_moved(wp);
+ if (!(wp->w_valid & VALID_CHEIGHT))
+ {
+ if (all_invalid
+ || i == wp->w_lines_valid
+ || (i < wp->w_lines_valid
+ && (!wp->w_lines[i].wl_valid
+ || wp->w_lines[i].wl_lnum != wp->w_cursor.lnum)))
+ {
+#ifdef FEAT_DIFF
+ if (wp->w_cursor.lnum == wp->w_topline)
+ wp->w_cline_height = plines_win_nofill(wp, wp->w_cursor.lnum,
+ TRUE) + wp->w_topfill;
+ else
+#endif
+ wp->w_cline_height = plines_win(wp, wp->w_cursor.lnum, TRUE);
+#ifdef FEAT_FOLDING
+ wp->w_cline_folded = hasFoldingWin(wp, wp->w_cursor.lnum,
+ NULL, NULL, TRUE, NULL);
+#endif
+ }
+ else if (i > wp->w_lines_valid)
+ {
+ /* a line that is too long to fit on the last screen line */
+ wp->w_cline_height = 0;
+#ifdef FEAT_FOLDING
+ wp->w_cline_folded = hasFoldingWin(wp, wp->w_cursor.lnum,
+ NULL, NULL, TRUE, NULL);
+#endif
+ }
+ else
+ {
+ wp->w_cline_height = wp->w_lines[i].wl_size;
+#ifdef FEAT_FOLDING
+ wp->w_cline_folded = wp->w_lines[i].wl_folded;
+#endif
+ }
+ }
+
+ redraw_for_cursorline(curwin);
+ wp->w_valid |= VALID_CROW|VALID_CHEIGHT;
+
+}
+
+/*
+ * Validate curwin->w_virtcol only.
+ */
+ void
+validate_virtcol(void)
+{
+ validate_virtcol_win(curwin);
+}
+
+/*
+ * Validate wp->w_virtcol only.
+ */
+ void
+validate_virtcol_win(win_T *wp)
+{
+ check_cursor_moved(wp);
+ if (!(wp->w_valid & VALID_VIRTCOL))
+ {
+ getvvcol(wp, &wp->w_cursor, NULL, &(wp->w_virtcol), NULL);
+ wp->w_valid |= VALID_VIRTCOL;
+#ifdef FEAT_SYN_HL
+ if (wp->w_p_cuc
+# ifdef FEAT_INS_EXPAND
+ && !pum_visible()
+# endif
+ )
+ redraw_win_later(wp, SOME_VALID);
+#endif
+ }
+}
+
+/*
+ * Validate curwin->w_cline_height only.
+ */
+ static void
+validate_cheight(void)
+{
+ check_cursor_moved(curwin);
+ if (!(curwin->w_valid & VALID_CHEIGHT))
+ {
+#ifdef FEAT_DIFF
+ if (curwin->w_cursor.lnum == curwin->w_topline)
+ curwin->w_cline_height = plines_nofill(curwin->w_cursor.lnum)
+ + curwin->w_topfill;
+ else
+#endif
+ curwin->w_cline_height = plines(curwin->w_cursor.lnum);
+#ifdef FEAT_FOLDING
+ curwin->w_cline_folded = hasFolding(curwin->w_cursor.lnum, NULL, NULL);
+#endif
+ curwin->w_valid |= VALID_CHEIGHT;
+ }
+}
+
+/*
+ * Validate w_wcol and w_virtcol only.
+ */
+ void
+validate_cursor_col(void)
+{
+ colnr_T off;
+ colnr_T col;
+ int width;
+
+ validate_virtcol();
+ if (!(curwin->w_valid & VALID_WCOL))
+ {
+ col = curwin->w_virtcol;
+ off = curwin_col_off();
+ col += off;
+ width = curwin->w_width - off + curwin_col_off2();
+
+ /* long line wrapping, adjust curwin->w_wrow */
+ if (curwin->w_p_wrap
+ && col >= (colnr_T)curwin->w_width
+ && width > 0)
+ /* use same formula as what is used in curs_columns() */
+ col -= ((col - curwin->w_width) / width + 1) * width;
+ if (col > (int)curwin->w_leftcol)
+ col -= curwin->w_leftcol;
+ else
+ col = 0;
+ curwin->w_wcol = col;
+
+ curwin->w_valid |= VALID_WCOL;
+ }
+}
+
+/*
+ * Compute offset of a window, occupied by absolute or relative line number,
+ * fold column and sign column (these don't move when scrolling horizontally).
+ */
+ int
+win_col_off(win_T *wp)
+{
+ return (((wp->w_p_nu || wp->w_p_rnu) ? number_width(wp) + 1 : 0)
+#ifdef FEAT_CMDWIN
+ + (cmdwin_type == 0 || wp != curwin ? 0 : 1)
+#endif
+#ifdef FEAT_FOLDING
+ + wp->w_p_fdc
+#endif
+#ifdef FEAT_SIGNS
+ + (signcolumn_on(wp) ? 2 : 0)
+#endif
+ );
+}
+
+ int
+curwin_col_off(void)
+{
+ return win_col_off(curwin);
+}
+
+/*
+ * Return the difference in column offset for the second screen line of a
+ * wrapped line. It's 8 if 'number' or 'relativenumber' is on and 'n' is in
+ * 'cpoptions'.
+ */
+ int
+win_col_off2(win_T *wp)
+{
+ if ((wp->w_p_nu || wp->w_p_rnu) && vim_strchr(p_cpo, CPO_NUMCOL) != NULL)
+ return number_width(wp) + 1;
+ return 0;
+}
+
+ int
+curwin_col_off2(void)
+{
+ return win_col_off2(curwin);
+}
+
+/*
+ * Compute curwin->w_wcol and curwin->w_virtcol.
+ * Also updates curwin->w_wrow and curwin->w_cline_row.
+ * Also updates curwin->w_leftcol.
+ */
+ void
+curs_columns(
+ int may_scroll) /* when TRUE, may scroll horizontally */
+{
+ int diff;
+ int extra; /* offset for first screen line */
+ int off_left, off_right;
+ int n;
+ int p_lines;
+ int width = 0;
+ int textwidth;
+ int new_leftcol;
+ colnr_T startcol;
+ colnr_T endcol;
+ colnr_T prev_skipcol;
+ long so = get_scrolloff_value();
+ long siso = get_sidescrolloff_value();
+
+ /*
+ * First make sure that w_topline is valid (after moving the cursor).
+ */
+ update_topline();
+
+ /*
+ * Next make sure that w_cline_row is valid.
+ */
+ if (!(curwin->w_valid & VALID_CROW))
+ curs_rows(curwin);
+
+ /*
+ * Compute the number of virtual columns.
+ */
+#ifdef FEAT_FOLDING
+ if (curwin->w_cline_folded)
+ /* In a folded line the cursor is always in the first column */
+ startcol = curwin->w_virtcol = endcol = curwin->w_leftcol;
+ else
+#endif
+ getvvcol(curwin, &curwin->w_cursor,
+ &startcol, &(curwin->w_virtcol), &endcol);
+
+ /* remove '$' from change command when cursor moves onto it */
+ if (startcol > dollar_vcol)
+ dollar_vcol = -1;
+
+ extra = curwin_col_off();
+ curwin->w_wcol = curwin->w_virtcol + extra;
+ endcol += extra;
+
+ /*
+ * Now compute w_wrow, counting screen lines from w_cline_row.
+ */
+ curwin->w_wrow = curwin->w_cline_row;
+
+ textwidth = curwin->w_width - extra;
+ if (textwidth <= 0)
+ {
+ /* No room for text, put cursor in last char of window. */
+ curwin->w_wcol = curwin->w_width - 1;
+ curwin->w_wrow = curwin->w_height - 1;
+ }
+ else if (curwin->w_p_wrap && curwin->w_width != 0)
+ {
+ width = textwidth + curwin_col_off2();
+
+ /* long line wrapping, adjust curwin->w_wrow */
+ if (curwin->w_wcol >= curwin->w_width)
+ {
+ /* this same formula is used in validate_cursor_col() */
+ n = (curwin->w_wcol - curwin->w_width) / width + 1;
+ curwin->w_wcol -= n * width;
+ curwin->w_wrow += n;
+
+#ifdef FEAT_LINEBREAK
+ /* When cursor wraps to first char of next line in Insert
+ * mode, the 'showbreak' string isn't shown, backup to first
+ * column */
+ if (*p_sbr && *ml_get_cursor() == NUL
+ && curwin->w_wcol == (int)vim_strsize(p_sbr))
+ curwin->w_wcol = 0;
+#endif
+ }
+ }
+
+ /* No line wrapping: compute curwin->w_leftcol if scrolling is on and line
+ * is not folded.
+ * If scrolling is off, curwin->w_leftcol is assumed to be 0 */
+ else if (may_scroll
+#ifdef FEAT_FOLDING
+ && !curwin->w_cline_folded
+#endif
+ )
+ {
+ /*
+ * If Cursor is left of the screen, scroll rightwards.
+ * If Cursor is right of the screen, scroll leftwards
+ * If we get closer to the edge than 'sidescrolloff', scroll a little
+ * extra
+ */
+ off_left = (int)startcol - (int)curwin->w_leftcol - siso;
+ off_right = (int)endcol - (int)(curwin->w_leftcol + curwin->w_width
+ - siso) + 1;
+ if (off_left < 0 || off_right > 0)
+ {
+ if (off_left < 0)
+ diff = -off_left;
+ else
+ diff = off_right;
+
+ /* When far off or not enough room on either side, put cursor in
+ * middle of window. */
+ if (p_ss == 0 || diff >= textwidth / 2 || off_right >= off_left)
+ new_leftcol = curwin->w_wcol - extra - textwidth / 2;
+ else
+ {
+ if (diff < p_ss)
+ diff = p_ss;
+ if (off_left < 0)
+ new_leftcol = curwin->w_leftcol - diff;
+ else
+ new_leftcol = curwin->w_leftcol + diff;
+ }
+ if (new_leftcol < 0)
+ new_leftcol = 0;
+ if (new_leftcol != (int)curwin->w_leftcol)
+ {
+ curwin->w_leftcol = new_leftcol;
+ /* screen has to be redrawn with new curwin->w_leftcol */
+ redraw_later(NOT_VALID);
+ }
+ }
+ curwin->w_wcol -= curwin->w_leftcol;
+ }
+ else if (curwin->w_wcol > (int)curwin->w_leftcol)
+ curwin->w_wcol -= curwin->w_leftcol;
+ else
+ curwin->w_wcol = 0;
+
+#ifdef FEAT_DIFF
+ /* Skip over filler lines. At the top use w_topfill, there
+ * may be some filler lines above the window. */
+ if (curwin->w_cursor.lnum == curwin->w_topline)
+ curwin->w_wrow += curwin->w_topfill;
+ else
+ curwin->w_wrow += diff_check_fill(curwin, curwin->w_cursor.lnum);
+#endif
+
+ prev_skipcol = curwin->w_skipcol;
+
+ p_lines = 0;
+
+ if ((curwin->w_wrow >= curwin->w_height
+ || ((prev_skipcol > 0
+ || curwin->w_wrow + so >= curwin->w_height)
+ && (p_lines =
+#ifdef FEAT_DIFF
+ plines_win_nofill
+#else
+ plines_win
+#endif
+ (curwin, curwin->w_cursor.lnum, FALSE))
+ - 1 >= curwin->w_height))
+ && curwin->w_height != 0
+ && curwin->w_cursor.lnum == curwin->w_topline
+ && width > 0
+ && curwin->w_width != 0)
+ {
+ /* Cursor past end of screen. Happens with a single line that does
+ * not fit on screen. Find a skipcol to show the text around the
+ * cursor. Avoid scrolling all the time. compute value of "extra":
+ * 1: Less than 'scrolloff' lines above
+ * 2: Less than 'scrolloff' lines below
+ * 3: both of them */
+ extra = 0;
+ if (curwin->w_skipcol + so * width > curwin->w_virtcol)
+ extra = 1;
+ /* Compute last display line of the buffer line that we want at the
+ * bottom of the window. */
+ if (p_lines == 0)
+ p_lines = plines_win(curwin, curwin->w_cursor.lnum, FALSE);
+ --p_lines;
+ if (p_lines > curwin->w_wrow + so)
+ n = curwin->w_wrow + so;
+ else
+ n = p_lines;
+ if ((colnr_T)n >= curwin->w_height + curwin->w_skipcol / width)
+ extra += 2;
+
+ if (extra == 3 || p_lines < so * 2)
+ {
+ /* not enough room for 'scrolloff', put cursor in the middle */
+ n = curwin->w_virtcol / width;
+ if (n > curwin->w_height / 2)
+ n -= curwin->w_height / 2;
+ else
+ n = 0;
+ /* don't skip more than necessary */
+ if (n > p_lines - curwin->w_height + 1)
+ n = p_lines - curwin->w_height + 1;
+ curwin->w_skipcol = n * width;
+ }
+ else if (extra == 1)
+ {
+ /* less then 'scrolloff' lines above, decrease skipcol */
+ extra = (curwin->w_skipcol + so * width - curwin->w_virtcol
+ + width - 1) / width;
+ if (extra > 0)
+ {
+ if ((colnr_T)(extra * width) > curwin->w_skipcol)
+ extra = curwin->w_skipcol / width;
+ curwin->w_skipcol -= extra * width;
+ }
+ }
+ else if (extra == 2)
+ {
+ /* less then 'scrolloff' lines below, increase skipcol */
+ endcol = (n - curwin->w_height + 1) * width;
+ while (endcol > curwin->w_virtcol)
+ endcol -= width;
+ if (endcol > curwin->w_skipcol)
+ curwin->w_skipcol = endcol;
+ }
+
+ curwin->w_wrow -= curwin->w_skipcol / width;
+ if (curwin->w_wrow >= curwin->w_height)
+ {
+ /* small window, make sure cursor is in it */
+ extra = curwin->w_wrow - curwin->w_height + 1;
+ curwin->w_skipcol += extra * width;
+ curwin->w_wrow -= extra;
+ }
+
+ extra = ((int)prev_skipcol - (int)curwin->w_skipcol) / width;
+ if (extra > 0)
+ win_ins_lines(curwin, 0, extra, FALSE, FALSE);
+ else if (extra < 0)
+ win_del_lines(curwin, 0, -extra, FALSE, FALSE, 0);
+ }
+ else
+ curwin->w_skipcol = 0;
+ if (prev_skipcol != curwin->w_skipcol)
+ redraw_later(NOT_VALID);
+
+#ifdef FEAT_SYN_HL
+ /* Redraw when w_virtcol changes and 'cursorcolumn' is set */
+ if (curwin->w_p_cuc && (curwin->w_valid & VALID_VIRTCOL) == 0
+# ifdef FEAT_INS_EXPAND
+ && !pum_visible()
+# endif
+ )
+ redraw_later(SOME_VALID);
+#endif
+
+ curwin->w_valid |= VALID_WCOL|VALID_WROW|VALID_VIRTCOL;
+}
+
+/*
+ * Scroll the current window down by "line_count" logical lines. "CTRL-Y"
+ */
+ void
+scrolldown(
+ long line_count,
+ int byfold UNUSED) /* TRUE: count a closed fold as one line */
+{
+ long done = 0; /* total # of physical lines done */
+ int wrow;
+ int moved = FALSE;
+
+#ifdef FEAT_FOLDING
+ linenr_T first;
+
+ /* Make sure w_topline is at the first of a sequence of folded lines. */
+ (void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
+#endif
+ validate_cursor(); /* w_wrow needs to be valid */
+ while (line_count-- > 0)
+ {
+#ifdef FEAT_DIFF
+ if (curwin->w_topfill < diff_check(curwin, curwin->w_topline)
+ && curwin->w_topfill < curwin->w_height - 1)
+ {
+ ++curwin->w_topfill;
+ ++done;
+ }
+ else
+#endif
+ {
+ if (curwin->w_topline == 1)
+ break;
+ --curwin->w_topline;
+#ifdef FEAT_DIFF
+ curwin->w_topfill = 0;
+#endif
+#ifdef FEAT_FOLDING
+ /* A sequence of folded lines only counts for one logical line */
+ if (hasFolding(curwin->w_topline, &first, NULL))
+ {
+ ++done;
+ if (!byfold)
+ line_count -= curwin->w_topline - first - 1;
+ curwin->w_botline -= curwin->w_topline - first;
+ curwin->w_topline = first;
+ }
+ else
+#endif
+ done += PLINES_NOFILL(curwin->w_topline);
+ }
+ --curwin->w_botline; /* approximate w_botline */
+ invalidate_botline();
+ }
+ curwin->w_wrow += done; /* keep w_wrow updated */
+ curwin->w_cline_row += done; /* keep w_cline_row updated */
+
+#ifdef FEAT_DIFF
+ if (curwin->w_cursor.lnum == curwin->w_topline)
+ curwin->w_cline_row = 0;
+ check_topfill(curwin, TRUE);
+#endif
+
+ /*
+ * Compute the row number of the last row of the cursor line
+ * and move the cursor onto the displayed part of the window.
+ */
+ wrow = curwin->w_wrow;
+ if (curwin->w_p_wrap && curwin->w_width != 0)
+ {
+ validate_virtcol();
+ validate_cheight();
+ wrow += curwin->w_cline_height - 1 -
+ curwin->w_virtcol / curwin->w_width;
+ }
+ while (wrow >= curwin->w_height && curwin->w_cursor.lnum > 1)
+ {
+#ifdef FEAT_FOLDING
+ if (hasFolding(curwin->w_cursor.lnum, &first, NULL))
+ {
+ --wrow;
+ if (first == 1)
+ curwin->w_cursor.lnum = 1;
+ else
+ curwin->w_cursor.lnum = first - 1;
+ }
+ else
+#endif
+ wrow -= plines(curwin->w_cursor.lnum--);
+ curwin->w_valid &=
+ ~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW|VALID_VIRTCOL);
+ moved = TRUE;
+ }
+ if (moved)
+ {
+#ifdef FEAT_FOLDING
+ /* Move cursor to first line of closed fold. */
+ foldAdjustCursor();
+#endif
+ coladvance(curwin->w_curswant);
+ }
+}
+
+/*
+ * Scroll the current window up by "line_count" logical lines. "CTRL-E"
+ */
+ void
+scrollup(
+ long line_count,
+ int byfold UNUSED) /* TRUE: count a closed fold as one line */
+{
+#if defined(FEAT_FOLDING) || defined(FEAT_DIFF)
+ linenr_T lnum;
+
+ if (
+# ifdef FEAT_FOLDING
+ (byfold && hasAnyFolding(curwin))
+# ifdef FEAT_DIFF
+ ||
+# endif
+# endif
+# ifdef FEAT_DIFF
+ curwin->w_p_diff
+# endif
+ )
+ {
+ /* count each sequence of folded lines as one logical line */
+ lnum = curwin->w_topline;
+ while (line_count--)
+ {
+# ifdef FEAT_DIFF
+ if (curwin->w_topfill > 0)
+ --curwin->w_topfill;
+ else
+# endif
+ {
+# ifdef FEAT_FOLDING
+ if (byfold)
+ (void)hasFolding(lnum, NULL, &lnum);
+# endif
+ if (lnum >= curbuf->b_ml.ml_line_count)
+ break;
+ ++lnum;
+# ifdef FEAT_DIFF
+ curwin->w_topfill = diff_check_fill(curwin, lnum);
+# endif
+ }
+ }
+ /* approximate w_botline */
+ curwin->w_botline += lnum - curwin->w_topline;
+ curwin->w_topline = lnum;
+ }
+ else
+#endif
+ {
+ curwin->w_topline += line_count;
+ curwin->w_botline += line_count; /* approximate w_botline */
+ }
+
+ if (curwin->w_topline > curbuf->b_ml.ml_line_count)
+ curwin->w_topline = curbuf->b_ml.ml_line_count;
+ if (curwin->w_botline > curbuf->b_ml.ml_line_count + 1)
+ curwin->w_botline = curbuf->b_ml.ml_line_count + 1;
+
+#ifdef FEAT_DIFF
+ check_topfill(curwin, FALSE);
+#endif
+
+#ifdef FEAT_FOLDING
+ if (hasAnyFolding(curwin))
+ /* Make sure w_topline is at the first of a sequence of folded lines. */
+ (void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
+#endif
+
+ curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE);
+ if (curwin->w_cursor.lnum < curwin->w_topline)
+ {
+ curwin->w_cursor.lnum = curwin->w_topline;
+ curwin->w_valid &=
+ ~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW|VALID_VIRTCOL);
+ coladvance(curwin->w_curswant);
+ }
+}
+
+#ifdef FEAT_DIFF
+/*
+ * Don't end up with too many filler lines in the window.
+ */
+ void
+check_topfill(
+ win_T *wp,
+ int down) /* when TRUE scroll down when not enough space */
+{
+ int n;
+
+ if (wp->w_topfill > 0)
+ {
+ n = plines_win_nofill(wp, wp->w_topline, TRUE);
+ if (wp->w_topfill + n > wp->w_height)
+ {
+ if (down && wp->w_topline > 1)
+ {
+ --wp->w_topline;
+ wp->w_topfill = 0;
+ }
+ else
+ {
+ wp->w_topfill = wp->w_height - n;
+ if (wp->w_topfill < 0)
+ wp->w_topfill = 0;
+ }
+ }
+ }
+}
+
+/*
+ * Use as many filler lines as possible for w_topline. Make sure w_topline
+ * is still visible.
+ */
+ static void
+max_topfill(void)
+{
+ int n;
+
+ n = plines_nofill(curwin->w_topline);
+ if (n >= curwin->w_height)
+ curwin->w_topfill = 0;
+ else
+ {
+ curwin->w_topfill = diff_check_fill(curwin, curwin->w_topline);
+ if (curwin->w_topfill + n > curwin->w_height)
+ curwin->w_topfill = curwin->w_height - n;
+ }
+}
+#endif
+
+#if defined(FEAT_INS_EXPAND) || defined(PROTO)
+/*
+ * Scroll the screen one line down, but don't do it if it would move the
+ * cursor off the screen.
+ */
+ void
+scrolldown_clamp(void)
+{
+ int end_row;
+#ifdef FEAT_DIFF
+ int can_fill = (curwin->w_topfill
+ < diff_check_fill(curwin, curwin->w_topline));
+#endif
+
+ if (curwin->w_topline <= 1
+#ifdef FEAT_DIFF
+ && !can_fill
+#endif
+ )
+ return;
+
+ validate_cursor(); /* w_wrow needs to be valid */
+
+ /*
+ * Compute the row number of the last row of the cursor line
+ * and make sure it doesn't go off the screen. Make sure the cursor
+ * doesn't go past 'scrolloff' lines from the screen end.
+ */
+ end_row = curwin->w_wrow;
+#ifdef FEAT_DIFF
+ if (can_fill)
+ ++end_row;
+ else
+ end_row += plines_nofill(curwin->w_topline - 1);
+#else
+ end_row += plines(curwin->w_topline - 1);
+#endif
+ if (curwin->w_p_wrap && curwin->w_width != 0)
+ {
+ validate_cheight();
+ validate_virtcol();
+ end_row += curwin->w_cline_height - 1 -
+ curwin->w_virtcol / curwin->w_width;
+ }
+ if (end_row < curwin->w_height - get_scrolloff_value())
+ {
+#ifdef FEAT_DIFF
+ if (can_fill)
+ {
+ ++curwin->w_topfill;
+ check_topfill(curwin, TRUE);
+ }
+ else
+ {
+ --curwin->w_topline;
+ curwin->w_topfill = 0;
+ }
+#else
+ --curwin->w_topline;
+#endif
+#ifdef FEAT_FOLDING
+ (void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
+#endif
+ --curwin->w_botline; /* approximate w_botline */
+ curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE);
+ }
+}
+
+/*
+ * Scroll the screen one line up, but don't do it if it would move the cursor
+ * off the screen.
+ */
+ void
+scrollup_clamp(void)
+{
+ int start_row;
+
+ if (curwin->w_topline == curbuf->b_ml.ml_line_count
+#ifdef FEAT_DIFF
+ && curwin->w_topfill == 0
+#endif
+ )
+ return;
+
+ validate_cursor(); /* w_wrow needs to be valid */
+
+ /*
+ * Compute the row number of the first row of the cursor line
+ * and make sure it doesn't go off the screen. Make sure the cursor
+ * doesn't go before 'scrolloff' lines from the screen start.
+ */
+#ifdef FEAT_DIFF
+ start_row = curwin->w_wrow - plines_nofill(curwin->w_topline)
+ - curwin->w_topfill;
+#else
+ start_row = curwin->w_wrow - plines(curwin->w_topline);
+#endif
+ if (curwin->w_p_wrap && curwin->w_width != 0)
+ {
+ validate_virtcol();
+ start_row -= curwin->w_virtcol / curwin->w_width;
+ }
+ if (start_row >= get_scrolloff_value())
+ {
+#ifdef FEAT_DIFF
+ if (curwin->w_topfill > 0)
+ --curwin->w_topfill;
+ else
+#endif
+ {
+#ifdef FEAT_FOLDING
+ (void)hasFolding(curwin->w_topline, NULL, &curwin->w_topline);
+#endif
+ ++curwin->w_topline;
+ }
+ ++curwin->w_botline; /* approximate w_botline */
+ curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE);
+ }
+}
+#endif /* FEAT_INS_EXPAND */
+
+/*
+ * Add one line above "lp->lnum". This can be a filler line, a closed fold or
+ * a (wrapped) text line. Uses and sets "lp->fill".
+ * Returns the height of the added line in "lp->height".
+ * Lines above the first one are incredibly high: MAXCOL.
+ */
+ static void
+topline_back(lineoff_T *lp)
+{
+#ifdef FEAT_DIFF
+ if (lp->fill < diff_check_fill(curwin, lp->lnum))
+ {
+ /* Add a filler line. */
+ ++lp->fill;
+ lp->height = 1;
+ }
+ else
+#endif
+ {
+ --lp->lnum;
+#ifdef FEAT_DIFF
+ lp->fill = 0;
+#endif
+ if (lp->lnum < 1)
+ lp->height = MAXCOL;
+ else
+#ifdef FEAT_FOLDING
+ if (hasFolding(lp->lnum, &lp->lnum, NULL))
+ /* Add a closed fold */
+ lp->height = 1;
+ else
+#endif
+ lp->height = PLINES_NOFILL(lp->lnum);
+ }
+}
+
+/*
+ * Add one line below "lp->lnum". This can be a filler line, a closed fold or
+ * a (wrapped) text line. Uses and sets "lp->fill".
+ * Returns the height of the added line in "lp->height".
+ * Lines below the last one are incredibly high.
+ */
+ static void
+botline_forw(lineoff_T *lp)
+{
+#ifdef FEAT_DIFF
+ if (lp->fill < diff_check_fill(curwin, lp->lnum + 1))
+ {
+ /* Add a filler line. */
+ ++lp->fill;
+ lp->height = 1;
+ }
+ else
+#endif
+ {
+ ++lp->lnum;
+#ifdef FEAT_DIFF
+ lp->fill = 0;
+#endif
+ if (lp->lnum > curbuf->b_ml.ml_line_count)
+ lp->height = MAXCOL;
+ else
+#ifdef FEAT_FOLDING
+ if (hasFolding(lp->lnum, NULL, &lp->lnum))
+ /* Add a closed fold */
+ lp->height = 1;
+ else
+#endif
+ {
+ lp->height = PLINES_NOFILL(lp->lnum);
+ }
+ }
+}
+
+#ifdef FEAT_DIFF
+/*
+ * Switch from including filler lines below lp->lnum to including filler
+ * lines above loff.lnum + 1. This keeps pointing to the same line.
+ * When there are no filler lines nothing changes.
+ */
+ static void
+botline_topline(lineoff_T *lp)
+{
+ if (lp->fill > 0)
+ {
+ ++lp->lnum;
+ lp->fill = diff_check_fill(curwin, lp->lnum) - lp->fill + 1;
+ }
+}
+
+/*
+ * Switch from including filler lines above lp->lnum to including filler
+ * lines below loff.lnum - 1. This keeps pointing to the same line.
+ * When there are no filler lines nothing changes.
+ */
+ static void
+topline_botline(lineoff_T *lp)
+{
+ if (lp->fill > 0)
+ {
+ lp->fill = diff_check_fill(curwin, lp->lnum) - lp->fill + 1;
+ --lp->lnum;
+ }
+}
+#endif
+
+/*
+ * Recompute topline to put the cursor at the top of the window.
+ * Scroll at least "min_scroll" lines.
+ * If "always" is TRUE, always set topline (for "zt").
+ */
+ void
+scroll_cursor_top(int min_scroll, int always)
+{
+ int scrolled = 0;
+ int extra = 0;
+ int used;
+ int i;
+ linenr_T top; /* just above displayed lines */
+ linenr_T bot; /* just below displayed lines */
+ linenr_T old_topline = curwin->w_topline;
+#ifdef FEAT_DIFF
+ linenr_T old_topfill = curwin->w_topfill;
+#endif
+ linenr_T new_topline;
+ int off = get_scrolloff_value();
+
+#ifdef FEAT_MOUSE
+ if (mouse_dragging > 0)
+ off = mouse_dragging - 1;
+#endif
+
+ /*
+ * Decrease topline until:
+ * - it has become 1
+ * - (part of) the cursor line is moved off the screen or
+ * - moved at least 'scrolljump' lines and
+ * - at least 'scrolloff' lines above and below the cursor
+ */
+ validate_cheight();
+ used = curwin->w_cline_height; /* includes filler lines above */
+ if (curwin->w_cursor.lnum < curwin->w_topline)
+ scrolled = used;
+
+#ifdef FEAT_FOLDING
+ if (hasFolding(curwin->w_cursor.lnum, &top, &bot))
+ {
+ --top;
+ ++bot;
+ }
+ else
+#endif
+ {
+ top = curwin->w_cursor.lnum - 1;
+ bot = curwin->w_cursor.lnum + 1;
+ }
+ new_topline = top + 1;
+
+#ifdef FEAT_DIFF
+ /* "used" already contains the number of filler lines above, don't add it
+ * again.
+ * Hide filler lines above cursor line by adding them to "extra". */
+ extra += diff_check_fill(curwin, curwin->w_cursor.lnum);
+#endif
+
+ /*
+ * Check if the lines from "top" to "bot" fit in the window. If they do,
+ * set new_topline and advance "top" and "bot" to include more lines.
+ */
+ while (top > 0)
+ {
+#ifdef FEAT_FOLDING
+ if (hasFolding(top, &top, NULL))
+ /* count one logical line for a sequence of folded lines */
+ i = 1;
+ else
+#endif
+ i = PLINES_NOFILL(top);
+ used += i;
+ if (extra + i <= off && bot < curbuf->b_ml.ml_line_count)
+ {
+#ifdef FEAT_FOLDING
+ if (hasFolding(bot, NULL, &bot))
+ /* count one logical line for a sequence of folded lines */
+ ++used;
+ else
+#endif
+ used += plines(bot);
+ }
+ if (used > curwin->w_height)
+ break;
+ if (top < curwin->w_topline)
+ scrolled += i;
+
+ /*
+ * If scrolling is needed, scroll at least 'sj' lines.
+ */
+ if ((new_topline >= curwin->w_topline || scrolled > min_scroll)
+ && extra >= off)
+ break;
+
+ extra += i;
+ new_topline = top;
+ --top;
+ ++bot;
+ }
+
+ /*
+ * If we don't have enough space, put cursor in the middle.
+ * This makes sure we get the same position when using "k" and "j"
+ * in a small window.
+ */
+ if (used > curwin->w_height)
+ scroll_cursor_halfway(FALSE);
+ else
+ {
+ /*
+ * If "always" is FALSE, only adjust topline to a lower value, higher
+ * value may happen with wrapping lines
+ */
+ if (new_topline < curwin->w_topline || always)
+ curwin->w_topline = new_topline;
+ if (curwin->w_topline > curwin->w_cursor.lnum)
+ curwin->w_topline = curwin->w_cursor.lnum;
+#ifdef FEAT_DIFF
+ curwin->w_topfill = diff_check_fill(curwin, curwin->w_topline);
+ if (curwin->w_topfill > 0 && extra > off)
+ {
+ curwin->w_topfill -= extra - off;
+ if (curwin->w_topfill < 0)
+ curwin->w_topfill = 0;
+ }
+ check_topfill(curwin, FALSE);
+#endif
+ if (curwin->w_topline != old_topline
+#ifdef FEAT_DIFF
+ || curwin->w_topfill != old_topfill
+#endif
+ )
+ curwin->w_valid &=
+ ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP);
+ curwin->w_valid |= VALID_TOPLINE;
+ }
+}
+
+/*
+ * Set w_empty_rows and w_filler_rows for window "wp", having used up "used"
+ * screen lines for text lines.
+ */
+ void
+set_empty_rows(win_T *wp, int used)
+{
+#ifdef FEAT_DIFF
+ wp->w_filler_rows = 0;
+#endif
+ if (used == 0)
+ wp->w_empty_rows = 0; /* single line that doesn't fit */
+ else
+ {
+ wp->w_empty_rows = wp->w_height - used;
+#ifdef FEAT_DIFF
+ if (wp->w_botline <= wp->w_buffer->b_ml.ml_line_count)
+ {
+ wp->w_filler_rows = diff_check_fill(wp, wp->w_botline);
+ if (wp->w_empty_rows > wp->w_filler_rows)
+ wp->w_empty_rows -= wp->w_filler_rows;
+ else
+ {
+ wp->w_filler_rows = wp->w_empty_rows;
+ wp->w_empty_rows = 0;
+ }
+ }
+#endif
+ }
+}
+
+/*
+ * Recompute topline to put the cursor at the bottom of the window.
+ * Scroll at least "min_scroll" lines.
+ * If "set_topbot" is TRUE, set topline and botline first (for "zb").
+ * This is messy stuff!!!
+ */
+ void
+scroll_cursor_bot(int min_scroll, int set_topbot)
+{
+ int used;
+ int scrolled = 0;
+ int extra = 0;
+ int i;
+ linenr_T line_count;
+ linenr_T old_topline = curwin->w_topline;
+ lineoff_T loff;
+ lineoff_T boff;
+#ifdef FEAT_DIFF
+ int old_topfill = curwin->w_topfill;
+ int fill_below_window;
+#endif
+ linenr_T old_botline = curwin->w_botline;
+ linenr_T old_valid = curwin->w_valid;
+ int old_empty_rows = curwin->w_empty_rows;
+ linenr_T cln; /* Cursor Line Number */
+ long so = get_scrolloff_value();
+
+ cln = curwin->w_cursor.lnum;
+ if (set_topbot)
+ {
+ used = 0;
+ curwin->w_botline = cln + 1;
+#ifdef FEAT_DIFF
+ loff.fill = 0;
+#endif
+ for (curwin->w_topline = curwin->w_botline;
+ curwin->w_topline > 1;
+ curwin->w_topline = loff.lnum)
+ {
+ loff.lnum = curwin->w_topline;
+ topline_back(&loff);
+ if (loff.height == MAXCOL || used + loff.height > curwin->w_height)
+ break;
+ used += loff.height;
+#ifdef FEAT_DIFF
+ curwin->w_topfill = loff.fill;
+#endif
+ }
+ set_empty_rows(curwin, used);
+ curwin->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP;
+ if (curwin->w_topline != old_topline
+#ifdef FEAT_DIFF
+ || curwin->w_topfill != old_topfill
+#endif
+ )
+ curwin->w_valid &= ~(VALID_WROW|VALID_CROW);
+ }
+ else
+ validate_botline();
+
+ /* The lines of the cursor line itself are always used. */
+#ifdef FEAT_DIFF
+ used = plines_nofill(cln);
+#else
+ validate_cheight();
+ used = curwin->w_cline_height;
+#endif
+
+ /* If the cursor is below botline, we will at least scroll by the height
+ * of the cursor line. Correct for empty lines, which are really part of
+ * botline. */
+ if (cln >= curwin->w_botline)
+ {
+ scrolled = used;
+ if (cln == curwin->w_botline)
+ scrolled -= curwin->w_empty_rows;
+ }
+
+ /*
+ * Stop counting lines to scroll when
+ * - hitting start of the file
+ * - scrolled nothing or at least 'sj' lines
+ * - at least 'scrolloff' lines below the cursor
+ * - lines between botline and cursor have been counted
+ */
+#ifdef FEAT_FOLDING
+ if (!hasFolding(curwin->w_cursor.lnum, &loff.lnum, &boff.lnum))
+#endif
+ {
+ loff.lnum = cln;
+ boff.lnum = cln;
+ }
+#ifdef FEAT_DIFF
+ loff.fill = 0;
+ boff.fill = 0;
+ fill_below_window = diff_check_fill(curwin, curwin->w_botline)
+ - curwin->w_filler_rows;
+#endif
+
+ while (loff.lnum > 1)
+ {
+ /* Stop when scrolled nothing or at least "min_scroll", found "extra"
+ * context for 'scrolloff' and counted all lines below the window. */
+ if ((((scrolled <= 0 || scrolled >= min_scroll)
+ && extra >= (
+#ifdef FEAT_MOUSE
+ mouse_dragging > 0 ? mouse_dragging - 1 :
+#endif
+ so))
+ || boff.lnum + 1 > curbuf->b_ml.ml_line_count)
+ && loff.lnum <= curwin->w_botline
+#ifdef FEAT_DIFF
+ && (loff.lnum < curwin->w_botline
+ || loff.fill >= fill_below_window)
+#endif
+ )
+ break;
+
+ /* Add one line above */
+ topline_back(&loff);
+ if (loff.height == MAXCOL)
+ used = MAXCOL;
+ else
+ used += loff.height;
+ if (used > curwin->w_height)
+ break;
+ if (loff.lnum >= curwin->w_botline
+#ifdef FEAT_DIFF
+ && (loff.lnum > curwin->w_botline
+ || loff.fill <= fill_below_window)
+#endif
+ )
+ {
+ /* Count screen lines that are below the window. */
+ scrolled += loff.height;
+ if (loff.lnum == curwin->w_botline
+#ifdef FEAT_DIFF
+ && loff.fill == 0
+#endif
+ )
+ scrolled -= curwin->w_empty_rows;
+ }
+
+ if (boff.lnum < curbuf->b_ml.ml_line_count)
+ {
+ /* Add one line below */
+ botline_forw(&boff);
+ used += boff.height;
+ if (used > curwin->w_height)
+ break;
+ if (extra < (
+#ifdef FEAT_MOUSE
+ mouse_dragging > 0 ? mouse_dragging - 1 :
+#endif
+ so) || scrolled < min_scroll)
+ {
+ extra += boff.height;
+ if (boff.lnum >= curwin->w_botline
+#ifdef FEAT_DIFF
+ || (boff.lnum + 1 == curwin->w_botline
+ && boff.fill > curwin->w_filler_rows)
+#endif
+ )
+ {
+ /* Count screen lines that are below the window. */
+ scrolled += boff.height;
+ if (boff.lnum == curwin->w_botline
+#ifdef FEAT_DIFF
+ && boff.fill == 0
+#endif
+ )
+ scrolled -= curwin->w_empty_rows;
+ }
+ }
+ }
+ }
+
+ /* curwin->w_empty_rows is larger, no need to scroll */
+ if (scrolled <= 0)
+ line_count = 0;
+ /* more than a screenfull, don't scroll but redraw */
+ else if (used > curwin->w_height)
+ line_count = used;
+ /* scroll minimal number of lines */
+ else
+ {
+ line_count = 0;
+#ifdef FEAT_DIFF
+ boff.fill = curwin->w_topfill;
+#endif
+ boff.lnum = curwin->w_topline - 1;
+ for (i = 0; i < scrolled && boff.lnum < curwin->w_botline; )
+ {
+ botline_forw(&boff);
+ i += boff.height;
+ ++line_count;
+ }
+ if (i < scrolled) /* below curwin->w_botline, don't scroll */
+ line_count = 9999;
+ }
+
+ /*
+ * Scroll up if the cursor is off the bottom of the screen a bit.
+ * Otherwise put it at 1/2 of the screen.
+ */
+ if (line_count >= curwin->w_height && line_count > min_scroll)
+ scroll_cursor_halfway(FALSE);
+ else
+ scrollup(line_count, TRUE);
+
+ /*
+ * If topline didn't change we need to restore w_botline and w_empty_rows
+ * (we changed them).
+ * If topline did change, update_screen() will set botline.
+ */
+ if (curwin->w_topline == old_topline && set_topbot)
+ {
+ curwin->w_botline = old_botline;
+ curwin->w_empty_rows = old_empty_rows;
+ curwin->w_valid = old_valid;
+ }
+ curwin->w_valid |= VALID_TOPLINE;
+}
+
+/*
+ * Recompute topline to put the cursor halfway the window
+ * If "atend" is TRUE, also put it halfway at the end of the file.
+ */
+ void
+scroll_cursor_halfway(int atend)
+{
+ int above = 0;
+ linenr_T topline;
+#ifdef FEAT_DIFF
+ int topfill = 0;
+#endif
+ int below = 0;
+ int used;
+ lineoff_T loff;
+ lineoff_T boff;
+#ifdef FEAT_DIFF
+ linenr_T old_topline = curwin->w_topline;
+#endif
+
+ loff.lnum = boff.lnum = curwin->w_cursor.lnum;
+#ifdef FEAT_FOLDING
+ (void)hasFolding(loff.lnum, &loff.lnum, &boff.lnum);
+#endif
+#ifdef FEAT_DIFF
+ used = plines_nofill(loff.lnum);
+ loff.fill = 0;
+ boff.fill = 0;
+#else
+ used = plines(loff.lnum);
+#endif
+ topline = loff.lnum;
+ while (topline > 1)
+ {
+ if (below <= above) /* add a line below the cursor first */
+ {
+ if (boff.lnum < curbuf->b_ml.ml_line_count)
+ {
+ botline_forw(&boff);
+ used += boff.height;
+ if (used > curwin->w_height)
+ break;
+ below += boff.height;
+ }
+ else
+ {
+ ++below; /* count a "~" line */
+ if (atend)
+ ++used;
+ }
+ }
+
+ if (below > above) /* add a line above the cursor */
+ {
+ topline_back(&loff);
+ if (loff.height == MAXCOL)
+ used = MAXCOL;
+ else
+ used += loff.height;
+ if (used > curwin->w_height)
+ break;
+ above += loff.height;
+ topline = loff.lnum;
+#ifdef FEAT_DIFF
+ topfill = loff.fill;
+#endif
+ }
+ }
+#ifdef FEAT_FOLDING
+ if (!hasFolding(topline, &curwin->w_topline, NULL))
+#endif
+ curwin->w_topline = topline;
+#ifdef FEAT_DIFF
+ curwin->w_topfill = topfill;
+ if (old_topline > curwin->w_topline + curwin->w_height)
+ curwin->w_botfill = FALSE;
+ check_topfill(curwin, FALSE);
+#endif
+ curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP);
+ curwin->w_valid |= VALID_TOPLINE;
+}
+
+/*
+ * Correct the cursor position so that it is in a part of the screen at least
+ * 'scrolloff' lines from the top and bottom, if possible.
+ * If not possible, put it at the same position as scroll_cursor_halfway().
+ * When called topline must be valid!
+ */
+ void
+cursor_correct(void)
+{
+ int above = 0; /* screen lines above topline */
+ linenr_T topline;
+ int below = 0; /* screen lines below botline */
+ linenr_T botline;
+ int above_wanted, below_wanted;
+ linenr_T cln; /* Cursor Line Number */
+ int max_off;
+ long so = get_scrolloff_value();
+
+ /*
+ * How many lines we would like to have above/below the cursor depends on
+ * whether the first/last line of the file is on screen.
+ */
+ above_wanted = so;
+ below_wanted = so;
+#ifdef FEAT_MOUSE
+ if (mouse_dragging > 0)
+ {
+ above_wanted = mouse_dragging - 1;
+ below_wanted = mouse_dragging - 1;
+ }
+#endif
+ if (curwin->w_topline == 1)
+ {
+ above_wanted = 0;
+ max_off = curwin->w_height / 2;
+ if (below_wanted > max_off)
+ below_wanted = max_off;
+ }
+ validate_botline();
+ if (curwin->w_botline == curbuf->b_ml.ml_line_count + 1
+#ifdef FEAT_MOUSE
+ && mouse_dragging == 0
+#endif
+ )
+ {
+ below_wanted = 0;
+ max_off = (curwin->w_height - 1) / 2;
+ if (above_wanted > max_off)
+ above_wanted = max_off;
+ }
+
+ /*
+ * If there are sufficient file-lines above and below the cursor, we can
+ * return now.
+ */
+ cln = curwin->w_cursor.lnum;
+ if (cln >= curwin->w_topline + above_wanted
+ && cln < curwin->w_botline - below_wanted
+#ifdef FEAT_FOLDING
+ && !hasAnyFolding(curwin)
+#endif
+ )
+ return;
+
+ /*
+ * Narrow down the area where the cursor can be put by taking lines from
+ * the top and the bottom until:
+ * - the desired context lines are found
+ * - the lines from the top is past the lines from the bottom
+ */
+ topline = curwin->w_topline;
+ botline = curwin->w_botline - 1;
+#ifdef FEAT_DIFF
+ /* count filler lines as context */
+ above = curwin->w_topfill;
+ below = curwin->w_filler_rows;
+#endif
+ while ((above < above_wanted || below < below_wanted) && topline < botline)
+ {
+ if (below < below_wanted && (below <= above || above >= above_wanted))
+ {
+#ifdef FEAT_FOLDING
+ if (hasFolding(botline, &botline, NULL))
+ ++below;
+ else
+#endif
+ below += plines(botline);
+ --botline;
+ }
+ if (above < above_wanted && (above < below || below >= below_wanted))
+ {
+#ifdef FEAT_FOLDING
+ if (hasFolding(topline, NULL, &topline))
+ ++above;
+ else
+#endif
+ above += PLINES_NOFILL(topline);
+#ifdef FEAT_DIFF
+ /* Count filler lines below this line as context. */
+ if (topline < botline)
+ above += diff_check_fill(curwin, topline + 1);
+#endif
+ ++topline;
+ }
+ }
+ if (topline == botline || botline == 0)
+ curwin->w_cursor.lnum = topline;
+ else if (topline > botline)
+ curwin->w_cursor.lnum = botline;
+ else
+ {
+ if (cln < topline && curwin->w_topline > 1)
+ {
+ curwin->w_cursor.lnum = topline;
+ curwin->w_valid &=
+ ~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW);
+ }
+ if (cln > botline && curwin->w_botline <= curbuf->b_ml.ml_line_count)
+ {
+ curwin->w_cursor.lnum = botline;
+ curwin->w_valid &=
+ ~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW);
+ }
+ }
+ curwin->w_valid |= VALID_TOPLINE;
+}
+
+static void get_scroll_overlap(lineoff_T *lp, int dir);
+
+/*
+ * move screen 'count' pages up or down and update screen
+ *
+ * return FAIL for failure, OK otherwise
+ */
+ int
+onepage(int dir, long count)
+{
+ long n;
+ int retval = OK;
+ lineoff_T loff;
+ linenr_T old_topline = curwin->w_topline;
+ long so = get_scrolloff_value();
+
+ if (curbuf->b_ml.ml_line_count == 1) /* nothing to do */
+ {
+ beep_flush();
+ return FAIL;
+ }
+
+ for ( ; count > 0; --count)
+ {
+ validate_botline();
+ /*
+ * It's an error to move a page up when the first line is already on
+ * the screen. It's an error to move a page down when the last line
+ * is on the screen and the topline is 'scrolloff' lines from the
+ * last line.
+ */
+ if (dir == FORWARD
+ ? ((curwin->w_topline >= curbuf->b_ml.ml_line_count - so)
+ && curwin->w_botline > curbuf->b_ml.ml_line_count)
+ : (curwin->w_topline == 1
+#ifdef FEAT_DIFF
+ && curwin->w_topfill ==
+ diff_check_fill(curwin, curwin->w_topline)
+#endif
+ ))
+ {
+ beep_flush();
+ retval = FAIL;
+ break;
+ }
+
+#ifdef FEAT_DIFF
+ loff.fill = 0;
+#endif
+ if (dir == FORWARD)
+ {
+ if (ONE_WINDOW && p_window > 0 && p_window < Rows - 1)
+ {
+ /* Vi compatible scrolling */
+ if (p_window <= 2)
+ ++curwin->w_topline;
+ else
+ curwin->w_topline += p_window - 2;
+ if (curwin->w_topline > curbuf->b_ml.ml_line_count)
+ curwin->w_topline = curbuf->b_ml.ml_line_count;
+ curwin->w_cursor.lnum = curwin->w_topline;
+ }
+ else if (curwin->w_botline > curbuf->b_ml.ml_line_count)
+ {
+ /* at end of file */
+ curwin->w_topline = curbuf->b_ml.ml_line_count;
+#ifdef FEAT_DIFF
+ curwin->w_topfill = 0;
+#endif
+ curwin->w_valid &= ~(VALID_WROW|VALID_CROW);
+ }
+ else
+ {
+ /* For the overlap, start with the line just below the window
+ * and go upwards. */
+ loff.lnum = curwin->w_botline;
+#ifdef FEAT_DIFF
+ loff.fill = diff_check_fill(curwin, loff.lnum)
+ - curwin->w_filler_rows;
+#endif
+ get_scroll_overlap(&loff, -1);
+ curwin->w_topline = loff.lnum;
+#ifdef FEAT_DIFF
+ curwin->w_topfill = loff.fill;
+ check_topfill(curwin, FALSE);
+#endif
+ curwin->w_cursor.lnum = curwin->w_topline;
+ curwin->w_valid &= ~(VALID_WCOL|VALID_CHEIGHT|VALID_WROW|
+ VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP);
+ }
+ }
+ else /* dir == BACKWARDS */
+ {
+#ifdef FEAT_DIFF
+ if (curwin->w_topline == 1)
+ {
+ /* Include max number of filler lines */
+ max_topfill();
+ continue;
+ }
+#endif
+ if (ONE_WINDOW && p_window > 0 && p_window < Rows - 1)
+ {
+ /* Vi compatible scrolling (sort of) */
+ if (p_window <= 2)
+ --curwin->w_topline;
+ else
+ curwin->w_topline -= p_window - 2;
+ if (curwin->w_topline < 1)
+ curwin->w_topline = 1;
+ curwin->w_cursor.lnum = curwin->w_topline + p_window - 1;
+ if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
+ curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
+ continue;
+ }
+
+ /* Find the line at the top of the window that is going to be the
+ * line at the bottom of the window. Make sure this results in
+ * the same line as before doing CTRL-F. */
+ loff.lnum = curwin->w_topline - 1;
+#ifdef FEAT_DIFF
+ loff.fill = diff_check_fill(curwin, loff.lnum + 1)
+ - curwin->w_topfill;
+#endif
+ get_scroll_overlap(&loff, 1);
+
+ if (loff.lnum >= curbuf->b_ml.ml_line_count)
+ {
+ loff.lnum = curbuf->b_ml.ml_line_count;
+#ifdef FEAT_DIFF
+ loff.fill = 0;
+ }
+ else
+ {
+ botline_topline(&loff);
+#endif
+ }
+ curwin->w_cursor.lnum = loff.lnum;
+
+ /* Find the line just above the new topline to get the right line
+ * at the bottom of the window. */
+ n = 0;
+ while (n <= curwin->w_height && loff.lnum >= 1)
+ {
+ topline_back(&loff);
+ if (loff.height == MAXCOL)
+ n = MAXCOL;
+ else
+ n += loff.height;
+ }
+ if (loff.lnum < 1) /* at begin of file */
+ {
+ curwin->w_topline = 1;
+#ifdef FEAT_DIFF
+ max_topfill();
+#endif
+ curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE);
+ }
+ else
+ {
+ /* Go two lines forward again. */
+#ifdef FEAT_DIFF
+ topline_botline(&loff);
+#endif
+ botline_forw(&loff);
+ botline_forw(&loff);
+#ifdef FEAT_DIFF
+ botline_topline(&loff);
+#endif
+#ifdef FEAT_FOLDING
+ /* We're at the wrong end of a fold now. */
+ (void)hasFolding(loff.lnum, &loff.lnum, NULL);
+#endif
+
+ /* Always scroll at least one line. Avoid getting stuck on
+ * very long lines. */
+ if (loff.lnum >= curwin->w_topline
+#ifdef FEAT_DIFF
+ && (loff.lnum > curwin->w_topline
+ || loff.fill >= curwin->w_topfill)
+#endif
+ )
+ {
+#ifdef FEAT_DIFF
+ /* First try using the maximum number of filler lines. If
+ * that's not enough, backup one line. */
+ loff.fill = curwin->w_topfill;
+ if (curwin->w_topfill < diff_check_fill(curwin,
+ curwin->w_topline))
+ max_topfill();
+ if (curwin->w_topfill == loff.fill)
+#endif
+ {
+ --curwin->w_topline;
+#ifdef FEAT_DIFF
+ curwin->w_topfill = 0;
+#endif
+ }
+ comp_botline(curwin);
+ curwin->w_cursor.lnum = curwin->w_botline - 1;
+ curwin->w_valid &=
+ ~(VALID_WCOL|VALID_CHEIGHT|VALID_WROW|VALID_CROW);
+ }
+ else
+ {
+ curwin->w_topline = loff.lnum;
+#ifdef FEAT_DIFF
+ curwin->w_topfill = loff.fill;
+ check_topfill(curwin, FALSE);
+#endif
+ curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE);
+ }
+ }
+ }
+ }
+#ifdef FEAT_FOLDING
+ foldAdjustCursor();
+#endif
+ cursor_correct();
+ check_cursor_col();
+ if (retval == OK)
+ beginline(BL_SOL | BL_FIX);
+ curwin->w_valid &= ~(VALID_WCOL|VALID_WROW|VALID_VIRTCOL);
+
+ if (retval == OK && dir == FORWARD)
+ {
+ // Avoid the screen jumping up and down when 'scrolloff' is non-zero.
+ // But make sure we scroll at least one line (happens with mix of long
+ // wrapping lines and non-wrapping line).
+ if (check_top_offset())
+ {
+ scroll_cursor_top(1, FALSE);
+ if (curwin->w_topline <= old_topline
+ && old_topline < curbuf->b_ml.ml_line_count)
+ {
+ curwin->w_topline = old_topline + 1;
+#ifdef FEAT_FOLDING
+ (void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
+#endif
+ }
+ }
+#ifdef FEAT_FOLDING
+ else if (curwin->w_botline > curbuf->b_ml.ml_line_count)
+ (void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
+#endif
+ }
+
+ redraw_later(VALID);
+ return retval;
+}
+
+/*
+ * Decide how much overlap to use for page-up or page-down scrolling.
+ * This is symmetric, so that doing both keeps the same lines displayed.
+ * Three lines are examined:
+ *
+ * before CTRL-F after CTRL-F / before CTRL-B
+ * etc. l1
+ * l1 last but one line ------------
+ * l2 last text line l2 top text line
+ * ------------- l3 second text line
+ * l3 etc.
+ */
+ static void
+get_scroll_overlap(lineoff_T *lp, int dir)
+{
+ int h1, h2, h3, h4;
+ int min_height = curwin->w_height - 2;
+ lineoff_T loff0, loff1, loff2;
+
+#ifdef FEAT_DIFF
+ if (lp->fill > 0)
+ lp->height = 1;
+ else
+ lp->height = plines_nofill(lp->lnum);
+#else
+ lp->height = plines(lp->lnum);
+#endif
+ h1 = lp->height;
+ if (h1 > min_height)
+ return; /* no overlap */
+
+ loff0 = *lp;
+ if (dir > 0)
+ botline_forw(lp);
+ else
+ topline_back(lp);
+ h2 = lp->height;
+ if (h2 == MAXCOL || h2 + h1 > min_height)
+ {
+ *lp = loff0; /* no overlap */
+ return;
+ }
+
+ loff1 = *lp;
+ if (dir > 0)
+ botline_forw(lp);
+ else
+ topline_back(lp);
+ h3 = lp->height;
+ if (h3 == MAXCOL || h3 + h2 > min_height)
+ {
+ *lp = loff0; /* no overlap */
+ return;
+ }
+
+ loff2 = *lp;
+ if (dir > 0)
+ botline_forw(lp);
+ else
+ topline_back(lp);
+ h4 = lp->height;
+ if (h4 == MAXCOL || h4 + h3 + h2 > min_height || h3 + h2 + h1 > min_height)
+ *lp = loff1; /* 1 line overlap */
+ else
+ *lp = loff2; /* 2 lines overlap */
+ return;
+}
+
+/* #define KEEP_SCREEN_LINE */
+/*
+ * Scroll 'scroll' lines up or down.
+ */
+ void
+halfpage(int flag, linenr_T Prenum)
+{
+ long scrolled = 0;
+ int i;
+ int n;
+ int room;
+
+ if (Prenum)
+ curwin->w_p_scr = (Prenum > curwin->w_height) ?
+ curwin->w_height : Prenum;
+ n = (curwin->w_p_scr <= curwin->w_height) ?
+ curwin->w_p_scr : curwin->w_height;
+
+ update_topline();
+ validate_botline();
+ room = curwin->w_empty_rows;
+#ifdef FEAT_DIFF
+ room += curwin->w_filler_rows;
+#endif
+ if (flag)
+ {
+ /*
+ * scroll the text up
+ */
+ while (n > 0 && curwin->w_botline <= curbuf->b_ml.ml_line_count)
+ {
+#ifdef FEAT_DIFF
+ if (curwin->w_topfill > 0)
+ {
+ i = 1;
+ if (--n < 0 && scrolled > 0)
+ break;
+ --curwin->w_topfill;
+ }
+ else
+#endif
+ {
+ i = PLINES_NOFILL(curwin->w_topline);
+ n -= i;
+ if (n < 0 && scrolled > 0)
+ break;
+#ifdef FEAT_FOLDING
+ (void)hasFolding(curwin->w_topline, NULL, &curwin->w_topline);
+#endif
+ ++curwin->w_topline;
+#ifdef FEAT_DIFF
+ curwin->w_topfill = diff_check_fill(curwin, curwin->w_topline);
+#endif
+
+#ifndef KEEP_SCREEN_LINE
+ if (curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
+ {
+ ++curwin->w_cursor.lnum;
+ curwin->w_valid &=
+ ~(VALID_VIRTCOL|VALID_CHEIGHT|VALID_WCOL);
+ }
+#endif
+ }
+ curwin->w_valid &= ~(VALID_CROW|VALID_WROW);
+ scrolled += i;
+
+ /*
+ * Correct w_botline for changed w_topline.
+ * Won't work when there are filler lines.
+ */
+#ifdef FEAT_DIFF
+ if (curwin->w_p_diff)
+ curwin->w_valid &= ~(VALID_BOTLINE|VALID_BOTLINE_AP);
+ else
+#endif
+ {
+ room += i;
+ do
+ {
+ i = plines(curwin->w_botline);
+ if (i > room)
+ break;
+#ifdef FEAT_FOLDING
+ (void)hasFolding(curwin->w_botline, NULL,
+ &curwin->w_botline);
+#endif
+ ++curwin->w_botline;
+ room -= i;
+ } while (curwin->w_botline <= curbuf->b_ml.ml_line_count);
+ }
+ }
+
+#ifndef KEEP_SCREEN_LINE
+ /*
+ * When hit bottom of the file: move cursor down.
+ */
+ if (n > 0)
+ {
+# ifdef FEAT_FOLDING
+ if (hasAnyFolding(curwin))
+ {
+ while (--n >= 0
+ && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
+ {
+ (void)hasFolding(curwin->w_cursor.lnum, NULL,
+ &curwin->w_cursor.lnum);
+ ++curwin->w_cursor.lnum;
+ }
+ }
+ else
+# endif
+ curwin->w_cursor.lnum += n;
+ check_cursor_lnum();
+ }
+#else
+ /* try to put the cursor in the same screen line */
+ while ((curwin->w_cursor.lnum < curwin->w_topline || scrolled > 0)
+ && curwin->w_cursor.lnum < curwin->w_botline - 1)
+ {
+ scrolled -= plines(curwin->w_cursor.lnum);
+ if (scrolled < 0 && curwin->w_cursor.lnum >= curwin->w_topline)
+ break;
+# ifdef FEAT_FOLDING
+ (void)hasFolding(curwin->w_cursor.lnum, NULL,
+ &curwin->w_cursor.lnum);
+# endif
+ ++curwin->w_cursor.lnum;
+ }
+#endif
+ }
+ else
+ {
+ /*
+ * scroll the text down
+ */
+ while (n > 0 && curwin->w_topline > 1)
+ {
+#ifdef FEAT_DIFF
+ if (curwin->w_topfill < diff_check_fill(curwin, curwin->w_topline))
+ {
+ i = 1;
+ if (--n < 0 && scrolled > 0)
+ break;
+ ++curwin->w_topfill;
+ }
+ else
+#endif
+ {
+ i = PLINES_NOFILL(curwin->w_topline - 1);
+ n -= i;
+ if (n < 0 && scrolled > 0)
+ break;
+ --curwin->w_topline;
+#ifdef FEAT_FOLDING
+ (void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
+#endif
+#ifdef FEAT_DIFF
+ curwin->w_topfill = 0;
+#endif
+ }
+ curwin->w_valid &= ~(VALID_CROW|VALID_WROW|
+ VALID_BOTLINE|VALID_BOTLINE_AP);
+ scrolled += i;
+#ifndef KEEP_SCREEN_LINE
+ if (curwin->w_cursor.lnum > 1)
+ {
+ --curwin->w_cursor.lnum;
+ curwin->w_valid &= ~(VALID_VIRTCOL|VALID_CHEIGHT|VALID_WCOL);
+ }
+#endif
+ }
+#ifndef KEEP_SCREEN_LINE
+ /*
+ * When hit top of the file: move cursor up.
+ */
+ if (n > 0)
+ {
+ if (curwin->w_cursor.lnum <= (linenr_T)n)
+ curwin->w_cursor.lnum = 1;
+ else
+# ifdef FEAT_FOLDING
+ if (hasAnyFolding(curwin))
+ {
+ while (--n >= 0 && curwin->w_cursor.lnum > 1)
+ {
+ --curwin->w_cursor.lnum;
+ (void)hasFolding(curwin->w_cursor.lnum,
+ &curwin->w_cursor.lnum, NULL);
+ }
+ }
+ else
+# endif
+ curwin->w_cursor.lnum -= n;
+ }
+#else
+ /* try to put the cursor in the same screen line */
+ scrolled += n; /* move cursor when topline is 1 */
+ while (curwin->w_cursor.lnum > curwin->w_topline
+ && (scrolled > 0 || curwin->w_cursor.lnum >= curwin->w_botline))
+ {
+ scrolled -= plines(curwin->w_cursor.lnum - 1);
+ if (scrolled < 0 && curwin->w_cursor.lnum < curwin->w_botline)
+ break;
+ --curwin->w_cursor.lnum;
+# ifdef FEAT_FOLDING
+ foldAdjustCursor();
+# endif
+ }
+#endif
+ }
+# ifdef FEAT_FOLDING
+ /* Move cursor to first line of closed fold. */
+ foldAdjustCursor();
+# endif
+#ifdef FEAT_DIFF
+ check_topfill(curwin, !flag);
+#endif
+ cursor_correct();
+ beginline(BL_SOL | BL_FIX);
+ redraw_later(VALID);
+}
+
+ void
+do_check_cursorbind(void)
+{
+ linenr_T line = curwin->w_cursor.lnum;
+ colnr_T col = curwin->w_cursor.col;
+ colnr_T coladd = curwin->w_cursor.coladd;
+ colnr_T curswant = curwin->w_curswant;
+ int set_curswant = curwin->w_set_curswant;
+ win_T *old_curwin = curwin;
+ buf_T *old_curbuf = curbuf;
+ int restart_edit_save;
+ int old_VIsual_select = VIsual_select;
+ int old_VIsual_active = VIsual_active;
+
+ /*
+ * loop through the cursorbound windows
+ */
+ VIsual_select = VIsual_active = 0;
+ FOR_ALL_WINDOWS(curwin)
+ {
+ curbuf = curwin->w_buffer;
+ /* skip original window and windows with 'noscrollbind' */
+ if (curwin != old_curwin && curwin->w_p_crb)
+ {
+# ifdef FEAT_DIFF
+ if (curwin->w_p_diff)
+ curwin->w_cursor.lnum =
+ diff_get_corresponding_line(old_curbuf, line);
+ else
+# endif
+ curwin->w_cursor.lnum = line;
+ curwin->w_cursor.col = col;
+ curwin->w_cursor.coladd = coladd;
+ curwin->w_curswant = curswant;
+ curwin->w_set_curswant = set_curswant;
+
+ /* Make sure the cursor is in a valid position. Temporarily set
+ * "restart_edit" to allow the cursor to be beyond the EOL. */
+ restart_edit_save = restart_edit;
+ restart_edit = TRUE;
+ check_cursor();
+# ifdef FEAT_SYN_HL
+ if (curwin->w_p_cul || curwin->w_p_cuc)
+ validate_cursor();
+# endif
+ restart_edit = restart_edit_save;
+ /* Correct cursor for multi-byte character. */
+ if (has_mbyte)
+ mb_adjust_cursor();
+ redraw_later(VALID);
+
+ /* Only scroll when 'scrollbind' hasn't done this. */
+ if (!curwin->w_p_scb)
+ update_topline();
+ curwin->w_redr_status = TRUE;
+ }
+ }
+
+ /*
+ * reset current-window
+ */
+ VIsual_select = old_VIsual_select;
+ VIsual_active = old_VIsual_active;
+ curwin = old_curwin;
+ curbuf = old_curbuf;
+}
diff --git a/src/msvc2008.bat b/src/msvc2008.bat
new file mode 100644
index 0000000..c1cd76a
--- /dev/null
+++ b/src/msvc2008.bat
@@ -0,0 +1,7 @@
+@echo off
+rem To be used on MS-Windows for Visual C++ 2008 Express Edition
+rem aka Microsoft Visual Studio 9.0.
+rem See INSTALLpc.txt for information.
+@echo on
+
+call "%VS90COMNTOOLS%vsvars32.bat"
diff --git a/src/msvc2010.bat b/src/msvc2010.bat
new file mode 100644
index 0000000..5c258e9
--- /dev/null
+++ b/src/msvc2010.bat
@@ -0,0 +1,7 @@
+@echo off
+rem To be used on MS-Windows for Visual C++ 2010 Express Edition
+rem aka Microsoft Visual Studio 10.0.
+rem See INSTALLpc.txt for information.
+@echo on
+
+call "%VS100COMNTOOLS%vsvars32.bat"
diff --git a/src/msvc2015.bat b/src/msvc2015.bat
new file mode 100644
index 0000000..41e6f90
--- /dev/null
+++ b/src/msvc2015.bat
@@ -0,0 +1,37 @@
+@echo off
+rem To be used on MS-Windows for Visual C++ 2015 (either Express or Community)
+rem See INSTALLpc.txt for information.
+rem
+rem Usage:
+rem For x86 builds run this without options:
+rem msvc2015
+rem For x64 builds run this with "x86_amd64" option:
+rem msvc2015 x86_amd64
+rem This works on any editions including Express edition.
+rem If you use Community (or Professional) edition, you can also use "x64"
+rem option:
+rem msvc2015 x64
+@echo on
+
+call "%VS140COMNTOOLS%..\..\VC\vcvarsall.bat" %*
+
+rem Use Windows SDK 7.1A for targeting Windows XP.
+if "%ProgramFiles(x86)%"=="" (
+ set "WinSdk71=%ProgramFiles%\Microsoft SDKs\Windows\v7.1A"
+) else (
+ set "WinSdk71=%ProgramFiles(x86)%\Microsoft SDKs\Windows\v7.1A"
+)
+if not exist "%WinSdk71%" (
+ echo Windows SDK 7.1A is not found. Targeting Windows Vista and later.
+ goto :eof
+)
+
+set INCLUDE=%WinSdk71%\Include;%INCLUDE%
+if /i "%Platform%"=="x64" (
+ set "LIB=%WinSdk71%\Lib\x64;%LIB%"
+ set SUBSYSTEM_VER=5.02
+) else (
+ set "LIB=%WinSdk71%\Lib;%LIB%"
+ set SUBSYSTEM_VER=5.01
+)
+set CL=/D_USING_V110_SDK71_
diff --git a/src/msvcsetup.bat b/src/msvcsetup.bat
new file mode 100644
index 0000000..e577020
--- /dev/null
+++ b/src/msvcsetup.bat
@@ -0,0 +1,12 @@
+rem To be used on MS-Windows when using the Visual C++ Toolkit 2003
+rem See INSTALLpc.txt for information.
+
+set PATH=%SystemRoot%\Microsoft.NET\Framework\v1.1.4322;%PATH%
+call "%VCToolkitInstallDir%vcvars32.bat"
+set MSVCVer=7.1
+
+rem The platform SDK can be installed elsewhere, adjust the path.
+call "%ProgramFiles%\Microsoft Platform SDK\SetEnv.Cmd"
+rem call "e:\Microsoft Platform SDK\SetEnv.Cmd"
+
+set LIB=%ProgramFiles%\Microsoft Visual Studio .NET 2003\Vc7\lib;%LIB%
diff --git a/src/msys32.bat b/src/msys32.bat
new file mode 100755
index 0000000..6c9b81d
--- /dev/null
+++ b/src/msys32.bat
@@ -0,0 +1,6 @@
+@echo off
+rem To be used on MS-Windows for Msys2 with the 32 bit MinGW compiler.
+rem Adjust the "c:\msys64" part to match your installation.
+@echo on
+
+set PATH=c:\msys64\mingw32\bin;c:\msys64\usr\bin;%PATH%
diff --git a/src/msys64.bat b/src/msys64.bat
new file mode 100755
index 0000000..dcfbbc9
--- /dev/null
+++ b/src/msys64.bat
@@ -0,0 +1,6 @@
+@echo off
+rem To be used on MS-Windows for Msys2 with the 64 bit MinGW compiler.
+rem Adjust the "c:\msys64" part to match your installation.
+@echo on
+
+set PATH=c:\msys64\mingw64\bin;c:\msys64\usr\bin;%PATH%
diff --git a/src/mysign b/src/mysign
new file mode 100644
index 0000000..fc751c0
--- /dev/null
+++ b/src/mysign
@@ -0,0 +1 @@
+=auto/configure-lastupdate=1178970549.78-@buildcheck=dfc15c059b7ce88a951584995c49a201=configure.ac@md5=e0d6e9a7d7b986d63ce4e8e7362fd0b9
diff --git a/src/nbdebug.c b/src/nbdebug.c
new file mode 100644
index 0000000..991bc66
--- /dev/null
+++ b/src/nbdebug.c
@@ -0,0 +1,162 @@
+/* vi:set ts=8 sw=8 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ * Visual Workshop integration by Gordon Prieur
+ *
+ * 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.
+ */
+
+/*
+ * NetBeans Debugging Tools. What are these tools and why are they important?
+ * There are two main tools here. The first tool is a tool for delaying or
+ * stopping gvim during startup. The second tool is a protocol log tool.
+ *
+ * The startup delay tool is called nbdebug_wait(). This is very important for
+ * debugging startup problems because gvim will be started automatically from
+ * netbeans and cannot be run directly from a debugger. The only way to debug
+ * a gvim started by netbeans is by attaching a debugger to it. Without this
+ * tool all startup code will have completed before you can get the pid and
+ * attach.
+ *
+ * The second tool is a log tool.
+ *
+ * This code must have NBDEBUG defined for it to be compiled into vim/gvim.
+ */
+
+#ifdef NBDEBUG
+
+#include "vim.h"
+
+FILE *nb_debug = NULL;
+u_int nb_dlevel = 0; /* nb_debug verbosity level */
+
+void nbdb(char *, ...);
+
+static int lookup(char *);
+#ifdef USE_NB_ERRORHANDLER
+static int errorHandler(Display *, XErrorEvent *);
+#endif
+
+/*
+ * nbdebug_wait - This function can be used to delay or stop execution of vim.
+ * It's normally used to delay startup while attaching a
+ * debugger to a running process. Since NetBeans starts gvim
+ * from a background process this is the only way to debug
+ * startup problems.
+ */
+
+void nbdebug_wait(
+ u_int wait_flags, /* tells what to do */
+ char *wait_var, /* wait environment variable */
+ u_int wait_secs) /* how many seconds to wait */
+{
+
+ init_homedir(); /* not inited yet */
+#ifdef USE_WDDUMP
+ WDDump(0, 0, 0);
+#endif
+
+ /* for debugging purposes only */
+ if (wait_flags & WT_ENV && wait_var && getenv(wait_var) != NULL) {
+ sleep(atoi(getenv(wait_var)));
+ } else if (wait_flags & WT_WAIT && lookup("~/.gvimwait")) {
+ sleep(wait_secs > 0 && wait_secs < 120 ? wait_secs : 20);
+ } else if (wait_flags & WT_STOP && lookup("~/.gvimstop")) {
+ int w = 1;
+ while (w) {
+ ;
+ }
+ }
+} /* end nbdebug_wait */
+
+
+void
+nbdebug_log_init(
+ char *log_var, /* env var with log file */
+ char *level_var) /* env var with nb_debug level */
+{
+ char *file; /* possible nb_debug output file */
+ char *cp; /* nb_dlevel pointer */
+
+ if (log_var && (file = getenv(log_var)) != NULL) {
+ time_t now;
+
+ nb_debug = fopen(file, "a");
+ time(&now);
+ fprintf(nb_debug, "%s", asctime(localtime(&now)));
+ if (level_var && (cp = getenv(level_var)) != NULL) {
+ nb_dlevel = strtoul(cp, NULL, 0);
+ } else {
+ nb_dlevel = NB_TRACE; /* default level */
+ }
+#ifdef USE_NB_ERRORHANDLER
+ XSetErrorHandler(errorHandler);
+#endif
+ }
+
+} /* end nbdebug_log_init */
+
+
+void
+nbdbg(
+ char *fmt,
+ ...)
+{
+ va_list ap;
+
+ if (nb_debug != NULL && nb_dlevel & NB_TRACE) {
+ va_start(ap, fmt);
+ vfprintf(nb_debug, fmt, ap);
+ va_end(ap);
+ fflush(nb_debug);
+ }
+
+} /* end nbdbg */
+
+
+static int
+lookup(
+ char *file)
+{
+ char buf[BUFSIZ];
+
+ expand_env((char_u *) file, (char_u *) buf, BUFSIZ);
+ return
+#ifndef FEAT_GUI_W32
+ (access(buf, F_OK) == 0);
+#else
+ (access(buf, 0) == 0);
+#endif
+
+} /* end lookup */
+
+#ifdef USE_NB_ERRORHANDLER
+static int
+errorHandler(
+ Display *dpy,
+ XErrorEvent *err)
+{
+ char msg[256];
+ char buf[256];
+
+ XGetErrorText(dpy, err->error_code, msg, sizeof(msg));
+ nbdbg("\n\nNBDEBUG Vim: X Error of failed request: %s\n", msg);
+
+ sprintf(buf, "%d", err->request_code);
+ XGetErrorDatabaseText(dpy,
+ "XRequest", buf, "Unknown", msg, sizeof(msg));
+ nbdbg("\tMajor opcode of failed request: %d (%s)\n",
+ err->request_code, msg);
+ if (err->request_code > 128) {
+ nbdbg("\tMinor opcode of failed request: %d\n",
+ err->minor_code);
+ }
+
+ return 0;
+}
+#endif
+
+
+#endif /* NBDEBUG */
diff --git a/src/nbdebug.h b/src/nbdebug.h
new file mode 100644
index 0000000..6331f49
--- /dev/null
+++ b/src/nbdebug.h
@@ -0,0 +1,72 @@
+/* vi:set ts=8 sw=8 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ * Visual Workshop integration by Gordon Prieur
+ *
+ * Do ":help uganda" in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ */
+
+
+#ifndef NBDEBUG_H
+#define NBDEBUG_H
+
+#ifdef NBDEBUG
+
+#ifndef ASSERT
+#define ASSERT(c) \
+ if (!(c)) { \
+ fprintf(stderr, "Assertion failed: line %d, file %s\n", \
+ __LINE__, __FILE__); \
+ fflush(stderr); \
+ abort(); \
+ }
+#endif
+
+#define nbdebug(a) nbdbg a
+
+#define NB_TRACE 0x00000001
+#define NB_TRACE_VERBOSE 0x00000002
+#define NB_TRACE_COLONCMD 0x00000004
+#define NB_PRINT 0x00000008
+#define NB_DEBUG_ALL 0xffffffff
+
+#define NBDLEVEL(flags) (nb_debug != NULL && (nb_dlevel & (flags)))
+
+#define NBDEBUG_TRACE 1
+
+typedef enum {
+ WT_ENV = 1, /* look for env var if set */
+ WT_WAIT, /* look for ~/.gvimwait if set */
+ WT_STOP /* look for ~/.gvimstop if set */
+} WtWait;
+
+
+void nbdbg(char *, ...);
+
+void nbdebug_wait(u_int wait_flags, char *wait_var, u_int wait_secs);
+void nbdebug_log_init(char *log_var, char *level_var);
+
+extern FILE *nb_debug;
+extern u_int nb_dlevel; /* nb_debug verbosity level */
+
+# else /* not NBDEBUG */
+
+#ifndef ASSERT
+# define ASSERT(c)
+#endif
+
+/*
+ * The following 3 stubs are needed because a macro cannot be used because of
+ * the variable number of arguments.
+ */
+
+void
+nbdbg(
+ char *fmt,
+ ...)
+{
+}
+
+#endif /* NBDEBUG */
+#endif /* NBDEBUG_H */
diff --git a/src/netbeans.c b/src/netbeans.c
new file mode 100644
index 0000000..ecc7625
--- /dev/null
+++ b/src/netbeans.c
@@ -0,0 +1,3488 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ * Netbeans integration by David Weatherford
+ * Adopted for Win32 by Sergey Khorev
+ *
+ * Do ":help uganda" in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ */
+
+/*
+ * Implements client side of org.netbeans.modules.emacs editor
+ * integration protocol. Be careful! The protocol uses offsets
+ * which are *between* characters, whereas vim uses line number
+ * and column number which are *on* characters.
+ * See ":help netbeans-protocol" for explanation.
+ *
+ * The Netbeans messages are received and queued in the gui event loop, or in
+ * the select loop when Vim runs in a terminal. These messages are processed
+ * by netbeans_parse_messages() which is invoked in the idle loop when Vim is
+ * waiting for user input. The function netbeans_parse_messages() is also
+ * called from the ":sleep" command, to allow the execution of test cases that
+ * may not invoke the idle loop.
+ */
+
+#include "vim.h"
+
+#if defined(FEAT_NETBEANS_INTG) || defined(PROTO)
+
+#ifndef WIN32
+# include <netdb.h>
+# ifdef HAVE_LIBGEN_H
+# include <libgen.h>
+# endif
+#endif
+
+#include "version.h"
+
+#define GUARDED 10000 /* typenr for "guarded" annotation */
+#define GUARDEDOFFSET 1000000 /* base for "guarded" sign id's */
+#define MAX_COLOR_LENGTH 32 /* max length of color name in defineAnnoType */
+
+/* The first implementation (working only with Netbeans) returned "1.1". The
+ * protocol implemented here also supports A-A-P. */
+static char *ExtEdProtocolVersion = "2.5";
+
+static long pos2off(buf_T *, pos_T *);
+static pos_T *off2pos(buf_T *, long);
+static pos_T *get_off_or_lnum(buf_T *buf, char_u **argp);
+static long get_buf_size(buf_T *);
+static int netbeans_keystring(char_u *keystr);
+static void special_keys(char_u *args);
+
+static int getConnInfo(char *file, char **host, char **port, char **password);
+
+static void nb_init_graphics(void);
+static void coloncmd(char *cmd, ...);
+static void nb_set_curbuf(buf_T *buf);
+static void nb_parse_cmd(char_u *);
+static int nb_do_cmd(int, char_u *, int, int, char_u *);
+static void nb_send(char *buf, char *fun);
+static void nb_free(void);
+
+#define NETBEANS_OPEN (channel_can_write_to(nb_channel))
+static channel_T *nb_channel = NULL;
+
+static int r_cmdno; /* current command number for reply */
+static int dosetvisible = FALSE;
+
+/*
+ * Include the debugging code if wanted.
+ */
+#ifdef NBDEBUG
+# include "nbdebug.c"
+#endif
+
+static int needupdate = 0;
+static int inAtomic = 0;
+
+/*
+ * Callback invoked when the channel is closed.
+ */
+ static void
+nb_channel_closed(void)
+{
+ nb_channel = NULL;
+}
+
+/*
+ * Close the connection and cleanup.
+ * May be called when the socket was closed earlier.
+ */
+ static void
+netbeans_close(void)
+{
+ if (NETBEANS_OPEN)
+ {
+ netbeans_send_disconnect();
+ if (nb_channel != NULL)
+ {
+ /* Close the socket and remove the input handlers. */
+ channel_close(nb_channel, TRUE);
+ channel_clear(nb_channel);
+ }
+ nb_channel = NULL;
+ }
+
+#ifdef FEAT_BEVAL_GUI
+ bevalServers &= ~BEVAL_NETBEANS;
+#endif
+
+ needupdate = 0;
+ inAtomic = 0;
+ nb_free();
+
+ /* remove all signs and update the screen after gutter removal */
+ coloncmd(":sign unplace *");
+ changed_window_setting();
+ update_screen(CLEAR);
+ setcursor();
+ cursor_on();
+ out_flush_cursor(TRUE, FALSE);
+}
+
+#define NB_DEF_HOST "localhost"
+#define NB_DEF_ADDR "3219"
+#define NB_DEF_PASS "changeme"
+
+ static int
+netbeans_connect(char *params, int doabort)
+{
+ int port;
+ char buf[32];
+ char *hostname = NULL;
+ char *address = NULL;
+ char *password = NULL;
+ char *fname;
+ char *arg = NULL;
+
+ if (*params == '=')
+ {
+ /* "=fname": Read info from specified file. */
+ if (getConnInfo(params + 1, &hostname, &address, &password) == FAIL)
+ return FAIL;
+ }
+ else
+ {
+ if (*params == ':')
+ /* ":<host>:<addr>:<password>": get info from argument */
+ arg = params + 1;
+ if (arg == NULL && (fname = getenv("__NETBEANS_CONINFO")) != NULL)
+ {
+ /* "": get info from file specified in environment */
+ if (getConnInfo(fname, &hostname, &address, &password) == FAIL)
+ return FAIL;
+ }
+ else
+ {
+ if (arg != NULL)
+ {
+ /* ":<host>:<addr>:<password>": get info from argument */
+ hostname = arg;
+ address = strchr(hostname, ':');
+ if (address != NULL)
+ {
+ *address++ = '\0';
+ password = strchr(address, ':');
+ if (password != NULL)
+ *password++ = '\0';
+ }
+ }
+
+ /* Get the missing values from the environment. */
+ if (hostname == NULL || *hostname == '\0')
+ hostname = getenv("__NETBEANS_HOST");
+ if (address == NULL)
+ address = getenv("__NETBEANS_SOCKET");
+ if (password == NULL)
+ password = getenv("__NETBEANS_VIM_PASSWORD");
+
+ /* Move values to allocated memory. */
+ if (hostname != NULL)
+ hostname = (char *)vim_strsave((char_u *)hostname);
+ if (address != NULL)
+ address = (char *)vim_strsave((char_u *)address);
+ if (password != NULL)
+ password = (char *)vim_strsave((char_u *)password);
+ }
+ }
+
+ /* Use the default when a value is missing. */
+ if (hostname == NULL || *hostname == '\0')
+ {
+ vim_free(hostname);
+ hostname = (char *)vim_strsave((char_u *)NB_DEF_HOST);
+ }
+ if (address == NULL || *address == '\0')
+ {
+ vim_free(address);
+ address = (char *)vim_strsave((char_u *)NB_DEF_ADDR);
+ }
+ if (password == NULL || *password == '\0')
+ {
+ vim_free(password);
+ password = (char *)vim_strsave((char_u *)NB_DEF_PASS);
+ }
+ if (hostname != NULL && address != NULL && password != NULL)
+ {
+ port = atoi(address);
+ nb_channel = channel_open(hostname, port, 3000, nb_channel_closed);
+ if (nb_channel != NULL)
+ {
+ /* success */
+# ifdef FEAT_BEVAL_GUI
+ bevalServers |= BEVAL_NETBEANS;
+# endif
+
+ /* success, login */
+ vim_snprintf(buf, sizeof(buf), "AUTH %s\n", password);
+ nb_send(buf, "netbeans_connect");
+
+ sprintf(buf, "0:version=0 \"%s\"\n", ExtEdProtocolVersion);
+ nb_send(buf, "externaleditor_version");
+ }
+ }
+
+ if (nb_channel == NULL && doabort)
+ getout(1);
+
+ vim_free(hostname);
+ vim_free(address);
+ vim_free(password);
+ return NETBEANS_OPEN ? OK : FAIL;
+}
+
+/*
+ * Obtain the NetBeans hostname, port address and password from a file.
+ * Return the strings in allocated memory.
+ * Return FAIL if the file could not be read, OK otherwise (no matter what it
+ * contains).
+ */
+ static int
+getConnInfo(char *file, char **host, char **port, char **auth)
+{
+ FILE *fp;
+ char_u buf[BUFSIZ];
+ char_u *lp;
+ char_u *nlp;
+#ifdef UNIX
+ stat_T st;
+
+ /*
+ * For Unix only accept the file when it's not accessible by others.
+ * The open will then fail if we don't own the file.
+ */
+ if (mch_stat(file, &st) == 0 && (st.st_mode & 0077) != 0)
+ {
+ nbdebug(("Wrong access mode for NetBeans connection info file: \"%s\"\n",
+ file));
+ semsg(_("E668: Wrong access mode for NetBeans connection info file: \"%s\""),
+ file);
+ return FAIL;
+ }
+#endif
+
+ fp = mch_fopen(file, "r");
+ if (fp == NULL)
+ {
+ nbdebug(("Cannot open NetBeans connection info file\n"));
+ PERROR("E660: Cannot open NetBeans connection info file");
+ return FAIL;
+ }
+
+ /* Read the file. There should be one of each parameter */
+ while ((lp = (char_u *)fgets((char *)buf, BUFSIZ, fp)) != NULL)
+ {
+ if ((nlp = vim_strchr(lp, '\n')) != NULL)
+ *nlp = 0; /* strip off the trailing newline */
+
+ if (STRNCMP(lp, "host=", 5) == 0)
+ {
+ vim_free(*host);
+ *host = (char *)vim_strsave(&buf[5]);
+ }
+ else if (STRNCMP(lp, "port=", 5) == 0)
+ {
+ vim_free(*port);
+ *port = (char *)vim_strsave(&buf[5]);
+ }
+ else if (STRNCMP(lp, "auth=", 5) == 0)
+ {
+ vim_free(*auth);
+ *auth = (char *)vim_strsave(&buf[5]);
+ }
+ }
+ fclose(fp);
+
+ return OK;
+}
+
+
+struct keyqueue
+{
+ char_u *keystr;
+ struct keyqueue *next;
+ struct keyqueue *prev;
+};
+
+typedef struct keyqueue keyQ_T;
+
+static keyQ_T keyHead; /* dummy node, header for circular queue */
+
+
+/*
+ * Queue up key commands sent from netbeans.
+ * We store the string, because it may depend on the global mod_mask and
+ * :nbkey doesn't have a key number.
+ */
+ static void
+postpone_keycommand(char_u *keystr)
+{
+ keyQ_T *node;
+
+ node = (keyQ_T *)alloc(sizeof(keyQ_T));
+ if (node == NULL)
+ return; /* out of memory, drop the key */
+
+ if (keyHead.next == NULL) /* initialize circular queue */
+ {
+ keyHead.next = &keyHead;
+ keyHead.prev = &keyHead;
+ }
+
+ /* insert node at tail of queue */
+ node->next = &keyHead;
+ node->prev = keyHead.prev;
+ keyHead.prev->next = node;
+ keyHead.prev = node;
+
+ node->keystr = vim_strsave(keystr);
+}
+
+/*
+ * Handle any queued-up NetBeans keycommands to be send.
+ */
+ static void
+handle_key_queue(void)
+{
+ int postponed = FALSE;
+
+ while (!postponed && keyHead.next && keyHead.next != &keyHead)
+ {
+ /* first, unlink the node */
+ keyQ_T *node = keyHead.next;
+ keyHead.next = node->next;
+ node->next->prev = node->prev;
+
+ /* Now, send the keycommand. This may cause it to be postponed again
+ * and change keyHead. */
+ if (node->keystr != NULL)
+ postponed = !netbeans_keystring(node->keystr);
+ vim_free(node->keystr);
+
+ /* Finally, dispose of the node */
+ vim_free(node);
+ }
+}
+
+
+/*
+ * While there's still a command in the work queue, parse and execute it.
+ */
+ void
+netbeans_parse_messages(void)
+{
+ readq_T *node;
+ char_u *buffer;
+ char_u *p;
+ int own_node;
+
+ while (nb_channel != NULL)
+ {
+ node = channel_peek(nb_channel, PART_SOCK);
+ if (node == NULL)
+ break; /* nothing to read */
+
+ /* Locate the end of the first line in the first buffer. */
+ p = channel_first_nl(node);
+ if (p == NULL)
+ {
+ /* Command isn't complete. If there is no following buffer,
+ * return (wait for more). If there is another buffer following,
+ * prepend the text to that buffer and delete this one. */
+ if (channel_collapse(nb_channel, PART_SOCK, TRUE) == FAIL)
+ return;
+ continue;
+ }
+
+ /* There is a complete command at the start of the buffer.
+ * Terminate it with a NUL. When no more text is following unlink
+ * the buffer. Do this before executing, because new buffers can
+ * be added while busy handling the command. */
+ *p++ = NUL;
+ if (*p == NUL)
+ {
+ own_node = TRUE;
+ buffer = channel_get(nb_channel, PART_SOCK, NULL);
+ /* "node" is now invalid! */
+ }
+ else
+ {
+ own_node = FALSE;
+ buffer = node->rq_buffer;
+ }
+
+ /* Now, parse and execute the commands. This may set nb_channel to
+ * NULL if the channel is closed. */
+ nb_parse_cmd(buffer);
+
+ if (own_node)
+ /* buffer finished, dispose of it */
+ vim_free(buffer);
+ else if (nb_channel != NULL)
+ /* more follows, move it to the start */
+ channel_consume(nb_channel, PART_SOCK, (int)(p - buffer));
+ }
+}
+
+/*
+ * Handle one NUL terminated command.
+ *
+ * format of a command from netbeans:
+ *
+ * 6:setTitle!84 "a.c"
+ *
+ * bufno
+ * colon
+ * cmd
+ * !
+ * cmdno
+ * args
+ *
+ * for function calls, the ! is replaced by a /
+ */
+ static void
+nb_parse_cmd(char_u *cmd)
+{
+ char *verb;
+ char *q;
+ int bufno;
+ int isfunc = -1;
+
+ if (STRCMP(cmd, "DISCONNECT") == 0)
+ {
+ /* We assume the server knows that we can safely exit! */
+ /* Disconnect before exiting, Motif hangs in a Select error
+ * message otherwise. */
+ netbeans_close();
+ getout(0);
+ /* NOTREACHED */
+ }
+
+ if (STRCMP(cmd, "DETACH") == 0)
+ {
+ buf_T *buf;
+
+ FOR_ALL_BUFFERS(buf)
+ buf->b_has_sign_column = FALSE;
+
+ /* The IDE is breaking the connection. */
+ netbeans_close();
+ return;
+ }
+
+ bufno = strtol((char *)cmd, &verb, 10);
+
+ if (*verb != ':')
+ {
+ nbdebug((" missing colon: %s\n", cmd));
+ semsg("E627: missing colon: %s", cmd);
+ return;
+ }
+ ++verb; /* skip colon */
+
+ for (q = verb; *q; q++)
+ {
+ if (*q == '!')
+ {
+ *q++ = NUL;
+ isfunc = 0;
+ break;
+ }
+ else if (*q == '/')
+ {
+ *q++ = NUL;
+ isfunc = 1;
+ break;
+ }
+ }
+
+ if (isfunc < 0)
+ {
+ nbdebug((" missing ! or / in: %s\n", cmd));
+ semsg("E628: missing ! or / in: %s", cmd);
+ return;
+ }
+
+ r_cmdno = strtol(q, &q, 10);
+
+ q = (char *)skipwhite((char_u *)q);
+
+ if (nb_do_cmd(bufno, (char_u *)verb, isfunc, r_cmdno, (char_u *)q) == FAIL)
+ {
+#ifdef NBDEBUG
+ /*
+ * This happens because the ExtEd can send a command or 2 after
+ * doing a stopDocumentListen command. It doesn't harm anything
+ * so I'm disabling it except for debugging.
+ */
+ nbdebug(("nb_parse_cmd: Command error for \"%s\"\n", cmd));
+ emsg("E629: bad return from nb_do_cmd");
+#endif
+ }
+}
+
+struct nbbuf_struct
+{
+ buf_T *bufp;
+ unsigned int fireChanges:1;
+ unsigned int initDone:1;
+ unsigned int insertDone:1;
+ unsigned int modified:1;
+ int nbbuf_number;
+ char *displayname;
+ int *signmap;
+ short_u signmaplen;
+ short_u signmapused;
+};
+
+typedef struct nbbuf_struct nbbuf_T;
+
+static nbbuf_T *buf_list = NULL;
+static int buf_list_size = 0; /* size of buf_list */
+static int buf_list_used = 0; /* nr of entries in buf_list actually in use */
+
+static char **globalsignmap = NULL;
+static int globalsignmaplen = 0;
+static int globalsignmapused = 0;
+
+static int mapsigntype(nbbuf_T *, int localsigntype);
+static void addsigntype(nbbuf_T *, int localsigntype, char_u *typeName,
+ char_u *tooltip, char_u *glyphfile,
+ char_u *fg, char_u *bg);
+static void print_read_msg(nbbuf_T *buf);
+static void print_save_msg(nbbuf_T *buf, off_T nchars);
+
+static int curPCtype = -1;
+
+/*
+ * Free netbeans resources.
+ */
+ static void
+nb_free(void)
+{
+ keyQ_T *key_node = keyHead.next;
+ nbbuf_T buf;
+ int i;
+
+ /* free the netbeans buffer list */
+ for (i = 0; i < buf_list_used; i++)
+ {
+ buf = buf_list[i];
+ vim_free(buf.displayname);
+ vim_free(buf.signmap);
+ if (buf.bufp != NULL)
+ {
+ buf.bufp->b_netbeans_file = FALSE;
+ buf.bufp->b_was_netbeans_file = FALSE;
+ }
+ }
+ VIM_CLEAR(buf_list);
+ buf_list_size = 0;
+ buf_list_used = 0;
+
+ /* free the queued key commands */
+ while (key_node != NULL && key_node != &keyHead)
+ {
+ keyQ_T *next = key_node->next;
+ vim_free(key_node->keystr);
+ vim_free(key_node);
+ if (next == &keyHead)
+ {
+ keyHead.next = &keyHead;
+ keyHead.prev = &keyHead;
+ break;
+ }
+ key_node = next;
+ }
+
+ /* free the queued netbeans commands */
+ if (nb_channel != NULL)
+ channel_clear(nb_channel);
+}
+
+/*
+ * Get the Netbeans buffer number for the specified buffer.
+ */
+ static int
+nb_getbufno(buf_T *bufp)
+{
+ int i;
+
+ for (i = 0; i < buf_list_used; i++)
+ if (buf_list[i].bufp == bufp)
+ return i;
+ return -1;
+}
+
+/*
+ * Is this a NetBeans-owned buffer?
+ */
+ int
+isNetbeansBuffer(buf_T *bufp)
+{
+ return NETBEANS_OPEN && bufp->b_netbeans_file;
+}
+
+/*
+ * NetBeans and Vim have different undo models. In Vim, the file isn't
+ * changed if changes are undone via the undo command. In NetBeans, once
+ * a change has been made the file is marked as modified until saved. It
+ * doesn't matter if the change was undone.
+ *
+ * So this function is for the corner case where Vim thinks a buffer is
+ * unmodified but NetBeans thinks it IS modified.
+ */
+ int
+isNetbeansModified(buf_T *bufp)
+{
+ if (isNetbeansBuffer(bufp))
+ {
+ int bufno = nb_getbufno(bufp);
+
+ if (bufno > 0)
+ return buf_list[bufno].modified;
+ else
+ return FALSE;
+ }
+ else
+ return FALSE;
+}
+
+/*
+ * Given a Netbeans buffer number, return the netbeans buffer.
+ * Returns NULL for 0 or a negative number. A 0 bufno means a
+ * non-buffer related command has been sent.
+ */
+ static nbbuf_T *
+nb_get_buf(int bufno)
+{
+ /* find or create a buffer with the given number */
+ int incr;
+
+ if (bufno <= 0)
+ return NULL;
+
+ if (!buf_list)
+ {
+ /* initialize */
+ buf_list = (nbbuf_T *)alloc_clear(100 * sizeof(nbbuf_T));
+ buf_list_size = 100;
+ }
+ if (bufno >= buf_list_used) /* new */
+ {
+ if (bufno >= buf_list_size) /* grow list */
+ {
+ nbbuf_T *t_buf_list = buf_list;
+
+ incr = bufno - buf_list_size + 90;
+ buf_list_size += incr;
+ buf_list = (nbbuf_T *)vim_realloc(
+ buf_list, buf_list_size * sizeof(nbbuf_T));
+ if (buf_list == NULL)
+ {
+ vim_free(t_buf_list);
+ buf_list_size = 0;
+ return NULL;
+ }
+ vim_memset(buf_list + buf_list_size - incr, 0,
+ incr * sizeof(nbbuf_T));
+ }
+
+ while (buf_list_used <= bufno)
+ {
+ /* Default is to fire text changes. */
+ buf_list[buf_list_used].fireChanges = 1;
+ ++buf_list_used;
+ }
+ }
+
+ return buf_list + bufno;
+}
+
+/*
+ * Return the number of buffers that are modified.
+ */
+ static int
+count_changed_buffers(void)
+{
+ buf_T *bufp;
+ int n;
+
+ n = 0;
+ FOR_ALL_BUFFERS(bufp)
+ if (bufp->b_changed)
+ ++n;
+ return n;
+}
+
+/*
+ * End the netbeans session.
+ */
+ void
+netbeans_end(void)
+{
+ int i;
+ static char buf[128];
+
+ if (!NETBEANS_OPEN)
+ return;
+
+ for (i = 0; i < buf_list_used; i++)
+ {
+ if (!buf_list[i].bufp)
+ continue;
+ if (netbeansForcedQuit)
+ {
+ /* mark as unmodified so NetBeans won't put up dialog on "killed" */
+ sprintf(buf, "%d:unmodified=%d\n", i, r_cmdno);
+ nbdebug(("EVT: %s", buf));
+ nb_send(buf, "netbeans_end");
+ }
+ sprintf(buf, "%d:killed=%d\n", i, r_cmdno);
+ nbdebug(("EVT: %s", buf));
+ /* nb_send(buf, "netbeans_end"); avoid "write failed" messages */
+ nb_send(buf, NULL);
+ }
+}
+
+/*
+ * Send a message to netbeans.
+ * When "fun" is NULL no error is given.
+ */
+ static void
+nb_send(char *buf, char *fun)
+{
+ if (nb_channel != NULL)
+ channel_send(nb_channel, PART_SOCK, (char_u *)buf,
+ (int)STRLEN(buf), fun);
+}
+
+/*
+ * Some input received from netbeans requires a response. This function
+ * handles a response with no information (except the command number).
+ */
+ static void
+nb_reply_nil(int cmdno)
+{
+ char reply[32];
+
+ nbdebug(("REP %d: <none>\n", cmdno));
+
+ /* Avoid printing an annoying error message. */
+ if (!NETBEANS_OPEN)
+ return;
+
+ sprintf(reply, "%d\n", cmdno);
+ nb_send(reply, "nb_reply_nil");
+}
+
+
+/*
+ * Send a response with text.
+ * "result" must have been quoted already (using nb_quote()).
+ */
+ static void
+nb_reply_text(int cmdno, char_u *result)
+{
+ char_u *reply;
+
+ nbdebug(("REP %d: %s\n", cmdno, (char *)result));
+
+ reply = alloc((unsigned)STRLEN(result) + 32);
+ sprintf((char *)reply, "%d %s\n", cmdno, (char *)result);
+ nb_send((char *)reply, "nb_reply_text");
+
+ vim_free(reply);
+}
+
+
+/*
+ * Send a response with a number result code.
+ */
+ static void
+nb_reply_nr(int cmdno, long result)
+{
+ char reply[32];
+
+ nbdebug(("REP %d: %ld\n", cmdno, result));
+
+ sprintf(reply, "%d %ld\n", cmdno, result);
+ nb_send(reply, "nb_reply_nr");
+}
+
+
+/*
+ * Encode newline, ret, backslash, double quote for transmission to NetBeans.
+ */
+ static char_u *
+nb_quote(char_u *txt)
+{
+ char_u *buf = alloc((unsigned)(2 * STRLEN(txt) + 1));
+ char_u *p = txt;
+ char_u *q = buf;
+
+ if (buf == NULL)
+ return NULL;
+ for (; *p; p++)
+ {
+ switch (*p)
+ {
+ case '\"':
+ case '\\':
+ *q++ = '\\'; *q++ = *p; break;
+ /* case '\t': */
+ /* *q++ = '\\'; *q++ = 't'; break; */
+ case '\n':
+ *q++ = '\\'; *q++ = 'n'; break;
+ case '\r':
+ *q++ = '\\'; *q++ = 'r'; break;
+ default:
+ *q++ = *p;
+ break;
+ }
+ }
+ *q = '\0';
+
+ return buf;
+}
+
+
+/*
+ * Remove top level double quotes; convert backslashed chars.
+ * Returns an allocated string (NULL for failure).
+ * If "endp" is not NULL it is set to the character after the terminating
+ * quote.
+ */
+ static char *
+nb_unquote(char_u *p, char_u **endp)
+{
+ char *result = 0;
+ char *q;
+ int done = 0;
+
+ /* result is never longer than input */
+ result = (char *)alloc_clear((unsigned)STRLEN(p) + 1);
+ if (result == NULL)
+ return NULL;
+
+ if (*p++ != '"')
+ {
+ nbdebug(("nb_unquote called with string that doesn't start with a quote!: %s\n",
+ p));
+ result[0] = NUL;
+ return result;
+ }
+
+ for (q = result; !done && *p != NUL;)
+ {
+ switch (*p)
+ {
+ case '"':
+ /*
+ * Unbackslashed dquote marks the end, if first char was dquote.
+ */
+ done = 1;
+ break;
+
+ case '\\':
+ ++p;
+ switch (*p)
+ {
+ case '\\': *q++ = '\\'; break;
+ case 'n': *q++ = '\n'; break;
+ case 't': *q++ = '\t'; break;
+ case 'r': *q++ = '\r'; break;
+ case '"': *q++ = '"'; break;
+ case NUL: --p; break;
+ /* default: skip over illegal chars */
+ }
+ ++p;
+ break;
+
+ default:
+ *q++ = *p++;
+ }
+ }
+
+ if (endp != NULL)
+ *endp = p;
+
+ return result;
+}
+
+/*
+ * Remove from "first" byte to "last" byte (inclusive), at line "lnum" of the
+ * current buffer. Remove to end of line when "last" is MAXCOL.
+ */
+ static void
+nb_partialremove(linenr_T lnum, colnr_T first, colnr_T last)
+{
+ char_u *oldtext, *newtext;
+ int oldlen;
+ int lastbyte = last;
+
+ oldtext = ml_get(lnum);
+ oldlen = (int)STRLEN(oldtext);
+ if (first >= (colnr_T)oldlen || oldlen == 0) /* just in case */
+ return;
+ if (lastbyte >= oldlen)
+ lastbyte = oldlen - 1;
+ newtext = alloc(oldlen - (int)(lastbyte - first));
+ if (newtext != NULL)
+ {
+ mch_memmove(newtext, oldtext, first);
+ STRMOVE(newtext + first, oldtext + lastbyte + 1);
+ nbdebug((" NEW LINE %d: %s\n", lnum, newtext));
+ ml_replace(lnum, newtext, FALSE);
+ }
+}
+
+/*
+ * Replace the "first" line with the concatenation of the "first" and
+ * the "other" line. The "other" line is not removed.
+ */
+ static void
+nb_joinlines(linenr_T first, linenr_T other)
+{
+ int len_first, len_other;
+ char_u *p;
+
+ len_first = (int)STRLEN(ml_get(first));
+ len_other = (int)STRLEN(ml_get(other));
+ p = alloc((unsigned)(len_first + len_other + 1));
+ if (p != NULL)
+ {
+ mch_memmove(p, ml_get(first), len_first);
+ mch_memmove(p + len_first, ml_get(other), len_other + 1);
+ ml_replace(first, p, FALSE);
+ }
+}
+
+#define SKIP_STOP 2
+#define streq(a,b) (strcmp(a,b) == 0)
+
+/*
+ * Do the actual processing of a single netbeans command or function.
+ * The difference between a command and function is that a function
+ * gets a response (it's required) but a command does not.
+ * For arguments see comment for nb_parse_cmd().
+ */
+ static int
+nb_do_cmd(
+ int bufno,
+ char_u *cmd,
+ int func,
+ int cmdno,
+ char_u *args) /* points to space before arguments or NUL */
+{
+ int do_update = 0;
+ long off = 0;
+ nbbuf_T *buf = nb_get_buf(bufno);
+ static int skip = 0;
+ int retval = OK;
+ char *cp; /* for when a char pointer is needed */
+
+ nbdebug(("%s %d: (%d) %s %s\n", (func) ? "FUN" : "CMD", cmdno, bufno, cmd,
+ STRCMP(cmd, "insert") == 0 ? "<text>" : (char *)args));
+
+ if (func)
+ {
+/* =====================================================================*/
+ if (streq((char *)cmd, "getModified"))
+ {
+ if (buf == NULL || buf->bufp == NULL)
+ /* Return the number of buffers that are modified. */
+ nb_reply_nr(cmdno, (long)count_changed_buffers());
+ else
+ /* Return whether the buffer is modified. */
+ nb_reply_nr(cmdno, (long)(buf->bufp->b_changed
+ || isNetbeansModified(buf->bufp)));
+/* =====================================================================*/
+ }
+ else if (streq((char *)cmd, "saveAndExit"))
+ {
+ /* Note: this will exit Vim if successful. */
+ coloncmd(":confirm qall");
+
+ /* We didn't exit: return the number of changed buffers. */
+ nb_reply_nr(cmdno, (long)count_changed_buffers());
+/* =====================================================================*/
+ }
+ else if (streq((char *)cmd, "getCursor"))
+ {
+ char_u text[200];
+
+ /* Note: nb_getbufno() may return -1. This indicates the IDE
+ * didn't assign a number to the current buffer in response to a
+ * fileOpened event. */
+ sprintf((char *)text, "%d %ld %d %ld",
+ nb_getbufno(curbuf),
+ (long)curwin->w_cursor.lnum,
+ (int)curwin->w_cursor.col,
+ pos2off(curbuf, &curwin->w_cursor));
+ nb_reply_text(cmdno, text);
+/* =====================================================================*/
+ }
+ else if (streq((char *)cmd, "getAnno"))
+ {
+ long linenum = 0;
+#ifdef FEAT_SIGNS
+ if (buf == NULL || buf->bufp == NULL)
+ {
+ nbdebug((" Invalid buffer identifier in getAnno\n"));
+ emsg("E652: Invalid buffer identifier in getAnno");
+ retval = FAIL;
+ }
+ else
+ {
+ int serNum;
+
+ cp = (char *)args;
+ serNum = strtol(cp, &cp, 10);
+ /* If the sign isn't found linenum will be zero. */
+ linenum = (long)buf_findsign(buf->bufp, serNum, NULL);
+ }
+#endif
+ nb_reply_nr(cmdno, linenum);
+/* =====================================================================*/
+ }
+ else if (streq((char *)cmd, "getLength"))
+ {
+ long len = 0;
+
+ if (buf == NULL || buf->bufp == NULL)
+ {
+ nbdebug((" invalid buffer identifier in getLength\n"));
+ emsg("E632: invalid buffer identifier in getLength");
+ retval = FAIL;
+ }
+ else
+ {
+ len = get_buf_size(buf->bufp);
+ }
+ nb_reply_nr(cmdno, len);
+/* =====================================================================*/
+ }
+ else if (streq((char *)cmd, "getText"))
+ {
+ long len;
+ linenr_T nlines;
+ char_u *text = NULL;
+ linenr_T lno = 1;
+ char_u *p;
+ char_u *line;
+
+ if (buf == NULL || buf->bufp == NULL)
+ {
+ nbdebug((" invalid buffer identifier in getText\n"));
+ emsg("E633: invalid buffer identifier in getText");
+ retval = FAIL;
+ }
+ else
+ {
+ len = get_buf_size(buf->bufp);
+ nlines = buf->bufp->b_ml.ml_line_count;
+ text = alloc((unsigned)((len > 0)
+ ? ((len + nlines) * 2) : 4));
+ if (text == NULL)
+ {
+ nbdebug((" nb_do_cmd: getText has null text field\n"));
+ retval = FAIL;
+ }
+ else
+ {
+ p = text;
+ *p++ = '\"';
+ for (; lno <= nlines ; lno++)
+ {
+ line = nb_quote(ml_get_buf(buf->bufp, lno, FALSE));
+ if (line != NULL)
+ {
+ STRCPY(p, line);
+ p += STRLEN(line);
+ *p++ = '\\';
+ *p++ = 'n';
+ vim_free(line);
+ }
+ }
+ *p++ = '\"';
+ *p = '\0';
+ }
+ }
+ if (text == NULL)
+ nb_reply_text(cmdno, (char_u *)"");
+ else
+ {
+ nb_reply_text(cmdno, text);
+ vim_free(text);
+ }
+/* =====================================================================*/
+ }
+ else if (streq((char *)cmd, "remove"))
+ {
+ long count;
+ pos_T first, last;
+ pos_T *pos;
+ pos_T *next;
+ linenr_T del_from_lnum, del_to_lnum; /* lines to be deleted as a whole */
+ int oldFire = netbeansFireChanges;
+ int oldSuppress = netbeansSuppressNoLines;
+ int wasChanged;
+
+ if (skip >= SKIP_STOP)
+ {
+ nbdebug((" Skipping %s command\n", (char *) cmd));
+ nb_reply_nil(cmdno);
+ return OK;
+ }
+
+ if (buf == NULL || buf->bufp == NULL)
+ {
+ nbdebug((" invalid buffer identifier in remove\n"));
+ emsg("E634: invalid buffer identifier in remove");
+ retval = FAIL;
+ }
+ else
+ {
+ netbeansFireChanges = FALSE;
+ netbeansSuppressNoLines = TRUE;
+
+ nb_set_curbuf(buf->bufp);
+ wasChanged = buf->bufp->b_changed;
+ cp = (char *)args;
+ off = strtol(cp, &cp, 10);
+ count = strtol(cp, &cp, 10);
+ args = (char_u *)cp;
+ /* delete "count" chars, starting at "off" */
+ pos = off2pos(buf->bufp, off);
+ if (!pos)
+ {
+ nbdebug((" !bad position\n"));
+ nb_reply_text(cmdno, (char_u *)"!bad position");
+ netbeansFireChanges = oldFire;
+ netbeansSuppressNoLines = oldSuppress;
+ return FAIL;
+ }
+ first = *pos;
+ nbdebug((" FIRST POS: line %d, col %d\n",
+ first.lnum, first.col));
+ pos = off2pos(buf->bufp, off+count-1);
+ if (!pos)
+ {
+ nbdebug((" !bad count\n"));
+ nb_reply_text(cmdno, (char_u *)"!bad count");
+ netbeansFireChanges = oldFire;
+ netbeansSuppressNoLines = oldSuppress;
+ return FAIL;
+ }
+ last = *pos;
+ nbdebug((" LAST POS: line %d, col %d\n",
+ last.lnum, last.col));
+ del_from_lnum = first.lnum;
+ del_to_lnum = last.lnum;
+ do_update = 1;
+
+ /* Get the position of the first byte after the deleted
+ * section. "next" is NULL when deleting to the end of the
+ * file. */
+ next = off2pos(buf->bufp, off + count);
+
+ /* Remove part of the first line. */
+ if (first.col != 0
+ || (next != NULL && first.lnum == next->lnum))
+ {
+ if (first.lnum != last.lnum
+ || (next != NULL && first.lnum != next->lnum))
+ {
+ /* remove to the end of the first line */
+ nb_partialremove(first.lnum, first.col,
+ (colnr_T)MAXCOL);
+ if (first.lnum == last.lnum)
+ {
+ /* Partial line to remove includes the end of
+ * line. Join the line with the next one, have
+ * the next line deleted below. */
+ nb_joinlines(first.lnum, next->lnum);
+ del_to_lnum = next->lnum;
+ }
+ }
+ else
+ {
+ /* remove within one line */
+ nb_partialremove(first.lnum, first.col, last.col);
+ }
+ ++del_from_lnum; /* don't delete the first line */
+ }
+
+ /* Remove part of the last line. */
+ if (first.lnum != last.lnum && next != NULL
+ && next->col != 0 && last.lnum == next->lnum)
+ {
+ nb_partialremove(last.lnum, 0, last.col);
+ if (del_from_lnum > first.lnum)
+ {
+ /* Join end of last line to start of first line; last
+ * line is deleted below. */
+ nb_joinlines(first.lnum, last.lnum);
+ }
+ else
+ /* First line is deleted as a whole, keep the last
+ * line. */
+ --del_to_lnum;
+ }
+
+ /* First is partial line; last line to remove includes
+ * the end of line; join first line to line following last
+ * line; line following last line is deleted below. */
+ if (first.lnum != last.lnum && del_from_lnum > first.lnum
+ && next != NULL && last.lnum != next->lnum)
+ {
+ nb_joinlines(first.lnum, next->lnum);
+ del_to_lnum = next->lnum;
+ }
+
+ /* Delete whole lines if there are any. */
+ if (del_to_lnum >= del_from_lnum)
+ {
+ int i;
+
+ /* delete signs from the lines being deleted */
+ for (i = del_from_lnum; i <= del_to_lnum; i++)
+ {
+ int id = buf_findsign_id(buf->bufp, (linenr_T)i, NULL);
+ if (id > 0)
+ {
+ nbdebug((" Deleting sign %d on line %d\n",
+ id, i));
+ buf_delsign(buf->bufp, 0, id, NULL);
+ }
+ else
+ {
+ nbdebug((" No sign on line %d\n", i));
+ }
+ }
+
+ nbdebug((" Deleting lines %d through %d\n",
+ del_from_lnum, del_to_lnum));
+ curwin->w_cursor.lnum = del_from_lnum;
+ curwin->w_cursor.col = 0;
+ del_lines(del_to_lnum - del_from_lnum + 1, FALSE);
+ }
+
+ /* Leave cursor at first deleted byte. */
+ curwin->w_cursor = first;
+ check_cursor_lnum();
+ buf->bufp->b_changed = wasChanged; /* logically unchanged */
+ netbeansFireChanges = oldFire;
+ netbeansSuppressNoLines = oldSuppress;
+
+ u_blockfree(buf->bufp);
+ u_clearall(buf->bufp);
+ }
+ nb_reply_nil(cmdno);
+/* =====================================================================*/
+ }
+ else if (streq((char *)cmd, "insert"))
+ {
+ char_u *to_free;
+
+ if (skip >= SKIP_STOP)
+ {
+ nbdebug((" Skipping %s command\n", (char *) cmd));
+ nb_reply_nil(cmdno);
+ return OK;
+ }
+
+ /* get offset */
+ cp = (char *)args;
+ off = strtol(cp, &cp, 10);
+ args = (char_u *)cp;
+
+ /* get text to be inserted */
+ args = skipwhite(args);
+ args = to_free = (char_u *)nb_unquote(args, NULL);
+ /*
+ nbdebug((" CHUNK[%d]: %d bytes at offset %d\n",
+ buf->bufp->b_ml.ml_line_count, STRLEN(args), off));
+ */
+
+ if (buf == NULL || buf->bufp == NULL)
+ {
+ nbdebug((" invalid buffer identifier in insert\n"));
+ emsg("E635: invalid buffer identifier in insert");
+ retval = FAIL;
+ }
+ else if (args != NULL)
+ {
+ int ff_detected = EOL_UNKNOWN;
+ int buf_was_empty = (buf->bufp->b_ml.ml_flags & ML_EMPTY);
+ size_t len = 0;
+ int added = 0;
+ int oldFire = netbeansFireChanges;
+ int old_b_changed;
+ char_u *nlp;
+ linenr_T lnum;
+ linenr_T lnum_start;
+ pos_T *pos;
+
+ netbeansFireChanges = 0;
+
+ /* Jump to the buffer where we insert. After this "curbuf"
+ * can be used. */
+ nb_set_curbuf(buf->bufp);
+ old_b_changed = curbuf->b_changed;
+
+ /* Convert the specified character offset into a lnum/col
+ * position. */
+ pos = off2pos(curbuf, off);
+ if (pos != NULL)
+ {
+ if (pos->lnum <= 0)
+ lnum_start = 1;
+ else
+ lnum_start = pos->lnum;
+ }
+ else
+ {
+ /* If the given position is not found, assume we want
+ * the end of the file. See setLocAndSize HACK. */
+ if (buf_was_empty)
+ lnum_start = 1; /* above empty line */
+ else
+ lnum_start = curbuf->b_ml.ml_line_count + 1;
+ }
+
+ /* "lnum" is the line where we insert: either append to it or
+ * insert a new line above it. */
+ lnum = lnum_start;
+
+ /* Loop over the "\n" separated lines of the argument. */
+ do_update = 1;
+ while (*args != NUL)
+ {
+ nlp = vim_strchr(args, '\n');
+ if (nlp == NULL)
+ {
+ /* Incomplete line, probably truncated. Next "insert"
+ * command should append to this one. */
+ len = STRLEN(args);
+ }
+ else
+ {
+ len = nlp - args;
+
+ /*
+ * We need to detect EOL style, because the commands
+ * use a character offset.
+ */
+ if (nlp > args && nlp[-1] == '\r')
+ {
+ ff_detected = EOL_DOS;
+ --len;
+ }
+ else
+ ff_detected = EOL_UNIX;
+ }
+ args[len] = NUL;
+
+ if (lnum == lnum_start
+ && ((pos != NULL && pos->col > 0)
+ || (lnum == 1 && buf_was_empty)))
+ {
+ char_u *oldline = ml_get(lnum);
+ char_u *newline;
+
+ /* Insert halfway a line. */
+ newline = alloc_check(
+ (unsigned)(STRLEN(oldline) + len + 1));
+ if (newline != NULL)
+ {
+ mch_memmove(newline, oldline, (size_t)pos->col);
+ newline[pos->col] = NUL;
+ STRCAT(newline, args);
+ STRCAT(newline, oldline + pos->col);
+ ml_replace(lnum, newline, FALSE);
+ }
+ }
+ else
+ {
+ /* Append a new line. Not that we always do this,
+ * also when the text doesn't end in a "\n". */
+ ml_append((linenr_T)(lnum - 1), args,
+ (colnr_T)(len + 1), FALSE);
+ ++added;
+ }
+
+ if (nlp == NULL)
+ break;
+ ++lnum;
+ args = nlp + 1;
+ }
+
+ /* Adjust the marks below the inserted lines. */
+ appended_lines_mark(lnum_start - 1, (long)added);
+
+ /*
+ * When starting with an empty buffer set the fileformat.
+ * This is just guessing...
+ */
+ if (buf_was_empty)
+ {
+ if (ff_detected == EOL_UNKNOWN)
+#if defined(MSWIN)
+ ff_detected = EOL_DOS;
+#else
+ ff_detected = EOL_UNIX;
+#endif
+ set_fileformat(ff_detected, OPT_LOCAL);
+ curbuf->b_start_ffc = *curbuf->b_p_ff;
+ }
+
+ /*
+ * XXX - GRP - Is the next line right? If I've inserted
+ * text the buffer has been updated but not written. Will
+ * netbeans guarantee to write it? Even if I do a :q! ?
+ */
+ curbuf->b_changed = old_b_changed; /* logically unchanged */
+ netbeansFireChanges = oldFire;
+
+ /* Undo info is invalid now... */
+ u_blockfree(curbuf);
+ u_clearall(curbuf);
+ }
+ vim_free(to_free);
+ nb_reply_nil(cmdno); /* or !error */
+ }
+ else
+ {
+ nbdebug(("UNIMPLEMENTED FUNCTION: %s\n", cmd));
+ nb_reply_nil(cmdno);
+ retval = FAIL;
+ }
+ }
+ else /* Not a function; no reply required. */
+ {
+/* =====================================================================*/
+ if (streq((char *)cmd, "create"))
+ {
+ /* Create a buffer without a name. */
+ if (buf == NULL)
+ {
+ nbdebug((" invalid buffer identifier in create\n"));
+ emsg("E636: invalid buffer identifier in create");
+ return FAIL;
+ }
+ VIM_CLEAR(buf->displayname);
+
+ netbeansReadFile = 0; /* don't try to open disk file */
+ do_ecmd(0, NULL, 0, 0, ECMD_ONE, ECMD_HIDE + ECMD_OLDBUF, curwin);
+ netbeansReadFile = 1;
+ buf->bufp = curbuf;
+ maketitle();
+ buf->insertDone = FALSE;
+#if defined(FEAT_MENU) && defined(FEAT_GUI)
+ if (gui.in_use)
+ gui_update_menus(0);
+#endif
+/* =====================================================================*/
+ }
+ else if (streq((char *)cmd, "insertDone"))
+ {
+ if (buf == NULL || buf->bufp == NULL)
+ {
+ nbdebug((" invalid buffer identifier in insertDone\n"));
+ }
+ else
+ {
+ buf->bufp->b_start_eol = *args == 'T';
+ buf->insertDone = TRUE;
+ args += 2;
+ buf->bufp->b_p_ro = *args == 'T';
+ print_read_msg(buf);
+ }
+/* =====================================================================*/
+ }
+ else if (streq((char *)cmd, "saveDone"))
+ {
+ long savedChars = atol((char *)args);
+
+ if (buf == NULL || buf->bufp == NULL)
+ {
+ nbdebug((" invalid buffer identifier in saveDone\n"));
+ }
+ else
+ print_save_msg(buf, savedChars);
+/* =====================================================================*/
+ }
+ else if (streq((char *)cmd, "startDocumentListen"))
+ {
+ if (buf == NULL)
+ {
+ nbdebug((" invalid buffer identifier in startDocumentListen\n"));
+ emsg("E637: invalid buffer identifier in startDocumentListen");
+ return FAIL;
+ }
+ buf->fireChanges = 1;
+/* =====================================================================*/
+ }
+ else if (streq((char *)cmd, "stopDocumentListen"))
+ {
+ if (buf == NULL)
+ {
+ nbdebug((" invalid buffer identifier in stopDocumentListen\n"));
+ emsg("E638: invalid buffer identifier in stopDocumentListen");
+ return FAIL;
+ }
+ buf->fireChanges = 0;
+ if (buf->bufp != NULL && buf->bufp->b_was_netbeans_file)
+ {
+ if (!buf->bufp->b_netbeans_file)
+ {
+ nbdebug(("E658: NetBeans connection lost for buffer %ld\n", buf->bufp->b_fnum));
+ semsg(_("E658: NetBeans connection lost for buffer %d"),
+ buf->bufp->b_fnum);
+ }
+ else
+ {
+ /* NetBeans uses stopDocumentListen when it stops editing
+ * a file. It then expects the buffer in Vim to
+ * disappear. */
+ do_bufdel(DOBUF_DEL, (char_u *)"", 1,
+ buf->bufp->b_fnum, buf->bufp->b_fnum, TRUE);
+ vim_memset(buf, 0, sizeof(nbbuf_T));
+ }
+ }
+/* =====================================================================*/
+ }
+ else if (streq((char *)cmd, "setTitle"))
+ {
+ if (buf == NULL)
+ {
+ nbdebug((" invalid buffer identifier in setTitle\n"));
+ emsg("E639: invalid buffer identifier in setTitle");
+ return FAIL;
+ }
+ vim_free(buf->displayname);
+ buf->displayname = nb_unquote(args, NULL);
+/* =====================================================================*/
+ }
+ else if (streq((char *)cmd, "initDone"))
+ {
+ if (buf == NULL || buf->bufp == NULL)
+ {
+ nbdebug((" invalid buffer identifier in initDone\n"));
+ emsg("E640: invalid buffer identifier in initDone");
+ return FAIL;
+ }
+ do_update = 1;
+ buf->initDone = TRUE;
+ nb_set_curbuf(buf->bufp);
+ apply_autocmds(EVENT_BUFREADPOST, 0, 0, FALSE, buf->bufp);
+
+ /* handle any postponed key commands */
+ handle_key_queue();
+/* =====================================================================*/
+ }
+ else if (streq((char *)cmd, "setBufferNumber")
+ || streq((char *)cmd, "putBufferNumber"))
+ {
+ char_u *path;
+ buf_T *bufp;
+
+ if (buf == NULL)
+ {
+ nbdebug((" invalid buffer identifier in setBufferNumber\n"));
+ emsg("E641: invalid buffer identifier in setBufferNumber");
+ return FAIL;
+ }
+ path = (char_u *)nb_unquote(args, NULL);
+ if (path == NULL)
+ return FAIL;
+ bufp = buflist_findname(path);
+ vim_free(path);
+ if (bufp == NULL)
+ {
+ nbdebug((" File %s not found in setBufferNumber\n", args));
+ semsg("E642: File %s not found in setBufferNumber", args);
+ return FAIL;
+ }
+ buf->bufp = bufp;
+ buf->nbbuf_number = bufp->b_fnum;
+
+ /* "setBufferNumber" has the side effect of jumping to the buffer
+ * (don't know why!). Don't do that for "putBufferNumber". */
+ if (*cmd != 'p')
+ coloncmd(":buffer %d", bufp->b_fnum);
+ else
+ {
+ buf->initDone = TRUE;
+
+ /* handle any postponed key commands */
+ handle_key_queue();
+ }
+
+/* =====================================================================*/
+ }
+ else if (streq((char *)cmd, "setFullName"))
+ {
+ if (buf == NULL)
+ {
+ nbdebug((" invalid buffer identifier in setFullName\n"));
+ emsg("E643: invalid buffer identifier in setFullName");
+ return FAIL;
+ }
+ vim_free(buf->displayname);
+ buf->displayname = nb_unquote(args, NULL);
+
+ netbeansReadFile = 0; /* don't try to open disk file */
+ do_ecmd(0, (char_u *)buf->displayname, 0, 0, ECMD_ONE,
+ ECMD_HIDE + ECMD_OLDBUF, curwin);
+ netbeansReadFile = 1;
+ buf->bufp = curbuf;
+ maketitle();
+#if defined(FEAT_MENU) && defined(FEAT_GUI)
+ if (gui.in_use)
+ gui_update_menus(0);
+#endif
+/* =====================================================================*/
+ }
+ else if (streq((char *)cmd, "editFile"))
+ {
+ if (buf == NULL)
+ {
+ nbdebug((" invalid buffer identifier in editFile\n"));
+ emsg("E644: invalid buffer identifier in editFile");
+ return FAIL;
+ }
+ /* Edit a file: like create + setFullName + read the file. */
+ vim_free(buf->displayname);
+ buf->displayname = nb_unquote(args, NULL);
+ do_ecmd(0, (char_u *)buf->displayname, NULL, NULL, ECMD_ONE,
+ ECMD_HIDE + ECMD_OLDBUF, curwin);
+ buf->bufp = curbuf;
+ buf->initDone = TRUE;
+ do_update = 1;
+#if defined(FEAT_TITLE)
+ maketitle();
+#endif
+#if defined(FEAT_MENU) && defined(FEAT_GUI)
+ if (gui.in_use)
+ gui_update_menus(0);
+#endif
+/* =====================================================================*/
+ }
+ else if (streq((char *)cmd, "setVisible"))
+ {
+ if (buf == NULL || buf->bufp == NULL)
+ {
+ nbdebug((" invalid buffer identifier in setVisible\n"));
+ /* This message was commented out, probably because it can
+ * happen when shutting down. */
+ if (p_verbose > 0)
+ emsg("E645: invalid buffer identifier in setVisible");
+ return FAIL;
+ }
+ if (streq((char *)args, "T") && buf->bufp != curbuf)
+ {
+ exarg_T exarg;
+ exarg.cmd = (char_u *)"goto";
+ exarg.forceit = FALSE;
+ dosetvisible = TRUE;
+ goto_buffer(&exarg, DOBUF_FIRST, FORWARD, buf->bufp->b_fnum);
+ do_update = 1;
+ dosetvisible = FALSE;
+
+#ifdef FEAT_GUI
+ /* Side effect!!!. */
+ if (gui.in_use)
+ gui_mch_set_foreground();
+#endif
+ }
+/* =====================================================================*/
+ }
+ else if (streq((char *)cmd, "raise"))
+ {
+#ifdef FEAT_GUI
+ /* Bring gvim to the foreground. */
+ if (gui.in_use)
+ gui_mch_set_foreground();
+#endif
+/* =====================================================================*/
+ }
+ else if (streq((char *)cmd, "setModified"))
+ {
+ int prev_b_changed;
+
+ if (buf == NULL || buf->bufp == NULL)
+ {
+ nbdebug((" invalid buffer identifier in setModified\n"));
+ /* This message was commented out, probably because it can
+ * happen when shutting down. */
+ if (p_verbose > 0)
+ emsg("E646: invalid buffer identifier in setModified");
+ return FAIL;
+ }
+ prev_b_changed = buf->bufp->b_changed;
+ if (streq((char *)args, "T"))
+ buf->bufp->b_changed = TRUE;
+ else
+ {
+ stat_T st;
+
+ /* Assume NetBeans stored the file. Reset the timestamp to
+ * avoid "file changed" warnings. */
+ if (buf->bufp->b_ffname != NULL
+ && mch_stat((char *)buf->bufp->b_ffname, &st) >= 0)
+ buf_store_time(buf->bufp, &st, buf->bufp->b_ffname);
+ buf->bufp->b_changed = FALSE;
+ }
+ buf->modified = buf->bufp->b_changed;
+ if (prev_b_changed != buf->bufp->b_changed)
+ {
+ check_status(buf->bufp);
+ redraw_tabline = TRUE;
+#ifdef FEAT_TITLE
+ maketitle();
+#endif
+ update_screen(0);
+ }
+/* =====================================================================*/
+ }
+ else if (streq((char *)cmd, "setModtime"))
+ {
+ if (buf == NULL || buf->bufp == NULL)
+ nbdebug((" invalid buffer identifier in setModtime\n"));
+ else
+ buf->bufp->b_mtime = atoi((char *)args);
+/* =====================================================================*/
+ }
+ else if (streq((char *)cmd, "setReadOnly"))
+ {
+ if (buf == NULL || buf->bufp == NULL)
+ nbdebug((" invalid buffer identifier in setReadOnly\n"));
+ else if (streq((char *)args, "T"))
+ buf->bufp->b_p_ro = TRUE;
+ else
+ buf->bufp->b_p_ro = FALSE;
+/* =====================================================================*/
+ }
+ else if (streq((char *)cmd, "setMark"))
+ {
+ /* not yet */
+/* =====================================================================*/
+ }
+ else if (streq((char *)cmd, "showBalloon"))
+ {
+#if defined(FEAT_BEVAL_GUI)
+ static char *text = NULL;
+
+ /*
+ * Set up the Balloon Expression Evaluation area.
+ * Ignore 'ballooneval' here.
+ * The text pointer must remain valid for a while.
+ */
+ if (balloonEval != NULL)
+ {
+ vim_free(text);
+ text = nb_unquote(args, NULL);
+ if (text != NULL)
+ gui_mch_post_balloon(balloonEval, (char_u *)text);
+ }
+#endif
+/* =====================================================================*/
+ }
+ else if (streq((char *)cmd, "setDot"))
+ {
+ pos_T *pos;
+#ifdef NBDEBUG
+ char_u *s;
+#endif
+
+ if (buf == NULL || buf->bufp == NULL)
+ {
+ nbdebug((" invalid buffer identifier in setDot\n"));
+ emsg("E647: invalid buffer identifier in setDot");
+ return FAIL;
+ }
+
+ nb_set_curbuf(buf->bufp);
+
+ /* Don't want Visual mode now. */
+ if (VIsual_active)
+ end_visual_mode();
+#ifdef NBDEBUG
+ s = args;
+#endif
+ pos = get_off_or_lnum(buf->bufp, &args);
+ if (pos)
+ {
+ curwin->w_cursor = *pos;
+ check_cursor();
+#ifdef FEAT_FOLDING
+ foldOpenCursor();
+#endif
+ }
+ else
+ {
+ nbdebug((" BAD POSITION in setDot: %s\n", s));
+ }
+
+ /* gui_update_cursor(TRUE, FALSE); */
+ /* update_curbuf(NOT_VALID); */
+ update_topline(); /* scroll to show the line */
+ update_screen(VALID);
+ setcursor();
+ cursor_on();
+ out_flush_cursor(TRUE, FALSE);
+
+ /* Quit a hit-return or more prompt. */
+ if (State == HITRETURN || State == ASKMORE)
+ {
+#ifdef FEAT_GUI_GTK
+ if (gui.in_use && gtk_main_level() > 0)
+ gtk_main_quit();
+#endif
+ }
+/* =====================================================================*/
+ }
+ else if (streq((char *)cmd, "close"))
+ {
+#ifdef NBDEBUG
+ char *name = "<NONE>";
+#endif
+
+ if (buf == NULL)
+ {
+ nbdebug((" invalid buffer identifier in close\n"));
+ emsg("E648: invalid buffer identifier in close");
+ return FAIL;
+ }
+
+#ifdef NBDEBUG
+ if (buf->displayname != NULL)
+ name = buf->displayname;
+#endif
+ if (buf->bufp == NULL)
+ {
+ nbdebug((" invalid buffer identifier in close\n"));
+ /* This message was commented out, probably because it can
+ * happen when shutting down. */
+ if (p_verbose > 0)
+ emsg("E649: invalid buffer identifier in close");
+ }
+ nbdebug((" CLOSE %d: %s\n", bufno, name));
+#ifdef FEAT_GUI
+ need_mouse_correct = TRUE;
+#endif
+ if (buf->bufp != NULL)
+ do_buffer(DOBUF_WIPE, DOBUF_FIRST, FORWARD,
+ buf->bufp->b_fnum, TRUE);
+ buf->bufp = NULL;
+ buf->initDone = FALSE;
+ do_update = 1;
+/* =====================================================================*/
+ }
+ else if (streq((char *)cmd, "setStyle")) /* obsolete... */
+ {
+ nbdebug((" setStyle is obsolete!\n"));
+/* =====================================================================*/
+ }
+ else if (streq((char *)cmd, "setExitDelay"))
+ {
+ /* Only used in version 2.1. */
+/* =====================================================================*/
+ }
+ else if (streq((char *)cmd, "defineAnnoType"))
+ {
+#ifdef FEAT_SIGNS
+ int typeNum;
+ char_u *typeName;
+ char_u *tooltip;
+ char_u *p;
+ char_u *glyphFile;
+ int parse_error = FALSE;
+ char_u *fg;
+ char_u *bg;
+
+ if (buf == NULL)
+ {
+ nbdebug((" invalid buffer identifier in defineAnnoType\n"));
+ emsg("E650: invalid buffer identifier in defineAnnoType");
+ return FAIL;
+ }
+
+ cp = (char *)args;
+ typeNum = strtol(cp, &cp, 10);
+ args = (char_u *)cp;
+ args = skipwhite(args);
+ typeName = (char_u *)nb_unquote(args, &args);
+ args = skipwhite(args + 1);
+ tooltip = (char_u *)nb_unquote(args, &args);
+ args = skipwhite(args + 1);
+
+ p = (char_u *)nb_unquote(args, &args);
+ glyphFile = vim_strsave_escaped(p, escape_chars);
+ vim_free(p);
+
+ args = skipwhite(args + 1);
+ p = skiptowhite(args);
+ if (*p != NUL)
+ {
+ *p = NUL;
+ p = skipwhite(p + 1);
+ }
+ fg = vim_strsave(args);
+ bg = vim_strsave(p);
+ if (STRLEN(fg) > MAX_COLOR_LENGTH || STRLEN(bg) > MAX_COLOR_LENGTH)
+ {
+ emsg("E532: highlighting color name too long in defineAnnoType");
+ vim_free(typeName);
+ parse_error = TRUE;
+ }
+ else if (typeName != NULL && tooltip != NULL && glyphFile != NULL)
+ addsigntype(buf, typeNum, typeName, tooltip, glyphFile, fg, bg);
+ else
+ vim_free(typeName);
+
+ /* don't free typeName; it's used directly in addsigntype() */
+ vim_free(fg);
+ vim_free(bg);
+ vim_free(tooltip);
+ vim_free(glyphFile);
+ if (parse_error)
+ return FAIL;
+
+#endif
+/* =====================================================================*/
+ }
+ else if (streq((char *)cmd, "addAnno"))
+ {
+#ifdef FEAT_SIGNS
+ int serNum;
+ int localTypeNum;
+ int typeNum;
+ pos_T *pos;
+
+ if (buf == NULL || buf->bufp == NULL)
+ {
+ nbdebug((" invalid buffer identifier in addAnno\n"));
+ emsg("E651: invalid buffer identifier in addAnno");
+ return FAIL;
+ }
+
+ do_update = 1;
+
+ cp = (char *)args;
+ serNum = strtol(cp, &cp, 10);
+
+ /* Get the typenr specific for this buffer and convert it to
+ * the global typenumber, as used for the sign name. */
+ localTypeNum = strtol(cp, &cp, 10);
+ args = (char_u *)cp;
+ typeNum = mapsigntype(buf, localTypeNum);
+
+ pos = get_off_or_lnum(buf->bufp, &args);
+
+ cp = (char *)args;
+ vim_ignored = (int)strtol(cp, &cp, 10);
+ args = (char_u *)cp;
+# ifdef NBDEBUG
+ if (vim_ignored != -1)
+ {
+ nbdebug((" partial line annotation -- Not Yet Implemented!\n"));
+ }
+# endif
+ if (serNum >= GUARDEDOFFSET)
+ {
+ nbdebug((" too many annotations! ignoring...\n"));
+ return FAIL;
+ }
+ if (pos)
+ {
+ coloncmd(":sign place %d line=%ld name=%d buffer=%d",
+ serNum, pos->lnum, typeNum, buf->bufp->b_fnum);
+ if (typeNum == curPCtype)
+ coloncmd(":sign jump %d buffer=%d", serNum,
+ buf->bufp->b_fnum);
+ }
+#endif
+/* =====================================================================*/
+ }
+ else if (streq((char *)cmd, "removeAnno"))
+ {
+#ifdef FEAT_SIGNS
+ int serNum;
+
+ if (buf == NULL || buf->bufp == NULL)
+ {
+ nbdebug((" invalid buffer identifier in removeAnno\n"));
+ return FAIL;
+ }
+ do_update = 1;
+ cp = (char *)args;
+ serNum = strtol(cp, &cp, 10);
+ args = (char_u *)cp;
+ coloncmd(":sign unplace %d buffer=%d",
+ serNum, buf->bufp->b_fnum);
+ redraw_buf_later(buf->bufp, NOT_VALID);
+#endif
+/* =====================================================================*/
+ }
+ else if (streq((char *)cmd, "moveAnnoToFront"))
+ {
+#ifdef FEAT_SIGNS
+ nbdebug((" moveAnnoToFront: Not Yet Implemented!\n"));
+#endif
+/* =====================================================================*/
+ }
+ else if (streq((char *)cmd, "guard") || streq((char *)cmd, "unguard"))
+ {
+ int len;
+ pos_T first;
+ pos_T last;
+ pos_T *pos;
+ int un = (cmd[0] == 'u');
+ static int guardId = GUARDEDOFFSET;
+
+ if (skip >= SKIP_STOP)
+ {
+ nbdebug((" Skipping %s command\n", (char *) cmd));
+ return OK;
+ }
+
+ nb_init_graphics();
+
+ if (buf == NULL || buf->bufp == NULL)
+ {
+ nbdebug((" invalid buffer identifier in %s command\n", cmd));
+ return FAIL;
+ }
+ nb_set_curbuf(buf->bufp);
+ cp = (char *)args;
+ off = strtol(cp, &cp, 10);
+ len = strtol(cp, NULL, 10);
+ args = (char_u *)cp;
+ pos = off2pos(buf->bufp, off);
+ do_update = 1;
+ if (!pos)
+ nbdebug((" no such start pos in %s, %ld\n", cmd, off));
+ else
+ {
+ first = *pos;
+ pos = off2pos(buf->bufp, off + len - 1);
+ if (pos != NULL && pos->col == 0)
+ {
+ /*
+ * In Java Swing the offset is a position between 2
+ * characters. If col == 0 then we really want the
+ * previous line as the end.
+ */
+ pos = off2pos(buf->bufp, off + len - 2);
+ }
+ if (!pos)
+ nbdebug((" no such end pos in %s, %ld\n",
+ cmd, off + len - 1));
+ else
+ {
+ long lnum;
+ last = *pos;
+ /* set highlight for region */
+ nbdebug((" %sGUARD %ld,%d to %ld,%d\n", (un) ? "UN" : "",
+ first.lnum, first.col,
+ last.lnum, last.col));
+#ifdef FEAT_SIGNS
+ for (lnum = first.lnum; lnum <= last.lnum; lnum++)
+ {
+ if (un)
+ {
+ /* never used */
+ }
+ else
+ {
+ if (buf_findsigntype_id(buf->bufp, lnum,
+ GUARDED) == 0)
+ {
+ coloncmd(
+ ":sign place %d line=%ld name=%d buffer=%d",
+ guardId++, lnum, GUARDED,
+ buf->bufp->b_fnum);
+ }
+ }
+ }
+#endif
+ redraw_buf_later(buf->bufp, NOT_VALID);
+ }
+ }
+/* =====================================================================*/
+ }
+ else if (streq((char *)cmd, "startAtomic"))
+ {
+ inAtomic = 1;
+/* =====================================================================*/
+ }
+ else if (streq((char *)cmd, "endAtomic"))
+ {
+ inAtomic = 0;
+ if (needupdate)
+ {
+ do_update = 1;
+ needupdate = 0;
+ }
+/* =====================================================================*/
+ }
+ else if (streq((char *)cmd, "save"))
+ {
+ /*
+ * NOTE - This command is obsolete wrt NetBeans. It's left in
+ * only for historical reasons.
+ */
+ if (buf == NULL || buf->bufp == NULL)
+ {
+ nbdebug((" invalid buffer identifier in %s command\n", cmd));
+ return FAIL;
+ }
+
+ /* the following is taken from ex_cmds.c (do_wqall function) */
+ if (bufIsChanged(buf->bufp))
+ {
+ /* Only write if the buffer can be written. */
+ if (p_write
+ && !buf->bufp->b_p_ro
+ && buf->bufp->b_ffname != NULL
+#ifdef FEAT_QUICKFIX
+ && !bt_dontwrite(buf->bufp)
+#endif
+ )
+ {
+ bufref_T bufref;
+
+ set_bufref(&bufref, buf->bufp);
+ buf_write_all(buf->bufp, FALSE);
+ /* an autocommand may have deleted the buffer */
+ if (!bufref_valid(&bufref))
+ buf->bufp = NULL;
+ }
+ }
+ else
+ {
+ nbdebug((" Buffer has no changes!\n"));
+ }
+/* =====================================================================*/
+ }
+ else if (streq((char *)cmd, "netbeansBuffer"))
+ {
+ if (buf == NULL || buf->bufp == NULL)
+ {
+ nbdebug((" invalid buffer identifier in %s command\n", cmd));
+ return FAIL;
+ }
+ if (*args == 'T')
+ {
+ buf->bufp->b_netbeans_file = TRUE;
+ buf->bufp->b_was_netbeans_file = TRUE;
+ }
+ else
+ buf->bufp->b_netbeans_file = FALSE;
+/* =====================================================================*/
+ }
+ else if (streq((char *)cmd, "specialKeys"))
+ {
+ special_keys(args);
+/* =====================================================================*/
+ }
+ else if (streq((char *)cmd, "actionMenuItem"))
+ {
+ /* not used yet */
+/* =====================================================================*/
+ }
+ else if (streq((char *)cmd, "version"))
+ {
+ /* not used yet */
+ }
+ else
+ {
+ nbdebug(("Unrecognised command: %s\n", cmd));
+ }
+ /*
+ * Unrecognized command is ignored.
+ */
+ }
+ if (inAtomic && do_update)
+ {
+ needupdate = 1;
+ do_update = 0;
+ }
+
+ /*
+ * Is this needed? I moved the netbeans_Xt_connect() later during startup
+ * and it may no longer be necessary. If it's not needed then needupdate
+ * and do_update can also be removed.
+ */
+ if (buf != NULL && buf->initDone && do_update)
+ {
+ update_screen(NOT_VALID);
+ setcursor();
+ cursor_on();
+ out_flush_cursor(TRUE, FALSE);
+
+ /* Quit a hit-return or more prompt. */
+ if (State == HITRETURN || State == ASKMORE)
+ {
+#ifdef FEAT_GUI_GTK
+ if (gui.in_use && gtk_main_level() > 0)
+ gtk_main_quit();
+#endif
+ }
+ }
+
+ return retval;
+}
+
+
+/*
+ * If "buf" is not the current buffer try changing to a window that edits this
+ * buffer. If there is no such window then close the current buffer and set
+ * the current buffer as "buf".
+ */
+ static void
+nb_set_curbuf(buf_T *buf)
+{
+ if (curbuf != buf) {
+ if (buf_jump_open_win(buf) != NULL)
+ return;
+ if ((swb_flags & SWB_USETAB) && buf_jump_open_tab(buf) != NULL)
+ return;
+ set_curbuf(buf, DOBUF_GOTO);
+ }
+}
+
+/*
+ * Process a vim colon command.
+ */
+ static void
+coloncmd(char *cmd, ...)
+{
+ char buf[1024];
+ va_list ap;
+
+ va_start(ap, cmd);
+ vim_vsnprintf(buf, sizeof(buf), cmd, ap);
+ va_end(ap);
+
+ nbdebug((" COLONCMD %s\n", buf));
+
+ do_cmdline((char_u *)buf, NULL, NULL, DOCMD_NOWAIT | DOCMD_KEYTYPED);
+
+ setcursor(); /* restore the cursor position */
+ out_flush_cursor(TRUE, FALSE);
+}
+
+
+/*
+ * Parse the specialKeys argument and issue the appropriate map commands.
+ */
+ static void
+special_keys(char_u *args)
+{
+ char *save_str = nb_unquote(args, NULL);
+ char *tok = strtok(save_str, " ");
+ char *sep;
+#define KEYBUFLEN 64
+ char keybuf[KEYBUFLEN];
+ char cmdbuf[256];
+
+ while (tok != NULL)
+ {
+ int i = 0;
+
+ if ((sep = strchr(tok, '-')) != NULL)
+ {
+ *sep = NUL;
+ while (*tok)
+ {
+ switch (*tok)
+ {
+ case 'A':
+ case 'M':
+ case 'C':
+ case 'S':
+ keybuf[i++] = *tok;
+ keybuf[i++] = '-';
+ break;
+ }
+ tok++;
+ }
+ tok++;
+ }
+
+ if (strlen(tok) + i < KEYBUFLEN)
+ {
+ strcpy(&keybuf[i], tok);
+ vim_snprintf(cmdbuf, sizeof(cmdbuf),
+ "<silent><%s> :nbkey %s<CR>", keybuf, keybuf);
+ do_map(0, (char_u *)cmdbuf, NORMAL, FALSE);
+ }
+ tok = strtok(NULL, " ");
+ }
+ vim_free(save_str);
+}
+
+ void
+ex_nbclose(exarg_T *eap UNUSED)
+{
+ netbeans_close();
+}
+
+ void
+ex_nbkey(exarg_T *eap)
+{
+ (void)netbeans_keystring(eap->arg);
+}
+
+ void
+ex_nbstart(
+ exarg_T *eap)
+{
+#ifdef FEAT_GUI
+# if !defined(FEAT_GUI_X11) && !defined(FEAT_GUI_GTK) \
+ && !defined(FEAT_GUI_W32)
+ if (gui.in_use)
+ {
+ emsg(_("E838: netbeans is not supported with this GUI"));
+ return;
+ }
+# endif
+#endif
+ netbeans_open((char *)eap->arg, FALSE);
+}
+
+/*
+ * Initialize highlights and signs for use by netbeans (mostly obsolete)
+ */
+ static void
+nb_init_graphics(void)
+{
+ static int did_init = FALSE;
+
+ if (!did_init)
+ {
+ coloncmd(":highlight NBGuarded guibg=Cyan guifg=Black"
+ " ctermbg=LightCyan ctermfg=Black");
+ coloncmd(":sign define %d linehl=NBGuarded", GUARDED);
+
+ did_init = TRUE;
+ }
+}
+
+/*
+ * Convert key to netbeans name. This uses the global "mod_mask".
+ */
+ static void
+netbeans_keyname(int key, char *buf)
+{
+ char *name = 0;
+ char namebuf[2];
+ int ctrl = 0;
+ int shift = 0;
+ int alt = 0;
+
+ if (mod_mask & MOD_MASK_CTRL)
+ ctrl = 1;
+ if (mod_mask & MOD_MASK_SHIFT)
+ shift = 1;
+ if (mod_mask & MOD_MASK_ALT)
+ alt = 1;
+
+
+ switch (key)
+ {
+ case K_F1: name = "F1"; break;
+ case K_S_F1: name = "F1"; shift = 1; break;
+ case K_F2: name = "F2"; break;
+ case K_S_F2: name = "F2"; shift = 1; break;
+ case K_F3: name = "F3"; break;
+ case K_S_F3: name = "F3"; shift = 1; break;
+ case K_F4: name = "F4"; break;
+ case K_S_F4: name = "F4"; shift = 1; break;
+ case K_F5: name = "F5"; break;
+ case K_S_F5: name = "F5"; shift = 1; break;
+ case K_F6: name = "F6"; break;
+ case K_S_F6: name = "F6"; shift = 1; break;
+ case K_F7: name = "F7"; break;
+ case K_S_F7: name = "F7"; shift = 1; break;
+ case K_F8: name = "F8"; break;
+ case K_S_F8: name = "F8"; shift = 1; break;
+ case K_F9: name = "F9"; break;
+ case K_S_F9: name = "F9"; shift = 1; break;
+ case K_F10: name = "F10"; break;
+ case K_S_F10: name = "F10"; shift = 1; break;
+ case K_F11: name = "F11"; break;
+ case K_S_F11: name = "F11"; shift = 1; break;
+ case K_F12: name = "F12"; break;
+ case K_S_F12: name = "F12"; shift = 1; break;
+ default:
+ if (key >= ' ' && key <= '~')
+ {
+ /* Allow ASCII characters. */
+ name = namebuf;
+ namebuf[0] = key;
+ namebuf[1] = NUL;
+ }
+ else
+ name = "X";
+ break;
+ }
+
+ buf[0] = '\0';
+ if (ctrl)
+ strcat(buf, "C");
+ if (shift)
+ strcat(buf, "S");
+ if (alt)
+ strcat(buf, "M"); /* META */
+ if (ctrl || shift || alt)
+ strcat(buf, "-");
+ strcat(buf, name);
+}
+
+#if defined(FEAT_BEVAL) || defined(PROTO)
+/*
+ * Function to be called for balloon evaluation. Grabs the text under the
+ * cursor and sends it to the debugger for evaluation. The debugger should
+ * respond with a showBalloon command when there is a useful result.
+ */
+ void
+netbeans_beval_cb(
+ BalloonEval *beval,
+ int state UNUSED)
+{
+ win_T *wp;
+ char_u *text;
+ linenr_T lnum;
+ int col;
+ char *buf;
+ char_u *p;
+
+ /* Don't do anything when 'ballooneval' is off, messages scrolled the
+ * windows up or we have no connection. */
+ if (!can_use_beval() || !NETBEANS_OPEN)
+ return;
+
+ if (get_beval_info(beval, TRUE, &wp, &lnum, &text, &col) == OK)
+ {
+ /* Send debugger request. Only when the text is of reasonable
+ * length. */
+ if (text != NULL && text[0] != NUL && STRLEN(text) < MAXPATHL)
+ {
+ buf = (char *)alloc(MAXPATHL * 2 + 25);
+ if (buf != NULL)
+ {
+ p = nb_quote(text);
+ if (p != NULL)
+ {
+ vim_snprintf(buf, MAXPATHL * 2 + 25,
+ "0:balloonText=%d \"%s\"\n", r_cmdno, p);
+ vim_free(p);
+ }
+ nbdebug(("EVT: %s", buf));
+ nb_send(buf, "netbeans_beval_cb");
+ vim_free(buf);
+ }
+ }
+ vim_free(text);
+ }
+}
+#endif
+
+/*
+ * Return TRUE when the netbeans connection is active.
+ */
+ int
+netbeans_active(void)
+{
+ return NETBEANS_OPEN;
+}
+
+/*
+ * Tell netbeans that the window was opened, ready for commands.
+ */
+ void
+netbeans_open(char *params, int doabort)
+{
+ char *cmd = "0:startupDone=0\n";
+
+ if (NETBEANS_OPEN)
+ {
+ emsg(_("E511: netbeans already connected"));
+ return;
+ }
+
+ if (netbeans_connect(params, doabort) != OK)
+ return;
+
+ nbdebug(("EVT: %s", cmd));
+ nb_send(cmd, "netbeans_startup_done");
+
+ /* update the screen after having added the gutter */
+ changed_window_setting();
+ update_screen(CLEAR);
+ setcursor();
+ cursor_on();
+ out_flush_cursor(TRUE, FALSE);
+}
+
+/*
+ * Tell netbeans that we're exiting. This should be called right
+ * before calling exit.
+ */
+ void
+netbeans_send_disconnect(void)
+{
+ char buf[128];
+
+ if (NETBEANS_OPEN)
+ {
+ sprintf(buf, "0:disconnect=%d\n", r_cmdno);
+ nbdebug(("EVT: %s", buf));
+ nb_send(buf, "netbeans_disconnect");
+ }
+}
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+ int
+set_ref_in_nb_channel(int copyID)
+{
+ int abort = FALSE;
+ typval_T tv;
+
+ if (nb_channel != NULL)
+ {
+ tv.v_type = VAR_CHANNEL;
+ tv.vval.v_channel = nb_channel;
+ abort = set_ref_in_item(&tv, copyID, NULL, NULL);
+ }
+ return abort;
+}
+#endif
+
+#if defined(FEAT_GUI_X11) || defined(FEAT_GUI_W32) || defined(PROTO)
+/*
+ * Tell netbeans that the window was moved or resized.
+ */
+ void
+netbeans_frame_moved(int new_x, int new_y)
+{
+ char buf[128];
+
+ if (!NETBEANS_OPEN)
+ return;
+
+ sprintf(buf, "0:geometry=%d %d %d %d %d\n",
+ r_cmdno, (int)Columns, (int)Rows, new_x, new_y);
+ /*nbdebug(("EVT: %s", buf)); happens too many times during a move */
+ nb_send(buf, "netbeans_frame_moved");
+}
+#endif
+
+/*
+ * Tell netbeans the user opened or activated a file.
+ */
+ void
+netbeans_file_activated(buf_T *bufp)
+{
+ int bufno = nb_getbufno(bufp);
+ nbbuf_T *bp = nb_get_buf(bufno);
+ char buffer[2*MAXPATHL];
+ char_u *q;
+
+ if (!NETBEANS_OPEN || !bufp->b_netbeans_file || dosetvisible)
+ return;
+
+ q = nb_quote(bufp->b_ffname);
+ if (q == NULL || bp == NULL)
+ return;
+
+ vim_snprintf(buffer, sizeof(buffer), "%d:fileOpened=%d \"%s\" %s %s\n",
+ bufno,
+ bufno,
+ (char *)q,
+ "T", /* open in NetBeans */
+ "F"); /* modified */
+
+ vim_free(q);
+ nbdebug(("EVT: %s", buffer));
+
+ nb_send(buffer, "netbeans_file_opened");
+}
+
+/*
+ * Tell netbeans the user opened a file.
+ */
+ void
+netbeans_file_opened(buf_T *bufp)
+{
+ int bufno = nb_getbufno(bufp);
+ char buffer[2*MAXPATHL];
+ char_u *q;
+ nbbuf_T *bp = nb_get_buf(nb_getbufno(bufp));
+ int bnum;
+
+ if (!NETBEANS_OPEN)
+ return;
+
+ q = nb_quote(bufp->b_ffname);
+ if (q == NULL)
+ return;
+ if (bp != NULL)
+ bnum = bufno;
+ else
+ bnum = 0;
+
+ vim_snprintf(buffer, sizeof(buffer), "%d:fileOpened=%d \"%s\" %s %s\n",
+ bnum,
+ 0,
+ (char *)q,
+ "T", /* open in NetBeans */
+ "F"); /* modified */
+
+ vim_free(q);
+ nbdebug(("EVT: %s", buffer));
+
+ nb_send(buffer, "netbeans_file_opened");
+ if (p_acd && vim_chdirfile(bufp->b_ffname, "auto") == OK)
+ shorten_fnames(TRUE);
+}
+
+/*
+ * Tell netbeans that a file was deleted or wiped out.
+ */
+ void
+netbeans_file_killed(buf_T *bufp)
+{
+ int bufno = nb_getbufno(bufp);
+ nbbuf_T *nbbuf = nb_get_buf(bufno);
+ char buffer[2*MAXPATHL];
+
+ if (!NETBEANS_OPEN || bufno == -1)
+ return;
+
+ nbdebug(("netbeans_file_killed:\n"));
+ nbdebug((" Killing bufno: %d", bufno));
+
+ sprintf(buffer, "%d:killed=%d\n", bufno, r_cmdno);
+
+ nbdebug(("EVT: %s", buffer));
+
+ nb_send(buffer, "netbeans_file_killed");
+
+ if (nbbuf != NULL)
+ nbbuf->bufp = NULL;
+}
+
+/*
+ * Get a pointer to the Netbeans buffer for Vim buffer "bufp".
+ * Return NULL if there is no such buffer or changes are not to be reported.
+ * Otherwise store the buffer number in "*bufnop".
+ */
+ static nbbuf_T *
+nb_bufp2nbbuf_fire(buf_T *bufp, int *bufnop)
+{
+ int bufno;
+ nbbuf_T *nbbuf;
+
+ if (!NETBEANS_OPEN || !netbeansFireChanges)
+ return NULL; /* changes are not reported at all */
+
+ bufno = nb_getbufno(bufp);
+ if (bufno <= 0)
+ return NULL; /* file is not known to NetBeans */
+
+ nbbuf = nb_get_buf(bufno);
+ if (nbbuf != NULL && !nbbuf->fireChanges)
+ return NULL; /* changes in this buffer are not reported */
+
+ *bufnop = bufno;
+ return nbbuf;
+}
+
+/*
+ * Tell netbeans the user inserted some text.
+ */
+ void
+netbeans_inserted(
+ buf_T *bufp,
+ linenr_T linenr,
+ colnr_T col,
+ char_u *txt,
+ int newlen)
+{
+ char_u *buf;
+ int bufno;
+ nbbuf_T *nbbuf;
+ pos_T pos;
+ long off;
+ char_u *p;
+ char_u *newtxt;
+
+ if (!NETBEANS_OPEN)
+ return;
+
+ nbbuf = nb_bufp2nbbuf_fire(bufp, &bufno);
+ if (nbbuf == NULL)
+ return;
+
+ /* Don't mark as modified for initial read */
+ if (nbbuf->insertDone)
+ nbbuf->modified = 1;
+
+ pos.lnum = linenr;
+ pos.col = col;
+ off = pos2off(bufp, &pos);
+
+ /* send the "insert" EVT */
+ newtxt = alloc(newlen + 1);
+ vim_strncpy(newtxt, txt, newlen);
+ p = nb_quote(newtxt);
+ if (p != NULL)
+ {
+ buf = alloc(128 + 2*newlen);
+ sprintf((char *)buf, "%d:insert=%d %ld \"%s\"\n",
+ bufno, r_cmdno, off, p);
+ nbdebug(("EVT: %s", buf));
+ nb_send((char *)buf, "netbeans_inserted");
+ vim_free(p);
+ vim_free(buf);
+ }
+ vim_free(newtxt);
+}
+
+/*
+ * Tell netbeans some bytes have been removed.
+ */
+ void
+netbeans_removed(
+ buf_T *bufp,
+ linenr_T linenr,
+ colnr_T col,
+ long len)
+{
+ char_u buf[128];
+ int bufno;
+ nbbuf_T *nbbuf;
+ pos_T pos;
+ long off;
+
+ if (!NETBEANS_OPEN)
+ return;
+
+ nbbuf = nb_bufp2nbbuf_fire(bufp, &bufno);
+ if (nbbuf == NULL)
+ return;
+
+ if (len < 0)
+ {
+ nbdebug(("Negative len %ld in netbeans_removed()!\n", len));
+ return;
+ }
+
+ nbbuf->modified = 1;
+
+ pos.lnum = linenr;
+ pos.col = col;
+
+ off = pos2off(bufp, &pos);
+
+ sprintf((char *)buf, "%d:remove=%d %ld %ld\n", bufno, r_cmdno, off, len);
+ nbdebug(("EVT: %s", buf));
+ nb_send((char *)buf, "netbeans_removed");
+}
+
+/*
+ * Send netbeans an unmodified command.
+ */
+ void
+netbeans_unmodified(buf_T *bufp UNUSED)
+{
+ /* This is a no-op, because NetBeans considers a buffer modified
+ * even when all changes have been undone. */
+}
+
+/*
+ * Send a button release event back to netbeans. It's up to netbeans
+ * to decide what to do (if anything) with this event.
+ */
+ void
+netbeans_button_release(int button)
+{
+ char buf[128];
+ int bufno;
+
+ if (!NETBEANS_OPEN)
+ return;
+
+ bufno = nb_getbufno(curbuf);
+
+ if (bufno >= 0 && curwin != NULL && curwin->w_buffer == curbuf)
+ {
+ int col = mouse_col - curwin->w_wincol
+ - ((curwin->w_p_nu || curwin->w_p_rnu) ? 9 : 1);
+ long off = pos2off(curbuf, &curwin->w_cursor);
+
+ /* sync the cursor position */
+ sprintf(buf, "%d:newDotAndMark=%d %ld %ld\n", bufno, r_cmdno, off, off);
+ nbdebug(("EVT: %s", buf));
+ nb_send(buf, "netbeans_button_release[newDotAndMark]");
+
+ sprintf(buf, "%d:buttonRelease=%d %d %ld %d\n", bufno, r_cmdno,
+ button, (long)curwin->w_cursor.lnum, col);
+ nbdebug(("EVT: %s", buf));
+ nb_send(buf, "netbeans_button_release");
+ }
+}
+
+
+/*
+ * Send a keypress event back to netbeans. This usually simulates some
+ * kind of function key press. This function operates on a key code.
+ * Return TRUE when the key was sent, FALSE when the command has been
+ * postponed.
+ */
+ int
+netbeans_keycommand(int key)
+{
+ char keyName[60];
+
+ netbeans_keyname(key, keyName);
+ return netbeans_keystring((char_u *)keyName);
+}
+
+
+/*
+ * Send a keypress event back to netbeans. This usually simulates some
+ * kind of function key press. This function operates on a key string.
+ * Return TRUE when the key was sent, FALSE when the command has been
+ * postponed.
+ */
+ static int
+netbeans_keystring(char_u *keyName)
+{
+ char buf[2*MAXPATHL];
+ int bufno = nb_getbufno(curbuf);
+ long off;
+ char_u *q;
+
+ if (!NETBEANS_OPEN)
+ return TRUE;
+
+ if (bufno == -1)
+ {
+ nbdebug(("got keycommand for non-NetBeans buffer, opening...\n"));
+ q = curbuf->b_ffname == NULL ? (char_u *)""
+ : nb_quote(curbuf->b_ffname);
+ if (q == NULL)
+ return TRUE;
+ vim_snprintf(buf, sizeof(buf), "0:fileOpened=%d \"%s\" %s %s\n", 0,
+ q,
+ "T", /* open in NetBeans */
+ "F"); /* modified */
+ if (curbuf->b_ffname != NULL)
+ vim_free(q);
+ nbdebug(("EVT: %s", buf));
+ nb_send(buf, "netbeans_keycommand");
+
+ postpone_keycommand(keyName);
+ return FALSE;
+ }
+
+ /* sync the cursor position */
+ off = pos2off(curbuf, &curwin->w_cursor);
+ sprintf(buf, "%d:newDotAndMark=%d %ld %ld\n", bufno, r_cmdno, off, off);
+ nbdebug(("EVT: %s", buf));
+ nb_send(buf, "netbeans_keycommand");
+
+ /* To work on Win32 you must apply patch to ExtEditor module
+ * from ExtEdCaret.java.diff - make EVT_newDotAndMark handler
+ * more synchronous
+ */
+
+ /* now send keyCommand event */
+ vim_snprintf(buf, sizeof(buf), "%d:keyCommand=%d \"%s\"\n",
+ bufno, r_cmdno, keyName);
+ nbdebug(("EVT: %s", buf));
+ nb_send(buf, "netbeans_keycommand");
+
+ /* New: do both at once and include the lnum/col. */
+ vim_snprintf(buf, sizeof(buf), "%d:keyAtPos=%d \"%s\" %ld %ld/%ld\n",
+ bufno, r_cmdno, keyName,
+ off, (long)curwin->w_cursor.lnum, (long)curwin->w_cursor.col);
+ nbdebug(("EVT: %s", buf));
+ nb_send(buf, "netbeans_keycommand");
+ return TRUE;
+}
+
+
+/*
+ * Send a save event to netbeans.
+ */
+ void
+netbeans_save_buffer(buf_T *bufp)
+{
+ char_u buf[64];
+ int bufno;
+ nbbuf_T *nbbuf;
+
+ if (!NETBEANS_OPEN)
+ return;
+
+ nbbuf = nb_bufp2nbbuf_fire(bufp, &bufno);
+ if (nbbuf == NULL)
+ return;
+
+ nbbuf->modified = 0;
+
+ sprintf((char *)buf, "%d:save=%d\n", bufno, r_cmdno);
+ nbdebug(("EVT: %s", buf));
+ nb_send((char *)buf, "netbeans_save_buffer");
+}
+
+
+/*
+ * Send remove command to netbeans (this command has been turned off).
+ */
+ void
+netbeans_deleted_all_lines(buf_T *bufp)
+{
+ char_u buf[64];
+ int bufno;
+ nbbuf_T *nbbuf;
+
+ if (!NETBEANS_OPEN)
+ return;
+
+ nbbuf = nb_bufp2nbbuf_fire(bufp, &bufno);
+ if (nbbuf == NULL)
+ return;
+
+ /* Don't mark as modified for initial read */
+ if (nbbuf->insertDone)
+ nbbuf->modified = 1;
+
+ sprintf((char *)buf, "%d:remove=%d 0 -1\n", bufno, r_cmdno);
+ nbdebug(("EVT(suppressed): %s", buf));
+/* nb_send(buf, "netbeans_deleted_all_lines"); */
+}
+
+
+/*
+ * See if the lines are guarded. The top and bot parameters are from
+ * u_savecommon(), these are the line above the change and the line below the
+ * change.
+ */
+ int
+netbeans_is_guarded(linenr_T top, linenr_T bot)
+{
+ signlist_T *p;
+ int lnum;
+
+ if (!NETBEANS_OPEN)
+ return FALSE;
+
+ for (p = curbuf->b_signlist; p != NULL; p = p->next)
+ if (p->id >= GUARDEDOFFSET)
+ for (lnum = top + 1; lnum < bot; lnum++)
+ if (lnum == p->lnum)
+ return TRUE;
+
+ return FALSE;
+}
+
+#if defined(FEAT_GUI_X11) || defined(PROTO)
+/*
+ * We have multiple signs to draw at the same location. Draw the
+ * multi-sign indicator instead. This is the Motif version.
+ */
+ void
+netbeans_draw_multisign_indicator(int row)
+{
+ int i;
+ int y;
+ int x;
+
+ if (!NETBEANS_OPEN)
+ return;
+
+ x = 0;
+ y = row * gui.char_height + 2;
+
+ for (i = 0; i < gui.char_height - 3; i++)
+ XDrawPoint(gui.dpy, gui.wid, gui.text_gc, x+2, y++);
+
+ XDrawPoint(gui.dpy, gui.wid, gui.text_gc, x+0, y);
+ XDrawPoint(gui.dpy, gui.wid, gui.text_gc, x+2, y);
+ XDrawPoint(gui.dpy, gui.wid, gui.text_gc, x+4, y++);
+ XDrawPoint(gui.dpy, gui.wid, gui.text_gc, x+1, y);
+ XDrawPoint(gui.dpy, gui.wid, gui.text_gc, x+2, y);
+ XDrawPoint(gui.dpy, gui.wid, gui.text_gc, x+3, y++);
+ XDrawPoint(gui.dpy, gui.wid, gui.text_gc, x+2, y);
+}
+#endif /* FEAT_GUI_X11 */
+
+#if defined(FEAT_GUI_GTK) && !defined(PROTO)
+/*
+ * We have multiple signs to draw at the same location. Draw the
+ * multi-sign indicator instead. This is the GTK/Gnome version.
+ */
+ void
+netbeans_draw_multisign_indicator(int row)
+{
+ int i;
+ int y;
+ int x;
+#if GTK_CHECK_VERSION(3,0,0)
+ cairo_t *cr = NULL;
+#else
+ GdkDrawable *drawable = gui.drawarea->window;
+#endif
+
+ if (!NETBEANS_OPEN)
+ return;
+
+#if GTK_CHECK_VERSION(3,0,0)
+ cr = cairo_create(gui.surface);
+ cairo_set_source_rgba(cr,
+ gui.fgcolor->red, gui.fgcolor->green, gui.fgcolor->blue,
+ gui.fgcolor->alpha);
+#endif
+
+ x = 0;
+ y = row * gui.char_height + 2;
+
+ for (i = 0; i < gui.char_height - 3; i++)
+#if GTK_CHECK_VERSION(3,0,0)
+ cairo_rectangle(cr, x+2, y++, 1, 1);
+#else
+ gdk_draw_point(drawable, gui.text_gc, x+2, y++);
+#endif
+
+#if GTK_CHECK_VERSION(3,0,0)
+ cairo_rectangle(cr, x+0, y, 1, 1);
+ cairo_rectangle(cr, x+2, y, 1, 1);
+ cairo_rectangle(cr, x+4, y++, 1, 1);
+ cairo_rectangle(cr, x+1, y, 1, 1);
+ cairo_rectangle(cr, x+2, y, 1, 1);
+ cairo_rectangle(cr, x+3, y++, 1, 1);
+ cairo_rectangle(cr, x+2, y, 1, 1);
+#else
+ gdk_draw_point(drawable, gui.text_gc, x+0, y);
+ gdk_draw_point(drawable, gui.text_gc, x+2, y);
+ gdk_draw_point(drawable, gui.text_gc, x+4, y++);
+ gdk_draw_point(drawable, gui.text_gc, x+1, y);
+ gdk_draw_point(drawable, gui.text_gc, x+2, y);
+ gdk_draw_point(drawable, gui.text_gc, x+3, y++);
+ gdk_draw_point(drawable, gui.text_gc, x+2, y);
+#endif
+
+#if GTK_CHECK_VERSION(3,0,0)
+ cairo_destroy(cr);
+#endif
+}
+#endif /* FEAT_GUI_GTK */
+
+/*
+ * If the mouse is clicked in the gutter of a line with multiple
+ * annotations, cycle through the set of signs.
+ */
+ void
+netbeans_gutter_click(linenr_T lnum)
+{
+ signlist_T *p;
+
+ if (!NETBEANS_OPEN)
+ return;
+
+ for (p = curbuf->b_signlist; p != NULL; p = p->next)
+ {
+ if (p->lnum == lnum && p->next && p->next->lnum == lnum)
+ {
+ signlist_T *tail;
+
+ /* remove "p" from list, reinsert it at the tail of the sublist */
+ if (p->prev)
+ p->prev->next = p->next;
+ else
+ curbuf->b_signlist = p->next;
+ p->next->prev = p->prev;
+ /* now find end of sublist and insert p */
+ for (tail = p->next;
+ tail->next && tail->next->lnum == lnum
+ && tail->next->id < GUARDEDOFFSET;
+ tail = tail->next)
+ ;
+ /* tail now points to last entry with same lnum (except
+ * that "guarded" annotations are always last) */
+ p->next = tail->next;
+ if (tail->next)
+ tail->next->prev = p;
+ p->prev = tail;
+ tail->next = p;
+ update_debug_sign(curbuf, lnum);
+ break;
+ }
+ }
+}
+
+/*
+ * Add a sign of the requested type at the requested location.
+ *
+ * Reverse engineering:
+ * Apparently an annotation is defined the first time it is used in a buffer.
+ * When the same annotation is used in two buffers, the second time we do not
+ * need to define a new sign name but reuse the existing one. But since the
+ * ID number used in the second buffer starts counting at one again, a mapping
+ * is made from the ID specifically for the buffer to the global sign name
+ * (which is a number).
+ *
+ * globalsignmap[] stores the signs that have been defined globally.
+ * buf->signmapused[] maps buffer-local annotation IDs to an index in
+ * globalsignmap[].
+ */
+ static void
+addsigntype(
+ nbbuf_T *buf,
+ int typeNum,
+ char_u *typeName,
+ char_u *tooltip UNUSED,
+ char_u *glyphFile,
+ char_u *fg,
+ char_u *bg)
+{
+ int i, j;
+ int use_fg = (*fg && STRCMP(fg, "none") != 0);
+ int use_bg = (*bg && STRCMP(bg, "none") != 0);
+
+ for (i = 0; i < globalsignmapused; i++)
+ if (STRCMP(typeName, globalsignmap[i]) == 0)
+ break;
+
+ if (i == globalsignmapused) /* not found; add it to global map */
+ {
+ nbdebug(("DEFINEANNOTYPE(%d,%s,%s,%s,%s,%s)\n",
+ typeNum, typeName, tooltip, glyphFile, fg, bg));
+ if (use_fg || use_bg)
+ {
+ char fgbuf[2 * (8 + MAX_COLOR_LENGTH) + 1];
+ char bgbuf[2 * (8 + MAX_COLOR_LENGTH) + 1];
+ char *ptr;
+ int value;
+
+ value = strtol((char *)fg, &ptr, 10);
+ if (ptr != (char *)fg)
+ sprintf(fgbuf, "guifg=#%06x", value & 0xFFFFFF);
+ else
+ sprintf(fgbuf, "guifg=%s ctermfg=%s", fg, fg);
+
+ value = strtol((char *)bg, &ptr, 10);
+ if (ptr != (char *)bg)
+ sprintf(bgbuf, "guibg=#%06x", value & 0xFFFFFF);
+ else
+ sprintf(bgbuf, "guibg=%s ctermbg=%s", bg, bg);
+
+ coloncmd(":highlight NB_%s %s %s", typeName, (use_fg) ? fgbuf : "",
+ (use_bg) ? bgbuf : "");
+ if (*glyphFile == NUL)
+ /* no glyph, line highlighting only */
+ coloncmd(":sign define %d linehl=NB_%s", i + 1, typeName);
+ else if (vim_strsize(glyphFile) <= 2)
+ /* one- or two-character glyph name, use as text glyph with
+ * texthl */
+ coloncmd(":sign define %d text=%s texthl=NB_%s", i + 1,
+ glyphFile, typeName);
+ else
+ /* glyph, line highlighting */
+ coloncmd(":sign define %d icon=%s linehl=NB_%s", i + 1,
+ glyphFile, typeName);
+ }
+ else
+ /* glyph, no line highlighting */
+ coloncmd(":sign define %d icon=%s", i + 1, glyphFile);
+
+ if (STRCMP(typeName,"CurrentPC") == 0)
+ curPCtype = typeNum;
+
+ if (globalsignmapused == globalsignmaplen)
+ {
+ if (globalsignmaplen == 0) /* first allocation */
+ {
+ globalsignmaplen = 20;
+ globalsignmap = (char **)alloc_clear(globalsignmaplen*sizeof(char *));
+ }
+ else /* grow it */
+ {
+ int incr;
+ int oldlen = globalsignmaplen;
+ char **t_globalsignmap = globalsignmap;
+
+ globalsignmaplen *= 2;
+ incr = globalsignmaplen - oldlen;
+ globalsignmap = (char **)vim_realloc(globalsignmap,
+ globalsignmaplen * sizeof(char *));
+ if (globalsignmap == NULL)
+ {
+ vim_free(t_globalsignmap);
+ globalsignmaplen = 0;
+ return;
+ }
+ vim_memset(globalsignmap + oldlen, 0, incr * sizeof(char *));
+ }
+ }
+
+ globalsignmap[i] = (char *)typeName;
+ globalsignmapused = i + 1;
+ }
+
+ /* check local map; should *not* be found! */
+ for (j = 0; j < buf->signmapused; j++)
+ if (buf->signmap[j] == i + 1)
+ return;
+
+ /* add to local map */
+ if (buf->signmapused == buf->signmaplen)
+ {
+ if (buf->signmaplen == 0) /* first allocation */
+ {
+ buf->signmaplen = 5;
+ buf->signmap = (int *)alloc_clear(buf->signmaplen * sizeof(int));
+ }
+ else /* grow it */
+ {
+ int incr;
+ int oldlen = buf->signmaplen;
+ int *t_signmap = buf->signmap;
+
+ buf->signmaplen *= 2;
+ incr = buf->signmaplen - oldlen;
+ buf->signmap = (int *)vim_realloc(buf->signmap,
+ buf->signmaplen * sizeof(int));
+ if (buf->signmap == NULL)
+ {
+ vim_free(t_signmap);
+ buf->signmaplen = 0;
+ return;
+ }
+ vim_memset(buf->signmap + oldlen, 0, incr * sizeof(int));
+ }
+ }
+
+ buf->signmap[buf->signmapused++] = i + 1;
+
+}
+
+
+/*
+ * See if we have the requested sign type in the buffer.
+ */
+ static int
+mapsigntype(nbbuf_T *buf, int localsigntype)
+{
+ if (--localsigntype >= 0 && localsigntype < buf->signmapused)
+ return buf->signmap[localsigntype];
+
+ return 0;
+}
+
+
+/*
+ * Compute length of buffer, don't print anything.
+ */
+ static long
+get_buf_size(buf_T *bufp)
+{
+ linenr_T lnum;
+ long char_count = 0;
+ int eol_size;
+ long last_check = 100000L;
+
+ if (bufp->b_ml.ml_flags & ML_EMPTY)
+ return 0;
+ else
+ {
+ if (get_fileformat(bufp) == EOL_DOS)
+ eol_size = 2;
+ else
+ eol_size = 1;
+ for (lnum = 1; lnum <= bufp->b_ml.ml_line_count; ++lnum)
+ {
+ char_count += (long)STRLEN(ml_get_buf(bufp, lnum, FALSE))
+ + eol_size;
+ /* Check for a CTRL-C every 100000 characters */
+ if (char_count > last_check)
+ {
+ ui_breakcheck();
+ if (got_int)
+ return char_count;
+ last_check = char_count + 100000L;
+ }
+ }
+ /* Correction for when last line doesn't have an EOL. */
+ if (!bufp->b_p_eol && (bufp->b_p_bin || !bufp->b_p_fixeol))
+ char_count -= eol_size;
+ }
+
+ return char_count;
+}
+
+/*
+ * Convert character offset to lnum,col
+ */
+ static pos_T *
+off2pos(buf_T *buf, long offset)
+{
+ linenr_T lnum;
+ static pos_T pos;
+
+ pos.lnum = 0;
+ pos.col = 0;
+ pos.coladd = 0;
+
+ if (!(buf->b_ml.ml_flags & ML_EMPTY))
+ {
+ if ((lnum = ml_find_line_or_offset(buf, (linenr_T)0, &offset)) < 0)
+ return NULL;
+ pos.lnum = lnum;
+ pos.col = offset;
+ }
+
+ return &pos;
+}
+
+/*
+ * Convert an argument in the form "1234" to an offset and compute the
+ * lnum/col from it. Convert an argument in the form "123/12" directly to a
+ * lnum/col.
+ * "argp" is advanced to after the argument.
+ * Return a pointer to the position, NULL if something is wrong.
+ */
+ static pos_T *
+get_off_or_lnum(buf_T *buf, char_u **argp)
+{
+ static pos_T mypos;
+ long off;
+
+ off = strtol((char *)*argp, (char **)argp, 10);
+ if (**argp == '/')
+ {
+ mypos.lnum = (linenr_T)off;
+ ++*argp;
+ mypos.col = strtol((char *)*argp, (char **)argp, 10);
+ mypos.coladd = 0;
+ return &mypos;
+ }
+ return off2pos(buf, off);
+}
+
+
+/*
+ * Convert (lnum,col) to byte offset in the file.
+ */
+ static long
+pos2off(buf_T *buf, pos_T *pos)
+{
+ long offset = 0;
+
+ if (!(buf->b_ml.ml_flags & ML_EMPTY))
+ {
+ if ((offset = ml_find_line_or_offset(buf, pos->lnum, 0)) < 0)
+ return 0;
+ offset += pos->col;
+ }
+
+ return offset;
+}
+
+
+/*
+ * This message is printed after NetBeans opens a new file. It's
+ * similar to the message readfile() uses, but since NetBeans
+ * doesn't normally call readfile, we do our own.
+ */
+ static void
+print_read_msg(nbbuf_T *buf)
+{
+ int lnum = buf->bufp->b_ml.ml_line_count;
+ off_T nchars = buf->bufp->b_orig_size;
+ char_u c;
+
+ msg_add_fname(buf->bufp, buf->bufp->b_ffname);
+ c = FALSE;
+
+ if (buf->bufp->b_p_ro)
+ {
+ STRCAT(IObuff, shortmess(SHM_RO) ? _("[RO]") : _("[readonly]"));
+ c = TRUE;
+ }
+ if (!buf->bufp->b_start_eol)
+ {
+ STRCAT(IObuff, shortmess(SHM_LAST) ? _("[noeol]")
+ : _("[Incomplete last line]"));
+ c = TRUE;
+ }
+ msg_add_lines(c, (long)lnum, nchars);
+
+ /* Now display it */
+ VIM_CLEAR(keep_msg);
+ msg_scrolled_ign = TRUE;
+ msg_trunc_attr((char *)IObuff, FALSE, 0);
+ msg_scrolled_ign = FALSE;
+}
+
+
+/*
+ * Print a message after NetBeans writes the file. This message should be
+ * identical to the standard message a non-netbeans user would see when
+ * writing a file.
+ */
+ static void
+print_save_msg(nbbuf_T *buf, off_T nchars)
+{
+ char_u c;
+ char_u *p;
+
+ if (nchars >= 0)
+ {
+ /* put fname in IObuff with quotes */
+ msg_add_fname(buf->bufp, buf->bufp->b_ffname);
+ c = FALSE;
+
+ msg_add_lines(c, buf->bufp->b_ml.ml_line_count,
+ buf->bufp->b_orig_size);
+
+ VIM_CLEAR(keep_msg);
+ msg_scrolled_ign = TRUE;
+ p = (char_u *)msg_trunc_attr((char *)IObuff, FALSE, 0);
+ if ((msg_scrolled && !need_wait_return) || !buf->initDone)
+ {
+ /* Need to repeat the message after redrawing when:
+ * - When reading from stdin (the screen will be cleared next).
+ * - When restart_edit is set (otherwise there will be a delay
+ * before redrawing).
+ * - When the screen was scrolled but there is no wait-return
+ * prompt. */
+ set_keep_msg(p, 0);
+ }
+ msg_scrolled_ign = FALSE;
+ /* add_to_input_buf((char_u *)"\f", 1); */
+ }
+ else
+ {
+ char msgbuf[IOSIZE];
+
+ vim_snprintf(msgbuf, IOSIZE,
+ _("E505: %s is read-only (add ! to override)"), IObuff);
+ nbdebug((" %s\n", msgbuf));
+ emsg(msgbuf);
+ }
+}
+
+#endif /* defined(FEAT_NETBEANS_INTG) */
diff --git a/src/normal.c b/src/normal.c
new file mode 100644
index 0000000..41af966
--- /dev/null
+++ b/src/normal.c
@@ -0,0 +1,9560 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+/*
+ * normal.c: Contains the main routine for processing characters in command
+ * mode. Communicates closely with the code in ops.c to handle
+ * the operators.
+ */
+
+#include "vim.h"
+
+/*
+ * The Visual area is remembered for reselection.
+ */
+static int resel_VIsual_mode = NUL; /* 'v', 'V', or Ctrl-V */
+static linenr_T resel_VIsual_line_count; /* number of lines */
+static colnr_T resel_VIsual_vcol; /* nr of cols or end col */
+static int VIsual_mode_orig = NUL; /* saved Visual mode */
+
+static int restart_VIsual_select = 0;
+
+#ifdef FEAT_EVAL
+static void set_vcount_ca(cmdarg_T *cap, int *set_prevcount);
+#endif
+static int
+#ifdef __BORLANDC__
+ _RTLENTRYF
+#endif
+ nv_compare(const void *s1, const void *s2);
+static void op_colon(oparg_T *oap);
+static void op_function(oparg_T *oap);
+#if defined(FEAT_MOUSE)
+static void find_start_of_word(pos_T *);
+static void find_end_of_word(pos_T *);
+static int get_mouse_class(char_u *p);
+#endif
+static void prep_redo(int regname, long, int, int, int, int, int);
+static void clearop(oparg_T *oap);
+static void clearopbeep(oparg_T *oap);
+static void unshift_special(cmdarg_T *cap);
+static void may_clear_cmdline(void);
+#ifdef FEAT_CMDL_INFO
+static void del_from_showcmd(int);
+#endif
+
+/*
+ * nv_*(): functions called to handle Normal and Visual mode commands.
+ * n_*(): functions called to handle Normal mode commands.
+ * v_*(): functions called to handle Visual mode commands.
+ */
+static void nv_ignore(cmdarg_T *cap);
+static void nv_nop(cmdarg_T *cap);
+static void nv_error(cmdarg_T *cap);
+static void nv_help(cmdarg_T *cap);
+static void nv_addsub(cmdarg_T *cap);
+static void nv_page(cmdarg_T *cap);
+#ifdef FEAT_MOUSE
+static void nv_mousescroll(cmdarg_T *cap);
+static void nv_mouse(cmdarg_T *cap);
+#endif
+static void nv_scroll_line(cmdarg_T *cap);
+static void nv_zet(cmdarg_T *cap);
+#ifdef FEAT_GUI
+static void nv_ver_scrollbar(cmdarg_T *cap);
+static void nv_hor_scrollbar(cmdarg_T *cap);
+#endif
+#ifdef FEAT_GUI_TABLINE
+static void nv_tabline(cmdarg_T *cap);
+static void nv_tabmenu(cmdarg_T *cap);
+#endif
+static void nv_exmode(cmdarg_T *cap);
+static void nv_colon(cmdarg_T *cap);
+static void nv_ctrlg(cmdarg_T *cap);
+static void nv_ctrlh(cmdarg_T *cap);
+static void nv_clear(cmdarg_T *cap);
+static void nv_ctrlo(cmdarg_T *cap);
+static void nv_hat(cmdarg_T *cap);
+static void nv_Zet(cmdarg_T *cap);
+static void nv_ident(cmdarg_T *cap);
+static void nv_tagpop(cmdarg_T *cap);
+static void nv_scroll(cmdarg_T *cap);
+static void nv_right(cmdarg_T *cap);
+static void nv_left(cmdarg_T *cap);
+static void nv_up(cmdarg_T *cap);
+static void nv_down(cmdarg_T *cap);
+static void nv_end(cmdarg_T *cap);
+static void nv_dollar(cmdarg_T *cap);
+static void nv_search(cmdarg_T *cap);
+static void nv_next(cmdarg_T *cap);
+static int normal_search(cmdarg_T *cap, int dir, char_u *pat, int opt);
+static void nv_csearch(cmdarg_T *cap);
+static void nv_brackets(cmdarg_T *cap);
+static void nv_percent(cmdarg_T *cap);
+static void nv_brace(cmdarg_T *cap);
+static void nv_mark(cmdarg_T *cap);
+static void nv_findpar(cmdarg_T *cap);
+static void nv_undo(cmdarg_T *cap);
+static void nv_kundo(cmdarg_T *cap);
+static void nv_Replace(cmdarg_T *cap);
+static void nv_replace(cmdarg_T *cap);
+static void nv_cursormark(cmdarg_T *cap, int flag, pos_T *pos);
+static void v_visop(cmdarg_T *cap);
+static void nv_subst(cmdarg_T *cap);
+static void nv_abbrev(cmdarg_T *cap);
+static void nv_optrans(cmdarg_T *cap);
+static void nv_gomark(cmdarg_T *cap);
+static void nv_pcmark(cmdarg_T *cap);
+static void nv_regname(cmdarg_T *cap);
+static void nv_visual(cmdarg_T *cap);
+static void n_start_visual_mode(int c);
+static void nv_window(cmdarg_T *cap);
+static void nv_suspend(cmdarg_T *cap);
+static void nv_g_cmd(cmdarg_T *cap);
+static void nv_dot(cmdarg_T *cap);
+static void nv_redo(cmdarg_T *cap);
+static void nv_Undo(cmdarg_T *cap);
+static void nv_tilde(cmdarg_T *cap);
+static void nv_operator(cmdarg_T *cap);
+#ifdef FEAT_EVAL
+static void set_op_var(int optype);
+#endif
+static void nv_lineop(cmdarg_T *cap);
+static void nv_home(cmdarg_T *cap);
+static void nv_pipe(cmdarg_T *cap);
+static void nv_bck_word(cmdarg_T *cap);
+static void nv_wordcmd(cmdarg_T *cap);
+static void nv_beginline(cmdarg_T *cap);
+static void adjust_cursor(oparg_T *oap);
+static void adjust_for_sel(cmdarg_T *cap);
+static int unadjust_for_sel(void);
+static void nv_select(cmdarg_T *cap);
+static void nv_goto(cmdarg_T *cap);
+static void nv_normal(cmdarg_T *cap);
+static void nv_esc(cmdarg_T *oap);
+static void nv_edit(cmdarg_T *cap);
+static void invoke_edit(cmdarg_T *cap, int repl, int cmd, int startln);
+#ifdef FEAT_TEXTOBJ
+static void nv_object(cmdarg_T *cap);
+#endif
+static void nv_record(cmdarg_T *cap);
+static void nv_at(cmdarg_T *cap);
+static void nv_halfpage(cmdarg_T *cap);
+static void nv_join(cmdarg_T *cap);
+static void nv_put(cmdarg_T *cap);
+static void nv_open(cmdarg_T *cap);
+#ifdef FEAT_NETBEANS_INTG
+static void nv_nbcmd(cmdarg_T *cap);
+#endif
+#ifdef FEAT_DND
+static void nv_drop(cmdarg_T *cap);
+#endif
+static void nv_cursorhold(cmdarg_T *cap);
+static void get_op_vcol(oparg_T *oap, colnr_T col, int initial);
+
+static char *e_noident = N_("E349: No identifier under cursor");
+
+/*
+ * Function to be called for a Normal or Visual mode command.
+ * The argument is a cmdarg_T.
+ */
+typedef void (*nv_func_T)(cmdarg_T *cap);
+
+/* Values for cmd_flags. */
+#define NV_NCH 0x01 /* may need to get a second char */
+#define NV_NCH_NOP (0x02|NV_NCH) /* get second char when no operator pending */
+#define NV_NCH_ALW (0x04|NV_NCH) /* always get a second char */
+#define NV_LANG 0x08 /* second char needs language adjustment */
+
+#define NV_SS 0x10 /* may start selection */
+#define NV_SSS 0x20 /* may start selection with shift modifier */
+#define NV_STS 0x40 /* may stop selection without shift modif. */
+#define NV_RL 0x80 /* 'rightleft' modifies command */
+#define NV_KEEPREG 0x100 /* don't clear regname */
+#define NV_NCW 0x200 /* not allowed in command-line window */
+
+/*
+ * Generally speaking, every Normal mode command should either clear any
+ * pending operator (with *clearop*()), or set the motion type variable
+ * oap->motion_type.
+ *
+ * When a cursor motion command is made, it is marked as being a character or
+ * line oriented motion. Then, if an operator is in effect, the operation
+ * becomes character or line oriented accordingly.
+ */
+
+/*
+ * This table contains one entry for every Normal or Visual mode command.
+ * The order doesn't matter, init_normal_cmds() will create a sorted index.
+ * It is faster when all keys from zero to '~' are present.
+ */
+static const struct nv_cmd
+{
+ int cmd_char; /* (first) command character */
+ nv_func_T cmd_func; /* function for this command */
+ short_u cmd_flags; /* NV_ flags */
+ short cmd_arg; /* value for ca.arg */
+} nv_cmds[] =
+{
+ {NUL, nv_error, 0, 0},
+ {Ctrl_A, nv_addsub, 0, 0},
+ {Ctrl_B, nv_page, NV_STS, BACKWARD},
+ {Ctrl_C, nv_esc, 0, TRUE},
+ {Ctrl_D, nv_halfpage, 0, 0},
+ {Ctrl_E, nv_scroll_line, 0, TRUE},
+ {Ctrl_F, nv_page, NV_STS, FORWARD},
+ {Ctrl_G, nv_ctrlg, 0, 0},
+ {Ctrl_H, nv_ctrlh, 0, 0},
+ {Ctrl_I, nv_pcmark, 0, 0},
+ {NL, nv_down, 0, FALSE},
+ {Ctrl_K, nv_error, 0, 0},
+ {Ctrl_L, nv_clear, 0, 0},
+ {Ctrl_M, nv_down, 0, TRUE},
+ {Ctrl_N, nv_down, NV_STS, FALSE},
+ {Ctrl_O, nv_ctrlo, 0, 0},
+ {Ctrl_P, nv_up, NV_STS, FALSE},
+ {Ctrl_Q, nv_visual, 0, FALSE},
+ {Ctrl_R, nv_redo, 0, 0},
+ {Ctrl_S, nv_ignore, 0, 0},
+ {Ctrl_T, nv_tagpop, NV_NCW, 0},
+ {Ctrl_U, nv_halfpage, 0, 0},
+ {Ctrl_V, nv_visual, 0, FALSE},
+ {'V', nv_visual, 0, FALSE},
+ {'v', nv_visual, 0, FALSE},
+ {Ctrl_W, nv_window, 0, 0},
+ {Ctrl_X, nv_addsub, 0, 0},
+ {Ctrl_Y, nv_scroll_line, 0, FALSE},
+ {Ctrl_Z, nv_suspend, 0, 0},
+ {ESC, nv_esc, 0, FALSE},
+ {Ctrl_BSL, nv_normal, NV_NCH_ALW, 0},
+ {Ctrl_RSB, nv_ident, NV_NCW, 0},
+ {Ctrl_HAT, nv_hat, NV_NCW, 0},
+ {Ctrl__, nv_error, 0, 0},
+ {' ', nv_right, 0, 0},
+ {'!', nv_operator, 0, 0},
+ {'"', nv_regname, NV_NCH_NOP|NV_KEEPREG, 0},
+ {'#', nv_ident, 0, 0},
+ {'$', nv_dollar, 0, 0},
+ {'%', nv_percent, 0, 0},
+ {'&', nv_optrans, 0, 0},
+ {'\'', nv_gomark, NV_NCH_ALW, TRUE},
+ {'(', nv_brace, 0, BACKWARD},
+ {')', nv_brace, 0, FORWARD},
+ {'*', nv_ident, 0, 0},
+ {'+', nv_down, 0, TRUE},
+ {',', nv_csearch, 0, TRUE},
+ {'-', nv_up, 0, TRUE},
+ {'.', nv_dot, NV_KEEPREG, 0},
+ {'/', nv_search, 0, FALSE},
+ {'0', nv_beginline, 0, 0},
+ {'1', nv_ignore, 0, 0},
+ {'2', nv_ignore, 0, 0},
+ {'3', nv_ignore, 0, 0},
+ {'4', nv_ignore, 0, 0},
+ {'5', nv_ignore, 0, 0},
+ {'6', nv_ignore, 0, 0},
+ {'7', nv_ignore, 0, 0},
+ {'8', nv_ignore, 0, 0},
+ {'9', nv_ignore, 0, 0},
+ {':', nv_colon, 0, 0},
+ {';', nv_csearch, 0, FALSE},
+ {'<', nv_operator, NV_RL, 0},
+ {'=', nv_operator, 0, 0},
+ {'>', nv_operator, NV_RL, 0},
+ {'?', nv_search, 0, FALSE},
+ {'@', nv_at, NV_NCH_NOP, FALSE},
+ {'A', nv_edit, 0, 0},
+ {'B', nv_bck_word, 0, 1},
+ {'C', nv_abbrev, NV_KEEPREG, 0},
+ {'D', nv_abbrev, NV_KEEPREG, 0},
+ {'E', nv_wordcmd, 0, TRUE},
+ {'F', nv_csearch, NV_NCH_ALW|NV_LANG, BACKWARD},
+ {'G', nv_goto, 0, TRUE},
+ {'H', nv_scroll, 0, 0},
+ {'I', nv_edit, 0, 0},
+ {'J', nv_join, 0, 0},
+ {'K', nv_ident, 0, 0},
+ {'L', nv_scroll, 0, 0},
+ {'M', nv_scroll, 0, 0},
+ {'N', nv_next, 0, SEARCH_REV},
+ {'O', nv_open, 0, 0},
+ {'P', nv_put, 0, 0},
+ {'Q', nv_exmode, NV_NCW, 0},
+ {'R', nv_Replace, 0, FALSE},
+ {'S', nv_subst, NV_KEEPREG, 0},
+ {'T', nv_csearch, NV_NCH_ALW|NV_LANG, BACKWARD},
+ {'U', nv_Undo, 0, 0},
+ {'W', nv_wordcmd, 0, TRUE},
+ {'X', nv_abbrev, NV_KEEPREG, 0},
+ {'Y', nv_abbrev, NV_KEEPREG, 0},
+ {'Z', nv_Zet, NV_NCH_NOP|NV_NCW, 0},
+ {'[', nv_brackets, NV_NCH_ALW, BACKWARD},
+ {'\\', nv_error, 0, 0},
+ {']', nv_brackets, NV_NCH_ALW, FORWARD},
+ {'^', nv_beginline, 0, BL_WHITE | BL_FIX},
+ {'_', nv_lineop, 0, 0},
+ {'`', nv_gomark, NV_NCH_ALW, FALSE},
+ {'a', nv_edit, NV_NCH, 0},
+ {'b', nv_bck_word, 0, 0},
+ {'c', nv_operator, 0, 0},
+ {'d', nv_operator, 0, 0},
+ {'e', nv_wordcmd, 0, FALSE},
+ {'f', nv_csearch, NV_NCH_ALW|NV_LANG, FORWARD},
+ {'g', nv_g_cmd, NV_NCH_ALW, FALSE},
+ {'h', nv_left, NV_RL, 0},
+ {'i', nv_edit, NV_NCH, 0},
+ {'j', nv_down, 0, FALSE},
+ {'k', nv_up, 0, FALSE},
+ {'l', nv_right, NV_RL, 0},
+ {'m', nv_mark, NV_NCH_NOP, 0},
+ {'n', nv_next, 0, 0},
+ {'o', nv_open, 0, 0},
+ {'p', nv_put, 0, 0},
+ {'q', nv_record, NV_NCH, 0},
+ {'r', nv_replace, NV_NCH_NOP|NV_LANG, 0},
+ {'s', nv_subst, NV_KEEPREG, 0},
+ {'t', nv_csearch, NV_NCH_ALW|NV_LANG, FORWARD},
+ {'u', nv_undo, 0, 0},
+ {'w', nv_wordcmd, 0, FALSE},
+ {'x', nv_abbrev, NV_KEEPREG, 0},
+ {'y', nv_operator, 0, 0},
+ {'z', nv_zet, NV_NCH_ALW, 0},
+ {'{', nv_findpar, 0, BACKWARD},
+ {'|', nv_pipe, 0, 0},
+ {'}', nv_findpar, 0, FORWARD},
+ {'~', nv_tilde, 0, 0},
+
+ /* pound sign */
+ {POUND, nv_ident, 0, 0},
+#ifdef FEAT_MOUSE
+ {K_MOUSEUP, nv_mousescroll, 0, MSCR_UP},
+ {K_MOUSEDOWN, nv_mousescroll, 0, MSCR_DOWN},
+ {K_MOUSELEFT, nv_mousescroll, 0, MSCR_LEFT},
+ {K_MOUSERIGHT, nv_mousescroll, 0, MSCR_RIGHT},
+ {K_LEFTMOUSE, nv_mouse, 0, 0},
+ {K_LEFTMOUSE_NM, nv_mouse, 0, 0},
+ {K_LEFTDRAG, nv_mouse, 0, 0},
+ {K_LEFTRELEASE, nv_mouse, 0, 0},
+ {K_LEFTRELEASE_NM, nv_mouse, 0, 0},
+ {K_MOUSEMOVE, nv_mouse, 0, 0},
+ {K_MIDDLEMOUSE, nv_mouse, 0, 0},
+ {K_MIDDLEDRAG, nv_mouse, 0, 0},
+ {K_MIDDLERELEASE, nv_mouse, 0, 0},
+ {K_RIGHTMOUSE, nv_mouse, 0, 0},
+ {K_RIGHTDRAG, nv_mouse, 0, 0},
+ {K_RIGHTRELEASE, nv_mouse, 0, 0},
+ {K_X1MOUSE, nv_mouse, 0, 0},
+ {K_X1DRAG, nv_mouse, 0, 0},
+ {K_X1RELEASE, nv_mouse, 0, 0},
+ {K_X2MOUSE, nv_mouse, 0, 0},
+ {K_X2DRAG, nv_mouse, 0, 0},
+ {K_X2RELEASE, nv_mouse, 0, 0},
+#endif
+ {K_IGNORE, nv_ignore, NV_KEEPREG, 0},
+ {K_NOP, nv_nop, 0, 0},
+ {K_INS, nv_edit, 0, 0},
+ {K_KINS, nv_edit, 0, 0},
+ {K_BS, nv_ctrlh, 0, 0},
+ {K_UP, nv_up, NV_SSS|NV_STS, FALSE},
+ {K_S_UP, nv_page, NV_SS, BACKWARD},
+ {K_DOWN, nv_down, NV_SSS|NV_STS, FALSE},
+ {K_S_DOWN, nv_page, NV_SS, FORWARD},
+ {K_LEFT, nv_left, NV_SSS|NV_STS|NV_RL, 0},
+ {K_S_LEFT, nv_bck_word, NV_SS|NV_RL, 0},
+ {K_C_LEFT, nv_bck_word, NV_SSS|NV_RL|NV_STS, 1},
+ {K_RIGHT, nv_right, NV_SSS|NV_STS|NV_RL, 0},
+ {K_S_RIGHT, nv_wordcmd, NV_SS|NV_RL, FALSE},
+ {K_C_RIGHT, nv_wordcmd, NV_SSS|NV_RL|NV_STS, TRUE},
+ {K_PAGEUP, nv_page, NV_SSS|NV_STS, BACKWARD},
+ {K_KPAGEUP, nv_page, NV_SSS|NV_STS, BACKWARD},
+ {K_PAGEDOWN, nv_page, NV_SSS|NV_STS, FORWARD},
+ {K_KPAGEDOWN, nv_page, NV_SSS|NV_STS, FORWARD},
+ {K_END, nv_end, NV_SSS|NV_STS, FALSE},
+ {K_KEND, nv_end, NV_SSS|NV_STS, FALSE},
+ {K_S_END, nv_end, NV_SS, FALSE},
+ {K_C_END, nv_end, NV_SSS|NV_STS, TRUE},
+ {K_HOME, nv_home, NV_SSS|NV_STS, 0},
+ {K_KHOME, nv_home, NV_SSS|NV_STS, 0},
+ {K_S_HOME, nv_home, NV_SS, 0},
+ {K_C_HOME, nv_goto, NV_SSS|NV_STS, FALSE},
+ {K_DEL, nv_abbrev, 0, 0},
+ {K_KDEL, nv_abbrev, 0, 0},
+ {K_UNDO, nv_kundo, 0, 0},
+ {K_HELP, nv_help, NV_NCW, 0},
+ {K_F1, nv_help, NV_NCW, 0},
+ {K_XF1, nv_help, NV_NCW, 0},
+ {K_SELECT, nv_select, 0, 0},
+#ifdef FEAT_GUI
+ {K_VER_SCROLLBAR, nv_ver_scrollbar, 0, 0},
+ {K_HOR_SCROLLBAR, nv_hor_scrollbar, 0, 0},
+#endif
+#ifdef FEAT_GUI_TABLINE
+ {K_TABLINE, nv_tabline, 0, 0},
+ {K_TABMENU, nv_tabmenu, 0, 0},
+#endif
+#ifdef FEAT_FKMAP
+ {K_F8, farsi_f8, 0, 0},
+ {K_F9, farsi_f9, 0, 0},
+#endif
+#ifdef FEAT_NETBEANS_INTG
+ {K_F21, nv_nbcmd, NV_NCH_ALW, 0},
+#endif
+#ifdef FEAT_DND
+ {K_DROP, nv_drop, NV_STS, 0},
+#endif
+ {K_CURSORHOLD, nv_cursorhold, NV_KEEPREG, 0},
+ {K_PS, nv_edit, 0, 0},
+};
+
+/* Number of commands in nv_cmds[]. */
+#define NV_CMDS_SIZE (sizeof(nv_cmds) / sizeof(struct nv_cmd))
+
+/* Sorted index of commands in nv_cmds[]. */
+static short nv_cmd_idx[NV_CMDS_SIZE];
+
+/* The highest index for which
+ * nv_cmds[idx].cmd_char == nv_cmd_idx[nv_cmds[idx].cmd_char] */
+static int nv_max_linear;
+
+/*
+ * Compare functions for qsort() below, that checks the command character
+ * through the index in nv_cmd_idx[].
+ */
+ static int
+#ifdef __BORLANDC__
+_RTLENTRYF
+#endif
+nv_compare(const void *s1, const void *s2)
+{
+ int c1, c2;
+
+ /* The commands are sorted on absolute value. */
+ c1 = nv_cmds[*(const short *)s1].cmd_char;
+ c2 = nv_cmds[*(const short *)s2].cmd_char;
+ if (c1 < 0)
+ c1 = -c1;
+ if (c2 < 0)
+ c2 = -c2;
+ return c1 - c2;
+}
+
+/*
+ * Initialize the nv_cmd_idx[] table.
+ */
+ void
+init_normal_cmds(void)
+{
+ int i;
+
+ /* Fill the index table with a one to one relation. */
+ for (i = 0; i < (int)NV_CMDS_SIZE; ++i)
+ nv_cmd_idx[i] = i;
+
+ /* Sort the commands by the command character. */
+ qsort((void *)&nv_cmd_idx, (size_t)NV_CMDS_SIZE, sizeof(short), nv_compare);
+
+ /* Find the first entry that can't be indexed by the command character. */
+ for (i = 0; i < (int)NV_CMDS_SIZE; ++i)
+ if (i != nv_cmds[nv_cmd_idx[i]].cmd_char)
+ break;
+ nv_max_linear = i - 1;
+}
+
+/*
+ * Search for a command in the commands table.
+ * Returns -1 for invalid command.
+ */
+ static int
+find_command(int cmdchar)
+{
+ int i;
+ int idx;
+ int top, bot;
+ int c;
+
+ /* A multi-byte character is never a command. */
+ if (cmdchar >= 0x100)
+ return -1;
+
+ /* We use the absolute value of the character. Special keys have a
+ * negative value, but are sorted on their absolute value. */
+ if (cmdchar < 0)
+ cmdchar = -cmdchar;
+
+ /* If the character is in the first part: The character is the index into
+ * nv_cmd_idx[]. */
+ if (cmdchar <= nv_max_linear)
+ return nv_cmd_idx[cmdchar];
+
+ /* Perform a binary search. */
+ bot = nv_max_linear + 1;
+ top = NV_CMDS_SIZE - 1;
+ idx = -1;
+ while (bot <= top)
+ {
+ i = (top + bot) / 2;
+ c = nv_cmds[nv_cmd_idx[i]].cmd_char;
+ if (c < 0)
+ c = -c;
+ if (cmdchar == c)
+ {
+ idx = nv_cmd_idx[i];
+ break;
+ }
+ if (cmdchar > c)
+ bot = i + 1;
+ else
+ top = i - 1;
+ }
+ return idx;
+}
+
+/*
+ * Execute a command in Normal mode.
+ */
+ void
+normal_cmd(
+ oparg_T *oap,
+ int toplevel UNUSED) /* TRUE when called from main() */
+{
+ cmdarg_T ca; /* command arguments */
+ int c;
+ int ctrl_w = FALSE; /* got CTRL-W command */
+ int old_col = curwin->w_curswant;
+#ifdef FEAT_CMDL_INFO
+ int need_flushbuf; /* need to call out_flush() */
+#endif
+ pos_T old_pos; /* cursor position before command */
+ int mapped_len;
+ static int old_mapped_len = 0;
+ int idx;
+#ifdef FEAT_EVAL
+ int set_prevcount = FALSE;
+#endif
+
+ vim_memset(&ca, 0, sizeof(ca)); /* also resets ca.retval */
+ ca.oap = oap;
+
+ /* Use a count remembered from before entering an operator. After typing
+ * "3d" we return from normal_cmd() and come back here, the "3" is
+ * remembered in "opcount". */
+ ca.opcount = opcount;
+
+ /*
+ * If there is an operator pending, then the command we take this time
+ * will terminate it. Finish_op tells us to finish the operation before
+ * returning this time (unless the operation was cancelled).
+ */
+#ifdef CURSOR_SHAPE
+ c = finish_op;
+#endif
+ finish_op = (oap->op_type != OP_NOP);
+#ifdef CURSOR_SHAPE
+ if (finish_op != c)
+ {
+ ui_cursor_shape(); /* may show different cursor shape */
+# ifdef FEAT_MOUSESHAPE
+ update_mouseshape(-1);
+# endif
+ }
+#endif
+
+ /* When not finishing an operator and no register name typed, reset the
+ * count. */
+ if (!finish_op && !oap->regname)
+ {
+ ca.opcount = 0;
+#ifdef FEAT_EVAL
+ set_prevcount = TRUE;
+#endif
+ }
+
+ /* Restore counts from before receiving K_CURSORHOLD. This means after
+ * typing "3", handling K_CURSORHOLD and then typing "2" we get "32", not
+ * "3 * 2". */
+ if (oap->prev_opcount > 0 || oap->prev_count0 > 0)
+ {
+ ca.opcount = oap->prev_opcount;
+ ca.count0 = oap->prev_count0;
+ oap->prev_opcount = 0;
+ oap->prev_count0 = 0;
+ }
+
+ mapped_len = typebuf_maplen();
+
+ State = NORMAL_BUSY;
+#ifdef USE_ON_FLY_SCROLL
+ dont_scroll = FALSE; /* allow scrolling here */
+#endif
+
+#ifdef FEAT_EVAL
+ /* Set v:count here, when called from main() and not a stuffed
+ * command, so that v:count can be used in an expression mapping
+ * when there is no count. Do set it for redo. */
+ if (toplevel && readbuf1_empty())
+ set_vcount_ca(&ca, &set_prevcount);
+#endif
+
+ /*
+ * Get the command character from the user.
+ */
+ c = safe_vgetc();
+ LANGMAP_ADJUST(c, get_real_state() != SELECTMODE);
+
+ /*
+ * If a mapping was started in Visual or Select mode, remember the length
+ * of the mapping. This is used below to not return to Insert mode for as
+ * long as the mapping is being executed.
+ */
+ if (restart_edit == 0)
+ old_mapped_len = 0;
+ else if (old_mapped_len
+ || (VIsual_active && mapped_len == 0 && typebuf_maplen() > 0))
+ old_mapped_len = typebuf_maplen();
+
+ if (c == NUL)
+ c = K_ZERO;
+
+ /*
+ * In Select mode, typed text replaces the selection.
+ */
+ if (VIsual_active
+ && VIsual_select
+ && (vim_isprintc(c) || c == NL || c == CAR || c == K_KENTER))
+ {
+ /* Fake a "c"hange command. When "restart_edit" is set (e.g., because
+ * 'insertmode' is set) fake a "d"elete command, Insert mode will
+ * restart automatically.
+ * Insert the typed character in the typeahead buffer, so that it can
+ * be mapped in Insert mode. Required for ":lmap" to work. */
+ ins_char_typebuf(c);
+ if (restart_edit != 0)
+ c = 'd';
+ else
+ c = 'c';
+ msg_nowait = TRUE; /* don't delay going to insert mode */
+ old_mapped_len = 0; /* do go to Insert mode */
+ }
+
+#ifdef FEAT_CMDL_INFO
+ need_flushbuf = add_to_showcmd(c);
+#endif
+
+getcount:
+ if (!(VIsual_active && VIsual_select))
+ {
+ /*
+ * Handle a count before a command and compute ca.count0.
+ * Note that '0' is a command and not the start of a count, but it's
+ * part of a count after other digits.
+ */
+ while ( (c >= '1' && c <= '9')
+ || (ca.count0 != 0 && (c == K_DEL || c == K_KDEL || c == '0')))
+ {
+ if (c == K_DEL || c == K_KDEL)
+ {
+ ca.count0 /= 10;
+#ifdef FEAT_CMDL_INFO
+ del_from_showcmd(4); /* delete the digit and ~@% */
+#endif
+ }
+ else
+ ca.count0 = ca.count0 * 10 + (c - '0');
+ if (ca.count0 < 0) /* got too large! */
+ ca.count0 = 999999999L;
+#ifdef FEAT_EVAL
+ /* Set v:count here, when called from main() and not a stuffed
+ * command, so that v:count can be used in an expression mapping
+ * right after the count. Do set it for redo. */
+ if (toplevel && readbuf1_empty())
+ set_vcount_ca(&ca, &set_prevcount);
+#endif
+ if (ctrl_w)
+ {
+ ++no_mapping;
+ ++allow_keys; /* no mapping for nchar, but keys */
+ }
+ ++no_zero_mapping; /* don't map zero here */
+ c = plain_vgetc();
+ LANGMAP_ADJUST(c, TRUE);
+ --no_zero_mapping;
+ if (ctrl_w)
+ {
+ --no_mapping;
+ --allow_keys;
+ }
+#ifdef FEAT_CMDL_INFO
+ need_flushbuf |= add_to_showcmd(c);
+#endif
+ }
+
+ /*
+ * If we got CTRL-W there may be a/another count
+ */
+ if (c == Ctrl_W && !ctrl_w && oap->op_type == OP_NOP)
+ {
+ ctrl_w = TRUE;
+ ca.opcount = ca.count0; /* remember first count */
+ ca.count0 = 0;
+ ++no_mapping;
+ ++allow_keys; /* no mapping for nchar, but keys */
+ c = plain_vgetc(); /* get next character */
+ LANGMAP_ADJUST(c, TRUE);
+ --no_mapping;
+ --allow_keys;
+#ifdef FEAT_CMDL_INFO
+ need_flushbuf |= add_to_showcmd(c);
+#endif
+ goto getcount; /* jump back */
+ }
+ }
+
+ if (c == K_CURSORHOLD)
+ {
+ /* Save the count values so that ca.opcount and ca.count0 are exactly
+ * the same when coming back here after handling K_CURSORHOLD. */
+ oap->prev_opcount = ca.opcount;
+ oap->prev_count0 = ca.count0;
+ }
+ else if (ca.opcount != 0)
+ {
+ /*
+ * If we're in the middle of an operator (including after entering a
+ * yank buffer with '"') AND we had a count before the operator, then
+ * that count overrides the current value of ca.count0.
+ * What this means effectively, is that commands like "3dw" get turned
+ * into "d3w" which makes things fall into place pretty neatly.
+ * If you give a count before AND after the operator, they are
+ * multiplied.
+ */
+ if (ca.count0)
+ ca.count0 *= ca.opcount;
+ else
+ ca.count0 = ca.opcount;
+ }
+
+ /*
+ * Always remember the count. It will be set to zero (on the next call,
+ * above) when there is no pending operator.
+ * When called from main(), save the count for use by the "count" built-in
+ * variable.
+ */
+ ca.opcount = ca.count0;
+ ca.count1 = (ca.count0 == 0 ? 1 : ca.count0);
+
+#ifdef FEAT_EVAL
+ /*
+ * Only set v:count when called from main() and not a stuffed command.
+ * Do set it for redo.
+ */
+ if (toplevel && readbuf1_empty())
+ set_vcount(ca.count0, ca.count1, set_prevcount);
+#endif
+
+ /*
+ * Find the command character in the table of commands.
+ * For CTRL-W we already got nchar when looking for a count.
+ */
+ if (ctrl_w)
+ {
+ ca.nchar = c;
+ ca.cmdchar = Ctrl_W;
+ }
+ else
+ ca.cmdchar = c;
+ idx = find_command(ca.cmdchar);
+ if (idx < 0)
+ {
+ /* Not a known command: beep. */
+ clearopbeep(oap);
+ goto normal_end;
+ }
+
+ if (text_locked() && (nv_cmds[idx].cmd_flags & NV_NCW))
+ {
+ /* This command is not allowed while editing a cmdline: beep. */
+ clearopbeep(oap);
+ text_locked_msg();
+ goto normal_end;
+ }
+ if ((nv_cmds[idx].cmd_flags & NV_NCW) && curbuf_locked())
+ goto normal_end;
+
+ /*
+ * In Visual/Select mode, a few keys are handled in a special way.
+ */
+ if (VIsual_active)
+ {
+ /* when 'keymodel' contains "stopsel" may stop Select/Visual mode */
+ if (km_stopsel
+ && (nv_cmds[idx].cmd_flags & NV_STS)
+ && !(mod_mask & MOD_MASK_SHIFT))
+ {
+ end_visual_mode();
+ redraw_curbuf_later(INVERTED);
+ }
+
+ /* Keys that work different when 'keymodel' contains "startsel" */
+ if (km_startsel)
+ {
+ if (nv_cmds[idx].cmd_flags & NV_SS)
+ {
+ unshift_special(&ca);
+ idx = find_command(ca.cmdchar);
+ if (idx < 0)
+ {
+ /* Just in case */
+ clearopbeep(oap);
+ goto normal_end;
+ }
+ }
+ else if ((nv_cmds[idx].cmd_flags & NV_SSS)
+ && (mod_mask & MOD_MASK_SHIFT))
+ {
+ mod_mask &= ~MOD_MASK_SHIFT;
+ }
+ }
+ }
+
+#ifdef FEAT_RIGHTLEFT
+ if (curwin->w_p_rl && KeyTyped && !KeyStuffed
+ && (nv_cmds[idx].cmd_flags & NV_RL))
+ {
+ /* Invert horizontal movements and operations. Only when typed by the
+ * user directly, not when the result of a mapping or "x" translated
+ * to "dl". */
+ switch (ca.cmdchar)
+ {
+ case 'l': ca.cmdchar = 'h'; break;
+ case K_RIGHT: ca.cmdchar = K_LEFT; break;
+ case K_S_RIGHT: ca.cmdchar = K_S_LEFT; break;
+ case K_C_RIGHT: ca.cmdchar = K_C_LEFT; break;
+ case 'h': ca.cmdchar = 'l'; break;
+ case K_LEFT: ca.cmdchar = K_RIGHT; break;
+ case K_S_LEFT: ca.cmdchar = K_S_RIGHT; break;
+ case K_C_LEFT: ca.cmdchar = K_C_RIGHT; break;
+ case '>': ca.cmdchar = '<'; break;
+ case '<': ca.cmdchar = '>'; break;
+ }
+ idx = find_command(ca.cmdchar);
+ }
+#endif
+
+ /*
+ * Get an additional character if we need one.
+ */
+ if ((nv_cmds[idx].cmd_flags & NV_NCH)
+ && (((nv_cmds[idx].cmd_flags & NV_NCH_NOP) == NV_NCH_NOP
+ && oap->op_type == OP_NOP)
+ || (nv_cmds[idx].cmd_flags & NV_NCH_ALW) == NV_NCH_ALW
+ || (ca.cmdchar == 'q'
+ && oap->op_type == OP_NOP
+ && reg_recording == 0
+ && reg_executing == 0)
+ || ((ca.cmdchar == 'a' || ca.cmdchar == 'i')
+ && (oap->op_type != OP_NOP || VIsual_active))))
+ {
+ int *cp;
+ int repl = FALSE; /* get character for replace mode */
+ int lit = FALSE; /* get extra character literally */
+ int langmap_active = FALSE; /* using :lmap mappings */
+ int lang; /* getting a text character */
+#ifdef HAVE_INPUT_METHOD
+ int save_smd; /* saved value of p_smd */
+#endif
+
+ ++no_mapping;
+ ++allow_keys; /* no mapping for nchar, but allow key codes */
+ /* Don't generate a CursorHold event here, most commands can't handle
+ * it, e.g., nv_replace(), nv_csearch(). */
+ did_cursorhold = TRUE;
+ if (ca.cmdchar == 'g')
+ {
+ /*
+ * For 'g' get the next character now, so that we can check for
+ * "gr", "g'" and "g`".
+ */
+ ca.nchar = plain_vgetc();
+ LANGMAP_ADJUST(ca.nchar, TRUE);
+#ifdef FEAT_CMDL_INFO
+ need_flushbuf |= add_to_showcmd(ca.nchar);
+#endif
+ if (ca.nchar == 'r' || ca.nchar == '\'' || ca.nchar == '`'
+ || ca.nchar == Ctrl_BSL)
+ {
+ cp = &ca.extra_char; /* need to get a third character */
+ if (ca.nchar != 'r')
+ lit = TRUE; /* get it literally */
+ else
+ repl = TRUE; /* get it in replace mode */
+ }
+ else
+ cp = NULL; /* no third character needed */
+ }
+ else
+ {
+ if (ca.cmdchar == 'r') /* get it in replace mode */
+ repl = TRUE;
+ cp = &ca.nchar;
+ }
+ lang = (repl || (nv_cmds[idx].cmd_flags & NV_LANG));
+
+ /*
+ * Get a second or third character.
+ */
+ if (cp != NULL)
+ {
+#ifdef CURSOR_SHAPE
+ if (repl)
+ {
+ State = REPLACE; /* pretend Replace mode */
+ ui_cursor_shape(); /* show different cursor shape */
+ }
+#endif
+ if (lang && curbuf->b_p_iminsert == B_IMODE_LMAP)
+ {
+ /* Allow mappings defined with ":lmap". */
+ --no_mapping;
+ --allow_keys;
+ if (repl)
+ State = LREPLACE;
+ else
+ State = LANGMAP;
+ langmap_active = TRUE;
+ }
+#ifdef HAVE_INPUT_METHOD
+ save_smd = p_smd;
+ p_smd = FALSE; /* Don't let the IM code show the mode here */
+ if (lang && curbuf->b_p_iminsert == B_IMODE_IM)
+ im_set_active(TRUE);
+#endif
+
+ *cp = plain_vgetc();
+
+ if (langmap_active)
+ {
+ /* Undo the decrement done above */
+ ++no_mapping;
+ ++allow_keys;
+ State = NORMAL_BUSY;
+ }
+#ifdef HAVE_INPUT_METHOD
+ if (lang)
+ {
+ if (curbuf->b_p_iminsert != B_IMODE_LMAP)
+ im_save_status(&curbuf->b_p_iminsert);
+ im_set_active(FALSE);
+ }
+ p_smd = save_smd;
+#endif
+#ifdef CURSOR_SHAPE
+ State = NORMAL_BUSY;
+#endif
+#ifdef FEAT_CMDL_INFO
+ need_flushbuf |= add_to_showcmd(*cp);
+#endif
+
+ if (!lit)
+ {
+#ifdef FEAT_DIGRAPHS
+ /* Typing CTRL-K gets a digraph. */
+ if (*cp == Ctrl_K
+ && ((nv_cmds[idx].cmd_flags & NV_LANG)
+ || cp == &ca.extra_char)
+ && vim_strchr(p_cpo, CPO_DIGRAPH) == NULL)
+ {
+ c = get_digraph(FALSE);
+ if (c > 0)
+ {
+ *cp = c;
+# ifdef FEAT_CMDL_INFO
+ /* Guessing how to update showcmd here... */
+ del_from_showcmd(3);
+ need_flushbuf |= add_to_showcmd(*cp);
+# endif
+ }
+ }
+#endif
+
+ /* adjust chars > 127, except after "tTfFr" commands */
+ LANGMAP_ADJUST(*cp, !lang);
+#ifdef FEAT_RIGHTLEFT
+ /* adjust Hebrew mapped char */
+ if (p_hkmap && lang && KeyTyped)
+ *cp = hkmap(*cp);
+# ifdef FEAT_FKMAP
+ /* adjust Farsi mapped char */
+ if (p_fkmap && lang && KeyTyped)
+ *cp = fkmap(*cp);
+# endif
+#endif
+ }
+
+ /*
+ * When the next character is CTRL-\ a following CTRL-N means the
+ * command is aborted and we go to Normal mode.
+ */
+ if (cp == &ca.extra_char
+ && ca.nchar == Ctrl_BSL
+ && (ca.extra_char == Ctrl_N || ca.extra_char == Ctrl_G))
+ {
+ ca.cmdchar = Ctrl_BSL;
+ ca.nchar = ca.extra_char;
+ idx = find_command(ca.cmdchar);
+ }
+ else if ((ca.nchar == 'n' || ca.nchar == 'N') && ca.cmdchar == 'g')
+ ca.oap->op_type = get_op_type(*cp, NUL);
+ else if (*cp == Ctrl_BSL)
+ {
+ long towait = (p_ttm >= 0 ? p_ttm : p_tm);
+
+ /* There is a busy wait here when typing "f<C-\>" and then
+ * something different from CTRL-N. Can't be avoided. */
+ while ((c = vpeekc()) <= 0 && towait > 0L)
+ {
+ do_sleep(towait > 50L ? 50L : towait);
+ towait -= 50L;
+ }
+ if (c > 0)
+ {
+ c = plain_vgetc();
+ if (c != Ctrl_N && c != Ctrl_G)
+ vungetc(c);
+ else
+ {
+ ca.cmdchar = Ctrl_BSL;
+ ca.nchar = c;
+ idx = find_command(ca.cmdchar);
+ }
+ }
+ }
+
+ /* When getting a text character and the next character is a
+ * multi-byte character, it could be a composing character.
+ * However, don't wait for it to arrive. Also, do enable mapping,
+ * because if it's put back with vungetc() it's too late to apply
+ * mapping. */
+ --no_mapping;
+ while (enc_utf8 && lang && (c = vpeekc()) > 0
+ && (c >= 0x100 || MB_BYTE2LEN(vpeekc()) > 1))
+ {
+ c = plain_vgetc();
+ if (!utf_iscomposing(c))
+ {
+ vungetc(c); /* it wasn't, put it back */
+ break;
+ }
+ else if (ca.ncharC1 == 0)
+ ca.ncharC1 = c;
+ else
+ ca.ncharC2 = c;
+ }
+ ++no_mapping;
+ }
+ --no_mapping;
+ --allow_keys;
+ }
+
+#ifdef FEAT_CMDL_INFO
+ /*
+ * Flush the showcmd characters onto the screen so we can see them while
+ * the command is being executed. Only do this when the shown command was
+ * actually displayed, otherwise this will slow down a lot when executing
+ * mappings.
+ */
+ if (need_flushbuf)
+ out_flush();
+#endif
+ if (ca.cmdchar != K_IGNORE)
+ did_cursorhold = FALSE;
+
+ State = NORMAL;
+
+ if (ca.nchar == ESC)
+ {
+ clearop(oap);
+ if (restart_edit == 0 && goto_im())
+ restart_edit = 'a';
+ goto normal_end;
+ }
+
+ if (ca.cmdchar != K_IGNORE)
+ {
+ msg_didout = FALSE; /* don't scroll screen up for normal command */
+ msg_col = 0;
+ }
+
+ old_pos = curwin->w_cursor; /* remember where cursor was */
+
+ /* When 'keymodel' contains "startsel" some keys start Select/Visual
+ * mode. */
+ if (!VIsual_active && km_startsel)
+ {
+ if (nv_cmds[idx].cmd_flags & NV_SS)
+ {
+ start_selection();
+ unshift_special(&ca);
+ idx = find_command(ca.cmdchar);
+ }
+ else if ((nv_cmds[idx].cmd_flags & NV_SSS)
+ && (mod_mask & MOD_MASK_SHIFT))
+ {
+ start_selection();
+ mod_mask &= ~MOD_MASK_SHIFT;
+ }
+ }
+
+ /*
+ * Execute the command!
+ * Call the command function found in the commands table.
+ */
+ ca.arg = nv_cmds[idx].cmd_arg;
+ (nv_cmds[idx].cmd_func)(&ca);
+
+ /*
+ * If we didn't start or finish an operator, reset oap->regname, unless we
+ * need it later.
+ */
+ if (!finish_op
+ && !oap->op_type
+ && (idx < 0 || !(nv_cmds[idx].cmd_flags & NV_KEEPREG)))
+ {
+ clearop(oap);
+#ifdef FEAT_EVAL
+ {
+ int regname = 0;
+
+ /* Adjust the register according to 'clipboard', so that when
+ * "unnamed" is present it becomes '*' or '+' instead of '"'. */
+# ifdef FEAT_CLIPBOARD
+ adjust_clip_reg(&regname);
+# endif
+ set_reg_var(regname);
+ }
+#endif
+ }
+
+ /* Get the length of mapped chars again after typing a count, second
+ * character or "z333<cr>". */
+ if (old_mapped_len > 0)
+ old_mapped_len = typebuf_maplen();
+
+ /*
+ * If an operation is pending, handle it...
+ */
+ do_pending_operator(&ca, old_col, FALSE);
+
+ /*
+ * Wait for a moment when a message is displayed that will be overwritten
+ * by the mode message.
+ * In Visual mode and with "^O" in Insert mode, a short message will be
+ * overwritten by the mode message. Wait a bit, until a key is hit.
+ * In Visual mode, it's more important to keep the Visual area updated
+ * than keeping a message (e.g. from a /pat search).
+ * Only do this if the command was typed, not from a mapping.
+ * Don't wait when emsg_silent is non-zero.
+ * Also wait a bit after an error message, e.g. for "^O:".
+ * Don't redraw the screen, it would remove the message.
+ */
+ if ( ((p_smd
+ && msg_silent == 0
+ && (restart_edit != 0
+ || (VIsual_active
+ && old_pos.lnum == curwin->w_cursor.lnum
+ && old_pos.col == curwin->w_cursor.col)
+ )
+ && (clear_cmdline
+ || redraw_cmdline)
+ && (msg_didout || (msg_didany && msg_scroll))
+ && !msg_nowait
+ && KeyTyped)
+ || (restart_edit != 0
+ && !VIsual_active
+ && (msg_scroll
+ || emsg_on_display)))
+ && oap->regname == 0
+ && !(ca.retval & CA_COMMAND_BUSY)
+ && stuff_empty()
+ && typebuf_typed()
+ && emsg_silent == 0
+ && !did_wait_return
+ && oap->op_type == OP_NOP)
+ {
+ int save_State = State;
+
+ /* Draw the cursor with the right shape here */
+ if (restart_edit != 0)
+ State = INSERT;
+
+ /* If need to redraw, and there is a "keep_msg", redraw before the
+ * delay */
+ if (must_redraw && keep_msg != NULL && !emsg_on_display)
+ {
+ char_u *kmsg;
+
+ kmsg = keep_msg;
+ keep_msg = NULL;
+ /* showmode() will clear keep_msg, but we want to use it anyway */
+ update_screen(0);
+ /* now reset it, otherwise it's put in the history again */
+ keep_msg = kmsg;
+ msg_attr((char *)kmsg, keep_msg_attr);
+ vim_free(kmsg);
+ }
+ setcursor();
+ cursor_on();
+ out_flush();
+ if (msg_scroll || emsg_on_display)
+ ui_delay(1000L, TRUE); /* wait at least one second */
+ ui_delay(3000L, FALSE); /* wait up to three seconds */
+ State = save_State;
+
+ msg_scroll = FALSE;
+ emsg_on_display = FALSE;
+ }
+
+ /*
+ * Finish up after executing a Normal mode command.
+ */
+normal_end:
+
+ msg_nowait = FALSE;
+
+ /* Reset finish_op, in case it was set */
+#ifdef CURSOR_SHAPE
+ c = finish_op;
+#endif
+ finish_op = FALSE;
+#ifdef CURSOR_SHAPE
+ /* Redraw the cursor with another shape, if we were in Operator-pending
+ * mode or did a replace command. */
+ if (c || ca.cmdchar == 'r')
+ {
+ ui_cursor_shape(); /* may show different cursor shape */
+# ifdef FEAT_MOUSESHAPE
+ update_mouseshape(-1);
+# endif
+ }
+#endif
+
+#ifdef FEAT_CMDL_INFO
+ if (oap->op_type == OP_NOP && oap->regname == 0
+ && ca.cmdchar != K_CURSORHOLD)
+ clear_showcmd();
+#endif
+
+ checkpcmark(); /* check if we moved since setting pcmark */
+ vim_free(ca.searchbuf);
+
+ if (has_mbyte)
+ mb_adjust_cursor();
+
+ if (curwin->w_p_scb && toplevel)
+ {
+ validate_cursor(); /* may need to update w_leftcol */
+ do_check_scrollbind(TRUE);
+ }
+
+ if (curwin->w_p_crb && toplevel)
+ {
+ validate_cursor(); /* may need to update w_leftcol */
+ do_check_cursorbind();
+ }
+
+#ifdef FEAT_TERMINAL
+ /* don't go to Insert mode if a terminal has a running job */
+ if (term_job_running(curbuf->b_term))
+ restart_edit = 0;
+#endif
+
+ /*
+ * May restart edit(), if we got here with CTRL-O in Insert mode (but not
+ * if still inside a mapping that started in Visual mode).
+ * May switch from Visual to Select mode after CTRL-O command.
+ */
+ if ( oap->op_type == OP_NOP
+ && ((restart_edit != 0 && !VIsual_active && old_mapped_len == 0)
+ || restart_VIsual_select == 1)
+ && !(ca.retval & CA_COMMAND_BUSY)
+ && stuff_empty()
+ && oap->regname == 0)
+ {
+ if (restart_VIsual_select == 1)
+ {
+ VIsual_select = TRUE;
+ showmode();
+ restart_VIsual_select = 0;
+ }
+ if (restart_edit != 0 && !VIsual_active && old_mapped_len == 0)
+ (void)edit(restart_edit, FALSE, 1L);
+ }
+
+ if (restart_VIsual_select == 2)
+ restart_VIsual_select = 1;
+
+ /* Save count before an operator for next time. */
+ opcount = ca.opcount;
+}
+
+#ifdef FEAT_EVAL
+/*
+ * Set v:count and v:count1 according to "cap".
+ * Set v:prevcount only when "set_prevcount" is TRUE.
+ */
+ static void
+set_vcount_ca(cmdarg_T *cap, int *set_prevcount)
+{
+ long count = cap->count0;
+
+ /* multiply with cap->opcount the same way as above */
+ if (cap->opcount != 0)
+ count = cap->opcount * (count == 0 ? 1 : count);
+ set_vcount(count, count == 0 ? 1 : count, *set_prevcount);
+ *set_prevcount = FALSE; /* only set v:prevcount once */
+}
+#endif
+
+/*
+ * Handle an operator after Visual mode or when the movement is finished.
+ * "gui_yank" is true when yanking text for the clipboard.
+ */
+ void
+do_pending_operator(cmdarg_T *cap, int old_col, int gui_yank)
+{
+ oparg_T *oap = cap->oap;
+ pos_T old_cursor;
+ int empty_region_error;
+ int restart_edit_save;
+#ifdef FEAT_LINEBREAK
+ int lbr_saved = curwin->w_p_lbr;
+#endif
+
+ /* The visual area is remembered for redo */
+ static int redo_VIsual_mode = NUL; /* 'v', 'V', or Ctrl-V */
+ static linenr_T redo_VIsual_line_count; /* number of lines */
+ static colnr_T redo_VIsual_vcol; /* number of cols or end column */
+ static long redo_VIsual_count; /* count for Visual operator */
+ static int redo_VIsual_arg; /* extra argument */
+ int include_line_break = FALSE;
+
+#if defined(FEAT_CLIPBOARD)
+ /*
+ * Yank the visual area into the GUI selection register before we operate
+ * on it and lose it forever.
+ * Don't do it if a specific register was specified, so that ""x"*P works.
+ * This could call do_pending_operator() recursively, but that's OK
+ * because gui_yank will be TRUE for the nested call.
+ */
+ if ((clip_star.available || clip_plus.available)
+ && oap->op_type != OP_NOP
+ && !gui_yank
+ && VIsual_active
+ && !redo_VIsual_busy
+ && oap->regname == 0)
+ clip_auto_select();
+#endif
+ old_cursor = curwin->w_cursor;
+
+ /*
+ * If an operation is pending, handle it...
+ */
+ if ((finish_op || VIsual_active) && oap->op_type != OP_NOP)
+ {
+ // Yank can be redone when 'y' is in 'cpoptions', but not when yanking
+ // for the clipboard.
+ int redo_yank = vim_strchr(p_cpo, CPO_YANK) != NULL && !gui_yank;
+
+#ifdef FEAT_LINEBREAK
+ /* Avoid a problem with unwanted linebreaks in block mode. */
+ if (curwin->w_p_lbr)
+ curwin->w_valid &= ~VALID_VIRTCOL;
+ curwin->w_p_lbr = FALSE;
+#endif
+ oap->is_VIsual = VIsual_active;
+ if (oap->motion_force == 'V')
+ oap->motion_type = MLINE;
+ else if (oap->motion_force == 'v')
+ {
+ /* If the motion was linewise, "inclusive" will not have been set.
+ * Use "exclusive" to be consistent. Makes "dvj" work nice. */
+ if (oap->motion_type == MLINE)
+ oap->inclusive = FALSE;
+ /* If the motion already was characterwise, toggle "inclusive" */
+ else if (oap->motion_type == MCHAR)
+ oap->inclusive = !oap->inclusive;
+ oap->motion_type = MCHAR;
+ }
+ else if (oap->motion_force == Ctrl_V)
+ {
+ /* Change line- or characterwise motion into Visual block mode. */
+ if (!VIsual_active)
+ {
+ VIsual_active = TRUE;
+ VIsual = oap->start;
+ }
+ VIsual_mode = Ctrl_V;
+ VIsual_select = FALSE;
+ VIsual_reselect = FALSE;
+ }
+
+ /* Only redo yank when 'y' flag is in 'cpoptions'. */
+ /* Never redo "zf" (define fold). */
+ if ((redo_yank || oap->op_type != OP_YANK)
+ && ((!VIsual_active || oap->motion_force)
+ /* Also redo Operator-pending Visual mode mappings */
+ || (VIsual_active && cap->cmdchar == ':'
+ && oap->op_type != OP_COLON))
+ && cap->cmdchar != 'D'
+#ifdef FEAT_FOLDING
+ && oap->op_type != OP_FOLD
+ && oap->op_type != OP_FOLDOPEN
+ && oap->op_type != OP_FOLDOPENREC
+ && oap->op_type != OP_FOLDCLOSE
+ && oap->op_type != OP_FOLDCLOSEREC
+ && oap->op_type != OP_FOLDDEL
+ && oap->op_type != OP_FOLDDELREC
+#endif
+ )
+ {
+ prep_redo(oap->regname, cap->count0,
+ get_op_char(oap->op_type), get_extra_op_char(oap->op_type),
+ oap->motion_force, cap->cmdchar, cap->nchar);
+ if (cap->cmdchar == '/' || cap->cmdchar == '?') /* was a search */
+ {
+ /*
+ * If 'cpoptions' does not contain 'r', insert the search
+ * pattern to really repeat the same command.
+ */
+ if (vim_strchr(p_cpo, CPO_REDO) == NULL)
+ AppendToRedobuffLit(cap->searchbuf, -1);
+ AppendToRedobuff(NL_STR);
+ }
+ else if (cap->cmdchar == ':')
+ {
+ /* do_cmdline() has stored the first typed line in
+ * "repeat_cmdline". When several lines are typed repeating
+ * won't be possible. */
+ if (repeat_cmdline == NULL)
+ ResetRedobuff();
+ else
+ {
+ AppendToRedobuffLit(repeat_cmdline, -1);
+ AppendToRedobuff(NL_STR);
+ VIM_CLEAR(repeat_cmdline);
+ }
+ }
+ }
+
+ if (redo_VIsual_busy)
+ {
+ /* Redo of an operation on a Visual area. Use the same size from
+ * redo_VIsual_line_count and redo_VIsual_vcol. */
+ oap->start = curwin->w_cursor;
+ curwin->w_cursor.lnum += redo_VIsual_line_count - 1;
+ if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
+ curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
+ VIsual_mode = redo_VIsual_mode;
+ if (redo_VIsual_vcol == MAXCOL || VIsual_mode == 'v')
+ {
+ if (VIsual_mode == 'v')
+ {
+ if (redo_VIsual_line_count <= 1)
+ {
+ validate_virtcol();
+ curwin->w_curswant =
+ curwin->w_virtcol + redo_VIsual_vcol - 1;
+ }
+ else
+ curwin->w_curswant = redo_VIsual_vcol;
+ }
+ else
+ {
+ curwin->w_curswant = MAXCOL;
+ }
+ coladvance(curwin->w_curswant);
+ }
+ cap->count0 = redo_VIsual_count;
+ if (redo_VIsual_count != 0)
+ cap->count1 = redo_VIsual_count;
+ else
+ cap->count1 = 1;
+ }
+ else if (VIsual_active)
+ {
+ if (!gui_yank)
+ {
+ /* Save the current VIsual area for '< and '> marks, and "gv" */
+ curbuf->b_visual.vi_start = VIsual;
+ curbuf->b_visual.vi_end = curwin->w_cursor;
+ curbuf->b_visual.vi_mode = VIsual_mode;
+ if (VIsual_mode_orig != NUL)
+ {
+ curbuf->b_visual.vi_mode = VIsual_mode_orig;
+ VIsual_mode_orig = NUL;
+ }
+ curbuf->b_visual.vi_curswant = curwin->w_curswant;
+# ifdef FEAT_EVAL
+ curbuf->b_visual_mode_eval = VIsual_mode;
+# endif
+ }
+
+ /* In Select mode, a linewise selection is operated upon like a
+ * characterwise selection.
+ * Special case: gH<Del> deletes the last line. */
+ if (VIsual_select && VIsual_mode == 'V'
+ && cap->oap->op_type != OP_DELETE)
+ {
+ if (LT_POS(VIsual, curwin->w_cursor))
+ {
+ VIsual.col = 0;
+ curwin->w_cursor.col =
+ (colnr_T)STRLEN(ml_get(curwin->w_cursor.lnum));
+ }
+ else
+ {
+ curwin->w_cursor.col = 0;
+ VIsual.col = (colnr_T)STRLEN(ml_get(VIsual.lnum));
+ }
+ VIsual_mode = 'v';
+ }
+ /* If 'selection' is "exclusive", backup one character for
+ * charwise selections. */
+ else if (VIsual_mode == 'v')
+ include_line_break = unadjust_for_sel();
+
+ oap->start = VIsual;
+ if (VIsual_mode == 'V')
+ {
+ oap->start.col = 0;
+ oap->start.coladd = 0;
+ }
+ }
+
+ /*
+ * Set oap->start to the first position of the operated text, oap->end
+ * to the end of the operated text. w_cursor is equal to oap->start.
+ */
+ if (LT_POS(oap->start, curwin->w_cursor))
+ {
+#ifdef FEAT_FOLDING
+ /* Include folded lines completely. */
+ if (!VIsual_active)
+ {
+ if (hasFolding(oap->start.lnum, &oap->start.lnum, NULL))
+ oap->start.col = 0;
+ if (hasFolding(curwin->w_cursor.lnum, NULL,
+ &curwin->w_cursor.lnum))
+ curwin->w_cursor.col = (colnr_T)STRLEN(ml_get_curline());
+ }
+#endif
+ oap->end = curwin->w_cursor;
+ curwin->w_cursor = oap->start;
+
+ /* w_virtcol may have been updated; if the cursor goes back to its
+ * previous position w_virtcol becomes invalid and isn't updated
+ * automatically. */
+ curwin->w_valid &= ~VALID_VIRTCOL;
+ }
+ else
+ {
+#ifdef FEAT_FOLDING
+ /* Include folded lines completely. */
+ if (!VIsual_active && oap->motion_type == MLINE)
+ {
+ if (hasFolding(curwin->w_cursor.lnum, &curwin->w_cursor.lnum,
+ NULL))
+ curwin->w_cursor.col = 0;
+ if (hasFolding(oap->start.lnum, NULL, &oap->start.lnum))
+ oap->start.col = (colnr_T)STRLEN(ml_get(oap->start.lnum));
+ }
+#endif
+ oap->end = oap->start;
+ oap->start = curwin->w_cursor;
+ }
+
+ /* Just in case lines were deleted that make the position invalid. */
+ check_pos(curwin->w_buffer, &oap->end);
+ oap->line_count = oap->end.lnum - oap->start.lnum + 1;
+
+ /* Set "virtual_op" before resetting VIsual_active. */
+ virtual_op = virtual_active();
+
+ if (VIsual_active || redo_VIsual_busy)
+ {
+ get_op_vcol(oap, redo_VIsual_vcol, TRUE);
+
+ if (!redo_VIsual_busy && !gui_yank)
+ {
+ /*
+ * Prepare to reselect and redo Visual: this is based on the
+ * size of the Visual text
+ */
+ resel_VIsual_mode = VIsual_mode;
+ if (curwin->w_curswant == MAXCOL)
+ resel_VIsual_vcol = MAXCOL;
+ else
+ {
+ if (VIsual_mode != Ctrl_V)
+ getvvcol(curwin, &(oap->end),
+ NULL, NULL, &oap->end_vcol);
+ if (VIsual_mode == Ctrl_V || oap->line_count <= 1)
+ {
+ if (VIsual_mode != Ctrl_V)
+ getvvcol(curwin, &(oap->start),
+ &oap->start_vcol, NULL, NULL);
+ resel_VIsual_vcol = oap->end_vcol - oap->start_vcol + 1;
+ }
+ else
+ resel_VIsual_vcol = oap->end_vcol;
+ }
+ resel_VIsual_line_count = oap->line_count;
+ }
+
+ /* can't redo yank (unless 'y' is in 'cpoptions') and ":" */
+ if ((redo_yank || oap->op_type != OP_YANK)
+ && oap->op_type != OP_COLON
+#ifdef FEAT_FOLDING
+ && oap->op_type != OP_FOLD
+ && oap->op_type != OP_FOLDOPEN
+ && oap->op_type != OP_FOLDOPENREC
+ && oap->op_type != OP_FOLDCLOSE
+ && oap->op_type != OP_FOLDCLOSEREC
+ && oap->op_type != OP_FOLDDEL
+ && oap->op_type != OP_FOLDDELREC
+#endif
+ && oap->motion_force == NUL
+ )
+ {
+ /* Prepare for redoing. Only use the nchar field for "r",
+ * otherwise it might be the second char of the operator. */
+ if (cap->cmdchar == 'g' && (cap->nchar == 'n'
+ || cap->nchar == 'N'))
+ prep_redo(oap->regname, cap->count0,
+ get_op_char(oap->op_type), get_extra_op_char(oap->op_type),
+ oap->motion_force, cap->cmdchar, cap->nchar);
+ else if (cap->cmdchar != ':')
+ {
+ int nchar = oap->op_type == OP_REPLACE ? cap->nchar : NUL;
+
+ /* reverse what nv_replace() did */
+ if (nchar == REPLACE_CR_NCHAR)
+ nchar = CAR;
+ else if (nchar == REPLACE_NL_NCHAR)
+ nchar = NL;
+ prep_redo(oap->regname, 0L, NUL, 'v',
+ get_op_char(oap->op_type),
+ get_extra_op_char(oap->op_type),
+ nchar);
+ }
+ if (!redo_VIsual_busy)
+ {
+ redo_VIsual_mode = resel_VIsual_mode;
+ redo_VIsual_vcol = resel_VIsual_vcol;
+ redo_VIsual_line_count = resel_VIsual_line_count;
+ redo_VIsual_count = cap->count0;
+ redo_VIsual_arg = cap->arg;
+ }
+ }
+
+ /*
+ * oap->inclusive defaults to TRUE.
+ * If oap->end is on a NUL (empty line) oap->inclusive becomes
+ * FALSE. This makes "d}P" and "v}dP" work the same.
+ */
+ if (oap->motion_force == NUL || oap->motion_type == MLINE)
+ oap->inclusive = TRUE;
+ if (VIsual_mode == 'V')
+ oap->motion_type = MLINE;
+ else
+ {
+ oap->motion_type = MCHAR;
+ if (VIsual_mode != Ctrl_V && *ml_get_pos(&(oap->end)) == NUL
+ && (include_line_break || !virtual_op))
+ {
+ oap->inclusive = FALSE;
+ /* Try to include the newline, unless it's an operator
+ * that works on lines only. */
+ if (*p_sel != 'o'
+ && !op_on_lines(oap->op_type)
+ && oap->end.lnum < curbuf->b_ml.ml_line_count)
+ {
+ ++oap->end.lnum;
+ oap->end.col = 0;
+ oap->end.coladd = 0;
+ ++oap->line_count;
+ }
+ }
+ }
+
+ redo_VIsual_busy = FALSE;
+
+ /*
+ * Switch Visual off now, so screen updating does
+ * not show inverted text when the screen is redrawn.
+ * With OP_YANK and sometimes with OP_COLON and OP_FILTER there is
+ * no screen redraw, so it is done here to remove the inverted
+ * part.
+ */
+ if (!gui_yank)
+ {
+ VIsual_active = FALSE;
+#ifdef FEAT_MOUSE
+ setmouse();
+ mouse_dragging = 0;
+#endif
+ may_clear_cmdline();
+ if ((oap->op_type == OP_YANK
+ || oap->op_type == OP_COLON
+ || oap->op_type == OP_FUNCTION
+ || oap->op_type == OP_FILTER)
+ && oap->motion_force == NUL)
+ {
+#ifdef FEAT_LINEBREAK
+ /* make sure redrawing is correct */
+ curwin->w_p_lbr = lbr_saved;
+#endif
+ redraw_curbuf_later(INVERTED);
+ }
+ }
+ }
+
+ /* Include the trailing byte of a multi-byte char. */
+ if (has_mbyte && oap->inclusive)
+ {
+ int l;
+
+ l = (*mb_ptr2len)(ml_get_pos(&oap->end));
+ if (l > 1)
+ oap->end.col += l - 1;
+ }
+ curwin->w_set_curswant = TRUE;
+
+ /*
+ * oap->empty is set when start and end are the same. The inclusive
+ * flag affects this too, unless yanking and the end is on a NUL.
+ */
+ oap->empty = (oap->motion_type == MCHAR
+ && (!oap->inclusive
+ || (oap->op_type == OP_YANK
+ && gchar_pos(&oap->end) == NUL))
+ && EQUAL_POS(oap->start, oap->end)
+ && !(virtual_op && oap->start.coladd != oap->end.coladd));
+ /*
+ * For delete, change and yank, it's an error to operate on an
+ * empty region, when 'E' included in 'cpoptions' (Vi compatible).
+ */
+ empty_region_error = (oap->empty
+ && vim_strchr(p_cpo, CPO_EMPTYREGION) != NULL);
+
+ /* Force a redraw when operating on an empty Visual region, when
+ * 'modifiable is off or creating a fold. */
+ if (oap->is_VIsual && (oap->empty || !curbuf->b_p_ma
+#ifdef FEAT_FOLDING
+ || oap->op_type == OP_FOLD
+#endif
+ ))
+ {
+#ifdef FEAT_LINEBREAK
+ curwin->w_p_lbr = lbr_saved;
+#endif
+ redraw_curbuf_later(INVERTED);
+ }
+
+ /*
+ * If the end of an operator is in column one while oap->motion_type
+ * is MCHAR and oap->inclusive is FALSE, we put op_end after the last
+ * character in the previous line. If op_start is on or before the
+ * first non-blank in the line, the operator becomes linewise
+ * (strange, but that's the way vi does it).
+ */
+ if ( oap->motion_type == MCHAR
+ && oap->inclusive == FALSE
+ && !(cap->retval & CA_NO_ADJ_OP_END)
+ && oap->end.col == 0
+ && (!oap->is_VIsual || *p_sel == 'o')
+ && !oap->block_mode
+ && oap->line_count > 1)
+ {
+ oap->end_adjusted = TRUE; /* remember that we did this */
+ --oap->line_count;
+ --oap->end.lnum;
+ if (inindent(0))
+ oap->motion_type = MLINE;
+ else
+ {
+ oap->end.col = (colnr_T)STRLEN(ml_get(oap->end.lnum));
+ if (oap->end.col)
+ {
+ --oap->end.col;
+ oap->inclusive = TRUE;
+ }
+ }
+ }
+ else
+ oap->end_adjusted = FALSE;
+
+ switch (oap->op_type)
+ {
+ case OP_LSHIFT:
+ case OP_RSHIFT:
+ op_shift(oap, TRUE, oap->is_VIsual ? (int)cap->count1 : 1);
+ auto_format(FALSE, TRUE);
+ break;
+
+ case OP_JOIN_NS:
+ case OP_JOIN:
+ if (oap->line_count < 2)
+ oap->line_count = 2;
+ if (curwin->w_cursor.lnum + oap->line_count - 1 >
+ curbuf->b_ml.ml_line_count)
+ beep_flush();
+ else
+ {
+ (void)do_join(oap->line_count, oap->op_type == OP_JOIN,
+ TRUE, TRUE, TRUE);
+ auto_format(FALSE, TRUE);
+ }
+ break;
+
+ case OP_DELETE:
+ VIsual_reselect = FALSE; /* don't reselect now */
+ if (empty_region_error)
+ {
+ vim_beep(BO_OPER);
+ CancelRedo();
+ }
+ else
+ {
+ (void)op_delete(oap);
+ if (oap->motion_type == MLINE && has_format_option(FO_AUTO))
+ u_save_cursor(); /* cursor line wasn't saved yet */
+ auto_format(FALSE, TRUE);
+ }
+ break;
+
+ case OP_YANK:
+ if (empty_region_error)
+ {
+ if (!gui_yank)
+ {
+ vim_beep(BO_OPER);
+ CancelRedo();
+ }
+ }
+ else
+ {
+#ifdef FEAT_LINEBREAK
+ curwin->w_p_lbr = lbr_saved;
+#endif
+ (void)op_yank(oap, FALSE, !gui_yank);
+ }
+ check_cursor_col();
+ break;
+
+ case OP_CHANGE:
+ VIsual_reselect = FALSE; /* don't reselect now */
+ if (empty_region_error)
+ {
+ vim_beep(BO_OPER);
+ CancelRedo();
+ }
+ else
+ {
+ /* This is a new edit command, not a restart. Need to
+ * remember it to make 'insertmode' work with mappings for
+ * Visual mode. But do this only once and not when typed and
+ * 'insertmode' isn't set. */
+ if (p_im || !KeyTyped)
+ restart_edit_save = restart_edit;
+ else
+ restart_edit_save = 0;
+ restart_edit = 0;
+#ifdef FEAT_LINEBREAK
+ /* Restore linebreak, so that when the user edits it looks as
+ * before. */
+ if (curwin->w_p_lbr != lbr_saved)
+ {
+ curwin->w_p_lbr = lbr_saved;
+ get_op_vcol(oap, redo_VIsual_mode, FALSE);
+ }
+#endif
+ /* Reset finish_op now, don't want it set inside edit(). */
+ finish_op = FALSE;
+ if (op_change(oap)) /* will call edit() */
+ cap->retval |= CA_COMMAND_BUSY;
+ if (restart_edit == 0)
+ restart_edit = restart_edit_save;
+ }
+ break;
+
+ case OP_FILTER:
+ if (vim_strchr(p_cpo, CPO_FILTER) != NULL)
+ AppendToRedobuff((char_u *)"!\r"); /* use any last used !cmd */
+ else
+ bangredo = TRUE; /* do_bang() will put cmd in redo buffer */
+ /* FALLTHROUGH */
+
+ case OP_INDENT:
+ case OP_COLON:
+
+#if defined(FEAT_LISP) || defined(FEAT_CINDENT)
+ /*
+ * If 'equalprg' is empty, do the indenting internally.
+ */
+ if (oap->op_type == OP_INDENT && *get_equalprg() == NUL)
+ {
+# ifdef FEAT_LISP
+ if (curbuf->b_p_lisp)
+ {
+ op_reindent(oap, get_lisp_indent);
+ break;
+ }
+# endif
+# ifdef FEAT_CINDENT
+ op_reindent(oap,
+# ifdef FEAT_EVAL
+ *curbuf->b_p_inde != NUL ? get_expr_indent :
+# endif
+ get_c_indent);
+ break;
+# endif
+ }
+#endif
+
+ op_colon(oap);
+ break;
+
+ case OP_TILDE:
+ case OP_UPPER:
+ case OP_LOWER:
+ case OP_ROT13:
+ if (empty_region_error)
+ {
+ vim_beep(BO_OPER);
+ CancelRedo();
+ }
+ else
+ op_tilde(oap);
+ check_cursor_col();
+ break;
+
+ case OP_FORMAT:
+#if defined(FEAT_EVAL)
+ if (*curbuf->b_p_fex != NUL)
+ op_formatexpr(oap); /* use expression */
+ else
+#endif
+ if (*p_fp != NUL || *curbuf->b_p_fp != NUL)
+ op_colon(oap); /* use external command */
+ else
+ op_format(oap, FALSE); /* use internal function */
+ break;
+
+ case OP_FORMAT2:
+ op_format(oap, TRUE); /* use internal function */
+ break;
+
+ case OP_FUNCTION:
+#ifdef FEAT_LINEBREAK
+ /* Restore linebreak, so that when the user edits it looks as
+ * before. */
+ curwin->w_p_lbr = lbr_saved;
+#endif
+ op_function(oap); /* call 'operatorfunc' */
+ break;
+
+ case OP_INSERT:
+ case OP_APPEND:
+ VIsual_reselect = FALSE; /* don't reselect now */
+ if (empty_region_error)
+ {
+ vim_beep(BO_OPER);
+ CancelRedo();
+ }
+ else
+ {
+ /* This is a new edit command, not a restart. Need to
+ * remember it to make 'insertmode' work with mappings for
+ * Visual mode. But do this only once. */
+ restart_edit_save = restart_edit;
+ restart_edit = 0;
+#ifdef FEAT_LINEBREAK
+ /* Restore linebreak, so that when the user edits it looks as
+ * before. */
+ if (curwin->w_p_lbr != lbr_saved)
+ {
+ curwin->w_p_lbr = lbr_saved;
+ get_op_vcol(oap, redo_VIsual_mode, FALSE);
+ }
+#endif
+ op_insert(oap, cap->count1);
+#ifdef FEAT_LINEBREAK
+ /* Reset linebreak, so that formatting works correctly. */
+ curwin->w_p_lbr = FALSE;
+#endif
+
+ /* TODO: when inserting in several lines, should format all
+ * the lines. */
+ auto_format(FALSE, TRUE);
+
+ if (restart_edit == 0)
+ restart_edit = restart_edit_save;
+ else
+ cap->retval |= CA_COMMAND_BUSY;
+ }
+ break;
+
+ case OP_REPLACE:
+ VIsual_reselect = FALSE; /* don't reselect now */
+ if (empty_region_error)
+ {
+ vim_beep(BO_OPER);
+ CancelRedo();
+ }
+ else
+ {
+#ifdef FEAT_LINEBREAK
+ /* Restore linebreak, so that when the user edits it looks as
+ * before. */
+ if (curwin->w_p_lbr != lbr_saved)
+ {
+ curwin->w_p_lbr = lbr_saved;
+ get_op_vcol(oap, redo_VIsual_mode, FALSE);
+ }
+#endif
+ op_replace(oap, cap->nchar);
+ }
+ break;
+
+#ifdef FEAT_FOLDING
+ case OP_FOLD:
+ VIsual_reselect = FALSE; /* don't reselect now */
+ foldCreate(oap->start.lnum, oap->end.lnum);
+ break;
+
+ case OP_FOLDOPEN:
+ case OP_FOLDOPENREC:
+ case OP_FOLDCLOSE:
+ case OP_FOLDCLOSEREC:
+ VIsual_reselect = FALSE; /* don't reselect now */
+ opFoldRange(oap->start.lnum, oap->end.lnum,
+ oap->op_type == OP_FOLDOPEN
+ || oap->op_type == OP_FOLDOPENREC,
+ oap->op_type == OP_FOLDOPENREC
+ || oap->op_type == OP_FOLDCLOSEREC,
+ oap->is_VIsual);
+ break;
+
+ case OP_FOLDDEL:
+ case OP_FOLDDELREC:
+ VIsual_reselect = FALSE; /* don't reselect now */
+ deleteFold(oap->start.lnum, oap->end.lnum,
+ oap->op_type == OP_FOLDDELREC, oap->is_VIsual);
+ break;
+#endif
+ case OP_NR_ADD:
+ case OP_NR_SUB:
+ if (empty_region_error)
+ {
+ vim_beep(BO_OPER);
+ CancelRedo();
+ }
+ else
+ {
+ VIsual_active = TRUE;
+#ifdef FEAT_LINEBREAK
+ curwin->w_p_lbr = lbr_saved;
+#endif
+ op_addsub(oap, cap->count1, redo_VIsual_arg);
+ VIsual_active = FALSE;
+ }
+ check_cursor_col();
+ break;
+ default:
+ clearopbeep(oap);
+ }
+ virtual_op = MAYBE;
+ if (!gui_yank)
+ {
+ /*
+ * if 'sol' not set, go back to old column for some commands
+ */
+ if (!p_sol && oap->motion_type == MLINE && !oap->end_adjusted
+ && (oap->op_type == OP_LSHIFT || oap->op_type == OP_RSHIFT
+ || oap->op_type == OP_DELETE))
+ {
+#ifdef FEAT_LINEBREAK
+ curwin->w_p_lbr = FALSE;
+#endif
+ coladvance(curwin->w_curswant = old_col);
+ }
+ }
+ else
+ {
+ curwin->w_cursor = old_cursor;
+ }
+ oap->block_mode = FALSE;
+ clearop(oap);
+ motion_force = NUL;
+ }
+#ifdef FEAT_LINEBREAK
+ curwin->w_p_lbr = lbr_saved;
+#endif
+}
+
+/*
+ * Handle indent and format operators and visual mode ":".
+ */
+ static void
+op_colon(oparg_T *oap)
+{
+ stuffcharReadbuff(':');
+ if (oap->is_VIsual)
+ stuffReadbuff((char_u *)"'<,'>");
+ else
+ {
+ /*
+ * Make the range look nice, so it can be repeated.
+ */
+ if (oap->start.lnum == curwin->w_cursor.lnum)
+ stuffcharReadbuff('.');
+ else
+ stuffnumReadbuff((long)oap->start.lnum);
+ if (oap->end.lnum != oap->start.lnum)
+ {
+ stuffcharReadbuff(',');
+ if (oap->end.lnum == curwin->w_cursor.lnum)
+ stuffcharReadbuff('.');
+ else if (oap->end.lnum == curbuf->b_ml.ml_line_count)
+ stuffcharReadbuff('$');
+ else if (oap->start.lnum == curwin->w_cursor.lnum)
+ {
+ stuffReadbuff((char_u *)".+");
+ stuffnumReadbuff((long)oap->line_count - 1);
+ }
+ else
+ stuffnumReadbuff((long)oap->end.lnum);
+ }
+ }
+ if (oap->op_type != OP_COLON)
+ stuffReadbuff((char_u *)"!");
+ if (oap->op_type == OP_INDENT)
+ {
+#ifndef FEAT_CINDENT
+ if (*get_equalprg() == NUL)
+ stuffReadbuff((char_u *)"indent");
+ else
+#endif
+ stuffReadbuff(get_equalprg());
+ stuffReadbuff((char_u *)"\n");
+ }
+ else if (oap->op_type == OP_FORMAT)
+ {
+ if (*curbuf->b_p_fp != NUL)
+ stuffReadbuff(curbuf->b_p_fp);
+ else if (*p_fp != NUL)
+ stuffReadbuff(p_fp);
+ else
+ stuffReadbuff((char_u *)"fmt");
+ stuffReadbuff((char_u *)"\n']");
+ }
+
+ /*
+ * do_cmdline() does the rest
+ */
+}
+
+/*
+ * Handle the "g@" operator: call 'operatorfunc'.
+ */
+ static void
+op_function(oparg_T *oap UNUSED)
+{
+#ifdef FEAT_EVAL
+ typval_T argv[2];
+ int save_virtual_op = virtual_op;
+
+ if (*p_opfunc == NUL)
+ emsg(_("E774: 'operatorfunc' is empty"));
+ else
+ {
+ /* Set '[ and '] marks to text to be operated on. */
+ curbuf->b_op_start = oap->start;
+ curbuf->b_op_end = oap->end;
+ if (oap->motion_type != MLINE && !oap->inclusive)
+ /* Exclude the end position. */
+ decl(&curbuf->b_op_end);
+
+ argv[0].v_type = VAR_STRING;
+ if (oap->block_mode)
+ argv[0].vval.v_string = (char_u *)"block";
+ else if (oap->motion_type == MLINE)
+ argv[0].vval.v_string = (char_u *)"line";
+ else
+ argv[0].vval.v_string = (char_u *)"char";
+ argv[1].v_type = VAR_UNKNOWN;
+
+ /* Reset virtual_op so that 'virtualedit' can be changed in the
+ * function. */
+ virtual_op = MAYBE;
+
+ (void)call_func_retnr(p_opfunc, 1, argv);
+
+ virtual_op = save_virtual_op;
+ }
+#else
+ emsg(_("E775: Eval feature not available"));
+#endif
+}
+
+#if defined(FEAT_MOUSE) || defined(PROTO)
+/*
+ * Do the appropriate action for the current mouse click in the current mode.
+ * Not used for Command-line mode.
+ *
+ * Normal and Visual Mode:
+ * event modi- position visual change action
+ * fier cursor window
+ * left press - yes end yes
+ * left press C yes end yes "^]" (2)
+ * left press S yes end (popup: extend) yes "*" (2)
+ * left drag - yes start if moved no
+ * left relse - yes start if moved no
+ * middle press - yes if not active no put register
+ * middle press - yes if active no yank and put
+ * right press - yes start or extend yes
+ * right press S yes no change yes "#" (2)
+ * right drag - yes extend no
+ * right relse - yes extend no
+ *
+ * Insert or Replace Mode:
+ * event modi- position visual change action
+ * fier cursor window
+ * left press - yes (cannot be active) yes
+ * left press C yes (cannot be active) yes "CTRL-O^]" (2)
+ * left press S yes (cannot be active) yes "CTRL-O*" (2)
+ * left drag - yes start or extend (1) no CTRL-O (1)
+ * left relse - yes start or extend (1) no CTRL-O (1)
+ * middle press - no (cannot be active) no put register
+ * right press - yes start or extend yes CTRL-O
+ * right press S yes (cannot be active) yes "CTRL-O#" (2)
+ *
+ * (1) only if mouse pointer moved since press
+ * (2) only if click is in same buffer
+ *
+ * Return TRUE if start_arrow() should be called for edit mode.
+ */
+ int
+do_mouse(
+ oparg_T *oap, /* operator argument, can be NULL */
+ int c, /* K_LEFTMOUSE, etc */
+ int dir, /* Direction to 'put' if necessary */
+ long count,
+ int fixindent) /* PUT_FIXINDENT if fixing indent necessary */
+{
+ static int do_always = FALSE; /* ignore 'mouse' setting next time */
+ static int got_click = FALSE; /* got a click some time back */
+
+ int which_button; /* MOUSE_LEFT, _MIDDLE or _RIGHT */
+ int is_click; /* If FALSE it's a drag or release event */
+ int is_drag; /* If TRUE it's a drag event */
+ int jump_flags = 0; /* flags for jump_to_mouse() */
+ pos_T start_visual;
+ int moved; /* Has cursor moved? */
+ int in_status_line; /* mouse in status line */
+ static int in_tab_line = FALSE; /* mouse clicked in tab line */
+ int in_sep_line; /* mouse in vertical separator line */
+ int c1, c2;
+#if defined(FEAT_FOLDING)
+ pos_T save_cursor;
+#endif
+ win_T *old_curwin = curwin;
+ static pos_T orig_cursor;
+ colnr_T leftcol, rightcol;
+ pos_T end_visual;
+ int diff;
+ int old_active = VIsual_active;
+ int old_mode = VIsual_mode;
+ int regname;
+
+#if defined(FEAT_FOLDING)
+ save_cursor = curwin->w_cursor;
+#endif
+
+ /*
+ * When GUI is active, always recognize mouse events, otherwise:
+ * - Ignore mouse event in normal mode if 'mouse' doesn't include 'n'.
+ * - Ignore mouse event in visual mode if 'mouse' doesn't include 'v'.
+ * - For command line and insert mode 'mouse' is checked before calling
+ * do_mouse().
+ */
+ if (do_always)
+ do_always = FALSE;
+ else
+#ifdef FEAT_GUI
+ if (!gui.in_use)
+#endif
+ {
+ if (VIsual_active)
+ {
+ if (!mouse_has(MOUSE_VISUAL))
+ return FALSE;
+ }
+ else if (State == NORMAL && !mouse_has(MOUSE_NORMAL))
+ return FALSE;
+ }
+
+ for (;;)
+ {
+ which_button = get_mouse_button(KEY2TERMCAP1(c), &is_click, &is_drag);
+ if (is_drag)
+ {
+ /* If the next character is the same mouse event then use that
+ * one. Speeds up dragging the status line. */
+ if (vpeekc() != NUL)
+ {
+ int nc;
+ int save_mouse_row = mouse_row;
+ int save_mouse_col = mouse_col;
+
+ /* Need to get the character, peeking doesn't get the actual
+ * one. */
+ nc = safe_vgetc();
+ if (c == nc)
+ continue;
+ vungetc(nc);
+ mouse_row = save_mouse_row;
+ mouse_col = save_mouse_col;
+ }
+ }
+ break;
+ }
+
+ if (c == K_MOUSEMOVE)
+ {
+ /* Mouse moved without a button pressed. */
+#ifdef FEAT_BEVAL_TERM
+ ui_may_remove_balloon();
+ if (p_bevalterm && !VIsual_active)
+ {
+ profile_setlimit(p_bdlay, &bevalexpr_due);
+ bevalexpr_due_set = TRUE;
+ }
+#endif
+ return FALSE;
+ }
+
+#ifdef FEAT_MOUSESHAPE
+ /* May have stopped dragging the status or separator line. The pointer is
+ * most likely still on the status or separator line. */
+ if (!is_drag && drag_status_line)
+ {
+ drag_status_line = FALSE;
+ update_mouseshape(SHAPE_IDX_STATUS);
+ }
+ if (!is_drag && drag_sep_line)
+ {
+ drag_sep_line = FALSE;
+ update_mouseshape(SHAPE_IDX_VSEP);
+ }
+#endif
+
+ /*
+ * Ignore drag and release events if we didn't get a click.
+ */
+ if (is_click)
+ got_click = TRUE;
+ else
+ {
+ if (!got_click) /* didn't get click, ignore */
+ return FALSE;
+ if (!is_drag) /* release, reset got_click */
+ {
+ got_click = FALSE;
+ if (in_tab_line)
+ {
+ in_tab_line = FALSE;
+ return FALSE;
+ }
+ }
+ }
+
+ /*
+ * CTRL right mouse button does CTRL-T
+ */
+ if (is_click && (mod_mask & MOD_MASK_CTRL) && which_button == MOUSE_RIGHT)
+ {
+ if (State & INSERT)
+ stuffcharReadbuff(Ctrl_O);
+ if (count > 1)
+ stuffnumReadbuff(count);
+ stuffcharReadbuff(Ctrl_T);
+ got_click = FALSE; /* ignore drag&release now */
+ return FALSE;
+ }
+
+ /*
+ * CTRL only works with left mouse button
+ */
+ if ((mod_mask & MOD_MASK_CTRL) && which_button != MOUSE_LEFT)
+ return FALSE;
+
+ /*
+ * When a modifier is down, ignore drag and release events, as well as
+ * multiple clicks and the middle mouse button.
+ * Accept shift-leftmouse drags when 'mousemodel' is "popup.*".
+ */
+ if ((mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL | MOD_MASK_ALT
+ | MOD_MASK_META))
+ && (!is_click
+ || (mod_mask & MOD_MASK_MULTI_CLICK)
+ || which_button == MOUSE_MIDDLE)
+ && !((mod_mask & (MOD_MASK_SHIFT|MOD_MASK_ALT))
+ && mouse_model_popup()
+ && which_button == MOUSE_LEFT)
+ && !((mod_mask & MOD_MASK_ALT)
+ && !mouse_model_popup()
+ && which_button == MOUSE_RIGHT)
+ )
+ return FALSE;
+
+ /*
+ * If the button press was used as the movement command for an operator
+ * (eg "d<MOUSE>"), or it is the middle button that is held down, ignore
+ * drag/release events.
+ */
+ if (!is_click && which_button == MOUSE_MIDDLE)
+ return FALSE;
+
+ if (oap != NULL)
+ regname = oap->regname;
+ else
+ regname = 0;
+
+ /*
+ * Middle mouse button does a 'put' of the selected text
+ */
+ if (which_button == MOUSE_MIDDLE)
+ {
+ if (State == NORMAL)
+ {
+ /*
+ * If an operator was pending, we don't know what the user wanted
+ * to do. Go back to normal mode: Clear the operator and beep().
+ */
+ if (oap != NULL && oap->op_type != OP_NOP)
+ {
+ clearopbeep(oap);
+ return FALSE;
+ }
+
+ /*
+ * If visual was active, yank the highlighted text and put it
+ * before the mouse pointer position.
+ * In Select mode replace the highlighted text with the clipboard.
+ */
+ if (VIsual_active)
+ {
+ if (VIsual_select)
+ {
+ stuffcharReadbuff(Ctrl_G);
+ stuffReadbuff((char_u *)"\"+p");
+ }
+ else
+ {
+ stuffcharReadbuff('y');
+ stuffcharReadbuff(K_MIDDLEMOUSE);
+ }
+ do_always = TRUE; /* ignore 'mouse' setting next time */
+ return FALSE;
+ }
+ /*
+ * The rest is below jump_to_mouse()
+ */
+ }
+
+ else if ((State & INSERT) == 0)
+ return FALSE;
+
+ /*
+ * Middle click in insert mode doesn't move the mouse, just insert the
+ * contents of a register. '.' register is special, can't insert that
+ * with do_put().
+ * Also paste at the cursor if the current mode isn't in 'mouse' (only
+ * happens for the GUI).
+ */
+ if ((State & INSERT) || !mouse_has(MOUSE_NORMAL))
+ {
+ if (regname == '.')
+ insert_reg(regname, TRUE);
+ else
+ {
+#ifdef FEAT_CLIPBOARD
+ if (clip_star.available && regname == 0)
+ regname = '*';
+#endif
+ if ((State & REPLACE_FLAG) && !yank_register_mline(regname))
+ insert_reg(regname, TRUE);
+ else
+ {
+ do_put(regname, BACKWARD, 1L, fixindent | PUT_CURSEND);
+
+ /* Repeat it with CTRL-R CTRL-O r or CTRL-R CTRL-P r */
+ AppendCharToRedobuff(Ctrl_R);
+ AppendCharToRedobuff(fixindent ? Ctrl_P : Ctrl_O);
+ AppendCharToRedobuff(regname == 0 ? '"' : regname);
+ }
+ }
+ return FALSE;
+ }
+ }
+
+ /* When dragging or button-up stay in the same window. */
+ if (!is_click)
+ jump_flags |= MOUSE_FOCUS | MOUSE_DID_MOVE;
+
+ start_visual.lnum = 0;
+
+ /* Check for clicking in the tab page line. */
+ if (mouse_row == 0 && firstwin->w_winrow > 0)
+ {
+ if (is_drag)
+ {
+ if (in_tab_line)
+ {
+ c1 = TabPageIdxs[mouse_col];
+ tabpage_move(c1 <= 0 ? 9999 : c1 < tabpage_index(curtab)
+ ? c1 - 1 : c1);
+ }
+ return FALSE;
+ }
+
+ /* click in a tab selects that tab page */
+ if (is_click
+# ifdef FEAT_CMDWIN
+ && cmdwin_type == 0
+# endif
+ && mouse_col < Columns)
+ {
+ in_tab_line = TRUE;
+ c1 = TabPageIdxs[mouse_col];
+ if (c1 >= 0)
+ {
+ if ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK)
+ {
+ /* double click opens new page */
+ end_visual_mode();
+ tabpage_new();
+ tabpage_move(c1 == 0 ? 9999 : c1 - 1);
+ }
+ else
+ {
+ /* Go to specified tab page, or next one if not clicking
+ * on a label. */
+ goto_tabpage(c1);
+
+ /* It's like clicking on the status line of a window. */
+ if (curwin != old_curwin)
+ end_visual_mode();
+ }
+ }
+ else
+ {
+ tabpage_T *tp;
+
+ /* Close the current or specified tab page. */
+ if (c1 == -999)
+ tp = curtab;
+ else
+ tp = find_tabpage(-c1);
+ if (tp == curtab)
+ {
+ if (first_tabpage->tp_next != NULL)
+ tabpage_close(FALSE);
+ }
+ else if (tp != NULL)
+ tabpage_close_other(tp, FALSE);
+ }
+ }
+ return TRUE;
+ }
+ else if (is_drag && in_tab_line)
+ {
+ c1 = TabPageIdxs[mouse_col];
+ tabpage_move(c1 <= 0 ? 9999 : c1 - 1);
+ return FALSE;
+ }
+
+ /*
+ * When 'mousemodel' is "popup" or "popup_setpos", translate mouse events:
+ * right button up -> pop-up menu
+ * shift-left button -> right button
+ * alt-left button -> alt-right button
+ */
+ if (mouse_model_popup())
+ {
+ if (which_button == MOUSE_RIGHT
+ && !(mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL)))
+ {
+#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)
+# ifdef FEAT_GUI
+ if (gui.in_use)
+ {
+# if defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_GTK) \
+ || defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC)
+ if (!is_click)
+ /* Ignore right button release events, only shows the popup
+ * menu on the button down event. */
+ return FALSE;
+# endif
+# if defined(FEAT_GUI_ATHENA) || defined(FEAT_GUI_MSWIN)
+ if (is_click || is_drag)
+ /* Ignore right button down and drag mouse events. Windows
+ * only shows the popup menu on the button up event. */
+ return FALSE;
+# endif
+ }
+# endif
+# if defined(FEAT_GUI) && defined(FEAT_TERM_POPUP_MENU)
+ else
+# endif
+# if defined(FEAT_TERM_POPUP_MENU)
+ if (!is_click)
+ /* Ignore right button release events, only shows the popup
+ * menu on the button down event. */
+ return FALSE;
+#endif
+
+ jump_flags = 0;
+ if (STRCMP(p_mousem, "popup_setpos") == 0)
+ {
+ /* First set the cursor position before showing the popup
+ * menu. */
+ if (VIsual_active)
+ {
+ pos_T m_pos;
+
+ /*
+ * set MOUSE_MAY_STOP_VIS if we are outside the
+ * selection or the current window (might have false
+ * negative here)
+ */
+ if (mouse_row < curwin->w_winrow
+ || mouse_row
+ > (curwin->w_winrow + curwin->w_height))
+ jump_flags = MOUSE_MAY_STOP_VIS;
+ else if (get_fpos_of_mouse(&m_pos) != IN_BUFFER)
+ jump_flags = MOUSE_MAY_STOP_VIS;
+ else
+ {
+ if ((LT_POS(curwin->w_cursor, VIsual)
+ && (LT_POS(m_pos, curwin->w_cursor)
+ || LT_POS(VIsual, m_pos)))
+ || (LT_POS(VIsual, curwin->w_cursor)
+ && (LT_POS(m_pos, VIsual)
+ || LT_POS(curwin->w_cursor, m_pos))))
+ {
+ jump_flags = MOUSE_MAY_STOP_VIS;
+ }
+ else if (VIsual_mode == Ctrl_V)
+ {
+ getvcols(curwin, &curwin->w_cursor, &VIsual,
+ &leftcol, &rightcol);
+ getvcol(curwin, &m_pos, NULL, &m_pos.col, NULL);
+ if (m_pos.col < leftcol || m_pos.col > rightcol)
+ jump_flags = MOUSE_MAY_STOP_VIS;
+ }
+ }
+ }
+ else
+ jump_flags = MOUSE_MAY_STOP_VIS;
+ }
+ if (jump_flags)
+ {
+ jump_flags = jump_to_mouse(jump_flags, NULL, which_button);
+ update_curbuf(VIsual_active ? INVERTED : VALID);
+ setcursor();
+ out_flush(); /* Update before showing popup menu */
+ }
+# ifdef FEAT_MENU
+ show_popupmenu();
+ got_click = FALSE; /* ignore release events */
+# endif
+ return (jump_flags & CURSOR_MOVED) != 0;
+#else
+ return FALSE;
+#endif
+ }
+ if (which_button == MOUSE_LEFT
+ && (mod_mask & (MOD_MASK_SHIFT|MOD_MASK_ALT)))
+ {
+ which_button = MOUSE_RIGHT;
+ mod_mask &= ~MOD_MASK_SHIFT;
+ }
+ }
+
+ if ((State & (NORMAL | INSERT))
+ && !(mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL)))
+ {
+ if (which_button == MOUSE_LEFT)
+ {
+ if (is_click)
+ {
+ /* stop Visual mode for a left click in a window, but not when
+ * on a status line */
+ if (VIsual_active)
+ jump_flags |= MOUSE_MAY_STOP_VIS;
+ }
+ else if (mouse_has(MOUSE_VISUAL))
+ jump_flags |= MOUSE_MAY_VIS;
+ }
+ else if (which_button == MOUSE_RIGHT)
+ {
+ if (is_click && VIsual_active)
+ {
+ /*
+ * Remember the start and end of visual before moving the
+ * cursor.
+ */
+ if (LT_POS(curwin->w_cursor, VIsual))
+ {
+ start_visual = curwin->w_cursor;
+ end_visual = VIsual;
+ }
+ else
+ {
+ start_visual = VIsual;
+ end_visual = curwin->w_cursor;
+ }
+ }
+ jump_flags |= MOUSE_FOCUS;
+ if (mouse_has(MOUSE_VISUAL))
+ jump_flags |= MOUSE_MAY_VIS;
+ }
+ }
+
+ /*
+ * If an operator is pending, ignore all drags and releases until the
+ * next mouse click.
+ */
+ if (!is_drag && oap != NULL && oap->op_type != OP_NOP)
+ {
+ got_click = FALSE;
+ oap->motion_type = MCHAR;
+ }
+
+ /* When releasing the button let jump_to_mouse() know. */
+ if (!is_click && !is_drag)
+ jump_flags |= MOUSE_RELEASED;
+
+ /*
+ * JUMP!
+ */
+ jump_flags = jump_to_mouse(jump_flags,
+ oap == NULL ? NULL : &(oap->inclusive), which_button);
+
+#ifdef FEAT_MENU
+ /* A click in the window toolbar has no side effects. */
+ if (jump_flags & MOUSE_WINBAR)
+ return FALSE;
+#endif
+ moved = (jump_flags & CURSOR_MOVED);
+ in_status_line = (jump_flags & IN_STATUS_LINE);
+ in_sep_line = (jump_flags & IN_SEP_LINE);
+
+#ifdef FEAT_NETBEANS_INTG
+ if (isNetbeansBuffer(curbuf)
+ && !(jump_flags & (IN_STATUS_LINE | IN_SEP_LINE)))
+ {
+ int key = KEY2TERMCAP1(c);
+
+ if (key == (int)KE_LEFTRELEASE || key == (int)KE_MIDDLERELEASE
+ || key == (int)KE_RIGHTRELEASE)
+ netbeans_button_release(which_button);
+ }
+#endif
+
+ /* When jumping to another window, clear a pending operator. That's a bit
+ * friendlier than beeping and not jumping to that window. */
+ if (curwin != old_curwin && oap != NULL && oap->op_type != OP_NOP)
+ clearop(oap);
+
+#ifdef FEAT_FOLDING
+ if (mod_mask == 0
+ && !is_drag
+ && (jump_flags & (MOUSE_FOLD_CLOSE | MOUSE_FOLD_OPEN))
+ && which_button == MOUSE_LEFT)
+ {
+ /* open or close a fold at this line */
+ if (jump_flags & MOUSE_FOLD_OPEN)
+ openFold(curwin->w_cursor.lnum, 1L);
+ else
+ closeFold(curwin->w_cursor.lnum, 1L);
+ /* don't move the cursor if still in the same window */
+ if (curwin == old_curwin)
+ curwin->w_cursor = save_cursor;
+ }
+#endif
+
+#if defined(FEAT_CLIPBOARD) && defined(FEAT_CMDWIN)
+ if ((jump_flags & IN_OTHER_WIN) && !VIsual_active && clip_star.available)
+ {
+ clip_modeless(which_button, is_click, is_drag);
+ return FALSE;
+ }
+#endif
+
+ /* Set global flag that we are extending the Visual area with mouse
+ * dragging; temporarily minimize 'scrolloff'. */
+ if (VIsual_active && is_drag && get_scrolloff_value())
+ {
+ /* In the very first line, allow scrolling one line */
+ if (mouse_row == 0)
+ mouse_dragging = 2;
+ else
+ mouse_dragging = 1;
+ }
+
+ /* When dragging the mouse above the window, scroll down. */
+ if (is_drag && mouse_row < 0 && !in_status_line)
+ {
+ scroll_redraw(FALSE, 1L);
+ mouse_row = 0;
+ }
+
+ if (start_visual.lnum) /* right click in visual mode */
+ {
+ /* When ALT is pressed make Visual mode blockwise. */
+ if (mod_mask & MOD_MASK_ALT)
+ VIsual_mode = Ctrl_V;
+
+ /*
+ * In Visual-block mode, divide the area in four, pick up the corner
+ * that is in the quarter that the cursor is in.
+ */
+ if (VIsual_mode == Ctrl_V)
+ {
+ getvcols(curwin, &start_visual, &end_visual, &leftcol, &rightcol);
+ if (curwin->w_curswant > (leftcol + rightcol) / 2)
+ end_visual.col = leftcol;
+ else
+ end_visual.col = rightcol;
+ if (curwin->w_cursor.lnum >=
+ (start_visual.lnum + end_visual.lnum) / 2)
+ end_visual.lnum = start_visual.lnum;
+
+ /* move VIsual to the right column */
+ start_visual = curwin->w_cursor; /* save the cursor pos */
+ curwin->w_cursor = end_visual;
+ coladvance(end_visual.col);
+ VIsual = curwin->w_cursor;
+ curwin->w_cursor = start_visual; /* restore the cursor */
+ }
+ else
+ {
+ /*
+ * If the click is before the start of visual, change the start.
+ * If the click is after the end of visual, change the end. If
+ * the click is inside the visual, change the closest side.
+ */
+ if (LT_POS(curwin->w_cursor, start_visual))
+ VIsual = end_visual;
+ else if (LT_POS(end_visual, curwin->w_cursor))
+ VIsual = start_visual;
+ else
+ {
+ /* In the same line, compare column number */
+ if (end_visual.lnum == start_visual.lnum)
+ {
+ if (curwin->w_cursor.col - start_visual.col >
+ end_visual.col - curwin->w_cursor.col)
+ VIsual = start_visual;
+ else
+ VIsual = end_visual;
+ }
+
+ /* In different lines, compare line number */
+ else
+ {
+ diff = (curwin->w_cursor.lnum - start_visual.lnum) -
+ (end_visual.lnum - curwin->w_cursor.lnum);
+
+ if (diff > 0) /* closest to end */
+ VIsual = start_visual;
+ else if (diff < 0) /* closest to start */
+ VIsual = end_visual;
+ else /* in the middle line */
+ {
+ if (curwin->w_cursor.col <
+ (start_visual.col + end_visual.col) / 2)
+ VIsual = end_visual;
+ else
+ VIsual = start_visual;
+ }
+ }
+ }
+ }
+ }
+ /*
+ * If Visual mode started in insert mode, execute "CTRL-O"
+ */
+ else if ((State & INSERT) && VIsual_active)
+ stuffcharReadbuff(Ctrl_O);
+
+ /*
+ * Middle mouse click: Put text before cursor.
+ */
+ if (which_button == MOUSE_MIDDLE)
+ {
+#ifdef FEAT_CLIPBOARD
+ if (clip_star.available && regname == 0)
+ regname = '*';
+#endif
+ if (yank_register_mline(regname))
+ {
+ if (mouse_past_bottom)
+ dir = FORWARD;
+ }
+ else if (mouse_past_eol)
+ dir = FORWARD;
+
+ if (fixindent)
+ {
+ c1 = (dir == BACKWARD) ? '[' : ']';
+ c2 = 'p';
+ }
+ else
+ {
+ c1 = (dir == FORWARD) ? 'p' : 'P';
+ c2 = NUL;
+ }
+ prep_redo(regname, count, NUL, c1, NUL, c2, NUL);
+
+ /*
+ * Remember where the paste started, so in edit() Insstart can be set
+ * to this position
+ */
+ if (restart_edit != 0)
+ where_paste_started = curwin->w_cursor;
+ do_put(regname, dir, count, fixindent | PUT_CURSEND);
+ }
+
+#if defined(FEAT_QUICKFIX)
+ /*
+ * Ctrl-Mouse click or double click in a quickfix window jumps to the
+ * error under the mouse pointer.
+ */
+ else if (((mod_mask & MOD_MASK_CTRL)
+ || (mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK)
+ && bt_quickfix(curbuf))
+ {
+ if (curwin->w_llist_ref == NULL) /* quickfix window */
+ do_cmdline_cmd((char_u *)".cc");
+ else /* location list window */
+ do_cmdline_cmd((char_u *)".ll");
+ got_click = FALSE; /* ignore drag&release now */
+ }
+#endif
+
+ /*
+ * Ctrl-Mouse click (or double click in a help window) jumps to the tag
+ * under the mouse pointer.
+ */
+ else if ((mod_mask & MOD_MASK_CTRL) || (curbuf->b_help
+ && (mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK))
+ {
+ if (State & INSERT)
+ stuffcharReadbuff(Ctrl_O);
+ stuffcharReadbuff(Ctrl_RSB);
+ got_click = FALSE; /* ignore drag&release now */
+ }
+
+ /*
+ * Shift-Mouse click searches for the next occurrence of the word under
+ * the mouse pointer
+ */
+ else if ((mod_mask & MOD_MASK_SHIFT))
+ {
+ if ((State & INSERT) || (VIsual_active && VIsual_select))
+ stuffcharReadbuff(Ctrl_O);
+ if (which_button == MOUSE_LEFT)
+ stuffcharReadbuff('*');
+ else /* MOUSE_RIGHT */
+ stuffcharReadbuff('#');
+ }
+
+ /* Handle double clicks, unless on status line */
+ else if (in_status_line)
+ {
+#ifdef FEAT_MOUSESHAPE
+ if ((is_drag || is_click) && !drag_status_line)
+ {
+ drag_status_line = TRUE;
+ update_mouseshape(-1);
+ }
+#endif
+ }
+ else if (in_sep_line)
+ {
+#ifdef FEAT_MOUSESHAPE
+ if ((is_drag || is_click) && !drag_sep_line)
+ {
+ drag_sep_line = TRUE;
+ update_mouseshape(-1);
+ }
+#endif
+ }
+ else if ((mod_mask & MOD_MASK_MULTI_CLICK) && (State & (NORMAL | INSERT))
+ && mouse_has(MOUSE_VISUAL))
+ {
+ if (is_click || !VIsual_active)
+ {
+ if (VIsual_active)
+ orig_cursor = VIsual;
+ else
+ {
+ check_visual_highlight();
+ VIsual = curwin->w_cursor;
+ orig_cursor = VIsual;
+ VIsual_active = TRUE;
+ VIsual_reselect = TRUE;
+ /* start Select mode if 'selectmode' contains "mouse" */
+ may_start_select('o');
+ setmouse();
+ }
+ if ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK)
+ {
+ /* Double click with ALT pressed makes it blockwise. */
+ if (mod_mask & MOD_MASK_ALT)
+ VIsual_mode = Ctrl_V;
+ else
+ VIsual_mode = 'v';
+ }
+ else if ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_3CLICK)
+ VIsual_mode = 'V';
+ else if ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_4CLICK)
+ VIsual_mode = Ctrl_V;
+#ifdef FEAT_CLIPBOARD
+ /* Make sure the clipboard gets updated. Needed because start and
+ * end may still be the same, and the selection needs to be owned */
+ clip_star.vmode = NUL;
+#endif
+ }
+ /*
+ * A double click selects a word or a block.
+ */
+ if ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK)
+ {
+ pos_T *pos = NULL;
+ int gc;
+
+ if (is_click)
+ {
+ /* If the character under the cursor (skipping white space) is
+ * not a word character, try finding a match and select a (),
+ * {}, [], #if/#endif, etc. block. */
+ end_visual = curwin->w_cursor;
+ while (gc = gchar_pos(&end_visual), VIM_ISWHITE(gc))
+ inc(&end_visual);
+ if (oap != NULL)
+ oap->motion_type = MCHAR;
+ if (oap != NULL
+ && VIsual_mode == 'v'
+ && !vim_iswordc(gchar_pos(&end_visual))
+ && EQUAL_POS(curwin->w_cursor, VIsual)
+ && (pos = findmatch(oap, NUL)) != NULL)
+ {
+ curwin->w_cursor = *pos;
+ if (oap->motion_type == MLINE)
+ VIsual_mode = 'V';
+ else if (*p_sel == 'e')
+ {
+ if (LT_POS(curwin->w_cursor, VIsual))
+ ++VIsual.col;
+ else
+ ++curwin->w_cursor.col;
+ }
+ }
+ }
+
+ if (pos == NULL && (is_click || is_drag))
+ {
+ /* When not found a match or when dragging: extend to include
+ * a word. */
+ if (LT_POS(curwin->w_cursor, orig_cursor))
+ {
+ find_start_of_word(&curwin->w_cursor);
+ find_end_of_word(&VIsual);
+ }
+ else
+ {
+ find_start_of_word(&VIsual);
+ if (*p_sel == 'e' && *ml_get_cursor() != NUL)
+ curwin->w_cursor.col +=
+ (*mb_ptr2len)(ml_get_cursor());
+ find_end_of_word(&curwin->w_cursor);
+ }
+ }
+ curwin->w_set_curswant = TRUE;
+ }
+ if (is_click)
+ redraw_curbuf_later(INVERTED); /* update the inversion */
+ }
+ else if (VIsual_active && !old_active)
+ {
+ if (mod_mask & MOD_MASK_ALT)
+ VIsual_mode = Ctrl_V;
+ else
+ VIsual_mode = 'v';
+ }
+
+ /* If Visual mode changed show it later. */
+ if ((!VIsual_active && old_active && mode_displayed)
+ || (VIsual_active && p_smd && msg_silent == 0
+ && (!old_active || VIsual_mode != old_mode)))
+ redraw_cmdline = TRUE;
+
+ return moved;
+}
+
+/*
+ * Move "pos" back to the start of the word it's in.
+ */
+ static void
+find_start_of_word(pos_T *pos)
+{
+ char_u *line;
+ int cclass;
+ int col;
+
+ line = ml_get(pos->lnum);
+ cclass = get_mouse_class(line + pos->col);
+
+ while (pos->col > 0)
+ {
+ col = pos->col - 1;
+ col -= (*mb_head_off)(line, line + col);
+ if (get_mouse_class(line + col) != cclass)
+ break;
+ pos->col = col;
+ }
+}
+
+/*
+ * Move "pos" forward to the end of the word it's in.
+ * When 'selection' is "exclusive", the position is just after the word.
+ */
+ static void
+find_end_of_word(pos_T *pos)
+{
+ char_u *line;
+ int cclass;
+ int col;
+
+ line = ml_get(pos->lnum);
+ if (*p_sel == 'e' && pos->col > 0)
+ {
+ --pos->col;
+ pos->col -= (*mb_head_off)(line, line + pos->col);
+ }
+ cclass = get_mouse_class(line + pos->col);
+ while (line[pos->col] != NUL)
+ {
+ col = pos->col + (*mb_ptr2len)(line + pos->col);
+ if (get_mouse_class(line + col) != cclass)
+ {
+ if (*p_sel == 'e')
+ pos->col = col;
+ break;
+ }
+ pos->col = col;
+ }
+}
+
+/*
+ * Get class of a character for selection: same class means same word.
+ * 0: blank
+ * 1: punctuation groups
+ * 2: normal word character
+ * >2: multi-byte word character.
+ */
+ static int
+get_mouse_class(char_u *p)
+{
+ int c;
+
+ if (has_mbyte && MB_BYTE2LEN(p[0]) > 1)
+ return mb_get_class(p);
+
+ c = *p;
+ if (c == ' ' || c == '\t')
+ return 0;
+
+ if (vim_iswordc(c))
+ return 2;
+
+ /*
+ * There are a few special cases where we want certain combinations of
+ * characters to be considered as a single word. These are things like
+ * "->", "/ *", "*=", "+=", "&=", "<=", ">=", "!=" etc. Otherwise, each
+ * character is in its own class.
+ */
+ if (c != NUL && vim_strchr((char_u *)"-+*/%<>&|^!=", c) != NULL)
+ return 1;
+ return c;
+}
+#endif /* FEAT_MOUSE */
+
+/*
+ * Check if highlighting for visual mode is possible, give a warning message
+ * if not.
+ */
+ void
+check_visual_highlight(void)
+{
+ static int did_check = FALSE;
+
+ if (full_screen)
+ {
+ if (!did_check && HL_ATTR(HLF_V) == 0)
+ msg(_("Warning: terminal cannot highlight"));
+ did_check = TRUE;
+ }
+}
+
+/*
+ * End Visual mode.
+ * This function should ALWAYS be called to end Visual mode, except from
+ * do_pending_operator().
+ */
+ void
+end_visual_mode(void)
+{
+#ifdef FEAT_CLIPBOARD
+ /*
+ * If we are using the clipboard, then remember what was selected in case
+ * we need to paste it somewhere while we still own the selection.
+ * Only do this when the clipboard is already owned. Don't want to grab
+ * the selection when hitting ESC.
+ */
+ if (clip_star.available && clip_star.owned)
+ clip_auto_select();
+#endif
+
+ VIsual_active = FALSE;
+#ifdef FEAT_MOUSE
+ setmouse();
+ mouse_dragging = 0;
+#endif
+
+ /* Save the current VIsual area for '< and '> marks, and "gv" */
+ curbuf->b_visual.vi_mode = VIsual_mode;
+ curbuf->b_visual.vi_start = VIsual;
+ curbuf->b_visual.vi_end = curwin->w_cursor;
+ curbuf->b_visual.vi_curswant = curwin->w_curswant;
+#ifdef FEAT_EVAL
+ curbuf->b_visual_mode_eval = VIsual_mode;
+#endif
+ if (!virtual_active())
+ curwin->w_cursor.coladd = 0;
+ may_clear_cmdline();
+
+ adjust_cursor_eol();
+}
+
+/*
+ * Reset VIsual_active and VIsual_reselect.
+ */
+ void
+reset_VIsual_and_resel(void)
+{
+ if (VIsual_active)
+ {
+ end_visual_mode();
+ redraw_curbuf_later(INVERTED); /* delete the inversion later */
+ }
+ VIsual_reselect = FALSE;
+}
+
+/*
+ * Reset VIsual_active and VIsual_reselect if it's set.
+ */
+ void
+reset_VIsual(void)
+{
+ if (VIsual_active)
+ {
+ end_visual_mode();
+ redraw_curbuf_later(INVERTED); /* delete the inversion later */
+ VIsual_reselect = FALSE;
+ }
+}
+
+/*
+ * Check for a balloon-eval special item to include when searching for an
+ * identifier. When "dir" is BACKWARD "ptr[-1]" must be valid!
+ * Returns TRUE if the character at "*ptr" should be included.
+ * "dir" is FORWARD or BACKWARD, the direction of searching.
+ * "*colp" is in/decremented if "ptr[-dir]" should also be included.
+ * "bnp" points to a counter for square brackets.
+ */
+ static int
+find_is_eval_item(
+ char_u *ptr,
+ int *colp,
+ int *bnp,
+ int dir)
+{
+ /* Accept everything inside []. */
+ if ((*ptr == ']' && dir == BACKWARD) || (*ptr == '[' && dir == FORWARD))
+ ++*bnp;
+ if (*bnp > 0)
+ {
+ if ((*ptr == '[' && dir == BACKWARD) || (*ptr == ']' && dir == FORWARD))
+ --*bnp;
+ return TRUE;
+ }
+
+ /* skip over "s.var" */
+ if (*ptr == '.')
+ return TRUE;
+
+ /* two-character item: s->var */
+ if (ptr[dir == BACKWARD ? 0 : 1] == '>'
+ && ptr[dir == BACKWARD ? -1 : 0] == '-')
+ {
+ *colp += dir;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * Find the identifier under or to the right of the cursor.
+ * "find_type" can have one of three values:
+ * FIND_IDENT: find an identifier (keyword)
+ * FIND_STRING: find any non-white string
+ * FIND_IDENT + FIND_STRING: find any non-white string, identifier preferred.
+ * FIND_EVAL: find text useful for C program debugging
+ *
+ * There are three steps:
+ * 1. Search forward for the start of an identifier/string. Doesn't move if
+ * already on one.
+ * 2. Search backward for the start of this identifier/string.
+ * This doesn't match the real Vi but I like it a little better and it
+ * shouldn't bother anyone.
+ * 3. Search forward to the end of this identifier/string.
+ * When FIND_IDENT isn't defined, we backup until a blank.
+ *
+ * Returns the length of the string, or zero if no string is found.
+ * If a string is found, a pointer to the string is put in "*string". This
+ * string is not always NUL terminated.
+ */
+ int
+find_ident_under_cursor(char_u **string, int find_type)
+{
+ return find_ident_at_pos(curwin, curwin->w_cursor.lnum,
+ curwin->w_cursor.col, string, find_type);
+}
+
+/*
+ * Like find_ident_under_cursor(), but for any window and any position.
+ * However: Uses 'iskeyword' from the current window!.
+ */
+ int
+find_ident_at_pos(
+ win_T *wp,
+ linenr_T lnum,
+ colnr_T startcol,
+ char_u **string,
+ int find_type)
+{
+ char_u *ptr;
+ int col = 0; /* init to shut up GCC */
+ int i;
+ int this_class = 0;
+ int prev_class;
+ int prevcol;
+ int bn = 0; /* bracket nesting */
+
+ /*
+ * if i == 0: try to find an identifier
+ * if i == 1: try to find any non-white string
+ */
+ ptr = ml_get_buf(wp->w_buffer, lnum, FALSE);
+ for (i = (find_type & FIND_IDENT) ? 0 : 1; i < 2; ++i)
+ {
+ /*
+ * 1. skip to start of identifier/string
+ */
+ col = startcol;
+ if (has_mbyte)
+ {
+ while (ptr[col] != NUL)
+ {
+ /* Stop at a ']' to evaluate "a[x]". */
+ if ((find_type & FIND_EVAL) && ptr[col] == ']')
+ break;
+ this_class = mb_get_class(ptr + col);
+ if (this_class != 0 && (i == 1 || this_class != 1))
+ break;
+ col += (*mb_ptr2len)(ptr + col);
+ }
+ }
+ else
+ while (ptr[col] != NUL
+ && (i == 0 ? !vim_iswordc(ptr[col]) : VIM_ISWHITE(ptr[col]))
+ && (!(find_type & FIND_EVAL) || ptr[col] != ']')
+ )
+ ++col;
+
+ /* When starting on a ']' count it, so that we include the '['. */
+ bn = ptr[col] == ']';
+
+ /*
+ * 2. Back up to start of identifier/string.
+ */
+ if (has_mbyte)
+ {
+ /* Remember class of character under cursor. */
+ if ((find_type & FIND_EVAL) && ptr[col] == ']')
+ this_class = mb_get_class((char_u *)"a");
+ else
+ this_class = mb_get_class(ptr + col);
+ while (col > 0 && this_class != 0)
+ {
+ prevcol = col - 1 - (*mb_head_off)(ptr, ptr + col - 1);
+ prev_class = mb_get_class(ptr + prevcol);
+ if (this_class != prev_class
+ && (i == 0
+ || prev_class == 0
+ || (find_type & FIND_IDENT))
+ && (!(find_type & FIND_EVAL)
+ || prevcol == 0
+ || !find_is_eval_item(ptr + prevcol, &prevcol,
+ &bn, BACKWARD))
+ )
+ break;
+ col = prevcol;
+ }
+
+ /* If we don't want just any old string, or we've found an
+ * identifier, stop searching. */
+ if (this_class > 2)
+ this_class = 2;
+ if (!(find_type & FIND_STRING) || this_class == 2)
+ break;
+ }
+ else
+ {
+ while (col > 0
+ && ((i == 0
+ ? vim_iswordc(ptr[col - 1])
+ : (!VIM_ISWHITE(ptr[col - 1])
+ && (!(find_type & FIND_IDENT)
+ || !vim_iswordc(ptr[col - 1]))))
+ || ((find_type & FIND_EVAL)
+ && col > 1
+ && find_is_eval_item(ptr + col - 1, &col,
+ &bn, BACKWARD))
+ ))
+ --col;
+
+ /* If we don't want just any old string, or we've found an
+ * identifier, stop searching. */
+ if (!(find_type & FIND_STRING) || vim_iswordc(ptr[col]))
+ break;
+ }
+ }
+
+ if (ptr[col] == NUL || (i == 0
+ && (has_mbyte ? this_class != 2 : !vim_iswordc(ptr[col]))))
+ {
+ /*
+ * didn't find an identifier or string
+ */
+ if (find_type & FIND_STRING)
+ emsg(_("E348: No string under cursor"));
+ else
+ emsg(_(e_noident));
+ return 0;
+ }
+ ptr += col;
+ *string = ptr;
+
+ /*
+ * 3. Find the end if the identifier/string.
+ */
+ bn = 0;
+ startcol -= col;
+ col = 0;
+ if (has_mbyte)
+ {
+ /* Search for point of changing multibyte character class. */
+ this_class = mb_get_class(ptr);
+ while (ptr[col] != NUL
+ && ((i == 0 ? mb_get_class(ptr + col) == this_class
+ : mb_get_class(ptr + col) != 0)
+ || ((find_type & FIND_EVAL)
+ && col <= (int)startcol
+ && find_is_eval_item(ptr + col, &col, &bn, FORWARD))
+ ))
+ col += (*mb_ptr2len)(ptr + col);
+ }
+ else
+ while ((i == 0 ? vim_iswordc(ptr[col])
+ : (ptr[col] != NUL && !VIM_ISWHITE(ptr[col])))
+ || ((find_type & FIND_EVAL)
+ && col <= (int)startcol
+ && find_is_eval_item(ptr + col, &col, &bn, FORWARD))
+ )
+ {
+ ++col;
+ }
+
+ return col;
+}
+
+/*
+ * Prepare for redo of a normal command.
+ */
+ static void
+prep_redo_cmd(cmdarg_T *cap)
+{
+ prep_redo(cap->oap->regname, cap->count0,
+ NUL, cap->cmdchar, NUL, NUL, cap->nchar);
+}
+
+/*
+ * Prepare for redo of any command.
+ * Note that only the last argument can be a multi-byte char.
+ */
+ static void
+prep_redo(
+ int regname,
+ long num,
+ int cmd1,
+ int cmd2,
+ int cmd3,
+ int cmd4,
+ int cmd5)
+{
+ ResetRedobuff();
+ if (regname != 0) /* yank from specified buffer */
+ {
+ AppendCharToRedobuff('"');
+ AppendCharToRedobuff(regname);
+ }
+ if (num)
+ AppendNumberToRedobuff(num);
+
+ if (cmd1 != NUL)
+ AppendCharToRedobuff(cmd1);
+ if (cmd2 != NUL)
+ AppendCharToRedobuff(cmd2);
+ if (cmd3 != NUL)
+ AppendCharToRedobuff(cmd3);
+ if (cmd4 != NUL)
+ AppendCharToRedobuff(cmd4);
+ if (cmd5 != NUL)
+ AppendCharToRedobuff(cmd5);
+}
+
+/*
+ * check for operator active and clear it
+ *
+ * return TRUE if operator was active
+ */
+ static int
+checkclearop(oparg_T *oap)
+{
+ if (oap->op_type == OP_NOP)
+ return FALSE;
+ clearopbeep(oap);
+ return TRUE;
+}
+
+/*
+ * Check for operator or Visual active. Clear active operator.
+ *
+ * Return TRUE if operator or Visual was active.
+ */
+ static int
+checkclearopq(oparg_T *oap)
+{
+ if (oap->op_type == OP_NOP && !VIsual_active)
+ return FALSE;
+ clearopbeep(oap);
+ return TRUE;
+}
+
+ static void
+clearop(oparg_T *oap)
+{
+ oap->op_type = OP_NOP;
+ oap->regname = 0;
+ oap->motion_force = NUL;
+ oap->use_reg_one = FALSE;
+}
+
+ static void
+clearopbeep(oparg_T *oap)
+{
+ clearop(oap);
+ beep_flush();
+}
+
+/*
+ * Remove the shift modifier from a special key.
+ */
+ static void
+unshift_special(cmdarg_T *cap)
+{
+ switch (cap->cmdchar)
+ {
+ case K_S_RIGHT: cap->cmdchar = K_RIGHT; break;
+ case K_S_LEFT: cap->cmdchar = K_LEFT; break;
+ case K_S_UP: cap->cmdchar = K_UP; break;
+ case K_S_DOWN: cap->cmdchar = K_DOWN; break;
+ case K_S_HOME: cap->cmdchar = K_HOME; break;
+ case K_S_END: cap->cmdchar = K_END; break;
+ }
+ cap->cmdchar = simplify_key(cap->cmdchar, &mod_mask);
+}
+
+/*
+ * If the mode is currently displayed clear the command line or update the
+ * command displayed.
+ */
+ static void
+may_clear_cmdline(void)
+{
+ if (mode_displayed)
+ clear_cmdline = TRUE; /* unshow visual mode later */
+#ifdef FEAT_CMDL_INFO
+ else
+ clear_showcmd();
+#endif
+}
+
+#if defined(FEAT_CMDL_INFO) || defined(PROTO)
+/*
+ * Routines for displaying a partly typed command
+ */
+
+#define SHOWCMD_BUFLEN SHOWCMD_COLS + 1 + 30
+static char_u showcmd_buf[SHOWCMD_BUFLEN];
+static char_u old_showcmd_buf[SHOWCMD_BUFLEN]; /* For push_showcmd() */
+static int showcmd_is_clear = TRUE;
+static int showcmd_visual = FALSE;
+
+static void display_showcmd(void);
+
+ void
+clear_showcmd(void)
+{
+ if (!p_sc)
+ return;
+
+ if (VIsual_active && !char_avail())
+ {
+ int cursor_bot = LT_POS(VIsual, curwin->w_cursor);
+ long lines;
+ colnr_T leftcol, rightcol;
+ linenr_T top, bot;
+
+ /* Show the size of the Visual area. */
+ if (cursor_bot)
+ {
+ top = VIsual.lnum;
+ bot = curwin->w_cursor.lnum;
+ }
+ else
+ {
+ top = curwin->w_cursor.lnum;
+ bot = VIsual.lnum;
+ }
+# ifdef FEAT_FOLDING
+ /* Include closed folds as a whole. */
+ (void)hasFolding(top, &top, NULL);
+ (void)hasFolding(bot, NULL, &bot);
+# endif
+ lines = bot - top + 1;
+
+ if (VIsual_mode == Ctrl_V)
+ {
+# ifdef FEAT_LINEBREAK
+ char_u *saved_sbr = p_sbr;
+
+ /* Make 'sbr' empty for a moment to get the correct size. */
+ p_sbr = empty_option;
+# endif
+ getvcols(curwin, &curwin->w_cursor, &VIsual, &leftcol, &rightcol);
+# ifdef FEAT_LINEBREAK
+ p_sbr = saved_sbr;
+# endif
+ sprintf((char *)showcmd_buf, "%ldx%ld", lines,
+ (long)(rightcol - leftcol + 1));
+ }
+ else if (VIsual_mode == 'V' || VIsual.lnum != curwin->w_cursor.lnum)
+ sprintf((char *)showcmd_buf, "%ld", lines);
+ else
+ {
+ char_u *s, *e;
+ int l;
+ int bytes = 0;
+ int chars = 0;
+
+ if (cursor_bot)
+ {
+ s = ml_get_pos(&VIsual);
+ e = ml_get_cursor();
+ }
+ else
+ {
+ s = ml_get_cursor();
+ e = ml_get_pos(&VIsual);
+ }
+ while ((*p_sel != 'e') ? s <= e : s < e)
+ {
+ l = (*mb_ptr2len)(s);
+ if (l == 0)
+ {
+ ++bytes;
+ ++chars;
+ break; /* end of line */
+ }
+ bytes += l;
+ ++chars;
+ s += l;
+ }
+ if (bytes == chars)
+ sprintf((char *)showcmd_buf, "%d", chars);
+ else
+ sprintf((char *)showcmd_buf, "%d-%d", chars, bytes);
+ }
+ showcmd_buf[SHOWCMD_COLS] = NUL; /* truncate */
+ showcmd_visual = TRUE;
+ }
+ else
+ {
+ showcmd_buf[0] = NUL;
+ showcmd_visual = FALSE;
+
+ /* Don't actually display something if there is nothing to clear. */
+ if (showcmd_is_clear)
+ return;
+ }
+
+ display_showcmd();
+}
+
+/*
+ * Add 'c' to string of shown command chars.
+ * Return TRUE if output has been written (and setcursor() has been called).
+ */
+ int
+add_to_showcmd(int c)
+{
+ char_u *p;
+ int old_len;
+ int extra_len;
+ int overflow;
+#if defined(FEAT_MOUSE)
+ int i;
+ static int ignore[] =
+ {
+# ifdef FEAT_GUI
+ K_VER_SCROLLBAR, K_HOR_SCROLLBAR,
+ K_LEFTMOUSE_NM, K_LEFTRELEASE_NM,
+# endif
+ K_IGNORE, K_PS,
+ K_LEFTMOUSE, K_LEFTDRAG, K_LEFTRELEASE, K_MOUSEMOVE,
+ K_MIDDLEMOUSE, K_MIDDLEDRAG, K_MIDDLERELEASE,
+ K_RIGHTMOUSE, K_RIGHTDRAG, K_RIGHTRELEASE,
+ K_MOUSEDOWN, K_MOUSEUP, K_MOUSELEFT, K_MOUSERIGHT,
+ K_X1MOUSE, K_X1DRAG, K_X1RELEASE, K_X2MOUSE, K_X2DRAG, K_X2RELEASE,
+ K_CURSORHOLD,
+ 0
+ };
+#endif
+
+ if (!p_sc || msg_silent != 0)
+ return FALSE;
+
+ if (showcmd_visual)
+ {
+ showcmd_buf[0] = NUL;
+ showcmd_visual = FALSE;
+ }
+
+#if defined(FEAT_MOUSE)
+ /* Ignore keys that are scrollbar updates and mouse clicks */
+ if (IS_SPECIAL(c))
+ for (i = 0; ignore[i] != 0; ++i)
+ if (ignore[i] == c)
+ return FALSE;
+#endif
+
+ p = transchar(c);
+ if (*p == ' ')
+ STRCPY(p, "<20>");
+ old_len = (int)STRLEN(showcmd_buf);
+ extra_len = (int)STRLEN(p);
+ overflow = old_len + extra_len - SHOWCMD_COLS;
+ if (overflow > 0)
+ mch_memmove(showcmd_buf, showcmd_buf + overflow,
+ old_len - overflow + 1);
+ STRCAT(showcmd_buf, p);
+
+ if (char_avail())
+ return FALSE;
+
+ display_showcmd();
+
+ return TRUE;
+}
+
+ void
+add_to_showcmd_c(int c)
+{
+ if (!add_to_showcmd(c))
+ setcursor();
+}
+
+/*
+ * Delete 'len' characters from the end of the shown command.
+ */
+ static void
+del_from_showcmd(int len)
+{
+ int old_len;
+
+ if (!p_sc)
+ return;
+
+ old_len = (int)STRLEN(showcmd_buf);
+ if (len > old_len)
+ len = old_len;
+ showcmd_buf[old_len - len] = NUL;
+
+ if (!char_avail())
+ display_showcmd();
+}
+
+/*
+ * push_showcmd() and pop_showcmd() are used when waiting for the user to type
+ * something and there is a partial mapping.
+ */
+ void
+push_showcmd(void)
+{
+ if (p_sc)
+ STRCPY(old_showcmd_buf, showcmd_buf);
+}
+
+ void
+pop_showcmd(void)
+{
+ if (!p_sc)
+ return;
+
+ STRCPY(showcmd_buf, old_showcmd_buf);
+
+ display_showcmd();
+}
+
+ static void
+display_showcmd(void)
+{
+ int len;
+
+ cursor_off();
+
+ len = (int)STRLEN(showcmd_buf);
+ if (len == 0)
+ showcmd_is_clear = TRUE;
+ else
+ {
+ screen_puts(showcmd_buf, (int)Rows - 1, sc_col, 0);
+ showcmd_is_clear = FALSE;
+ }
+
+ /*
+ * clear the rest of an old message by outputting up to SHOWCMD_COLS
+ * spaces
+ */
+ screen_puts((char_u *)" " + len, (int)Rows - 1, sc_col + len, 0);
+
+ setcursor(); /* put cursor back where it belongs */
+}
+#endif
+
+/*
+ * When "check" is FALSE, prepare for commands that scroll the window.
+ * When "check" is TRUE, take care of scroll-binding after the window has
+ * scrolled. Called from normal_cmd() and edit().
+ */
+ void
+do_check_scrollbind(int check)
+{
+ static win_T *old_curwin = NULL;
+ static linenr_T old_topline = 0;
+#ifdef FEAT_DIFF
+ static int old_topfill = 0;
+#endif
+ static buf_T *old_buf = NULL;
+ static colnr_T old_leftcol = 0;
+
+ if (check && curwin->w_p_scb)
+ {
+ /* If a ":syncbind" command was just used, don't scroll, only reset
+ * the values. */
+ if (did_syncbind)
+ did_syncbind = FALSE;
+ else if (curwin == old_curwin)
+ {
+ /*
+ * Synchronize other windows, as necessary according to
+ * 'scrollbind'. Don't do this after an ":edit" command, except
+ * when 'diff' is set.
+ */
+ if ((curwin->w_buffer == old_buf
+#ifdef FEAT_DIFF
+ || curwin->w_p_diff
+#endif
+ )
+ && (curwin->w_topline != old_topline
+#ifdef FEAT_DIFF
+ || curwin->w_topfill != old_topfill
+#endif
+ || curwin->w_leftcol != old_leftcol))
+ {
+ check_scrollbind(curwin->w_topline - old_topline,
+ (long)(curwin->w_leftcol - old_leftcol));
+ }
+ }
+ else if (vim_strchr(p_sbo, 'j')) /* jump flag set in 'scrollopt' */
+ {
+ /*
+ * When switching between windows, make sure that the relative
+ * vertical offset is valid for the new window. The relative
+ * offset is invalid whenever another 'scrollbind' window has
+ * scrolled to a point that would force the current window to
+ * scroll past the beginning or end of its buffer. When the
+ * resync is performed, some of the other 'scrollbind' windows may
+ * need to jump so that the current window's relative position is
+ * visible on-screen.
+ */
+ check_scrollbind(curwin->w_topline - curwin->w_scbind_pos, 0L);
+ }
+ curwin->w_scbind_pos = curwin->w_topline;
+ }
+
+ old_curwin = curwin;
+ old_topline = curwin->w_topline;
+#ifdef FEAT_DIFF
+ old_topfill = curwin->w_topfill;
+#endif
+ old_buf = curwin->w_buffer;
+ old_leftcol = curwin->w_leftcol;
+}
+
+/*
+ * Synchronize any windows that have "scrollbind" set, based on the
+ * number of rows by which the current window has changed
+ * (1998-11-02 16:21:01 R. Edward Ralston <eralston@computer.org>)
+ */
+ void
+check_scrollbind(linenr_T topline_diff, long leftcol_diff)
+{
+ int want_ver;
+ int want_hor;
+ win_T *old_curwin = curwin;
+ buf_T *old_curbuf = curbuf;
+ int old_VIsual_select = VIsual_select;
+ int old_VIsual_active = VIsual_active;
+ colnr_T tgt_leftcol = curwin->w_leftcol;
+ long topline;
+ long y;
+
+ /*
+ * check 'scrollopt' string for vertical and horizontal scroll options
+ */
+ want_ver = (vim_strchr(p_sbo, 'v') && topline_diff != 0);
+#ifdef FEAT_DIFF
+ want_ver |= old_curwin->w_p_diff;
+#endif
+ want_hor = (vim_strchr(p_sbo, 'h') && (leftcol_diff || topline_diff != 0));
+
+ /*
+ * loop through the scrollbound windows and scroll accordingly
+ */
+ VIsual_select = VIsual_active = 0;
+ FOR_ALL_WINDOWS(curwin)
+ {
+ curbuf = curwin->w_buffer;
+ /* skip original window and windows with 'noscrollbind' */
+ if (curwin != old_curwin && curwin->w_p_scb)
+ {
+ /*
+ * do the vertical scroll
+ */
+ if (want_ver)
+ {
+#ifdef FEAT_DIFF
+ if (old_curwin->w_p_diff && curwin->w_p_diff)
+ {
+ diff_set_topline(old_curwin, curwin);
+ }
+ else
+#endif
+ {
+ curwin->w_scbind_pos += topline_diff;
+ topline = curwin->w_scbind_pos;
+ if (topline > curbuf->b_ml.ml_line_count)
+ topline = curbuf->b_ml.ml_line_count;
+ if (topline < 1)
+ topline = 1;
+
+ y = topline - curwin->w_topline;
+ if (y > 0)
+ scrollup(y, FALSE);
+ else
+ scrolldown(-y, FALSE);
+ }
+
+ redraw_later(VALID);
+ cursor_correct();
+ curwin->w_redr_status = TRUE;
+ }
+
+ /*
+ * do the horizontal scroll
+ */
+ if (want_hor && curwin->w_leftcol != tgt_leftcol)
+ {
+ curwin->w_leftcol = tgt_leftcol;
+ leftcol_changed();
+ }
+ }
+ }
+
+ /*
+ * reset current-window
+ */
+ VIsual_select = old_VIsual_select;
+ VIsual_active = old_VIsual_active;
+ curwin = old_curwin;
+ curbuf = old_curbuf;
+}
+
+/*
+ * Command character that's ignored.
+ * Used for CTRL-Q and CTRL-S to avoid problems with terminals that use
+ * xon/xoff.
+ */
+ static void
+nv_ignore(cmdarg_T *cap)
+{
+ cap->retval |= CA_COMMAND_BUSY; /* don't call edit() now */
+}
+
+/*
+ * Command character that doesn't do anything, but unlike nv_ignore() does
+ * start edit(). Used for "startinsert" executed while starting up.
+ */
+ static void
+nv_nop(cmdarg_T *cap UNUSED)
+{
+}
+
+/*
+ * Command character doesn't exist.
+ */
+ static void
+nv_error(cmdarg_T *cap)
+{
+ clearopbeep(cap->oap);
+}
+
+/*
+ * <Help> and <F1> commands.
+ */
+ static void
+nv_help(cmdarg_T *cap)
+{
+ if (!checkclearopq(cap->oap))
+ ex_help(NULL);
+}
+
+/*
+ * CTRL-A and CTRL-X: Add or subtract from letter or number under cursor.
+ */
+ static void
+nv_addsub(cmdarg_T *cap)
+{
+#ifdef FEAT_JOB_CHANNEL
+ if (bt_prompt(curbuf) && !prompt_curpos_editable())
+ clearopbeep(cap->oap);
+ else
+#endif
+ if (!VIsual_active && cap->oap->op_type == OP_NOP)
+ {
+ prep_redo_cmd(cap);
+ cap->oap->op_type = cap->cmdchar == Ctrl_A ? OP_NR_ADD : OP_NR_SUB;
+ op_addsub(cap->oap, cap->count1, cap->arg);
+ cap->oap->op_type = OP_NOP;
+ }
+ else if (VIsual_active)
+ nv_operator(cap);
+ else
+ clearop(cap->oap);
+}
+
+/*
+ * CTRL-F, CTRL-B, etc: Scroll page up or down.
+ */
+ static void
+nv_page(cmdarg_T *cap)
+{
+ if (!checkclearop(cap->oap))
+ {
+ if (mod_mask & MOD_MASK_CTRL)
+ {
+ /* <C-PageUp>: tab page back; <C-PageDown>: tab page forward */
+ if (cap->arg == BACKWARD)
+ goto_tabpage(-(int)cap->count1);
+ else
+ goto_tabpage((int)cap->count0);
+ }
+ else
+ (void)onepage(cap->arg, cap->count1);
+ }
+}
+
+/*
+ * Implementation of "gd" and "gD" command.
+ */
+ static void
+nv_gd(
+ oparg_T *oap,
+ int nchar,
+ int thisblock) /* 1 for "1gd" and "1gD" */
+{
+ int len;
+ char_u *ptr;
+
+ if ((len = find_ident_under_cursor(&ptr, FIND_IDENT)) == 0
+ || find_decl(ptr, len, nchar == 'd', thisblock, SEARCH_START)
+ == FAIL)
+ clearopbeep(oap);
+#ifdef FEAT_FOLDING
+ else if ((fdo_flags & FDO_SEARCH) && KeyTyped && oap->op_type == OP_NOP)
+ foldOpenCursor();
+#endif
+}
+
+/*
+ * Return TRUE if line[offset] is not inside a C-style comment or string, FALSE
+ * otherwise.
+ */
+ static int
+is_ident(char_u *line, int offset)
+{
+ int i;
+ int incomment = FALSE;
+ int instring = 0;
+ int prev = 0;
+
+ for (i = 0; i < offset && line[i] != NUL; i++)
+ {
+ if (instring != 0)
+ {
+ if (prev != '\\' && line[i] == instring)
+ instring = 0;
+ }
+ else if ((line[i] == '"' || line[i] == '\'') && !incomment)
+ {
+ instring = line[i];
+ }
+ else
+ {
+ if (incomment)
+ {
+ if (prev == '*' && line[i] == '/')
+ incomment = FALSE;
+ }
+ else if (prev == '/' && line[i] == '*')
+ {
+ incomment = TRUE;
+ }
+ else if (prev == '/' && line[i] == '/')
+ {
+ return FALSE;
+ }
+ }
+
+ prev = line[i];
+ }
+
+ return incomment == FALSE && instring == 0;
+}
+
+/*
+ * Search for variable declaration of "ptr[len]".
+ * When "locally" is TRUE in the current function ("gd"), otherwise in the
+ * current file ("gD").
+ * When "thisblock" is TRUE check the {} block scope.
+ * Return FAIL when not found.
+ */
+ int
+find_decl(
+ char_u *ptr,
+ int len,
+ int locally,
+ int thisblock,
+ int flags_arg) /* flags passed to searchit() */
+{
+ char_u *pat;
+ pos_T old_pos;
+ pos_T par_pos;
+ pos_T found_pos;
+ int t;
+ int save_p_ws;
+ int save_p_scs;
+ int retval = OK;
+ int incll;
+ int searchflags = flags_arg;
+ int valid;
+
+ if ((pat = alloc(len + 7)) == NULL)
+ return FAIL;
+
+ /* Put "\V" before the pattern to avoid that the special meaning of "."
+ * and "~" causes trouble. */
+ sprintf((char *)pat, vim_iswordp(ptr) ? "\\V\\<%.*s\\>" : "\\V%.*s",
+ len, ptr);
+ old_pos = curwin->w_cursor;
+ save_p_ws = p_ws;
+ save_p_scs = p_scs;
+ p_ws = FALSE; /* don't wrap around end of file now */
+ p_scs = FALSE; /* don't switch ignorecase off now */
+
+ /*
+ * With "gD" go to line 1.
+ * With "gd" Search back for the start of the current function, then go
+ * back until a blank line. If this fails go to line 1.
+ */
+ if (!locally || !findpar(&incll, BACKWARD, 1L, '{', FALSE))
+ {
+ setpcmark(); /* Set in findpar() otherwise */
+ curwin->w_cursor.lnum = 1;
+ par_pos = curwin->w_cursor;
+ }
+ else
+ {
+ par_pos = curwin->w_cursor;
+ while (curwin->w_cursor.lnum > 1 && *skipwhite(ml_get_curline()) != NUL)
+ --curwin->w_cursor.lnum;
+ }
+ curwin->w_cursor.col = 0;
+
+ /* Search forward for the identifier, ignore comment lines. */
+ CLEAR_POS(&found_pos);
+ for (;;)
+ {
+ valid = FALSE;
+ t = searchit(curwin, curbuf, &curwin->w_cursor, NULL, FORWARD,
+ pat, 1L, searchflags, RE_LAST, (linenr_T)0, NULL, NULL);
+ if (curwin->w_cursor.lnum >= old_pos.lnum)
+ t = FAIL; /* match after start is failure too */
+
+ if (thisblock && t != FAIL)
+ {
+ pos_T *pos;
+
+ /* Check that the block the match is in doesn't end before the
+ * position where we started the search from. */
+ if ((pos = findmatchlimit(NULL, '}', FM_FORWARD,
+ (int)(old_pos.lnum - curwin->w_cursor.lnum + 1))) != NULL
+ && pos->lnum < old_pos.lnum)
+ {
+ /* There can't be a useful match before the end of this block.
+ * Skip to the end. */
+ curwin->w_cursor = *pos;
+ continue;
+ }
+ }
+
+ if (t == FAIL)
+ {
+ /* If we previously found a valid position, use it. */
+ if (found_pos.lnum != 0)
+ {
+ curwin->w_cursor = found_pos;
+ t = OK;
+ }
+ break;
+ }
+#ifdef FEAT_COMMENTS
+ if (get_leader_len(ml_get_curline(), NULL, FALSE, TRUE) > 0)
+ {
+ /* Ignore this line, continue at start of next line. */
+ ++curwin->w_cursor.lnum;
+ curwin->w_cursor.col = 0;
+ continue;
+ }
+#endif
+ valid = is_ident(ml_get_curline(), curwin->w_cursor.col);
+
+ /* If the current position is not a valid identifier and a previous
+ * match is present, favor that one instead. */
+ if (!valid && found_pos.lnum != 0)
+ {
+ curwin->w_cursor = found_pos;
+ break;
+ }
+
+ /* Global search: use first valid match found */
+ if (valid && !locally)
+ break;
+ if (valid && curwin->w_cursor.lnum >= par_pos.lnum)
+ {
+ /* If we previously found a valid position, use it. */
+ if (found_pos.lnum != 0)
+ curwin->w_cursor = found_pos;
+ break;
+ }
+
+ /* For finding a local variable and the match is before the "{" or
+ * inside a comment, continue searching. For K&R style function
+ * declarations this skips the function header without types. */
+ if (!valid)
+ {
+ CLEAR_POS(&found_pos);
+ }
+ else
+ found_pos = curwin->w_cursor;
+ /* Remove SEARCH_START from flags to avoid getting stuck at one
+ * position. */
+ searchflags &= ~SEARCH_START;
+ }
+
+ if (t == FAIL)
+ {
+ retval = FAIL;
+ curwin->w_cursor = old_pos;
+ }
+ else
+ {
+ curwin->w_set_curswant = TRUE;
+ /* "n" searches forward now */
+ reset_search_dir();
+ }
+
+ vim_free(pat);
+ p_ws = save_p_ws;
+ p_scs = save_p_scs;
+
+ return retval;
+}
+
+/*
+ * Move 'dist' lines in direction 'dir', counting lines by *screen*
+ * lines rather than lines in the file.
+ * 'dist' must be positive.
+ *
+ * Return OK if able to move cursor, FAIL otherwise.
+ */
+ static int
+nv_screengo(oparg_T *oap, int dir, long dist)
+{
+ int linelen = linetabsize(ml_get_curline());
+ int retval = OK;
+ int atend = FALSE;
+ int n;
+ int col_off1; /* margin offset for first screen line */
+ int col_off2; /* margin offset for wrapped screen line */
+ int width1; /* text width for first screen line */
+ int width2; /* test width for wrapped screen line */
+
+ oap->motion_type = MCHAR;
+ oap->inclusive = (curwin->w_curswant == MAXCOL);
+
+ col_off1 = curwin_col_off();
+ col_off2 = col_off1 - curwin_col_off2();
+ width1 = curwin->w_width - col_off1;
+ width2 = curwin->w_width - col_off2;
+ if (width2 == 0)
+ width2 = 1; /* avoid divide by zero */
+
+ if (curwin->w_width != 0)
+ {
+ /*
+ * Instead of sticking at the last character of the buffer line we
+ * try to stick in the last column of the screen.
+ */
+ if (curwin->w_curswant == MAXCOL)
+ {
+ atend = TRUE;
+ validate_virtcol();
+ if (width1 <= 0)
+ curwin->w_curswant = 0;
+ else
+ {
+ curwin->w_curswant = width1 - 1;
+ if (curwin->w_virtcol > curwin->w_curswant)
+ curwin->w_curswant += ((curwin->w_virtcol
+ - curwin->w_curswant - 1) / width2 + 1) * width2;
+ }
+ }
+ else
+ {
+ if (linelen > width1)
+ n = ((linelen - width1 - 1) / width2 + 1) * width2 + width1;
+ else
+ n = width1;
+ if (curwin->w_curswant > (colnr_T)n + 1)
+ curwin->w_curswant -= ((curwin->w_curswant - n) / width2 + 1)
+ * width2;
+ }
+
+ while (dist--)
+ {
+ if (dir == BACKWARD)
+ {
+ if ((long)curwin->w_curswant >= width2)
+ /* move back within line */
+ curwin->w_curswant -= width2;
+ else
+ {
+ /* to previous line */
+ if (curwin->w_cursor.lnum == 1)
+ {
+ retval = FAIL;
+ break;
+ }
+ --curwin->w_cursor.lnum;
+#ifdef FEAT_FOLDING
+ /* Move to the start of a closed fold. Don't do that when
+ * 'foldopen' contains "all": it will open in a moment. */
+ if (!(fdo_flags & FDO_ALL))
+ (void)hasFolding(curwin->w_cursor.lnum,
+ &curwin->w_cursor.lnum, NULL);
+#endif
+ linelen = linetabsize(ml_get_curline());
+ if (linelen > width1)
+ curwin->w_curswant += (((linelen - width1 - 1) / width2)
+ + 1) * width2;
+ }
+ }
+ else /* dir == FORWARD */
+ {
+ if (linelen > width1)
+ n = ((linelen - width1 - 1) / width2 + 1) * width2 + width1;
+ else
+ n = width1;
+ if (curwin->w_curswant + width2 < (colnr_T)n)
+ /* move forward within line */
+ curwin->w_curswant += width2;
+ else
+ {
+ /* to next line */
+#ifdef FEAT_FOLDING
+ /* Move to the end of a closed fold. */
+ (void)hasFolding(curwin->w_cursor.lnum, NULL,
+ &curwin->w_cursor.lnum);
+#endif
+ if (curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count)
+ {
+ retval = FAIL;
+ break;
+ }
+ curwin->w_cursor.lnum++;
+ curwin->w_curswant %= width2;
+ linelen = linetabsize(ml_get_curline());
+ }
+ }
+ }
+ }
+
+ if (virtual_active() && atend)
+ coladvance(MAXCOL);
+ else
+ coladvance(curwin->w_curswant);
+
+ if (curwin->w_cursor.col > 0 && curwin->w_p_wrap)
+ {
+ colnr_T virtcol;
+
+ /*
+ * Check for landing on a character that got split at the end of the
+ * last line. We want to advance a screenline, not end up in the same
+ * screenline or move two screenlines.
+ */
+ validate_virtcol();
+ virtcol = curwin->w_virtcol;
+#if defined(FEAT_LINEBREAK)
+ if (virtcol > (colnr_T)width1 && *p_sbr != NUL)
+ virtcol -= vim_strsize(p_sbr);
+#endif
+
+ if (virtcol > curwin->w_curswant
+ && (curwin->w_curswant < (colnr_T)width1
+ ? (curwin->w_curswant > (colnr_T)width1 / 2)
+ : ((curwin->w_curswant - width1) % width2
+ > (colnr_T)width2 / 2)))
+ --curwin->w_cursor.col;
+ }
+
+ if (atend)
+ curwin->w_curswant = MAXCOL; /* stick in the last column */
+
+ return retval;
+}
+
+#ifdef FEAT_MOUSE
+/*
+ * Mouse scroll wheel: Default action is to scroll three lines, or one page
+ * when Shift or Ctrl is used.
+ * K_MOUSEUP (cap->arg == 1) or K_MOUSEDOWN (cap->arg == 0) or
+ * K_MOUSELEFT (cap->arg == -1) or K_MOUSERIGHT (cap->arg == -2)
+ */
+ static void
+nv_mousescroll(cmdarg_T *cap)
+{
+ win_T *old_curwin = curwin, *wp;
+
+ if (mouse_row >= 0 && mouse_col >= 0)
+ {
+ int row, col;
+
+ row = mouse_row;
+ col = mouse_col;
+
+ /* find the window at the pointer coordinates */
+ wp = mouse_find_win(&row, &col);
+ if (wp == NULL)
+ return;
+ curwin = wp;
+ curbuf = curwin->w_buffer;
+ }
+
+ if (cap->arg == MSCR_UP || cap->arg == MSCR_DOWN)
+ {
+# ifdef FEAT_TERMINAL
+ if (term_use_loop())
+ /* This window is a terminal window, send the mouse event there.
+ * Set "typed" to FALSE to avoid an endless loop. */
+ send_keys_to_term(curbuf->b_term, cap->cmdchar, FALSE);
+ else
+# endif
+ if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL))
+ {
+ (void)onepage(cap->arg ? FORWARD : BACKWARD, 1L);
+ }
+ else
+ {
+ cap->count1 = 3;
+ cap->count0 = 3;
+ nv_scroll_line(cap);
+ }
+ }
+# ifdef FEAT_GUI
+ else
+ {
+ /* Horizontal scroll - only allowed when 'wrap' is disabled */
+ if (!curwin->w_p_wrap)
+ {
+ int val, step = 6;
+
+ if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL))
+ step = curwin->w_width;
+ val = curwin->w_leftcol + (cap->arg == MSCR_RIGHT ? -step : +step);
+ if (val < 0)
+ val = 0;
+
+ gui_do_horiz_scroll(val, TRUE);
+ }
+ }
+# endif
+# ifdef FEAT_SYN_HL
+ if (curwin != old_curwin && curwin->w_p_cul)
+ redraw_for_cursorline(curwin);
+# endif
+
+ curwin->w_redr_status = TRUE;
+
+ curwin = old_curwin;
+ curbuf = curwin->w_buffer;
+}
+
+/*
+ * Mouse clicks and drags.
+ */
+ static void
+nv_mouse(cmdarg_T *cap)
+{
+ (void)do_mouse(cap->oap, cap->cmdchar, BACKWARD, cap->count1, 0);
+}
+#endif
+
+/*
+ * Handle CTRL-E and CTRL-Y commands: scroll a line up or down.
+ * cap->arg must be TRUE for CTRL-E.
+ */
+ static void
+nv_scroll_line(cmdarg_T *cap)
+{
+ if (!checkclearop(cap->oap))
+ scroll_redraw(cap->arg, cap->count1);
+}
+
+/*
+ * Scroll "count" lines up or down, and redraw.
+ */
+ void
+scroll_redraw(int up, long count)
+{
+ linenr_T prev_topline = curwin->w_topline;
+#ifdef FEAT_DIFF
+ int prev_topfill = curwin->w_topfill;
+#endif
+ linenr_T prev_lnum = curwin->w_cursor.lnum;
+
+ if (up)
+ scrollup(count, TRUE);
+ else
+ scrolldown(count, TRUE);
+ if (get_scrolloff_value())
+ {
+ /* Adjust the cursor position for 'scrolloff'. Mark w_topline as
+ * valid, otherwise the screen jumps back at the end of the file. */
+ cursor_correct();
+ check_cursor_moved(curwin);
+ curwin->w_valid |= VALID_TOPLINE;
+
+ /* If moved back to where we were, at least move the cursor, otherwise
+ * we get stuck at one position. Don't move the cursor up if the
+ * first line of the buffer is already on the screen */
+ while (curwin->w_topline == prev_topline
+#ifdef FEAT_DIFF
+ && curwin->w_topfill == prev_topfill
+#endif
+ )
+ {
+ if (up)
+ {
+ if (curwin->w_cursor.lnum > prev_lnum
+ || cursor_down(1L, FALSE) == FAIL)
+ break;
+ }
+ else
+ {
+ if (curwin->w_cursor.lnum < prev_lnum
+ || prev_topline == 1L
+ || cursor_up(1L, FALSE) == FAIL)
+ break;
+ }
+ /* Mark w_topline as valid, otherwise the screen jumps back at the
+ * end of the file. */
+ check_cursor_moved(curwin);
+ curwin->w_valid |= VALID_TOPLINE;
+ }
+ }
+ if (curwin->w_cursor.lnum != prev_lnum)
+ coladvance(curwin->w_curswant);
+ redraw_later(VALID);
+}
+
+/*
+ * Commands that start with "z".
+ */
+ static void
+nv_zet(cmdarg_T *cap)
+{
+ long n;
+ colnr_T col;
+ int nchar = cap->nchar;
+#ifdef FEAT_FOLDING
+ long old_fdl = curwin->w_p_fdl;
+ int old_fen = curwin->w_p_fen;
+#endif
+#ifdef FEAT_SPELL
+ int undo = FALSE;
+#endif
+ long siso = get_sidescrolloff_value();
+
+ if (VIM_ISDIGIT(nchar))
+ {
+ /*
+ * "z123{nchar}": edit the count before obtaining {nchar}
+ */
+ if (checkclearop(cap->oap))
+ return;
+ n = nchar - '0';
+ for (;;)
+ {
+#ifdef USE_ON_FLY_SCROLL
+ dont_scroll = TRUE; /* disallow scrolling here */
+#endif
+ ++no_mapping;
+ ++allow_keys; /* no mapping for nchar, but allow key codes */
+ nchar = plain_vgetc();
+ LANGMAP_ADJUST(nchar, TRUE);
+ --no_mapping;
+ --allow_keys;
+#ifdef FEAT_CMDL_INFO
+ (void)add_to_showcmd(nchar);
+#endif
+ if (nchar == K_DEL || nchar == K_KDEL)
+ n /= 10;
+ else if (VIM_ISDIGIT(nchar))
+ n = n * 10 + (nchar - '0');
+ else if (nchar == CAR)
+ {
+#ifdef FEAT_GUI
+ need_mouse_correct = TRUE;
+#endif
+ win_setheight((int)n);
+ break;
+ }
+ else if (nchar == 'l'
+ || nchar == 'h'
+ || nchar == K_LEFT
+ || nchar == K_RIGHT)
+ {
+ cap->count1 = n ? n * cap->count1 : cap->count1;
+ goto dozet;
+ }
+ else
+ {
+ clearopbeep(cap->oap);
+ break;
+ }
+ }
+ cap->oap->op_type = OP_NOP;
+ return;
+ }
+
+dozet:
+ if (
+#ifdef FEAT_FOLDING
+ /* "zf" and "zF" are always an operator, "zd", "zo", "zO", "zc"
+ * and "zC" only in Visual mode. "zj" and "zk" are motion
+ * commands. */
+ cap->nchar != 'f' && cap->nchar != 'F'
+ && !(VIsual_active && vim_strchr((char_u *)"dcCoO", cap->nchar))
+ && cap->nchar != 'j' && cap->nchar != 'k'
+ &&
+#endif
+ checkclearop(cap->oap))
+ return;
+
+ /*
+ * For "z+", "z<CR>", "zt", "z.", "zz", "z^", "z-", "zb":
+ * If line number given, set cursor.
+ */
+ if ((vim_strchr((char_u *)"+\r\nt.z^-b", nchar) != NULL)
+ && cap->count0
+ && cap->count0 != curwin->w_cursor.lnum)
+ {
+ setpcmark();
+ if (cap->count0 > curbuf->b_ml.ml_line_count)
+ curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
+ else
+ curwin->w_cursor.lnum = cap->count0;
+ check_cursor_col();
+ }
+
+ switch (nchar)
+ {
+ /* "z+", "z<CR>" and "zt": put cursor at top of screen */
+ case '+':
+ if (cap->count0 == 0)
+ {
+ /* No count given: put cursor at the line below screen */
+ validate_botline(); /* make sure w_botline is valid */
+ if (curwin->w_botline > curbuf->b_ml.ml_line_count)
+ curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
+ else
+ curwin->w_cursor.lnum = curwin->w_botline;
+ }
+ /* FALLTHROUGH */
+ case NL:
+ case CAR:
+ case K_KENTER:
+ beginline(BL_WHITE | BL_FIX);
+ /* FALLTHROUGH */
+
+ case 't': scroll_cursor_top(0, TRUE);
+ redraw_later(VALID);
+ set_fraction(curwin);
+ break;
+
+ /* "z." and "zz": put cursor in middle of screen */
+ case '.': beginline(BL_WHITE | BL_FIX);
+ /* FALLTHROUGH */
+
+ case 'z': scroll_cursor_halfway(TRUE);
+ redraw_later(VALID);
+ set_fraction(curwin);
+ break;
+
+ /* "z^", "z-" and "zb": put cursor at bottom of screen */
+ case '^': /* Strange Vi behavior: <count>z^ finds line at top of window
+ * when <count> is at bottom of window, and puts that one at
+ * bottom of window. */
+ if (cap->count0 != 0)
+ {
+ scroll_cursor_bot(0, TRUE);
+ curwin->w_cursor.lnum = curwin->w_topline;
+ }
+ else if (curwin->w_topline == 1)
+ curwin->w_cursor.lnum = 1;
+ else
+ curwin->w_cursor.lnum = curwin->w_topline - 1;
+ /* FALLTHROUGH */
+ case '-':
+ beginline(BL_WHITE | BL_FIX);
+ /* FALLTHROUGH */
+
+ case 'b': scroll_cursor_bot(0, TRUE);
+ redraw_later(VALID);
+ set_fraction(curwin);
+ break;
+
+ /* "zH" - scroll screen right half-page */
+ case 'H':
+ cap->count1 *= curwin->w_width / 2;
+ /* FALLTHROUGH */
+
+ /* "zh" - scroll screen to the right */
+ case 'h':
+ case K_LEFT:
+ if (!curwin->w_p_wrap)
+ {
+ if ((colnr_T)cap->count1 > curwin->w_leftcol)
+ curwin->w_leftcol = 0;
+ else
+ curwin->w_leftcol -= (colnr_T)cap->count1;
+ leftcol_changed();
+ }
+ break;
+
+ /* "zL" - scroll screen left half-page */
+ case 'L': cap->count1 *= curwin->w_width / 2;
+ /* FALLTHROUGH */
+
+ /* "zl" - scroll screen to the left */
+ case 'l':
+ case K_RIGHT:
+ if (!curwin->w_p_wrap)
+ {
+ /* scroll the window left */
+ curwin->w_leftcol += (colnr_T)cap->count1;
+ leftcol_changed();
+ }
+ break;
+
+ /* "zs" - scroll screen, cursor at the start */
+ case 's': if (!curwin->w_p_wrap)
+ {
+#ifdef FEAT_FOLDING
+ if (hasFolding(curwin->w_cursor.lnum, NULL, NULL))
+ col = 0; /* like the cursor is in col 0 */
+ else
+#endif
+ getvcol(curwin, &curwin->w_cursor, &col, NULL, NULL);
+ if ((long)col > siso)
+ col -= siso;
+ else
+ col = 0;
+ if (curwin->w_leftcol != col)
+ {
+ curwin->w_leftcol = col;
+ redraw_later(NOT_VALID);
+ }
+ }
+ break;
+
+ /* "ze" - scroll screen, cursor at the end */
+ case 'e': if (!curwin->w_p_wrap)
+ {
+#ifdef FEAT_FOLDING
+ if (hasFolding(curwin->w_cursor.lnum, NULL, NULL))
+ col = 0; /* like the cursor is in col 0 */
+ else
+#endif
+ getvcol(curwin, &curwin->w_cursor, NULL, NULL, &col);
+ n = curwin->w_width - curwin_col_off();
+ if ((long)col + siso < n)
+ col = 0;
+ else
+ col = col + siso - n + 1;
+ if (curwin->w_leftcol != col)
+ {
+ curwin->w_leftcol = col;
+ redraw_later(NOT_VALID);
+ }
+ }
+ break;
+
+#ifdef FEAT_FOLDING
+ /* "zF": create fold command */
+ /* "zf": create fold operator */
+ case 'F':
+ case 'f': if (foldManualAllowed(TRUE))
+ {
+ cap->nchar = 'f';
+ nv_operator(cap);
+ curwin->w_p_fen = TRUE;
+
+ /* "zF" is like "zfzf" */
+ if (nchar == 'F' && cap->oap->op_type == OP_FOLD)
+ {
+ nv_operator(cap);
+ finish_op = TRUE;
+ }
+ }
+ else
+ clearopbeep(cap->oap);
+ break;
+
+ /* "zd": delete fold at cursor */
+ /* "zD": delete fold at cursor recursively */
+ case 'd':
+ case 'D': if (foldManualAllowed(FALSE))
+ {
+ if (VIsual_active)
+ nv_operator(cap);
+ else
+ deleteFold(curwin->w_cursor.lnum,
+ curwin->w_cursor.lnum, nchar == 'D', FALSE);
+ }
+ break;
+
+ /* "zE": erase all folds */
+ case 'E': if (foldmethodIsManual(curwin))
+ {
+ clearFolding(curwin);
+ changed_window_setting();
+ }
+ else if (foldmethodIsMarker(curwin))
+ deleteFold((linenr_T)1, curbuf->b_ml.ml_line_count,
+ TRUE, FALSE);
+ else
+ emsg(_("E352: Cannot erase folds with current 'foldmethod'"));
+ break;
+
+ /* "zn": fold none: reset 'foldenable' */
+ case 'n': curwin->w_p_fen = FALSE;
+ break;
+
+ /* "zN": fold Normal: set 'foldenable' */
+ case 'N': curwin->w_p_fen = TRUE;
+ break;
+
+ /* "zi": invert folding: toggle 'foldenable' */
+ case 'i': curwin->w_p_fen = !curwin->w_p_fen;
+ break;
+
+ /* "za": open closed fold or close open fold at cursor */
+ case 'a': if (hasFolding(curwin->w_cursor.lnum, NULL, NULL))
+ openFold(curwin->w_cursor.lnum, cap->count1);
+ else
+ {
+ closeFold(curwin->w_cursor.lnum, cap->count1);
+ curwin->w_p_fen = TRUE;
+ }
+ break;
+
+ /* "zA": open fold at cursor recursively */
+ case 'A': if (hasFolding(curwin->w_cursor.lnum, NULL, NULL))
+ openFoldRecurse(curwin->w_cursor.lnum);
+ else
+ {
+ closeFoldRecurse(curwin->w_cursor.lnum);
+ curwin->w_p_fen = TRUE;
+ }
+ break;
+
+ /* "zo": open fold at cursor or Visual area */
+ case 'o': if (VIsual_active)
+ nv_operator(cap);
+ else
+ openFold(curwin->w_cursor.lnum, cap->count1);
+ break;
+
+ /* "zO": open fold recursively */
+ case 'O': if (VIsual_active)
+ nv_operator(cap);
+ else
+ openFoldRecurse(curwin->w_cursor.lnum);
+ break;
+
+ /* "zc": close fold at cursor or Visual area */
+ case 'c': if (VIsual_active)
+ nv_operator(cap);
+ else
+ closeFold(curwin->w_cursor.lnum, cap->count1);
+ curwin->w_p_fen = TRUE;
+ break;
+
+ /* "zC": close fold recursively */
+ case 'C': if (VIsual_active)
+ nv_operator(cap);
+ else
+ closeFoldRecurse(curwin->w_cursor.lnum);
+ curwin->w_p_fen = TRUE;
+ break;
+
+ /* "zv": open folds at the cursor */
+ case 'v': foldOpenCursor();
+ break;
+
+ /* "zx": re-apply 'foldlevel' and open folds at the cursor */
+ case 'x': curwin->w_p_fen = TRUE;
+ curwin->w_foldinvalid = TRUE; /* recompute folds */
+ newFoldLevel(); /* update right now */
+ foldOpenCursor();
+ break;
+
+ /* "zX": undo manual opens/closes, re-apply 'foldlevel' */
+ case 'X': curwin->w_p_fen = TRUE;
+ curwin->w_foldinvalid = TRUE; /* recompute folds */
+ old_fdl = -1; /* force an update */
+ break;
+
+ /* "zm": fold more */
+ case 'm': if (curwin->w_p_fdl > 0)
+ {
+ curwin->w_p_fdl -= cap->count1;
+ if (curwin->w_p_fdl < 0)
+ curwin->w_p_fdl = 0;
+ }
+ old_fdl = -1; /* force an update */
+ curwin->w_p_fen = TRUE;
+ break;
+
+ /* "zM": close all folds */
+ case 'M': curwin->w_p_fdl = 0;
+ old_fdl = -1; /* force an update */
+ curwin->w_p_fen = TRUE;
+ break;
+
+ /* "zr": reduce folding */
+ case 'r': curwin->w_p_fdl += cap->count1;
+ {
+ int d = getDeepestNesting();
+
+ if (curwin->w_p_fdl >= d)
+ curwin->w_p_fdl = d;
+ }
+ break;
+
+ /* "zR": open all folds */
+ case 'R': curwin->w_p_fdl = getDeepestNesting();
+ old_fdl = -1; /* force an update */
+ break;
+
+ case 'j': /* "zj" move to next fold downwards */
+ case 'k': /* "zk" move to next fold upwards */
+ if (foldMoveTo(TRUE, nchar == 'j' ? FORWARD : BACKWARD,
+ cap->count1) == FAIL)
+ clearopbeep(cap->oap);
+ break;
+
+#endif /* FEAT_FOLDING */
+
+#ifdef FEAT_SPELL
+ case 'u': /* "zug" and "zuw": undo "zg" and "zw" */
+ ++no_mapping;
+ ++allow_keys; /* no mapping for nchar, but allow key codes */
+ nchar = plain_vgetc();
+ LANGMAP_ADJUST(nchar, TRUE);
+ --no_mapping;
+ --allow_keys;
+#ifdef FEAT_CMDL_INFO
+ (void)add_to_showcmd(nchar);
+#endif
+ if (vim_strchr((char_u *)"gGwW", nchar) == NULL)
+ {
+ clearopbeep(cap->oap);
+ break;
+ }
+ undo = TRUE;
+ /* FALLTHROUGH */
+
+ case 'g': /* "zg": add good word to word list */
+ case 'w': /* "zw": add wrong word to word list */
+ case 'G': /* "zG": add good word to temp word list */
+ case 'W': /* "zW": add wrong word to temp word list */
+ {
+ char_u *ptr = NULL;
+ int len;
+
+ if (checkclearop(cap->oap))
+ break;
+ if (VIsual_active && get_visual_text(cap, &ptr, &len)
+ == FAIL)
+ return;
+ if (ptr == NULL)
+ {
+ pos_T pos = curwin->w_cursor;
+
+ /* Find bad word under the cursor. When 'spell' is
+ * off this fails and find_ident_under_cursor() is
+ * used below. */
+ emsg_off++;
+ len = spell_move_to(curwin, FORWARD, TRUE, TRUE, NULL);
+ emsg_off--;
+ if (len != 0 && curwin->w_cursor.col <= pos.col)
+ ptr = ml_get_pos(&curwin->w_cursor);
+ curwin->w_cursor = pos;
+ }
+
+ if (ptr == NULL && (len = find_ident_under_cursor(&ptr,
+ FIND_IDENT)) == 0)
+ return;
+ spell_add_word(ptr, len, nchar == 'w' || nchar == 'W',
+ (nchar == 'G' || nchar == 'W')
+ ? 0 : (int)cap->count1,
+ undo);
+ }
+ break;
+
+ case '=': /* "z=": suggestions for a badly spelled word */
+ if (!checkclearop(cap->oap))
+ spell_suggest((int)cap->count0);
+ break;
+#endif
+
+ default: clearopbeep(cap->oap);
+ }
+
+#ifdef FEAT_FOLDING
+ /* Redraw when 'foldenable' changed */
+ if (old_fen != curwin->w_p_fen)
+ {
+# ifdef FEAT_DIFF
+ win_T *wp;
+
+ if (foldmethodIsDiff(curwin) && curwin->w_p_scb)
+ {
+ /* Adjust 'foldenable' in diff-synced windows. */
+ FOR_ALL_WINDOWS(wp)
+ {
+ if (wp != curwin && foldmethodIsDiff(wp) && wp->w_p_scb)
+ {
+ wp->w_p_fen = curwin->w_p_fen;
+ changed_window_setting_win(wp);
+ }
+ }
+ }
+# endif
+ changed_window_setting();
+ }
+
+ /* Redraw when 'foldlevel' changed. */
+ if (old_fdl != curwin->w_p_fdl)
+ newFoldLevel();
+#endif
+}
+
+#ifdef FEAT_GUI
+/*
+ * Vertical scrollbar movement.
+ */
+ static void
+nv_ver_scrollbar(cmdarg_T *cap)
+{
+ if (cap->oap->op_type != OP_NOP)
+ clearopbeep(cap->oap);
+
+ /* Even if an operator was pending, we still want to scroll */
+ gui_do_scroll();
+}
+
+/*
+ * Horizontal scrollbar movement.
+ */
+ static void
+nv_hor_scrollbar(cmdarg_T *cap)
+{
+ if (cap->oap->op_type != OP_NOP)
+ clearopbeep(cap->oap);
+
+ /* Even if an operator was pending, we still want to scroll */
+ gui_do_horiz_scroll(scrollbar_value, FALSE);
+}
+#endif
+
+#if defined(FEAT_GUI_TABLINE) || defined(PROTO)
+/*
+ * Click in GUI tab.
+ */
+ static void
+nv_tabline(cmdarg_T *cap)
+{
+ if (cap->oap->op_type != OP_NOP)
+ clearopbeep(cap->oap);
+
+ /* Even if an operator was pending, we still want to jump tabs. */
+ goto_tabpage(current_tab);
+}
+
+/*
+ * Selected item in tab line menu.
+ */
+ static void
+nv_tabmenu(cmdarg_T *cap)
+{
+ if (cap->oap->op_type != OP_NOP)
+ clearopbeep(cap->oap);
+
+ /* Even if an operator was pending, we still want to jump tabs. */
+ handle_tabmenu();
+}
+
+/*
+ * Handle selecting an item of the GUI tab line menu.
+ * Used in Normal and Insert mode.
+ */
+ void
+handle_tabmenu(void)
+{
+ switch (current_tabmenu)
+ {
+ case TABLINE_MENU_CLOSE:
+ if (current_tab == 0)
+ do_cmdline_cmd((char_u *)"tabclose");
+ else
+ {
+ vim_snprintf((char *)IObuff, IOSIZE, "tabclose %d",
+ current_tab);
+ do_cmdline_cmd(IObuff);
+ }
+ break;
+
+ case TABLINE_MENU_NEW:
+ if (current_tab == 0)
+ do_cmdline_cmd((char_u *)"$tabnew");
+ else
+ {
+ vim_snprintf((char *)IObuff, IOSIZE, "%dtabnew",
+ current_tab - 1);
+ do_cmdline_cmd(IObuff);
+ }
+ break;
+
+ case TABLINE_MENU_OPEN:
+ if (current_tab == 0)
+ do_cmdline_cmd((char_u *)"browse $tabnew");
+ else
+ {
+ vim_snprintf((char *)IObuff, IOSIZE, "browse %dtabnew",
+ current_tab - 1);
+ do_cmdline_cmd(IObuff);
+ }
+ break;
+ }
+}
+#endif
+
+/*
+ * "Q" command.
+ */
+ static void
+nv_exmode(cmdarg_T *cap)
+{
+ /*
+ * Ignore 'Q' in Visual mode, just give a beep.
+ */
+ if (VIsual_active)
+ vim_beep(BO_EX);
+ else if (!checkclearop(cap->oap))
+ do_exmode(FALSE);
+}
+
+/*
+ * Handle a ":" command.
+ */
+ static void
+nv_colon(cmdarg_T *cap)
+{
+ int old_p_im;
+ int cmd_result;
+
+ if (VIsual_active)
+ nv_operator(cap);
+ else
+ {
+ if (cap->oap->op_type != OP_NOP)
+ {
+ /* Using ":" as a movement is characterwise exclusive. */
+ cap->oap->motion_type = MCHAR;
+ cap->oap->inclusive = FALSE;
+ }
+ else if (cap->count0)
+ {
+ /* translate "count:" into ":.,.+(count - 1)" */
+ stuffcharReadbuff('.');
+ if (cap->count0 > 1)
+ {
+ stuffReadbuff((char_u *)",.+");
+ stuffnumReadbuff((long)cap->count0 - 1L);
+ }
+ }
+
+ /* When typing, don't type below an old message */
+ if (KeyTyped)
+ compute_cmdrow();
+
+ old_p_im = p_im;
+
+ /* get a command line and execute it */
+ cmd_result = do_cmdline(NULL, getexline, NULL,
+ cap->oap->op_type != OP_NOP ? DOCMD_KEEPLINE : 0);
+
+ /* If 'insertmode' changed, enter or exit Insert mode */
+ if (p_im != old_p_im)
+ {
+ if (p_im)
+ restart_edit = 'i';
+ else
+ restart_edit = 0;
+ }
+
+ if (cmd_result == FAIL)
+ /* The Ex command failed, do not execute the operator. */
+ clearop(cap->oap);
+ else if (cap->oap->op_type != OP_NOP
+ && (cap->oap->start.lnum > curbuf->b_ml.ml_line_count
+ || cap->oap->start.col >
+ (colnr_T)STRLEN(ml_get(cap->oap->start.lnum))
+ || did_emsg
+ ))
+ /* The start of the operator has become invalid by the Ex command.
+ */
+ clearopbeep(cap->oap);
+ }
+}
+
+/*
+ * Handle CTRL-G command.
+ */
+ static void
+nv_ctrlg(cmdarg_T *cap)
+{
+ if (VIsual_active) /* toggle Selection/Visual mode */
+ {
+ VIsual_select = !VIsual_select;
+ showmode();
+ }
+ else if (!checkclearop(cap->oap))
+ /* print full name if count given or :cd used */
+ fileinfo((int)cap->count0, FALSE, TRUE);
+}
+
+/*
+ * Handle CTRL-H <Backspace> command.
+ */
+ static void
+nv_ctrlh(cmdarg_T *cap)
+{
+ if (VIsual_active && VIsual_select)
+ {
+ cap->cmdchar = 'x'; /* BS key behaves like 'x' in Select mode */
+ v_visop(cap);
+ }
+ else
+ nv_left(cap);
+}
+
+/*
+ * CTRL-L: clear screen and redraw.
+ */
+ static void
+nv_clear(cmdarg_T *cap)
+{
+ if (!checkclearop(cap->oap))
+ {
+#if defined(__BEOS__) && !USE_THREAD_FOR_INPUT_WITH_TIMEOUT
+ /*
+ * Right now, the BeBox doesn't seem to have an easy way to detect
+ * window resizing, so we cheat and make the user detect it
+ * manually with CTRL-L instead
+ */
+ ui_get_shellsize();
+#endif
+#ifdef FEAT_SYN_HL
+ /* Clear all syntax states to force resyncing. */
+ syn_stack_free_all(curwin->w_s);
+# ifdef FEAT_RELTIME
+ {
+ win_T *wp;
+
+ FOR_ALL_WINDOWS(wp)
+ wp->w_s->b_syn_slow = FALSE;
+ }
+# endif
+#endif
+ redraw_later(CLEAR);
+ }
+}
+
+/*
+ * CTRL-O: In Select mode: switch to Visual mode for one command.
+ * Otherwise: Go to older pcmark.
+ */
+ static void
+nv_ctrlo(cmdarg_T *cap)
+{
+ if (VIsual_active && VIsual_select)
+ {
+ VIsual_select = FALSE;
+ showmode();
+ restart_VIsual_select = 2; /* restart Select mode later */
+ }
+ else
+ {
+ cap->count1 = -cap->count1;
+ nv_pcmark(cap);
+ }
+}
+
+/*
+ * CTRL-^ command, short for ":e #". Works even when the alternate buffer is
+ * not named.
+ */
+ static void
+nv_hat(cmdarg_T *cap)
+{
+ if (!checkclearopq(cap->oap))
+ (void)buflist_getfile((int)cap->count0, (linenr_T)0,
+ GETF_SETMARK|GETF_ALT, FALSE);
+}
+
+/*
+ * "Z" commands.
+ */
+ static void
+nv_Zet(cmdarg_T *cap)
+{
+ if (!checkclearopq(cap->oap))
+ {
+ switch (cap->nchar)
+ {
+ /* "ZZ": equivalent to ":x". */
+ case 'Z': do_cmdline_cmd((char_u *)"x");
+ break;
+
+ /* "ZQ": equivalent to ":q!" (Elvis compatible). */
+ case 'Q': do_cmdline_cmd((char_u *)"q!");
+ break;
+
+ default: clearopbeep(cap->oap);
+ }
+ }
+}
+
+/*
+ * Call nv_ident() as if "c1" was used, with "c2" as next character.
+ */
+ void
+do_nv_ident(int c1, int c2)
+{
+ oparg_T oa;
+ cmdarg_T ca;
+
+ clear_oparg(&oa);
+ vim_memset(&ca, 0, sizeof(ca));
+ ca.oap = &oa;
+ ca.cmdchar = c1;
+ ca.nchar = c2;
+ nv_ident(&ca);
+}
+
+/*
+ * Handle the commands that use the word under the cursor.
+ * [g] CTRL-] :ta to current identifier
+ * [g] 'K' run program for current identifier
+ * [g] '*' / to current identifier or string
+ * [g] '#' ? to current identifier or string
+ * g ']' :tselect for current identifier
+ */
+ static void
+nv_ident(cmdarg_T *cap)
+{
+ char_u *ptr = NULL;
+ char_u *buf;
+ unsigned buflen;
+ char_u *newbuf;
+ char_u *p;
+ char_u *kp; /* value of 'keywordprg' */
+ int kp_help; /* 'keywordprg' is ":he" */
+ int kp_ex; /* 'keywordprg' starts with ":" */
+ int n = 0; /* init for GCC */
+ int cmdchar;
+ int g_cmd; /* "g" command */
+ int tag_cmd = FALSE;
+ char_u *aux_ptr;
+ int isman;
+ int isman_s;
+
+ if (cap->cmdchar == 'g') /* "g*", "g#", "g]" and "gCTRL-]" */
+ {
+ cmdchar = cap->nchar;
+ g_cmd = TRUE;
+ }
+ else
+ {
+ cmdchar = cap->cmdchar;
+ g_cmd = FALSE;
+ }
+
+ if (cmdchar == POUND) /* the pound sign, '#' for English keyboards */
+ cmdchar = '#';
+
+ /*
+ * The "]", "CTRL-]" and "K" commands accept an argument in Visual mode.
+ */
+ if (cmdchar == ']' || cmdchar == Ctrl_RSB || cmdchar == 'K')
+ {
+ if (VIsual_active && get_visual_text(cap, &ptr, &n) == FAIL)
+ return;
+ if (checkclearopq(cap->oap))
+ return;
+ }
+
+ if (ptr == NULL && (n = find_ident_under_cursor(&ptr,
+ (cmdchar == '*' || cmdchar == '#')
+ ? FIND_IDENT|FIND_STRING : FIND_IDENT)) == 0)
+ {
+ clearop(cap->oap);
+ return;
+ }
+
+ /* Allocate buffer to put the command in. Inserting backslashes can
+ * double the length of the word. p_kp / curbuf->b_p_kp could be added
+ * and some numbers. */
+ kp = (*curbuf->b_p_kp == NUL ? p_kp : curbuf->b_p_kp);
+ kp_help = (*kp == NUL || STRCMP(kp, ":he") == 0
+ || STRCMP(kp, ":help") == 0);
+ if (kp_help && *skipwhite(ptr) == NUL)
+ {
+ emsg(_(e_noident)); /* found white space only */
+ return;
+ }
+ kp_ex = (*kp == ':');
+ buflen = (unsigned)(n * 2 + 30 + STRLEN(kp));
+ buf = alloc(buflen);
+ if (buf == NULL)
+ return;
+ buf[0] = NUL;
+
+ switch (cmdchar)
+ {
+ case '*':
+ case '#':
+ /*
+ * Put cursor at start of word, makes search skip the word
+ * under the cursor.
+ * Call setpcmark() first, so "*``" puts the cursor back where
+ * it was.
+ */
+ setpcmark();
+ curwin->w_cursor.col = (colnr_T) (ptr - ml_get_curline());
+
+ if (!g_cmd && vim_iswordp(ptr))
+ STRCPY(buf, "\\<");
+ no_smartcase = TRUE; /* don't use 'smartcase' now */
+ break;
+
+ case 'K':
+ if (kp_help)
+ STRCPY(buf, "he! ");
+ else if (kp_ex)
+ {
+ if (cap->count0 != 0)
+ vim_snprintf((char *)buf, buflen, "%s %ld",
+ kp, cap->count0);
+ else
+ STRCPY(buf, kp);
+ STRCAT(buf, " ");
+ }
+ else
+ {
+ /* An external command will probably use an argument starting
+ * with "-" as an option. To avoid trouble we skip the "-". */
+ while (*ptr == '-' && n > 0)
+ {
+ ++ptr;
+ --n;
+ }
+ if (n == 0)
+ {
+ emsg(_(e_noident)); /* found dashes only */
+ vim_free(buf);
+ return;
+ }
+
+ /* When a count is given, turn it into a range. Is this
+ * really what we want? */
+ isman = (STRCMP(kp, "man") == 0);
+ isman_s = (STRCMP(kp, "man -s") == 0);
+ if (cap->count0 != 0 && !(isman || isman_s))
+ sprintf((char *)buf, ".,.+%ld", cap->count0 - 1);
+
+ STRCAT(buf, "! ");
+ if (cap->count0 == 0 && isman_s)
+ STRCAT(buf, "man");
+ else
+ STRCAT(buf, kp);
+ STRCAT(buf, " ");
+ if (cap->count0 != 0 && (isman || isman_s))
+ {
+ sprintf((char *)buf + STRLEN(buf), "%ld", cap->count0);
+ STRCAT(buf, " ");
+ }
+ }
+ break;
+
+ case ']':
+ tag_cmd = TRUE;
+#ifdef FEAT_CSCOPE
+ if (p_cst)
+ STRCPY(buf, "cstag ");
+ else
+#endif
+ STRCPY(buf, "ts ");
+ break;
+
+ default:
+ tag_cmd = TRUE;
+ if (curbuf->b_help)
+ STRCPY(buf, "he! ");
+ else
+ {
+ if (g_cmd)
+ STRCPY(buf, "tj ");
+ else
+ sprintf((char *)buf, "%ldta ", cap->count0);
+ }
+ }
+
+ /*
+ * Now grab the chars in the identifier
+ */
+ if (cmdchar == 'K' && !kp_help)
+ {
+ ptr = vim_strnsave(ptr, n);
+ if (kp_ex)
+ /* Escape the argument properly for an Ex command */
+ p = vim_strsave_fnameescape(ptr, FALSE);
+ else
+ /* Escape the argument properly for a shell command */
+ p = vim_strsave_shellescape(ptr, TRUE, TRUE);
+ vim_free(ptr);
+ if (p == NULL)
+ {
+ vim_free(buf);
+ return;
+ }
+ newbuf = (char_u *)vim_realloc(buf, STRLEN(buf) + STRLEN(p) + 1);
+ if (newbuf == NULL)
+ {
+ vim_free(buf);
+ vim_free(p);
+ return;
+ }
+ buf = newbuf;
+ STRCAT(buf, p);
+ vim_free(p);
+ }
+ else
+ {
+ if (cmdchar == '*')
+ aux_ptr = (char_u *)(p_magic ? "/.*~[^$\\" : "/^$\\");
+ else if (cmdchar == '#')
+ aux_ptr = (char_u *)(p_magic ? "/?.*~[^$\\" : "/?^$\\");
+ else if (tag_cmd)
+ {
+ if (curbuf->b_help)
+ /* ":help" handles unescaped argument */
+ aux_ptr = (char_u *)"";
+ else
+ aux_ptr = (char_u *)"\\|\"\n[";
+ }
+ else
+ aux_ptr = (char_u *)"\\|\"\n*?[";
+
+ p = buf + STRLEN(buf);
+ while (n-- > 0)
+ {
+ /* put a backslash before \ and some others */
+ if (vim_strchr(aux_ptr, *ptr) != NULL)
+ *p++ = '\\';
+ /* When current byte is a part of multibyte character, copy all
+ * bytes of that character. */
+ if (has_mbyte)
+ {
+ int i;
+ int len = (*mb_ptr2len)(ptr) - 1;
+
+ for (i = 0; i < len && n >= 1; ++i, --n)
+ *p++ = *ptr++;
+ }
+ *p++ = *ptr++;
+ }
+ *p = NUL;
+ }
+
+ /*
+ * Execute the command.
+ */
+ if (cmdchar == '*' || cmdchar == '#')
+ {
+ if (!g_cmd && (has_mbyte
+ ? vim_iswordp(mb_prevptr(ml_get_curline(), ptr))
+ : vim_iswordc(ptr[-1])))
+ STRCAT(buf, "\\>");
+#ifdef FEAT_CMDHIST
+ /* put pattern in search history */
+ init_history();
+ add_to_history(HIST_SEARCH, buf, TRUE, NUL);
+#endif
+ (void)normal_search(cap, cmdchar == '*' ? '/' : '?', buf, 0);
+ }
+ else
+ do_cmdline_cmd(buf);
+
+ vim_free(buf);
+}
+
+/*
+ * Get visually selected text, within one line only.
+ * Returns FAIL if more than one line selected.
+ */
+ int
+get_visual_text(
+ cmdarg_T *cap,
+ char_u **pp, /* return: start of selected text */
+ int *lenp) /* return: length of selected text */
+{
+ if (VIsual_mode != 'V')
+ unadjust_for_sel();
+ if (VIsual.lnum != curwin->w_cursor.lnum)
+ {
+ if (cap != NULL)
+ clearopbeep(cap->oap);
+ return FAIL;
+ }
+ if (VIsual_mode == 'V')
+ {
+ *pp = ml_get_curline();
+ *lenp = (int)STRLEN(*pp);
+ }
+ else
+ {
+ if (LT_POS(curwin->w_cursor, VIsual))
+ {
+ *pp = ml_get_pos(&curwin->w_cursor);
+ *lenp = VIsual.col - curwin->w_cursor.col + 1;
+ }
+ else
+ {
+ *pp = ml_get_pos(&VIsual);
+ *lenp = curwin->w_cursor.col - VIsual.col + 1;
+ }
+ if (has_mbyte)
+ /* Correct the length to include the whole last character. */
+ *lenp += (*mb_ptr2len)(*pp + (*lenp - 1)) - 1;
+ }
+ reset_VIsual_and_resel();
+ return OK;
+}
+
+/*
+ * CTRL-T: backwards in tag stack
+ */
+ static void
+nv_tagpop(cmdarg_T *cap)
+{
+ if (!checkclearopq(cap->oap))
+ do_tag((char_u *)"", DT_POP, (int)cap->count1, FALSE, TRUE);
+}
+
+/*
+ * Handle scrolling command 'H', 'L' and 'M'.
+ */
+ static void
+nv_scroll(cmdarg_T *cap)
+{
+ int used = 0;
+ long n;
+#ifdef FEAT_FOLDING
+ linenr_T lnum;
+#endif
+ int half;
+
+ cap->oap->motion_type = MLINE;
+ setpcmark();
+
+ if (cap->cmdchar == 'L')
+ {
+ validate_botline(); /* make sure curwin->w_botline is valid */
+ curwin->w_cursor.lnum = curwin->w_botline - 1;
+ if (cap->count1 - 1 >= curwin->w_cursor.lnum)
+ curwin->w_cursor.lnum = 1;
+ else
+ {
+#ifdef FEAT_FOLDING
+ if (hasAnyFolding(curwin))
+ {
+ /* Count a fold for one screen line. */
+ for (n = cap->count1 - 1; n > 0
+ && curwin->w_cursor.lnum > curwin->w_topline; --n)
+ {
+ (void)hasFolding(curwin->w_cursor.lnum,
+ &curwin->w_cursor.lnum, NULL);
+ --curwin->w_cursor.lnum;
+ }
+ }
+ else
+#endif
+ curwin->w_cursor.lnum -= cap->count1 - 1;
+ }
+ }
+ else
+ {
+ if (cap->cmdchar == 'M')
+ {
+#ifdef FEAT_DIFF
+ /* Don't count filler lines above the window. */
+ used -= diff_check_fill(curwin, curwin->w_topline)
+ - curwin->w_topfill;
+#endif
+ validate_botline(); /* make sure w_empty_rows is valid */
+ half = (curwin->w_height - curwin->w_empty_rows + 1) / 2;
+ for (n = 0; curwin->w_topline + n < curbuf->b_ml.ml_line_count; ++n)
+ {
+#ifdef FEAT_DIFF
+ /* Count half he number of filler lines to be "below this
+ * line" and half to be "above the next line". */
+ if (n > 0 && used + diff_check_fill(curwin, curwin->w_topline
+ + n) / 2 >= half)
+ {
+ --n;
+ break;
+ }
+#endif
+ used += plines(curwin->w_topline + n);
+ if (used >= half)
+ break;
+#ifdef FEAT_FOLDING
+ if (hasFolding(curwin->w_topline + n, NULL, &lnum))
+ n = lnum - curwin->w_topline;
+#endif
+ }
+ if (n > 0 && used > curwin->w_height)
+ --n;
+ }
+ else /* (cap->cmdchar == 'H') */
+ {
+ n = cap->count1 - 1;
+#ifdef FEAT_FOLDING
+ if (hasAnyFolding(curwin))
+ {
+ /* Count a fold for one screen line. */
+ lnum = curwin->w_topline;
+ while (n-- > 0 && lnum < curwin->w_botline - 1)
+ {
+ (void)hasFolding(lnum, NULL, &lnum);
+ ++lnum;
+ }
+ n = lnum - curwin->w_topline;
+ }
+#endif
+ }
+ curwin->w_cursor.lnum = curwin->w_topline + n;
+ if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
+ curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
+ }
+
+ /* Correct for 'so', except when an operator is pending. */
+ if (cap->oap->op_type == OP_NOP)
+ cursor_correct();
+ beginline(BL_SOL | BL_FIX);
+}
+
+/*
+ * Cursor right commands.
+ */
+ static void
+nv_right(cmdarg_T *cap)
+{
+ long n;
+ int past_line;
+
+ if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL))
+ {
+ /* <C-Right> and <S-Right> move a word or WORD right */
+ if (mod_mask & MOD_MASK_CTRL)
+ cap->arg = TRUE;
+ nv_wordcmd(cap);
+ return;
+ }
+
+ cap->oap->motion_type = MCHAR;
+ cap->oap->inclusive = FALSE;
+ past_line = (VIsual_active && *p_sel != 'o');
+
+ /*
+ * In virtual edit mode, there's no such thing as "past_line", as lines
+ * are (theoretically) infinitely long.
+ */
+ if (virtual_active())
+ past_line = 0;
+
+ for (n = cap->count1; n > 0; --n)
+ {
+ if ((!past_line && oneright() == FAIL)
+ || (past_line && *ml_get_cursor() == NUL)
+ )
+ {
+ /*
+ * <Space> wraps to next line if 'whichwrap' has 's'.
+ * 'l' wraps to next line if 'whichwrap' has 'l'.
+ * CURS_RIGHT wraps to next line if 'whichwrap' has '>'.
+ */
+ if ( ((cap->cmdchar == ' '
+ && vim_strchr(p_ww, 's') != NULL)
+ || (cap->cmdchar == 'l'
+ && vim_strchr(p_ww, 'l') != NULL)
+ || (cap->cmdchar == K_RIGHT
+ && vim_strchr(p_ww, '>') != NULL))
+ && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
+ {
+ /* When deleting we also count the NL as a character.
+ * Set cap->oap->inclusive when last char in the line is
+ * included, move to next line after that */
+ if ( cap->oap->op_type != OP_NOP
+ && !cap->oap->inclusive
+ && !LINEEMPTY(curwin->w_cursor.lnum))
+ cap->oap->inclusive = TRUE;
+ else
+ {
+ ++curwin->w_cursor.lnum;
+ curwin->w_cursor.col = 0;
+ curwin->w_cursor.coladd = 0;
+ curwin->w_set_curswant = TRUE;
+ cap->oap->inclusive = FALSE;
+ }
+ continue;
+ }
+ if (cap->oap->op_type == OP_NOP)
+ {
+ /* Only beep and flush if not moved at all */
+ if (n == cap->count1)
+ beep_flush();
+ }
+ else
+ {
+ if (!LINEEMPTY(curwin->w_cursor.lnum))
+ cap->oap->inclusive = TRUE;
+ }
+ break;
+ }
+ else if (past_line)
+ {
+ curwin->w_set_curswant = TRUE;
+ if (virtual_active())
+ oneright();
+ else
+ {
+ if (has_mbyte)
+ curwin->w_cursor.col +=
+ (*mb_ptr2len)(ml_get_cursor());
+ else
+ ++curwin->w_cursor.col;
+ }
+ }
+ }
+#ifdef FEAT_FOLDING
+ if (n != cap->count1 && (fdo_flags & FDO_HOR) && KeyTyped
+ && cap->oap->op_type == OP_NOP)
+ foldOpenCursor();
+#endif
+}
+
+/*
+ * Cursor left commands.
+ *
+ * Returns TRUE when operator end should not be adjusted.
+ */
+ static void
+nv_left(cmdarg_T *cap)
+{
+ long n;
+
+ if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL))
+ {
+ /* <C-Left> and <S-Left> move a word or WORD left */
+ if (mod_mask & MOD_MASK_CTRL)
+ cap->arg = 1;
+ nv_bck_word(cap);
+ return;
+ }
+
+ cap->oap->motion_type = MCHAR;
+ cap->oap->inclusive = FALSE;
+ for (n = cap->count1; n > 0; --n)
+ {
+ if (oneleft() == FAIL)
+ {
+ /* <BS> and <Del> wrap to previous line if 'whichwrap' has 'b'.
+ * 'h' wraps to previous line if 'whichwrap' has 'h'.
+ * CURS_LEFT wraps to previous line if 'whichwrap' has '<'.
+ */
+ if ( (((cap->cmdchar == K_BS
+ || cap->cmdchar == Ctrl_H)
+ && vim_strchr(p_ww, 'b') != NULL)
+ || (cap->cmdchar == 'h'
+ && vim_strchr(p_ww, 'h') != NULL)
+ || (cap->cmdchar == K_LEFT
+ && vim_strchr(p_ww, '<') != NULL))
+ && curwin->w_cursor.lnum > 1)
+ {
+ --(curwin->w_cursor.lnum);
+ coladvance((colnr_T)MAXCOL);
+ curwin->w_set_curswant = TRUE;
+
+ /* When the NL before the first char has to be deleted we
+ * put the cursor on the NUL after the previous line.
+ * This is a very special case, be careful!
+ * Don't adjust op_end now, otherwise it won't work. */
+ if ( (cap->oap->op_type == OP_DELETE
+ || cap->oap->op_type == OP_CHANGE)
+ && !LINEEMPTY(curwin->w_cursor.lnum))
+ {
+ char_u *cp = ml_get_cursor();
+
+ if (*cp != NUL)
+ {
+ if (has_mbyte)
+ curwin->w_cursor.col += (*mb_ptr2len)(cp);
+ else
+ ++curwin->w_cursor.col;
+ }
+ cap->retval |= CA_NO_ADJ_OP_END;
+ }
+ continue;
+ }
+ /* Only beep and flush if not moved at all */
+ else if (cap->oap->op_type == OP_NOP && n == cap->count1)
+ beep_flush();
+ break;
+ }
+ }
+#ifdef FEAT_FOLDING
+ if (n != cap->count1 && (fdo_flags & FDO_HOR) && KeyTyped
+ && cap->oap->op_type == OP_NOP)
+ foldOpenCursor();
+#endif
+}
+
+/*
+ * Cursor up commands.
+ * cap->arg is TRUE for "-": Move cursor to first non-blank.
+ */
+ static void
+nv_up(cmdarg_T *cap)
+{
+ if (mod_mask & MOD_MASK_SHIFT)
+ {
+ /* <S-Up> is page up */
+ cap->arg = BACKWARD;
+ nv_page(cap);
+ }
+ else
+ {
+ cap->oap->motion_type = MLINE;
+ if (cursor_up(cap->count1, cap->oap->op_type == OP_NOP) == FAIL)
+ clearopbeep(cap->oap);
+ else if (cap->arg)
+ beginline(BL_WHITE | BL_FIX);
+ }
+}
+
+/*
+ * Cursor down commands.
+ * cap->arg is TRUE for CR and "+": Move cursor to first non-blank.
+ */
+ static void
+nv_down(cmdarg_T *cap)
+{
+ if (mod_mask & MOD_MASK_SHIFT)
+ {
+ /* <S-Down> is page down */
+ cap->arg = FORWARD;
+ nv_page(cap);
+ }
+#if defined(FEAT_QUICKFIX)
+ /* Quickfix window only: view the result under the cursor. */
+ else if (bt_quickfix(curbuf) && cap->cmdchar == CAR)
+ qf_view_result(FALSE);
+#endif
+ else
+ {
+#ifdef FEAT_CMDWIN
+ /* In the cmdline window a <CR> executes the command. */
+ if (cmdwin_type != 0 && cap->cmdchar == CAR)
+ cmdwin_result = CAR;
+ else
+#endif
+#ifdef FEAT_JOB_CHANNEL
+ /* In a prompt buffer a <CR> in the last line invokes the callback. */
+ if (bt_prompt(curbuf) && cap->cmdchar == CAR
+ && curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count)
+ {
+ invoke_prompt_callback();
+ if (restart_edit == 0)
+ restart_edit = 'a';
+ }
+ else
+#endif
+ {
+ cap->oap->motion_type = MLINE;
+ if (cursor_down(cap->count1, cap->oap->op_type == OP_NOP) == FAIL)
+ clearopbeep(cap->oap);
+ else if (cap->arg)
+ beginline(BL_WHITE | BL_FIX);
+ }
+ }
+}
+
+#ifdef FEAT_SEARCHPATH
+/*
+ * Grab the file name under the cursor and edit it.
+ */
+ static void
+nv_gotofile(cmdarg_T *cap)
+{
+ char_u *ptr;
+ linenr_T lnum = -1;
+
+ if (text_locked())
+ {
+ clearopbeep(cap->oap);
+ text_locked_msg();
+ return;
+ }
+ if (curbuf_locked())
+ {
+ clearop(cap->oap);
+ return;
+ }
+
+ ptr = grab_file_name(cap->count1, &lnum);
+
+ if (ptr != NULL)
+ {
+ /* do autowrite if necessary */
+ if (curbufIsChanged() && curbuf->b_nwindows <= 1 && !buf_hide(curbuf))
+ (void)autowrite(curbuf, FALSE);
+ setpcmark();
+ if (do_ecmd(0, ptr, NULL, NULL, ECMD_LAST,
+ buf_hide(curbuf) ? ECMD_HIDE : 0, curwin) == OK
+ && cap->nchar == 'F' && lnum >= 0)
+ {
+ curwin->w_cursor.lnum = lnum;
+ check_cursor_lnum();
+ beginline(BL_SOL | BL_FIX);
+ }
+ vim_free(ptr);
+ }
+ else
+ clearop(cap->oap);
+}
+#endif
+
+/*
+ * <End> command: to end of current line or last line.
+ */
+ static void
+nv_end(cmdarg_T *cap)
+{
+ if (cap->arg || (mod_mask & MOD_MASK_CTRL)) /* CTRL-END = goto last line */
+ {
+ cap->arg = TRUE;
+ nv_goto(cap);
+ cap->count1 = 1; /* to end of current line */
+ }
+ nv_dollar(cap);
+}
+
+/*
+ * Handle the "$" command.
+ */
+ static void
+nv_dollar(cmdarg_T *cap)
+{
+ cap->oap->motion_type = MCHAR;
+ cap->oap->inclusive = TRUE;
+ /* In virtual mode when off the edge of a line and an operator
+ * is pending (whew!) keep the cursor where it is.
+ * Otherwise, send it to the end of the line. */
+ if (!virtual_active() || gchar_cursor() != NUL
+ || cap->oap->op_type == OP_NOP)
+ curwin->w_curswant = MAXCOL; /* so we stay at the end */
+ if (cursor_down((long)(cap->count1 - 1),
+ cap->oap->op_type == OP_NOP) == FAIL)
+ clearopbeep(cap->oap);
+#ifdef FEAT_FOLDING
+ else if ((fdo_flags & FDO_HOR) && KeyTyped && cap->oap->op_type == OP_NOP)
+ foldOpenCursor();
+#endif
+}
+
+/*
+ * Implementation of '?' and '/' commands.
+ * If cap->arg is TRUE don't set PC mark.
+ */
+ static void
+nv_search(cmdarg_T *cap)
+{
+ oparg_T *oap = cap->oap;
+ pos_T save_cursor = curwin->w_cursor;
+
+ if (cap->cmdchar == '?' && cap->oap->op_type == OP_ROT13)
+ {
+ /* Translate "g??" to "g?g?" */
+ cap->cmdchar = 'g';
+ cap->nchar = '?';
+ nv_operator(cap);
+ return;
+ }
+
+ /* When using 'incsearch' the cursor may be moved to set a different search
+ * start position. */
+ cap->searchbuf = getcmdline(cap->cmdchar, cap->count1, 0);
+
+ if (cap->searchbuf == NULL)
+ {
+ clearop(oap);
+ return;
+ }
+
+ (void)normal_search(cap, cap->cmdchar, cap->searchbuf,
+ (cap->arg || !EQUAL_POS(save_cursor, curwin->w_cursor))
+ ? 0 : SEARCH_MARK);
+}
+
+/*
+ * Handle "N" and "n" commands.
+ * cap->arg is SEARCH_REV for "N", 0 for "n".
+ */
+ static void
+nv_next(cmdarg_T *cap)
+{
+ pos_T old = curwin->w_cursor;
+ int i = normal_search(cap, 0, NULL, SEARCH_MARK | cap->arg);
+
+ if (i == 1 && EQUAL_POS(old, curwin->w_cursor))
+ {
+ /* Avoid getting stuck on the current cursor position, which can
+ * happen when an offset is given and the cursor is on the last char
+ * in the buffer: Repeat with count + 1. */
+ cap->count1 += 1;
+ (void)normal_search(cap, 0, NULL, SEARCH_MARK | cap->arg);
+ cap->count1 -= 1;
+ }
+}
+
+/*
+ * Search for "pat" in direction "dir" ('/' or '?', 0 for repeat).
+ * Uses only cap->count1 and cap->oap from "cap".
+ * Return 0 for failure, 1 for found, 2 for found and line offset added.
+ */
+ static int
+normal_search(
+ cmdarg_T *cap,
+ int dir,
+ char_u *pat,
+ int opt) /* extra flags for do_search() */
+{
+ int i;
+
+ cap->oap->motion_type = MCHAR;
+ cap->oap->inclusive = FALSE;
+ cap->oap->use_reg_one = TRUE;
+ curwin->w_set_curswant = TRUE;
+
+ i = do_search(cap->oap, dir, pat, cap->count1,
+ opt | SEARCH_OPT | SEARCH_ECHO | SEARCH_MSG, NULL, NULL);
+ if (i == 0)
+ clearop(cap->oap);
+ else
+ {
+ if (i == 2)
+ cap->oap->motion_type = MLINE;
+ curwin->w_cursor.coladd = 0;
+#ifdef FEAT_FOLDING
+ if (cap->oap->op_type == OP_NOP && (fdo_flags & FDO_SEARCH) && KeyTyped)
+ foldOpenCursor();
+#endif
+ }
+
+ /* "/$" will put the cursor after the end of the line, may need to
+ * correct that here */
+ check_cursor();
+ return i;
+}
+
+/*
+ * Character search commands.
+ * cap->arg is BACKWARD for 'F' and 'T', FORWARD for 'f' and 't', TRUE for
+ * ',' and FALSE for ';'.
+ * cap->nchar is NUL for ',' and ';' (repeat the search)
+ */
+ static void
+nv_csearch(cmdarg_T *cap)
+{
+ int t_cmd;
+
+ if (cap->cmdchar == 't' || cap->cmdchar == 'T')
+ t_cmd = TRUE;
+ else
+ t_cmd = FALSE;
+
+ cap->oap->motion_type = MCHAR;
+ if (IS_SPECIAL(cap->nchar) || searchc(cap, t_cmd) == FAIL)
+ clearopbeep(cap->oap);
+ else
+ {
+ curwin->w_set_curswant = TRUE;
+ /* Include a Tab for "tx" and for "dfx". */
+ if (gchar_cursor() == TAB && virtual_active() && cap->arg == FORWARD
+ && (t_cmd || cap->oap->op_type != OP_NOP))
+ {
+ colnr_T scol, ecol;
+
+ getvcol(curwin, &curwin->w_cursor, &scol, NULL, &ecol);
+ curwin->w_cursor.coladd = ecol - scol;
+ }
+ else
+ curwin->w_cursor.coladd = 0;
+ adjust_for_sel(cap);
+#ifdef FEAT_FOLDING
+ if ((fdo_flags & FDO_HOR) && KeyTyped && cap->oap->op_type == OP_NOP)
+ foldOpenCursor();
+#endif
+ }
+}
+
+/*
+ * "[" and "]" commands.
+ * cap->arg is BACKWARD for "[" and FORWARD for "]".
+ */
+ static void
+nv_brackets(cmdarg_T *cap)
+{
+ pos_T new_pos = {0, 0, 0};
+ pos_T prev_pos;
+ pos_T *pos = NULL; /* init for GCC */
+ pos_T old_pos; /* cursor position before command */
+ int flag;
+ long n;
+ int findc;
+ int c;
+
+ cap->oap->motion_type = MCHAR;
+ cap->oap->inclusive = FALSE;
+ old_pos = curwin->w_cursor;
+ curwin->w_cursor.coladd = 0; // TODO: don't do this for an error.
+
+#ifdef FEAT_SEARCHPATH
+ /*
+ * "[f" or "]f" : Edit file under the cursor (same as "gf")
+ */
+ if (cap->nchar == 'f')
+ nv_gotofile(cap);
+ else
+#endif
+
+#ifdef FEAT_FIND_ID
+ /*
+ * Find the occurrence(s) of the identifier or define under cursor
+ * in current and included files or jump to the first occurrence.
+ *
+ * search list jump
+ * fwd bwd fwd bwd fwd bwd
+ * identifier "]i" "[i" "]I" "[I" "]^I" "[^I"
+ * define "]d" "[d" "]D" "[D" "]^D" "[^D"
+ */
+ if (vim_strchr((char_u *)
+# ifdef EBCDIC
+ "iI\005dD\067",
+# else
+ "iI\011dD\004",
+# endif
+ cap->nchar) != NULL)
+ {
+ char_u *ptr;
+ int len;
+
+ if ((len = find_ident_under_cursor(&ptr, FIND_IDENT)) == 0)
+ clearop(cap->oap);
+ else
+ {
+ find_pattern_in_path(ptr, 0, len, TRUE,
+ cap->count0 == 0 ? !isupper(cap->nchar) : FALSE,
+ ((cap->nchar & 0xf) == ('d' & 0xf)) ? FIND_DEFINE : FIND_ANY,
+ cap->count1,
+ isupper(cap->nchar) ? ACTION_SHOW_ALL :
+ islower(cap->nchar) ? ACTION_SHOW : ACTION_GOTO,
+ cap->cmdchar == ']' ? curwin->w_cursor.lnum + 1 : (linenr_T)1,
+ (linenr_T)MAXLNUM);
+ curwin->w_set_curswant = TRUE;
+ }
+ }
+ else
+#endif
+
+ /*
+ * "[{", "[(", "]}" or "])": go to Nth unclosed '{', '(', '}' or ')'
+ * "[#", "]#": go to start/end of Nth innermost #if..#endif construct.
+ * "[/", "[*", "]/", "]*": go to Nth comment start/end.
+ * "[m" or "]m" search for prev/next start of (Java) method.
+ * "[M" or "]M" search for prev/next end of (Java) method.
+ */
+ if ( (cap->cmdchar == '['
+ && vim_strchr((char_u *)"{(*/#mM", cap->nchar) != NULL)
+ || (cap->cmdchar == ']'
+ && vim_strchr((char_u *)"})*/#mM", cap->nchar) != NULL))
+ {
+ if (cap->nchar == '*')
+ cap->nchar = '/';
+ prev_pos.lnum = 0;
+ if (cap->nchar == 'm' || cap->nchar == 'M')
+ {
+ if (cap->cmdchar == '[')
+ findc = '{';
+ else
+ findc = '}';
+ n = 9999;
+ }
+ else
+ {
+ findc = cap->nchar;
+ n = cap->count1;
+ }
+ for ( ; n > 0; --n)
+ {
+ if ((pos = findmatchlimit(cap->oap, findc,
+ (cap->cmdchar == '[') ? FM_BACKWARD : FM_FORWARD, 0)) == NULL)
+ {
+ if (new_pos.lnum == 0) /* nothing found */
+ {
+ if (cap->nchar != 'm' && cap->nchar != 'M')
+ clearopbeep(cap->oap);
+ }
+ else
+ pos = &new_pos; /* use last one found */
+ break;
+ }
+ prev_pos = new_pos;
+ curwin->w_cursor = *pos;
+ new_pos = *pos;
+ }
+ curwin->w_cursor = old_pos;
+
+ /*
+ * Handle "[m", "]m", "[M" and "[M". The findmatchlimit() only
+ * brought us to the match for "[m" and "]M" when inside a method.
+ * Try finding the '{' or '}' we want to be at.
+ * Also repeat for the given count.
+ */
+ if (cap->nchar == 'm' || cap->nchar == 'M')
+ {
+ /* norm is TRUE for "]M" and "[m" */
+ int norm = ((findc == '{') == (cap->nchar == 'm'));
+
+ n = cap->count1;
+ /* found a match: we were inside a method */
+ if (prev_pos.lnum != 0)
+ {
+ pos = &prev_pos;
+ curwin->w_cursor = prev_pos;
+ if (norm)
+ --n;
+ }
+ else
+ pos = NULL;
+ while (n > 0)
+ {
+ for (;;)
+ {
+ if ((findc == '{' ? dec_cursor() : inc_cursor()) < 0)
+ {
+ /* if not found anything, that's an error */
+ if (pos == NULL)
+ clearopbeep(cap->oap);
+ n = 0;
+ break;
+ }
+ c = gchar_cursor();
+ if (c == '{' || c == '}')
+ {
+ /* Must have found end/start of class: use it.
+ * Or found the place to be at. */
+ if ((c == findc && norm) || (n == 1 && !norm))
+ {
+ new_pos = curwin->w_cursor;
+ pos = &new_pos;
+ n = 0;
+ }
+ /* if no match found at all, we started outside of the
+ * class and we're inside now. Just go on. */
+ else if (new_pos.lnum == 0)
+ {
+ new_pos = curwin->w_cursor;
+ pos = &new_pos;
+ }
+ /* found start/end of other method: go to match */
+ else if ((pos = findmatchlimit(cap->oap, findc,
+ (cap->cmdchar == '[') ? FM_BACKWARD : FM_FORWARD,
+ 0)) == NULL)
+ n = 0;
+ else
+ curwin->w_cursor = *pos;
+ break;
+ }
+ }
+ --n;
+ }
+ curwin->w_cursor = old_pos;
+ if (pos == NULL && new_pos.lnum != 0)
+ clearopbeep(cap->oap);
+ }
+ if (pos != NULL)
+ {
+ setpcmark();
+ curwin->w_cursor = *pos;
+ curwin->w_set_curswant = TRUE;
+#ifdef FEAT_FOLDING
+ if ((fdo_flags & FDO_BLOCK) && KeyTyped
+ && cap->oap->op_type == OP_NOP)
+ foldOpenCursor();
+#endif
+ }
+ }
+
+ /*
+ * "[[", "[]", "]]" and "][": move to start or end of function
+ */
+ else if (cap->nchar == '[' || cap->nchar == ']')
+ {
+ if (cap->nchar == cap->cmdchar) /* "]]" or "[[" */
+ flag = '{';
+ else
+ flag = '}'; /* "][" or "[]" */
+
+ curwin->w_set_curswant = TRUE;
+ /*
+ * Imitate strange Vi behaviour: When using "]]" with an operator
+ * we also stop at '}'.
+ */
+ if (!findpar(&cap->oap->inclusive, cap->arg, cap->count1, flag,
+ (cap->oap->op_type != OP_NOP
+ && cap->arg == FORWARD && flag == '{')))
+ clearopbeep(cap->oap);
+ else
+ {
+ if (cap->oap->op_type == OP_NOP)
+ beginline(BL_WHITE | BL_FIX);
+#ifdef FEAT_FOLDING
+ if ((fdo_flags & FDO_BLOCK) && KeyTyped && cap->oap->op_type == OP_NOP)
+ foldOpenCursor();
+#endif
+ }
+ }
+
+ /*
+ * "[p", "[P", "]P" and "]p": put with indent adjustment
+ */
+ else if (cap->nchar == 'p' || cap->nchar == 'P')
+ {
+ if (!checkclearop(cap->oap))
+ {
+ int dir = (cap->cmdchar == ']' && cap->nchar == 'p')
+ ? FORWARD : BACKWARD;
+ int regname = cap->oap->regname;
+ int was_visual = VIsual_active;
+ int line_count = curbuf->b_ml.ml_line_count;
+ pos_T start, end;
+
+ if (VIsual_active)
+ {
+ start = LTOREQ_POS(VIsual, curwin->w_cursor)
+ ? VIsual : curwin->w_cursor;
+ end = EQUAL_POS(start,VIsual) ? curwin->w_cursor : VIsual;
+ curwin->w_cursor = (dir == BACKWARD ? start : end);
+ }
+# ifdef FEAT_CLIPBOARD
+ adjust_clip_reg(&regname);
+# endif
+ prep_redo_cmd(cap);
+
+ do_put(regname, dir, cap->count1, PUT_FIXINDENT);
+ if (was_visual)
+ {
+ VIsual = start;
+ curwin->w_cursor = end;
+ if (dir == BACKWARD)
+ {
+ /* adjust lines */
+ VIsual.lnum += curbuf->b_ml.ml_line_count - line_count;
+ curwin->w_cursor.lnum +=
+ curbuf->b_ml.ml_line_count - line_count;
+ }
+
+ VIsual_active = TRUE;
+ if (VIsual_mode == 'V')
+ {
+ /* delete visually selected lines */
+ cap->cmdchar = 'd';
+ cap->nchar = NUL;
+ cap->oap->regname = regname;
+ nv_operator(cap);
+ do_pending_operator(cap, 0, FALSE);
+ }
+ if (VIsual_active)
+ {
+ end_visual_mode();
+ redraw_later(SOME_VALID);
+ }
+ }
+ }
+ }
+
+ /*
+ * "['", "[`", "]'" and "]`": jump to next mark
+ */
+ else if (cap->nchar == '\'' || cap->nchar == '`')
+ {
+ pos = &curwin->w_cursor;
+ for (n = cap->count1; n > 0; --n)
+ {
+ prev_pos = *pos;
+ pos = getnextmark(pos, cap->cmdchar == '[' ? BACKWARD : FORWARD,
+ cap->nchar == '\'');
+ if (pos == NULL)
+ break;
+ }
+ if (pos == NULL)
+ pos = &prev_pos;
+ nv_cursormark(cap, cap->nchar == '\'', pos);
+ }
+
+#ifdef FEAT_MOUSE
+ /*
+ * [ or ] followed by a middle mouse click: put selected text with
+ * indent adjustment. Any other button just does as usual.
+ */
+ else if (cap->nchar >= K_RIGHTRELEASE && cap->nchar <= K_LEFTMOUSE)
+ {
+ (void)do_mouse(cap->oap, cap->nchar,
+ (cap->cmdchar == ']') ? FORWARD : BACKWARD,
+ cap->count1, PUT_FIXINDENT);
+ }
+#endif /* FEAT_MOUSE */
+
+#ifdef FEAT_FOLDING
+ /*
+ * "[z" and "]z": move to start or end of open fold.
+ */
+ else if (cap->nchar == 'z')
+ {
+ if (foldMoveTo(FALSE, cap->cmdchar == ']' ? FORWARD : BACKWARD,
+ cap->count1) == FAIL)
+ clearopbeep(cap->oap);
+ }
+#endif
+
+#ifdef FEAT_DIFF
+ /*
+ * "[c" and "]c": move to next or previous diff-change.
+ */
+ else if (cap->nchar == 'c')
+ {
+ if (diff_move_to(cap->cmdchar == ']' ? FORWARD : BACKWARD,
+ cap->count1) == FAIL)
+ clearopbeep(cap->oap);
+ }
+#endif
+
+#ifdef FEAT_SPELL
+ /*
+ * "[s", "[S", "]s" and "]S": move to next spell error.
+ */
+ else if (cap->nchar == 's' || cap->nchar == 'S')
+ {
+ setpcmark();
+ for (n = 0; n < cap->count1; ++n)
+ if (spell_move_to(curwin, cap->cmdchar == ']' ? FORWARD : BACKWARD,
+ cap->nchar == 's' ? TRUE : FALSE, FALSE, NULL) == 0)
+ {
+ clearopbeep(cap->oap);
+ break;
+ }
+ else
+ curwin->w_set_curswant = TRUE;
+# ifdef FEAT_FOLDING
+ if (cap->oap->op_type == OP_NOP && (fdo_flags & FDO_SEARCH) && KeyTyped)
+ foldOpenCursor();
+# endif
+ }
+#endif
+
+ /* Not a valid cap->nchar. */
+ else
+ clearopbeep(cap->oap);
+}
+
+/*
+ * Handle Normal mode "%" command.
+ */
+ static void
+nv_percent(cmdarg_T *cap)
+{
+ pos_T *pos;
+#if defined(FEAT_FOLDING)
+ linenr_T lnum = curwin->w_cursor.lnum;
+#endif
+
+ cap->oap->inclusive = TRUE;
+ if (cap->count0) /* {cnt}% : goto {cnt} percentage in file */
+ {
+ if (cap->count0 > 100)
+ clearopbeep(cap->oap);
+ else
+ {
+ cap->oap->motion_type = MLINE;
+ setpcmark();
+ /* Round up, so CTRL-G will give same value. Watch out for a
+ * large line count, the line number must not go negative! */
+ if (curbuf->b_ml.ml_line_count > 1000000)
+ curwin->w_cursor.lnum = (curbuf->b_ml.ml_line_count + 99L)
+ / 100L * cap->count0;
+ else
+ curwin->w_cursor.lnum = (curbuf->b_ml.ml_line_count *
+ cap->count0 + 99L) / 100L;
+ if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
+ curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
+ beginline(BL_SOL | BL_FIX);
+ }
+ }
+ else /* "%" : go to matching paren */
+ {
+ cap->oap->motion_type = MCHAR;
+ cap->oap->use_reg_one = TRUE;
+ if ((pos = findmatch(cap->oap, NUL)) == NULL)
+ clearopbeep(cap->oap);
+ else
+ {
+ setpcmark();
+ curwin->w_cursor = *pos;
+ curwin->w_set_curswant = TRUE;
+ curwin->w_cursor.coladd = 0;
+ adjust_for_sel(cap);
+ }
+ }
+#ifdef FEAT_FOLDING
+ if (cap->oap->op_type == OP_NOP
+ && lnum != curwin->w_cursor.lnum
+ && (fdo_flags & FDO_PERCENT)
+ && KeyTyped)
+ foldOpenCursor();
+#endif
+}
+
+/*
+ * Handle "(" and ")" commands.
+ * cap->arg is BACKWARD for "(" and FORWARD for ")".
+ */
+ static void
+nv_brace(cmdarg_T *cap)
+{
+ cap->oap->motion_type = MCHAR;
+ cap->oap->use_reg_one = TRUE;
+ /* The motion used to be inclusive for "(", but that is not what Vi does. */
+ cap->oap->inclusive = FALSE;
+ curwin->w_set_curswant = TRUE;
+
+ if (findsent(cap->arg, cap->count1) == FAIL)
+ clearopbeep(cap->oap);
+ else
+ {
+ /* Don't leave the cursor on the NUL past end of line. */
+ adjust_cursor(cap->oap);
+ curwin->w_cursor.coladd = 0;
+#ifdef FEAT_FOLDING
+ if ((fdo_flags & FDO_BLOCK) && KeyTyped && cap->oap->op_type == OP_NOP)
+ foldOpenCursor();
+#endif
+ }
+}
+
+/*
+ * "m" command: Mark a position.
+ */
+ static void
+nv_mark(cmdarg_T *cap)
+{
+ if (!checkclearop(cap->oap))
+ {
+ if (setmark(cap->nchar) == FAIL)
+ clearopbeep(cap->oap);
+ }
+}
+
+/*
+ * "{" and "}" commands.
+ * cmd->arg is BACKWARD for "{" and FORWARD for "}".
+ */
+ static void
+nv_findpar(cmdarg_T *cap)
+{
+ cap->oap->motion_type = MCHAR;
+ cap->oap->inclusive = FALSE;
+ cap->oap->use_reg_one = TRUE;
+ curwin->w_set_curswant = TRUE;
+ if (!findpar(&cap->oap->inclusive, cap->arg, cap->count1, NUL, FALSE))
+ clearopbeep(cap->oap);
+ else
+ {
+ curwin->w_cursor.coladd = 0;
+#ifdef FEAT_FOLDING
+ if ((fdo_flags & FDO_BLOCK) && KeyTyped && cap->oap->op_type == OP_NOP)
+ foldOpenCursor();
+#endif
+ }
+}
+
+/*
+ * "u" command: Undo or make lower case.
+ */
+ static void
+nv_undo(cmdarg_T *cap)
+{
+ if (cap->oap->op_type == OP_LOWER || VIsual_active)
+ {
+ /* translate "<Visual>u" to "<Visual>gu" and "guu" to "gugu" */
+ cap->cmdchar = 'g';
+ cap->nchar = 'u';
+ nv_operator(cap);
+ }
+ else
+ nv_kundo(cap);
+}
+
+/*
+ * <Undo> command.
+ */
+ static void
+nv_kundo(cmdarg_T *cap)
+{
+ if (!checkclearopq(cap->oap))
+ {
+#ifdef FEAT_JOB_CHANNEL
+ if (bt_prompt(curbuf))
+ {
+ clearopbeep(cap->oap);
+ return;
+ }
+#endif
+ u_undo((int)cap->count1);
+ curwin->w_set_curswant = TRUE;
+ }
+}
+
+/*
+ * Handle the "r" command.
+ */
+ static void
+nv_replace(cmdarg_T *cap)
+{
+ char_u *ptr;
+ int had_ctrl_v;
+ long n;
+
+ if (checkclearop(cap->oap))
+ return;
+#ifdef FEAT_JOB_CHANNEL
+ if (bt_prompt(curbuf) && !prompt_curpos_editable())
+ {
+ clearopbeep(cap->oap);
+ return;
+ }
+#endif
+
+ /* get another character */
+ if (cap->nchar == Ctrl_V)
+ {
+ had_ctrl_v = Ctrl_V;
+ cap->nchar = get_literal();
+ /* Don't redo a multibyte character with CTRL-V. */
+ if (cap->nchar > DEL)
+ had_ctrl_v = NUL;
+ }
+ else
+ had_ctrl_v = NUL;
+
+ /* Abort if the character is a special key. */
+ if (IS_SPECIAL(cap->nchar))
+ {
+ clearopbeep(cap->oap);
+ return;
+ }
+
+ /* Visual mode "r" */
+ if (VIsual_active)
+ {
+ if (got_int)
+ reset_VIsual();
+ if (had_ctrl_v)
+ {
+ /* Use a special (negative) number to make a difference between a
+ * literal CR or NL and a line break. */
+ if (cap->nchar == CAR)
+ cap->nchar = REPLACE_CR_NCHAR;
+ else if (cap->nchar == NL)
+ cap->nchar = REPLACE_NL_NCHAR;
+ }
+ nv_operator(cap);
+ return;
+ }
+
+ /* Break tabs, etc. */
+ if (virtual_active())
+ {
+ if (u_save_cursor() == FAIL)
+ return;
+ if (gchar_cursor() == NUL)
+ {
+ /* Add extra space and put the cursor on the first one. */
+ coladvance_force((colnr_T)(getviscol() + cap->count1));
+ curwin->w_cursor.col -= cap->count1;
+ }
+ else if (gchar_cursor() == TAB)
+ coladvance_force(getviscol());
+ }
+
+ /* Abort if not enough characters to replace. */
+ ptr = ml_get_cursor();
+ if (STRLEN(ptr) < (unsigned)cap->count1
+ || (has_mbyte && mb_charlen(ptr) < cap->count1))
+ {
+ clearopbeep(cap->oap);
+ return;
+ }
+
+ /*
+ * Replacing with a TAB is done by edit() when it is complicated because
+ * 'expandtab' or 'smarttab' is set. CTRL-V TAB inserts a literal TAB.
+ * Other characters are done below to avoid problems with things like
+ * CTRL-V 048 (for edit() this would be R CTRL-V 0 ESC).
+ */
+ if (had_ctrl_v != Ctrl_V && cap->nchar == '\t' && (curbuf->b_p_et || p_sta))
+ {
+ stuffnumReadbuff(cap->count1);
+ stuffcharReadbuff('R');
+ stuffcharReadbuff('\t');
+ stuffcharReadbuff(ESC);
+ return;
+ }
+
+ /* save line for undo */
+ if (u_save_cursor() == FAIL)
+ return;
+
+ if (had_ctrl_v != Ctrl_V && (cap->nchar == '\r' || cap->nchar == '\n'))
+ {
+ /*
+ * Replace character(s) by a single newline.
+ * Strange vi behaviour: Only one newline is inserted.
+ * Delete the characters here.
+ * Insert the newline with an insert command, takes care of
+ * autoindent. The insert command depends on being on the last
+ * character of a line or not.
+ */
+ (void)del_chars(cap->count1, FALSE); /* delete the characters */
+ stuffcharReadbuff('\r');
+ stuffcharReadbuff(ESC);
+
+ /* Give 'r' to edit(), to get the redo command right. */
+ invoke_edit(cap, TRUE, 'r', FALSE);
+ }
+ else
+ {
+ prep_redo(cap->oap->regname, cap->count1,
+ NUL, 'r', NUL, had_ctrl_v, cap->nchar);
+
+ curbuf->b_op_start = curwin->w_cursor;
+ if (has_mbyte)
+ {
+ int old_State = State;
+
+ if (cap->ncharC1 != 0)
+ AppendCharToRedobuff(cap->ncharC1);
+ if (cap->ncharC2 != 0)
+ AppendCharToRedobuff(cap->ncharC2);
+
+ /* This is slow, but it handles replacing a single-byte with a
+ * multi-byte and the other way around. Also handles adding
+ * composing characters for utf-8. */
+ for (n = cap->count1; n > 0; --n)
+ {
+ State = REPLACE;
+ if (cap->nchar == Ctrl_E || cap->nchar == Ctrl_Y)
+ {
+ int c = ins_copychar(curwin->w_cursor.lnum
+ + (cap->nchar == Ctrl_Y ? -1 : 1));
+ if (c != NUL)
+ ins_char(c);
+ else
+ /* will be decremented further down */
+ ++curwin->w_cursor.col;
+ }
+ else
+ ins_char(cap->nchar);
+ State = old_State;
+ if (cap->ncharC1 != 0)
+ ins_char(cap->ncharC1);
+ if (cap->ncharC2 != 0)
+ ins_char(cap->ncharC2);
+ }
+ }
+ else
+ {
+ /*
+ * Replace the characters within one line.
+ */
+ for (n = cap->count1; n > 0; --n)
+ {
+ /*
+ * Get ptr again, because u_save and/or showmatch() will have
+ * released the line. At the same time we let know that the
+ * line will be changed.
+ */
+ ptr = ml_get_buf(curbuf, curwin->w_cursor.lnum, TRUE);
+ if (cap->nchar == Ctrl_E || cap->nchar == Ctrl_Y)
+ {
+ int c = ins_copychar(curwin->w_cursor.lnum
+ + (cap->nchar == Ctrl_Y ? -1 : 1));
+ if (c != NUL)
+ ptr[curwin->w_cursor.col] = c;
+ }
+ else
+ ptr[curwin->w_cursor.col] = cap->nchar;
+ if (p_sm && msg_silent == 0)
+ showmatch(cap->nchar);
+ ++curwin->w_cursor.col;
+ }
+#ifdef FEAT_NETBEANS_INTG
+ if (netbeans_active())
+ {
+ colnr_T start = (colnr_T)(curwin->w_cursor.col - cap->count1);
+
+ netbeans_removed(curbuf, curwin->w_cursor.lnum, start,
+ (long)cap->count1);
+ netbeans_inserted(curbuf, curwin->w_cursor.lnum, start,
+ &ptr[start], (int)cap->count1);
+ }
+#endif
+
+ /* mark the buffer as changed and prepare for displaying */
+ changed_bytes(curwin->w_cursor.lnum,
+ (colnr_T)(curwin->w_cursor.col - cap->count1));
+ }
+ --curwin->w_cursor.col; /* cursor on the last replaced char */
+ /* if the character on the left of the current cursor is a multi-byte
+ * character, move two characters left */
+ if (has_mbyte)
+ mb_adjust_cursor();
+ curbuf->b_op_end = curwin->w_cursor;
+ curwin->w_set_curswant = TRUE;
+ set_last_insert(cap->nchar);
+ }
+}
+
+/*
+ * 'o': Exchange start and end of Visual area.
+ * 'O': same, but in block mode exchange left and right corners.
+ */
+ static void
+v_swap_corners(int cmdchar)
+{
+ pos_T old_cursor;
+ colnr_T left, right;
+
+ if (cmdchar == 'O' && VIsual_mode == Ctrl_V)
+ {
+ old_cursor = curwin->w_cursor;
+ getvcols(curwin, &old_cursor, &VIsual, &left, &right);
+ curwin->w_cursor.lnum = VIsual.lnum;
+ coladvance(left);
+ VIsual = curwin->w_cursor;
+
+ curwin->w_cursor.lnum = old_cursor.lnum;
+ curwin->w_curswant = right;
+ /* 'selection "exclusive" and cursor at right-bottom corner: move it
+ * right one column */
+ if (old_cursor.lnum >= VIsual.lnum && *p_sel == 'e')
+ ++curwin->w_curswant;
+ coladvance(curwin->w_curswant);
+ if (curwin->w_cursor.col == old_cursor.col
+ && (!virtual_active()
+ || curwin->w_cursor.coladd == old_cursor.coladd))
+ {
+ curwin->w_cursor.lnum = VIsual.lnum;
+ if (old_cursor.lnum <= VIsual.lnum && *p_sel == 'e')
+ ++right;
+ coladvance(right);
+ VIsual = curwin->w_cursor;
+
+ curwin->w_cursor.lnum = old_cursor.lnum;
+ coladvance(left);
+ curwin->w_curswant = left;
+ }
+ }
+ else
+ {
+ old_cursor = curwin->w_cursor;
+ curwin->w_cursor = VIsual;
+ VIsual = old_cursor;
+ curwin->w_set_curswant = TRUE;
+ }
+}
+
+/*
+ * "R" (cap->arg is FALSE) and "gR" (cap->arg is TRUE).
+ */
+ static void
+nv_Replace(cmdarg_T *cap)
+{
+ if (VIsual_active) /* "R" is replace lines */
+ {
+ cap->cmdchar = 'c';
+ cap->nchar = NUL;
+ VIsual_mode_orig = VIsual_mode; /* remember original area for gv */
+ VIsual_mode = 'V';
+ nv_operator(cap);
+ }
+ else if (!checkclearopq(cap->oap))
+ {
+ if (!curbuf->b_p_ma)
+ emsg(_(e_modifiable));
+ else
+ {
+ if (virtual_active())
+ coladvance(getviscol());
+ invoke_edit(cap, FALSE, cap->arg ? 'V' : 'R', FALSE);
+ }
+ }
+}
+
+/*
+ * "gr".
+ */
+ static void
+nv_vreplace(cmdarg_T *cap)
+{
+ if (VIsual_active)
+ {
+ cap->cmdchar = 'r';
+ cap->nchar = cap->extra_char;
+ nv_replace(cap); /* Do same as "r" in Visual mode for now */
+ }
+ else if (!checkclearopq(cap->oap))
+ {
+ if (!curbuf->b_p_ma)
+ emsg(_(e_modifiable));
+ else
+ {
+ if (cap->extra_char == Ctrl_V) /* get another character */
+ cap->extra_char = get_literal();
+ stuffcharReadbuff(cap->extra_char);
+ stuffcharReadbuff(ESC);
+ if (virtual_active())
+ coladvance(getviscol());
+ invoke_edit(cap, TRUE, 'v', FALSE);
+ }
+ }
+}
+
+/*
+ * Swap case for "~" command, when it does not work like an operator.
+ */
+ static void
+n_swapchar(cmdarg_T *cap)
+{
+ long n;
+ pos_T startpos;
+ int did_change = 0;
+#ifdef FEAT_NETBEANS_INTG
+ pos_T pos;
+ char_u *ptr;
+ int count;
+#endif
+
+ if (checkclearopq(cap->oap))
+ return;
+
+ if (LINEEMPTY(curwin->w_cursor.lnum) && vim_strchr(p_ww, '~') == NULL)
+ {
+ clearopbeep(cap->oap);
+ return;
+ }
+
+ prep_redo_cmd(cap);
+
+ if (u_save_cursor() == FAIL)
+ return;
+
+ startpos = curwin->w_cursor;
+#ifdef FEAT_NETBEANS_INTG
+ pos = startpos;
+#endif
+ for (n = cap->count1; n > 0; --n)
+ {
+ did_change |= swapchar(cap->oap->op_type, &curwin->w_cursor);
+ inc_cursor();
+ if (gchar_cursor() == NUL)
+ {
+ if (vim_strchr(p_ww, '~') != NULL
+ && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
+ {
+#ifdef FEAT_NETBEANS_INTG
+ if (netbeans_active())
+ {
+ if (did_change)
+ {
+ ptr = ml_get(pos.lnum);
+ count = (int)STRLEN(ptr) - pos.col;
+ netbeans_removed(curbuf, pos.lnum, pos.col,
+ (long)count);
+ netbeans_inserted(curbuf, pos.lnum, pos.col,
+ &ptr[pos.col], count);
+ }
+ pos.col = 0;
+ pos.lnum++;
+ }
+#endif
+ ++curwin->w_cursor.lnum;
+ curwin->w_cursor.col = 0;
+ if (n > 1)
+ {
+ if (u_savesub(curwin->w_cursor.lnum) == FAIL)
+ break;
+ u_clearline();
+ }
+ }
+ else
+ break;
+ }
+ }
+#ifdef FEAT_NETBEANS_INTG
+ if (did_change && netbeans_active())
+ {
+ ptr = ml_get(pos.lnum);
+ count = curwin->w_cursor.col - pos.col;
+ netbeans_removed(curbuf, pos.lnum, pos.col, (long)count);
+ netbeans_inserted(curbuf, pos.lnum, pos.col, &ptr[pos.col], count);
+ }
+#endif
+
+
+ check_cursor();
+ curwin->w_set_curswant = TRUE;
+ if (did_change)
+ {
+ changed_lines(startpos.lnum, startpos.col, curwin->w_cursor.lnum + 1,
+ 0L);
+ curbuf->b_op_start = startpos;
+ curbuf->b_op_end = curwin->w_cursor;
+ if (curbuf->b_op_end.col > 0)
+ --curbuf->b_op_end.col;
+ }
+}
+
+/*
+ * Move cursor to mark.
+ */
+ static void
+nv_cursormark(cmdarg_T *cap, int flag, pos_T *pos)
+{
+ if (check_mark(pos) == FAIL)
+ clearop(cap->oap);
+ else
+ {
+ if (cap->cmdchar == '\''
+ || cap->cmdchar == '`'
+ || cap->cmdchar == '['
+ || cap->cmdchar == ']')
+ setpcmark();
+ curwin->w_cursor = *pos;
+ if (flag)
+ beginline(BL_WHITE | BL_FIX);
+ else
+ check_cursor();
+ }
+ cap->oap->motion_type = flag ? MLINE : MCHAR;
+ if (cap->cmdchar == '`')
+ cap->oap->use_reg_one = TRUE;
+ cap->oap->inclusive = FALSE; /* ignored if not MCHAR */
+ curwin->w_set_curswant = TRUE;
+}
+
+/*
+ * Handle commands that are operators in Visual mode.
+ */
+ static void
+v_visop(cmdarg_T *cap)
+{
+ static char_u trans[] = "YyDdCcxdXdAAIIrr";
+
+ /* Uppercase means linewise, except in block mode, then "D" deletes till
+ * the end of the line, and "C" replaces till EOL */
+ if (isupper(cap->cmdchar))
+ {
+ if (VIsual_mode != Ctrl_V)
+ {
+ VIsual_mode_orig = VIsual_mode;
+ VIsual_mode = 'V';
+ }
+ else if (cap->cmdchar == 'C' || cap->cmdchar == 'D')
+ curwin->w_curswant = MAXCOL;
+ }
+ cap->cmdchar = *(vim_strchr(trans, cap->cmdchar) + 1);
+ nv_operator(cap);
+}
+
+/*
+ * "s" and "S" commands.
+ */
+ static void
+nv_subst(cmdarg_T *cap)
+{
+#ifdef FEAT_TERMINAL
+ /* When showing output of term_dumpdiff() swap the top and botom. */
+ if (term_swap_diff() == OK)
+ return;
+#endif
+#ifdef FEAT_JOB_CHANNEL
+ if (bt_prompt(curbuf) && !prompt_curpos_editable())
+ {
+ clearopbeep(cap->oap);
+ return;
+ }
+#endif
+ if (VIsual_active) /* "vs" and "vS" are the same as "vc" */
+ {
+ if (cap->cmdchar == 'S')
+ {
+ VIsual_mode_orig = VIsual_mode;
+ VIsual_mode = 'V';
+ }
+ cap->cmdchar = 'c';
+ nv_operator(cap);
+ }
+ else
+ nv_optrans(cap);
+}
+
+/*
+ * Abbreviated commands.
+ */
+ static void
+nv_abbrev(cmdarg_T *cap)
+{
+ if (cap->cmdchar == K_DEL || cap->cmdchar == K_KDEL)
+ cap->cmdchar = 'x'; /* DEL key behaves like 'x' */
+
+ /* in Visual mode these commands are operators */
+ if (VIsual_active)
+ v_visop(cap);
+ else
+ nv_optrans(cap);
+}
+
+/*
+ * Translate a command into another command.
+ */
+ static void
+nv_optrans(cmdarg_T *cap)
+{
+ static char_u *(ar[8]) = {(char_u *)"dl", (char_u *)"dh",
+ (char_u *)"d$", (char_u *)"c$",
+ (char_u *)"cl", (char_u *)"cc",
+ (char_u *)"yy", (char_u *)":s\r"};
+ static char_u *str = (char_u *)"xXDCsSY&";
+
+ if (!checkclearopq(cap->oap))
+ {
+ /* In Vi "2D" doesn't delete the next line. Can't translate it
+ * either, because "2." should also not use the count. */
+ if (cap->cmdchar == 'D' && vim_strchr(p_cpo, CPO_HASH) != NULL)
+ {
+ cap->oap->start = curwin->w_cursor;
+ cap->oap->op_type = OP_DELETE;
+#ifdef FEAT_EVAL
+ set_op_var(OP_DELETE);
+#endif
+ cap->count1 = 1;
+ nv_dollar(cap);
+ finish_op = TRUE;
+ ResetRedobuff();
+ AppendCharToRedobuff('D');
+ }
+ else
+ {
+ if (cap->count0)
+ stuffnumReadbuff(cap->count0);
+ stuffReadbuff(ar[(int)(vim_strchr(str, cap->cmdchar) - str)]);
+ }
+ }
+ cap->opcount = 0;
+}
+
+/*
+ * "'" and "`" commands. Also for "g'" and "g`".
+ * cap->arg is TRUE for "'" and "g'".
+ */
+ static void
+nv_gomark(cmdarg_T *cap)
+{
+ pos_T *pos;
+ int c;
+#ifdef FEAT_FOLDING
+ pos_T old_cursor = curwin->w_cursor;
+ int old_KeyTyped = KeyTyped; /* getting file may reset it */
+#endif
+
+ if (cap->cmdchar == 'g')
+ c = cap->extra_char;
+ else
+ c = cap->nchar;
+ pos = getmark(c, (cap->oap->op_type == OP_NOP));
+ if (pos == (pos_T *)-1) /* jumped to other file */
+ {
+ if (cap->arg)
+ {
+ check_cursor_lnum();
+ beginline(BL_WHITE | BL_FIX);
+ }
+ else
+ check_cursor();
+ }
+ else
+ nv_cursormark(cap, cap->arg, pos);
+
+ /* May need to clear the coladd that a mark includes. */
+ if (!virtual_active())
+ curwin->w_cursor.coladd = 0;
+ check_cursor_col();
+#ifdef FEAT_FOLDING
+ if (cap->oap->op_type == OP_NOP
+ && pos != NULL
+ && (pos == (pos_T *)-1 || !EQUAL_POS(old_cursor, *pos))
+ && (fdo_flags & FDO_MARK)
+ && old_KeyTyped)
+ foldOpenCursor();
+#endif
+}
+
+/*
+ * Handle CTRL-O, CTRL-I, "g;" and "g," commands.
+ */
+ static void
+nv_pcmark(cmdarg_T *cap)
+{
+#ifdef FEAT_JUMPLIST
+ pos_T *pos;
+# ifdef FEAT_FOLDING
+ linenr_T lnum = curwin->w_cursor.lnum;
+ int old_KeyTyped = KeyTyped; /* getting file may reset it */
+# endif
+
+ if (!checkclearopq(cap->oap))
+ {
+ if (cap->cmdchar == 'g')
+ pos = movechangelist((int)cap->count1);
+ else
+ pos = movemark((int)cap->count1);
+ if (pos == (pos_T *)-1) /* jump to other file */
+ {
+ curwin->w_set_curswant = TRUE;
+ check_cursor();
+ }
+ else if (pos != NULL) /* can jump */
+ nv_cursormark(cap, FALSE, pos);
+ else if (cap->cmdchar == 'g')
+ {
+ if (curbuf->b_changelistlen == 0)
+ emsg(_("E664: changelist is empty"));
+ else if (cap->count1 < 0)
+ emsg(_("E662: At start of changelist"));
+ else
+ emsg(_("E663: At end of changelist"));
+ }
+ else
+ clearopbeep(cap->oap);
+# ifdef FEAT_FOLDING
+ if (cap->oap->op_type == OP_NOP
+ && (pos == (pos_T *)-1 || lnum != curwin->w_cursor.lnum)
+ && (fdo_flags & FDO_MARK)
+ && old_KeyTyped)
+ foldOpenCursor();
+# endif
+ }
+#else
+ clearopbeep(cap->oap);
+#endif
+}
+
+/*
+ * Handle '"' command.
+ */
+ static void
+nv_regname(cmdarg_T *cap)
+{
+ if (checkclearop(cap->oap))
+ return;
+#ifdef FEAT_EVAL
+ if (cap->nchar == '=')
+ cap->nchar = get_expr_register();
+#endif
+ if (cap->nchar != NUL && valid_yank_reg(cap->nchar, FALSE))
+ {
+ cap->oap->regname = cap->nchar;
+ cap->opcount = cap->count0; /* remember count before '"' */
+#ifdef FEAT_EVAL
+ set_reg_var(cap->oap->regname);
+#endif
+ }
+ else
+ clearopbeep(cap->oap);
+}
+
+/*
+ * Handle "v", "V" and "CTRL-V" commands.
+ * Also for "gh", "gH" and "g^H" commands: Always start Select mode, cap->arg
+ * is TRUE.
+ * Handle CTRL-Q just like CTRL-V.
+ */
+ static void
+nv_visual(cmdarg_T *cap)
+{
+ if (cap->cmdchar == Ctrl_Q)
+ cap->cmdchar = Ctrl_V;
+
+ /* 'v', 'V' and CTRL-V can be used while an operator is pending to make it
+ * characterwise, linewise, or blockwise. */
+ if (cap->oap->op_type != OP_NOP)
+ {
+ motion_force = cap->oap->motion_force = cap->cmdchar;
+ finish_op = FALSE; /* operator doesn't finish now but later */
+ return;
+ }
+
+ VIsual_select = cap->arg;
+ if (VIsual_active) /* change Visual mode */
+ {
+ if (VIsual_mode == cap->cmdchar) /* stop visual mode */
+ end_visual_mode();
+ else /* toggle char/block mode */
+ { /* or char/line mode */
+ VIsual_mode = cap->cmdchar;
+ showmode();
+ }
+ redraw_curbuf_later(INVERTED); /* update the inversion */
+ }
+ else /* start Visual mode */
+ {
+ check_visual_highlight();
+ if (cap->count0 > 0 && resel_VIsual_mode != NUL)
+ {
+ /* use previously selected part */
+ VIsual = curwin->w_cursor;
+
+ VIsual_active = TRUE;
+ VIsual_reselect = TRUE;
+ if (!cap->arg)
+ /* start Select mode when 'selectmode' contains "cmd" */
+ may_start_select('c');
+#ifdef FEAT_MOUSE
+ setmouse();
+#endif
+ if (p_smd && msg_silent == 0)
+ redraw_cmdline = TRUE; /* show visual mode later */
+ /*
+ * For V and ^V, we multiply the number of lines even if there
+ * was only one -- webb
+ */
+ if (resel_VIsual_mode != 'v' || resel_VIsual_line_count > 1)
+ {
+ curwin->w_cursor.lnum +=
+ resel_VIsual_line_count * cap->count0 - 1;
+ if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
+ curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
+ }
+ VIsual_mode = resel_VIsual_mode;
+ if (VIsual_mode == 'v')
+ {
+ if (resel_VIsual_line_count <= 1)
+ {
+ validate_virtcol();
+ curwin->w_curswant = curwin->w_virtcol
+ + resel_VIsual_vcol * cap->count0 - 1;
+ }
+ else
+ curwin->w_curswant = resel_VIsual_vcol;
+ coladvance(curwin->w_curswant);
+ }
+ if (resel_VIsual_vcol == MAXCOL)
+ {
+ curwin->w_curswant = MAXCOL;
+ coladvance((colnr_T)MAXCOL);
+ }
+ else if (VIsual_mode == Ctrl_V)
+ {
+ validate_virtcol();
+ curwin->w_curswant = curwin->w_virtcol
+ + resel_VIsual_vcol * cap->count0 - 1;
+ coladvance(curwin->w_curswant);
+ }
+ else
+ curwin->w_set_curswant = TRUE;
+ redraw_curbuf_later(INVERTED); /* show the inversion */
+ }
+ else
+ {
+ if (!cap->arg)
+ /* start Select mode when 'selectmode' contains "cmd" */
+ may_start_select('c');
+ n_start_visual_mode(cap->cmdchar);
+ if (VIsual_mode != 'V' && *p_sel == 'e')
+ ++cap->count1; /* include one more char */
+ if (cap->count0 > 0 && --cap->count1 > 0)
+ {
+ /* With a count select that many characters or lines. */
+ if (VIsual_mode == 'v' || VIsual_mode == Ctrl_V)
+ nv_right(cap);
+ else if (VIsual_mode == 'V')
+ nv_down(cap);
+ }
+ }
+ }
+}
+
+/*
+ * Start selection for Shift-movement keys.
+ */
+ void
+start_selection(void)
+{
+ /* if 'selectmode' contains "key", start Select mode */
+ may_start_select('k');
+ n_start_visual_mode('v');
+}
+
+/*
+ * Start Select mode, if "c" is in 'selectmode' and not in a mapping or menu.
+ */
+ void
+may_start_select(int c)
+{
+ VIsual_select = (stuff_empty() && typebuf_typed()
+ && (vim_strchr(p_slm, c) != NULL));
+}
+
+/*
+ * Start Visual mode "c".
+ * Should set VIsual_select before calling this.
+ */
+ static void
+n_start_visual_mode(int c)
+{
+#ifdef FEAT_CONCEAL
+ /* Check for redraw before changing the state. */
+ conceal_check_cursor_line();
+#endif
+
+ VIsual_mode = c;
+ VIsual_active = TRUE;
+ VIsual_reselect = TRUE;
+
+ // Corner case: the 0 position in a tab may change when going into
+ // virtualedit. Recalculate curwin->w_cursor to avoid bad hilighting.
+ if (c == Ctrl_V && (ve_flags & VE_BLOCK) && gchar_cursor() == TAB)
+ {
+ validate_virtcol();
+ coladvance(curwin->w_virtcol);
+ }
+ VIsual = curwin->w_cursor;
+
+#ifdef FEAT_FOLDING
+ foldAdjustVisual();
+#endif
+
+#ifdef FEAT_MOUSE
+ setmouse();
+#endif
+#ifdef FEAT_CONCEAL
+ /* Check for redraw after changing the state. */
+ conceal_check_cursor_line();
+#endif
+
+ if (p_smd && msg_silent == 0)
+ redraw_cmdline = TRUE; /* show visual mode later */
+#ifdef FEAT_CLIPBOARD
+ /* Make sure the clipboard gets updated. Needed because start and
+ * end may still be the same, and the selection needs to be owned */
+ clip_star.vmode = NUL;
+#endif
+
+ /* Only need to redraw this line, unless still need to redraw an old
+ * Visual area (when 'lazyredraw' is set). */
+ if (curwin->w_redr_type < INVERTED)
+ {
+ curwin->w_old_cursor_lnum = curwin->w_cursor.lnum;
+ curwin->w_old_visual_lnum = curwin->w_cursor.lnum;
+ }
+}
+
+
+/*
+ * CTRL-W: Window commands
+ */
+ static void
+nv_window(cmdarg_T *cap)
+{
+ if (cap->nchar == ':')
+ {
+ /* "CTRL-W :" is the same as typing ":"; useful in a terminal window */
+ cap->cmdchar = ':';
+ cap->nchar = NUL;
+ nv_colon(cap);
+ }
+ else if (!checkclearop(cap->oap))
+ do_window(cap->nchar, cap->count0, NUL); /* everything is in window.c */
+}
+
+/*
+ * CTRL-Z: Suspend
+ */
+ static void
+nv_suspend(cmdarg_T *cap)
+{
+ clearop(cap->oap);
+ if (VIsual_active)
+ end_visual_mode(); /* stop Visual mode */
+ do_cmdline_cmd((char_u *)"st");
+}
+
+/*
+ * Commands starting with "g".
+ */
+ static void
+nv_g_cmd(cmdarg_T *cap)
+{
+ oparg_T *oap = cap->oap;
+ pos_T tpos;
+ int i;
+ int flag = FALSE;
+
+ switch (cap->nchar)
+ {
+ case Ctrl_A:
+ case Ctrl_X:
+#ifdef MEM_PROFILE
+ /*
+ * "g^A": dump log of used memory.
+ */
+ if (!VIsual_active && cap->nchar == Ctrl_A)
+ vim_mem_profile_dump();
+ else
+#endif
+ /*
+ * "g^A/g^X": sequentially increment visually selected region
+ */
+ if (VIsual_active)
+ {
+ cap->arg = TRUE;
+ cap->cmdchar = cap->nchar;
+ cap->nchar = NUL;
+ nv_addsub(cap);
+ }
+ else
+ clearopbeep(oap);
+ break;
+
+ /*
+ * "gR": Enter virtual replace mode.
+ */
+ case 'R':
+ cap->arg = TRUE;
+ nv_Replace(cap);
+ break;
+
+ case 'r':
+ nv_vreplace(cap);
+ break;
+
+ case '&':
+ do_cmdline_cmd((char_u *)"%s//~/&");
+ break;
+
+ /*
+ * "gv": Reselect the previous Visual area. If Visual already active,
+ * exchange previous and current Visual area.
+ */
+ case 'v':
+ if (checkclearop(oap))
+ break;
+
+ if ( curbuf->b_visual.vi_start.lnum == 0
+ || curbuf->b_visual.vi_start.lnum > curbuf->b_ml.ml_line_count
+ || curbuf->b_visual.vi_end.lnum == 0)
+ beep_flush();
+ else
+ {
+ /* set w_cursor to the start of the Visual area, tpos to the end */
+ if (VIsual_active)
+ {
+ i = VIsual_mode;
+ VIsual_mode = curbuf->b_visual.vi_mode;
+ curbuf->b_visual.vi_mode = i;
+# ifdef FEAT_EVAL
+ curbuf->b_visual_mode_eval = i;
+# endif
+ i = curwin->w_curswant;
+ curwin->w_curswant = curbuf->b_visual.vi_curswant;
+ curbuf->b_visual.vi_curswant = i;
+
+ tpos = curbuf->b_visual.vi_end;
+ curbuf->b_visual.vi_end = curwin->w_cursor;
+ curwin->w_cursor = curbuf->b_visual.vi_start;
+ curbuf->b_visual.vi_start = VIsual;
+ }
+ else
+ {
+ VIsual_mode = curbuf->b_visual.vi_mode;
+ curwin->w_curswant = curbuf->b_visual.vi_curswant;
+ tpos = curbuf->b_visual.vi_end;
+ curwin->w_cursor = curbuf->b_visual.vi_start;
+ }
+
+ VIsual_active = TRUE;
+ VIsual_reselect = TRUE;
+
+ /* Set Visual to the start and w_cursor to the end of the Visual
+ * area. Make sure they are on an existing character. */
+ check_cursor();
+ VIsual = curwin->w_cursor;
+ curwin->w_cursor = tpos;
+ check_cursor();
+ update_topline();
+ /*
+ * When called from normal "g" command: start Select mode when
+ * 'selectmode' contains "cmd". When called for K_SELECT, always
+ * start Select mode.
+ */
+ if (cap->arg)
+ VIsual_select = TRUE;
+ else
+ may_start_select('c');
+#ifdef FEAT_MOUSE
+ setmouse();
+#endif
+#ifdef FEAT_CLIPBOARD
+ /* Make sure the clipboard gets updated. Needed because start and
+ * end are still the same, and the selection needs to be owned */
+ clip_star.vmode = NUL;
+#endif
+ redraw_curbuf_later(INVERTED);
+ showmode();
+ }
+ break;
+ /*
+ * "gV": Don't reselect the previous Visual area after a Select mode
+ * mapping of menu.
+ */
+ case 'V':
+ VIsual_reselect = FALSE;
+ break;
+
+ /*
+ * "gh": start Select mode.
+ * "gH": start Select line mode.
+ * "g^H": start Select block mode.
+ */
+ case K_BS:
+ cap->nchar = Ctrl_H;
+ /* FALLTHROUGH */
+ case 'h':
+ case 'H':
+ case Ctrl_H:
+# ifdef EBCDIC
+ /* EBCDIC: 'v'-'h' != '^v'-'^h' */
+ if (cap->nchar == Ctrl_H)
+ cap->cmdchar = Ctrl_V;
+ else
+# endif
+ cap->cmdchar = cap->nchar + ('v' - 'h');
+ cap->arg = TRUE;
+ nv_visual(cap);
+ break;
+
+ /* "gn", "gN" visually select next/previous search match
+ * "gn" selects next match
+ * "gN" selects previous match
+ */
+ case 'N':
+ case 'n':
+ if (!current_search(cap->count1, cap->nchar == 'n'))
+ clearopbeep(oap);
+ break;
+
+ /*
+ * "gj" and "gk" two new funny movement keys -- up and down
+ * movement based on *screen* line rather than *file* line.
+ */
+ case 'j':
+ case K_DOWN:
+ /* with 'nowrap' it works just like the normal "j" command; also when
+ * in a closed fold */
+ if (!curwin->w_p_wrap
+#ifdef FEAT_FOLDING
+ || hasFolding(curwin->w_cursor.lnum, NULL, NULL)
+#endif
+ )
+ {
+ oap->motion_type = MLINE;
+ i = cursor_down(cap->count1, oap->op_type == OP_NOP);
+ }
+ else
+ i = nv_screengo(oap, FORWARD, cap->count1);
+ if (i == FAIL)
+ clearopbeep(oap);
+ break;
+
+ case 'k':
+ case K_UP:
+ /* with 'nowrap' it works just like the normal "k" command; also when
+ * in a closed fold */
+ if (!curwin->w_p_wrap
+#ifdef FEAT_FOLDING
+ || hasFolding(curwin->w_cursor.lnum, NULL, NULL)
+#endif
+ )
+ {
+ oap->motion_type = MLINE;
+ i = cursor_up(cap->count1, oap->op_type == OP_NOP);
+ }
+ else
+ i = nv_screengo(oap, BACKWARD, cap->count1);
+ if (i == FAIL)
+ clearopbeep(oap);
+ break;
+
+ /*
+ * "gJ": join two lines without inserting a space.
+ */
+ case 'J':
+ nv_join(cap);
+ break;
+
+ /*
+ * "g0", "g^" and "g$": Like "0", "^" and "$" but for screen lines.
+ * "gm": middle of "g0" and "g$".
+ */
+ case '^':
+ flag = TRUE;
+ /* FALLTHROUGH */
+
+ case '0':
+ case 'm':
+ case K_HOME:
+ case K_KHOME:
+ oap->motion_type = MCHAR;
+ oap->inclusive = FALSE;
+ if (curwin->w_p_wrap && curwin->w_width != 0)
+ {
+ int width1 = curwin->w_width - curwin_col_off();
+ int width2 = width1 + curwin_col_off2();
+
+ validate_virtcol();
+ i = 0;
+ if (curwin->w_virtcol >= (colnr_T)width1 && width2 > 0)
+ i = (curwin->w_virtcol - width1) / width2 * width2 + width1;
+ }
+ else
+ i = curwin->w_leftcol;
+ /* Go to the middle of the screen line. When 'number' or
+ * 'relativenumber' is on and lines are wrapping the middle can be more
+ * to the left. */
+ if (cap->nchar == 'm')
+ i += (curwin->w_width - curwin_col_off()
+ + ((curwin->w_p_wrap && i > 0)
+ ? curwin_col_off2() : 0)) / 2;
+ coladvance((colnr_T)i);
+ if (flag)
+ {
+ do
+ i = gchar_cursor();
+ while (VIM_ISWHITE(i) && oneright() == OK);
+ curwin->w_valid &= ~VALID_WCOL;
+ }
+ curwin->w_set_curswant = TRUE;
+ break;
+
+ case '_':
+ /* "g_": to the last non-blank character in the line or <count> lines
+ * downward. */
+ cap->oap->motion_type = MCHAR;
+ cap->oap->inclusive = TRUE;
+ curwin->w_curswant = MAXCOL;
+ if (cursor_down((long)(cap->count1 - 1),
+ cap->oap->op_type == OP_NOP) == FAIL)
+ clearopbeep(cap->oap);
+ else
+ {
+ char_u *ptr = ml_get_curline();
+
+ /* In Visual mode we may end up after the line. */
+ if (curwin->w_cursor.col > 0 && ptr[curwin->w_cursor.col] == NUL)
+ --curwin->w_cursor.col;
+
+ /* Decrease the cursor column until it's on a non-blank. */
+ while (curwin->w_cursor.col > 0
+ && VIM_ISWHITE(ptr[curwin->w_cursor.col]))
+ --curwin->w_cursor.col;
+ curwin->w_set_curswant = TRUE;
+ adjust_for_sel(cap);
+ }
+ break;
+
+ case '$':
+ case K_END:
+ case K_KEND:
+ {
+ int col_off = curwin_col_off();
+
+ oap->motion_type = MCHAR;
+ oap->inclusive = TRUE;
+ if (curwin->w_p_wrap && curwin->w_width != 0)
+ {
+ curwin->w_curswant = MAXCOL; /* so we stay at the end */
+ if (cap->count1 == 1)
+ {
+ int width1 = curwin->w_width - col_off;
+ int width2 = width1 + curwin_col_off2();
+
+ validate_virtcol();
+ i = width1 - 1;
+ if (curwin->w_virtcol >= (colnr_T)width1)
+ i += ((curwin->w_virtcol - width1) / width2 + 1)
+ * width2;
+ coladvance((colnr_T)i);
+
+ /* Make sure we stick in this column. */
+ validate_virtcol();
+ curwin->w_curswant = curwin->w_virtcol;
+ curwin->w_set_curswant = FALSE;
+ if (curwin->w_cursor.col > 0 && curwin->w_p_wrap)
+ {
+ /*
+ * Check for landing on a character that got split at
+ * the end of the line. We do not want to advance to
+ * the next screen line.
+ */
+ if (curwin->w_virtcol > (colnr_T)i)
+ --curwin->w_cursor.col;
+ }
+ }
+ else if (nv_screengo(oap, FORWARD, cap->count1 - 1) == FAIL)
+ clearopbeep(oap);
+ }
+ else
+ {
+ i = curwin->w_leftcol + curwin->w_width - col_off - 1;
+ coladvance((colnr_T)i);
+
+ /* Make sure we stick in this column. */
+ validate_virtcol();
+ curwin->w_curswant = curwin->w_virtcol;
+ curwin->w_set_curswant = FALSE;
+ }
+ }
+ break;
+
+ /*
+ * "g*" and "g#", like "*" and "#" but without using "\<" and "\>"
+ */
+ case '*':
+ case '#':
+#if POUND != '#'
+ case POUND: /* pound sign (sometimes equal to '#') */
+#endif
+ case Ctrl_RSB: /* :tag or :tselect for current identifier */
+ case ']': /* :tselect for current identifier */
+ nv_ident(cap);
+ break;
+
+ /*
+ * ge and gE: go back to end of word
+ */
+ case 'e':
+ case 'E':
+ oap->motion_type = MCHAR;
+ curwin->w_set_curswant = TRUE;
+ oap->inclusive = TRUE;
+ if (bckend_word(cap->count1, cap->nchar == 'E', FALSE) == FAIL)
+ clearopbeep(oap);
+ break;
+
+ /*
+ * "g CTRL-G": display info about cursor position
+ */
+ case Ctrl_G:
+ cursor_pos_info(NULL);
+ break;
+
+ /*
+ * "gi": start Insert at the last position.
+ */
+ case 'i':
+ if (curbuf->b_last_insert.lnum != 0)
+ {
+ curwin->w_cursor = curbuf->b_last_insert;
+ check_cursor_lnum();
+ i = (int)STRLEN(ml_get_curline());
+ if (curwin->w_cursor.col > (colnr_T)i)
+ {
+ if (virtual_active())
+ curwin->w_cursor.coladd += curwin->w_cursor.col - i;
+ curwin->w_cursor.col = i;
+ }
+ }
+ cap->cmdchar = 'i';
+ nv_edit(cap);
+ break;
+
+ /*
+ * "gI": Start insert in column 1.
+ */
+ case 'I':
+ beginline(0);
+ if (!checkclearopq(oap))
+ invoke_edit(cap, FALSE, 'g', FALSE);
+ break;
+
+#ifdef FEAT_SEARCHPATH
+ /*
+ * "gf": goto file, edit file under cursor
+ * "]f" and "[f": can also be used.
+ */
+ case 'f':
+ case 'F':
+ nv_gotofile(cap);
+ break;
+#endif
+
+ /* "g'm" and "g`m": jump to mark without setting pcmark */
+ case '\'':
+ cap->arg = TRUE;
+ /* FALLTHROUGH */
+ case '`':
+ nv_gomark(cap);
+ break;
+
+ /*
+ * "gs": Goto sleep.
+ */
+ case 's':
+ do_sleep(cap->count1 * 1000L);
+ break;
+
+ /*
+ * "ga": Display the ascii value of the character under the
+ * cursor. It is displayed in decimal, hex, and octal. -- webb
+ */
+ case 'a':
+ do_ascii(NULL);
+ break;
+
+ /*
+ * "g8": Display the bytes used for the UTF-8 character under the
+ * cursor. It is displayed in hex.
+ * "8g8" finds illegal byte sequence.
+ */
+ case '8':
+ if (cap->count0 == 8)
+ utf_find_illegal();
+ else
+ show_utf8();
+ break;
+
+ /* "g<": show scrollback text */
+ case '<':
+ show_sb_text();
+ break;
+
+ /*
+ * "gg": Goto the first line in file. With a count it goes to
+ * that line number like for "G". -- webb
+ */
+ case 'g':
+ cap->arg = FALSE;
+ nv_goto(cap);
+ break;
+
+ /*
+ * Two-character operators:
+ * "gq" Format text
+ * "gw" Format text and keep cursor position
+ * "g~" Toggle the case of the text.
+ * "gu" Change text to lower case.
+ * "gU" Change text to upper case.
+ * "g?" rot13 encoding
+ * "g@" call 'operatorfunc'
+ */
+ case 'q':
+ case 'w':
+ oap->cursor_start = curwin->w_cursor;
+ /* FALLTHROUGH */
+ case '~':
+ case 'u':
+ case 'U':
+ case '?':
+ case '@':
+ nv_operator(cap);
+ break;
+
+ /*
+ * "gd": Find first occurrence of pattern under the cursor in the
+ * current function
+ * "gD": idem, but in the current file.
+ */
+ case 'd':
+ case 'D':
+ nv_gd(oap, cap->nchar, (int)cap->count0);
+ break;
+
+#ifdef FEAT_MOUSE
+ /*
+ * g<*Mouse> : <C-*mouse>
+ */
+ case K_MIDDLEMOUSE:
+ case K_MIDDLEDRAG:
+ case K_MIDDLERELEASE:
+ case K_LEFTMOUSE:
+ case K_LEFTDRAG:
+ case K_LEFTRELEASE:
+ case K_MOUSEMOVE:
+ case K_RIGHTMOUSE:
+ case K_RIGHTDRAG:
+ case K_RIGHTRELEASE:
+ case K_X1MOUSE:
+ case K_X1DRAG:
+ case K_X1RELEASE:
+ case K_X2MOUSE:
+ case K_X2DRAG:
+ case K_X2RELEASE:
+ mod_mask = MOD_MASK_CTRL;
+ (void)do_mouse(oap, cap->nchar, BACKWARD, cap->count1, 0);
+ break;
+#endif
+
+ case K_IGNORE:
+ break;
+
+ /*
+ * "gP" and "gp": same as "P" and "p" but leave cursor just after new text
+ */
+ case 'p':
+ case 'P':
+ nv_put(cap);
+ break;
+
+#ifdef FEAT_BYTEOFF
+ /* "go": goto byte count from start of buffer */
+ case 'o':
+ goto_byte(cap->count0);
+ break;
+#endif
+
+ /* "gQ": improved Ex mode */
+ case 'Q':
+ if (text_locked())
+ {
+ clearopbeep(cap->oap);
+ text_locked_msg();
+ break;
+ }
+
+ if (!checkclearopq(oap))
+ do_exmode(TRUE);
+ break;
+
+#ifdef FEAT_JUMPLIST
+ case ',':
+ nv_pcmark(cap);
+ break;
+
+ case ';':
+ cap->count1 = -cap->count1;
+ nv_pcmark(cap);
+ break;
+#endif
+
+ case 't':
+ if (!checkclearop(oap))
+ goto_tabpage((int)cap->count0);
+ break;
+ case 'T':
+ if (!checkclearop(oap))
+ goto_tabpage(-(int)cap->count1);
+ break;
+
+ case '+':
+ case '-': /* "g+" and "g-": undo or redo along the timeline */
+ if (!checkclearopq(oap))
+ undo_time(cap->nchar == '-' ? -cap->count1 : cap->count1,
+ FALSE, FALSE, FALSE);
+ break;
+
+ default:
+ clearopbeep(oap);
+ break;
+ }
+}
+
+/*
+ * Handle "o" and "O" commands.
+ */
+ static void
+n_opencmd(cmdarg_T *cap)
+{
+#ifdef FEAT_CONCEAL
+ linenr_T oldline = curwin->w_cursor.lnum;
+#endif
+
+ if (!checkclearopq(cap->oap))
+ {
+#ifdef FEAT_FOLDING
+ if (cap->cmdchar == 'O')
+ /* Open above the first line of a folded sequence of lines */
+ (void)hasFolding(curwin->w_cursor.lnum,
+ &curwin->w_cursor.lnum, NULL);
+ else
+ /* Open below the last line of a folded sequence of lines */
+ (void)hasFolding(curwin->w_cursor.lnum,
+ NULL, &curwin->w_cursor.lnum);
+#endif
+ if (u_save((linenr_T)(curwin->w_cursor.lnum -
+ (cap->cmdchar == 'O' ? 1 : 0)),
+ (linenr_T)(curwin->w_cursor.lnum +
+ (cap->cmdchar == 'o' ? 1 : 0))
+ ) == OK
+ && open_line(cap->cmdchar == 'O' ? BACKWARD : FORWARD,
+#ifdef FEAT_COMMENTS
+ has_format_option(FO_OPEN_COMS) ? OPENLINE_DO_COM :
+#endif
+ 0, 0) == OK)
+ {
+#ifdef FEAT_CONCEAL
+ if (curwin->w_p_cole > 0 && oldline != curwin->w_cursor.lnum)
+ redrawWinline(curwin, oldline);
+#endif
+#ifdef FEAT_SYN_HL
+ if (curwin->w_p_cul)
+ /* force redraw of cursorline */
+ curwin->w_valid &= ~VALID_CROW;
+#endif
+ /* When '#' is in 'cpoptions' ignore the count. */
+ if (vim_strchr(p_cpo, CPO_HASH) != NULL)
+ cap->count1 = 1;
+ invoke_edit(cap, FALSE, cap->cmdchar, TRUE);
+ }
+ }
+}
+
+/*
+ * "." command: redo last change.
+ */
+ static void
+nv_dot(cmdarg_T *cap)
+{
+ if (!checkclearopq(cap->oap))
+ {
+ /*
+ * If "restart_edit" is TRUE, the last but one command is repeated
+ * instead of the last command (inserting text). This is used for
+ * CTRL-O <.> in insert mode.
+ */
+ if (start_redo(cap->count0, restart_edit != 0 && !arrow_used) == FAIL)
+ clearopbeep(cap->oap);
+ }
+}
+
+/*
+ * CTRL-R: undo undo
+ */
+ static void
+nv_redo(cmdarg_T *cap)
+{
+ if (!checkclearopq(cap->oap))
+ {
+ u_redo((int)cap->count1);
+ curwin->w_set_curswant = TRUE;
+ }
+}
+
+/*
+ * Handle "U" command.
+ */
+ static void
+nv_Undo(cmdarg_T *cap)
+{
+ /* In Visual mode and typing "gUU" triggers an operator */
+ if (cap->oap->op_type == OP_UPPER || VIsual_active)
+ {
+ /* translate "gUU" to "gUgU" */
+ cap->cmdchar = 'g';
+ cap->nchar = 'U';
+ nv_operator(cap);
+ }
+ else if (!checkclearopq(cap->oap))
+ {
+ u_undoline();
+ curwin->w_set_curswant = TRUE;
+ }
+}
+
+/*
+ * '~' command: If tilde is not an operator and Visual is off: swap case of a
+ * single character.
+ */
+ static void
+nv_tilde(cmdarg_T *cap)
+{
+ if (!p_to && !VIsual_active && cap->oap->op_type != OP_TILDE)
+ {
+#ifdef FEAT_JOB_CHANNEL
+ if (bt_prompt(curbuf) && !prompt_curpos_editable())
+ {
+ clearopbeep(cap->oap);
+ return;
+ }
+#endif
+ n_swapchar(cap);
+ }
+ else
+ nv_operator(cap);
+}
+
+/*
+ * Handle an operator command.
+ * The actual work is done by do_pending_operator().
+ */
+ static void
+nv_operator(cmdarg_T *cap)
+{
+ int op_type;
+
+ op_type = get_op_type(cap->cmdchar, cap->nchar);
+#ifdef FEAT_JOB_CHANNEL
+ if (bt_prompt(curbuf) && op_is_change(op_type) && !prompt_curpos_editable())
+ {
+ clearopbeep(cap->oap);
+ return;
+ }
+#endif
+
+ if (op_type == cap->oap->op_type) /* double operator works on lines */
+ nv_lineop(cap);
+ else if (!checkclearop(cap->oap))
+ {
+ cap->oap->start = curwin->w_cursor;
+ cap->oap->op_type = op_type;
+#ifdef FEAT_EVAL
+ set_op_var(op_type);
+#endif
+ }
+}
+
+#ifdef FEAT_EVAL
+/*
+ * Set v:operator to the characters for "optype".
+ */
+ static void
+set_op_var(int optype)
+{
+ char_u opchars[3];
+
+ if (optype == OP_NOP)
+ set_vim_var_string(VV_OP, NULL, 0);
+ else
+ {
+ opchars[0] = get_op_char(optype);
+ opchars[1] = get_extra_op_char(optype);
+ opchars[2] = NUL;
+ set_vim_var_string(VV_OP, opchars, -1);
+ }
+}
+#endif
+
+/*
+ * Handle linewise operator "dd", "yy", etc.
+ *
+ * "_" is is a strange motion command that helps make operators more logical.
+ * It is actually implemented, but not documented in the real Vi. This motion
+ * command actually refers to "the current line". Commands like "dd" and "yy"
+ * are really an alternate form of "d_" and "y_". It does accept a count, so
+ * "d3_" works to delete 3 lines.
+ */
+ static void
+nv_lineop(cmdarg_T *cap)
+{
+ cap->oap->motion_type = MLINE;
+ if (cursor_down(cap->count1 - 1L, cap->oap->op_type == OP_NOP) == FAIL)
+ clearopbeep(cap->oap);
+ else if ( (cap->oap->op_type == OP_DELETE /* only with linewise motions */
+ && cap->oap->motion_force != 'v'
+ && cap->oap->motion_force != Ctrl_V)
+ || cap->oap->op_type == OP_LSHIFT
+ || cap->oap->op_type == OP_RSHIFT)
+ beginline(BL_SOL | BL_FIX);
+ else if (cap->oap->op_type != OP_YANK) /* 'Y' does not move cursor */
+ beginline(BL_WHITE | BL_FIX);
+}
+
+/*
+ * <Home> command.
+ */
+ static void
+nv_home(cmdarg_T *cap)
+{
+ /* CTRL-HOME is like "gg" */
+ if (mod_mask & MOD_MASK_CTRL)
+ nv_goto(cap);
+ else
+ {
+ cap->count0 = 1;
+ nv_pipe(cap);
+ }
+ ins_at_eol = FALSE; /* Don't move cursor past eol (only necessary in a
+ one-character line). */
+}
+
+/*
+ * "|" command.
+ */
+ static void
+nv_pipe(cmdarg_T *cap)
+{
+ cap->oap->motion_type = MCHAR;
+ cap->oap->inclusive = FALSE;
+ beginline(0);
+ if (cap->count0 > 0)
+ {
+ coladvance((colnr_T)(cap->count0 - 1));
+ curwin->w_curswant = (colnr_T)(cap->count0 - 1);
+ }
+ else
+ curwin->w_curswant = 0;
+ /* keep curswant at the column where we wanted to go, not where
+ * we ended; differs if line is too short */
+ curwin->w_set_curswant = FALSE;
+}
+
+/*
+ * Handle back-word command "b" and "B".
+ * cap->arg is 1 for "B"
+ */
+ static void
+nv_bck_word(cmdarg_T *cap)
+{
+ cap->oap->motion_type = MCHAR;
+ cap->oap->inclusive = FALSE;
+ curwin->w_set_curswant = TRUE;
+ if (bck_word(cap->count1, cap->arg, FALSE) == FAIL)
+ clearopbeep(cap->oap);
+#ifdef FEAT_FOLDING
+ else if ((fdo_flags & FDO_HOR) && KeyTyped && cap->oap->op_type == OP_NOP)
+ foldOpenCursor();
+#endif
+}
+
+/*
+ * Handle word motion commands "e", "E", "w" and "W".
+ * cap->arg is TRUE for "E" and "W".
+ */
+ static void
+nv_wordcmd(cmdarg_T *cap)
+{
+ int n;
+ int word_end;
+ int flag = FALSE;
+ pos_T startpos = curwin->w_cursor;
+
+ /*
+ * Set inclusive for the "E" and "e" command.
+ */
+ if (cap->cmdchar == 'e' || cap->cmdchar == 'E')
+ word_end = TRUE;
+ else
+ word_end = FALSE;
+ cap->oap->inclusive = word_end;
+
+ /*
+ * "cw" and "cW" are a special case.
+ */
+ if (!word_end && cap->oap->op_type == OP_CHANGE)
+ {
+ n = gchar_cursor();
+ if (n != NUL) /* not an empty line */
+ {
+ if (VIM_ISWHITE(n))
+ {
+ /*
+ * Reproduce a funny Vi behaviour: "cw" on a blank only
+ * changes one character, not all blanks until the start of
+ * the next word. Only do this when the 'w' flag is included
+ * in 'cpoptions'.
+ */
+ if (cap->count1 == 1 && vim_strchr(p_cpo, CPO_CW) != NULL)
+ {
+ cap->oap->inclusive = TRUE;
+ cap->oap->motion_type = MCHAR;
+ return;
+ }
+ }
+ else
+ {
+ /*
+ * This is a little strange. To match what the real Vi does,
+ * we effectively map 'cw' to 'ce', and 'cW' to 'cE', provided
+ * that we are not on a space or a TAB. This seems impolite
+ * at first, but it's really more what we mean when we say
+ * 'cw'.
+ * Another strangeness: When standing on the end of a word
+ * "ce" will change until the end of the next word, but "cw"
+ * will change only one character! This is done by setting
+ * flag.
+ */
+ cap->oap->inclusive = TRUE;
+ word_end = TRUE;
+ flag = TRUE;
+ }
+ }
+ }
+
+ cap->oap->motion_type = MCHAR;
+ curwin->w_set_curswant = TRUE;
+ if (word_end)
+ n = end_word(cap->count1, cap->arg, flag, FALSE);
+ else
+ n = fwd_word(cap->count1, cap->arg, cap->oap->op_type != OP_NOP);
+
+ /* Don't leave the cursor on the NUL past the end of line. Unless we
+ * didn't move it forward. */
+ if (LT_POS(startpos, curwin->w_cursor))
+ adjust_cursor(cap->oap);
+
+ if (n == FAIL && cap->oap->op_type == OP_NOP)
+ clearopbeep(cap->oap);
+ else
+ {
+ adjust_for_sel(cap);
+#ifdef FEAT_FOLDING
+ if ((fdo_flags & FDO_HOR) && KeyTyped && cap->oap->op_type == OP_NOP)
+ foldOpenCursor();
+#endif
+ }
+}
+
+/*
+ * Used after a movement command: If the cursor ends up on the NUL after the
+ * end of the line, may move it back to the last character and make the motion
+ * inclusive.
+ */
+ static void
+adjust_cursor(oparg_T *oap)
+{
+ /* The cursor cannot remain on the NUL when:
+ * - the column is > 0
+ * - not in Visual mode or 'selection' is "o"
+ * - 'virtualedit' is not "all" and not "onemore".
+ */
+ if (curwin->w_cursor.col > 0 && gchar_cursor() == NUL
+ && (!VIsual_active || *p_sel == 'o')
+ && !virtual_active() && (ve_flags & VE_ONEMORE) == 0)
+ {
+ --curwin->w_cursor.col;
+ /* prevent cursor from moving on the trail byte */
+ if (has_mbyte)
+ mb_adjust_cursor();
+ oap->inclusive = TRUE;
+ }
+}
+
+/*
+ * "0" and "^" commands.
+ * cap->arg is the argument for beginline().
+ */
+ static void
+nv_beginline(cmdarg_T *cap)
+{
+ cap->oap->motion_type = MCHAR;
+ cap->oap->inclusive = FALSE;
+ beginline(cap->arg);
+#ifdef FEAT_FOLDING
+ if ((fdo_flags & FDO_HOR) && KeyTyped && cap->oap->op_type == OP_NOP)
+ foldOpenCursor();
+#endif
+ ins_at_eol = FALSE; /* Don't move cursor past eol (only necessary in a
+ one-character line). */
+}
+
+/*
+ * In exclusive Visual mode, may include the last character.
+ */
+ static void
+adjust_for_sel(cmdarg_T *cap)
+{
+ if (VIsual_active && cap->oap->inclusive && *p_sel == 'e'
+ && gchar_cursor() != NUL && LT_POS(VIsual, curwin->w_cursor))
+ {
+ if (has_mbyte)
+ inc_cursor();
+ else
+ ++curwin->w_cursor.col;
+ cap->oap->inclusive = FALSE;
+ }
+}
+
+/*
+ * Exclude last character at end of Visual area for 'selection' == "exclusive".
+ * Should check VIsual_mode before calling this.
+ * Returns TRUE when backed up to the previous line.
+ */
+ static int
+unadjust_for_sel(void)
+{
+ pos_T *pp;
+
+ if (*p_sel == 'e' && !EQUAL_POS(VIsual, curwin->w_cursor))
+ {
+ if (LT_POS(VIsual, curwin->w_cursor))
+ pp = &curwin->w_cursor;
+ else
+ pp = &VIsual;
+ if (pp->coladd > 0)
+ --pp->coladd;
+ else
+ if (pp->col > 0)
+ {
+ --pp->col;
+ mb_adjustpos(curbuf, pp);
+ }
+ else if (pp->lnum > 1)
+ {
+ --pp->lnum;
+ pp->col = (colnr_T)STRLEN(ml_get(pp->lnum));
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/*
+ * SELECT key in Normal or Visual mode: end of Select mode mapping.
+ */
+ static void
+nv_select(cmdarg_T *cap)
+{
+ if (VIsual_active)
+ VIsual_select = TRUE;
+ else if (VIsual_reselect)
+ {
+ cap->nchar = 'v'; /* fake "gv" command */
+ cap->arg = TRUE;
+ nv_g_cmd(cap);
+ }
+}
+
+
+/*
+ * "G", "gg", CTRL-END, CTRL-HOME.
+ * cap->arg is TRUE for "G".
+ */
+ static void
+nv_goto(cmdarg_T *cap)
+{
+ linenr_T lnum;
+
+ if (cap->arg)
+ lnum = curbuf->b_ml.ml_line_count;
+ else
+ lnum = 1L;
+ cap->oap->motion_type = MLINE;
+ setpcmark();
+
+ /* When a count is given, use it instead of the default lnum */
+ if (cap->count0 != 0)
+ lnum = cap->count0;
+ 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;
+ beginline(BL_SOL | BL_FIX);
+#ifdef FEAT_FOLDING
+ if ((fdo_flags & FDO_JUMP) && KeyTyped && cap->oap->op_type == OP_NOP)
+ foldOpenCursor();
+#endif
+}
+
+/*
+ * CTRL-\ in Normal mode.
+ */
+ static void
+nv_normal(cmdarg_T *cap)
+{
+ if (cap->nchar == Ctrl_N || cap->nchar == Ctrl_G)
+ {
+ clearop(cap->oap);
+ if (restart_edit != 0 && mode_displayed)
+ clear_cmdline = TRUE; /* unshow mode later */
+ restart_edit = 0;
+#ifdef FEAT_CMDWIN
+ if (cmdwin_type != 0)
+ cmdwin_result = Ctrl_C;
+#endif
+ if (VIsual_active)
+ {
+ end_visual_mode(); /* stop Visual */
+ redraw_curbuf_later(INVERTED);
+ }
+ /* CTRL-\ CTRL-G restarts Insert mode when 'insertmode' is set. */
+ if (cap->nchar == Ctrl_G && p_im)
+ restart_edit = 'a';
+ }
+ else
+ clearopbeep(cap->oap);
+}
+
+/*
+ * ESC in Normal mode: beep, but don't flush buffers.
+ * Don't even beep if we are canceling a command.
+ */
+ static void
+nv_esc(cmdarg_T *cap)
+{
+ int no_reason;
+
+ no_reason = (cap->oap->op_type == OP_NOP
+ && cap->opcount == 0
+ && cap->count0 == 0
+ && cap->oap->regname == 0
+ && !p_im);
+
+ if (cap->arg) /* TRUE for CTRL-C */
+ {
+ if (restart_edit == 0
+#ifdef FEAT_CMDWIN
+ && cmdwin_type == 0
+#endif
+ && !VIsual_active
+ && no_reason)
+ msg(_("Type :qa! and press <Enter> to abandon all changes and exit Vim"));
+
+ /* Don't reset "restart_edit" when 'insertmode' is set, it won't be
+ * set again below when halfway a mapping. */
+ if (!p_im)
+ restart_edit = 0;
+#ifdef FEAT_CMDWIN
+ if (cmdwin_type != 0)
+ {
+ cmdwin_result = K_IGNORE;
+ got_int = FALSE; /* don't stop executing autocommands et al. */
+ return;
+ }
+#endif
+ }
+
+ if (VIsual_active)
+ {
+ end_visual_mode(); /* stop Visual */
+ check_cursor_col(); /* make sure cursor is not beyond EOL */
+ curwin->w_set_curswant = TRUE;
+ redraw_curbuf_later(INVERTED);
+ }
+ else if (no_reason)
+ vim_beep(BO_ESC);
+ clearop(cap->oap);
+
+ /* A CTRL-C is often used at the start of a menu. When 'insertmode' is
+ * set return to Insert mode afterwards. */
+ if (restart_edit == 0 && goto_im() && ex_normal_busy == 0)
+ restart_edit = 'a';
+}
+
+/*
+ * Handle "A", "a", "I", "i" and <Insert> commands.
+ * Also handle K_PS, start bracketed paste.
+ */
+ static void
+nv_edit(cmdarg_T *cap)
+{
+ /* <Insert> is equal to "i" */
+ if (cap->cmdchar == K_INS || cap->cmdchar == K_KINS)
+ cap->cmdchar = 'i';
+
+ /* in Visual mode "A" and "I" are an operator */
+ if (VIsual_active && (cap->cmdchar == 'A' || cap->cmdchar == 'I'))
+ {
+#ifdef FEAT_TERMINAL
+ if (term_in_normal_mode())
+ {
+ end_visual_mode();
+ clearop(cap->oap);
+ term_enter_job_mode();
+ return;
+ }
+#endif
+ v_visop(cap);
+ }
+
+ /* in Visual mode and after an operator "a" and "i" are for text objects */
+ else if ((cap->cmdchar == 'a' || cap->cmdchar == 'i')
+ && (cap->oap->op_type != OP_NOP || VIsual_active))
+ {
+#ifdef FEAT_TEXTOBJ
+ nv_object(cap);
+#else
+ clearopbeep(cap->oap);
+#endif
+ }
+#ifdef FEAT_TERMINAL
+ else if (term_in_normal_mode())
+ {
+ clearop(cap->oap);
+ term_enter_job_mode();
+ return;
+ }
+#endif
+ else if (!curbuf->b_p_ma && !p_im)
+ {
+ /* Only give this error when 'insertmode' is off. */
+ emsg(_(e_modifiable));
+ clearop(cap->oap);
+ if (cap->cmdchar == K_PS)
+ /* drop the pasted text */
+ bracketed_paste(PASTE_INSERT, TRUE, NULL);
+ }
+ else if (cap->cmdchar == K_PS && VIsual_active)
+ {
+ pos_T old_pos = curwin->w_cursor;
+ pos_T old_visual = VIsual;
+
+ /* In Visual mode the selected text is deleted. */
+ if (VIsual_mode == 'V' || curwin->w_cursor.lnum != VIsual.lnum)
+ {
+ shift_delete_registers();
+ cap->oap->regname = '1';
+ }
+ else
+ cap->oap->regname = '-';
+ cap->cmdchar = 'd';
+ cap->nchar = NUL;
+ nv_operator(cap);
+ do_pending_operator(cap, 0, FALSE);
+ cap->cmdchar = K_PS;
+
+ /* When the last char in the line was deleted then append. Detect this
+ * by checking if the cursor moved to before the Visual area. */
+ if (*ml_get_cursor() != NUL && LT_POS(curwin->w_cursor, old_pos)
+ && LT_POS(curwin->w_cursor, old_visual))
+ inc_cursor();
+
+ /* Insert to replace the deleted text with the pasted text. */
+ invoke_edit(cap, FALSE, cap->cmdchar, FALSE);
+ }
+ else if (!checkclearopq(cap->oap))
+ {
+ switch (cap->cmdchar)
+ {
+ case 'A': /* "A"ppend after the line */
+ curwin->w_set_curswant = TRUE;
+ if (ve_flags == VE_ALL)
+ {
+ int save_State = State;
+
+ /* Pretend Insert mode here to allow the cursor on the
+ * character past the end of the line */
+ State = INSERT;
+ coladvance((colnr_T)MAXCOL);
+ State = save_State;
+ }
+ else
+ curwin->w_cursor.col += (colnr_T)STRLEN(ml_get_cursor());
+ break;
+
+ case 'I': /* "I"nsert before the first non-blank */
+ if (vim_strchr(p_cpo, CPO_INSEND) == NULL)
+ beginline(BL_WHITE);
+ else
+ beginline(BL_WHITE|BL_FIX);
+ break;
+
+ case K_PS:
+ /* Bracketed paste works like "a"ppend, unless the cursor is in
+ * the first column, then it inserts. */
+ if (curwin->w_cursor.col == 0)
+ break;
+ /* FALLTHROUGH */
+
+ case 'a': /* "a"ppend is like "i"nsert on the next character. */
+ /* increment coladd when in virtual space, increment the
+ * column otherwise, also to append after an unprintable char */
+ if (virtual_active()
+ && (curwin->w_cursor.coladd > 0
+ || *ml_get_cursor() == NUL
+ || *ml_get_cursor() == TAB))
+ curwin->w_cursor.coladd++;
+ else if (*ml_get_cursor() != NUL)
+ inc_cursor();
+ break;
+ }
+
+ if (curwin->w_cursor.coladd && cap->cmdchar != 'A')
+ {
+ int save_State = State;
+
+ /* Pretend Insert mode here to allow the cursor on the
+ * character past the end of the line */
+ State = INSERT;
+ coladvance(getviscol());
+ State = save_State;
+ }
+
+ invoke_edit(cap, FALSE, cap->cmdchar, FALSE);
+ }
+ else if (cap->cmdchar == K_PS)
+ /* drop the pasted text */
+ bracketed_paste(PASTE_INSERT, TRUE, NULL);
+}
+
+/*
+ * Invoke edit() and take care of "restart_edit" and the return value.
+ */
+ static void
+invoke_edit(
+ cmdarg_T *cap,
+ int repl, /* "r" or "gr" command */
+ int cmd,
+ int startln)
+{
+ int restart_edit_save = 0;
+
+ /* Complicated: When the user types "a<C-O>a" we don't want to do Insert
+ * mode recursively. But when doing "a<C-O>." or "a<C-O>rx" we do allow
+ * it. */
+ if (repl || !stuff_empty())
+ restart_edit_save = restart_edit;
+ else
+ restart_edit_save = 0;
+
+ /* Always reset "restart_edit", this is not a restarted edit. */
+ restart_edit = 0;
+
+ if (edit(cmd, startln, cap->count1))
+ cap->retval |= CA_COMMAND_BUSY;
+
+ if (restart_edit == 0)
+ restart_edit = restart_edit_save;
+}
+
+#ifdef FEAT_TEXTOBJ
+/*
+ * "a" or "i" while an operator is pending or in Visual mode: object motion.
+ */
+ static void
+nv_object(
+ cmdarg_T *cap)
+{
+ int flag;
+ int include;
+ char_u *mps_save;
+
+ if (cap->cmdchar == 'i')
+ include = FALSE; /* "ix" = inner object: exclude white space */
+ else
+ include = TRUE; /* "ax" = an object: include white space */
+
+ /* Make sure (), [], {} and <> are in 'matchpairs' */
+ mps_save = curbuf->b_p_mps;
+ curbuf->b_p_mps = (char_u *)"(:),{:},[:],<:>";
+
+ switch (cap->nchar)
+ {
+ case 'w': /* "aw" = a word */
+ flag = current_word(cap->oap, cap->count1, include, FALSE);
+ break;
+ case 'W': /* "aW" = a WORD */
+ flag = current_word(cap->oap, cap->count1, include, TRUE);
+ break;
+ case 'b': /* "ab" = a braces block */
+ case '(':
+ case ')':
+ flag = current_block(cap->oap, cap->count1, include, '(', ')');
+ break;
+ case 'B': /* "aB" = a Brackets block */
+ case '{':
+ case '}':
+ flag = current_block(cap->oap, cap->count1, include, '{', '}');
+ break;
+ case '[': /* "a[" = a [] block */
+ case ']':
+ flag = current_block(cap->oap, cap->count1, include, '[', ']');
+ break;
+ case '<': /* "a<" = a <> block */
+ case '>':
+ flag = current_block(cap->oap, cap->count1, include, '<', '>');
+ break;
+ case 't': /* "at" = a tag block (xml and html) */
+ /* Do not adjust oap->end in do_pending_operator()
+ * otherwise there are different results for 'dit'
+ * (note leading whitespace in last line):
+ * 1) <b> 2) <b>
+ * foobar foobar
+ * </b> </b>
+ */
+ cap->retval |= CA_NO_ADJ_OP_END;
+ flag = current_tagblock(cap->oap, cap->count1, include);
+ break;
+ case 'p': /* "ap" = a paragraph */
+ flag = current_par(cap->oap, cap->count1, include, 'p');
+ break;
+ case 's': /* "as" = a sentence */
+ flag = current_sent(cap->oap, cap->count1, include);
+ break;
+ case '"': /* "a"" = a double quoted string */
+ case '\'': /* "a'" = a single quoted string */
+ case '`': /* "a`" = a backtick quoted string */
+ flag = current_quote(cap->oap, cap->count1, include,
+ cap->nchar);
+ break;
+#if 0 /* TODO */
+ case 'S': /* "aS" = a section */
+ case 'f': /* "af" = a filename */
+ case 'u': /* "au" = a URL */
+#endif
+ default:
+ flag = FAIL;
+ break;
+ }
+
+ curbuf->b_p_mps = mps_save;
+ if (flag == FAIL)
+ clearopbeep(cap->oap);
+ adjust_cursor_col();
+ curwin->w_set_curswant = TRUE;
+}
+#endif
+
+/*
+ * "q" command: Start/stop recording.
+ * "q:", "q/", "q?": edit command-line in command-line window.
+ */
+ static void
+nv_record(cmdarg_T *cap)
+{
+ if (cap->oap->op_type == OP_FORMAT)
+ {
+ /* "gqq" is the same as "gqgq": format line */
+ cap->cmdchar = 'g';
+ cap->nchar = 'q';
+ nv_operator(cap);
+ }
+ else if (!checkclearop(cap->oap))
+ {
+#ifdef FEAT_CMDWIN
+ if (cap->nchar == ':' || cap->nchar == '/' || cap->nchar == '?')
+ {
+ stuffcharReadbuff(cap->nchar);
+ stuffcharReadbuff(K_CMDWIN);
+ }
+ else
+#endif
+ /* (stop) recording into a named register, unless executing a
+ * register */
+ if (reg_executing == 0 && do_record(cap->nchar) == FAIL)
+ clearopbeep(cap->oap);
+ }
+}
+
+/*
+ * Handle the "@r" command.
+ */
+ static void
+nv_at(cmdarg_T *cap)
+{
+ if (checkclearop(cap->oap))
+ return;
+#ifdef FEAT_EVAL
+ if (cap->nchar == '=')
+ {
+ if (get_expr_register() == NUL)
+ return;
+ }
+#endif
+ while (cap->count1-- && !got_int)
+ {
+ if (do_execreg(cap->nchar, FALSE, FALSE, FALSE) == FAIL)
+ {
+ clearopbeep(cap->oap);
+ break;
+ }
+ line_breakcheck();
+ }
+}
+
+/*
+ * Handle the CTRL-U and CTRL-D commands.
+ */
+ static void
+nv_halfpage(cmdarg_T *cap)
+{
+ if ((cap->cmdchar == Ctrl_U && curwin->w_cursor.lnum == 1)
+ || (cap->cmdchar == Ctrl_D
+ && curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count))
+ clearopbeep(cap->oap);
+ else if (!checkclearop(cap->oap))
+ halfpage(cap->cmdchar == Ctrl_D, cap->count0);
+}
+
+/*
+ * Handle "J" or "gJ" command.
+ */
+ static void
+nv_join(cmdarg_T *cap)
+{
+ if (VIsual_active) /* join the visual lines */
+ nv_operator(cap);
+ else if (!checkclearop(cap->oap))
+ {
+ if (cap->count0 <= 1)
+ cap->count0 = 2; /* default for join is two lines! */
+ if (curwin->w_cursor.lnum + cap->count0 - 1 >
+ curbuf->b_ml.ml_line_count)
+ {
+ /* can't join when on the last line */
+ if (cap->count0 <= 2)
+ {
+ clearopbeep(cap->oap);
+ return;
+ }
+ cap->count0 = curbuf->b_ml.ml_line_count
+ - curwin->w_cursor.lnum + 1;
+ }
+
+ prep_redo(cap->oap->regname, cap->count0,
+ NUL, cap->cmdchar, NUL, NUL, cap->nchar);
+ (void)do_join(cap->count0, cap->nchar == NUL, TRUE, TRUE, TRUE);
+ }
+}
+
+/*
+ * "P", "gP", "p" and "gp" commands.
+ */
+ static void
+nv_put(cmdarg_T *cap)
+{
+ int regname = 0;
+ void *reg1 = NULL, *reg2 = NULL;
+ int empty = FALSE;
+ int was_visual = FALSE;
+ int dir;
+ int flags = 0;
+
+ if (cap->oap->op_type != OP_NOP)
+ {
+#ifdef FEAT_DIFF
+ /* "dp" is ":diffput" */
+ if (cap->oap->op_type == OP_DELETE && cap->cmdchar == 'p')
+ {
+ clearop(cap->oap);
+ nv_diffgetput(TRUE, cap->opcount);
+ }
+ else
+#endif
+ clearopbeep(cap->oap);
+ }
+#ifdef FEAT_JOB_CHANNEL
+ else if (bt_prompt(curbuf) && !prompt_curpos_editable())
+ {
+ clearopbeep(cap->oap);
+ }
+#endif
+ else
+ {
+ dir = (cap->cmdchar == 'P'
+ || (cap->cmdchar == 'g' && cap->nchar == 'P'))
+ ? BACKWARD : FORWARD;
+ prep_redo_cmd(cap);
+ if (cap->cmdchar == 'g')
+ flags |= PUT_CURSEND;
+
+ if (VIsual_active)
+ {
+ /* Putting in Visual mode: The put text replaces the selected
+ * text. First delete the selected text, then put the new text.
+ * Need to save and restore the registers that the delete
+ * overwrites if the old contents is being put.
+ */
+ was_visual = TRUE;
+ regname = cap->oap->regname;
+#ifdef FEAT_CLIPBOARD
+ adjust_clip_reg(&regname);
+#endif
+ if (regname == 0 || regname == '"'
+ || VIM_ISDIGIT(regname) || regname == '-'
+#ifdef FEAT_CLIPBOARD
+ || (clip_unnamed && (regname == '*' || regname == '+'))
+#endif
+
+ )
+ {
+ /* The delete is going to overwrite the register we want to
+ * put, save it first. */
+ reg1 = get_register(regname, TRUE);
+ }
+
+ /* Now delete the selected text. */
+ cap->cmdchar = 'd';
+ cap->nchar = NUL;
+ cap->oap->regname = NUL;
+ nv_operator(cap);
+ do_pending_operator(cap, 0, FALSE);
+ empty = (curbuf->b_ml.ml_flags & ML_EMPTY);
+
+ /* delete PUT_LINE_BACKWARD; */
+ cap->oap->regname = regname;
+
+ if (reg1 != NULL)
+ {
+ /* Delete probably changed the register we want to put, save
+ * it first. Then put back what was there before the delete. */
+ reg2 = get_register(regname, FALSE);
+ put_register(regname, reg1);
+ }
+
+ /* When deleted a linewise Visual area, put the register as
+ * lines to avoid it joined with the next line. When deletion was
+ * characterwise, split a line when putting lines. */
+ if (VIsual_mode == 'V')
+ flags |= PUT_LINE;
+ else if (VIsual_mode == 'v')
+ flags |= PUT_LINE_SPLIT;
+ if (VIsual_mode == Ctrl_V && dir == FORWARD)
+ flags |= PUT_LINE_FORWARD;
+ dir = BACKWARD;
+ if ((VIsual_mode != 'V'
+ && curwin->w_cursor.col < curbuf->b_op_start.col)
+ || (VIsual_mode == 'V'
+ && curwin->w_cursor.lnum < curbuf->b_op_start.lnum))
+ /* cursor is at the end of the line or end of file, put
+ * forward. */
+ dir = FORWARD;
+ /* May have been reset in do_put(). */
+ VIsual_active = TRUE;
+ }
+ do_put(cap->oap->regname, dir, cap->count1, flags);
+
+ /* If a register was saved, put it back now. */
+ if (reg2 != NULL)
+ put_register(regname, reg2);
+
+ /* What to reselect with "gv"? Selecting the just put text seems to
+ * be the most useful, since the original text was removed. */
+ if (was_visual)
+ {
+ curbuf->b_visual.vi_start = curbuf->b_op_start;
+ curbuf->b_visual.vi_end = curbuf->b_op_end;
+ /* need to adjust cursor position */
+ if (*p_sel == 'e')
+ inc(&curbuf->b_visual.vi_end);
+ }
+
+ /* When all lines were selected and deleted do_put() leaves an empty
+ * line that needs to be deleted now. */
+ if (empty && *ml_get(curbuf->b_ml.ml_line_count) == NUL)
+ {
+ ml_delete(curbuf->b_ml.ml_line_count, TRUE);
+
+ /* If the cursor was in that line, move it to the end of the last
+ * line. */
+ if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
+ {
+ curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
+ coladvance((colnr_T)MAXCOL);
+ }
+ }
+ auto_format(FALSE, TRUE);
+ }
+}
+
+/*
+ * "o" and "O" commands.
+ */
+ static void
+nv_open(cmdarg_T *cap)
+{
+#ifdef FEAT_DIFF
+ /* "do" is ":diffget" */
+ if (cap->oap->op_type == OP_DELETE && cap->cmdchar == 'o')
+ {
+ clearop(cap->oap);
+ nv_diffgetput(FALSE, cap->opcount);
+ }
+ else
+#endif
+ if (VIsual_active) /* switch start and end of visual */
+ v_swap_corners(cap->cmdchar);
+#ifdef FEAT_JOB_CHANNEL
+ else if (bt_prompt(curbuf))
+ {
+ clearopbeep(cap->oap);
+ }
+#endif
+ else
+ n_opencmd(cap);
+}
+
+#ifdef FEAT_NETBEANS_INTG
+ static void
+nv_nbcmd(cmdarg_T *cap)
+{
+ netbeans_keycommand(cap->nchar);
+}
+#endif
+
+#ifdef FEAT_DND
+ static void
+nv_drop(cmdarg_T *cap UNUSED)
+{
+ do_put('~', BACKWARD, 1L, PUT_CURSEND);
+}
+#endif
+
+/*
+ * Trigger CursorHold event.
+ * When waiting for a character for 'updatetime' K_CURSORHOLD is put in the
+ * input buffer. "did_cursorhold" is set to avoid retriggering.
+ */
+ static void
+nv_cursorhold(cmdarg_T *cap)
+{
+ apply_autocmds(EVENT_CURSORHOLD, NULL, NULL, FALSE, curbuf);
+ did_cursorhold = TRUE;
+ cap->retval |= CA_COMMAND_BUSY; /* don't call edit() now */
+}
+
+/*
+ * Calculate start/end virtual columns for operating in block mode.
+ */
+ static void
+get_op_vcol(
+ oparg_T *oap,
+ colnr_T redo_VIsual_vcol,
+ int initial) /* when TRUE adjust position for 'selectmode' */
+{
+ colnr_T start, end;
+
+ if (VIsual_mode != Ctrl_V
+ || (!initial && oap->end.col < curwin->w_width))
+ return;
+
+ oap->block_mode = TRUE;
+
+ /* prevent from moving onto a trail byte */
+ if (has_mbyte)
+ mb_adjustpos(curwin->w_buffer, &oap->end);
+
+ getvvcol(curwin, &(oap->start), &oap->start_vcol, NULL, &oap->end_vcol);
+
+ if (!redo_VIsual_busy)
+ {
+ getvvcol(curwin, &(oap->end), &start, NULL, &end);
+
+ if (start < oap->start_vcol)
+ oap->start_vcol = start;
+ if (end > oap->end_vcol)
+ {
+ if (initial && *p_sel == 'e' && start >= 1
+ && start - 1 >= oap->end_vcol)
+ oap->end_vcol = start - 1;
+ else
+ oap->end_vcol = end;
+ }
+ }
+
+ /* if '$' was used, get oap->end_vcol from longest line */
+ if (curwin->w_curswant == MAXCOL)
+ {
+ curwin->w_cursor.col = MAXCOL;
+ oap->end_vcol = 0;
+ for (curwin->w_cursor.lnum = oap->start.lnum;
+ curwin->w_cursor.lnum <= oap->end.lnum;
+ ++curwin->w_cursor.lnum)
+ {
+ getvvcol(curwin, &curwin->w_cursor, NULL, NULL, &end);
+ if (end > oap->end_vcol)
+ oap->end_vcol = end;
+ }
+ }
+ else if (redo_VIsual_busy)
+ oap->end_vcol = oap->start_vcol + redo_VIsual_vcol - 1;
+ /*
+ * Correct oap->end.col and oap->start.col to be the
+ * upper-left and lower-right corner of the block area.
+ *
+ * (Actually, this does convert column positions into character
+ * positions)
+ */
+ curwin->w_cursor.lnum = oap->end.lnum;
+ coladvance(oap->end_vcol);
+ oap->end = curwin->w_cursor;
+
+ curwin->w_cursor = oap->start;
+ coladvance(oap->start_vcol);
+ oap->start = curwin->w_cursor;
+}
diff --git a/src/ops.c b/src/ops.c
new file mode 100644
index 0000000..dacbfd8
--- /dev/null
+++ b/src/ops.c
@@ -0,0 +1,7467 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * ops.c: implementation of various operators: op_shift, op_delete, op_tilde,
+ * op_change, op_yank, do_put, do_join
+ */
+
+#include "vim.h"
+
+/*
+ * Number of registers.
+ * 0 = unnamed register, for normal yanks and puts
+ * 1..9 = registers '1' to '9', for deletes
+ * 10..35 = registers 'a' to 'z'
+ * 36 = delete register '-'
+ * 37 = Selection register '*'. Only if FEAT_CLIPBOARD defined
+ * 38 = Clipboard register '+'. Only if FEAT_CLIPBOARD and FEAT_X11 defined
+ */
+/*
+ * Symbolic names for some registers.
+ */
+#define DELETION_REGISTER 36
+#ifdef FEAT_CLIPBOARD
+# define STAR_REGISTER 37
+# ifdef FEAT_X11
+# define PLUS_REGISTER 38
+# else
+# define PLUS_REGISTER STAR_REGISTER /* there is only one */
+# endif
+#endif
+#ifdef FEAT_DND
+# define TILDE_REGISTER (PLUS_REGISTER + 1)
+#endif
+
+#ifdef FEAT_CLIPBOARD
+# ifdef FEAT_DND
+# define NUM_REGISTERS (TILDE_REGISTER + 1)
+# else
+# define NUM_REGISTERS (PLUS_REGISTER + 1)
+# endif
+#else
+# define NUM_REGISTERS 37
+#endif
+
+/*
+ * Each yank register has an array of pointers to lines.
+ */
+typedef struct
+{
+ char_u **y_array; /* pointer to array of line pointers */
+ linenr_T y_size; /* number of lines in y_array */
+ char_u y_type; /* MLINE, MCHAR or MBLOCK */
+ colnr_T y_width; /* only set if y_type == MBLOCK */
+#ifdef FEAT_VIMINFO
+ time_t y_time_set;
+#endif
+} yankreg_T;
+
+static yankreg_T y_regs[NUM_REGISTERS];
+
+static yankreg_T *y_current; /* ptr to current yankreg */
+static int y_append; /* TRUE when appending */
+static yankreg_T *y_previous = NULL; /* ptr to last written yankreg */
+
+/*
+ * structure used by block_prep, op_delete and op_yank for blockwise operators
+ * also op_change, op_shift, op_insert, op_replace - AKelly
+ */
+struct block_def
+{
+ int startspaces; /* 'extra' cols before first char */
+ int endspaces; /* 'extra' cols after last char */
+ int textlen; /* chars in block */
+ char_u *textstart; /* pointer to 1st char (partially) in block */
+ colnr_T textcol; /* index of chars (partially) in block */
+ colnr_T start_vcol; /* start col of 1st char wholly inside block */
+ colnr_T end_vcol; /* start col of 1st char wholly after block */
+ int is_short; /* TRUE if line is too short to fit in block */
+ int is_MAX; /* TRUE if curswant==MAXCOL when starting */
+ int is_oneChar; /* TRUE if block within one character */
+ int pre_whitesp; /* screen cols of ws before block */
+ int pre_whitesp_c; /* chars of ws before block */
+ colnr_T end_char_vcols; /* number of vcols of post-block char */
+ colnr_T start_char_vcols; /* number of vcols of pre-block char */
+};
+
+static void shift_block(oparg_T *oap, int amount);
+static int stuff_yank(int, char_u *);
+static void put_reedit_in_typebuf(int silent);
+static int put_in_typebuf(char_u *s, int esc, int colon,
+ int silent);
+static void stuffescaped(char_u *arg, int literally);
+static void mb_adjust_opend(oparg_T *oap);
+static void free_yank_all(void);
+static int yank_copy_line(struct block_def *bd, long y_idx);
+#ifdef FEAT_CLIPBOARD
+static void copy_yank_reg(yankreg_T *reg);
+static void may_set_selection(void);
+#endif
+static void dis_msg(char_u *p, int skip_esc);
+static void block_prep(oparg_T *oap, struct block_def *, linenr_T, int);
+static int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1);
+#if defined(FEAT_CLIPBOARD) || defined(FEAT_EVAL)
+static void str_to_reg(yankreg_T *y_ptr, int yank_type, char_u *str, long len, long blocklen, int str_list);
+#endif
+static int ends_in_white(linenr_T lnum);
+#ifdef FEAT_COMMENTS
+static int fmt_check_par(linenr_T, int *, char_u **, int do_comments);
+#else
+static int fmt_check_par(linenr_T);
+#endif
+
+// Flags for third item in "opchars".
+#define OPF_LINES 1 // operator always works on lines
+#define OPF_CHANGE 2 // operator changes text
+
+/*
+ * The names of operators.
+ * IMPORTANT: Index must correspond with defines in vim.h!!!
+ * The third field holds OPF_ flags.
+ */
+static char opchars[][3] =
+{
+ {NUL, NUL, 0}, // OP_NOP
+ {'d', NUL, OPF_CHANGE}, // OP_DELETE
+ {'y', NUL, 0}, // OP_YANK
+ {'c', NUL, OPF_CHANGE}, // OP_CHANGE
+ {'<', NUL, OPF_LINES | OPF_CHANGE}, // OP_LSHIFT
+ {'>', NUL, OPF_LINES | OPF_CHANGE}, // OP_RSHIFT
+ {'!', NUL, OPF_LINES | OPF_CHANGE}, // OP_FILTER
+ {'g', '~', OPF_CHANGE}, // OP_TILDE
+ {'=', NUL, OPF_LINES | OPF_CHANGE}, // OP_INDENT
+ {'g', 'q', OPF_LINES | OPF_CHANGE}, // OP_FORMAT
+ {':', NUL, OPF_LINES}, // OP_COLON
+ {'g', 'U', OPF_CHANGE}, // OP_UPPER
+ {'g', 'u', OPF_CHANGE}, // OP_LOWER
+ {'J', NUL, OPF_LINES | OPF_CHANGE}, // DO_JOIN
+ {'g', 'J', OPF_LINES | OPF_CHANGE}, // DO_JOIN_NS
+ {'g', '?', OPF_CHANGE}, // OP_ROT13
+ {'r', NUL, OPF_CHANGE}, // OP_REPLACE
+ {'I', NUL, OPF_CHANGE}, // OP_INSERT
+ {'A', NUL, OPF_CHANGE}, // OP_APPEND
+ {'z', 'f', OPF_LINES}, // OP_FOLD
+ {'z', 'o', OPF_LINES}, // OP_FOLDOPEN
+ {'z', 'O', OPF_LINES}, // OP_FOLDOPENREC
+ {'z', 'c', OPF_LINES}, // OP_FOLDCLOSE
+ {'z', 'C', OPF_LINES}, // OP_FOLDCLOSEREC
+ {'z', 'd', OPF_LINES}, // OP_FOLDDEL
+ {'z', 'D', OPF_LINES}, // OP_FOLDDELREC
+ {'g', 'w', OPF_LINES | OPF_CHANGE}, // OP_FORMAT2
+ {'g', '@', OPF_CHANGE}, // OP_FUNCTION
+ {Ctrl_A, NUL, OPF_CHANGE}, // OP_NR_ADD
+ {Ctrl_X, NUL, OPF_CHANGE}, // OP_NR_SUB
+};
+
+/*
+ * Translate a command name into an operator type.
+ * Must only be called with a valid operator name!
+ */
+ int
+get_op_type(int char1, int char2)
+{
+ int i;
+
+ if (char1 == 'r') /* ignore second character */
+ return OP_REPLACE;
+ if (char1 == '~') /* when tilde is an operator */
+ return OP_TILDE;
+ if (char1 == 'g' && char2 == Ctrl_A) /* add */
+ return OP_NR_ADD;
+ if (char1 == 'g' && char2 == Ctrl_X) /* subtract */
+ return OP_NR_SUB;
+ for (i = 0; ; ++i)
+ {
+ if (opchars[i][0] == char1 && opchars[i][1] == char2)
+ break;
+ if (i == (int)(sizeof(opchars) / sizeof(char [3]) - 1))
+ {
+ internal_error("get_op_type()");
+ break;
+ }
+ }
+ return i;
+}
+
+/*
+ * Return TRUE if operator "op" always works on whole lines.
+ */
+ int
+op_on_lines(int op)
+{
+ return opchars[op][2] & OPF_LINES;
+}
+
+#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
+/*
+ * Return TRUE if operator "op" changes text.
+ */
+ int
+op_is_change(int op)
+{
+ return opchars[op][2] & OPF_CHANGE;
+}
+#endif
+
+/*
+ * Get first operator command character.
+ * Returns 'g' or 'z' if there is another command character.
+ */
+ int
+get_op_char(int optype)
+{
+ return opchars[optype][0];
+}
+
+/*
+ * Get second operator command character.
+ */
+ int
+get_extra_op_char(int optype)
+{
+ return opchars[optype][1];
+}
+
+/*
+ * op_shift - handle a shift operation
+ */
+ void
+op_shift(oparg_T *oap, int curs_top, int amount)
+{
+ long i;
+ int first_char;
+ int block_col = 0;
+
+ if (u_save((linenr_T)(oap->start.lnum - 1),
+ (linenr_T)(oap->end.lnum + 1)) == FAIL)
+ return;
+
+ if (oap->block_mode)
+ block_col = curwin->w_cursor.col;
+
+ for (i = oap->line_count; --i >= 0; )
+ {
+ first_char = *ml_get_curline();
+ if (first_char == NUL) /* empty line */
+ curwin->w_cursor.col = 0;
+ else if (oap->block_mode)
+ shift_block(oap, amount);
+ else
+ /* Move the line right if it doesn't start with '#', 'smartindent'
+ * isn't set or 'cindent' isn't set or '#' isn't in 'cino'. */
+#if defined(FEAT_SMARTINDENT) || defined(FEAT_CINDENT)
+ if (first_char != '#' || !preprocs_left())
+#endif
+ {
+ shift_line(oap->op_type == OP_LSHIFT, p_sr, amount, FALSE);
+ }
+ ++curwin->w_cursor.lnum;
+ }
+
+ changed_lines(oap->start.lnum, 0, oap->end.lnum + 1, 0L);
+ if (oap->block_mode)
+ {
+ curwin->w_cursor.lnum = oap->start.lnum;
+ curwin->w_cursor.col = block_col;
+ }
+ else if (curs_top) /* put cursor on first line, for ">>" */
+ {
+ curwin->w_cursor.lnum = oap->start.lnum;
+ beginline(BL_SOL | BL_FIX); /* shift_line() may have set cursor.col */
+ }
+ else
+ --curwin->w_cursor.lnum; /* put cursor on last line, for ":>" */
+
+#ifdef FEAT_FOLDING
+ /* The cursor line is not in a closed fold */
+ foldOpenCursor();
+#endif
+
+
+ if (oap->line_count > p_report)
+ {
+ char *op;
+ char *msg_line_single;
+ char *msg_line_plural;
+
+ if (oap->op_type == OP_RSHIFT)
+ op = ">";
+ else
+ op = "<";
+ msg_line_single = NGETTEXT("%ld line %sed %d time",
+ "%ld line %sed %d times", amount);
+ msg_line_plural = NGETTEXT("%ld lines %sed %d time",
+ "%ld lines %sed %d times", amount);
+ vim_snprintf((char *)IObuff, IOSIZE,
+ NGETTEXT(msg_line_single, msg_line_plural, oap->line_count),
+ oap->line_count, op, amount);
+ msg((char *)IObuff);
+ }
+
+ /*
+ * Set "'[" and "']" marks.
+ */
+ curbuf->b_op_start = oap->start;
+ curbuf->b_op_end.lnum = oap->end.lnum;
+ curbuf->b_op_end.col = (colnr_T)STRLEN(ml_get(oap->end.lnum));
+ if (curbuf->b_op_end.col > 0)
+ --curbuf->b_op_end.col;
+}
+
+/*
+ * Shift the current line one shiftwidth left (if left != 0) or right
+ * leaves cursor on first blank in the line.
+ */
+ void
+shift_line(
+ int left,
+ int round,
+ int amount,
+ int call_changed_bytes) /* call changed_bytes() */
+{
+ int count;
+ int i, j;
+ int p_sw = (int)get_sw_value_indent(curbuf);
+
+ count = get_indent(); /* get current indent */
+
+ if (round) /* round off indent */
+ {
+ i = count / p_sw; /* number of p_sw rounded down */
+ j = count % p_sw; /* extra spaces */
+ if (j && left) /* first remove extra spaces */
+ --amount;
+ if (left)
+ {
+ i -= amount;
+ if (i < 0)
+ i = 0;
+ }
+ else
+ i += amount;
+ count = i * p_sw;
+ }
+ else /* original vi indent */
+ {
+ if (left)
+ {
+ count -= p_sw * amount;
+ if (count < 0)
+ count = 0;
+ }
+ else
+ count += p_sw * amount;
+ }
+
+ /* Set new indent */
+ if (State & VREPLACE_FLAG)
+ change_indent(INDENT_SET, count, FALSE, NUL, call_changed_bytes);
+ else
+ (void)set_indent(count, call_changed_bytes ? SIN_CHANGED : 0);
+}
+
+/*
+ * Shift one line of the current block one shiftwidth right or left.
+ * Leaves cursor on first character in block.
+ */
+ static void
+shift_block(oparg_T *oap, int amount)
+{
+ int left = (oap->op_type == OP_LSHIFT);
+ int oldstate = State;
+ int total;
+ char_u *newp, *oldp;
+ int oldcol = curwin->w_cursor.col;
+ int p_sw = (int)get_sw_value_indent(curbuf);
+#ifdef FEAT_VARTABS
+ int *p_vts = curbuf->b_p_vts_array;
+#endif
+ int p_ts = (int)curbuf->b_p_ts;
+ struct block_def bd;
+ int incr;
+ colnr_T ws_vcol;
+ int i = 0, j = 0;
+ int len;
+#ifdef FEAT_RIGHTLEFT
+ int old_p_ri = p_ri;
+
+ p_ri = 0; /* don't want revins in indent */
+#endif
+
+ State = INSERT; /* don't want REPLACE for State */
+ block_prep(oap, &bd, curwin->w_cursor.lnum, TRUE);
+ if (bd.is_short)
+ return;
+
+ /* total is number of screen columns to be inserted/removed */
+ total = (int)((unsigned)amount * (unsigned)p_sw);
+ if ((total / p_sw) != amount)
+ return; /* multiplication overflow */
+
+ oldp = ml_get_curline();
+
+ if (!left)
+ {
+ /*
+ * 1. Get start vcol
+ * 2. Total ws vcols
+ * 3. Divvy into TABs & spp
+ * 4. Construct new string
+ */
+ total += bd.pre_whitesp; /* all virtual WS upto & incl a split TAB */
+ ws_vcol = bd.start_vcol - bd.pre_whitesp;
+ if (bd.startspaces)
+ {
+ if (has_mbyte)
+ {
+ if ((*mb_ptr2len)(bd.textstart) == 1)
+ ++bd.textstart;
+ else
+ {
+ ws_vcol = 0;
+ bd.startspaces = 0;
+ }
+ }
+ else
+ ++bd.textstart;
+ }
+ for ( ; VIM_ISWHITE(*bd.textstart); )
+ {
+ /* TODO: is passing bd.textstart for start of the line OK? */
+ incr = lbr_chartabsize_adv(bd.textstart, &bd.textstart,
+ (colnr_T)(bd.start_vcol));
+ total += incr;
+ bd.start_vcol += incr;
+ }
+ /* OK, now total=all the VWS reqd, and textstart points at the 1st
+ * non-ws char in the block. */
+#ifdef FEAT_VARTABS
+ if (!curbuf->b_p_et)
+ tabstop_fromto(ws_vcol, ws_vcol + total, p_ts, p_vts, &i, &j);
+ else
+ j = total;
+#else
+ if (!curbuf->b_p_et)
+ i = ((ws_vcol % p_ts) + total) / p_ts; /* number of tabs */
+ if (i)
+ j = ((ws_vcol % p_ts) + total) % p_ts; /* number of spp */
+ else
+ j = total;
+#endif
+ /* if we're splitting a TAB, allow for it */
+ bd.textcol -= bd.pre_whitesp_c - (bd.startspaces != 0);
+ len = (int)STRLEN(bd.textstart) + 1;
+ newp = alloc_check((unsigned)(bd.textcol + i + j + len));
+ if (newp == NULL)
+ return;
+ vim_memset(newp, NUL, (size_t)(bd.textcol + i + j + len));
+ mch_memmove(newp, oldp, (size_t)bd.textcol);
+ vim_memset(newp + bd.textcol, TAB, (size_t)i);
+ vim_memset(newp + bd.textcol + i, ' ', (size_t)j);
+ /* the end */
+ mch_memmove(newp + bd.textcol + i + j, bd.textstart, (size_t)len);
+ }
+ else /* left */
+ {
+ colnr_T destination_col; /* column to which text in block will
+ be shifted */
+ char_u *verbatim_copy_end; /* end of the part of the line which is
+ copied verbatim */
+ colnr_T verbatim_copy_width;/* the (displayed) width of this part
+ of line */
+ unsigned fill; /* nr of spaces that replace a TAB */
+ unsigned new_line_len; /* the length of the line after the
+ block shift */
+ size_t block_space_width;
+ size_t shift_amount;
+ char_u *non_white = bd.textstart;
+ colnr_T non_white_col;
+
+ /*
+ * Firstly, let's find the first non-whitespace character that is
+ * displayed after the block's start column and the character's column
+ * number. Also, let's calculate the width of all the whitespace
+ * characters that are displayed in the block and precede the searched
+ * non-whitespace character.
+ */
+
+ /* If "bd.startspaces" is set, "bd.textstart" points to the character,
+ * the part of which is displayed at the block's beginning. Let's start
+ * searching from the next character. */
+ if (bd.startspaces)
+ MB_PTR_ADV(non_white);
+
+ /* The character's column is in "bd.start_vcol". */
+ non_white_col = bd.start_vcol;
+
+ while (VIM_ISWHITE(*non_white))
+ {
+ incr = lbr_chartabsize_adv(bd.textstart, &non_white, non_white_col);
+ non_white_col += incr;
+ }
+
+ block_space_width = non_white_col - oap->start_vcol;
+ /* We will shift by "total" or "block_space_width", whichever is less.
+ */
+ shift_amount = (block_space_width < (size_t)total
+ ? block_space_width : (size_t)total);
+
+ /* The column to which we will shift the text. */
+ destination_col = (colnr_T)(non_white_col - shift_amount);
+
+ /* Now let's find out how much of the beginning of the line we can
+ * reuse without modification. */
+ verbatim_copy_end = bd.textstart;
+ verbatim_copy_width = bd.start_vcol;
+
+ /* If "bd.startspaces" is set, "bd.textstart" points to the character
+ * preceding the block. We have to subtract its width to obtain its
+ * column number. */
+ if (bd.startspaces)
+ verbatim_copy_width -= bd.start_char_vcols;
+ while (verbatim_copy_width < destination_col)
+ {
+ char_u *line = verbatim_copy_end;
+
+ /* TODO: is passing verbatim_copy_end for start of the line OK? */
+ incr = lbr_chartabsize(line, verbatim_copy_end,
+ verbatim_copy_width);
+ if (verbatim_copy_width + incr > destination_col)
+ break;
+ verbatim_copy_width += incr;
+ MB_PTR_ADV(verbatim_copy_end);
+ }
+
+ /* If "destination_col" is different from the width of the initial
+ * part of the line that will be copied, it means we encountered a tab
+ * character, which we will have to partly replace with spaces. */
+ fill = destination_col - verbatim_copy_width;
+
+ /* The replacement line will consist of:
+ * - the beginning of the original line up to "verbatim_copy_end",
+ * - "fill" number of spaces,
+ * - the rest of the line, pointed to by non_white. */
+ new_line_len = (unsigned)(verbatim_copy_end - oldp)
+ + fill
+ + (unsigned)STRLEN(non_white) + 1;
+
+ newp = alloc_check(new_line_len);
+ if (newp == NULL)
+ return;
+ mch_memmove(newp, oldp, (size_t)(verbatim_copy_end - oldp));
+ vim_memset(newp + (verbatim_copy_end - oldp), ' ', (size_t)fill);
+ STRMOVE(newp + (verbatim_copy_end - oldp) + fill, non_white);
+ }
+ /* replace the line */
+ ml_replace(curwin->w_cursor.lnum, newp, FALSE);
+ changed_bytes(curwin->w_cursor.lnum, (colnr_T)bd.textcol);
+ State = oldstate;
+ curwin->w_cursor.col = oldcol;
+#ifdef FEAT_RIGHTLEFT
+ p_ri = old_p_ri;
+#endif
+}
+
+/*
+ * Insert string "s" (b_insert ? before : after) block :AKelly
+ * Caller must prepare for undo.
+ */
+ static void
+block_insert(
+ oparg_T *oap,
+ char_u *s,
+ int b_insert,
+ struct block_def *bdp)
+{
+ int p_ts;
+ int count = 0; /* extra spaces to replace a cut TAB */
+ int spaces = 0; /* non-zero if cutting a TAB */
+ colnr_T offset; /* pointer along new line */
+ unsigned s_len; /* STRLEN(s) */
+ char_u *newp, *oldp; /* new, old lines */
+ linenr_T lnum; /* loop var */
+ int oldstate = State;
+
+ State = INSERT; /* don't want REPLACE for State */
+ s_len = (unsigned)STRLEN(s);
+
+ for (lnum = oap->start.lnum + 1; lnum <= oap->end.lnum; lnum++)
+ {
+ block_prep(oap, bdp, lnum, TRUE);
+ if (bdp->is_short && b_insert)
+ continue; /* OP_INSERT, line ends before block start */
+
+ oldp = ml_get(lnum);
+
+ if (b_insert)
+ {
+ p_ts = bdp->start_char_vcols;
+ spaces = bdp->startspaces;
+ if (spaces != 0)
+ count = p_ts - 1; /* we're cutting a TAB */
+ offset = bdp->textcol;
+ }
+ else /* append */
+ {
+ p_ts = bdp->end_char_vcols;
+ if (!bdp->is_short) /* spaces = padding after block */
+ {
+ spaces = (bdp->endspaces ? p_ts - bdp->endspaces : 0);
+ if (spaces != 0)
+ count = p_ts - 1; /* we're cutting a TAB */
+ offset = bdp->textcol + bdp->textlen - (spaces != 0);
+ }
+ else /* spaces = padding to block edge */
+ {
+ /* if $ used, just append to EOL (ie spaces==0) */
+ if (!bdp->is_MAX)
+ spaces = (oap->end_vcol - bdp->end_vcol) + 1;
+ count = spaces;
+ offset = bdp->textcol + bdp->textlen;
+ }
+ }
+
+ if (has_mbyte && spaces > 0)
+ {
+ int off;
+
+ /* Avoid starting halfway a multi-byte character. */
+ if (b_insert)
+ {
+ off = (*mb_head_off)(oldp, oldp + offset + spaces);
+ }
+ else
+ {
+ off = (*mb_off_next)(oldp, oldp + offset);
+ offset += off;
+ }
+ spaces -= off;
+ count -= off;
+ }
+
+ newp = alloc_check((unsigned)(STRLEN(oldp)) + s_len + count + 1);
+ if (newp == NULL)
+ continue;
+
+ /* copy up to shifted part */
+ mch_memmove(newp, oldp, (size_t)(offset));
+ oldp += offset;
+
+ /* insert pre-padding */
+ vim_memset(newp + offset, ' ', (size_t)spaces);
+
+ /* copy the new text */
+ mch_memmove(newp + offset + spaces, s, (size_t)s_len);
+ offset += s_len;
+
+ if (spaces && !bdp->is_short)
+ {
+ /* insert post-padding */
+ vim_memset(newp + offset + spaces, ' ', (size_t)(p_ts - spaces));
+ /* We're splitting a TAB, don't copy it. */
+ oldp++;
+ /* We allowed for that TAB, remember this now */
+ count++;
+ }
+
+ if (spaces > 0)
+ offset += count;
+ STRMOVE(newp + offset, oldp);
+
+ ml_replace(lnum, newp, FALSE);
+
+ if (lnum == oap->end.lnum)
+ {
+ /* Set "']" mark to the end of the block instead of the end of
+ * the insert in the first line. */
+ curbuf->b_op_end.lnum = oap->end.lnum;
+ curbuf->b_op_end.col = offset;
+ }
+ } /* for all lnum */
+
+ changed_lines(oap->start.lnum + 1, 0, oap->end.lnum + 1, 0L);
+
+ State = oldstate;
+}
+
+#if defined(FEAT_LISP) || defined(FEAT_CINDENT) || defined(PROTO)
+/*
+ * op_reindent - handle reindenting a block of lines.
+ */
+ void
+op_reindent(oparg_T *oap, int (*how)(void))
+{
+ long i;
+ char_u *l;
+ int amount;
+ linenr_T first_changed = 0;
+ linenr_T last_changed = 0;
+ linenr_T start_lnum = curwin->w_cursor.lnum;
+
+ /* Don't even try when 'modifiable' is off. */
+ if (!curbuf->b_p_ma)
+ {
+ emsg(_(e_modifiable));
+ return;
+ }
+
+ for (i = oap->line_count; --i >= 0 && !got_int; )
+ {
+ /* it's a slow thing to do, so give feedback so there's no worry that
+ * the computer's just hung. */
+
+ if (i > 1
+ && (i % 50 == 0 || i == oap->line_count - 1)
+ && oap->line_count > p_report)
+ smsg(_("%ld lines to indent... "), i);
+
+ /*
+ * Be vi-compatible: For lisp indenting the first line is not
+ * indented, unless there is only one line.
+ */
+#ifdef FEAT_LISP
+ if (i != oap->line_count - 1 || oap->line_count == 1
+ || how != get_lisp_indent)
+#endif
+ {
+ l = skipwhite(ml_get_curline());
+ if (*l == NUL) /* empty or blank line */
+ amount = 0;
+ else
+ amount = how(); /* get the indent for this line */
+
+ if (amount >= 0 && set_indent(amount, SIN_UNDO))
+ {
+ /* did change the indent, call changed_lines() later */
+ if (first_changed == 0)
+ first_changed = curwin->w_cursor.lnum;
+ last_changed = curwin->w_cursor.lnum;
+ }
+ }
+ ++curwin->w_cursor.lnum;
+ curwin->w_cursor.col = 0; /* make sure it's valid */
+ }
+
+ /* put cursor on first non-blank of indented line */
+ curwin->w_cursor.lnum = start_lnum;
+ beginline(BL_SOL | BL_FIX);
+
+ /* Mark changed lines so that they will be redrawn. When Visual
+ * highlighting was present, need to continue until the last line. When
+ * there is no change still need to remove the Visual highlighting. */
+ if (last_changed != 0)
+ changed_lines(first_changed, 0,
+ oap->is_VIsual ? start_lnum + oap->line_count :
+ last_changed + 1, 0L);
+ else if (oap->is_VIsual)
+ redraw_curbuf_later(INVERTED);
+
+ if (oap->line_count > p_report)
+ {
+ i = oap->line_count - (i + 1);
+ smsg(NGETTEXT("%ld line indented ",
+ "%ld lines indented ", i), i);
+ }
+ /* set '[ and '] marks */
+ curbuf->b_op_start = oap->start;
+ curbuf->b_op_end = oap->end;
+}
+#endif /* defined(FEAT_LISP) || defined(FEAT_CINDENT) */
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * Keep the last expression line here, for repeating.
+ */
+static char_u *expr_line = NULL;
+
+/*
+ * Get an expression for the "\"=expr1" or "CTRL-R =expr1"
+ * Returns '=' when OK, NUL otherwise.
+ */
+ int
+get_expr_register(void)
+{
+ char_u *new_line;
+
+ new_line = getcmdline('=', 0L, 0);
+ if (new_line == NULL)
+ return NUL;
+ if (*new_line == NUL) /* use previous line */
+ vim_free(new_line);
+ else
+ set_expr_line(new_line);
+ return '=';
+}
+
+/*
+ * Set the expression for the '=' register.
+ * Argument must be an allocated string.
+ */
+ void
+set_expr_line(char_u *new_line)
+{
+ vim_free(expr_line);
+ expr_line = new_line;
+}
+
+/*
+ * Get the result of the '=' register expression.
+ * Returns a pointer to allocated memory, or NULL for failure.
+ */
+ char_u *
+get_expr_line(void)
+{
+ char_u *expr_copy;
+ char_u *rv;
+ static int nested = 0;
+
+ if (expr_line == NULL)
+ return NULL;
+
+ /* Make a copy of the expression, because evaluating it may cause it to be
+ * changed. */
+ expr_copy = vim_strsave(expr_line);
+ if (expr_copy == NULL)
+ return NULL;
+
+ /* When we are invoked recursively limit the evaluation to 10 levels.
+ * Then return the string as-is. */
+ if (nested >= 10)
+ return expr_copy;
+
+ ++nested;
+ rv = eval_to_string(expr_copy, NULL, TRUE);
+ --nested;
+ vim_free(expr_copy);
+ return rv;
+}
+
+/*
+ * Get the '=' register expression itself, without evaluating it.
+ */
+ char_u *
+get_expr_line_src(void)
+{
+ if (expr_line == NULL)
+ return NULL;
+ return vim_strsave(expr_line);
+}
+#endif /* FEAT_EVAL */
+
+/*
+ * Check if 'regname' is a valid name of a yank register.
+ * Note: There is no check for 0 (default register), caller should do this
+ */
+ int
+valid_yank_reg(
+ int regname,
+ int writing) /* if TRUE check for writable registers */
+{
+ if ( (regname > 0 && ASCII_ISALNUM(regname))
+ || (!writing && vim_strchr((char_u *)
+#ifdef FEAT_EVAL
+ "/.%:="
+#else
+ "/.%:"
+#endif
+ , regname) != NULL)
+ || regname == '#'
+ || regname == '"'
+ || regname == '-'
+ || regname == '_'
+#ifdef FEAT_CLIPBOARD
+ || regname == '*'
+ || regname == '+'
+#endif
+#ifdef FEAT_DND
+ || (!writing && regname == '~')
+#endif
+ )
+ return TRUE;
+ return FALSE;
+}
+
+/*
+ * Set y_current and y_append, according to the value of "regname".
+ * Cannot handle the '_' register.
+ * Must only be called with a valid register name!
+ *
+ * If regname is 0 and writing, use register 0
+ * If regname is 0 and reading, use previous register
+ *
+ * Return TRUE when the register should be inserted literally (selection or
+ * clipboard).
+ */
+ int
+get_yank_register(int regname, int writing)
+{
+ int i;
+ int ret = FALSE;
+
+ y_append = FALSE;
+ if ((regname == 0 || regname == '"') && !writing && y_previous != NULL)
+ {
+ y_current = y_previous;
+ return ret;
+ }
+ i = regname;
+ if (VIM_ISDIGIT(i))
+ i -= '0';
+ else if (ASCII_ISLOWER(i))
+ i = CharOrdLow(i) + 10;
+ else if (ASCII_ISUPPER(i))
+ {
+ i = CharOrdUp(i) + 10;
+ y_append = TRUE;
+ }
+ else if (regname == '-')
+ i = DELETION_REGISTER;
+#ifdef FEAT_CLIPBOARD
+ /* When selection is not available, use register 0 instead of '*' */
+ else if (clip_star.available && regname == '*')
+ {
+ i = STAR_REGISTER;
+ ret = TRUE;
+ }
+ /* When clipboard is not available, use register 0 instead of '+' */
+ else if (clip_plus.available && regname == '+')
+ {
+ i = PLUS_REGISTER;
+ ret = TRUE;
+ }
+#endif
+#ifdef FEAT_DND
+ else if (!writing && regname == '~')
+ i = TILDE_REGISTER;
+#endif
+ else /* not 0-9, a-z, A-Z or '-': use register 0 */
+ i = 0;
+ y_current = &(y_regs[i]);
+ if (writing) /* remember the register we write into for do_put() */
+ y_previous = y_current;
+ return ret;
+}
+
+#if defined(FEAT_CLIPBOARD) || defined(PROTO)
+/*
+ * When "regname" is a clipboard register, obtain the selection. If it's not
+ * available return zero, otherwise return "regname".
+ */
+ int
+may_get_selection(int regname)
+{
+ if (regname == '*')
+ {
+ if (!clip_star.available)
+ regname = 0;
+ else
+ clip_get_selection(&clip_star);
+ }
+ else if (regname == '+')
+ {
+ if (!clip_plus.available)
+ regname = 0;
+ else
+ clip_get_selection(&clip_plus);
+ }
+ return regname;
+}
+#endif
+
+/*
+ * Obtain the contents of a "normal" register. The register is made empty.
+ * The returned pointer has allocated memory, use put_register() later.
+ */
+ void *
+get_register(
+ int name,
+ int copy) /* make a copy, if FALSE make register empty. */
+{
+ yankreg_T *reg;
+ int i;
+
+#ifdef FEAT_CLIPBOARD
+ /* When Visual area changed, may have to update selection. Obtain the
+ * selection too. */
+ if (name == '*' && clip_star.available)
+ {
+ if (clip_isautosel_star())
+ clip_update_selection(&clip_star);
+ may_get_selection(name);
+ }
+ if (name == '+' && clip_plus.available)
+ {
+ if (clip_isautosel_plus())
+ clip_update_selection(&clip_plus);
+ may_get_selection(name);
+ }
+#endif
+
+ get_yank_register(name, 0);
+ reg = (yankreg_T *)alloc((unsigned)sizeof(yankreg_T));
+ if (reg != NULL)
+ {
+ *reg = *y_current;
+ if (copy)
+ {
+ /* If we run out of memory some or all of the lines are empty. */
+ if (reg->y_size == 0)
+ reg->y_array = NULL;
+ else
+ reg->y_array = (char_u **)alloc((unsigned)(sizeof(char_u *)
+ * reg->y_size));
+ if (reg->y_array != NULL)
+ {
+ for (i = 0; i < reg->y_size; ++i)
+ reg->y_array[i] = vim_strsave(y_current->y_array[i]);
+ }
+ }
+ else
+ y_current->y_array = NULL;
+ }
+ return (void *)reg;
+}
+
+/*
+ * Put "reg" into register "name". Free any previous contents and "reg".
+ */
+ void
+put_register(int name, void *reg)
+{
+ get_yank_register(name, 0);
+ free_yank_all();
+ *y_current = *(yankreg_T *)reg;
+ vim_free(reg);
+
+#ifdef FEAT_CLIPBOARD
+ /* Send text written to clipboard register to the clipboard. */
+ may_set_selection();
+#endif
+}
+
+#if (defined(FEAT_CLIPBOARD) && defined(FEAT_X11) && defined(USE_SYSTEM)) \
+ || defined(PROTO)
+ void
+free_register(void *reg)
+{
+ yankreg_T tmp;
+
+ tmp = *y_current;
+ *y_current = *(yankreg_T *)reg;
+ free_yank_all();
+ vim_free(reg);
+ *y_current = tmp;
+}
+#endif
+
+#if defined(FEAT_MOUSE) || defined(PROTO)
+/*
+ * return TRUE if the current yank register has type MLINE
+ */
+ int
+yank_register_mline(int regname)
+{
+ if (regname != 0 && !valid_yank_reg(regname, FALSE))
+ return FALSE;
+ if (regname == '_') /* black hole is always empty */
+ return FALSE;
+ get_yank_register(regname, FALSE);
+ return (y_current->y_type == MLINE);
+}
+#endif
+
+/*
+ * Start or stop recording into a yank register.
+ *
+ * Return FAIL for failure, OK otherwise.
+ */
+ int
+do_record(int c)
+{
+ char_u *p;
+ static int regname;
+ yankreg_T *old_y_previous, *old_y_current;
+ int retval;
+
+ if (reg_recording == 0) /* start recording */
+ {
+ /* registers 0-9, a-z and " are allowed */
+ if (c < 0 || (!ASCII_ISALNUM(c) && c != '"'))
+ retval = FAIL;
+ else
+ {
+ reg_recording = c;
+ showmode();
+ regname = c;
+ retval = OK;
+ }
+ }
+ else /* stop recording */
+ {
+ /*
+ * Get the recorded key hits. K_SPECIAL and CSI will be escaped, this
+ * needs to be removed again to put it in a register. exec_reg then
+ * adds the escaping back later.
+ */
+ reg_recording = 0;
+ msg("");
+ p = get_recorded();
+ if (p == NULL)
+ retval = FAIL;
+ else
+ {
+ /* Remove escaping for CSI and K_SPECIAL in multi-byte chars. */
+ vim_unescape_csi(p);
+
+ /*
+ * We don't want to change the default register here, so save and
+ * restore the current register name.
+ */
+ old_y_previous = y_previous;
+ old_y_current = y_current;
+
+ retval = stuff_yank(regname, p);
+
+ y_previous = old_y_previous;
+ y_current = old_y_current;
+ }
+ }
+ return retval;
+}
+
+/*
+ * Stuff string "p" into yank register "regname" as a single line (append if
+ * uppercase). "p" must have been alloced.
+ *
+ * return FAIL for failure, OK otherwise
+ */
+ static int
+stuff_yank(int regname, char_u *p)
+{
+ char_u *lp;
+ char_u **pp;
+
+ /* check for read-only register */
+ if (regname != 0 && !valid_yank_reg(regname, TRUE))
+ {
+ vim_free(p);
+ return FAIL;
+ }
+ if (regname == '_') /* black hole: don't do anything */
+ {
+ vim_free(p);
+ return OK;
+ }
+ get_yank_register(regname, TRUE);
+ if (y_append && y_current->y_array != NULL)
+ {
+ pp = &(y_current->y_array[y_current->y_size - 1]);
+ lp = lalloc((long_u)(STRLEN(*pp) + STRLEN(p) + 1), TRUE);
+ if (lp == NULL)
+ {
+ vim_free(p);
+ return FAIL;
+ }
+ STRCPY(lp, *pp);
+ STRCAT(lp, p);
+ vim_free(p);
+ vim_free(*pp);
+ *pp = lp;
+ }
+ else
+ {
+ free_yank_all();
+ if ((y_current->y_array =
+ (char_u **)alloc((unsigned)sizeof(char_u *))) == NULL)
+ {
+ vim_free(p);
+ return FAIL;
+ }
+ y_current->y_array[0] = p;
+ y_current->y_size = 1;
+ y_current->y_type = MCHAR; /* used to be MLINE, why? */
+#ifdef FEAT_VIMINFO
+ y_current->y_time_set = vim_time();
+#endif
+ }
+ return OK;
+}
+
+static int execreg_lastc = NUL;
+
+/*
+ * Execute a yank register: copy it into the stuff buffer.
+ *
+ * Return FAIL for failure, OK otherwise.
+ */
+ int
+do_execreg(
+ int regname,
+ int colon, /* insert ':' before each line */
+ int addcr, /* always add '\n' to end of line */
+ int silent) /* set "silent" flag in typeahead buffer */
+{
+ long i;
+ char_u *p;
+ int retval = OK;
+ int remap;
+
+ if (regname == '@') /* repeat previous one */
+ {
+ if (execreg_lastc == NUL)
+ {
+ emsg(_("E748: No previously used register"));
+ return FAIL;
+ }
+ regname = execreg_lastc;
+ }
+ /* check for valid regname */
+ if (regname == '%' || regname == '#' || !valid_yank_reg(regname, FALSE))
+ {
+ emsg_invreg(regname);
+ return FAIL;
+ }
+ execreg_lastc = regname;
+
+#ifdef FEAT_CLIPBOARD
+ regname = may_get_selection(regname);
+#endif
+
+ if (regname == '_') /* black hole: don't stuff anything */
+ return OK;
+
+#ifdef FEAT_CMDHIST
+ if (regname == ':') /* use last command line */
+ {
+ if (last_cmdline == NULL)
+ {
+ emsg(_(e_nolastcmd));
+ return FAIL;
+ }
+ VIM_CLEAR(new_last_cmdline); /* don't keep the cmdline containing @: */
+ /* Escape all control characters with a CTRL-V */
+ p = vim_strsave_escaped_ext(last_cmdline,
+ (char_u *)"\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037", Ctrl_V, FALSE);
+ if (p != NULL)
+ {
+ /* When in Visual mode "'<,'>" will be prepended to the command.
+ * Remove it when it's already there. */
+ if (VIsual_active && STRNCMP(p, "'<,'>", 5) == 0)
+ retval = put_in_typebuf(p + 5, TRUE, TRUE, silent);
+ else
+ retval = put_in_typebuf(p, TRUE, TRUE, silent);
+ }
+ vim_free(p);
+ }
+#endif
+#ifdef FEAT_EVAL
+ else if (regname == '=')
+ {
+ p = get_expr_line();
+ if (p == NULL)
+ return FAIL;
+ retval = put_in_typebuf(p, TRUE, colon, silent);
+ vim_free(p);
+ }
+#endif
+ else if (regname == '.') /* use last inserted text */
+ {
+ p = get_last_insert_save();
+ if (p == NULL)
+ {
+ emsg(_(e_noinstext));
+ return FAIL;
+ }
+ retval = put_in_typebuf(p, FALSE, colon, silent);
+ vim_free(p);
+ }
+ else
+ {
+ get_yank_register(regname, FALSE);
+ if (y_current->y_array == NULL)
+ return FAIL;
+
+ /* Disallow remaping for ":@r". */
+ remap = colon ? REMAP_NONE : REMAP_YES;
+
+ /*
+ * Insert lines into typeahead buffer, from last one to first one.
+ */
+ put_reedit_in_typebuf(silent);
+ for (i = y_current->y_size; --i >= 0; )
+ {
+ char_u *escaped;
+
+ /* insert NL between lines and after last line if type is MLINE */
+ if (y_current->y_type == MLINE || i < y_current->y_size - 1
+ || addcr)
+ {
+ if (ins_typebuf((char_u *)"\n", remap, 0, TRUE, silent) == FAIL)
+ return FAIL;
+ }
+ escaped = vim_strsave_escape_csi(y_current->y_array[i]);
+ if (escaped == NULL)
+ return FAIL;
+ retval = ins_typebuf(escaped, remap, 0, TRUE, silent);
+ vim_free(escaped);
+ if (retval == FAIL)
+ return FAIL;
+ if (colon && ins_typebuf((char_u *)":", remap, 0, TRUE, silent)
+ == FAIL)
+ return FAIL;
+ }
+ reg_executing = regname == 0 ? '"' : regname; // disable "q" command
+ }
+ return retval;
+}
+
+/*
+ * If "restart_edit" is not zero, put it in the typeahead buffer, so that it's
+ * used only after other typeahead has been processed.
+ */
+ static void
+put_reedit_in_typebuf(int silent)
+{
+ char_u buf[3];
+
+ if (restart_edit != NUL)
+ {
+ if (restart_edit == 'V')
+ {
+ buf[0] = 'g';
+ buf[1] = 'R';
+ buf[2] = NUL;
+ }
+ else
+ {
+ buf[0] = restart_edit == 'I' ? 'i' : restart_edit;
+ buf[1] = NUL;
+ }
+ if (ins_typebuf(buf, REMAP_NONE, 0, TRUE, silent) == OK)
+ restart_edit = NUL;
+ }
+}
+
+/*
+ * Insert register contents "s" into the typeahead buffer, so that it will be
+ * executed again.
+ * When "esc" is TRUE it is to be taken literally: Escape CSI characters and
+ * no remapping.
+ */
+ static int
+put_in_typebuf(
+ char_u *s,
+ int esc,
+ int colon, /* add ':' before the line */
+ int silent)
+{
+ int retval = OK;
+
+ put_reedit_in_typebuf(silent);
+ if (colon)
+ retval = ins_typebuf((char_u *)"\n", REMAP_NONE, 0, TRUE, silent);
+ if (retval == OK)
+ {
+ char_u *p;
+
+ if (esc)
+ p = vim_strsave_escape_csi(s);
+ else
+ p = s;
+ if (p == NULL)
+ retval = FAIL;
+ else
+ retval = ins_typebuf(p, esc ? REMAP_NONE : REMAP_YES,
+ 0, TRUE, silent);
+ if (esc)
+ vim_free(p);
+ }
+ if (colon && retval == OK)
+ retval = ins_typebuf((char_u *)":", REMAP_NONE, 0, TRUE, silent);
+ return retval;
+}
+
+/*
+ * Insert a yank register: copy it into the Read buffer.
+ * Used by CTRL-R command and middle mouse button in insert mode.
+ *
+ * return FAIL for failure, OK otherwise
+ */
+ int
+insert_reg(
+ int regname,
+ int literally_arg) /* insert literally, not as if typed */
+{
+ long i;
+ int retval = OK;
+ char_u *arg;
+ int allocated;
+ int literally = literally_arg;
+
+ /*
+ * It is possible to get into an endless loop by having CTRL-R a in
+ * register a and then, in insert mode, doing CTRL-R a.
+ * If you hit CTRL-C, the loop will be broken here.
+ */
+ ui_breakcheck();
+ if (got_int)
+ return FAIL;
+
+ /* check for valid regname */
+ if (regname != NUL && !valid_yank_reg(regname, FALSE))
+ return FAIL;
+
+#ifdef FEAT_CLIPBOARD
+ regname = may_get_selection(regname);
+#endif
+
+ if (regname == '.') /* insert last inserted text */
+ retval = stuff_inserted(NUL, 1L, TRUE);
+ else if (get_spec_reg(regname, &arg, &allocated, TRUE))
+ {
+ if (arg == NULL)
+ return FAIL;
+ stuffescaped(arg, literally);
+ if (allocated)
+ vim_free(arg);
+ }
+ else /* name or number register */
+ {
+ if (get_yank_register(regname, FALSE))
+ literally = TRUE;
+ if (y_current->y_array == NULL)
+ retval = FAIL;
+ else
+ {
+ for (i = 0; i < y_current->y_size; ++i)
+ {
+ stuffescaped(y_current->y_array[i], literally);
+ /*
+ * Insert a newline between lines and after last line if
+ * y_type is MLINE.
+ */
+ if (y_current->y_type == MLINE || i < y_current->y_size - 1)
+ stuffcharReadbuff('\n');
+ }
+ }
+ }
+
+ return retval;
+}
+
+/*
+ * Stuff a string into the typeahead buffer, such that edit() will insert it
+ * literally ("literally" TRUE) or interpret is as typed characters.
+ */
+ static void
+stuffescaped(char_u *arg, int literally)
+{
+ int c;
+ char_u *start;
+
+ while (*arg != NUL)
+ {
+ /* Stuff a sequence of normal ASCII characters, that's fast. Also
+ * stuff K_SPECIAL to get the effect of a special key when "literally"
+ * is TRUE. */
+ start = arg;
+ while ((*arg >= ' '
+#ifndef EBCDIC
+ && *arg < DEL /* EBCDIC: chars above space are normal */
+#endif
+ )
+ || (*arg == K_SPECIAL && !literally))
+ ++arg;
+ if (arg > start)
+ stuffReadbuffLen(start, (long)(arg - start));
+
+ /* stuff a single special character */
+ if (*arg != NUL)
+ {
+ if (has_mbyte)
+ c = mb_cptr2char_adv(&arg);
+ else
+ c = *arg++;
+ if (literally && ((c < ' ' && c != TAB) || c == DEL))
+ stuffcharReadbuff(Ctrl_V);
+ stuffcharReadbuff(c);
+ }
+ }
+}
+
+/*
+ * If "regname" is a special register, return TRUE and store a pointer to its
+ * value in "argp".
+ */
+ int
+get_spec_reg(
+ int regname,
+ char_u **argp,
+ int *allocated, /* return: TRUE when value was allocated */
+ int errmsg) /* give error message when failing */
+{
+ int cnt;
+
+ *argp = NULL;
+ *allocated = FALSE;
+ switch (regname)
+ {
+ case '%': /* file name */
+ if (errmsg)
+ check_fname(); /* will give emsg if not set */
+ *argp = curbuf->b_fname;
+ return TRUE;
+
+ case '#': /* alternate file name */
+ *argp = getaltfname(errmsg); /* may give emsg if not set */
+ return TRUE;
+
+#ifdef FEAT_EVAL
+ case '=': /* result of expression */
+ *argp = get_expr_line();
+ *allocated = TRUE;
+ return TRUE;
+#endif
+
+ case ':': /* last command line */
+ if (last_cmdline == NULL && errmsg)
+ emsg(_(e_nolastcmd));
+ *argp = last_cmdline;
+ return TRUE;
+
+ case '/': /* last search-pattern */
+ if (last_search_pat() == NULL && errmsg)
+ emsg(_(e_noprevre));
+ *argp = last_search_pat();
+ return TRUE;
+
+ case '.': /* last inserted text */
+ *argp = get_last_insert_save();
+ *allocated = TRUE;
+ if (*argp == NULL && errmsg)
+ emsg(_(e_noinstext));
+ return TRUE;
+
+#ifdef FEAT_SEARCHPATH
+ case Ctrl_F: /* Filename under cursor */
+ case Ctrl_P: /* Path under cursor, expand via "path" */
+ if (!errmsg)
+ return FALSE;
+ *argp = file_name_at_cursor(FNAME_MESS | FNAME_HYP
+ | (regname == Ctrl_P ? FNAME_EXP : 0), 1L, NULL);
+ *allocated = TRUE;
+ return TRUE;
+#endif
+
+ case Ctrl_W: /* word under cursor */
+ case Ctrl_A: /* WORD (mnemonic All) under cursor */
+ if (!errmsg)
+ return FALSE;
+ cnt = find_ident_under_cursor(argp, regname == Ctrl_W
+ ? (FIND_IDENT|FIND_STRING) : FIND_STRING);
+ *argp = cnt ? vim_strnsave(*argp, cnt) : NULL;
+ *allocated = TRUE;
+ return TRUE;
+
+ case Ctrl_L: /* Line under cursor */
+ if (!errmsg)
+ return FALSE;
+
+ *argp = ml_get_buf(curwin->w_buffer,
+ curwin->w_cursor.lnum, FALSE);
+ return TRUE;
+
+ case '_': /* black hole: always empty */
+ *argp = (char_u *)"";
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/*
+ * Paste a yank register into the command line.
+ * Only for non-special registers.
+ * Used by CTRL-R command in command-line mode
+ * insert_reg() can't be used here, because special characters from the
+ * register contents will be interpreted as commands.
+ *
+ * return FAIL for failure, OK otherwise
+ */
+ int
+cmdline_paste_reg(
+ int regname,
+ int literally_arg, /* Insert text literally instead of "as typed" */
+ int remcr) /* don't add CR characters */
+{
+ long i;
+ int literally = literally_arg;
+
+ if (get_yank_register(regname, FALSE))
+ literally = TRUE;
+ if (y_current->y_array == NULL)
+ return FAIL;
+
+ for (i = 0; i < y_current->y_size; ++i)
+ {
+ cmdline_paste_str(y_current->y_array[i], literally);
+
+ /* Insert ^M between lines and after last line if type is MLINE.
+ * Don't do this when "remcr" is TRUE. */
+ if ((y_current->y_type == MLINE || i < y_current->y_size - 1) && !remcr)
+ cmdline_paste_str((char_u *)"\r", literally);
+
+ /* Check for CTRL-C, in case someone tries to paste a few thousand
+ * lines and gets bored. */
+ ui_breakcheck();
+ if (got_int)
+ return FAIL;
+ }
+ return OK;
+}
+
+#if defined(FEAT_CLIPBOARD) || defined(PROTO)
+/*
+ * Adjust the register name pointed to with "rp" for the clipboard being
+ * used always and the clipboard being available.
+ */
+ void
+adjust_clip_reg(int *rp)
+{
+ /* If no reg. specified, and "unnamed" or "unnamedplus" is in 'clipboard',
+ * use '*' or '+' reg, respectively. "unnamedplus" prevails. */
+ if (*rp == 0 && (clip_unnamed != 0 || clip_unnamed_saved != 0))
+ {
+ if (clip_unnamed != 0)
+ *rp = ((clip_unnamed & CLIP_UNNAMED_PLUS) && clip_plus.available)
+ ? '+' : '*';
+ else
+ *rp = ((clip_unnamed_saved & CLIP_UNNAMED_PLUS) && clip_plus.available)
+ ? '+' : '*';
+ }
+ if (!clip_star.available && *rp == '*')
+ *rp = 0;
+ if (!clip_plus.available && *rp == '+')
+ *rp = 0;
+}
+#endif
+
+/*
+ * Shift the delete registers: "9 is cleared, "8 becomes "9, etc.
+ */
+ void
+shift_delete_registers()
+{
+ int n;
+
+ y_current = &y_regs[9];
+ free_yank_all(); /* free register nine */
+ for (n = 9; n > 1; --n)
+ y_regs[n] = y_regs[n - 1];
+ y_current = &y_regs[1];
+ if (!y_append)
+ y_previous = y_current;
+ y_regs[1].y_array = NULL; /* set register one to empty */
+}
+
+#if defined(FEAT_EVAL)
+ static void
+yank_do_autocmd(oparg_T *oap, yankreg_T *reg)
+{
+ static int recursive = FALSE;
+ dict_T *v_event;
+ list_T *list;
+ int n;
+ char_u buf[NUMBUFLEN + 2];
+ long reglen = 0;
+
+ if (recursive)
+ return;
+
+ v_event = get_vim_var_dict(VV_EVENT);
+
+ list = list_alloc();
+ if (list == NULL)
+ return;
+ for (n = 0; n < reg->y_size; n++)
+ list_append_string(list, reg->y_array[n], -1);
+ list->lv_lock = VAR_FIXED;
+ dict_add_list(v_event, "regcontents", list);
+
+ buf[0] = (char_u)oap->regname;
+ buf[1] = NUL;
+ dict_add_string(v_event, "regname", buf);
+
+ buf[0] = get_op_char(oap->op_type);
+ buf[1] = get_extra_op_char(oap->op_type);
+ buf[2] = NUL;
+ dict_add_string(v_event, "operator", buf);
+
+ buf[0] = NUL;
+ buf[1] = NUL;
+ switch (get_reg_type(oap->regname, &reglen))
+ {
+ case MLINE: buf[0] = 'V'; break;
+ case MCHAR: buf[0] = 'v'; break;
+ case MBLOCK:
+ vim_snprintf((char *)buf, sizeof(buf), "%c%ld", Ctrl_V,
+ reglen + 1);
+ break;
+ }
+ dict_add_string(v_event, "regtype", buf);
+
+ /* Lock the dictionary and its keys */
+ dict_set_items_ro(v_event);
+
+ recursive = TRUE;
+ textlock++;
+ apply_autocmds(EVENT_TEXTYANKPOST, NULL, NULL, FALSE, curbuf);
+ textlock--;
+ recursive = FALSE;
+
+ /* Empty the dictionary, v:event is still valid */
+ dict_free_contents(v_event);
+ hash_init(&v_event->dv_hashtab);
+}
+#endif
+
+/*
+ * Handle a delete operation.
+ *
+ * Return FAIL if undo failed, OK otherwise.
+ */
+ int
+op_delete(oparg_T *oap)
+{
+ int n;
+ linenr_T lnum;
+ char_u *ptr;
+ char_u *newp, *oldp;
+ struct block_def bd;
+ linenr_T old_lcount = curbuf->b_ml.ml_line_count;
+ int did_yank = FALSE;
+ int orig_regname = oap->regname;
+
+ if (curbuf->b_ml.ml_flags & ML_EMPTY) /* nothing to do */
+ return OK;
+
+ /* Nothing to delete, return here. Do prepare undo, for op_change(). */
+ if (oap->empty)
+ return u_save_cursor();
+
+ if (!curbuf->b_p_ma)
+ {
+ emsg(_(e_modifiable));
+ return FAIL;
+ }
+
+#ifdef FEAT_CLIPBOARD
+ adjust_clip_reg(&oap->regname);
+#endif
+
+ if (has_mbyte)
+ mb_adjust_opend(oap);
+
+ /*
+ * Imitate the strange Vi behaviour: If the delete spans more than one
+ * line and motion_type == MCHAR and the result is a blank line, make the
+ * delete linewise. Don't do this for the change command or Visual mode.
+ */
+ if ( oap->motion_type == MCHAR
+ && !oap->is_VIsual
+ && !oap->block_mode
+ && oap->line_count > 1
+ && oap->motion_force == NUL
+ && oap->op_type == OP_DELETE)
+ {
+ ptr = ml_get(oap->end.lnum) + oap->end.col;
+ if (*ptr != NUL)
+ ptr += oap->inclusive;
+ ptr = skipwhite(ptr);
+ if (*ptr == NUL && inindent(0))
+ oap->motion_type = MLINE;
+ }
+
+ /*
+ * Check for trying to delete (e.g. "D") in an empty line.
+ * Note: For the change operator it is ok.
+ */
+ if ( oap->motion_type == MCHAR
+ && oap->line_count == 1
+ && oap->op_type == OP_DELETE
+ && *ml_get(oap->start.lnum) == NUL)
+ {
+ /*
+ * It's an error to operate on an empty region, when 'E' included in
+ * 'cpoptions' (Vi compatible).
+ */
+ if (virtual_op)
+ /* Virtual editing: Nothing gets deleted, but we set the '[ and ']
+ * marks as if it happened. */
+ goto setmarks;
+ if (vim_strchr(p_cpo, CPO_EMPTYREGION) != NULL)
+ beep_flush();
+ return OK;
+ }
+
+ /*
+ * Do a yank of whatever we're about to delete.
+ * If a yank register was specified, put the deleted text into that
+ * register. For the black hole register '_' don't yank anything.
+ */
+ if (oap->regname != '_')
+ {
+ if (oap->regname != 0)
+ {
+ /* check for read-only register */
+ if (!valid_yank_reg(oap->regname, TRUE))
+ {
+ beep_flush();
+ return OK;
+ }
+ get_yank_register(oap->regname, TRUE); /* yank into specif'd reg. */
+ if (op_yank(oap, TRUE, FALSE) == OK) /* yank without message */
+ did_yank = TRUE;
+ }
+
+ /*
+ * Put deleted text into register 1 and shift number registers if the
+ * delete contains a line break, or when a regname has been specified.
+ * Use the register name from before adjust_clip_reg() may have
+ * changed it.
+ */
+ if (orig_regname != 0 || oap->motion_type == MLINE
+ || oap->line_count > 1 || oap->use_reg_one)
+ {
+ shift_delete_registers();
+ if (op_yank(oap, TRUE, FALSE) == OK)
+ did_yank = TRUE;
+ }
+
+ /* Yank into small delete register when no named register specified
+ * and the delete is within one line. */
+ if ((
+#ifdef FEAT_CLIPBOARD
+ ((clip_unnamed & CLIP_UNNAMED) && oap->regname == '*') ||
+ ((clip_unnamed & CLIP_UNNAMED_PLUS) && oap->regname == '+') ||
+#endif
+ oap->regname == 0) && oap->motion_type != MLINE
+ && oap->line_count == 1)
+ {
+ oap->regname = '-';
+ get_yank_register(oap->regname, TRUE);
+ if (op_yank(oap, TRUE, FALSE) == OK)
+ did_yank = TRUE;
+ oap->regname = 0;
+ }
+
+ /*
+ * If there's too much stuff to fit in the yank register, then get a
+ * confirmation before doing the delete. This is crude, but simple.
+ * And it avoids doing a delete of something we can't put back if we
+ * want.
+ */
+ if (!did_yank)
+ {
+ int msg_silent_save = msg_silent;
+
+ msg_silent = 0; /* must display the prompt */
+ n = ask_yesno((char_u *)_("cannot yank; delete anyway"), TRUE);
+ msg_silent = msg_silent_save;
+ if (n != 'y')
+ {
+ emsg(_(e_abort));
+ return FAIL;
+ }
+ }
+
+#if defined(FEAT_EVAL)
+ if (did_yank && has_textyankpost())
+ yank_do_autocmd(oap, y_current);
+#endif
+ }
+
+ /*
+ * block mode delete
+ */
+ if (oap->block_mode)
+ {
+ if (u_save((linenr_T)(oap->start.lnum - 1),
+ (linenr_T)(oap->end.lnum + 1)) == FAIL)
+ return FAIL;
+
+ for (lnum = curwin->w_cursor.lnum; lnum <= oap->end.lnum; ++lnum)
+ {
+ block_prep(oap, &bd, lnum, TRUE);
+ if (bd.textlen == 0) /* nothing to delete */
+ continue;
+
+ /* Adjust cursor position for tab replaced by spaces and 'lbr'. */
+ if (lnum == curwin->w_cursor.lnum)
+ {
+ curwin->w_cursor.col = bd.textcol + bd.startspaces;
+ curwin->w_cursor.coladd = 0;
+ }
+
+ /* n == number of chars deleted
+ * If we delete a TAB, it may be replaced by several characters.
+ * Thus the number of characters may increase!
+ */
+ n = bd.textlen - bd.startspaces - bd.endspaces;
+ oldp = ml_get(lnum);
+ newp = alloc_check((unsigned)STRLEN(oldp) + 1 - n);
+ if (newp == NULL)
+ continue;
+ /* copy up to deleted part */
+ mch_memmove(newp, oldp, (size_t)bd.textcol);
+ /* insert spaces */
+ vim_memset(newp + bd.textcol, ' ',
+ (size_t)(bd.startspaces + bd.endspaces));
+ /* copy the part after the deleted part */
+ oldp += bd.textcol + bd.textlen;
+ STRMOVE(newp + bd.textcol + bd.startspaces + bd.endspaces, oldp);
+ /* replace the line */
+ ml_replace(lnum, newp, FALSE);
+ }
+
+ check_cursor_col();
+ changed_lines(curwin->w_cursor.lnum, curwin->w_cursor.col,
+ oap->end.lnum + 1, 0L);
+ oap->line_count = 0; /* no lines deleted */
+ }
+ else if (oap->motion_type == MLINE)
+ {
+ if (oap->op_type == OP_CHANGE)
+ {
+ /* Delete the lines except the first one. Temporarily move the
+ * cursor to the next line. Save the current line number, if the
+ * last line is deleted it may be changed.
+ */
+ if (oap->line_count > 1)
+ {
+ lnum = curwin->w_cursor.lnum;
+ ++curwin->w_cursor.lnum;
+ del_lines((long)(oap->line_count - 1), TRUE);
+ curwin->w_cursor.lnum = lnum;
+ }
+ if (u_save_cursor() == FAIL)
+ return FAIL;
+ if (curbuf->b_p_ai) /* don't delete indent */
+ {
+ beginline(BL_WHITE); /* cursor on first non-white */
+ did_ai = TRUE; /* delete the indent when ESC hit */
+ ai_col = curwin->w_cursor.col;
+ }
+ else
+ beginline(0); /* cursor in column 0 */
+ truncate_line(FALSE); /* delete the rest of the line */
+ /* leave cursor past last char in line */
+ if (oap->line_count > 1)
+ u_clearline(); /* "U" command not possible after "2cc" */
+ }
+ else
+ {
+ del_lines(oap->line_count, TRUE);
+ beginline(BL_WHITE | BL_FIX);
+ u_clearline(); /* "U" command not possible after "dd" */
+ }
+ }
+ else
+ {
+ if (virtual_op)
+ {
+ int endcol = 0;
+
+ /* For virtualedit: break the tabs that are partly included. */
+ if (gchar_pos(&oap->start) == '\t')
+ {
+ if (u_save_cursor() == FAIL) /* save first line for undo */
+ return FAIL;
+ if (oap->line_count == 1)
+ endcol = getviscol2(oap->end.col, oap->end.coladd);
+ coladvance_force(getviscol2(oap->start.col, oap->start.coladd));
+ oap->start = curwin->w_cursor;
+ if (oap->line_count == 1)
+ {
+ coladvance(endcol);
+ oap->end.col = curwin->w_cursor.col;
+ oap->end.coladd = curwin->w_cursor.coladd;
+ curwin->w_cursor = oap->start;
+ }
+ }
+
+ /* Break a tab only when it's included in the area. */
+ if (gchar_pos(&oap->end) == '\t'
+ && (int)oap->end.coladd < oap->inclusive)
+ {
+ /* save last line for undo */
+ if (u_save((linenr_T)(oap->end.lnum - 1),
+ (linenr_T)(oap->end.lnum + 1)) == FAIL)
+ return FAIL;
+ curwin->w_cursor = oap->end;
+ coladvance_force(getviscol2(oap->end.col, oap->end.coladd));
+ oap->end = curwin->w_cursor;
+ curwin->w_cursor = oap->start;
+ }
+ }
+
+ if (oap->line_count == 1) /* delete characters within one line */
+ {
+ if (u_save_cursor() == FAIL) /* save line for undo */
+ return FAIL;
+
+ /* if 'cpoptions' contains '$', display '$' at end of change */
+ if ( vim_strchr(p_cpo, CPO_DOLLAR) != NULL
+ && oap->op_type == OP_CHANGE
+ && oap->end.lnum == curwin->w_cursor.lnum
+ && !oap->is_VIsual)
+ display_dollar(oap->end.col - !oap->inclusive);
+
+ n = oap->end.col - oap->start.col + 1 - !oap->inclusive;
+
+ if (virtual_op)
+ {
+ /* fix up things for virtualedit-delete:
+ * break the tabs which are going to get in our way
+ */
+ char_u *curline = ml_get_curline();
+ int len = (int)STRLEN(curline);
+
+ if (oap->end.coladd != 0
+ && (int)oap->end.col >= len - 1
+ && !(oap->start.coladd && (int)oap->end.col >= len - 1))
+ n++;
+ /* Delete at least one char (e.g, when on a control char). */
+ if (n == 0 && oap->start.coladd != oap->end.coladd)
+ n = 1;
+
+ /* When deleted a char in the line, reset coladd. */
+ if (gchar_cursor() != NUL)
+ curwin->w_cursor.coladd = 0;
+ }
+ (void)del_bytes((long)n, !virtual_op,
+ oap->op_type == OP_DELETE && !oap->is_VIsual);
+ }
+ else /* delete characters between lines */
+ {
+ pos_T curpos;
+
+ /* save deleted and changed lines for undo */
+ if (u_save((linenr_T)(curwin->w_cursor.lnum - 1),
+ (linenr_T)(curwin->w_cursor.lnum + oap->line_count)) == FAIL)
+ return FAIL;
+
+ truncate_line(TRUE); /* delete from cursor to end of line */
+
+ curpos = curwin->w_cursor; /* remember curwin->w_cursor */
+ ++curwin->w_cursor.lnum;
+ del_lines((long)(oap->line_count - 2), FALSE);
+
+ /* delete from start of line until op_end */
+ n = (oap->end.col + 1 - !oap->inclusive);
+ curwin->w_cursor.col = 0;
+ (void)del_bytes((long)n, !virtual_op,
+ oap->op_type == OP_DELETE && !oap->is_VIsual);
+ curwin->w_cursor = curpos; /* restore curwin->w_cursor */
+ (void)do_join(2, FALSE, FALSE, FALSE, FALSE);
+ }
+ }
+
+ msgmore(curbuf->b_ml.ml_line_count - old_lcount);
+
+setmarks:
+ if (oap->block_mode)
+ {
+ curbuf->b_op_end.lnum = oap->end.lnum;
+ curbuf->b_op_end.col = oap->start.col;
+ }
+ else
+ curbuf->b_op_end = oap->start;
+ curbuf->b_op_start = oap->start;
+
+ return OK;
+}
+
+/*
+ * Adjust end of operating area for ending on a multi-byte character.
+ * Used for deletion.
+ */
+ static void
+mb_adjust_opend(oparg_T *oap)
+{
+ char_u *p;
+
+ if (oap->inclusive)
+ {
+ p = ml_get(oap->end.lnum);
+ oap->end.col += mb_tail_off(p, p + oap->end.col);
+ }
+}
+
+/*
+ * Replace the character under the cursor with "c".
+ * This takes care of multi-byte characters.
+ */
+ static void
+replace_character(int c)
+{
+ int n = State;
+
+ State = REPLACE;
+ ins_char(c);
+ State = n;
+ /* Backup to the replaced character. */
+ dec_cursor();
+}
+
+/*
+ * Replace a whole area with one character.
+ */
+ int
+op_replace(oparg_T *oap, int c)
+{
+ int n, numc;
+ int num_chars;
+ char_u *newp, *oldp;
+ size_t oldlen;
+ struct block_def bd;
+ char_u *after_p = NULL;
+ int had_ctrl_v_cr = FALSE;
+
+ if ((curbuf->b_ml.ml_flags & ML_EMPTY ) || oap->empty)
+ return OK; /* nothing to do */
+
+ if (c == REPLACE_CR_NCHAR)
+ {
+ had_ctrl_v_cr = TRUE;
+ c = CAR;
+ }
+ else if (c == REPLACE_NL_NCHAR)
+ {
+ had_ctrl_v_cr = TRUE;
+ c = NL;
+ }
+
+ if (has_mbyte)
+ mb_adjust_opend(oap);
+
+ if (u_save((linenr_T)(oap->start.lnum - 1),
+ (linenr_T)(oap->end.lnum + 1)) == FAIL)
+ return FAIL;
+
+ /*
+ * block mode replace
+ */
+ if (oap->block_mode)
+ {
+ bd.is_MAX = (curwin->w_curswant == MAXCOL);
+ for ( ; curwin->w_cursor.lnum <= oap->end.lnum; ++curwin->w_cursor.lnum)
+ {
+ curwin->w_cursor.col = 0; /* make sure cursor position is valid */
+ block_prep(oap, &bd, curwin->w_cursor.lnum, TRUE);
+ if (bd.textlen == 0 && (!virtual_op || bd.is_MAX))
+ continue; /* nothing to replace */
+
+ /* n == number of extra chars required
+ * If we split a TAB, it may be replaced by several characters.
+ * Thus the number of characters may increase!
+ */
+ /* If the range starts in virtual space, count the initial
+ * coladd offset as part of "startspaces" */
+ if (virtual_op && bd.is_short && *bd.textstart == NUL)
+ {
+ pos_T vpos;
+
+ vpos.lnum = curwin->w_cursor.lnum;
+ getvpos(&vpos, oap->start_vcol);
+ bd.startspaces += vpos.coladd;
+ n = bd.startspaces;
+ }
+ else
+ /* allow for pre spaces */
+ n = (bd.startspaces ? bd.start_char_vcols - 1 : 0);
+
+ /* allow for post spp */
+ n += (bd.endspaces
+ && !bd.is_oneChar
+ && bd.end_char_vcols > 0) ? bd.end_char_vcols - 1 : 0;
+ /* Figure out how many characters to replace. */
+ numc = oap->end_vcol - oap->start_vcol + 1;
+ if (bd.is_short && (!virtual_op || bd.is_MAX))
+ numc -= (oap->end_vcol - bd.end_vcol) + 1;
+
+ /* A double-wide character can be replaced only up to half the
+ * times. */
+ if ((*mb_char2cells)(c) > 1)
+ {
+ if ((numc & 1) && !bd.is_short)
+ {
+ ++bd.endspaces;
+ ++n;
+ }
+ numc = numc / 2;
+ }
+
+ /* Compute bytes needed, move character count to num_chars. */
+ num_chars = numc;
+ numc *= (*mb_char2len)(c);
+ /* oldlen includes textlen, so don't double count */
+ n += numc - bd.textlen;
+
+ oldp = ml_get_curline();
+ oldlen = STRLEN(oldp);
+ newp = alloc_check((unsigned)oldlen + 1 + n);
+ if (newp == NULL)
+ continue;
+ vim_memset(newp, NUL, (size_t)(oldlen + 1 + n));
+ /* copy up to deleted part */
+ mch_memmove(newp, oldp, (size_t)bd.textcol);
+ oldp += bd.textcol + bd.textlen;
+ /* insert pre-spaces */
+ vim_memset(newp + bd.textcol, ' ', (size_t)bd.startspaces);
+ /* insert replacement chars CHECK FOR ALLOCATED SPACE */
+ /* REPLACE_CR_NCHAR/REPLACE_NL_NCHAR is used for entering CR
+ * literally. */
+ if (had_ctrl_v_cr || (c != '\r' && c != '\n'))
+ {
+ if (has_mbyte)
+ {
+ n = (int)STRLEN(newp);
+ while (--num_chars >= 0)
+ n += (*mb_char2bytes)(c, newp + n);
+ }
+ else
+ vim_memset(newp + STRLEN(newp), c, (size_t)numc);
+ if (!bd.is_short)
+ {
+ /* insert post-spaces */
+ vim_memset(newp + STRLEN(newp), ' ', (size_t)bd.endspaces);
+ /* copy the part after the changed part */
+ STRMOVE(newp + STRLEN(newp), oldp);
+ }
+ }
+ else
+ {
+ /* Replacing with \r or \n means splitting the line. */
+ after_p = alloc_check(
+ (unsigned)(oldlen + 1 + n - STRLEN(newp)));
+ if (after_p != NULL)
+ STRMOVE(after_p, oldp);
+ }
+ /* replace the line */
+ ml_replace(curwin->w_cursor.lnum, newp, FALSE);
+ if (after_p != NULL)
+ {
+ ml_append(curwin->w_cursor.lnum++, after_p, 0, FALSE);
+ appended_lines_mark(curwin->w_cursor.lnum, 1L);
+ oap->end.lnum++;
+ vim_free(after_p);
+ }
+ }
+ }
+ else
+ {
+ /*
+ * MCHAR and MLINE motion replace.
+ */
+ if (oap->motion_type == MLINE)
+ {
+ oap->start.col = 0;
+ curwin->w_cursor.col = 0;
+ oap->end.col = (colnr_T)STRLEN(ml_get(oap->end.lnum));
+ if (oap->end.col)
+ --oap->end.col;
+ }
+ else if (!oap->inclusive)
+ dec(&(oap->end));
+
+ while (LTOREQ_POS(curwin->w_cursor, oap->end))
+ {
+ n = gchar_cursor();
+ if (n != NUL)
+ {
+ if ((*mb_char2len)(c) > 1 || (*mb_char2len)(n) > 1)
+ {
+ /* This is slow, but it handles replacing a single-byte
+ * with a multi-byte and the other way around. */
+ if (curwin->w_cursor.lnum == oap->end.lnum)
+ oap->end.col += (*mb_char2len)(c) - (*mb_char2len)(n);
+ replace_character(c);
+ }
+ else
+ {
+ if (n == TAB)
+ {
+ int end_vcol = 0;
+
+ if (curwin->w_cursor.lnum == oap->end.lnum)
+ {
+ /* oap->end has to be recalculated when
+ * the tab breaks */
+ end_vcol = getviscol2(oap->end.col,
+ oap->end.coladd);
+ }
+ coladvance_force(getviscol());
+ if (curwin->w_cursor.lnum == oap->end.lnum)
+ getvpos(&oap->end, end_vcol);
+ }
+ PBYTE(curwin->w_cursor, c);
+ }
+ }
+ else if (virtual_op && curwin->w_cursor.lnum == oap->end.lnum)
+ {
+ int virtcols = oap->end.coladd;
+
+ if (curwin->w_cursor.lnum == oap->start.lnum
+ && oap->start.col == oap->end.col && oap->start.coladd)
+ virtcols -= oap->start.coladd;
+
+ /* oap->end has been trimmed so it's effectively inclusive;
+ * as a result an extra +1 must be counted so we don't
+ * trample the NUL byte. */
+ coladvance_force(getviscol2(oap->end.col, oap->end.coladd) + 1);
+ curwin->w_cursor.col -= (virtcols + 1);
+ for (; virtcols >= 0; virtcols--)
+ {
+ if ((*mb_char2len)(c) > 1)
+ replace_character(c);
+ else
+ PBYTE(curwin->w_cursor, c);
+ if (inc(&curwin->w_cursor) == -1)
+ break;
+ }
+ }
+
+ /* Advance to next character, stop at the end of the file. */
+ if (inc_cursor() == -1)
+ break;
+ }
+ }
+
+ curwin->w_cursor = oap->start;
+ check_cursor();
+ changed_lines(oap->start.lnum, oap->start.col, oap->end.lnum + 1, 0L);
+
+ /* Set "'[" and "']" marks. */
+ curbuf->b_op_start = oap->start;
+ curbuf->b_op_end = oap->end;
+
+ return OK;
+}
+
+static int swapchars(int op_type, pos_T *pos, int length);
+
+/*
+ * Handle the (non-standard vi) tilde operator. Also for "gu", "gU" and "g?".
+ */
+ void
+op_tilde(oparg_T *oap)
+{
+ pos_T pos;
+ struct block_def bd;
+ int did_change = FALSE;
+
+ if (u_save((linenr_T)(oap->start.lnum - 1),
+ (linenr_T)(oap->end.lnum + 1)) == FAIL)
+ return;
+
+ pos = oap->start;
+ if (oap->block_mode) /* Visual block mode */
+ {
+ for (; pos.lnum <= oap->end.lnum; ++pos.lnum)
+ {
+ int one_change;
+
+ block_prep(oap, &bd, pos.lnum, FALSE);
+ pos.col = bd.textcol;
+ one_change = swapchars(oap->op_type, &pos, bd.textlen);
+ did_change |= one_change;
+
+#ifdef FEAT_NETBEANS_INTG
+ if (netbeans_active() && one_change)
+ {
+ char_u *ptr = ml_get_buf(curbuf, pos.lnum, FALSE);
+
+ netbeans_removed(curbuf, pos.lnum, bd.textcol,
+ (long)bd.textlen);
+ netbeans_inserted(curbuf, pos.lnum, bd.textcol,
+ &ptr[bd.textcol], bd.textlen);
+ }
+#endif
+ }
+ if (did_change)
+ changed_lines(oap->start.lnum, 0, oap->end.lnum + 1, 0L);
+ }
+ else /* not block mode */
+ {
+ if (oap->motion_type == MLINE)
+ {
+ oap->start.col = 0;
+ pos.col = 0;
+ oap->end.col = (colnr_T)STRLEN(ml_get(oap->end.lnum));
+ if (oap->end.col)
+ --oap->end.col;
+ }
+ else if (!oap->inclusive)
+ dec(&(oap->end));
+
+ if (pos.lnum == oap->end.lnum)
+ did_change = swapchars(oap->op_type, &pos,
+ oap->end.col - pos.col + 1);
+ else
+ for (;;)
+ {
+ did_change |= swapchars(oap->op_type, &pos,
+ pos.lnum == oap->end.lnum ? oap->end.col + 1:
+ (int)STRLEN(ml_get_pos(&pos)));
+ if (LTOREQ_POS(oap->end, pos) || inc(&pos) == -1)
+ break;
+ }
+ if (did_change)
+ {
+ changed_lines(oap->start.lnum, oap->start.col, oap->end.lnum + 1,
+ 0L);
+#ifdef FEAT_NETBEANS_INTG
+ if (netbeans_active() && did_change)
+ {
+ char_u *ptr;
+ int count;
+
+ pos = oap->start;
+ while (pos.lnum < oap->end.lnum)
+ {
+ ptr = ml_get_buf(curbuf, pos.lnum, FALSE);
+ count = (int)STRLEN(ptr) - pos.col;
+ netbeans_removed(curbuf, pos.lnum, pos.col, (long)count);
+ netbeans_inserted(curbuf, pos.lnum, pos.col,
+ &ptr[pos.col], count);
+ pos.col = 0;
+ pos.lnum++;
+ }
+ ptr = ml_get_buf(curbuf, pos.lnum, FALSE);
+ count = oap->end.col - pos.col + 1;
+ netbeans_removed(curbuf, pos.lnum, pos.col, (long)count);
+ netbeans_inserted(curbuf, pos.lnum, pos.col,
+ &ptr[pos.col], count);
+ }
+#endif
+ }
+ }
+
+ if (!did_change && oap->is_VIsual)
+ /* No change: need to remove the Visual selection */
+ redraw_curbuf_later(INVERTED);
+
+ /*
+ * Set '[ and '] marks.
+ */
+ curbuf->b_op_start = oap->start;
+ curbuf->b_op_end = oap->end;
+
+ if (oap->line_count > p_report)
+ smsg(NGETTEXT("%ld line changed", "%ld lines changed",
+ oap->line_count), oap->line_count);
+}
+
+/*
+ * Invoke swapchar() on "length" bytes at position "pos".
+ * "pos" is advanced to just after the changed characters.
+ * "length" is rounded up to include the whole last multi-byte character.
+ * Also works correctly when the number of bytes changes.
+ * Returns TRUE if some character was changed.
+ */
+ static int
+swapchars(int op_type, pos_T *pos, int length)
+{
+ int todo;
+ int did_change = 0;
+
+ for (todo = length; todo > 0; --todo)
+ {
+ if (has_mbyte)
+ {
+ int len = (*mb_ptr2len)(ml_get_pos(pos));
+
+ /* we're counting bytes, not characters */
+ if (len > 0)
+ todo -= len - 1;
+ }
+ did_change |= swapchar(op_type, pos);
+ if (inc(pos) == -1) /* at end of file */
+ break;
+ }
+ return did_change;
+}
+
+/*
+ * If op_type == OP_UPPER: make uppercase,
+ * if op_type == OP_LOWER: make lowercase,
+ * if op_type == OP_ROT13: do rot13 encoding,
+ * else swap case of character at 'pos'
+ * returns TRUE when something actually changed.
+ */
+ int
+swapchar(int op_type, pos_T *pos)
+{
+ int c;
+ int nc;
+
+ c = gchar_pos(pos);
+
+ /* Only do rot13 encoding for ASCII characters. */
+ if (c >= 0x80 && op_type == OP_ROT13)
+ return FALSE;
+
+ if (op_type == OP_UPPER && c == 0xdf
+ && (enc_latin1like || STRCMP(p_enc, "iso-8859-2") == 0))
+ {
+ pos_T sp = curwin->w_cursor;
+
+ /* Special handling of German sharp s: change to "SS". */
+ curwin->w_cursor = *pos;
+ del_char(FALSE);
+ ins_char('S');
+ ins_char('S');
+ curwin->w_cursor = sp;
+ inc(pos);
+ }
+
+ if (enc_dbcs != 0 && c >= 0x100) /* No lower/uppercase letter */
+ return FALSE;
+ nc = c;
+ if (MB_ISLOWER(c))
+ {
+ if (op_type == OP_ROT13)
+ nc = ROT13(c, 'a');
+ else if (op_type != OP_LOWER)
+ nc = MB_TOUPPER(c);
+ }
+ else if (MB_ISUPPER(c))
+ {
+ if (op_type == OP_ROT13)
+ nc = ROT13(c, 'A');
+ else if (op_type != OP_UPPER)
+ nc = MB_TOLOWER(c);
+ }
+ if (nc != c)
+ {
+ if (enc_utf8 && (c >= 0x80 || nc >= 0x80))
+ {
+ pos_T sp = curwin->w_cursor;
+
+ curwin->w_cursor = *pos;
+ /* don't use del_char(), it also removes composing chars */
+ del_bytes(utf_ptr2len(ml_get_cursor()), FALSE, FALSE);
+ ins_char(nc);
+ curwin->w_cursor = sp;
+ }
+ else
+ PBYTE(*pos, nc);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * op_insert - Insert and append operators for Visual mode.
+ */
+ void
+op_insert(oparg_T *oap, long count1)
+{
+ long ins_len, pre_textlen = 0;
+ char_u *firstline, *ins_text;
+ colnr_T ind_pre = 0, ind_post;
+ struct block_def bd;
+ int i;
+ pos_T t1;
+
+ /* edit() changes this - record it for OP_APPEND */
+ bd.is_MAX = (curwin->w_curswant == MAXCOL);
+
+ /* vis block is still marked. Get rid of it now. */
+ curwin->w_cursor.lnum = oap->start.lnum;
+ update_screen(INVERTED);
+
+ if (oap->block_mode)
+ {
+ /* When 'virtualedit' is used, need to insert the extra spaces before
+ * doing block_prep(). When only "block" is used, virtual edit is
+ * already disabled, but still need it when calling
+ * coladvance_force(). */
+ if (curwin->w_cursor.coladd > 0)
+ {
+ int old_ve_flags = ve_flags;
+
+ ve_flags = VE_ALL;
+ if (u_save_cursor() == FAIL)
+ return;
+ coladvance_force(oap->op_type == OP_APPEND
+ ? oap->end_vcol + 1 : getviscol());
+ if (oap->op_type == OP_APPEND)
+ --curwin->w_cursor.col;
+ ve_flags = old_ve_flags;
+ }
+ /* Get the info about the block before entering the text */
+ block_prep(oap, &bd, oap->start.lnum, TRUE);
+ /* Get indent information */
+ ind_pre = (colnr_T)getwhitecols_curline();
+ firstline = ml_get(oap->start.lnum) + bd.textcol;
+
+ if (oap->op_type == OP_APPEND)
+ firstline += bd.textlen;
+ pre_textlen = (long)STRLEN(firstline);
+ }
+
+ if (oap->op_type == OP_APPEND)
+ {
+ if (oap->block_mode && curwin->w_cursor.coladd == 0)
+ {
+ /* Move the cursor to the character right of the block. */
+ curwin->w_set_curswant = TRUE;
+ while (*ml_get_cursor() != NUL
+ && (curwin->w_cursor.col < bd.textcol + bd.textlen))
+ ++curwin->w_cursor.col;
+ if (bd.is_short && !bd.is_MAX)
+ {
+ /* First line was too short, make it longer and adjust the
+ * values in "bd". */
+ if (u_save_cursor() == FAIL)
+ return;
+ for (i = 0; i < bd.endspaces; ++i)
+ ins_char(' ');
+ bd.textlen += bd.endspaces;
+ }
+ }
+ else
+ {
+ curwin->w_cursor = oap->end;
+ check_cursor_col();
+
+ /* Works just like an 'i'nsert on the next character. */
+ if (!LINEEMPTY(curwin->w_cursor.lnum)
+ && oap->start_vcol != oap->end_vcol)
+ inc_cursor();
+ }
+ }
+
+ t1 = oap->start;
+ (void)edit(NUL, FALSE, (linenr_T)count1);
+
+ /* When a tab was inserted, and the characters in front of the tab
+ * have been converted to a tab as well, the column of the cursor
+ * might have actually been reduced, so need to adjust here. */
+ if (t1.lnum == curbuf->b_op_start_orig.lnum
+ && LT_POS(curbuf->b_op_start_orig, t1))
+ oap->start = curbuf->b_op_start_orig;
+
+ /* If user has moved off this line, we don't know what to do, so do
+ * nothing.
+ * Also don't repeat the insert when Insert mode ended with CTRL-C. */
+ if (curwin->w_cursor.lnum != oap->start.lnum || got_int)
+ return;
+
+ if (oap->block_mode)
+ {
+ struct block_def bd2;
+ int did_indent = FALSE;
+ size_t len;
+ int add;
+
+ /* If indent kicked in, the firstline might have changed
+ * but only do that, if the indent actually increased. */
+ ind_post = (colnr_T)getwhitecols_curline();
+ if (curbuf->b_op_start.col > ind_pre && ind_post > ind_pre)
+ {
+ bd.textcol += ind_post - ind_pre;
+ bd.start_vcol += ind_post - ind_pre;
+ did_indent = TRUE;
+ }
+
+ /* The user may have moved the cursor before inserting something, try
+ * to adjust the block for that. But only do it, if the difference
+ * does not come from indent kicking in. */
+ if (oap->start.lnum == curbuf->b_op_start_orig.lnum
+ && !bd.is_MAX && !did_indent)
+ {
+ if (oap->op_type == OP_INSERT
+ && oap->start.col + oap->start.coladd
+ != curbuf->b_op_start_orig.col
+ + curbuf->b_op_start_orig.coladd)
+ {
+ int t = getviscol2(curbuf->b_op_start_orig.col,
+ curbuf->b_op_start_orig.coladd);
+ oap->start.col = curbuf->b_op_start_orig.col;
+ pre_textlen -= t - oap->start_vcol;
+ oap->start_vcol = t;
+ }
+ else if (oap->op_type == OP_APPEND
+ && oap->end.col + oap->end.coladd
+ >= curbuf->b_op_start_orig.col
+ + curbuf->b_op_start_orig.coladd)
+ {
+ int t = getviscol2(curbuf->b_op_start_orig.col,
+ curbuf->b_op_start_orig.coladd);
+ oap->start.col = curbuf->b_op_start_orig.col;
+ /* reset pre_textlen to the value of OP_INSERT */
+ pre_textlen += bd.textlen;
+ pre_textlen -= t - oap->start_vcol;
+ oap->start_vcol = t;
+ oap->op_type = OP_INSERT;
+ }
+ }
+
+ /*
+ * Spaces and tabs in the indent may have changed to other spaces and
+ * tabs. Get the starting column again and correct the length.
+ * Don't do this when "$" used, end-of-line will have changed.
+ */
+ block_prep(oap, &bd2, oap->start.lnum, TRUE);
+ if (!bd.is_MAX || bd2.textlen < bd.textlen)
+ {
+ if (oap->op_type == OP_APPEND)
+ {
+ pre_textlen += bd2.textlen - bd.textlen;
+ if (bd2.endspaces)
+ --bd2.textlen;
+ }
+ bd.textcol = bd2.textcol;
+ bd.textlen = bd2.textlen;
+ }
+
+ /*
+ * Subsequent calls to ml_get() flush the firstline data - take a
+ * copy of the required string.
+ */
+ firstline = ml_get(oap->start.lnum);
+ len = STRLEN(firstline);
+ add = bd.textcol;
+ if (oap->op_type == OP_APPEND)
+ add += bd.textlen;
+ if ((size_t)add > len)
+ firstline += len; // short line, point to the NUL
+ else
+ firstline += add;
+ if (pre_textlen >= 0
+ && (ins_len = (long)STRLEN(firstline) - pre_textlen) > 0)
+ {
+ ins_text = vim_strnsave(firstline, (int)ins_len);
+ if (ins_text != NULL)
+ {
+ /* block handled here */
+ if (u_save(oap->start.lnum,
+ (linenr_T)(oap->end.lnum + 1)) == OK)
+ block_insert(oap, ins_text, (oap->op_type == OP_INSERT),
+ &bd);
+
+ curwin->w_cursor.col = oap->start.col;
+ check_cursor();
+ vim_free(ins_text);
+ }
+ }
+ }
+}
+
+/*
+ * op_change - handle a change operation
+ *
+ * return TRUE if edit() returns because of a CTRL-O command
+ */
+ int
+op_change(oparg_T *oap)
+{
+ colnr_T l;
+ int retval;
+ long offset;
+ linenr_T linenr;
+ long ins_len;
+ long pre_textlen = 0;
+ long pre_indent = 0;
+ char_u *firstline;
+ char_u *ins_text, *newp, *oldp;
+ struct block_def bd;
+
+ l = oap->start.col;
+ if (oap->motion_type == MLINE)
+ {
+ l = 0;
+#ifdef FEAT_SMARTINDENT
+ if (!p_paste && curbuf->b_p_si
+# ifdef FEAT_CINDENT
+ && !curbuf->b_p_cin
+# endif
+ )
+ can_si = TRUE; /* It's like opening a new line, do si */
+#endif
+ }
+
+ /* First delete the text in the region. In an empty buffer only need to
+ * save for undo */
+ if (curbuf->b_ml.ml_flags & ML_EMPTY)
+ {
+ if (u_save_cursor() == FAIL)
+ return FALSE;
+ }
+ else if (op_delete(oap) == FAIL)
+ return FALSE;
+
+ if ((l > curwin->w_cursor.col) && !LINEEMPTY(curwin->w_cursor.lnum)
+ && !virtual_op)
+ inc_cursor();
+
+ /* check for still on same line (<CR> in inserted text meaningless) */
+ /* skip blank lines too */
+ if (oap->block_mode)
+ {
+ /* Add spaces before getting the current line length. */
+ if (virtual_op && (curwin->w_cursor.coladd > 0
+ || gchar_cursor() == NUL))
+ coladvance_force(getviscol());
+ firstline = ml_get(oap->start.lnum);
+ pre_textlen = (long)STRLEN(firstline);
+ pre_indent = (long)getwhitecols(firstline);
+ bd.textcol = curwin->w_cursor.col;
+ }
+
+#if defined(FEAT_LISP) || defined(FEAT_CINDENT)
+ if (oap->motion_type == MLINE)
+ fix_indent();
+#endif
+
+ retval = edit(NUL, FALSE, (linenr_T)1);
+
+ /*
+ * In Visual block mode, handle copying the new text to all lines of the
+ * block.
+ * Don't repeat the insert when Insert mode ended with CTRL-C.
+ */
+ if (oap->block_mode && oap->start.lnum != oap->end.lnum && !got_int)
+ {
+ /* Auto-indenting may have changed the indent. If the cursor was past
+ * the indent, exclude that indent change from the inserted text. */
+ firstline = ml_get(oap->start.lnum);
+ if (bd.textcol > (colnr_T)pre_indent)
+ {
+ long new_indent = (long)getwhitecols(firstline);
+
+ pre_textlen += new_indent - pre_indent;
+ bd.textcol += new_indent - pre_indent;
+ }
+
+ ins_len = (long)STRLEN(firstline) - pre_textlen;
+ if (ins_len > 0)
+ {
+ /* Subsequent calls to ml_get() flush the firstline data - take a
+ * copy of the inserted text. */
+ if ((ins_text = alloc_check((unsigned)(ins_len + 1))) != NULL)
+ {
+ vim_strncpy(ins_text, firstline + bd.textcol, (size_t)ins_len);
+ for (linenr = oap->start.lnum + 1; linenr <= oap->end.lnum;
+ linenr++)
+ {
+ block_prep(oap, &bd, linenr, TRUE);
+ if (!bd.is_short || virtual_op)
+ {
+ pos_T vpos;
+
+ /* If the block starts in virtual space, count the
+ * initial coladd offset as part of "startspaces" */
+ if (bd.is_short)
+ {
+ vpos.lnum = linenr;
+ (void)getvpos(&vpos, oap->start_vcol);
+ }
+ else
+ vpos.coladd = 0;
+ oldp = ml_get(linenr);
+ newp = alloc_check((unsigned)(STRLEN(oldp)
+ + vpos.coladd + ins_len + 1));
+ if (newp == NULL)
+ continue;
+ /* copy up to block start */
+ mch_memmove(newp, oldp, (size_t)bd.textcol);
+ offset = bd.textcol;
+ vim_memset(newp + offset, ' ', (size_t)vpos.coladd);
+ offset += vpos.coladd;
+ mch_memmove(newp + offset, ins_text, (size_t)ins_len);
+ offset += ins_len;
+ oldp += bd.textcol;
+ STRMOVE(newp + offset, oldp);
+ ml_replace(linenr, newp, FALSE);
+ }
+ }
+ check_cursor();
+
+ changed_lines(oap->start.lnum + 1, 0, oap->end.lnum + 1, 0L);
+ }
+ vim_free(ins_text);
+ }
+ }
+
+ return retval;
+}
+
+/*
+ * set all the yank registers to empty (called from main())
+ */
+ void
+init_yank(void)
+{
+ int i;
+
+ for (i = 0; i < NUM_REGISTERS; ++i)
+ y_regs[i].y_array = NULL;
+}
+
+#if defined(EXITFREE) || defined(PROTO)
+ void
+clear_registers(void)
+{
+ int i;
+
+ for (i = 0; i < NUM_REGISTERS; ++i)
+ {
+ y_current = &y_regs[i];
+ if (y_current->y_array != NULL)
+ free_yank_all();
+ }
+}
+#endif
+
+/*
+ * Free "n" lines from the current yank register.
+ * Called for normal freeing and in case of error.
+ */
+ static void
+free_yank(long n)
+{
+ if (y_current->y_array != NULL)
+ {
+ long i;
+
+ for (i = n; --i >= 0; )
+ {
+#ifdef AMIGA /* only for very slow machines */
+ if ((i & 1023) == 1023) /* this may take a while */
+ {
+ /*
+ * This message should never cause a hit-return message.
+ * Overwrite this message with any next message.
+ */
+ ++no_wait_return;
+ smsg(_("freeing %ld lines"), i + 1);
+ --no_wait_return;
+ msg_didout = FALSE;
+ msg_col = 0;
+ }
+#endif
+ vim_free(y_current->y_array[i]);
+ }
+ VIM_CLEAR(y_current->y_array);
+#ifdef AMIGA
+ if (n >= 1000)
+ msg("");
+#endif
+ }
+}
+
+ static void
+free_yank_all(void)
+{
+ free_yank(y_current->y_size);
+}
+
+/*
+ * Yank the text between "oap->start" and "oap->end" into a yank register.
+ * If we are to append (uppercase register), we first yank into a new yank
+ * register and then concatenate the old and the new one (so we keep the old
+ * one in case of out-of-memory).
+ *
+ * Return FAIL for failure, OK otherwise.
+ */
+ int
+op_yank(oparg_T *oap, int deleting, int mess)
+{
+ long y_idx; /* index in y_array[] */
+ yankreg_T *curr; /* copy of y_current */
+ yankreg_T newreg; /* new yank register when appending */
+ char_u **new_ptr;
+ linenr_T lnum; /* current line number */
+ long j;
+ int yanktype = oap->motion_type;
+ long yanklines = oap->line_count;
+ linenr_T yankendlnum = oap->end.lnum;
+ char_u *p;
+ char_u *pnew;
+ struct block_def bd;
+#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
+ int did_star = FALSE;
+#endif
+
+ /* check for read-only register */
+ if (oap->regname != 0 && !valid_yank_reg(oap->regname, TRUE))
+ {
+ beep_flush();
+ return FAIL;
+ }
+ if (oap->regname == '_') /* black hole: nothing to do */
+ return OK;
+
+#ifdef FEAT_CLIPBOARD
+ if (!clip_star.available && oap->regname == '*')
+ oap->regname = 0;
+ else if (!clip_plus.available && oap->regname == '+')
+ oap->regname = 0;
+#endif
+
+ if (!deleting) /* op_delete() already set y_current */
+ get_yank_register(oap->regname, TRUE);
+
+ curr = y_current;
+ /* append to existing contents */
+ if (y_append && y_current->y_array != NULL)
+ y_current = &newreg;
+ else
+ free_yank_all(); /* free previously yanked lines */
+
+ /*
+ * If the cursor was in column 1 before and after the movement, and the
+ * operator is not inclusive, the yank is always linewise.
+ */
+ if ( oap->motion_type == MCHAR
+ && oap->start.col == 0
+ && !oap->inclusive
+ && (!oap->is_VIsual || *p_sel == 'o')
+ && !oap->block_mode
+ && oap->end.col == 0
+ && yanklines > 1)
+ {
+ yanktype = MLINE;
+ --yankendlnum;
+ --yanklines;
+ }
+
+ y_current->y_size = yanklines;
+ y_current->y_type = yanktype; /* set the yank register type */
+ y_current->y_width = 0;
+ y_current->y_array = (char_u **)lalloc_clear((long_u)(sizeof(char_u *) *
+ yanklines), TRUE);
+ if (y_current->y_array == NULL)
+ {
+ y_current = curr;
+ return FAIL;
+ }
+#ifdef FEAT_VIMINFO
+ y_current->y_time_set = vim_time();
+#endif
+
+ y_idx = 0;
+ lnum = oap->start.lnum;
+
+ if (oap->block_mode)
+ {
+ /* Visual block mode */
+ y_current->y_type = MBLOCK; /* set the yank register type */
+ y_current->y_width = oap->end_vcol - oap->start_vcol;
+
+ if (curwin->w_curswant == MAXCOL && y_current->y_width > 0)
+ y_current->y_width--;
+ }
+
+ for ( ; lnum <= yankendlnum; lnum++, y_idx++)
+ {
+ switch (y_current->y_type)
+ {
+ case MBLOCK:
+ block_prep(oap, &bd, lnum, FALSE);
+ if (yank_copy_line(&bd, y_idx) == FAIL)
+ goto fail;
+ break;
+
+ case MLINE:
+ if ((y_current->y_array[y_idx] =
+ vim_strsave(ml_get(lnum))) == NULL)
+ goto fail;
+ break;
+
+ case MCHAR:
+ {
+ colnr_T startcol = 0, endcol = MAXCOL;
+ int is_oneChar = FALSE;
+ colnr_T cs, ce;
+
+ p = ml_get(lnum);
+ bd.startspaces = 0;
+ bd.endspaces = 0;
+
+ if (lnum == oap->start.lnum)
+ {
+ startcol = oap->start.col;
+ if (virtual_op)
+ {
+ getvcol(curwin, &oap->start, &cs, NULL, &ce);
+ if (ce != cs && oap->start.coladd > 0)
+ {
+ /* Part of a tab selected -- but don't
+ * double-count it. */
+ bd.startspaces = (ce - cs + 1)
+ - oap->start.coladd;
+ startcol++;
+ }
+ }
+ }
+
+ if (lnum == oap->end.lnum)
+ {
+ endcol = oap->end.col;
+ if (virtual_op)
+ {
+ getvcol(curwin, &oap->end, &cs, NULL, &ce);
+ if (p[endcol] == NUL || (cs + oap->end.coladd < ce
+ /* Don't add space for double-wide
+ * char; endcol will be on last byte
+ * of multi-byte char. */
+ && (*mb_head_off)(p, p + endcol) == 0))
+ {
+ if (oap->start.lnum == oap->end.lnum
+ && oap->start.col == oap->end.col)
+ {
+ /* Special case: inside a single char */
+ is_oneChar = TRUE;
+ bd.startspaces = oap->end.coladd
+ - oap->start.coladd + oap->inclusive;
+ endcol = startcol;
+ }
+ else
+ {
+ bd.endspaces = oap->end.coladd
+ + oap->inclusive;
+ endcol -= oap->inclusive;
+ }
+ }
+ }
+ }
+ if (endcol == MAXCOL)
+ endcol = (colnr_T)STRLEN(p);
+ if (startcol > endcol || is_oneChar)
+ bd.textlen = 0;
+ else
+ {
+ bd.textlen = endcol - startcol + oap->inclusive;
+ }
+ bd.textstart = p + startcol;
+ if (yank_copy_line(&bd, y_idx) == FAIL)
+ goto fail;
+ break;
+ }
+ /* NOTREACHED */
+ }
+ }
+
+ if (curr != y_current) /* append the new block to the old block */
+ {
+ new_ptr = (char_u **)lalloc((long_u)(sizeof(char_u *) *
+ (curr->y_size + y_current->y_size)), TRUE);
+ if (new_ptr == NULL)
+ goto fail;
+ for (j = 0; j < curr->y_size; ++j)
+ new_ptr[j] = curr->y_array[j];
+ vim_free(curr->y_array);
+ curr->y_array = new_ptr;
+#ifdef FEAT_VIMINFO
+ curr->y_time_set = vim_time();
+#endif
+
+ if (yanktype == MLINE) /* MLINE overrides MCHAR and MBLOCK */
+ curr->y_type = MLINE;
+
+ /* Concatenate the last line of the old block with the first line of
+ * the new block, unless being Vi compatible. */
+ if (curr->y_type == MCHAR && vim_strchr(p_cpo, CPO_REGAPPEND) == NULL)
+ {
+ pnew = lalloc((long_u)(STRLEN(curr->y_array[curr->y_size - 1])
+ + STRLEN(y_current->y_array[0]) + 1), TRUE);
+ if (pnew == NULL)
+ {
+ y_idx = y_current->y_size - 1;
+ goto fail;
+ }
+ STRCPY(pnew, curr->y_array[--j]);
+ STRCAT(pnew, y_current->y_array[0]);
+ vim_free(curr->y_array[j]);
+ vim_free(y_current->y_array[0]);
+ curr->y_array[j++] = pnew;
+ y_idx = 1;
+ }
+ else
+ y_idx = 0;
+ while (y_idx < y_current->y_size)
+ curr->y_array[j++] = y_current->y_array[y_idx++];
+ curr->y_size = j;
+ vim_free(y_current->y_array);
+ y_current = curr;
+ }
+ if (curwin->w_p_rnu)
+ redraw_later(SOME_VALID); /* cursor moved to start */
+ if (mess) /* Display message about yank? */
+ {
+ if (yanktype == MCHAR
+ && !oap->block_mode
+ && yanklines == 1)
+ yanklines = 0;
+ /* Some versions of Vi use ">=" here, some don't... */
+ if (yanklines > p_report)
+ {
+ char namebuf[100];
+
+ if (oap->regname == NUL)
+ *namebuf = NUL;
+ else
+ vim_snprintf(namebuf, sizeof(namebuf),
+ _(" into \"%c"), oap->regname);
+
+ /* redisplay now, so message is not deleted */
+ update_topline_redraw();
+ if (oap->block_mode)
+ {
+ smsg(NGETTEXT("block of %ld line yanked%s",
+ "block of %ld lines yanked%s", yanklines),
+ yanklines, namebuf);
+ }
+ else
+ {
+ smsg(NGETTEXT("%ld line yanked%s",
+ "%ld lines yanked%s", yanklines),
+ yanklines, namebuf);
+ }
+ }
+ }
+
+ /*
+ * Set "'[" and "']" marks.
+ */
+ curbuf->b_op_start = oap->start;
+ curbuf->b_op_end = oap->end;
+ if (yanktype == MLINE && !oap->block_mode)
+ {
+ curbuf->b_op_start.col = 0;
+ curbuf->b_op_end.col = MAXCOL;
+ }
+
+#ifdef FEAT_CLIPBOARD
+ /*
+ * If we were yanking to the '*' register, send result to clipboard.
+ * If no register was specified, and "unnamed" in 'clipboard', make a copy
+ * to the '*' register.
+ */
+ if (clip_star.available
+ && (curr == &(y_regs[STAR_REGISTER])
+ || (!deleting && oap->regname == 0
+ && ((clip_unnamed | clip_unnamed_saved) & CLIP_UNNAMED))))
+ {
+ if (curr != &(y_regs[STAR_REGISTER]))
+ /* Copy the text from register 0 to the clipboard register. */
+ copy_yank_reg(&(y_regs[STAR_REGISTER]));
+
+ clip_own_selection(&clip_star);
+ clip_gen_set_selection(&clip_star);
+# ifdef FEAT_X11
+ did_star = TRUE;
+# endif
+ }
+
+# ifdef FEAT_X11
+ /*
+ * If we were yanking to the '+' register, send result to selection.
+ * Also copy to the '*' register, in case auto-select is off.
+ */
+ if (clip_plus.available
+ && (curr == &(y_regs[PLUS_REGISTER])
+ || (!deleting && oap->regname == 0
+ && ((clip_unnamed | clip_unnamed_saved) &
+ CLIP_UNNAMED_PLUS))))
+ {
+ if (curr != &(y_regs[PLUS_REGISTER]))
+ /* Copy the text from register 0 to the clipboard register. */
+ copy_yank_reg(&(y_regs[PLUS_REGISTER]));
+
+ clip_own_selection(&clip_plus);
+ clip_gen_set_selection(&clip_plus);
+ if (!clip_isautosel_star() && !clip_isautosel_plus()
+ && !did_star && curr == &(y_regs[PLUS_REGISTER]))
+ {
+ copy_yank_reg(&(y_regs[STAR_REGISTER]));
+ clip_own_selection(&clip_star);
+ clip_gen_set_selection(&clip_star);
+ }
+ }
+# endif
+#endif
+
+#if defined(FEAT_EVAL)
+ if (!deleting && has_textyankpost())
+ yank_do_autocmd(oap, y_current);
+#endif
+
+ return OK;
+
+fail: /* free the allocated lines */
+ free_yank(y_idx + 1);
+ y_current = curr;
+ return FAIL;
+}
+
+ static int
+yank_copy_line(struct block_def *bd, long y_idx)
+{
+ char_u *pnew;
+
+ if ((pnew = alloc(bd->startspaces + bd->endspaces + bd->textlen + 1))
+ == NULL)
+ return FAIL;
+ y_current->y_array[y_idx] = pnew;
+ vim_memset(pnew, ' ', (size_t)bd->startspaces);
+ pnew += bd->startspaces;
+ mch_memmove(pnew, bd->textstart, (size_t)bd->textlen);
+ pnew += bd->textlen;
+ vim_memset(pnew, ' ', (size_t)bd->endspaces);
+ pnew += bd->endspaces;
+ *pnew = NUL;
+ return OK;
+}
+
+#ifdef FEAT_CLIPBOARD
+/*
+ * Make a copy of the y_current register to register "reg".
+ */
+ static void
+copy_yank_reg(yankreg_T *reg)
+{
+ yankreg_T *curr = y_current;
+ long j;
+
+ y_current = reg;
+ free_yank_all();
+ *y_current = *curr;
+ y_current->y_array = (char_u **)lalloc_clear(
+ (long_u)(sizeof(char_u *) * y_current->y_size), TRUE);
+ if (y_current->y_array == NULL)
+ y_current->y_size = 0;
+ else
+ for (j = 0; j < y_current->y_size; ++j)
+ if ((y_current->y_array[j] = vim_strsave(curr->y_array[j])) == NULL)
+ {
+ free_yank(j);
+ y_current->y_size = 0;
+ break;
+ }
+ y_current = curr;
+}
+#endif
+
+/*
+ * Put contents of register "regname" into the text.
+ * Caller must check "regname" to be valid!
+ * "flags": PUT_FIXINDENT make indent look nice
+ * PUT_CURSEND leave cursor after end of new text
+ * PUT_LINE force linewise put (":put")
+ */
+ void
+do_put(
+ int regname,
+ int dir, /* BACKWARD for 'P', FORWARD for 'p' */
+ long count,
+ int flags)
+{
+ char_u *ptr;
+ char_u *newp, *oldp;
+ int yanklen;
+ int totlen = 0; /* init for gcc */
+ linenr_T lnum;
+ colnr_T col;
+ long i; /* index in y_array[] */
+ int y_type;
+ long y_size;
+ int oldlen;
+ long y_width = 0;
+ colnr_T vcol;
+ int delcount;
+ int incr = 0;
+ long j;
+ struct block_def bd;
+ char_u **y_array = NULL;
+ long nr_lines = 0;
+ pos_T new_cursor;
+ int indent;
+ int orig_indent = 0; /* init for gcc */
+ int indent_diff = 0; /* init for gcc */
+ int first_indent = TRUE;
+ int lendiff = 0;
+ pos_T old_pos;
+ char_u *insert_string = NULL;
+ int allocated = FALSE;
+ long cnt;
+
+#ifdef FEAT_CLIPBOARD
+ /* Adjust register name for "unnamed" in 'clipboard'. */
+ adjust_clip_reg(&regname);
+ (void)may_get_selection(regname);
+#endif
+
+ if (flags & PUT_FIXINDENT)
+ orig_indent = get_indent();
+
+ curbuf->b_op_start = curwin->w_cursor; /* default for '[ mark */
+ curbuf->b_op_end = curwin->w_cursor; /* default for '] mark */
+
+ /*
+ * Using inserted text works differently, because the register includes
+ * special characters (newlines, etc.).
+ */
+ if (regname == '.')
+ {
+ if (VIsual_active)
+ stuffcharReadbuff(VIsual_mode);
+ (void)stuff_inserted((dir == FORWARD ? (count == -1 ? 'o' : 'a') :
+ (count == -1 ? 'O' : 'i')), count, FALSE);
+ /* Putting the text is done later, so can't really move the cursor to
+ * the next character. Use "l" to simulate it. */
+ if ((flags & PUT_CURSEND) && gchar_cursor() != NUL)
+ stuffcharReadbuff('l');
+ return;
+ }
+
+ /*
+ * For special registers '%' (file name), '#' (alternate file name) and
+ * ':' (last command line), etc. we have to create a fake yank register.
+ */
+ if (get_spec_reg(regname, &insert_string, &allocated, TRUE))
+ {
+ if (insert_string == NULL)
+ return;
+ }
+
+ /* Autocommands may be executed when saving lines for undo. This might
+ * make "y_array" invalid, so we start undo now to avoid that. */
+ if (u_save(curwin->w_cursor.lnum, curwin->w_cursor.lnum + 1) == FAIL)
+ goto end;
+
+ if (insert_string != NULL)
+ {
+ y_type = MCHAR;
+#ifdef FEAT_EVAL
+ if (regname == '=')
+ {
+ /* For the = register we need to split the string at NL
+ * characters.
+ * Loop twice: count the number of lines and save them. */
+ for (;;)
+ {
+ y_size = 0;
+ ptr = insert_string;
+ while (ptr != NULL)
+ {
+ if (y_array != NULL)
+ y_array[y_size] = ptr;
+ ++y_size;
+ ptr = vim_strchr(ptr, '\n');
+ if (ptr != NULL)
+ {
+ if (y_array != NULL)
+ *ptr = NUL;
+ ++ptr;
+ /* A trailing '\n' makes the register linewise. */
+ if (*ptr == NUL)
+ {
+ y_type = MLINE;
+ break;
+ }
+ }
+ }
+ if (y_array != NULL)
+ break;
+ y_array = (char_u **)alloc((unsigned)
+ (y_size * sizeof(char_u *)));
+ if (y_array == NULL)
+ goto end;
+ }
+ }
+ else
+#endif
+ {
+ y_size = 1; /* use fake one-line yank register */
+ y_array = &insert_string;
+ }
+ }
+ else
+ {
+ get_yank_register(regname, FALSE);
+
+ y_type = y_current->y_type;
+ y_width = y_current->y_width;
+ y_size = y_current->y_size;
+ y_array = y_current->y_array;
+ }
+
+ if (y_type == MLINE)
+ {
+ if (flags & PUT_LINE_SPLIT)
+ {
+ char_u *p;
+
+ /* "p" or "P" in Visual mode: split the lines to put the text in
+ * between. */
+ if (u_save_cursor() == FAIL)
+ goto end;
+ p = ml_get_cursor();
+ if (dir == FORWARD && *p != NUL)
+ MB_PTR_ADV(p);
+ ptr = vim_strsave(p);
+ if (ptr == NULL)
+ goto end;
+ ml_append(curwin->w_cursor.lnum, ptr, (colnr_T)0, FALSE);
+ vim_free(ptr);
+
+ oldp = ml_get_curline();
+ p = oldp + curwin->w_cursor.col;
+ if (dir == FORWARD && *p != NUL)
+ MB_PTR_ADV(p);
+ ptr = vim_strnsave(oldp, p - oldp);
+ if (ptr == NULL)
+ goto end;
+ ml_replace(curwin->w_cursor.lnum, ptr, FALSE);
+ ++nr_lines;
+ dir = FORWARD;
+ }
+ if (flags & PUT_LINE_FORWARD)
+ {
+ /* Must be "p" for a Visual block, put lines below the block. */
+ curwin->w_cursor = curbuf->b_visual.vi_end;
+ dir = FORWARD;
+ }
+ curbuf->b_op_start = curwin->w_cursor; /* default for '[ mark */
+ curbuf->b_op_end = curwin->w_cursor; /* default for '] mark */
+ }
+
+ if (flags & PUT_LINE) /* :put command or "p" in Visual line mode. */
+ y_type = MLINE;
+
+ if (y_size == 0 || y_array == NULL)
+ {
+ semsg(_("E353: Nothing in register %s"),
+ regname == 0 ? (char_u *)"\"" : transchar(regname));
+ goto end;
+ }
+
+ if (y_type == MBLOCK)
+ {
+ lnum = curwin->w_cursor.lnum + y_size + 1;
+ if (lnum > curbuf->b_ml.ml_line_count)
+ lnum = curbuf->b_ml.ml_line_count + 1;
+ if (u_save(curwin->w_cursor.lnum - 1, lnum) == FAIL)
+ goto end;
+ }
+ else if (y_type == MLINE)
+ {
+ lnum = curwin->w_cursor.lnum;
+#ifdef FEAT_FOLDING
+ /* Correct line number for closed fold. Don't move the cursor yet,
+ * u_save() uses it. */
+ if (dir == BACKWARD)
+ (void)hasFolding(lnum, &lnum, NULL);
+ else
+ (void)hasFolding(lnum, NULL, &lnum);
+#endif
+ if (dir == FORWARD)
+ ++lnum;
+ /* In an empty buffer the empty line is going to be replaced, include
+ * it in the saved lines. */
+ if ((BUFEMPTY() ? u_save(0, 2) : u_save(lnum - 1, lnum)) == FAIL)
+ goto end;
+#ifdef FEAT_FOLDING
+ if (dir == FORWARD)
+ curwin->w_cursor.lnum = lnum - 1;
+ else
+ curwin->w_cursor.lnum = lnum;
+ curbuf->b_op_start = curwin->w_cursor; /* for mark_adjust() */
+#endif
+ }
+ else if (u_save_cursor() == FAIL)
+ goto end;
+
+ yanklen = (int)STRLEN(y_array[0]);
+
+ if (ve_flags == VE_ALL && y_type == MCHAR)
+ {
+ if (gchar_cursor() == TAB)
+ {
+ /* Don't need to insert spaces when "p" on the last position of a
+ * tab or "P" on the first position. */
+#ifdef FEAT_VARTABS
+ int viscol = getviscol();
+ if (dir == FORWARD
+ ? tabstop_padding(viscol, curbuf->b_p_ts,
+ curbuf->b_p_vts_array) != 1
+ : curwin->w_cursor.coladd > 0)
+ coladvance_force(viscol);
+#else
+ if (dir == FORWARD
+ ? (int)curwin->w_cursor.coladd < curbuf->b_p_ts - 1
+ : curwin->w_cursor.coladd > 0)
+ coladvance_force(getviscol());
+#endif
+ else
+ curwin->w_cursor.coladd = 0;
+ }
+ else if (curwin->w_cursor.coladd > 0 || gchar_cursor() == NUL)
+ coladvance_force(getviscol() + (dir == FORWARD));
+ }
+
+ lnum = curwin->w_cursor.lnum;
+ col = curwin->w_cursor.col;
+
+ /*
+ * Block mode
+ */
+ if (y_type == MBLOCK)
+ {
+ int c = gchar_cursor();
+ colnr_T endcol2 = 0;
+
+ if (dir == FORWARD && c != NUL)
+ {
+ if (ve_flags == VE_ALL)
+ getvcol(curwin, &curwin->w_cursor, &col, NULL, &endcol2);
+ else
+ getvcol(curwin, &curwin->w_cursor, NULL, NULL, &col);
+
+ if (has_mbyte)
+ /* move to start of next multi-byte character */
+ curwin->w_cursor.col += (*mb_ptr2len)(ml_get_cursor());
+ else
+ if (c != TAB || ve_flags != VE_ALL)
+ ++curwin->w_cursor.col;
+ ++col;
+ }
+ else
+ getvcol(curwin, &curwin->w_cursor, &col, NULL, &endcol2);
+
+ col += curwin->w_cursor.coladd;
+ if (ve_flags == VE_ALL
+ && (curwin->w_cursor.coladd > 0
+ || endcol2 == curwin->w_cursor.col))
+ {
+ if (dir == FORWARD && c == NUL)
+ ++col;
+ if (dir != FORWARD && c != NUL)
+ ++curwin->w_cursor.col;
+ if (c == TAB)
+ {
+ if (dir == BACKWARD && curwin->w_cursor.col)
+ curwin->w_cursor.col--;
+ if (dir == FORWARD && col - 1 == endcol2)
+ curwin->w_cursor.col++;
+ }
+ }
+ curwin->w_cursor.coladd = 0;
+ bd.textcol = 0;
+ for (i = 0; i < y_size; ++i)
+ {
+ int spaces;
+ char shortline;
+
+ bd.startspaces = 0;
+ bd.endspaces = 0;
+ vcol = 0;
+ delcount = 0;
+
+ /* add a new line */
+ if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
+ {
+ if (ml_append(curbuf->b_ml.ml_line_count, (char_u *)"",
+ (colnr_T)1, FALSE) == FAIL)
+ break;
+ ++nr_lines;
+ }
+ /* get the old line and advance to the position to insert at */
+ oldp = ml_get_curline();
+ oldlen = (int)STRLEN(oldp);
+ for (ptr = oldp; vcol < col && *ptr; )
+ {
+ /* Count a tab for what it's worth (if list mode not on) */
+ incr = lbr_chartabsize_adv(oldp, &ptr, (colnr_T)vcol);
+ vcol += incr;
+ }
+ bd.textcol = (colnr_T)(ptr - oldp);
+
+ shortline = (vcol < col) || (vcol == col && !*ptr) ;
+
+ if (vcol < col) /* line too short, padd with spaces */
+ bd.startspaces = col - vcol;
+ else if (vcol > col)
+ {
+ bd.endspaces = vcol - col;
+ bd.startspaces = incr - bd.endspaces;
+ --bd.textcol;
+ delcount = 1;
+ if (has_mbyte)
+ bd.textcol -= (*mb_head_off)(oldp, oldp + bd.textcol);
+ if (oldp[bd.textcol] != TAB)
+ {
+ /* Only a Tab can be split into spaces. Other
+ * characters will have to be moved to after the
+ * block, causing misalignment. */
+ delcount = 0;
+ bd.endspaces = 0;
+ }
+ }
+
+ yanklen = (int)STRLEN(y_array[i]);
+
+ /* calculate number of spaces required to fill right side of block*/
+ spaces = y_width + 1;
+ for (j = 0; j < yanklen; j++)
+ spaces -= lbr_chartabsize(NULL, &y_array[i][j], 0);
+ if (spaces < 0)
+ spaces = 0;
+
+ /* insert the new text */
+ totlen = count * (yanklen + spaces) + bd.startspaces + bd.endspaces;
+ newp = alloc_check((unsigned)totlen + oldlen + 1);
+ if (newp == NULL)
+ break;
+ /* copy part up to cursor to new line */
+ ptr = newp;
+ mch_memmove(ptr, oldp, (size_t)bd.textcol);
+ ptr += bd.textcol;
+ /* may insert some spaces before the new text */
+ vim_memset(ptr, ' ', (size_t)bd.startspaces);
+ ptr += bd.startspaces;
+ /* insert the new text */
+ for (j = 0; j < count; ++j)
+ {
+ mch_memmove(ptr, y_array[i], (size_t)yanklen);
+ ptr += yanklen;
+
+ /* insert block's trailing spaces only if there's text behind */
+ if ((j < count - 1 || !shortline) && spaces)
+ {
+ vim_memset(ptr, ' ', (size_t)spaces);
+ ptr += spaces;
+ }
+ }
+ /* may insert some spaces after the new text */
+ vim_memset(ptr, ' ', (size_t)bd.endspaces);
+ ptr += bd.endspaces;
+ /* move the text after the cursor to the end of the line. */
+ mch_memmove(ptr, oldp + bd.textcol + delcount,
+ (size_t)(oldlen - bd.textcol - delcount + 1));
+ ml_replace(curwin->w_cursor.lnum, newp, FALSE);
+
+ ++curwin->w_cursor.lnum;
+ if (i == 0)
+ curwin->w_cursor.col += bd.startspaces;
+ }
+
+ changed_lines(lnum, 0, curwin->w_cursor.lnum, nr_lines);
+
+ /* Set '[ mark. */
+ curbuf->b_op_start = curwin->w_cursor;
+ curbuf->b_op_start.lnum = lnum;
+
+ /* adjust '] mark */
+ curbuf->b_op_end.lnum = curwin->w_cursor.lnum - 1;
+ curbuf->b_op_end.col = bd.textcol + totlen - 1;
+ curbuf->b_op_end.coladd = 0;
+ if (flags & PUT_CURSEND)
+ {
+ colnr_T len;
+
+ curwin->w_cursor = curbuf->b_op_end;
+ curwin->w_cursor.col++;
+
+ /* in Insert mode we might be after the NUL, correct for that */
+ len = (colnr_T)STRLEN(ml_get_curline());
+ if (curwin->w_cursor.col > len)
+ curwin->w_cursor.col = len;
+ }
+ else
+ curwin->w_cursor.lnum = lnum;
+ }
+ else
+ {
+ /*
+ * Character or Line mode
+ */
+ if (y_type == MCHAR)
+ {
+ /* if type is MCHAR, FORWARD is the same as BACKWARD on the next
+ * char */
+ if (dir == FORWARD && gchar_cursor() != NUL)
+ {
+ if (has_mbyte)
+ {
+ int bytelen = (*mb_ptr2len)(ml_get_cursor());
+
+ /* put it on the next of the multi-byte character. */
+ col += bytelen;
+ if (yanklen)
+ {
+ curwin->w_cursor.col += bytelen;
+ curbuf->b_op_end.col += bytelen;
+ }
+ }
+ else
+ {
+ ++col;
+ if (yanklen)
+ {
+ ++curwin->w_cursor.col;
+ ++curbuf->b_op_end.col;
+ }
+ }
+ }
+ curbuf->b_op_start = curwin->w_cursor;
+ }
+ /*
+ * Line mode: BACKWARD is the same as FORWARD on the previous line
+ */
+ else if (dir == BACKWARD)
+ --lnum;
+ new_cursor = curwin->w_cursor;
+
+ /*
+ * simple case: insert into current line
+ */
+ if (y_type == MCHAR && y_size == 1)
+ {
+ linenr_T end_lnum = 0; /* init for gcc */
+
+ if (VIsual_active)
+ {
+ end_lnum = curbuf->b_visual.vi_end.lnum;
+ if (end_lnum < curbuf->b_visual.vi_start.lnum)
+ end_lnum = curbuf->b_visual.vi_start.lnum;
+ }
+
+ do {
+ totlen = count * yanklen;
+ if (totlen > 0)
+ {
+ oldp = ml_get(lnum);
+ if (VIsual_active && col > (int)STRLEN(oldp))
+ {
+ lnum++;
+ continue;
+ }
+ newp = alloc_check((unsigned)(STRLEN(oldp) + totlen + 1));
+ if (newp == NULL)
+ goto end; /* alloc() gave an error message */
+ mch_memmove(newp, oldp, (size_t)col);
+ ptr = newp + col;
+ for (i = 0; i < count; ++i)
+ {
+ mch_memmove(ptr, y_array[0], (size_t)yanklen);
+ ptr += yanklen;
+ }
+ STRMOVE(ptr, oldp + col);
+ ml_replace(lnum, newp, FALSE);
+ /* Place cursor on last putted char. */
+ if (lnum == curwin->w_cursor.lnum)
+ {
+ /* make sure curwin->w_virtcol is updated */
+ changed_cline_bef_curs();
+ curwin->w_cursor.col += (colnr_T)(totlen - 1);
+ }
+ }
+ if (VIsual_active)
+ lnum++;
+ } while (VIsual_active && lnum <= end_lnum);
+
+ if (VIsual_active) /* reset lnum to the last visual line */
+ lnum--;
+
+ curbuf->b_op_end = curwin->w_cursor;
+ /* For "CTRL-O p" in Insert mode, put cursor after last char */
+ if (totlen && (restart_edit != 0 || (flags & PUT_CURSEND)))
+ ++curwin->w_cursor.col;
+ changed_bytes(lnum, col);
+ }
+ else
+ {
+ /*
+ * Insert at least one line. When y_type is MCHAR, break the first
+ * line in two.
+ */
+ for (cnt = 1; cnt <= count; ++cnt)
+ {
+ i = 0;
+ if (y_type == MCHAR)
+ {
+ /*
+ * Split the current line in two at the insert position.
+ * First insert y_array[size - 1] in front of second line.
+ * Then append y_array[0] to first line.
+ */
+ lnum = new_cursor.lnum;
+ ptr = ml_get(lnum) + col;
+ totlen = (int)STRLEN(y_array[y_size - 1]);
+ newp = alloc_check((unsigned)(STRLEN(ptr) + totlen + 1));
+ if (newp == NULL)
+ goto error;
+ STRCPY(newp, y_array[y_size - 1]);
+ STRCAT(newp, ptr);
+ /* insert second line */
+ ml_append(lnum, newp, (colnr_T)0, FALSE);
+ vim_free(newp);
+
+ oldp = ml_get(lnum);
+ newp = alloc_check((unsigned)(col + yanklen + 1));
+ if (newp == NULL)
+ goto error;
+ /* copy first part of line */
+ mch_memmove(newp, oldp, (size_t)col);
+ /* append to first line */
+ mch_memmove(newp + col, y_array[0], (size_t)(yanklen + 1));
+ ml_replace(lnum, newp, FALSE);
+
+ curwin->w_cursor.lnum = lnum;
+ i = 1;
+ }
+
+ for (; i < y_size; ++i)
+ {
+ if ((y_type != MCHAR || i < y_size - 1)
+ && ml_append(lnum, y_array[i], (colnr_T)0, FALSE)
+ == FAIL)
+ goto error;
+ lnum++;
+ ++nr_lines;
+ if (flags & PUT_FIXINDENT)
+ {
+ old_pos = curwin->w_cursor;
+ curwin->w_cursor.lnum = lnum;
+ ptr = ml_get(lnum);
+ if (cnt == count && i == y_size - 1)
+ lendiff = (int)STRLEN(ptr);
+#if defined(FEAT_SMARTINDENT) || defined(FEAT_CINDENT)
+ if (*ptr == '#' && preprocs_left())
+ indent = 0; /* Leave # lines at start */
+ else
+#endif
+ if (*ptr == NUL)
+ indent = 0; /* Ignore empty lines */
+ else if (first_indent)
+ {
+ indent_diff = orig_indent - get_indent();
+ indent = orig_indent;
+ first_indent = FALSE;
+ }
+ else if ((indent = get_indent() + indent_diff) < 0)
+ indent = 0;
+ (void)set_indent(indent, 0);
+ curwin->w_cursor = old_pos;
+ /* remember how many chars were removed */
+ if (cnt == count && i == y_size - 1)
+ lendiff -= (int)STRLEN(ml_get(lnum));
+ }
+ }
+ }
+
+error:
+ /* Adjust marks. */
+ if (y_type == MLINE)
+ {
+ curbuf->b_op_start.col = 0;
+ if (dir == FORWARD)
+ curbuf->b_op_start.lnum++;
+ }
+ /* Skip mark_adjust when adding lines after the last one, there
+ * can't be marks there. But still needed in diff mode. */
+ if (curbuf->b_op_start.lnum + (y_type == MCHAR) - 1 + nr_lines
+ < curbuf->b_ml.ml_line_count
+#ifdef FEAT_DIFF
+ || curwin->w_p_diff
+#endif
+ )
+ mark_adjust(curbuf->b_op_start.lnum + (y_type == MCHAR),
+ (linenr_T)MAXLNUM, nr_lines, 0L);
+
+ /* note changed text for displaying and folding */
+ if (y_type == MCHAR)
+ changed_lines(curwin->w_cursor.lnum, col,
+ curwin->w_cursor.lnum + 1, nr_lines);
+ else
+ changed_lines(curbuf->b_op_start.lnum, 0,
+ curbuf->b_op_start.lnum, nr_lines);
+
+ /* put '] mark at last inserted character */
+ curbuf->b_op_end.lnum = lnum;
+ /* correct length for change in indent */
+ col = (colnr_T)STRLEN(y_array[y_size - 1]) - lendiff;
+ if (col > 1)
+ curbuf->b_op_end.col = col - 1;
+ else
+ curbuf->b_op_end.col = 0;
+
+ if (flags & PUT_CURSLINE)
+ {
+ /* ":put": put cursor on last inserted line */
+ curwin->w_cursor.lnum = lnum;
+ beginline(BL_WHITE | BL_FIX);
+ }
+ else if (flags & PUT_CURSEND)
+ {
+ /* put cursor after inserted text */
+ if (y_type == MLINE)
+ {
+ if (lnum >= curbuf->b_ml.ml_line_count)
+ curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
+ else
+ curwin->w_cursor.lnum = lnum + 1;
+ curwin->w_cursor.col = 0;
+ }
+ else
+ {
+ curwin->w_cursor.lnum = lnum;
+ curwin->w_cursor.col = col;
+ }
+ }
+ else if (y_type == MLINE)
+ {
+ /* put cursor on first non-blank in first inserted line */
+ curwin->w_cursor.col = 0;
+ if (dir == FORWARD)
+ ++curwin->w_cursor.lnum;
+ beginline(BL_WHITE | BL_FIX);
+ }
+ else /* put cursor on first inserted character */
+ curwin->w_cursor = new_cursor;
+ }
+ }
+
+ msgmore(nr_lines);
+ curwin->w_set_curswant = TRUE;
+
+end:
+ if (allocated)
+ vim_free(insert_string);
+ if (regname == '=')
+ vim_free(y_array);
+
+ VIsual_active = FALSE;
+
+ /* If the cursor is past the end of the line put it at the end. */
+ adjust_cursor_eol();
+}
+
+/*
+ * When the cursor is on the NUL past the end of the line and it should not be
+ * there move it left.
+ */
+ void
+adjust_cursor_eol(void)
+{
+ if (curwin->w_cursor.col > 0
+ && gchar_cursor() == NUL
+ && (ve_flags & VE_ONEMORE) == 0
+ && !(restart_edit || (State & INSERT)))
+ {
+ /* Put the cursor on the last character in the line. */
+ dec_cursor();
+
+ if (ve_flags == VE_ALL)
+ {
+ colnr_T scol, ecol;
+
+ /* Coladd is set to the width of the last character. */
+ getvcol(curwin, &curwin->w_cursor, &scol, NULL, &ecol);
+ curwin->w_cursor.coladd = ecol - scol + 1;
+ }
+ }
+}
+
+#if defined(FEAT_SMARTINDENT) || defined(FEAT_CINDENT) || defined(PROTO)
+/*
+ * Return TRUE if lines starting with '#' should be left aligned.
+ */
+ int
+preprocs_left(void)
+{
+ return
+# ifdef FEAT_SMARTINDENT
+# ifdef FEAT_CINDENT
+ (curbuf->b_p_si && !curbuf->b_p_cin) ||
+# else
+ curbuf->b_p_si
+# endif
+# endif
+# ifdef FEAT_CINDENT
+ (curbuf->b_p_cin && in_cinkeys('#', ' ', TRUE)
+ && curbuf->b_ind_hash_comment == 0)
+# endif
+ ;
+}
+#endif
+
+/*
+ * Return the character name of the register with the given number.
+ */
+ int
+get_register_name(int num)
+{
+ if (num == -1)
+ return '"';
+ else if (num < 10)
+ return num + '0';
+ else if (num == DELETION_REGISTER)
+ return '-';
+#ifdef FEAT_CLIPBOARD
+ else if (num == STAR_REGISTER)
+ return '*';
+ else if (num == PLUS_REGISTER)
+ return '+';
+#endif
+ else
+ {
+#ifdef EBCDIC
+ int i;
+
+ /* EBCDIC is really braindead ... */
+ i = 'a' + (num - 10);
+ if (i > 'i')
+ i += 7;
+ if (i > 'r')
+ i += 8;
+ return i;
+#else
+ return num + 'a' - 10;
+#endif
+ }
+}
+
+/*
+ * ":dis" and ":registers": Display the contents of the yank registers.
+ */
+ void
+ex_display(exarg_T *eap)
+{
+ int i, n;
+ long j;
+ char_u *p;
+ yankreg_T *yb;
+ int name;
+ int attr;
+ char_u *arg = eap->arg;
+ int clen;
+
+ if (arg != NULL && *arg == NUL)
+ arg = NULL;
+ attr = HL_ATTR(HLF_8);
+
+ /* Highlight title */
+ msg_puts_title(_("\n--- Registers ---"));
+ for (i = -1; i < NUM_REGISTERS && !got_int; ++i)
+ {
+ name = get_register_name(i);
+ if (arg != NULL && vim_strchr(arg, name) == NULL
+#ifdef ONE_CLIPBOARD
+ /* Star register and plus register contain the same thing. */
+ && (name != '*' || vim_strchr(arg, '+') == NULL)
+#endif
+ )
+ continue; /* did not ask for this register */
+
+#ifdef FEAT_CLIPBOARD
+ /* Adjust register name for "unnamed" in 'clipboard'.
+ * When it's a clipboard register, fill it with the current contents
+ * of the clipboard. */
+ adjust_clip_reg(&name);
+ (void)may_get_selection(name);
+#endif
+
+ if (i == -1)
+ {
+ if (y_previous != NULL)
+ yb = y_previous;
+ else
+ yb = &(y_regs[0]);
+ }
+ else
+ yb = &(y_regs[i]);
+
+#ifdef FEAT_EVAL
+ if (name == MB_TOLOWER(redir_reg)
+ || (redir_reg == '"' && yb == y_previous))
+ continue; /* do not list register being written to, the
+ * pointer can be freed */
+#endif
+
+ if (yb->y_array != NULL)
+ {
+ msg_putchar('\n');
+ msg_putchar('"');
+ msg_putchar(name);
+ msg_puts(" ");
+
+ n = (int)Columns - 6;
+ for (j = 0; j < yb->y_size && n > 1; ++j)
+ {
+ if (j)
+ {
+ msg_puts_attr("^J", attr);
+ n -= 2;
+ }
+ for (p = yb->y_array[j]; *p && (n -= ptr2cells(p)) >= 0; ++p)
+ {
+ clen = (*mb_ptr2len)(p);
+ msg_outtrans_len(p, clen);
+ p += clen - 1;
+ }
+ }
+ if (n > 1 && yb->y_type == MLINE)
+ msg_puts_attr("^J", attr);
+ out_flush(); /* show one line at a time */
+ }
+ ui_breakcheck();
+ }
+
+ /*
+ * display last inserted text
+ */
+ if ((p = get_last_insert()) != NULL
+ && (arg == NULL || vim_strchr(arg, '.') != NULL) && !got_int)
+ {
+ msg_puts("\n\". ");
+ dis_msg(p, TRUE);
+ }
+
+ /*
+ * display last command line
+ */
+ if (last_cmdline != NULL && (arg == NULL || vim_strchr(arg, ':') != NULL)
+ && !got_int)
+ {
+ msg_puts("\n\": ");
+ dis_msg(last_cmdline, FALSE);
+ }
+
+ /*
+ * display current file name
+ */
+ if (curbuf->b_fname != NULL
+ && (arg == NULL || vim_strchr(arg, '%') != NULL) && !got_int)
+ {
+ msg_puts("\n\"% ");
+ dis_msg(curbuf->b_fname, FALSE);
+ }
+
+ /*
+ * display alternate file name
+ */
+ if ((arg == NULL || vim_strchr(arg, '%') != NULL) && !got_int)
+ {
+ char_u *fname;
+ linenr_T dummy;
+
+ if (buflist_name_nr(0, &fname, &dummy) != FAIL)
+ {
+ msg_puts("\n\"# ");
+ dis_msg(fname, FALSE);
+ }
+ }
+
+ /*
+ * display last search pattern
+ */
+ if (last_search_pat() != NULL
+ && (arg == NULL || vim_strchr(arg, '/') != NULL) && !got_int)
+ {
+ msg_puts("\n\"/ ");
+ dis_msg(last_search_pat(), FALSE);
+ }
+
+#ifdef FEAT_EVAL
+ /*
+ * display last used expression
+ */
+ if (expr_line != NULL && (arg == NULL || vim_strchr(arg, '=') != NULL)
+ && !got_int)
+ {
+ msg_puts("\n\"= ");
+ dis_msg(expr_line, FALSE);
+ }
+#endif
+}
+
+/*
+ * display a string for do_dis()
+ * truncate at end of screen line
+ */
+ static void
+dis_msg(
+ char_u *p,
+ int skip_esc) /* if TRUE, ignore trailing ESC */
+{
+ int n;
+ int l;
+
+ n = (int)Columns - 6;
+ while (*p != NUL
+ && !(*p == ESC && skip_esc && *(p + 1) == NUL)
+ && (n -= ptr2cells(p)) >= 0)
+ {
+ if (has_mbyte && (l = (*mb_ptr2len)(p)) > 1)
+ {
+ msg_outtrans_len(p, l);
+ p += l;
+ }
+ else
+ msg_outtrans_len(p++, 1);
+ }
+ ui_breakcheck();
+}
+
+#if defined(FEAT_COMMENTS) || defined(PROTO)
+/*
+ * If "process" is TRUE and the line begins with a comment leader (possibly
+ * after some white space), return a pointer to the text after it. Put a boolean
+ * value indicating whether the line ends with an unclosed comment in
+ * "is_comment".
+ * line - line to be processed,
+ * process - if FALSE, will only check whether the line ends with an unclosed
+ * comment,
+ * include_space - whether to also skip space following the comment leader,
+ * is_comment - will indicate whether the current line ends with an unclosed
+ * comment.
+ */
+ char_u *
+skip_comment(
+ char_u *line,
+ int process,
+ int include_space,
+ int *is_comment)
+{
+ char_u *comment_flags = NULL;
+ int lead_len;
+ int leader_offset = get_last_leader_offset(line, &comment_flags);
+
+ *is_comment = FALSE;
+ if (leader_offset != -1)
+ {
+ /* Let's check whether the line ends with an unclosed comment.
+ * If the last comment leader has COM_END in flags, there's no comment.
+ */
+ while (*comment_flags)
+ {
+ if (*comment_flags == COM_END
+ || *comment_flags == ':')
+ break;
+ ++comment_flags;
+ }
+ if (*comment_flags != COM_END)
+ *is_comment = TRUE;
+ }
+
+ if (process == FALSE)
+ return line;
+
+ lead_len = get_leader_len(line, &comment_flags, FALSE, include_space);
+
+ if (lead_len == 0)
+ return line;
+
+ /* Find:
+ * - COM_END,
+ * - colon,
+ * whichever comes first.
+ */
+ while (*comment_flags)
+ {
+ if (*comment_flags == COM_END
+ || *comment_flags == ':')
+ {
+ break;
+ }
+ ++comment_flags;
+ }
+
+ /* If we found a colon, it means that we are not processing a line
+ * starting with a closing part of a three-part comment. That's good,
+ * because we don't want to remove those as this would be annoying.
+ */
+ if (*comment_flags == ':' || *comment_flags == NUL)
+ line += lead_len;
+
+ return line;
+}
+#endif
+
+/*
+ * Join 'count' lines (minimal 2) at cursor position.
+ * When "save_undo" is TRUE save lines for undo first.
+ * Set "use_formatoptions" to FALSE when e.g. processing backspace and comment
+ * leaders should not be removed.
+ * When setmark is TRUE, sets the '[ and '] mark, else, the caller is expected
+ * to set those marks.
+ *
+ * return FAIL for failure, OK otherwise
+ */
+ int
+do_join(
+ long count,
+ int insert_space,
+ int save_undo,
+ int use_formatoptions UNUSED,
+ int setmark)
+{
+ char_u *curr = NULL;
+ char_u *curr_start = NULL;
+ char_u *cend;
+ char_u *newp;
+ char_u *spaces; /* number of spaces inserted before a line */
+ int endcurr1 = NUL;
+ int endcurr2 = NUL;
+ int currsize = 0; /* size of the current line */
+ int sumsize = 0; /* size of the long new line */
+ linenr_T t;
+ colnr_T col = 0;
+ int ret = OK;
+#if defined(FEAT_COMMENTS) || defined(PROTO)
+ int *comments = NULL;
+ int remove_comments = (use_formatoptions == TRUE)
+ && has_format_option(FO_REMOVE_COMS);
+ int prev_was_comment;
+#endif
+
+
+ if (save_undo && u_save((linenr_T)(curwin->w_cursor.lnum - 1),
+ (linenr_T)(curwin->w_cursor.lnum + count)) == FAIL)
+ return FAIL;
+
+ /* Allocate an array to store the number of spaces inserted before each
+ * line. We will use it to pre-compute the length of the new line and the
+ * proper placement of each original line in the new one. */
+ spaces = lalloc_clear((long_u)count, TRUE);
+ if (spaces == NULL)
+ return FAIL;
+#if defined(FEAT_COMMENTS) || defined(PROTO)
+ if (remove_comments)
+ {
+ comments = (int *)lalloc_clear((long_u)count * sizeof(int), TRUE);
+ if (comments == NULL)
+ {
+ vim_free(spaces);
+ return FAIL;
+ }
+ }
+#endif
+
+ /*
+ * Don't move anything, just compute the final line length
+ * and setup the array of space strings lengths
+ */
+ for (t = 0; t < count; ++t)
+ {
+ curr = curr_start = ml_get((linenr_T)(curwin->w_cursor.lnum + t));
+ if (t == 0 && setmark)
+ {
+ /* Set the '[ mark. */
+ curwin->w_buffer->b_op_start.lnum = curwin->w_cursor.lnum;
+ curwin->w_buffer->b_op_start.col = (colnr_T)STRLEN(curr);
+ }
+#if defined(FEAT_COMMENTS) || defined(PROTO)
+ if (remove_comments)
+ {
+ /* We don't want to remove the comment leader if the
+ * previous line is not a comment. */
+ if (t > 0 && prev_was_comment)
+ {
+
+ char_u *new_curr = skip_comment(curr, TRUE, insert_space,
+ &prev_was_comment);
+ comments[t] = (int)(new_curr - curr);
+ curr = new_curr;
+ }
+ else
+ curr = skip_comment(curr, FALSE, insert_space,
+ &prev_was_comment);
+ }
+#endif
+
+ if (insert_space && t > 0)
+ {
+ curr = skipwhite(curr);
+ if (*curr != ')' && currsize != 0 && endcurr1 != TAB
+ && (!has_format_option(FO_MBYTE_JOIN)
+ || (mb_ptr2char(curr) < 0x100 && endcurr1 < 0x100))
+ && (!has_format_option(FO_MBYTE_JOIN2)
+ || mb_ptr2char(curr) < 0x100 || endcurr1 < 0x100)
+ )
+ {
+ /* don't add a space if the line is ending in a space */
+ if (endcurr1 == ' ')
+ endcurr1 = endcurr2;
+ else
+ ++spaces[t];
+ /* extra space when 'joinspaces' set and line ends in '.' */
+ if ( p_js
+ && (endcurr1 == '.'
+ || (vim_strchr(p_cpo, CPO_JOINSP) == NULL
+ && (endcurr1 == '?' || endcurr1 == '!'))))
+ ++spaces[t];
+ }
+ }
+ currsize = (int)STRLEN(curr);
+ sumsize += currsize + spaces[t];
+ endcurr1 = endcurr2 = NUL;
+ if (insert_space && currsize > 0)
+ {
+ if (has_mbyte)
+ {
+ cend = curr + currsize;
+ MB_PTR_BACK(curr, cend);
+ endcurr1 = (*mb_ptr2char)(cend);
+ if (cend > curr)
+ {
+ MB_PTR_BACK(curr, cend);
+ endcurr2 = (*mb_ptr2char)(cend);
+ }
+ }
+ else
+ {
+ endcurr1 = *(curr + currsize - 1);
+ if (currsize > 1)
+ endcurr2 = *(curr + currsize - 2);
+ }
+ }
+ line_breakcheck();
+ if (got_int)
+ {
+ ret = FAIL;
+ goto theend;
+ }
+ }
+
+ /* store the column position before last line */
+ col = sumsize - currsize - spaces[count - 1];
+
+ /* allocate the space for the new line */
+ newp = alloc_check((unsigned)(sumsize + 1));
+ cend = newp + sumsize;
+ *cend = 0;
+
+ /*
+ * Move affected lines to the new long one.
+ *
+ * Move marks from each deleted line to the joined line, adjusting the
+ * column. This is not Vi compatible, but Vi deletes the marks, thus that
+ * should not really be a problem.
+ */
+ for (t = count - 1; ; --t)
+ {
+ int spaces_removed;
+
+ cend -= currsize;
+ mch_memmove(cend, curr, (size_t)currsize);
+ if (spaces[t] > 0)
+ {
+ cend -= spaces[t];
+ vim_memset(cend, ' ', (size_t)(spaces[t]));
+ }
+
+ // If deleting more spaces than adding, the cursor moves no more than
+ // what is added if it is inside these spaces.
+ spaces_removed = (curr - curr_start) - spaces[t];
+
+ mark_col_adjust(curwin->w_cursor.lnum + t, (colnr_T)0, (linenr_T)-t,
+ (long)(cend - newp - spaces_removed), spaces_removed);
+ if (t == 0)
+ break;
+ curr = curr_start = ml_get((linenr_T)(curwin->w_cursor.lnum + t - 1));
+#if defined(FEAT_COMMENTS) || defined(PROTO)
+ if (remove_comments)
+ curr += comments[t - 1];
+#endif
+ if (insert_space && t > 1)
+ curr = skipwhite(curr);
+ currsize = (int)STRLEN(curr);
+ }
+ ml_replace(curwin->w_cursor.lnum, newp, FALSE);
+
+ if (setmark)
+ {
+ /* Set the '] mark. */
+ curwin->w_buffer->b_op_end.lnum = curwin->w_cursor.lnum;
+ curwin->w_buffer->b_op_end.col = (colnr_T)STRLEN(newp);
+ }
+
+ /* Only report the change in the first line here, del_lines() will report
+ * the deleted line. */
+ changed_lines(curwin->w_cursor.lnum, currsize,
+ curwin->w_cursor.lnum + 1, 0L);
+
+ /*
+ * Delete following lines. To do this we move the cursor there
+ * briefly, and then move it back. After del_lines() the cursor may
+ * have moved up (last line deleted), so the current lnum is kept in t.
+ */
+ t = curwin->w_cursor.lnum;
+ ++curwin->w_cursor.lnum;
+ del_lines(count - 1, FALSE);
+ curwin->w_cursor.lnum = t;
+
+ /*
+ * Set the cursor column:
+ * Vi compatible: use the column of the first join
+ * vim: use the column of the last join
+ */
+ curwin->w_cursor.col =
+ (vim_strchr(p_cpo, CPO_JOINCOL) != NULL ? currsize : col);
+ check_cursor_col();
+
+ curwin->w_cursor.coladd = 0;
+ curwin->w_set_curswant = TRUE;
+
+theend:
+ vim_free(spaces);
+#if defined(FEAT_COMMENTS) || defined(PROTO)
+ if (remove_comments)
+ vim_free(comments);
+#endif
+ return ret;
+}
+
+#ifdef FEAT_COMMENTS
+/*
+ * Return TRUE if the two comment leaders given are the same. "lnum" is
+ * the first line. White-space is ignored. Note that the whole of
+ * 'leader1' must match 'leader2_len' characters from 'leader2' -- webb
+ */
+ static int
+same_leader(
+ linenr_T lnum,
+ int leader1_len,
+ char_u *leader1_flags,
+ int leader2_len,
+ char_u *leader2_flags)
+{
+ int idx1 = 0, idx2 = 0;
+ char_u *p;
+ char_u *line1;
+ char_u *line2;
+
+ if (leader1_len == 0)
+ return (leader2_len == 0);
+
+ /*
+ * If first leader has 'f' flag, the lines can be joined only if the
+ * second line does not have a leader.
+ * If first leader has 'e' flag, the lines can never be joined.
+ * If fist leader has 's' flag, the lines can only be joined if there is
+ * some text after it and the second line has the 'm' flag.
+ */
+ if (leader1_flags != NULL)
+ {
+ for (p = leader1_flags; *p && *p != ':'; ++p)
+ {
+ if (*p == COM_FIRST)
+ return (leader2_len == 0);
+ if (*p == COM_END)
+ return FALSE;
+ if (*p == COM_START)
+ {
+ if (*(ml_get(lnum) + leader1_len) == NUL)
+ return FALSE;
+ if (leader2_flags == NULL || leader2_len == 0)
+ return FALSE;
+ for (p = leader2_flags; *p && *p != ':'; ++p)
+ if (*p == COM_MIDDLE)
+ return TRUE;
+ return FALSE;
+ }
+ }
+ }
+
+ /*
+ * Get current line and next line, compare the leaders.
+ * The first line has to be saved, only one line can be locked at a time.
+ */
+ line1 = vim_strsave(ml_get(lnum));
+ if (line1 != NULL)
+ {
+ for (idx1 = 0; VIM_ISWHITE(line1[idx1]); ++idx1)
+ ;
+ line2 = ml_get(lnum + 1);
+ for (idx2 = 0; idx2 < leader2_len; ++idx2)
+ {
+ if (!VIM_ISWHITE(line2[idx2]))
+ {
+ if (line1[idx1++] != line2[idx2])
+ break;
+ }
+ else
+ while (VIM_ISWHITE(line1[idx1]))
+ ++idx1;
+ }
+ vim_free(line1);
+ }
+ return (idx2 == leader2_len && idx1 == leader1_len);
+}
+#endif
+
+/*
+ * Implementation of the format operator 'gq'.
+ */
+ void
+op_format(
+ oparg_T *oap,
+ int keep_cursor) /* keep cursor on same text char */
+{
+ long old_line_count = curbuf->b_ml.ml_line_count;
+
+ /* Place the cursor where the "gq" or "gw" command was given, so that "u"
+ * can put it back there. */
+ curwin->w_cursor = oap->cursor_start;
+
+ if (u_save((linenr_T)(oap->start.lnum - 1),
+ (linenr_T)(oap->end.lnum + 1)) == FAIL)
+ return;
+ curwin->w_cursor = oap->start;
+
+ if (oap->is_VIsual)
+ /* When there is no change: need to remove the Visual selection */
+ redraw_curbuf_later(INVERTED);
+
+ /* Set '[ mark at the start of the formatted area */
+ curbuf->b_op_start = oap->start;
+
+ /* For "gw" remember the cursor position and put it back below (adjusted
+ * for joined and split lines). */
+ if (keep_cursor)
+ saved_cursor = oap->cursor_start;
+
+ format_lines(oap->line_count, keep_cursor);
+
+ /*
+ * Leave the cursor at the first non-blank of the last formatted line.
+ * If the cursor was moved one line back (e.g. with "Q}") go to the next
+ * line, so "." will do the next lines.
+ */
+ if (oap->end_adjusted && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
+ ++curwin->w_cursor.lnum;
+ beginline(BL_WHITE | BL_FIX);
+ old_line_count = curbuf->b_ml.ml_line_count - old_line_count;
+ msgmore(old_line_count);
+
+ /* put '] mark on the end of the formatted area */
+ curbuf->b_op_end = curwin->w_cursor;
+
+ if (keep_cursor)
+ {
+ curwin->w_cursor = saved_cursor;
+ saved_cursor.lnum = 0;
+ }
+
+ if (oap->is_VIsual)
+ {
+ win_T *wp;
+
+ FOR_ALL_WINDOWS(wp)
+ {
+ if (wp->w_old_cursor_lnum != 0)
+ {
+ /* When lines have been inserted or deleted, adjust the end of
+ * the Visual area to be redrawn. */
+ if (wp->w_old_cursor_lnum > wp->w_old_visual_lnum)
+ wp->w_old_cursor_lnum += old_line_count;
+ else
+ wp->w_old_visual_lnum += old_line_count;
+ }
+ }
+ }
+}
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * Implementation of the format operator 'gq' for when using 'formatexpr'.
+ */
+ void
+op_formatexpr(oparg_T *oap)
+{
+ if (oap->is_VIsual)
+ /* When there is no change: need to remove the Visual selection */
+ redraw_curbuf_later(INVERTED);
+
+ if (fex_format(oap->start.lnum, oap->line_count, NUL) != 0)
+ /* As documented: when 'formatexpr' returns non-zero fall back to
+ * internal formatting. */
+ op_format(oap, FALSE);
+}
+
+ int
+fex_format(
+ linenr_T lnum,
+ long count,
+ int c) /* character to be inserted */
+{
+ int use_sandbox = was_set_insecurely((char_u *)"formatexpr",
+ OPT_LOCAL);
+ int r;
+ char_u *fex;
+
+ /*
+ * Set v:lnum to the first line number and v:count to the number of lines.
+ * Set v:char to the character to be inserted (can be NUL).
+ */
+ set_vim_var_nr(VV_LNUM, lnum);
+ set_vim_var_nr(VV_COUNT, count);
+ set_vim_var_char(c);
+
+ /* Make a copy, the option could be changed while calling it. */
+ fex = vim_strsave(curbuf->b_p_fex);
+ if (fex == NULL)
+ return 0;
+
+ /*
+ * Evaluate the function.
+ */
+ if (use_sandbox)
+ ++sandbox;
+ r = (int)eval_to_number(fex);
+ if (use_sandbox)
+ --sandbox;
+
+ set_vim_var_string(VV_CHAR, NULL, -1);
+ vim_free(fex);
+
+ return r;
+}
+#endif
+
+/*
+ * Format "line_count" lines, starting at the cursor position.
+ * When "line_count" is negative, format until the end of the paragraph.
+ * Lines after the cursor line are saved for undo, caller must have saved the
+ * first line.
+ */
+ void
+format_lines(
+ linenr_T line_count,
+ int avoid_fex) /* don't use 'formatexpr' */
+{
+ int max_len;
+ int is_not_par; /* current line not part of parag. */
+ int next_is_not_par; /* next line not part of paragraph */
+ int is_end_par; /* at end of paragraph */
+ int prev_is_end_par = FALSE;/* prev. line not part of parag. */
+ int next_is_start_par = FALSE;
+#ifdef FEAT_COMMENTS
+ int leader_len = 0; /* leader len of current line */
+ int next_leader_len; /* leader len of next line */
+ char_u *leader_flags = NULL; /* flags for leader of current line */
+ char_u *next_leader_flags; /* flags for leader of next line */
+ int do_comments; /* format comments */
+ int do_comments_list = 0; /* format comments with 'n' or '2' */
+#endif
+ int advance = TRUE;
+ int second_indent = -1; /* indent for second line (comment
+ * aware) */
+ int do_second_indent;
+ int do_number_indent;
+ int do_trail_white;
+ int first_par_line = TRUE;
+ int smd_save;
+ long count;
+ int need_set_indent = TRUE; /* set indent of next paragraph */
+ int force_format = FALSE;
+ int old_State = State;
+
+ /* length of a line to force formatting: 3 * 'tw' */
+ max_len = comp_textwidth(TRUE) * 3;
+
+ /* check for 'q', '2' and '1' in 'formatoptions' */
+#ifdef FEAT_COMMENTS
+ do_comments = has_format_option(FO_Q_COMS);
+#endif
+ do_second_indent = has_format_option(FO_Q_SECOND);
+ do_number_indent = has_format_option(FO_Q_NUMBER);
+ do_trail_white = has_format_option(FO_WHITE_PAR);
+
+ /*
+ * Get info about the previous and current line.
+ */
+ if (curwin->w_cursor.lnum > 1)
+ is_not_par = fmt_check_par(curwin->w_cursor.lnum - 1
+#ifdef FEAT_COMMENTS
+ , &leader_len, &leader_flags, do_comments
+#endif
+ );
+ else
+ is_not_par = TRUE;
+ next_is_not_par = fmt_check_par(curwin->w_cursor.lnum
+#ifdef FEAT_COMMENTS
+ , &next_leader_len, &next_leader_flags, do_comments
+#endif
+ );
+ is_end_par = (is_not_par || next_is_not_par);
+ if (!is_end_par && do_trail_white)
+ is_end_par = !ends_in_white(curwin->w_cursor.lnum - 1);
+
+ curwin->w_cursor.lnum--;
+ for (count = line_count; count != 0 && !got_int; --count)
+ {
+ /*
+ * Advance to next paragraph.
+ */
+ if (advance)
+ {
+ curwin->w_cursor.lnum++;
+ prev_is_end_par = is_end_par;
+ is_not_par = next_is_not_par;
+#ifdef FEAT_COMMENTS
+ leader_len = next_leader_len;
+ leader_flags = next_leader_flags;
+#endif
+ }
+
+ /*
+ * The last line to be formatted.
+ */
+ if (count == 1 || curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count)
+ {
+ next_is_not_par = TRUE;
+#ifdef FEAT_COMMENTS
+ next_leader_len = 0;
+ next_leader_flags = NULL;
+#endif
+ }
+ else
+ {
+ next_is_not_par = fmt_check_par(curwin->w_cursor.lnum + 1
+#ifdef FEAT_COMMENTS
+ , &next_leader_len, &next_leader_flags, do_comments
+#endif
+ );
+ if (do_number_indent)
+ next_is_start_par =
+ (get_number_indent(curwin->w_cursor.lnum + 1) > 0);
+ }
+ advance = TRUE;
+ is_end_par = (is_not_par || next_is_not_par || next_is_start_par);
+ if (!is_end_par && do_trail_white)
+ is_end_par = !ends_in_white(curwin->w_cursor.lnum);
+
+ /*
+ * Skip lines that are not in a paragraph.
+ */
+ if (is_not_par)
+ {
+ if (line_count < 0)
+ break;
+ }
+ else
+ {
+ /*
+ * For the first line of a paragraph, check indent of second line.
+ * Don't do this for comments and empty lines.
+ */
+ if (first_par_line
+ && (do_second_indent || do_number_indent)
+ && prev_is_end_par
+ && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
+ {
+ if (do_second_indent && !LINEEMPTY(curwin->w_cursor.lnum + 1))
+ {
+#ifdef FEAT_COMMENTS
+ if (leader_len == 0 && next_leader_len == 0)
+ {
+ /* no comment found */
+#endif
+ second_indent =
+ get_indent_lnum(curwin->w_cursor.lnum + 1);
+#ifdef FEAT_COMMENTS
+ }
+ else
+ {
+ second_indent = next_leader_len;
+ do_comments_list = 1;
+ }
+#endif
+ }
+ else if (do_number_indent)
+ {
+#ifdef FEAT_COMMENTS
+ if (leader_len == 0 && next_leader_len == 0)
+ {
+ /* no comment found */
+#endif
+ second_indent =
+ get_number_indent(curwin->w_cursor.lnum);
+#ifdef FEAT_COMMENTS
+ }
+ else
+ {
+ /* get_number_indent() is now "comment aware"... */
+ second_indent =
+ get_number_indent(curwin->w_cursor.lnum);
+ do_comments_list = 1;
+ }
+#endif
+ }
+ }
+
+ /*
+ * When the comment leader changes, it's the end of the paragraph.
+ */
+ if (curwin->w_cursor.lnum >= curbuf->b_ml.ml_line_count
+#ifdef FEAT_COMMENTS
+ || !same_leader(curwin->w_cursor.lnum,
+ leader_len, leader_flags,
+ next_leader_len, next_leader_flags)
+#endif
+ )
+ is_end_par = TRUE;
+
+ /*
+ * If we have got to the end of a paragraph, or the line is
+ * getting long, format it.
+ */
+ if (is_end_par || force_format)
+ {
+ if (need_set_indent)
+ /* replace indent in first line with minimal number of
+ * tabs and spaces, according to current options */
+ (void)set_indent(get_indent(), SIN_CHANGED);
+
+ /* put cursor on last non-space */
+ State = NORMAL; /* don't go past end-of-line */
+ coladvance((colnr_T)MAXCOL);
+ while (curwin->w_cursor.col && vim_isspace(gchar_cursor()))
+ dec_cursor();
+
+ /* do the formatting, without 'showmode' */
+ State = INSERT; /* for open_line() */
+ smd_save = p_smd;
+ p_smd = FALSE;
+ insertchar(NUL, INSCHAR_FORMAT
+#ifdef FEAT_COMMENTS
+ + (do_comments ? INSCHAR_DO_COM : 0)
+ + (do_comments && do_comments_list
+ ? INSCHAR_COM_LIST : 0)
+#endif
+ + (avoid_fex ? INSCHAR_NO_FEX : 0), second_indent);
+ State = old_State;
+ p_smd = smd_save;
+ second_indent = -1;
+ /* at end of par.: need to set indent of next par. */
+ need_set_indent = is_end_par;
+ if (is_end_par)
+ {
+ /* When called with a negative line count, break at the
+ * end of the paragraph. */
+ if (line_count < 0)
+ break;
+ first_par_line = TRUE;
+ }
+ force_format = FALSE;
+ }
+
+ /*
+ * When still in same paragraph, join the lines together. But
+ * first delete the leader from the second line.
+ */
+ if (!is_end_par)
+ {
+ advance = FALSE;
+ curwin->w_cursor.lnum++;
+ curwin->w_cursor.col = 0;
+ if (line_count < 0 && u_save_cursor() == FAIL)
+ break;
+#ifdef FEAT_COMMENTS
+ if (next_leader_len > 0)
+ {
+ (void)del_bytes((long)next_leader_len, FALSE, FALSE);
+ mark_col_adjust(curwin->w_cursor.lnum, (colnr_T)0, 0L,
+ (long)-next_leader_len, 0);
+ } else
+#endif
+ if (second_indent > 0) /* the "leader" for FO_Q_SECOND */
+ {
+ int indent = getwhitecols_curline();
+
+ if (indent > 0)
+ {
+ (void)del_bytes(indent, FALSE, FALSE);
+ mark_col_adjust(curwin->w_cursor.lnum,
+ (colnr_T)0, 0L, (long)-indent, 0);
+ }
+ }
+ curwin->w_cursor.lnum--;
+ if (do_join(2, TRUE, FALSE, FALSE, FALSE) == FAIL)
+ {
+ beep_flush();
+ break;
+ }
+ first_par_line = FALSE;
+ /* If the line is getting long, format it next time */
+ if (STRLEN(ml_get_curline()) > (size_t)max_len)
+ force_format = TRUE;
+ else
+ force_format = FALSE;
+ }
+ }
+ line_breakcheck();
+ }
+}
+
+/*
+ * Return TRUE if line "lnum" ends in a white character.
+ */
+ static int
+ends_in_white(linenr_T lnum)
+{
+ char_u *s = ml_get(lnum);
+ size_t l;
+
+ if (*s == NUL)
+ return FALSE;
+ /* Don't use STRLEN() inside VIM_ISWHITE(), SAS/C complains: "macro
+ * invocation may call function multiple times". */
+ l = STRLEN(s) - 1;
+ return VIM_ISWHITE(s[l]);
+}
+
+/*
+ * Blank lines, and lines containing only the comment leader, are left
+ * untouched by the formatting. The function returns TRUE in this
+ * case. It also returns TRUE when a line starts with the end of a comment
+ * ('e' in comment flags), so that this line is skipped, and not joined to the
+ * previous line. A new paragraph starts after a blank line, or when the
+ * comment leader changes -- webb.
+ */
+#ifdef FEAT_COMMENTS
+ static int
+fmt_check_par(
+ linenr_T lnum,
+ int *leader_len,
+ char_u **leader_flags,
+ int do_comments)
+{
+ char_u *flags = NULL; /* init for GCC */
+ char_u *ptr;
+
+ ptr = ml_get(lnum);
+ if (do_comments)
+ *leader_len = get_leader_len(ptr, leader_flags, FALSE, TRUE);
+ else
+ *leader_len = 0;
+
+ if (*leader_len > 0)
+ {
+ /*
+ * Search for 'e' flag in comment leader flags.
+ */
+ flags = *leader_flags;
+ while (*flags && *flags != ':' && *flags != COM_END)
+ ++flags;
+ }
+
+ return (*skipwhite(ptr + *leader_len) == NUL
+ || (*leader_len > 0 && *flags == COM_END)
+ || startPS(lnum, NUL, FALSE));
+}
+#else
+ static int
+fmt_check_par(linenr_T lnum)
+{
+ return (*skipwhite(ml_get(lnum)) == NUL || startPS(lnum, NUL, FALSE));
+}
+#endif
+
+/*
+ * Return TRUE when a paragraph starts in line "lnum". Return FALSE when the
+ * previous line is in the same paragraph. Used for auto-formatting.
+ */
+ int
+paragraph_start(linenr_T lnum)
+{
+ char_u *p;
+#ifdef FEAT_COMMENTS
+ int leader_len = 0; /* leader len of current line */
+ char_u *leader_flags = NULL; /* flags for leader of current line */
+ int next_leader_len; /* leader len of next line */
+ char_u *next_leader_flags; /* flags for leader of next line */
+ int do_comments; /* format comments */
+#endif
+
+ if (lnum <= 1)
+ return TRUE; /* start of the file */
+
+ p = ml_get(lnum - 1);
+ if (*p == NUL)
+ return TRUE; /* after empty line */
+
+#ifdef FEAT_COMMENTS
+ do_comments = has_format_option(FO_Q_COMS);
+#endif
+ if (fmt_check_par(lnum - 1
+#ifdef FEAT_COMMENTS
+ , &leader_len, &leader_flags, do_comments
+#endif
+ ))
+ return TRUE; /* after non-paragraph line */
+
+ if (fmt_check_par(lnum
+#ifdef FEAT_COMMENTS
+ , &next_leader_len, &next_leader_flags, do_comments
+#endif
+ ))
+ return TRUE; /* "lnum" is not a paragraph line */
+
+ if (has_format_option(FO_WHITE_PAR) && !ends_in_white(lnum - 1))
+ return TRUE; /* missing trailing space in previous line. */
+
+ if (has_format_option(FO_Q_NUMBER) && (get_number_indent(lnum) > 0))
+ return TRUE; /* numbered item starts in "lnum". */
+
+#ifdef FEAT_COMMENTS
+ if (!same_leader(lnum - 1, leader_len, leader_flags,
+ next_leader_len, next_leader_flags))
+ return TRUE; /* change of comment leader. */
+#endif
+
+ return FALSE;
+}
+
+/*
+ * prepare a few things for block mode yank/delete/tilde
+ *
+ * for delete:
+ * - textlen includes the first/last char to be (partly) deleted
+ * - start/endspaces is the number of columns that are taken by the
+ * first/last deleted char minus the number of columns that have to be
+ * deleted.
+ * for yank and tilde:
+ * - textlen includes the first/last char to be wholly yanked
+ * - start/endspaces is the number of columns of the first/last yanked char
+ * that are to be yanked.
+ */
+ static void
+block_prep(
+ oparg_T *oap,
+ struct block_def *bdp,
+ linenr_T lnum,
+ int is_del)
+{
+ int incr = 0;
+ char_u *pend;
+ char_u *pstart;
+ char_u *line;
+ char_u *prev_pstart;
+ char_u *prev_pend;
+
+ bdp->startspaces = 0;
+ bdp->endspaces = 0;
+ bdp->textlen = 0;
+ bdp->start_vcol = 0;
+ bdp->end_vcol = 0;
+ bdp->is_short = FALSE;
+ bdp->is_oneChar = FALSE;
+ bdp->pre_whitesp = 0;
+ bdp->pre_whitesp_c = 0;
+ bdp->end_char_vcols = 0;
+ bdp->start_char_vcols = 0;
+
+ line = ml_get(lnum);
+ pstart = line;
+ prev_pstart = line;
+ while (bdp->start_vcol < oap->start_vcol && *pstart)
+ {
+ /* Count a tab for what it's worth (if list mode not on) */
+ incr = lbr_chartabsize(line, pstart, (colnr_T)bdp->start_vcol);
+ bdp->start_vcol += incr;
+ if (VIM_ISWHITE(*pstart))
+ {
+ bdp->pre_whitesp += incr;
+ bdp->pre_whitesp_c++;
+ }
+ else
+ {
+ bdp->pre_whitesp = 0;
+ bdp->pre_whitesp_c = 0;
+ }
+ prev_pstart = pstart;
+ MB_PTR_ADV(pstart);
+ }
+ bdp->start_char_vcols = incr;
+ if (bdp->start_vcol < oap->start_vcol) /* line too short */
+ {
+ bdp->end_vcol = bdp->start_vcol;
+ bdp->is_short = TRUE;
+ if (!is_del || oap->op_type == OP_APPEND)
+ bdp->endspaces = oap->end_vcol - oap->start_vcol + 1;
+ }
+ else
+ {
+ /* notice: this converts partly selected Multibyte characters to
+ * spaces, too. */
+ bdp->startspaces = bdp->start_vcol - oap->start_vcol;
+ if (is_del && bdp->startspaces)
+ bdp->startspaces = bdp->start_char_vcols - bdp->startspaces;
+ pend = pstart;
+ bdp->end_vcol = bdp->start_vcol;
+ if (bdp->end_vcol > oap->end_vcol) /* it's all in one character */
+ {
+ bdp->is_oneChar = TRUE;
+ if (oap->op_type == OP_INSERT)
+ bdp->endspaces = bdp->start_char_vcols - bdp->startspaces;
+ else if (oap->op_type == OP_APPEND)
+ {
+ bdp->startspaces += oap->end_vcol - oap->start_vcol + 1;
+ bdp->endspaces = bdp->start_char_vcols - bdp->startspaces;
+ }
+ else
+ {
+ bdp->startspaces = oap->end_vcol - oap->start_vcol + 1;
+ if (is_del && oap->op_type != OP_LSHIFT)
+ {
+ /* just putting the sum of those two into
+ * bdp->startspaces doesn't work for Visual replace,
+ * so we have to split the tab in two */
+ bdp->startspaces = bdp->start_char_vcols
+ - (bdp->start_vcol - oap->start_vcol);
+ bdp->endspaces = bdp->end_vcol - oap->end_vcol - 1;
+ }
+ }
+ }
+ else
+ {
+ prev_pend = pend;
+ while (bdp->end_vcol <= oap->end_vcol && *pend != NUL)
+ {
+ /* Count a tab for what it's worth (if list mode not on) */
+ prev_pend = pend;
+ incr = lbr_chartabsize_adv(line, &pend, (colnr_T)bdp->end_vcol);
+ bdp->end_vcol += incr;
+ }
+ if (bdp->end_vcol <= oap->end_vcol
+ && (!is_del
+ || oap->op_type == OP_APPEND
+ || oap->op_type == OP_REPLACE)) /* line too short */
+ {
+ bdp->is_short = TRUE;
+ /* Alternative: include spaces to fill up the block.
+ * Disadvantage: can lead to trailing spaces when the line is
+ * short where the text is put */
+ /* if (!is_del || oap->op_type == OP_APPEND) */
+ if (oap->op_type == OP_APPEND || virtual_op)
+ bdp->endspaces = oap->end_vcol - bdp->end_vcol
+ + oap->inclusive;
+ else
+ bdp->endspaces = 0; /* replace doesn't add characters */
+ }
+ else if (bdp->end_vcol > oap->end_vcol)
+ {
+ bdp->endspaces = bdp->end_vcol - oap->end_vcol - 1;
+ if (!is_del && bdp->endspaces)
+ {
+ bdp->endspaces = incr - bdp->endspaces;
+ if (pend != pstart)
+ pend = prev_pend;
+ }
+ }
+ }
+ bdp->end_char_vcols = incr;
+ if (is_del && bdp->startspaces)
+ pstart = prev_pstart;
+ bdp->textlen = (int)(pend - pstart);
+ }
+ bdp->textcol = (colnr_T) (pstart - line);
+ bdp->textstart = pstart;
+}
+
+/*
+ * Handle the add/subtract operator.
+ */
+ void
+op_addsub(
+ oparg_T *oap,
+ linenr_T Prenum1, /* Amount of add/subtract */
+ int g_cmd) /* was g<c-a>/g<c-x> */
+{
+ pos_T pos;
+ struct block_def bd;
+ int change_cnt = 0;
+ linenr_T amount = Prenum1;
+
+ // do_addsub() might trigger re-evaluation of 'foldexpr' halfway, when the
+ // buffer is not completly updated yet. Postpone updating folds until before
+ // the call to changed_lines().
+#ifdef FEAT_FOLDING
+ disable_fold_update++;
+#endif
+
+ if (!VIsual_active)
+ {
+ pos = curwin->w_cursor;
+ if (u_save_cursor() == FAIL)
+ {
+#ifdef FEAT_FOLDING
+ disable_fold_update--;
+#endif
+ return;
+ }
+ change_cnt = do_addsub(oap->op_type, &pos, 0, amount);
+#ifdef FEAT_FOLDING
+ disable_fold_update--;
+#endif
+ if (change_cnt)
+ changed_lines(pos.lnum, 0, pos.lnum + 1, 0L);
+ }
+ else
+ {
+ int one_change;
+ int length;
+ pos_T startpos;
+
+ if (u_save((linenr_T)(oap->start.lnum - 1),
+ (linenr_T)(oap->end.lnum + 1)) == FAIL)
+ {
+#ifdef FEAT_FOLDING
+ disable_fold_update--;
+#endif
+ return;
+ }
+
+ pos = oap->start;
+ for (; pos.lnum <= oap->end.lnum; ++pos.lnum)
+ {
+ if (oap->block_mode) /* Visual block mode */
+ {
+ block_prep(oap, &bd, pos.lnum, FALSE);
+ pos.col = bd.textcol;
+ length = bd.textlen;
+ }
+ else if (oap->motion_type == MLINE)
+ {
+ curwin->w_cursor.col = 0;
+ pos.col = 0;
+ length = (colnr_T)STRLEN(ml_get(pos.lnum));
+ }
+ else /* oap->motion_type == MCHAR */
+ {
+ if (pos.lnum == oap->start.lnum && !oap->inclusive)
+ dec(&(oap->end));
+ length = (colnr_T)STRLEN(ml_get(pos.lnum));
+ pos.col = 0;
+ if (pos.lnum == oap->start.lnum)
+ {
+ pos.col += oap->start.col;
+ length -= oap->start.col;
+ }
+ if (pos.lnum == oap->end.lnum)
+ {
+ length = (int)STRLEN(ml_get(oap->end.lnum));
+ if (oap->end.col >= length)
+ oap->end.col = length - 1;
+ length = oap->end.col - pos.col + 1;
+ }
+ }
+ one_change = do_addsub(oap->op_type, &pos, length, amount);
+ if (one_change)
+ {
+ /* Remember the start position of the first change. */
+ if (change_cnt == 0)
+ startpos = curbuf->b_op_start;
+ ++change_cnt;
+ }
+
+#ifdef FEAT_NETBEANS_INTG
+ if (netbeans_active() && one_change)
+ {
+ char_u *ptr = ml_get_buf(curbuf, pos.lnum, FALSE);
+
+ netbeans_removed(curbuf, pos.lnum, pos.col, (long)length);
+ netbeans_inserted(curbuf, pos.lnum, pos.col,
+ &ptr[pos.col], length);
+ }
+#endif
+ if (g_cmd && one_change)
+ amount += Prenum1;
+ }
+
+#ifdef FEAT_FOLDING
+ disable_fold_update--;
+#endif
+ if (change_cnt)
+ changed_lines(oap->start.lnum, 0, oap->end.lnum + 1, 0L);
+
+ if (!change_cnt && oap->is_VIsual)
+ /* No change: need to remove the Visual selection */
+ redraw_curbuf_later(INVERTED);
+
+ /* Set '[ mark if something changed. Keep the last end
+ * position from do_addsub(). */
+ if (change_cnt > 0)
+ curbuf->b_op_start = startpos;
+
+ if (change_cnt > p_report)
+ smsg(NGETTEXT("%ld line changed", "%ld lines changed",
+ change_cnt), change_cnt);
+ }
+}
+
+/*
+ * Add or subtract 'Prenum1' from a number in a line
+ * op_type is OP_NR_ADD or OP_NR_SUB
+ *
+ * Returns TRUE if some character was changed.
+ */
+ static int
+do_addsub(
+ int op_type,
+ pos_T *pos,
+ int length,
+ linenr_T Prenum1)
+{
+ int col;
+ char_u *buf1;
+ char_u buf2[NUMBUFLEN];
+ int pre; /* 'X'/'x': hex; '0': octal; 'B'/'b': bin */
+ static int hexupper = FALSE; /* 0xABC */
+ uvarnumber_T n;
+ uvarnumber_T oldn;
+ char_u *ptr;
+ int c;
+ int todel;
+ int dohex;
+ int dooct;
+ int dobin;
+ int doalp;
+ int firstdigit;
+ int subtract;
+ int negative = FALSE;
+ int was_positive = TRUE;
+ int visual = VIsual_active;
+ int did_change = FALSE;
+ pos_T save_cursor = curwin->w_cursor;
+ int maxlen = 0;
+ pos_T startpos;
+ pos_T endpos;
+
+ dohex = (vim_strchr(curbuf->b_p_nf, 'x') != NULL); /* "heX" */
+ dooct = (vim_strchr(curbuf->b_p_nf, 'o') != NULL); /* "Octal" */
+ dobin = (vim_strchr(curbuf->b_p_nf, 'b') != NULL); /* "Bin" */
+ doalp = (vim_strchr(curbuf->b_p_nf, 'p') != NULL); /* "alPha" */
+
+ curwin->w_cursor = *pos;
+ ptr = ml_get(pos->lnum);
+ col = pos->col;
+
+ if (*ptr == NUL)
+ goto theend;
+
+ /*
+ * First check if we are on a hexadecimal number, after the "0x".
+ */
+ if (!VIsual_active)
+ {
+ if (dobin)
+ while (col > 0 && vim_isbdigit(ptr[col]))
+ {
+ --col;
+ if (has_mbyte)
+ col -= (*mb_head_off)(ptr, ptr + col);
+ }
+
+ if (dohex)
+ while (col > 0 && vim_isxdigit(ptr[col]))
+ {
+ --col;
+ if (has_mbyte)
+ col -= (*mb_head_off)(ptr, ptr + col);
+ }
+
+ if ( dobin
+ && dohex
+ && ! ((col > 0
+ && (ptr[col] == 'X'
+ || ptr[col] == 'x')
+ && ptr[col - 1] == '0'
+ && (!has_mbyte ||
+ !(*mb_head_off)(ptr, ptr + col - 1))
+ && vim_isxdigit(ptr[col + 1]))))
+ {
+
+ /* In case of binary/hexadecimal pattern overlap match, rescan */
+
+ col = pos->col;
+
+ while (col > 0 && vim_isdigit(ptr[col]))
+ {
+ col--;
+ if (has_mbyte)
+ col -= (*mb_head_off)(ptr, ptr + col);
+ }
+ }
+
+ if (( dohex
+ && col > 0
+ && (ptr[col] == 'X'
+ || ptr[col] == 'x')
+ && ptr[col - 1] == '0'
+ && (!has_mbyte ||
+ !(*mb_head_off)(ptr, ptr + col - 1))
+ && vim_isxdigit(ptr[col + 1])) ||
+ ( dobin
+ && col > 0
+ && (ptr[col] == 'B'
+ || ptr[col] == 'b')
+ && ptr[col - 1] == '0'
+ && (!has_mbyte ||
+ !(*mb_head_off)(ptr, ptr + col - 1))
+ && vim_isbdigit(ptr[col + 1])))
+ {
+ /* Found hexadecimal or binary number, move to its start. */
+ --col;
+ if (has_mbyte)
+ col -= (*mb_head_off)(ptr, ptr + col);
+ }
+ else
+ {
+ /*
+ * Search forward and then backward to find the start of number.
+ */
+ col = pos->col;
+
+ while (ptr[col] != NUL
+ && !vim_isdigit(ptr[col])
+ && !(doalp && ASCII_ISALPHA(ptr[col])))
+ col += MB_PTR2LEN(ptr + col);
+
+ while (col > 0
+ && vim_isdigit(ptr[col - 1])
+ && !(doalp && ASCII_ISALPHA(ptr[col])))
+ {
+ --col;
+ if (has_mbyte)
+ col -= (*mb_head_off)(ptr, ptr + col);
+ }
+ }
+ }
+
+ if (visual)
+ {
+ while (ptr[col] != NUL && length > 0
+ && !vim_isdigit(ptr[col])
+ && !(doalp && ASCII_ISALPHA(ptr[col])))
+ {
+ int mb_len = MB_PTR2LEN(ptr + col);
+
+ col += mb_len;
+ length -= mb_len;
+ }
+
+ if (length == 0)
+ goto theend;
+
+ if (col > pos->col && ptr[col - 1] == '-'
+ && (!has_mbyte || !(*mb_head_off)(ptr, ptr + col - 1)))
+ {
+ negative = TRUE;
+ was_positive = FALSE;
+ }
+ }
+
+ /*
+ * If a number was found, and saving for undo works, replace the number.
+ */
+ firstdigit = ptr[col];
+ if (!VIM_ISDIGIT(firstdigit) && !(doalp && ASCII_ISALPHA(firstdigit)))
+ {
+ beep_flush();
+ goto theend;
+ }
+
+ if (doalp && ASCII_ISALPHA(firstdigit))
+ {
+ /* decrement or increment alphabetic character */
+ if (op_type == OP_NR_SUB)
+ {
+ if (CharOrd(firstdigit) < Prenum1)
+ {
+ if (isupper(firstdigit))
+ firstdigit = 'A';
+ else
+ firstdigit = 'a';
+ }
+ else
+#ifdef EBCDIC
+ firstdigit = EBCDIC_CHAR_ADD(firstdigit, -Prenum1);
+#else
+ firstdigit -= Prenum1;
+#endif
+ }
+ else
+ {
+ if (26 - CharOrd(firstdigit) - 1 < Prenum1)
+ {
+ if (isupper(firstdigit))
+ firstdigit = 'Z';
+ else
+ firstdigit = 'z';
+ }
+ else
+#ifdef EBCDIC
+ firstdigit = EBCDIC_CHAR_ADD(firstdigit, Prenum1);
+#else
+ firstdigit += Prenum1;
+#endif
+ }
+ curwin->w_cursor.col = col;
+ if (!did_change)
+ startpos = curwin->w_cursor;
+ did_change = TRUE;
+ (void)del_char(FALSE);
+ ins_char(firstdigit);
+ endpos = curwin->w_cursor;
+ curwin->w_cursor.col = col;
+ }
+ else
+ {
+ if (col > 0 && ptr[col - 1] == '-'
+ && (!has_mbyte ||
+ !(*mb_head_off)(ptr, ptr + col - 1))
+ && !visual)
+ {
+ /* negative number */
+ --col;
+ negative = TRUE;
+ }
+ /* get the number value (unsigned) */
+ if (visual && VIsual_mode != 'V')
+ maxlen = (curbuf->b_visual.vi_curswant == MAXCOL
+ ? (int)STRLEN(ptr) - col
+ : length);
+
+ vim_str2nr(ptr + col, &pre, &length,
+ 0 + (dobin ? STR2NR_BIN : 0)
+ + (dooct ? STR2NR_OCT : 0)
+ + (dohex ? STR2NR_HEX : 0),
+ NULL, &n, maxlen);
+
+ /* ignore leading '-' for hex and octal and bin numbers */
+ if (pre && negative)
+ {
+ ++col;
+ --length;
+ negative = FALSE;
+ }
+ /* add or subtract */
+ subtract = FALSE;
+ if (op_type == OP_NR_SUB)
+ subtract ^= TRUE;
+ if (negative)
+ subtract ^= TRUE;
+
+ oldn = n;
+ if (subtract)
+ n -= (uvarnumber_T)Prenum1;
+ else
+ n += (uvarnumber_T)Prenum1;
+ /* handle wraparound for decimal numbers */
+ if (!pre)
+ {
+ if (subtract)
+ {
+ if (n > oldn)
+ {
+ n = 1 + (n ^ (uvarnumber_T)-1);
+ negative ^= TRUE;
+ }
+ }
+ else
+ {
+ /* add */
+ if (n < oldn)
+ {
+ n = (n ^ (uvarnumber_T)-1);
+ negative ^= TRUE;
+ }
+ }
+ if (n == 0)
+ negative = FALSE;
+ }
+
+ if (visual && !was_positive && !negative && col > 0)
+ {
+ /* need to remove the '-' */
+ col--;
+ length++;
+ }
+
+ /*
+ * Delete the old number.
+ */
+ curwin->w_cursor.col = col;
+ if (!did_change)
+ startpos = curwin->w_cursor;
+ did_change = TRUE;
+ todel = length;
+ c = gchar_cursor();
+ /*
+ * Don't include the '-' in the length, only the length of the
+ * part after it is kept the same.
+ */
+ if (c == '-')
+ --length;
+ while (todel-- > 0)
+ {
+ if (c < 0x100 && isalpha(c))
+ {
+ if (isupper(c))
+ hexupper = TRUE;
+ else
+ hexupper = FALSE;
+ }
+ /* del_char() will mark line needing displaying */
+ (void)del_char(FALSE);
+ c = gchar_cursor();
+ }
+
+ /*
+ * Prepare the leading characters in buf1[].
+ * When there are many leading zeros it could be very long.
+ * Allocate a bit too much.
+ */
+ buf1 = alloc((unsigned)length + NUMBUFLEN);
+ if (buf1 == NULL)
+ goto theend;
+ ptr = buf1;
+ if (negative && (!visual || was_positive))
+ {
+ *ptr++ = '-';
+ }
+ if (pre)
+ {
+ *ptr++ = '0';
+ --length;
+ }
+ if (pre == 'b' || pre == 'B' ||
+ pre == 'x' || pre == 'X')
+ {
+ *ptr++ = pre;
+ --length;
+ }
+
+ /*
+ * Put the number characters in buf2[].
+ */
+ if (pre == 'b' || pre == 'B')
+ {
+ int i;
+ int bit = 0;
+ int bits = sizeof(uvarnumber_T) * 8;
+
+ /* leading zeros */
+ for (bit = bits; bit > 0; bit--)
+ if ((n >> (bit - 1)) & 0x1) break;
+
+ for (i = 0; bit > 0; bit--)
+ buf2[i++] = ((n >> (bit - 1)) & 0x1) ? '1' : '0';
+
+ buf2[i] = '\0';
+ }
+ else if (pre == 0)
+ vim_snprintf((char *)buf2, NUMBUFLEN, "%llu",
+ (long_long_u_T)n);
+ else if (pre == '0')
+ vim_snprintf((char *)buf2, NUMBUFLEN, "%llo",
+ (long_long_u_T)n);
+ else if (pre && hexupper)
+ vim_snprintf((char *)buf2, NUMBUFLEN, "%llX",
+ (long_long_u_T)n);
+ else
+ vim_snprintf((char *)buf2, NUMBUFLEN, "%llx",
+ (long_long_u_T)n);
+ length -= (int)STRLEN(buf2);
+
+ /*
+ * Adjust number of zeros to the new number of digits, so the
+ * total length of the number remains the same.
+ * Don't do this when
+ * the result may look like an octal number.
+ */
+ if (firstdigit == '0' && !(dooct && pre == 0))
+ while (length-- > 0)
+ *ptr++ = '0';
+ *ptr = NUL;
+ STRCAT(buf1, buf2);
+ ins_str(buf1); /* insert the new number */
+ vim_free(buf1);
+ endpos = curwin->w_cursor;
+ if (did_change && curwin->w_cursor.col)
+ --curwin->w_cursor.col;
+ }
+
+ if (did_change)
+ {
+ /* set the '[ and '] marks */
+ curbuf->b_op_start = startpos;
+ curbuf->b_op_end = endpos;
+ if (curbuf->b_op_end.col > 0)
+ --curbuf->b_op_end.col;
+ }
+
+theend:
+ if (visual)
+ curwin->w_cursor = save_cursor;
+ else if (did_change)
+ curwin->w_set_curswant = TRUE;
+
+ return did_change;
+}
+
+#ifdef FEAT_VIMINFO
+
+static yankreg_T *y_read_regs = NULL;
+
+#define REG_PREVIOUS 1
+#define REG_EXEC 2
+
+/*
+ * Prepare for reading viminfo registers when writing viminfo later.
+ */
+ void
+prepare_viminfo_registers(void)
+{
+ y_read_regs = (yankreg_T *)alloc_clear(NUM_REGISTERS
+ * (int)sizeof(yankreg_T));
+}
+
+ void
+finish_viminfo_registers(void)
+{
+ int i;
+ int j;
+
+ if (y_read_regs != NULL)
+ {
+ for (i = 0; i < NUM_REGISTERS; ++i)
+ if (y_read_regs[i].y_array != NULL)
+ {
+ for (j = 0; j < y_read_regs[i].y_size; j++)
+ vim_free(y_read_regs[i].y_array[j]);
+ vim_free(y_read_regs[i].y_array);
+ }
+ VIM_CLEAR(y_read_regs);
+ }
+}
+
+ int
+read_viminfo_register(vir_T *virp, int force)
+{
+ int eof;
+ int do_it = TRUE;
+ int size;
+ int limit;
+ int i;
+ int set_prev = FALSE;
+ char_u *str;
+ char_u **array = NULL;
+ int new_type = MCHAR; /* init to shut up compiler */
+ colnr_T new_width = 0; /* init to shut up compiler */
+
+ /* We only get here (hopefully) if line[0] == '"' */
+ str = virp->vir_line + 1;
+
+ /* If the line starts with "" this is the y_previous register. */
+ if (*str == '"')
+ {
+ set_prev = TRUE;
+ str++;
+ }
+
+ if (!ASCII_ISALNUM(*str) && *str != '-')
+ {
+ if (viminfo_error("E577: ", _("Illegal register name"), virp->vir_line))
+ return TRUE; /* too many errors, pretend end-of-file */
+ do_it = FALSE;
+ }
+ get_yank_register(*str++, FALSE);
+ if (!force && y_current->y_array != NULL)
+ do_it = FALSE;
+
+ if (*str == '@')
+ {
+ /* "x@: register x used for @@ */
+ if (force || execreg_lastc == NUL)
+ execreg_lastc = str[-1];
+ }
+
+ size = 0;
+ limit = 100; /* Optimized for registers containing <= 100 lines */
+ if (do_it)
+ {
+ /*
+ * Build the new register in array[].
+ * y_array is kept as-is until done.
+ * The "do_it" flag is reset when something is wrong, in which case
+ * array[] needs to be freed.
+ */
+ if (set_prev)
+ y_previous = y_current;
+ array = (char_u **)alloc((unsigned)(limit * sizeof(char_u *)));
+ str = skipwhite(skiptowhite(str));
+ if (STRNCMP(str, "CHAR", 4) == 0)
+ new_type = MCHAR;
+ else if (STRNCMP(str, "BLOCK", 5) == 0)
+ new_type = MBLOCK;
+ else
+ new_type = MLINE;
+ /* get the block width; if it's missing we get a zero, which is OK */
+ str = skipwhite(skiptowhite(str));
+ new_width = getdigits(&str);
+ }
+
+ while (!(eof = viminfo_readline(virp))
+ && (virp->vir_line[0] == TAB || virp->vir_line[0] == '<'))
+ {
+ if (do_it)
+ {
+ if (size == limit)
+ {
+ char_u **new_array = (char_u **)
+ alloc((unsigned)(limit * 2 * sizeof(char_u *)));
+
+ if (new_array == NULL)
+ {
+ do_it = FALSE;
+ break;
+ }
+ for (i = 0; i < limit; i++)
+ new_array[i] = array[i];
+ vim_free(array);
+ array = new_array;
+ limit *= 2;
+ }
+ str = viminfo_readstring(virp, 1, TRUE);
+ if (str != NULL)
+ array[size++] = str;
+ else
+ /* error, don't store the result */
+ do_it = FALSE;
+ }
+ }
+
+ if (do_it)
+ {
+ /* free y_array[] */
+ for (i = 0; i < y_current->y_size; i++)
+ vim_free(y_current->y_array[i]);
+ vim_free(y_current->y_array);
+
+ y_current->y_type = new_type;
+ y_current->y_width = new_width;
+ y_current->y_size = size;
+ y_current->y_time_set = 0;
+ if (size == 0)
+ {
+ y_current->y_array = NULL;
+ }
+ else
+ {
+ /* Move the lines from array[] to y_array[]. */
+ y_current->y_array =
+ (char_u **)alloc((unsigned)(size * sizeof(char_u *)));
+ for (i = 0; i < size; i++)
+ {
+ if (y_current->y_array == NULL)
+ vim_free(array[i]);
+ else
+ y_current->y_array[i] = array[i];
+ }
+ }
+ }
+ else
+ {
+ /* Free array[] if it was filled. */
+ for (i = 0; i < size; i++)
+ vim_free(array[i]);
+ }
+ vim_free(array);
+
+ return eof;
+}
+
+/*
+ * Accept a new style register line from the viminfo, store it when it's new.
+ */
+ void
+handle_viminfo_register(garray_T *values, int force)
+{
+ bval_T *vp = (bval_T *)values->ga_data;
+ int flags;
+ int name;
+ int type;
+ int linecount;
+ int width;
+ time_t timestamp;
+ yankreg_T *y_ptr;
+ int i;
+
+ /* Check the format:
+ * |{bartype},{flags},{name},{type},
+ * {linecount},{width},{timestamp},"line1","line2"
+ */
+ if (values->ga_len < 6
+ || vp[0].bv_type != BVAL_NR
+ || vp[1].bv_type != BVAL_NR
+ || vp[2].bv_type != BVAL_NR
+ || vp[3].bv_type != BVAL_NR
+ || vp[4].bv_type != BVAL_NR
+ || vp[5].bv_type != BVAL_NR)
+ return;
+ flags = vp[0].bv_nr;
+ name = vp[1].bv_nr;
+ if (name < 0 || name >= NUM_REGISTERS)
+ return;
+ type = vp[2].bv_nr;
+ if (type != MCHAR && type != MLINE && type != MBLOCK)
+ return;
+ linecount = vp[3].bv_nr;
+ if (values->ga_len < 6 + linecount)
+ return;
+ width = vp[4].bv_nr;
+ if (width < 0)
+ return;
+
+ if (y_read_regs != NULL)
+ /* Reading viminfo for merging and writing. Store the register
+ * content, don't update the current registers. */
+ y_ptr = &y_read_regs[name];
+ else
+ y_ptr = &y_regs[name];
+
+ /* Do not overwrite unless forced or the timestamp is newer. */
+ timestamp = (time_t)vp[5].bv_nr;
+ if (y_ptr->y_array != NULL && !force
+ && (timestamp == 0 || y_ptr->y_time_set > timestamp))
+ return;
+
+ if (y_ptr->y_array != NULL)
+ for (i = 0; i < y_ptr->y_size; i++)
+ vim_free(y_ptr->y_array[i]);
+ vim_free(y_ptr->y_array);
+
+ if (y_read_regs == NULL)
+ {
+ if (flags & REG_PREVIOUS)
+ y_previous = y_ptr;
+ if ((flags & REG_EXEC) && (force || execreg_lastc == NUL))
+ execreg_lastc = get_register_name(name);
+ }
+ y_ptr->y_type = type;
+ y_ptr->y_width = width;
+ y_ptr->y_size = linecount;
+ y_ptr->y_time_set = timestamp;
+ if (linecount == 0)
+ y_ptr->y_array = NULL;
+ else
+ {
+ y_ptr->y_array =
+ (char_u **)alloc((unsigned)(linecount * sizeof(char_u *)));
+ for (i = 0; i < linecount; i++)
+ {
+ if (vp[i + 6].bv_allocated)
+ {
+ y_ptr->y_array[i] = vp[i + 6].bv_string;
+ vp[i + 6].bv_string = NULL;
+ }
+ else
+ y_ptr->y_array[i] = vim_strsave(vp[i + 6].bv_string);
+ }
+ }
+}
+
+ void
+write_viminfo_registers(FILE *fp)
+{
+ int i, j;
+ char_u *type;
+ char_u c;
+ int num_lines;
+ int max_num_lines;
+ int max_kbyte;
+ long len;
+ yankreg_T *y_ptr;
+
+ fputs(_("\n# Registers:\n"), fp);
+
+ /* Get '<' value, use old '"' value if '<' is not found. */
+ max_num_lines = get_viminfo_parameter('<');
+ if (max_num_lines < 0)
+ max_num_lines = get_viminfo_parameter('"');
+ if (max_num_lines == 0)
+ return;
+ max_kbyte = get_viminfo_parameter('s');
+ if (max_kbyte == 0)
+ return;
+
+ for (i = 0; i < NUM_REGISTERS; i++)
+ {
+#ifdef FEAT_CLIPBOARD
+ /* Skip '*'/'+' register, we don't want them back next time */
+ if (i == STAR_REGISTER || i == PLUS_REGISTER)
+ continue;
+#endif
+#ifdef FEAT_DND
+ /* Neither do we want the '~' register */
+ if (i == TILDE_REGISTER)
+ continue;
+#endif
+ /* When reading viminfo for merging and writing: Use the register from
+ * viminfo if it's newer. */
+ if (y_read_regs != NULL
+ && y_read_regs[i].y_array != NULL
+ && (y_regs[i].y_array == NULL ||
+ y_read_regs[i].y_time_set > y_regs[i].y_time_set))
+ y_ptr = &y_read_regs[i];
+ else if (y_regs[i].y_array == NULL)
+ continue;
+ else
+ y_ptr = &y_regs[i];
+
+ /* Skip empty registers. */
+ num_lines = y_ptr->y_size;
+ if (num_lines == 0
+ || (num_lines == 1 && y_ptr->y_type == MCHAR
+ && *y_ptr->y_array[0] == NUL))
+ continue;
+
+ if (max_kbyte > 0)
+ {
+ /* Skip register if there is more text than the maximum size. */
+ len = 0;
+ for (j = 0; j < num_lines; j++)
+ len += (long)STRLEN(y_ptr->y_array[j]) + 1L;
+ if (len > (long)max_kbyte * 1024L)
+ continue;
+ }
+
+ switch (y_ptr->y_type)
+ {
+ case MLINE:
+ type = (char_u *)"LINE";
+ break;
+ case MCHAR:
+ type = (char_u *)"CHAR";
+ break;
+ case MBLOCK:
+ type = (char_u *)"BLOCK";
+ break;
+ default:
+ semsg(_("E574: Unknown register type %d"), y_ptr->y_type);
+ type = (char_u *)"LINE";
+ break;
+ }
+ if (y_previous == &y_regs[i])
+ fprintf(fp, "\"");
+ c = get_register_name(i);
+ fprintf(fp, "\"%c", c);
+ if (c == execreg_lastc)
+ fprintf(fp, "@");
+ fprintf(fp, "\t%s\t%d\n", type, (int)y_ptr->y_width);
+
+ /* If max_num_lines < 0, then we save ALL the lines in the register */
+ if (max_num_lines > 0 && num_lines > max_num_lines)
+ num_lines = max_num_lines;
+ for (j = 0; j < num_lines; j++)
+ {
+ putc('\t', fp);
+ viminfo_writestring(fp, y_ptr->y_array[j]);
+ }
+
+ {
+ int flags = 0;
+ int remaining;
+
+ /* New style with a bar line. Format:
+ * |{bartype},{flags},{name},{type},
+ * {linecount},{width},{timestamp},"line1","line2"
+ * flags: REG_PREVIOUS - register is y_previous
+ * REG_EXEC - used for @@
+ */
+ if (y_previous == &y_regs[i])
+ flags |= REG_PREVIOUS;
+ if (c == execreg_lastc)
+ flags |= REG_EXEC;
+ fprintf(fp, "|%d,%d,%d,%d,%d,%d,%ld", BARTYPE_REGISTER, flags,
+ i, y_ptr->y_type, num_lines, (int)y_ptr->y_width,
+ (long)y_ptr->y_time_set);
+ /* 11 chars for type/flags/name/type, 3 * 20 for numbers */
+ remaining = LSIZE - 71;
+ for (j = 0; j < num_lines; j++)
+ {
+ putc(',', fp);
+ --remaining;
+ remaining = barline_writestring(fp, y_ptr->y_array[j],
+ remaining);
+ }
+ putc('\n', fp);
+ }
+ }
+}
+#endif /* FEAT_VIMINFO */
+
+#if defined(FEAT_CLIPBOARD) || defined(PROTO)
+/*
+ * SELECTION / PRIMARY ('*')
+ *
+ * Text selection stuff that uses the GUI selection register '*'. When using a
+ * GUI this may be text from another window, otherwise it is the last text we
+ * had highlighted with VIsual mode. With mouse support, clicking the middle
+ * button performs the paste, otherwise you will need to do <"*p>. "
+ * If not under X, it is synonymous with the clipboard register '+'.
+ *
+ * X CLIPBOARD ('+')
+ *
+ * Text selection stuff that uses the GUI clipboard register '+'.
+ * Under X, this matches the standard cut/paste buffer CLIPBOARD selection.
+ * It will be used for unnamed cut/pasting is 'clipboard' contains "unnamed",
+ * otherwise you will need to do <"+p>. "
+ * If not under X, it is synonymous with the selection register '*'.
+ */
+
+/*
+ * Routine to export any final X selection we had to the environment
+ * so that the text is still available after Vim has exited. X selections
+ * only exist while the owning application exists, so we write to the
+ * permanent (while X runs) store CUT_BUFFER0.
+ * Dump the CLIPBOARD selection if we own it (it's logically the more
+ * 'permanent' of the two), otherwise the PRIMARY one.
+ * For now, use a hard-coded sanity limit of 1Mb of data.
+ */
+#if (defined(FEAT_X11) && defined(FEAT_CLIPBOARD)) || defined(PROTO)
+ void
+x11_export_final_selection(void)
+{
+ Display *dpy;
+ char_u *str = NULL;
+ long_u len = 0;
+ int motion_type = -1;
+
+# ifdef FEAT_GUI
+ if (gui.in_use)
+ dpy = X_DISPLAY;
+ else
+# endif
+# ifdef FEAT_XCLIPBOARD
+ dpy = xterm_dpy;
+# else
+ return;
+# endif
+
+ /* Get selection to export */
+ if (clip_plus.owned)
+ motion_type = clip_convert_selection(&str, &len, &clip_plus);
+ else if (clip_star.owned)
+ motion_type = clip_convert_selection(&str, &len, &clip_star);
+
+ /* Check it's OK */
+ if (dpy != NULL && str != NULL && motion_type >= 0
+ && len < 1024*1024 && len > 0)
+ {
+ int ok = TRUE;
+
+ /* The CUT_BUFFER0 is supposed to always contain latin1. Convert from
+ * 'enc' when it is a multi-byte encoding. When 'enc' is an 8-bit
+ * encoding conversion usually doesn't work, so keep the text as-is.
+ */
+ if (has_mbyte)
+ {
+ vimconv_T vc;
+
+ vc.vc_type = CONV_NONE;
+ if (convert_setup(&vc, p_enc, (char_u *)"latin1") == OK)
+ {
+ int intlen = len;
+ char_u *conv_str;
+
+ vc.vc_fail = TRUE;
+ conv_str = string_convert(&vc, str, &intlen);
+ len = intlen;
+ if (conv_str != NULL)
+ {
+ vim_free(str);
+ str = conv_str;
+ }
+ else
+ {
+ ok = FALSE;
+ }
+ convert_setup(&vc, NULL, NULL);
+ }
+ else
+ {
+ ok = FALSE;
+ }
+ }
+
+ /* Do not store the string if conversion failed. Better to use any
+ * other selection than garbled text. */
+ if (ok)
+ {
+ XStoreBuffer(dpy, (char *)str, (int)len, 0);
+ XFlush(dpy);
+ }
+ }
+
+ vim_free(str);
+}
+#endif
+
+ void
+clip_free_selection(VimClipboard *cbd)
+{
+ yankreg_T *y_ptr = y_current;
+
+ if (cbd == &clip_plus)
+ y_current = &y_regs[PLUS_REGISTER];
+ else
+ y_current = &y_regs[STAR_REGISTER];
+ free_yank_all();
+ y_current->y_size = 0;
+ y_current = y_ptr;
+}
+
+/*
+ * Get the selected text and put it in register '*' or '+'.
+ */
+ void
+clip_get_selection(VimClipboard *cbd)
+{
+ yankreg_T *old_y_previous, *old_y_current;
+ pos_T old_cursor;
+ pos_T old_visual;
+ int old_visual_mode;
+ colnr_T old_curswant;
+ int old_set_curswant;
+ pos_T old_op_start, old_op_end;
+ oparg_T oa;
+ cmdarg_T ca;
+
+ if (cbd->owned)
+ {
+ if ((cbd == &clip_plus && y_regs[PLUS_REGISTER].y_array != NULL)
+ || (cbd == &clip_star && y_regs[STAR_REGISTER].y_array != NULL))
+ return;
+
+ /* Get the text between clip_star.start & clip_star.end */
+ old_y_previous = y_previous;
+ old_y_current = y_current;
+ old_cursor = curwin->w_cursor;
+ old_curswant = curwin->w_curswant;
+ old_set_curswant = curwin->w_set_curswant;
+ old_op_start = curbuf->b_op_start;
+ old_op_end = curbuf->b_op_end;
+ old_visual = VIsual;
+ old_visual_mode = VIsual_mode;
+ clear_oparg(&oa);
+ oa.regname = (cbd == &clip_plus ? '+' : '*');
+ oa.op_type = OP_YANK;
+ vim_memset(&ca, 0, sizeof(ca));
+ ca.oap = &oa;
+ ca.cmdchar = 'y';
+ ca.count1 = 1;
+ ca.retval = CA_NO_ADJ_OP_END;
+ do_pending_operator(&ca, 0, TRUE);
+ y_previous = old_y_previous;
+ y_current = old_y_current;
+ curwin->w_cursor = old_cursor;
+ changed_cline_bef_curs(); /* need to update w_virtcol et al */
+ curwin->w_curswant = old_curswant;
+ curwin->w_set_curswant = old_set_curswant;
+ curbuf->b_op_start = old_op_start;
+ curbuf->b_op_end = old_op_end;
+ VIsual = old_visual;
+ VIsual_mode = old_visual_mode;
+ }
+ else if (!is_clipboard_needs_update())
+ {
+ clip_free_selection(cbd);
+
+ /* Try to get selected text from another window */
+ clip_gen_request_selection(cbd);
+ }
+}
+
+/*
+ * Convert from the GUI selection string into the '*'/'+' register.
+ */
+ void
+clip_yank_selection(
+ int type,
+ char_u *str,
+ long len,
+ VimClipboard *cbd)
+{
+ yankreg_T *y_ptr;
+
+ if (cbd == &clip_plus)
+ y_ptr = &y_regs[PLUS_REGISTER];
+ else
+ y_ptr = &y_regs[STAR_REGISTER];
+
+ clip_free_selection(cbd);
+
+ str_to_reg(y_ptr, type, str, len, 0L, FALSE);
+}
+
+/*
+ * Convert the '*'/'+' register into a GUI selection string returned in *str
+ * with length *len.
+ * Returns the motion type, or -1 for failure.
+ */
+ int
+clip_convert_selection(char_u **str, long_u *len, VimClipboard *cbd)
+{
+ char_u *p;
+ int lnum;
+ int i, j;
+ int_u eolsize;
+ yankreg_T *y_ptr;
+
+ if (cbd == &clip_plus)
+ y_ptr = &y_regs[PLUS_REGISTER];
+ else
+ y_ptr = &y_regs[STAR_REGISTER];
+
+#ifdef USE_CRNL
+ eolsize = 2;
+#else
+ eolsize = 1;
+#endif
+
+ *str = NULL;
+ *len = 0;
+ if (y_ptr->y_array == NULL)
+ return -1;
+
+ for (i = 0; i < y_ptr->y_size; i++)
+ *len += (long_u)STRLEN(y_ptr->y_array[i]) + eolsize;
+
+ /*
+ * Don't want newline character at end of last line if we're in MCHAR mode.
+ */
+ if (y_ptr->y_type == MCHAR && *len >= eolsize)
+ *len -= eolsize;
+
+ p = *str = lalloc(*len + 1, TRUE); /* add one to avoid zero */
+ if (p == NULL)
+ return -1;
+ lnum = 0;
+ for (i = 0, j = 0; i < (int)*len; i++, j++)
+ {
+ if (y_ptr->y_array[lnum][j] == '\n')
+ p[i] = NUL;
+ else if (y_ptr->y_array[lnum][j] == NUL)
+ {
+#ifdef USE_CRNL
+ p[i++] = '\r';
+#endif
+#ifdef USE_CR
+ p[i] = '\r';
+#else
+ p[i] = '\n';
+#endif
+ lnum++;
+ j = -1;
+ }
+ else
+ p[i] = y_ptr->y_array[lnum][j];
+ }
+ return y_ptr->y_type;
+}
+
+
+/*
+ * If we have written to a clipboard register, send the text to the clipboard.
+ */
+ static void
+may_set_selection(void)
+{
+ if (y_current == &(y_regs[STAR_REGISTER]) && clip_star.available)
+ {
+ clip_own_selection(&clip_star);
+ clip_gen_set_selection(&clip_star);
+ }
+ else if (y_current == &(y_regs[PLUS_REGISTER]) && clip_plus.available)
+ {
+ clip_own_selection(&clip_plus);
+ clip_gen_set_selection(&clip_plus);
+ }
+}
+
+#endif /* FEAT_CLIPBOARD || PROTO */
+
+
+#if defined(FEAT_DND) || defined(PROTO)
+/*
+ * Replace the contents of the '~' register with str.
+ */
+ void
+dnd_yank_drag_data(char_u *str, long len)
+{
+ yankreg_T *curr;
+
+ curr = y_current;
+ y_current = &y_regs[TILDE_REGISTER];
+ free_yank_all();
+ str_to_reg(y_current, MCHAR, str, len, 0L, FALSE);
+ y_current = curr;
+}
+#endif
+
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * Return the type of a register.
+ * Used for getregtype()
+ * Returns MAUTO for error.
+ */
+ char_u
+get_reg_type(int regname, long *reglen)
+{
+ switch (regname)
+ {
+ case '%': /* file name */
+ case '#': /* alternate file name */
+ case '=': /* expression */
+ case ':': /* last command line */
+ case '/': /* last search-pattern */
+ case '.': /* last inserted text */
+#ifdef FEAT_SEARCHPATH
+ case Ctrl_F: /* Filename under cursor */
+ case Ctrl_P: /* Path under cursor, expand via "path" */
+#endif
+ case Ctrl_W: /* word under cursor */
+ case Ctrl_A: /* WORD (mnemonic All) under cursor */
+ case '_': /* black hole: always empty */
+ return MCHAR;
+ }
+
+#ifdef FEAT_CLIPBOARD
+ regname = may_get_selection(regname);
+#endif
+
+ if (regname != NUL && !valid_yank_reg(regname, FALSE))
+ return MAUTO;
+
+ get_yank_register(regname, FALSE);
+
+ if (y_current->y_array != NULL)
+ {
+ if (reglen != NULL && y_current->y_type == MBLOCK)
+ *reglen = y_current->y_width;
+ return y_current->y_type;
+ }
+ return MAUTO;
+}
+
+/*
+ * When "flags" has GREG_LIST return a list with text "s".
+ * Otherwise just return "s".
+ */
+ static char_u *
+getreg_wrap_one_line(char_u *s, int flags)
+{
+ if (flags & GREG_LIST)
+ {
+ list_T *list = list_alloc();
+
+ if (list != NULL)
+ {
+ if (list_append_string(list, NULL, -1) == FAIL)
+ {
+ list_free(list);
+ return NULL;
+ }
+ list->lv_first->li_tv.vval.v_string = s;
+ }
+ return (char_u *)list;
+ }
+ return s;
+}
+
+/*
+ * Return the contents of a register as a single allocated string.
+ * Used for "@r" in expressions and for getreg().
+ * Returns NULL for error.
+ * Flags:
+ * GREG_NO_EXPR Do not allow expression register
+ * GREG_EXPR_SRC For the expression register: return expression itself,
+ * not the result of its evaluation.
+ * GREG_LIST Return a list of lines in place of a single string.
+ */
+ char_u *
+get_reg_contents(int regname, int flags)
+{
+ long i;
+ char_u *retval;
+ int allocated;
+ long len;
+
+ /* Don't allow using an expression register inside an expression */
+ if (regname == '=')
+ {
+ if (flags & GREG_NO_EXPR)
+ return NULL;
+ if (flags & GREG_EXPR_SRC)
+ return getreg_wrap_one_line(get_expr_line_src(), flags);
+ return getreg_wrap_one_line(get_expr_line(), flags);
+ }
+
+ if (regname == '@') /* "@@" is used for unnamed register */
+ regname = '"';
+
+ /* check for valid regname */
+ if (regname != NUL && !valid_yank_reg(regname, FALSE))
+ return NULL;
+
+#ifdef FEAT_CLIPBOARD
+ regname = may_get_selection(regname);
+#endif
+
+ if (get_spec_reg(regname, &retval, &allocated, FALSE))
+ {
+ if (retval == NULL)
+ return NULL;
+ if (allocated)
+ return getreg_wrap_one_line(retval, flags);
+ return getreg_wrap_one_line(vim_strsave(retval), flags);
+ }
+
+ get_yank_register(regname, FALSE);
+ if (y_current->y_array == NULL)
+ return NULL;
+
+ if (flags & GREG_LIST)
+ {
+ list_T *list = list_alloc();
+ int error = FALSE;
+
+ if (list == NULL)
+ return NULL;
+ for (i = 0; i < y_current->y_size; ++i)
+ if (list_append_string(list, y_current->y_array[i], -1) == FAIL)
+ error = TRUE;
+ if (error)
+ {
+ list_free(list);
+ return NULL;
+ }
+ return (char_u *)list;
+ }
+
+ /*
+ * Compute length of resulting string.
+ */
+ len = 0;
+ for (i = 0; i < y_current->y_size; ++i)
+ {
+ len += (long)STRLEN(y_current->y_array[i]);
+ /*
+ * Insert a newline between lines and after last line if
+ * y_type is MLINE.
+ */
+ if (y_current->y_type == MLINE || i < y_current->y_size - 1)
+ ++len;
+ }
+
+ retval = lalloc(len + 1, TRUE);
+
+ /*
+ * Copy the lines of the yank register into the string.
+ */
+ if (retval != NULL)
+ {
+ len = 0;
+ for (i = 0; i < y_current->y_size; ++i)
+ {
+ STRCPY(retval + len, y_current->y_array[i]);
+ len += (long)STRLEN(retval + len);
+
+ /*
+ * Insert a NL between lines and after the last line if y_type is
+ * MLINE.
+ */
+ if (y_current->y_type == MLINE || i < y_current->y_size - 1)
+ retval[len++] = '\n';
+ }
+ retval[len] = NUL;
+ }
+
+ return retval;
+}
+
+ static int
+init_write_reg(
+ int name,
+ yankreg_T **old_y_previous,
+ yankreg_T **old_y_current,
+ int must_append,
+ int *yank_type UNUSED)
+{
+ if (!valid_yank_reg(name, TRUE)) /* check for valid reg name */
+ {
+ emsg_invreg(name);
+ return FAIL;
+ }
+
+ /* Don't want to change the current (unnamed) register */
+ *old_y_previous = y_previous;
+ *old_y_current = y_current;
+
+ get_yank_register(name, TRUE);
+ if (!y_append && !must_append)
+ free_yank_all();
+ return OK;
+}
+
+ static void
+finish_write_reg(
+ int name,
+ yankreg_T *old_y_previous,
+ yankreg_T *old_y_current)
+{
+# ifdef FEAT_CLIPBOARD
+ /* Send text of clipboard register to the clipboard. */
+ may_set_selection();
+# endif
+
+ /* ':let @" = "val"' should change the meaning of the "" register */
+ if (name != '"')
+ y_previous = old_y_previous;
+ y_current = old_y_current;
+}
+
+/*
+ * Store string "str" in register "name".
+ * "maxlen" is the maximum number of bytes to use, -1 for all bytes.
+ * If "must_append" is TRUE, always append to the register. Otherwise append
+ * if "name" is an uppercase letter.
+ * Note: "maxlen" and "must_append" don't work for the "/" register.
+ * Careful: 'str' is modified, you may have to use a copy!
+ * If "str" ends in '\n' or '\r', use linewise, otherwise use characterwise.
+ */
+ void
+write_reg_contents(
+ int name,
+ char_u *str,
+ int maxlen,
+ int must_append)
+{
+ write_reg_contents_ex(name, str, maxlen, must_append, MAUTO, 0L);
+}
+
+ void
+write_reg_contents_lst(
+ int name,
+ char_u **strings,
+ int maxlen UNUSED,
+ int must_append,
+ int yank_type,
+ long block_len)
+{
+ yankreg_T *old_y_previous, *old_y_current;
+
+ if (name == '/'
+#ifdef FEAT_EVAL
+ || name == '='
+#endif
+ )
+ {
+ char_u *s;
+
+ if (strings[0] == NULL)
+ s = (char_u *)"";
+ else if (strings[1] != NULL)
+ {
+ emsg(_("E883: search pattern and expression register may not "
+ "contain two or more lines"));
+ return;
+ }
+ else
+ s = strings[0];
+ write_reg_contents_ex(name, s, -1, must_append, yank_type, block_len);
+ return;
+ }
+
+ if (name == '_') /* black hole: nothing to do */
+ return;
+
+ if (init_write_reg(name, &old_y_previous, &old_y_current, must_append,
+ &yank_type) == FAIL)
+ return;
+
+ str_to_reg(y_current, yank_type, (char_u *) strings, -1, block_len, TRUE);
+
+ finish_write_reg(name, old_y_previous, old_y_current);
+}
+
+ void
+write_reg_contents_ex(
+ int name,
+ char_u *str,
+ int maxlen,
+ int must_append,
+ int yank_type,
+ long block_len)
+{
+ yankreg_T *old_y_previous, *old_y_current;
+ long len;
+
+ if (maxlen >= 0)
+ len = maxlen;
+ else
+ len = (long)STRLEN(str);
+
+ /* Special case: '/' search pattern */
+ if (name == '/')
+ {
+ set_last_search_pat(str, RE_SEARCH, TRUE, TRUE);
+ return;
+ }
+
+ if (name == '#')
+ {
+ buf_T *buf;
+
+ if (VIM_ISDIGIT(*str))
+ {
+ int num = atoi((char *)str);
+
+ buf = buflist_findnr(num);
+ if (buf == NULL)
+ semsg(_(e_nobufnr), (long)num);
+ }
+ else
+ buf = buflist_findnr(buflist_findpat(str, str + STRLEN(str),
+ TRUE, FALSE, FALSE));
+ if (buf == NULL)
+ return;
+ curwin->w_alt_fnum = buf->b_fnum;
+ return;
+ }
+
+#ifdef FEAT_EVAL
+ if (name == '=')
+ {
+ char_u *p, *s;
+
+ p = vim_strnsave(str, (int)len);
+ if (p == NULL)
+ return;
+ if (must_append)
+ {
+ s = concat_str(get_expr_line_src(), p);
+ vim_free(p);
+ p = s;
+ }
+ set_expr_line(p);
+ return;
+ }
+#endif
+
+ if (name == '_') /* black hole: nothing to do */
+ return;
+
+ if (init_write_reg(name, &old_y_previous, &old_y_current, must_append,
+ &yank_type) == FAIL)
+ return;
+
+ str_to_reg(y_current, yank_type, str, len, block_len, FALSE);
+
+ finish_write_reg(name, old_y_previous, old_y_current);
+}
+#endif /* FEAT_EVAL */
+
+#if defined(FEAT_CLIPBOARD) || defined(FEAT_EVAL)
+/*
+ * Put a string into a register. When the register is not empty, the string
+ * is appended.
+ */
+ static void
+str_to_reg(
+ yankreg_T *y_ptr, /* pointer to yank register */
+ int yank_type, /* MCHAR, MLINE, MBLOCK, MAUTO */
+ char_u *str, /* string to put in register */
+ long len, /* length of string */
+ long blocklen, /* width of Visual block */
+ int str_list) /* TRUE if str is char_u ** */
+{
+ int type; /* MCHAR, MLINE or MBLOCK */
+ int lnum;
+ long start;
+ long i;
+ int extra;
+ int newlines; /* number of lines added */
+ int extraline = 0; /* extra line at the end */
+ int append = FALSE; /* append to last line in register */
+ char_u *s;
+ char_u **ss;
+ char_u **pp;
+ long maxlen;
+
+ if (y_ptr->y_array == NULL) /* NULL means empty register */
+ y_ptr->y_size = 0;
+
+ if (yank_type == MAUTO)
+ type = ((str_list || (len > 0 && (str[len - 1] == NL
+ || str[len - 1] == CAR)))
+ ? MLINE : MCHAR);
+ else
+ type = yank_type;
+
+ /*
+ * Count the number of lines within the string
+ */
+ newlines = 0;
+ if (str_list)
+ {
+ for (ss = (char_u **) str; *ss != NULL; ++ss)
+ ++newlines;
+ }
+ else
+ {
+ for (i = 0; i < len; i++)
+ if (str[i] == '\n')
+ ++newlines;
+ if (type == MCHAR || len == 0 || str[len - 1] != '\n')
+ {
+ extraline = 1;
+ ++newlines; /* count extra newline at the end */
+ }
+ if (y_ptr->y_size > 0 && y_ptr->y_type == MCHAR)
+ {
+ append = TRUE;
+ --newlines; /* uncount newline when appending first line */
+ }
+ }
+
+ /* Without any lines make the register empty. */
+ if (y_ptr->y_size + newlines == 0)
+ {
+ VIM_CLEAR(y_ptr->y_array);
+ return;
+ }
+
+ /*
+ * Allocate an array to hold the pointers to the new register lines.
+ * If the register was not empty, move the existing lines to the new array.
+ */
+ pp = (char_u **)lalloc_clear((y_ptr->y_size + newlines)
+ * sizeof(char_u *), TRUE);
+ if (pp == NULL) /* out of memory */
+ return;
+ for (lnum = 0; lnum < y_ptr->y_size; ++lnum)
+ pp[lnum] = y_ptr->y_array[lnum];
+ vim_free(y_ptr->y_array);
+ y_ptr->y_array = pp;
+ maxlen = 0;
+
+ /*
+ * Find the end of each line and save it into the array.
+ */
+ if (str_list)
+ {
+ for (ss = (char_u **) str; *ss != NULL; ++ss, ++lnum)
+ {
+ i = (long)STRLEN(*ss);
+ pp[lnum] = vim_strnsave(*ss, i);
+ if (i > maxlen)
+ maxlen = i;
+ }
+ }
+ else
+ {
+ for (start = 0; start < len + extraline; start += i + 1)
+ {
+ for (i = start; i < len; ++i) /* find the end of the line */
+ if (str[i] == '\n')
+ break;
+ i -= start; /* i is now length of line */
+ if (i > maxlen)
+ maxlen = i;
+ if (append)
+ {
+ --lnum;
+ extra = (int)STRLEN(y_ptr->y_array[lnum]);
+ }
+ else
+ extra = 0;
+ s = alloc((unsigned)(i + extra + 1));
+ if (s == NULL)
+ break;
+ if (extra)
+ mch_memmove(s, y_ptr->y_array[lnum], (size_t)extra);
+ if (append)
+ vim_free(y_ptr->y_array[lnum]);
+ if (i)
+ mch_memmove(s + extra, str + start, (size_t)i);
+ extra += i;
+ s[extra] = NUL;
+ y_ptr->y_array[lnum++] = s;
+ while (--extra >= 0)
+ {
+ if (*s == NUL)
+ *s = '\n'; /* replace NUL with newline */
+ ++s;
+ }
+ append = FALSE; /* only first line is appended */
+ }
+ }
+ y_ptr->y_type = type;
+ y_ptr->y_size = lnum;
+ if (type == MBLOCK)
+ y_ptr->y_width = (blocklen < 0 ? maxlen - 1 : blocklen);
+ else
+ y_ptr->y_width = 0;
+#ifdef FEAT_VIMINFO
+ y_ptr->y_time_set = vim_time();
+#endif
+}
+#endif /* FEAT_CLIPBOARD || FEAT_EVAL || PROTO */
+
+ void
+clear_oparg(oparg_T *oap)
+{
+ vim_memset(oap, 0, sizeof(oparg_T));
+}
+
+/*
+ * Count the number of bytes, characters and "words" in a line.
+ *
+ * "Words" are counted by looking for boundaries between non-space and
+ * space characters. (it seems to produce results that match 'wc'.)
+ *
+ * Return value is byte count; word count for the line is added to "*wc".
+ * Char count is added to "*cc".
+ *
+ * The function will only examine the first "limit" characters in the
+ * line, stopping if it encounters an end-of-line (NUL byte). In that
+ * case, eol_size will be added to the character count to account for
+ * the size of the EOL character.
+ */
+ static varnumber_T
+line_count_info(
+ char_u *line,
+ varnumber_T *wc,
+ varnumber_T *cc,
+ varnumber_T limit,
+ int eol_size)
+{
+ varnumber_T i;
+ varnumber_T words = 0;
+ varnumber_T chars = 0;
+ int is_word = 0;
+
+ for (i = 0; i < limit && line[i] != NUL; )
+ {
+ if (is_word)
+ {
+ if (vim_isspace(line[i]))
+ {
+ words++;
+ is_word = 0;
+ }
+ }
+ else if (!vim_isspace(line[i]))
+ is_word = 1;
+ ++chars;
+ i += (*mb_ptr2len)(line + i);
+ }
+
+ if (is_word)
+ words++;
+ *wc += words;
+
+ /* Add eol_size if the end of line was reached before hitting limit. */
+ if (i < limit && line[i] == NUL)
+ {
+ i += eol_size;
+ chars += eol_size;
+ }
+ *cc += chars;
+ return i;
+}
+
+/*
+ * Give some info about the position of the cursor (for "g CTRL-G").
+ * In Visual mode, give some info about the selected region. (In this case,
+ * the *_count_cursor variables store running totals for the selection.)
+ * When "dict" is not NULL store the info there instead of showing it.
+ */
+ void
+cursor_pos_info(dict_T *dict)
+{
+ char_u *p;
+ char_u buf1[50];
+ char_u buf2[40];
+ linenr_T lnum;
+ varnumber_T byte_count = 0;
+ varnumber_T bom_count = 0;
+ varnumber_T byte_count_cursor = 0;
+ varnumber_T char_count = 0;
+ varnumber_T char_count_cursor = 0;
+ varnumber_T word_count = 0;
+ varnumber_T word_count_cursor = 0;
+ int eol_size;
+ varnumber_T last_check = 100000L;
+ long line_count_selected = 0;
+ pos_T min_pos, max_pos;
+ oparg_T oparg;
+ struct block_def bd;
+
+ /*
+ * Compute the length of the file in characters.
+ */
+ if (curbuf->b_ml.ml_flags & ML_EMPTY)
+ {
+ if (dict == NULL)
+ {
+ msg(_(no_lines_msg));
+ return;
+ }
+ }
+ else
+ {
+ if (get_fileformat(curbuf) == EOL_DOS)
+ eol_size = 2;
+ else
+ eol_size = 1;
+
+ if (VIsual_active)
+ {
+ if (LT_POS(VIsual, curwin->w_cursor))
+ {
+ min_pos = VIsual;
+ max_pos = curwin->w_cursor;
+ }
+ else
+ {
+ min_pos = curwin->w_cursor;
+ max_pos = VIsual;
+ }
+ if (*p_sel == 'e' && max_pos.col > 0)
+ --max_pos.col;
+
+ if (VIsual_mode == Ctrl_V)
+ {
+#ifdef FEAT_LINEBREAK
+ char_u * saved_sbr = p_sbr;
+
+ /* Make 'sbr' empty for a moment to get the correct size. */
+ p_sbr = empty_option;
+#endif
+ oparg.is_VIsual = 1;
+ oparg.block_mode = TRUE;
+ oparg.op_type = OP_NOP;
+ getvcols(curwin, &min_pos, &max_pos,
+ &oparg.start_vcol, &oparg.end_vcol);
+#ifdef FEAT_LINEBREAK
+ p_sbr = saved_sbr;
+#endif
+ if (curwin->w_curswant == MAXCOL)
+ oparg.end_vcol = MAXCOL;
+ /* Swap the start, end vcol if needed */
+ if (oparg.end_vcol < oparg.start_vcol)
+ {
+ oparg.end_vcol += oparg.start_vcol;
+ oparg.start_vcol = oparg.end_vcol - oparg.start_vcol;
+ oparg.end_vcol -= oparg.start_vcol;
+ }
+ }
+ line_count_selected = max_pos.lnum - min_pos.lnum + 1;
+ }
+
+ for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count; ++lnum)
+ {
+ /* Check for a CTRL-C every 100000 characters. */
+ if (byte_count > last_check)
+ {
+ ui_breakcheck();
+ if (got_int)
+ return;
+ last_check = byte_count + 100000L;
+ }
+
+ /* Do extra processing for VIsual mode. */
+ if (VIsual_active
+ && lnum >= min_pos.lnum && lnum <= max_pos.lnum)
+ {
+ char_u *s = NULL;
+ long len = 0L;
+
+ switch (VIsual_mode)
+ {
+ case Ctrl_V:
+ virtual_op = virtual_active();
+ block_prep(&oparg, &bd, lnum, 0);
+ virtual_op = MAYBE;
+ s = bd.textstart;
+ len = (long)bd.textlen;
+ break;
+ case 'V':
+ s = ml_get(lnum);
+ len = MAXCOL;
+ break;
+ case 'v':
+ {
+ colnr_T start_col = (lnum == min_pos.lnum)
+ ? min_pos.col : 0;
+ colnr_T end_col = (lnum == max_pos.lnum)
+ ? max_pos.col - start_col + 1 : MAXCOL;
+
+ s = ml_get(lnum) + start_col;
+ len = end_col;
+ }
+ break;
+ }
+ if (s != NULL)
+ {
+ byte_count_cursor += line_count_info(s, &word_count_cursor,
+ &char_count_cursor, len, eol_size);
+ if (lnum == curbuf->b_ml.ml_line_count
+ && !curbuf->b_p_eol
+ && (curbuf->b_p_bin || !curbuf->b_p_fixeol)
+ && (long)STRLEN(s) < len)
+ byte_count_cursor -= eol_size;
+ }
+ }
+ else
+ {
+ /* In non-visual mode, check for the line the cursor is on */
+ if (lnum == curwin->w_cursor.lnum)
+ {
+ word_count_cursor += word_count;
+ char_count_cursor += char_count;
+ byte_count_cursor = byte_count +
+ line_count_info(ml_get(lnum),
+ &word_count_cursor, &char_count_cursor,
+ (varnumber_T)(curwin->w_cursor.col + 1),
+ eol_size);
+ }
+ }
+ /* Add to the running totals */
+ byte_count += line_count_info(ml_get(lnum), &word_count,
+ &char_count, (varnumber_T)MAXCOL,
+ eol_size);
+ }
+
+ /* Correction for when last line doesn't have an EOL. */
+ if (!curbuf->b_p_eol && (curbuf->b_p_bin || !curbuf->b_p_fixeol))
+ byte_count -= eol_size;
+
+ if (dict == NULL)
+ {
+ if (VIsual_active)
+ {
+ if (VIsual_mode == Ctrl_V && curwin->w_curswant < MAXCOL)
+ {
+ getvcols(curwin, &min_pos, &max_pos, &min_pos.col,
+ &max_pos.col);
+ vim_snprintf((char *)buf1, sizeof(buf1), _("%ld Cols; "),
+ (long)(oparg.end_vcol - oparg.start_vcol + 1));
+ }
+ else
+ buf1[0] = NUL;
+
+ if (char_count_cursor == byte_count_cursor
+ && char_count == byte_count)
+ vim_snprintf((char *)IObuff, IOSIZE,
+ _("Selected %s%ld of %ld Lines; %lld of %lld Words; %lld of %lld Bytes"),
+ buf1, line_count_selected,
+ (long)curbuf->b_ml.ml_line_count,
+ (long_long_T)word_count_cursor,
+ (long_long_T)word_count,
+ (long_long_T)byte_count_cursor,
+ (long_long_T)byte_count);
+ else
+ vim_snprintf((char *)IObuff, IOSIZE,
+ _("Selected %s%ld of %ld Lines; %lld of %lld Words; %lld of %lld Chars; %lld of %lld Bytes"),
+ buf1, line_count_selected,
+ (long)curbuf->b_ml.ml_line_count,
+ (long_long_T)word_count_cursor,
+ (long_long_T)word_count,
+ (long_long_T)char_count_cursor,
+ (long_long_T)char_count,
+ (long_long_T)byte_count_cursor,
+ (long_long_T)byte_count);
+ }
+ else
+ {
+ p = ml_get_curline();
+ validate_virtcol();
+ col_print(buf1, sizeof(buf1), (int)curwin->w_cursor.col + 1,
+ (int)curwin->w_virtcol + 1);
+ col_print(buf2, sizeof(buf2), (int)STRLEN(p),
+ linetabsize(p));
+
+ if (char_count_cursor == byte_count_cursor
+ && char_count == byte_count)
+ vim_snprintf((char *)IObuff, IOSIZE,
+ _("Col %s of %s; Line %ld of %ld; Word %lld of %lld; Byte %lld of %lld"),
+ (char *)buf1, (char *)buf2,
+ (long)curwin->w_cursor.lnum,
+ (long)curbuf->b_ml.ml_line_count,
+ (long_long_T)word_count_cursor, (long_long_T)word_count,
+ (long_long_T)byte_count_cursor, (long_long_T)byte_count);
+ else
+ vim_snprintf((char *)IObuff, IOSIZE,
+ _("Col %s of %s; Line %ld of %ld; Word %lld of %lld; Char %lld of %lld; Byte %lld of %lld"),
+ (char *)buf1, (char *)buf2,
+ (long)curwin->w_cursor.lnum,
+ (long)curbuf->b_ml.ml_line_count,
+ (long_long_T)word_count_cursor, (long_long_T)word_count,
+ (long_long_T)char_count_cursor, (long_long_T)char_count,
+ (long_long_T)byte_count_cursor, (long_long_T)byte_count);
+ }
+ }
+
+ bom_count = bomb_size();
+ if (bom_count > 0)
+ vim_snprintf((char *)IObuff + STRLEN(IObuff), IOSIZE,
+ _("(+%lld for BOM)"), (long_long_T)bom_count);
+ if (dict == NULL)
+ {
+ /* Don't shorten this message, the user asked for it. */
+ p = p_shm;
+ p_shm = (char_u *)"";
+ msg((char *)IObuff);
+ p_shm = p;
+ }
+ }
+#if defined(FEAT_EVAL)
+ if (dict != NULL)
+ {
+ dict_add_number(dict, "words", word_count);
+ dict_add_number(dict, "chars", char_count);
+ dict_add_number(dict, "bytes", byte_count + bom_count);
+ dict_add_number(dict, VIsual_active ? "visual_bytes" : "cursor_bytes",
+ byte_count_cursor);
+ dict_add_number(dict, VIsual_active ? "visual_chars" : "cursor_chars",
+ char_count_cursor);
+ dict_add_number(dict, VIsual_active ? "visual_words" : "cursor_words",
+ word_count_cursor);
+ }
+#endif
+}
diff --git a/src/option.c b/src/option.c
new file mode 100644
index 0000000..77d1024
--- /dev/null
+++ b/src/option.c
@@ -0,0 +1,13378 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * Code to handle user-settable options. This is all pretty much table-
+ * driven. Checklist for adding a new option:
+ * - Put it in the options array below (copy an existing entry).
+ * - For a global option: Add a variable for it in option.h.
+ * - For a buffer or window local option:
+ * - Add a PV_XX entry to the enum below.
+ * - Add a variable to the window or buffer struct in structs.h.
+ * - For a window option, add some code to copy_winopt().
+ * - For a buffer option, add some code to buf_copy_options().
+ * - For a buffer string option, add code to check_buf_options().
+ * - If it's a numeric option, add any necessary bounds checks to do_set().
+ * - If it's a list of flags, add some code in do_set(), search for WW_ALL.
+ * - When adding an option with expansion (P_EXPAND), but with a different
+ * default for Vi and Vim (no P_VI_DEF), add some code at VIMEXP.
+ * - Add documentation! One line in doc/quickref.txt, full description in
+ * options.txt, and any other related places.
+ * - Add an entry in runtime/optwin.vim.
+ * When making changes:
+ * - Adjust the help for the option in doc/option.txt.
+ * - When an entry has the P_VIM flag, or is lacking the P_VI_DEF flag, add a
+ * comment at the help for the 'compatible' option.
+ */
+
+#define IN_OPTION_C
+#include "vim.h"
+
+/*
+ * The options that are local to a window or buffer have "indir" set to one of
+ * these values. Special values:
+ * PV_NONE: global option.
+ * PV_WIN is added: window-local option
+ * PV_BUF is added: buffer-local option
+ * PV_BOTH is added: global option which also has a local value.
+ */
+#define PV_BOTH 0x1000
+#define PV_WIN 0x2000
+#define PV_BUF 0x4000
+#define PV_MASK 0x0fff
+#define OPT_WIN(x) (idopt_T)(PV_WIN + (int)(x))
+#define OPT_BUF(x) (idopt_T)(PV_BUF + (int)(x))
+#define OPT_BOTH(x) (idopt_T)(PV_BOTH + (int)(x))
+
+/*
+ * Definition of the PV_ values for buffer-local options.
+ * The BV_ values are defined in option.h.
+ */
+#define PV_AI OPT_BUF(BV_AI)
+#define PV_AR OPT_BOTH(OPT_BUF(BV_AR))
+#define PV_BKC OPT_BOTH(OPT_BUF(BV_BKC))
+#define PV_BH OPT_BUF(BV_BH)
+#define PV_BT OPT_BUF(BV_BT)
+#ifdef FEAT_QUICKFIX
+# define PV_EFM OPT_BOTH(OPT_BUF(BV_EFM))
+# define PV_GP OPT_BOTH(OPT_BUF(BV_GP))
+# define PV_MP OPT_BOTH(OPT_BUF(BV_MP))
+#endif
+#define PV_BIN OPT_BUF(BV_BIN)
+#define PV_BL OPT_BUF(BV_BL)
+#define PV_BOMB OPT_BUF(BV_BOMB)
+#define PV_CI OPT_BUF(BV_CI)
+#ifdef FEAT_CINDENT
+# define PV_CIN OPT_BUF(BV_CIN)
+# define PV_CINK OPT_BUF(BV_CINK)
+# define PV_CINO OPT_BUF(BV_CINO)
+#endif
+#if defined(FEAT_SMARTINDENT) || defined(FEAT_CINDENT)
+# define PV_CINW OPT_BUF(BV_CINW)
+#endif
+#define PV_CM OPT_BOTH(OPT_BUF(BV_CM))
+#ifdef FEAT_FOLDING
+# define PV_CMS OPT_BUF(BV_CMS)
+#endif
+#ifdef FEAT_COMMENTS
+# define PV_COM OPT_BUF(BV_COM)
+#endif
+#ifdef FEAT_INS_EXPAND
+# define PV_CPT OPT_BUF(BV_CPT)
+# define PV_DICT OPT_BOTH(OPT_BUF(BV_DICT))
+# define PV_TSR OPT_BOTH(OPT_BUF(BV_TSR))
+#endif
+#ifdef FEAT_COMPL_FUNC
+# define PV_CFU OPT_BUF(BV_CFU)
+#endif
+#ifdef FEAT_FIND_ID
+# define PV_DEF OPT_BOTH(OPT_BUF(BV_DEF))
+# define PV_INC OPT_BOTH(OPT_BUF(BV_INC))
+#endif
+#define PV_EOL OPT_BUF(BV_EOL)
+#define PV_FIXEOL OPT_BUF(BV_FIXEOL)
+#define PV_EP OPT_BOTH(OPT_BUF(BV_EP))
+#define PV_ET OPT_BUF(BV_ET)
+#define PV_FENC OPT_BUF(BV_FENC)
+#if defined(FEAT_BEVAL) && defined(FEAT_EVAL)
+# define PV_BEXPR OPT_BOTH(OPT_BUF(BV_BEXPR))
+#endif
+#define PV_FP OPT_BOTH(OPT_BUF(BV_FP))
+#ifdef FEAT_EVAL
+# define PV_FEX OPT_BUF(BV_FEX)
+#endif
+#define PV_FF OPT_BUF(BV_FF)
+#define PV_FLP OPT_BUF(BV_FLP)
+#define PV_FO OPT_BUF(BV_FO)
+#define PV_FT OPT_BUF(BV_FT)
+#define PV_IMI OPT_BUF(BV_IMI)
+#define PV_IMS OPT_BUF(BV_IMS)
+#if defined(FEAT_CINDENT) && defined(FEAT_EVAL)
+# define PV_INDE OPT_BUF(BV_INDE)
+# define PV_INDK OPT_BUF(BV_INDK)
+#endif
+#if defined(FEAT_FIND_ID) && defined(FEAT_EVAL)
+# define PV_INEX OPT_BUF(BV_INEX)
+#endif
+#define PV_INF OPT_BUF(BV_INF)
+#define PV_ISK OPT_BUF(BV_ISK)
+#ifdef FEAT_CRYPT
+# define PV_KEY OPT_BUF(BV_KEY)
+#endif
+#ifdef FEAT_KEYMAP
+# define PV_KMAP OPT_BUF(BV_KMAP)
+#endif
+#define PV_KP OPT_BOTH(OPT_BUF(BV_KP))
+#ifdef FEAT_LISP
+# define PV_LISP OPT_BUF(BV_LISP)
+# define PV_LW OPT_BOTH(OPT_BUF(BV_LW))
+#endif
+#define PV_MENC OPT_BOTH(OPT_BUF(BV_MENC))
+#define PV_MA OPT_BUF(BV_MA)
+#define PV_ML OPT_BUF(BV_ML)
+#define PV_MOD OPT_BUF(BV_MOD)
+#define PV_MPS OPT_BUF(BV_MPS)
+#define PV_NF OPT_BUF(BV_NF)
+#ifdef FEAT_COMPL_FUNC
+# define PV_OFU OPT_BUF(BV_OFU)
+#endif
+#define PV_PATH OPT_BOTH(OPT_BUF(BV_PATH))
+#define PV_PI OPT_BUF(BV_PI)
+#ifdef FEAT_TEXTOBJ
+# define PV_QE OPT_BUF(BV_QE)
+#endif
+#define PV_RO OPT_BUF(BV_RO)
+#ifdef FEAT_SMARTINDENT
+# define PV_SI OPT_BUF(BV_SI)
+#endif
+#define PV_SN OPT_BUF(BV_SN)
+#ifdef FEAT_SYN_HL
+# define PV_SMC OPT_BUF(BV_SMC)
+# define PV_SYN OPT_BUF(BV_SYN)
+#endif
+#ifdef FEAT_SPELL
+# define PV_SPC OPT_BUF(BV_SPC)
+# define PV_SPF OPT_BUF(BV_SPF)
+# define PV_SPL OPT_BUF(BV_SPL)
+#endif
+#define PV_STS OPT_BUF(BV_STS)
+#ifdef FEAT_SEARCHPATH
+# define PV_SUA OPT_BUF(BV_SUA)
+#endif
+#define PV_SW OPT_BUF(BV_SW)
+#define PV_SWF OPT_BUF(BV_SWF)
+#define PV_TAGS OPT_BOTH(OPT_BUF(BV_TAGS))
+#define PV_TC OPT_BOTH(OPT_BUF(BV_TC))
+#define PV_TS OPT_BUF(BV_TS)
+#define PV_TW OPT_BUF(BV_TW)
+#define PV_TX OPT_BUF(BV_TX)
+#ifdef FEAT_PERSISTENT_UNDO
+# define PV_UDF OPT_BUF(BV_UDF)
+#endif
+#define PV_WM OPT_BUF(BV_WM)
+#ifdef FEAT_VARTABS
+# define PV_VSTS OPT_BUF(BV_VSTS)
+# define PV_VTS OPT_BUF(BV_VTS)
+#endif
+
+/*
+ * Definition of the PV_ values for window-local options.
+ * The WV_ values are defined in option.h.
+ */
+#define PV_LIST OPT_WIN(WV_LIST)
+#ifdef FEAT_ARABIC
+# define PV_ARAB OPT_WIN(WV_ARAB)
+#endif
+#ifdef FEAT_LINEBREAK
+# define PV_BRI OPT_WIN(WV_BRI)
+# define PV_BRIOPT OPT_WIN(WV_BRIOPT)
+#endif
+#ifdef FEAT_DIFF
+# define PV_DIFF OPT_WIN(WV_DIFF)
+#endif
+#ifdef FEAT_FOLDING
+# define PV_FDC OPT_WIN(WV_FDC)
+# define PV_FEN OPT_WIN(WV_FEN)
+# define PV_FDI OPT_WIN(WV_FDI)
+# define PV_FDL OPT_WIN(WV_FDL)
+# define PV_FDM OPT_WIN(WV_FDM)
+# define PV_FML OPT_WIN(WV_FML)
+# define PV_FDN OPT_WIN(WV_FDN)
+# ifdef FEAT_EVAL
+# define PV_FDE OPT_WIN(WV_FDE)
+# define PV_FDT OPT_WIN(WV_FDT)
+# endif
+# define PV_FMR OPT_WIN(WV_FMR)
+#endif
+#ifdef FEAT_LINEBREAK
+# define PV_LBR OPT_WIN(WV_LBR)
+#endif
+#define PV_NU OPT_WIN(WV_NU)
+#define PV_RNU OPT_WIN(WV_RNU)
+#ifdef FEAT_LINEBREAK
+# define PV_NUW OPT_WIN(WV_NUW)
+#endif
+#if defined(FEAT_QUICKFIX)
+# define PV_PVW OPT_WIN(WV_PVW)
+#endif
+#ifdef FEAT_RIGHTLEFT
+# define PV_RL OPT_WIN(WV_RL)
+# define PV_RLC OPT_WIN(WV_RLC)
+#endif
+#define PV_SCBIND OPT_WIN(WV_SCBIND)
+#define PV_SCROLL OPT_WIN(WV_SCROLL)
+#define PV_SISO OPT_BOTH(OPT_WIN(WV_SISO))
+#define PV_SO OPT_BOTH(OPT_WIN(WV_SO))
+#ifdef FEAT_SPELL
+# define PV_SPELL OPT_WIN(WV_SPELL)
+#endif
+#ifdef FEAT_SYN_HL
+# define PV_CUC OPT_WIN(WV_CUC)
+# define PV_CUL OPT_WIN(WV_CUL)
+# define PV_CC OPT_WIN(WV_CC)
+#endif
+#ifdef FEAT_STL_OPT
+# define PV_STL OPT_BOTH(OPT_WIN(WV_STL))
+#endif
+#define PV_UL OPT_BOTH(OPT_BUF(BV_UL))
+# define PV_WFH OPT_WIN(WV_WFH)
+# define PV_WFW OPT_WIN(WV_WFW)
+#define PV_WRAP OPT_WIN(WV_WRAP)
+#define PV_CRBIND OPT_WIN(WV_CRBIND)
+#ifdef FEAT_CONCEAL
+# define PV_COCU OPT_WIN(WV_COCU)
+# define PV_COLE OPT_WIN(WV_COLE)
+#endif
+#ifdef FEAT_TERMINAL
+# define PV_TWK OPT_WIN(WV_TWK)
+# define PV_TWS OPT_WIN(WV_TWS)
+# define PV_TWSL OPT_BUF(BV_TWSL)
+# define PV_TMOD OPT_WIN(WV_TMOD)
+#endif
+#ifdef FEAT_SIGNS
+# define PV_SCL OPT_WIN(WV_SCL)
+#endif
+
+/* WV_ and BV_ values get typecasted to this for the "indir" field */
+typedef enum
+{
+ PV_NONE = 0,
+ PV_MAXVAL = 0xffff /* to avoid warnings for value out of range */
+} idopt_T;
+
+/*
+ * Options local to a window have a value local to a buffer and global to all
+ * buffers. Indicate this by setting "var" to VAR_WIN.
+ */
+#define VAR_WIN ((char_u *)-1)
+
+/*
+ * These are the global values for options which are also local to a buffer.
+ * Only to be used in option.c!
+ */
+static int p_ai;
+static int p_bin;
+static int p_bomb;
+static char_u *p_bh;
+static char_u *p_bt;
+static int p_bl;
+static int p_ci;
+#ifdef FEAT_CINDENT
+static int p_cin;
+static char_u *p_cink;
+static char_u *p_cino;
+#endif
+#if defined(FEAT_SMARTINDENT) || defined(FEAT_CINDENT)
+static char_u *p_cinw;
+#endif
+#ifdef FEAT_COMMENTS
+static char_u *p_com;
+#endif
+#ifdef FEAT_FOLDING
+static char_u *p_cms;
+#endif
+#ifdef FEAT_INS_EXPAND
+static char_u *p_cpt;
+#endif
+#ifdef FEAT_COMPL_FUNC
+static char_u *p_cfu;
+static char_u *p_ofu;
+#endif
+static int p_eol;
+static int p_fixeol;
+static int p_et;
+static char_u *p_fenc;
+static char_u *p_ff;
+static char_u *p_fo;
+static char_u *p_flp;
+static char_u *p_ft;
+static long p_iminsert;
+static long p_imsearch;
+#if defined(FEAT_FIND_ID) && defined(FEAT_EVAL)
+static char_u *p_inex;
+#endif
+#if defined(FEAT_CINDENT) && defined(FEAT_EVAL)
+static char_u *p_inde;
+static char_u *p_indk;
+#endif
+#if defined(FEAT_EVAL)
+static char_u *p_fex;
+#endif
+static int p_inf;
+static char_u *p_isk;
+#ifdef FEAT_CRYPT
+static char_u *p_key;
+#endif
+#ifdef FEAT_LISP
+static int p_lisp;
+#endif
+static int p_ml;
+static int p_ma;
+static int p_mod;
+static char_u *p_mps;
+static char_u *p_nf;
+static int p_pi;
+#ifdef FEAT_TEXTOBJ
+static char_u *p_qe;
+#endif
+static int p_ro;
+#ifdef FEAT_SMARTINDENT
+static int p_si;
+#endif
+static int p_sn;
+static long p_sts;
+#if defined(FEAT_SEARCHPATH)
+static char_u *p_sua;
+#endif
+static long p_sw;
+static int p_swf;
+#ifdef FEAT_SYN_HL
+static long p_smc;
+static char_u *p_syn;
+#endif
+#ifdef FEAT_SPELL
+static char_u *p_spc;
+static char_u *p_spf;
+static char_u *p_spl;
+#endif
+static long p_ts;
+static long p_tw;
+static int p_tx;
+#ifdef FEAT_PERSISTENT_UNDO
+static int p_udf;
+#endif
+static long p_wm;
+#ifdef FEAT_VARTABS
+static char_u *p_vsts;
+static char_u *p_vts;
+#endif
+#ifdef FEAT_KEYMAP
+static char_u *p_keymap;
+#endif
+#ifdef FEAT_TERMINAL
+static long p_twsl; /* 'termwinscroll' */
+#endif
+
+/* Saved values for when 'bin' is set. */
+static int p_et_nobin;
+static int p_ml_nobin;
+static long p_tw_nobin;
+static long p_wm_nobin;
+
+/* Saved values for when 'paste' is set */
+static int p_ai_nopaste;
+static int p_et_nopaste;
+static long p_sts_nopaste;
+static long p_tw_nopaste;
+static long p_wm_nopaste;
+#ifdef FEAT_VARTABS
+static char_u *p_vsts_nopaste;
+#endif
+
+struct vimoption
+{
+ char *fullname; // full option name
+ char *shortname; // permissible abbreviation
+ long_u flags; // see below
+ char_u *var; // global option: pointer to variable;
+ // window-local option: VAR_WIN;
+ // buffer-local option: global value
+ idopt_T indir; // global option: PV_NONE;
+ // local option: indirect option index
+ char_u *def_val[2]; // default values for variable (vi and vim)
+#ifdef FEAT_EVAL
+ sctx_T script_ctx; // script context where the option was last set
+# define SCTX_INIT , {0, 0, 0}
+#else
+# define SCTX_INIT
+#endif
+};
+
+#define VI_DEFAULT 0 /* def_val[VI_DEFAULT] is Vi default value */
+#define VIM_DEFAULT 1 /* def_val[VIM_DEFAULT] is Vim default value */
+
+/*
+ * Flags
+ */
+#define P_BOOL 0x01 /* the option is boolean */
+#define P_NUM 0x02 /* the option is numeric */
+#define P_STRING 0x04 /* the option is a string */
+#define P_ALLOCED 0x08 /* the string option is in allocated memory,
+ must use free_string_option() when
+ assigning new value. Not set if default is
+ the same. */
+#define P_EXPAND 0x10 /* environment expansion. NOTE: P_EXPAND can
+ never be used for local or hidden options! */
+#define P_NODEFAULT 0x40 /* don't set to default value */
+#define P_DEF_ALLOCED 0x80 /* default value is in allocated memory, must
+ use vim_free() when assigning new value */
+#define P_WAS_SET 0x100 /* option has been set/reset */
+#define P_NO_MKRC 0x200 /* don't include in :mkvimrc output */
+#define P_VI_DEF 0x400 /* Use Vi default for Vim */
+#define P_VIM 0x800 /* Vim option, reset when 'cp' set */
+
+ /* when option changed, what to display: */
+#define P_RSTAT 0x1000 /* redraw status lines */
+#define P_RWIN 0x2000 /* redraw current window and recompute text */
+#define P_RBUF 0x4000 /* redraw current buffer and recompute text */
+#define P_RALL 0x6000 /* redraw all windows */
+#define P_RCLR 0x7000 /* clear and redraw all */
+
+#define P_COMMA 0x8000 /* comma separated list */
+#define P_ONECOMMA 0x18000L /* P_COMMA and cannot have two consecutive
+ * commas */
+#define P_NODUP 0x20000L /* don't allow duplicate strings */
+#define P_FLAGLIST 0x40000L /* list of single-char flags */
+
+#define P_SECURE 0x80000L /* cannot change in modeline or secure mode */
+#define P_GETTEXT 0x100000L /* expand default value with _() */
+#define P_NOGLOB 0x200000L /* do not use local value for global vimrc */
+#define P_NFNAME 0x400000L /* only normal file name chars allowed */
+#define P_INSECURE 0x800000L /* option was set from a modeline */
+#define P_PRI_MKRC 0x1000000L /* priority for :mkvimrc (setting option has
+ side effects) */
+#define P_NO_ML 0x2000000L /* not allowed in modeline */
+#define P_CURSWANT 0x4000000L /* update curswant required; not needed when
+ * there is a redraw flag */
+#define P_NDNAME 0x8000000L /* only normal dir name chars allowed */
+#define P_RWINONLY 0x10000000L /* only redraw current window */
+
+#define ISK_LATIN1 (char_u *)"@,48-57,_,192-255"
+
+/* 'isprint' for latin1 is also used for MS-Windows cp1252, where 0x80 is used
+ * for the currency sign. */
+#if defined(MSWIN)
+# define ISP_LATIN1 (char_u *)"@,~-255"
+#else
+# define ISP_LATIN1 (char_u *)"@,161-255"
+#endif
+
+# define HIGHLIGHT_INIT "8:SpecialKey,~:EndOfBuffer,@:NonText,d:Directory,e:ErrorMsg,i:IncSearch,l:Search,m:MoreMsg,M:ModeMsg,n:LineNr,N:CursorLineNr,r:Question,s:StatusLine,S:StatusLineNC,c:VertSplit,t:Title,v:Visual,V:VisualNOS,w:WarningMsg,W:WildMenu,f:Folded,F:FoldColumn,A:DiffAdd,C:DiffChange,D:DiffDelete,T:DiffText,>:SignColumn,-:Conceal,B:SpellBad,P:SpellCap,R:SpellRare,L:SpellLocal,+:Pmenu,=:PmenuSel,x:PmenuSbar,X:PmenuThumb,*:TabLine,#:TabLineSel,_:TabLineFill,!:CursorColumn,.:CursorLine,o:ColorColumn,q:QuickFixLine,z:StatusLineTerm,Z:StatusLineTermNC"
+
+/* Default python version for pyx* commands */
+#if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
+# define DEFAULT_PYTHON_VER 0
+#elif defined(FEAT_PYTHON3)
+# define DEFAULT_PYTHON_VER 3
+#elif defined(FEAT_PYTHON)
+# define DEFAULT_PYTHON_VER 2
+#else
+# define DEFAULT_PYTHON_VER 0
+#endif
+
+// used for 'cinkeys' and 'indentkeys'
+#define INDENTKEYS_DEFAULT (char_u *)"0{,0},0),0],:,0#,!^F,o,O,e"
+
+/*
+ * options[] is initialized here.
+ * The order of the options MUST be alphabetic for ":set all" and findoption().
+ * All option names MUST start with a lowercase letter (for findoption()).
+ * Exception: "t_" options are at the end.
+ * The options with a NULL variable are 'hidden': a set command for them is
+ * ignored and they are not printed.
+ */
+static struct vimoption options[] =
+{
+ {"aleph", "al", P_NUM|P_VI_DEF|P_CURSWANT,
+#ifdef FEAT_RIGHTLEFT
+ (char_u *)&p_aleph, PV_NONE,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {
+#if (defined(WIN3264)) && !defined(FEAT_GUI_W32)
+ (char_u *)128L,
+#else
+ (char_u *)224L,
+#endif
+ (char_u *)0L} SCTX_INIT},
+ {"antialias", "anti", P_BOOL|P_VI_DEF|P_VIM|P_RCLR,
+#if defined(FEAT_GUI_MAC)
+ (char_u *)&p_antialias, PV_NONE,
+ {(char_u *)FALSE, (char_u *)FALSE}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)FALSE, (char_u *)FALSE}
+#endif
+ SCTX_INIT},
+ {"arabic", "arab", P_BOOL|P_VI_DEF|P_VIM|P_CURSWANT,
+#ifdef FEAT_ARABIC
+ (char_u *)VAR_WIN, PV_ARAB,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"arabicshape", "arshape", P_BOOL|P_VI_DEF|P_VIM|P_RCLR,
+#ifdef FEAT_ARABIC
+ (char_u *)&p_arshape, PV_NONE,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)TRUE, (char_u *)0L} SCTX_INIT},
+ {"allowrevins", "ari", P_BOOL|P_VI_DEF|P_VIM,
+#ifdef FEAT_RIGHTLEFT
+ (char_u *)&p_ari, PV_NONE,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"altkeymap", "akm", P_BOOL|P_VI_DEF,
+#ifdef FEAT_FKMAP
+ (char_u *)&p_altkeymap, PV_NONE,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"ambiwidth", "ambw", P_STRING|P_VI_DEF|P_RCLR,
+ (char_u *)&p_ambw, PV_NONE,
+ {(char_u *)"single", (char_u *)0L}
+ SCTX_INIT},
+ {"autochdir", "acd", P_BOOL|P_VI_DEF,
+#ifdef FEAT_AUTOCHDIR
+ (char_u *)&p_acd, PV_NONE,
+ {(char_u *)FALSE, (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"autoindent", "ai", P_BOOL|P_VI_DEF,
+ (char_u *)&p_ai, PV_AI,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"autoprint", "ap", P_BOOL|P_VI_DEF,
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"autoread", "ar", P_BOOL|P_VI_DEF,
+ (char_u *)&p_ar, PV_AR,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"autowrite", "aw", P_BOOL|P_VI_DEF,
+ (char_u *)&p_aw, PV_NONE,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"autowriteall","awa", P_BOOL|P_VI_DEF,
+ (char_u *)&p_awa, PV_NONE,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"background", "bg", P_STRING|P_VI_DEF|P_RCLR,
+ (char_u *)&p_bg, PV_NONE,
+ {
+#if (defined(WIN3264)) && !defined(FEAT_GUI)
+ (char_u *)"dark",
+#else
+ (char_u *)"light",
+#endif
+ (char_u *)0L} SCTX_INIT},
+ {"backspace", "bs", P_STRING|P_VI_DEF|P_VIM|P_ONECOMMA|P_NODUP,
+ (char_u *)&p_bs, PV_NONE,
+ {(char_u *)"", (char_u *)0L} SCTX_INIT},
+ {"backup", "bk", P_BOOL|P_VI_DEF|P_VIM,
+ (char_u *)&p_bk, PV_NONE,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"backupcopy", "bkc", P_STRING|P_VIM|P_ONECOMMA|P_NODUP,
+ (char_u *)&p_bkc, PV_BKC,
+#ifdef UNIX
+ {(char_u *)"yes", (char_u *)"auto"}
+#else
+ {(char_u *)"auto", (char_u *)"auto"}
+#endif
+ SCTX_INIT},
+ {"backupdir", "bdir", P_STRING|P_EXPAND|P_VI_DEF|P_ONECOMMA
+ |P_NODUP|P_SECURE,
+ (char_u *)&p_bdir, PV_NONE,
+ {(char_u *)DFLT_BDIR, (char_u *)0L} SCTX_INIT},
+ {"backupext", "bex", P_STRING|P_VI_DEF|P_NFNAME,
+ (char_u *)&p_bex, PV_NONE,
+ {
+#ifdef VMS
+ (char_u *)"_",
+#else
+ (char_u *)"~",
+#endif
+ (char_u *)0L} SCTX_INIT},
+ {"backupskip", "bsk", P_STRING|P_VI_DEF|P_ONECOMMA,
+#ifdef FEAT_WILDIGN
+ (char_u *)&p_bsk, PV_NONE,
+ {(char_u *)"", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"balloondelay","bdlay",P_NUM|P_VI_DEF,
+#ifdef FEAT_BEVAL
+ (char_u *)&p_bdlay, PV_NONE,
+ {(char_u *)600L, (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"ballooneval", "beval",P_BOOL|P_VI_DEF|P_NO_MKRC,
+#ifdef FEAT_BEVAL_GUI
+ (char_u *)&p_beval, PV_NONE,
+ {(char_u *)FALSE, (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"balloonevalterm", "bevalterm",P_BOOL|P_VI_DEF|P_NO_MKRC,
+#ifdef FEAT_BEVAL_TERM
+ (char_u *)&p_bevalterm, PV_NONE,
+ {(char_u *)FALSE, (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"balloonexpr", "bexpr", P_STRING|P_ALLOCED|P_VI_DEF|P_VIM,
+#if defined(FEAT_BEVAL) && defined(FEAT_EVAL)
+ (char_u *)&p_bexpr, PV_BEXPR,
+ {(char_u *)"", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"beautify", "bf", P_BOOL|P_VI_DEF,
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"belloff", "bo", P_STRING|P_VI_DEF|P_COMMA|P_NODUP,
+ (char_u *)&p_bo, PV_NONE,
+ {(char_u *)"", (char_u *)0L} SCTX_INIT},
+ {"binary", "bin", P_BOOL|P_VI_DEF|P_RSTAT,
+ (char_u *)&p_bin, PV_BIN,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"bioskey", "biosk",P_BOOL|P_VI_DEF,
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)TRUE, (char_u *)0L} SCTX_INIT},
+ {"bomb", NULL, P_BOOL|P_NO_MKRC|P_VI_DEF|P_RSTAT,
+ (char_u *)&p_bomb, PV_BOMB,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"breakat", "brk", P_STRING|P_VI_DEF|P_RALL|P_FLAGLIST,
+#ifdef FEAT_LINEBREAK
+ (char_u *)&p_breakat, PV_NONE,
+ {(char_u *)" \t!@*-+;:,./?", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"breakindent", "bri", P_BOOL|P_VI_DEF|P_VIM|P_RWIN,
+#ifdef FEAT_LINEBREAK
+ (char_u *)VAR_WIN, PV_BRI,
+ {(char_u *)FALSE, (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"breakindentopt", "briopt", P_STRING|P_ALLOCED|P_VI_DEF|P_RBUF
+ |P_ONECOMMA|P_NODUP,
+#ifdef FEAT_LINEBREAK
+ (char_u *)VAR_WIN, PV_BRIOPT,
+ {(char_u *)"", (char_u *)NULL}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)"", (char_u *)NULL}
+#endif
+ SCTX_INIT},
+ {"browsedir", "bsdir",P_STRING|P_VI_DEF,
+#ifdef FEAT_BROWSE
+ (char_u *)&p_bsdir, PV_NONE,
+ {(char_u *)"last", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"bufhidden", "bh", P_STRING|P_ALLOCED|P_VI_DEF|P_NOGLOB,
+ (char_u *)&p_bh, PV_BH,
+ {(char_u *)"", (char_u *)0L}
+ SCTX_INIT},
+ {"buflisted", "bl", P_BOOL|P_VI_DEF|P_NOGLOB,
+ (char_u *)&p_bl, PV_BL,
+ {(char_u *)1L, (char_u *)0L}
+ SCTX_INIT},
+ {"buftype", "bt", P_STRING|P_ALLOCED|P_VI_DEF|P_NOGLOB,
+ (char_u *)&p_bt, PV_BT,
+ {(char_u *)"", (char_u *)0L}
+ SCTX_INIT},
+ {"casemap", "cmp", P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP,
+ (char_u *)&p_cmp, PV_NONE,
+ {(char_u *)"internal,keepascii", (char_u *)0L}
+ SCTX_INIT},
+ {"cdpath", "cd", P_STRING|P_EXPAND|P_VI_DEF|P_COMMA|P_NODUP,
+#ifdef FEAT_SEARCHPATH
+ (char_u *)&p_cdpath, PV_NONE,
+ {(char_u *)",,", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"cedit", NULL, P_STRING,
+#ifdef FEAT_CMDWIN
+ (char_u *)&p_cedit, PV_NONE,
+ {(char_u *)"", (char_u *)CTRL_F_STR}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"charconvert", "ccv", P_STRING|P_VI_DEF|P_SECURE,
+#if defined(FEAT_EVAL)
+ (char_u *)&p_ccv, PV_NONE,
+ {(char_u *)"", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"cindent", "cin", P_BOOL|P_VI_DEF|P_VIM,
+#ifdef FEAT_CINDENT
+ (char_u *)&p_cin, PV_CIN,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"cinkeys", "cink", P_STRING|P_ALLOCED|P_VI_DEF|P_ONECOMMA|P_NODUP,
+#ifdef FEAT_CINDENT
+ (char_u *)&p_cink, PV_CINK,
+ {INDENTKEYS_DEFAULT, (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"cinoptions", "cino", P_STRING|P_ALLOCED|P_VI_DEF|P_ONECOMMA|P_NODUP,
+#ifdef FEAT_CINDENT
+ (char_u *)&p_cino, PV_CINO,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)"", (char_u *)0L} SCTX_INIT},
+ {"cinwords", "cinw", P_STRING|P_ALLOCED|P_VI_DEF|P_ONECOMMA|P_NODUP,
+#if defined(FEAT_SMARTINDENT) || defined(FEAT_CINDENT)
+ (char_u *)&p_cinw, PV_CINW,
+ {(char_u *)"if,else,while,do,for,switch",
+ (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"clipboard", "cb", P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP,
+#ifdef FEAT_CLIPBOARD
+ (char_u *)&p_cb, PV_NONE,
+# ifdef FEAT_XCLIPBOARD
+ {(char_u *)"autoselect,exclude:cons\\|linux",
+ (char_u *)0L}
+# else
+ {(char_u *)"", (char_u *)0L}
+# endif
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)"", (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"cmdheight", "ch", P_NUM|P_VI_DEF|P_RALL,
+ (char_u *)&p_ch, PV_NONE,
+ {(char_u *)1L, (char_u *)0L} SCTX_INIT},
+ {"cmdwinheight", "cwh", P_NUM|P_VI_DEF,
+#ifdef FEAT_CMDWIN
+ (char_u *)&p_cwh, PV_NONE,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)7L, (char_u *)0L} SCTX_INIT},
+ {"colorcolumn", "cc", P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP|P_RWIN,
+#ifdef FEAT_SYN_HL
+ (char_u *)VAR_WIN, PV_CC,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)"", (char_u *)0L} SCTX_INIT},
+ {"columns", "co", P_NUM|P_NODEFAULT|P_NO_MKRC|P_VI_DEF|P_RCLR,
+ (char_u *)&Columns, PV_NONE,
+ {(char_u *)80L, (char_u *)0L} SCTX_INIT},
+ {"comments", "com", P_STRING|P_ALLOCED|P_VI_DEF|P_ONECOMMA
+ |P_NODUP|P_CURSWANT,
+#ifdef FEAT_COMMENTS
+ (char_u *)&p_com, PV_COM,
+ {(char_u *)"s1:/*,mb:*,ex:*/,://,b:#,:%,:XCOMM,n:>,fb:-",
+ (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"commentstring", "cms", P_STRING|P_ALLOCED|P_VI_DEF|P_CURSWANT,
+#ifdef FEAT_FOLDING
+ (char_u *)&p_cms, PV_CMS,
+ {(char_u *)"/*%s*/", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ /* P_PRI_MKRC isn't needed here, optval_default()
+ * always returns TRUE for 'compatible' */
+ {"compatible", "cp", P_BOOL|P_RALL,
+ (char_u *)&p_cp, PV_NONE,
+ {(char_u *)TRUE, (char_u *)FALSE} SCTX_INIT},
+ {"complete", "cpt", P_STRING|P_ALLOCED|P_VI_DEF|P_ONECOMMA|P_NODUP,
+#ifdef FEAT_INS_EXPAND
+ (char_u *)&p_cpt, PV_CPT,
+ {(char_u *)".,w,b,u,t,i", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"concealcursor","cocu", P_STRING|P_ALLOCED|P_RWIN|P_VI_DEF,
+#ifdef FEAT_CONCEAL
+ (char_u *)VAR_WIN, PV_COCU,
+ {(char_u *)"", (char_u *)NULL}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"conceallevel","cole", P_NUM|P_RWIN|P_VI_DEF,
+#ifdef FEAT_CONCEAL
+ (char_u *)VAR_WIN, PV_COLE,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)0L, (char_u *)0L}
+ SCTX_INIT},
+ {"completefunc", "cfu", P_STRING|P_ALLOCED|P_VI_DEF|P_SECURE,
+#ifdef FEAT_COMPL_FUNC
+ (char_u *)&p_cfu, PV_CFU,
+ {(char_u *)"", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"completeopt", "cot", P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP,
+#ifdef FEAT_INS_EXPAND
+ (char_u *)&p_cot, PV_NONE,
+ {(char_u *)"menu,preview", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"confirm", "cf", P_BOOL|P_VI_DEF,
+#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
+ (char_u *)&p_confirm, PV_NONE,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"conskey", "consk",P_BOOL|P_VI_DEF,
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"copyindent", "ci", P_BOOL|P_VI_DEF|P_VIM,
+ (char_u *)&p_ci, PV_CI,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"cpoptions", "cpo", P_STRING|P_VIM|P_RALL|P_FLAGLIST,
+ (char_u *)&p_cpo, PV_NONE,
+ {(char_u *)CPO_VI, (char_u *)CPO_VIM}
+ SCTX_INIT},
+ {"cryptmethod", "cm", P_STRING|P_ALLOCED|P_VI_DEF,
+#ifdef FEAT_CRYPT
+ (char_u *)&p_cm, PV_CM,
+ {(char_u *)"blowfish2", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"cscopepathcomp", "cspc", P_NUM|P_VI_DEF|P_VIM,
+#ifdef FEAT_CSCOPE
+ (char_u *)&p_cspc, PV_NONE,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)0L, (char_u *)0L} SCTX_INIT},
+ {"cscopeprg", "csprg", P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
+#ifdef FEAT_CSCOPE
+ (char_u *)&p_csprg, PV_NONE,
+ {(char_u *)"cscope", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"cscopequickfix", "csqf", P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP,
+#if defined(FEAT_CSCOPE) && defined(FEAT_QUICKFIX)
+ (char_u *)&p_csqf, PV_NONE,
+ {(char_u *)"", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"cscoperelative", "csre", P_BOOL|P_VI_DEF|P_VIM,
+#ifdef FEAT_CSCOPE
+ (char_u *)&p_csre, PV_NONE,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)0L, (char_u *)0L} SCTX_INIT},
+ {"cscopetag", "cst", P_BOOL|P_VI_DEF|P_VIM,
+#ifdef FEAT_CSCOPE
+ (char_u *)&p_cst, PV_NONE,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)0L, (char_u *)0L} SCTX_INIT},
+ {"cscopetagorder", "csto", P_NUM|P_VI_DEF|P_VIM,
+#ifdef FEAT_CSCOPE
+ (char_u *)&p_csto, PV_NONE,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)0L, (char_u *)0L} SCTX_INIT},
+ {"cscopeverbose", "csverb", P_BOOL|P_VI_DEF|P_VIM,
+#ifdef FEAT_CSCOPE
+ (char_u *)&p_csverbose, PV_NONE,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)0L, (char_u *)0L} SCTX_INIT},
+ {"cursorbind", "crb", P_BOOL|P_VI_DEF,
+ (char_u *)VAR_WIN, PV_CRBIND,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"cursorcolumn", "cuc", P_BOOL|P_VI_DEF|P_RWINONLY,
+#ifdef FEAT_SYN_HL
+ (char_u *)VAR_WIN, PV_CUC,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"cursorline", "cul", P_BOOL|P_VI_DEF|P_RWINONLY,
+#ifdef FEAT_SYN_HL
+ (char_u *)VAR_WIN, PV_CUL,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"debug", NULL, P_STRING|P_VI_DEF,
+ (char_u *)&p_debug, PV_NONE,
+ {(char_u *)"", (char_u *)0L} SCTX_INIT},
+ {"define", "def", P_STRING|P_ALLOCED|P_VI_DEF|P_CURSWANT,
+#ifdef FEAT_FIND_ID
+ (char_u *)&p_def, PV_DEF,
+ {(char_u *)"^\\s*#\\s*define", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"delcombine", "deco", P_BOOL|P_VI_DEF|P_VIM,
+ (char_u *)&p_deco, PV_NONE,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"dictionary", "dict", P_STRING|P_EXPAND|P_VI_DEF|P_ONECOMMA|P_NODUP|P_NDNAME,
+#ifdef FEAT_INS_EXPAND
+ (char_u *)&p_dict, PV_DICT,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)"", (char_u *)0L} SCTX_INIT},
+ {"diff", NULL, P_BOOL|P_VI_DEF|P_RWIN|P_NOGLOB,
+#ifdef FEAT_DIFF
+ (char_u *)VAR_WIN, PV_DIFF,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"diffexpr", "dex", P_STRING|P_VI_DEF|P_SECURE|P_CURSWANT,
+#if defined(FEAT_DIFF) && defined(FEAT_EVAL)
+ (char_u *)&p_dex, PV_NONE,
+ {(char_u *)"", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"diffopt", "dip", P_STRING|P_ALLOCED|P_VI_DEF|P_RWIN|P_ONECOMMA
+ |P_NODUP,
+#ifdef FEAT_DIFF
+ (char_u *)&p_dip, PV_NONE,
+ {(char_u *)"internal,filler", (char_u *)NULL}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)"", (char_u *)NULL}
+#endif
+ SCTX_INIT},
+ {"digraph", "dg", P_BOOL|P_VI_DEF|P_VIM,
+#ifdef FEAT_DIGRAPHS
+ (char_u *)&p_dg, PV_NONE,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"directory", "dir", P_STRING|P_EXPAND|P_VI_DEF|P_ONECOMMA
+ |P_NODUP|P_SECURE,
+ (char_u *)&p_dir, PV_NONE,
+ {(char_u *)DFLT_DIR, (char_u *)0L} SCTX_INIT},
+ {"display", "dy", P_STRING|P_VI_DEF|P_ONECOMMA|P_RALL|P_NODUP,
+ (char_u *)&p_dy, PV_NONE,
+ {(char_u *)"", (char_u *)0L} SCTX_INIT},
+ {"eadirection", "ead", P_STRING|P_VI_DEF,
+ (char_u *)&p_ead, PV_NONE,
+ {(char_u *)"both", (char_u *)0L}
+ SCTX_INIT},
+ {"edcompatible","ed", P_BOOL|P_VI_DEF,
+ (char_u *)&p_ed, PV_NONE,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"emoji", "emo", P_BOOL|P_VI_DEF|P_RCLR,
+ (char_u *)&p_emoji, PV_NONE,
+ {(char_u *)TRUE, (char_u *)0L}
+ SCTX_INIT},
+ {"encoding", "enc", P_STRING|P_VI_DEF|P_RCLR|P_NO_ML,
+ (char_u *)&p_enc, PV_NONE,
+ {(char_u *)ENC_DFLT, (char_u *)0L}
+ SCTX_INIT},
+ {"endofline", "eol", P_BOOL|P_NO_MKRC|P_VI_DEF|P_RSTAT,
+ (char_u *)&p_eol, PV_EOL,
+ {(char_u *)TRUE, (char_u *)0L} SCTX_INIT},
+ {"equalalways", "ea", P_BOOL|P_VI_DEF|P_RALL,
+ (char_u *)&p_ea, PV_NONE,
+ {(char_u *)TRUE, (char_u *)0L} SCTX_INIT},
+ {"equalprg", "ep", P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
+ (char_u *)&p_ep, PV_EP,
+ {(char_u *)"", (char_u *)0L} SCTX_INIT},
+ {"errorbells", "eb", P_BOOL|P_VI_DEF,
+ (char_u *)&p_eb, PV_NONE,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"errorfile", "ef", P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
+#ifdef FEAT_QUICKFIX
+ (char_u *)&p_ef, PV_NONE,
+ {(char_u *)DFLT_ERRORFILE, (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"errorformat", "efm", P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP,
+#ifdef FEAT_QUICKFIX
+ (char_u *)&p_efm, PV_EFM,
+ {(char_u *)DFLT_EFM, (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"esckeys", "ek", P_BOOL|P_VIM,
+ (char_u *)&p_ek, PV_NONE,
+ {(char_u *)FALSE, (char_u *)TRUE} SCTX_INIT},
+ {"eventignore", "ei", P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP,
+ (char_u *)&p_ei, PV_NONE,
+ {(char_u *)"", (char_u *)0L} SCTX_INIT},
+ {"expandtab", "et", P_BOOL|P_VI_DEF|P_VIM,
+ (char_u *)&p_et, PV_ET,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"exrc", "ex", P_BOOL|P_VI_DEF|P_SECURE,
+ (char_u *)&p_exrc, PV_NONE,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"fileencoding","fenc", P_STRING|P_ALLOCED|P_VI_DEF|P_RSTAT|P_RBUF
+ |P_NO_MKRC,
+ (char_u *)&p_fenc, PV_FENC,
+ {(char_u *)"", (char_u *)0L}
+ SCTX_INIT},
+ {"fileencodings","fencs", P_STRING|P_VI_DEF|P_ONECOMMA,
+ (char_u *)&p_fencs, PV_NONE,
+ {(char_u *)"ucs-bom", (char_u *)0L}
+ SCTX_INIT},
+ {"fileformat", "ff", P_STRING|P_ALLOCED|P_VI_DEF|P_RSTAT|P_NO_MKRC
+ |P_CURSWANT,
+ (char_u *)&p_ff, PV_FF,
+ {(char_u *)DFLT_FF, (char_u *)0L} SCTX_INIT},
+ {"fileformats", "ffs", P_STRING|P_VIM|P_ONECOMMA|P_NODUP,
+ (char_u *)&p_ffs, PV_NONE,
+ {(char_u *)DFLT_FFS_VI, (char_u *)DFLT_FFS_VIM}
+ SCTX_INIT},
+ {"fileignorecase", "fic", P_BOOL|P_VI_DEF,
+ (char_u *)&p_fic, PV_NONE,
+ {
+#ifdef CASE_INSENSITIVE_FILENAME
+ (char_u *)TRUE,
+#else
+ (char_u *)FALSE,
+#endif
+ (char_u *)0L} SCTX_INIT},
+ {"filetype", "ft", P_STRING|P_ALLOCED|P_VI_DEF|P_NOGLOB|P_NFNAME,
+ (char_u *)&p_ft, PV_FT,
+ {(char_u *)"", (char_u *)0L}
+ SCTX_INIT},
+ {"fillchars", "fcs", P_STRING|P_VI_DEF|P_RALL|P_ONECOMMA|P_NODUP,
+ (char_u *)&p_fcs, PV_NONE,
+ {(char_u *)"vert:|,fold:-", (char_u *)0L}
+ SCTX_INIT},
+ {"fixendofline", "fixeol", P_BOOL|P_VI_DEF|P_RSTAT,
+ (char_u *)&p_fixeol, PV_FIXEOL,
+ {(char_u *)TRUE, (char_u *)0L} SCTX_INIT},
+ {"fkmap", "fk", P_BOOL|P_VI_DEF,
+#ifdef FEAT_FKMAP
+ (char_u *)&p_fkmap, PV_NONE,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"flash", "fl", P_BOOL|P_VI_DEF,
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"foldclose", "fcl", P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP|P_RWIN,
+#ifdef FEAT_FOLDING
+ (char_u *)&p_fcl, PV_NONE,
+ {(char_u *)"", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"foldcolumn", "fdc", P_NUM|P_VI_DEF|P_RWIN,
+#ifdef FEAT_FOLDING
+ (char_u *)VAR_WIN, PV_FDC,
+ {(char_u *)FALSE, (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"foldenable", "fen", P_BOOL|P_VI_DEF|P_RWIN,
+#ifdef FEAT_FOLDING
+ (char_u *)VAR_WIN, PV_FEN,
+ {(char_u *)TRUE, (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"foldexpr", "fde", P_STRING|P_ALLOCED|P_VIM|P_VI_DEF|P_RWIN,
+#if defined(FEAT_FOLDING) && defined(FEAT_EVAL)
+ (char_u *)VAR_WIN, PV_FDE,
+ {(char_u *)"0", (char_u *)NULL}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"foldignore", "fdi", P_STRING|P_ALLOCED|P_VIM|P_VI_DEF|P_RWIN,
+#ifdef FEAT_FOLDING
+ (char_u *)VAR_WIN, PV_FDI,
+ {(char_u *)"#", (char_u *)NULL}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"foldlevel", "fdl", P_NUM|P_VI_DEF|P_RWIN,
+#ifdef FEAT_FOLDING
+ (char_u *)VAR_WIN, PV_FDL,
+ {(char_u *)0L, (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"foldlevelstart","fdls", P_NUM|P_VI_DEF|P_CURSWANT,
+#ifdef FEAT_FOLDING
+ (char_u *)&p_fdls, PV_NONE,
+ {(char_u *)-1L, (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"foldmarker", "fmr", P_STRING|P_ALLOCED|P_VIM|P_VI_DEF|
+ P_RWIN|P_ONECOMMA|P_NODUP,
+#ifdef FEAT_FOLDING
+ (char_u *)VAR_WIN, PV_FMR,
+ {(char_u *)"{{{,}}}", (char_u *)NULL}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"foldmethod", "fdm", P_STRING|P_ALLOCED|P_VIM|P_VI_DEF|P_RWIN,
+#ifdef FEAT_FOLDING
+ (char_u *)VAR_WIN, PV_FDM,
+ {(char_u *)"manual", (char_u *)NULL}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"foldminlines","fml", P_NUM|P_VI_DEF|P_RWIN,
+#ifdef FEAT_FOLDING
+ (char_u *)VAR_WIN, PV_FML,
+ {(char_u *)1L, (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"foldnestmax", "fdn", P_NUM|P_VI_DEF|P_RWIN,
+#ifdef FEAT_FOLDING
+ (char_u *)VAR_WIN, PV_FDN,
+ {(char_u *)20L, (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"foldopen", "fdo", P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP|P_CURSWANT,
+#ifdef FEAT_FOLDING
+ (char_u *)&p_fdo, PV_NONE,
+ {(char_u *)"block,hor,mark,percent,quickfix,search,tag,undo",
+ (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"foldtext", "fdt", P_STRING|P_ALLOCED|P_VIM|P_VI_DEF|P_RWIN,
+#if defined(FEAT_FOLDING) && defined(FEAT_EVAL)
+ (char_u *)VAR_WIN, PV_FDT,
+ {(char_u *)"foldtext()", (char_u *)NULL}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"formatexpr", "fex", P_STRING|P_ALLOCED|P_VI_DEF|P_VIM,
+#ifdef FEAT_EVAL
+ (char_u *)&p_fex, PV_FEX,
+ {(char_u *)"", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"formatoptions","fo", P_STRING|P_ALLOCED|P_VIM|P_FLAGLIST,
+ (char_u *)&p_fo, PV_FO,
+ {(char_u *)DFLT_FO_VI, (char_u *)DFLT_FO_VIM}
+ SCTX_INIT},
+ {"formatlistpat","flp", P_STRING|P_ALLOCED|P_VI_DEF,
+ (char_u *)&p_flp, PV_FLP,
+ {(char_u *)"^\\s*\\d\\+[\\]:.)}\\t ]\\s*",
+ (char_u *)0L} SCTX_INIT},
+ {"formatprg", "fp", P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
+ (char_u *)&p_fp, PV_FP,
+ {(char_u *)"", (char_u *)0L} SCTX_INIT},
+ {"fsync", "fs", P_BOOL|P_SECURE|P_VI_DEF,
+#ifdef HAVE_FSYNC
+ (char_u *)&p_fs, PV_NONE,
+ {(char_u *)TRUE, (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)FALSE, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"gdefault", "gd", P_BOOL|P_VI_DEF|P_VIM,
+ (char_u *)&p_gd, PV_NONE,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"graphic", "gr", P_BOOL|P_VI_DEF,
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"grepformat", "gfm", P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP,
+#ifdef FEAT_QUICKFIX
+ (char_u *)&p_gefm, PV_NONE,
+ {(char_u *)DFLT_GREPFORMAT, (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"grepprg", "gp", P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
+#ifdef FEAT_QUICKFIX
+ (char_u *)&p_gp, PV_GP,
+ {
+# ifdef WIN3264
+ /* may be changed to "grep -n" in os_win32.c */
+ (char_u *)"findstr /n",
+# else
+# ifdef UNIX
+ /* Add an extra file name so that grep will always
+ * insert a file name in the match line. */
+ (char_u *)"grep -n $* /dev/null",
+# else
+# ifdef VMS
+ (char_u *)"SEARCH/NUMBERS ",
+# else
+ (char_u *)"grep -n ",
+# endif
+# endif
+# endif
+ (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"guicursor", "gcr", P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP,
+#ifdef CURSOR_SHAPE
+ (char_u *)&p_guicursor, PV_NONE,
+ {
+# ifdef FEAT_GUI
+ (char_u *)"n-v-c:block-Cursor/lCursor,ve:ver35-Cursor,o:hor50-Cursor,i-ci:ver25-Cursor/lCursor,r-cr:hor20-Cursor/lCursor,sm:block-Cursor-blinkwait175-blinkoff150-blinkon175",
+# else /* Win32 console */
+ (char_u *)"n-v-c:block,o:hor50,i-ci:hor15,r-cr:hor30,sm:block",
+# endif
+ (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"guifont", "gfn", P_STRING|P_VI_DEF|P_RCLR|P_ONECOMMA|P_NODUP,
+#ifdef FEAT_GUI
+ (char_u *)&p_guifont, PV_NONE,
+ {(char_u *)"", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"guifontset", "gfs", P_STRING|P_VI_DEF|P_RCLR|P_ONECOMMA,
+#if defined(FEAT_GUI) && defined(FEAT_XFONTSET)
+ (char_u *)&p_guifontset, PV_NONE,
+ {(char_u *)"", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"guifontwide", "gfw", P_STRING|P_VI_DEF|P_RCLR|P_ONECOMMA|P_NODUP,
+#if defined(FEAT_GUI)
+ (char_u *)&p_guifontwide, PV_NONE,
+ {(char_u *)"", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"guiheadroom", "ghr", P_NUM|P_VI_DEF,
+#if defined(FEAT_GUI_GTK) || defined(FEAT_GUI_X11)
+ (char_u *)&p_ghr, PV_NONE,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)50L, (char_u *)0L} SCTX_INIT},
+ {"guioptions", "go", P_STRING|P_VI_DEF|P_RALL|P_FLAGLIST,
+#if defined(FEAT_GUI)
+ (char_u *)&p_go, PV_NONE,
+# if defined(UNIX) && !defined(FEAT_GUI_MAC)
+ {(char_u *)"aegimrLtT", (char_u *)0L}
+# else
+ {(char_u *)"egmrLtT", (char_u *)0L}
+# endif
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"guipty", NULL, P_BOOL|P_VI_DEF,
+#if defined(FEAT_GUI)
+ (char_u *)&p_guipty, PV_NONE,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)TRUE, (char_u *)0L} SCTX_INIT},
+ {"guitablabel", "gtl", P_STRING|P_VI_DEF|P_RWIN,
+#if defined(FEAT_GUI_TABLINE)
+ (char_u *)&p_gtl, PV_NONE,
+ {(char_u *)"", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"guitabtooltip", "gtt", P_STRING|P_VI_DEF|P_RWIN,
+#if defined(FEAT_GUI_TABLINE)
+ (char_u *)&p_gtt, PV_NONE,
+ {(char_u *)"", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"hardtabs", "ht", P_NUM|P_VI_DEF,
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L} SCTX_INIT},
+ {"helpfile", "hf", P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
+ (char_u *)&p_hf, PV_NONE,
+ {(char_u *)DFLT_HELPFILE, (char_u *)0L}
+ SCTX_INIT},
+ {"helpheight", "hh", P_NUM|P_VI_DEF,
+ (char_u *)&p_hh, PV_NONE,
+ {(char_u *)20L, (char_u *)0L} SCTX_INIT},
+ {"helplang", "hlg", P_STRING|P_VI_DEF|P_ONECOMMA,
+#ifdef FEAT_MULTI_LANG
+ (char_u *)&p_hlg, PV_NONE,
+ {(char_u *)"", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"hidden", "hid", P_BOOL|P_VI_DEF,
+ (char_u *)&p_hid, PV_NONE,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"highlight", "hl", P_STRING|P_VI_DEF|P_RCLR|P_ONECOMMA|P_NODUP,
+ (char_u *)&p_hl, PV_NONE,
+ {(char_u *)HIGHLIGHT_INIT, (char_u *)0L}
+ SCTX_INIT},
+ {"history", "hi", P_NUM|P_VIM,
+ (char_u *)&p_hi, PV_NONE,
+ {(char_u *)0L, (char_u *)50L} SCTX_INIT},
+ {"hkmap", "hk", P_BOOL|P_VI_DEF|P_VIM,
+#ifdef FEAT_RIGHTLEFT
+ (char_u *)&p_hkmap, PV_NONE,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"hkmapp", "hkp", P_BOOL|P_VI_DEF|P_VIM,
+#ifdef FEAT_RIGHTLEFT
+ (char_u *)&p_hkmapp, PV_NONE,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"hlsearch", "hls", P_BOOL|P_VI_DEF|P_VIM|P_RALL,
+ (char_u *)&p_hls, PV_NONE,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"icon", NULL, P_BOOL|P_VI_DEF,
+#ifdef FEAT_TITLE
+ (char_u *)&p_icon, PV_NONE,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"iconstring", NULL, P_STRING|P_VI_DEF,
+#ifdef FEAT_TITLE
+ (char_u *)&p_iconstring, PV_NONE,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)"", (char_u *)0L} SCTX_INIT},
+ {"ignorecase", "ic", P_BOOL|P_VI_DEF,
+ (char_u *)&p_ic, PV_NONE,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"imactivatefunc","imaf",P_STRING|P_VI_DEF|P_SECURE,
+#if defined(FEAT_EVAL)
+ (char_u *)&p_imaf, PV_NONE,
+ {(char_u *)"", (char_u *)NULL}
+# else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+# endif
+ SCTX_INIT},
+ {"imactivatekey","imak",P_STRING|P_VI_DEF,
+#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
+ (char_u *)&p_imak, PV_NONE,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)"", (char_u *)0L} SCTX_INIT},
+ {"imcmdline", "imc", P_BOOL|P_VI_DEF,
+ (char_u *)&p_imcmdline, PV_NONE,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"imdisable", "imd", P_BOOL|P_VI_DEF,
+ (char_u *)&p_imdisable, PV_NONE,
+#ifdef __sgi
+ {(char_u *)TRUE, (char_u *)0L}
+#else
+ {(char_u *)FALSE, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"iminsert", "imi", P_NUM|P_VI_DEF,
+ (char_u *)&p_iminsert, PV_IMI,
+ {(char_u *)B_IMODE_NONE, (char_u *)0L}
+ SCTX_INIT},
+ {"imsearch", "ims", P_NUM|P_VI_DEF,
+ (char_u *)&p_imsearch, PV_IMS,
+ {(char_u *)B_IMODE_USE_INSERT, (char_u *)0L}
+ SCTX_INIT},
+ {"imstatusfunc","imsf",P_STRING|P_VI_DEF|P_SECURE,
+#if defined(FEAT_EVAL)
+ (char_u *)&p_imsf, PV_NONE,
+ {(char_u *)"", (char_u *)NULL}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"imstyle", "imst", P_NUM|P_VI_DEF|P_SECURE,
+#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
+ (char_u *)&p_imst, PV_NONE,
+ {(char_u *)IM_OVER_THE_SPOT, (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"include", "inc", P_STRING|P_ALLOCED|P_VI_DEF,
+#ifdef FEAT_FIND_ID
+ (char_u *)&p_inc, PV_INC,
+ {(char_u *)"^\\s*#\\s*include", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"includeexpr", "inex", P_STRING|P_ALLOCED|P_VI_DEF,
+#if defined(FEAT_FIND_ID) && defined(FEAT_EVAL)
+ (char_u *)&p_inex, PV_INEX,
+ {(char_u *)"", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"incsearch", "is", P_BOOL|P_VI_DEF|P_VIM,
+ (char_u *)&p_is, PV_NONE,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"indentexpr", "inde", P_STRING|P_ALLOCED|P_VI_DEF|P_VIM,
+#if defined(FEAT_CINDENT) && defined(FEAT_EVAL)
+ (char_u *)&p_inde, PV_INDE,
+ {(char_u *)"", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"indentkeys", "indk", P_STRING|P_ALLOCED|P_VI_DEF|P_ONECOMMA|P_NODUP,
+#if defined(FEAT_CINDENT) && defined(FEAT_EVAL)
+ (char_u *)&p_indk, PV_INDK,
+ {INDENTKEYS_DEFAULT, (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"infercase", "inf", P_BOOL|P_VI_DEF,
+ (char_u *)&p_inf, PV_INF,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"insertmode", "im", P_BOOL|P_VI_DEF|P_VIM,
+ (char_u *)&p_im, PV_NONE,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"isfname", "isf", P_STRING|P_VI_DEF|P_COMMA|P_NODUP,
+ (char_u *)&p_isf, PV_NONE,
+ {
+#ifdef BACKSLASH_IN_FILENAME
+ /* Excluded are: & and ^ are special in cmd.exe
+ * ( and ) are used in text separating fnames */
+ (char_u *)"@,48-57,/,\\,.,-,_,+,,,#,$,%,{,},[,],:,@-@,!,~,=",
+#else
+# ifdef AMIGA
+ (char_u *)"@,48-57,/,.,-,_,+,,,$,:",
+# else
+# ifdef VMS
+ (char_u *)"@,48-57,/,.,-,_,+,,,#,$,%,<,>,[,],:,;,~",
+# else /* UNIX et al. */
+# ifdef EBCDIC
+ (char_u *)"@,240-249,/,.,-,_,+,,,#,$,%,~,=",
+# else
+ (char_u *)"@,48-57,/,.,-,_,+,,,#,$,%,~,=",
+# endif
+# endif
+# endif
+#endif
+ (char_u *)0L} SCTX_INIT},
+ {"isident", "isi", P_STRING|P_VI_DEF|P_COMMA|P_NODUP,
+ (char_u *)&p_isi, PV_NONE,
+ {
+#if defined(MSWIN)
+ (char_u *)"@,48-57,_,128-167,224-235",
+#else
+# ifdef EBCDIC
+ /* TODO: EBCDIC Check this! @ == isalpha()*/
+ (char_u *)"@,240-249,_,66-73,81-89,98-105,"
+ "112-120,128,140-142,156,158,172,"
+ "174,186,191,203-207,219-225,235-239,"
+ "251-254",
+# else
+ (char_u *)"@,48-57,_,192-255",
+# endif
+#endif
+ (char_u *)0L} SCTX_INIT},
+ {"iskeyword", "isk", P_STRING|P_ALLOCED|P_VIM|P_COMMA|P_NODUP,
+ (char_u *)&p_isk, PV_ISK,
+ {
+#ifdef EBCDIC
+ (char_u *)"@,240-249,_",
+ /* TODO: EBCDIC Check this! @ == isalpha()*/
+ (char_u *)"@,240-249,_,66-73,81-89,98-105,"
+ "112-120,128,140-142,156,158,172,"
+ "174,186,191,203-207,219-225,235-239,"
+ "251-254",
+#else
+ (char_u *)"@,48-57,_",
+# if defined(MSWIN)
+ (char_u *)"@,48-57,_,128-167,224-235"
+# else
+ ISK_LATIN1
+# endif
+#endif
+ } SCTX_INIT},
+ {"isprint", "isp", P_STRING|P_VI_DEF|P_RALL|P_COMMA|P_NODUP,
+ (char_u *)&p_isp, PV_NONE,
+ {
+#if defined(MSWIN) || defined(VMS)
+ (char_u *)"@,~-255",
+#else
+# ifdef EBCDIC
+ /* all chars above 63 are printable */
+ (char_u *)"63-255",
+# else
+ ISP_LATIN1,
+# endif
+#endif
+ (char_u *)0L} SCTX_INIT},
+ {"joinspaces", "js", P_BOOL|P_VI_DEF|P_VIM,
+ (char_u *)&p_js, PV_NONE,
+ {(char_u *)TRUE, (char_u *)0L} SCTX_INIT},
+ {"key", NULL, P_STRING|P_ALLOCED|P_VI_DEF|P_NO_MKRC,
+#ifdef FEAT_CRYPT
+ (char_u *)&p_key, PV_KEY,
+ {(char_u *)"", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"keymap", "kmp", P_STRING|P_ALLOCED|P_VI_DEF|P_RBUF|P_RSTAT|P_NFNAME|P_PRI_MKRC,
+#ifdef FEAT_KEYMAP
+ (char_u *)&p_keymap, PV_KMAP,
+ {(char_u *)"", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)"", (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"keymodel", "km", P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP,
+ (char_u *)&p_km, PV_NONE,
+ {(char_u *)"", (char_u *)0L} SCTX_INIT},
+ {"keywordprg", "kp", P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
+ (char_u *)&p_kp, PV_KP,
+ {
+#ifdef MSWIN
+ (char_u *)":help",
+#else
+# ifdef VMS
+ (char_u *)"help",
+# else
+# ifdef USEMAN_S
+ (char_u *)"man -s",
+# else
+ (char_u *)"man",
+# endif
+# endif
+#endif
+ (char_u *)0L} SCTX_INIT},
+ {"langmap", "lmap", P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP|P_SECURE,
+#ifdef FEAT_LANGMAP
+ (char_u *)&p_langmap, PV_NONE,
+ {(char_u *)"", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"langmenu", "lm", P_STRING|P_VI_DEF|P_NFNAME,
+#if defined(FEAT_MENU) && defined(FEAT_MULTI_LANG)
+ (char_u *)&p_lm, PV_NONE,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)"", (char_u *)0L} SCTX_INIT},
+ {"langnoremap", "lnr", P_BOOL|P_VI_DEF,
+#ifdef FEAT_LANGMAP
+ (char_u *)&p_lnr, PV_NONE,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"langremap", "lrm", P_BOOL|P_VI_DEF,
+#ifdef FEAT_LANGMAP
+ (char_u *)&p_lrm, PV_NONE,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)TRUE, (char_u *)0L} SCTX_INIT},
+ {"laststatus", "ls", P_NUM|P_VI_DEF|P_RALL,
+ (char_u *)&p_ls, PV_NONE,
+ {(char_u *)1L, (char_u *)0L} SCTX_INIT},
+ {"lazyredraw", "lz", P_BOOL|P_VI_DEF,
+ (char_u *)&p_lz, PV_NONE,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"linebreak", "lbr", P_BOOL|P_VI_DEF|P_RWIN,
+#ifdef FEAT_LINEBREAK
+ (char_u *)VAR_WIN, PV_LBR,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"lines", NULL, P_NUM|P_NODEFAULT|P_NO_MKRC|P_VI_DEF|P_RCLR,
+ (char_u *)&Rows, PV_NONE,
+ {
+#if defined(WIN3264)
+ (char_u *)25L,
+#else
+ (char_u *)24L,
+#endif
+ (char_u *)0L} SCTX_INIT},
+ {"linespace", "lsp", P_NUM|P_VI_DEF|P_RCLR,
+#ifdef FEAT_GUI
+ (char_u *)&p_linespace, PV_NONE,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+#ifdef FEAT_GUI_W32
+ {(char_u *)1L, (char_u *)0L}
+#else
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"lisp", NULL, P_BOOL|P_VI_DEF,
+#ifdef FEAT_LISP
+ (char_u *)&p_lisp, PV_LISP,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"lispwords", "lw", P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP,
+#ifdef FEAT_LISP
+ (char_u *)&p_lispwords, PV_LW,
+ {(char_u *)LISPWORD_VALUE, (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)"", (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"list", NULL, P_BOOL|P_VI_DEF|P_RWIN,
+ (char_u *)VAR_WIN, PV_LIST,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"listchars", "lcs", P_STRING|P_VI_DEF|P_RALL|P_ONECOMMA|P_NODUP,
+ (char_u *)&p_lcs, PV_NONE,
+ {(char_u *)"eol:$", (char_u *)0L} SCTX_INIT},
+ {"loadplugins", "lpl", P_BOOL|P_VI_DEF,
+ (char_u *)&p_lpl, PV_NONE,
+ {(char_u *)TRUE, (char_u *)0L} SCTX_INIT},
+ {"luadll", NULL, P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
+#if defined(DYNAMIC_LUA)
+ (char_u *)&p_luadll, PV_NONE,
+ {(char_u *)DYNAMIC_LUA_DLL, (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)"", (char_u *)0L}
+#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},
+ {"magic", NULL, P_BOOL|P_VI_DEF,
+ (char_u *)&p_magic, PV_NONE,
+ {(char_u *)TRUE, (char_u *)0L} SCTX_INIT},
+ {"makeef", "mef", P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
+#ifdef FEAT_QUICKFIX
+ (char_u *)&p_mef, PV_NONE,
+ {(char_u *)"", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"makeencoding","menc", P_STRING|P_VI_DEF,
+ (char_u *)&p_menc, PV_MENC,
+ {(char_u *)"", (char_u *)0L}
+ SCTX_INIT},
+ {"makeprg", "mp", P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
+#ifdef FEAT_QUICKFIX
+ (char_u *)&p_mp, PV_MP,
+# ifdef VMS
+ {(char_u *)"MMS", (char_u *)0L}
+# else
+ {(char_u *)"make", (char_u *)0L}
+# endif
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"matchpairs", "mps", P_STRING|P_ALLOCED|P_VI_DEF|P_ONECOMMA|P_NODUP,
+ (char_u *)&p_mps, PV_MPS,
+ {(char_u *)"(:),{:},[:]", (char_u *)0L}
+ SCTX_INIT},
+ {"matchtime", "mat", P_NUM|P_VI_DEF,
+ (char_u *)&p_mat, PV_NONE,
+ {(char_u *)5L, (char_u *)0L} SCTX_INIT},
+ {"maxcombine", "mco", P_NUM|P_VI_DEF|P_CURSWANT,
+ (char_u *)&p_mco, PV_NONE,
+ {(char_u *)2, (char_u *)0L} SCTX_INIT},
+ {"maxfuncdepth", "mfd", P_NUM|P_VI_DEF,
+#ifdef FEAT_EVAL
+ (char_u *)&p_mfd, PV_NONE,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)100L, (char_u *)0L} SCTX_INIT},
+ {"maxmapdepth", "mmd", P_NUM|P_VI_DEF,
+ (char_u *)&p_mmd, PV_NONE,
+ {(char_u *)1000L, (char_u *)0L} SCTX_INIT},
+ {"maxmem", "mm", P_NUM|P_VI_DEF,
+ (char_u *)&p_mm, PV_NONE,
+ {(char_u *)DFLT_MAXMEM, (char_u *)0L}
+ SCTX_INIT},
+ {"maxmempattern","mmp", P_NUM|P_VI_DEF,
+ (char_u *)&p_mmp, PV_NONE,
+ {(char_u *)1000L, (char_u *)0L} SCTX_INIT},
+ {"maxmemtot", "mmt", P_NUM|P_VI_DEF,
+ (char_u *)&p_mmt, PV_NONE,
+ {(char_u *)DFLT_MAXMEMTOT, (char_u *)0L}
+ SCTX_INIT},
+ {"menuitems", "mis", P_NUM|P_VI_DEF,
+#ifdef FEAT_MENU
+ (char_u *)&p_mis, PV_NONE,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)25L, (char_u *)0L} SCTX_INIT},
+ {"mesg", NULL, P_BOOL|P_VI_DEF,
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"mkspellmem", "msm", P_STRING|P_VI_DEF|P_EXPAND|P_SECURE,
+#ifdef FEAT_SPELL
+ (char_u *)&p_msm, PV_NONE,
+ {(char_u *)"460000,2000,500", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"modeline", "ml", P_BOOL|P_VIM,
+ (char_u *)&p_ml, PV_ML,
+ {(char_u *)FALSE, (char_u *)TRUE} SCTX_INIT},
+ {"modelines", "mls", P_NUM|P_VI_DEF,
+ (char_u *)&p_mls, PV_NONE,
+ {(char_u *)5L, (char_u *)0L} SCTX_INIT},
+ {"modifiable", "ma", P_BOOL|P_VI_DEF|P_NOGLOB,
+ (char_u *)&p_ma, PV_MA,
+ {(char_u *)TRUE, (char_u *)0L} SCTX_INIT},
+ {"modified", "mod", P_BOOL|P_NO_MKRC|P_VI_DEF|P_RSTAT,
+ (char_u *)&p_mod, PV_MOD,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"more", NULL, P_BOOL|P_VIM,
+ (char_u *)&p_more, PV_NONE,
+ {(char_u *)FALSE, (char_u *)TRUE} SCTX_INIT},
+ {"mouse", NULL, P_STRING|P_VI_DEF|P_FLAGLIST,
+ (char_u *)&p_mouse, PV_NONE,
+ {
+#if defined(WIN3264)
+ (char_u *)"a",
+#else
+ (char_u *)"",
+#endif
+ (char_u *)0L} SCTX_INIT},
+ {"mousefocus", "mousef", P_BOOL|P_VI_DEF,
+#ifdef FEAT_GUI
+ (char_u *)&p_mousef, PV_NONE,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"mousehide", "mh", P_BOOL|P_VI_DEF,
+#ifdef FEAT_GUI
+ (char_u *)&p_mh, PV_NONE,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)TRUE, (char_u *)0L} SCTX_INIT},
+ {"mousemodel", "mousem", P_STRING|P_VI_DEF,
+ (char_u *)&p_mousem, PV_NONE,
+ {
+#if defined(MSWIN)
+ (char_u *)"popup",
+#else
+# if defined(MACOS_X)
+ (char_u *)"popup_setpos",
+# else
+ (char_u *)"extend",
+# endif
+#endif
+ (char_u *)0L} SCTX_INIT},
+ {"mouseshape", "mouses", P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP,
+#ifdef FEAT_MOUSESHAPE
+ (char_u *)&p_mouseshape, PV_NONE,
+ {(char_u *)"i-r:beam,s:updown,sd:udsizing,vs:leftright,vd:lrsizing,m:no,ml:up-arrow,v:rightup-arrow", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"mousetime", "mouset", P_NUM|P_VI_DEF,
+ (char_u *)&p_mouset, PV_NONE,
+ {(char_u *)500L, (char_u *)0L} SCTX_INIT},
+ {"mzschemedll", NULL, P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
+#if defined(DYNAMIC_MZSCHEME)
+ (char_u *)&p_mzschemedll, PV_NONE,
+ {(char_u *)DYNAMIC_MZSCH_DLL, (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)"", (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"mzschemegcdll", NULL, P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
+#if defined(DYNAMIC_MZSCHEME)
+ (char_u *)&p_mzschemegcdll, PV_NONE,
+ {(char_u *)DYNAMIC_MZGC_DLL, (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)"", (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"mzquantum", "mzq", P_NUM,
+#ifdef FEAT_MZSCHEME
+ (char_u *)&p_mzq, PV_NONE,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)100L, (char_u *)100L} SCTX_INIT},
+ {"novice", NULL, P_BOOL|P_VI_DEF,
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"nrformats", "nf", P_STRING|P_ALLOCED|P_VI_DEF|P_ONECOMMA|P_NODUP,
+ (char_u *)&p_nf, PV_NF,
+ {(char_u *)"bin,octal,hex", (char_u *)0L}
+ SCTX_INIT},
+ {"number", "nu", P_BOOL|P_VI_DEF|P_RWIN,
+ (char_u *)VAR_WIN, PV_NU,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"numberwidth", "nuw", P_NUM|P_RWIN|P_VIM,
+#ifdef FEAT_LINEBREAK
+ (char_u *)VAR_WIN, PV_NUW,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)8L, (char_u *)4L} SCTX_INIT},
+ {"omnifunc", "ofu", P_STRING|P_ALLOCED|P_VI_DEF|P_SECURE,
+#ifdef FEAT_COMPL_FUNC
+ (char_u *)&p_ofu, PV_OFU,
+ {(char_u *)"", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"open", NULL, P_BOOL|P_VI_DEF,
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"opendevice", "odev", P_BOOL|P_VI_DEF,
+#if defined(MSWIN)
+ (char_u *)&p_odev, PV_NONE,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)FALSE, (char_u *)FALSE}
+ SCTX_INIT},
+ {"operatorfunc", "opfunc", P_STRING|P_VI_DEF|P_SECURE,
+ (char_u *)&p_opfunc, PV_NONE,
+ {(char_u *)"", (char_u *)0L} SCTX_INIT},
+ {"optimize", "opt", P_BOOL|P_VI_DEF,
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"osfiletype", "oft", P_STRING|P_ALLOCED|P_VI_DEF,
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L} SCTX_INIT},
+ {"packpath", "pp", P_STRING|P_VI_DEF|P_EXPAND|P_ONECOMMA|P_NODUP
+ |P_SECURE,
+ (char_u *)&p_pp, PV_NONE,
+ {(char_u *)DFLT_RUNTIMEPATH, (char_u *)0L}
+ SCTX_INIT},
+ {"paragraphs", "para", P_STRING|P_VI_DEF,
+ (char_u *)&p_para, PV_NONE,
+ {(char_u *)"IPLPPPQPP TPHPLIPpLpItpplpipbp",
+ (char_u *)0L} SCTX_INIT},
+ {"paste", NULL, P_BOOL|P_VI_DEF|P_PRI_MKRC,
+ (char_u *)&p_paste, PV_NONE,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"pastetoggle", "pt", P_STRING|P_VI_DEF,
+ (char_u *)&p_pt, PV_NONE,
+ {(char_u *)"", (char_u *)0L} SCTX_INIT},
+ {"patchexpr", "pex", P_STRING|P_VI_DEF|P_SECURE,
+#if defined(FEAT_DIFF) && defined(FEAT_EVAL)
+ (char_u *)&p_pex, PV_NONE,
+ {(char_u *)"", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"patchmode", "pm", P_STRING|P_VI_DEF|P_NFNAME,
+ (char_u *)&p_pm, PV_NONE,
+ {(char_u *)"", (char_u *)0L} SCTX_INIT},
+ {"path", "pa", P_STRING|P_EXPAND|P_VI_DEF|P_COMMA|P_NODUP,
+ (char_u *)&p_path, PV_PATH,
+ {
+#if defined(AMIGA) || defined(MSWIN)
+ (char_u *)".,,",
+#else
+ (char_u *)".,/usr/include,,",
+#endif
+ (char_u *)0L} SCTX_INIT},
+ {"perldll", NULL, P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
+#if defined(DYNAMIC_PERL)
+ (char_u *)&p_perldll, PV_NONE,
+ {(char_u *)DYNAMIC_PERL_DLL, (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"preserveindent", "pi", P_BOOL|P_VI_DEF|P_VIM,
+ (char_u *)&p_pi, PV_PI,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"previewheight", "pvh", P_NUM|P_VI_DEF,
+#if defined(FEAT_QUICKFIX)
+ (char_u *)&p_pvh, PV_NONE,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)12L, (char_u *)0L} SCTX_INIT},
+ {"previewwindow", "pvw", P_BOOL|P_VI_DEF|P_RSTAT|P_NOGLOB,
+#if defined(FEAT_QUICKFIX)
+ (char_u *)VAR_WIN, PV_PVW,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"printdevice", "pdev", P_STRING|P_VI_DEF|P_SECURE,
+#ifdef FEAT_PRINTER
+ (char_u *)&p_pdev, PV_NONE,
+ {(char_u *)"", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"printencoding", "penc", P_STRING|P_VI_DEF,
+#ifdef FEAT_POSTSCRIPT
+ (char_u *)&p_penc, PV_NONE,
+ {(char_u *)"", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"printexpr", "pexpr", P_STRING|P_VI_DEF|P_SECURE,
+#ifdef FEAT_POSTSCRIPT
+ (char_u *)&p_pexpr, PV_NONE,
+ {(char_u *)"", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"printfont", "pfn", P_STRING|P_VI_DEF,
+#ifdef FEAT_PRINTER
+ (char_u *)&p_pfn, PV_NONE,
+ {
+# ifdef MSWIN
+ (char_u *)"Courier_New:h10",
+# else
+ (char_u *)"courier",
+# endif
+ (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"printheader", "pheader", P_STRING|P_VI_DEF|P_GETTEXT,
+#ifdef FEAT_PRINTER
+ (char_u *)&p_header, PV_NONE,
+ /* untranslated to avoid problems when 'encoding'
+ * is changed */
+ {(char_u *)"%<%f%h%m%=Page %N", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"printmbcharset", "pmbcs", P_STRING|P_VI_DEF,
+#if defined(FEAT_POSTSCRIPT)
+ (char_u *)&p_pmcs, PV_NONE,
+ {(char_u *)"", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"printmbfont", "pmbfn", P_STRING|P_VI_DEF,
+#if defined(FEAT_POSTSCRIPT)
+ (char_u *)&p_pmfn, PV_NONE,
+ {(char_u *)"", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"printoptions", "popt", P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP,
+#ifdef FEAT_PRINTER
+ (char_u *)&p_popt, PV_NONE,
+ {(char_u *)"", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"prompt", NULL, P_BOOL|P_VI_DEF,
+ (char_u *)&p_prompt, PV_NONE,
+ {(char_u *)TRUE, (char_u *)0L} SCTX_INIT},
+ {"pumheight", "ph", P_NUM|P_VI_DEF,
+#ifdef FEAT_INS_EXPAND
+ (char_u *)&p_ph, PV_NONE,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)0L, (char_u *)0L} SCTX_INIT},
+ {"pumwidth", "pw", P_NUM|P_VI_DEF,
+#ifdef FEAT_INS_EXPAND
+ (char_u *)&p_pw, PV_NONE,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)15L, (char_u *)15L} SCTX_INIT},
+ {"pythonthreedll", NULL, P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
+#if defined(DYNAMIC_PYTHON3)
+ (char_u *)&p_py3dll, PV_NONE,
+ {(char_u *)DYNAMIC_PYTHON3_DLL, (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"pythonthreehome", NULL, P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
+#if defined(FEAT_PYTHON3)
+ (char_u *)&p_py3home, PV_NONE,
+ {(char_u *)"", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"pythondll", NULL, P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
+#if defined(DYNAMIC_PYTHON)
+ (char_u *)&p_pydll, PV_NONE,
+ {(char_u *)DYNAMIC_PYTHON_DLL, (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"pythonhome", NULL, P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
+#if defined(FEAT_PYTHON)
+ (char_u *)&p_pyhome, PV_NONE,
+ {(char_u *)"", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"pyxversion", "pyx", P_NUM|P_VI_DEF|P_SECURE,
+#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
+ (char_u *)&p_pyx, PV_NONE,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)DEFAULT_PYTHON_VER, (char_u *)0L}
+ SCTX_INIT},
+ {"quoteescape", "qe", P_STRING|P_ALLOCED|P_VI_DEF,
+#ifdef FEAT_TEXTOBJ
+ (char_u *)&p_qe, PV_QE,
+ {(char_u *)"\\", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"readonly", "ro", P_BOOL|P_VI_DEF|P_RSTAT|P_NOGLOB,
+ (char_u *)&p_ro, PV_RO,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"redraw", NULL, P_BOOL|P_VI_DEF,
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"redrawtime", "rdt", P_NUM|P_VI_DEF,
+#ifdef FEAT_RELTIME
+ (char_u *)&p_rdt, PV_NONE,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)2000L, (char_u *)0L} SCTX_INIT},
+ {"regexpengine", "re", P_NUM|P_VI_DEF,
+ (char_u *)&p_re, PV_NONE,
+ {(char_u *)0L, (char_u *)0L} SCTX_INIT},
+ {"relativenumber", "rnu", P_BOOL|P_VI_DEF|P_RWIN,
+ (char_u *)VAR_WIN, PV_RNU,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"remap", NULL, P_BOOL|P_VI_DEF,
+ (char_u *)&p_remap, PV_NONE,
+ {(char_u *)TRUE, (char_u *)0L} SCTX_INIT},
+ {"renderoptions", "rop", P_STRING|P_ONECOMMA|P_RCLR|P_VI_DEF,
+#ifdef FEAT_RENDER_OPTIONS
+ (char_u *)&p_rop, PV_NONE,
+ {(char_u *)"", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"report", NULL, P_NUM|P_VI_DEF,
+ (char_u *)&p_report, PV_NONE,
+ {(char_u *)2L, (char_u *)0L} SCTX_INIT},
+ {"restorescreen", "rs", P_BOOL|P_VI_DEF,
+#ifdef WIN3264
+ (char_u *)&p_rs, PV_NONE,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)TRUE, (char_u *)0L} SCTX_INIT},
+ {"revins", "ri", P_BOOL|P_VI_DEF|P_VIM,
+#ifdef FEAT_RIGHTLEFT
+ (char_u *)&p_ri, PV_NONE,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"rightleft", "rl", P_BOOL|P_VI_DEF|P_RWIN,
+#ifdef FEAT_RIGHTLEFT
+ (char_u *)VAR_WIN, PV_RL,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"rightleftcmd", "rlc", P_STRING|P_ALLOCED|P_VI_DEF|P_RWIN,
+#ifdef FEAT_RIGHTLEFT
+ (char_u *)VAR_WIN, PV_RLC,
+ {(char_u *)"search", (char_u *)NULL}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"rubydll", NULL, P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
+#if defined(DYNAMIC_RUBY)
+ (char_u *)&p_rubydll, PV_NONE,
+ {(char_u *)DYNAMIC_RUBY_DLL, (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"ruler", "ru", P_BOOL|P_VI_DEF|P_VIM|P_RSTAT,
+#ifdef FEAT_CMDL_INFO
+ (char_u *)&p_ru, PV_NONE,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"rulerformat", "ruf", P_STRING|P_VI_DEF|P_ALLOCED|P_RSTAT,
+#ifdef FEAT_STL_OPT
+ (char_u *)&p_ruf, PV_NONE,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)"", (char_u *)0L} SCTX_INIT},
+ {"runtimepath", "rtp", P_STRING|P_VI_DEF|P_EXPAND|P_ONECOMMA|P_NODUP
+ |P_SECURE,
+ (char_u *)&p_rtp, PV_NONE,
+ {(char_u *)DFLT_RUNTIMEPATH, (char_u *)0L}
+ SCTX_INIT},
+ {"scroll", "scr", P_NUM|P_NO_MKRC|P_VI_DEF,
+ (char_u *)VAR_WIN, PV_SCROLL,
+ {(char_u *)0L, (char_u *)0L} SCTX_INIT},
+ {"scrollbind", "scb", P_BOOL|P_VI_DEF,
+ (char_u *)VAR_WIN, PV_SCBIND,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"scrolljump", "sj", P_NUM|P_VI_DEF|P_VIM,
+ (char_u *)&p_sj, PV_NONE,
+ {(char_u *)1L, (char_u *)0L} SCTX_INIT},
+ {"scrolloff", "so", P_NUM|P_VI_DEF|P_VIM|P_RALL,
+ (char_u *)&p_so, PV_SO,
+ {(char_u *)0L, (char_u *)0L} SCTX_INIT},
+ {"scrollopt", "sbo", P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP,
+ (char_u *)&p_sbo, PV_NONE,
+ {(char_u *)"ver,jump", (char_u *)0L}
+ SCTX_INIT},
+ {"sections", "sect", P_STRING|P_VI_DEF,
+ (char_u *)&p_sections, PV_NONE,
+ {(char_u *)"SHNHH HUnhsh", (char_u *)0L}
+ SCTX_INIT},
+ {"secure", NULL, P_BOOL|P_VI_DEF|P_SECURE,
+ (char_u *)&p_secure, PV_NONE,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"selection", "sel", P_STRING|P_VI_DEF,
+ (char_u *)&p_sel, PV_NONE,
+ {(char_u *)"inclusive", (char_u *)0L}
+ SCTX_INIT},
+ {"selectmode", "slm", P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP,
+ (char_u *)&p_slm, PV_NONE,
+ {(char_u *)"", (char_u *)0L} SCTX_INIT},
+ {"sessionoptions", "ssop", P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP,
+#ifdef FEAT_SESSION
+ (char_u *)&p_ssop, PV_NONE,
+ {(char_u *)"blank,buffers,curdir,folds,help,options,tabpages,winsize,terminal",
+ (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"shell", "sh", P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
+ (char_u *)&p_sh, PV_NONE,
+ {
+#ifdef VMS
+ (char_u *)"-",
+#else
+# if defined(WIN3264)
+ (char_u *)"", /* set in set_init_1() */
+# else
+ (char_u *)"sh",
+# endif
+#endif /* VMS */
+ (char_u *)0L} SCTX_INIT},
+ {"shellcmdflag","shcf", P_STRING|P_VI_DEF|P_SECURE,
+ (char_u *)&p_shcf, PV_NONE,
+ {
+#if defined(MSWIN)
+ (char_u *)"/c",
+#else
+ (char_u *)"-c",
+#endif
+ (char_u *)0L} SCTX_INIT},
+ {"shellpipe", "sp", P_STRING|P_VI_DEF|P_SECURE,
+#ifdef FEAT_QUICKFIX
+ (char_u *)&p_sp, PV_NONE,
+ {
+#if defined(UNIX)
+ (char_u *)"| tee",
+#else
+ (char_u *)">",
+#endif
+ (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"shellquote", "shq", P_STRING|P_VI_DEF|P_SECURE,
+ (char_u *)&p_shq, PV_NONE,
+ {(char_u *)"", (char_u *)0L} SCTX_INIT},
+ {"shellredir", "srr", P_STRING|P_VI_DEF|P_SECURE,
+ (char_u *)&p_srr, PV_NONE,
+ {(char_u *)">", (char_u *)0L} SCTX_INIT},
+ {"shellslash", "ssl", P_BOOL|P_VI_DEF,
+#ifdef BACKSLASH_IN_FILENAME
+ (char_u *)&p_ssl, PV_NONE,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"shelltemp", "stmp", P_BOOL,
+ (char_u *)&p_stmp, PV_NONE,
+ {(char_u *)FALSE, (char_u *)TRUE} SCTX_INIT},
+ {"shelltype", "st", P_NUM|P_VI_DEF,
+#ifdef AMIGA
+ (char_u *)&p_st, PV_NONE,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)0L, (char_u *)0L} SCTX_INIT},
+ {"shellxquote", "sxq", P_STRING|P_VI_DEF|P_SECURE,
+ (char_u *)&p_sxq, PV_NONE,
+ {
+#if defined(UNIX) && defined(USE_SYSTEM)
+ (char_u *)"\"",
+#else
+ (char_u *)"",
+#endif
+ (char_u *)0L} SCTX_INIT},
+ {"shellxescape", "sxe", P_STRING|P_VI_DEF|P_SECURE,
+ (char_u *)&p_sxe, PV_NONE,
+ {
+#if defined(WIN3264)
+ (char_u *)"\"&|<>()@^",
+#else
+ (char_u *)"",
+#endif
+ (char_u *)0L} SCTX_INIT},
+ {"shiftround", "sr", P_BOOL|P_VI_DEF|P_VIM,
+ (char_u *)&p_sr, PV_NONE,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"shiftwidth", "sw", P_NUM|P_VI_DEF,
+ (char_u *)&p_sw, PV_SW,
+ {(char_u *)8L, (char_u *)0L} SCTX_INIT},
+ {"shortmess", "shm", P_STRING|P_VIM|P_FLAGLIST,
+ (char_u *)&p_shm, PV_NONE,
+ {(char_u *)"", (char_u *)"filnxtToO"}
+ SCTX_INIT},
+ {"shortname", "sn", P_BOOL|P_VI_DEF,
+ (char_u *)&p_sn, PV_SN,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"showbreak", "sbr", P_STRING|P_VI_DEF|P_RALL,
+#ifdef FEAT_LINEBREAK
+ (char_u *)&p_sbr, PV_NONE,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)"", (char_u *)0L} SCTX_INIT},
+ {"showcmd", "sc", P_BOOL|P_VIM,
+#ifdef FEAT_CMDL_INFO
+ (char_u *)&p_sc, PV_NONE,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)FALSE,
+#ifdef UNIX
+ (char_u *)FALSE
+#else
+ (char_u *)TRUE
+#endif
+ } SCTX_INIT},
+ {"showfulltag", "sft", P_BOOL|P_VI_DEF,
+ (char_u *)&p_sft, PV_NONE,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"showmatch", "sm", P_BOOL|P_VI_DEF,
+ (char_u *)&p_sm, PV_NONE,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"showmode", "smd", P_BOOL|P_VIM,
+ (char_u *)&p_smd, PV_NONE,
+ {(char_u *)FALSE, (char_u *)TRUE} SCTX_INIT},
+ {"showtabline", "stal", P_NUM|P_VI_DEF|P_RALL,
+ (char_u *)&p_stal, PV_NONE,
+ {(char_u *)1L, (char_u *)0L} SCTX_INIT},
+ {"sidescroll", "ss", P_NUM|P_VI_DEF,
+ (char_u *)&p_ss, PV_NONE,
+ {(char_u *)0L, (char_u *)0L} SCTX_INIT},
+ {"sidescrolloff", "siso", P_NUM|P_VI_DEF|P_VIM|P_RBUF,
+ (char_u *)&p_siso, PV_SISO,
+ {(char_u *)0L, (char_u *)0L} SCTX_INIT},
+ {"signcolumn", "scl", P_STRING|P_ALLOCED|P_VI_DEF|P_RWIN,
+#ifdef FEAT_SIGNS
+ (char_u *)VAR_WIN, PV_SCL,
+ {(char_u *)"auto", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"slowopen", "slow", P_BOOL|P_VI_DEF,
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"smartcase", "scs", P_BOOL|P_VI_DEF|P_VIM,
+ (char_u *)&p_scs, PV_NONE,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"smartindent", "si", P_BOOL|P_VI_DEF|P_VIM,
+#ifdef FEAT_SMARTINDENT
+ (char_u *)&p_si, PV_SI,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"smarttab", "sta", P_BOOL|P_VI_DEF|P_VIM,
+ (char_u *)&p_sta, PV_NONE,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"softtabstop", "sts", P_NUM|P_VI_DEF|P_VIM,
+ (char_u *)&p_sts, PV_STS,
+ {(char_u *)0L, (char_u *)0L} SCTX_INIT},
+ {"sourceany", NULL, P_BOOL|P_VI_DEF,
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"spell", NULL, P_BOOL|P_VI_DEF|P_RWIN,
+#ifdef FEAT_SPELL
+ (char_u *)VAR_WIN, PV_SPELL,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"spellcapcheck", "spc", P_STRING|P_ALLOCED|P_VI_DEF|P_RBUF,
+#ifdef FEAT_SPELL
+ (char_u *)&p_spc, PV_SPC,
+ {(char_u *)"[.?!]\\_[\\])'\" ]\\+", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"spellfile", "spf", P_STRING|P_EXPAND|P_ALLOCED|P_VI_DEF|P_SECURE
+ |P_ONECOMMA,
+#ifdef FEAT_SPELL
+ (char_u *)&p_spf, PV_SPF,
+ {(char_u *)"", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"spelllang", "spl", P_STRING|P_ALLOCED|P_VI_DEF|P_ONECOMMA
+ |P_RBUF|P_EXPAND,
+#ifdef FEAT_SPELL
+ (char_u *)&p_spl, PV_SPL,
+ {(char_u *)"en", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"spellsuggest", "sps", P_STRING|P_VI_DEF|P_EXPAND|P_SECURE|P_ONECOMMA,
+#ifdef FEAT_SPELL
+ (char_u *)&p_sps, PV_NONE,
+ {(char_u *)"best", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"splitbelow", "sb", P_BOOL|P_VI_DEF,
+ (char_u *)&p_sb, PV_NONE,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"splitright", "spr", P_BOOL|P_VI_DEF,
+ (char_u *)&p_spr, PV_NONE,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"startofline", "sol", P_BOOL|P_VI_DEF|P_VIM,
+ (char_u *)&p_sol, PV_NONE,
+ {(char_u *)TRUE, (char_u *)0L} SCTX_INIT},
+ {"statusline" ,"stl", P_STRING|P_VI_DEF|P_ALLOCED|P_RSTAT,
+#ifdef FEAT_STL_OPT
+ (char_u *)&p_stl, PV_STL,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)"", (char_u *)0L} SCTX_INIT},
+ {"suffixes", "su", P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP,
+ (char_u *)&p_su, PV_NONE,
+ {(char_u *)".bak,~,.o,.h,.info,.swp,.obj",
+ (char_u *)0L} SCTX_INIT},
+ {"suffixesadd", "sua", P_STRING|P_VI_DEF|P_ALLOCED|P_ONECOMMA|P_NODUP,
+#ifdef FEAT_SEARCHPATH
+ (char_u *)&p_sua, PV_SUA,
+ {(char_u *)"", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"swapfile", "swf", P_BOOL|P_VI_DEF|P_RSTAT,
+ (char_u *)&p_swf, PV_SWF,
+ {(char_u *)TRUE, (char_u *)0L} SCTX_INIT},
+ {"swapsync", "sws", P_STRING|P_VI_DEF,
+ (char_u *)&p_sws, PV_NONE,
+ {(char_u *)"fsync", (char_u *)0L} SCTX_INIT},
+ {"switchbuf", "swb", P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP,
+ (char_u *)&p_swb, PV_NONE,
+ {(char_u *)"", (char_u *)0L} SCTX_INIT},
+ {"synmaxcol", "smc", P_NUM|P_VI_DEF|P_RBUF,
+#ifdef FEAT_SYN_HL
+ (char_u *)&p_smc, PV_SMC,
+ {(char_u *)3000L, (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"syntax", "syn", P_STRING|P_ALLOCED|P_VI_DEF|P_NOGLOB|P_NFNAME,
+#ifdef FEAT_SYN_HL
+ (char_u *)&p_syn, PV_SYN,
+ {(char_u *)"", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"tabline", "tal", P_STRING|P_VI_DEF|P_RALL,
+#ifdef FEAT_STL_OPT
+ (char_u *)&p_tal, PV_NONE,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)"", (char_u *)0L} SCTX_INIT},
+ {"tabpagemax", "tpm", P_NUM|P_VI_DEF,
+ (char_u *)&p_tpm, PV_NONE,
+ {(char_u *)10L, (char_u *)0L} SCTX_INIT},
+ {"tabstop", "ts", P_NUM|P_VI_DEF|P_RBUF,
+ (char_u *)&p_ts, PV_TS,
+ {(char_u *)8L, (char_u *)0L} SCTX_INIT},
+ {"tagbsearch", "tbs", P_BOOL|P_VI_DEF,
+ (char_u *)&p_tbs, PV_NONE,
+#ifdef VMS /* binary searching doesn't appear to work on VMS */
+ {(char_u *)0L, (char_u *)0L}
+#else
+ {(char_u *)TRUE, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"tagcase", "tc", P_STRING|P_VIM,
+ (char_u *)&p_tc, PV_TC,
+ {(char_u *)"followic", (char_u *)"followic"} SCTX_INIT},
+ {"taglength", "tl", P_NUM|P_VI_DEF,
+ (char_u *)&p_tl, PV_NONE,
+ {(char_u *)0L, (char_u *)0L} SCTX_INIT},
+ {"tagrelative", "tr", P_BOOL|P_VIM,
+ (char_u *)&p_tr, PV_NONE,
+ {(char_u *)FALSE, (char_u *)TRUE} SCTX_INIT},
+ {"tags", "tag", P_STRING|P_EXPAND|P_VI_DEF|P_ONECOMMA|P_NODUP,
+ (char_u *)&p_tags, PV_TAGS,
+ {
+#if defined(FEAT_EMACS_TAGS) && !defined(CASE_INSENSITIVE_FILENAME)
+ (char_u *)"./tags,./TAGS,tags,TAGS",
+#else
+ (char_u *)"./tags,tags",
+#endif
+ (char_u *)0L} SCTX_INIT},
+ {"tagstack", "tgst", P_BOOL|P_VI_DEF,
+ (char_u *)&p_tgst, PV_NONE,
+ {(char_u *)TRUE, (char_u *)0L} SCTX_INIT},
+ {"tcldll", NULL, P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
+#if defined(DYNAMIC_TCL)
+ (char_u *)&p_tcldll, PV_NONE,
+ {(char_u *)DYNAMIC_TCL_DLL, (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"term", NULL, P_STRING|P_EXPAND|P_NODEFAULT|P_NO_MKRC|P_VI_DEF|P_RALL,
+ (char_u *)&T_NAME, PV_NONE,
+ {(char_u *)"", (char_u *)0L} SCTX_INIT},
+ {"termbidi", "tbidi", P_BOOL|P_VI_DEF,
+#ifdef FEAT_ARABIC
+ (char_u *)&p_tbidi, PV_NONE,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"termencoding", "tenc", P_STRING|P_VI_DEF|P_RCLR,
+ (char_u *)&p_tenc, PV_NONE,
+ {(char_u *)"", (char_u *)0L}
+ SCTX_INIT},
+ {"termguicolors", "tgc", P_BOOL|P_VI_DEF|P_VIM|P_RCLR,
+#ifdef FEAT_TERMGUICOLORS
+ (char_u *)&p_tgc, PV_NONE,
+ {(char_u *)FALSE, (char_u *)FALSE}
+#else
+ (char_u*)NULL, PV_NONE,
+ {(char_u *)FALSE, (char_u *)FALSE}
+#endif
+ SCTX_INIT},
+ {"termmode", "tmod", P_STRING|P_ALLOCED|P_VI_DEF,
+#ifdef FEAT_TERMINAL
+ (char_u *)VAR_WIN, PV_TMOD,
+ {(char_u *)"", (char_u *)NULL}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"termwinkey", "twk", P_STRING|P_ALLOCED|P_RWIN|P_VI_DEF,
+#ifdef FEAT_TERMINAL
+ (char_u *)VAR_WIN, PV_TWK,
+ {(char_u *)"", (char_u *)NULL}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"termwinscroll", "twsl", P_NUM|P_VI_DEF|P_VIM|P_RBUF,
+#ifdef FEAT_TERMINAL
+ (char_u *)&p_twsl, PV_TWSL,
+ {(char_u *)10000L, (char_u *)10000L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"termwinsize", "tws", P_STRING|P_ALLOCED|P_RWIN|P_VI_DEF,
+#ifdef FEAT_TERMINAL
+ (char_u *)VAR_WIN, PV_TWS,
+ {(char_u *)"", (char_u *)NULL}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"terse", NULL, P_BOOL|P_VI_DEF,
+ (char_u *)&p_terse, PV_NONE,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"textauto", "ta", P_BOOL|P_VIM,
+ (char_u *)&p_ta, PV_NONE,
+ {(char_u *)DFLT_TEXTAUTO, (char_u *)TRUE}
+ SCTX_INIT},
+ {"textmode", "tx", P_BOOL|P_VI_DEF|P_NO_MKRC,
+ (char_u *)&p_tx, PV_TX,
+ {
+#ifdef USE_CRNL
+ (char_u *)TRUE,
+#else
+ (char_u *)FALSE,
+#endif
+ (char_u *)0L} SCTX_INIT},
+ {"textwidth", "tw", P_NUM|P_VI_DEF|P_VIM|P_RBUF,
+ (char_u *)&p_tw, PV_TW,
+ {(char_u *)0L, (char_u *)0L} SCTX_INIT},
+ {"thesaurus", "tsr", P_STRING|P_EXPAND|P_VI_DEF|P_ONECOMMA|P_NODUP|P_NDNAME,
+#ifdef FEAT_INS_EXPAND
+ (char_u *)&p_tsr, PV_TSR,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)"", (char_u *)0L} SCTX_INIT},
+ {"tildeop", "top", P_BOOL|P_VI_DEF|P_VIM,
+ (char_u *)&p_to, PV_NONE,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"timeout", "to", P_BOOL|P_VI_DEF,
+ (char_u *)&p_timeout, PV_NONE,
+ {(char_u *)TRUE, (char_u *)0L} SCTX_INIT},
+ {"timeoutlen", "tm", P_NUM|P_VI_DEF,
+ (char_u *)&p_tm, PV_NONE,
+ {(char_u *)1000L, (char_u *)0L} SCTX_INIT},
+ {"title", NULL, P_BOOL|P_VI_DEF,
+#ifdef FEAT_TITLE
+ (char_u *)&p_title, PV_NONE,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"titlelen", NULL, P_NUM|P_VI_DEF,
+#ifdef FEAT_TITLE
+ (char_u *)&p_titlelen, PV_NONE,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)85L, (char_u *)0L} SCTX_INIT},
+ {"titleold", NULL, P_STRING|P_VI_DEF|P_GETTEXT|P_SECURE|P_NO_MKRC,
+#ifdef FEAT_TITLE
+ (char_u *)&p_titleold, PV_NONE,
+ {(char_u *)N_("Thanks for flying Vim"),
+ (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"titlestring", NULL, P_STRING|P_VI_DEF,
+#ifdef FEAT_TITLE
+ (char_u *)&p_titlestring, PV_NONE,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)"", (char_u *)0L} SCTX_INIT},
+ {"toolbar", "tb", P_STRING|P_ONECOMMA|P_VI_DEF|P_NODUP,
+#if defined(FEAT_TOOLBAR) && !defined(FEAT_GUI_W32)
+ (char_u *)&p_toolbar, PV_NONE,
+ {(char_u *)"icons,tooltips", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"toolbariconsize", "tbis", P_STRING|P_VI_DEF,
+#if defined(FEAT_TOOLBAR) && defined(FEAT_GUI_GTK)
+ (char_u *)&p_tbis, PV_NONE,
+ {(char_u *)"small", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"ttimeout", NULL, P_BOOL|P_VI_DEF|P_VIM,
+ (char_u *)&p_ttimeout, PV_NONE,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"ttimeoutlen", "ttm", P_NUM|P_VI_DEF,
+ (char_u *)&p_ttm, PV_NONE,
+ {(char_u *)-1L, (char_u *)0L} SCTX_INIT},
+ {"ttybuiltin", "tbi", P_BOOL|P_VI_DEF,
+ (char_u *)&p_tbi, PV_NONE,
+ {(char_u *)TRUE, (char_u *)0L} SCTX_INIT},
+ {"ttyfast", "tf", P_BOOL|P_NO_MKRC|P_VI_DEF,
+ (char_u *)&p_tf, PV_NONE,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"ttymouse", "ttym", P_STRING|P_NODEFAULT|P_NO_MKRC|P_VI_DEF,
+#if defined(FEAT_MOUSE) && (defined(UNIX) || defined(VMS))
+ (char_u *)&p_ttym, PV_NONE,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)"", (char_u *)0L} SCTX_INIT},
+ {"ttyscroll", "tsl", P_NUM|P_VI_DEF,
+ (char_u *)&p_ttyscroll, PV_NONE,
+ {(char_u *)999L, (char_u *)0L} SCTX_INIT},
+ {"ttytype", "tty", P_STRING|P_EXPAND|P_NODEFAULT|P_NO_MKRC|P_VI_DEF|P_RALL,
+ (char_u *)&T_NAME, PV_NONE,
+ {(char_u *)"", (char_u *)0L} SCTX_INIT},
+ {"undodir", "udir", P_STRING|P_EXPAND|P_ONECOMMA|P_NODUP|P_SECURE
+ |P_VI_DEF,
+#ifdef FEAT_PERSISTENT_UNDO
+ (char_u *)&p_udir, PV_NONE,
+ {(char_u *)".", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"undofile", "udf", P_BOOL|P_VI_DEF|P_VIM,
+#ifdef FEAT_PERSISTENT_UNDO
+ (char_u *)&p_udf, PV_UDF,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"undolevels", "ul", P_NUM|P_VI_DEF,
+ (char_u *)&p_ul, PV_UL,
+ {
+#if defined(UNIX) || defined(WIN3264) || defined(VMS)
+ (char_u *)1000L,
+#else
+ (char_u *)100L,
+#endif
+ (char_u *)0L} SCTX_INIT},
+ {"undoreload", "ur", P_NUM|P_VI_DEF,
+ (char_u *)&p_ur, PV_NONE,
+ { (char_u *)10000L, (char_u *)0L} SCTX_INIT},
+ {"updatecount", "uc", P_NUM|P_VI_DEF,
+ (char_u *)&p_uc, PV_NONE,
+ {(char_u *)200L, (char_u *)0L} SCTX_INIT},
+ {"updatetime", "ut", P_NUM|P_VI_DEF,
+ (char_u *)&p_ut, PV_NONE,
+ {(char_u *)4000L, (char_u *)0L} SCTX_INIT},
+ {"varsofttabstop", "vsts", P_STRING|P_VI_DEF|P_VIM|P_COMMA,
+#ifdef FEAT_VARTABS
+ (char_u *)&p_vsts, PV_VSTS,
+ {(char_u *)"", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)"", (char_u *)NULL}
+#endif
+ SCTX_INIT},
+ {"vartabstop", "vts", P_STRING|P_VI_DEF|P_VIM|P_RBUF|P_COMMA,
+#ifdef FEAT_VARTABS
+ (char_u *)&p_vts, PV_VTS,
+ {(char_u *)"", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)"", (char_u *)NULL}
+#endif
+ SCTX_INIT},
+ {"verbose", "vbs", P_NUM|P_VI_DEF,
+ (char_u *)&p_verbose, PV_NONE,
+ {(char_u *)0L, (char_u *)0L} SCTX_INIT},
+ {"verbosefile", "vfile", P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
+ (char_u *)&p_vfile, PV_NONE,
+ {(char_u *)"", (char_u *)0L} SCTX_INIT},
+ {"viewdir", "vdir", P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
+#ifdef FEAT_SESSION
+ (char_u *)&p_vdir, PV_NONE,
+ {(char_u *)DFLT_VDIR, (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"viewoptions", "vop", P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP,
+#ifdef FEAT_SESSION
+ (char_u *)&p_vop, PV_NONE,
+ {(char_u *)"folds,options,cursor,curdir",
+ (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"viminfo", "vi", P_STRING|P_ONECOMMA|P_NODUP|P_SECURE,
+#ifdef FEAT_VIMINFO
+ (char_u *)&p_viminfo, PV_NONE,
+#if defined(MSWIN)
+ {(char_u *)"", (char_u *)"'100,<50,s10,h,rA:,rB:"}
+#else
+# ifdef AMIGA
+ {(char_u *)"",
+ (char_u *)"'100,<50,s10,h,rdf0:,rdf1:,rdf2:"}
+# else
+ {(char_u *)"", (char_u *)"'100,<50,s10,h"}
+# endif
+#endif
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"viminfofile", "vif", P_STRING|P_EXPAND|P_ONECOMMA|P_NODUP
+ |P_SECURE|P_VI_DEF,
+#ifdef FEAT_VIMINFO
+ (char_u *)&p_viminfofile, PV_NONE,
+ {(char_u *)"", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"virtualedit", "ve", P_STRING|P_ONECOMMA|P_NODUP|P_VI_DEF
+ |P_VIM|P_CURSWANT,
+ (char_u *)&p_ve, PV_NONE,
+ {(char_u *)"", (char_u *)""}
+ SCTX_INIT},
+ {"visualbell", "vb", P_BOOL|P_VI_DEF,
+ (char_u *)&p_vb, PV_NONE,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"w300", NULL, P_NUM|P_VI_DEF,
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L} SCTX_INIT},
+ {"w1200", NULL, P_NUM|P_VI_DEF,
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L} SCTX_INIT},
+ {"w9600", NULL, P_NUM|P_VI_DEF,
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L} SCTX_INIT},
+ {"warn", NULL, P_BOOL|P_VI_DEF,
+ (char_u *)&p_warn, PV_NONE,
+ {(char_u *)TRUE, (char_u *)0L} SCTX_INIT},
+ {"weirdinvert", "wiv", P_BOOL|P_VI_DEF|P_RCLR,
+ (char_u *)&p_wiv, PV_NONE,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"whichwrap", "ww", P_STRING|P_VIM|P_ONECOMMA|P_FLAGLIST,
+ (char_u *)&p_ww, PV_NONE,
+ {(char_u *)"", (char_u *)"b,s"} SCTX_INIT},
+ {"wildchar", "wc", P_NUM|P_VIM,
+ (char_u *)&p_wc, PV_NONE,
+ {(char_u *)(long)Ctrl_E, (char_u *)(long)TAB}
+ SCTX_INIT},
+ {"wildcharm", "wcm", P_NUM|P_VI_DEF,
+ (char_u *)&p_wcm, PV_NONE,
+ {(char_u *)0L, (char_u *)0L} SCTX_INIT},
+ {"wildignore", "wig", P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP,
+#ifdef FEAT_WILDIGN
+ (char_u *)&p_wig, PV_NONE,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)"", (char_u *)0L} SCTX_INIT},
+ {"wildignorecase", "wic", P_BOOL|P_VI_DEF,
+ (char_u *)&p_wic, PV_NONE,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"wildmenu", "wmnu", P_BOOL|P_VI_DEF,
+#ifdef FEAT_WILDMENU
+ (char_u *)&p_wmnu, PV_NONE,
+#else
+ (char_u *)NULL, PV_NONE,
+#endif
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"wildmode", "wim", P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP,
+ (char_u *)&p_wim, PV_NONE,
+ {(char_u *)"full", (char_u *)0L} SCTX_INIT},
+ {"wildoptions", "wop", P_STRING|P_VI_DEF,
+#ifdef FEAT_CMDL_COMPL
+ (char_u *)&p_wop, PV_NONE,
+ {(char_u *)"", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"winaltkeys", "wak", P_STRING|P_VI_DEF,
+#ifdef FEAT_WAK
+ (char_u *)&p_wak, PV_NONE,
+ {(char_u *)"menu", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"window", "wi", P_NUM|P_VI_DEF,
+ (char_u *)&p_window, PV_NONE,
+ {(char_u *)0L, (char_u *)0L} SCTX_INIT},
+ {"winheight", "wh", P_NUM|P_VI_DEF,
+ (char_u *)&p_wh, PV_NONE,
+ {(char_u *)1L, (char_u *)0L} SCTX_INIT},
+ {"winfixheight", "wfh", P_BOOL|P_VI_DEF|P_RSTAT,
+ (char_u *)VAR_WIN, PV_WFH,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"winfixwidth", "wfw", P_BOOL|P_VI_DEF|P_RSTAT,
+ (char_u *)VAR_WIN, PV_WFW,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"winminheight", "wmh", P_NUM|P_VI_DEF,
+ (char_u *)&p_wmh, PV_NONE,
+ {(char_u *)1L, (char_u *)0L} SCTX_INIT},
+ {"winminwidth", "wmw", P_NUM|P_VI_DEF,
+ (char_u *)&p_wmw, PV_NONE,
+ {(char_u *)1L, (char_u *)0L} SCTX_INIT},
+ {"winptydll", NULL, P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
+#if defined(WIN3264) && defined(FEAT_TERMINAL)
+ (char_u *)&p_winptydll, PV_NONE, {
+# ifdef _WIN64
+ (char_u *)"winpty64.dll",
+# else
+ (char_u *)"winpty32.dll",
+# endif
+ (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
+ {"winwidth", "wiw", P_NUM|P_VI_DEF,
+ (char_u *)&p_wiw, PV_NONE,
+ {(char_u *)20L, (char_u *)0L} SCTX_INIT},
+ {"wrap", NULL, P_BOOL|P_VI_DEF|P_RWIN,
+ (char_u *)VAR_WIN, PV_WRAP,
+ {(char_u *)TRUE, (char_u *)0L} SCTX_INIT},
+ {"wrapmargin", "wm", P_NUM|P_VI_DEF,
+ (char_u *)&p_wm, PV_WM,
+ {(char_u *)0L, (char_u *)0L} SCTX_INIT},
+ {"wrapscan", "ws", P_BOOL|P_VI_DEF,
+ (char_u *)&p_ws, PV_NONE,
+ {(char_u *)TRUE, (char_u *)0L} SCTX_INIT},
+ {"write", NULL, P_BOOL|P_VI_DEF,
+ (char_u *)&p_write, PV_NONE,
+ {(char_u *)TRUE, (char_u *)0L} SCTX_INIT},
+ {"writeany", "wa", P_BOOL|P_VI_DEF,
+ (char_u *)&p_wa, PV_NONE,
+ {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
+ {"writebackup", "wb", P_BOOL|P_VI_DEF|P_VIM,
+ (char_u *)&p_wb, PV_NONE,
+ {
+#ifdef FEAT_WRITEBACKUP
+ (char_u *)TRUE,
+#else
+ (char_u *)FALSE,
+#endif
+ (char_u *)0L} SCTX_INIT},
+ {"writedelay", "wd", P_NUM|P_VI_DEF,
+ (char_u *)&p_wd, PV_NONE,
+ {(char_u *)0L, (char_u *)0L} SCTX_INIT},
+
+/* terminal output codes */
+#define p_term(sss, vvv) {sss, NULL, P_STRING|P_VI_DEF|P_RALL|P_SECURE, \
+ (char_u *)&vvv, PV_NONE, \
+ {(char_u *)"", (char_u *)0L} SCTX_INIT},
+
+ p_term("t_AB", T_CAB)
+ p_term("t_AF", T_CAF)
+ p_term("t_AL", T_CAL)
+ p_term("t_al", T_AL)
+ p_term("t_bc", T_BC)
+ p_term("t_BE", T_BE)
+ p_term("t_BD", T_BD)
+ p_term("t_cd", T_CD)
+ p_term("t_ce", T_CE)
+ p_term("t_cl", T_CL)
+ p_term("t_cm", T_CM)
+ p_term("t_Ce", T_UCE)
+ p_term("t_Co", T_CCO)
+ p_term("t_CS", T_CCS)
+ p_term("t_Cs", T_UCS)
+ p_term("t_cs", T_CS)
+ p_term("t_CV", T_CSV)
+ p_term("t_da", T_DA)
+ p_term("t_db", T_DB)
+ p_term("t_DL", T_CDL)
+ p_term("t_dl", T_DL)
+ p_term("t_EC", T_CEC)
+ p_term("t_EI", T_CEI)
+ p_term("t_fs", T_FS)
+ p_term("t_GP", T_CGP)
+ p_term("t_IE", T_CIE)
+ p_term("t_IS", T_CIS)
+ p_term("t_ke", T_KE)
+ p_term("t_ks", T_KS)
+ p_term("t_le", T_LE)
+ p_term("t_mb", T_MB)
+ p_term("t_md", T_MD)
+ p_term("t_me", T_ME)
+ p_term("t_mr", T_MR)
+ p_term("t_ms", T_MS)
+ p_term("t_nd", T_ND)
+ p_term("t_op", T_OP)
+ p_term("t_RF", T_RFG)
+ p_term("t_RB", T_RBG)
+ p_term("t_RC", T_CRC)
+ p_term("t_RI", T_CRI)
+ p_term("t_Ri", T_SRI)
+ p_term("t_RS", T_CRS)
+ p_term("t_RT", T_CRT)
+ p_term("t_RV", T_CRV)
+ p_term("t_Sb", T_CSB)
+ p_term("t_SC", T_CSC)
+ p_term("t_se", T_SE)
+ p_term("t_Sf", T_CSF)
+ p_term("t_SH", T_CSH)
+ p_term("t_SI", T_CSI)
+ p_term("t_Si", T_SSI)
+ p_term("t_so", T_SO)
+ p_term("t_SR", T_CSR)
+ p_term("t_sr", T_SR)
+ p_term("t_ST", T_CST)
+ p_term("t_Te", T_STE)
+ p_term("t_te", T_TE)
+ p_term("t_ti", T_TI)
+ p_term("t_Ts", T_STS)
+ p_term("t_ts", T_TS)
+ p_term("t_u7", T_U7)
+ p_term("t_ue", T_UE)
+ p_term("t_us", T_US)
+ p_term("t_ut", T_UT)
+ p_term("t_vb", T_VB)
+ p_term("t_ve", T_VE)
+ p_term("t_vi", T_VI)
+ p_term("t_VS", T_CVS)
+ p_term("t_vs", T_VS)
+ p_term("t_WP", T_CWP)
+ p_term("t_WS", T_CWS)
+ p_term("t_xn", T_XN)
+ p_term("t_xs", T_XS)
+ p_term("t_ZH", T_CZH)
+ p_term("t_ZR", T_CZR)
+ p_term("t_8f", T_8F)
+ p_term("t_8b", T_8B)
+
+/* terminal key codes are not in here */
+
+ /* end marker */
+ {NULL, NULL, 0, NULL, PV_NONE, {NULL, NULL} SCTX_INIT}
+};
+
+#define PARAM_COUNT (sizeof(options) / sizeof(struct vimoption))
+
+static char *(p_ambw_values[]) = {"single", "double", NULL};
+static char *(p_bg_values[]) = {"light", "dark", NULL};
+static char *(p_nf_values[]) = {"bin", "octal", "hex", "alpha", NULL};
+static char *(p_ff_values[]) = {FF_UNIX, FF_DOS, FF_MAC, NULL};
+#ifdef FEAT_CRYPT
+static char *(p_cm_values[]) = {"zip", "blowfish", "blowfish2", NULL};
+#endif
+#ifdef FEAT_CMDL_COMPL
+static char *(p_wop_values[]) = {"tagfile", NULL};
+#endif
+#ifdef FEAT_WAK
+static char *(p_wak_values[]) = {"yes", "menu", "no", NULL};
+#endif
+static char *(p_mousem_values[]) = {"extend", "popup", "popup_setpos", "mac", NULL};
+static char *(p_sel_values[]) = {"inclusive", "exclusive", "old", NULL};
+static char *(p_slm_values[]) = {"mouse", "key", "cmd", NULL};
+static char *(p_km_values[]) = {"startsel", "stopsel", NULL};
+#ifdef FEAT_BROWSE
+static char *(p_bsdir_values[]) = {"current", "last", "buffer", NULL};
+#endif
+static char *(p_scbopt_values[]) = {"ver", "hor", "jump", NULL};
+static char *(p_debug_values[]) = {"msg", "throw", "beep", NULL};
+static char *(p_ead_values[]) = {"both", "ver", "hor", NULL};
+static char *(p_buftype_values[]) = {"nofile", "nowrite", "quickfix", "help", "terminal", "acwrite", "prompt", NULL};
+static char *(p_bufhidden_values[]) = {"hide", "unload", "delete", "wipe", NULL};
+static char *(p_bs_values[]) = {"indent", "eol", "start", NULL};
+#ifdef FEAT_FOLDING
+static char *(p_fdm_values[]) = {"manual", "expr", "marker", "indent", "syntax",
+# ifdef FEAT_DIFF
+ "diff",
+# endif
+ NULL};
+static char *(p_fcl_values[]) = {"all", NULL};
+#endif
+#ifdef FEAT_INS_EXPAND
+static char *(p_cot_values[]) = {"menu", "menuone", "longest", "preview", "noinsert", "noselect", NULL};
+#endif
+#ifdef FEAT_SIGNS
+static char *(p_scl_values[]) = {"yes", "no", "auto", NULL};
+#endif
+#ifdef FEAT_TERMINAL
+static char *(p_tmod_values[]) = {"winpty", "conpty", "", NULL};
+#endif
+
+static void set_options_default(int opt_flags);
+static void set_string_default_esc(char *name, char_u *val, int escape);
+static char_u *term_bg_default(void);
+static void did_set_option(int opt_idx, int opt_flags, int new_value, int value_checked);
+static char_u *option_expand(int opt_idx, char_u *val);
+static void didset_options(void);
+static void didset_options2(void);
+static void check_string_option(char_u **pp);
+#if defined(FEAT_EVAL) || defined(PROTO)
+static long_u *insecure_flag(int opt_idx, int opt_flags);
+#else
+# define insecure_flag(opt_idx, opt_flags) (&options[opt_idx].flags)
+#endif
+static void set_string_option_global(int opt_idx, char_u **varp);
+static char *did_set_string_option(int opt_idx, char_u **varp, int new_value_alloced, char_u *oldval, char *errbuf, int opt_flags, int *value_checked);
+static char *set_chars_option(char_u **varp);
+#ifdef FEAT_CLIPBOARD
+static char *check_clipboard_option(void);
+#endif
+#ifdef FEAT_SPELL
+static char *did_set_spell_option(int is_spellfile);
+static char *compile_cap_prog(synblock_T *synblock);
+#endif
+#ifdef FEAT_EVAL
+static void set_option_sctx_idx(int opt_idx, int opt_flags, sctx_T script_ctx);
+#endif
+static char *set_bool_option(int opt_idx, char_u *varp, int value, int opt_flags);
+static char *set_num_option(int opt_idx, char_u *varp, long value, char *errbuf, size_t errbuflen, int opt_flags);
+static void check_redraw(long_u flags);
+static int findoption(char_u *);
+static int find_key_option(char_u *arg_arg, int has_lt);
+static void showoptions(int all, int opt_flags);
+static int optval_default(struct vimoption *, char_u *varp);
+static void showoneopt(struct vimoption *, int opt_flags);
+static int put_setstring(FILE *fd, char *cmd, char *name, char_u **valuep, long_u flags);
+static int put_setnum(FILE *fd, char *cmd, char *name, long *valuep);
+static int put_setbool(FILE *fd, char *cmd, char *name, int value);
+static int istermoption(struct vimoption *);
+static char_u *get_varp_scope(struct vimoption *p, int opt_flags);
+static char_u *get_varp(struct vimoption *);
+static void option_value2string(struct vimoption *, int opt_flags);
+static void check_winopt(winopt_T *wop);
+static int wc_use_keyname(char_u *varp, long *wcp);
+#ifdef FEAT_LANGMAP
+static void langmap_init(void);
+static void langmap_set(void);
+#endif
+static void paste_option_changed(void);
+static void compatible_set(void);
+#ifdef FEAT_LINEBREAK
+static void fill_breakat_flags(void);
+#endif
+static int opt_strings_flags(char_u *val, char **values, unsigned *flagp, int list);
+static int check_opt_strings(char_u *val, char **values, int);
+static int check_opt_wim(void);
+#ifdef FEAT_LINEBREAK
+static int briopt_check(win_T *wp);
+#endif
+
+/*
+ * Initialize the options, first part.
+ *
+ * Called only once from main(), just after creating the first buffer.
+ * If "clean_arg" is TRUE Vim was started with --clean.
+ */
+ void
+set_init_1(int clean_arg)
+{
+ char_u *p;
+ int opt_idx;
+ long_u n;
+
+#ifdef FEAT_LANGMAP
+ langmap_init();
+#endif
+
+ /* Be Vi compatible by default */
+ p_cp = TRUE;
+
+ /* Use POSIX compatibility when $VIM_POSIX is set. */
+ if (mch_getenv((char_u *)"VIM_POSIX") != NULL)
+ {
+ set_string_default("cpo", (char_u *)CPO_ALL);
+ set_string_default("shm", (char_u *)"A");
+ }
+
+ /*
+ * Find default value for 'shell' option.
+ * Don't use it if it is empty.
+ */
+ if (((p = mch_getenv((char_u *)"SHELL")) != NULL && *p != NUL)
+#if defined(MSWIN)
+ || ((p = mch_getenv((char_u *)"COMSPEC")) != NULL && *p != NUL)
+# ifdef WIN3264
+ || ((p = (char_u *)default_shell()) != NULL && *p != NUL)
+# endif
+#endif
+ )
+ set_string_default_esc("sh", p, TRUE);
+
+#ifdef FEAT_WILDIGN
+ /*
+ * Set the default for 'backupskip' to include environment variables for
+ * temp files.
+ */
+ {
+# ifdef UNIX
+ static char *(names[4]) = {"", "TMPDIR", "TEMP", "TMP"};
+# else
+ static char *(names[3]) = {"TMPDIR", "TEMP", "TMP"};
+# endif
+ int len;
+ garray_T ga;
+ int mustfree;
+
+ ga_init2(&ga, 1, 100);
+ for (n = 0; n < (long)(sizeof(names) / sizeof(char *)); ++n)
+ {
+ mustfree = FALSE;
+# ifdef UNIX
+ if (*names[n] == NUL)
+# ifdef MACOS_X
+ p = (char_u *)"/private/tmp";
+# else
+ p = (char_u *)"/tmp";
+# endif
+ else
+# endif
+ p = vim_getenv((char_u *)names[n], &mustfree);
+ if (p != NULL && *p != NUL)
+ {
+ /* First time count the NUL, otherwise count the ','. */
+ len = (int)STRLEN(p) + 3;
+ if (ga_grow(&ga, len) == OK)
+ {
+ if (ga.ga_len > 0)
+ STRCAT(ga.ga_data, ",");
+ STRCAT(ga.ga_data, p);
+ add_pathsep(ga.ga_data);
+ STRCAT(ga.ga_data, "*");
+ ga.ga_len += len;
+ }
+ }
+ if (mustfree)
+ vim_free(p);
+ }
+ if (ga.ga_data != NULL)
+ {
+ set_string_default("bsk", ga.ga_data);
+ vim_free(ga.ga_data);
+ }
+ }
+#endif
+
+ /*
+ * 'maxmemtot' and 'maxmem' may have to be adjusted for available memory
+ */
+ opt_idx = findoption((char_u *)"maxmemtot");
+ if (opt_idx >= 0)
+ {
+#if !defined(HAVE_AVAIL_MEM) && !defined(HAVE_TOTAL_MEM)
+ if (options[opt_idx].def_val[VI_DEFAULT] == (char_u *)0L)
+#endif
+ {
+#ifdef HAVE_AVAIL_MEM
+ /* Use amount of memory available at this moment. */
+ n = (mch_avail_mem(FALSE) >> 1);
+#else
+# ifdef HAVE_TOTAL_MEM
+ /* Use amount of memory available to Vim. */
+ n = (mch_total_mem(FALSE) >> 1);
+# else
+ n = (0x7fffffff >> 11);
+# endif
+#endif
+ options[opt_idx].def_val[VI_DEFAULT] = (char_u *)n;
+ opt_idx = findoption((char_u *)"maxmem");
+ if (opt_idx >= 0)
+ {
+#if !defined(HAVE_AVAIL_MEM) && !defined(HAVE_TOTAL_MEM)
+ if ((long)(long_i)options[opt_idx].def_val[VI_DEFAULT] > (long)n
+ || (long)(long_i)options[opt_idx].def_val[VI_DEFAULT] == 0L)
+#endif
+ options[opt_idx].def_val[VI_DEFAULT] = (char_u *)n;
+ }
+ }
+ }
+
+#ifdef FEAT_SEARCHPATH
+ {
+ char_u *cdpath;
+ char_u *buf;
+ int i;
+ int j;
+ int mustfree = FALSE;
+
+ /* Initialize the 'cdpath' option's default value. */
+ cdpath = vim_getenv((char_u *)"CDPATH", &mustfree);
+ if (cdpath != NULL)
+ {
+ buf = alloc((unsigned)((STRLEN(cdpath) << 1) + 2));
+ if (buf != NULL)
+ {
+ buf[0] = ','; /* start with ",", current dir first */
+ j = 1;
+ for (i = 0; cdpath[i] != NUL; ++i)
+ {
+ if (vim_ispathlistsep(cdpath[i]))
+ buf[j++] = ',';
+ else
+ {
+ if (cdpath[i] == ' ' || cdpath[i] == ',')
+ buf[j++] = '\\';
+ buf[j++] = cdpath[i];
+ }
+ }
+ buf[j] = NUL;
+ opt_idx = findoption((char_u *)"cdpath");
+ if (opt_idx >= 0)
+ {
+ options[opt_idx].def_val[VI_DEFAULT] = buf;
+ options[opt_idx].flags |= P_DEF_ALLOCED;
+ }
+ else
+ vim_free(buf); /* cannot happen */
+ }
+ if (mustfree)
+ vim_free(cdpath);
+ }
+ }
+#endif
+
+#if defined(FEAT_POSTSCRIPT) && (defined(MSWIN) || defined(VMS) || defined(EBCDIC) || defined(MAC) || defined(hpux))
+ /* Set print encoding on platforms that don't default to latin1 */
+ set_string_default("penc",
+# if defined(MSWIN)
+ (char_u *)"cp1252"
+# else
+# ifdef VMS
+ (char_u *)"dec-mcs"
+# else
+# ifdef EBCDIC
+ (char_u *)"ebcdic-uk"
+# else
+# ifdef MAC
+ (char_u *)"mac-roman"
+# else /* HPUX */
+ (char_u *)"hp-roman8"
+# endif
+# endif
+# endif
+# endif
+ );
+#endif
+
+#ifdef FEAT_POSTSCRIPT
+ /* 'printexpr' must be allocated to be able to evaluate it. */
+ set_string_default("pexpr",
+# if defined(MSWIN)
+ (char_u *)"system('copy' . ' ' . v:fname_in . (&printdevice == '' ? ' LPT1:' : (' \"' . &printdevice . '\"'))) . delete(v:fname_in)"
+# else
+# ifdef VMS
+ (char_u *)"system('print/delete' . (&printdevice == '' ? '' : ' /queue=' . &printdevice) . ' ' . v:fname_in)"
+
+# else
+ (char_u *)"system('lpr' . (&printdevice == '' ? '' : ' -P' . &printdevice) . ' ' . v:fname_in) . delete(v:fname_in) + v:shell_error"
+# endif
+# endif
+ );
+#endif
+
+ /*
+ * Set all the options (except the terminal options) to their default
+ * value. Also set the global value for local options.
+ */
+ set_options_default(0);
+
+#ifdef CLEAN_RUNTIMEPATH
+ if (clean_arg)
+ {
+ opt_idx = findoption((char_u *)"runtimepath");
+ if (opt_idx >= 0)
+ {
+ options[opt_idx].def_val[VI_DEFAULT] = (char_u *)CLEAN_RUNTIMEPATH;
+ p_rtp = (char_u *)CLEAN_RUNTIMEPATH;
+ }
+ opt_idx = findoption((char_u *)"packpath");
+ if (opt_idx >= 0)
+ {
+ options[opt_idx].def_val[VI_DEFAULT] = (char_u *)CLEAN_RUNTIMEPATH;
+ p_pp = (char_u *)CLEAN_RUNTIMEPATH;
+ }
+ }
+#endif
+
+#ifdef FEAT_GUI
+ if (found_reverse_arg)
+ set_option_value((char_u *)"bg", 0L, (char_u *)"dark", 0);
+#endif
+
+ curbuf->b_p_initialized = TRUE;
+ curbuf->b_p_ar = -1; /* no local 'autoread' value */
+ curbuf->b_p_ul = NO_LOCAL_UNDOLEVEL;
+ check_buf_options(curbuf);
+ check_win_options(curwin);
+ check_options();
+
+ /* Must be before option_expand(), because that one needs vim_isIDc() */
+ didset_options();
+
+#ifdef FEAT_SPELL
+ /* Use the current chartab for the generic chartab. This is not in
+ * didset_options() because it only depends on 'encoding'. */
+ init_spell_chartab();
+#endif
+
+ /*
+ * Expand environment variables and things like "~" for the defaults.
+ * If option_expand() returns non-NULL the variable is expanded. This can
+ * only happen for non-indirect options.
+ * Also set the default to the expanded value, so ":set" does not list
+ * them.
+ * Don't set the P_ALLOCED flag, because we don't want to free the
+ * default.
+ */
+ for (opt_idx = 0; !istermoption(&options[opt_idx]); opt_idx++)
+ {
+ if ((options[opt_idx].flags & P_GETTEXT)
+ && options[opt_idx].var != NULL)
+ p = (char_u *)_(*(char **)options[opt_idx].var);
+ else
+ p = option_expand(opt_idx, NULL);
+ if (p != NULL && (p = vim_strsave(p)) != NULL)
+ {
+ *(char_u **)options[opt_idx].var = p;
+ /* VIMEXP
+ * Defaults for all expanded options are currently the same for Vi
+ * and Vim. When this changes, add some code here! Also need to
+ * split P_DEF_ALLOCED in two.
+ */
+ if (options[opt_idx].flags & P_DEF_ALLOCED)
+ vim_free(options[opt_idx].def_val[VI_DEFAULT]);
+ options[opt_idx].def_val[VI_DEFAULT] = p;
+ options[opt_idx].flags |= P_DEF_ALLOCED;
+ }
+ }
+
+ save_file_ff(curbuf); /* Buffer is unchanged */
+
+#if defined(FEAT_ARABIC)
+ /* Detect use of mlterm.
+ * Mlterm is a terminal emulator akin to xterm that has some special
+ * abilities (bidi namely).
+ * NOTE: mlterm's author is being asked to 'set' a variable
+ * instead of an environment variable due to inheritance.
+ */
+ if (mch_getenv((char_u *)"MLTERM") != NULL)
+ set_option_value((char_u *)"tbidi", 1L, NULL, 0);
+#endif
+
+ didset_options2();
+
+# if defined(WIN3264) && defined(FEAT_GETTEXT)
+ /*
+ * If $LANG isn't set, try to get a good value for it. This makes the
+ * right language be used automatically. Don't do this for English.
+ */
+ if (mch_getenv((char_u *)"LANG") == NULL)
+ {
+ char buf[20];
+
+ /* Could use LOCALE_SISO639LANGNAME, but it's not in Win95.
+ * LOCALE_SABBREVLANGNAME gives us three letters, like "enu", we use
+ * only the first two. */
+ n = GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SABBREVLANGNAME,
+ (LPTSTR)buf, 20);
+ if (n >= 2 && STRNICMP(buf, "en", 2) != 0)
+ {
+ /* There are a few exceptions (probably more) */
+ if (STRNICMP(buf, "cht", 3) == 0 || STRNICMP(buf, "zht", 3) == 0)
+ STRCPY(buf, "zh_TW");
+ else if (STRNICMP(buf, "chs", 3) == 0
+ || STRNICMP(buf, "zhc", 3) == 0)
+ STRCPY(buf, "zh_CN");
+ else if (STRNICMP(buf, "jp", 2) == 0)
+ STRCPY(buf, "ja");
+ else
+ buf[2] = NUL; /* truncate to two-letter code */
+ vim_setenv((char_u *)"LANG", (char_u *)buf);
+ }
+ }
+# else
+# ifdef MACOS_CONVERT
+ /* Moved to os_mac_conv.c to avoid dependency problems. */
+ mac_lang_init();
+# endif
+# endif
+
+ /* enc_locale() will try to find the encoding of the current locale. */
+ p = enc_locale();
+ if (p != NULL)
+ {
+ char_u *save_enc;
+
+ /* Try setting 'encoding' and check if the value is valid.
+ * If not, go back to the default "latin1". */
+ save_enc = p_enc;
+ p_enc = p;
+ if (STRCMP(p_enc, "gb18030") == 0)
+ {
+ /* We don't support "gb18030", but "cp936" is a good substitute
+ * for practical purposes, thus use that. It's not an alias to
+ * still support conversion between gb18030 and utf-8. */
+ p_enc = vim_strsave((char_u *)"cp936");
+ vim_free(p);
+ }
+ if (mb_init() == NULL)
+ {
+ opt_idx = findoption((char_u *)"encoding");
+ if (opt_idx >= 0)
+ {
+ options[opt_idx].def_val[VI_DEFAULT] = p_enc;
+ options[opt_idx].flags |= P_DEF_ALLOCED;
+ }
+
+#if defined(MSWIN) || defined(MACOS_X) || defined(VMS)
+ if (STRCMP(p_enc, "latin1") == 0 || enc_utf8)
+ {
+ /* Adjust the default for 'isprint' and 'iskeyword' to match
+ * latin1. Also set the defaults for when 'nocompatible' is
+ * set. */
+ set_string_option_direct((char_u *)"isp", -1,
+ ISP_LATIN1, OPT_FREE, SID_NONE);
+ set_string_option_direct((char_u *)"isk", -1,
+ ISK_LATIN1, OPT_FREE, SID_NONE);
+ opt_idx = findoption((char_u *)"isp");
+ if (opt_idx >= 0)
+ options[opt_idx].def_val[VIM_DEFAULT] = ISP_LATIN1;
+ opt_idx = findoption((char_u *)"isk");
+ if (opt_idx >= 0)
+ options[opt_idx].def_val[VIM_DEFAULT] = ISK_LATIN1;
+ (void)init_chartab();
+ }
+#endif
+
+#if defined(WIN3264) && !defined(FEAT_GUI)
+ /* Win32 console: When GetACP() returns a different value from
+ * GetConsoleCP() set 'termencoding'. */
+ if (GetACP() != GetConsoleCP())
+ {
+ char buf[50];
+
+ /* Win32 console: In ConPTY, GetConsoleCP() returns zero.
+ * Use an alternative value. */
+ if (GetConsoleCP() == 0)
+ sprintf(buf, "cp%ld", (long)GetACP());
+ else
+ sprintf(buf, "cp%ld", (long)GetConsoleCP());
+ p_tenc = vim_strsave((char_u *)buf);
+ if (p_tenc != NULL)
+ {
+ opt_idx = findoption((char_u *)"termencoding");
+ if (opt_idx >= 0)
+ {
+ options[opt_idx].def_val[VI_DEFAULT] = p_tenc;
+ options[opt_idx].flags |= P_DEF_ALLOCED;
+ }
+ convert_setup(&input_conv, p_tenc, p_enc);
+ convert_setup(&output_conv, p_enc, p_tenc);
+ }
+ else
+ p_tenc = empty_option;
+ }
+#endif
+#if defined(WIN3264)
+ /* $HOME may have characters in active code page. */
+ init_homedir();
+#endif
+ }
+ else
+ {
+ vim_free(p_enc);
+ p_enc = save_enc;
+ }
+ }
+
+#ifdef FEAT_MULTI_LANG
+ /* Set the default for 'helplang'. */
+ set_helplang_default(get_mess_lang());
+#endif
+}
+
+/*
+ * Set an option to its default value.
+ * This does not take care of side effects!
+ */
+ static void
+set_option_default(
+ int opt_idx,
+ int opt_flags, /* OPT_FREE, OPT_LOCAL and/or OPT_GLOBAL */
+ int compatible) /* use Vi default value */
+{
+ char_u *varp; /* pointer to variable for current option */
+ int dvi; /* index in def_val[] */
+ long_u flags;
+ long_u *flagsp;
+ int both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0;
+
+ varp = get_varp_scope(&(options[opt_idx]), both ? OPT_LOCAL : opt_flags);
+ flags = options[opt_idx].flags;
+ if (varp != NULL) /* skip hidden option, nothing to do for it */
+ {
+ dvi = ((flags & P_VI_DEF) || compatible) ? VI_DEFAULT : VIM_DEFAULT;
+ if (flags & P_STRING)
+ {
+ /* Use set_string_option_direct() for local options to handle
+ * freeing and allocating the value. */
+ if (options[opt_idx].indir != PV_NONE)
+ set_string_option_direct(NULL, opt_idx,
+ options[opt_idx].def_val[dvi], opt_flags, 0);
+ else
+ {
+ if ((opt_flags & OPT_FREE) && (flags & P_ALLOCED))
+ free_string_option(*(char_u **)(varp));
+ *(char_u **)varp = options[opt_idx].def_val[dvi];
+ options[opt_idx].flags &= ~P_ALLOCED;
+ }
+ }
+ else if (flags & P_NUM)
+ {
+ if (options[opt_idx].indir == PV_SCROLL)
+ win_comp_scroll(curwin);
+ else
+ {
+ long def_val = (long)(long_i)options[opt_idx].def_val[dvi];
+
+ if ((long *)varp == &curwin->w_p_so
+ || (long *)varp == &curwin->w_p_siso)
+ // 'scrolloff' and 'sidescrolloff' local values have a
+ // different default value than the global default.
+ *(long *)varp = -1;
+ else
+ *(long *)varp = def_val;
+ /* May also set global value for local option. */
+ if (both)
+ *(long *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL) =
+ def_val;
+ }
+ }
+ else /* P_BOOL */
+ {
+ /* the cast to long is required for Manx C, long_i is needed for
+ * MSVC */
+ *(int *)varp = (int)(long)(long_i)options[opt_idx].def_val[dvi];
+#ifdef UNIX
+ /* 'modeline' defaults to off for root */
+ if (options[opt_idx].indir == PV_ML && getuid() == ROOT_UID)
+ *(int *)varp = FALSE;
+#endif
+ /* May also set global value for local option. */
+ if (both)
+ *(int *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL) =
+ *(int *)varp;
+ }
+
+ /* The default value is not insecure. */
+ flagsp = insecure_flag(opt_idx, opt_flags);
+ *flagsp = *flagsp & ~P_INSECURE;
+ }
+
+#ifdef FEAT_EVAL
+ set_option_sctx_idx(opt_idx, opt_flags, current_sctx);
+#endif
+}
+
+/*
+ * Set all options (except terminal options) to their default value.
+ * When "opt_flags" is non-zero skip 'encoding'.
+ */
+ static void
+set_options_default(
+ int opt_flags) /* OPT_FREE, OPT_LOCAL and/or OPT_GLOBAL */
+{
+ int i;
+ win_T *wp;
+ tabpage_T *tp;
+
+ for (i = 0; !istermoption(&options[i]); i++)
+ if (!(options[i].flags & P_NODEFAULT)
+ && (opt_flags == 0
+ || (options[i].var != (char_u *)&p_enc
+# if defined(FEAT_CRYPT)
+ && options[i].var != (char_u *)&p_cm
+ && options[i].var != (char_u *)&p_key
+# endif
+ )))
+ set_option_default(i, opt_flags, p_cp);
+
+ /* The 'scroll' option must be computed for all windows. */
+ FOR_ALL_TAB_WINDOWS(tp, wp)
+ win_comp_scroll(wp);
+#ifdef FEAT_CINDENT
+ parse_cino(curbuf);
+#endif
+}
+
+/*
+ * Set the Vi-default value of a string option.
+ * Used for 'sh', 'backupskip' and 'term'.
+ * When "escape" is TRUE escape spaces with a backslash.
+ */
+ static void
+set_string_default_esc(char *name, char_u *val, int escape)
+{
+ char_u *p;
+ int opt_idx;
+
+ if (escape && vim_strchr(val, ' ') != NULL)
+ p = vim_strsave_escaped(val, (char_u *)" ");
+ else
+ p = vim_strsave(val);
+ if (p != NULL) /* we don't want a NULL */
+ {
+ opt_idx = findoption((char_u *)name);
+ if (opt_idx >= 0)
+ {
+ if (options[opt_idx].flags & P_DEF_ALLOCED)
+ vim_free(options[opt_idx].def_val[VI_DEFAULT]);
+ options[opt_idx].def_val[VI_DEFAULT] = p;
+ options[opt_idx].flags |= P_DEF_ALLOCED;
+ }
+ }
+}
+
+ void
+set_string_default(char *name, char_u *val)
+{
+ set_string_default_esc(name, val, FALSE);
+}
+
+/*
+ * Set the Vi-default value of a number option.
+ * Used for 'lines' and 'columns'.
+ */
+ void
+set_number_default(char *name, long val)
+{
+ int opt_idx;
+
+ opt_idx = findoption((char_u *)name);
+ if (opt_idx >= 0)
+ options[opt_idx].def_val[VI_DEFAULT] = (char_u *)(long_i)val;
+}
+
+#if defined(EXITFREE) || defined(PROTO)
+/*
+ * Free all options.
+ */
+ void
+free_all_options(void)
+{
+ int i;
+
+ for (i = 0; !istermoption(&options[i]); i++)
+ {
+ if (options[i].indir == PV_NONE)
+ {
+ /* global option: free value and default value. */
+ if ((options[i].flags & P_ALLOCED) && options[i].var != NULL)
+ free_string_option(*(char_u **)options[i].var);
+ if (options[i].flags & P_DEF_ALLOCED)
+ free_string_option(options[i].def_val[VI_DEFAULT]);
+ }
+ else if (options[i].var != VAR_WIN
+ && (options[i].flags & P_STRING))
+ /* buffer-local option: free global value */
+ free_string_option(*(char_u **)options[i].var);
+ }
+}
+#endif
+
+
+/*
+ * Initialize the options, part two: After getting Rows and Columns and
+ * setting 'term'.
+ */
+ void
+set_init_2(void)
+{
+ int idx;
+
+ /*
+ * 'scroll' defaults to half the window height. The stored default is zero,
+ * which results in the actual value computed from the window height.
+ */
+ idx = findoption((char_u *)"scroll");
+ if (idx >= 0 && !(options[idx].flags & P_WAS_SET))
+ set_option_default(idx, OPT_LOCAL, p_cp);
+ comp_col();
+
+ /*
+ * 'window' is only for backwards compatibility with Vi.
+ * Default is Rows - 1.
+ */
+ if (!option_was_set((char_u *)"window"))
+ p_window = Rows - 1;
+ set_number_default("window", Rows - 1);
+
+ /* For DOS console the default is always black. */
+#if !((defined(WIN3264)) && !defined(FEAT_GUI))
+ /*
+ * If 'background' wasn't set by the user, try guessing the value,
+ * depending on the terminal name. Only need to check for terminals
+ * with a dark background, that can handle color.
+ */
+ idx = findoption((char_u *)"bg");
+ if (idx >= 0 && !(options[idx].flags & P_WAS_SET)
+ && *term_bg_default() == 'd')
+ {
+ set_string_option_direct(NULL, idx, (char_u *)"dark", OPT_FREE, 0);
+ /* don't mark it as set, when starting the GUI it may be
+ * changed again */
+ options[idx].flags &= ~P_WAS_SET;
+ }
+#endif
+
+#ifdef CURSOR_SHAPE
+ parse_shape_opt(SHAPE_CURSOR); /* set cursor shapes from 'guicursor' */
+#endif
+#ifdef FEAT_MOUSESHAPE
+ parse_shape_opt(SHAPE_MOUSE); /* set mouse shapes from 'mouseshape' */
+#endif
+#ifdef FEAT_PRINTER
+ (void)parse_printoptions(); /* parse 'printoptions' default value */
+#endif
+}
+
+/*
+ * Return "dark" or "light" depending on the kind of terminal.
+ * This is just guessing! Recognized are:
+ * "linux" Linux console
+ * "screen.linux" Linux console with screen
+ * "cygwin.*" Cygwin shell
+ * "putty.*" Putty program
+ * We also check the COLORFGBG environment variable, which is set by
+ * rxvt and derivatives. This variable contains either two or three
+ * values separated by semicolons; we want the last value in either
+ * case. If this value is 0-6 or 8, our background is dark.
+ */
+ static char_u *
+term_bg_default(void)
+{
+#if defined(WIN3264)
+ /* DOS console is nearly always black */
+ return (char_u *)"dark";
+#else
+ char_u *p;
+
+ if (STRCMP(T_NAME, "linux") == 0
+ || STRCMP(T_NAME, "screen.linux") == 0
+ || STRNCMP(T_NAME, "cygwin", 6) == 0
+ || STRNCMP(T_NAME, "putty", 5) == 0
+ || ((p = mch_getenv((char_u *)"COLORFGBG")) != NULL
+ && (p = vim_strrchr(p, ';')) != NULL
+ && ((p[1] >= '0' && p[1] <= '6') || p[1] == '8')
+ && p[2] == NUL))
+ return (char_u *)"dark";
+ return (char_u *)"light";
+#endif
+}
+
+/*
+ * Initialize the options, part three: After reading the .vimrc
+ */
+ void
+set_init_3(void)
+{
+#if defined(UNIX) || defined(WIN3264)
+/*
+ * Set 'shellpipe' and 'shellredir', depending on the 'shell' option.
+ * This is done after other initializations, where 'shell' might have been
+ * set, but only if they have not been set before.
+ */
+ char_u *p;
+ int idx_srr;
+ int do_srr;
+# ifdef FEAT_QUICKFIX
+ int idx_sp;
+ int do_sp;
+# endif
+
+ idx_srr = findoption((char_u *)"srr");
+ if (idx_srr < 0)
+ do_srr = FALSE;
+ else
+ do_srr = !(options[idx_srr].flags & P_WAS_SET);
+# ifdef FEAT_QUICKFIX
+ idx_sp = findoption((char_u *)"sp");
+ if (idx_sp < 0)
+ do_sp = FALSE;
+ else
+ do_sp = !(options[idx_sp].flags & P_WAS_SET);
+# endif
+ p = get_isolated_shell_name();
+ if (p != NULL)
+ {
+ /*
+ * Default for p_sp is "| tee", for p_srr is ">".
+ * For known shells it is changed here to include stderr.
+ */
+ if ( fnamecmp(p, "csh") == 0
+ || fnamecmp(p, "tcsh") == 0
+# if defined(WIN3264) /* also check with .exe extension */
+ || fnamecmp(p, "csh.exe") == 0
+ || fnamecmp(p, "tcsh.exe") == 0
+# endif
+ )
+ {
+# if defined(FEAT_QUICKFIX)
+ if (do_sp)
+ {
+# ifdef WIN3264
+ p_sp = (char_u *)">&";
+# else
+ p_sp = (char_u *)"|& tee";
+# endif
+ options[idx_sp].def_val[VI_DEFAULT] = p_sp;
+ }
+# endif
+ if (do_srr)
+ {
+ p_srr = (char_u *)">&";
+ options[idx_srr].def_val[VI_DEFAULT] = p_srr;
+ }
+ }
+ else
+ /* Always use bourne shell style redirection if we reach this */
+ if ( fnamecmp(p, "sh") == 0
+ || fnamecmp(p, "ksh") == 0
+ || fnamecmp(p, "mksh") == 0
+ || fnamecmp(p, "pdksh") == 0
+ || fnamecmp(p, "zsh") == 0
+ || fnamecmp(p, "zsh-beta") == 0
+ || fnamecmp(p, "bash") == 0
+ || fnamecmp(p, "fish") == 0
+# ifdef WIN3264
+ || fnamecmp(p, "cmd") == 0
+ || fnamecmp(p, "sh.exe") == 0
+ || fnamecmp(p, "ksh.exe") == 0
+ || fnamecmp(p, "mksh.exe") == 0
+ || fnamecmp(p, "pdksh.exe") == 0
+ || fnamecmp(p, "zsh.exe") == 0
+ || fnamecmp(p, "zsh-beta.exe") == 0
+ || fnamecmp(p, "bash.exe") == 0
+ || fnamecmp(p, "cmd.exe") == 0
+# endif
+ )
+ {
+# if defined(FEAT_QUICKFIX)
+ if (do_sp)
+ {
+# ifdef WIN3264
+ p_sp = (char_u *)">%s 2>&1";
+# else
+ p_sp = (char_u *)"2>&1| tee";
+# endif
+ options[idx_sp].def_val[VI_DEFAULT] = p_sp;
+ }
+# endif
+ if (do_srr)
+ {
+ p_srr = (char_u *)">%s 2>&1";
+ options[idx_srr].def_val[VI_DEFAULT] = p_srr;
+ }
+ }
+ vim_free(p);
+ }
+#endif
+
+#if defined(WIN3264)
+ /*
+ * Set 'shellcmdflag', 'shellxquote', and 'shellquote' depending on the
+ * 'shell' option.
+ * This is done after other initializations, where 'shell' might have been
+ * set, but only if they have not been set before. Default for p_shcf is
+ * "/c", for p_shq is "". For "sh" like shells it is changed here to
+ * "-c" and "\"". And for Win32 we need to set p_sxq instead.
+ */
+ if (strstr((char *)gettail(p_sh), "sh") != NULL)
+ {
+ int idx3;
+
+ idx3 = findoption((char_u *)"shcf");
+ if (idx3 >= 0 && !(options[idx3].flags & P_WAS_SET))
+ {
+ p_shcf = (char_u *)"-c";
+ options[idx3].def_val[VI_DEFAULT] = p_shcf;
+ }
+
+ /* Somehow Win32 requires the quotes around the redirection too */
+ idx3 = findoption((char_u *)"sxq");
+ if (idx3 >= 0 && !(options[idx3].flags & P_WAS_SET))
+ {
+ p_sxq = (char_u *)"\"";
+ options[idx3].def_val[VI_DEFAULT] = p_sxq;
+ }
+ }
+ else if (strstr((char *)gettail(p_sh), "cmd.exe") != NULL)
+ {
+ int idx3;
+
+ /*
+ * cmd.exe on Windows will strip the first and last double quote given
+ * on the command line, e.g. most of the time things like:
+ * cmd /c "my path/to/echo" "my args to echo"
+ * become:
+ * my path/to/echo" "my args to echo
+ * when executed.
+ *
+ * To avoid this, set shellxquote to surround the command in
+ * parenthesis. This appears to make most commands work, without
+ * breaking commands that worked previously, such as
+ * '"path with spaces/cmd" "a&b"'.
+ */
+ idx3 = findoption((char_u *)"sxq");
+ if (idx3 >= 0 && !(options[idx3].flags & P_WAS_SET))
+ {
+ p_sxq = (char_u *)"(";
+ options[idx3].def_val[VI_DEFAULT] = p_sxq;
+ }
+
+ idx3 = findoption((char_u *)"shcf");
+ if (idx3 >= 0 && !(options[idx3].flags & P_WAS_SET))
+ {
+ p_shcf = (char_u *)"/c";
+ options[idx3].def_val[VI_DEFAULT] = p_shcf;
+ }
+ }
+#endif
+
+ if (BUFEMPTY())
+ {
+ int idx_ffs = findoption((char_u *)"ffs");
+
+ /* Apply the first entry of 'fileformats' to the initial buffer. */
+ if (idx_ffs >= 0 && (options[idx_ffs].flags & P_WAS_SET))
+ set_fileformat(default_fileformat(), OPT_LOCAL);
+ }
+
+#ifdef FEAT_TITLE
+ set_title_defaults();
+#endif
+}
+
+#if defined(FEAT_MULTI_LANG) || defined(PROTO)
+/*
+ * When 'helplang' is still at its default value, set it to "lang".
+ * Only the first two characters of "lang" are used.
+ */
+ void
+set_helplang_default(char_u *lang)
+{
+ int idx;
+
+ if (lang == NULL || STRLEN(lang) < 2) /* safety check */
+ return;
+ idx = findoption((char_u *)"hlg");
+ if (idx >= 0 && !(options[idx].flags & P_WAS_SET))
+ {
+ if (options[idx].flags & P_ALLOCED)
+ free_string_option(p_hlg);
+ p_hlg = vim_strsave(lang);
+ if (p_hlg == NULL)
+ p_hlg = empty_option;
+ else
+ {
+ // zh_CN becomes "cn", zh_TW becomes "tw"
+ if (STRNICMP(p_hlg, "zh_", 3) == 0 && STRLEN(p_hlg) >= 5)
+ {
+ p_hlg[0] = TOLOWER_ASC(p_hlg[3]);
+ p_hlg[1] = TOLOWER_ASC(p_hlg[4]);
+ }
+ // any C like setting, such as C.UTF-8, becomes "en"
+ else if (STRLEN(p_hlg) >= 1 && *p_hlg == 'C')
+ {
+ p_hlg[0] = 'e';
+ p_hlg[1] = 'n';
+ }
+ p_hlg[2] = NUL;
+ }
+ options[idx].flags |= P_ALLOCED;
+ }
+}
+#endif
+
+#ifdef FEAT_GUI
+ static char_u *
+gui_bg_default(void)
+{
+ if (gui_get_lightness(gui.back_pixel) < 127)
+ return (char_u *)"dark";
+ return (char_u *)"light";
+}
+
+/*
+ * Option initializations that can only be done after opening the GUI window.
+ */
+ void
+init_gui_options(void)
+{
+ /* Set the 'background' option according to the lightness of the
+ * background color, unless the user has set it already. */
+ if (!option_was_set((char_u *)"bg") && STRCMP(p_bg, gui_bg_default()) != 0)
+ {
+ set_option_value((char_u *)"bg", 0L, gui_bg_default(), 0);
+ highlight_changed();
+ }
+}
+#endif
+
+#ifdef FEAT_TITLE
+/*
+ * 'title' and 'icon' only default to true if they have not been set or reset
+ * in .vimrc and we can read the old value.
+ * When 'title' and 'icon' have been reset in .vimrc, we won't even check if
+ * they can be reset. This reduces startup time when using X on a remote
+ * machine.
+ */
+ void
+set_title_defaults(void)
+{
+ int idx1;
+ long val;
+
+ /*
+ * If GUI is (going to be) used, we can always set the window title and
+ * icon name. Saves a bit of time, because the X11 display server does
+ * not need to be contacted.
+ */
+ idx1 = findoption((char_u *)"title");
+ if (idx1 >= 0 && !(options[idx1].flags & P_WAS_SET))
+ {
+#ifdef FEAT_GUI
+ if (gui.starting || gui.in_use)
+ val = TRUE;
+ else
+#endif
+ val = mch_can_restore_title();
+ options[idx1].def_val[VI_DEFAULT] = (char_u *)(long_i)val;
+ p_title = val;
+ }
+ idx1 = findoption((char_u *)"icon");
+ if (idx1 >= 0 && !(options[idx1].flags & P_WAS_SET))
+ {
+#ifdef FEAT_GUI
+ if (gui.starting || gui.in_use)
+ val = TRUE;
+ else
+#endif
+ val = mch_can_restore_icon();
+ options[idx1].def_val[VI_DEFAULT] = (char_u *)(long_i)val;
+ p_icon = val;
+ }
+}
+#endif
+
+#if defined(FEAT_EVAL)
+ static void
+trigger_optionsset_string(
+ int opt_idx,
+ int opt_flags,
+ char_u *oldval,
+ char_u *newval)
+{
+ // Don't do this recursively.
+ if (oldval != NULL && newval != NULL
+ && *get_vim_var_str(VV_OPTION_TYPE) == NUL)
+ {
+ char_u buf_type[7];
+
+ sprintf((char *)buf_type, "%s",
+ (opt_flags & OPT_LOCAL) ? "local" : "global");
+ set_vim_var_string(VV_OPTION_OLD, oldval, -1);
+ set_vim_var_string(VV_OPTION_NEW, newval, -1);
+ set_vim_var_string(VV_OPTION_TYPE, buf_type, -1);
+ apply_autocmds(EVENT_OPTIONSET,
+ (char_u *)options[opt_idx].fullname, NULL, FALSE, NULL);
+ reset_v_option_vars();
+ }
+}
+#endif
+
+/*
+ * Parse 'arg' for option settings.
+ *
+ * 'arg' may be IObuff, but only when no errors can be present and option
+ * does not need to be expanded with option_expand().
+ * "opt_flags":
+ * 0 for ":set"
+ * OPT_GLOBAL for ":setglobal"
+ * OPT_LOCAL for ":setlocal" and a modeline
+ * OPT_MODELINE for a modeline
+ * OPT_WINONLY to only set window-local options
+ * OPT_NOWIN to skip setting window-local options
+ *
+ * returns FAIL if an error is detected, OK otherwise
+ */
+ int
+do_set(
+ char_u *arg, /* option string (may be written to!) */
+ int opt_flags)
+{
+ int opt_idx;
+ char *errmsg;
+ char errbuf[80];
+ char_u *startarg;
+ int prefix; /* 1: nothing, 0: "no", 2: "inv" in front of name */
+ int nextchar; /* next non-white char after option name */
+ int afterchar; /* character just after option name */
+ int len;
+ int i;
+ varnumber_T value;
+ int key;
+ long_u flags; /* flags for current option */
+ char_u *varp = NULL; /* pointer to variable for current option */
+ int did_show = FALSE; /* already showed one value */
+ int adding; /* "opt+=arg" */
+ int prepending; /* "opt^=arg" */
+ int removing; /* "opt-=arg" */
+ int cp_val = 0;
+ char_u key_name[2];
+
+ if (*arg == NUL)
+ {
+ showoptions(0, opt_flags);
+ did_show = TRUE;
+ goto theend;
+ }
+
+ while (*arg != NUL) /* loop to process all options */
+ {
+ errmsg = NULL;
+ startarg = arg; /* remember for error message */
+
+ if (STRNCMP(arg, "all", 3) == 0 && !isalpha(arg[3])
+ && !(opt_flags & OPT_MODELINE))
+ {
+ /*
+ * ":set all" show all options.
+ * ":set all&" set all options to their default value.
+ */
+ arg += 3;
+ if (*arg == '&')
+ {
+ ++arg;
+ /* Only for :set command set global value of local options. */
+ set_options_default(OPT_FREE | opt_flags);
+ didset_options();
+ didset_options2();
+ redraw_all_later(CLEAR);
+ }
+ else
+ {
+ showoptions(1, opt_flags);
+ did_show = TRUE;
+ }
+ }
+ else if (STRNCMP(arg, "termcap", 7) == 0 && !(opt_flags & OPT_MODELINE))
+ {
+ showoptions(2, opt_flags);
+ show_termcodes();
+ did_show = TRUE;
+ arg += 7;
+ }
+ else
+ {
+ prefix = 1;
+ if (STRNCMP(arg, "no", 2) == 0 && STRNCMP(arg, "novice", 6) != 0)
+ {
+ prefix = 0;
+ arg += 2;
+ }
+ else if (STRNCMP(arg, "inv", 3) == 0)
+ {
+ prefix = 2;
+ arg += 3;
+ }
+
+ /* find end of name */
+ key = 0;
+ if (*arg == '<')
+ {
+ nextchar = 0;
+ opt_idx = -1;
+ /* look out for <t_>;> */
+ if (arg[1] == 't' && arg[2] == '_' && arg[3] && arg[4])
+ len = 5;
+ else
+ {
+ len = 1;
+ while (arg[len] != NUL && arg[len] != '>')
+ ++len;
+ }
+ if (arg[len] != '>')
+ {
+ errmsg = e_invarg;
+ goto skip;
+ }
+ arg[len] = NUL; /* put NUL after name */
+ if (arg[1] == 't' && arg[2] == '_') /* could be term code */
+ opt_idx = findoption(arg + 1);
+ arg[len++] = '>'; /* restore '>' */
+ if (opt_idx == -1)
+ key = find_key_option(arg + 1, TRUE);
+ }
+ else
+ {
+ len = 0;
+ /*
+ * The two characters after "t_" may not be alphanumeric.
+ */
+ if (arg[0] == 't' && arg[1] == '_' && arg[2] && arg[3])
+ len = 4;
+ else
+ while (ASCII_ISALNUM(arg[len]) || arg[len] == '_')
+ ++len;
+ nextchar = arg[len];
+ arg[len] = NUL; /* put NUL after name */
+ opt_idx = findoption(arg);
+ arg[len] = nextchar; /* restore nextchar */
+ if (opt_idx == -1)
+ key = find_key_option(arg, FALSE);
+ }
+
+ /* remember character after option name */
+ afterchar = arg[len];
+
+ /* skip white space, allow ":set ai ?" */
+ while (VIM_ISWHITE(arg[len]))
+ ++len;
+
+ adding = FALSE;
+ prepending = FALSE;
+ removing = FALSE;
+ if (arg[len] != NUL && arg[len + 1] == '=')
+ {
+ if (arg[len] == '+')
+ {
+ adding = TRUE; /* "+=" */
+ ++len;
+ }
+ else if (arg[len] == '^')
+ {
+ prepending = TRUE; /* "^=" */
+ ++len;
+ }
+ else if (arg[len] == '-')
+ {
+ removing = TRUE; /* "-=" */
+ ++len;
+ }
+ }
+ nextchar = arg[len];
+
+ if (opt_idx == -1 && key == 0) /* found a mismatch: skip */
+ {
+ errmsg = N_("E518: Unknown option");
+ goto skip;
+ }
+
+ if (opt_idx >= 0)
+ {
+ if (options[opt_idx].var == NULL) /* hidden option: skip */
+ {
+ /* Only give an error message when requesting the value of
+ * a hidden option, ignore setting it. */
+ if (vim_strchr((char_u *)"=:!&<", nextchar) == NULL
+ && (!(options[opt_idx].flags & P_BOOL)
+ || nextchar == '?'))
+ errmsg = N_("E519: Option not supported");
+ goto skip;
+ }
+
+ flags = options[opt_idx].flags;
+ varp = get_varp_scope(&(options[opt_idx]), opt_flags);
+ }
+ else
+ {
+ flags = P_STRING;
+ if (key < 0)
+ {
+ key_name[0] = KEY2TERMCAP0(key);
+ key_name[1] = KEY2TERMCAP1(key);
+ }
+ else
+ {
+ key_name[0] = KS_KEY;
+ key_name[1] = (key & 0xff);
+ }
+ }
+
+ /* Skip all options that are not window-local (used when showing
+ * an already loaded buffer in a window). */
+ if ((opt_flags & OPT_WINONLY)
+ && (opt_idx < 0 || options[opt_idx].var != VAR_WIN))
+ goto skip;
+
+ /* Skip all options that are window-local (used for :vimgrep). */
+ if ((opt_flags & OPT_NOWIN) && opt_idx >= 0
+ && options[opt_idx].var == VAR_WIN)
+ goto skip;
+
+ /* Disallow changing some options from modelines. */
+ if (opt_flags & OPT_MODELINE)
+ {
+ if (flags & (P_SECURE | P_NO_ML))
+ {
+ errmsg = _("E520: Not allowed in a modeline");
+ goto skip;
+ }
+#ifdef FEAT_DIFF
+ /* In diff mode some options are overruled. This avoids that
+ * 'foldmethod' becomes "marker" instead of "diff" and that
+ * "wrap" gets set. */
+ if (curwin->w_p_diff
+ && opt_idx >= 0 /* shut up coverity warning */
+ && (
+#ifdef FEAT_FOLDING
+ options[opt_idx].indir == PV_FDM ||
+#endif
+ options[opt_idx].indir == PV_WRAP))
+ goto skip;
+#endif
+ }
+
+#ifdef HAVE_SANDBOX
+ /* Disallow changing some options in the sandbox */
+ if (sandbox != 0 && (flags & P_SECURE))
+ {
+ errmsg = _(e_sandbox);
+ goto skip;
+ }
+#endif
+
+ if (vim_strchr((char_u *)"?=:!&<", nextchar) != NULL)
+ {
+ arg += len;
+ cp_val = p_cp;
+ if (nextchar == '&' && arg[1] == 'v' && arg[2] == 'i')
+ {
+ if (arg[3] == 'm') /* "opt&vim": set to Vim default */
+ {
+ cp_val = FALSE;
+ arg += 3;
+ }
+ else /* "opt&vi": set to Vi default */
+ {
+ cp_val = TRUE;
+ arg += 2;
+ }
+ }
+ if (vim_strchr((char_u *)"?!&<", nextchar) != NULL
+ && arg[1] != NUL && !VIM_ISWHITE(arg[1]))
+ {
+ errmsg = e_trailing;
+ goto skip;
+ }
+ }
+
+ /*
+ * allow '=' and ':' for hystorical reasons (MSDOS command.com
+ * allows only one '=' character per "set" command line. grrr. (jw)
+ */
+ if (nextchar == '?'
+ || (prefix == 1
+ && vim_strchr((char_u *)"=:&<", nextchar) == NULL
+ && !(flags & P_BOOL)))
+ {
+ /*
+ * print value
+ */
+ if (did_show)
+ msg_putchar('\n'); /* cursor below last one */
+ else
+ {
+ gotocmdline(TRUE); /* cursor at status line */
+ did_show = TRUE; /* remember that we did a line */
+ }
+ if (opt_idx >= 0)
+ {
+ showoneopt(&options[opt_idx], opt_flags);
+#ifdef FEAT_EVAL
+ if (p_verbose > 0)
+ {
+ /* Mention where the option was last set. */
+ if (varp == options[opt_idx].var)
+ last_set_msg(options[opt_idx].script_ctx);
+ else if ((int)options[opt_idx].indir & PV_WIN)
+ last_set_msg(curwin->w_p_script_ctx[
+ (int)options[opt_idx].indir & PV_MASK]);
+ else if ((int)options[opt_idx].indir & PV_BUF)
+ last_set_msg(curbuf->b_p_script_ctx[
+ (int)options[opt_idx].indir & PV_MASK]);
+ }
+#endif
+ }
+ else
+ {
+ char_u *p;
+
+ p = find_termcode(key_name);
+ if (p == NULL)
+ {
+ errmsg = N_("E846: Key code not set");
+ goto skip;
+ }
+ else
+ (void)show_one_termcode(key_name, p, TRUE);
+ }
+ if (nextchar != '?'
+ && nextchar != NUL && !VIM_ISWHITE(afterchar))
+ errmsg = e_trailing;
+ }
+ else
+ {
+ int value_is_replaced = !prepending && !adding && !removing;
+ int value_checked = FALSE;
+
+ if (flags & P_BOOL) /* boolean */
+ {
+ if (nextchar == '=' || nextchar == ':')
+ {
+ errmsg = e_invarg;
+ goto skip;
+ }
+
+ /*
+ * ":set opt!": invert
+ * ":set opt&": reset to default value
+ * ":set opt<": reset to global value
+ */
+ if (nextchar == '!')
+ value = *(int *)(varp) ^ 1;
+ else if (nextchar == '&')
+ value = (int)(long)(long_i)options[opt_idx].def_val[
+ ((flags & P_VI_DEF) || cp_val)
+ ? VI_DEFAULT : VIM_DEFAULT];
+ else if (nextchar == '<')
+ {
+ /* For 'autoread' -1 means to use global value. */
+ if ((int *)varp == &curbuf->b_p_ar
+ && opt_flags == OPT_LOCAL)
+ value = -1;
+ else
+ value = *(int *)get_varp_scope(&(options[opt_idx]),
+ OPT_GLOBAL);
+ }
+ else
+ {
+ /*
+ * ":set invopt": invert
+ * ":set opt" or ":set noopt": set or reset
+ */
+ if (nextchar != NUL && !VIM_ISWHITE(afterchar))
+ {
+ errmsg = e_trailing;
+ goto skip;
+ }
+ if (prefix == 2) /* inv */
+ value = *(int *)(varp) ^ 1;
+ else
+ value = prefix;
+ }
+
+ errmsg = set_bool_option(opt_idx, varp, (int)value,
+ opt_flags);
+ }
+ else /* numeric or string */
+ {
+ if (vim_strchr((char_u *)"=:&<", nextchar) == NULL
+ || prefix != 1)
+ {
+ errmsg = e_invarg;
+ goto skip;
+ }
+
+ if (flags & P_NUM) /* numeric */
+ {
+ /*
+ * Different ways to set a number option:
+ * & set to default value
+ * < set to global value
+ * <xx> accept special key codes for 'wildchar'
+ * c accept any non-digit for 'wildchar'
+ * [-]0-9 set number
+ * other error
+ */
+ ++arg;
+ if (nextchar == '&')
+ value = (long)(long_i)options[opt_idx].def_val[
+ ((flags & P_VI_DEF) || cp_val)
+ ? VI_DEFAULT : VIM_DEFAULT];
+ else if (nextchar == '<')
+ {
+ /* For 'undolevels' NO_LOCAL_UNDOLEVEL means to
+ * use the global value. */
+ if ((long *)varp == &curbuf->b_p_ul
+ && opt_flags == OPT_LOCAL)
+ value = NO_LOCAL_UNDOLEVEL;
+ else
+ value = *(long *)get_varp_scope(
+ &(options[opt_idx]), OPT_GLOBAL);
+ }
+ else if (((long *)varp == &p_wc
+ || (long *)varp == &p_wcm)
+ && (*arg == '<'
+ || *arg == '^'
+ || (*arg != NUL
+ && (!arg[1] || VIM_ISWHITE(arg[1]))
+ && !VIM_ISDIGIT(*arg))))
+ {
+ value = string_to_key(arg, FALSE);
+ if (value == 0 && (long *)varp != &p_wcm)
+ {
+ errmsg = e_invarg;
+ goto skip;
+ }
+ }
+ else if (*arg == '-' || VIM_ISDIGIT(*arg))
+ {
+ /* Allow negative (for 'undolevels'), octal and
+ * hex numbers. */
+ vim_str2nr(arg, NULL, &i, STR2NR_ALL,
+ &value, NULL, 0);
+ if (arg[i] != NUL && !VIM_ISWHITE(arg[i]))
+ {
+ errmsg = e_invarg;
+ goto skip;
+ }
+ }
+ else
+ {
+ errmsg = N_("E521: Number required after =");
+ goto skip;
+ }
+
+ if (adding)
+ value = *(long *)varp + value;
+ if (prepending)
+ value = *(long *)varp * value;
+ if (removing)
+ value = *(long *)varp - value;
+ errmsg = set_num_option(opt_idx, varp, value,
+ errbuf, sizeof(errbuf), opt_flags);
+ }
+ else if (opt_idx >= 0) /* string */
+ {
+ char_u *save_arg = NULL;
+ char_u *s = NULL;
+ char_u *oldval = NULL; /* previous value if *varp */
+ char_u *newval;
+ char_u *origval = NULL;
+#if defined(FEAT_EVAL)
+ char_u *saved_origval = NULL;
+ char_u *saved_newval = NULL;
+#endif
+ unsigned newlen;
+ int comma;
+ int bs;
+ int new_value_alloced; /* new string option
+ was allocated */
+
+ /* When using ":set opt=val" for a global option
+ * with a local value the local value will be
+ * reset, use the global value here. */
+ if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0
+ && ((int)options[opt_idx].indir & PV_BOTH))
+ varp = options[opt_idx].var;
+
+ /* The old value is kept until we are sure that the
+ * new value is valid. */
+ oldval = *(char_u **)varp;
+
+ /* When setting the local value of a global
+ * option, the old value may be the global value. */
+ if (((int)options[opt_idx].indir & PV_BOTH)
+ && (opt_flags & OPT_LOCAL))
+ origval = *(char_u **)get_varp(
+ &options[opt_idx]);
+ else
+ origval = oldval;
+
+ if (nextchar == '&') /* set to default val */
+ {
+ newval = options[opt_idx].def_val[
+ ((flags & P_VI_DEF) || cp_val)
+ ? VI_DEFAULT : VIM_DEFAULT];
+ if ((char_u **)varp == &p_bg)
+ {
+ /* guess the value of 'background' */
+#ifdef FEAT_GUI
+ if (gui.in_use)
+ newval = gui_bg_default();
+ else
+#endif
+ newval = term_bg_default();
+ }
+
+ /* expand environment variables and ~ (since the
+ * default value was already expanded, only
+ * required when an environment variable was set
+ * later */
+ if (newval == NULL)
+ newval = empty_option;
+ else
+ {
+ s = option_expand(opt_idx, newval);
+ if (s == NULL)
+ s = newval;
+ newval = vim_strsave(s);
+ }
+ new_value_alloced = TRUE;
+ }
+ else if (nextchar == '<') /* set to global val */
+ {
+ newval = vim_strsave(*(char_u **)get_varp_scope(
+ &(options[opt_idx]), OPT_GLOBAL));
+ new_value_alloced = TRUE;
+ }
+ else
+ {
+ ++arg; /* jump to after the '=' or ':' */
+
+ /*
+ * Set 'keywordprg' to ":help" if an empty
+ * value was passed to :set by the user.
+ * Misuse errbuf[] for the resulting string.
+ */
+ if (varp == (char_u *)&p_kp
+ && (*arg == NUL || *arg == ' '))
+ {
+ STRCPY(errbuf, ":help");
+ save_arg = arg;
+ arg = (char_u *)errbuf;
+ }
+ /*
+ * Convert 'backspace' number to string, for
+ * adding, prepending and removing string.
+ */
+ else if (varp == (char_u *)&p_bs
+ && VIM_ISDIGIT(**(char_u **)varp))
+ {
+ i = getdigits((char_u **)varp);
+ switch (i)
+ {
+ case 0:
+ *(char_u **)varp = empty_option;
+ break;
+ case 1:
+ *(char_u **)varp = vim_strsave(
+ (char_u *)"indent,eol");
+ break;
+ case 2:
+ *(char_u **)varp = vim_strsave(
+ (char_u *)"indent,eol,start");
+ break;
+ }
+ vim_free(oldval);
+ if (origval == oldval)
+ origval = *(char_u **)varp;
+ oldval = *(char_u **)varp;
+ }
+ /*
+ * Convert 'whichwrap' number to string, for
+ * backwards compatibility with Vim 3.0.
+ * Misuse errbuf[] for the resulting string.
+ */
+ else if (varp == (char_u *)&p_ww
+ && VIM_ISDIGIT(*arg))
+ {
+ *errbuf = NUL;
+ i = getdigits(&arg);
+ if (i & 1)
+ STRCAT(errbuf, "b,");
+ if (i & 2)
+ STRCAT(errbuf, "s,");
+ if (i & 4)
+ STRCAT(errbuf, "h,l,");
+ if (i & 8)
+ STRCAT(errbuf, "<,>,");
+ if (i & 16)
+ STRCAT(errbuf, "[,],");
+ if (*errbuf != NUL) /* remove trailing , */
+ errbuf[STRLEN(errbuf) - 1] = NUL;
+ save_arg = arg;
+ arg = (char_u *)errbuf;
+ }
+ /*
+ * Remove '>' before 'dir' and 'bdir', for
+ * backwards compatibility with version 3.0
+ */
+ else if ( *arg == '>'
+ && (varp == (char_u *)&p_dir
+ || varp == (char_u *)&p_bdir))
+ {
+ ++arg;
+ }
+
+ /*
+ * Copy the new string into allocated memory.
+ * Can't use set_string_option_direct(), because
+ * we need to remove the backslashes.
+ */
+ /* get a bit too much */
+ newlen = (unsigned)STRLEN(arg) + 1;
+ if (adding || prepending || removing)
+ newlen += (unsigned)STRLEN(origval) + 1;
+ newval = alloc(newlen);
+ if (newval == NULL) /* out of mem, don't change */
+ break;
+ s = newval;
+
+ /*
+ * Copy the string, skip over escaped chars.
+ * For MS-DOS and WIN32 backslashes before normal
+ * file name characters are not removed, and keep
+ * backslash at start, for "\\machine\path", but
+ * do remove it for "\\\\machine\\path".
+ * The reverse is found in ExpandOldSetting().
+ */
+ while (*arg && !VIM_ISWHITE(*arg))
+ {
+ if (*arg == '\\' && arg[1] != NUL
+#ifdef BACKSLASH_IN_FILENAME
+ && !((flags & P_EXPAND)
+ && vim_isfilec(arg[1])
+ && (arg[1] != '\\'
+ || (s == newval
+ && arg[2] != '\\')))
+#endif
+ )
+ ++arg; /* remove backslash */
+ if (has_mbyte
+ && (i = (*mb_ptr2len)(arg)) > 1)
+ {
+ /* copy multibyte char */
+ mch_memmove(s, arg, (size_t)i);
+ arg += i;
+ s += i;
+ }
+ else
+ *s++ = *arg++;
+ }
+ *s = NUL;
+
+ /*
+ * Expand environment variables and ~.
+ * Don't do it when adding without inserting a
+ * comma.
+ */
+ if (!(adding || prepending || removing)
+ || (flags & P_COMMA))
+ {
+ s = option_expand(opt_idx, newval);
+ if (s != NULL)
+ {
+ vim_free(newval);
+ newlen = (unsigned)STRLEN(s) + 1;
+ if (adding || prepending || removing)
+ newlen += (unsigned)STRLEN(origval) + 1;
+ newval = alloc(newlen);
+ if (newval == NULL)
+ break;
+ STRCPY(newval, s);
+ }
+ }
+
+ /* locate newval[] in origval[] when removing it
+ * and when adding to avoid duplicates */
+ i = 0; /* init for GCC */
+ if (removing || (flags & P_NODUP))
+ {
+ i = (int)STRLEN(newval);
+ bs = 0;
+ for (s = origval; *s; ++s)
+ {
+ if ((!(flags & P_COMMA)
+ || s == origval
+ || (s[-1] == ',' && !(bs & 1)))
+ && STRNCMP(s, newval, i) == 0
+ && (!(flags & P_COMMA)
+ || s[i] == ','
+ || s[i] == NUL))
+ break;
+ /* Count backslashes. Only a comma with an
+ * even number of backslashes or a single
+ * backslash preceded by a comma before it
+ * is recognized as a separator */
+ if ((s > origval + 1
+ && s[-1] == '\\'
+ && s[-2] != ',')
+ || (s == origval + 1
+ && s[-1] == '\\'))
+
+ ++bs;
+ else
+ bs = 0;
+ }
+
+ /* do not add if already there */
+ if ((adding || prepending) && *s)
+ {
+ prepending = FALSE;
+ adding = FALSE;
+ STRCPY(newval, origval);
+ }
+ }
+
+ /* concatenate the two strings; add a ',' if
+ * needed */
+ if (adding || prepending)
+ {
+ comma = ((flags & P_COMMA) && *origval != NUL
+ && *newval != NUL);
+ if (adding)
+ {
+ i = (int)STRLEN(origval);
+ /* strip a trailing comma, would get 2 */
+ if (comma && i > 1
+ && (flags & P_ONECOMMA) == P_ONECOMMA
+ && origval[i - 1] == ','
+ && origval[i - 2] != '\\')
+ i--;
+ mch_memmove(newval + i + comma, newval,
+ STRLEN(newval) + 1);
+ mch_memmove(newval, origval, (size_t)i);
+ }
+ else
+ {
+ i = (int)STRLEN(newval);
+ STRMOVE(newval + i + comma, origval);
+ }
+ if (comma)
+ newval[i] = ',';
+ }
+
+ /* Remove newval[] from origval[]. (Note: "i" has
+ * been set above and is used here). */
+ if (removing)
+ {
+ STRCPY(newval, origval);
+ if (*s)
+ {
+ /* may need to remove a comma */
+ if (flags & P_COMMA)
+ {
+ if (s == origval)
+ {
+ /* include comma after string */
+ if (s[i] == ',')
+ ++i;
+ }
+ else
+ {
+ /* include comma before string */
+ --s;
+ ++i;
+ }
+ }
+ STRMOVE(newval + (s - origval), s + i);
+ }
+ }
+
+ if (flags & P_FLAGLIST)
+ {
+ /* Remove flags that appear twice. */
+ for (s = newval; *s;)
+ {
+ /* if options have P_FLAGLIST and
+ * P_ONECOMMA such as 'whichwrap' */
+ if (flags & P_ONECOMMA)
+ {
+ if (*s != ',' && *(s + 1) == ','
+ && vim_strchr(s + 2, *s) != NULL)
+ {
+ /* Remove the duplicated value and
+ * the next comma. */
+ STRMOVE(s, s + 2);
+ continue;
+ }
+ }
+ else
+ {
+ if ((!(flags & P_COMMA) || *s != ',')
+ && vim_strchr(s + 1, *s) != NULL)
+ {
+ STRMOVE(s, s + 1);
+ continue;
+ }
+ }
+ ++s;
+ }
+ }
+
+ if (save_arg != NULL) /* number for 'whichwrap' */
+ arg = save_arg;
+ new_value_alloced = TRUE;
+ }
+
+ /*
+ * Set the new value.
+ */
+ *(char_u **)(varp) = newval;
+
+#if defined(FEAT_EVAL)
+ if (!starting
+# ifdef FEAT_CRYPT
+ && options[opt_idx].indir != PV_KEY
+# endif
+ && origval != NULL && newval != NULL)
+ {
+ /* origval may be freed by
+ * did_set_string_option(), make a copy. */
+ saved_origval = vim_strsave(origval);
+ /* newval (and varp) may become invalid if the
+ * buffer is closed by autocommands. */
+ saved_newval = vim_strsave(newval);
+ }
+#endif
+
+ {
+ long_u *p = insecure_flag(opt_idx, opt_flags);
+ int secure_saved = secure;
+
+ // When an option is set in the sandbox, from a
+ // modeline or in secure mode, then deal with side
+ // effects in secure mode. Also when the value was
+ // set with the P_INSECURE flag and is not
+ // completely replaced.
+ if (secure
+#ifdef HAVE_SANDBOX
+ || sandbox != 0
+#endif
+ || (opt_flags & OPT_MODELINE)
+ || (!value_is_replaced && (*p & P_INSECURE)))
+ ++secure;
+
+ // Handle side effects, and set the global value
+ // for ":set" on local options. Note: when setting
+ // 'syntax' or 'filetype' autocommands may be
+ // triggered that can cause havoc.
+ errmsg = did_set_string_option(
+ opt_idx, (char_u **)varp,
+ new_value_alloced, oldval, errbuf,
+ opt_flags, &value_checked);
+
+ secure = secure_saved;
+ }
+
+#if defined(FEAT_EVAL)
+ if (errmsg == NULL)
+ trigger_optionsset_string(opt_idx, opt_flags,
+ saved_origval, saved_newval);
+ vim_free(saved_origval);
+ vim_free(saved_newval);
+#endif
+ /* If error detected, print the error message. */
+ if (errmsg != NULL)
+ goto skip;
+ }
+ else /* key code option */
+ {
+ char_u *p;
+
+ if (nextchar == '&')
+ {
+ if (add_termcap_entry(key_name, TRUE) == FAIL)
+ errmsg = N_("E522: Not found in termcap");
+ }
+ else
+ {
+ ++arg; /* jump to after the '=' or ':' */
+ for (p = arg; *p && !VIM_ISWHITE(*p); ++p)
+ if (*p == '\\' && p[1] != NUL)
+ ++p;
+ nextchar = *p;
+ *p = NUL;
+ add_termcode(key_name, arg, FALSE);
+ *p = nextchar;
+ }
+ if (full_screen)
+ ttest(FALSE);
+ redraw_all_later(CLEAR);
+ }
+ }
+
+ if (opt_idx >= 0)
+ did_set_option(
+ opt_idx, opt_flags, value_is_replaced, value_checked);
+ }
+
+skip:
+ /*
+ * Advance to next argument.
+ * - skip until a blank found, taking care of backslashes
+ * - skip blanks
+ * - skip one "=val" argument (for hidden options ":set gfn =xx")
+ */
+ for (i = 0; i < 2 ; ++i)
+ {
+ while (*arg != NUL && !VIM_ISWHITE(*arg))
+ if (*arg++ == '\\' && *arg != NUL)
+ ++arg;
+ arg = skipwhite(arg);
+ if (*arg != '=')
+ break;
+ }
+ }
+
+ if (errmsg != NULL)
+ {
+ vim_strncpy(IObuff, (char_u *)_(errmsg), IOSIZE - 1);
+ i = (int)STRLEN(IObuff) + 2;
+ if (i + (arg - startarg) < IOSIZE)
+ {
+ /* append the argument with the error */
+ STRCAT(IObuff, ": ");
+ mch_memmove(IObuff + i, startarg, (arg - startarg));
+ IObuff[i + (arg - startarg)] = NUL;
+ }
+ /* make sure all characters are printable */
+ trans_characters(IObuff, IOSIZE);
+
+ ++no_wait_return; // wait_return done later
+ emsg((char *)IObuff); // show error highlighted
+ --no_wait_return;
+
+ return FAIL;
+ }
+
+ arg = skipwhite(arg);
+ }
+
+theend:
+ if (silent_mode && did_show)
+ {
+ /* After displaying option values in silent mode. */
+ silent_mode = FALSE;
+ info_message = TRUE; /* use mch_msg(), not mch_errmsg() */
+ msg_putchar('\n');
+ cursor_on(); /* msg_start() switches it off */
+ out_flush();
+ silent_mode = TRUE;
+ info_message = FALSE; /* use mch_msg(), not mch_errmsg() */
+ }
+
+ return OK;
+}
+
+/*
+ * Call this when an option has been given a new value through a user command.
+ * Sets the P_WAS_SET flag and takes care of the P_INSECURE flag.
+ */
+ static void
+did_set_option(
+ int opt_idx,
+ int opt_flags, // possibly with OPT_MODELINE
+ int new_value, // value was replaced completely
+ int value_checked) // value was checked to be safe, no need to set the
+ // P_INSECURE flag.
+{
+ long_u *p;
+
+ options[opt_idx].flags |= P_WAS_SET;
+
+ /* When an option is set in the sandbox, from a modeline or in secure mode
+ * set the P_INSECURE flag. Otherwise, if a new value is stored reset the
+ * flag. */
+ p = insecure_flag(opt_idx, opt_flags);
+ if (!value_checked && (secure
+#ifdef HAVE_SANDBOX
+ || sandbox != 0
+#endif
+ || (opt_flags & OPT_MODELINE)))
+ *p = *p | P_INSECURE;
+ else if (new_value)
+ *p = *p & ~P_INSECURE;
+}
+
+ static char *
+illegal_char(char *errbuf, int c)
+{
+ if (errbuf == NULL)
+ return "";
+ sprintf((char *)errbuf, _("E539: Illegal character <%s>"),
+ (char *)transchar(c));
+ return errbuf;
+}
+
+/*
+ * Convert a key name or string into a key value.
+ * Used for 'wildchar' and 'cedit' options.
+ * When "multi_byte" is TRUE allow for multi-byte characters.
+ */
+ int
+string_to_key(char_u *arg, int multi_byte)
+{
+ if (*arg == '<')
+ return find_key_option(arg + 1, TRUE);
+ if (*arg == '^')
+ return Ctrl_chr(arg[1]);
+ if (multi_byte)
+ return PTR2CHAR(arg);
+ return *arg;
+}
+
+#ifdef FEAT_CMDWIN
+/*
+ * Check value of 'cedit' and set cedit_key.
+ * Returns NULL if value is OK, error message otherwise.
+ */
+ static char *
+check_cedit(void)
+{
+ int n;
+
+ if (*p_cedit == NUL)
+ cedit_key = -1;
+ else
+ {
+ n = string_to_key(p_cedit, FALSE);
+ if (vim_isprintc(n))
+ return e_invarg;
+ cedit_key = n;
+ }
+ return NULL;
+}
+#endif
+
+#ifdef FEAT_TITLE
+/*
+ * When changing 'title', 'titlestring', 'icon' or 'iconstring', call
+ * maketitle() to create and display it.
+ * When switching the title or icon off, call mch_restore_title() to get
+ * the old value back.
+ */
+ static void
+did_set_title(void)
+{
+ if (starting != NO_SCREEN
+#ifdef FEAT_GUI
+ && !gui.starting
+#endif
+ )
+ maketitle();
+}
+#endif
+
+/*
+ * set_options_bin - called when 'bin' changes value.
+ */
+ void
+set_options_bin(
+ int oldval,
+ int newval,
+ int opt_flags) /* OPT_LOCAL and/or OPT_GLOBAL */
+{
+ /*
+ * The option values that are changed when 'bin' changes are
+ * copied when 'bin is set and restored when 'bin' is reset.
+ */
+ if (newval)
+ {
+ if (!oldval) /* switched on */
+ {
+ if (!(opt_flags & OPT_GLOBAL))
+ {
+ curbuf->b_p_tw_nobin = curbuf->b_p_tw;
+ curbuf->b_p_wm_nobin = curbuf->b_p_wm;
+ curbuf->b_p_ml_nobin = curbuf->b_p_ml;
+ curbuf->b_p_et_nobin = curbuf->b_p_et;
+ }
+ if (!(opt_flags & OPT_LOCAL))
+ {
+ p_tw_nobin = p_tw;
+ p_wm_nobin = p_wm;
+ p_ml_nobin = p_ml;
+ p_et_nobin = p_et;
+ }
+ }
+
+ if (!(opt_flags & OPT_GLOBAL))
+ {
+ curbuf->b_p_tw = 0; /* no automatic line wrap */
+ curbuf->b_p_wm = 0; /* no automatic line wrap */
+ curbuf->b_p_ml = 0; /* no modelines */
+ curbuf->b_p_et = 0; /* no expandtab */
+ }
+ if (!(opt_flags & OPT_LOCAL))
+ {
+ p_tw = 0;
+ p_wm = 0;
+ p_ml = FALSE;
+ p_et = FALSE;
+ p_bin = TRUE; /* needed when called for the "-b" argument */
+ }
+ }
+ else if (oldval) /* switched off */
+ {
+ if (!(opt_flags & OPT_GLOBAL))
+ {
+ curbuf->b_p_tw = curbuf->b_p_tw_nobin;
+ curbuf->b_p_wm = curbuf->b_p_wm_nobin;
+ curbuf->b_p_ml = curbuf->b_p_ml_nobin;
+ curbuf->b_p_et = curbuf->b_p_et_nobin;
+ }
+ if (!(opt_flags & OPT_LOCAL))
+ {
+ p_tw = p_tw_nobin;
+ p_wm = p_wm_nobin;
+ p_ml = p_ml_nobin;
+ p_et = p_et_nobin;
+ }
+ }
+}
+
+#ifdef FEAT_VIMINFO
+/*
+ * Find the parameter represented by the given character (eg ', :, ", or /),
+ * and return its associated value in the 'viminfo' string.
+ * Only works for number parameters, not for 'r' or 'n'.
+ * If the parameter is not specified in the string or there is no following
+ * number, return -1.
+ */
+ int
+get_viminfo_parameter(int type)
+{
+ char_u *p;
+
+ p = find_viminfo_parameter(type);
+ if (p != NULL && VIM_ISDIGIT(*p))
+ return atoi((char *)p);
+ return -1;
+}
+
+/*
+ * Find the parameter represented by the given character (eg ''', ':', '"', or
+ * '/') in the 'viminfo' option and return a pointer to the string after it.
+ * Return NULL if the parameter is not specified in the string.
+ */
+ char_u *
+find_viminfo_parameter(int type)
+{
+ char_u *p;
+
+ for (p = p_viminfo; *p; ++p)
+ {
+ if (*p == type)
+ return p + 1;
+ if (*p == 'n') /* 'n' is always the last one */
+ break;
+ p = vim_strchr(p, ','); /* skip until next ',' */
+ if (p == NULL) /* hit the end without finding parameter */
+ break;
+ }
+ return NULL;
+}
+#endif
+
+/*
+ * Expand environment variables for some string options.
+ * These string options cannot be indirect!
+ * If "val" is NULL expand the current value of the option.
+ * Return pointer to NameBuff, or NULL when not expanded.
+ */
+ static char_u *
+option_expand(int opt_idx, char_u *val)
+{
+ /* if option doesn't need expansion nothing to do */
+ if (!(options[opt_idx].flags & P_EXPAND) || options[opt_idx].var == NULL)
+ return NULL;
+
+ /* If val is longer than MAXPATHL no meaningful expansion can be done,
+ * expand_env() would truncate the string. */
+ if (val != NULL && STRLEN(val) > MAXPATHL)
+ return NULL;
+
+ if (val == NULL)
+ val = *(char_u **)options[opt_idx].var;
+
+ /*
+ * Expanding this with NameBuff, expand_env() must not be passed IObuff.
+ * Escape spaces when expanding 'tags', they are used to separate file
+ * names.
+ * For 'spellsuggest' expand after "file:".
+ */
+ expand_env_esc(val, NameBuff, MAXPATHL,
+ (char_u **)options[opt_idx].var == &p_tags, FALSE,
+#ifdef FEAT_SPELL
+ (char_u **)options[opt_idx].var == &p_sps ? (char_u *)"file:" :
+#endif
+ NULL);
+ if (STRCMP(NameBuff, val) == 0) /* they are the same */
+ return NULL;
+
+ return NameBuff;
+}
+
+/*
+ * After setting various option values: recompute variables that depend on
+ * option values.
+ */
+ static void
+didset_options(void)
+{
+ /* initialize the table for 'iskeyword' et.al. */
+ (void)init_chartab();
+
+ (void)opt_strings_flags(p_cmp, p_cmp_values, &cmp_flags, TRUE);
+ (void)opt_strings_flags(p_bkc, p_bkc_values, &bkc_flags, TRUE);
+ (void)opt_strings_flags(p_bo, p_bo_values, &bo_flags, TRUE);
+#ifdef FEAT_SESSION
+ (void)opt_strings_flags(p_ssop, p_ssop_values, &ssop_flags, TRUE);
+ (void)opt_strings_flags(p_vop, p_ssop_values, &vop_flags, TRUE);
+#endif
+#ifdef FEAT_FOLDING
+ (void)opt_strings_flags(p_fdo, p_fdo_values, &fdo_flags, TRUE);
+#endif
+ (void)opt_strings_flags(p_dy, p_dy_values, &dy_flags, TRUE);
+ (void)opt_strings_flags(p_tc, p_tc_values, &tc_flags, FALSE);
+ (void)opt_strings_flags(p_ve, p_ve_values, &ve_flags, TRUE);
+#if defined(FEAT_MOUSE) && (defined(UNIX) || defined(VMS))
+ (void)opt_strings_flags(p_ttym, p_ttym_values, &ttym_flags, FALSE);
+#endif
+#ifdef FEAT_SPELL
+ (void)spell_check_msm();
+ (void)spell_check_sps();
+ (void)compile_cap_prog(curwin->w_s);
+ (void)did_set_spell_option(TRUE);
+#endif
+#if defined(FEAT_TOOLBAR) && !defined(FEAT_GUI_W32)
+ (void)opt_strings_flags(p_toolbar, p_toolbar_values, &toolbar_flags, TRUE);
+#endif
+#if defined(FEAT_TOOLBAR) && defined(FEAT_GUI_GTK)
+ (void)opt_strings_flags(p_tbis, p_tbis_values, &tbis_flags, FALSE);
+#endif
+#ifdef FEAT_CMDWIN
+ /* set cedit_key */
+ (void)check_cedit();
+#endif
+#ifdef FEAT_LINEBREAK
+ briopt_check(curwin);
+#endif
+#ifdef FEAT_LINEBREAK
+ /* initialize the table for 'breakat'. */
+ fill_breakat_flags();
+#endif
+
+}
+
+/*
+ * More side effects of setting options.
+ */
+ static void
+didset_options2(void)
+{
+ /* Initialize the highlight_attr[] table. */
+ (void)highlight_changed();
+
+ /* Parse default for 'wildmode' */
+ check_opt_wim();
+
+ (void)set_chars_option(&p_lcs);
+ /* Parse default for 'fillchars'. */
+ (void)set_chars_option(&p_fcs);
+
+#ifdef FEAT_CLIPBOARD
+ /* Parse default for 'clipboard' */
+ (void)check_clipboard_option();
+#endif
+#ifdef FEAT_VARTABS
+ tabstop_set(curbuf->b_p_vsts, &curbuf->b_p_vsts_array);
+ tabstop_set(curbuf->b_p_vts, &curbuf->b_p_vts_array);
+#endif
+}
+
+/*
+ * Check for string options that are NULL (normally only termcap options).
+ */
+ void
+check_options(void)
+{
+ int opt_idx;
+
+ for (opt_idx = 0; options[opt_idx].fullname != NULL; opt_idx++)
+ if ((options[opt_idx].flags & P_STRING) && options[opt_idx].var != NULL)
+ check_string_option((char_u **)get_varp(&(options[opt_idx])));
+}
+
+/*
+ * Check string options in a buffer for NULL value.
+ */
+ void
+check_buf_options(buf_T *buf)
+{
+ check_string_option(&buf->b_p_bh);
+ check_string_option(&buf->b_p_bt);
+ check_string_option(&buf->b_p_fenc);
+ check_string_option(&buf->b_p_ff);
+#ifdef FEAT_FIND_ID
+ check_string_option(&buf->b_p_def);
+ check_string_option(&buf->b_p_inc);
+# ifdef FEAT_EVAL
+ check_string_option(&buf->b_p_inex);
+# endif
+#endif
+#if defined(FEAT_CINDENT) && defined(FEAT_EVAL)
+ check_string_option(&buf->b_p_inde);
+ check_string_option(&buf->b_p_indk);
+#endif
+#if defined(FEAT_BEVAL) && defined(FEAT_EVAL)
+ check_string_option(&buf->b_p_bexpr);
+#endif
+#if defined(FEAT_CRYPT)
+ check_string_option(&buf->b_p_cm);
+#endif
+ check_string_option(&buf->b_p_fp);
+#if defined(FEAT_EVAL)
+ check_string_option(&buf->b_p_fex);
+#endif
+#ifdef FEAT_CRYPT
+ check_string_option(&buf->b_p_key);
+#endif
+ check_string_option(&buf->b_p_kp);
+ check_string_option(&buf->b_p_mps);
+ check_string_option(&buf->b_p_fo);
+ check_string_option(&buf->b_p_flp);
+ check_string_option(&buf->b_p_isk);
+#ifdef FEAT_COMMENTS
+ check_string_option(&buf->b_p_com);
+#endif
+#ifdef FEAT_FOLDING
+ check_string_option(&buf->b_p_cms);
+#endif
+ check_string_option(&buf->b_p_nf);
+#ifdef FEAT_TEXTOBJ
+ check_string_option(&buf->b_p_qe);
+#endif
+#ifdef FEAT_SYN_HL
+ check_string_option(&buf->b_p_syn);
+ check_string_option(&buf->b_s.b_syn_isk);
+#endif
+#ifdef FEAT_SPELL
+ check_string_option(&buf->b_s.b_p_spc);
+ check_string_option(&buf->b_s.b_p_spf);
+ check_string_option(&buf->b_s.b_p_spl);
+#endif
+#ifdef FEAT_SEARCHPATH
+ check_string_option(&buf->b_p_sua);
+#endif
+#ifdef FEAT_CINDENT
+ check_string_option(&buf->b_p_cink);
+ check_string_option(&buf->b_p_cino);
+ parse_cino(buf);
+#endif
+ check_string_option(&buf->b_p_ft);
+#if defined(FEAT_SMARTINDENT) || defined(FEAT_CINDENT)
+ check_string_option(&buf->b_p_cinw);
+#endif
+#ifdef FEAT_INS_EXPAND
+ check_string_option(&buf->b_p_cpt);
+#endif
+#ifdef FEAT_COMPL_FUNC
+ check_string_option(&buf->b_p_cfu);
+ check_string_option(&buf->b_p_ofu);
+#endif
+#ifdef FEAT_KEYMAP
+ check_string_option(&buf->b_p_keymap);
+#endif
+#ifdef FEAT_QUICKFIX
+ check_string_option(&buf->b_p_gp);
+ check_string_option(&buf->b_p_mp);
+ check_string_option(&buf->b_p_efm);
+#endif
+ check_string_option(&buf->b_p_ep);
+ check_string_option(&buf->b_p_path);
+ check_string_option(&buf->b_p_tags);
+ check_string_option(&buf->b_p_tc);
+#ifdef FEAT_INS_EXPAND
+ check_string_option(&buf->b_p_dict);
+ check_string_option(&buf->b_p_tsr);
+#endif
+#ifdef FEAT_LISP
+ check_string_option(&buf->b_p_lw);
+#endif
+ check_string_option(&buf->b_p_bkc);
+ check_string_option(&buf->b_p_menc);
+#ifdef FEAT_VARTABS
+ check_string_option(&buf->b_p_vsts);
+ check_string_option(&buf->b_p_vts);
+#endif
+}
+
+/*
+ * Free the string allocated for an option.
+ * Checks for the string being empty_option. This may happen if we're out of
+ * memory, vim_strsave() returned NULL, which was replaced by empty_option by
+ * check_options().
+ * Does NOT check for P_ALLOCED flag!
+ */
+ void
+free_string_option(char_u *p)
+{
+ if (p != empty_option)
+ vim_free(p);
+}
+
+ void
+clear_string_option(char_u **pp)
+{
+ if (*pp != empty_option)
+ vim_free(*pp);
+ *pp = empty_option;
+}
+
+ static void
+check_string_option(char_u **pp)
+{
+ if (*pp == NULL)
+ *pp = empty_option;
+}
+
+/*
+ * Return the option index found by a pointer into term_strings[].
+ * Return -1 if not found.
+ */
+ int
+get_term_opt_idx(char_u **p)
+{
+ int opt_idx;
+
+ for (opt_idx = 1; options[opt_idx].fullname != NULL; opt_idx++)
+ if (options[opt_idx].var == (char_u *)p)
+ return opt_idx;
+ return -1; // cannot happen: didn't find it!
+}
+
+/*
+ * Mark a terminal option as allocated, found by a pointer into term_strings[].
+ * Return the option index or -1 if not found.
+ */
+ int
+set_term_option_alloced(char_u **p)
+{
+ int opt_idx = get_term_opt_idx(p);
+
+ if (opt_idx >= 0)
+ options[opt_idx].flags |= P_ALLOCED;
+ return opt_idx;
+}
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * Return TRUE when option "opt" was set from a modeline or in secure mode.
+ * Return FALSE when it wasn't.
+ * Return -1 for an unknown option.
+ */
+ int
+was_set_insecurely(char_u *opt, int opt_flags)
+{
+ int idx = findoption(opt);
+ long_u *flagp;
+
+ if (idx >= 0)
+ {
+ flagp = insecure_flag(idx, opt_flags);
+ return (*flagp & P_INSECURE) != 0;
+ }
+ internal_error("was_set_insecurely()");
+ return -1;
+}
+
+/*
+ * Get a pointer to the flags used for the P_INSECURE flag of option
+ * "opt_idx". For some local options a local flags field is used.
+ */
+ static long_u *
+insecure_flag(int opt_idx, int opt_flags)
+{
+ if (opt_flags & OPT_LOCAL)
+ switch ((int)options[opt_idx].indir)
+ {
+#ifdef FEAT_STL_OPT
+ case PV_STL: return &curwin->w_p_stl_flags;
+#endif
+#ifdef FEAT_EVAL
+# ifdef FEAT_FOLDING
+ case PV_FDE: return &curwin->w_p_fde_flags;
+ case PV_FDT: return &curwin->w_p_fdt_flags;
+# endif
+# ifdef FEAT_BEVAL
+ case PV_BEXPR: return &curbuf->b_p_bexpr_flags;
+# endif
+# if defined(FEAT_CINDENT)
+ case PV_INDE: return &curbuf->b_p_inde_flags;
+# endif
+ case PV_FEX: return &curbuf->b_p_fex_flags;
+# ifdef FEAT_FIND_ID
+ case PV_INEX: return &curbuf->b_p_inex_flags;
+# endif
+#endif
+ }
+
+ /* Nothing special, return global flags field. */
+ return &options[opt_idx].flags;
+}
+#endif
+
+#ifdef FEAT_TITLE
+/*
+ * Redraw the window title and/or tab page text later.
+ */
+static void redraw_titles(void)
+{
+ need_maketitle = TRUE;
+ redraw_tabline = TRUE;
+}
+#endif
+
+/*
+ * Set a string option to a new value (without checking the effect).
+ * The string is copied into allocated memory.
+ * if ("opt_idx" == -1) "name" is used, otherwise "opt_idx" is used.
+ * When "set_sid" is zero set the scriptID to current_sctx.sc_sid. When
+ * "set_sid" is SID_NONE don't set the scriptID. Otherwise set the scriptID to
+ * "set_sid".
+ */
+ void
+set_string_option_direct(
+ char_u *name,
+ int opt_idx,
+ char_u *val,
+ int opt_flags, /* OPT_FREE, OPT_LOCAL and/or OPT_GLOBAL */
+ int set_sid UNUSED)
+{
+ char_u *s;
+ char_u **varp;
+ int both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0;
+ int idx = opt_idx;
+
+ if (idx == -1) /* use name */
+ {
+ idx = findoption(name);
+ if (idx < 0) /* not found (should not happen) */
+ {
+ semsg(_(e_intern2), "set_string_option_direct()");
+ siemsg(_("For option %s"), name);
+ return;
+ }
+ }
+
+ if (options[idx].var == NULL) /* can't set hidden option */
+ return;
+
+ s = vim_strsave(val);
+ if (s != NULL)
+ {
+ varp = (char_u **)get_varp_scope(&(options[idx]),
+ both ? OPT_LOCAL : opt_flags);
+ if ((opt_flags & OPT_FREE) && (options[idx].flags & P_ALLOCED))
+ free_string_option(*varp);
+ *varp = s;
+
+ /* For buffer/window local option may also set the global value. */
+ if (both)
+ set_string_option_global(idx, varp);
+
+ options[idx].flags |= P_ALLOCED;
+
+ /* When setting both values of a global option with a local value,
+ * make the local value empty, so that the global value is used. */
+ if (((int)options[idx].indir & PV_BOTH) && both)
+ {
+ free_string_option(*varp);
+ *varp = empty_option;
+ }
+# ifdef FEAT_EVAL
+ if (set_sid != SID_NONE)
+ {
+ sctx_T script_ctx;
+
+ if (set_sid == 0)
+ script_ctx = current_sctx;
+ else
+ {
+ script_ctx.sc_sid = set_sid;
+ script_ctx.sc_seq = 0;
+ script_ctx.sc_lnum = 0;
+ }
+ set_option_sctx_idx(idx, opt_flags, script_ctx);
+ }
+# endif
+ }
+}
+
+/*
+ * Set global value for string option when it's a local option.
+ */
+ static void
+set_string_option_global(
+ int opt_idx, /* option index */
+ char_u **varp) /* pointer to option variable */
+{
+ char_u **p, *s;
+
+ /* the global value is always allocated */
+ if (options[opt_idx].var == VAR_WIN)
+ p = (char_u **)GLOBAL_WO(varp);
+ else
+ p = (char_u **)options[opt_idx].var;
+ if (options[opt_idx].indir != PV_NONE
+ && p != varp
+ && (s = vim_strsave(*varp)) != NULL)
+ {
+ free_string_option(*p);
+ *p = s;
+ }
+}
+
+/*
+ * Set a string option to a new value, and handle the effects.
+ *
+ * Returns NULL on success or error message on error.
+ */
+ static char *
+set_string_option(
+ int opt_idx,
+ char_u *value,
+ int opt_flags) /* OPT_LOCAL and/or OPT_GLOBAL */
+{
+ char_u *s;
+ char_u **varp;
+ char_u *oldval;
+#if defined(FEAT_EVAL)
+ char_u *saved_oldval = NULL;
+ char_u *saved_newval = NULL;
+#endif
+ char *r = NULL;
+ int value_checked = FALSE;
+
+ if (options[opt_idx].var == NULL) /* don't set hidden option */
+ return NULL;
+
+ s = vim_strsave(value);
+ if (s != NULL)
+ {
+ varp = (char_u **)get_varp_scope(&(options[opt_idx]),
+ (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0
+ ? (((int)options[opt_idx].indir & PV_BOTH)
+ ? OPT_GLOBAL : OPT_LOCAL)
+ : opt_flags);
+ oldval = *varp;
+ *varp = s;
+
+#if defined(FEAT_EVAL)
+ if (!starting
+# ifdef FEAT_CRYPT
+ && options[opt_idx].indir != PV_KEY
+# endif
+ )
+ {
+ saved_oldval = vim_strsave(oldval);
+ saved_newval = vim_strsave(s);
+ }
+#endif
+ if ((r = did_set_string_option(opt_idx, varp, TRUE, oldval, NULL,
+ opt_flags, &value_checked)) == NULL)
+ did_set_option(opt_idx, opt_flags, TRUE, value_checked);
+
+#if defined(FEAT_EVAL)
+ /* call autocommand after handling side effects */
+ if (r == NULL)
+ trigger_optionsset_string(opt_idx, opt_flags,
+ saved_oldval, saved_newval);
+ vim_free(saved_oldval);
+ vim_free(saved_newval);
+#endif
+ }
+ return r;
+}
+
+/*
+ * Return TRUE if "val" is a valid 'filetype' name.
+ * Also used for 'syntax' and 'keymap'.
+ */
+ static int
+valid_filetype(char_u *val)
+{
+ char_u *s;
+
+ for (s = val; *s != NUL; ++s)
+ if (!ASCII_ISALNUM(*s) && vim_strchr((char_u *)".-_", *s) == NULL)
+ return FALSE;
+ return TRUE;
+}
+
+/*
+ * Handle string options that need some action to perform when changed.
+ * Returns NULL for success, or an error message for an error.
+ */
+ static char *
+did_set_string_option(
+ int opt_idx, // index in options[] table
+ char_u **varp, // pointer to the option variable
+ int new_value_alloced, // new value was allocated
+ char_u *oldval, // previous value of the option
+ char *errbuf, // buffer for errors, or NULL
+ int opt_flags, // OPT_LOCAL and/or OPT_GLOBAL
+ int *value_checked) // value was checked to be save, no
+ // need to set P_INSECURE
+{
+ char *errmsg = NULL;
+ char_u *s, *p;
+ int did_chartab = FALSE;
+ char_u **gvarp;
+ long_u free_oldval = (options[opt_idx].flags & P_ALLOCED);
+#ifdef FEAT_GUI
+ /* set when changing an option that only requires a redraw in the GUI */
+ int redraw_gui_only = FALSE;
+#endif
+ int value_changed = FALSE;
+#if defined(FEAT_VTP) && defined(FEAT_TERMGUICOLORS)
+ int did_swaptcap = FALSE;
+#endif
+
+ /* Get the global option to compare with, otherwise we would have to check
+ * two values for all local options. */
+ gvarp = (char_u **)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL);
+
+ /* Disallow changing some options from secure mode */
+ if ((secure
+#ifdef HAVE_SANDBOX
+ || sandbox != 0
+#endif
+ ) && (options[opt_idx].flags & P_SECURE))
+ {
+ errmsg = e_secure;
+ }
+
+ // Check for a "normal" directory or file name in some options. Disallow a
+ // path separator (slash and/or backslash), wildcards and characters that
+ // are often illegal in a file name. Be more permissive if "secure" is off.
+ else if (((options[opt_idx].flags & P_NFNAME)
+ && vim_strpbrk(*varp, (char_u *)(secure
+ ? "/\\*?[|;&<>\r\n" : "/\\*?[<>\r\n")) != NULL)
+ || ((options[opt_idx].flags & P_NDNAME)
+ && vim_strpbrk(*varp, (char_u *)"*?[|;&<>\r\n") != NULL))
+ {
+ errmsg = e_invarg;
+ }
+
+ /* 'term' */
+ else if (varp == &T_NAME)
+ {
+ if (T_NAME[0] == NUL)
+ errmsg = N_("E529: Cannot set 'term' to empty string");
+#ifdef FEAT_GUI
+ if (gui.in_use)
+ errmsg = N_("E530: Cannot change term in GUI");
+ else if (term_is_gui(T_NAME))
+ errmsg = N_("E531: Use \":gui\" to start the GUI");
+#endif
+ else if (set_termname(T_NAME) == FAIL)
+ errmsg = N_("E522: Not found in termcap");
+ else
+ {
+ /* Screen colors may have changed. */
+ redraw_later_clear();
+
+ /* Both 'term' and 'ttytype' point to T_NAME, only set the
+ * P_ALLOCED flag on 'term'. */
+ opt_idx = findoption((char_u *)"term");
+ free_oldval = (options[opt_idx].flags & P_ALLOCED);
+ }
+ }
+
+ /* 'backupcopy' */
+ else if (gvarp == &p_bkc)
+ {
+ char_u *bkc = p_bkc;
+ unsigned int *flags = &bkc_flags;
+
+ if (opt_flags & OPT_LOCAL)
+ {
+ bkc = curbuf->b_p_bkc;
+ flags = &curbuf->b_bkc_flags;
+ }
+
+ if ((opt_flags & OPT_LOCAL) && *bkc == NUL)
+ /* make the local value empty: use the global value */
+ *flags = 0;
+ else
+ {
+ if (opt_strings_flags(bkc, p_bkc_values, flags, TRUE) != OK)
+ errmsg = e_invarg;
+ if ((((int)*flags & BKC_AUTO) != 0)
+ + (((int)*flags & BKC_YES) != 0)
+ + (((int)*flags & BKC_NO) != 0) != 1)
+ {
+ /* Must have exactly one of "auto", "yes" and "no". */
+ (void)opt_strings_flags(oldval, p_bkc_values, flags, TRUE);
+ errmsg = e_invarg;
+ }
+ }
+ }
+
+ /* 'backupext' and 'patchmode' */
+ else if (varp == &p_bex || varp == &p_pm)
+ {
+ if (STRCMP(*p_bex == '.' ? p_bex + 1 : p_bex,
+ *p_pm == '.' ? p_pm + 1 : p_pm) == 0)
+ errmsg = N_("E589: 'backupext' and 'patchmode' are equal");
+ }
+#ifdef FEAT_LINEBREAK
+ /* 'breakindentopt' */
+ else if (varp == &curwin->w_p_briopt)
+ {
+ if (briopt_check(curwin) == FAIL)
+ errmsg = e_invarg;
+ }
+#endif
+
+ /*
+ * 'isident', 'iskeyword', 'isprint or 'isfname' option: refill g_chartab[]
+ * If the new option is invalid, use old value. 'lisp' option: refill
+ * g_chartab[] for '-' char
+ */
+ else if ( varp == &p_isi
+ || varp == &(curbuf->b_p_isk)
+ || varp == &p_isp
+ || varp == &p_isf)
+ {
+ if (init_chartab() == FAIL)
+ {
+ did_chartab = TRUE; /* need to restore it below */
+ errmsg = e_invarg; /* error in value */
+ }
+ }
+
+ /* 'helpfile' */
+ else if (varp == &p_hf)
+ {
+ /* May compute new values for $VIM and $VIMRUNTIME */
+ if (didset_vim)
+ {
+ vim_setenv((char_u *)"VIM", (char_u *)"");
+ didset_vim = FALSE;
+ }
+ if (didset_vimruntime)
+ {
+ vim_setenv((char_u *)"VIMRUNTIME", (char_u *)"");
+ didset_vimruntime = FALSE;
+ }
+ }
+
+#ifdef FEAT_SYN_HL
+ /* 'colorcolumn' */
+ else if (varp == &curwin->w_p_cc)
+ errmsg = check_colorcolumn(curwin);
+#endif
+
+#ifdef FEAT_MULTI_LANG
+ /* 'helplang' */
+ else if (varp == &p_hlg)
+ {
+ /* Check for "", "ab", "ab,cd", etc. */
+ for (s = p_hlg; *s != NUL; s += 3)
+ {
+ if (s[1] == NUL || ((s[2] != ',' || s[3] == NUL) && s[2] != NUL))
+ {
+ errmsg = e_invarg;
+ break;
+ }
+ if (s[2] == NUL)
+ break;
+ }
+ }
+#endif
+
+ /* 'highlight' */
+ else if (varp == &p_hl)
+ {
+ if (highlight_changed() == FAIL)
+ errmsg = e_invarg; /* invalid flags */
+ }
+
+ /* 'nrformats' */
+ else if (gvarp == &p_nf)
+ {
+ if (check_opt_strings(*varp, p_nf_values, TRUE) != OK)
+ errmsg = e_invarg;
+ }
+
+#ifdef FEAT_SESSION
+ /* 'sessionoptions' */
+ else if (varp == &p_ssop)
+ {
+ if (opt_strings_flags(p_ssop, p_ssop_values, &ssop_flags, TRUE) != OK)
+ errmsg = e_invarg;
+ if ((ssop_flags & SSOP_CURDIR) && (ssop_flags & SSOP_SESDIR))
+ {
+ /* Don't allow both "sesdir" and "curdir". */
+ (void)opt_strings_flags(oldval, p_ssop_values, &ssop_flags, TRUE);
+ errmsg = e_invarg;
+ }
+ }
+ /* 'viewoptions' */
+ else if (varp == &p_vop)
+ {
+ if (opt_strings_flags(p_vop, p_ssop_values, &vop_flags, TRUE) != OK)
+ errmsg = e_invarg;
+ }
+#endif
+
+ /* 'scrollopt' */
+ else if (varp == &p_sbo)
+ {
+ if (check_opt_strings(p_sbo, p_scbopt_values, TRUE) != OK)
+ errmsg = e_invarg;
+ }
+
+ /* 'ambiwidth' */
+ else if (varp == &p_ambw || varp == &p_emoji)
+ {
+ if (check_opt_strings(p_ambw, p_ambw_values, FALSE) != OK)
+ errmsg = e_invarg;
+ else if (set_chars_option(&p_lcs) != NULL)
+ errmsg = _("E834: Conflicts with value of 'listchars'");
+ else if (set_chars_option(&p_fcs) != NULL)
+ errmsg = _("E835: Conflicts with value of 'fillchars'");
+ }
+
+ /* 'background' */
+ else if (varp == &p_bg)
+ {
+ if (check_opt_strings(p_bg, p_bg_values, FALSE) == OK)
+ {
+#ifdef FEAT_EVAL
+ int dark = (*p_bg == 'd');
+#endif
+
+ init_highlight(FALSE, FALSE);
+
+#ifdef FEAT_EVAL
+ if (dark != (*p_bg == 'd')
+ && get_var_value((char_u *)"g:colors_name") != NULL)
+ {
+ /* The color scheme must have set 'background' back to another
+ * value, that's not what we want here. Disable the color
+ * scheme and set the colors again. */
+ do_unlet((char_u *)"g:colors_name", TRUE);
+ free_string_option(p_bg);
+ p_bg = vim_strsave((char_u *)(dark ? "dark" : "light"));
+ check_string_option(&p_bg);
+ init_highlight(FALSE, FALSE);
+ }
+#endif
+ }
+ else
+ errmsg = e_invarg;
+ }
+
+ /* 'wildmode' */
+ else if (varp == &p_wim)
+ {
+ if (check_opt_wim() == FAIL)
+ errmsg = e_invarg;
+ }
+
+#ifdef FEAT_CMDL_COMPL
+ /* 'wildoptions' */
+ else if (varp == &p_wop)
+ {
+ if (check_opt_strings(p_wop, p_wop_values, TRUE) != OK)
+ errmsg = e_invarg;
+ }
+#endif
+
+#ifdef FEAT_WAK
+ /* 'winaltkeys' */
+ else if (varp == &p_wak)
+ {
+ if (*p_wak == NUL
+ || check_opt_strings(p_wak, p_wak_values, FALSE) != OK)
+ errmsg = e_invarg;
+# ifdef FEAT_MENU
+# ifdef FEAT_GUI_MOTIF
+ else if (gui.in_use)
+ gui_motif_set_mnemonics(p_wak[0] == 'y' || p_wak[0] == 'm');
+# else
+# ifdef FEAT_GUI_GTK
+ else if (gui.in_use)
+ gui_gtk_set_mnemonics(p_wak[0] == 'y' || p_wak[0] == 'm');
+# endif
+# endif
+# endif
+ }
+#endif
+
+ /* 'eventignore' */
+ else if (varp == &p_ei)
+ {
+ if (check_ei() == FAIL)
+ errmsg = e_invarg;
+ }
+
+ /* 'encoding', 'fileencoding', 'termencoding' and 'makeencoding' */
+ else if (varp == &p_enc || gvarp == &p_fenc || varp == &p_tenc
+ || gvarp == &p_menc)
+ {
+ if (gvarp == &p_fenc)
+ {
+ if (!curbuf->b_p_ma && opt_flags != OPT_GLOBAL)
+ errmsg = e_modifiable;
+ else if (vim_strchr(*varp, ',') != NULL)
+ /* No comma allowed in 'fileencoding'; catches confusing it
+ * with 'fileencodings'. */
+ errmsg = e_invarg;
+ else
+ {
+#ifdef FEAT_TITLE
+ /* May show a "+" in the title now. */
+ redraw_titles();
+#endif
+ /* Add 'fileencoding' to the swap file. */
+ ml_setflags(curbuf);
+ }
+ }
+ if (errmsg == NULL)
+ {
+ /* canonize the value, so that STRCMP() can be used on it */
+ p = enc_canonize(*varp);
+ if (p != NULL)
+ {
+ vim_free(*varp);
+ *varp = p;
+ }
+ if (varp == &p_enc)
+ {
+ errmsg = mb_init();
+#ifdef FEAT_TITLE
+ redraw_titles();
+#endif
+ }
+ }
+
+#if defined(FEAT_GUI_GTK)
+ if (errmsg == NULL && varp == &p_tenc && gui.in_use)
+ {
+ /* GTK+ 2 uses only a single encoding, and that is UTF-8. */
+ if (STRCMP(p_tenc, "utf-8") != 0)
+ errmsg = N_("E617: Cannot be changed in the GTK+ 2 GUI");
+ }
+#endif
+
+ if (errmsg == NULL)
+ {
+#ifdef FEAT_KEYMAP
+ /* When 'keymap' is used and 'encoding' changes, reload the keymap
+ * (with another encoding). */
+ if (varp == &p_enc && *curbuf->b_p_keymap != NUL)
+ (void)keymap_init();
+#endif
+
+ /* When 'termencoding' is not empty and 'encoding' changes or when
+ * 'termencoding' changes, need to setup for keyboard input and
+ * display output conversion. */
+ if (((varp == &p_enc && *p_tenc != NUL) || varp == &p_tenc))
+ {
+ if (convert_setup(&input_conv, p_tenc, p_enc) == FAIL
+ || convert_setup(&output_conv, p_enc, p_tenc) == FAIL)
+ {
+ semsg(_("E950: Cannot convert between %s and %s"),
+ p_tenc, p_enc);
+ errmsg = e_invarg;
+ }
+ }
+
+#if defined(WIN3264)
+ /* $HOME may have characters in active code page. */
+ if (varp == &p_enc)
+ init_homedir();
+#endif
+ }
+ }
+
+#if defined(FEAT_POSTSCRIPT)
+ else if (varp == &p_penc)
+ {
+ /* Canonize printencoding if VIM standard one */
+ p = enc_canonize(p_penc);
+ if (p != NULL)
+ {
+ vim_free(p_penc);
+ p_penc = p;
+ }
+ else
+ {
+ /* Ensure lower case and '-' for '_' */
+ for (s = p_penc; *s != NUL; s++)
+ {
+ if (*s == '_')
+ *s = '-';
+ else
+ *s = TOLOWER_ASC(*s);
+ }
+ }
+ }
+#endif
+
+#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
+ else if (varp == &p_imak)
+ {
+ if (!im_xim_isvalid_imactivate())
+ errmsg = e_invarg;
+ }
+#endif
+
+#ifdef FEAT_KEYMAP
+ else if (varp == &curbuf->b_p_keymap)
+ {
+ if (!valid_filetype(*varp))
+ errmsg = e_invarg;
+ else
+ {
+ int secure_save = secure;
+
+ // Reset the secure flag, since the value of 'keymap' has
+ // been checked to be safe.
+ secure = 0;
+
+ // load or unload key mapping tables
+ errmsg = keymap_init();
+
+ secure = secure_save;
+
+ // Since we check the value, there is no need to set P_INSECURE,
+ // even when the value comes from a modeline.
+ *value_checked = TRUE;
+ }
+
+ if (errmsg == NULL)
+ {
+ if (*curbuf->b_p_keymap != NUL)
+ {
+ /* Installed a new keymap, switch on using it. */
+ curbuf->b_p_iminsert = B_IMODE_LMAP;
+ if (curbuf->b_p_imsearch != B_IMODE_USE_INSERT)
+ curbuf->b_p_imsearch = B_IMODE_LMAP;
+ }
+ else
+ {
+ /* Cleared the keymap, may reset 'iminsert' and 'imsearch'. */
+ if (curbuf->b_p_iminsert == B_IMODE_LMAP)
+ curbuf->b_p_iminsert = B_IMODE_NONE;
+ if (curbuf->b_p_imsearch == B_IMODE_LMAP)
+ curbuf->b_p_imsearch = B_IMODE_USE_INSERT;
+ }
+ if ((opt_flags & OPT_LOCAL) == 0)
+ {
+ set_iminsert_global();
+ set_imsearch_global();
+ }
+ status_redraw_curbuf();
+ }
+ }
+#endif
+
+ /* 'fileformat' */
+ else if (gvarp == &p_ff)
+ {
+ if (!curbuf->b_p_ma && !(opt_flags & OPT_GLOBAL))
+ errmsg = e_modifiable;
+ else if (check_opt_strings(*varp, p_ff_values, FALSE) != OK)
+ errmsg = e_invarg;
+ else
+ {
+ /* may also change 'textmode' */
+ if (get_fileformat(curbuf) == EOL_DOS)
+ curbuf->b_p_tx = TRUE;
+ else
+ curbuf->b_p_tx = FALSE;
+#ifdef FEAT_TITLE
+ redraw_titles();
+#endif
+ /* update flag in swap file */
+ ml_setflags(curbuf);
+ /* Redraw needed when switching to/from "mac": a CR in the text
+ * will be displayed differently. */
+ if (get_fileformat(curbuf) == EOL_MAC || *oldval == 'm')
+ redraw_curbuf_later(NOT_VALID);
+ }
+ }
+
+ /* 'fileformats' */
+ else if (varp == &p_ffs)
+ {
+ if (check_opt_strings(p_ffs, p_ff_values, TRUE) != OK)
+ errmsg = e_invarg;
+ else
+ {
+ /* also change 'textauto' */
+ if (*p_ffs == NUL)
+ p_ta = FALSE;
+ else
+ p_ta = TRUE;
+ }
+ }
+
+#if defined(FEAT_CRYPT)
+ /* 'cryptkey' */
+ else if (gvarp == &p_key)
+ {
+# if defined(FEAT_CMDHIST)
+ /* Make sure the ":set" command doesn't show the new value in the
+ * history. */
+ remove_key_from_history();
+# endif
+ if (STRCMP(curbuf->b_p_key, oldval) != 0)
+ /* Need to update the swapfile. */
+ ml_set_crypt_key(curbuf, oldval,
+ *curbuf->b_p_cm == NUL ? p_cm : curbuf->b_p_cm);
+ }
+
+ else if (gvarp == &p_cm)
+ {
+ if (opt_flags & OPT_LOCAL)
+ p = curbuf->b_p_cm;
+ else
+ p = p_cm;
+ if (check_opt_strings(p, p_cm_values, TRUE) != OK)
+ errmsg = e_invarg;
+ else if (crypt_self_test() == FAIL)
+ errmsg = e_invarg;
+ else
+ {
+ /* When setting the global value to empty, make it "zip". */
+ if (*p_cm == NUL)
+ {
+ if (new_value_alloced)
+ free_string_option(p_cm);
+ p_cm = vim_strsave((char_u *)"zip");
+ new_value_alloced = TRUE;
+ }
+ /* When using ":set cm=name" the local value is going to be empty.
+ * Do that here, otherwise the crypt functions will still use the
+ * local value. */
+ if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0)
+ {
+ free_string_option(curbuf->b_p_cm);
+ curbuf->b_p_cm = empty_option;
+ }
+
+ /* Need to update the swapfile when the effective method changed.
+ * Set "s" to the effective old value, "p" to the effective new
+ * method and compare. */
+ if ((opt_flags & OPT_LOCAL) && *oldval == NUL)
+ s = p_cm; /* was previously using the global value */
+ else
+ s = oldval;
+ if (*curbuf->b_p_cm == NUL)
+ p = p_cm; /* is now using the global value */
+ else
+ p = curbuf->b_p_cm;
+ if (STRCMP(s, p) != 0)
+ ml_set_crypt_key(curbuf, curbuf->b_p_key, s);
+
+ /* If the global value changes need to update the swapfile for all
+ * buffers using that value. */
+ if ((opt_flags & OPT_GLOBAL) && STRCMP(p_cm, oldval) != 0)
+ {
+ buf_T *buf;
+
+ FOR_ALL_BUFFERS(buf)
+ if (buf != curbuf && *buf->b_p_cm == NUL)
+ ml_set_crypt_key(buf, buf->b_p_key, oldval);
+ }
+ }
+ }
+#endif
+
+ /* 'matchpairs' */
+ else if (gvarp == &p_mps)
+ {
+ if (has_mbyte)
+ {
+ for (p = *varp; *p != NUL; ++p)
+ {
+ int x2 = -1;
+ int x3 = -1;
+
+ if (*p != NUL)
+ p += mb_ptr2len(p);
+ if (*p != NUL)
+ x2 = *p++;
+ if (*p != NUL)
+ {
+ x3 = mb_ptr2char(p);
+ p += mb_ptr2len(p);
+ }
+ if (x2 != ':' || x3 == -1 || (*p != NUL && *p != ','))
+ {
+ errmsg = e_invarg;
+ break;
+ }
+ if (*p == NUL)
+ break;
+ }
+ }
+ else
+ {
+ /* Check for "x:y,x:y" */
+ for (p = *varp; *p != NUL; p += 4)
+ {
+ if (p[1] != ':' || p[2] == NUL || (p[3] != NUL && p[3] != ','))
+ {
+ errmsg = e_invarg;
+ break;
+ }
+ if (p[3] == NUL)
+ break;
+ }
+ }
+ }
+
+#ifdef FEAT_COMMENTS
+ /* 'comments' */
+ else if (gvarp == &p_com)
+ {
+ for (s = *varp; *s; )
+ {
+ while (*s && *s != ':')
+ {
+ if (vim_strchr((char_u *)COM_ALL, *s) == NULL
+ && !VIM_ISDIGIT(*s) && *s != '-')
+ {
+ errmsg = illegal_char(errbuf, *s);
+ break;
+ }
+ ++s;
+ }
+ if (*s++ == NUL)
+ errmsg = N_("E524: Missing colon");
+ else if (*s == ',' || *s == NUL)
+ errmsg = N_("E525: Zero length string");
+ if (errmsg != NULL)
+ break;
+ while (*s && *s != ',')
+ {
+ if (*s == '\\' && s[1] != NUL)
+ ++s;
+ ++s;
+ }
+ s = skip_to_option_part(s);
+ }
+ }
+#endif
+
+ /* 'listchars' */
+ else if (varp == &p_lcs)
+ {
+ errmsg = set_chars_option(varp);
+ }
+
+ /* 'fillchars' */
+ else if (varp == &p_fcs)
+ {
+ errmsg = set_chars_option(varp);
+ }
+
+#ifdef FEAT_CMDWIN
+ /* 'cedit' */
+ else if (varp == &p_cedit)
+ {
+ errmsg = check_cedit();
+ }
+#endif
+
+ /* 'verbosefile' */
+ else if (varp == &p_vfile)
+ {
+ verbose_stop();
+ if (*p_vfile != NUL && verbose_open() == FAIL)
+ errmsg = e_invarg;
+ }
+
+#ifdef FEAT_VIMINFO
+ /* 'viminfo' */
+ else if (varp == &p_viminfo)
+ {
+ for (s = p_viminfo; *s;)
+ {
+ /* Check it's a valid character */
+ if (vim_strchr((char_u *)"!\"%'/:<@cfhnrs", *s) == NULL)
+ {
+ errmsg = illegal_char(errbuf, *s);
+ break;
+ }
+ if (*s == 'n') /* name is always last one */
+ {
+ break;
+ }
+ else if (*s == 'r') /* skip until next ',' */
+ {
+ while (*++s && *s != ',')
+ ;
+ }
+ else if (*s == '%')
+ {
+ /* optional number */
+ while (vim_isdigit(*++s))
+ ;
+ }
+ else if (*s == '!' || *s == 'h' || *s == 'c')
+ ++s; /* no extra chars */
+ else /* must have a number */
+ {
+ while (vim_isdigit(*++s))
+ ;
+
+ if (!VIM_ISDIGIT(*(s - 1)))
+ {
+ if (errbuf != NULL)
+ {
+ sprintf(errbuf, _("E526: Missing number after <%s>"),
+ transchar_byte(*(s - 1)));
+ errmsg = errbuf;
+ }
+ else
+ errmsg = "";
+ break;
+ }
+ }
+ if (*s == ',')
+ ++s;
+ else if (*s)
+ {
+ if (errbuf != NULL)
+ errmsg = N_("E527: Missing comma");
+ else
+ errmsg = "";
+ break;
+ }
+ }
+ if (*p_viminfo && errmsg == NULL && get_viminfo_parameter('\'') < 0)
+ errmsg = N_("E528: Must specify a ' value");
+ }
+#endif /* FEAT_VIMINFO */
+
+ /* terminal options */
+ else if (istermoption(&options[opt_idx]) && full_screen)
+ {
+ /* ":set t_Co=0" and ":set t_Co=1" do ":set t_Co=" */
+ if (varp == &T_CCO)
+ {
+ int colors = atoi((char *)T_CCO);
+
+ /* Only reinitialize colors if t_Co value has really changed to
+ * avoid expensive reload of colorscheme if t_Co is set to the
+ * same value multiple times. */
+ if (colors != t_colors)
+ {
+ t_colors = colors;
+ if (t_colors <= 1)
+ {
+ if (new_value_alloced)
+ vim_free(T_CCO);
+ T_CCO = empty_option;
+ }
+#if defined(FEAT_VTP) && defined(FEAT_TERMGUICOLORS)
+ if (is_term_win32())
+ {
+ swap_tcap();
+ did_swaptcap = TRUE;
+ }
+#endif
+ /* We now have a different color setup, initialize it again. */
+ init_highlight(TRUE, FALSE);
+ }
+ }
+ ttest(FALSE);
+ if (varp == &T_ME)
+ {
+ out_str(T_ME);
+ redraw_later(CLEAR);
+#if defined(WIN3264) && !defined(FEAT_GUI_W32)
+ /* Since t_me has been set, this probably means that the user
+ * wants to use this as default colors. Need to reset default
+ * background/foreground colors. */
+ mch_set_normal_colors();
+#endif
+ }
+ if (varp == &T_BE && termcap_active)
+ {
+ if (*T_BE == NUL)
+ /* When clearing t_BE we assume the user no longer wants
+ * bracketed paste, thus disable it by writing t_BD. */
+ out_str(T_BD);
+ else
+ out_str(T_BE);
+ }
+ }
+
+#ifdef FEAT_LINEBREAK
+ /* 'showbreak' */
+ else if (varp == &p_sbr)
+ {
+ for (s = p_sbr; *s; )
+ {
+ if (ptr2cells(s) != 1)
+ errmsg = N_("E595: contains unprintable or wide character");
+ MB_PTR_ADV(s);
+ }
+ }
+#endif
+
+#ifdef FEAT_GUI
+ /* 'guifont' */
+ else if (varp == &p_guifont)
+ {
+ if (gui.in_use)
+ {
+ p = p_guifont;
+# if defined(FEAT_GUI_GTK)
+ /*
+ * Put up a font dialog and let the user select a new value.
+ * If this is cancelled go back to the old value but don't
+ * give an error message.
+ */
+ if (STRCMP(p, "*") == 0)
+ {
+ p = gui_mch_font_dialog(oldval);
+
+ if (new_value_alloced)
+ free_string_option(p_guifont);
+
+ p_guifont = (p != NULL) ? p : vim_strsave(oldval);
+ new_value_alloced = TRUE;
+ }
+# endif
+ if (p != NULL && gui_init_font(p_guifont, FALSE) != OK)
+ {
+# if defined(FEAT_GUI_MSWIN) || defined(FEAT_GUI_PHOTON)
+ if (STRCMP(p_guifont, "*") == 0)
+ {
+ /* Dialog was cancelled: Keep the old value without giving
+ * an error message. */
+ if (new_value_alloced)
+ free_string_option(p_guifont);
+ p_guifont = vim_strsave(oldval);
+ new_value_alloced = TRUE;
+ }
+ else
+# endif
+ errmsg = N_("E596: Invalid font(s)");
+ }
+ }
+ redraw_gui_only = TRUE;
+ }
+# ifdef FEAT_XFONTSET
+ else if (varp == &p_guifontset)
+ {
+ if (STRCMP(p_guifontset, "*") == 0)
+ errmsg = N_("E597: can't select fontset");
+ else if (gui.in_use && gui_init_font(p_guifontset, TRUE) != OK)
+ errmsg = N_("E598: Invalid fontset");
+ redraw_gui_only = TRUE;
+ }
+# endif
+ else if (varp == &p_guifontwide)
+ {
+ if (STRCMP(p_guifontwide, "*") == 0)
+ errmsg = N_("E533: can't select wide font");
+ else if (gui_get_wide_font() == FAIL)
+ errmsg = N_("E534: Invalid wide font");
+ redraw_gui_only = TRUE;
+ }
+#endif
+
+#ifdef CURSOR_SHAPE
+ /* 'guicursor' */
+ else if (varp == &p_guicursor)
+ errmsg = parse_shape_opt(SHAPE_CURSOR);
+#endif
+
+#ifdef FEAT_MOUSESHAPE
+ /* 'mouseshape' */
+ else if (varp == &p_mouseshape)
+ {
+ errmsg = parse_shape_opt(SHAPE_MOUSE);
+ update_mouseshape(-1);
+ }
+#endif
+
+#ifdef FEAT_PRINTER
+ else if (varp == &p_popt)
+ errmsg = parse_printoptions();
+# if defined(FEAT_POSTSCRIPT)
+ else if (varp == &p_pmfn)
+ errmsg = parse_printmbfont();
+# endif
+#endif
+
+#ifdef FEAT_LANGMAP
+ /* 'langmap' */
+ else if (varp == &p_langmap)
+ langmap_set();
+#endif
+
+#ifdef FEAT_LINEBREAK
+ /* 'breakat' */
+ else if (varp == &p_breakat)
+ fill_breakat_flags();
+#endif
+
+#ifdef FEAT_TITLE
+ /* 'titlestring' and 'iconstring' */
+ else if (varp == &p_titlestring || varp == &p_iconstring)
+ {
+# ifdef FEAT_STL_OPT
+ int flagval = (varp == &p_titlestring) ? STL_IN_TITLE : STL_IN_ICON;
+
+ /* NULL => statusline syntax */
+ if (vim_strchr(*varp, '%') && check_stl_option(*varp) == NULL)
+ stl_syntax |= flagval;
+ else
+ stl_syntax &= ~flagval;
+# endif
+ did_set_title();
+ }
+#endif
+
+#ifdef FEAT_GUI
+ /* 'guioptions' */
+ else if (varp == &p_go)
+ {
+ gui_init_which_components(oldval);
+ redraw_gui_only = TRUE;
+ }
+#endif
+
+#if defined(FEAT_GUI_TABLINE)
+ /* 'guitablabel' */
+ else if (varp == &p_gtl)
+ {
+ redraw_tabline = TRUE;
+ redraw_gui_only = TRUE;
+ }
+ /* 'guitabtooltip' */
+ else if (varp == &p_gtt)
+ {
+ redraw_gui_only = TRUE;
+ }
+#endif
+
+#if defined(FEAT_MOUSE_TTY) && (defined(UNIX) || defined(VMS))
+ /* 'ttymouse' */
+ else if (varp == &p_ttym)
+ {
+ /* Switch the mouse off before changing the escape sequences used for
+ * that. */
+ mch_setmouse(FALSE);
+ if (opt_strings_flags(p_ttym, p_ttym_values, &ttym_flags, FALSE) != OK)
+ errmsg = e_invarg;
+ else
+ check_mouse_termcode();
+ if (termcap_active)
+ setmouse(); /* may switch it on again */
+ }
+#endif
+
+ /* 'selection' */
+ else if (varp == &p_sel)
+ {
+ if (*p_sel == NUL
+ || check_opt_strings(p_sel, p_sel_values, FALSE) != OK)
+ errmsg = e_invarg;
+ }
+
+ /* 'selectmode' */
+ else if (varp == &p_slm)
+ {
+ if (check_opt_strings(p_slm, p_slm_values, TRUE) != OK)
+ errmsg = e_invarg;
+ }
+
+#ifdef FEAT_BROWSE
+ /* 'browsedir' */
+ else if (varp == &p_bsdir)
+ {
+ if (check_opt_strings(p_bsdir, p_bsdir_values, FALSE) != OK
+ && !mch_isdir(p_bsdir))
+ errmsg = e_invarg;
+ }
+#endif
+
+ /* 'keymodel' */
+ else if (varp == &p_km)
+ {
+ if (check_opt_strings(p_km, p_km_values, TRUE) != OK)
+ errmsg = e_invarg;
+ else
+ {
+ km_stopsel = (vim_strchr(p_km, 'o') != NULL);
+ km_startsel = (vim_strchr(p_km, 'a') != NULL);
+ }
+ }
+
+ /* 'mousemodel' */
+ else if (varp == &p_mousem)
+ {
+ if (check_opt_strings(p_mousem, p_mousem_values, FALSE) != OK)
+ errmsg = e_invarg;
+#if defined(FEAT_GUI_MOTIF) && defined(FEAT_MENU) && (XmVersion <= 1002)
+ else if (*p_mousem != *oldval)
+ /* Changed from "extend" to "popup" or "popup_setpos" or vv: need
+ * to create or delete the popup menus. */
+ gui_motif_update_mousemodel(root_menu);
+#endif
+ }
+
+ /* 'switchbuf' */
+ else if (varp == &p_swb)
+ {
+ if (opt_strings_flags(p_swb, p_swb_values, &swb_flags, TRUE) != OK)
+ errmsg = e_invarg;
+ }
+
+ /* 'debug' */
+ else if (varp == &p_debug)
+ {
+ if (check_opt_strings(p_debug, p_debug_values, TRUE) != OK)
+ errmsg = e_invarg;
+ }
+
+ /* 'display' */
+ else if (varp == &p_dy)
+ {
+ if (opt_strings_flags(p_dy, p_dy_values, &dy_flags, TRUE) != OK)
+ errmsg = e_invarg;
+ else
+ (void)init_chartab();
+
+ }
+
+ /* 'eadirection' */
+ else if (varp == &p_ead)
+ {
+ if (check_opt_strings(p_ead, p_ead_values, FALSE) != OK)
+ errmsg = e_invarg;
+ }
+
+#ifdef FEAT_CLIPBOARD
+ /* 'clipboard' */
+ else if (varp == &p_cb)
+ errmsg = check_clipboard_option();
+#endif
+
+#ifdef FEAT_SPELL
+ /* When 'spelllang' or 'spellfile' is set and there is a window for this
+ * buffer in which 'spell' is set load the wordlists. */
+ else if (varp == &(curwin->w_s->b_p_spl)
+ || varp == &(curwin->w_s->b_p_spf))
+ {
+ errmsg = did_set_spell_option(varp == &(curwin->w_s->b_p_spf));
+ }
+ /* When 'spellcapcheck' is set compile the regexp program. */
+ else if (varp == &(curwin->w_s->b_p_spc))
+ {
+ errmsg = compile_cap_prog(curwin->w_s);
+ }
+ /* 'spellsuggest' */
+ else if (varp == &p_sps)
+ {
+ if (spell_check_sps() != OK)
+ errmsg = e_invarg;
+ }
+ /* 'mkspellmem' */
+ else if (varp == &p_msm)
+ {
+ if (spell_check_msm() != OK)
+ errmsg = e_invarg;
+ }
+#endif
+
+ /* When 'bufhidden' is set, check for valid value. */
+ else if (gvarp == &p_bh)
+ {
+ if (check_opt_strings(curbuf->b_p_bh, p_bufhidden_values, FALSE) != OK)
+ errmsg = e_invarg;
+ }
+
+ /* When 'buftype' is set, check for valid value. */
+ else if (gvarp == &p_bt)
+ {
+ if (check_opt_strings(curbuf->b_p_bt, p_buftype_values, FALSE) != OK)
+ errmsg = e_invarg;
+ else
+ {
+ if (curwin->w_status_height)
+ {
+ curwin->w_redr_status = TRUE;
+ redraw_later(VALID);
+ }
+ curbuf->b_help = (curbuf->b_p_bt[0] == 'h');
+#ifdef FEAT_TITLE
+ redraw_titles();
+#endif
+ }
+ }
+
+#ifdef FEAT_STL_OPT
+ /* 'statusline' or 'rulerformat' */
+ else if (gvarp == &p_stl || varp == &p_ruf)
+ {
+ int wid;
+
+ if (varp == &p_ruf) /* reset ru_wid first */
+ ru_wid = 0;
+ s = *varp;
+ if (varp == &p_ruf && *s == '%')
+ {
+ /* set ru_wid if 'ruf' starts with "%99(" */
+ if (*++s == '-') /* ignore a '-' */
+ s++;
+ wid = getdigits(&s);
+ if (wid && *s == '(' && (errmsg = check_stl_option(p_ruf)) == NULL)
+ ru_wid = wid;
+ else
+ errmsg = check_stl_option(p_ruf);
+ }
+ /* check 'statusline' only if it doesn't start with "%!" */
+ else if (varp == &p_ruf || s[0] != '%' || s[1] != '!')
+ errmsg = check_stl_option(s);
+ if (varp == &p_ruf && errmsg == NULL)
+ comp_col();
+ }
+#endif
+
+#ifdef FEAT_INS_EXPAND
+ /* check if it is a valid value for 'complete' -- Acevedo */
+ else if (gvarp == &p_cpt)
+ {
+ for (s = *varp; *s;)
+ {
+ while (*s == ',' || *s == ' ')
+ s++;
+ if (!*s)
+ break;
+ if (vim_strchr((char_u *)".wbuksid]tU", *s) == NULL)
+ {
+ errmsg = illegal_char(errbuf, *s);
+ break;
+ }
+ if (*++s != NUL && *s != ',' && *s != ' ')
+ {
+ if (s[-1] == 'k' || s[-1] == 's')
+ {
+ /* skip optional filename after 'k' and 's' */
+ while (*s && *s != ',' && *s != ' ')
+ {
+ if (*s == '\\' && s[1] != NUL)
+ ++s;
+ ++s;
+ }
+ }
+ else
+ {
+ if (errbuf != NULL)
+ {
+ sprintf((char *)errbuf,
+ _("E535: Illegal character after <%c>"),
+ *--s);
+ errmsg = errbuf;
+ }
+ else
+ errmsg = "";
+ break;
+ }
+ }
+ }
+ }
+
+ /* 'completeopt' */
+ else if (varp == &p_cot)
+ {
+ if (check_opt_strings(p_cot, p_cot_values, TRUE) != OK)
+ errmsg = e_invarg;
+ else
+ completeopt_was_set();
+ }
+#endif /* FEAT_INS_EXPAND */
+
+#ifdef FEAT_SIGNS
+ /* 'signcolumn' */
+ else if (varp == &curwin->w_p_scl)
+ {
+ if (check_opt_strings(*varp, p_scl_values, FALSE) != OK)
+ errmsg = e_invarg;
+ }
+#endif
+
+
+#if defined(FEAT_TOOLBAR) && !defined(FEAT_GUI_W32)
+ /* 'toolbar' */
+ else if (varp == &p_toolbar)
+ {
+ if (opt_strings_flags(p_toolbar, p_toolbar_values,
+ &toolbar_flags, TRUE) != OK)
+ errmsg = e_invarg;
+ else
+ {
+ out_flush();
+ gui_mch_show_toolbar((toolbar_flags &
+ (TOOLBAR_TEXT | TOOLBAR_ICONS)) != 0);
+ }
+ }
+#endif
+
+#if defined(FEAT_TOOLBAR) && defined(FEAT_GUI_GTK)
+ /* 'toolbariconsize': GTK+ 2 only */
+ else if (varp == &p_tbis)
+ {
+ if (opt_strings_flags(p_tbis, p_tbis_values, &tbis_flags, FALSE) != OK)
+ errmsg = e_invarg;
+ else
+ {
+ out_flush();
+ gui_mch_show_toolbar((toolbar_flags &
+ (TOOLBAR_TEXT | TOOLBAR_ICONS)) != 0);
+ }
+ }
+#endif
+
+ /* 'pastetoggle': translate key codes like in a mapping */
+ else if (varp == &p_pt)
+ {
+ if (*p_pt)
+ {
+ (void)replace_termcodes(p_pt, &p, TRUE, TRUE, FALSE);
+ if (p != NULL)
+ {
+ if (new_value_alloced)
+ free_string_option(p_pt);
+ p_pt = p;
+ new_value_alloced = TRUE;
+ }
+ }
+ }
+
+ /* 'backspace' */
+ else if (varp == &p_bs)
+ {
+ if (VIM_ISDIGIT(*p_bs))
+ {
+ if (*p_bs > '2' || p_bs[1] != NUL)
+ errmsg = e_invarg;
+ }
+ else if (check_opt_strings(p_bs, p_bs_values, TRUE) != OK)
+ errmsg = e_invarg;
+ }
+ else if (varp == &p_bo)
+ {
+ if (opt_strings_flags(p_bo, p_bo_values, &bo_flags, TRUE) != OK)
+ errmsg = e_invarg;
+ }
+
+ /* 'tagcase' */
+ else if (gvarp == &p_tc)
+ {
+ unsigned int *flags;
+
+ if (opt_flags & OPT_LOCAL)
+ {
+ p = curbuf->b_p_tc;
+ flags = &curbuf->b_tc_flags;
+ }
+ else
+ {
+ p = p_tc;
+ flags = &tc_flags;
+ }
+
+ if ((opt_flags & OPT_LOCAL) && *p == NUL)
+ /* make the local value empty: use the global value */
+ *flags = 0;
+ else if (*p == NUL
+ || opt_strings_flags(p, p_tc_values, flags, FALSE) != OK)
+ errmsg = e_invarg;
+ }
+
+ /* 'casemap' */
+ else if (varp == &p_cmp)
+ {
+ if (opt_strings_flags(p_cmp, p_cmp_values, &cmp_flags, TRUE) != OK)
+ errmsg = e_invarg;
+ }
+
+#ifdef FEAT_DIFF
+ /* 'diffopt' */
+ else if (varp == &p_dip)
+ {
+ if (diffopt_changed() == FAIL)
+ errmsg = e_invarg;
+ }
+#endif
+
+#ifdef FEAT_FOLDING
+ /* 'foldmethod' */
+ else if (gvarp == &curwin->w_allbuf_opt.wo_fdm)
+ {
+ if (check_opt_strings(*varp, p_fdm_values, FALSE) != OK
+ || *curwin->w_p_fdm == NUL)
+ errmsg = e_invarg;
+ else
+ {
+ foldUpdateAll(curwin);
+ if (foldmethodIsDiff(curwin))
+ newFoldLevel();
+ }
+ }
+# ifdef FEAT_EVAL
+ /* 'foldexpr' */
+ else if (varp == &curwin->w_p_fde)
+ {
+ if (foldmethodIsExpr(curwin))
+ foldUpdateAll(curwin);
+ }
+# endif
+ /* 'foldmarker' */
+ else if (gvarp == &curwin->w_allbuf_opt.wo_fmr)
+ {
+ p = vim_strchr(*varp, ',');
+ if (p == NULL)
+ errmsg = N_("E536: comma required");
+ else if (p == *varp || p[1] == NUL)
+ errmsg = e_invarg;
+ else if (foldmethodIsMarker(curwin))
+ foldUpdateAll(curwin);
+ }
+ /* 'commentstring' */
+ else if (gvarp == &p_cms)
+ {
+ if (**varp != NUL && strstr((char *)*varp, "%s") == NULL)
+ errmsg = N_("E537: 'commentstring' must be empty or contain %s");
+ }
+ /* 'foldopen' */
+ else if (varp == &p_fdo)
+ {
+ if (opt_strings_flags(p_fdo, p_fdo_values, &fdo_flags, TRUE) != OK)
+ errmsg = e_invarg;
+ }
+ /* 'foldclose' */
+ else if (varp == &p_fcl)
+ {
+ if (check_opt_strings(p_fcl, p_fcl_values, TRUE) != OK)
+ errmsg = e_invarg;
+ }
+ /* 'foldignore' */
+ else if (gvarp == &curwin->w_allbuf_opt.wo_fdi)
+ {
+ if (foldmethodIsIndent(curwin))
+ foldUpdateAll(curwin);
+ }
+#endif
+
+ /* 'virtualedit' */
+ else if (varp == &p_ve)
+ {
+ if (opt_strings_flags(p_ve, p_ve_values, &ve_flags, TRUE) != OK)
+ errmsg = e_invarg;
+ else if (STRCMP(p_ve, oldval) != 0)
+ {
+ /* Recompute cursor position in case the new 've' setting
+ * changes something. */
+ validate_virtcol();
+ coladvance(curwin->w_virtcol);
+ }
+ }
+
+#if defined(FEAT_CSCOPE) && defined(FEAT_QUICKFIX)
+ else if (varp == &p_csqf)
+ {
+ if (p_csqf != NULL)
+ {
+ p = p_csqf;
+ while (*p != NUL)
+ {
+ if (vim_strchr((char_u *)CSQF_CMDS, *p) == NULL
+ || p[1] == NUL
+ || vim_strchr((char_u *)CSQF_FLAGS, p[1]) == NULL
+ || (p[2] != NUL && p[2] != ','))
+ {
+ errmsg = e_invarg;
+ break;
+ }
+ else if (p[2] == NUL)
+ break;
+ else
+ p += 3;
+ }
+ }
+ }
+#endif
+
+#ifdef FEAT_CINDENT
+ /* 'cinoptions' */
+ else if (gvarp == &p_cino)
+ {
+ /* TODO: recognize errors */
+ parse_cino(curbuf);
+ }
+#endif
+
+#if defined(FEAT_RENDER_OPTIONS)
+ /* 'renderoptions' */
+ else if (varp == &p_rop)
+ {
+ if (!gui_mch_set_rendering_options(p_rop))
+ errmsg = e_invarg;
+ }
+#endif
+
+ else if (gvarp == &p_ft)
+ {
+ if (!valid_filetype(*varp))
+ errmsg = e_invarg;
+ else
+ {
+ value_changed = STRCMP(oldval, *varp) != 0;
+
+ // Since we check the value, there is no need to set P_INSECURE,
+ // even when the value comes from a modeline.
+ *value_checked = TRUE;
+ }
+ }
+
+#ifdef FEAT_SYN_HL
+ else if (gvarp == &p_syn)
+ {
+ if (!valid_filetype(*varp))
+ errmsg = e_invarg;
+ else
+ {
+ value_changed = STRCMP(oldval, *varp) != 0;
+
+ // Since we check the value, there is no need to set P_INSECURE,
+ // even when the value comes from a modeline.
+ *value_checked = TRUE;
+ }
+ }
+#endif
+
+#ifdef FEAT_TERMINAL
+ // 'termwinkey'
+ else if (varp == &curwin->w_p_twk)
+ {
+ if (*curwin->w_p_twk != NUL
+ && string_to_key(curwin->w_p_twk, TRUE) == 0)
+ errmsg = e_invarg;
+ }
+ // 'termwinsize'
+ else if (varp == &curwin->w_p_tws)
+ {
+ if (*curwin->w_p_tws != NUL)
+ {
+ p = skipdigits(curwin->w_p_tws);
+ if (p == curwin->w_p_tws
+ || (*p != 'x' && *p != '*')
+ || *skipdigits(p + 1) != NUL)
+ errmsg = e_invarg;
+ }
+ }
+ // 'termmode'
+ else if (varp == &curwin->w_p_tmod)
+ {
+ if (check_opt_strings(*varp, p_tmod_values, FALSE) != OK)
+ errmsg = e_invarg;
+ }
+#endif
+
+#ifdef FEAT_VARTABS
+ /* 'varsofttabstop' */
+ else if (varp == &(curbuf->b_p_vsts))
+ {
+ char_u *cp;
+
+ if (!(*varp)[0] || ((*varp)[0] == '0' && !(*varp)[1]))
+ {
+ if (curbuf->b_p_vsts_array)
+ {
+ vim_free(curbuf->b_p_vsts_array);
+ curbuf->b_p_vsts_array = 0;
+ }
+ }
+ else
+ {
+ for (cp = *varp; *cp; ++cp)
+ {
+ if (vim_isdigit(*cp))
+ continue;
+ if (*cp == ',' && cp > *varp && *(cp-1) != ',')
+ continue;
+ errmsg = e_invarg;
+ break;
+ }
+ if (errmsg == NULL)
+ {
+ int *oldarray = curbuf->b_p_vsts_array;
+ if (tabstop_set(*varp, &(curbuf->b_p_vsts_array)))
+ {
+ if (oldarray)
+ vim_free(oldarray);
+ }
+ else
+ errmsg = e_invarg;
+ }
+ }
+ }
+
+ /* 'vartabstop' */
+ else if (varp == &(curbuf->b_p_vts))
+ {
+ char_u *cp;
+
+ if (!(*varp)[0] || ((*varp)[0] == '0' && !(*varp)[1]))
+ {
+ if (curbuf->b_p_vts_array)
+ {
+ vim_free(curbuf->b_p_vts_array);
+ curbuf->b_p_vts_array = NULL;
+ }
+ }
+ else
+ {
+ for (cp = *varp; *cp; ++cp)
+ {
+ if (vim_isdigit(*cp))
+ continue;
+ if (*cp == ',' && cp > *varp && *(cp-1) != ',')
+ continue;
+ errmsg = e_invarg;
+ break;
+ }
+ if (errmsg == NULL)
+ {
+ int *oldarray = curbuf->b_p_vts_array;
+ if (tabstop_set(*varp, &(curbuf->b_p_vts_array)))
+ {
+ if (oldarray)
+ vim_free(oldarray);
+#ifdef FEAT_FOLDING
+ if (foldmethodIsIndent(curwin))
+ foldUpdateAll(curwin);
+#endif /* FEAT_FOLDING */
+ }
+ else
+ errmsg = e_invarg;
+ }
+ }
+ }
+#endif
+
+ /* Options that are a list of flags. */
+ else
+ {
+ p = NULL;
+ if (varp == &p_ww) /* 'whichwrap' */
+ p = (char_u *)WW_ALL;
+ if (varp == &p_shm) /* 'shortmess' */
+ p = (char_u *)SHM_ALL;
+ else if (varp == &(p_cpo)) /* 'cpoptions' */
+ p = (char_u *)CPO_ALL;
+ else if (varp == &(curbuf->b_p_fo)) /* 'formatoptions' */
+ p = (char_u *)FO_ALL;
+#ifdef FEAT_CONCEAL
+ else if (varp == &curwin->w_p_cocu) /* 'concealcursor' */
+ p = (char_u *)COCU_ALL;
+#endif
+ else if (varp == &p_mouse) /* 'mouse' */
+ {
+#ifdef FEAT_MOUSE
+ p = (char_u *)MOUSE_ALL;
+#else
+ if (*p_mouse != NUL)
+ errmsg = N_("E538: No mouse support");
+#endif
+ }
+#if defined(FEAT_GUI)
+ else if (varp == &p_go) /* 'guioptions' */
+ p = (char_u *)GO_ALL;
+#endif
+ if (p != NULL)
+ {
+ for (s = *varp; *s; ++s)
+ if (vim_strchr(p, *s) == NULL)
+ {
+ errmsg = illegal_char(errbuf, *s);
+ break;
+ }
+ }
+ }
+
+ /*
+ * If error detected, restore the previous value.
+ */
+ if (errmsg != NULL)
+ {
+ if (new_value_alloced)
+ free_string_option(*varp);
+ *varp = oldval;
+ /*
+ * When resetting some values, need to act on it.
+ */
+ if (did_chartab)
+ (void)init_chartab();
+ if (varp == &p_hl)
+ (void)highlight_changed();
+ }
+ else
+ {
+#ifdef FEAT_EVAL
+ /* Remember where the option was set. */
+ set_option_sctx_idx(opt_idx, opt_flags, current_sctx);
+#endif
+ /*
+ * Free string options that are in allocated memory.
+ * Use "free_oldval", because recursiveness may change the flags under
+ * our fingers (esp. init_highlight()).
+ */
+ if (free_oldval)
+ free_string_option(oldval);
+ if (new_value_alloced)
+ options[opt_idx].flags |= P_ALLOCED;
+ else
+ options[opt_idx].flags &= ~P_ALLOCED;
+
+ if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0
+ && ((int)options[opt_idx].indir & PV_BOTH))
+ {
+ /* global option with local value set to use global value; free
+ * the local value and make it empty */
+ p = get_varp_scope(&(options[opt_idx]), OPT_LOCAL);
+ free_string_option(*(char_u **)p);
+ *(char_u **)p = empty_option;
+ }
+
+ /* May set global value for local option. */
+ else if (!(opt_flags & OPT_LOCAL) && opt_flags != OPT_GLOBAL)
+ set_string_option_global(opt_idx, varp);
+
+ /*
+ * Trigger the autocommand only after setting the flags.
+ */
+#ifdef FEAT_SYN_HL
+ /* When 'syntax' is set, load the syntax of that name */
+ if (varp == &(curbuf->b_p_syn))
+ {
+ static int syn_recursive = 0;
+
+ ++syn_recursive;
+ // Only pass TRUE for "force" when the value changed or not used
+ // recursively, to avoid endless recurrence.
+ apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn, curbuf->b_fname,
+ value_changed || syn_recursive == 1, curbuf);
+ --syn_recursive;
+ }
+#endif
+ else if (varp == &(curbuf->b_p_ft))
+ {
+ /* 'filetype' is set, trigger the FileType autocommand.
+ * Skip this when called from a modeline and the filetype was
+ * already set to this value. */
+ if (!(opt_flags & OPT_MODELINE) || value_changed)
+ {
+ static int ft_recursive = 0;
+ int secure_save = secure;
+
+ // Reset the secure flag, since the value of 'filetype' has
+ // been checked to be safe.
+ secure = 0;
+
+ ++ft_recursive;
+ did_filetype = TRUE;
+ // Only pass TRUE for "force" when the value changed or not
+ // used recursively, to avoid endless recurrence.
+ apply_autocmds(EVENT_FILETYPE, curbuf->b_p_ft, curbuf->b_fname,
+ value_changed || ft_recursive == 1, curbuf);
+ --ft_recursive;
+ /* Just in case the old "curbuf" is now invalid. */
+ if (varp != &(curbuf->b_p_ft))
+ varp = NULL;
+
+ secure = secure_save;
+ }
+ }
+#ifdef FEAT_SPELL
+ if (varp == &(curwin->w_s->b_p_spl))
+ {
+ char_u fname[200];
+ char_u *q = curwin->w_s->b_p_spl;
+
+ /* Skip the first name if it is "cjk". */
+ if (STRNCMP(q, "cjk,", 4) == 0)
+ q += 4;
+
+ /*
+ * Source the spell/LANG.vim in 'runtimepath'.
+ * They could set 'spellcapcheck' depending on the language.
+ * Use the first name in 'spelllang' up to '_region' or
+ * '.encoding'.
+ */
+ for (p = q; *p != NUL; ++p)
+ if (!ASCII_ISALNUM(*p) && *p != '-')
+ break;
+ if (p > q)
+ {
+ vim_snprintf((char *)fname, 200, "spell/%.*s.vim", (int)(p - q), q);
+ source_runtime(fname, DIP_ALL);
+ }
+ }
+#endif
+ }
+
+#ifdef FEAT_MOUSE
+ if (varp == &p_mouse)
+ {
+# ifdef FEAT_MOUSE_TTY
+ if (*p_mouse == NUL)
+ mch_setmouse(FALSE); /* switch mouse off */
+ else
+# endif
+ setmouse(); /* in case 'mouse' changed */
+ }
+#endif
+
+ if (curwin->w_curswant != MAXCOL
+ && (options[opt_idx].flags & (P_CURSWANT | P_RALL)) != 0)
+ curwin->w_set_curswant = TRUE;
+
+#ifdef FEAT_GUI
+ /* check redraw when it's not a GUI option or the GUI is active. */
+ if (!redraw_gui_only || gui.in_use)
+#endif
+ check_redraw(options[opt_idx].flags);
+
+#if defined(FEAT_VTP) && defined(FEAT_TERMGUICOLORS)
+ if (did_swaptcap)
+ {
+ set_termname((char_u *)"win32");
+ init_highlight(TRUE, FALSE);
+ }
+#endif
+
+ return errmsg;
+}
+
+#if defined(FEAT_SYN_HL) || defined(PROTO)
+/*
+ * Simple int comparison function for use with qsort()
+ */
+ static int
+int_cmp(const void *a, const void *b)
+{
+ return *(const int *)a - *(const int *)b;
+}
+
+/*
+ * Handle setting 'colorcolumn' or 'textwidth' in window "wp".
+ * Returns error message, NULL if it's OK.
+ */
+ char *
+check_colorcolumn(win_T *wp)
+{
+ char_u *s;
+ int col;
+ int count = 0;
+ int color_cols[256];
+ int i;
+ int j = 0;
+
+ if (wp->w_buffer == NULL)
+ return NULL; /* buffer was closed */
+
+ for (s = wp->w_p_cc; *s != NUL && count < 255;)
+ {
+ if (*s == '-' || *s == '+')
+ {
+ /* -N and +N: add to 'textwidth' */
+ col = (*s == '-') ? -1 : 1;
+ ++s;
+ if (!VIM_ISDIGIT(*s))
+ return e_invarg;
+ col = col * getdigits(&s);
+ if (wp->w_buffer->b_p_tw == 0)
+ goto skip; /* 'textwidth' not set, skip this item */
+ col += wp->w_buffer->b_p_tw;
+ if (col < 0)
+ goto skip;
+ }
+ else if (VIM_ISDIGIT(*s))
+ col = getdigits(&s);
+ else
+ return e_invarg;
+ color_cols[count++] = col - 1; /* 1-based to 0-based */
+skip:
+ if (*s == NUL)
+ break;
+ if (*s != ',')
+ return e_invarg;
+ if (*++s == NUL)
+ return e_invarg; /* illegal trailing comma as in "set cc=80," */
+ }
+
+ vim_free(wp->w_p_cc_cols);
+ if (count == 0)
+ wp->w_p_cc_cols = NULL;
+ else
+ {
+ wp->w_p_cc_cols = (int *)alloc((unsigned)sizeof(int) * (count + 1));
+ if (wp->w_p_cc_cols != NULL)
+ {
+ /* sort the columns for faster usage on screen redraw inside
+ * win_line() */
+ qsort(color_cols, count, sizeof(int), int_cmp);
+
+ for (i = 0; i < count; ++i)
+ /* skip duplicates */
+ if (j == 0 || wp->w_p_cc_cols[j - 1] != color_cols[i])
+ wp->w_p_cc_cols[j++] = color_cols[i];
+ wp->w_p_cc_cols[j] = -1; /* end marker */
+ }
+ }
+
+ return NULL; /* no error */
+}
+#endif
+
+/*
+ * Handle setting 'listchars' or 'fillchars'.
+ * Returns error message, NULL if it's OK.
+ */
+ static char *
+set_chars_option(char_u **varp)
+{
+ int round, i, len, entries;
+ char_u *p, *s;
+ int c1 = 0, c2 = 0, c3 = 0;
+ struct charstab
+ {
+ int *cp;
+ char *name;
+ };
+ static struct charstab filltab[] =
+ {
+ {&fill_stl, "stl"},
+ {&fill_stlnc, "stlnc"},
+ {&fill_vert, "vert"},
+ {&fill_fold, "fold"},
+ {&fill_diff, "diff"},
+ };
+ static struct charstab lcstab[] =
+ {
+ {&lcs_eol, "eol"},
+ {&lcs_ext, "extends"},
+ {&lcs_nbsp, "nbsp"},
+ {&lcs_prec, "precedes"},
+ {&lcs_space, "space"},
+ {&lcs_tab2, "tab"},
+ {&lcs_trail, "trail"},
+#ifdef FEAT_CONCEAL
+ {&lcs_conceal, "conceal"},
+#else
+ {NULL, "conceal"},
+#endif
+ };
+ struct charstab *tab;
+
+ if (varp == &p_lcs)
+ {
+ tab = lcstab;
+ entries = sizeof(lcstab) / sizeof(struct charstab);
+ }
+ else
+ {
+ tab = filltab;
+ entries = sizeof(filltab) / sizeof(struct charstab);
+ }
+
+ /* first round: check for valid value, second round: assign values */
+ for (round = 0; round <= 1; ++round)
+ {
+ if (round > 0)
+ {
+ /* After checking that the value is valid: set defaults: space for
+ * 'fillchars', NUL for 'listchars' */
+ for (i = 0; i < entries; ++i)
+ if (tab[i].cp != NULL)
+ *(tab[i].cp) = (varp == &p_lcs ? NUL : ' ');
+
+ if (varp == &p_lcs)
+ {
+ lcs_tab1 = NUL;
+ lcs_tab3 = NUL;
+ }
+ else
+ fill_diff = '-';
+ }
+ p = *varp;
+ while (*p)
+ {
+ for (i = 0; i < entries; ++i)
+ {
+ len = (int)STRLEN(tab[i].name);
+ if (STRNCMP(p, tab[i].name, len) == 0
+ && p[len] == ':'
+ && p[len + 1] != NUL)
+ {
+ c1 = c2 = c3 = 0;
+ s = p + len + 1;
+ c1 = mb_ptr2char_adv(&s);
+ if (mb_char2cells(c1) > 1)
+ continue;
+ if (tab[i].cp == &lcs_tab2)
+ {
+ if (*s == NUL)
+ continue;
+ c2 = mb_ptr2char_adv(&s);
+ if (mb_char2cells(c2) > 1)
+ continue;
+ if (!(*s == ',' || *s == NUL))
+ {
+ c3 = mb_ptr2char_adv(&s);
+ if (mb_char2cells(c3) > 1)
+ continue;
+ }
+ }
+
+ if (*s == ',' || *s == NUL)
+ {
+ if (round)
+ {
+ if (tab[i].cp == &lcs_tab2)
+ {
+ lcs_tab1 = c1;
+ lcs_tab2 = c2;
+ lcs_tab3 = c3;
+ }
+ else if (tab[i].cp != NULL)
+ *(tab[i].cp) = c1;
+
+ }
+ p = s;
+ break;
+ }
+ }
+ }
+
+ if (i == entries)
+ return e_invarg;
+ if (*p == ',')
+ ++p;
+ }
+ }
+
+ return NULL; /* no error */
+}
+
+#ifdef FEAT_STL_OPT
+/*
+ * Check validity of options with the 'statusline' format.
+ * Return error message or NULL.
+ */
+ char *
+check_stl_option(char_u *s)
+{
+ int itemcnt = 0;
+ int groupdepth = 0;
+ static char errbuf[80];
+
+ while (*s && itemcnt < STL_MAX_ITEM)
+ {
+ /* Check for valid keys after % sequences */
+ while (*s && *s != '%')
+ s++;
+ if (!*s)
+ break;
+ s++;
+ if (*s != '%' && *s != ')')
+ ++itemcnt;
+ if (*s == '%' || *s == STL_TRUNCMARK || *s == STL_MIDDLEMARK)
+ {
+ s++;
+ continue;
+ }
+ if (*s == ')')
+ {
+ s++;
+ if (--groupdepth < 0)
+ break;
+ continue;
+ }
+ if (*s == '-')
+ s++;
+ while (VIM_ISDIGIT(*s))
+ s++;
+ if (*s == STL_USER_HL)
+ continue;
+ if (*s == '.')
+ {
+ s++;
+ while (*s && VIM_ISDIGIT(*s))
+ s++;
+ }
+ if (*s == '(')
+ {
+ groupdepth++;
+ continue;
+ }
+ if (vim_strchr(STL_ALL, *s) == NULL)
+ {
+ return illegal_char(errbuf, *s);
+ }
+ if (*s == '{')
+ {
+ s++;
+ while (*s != '}' && *s)
+ s++;
+ if (*s != '}')
+ return N_("E540: Unclosed expression sequence");
+ }
+ }
+ if (itemcnt >= STL_MAX_ITEM)
+ return N_("E541: too many items");
+ if (groupdepth != 0)
+ return N_("E542: unbalanced groups");
+ return NULL;
+}
+#endif
+
+#ifdef FEAT_CLIPBOARD
+/*
+ * Extract the items in the 'clipboard' option and set global values.
+ * Return an error message or NULL for success.
+ */
+ static char *
+check_clipboard_option(void)
+{
+ int new_unnamed = 0;
+ int new_autoselect_star = FALSE;
+ int new_autoselect_plus = FALSE;
+ int new_autoselectml = FALSE;
+ int new_html = FALSE;
+ regprog_T *new_exclude_prog = NULL;
+ char *errmsg = NULL;
+ char_u *p;
+
+ for (p = p_cb; *p != NUL; )
+ {
+ if (STRNCMP(p, "unnamed", 7) == 0 && (p[7] == ',' || p[7] == NUL))
+ {
+ new_unnamed |= CLIP_UNNAMED;
+ p += 7;
+ }
+ else if (STRNCMP(p, "unnamedplus", 11) == 0
+ && (p[11] == ',' || p[11] == NUL))
+ {
+ new_unnamed |= CLIP_UNNAMED_PLUS;
+ p += 11;
+ }
+ else if (STRNCMP(p, "autoselect", 10) == 0
+ && (p[10] == ',' || p[10] == NUL))
+ {
+ new_autoselect_star = TRUE;
+ p += 10;
+ }
+ else if (STRNCMP(p, "autoselectplus", 14) == 0
+ && (p[14] == ',' || p[14] == NUL))
+ {
+ new_autoselect_plus = TRUE;
+ p += 14;
+ }
+ else if (STRNCMP(p, "autoselectml", 12) == 0
+ && (p[12] == ',' || p[12] == NUL))
+ {
+ new_autoselectml = TRUE;
+ p += 12;
+ }
+ else if (STRNCMP(p, "html", 4) == 0 && (p[4] == ',' || p[4] == NUL))
+ {
+ new_html = TRUE;
+ p += 4;
+ }
+ else if (STRNCMP(p, "exclude:", 8) == 0 && new_exclude_prog == NULL)
+ {
+ p += 8;
+ new_exclude_prog = vim_regcomp(p, RE_MAGIC);
+ if (new_exclude_prog == NULL)
+ errmsg = e_invarg;
+ break;
+ }
+ else
+ {
+ errmsg = e_invarg;
+ break;
+ }
+ if (*p == ',')
+ ++p;
+ }
+ if (errmsg == NULL)
+ {
+ clip_unnamed = new_unnamed;
+ clip_autoselect_star = new_autoselect_star;
+ clip_autoselect_plus = new_autoselect_plus;
+ clip_autoselectml = new_autoselectml;
+ clip_html = new_html;
+ vim_regfree(clip_exclude_prog);
+ clip_exclude_prog = new_exclude_prog;
+#ifdef FEAT_GUI_GTK
+ if (gui.in_use)
+ {
+ gui_gtk_set_selection_targets();
+ gui_gtk_set_dnd_targets();
+ }
+#endif
+ }
+ else
+ vim_regfree(new_exclude_prog);
+
+ return errmsg;
+}
+#endif
+
+#ifdef FEAT_SPELL
+/*
+ * Handle side effects of setting 'spell'.
+ * Return an error message or NULL for success.
+ */
+ static char *
+did_set_spell_option(int is_spellfile)
+{
+ char *errmsg = NULL;
+ win_T *wp;
+ int l;
+
+ if (is_spellfile)
+ {
+ l = (int)STRLEN(curwin->w_s->b_p_spf);
+ if (l > 0 && (l < 4
+ || STRCMP(curwin->w_s->b_p_spf + l - 4, ".add") != 0))
+ errmsg = e_invarg;
+ }
+
+ if (errmsg == NULL)
+ {
+ FOR_ALL_WINDOWS(wp)
+ if (wp->w_buffer == curbuf && wp->w_p_spell)
+ {
+ errmsg = did_set_spelllang(wp);
+ break;
+ }
+ }
+ return errmsg;
+}
+
+/*
+ * Set curbuf->b_cap_prog to the regexp program for 'spellcapcheck'.
+ * Return error message when failed, NULL when OK.
+ */
+ static char *
+compile_cap_prog(synblock_T *synblock)
+{
+ regprog_T *rp = synblock->b_cap_prog;
+ char_u *re;
+
+ if (*synblock->b_p_spc == NUL)
+ synblock->b_cap_prog = NULL;
+ else
+ {
+ /* Prepend a ^ so that we only match at one column */
+ re = concat_str((char_u *)"^", synblock->b_p_spc);
+ if (re != NULL)
+ {
+ synblock->b_cap_prog = vim_regcomp(re, RE_MAGIC);
+ vim_free(re);
+ if (synblock->b_cap_prog == NULL)
+ {
+ synblock->b_cap_prog = rp; /* restore the previous program */
+ return e_invarg;
+ }
+ }
+ }
+
+ vim_regfree(rp);
+ return NULL;
+}
+#endif
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * Set the script_ctx for an option, taking care of setting the buffer- or
+ * window-local value.
+ */
+ static void
+set_option_sctx_idx(int opt_idx, int opt_flags, sctx_T script_ctx)
+{
+ int both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0;
+ int indir = (int)options[opt_idx].indir;
+ sctx_T new_script_ctx = script_ctx;
+
+ new_script_ctx.sc_lnum += sourcing_lnum;
+
+ /* Remember where the option was set. For local options need to do that
+ * in the buffer or window structure. */
+ if (both || (opt_flags & OPT_GLOBAL) || (indir & (PV_BUF|PV_WIN)) == 0)
+ options[opt_idx].script_ctx = new_script_ctx;
+ if (both || (opt_flags & OPT_LOCAL))
+ {
+ if (indir & PV_BUF)
+ curbuf->b_p_script_ctx[indir & PV_MASK] = new_script_ctx;
+ else if (indir & PV_WIN)
+ curwin->w_p_script_ctx[indir & PV_MASK] = new_script_ctx;
+ }
+}
+
+/*
+ * Set the script_ctx for a termcap option.
+ * "name" must be the two character code, e.g. "RV".
+ * When "name" is NULL use "opt_idx".
+ */
+ void
+set_term_option_sctx_idx(char *name, int opt_idx)
+{
+ char_u buf[5];
+ int idx;
+
+ if (name == NULL)
+ idx = opt_idx;
+ else
+ {
+ buf[0] = 't';
+ buf[1] = '_';
+ buf[2] = name[0];
+ buf[3] = name[1];
+ buf[4] = 0;
+ idx = findoption(buf);
+ }
+ if (idx >= 0)
+ set_option_sctx_idx(idx, OPT_GLOBAL, current_sctx);
+}
+#endif
+
+/*
+ * Set the value of a boolean option, and take care of side effects.
+ * Returns NULL for success, or an error message for an error.
+ */
+ static char *
+set_bool_option(
+ int opt_idx, /* index in options[] table */
+ char_u *varp, /* pointer to the option variable */
+ int value, /* new value */
+ int opt_flags) /* OPT_LOCAL and/or OPT_GLOBAL */
+{
+ int old_value = *(int *)varp;
+
+ /* Disallow changing some options from secure mode */
+ if ((secure
+#ifdef HAVE_SANDBOX
+ || sandbox != 0
+#endif
+ ) && (options[opt_idx].flags & P_SECURE))
+ return e_secure;
+
+ *(int *)varp = value; /* set the new value */
+#ifdef FEAT_EVAL
+ /* Remember where the option was set. */
+ set_option_sctx_idx(opt_idx, opt_flags, current_sctx);
+#endif
+
+#ifdef FEAT_GUI
+ need_mouse_correct = TRUE;
+#endif
+
+ /* May set global value for local option. */
+ if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0)
+ *(int *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL) = value;
+
+ /*
+ * Handle side effects of changing a bool option.
+ */
+
+ /* 'compatible' */
+ if ((int *)varp == &p_cp)
+ {
+ compatible_set();
+ }
+
+#ifdef FEAT_LANGMAP
+ if ((int *)varp == &p_lrm)
+ /* 'langremap' -> !'langnoremap' */
+ p_lnr = !p_lrm;
+ else if ((int *)varp == &p_lnr)
+ /* 'langnoremap' -> !'langremap' */
+ p_lrm = !p_lnr;
+#endif
+
+#ifdef FEAT_SYN_HL
+ else if ((int *)varp == &curwin->w_p_cul && !value && old_value)
+ reset_cursorline();
+#endif
+
+#ifdef FEAT_PERSISTENT_UNDO
+ /* 'undofile' */
+ else if ((int *)varp == &curbuf->b_p_udf || (int *)varp == &p_udf)
+ {
+ /* Only take action when the option was set. When reset we do not
+ * delete the undo file, the option may be set again without making
+ * any changes in between. */
+ if (curbuf->b_p_udf || p_udf)
+ {
+ char_u hash[UNDO_HASH_SIZE];
+ buf_T *save_curbuf = curbuf;
+
+ FOR_ALL_BUFFERS(curbuf)
+ {
+ /* When 'undofile' is set globally: for every buffer, otherwise
+ * only for the current buffer: Try to read in the undofile,
+ * if one exists, the buffer wasn't changed and the buffer was
+ * loaded */
+ if ((curbuf == save_curbuf
+ || (opt_flags & OPT_GLOBAL) || opt_flags == 0)
+ && !curbufIsChanged() && curbuf->b_ml.ml_mfp != NULL)
+ {
+ u_compute_hash(hash);
+ u_read_undo(NULL, hash, curbuf->b_fname);
+ }
+ }
+ curbuf = save_curbuf;
+ }
+ }
+#endif
+
+ else if ((int *)varp == &curbuf->b_p_ro)
+ {
+ /* when 'readonly' is reset globally, also reset readonlymode */
+ if (!curbuf->b_p_ro && (opt_flags & OPT_LOCAL) == 0)
+ readonlymode = FALSE;
+
+ /* when 'readonly' is set may give W10 again */
+ if (curbuf->b_p_ro)
+ curbuf->b_did_warn = FALSE;
+
+#ifdef FEAT_TITLE
+ redraw_titles();
+#endif
+ }
+
+#ifdef FEAT_GUI
+ else if ((int *)varp == &p_mh)
+ {
+ if (!p_mh)
+ gui_mch_mousehide(FALSE);
+ }
+#endif
+
+ /* when 'modifiable' is changed, redraw the window title */
+ else if ((int *)varp == &curbuf->b_p_ma)
+ {
+# ifdef FEAT_TERMINAL
+ /* Cannot set 'modifiable' when in Terminal mode. */
+ if (curbuf->b_p_ma && (term_in_normal_mode() || (bt_terminal(curbuf)
+ && curbuf->b_term != NULL && !term_is_finished(curbuf))))
+ {
+ curbuf->b_p_ma = FALSE;
+ return N_("E946: Cannot make a terminal with running job modifiable");
+ }
+# endif
+# ifdef FEAT_TITLE
+ redraw_titles();
+# endif
+ }
+#ifdef FEAT_TITLE
+ /* when 'endofline' is changed, redraw the window title */
+ else if ((int *)varp == &curbuf->b_p_eol)
+ {
+ redraw_titles();
+ }
+ /* when 'fixeol' is changed, redraw the window title */
+ else if ((int *)varp == &curbuf->b_p_fixeol)
+ {
+ redraw_titles();
+ }
+ /* when 'bomb' is changed, redraw the window title and tab page text */
+ else if ((int *)varp == &curbuf->b_p_bomb)
+ {
+ redraw_titles();
+ }
+#endif
+
+ /* when 'bin' is set also set some other options */
+ else if ((int *)varp == &curbuf->b_p_bin)
+ {
+ set_options_bin(old_value, curbuf->b_p_bin, opt_flags);
+#ifdef FEAT_TITLE
+ redraw_titles();
+#endif
+ }
+
+ /* when 'buflisted' changes, trigger autocommands */
+ else if ((int *)varp == &curbuf->b_p_bl && old_value != curbuf->b_p_bl)
+ {
+ apply_autocmds(curbuf->b_p_bl ? EVENT_BUFADD : EVENT_BUFDELETE,
+ NULL, NULL, TRUE, curbuf);
+ }
+
+ /* when 'swf' is set, create swapfile, when reset remove swapfile */
+ else if ((int *)varp == &curbuf->b_p_swf)
+ {
+ if (curbuf->b_p_swf && p_uc)
+ ml_open_file(curbuf); /* create the swap file */
+ else
+ /* no need to reset curbuf->b_may_swap, ml_open_file() will check
+ * buf->b_p_swf */
+ mf_close_file(curbuf, TRUE); /* remove the swap file */
+ }
+
+ /* when 'terse' is set change 'shortmess' */
+ else if ((int *)varp == &p_terse)
+ {
+ char_u *p;
+
+ p = vim_strchr(p_shm, SHM_SEARCH);
+
+ /* insert 's' in p_shm */
+ if (p_terse && p == NULL)
+ {
+ STRCPY(IObuff, p_shm);
+ STRCAT(IObuff, "s");
+ set_string_option_direct((char_u *)"shm", -1, IObuff, OPT_FREE, 0);
+ }
+ /* remove 's' from p_shm */
+ else if (!p_terse && p != NULL)
+ STRMOVE(p, p + 1);
+ }
+
+ /* when 'paste' is set or reset also change other options */
+ else if ((int *)varp == &p_paste)
+ {
+ paste_option_changed();
+ }
+
+ /* when 'insertmode' is set from an autocommand need to do work here */
+ else if ((int *)varp == &p_im)
+ {
+ if (p_im)
+ {
+ if ((State & INSERT) == 0)
+ need_start_insertmode = TRUE;
+ stop_insert_mode = FALSE;
+ }
+ /* only reset if it was set previously */
+ else if (old_value)
+ {
+ need_start_insertmode = FALSE;
+ stop_insert_mode = TRUE;
+ if (restart_edit != 0 && mode_displayed)
+ clear_cmdline = TRUE; /* remove "(insert)" */
+ restart_edit = 0;
+ }
+ }
+
+ /* when 'ignorecase' is set or reset and 'hlsearch' is set, redraw */
+ else if ((int *)varp == &p_ic && p_hls)
+ {
+ redraw_all_later(SOME_VALID);
+ }
+
+#ifdef FEAT_SEARCH_EXTRA
+ /* when 'hlsearch' is set or reset: reset no_hlsearch */
+ else if ((int *)varp == &p_hls)
+ {
+ set_no_hlsearch(FALSE);
+ }
+#endif
+
+ /* when 'scrollbind' is set: snapshot the current position to avoid a jump
+ * at the end of normal_cmd() */
+ else if ((int *)varp == &curwin->w_p_scb)
+ {
+ if (curwin->w_p_scb)
+ {
+ do_check_scrollbind(FALSE);
+ curwin->w_scbind_pos = curwin->w_topline;
+ }
+ }
+
+#if defined(FEAT_QUICKFIX)
+ /* There can be only one window with 'previewwindow' set. */
+ else if ((int *)varp == &curwin->w_p_pvw)
+ {
+ if (curwin->w_p_pvw)
+ {
+ win_T *win;
+
+ FOR_ALL_WINDOWS(win)
+ if (win->w_p_pvw && win != curwin)
+ {
+ curwin->w_p_pvw = FALSE;
+ return N_("E590: A preview window already exists");
+ }
+ }
+ }
+#endif
+
+ /* when 'textmode' is set or reset also change 'fileformat' */
+ else if ((int *)varp == &curbuf->b_p_tx)
+ {
+ set_fileformat(curbuf->b_p_tx ? EOL_DOS : EOL_UNIX, opt_flags);
+ }
+
+ /* when 'textauto' is set or reset also change 'fileformats' */
+ else if ((int *)varp == &p_ta)
+ set_string_option_direct((char_u *)"ffs", -1,
+ p_ta ? (char_u *)DFLT_FFS_VIM : (char_u *)"",
+ OPT_FREE | opt_flags, 0);
+
+ /*
+ * When 'lisp' option changes include/exclude '-' in
+ * keyword characters.
+ */
+#ifdef FEAT_LISP
+ else if (varp == (char_u *)&(curbuf->b_p_lisp))
+ {
+ (void)buf_init_chartab(curbuf, FALSE); /* ignore errors */
+ }
+#endif
+
+#ifdef FEAT_TITLE
+ /* when 'title' changed, may need to change the title; same for 'icon' */
+ else if ((int *)varp == &p_title || (int *)varp == &p_icon)
+ {
+ did_set_title();
+ }
+#endif
+
+ else if ((int *)varp == &curbuf->b_changed)
+ {
+ if (!value)
+ save_file_ff(curbuf); /* Buffer is unchanged */
+#ifdef FEAT_TITLE
+ redraw_titles();
+#endif
+ modified_was_set = value;
+ }
+
+#ifdef BACKSLASH_IN_FILENAME
+ else if ((int *)varp == &p_ssl)
+ {
+ if (p_ssl)
+ {
+ psepc = '/';
+ psepcN = '\\';
+ pseps[0] = '/';
+ }
+ else
+ {
+ psepc = '\\';
+ psepcN = '/';
+ pseps[0] = '\\';
+ }
+
+ /* need to adjust the file name arguments and buffer names. */
+ buflist_slash_adjust();
+ alist_slash_adjust();
+# ifdef FEAT_EVAL
+ scriptnames_slash_adjust();
+# endif
+ }
+#endif
+
+ /* If 'wrap' is set, set w_leftcol to zero. */
+ else if ((int *)varp == &curwin->w_p_wrap)
+ {
+ if (curwin->w_p_wrap)
+ curwin->w_leftcol = 0;
+ }
+
+ else if ((int *)varp == &p_ea)
+ {
+ if (p_ea && !old_value)
+ win_equal(curwin, FALSE, 0);
+ }
+
+ else if ((int *)varp == &p_wiv)
+ {
+ /*
+ * When 'weirdinvert' changed, set/reset 't_xs'.
+ * Then set 'weirdinvert' according to value of 't_xs'.
+ */
+ if (p_wiv && !old_value)
+ T_XS = (char_u *)"y";
+ else if (!p_wiv && old_value)
+ T_XS = empty_option;
+ p_wiv = (*T_XS != NUL);
+ }
+
+#ifdef FEAT_BEVAL_GUI
+ else if ((int *)varp == &p_beval)
+ {
+ if (!balloonEvalForTerm)
+ {
+ if (p_beval && !old_value)
+ gui_mch_enable_beval_area(balloonEval);
+ else if (!p_beval && old_value)
+ gui_mch_disable_beval_area(balloonEval);
+ }
+ }
+#endif
+#ifdef FEAT_BEVAL_TERM
+ else if ((int *)varp == &p_bevalterm)
+ {
+ mch_bevalterm_changed();
+ }
+#endif
+
+#ifdef FEAT_AUTOCHDIR
+ else if ((int *)varp == &p_acd)
+ {
+ /* Change directories when the 'acd' option is set now. */
+ DO_AUTOCHDIR;
+ }
+#endif
+
+#ifdef FEAT_DIFF
+ /* 'diff' */
+ else if ((int *)varp == &curwin->w_p_diff)
+ {
+ /* May add or remove the buffer from the list of diff buffers. */
+ diff_buf_adjust(curwin);
+# ifdef FEAT_FOLDING
+ if (foldmethodIsDiff(curwin))
+ foldUpdateAll(curwin);
+# endif
+ }
+#endif
+
+#ifdef HAVE_INPUT_METHOD
+ /* 'imdisable' */
+ else if ((int *)varp == &p_imdisable)
+ {
+ /* Only de-activate it here, it will be enabled when changing mode. */
+ if (p_imdisable)
+ im_set_active(FALSE);
+ else if (State & INSERT)
+ /* When the option is set from an autocommand, it may need to take
+ * effect right away. */
+ im_set_active(curbuf->b_p_iminsert == B_IMODE_IM);
+ }
+#endif
+
+#ifdef FEAT_SPELL
+ /* 'spell' */
+ else if ((int *)varp == &curwin->w_p_spell)
+ {
+ if (curwin->w_p_spell)
+ {
+ char *errmsg = did_set_spelllang(curwin);
+
+ if (errmsg != NULL)
+ emsg(_(errmsg));
+ }
+ }
+#endif
+
+#ifdef FEAT_FKMAP
+ else if ((int *)varp == &p_altkeymap)
+ {
+ if (old_value != p_altkeymap)
+ {
+ if (!p_altkeymap)
+ {
+ p_hkmap = p_fkmap;
+ p_fkmap = 0;
+ }
+ else
+ {
+ p_fkmap = p_hkmap;
+ p_hkmap = 0;
+ }
+ (void)init_chartab();
+ }
+ }
+
+ /*
+ * In case some second language keymapping options have changed, check
+ * and correct the setting in a consistent way.
+ */
+
+ /*
+ * If hkmap or fkmap are set, reset Arabic keymapping.
+ */
+ if ((p_hkmap || p_fkmap) && p_altkeymap)
+ {
+ p_altkeymap = p_fkmap;
+# ifdef FEAT_ARABIC
+ curwin->w_p_arab = FALSE;
+# endif
+ (void)init_chartab();
+ }
+
+ /*
+ * If hkmap set, reset Farsi keymapping.
+ */
+ if (p_hkmap && p_altkeymap)
+ {
+ p_altkeymap = 0;
+ p_fkmap = 0;
+# ifdef FEAT_ARABIC
+ curwin->w_p_arab = FALSE;
+# endif
+ (void)init_chartab();
+ }
+
+ /*
+ * If fkmap set, reset Hebrew keymapping.
+ */
+ if (p_fkmap && !p_altkeymap)
+ {
+ p_altkeymap = 1;
+ p_hkmap = 0;
+# ifdef FEAT_ARABIC
+ curwin->w_p_arab = FALSE;
+# endif
+ (void)init_chartab();
+ }
+#endif
+
+#ifdef FEAT_ARABIC
+ if ((int *)varp == &curwin->w_p_arab)
+ {
+ if (curwin->w_p_arab)
+ {
+ /*
+ * 'arabic' is set, handle various sub-settings.
+ */
+ if (!p_tbidi)
+ {
+ /* set rightleft mode */
+ if (!curwin->w_p_rl)
+ {
+ curwin->w_p_rl = TRUE;
+ changed_window_setting();
+ }
+
+ /* Enable Arabic shaping (major part of what Arabic requires) */
+ if (!p_arshape)
+ {
+ p_arshape = TRUE;
+ redraw_later_clear();
+ }
+ }
+
+ /* Arabic requires a utf-8 encoding, inform the user if its not
+ * set. */
+ if (STRCMP(p_enc, "utf-8") != 0)
+ {
+ static char *w_arabic = N_("W17: Arabic requires UTF-8, do ':set encoding=utf-8'");
+
+ msg_source(HL_ATTR(HLF_W));
+ msg_attr(_(w_arabic), HL_ATTR(HLF_W));
+#ifdef FEAT_EVAL
+ set_vim_var_string(VV_WARNINGMSG, (char_u *)_(w_arabic), -1);
+#endif
+ }
+
+ /* set 'delcombine' */
+ p_deco = TRUE;
+
+# ifdef FEAT_KEYMAP
+ /* Force-set the necessary keymap for arabic */
+ set_option_value((char_u *)"keymap", 0L, (char_u *)"arabic",
+ OPT_LOCAL);
+# endif
+# ifdef FEAT_FKMAP
+ p_altkeymap = 0;
+ p_hkmap = 0;
+ p_fkmap = 0;
+ (void)init_chartab();
+# endif
+ }
+ else
+ {
+ /*
+ * 'arabic' is reset, handle various sub-settings.
+ */
+ if (!p_tbidi)
+ {
+ /* reset rightleft mode */
+ if (curwin->w_p_rl)
+ {
+ curwin->w_p_rl = FALSE;
+ changed_window_setting();
+ }
+
+ /* 'arabicshape' isn't reset, it is a global option and
+ * another window may still need it "on". */
+ }
+
+ /* 'delcombine' isn't reset, it is a global option and another
+ * window may still want it "on". */
+
+# ifdef FEAT_KEYMAP
+ /* Revert to the default keymap */
+ curbuf->b_p_iminsert = B_IMODE_NONE;
+ curbuf->b_p_imsearch = B_IMODE_USE_INSERT;
+# endif
+ }
+ }
+
+#endif
+
+#ifdef FEAT_TERMGUICOLORS
+ /* 'termguicolors' */
+ else if ((int *)varp == &p_tgc)
+ {
+# ifdef FEAT_VTP
+ /* Do not turn on 'tgc' when 24-bit colors are not supported. */
+ if (!has_vtp_working())
+ {
+ p_tgc = 0;
+ return N_("E954: 24-bit colors are not supported on this environment");
+ }
+ if (is_term_win32())
+ swap_tcap();
+# endif
+# ifdef FEAT_GUI
+ if (!gui.in_use && !gui.starting)
+# endif
+ highlight_gui_started();
+# ifdef FEAT_VTP
+ /* reset t_Co */
+ if (is_term_win32())
+ {
+ control_console_color_rgb();
+ set_termname(T_NAME);
+ init_highlight(TRUE, FALSE);
+ }
+# endif
+ }
+#endif
+
+ /*
+ * End of handling side effects for bool options.
+ */
+
+ /* after handling side effects, call autocommand */
+
+ options[opt_idx].flags |= P_WAS_SET;
+
+#if defined(FEAT_EVAL)
+ // Don't do this while starting up or recursively.
+ if (!starting && *get_vim_var_str(VV_OPTION_TYPE) == NUL)
+ {
+ char_u buf_old[2], buf_new[2], buf_type[7];
+
+ vim_snprintf((char *)buf_old, 2, "%d", old_value ? TRUE: FALSE);
+ vim_snprintf((char *)buf_new, 2, "%d", value ? TRUE: FALSE);
+ vim_snprintf((char *)buf_type, 7, "%s", (opt_flags & OPT_LOCAL) ? "local" : "global");
+ set_vim_var_string(VV_OPTION_NEW, buf_new, -1);
+ set_vim_var_string(VV_OPTION_OLD, buf_old, -1);
+ set_vim_var_string(VV_OPTION_TYPE, buf_type, -1);
+ apply_autocmds(EVENT_OPTIONSET, (char_u *) options[opt_idx].fullname, NULL, FALSE, NULL);
+ reset_v_option_vars();
+ }
+#endif
+
+ comp_col(); /* in case 'ruler' or 'showcmd' changed */
+ if (curwin->w_curswant != MAXCOL
+ && (options[opt_idx].flags & (P_CURSWANT | P_RALL)) != 0)
+ curwin->w_set_curswant = TRUE;
+ check_redraw(options[opt_idx].flags);
+
+ return NULL;
+}
+
+/*
+ * Set the value of a number option, and take care of side effects.
+ * Returns NULL for success, or an error message for an error.
+ */
+ static char *
+set_num_option(
+ int opt_idx, /* index in options[] table */
+ char_u *varp, /* pointer to the option variable */
+ long value, /* new value */
+ char *errbuf, /* buffer for error messages */
+ size_t errbuflen, /* length of "errbuf" */
+ int opt_flags) /* OPT_LOCAL, OPT_GLOBAL and
+ OPT_MODELINE */
+{
+ char *errmsg = NULL;
+ long old_value = *(long *)varp;
+ long old_Rows = Rows; /* remember old Rows */
+ long old_Columns = Columns; /* remember old Columns */
+ long *pp = (long *)varp;
+
+ /* Disallow changing some options from secure mode. */
+ if ((secure
+#ifdef HAVE_SANDBOX
+ || sandbox != 0
+#endif
+ ) && (options[opt_idx].flags & P_SECURE))
+ return e_secure;
+
+ *pp = value;
+#ifdef FEAT_EVAL
+ /* Remember where the option was set. */
+ set_option_sctx_idx(opt_idx, opt_flags, current_sctx);
+#endif
+#ifdef FEAT_GUI
+ need_mouse_correct = TRUE;
+#endif
+
+ if (curbuf->b_p_sw < 0)
+ {
+ errmsg = e_positive;
+#ifdef FEAT_VARTABS
+ // Use the first 'vartabstop' value, or 'tabstop' if vts isn't in use.
+ curbuf->b_p_sw = tabstop_count(curbuf->b_p_vts_array) > 0
+ ? tabstop_first(curbuf->b_p_vts_array)
+ : curbuf->b_p_ts;
+#else
+ curbuf->b_p_sw = curbuf->b_p_ts;
+#endif
+ }
+
+ /*
+ * Number options that need some action when changed
+ */
+ if (pp == &p_wh || pp == &p_hh)
+ {
+ // 'winheight' and 'helpheight'
+ if (p_wh < 1)
+ {
+ errmsg = e_positive;
+ p_wh = 1;
+ }
+ if (p_wmh > p_wh)
+ {
+ errmsg = e_winheight;
+ p_wh = p_wmh;
+ }
+ if (p_hh < 0)
+ {
+ errmsg = e_positive;
+ p_hh = 0;
+ }
+
+ /* Change window height NOW */
+ if (!ONE_WINDOW)
+ {
+ if (pp == &p_wh && curwin->w_height < p_wh)
+ win_setheight((int)p_wh);
+ if (pp == &p_hh && curbuf->b_help && curwin->w_height < p_hh)
+ win_setheight((int)p_hh);
+ }
+ }
+ else if (pp == &p_wmh)
+ {
+ // 'winminheight'
+ if (p_wmh < 0)
+ {
+ errmsg = e_positive;
+ p_wmh = 0;
+ }
+ if (p_wmh > p_wh)
+ {
+ errmsg = e_winheight;
+ p_wmh = p_wh;
+ }
+ win_setminheight();
+ }
+ else if (pp == &p_wiw)
+ {
+ // 'winwidth'
+ if (p_wiw < 1)
+ {
+ errmsg = e_positive;
+ p_wiw = 1;
+ }
+ if (p_wmw > p_wiw)
+ {
+ errmsg = e_winwidth;
+ p_wiw = p_wmw;
+ }
+
+ /* Change window width NOW */
+ if (!ONE_WINDOW && curwin->w_width < p_wiw)
+ win_setwidth((int)p_wiw);
+ }
+ else if (pp == &p_wmw)
+ {
+ // 'winminwidth'
+ if (p_wmw < 0)
+ {
+ errmsg = e_positive;
+ p_wmw = 0;
+ }
+ if (p_wmw > p_wiw)
+ {
+ errmsg = e_winwidth;
+ p_wmw = p_wiw;
+ }
+ win_setminwidth();
+ }
+
+ /* (re)set last window status line */
+ else if (pp == &p_ls)
+ {
+ last_status(FALSE);
+ }
+
+ /* (re)set tab page line */
+ else if (pp == &p_stal)
+ {
+ shell_new_rows(); /* recompute window positions and heights */
+ }
+
+#ifdef FEAT_GUI
+ else if (pp == &p_linespace)
+ {
+ /* Recompute gui.char_height and resize the Vim window to keep the
+ * same number of lines. */
+ if (gui.in_use && gui_mch_adjust_charheight() == OK)
+ gui_set_shellsize(FALSE, FALSE, RESIZE_VERT);
+ }
+#endif
+
+#ifdef FEAT_FOLDING
+ /* 'foldlevel' */
+ else if (pp == &curwin->w_p_fdl)
+ {
+ if (curwin->w_p_fdl < 0)
+ curwin->w_p_fdl = 0;
+ newFoldLevel();
+ }
+
+ /* 'foldminlines' */
+ else if (pp == &curwin->w_p_fml)
+ {
+ foldUpdateAll(curwin);
+ }
+
+ /* 'foldnestmax' */
+ else if (pp == &curwin->w_p_fdn)
+ {
+ if (foldmethodIsSyntax(curwin) || foldmethodIsIndent(curwin))
+ foldUpdateAll(curwin);
+ }
+
+ /* 'foldcolumn' */
+ else if (pp == &curwin->w_p_fdc)
+ {
+ if (curwin->w_p_fdc < 0)
+ {
+ errmsg = e_positive;
+ curwin->w_p_fdc = 0;
+ }
+ else if (curwin->w_p_fdc > 12)
+ {
+ errmsg = e_invarg;
+ curwin->w_p_fdc = 12;
+ }
+ }
+#endif /* FEAT_FOLDING */
+
+#if defined(FEAT_FOLDING) || defined(FEAT_CINDENT)
+ /* 'shiftwidth' or 'tabstop' */
+ else if (pp == &curbuf->b_p_sw || pp == &curbuf->b_p_ts)
+ {
+# ifdef FEAT_FOLDING
+ if (foldmethodIsIndent(curwin))
+ foldUpdateAll(curwin);
+# endif
+# ifdef FEAT_CINDENT
+ /* When 'shiftwidth' changes, or it's zero and 'tabstop' changes:
+ * parse 'cinoptions'. */
+ if (pp == &curbuf->b_p_sw || curbuf->b_p_sw == 0)
+ parse_cino(curbuf);
+# endif
+ }
+#endif
+
+ /* 'maxcombine' */
+ else if (pp == &p_mco)
+ {
+ if (p_mco > MAX_MCO)
+ p_mco = MAX_MCO;
+ else if (p_mco < 0)
+ p_mco = 0;
+ screenclear(); /* will re-allocate the screen */
+ }
+
+ else if (pp == &curbuf->b_p_iminsert)
+ {
+ if (curbuf->b_p_iminsert < 0 || curbuf->b_p_iminsert > B_IMODE_LAST)
+ {
+ errmsg = e_invarg;
+ curbuf->b_p_iminsert = B_IMODE_NONE;
+ }
+ p_iminsert = curbuf->b_p_iminsert;
+ if (termcap_active) /* don't do this in the alternate screen */
+ showmode();
+#if defined(FEAT_KEYMAP)
+ /* Show/unshow value of 'keymap' in status lines. */
+ status_redraw_curbuf();
+#endif
+ }
+
+#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
+ /* 'imstyle' */
+ else if (pp == &p_imst)
+ {
+ if (p_imst != IM_ON_THE_SPOT && p_imst != IM_OVER_THE_SPOT)
+ errmsg = e_invarg;
+ }
+#endif
+
+ else if (pp == &p_window)
+ {
+ if (p_window < 1)
+ p_window = 1;
+ else if (p_window >= Rows)
+ p_window = Rows - 1;
+ }
+
+ else if (pp == &curbuf->b_p_imsearch)
+ {
+ if (curbuf->b_p_imsearch < -1 || curbuf->b_p_imsearch > B_IMODE_LAST)
+ {
+ errmsg = e_invarg;
+ curbuf->b_p_imsearch = B_IMODE_NONE;
+ }
+ p_imsearch = curbuf->b_p_imsearch;
+ }
+
+#ifdef FEAT_TITLE
+ /* if 'titlelen' has changed, redraw the title */
+ else if (pp == &p_titlelen)
+ {
+ if (p_titlelen < 0)
+ {
+ errmsg = e_positive;
+ p_titlelen = 85;
+ }
+ if (starting != NO_SCREEN && old_value != p_titlelen)
+ need_maketitle = TRUE;
+ }
+#endif
+
+ /* if p_ch changed value, change the command line height */
+ else if (pp == &p_ch)
+ {
+ if (p_ch < 1)
+ {
+ errmsg = e_positive;
+ p_ch = 1;
+ }
+ if (p_ch > Rows - min_rows() + 1)
+ p_ch = Rows - min_rows() + 1;
+
+ /* Only compute the new window layout when startup has been
+ * completed. Otherwise the frame sizes may be wrong. */
+ if (p_ch != old_value && full_screen
+#ifdef FEAT_GUI
+ && !gui.starting
+#endif
+ )
+ command_height();
+ }
+
+ /* when 'updatecount' changes from zero to non-zero, open swap files */
+ else if (pp == &p_uc)
+ {
+ if (p_uc < 0)
+ {
+ errmsg = e_positive;
+ p_uc = 100;
+ }
+ if (p_uc && !old_value)
+ ml_open_files();
+ }
+#ifdef FEAT_CONCEAL
+ else if (pp == &curwin->w_p_cole)
+ {
+ if (curwin->w_p_cole < 0)
+ {
+ errmsg = e_positive;
+ curwin->w_p_cole = 0;
+ }
+ else if (curwin->w_p_cole > 3)
+ {
+ errmsg = e_invarg;
+ curwin->w_p_cole = 3;
+ }
+ }
+#endif
+#ifdef MZSCHEME_GUI_THREADS
+ else if (pp == &p_mzq)
+ mzvim_reset_timer();
+#endif
+
+#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
+ /* 'pyxversion' */
+ else if (pp == &p_pyx)
+ {
+ if (p_pyx != 0 && p_pyx != 2 && p_pyx != 3)
+ errmsg = e_invarg;
+ }
+#endif
+
+ /* sync undo before 'undolevels' changes */
+ else if (pp == &p_ul)
+ {
+ /* use the old value, otherwise u_sync() may not work properly */
+ p_ul = old_value;
+ u_sync(TRUE);
+ p_ul = value;
+ }
+ else if (pp == &curbuf->b_p_ul)
+ {
+ /* use the old value, otherwise u_sync() may not work properly */
+ curbuf->b_p_ul = old_value;
+ u_sync(TRUE);
+ curbuf->b_p_ul = value;
+ }
+
+#ifdef FEAT_LINEBREAK
+ /* 'numberwidth' must be positive */
+ else if (pp == &curwin->w_p_nuw)
+ {
+ if (curwin->w_p_nuw < 1)
+ {
+ errmsg = e_positive;
+ curwin->w_p_nuw = 1;
+ }
+ if (curwin->w_p_nuw > 10)
+ {
+ errmsg = e_invarg;
+ curwin->w_p_nuw = 10;
+ }
+ curwin->w_nrwidth_line_count = 0; /* trigger a redraw */
+ }
+#endif
+
+ else if (pp == &curbuf->b_p_tw)
+ {
+ if (curbuf->b_p_tw < 0)
+ {
+ errmsg = e_positive;
+ curbuf->b_p_tw = 0;
+ }
+#ifdef FEAT_SYN_HL
+ {
+ win_T *wp;
+ tabpage_T *tp;
+
+ FOR_ALL_TAB_WINDOWS(tp, wp)
+ check_colorcolumn(wp);
+ }
+#endif
+ }
+
+ /*
+ * Check the bounds for numeric options here
+ */
+ if (Rows < min_rows() && full_screen)
+ {
+ if (errbuf != NULL)
+ {
+ vim_snprintf((char *)errbuf, errbuflen,
+ _("E593: Need at least %d lines"), min_rows());
+ errmsg = errbuf;
+ }
+ Rows = min_rows();
+ }
+ if (Columns < MIN_COLUMNS && full_screen)
+ {
+ if (errbuf != NULL)
+ {
+ vim_snprintf((char *)errbuf, errbuflen,
+ _("E594: Need at least %d columns"), MIN_COLUMNS);
+ errmsg = errbuf;
+ }
+ Columns = MIN_COLUMNS;
+ }
+ limit_screen_size();
+
+ /*
+ * If the screen (shell) height has been changed, assume it is the
+ * physical screenheight.
+ */
+ if (old_Rows != Rows || old_Columns != Columns)
+ {
+ /* Changing the screen size is not allowed while updating the screen. */
+ if (updating_screen)
+ *pp = old_value;
+ else if (full_screen
+#ifdef FEAT_GUI
+ && !gui.starting
+#endif
+ )
+ set_shellsize((int)Columns, (int)Rows, TRUE);
+ else
+ {
+ /* Postpone the resizing; check the size and cmdline position for
+ * messages. */
+ check_shellsize();
+ if (cmdline_row > Rows - p_ch && Rows > p_ch)
+ cmdline_row = Rows - p_ch;
+ }
+ if (p_window >= Rows || !option_was_set((char_u *)"window"))
+ p_window = Rows - 1;
+ }
+
+ if (curbuf->b_p_ts <= 0)
+ {
+ errmsg = e_positive;
+ curbuf->b_p_ts = 8;
+ }
+ if (p_tm < 0)
+ {
+ errmsg = e_positive;
+ p_tm = 0;
+ }
+ if ((curwin->w_p_scr <= 0
+ || (curwin->w_p_scr > curwin->w_height
+ && curwin->w_height > 0))
+ && full_screen)
+ {
+ if (pp == &(curwin->w_p_scr))
+ {
+ if (curwin->w_p_scr != 0)
+ errmsg = e_scroll;
+ win_comp_scroll(curwin);
+ }
+ /* If 'scroll' became invalid because of a side effect silently adjust
+ * it. */
+ else if (curwin->w_p_scr <= 0)
+ curwin->w_p_scr = 1;
+ else /* curwin->w_p_scr > curwin->w_height */
+ curwin->w_p_scr = curwin->w_height;
+ }
+ if (p_hi < 0)
+ {
+ errmsg = e_positive;
+ p_hi = 0;
+ }
+ else if (p_hi > 10000)
+ {
+ errmsg = e_invarg;
+ p_hi = 10000;
+ }
+ if (p_re < 0 || p_re > 2)
+ {
+ errmsg = e_invarg;
+ p_re = 0;
+ }
+ if (p_report < 0)
+ {
+ errmsg = e_positive;
+ p_report = 1;
+ }
+ if ((p_sj < -100 || p_sj >= Rows) && full_screen)
+ {
+ if (Rows != old_Rows) /* Rows changed, just adjust p_sj */
+ p_sj = Rows / 2;
+ else
+ {
+ errmsg = e_scroll;
+ p_sj = 1;
+ }
+ }
+ if (p_so < 0 && full_screen)
+ {
+ errmsg = e_positive;
+ p_so = 0;
+ }
+ if (p_siso < 0 && full_screen)
+ {
+ errmsg = e_positive;
+ p_siso = 0;
+ }
+#ifdef FEAT_CMDWIN
+ if (p_cwh < 1)
+ {
+ errmsg = e_positive;
+ p_cwh = 1;
+ }
+#endif
+ if (p_ut < 0)
+ {
+ errmsg = e_positive;
+ p_ut = 2000;
+ }
+ if (p_ss < 0)
+ {
+ errmsg = e_positive;
+ p_ss = 0;
+ }
+
+ /* May set global value for local option. */
+ if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0)
+ *(long *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL) = *pp;
+
+ options[opt_idx].flags |= P_WAS_SET;
+
+#if defined(FEAT_EVAL)
+ // Don't do this while starting up, failure or recursively.
+ if (!starting && errmsg == NULL && *get_vim_var_str(VV_OPTION_TYPE) == NUL)
+ {
+ char_u buf_old[11], buf_new[11], buf_type[7];
+ vim_snprintf((char *)buf_old, 10, "%ld", old_value);
+ vim_snprintf((char *)buf_new, 10, "%ld", value);
+ vim_snprintf((char *)buf_type, 7, "%s", (opt_flags & OPT_LOCAL) ? "local" : "global");
+ set_vim_var_string(VV_OPTION_NEW, buf_new, -1);
+ set_vim_var_string(VV_OPTION_OLD, buf_old, -1);
+ set_vim_var_string(VV_OPTION_TYPE, buf_type, -1);
+ apply_autocmds(EVENT_OPTIONSET, (char_u *) options[opt_idx].fullname, NULL, FALSE, NULL);
+ reset_v_option_vars();
+ }
+#endif
+
+ comp_col(); /* in case 'columns' or 'ls' changed */
+ if (curwin->w_curswant != MAXCOL
+ && (options[opt_idx].flags & (P_CURSWANT | P_RALL)) != 0)
+ curwin->w_set_curswant = TRUE;
+ check_redraw(options[opt_idx].flags);
+
+ return errmsg;
+}
+
+/*
+ * Called after an option changed: check if something needs to be redrawn.
+ */
+ static void
+check_redraw(long_u flags)
+{
+ /* Careful: P_RCLR and P_RALL are a combination of other P_ flags */
+ int doclear = (flags & P_RCLR) == P_RCLR;
+ int all = ((flags & P_RALL) == P_RALL || doclear);
+
+ if ((flags & P_RSTAT) || all) /* mark all status lines dirty */
+ status_redraw_all();
+
+ if ((flags & P_RBUF) || (flags & P_RWIN) || all)
+ changed_window_setting();
+ if (flags & P_RBUF)
+ redraw_curbuf_later(NOT_VALID);
+ if (flags & P_RWINONLY)
+ redraw_later(NOT_VALID);
+ if (doclear)
+ redraw_all_later(CLEAR);
+ else if (all)
+ redraw_all_later(NOT_VALID);
+}
+
+/*
+ * Find index for option 'arg'.
+ * Return -1 if not found.
+ */
+ static int
+findoption(char_u *arg)
+{
+ int opt_idx;
+ char *s, *p;
+ static short quick_tab[27] = {0, 0}; /* quick access table */
+ int is_term_opt;
+
+ /*
+ * For first call: Initialize the quick-access table.
+ * It contains the index for the first option that starts with a certain
+ * letter. There are 26 letters, plus the first "t_" option.
+ */
+ if (quick_tab[1] == 0)
+ {
+ p = options[0].fullname;
+ for (opt_idx = 1; (s = options[opt_idx].fullname) != NULL; opt_idx++)
+ {
+ if (s[0] != p[0])
+ {
+ if (s[0] == 't' && s[1] == '_')
+ quick_tab[26] = opt_idx;
+ else
+ quick_tab[CharOrdLow(s[0])] = opt_idx;
+ }
+ p = s;
+ }
+ }
+
+ /*
+ * Check for name starting with an illegal character.
+ */
+#ifdef EBCDIC
+ if (!islower(arg[0]))
+#else
+ if (arg[0] < 'a' || arg[0] > 'z')
+#endif
+ return -1;
+
+ is_term_opt = (arg[0] == 't' && arg[1] == '_');
+ if (is_term_opt)
+ opt_idx = quick_tab[26];
+ else
+ opt_idx = quick_tab[CharOrdLow(arg[0])];
+ for ( ; (s = options[opt_idx].fullname) != NULL; opt_idx++)
+ {
+ if (STRCMP(arg, s) == 0) /* match full name */
+ break;
+ }
+ if (s == NULL && !is_term_opt)
+ {
+ opt_idx = quick_tab[CharOrdLow(arg[0])];
+ for ( ; options[opt_idx].fullname != NULL; opt_idx++)
+ {
+ s = options[opt_idx].shortname;
+ if (s != NULL && STRCMP(arg, s) == 0) /* match short name */
+ break;
+ s = NULL;
+ }
+ }
+ if (s == NULL)
+ opt_idx = -1;
+ return opt_idx;
+}
+
+#if defined(FEAT_EVAL) || defined(FEAT_TCL) || defined(FEAT_MZSCHEME)
+/*
+ * Get the value for an option.
+ *
+ * Returns:
+ * Number or Toggle option: 1, *numval gets value.
+ * String option: 0, *stringval gets allocated string.
+ * Hidden Number or Toggle option: -1.
+ * hidden String option: -2.
+ * unknown option: -3.
+ */
+ int
+get_option_value(
+ char_u *name,
+ long *numval,
+ char_u **stringval, /* NULL when only checking existence */
+ int opt_flags)
+{
+ int opt_idx;
+ char_u *varp;
+
+ opt_idx = findoption(name);
+ if (opt_idx < 0) /* unknown option */
+ {
+ int key;
+
+ if (STRLEN(name) == 4 && name[0] == 't' && name[1] == '_'
+ && (key = find_key_option(name, FALSE)) != 0)
+ {
+ char_u key_name[2];
+ char_u *p;
+
+ if (key < 0)
+ {
+ key_name[0] = KEY2TERMCAP0(key);
+ key_name[1] = KEY2TERMCAP1(key);
+ }
+ else
+ {
+ key_name[0] = KS_KEY;
+ key_name[1] = (key & 0xff);
+ }
+ p = find_termcode(key_name);
+ if (p != NULL)
+ {
+ if (stringval != NULL)
+ *stringval = vim_strsave(p);
+ return 0;
+ }
+ }
+ return -3;
+ }
+
+ varp = get_varp_scope(&(options[opt_idx]), opt_flags);
+
+ if (options[opt_idx].flags & P_STRING)
+ {
+ if (varp == NULL) /* hidden option */
+ return -2;
+ if (stringval != NULL)
+ {
+#ifdef FEAT_CRYPT
+ /* never return the value of the crypt key */
+ if ((char_u **)varp == &curbuf->b_p_key
+ && **(char_u **)(varp) != NUL)
+ *stringval = vim_strsave((char_u *)"*****");
+ else
+#endif
+ *stringval = vim_strsave(*(char_u **)(varp));
+ }
+ return 0;
+ }
+
+ if (varp == NULL) /* hidden option */
+ return -1;
+ if (options[opt_idx].flags & P_NUM)
+ *numval = *(long *)varp;
+ else
+ {
+ /* Special case: 'modified' is b_changed, but we also want to consider
+ * it set when 'ff' or 'fenc' changed. */
+ if ((int *)varp == &curbuf->b_changed)
+ *numval = curbufIsChanged();
+ else
+ *numval = (long) *(int *)varp;
+ }
+ return 1;
+}
+#endif
+
+#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) || defined(PROTO)
+/*
+ * Returns the option attributes and its value. Unlike the above function it
+ * will return either global value or local value of the option depending on
+ * what was requested, but it will never return global value if it was
+ * requested to return local one and vice versa. Neither it will return
+ * buffer-local value if it was requested to return window-local one.
+ *
+ * Pretends that option is absent if it is not present in the requested scope
+ * (i.e. has no global, window-local or buffer-local value depending on
+ * opt_type). Uses
+ *
+ * Returned flags:
+ * 0 hidden or unknown option, also option that does not have requested
+ * type (see SREQ_* in vim.h)
+ * see SOPT_* in vim.h for other flags
+ *
+ * Possible opt_type values: see SREQ_* in vim.h
+ */
+ int
+get_option_value_strict(
+ char_u *name,
+ long *numval,
+ char_u **stringval, /* NULL when only obtaining attributes */
+ int opt_type,
+ void *from)
+{
+ int opt_idx;
+ char_u *varp = NULL;
+ struct vimoption *p;
+ int r = 0;
+
+ opt_idx = findoption(name);
+ if (opt_idx < 0)
+ return 0;
+
+ p = &(options[opt_idx]);
+
+ /* Hidden option */
+ if (p->var == NULL)
+ return 0;
+
+ if (p->flags & P_BOOL)
+ r |= SOPT_BOOL;
+ else if (p->flags & P_NUM)
+ r |= SOPT_NUM;
+ else if (p->flags & P_STRING)
+ r |= SOPT_STRING;
+
+ if (p->indir == PV_NONE)
+ {
+ if (opt_type == SREQ_GLOBAL)
+ r |= SOPT_GLOBAL;
+ else
+ return 0; /* Did not request global-only option */
+ }
+ else
+ {
+ if (p->indir & PV_BOTH)
+ r |= SOPT_GLOBAL;
+ else if (opt_type == SREQ_GLOBAL)
+ return 0; /* Requested global option */
+
+ if (p->indir & PV_WIN)
+ {
+ if (opt_type == SREQ_BUF)
+ return 0; /* Did not request window-local option */
+ else
+ r |= SOPT_WIN;
+ }
+ else if (p->indir & PV_BUF)
+ {
+ if (opt_type == SREQ_WIN)
+ return 0; /* Did not request buffer-local option */
+ else
+ r |= SOPT_BUF;
+ }
+ }
+
+ if (stringval == NULL)
+ return r;
+
+ if (opt_type == SREQ_GLOBAL)
+ varp = p->var;
+ else
+ {
+ if (opt_type == SREQ_BUF)
+ {
+ /* Special case: 'modified' is b_changed, but we also want to
+ * consider it set when 'ff' or 'fenc' changed. */
+ if (p->indir == PV_MOD)
+ {
+ *numval = bufIsChanged((buf_T *)from);
+ varp = NULL;
+ }
+#ifdef FEAT_CRYPT
+ else if (p->indir == PV_KEY)
+ {
+ /* never return the value of the crypt key */
+ *stringval = NULL;
+ varp = NULL;
+ }
+#endif
+ else
+ {
+ buf_T *save_curbuf = curbuf;
+
+ // only getting a pointer, no need to use aucmd_prepbuf()
+ curbuf = (buf_T *)from;
+ curwin->w_buffer = curbuf;
+ varp = get_varp(p);
+ curbuf = save_curbuf;
+ curwin->w_buffer = curbuf;
+ }
+ }
+ else if (opt_type == SREQ_WIN)
+ {
+ win_T *save_curwin = curwin;
+
+ curwin = (win_T *)from;
+ curbuf = curwin->w_buffer;
+ varp = get_varp(p);
+ curwin = save_curwin;
+ curbuf = curwin->w_buffer;
+ }
+ if (varp == p->var)
+ return (r | SOPT_UNSET);
+ }
+
+ if (varp != NULL)
+ {
+ if (p->flags & P_STRING)
+ *stringval = vim_strsave(*(char_u **)(varp));
+ else if (p->flags & P_NUM)
+ *numval = *(long *) varp;
+ else
+ *numval = *(int *)varp;
+ }
+
+ return r;
+}
+
+/*
+ * Iterate over options. First argument is a pointer to a pointer to a
+ * structure inside options[] array, second is option type like in the above
+ * function.
+ *
+ * If first argument points to NULL it is assumed that iteration just started
+ * and caller needs the very first value.
+ * If first argument points to the end marker function returns NULL and sets
+ * first argument to NULL.
+ *
+ * Returns full option name for current option on each call.
+ */
+ char_u *
+option_iter_next(void **option, int opt_type)
+{
+ struct vimoption *ret = NULL;
+ do
+ {
+ if (*option == NULL)
+ *option = (void *) options;
+ else if (((struct vimoption *) (*option))->fullname == NULL)
+ {
+ *option = NULL;
+ return NULL;
+ }
+ else
+ *option = (void *) (((struct vimoption *) (*option)) + 1);
+
+ ret = ((struct vimoption *) (*option));
+
+ /* Hidden option */
+ if (ret->var == NULL)
+ {
+ ret = NULL;
+ continue;
+ }
+
+ switch (opt_type)
+ {
+ case SREQ_GLOBAL:
+ if (!(ret->indir == PV_NONE || ret->indir & PV_BOTH))
+ ret = NULL;
+ break;
+ case SREQ_BUF:
+ if (!(ret->indir & PV_BUF))
+ ret = NULL;
+ break;
+ case SREQ_WIN:
+ if (!(ret->indir & PV_WIN))
+ ret = NULL;
+ break;
+ default:
+ internal_error("option_iter_next()");
+ return NULL;
+ }
+ }
+ while (ret == NULL);
+
+ return (char_u *)ret->fullname;
+}
+#endif
+
+/*
+ * Set the value of option "name".
+ * Use "string" for string options, use "number" for other options.
+ *
+ * Returns NULL on success or error message on error.
+ */
+ char *
+set_option_value(
+ char_u *name,
+ long number,
+ char_u *string,
+ int opt_flags) /* OPT_LOCAL or 0 (both) */
+{
+ int opt_idx;
+ char_u *varp;
+ long_u flags;
+
+ opt_idx = findoption(name);
+ if (opt_idx < 0)
+ {
+ int key;
+
+ if (STRLEN(name) == 4 && name[0] == 't' && name[1] == '_'
+ && (key = find_key_option(name, FALSE)) != 0)
+ {
+ char_u key_name[2];
+
+ if (key < 0)
+ {
+ key_name[0] = KEY2TERMCAP0(key);
+ key_name[1] = KEY2TERMCAP1(key);
+ }
+ else
+ {
+ key_name[0] = KS_KEY;
+ key_name[1] = (key & 0xff);
+ }
+ add_termcode(key_name, string, FALSE);
+ if (full_screen)
+ ttest(FALSE);
+ redraw_all_later(CLEAR);
+ return NULL;
+ }
+
+ semsg(_("E355: Unknown option: %s"), name);
+ }
+ else
+ {
+ flags = options[opt_idx].flags;
+#ifdef HAVE_SANDBOX
+ /* Disallow changing some options in the sandbox */
+ if (sandbox > 0 && (flags & P_SECURE))
+ {
+ emsg(_(e_sandbox));
+ return NULL;
+ }
+#endif
+ if (flags & P_STRING)
+ return set_string_option(opt_idx, string, opt_flags);
+ else
+ {
+ varp = get_varp_scope(&(options[opt_idx]), opt_flags);
+ if (varp != NULL) /* hidden option is not changed */
+ {
+ if (number == 0 && string != NULL)
+ {
+ int idx;
+
+ /* Either we are given a string or we are setting option
+ * to zero. */
+ for (idx = 0; string[idx] == '0'; ++idx)
+ ;
+ if (string[idx] != NUL || idx == 0)
+ {
+ /* There's another character after zeros or the string
+ * is empty. In both cases, we are trying to set a
+ * num option using a string. */
+ semsg(_("E521: Number required: &%s = '%s'"),
+ name, string);
+ return NULL; /* do nothing as we hit an error */
+
+ }
+ }
+ if (flags & P_NUM)
+ return set_num_option(opt_idx, varp, number,
+ NULL, 0, opt_flags);
+ else
+ return set_bool_option(opt_idx, varp, (int)number,
+ opt_flags);
+ }
+ }
+ }
+ return NULL;
+}
+
+/*
+ * Get the terminal code for a terminal option.
+ * Returns NULL when not found.
+ */
+ char_u *
+get_term_code(char_u *tname)
+{
+ int opt_idx;
+ char_u *varp;
+
+ if (tname[0] != 't' || tname[1] != '_' ||
+ tname[2] == NUL || tname[3] == NUL)
+ return NULL;
+ if ((opt_idx = findoption(tname)) >= 0)
+ {
+ varp = get_varp(&(options[opt_idx]));
+ if (varp != NULL)
+ varp = *(char_u **)(varp);
+ return varp;
+ }
+ return find_termcode(tname + 2);
+}
+
+ char_u *
+get_highlight_default(void)
+{
+ int i;
+
+ i = findoption((char_u *)"hl");
+ if (i >= 0)
+ return options[i].def_val[VI_DEFAULT];
+ return (char_u *)NULL;
+}
+
+ char_u *
+get_encoding_default(void)
+{
+ int i;
+
+ i = findoption((char_u *)"enc");
+ if (i >= 0)
+ return options[i].def_val[VI_DEFAULT];
+ return (char_u *)NULL;
+}
+
+/*
+ * Translate a string like "t_xx", "<t_xx>" or "<S-Tab>" to a key number.
+ * When "has_lt" is true there is a '<' before "*arg_arg".
+ * Returns 0 when the key is not recognized.
+ */
+ static int
+find_key_option(char_u *arg_arg, int has_lt)
+{
+ int key = 0;
+ int modifiers;
+ char_u *arg = arg_arg;
+
+ /*
+ * Don't use get_special_key_code() for t_xx, we don't want it to call
+ * add_termcap_entry().
+ */
+ if (arg[0] == 't' && arg[1] == '_' && arg[2] && arg[3])
+ key = TERMCAP2KEY(arg[2], arg[3]);
+ else if (has_lt)
+ {
+ --arg; /* put arg at the '<' */
+ modifiers = 0;
+ key = find_special_key(&arg, &modifiers, TRUE, TRUE, FALSE);
+ if (modifiers) /* can't handle modifiers here */
+ key = 0;
+ }
+ return key;
+}
+
+/*
+ * if 'all' == 0: show changed options
+ * if 'all' == 1: show all normal options
+ * if 'all' == 2: show all terminal options
+ */
+ static void
+showoptions(
+ int all,
+ int opt_flags) /* OPT_LOCAL and/or OPT_GLOBAL */
+{
+ struct vimoption *p;
+ int col;
+ int isterm;
+ char_u *varp;
+ struct vimoption **items;
+ int item_count;
+ int run;
+ int row, rows;
+ int cols;
+ int i;
+ int len;
+
+#define INC 20
+#define GAP 3
+
+ items = (struct vimoption **)alloc((unsigned)(sizeof(struct vimoption *) *
+ PARAM_COUNT));
+ if (items == NULL)
+ return;
+
+ /* Highlight title */
+ if (all == 2)
+ msg_puts_title(_("\n--- Terminal codes ---"));
+ else if (opt_flags & OPT_GLOBAL)
+ msg_puts_title(_("\n--- Global option values ---"));
+ else if (opt_flags & OPT_LOCAL)
+ msg_puts_title(_("\n--- Local option values ---"));
+ else
+ msg_puts_title(_("\n--- Options ---"));
+
+ /*
+ * do the loop two times:
+ * 1. display the short items
+ * 2. display the long items (only strings and numbers)
+ */
+ for (run = 1; run <= 2 && !got_int; ++run)
+ {
+ /*
+ * collect the items in items[]
+ */
+ item_count = 0;
+ for (p = &options[0]; p->fullname != NULL; p++)
+ {
+ // apply :filter /pat/
+ if (message_filtered((char_u *) p->fullname))
+ continue;
+
+ varp = NULL;
+ isterm = istermoption(p);
+ if (opt_flags != 0)
+ {
+ if (p->indir != PV_NONE && !isterm)
+ varp = get_varp_scope(p, opt_flags);
+ }
+ else
+ varp = get_varp(p);
+ if (varp != NULL
+ && ((all == 2 && isterm)
+ || (all == 1 && !isterm)
+ || (all == 0 && !optval_default(p, varp))))
+ {
+ if (p->flags & P_BOOL)
+ len = 1; /* a toggle option fits always */
+ else
+ {
+ option_value2string(p, opt_flags);
+ len = (int)STRLEN(p->fullname) + vim_strsize(NameBuff) + 1;
+ }
+ if ((len <= INC - GAP && run == 1) ||
+ (len > INC - GAP && run == 2))
+ items[item_count++] = p;
+ }
+ }
+
+ /*
+ * display the items
+ */
+ if (run == 1)
+ {
+ cols = (Columns + GAP - 3) / INC;
+ if (cols == 0)
+ cols = 1;
+ rows = (item_count + cols - 1) / cols;
+ }
+ else /* run == 2 */
+ rows = item_count;
+ for (row = 0; row < rows && !got_int; ++row)
+ {
+ msg_putchar('\n'); /* go to next line */
+ if (got_int) /* 'q' typed in more */
+ break;
+ col = 0;
+ for (i = row; i < item_count; i += rows)
+ {
+ msg_col = col; /* make columns */
+ showoneopt(items[i], opt_flags);
+ col += INC;
+ }
+ out_flush();
+ ui_breakcheck();
+ }
+ }
+ vim_free(items);
+}
+
+/*
+ * Return TRUE if option "p" has its default value.
+ */
+ static int
+optval_default(struct vimoption *p, char_u *varp)
+{
+ int dvi;
+
+ if (varp == NULL)
+ return TRUE; /* hidden option is always at default */
+ dvi = ((p->flags & P_VI_DEF) || p_cp) ? VI_DEFAULT : VIM_DEFAULT;
+ if (p->flags & P_NUM)
+ return (*(long *)varp == (long)(long_i)p->def_val[dvi]);
+ if (p->flags & P_BOOL)
+ /* the cast to long is required for Manx C, long_i is
+ * needed for MSVC */
+ return (*(int *)varp == (int)(long)(long_i)p->def_val[dvi]);
+ /* P_STRING */
+ return (STRCMP(*(char_u **)varp, p->def_val[dvi]) == 0);
+}
+
+/*
+ * showoneopt: show the value of one option
+ * must not be called with a hidden option!
+ */
+ static void
+showoneopt(
+ struct vimoption *p,
+ int opt_flags) /* OPT_LOCAL or OPT_GLOBAL */
+{
+ char_u *varp;
+ int save_silent = silent_mode;
+
+ silent_mode = FALSE;
+ info_message = TRUE; /* use mch_msg(), not mch_errmsg() */
+
+ varp = get_varp_scope(p, opt_flags);
+
+ /* for 'modified' we also need to check if 'ff' or 'fenc' changed. */
+ if ((p->flags & P_BOOL) && ((int *)varp == &curbuf->b_changed
+ ? !curbufIsChanged() : !*(int *)varp))
+ msg_puts("no");
+ else if ((p->flags & P_BOOL) && *(int *)varp < 0)
+ msg_puts("--");
+ else
+ msg_puts(" ");
+ msg_puts(p->fullname);
+ if (!(p->flags & P_BOOL))
+ {
+ msg_putchar('=');
+ /* put value string in NameBuff */
+ option_value2string(p, opt_flags);
+ msg_outtrans(NameBuff);
+ }
+
+ silent_mode = save_silent;
+ info_message = FALSE;
+}
+
+/*
+ * Write modified options as ":set" commands to a file.
+ *
+ * There are three values for "opt_flags":
+ * OPT_GLOBAL: Write global option values and fresh values of
+ * buffer-local options (used for start of a session
+ * file).
+ * OPT_GLOBAL + OPT_LOCAL: Idem, add fresh values of window-local options for
+ * curwin (used for a vimrc file).
+ * OPT_LOCAL: Write buffer-local option values for curbuf, fresh
+ * and local values for window-local options of
+ * curwin. Local values are also written when at the
+ * default value, because a modeline or autocommand
+ * may have set them when doing ":edit file" and the
+ * user has set them back at the default or fresh
+ * value.
+ * When "local_only" is TRUE, don't write fresh
+ * values, only local values (for ":mkview").
+ * (fresh value = value used for a new buffer or window for a local option).
+ *
+ * Return FAIL on error, OK otherwise.
+ */
+ int
+makeset(FILE *fd, int opt_flags, int local_only)
+{
+ struct vimoption *p;
+ char_u *varp; /* currently used value */
+ char_u *varp_fresh; /* local value */
+ char_u *varp_local = NULL; /* fresh value */
+ char *cmd;
+ int round;
+ int pri;
+
+ /*
+ * The options that don't have a default (terminal name, columns, lines)
+ * are never written. Terminal options are also not written.
+ * Do the loop over "options[]" twice: once for options with the
+ * P_PRI_MKRC flag and once without.
+ */
+ for (pri = 1; pri >= 0; --pri)
+ {
+ for (p = &options[0]; !istermoption(p); p++)
+ if (!(p->flags & P_NO_MKRC)
+ && !istermoption(p)
+ && ((pri == 1) == ((p->flags & P_PRI_MKRC) != 0)))
+ {
+ /* skip global option when only doing locals */
+ if (p->indir == PV_NONE && !(opt_flags & OPT_GLOBAL))
+ continue;
+
+ /* Do not store options like 'bufhidden' and 'syntax' in a vimrc
+ * file, they are always buffer-specific. */
+ if ((opt_flags & OPT_GLOBAL) && (p->flags & P_NOGLOB))
+ continue;
+
+ /* Global values are only written when not at the default value. */
+ varp = get_varp_scope(p, opt_flags);
+ if ((opt_flags & OPT_GLOBAL) && optval_default(p, varp))
+ continue;
+
+ round = 2;
+ if (p->indir != PV_NONE)
+ {
+ if (p->var == VAR_WIN)
+ {
+ /* skip window-local option when only doing globals */
+ if (!(opt_flags & OPT_LOCAL))
+ continue;
+ /* When fresh value of window-local option is not at the
+ * default, need to write it too. */
+ if (!(opt_flags & OPT_GLOBAL) && !local_only)
+ {
+ varp_fresh = get_varp_scope(p, OPT_GLOBAL);
+ if (!optval_default(p, varp_fresh))
+ {
+ round = 1;
+ varp_local = varp;
+ varp = varp_fresh;
+ }
+ }
+ }
+ }
+
+ /* Round 1: fresh value for window-local options.
+ * Round 2: other values */
+ for ( ; round <= 2; varp = varp_local, ++round)
+ {
+ if (round == 1 || (opt_flags & OPT_GLOBAL))
+ cmd = "set";
+ else
+ cmd = "setlocal";
+
+ if (p->flags & P_BOOL)
+ {
+ if (put_setbool(fd, cmd, p->fullname, *(int *)varp) == FAIL)
+ return FAIL;
+ }
+ else if (p->flags & P_NUM)
+ {
+ if (put_setnum(fd, cmd, p->fullname, (long *)varp) == FAIL)
+ return FAIL;
+ }
+ else /* P_STRING */
+ {
+ int do_endif = FALSE;
+
+ /* Don't set 'syntax' and 'filetype' again if the value is
+ * already right, avoids reloading the syntax file. */
+ if (
+#if defined(FEAT_SYN_HL)
+ p->indir == PV_SYN ||
+#endif
+ p->indir == PV_FT)
+ {
+ if (fprintf(fd, "if &%s != '%s'", p->fullname,
+ *(char_u **)(varp)) < 0
+ || put_eol(fd) < 0)
+ return FAIL;
+ do_endif = TRUE;
+ }
+ if (put_setstring(fd, cmd, p->fullname, (char_u **)varp,
+ p->flags) == FAIL)
+ return FAIL;
+ if (do_endif)
+ {
+ if (put_line(fd, "endif") == FAIL)
+ return FAIL;
+ }
+ }
+ }
+ }
+ }
+ return OK;
+}
+
+#if defined(FEAT_FOLDING) || defined(PROTO)
+/*
+ * Generate set commands for the local fold options only. Used when
+ * 'sessionoptions' or 'viewoptions' contains "folds" but not "options".
+ */
+ int
+makefoldset(FILE *fd)
+{
+ if (put_setstring(fd, "setlocal", "fdm", &curwin->w_p_fdm, 0) == FAIL
+# ifdef FEAT_EVAL
+ || put_setstring(fd, "setlocal", "fde", &curwin->w_p_fde, 0)
+ == FAIL
+# endif
+ || put_setstring(fd, "setlocal", "fmr", &curwin->w_p_fmr, 0)
+ == FAIL
+ || put_setstring(fd, "setlocal", "fdi", &curwin->w_p_fdi, 0)
+ == FAIL
+ || put_setnum(fd, "setlocal", "fdl", &curwin->w_p_fdl) == FAIL
+ || put_setnum(fd, "setlocal", "fml", &curwin->w_p_fml) == FAIL
+ || put_setnum(fd, "setlocal", "fdn", &curwin->w_p_fdn) == FAIL
+ || put_setbool(fd, "setlocal", "fen", curwin->w_p_fen) == FAIL
+ )
+ return FAIL;
+
+ return OK;
+}
+#endif
+
+ static int
+put_setstring(
+ FILE *fd,
+ char *cmd,
+ char *name,
+ char_u **valuep,
+ long_u flags)
+{
+ char_u *s;
+ char_u *buf = NULL;
+ char_u *part = NULL;
+ char_u *p;
+
+ if (fprintf(fd, "%s %s=", cmd, name) < 0)
+ return FAIL;
+ if (*valuep != NULL)
+ {
+ /* Output 'pastetoggle' as key names. For other
+ * options some characters have to be escaped with
+ * CTRL-V or backslash */
+ if (valuep == &p_pt)
+ {
+ s = *valuep;
+ while (*s != NUL)
+ if (put_escstr(fd, str2special(&s, FALSE), 2) == FAIL)
+ return FAIL;
+ }
+ // expand the option value, replace $HOME by ~
+ else if ((flags & P_EXPAND) != 0)
+ {
+ int size = (int)STRLEN(*valuep) + 1;
+
+ // replace home directory in the whole option value into "buf"
+ buf = alloc(size);
+ if (buf == NULL)
+ goto fail;
+ home_replace(NULL, *valuep, buf, size, FALSE);
+
+ // If the option value is longer than MAXPATHL, we need to append
+ // earch comma separated part of the option separately, so that it
+ // can be expanded when read back.
+ if (size >= MAXPATHL && (flags & P_COMMA) != 0
+ && vim_strchr(*valuep, ',') != NULL)
+ {
+ part = alloc(size);
+ if (part == NULL)
+ goto fail;
+
+ // write line break to clear the option, e.g. ':set rtp='
+ if (put_eol(fd) == FAIL)
+ goto fail;
+
+ p = buf;
+ while (*p != NUL)
+ {
+ // for each comma separated option part, append value to
+ // the option, :set rtp+=value
+ if (fprintf(fd, "%s %s+=", cmd, name) < 0)
+ goto fail;
+ (void)copy_option_part(&p, part, size, ",");
+ if (put_escstr(fd, part, 2) == FAIL || put_eol(fd) == FAIL)
+ goto fail;
+ }
+ vim_free(buf);
+ vim_free(part);
+ return OK;
+ }
+ if (put_escstr(fd, buf, 2) == FAIL)
+ {
+ vim_free(buf);
+ return FAIL;
+ }
+ vim_free(buf);
+ }
+ else if (put_escstr(fd, *valuep, 2) == FAIL)
+ return FAIL;
+ }
+ if (put_eol(fd) < 0)
+ return FAIL;
+ return OK;
+fail:
+ vim_free(buf);
+ vim_free(part);
+ return FAIL;
+}
+
+ static int
+put_setnum(
+ FILE *fd,
+ char *cmd,
+ char *name,
+ long *valuep)
+{
+ long wc;
+
+ if (fprintf(fd, "%s %s=", cmd, name) < 0)
+ return FAIL;
+ if (wc_use_keyname((char_u *)valuep, &wc))
+ {
+ /* print 'wildchar' and 'wildcharm' as a key name */
+ if (fputs((char *)get_special_key_name((int)wc, 0), fd) < 0)
+ return FAIL;
+ }
+ else if (fprintf(fd, "%ld", *valuep) < 0)
+ return FAIL;
+ if (put_eol(fd) < 0)
+ return FAIL;
+ return OK;
+}
+
+ static int
+put_setbool(
+ FILE *fd,
+ char *cmd,
+ char *name,
+ int value)
+{
+ if (value < 0) /* global/local option using global value */
+ return OK;
+ if (fprintf(fd, "%s %s%s", cmd, value ? "" : "no", name) < 0
+ || put_eol(fd) < 0)
+ return FAIL;
+ return OK;
+}
+
+/*
+ * Clear all the terminal options.
+ * If the option has been allocated, free the memory.
+ * Terminal options are never hidden or indirect.
+ */
+ void
+clear_termoptions(void)
+{
+ /*
+ * Reset a few things before clearing the old options. This may cause
+ * outputting a few things that the terminal doesn't understand, but the
+ * screen will be cleared later, so this is OK.
+ */
+#ifdef FEAT_MOUSE_TTY
+ mch_setmouse(FALSE); /* switch mouse off */
+#endif
+#ifdef FEAT_TITLE
+ mch_restore_title(SAVE_RESTORE_BOTH); /* restore window titles */
+#endif
+#if defined(FEAT_XCLIPBOARD) && defined(FEAT_GUI)
+ /* When starting the GUI close the display opened for the clipboard.
+ * After restoring the title, because that will need the display. */
+ if (gui.starting)
+ clear_xterm_clip();
+#endif
+ stoptermcap(); /* stop termcap mode */
+
+ free_termoptions();
+}
+
+ void
+free_termoptions(void)
+{
+ struct vimoption *p;
+
+ for (p = options; p->fullname != NULL; p++)
+ if (istermoption(p))
+ {
+ if (p->flags & P_ALLOCED)
+ free_string_option(*(char_u **)(p->var));
+ if (p->flags & P_DEF_ALLOCED)
+ free_string_option(p->def_val[VI_DEFAULT]);
+ *(char_u **)(p->var) = empty_option;
+ p->def_val[VI_DEFAULT] = empty_option;
+ p->flags &= ~(P_ALLOCED|P_DEF_ALLOCED);
+#ifdef FEAT_EVAL
+ // remember where the option was cleared
+ set_option_sctx_idx((int)(p - options), OPT_GLOBAL, current_sctx);
+#endif
+ }
+ clear_termcodes();
+}
+
+/*
+ * Free the string for one term option, if it was allocated.
+ * Set the string to empty_option and clear allocated flag.
+ * "var" points to the option value.
+ */
+ void
+free_one_termoption(char_u *var)
+{
+ struct vimoption *p;
+
+ for (p = &options[0]; p->fullname != NULL; p++)
+ if (p->var == var)
+ {
+ if (p->flags & P_ALLOCED)
+ free_string_option(*(char_u **)(p->var));
+ *(char_u **)(p->var) = empty_option;
+ p->flags &= ~P_ALLOCED;
+ break;
+ }
+}
+
+/*
+ * Set the terminal option defaults to the current value.
+ * Used after setting the terminal name.
+ */
+ void
+set_term_defaults(void)
+{
+ struct vimoption *p;
+
+ for (p = &options[0]; p->fullname != NULL; p++)
+ {
+ if (istermoption(p) && p->def_val[VI_DEFAULT] != *(char_u **)(p->var))
+ {
+ if (p->flags & P_DEF_ALLOCED)
+ {
+ free_string_option(p->def_val[VI_DEFAULT]);
+ p->flags &= ~P_DEF_ALLOCED;
+ }
+ p->def_val[VI_DEFAULT] = *(char_u **)(p->var);
+ if (p->flags & P_ALLOCED)
+ {
+ p->flags |= P_DEF_ALLOCED;
+ p->flags &= ~P_ALLOCED; /* don't free the value now */
+ }
+ }
+ }
+}
+
+/*
+ * return TRUE if 'p' starts with 't_'
+ */
+ static int
+istermoption(struct vimoption *p)
+{
+ return (p->fullname[0] == 't' && p->fullname[1] == '_');
+}
+
+/*
+ * Compute columns for ruler and shown command. 'sc_col' is also used to
+ * decide what the maximum length of a message on the status line can be.
+ * If there is a status line for the last window, 'sc_col' is independent
+ * of 'ru_col'.
+ */
+
+#define COL_RULER 17 /* columns needed by standard ruler */
+
+ void
+comp_col(void)
+{
+#if defined(FEAT_CMDL_INFO)
+ int last_has_status = (p_ls == 2 || (p_ls == 1 && !ONE_WINDOW));
+
+ sc_col = 0;
+ ru_col = 0;
+ if (p_ru)
+ {
+# ifdef FEAT_STL_OPT
+ ru_col = (ru_wid ? ru_wid : COL_RULER) + 1;
+# else
+ ru_col = COL_RULER + 1;
+# endif
+ /* no last status line, adjust sc_col */
+ if (!last_has_status)
+ sc_col = ru_col;
+ }
+ if (p_sc)
+ {
+ sc_col += SHOWCMD_COLS;
+ if (!p_ru || last_has_status) /* no need for separating space */
+ ++sc_col;
+ }
+ sc_col = Columns - sc_col;
+ ru_col = Columns - ru_col;
+ if (sc_col <= 0) /* screen too narrow, will become a mess */
+ sc_col = 1;
+ if (ru_col <= 0)
+ ru_col = 1;
+#else
+ sc_col = Columns;
+ ru_col = Columns;
+#endif
+}
+
+#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) || defined(PROTO)
+/*
+ * Unset local option value, similar to ":set opt<".
+ */
+ void
+unset_global_local_option(char_u *name, void *from)
+{
+ struct vimoption *p;
+ int opt_idx;
+ buf_T *buf = (buf_T *)from;
+
+ opt_idx = findoption(name);
+ if (opt_idx < 0)
+ return;
+ p = &(options[opt_idx]);
+
+ switch ((int)p->indir)
+ {
+ /* global option with local value: use local value if it's been set */
+ case PV_EP:
+ clear_string_option(&buf->b_p_ep);
+ break;
+ case PV_KP:
+ clear_string_option(&buf->b_p_kp);
+ break;
+ case PV_PATH:
+ clear_string_option(&buf->b_p_path);
+ break;
+ case PV_AR:
+ buf->b_p_ar = -1;
+ break;
+ case PV_BKC:
+ clear_string_option(&buf->b_p_bkc);
+ buf->b_bkc_flags = 0;
+ break;
+ case PV_TAGS:
+ clear_string_option(&buf->b_p_tags);
+ break;
+ case PV_TC:
+ clear_string_option(&buf->b_p_tc);
+ buf->b_tc_flags = 0;
+ break;
+ case PV_SISO:
+ curwin->w_p_siso = -1;
+ break;
+ case PV_SO:
+ curwin->w_p_so = -1;
+ break;
+#ifdef FEAT_FIND_ID
+ case PV_DEF:
+ clear_string_option(&buf->b_p_def);
+ break;
+ case PV_INC:
+ clear_string_option(&buf->b_p_inc);
+ break;
+#endif
+#ifdef FEAT_INS_EXPAND
+ case PV_DICT:
+ clear_string_option(&buf->b_p_dict);
+ break;
+ case PV_TSR:
+ clear_string_option(&buf->b_p_tsr);
+ break;
+#endif
+ case PV_FP:
+ clear_string_option(&buf->b_p_fp);
+ break;
+#ifdef FEAT_QUICKFIX
+ case PV_EFM:
+ clear_string_option(&buf->b_p_efm);
+ break;
+ case PV_GP:
+ clear_string_option(&buf->b_p_gp);
+ break;
+ case PV_MP:
+ clear_string_option(&buf->b_p_mp);
+ break;
+#endif
+#if defined(FEAT_BEVAL) && defined(FEAT_EVAL)
+ case PV_BEXPR:
+ clear_string_option(&buf->b_p_bexpr);
+ break;
+#endif
+#if defined(FEAT_CRYPT)
+ case PV_CM:
+ clear_string_option(&buf->b_p_cm);
+ break;
+#endif
+#ifdef FEAT_STL_OPT
+ case PV_STL:
+ clear_string_option(&((win_T *)from)->w_p_stl);
+ break;
+#endif
+ case PV_UL:
+ buf->b_p_ul = NO_LOCAL_UNDOLEVEL;
+ break;
+#ifdef FEAT_LISP
+ case PV_LW:
+ clear_string_option(&buf->b_p_lw);
+ break;
+#endif
+ case PV_MENC:
+ clear_string_option(&buf->b_p_menc);
+ break;
+ }
+}
+#endif
+
+/*
+ * Get pointer to option variable, depending on local or global scope.
+ */
+ static char_u *
+get_varp_scope(struct vimoption *p, int opt_flags)
+{
+ if ((opt_flags & OPT_GLOBAL) && p->indir != PV_NONE)
+ {
+ if (p->var == VAR_WIN)
+ return (char_u *)GLOBAL_WO(get_varp(p));
+ return p->var;
+ }
+ if ((opt_flags & OPT_LOCAL) && ((int)p->indir & PV_BOTH))
+ {
+ switch ((int)p->indir)
+ {
+ case PV_FP: return (char_u *)&(curbuf->b_p_fp);
+#ifdef FEAT_QUICKFIX
+ case PV_EFM: return (char_u *)&(curbuf->b_p_efm);
+ case PV_GP: return (char_u *)&(curbuf->b_p_gp);
+ case PV_MP: return (char_u *)&(curbuf->b_p_mp);
+#endif
+ case PV_EP: return (char_u *)&(curbuf->b_p_ep);
+ case PV_KP: return (char_u *)&(curbuf->b_p_kp);
+ case PV_PATH: return (char_u *)&(curbuf->b_p_path);
+ case PV_AR: return (char_u *)&(curbuf->b_p_ar);
+ case PV_TAGS: return (char_u *)&(curbuf->b_p_tags);
+ case PV_TC: return (char_u *)&(curbuf->b_p_tc);
+ case PV_SISO: return (char_u *)&(curwin->w_p_siso);
+ case PV_SO: return (char_u *)&(curwin->w_p_so);
+#ifdef FEAT_FIND_ID
+ case PV_DEF: return (char_u *)&(curbuf->b_p_def);
+ case PV_INC: return (char_u *)&(curbuf->b_p_inc);
+#endif
+#ifdef FEAT_INS_EXPAND
+ case PV_DICT: return (char_u *)&(curbuf->b_p_dict);
+ case PV_TSR: return (char_u *)&(curbuf->b_p_tsr);
+#endif
+#if defined(FEAT_BEVAL) && defined(FEAT_EVAL)
+ case PV_BEXPR: return (char_u *)&(curbuf->b_p_bexpr);
+#endif
+#if defined(FEAT_CRYPT)
+ case PV_CM: return (char_u *)&(curbuf->b_p_cm);
+#endif
+#ifdef FEAT_STL_OPT
+ case PV_STL: return (char_u *)&(curwin->w_p_stl);
+#endif
+ case PV_UL: return (char_u *)&(curbuf->b_p_ul);
+#ifdef FEAT_LISP
+ case PV_LW: return (char_u *)&(curbuf->b_p_lw);
+#endif
+ case PV_BKC: return (char_u *)&(curbuf->b_p_bkc);
+ case PV_MENC: return (char_u *)&(curbuf->b_p_menc);
+ }
+ return NULL; /* "cannot happen" */
+ }
+ return get_varp(p);
+}
+
+/*
+ * Get pointer to option variable.
+ */
+ static char_u *
+get_varp(struct vimoption *p)
+{
+ /* hidden option, always return NULL */
+ if (p->var == NULL)
+ return NULL;
+
+ switch ((int)p->indir)
+ {
+ case PV_NONE: return p->var;
+
+ /* global option with local value: use local value if it's been set */
+ case PV_EP: return *curbuf->b_p_ep != NUL
+ ? (char_u *)&curbuf->b_p_ep : p->var;
+ case PV_KP: return *curbuf->b_p_kp != NUL
+ ? (char_u *)&curbuf->b_p_kp : p->var;
+ case PV_PATH: return *curbuf->b_p_path != NUL
+ ? (char_u *)&(curbuf->b_p_path) : p->var;
+ case PV_AR: return curbuf->b_p_ar >= 0
+ ? (char_u *)&(curbuf->b_p_ar) : p->var;
+ case PV_TAGS: return *curbuf->b_p_tags != NUL
+ ? (char_u *)&(curbuf->b_p_tags) : p->var;
+ case PV_TC: return *curbuf->b_p_tc != NUL
+ ? (char_u *)&(curbuf->b_p_tc) : p->var;
+ case PV_BKC: return *curbuf->b_p_bkc != NUL
+ ? (char_u *)&(curbuf->b_p_bkc) : p->var;
+ case PV_SISO: return curwin->w_p_siso >= 0
+ ? (char_u *)&(curwin->w_p_siso) : p->var;
+ case PV_SO: return curwin->w_p_so >= 0
+ ? (char_u *)&(curwin->w_p_so) : p->var;
+#ifdef FEAT_FIND_ID
+ case PV_DEF: return *curbuf->b_p_def != NUL
+ ? (char_u *)&(curbuf->b_p_def) : p->var;
+ case PV_INC: return *curbuf->b_p_inc != NUL
+ ? (char_u *)&(curbuf->b_p_inc) : p->var;
+#endif
+#ifdef FEAT_INS_EXPAND
+ case PV_DICT: return *curbuf->b_p_dict != NUL
+ ? (char_u *)&(curbuf->b_p_dict) : p->var;
+ case PV_TSR: return *curbuf->b_p_tsr != NUL
+ ? (char_u *)&(curbuf->b_p_tsr) : p->var;
+#endif
+ case PV_FP: return *curbuf->b_p_fp != NUL
+ ? (char_u *)&(curbuf->b_p_fp) : p->var;
+#ifdef FEAT_QUICKFIX
+ case PV_EFM: return *curbuf->b_p_efm != NUL
+ ? (char_u *)&(curbuf->b_p_efm) : p->var;
+ case PV_GP: return *curbuf->b_p_gp != NUL
+ ? (char_u *)&(curbuf->b_p_gp) : p->var;
+ case PV_MP: return *curbuf->b_p_mp != NUL
+ ? (char_u *)&(curbuf->b_p_mp) : p->var;
+#endif
+#if defined(FEAT_BEVAL) && defined(FEAT_EVAL)
+ case PV_BEXPR: return *curbuf->b_p_bexpr != NUL
+ ? (char_u *)&(curbuf->b_p_bexpr) : p->var;
+#endif
+#if defined(FEAT_CRYPT)
+ case PV_CM: return *curbuf->b_p_cm != NUL
+ ? (char_u *)&(curbuf->b_p_cm) : p->var;
+#endif
+#ifdef FEAT_STL_OPT
+ case PV_STL: return *curwin->w_p_stl != NUL
+ ? (char_u *)&(curwin->w_p_stl) : p->var;
+#endif
+ case PV_UL: return curbuf->b_p_ul != NO_LOCAL_UNDOLEVEL
+ ? (char_u *)&(curbuf->b_p_ul) : p->var;
+#ifdef FEAT_LISP
+ case PV_LW: return *curbuf->b_p_lw != NUL
+ ? (char_u *)&(curbuf->b_p_lw) : p->var;
+#endif
+ case PV_MENC: return *curbuf->b_p_menc != NUL
+ ? (char_u *)&(curbuf->b_p_menc) : p->var;
+
+#ifdef FEAT_ARABIC
+ case PV_ARAB: return (char_u *)&(curwin->w_p_arab);
+#endif
+ case PV_LIST: return (char_u *)&(curwin->w_p_list);
+#ifdef FEAT_SPELL
+ case PV_SPELL: return (char_u *)&(curwin->w_p_spell);
+#endif
+#ifdef FEAT_SYN_HL
+ case PV_CUC: return (char_u *)&(curwin->w_p_cuc);
+ case PV_CUL: return (char_u *)&(curwin->w_p_cul);
+ case PV_CC: return (char_u *)&(curwin->w_p_cc);
+#endif
+#ifdef FEAT_DIFF
+ case PV_DIFF: return (char_u *)&(curwin->w_p_diff);
+#endif
+#ifdef FEAT_FOLDING
+ case PV_FDC: return (char_u *)&(curwin->w_p_fdc);
+ case PV_FEN: return (char_u *)&(curwin->w_p_fen);
+ case PV_FDI: return (char_u *)&(curwin->w_p_fdi);
+ case PV_FDL: return (char_u *)&(curwin->w_p_fdl);
+ case PV_FDM: return (char_u *)&(curwin->w_p_fdm);
+ case PV_FML: return (char_u *)&(curwin->w_p_fml);
+ case PV_FDN: return (char_u *)&(curwin->w_p_fdn);
+# ifdef FEAT_EVAL
+ case PV_FDE: return (char_u *)&(curwin->w_p_fde);
+ case PV_FDT: return (char_u *)&(curwin->w_p_fdt);
+# endif
+ case PV_FMR: return (char_u *)&(curwin->w_p_fmr);
+#endif
+ case PV_NU: return (char_u *)&(curwin->w_p_nu);
+ case PV_RNU: return (char_u *)&(curwin->w_p_rnu);
+#ifdef FEAT_LINEBREAK
+ case PV_NUW: return (char_u *)&(curwin->w_p_nuw);
+#endif
+ case PV_WFH: return (char_u *)&(curwin->w_p_wfh);
+ case PV_WFW: return (char_u *)&(curwin->w_p_wfw);
+#if defined(FEAT_QUICKFIX)
+ case PV_PVW: return (char_u *)&(curwin->w_p_pvw);
+#endif
+#ifdef FEAT_RIGHTLEFT
+ case PV_RL: return (char_u *)&(curwin->w_p_rl);
+ case PV_RLC: return (char_u *)&(curwin->w_p_rlc);
+#endif
+ case PV_SCROLL: return (char_u *)&(curwin->w_p_scr);
+ case PV_WRAP: return (char_u *)&(curwin->w_p_wrap);
+#ifdef FEAT_LINEBREAK
+ case PV_LBR: return (char_u *)&(curwin->w_p_lbr);
+ case PV_BRI: return (char_u *)&(curwin->w_p_bri);
+ case PV_BRIOPT: return (char_u *)&(curwin->w_p_briopt);
+#endif
+ case PV_SCBIND: return (char_u *)&(curwin->w_p_scb);
+ case PV_CRBIND: return (char_u *)&(curwin->w_p_crb);
+#ifdef FEAT_CONCEAL
+ case PV_COCU: return (char_u *)&(curwin->w_p_cocu);
+ case PV_COLE: return (char_u *)&(curwin->w_p_cole);
+#endif
+#ifdef FEAT_TERMINAL
+ case PV_TWK: return (char_u *)&(curwin->w_p_twk);
+ case PV_TWS: return (char_u *)&(curwin->w_p_tws);
+ case PV_TWSL: return (char_u *)&(curbuf->b_p_twsl);
+ case PV_TMOD: return (char_u *)&(curwin->w_p_tmod);
+#endif
+
+ case PV_AI: return (char_u *)&(curbuf->b_p_ai);
+ case PV_BIN: return (char_u *)&(curbuf->b_p_bin);
+ case PV_BOMB: return (char_u *)&(curbuf->b_p_bomb);
+ case PV_BH: return (char_u *)&(curbuf->b_p_bh);
+ case PV_BT: return (char_u *)&(curbuf->b_p_bt);
+ case PV_BL: return (char_u *)&(curbuf->b_p_bl);
+ case PV_CI: return (char_u *)&(curbuf->b_p_ci);
+#ifdef FEAT_CINDENT
+ case PV_CIN: return (char_u *)&(curbuf->b_p_cin);
+ case PV_CINK: return (char_u *)&(curbuf->b_p_cink);
+ case PV_CINO: return (char_u *)&(curbuf->b_p_cino);
+#endif
+#if defined(FEAT_SMARTINDENT) || defined(FEAT_CINDENT)
+ case PV_CINW: return (char_u *)&(curbuf->b_p_cinw);
+#endif
+#ifdef FEAT_COMMENTS
+ case PV_COM: return (char_u *)&(curbuf->b_p_com);
+#endif
+#ifdef FEAT_FOLDING
+ case PV_CMS: return (char_u *)&(curbuf->b_p_cms);
+#endif
+#ifdef FEAT_INS_EXPAND
+ case PV_CPT: return (char_u *)&(curbuf->b_p_cpt);
+#endif
+#ifdef FEAT_COMPL_FUNC
+ case PV_CFU: return (char_u *)&(curbuf->b_p_cfu);
+ case PV_OFU: return (char_u *)&(curbuf->b_p_ofu);
+#endif
+ case PV_EOL: return (char_u *)&(curbuf->b_p_eol);
+ case PV_FIXEOL: return (char_u *)&(curbuf->b_p_fixeol);
+ case PV_ET: return (char_u *)&(curbuf->b_p_et);
+ case PV_FENC: return (char_u *)&(curbuf->b_p_fenc);
+ case PV_FF: return (char_u *)&(curbuf->b_p_ff);
+ case PV_FT: return (char_u *)&(curbuf->b_p_ft);
+ case PV_FO: return (char_u *)&(curbuf->b_p_fo);
+ case PV_FLP: return (char_u *)&(curbuf->b_p_flp);
+ case PV_IMI: return (char_u *)&(curbuf->b_p_iminsert);
+ case PV_IMS: return (char_u *)&(curbuf->b_p_imsearch);
+ case PV_INF: return (char_u *)&(curbuf->b_p_inf);
+ case PV_ISK: return (char_u *)&(curbuf->b_p_isk);
+#ifdef FEAT_FIND_ID
+# ifdef FEAT_EVAL
+ case PV_INEX: return (char_u *)&(curbuf->b_p_inex);
+# endif
+#endif
+#if defined(FEAT_CINDENT) && defined(FEAT_EVAL)
+ case PV_INDE: return (char_u *)&(curbuf->b_p_inde);
+ case PV_INDK: return (char_u *)&(curbuf->b_p_indk);
+#endif
+#ifdef FEAT_EVAL
+ case PV_FEX: return (char_u *)&(curbuf->b_p_fex);
+#endif
+#ifdef FEAT_CRYPT
+ case PV_KEY: return (char_u *)&(curbuf->b_p_key);
+#endif
+#ifdef FEAT_LISP
+ case PV_LISP: return (char_u *)&(curbuf->b_p_lisp);
+#endif
+ case PV_ML: return (char_u *)&(curbuf->b_p_ml);
+ case PV_MPS: return (char_u *)&(curbuf->b_p_mps);
+ case PV_MA: return (char_u *)&(curbuf->b_p_ma);
+ case PV_MOD: return (char_u *)&(curbuf->b_changed);
+ case PV_NF: return (char_u *)&(curbuf->b_p_nf);
+ case PV_PI: return (char_u *)&(curbuf->b_p_pi);
+#ifdef FEAT_TEXTOBJ
+ case PV_QE: return (char_u *)&(curbuf->b_p_qe);
+#endif
+ case PV_RO: return (char_u *)&(curbuf->b_p_ro);
+#ifdef FEAT_SMARTINDENT
+ case PV_SI: return (char_u *)&(curbuf->b_p_si);
+#endif
+ case PV_SN: return (char_u *)&(curbuf->b_p_sn);
+ case PV_STS: return (char_u *)&(curbuf->b_p_sts);
+#ifdef FEAT_SEARCHPATH
+ case PV_SUA: return (char_u *)&(curbuf->b_p_sua);
+#endif
+ case PV_SWF: return (char_u *)&(curbuf->b_p_swf);
+#ifdef FEAT_SYN_HL
+ case PV_SMC: return (char_u *)&(curbuf->b_p_smc);
+ case PV_SYN: return (char_u *)&(curbuf->b_p_syn);
+#endif
+#ifdef FEAT_SPELL
+ case PV_SPC: return (char_u *)&(curwin->w_s->b_p_spc);
+ case PV_SPF: return (char_u *)&(curwin->w_s->b_p_spf);
+ case PV_SPL: return (char_u *)&(curwin->w_s->b_p_spl);
+#endif
+ case PV_SW: return (char_u *)&(curbuf->b_p_sw);
+ case PV_TS: return (char_u *)&(curbuf->b_p_ts);
+ case PV_TW: return (char_u *)&(curbuf->b_p_tw);
+ case PV_TX: return (char_u *)&(curbuf->b_p_tx);
+#ifdef FEAT_PERSISTENT_UNDO
+ case PV_UDF: return (char_u *)&(curbuf->b_p_udf);
+#endif
+ case PV_WM: return (char_u *)&(curbuf->b_p_wm);
+#ifdef FEAT_KEYMAP
+ case PV_KMAP: return (char_u *)&(curbuf->b_p_keymap);
+#endif
+#ifdef FEAT_SIGNS
+ case PV_SCL: return (char_u *)&(curwin->w_p_scl);
+#endif
+#ifdef FEAT_VARTABS
+ case PV_VSTS: return (char_u *)&(curbuf->b_p_vsts);
+ case PV_VTS: return (char_u *)&(curbuf->b_p_vts);
+#endif
+ default: iemsg(_("E356: get_varp ERROR"));
+ }
+ /* always return a valid pointer to avoid a crash! */
+ return (char_u *)&(curbuf->b_p_wm);
+}
+
+/*
+ * Get the value of 'equalprg', either the buffer-local one or the global one.
+ */
+ char_u *
+get_equalprg(void)
+{
+ if (*curbuf->b_p_ep == NUL)
+ return p_ep;
+ return curbuf->b_p_ep;
+}
+
+/*
+ * Copy options from one window to another.
+ * Used when splitting a window.
+ */
+ void
+win_copy_options(win_T *wp_from, win_T *wp_to)
+{
+ copy_winopt(&wp_from->w_onebuf_opt, &wp_to->w_onebuf_opt);
+ copy_winopt(&wp_from->w_allbuf_opt, &wp_to->w_allbuf_opt);
+# ifdef FEAT_RIGHTLEFT
+# ifdef FEAT_FKMAP
+ /* Is this right? */
+ wp_to->w_farsi = wp_from->w_farsi;
+# endif
+# endif
+#if defined(FEAT_LINEBREAK)
+ briopt_check(wp_to);
+#endif
+}
+
+/*
+ * Copy the options from one winopt_T to another.
+ * Doesn't free the old option values in "to", use clear_winopt() for that.
+ * The 'scroll' option is not copied, because it depends on the window height.
+ * The 'previewwindow' option is reset, there can be only one preview window.
+ */
+ void
+copy_winopt(winopt_T *from, winopt_T *to)
+{
+#ifdef FEAT_ARABIC
+ to->wo_arab = from->wo_arab;
+#endif
+ to->wo_list = from->wo_list;
+ to->wo_nu = from->wo_nu;
+ to->wo_rnu = from->wo_rnu;
+#ifdef FEAT_LINEBREAK
+ to->wo_nuw = from->wo_nuw;
+#endif
+#ifdef FEAT_RIGHTLEFT
+ to->wo_rl = from->wo_rl;
+ to->wo_rlc = vim_strsave(from->wo_rlc);
+#endif
+#ifdef FEAT_STL_OPT
+ to->wo_stl = vim_strsave(from->wo_stl);
+#endif
+ to->wo_wrap = from->wo_wrap;
+#ifdef FEAT_DIFF
+ to->wo_wrap_save = from->wo_wrap_save;
+#endif
+#ifdef FEAT_LINEBREAK
+ to->wo_lbr = from->wo_lbr;
+ to->wo_bri = from->wo_bri;
+ to->wo_briopt = vim_strsave(from->wo_briopt);
+#endif
+ to->wo_scb = from->wo_scb;
+ to->wo_scb_save = from->wo_scb_save;
+ to->wo_crb = from->wo_crb;
+ to->wo_crb_save = from->wo_crb_save;
+#ifdef FEAT_SPELL
+ to->wo_spell = from->wo_spell;
+#endif
+#ifdef FEAT_SYN_HL
+ to->wo_cuc = from->wo_cuc;
+ to->wo_cul = from->wo_cul;
+ to->wo_cc = vim_strsave(from->wo_cc);
+#endif
+#ifdef FEAT_DIFF
+ to->wo_diff = from->wo_diff;
+ to->wo_diff_saved = from->wo_diff_saved;
+#endif
+#ifdef FEAT_CONCEAL
+ to->wo_cocu = vim_strsave(from->wo_cocu);
+ to->wo_cole = from->wo_cole;
+#endif
+#ifdef FEAT_TERMINAL
+ to->wo_twk = vim_strsave(from->wo_twk);
+ to->wo_tws = vim_strsave(from->wo_tws);
+ to->wo_tmod = vim_strsave(from->wo_tmod);
+#endif
+#ifdef FEAT_FOLDING
+ to->wo_fdc = from->wo_fdc;
+ to->wo_fdc_save = from->wo_fdc_save;
+ to->wo_fen = from->wo_fen;
+ to->wo_fen_save = from->wo_fen_save;
+ to->wo_fdi = vim_strsave(from->wo_fdi);
+ to->wo_fml = from->wo_fml;
+ to->wo_fdl = from->wo_fdl;
+ to->wo_fdl_save = from->wo_fdl_save;
+ to->wo_fdm = vim_strsave(from->wo_fdm);
+ to->wo_fdm_save = from->wo_diff_saved
+ ? vim_strsave(from->wo_fdm_save) : empty_option;
+ to->wo_fdn = from->wo_fdn;
+# ifdef FEAT_EVAL
+ to->wo_fde = vim_strsave(from->wo_fde);
+ to->wo_fdt = vim_strsave(from->wo_fdt);
+# endif
+ to->wo_fmr = vim_strsave(from->wo_fmr);
+#endif
+#ifdef FEAT_SIGNS
+ to->wo_scl = vim_strsave(from->wo_scl);
+#endif
+ check_winopt(to); /* don't want NULL pointers */
+}
+
+/*
+ * Check string options in a window for a NULL value.
+ */
+ void
+check_win_options(win_T *win)
+{
+ check_winopt(&win->w_onebuf_opt);
+ check_winopt(&win->w_allbuf_opt);
+}
+
+/*
+ * Check for NULL pointers in a winopt_T and replace them with empty_option.
+ */
+ static void
+check_winopt(winopt_T *wop UNUSED)
+{
+#ifdef FEAT_FOLDING
+ check_string_option(&wop->wo_fdi);
+ check_string_option(&wop->wo_fdm);
+ check_string_option(&wop->wo_fdm_save);
+# ifdef FEAT_EVAL
+ check_string_option(&wop->wo_fde);
+ check_string_option(&wop->wo_fdt);
+# endif
+ check_string_option(&wop->wo_fmr);
+#endif
+#ifdef FEAT_SIGNS
+ check_string_option(&wop->wo_scl);
+#endif
+#ifdef FEAT_RIGHTLEFT
+ check_string_option(&wop->wo_rlc);
+#endif
+#ifdef FEAT_STL_OPT
+ check_string_option(&wop->wo_stl);
+#endif
+#ifdef FEAT_SYN_HL
+ check_string_option(&wop->wo_cc);
+#endif
+#ifdef FEAT_CONCEAL
+ check_string_option(&wop->wo_cocu);
+#endif
+#ifdef FEAT_TERMINAL
+ check_string_option(&wop->wo_twk);
+ check_string_option(&wop->wo_tws);
+ check_string_option(&wop->wo_tmod);
+#endif
+#ifdef FEAT_LINEBREAK
+ check_string_option(&wop->wo_briopt);
+#endif
+}
+
+/*
+ * Free the allocated memory inside a winopt_T.
+ */
+ void
+clear_winopt(winopt_T *wop UNUSED)
+{
+#ifdef FEAT_FOLDING
+ clear_string_option(&wop->wo_fdi);
+ clear_string_option(&wop->wo_fdm);
+ clear_string_option(&wop->wo_fdm_save);
+# ifdef FEAT_EVAL
+ clear_string_option(&wop->wo_fde);
+ clear_string_option(&wop->wo_fdt);
+# endif
+ clear_string_option(&wop->wo_fmr);
+#endif
+#ifdef FEAT_SIGNS
+ clear_string_option(&wop->wo_scl);
+#endif
+#ifdef FEAT_LINEBREAK
+ clear_string_option(&wop->wo_briopt);
+#endif
+#ifdef FEAT_RIGHTLEFT
+ clear_string_option(&wop->wo_rlc);
+#endif
+#ifdef FEAT_STL_OPT
+ clear_string_option(&wop->wo_stl);
+#endif
+#ifdef FEAT_SYN_HL
+ clear_string_option(&wop->wo_cc);
+#endif
+#ifdef FEAT_CONCEAL
+ clear_string_option(&wop->wo_cocu);
+#endif
+#ifdef FEAT_TERMINAL
+ clear_string_option(&wop->wo_twk);
+ clear_string_option(&wop->wo_tws);
+ clear_string_option(&wop->wo_tmod);
+#endif
+}
+
+/*
+ * Copy global option values to local options for one buffer.
+ * Used when creating a new buffer and sometimes when entering a buffer.
+ * flags:
+ * BCO_ENTER We will enter the buf buffer.
+ * BCO_ALWAYS Always copy the options, but only set b_p_initialized when
+ * appropriate.
+ * BCO_NOHELP Don't copy the values to a help buffer.
+ */
+ void
+buf_copy_options(buf_T *buf, int flags)
+{
+ int should_copy = TRUE;
+ char_u *save_p_isk = NULL; /* init for GCC */
+ int dont_do_help;
+ int did_isk = FALSE;
+
+ /*
+ * Skip this when the option defaults have not been set yet. Happens when
+ * main() allocates the first buffer.
+ */
+ if (p_cpo != NULL)
+ {
+ /*
+ * Always copy when entering and 'cpo' contains 'S'.
+ * Don't copy when already initialized.
+ * Don't copy when 'cpo' contains 's' and not entering.
+ * 'S' BCO_ENTER initialized 's' should_copy
+ * yes yes X X TRUE
+ * yes no yes X FALSE
+ * no X yes X FALSE
+ * X no no yes FALSE
+ * X no no no TRUE
+ * no yes no X TRUE
+ */
+ if ((vim_strchr(p_cpo, CPO_BUFOPTGLOB) == NULL || !(flags & BCO_ENTER))
+ && (buf->b_p_initialized
+ || (!(flags & BCO_ENTER)
+ && vim_strchr(p_cpo, CPO_BUFOPT) != NULL)))
+ should_copy = FALSE;
+
+ if (should_copy || (flags & BCO_ALWAYS))
+ {
+ /* Don't copy the options specific to a help buffer when
+ * BCO_NOHELP is given or the options were initialized already
+ * (jumping back to a help file with CTRL-T or CTRL-O) */
+ dont_do_help = ((flags & BCO_NOHELP) && buf->b_help)
+ || buf->b_p_initialized;
+ if (dont_do_help) /* don't free b_p_isk */
+ {
+ save_p_isk = buf->b_p_isk;
+ buf->b_p_isk = NULL;
+ }
+ /*
+ * Always free the allocated strings. If not already initialized,
+ * reset 'readonly' and copy 'fileformat'.
+ */
+ if (!buf->b_p_initialized)
+ {
+ free_buf_options(buf, TRUE);
+ buf->b_p_ro = FALSE; /* don't copy readonly */
+ buf->b_p_tx = p_tx;
+ buf->b_p_fenc = vim_strsave(p_fenc);
+ switch (*p_ffs)
+ {
+ case 'm':
+ buf->b_p_ff = vim_strsave((char_u *)FF_MAC); break;
+ case 'd':
+ buf->b_p_ff = vim_strsave((char_u *)FF_DOS); break;
+ case 'u':
+ buf->b_p_ff = vim_strsave((char_u *)FF_UNIX); break;
+ default:
+ buf->b_p_ff = vim_strsave(p_ff);
+ }
+ if (buf->b_p_ff != NULL)
+ buf->b_start_ffc = *buf->b_p_ff;
+ buf->b_p_bh = empty_option;
+ buf->b_p_bt = empty_option;
+ }
+ else
+ free_buf_options(buf, FALSE);
+
+ buf->b_p_ai = p_ai;
+ buf->b_p_ai_nopaste = p_ai_nopaste;
+ buf->b_p_sw = p_sw;
+ buf->b_p_tw = p_tw;
+ buf->b_p_tw_nopaste = p_tw_nopaste;
+ buf->b_p_tw_nobin = p_tw_nobin;
+ buf->b_p_wm = p_wm;
+ buf->b_p_wm_nopaste = p_wm_nopaste;
+ buf->b_p_wm_nobin = p_wm_nobin;
+ buf->b_p_bin = p_bin;
+ buf->b_p_bomb = p_bomb;
+ buf->b_p_fixeol = p_fixeol;
+ buf->b_p_et = p_et;
+ buf->b_p_et_nobin = p_et_nobin;
+ buf->b_p_et_nopaste = p_et_nopaste;
+ buf->b_p_ml = p_ml;
+ buf->b_p_ml_nobin = p_ml_nobin;
+ buf->b_p_inf = p_inf;
+ buf->b_p_swf = cmdmod.noswapfile ? FALSE : p_swf;
+#ifdef FEAT_INS_EXPAND
+ buf->b_p_cpt = vim_strsave(p_cpt);
+#endif
+#ifdef FEAT_COMPL_FUNC
+ buf->b_p_cfu = vim_strsave(p_cfu);
+ buf->b_p_ofu = vim_strsave(p_ofu);
+#endif
+ buf->b_p_sts = p_sts;
+ buf->b_p_sts_nopaste = p_sts_nopaste;
+#ifdef FEAT_VARTABS
+ buf->b_p_vsts = vim_strsave(p_vsts);
+ if (p_vsts && p_vsts != empty_option)
+ tabstop_set(p_vsts, &buf->b_p_vsts_array);
+ else
+ buf->b_p_vsts_array = 0;
+ buf->b_p_vsts_nopaste = p_vsts_nopaste
+ ? vim_strsave(p_vsts_nopaste) : NULL;
+#endif
+ buf->b_p_sn = p_sn;
+#ifdef FEAT_COMMENTS
+ buf->b_p_com = vim_strsave(p_com);
+#endif
+#ifdef FEAT_FOLDING
+ buf->b_p_cms = vim_strsave(p_cms);
+#endif
+ buf->b_p_fo = vim_strsave(p_fo);
+ buf->b_p_flp = vim_strsave(p_flp);
+ buf->b_p_nf = vim_strsave(p_nf);
+ buf->b_p_mps = vim_strsave(p_mps);
+#ifdef FEAT_SMARTINDENT
+ buf->b_p_si = p_si;
+#endif
+ buf->b_p_ci = p_ci;
+#ifdef FEAT_CINDENT
+ buf->b_p_cin = p_cin;
+ buf->b_p_cink = vim_strsave(p_cink);
+ buf->b_p_cino = vim_strsave(p_cino);
+#endif
+ /* Don't copy 'filetype', it must be detected */
+ buf->b_p_ft = empty_option;
+ buf->b_p_pi = p_pi;
+#if defined(FEAT_SMARTINDENT) || defined(FEAT_CINDENT)
+ buf->b_p_cinw = vim_strsave(p_cinw);
+#endif
+#ifdef FEAT_LISP
+ buf->b_p_lisp = p_lisp;
+#endif
+#ifdef FEAT_SYN_HL
+ /* Don't copy 'syntax', it must be set */
+ buf->b_p_syn = empty_option;
+ buf->b_p_smc = p_smc;
+ buf->b_s.b_syn_isk = empty_option;
+#endif
+#ifdef FEAT_SPELL
+ buf->b_s.b_p_spc = vim_strsave(p_spc);
+ (void)compile_cap_prog(&buf->b_s);
+ buf->b_s.b_p_spf = vim_strsave(p_spf);
+ buf->b_s.b_p_spl = vim_strsave(p_spl);
+#endif
+#if defined(FEAT_CINDENT) && defined(FEAT_EVAL)
+ buf->b_p_inde = vim_strsave(p_inde);
+ buf->b_p_indk = vim_strsave(p_indk);
+#endif
+ buf->b_p_fp = empty_option;
+#if defined(FEAT_EVAL)
+ buf->b_p_fex = vim_strsave(p_fex);
+#endif
+#ifdef FEAT_CRYPT
+ buf->b_p_key = vim_strsave(p_key);
+#endif
+#ifdef FEAT_SEARCHPATH
+ buf->b_p_sua = vim_strsave(p_sua);
+#endif
+#ifdef FEAT_KEYMAP
+ buf->b_p_keymap = vim_strsave(p_keymap);
+ buf->b_kmap_state |= KEYMAP_INIT;
+#endif
+#ifdef FEAT_TERMINAL
+ buf->b_p_twsl = p_twsl;
+#endif
+ /* This isn't really an option, but copying the langmap and IME
+ * state from the current buffer is better than resetting it. */
+ buf->b_p_iminsert = p_iminsert;
+ buf->b_p_imsearch = p_imsearch;
+
+ /* options that are normally global but also have a local value
+ * are not copied, start using the global value */
+ buf->b_p_ar = -1;
+ buf->b_p_ul = NO_LOCAL_UNDOLEVEL;
+ buf->b_p_bkc = empty_option;
+ buf->b_bkc_flags = 0;
+#ifdef FEAT_QUICKFIX
+ buf->b_p_gp = empty_option;
+ buf->b_p_mp = empty_option;
+ buf->b_p_efm = empty_option;
+#endif
+ buf->b_p_ep = empty_option;
+ buf->b_p_kp = empty_option;
+ buf->b_p_path = empty_option;
+ buf->b_p_tags = empty_option;
+ buf->b_p_tc = empty_option;
+ buf->b_tc_flags = 0;
+#ifdef FEAT_FIND_ID
+ buf->b_p_def = empty_option;
+ buf->b_p_inc = empty_option;
+# ifdef FEAT_EVAL
+ buf->b_p_inex = vim_strsave(p_inex);
+# endif
+#endif
+#ifdef FEAT_INS_EXPAND
+ buf->b_p_dict = empty_option;
+ buf->b_p_tsr = empty_option;
+#endif
+#ifdef FEAT_TEXTOBJ
+ buf->b_p_qe = vim_strsave(p_qe);
+#endif
+#if defined(FEAT_BEVAL) && defined(FEAT_EVAL)
+ buf->b_p_bexpr = empty_option;
+#endif
+#if defined(FEAT_CRYPT)
+ buf->b_p_cm = empty_option;
+#endif
+#ifdef FEAT_PERSISTENT_UNDO
+ buf->b_p_udf = p_udf;
+#endif
+#ifdef FEAT_LISP
+ buf->b_p_lw = empty_option;
+#endif
+ buf->b_p_menc = empty_option;
+
+ /*
+ * Don't copy the options set by ex_help(), use the saved values,
+ * when going from a help buffer to a non-help buffer.
+ * Don't touch these at all when BCO_NOHELP is used and going from
+ * or to a help buffer.
+ */
+ if (dont_do_help)
+ {
+ buf->b_p_isk = save_p_isk;
+#ifdef FEAT_VARTABS
+ if (p_vts && p_vts != empty_option && !buf->b_p_vts_array)
+ tabstop_set(p_vts, &buf->b_p_vts_array);
+ else
+ buf->b_p_vts_array = NULL;
+#endif
+ }
+ else
+ {
+ buf->b_p_isk = vim_strsave(p_isk);
+ did_isk = TRUE;
+ buf->b_p_ts = p_ts;
+#ifdef FEAT_VARTABS
+ buf->b_p_vts = vim_strsave(p_vts);
+ if (p_vts && p_vts != empty_option && !buf->b_p_vts_array)
+ tabstop_set(p_vts, &buf->b_p_vts_array);
+ else
+ buf->b_p_vts_array = NULL;
+#endif
+ buf->b_help = FALSE;
+ if (buf->b_p_bt[0] == 'h')
+ clear_string_option(&buf->b_p_bt);
+ buf->b_p_ma = p_ma;
+ }
+ }
+
+ /*
+ * When the options should be copied (ignoring BCO_ALWAYS), set the
+ * flag that indicates that the options have been initialized.
+ */
+ if (should_copy)
+ buf->b_p_initialized = TRUE;
+ }
+
+ check_buf_options(buf); /* make sure we don't have NULLs */
+ if (did_isk)
+ (void)buf_init_chartab(buf, FALSE);
+}
+
+/*
+ * Reset the 'modifiable' option and its default value.
+ */
+ void
+reset_modifiable(void)
+{
+ int opt_idx;
+
+ curbuf->b_p_ma = FALSE;
+ p_ma = FALSE;
+ opt_idx = findoption((char_u *)"ma");
+ if (opt_idx >= 0)
+ options[opt_idx].def_val[VI_DEFAULT] = FALSE;
+}
+
+/*
+ * Set the global value for 'iminsert' to the local value.
+ */
+ void
+set_iminsert_global(void)
+{
+ p_iminsert = curbuf->b_p_iminsert;
+}
+
+/*
+ * Set the global value for 'imsearch' to the local value.
+ */
+ void
+set_imsearch_global(void)
+{
+ p_imsearch = curbuf->b_p_imsearch;
+}
+
+#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
+static int expand_option_idx = -1;
+static char_u expand_option_name[5] = {'t', '_', NUL, NUL, NUL};
+static int expand_option_flags = 0;
+
+ void
+set_context_in_set_cmd(
+ expand_T *xp,
+ char_u *arg,
+ int opt_flags) /* OPT_GLOBAL and/or OPT_LOCAL */
+{
+ int nextchar;
+ long_u flags = 0; /* init for GCC */
+ int opt_idx = 0; /* init for GCC */
+ char_u *p;
+ char_u *s;
+ int is_term_option = FALSE;
+ int key;
+
+ expand_option_flags = opt_flags;
+
+ xp->xp_context = EXPAND_SETTINGS;
+ if (*arg == NUL)
+ {
+ xp->xp_pattern = arg;
+ return;
+ }
+ p = arg + STRLEN(arg) - 1;
+ if (*p == ' ' && *(p - 1) != '\\')
+ {
+ xp->xp_pattern = p + 1;
+ return;
+ }
+ while (p > arg)
+ {
+ s = p;
+ /* count number of backslashes before ' ' or ',' */
+ if (*p == ' ' || *p == ',')
+ {
+ while (s > arg && *(s - 1) == '\\')
+ --s;
+ }
+ /* break at a space with an even number of backslashes */
+ if (*p == ' ' && ((p - s) & 1) == 0)
+ {
+ ++p;
+ break;
+ }
+ --p;
+ }
+ if (STRNCMP(p, "no", 2) == 0 && STRNCMP(p, "novice", 6) != 0)
+ {
+ xp->xp_context = EXPAND_BOOL_SETTINGS;
+ p += 2;
+ }
+ if (STRNCMP(p, "inv", 3) == 0)
+ {
+ xp->xp_context = EXPAND_BOOL_SETTINGS;
+ p += 3;
+ }
+ xp->xp_pattern = arg = p;
+ if (*arg == '<')
+ {
+ while (*p != '>')
+ if (*p++ == NUL) /* expand terminal option name */
+ return;
+ key = get_special_key_code(arg + 1);
+ if (key == 0) /* unknown name */
+ {
+ xp->xp_context = EXPAND_NOTHING;
+ return;
+ }
+ nextchar = *++p;
+ is_term_option = TRUE;
+ expand_option_name[2] = KEY2TERMCAP0(key);
+ expand_option_name[3] = KEY2TERMCAP1(key);
+ }
+ else
+ {
+ if (p[0] == 't' && p[1] == '_')
+ {
+ p += 2;
+ if (*p != NUL)
+ ++p;
+ if (*p == NUL)
+ return; /* expand option name */
+ nextchar = *++p;
+ is_term_option = TRUE;
+ expand_option_name[2] = p[-2];
+ expand_option_name[3] = p[-1];
+ }
+ else
+ {
+ /* Allow * wildcard */
+ while (ASCII_ISALNUM(*p) || *p == '_' || *p == '*')
+ p++;
+ if (*p == NUL)
+ return;
+ nextchar = *p;
+ *p = NUL;
+ opt_idx = findoption(arg);
+ *p = nextchar;
+ if (opt_idx == -1 || options[opt_idx].var == NULL)
+ {
+ xp->xp_context = EXPAND_NOTHING;
+ return;
+ }
+ flags = options[opt_idx].flags;
+ if (flags & P_BOOL)
+ {
+ xp->xp_context = EXPAND_NOTHING;
+ return;
+ }
+ }
+ }
+ /* handle "-=" and "+=" */
+ if ((nextchar == '-' || nextchar == '+' || nextchar == '^') && p[1] == '=')
+ {
+ ++p;
+ nextchar = '=';
+ }
+ if ((nextchar != '=' && nextchar != ':')
+ || xp->xp_context == EXPAND_BOOL_SETTINGS)
+ {
+ xp->xp_context = EXPAND_UNSUCCESSFUL;
+ return;
+ }
+ if (xp->xp_context != EXPAND_BOOL_SETTINGS && p[1] == NUL)
+ {
+ xp->xp_context = EXPAND_OLD_SETTING;
+ if (is_term_option)
+ expand_option_idx = -1;
+ else
+ expand_option_idx = opt_idx;
+ xp->xp_pattern = p + 1;
+ return;
+ }
+ xp->xp_context = EXPAND_NOTHING;
+ if (is_term_option || (flags & P_NUM))
+ return;
+
+ xp->xp_pattern = p + 1;
+
+ if (flags & P_EXPAND)
+ {
+ p = options[opt_idx].var;
+ if (p == (char_u *)&p_bdir
+ || p == (char_u *)&p_dir
+ || p == (char_u *)&p_path
+ || p == (char_u *)&p_pp
+ || p == (char_u *)&p_rtp
+#ifdef FEAT_SEARCHPATH
+ || p == (char_u *)&p_cdpath
+#endif
+#ifdef FEAT_SESSION
+ || p == (char_u *)&p_vdir
+#endif
+ )
+ {
+ xp->xp_context = EXPAND_DIRECTORIES;
+ if (p == (char_u *)&p_path
+#ifdef FEAT_SEARCHPATH
+ || p == (char_u *)&p_cdpath
+#endif
+ )
+ xp->xp_backslash = XP_BS_THREE;
+ else
+ xp->xp_backslash = XP_BS_ONE;
+ }
+ else
+ {
+ xp->xp_context = EXPAND_FILES;
+ /* for 'tags' need three backslashes for a space */
+ if (p == (char_u *)&p_tags)
+ xp->xp_backslash = XP_BS_THREE;
+ else
+ xp->xp_backslash = XP_BS_ONE;
+ }
+ }
+
+ /* For an option that is a list of file names, find the start of the
+ * last file name. */
+ for (p = arg + STRLEN(arg) - 1; p > xp->xp_pattern; --p)
+ {
+ /* count number of backslashes before ' ' or ',' */
+ if (*p == ' ' || *p == ',')
+ {
+ s = p;
+ while (s > xp->xp_pattern && *(s - 1) == '\\')
+ --s;
+ if ((*p == ' ' && (xp->xp_backslash == XP_BS_THREE && (p - s) < 3))
+ || (*p == ',' && (flags & P_COMMA) && ((p - s) & 1) == 0))
+ {
+ xp->xp_pattern = p + 1;
+ break;
+ }
+ }
+
+#ifdef FEAT_SPELL
+ /* for 'spellsuggest' start at "file:" */
+ if (options[opt_idx].var == (char_u *)&p_sps
+ && STRNCMP(p, "file:", 5) == 0)
+ {
+ xp->xp_pattern = p + 5;
+ break;
+ }
+#endif
+ }
+
+ return;
+}
+
+ int
+ExpandSettings(
+ expand_T *xp,
+ regmatch_T *regmatch,
+ int *num_file,
+ char_u ***file)
+{
+ int num_normal = 0; /* Nr of matching non-term-code settings */
+ int num_term = 0; /* Nr of matching terminal code settings */
+ int opt_idx;
+ int match;
+ int count = 0;
+ char_u *str;
+ int loop;
+ int is_term_opt;
+ char_u name_buf[MAX_KEY_NAME_LEN];
+ static char *(names[]) = {"all", "termcap"};
+ int ic = regmatch->rm_ic; /* remember the ignore-case flag */
+
+ /* do this loop twice:
+ * loop == 0: count the number of matching options
+ * loop == 1: copy the matching options into allocated memory
+ */
+ for (loop = 0; loop <= 1; ++loop)
+ {
+ regmatch->rm_ic = ic;
+ if (xp->xp_context != EXPAND_BOOL_SETTINGS)
+ {
+ for (match = 0; match < (int)(sizeof(names) / sizeof(char *));
+ ++match)
+ if (vim_regexec(regmatch, (char_u *)names[match], (colnr_T)0))
+ {
+ if (loop == 0)
+ num_normal++;
+ else
+ (*file)[count++] = vim_strsave((char_u *)names[match]);
+ }
+ }
+ for (opt_idx = 0; (str = (char_u *)options[opt_idx].fullname) != NULL;
+ opt_idx++)
+ {
+ if (options[opt_idx].var == NULL)
+ continue;
+ if (xp->xp_context == EXPAND_BOOL_SETTINGS
+ && !(options[opt_idx].flags & P_BOOL))
+ continue;
+ is_term_opt = istermoption(&options[opt_idx]);
+ if (is_term_opt && num_normal > 0)
+ continue;
+ match = FALSE;
+ if (vim_regexec(regmatch, str, (colnr_T)0)
+ || (options[opt_idx].shortname != NULL
+ && vim_regexec(regmatch,
+ (char_u *)options[opt_idx].shortname, (colnr_T)0)))
+ match = TRUE;
+ else if (is_term_opt)
+ {
+ name_buf[0] = '<';
+ name_buf[1] = 't';
+ name_buf[2] = '_';
+ name_buf[3] = str[2];
+ name_buf[4] = str[3];
+ name_buf[5] = '>';
+ name_buf[6] = NUL;
+ if (vim_regexec(regmatch, name_buf, (colnr_T)0))
+ {
+ match = TRUE;
+ str = name_buf;
+ }
+ }
+ if (match)
+ {
+ if (loop == 0)
+ {
+ if (is_term_opt)
+ num_term++;
+ else
+ num_normal++;
+ }
+ else
+ (*file)[count++] = vim_strsave(str);
+ }
+ }
+ /*
+ * Check terminal key codes, these are not in the option table
+ */
+ if (xp->xp_context != EXPAND_BOOL_SETTINGS && num_normal == 0)
+ {
+ for (opt_idx = 0; (str = get_termcode(opt_idx)) != NULL; opt_idx++)
+ {
+ if (!isprint(str[0]) || !isprint(str[1]))
+ continue;
+
+ name_buf[0] = 't';
+ name_buf[1] = '_';
+ name_buf[2] = str[0];
+ name_buf[3] = str[1];
+ name_buf[4] = NUL;
+
+ match = FALSE;
+ if (vim_regexec(regmatch, name_buf, (colnr_T)0))
+ match = TRUE;
+ else
+ {
+ name_buf[0] = '<';
+ name_buf[1] = 't';
+ name_buf[2] = '_';
+ name_buf[3] = str[0];
+ name_buf[4] = str[1];
+ name_buf[5] = '>';
+ name_buf[6] = NUL;
+
+ if (vim_regexec(regmatch, name_buf, (colnr_T)0))
+ match = TRUE;
+ }
+ if (match)
+ {
+ if (loop == 0)
+ num_term++;
+ else
+ (*file)[count++] = vim_strsave(name_buf);
+ }
+ }
+
+ /*
+ * Check special key names.
+ */
+ regmatch->rm_ic = TRUE; /* ignore case here */
+ for (opt_idx = 0; (str = get_key_name(opt_idx)) != NULL; opt_idx++)
+ {
+ name_buf[0] = '<';
+ STRCPY(name_buf + 1, str);
+ STRCAT(name_buf, ">");
+
+ if (vim_regexec(regmatch, name_buf, (colnr_T)0))
+ {
+ if (loop == 0)
+ num_term++;
+ else
+ (*file)[count++] = vim_strsave(name_buf);
+ }
+ }
+ }
+ if (loop == 0)
+ {
+ if (num_normal > 0)
+ *num_file = num_normal;
+ else if (num_term > 0)
+ *num_file = num_term;
+ else
+ return OK;
+ *file = (char_u **)alloc((unsigned)(*num_file * sizeof(char_u *)));
+ if (*file == NULL)
+ {
+ *file = (char_u **)"";
+ return FAIL;
+ }
+ }
+ }
+ return OK;
+}
+
+ int
+ExpandOldSetting(int *num_file, char_u ***file)
+{
+ char_u *var = NULL; /* init for GCC */
+ char_u *buf;
+
+ *num_file = 0;
+ *file = (char_u **)alloc((unsigned)sizeof(char_u *));
+ if (*file == NULL)
+ return FAIL;
+
+ /*
+ * For a terminal key code expand_option_idx is < 0.
+ */
+ if (expand_option_idx < 0)
+ {
+ var = find_termcode(expand_option_name + 2);
+ if (var == NULL)
+ expand_option_idx = findoption(expand_option_name);
+ }
+
+ if (expand_option_idx >= 0)
+ {
+ /* put string of option value in NameBuff */
+ option_value2string(&options[expand_option_idx], expand_option_flags);
+ var = NameBuff;
+ }
+ else if (var == NULL)
+ var = (char_u *)"";
+
+ /* A backslash is required before some characters. This is the reverse of
+ * what happens in do_set(). */
+ buf = vim_strsave_escaped(var, escape_chars);
+
+ if (buf == NULL)
+ {
+ VIM_CLEAR(*file);
+ return FAIL;
+ }
+
+#ifdef BACKSLASH_IN_FILENAME
+ /* For MS-Windows et al. we don't double backslashes at the start and
+ * before a file name character. */
+ for (var = buf; *var != NUL; MB_PTR_ADV(var))
+ if (var[0] == '\\' && var[1] == '\\'
+ && expand_option_idx >= 0
+ && (options[expand_option_idx].flags & P_EXPAND)
+ && vim_isfilec(var[2])
+ && (var[2] != '\\' || (var == buf && var[4] != '\\')))
+ STRMOVE(var, var + 1);
+#endif
+
+ *file[0] = buf;
+ *num_file = 1;
+ return OK;
+}
+#endif
+
+/*
+ * Get the value for the numeric or string option *opp in a nice format into
+ * NameBuff[]. Must not be called with a hidden option!
+ */
+ static void
+option_value2string(
+ struct vimoption *opp,
+ int opt_flags) /* OPT_GLOBAL and/or OPT_LOCAL */
+{
+ char_u *varp;
+
+ varp = get_varp_scope(opp, opt_flags);
+
+ if (opp->flags & P_NUM)
+ {
+ long wc = 0;
+
+ if (wc_use_keyname(varp, &wc))
+ STRCPY(NameBuff, get_special_key_name((int)wc, 0));
+ else if (wc != 0)
+ STRCPY(NameBuff, transchar((int)wc));
+ else
+ sprintf((char *)NameBuff, "%ld", *(long *)varp);
+ }
+ else /* P_STRING */
+ {
+ varp = *(char_u **)(varp);
+ if (varp == NULL) /* just in case */
+ NameBuff[0] = NUL;
+#ifdef FEAT_CRYPT
+ /* don't show the actual value of 'key', only that it's set */
+ else if (opp->var == (char_u *)&p_key && *varp)
+ STRCPY(NameBuff, "*****");
+#endif
+ else if (opp->flags & P_EXPAND)
+ home_replace(NULL, varp, NameBuff, MAXPATHL, FALSE);
+ /* Translate 'pastetoggle' into special key names */
+ else if ((char_u **)opp->var == &p_pt)
+ str2specialbuf(p_pt, NameBuff, MAXPATHL);
+ else
+ vim_strncpy(NameBuff, varp, MAXPATHL - 1);
+ }
+}
+
+/*
+ * Return TRUE if "varp" points to 'wildchar' or 'wildcharm' and it can be
+ * printed as a keyname.
+ * "*wcp" is set to the value of the option if it's 'wildchar' or 'wildcharm'.
+ */
+ static int
+wc_use_keyname(char_u *varp, long *wcp)
+{
+ if (((long *)varp == &p_wc) || ((long *)varp == &p_wcm))
+ {
+ *wcp = *(long *)varp;
+ if (IS_SPECIAL(*wcp) || find_special_key_in_table((int)*wcp) >= 0)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+#if defined(FEAT_LANGMAP) || defined(PROTO)
+/*
+ * Any character has an equivalent 'langmap' character. This is used for
+ * keyboards that have a special language mode that sends characters above
+ * 128 (although other characters can be translated too). The "to" field is a
+ * Vim command character. This avoids having to switch the keyboard back to
+ * ASCII mode when leaving Insert mode.
+ *
+ * langmap_mapchar[] maps any of 256 chars to an ASCII char used for Vim
+ * commands.
+ * langmap_mapga.ga_data is a sorted table of langmap_entry_T. This does the
+ * same as langmap_mapchar[] for characters >= 256.
+ *
+ * Use growarray for 'langmap' chars >= 256
+ */
+typedef struct
+{
+ int from;
+ int to;
+} langmap_entry_T;
+
+static garray_T langmap_mapga;
+
+/*
+ * Search for an entry in "langmap_mapga" for "from". If found set the "to"
+ * field. If not found insert a new entry at the appropriate location.
+ */
+ static void
+langmap_set_entry(int from, int to)
+{
+ langmap_entry_T *entries = (langmap_entry_T *)(langmap_mapga.ga_data);
+ int a = 0;
+ int b = langmap_mapga.ga_len;
+
+ /* Do a binary search for an existing entry. */
+ while (a != b)
+ {
+ int i = (a + b) / 2;
+ int d = entries[i].from - from;
+
+ if (d == 0)
+ {
+ entries[i].to = to;
+ return;
+ }
+ if (d < 0)
+ a = i + 1;
+ else
+ b = i;
+ }
+
+ if (ga_grow(&langmap_mapga, 1) != OK)
+ return; /* out of memory */
+
+ /* insert new entry at position "a" */
+ entries = (langmap_entry_T *)(langmap_mapga.ga_data) + a;
+ mch_memmove(entries + 1, entries,
+ (langmap_mapga.ga_len - a) * sizeof(langmap_entry_T));
+ ++langmap_mapga.ga_len;
+ entries[0].from = from;
+ entries[0].to = to;
+}
+
+/*
+ * Apply 'langmap' to multi-byte character "c" and return the result.
+ */
+ int
+langmap_adjust_mb(int c)
+{
+ langmap_entry_T *entries = (langmap_entry_T *)(langmap_mapga.ga_data);
+ int a = 0;
+ int b = langmap_mapga.ga_len;
+
+ while (a != b)
+ {
+ int i = (a + b) / 2;
+ int d = entries[i].from - c;
+
+ if (d == 0)
+ return entries[i].to; /* found matching entry */
+ if (d < 0)
+ a = i + 1;
+ else
+ b = i;
+ }
+ return c; /* no entry found, return "c" unmodified */
+}
+
+ static void
+langmap_init(void)
+{
+ int i;
+
+ for (i = 0; i < 256; i++)
+ langmap_mapchar[i] = i; /* we init with a one-to-one map */
+ ga_init2(&langmap_mapga, sizeof(langmap_entry_T), 8);
+}
+
+/*
+ * Called when langmap option is set; the language map can be
+ * changed at any time!
+ */
+ static void
+langmap_set(void)
+{
+ char_u *p;
+ char_u *p2;
+ int from, to;
+
+ ga_clear(&langmap_mapga); /* clear the previous map first */
+ langmap_init(); /* back to one-to-one map */
+
+ for (p = p_langmap; p[0] != NUL; )
+ {
+ for (p2 = p; p2[0] != NUL && p2[0] != ',' && p2[0] != ';';
+ MB_PTR_ADV(p2))
+ {
+ if (p2[0] == '\\' && p2[1] != NUL)
+ ++p2;
+ }
+ if (p2[0] == ';')
+ ++p2; /* abcd;ABCD form, p2 points to A */
+ else
+ p2 = NULL; /* aAbBcCdD form, p2 is NULL */
+ while (p[0])
+ {
+ if (p[0] == ',')
+ {
+ ++p;
+ break;
+ }
+ if (p[0] == '\\' && p[1] != NUL)
+ ++p;
+ from = (*mb_ptr2char)(p);
+ to = NUL;
+ if (p2 == NULL)
+ {
+ MB_PTR_ADV(p);
+ if (p[0] != ',')
+ {
+ if (p[0] == '\\')
+ ++p;
+ to = (*mb_ptr2char)(p);
+ }
+ }
+ else
+ {
+ if (p2[0] != ',')
+ {
+ if (p2[0] == '\\')
+ ++p2;
+ to = (*mb_ptr2char)(p2);
+ }
+ }
+ if (to == NUL)
+ {
+ semsg(_("E357: 'langmap': Matching character missing for %s"),
+ transchar(from));
+ return;
+ }
+
+ if (from >= 256)
+ langmap_set_entry(from, to);
+ else
+ langmap_mapchar[from & 255] = to;
+
+ /* Advance to next pair */
+ MB_PTR_ADV(p);
+ if (p2 != NULL)
+ {
+ MB_PTR_ADV(p2);
+ if (*p == ';')
+ {
+ p = p2;
+ if (p[0] != NUL)
+ {
+ if (p[0] != ',')
+ {
+ semsg(_("E358: 'langmap': Extra characters after semicolon: %s"), p);
+ return;
+ }
+ ++p;
+ }
+ break;
+ }
+ }
+ }
+ }
+}
+#endif
+
+/*
+ * Return TRUE if format option 'x' is in effect.
+ * Take care of no formatting when 'paste' is set.
+ */
+ int
+has_format_option(int x)
+{
+ if (p_paste)
+ return FALSE;
+ return (vim_strchr(curbuf->b_p_fo, x) != NULL);
+}
+
+/*
+ * Return TRUE if "x" is present in 'shortmess' option, or
+ * 'shortmess' contains 'a' and "x" is present in SHM_A.
+ */
+ int
+shortmess(int x)
+{
+ return p_shm != NULL &&
+ ( vim_strchr(p_shm, x) != NULL
+ || (vim_strchr(p_shm, 'a') != NULL
+ && vim_strchr((char_u *)SHM_A, x) != NULL));
+}
+
+/*
+ * paste_option_changed() - Called after p_paste was set or reset.
+ */
+ static void
+paste_option_changed(void)
+{
+ static int old_p_paste = FALSE;
+ static int save_sm = 0;
+ static int save_sta = 0;
+#ifdef FEAT_CMDL_INFO
+ static int save_ru = 0;
+#endif
+#ifdef FEAT_RIGHTLEFT
+ static int save_ri = 0;
+ static int save_hkmap = 0;
+#endif
+ buf_T *buf;
+
+ if (p_paste)
+ {
+ /*
+ * Paste switched from off to on.
+ * Save the current values, so they can be restored later.
+ */
+ if (!old_p_paste)
+ {
+ /* save options for each buffer */
+ FOR_ALL_BUFFERS(buf)
+ {
+ buf->b_p_tw_nopaste = buf->b_p_tw;
+ buf->b_p_wm_nopaste = buf->b_p_wm;
+ buf->b_p_sts_nopaste = buf->b_p_sts;
+ buf->b_p_ai_nopaste = buf->b_p_ai;
+ buf->b_p_et_nopaste = buf->b_p_et;
+#ifdef FEAT_VARTABS
+ if (buf->b_p_vsts_nopaste)
+ vim_free(buf->b_p_vsts_nopaste);
+ buf->b_p_vsts_nopaste = buf->b_p_vsts && buf->b_p_vsts != empty_option
+ ? vim_strsave(buf->b_p_vsts) : NULL;
+#endif
+ }
+
+ /* save global options */
+ save_sm = p_sm;
+ save_sta = p_sta;
+#ifdef FEAT_CMDL_INFO
+ save_ru = p_ru;
+#endif
+#ifdef FEAT_RIGHTLEFT
+ save_ri = p_ri;
+ save_hkmap = p_hkmap;
+#endif
+ /* save global values for local buffer options */
+ p_ai_nopaste = p_ai;
+ p_et_nopaste = p_et;
+ p_sts_nopaste = p_sts;
+ p_tw_nopaste = p_tw;
+ p_wm_nopaste = p_wm;
+#ifdef FEAT_VARTABS
+ if (p_vsts_nopaste)
+ vim_free(p_vsts_nopaste);
+ p_vsts_nopaste = p_vsts && p_vsts != empty_option ? vim_strsave(p_vsts) : NULL;
+#endif
+ }
+
+ /*
+ * Always set the option values, also when 'paste' is set when it is
+ * already on.
+ */
+ /* set options for each buffer */
+ FOR_ALL_BUFFERS(buf)
+ {
+ buf->b_p_tw = 0; /* textwidth is 0 */
+ buf->b_p_wm = 0; /* wrapmargin is 0 */
+ buf->b_p_sts = 0; /* softtabstop is 0 */
+ buf->b_p_ai = 0; /* no auto-indent */
+ buf->b_p_et = 0; /* no expandtab */
+#ifdef FEAT_VARTABS
+ if (buf->b_p_vsts)
+ free_string_option(buf->b_p_vsts);
+ buf->b_p_vsts = empty_option;
+ if (buf->b_p_vsts_array)
+ vim_free(buf->b_p_vsts_array);
+ buf->b_p_vsts_array = 0;
+#endif
+ }
+
+ /* set global options */
+ p_sm = 0; /* no showmatch */
+ p_sta = 0; /* no smarttab */
+#ifdef FEAT_CMDL_INFO
+ if (p_ru)
+ status_redraw_all(); /* redraw to remove the ruler */
+ p_ru = 0; /* no ruler */
+#endif
+#ifdef FEAT_RIGHTLEFT
+ p_ri = 0; /* no reverse insert */
+ p_hkmap = 0; /* no Hebrew keyboard */
+#endif
+ /* set global values for local buffer options */
+ p_tw = 0;
+ p_wm = 0;
+ p_sts = 0;
+ p_ai = 0;
+#ifdef FEAT_VARTABS
+ if (p_vsts)
+ free_string_option(p_vsts);
+ p_vsts = empty_option;
+#endif
+ }
+
+ /*
+ * Paste switched from on to off: Restore saved values.
+ */
+ else if (old_p_paste)
+ {
+ /* restore options for each buffer */
+ FOR_ALL_BUFFERS(buf)
+ {
+ buf->b_p_tw = buf->b_p_tw_nopaste;
+ buf->b_p_wm = buf->b_p_wm_nopaste;
+ buf->b_p_sts = buf->b_p_sts_nopaste;
+ buf->b_p_ai = buf->b_p_ai_nopaste;
+ buf->b_p_et = buf->b_p_et_nopaste;
+#ifdef FEAT_VARTABS
+ if (buf->b_p_vsts)
+ free_string_option(buf->b_p_vsts);
+ buf->b_p_vsts = buf->b_p_vsts_nopaste
+ ? vim_strsave(buf->b_p_vsts_nopaste) : empty_option;
+ if (buf->b_p_vsts_array)
+ vim_free(buf->b_p_vsts_array);
+ if (buf->b_p_vsts && buf->b_p_vsts != empty_option)
+ tabstop_set(buf->b_p_vsts, &buf->b_p_vsts_array);
+ else
+ buf->b_p_vsts_array = 0;
+#endif
+ }
+
+ /* restore global options */
+ p_sm = save_sm;
+ p_sta = save_sta;
+#ifdef FEAT_CMDL_INFO
+ if (p_ru != save_ru)
+ status_redraw_all(); /* redraw to draw the ruler */
+ p_ru = save_ru;
+#endif
+#ifdef FEAT_RIGHTLEFT
+ p_ri = save_ri;
+ p_hkmap = save_hkmap;
+#endif
+ /* set global values for local buffer options */
+ p_ai = p_ai_nopaste;
+ p_et = p_et_nopaste;
+ p_sts = p_sts_nopaste;
+ p_tw = p_tw_nopaste;
+ p_wm = p_wm_nopaste;
+#ifdef FEAT_VARTABS
+ if (p_vsts)
+ free_string_option(p_vsts);
+ p_vsts = p_vsts_nopaste ? vim_strsave(p_vsts_nopaste) : empty_option;
+#endif
+ }
+
+ old_p_paste = p_paste;
+}
+
+/*
+ * vimrc_found() - Called when a ".vimrc" or "VIMINIT" has been found.
+ *
+ * Reset 'compatible' and set the values for options that didn't get set yet
+ * to the Vim defaults.
+ * Don't do this if the 'compatible' option has been set or reset before.
+ * When "fname" is not NULL, use it to set $"envname" when it wasn't set yet.
+ */
+ void
+vimrc_found(char_u *fname, char_u *envname)
+{
+ int opt_idx;
+ int dofree = FALSE;
+ char_u *p;
+
+ if (!option_was_set((char_u *)"cp"))
+ {
+ p_cp = FALSE;
+ for (opt_idx = 0; !istermoption(&options[opt_idx]); opt_idx++)
+ if (!(options[opt_idx].flags & (P_WAS_SET|P_VI_DEF)))
+ set_option_default(opt_idx, OPT_FREE, FALSE);
+ didset_options();
+ didset_options2();
+ }
+
+ if (fname != NULL)
+ {
+ p = vim_getenv(envname, &dofree);
+ if (p == NULL)
+ {
+ /* Set $MYVIMRC to the first vimrc file found. */
+ p = FullName_save(fname, FALSE);
+ if (p != NULL)
+ {
+ vim_setenv(envname, p);
+ vim_free(p);
+ }
+ }
+ else if (dofree)
+ vim_free(p);
+ }
+}
+
+/*
+ * Set 'compatible' on or off. Called for "-C" and "-N" command line arg.
+ */
+ void
+change_compatible(int on)
+{
+ int opt_idx;
+
+ if (p_cp != on)
+ {
+ p_cp = on;
+ compatible_set();
+ }
+ opt_idx = findoption((char_u *)"cp");
+ if (opt_idx >= 0)
+ options[opt_idx].flags |= P_WAS_SET;
+}
+
+/*
+ * Return TRUE when option "name" has been set.
+ * Only works correctly for global options.
+ */
+ int
+option_was_set(char_u *name)
+{
+ int idx;
+
+ idx = findoption(name);
+ if (idx < 0) /* unknown option */
+ return FALSE;
+ if (options[idx].flags & P_WAS_SET)
+ return TRUE;
+ return FALSE;
+}
+
+/*
+ * Reset the flag indicating option "name" was set.
+ */
+ int
+reset_option_was_set(char_u *name)
+{
+ int idx = findoption(name);
+
+ if (idx >= 0)
+ {
+ options[idx].flags &= ~P_WAS_SET;
+ return OK;
+ }
+ return FAIL;
+}
+
+/*
+ * compatible_set() - Called when 'compatible' has been set or unset.
+ *
+ * When 'compatible' set: Set all relevant options (those that have the P_VIM)
+ * flag) to a Vi compatible value.
+ * When 'compatible' is unset: Set all options that have a different default
+ * for Vim (without the P_VI_DEF flag) to that default.
+ */
+ static void
+compatible_set(void)
+{
+ int opt_idx;
+
+ for (opt_idx = 0; !istermoption(&options[opt_idx]); opt_idx++)
+ if ( ((options[opt_idx].flags & P_VIM) && p_cp)
+ || (!(options[opt_idx].flags & P_VI_DEF) && !p_cp))
+ set_option_default(opt_idx, OPT_FREE, p_cp);
+ didset_options();
+ didset_options2();
+}
+
+#ifdef FEAT_LINEBREAK
+
+# if defined(__BORLANDC__) && (__BORLANDC__ < 0x500)
+ /* Borland C++ screws up loop optimisation here (negri) */
+ #pragma option -O-l
+# endif
+
+/*
+ * fill_breakat_flags() -- called when 'breakat' changes value.
+ */
+ static void
+fill_breakat_flags(void)
+{
+ char_u *p;
+ int i;
+
+ for (i = 0; i < 256; i++)
+ breakat_flags[i] = FALSE;
+
+ if (p_breakat != NULL)
+ for (p = p_breakat; *p; p++)
+ breakat_flags[*p] = TRUE;
+}
+
+# if defined(__BORLANDC__) && (__BORLANDC__ < 0x500)
+ #pragma option -O.l
+# endif
+
+#endif
+
+/*
+ * Check an option that can be a range of string values.
+ *
+ * Return OK for correct value, FAIL otherwise.
+ * Empty is always OK.
+ */
+ static int
+check_opt_strings(
+ char_u *val,
+ char **values,
+ int list) /* when TRUE: accept a list of values */
+{
+ return opt_strings_flags(val, values, NULL, list);
+}
+
+/*
+ * Handle an option that can be a range of string values.
+ * Set a flag in "*flagp" for each string present.
+ *
+ * Return OK for correct value, FAIL otherwise.
+ * Empty is always OK.
+ */
+ static int
+opt_strings_flags(
+ char_u *val, /* new value */
+ char **values, /* array of valid string values */
+ unsigned *flagp,
+ int list) /* when TRUE: accept a list of values */
+{
+ int i;
+ int len;
+ unsigned new_flags = 0;
+
+ while (*val)
+ {
+ for (i = 0; ; ++i)
+ {
+ if (values[i] == NULL) /* val not found in values[] */
+ return FAIL;
+
+ len = (int)STRLEN(values[i]);
+ if (STRNCMP(values[i], val, len) == 0
+ && ((list && val[len] == ',') || val[len] == NUL))
+ {
+ val += len + (val[len] == ',');
+ new_flags |= (1 << i);
+ break; /* check next item in val list */
+ }
+ }
+ }
+ if (flagp != NULL)
+ *flagp = new_flags;
+
+ return OK;
+}
+
+/*
+ * Read the 'wildmode' option, fill wim_flags[].
+ */
+ static int
+check_opt_wim(void)
+{
+ char_u new_wim_flags[4];
+ char_u *p;
+ int i;
+ int idx = 0;
+
+ for (i = 0; i < 4; ++i)
+ new_wim_flags[i] = 0;
+
+ for (p = p_wim; *p; ++p)
+ {
+ for (i = 0; ASCII_ISALPHA(p[i]); ++i)
+ ;
+ if (p[i] != NUL && p[i] != ',' && p[i] != ':')
+ return FAIL;
+ if (i == 7 && STRNCMP(p, "longest", 7) == 0)
+ new_wim_flags[idx] |= WIM_LONGEST;
+ else if (i == 4 && STRNCMP(p, "full", 4) == 0)
+ new_wim_flags[idx] |= WIM_FULL;
+ else if (i == 4 && STRNCMP(p, "list", 4) == 0)
+ new_wim_flags[idx] |= WIM_LIST;
+ else
+ return FAIL;
+ p += i;
+ if (*p == NUL)
+ break;
+ if (*p == ',')
+ {
+ if (idx == 3)
+ return FAIL;
+ ++idx;
+ }
+ }
+
+ /* fill remaining entries with last flag */
+ while (idx < 3)
+ {
+ new_wim_flags[idx + 1] = new_wim_flags[idx];
+ ++idx;
+ }
+
+ /* only when there are no errors, wim_flags[] is changed */
+ for (i = 0; i < 4; ++i)
+ wim_flags[i] = new_wim_flags[i];
+ return OK;
+}
+
+/*
+ * Check if backspacing over something is allowed.
+ */
+ int
+can_bs(
+ int what) /* BS_INDENT, BS_EOL or BS_START */
+{
+#ifdef FEAT_JOB_CHANNEL
+ if (what == BS_START && bt_prompt(curbuf))
+ return FALSE;
+#endif
+ switch (*p_bs)
+ {
+ case '2': return TRUE;
+ case '1': return (what != BS_START);
+ case '0': return FALSE;
+ }
+ return vim_strchr(p_bs, what) != NULL;
+}
+
+/*
+ * Save the current values of 'fileformat' and 'fileencoding', so that we know
+ * the file must be considered changed when the value is different.
+ */
+ void
+save_file_ff(buf_T *buf)
+{
+ buf->b_start_ffc = *buf->b_p_ff;
+ buf->b_start_eol = buf->b_p_eol;
+ buf->b_start_bomb = buf->b_p_bomb;
+
+ /* Only use free/alloc when necessary, they take time. */
+ if (buf->b_start_fenc == NULL
+ || STRCMP(buf->b_start_fenc, buf->b_p_fenc) != 0)
+ {
+ vim_free(buf->b_start_fenc);
+ buf->b_start_fenc = vim_strsave(buf->b_p_fenc);
+ }
+}
+
+/*
+ * Return TRUE if 'fileformat' and/or 'fileencoding' has a different value
+ * from when editing started (save_file_ff() called).
+ * Also when 'endofline' was changed and 'binary' is set, or when 'bomb' was
+ * changed and 'binary' is not set.
+ * Also when 'endofline' was changed and 'fixeol' is not set.
+ * When "ignore_empty" is true don't consider a new, empty buffer to be
+ * changed.
+ */
+ int
+file_ff_differs(buf_T *buf, int ignore_empty)
+{
+ /* In a buffer that was never loaded the options are not valid. */
+ if (buf->b_flags & BF_NEVERLOADED)
+ return FALSE;
+ if (ignore_empty
+ && (buf->b_flags & BF_NEW)
+ && buf->b_ml.ml_line_count == 1
+ && *ml_get_buf(buf, (linenr_T)1, FALSE) == NUL)
+ return FALSE;
+ if (buf->b_start_ffc != *buf->b_p_ff)
+ return TRUE;
+ if ((buf->b_p_bin || !buf->b_p_fixeol) && buf->b_start_eol != buf->b_p_eol)
+ return TRUE;
+ if (!buf->b_p_bin && buf->b_start_bomb != buf->b_p_bomb)
+ return TRUE;
+ if (buf->b_start_fenc == NULL)
+ return (*buf->b_p_fenc != NUL);
+ return (STRCMP(buf->b_start_fenc, buf->b_p_fenc) != 0);
+}
+
+/*
+ * return OK if "p" is a valid fileformat name, FAIL otherwise.
+ */
+ int
+check_ff_value(char_u *p)
+{
+ return check_opt_strings(p, p_ff_values, FALSE);
+}
+
+#ifdef FEAT_VARTABS
+
+/*
+ * Set the integer values corresponding to the string setting of 'vartabstop'.
+ */
+ int
+tabstop_set(char_u *var, int **array)
+{
+ int valcount = 1;
+ int t;
+ char_u *cp;
+
+ if (var[0] == NUL || (var[0] == '0' && var[1] == NUL))
+ {
+ *array = NULL;
+ return TRUE;
+ }
+
+ for (cp = var; *cp != NUL; ++cp)
+ {
+ if (cp == var || cp[-1] == ',')
+ {
+ char_u *end;
+
+ if (strtol((char *)cp, (char **)&end, 10) <= 0)
+ {
+ if (cp != end)
+ emsg(_(e_positive));
+ else
+ emsg(_(e_invarg));
+ return FALSE;
+ }
+ }
+
+ if (VIM_ISDIGIT(*cp))
+ continue;
+ if (cp[0] == ',' && cp > var && cp[-1] != ',' && cp[1] != NUL)
+ {
+ ++valcount;
+ continue;
+ }
+ emsg(_(e_invarg));
+ return FALSE;
+ }
+
+ *array = (int *)alloc((unsigned) ((valcount + 1) * sizeof(int)));
+ (*array)[0] = valcount;
+
+ t = 1;
+ for (cp = var; *cp != NUL;)
+ {
+ (*array)[t++] = atoi((char *)cp);
+ while (*cp != NUL && *cp != ',')
+ ++cp;
+ if (*cp != NUL)
+ ++cp;
+ }
+
+ return TRUE;
+}
+
+/*
+ * Calculate the number of screen spaces a tab will occupy.
+ * If "vts" is set then the tab widths are taken from that array,
+ * otherwise the value of ts is used.
+ */
+ int
+tabstop_padding(colnr_T col, int ts_arg, int *vts)
+{
+ int ts = ts_arg == 0 ? 8 : ts_arg;
+ int tabcount;
+ colnr_T tabcol = 0;
+ int t;
+ int padding = 0;
+
+ if (vts == NULL || vts[0] == 0)
+ return ts - (col % ts);
+
+ tabcount = vts[0];
+
+ for (t = 1; t <= tabcount; ++t)
+ {
+ tabcol += vts[t];
+ if (tabcol > col)
+ {
+ padding = (int)(tabcol - col);
+ break;
+ }
+ }
+ if (t > tabcount)
+ padding = vts[tabcount] - (int)((col - tabcol) % vts[tabcount]);
+
+ return padding;
+}
+
+/*
+ * Find the size of the tab that covers a particular column.
+ */
+ int
+tabstop_at(colnr_T col, int ts, int *vts)
+{
+ int tabcount;
+ colnr_T tabcol = 0;
+ int t;
+ int tab_size = 0;
+
+ if (vts == 0 || vts[0] == 0)
+ return ts;
+
+ tabcount = vts[0];
+ for (t = 1; t <= tabcount; ++t)
+ {
+ tabcol += vts[t];
+ if (tabcol > col)
+ {
+ tab_size = vts[t];
+ break;
+ }
+ }
+ if (t > tabcount)
+ tab_size = vts[tabcount];
+
+ return tab_size;
+}
+
+/*
+ * Find the column on which a tab starts.
+ */
+ colnr_T
+tabstop_start(colnr_T col, int ts, int *vts)
+{
+ int tabcount;
+ colnr_T tabcol = 0;
+ int t;
+ int excess;
+
+ if (vts == NULL || vts[0] == 0)
+ return (col / ts) * ts;
+
+ tabcount = vts[0];
+ for (t = 1; t <= tabcount; ++t)
+ {
+ tabcol += vts[t];
+ if (tabcol > col)
+ return tabcol - vts[t];
+ }
+
+ excess = tabcol % vts[tabcount];
+ return excess + ((col - excess) / vts[tabcount]) * vts[tabcount];
+}
+
+/*
+ * Find the number of tabs and spaces necessary to get from one column
+ * to another.
+ */
+ void
+tabstop_fromto(
+ colnr_T start_col,
+ colnr_T end_col,
+ int ts_arg,
+ int *vts,
+ int *ntabs,
+ int *nspcs)
+{
+ int spaces = end_col - start_col;
+ colnr_T tabcol = 0;
+ int padding = 0;
+ int tabcount;
+ int t;
+ int ts = ts_arg == 0 ? curbuf->b_p_ts : ts_arg;
+
+ if (vts == NULL || vts[0] == 0)
+ {
+ int tabs = 0;
+ int initspc = 0;
+
+ initspc = ts - (start_col % ts);
+ if (spaces >= initspc)
+ {
+ spaces -= initspc;
+ tabs++;
+ }
+ tabs += spaces / ts;
+ spaces -= (spaces / ts) * ts;
+
+ *ntabs = tabs;
+ *nspcs = spaces;
+ return;
+ }
+
+ /* Find the padding needed to reach the next tabstop. */
+ tabcount = vts[0];
+ for (t = 1; t <= tabcount; ++t)
+ {
+ tabcol += vts[t];
+ if (tabcol > start_col)
+ {
+ padding = (int)(tabcol - start_col);
+ break;
+ }
+ }
+ if (t > tabcount)
+ padding = vts[tabcount] - (int)((start_col - tabcol) % vts[tabcount]);
+
+ /* If the space needed is less than the padding no tabs can be used. */
+ if (spaces < padding)
+ {
+ *ntabs = 0;
+ *nspcs = spaces;
+ return;
+ }
+
+ *ntabs = 1;
+ spaces -= padding;
+
+ /* At least one tab has been used. See if any more will fit. */
+ while (spaces != 0 && ++t <= tabcount)
+ {
+ padding = vts[t];
+ if (spaces < padding)
+ {
+ *nspcs = spaces;
+ return;
+ }
+ ++*ntabs;
+ spaces -= padding;
+ }
+
+ *ntabs += spaces / vts[tabcount];
+ *nspcs = spaces % vts[tabcount];
+}
+
+/*
+ * See if two tabstop arrays contain the same values.
+ */
+ int
+tabstop_eq(int *ts1, int *ts2)
+{
+ int t;
+
+ if ((ts1 == 0 && ts2) || (ts1 && ts2 == 0))
+ return FALSE;
+ if (ts1 == ts2)
+ return TRUE;
+ if (ts1[0] != ts2[0])
+ return FALSE;
+
+ for (t = 1; t <= ts1[0]; ++t)
+ if (ts1[t] != ts2[t])
+ return FALSE;
+
+ return TRUE;
+}
+
+#if defined(FEAT_BEVAL) || defined(PROTO)
+/*
+ * Copy a tabstop array, allocating space for the new array.
+ */
+ int *
+tabstop_copy(int *oldts)
+{
+ int *newts;
+ int t;
+
+ if (oldts == 0)
+ return 0;
+
+ newts = (int *) alloc((unsigned) ((oldts[0] + 1) * sizeof(int)));
+ for (t = 0; t <= oldts[0]; ++t)
+ newts[t] = oldts[t];
+
+ return newts;
+}
+#endif
+
+/*
+ * Return a count of the number of tabstops.
+ */
+ int
+tabstop_count(int *ts)
+{
+ return ts != NULL ? ts[0] : 0;
+}
+
+/*
+ * Return the first tabstop, or 8 if there are no tabstops defined.
+ */
+ int
+tabstop_first(int *ts)
+{
+ return ts != NULL ? ts[1] : 8;
+}
+
+#endif
+
+/*
+ * Return the effective shiftwidth value for current buffer, using the
+ * 'tabstop' value when 'shiftwidth' is zero.
+ */
+ long
+get_sw_value(buf_T *buf)
+{
+ return get_sw_value_col(buf, 0);
+}
+
+/*
+ * Idem, using the first non-black in the current line.
+ */
+ long
+get_sw_value_indent(buf_T *buf)
+{
+ pos_T pos = curwin->w_cursor;
+
+ pos.col = getwhitecols_curline();
+ return get_sw_value_pos(buf, &pos);
+}
+
+/*
+ * Idem, using "pos".
+ */
+ long
+get_sw_value_pos(buf_T *buf, pos_T *pos)
+{
+ pos_T save_cursor = curwin->w_cursor;
+ long sw_value;
+
+ curwin->w_cursor = *pos;
+ sw_value = get_sw_value_col(buf, get_nolist_virtcol());
+ curwin->w_cursor = save_cursor;
+ return sw_value;
+}
+
+/*
+ * Idem, using virtual column "col".
+ */
+ long
+get_sw_value_col(buf_T *buf, colnr_T col UNUSED)
+{
+ return buf->b_p_sw ? buf->b_p_sw :
+ #ifdef FEAT_VARTABS
+ tabstop_at(col, buf->b_p_ts, buf->b_p_vts_array);
+ #else
+ buf->b_p_ts;
+ #endif
+}
+
+/*
+ * Return the effective softtabstop value for the current buffer, using the
+ * 'shiftwidth' value when 'softtabstop' is negative.
+ */
+ long
+get_sts_value(void)
+{
+ return curbuf->b_p_sts < 0 ? get_sw_value(curbuf) : curbuf->b_p_sts;
+}
+
+/*
+ * Return the effective 'scrolloff' value for the current window, using the
+ * global value when appropriate.
+ */
+ long
+get_scrolloff_value(void)
+{
+ return curwin->w_p_so < 0 ? p_so : curwin->w_p_so;
+}
+
+/*
+ * Return the effective 'sidescrolloff' value for the current window, using the
+ * global value when appropriate.
+ */
+ long
+get_sidescrolloff_value(void)
+{
+ return curwin->w_p_siso < 0 ? p_siso : curwin->w_p_siso;
+}
+
+/*
+ * Check matchpairs option for "*initc".
+ * If there is a match set "*initc" to the matching character and "*findc" to
+ * the opposite character. Set "*backwards" to the direction.
+ * When "switchit" is TRUE swap the direction.
+ */
+ void
+find_mps_values(
+ int *initc,
+ int *findc,
+ int *backwards,
+ int switchit)
+{
+ char_u *ptr;
+
+ ptr = curbuf->b_p_mps;
+ while (*ptr != NUL)
+ {
+ if (has_mbyte)
+ {
+ char_u *prev;
+
+ if (mb_ptr2char(ptr) == *initc)
+ {
+ if (switchit)
+ {
+ *findc = *initc;
+ *initc = mb_ptr2char(ptr + mb_ptr2len(ptr) + 1);
+ *backwards = TRUE;
+ }
+ else
+ {
+ *findc = mb_ptr2char(ptr + mb_ptr2len(ptr) + 1);
+ *backwards = FALSE;
+ }
+ return;
+ }
+ prev = ptr;
+ ptr += mb_ptr2len(ptr) + 1;
+ if (mb_ptr2char(ptr) == *initc)
+ {
+ if (switchit)
+ {
+ *findc = *initc;
+ *initc = mb_ptr2char(prev);
+ *backwards = FALSE;
+ }
+ else
+ {
+ *findc = mb_ptr2char(prev);
+ *backwards = TRUE;
+ }
+ return;
+ }
+ ptr += mb_ptr2len(ptr);
+ }
+ else
+ {
+ if (*ptr == *initc)
+ {
+ if (switchit)
+ {
+ *backwards = TRUE;
+ *findc = *initc;
+ *initc = ptr[2];
+ }
+ else
+ {
+ *backwards = FALSE;
+ *findc = ptr[2];
+ }
+ return;
+ }
+ ptr += 2;
+ if (*ptr == *initc)
+ {
+ if (switchit)
+ {
+ *backwards = FALSE;
+ *findc = *initc;
+ *initc = ptr[-2];
+ }
+ else
+ {
+ *backwards = TRUE;
+ *findc = ptr[-2];
+ }
+ return;
+ }
+ ++ptr;
+ }
+ if (*ptr == ',')
+ ++ptr;
+ }
+}
+
+#if defined(FEAT_LINEBREAK) || defined(PROTO)
+/*
+ * This is called when 'breakindentopt' is changed and when a window is
+ * initialized.
+ */
+ static int
+briopt_check(win_T *wp)
+{
+ char_u *p;
+ int bri_shift = 0;
+ long bri_min = 20;
+ int bri_sbr = FALSE;
+
+ p = wp->w_p_briopt;
+ while (*p != NUL)
+ {
+ if (STRNCMP(p, "shift:", 6) == 0
+ && ((p[6] == '-' && VIM_ISDIGIT(p[7])) || VIM_ISDIGIT(p[6])))
+ {
+ p += 6;
+ bri_shift = getdigits(&p);
+ }
+ else if (STRNCMP(p, "min:", 4) == 0 && VIM_ISDIGIT(p[4]))
+ {
+ p += 4;
+ bri_min = getdigits(&p);
+ }
+ else if (STRNCMP(p, "sbr", 3) == 0)
+ {
+ p += 3;
+ bri_sbr = TRUE;
+ }
+ if (*p != ',' && *p != NUL)
+ return FAIL;
+ if (*p == ',')
+ ++p;
+ }
+
+ wp->w_p_brishift = bri_shift;
+ wp->w_p_brimin = bri_min;
+ wp->w_p_brisbr = bri_sbr;
+
+ return OK;
+}
+#endif
+
+/*
+ * Get the local or global value of 'backupcopy'.
+ */
+ unsigned int
+get_bkc_value(buf_T *buf)
+{
+ return buf->b_bkc_flags ? buf->b_bkc_flags : bkc_flags;
+}
+
+#if defined(FEAT_SIGNS) || defined(PROTO)
+/*
+ * Return TRUE when window "wp" has a column to draw signs in.
+ */
+ int
+signcolumn_on(win_T *wp)
+{
+ if (*wp->w_p_scl == 'n')
+ return FALSE;
+ if (*wp->w_p_scl == 'y')
+ return TRUE;
+ return (wp->w_buffer->b_signlist != NULL
+# ifdef FEAT_NETBEANS_INTG
+ || wp->w_buffer->b_has_sign_column
+# endif
+ );
+}
+#endif
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * Get window or buffer local options.
+ */
+ dict_T *
+get_winbuf_options(int bufopt)
+{
+ dict_T *d;
+ int opt_idx;
+
+ d = dict_alloc();
+ if (d == NULL)
+ return NULL;
+
+ for (opt_idx = 0; !istermoption(&options[opt_idx]); opt_idx++)
+ {
+ struct vimoption *opt = &options[opt_idx];
+
+ if ((bufopt && (opt->indir & PV_BUF))
+ || (!bufopt && (opt->indir & PV_WIN)))
+ {
+ char_u *varp = get_varp(opt);
+
+ if (varp != NULL)
+ {
+ if (opt->flags & P_STRING)
+ dict_add_string(d, opt->fullname, *(char_u **)varp);
+ else if (opt->flags & P_NUM)
+ dict_add_number(d, opt->fullname, *(long *)varp);
+ else
+ dict_add_number(d, opt->fullname, *(int *)varp);
+ }
+ }
+ }
+
+ return d;
+}
+#endif
diff --git a/src/option.h b/src/option.h
new file mode 100644
index 0000000..2985781
--- /dev/null
+++ b/src/option.h
@@ -0,0 +1,1179 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * Do ":help uganda" in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ */
+
+/*
+ * option.h: definition of global variables for settable options
+ */
+
+/*
+ * Default values for 'errorformat'.
+ * The "%f|%l| %m" one is used for when the contents of the quickfix window is
+ * written to a file.
+ */
+#ifdef AMIGA
+# define DFLT_EFM "%f>%l:%c:%t:%n:%m,%f:%l: %t%*\\D%n: %m,%f %l %t%*\\D%n: %m,%*[^\"]\"%f\"%*\\D%l: %m,%f:%l:%m,%f|%l| %m"
+#else
+# if defined(WIN3264)
+# define DFLT_EFM "%f(%l) \\=: %t%*\\D%n: %m,%*[^\"]\"%f\"%*\\D%l: %m,%f(%l) \\=: %m,%*[^ ] %f %l: %m,%f:%l:%c:%m,%f(%l):%m,%f:%l:%m,%f|%l| %m"
+# else
+# if defined(__QNX__)
+# define DFLT_EFM "%f(%l):%*[^WE]%t%*\\D%n:%m,%f|%l| %m"
+# else
+# ifdef VMS
+# define DFLT_EFM "%A%p^,%C%%CC-%t-%m,%Cat line number %l in file %f,%f|%l| %m"
+# else /* Unix, probably */
+# ifdef EBCDIC
+#define DFLT_EFM "%*[^ ] %*[^ ] %f:%l%*[ ]%m,%*[^\"]\"%f\"%*\\D%l: %m,\"%f\"%*\\D%l: %m,%f:%l:%c:%m,%f(%l):%m,%f:%l:%m,\"%f\"\\, line %l%*\\D%c%*[^ ] %m,%D%*\\a[%*\\d]: Entering directory %*[`']%f',%X%*\\a[%*\\d]: Leaving directory %*[`']%f',%DMaking %*\\a in %f,%f|%l| %m"
+# else
+#define DFLT_EFM "%*[^\"]\"%f\"%*\\D%l: %m,\"%f\"%*\\D%l: %m,%-G%f:%l: (Each undeclared identifier is reported only once,%-G%f:%l: for each function it appears in.),%-GIn file included from %f:%l:%c:,%-GIn file included from %f:%l:%c\\,,%-GIn file included from %f:%l:%c,%-GIn file included from %f:%l,%-G%*[ ]from %f:%l:%c,%-G%*[ ]from %f:%l:,%-G%*[ ]from %f:%l\\,,%-G%*[ ]from %f:%l,%f:%l:%c:%m,%f(%l):%m,%f:%l:%m,\"%f\"\\, line %l%*\\D%c%*[^ ] %m,%D%*\\a[%*\\d]: Entering directory %*[`']%f',%X%*\\a[%*\\d]: Leaving directory %*[`']%f',%D%*\\a: Entering directory %*[`']%f',%X%*\\a: Leaving directory %*[`']%f',%DMaking %*\\a in %f,%f|%l| %m"
+# endif
+# endif
+# endif
+# endif
+#endif
+
+#define DFLT_GREPFORMAT "%f:%l:%m,%f:%l%m,%f %l%m"
+
+/* default values for b_p_ff 'fileformat' and p_ffs 'fileformats' */
+#define FF_DOS "dos"
+#define FF_MAC "mac"
+#define FF_UNIX "unix"
+
+#ifdef USE_CRNL
+# define DFLT_FF "dos"
+# define DFLT_FFS_VIM "dos,unix"
+# define DFLT_FFS_VI "dos,unix" /* also autodetect in compatible mode */
+# define DFLT_TEXTAUTO TRUE
+#else
+# ifdef USE_CR
+# define DFLT_FF "mac"
+# define DFLT_FFS_VIM "mac,unix,dos"
+# define DFLT_FFS_VI "mac,unix,dos"
+# define DFLT_TEXTAUTO TRUE
+# else
+# define DFLT_FF "unix"
+# define DFLT_FFS_VIM "unix,dos"
+# ifdef __CYGWIN__
+# define DFLT_FFS_VI "unix,dos" /* Cygwin always needs file detection */
+# define DFLT_TEXTAUTO TRUE
+# else
+# define DFLT_FFS_VI ""
+# define DFLT_TEXTAUTO FALSE
+# endif
+# endif
+#endif
+
+
+/* Possible values for 'encoding' */
+#define ENC_UCSBOM "ucs-bom" /* check for BOM at start of file */
+
+/* default value for 'encoding' */
+#define ENC_DFLT "latin1"
+
+/* end-of-line style */
+#define EOL_UNKNOWN -1 /* not defined yet */
+#define EOL_UNIX 0 /* NL */
+#define EOL_DOS 1 /* CR NL */
+#define EOL_MAC 2 /* CR */
+
+/* Formatting options for p_fo 'formatoptions' */
+#define FO_WRAP 't'
+#define FO_WRAP_COMS 'c'
+#define FO_RET_COMS 'r'
+#define FO_OPEN_COMS 'o'
+#define FO_Q_COMS 'q'
+#define FO_Q_NUMBER 'n'
+#define FO_Q_SECOND '2'
+#define FO_INS_VI 'v'
+#define FO_INS_LONG 'l'
+#define FO_INS_BLANK 'b'
+#define FO_MBYTE_BREAK 'm' /* break before/after multi-byte char */
+#define FO_MBYTE_JOIN 'M' /* no space before/after multi-byte char */
+#define FO_MBYTE_JOIN2 'B' /* no space between multi-byte chars */
+#define FO_ONE_LETTER '1'
+#define FO_WHITE_PAR 'w' /* trailing white space continues paragr. */
+#define FO_AUTO 'a' /* automatic formatting */
+#define FO_REMOVE_COMS 'j' /* remove comment leaders when joining lines */
+#define FO_PERIOD_ABBR 'p' /* don't break a single space after a period */
+
+#define DFLT_FO_VI "vt"
+#define DFLT_FO_VIM "tcq"
+#define FO_ALL "tcroq2vlb1mMBn,awjp" /* for do_set() */
+
+/* characters for the p_cpo option: */
+#define CPO_ALTREAD 'a' /* ":read" sets alternate file name */
+#define CPO_ALTWRITE 'A' /* ":write" sets alternate file name */
+#define CPO_BAR 'b' /* "\|" ends a mapping */
+#define CPO_BSLASH 'B' /* backslash in mapping is not special */
+#define CPO_SEARCH 'c'
+#define CPO_CONCAT 'C' /* Don't concatenate sourced lines */
+#define CPO_DOTTAG 'd' /* "./tags" in 'tags' is in current dir */
+#define CPO_DIGRAPH 'D' /* No digraph after "r", "f", etc. */
+#define CPO_EXECBUF 'e'
+#define CPO_EMPTYREGION 'E' /* operating on empty region is an error */
+#define CPO_FNAMER 'f' /* set file name for ":r file" */
+#define CPO_FNAMEW 'F' /* set file name for ":w file" */
+#define CPO_GOTO1 'g' /* goto line 1 for ":edit" */
+#define CPO_INSEND 'H' /* "I" inserts before last blank in line */
+#define CPO_INTMOD 'i' /* interrupt a read makes buffer modified */
+#define CPO_INDENT 'I' /* remove auto-indent more often */
+#define CPO_JOINSP 'j' /* only use two spaces for join after '.' */
+#define CPO_ENDOFSENT 'J' /* need two spaces to detect end of sentence */
+#define CPO_KEYCODE 'k' /* don't recognize raw key code in mappings */
+#define CPO_KOFFSET 'K' /* don't wait for key code in mappings */
+#define CPO_LITERAL 'l' /* take char after backslash in [] literal */
+#define CPO_LISTWM 'L' /* 'list' changes wrapmargin */
+#define CPO_SHOWMATCH 'm'
+#define CPO_MATCHBSL 'M' /* "%" ignores use of backslashes */
+#define CPO_NUMCOL 'n' /* 'number' column also used for text */
+#define CPO_LINEOFF 'o'
+#define CPO_OVERNEW 'O' /* silently overwrite new file */
+#define CPO_LISP 'p' /* 'lisp' indenting */
+#define CPO_FNAMEAPP 'P' /* set file name for ":w >>file" */
+#define CPO_JOINCOL 'q' /* with "3J" use column after first join */
+#define CPO_REDO 'r'
+#define CPO_REMMARK 'R' /* remove marks when filtering */
+#define CPO_BUFOPT 's'
+#define CPO_BUFOPTGLOB 'S'
+#define CPO_TAGPAT 't'
+#define CPO_UNDO 'u' /* "u" undoes itself */
+#define CPO_BACKSPACE 'v' /* "v" keep deleted text */
+#define CPO_CW 'w' /* "cw" only changes one blank */
+#define CPO_FWRITE 'W' /* "w!" doesn't overwrite readonly files */
+#define CPO_ESC 'x'
+#define CPO_REPLCNT 'X' /* "R" with a count only deletes chars once */
+#define CPO_YANK 'y'
+#define CPO_KEEPRO 'Z' /* don't reset 'readonly' on ":w!" */
+#define CPO_DOLLAR '$'
+#define CPO_FILTER '!'
+#define CPO_MATCH '%'
+#define CPO_STAR '*' /* ":*" means ":@" */
+#define CPO_PLUS '+' /* ":write file" resets 'modified' */
+#define CPO_MINUS '-' /* "9-" fails at and before line 9 */
+#define CPO_SPECI '<' /* don't recognize <> in mappings */
+#define CPO_REGAPPEND '>' /* insert NL when appending to a register */
+/* POSIX flags */
+#define CPO_HASH '#' /* "D", "o" and "O" do not use a count */
+#define CPO_PARA '{' /* "{" is also a paragraph boundary */
+#define CPO_TSIZE '|' /* $LINES and $COLUMNS overrule term size */
+#define CPO_PRESERVE '&' /* keep swap file after :preserve */
+#define CPO_SUBPERCENT '/' /* % in :s string uses previous one */
+#define CPO_BACKSL '\\' /* \ is not special in [] */
+#define CPO_CHDIR '.' /* don't chdir if buffer is modified */
+#define CPO_SCOLON ';' /* using "," and ";" will skip over char if
+ * cursor would not move */
+/* default values for Vim, Vi and POSIX */
+#define CPO_VIM "aABceFs"
+#define CPO_VI "aAbBcCdDeEfFgHiIjJkKlLmMnoOpPqrRsStuvwWxXyZ$!%*-+<>;"
+#define CPO_ALL "aAbBcCdDeEfFgHiIjJkKlLmMnoOpPqrRsStuvwWxXyZ$!%*-+<>#{|&/\\.;"
+
+/* characters for p_ww option: */
+#define WW_ALL "bshl<>[],~"
+
+/* characters for p_mouse option: */
+#define MOUSE_NORMAL 'n' /* use mouse in Normal mode */
+#define MOUSE_VISUAL 'v' /* use mouse in Visual/Select mode */
+#define MOUSE_INSERT 'i' /* use mouse in Insert mode */
+#define MOUSE_COMMAND 'c' /* use mouse in Command-line mode */
+#define MOUSE_HELP 'h' /* use mouse in help buffers */
+#define MOUSE_RETURN 'r' /* use mouse for hit-return message */
+#define MOUSE_A "nvich" /* used for 'a' flag */
+#define MOUSE_ALL "anvichr" /* all possible characters */
+#define MOUSE_NONE ' ' /* don't use Visual selection */
+#define MOUSE_NONEF 'x' /* forced modeless selection */
+
+#define COCU_ALL "nvic" /* flags for 'concealcursor' */
+
+/* characters for p_shm option: */
+#define SHM_RO 'r' /* readonly */
+#define SHM_MOD 'm' /* modified */
+#define SHM_FILE 'f' /* (file 1 of 2) */
+#define SHM_LAST 'i' /* last line incomplete */
+#define SHM_TEXT 'x' /* tx instead of textmode */
+#define SHM_LINES 'l' /* "L" instead of "lines" */
+#define SHM_NEW 'n' /* "[New]" instead of "[New file]" */
+#define SHM_WRI 'w' /* "[w]" instead of "written" */
+#define SHM_A "rmfixlnw" /* represented by 'a' flag */
+#define SHM_WRITE 'W' /* don't use "written" at all */
+#define SHM_TRUNC 't' /* trunctate file messages */
+#define SHM_TRUNCALL 'T' /* trunctate all messages */
+#define SHM_OVER 'o' /* overwrite file messages */
+#define SHM_OVERALL 'O' /* overwrite more messages */
+#define SHM_SEARCH 's' /* no search hit bottom messages */
+#define SHM_ATTENTION 'A' /* no ATTENTION messages */
+#define SHM_INTRO 'I' /* intro messages */
+#define SHM_COMPLETIONMENU 'c' /* completion menu messages */
+#define SHM_RECORDING 'q' /* short recording message */
+#define SHM_FILEINFO 'F' /* no file info messages */
+#define SHM_ALL "rmfixlnwaWtToOsAIcqF" /* all possible flags for 'shm' */
+
+/* characters for p_go: */
+#define GO_TERMINAL '!' /* use terminal for system commands */
+#define GO_ASEL 'a' /* autoselect */
+#define GO_ASELML 'A' /* autoselect modeless selection */
+#define GO_BOT 'b' /* use bottom scrollbar */
+#define GO_CONDIALOG 'c' /* use console dialog */
+#define GO_TABLINE 'e' /* may show tabline */
+#define GO_FORG 'f' /* start GUI in foreground */
+#define GO_GREY 'g' /* use grey menu items */
+#define GO_HORSCROLL 'h' /* flexible horizontal scrolling */
+#define GO_ICON 'i' /* use Vim icon */
+#define GO_LEFT 'l' /* use left scrollbar */
+#define GO_VLEFT 'L' /* left scrollbar with vert split */
+#define GO_MENUS 'm' /* use menu bar */
+#define GO_NOSYSMENU 'M' /* don't source system menu */
+#define GO_POINTER 'p' /* pointer enter/leave callbacks */
+#define GO_ASELPLUS 'P' /* autoselectPlus */
+#define GO_RIGHT 'r' /* use right scrollbar */
+#define GO_VRIGHT 'R' /* right scrollbar with vert split */
+#define GO_TEAROFF 't' /* add tear-off menu items */
+#define GO_TOOLBAR 'T' /* add toolbar */
+#define GO_FOOTER 'F' /* add footer */
+#define GO_VERTICAL 'v' /* arrange dialog buttons vertically */
+#define GO_KEEPWINSIZE 'k' /* keep GUI window size */
+#define GO_ALL "!aAbcefFghilmMprtTvk" /* all possible flags for 'go' */
+
+/* flags for 'comments' option */
+#define COM_NEST 'n' /* comments strings nest */
+#define COM_BLANK 'b' /* needs blank after string */
+#define COM_START 's' /* start of comment */
+#define COM_MIDDLE 'm' /* middle of comment */
+#define COM_END 'e' /* end of comment */
+#define COM_AUTO_END 'x' /* last char of end closes comment */
+#define COM_FIRST 'f' /* first line comment only */
+#define COM_LEFT 'l' /* left adjusted */
+#define COM_RIGHT 'r' /* right adjusted */
+#define COM_NOBACK 'O' /* don't use for "O" command */
+#define COM_ALL "nbsmexflrO" /* all flags for 'comments' option */
+#define COM_MAX_LEN 50 /* maximum length of a part */
+
+/* flags for 'statusline' option */
+#define STL_FILEPATH 'f' /* path of file in buffer */
+#define STL_FULLPATH 'F' /* full path of file in buffer */
+#define STL_FILENAME 't' /* last part (tail) of file path */
+#define STL_COLUMN 'c' /* column og cursor*/
+#define STL_VIRTCOL 'v' /* virtual column */
+#define STL_VIRTCOL_ALT 'V' /* - with 'if different' display */
+#define STL_LINE 'l' /* line number of cursor */
+#define STL_NUMLINES 'L' /* number of lines in buffer */
+#define STL_BUFNO 'n' /* current buffer number */
+#define STL_KEYMAP 'k' /* 'keymap' when active */
+#define STL_OFFSET 'o' /* offset of character under cursor*/
+#define STL_OFFSET_X 'O' /* - in hexadecimal */
+#define STL_BYTEVAL 'b' /* byte value of character */
+#define STL_BYTEVAL_X 'B' /* - in hexadecimal */
+#define STL_ROFLAG 'r' /* readonly flag */
+#define STL_ROFLAG_ALT 'R' /* - other display */
+#define STL_HELPFLAG 'h' /* window is showing a help file */
+#define STL_HELPFLAG_ALT 'H' /* - other display */
+#define STL_FILETYPE 'y' /* 'filetype' */
+#define STL_FILETYPE_ALT 'Y' /* - other display */
+#define STL_PREVIEWFLAG 'w' /* window is showing the preview buf */
+#define STL_PREVIEWFLAG_ALT 'W' /* - other display */
+#define STL_MODIFIED 'm' /* modified flag */
+#define STL_MODIFIED_ALT 'M' /* - other display */
+#define STL_QUICKFIX 'q' /* quickfix window description */
+#define STL_PERCENTAGE 'p' /* percentage through file */
+#define STL_ALTPERCENT 'P' /* percentage as TOP BOT ALL or NN% */
+#define STL_ARGLISTSTAT 'a' /* argument list status as (x of y) */
+#define STL_PAGENUM 'N' /* page number (when printing)*/
+#define STL_VIM_EXPR '{' /* start of expression to substitute */
+#define STL_MIDDLEMARK '=' /* separation between left and right */
+#define STL_TRUNCMARK '<' /* truncation mark if line is too long*/
+#define STL_USER_HL '*' /* highlight from (User)1..9 or 0 */
+#define STL_HIGHLIGHT '#' /* highlight name */
+#define STL_TABPAGENR 'T' /* tab page label nr */
+#define STL_TABCLOSENR 'X' /* tab page close nr */
+#define STL_ALL ((char_u *) "fFtcvVlLknoObBrRhHmYyWwMqpPaN{#")
+
+/* flags used for parsed 'wildmode' */
+#define WIM_FULL 1
+#define WIM_LONGEST 2
+#define WIM_LIST 4
+
+/* arguments for can_bs() */
+#define BS_INDENT 'i' /* "Indent" */
+#define BS_EOL 'o' /* "eOl" */
+#define BS_START 's' /* "Start" */
+
+#define LISPWORD_VALUE "defun,define,defmacro,set!,lambda,if,case,let,flet,let*,letrec,do,do*,define-syntax,let-syntax,letrec-syntax,destructuring-bind,defpackage,defparameter,defstruct,deftype,defvar,do-all-symbols,do-external-symbols,do-symbols,dolist,dotimes,ecase,etypecase,eval-when,labels,macrolet,multiple-value-bind,multiple-value-call,multiple-value-prog1,multiple-value-setq,prog1,progv,typecase,unless,unwind-protect,when,with-input-from-string,with-open-file,with-open-stream,with-output-to-string,with-package-iterator,define-condition,handler-bind,handler-case,restart-bind,restart-case,with-simple-restart,store-value,use-value,muffle-warning,abort,continue,with-slots,with-slots*,with-accessors,with-accessors*,defclass,defmethod,print-unreadable-object"
+
+/*
+ * The following are actual variables for the options
+ */
+
+#ifdef FEAT_RIGHTLEFT
+EXTERN long p_aleph; /* 'aleph' */
+#endif
+#ifdef FEAT_AUTOCHDIR
+EXTERN int p_acd; /* 'autochdir' */
+#endif
+EXTERN char_u *p_ambw; /* 'ambiwidth' */
+EXTERN char_u *p_emoji; /* 'emoji' */
+#if defined(FEAT_GUI) && defined(MACOS_X)
+EXTERN int *p_antialias; /* 'antialias' */
+#endif
+EXTERN int p_ar; /* 'autoread' */
+EXTERN int p_aw; /* 'autowrite' */
+EXTERN int p_awa; /* 'autowriteall' */
+EXTERN char_u *p_bs; /* 'backspace' */
+EXTERN char_u *p_bg; /* 'background' */
+EXTERN int p_bk; /* 'backup' */
+EXTERN char_u *p_bkc; /* 'backupcopy' */
+EXTERN unsigned bkc_flags; /* flags from 'backupcopy' */
+#ifdef IN_OPTION_C
+static char *(p_bkc_values[]) = {"yes", "auto", "no", "breaksymlink", "breakhardlink", NULL};
+#endif
+# define BKC_YES 0x001
+# define BKC_AUTO 0x002
+# define BKC_NO 0x004
+# define BKC_BREAKSYMLINK 0x008
+# define BKC_BREAKHARDLINK 0x010
+EXTERN char_u *p_bdir; /* 'backupdir' */
+EXTERN char_u *p_bex; /* 'backupext' */
+EXTERN char_u *p_bo; /* 'belloff' */
+EXTERN unsigned bo_flags;
+# ifdef IN_OPTION_C
+static char *(p_bo_values[]) = {"all", "backspace", "cursor", "complete",
+ "copy", "ctrlg", "error", "esc", "ex",
+ "hangul", "insertmode", "lang", "mess",
+ "showmatch", "operator", "register", "shell",
+ "spell", "wildmode", NULL};
+# endif
+
+/* values for the 'beepon' option */
+#define BO_ALL 0x0001
+#define BO_BS 0x0002
+#define BO_CRSR 0x0004
+#define BO_COMPL 0x0008
+#define BO_COPY 0x0010
+#define BO_CTRLG 0x0020
+#define BO_ERROR 0x0040
+#define BO_ESC 0x0080
+#define BO_EX 0x0100
+#define BO_HANGUL 0x0200
+#define BO_IM 0x0400
+#define BO_LANG 0x0800
+#define BO_MESS 0x1000
+#define BO_MATCH 0x2000
+#define BO_OPER 0x4000
+#define BO_REG 0x8000
+#define BO_SH 0x10000
+#define BO_SPELL 0x20000
+#define BO_WILD 0x40000
+
+#ifdef FEAT_WILDIGN
+EXTERN char_u *p_bsk; /* 'backupskip' */
+#endif
+#ifdef FEAT_CRYPT
+EXTERN char_u *p_cm; /* 'cryptmethod' */
+#endif
+#ifdef FEAT_BEVAL
+# ifdef FEAT_BEVAL_GUI
+EXTERN int p_beval; /* 'ballooneval' */
+# endif
+EXTERN long p_bdlay; /* 'balloondelay' */
+# ifdef FEAT_EVAL
+EXTERN char_u *p_bexpr;
+# endif
+# ifdef FEAT_BEVAL_TERM
+EXTERN int p_bevalterm; /* 'balloonevalterm' */
+# endif
+#endif
+#ifdef FEAT_BROWSE
+EXTERN char_u *p_bsdir; /* 'browsedir' */
+#endif
+#ifdef FEAT_LINEBREAK
+EXTERN char_u *p_breakat; /* 'breakat' */
+#endif
+EXTERN char_u *p_cmp; /* 'casemap' */
+EXTERN unsigned cmp_flags;
+#ifdef IN_OPTION_C
+static char *(p_cmp_values[]) = {"internal", "keepascii", NULL};
+#endif
+#define CMP_INTERNAL 0x001
+#define CMP_KEEPASCII 0x002
+EXTERN char_u *p_enc; /* 'encoding' */
+EXTERN int p_deco; /* 'delcombine' */
+#ifdef FEAT_EVAL
+EXTERN char_u *p_ccv; /* 'charconvert' */
+#endif
+#ifdef FEAT_CMDWIN
+EXTERN char_u *p_cedit; /* 'cedit' */
+EXTERN long p_cwh; /* 'cmdwinheight' */
+#endif
+#ifdef FEAT_CLIPBOARD
+EXTERN char_u *p_cb; /* 'clipboard' */
+#endif
+EXTERN long p_ch; /* 'cmdheight' */
+#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
+EXTERN int p_confirm; /* 'confirm' */
+#endif
+EXTERN int p_cp; /* 'compatible' */
+#ifdef FEAT_INS_EXPAND
+EXTERN char_u *p_cot; /* 'completeopt' */
+EXTERN long p_ph; /* 'pumheight' */
+EXTERN long p_pw; /* 'pumwidth' */
+#endif
+EXTERN char_u *p_cpo; /* 'cpoptions' */
+#ifdef FEAT_CSCOPE
+EXTERN char_u *p_csprg; /* 'cscopeprg' */
+EXTERN int p_csre; /* 'cscoperelative' */
+# ifdef FEAT_QUICKFIX
+EXTERN char_u *p_csqf; /* 'cscopequickfix' */
+# define CSQF_CMDS "sgdctefia"
+# define CSQF_FLAGS "+-0"
+# endif
+EXTERN int p_cst; /* 'cscopetag' */
+EXTERN long p_csto; /* 'cscopetagorder' */
+EXTERN long p_cspc; /* 'cscopepathcomp' */
+EXTERN int p_csverbose; /* 'cscopeverbose' */
+#endif
+EXTERN char_u *p_debug; /* 'debug' */
+#ifdef FEAT_FIND_ID
+EXTERN char_u *p_def; /* 'define' */
+EXTERN char_u *p_inc;
+#endif
+#ifdef FEAT_DIFF
+EXTERN char_u *p_dip; /* 'diffopt' */
+# ifdef FEAT_EVAL
+EXTERN char_u *p_dex; /* 'diffexpr' */
+# endif
+#endif
+#ifdef FEAT_INS_EXPAND
+EXTERN char_u *p_dict; /* 'dictionary' */
+#endif
+#ifdef FEAT_DIGRAPHS
+EXTERN int p_dg; /* 'digraph' */
+#endif
+EXTERN char_u *p_dir; /* 'directory' */
+EXTERN char_u *p_dy; /* 'display' */
+EXTERN unsigned dy_flags;
+#ifdef IN_OPTION_C
+static char *(p_dy_values[]) = {"lastline", "truncate", "uhex", NULL};
+#endif
+#define DY_LASTLINE 0x001
+#define DY_TRUNCATE 0x002
+#define DY_UHEX 0x004
+EXTERN int p_ed; /* 'edcompatible' */
+EXTERN char_u *p_ead; /* 'eadirection' */
+EXTERN int p_ea; /* 'equalalways' */
+EXTERN char_u *p_ep; /* 'equalprg' */
+EXTERN int p_eb; /* 'errorbells' */
+#ifdef FEAT_QUICKFIX
+EXTERN char_u *p_ef; /* 'errorfile' */
+EXTERN char_u *p_efm; /* 'errorformat' */
+EXTERN char_u *p_gefm; /* 'grepformat' */
+EXTERN char_u *p_gp; /* 'grepprg' */
+#endif
+EXTERN char_u *p_ei; /* 'eventignore' */
+EXTERN int p_ek; /* 'esckeys' */
+EXTERN int p_exrc; /* 'exrc' */
+EXTERN char_u *p_fencs; /* 'fileencodings' */
+EXTERN char_u *p_ffs; /* 'fileformats' */
+EXTERN long p_fic; /* 'fileignorecase' */
+#ifdef FEAT_FOLDING
+EXTERN char_u *p_fcl; /* 'foldclose' */
+EXTERN long p_fdls; /* 'foldlevelstart' */
+EXTERN char_u *p_fdo; /* 'foldopen' */
+EXTERN unsigned fdo_flags;
+# ifdef IN_OPTION_C
+static char *(p_fdo_values[]) = {"all", "block", "hor", "mark", "percent",
+ "quickfix", "search", "tag", "insert",
+ "undo", "jump", NULL};
+# endif
+# define FDO_ALL 0x001
+# define FDO_BLOCK 0x002
+# define FDO_HOR 0x004
+# define FDO_MARK 0x008
+# define FDO_PERCENT 0x010
+# define FDO_QUICKFIX 0x020
+# define FDO_SEARCH 0x040
+# define FDO_TAG 0x080
+# define FDO_INSERT 0x100
+# define FDO_UNDO 0x200
+# define FDO_JUMP 0x400
+#endif
+EXTERN char_u *p_fp; /* 'formatprg' */
+#ifdef HAVE_FSYNC
+EXTERN int p_fs; /* 'fsync' */
+#endif
+EXTERN int p_gd; /* 'gdefault' */
+#ifdef FEAT_PRINTER
+EXTERN char_u *p_pdev; /* 'printdevice' */
+# ifdef FEAT_POSTSCRIPT
+EXTERN char_u *p_penc; /* 'printencoding' */
+EXTERN char_u *p_pexpr; /* 'printexpr' */
+EXTERN char_u *p_pmfn; /* 'printmbfont' */
+EXTERN char_u *p_pmcs; /* 'printmbcharset' */
+# endif
+EXTERN char_u *p_pfn; /* 'printfont' */
+EXTERN char_u *p_popt; /* 'printoptions' */
+EXTERN char_u *p_header; /* 'printheader' */
+#endif
+EXTERN int p_prompt; /* 'prompt' */
+#ifdef FEAT_GUI
+EXTERN char_u *p_guifont; /* 'guifont' */
+# ifdef FEAT_XFONTSET
+EXTERN char_u *p_guifontset; /* 'guifontset' */
+# endif
+EXTERN char_u *p_guifontwide; /* 'guifontwide' */
+EXTERN int p_guipty; /* 'guipty' */
+#endif
+#if defined(FEAT_GUI_GTK) || defined(FEAT_GUI_X11)
+EXTERN long p_ghr; /* 'guiheadroom' */
+#endif
+#ifdef CURSOR_SHAPE
+EXTERN char_u *p_guicursor; /* 'guicursor' */
+#endif
+#ifdef FEAT_MOUSESHAPE
+EXTERN char_u *p_mouseshape; /* 'mouseshape' */
+#endif
+#if defined(FEAT_GUI)
+EXTERN char_u *p_go; /* 'guioptions' */
+#endif
+#if defined(FEAT_GUI_TABLINE)
+EXTERN char_u *p_gtl; /* 'guitablabel' */
+EXTERN char_u *p_gtt; /* 'guitabtooltip' */
+#endif
+EXTERN char_u *p_hf; /* 'helpfile' */
+EXTERN long p_hh; /* 'helpheight' */
+#ifdef FEAT_MULTI_LANG
+EXTERN char_u *p_hlg; /* 'helplang' */
+#endif
+EXTERN int p_hid; /* 'hidden' */
+EXTERN char_u *p_hl; /* 'highlight' */
+EXTERN int p_hls; /* 'hlsearch' */
+EXTERN long p_hi; /* 'history' */
+#ifdef FEAT_RIGHTLEFT
+EXTERN int p_hkmap; /* 'hkmap' */
+EXTERN int p_hkmapp; /* 'hkmapp' */
+# ifdef FEAT_FKMAP
+EXTERN int p_fkmap; /* 'fkmap' */
+EXTERN int p_altkeymap; /* 'altkeymap' */
+# endif
+# ifdef FEAT_ARABIC
+EXTERN int p_arshape; /* 'arabicshape' */
+# endif
+#endif
+#ifdef FEAT_TITLE
+EXTERN int p_icon; /* 'icon' */
+EXTERN char_u *p_iconstring; /* 'iconstring' */
+#endif
+EXTERN int p_ic; /* 'ignorecase' */
+#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
+EXTERN char_u *p_imak; /* 'imactivatekey' */
+#define IM_ON_THE_SPOT 0L
+#define IM_OVER_THE_SPOT 1L
+EXTERN long p_imst; /* 'imstyle' */
+#endif
+#if defined(FEAT_EVAL)
+EXTERN char_u *p_imaf; /* 'imactivatefunc' */
+EXTERN char_u *p_imsf; /* 'imstatusfunc' */
+#endif
+EXTERN int p_imcmdline; /* 'imcmdline' */
+EXTERN int p_imdisable; /* 'imdisable' */
+EXTERN int p_is; /* 'incsearch' */
+EXTERN int p_im; /* 'insertmode' */
+EXTERN char_u *p_isf; /* 'isfname' */
+EXTERN char_u *p_isi; /* 'isident' */
+EXTERN char_u *p_isp; /* 'isprint' */
+EXTERN int p_js; /* 'joinspaces' */
+EXTERN char_u *p_kp; /* 'keywordprg' */
+EXTERN char_u *p_km; /* 'keymodel' */
+#ifdef FEAT_LANGMAP
+EXTERN char_u *p_langmap; /* 'langmap'*/
+EXTERN int p_lnr; /* 'langnoremap' */
+EXTERN int p_lrm; /* 'langremap' */
+#endif
+#if defined(FEAT_MENU) && defined(FEAT_MULTI_LANG)
+EXTERN char_u *p_lm; /* 'langmenu' */
+#endif
+#ifdef FEAT_GUI
+EXTERN long p_linespace; /* 'linespace' */
+#endif
+#ifdef FEAT_LISP
+EXTERN char_u *p_lispwords; /* 'lispwords' */
+#endif
+EXTERN long p_ls; /* 'laststatus' */
+EXTERN long p_stal; /* 'showtabline' */
+EXTERN char_u *p_lcs; /* 'listchars' */
+
+EXTERN int p_lz; /* 'lazyredraw' */
+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
+EXTERN int p_magic; /* 'magic' */
+EXTERN char_u *p_menc; /* 'makeencoding' */
+#ifdef FEAT_QUICKFIX
+EXTERN char_u *p_mef; /* 'makeef' */
+EXTERN char_u *p_mp; /* 'makeprg' */
+#endif
+#ifdef FEAT_SIGNS
+EXTERN char_u *p_scl; /* signcolumn */
+#endif
+#ifdef FEAT_SYN_HL
+EXTERN char_u *p_cc; /* 'colorcolumn' */
+EXTERN int p_cc_cols[256]; /* array for 'colorcolumn' columns */
+#endif
+EXTERN long p_mat; /* 'matchtime' */
+EXTERN long p_mco; /* 'maxcombine' */
+#ifdef FEAT_EVAL
+EXTERN long p_mfd; /* 'maxfuncdepth' */
+#endif
+EXTERN long p_mmd; /* 'maxmapdepth' */
+EXTERN long p_mm; /* 'maxmem' */
+EXTERN long p_mmp; /* 'maxmempattern' */
+EXTERN long p_mmt; /* 'maxmemtot' */
+#ifdef FEAT_MENU
+EXTERN long p_mis; /* 'menuitems' */
+#endif
+#ifdef FEAT_SPELL
+EXTERN char_u *p_msm; /* 'mkspellmem' */
+#endif
+EXTERN long p_mls; /* 'modelines' */
+EXTERN char_u *p_mouse; /* 'mouse' */
+#ifdef FEAT_GUI
+EXTERN int p_mousef; /* 'mousefocus' */
+EXTERN int p_mh; /* 'mousehide' */
+#endif
+EXTERN char_u *p_mousem; /* 'mousemodel' */
+EXTERN long p_mouset; /* 'mousetime' */
+EXTERN int p_more; /* 'more' */
+#ifdef FEAT_MZSCHEME
+EXTERN long p_mzq; /* 'mzquantum */
+# if defined(DYNAMIC_MZSCHEME)
+EXTERN char_u *p_mzschemedll; /* 'mzschemedll' */
+EXTERN char_u *p_mzschemegcdll; /* 'mzschemegcdll' */
+# endif
+#endif
+#if defined(MSWIN)
+EXTERN int p_odev; /* 'opendevice' */
+#endif
+EXTERN char_u *p_opfunc; /* 'operatorfunc' */
+EXTERN char_u *p_para; /* 'paragraphs' */
+EXTERN int p_paste; /* 'paste' */
+EXTERN char_u *p_pt; /* 'pastetoggle' */
+#if defined(FEAT_EVAL) && defined(FEAT_DIFF)
+EXTERN char_u *p_pex; /* 'patchexpr' */
+#endif
+EXTERN char_u *p_pm; /* 'patchmode' */
+EXTERN char_u *p_path; /* 'path' */
+#ifdef FEAT_SEARCHPATH
+EXTERN char_u *p_cdpath; /* 'cdpath' */
+#endif
+#if defined(DYNAMIC_PERL)
+EXTERN char_u *p_perldll; /* 'perldll' */
+#endif
+#if defined(DYNAMIC_PYTHON3)
+EXTERN char_u *p_py3dll; /* 'pythonthreedll' */
+#endif
+#ifdef FEAT_PYTHON3
+EXTERN char_u *p_py3home; /* 'pythonthreehome' */
+#endif
+#if defined(DYNAMIC_PYTHON)
+EXTERN char_u *p_pydll; /* 'pythondll' */
+#endif
+#ifdef FEAT_PYTHON
+EXTERN char_u *p_pyhome; /* 'pythonhome' */
+#endif
+#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
+EXTERN long p_pyx; /* 'pyxversion' */
+#endif
+#ifdef FEAT_RELTIME
+EXTERN long p_rdt; /* 'redrawtime' */
+#endif
+EXTERN int p_remap; /* 'remap' */
+EXTERN long p_re; /* 'regexpengine' */
+#ifdef FEAT_RENDER_OPTIONS
+EXTERN char_u *p_rop; /* 'renderoptions' */
+#endif
+EXTERN long p_report; /* 'report' */
+#if defined(FEAT_QUICKFIX)
+EXTERN long p_pvh; /* 'previewheight' */
+#endif
+#ifdef WIN3264
+EXTERN int p_rs; /* 'restorescreen' */
+#endif
+#ifdef FEAT_RIGHTLEFT
+EXTERN int p_ari; /* 'allowrevins' */
+EXTERN int p_ri; /* 'revins' */
+#endif
+#if defined(DYNAMIC_RUBY)
+EXTERN char_u *p_rubydll; /* 'rubydll' */
+#endif
+#ifdef FEAT_CMDL_INFO
+EXTERN int p_ru; /* 'ruler' */
+#endif
+#ifdef FEAT_STL_OPT
+EXTERN char_u *p_ruf; /* 'rulerformat' */
+#endif
+EXTERN char_u *p_pp; /* 'packpath' */
+EXTERN char_u *p_rtp; /* 'runtimepath' */
+EXTERN long p_sj; /* 'scrolljump' */
+EXTERN long p_so; /* 'scrolloff' */
+EXTERN char_u *p_sbo; /* 'scrollopt' */
+EXTERN char_u *p_sections; /* 'sections' */
+EXTERN int p_secure; /* 'secure' */
+EXTERN char_u *p_sel; /* 'selection' */
+EXTERN char_u *p_slm; /* 'selectmode' */
+#ifdef FEAT_SESSION
+EXTERN char_u *p_ssop; /* 'sessionoptions' */
+EXTERN unsigned ssop_flags;
+# ifdef IN_OPTION_C
+/* Also used for 'viewoptions'! */
+static char *(p_ssop_values[]) = {"buffers", "winpos", "resize", "winsize",
+ "localoptions", "options", "help", "blank", "globals", "slash", "unix",
+ "sesdir", "curdir", "folds", "cursor", "tabpages", "terminal", NULL};
+# endif
+# define SSOP_BUFFERS 0x001
+# define SSOP_WINPOS 0x002
+# define SSOP_RESIZE 0x004
+# define SSOP_WINSIZE 0x008
+# define SSOP_LOCALOPTIONS 0x010
+# define SSOP_OPTIONS 0x020
+# define SSOP_HELP 0x040
+# define SSOP_BLANK 0x080
+# define SSOP_GLOBALS 0x100
+# define SSOP_SLASH 0x200
+# define SSOP_UNIX 0x400
+# define SSOP_SESDIR 0x800
+# define SSOP_CURDIR 0x1000
+# define SSOP_FOLDS 0x2000
+# define SSOP_CURSOR 0x4000
+# define SSOP_TABPAGES 0x8000
+# define SSOP_TERMINAL 0x10000
+#endif
+EXTERN char_u *p_sh; /* 'shell' */
+EXTERN char_u *p_shcf; /* 'shellcmdflag' */
+#ifdef FEAT_QUICKFIX
+EXTERN char_u *p_sp; /* 'shellpipe' */
+#endif
+EXTERN char_u *p_shq; /* 'shellquote' */
+EXTERN char_u *p_sxq; /* 'shellxquote' */
+EXTERN char_u *p_sxe; /* 'shellxescape' */
+EXTERN char_u *p_srr; /* 'shellredir' */
+#ifdef AMIGA
+EXTERN long p_st; /* 'shelltype' */
+#endif
+EXTERN int p_stmp; /* 'shelltemp' */
+#ifdef BACKSLASH_IN_FILENAME
+EXTERN int p_ssl; /* 'shellslash' */
+#endif
+#ifdef FEAT_STL_OPT
+EXTERN char_u *p_stl; /* 'statusline' */
+#endif
+EXTERN int p_sr; /* 'shiftround' */
+EXTERN char_u *p_shm; /* 'shortmess' */
+#ifdef FEAT_LINEBREAK
+EXTERN char_u *p_sbr; /* 'showbreak' */
+#endif
+#ifdef FEAT_CMDL_INFO
+EXTERN int p_sc; /* 'showcmd' */
+#endif
+EXTERN int p_sft; /* 'showfulltag' */
+EXTERN int p_sm; /* 'showmatch' */
+EXTERN int p_smd; /* 'showmode' */
+EXTERN long p_ss; /* 'sidescroll' */
+EXTERN long p_siso; /* 'sidescrolloff' */
+EXTERN int p_scs; /* 'smartcase' */
+EXTERN int p_sta; /* 'smarttab' */
+EXTERN int p_sb; /* 'splitbelow' */
+EXTERN long p_tpm; /* 'tabpagemax' */
+# if defined(FEAT_STL_OPT)
+EXTERN char_u *p_tal; /* 'tabline' */
+# endif
+#ifdef FEAT_SPELL
+EXTERN char_u *p_sps; /* 'spellsuggest' */
+#endif
+EXTERN int p_spr; /* 'splitright' */
+EXTERN int p_sol; /* 'startofline' */
+EXTERN char_u *p_su; /* 'suffixes' */
+EXTERN char_u *p_sws; /* 'swapsync' */
+EXTERN char_u *p_swb; /* 'switchbuf' */
+EXTERN unsigned swb_flags;
+#ifdef IN_OPTION_C
+static char *(p_swb_values[]) = {"useopen", "usetab", "split", "newtab", "vsplit", NULL};
+#endif
+#define SWB_USEOPEN 0x001
+#define SWB_USETAB 0x002
+#define SWB_SPLIT 0x004
+#define SWB_NEWTAB 0x008
+#define SWB_VSPLIT 0x010
+EXTERN int p_tbs; /* 'tagbsearch' */
+EXTERN char_u *p_tc; /* 'tagcase' */
+EXTERN unsigned tc_flags; /* flags from 'tagcase' */
+#ifdef IN_OPTION_C
+static char *(p_tc_values[]) = {"followic", "ignore", "match", "followscs", "smart", NULL};
+#endif
+#define TC_FOLLOWIC 0x01
+#define TC_IGNORE 0x02
+#define TC_MATCH 0x04
+#define TC_FOLLOWSCS 0x08
+#define TC_SMART 0x10
+EXTERN long p_tl; /* 'taglength' */
+EXTERN int p_tr; /* 'tagrelative' */
+EXTERN char_u *p_tags; /* 'tags' */
+EXTERN int p_tgst; /* 'tagstack' */
+#if defined(DYNAMIC_TCL)
+EXTERN char_u *p_tcldll; /* 'tcldll' */
+#endif
+#ifdef FEAT_ARABIC
+EXTERN int p_tbidi; /* 'termbidi' */
+#endif
+EXTERN char_u *p_tenc; /* 'termencoding' */
+#ifdef FEAT_TERMGUICOLORS
+EXTERN int p_tgc; /* 'termguicolors' */
+#endif
+EXTERN int p_terse; /* 'terse' */
+EXTERN int p_ta; /* 'textauto' */
+EXTERN int p_to; /* 'tildeop' */
+EXTERN int p_timeout; /* 'timeout' */
+EXTERN long p_tm; /* 'timeoutlen' */
+#ifdef FEAT_TITLE
+EXTERN int p_title; /* 'title' */
+EXTERN long p_titlelen; /* 'titlelen' */
+EXTERN char_u *p_titleold; /* 'titleold' */
+EXTERN char_u *p_titlestring; /* 'titlestring' */
+#endif
+#ifdef FEAT_INS_EXPAND
+EXTERN char_u *p_tsr; /* 'thesaurus' */
+#endif
+EXTERN int p_ttimeout; /* 'ttimeout' */
+EXTERN long p_ttm; /* 'ttimeoutlen' */
+EXTERN int p_tbi; /* 'ttybuiltin' */
+EXTERN int p_tf; /* 'ttyfast' */
+#if defined(FEAT_TOOLBAR) && !defined(FEAT_GUI_W32)
+EXTERN char_u *p_toolbar; /* 'toolbar' */
+EXTERN unsigned toolbar_flags;
+# ifdef IN_OPTION_C
+static char *(p_toolbar_values[]) = {"text", "icons", "tooltips", "horiz", NULL};
+# endif
+# define TOOLBAR_TEXT 0x01
+# define TOOLBAR_ICONS 0x02
+# define TOOLBAR_TOOLTIPS 0x04
+# define TOOLBAR_HORIZ 0x08
+#endif
+#if defined(FEAT_TOOLBAR) && defined(FEAT_GUI_GTK)
+EXTERN char_u *p_tbis; /* 'toolbariconsize' */
+EXTERN unsigned tbis_flags;
+# ifdef IN_OPTION_C
+static char *(p_tbis_values[]) = {"tiny", "small", "medium", "large", "huge", "giant", NULL};
+# endif
+# define TBIS_TINY 0x01
+# define TBIS_SMALL 0x02
+# define TBIS_MEDIUM 0x04
+# define TBIS_LARGE 0x08
+# define TBIS_HUGE 0x10
+# define TBIS_GIANT 0x20
+#endif
+EXTERN long p_ttyscroll; /* 'ttyscroll' */
+#if defined(FEAT_MOUSE) && (defined(UNIX) || defined(VMS))
+EXTERN char_u *p_ttym; /* 'ttymouse' */
+EXTERN unsigned ttym_flags;
+# ifdef IN_OPTION_C
+static char *(p_ttym_values[]) = {"xterm", "xterm2", "dec", "netterm", "jsbterm", "pterm", "urxvt", "sgr", NULL};
+# endif
+# define TTYM_XTERM 0x01
+# define TTYM_XTERM2 0x02
+# define TTYM_DEC 0x04
+# define TTYM_NETTERM 0x08
+# define TTYM_JSBTERM 0x10
+# define TTYM_PTERM 0x20
+# define TTYM_URXVT 0x40
+# define TTYM_SGR 0x80
+#endif
+EXTERN char_u *p_udir; /* 'undodir' */
+EXTERN long p_ul; /* 'undolevels' */
+EXTERN long p_ur; /* 'undoreload' */
+EXTERN long p_uc; /* 'updatecount' */
+EXTERN long p_ut; /* 'updatetime' */
+EXTERN char_u *p_fcs; /* 'fillchar' */
+#ifdef FEAT_VIMINFO
+EXTERN char_u *p_viminfo; /* 'viminfo' */
+EXTERN char_u *p_viminfofile; /* 'viminfofile' */
+#endif
+#ifdef FEAT_SESSION
+EXTERN char_u *p_vdir; /* 'viewdir' */
+EXTERN char_u *p_vop; /* 'viewoptions' */
+EXTERN unsigned vop_flags; /* uses SSOP_ flags */
+#endif
+EXTERN int p_vb; /* 'visualbell' */
+EXTERN char_u *p_ve; /* 'virtualedit' */
+EXTERN unsigned ve_flags;
+#ifdef IN_OPTION_C
+static char *(p_ve_values[]) = {"block", "insert", "all", "onemore", NULL};
+#endif
+#define VE_BLOCK 5 /* includes "all" */
+#define VE_INSERT 6 /* includes "all" */
+#define VE_ALL 4
+#define VE_ONEMORE 8
+EXTERN long p_verbose; /* 'verbose' */
+#ifdef IN_OPTION_C
+char_u *p_vfile = (char_u *)""; /* used before options are initialized */
+#else
+extern char_u *p_vfile; /* 'verbosefile' */
+#endif
+EXTERN int p_warn; /* 'warn' */
+#ifdef FEAT_CMDL_COMPL
+EXTERN char_u *p_wop; /* 'wildoptions' */
+#endif
+EXTERN long p_window; /* 'window' */
+#if defined(FEAT_GUI_MSWIN) || defined(FEAT_GUI_MOTIF) || defined(LINT) \
+ || defined (FEAT_GUI_GTK) || defined(FEAT_GUI_PHOTON)
+#define FEAT_WAK
+EXTERN char_u *p_wak; /* 'winaltkeys' */
+#endif
+#ifdef FEAT_WILDIGN
+EXTERN char_u *p_wig; /* 'wildignore' */
+#endif
+EXTERN int p_wiv; /* 'weirdinvert' */
+EXTERN char_u *p_ww; /* 'whichwrap' */
+EXTERN long p_wc; /* 'wildchar' */
+EXTERN long p_wcm; /* 'wildcharm' */
+EXTERN long p_wic; /* 'wildignorecase' */
+EXTERN char_u *p_wim; /* 'wildmode' */
+#ifdef FEAT_WILDMENU
+EXTERN int p_wmnu; /* 'wildmenu' */
+#endif
+EXTERN long p_wh; /* 'winheight' */
+EXTERN long p_wmh; /* 'winminheight' */
+EXTERN long p_wmw; /* 'winminwidth' */
+EXTERN long p_wiw; /* 'winwidth' */
+#if defined(WIN3264) && defined(FEAT_TERMINAL)
+EXTERN char_u *p_winptydll; /* 'winptydll' */
+#endif
+EXTERN int p_ws; /* 'wrapscan' */
+EXTERN int p_write; /* 'write' */
+EXTERN int p_wa; /* 'writeany' */
+EXTERN int p_wb; /* 'writebackup' */
+EXTERN long p_wd; /* 'writedelay' */
+
+/*
+ * "indir" values for buffer-local opions.
+ * These need to be defined globally, so that the BV_COUNT can be used with
+ * b_p_scriptID[].
+ */
+enum
+{
+ BV_AI = 0
+ , BV_AR
+ , BV_BH
+ , BV_BKC
+ , BV_BT
+#ifdef FEAT_QUICKFIX
+ , BV_EFM
+ , BV_GP
+ , BV_MP
+#endif
+ , BV_BIN
+ , BV_BL
+ , BV_BOMB
+ , BV_CI
+#ifdef FEAT_CINDENT
+ , BV_CIN
+ , BV_CINK
+ , BV_CINO
+#endif
+#if defined(FEAT_SMARTINDENT) || defined(FEAT_CINDENT)
+ , BV_CINW
+#endif
+ , BV_CM
+#ifdef FEAT_FOLDING
+ , BV_CMS
+#endif
+#ifdef FEAT_COMMENTS
+ , BV_COM
+#endif
+#ifdef FEAT_INS_EXPAND
+ , BV_CPT
+ , BV_DICT
+ , BV_TSR
+#endif
+#ifdef FEAT_COMPL_FUNC
+ , BV_CFU
+#endif
+#ifdef FEAT_FIND_ID
+ , BV_DEF
+ , BV_INC
+#endif
+ , BV_EOL
+ , BV_FIXEOL
+ , BV_EP
+ , BV_ET
+ , BV_FENC
+ , BV_FP
+#ifdef FEAT_EVAL
+ , BV_BEXPR
+ , BV_FEX
+#endif
+ , BV_FF
+ , BV_FLP
+ , BV_FO
+ , BV_FT
+ , BV_IMI
+ , BV_IMS
+#if defined(FEAT_CINDENT) && defined(FEAT_EVAL)
+ , BV_INDE
+ , BV_INDK
+#endif
+#if defined(FEAT_FIND_ID) && defined(FEAT_EVAL)
+ , BV_INEX
+#endif
+ , BV_INF
+ , BV_ISK
+#ifdef FEAT_CRYPT
+ , BV_KEY
+#endif
+#ifdef FEAT_KEYMAP
+ , BV_KMAP
+#endif
+ , BV_KP
+#ifdef FEAT_LISP
+ , BV_LISP
+ , BV_LW
+#endif
+ , BV_MENC
+ , BV_MA
+ , BV_ML
+ , BV_MOD
+ , BV_MPS
+ , BV_NF
+#ifdef FEAT_COMPL_FUNC
+ , BV_OFU
+#endif
+ , BV_PATH
+ , BV_PI
+#ifdef FEAT_TEXTOBJ
+ , BV_QE
+#endif
+ , BV_RO
+#ifdef FEAT_SMARTINDENT
+ , BV_SI
+#endif
+ , BV_SN
+#ifdef FEAT_SYN_HL
+ , BV_SMC
+ , BV_SYN
+#endif
+#ifdef FEAT_SPELL
+ , BV_SPC
+ , BV_SPF
+ , BV_SPL
+#endif
+ , BV_STS
+#ifdef FEAT_SEARCHPATH
+ , BV_SUA
+#endif
+ , BV_SW
+ , BV_SWF
+ , BV_TAGS
+ , BV_TC
+ , BV_TS
+ , BV_TW
+ , BV_TX
+ , BV_UDF
+ , BV_UL
+ , BV_WM
+#ifdef FEAT_TERMINAL
+ , BV_TWSL
+#endif
+#ifdef FEAT_VARTABS
+ , BV_VSTS
+ , BV_VTS
+#endif
+ , BV_COUNT /* must be the last one */
+};
+
+/*
+ * "indir" values for window-local options.
+ * These need to be defined globally, so that the WV_COUNT can be used in the
+ * window structure.
+ */
+enum
+{
+ WV_LIST = 0
+#ifdef FEAT_ARABIC
+ , WV_ARAB
+#endif
+#ifdef FEAT_CONCEAL
+ , WV_COCU
+ , WV_COLE
+#endif
+#ifdef FEAT_TERMINAL
+ , WV_TWK
+ , WV_TWS
+ , WV_TMOD
+#endif
+ , WV_CRBIND
+#ifdef FEAT_LINEBREAK
+ , WV_BRI
+ , WV_BRIOPT
+#endif
+#ifdef FEAT_DIFF
+ , WV_DIFF
+#endif
+#ifdef FEAT_FOLDING
+ , WV_FDC
+ , WV_FEN
+ , WV_FDI
+ , WV_FDL
+ , WV_FDM
+ , WV_FML
+ , WV_FDN
+# ifdef FEAT_EVAL
+ , WV_FDE
+ , WV_FDT
+# endif
+ , WV_FMR
+#endif
+#ifdef FEAT_LINEBREAK
+ , WV_LBR
+#endif
+ , WV_NU
+ , WV_RNU
+#ifdef FEAT_LINEBREAK
+ , WV_NUW
+#endif
+#if defined(FEAT_QUICKFIX)
+ , WV_PVW
+#endif
+#ifdef FEAT_RIGHTLEFT
+ , WV_RL
+ , WV_RLC
+#endif
+ , WV_SCBIND
+ , WV_SCROLL
+ , WV_SISO
+ , WV_SO
+#ifdef FEAT_SPELL
+ , WV_SPELL
+#endif
+#ifdef FEAT_SYN_HL
+ , WV_CUC
+ , WV_CUL
+ , WV_CC
+#endif
+#ifdef FEAT_STL_OPT
+ , WV_STL
+#endif
+ , WV_WFH
+ , WV_WFW
+ , WV_WRAP
+#ifdef FEAT_SIGNS
+ , WV_SCL
+#endif
+ , WV_COUNT /* must be the last one */
+};
+
+/* Value for b_p_ul indicating the global value must be used. */
+#define NO_LOCAL_UNDOLEVEL -123456
diff --git a/src/os_amiga.c b/src/os_amiga.c
new file mode 100644
index 0000000..4a6814c
--- /dev/null
+++ b/src/os_amiga.c
@@ -0,0 +1,1653 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * os_amiga.c
+ *
+ * Amiga system-dependent routines.
+ */
+
+#include "vim.h"
+
+#ifdef Window
+# undef Window /* Amiga has its own Window definition */
+#endif
+
+#undef TRUE /* will be redefined by exec/types.h */
+#undef FALSE
+
+/* cproto fails on missing include files, skip them */
+#ifndef PROTO
+
+#ifndef LATTICE
+# include <exec/types.h>
+# include <exec/exec.h>
+# include <libraries/dos.h>
+# include <intuition/intuition.h>
+#endif
+
+/* XXX These are included from os_amiga.h
+#include <proto/exec.h>
+#include <proto/dos.h>
+#include <proto/intuition.h>
+*/
+
+#include <exec/memory.h>
+#include <libraries/dosextens.h>
+
+#include <dos/dostags.h> /* for 2.0 functions */
+#include <dos/dosasl.h>
+
+/* From version 4 of AmigaOS, several system structures must be allocated
+ * and freed using system functions. "struct AnchorPath" is one.
+ */
+#ifdef __amigaos4__
+# include <dos/anchorpath.h>
+# define free_fib(x) FreeDosObject(DOS_FIB, x)
+#else
+# define free_fib(x) vim_free(fib)
+#endif
+
+#if defined(LATTICE) && !defined(SASC) && defined(FEAT_ARP)
+# include <libraries/arp_pragmas.h>
+#endif
+
+#endif /* PROTO */
+
+/*
+ * At this point TRUE and FALSE are defined as 1L and 0L, but we want 1 and 0.
+ */
+#undef TRUE
+#define TRUE (1)
+#undef FALSE
+#define FALSE (0)
+
+#ifdef __amigaos4__
+# define dos_packet(a, b, c) DoPkt(a, b, c, 0, 0, 0, 0)
+#elif !defined(AZTEC_C) && !defined(__AROS__)
+static long dos_packet(struct MsgPort *, long, long);
+#endif
+static int lock2name(BPTR lock, char_u *buf, long len);
+static void out_num(long n);
+static struct FileInfoBlock *get_fib(char_u *);
+static int sortcmp(const void *a, const void *b);
+
+static BPTR raw_in = (BPTR)NULL;
+static BPTR raw_out = (BPTR)NULL;
+static int close_win = FALSE; /* set if Vim opened the window */
+
+#ifndef __amigaos4__ /* Use autoopen for AmigaOS4 */
+struct IntuitionBase *IntuitionBase = NULL;
+#endif
+#ifdef FEAT_ARP
+struct ArpBase *ArpBase = NULL;
+#endif
+
+static struct Window *wb_window;
+static char_u *oldwindowtitle = NULL;
+
+#ifdef FEAT_ARP
+int dos2 = FALSE; /* Amiga DOS 2.0x or higher */
+#endif
+int size_set = FALSE; /* set to TRUE if window size was set */
+
+ void
+win_resize_on(void)
+{
+ OUT_STR_NF("\033[12{");
+}
+
+ void
+win_resize_off(void)
+{
+ OUT_STR_NF("\033[12}");
+}
+
+ void
+mch_write(char_u *p, int len)
+{
+ Write(raw_out, (char *)p, (long)len);
+}
+
+/*
+ * mch_inchar(): low level input function.
+ * Get a characters from the keyboard.
+ * If time == 0 do not wait for characters.
+ * If time == n wait a short time for characters.
+ * If time == -1 wait forever for characters.
+ *
+ * Return number of characters read.
+ */
+ int
+mch_inchar(
+ char_u *buf,
+ int maxlen,
+ long time, /* milli seconds */
+ int tb_change_cnt)
+{
+ int len;
+ long utime;
+
+ if (time >= 0)
+ {
+ if (time == 0)
+ utime = 100L; /* time = 0 causes problems in DOS 1.2 */
+ else
+ utime = time * 1000L; /* convert from milli to micro secs */
+ if (WaitForChar(raw_in, utime) == 0) /* no character available */
+ return 0;
+ }
+ else /* time == -1 */
+ {
+ /*
+ * If there is no character available within 2 seconds (default)
+ * write the autoscript file to disk. Or cause the CursorHold event
+ * to be triggered.
+ */
+ if (WaitForChar(raw_in, p_ut * 1000L) == 0)
+ {
+ if (trigger_cursorhold() && maxlen >= 3)
+ {
+ buf[0] = K_SPECIAL;
+ buf[1] = KS_EXTRA;
+ buf[2] = (int)KE_CURSORHOLD;
+ return 3;
+ }
+ before_blocking();
+ }
+ }
+
+ for (;;) /* repeat until we got a character */
+ {
+ len = Read(raw_in, (char *)buf, (long)maxlen / input_conv.vc_factor);
+ if (len > 0)
+ {
+ /* Convert from 'termencoding' to 'encoding'. */
+ if (input_conv.vc_type != CONV_NONE)
+ len = convert_input(buf, len, maxlen);
+ return len;
+ }
+ }
+}
+
+/*
+ * return non-zero if a character is available
+ */
+ int
+mch_char_avail(void)
+{
+ return (WaitForChar(raw_in, 100L) != 0);
+}
+
+/*
+ * Return amount of memory still available in Kbyte.
+ */
+ long_u
+mch_avail_mem(int special)
+{
+#ifdef __amigaos4__
+ return (long_u)AvailMem(MEMF_ANY) >> 10;
+#else
+ return (long_u)(AvailMem(special ? (long)MEMF_CHIP : (long)MEMF_ANY)) >> 10;
+#endif
+}
+
+/*
+ * Waits a specified amount of time, or until input arrives if
+ * ignoreinput is FALSE.
+ */
+ void
+mch_delay(long msec, int ignoreinput)
+{
+#ifndef LATTICE /* SAS declares void Delay(ULONG) */
+ void Delay(long);
+#endif
+
+ if (msec > 0)
+ {
+ if (ignoreinput)
+ Delay(msec / 20L); /* Delay works with 20 msec intervals */
+ else
+ WaitForChar(raw_in, msec * 1000L);
+ }
+}
+
+/*
+ * We have no job control, fake it by starting a new shell.
+ */
+ void
+mch_suspend(void)
+{
+ suspend_shell();
+}
+
+#ifndef DOS_LIBRARY
+# define DOS_LIBRARY ((UBYTE *)"dos.library")
+#endif
+
+ void
+mch_init(void)
+{
+ static char intlibname[] = "intuition.library";
+
+#ifdef AZTEC_C
+ Enable_Abort = 0; /* disallow vim to be aborted */
+#endif
+ Columns = 80;
+ Rows = 24;
+
+ /*
+ * Set input and output channels, unless we have opened our own window
+ */
+ if (raw_in == (BPTR)NULL)
+ {
+ raw_in = Input();
+ raw_out = Output();
+ /*
+ * If Input() is not interactive, then Output() will be (because of
+ * check in mch_check_win()). Used for "Vim -".
+ * Also check the other way around, for "Vim -h | more".
+ */
+ if (!IsInteractive(raw_in))
+ raw_in = raw_out;
+ else if (!IsInteractive(raw_out))
+ raw_out = raw_in;
+ }
+
+ out_flush();
+
+ wb_window = NULL;
+#ifndef __amigaos4__
+ if ((IntuitionBase = (struct IntuitionBase *)
+ OpenLibrary((UBYTE *)intlibname, 0L)) == NULL)
+ {
+ mch_errmsg(_("cannot open "));
+ mch_errmsg(intlibname);
+ mch_errmsg("!?\n");
+ mch_exit(3);
+ }
+#endif
+}
+
+#ifndef PROTO
+# include <workbench/startup.h>
+#endif
+
+/*
+ * Check_win checks whether we have an interactive window.
+ * If not, a new window is opened with the newcli command.
+ * If we would open a window ourselves, the :sh and :! commands would not
+ * work properly (Why? probably because we are then running in a background
+ * CLI). This also is the best way to assure proper working in a next
+ * Workbench release.
+ *
+ * For the -f option (foreground mode) we open our own window and disable :sh.
+ * Otherwise the calling program would never know when editing is finished.
+ */
+#define BUF2SIZE 320 /* length of buffer for argument with complete path */
+
+ int
+mch_check_win(int argc, char **argv)
+{
+ int i;
+ BPTR nilfh, fh;
+ char_u buf1[24];
+ char_u buf2[BUF2SIZE];
+ static char_u *(constrings[3]) = {(char_u *)"con:0/0/662/210/",
+ (char_u *)"con:0/0/640/200/",
+ (char_u *)"con:0/0/320/200/"};
+ static char_u *winerr = (char_u *)N_("VIM: Can't open window!\n");
+ struct WBArg *argp;
+ int ac;
+ char *av;
+ char_u *device = NULL;
+ int exitval = 4;
+#ifndef __amigaos4__
+ struct Library *DosBase;
+#endif
+ int usewin = FALSE;
+
+/*
+ * check if we are running under DOS 2.0x or higher
+ */
+#ifndef __amigaos4__
+ DosBase = OpenLibrary(DOS_LIBRARY, 37L);
+ if (DosBase != NULL)
+ /* if (((struct Library *)DOSBase)->lib_Version >= 37) */
+ {
+ CloseLibrary(DosBase);
+# ifdef FEAT_ARP
+ dos2 = TRUE;
+# endif
+ }
+ else /* without arp functions we NEED 2.0 */
+ {
+# ifndef FEAT_ARP
+ mch_errmsg(_("Need Amigados version 2.04 or later\n"));
+ exit(3);
+# else
+ /* need arp functions for dos 1.x */
+ if (!(ArpBase = (struct ArpBase *) OpenLibrary((UBYTE *)ArpName, ArpVersion)))
+ {
+ fprintf(stderr, _("Need %s version %ld\n"), ArpName, ArpVersion);
+ exit(3);
+ }
+# endif
+ }
+#endif /* __amigaos4__ */
+
+ /*
+ * scan argv[] for the "-f" and "-d" arguments
+ */
+ for (i = 1; i < argc; ++i)
+ if (argv[i][0] == '-')
+ {
+ switch (argv[i][1])
+ {
+ case 'f':
+ usewin = TRUE;
+ break;
+
+ case 'd':
+ if (i < argc - 1
+#ifdef FEAT_DIFF
+ /* require using "-dev", "-d" means diff mode */
+ && argv[i][2] == 'e' && argv[i][3] == 'v'
+#endif
+ )
+ device = (char_u *)argv[i + 1];
+ break;
+ }
+ }
+
+/*
+ * If we were not started from workbench, do not have a "-d" or "-dev"
+ * argument and we have been started with an interactive window, use that
+ * window.
+ */
+ if (argc != 0
+ && device == NULL
+ && (IsInteractive(Input()) || IsInteractive(Output())))
+ return OK;
+
+/*
+ * When given the "-f" argument, we open our own window. We can't use the
+ * newcli trick below, because the calling program (mail, rn, etc.) would not
+ * know when we are finished.
+ */
+ if (usewin)
+ {
+ /*
+ * Try to open a window. First try the specified device.
+ * Then try a 24 line 80 column window.
+ * If that fails, try two smaller ones.
+ */
+ for (i = -1; i < 3; ++i)
+ {
+ if (i >= 0)
+ device = constrings[i];
+ if (device != NULL && (raw_in = Open((UBYTE *)device,
+ (long)MODE_NEWFILE)) != (BPTR)NULL)
+ break;
+ }
+ if (raw_in == (BPTR)NULL) /* all three failed */
+ {
+ mch_errmsg(_(winerr));
+ goto exit;
+ }
+ raw_out = raw_in;
+ close_win = TRUE;
+ return OK;
+ }
+
+ if ((nilfh = Open((UBYTE *)"NIL:", (long)MODE_NEWFILE)) == (BPTR)NULL)
+ {
+ mch_errmsg(_("Cannot open NIL:\n"));
+ goto exit;
+ }
+
+ /*
+ * Make a unique name for the temp file (which we will not delete!).
+ * Use a pointer on the stack (nobody else will be using it).
+ * Under AmigaOS4, this assumption might change in the future, so
+ * we use a pointer to the current task instead. This should be a
+ * shared structure and thus globally unique.
+ */
+#ifdef __amigaos4__
+ sprintf((char *)buf1, "t:nc%p", FindTask(0));
+#else
+ sprintf((char *)buf1, "t:nc%ld", (long)buf1);
+#endif
+ if ((fh = Open((UBYTE *)buf1, (long)MODE_NEWFILE)) == (BPTR)NULL)
+ {
+ mch_errmsg(_("Cannot create "));
+ mch_errmsg((char *)buf1);
+ mch_errmsg("\n");
+ goto exit;
+ }
+ /*
+ * Write the command into the file, put quotes around the arguments that
+ * have a space in them.
+ */
+ if (argc == 0) /* run from workbench */
+ ac = ((struct WBStartup *)argv)->sm_NumArgs;
+ else
+ ac = argc;
+ for (i = 0; i < ac; ++i)
+ {
+ if (argc == 0)
+ {
+ *buf2 = NUL;
+ argp = &(((struct WBStartup *)argv)->sm_ArgList[i]);
+ if (argp->wa_Lock)
+ (void)lock2name(argp->wa_Lock, buf2, (long)(BUF2SIZE - 1));
+#ifdef FEAT_ARP
+ if (dos2) /* use 2.0 function */
+#endif
+ AddPart((UBYTE *)buf2, (UBYTE *)argp->wa_Name, (long)(BUF2SIZE - 1));
+#ifdef FEAT_ARP
+ else /* use arp function */
+ TackOn((char *)buf2, argp->wa_Name);
+#endif
+ av = (char *)buf2;
+ }
+ else
+ av = argv[i];
+
+ /* skip '-d' or "-dev" option */
+ if (av[0] == '-' && av[1] == 'd'
+#ifdef FEAT_DIFF
+ && av[2] == 'e' && av[3] == 'v'
+#endif
+ )
+ {
+ ++i;
+ continue;
+ }
+ if (vim_strchr((char_u *)av, ' '))
+ Write(fh, "\"", 1L);
+ Write(fh, av, (long)strlen(av));
+ if (vim_strchr((char_u *)av, ' '))
+ Write(fh, "\"", 1L);
+ Write(fh, " ", 1L);
+ }
+ Write(fh, "\nendcli\n", 8L);
+ Close(fh);
+
+/*
+ * Try to open a new cli in a window. If "-d" or "-dev" argument was given try
+ * to open the specified device. Then try a 24 line 80 column window. If that
+ * fails, try two smaller ones.
+ */
+ for (i = -1; i < 3; ++i)
+ {
+ if (i >= 0)
+ device = constrings[i];
+ else if (device == NULL)
+ continue;
+ sprintf((char *)buf2, "newcli <nil: >nil: %s from %s", (char *)device, (char *)buf1);
+#ifdef FEAT_ARP
+ if (dos2)
+ {
+#endif
+ if (!SystemTags((UBYTE *)buf2, SYS_UserShell, TRUE, TAG_DONE))
+ break;
+#ifdef FEAT_ARP
+ }
+ else
+ {
+ if (Execute((UBYTE *)buf2, nilfh, nilfh))
+ break;
+ }
+#endif
+ }
+ if (i == 3) /* all three failed */
+ {
+ DeleteFile((UBYTE *)buf1);
+ mch_errmsg(_(winerr));
+ goto exit;
+ }
+ exitval = 0; /* The Execute succeeded: exit this program */
+
+exit:
+#ifdef FEAT_ARP
+ if (ArpBase)
+ CloseLibrary((struct Library *) ArpBase);
+#endif
+ exit(exitval);
+ /* NOTREACHED */
+ return FAIL;
+}
+
+/*
+ * Return TRUE if the input comes from a terminal, FALSE otherwise.
+ * We fake there is a window, because we can always open one!
+ */
+ int
+mch_input_isatty(void)
+{
+ return TRUE;
+}
+
+/*
+ * fname_case(): Set the case of the file name, if it already exists.
+ * This will cause the file name to remain exactly the same
+ * if the file system ignores, but preserves case.
+ */
+/*ARGSUSED*/
+ void
+fname_case(
+ char_u *name,
+ int len) /* buffer size, ignored here */
+{
+ struct FileInfoBlock *fib;
+ size_t flen;
+
+ fib = get_fib(name);
+ if (fib != NULL)
+ {
+ flen = STRLEN(name);
+ /* TODO: Check if this fix applies to AmigaOS < 4 too.*/
+#ifdef __amigaos4__
+ if (fib->fib_DirEntryType == ST_ROOT)
+ strcat(fib->fib_FileName, ":");
+#endif
+ if (flen == strlen(fib->fib_FileName)) /* safety check */
+ mch_memmove(name, fib->fib_FileName, flen);
+ free_fib(fib);
+ }
+}
+
+/*
+ * Get the FileInfoBlock for file "fname"
+ * The returned structure has to be free()d.
+ * Returns NULL on error.
+ */
+ static struct FileInfoBlock *
+get_fib(char_u *fname)
+{
+ BPTR flock;
+ struct FileInfoBlock *fib;
+
+ if (fname == NULL) /* safety check */
+ return NULL;
+#ifdef __amigaos4__
+ fib = AllocDosObject(DOS_FIB,0);
+#else
+ fib = (struct FileInfoBlock *)alloc(sizeof(struct FileInfoBlock));
+#endif
+ if (fib != NULL)
+ {
+ flock = Lock((UBYTE *)fname, (long)ACCESS_READ);
+ if (flock == (BPTR)NULL || !Examine(flock, fib))
+ {
+ free_fib(fib); /* in case of an error the memory is freed here */
+ fib = NULL;
+ }
+ if (flock)
+ UnLock(flock);
+ }
+ return fib;
+}
+
+#ifdef FEAT_TITLE
+/*
+ * set the title of our window
+ * icon name is not set
+ */
+ void
+mch_settitle(char_u *title, char_u *icon)
+{
+ if (wb_window != NULL && title != NULL)
+ SetWindowTitles(wb_window, (UBYTE *)title, (UBYTE *)-1L);
+}
+
+/*
+ * Restore the window/icon title.
+ * which is one of:
+ * SAVE_RESTORE_TITLE Just restore title
+ * SAVE_RESTORE_ICON Just restore icon (which we don't have)
+ * SAVE_RESTORE_BOTH Restore title and icon (which we don't have)
+ */
+ void
+mch_restore_title(int which)
+{
+ if (which & SAVE_RESTORE_TITLE)
+ mch_settitle(oldwindowtitle, NULL);
+}
+
+ int
+mch_can_restore_title(void)
+{
+ return (wb_window != NULL);
+}
+
+ int
+mch_can_restore_icon(void)
+{
+ return FALSE;
+}
+#endif
+
+/*
+ * Insert user name in s[len].
+ */
+ int
+mch_get_user_name(char_u *s, int len)
+{
+ /* TODO: Implement this. */
+ *s = NUL;
+ return FAIL;
+}
+
+/*
+ * Insert host name is s[len].
+ */
+ void
+mch_get_host_name(char_u *s, int len)
+{
+#if defined(__amigaos4__) && defined(__CLIB2__)
+ gethostname(s, len);
+#else
+ vim_strncpy(s, "Amiga", len - 1);
+#endif
+}
+
+/*
+ * return process ID
+ */
+ long
+mch_get_pid(void)
+{
+#ifdef __amigaos4__
+ /* This is as close to a pid as we can come. We could use CLI numbers also,
+ * but then we would have two different types of process identifiers.
+ */
+ return((long)FindTask(0));
+#else
+ return (long)0;
+#endif
+}
+
+/*
+ * Get name of current directory into buffer 'buf' of length 'len' bytes.
+ * Return OK for success, FAIL for failure.
+ */
+ int
+mch_dirname(char_u *buf, int len)
+{
+ return mch_FullName((char_u *)"", buf, len, FALSE);
+}
+
+/*
+ * get absolute file name into buffer 'buf' of length 'len' bytes
+ *
+ * return FAIL for failure, OK otherwise
+ */
+ int
+mch_FullName(
+ char_u *fname,
+ char_u *buf,
+ int len,
+ int force)
+{
+ BPTR l;
+ int retval = FAIL;
+ int i;
+
+ /* Lock the file. If it exists, we can get the exact name. */
+ if ((l = Lock((UBYTE *)fname, (long)ACCESS_READ)) != (BPTR)0)
+ {
+ retval = lock2name(l, buf, (long)len - 1);
+ UnLock(l);
+ }
+ else if (force || !mch_isFullName(fname)) /* not a full path yet */
+ {
+ /*
+ * If the file cannot be locked (doesn't exist), try to lock the
+ * current directory and concatenate the file name.
+ */
+ if ((l = Lock((UBYTE *)"", (long)ACCESS_READ)) != (BPTR)NULL)
+ {
+ retval = lock2name(l, buf, (long)len);
+ UnLock(l);
+ if (retval == OK)
+ {
+ i = STRLEN(buf);
+ /* Concatenate the fname to the directory. Don't add a slash
+ * if fname is empty, but do change "" to "/". */
+ if (i == 0 || *fname != NUL)
+ {
+ if (i < len - 1 && (i == 0 || buf[i - 1] != ':'))
+ buf[i++] = '/';
+ vim_strncpy(buf + i, fname, len - i - 1);
+ }
+ }
+ }
+ }
+ if (*buf == 0 || *buf == ':')
+ retval = FAIL; /* something failed; use the file name */
+ return retval;
+}
+
+/*
+ * Return TRUE if "fname" does not depend on the current directory.
+ */
+ int
+mch_isFullName(char_u *fname)
+{
+ return (vim_strchr(fname, ':') != NULL && *fname != ':');
+}
+
+/*
+ * Get the full file name from a lock. Use 2.0 function if possible, because
+ * the arp function has more restrictions on the path length.
+ *
+ * return FAIL for failure, OK otherwise
+ */
+ static int
+lock2name(BPTR lock, char_u *buf, long len)
+{
+#ifdef FEAT_ARP
+ if (dos2) /* use 2.0 function */
+#endif
+ return ((int)NameFromLock(lock, (UBYTE *)buf, len) ? OK : FAIL);
+#ifdef FEAT_ARP
+ else /* use arp function */
+ return ((int)PathName(lock, (char *)buf, (long)(len/32)) ? OK : FAIL);
+#endif
+}
+
+/*
+ * get file permissions for 'name'
+ * Returns -1 when it doesn't exist.
+ */
+ long
+mch_getperm(char_u *name)
+{
+ struct FileInfoBlock *fib;
+ long retval = -1;
+
+ fib = get_fib(name);
+ if (fib != NULL)
+ {
+ retval = fib->fib_Protection;
+ free_fib(fib);
+ }
+ return retval;
+}
+
+/*
+ * set file permission for 'name' to 'perm'
+ *
+ * return FAIL for failure, OK otherwise
+ */
+ int
+mch_setperm(char_u *name, long perm)
+{
+ perm &= ~FIBF_ARCHIVE; /* reset archived bit */
+ return (SetProtection((UBYTE *)name, (long)perm) ? OK : FAIL);
+}
+
+/*
+ * Set hidden flag for "name".
+ */
+ void
+mch_hide(char_u *name)
+{
+ /* can't hide a file */
+}
+
+/*
+ * return FALSE if "name" is not a directory
+ * return TRUE if "name" is a directory.
+ * return FALSE for error.
+ */
+ int
+mch_isdir(char_u *name)
+{
+ struct FileInfoBlock *fib;
+ int retval = FALSE;
+
+ fib = get_fib(name);
+ if (fib != NULL)
+ {
+#ifdef __amigaos4__
+ retval = (FIB_IS_DRAWER(fib)) ? TRUE : FALSE;
+#else
+ retval = ((fib->fib_DirEntryType >= 0) ? TRUE : FALSE);
+#endif
+ free_fib(fib);
+ }
+ return retval;
+}
+
+/*
+ * Create directory "name".
+ */
+ int
+mch_mkdir(char_u *name)
+{
+ BPTR lock;
+
+ lock = CreateDir(name);
+ if (lock != NULL)
+ {
+ UnLock(lock);
+ return 0;
+ }
+ return -1;
+}
+
+/*
+ * Return 1 if "name" can be executed, 0 if not.
+ * If "use_path" is FALSE only check if "name" is executable.
+ * Return -1 if unknown.
+ */
+ int
+mch_can_exe(char_u *name, char_u **path, int use_path)
+{
+ /* TODO */
+ return -1;
+}
+
+/*
+ * Check what "name" is:
+ * NODE_NORMAL: file or directory (or doesn't exist)
+ * NODE_WRITABLE: writable device, socket, fifo, etc.
+ * NODE_OTHER: non-writable things
+ */
+ int
+mch_nodetype(char_u *name)
+{
+ /* TODO */
+ return NODE_NORMAL;
+}
+
+ void
+mch_early_init(void)
+{
+}
+
+/*
+ * Careful: mch_exit() may be called before mch_init()!
+ */
+ void
+mch_exit(int r)
+{
+ exiting = TRUE;
+
+ if (raw_in) /* put terminal in 'normal' mode */
+ {
+ settmode(TMODE_COOK);
+ stoptermcap();
+ }
+ out_char('\n');
+ if (raw_out)
+ {
+ if (term_console)
+ {
+ win_resize_off(); /* window resize events de-activated */
+ if (size_set)
+ OUT_STR("\233t\233u"); /* reset window size (CSI t CSI u) */
+ }
+ out_flush();
+ }
+
+#ifdef FEAT_TITLE
+ mch_restore_title(SAVE_RESTORE_BOTH); /* restore window title */
+#endif
+
+ ml_close_all(TRUE); /* remove all memfiles */
+
+#ifdef FEAT_ARP
+ if (ArpBase)
+ CloseLibrary((struct Library *) ArpBase);
+#endif
+ if (close_win)
+ Close(raw_in);
+ if (r)
+ printf(_("Vim exiting with %d\n"), r); /* somehow this makes :cq work!? */
+ exit(r);
+}
+
+/*
+ * This is a routine for setting a given stream to raw or cooked mode on the
+ * Amiga . This is useful when you are using Lattice C to produce programs
+ * that want to read single characters with the "getch()" or "fgetc" call.
+ *
+ * Written : 18-Jun-87 By Chuck McManis.
+ */
+
+#define MP(xx) ((struct MsgPort *)((struct FileHandle *) (BADDR(xx)))->fh_Type)
+
+/*
+ * Function mch_settmode() - Convert the specified file pointer to 'raw' or
+ * 'cooked' mode. This only works on TTY's.
+ *
+ * Raw: keeps DOS from translating keys for you, also (BIG WIN) it means
+ * getch() will return immediately rather than wait for a return. You
+ * lose editing features though.
+ *
+ * Cooked: This function returns the designate file pointer to its normal,
+ * wait for a <CR> mode. This is exactly like raw() except that
+ * it sends a 0 to the console to make it back into a CON: from a RAW:
+ */
+ void
+mch_settmode(int tmode)
+{
+#if defined(__AROS__) || defined(__amigaos4__)
+ if (!SetMode(raw_in, tmode == TMODE_RAW ? 1 : 0))
+#else
+ if (dos_packet(MP(raw_in), (long)ACTION_SCREEN_MODE,
+ tmode == TMODE_RAW ? -1L : 0L) == 0)
+#endif
+ mch_errmsg(_("cannot change console mode ?!\n"));
+}
+
+/*
+ * set screen mode, always fails.
+ */
+ int
+mch_screenmode(char_u *arg)
+{
+ emsg(_(e_screenmode));
+ return FAIL;
+}
+
+/*
+ * Code for this routine came from the following :
+ *
+ * ConPackets.c - C. Scheppner, A. Finkel, P. Lindsay CBM
+ * DOS packet example
+ * Requires 1.2
+ *
+ * Found on Fish Disk 56.
+ *
+ * Heavely modified by mool.
+ */
+
+#ifndef PROTO
+# include <devices/conunit.h>
+#endif
+
+/*
+ * try to get the real window size
+ * return FAIL for failure, OK otherwise
+ */
+ int
+mch_get_shellsize(void)
+{
+ struct ConUnit *conUnit;
+#ifndef __amigaos4__
+ char id_a[sizeof(struct InfoData) + 3];
+#endif
+ struct InfoData *id=0;
+
+ if (!term_console) /* not an amiga window */
+ goto out;
+
+ /* insure longword alignment */
+#ifdef __amigaos4__
+ if (!(id = AllocDosObject(DOS_INFODATA, 0)))
+ goto out;
+#else
+ id = (struct InfoData *)(((long)id_a + 3L) & ~3L);
+#endif
+
+ /*
+ * Should make console aware of real window size, not the one we set.
+ * Unfortunately, under DOS 2.0x this redraws the window and it
+ * is rarely needed, so we skip it now, unless we changed the size.
+ */
+ if (size_set)
+ OUT_STR("\233t\233u"); /* CSI t CSI u */
+ out_flush();
+
+#ifdef __AROS__
+ if (!Info(raw_out, id)
+ || (wb_window = (struct Window *) id->id_VolumeNode) == NULL)
+#else
+ if (dos_packet(MP(raw_out), (long)ACTION_DISK_INFO, ((ULONG) id) >> 2) == 0
+ || (wb_window = (struct Window *)id->id_VolumeNode) == NULL)
+#endif
+ {
+ /* it's not an amiga window, maybe aux device */
+ /* terminal type should be set */
+ term_console = FALSE;
+ goto out;
+ }
+ if (oldwindowtitle == NULL)
+ oldwindowtitle = (char_u *)wb_window->Title;
+ if (id->id_InUse == (BPTR)NULL)
+ {
+ mch_errmsg(_("mch_get_shellsize: not a console??\n"));
+ return FAIL;
+ }
+ conUnit = (struct ConUnit *) ((struct IOStdReq *) id->id_InUse)->io_Unit;
+
+ /* get window size */
+ Rows = conUnit->cu_YMax + 1;
+ Columns = conUnit->cu_XMax + 1;
+ if (Rows < 0 || Rows > 200) /* cannot be an amiga window */
+ {
+ Columns = 80;
+ Rows = 24;
+ term_console = FALSE;
+ return FAIL;
+ }
+
+ return OK;
+out:
+#ifdef __amigaos4__
+ FreeDosObject(DOS_INFODATA, id); /* Safe to pass NULL */
+#endif
+
+ return FAIL;
+}
+
+/*
+ * Try to set the real window size to Rows and Columns.
+ */
+ void
+mch_set_shellsize(void)
+{
+ if (term_console)
+ {
+ size_set = TRUE;
+ out_char(CSI);
+ out_num((long)Rows);
+ out_char('t');
+ out_char(CSI);
+ out_num((long)Columns);
+ out_char('u');
+ out_flush();
+ }
+}
+
+/*
+ * Rows and/or Columns has changed.
+ */
+ void
+mch_new_shellsize(void)
+{
+ /* Nothing to do. */
+}
+
+/*
+ * out_num - output a (big) number fast
+ */
+ static void
+out_num(long n)
+{
+ OUT_STR_NF(tltoa((unsigned long)n));
+}
+
+#if !defined(AZTEC_C) && !defined(__AROS__) && !defined(__amigaos4__)
+/*
+ * Sendpacket.c
+ *
+ * An invaluable addition to your Amiga.lib file. This code sends a packet to
+ * the given message port. This makes working around DOS lots easier.
+ *
+ * Note, I didn't write this, those wonderful folks at CBM did. I do suggest
+ * however that you may wish to add it to Amiga.Lib, to do so, compile it and
+ * say 'oml lib:amiga.lib -r sendpacket.o'
+ */
+
+#ifndef PROTO
+/* #include <proto/exec.h> */
+/* #include <proto/dos.h> */
+# include <exec/memory.h>
+#endif
+
+/*
+ * Function - dos_packet written by Phil Lindsay, Carolyn Scheppner, and Andy
+ * Finkel. This function will send a packet of the given type to the Message
+ * Port supplied.
+ */
+
+ static long
+dos_packet(
+ struct MsgPort *pid, /* process identifier ... (handlers message port) */
+ long action, /* packet type ... (what you want handler to do) */
+ long arg) /* single argument */
+{
+# ifdef FEAT_ARP
+ struct MsgPort *replyport;
+ struct StandardPacket *packet;
+ long res1;
+
+ if (dos2)
+# endif
+ return DoPkt(pid, action, arg, 0L, 0L, 0L, 0L); /* use 2.0 function */
+# ifdef FEAT_ARP
+
+ replyport = (struct MsgPort *) CreatePort(NULL, 0); /* use arp function */
+ if (!replyport)
+ return (0);
+
+ /* Allocate space for a packet, make it public and clear it */
+ packet = (struct StandardPacket *)
+ AllocMem((long) sizeof(struct StandardPacket), MEMF_PUBLIC | MEMF_CLEAR);
+ if (!packet) {
+ DeletePort(replyport);
+ return (0);
+ }
+ packet->sp_Msg.mn_Node.ln_Name = (char *) &(packet->sp_Pkt);
+ packet->sp_Pkt.dp_Link = &(packet->sp_Msg);
+ packet->sp_Pkt.dp_Port = replyport;
+ packet->sp_Pkt.dp_Type = action;
+ packet->sp_Pkt.dp_Arg1 = arg;
+
+ PutMsg(pid, (struct Message *)packet); /* send packet */
+
+ WaitPort(replyport);
+ GetMsg(replyport);
+
+ res1 = packet->sp_Pkt.dp_Res1;
+
+ FreeMem(packet, (long) sizeof(struct StandardPacket));
+ DeletePort(replyport);
+
+ return (res1);
+# endif
+}
+#endif /* !defined(AZTEC_C) && !defined(__AROS__) */
+
+/*
+ * Call shell.
+ * Return error number for failure, 0 otherwise
+ */
+ int
+mch_call_shell(
+ char_u *cmd,
+ int options) /* SHELL_*, see vim.h */
+{
+ BPTR mydir;
+ int x;
+ int tmode = cur_tmode;
+#ifdef AZTEC_C
+ int use_execute;
+ char_u *shellcmd = NULL;
+ char_u *shellarg;
+#endif
+ int retval = 0;
+
+ if (close_win)
+ {
+ /* if Vim opened a window: Executing a shell may cause crashes */
+ emsg(_("E360: Cannot execute shell with -f option"));
+ return -1;
+ }
+
+ if (term_console)
+ win_resize_off(); /* window resize events de-activated */
+ out_flush();
+
+ if (options & SHELL_COOKED)
+ settmode(TMODE_COOK); /* set to normal mode */
+ mydir = Lock((UBYTE *)"", (long)ACCESS_READ); /* remember current dir */
+
+#if !defined(AZTEC_C) /* not tested very much */
+ if (cmd == NULL)
+ {
+# ifdef FEAT_ARP
+ if (dos2)
+# endif
+ x = SystemTags(p_sh, SYS_UserShell, TRUE, TAG_DONE);
+# ifdef FEAT_ARP
+ else
+ x = Execute(p_sh, raw_in, raw_out);
+# endif
+ }
+ else
+ {
+# ifdef FEAT_ARP
+ if (dos2)
+# endif
+ x = SystemTags((char *)cmd, SYS_UserShell, TRUE, TAG_DONE);
+# ifdef FEAT_ARP
+ else
+ x = Execute((char *)cmd, 0L, raw_out);
+# endif
+ }
+# ifdef FEAT_ARP
+ if ((dos2 && x < 0) || (!dos2 && !x))
+# else
+ if (x < 0)
+# endif
+ {
+ msg_puts(_("Cannot execute "));
+ if (cmd == NULL)
+ {
+ msg_puts(_("shell "));
+ msg_outtrans(p_sh);
+ }
+ else
+ msg_outtrans(cmd);
+ msg_putchar('\n');
+ retval = -1;
+ }
+# ifdef FEAT_ARP
+ else if (!dos2 || x)
+# else
+ else if (x)
+# endif
+ {
+ if ((x = IoErr()) != 0)
+ {
+ if (!(options & SHELL_SILENT))
+ {
+ msg_putchar('\n');
+ msg_outnum((long)x);
+ msg_puts(_(" returned\n"));
+ }
+ retval = x;
+ }
+ }
+#else /* else part is for AZTEC_C */
+ if (p_st >= 4 || (p_st >= 2 && !(options & SHELL_FILTER)))
+ use_execute = 1;
+ else
+ use_execute = 0;
+ if (!use_execute)
+ {
+ /*
+ * separate shell name from argument
+ */
+ shellcmd = vim_strsave(p_sh);
+ if (shellcmd == NULL) /* out of memory, use Execute */
+ use_execute = 1;
+ else
+ {
+ shellarg = skiptowhite(shellcmd); /* find start of arguments */
+ if (*shellarg != NUL)
+ {
+ *shellarg++ = NUL;
+ shellarg = skipwhite(shellarg);
+ }
+ }
+ }
+ if (cmd == NULL)
+ {
+ if (use_execute)
+ {
+# ifdef FEAT_ARP
+ if (dos2)
+# endif
+ x = SystemTags((UBYTE *)p_sh, SYS_UserShell, TRUE, TAG_DONE);
+# ifdef FEAT_ARP
+ else
+ x = !Execute((UBYTE *)p_sh, raw_in, raw_out);
+# endif
+ }
+ else
+ x = fexecl((char *)shellcmd, (char *)shellcmd, (char *)shellarg, NULL);
+ }
+ else if (use_execute)
+ {
+# ifdef FEAT_ARP
+ if (dos2)
+# endif
+ x = SystemTags((UBYTE *)cmd, SYS_UserShell, TRUE, TAG_DONE);
+# ifdef FEAT_ARP
+ else
+ x = !Execute((UBYTE *)cmd, 0L, raw_out);
+# endif
+ }
+ else if (p_st & 1)
+ x = fexecl((char *)shellcmd, (char *)shellcmd, (char *)shellarg,
+ (char *)cmd, NULL);
+ else
+ x = fexecl((char *)shellcmd, (char *)shellcmd, (char *)shellarg,
+ (char *)p_shcf, (char *)cmd, NULL);
+# ifdef FEAT_ARP
+ if ((dos2 && x < 0) || (!dos2 && x))
+# else
+ if (x < 0)
+# endif
+ {
+ msg_puts(_("Cannot execute "));
+ if (use_execute)
+ {
+ if (cmd == NULL)
+ msg_outtrans(p_sh);
+ else
+ msg_outtrans(cmd);
+ }
+ else
+ {
+ msg_puts(_("shell "));
+ msg_outtrans(shellcmd);
+ }
+ msg_putchar('\n');
+ retval = -1;
+ }
+ else
+ {
+ if (use_execute)
+ {
+# ifdef FEAT_ARP
+ if (!dos2 || x)
+# else
+ if (x)
+# endif
+ x = IoErr();
+ }
+ else
+ x = wait();
+ if (x)
+ {
+ if (!(options & SHELL_SILENT) && !emsg_silent)
+ {
+ msg_putchar('\n');
+ msg_outnum((long)x);
+ msg_puts(_(" returned\n"));
+ }
+ retval = x;
+ }
+ }
+ vim_free(shellcmd);
+#endif /* AZTEC_C */
+
+ if ((mydir = CurrentDir(mydir)) != 0) /* make sure we stay in the same directory */
+ UnLock(mydir);
+ if (tmode == TMODE_RAW)
+ settmode(TMODE_RAW); /* set to raw mode */
+#ifdef FEAT_TITLE
+ resettitle();
+#endif
+ if (term_console)
+ win_resize_on(); /* window resize events activated */
+ return retval;
+}
+
+/*
+ * check for an "interrupt signal"
+ * We only react to a CTRL-C, but also clear the other break signals to avoid
+ * trouble with lattice-c programs.
+ */
+ void
+mch_breakcheck(int force)
+{
+ if (SetSignal(0L, (long)(SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_D|SIGBREAKF_CTRL_E|SIGBREAKF_CTRL_F)) & SIGBREAKF_CTRL_C)
+ got_int = TRUE;
+}
+
+/* this routine causes manx to use this Chk_Abort() rather than its own */
+/* otherwise it resets our ^C when doing any I/O (even when Enable_Abort */
+/* is zero). Since we want to check for our own ^C's */
+
+#ifdef _DCC
+#define Chk_Abort chkabort
+#endif
+
+#ifdef LATTICE
+void __regargs __chkabort(void);
+
+void __regargs __chkabort(void)
+{}
+
+#else
+ long
+Chk_Abort(void)
+{
+ return(0L);
+}
+#endif
+
+/*
+ * mch_expandpath() - this code does wild-card pattern matching using the arp
+ * routines.
+ *
+ * "pat" has backslashes before chars that are not to be expanded.
+ * Returns the number of matches found.
+ *
+ * This is based on WildDemo2.c (found in arp1.1 distribution).
+ * That code's copyright follows:
+ * Copyright (c) 1987, Scott Ballantyne
+ * Use and abuse as you please.
+ */
+
+#ifdef __amigaos4__
+# define ANCHOR_BUF_SIZE 1024
+#else
+# define ANCHOR_BUF_SIZE (512)
+# define ANCHOR_SIZE (sizeof(struct AnchorPath) + ANCHOR_BUF_SIZE)
+#endif
+
+ int
+mch_expandpath(
+ garray_T *gap,
+ char_u *pat,
+ int flags) /* EW_* flags */
+{
+ struct AnchorPath *Anchor;
+ LONG Result;
+ char_u *starbuf, *sp, *dp;
+ int start_len;
+ int matches;
+#ifdef __amigaos4__
+ struct TagItem AnchorTags[] = {
+ {ADO_Strlen, ANCHOR_BUF_SIZE},
+ {ADO_Flags, APF_DODOT|APF_DOWILD|APF_MultiAssigns},
+ {TAG_DONE, 0L}
+ };
+#endif
+
+ start_len = gap->ga_len;
+
+ /* Get our AnchorBase */
+#ifdef __amigaos4__
+ Anchor = AllocDosObject(DOS_ANCHORPATH, AnchorTags);
+#else
+ Anchor = (struct AnchorPath *)alloc_clear((unsigned)ANCHOR_SIZE);
+#endif
+ if (Anchor == NULL)
+ return 0;
+
+#ifndef __amigaos4__
+ Anchor->ap_Strlen = ANCHOR_BUF_SIZE; /* ap_Length not supported anymore */
+# ifdef APF_DODOT
+ Anchor->ap_Flags = APF_DODOT | APF_DOWILD; /* allow '.' for current dir */
+# else
+ Anchor->ap_Flags = APF_DoDot | APF_DoWild; /* allow '.' for current dir */
+# endif
+#endif
+
+#ifdef FEAT_ARP
+ if (dos2)
+ {
+#endif
+ /* hack to replace '*' by '#?' */
+ starbuf = alloc((unsigned)(2 * STRLEN(pat) + 1));
+ if (starbuf == NULL)
+ goto Return;
+ for (sp = pat, dp = starbuf; *sp; ++sp)
+ {
+ if (*sp == '*')
+ {
+ *dp++ = '#';
+ *dp++ = '?';
+ }
+ else
+ *dp++ = *sp;
+ }
+ *dp = NUL;
+ Result = MatchFirst((UBYTE *)starbuf, Anchor);
+ vim_free(starbuf);
+#ifdef FEAT_ARP
+ }
+ else
+ Result = FindFirst((char *)pat, Anchor);
+#endif
+
+ /*
+ * Loop to get all matches.
+ */
+ while (Result == 0)
+ {
+#ifdef __amigaos4__
+ addfile(gap, (char_u *)Anchor->ap_Buffer, flags);
+#else
+ addfile(gap, (char_u *)Anchor->ap_Buf, flags);
+#endif
+#ifdef FEAT_ARP
+ if (dos2)
+#endif
+ Result = MatchNext(Anchor);
+#ifdef FEAT_ARP
+ else
+ Result = FindNext(Anchor);
+#endif
+ }
+ matches = gap->ga_len - start_len;
+
+ if (Result == ERROR_BUFFER_OVERFLOW)
+ emsg(_("ANCHOR_BUF_SIZE too small."));
+ else if (matches == 0 && Result != ERROR_OBJECT_NOT_FOUND
+ && Result != ERROR_DEVICE_NOT_MOUNTED
+ && Result != ERROR_NO_MORE_ENTRIES)
+ emsg(_("I/O ERROR"));
+
+ /*
+ * Sort the files for this pattern.
+ */
+ if (matches)
+ qsort((void *)(((char_u **)gap->ga_data) + start_len),
+ (size_t)matches, sizeof(char_u *), sortcmp);
+
+ /* Free the wildcard stuff */
+#ifdef FEAT_ARP
+ if (dos2)
+#endif
+ MatchEnd(Anchor);
+#ifdef FEAT_ARP
+ else
+ FreeAnchorChain(Anchor);
+#endif
+
+Return:
+#ifdef __amigaos4__
+ FreeDosObject(DOS_ANCHORPATH, Anchor);
+#else
+ vim_free(Anchor);
+#endif
+
+ return matches;
+}
+
+ static int
+sortcmp(const void *a, const void *b)
+{
+ char *s = *(char **)a;
+ char *t = *(char **)b;
+
+ return pathcmp(s, t, -1);
+}
+
+/*
+ * Return TRUE if "p" has wildcards that can be expanded by mch_expandpath().
+ */
+ int
+mch_has_exp_wildcard(char_u *p)
+{
+ for ( ; *p; MB_PTR_ADV(p))
+ {
+ if (*p == '\\' && p[1] != NUL)
+ ++p;
+ else if (vim_strchr((char_u *)"*?[(#", *p) != NULL)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+ int
+mch_has_wildcard(char_u *p)
+{
+ for ( ; *p; MB_PTR_ADV(p))
+ {
+ if (*p == '\\' && p[1] != NUL)
+ ++p;
+ else
+ if (vim_strchr((char_u *)
+# ifdef VIM_BACKTICK
+ "*?[(#$`"
+# else
+ "*?[(#$"
+# endif
+ , *p) != NULL
+ || (*p == '~' && p[1] != NUL))
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * With AmigaDOS 2.0 support for reading local environment variables
+ *
+ * Two buffers are allocated:
+ * - A big one to do the expansion into. It is freed before returning.
+ * - A small one to hold the return value. It is kept until the next call.
+ */
+ char_u *
+mch_getenv(char_u *var)
+{
+ int len;
+ UBYTE *buf; /* buffer to expand in */
+ char_u *retval; /* return value */
+ static char_u *alloced = NULL; /* allocated memory */
+
+#ifdef FEAT_ARP
+ if (!dos2)
+ retval = (char_u *)getenv((char *)var);
+ else
+#endif
+ {
+ VIM_CLEAR(alloced);
+ retval = NULL;
+
+ buf = alloc(IOSIZE);
+ if (buf == NULL)
+ return NULL;
+
+ len = GetVar((UBYTE *)var, buf, (long)(IOSIZE - 1), (long)0);
+ if (len >= 0)
+ {
+ retval = vim_strsave((char_u *)buf);
+ alloced = retval;
+ }
+
+ vim_free(buf);
+ }
+
+ /* if $VIM is not defined, use "vim:" instead */
+ if (retval == NULL && STRCMP(var, "VIM") == 0)
+ retval = (char_u *)"vim:";
+
+ return retval;
+}
+
+/*
+ * Amiga version of setenv() with AmigaDOS 2.0 support.
+ */
+/* ARGSUSED */
+ int
+mch_setenv(char *var, char *value, int x)
+{
+#ifdef FEAT_ARP
+ if (!dos2)
+ return setenv(var, value);
+#endif
+
+ if (SetVar((UBYTE *)var, (UBYTE *)value, (LONG)-1, (ULONG)GVF_LOCAL_ONLY))
+ return 0; /* success */
+ return -1; /* failure */
+}
diff --git a/src/os_amiga.h b/src/os_amiga.h
new file mode 100644
index 0000000..336cbdb
--- /dev/null
+++ b/src/os_amiga.h
@@ -0,0 +1,230 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * Do ":help uganda" in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ */
+
+/*
+ * Amiga Machine-dependent things
+ */
+
+#define CASE_INSENSITIVE_FILENAME /* ignore case when comparing file names */
+#define SPACE_IN_FILENAME
+#define USE_FNAME_CASE /* adjust case of file names */
+#define USE_TERM_CONSOLE
+#define HAVE_AVAIL_MEM
+
+#ifndef HAVE_CONFIG_H
+# if defined(AZTEC_C) || defined(__amigaos4__)
+# define HAVE_STAT_H
+# endif
+# define HAVE_STDLIB_H
+# define HAVE_STRING_H
+# define HAVE_FCNTL_H
+# define HAVE_STRCSPN
+# define HAVE_STRICMP
+# define HAVE_STRNICMP
+# define HAVE_STRFTIME /* guessed */
+# define HAVE_SETENV
+# define HAVE_MEMSET
+# define HAVE_QSORT
+# if defined(__DATE__) && defined(__TIME__)
+# define HAVE_DATE_TIME
+# endif
+
+#endif /* HAVE_CONFIG_H */
+
+#ifndef DFLT_ERRORFILE
+# define DFLT_ERRORFILE "AztecC.Err" /* Should this change? */
+#endif
+
+#ifndef DFLT_RUNTIMEPATH
+# define DFLT_RUNTIMEPATH "home:vimfiles,$VIM/vimfiles,$VIMRUNTIME,$VIM/vimfiles/after,home:vimfiles/after"
+#endif
+#ifndef CLEAN_RUNTIMEPATH
+# define CLEAN_RUNTIMEPATH "$VIM/vimfiles,$VIMRUNTIME,$VIM/vimfiles/after"
+#endif
+
+#ifndef BASENAMELEN
+# define BASENAMELEN 26 /* Amiga */
+#endif
+
+#ifndef TEMPNAME
+# define TEMPNAME "t:v?XXXXXX"
+# define TEMPNAMELEN 12
+#endif
+
+/* cproto fails on missing include files */
+#ifndef PROTO
+
+#include <exec/types.h>
+#include <libraries/dos.h>
+#include <libraries/dosextens.h>
+
+/* Currently, all Amiga compilers except AZTEC C have these... */
+#ifndef AZTEC_C
+# include <proto/exec.h>
+# include <proto/dos.h>
+# include <proto/intuition.h>
+#endif
+
+#endif /* PROTO */
+
+#define FNAME_ILLEGAL ";*?`#%" /* illegal characters in a file name */
+
+/*
+ * Manx doesn't have off_t, define it here.
+ */
+#ifdef AZTEC_C
+typedef long off_t;
+#endif
+
+#ifdef LATTICE
+# define USE_TMPNAM /* use tmpnam() instead of mktemp() */
+#endif
+
+#ifdef __GNUC__
+# include <sys/stat.h>
+# include <unistd.h>
+#endif
+
+#ifndef PROTO
+/*
+ * arpbase.h must be included before functions.h
+ */
+#ifdef FEAT_ARP
+# include <libraries/arpbase.h>
+#endif
+
+#endif /* PROTO */
+
+/*
+ * This won't be needed if you have a version of Lattice 4.01 without broken
+ * break signal handling.
+ */
+#include <signal.h>
+
+/*
+ * Names for the EXRC, HELP and temporary files.
+ * Some of these may have been defined in the makefile.
+ */
+#ifndef SYS_VIMRC_FILE
+# define SYS_VIMRC_FILE "$VIM/vimrc"
+#endif
+#ifndef SYS_GVIMRC_FILE
+# define SYS_GVIMRC_FILE "$VIM/gvimrc"
+#endif
+#ifndef SYS_MENU_FILE
+# define SYS_MENU_FILE "$VIMRUNTIME/menu.vim"
+#endif
+#ifndef DFLT_HELPFILE
+# define DFLT_HELPFILE "$VIMRUNTIME/doc/help.txt"
+#endif
+#ifndef FILETYPE_FILE
+# define FILETYPE_FILE "filetype.vim"
+#endif
+#ifndef FTPLUGIN_FILE
+# define FTPLUGIN_FILE "ftplugin.vim"
+#endif
+#ifndef INDENT_FILE
+# define INDENT_FILE "indent.vim"
+#endif
+#ifndef FTOFF_FILE
+# define FTOFF_FILE "ftoff.vim"
+#endif
+#ifndef FTPLUGOF_FILE
+# define FTPLUGOF_FILE "ftplugof.vim"
+#endif
+#ifndef INDOFF_FILE
+# define INDOFF_FILE "indoff.vim"
+#endif
+#ifndef SYNTAX_FNAME
+# define SYNTAX_FNAME "$VIMRUNTIME/syntax/%s.vim"
+#endif
+
+#ifndef USR_EXRC_FILE
+# define USR_EXRC_FILE "s:.exrc"
+#endif
+#ifndef USR_EXRC_FILE2
+# define USR_EXRC_FILE2 "home:.exrc"
+#endif
+
+#ifndef USR_VIMRC_FILE
+# define USR_VIMRC_FILE "s:.vimrc"
+#endif
+#ifndef USR_VIMRC_FILE2
+# define USR_VIMRC_FILE2 "home:.vimrc"
+#endif
+#ifndef USR_VIMRC_FILE3
+# define USR_VIMRC_FILE3 "home:vimfiles:vimrc"
+#endif
+#ifndef USR_VIMRC_FILE4
+# define USR_VIMRC_FILE4 "$VIM/.vimrc"
+#endif
+#ifndef VIM_DEFAULTS_FILE
+# define VIM_DEFAULTS_FILE "$VIMRUNTIME/defaults.vim"
+#endif
+#ifndef EVIM_FILE
+# define EVIM_FILE "$VIMRUNTIME/evim.vim"
+#endif
+
+#ifndef USR_GVIMRC_FILE
+# define USR_GVIMRC_FILE "s:.gvimrc"
+#endif
+#ifndef USR_GVIMRC_FILE2
+# define USR_GVIMRC_FILE2 "home:.gvimrc"
+#endif
+#ifndef USR_GVIMRC_FILE3
+# define USR_GVIMRC_FILE3 "home:vimfiles:gvimrc"
+#endif
+#ifndef USR_GVIMRC_FILE4
+# define USR_GVIMRC_FILE4 "$VIM/.gvimrc"
+#endif
+
+#ifdef FEAT_VIMINFO
+# ifndef VIMINFO_FILE
+# define VIMINFO_FILE "s:.viminfo"
+# endif
+#endif /* FEAT_VIMINFO */
+
+#ifndef EXRC_FILE
+# define EXRC_FILE ".exrc"
+#endif
+
+#ifndef VIMRC_FILE
+# define VIMRC_FILE ".vimrc"
+#endif
+
+#ifndef GVIMRC_FILE
+# define GVIMRC_FILE ".gvimrc"
+#endif
+
+#ifndef DFLT_BDIR
+# define DFLT_BDIR ".,t:" /* default for 'backupdir' */
+#endif
+
+#ifndef DFLT_DIR
+# define DFLT_DIR ".,t:" /* default for 'directory' */
+#endif
+
+#ifndef DFLT_VDIR
+# define DFLT_VDIR "$VIM/vimfiles/view" /* default for 'viewdir' */
+#endif
+
+#ifndef DFLT_MAXMEM
+# define DFLT_MAXMEM 256 /* use up to 256Kbyte for buffer */
+#endif
+#ifndef DFLT_MAXMEMTOT
+# define DFLT_MAXMEMTOT 0 /* decide in set_init */
+#endif
+
+#if defined(SASC)
+int setenv(const char *, const char *);
+#endif
+
+#define mch_remove(x) remove((char *)(x))
+#define mch_rename(src, dst) rename(src, dst)
+#define mch_chdir(s) chdir(s)
+#define vim_mkdir(x, y) mch_mkdir(x)
diff --git a/src/os_beos.c b/src/os_beos.c
new file mode 100644
index 0000000..ebb4488
--- /dev/null
+++ b/src/os_beos.c
@@ -0,0 +1,200 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ * BeBox port Copyright 1997 by Olaf Seibert.
+ *
+ * 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.
+ */
+/*
+ * os_beos.c Additional stuff for BeOS (rest is in os_unix.c)
+ */
+
+#include <float.h>
+#include <termios.h>
+#ifndef PROTO
+# include <kernel/OS.h>
+#endif
+
+#include "vim.h"
+
+#if USE_THREAD_FOR_INPUT_WITH_TIMEOUT
+
+#ifdef PROTO /* making prototypes on Unix */
+#define sem_id int
+#define thread_id int
+#endif
+
+char_u charbuf;
+signed char charcount;
+sem_id character_present;
+sem_id character_wanted;
+thread_id read_thread_id;
+
+#define TRY_ABORT 0 /* This code does not work so turn it off. */
+
+#if TRY_ABORT
+ static void
+mostly_ignore(int sig)
+{
+}
+#endif
+
+ static long
+read_thread(void *dummy)
+{
+ signal(SIGINT, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+#if TRY_ABORT
+ signal(SIGUSR1, mostly_ignore);
+#endif
+
+ for (;;) {
+ if (acquire_sem(character_wanted) != B_NO_ERROR)
+ break;
+ charcount = read(read_cmd_fd, &charbuf, 1);
+ release_sem(character_present);
+ }
+
+ return 0;
+}
+
+ void
+beos_cleanup_read_thread(void)
+{
+ if (character_present > 0)
+ delete_sem(character_present);
+ character_present = 0;
+ if (read_thread_id > 0)
+ kill_thread(read_thread_id);
+ read_thread_id = 0;
+}
+
+#endif
+
+/*
+ * select() emulation. Hopefully, in DR9 there will be something
+ * useful supplied by the system. ... Alas, not. Not in AAPR, nor
+ * in PR or even PR2... R3 then maybe? I don't think so!
+ */
+
+ int
+beos_select(int nbits,
+ struct fd_set *rbits,
+ struct fd_set *wbits,
+ struct fd_set *ebits,
+ struct timeval *timeout)
+{
+ bigtime_t tmo;
+
+ if (nbits == 0) {
+ /* select is purely being used for delay */
+ snooze(timeout->tv_sec * 1e6 + timeout->tv_usec);
+ return 0;
+ }
+#if 0
+ /*
+ * This does not seem to work either. Reads here are not supposed to
+ * block indefinitely, yet they do. This is most annoying.
+ */
+ if (FD_ISSET(0, rbits)) {
+ char cbuf[1];
+ int count;
+ struct termios told;
+ struct termios tnew;
+ tcgetattr(0, &told);
+ tnew = told;
+ tnew.c_lflag &= ~ICANON;
+ tnew.c_cc[VMIN] = 0;
+ tnew.c_cc[VTIME] = timeout->tv_sec * 10 + timeout->tv_usec / 100000;
+ tcsetattr(0, TCSANOW, &tnew);
+
+ count = read(0, &cbuf, sizeof(cbuf));
+ tcsetattr(0, TCSANOW, &told);
+ if (count > 0) {
+ add_to_input_buf(&cbuf[0], count);
+ return 1;
+ }
+ return 0;
+ }
+#endif
+#if USE_THREAD_FOR_INPUT_WITH_TIMEOUT
+ /*
+ * Check if the operation is really on stdin...
+ */
+ if (FD_ISSET(read_cmd_fd, rbits))
+ {
+ int acquired;
+
+ /*
+ * Is this the first time through?
+ * Then start up the thread and initialise the semaphores.
+ */
+ if (character_present == 0) {
+ character_present = create_sem(0, "vim character_present");
+ character_wanted = create_sem(1, "vim character_wanted");
+ read_thread_id = spawn_thread(read_thread, "vim async read",
+ B_NORMAL_PRIORITY, NULL);
+ atexit(beos_cleanup_read_thread);
+ resume_thread(read_thread_id);
+ }
+
+ /* timeout == NULL means "indefinitely" */
+ if (timeout) {
+ tmo = timeout->tv_sec * 1e6 + timeout->tv_usec;
+ /* 0 means "don't wait, which is impossible to do exactly. */
+ if (tmo == 0)
+ tmo = 1.0;
+ }
+#if TRY_ABORT
+ release_sem(character_wanted);
+#endif
+ if (timeout)
+ acquired = acquire_sem_etc(character_present, 1, B_TIMEOUT, tmo);
+ else
+ acquired = acquire_sem(character_present);
+ if (acquired == B_NO_ERROR) {
+ if (charcount > 0) {
+ add_to_input_buf(&charbuf, 1);
+#if !TRY_ABORT
+ release_sem(character_wanted);
+#endif
+
+ return 1;
+ } else {
+#if !TRY_ABORT
+ release_sem(character_wanted);
+#endif
+
+ return 0;
+ }
+ }
+#if TRY_ABORT
+ else {
+ /*
+ * Timeout occurred. Break the read() call by sending
+ * a signal. Problem: it may be just read()ing it now.
+ * Therefore we still have to finish the handshake with
+ * the thread and maybe remember the character.
+ */
+ kill(read_thread_id, SIGUSR1);
+ /*
+ * If some other error occurred, don't hang now.
+ * (We will most likely hang later anyway...)
+ */
+ if (acquired == B_TIMED_OUT)
+ acquire_sem(character_present);
+ if (charcount > 0) {
+ add_to_input_buf(&charbuf, 1);
+ return 1;
+ }
+ return 0;
+ }
+#endif
+ }
+#endif
+
+ return 0;
+}
+
diff --git a/src/os_beos.h b/src/os_beos.h
new file mode 100644
index 0000000..0aa6f99
--- /dev/null
+++ b/src/os_beos.h
@@ -0,0 +1,27 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ * BeBox port by Olaf Seibert
+ *
+ * Do ":help uganda" in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ */
+
+/*
+ * os_beos.h
+ */
+
+#undef USE_SYSTEM
+#define USE_THREAD_FOR_INPUT_WITH_TIMEOUT 1
+#define USE_TERM_CONSOLE
+
+#define HAVE_DROP_FILE
+
+#undef BEOS_DR8
+#define BEOS_PR_OR_BETTER
+
+/* select emulation */
+
+#ifndef PROTO
+# include <net/socket.h> /* for typedefs and #defines only */
+#endif
diff --git a/src/os_beos.rsrc b/src/os_beos.rsrc
new file mode 100644
index 0000000..f6443cd
--- /dev/null
+++ b/src/os_beos.rsrc
Binary files differ
diff --git a/src/os_dos.h b/src/os_dos.h
new file mode 100644
index 0000000..bb8b308
--- /dev/null
+++ b/src/os_dos.h
@@ -0,0 +1,135 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * Do ":help uganda" in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ */
+
+/*
+ * Common MS-DOS and Win32 (Windows NT and Windows 95) defines.
+ *
+ * Names for the EXRC, HELP and temporary files.
+ * Some of these may have been defined in the makefile or feature.h.
+ */
+
+#ifndef SYS_VIMRC_FILE
+# define SYS_VIMRC_FILE "$VIM\\vimrc"
+#endif
+#ifndef USR_VIMRC_FILE
+# define USR_VIMRC_FILE "$HOME\\_vimrc"
+#endif
+#ifndef USR_VIMRC_FILE2
+# define USR_VIMRC_FILE2 "$HOME\\vimfiles\\vimrc"
+#endif
+#ifndef USR_VIMRC_FILE3
+# define USR_VIMRC_FILE3 "$VIM\\_vimrc"
+#endif
+#ifndef VIM_DEFAULTS_FILE
+# define VIM_DEFAULTS_FILE "$VIMRUNTIME\\defaults.vim"
+#endif
+#ifndef EVIM_FILE
+# define EVIM_FILE "$VIMRUNTIME\\evim.vim"
+#endif
+
+#ifndef USR_EXRC_FILE
+# define USR_EXRC_FILE "$HOME\\_exrc"
+#endif
+#ifndef USR_EXRC_FILE2
+# define USR_EXRC_FILE2 "$VIM\\_exrc"
+#endif
+
+#ifdef FEAT_GUI
+# ifndef SYS_GVIMRC_FILE
+# define SYS_GVIMRC_FILE "$VIM\\gvimrc"
+# endif
+# ifndef USR_GVIMRC_FILE
+# define USR_GVIMRC_FILE "$HOME\\_gvimrc"
+# endif
+# ifndef USR_GVIMRC_FILE2
+# define USR_GVIMRC_FILE2 "$HOME\\vimfiles\\gvimrc"
+# endif
+# ifndef USR_GVIMRC_FILE3
+# define USR_GVIMRC_FILE3 "$VIM\\_gvimrc"
+# endif
+# ifndef SYS_MENU_FILE
+# define SYS_MENU_FILE "$VIMRUNTIME\\menu.vim"
+# endif
+#endif
+
+#ifndef SYS_OPTWIN_FILE
+# define SYS_OPTWIN_FILE "$VIMRUNTIME\\optwin.vim"
+#endif
+
+#ifdef FEAT_VIMINFO
+# ifndef VIMINFO_FILE
+# define VIMINFO_FILE "$HOME\\_viminfo"
+# endif
+# ifndef VIMINFO_FILE2
+# define VIMINFO_FILE2 "$VIM\\_viminfo"
+# endif
+#endif
+
+#ifndef VIMRC_FILE
+# define VIMRC_FILE "_vimrc"
+#endif
+
+#ifndef EXRC_FILE
+# define EXRC_FILE "_exrc"
+#endif
+
+#ifdef FEAT_GUI
+# ifndef GVIMRC_FILE
+# define GVIMRC_FILE "_gvimrc"
+# endif
+#endif
+
+#ifndef DFLT_HELPFILE
+# define DFLT_HELPFILE "$VIMRUNTIME\\doc\\help.txt"
+#endif
+
+#ifndef FILETYPE_FILE
+# define FILETYPE_FILE "filetype.vim"
+#endif
+#ifndef FTPLUGIN_FILE
+# define FTPLUGIN_FILE "ftplugin.vim"
+#endif
+#ifndef INDENT_FILE
+# define INDENT_FILE "indent.vim"
+#endif
+#ifndef FTOFF_FILE
+# define FTOFF_FILE "ftoff.vim"
+#endif
+#ifndef FTPLUGOF_FILE
+# define FTPLUGOF_FILE "ftplugof.vim"
+#endif
+#ifndef INDOFF_FILE
+# define INDOFF_FILE "indoff.vim"
+#endif
+
+#ifndef SYNTAX_FNAME
+# define SYNTAX_FNAME "$VIMRUNTIME\\syntax\\%s.vim"
+#endif
+
+#ifndef DFLT_BDIR
+# define DFLT_BDIR ".,$TEMP,c:\\tmp,c:\\temp" /* default for 'backupdir' */
+#endif
+
+#ifndef DFLT_VDIR
+# define DFLT_VDIR "$VIM/vimfiles/view" /* default for 'viewdir' */
+#endif
+
+#ifndef DFLT_DIR
+# define DFLT_DIR ".,$TEMP,c:\\tmp,c:\\temp" /* default for 'directory' */
+#endif
+
+#define DFLT_ERRORFILE "errors.err"
+#define DFLT_RUNTIMEPATH "$HOME/vimfiles,$VIM/vimfiles,$VIMRUNTIME,$VIM/vimfiles/after,$HOME/vimfiles/after"
+#define CLEAN_RUNTIMEPATH "$VIM/vimfiles,$VIMRUNTIME,$VIM/vimfiles/after"
+
+#define CASE_INSENSITIVE_FILENAME /* ignore case when comparing file names */
+#define SPACE_IN_FILENAME
+#define BACKSLASH_IN_FILENAME
+#define USE_CRNL /* lines end in CR-NL instead of NL */
+#define HAVE_DUP /* have dup() */
+#define HAVE_ST_MODE /* have stat.st_mode */
diff --git a/src/os_mac.h b/src/os_mac.h
new file mode 100644
index 0000000..692e253
--- /dev/null
+++ b/src/os_mac.h
@@ -0,0 +1,293 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * Do ":help uganda" in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ */
+
+/* Before Including the MacOS specific files,
+ * lets set the OPAQUE_TOOLBOX_STRUCTS to 0 so we
+ * can access the internal structures.
+ * (Until fully Carbon compliant)
+ * TODO: Can we remove this? (Dany)
+ */
+#if 0
+# define OPAQUE_TOOLBOX_STRUCTS 0
+#endif
+
+/* Include MAC_OS_X_VERSION_* macros */
+#ifdef HAVE_AVAILABILITYMACROS_H
+# include <AvailabilityMacros.h>
+#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 <Quickdraw.h> /* Apple calls it QuickDraw.h... */
+# include <ToolUtils.h>
+# include <LowMem.h>
+# include <Scrap.h>
+# include <Sound.h>
+# include <TextUtils.h>
+# include <Memory.h>
+# include <OSUtils.h>
+# include <Files.h>
+# include <Script.h>
+#endif
+
+/*
+ * Unix interface
+ */
+#if defined(__APPLE_CC__) /* for Project Builder and ... */
+# include <unistd.h>
+/* Get stat.h or something similar. Comment: How come some OS get in in vim.h */
+# include <sys/stat.h>
+/* && defined(HAVE_CURSE) */
+/* The curses.h from MacOS X provides by default some BACKWARD compatibility
+ * definition which can cause us problem later on. So we undefine a few of them. */
+# include <curses.h>
+# undef reg
+# undef ospeed
+/* OK defined to 0 in MacOS X 10.2 curses! Remove it, we define it to be 1. */
+# undef OK
+#endif
+#include <signal.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <dirent.h>
+
+/*
+ * MacOS specific #define
+ */
+
+/* This will go away when CMD_KEY fully tested */
+#define USE_CMD_KEY
+/* On MacOS X use the / not the : */
+/* TODO: Should file such as ~/.vimrc reside instead in
+ * ~/Library/Vim or ~/Library/Preferences/org.vim.vim/ ? (Dany)
+ */
+/* When compiled under MacOS X (including CARBON version)
+ * we use the Unix File path style. Also when UNIX is defined. */
+#define USE_UNIXFILENAME
+
+
+/*
+ * Generic Vim #define
+ */
+
+#define FEAT_SOURCE_FFS
+#define FEAT_SOURCE_FF_MAC
+
+#define USE_EXE_NAME /* to find $VIM */
+#define CASE_INSENSITIVE_FILENAME /* ignore case when comparing file names */
+#define SPACE_IN_FILENAME
+#define BREAKCHECK_SKIP 32 /* call mch_breakcheck() each time, it's
+ quite fast. Did I forgot to update the
+ comment */
+
+#define USE_FNAME_CASE /* make ":e os_Mac.c" open the file in its
+ original case, as "os_mac.c" */
+#define BINARY_FILE_IO
+#define EOL_DEFAULT EOL_MAC
+#define HAVE_AVAIL_MEM
+
+#ifndef HAVE_CONFIG_H
+# define HAVE_STRING_H
+# define HAVE_STRCSPN
+# define HAVE_MEMSET
+# define USE_TMPNAM /* use tmpnam() instead of mktemp() */
+# define HAVE_FCNTL_H
+# define HAVE_QSORT
+# define HAVE_ST_MODE /* have stat.st_mode */
+# define HAVE_MATH_H
+
+# if defined(__DATE__) && defined(__TIME__)
+# define HAVE_DATE_TIME
+# endif
+# define HAVE_STRFTIME
+#endif
+
+/*
+ * Names for the EXRC, HELP and temporary files.
+ * Some of these may have been defined in the makefile.
+ */
+
+#ifndef SYS_VIMRC_FILE
+# define SYS_VIMRC_FILE "$VIM/vimrc"
+#endif
+#ifndef SYS_GVIMRC_FILE
+# define SYS_GVIMRC_FILE "$VIM/gvimrc"
+#endif
+#ifndef SYS_MENU_FILE
+# define SYS_MENU_FILE "$VIMRUNTIME/menu.vim"
+#endif
+#ifndef SYS_OPTWIN_FILE
+# define SYS_OPTWIN_FILE "$VIMRUNTIME/optwin.vim"
+#endif
+#ifndef VIM_DEFAULTS_FILE
+# define VIM_DEFAULTS_FILE "$VIMRUNTIME/defaults.vim"
+#endif
+#ifndef EVIM_FILE
+# define EVIM_FILE "$VIMRUNTIME/evim.vim"
+#endif
+
+#ifdef FEAT_GUI
+# ifndef USR_GVIMRC_FILE
+# define USR_GVIMRC_FILE "~/.gvimrc"
+# endif
+# ifndef GVIMRC_FILE
+# define GVIMRC_FILE "_gvimrc"
+# endif
+#endif
+#ifndef USR_VIMRC_FILE
+# define USR_VIMRC_FILE "~/.vimrc"
+#endif
+
+#ifndef USR_EXRC_FILE
+# define USR_EXRC_FILE "~/.exrc"
+#endif
+
+#ifndef VIMRC_FILE
+# define VIMRC_FILE "_vimrc"
+#endif
+
+#ifndef EXRC_FILE
+# define EXRC_FILE "_exrc"
+#endif
+
+#ifndef DFLT_HELPFILE
+# define DFLT_HELPFILE "$VIMRUNTIME/doc/help.txt"
+#endif
+
+#ifndef FILETYPE_FILE
+# define FILETYPE_FILE "filetype.vim"
+#endif
+#ifndef FTPLUGIN_FILE
+# define FTPLUGIN_FILE "ftplugin.vim"
+#endif
+#ifndef INDENT_FILE
+# define INDENT_FILE "indent.vim"
+#endif
+#ifndef FTOFF_FILE
+# define FTOFF_FILE "ftoff.vim"
+#endif
+#ifndef FTPLUGOF_FILE
+# define FTPLUGOF_FILE "ftplugof.vim"
+#endif
+#ifndef INDOFF_FILE
+# define INDOFF_FILE "indoff.vim"
+#endif
+
+#ifndef SYNTAX_FNAME
+# define SYNTAX_FNAME "$VIMRUNTIME/syntax/%s.vim"
+#endif
+
+#ifdef FEAT_VIMINFO
+# ifndef VIMINFO_FILE
+# define VIMINFO_FILE "~/.viminfo"
+# endif
+#endif /* FEAT_VIMINFO */
+
+#ifndef DFLT_BDIR
+# define DFLT_BDIR "." /* default for 'backupdir' */
+#endif
+
+#ifndef DFLT_DIR
+# define DFLT_DIR "." /* default for 'directory' */
+#endif
+
+#ifndef DFLT_VDIR
+# define DFLT_VDIR "$VIM/vimfiles/view" /* default for 'viewdir' */
+#endif
+
+#define DFLT_ERRORFILE "errors.err"
+
+#ifndef DFLT_RUNTIMEPATH
+# define DFLT_RUNTIMEPATH "~/.vim,$VIM/vimfiles,$VIMRUNTIME,$VIM/vimfiles/after,~/.vim/after"
+#endif
+#ifndef CLEAN_RUNTIMEPATH
+# define CLEAN_RUNTIMEPATH "$VIM/vimfiles,$VIMRUNTIME,$VIM/vimfiles/after"
+#endif
+
+/*
+ * Macintosh has plenty of memory, use large buffers
+ */
+#define CMDBUFFSIZE 1024 /* size of the command processing buffer */
+
+#ifndef DFLT_MAXMEM
+# define DFLT_MAXMEM 512 /* use up to 512 Kbyte for buffer */
+#endif
+
+#ifndef DFLT_MAXMEMTOT
+# define DFLT_MAXMEMTOT 2048 /* use up to 2048 Kbyte for Vim */
+#endif
+
+#define WILDCHAR_LIST "*?[{`$"
+
+/**************/
+#define mch_rename(src, dst) rename(src, dst)
+#define mch_remove(x) unlink((char *)(x))
+#ifndef mch_getenv
+# if defined(__APPLE_CC__)
+# define mch_getenv(name) ((char_u *)getenv((char *)(name)))
+# define mch_setenv(name, val, x) setenv(name, val, x)
+# else
+ /* vim_getenv() is in pty.c */
+# define USE_VIMPTY_GETENV
+# define mch_getenv(x) vimpty_getenv(x)
+# define mch_setenv(name, val, x) setenv(name, val, x)
+# endif
+#endif
+
+#ifndef HAVE_CONFIG_H
+# ifdef __APPLE_CC__
+/* Assuming compiling for MacOS X */
+/* Trying to take advantage of the prebinding */
+# define HAVE_TGETENT
+# define OSPEED_EXTERN
+# define UP_BC_PC_EXTERN
+# endif
+#endif
+
+/* Some "prep work" definition to be able to compile the MacOS X
+ * version with os_unix.c instead of os_mac.c. Based on the result
+ * of ./configure for console MacOS X.
+ */
+
+#ifndef SIGPROTOARG
+# define SIGPROTOARG (int)
+#endif
+#ifndef SIGDEFARG
+# define SIGDEFARG(s) (s) int s UNUSED;
+#endif
+#ifndef SIGDUMMYARG
+# define SIGDUMMYARG 0
+#endif
+#undef HAVE_AVAIL_MEM
+#ifndef HAVE_CONFIG_H
+# define RETSIGTYPE void
+# define SIGRETURN return
+/*# define USE_SYSTEM */ /* Output ship do debugger :(, but ot compile */
+# define HAVE_SYS_WAIT_H 1 /* Attempt */
+# define HAVE_TERMIOS_H 1
+# define SYS_SELECT_WITH_SYS_TIME 1
+# define HAVE_SELECT 1
+# define HAVE_SYS_SELECT_H 1
+# define HAVE_PUTENV
+# define HAVE_SETENV
+# define HAVE_RENAME
+#endif
+
+#if !defined(HAVE_CONFIG_H)
+# define HAVE_PUTENV
+#endif
+
+/* A Mac constant causing big problem to syntax highlighting */
+#define UNKNOWN_CREATOR '\?\?\?\?'
diff --git a/src/os_mac.rsr.hqx b/src/os_mac.rsr.hqx
new file mode 100644
index 0000000..04e9972
--- /dev/null
+++ b/src/os_mac.rsr.hqx
@@ -0,0 +1,659 @@
+(This file must be converted with BinHex 4.0)
+
+:$'GeD9pYB@-ZFR0bB`"58e*$8P0&4!%!!!!!!!!!HUUk%`!!!!!"!!!!GJX!!(8
+,!!!%R`!!$Ed,Eh0IGc-bC'aX,Q-#!!!!9%9B9%0A588"!2rr#hCTE9"33bjbFh*
+MFLe%EfYeE@9ZG'9PEL"%BA4PER8!!(*cFQ058d9%!3lrrrrr!!!!!!!!!!!!!!!
+!!!!!!!!!X3N1a!!!!!!!!%'-!!!!!!!!!!!4!!!!$Ed,Eh0IGc-bCAKP,Q-#!!!
+!9%9B9%0A588"!2rrrrm!!!!!$NN!!!!!$hi!!%)!!!!!!!!!!!!!!,#`81D`X&$
+Q!!!!!!!!!!!!!!!!!!!!!!!!!!!!!'6Y!!%!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!3!!!!!#a@58dK!!!!!8C548B!!J!!!)!!!3#"!!)!JNP$6L-!!J!!!))!!3#
+$!!)!!!!!!!G"8&"-!!!!!!!!"e4&@&3!!3!!!!!(+LSU+J!#!!!!!J!!!2rrrrr
+rrrrrrrm!!!!!!!$m$!`-$!`-$!`2m!!!!!!!m-$!`-E!`-$!cpm!!!!!!2`-$!`
+-$!`-$!r0m!!!!!$`aX$'aXCJB-$2$0m!!!!!r!B-"JB'"JB-$rrrm!!!!2$!B'$
+'aXE'`-$!c[!!!!$m$'aX"JB'"J`-$!l`!!!!m-$'`-E'aXE!`-$1m!!!!2`-$!`
+-$!`-$!`-$[!!!!$``-$!`-$!`-$!`-l`!!!!r!`-$!`-$!`-$!`1m!!!!2$!`-$
+!`-$!`-$!c[!!!!$m$!`-$!`-$!`-$!l`!!!!m-$!`-$!`-$!`-$1m!!!!2`-CJB
+-$!`-$!`-$[!!!!$`aXCJ`-$!`-$!`-l`!!!!r!`-$!`-$!`-$!`1m!!!!2$!`-$
+!`-$!`-$!c[!!!!$m$!`-$!`-$!`-$!l`!!!!m-$!`-$!`-$!`-$1m!!!!2`-$!`
+-$!`-$!`-$[!!!!$``-$!`-$!`-$!`-l`!!!!r!`-$!`-$!`-$!`1m!!!!2$!CXE
+!`-$!`-$!c[!!!!$m"JCX$!`-$!`-$!l`!!!!m-$!`-$!`-$!`-$1m!!!!2`-$!`
+-$!`-$!`-$[!!!!$``-$!`-$!`-$!`-l`!!!!r!`-$!`-$!`-$!`1m!!!!2lZlZl
+ZlZlZlZlZl[!!!!$rrrrrrrrrrrrrrrr`!!!!!J$rrrrrrrrrrrrrrrrrrrr`m!!
+!!!!!!!!!!!!!!!!!m2!!!!!!!!!!!!!!!!!!!2$`!!!!!!!!!!!!!!!!!!$`m!!
+!!!!!!!!2rrr`!!!!m2!!CJB!!!!!mJ)#$`!!!2$`"JCJ!!!!$b!J)#$`!!$`m!!
+!!!!!!2)2mJ)#$`!!m2!!!!!!!!$rrGmJ)#$`!2$`!!!!!!rr![rrrrm#$rrrm!!
+!!!!!$b![m#!J)#$fEr!!!!!!$Ghb!J)#!J)#pQr`!!!!!!!0hb!J)#!J)2C[m!!
+!!!!!!0hr!J)#!J,fEr!!CJB!!!!0hIrrrrmJpQr`"JCJ!!!!!0hGhGhGrrC[m!!
+!!!!!!!!!hGhGhGhIrr!!!!!!!!!!!!!!!!hGhI$`!!!!!!!!!!!!!!!!!!$`m!!
+!!!!!!!!!!!!'CQCJm2!!!!!!!!!!!!!!"QCQB2$`!!!!!!!'!!!!!!CQCQ$`m!!
+!!!!!!!!!!!!'CQCJm2!'B'!!B'B!CJB!"QCQB2$`"Q"J!'!'!'"JB!CQCQ$`m!!
+!"JB!"J"JB'!'CQCJm2!!!!B'!!B!B'"J"QCQB2$`"Q!'"J!'!'"JB!CQCQ$`m!C
+J!'!!"Q"JB'!'CQCJm2!!!!!!!!!!!!!!"QCQB2$`!!!!!!!!!!!!!!!!!!$`rrr
+rrrrrrrrrrrrrrrrrm!!!!J!!$rrrrrrrrrrrrrrrrr!!!2!!!!!!!!!!!!!!!!!
+2!!m!c-c-c-c-c-c-c-c-c[!2$-lZlZlZlZlZlZlZl-l`$`cZrrrrrrrrrrrrrq$
+1m!m-lrL2Mrrrrrrrrrr`c[!2$1q2L2rrrrrrrrrrm-l`$`c[rrrrrrrrrrrrrr$
+1m!m-lrrrrrrrrrrrrrr`c[!2$1rrrrrrrrrrrrrrm-l`$`c[rrrrrrrrrrrrrr$
+1m!m-lrL2Mrrrrrrrrrr`c[!2$1q2L2rrrrrrrrrrm-l`$`c[rrrrrrrrrrrrrr$
+1m!m-lrrrrrrrrrriL)M`c[!2$1rrrrrirrrrq)L)m-l`$`c[rrrrrrrrrrL)L2$
+1m!m-liq2q2MiMiriL)M`c[!2$1rrMrMiq2Miq)L)m-l`$`c[riq2q2Miq2L)L2$
+1m!m-liq)rrMiq2MiL)M`c[!2$1rrrrrrrrrrrrrrm-l`$`cZrrrrrrrrrrrrr`$
+1m!m-`!!!!!!!!!!!!!!-c[!2$-c-c-c-c-c-c-c-c1l`!2lZlZlZlZlZlZlZlZl
+[!!!2c1c1c1c1c1c1c1c1m!!!rmlXlXlXlXlXlXlXl[m!$rc1c1c1c1c1c1c1c1c
+1m2rmlXlXlXlXlXlXlXlXl[rrrrrrrrrrrrrrrrrrrrrr$rrrrrrrrrrrrrrrrrr
+rm!!!!J!!!!$rrrrrrrrrrrrrm!!!!!!!r!`-$!`-$!`-$2m!!!!!!2$!`-$!`-$
+!`-$qm!!!!!$m$!`-$!`-$!`-rHm!!!!!m-$!`-$!`-$!`2cHm!!!!2`-$!`-$!`
+-$!crrrm!rrrrrrrrrrrrrm$!`-$2$mc-c-c-c-c-c-cm$!`-$rcGhGhGhGhGhGh
+Glm$!`-rmhZlZlZlZlZlZlHm-$!`2r0lrrrrrrrq)Mmh[d-$!crcHMiq2L2MrL)r
+0lmd-$!rmhSq2Miq2MiL2cHrF`-$2r0k)riq2Miq)Mmh[c3`-$rcHrrrrrrrrrrr
+0lpc!`-rmh[rrrrrrrrrrcHr0$!`2r0liMirrrrrrrmh[h-$!crcHMiMrrrrrrrr
+0lmd-$!rmh[rrrrrrrrrrcHrF`-$2r0lrrrrrrrrrrmh[c3`-$rcHq)q2rrrrrrr
+0lpc!`-rmhSq)rrrrrrrrcHr0$!`2r0lrrrrrrrrrrmh[h-$!crcHc-c-c-c-c-c
+0lmd-$!rmhGhGhGhGhGhGhHrF`-$2$qlZlZlZlZlZlZlpc3`-$`$rrrrrrrrrrrr
+rh0$!`-m!!!$pcFh0cFh0cFd-$!`2!!!!r0cFh0cFh0c3`-$!c`!!!2`-$!`-$!`
+-$!`-$!m!!!$``-$!`-$!`-$!`-$2!!!!rrrrrrrrrrrrrrrrr`!!"!!!!!!!rrr
+rrrrrrrrrrrrrrrrrrrrrrrm!!!!!!!!!!!!!!!$rpIAepIAepIAepIAepIAepIA
+errm!!!!!!!!!!!!!!2repIAepIAepHcepIAepIAepIArq[m!!!!!!!!!!!!!rrA
+epIAepIAepIAepIAepIAepIrhq[m!!!!!!!!!!!$rpIAXpIAel2AXpHcXpHcepIA
+errAhq[m!!!!!!!!!!2repHcepIAXpHcel2AXpHcepIArrrrrrrm!!!!!!!!!rrA
+epHcel2Ael2AXpHcel2AepIAepIAlr`!!!!!!!!$rpIAel2AXpIAXpHcel2AXpIA
+epIAepI[r!!!!!!!!!2repIAel2AepHcel2AXpHcepIAepIAeqrm!!!!!!!!!rrA
+epIAepIAepIAepIAepIAepIAepIAlr`!!!!!!!!$rpIAepIAepIAepIAepIAepIA
+epIAepI[r!!!!!!!!!2repIAepIAepIAepIAepIAepIAepIAeqrm!!!!!!!!!rrA
+epIAepIAepIAepIAepIAepIAepIAlr`!!!!!!!!$rpIAepIAepIAepIAepIAepIA
+epIAepI[r!!!!!!!!!2repIAepIAepIAepIAepIAepIAepIAeqrm!!!!!!!!!rrA
+epHcXpHcepIAepIAepIAepIAepIAlr`!!!!!!!!$rpIAXpHcXpIAepIAepIAepIA
+epIAepI[r!!!!!!!!!2repIAepIAepIAepIAepIAepIAepIAeqrm!!!!!!!!!rrA
+epIAepIAepIAepIAepIAepIAepIAlr`!!!!!!!!$rpIAepIAepIAepIAepIAepIA
+epIAepI[r!!!!!!!!!2repIAepIAepIAepIAepIAepIAepIAeqrm!!!!!!!!!rrA
+epIAepIAepIAepIAepIAepIAepIAlr`!!!!!!!!$rpIAepIAepIAepIAepIAepIA
+epIAepI[r!!!!!!!!!2repIAepIAepIAepIAepIAepIAepIAeqrm!!!!!!!!!rrA
+epHcXpHcepIAepIAepIAepIAepIAlr`!!!!!!!!$rpIAXpHcXpIAepIAepIAepIA
+epIAepI[r!!!!!!!!!2repIAepIAepIAepIAepIAepIAepIAeqrm!!!!!!!!!rrA
+epIAepIAepIAepIAepIAepIAepIAlr`!!!!!!!!$rpIAepIAepIAepIAepIAepIA
+epIAepI[r!!!!!!!!!2repIAepIAepIAepIAepIAepIAepIAeqrm!!!!!!!!!rr[
+lqr[lqr[lqr[lqr[lqr[lqr[lqr[lr`!!!!!!!!$rrrrrrrrrrrrrrrrrrrrrrrr
+rrrrrrrrr!!!!!!!%!2rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrm!rdK
+)5%K)5%K)5%K)5%K)5%K)5%K)5%K)5%K)5%K)r`$r5%K)5%K)5%K)5%K)5%K)5%K
+)5%K)5%K)5%K)5%Mr!2p)5%K)5%K)5%K)5%K)5%K)5%K)5%K)5%K)5%K)52m!rdK
+)5%K)5%K)5%K)5%K)5%Mrrrrrrrp)5%K)5%K)r`$r5%K)l1a)l%K)5%K)5%K)r`J
+)#!J)#2p)5%K)5%Mr!2p)51a)l1a)5%K)5%K)52m)#!J)#!J)#2p)5%K)52m!rdK
+)5%K)5%K)5%K)5%Mr#!Mrr`J)#!J)#2p)5%K)r`$r5%K)5%K)5%K)5%K)52rrrhp
+rr`J)#!J)#2p)5%Mr!2p)5%K)5%K)5%K)rrrr#!Mrrrrrrrrrr`J)#2rrrrrrrdK
+)5%K)5%K)5%K)52m)#!Mrr`J)#!J)#!J)#2rXl2rr5%K)5%K)5%K)5(prIrm)#!J
+)#!J)#!J)#!J)rqcXrrp)5%K)5%K)5%K)5%KrIrm)#!J)#!J)#!J)#!Mrl1crrdK
+)5%K)5%K)5%K)5%KrIrrr#!J)#!J)#!J)#2rXl2rr5%K)l1a)l%K)5%K)5%KrIhr
+rrrrrrrrrr`J)rqcXrrp)51a)l1a)5%K)5%K)5%KrIhprIhprIhprrrrrl1crrdK
+)5%K)5%K)5%K)5%K)5%K)IhprIhprIhprIhrrrrrr5%K)5%K)5%K)5%K)5%K)5%K
+)5%K)5%K)IhprIhrr!2p)5%K)5%K)5%K)5%K)5%K)5%K)5%K)5%K)5%K)52m!rdK
+)5%K)5%K)5%K)5%K)5%K)5%K)5%MXl1cXl1a)r`$r5%K)5%K)5%K)5%K)5%K)5%K
+)5%K)51cXl1cXl%Mr!2p)5%K)5%K)5%K)5%MX5%K)5%K)5%K)l1cXl1cX52m!rdK
+)5%K)5%K)5%K)5%K)5%K)5%K)5%MXl1cXl1a)r`$r5%MXl%MX5%K)l%MXl%K)l1a
+)l%K)51cXl1cXl%Mr!2p)51cX51a)5%MX5%MX5%MX51a)l%K)l1cXl1cX52m!rdK
+)5%K)51a)l%K)51a)51a)l%MX5%MXl1cXl1a)r`$r5%K)5%K)l%MX5%K)l%K)l%M
+X51a)51cXl1cXl%Mr!2p)51cX5%MX51a)5%MX5%MX51a)l%K)l1cXl1cX52m!rdK
+)l1a)5%MX5%K)51cX51a)l%MX5%MXl1cXl1a)r`$r5%K)5%K)5%K)5%K)5%K)5%K
+)5%K)51cXl1cXl%Mr!2p)5%K)5%K)5%K)5%K)5%K)5%K)5%K)5%K)5%K)52m!rrr
+rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr`!!!!3!!!!!rrrrrrrrrrrrrrr
+rrrrrrrrrrrrrrrrrrrm!!!!!!2repIAepIAepIAepIAepIAepIAepIAepIAepIm
+!!!$rpIAiq2Miq2Miq2Miq2Miq2Miq2Miq2Miq2Mir2m!!2req2Mmr2cmr2cmr2c
+mr2cmr2cmr2cmr2cmq2Mmr`!!rrAir2crrrrrrrrrrrrrrrrrrrrrrrrrrrceq2c
+r!!$rpIMmrrrMirrMrrrrrrrrrrrrrrrrrrrrrrAir2m!!2req2crirrMirrrrrr
+rrrrrrrrrrrrrrrrrpIMmr`!!rrAir2rrrrrrrrrrrrrrrrrrrrrrrrrrrrreq2c
+r!!$rpIMmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrAir2m!!2req2crrrrrrrrrrrr
+rrrrrrrrrrrrrrrrrpIMmr`!!rrAir2rrrrrrrrrrrrrrrrrrrrrrrrrrrrreq2c
+r!!$rpIMmrrrMirrMrrrrrrrrrrrrrrrrrrrrrrAir2m!!2req2crirrMirrrrrr
+rrrrrrrrrrrrrrrrrpIMmr`!!rrAir2rrrrrrrrrrrrrrrrrrrrrrrrrrrrreq2c
+r!!$rpIMmrrrrrrrrrrrrrrrrrrrrrq2Miq2MrrAir2m!!2req2crrrrrrrrrrq2
+rrrrrrrrriq2Miq2rpIMmr`!!rrAir2rrrrrrrrrrrrrrrrrrrrrMiq2Mirreq2c
+r!!$rpIMmrq2rirrrirrMrq2Mrq2rrq2Miq2MrrAir2m!!2req2crrrrMrrrMrq2
+rirrMrq2riq2Miq2rpIMmr`!!rrAir2rrrq2rirrrirrMrq2rirrMiq2Mirreq2c
+r!!$rpIMmrq2riq2rrrrMrq2rirrMrq2Miq2MrrAir2m!!2req2crrrrrrrrrrrr
+rrrrrrrrrrrrrrrrrpIMmr`!!rrAir2crrrrrrrrrrrrrrrrrrrrrrrrrrrAeq2c
+r!!$rpIMipIAepIAepIAepIAepIAepIAepIAepIMir2m!!2req2Miq2Miq2Miq2M
+iq2Miq2Miq2Miq2Miq2cmr`!!!2rmr2cmr2cmr2cmr2cmr2cmr2cmr2cmr2cmr2m
+!!!!!!2rhpr[hpr[hpr[hpr[hpr[hpr[hpr[hpr[r!!!!!!$rrrIlqrIlqrIlqrI
+lqrIlqrIlqrIlqrIlqrrr!!!!rrrhpr[hpr[hpr[hpr[hpr[hpr[hpr[hpr[hpr[
+r!2rrrrIlqrIlqrIlqrIlqrIlqrIlqrIlqrIlqrIlqrrrrrrrrrrrrrrrrrrrrrr
+rrrrrrrrrrrrrrrrrrrrrrrm!rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr
+r!!!!"!!!!!!!!!$rrrrrrrrrrrrrrrrrrrrrrrrrrrm!!!!!!!!!!!!!!2rfp[E
+fp[Efp[Efp[Efp[Efp[Efrrm!!!!!!!!!!!!!rrEfp[Efp[Efp[Efp[Efp[Efp[E
+rr2m!!!!!!!!!!!$rp[Efp[Efp[Efp[Efp[Efp[Efp[rjr2m!!!!!!!!!!2rfp[E
+fp[Efp[Efp[Efp[Efp[EfrrMjr2m!!!!!!!!!rrEfp[Efp[Efp[Efp[Efp[Efp[E
+rrrrrrrm!!2rrrrrrrrrrrrrrrrrrrrrrrrrrp[Efp[Efp[Efr`$r+bXV+bXV+bX
+V+bXV+bXV+bXV+b[rp[Efp[Efp[Errb[jqIRjqIRjqIRjqIRjqIRjqIRjqIcrp[E
+fp[Efp[rr+rRmr2cmr2cmr2cmr2cmr2cmr2cjr2rfp[Efp[EfrrmVqIcrrrrrrrr
+rrrrrrrrMiq2r+rRmrrMfp[Efp[Errb[jr12rirrMrq2Mrq2rrq2MirmVqIcrq2M
+fp[Efp[rr+rRmirrMrq2rirrMrq2riq2Mrb[jr2riq2Efp[EfrrmVqIcMirrrirr
+Mrq2rirrMiq2r+rRmrrMip[Efp[Errb[jr2rrrrrrrrrrrrrrrrrrrrmVqIcrq2M
+fp[Efp[rr+rRmrrrrrrrrrrrrrrrrrrrrrb[jr2riq2Efp[EfrrmVqIcriq2rirr
+rrrrrrrrrrrrr+rRmrrMip[Efp[Errb[jr12riq2rrrrrrrrrrrrrrrmVqIcrq2M
+fp[Efp[rr+rRmrrrrrrrrrrrrrrrrrrrrrb[jr2riq2Efp[EfrrmVqIcrrrrrrrr
+rrrrrrrrrrrrr+rRmrrMip[Efp[Errb[jr2rMirrMrrrrrrrrrrrrrrmVqIcrq2M
+fp[Efp[rr+rRmirrMirrrrrrrrrrrrrrrrb[jr2riq2Efp[EfrrmVqIcrrrrrrrr
+rrrrrrrrrrrrr+rRmrrMip[Efp[Errb[jr#XV+bXV+bXV+bXV+bXV+bXVqIcrq2M
+fp[Efp[rr+rRjqIRjqIRjqIRjqIRjqIRjqIRjr2riq2Efp[Efr`$rr2cmr2cmr2c
+mr2cmr2cmr2cmr2crq2Mip[Efp[Er!!$rrrrrrrrrrrrrrrrrrrrrrrrrrrMiq2M
+fp[Efp[m!!!!!!!$rq2Miq2Miq2Miq2Miq2Miq2Mip[Efp[Efr`!!!!!!!2riq2M
+iq2Miq2Miq2Miq2Miq2Efp[Efp[Er!!!!!!!!rrEfp[Efp[Efp[Efp[Efp[Efp[E
+fp[Efp[m!!!!!!!$rp[Efp[Efp[Efp[Efp[Efp[Efp[Efp[Efr`!!!!!!!2rrrrr
+rrrrrrrrrrrrrrrrrrrrrrrrrrrrr!!!"!2rrrrk!!!!#J!!!!S!!!!+!!(i#M3#
+"!TB"!)+!!Q"#J!13!#+!(2mIJ!4J$i!#!!q!!3!2J!$!$id!2mq@!!!rJ!!!$i!
+!!!+!!!!#J!!"qS!!!IU!"!(kJ!!"qTSXdIUD*+RkJ85TqS&%UIUC4+RkQ)DTqS!
+!!IU!!!!#rrrrr[rrrrlrrrrqrrrrr[rrrrlrrrrqrrrrr[rrrrlrrrrqrrrrr[r
+rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr[rrrrlrrrrqrrrrr[r
+rrrlrrrrqrrrrr[rrrrlrrrrqrrrrr[rrrrlrrrrqrrrrr[rrrrlrrrrq!!!"!!r
+rr`!)!!'!#!3"3!J!!5!*&D%3#494q!LP8!J)T9!)#%93#!J!!!J)!!!)#!!!#!J
+!!!J)!!!)#!!!#!M3!!J*B!!)#!!!#!J!!!J)!!!)#!!!#!J!!!J)!!!)#!!!#!M
+3!!J*B!!)#!!!#!J!!!J)!!!)#!!!#!J!!!J2rrri$rrr!!rrri!2rrr!$rrri!r
+rrr!2rrri$rrrq!rrrrJ2rrri$rrrq!rrrrJ2rrri$rrrq!rrrrJ2rrri$rrrq!r
+rrrJ2rrri$rrrq!rrrrJ2rrri$rrrq!rrrrJ2rrri$rrrq!rrrrJ2rrri$rrrq!r
+rrrJ2rrri$rrrq!rrrrJ!!!%!(rrrq#!!!!4!!!!#4rrriNJ!!"*)!!!55D!!%NV
+!!"*)!!!55!!!%NJ!!"**S!!55X!!%NJ!!"*)!!I55!3(dNJ!"p*+PDI55*9AdNL
+P9p*+a9I55!!!%NJ!!"*(rrrL3!!!!M!!!!`Irrri0YYY['5555EYYYY[rrrrrhr
+rrriIrrri2rrrr(rrrrjrrrrqIrrrrRrrrrjrrrrqIrrrrRrrrrjrrrrqIrrrrRr
+rrrjrrrrqIrrrrRrrrrjrrrrqIrrrrRrrrrjrrrrqIrrrrRrrrrjrrrrqIrrrrRr
+rrrjrrrrq2rrrr"rrrrJrrrrmIrrrr[rrrrrrrrrrIrrrrJ!!!3!$rrrJ!J!!-!)
+!!#J#!!!N!J!!)J)!!$mrrr`"3!!#!Crrq3'J!!8"S!$P!DUdj3'UUZ8"V+VP!D!
+!"3'J!!8"TS!&!DX!"3'J!!8"S!!&!DD!"3'V!!8"S!!&!D!!"3'IrrN"3!!#!6r
+rr!%#!!!"!J!!!3)!!!%#!!!"!rrrr`2rrq!$rrr`!rrrq!2rrr`$rrrq!rrrrcr
+rrrprrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr
+rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrprrrrr2rrrr`2rrrm$rrrr!rrrr`2
+rrrm$rrrr!!!!32rrJ!'8!DJ"J!'!!C3"U!'!!B#"J!'UXBUjT+Q!!Irrrrrrrrr
+rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrm!!!"!Ir"!'%S89"j!!N!#5J*8!N!
+#3!*9BP9b9A**8N!#Irjrm(riIrarrRrqIrjrrRrqIrjrrRrqIrjrrRrqIrjrrJ!
+!!%"rrS!"RrQP"DS&S!@U[DUpT+fJ"CrjJ!&rrM9@DUYrrhrqrrrrrrrrrrrrrrr
+rrrrrrrrrrrrrrhrq2rjrrhrr!!!!3"ri%!`3#RrrJ!QIbD!TTUQV+D!TS#QIbB!
+*Ir%3!4rr(rJIr"rqIrrrrrrrrrrrrrrrrrrrrrrrrrprrarr(rm!!!#!rrrrrrr
+rrrrmc-c-c-c-crc2cmc-c-c2r2cmc-c-c-rmc-c-c-c-crc-c-c-c-c2r-r2c-c
+-c-rmr2c-c-c-crc-c-c-c-c2r-c-c2c-c-rmc-c-c-c-crcmr2cmrmc2r-cmr2c
+rr-rmr-r-r2cmcrc-c-c-c-c2rrrrrrrrrrm!!!#!$rrrrrrr!!!2$!`-$!r`!!r
+!B'$!cmm!$`B'$!`2rr!2`-$!`-$1m!m-$!`-$!l`$m"JB-$!c[!2"JB-$!`1m!r
+!`-$!`-l`$``-$!`-$[!2aXE'aQ$1m!m'"JB'CJl`$m"JaXCQc[!2$!`-$!`1m!r
+ZlZlZlZl`$rrrrrrrrr!!!!#!$rrrrrrrrr$mc-c-c-c-crcZlZlZlZl[r1q2Mrr
+rr1rmk2Mrrrrmlrc[rrrrrrc[r1Miq2L)r1rmk2Miq)Mmlrc[MrMiq2c[r1rrrrr
+rr1rml-c-c-c-lrlZlZlZlZl[$rrrrrrrrr!!rXl1cXl1m!rXl1cXl1cr$rrrrrr
+rrrm!!!#!!!rrrrrrm!!!$``-$!cr!!!2`-$!`2h`$rrrrrrrrrrmc-c-c-c`crc
+GhGhGh[`2r0rrrrrHm-rmhrL2Mplm$rcIMiMrh[$2r0rrrrrHr!rmhrrrrpl`crc
+GhGhGh[`2r1lZlZlZm-m2rrrrrrm-$`!2`-$!`-$2!!rrrrrrrrm!!!%!rrrrrrr
+rrrrrrrrrrrrrrrmU+LSU+LSU+LSU+LSU+[rr+LVr+[mU+LSU+LSU+LVrrbVr+[m
+U+LSU+LSU+LSUrrmU+LSU+LSU+LSU+LSU+[rr+LSU+LSU+LSU+LSU+LVrrbSUrbV
+r+LSU+LSU+LSUrrmUrbVr+LSU+LSU+LSU+[rr+LSU+LSU+LSU+LSU+LVrrbSU+LS
+U+LVr+LSU+LSUrrmU+LSU+LSU+LSU+LSU+[rr+[mUrbVr+[mUrrmU+LVrrbSU+[m
+UrbVr+[rrrbSUrrmUrbSUrbSUrbVr+[mU+[rr+LSU+LSU+LSU+LSU+LVrrrrrrrr
+rrrrrrrrrrrrrr`!!!3!!rrrrrrrrrrrrrrm!!!!!!2repIAepIAepIArr`!!!!$
+rpIAXpHcepIAerrIr!!!!rrAXpHcepIAepIrrrrm!!2repIAepIAepIAepI[r!!$
+rpIAepIAepIAepIAlr`!!rrAel2AXpIAepIAeqrm!!2rel2AXpIAepIAepI[r!!$
+rpIAepIAepIAepIAlr`!!rrAepIAepIAepIAeqrm!!2rel2AXpHcel1cepI[r!!$
+rpHcel2AXpHcXl2Alr`!!rrAel2Ael2AXl1ceqrm!!2repIAepIAepIAepI[r!!$
+rqr[lqr[lqr[lqr[lr`!!rrrrrrrrrrrrrrrrrrm!!!!"!!$rrrrrrrrrrrrrrrr
+rr`$rp[Efp[Efp[Efp[Efp[ErrrElqr[lqr[lqr[lqr[lrrrfqrrMrq2rrrrrrrr
+fqrrrp[[Mrq2rrrrrrrrrp[[rrrElrrrrrrrrrrrrrrElrrrfqq2rirrMrq2Mirr
+fqrrrp[[Mrq2rirrMiq2rp[[rrrElrq2rrq2rirrMrrElrrrfqrrrrrrrrrrrrrr
+fqrrrp[[fp[Efp[Efp[Efp[[rrr[lqr[lqr[lqr[lqr[lr`$rrrrrrrrrrrrrrrr
+rr`!!!2rlp[[fqrElp[[fqrm!!2rlp[[fqrElp[[fqrErr`$rrrrrrrrrrrrrrrr
+rrrm!!!%!!!!!rrrrrrrrrrrrr`!!!!!!!2mV+bXV+bXV+rrr!!!!!!$r+bXV+bX
+V+b[rqrm!!2rrrrrrrrrrrrrrrrrrrrmV+bXV+bXV+bXV+rmV+rrr+rVkq[Vkq[V
+kq[cr+b[rrb[krrrrrrrrrrVmrbXVrrmVq[rriq2rirrkr2mV+rrr+rVrirrMirr
+rq[cr+b[rrb[krrrrrrrrrrVmrbXVrrmVq[rrrrrrrrrkr2mV+rrr+rVkq[Vkq[V
+kq[cr+b[rrb[mr2cmr2cmr2cmrbXVr`$rrrrrrrrrrrrrrbXV+rm!!!$r+bXV+bX
+V+bXV+b[r!!!!rrrrrrrrrrrrrrrrr`!!!"SC9QPY)$8Z-b`J)%eKBdp6)(*PE'9
+KFf8J-J!!!!`!+!!S!43"S`#!998!!!!L!!%!!!!!!-N")3$G!9X%!Np,!!!!!!!
+8!#3!Y`&CL!*H-!!!!!,rr`!!!"B!!!!!!!!!E3!D!)%!9!3'3R9dG'pZ!!!!%J!
+!!!!!!!!0!"F!,3!hS!)!J!!!!"`!!!!!!!!!$3"1!'B"CSJ,8h4KG'PM)&4PH(3
+!!!!!&3!S!#J"%!'R!!!"!!%!!!!!!!#!!!!!!"8!43"-!'S!G`!&!3!"!!!!!!!
+!J3!!!!!9!*8!J!%P!1`!"3%!!3!!!!!!!))!!!!!&3!Z!#B!D3"d!!8"!!%!!!!
+!!!#$!!!!!"8!13!m!-B"Z3!!!3!"!!!!!!!!K!!!!!%!!!'!!!!#3!!IrDri)!2
+3"#!"m!)3!rJ'#!rm#JJ(q"3)$r!S#!IJ8!J2`+!)"i&`'!m"q#J'!raB$![qZ!!
+ArlJ),rpB!&rq+!$rr"J"2rJ)!6r`#!2rq!J')L3)!c!##"jc0!JZCQ3)IQCN#,c
+-b!6-6-3$Kr-i!!2!!!!"J!!!!B!!!!2!!"rrlrJrrrrm2rrrrKrrrri2rrrq$rr
+rr!rrrrJ2rrr`$rrri!rrrr!Irrri2rrrr(rrrrlrrrrrrrrrrhrrrrirrrrm(rr
+rq!rrrr!2rrri$rrrr!rrrri2rrrm$rrrr!rrrr`2rrri"mrrr!1(mcJ!!m!!!!'
+!!!!!!J!!!!!!!!!!$r!!!!!!!!!!!!!!!!!!!2L2!!!!!!!!!!!2rrrrrrq*Q2$
+rrrrrm!!!m!!!!!!!qCQ2!!!!!!m!!2$-c-c-c-qCR`c-c-c-m!!2c-c-c-cIQCR
+mc-c-cI!!!2h-c-cGqCQCRpc-c0h`!!$`c-c-hjQCQI$-c-hI!!!!m-c-c0qCQCm
+!c-cGm!!!!2$-c-cIQCR`$-c0h`!!!!$`c-c-hjQI!-c-hI!!!!!!m-c-c0qCm!c
+-cGp[!!!!$r$-c-cIR`$-c0hjP[!!!2M`c-c-hr!-c-hIQCP[!!q*m-c-c0m!c-c
+GqCQCP[$iQI$-c-c3$-c0hjQCQCP[q*R`c-c-d-c-hIQCQCQCE`q*m-c-c0c-cGq
+CQCQCP[!!q2$-c-c-c2rjQCQCQ@m!!!r`c-c-c-r-qCQCQCE`!!!!m-c-c-c2c2Q
+CQCP[!!!!!2$-c-c-hrqIrjrrrr!!!!$`c-c-cIc-r-cmc2c2!!!!m-c-c0hrc2r
+-c-c-c2!!!2$-c-hIr-rrc'E-rmm!!!$`c-cGqIc2r-Emcrc2!!!!m-c0hjRmcrc
+2r-rmc`!!!2$-hIqIc2r-rmcrc2!!!!!2cGm!rmc2c2r-rmc2!!!!!2r`!!rrp[m
+!r`$rm!!!!!!!!!!!pQm!!!!!!!!!!!!!!!!!!!r`!!!!!!!!!!!!!%!q[%(#3--
+KaL1-)4`L2Q!ri2jKI#(+)N%R95p9'P8"UMqmIrjrrcrq2r`rr(rqrrrrrRrm2ri
+rrcrr2rmEr`'U!!!!J!$rrrM`rrm!$`!!$jm!!2!2c-c0rmc-h`$mc0qI$-h`!2c
+-hr$-h`!!r-cI$-hr!!Mmc0$-hjR`LIc-$-hjQCrjr-c-rjQCB!rmc-r2rjm!!2c
+-crr-r2!!r-cmcmc-c`$mcIr2cmr2!2cIRmr2cmm!$r$mcmr2c`!!!!r`m2$`!!!
+%!!!!!!$rrrrrrrrrrrrrrrrrrrrrrrrr!!!!!!!!!!!!!!!!!2repIAepIAepIA
+epIAepIAepIrr!!!!!!!!!!!!!!!!rrAepIAepIAepIAepIAepIAerb[r!!!!!!!
+!!!!!!!$rpIAepIAepIAepIAepIAepIAr+b[r!!!!!!!!!!!!!2repIAepIAepIA
+epIAepIAepImV+b[r!!!!!!!!!!!!rrAepIAepIAepIAepIAepIAerbXV+b[r!!!
+!!!!!!!$rpIAepIAepIAepIAepIAepIArrrrrrrrr!!!!!!!!!2repIAepIAepIA
+epIAepIAepIAepIAepIm!!!!!!!!!rrAepIAepIAepIAepIAepIAepIAepIAer`!
+!!!!!!!$rpIAerrrrpIrrrrArrrrerrrerrrepIAr!!!!!!!!!2repIAepIAepIA
+epIAepIAepIAepIAepIm!!!!!!!!!rrAepIAepIAepIAepIAepIAepIAepIAer`!
+!!!!!!!$rpIAerrrrpIrrrrrerrrrrrArrrrepIAr!!!!!!!!!2repIAepIAepIA
+epIAepIAepIAepIAepIm!!!!!!2rrrrrrpIrerrrrrrAepIAepIAepIAepIAer`!
+!!!$r!!!!!!$rpIm!!!!!rrAerrArrrrerrrepIAr!!!!!2mVprFVprRrrb[hpb[
+krrAepIAepIAepIAepIm!!!!!!2rh+rIjrrAr!2FVq[repIAepIAepIAepIAer`!
+!!!!!rb[hprVrr`$h+rVrpIAepIAepIAepIAepIAr!!!!!!$rprIhqIm!pb[krrr
+epIAepIAepIAepIAepIm!!!!!!2mVpb[k!#[hq[repIAepIAepIAepIAepIAer`!
+!!!!!rrFVp`$hprRrpIAepIAepIAepIAepIAepIAr!!!!!!$rprFVpb[rrrAepIA
+epIAepIAepIAepIAepIm!!!!!!2mVprFVrb[rrrrerrAepIAepIAepIAepIAer`!
+!!!!!rrFVprIrrrmVprmVrrAepIAepIAepIAepIAr!!!!!!$r+rIhrrFVrrFVprF
+VrrAepIAepIAepIAepIm!!!!!!2rh+rVrrrIrprmVrrIrpIAepIAepIAepIAer`!
+!!!!!rb[kr`$r+rmVrrIr+rrepIAepIAepIAepIAr!!!!!!!!rrrerb[hrrIr+rr
+hrrAepIAepIAepIAepIm!!!!!!!!!rrAerrrerrArpIrepIAepIAepIAepIAer`!
+!!!!!!!$rpIAepIAepIAepIAepIAepIAepIAepIAr!!!!!!!!!2rrrrrrrrrrrrr
+rrrrrrrrrrrrrrrrrrrm!!!!!!!%!$rrq!!J!!`!)!!+!#!!#3!J!!L!)!!)3#!!
+$q!J!!!J)!!!)#1lYL!J!!!J)!!!)#1plL!J!!!Jq[!!)38*GL%$$!!JK4J!))i`
+!##%F!!JL-!!))#!!##$!!!JKG!!))FS!##*"!!JR93!),98!#"T9!!J*UJ!)#!!
+!#!rrrrJ2rri!$rrr!!rrri!2rrr!$rrri!rrrr!2rrri$rrrq!rrrrJ2rrri$rr
+rq!rrrrJ2rrri$rrrq$rrrrKrrrriIrrrq$rrrrJrrrri2rrrq$rrrrJrrrri2rr
+rq$rrrrJrrrri2rrrq$rrrrJrrrri(rrrq!rrrrJ2rrri$rrrq!!!!J!!!2rrrrr
+rrrrrrr!!!!!!!!$m$!`-$!`-$!cr!!!!!!!!m-$!`-$!`-$!r2!!!!!!!2`-$!`
+-$!`-$2c2!!!!!!$``-$!`-$!`-$mc2!!!!!!r!`-$!`-$!`-r-c2!!!!!2$!`-$
+!`-$!`2rrrr!!!!$m$!`-$!`-$!`-$!c`!!!!m-$!`-$!`-$!`-$!m!!!!2`-rrc
+rr2rmr`rm$2!!!!$``-$!`-$!`-$!`-$`!!!!r!`-$!`-$!`-$!`-m!!!!2$!rr$
+rrmrrm2r``2!!!!$m$!`-$!`-$!`-$!c`!!$rrr$`rrr!`-$!`-$!m!!2!!!2$`!
+!r!m2r`rm$2!!$mc-cIr-c0r!`-$!`-$`!!$mc0m2$-hm$!`-$!`-m!!!r-cIm-c
+I`-$!`-$!`2!!!2c-h`c0r``-$!`-$!c`!!$mc0$-hm$!`-$!`-$!m!!!r-`-cI`
+-$!`-$!`-$2!!!2c-c2r!`-$!`-$!`-$`!!$mc-r2r`m-$!`-$!`-m!!!r-c2rmc
+mm-$!`-$!`2!!!2c-r-r-c-m-$!`-$!c`!!$mcIr2cmr2`-$!`-$!m!!!r0m2cmr
+2c``-$!`-$2!!!!r`r-r2cmr!`-$!`-$`!!!!r!rmr2cm$!`-$!`-m!!!!2$!`-$
+!`-$!`-$!`2!!!!$rrrrrrrrrrrrrrrr`!!!!!)!!rrrrrrm!!!$`!!!!$r!!!2!
+!!!!2c`!!m!!!!!rrm!$`!!!!!!$`!2!2$r$r!2!!m!!!!!!!m!$r!2m2$`$`$mc
+rc2!!!2!2c2r-m2m!m!r-r-m!!!$`$mr-m!m2!2!2c-m!!!!!m!r-m!!!!!$`$mm
+!!!!!!2!!rrrrrrrrm!!!!%!rm#!B)"3J(L!#*E)J!M056)*-XNN#8P*%!NJ#8!)
+rrMr`2rJrr$rq2rirrMrq2rjrrRrqIrjrrRrqIrjrrMrq!!!%!!!!!!!!!!!!!!!
+!!!!!!2rr!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!$rZERr!!!!!!!!!!!
+!!!!!!!!!!!$rrrrrrrrrrrrrrlRPjVRr!2rrrrrrrrrrr`!!!!!!r`!!!!!!!!!
+!!!!!rqAQjERr!!!!!!!!!!!!r`!!!!$r!#[hpb[h+rIh+rFVrqAQjIm!+rIh+rF
+VprFVr`!!!!$rprFVprIh+rIh+rVrjZAQjIrhpb[hprIh+rVr!!!!!!$rqIIh+rI
+h+rVkrqAQjHEQjIrjprFVpb[kqIm!!!!!!2m!+rIh+rIhqIrPjZAQjHAr!2FVprF
+Vq[Rr!!!!!!!!r`$h+rIhpb[krqEPjZAQr`!!prFVprVjr`!!!!!!!!$r!2Ihpb[
+hprRrjHEPj[m!!#[h+rIkqIm!!!!!!!!!!2m!+rIhpb[hq[rPjHEr!!$hpb[hq[R
+r!!!!!!!!!!!!r`$hprFVprIjrqAQr`!!+rFVprVjrqrr!!!!!!!!!2rr!#[h+rI
+h+rVrj[m!!2IhprIjq[rPjZrr!!!!!!$rZIm!pb[hprIhqIrr!!$h+rFVqIVrjZA
+QjHrr!!!!rlRPr`$hpb[h+rIkr`!!+rIhprVjrqAPjZAQjHrr!2qjjHEr!#[hpb[
+hprN!!2Ihpb[kqIrQjHEPjZAQjHrrrlRQjIm!pb[hprFVqJ!Vpb[hq[RrjHEPjZA
+QjHEQm2m!rlRQr`!VprIh+rIjprFVprVjrqAQjHEPjZAQjHrr!!!!rlRr!2Ih+rI
+hprFVprIrrrrPjZAQjHEPjZA[r`!!!!!!rrm!pb[hpb[h+rIhrrFVrqEPjZAQjHE
+Plrm!!!!!!!!!r`$hpb[hpb[hpb[r+rIrjHEPjZAQjHrr!!!!!!!!!!$r!#[hpb[
+hprFVq[rrrqArrrrPrrrrrrrr!!!!!!!!!2m!pb[hpb[hprVr+rFVrb[hprmVpb[
+r+rIr!!!!!!!!r`$hprFVprIjqIrrprIrrrFVprFVprIhpb[r!!!!!!$r!#[hprF
+Vq[Vrrb[hrrrr+rI`lrFVrrmVr`!!!!!!!2m!pb[h+rVjrqArpb[rrb[hm2rh+rr
+rprIr!!!!!!!!r`$hpb[kq[rPj[rhprrrprIrrb[hrrmVprm!!!!!!!$r!#[hq[R
+rrqErpb[rrrFVrrmVprrr+rIr!!!!!!!!!!$rprRkr`!!rrmVprIr+rIrrrIhrrr
+h+rIr!!!!!!!!!!$rrrm!!!!!rrrrrqrrr`!!rrm!!2rrr`!!!!!!!!!!!!!!!!!
+!!!!!rqr`r`!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!rrm!!!!!!!!!!!!
+!!!!!!!!!!!3!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!rrrrrrre!!$rrrrr!!!!!!!!!!!
+!!!!!!!!!!!!!!2m!!!!!!2m!r`!!!!$r!!!!!!!!!!!!!!!!!!!!!!!!rb[hpb[
+hqIrr+rIh+rVr!!!!!!!!!!!!!!!!!!!!!!!!rrFVprRrpIm!pb[kr`!!!!!!!!!
+!!!!!!!!!!!!!!!$r+rIhq[rr!2FVq[m!!!!!!!!!!!!!!!!!!!!!!!!!!2rhprI
+jr`$h+rVr!!!!!!!!!!!!!!!!!!!!!!!!!!!!rb[h+rS!+rIkr`!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!$rpb[h!2IhqIm!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!2rhpb[
+h+rIrp3$r!2m!!2m!r`!!!!!!!2m!!!!!!!!!rb[hpb[hr`!!!2rrrrrrrrrrrrr
+rrrrrr`!!!!!!!!$rpb[hprm!!!!!!!!!!!!!!2m!!!!!!!!!!!!!!!!!!2mVprI
+r!!$rr`!!rrrrrrre!!$rrrrr!!!!!!!!!!!!rrFVr`!!!2m!!2m!!!!!!2m!!!!
+!!!$r!!!!!!!!!!$r+rm!!!!!rrm!!!!!!!!!!!!!!2Ih+rVr!!!!!!!!!!$r!!!
+!!!$r!!!!rrrr!!$rr`!!pb[kr`!!!!!!!!!!!!!!!!!!!2m!!2m!!!$rr`!!r`!
+Vq[m!!!!!!!!!!!!!!!!!!!!!rrm!!2m!r`$r!!$r!2Vr!!!!!!!!!!!!!!!!!!!
+!!!$r!!!!r`$rr`!!r`!!r`!!!!!!!!!!!!!!!!!!!!!!!2rrr`$r!2m!!2m!!2m
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!2m!!!$r!!$rp3!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!r`!!r`!!!!!!!2rr!!$rr`!!!!!!!!!!!!!!!!!!!!$r!2m!!!!!!!$
+rprIrrrIhr`!!!!!!!!!!!!!!!!!!!!$r!!!!!!!!!2rhprrrprIr!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!rrIhrrIhr`!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!$
+rprrhprm!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!2rhprIr!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!rrIhr`!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!$
+rprm!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!$r!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!3!!!2rrrrrrZIm!rrrrr`!!!2m
+!!!!!!2rPr`!!!!$r!!$r+rIh+rIjrrmVprFVq[m!!2rh+rIjrqAr!2FVq[m!!!$
+r+rIhq[rr!2FVq[m!!!!!rrIhprRr!2FVq[rr!!!!ZImVpb[k!#[hq[rPj[m!ZHA
+rpb[h!2IhqIrPjZAPrrrQrrIh+rFVrrrPjZAQl`!!rrmVprFVrb[rrrrQr`!!!!$
+rpb[hprrrrb[hrb[r!!!!rb[hprrh+rrh+rIh+rm!!2rh+rVrrrIrprmVrrIr!!$
+r+rVrjImVrb[rprmVr`!!!2rr!2mVprrhrb[rprm!!!!!!!!!rrm!r`$r!2m!!!!
+"!!!!rrrrrrrrrrrrr`!!!!!!!2repIAepIAepIrr!!!!!!$rpIAepIAepIAr+rm
+!!!!!rrAepIAepIAerrrrr`!!!2repIAepIAepIAepIm!!!$rpIArpIrrpIrrpIA
+r!!!!rrAepIAepIAepIAer`!!!2rrpIArrrArpIrepIm!!2rhprrrprIrpIAepIA
+r!!$rprIrrrIhrrArrrAer`!!rrIhrrIhrrAepIAepIm!!2rhrrIhrrAerrArpIA
+r!!$rprIhrrAepIAepIAer`!!rrIhrrAepIAepIAepIm!!2rhrrAepIAepIAepIA
+r!!!!rrrrrrrrrrrrrrrrr`!!!!%#!!S!!!!!!"3"@J!S!E`%"%CTEQ3!!!!!!$!
+"@3"%!EX%"e*PF'aKBf9M!!!!!!"0!9S!B3'm"!j5CA"XB@0P)#BJ4QPZC!!!!!!
+!D3&D!(d"[!3,8Q9`E'&MC5""E'bQ!!!!!!"h!&)!L3#m"3Y*Cfj[FQ8J3f&cCAF
+!!!!!!(J!a!#+!5i&"P*PCf9iF!!!!!!!M`"5!+%![!8,4@jdDA*P)&G[FQ4%!!!
+!!!!8!&8!0J%l%!P&C'Pd)&4PH(5m!!!!!!"#!&8!C!%l%!P&C'Pd)&4PH(4D!!!
+!!!!6!#d!)`"5L!9'D@jN1UB!!!!!!%3!&J"8!&+)#&*PF'aKBf8k!!!!&3"&!#)
+!m!(Y!!3"!!%!!!!!!!#&!!!!!1J!!!!!!1J!!J!"#%GKFQCTC@aN!!!!!!!!!!!
+!!!!!!!!!!!!!!,%1([G#4!!!!!![fJa3HA4SEfiJ-5ie,M%!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!#rEX@T1)J"
+h!&B"qJ'$rrrrr`!!!!!!!!!!!!!!!!!!!!!!!!!8T8aKEQGeB@GPFbp6Bh*TF(4
+TEQF!!3!%!!![fJ!#!#T(BA*QD@9XC$UP6'&ZCh9KCf9c,e0MFQP`G'PZCcT3HA4
+SEfiJ-5ie,M(rr`!!!!!!%&4&@&4dG(Kd!+J`-6Ja!!!!!!)!!!!!!!!!!!!!!!!
+!!!!!!!$rrrrrm!!!!!!!!!!!!!!!m!!!!2m!!!!!!!!!!!!!!2$r!!$`m!!!!!!
+!!!!!!!$Xrq!!rrm!!!!!!!!!!!!!c`r`!!!2!!!!!!!!!!!!!1rrrJ!!$q!!!!!
+!!!!!!!$`!2m!!!rJ!!!!!!!!!!!2rJlrm!!2i!!!!!!!!!!!!-!!!!!!$1!!!!!
+!!!!!!!$`-`!`!2rr`!!!!!!!!!!!m1-!-`$q$r!!!!!!!!!!!2!1-c-`rrr!!!!
+!!!!!!!$`!!!c!2i2m!!!!!!!!!!!m!!!-!$q$r!!!!!!!!!!!2rrrmrmrrr!!!!
+!!!!!!!!!$ZlZlXc-!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!%!!!!!!$rJ!!!J-!!!,#J!!#`m!!!@"!!
+!2JB!!#-'!!"MKJ!!!!)!!#b2!!!XcB!!*qm!!#$0J!!JMB!!2fm!!!I`!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!2q!!!$r`!!!rq!!!2r`!!$rm!!!rrJ!!2ri!!(rq!!!rrJ!
+!2rq!!$rrJ!!rri!!2rq!!$rrJ!!rri!!"rm!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!3$rrm!
+!J!"!!)!!3!#!!%!!J!"!!)!!3!#!!%!!J!"!!)!!3!#!!%!!J!"!!)!!3!#!!%!
+!J!"!!)!!3!#!!%!!J!"!!2rr`!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!2rr`!$rrm!!rrr!!2rr`!$rrm!
+!rrr!!2rr`!$rrm!!rrr!!2rr`!$rrm!!rrr!!2rr`!$rrm!!rrr!!2rr`!$rrm!
+!rrr!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!#!2rrrrrrrrrrr`!!!!!!!!$`!!!!!!!!!!m!!!!!!!!
+!m!!!!!!!!!!2!!!!!!!!!2!!!!!!!!!!$`!!!!!!!!$`!!!!!!!!!!m!!!!!!!!
+!m!!!!!!!!!!2!!!!!!!!!2!!!!!!!!!!$`!!!!!!!!$`!!!!!!!!!!m!!!!!!!!
+!m!!!!!!!!!!2!!!!!!!!!2!!!!!!!!!!$`!!!!!!!!$`!!!!!!!!!!m!!!!!!!!
+!m!!!!!!!!!!2!!!!!!!!!2!!!!!!!!!!$`!!!!!!!!$`!!!!!!!!!!m!!!!!!!!
+!m!!!!!!!!!!2!!!!!!!!!2!!!!!!!!!!$`!!!!!!!!$`!!!!!!!!!!m!!!!!!!!
+!rrrrrrrrrrrr!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!#!!!!!!!!!!!!!!!!!!!!!!!!!+!!!!#J!!!!!!!!!!!!!!Skrrrk1[!!!!!
+!!!!!!!#M-kc-Sc1Z!!!!!!!!!!!!#M-kbM-krJ!!!!!!!!!!!!qM-k-cS2i!!!!
+!!!!!!!!2bM-c1X$q!!!!!!!!!!!!$mbM-cc!rJ!!!!!!!!!!!!r+-c-c`2i!!!!
+!!!!!!!!2Sc1M-k$q!!!!!!!!!!!!#M-kbM-krJ!!!!!!!!!!!+-cV-bM-ki!!!!
+!!!!!!!!+1Xc-bM-k!!!!!!!!!!!!$kc-c-bMVJ!!!!!!!!!!!!m!!!!!b[i!!!!
+!!!!!!!!2rrrrrrrq!!!!!!!!!!!!!!$ZlZlZlJ!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"!!!!!!!)#!!
+!(ri!!$iq!!!IIJ!!(rS!!"Ib!!!6iJ!!&r)!!"rk!!!IIJ!!2Mi!!"`I!!!B$J!
+!%!B!!"rq!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!J)!!!IrJ!!2rm!!"rr!!!Ir`!
+!(rm!!"rr!!!Ir`!!(rm!!"rr!!!rr`!!(rm!!"rr!!!Ir`!!(rm!!!2r!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!)!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!2rrr
+rrr!!!!!!!!!!!!!!$`!!!!$q!!!!!!!!!!!!!!m2rrrrrrrr!!!!!!!!!!!2!!$
+`!!!!$`!!!!!!!!!!$`rrm2rrr`rJ!!!!!!!!!!m!!2!!!!!2i!!!!!!!!!!2$rr
+`rrrr$q!!!!!!!!!!$`!!m!!!!!rJ!!!!!!!!!!m2m2$rrrm2i!!!!!!!!!!2!!$
+`!!!!$q!!!!!!!!!!$rrrm2m!!!rJ!!!!!!!!!!$Zl[!!!!!2i!!!!!!!!!!!!!$
+rrrrrrq!!!!!!!!!!!!!!!1lZlZlJ!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!%
+!!!!!!!!!!!"ri!!!3$!!!&rr!!"#!3!!A[f!!%)"J!"HrB!!3J'!!&VpJ!"#!B!
+!IX'!!$i"J!!$ri!!!2q!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!(rJ!!"rm!!
+!Irm!!(rr!!"rri!!Irq!!(rrJ!"rri!!Irq!!(rrJ!"rri!!2rq!!!2rJ!!!ri!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!3!'q!!!#33!!!J#!!!*$3!!"[X!!"rrJ!!`H-!
+!B(M!!0ai`!#FH-!!R(M!!-"i`!"JH-!!2rr!!"rr`!!!H!!!!(J!!!!i!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!Ei!!!2r!!!$ri!!!rr!!!'q`!!(rq!!$rr`!"rrm!!rrr!!2rr`!$rrm!
+!rrr!!(rr`!!rrm!!(rr!!!"i!!!!H!!!!$J!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!#!!!!$r$rrr!
+!!!!!!!!!!!!!!2!2!!!2!!!!!!!!!!!!!!$`!!!!!2!!!!!!!!!!!!!!m!m!!2m
+2!!!!!!!!!!!!!!r`rrr3r`!!!!!!!!!!!!%F`Frr`Fr3!!!!!!!!!!!G%4%Irp%
+4r3!!!!!!!!!"d4%4(rr4%Id!!!!!!!!!(4cF%4rrd4(p!!!!!!!!!"%Gr4%Irp%
+4r3!!!!!!!!$4(0`4(rr4%Id!!!!!!!!!ha%4%4rrd4(p!!!!!!!!!!ha%4%Irp%
+4r3!!!!!!!!!!hrrrrrrIrrd!!!!!!!!!!!hGhGrrhGhG!!!!!!!!!!!!!!!2rp!
+!!!!!!!!!!!!!!!!!$rr3!!!!!!!!!!!!!!!!!!$Gd!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!%!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!$rrrrrrrrrrrm!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!2m
+!!!!!!!!!rrm!!!!!!!!!!!!!!!!!!!!!!!!!!!!!r`$rr`!!!!$r!2m!!!!!!!!
+!!!!!!!!!!!!!!!!!!!$j+rrrq3!!!2rrrrm!!!!!!!!!!!!!!!!!!!!!!!!!!#[
+r!2rr!!!!!!!!r`!!!!!!!!!!!!!!!!!!!!!!!!!!qIrrrrrj!!!!!!$rq3!!!!!
+!!!!!!!!!!!!!!!!!!!$r!!!!rrm!!!!!!2rj!!!!!!!!!!!!!!!!!!!!!!!!rrr
+j!2Rrrrm!!!!!rrN!!!!!!!!!!!!!!!!!!!!!!!!!+`!!!!!!!!!!!!!Vq3!!!!!
+!!!!!!!!!!!!!!!!!!!$r!0MB!!$B!!!!rrrrrbX!!!!!!!!!!!!!!!!!!!!!!2m
+!qGJ!!0MB!!$rr!$rr`!!!!!!!!!!!!!!!!!!!!!!r`!!qGMBf0MB!2rrrrmV!!!
+!!!!!!!!!!!!!!!!!!!$r!!!!!!$Bf!!!rr`!rrm!!!!!!!!!!!!!!!!!!!!!!2m
+!!!!!!0J!!!$rr!$rr`!!!!!!!!!!!!!!!!!!!!!!rrrrrrrr+rrr+rrrrrmV!!!
+!!!!!!!!!!!!!!!!!!!!!!!$jqIRjqIRj+bXV+`!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!3
+!rrrrrrrrrrrrrrrrrrrrrrrr!!!!!!!!!!!!!!!!!!$r!!!!!!!!!!!!!!!!!!!
+!!2m!!!!!!!!!!!!!!!!!!2m!!!!!!!!!!!!!!!!!!!!!r`!!!!!!!!!!!!!!!!!
+!r`!!!!!!!!!!!!!!!!!!!!$r!!!!!!!!!!!!!!!!!!$r!!!!!!!!!!!!!!!!!!!
+!!2m!!!!!!!!!!!!!!!!!!2m!!!!!!!!!!!!!!!!!!!!!r`!!!!!!!!!!!!!!!!!
+!r`!!!!!!!!!!!!!!!!!!!!$r!!!!!!!!!!!!!!!!!!$r!!!!!!!!!!!!!!!!!!!
+!!2m!!!!!!!!!!!!!!!!!!2m!!!!!!!!!!!!!!!!!!!!!r`!!!!!!!!!!!!!!!!!
+!r`!!!!!!!!!!!!!!!!!!!!$r!!!!!!!!!!!!!!!!!!$r!!!!!!!!!!!!!!!!!!!
+!!2m!!!!!!!!!!!!!!!!!!2m!!!!!!!!!!!!!!!!!!!!!r`!!!!!!!!!!!!!!!!!
+!r`!!!!!!!!!!!!!!!!!!!!$r!!!!!!!!!!!!!!!!!!$r!!!!!!!!!!!!!!!!!!!
+!!2m!!!!!!!!!!!!!!!!!!2m!!!!!!!!!!!!!!!!!!!!!r`!!!!!!!!!!!!!!!!!
+!r`!!!!!!!!!!!!!!!!!!!!$r!!!!!!!!!!!!!!!!!!$r!!!!!!!!!!!!!!!!!!!
+!!2m!!!!!!!!!!!!!!!!!!2rrrrrrrrrrrrrrrrrrrrrrr`!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!$F!!!!!!!!!0`!!!!!!!!!!!!!!!!!!!!!!!!!!!!!h#2Errrrrrr
+E)pcr!!!!!!!!!!!!!!!!!!!!!!!!!0XM)b2E+bXVfb-M)p[j!!!!!!!!!!!!!!!
+!!!!!!!!!!0`M)b2F+p`M)b2FrrN!!!!!!!!!!!!!!!!!!!!!!!!!rp`M)b2F)b-
+Mh!$rq3!!!!!!!!!!!!!!!!!!!!!!!!$r+p`M)b-M)p`V!2rj!!!!!!!!!!!!!!!
+!!!!!!!!!!2mV+p`M)b2E+bX!rrN!!!!!!!!!!!!!!!!!!!!!!!!!rb[F)b-M)b2
+E+`$rq3!!!!!!!!!!!!!!!!!!!!!!!!$rfb-M)p`M)b2F!2rj!!!!!!!!!!!!!!!
+!!!!!!!!!!0XM)b2F+p`M)b2FrrN!!!!!!!!!!!!!!!!!!!!!!!$F)b-MfbXV+pX
+M)b2Eq3!!!!!!!!!!!!!!!!!!!!!!!!$F)p`V+bXV+p`M)b2F!!!!!!!!!!!!!!!
+!!!!!!!!!!2rF+bXV+bXV+p`MfrN!!!!!!!!!!!!!!!!!!!!!!!!!r`!!!!!!!!!
+!+p[rq3!!!!!!!!!!!!!!!!!!!!!!!!$rrrrrrrrrrrrrrrrj!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!2RjqIRjqIRjqIN!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!%!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!rrrrrrrrrrrrr`!!!!!!!!!!!!!!!!!!!!!!!!!!!!$r!!!!!!!
+!!!$rq3!!!!!!!!!!!!!!!!!!!!!!!!!!!2m!rrrrrrrrrrrrrrrrr`!!!!!!!!!
+!!!!!!!!!!!!!r`!!!!$r!!!!!!!!!!$r!!!!!!!!!!!!!!!!!!!!!!$r!2rrrrm
+!rrrrrrrr!2rj!!!!!!!!!!!!!!!!!!!!!2m!!!!!r`!!!!!!!!!!rrN!!!!!!!!
+!!!!!!!!!!!!!r`$rrrrr!2rrrrrrr`$rq3!!!!!!!!!!!!!!!!!!!!$r!!!!!2m
+!!!!!!!!!!2rj!!!!!!!!!!!!!!!!!!!!!2m!rrm!r`$rrrrrrrm!rrN!!!!!!!!
+!!!!!!!!!!!!!r`!!!!$r!!!!!!!!!!$rq3!!!!!!!!!!!!!!!!!!!!$rrrrrrrm
+!rrm!!!!!!2rj!!!!!!!!!!!!!!!!!!!!!!$jqIRjr`!!!!!!!!!!rrN!!!!!!!!
+!!!!!!!!!!!!!!!!!!!$rrrrrrrrrrrrrq3!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!qIRjqIRjqIRj!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!3!!!!!!!$rr`$rrrrrr`!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!r`!!r`!!!!!!r`!!!!!!!!!!!!!!!!!!!!!!!!!!!!$r!!!!!!!!!!!!r`!!!!!
+!!!!!!!!!!!!!!!!!!!!!!2m!!2m!!!!!rrm!r`!!!!!!!!!!!!!!!!!!!!!!!!!
+!!2rr!2rrrrrj!2rr!!!!!!!!!!!!!!!!!!!!!!!!!!%"+bX"+rrrrbX"+rqI!!!
+!!!!!!!!!!!!!!!!!!!!"q38&"38&rrrrq38&"Irj!!!!!!!!!!!!!!!!!!!!!IN
+&"38&"3Arrrrj"38&rrN!!!!!!!!!!!!!!!!!!!(j"5[j+`8&"IrrrrN&"3Arq3!
+!!!!!!!!!!!!!!!!!!38&qIrj"38&rrrrq38&"Irj!!!!!!!!!!!!!!!!!!$j"38
+Vq5X&"3Arrrrj"38&rrN!!!!!!!!!!!!!!!!!!2Rr"38&"38&"IrrrrN&"3Arq3!
+!!!!!!!!!!!!!!!!!!2Rr"38&"38&rrrrq38&"Irj!!!!!!!!!!!!!!!!!!!!!2R
+rrrrrrrrrrrrjrrrrrrN!!!!!!!!!!!!!!!!!!!!!!2RjqIRjqIrrrrRjqIRjq3!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!rrrrq3!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!$rrrrj!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!$jqIN!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!J!!!!!!!!!!!!!!!!!!!!!
+!!!!2!!!2i!!!!!!!!!!!!!!!$q!!$q!!!!!!!!!!!!!!!!$`!2i!!!!!!!!!!!!
+!!!!!rJ$q!!!!!!!!!!!!!!!!!!m2i!!!!!!!!!!!!!!!!!!2lq!!!!!!!!!!!!!
+!!!!!!2i!!!!!!!!!!!!!!!!!!!rri!!!!!!!!!!!!!!!!!lq!2i!!!!!!!!!!!!
+!!!$rrJ$rm!!!!!!!!!!!!!!2l[i!rJm!!!!!!!!!!!!!$`$q!2i2i!!!!!!!!!!
+!!!m!rJ$q$q!!!!!!!!!!!!!!rqi!$ri!!!!!!!!!!!!!!1i!!!lJ!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!3!!!!!!""!!!!33!!!#)!!!!L!!!!&!!!!"3!!
+!!)!!!!(!!!!#)!!!$MJ!!")N!!!5*!!!%L3!!!`B!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!%'!!!"KJ!!!)`!!!$-!!!!@!!!!(J!!!!`!!!!H!!!!F`!!!21!!
+!(c`!!"mq!!!I2J!!$a`!!!`B!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"!!!!!!!!!!!
+!!2q!!!#"J!!!JB!!!i'!!!1"J!"rcB!!Iqf!!(rKJ!"r`B!!!i'!!!1"J!!!Ki!
+!!*q!!!$rJ!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!ri!!!2q!!!$rJ!!$ri!
+!!rq!!(rrJ!"rri!!Irq!!(rrJ!!$ri!!!rq!!!$rJ!!!ri!!!2q!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!)!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!rrrrrr!!!!!!!!!!!!!!!2!!!!r`!!!!!!!!!!!!!!$`!!!2m!!!!!!!!!!!!!$
+rm!!!$r!!!!!!!!!!!!!!mr!!!!r`!!!!!!!!!!rrrr-r!2m2m!!!!!!!!!!2-c-
+c-r$r$r!!!!!!!!!!$c-c-c2`!!r`!!!!!!!!!!rrrr-r!!!2m!!!!!!!!!!!!!$
+cm!!!$r!!!!!!!!!!!!!!rr!!!!r`!!!!!!!!!!!!!!$`!!rrm!!!!!!!!!!!!!!
+!m!rrrr!!!!!!!!!!!!!!!2rrrrr`!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!)
+!!!!!!!!!!!!!!!!!!!!!!!rrrrrr!!!!!!!!!!!!!!!2!!!!$r!!!!!!!!!!!!!
+!$`!!!!r2!!!!!!!!!!!!!!m!!!!2rr!!!!!!!!!!!!!2!!!!!!$`!!!!!!!!!!!
+!$`!!!!rrm!!!!!!!!!!!!!m!!!$mc-m!!!!!!!!!!!!2!!!2`!c-m!!!!!!!!!!
+!$`!!$m$-c2!!!!!!!!!!!!m!!!r-c-c`!!!!!!!!!!!2!!!2c-$-m!!!!!!!!!!
+!$`!!!2c-cm!!!!!!!!!!!!m!!!!2rrcr!!!!!!!!!!!2!!!!!!$`rr!!!!!!!!!
+!$rrrrrrrm!r`!!!!!!!!!!!!hGhGhGd!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!%!!!!!!(r!!!"!B!!
+!3&!!!%"i!!"!#!!!3(J!!%#%!!""!J!!33)!!%%#!!""!J!!3)3!!%"l!!"!#i!
+!IrQ!!!US!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!Im!!!(rJ!!"rm!!!IrJ!!(ri!!"rq!!
+!Ir`!!(rq!!"rrJ!!Iri!!(rq!!"rrJ!!Irm!!(rlJ!"rqB!!$r`!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!r`!
+!!!!!rrN!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!$rq3!!!!$rq3!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!$r!!!!rrN!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!2r
+j!!$rq3!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!2m!rrN!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!rrRrq3!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!rrN!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!2rrrrN!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!2Rrq3!!rrN!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!$rrrr
+j!!$rrrm!!!!!!!!!!!!!!!!!!!!!!!!!!!!!rrRjrrN!!2rj!2m!!!!!!!!!!!!
+!!!!!!!!!!!!!!!$r!!$rq3!!rrN!rrN!!!!!!!!!!!!!!!!!!!!!!!!!!2m!!2r
+j!!$rq3$rq3!!!!!!!!!!!!!!!!!!!!!!!!!!!2rrqIN!!!$rrrN!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!qIN!!!!!!2Rj!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!%!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!2rrrrrrrrrrr`!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!r`!!!!!!!2rr!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!$r!!!!!!!!rrm!!!!!!!!!!!!!!!!!!!!!!!!
+!!!$rrrm!!!!!!!$rr`!!!!!!!!!!!!!!!!!!!!!!!!!!!2rBr`!!!!!!!2rr!!!
+!!!!!!!!!!!!!!!!!!2rrrrrrrpMBr`!!rrm!rrm!!!!!!!!!!!!!!!!!!!!!rpM
+Bf0MBf0MBr`$rr`$rr`!!!!!!!!!!!!!!!!!!!!$rf0MBf0MBf0Mr!!!!!2rr!!!
+!!!!!!!!!!!!!!!!!!2rrrrrrrpMBr`!!!!!!rrm!!!!!!!!!!!!!!!!!!!!!!!!
+!!!$rf2m!!!!!!!$rr`!!!!!!!!!!!!!!!!!!!!!!!!!!!2rrr`!!!!!!!2rr!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!$r!!!!!2rrrrm!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!2m!!2rrrrrrr`!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!rrrrrrrrrrrr!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!3
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!rrrrrrrrrrrr!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!$r!!!!!!!!!2rr!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!2m!!!!!!!!!rb[r!!!!!!!!!!!!!!!!!!!!!!!!!!!!r`!!!!!!!!$rrrrr!!!
+!!!!!!!!!!!!!!!!!!!!!!!$r!!!!!!!!!!!!!2m!!!!!!!!!!!!!!!!!!!!!!!!
+!!2m!!!!!!!!!rrrrr`!!!!!!!!!!!!!!!!!!!!!!!!!!r`!!!!!!!2mVprFVr`!
+!!!!!!!!!!!!!!!!!!!!!!!$r!!!!!!$r+`!!prFVr`!!!!!!!!!!!!!!!!!!!!!
+!!2m!!!!!!2rh!2FVprIr!!!!!!!!!!!!!!!!!!!!!!!!r`!!!!!!rrIh+rIh+rm
+!!!!!!!!!!!!!!!!!!!!!!!$r!!!!!!$rpb[h!#[hr`!!!!!!!!!!!!!!!!!!!!!
+!!2m!!!!!!!$rprIhprmV!!!!!!!!!!!!!!!!!!!!!!!!r`!!!!!!!!$rrrrr+rr
+r!!!!!!!!!!!!!!!!!!!!!!$r!!!!!!!!!!!!!2m!rrrr!!!!!!!!!!!!!!!!!!!
+!!2rrrrrrrrrrrrrrr`!!rrm!!!!!!!!!!!!!!!!!!!!!!!!!q[RkqIVjq[Rkq3!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!3!!!(B,!!"e#`!!"*m,65PN"2i!!!!F"&S!$8*
+14%`!!!"b4P*&4J!#!(jTBf`d!!d!SQPME$J!$J&+5801)`!0!IjTBh-M!!8#TQP
+MFc3!"3,ZD@0c1!!&!cC@58dK!!!$IN&-8P3!!!1+4%P86!!&!jC%6%p(!!8$hQ&
+XDA-!!!3Q4e@h53!!"$)!J2rr!!!!!!!!!!!!J2rr!!!!-!!!!!!!JIrr!!!!1`!
+!!!!!J[rr!!!!4J!!!!!%DIrr!!!!83!!!!!%D2rr!!!#93!!!!!!J2rr!!!%@3!
+!!!!!JIrr!!!'A3!!!!!!J[rr!!!Ph!!!!!!!Jrrr!!!YX!!!!!!!KIrr!!!mU`!
+!!!!!K[rr!!"!Y`!!!!!!Krrr!!"#Z`!!!!!!L2rr!!"&``!!!!!!LIrr!!"*c`Y
+0*f3!L[rr!!"Ij`Y0*ZJ!Lrrr!!"Mm`Y0)q3!M2rr!!"Pp`Y0*c`%DIrr!!!)B3Y
+0*q!%D2rr!!!-C3Y0*m!!J2rr!!!3D3Y0*m`!JIrr!!!8E3Y0*lJ!J[rr!!!`I!Y
+0*mJ!Jrrr!!!SU!Y0*m3!K2rr!!!dJ!Y0*l`!KIrr!!",d`Y0)$!!KJ!d!!"2e`Y
+0*l!!K`!V!!"6f`Y0*k`!L!!p!!"Ah`Y0*kJ!LIrr!!"Ei`Y0*k3!L[rr!!"Sr`Y
+0(ZJ!Lrrr!!"Y!`Y0*d`!M2rr!!"a"`Y0(Z3%D2rr!!!BF3Y0#ZJ%DIrr!!!CG3Y
+0+!J!J2rr!!!DH3Y0+"3!JIrr!!!EI3Y0+$`!J[rr!!!Nf!Y0+!`!Jrrr!!!XV!Y
+0+"!!KIrr!!!qV`!!!!!!K[rr!!!rX`Y0+4J!Krrr!!"%[`Y0+"J!L2rr!!"(a`Y
+0+!3!LIrr!!")b`Y0*hJ!L[rr!!"Kk`Y0*Z!!Lrrr!!"Ll`Y0)r3!M2rr!!"Rq`Y
+0*#`%D2rr!!!FJ3Y0+#3%DIrr!!!Fa3Y0+#`!J2rr!!!G#3Y0+'3!JIrr!!!G63Y
+0+#!!J[rr!!!Ri!Y-+X3!Jrrr!!!`1!Y0+$!%D2rr!!!GN3Y0)X3%DIrr!!!H&3Y
+0(P`!J2rr!!!HQ3Y0*!3!JIrr!!!I(3Y0*`3!J[rr!!!S*!Y0(Q`!Jrrr!!![Y!Y
+0(P!%D2rr!!!IS3Y0)P`%DIrr!!!JT3Y0)P!!J2rr!!!KU3Y0)Q!!JIrr!!!LV3Y
+0(i!!J[rr!!!iK!Y0)P3!Jrrr!!!jL!Y0)Q3!!!!!!!!MX3!!!!!!J2rr!!!Mc`!
+!!!!!J2rr!!!Mh`!!!!!!JIrr!!!N"3!!!!!!J[rr!!!N#`!!!!!!Jrrr!!!N*3!
+!!!!!K2rr!!!N1`!!!!!!KIrr!!!kM!!!!!!!J2rr!!!N@`!!!!!!J3!2!!!NG!!
+!!!!!JJ!8!!!NM3!!!!!!J`!F!!!NTJ!!!!!!K!!K!!!N[`!!!!!!K3!Q!!!lNJ!
+!!!!!jIrr!!!lU`!!!!!S!Irr!!!mP`!!!!!16hGZCA)JFQ9cEh9bBf8%6@&TEJG
+#GA4dEfjc"%PMEfi%9'9iG!4'D@jN#(4LAf0XEh0P#(4LAf*XB@jV"h4LAf0[F(R
+VL!:
+
diff --git a/src/os_mac_conv.c b/src/os_mac_conv.c
new file mode 100644
index 0000000..2bd337e
--- /dev/null
+++ b/src/os_mac_conv.c
@@ -0,0 +1,586 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+/*
+ * os_mac_conv.c: Code specifically for Mac string conversions.
+ *
+ * This code has been put in a separate file to avoid the conflicts that are
+ * caused by including both the X11 and Carbon header files.
+ */
+
+#define NO_X11_INCLUDES
+
+#include "vim.h"
+
+#if !defined(FEAT_GUI_MAC) && !defined(PROTO)
+# include <CoreServices/CoreServices.h>
+#endif
+
+
+#if defined(MACOS_CONVERT) || defined(PROTO)
+
+# ifdef PROTO
+/* A few dummy types to be able to generate function prototypes. */
+typedef int UniChar;
+typedef int *TECObjectRef;
+typedef int CFStringRef;
+# endif
+
+static char_u *mac_utf16_to_utf8(UniChar *from, size_t fromLen, size_t *actualLen);
+static UniChar *mac_utf8_to_utf16(char_u *from, size_t fromLen, size_t *actualLen);
+
+/* Converter for composing decomposed HFS+ file paths */
+static TECObjectRef gPathConverter;
+/* Converter used by mac_utf16_to_utf8 */
+static TECObjectRef gUTF16ToUTF8Converter;
+
+/*
+ * A Mac version of string_convert_ext() for special cases.
+ */
+ char_u *
+mac_string_convert(
+ char_u *ptr,
+ int len,
+ int *lenp,
+ int fail_on_error,
+ int from_enc,
+ int to_enc,
+ int *unconvlenp)
+{
+ char_u *retval, *d;
+ CFStringRef cfstr;
+ int buflen, in, out, l, i;
+ CFStringEncoding from;
+ CFStringEncoding to;
+
+ switch (from_enc)
+ {
+ case 'l': from = kCFStringEncodingISOLatin1; break;
+ case 'm': from = kCFStringEncodingMacRoman; break;
+ case 'u': from = kCFStringEncodingUTF8; break;
+ default: return NULL;
+ }
+ switch (to_enc)
+ {
+ case 'l': to = kCFStringEncodingISOLatin1; break;
+ case 'm': to = kCFStringEncodingMacRoman; break;
+ case 'u': to = kCFStringEncodingUTF8; break;
+ default: return NULL;
+ }
+
+ if (unconvlenp != NULL)
+ *unconvlenp = 0;
+ cfstr = CFStringCreateWithBytes(NULL, ptr, len, from, 0);
+
+ if (cfstr == NULL)
+ fprintf(stderr, "Encoding failed\n");
+ /* When conversion failed, try excluding bytes from the end, helps when
+ * there is an incomplete byte sequence. Only do up to 6 bytes to avoid
+ * looping a long time when there really is something unconvertible. */
+ while (cfstr == NULL && unconvlenp != NULL && len > 1 && *unconvlenp < 6)
+ {
+ --len;
+ ++*unconvlenp;
+ cfstr = CFStringCreateWithBytes(NULL, ptr, len, from, 0);
+ }
+ if (cfstr == NULL)
+ return NULL;
+
+ if (to == kCFStringEncodingUTF8)
+ buflen = len * 6 + 1;
+ else
+ buflen = len + 1;
+ retval = alloc(buflen);
+ if (retval == NULL)
+ {
+ CFRelease(cfstr);
+ return NULL;
+ }
+
+#if 0
+ CFRange convertRange = CFRangeMake(0, CFStringGetLength(cfstr));
+ /* Determine output buffer size */
+ CFStringGetBytes(cfstr, convertRange, to, NULL, FALSE, NULL, 0, (CFIndex *)&buflen);
+ retval = (buflen > 0) ? alloc(buflen) : NULL;
+ if (retval == NULL) {
+ CFRelease(cfstr);
+ return NULL;
+ }
+
+ if (lenp)
+ *lenp = buflen / sizeof(char_u);
+
+ if (!CFStringGetBytes(cfstr, convertRange, to, NULL, FALSE, retval, buflen, NULL))
+#endif
+ if (!CFStringGetCString(cfstr, (char *)retval, buflen, to))
+ {
+ CFRelease(cfstr);
+ if (fail_on_error)
+ {
+ vim_free(retval);
+ return NULL;
+ }
+
+ fprintf(stderr, "Trying char-by-char conversion...\n");
+ /* conversion failed for the whole string, but maybe it will work
+ * for each character */
+ for (d = retval, in = 0, out = 0; in < len && out < buflen - 1;)
+ {
+ if (from == kCFStringEncodingUTF8)
+ l = utf_ptr2len(ptr + in);
+ else
+ l = 1;
+ cfstr = CFStringCreateWithBytes(NULL, ptr + in, l, from, 0);
+ if (cfstr == NULL)
+ {
+ *d++ = '?';
+ out++;
+ }
+ else
+ {
+ if (!CFStringGetCString(cfstr, (char *)d, buflen - out, to))
+ {
+ *d++ = '?';
+ out++;
+ }
+ else
+ {
+ i = STRLEN(d);
+ d += i;
+ out += i;
+ }
+ CFRelease(cfstr);
+ }
+ in += l;
+ }
+ *d = NUL;
+ if (lenp != NULL)
+ *lenp = out;
+ return retval;
+ }
+ CFRelease(cfstr);
+ if (lenp != NULL)
+ *lenp = STRLEN(retval);
+
+ return retval;
+}
+
+/*
+ * Conversion from Apple MacRoman char encoding to UTF-8 or latin1, using
+ * standard Carbon framework.
+ * Input: "ptr[*sizep]".
+ * "real_size" is the size of the buffer that "ptr" points to.
+ * output is in-place, "sizep" is adjusted.
+ * Returns OK or FAIL.
+ */
+ int
+macroman2enc(
+ char_u *ptr,
+ long *sizep,
+ long real_size)
+{
+ CFStringRef cfstr;
+ CFRange r;
+ CFIndex len = *sizep;
+
+ /* MacRoman is an 8-bit encoding, no need to move bytes to
+ * conv_rest[]. */
+ cfstr = CFStringCreateWithBytes(NULL, ptr, len,
+ kCFStringEncodingMacRoman, 0);
+ /*
+ * If there is a conversion error, try using another
+ * conversion.
+ */
+ if (cfstr == NULL)
+ return FAIL;
+
+ r.location = 0;
+ r.length = CFStringGetLength(cfstr);
+ if (r.length != CFStringGetBytes(cfstr, r,
+ (enc_utf8) ? kCFStringEncodingUTF8 : kCFStringEncodingISOLatin1,
+ 0, /* no lossy conversion */
+ 0, /* not external representation */
+ ptr + *sizep, real_size - *sizep, &len))
+ {
+ CFRelease(cfstr);
+ return FAIL;
+ }
+ CFRelease(cfstr);
+ mch_memmove(ptr, ptr + *sizep, len);
+ *sizep = len;
+
+ return OK;
+}
+
+/*
+ * Conversion from UTF-8 or latin1 to MacRoman.
+ * Input: "from[fromlen]"
+ * Output: "to[maxtolen]" length in "*tolenp"
+ * Unconverted rest in rest[*restlenp].
+ * Returns OK or FAIL.
+ */
+ int
+enc2macroman(
+ char_u *from,
+ size_t fromlen,
+ char_u *to,
+ int *tolenp,
+ int maxtolen,
+ char_u *rest,
+ int *restlenp)
+{
+ CFStringRef cfstr;
+ CFRange r;
+ CFIndex l;
+
+ *restlenp = 0;
+ cfstr = CFStringCreateWithBytes(NULL, from, fromlen,
+ (enc_utf8) ? kCFStringEncodingUTF8 : kCFStringEncodingISOLatin1,
+ 0);
+ while (cfstr == NULL && *restlenp < 3 && fromlen > 1)
+ {
+ rest[*restlenp++] = from[--fromlen];
+ cfstr = CFStringCreateWithBytes(NULL, from, fromlen,
+ (enc_utf8) ? kCFStringEncodingUTF8 : kCFStringEncodingISOLatin1,
+ 0);
+ }
+ if (cfstr == NULL)
+ return FAIL;
+
+ r.location = 0;
+ r.length = CFStringGetLength(cfstr);
+ if (r.length != CFStringGetBytes(cfstr, r,
+ kCFStringEncodingMacRoman,
+ 0, /* no lossy conversion */
+ 0, /* not external representation (since vim
+ * handles this internally */
+ to, maxtolen, &l))
+ {
+ CFRelease(cfstr);
+ return FAIL;
+ }
+ CFRelease(cfstr);
+ *tolenp = l;
+ return OK;
+}
+
+/*
+ * Initializes text converters
+ */
+ void
+mac_conv_init(void)
+{
+ TextEncoding utf8_encoding;
+ TextEncoding utf8_hfsplus_encoding;
+ TextEncoding utf8_canon_encoding;
+ TextEncoding utf16_encoding;
+
+ utf8_encoding = CreateTextEncoding(kTextEncodingUnicodeDefault,
+ kTextEncodingDefaultVariant, kUnicodeUTF8Format);
+ utf8_hfsplus_encoding = CreateTextEncoding(kTextEncodingUnicodeDefault,
+ kUnicodeHFSPlusCompVariant, kUnicodeUTF8Format);
+ utf8_canon_encoding = CreateTextEncoding(kTextEncodingUnicodeDefault,
+ kUnicodeCanonicalCompVariant, kUnicodeUTF8Format);
+ utf16_encoding = CreateTextEncoding(kTextEncodingUnicodeDefault,
+ kTextEncodingDefaultVariant, kUnicode16BitFormat);
+
+ if (TECCreateConverter(&gPathConverter, utf8_encoding,
+ utf8_hfsplus_encoding) != noErr)
+ gPathConverter = NULL;
+
+ if (TECCreateConverter(&gUTF16ToUTF8Converter, utf16_encoding,
+ utf8_canon_encoding) != noErr)
+ {
+ /* On pre-10.3, Unicode normalization is not available so
+ * fall back to non-normalizing converter */
+ if (TECCreateConverter(&gUTF16ToUTF8Converter, utf16_encoding,
+ utf8_encoding) != noErr)
+ gUTF16ToUTF8Converter = NULL;
+ }
+}
+
+/*
+ * Destroys text converters
+ */
+ void
+mac_conv_cleanup(void)
+{
+ if (gUTF16ToUTF8Converter)
+ {
+ TECDisposeConverter(gUTF16ToUTF8Converter);
+ gUTF16ToUTF8Converter = NULL;
+ }
+
+ if (gPathConverter)
+ {
+ TECDisposeConverter(gPathConverter);
+ gPathConverter = NULL;
+ }
+}
+
+/*
+ * Conversion from UTF-16 UniChars to 'encoding'
+ * The function signature uses the real type of UniChar (as typedef'ed in
+ * CFBase.h) to avoid clashes with X11 header files in the .pro file
+ */
+ char_u *
+mac_utf16_to_enc(
+ unsigned short *from,
+ size_t fromLen,
+ size_t *actualLen)
+{
+ /* Following code borrows somewhat from os_mswin.c */
+ vimconv_T conv;
+ size_t utf8_len;
+ char_u *utf8_str;
+ char_u *result = NULL;
+
+ /* Convert to utf-8 first, works better with iconv */
+ utf8_len = 0;
+ utf8_str = mac_utf16_to_utf8(from, fromLen, &utf8_len);
+
+ if (utf8_str)
+ {
+ /* We might be called before we have p_enc set up. */
+ conv.vc_type = CONV_NONE;
+
+ /* If encoding (p_enc) is any unicode, it is actually in utf-8 (vim
+ * internal unicode is always utf-8) so don't convert in such cases */
+
+ if ((enc_canon_props(p_enc) & ENC_UNICODE) == 0)
+ convert_setup(&conv, (char_u *)"utf-8",
+ p_enc? p_enc: (char_u *)"macroman");
+ if (conv.vc_type == CONV_NONE)
+ {
+ /* p_enc is utf-8, so we're done. */
+ result = utf8_str;
+ }
+ else
+ {
+ result = string_convert(&conv, utf8_str, (int *)&utf8_len);
+ vim_free(utf8_str);
+ }
+
+ convert_setup(&conv, NULL, NULL);
+
+ if (actualLen)
+ *actualLen = utf8_len;
+ }
+ else if (actualLen)
+ *actualLen = 0;
+
+ return result;
+}
+
+/*
+ * Conversion from 'encoding' to UTF-16 UniChars
+ * The function return uses the real type of UniChar (as typedef'ed in
+ * CFBase.h) to avoid clashes with X11 header files in the .pro file
+ */
+ unsigned short *
+mac_enc_to_utf16(
+ char_u *from,
+ size_t fromLen,
+ size_t *actualLen)
+{
+ /* Following code borrows somewhat from os_mswin.c */
+ vimconv_T conv;
+ size_t utf8_len;
+ char_u *utf8_str;
+ UniChar *result = NULL;
+ Boolean should_free_utf8 = FALSE;
+
+ do
+ {
+ /* Use MacRoman by default, we might be called before we have p_enc
+ * set up. Convert to utf-8 first, works better with iconv(). Does
+ * nothing if 'encoding' is "utf-8". */
+ conv.vc_type = CONV_NONE;
+ if ((enc_canon_props(p_enc) & ENC_UNICODE) == 0 &&
+ convert_setup(&conv, p_enc ? p_enc : (char_u *)"macroman",
+ (char_u *)"utf-8") == FAIL)
+ break;
+
+ if (conv.vc_type != CONV_NONE)
+ {
+ utf8_len = fromLen;
+ utf8_str = string_convert(&conv, from, (int *)&utf8_len);
+ should_free_utf8 = TRUE;
+ }
+ else
+ {
+ utf8_str = from;
+ utf8_len = fromLen;
+ }
+
+ if (utf8_str == NULL)
+ break;
+
+ convert_setup(&conv, NULL, NULL);
+
+ result = mac_utf8_to_utf16(utf8_str, utf8_len, actualLen);
+
+ if (should_free_utf8)
+ vim_free(utf8_str);
+ return result;
+ }
+ while (0);
+
+ if (actualLen)
+ *actualLen = 0;
+
+ return result;
+}
+
+/*
+ * Converts from UTF-16 UniChars to CFString
+ * The void * return type is actually a CFStringRef
+ */
+ void *
+mac_enc_to_cfstring(
+ char_u *from,
+ size_t fromLen)
+{
+ UniChar *utf16_str;
+ size_t utf16_len;
+ CFStringRef result = NULL;
+
+ utf16_str = mac_enc_to_utf16(from, fromLen, &utf16_len);
+ if (utf16_str)
+ {
+ result = CFStringCreateWithCharacters(NULL, utf16_str, utf16_len/sizeof(UniChar));
+ vim_free(utf16_str);
+ }
+
+ return (void *)result;
+}
+
+/*
+ * Converts a decomposed HFS+ UTF-8 path to precomposed UTF-8
+ */
+ char_u *
+mac_precompose_path(
+ char_u *decompPath,
+ size_t decompLen,
+ size_t *precompLen)
+{
+ char_u *result = NULL;
+ size_t actualLen = 0;
+
+ if (gPathConverter)
+ {
+ result = alloc(decompLen);
+ if (result)
+ {
+ if (TECConvertText(gPathConverter, decompPath,
+ decompLen, &decompLen, result,
+ decompLen, &actualLen) != noErr)
+ VIM_CLEAR(result);
+ }
+ }
+
+ if (precompLen)
+ *precompLen = actualLen;
+
+ return result;
+}
+
+/*
+ * Converts from UTF-16 UniChars to precomposed UTF-8
+ */
+ static char_u *
+mac_utf16_to_utf8(
+ UniChar *from,
+ size_t fromLen,
+ size_t *actualLen)
+{
+ ByteCount utf8_len;
+ ByteCount inputRead;
+ char_u *result;
+
+ if (gUTF16ToUTF8Converter)
+ {
+ result = alloc(fromLen * 6 + 1);
+ if (result && TECConvertText(gUTF16ToUTF8Converter, (ConstTextPtr)from,
+ fromLen, &inputRead, result,
+ (fromLen*6+1)*sizeof(char_u), &utf8_len) == noErr)
+ {
+ TECFlushText(gUTF16ToUTF8Converter, result, (fromLen*6+1)*sizeof(char_u), &inputRead);
+ utf8_len += inputRead;
+ }
+ else
+ VIM_CLEAR(result);
+ }
+ else
+ {
+ result = NULL;
+ }
+
+ if (actualLen)
+ *actualLen = result ? utf8_len : 0;
+
+ return result;
+}
+
+/*
+ * Converts from UTF-8 to UTF-16 UniChars
+ */
+ static UniChar *
+mac_utf8_to_utf16(
+ char_u *from,
+ size_t fromLen,
+ size_t *actualLen)
+{
+ CFStringRef utf8_str;
+ CFRange convertRange;
+ UniChar *result = NULL;
+
+ utf8_str = CFStringCreateWithBytes(NULL, from, fromLen,
+ kCFStringEncodingUTF8, FALSE);
+
+ if (utf8_str == NULL) {
+ if (actualLen)
+ *actualLen = 0;
+ return NULL;
+ }
+
+ convertRange = CFRangeMake(0, CFStringGetLength(utf8_str));
+ result = (UniChar *)alloc(convertRange.length * sizeof(UniChar));
+
+ CFStringGetCharacters(utf8_str, convertRange, result);
+
+ CFRelease(utf8_str);
+
+ if (actualLen)
+ *actualLen = convertRange.length * sizeof(UniChar);
+
+ return result;
+}
+
+/*
+ * Sets LANG environment variable in Vim from Mac locale
+ */
+ void
+mac_lang_init(void)
+{
+ if (mch_getenv((char_u *)"LANG") == NULL)
+ {
+ char buf[20];
+ if (LocaleRefGetPartString(NULL,
+ kLocaleLanguageMask | kLocaleLanguageVariantMask |
+ kLocaleRegionMask | kLocaleRegionVariantMask,
+ sizeof buf, buf) == noErr && *buf)
+ {
+ vim_setenv((char_u *)"LANG", (char_u *)buf);
+# ifdef HAVE_LOCALE_H
+ setlocale(LC_ALL, "");
+# endif
+ }
+ }
+}
+#endif /* MACOS_CONVERT */
diff --git a/src/os_mac_rsrc/app.icns b/src/os_mac_rsrc/app.icns
new file mode 100644
index 0000000..1442611
--- /dev/null
+++ b/src/os_mac_rsrc/app.icns
Binary files differ
diff --git a/src/os_mac_rsrc/doc-txt.icns b/src/os_mac_rsrc/doc-txt.icns
new file mode 100644
index 0000000..2219e2c
--- /dev/null
+++ b/src/os_mac_rsrc/doc-txt.icns
Binary files differ
diff --git a/src/os_mac_rsrc/doc.icns b/src/os_mac_rsrc/doc.icns
new file mode 100644
index 0000000..984d11d
--- /dev/null
+++ b/src/os_mac_rsrc/doc.icns
Binary files differ
diff --git a/src/os_macosx.m b/src/os_macosx.m
new file mode 100644
index 0000000..3b5c35a
--- /dev/null
+++ b/src/os_macosx.m
@@ -0,0 +1,218 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * os_macosx.m -- Mac specific things for Mac OS X.
+ */
+
+/* Suppress compiler warnings to non-C89 code. */
+#if defined(__clang__) && defined(__STRICT_ANSI__)
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wc99-extensions"
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wdeclaration-after-statement"
+#endif
+
+/* Avoid a conflict for the definition of Boolean between Mac header files and
+ * X11 header files. */
+#define NO_X11_INCLUDES
+
+#include "vim.h"
+#import <AppKit/AppKit.h>
+
+
+/*
+ * Clipboard support for the console.
+ * Don't include this when building the GUI version, the functions in
+ * 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))
+
+/* Used to identify clipboard data copied from Vim. */
+
+NSString *VimPboardType = @"VimPboardType";
+
+ void
+clip_mch_lose_selection(VimClipboard *cbd UNUSED)
+{
+}
+
+
+ int
+clip_mch_own_selection(VimClipboard *cbd UNUSED)
+{
+ /* This is called whenever there is a new selection and 'guioptions'
+ * contains the "a" flag (automatically copy selection). Return TRUE, else
+ * the "a" flag does nothing. Note that there is no concept of "ownership"
+ * of the clipboard in Mac OS X.
+ */
+ return TRUE;
+}
+
+
+ void
+clip_mch_request_selection(VimClipboard *cbd)
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ NSPasteboard *pb = [NSPasteboard generalPasteboard];
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
+ NSArray *supportedTypes = [NSArray arrayWithObjects:VimPboardType,
+ NSPasteboardTypeString, nil];
+#else
+ NSArray *supportedTypes = [NSArray arrayWithObjects:VimPboardType,
+ NSStringPboardType, nil];
+#endif
+ NSString *bestType = [pb availableTypeFromArray:supportedTypes];
+ if (!bestType) goto releasepool;
+
+ int motion_type = MAUTO;
+ NSString *string = nil;
+
+ if ([bestType isEqual:VimPboardType])
+ {
+ /* This type should consist of an array with two objects:
+ * 1. motion type (NSNumber)
+ * 2. text (NSString)
+ * If this is not the case we fall back on using NSPasteboardTypeString.
+ */
+ id plist = [pb propertyListForType:VimPboardType];
+ if ([plist isKindOfClass:[NSArray class]] && [plist count] == 2)
+ {
+ id obj = [plist objectAtIndex:1];
+ if ([obj isKindOfClass:[NSString class]])
+ {
+ motion_type = [[plist objectAtIndex:0] intValue];
+ string = obj;
+ }
+ }
+ }
+
+ if (!string)
+ {
+ /* Use NSPasteboardTypeString. The motion type is detected automatically.
+ */
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
+ NSMutableString *mstring =
+ [[pb stringForType:NSPasteboardTypeString] mutableCopy];
+#else
+ NSMutableString *mstring =
+ [[pb stringForType:NSStringPboardType] mutableCopy];
+#endif
+ if (!mstring) goto releasepool;
+
+ /* Replace unrecognized end-of-line sequences with \x0a (line feed). */
+ NSRange range = { 0, [mstring length] };
+ unsigned n = [mstring replaceOccurrencesOfString:@"\x0d\x0a"
+ withString:@"\x0a" options:0
+ range:range];
+ if (0 == n)
+ {
+ n = [mstring replaceOccurrencesOfString:@"\x0d" withString:@"\x0a"
+ options:0 range:range];
+ }
+
+ string = mstring;
+ }
+
+ /* Default to MAUTO, uses MCHAR or MLINE depending on trailing NL. */
+ if (!(MCHAR == motion_type || MLINE == motion_type || MBLOCK == motion_type
+ || MAUTO == motion_type))
+ motion_type = MAUTO;
+
+ char_u *str = (char_u*)[string UTF8String];
+ int len = [string lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
+
+ if (input_conv.vc_type != CONV_NONE)
+ str = string_convert(&input_conv, str, &len);
+
+ if (str)
+ clip_yank_selection(motion_type, str, len, cbd);
+
+ if (input_conv.vc_type != CONV_NONE)
+ vim_free(str);
+
+releasepool:
+ [pool release];
+}
+
+
+/*
+ * Send the current selection to the clipboard.
+ */
+ void
+clip_mch_set_selection(VimClipboard *cbd)
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ /* If the '*' register isn't already filled in, fill it in now. */
+ cbd->owned = TRUE;
+ clip_get_selection(cbd);
+ cbd->owned = FALSE;
+
+ /* Get the text to put on the pasteboard. */
+ long_u llen = 0; char_u *str = 0;
+ int motion_type = clip_convert_selection(&str, &llen, cbd);
+ if (motion_type < 0)
+ goto releasepool;
+
+ /* TODO: Avoid overflow. */
+ int len = (int)llen;
+ if (output_conv.vc_type != CONV_NONE)
+ {
+ char_u *conv_str = string_convert(&output_conv, str, &len);
+ if (conv_str)
+ {
+ vim_free(str);
+ str = conv_str;
+ }
+ }
+
+ if (len > 0)
+ {
+ NSString *string = [[NSString alloc]
+ initWithBytes:str length:len encoding:NSUTF8StringEncoding];
+
+ /* See clip_mch_request_selection() for info on pasteboard types. */
+ NSPasteboard *pb = [NSPasteboard generalPasteboard];
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
+ NSArray *supportedTypes = [NSArray arrayWithObjects:VimPboardType,
+ NSPasteboardTypeString, nil];
+#else
+ NSArray *supportedTypes = [NSArray arrayWithObjects:VimPboardType,
+ NSStringPboardType, nil];
+#endif
+ [pb declareTypes:supportedTypes owner:nil];
+
+ NSNumber *motion = [NSNumber numberWithInt:motion_type];
+ NSArray *plist = [NSArray arrayWithObjects:motion, string, nil];
+ [pb setPropertyList:plist forType:VimPboardType];
+
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
+ [pb setString:string forType:NSPasteboardTypeString];
+#else
+ [pb setString:string forType:NSStringPboardType];
+#endif
+
+ [string release];
+ }
+
+ vim_free(str);
+releasepool:
+ [pool release];
+}
+
+#endif /* FEAT_CLIPBOARD */
+
+/* Lift the compiler warning suppression. */
+#if defined(__clang__) && defined(__STRICT_ANSI__)
+# pragma clang diagnostic pop
+# pragma clang diagnostic pop
+#endif
diff --git a/src/os_mint.h b/src/os_mint.h
new file mode 100644
index 0000000..18bd78b
--- /dev/null
+++ b/src/os_mint.h
@@ -0,0 +1,13 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * Do ":help uganda" in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ */
+
+/*
+ * Atari MiNT Machine-dependent things.
+ */
+
+#define BINARY_FILE_IO
diff --git a/src/os_mswin.c b/src/os_mswin.c
new file mode 100644
index 0000000..363dc46
--- /dev/null
+++ b/src/os_mswin.c
@@ -0,0 +1,3088 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * os_mswin.c
+ *
+ * Routines for Win32.
+ */
+
+#include "vim.h"
+
+#include <sys/types.h>
+#include <signal.h>
+#include <limits.h>
+#ifndef PROTO
+# include <process.h>
+#endif
+
+#undef chdir
+#ifdef __GNUC__
+# ifndef __MINGW32__
+# include <dirent.h>
+# endif
+#else
+# include <direct.h>
+#endif
+
+#ifndef PROTO
+# if defined(FEAT_TITLE) && !defined(FEAT_GUI_W32)
+# include <shellapi.h>
+# endif
+
+# if defined(FEAT_PRINTER) && !defined(FEAT_POSTSCRIPT)
+# include <dlgs.h>
+# include <winspool.h>
+# include <commdlg.h>
+# endif
+
+#endif /* PROTO */
+
+#ifdef __MINGW32__
+# ifndef FROM_LEFT_1ST_BUTTON_PRESSED
+# define FROM_LEFT_1ST_BUTTON_PRESSED 0x0001
+# endif
+# ifndef RIGHTMOST_BUTTON_PRESSED
+# define RIGHTMOST_BUTTON_PRESSED 0x0002
+# endif
+# ifndef FROM_LEFT_2ND_BUTTON_PRESSED
+# define FROM_LEFT_2ND_BUTTON_PRESSED 0x0004
+# endif
+# ifndef FROM_LEFT_3RD_BUTTON_PRESSED
+# define FROM_LEFT_3RD_BUTTON_PRESSED 0x0008
+# endif
+# ifndef FROM_LEFT_4TH_BUTTON_PRESSED
+# define FROM_LEFT_4TH_BUTTON_PRESSED 0x0010
+# endif
+
+/*
+ * EventFlags
+ */
+# ifndef MOUSE_MOVED
+# define MOUSE_MOVED 0x0001
+# endif
+# ifndef DOUBLE_CLICK
+# define DOUBLE_CLICK 0x0002
+# endif
+#endif
+
+/*
+ * When generating prototypes for Win32 on Unix, these lines make the syntax
+ * errors disappear. They do not need to be correct.
+ */
+#ifdef PROTO
+#define WINAPI
+#define WINBASEAPI
+typedef int BOOL;
+typedef int CALLBACK;
+typedef int COLORREF;
+typedef int CONSOLE_CURSOR_INFO;
+typedef int COORD;
+typedef int DWORD;
+typedef int ENUMLOGFONT;
+typedef int HANDLE;
+typedef int HDC;
+typedef int HFONT;
+typedef int HICON;
+typedef int HWND;
+typedef int INPUT_RECORD;
+typedef int KEY_EVENT_RECORD;
+typedef int LOGFONT;
+typedef int LPARAM;
+typedef int LPBOOL;
+typedef int LPCSTR;
+typedef int LPCWSTR;
+typedef int LPSTR;
+typedef int LPTSTR;
+typedef int LPWSTR;
+typedef int LRESULT;
+typedef int MOUSE_EVENT_RECORD;
+typedef int NEWTEXTMETRIC;
+typedef int PACL;
+typedef int PRINTDLG;
+typedef int PSECURITY_DESCRIPTOR;
+typedef int PSID;
+typedef int SECURITY_INFORMATION;
+typedef int SHORT;
+typedef int SMALL_RECT;
+typedef int TEXTMETRIC;
+typedef int UINT;
+typedef int WCHAR;
+typedef int WNDENUMPROC;
+typedef int WORD;
+typedef int WPARAM;
+typedef void VOID;
+#endif
+
+/* Record all output and all keyboard & mouse input */
+/* #define MCH_WRITE_DUMP */
+
+#ifdef MCH_WRITE_DUMP
+FILE* fdDump = NULL;
+#endif
+
+#ifndef FEAT_GUI_MSWIN
+extern char g_szOrigTitle[];
+#endif
+
+#ifdef FEAT_GUI
+extern HWND s_hwnd;
+#else
+static HWND s_hwnd = 0; /* console window handle, set by GetConsoleHwnd() */
+#endif
+
+#ifdef FEAT_JOB_CHANNEL
+int WSInitialized = FALSE; /* WinSock is initialized */
+#endif
+
+/* Don't generate prototypes here, because some systems do have these
+ * functions. */
+#if defined(__GNUC__) && !defined(PROTO)
+# ifndef __MINGW32__
+int _stricoll(char *a, char *b)
+{
+ // the ANSI-ish correct way is to use strxfrm():
+ char a_buff[512], b_buff[512]; // file names, so this is enough on Win32
+ strxfrm(a_buff, a, 512);
+ strxfrm(b_buff, b, 512);
+ return strcoll(a_buff, b_buff);
+}
+
+char * _fullpath(char *buf, char *fname, int len)
+{
+ LPTSTR toss;
+
+ return (char *)GetFullPathName(fname, len, buf, &toss);
+}
+# endif
+
+# if !defined(__MINGW32__) || (__GNUC__ < 4)
+int _chdrive(int drive)
+{
+ char temp [3] = "-:";
+ temp[0] = drive + 'A' - 1;
+ return !SetCurrentDirectory(temp);
+}
+# endif
+#else
+# ifdef __BORLANDC__
+/* being a more ANSI compliant compiler, BorlandC doesn't define _stricoll:
+ * but it does in BC 5.02! */
+# if __BORLANDC__ < 0x502
+int _stricoll(char *a, char *b)
+{
+# if 1
+ // this is fast but not correct:
+ return stricmp(a, b);
+# else
+ // the ANSI-ish correct way is to use strxfrm():
+ char a_buff[512], b_buff[512]; // file names, so this is enough on Win32
+ strxfrm(a_buff, a, 512);
+ strxfrm(b_buff, b, 512);
+ return strcoll(a_buff, b_buff);
+# endif
+}
+# endif
+# endif
+#endif
+
+
+#if defined(FEAT_GUI_MSWIN) || defined(PROTO)
+/*
+ * GUI version of mch_exit().
+ * Shut down and exit with status `r'
+ * Careful: mch_exit() may be called before mch_init()!
+ */
+ void
+mch_exit(int r)
+{
+ exiting = TRUE;
+
+ display_errors();
+
+ ml_close_all(TRUE); /* remove all memfiles */
+
+# ifdef FEAT_OLE
+ UninitOLE();
+# endif
+# ifdef FEAT_JOB_CHANNEL
+ if (WSInitialized)
+ {
+ WSInitialized = FALSE;
+ WSACleanup();
+ }
+# endif
+#ifdef DYNAMIC_GETTEXT
+ dyn_libintl_end();
+#endif
+
+ if (gui.in_use)
+ gui_exit(r);
+
+#ifdef EXITFREE
+ free_all_mem();
+#endif
+
+ exit(r);
+}
+
+#endif /* FEAT_GUI_MSWIN */
+
+
+/*
+ * Init the tables for toupper() and tolower().
+ */
+ void
+mch_early_init(void)
+{
+ int i;
+
+ PlatformId();
+
+ /* Init the tables for toupper() and tolower() */
+ for (i = 0; i < 256; ++i)
+ toupper_tab[i] = tolower_tab[i] = i;
+ CharUpperBuff((LPSTR)toupper_tab, 256);
+ CharLowerBuff((LPSTR)tolower_tab, 256);
+}
+
+
+/*
+ * Return TRUE if the input comes from a terminal, FALSE otherwise.
+ */
+ int
+mch_input_isatty(void)
+{
+#ifdef FEAT_GUI_MSWIN
+ return OK; /* GUI always has a tty */
+#else
+ if (isatty(read_cmd_fd))
+ return TRUE;
+ return FALSE;
+#endif
+}
+
+#ifdef FEAT_TITLE
+/*
+ * mch_settitle(): set titlebar of our window
+ */
+ void
+mch_settitle(
+ char_u *title,
+ char_u *icon)
+{
+# ifdef FEAT_GUI_MSWIN
+ gui_mch_settitle(title, icon);
+# else
+ if (title != NULL)
+ {
+ if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+ {
+ /* Convert the title from 'encoding' to the active codepage. */
+ WCHAR *wp = enc_to_utf16(title, NULL);
+
+ if (wp != NULL)
+ {
+ SetConsoleTitleW(wp);
+ vim_free(wp);
+ return;
+ }
+ }
+ SetConsoleTitle((LPCSTR)title);
+ }
+# endif
+}
+
+
+/*
+ * Restore the window/icon title.
+ * which is one of:
+ * SAVE_RESTORE_TITLE: Just restore title
+ * SAVE_RESTORE_ICON: Just restore icon (which we don't have)
+ * SAVE_RESTORE_BOTH: Restore title and icon (which we don't have)
+ */
+ void
+mch_restore_title(int which UNUSED)
+{
+#ifndef FEAT_GUI_MSWIN
+ SetConsoleTitle(g_szOrigTitle);
+#endif
+}
+
+
+/*
+ * Return TRUE if we can restore the title (we can)
+ */
+ int
+mch_can_restore_title(void)
+{
+ return TRUE;
+}
+
+
+/*
+ * Return TRUE if we can restore the icon title (we can't)
+ */
+ int
+mch_can_restore_icon(void)
+{
+ return FALSE;
+}
+#endif /* FEAT_TITLE */
+
+
+/*
+ * Get absolute file name into buffer "buf" of length "len" bytes,
+ * turning all '/'s into '\\'s and getting the correct case of each component
+ * of the file name. Append a (back)slash to a directory name.
+ * When 'shellslash' set do it the other way around.
+ * Return OK or FAIL.
+ */
+ int
+mch_FullName(
+ char_u *fname,
+ char_u *buf,
+ int len,
+ int force UNUSED)
+{
+ int nResult = FAIL;
+
+#ifdef __BORLANDC__
+ if (*fname == NUL) /* Borland behaves badly here - make it consistent */
+ nResult = mch_dirname(buf, len);
+ else
+#endif
+ {
+ if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+ {
+ WCHAR *wname;
+ WCHAR wbuf[MAX_PATH];
+ char_u *cname = NULL;
+
+ /* Use the wide function:
+ * - convert the fname from 'encoding' to UCS2.
+ * - invoke _wfullpath()
+ * - convert the result from UCS2 to 'encoding'.
+ */
+ wname = enc_to_utf16(fname, NULL);
+ if (wname != NULL && _wfullpath(wbuf, wname, MAX_PATH) != NULL)
+ {
+ cname = utf16_to_enc((short_u *)wbuf, NULL);
+ if (cname != NULL)
+ {
+ vim_strncpy(buf, cname, len - 1);
+ nResult = OK;
+ }
+ }
+ vim_free(wname);
+ vim_free(cname);
+ }
+ if (nResult == FAIL) /* fall back to non-wide function */
+ {
+ if (_fullpath((char *)buf, (const char *)fname, len - 1) == NULL)
+ {
+ /* failed, use relative path name */
+ vim_strncpy(buf, fname, len - 1);
+ }
+ else
+ nResult = OK;
+ }
+ }
+
+#ifdef USE_FNAME_CASE
+ fname_case(buf, len);
+#else
+ slash_adjust(buf);
+#endif
+
+ return nResult;
+}
+
+
+/*
+ * Return TRUE if "fname" does not depend on the current directory.
+ */
+ int
+mch_isFullName(char_u *fname)
+{
+ /* WinNT and later can use _MAX_PATH wide characters for a pathname, which
+ * means that the maximum pathname is _MAX_PATH * 3 bytes when 'enc' is
+ * UTF-8. */
+ char szName[_MAX_PATH * 3 + 1];
+
+ /* A name like "d:/foo" and "//server/share" is absolute */
+ if ((fname[0] && fname[1] == ':' && (fname[2] == '/' || fname[2] == '\\'))
+ || (fname[0] == fname[1] && (fname[0] == '/' || fname[0] == '\\')))
+ return TRUE;
+
+ /* A name that can't be made absolute probably isn't absolute. */
+ if (mch_FullName(fname, (char_u *)szName, sizeof(szName) - 1, FALSE) == FAIL)
+ return FALSE;
+
+ return pathcmp((const char *)fname, (const char *)szName, -1) == 0;
+}
+
+/*
+ * Replace all slashes by backslashes.
+ * This used to be the other way around, but MS-DOS sometimes has problems
+ * with slashes (e.g. in a command name). We can't have mixed slashes and
+ * backslashes, because comparing file names will not work correctly. The
+ * commands that use a file name should try to avoid the need to type a
+ * backslash twice.
+ * When 'shellslash' set do it the other way around.
+ * When the path looks like a URL leave it unmodified.
+ */
+ void
+slash_adjust(char_u *p)
+{
+ if (path_with_url(p))
+ return;
+
+ if (*p == '`')
+ {
+ size_t len = STRLEN(p);
+
+ /* don't replace backslash in backtick quoted strings */
+ if (len > 2 && *(p + len - 1) == '`')
+ return;
+ }
+
+ while (*p)
+ {
+ if (*p == psepcN)
+ *p = psepc;
+ MB_PTR_ADV(p);
+ }
+}
+
+/* Use 64-bit stat functions if available. */
+#ifdef HAVE_STAT64
+# undef stat
+# undef _stat
+# undef _wstat
+# undef _fstat
+# define stat _stat64
+# define _stat _stat64
+# define _wstat _wstat64
+# define _fstat _fstat64
+#endif
+
+#if (defined(_MSC_VER) && (_MSC_VER >= 1300)) || defined(__MINGW32__)
+# define OPEN_OH_ARGTYPE intptr_t
+#else
+# define OPEN_OH_ARGTYPE long
+#endif
+
+ static int
+stat_symlink_aware(const char *name, stat_T *stp)
+{
+#if (defined(_MSC_VER) && (_MSC_VER < 1900)) || defined(__MINGW32__)
+ /* Work around for VC12 or earlier (and MinGW). stat() can't handle
+ * symlinks properly.
+ * VC9 or earlier: stat() doesn't support a symlink at all. It retrieves
+ * status of a symlink itself.
+ * VC10: stat() supports a symlink to a normal file, but it doesn't support
+ * a symlink to a directory (always returns an error).
+ * VC11 and VC12: stat() doesn't return an error for a symlink to a
+ * directory, but it doesn't set S_IFDIR flag.
+ * MinGW: Same as VC9. */
+ WIN32_FIND_DATA findData;
+ HANDLE hFind, h;
+ DWORD attr = 0;
+ BOOL is_symlink = FALSE;
+
+ hFind = FindFirstFile(name, &findData);
+ if (hFind != INVALID_HANDLE_VALUE)
+ {
+ attr = findData.dwFileAttributes;
+ if ((attr & FILE_ATTRIBUTE_REPARSE_POINT)
+ && (findData.dwReserved0 == IO_REPARSE_TAG_SYMLINK))
+ is_symlink = TRUE;
+ FindClose(hFind);
+ }
+ if (is_symlink)
+ {
+ h = CreateFile(name, FILE_READ_ATTRIBUTES,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
+ OPEN_EXISTING,
+ (attr & FILE_ATTRIBUTE_DIRECTORY)
+ ? FILE_FLAG_BACKUP_SEMANTICS : 0,
+ NULL);
+ if (h != INVALID_HANDLE_VALUE)
+ {
+ int fd, n;
+
+ fd = _open_osfhandle((OPEN_OH_ARGTYPE)h, _O_RDONLY);
+ n = _fstat(fd, (struct _stat *)stp);
+ if ((n == 0) && (attr & FILE_ATTRIBUTE_DIRECTORY))
+ stp->st_mode = (stp->st_mode & ~S_IFREG) | S_IFDIR;
+ _close(fd);
+ return n;
+ }
+ }
+#endif
+ return stat(name, stp);
+}
+
+ static int
+wstat_symlink_aware(const WCHAR *name, stat_T *stp)
+{
+#if (defined(_MSC_VER) && (_MSC_VER < 1900)) || defined(__MINGW32__)
+ /* Work around for VC12 or earlier (and MinGW). _wstat() can't handle
+ * symlinks properly.
+ * VC9 or earlier: _wstat() doesn't support a symlink at all. It retrieves
+ * status of a symlink itself.
+ * VC10: _wstat() supports a symlink to a normal file, but it doesn't
+ * support a symlink to a directory (always returns an error).
+ * VC11 and VC12: _wstat() doesn't return an error for a symlink to a
+ * directory, but it doesn't set S_IFDIR flag.
+ * MinGW: Same as VC9. */
+ int n;
+ BOOL is_symlink = FALSE;
+ HANDLE hFind, h;
+ DWORD attr = 0;
+ WIN32_FIND_DATAW findDataW;
+
+ hFind = FindFirstFileW(name, &findDataW);
+ if (hFind != INVALID_HANDLE_VALUE)
+ {
+ attr = findDataW.dwFileAttributes;
+ if ((attr & FILE_ATTRIBUTE_REPARSE_POINT)
+ && (findDataW.dwReserved0 == IO_REPARSE_TAG_SYMLINK))
+ is_symlink = TRUE;
+ FindClose(hFind);
+ }
+ if (is_symlink)
+ {
+ h = CreateFileW(name, FILE_READ_ATTRIBUTES,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
+ OPEN_EXISTING,
+ (attr & FILE_ATTRIBUTE_DIRECTORY)
+ ? FILE_FLAG_BACKUP_SEMANTICS : 0,
+ NULL);
+ if (h != INVALID_HANDLE_VALUE)
+ {
+ int fd;
+
+ fd = _open_osfhandle((OPEN_OH_ARGTYPE)h, _O_RDONLY);
+ n = _fstat(fd, (struct _stat *)stp);
+ if ((n == 0) && (attr & FILE_ATTRIBUTE_DIRECTORY))
+ stp->st_mode = (stp->st_mode & ~S_IFREG) | S_IFDIR;
+ _close(fd);
+ return n;
+ }
+ }
+#endif
+ return _wstat(name, (struct _stat *)stp);
+}
+
+/*
+ * stat() can't handle a trailing '/' or '\', remove it first.
+ */
+ int
+vim_stat(const char *name, stat_T *stp)
+{
+ /* WinNT and later can use _MAX_PATH wide characters for a pathname, which
+ * means that the maximum pathname is _MAX_PATH * 3 bytes when 'enc' is
+ * UTF-8. */
+ char_u buf[_MAX_PATH * 3 + 1];
+ char_u *p;
+
+ vim_strncpy((char_u *)buf, (char_u *)name, sizeof(buf) - 1);
+ p = buf + STRLEN(buf);
+ if (p > buf)
+ MB_PTR_BACK(buf, p);
+
+ /* Remove trailing '\\' except root path. */
+ if (p > buf && (*p == '\\' || *p == '/') && p[-1] != ':')
+ *p = NUL;
+
+ if ((buf[0] == '\\' && buf[1] == '\\') || (buf[0] == '/' && buf[1] == '/'))
+ {
+ /* UNC root path must be followed by '\\'. */
+ p = vim_strpbrk(buf + 2, (char_u *)"\\/");
+ if (p != NULL)
+ {
+ p = vim_strpbrk(p + 1, (char_u *)"\\/");
+ if (p == NULL)
+ STRCAT(buf, "\\");
+ }
+ }
+ if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+ {
+ WCHAR *wp = enc_to_utf16(buf, NULL);
+ int n;
+
+ if (wp != NULL)
+ {
+ n = wstat_symlink_aware(wp, stp);
+ vim_free(wp);
+ return n;
+ }
+ }
+ return stat_symlink_aware((char *)buf, stp);
+}
+
+#if defined(FEAT_GUI_MSWIN) || defined(PROTO)
+ void
+mch_settmode(int tmode UNUSED)
+{
+ /* nothing to do */
+}
+
+ int
+mch_get_shellsize(void)
+{
+ /* never used */
+ return OK;
+}
+
+ void
+mch_set_shellsize(void)
+{
+ /* never used */
+}
+
+/*
+ * Rows and/or Columns has changed.
+ */
+ void
+mch_new_shellsize(void)
+{
+ /* never used */
+}
+
+#endif
+
+/*
+ * We have no job control, so fake it by starting a new shell.
+ */
+ void
+mch_suspend(void)
+{
+ suspend_shell();
+}
+
+#if defined(USE_MCH_ERRMSG) || defined(PROTO)
+
+#ifdef display_errors
+# undef display_errors
+#endif
+
+/*
+ * Display the saved error message(s).
+ */
+ void
+display_errors(void)
+{
+ char *p;
+
+ if (error_ga.ga_data != NULL)
+ {
+ /* avoid putting up a message box with blanks only */
+ for (p = (char *)error_ga.ga_data; *p; ++p)
+ if (!isspace(*p))
+ {
+ (void)gui_mch_dialog(
+#ifdef FEAT_GUI
+ gui.starting ? VIM_INFO :
+#endif
+ VIM_ERROR,
+#ifdef FEAT_GUI
+ gui.starting ? (char_u *)_("Message") :
+#endif
+ (char_u *)_("Error"),
+ (char_u *)p, (char_u *)_("&Ok"),
+ 1, NULL, FALSE);
+ break;
+ }
+ ga_clear(&error_ga);
+ }
+}
+#endif
+
+
+/*
+ * Return TRUE if "p" contain a wildcard that can be expanded by
+ * dos_expandpath().
+ */
+ int
+mch_has_exp_wildcard(char_u *p)
+{
+ for ( ; *p; MB_PTR_ADV(p))
+ {
+ if (vim_strchr((char_u *)"?*[", *p) != NULL
+ || (*p == '~' && p[1] != NUL))
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * Return TRUE if "p" contain a wildcard or a "~1" kind of thing (could be a
+ * shortened file name).
+ */
+ int
+mch_has_wildcard(char_u *p)
+{
+ for ( ; *p; MB_PTR_ADV(p))
+ {
+ if (vim_strchr((char_u *)
+# ifdef VIM_BACKTICK
+ "?*$[`"
+# else
+ "?*$["
+# endif
+ , *p) != NULL
+ || (*p == '~' && p[1] != NUL))
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+/*
+ * The normal _chdir() does not change the default drive. This one does.
+ * Returning 0 implies success; -1 implies failure.
+ */
+ int
+mch_chdir(char *path)
+{
+ if (path[0] == NUL) /* just checking... */
+ return -1;
+
+ if (p_verbose >= 5)
+ {
+ verbose_enter();
+ smsg("chdir(%s)", path);
+ verbose_leave();
+ }
+ if (isalpha(path[0]) && path[1] == ':') /* has a drive name */
+ {
+ /* If we can change to the drive, skip that part of the path. If we
+ * can't then the current directory may be invalid, try using chdir()
+ * with the whole path. */
+ if (_chdrive(TOLOWER_ASC(path[0]) - 'a' + 1) == 0)
+ path += 2;
+ }
+
+ if (*path == NUL) /* drive name only */
+ return 0;
+
+ if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+ {
+ WCHAR *p = enc_to_utf16((char_u *)path, NULL);
+ int n;
+
+ if (p != NULL)
+ {
+ n = _wchdir(p);
+ vim_free(p);
+ return n;
+ }
+ }
+
+ return chdir(path); /* let the normal chdir() do the rest */
+}
+
+
+#ifdef FEAT_GUI_MSWIN
+/*
+ * return non-zero if a character is available
+ */
+ int
+mch_char_avail(void)
+{
+ /* never used */
+ return TRUE;
+}
+
+# if defined(FEAT_TERMINAL) || defined(PROTO)
+/*
+ * Check for any pending input or messages.
+ */
+ int
+mch_check_messages(void)
+{
+ /* TODO: check for messages */
+ return TRUE;
+}
+# endif
+#endif
+
+
+/*
+ * set screen mode, always fails.
+ */
+ int
+mch_screenmode(char_u *arg UNUSED)
+{
+ emsg(_(e_screenmode));
+ return FAIL;
+}
+
+
+#if defined(FEAT_LIBCALL) || defined(PROTO)
+/*
+ * Call a DLL routine which takes either a string or int param
+ * and returns an allocated string.
+ * Return OK if it worked, FAIL if not.
+ */
+typedef LPTSTR (*MYSTRPROCSTR)(LPTSTR);
+typedef LPTSTR (*MYINTPROCSTR)(int);
+typedef int (*MYSTRPROCINT)(LPTSTR);
+typedef int (*MYINTPROCINT)(int);
+
+/*
+ * Check if a pointer points to a valid NUL terminated string.
+ * Return the length of the string, including terminating NUL.
+ * Returns 0 for an invalid pointer, 1 for an empty string.
+ */
+ static size_t
+check_str_len(char_u *str)
+{
+ SYSTEM_INFO si;
+ MEMORY_BASIC_INFORMATION mbi;
+ size_t length = 0;
+ size_t i;
+ const char_u *p;
+
+ /* get page size */
+ GetSystemInfo(&si);
+
+ /* get memory information */
+ if (VirtualQuery(str, &mbi, sizeof(mbi)))
+ {
+ /* pre cast these (typing savers) */
+ long_u dwStr = (long_u)str;
+ long_u dwBaseAddress = (long_u)mbi.BaseAddress;
+
+ /* get start address of page that str is on */
+ long_u strPage = dwStr - (dwStr - dwBaseAddress) % si.dwPageSize;
+
+ /* get length from str to end of page */
+ long_u pageLength = si.dwPageSize - (dwStr - strPage);
+
+ for (p = str; !IsBadReadPtr(p, (UINT)pageLength);
+ p += pageLength, pageLength = si.dwPageSize)
+ for (i = 0; i < pageLength; ++i, ++length)
+ if (p[i] == NUL)
+ return length + 1;
+ }
+
+ return 0;
+}
+
+/*
+ * Passed to do_in_runtimepath() to load a vim.ico file.
+ */
+ static void
+mch_icon_load_cb(char_u *fname, void *cookie)
+{
+ HANDLE *h = (HANDLE *)cookie;
+
+ *h = LoadImage(NULL,
+ (LPSTR)fname,
+ IMAGE_ICON,
+ 64,
+ 64,
+ LR_LOADFROMFILE | LR_LOADMAP3DCOLORS);
+}
+
+/*
+ * Try loading an icon file from 'runtimepath'.
+ */
+ int
+mch_icon_load(HANDLE *iconp)
+{
+ return do_in_runtimepath((char_u *)"bitmaps/vim.ico",
+ 0, mch_icon_load_cb, iconp);
+}
+
+ int
+mch_libcall(
+ char_u *libname,
+ char_u *funcname,
+ char_u *argstring, /* NULL when using a argint */
+ int argint,
+ char_u **string_result,/* NULL when using number_result */
+ int *number_result)
+{
+ HINSTANCE hinstLib;
+ MYSTRPROCSTR ProcAdd;
+ MYINTPROCSTR ProcAddI;
+ char_u *retval_str = NULL;
+ int retval_int = 0;
+ size_t len;
+
+ BOOL fRunTimeLinkSuccess = FALSE;
+
+ // Get a handle to the DLL module.
+ hinstLib = vimLoadLib((char *)libname);
+
+ // If the handle is valid, try to get the function address.
+ if (hinstLib != NULL)
+ {
+#ifdef HAVE_TRY_EXCEPT
+ __try
+ {
+#endif
+ if (argstring != NULL)
+ {
+ /* Call with string argument */
+ ProcAdd = (MYSTRPROCSTR)GetProcAddress(hinstLib, (LPCSTR)funcname);
+ if ((fRunTimeLinkSuccess = (ProcAdd != NULL)) != 0)
+ {
+ if (string_result == NULL)
+ retval_int = ((MYSTRPROCINT)ProcAdd)((LPSTR)argstring);
+ else
+ retval_str = (char_u *)(ProcAdd)((LPSTR)argstring);
+ }
+ }
+ else
+ {
+ /* Call with number argument */
+ ProcAddI = (MYINTPROCSTR) GetProcAddress(hinstLib, (LPCSTR)funcname);
+ if ((fRunTimeLinkSuccess = (ProcAddI != NULL)) != 0)
+ {
+ if (string_result == NULL)
+ retval_int = ((MYINTPROCINT)ProcAddI)(argint);
+ else
+ retval_str = (char_u *)(ProcAddI)(argint);
+ }
+ }
+
+ // Save the string before we free the library.
+ // Assume that a "1" result is an illegal pointer.
+ if (string_result == NULL)
+ *number_result = retval_int;
+ else if (retval_str != NULL
+ && (len = check_str_len(retval_str)) > 0)
+ {
+ *string_result = lalloc((long_u)len, TRUE);
+ if (*string_result != NULL)
+ mch_memmove(*string_result, retval_str, len);
+ }
+
+#ifdef HAVE_TRY_EXCEPT
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ if (GetExceptionCode() == EXCEPTION_STACK_OVERFLOW)
+ RESETSTKOFLW();
+ fRunTimeLinkSuccess = 0;
+ }
+#endif
+
+ // Free the DLL module.
+ (void)FreeLibrary(hinstLib);
+ }
+
+ if (!fRunTimeLinkSuccess)
+ {
+ semsg(_(e_libcall), funcname);
+ return FAIL;
+ }
+
+ return OK;
+}
+#endif
+
+/*
+ * Debugging helper: expose the MCH_WRITE_DUMP stuff to other modules
+ */
+ void
+DumpPutS(const char *psz UNUSED)
+{
+# ifdef MCH_WRITE_DUMP
+ if (fdDump)
+ {
+ fputs(psz, fdDump);
+ if (psz[strlen(psz) - 1] != '\n')
+ fputc('\n', fdDump);
+ fflush(fdDump);
+ }
+# endif
+}
+
+#ifdef _DEBUG
+
+void __cdecl
+Trace(
+ char *pszFormat,
+ ...)
+{
+ CHAR szBuff[2048];
+ va_list args;
+
+ va_start(args, pszFormat);
+ vsprintf(szBuff, pszFormat, args);
+ va_end(args);
+
+ OutputDebugString(szBuff);
+}
+
+#endif //_DEBUG
+
+#if !defined(FEAT_GUI) || defined(PROTO)
+# ifdef FEAT_TITLE
+extern HWND g_hWnd; /* This is in os_win32.c. */
+# endif
+
+/*
+ * Showing the printer dialog is tricky since we have no GUI
+ * window to parent it. The following routines are needed to
+ * get the window parenting and Z-order to work properly.
+ */
+ static void
+GetConsoleHwnd(void)
+{
+# define MY_BUFSIZE 1024 // Buffer size for console window titles.
+
+ char pszNewWindowTitle[MY_BUFSIZE]; // Contains fabricated WindowTitle.
+ char pszOldWindowTitle[MY_BUFSIZE]; // Contains original WindowTitle.
+
+ /* Skip if it's already set. */
+ if (s_hwnd != 0)
+ return;
+
+# ifdef FEAT_TITLE
+ /* Window handle may have been found by init code (Windows NT only) */
+ if (g_hWnd != 0)
+ {
+ s_hwnd = g_hWnd;
+ return;
+ }
+# endif
+
+ GetConsoleTitle(pszOldWindowTitle, MY_BUFSIZE);
+
+ wsprintf(pszNewWindowTitle, "%s/%d/%d",
+ pszOldWindowTitle,
+ GetTickCount(),
+ GetCurrentProcessId());
+ SetConsoleTitle(pszNewWindowTitle);
+ Sleep(40);
+ s_hwnd = FindWindow(NULL, pszNewWindowTitle);
+
+ SetConsoleTitle(pszOldWindowTitle);
+}
+
+/*
+ * Console implementation of ":winpos".
+ */
+ int
+mch_get_winpos(int *x, int *y)
+{
+ RECT rect;
+
+ GetConsoleHwnd();
+ GetWindowRect(s_hwnd, &rect);
+ *x = rect.left;
+ *y = rect.top;
+ return OK;
+}
+
+/*
+ * Console implementation of ":winpos x y".
+ */
+ void
+mch_set_winpos(int x, int y)
+{
+ GetConsoleHwnd();
+ SetWindowPos(s_hwnd, NULL, x, y, 0, 0,
+ SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
+}
+#endif
+
+#if (defined(FEAT_PRINTER) && !defined(FEAT_POSTSCRIPT)) || defined(PROTO)
+
+/*=================================================================
+ * Win32 printer stuff
+ */
+
+static HFONT prt_font_handles[2][2][2];
+static PRINTDLG prt_dlg;
+static const int boldface[2] = {FW_REGULAR, FW_BOLD};
+static TEXTMETRIC prt_tm;
+static int prt_line_height;
+static int prt_number_width;
+static int prt_left_margin;
+static int prt_right_margin;
+static int prt_top_margin;
+static char_u szAppName[] = TEXT("VIM");
+static HWND hDlgPrint;
+static int *bUserAbort = NULL;
+static char_u *prt_name = NULL;
+
+/* Defines which are also in vim.rc. */
+#define IDC_BOX1 400
+#define IDC_PRINTTEXT1 401
+#define IDC_PRINTTEXT2 402
+#define IDC_PROGRESS 403
+
+ static BOOL
+vimSetDlgItemText(HWND hDlg, int nIDDlgItem, char_u *s)
+{
+ WCHAR *wp = NULL;
+ BOOL ret;
+
+ if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+ {
+ wp = enc_to_utf16(s, NULL);
+ }
+ if (wp != NULL)
+ {
+ ret = SetDlgItemTextW(hDlg, nIDDlgItem, wp);
+ vim_free(wp);
+ return ret;
+ }
+ return SetDlgItemText(hDlg, nIDDlgItem, (LPCSTR)s);
+}
+
+/*
+ * Convert BGR to RGB for Windows GDI calls
+ */
+ static COLORREF
+swap_me(COLORREF colorref)
+{
+ int temp;
+ char *ptr = (char *)&colorref;
+
+ temp = *(ptr);
+ *(ptr ) = *(ptr + 2);
+ *(ptr + 2) = temp;
+ return colorref;
+}
+
+/* Attempt to make this work for old and new compilers */
+#if !defined(_WIN64) && (!defined(_MSC_VER) || _MSC_VER < 1300)
+# define PDP_RETVAL BOOL
+#else
+# define PDP_RETVAL INT_PTR
+#endif
+
+ static PDP_RETVAL CALLBACK
+PrintDlgProc(
+ HWND hDlg,
+ UINT message,
+ WPARAM wParam UNUSED,
+ LPARAM lParam UNUSED)
+{
+#ifdef FEAT_GETTEXT
+ NONCLIENTMETRICS nm;
+ static HFONT hfont;
+#endif
+
+ switch (message)
+ {
+ case WM_INITDIALOG:
+#ifdef FEAT_GETTEXT
+ nm.cbSize = sizeof(NONCLIENTMETRICS);
+ if (SystemParametersInfo(
+ SPI_GETNONCLIENTMETRICS,
+ sizeof(NONCLIENTMETRICS),
+ &nm,
+ 0))
+ {
+ char buff[MAX_PATH];
+ int i;
+
+ /* Translate the dialog texts */
+ hfont = CreateFontIndirect(&nm.lfMessageFont);
+ for (i = IDC_PRINTTEXT1; i <= IDC_PROGRESS; i++)
+ {
+ SendDlgItemMessage(hDlg, i, WM_SETFONT, (WPARAM)hfont, 1);
+ if (GetDlgItemText(hDlg,i, buff, sizeof(buff)))
+ vimSetDlgItemText(hDlg,i, (char_u *)_(buff));
+ }
+ SendDlgItemMessage(hDlg, IDCANCEL,
+ WM_SETFONT, (WPARAM)hfont, 1);
+ if (GetDlgItemText(hDlg,IDCANCEL, buff, sizeof(buff)))
+ vimSetDlgItemText(hDlg,IDCANCEL, (char_u *)_(buff));
+ }
+#endif
+ SetWindowText(hDlg, (LPCSTR)szAppName);
+ if (prt_name != NULL)
+ {
+ vimSetDlgItemText(hDlg, IDC_PRINTTEXT2, (char_u *)prt_name);
+ VIM_CLEAR(prt_name);
+ }
+ EnableMenuItem(GetSystemMenu(hDlg, FALSE), SC_CLOSE, MF_GRAYED);
+#ifndef FEAT_GUI
+ BringWindowToTop(s_hwnd);
+#endif
+ return TRUE;
+
+ case WM_COMMAND:
+ *bUserAbort = TRUE;
+ EnableWindow(GetParent(hDlg), TRUE);
+ DestroyWindow(hDlg);
+ hDlgPrint = NULL;
+#ifdef FEAT_GETTEXT
+ DeleteObject(hfont);
+#endif
+ return TRUE;
+ }
+ return FALSE;
+}
+
+ static BOOL CALLBACK
+AbortProc(HDC hdcPrn UNUSED, int iCode UNUSED)
+{
+ MSG msg;
+
+ while (!*bUserAbort && pPeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
+ {
+ if (!hDlgPrint || !pIsDialogMessage(hDlgPrint, &msg))
+ {
+ TranslateMessage(&msg);
+ pDispatchMessage(&msg);
+ }
+ }
+ return !*bUserAbort;
+}
+
+#ifndef FEAT_GUI
+
+ static UINT_PTR CALLBACK
+PrintHookProc(
+ HWND hDlg, // handle to dialog box
+ UINT uiMsg, // message identifier
+ WPARAM wParam, // message parameter
+ LPARAM lParam // message parameter
+ )
+{
+ HWND hwndOwner;
+ RECT rc, rcDlg, rcOwner;
+ PRINTDLG *pPD;
+
+ if (uiMsg == WM_INITDIALOG)
+ {
+ // Get the owner window and dialog box rectangles.
+ if ((hwndOwner = GetParent(hDlg)) == NULL)
+ hwndOwner = GetDesktopWindow();
+
+ GetWindowRect(hwndOwner, &rcOwner);
+ GetWindowRect(hDlg, &rcDlg);
+ CopyRect(&rc, &rcOwner);
+
+ // Offset the owner and dialog box rectangles so that
+ // right and bottom values represent the width and
+ // height, and then offset the owner again to discard
+ // space taken up by the dialog box.
+
+ OffsetRect(&rcDlg, -rcDlg.left, -rcDlg.top);
+ OffsetRect(&rc, -rc.left, -rc.top);
+ OffsetRect(&rc, -rcDlg.right, -rcDlg.bottom);
+
+ // The new position is the sum of half the remaining
+ // space and the owner's original position.
+
+ SetWindowPos(hDlg,
+ HWND_TOP,
+ rcOwner.left + (rc.right / 2),
+ rcOwner.top + (rc.bottom / 2),
+ 0, 0, // ignores size arguments
+ SWP_NOSIZE);
+
+ /* tackle the printdlg copiesctrl problem */
+ pPD = (PRINTDLG *)lParam;
+ pPD->nCopies = (WORD)pPD->lCustData;
+ SetDlgItemInt( hDlg, edt3, pPD->nCopies, FALSE );
+ /* Bring the window to top */
+ BringWindowToTop(GetParent(hDlg));
+ SetForegroundWindow(hDlg);
+ }
+
+ return FALSE;
+}
+#endif
+
+ void
+mch_print_cleanup(void)
+{
+ int pifItalic;
+ int pifBold;
+ int pifUnderline;
+
+ for (pifBold = 0; pifBold <= 1; pifBold++)
+ for (pifItalic = 0; pifItalic <= 1; pifItalic++)
+ for (pifUnderline = 0; pifUnderline <= 1; pifUnderline++)
+ DeleteObject(prt_font_handles[pifBold][pifItalic][pifUnderline]);
+
+ if (prt_dlg.hDC != NULL)
+ DeleteDC(prt_dlg.hDC);
+ if (!*bUserAbort)
+ SendMessage(hDlgPrint, WM_COMMAND, 0, 0);
+}
+
+ static int
+to_device_units(int idx, int dpi, int physsize, int offset, int def_number)
+{
+ int ret = 0;
+ int u;
+ int nr;
+
+ u = prt_get_unit(idx);
+ if (u == PRT_UNIT_NONE)
+ {
+ u = PRT_UNIT_PERC;
+ nr = def_number;
+ }
+ else
+ nr = printer_opts[idx].number;
+
+ switch (u)
+ {
+ case PRT_UNIT_PERC:
+ ret = (physsize * nr) / 100;
+ break;
+ case PRT_UNIT_INCH:
+ ret = (nr * dpi);
+ break;
+ case PRT_UNIT_MM:
+ ret = (nr * 10 * dpi) / 254;
+ break;
+ case PRT_UNIT_POINT:
+ ret = (nr * 10 * dpi) / 720;
+ break;
+ }
+
+ if (ret < offset)
+ return 0;
+ else
+ return ret - offset;
+}
+
+ static int
+prt_get_cpl(void)
+{
+ int hr;
+ int phyw;
+ int dvoff;
+ int rev_offset;
+ int dpi;
+
+ GetTextMetrics(prt_dlg.hDC, &prt_tm);
+ prt_line_height = prt_tm.tmHeight + prt_tm.tmExternalLeading;
+
+ hr = GetDeviceCaps(prt_dlg.hDC, HORZRES);
+ phyw = GetDeviceCaps(prt_dlg.hDC, PHYSICALWIDTH);
+ dvoff = GetDeviceCaps(prt_dlg.hDC, PHYSICALOFFSETX);
+ dpi = GetDeviceCaps(prt_dlg.hDC, LOGPIXELSX);
+
+ rev_offset = phyw - (dvoff + hr);
+
+ prt_left_margin = to_device_units(OPT_PRINT_LEFT, dpi, phyw, dvoff, 10);
+ if (prt_use_number())
+ {
+ prt_number_width = PRINT_NUMBER_WIDTH * prt_tm.tmAveCharWidth;
+ prt_left_margin += prt_number_width;
+ }
+ else
+ prt_number_width = 0;
+
+ prt_right_margin = hr - to_device_units(OPT_PRINT_RIGHT, dpi, phyw,
+ rev_offset, 5);
+
+ return (prt_right_margin - prt_left_margin) / prt_tm.tmAveCharWidth;
+}
+
+ static int
+prt_get_lpp(void)
+{
+ int vr;
+ int phyw;
+ int dvoff;
+ int rev_offset;
+ int bottom_margin;
+ int dpi;
+
+ vr = GetDeviceCaps(prt_dlg.hDC, VERTRES);
+ phyw = GetDeviceCaps(prt_dlg.hDC, PHYSICALHEIGHT);
+ dvoff = GetDeviceCaps(prt_dlg.hDC, PHYSICALOFFSETY);
+ dpi = GetDeviceCaps(prt_dlg.hDC, LOGPIXELSY);
+
+ rev_offset = phyw - (dvoff + vr);
+
+ prt_top_margin = to_device_units(OPT_PRINT_TOP, dpi, phyw, dvoff, 5);
+
+ /* adjust top margin if there is a header */
+ prt_top_margin += prt_line_height * prt_header_height();
+
+ bottom_margin = vr - to_device_units(OPT_PRINT_BOT, dpi, phyw,
+ rev_offset, 5);
+
+ return (bottom_margin - prt_top_margin) / prt_line_height;
+}
+
+ int
+mch_print_init(prt_settings_T *psettings, char_u *jobname, int forceit)
+{
+ static HGLOBAL stored_dm = NULL;
+ static HGLOBAL stored_devn = NULL;
+ static int stored_nCopies = 1;
+ static int stored_nFlags = 0;
+
+ LOGFONT fLogFont;
+ int pifItalic;
+ int pifBold;
+ int pifUnderline;
+
+ DEVMODE *mem;
+ DEVNAMES *devname;
+ int i;
+
+ bUserAbort = &(psettings->user_abort);
+ vim_memset(&prt_dlg, 0, sizeof(PRINTDLG));
+ prt_dlg.lStructSize = sizeof(PRINTDLG);
+#ifndef FEAT_GUI
+ GetConsoleHwnd(); /* get value of s_hwnd */
+#endif
+ prt_dlg.hwndOwner = s_hwnd;
+ prt_dlg.Flags = PD_NOPAGENUMS | PD_NOSELECTION | PD_RETURNDC;
+ if (!forceit)
+ {
+ prt_dlg.hDevMode = stored_dm;
+ prt_dlg.hDevNames = stored_devn;
+ prt_dlg.lCustData = stored_nCopies; // work around bug in print dialog
+#ifndef FEAT_GUI
+ /*
+ * Use hook to prevent console window being sent to back
+ */
+ prt_dlg.lpfnPrintHook = PrintHookProc;
+ prt_dlg.Flags |= PD_ENABLEPRINTHOOK;
+#endif
+ prt_dlg.Flags |= stored_nFlags;
+ }
+
+ /*
+ * If bang present, return default printer setup with no dialog
+ * never show dialog if we are running over telnet
+ */
+ if (forceit
+#ifndef FEAT_GUI
+ || !term_console
+#endif
+ )
+ {
+ prt_dlg.Flags |= PD_RETURNDEFAULT;
+ /*
+ * MSDN suggests setting the first parameter to WINSPOOL for
+ * NT, but NULL appears to work just as well.
+ */
+ if (*p_pdev != NUL)
+ prt_dlg.hDC = CreateDC(NULL, (LPCSTR)p_pdev, NULL, NULL);
+ else
+ {
+ prt_dlg.Flags |= PD_RETURNDEFAULT;
+ if (PrintDlg(&prt_dlg) == 0)
+ goto init_fail_dlg;
+ }
+ }
+ else if (PrintDlg(&prt_dlg) == 0)
+ goto init_fail_dlg;
+ else
+ {
+ /*
+ * keep the previous driver context
+ */
+ stored_dm = prt_dlg.hDevMode;
+ stored_devn = prt_dlg.hDevNames;
+ stored_nFlags = prt_dlg.Flags;
+ stored_nCopies = prt_dlg.nCopies;
+ }
+
+ if (prt_dlg.hDC == NULL)
+ {
+ emsg(_("E237: Printer selection failed"));
+ mch_print_cleanup();
+ return FALSE;
+ }
+
+ /* Not all printer drivers report the support of color (or grey) in the
+ * same way. Let's set has_color if there appears to be some way to print
+ * more than B&W. */
+ i = GetDeviceCaps(prt_dlg.hDC, NUMCOLORS);
+ psettings->has_color = (GetDeviceCaps(prt_dlg.hDC, BITSPIXEL) > 1
+ || GetDeviceCaps(prt_dlg.hDC, PLANES) > 1
+ || i > 2 || i == -1);
+
+ /* Ensure all font styles are baseline aligned */
+ SetTextAlign(prt_dlg.hDC, TA_BASELINE|TA_LEFT);
+
+ /*
+ * On some windows systems the nCopies parameter is not
+ * passed back correctly. It must be retrieved from the
+ * hDevMode struct.
+ */
+ mem = (DEVMODE *)GlobalLock(prt_dlg.hDevMode);
+ if (mem != NULL)
+ {
+ if (mem->dmCopies != 1)
+ stored_nCopies = mem->dmCopies;
+ if ((mem->dmFields & DM_DUPLEX) && (mem->dmDuplex & ~DMDUP_SIMPLEX))
+ psettings->duplex = TRUE;
+ if ((mem->dmFields & DM_COLOR) && (mem->dmColor & DMCOLOR_COLOR))
+ psettings->has_color = TRUE;
+ }
+ GlobalUnlock(prt_dlg.hDevMode);
+
+ devname = (DEVNAMES *)GlobalLock(prt_dlg.hDevNames);
+ if (devname != 0)
+ {
+ char_u *printer_name = (char_u *)devname + devname->wDeviceOffset;
+ char_u *port_name = (char_u *)devname +devname->wOutputOffset;
+ char_u *text = (char_u *)_("to %s on %s");
+ char_u *printer_name_orig = printer_name;
+ char_u *port_name_orig = port_name;
+
+ if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+ {
+ char_u *to_free = NULL;
+ int maxlen;
+
+ acp_to_enc(printer_name, (int)STRLEN(printer_name), &to_free,
+ &maxlen);
+ if (to_free != NULL)
+ printer_name = to_free;
+ acp_to_enc(port_name, (int)STRLEN(port_name), &to_free, &maxlen);
+ if (to_free != NULL)
+ port_name = to_free;
+ }
+ prt_name = alloc((unsigned)(STRLEN(printer_name) + STRLEN(port_name)
+ + STRLEN(text)));
+ if (prt_name != NULL)
+ wsprintf((char *)prt_name, (const char *)text,
+ printer_name, port_name);
+ if (printer_name != printer_name_orig)
+ vim_free(printer_name);
+ if (port_name != port_name_orig)
+ vim_free(port_name);
+ }
+ GlobalUnlock(prt_dlg.hDevNames);
+
+ /*
+ * Initialise the font according to 'printfont'
+ */
+ vim_memset(&fLogFont, 0, sizeof(fLogFont));
+ if (get_logfont(&fLogFont, p_pfn, prt_dlg.hDC, TRUE) == FAIL)
+ {
+ semsg(_("E613: Unknown printer font: %s"), p_pfn);
+ mch_print_cleanup();
+ return FALSE;
+ }
+
+ for (pifBold = 0; pifBold <= 1; pifBold++)
+ for (pifItalic = 0; pifItalic <= 1; pifItalic++)
+ for (pifUnderline = 0; pifUnderline <= 1; pifUnderline++)
+ {
+ fLogFont.lfWeight = boldface[pifBold];
+ fLogFont.lfItalic = pifItalic;
+ fLogFont.lfUnderline = pifUnderline;
+ prt_font_handles[pifBold][pifItalic][pifUnderline]
+ = CreateFontIndirect(&fLogFont);
+ }
+
+ SetBkMode(prt_dlg.hDC, OPAQUE);
+ SelectObject(prt_dlg.hDC, prt_font_handles[0][0][0]);
+
+ /*
+ * Fill in the settings struct
+ */
+ psettings->chars_per_line = prt_get_cpl();
+ psettings->lines_per_page = prt_get_lpp();
+ if (prt_dlg.Flags & PD_USEDEVMODECOPIESANDCOLLATE)
+ {
+ psettings->n_collated_copies = (prt_dlg.Flags & PD_COLLATE)
+ ? prt_dlg.nCopies : 1;
+ psettings->n_uncollated_copies = (prt_dlg.Flags & PD_COLLATE)
+ ? 1 : prt_dlg.nCopies;
+
+ if (psettings->n_collated_copies == 0)
+ psettings->n_collated_copies = 1;
+
+ if (psettings->n_uncollated_copies == 0)
+ psettings->n_uncollated_copies = 1;
+ }
+ else
+ {
+ psettings->n_collated_copies = 1;
+ psettings->n_uncollated_copies = 1;
+ }
+
+ psettings->jobname = jobname;
+
+ return TRUE;
+
+init_fail_dlg:
+ {
+ DWORD err = CommDlgExtendedError();
+
+ if (err)
+ {
+ char_u *buf;
+
+ /* I suspect FormatMessage() doesn't work for values returned by
+ * CommDlgExtendedError(). What does? */
+ FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, err, 0, (LPTSTR)(&buf), 0, NULL);
+ semsg(_("E238: Print error: %s"),
+ buf == NULL ? (char_u *)_("Unknown") : buf);
+ LocalFree((LPVOID)(buf));
+ }
+ else
+ msg_clr_eos(); /* Maybe canceled */
+
+ mch_print_cleanup();
+ return FALSE;
+ }
+}
+
+
+ int
+mch_print_begin(prt_settings_T *psettings)
+{
+ int ret;
+ char szBuffer[300];
+ WCHAR *wp = NULL;
+
+ hDlgPrint = CreateDialog(GetModuleHandle(NULL), TEXT("PrintDlgBox"),
+ prt_dlg.hwndOwner, PrintDlgProc);
+ SetAbortProc(prt_dlg.hDC, AbortProc);
+ wsprintf(szBuffer, _("Printing '%s'"), gettail(psettings->jobname));
+ vimSetDlgItemText(hDlgPrint, IDC_PRINTTEXT1, (char_u *)szBuffer);
+
+ if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+ wp = enc_to_utf16(psettings->jobname, NULL);
+ if (wp != NULL)
+ {
+ DOCINFOW di;
+
+ vim_memset(&di, 0, sizeof(di));
+ di.cbSize = sizeof(di);
+ di.lpszDocName = wp;
+ ret = StartDocW(prt_dlg.hDC, &di);
+ vim_free(wp);
+ }
+ else
+ {
+ DOCINFO di;
+
+ vim_memset(&di, 0, sizeof(di));
+ di.cbSize = sizeof(di);
+ di.lpszDocName = (LPCSTR)psettings->jobname;
+ ret = StartDoc(prt_dlg.hDC, &di);
+ }
+
+#ifdef FEAT_GUI
+ /* Give focus back to main window (when using MDI). */
+ SetFocus(s_hwnd);
+#endif
+
+ return (ret > 0);
+}
+
+ void
+mch_print_end(prt_settings_T *psettings UNUSED)
+{
+ EndDoc(prt_dlg.hDC);
+ if (!*bUserAbort)
+ SendMessage(hDlgPrint, WM_COMMAND, 0, 0);
+}
+
+ int
+mch_print_end_page(void)
+{
+ return (EndPage(prt_dlg.hDC) > 0);
+}
+
+ int
+mch_print_begin_page(char_u *msg)
+{
+ if (msg != NULL)
+ vimSetDlgItemText(hDlgPrint, IDC_PROGRESS, msg);
+ return (StartPage(prt_dlg.hDC) > 0);
+}
+
+ int
+mch_print_blank_page(void)
+{
+ return (mch_print_begin_page(NULL) ? (mch_print_end_page()) : FALSE);
+}
+
+static int prt_pos_x = 0;
+static int prt_pos_y = 0;
+
+ void
+mch_print_start_line(int margin, int page_line)
+{
+ if (margin)
+ prt_pos_x = -prt_number_width;
+ else
+ prt_pos_x = 0;
+ prt_pos_y = page_line * prt_line_height
+ + prt_tm.tmAscent + prt_tm.tmExternalLeading;
+}
+
+ int
+mch_print_text_out(char_u *p, int len)
+{
+ SIZE sz;
+ WCHAR *wp = NULL;
+ int wlen = len;
+
+ if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+ {
+ wp = enc_to_utf16(p, &wlen);
+ }
+ if (wp != NULL)
+ {
+ int ret = FALSE;
+
+ TextOutW(prt_dlg.hDC, prt_pos_x + prt_left_margin,
+ prt_pos_y + prt_top_margin, wp, wlen);
+ GetTextExtentPoint32W(prt_dlg.hDC, wp, wlen, &sz);
+ vim_free(wp);
+ prt_pos_x += (sz.cx - prt_tm.tmOverhang);
+ /* This is wrong when printing spaces for a TAB. */
+ if (p[len] != NUL)
+ {
+ wlen = MB_PTR2LEN(p + len);
+ wp = enc_to_utf16(p + len, &wlen);
+ if (wp != NULL)
+ {
+ GetTextExtentPoint32W(prt_dlg.hDC, wp, 1, &sz);
+ ret = (prt_pos_x + prt_left_margin + sz.cx > prt_right_margin);
+ vim_free(wp);
+ }
+ }
+ return ret;
+ }
+ TextOut(prt_dlg.hDC, prt_pos_x + prt_left_margin,
+ prt_pos_y + prt_top_margin,
+ (LPCSTR)p, len);
+#ifndef FEAT_PROPORTIONAL_FONTS
+ prt_pos_x += len * prt_tm.tmAveCharWidth;
+ return (prt_pos_x + prt_left_margin + prt_tm.tmAveCharWidth
+ + prt_tm.tmOverhang > prt_right_margin);
+#else
+ GetTextExtentPoint32(prt_dlg.hDC, (LPCSTR)p, len, &sz);
+ prt_pos_x += (sz.cx - prt_tm.tmOverhang);
+ /* This is wrong when printing spaces for a TAB. */
+ if (p[len] == NUL)
+ return FALSE;
+ GetTextExtentPoint32(prt_dlg.hDC, p + len, 1, &sz);
+ return (prt_pos_x + prt_left_margin + sz.cx > prt_right_margin);
+#endif
+}
+
+ void
+mch_print_set_font(int iBold, int iItalic, int iUnderline)
+{
+ SelectObject(prt_dlg.hDC, prt_font_handles[iBold][iItalic][iUnderline]);
+}
+
+ void
+mch_print_set_bg(long_u bgcol)
+{
+ SetBkColor(prt_dlg.hDC, GetNearestColor(prt_dlg.hDC,
+ swap_me((COLORREF)bgcol)));
+ /*
+ * With a white background we can draw characters transparent, which is
+ * good for italic characters that overlap to the next char cell.
+ */
+ if (bgcol == 0xffffffUL)
+ SetBkMode(prt_dlg.hDC, TRANSPARENT);
+ else
+ SetBkMode(prt_dlg.hDC, OPAQUE);
+}
+
+ void
+mch_print_set_fg(long_u fgcol)
+{
+ SetTextColor(prt_dlg.hDC, GetNearestColor(prt_dlg.hDC,
+ swap_me((COLORREF)fgcol)));
+}
+
+#endif /*FEAT_PRINTER && !FEAT_POSTSCRIPT*/
+
+
+
+#if defined(FEAT_SHORTCUT) || defined(PROTO)
+# ifndef PROTO
+# include <shlobj.h>
+# endif
+
+/*
+ * When "fname" is the name of a shortcut (*.lnk) resolve the file it points
+ * to and return that name in allocated memory.
+ * Otherwise NULL is returned.
+ */
+ char_u *
+mch_resolve_shortcut(char_u *fname)
+{
+ HRESULT hr;
+ IShellLink *psl = NULL;
+ IPersistFile *ppf = NULL;
+ OLECHAR wsz[MAX_PATH];
+ WIN32_FIND_DATA ffd; // we get those free of charge
+ CHAR buf[MAX_PATH]; // could have simply reused 'wsz'...
+ char_u *rfname = NULL;
+ int len;
+ IShellLinkW *pslw = NULL;
+ WIN32_FIND_DATAW ffdw; // we get those free of charge
+
+ /* Check if the file name ends in ".lnk". Avoid calling
+ * CoCreateInstance(), it's quite slow. */
+ if (fname == NULL)
+ return rfname;
+ len = (int)STRLEN(fname);
+ if (len <= 4 || STRNICMP(fname + len - 4, ".lnk", 4) != 0)
+ return rfname;
+
+ CoInitialize(NULL);
+
+ if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+ {
+ // create a link manager object and request its interface
+ hr = CoCreateInstance(
+ &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
+ &IID_IShellLinkW, (void**)&pslw);
+ if (hr == S_OK)
+ {
+ WCHAR *p = enc_to_utf16(fname, NULL);
+
+ if (p != NULL)
+ {
+ // Get a pointer to the IPersistFile interface.
+ hr = pslw->lpVtbl->QueryInterface(
+ pslw, &IID_IPersistFile, (void**)&ppf);
+ if (hr != S_OK)
+ goto shortcut_errorw;
+
+ // "load" the name and resolve the link
+ hr = ppf->lpVtbl->Load(ppf, p, STGM_READ);
+ if (hr != S_OK)
+ goto shortcut_errorw;
+# if 0 // This makes Vim wait a long time if the target does not exist.
+ hr = pslw->lpVtbl->Resolve(pslw, NULL, SLR_NO_UI);
+ if (hr != S_OK)
+ goto shortcut_errorw;
+# endif
+
+ // Get the path to the link target.
+ ZeroMemory(wsz, MAX_PATH * sizeof(WCHAR));
+ hr = pslw->lpVtbl->GetPath(pslw, wsz, MAX_PATH, &ffdw, 0);
+ if (hr == S_OK && wsz[0] != NUL)
+ rfname = utf16_to_enc(wsz, NULL);
+
+shortcut_errorw:
+ vim_free(p);
+ goto shortcut_end;
+ }
+ }
+ goto shortcut_end;
+ }
+ // create a link manager object and request its interface
+ hr = CoCreateInstance(
+ &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
+ &IID_IShellLink, (void**)&psl);
+ if (hr != S_OK)
+ goto shortcut_end;
+
+ // Get a pointer to the IPersistFile interface.
+ hr = psl->lpVtbl->QueryInterface(
+ psl, &IID_IPersistFile, (void**)&ppf);
+ if (hr != S_OK)
+ goto shortcut_end;
+
+ // full path string must be in Unicode.
+ MultiByteToWideChar(CP_ACP, 0, (LPCSTR)fname, -1, wsz, MAX_PATH);
+
+ // "load" the name and resolve the link
+ hr = ppf->lpVtbl->Load(ppf, wsz, STGM_READ);
+ if (hr != S_OK)
+ goto shortcut_end;
+# if 0 // This makes Vim wait a long time if the target doesn't exist.
+ hr = psl->lpVtbl->Resolve(psl, NULL, SLR_NO_UI);
+ if (hr != S_OK)
+ goto shortcut_end;
+# endif
+
+ // Get the path to the link target.
+ ZeroMemory(buf, MAX_PATH);
+ hr = psl->lpVtbl->GetPath(psl, buf, MAX_PATH, &ffd, 0);
+ if (hr == S_OK && buf[0] != NUL)
+ rfname = vim_strsave((char_u *)buf);
+
+shortcut_end:
+ // Release all interface pointers (both belong to the same object)
+ if (ppf != NULL)
+ ppf->lpVtbl->Release(ppf);
+ if (psl != NULL)
+ psl->lpVtbl->Release(psl);
+ if (pslw != NULL)
+ pslw->lpVtbl->Release(pslw);
+
+ CoUninitialize();
+ return rfname;
+}
+#endif
+
+#if (defined(FEAT_EVAL) && !defined(FEAT_GUI)) || defined(PROTO)
+/*
+ * Bring ourselves to the foreground. Does work if the OS doesn't allow it.
+ */
+ void
+win32_set_foreground(void)
+{
+# ifndef FEAT_GUI
+ GetConsoleHwnd(); /* get value of s_hwnd */
+# endif
+ if (s_hwnd != 0)
+ SetForegroundWindow(s_hwnd);
+}
+#endif
+
+#if defined(FEAT_CLIENTSERVER) || defined(PROTO)
+/*
+ * Client-server code for Vim
+ *
+ * Originally written by Paul Moore
+ */
+
+/* In order to handle inter-process messages, we need to have a window. But
+ * the functions in this module can be called before the main GUI window is
+ * created (and may also be called in the console version, where there is no
+ * GUI window at all).
+ *
+ * So we create a hidden window, and arrange to destroy it on exit.
+ */
+HWND message_window = 0; /* window that's handling messages */
+
+#define VIM_CLASSNAME "VIM_MESSAGES"
+#define VIM_CLASSNAME_LEN (sizeof(VIM_CLASSNAME) - 1)
+
+/* Communication is via WM_COPYDATA messages. The message type is send in
+ * the dwData parameter. Types are defined here. */
+#define COPYDATA_KEYS 0
+#define COPYDATA_REPLY 1
+#define COPYDATA_EXPR 10
+#define COPYDATA_RESULT 11
+#define COPYDATA_ERROR_RESULT 12
+#define COPYDATA_ENCODING 20
+
+/* This is a structure containing a server HWND and its name. */
+struct server_id
+{
+ HWND hwnd;
+ char_u *name;
+};
+
+/* Last received 'encoding' that the client uses. */
+static char_u *client_enc = NULL;
+
+/*
+ * Tell the other side what encoding we are using.
+ * Errors are ignored.
+ */
+ static void
+serverSendEnc(HWND target)
+{
+ COPYDATASTRUCT data;
+
+ data.dwData = COPYDATA_ENCODING;
+ data.cbData = (DWORD)STRLEN(p_enc) + 1;
+ data.lpData = p_enc;
+ (void)SendMessage(target, WM_COPYDATA, (WPARAM)message_window,
+ (LPARAM)(&data));
+}
+
+/*
+ * Clean up on exit. This destroys the hidden message window.
+ */
+ static void
+#ifdef __BORLANDC__
+ _RTLENTRYF
+#endif
+CleanUpMessaging(void)
+{
+ if (message_window != 0)
+ {
+ DestroyWindow(message_window);
+ message_window = 0;
+ }
+}
+
+static int save_reply(HWND server, char_u *reply, int expr);
+
+/*
+ * The window procedure for the hidden message window.
+ * It handles callback messages and notifications from servers.
+ * In order to process these messages, it is necessary to run a
+ * message loop. Code which may run before the main message loop
+ * is started (in the GUI) is careful to pump messages when it needs
+ * to. Features which require message delivery during normal use will
+ * not work in the console version - this basically means those
+ * features which allow Vim to act as a server, rather than a client.
+ */
+ static LRESULT CALLBACK
+Messaging_WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ if (msg == WM_COPYDATA)
+ {
+ /* This is a message from another Vim. The dwData member of the
+ * COPYDATASTRUCT determines the type of message:
+ * COPYDATA_ENCODING:
+ * The encoding that the client uses. Following messages will
+ * use this encoding, convert if needed.
+ * COPYDATA_KEYS:
+ * A key sequence. We are a server, and a client wants these keys
+ * adding to the input queue.
+ * COPYDATA_REPLY:
+ * A reply. We are a client, and a server has sent this message
+ * in response to a request. (server2client())
+ * COPYDATA_EXPR:
+ * An expression. We are a server, and a client wants us to
+ * evaluate this expression.
+ * COPYDATA_RESULT:
+ * A reply. We are a client, and a server has sent this message
+ * in response to a COPYDATA_EXPR.
+ * COPYDATA_ERROR_RESULT:
+ * A reply. We are a client, and a server has sent this message
+ * in response to a COPYDATA_EXPR that failed to evaluate.
+ */
+ COPYDATASTRUCT *data = (COPYDATASTRUCT*)lParam;
+ HWND sender = (HWND)wParam;
+ COPYDATASTRUCT reply;
+ char_u *res;
+ int retval;
+ char_u *str;
+ char_u *tofree;
+
+ switch (data->dwData)
+ {
+ case COPYDATA_ENCODING:
+ /* Remember the encoding that the client uses. */
+ vim_free(client_enc);
+ client_enc = enc_canonize((char_u *)data->lpData);
+ return 1;
+
+ case COPYDATA_KEYS:
+ /* Remember who sent this, for <client> */
+ clientWindow = sender;
+
+ /* Add the received keys to the input buffer. The loop waiting
+ * for the user to do something should check the input buffer. */
+ str = serverConvert(client_enc, (char_u *)data->lpData, &tofree);
+ server_to_input_buf(str);
+ vim_free(tofree);
+
+# ifdef FEAT_GUI
+ /* Wake up the main GUI loop. */
+ if (s_hwnd != 0)
+ PostMessage(s_hwnd, WM_NULL, 0, 0);
+# endif
+ return 1;
+
+ case COPYDATA_EXPR:
+ /* Remember who sent this, for <client> */
+ clientWindow = sender;
+
+ str = serverConvert(client_enc, (char_u *)data->lpData, &tofree);
+ res = eval_client_expr_to_string(str);
+
+ if (res == NULL)
+ {
+ char *err = _(e_invexprmsg);
+ size_t len = STRLEN(str) + STRLEN(err) + 5;
+
+ res = alloc((unsigned)len);
+ if (res != NULL)
+ vim_snprintf((char *)res, len, "%s: \"%s\"", err, str);
+ reply.dwData = COPYDATA_ERROR_RESULT;
+ }
+ else
+ reply.dwData = COPYDATA_RESULT;
+ reply.lpData = res;
+ reply.cbData = (DWORD)STRLEN(res) + 1;
+
+ serverSendEnc(sender);
+ retval = (int)SendMessage(sender, WM_COPYDATA,
+ (WPARAM)message_window, (LPARAM)(&reply));
+ vim_free(tofree);
+ vim_free(res);
+ return retval;
+
+ case COPYDATA_REPLY:
+ case COPYDATA_RESULT:
+ case COPYDATA_ERROR_RESULT:
+ if (data->lpData != NULL)
+ {
+ str = serverConvert(client_enc, (char_u *)data->lpData,
+ &tofree);
+ if (tofree == NULL)
+ str = vim_strsave(str);
+ if (save_reply(sender, str,
+ (data->dwData == COPYDATA_REPLY ? 0 :
+ (data->dwData == COPYDATA_RESULT ? 1 :
+ 2))) == FAIL)
+ vim_free(str);
+ else if (data->dwData == COPYDATA_REPLY)
+ {
+ char_u winstr[30];
+
+ sprintf((char *)winstr, PRINTF_HEX_LONG_U, (long_u)sender);
+ apply_autocmds(EVENT_REMOTEREPLY, winstr, str,
+ TRUE, curbuf);
+ }
+ }
+ return 1;
+ }
+
+ return 0;
+ }
+
+ else if (msg == WM_ACTIVATE && wParam == WA_ACTIVE)
+ {
+ /* When the message window is activated (brought to the foreground),
+ * this actually applies to the text window. */
+#ifndef FEAT_GUI
+ GetConsoleHwnd(); /* get value of s_hwnd */
+#endif
+ if (s_hwnd != 0)
+ {
+ SetForegroundWindow(s_hwnd);
+ return 0;
+ }
+ }
+
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+}
+
+/*
+ * Initialise the message handling process. This involves creating a window
+ * to handle messages - the window will not be visible.
+ */
+ void
+serverInitMessaging(void)
+{
+ WNDCLASS wndclass;
+ HINSTANCE s_hinst;
+
+ /* Clean up on exit */
+ atexit(CleanUpMessaging);
+
+ /* Register a window class - we only really care
+ * about the window procedure
+ */
+ s_hinst = (HINSTANCE)GetModuleHandle(0);
+ wndclass.style = 0;
+ wndclass.lpfnWndProc = Messaging_WndProc;
+ wndclass.cbClsExtra = 0;
+ wndclass.cbWndExtra = 0;
+ wndclass.hInstance = s_hinst;
+ wndclass.hIcon = NULL;
+ wndclass.hCursor = NULL;
+ wndclass.hbrBackground = NULL;
+ wndclass.lpszMenuName = NULL;
+ wndclass.lpszClassName = VIM_CLASSNAME;
+ RegisterClass(&wndclass);
+
+ /* Create the message window. It will be hidden, so the details don't
+ * matter. Don't use WS_OVERLAPPEDWINDOW, it will make a shortcut remove
+ * focus from gvim. */
+ message_window = CreateWindow(VIM_CLASSNAME, "",
+ WS_POPUPWINDOW | WS_CAPTION,
+ CW_USEDEFAULT, CW_USEDEFAULT,
+ 100, 100, NULL, NULL,
+ s_hinst, NULL);
+}
+
+/* Used by serverSendToVim() to find an alternate server name. */
+static char_u *altname_buf_ptr = NULL;
+
+/*
+ * Get the title of the window "hwnd", which is the Vim server name, in
+ * "name[namelen]" and return the length.
+ * Returns zero if window "hwnd" is not a Vim server.
+ */
+ static int
+getVimServerName(HWND hwnd, char *name, int namelen)
+{
+ int len;
+ char buffer[VIM_CLASSNAME_LEN + 1];
+
+ /* Ignore windows which aren't Vim message windows */
+ len = GetClassName(hwnd, buffer, sizeof(buffer));
+ if (len != VIM_CLASSNAME_LEN || STRCMP(buffer, VIM_CLASSNAME) != 0)
+ return 0;
+
+ /* Get the title of the window */
+ return GetWindowText(hwnd, name, namelen);
+}
+
+ static BOOL CALLBACK
+enumWindowsGetServer(HWND hwnd, LPARAM lparam)
+{
+ struct server_id *id = (struct server_id *)lparam;
+ char server[MAX_PATH];
+
+ /* Get the title of the window */
+ if (getVimServerName(hwnd, server, sizeof(server)) == 0)
+ return TRUE;
+
+ /* If this is the server we're looking for, return its HWND */
+ if (STRICMP(server, id->name) == 0)
+ {
+ id->hwnd = hwnd;
+ return FALSE;
+ }
+
+ /* If we are looking for an alternate server, remember this name. */
+ if (altname_buf_ptr != NULL
+ && STRNICMP(server, id->name, STRLEN(id->name)) == 0
+ && vim_isdigit(server[STRLEN(id->name)]))
+ {
+ STRCPY(altname_buf_ptr, server);
+ altname_buf_ptr = NULL; /* don't use another name */
+ }
+
+ /* Otherwise, keep looking */
+ return TRUE;
+}
+
+ static BOOL CALLBACK
+enumWindowsGetNames(HWND hwnd, LPARAM lparam)
+{
+ garray_T *ga = (garray_T *)lparam;
+ char server[MAX_PATH];
+
+ /* Get the title of the window */
+ if (getVimServerName(hwnd, server, sizeof(server)) == 0)
+ return TRUE;
+
+ /* Add the name to the list */
+ ga_concat(ga, (char_u *)server);
+ ga_concat(ga, (char_u *)"\n");
+ return TRUE;
+}
+
+struct enum_windows_s
+{
+ WNDENUMPROC lpEnumFunc;
+ LPARAM lParam;
+};
+
+ static BOOL CALLBACK
+enum_windows_child(HWND hwnd, LPARAM lParam)
+{
+ struct enum_windows_s *ew = (struct enum_windows_s *)lParam;
+
+ return (ew->lpEnumFunc)(hwnd, ew->lParam);
+}
+
+ static BOOL CALLBACK
+enum_windows_toplevel(HWND hwnd, LPARAM lParam)
+{
+ struct enum_windows_s *ew = (struct enum_windows_s *)lParam;
+
+ if ((ew->lpEnumFunc)(hwnd, ew->lParam))
+ return TRUE;
+ return EnumChildWindows(hwnd, enum_windows_child, lParam);
+}
+
+/* Enumerate all windows including children. */
+ static BOOL
+enum_windows(WNDENUMPROC lpEnumFunc, LPARAM lParam)
+{
+ struct enum_windows_s ew;
+
+ ew.lpEnumFunc = lpEnumFunc;
+ ew.lParam = lParam;
+ return EnumWindows(enum_windows_toplevel, (LPARAM)&ew);
+}
+
+ static HWND
+findServer(char_u *name)
+{
+ struct server_id id;
+
+ id.name = name;
+ id.hwnd = 0;
+
+ enum_windows(enumWindowsGetServer, (LPARAM)(&id));
+
+ return id.hwnd;
+}
+
+ void
+serverSetName(char_u *name)
+{
+ char_u *ok_name;
+ HWND hwnd = 0;
+ int i = 0;
+ char_u *p;
+
+ /* Leave enough space for a 9-digit suffix to ensure uniqueness! */
+ ok_name = alloc((unsigned)STRLEN(name) + 10);
+
+ STRCPY(ok_name, name);
+ p = ok_name + STRLEN(name);
+
+ for (;;)
+ {
+ /* This is inefficient - we're doing an EnumWindows loop for each
+ * possible name. It would be better to grab all names in one go,
+ * and scan the list each time...
+ */
+ hwnd = findServer(ok_name);
+ if (hwnd == 0)
+ break;
+
+ ++i;
+ if (i >= 1000)
+ break;
+
+ sprintf((char *)p, "%d", i);
+ }
+
+ if (hwnd != 0)
+ vim_free(ok_name);
+ else
+ {
+ /* Remember the name */
+ serverName = ok_name;
+#ifdef FEAT_TITLE
+ need_maketitle = TRUE; /* update Vim window title later */
+#endif
+
+ /* Update the message window title */
+ SetWindowText(message_window, (LPCSTR)ok_name);
+
+#ifdef FEAT_EVAL
+ /* Set the servername variable */
+ set_vim_var_string(VV_SEND_SERVER, serverName, -1);
+#endif
+ }
+}
+
+ char_u *
+serverGetVimNames(void)
+{
+ garray_T ga;
+
+ ga_init2(&ga, 1, 100);
+
+ enum_windows(enumWindowsGetNames, (LPARAM)(&ga));
+ ga_append(&ga, NUL);
+
+ return ga.ga_data;
+}
+
+ int
+serverSendReply(
+ char_u *name, /* Where to send. */
+ char_u *reply) /* What to send. */
+{
+ HWND target;
+ COPYDATASTRUCT data;
+ long_u n = 0;
+
+ /* The "name" argument is a magic cookie obtained from expand("<client>").
+ * It should be of the form 0xXXXXX - i.e. a C hex literal, which is the
+ * value of the client's message window HWND.
+ */
+ sscanf((char *)name, SCANF_HEX_LONG_U, &n);
+ if (n == 0)
+ return -1;
+
+ target = (HWND)n;
+ if (!IsWindow(target))
+ return -1;
+
+ data.dwData = COPYDATA_REPLY;
+ data.cbData = (DWORD)STRLEN(reply) + 1;
+ data.lpData = reply;
+
+ serverSendEnc(target);
+ if (SendMessage(target, WM_COPYDATA, (WPARAM)message_window,
+ (LPARAM)(&data)))
+ return 0;
+
+ return -1;
+}
+
+ int
+serverSendToVim(
+ char_u *name, /* Where to send. */
+ char_u *cmd, /* What to send. */
+ char_u **result, /* Result of eval'ed expression */
+ void *ptarget, /* HWND of server */
+ int asExpr, /* Expression or keys? */
+ int timeout, /* timeout in seconds or zero */
+ int silent) /* don't complain about no server */
+{
+ HWND target;
+ COPYDATASTRUCT data;
+ char_u *retval = NULL;
+ int retcode = 0;
+ char_u altname_buf[MAX_PATH];
+
+ /* Execute locally if no display or target is ourselves */
+ if (serverName != NULL && STRICMP(name, serverName) == 0)
+ return sendToLocalVim(cmd, asExpr, result);
+
+ /* If the server name does not end in a digit then we look for an
+ * alternate name. e.g. when "name" is GVIM the we may find GVIM2. */
+ if (STRLEN(name) > 1 && !vim_isdigit(name[STRLEN(name) - 1]))
+ altname_buf_ptr = altname_buf;
+ altname_buf[0] = NUL;
+ target = findServer(name);
+ altname_buf_ptr = NULL;
+ if (target == 0 && altname_buf[0] != NUL)
+ /* Use another server name we found. */
+ target = findServer(altname_buf);
+
+ if (target == 0)
+ {
+ if (!silent)
+ semsg(_(e_noserver), name);
+ return -1;
+ }
+
+ if (ptarget)
+ *(HWND *)ptarget = target;
+
+ data.dwData = asExpr ? COPYDATA_EXPR : COPYDATA_KEYS;
+ data.cbData = (DWORD)STRLEN(cmd) + 1;
+ data.lpData = cmd;
+
+ serverSendEnc(target);
+ if (SendMessage(target, WM_COPYDATA, (WPARAM)message_window,
+ (LPARAM)(&data)) == 0)
+ return -1;
+
+ if (asExpr)
+ retval = serverGetReply(target, &retcode, TRUE, TRUE, timeout);
+
+ if (result == NULL)
+ vim_free(retval);
+ else
+ *result = retval; /* Caller assumes responsibility for freeing */
+
+ return retcode;
+}
+
+/*
+ * Bring the server to the foreground.
+ */
+ void
+serverForeground(char_u *name)
+{
+ HWND target = findServer(name);
+
+ if (target != 0)
+ SetForegroundWindow(target);
+}
+
+/* Replies from server need to be stored until the client picks them up via
+ * remote_read(). So we maintain a list of server-id/reply pairs.
+ * Note that there could be multiple replies from one server pending if the
+ * client is slow picking them up.
+ * We just store the replies in a simple list. When we remove an entry, we
+ * move list entries down to fill the gap.
+ * The server ID is simply the HWND.
+ */
+typedef struct
+{
+ HWND server; /* server window */
+ char_u *reply; /* reply string */
+ int expr_result; /* 0 for REPLY, 1 for RESULT 2 for error */
+} reply_T;
+
+static garray_T reply_list = {0, 0, sizeof(reply_T), 5, 0};
+
+#define REPLY_ITEM(i) ((reply_T *)(reply_list.ga_data) + (i))
+#define REPLY_COUNT (reply_list.ga_len)
+
+/* Flag which is used to wait for a reply */
+static int reply_received = 0;
+
+/*
+ * Store a reply. "reply" must be allocated memory (or NULL).
+ */
+ static int
+save_reply(HWND server, char_u *reply, int expr)
+{
+ reply_T *rep;
+
+ if (ga_grow(&reply_list, 1) == FAIL)
+ return FAIL;
+
+ rep = REPLY_ITEM(REPLY_COUNT);
+ rep->server = server;
+ rep->reply = reply;
+ rep->expr_result = expr;
+ if (rep->reply == NULL)
+ return FAIL;
+
+ ++REPLY_COUNT;
+ reply_received = 1;
+ return OK;
+}
+
+/*
+ * Get a reply from server "server".
+ * When "expr_res" is non NULL, get the result of an expression, otherwise a
+ * server2client() message.
+ * When non NULL, point to return code. 0 => OK, -1 => ERROR
+ * If "remove" is TRUE, consume the message, the caller must free it then.
+ * if "wait" is TRUE block until a message arrives (or the server exits).
+ */
+ char_u *
+serverGetReply(HWND server, int *expr_res, int remove, int wait, int timeout)
+{
+ int i;
+ char_u *reply;
+ reply_T *rep;
+ int did_process = FALSE;
+ time_t start;
+ time_t now;
+
+ /* When waiting, loop until the message waiting for is received. */
+ time(&start);
+ for (;;)
+ {
+ /* Reset this here, in case a message arrives while we are going
+ * through the already received messages. */
+ reply_received = 0;
+
+ for (i = 0; i < REPLY_COUNT; ++i)
+ {
+ rep = REPLY_ITEM(i);
+ if (rep->server == server
+ && ((rep->expr_result != 0) == (expr_res != NULL)))
+ {
+ /* Save the values we've found for later */
+ reply = rep->reply;
+ if (expr_res != NULL)
+ *expr_res = rep->expr_result == 1 ? 0 : -1;
+
+ if (remove)
+ {
+ /* Move the rest of the list down to fill the gap */
+ mch_memmove(rep, rep + 1,
+ (REPLY_COUNT - i - 1) * sizeof(reply_T));
+ --REPLY_COUNT;
+ }
+
+ /* Return the reply to the caller, who takes on responsibility
+ * for freeing it if "remove" is TRUE. */
+ return reply;
+ }
+ }
+
+ /* If we got here, we didn't find a reply. Return immediately if the
+ * "wait" parameter isn't set. */
+ if (!wait)
+ {
+ /* Process pending messages once. Without this, looping on
+ * remote_peek() would never get the reply. */
+ if (!did_process)
+ {
+ did_process = TRUE;
+ serverProcessPendingMessages();
+ continue;
+ }
+ break;
+ }
+
+ /* We need to wait for a reply. Enter a message loop until the
+ * "reply_received" flag gets set. */
+
+ /* Loop until we receive a reply */
+ while (reply_received == 0)
+ {
+#ifdef FEAT_TIMERS
+ /* TODO: use the return value to decide how long to wait. */
+ check_due_timer();
+#endif
+ time(&now);
+ if (timeout > 0 && (now - start) >= timeout)
+ break;
+
+ /* Wait for a SendMessage() call to us. This could be the reply
+ * we are waiting for. Use a timeout of a second, to catch the
+ * situation that the server died unexpectedly. */
+ MsgWaitForMultipleObjects(0, NULL, TRUE, 1000, QS_ALLINPUT);
+
+ /* If the server has died, give up */
+ if (!IsWindow(server))
+ return NULL;
+
+ serverProcessPendingMessages();
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * Process any messages in the Windows message queue.
+ */
+ void
+serverProcessPendingMessages(void)
+{
+ MSG msg;
+
+ while (pPeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
+ {
+ TranslateMessage(&msg);
+ pDispatchMessage(&msg);
+ }
+}
+
+#endif /* FEAT_CLIENTSERVER */
+
+#if defined(FEAT_GUI) || (defined(FEAT_PRINTER) && !defined(FEAT_POSTSCRIPT)) \
+ || defined(PROTO)
+
+struct charset_pair
+{
+ char *name;
+ BYTE charset;
+};
+
+static struct charset_pair
+charset_pairs[] =
+{
+ {"ANSI", ANSI_CHARSET},
+ {"CHINESEBIG5", CHINESEBIG5_CHARSET},
+ {"DEFAULT", DEFAULT_CHARSET},
+ {"HANGEUL", HANGEUL_CHARSET},
+ {"OEM", OEM_CHARSET},
+ {"SHIFTJIS", SHIFTJIS_CHARSET},
+ {"SYMBOL", SYMBOL_CHARSET},
+ {"ARABIC", ARABIC_CHARSET},
+ {"BALTIC", BALTIC_CHARSET},
+ {"EASTEUROPE", EASTEUROPE_CHARSET},
+ {"GB2312", GB2312_CHARSET},
+ {"GREEK", GREEK_CHARSET},
+ {"HEBREW", HEBREW_CHARSET},
+ {"JOHAB", JOHAB_CHARSET},
+ {"MAC", MAC_CHARSET},
+ {"RUSSIAN", RUSSIAN_CHARSET},
+ {"THAI", THAI_CHARSET},
+ {"TURKISH", TURKISH_CHARSET},
+#ifdef VIETNAMESE_CHARSET
+ {"VIETNAMESE", VIETNAMESE_CHARSET},
+#endif
+ {NULL, 0}
+};
+
+struct quality_pair
+{
+ char *name;
+ DWORD quality;
+};
+
+static struct quality_pair
+quality_pairs[] = {
+#ifdef CLEARTYPE_QUALITY
+ {"CLEARTYPE", CLEARTYPE_QUALITY},
+#endif
+#ifdef ANTIALIASED_QUALITY
+ {"ANTIALIASED", ANTIALIASED_QUALITY},
+#endif
+#ifdef NONANTIALIASED_QUALITY
+ {"NONANTIALIASED", NONANTIALIASED_QUALITY},
+#endif
+#ifdef PROOF_QUALITY
+ {"PROOF", PROOF_QUALITY},
+#endif
+#ifdef DRAFT_QUALITY
+ {"DRAFT", DRAFT_QUALITY},
+#endif
+ {"DEFAULT", DEFAULT_QUALITY},
+ {NULL, 0}
+};
+
+/*
+ * Convert a charset ID to a name.
+ * Return NULL when not recognized.
+ */
+ char *
+charset_id2name(int id)
+{
+ struct charset_pair *cp;
+
+ for (cp = charset_pairs; cp->name != NULL; ++cp)
+ if ((BYTE)id == cp->charset)
+ break;
+ return cp->name;
+}
+
+/*
+ * Convert a quality ID to a name.
+ * Return NULL when not recognized.
+ */
+ char *
+quality_id2name(DWORD id)
+{
+ struct quality_pair *qp;
+
+ for (qp = quality_pairs; qp->name != NULL; ++qp)
+ if (id == qp->quality)
+ break;
+ return qp->name;
+}
+
+static const LOGFONT s_lfDefault =
+{
+ -12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET,
+ OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
+ PROOF_QUALITY, FIXED_PITCH | FF_DONTCARE,
+ "Fixedsys" /* see _ReadVimIni */
+};
+
+/* Initialise the "current height" to -12 (same as s_lfDefault) just
+ * in case the user specifies a font in "guifont" with no size before a font
+ * with an explicit size has been set. This defaults the size to this value
+ * (-12 equates to roughly 9pt).
+ */
+int current_font_height = -12; /* also used in gui_w48.c */
+
+/* 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.
+ */
+ static int
+points_to_pixels(char_u *str, char_u **end, int vertical, long_i pprinter_dc)
+{
+ int pixels;
+ int points = 0;
+ int divisor = 0;
+ HWND hwnd = (HWND)0;
+ HDC hdc;
+ HDC printer_dc = (HDC)pprinter_dc;
+
+ while (*str != NUL)
+ {
+ if (*str == '.' && divisor == 0)
+ {
+ /* Start keeping a divisor, for later */
+ divisor = 1;
+ }
+ else
+ {
+ if (!VIM_ISDIGIT(*str))
+ break;
+
+ points *= 10;
+ points += *str - '0';
+ divisor *= 10;
+ }
+ ++str;
+ }
+
+ if (divisor == 0)
+ divisor = 1;
+
+ if (printer_dc == NULL)
+ {
+ hwnd = GetDesktopWindow();
+ hdc = GetWindowDC(hwnd);
+ }
+ else
+ hdc = printer_dc;
+
+ pixels = MulDiv(points,
+ GetDeviceCaps(hdc, vertical ? LOGPIXELSY : LOGPIXELSX),
+ 72 * divisor);
+
+ if (printer_dc == NULL)
+ ReleaseDC(hwnd, hdc);
+
+ *end = str;
+ return pixels;
+}
+
+ static int CALLBACK
+font_enumproc(
+ ENUMLOGFONT *elf,
+ NEWTEXTMETRIC *ntm UNUSED,
+ int type UNUSED,
+ LPARAM lparam)
+{
+ /* Return value:
+ * 0 = terminate now (monospace & ANSI)
+ * 1 = continue, still no luck...
+ * 2 = continue, but we have an acceptable LOGFONT
+ * (monospace, not ANSI)
+ * We use these values, as EnumFontFamilies returns 1 if the
+ * callback function is never called. So, we check the return as
+ * 0 = perfect, 2 = OK, 1 = no good...
+ * It's not pretty, but it works!
+ */
+
+ LOGFONT *lf = (LOGFONT *)(lparam);
+
+#ifndef FEAT_PROPORTIONAL_FONTS
+ /* Ignore non-monospace fonts without further ado */
+ if ((ntm->tmPitchAndFamily & 1) != 0)
+ return 1;
+#endif
+
+ /* Remember this LOGFONT as a "possible" */
+ *lf = elf->elfLogFont;
+
+ /* Terminate the scan as soon as we find an ANSI font */
+ if (lf->lfCharSet == ANSI_CHARSET
+ || lf->lfCharSet == OEM_CHARSET
+ || lf->lfCharSet == DEFAULT_CHARSET)
+ return 0;
+
+ /* Continue the scan - we have a non-ANSI font */
+ return 2;
+}
+
+ static int
+init_logfont(LOGFONT *lf)
+{
+ int n;
+ HWND hwnd = GetDesktopWindow();
+ HDC hdc = GetWindowDC(hwnd);
+
+ n = EnumFontFamilies(hdc,
+ (LPCSTR)lf->lfFaceName,
+ (FONTENUMPROC)font_enumproc,
+ (LPARAM)lf);
+
+ ReleaseDC(hwnd, hdc);
+
+ /* If we couldn't find a usable font, return failure */
+ if (n == 1)
+ return FAIL;
+
+ /* Tidy up the rest of the LOGFONT structure. We set to a basic
+ * font - get_logfont() sets bold, italic, etc based on the user's
+ * input.
+ */
+ lf->lfHeight = current_font_height;
+ lf->lfWidth = 0;
+ lf->lfItalic = FALSE;
+ lf->lfUnderline = FALSE;
+ lf->lfStrikeOut = FALSE;
+ lf->lfWeight = FW_NORMAL;
+
+ /* Return success */
+ return OK;
+}
+
+/*
+ * Get font info from "name" into logfont "lf".
+ * Return OK for a valid name, FAIL otherwise.
+ */
+ int
+get_logfont(
+ LOGFONT *lf,
+ char_u *name,
+ HDC printer_dc,
+ int verbose)
+{
+ char_u *p;
+ int i;
+ int ret = FAIL;
+ static LOGFONT *lastlf = NULL;
+ char_u *acpname = NULL;
+
+ *lf = s_lfDefault;
+ if (name == NULL)
+ return OK;
+
+ /* Convert 'name' from 'encoding' to the current codepage, because
+ * lf->lfFaceName uses the current codepage.
+ * TODO: Use Wide APIs instead of ANSI APIs. */
+ if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+ {
+ int len;
+ enc_to_acp(name, (int)STRLEN(name), &acpname, &len);
+ name = acpname;
+ }
+ if (STRCMP(name, "*") == 0)
+ {
+#if defined(FEAT_GUI_W32)
+ CHOOSEFONT cf;
+ /* if name is "*", bring up std font dialog: */
+ vim_memset(&cf, 0, sizeof(cf));
+ cf.lStructSize = sizeof(cf);
+ cf.hwndOwner = s_hwnd;
+ cf.Flags = CF_SCREENFONTS | CF_FIXEDPITCHONLY | CF_INITTOLOGFONTSTRUCT;
+ if (lastlf != NULL)
+ *lf = *lastlf;
+ cf.lpLogFont = lf;
+ cf.nFontType = 0 ; //REGULAR_FONTTYPE;
+ if (ChooseFont(&cf))
+ ret = OK;
+#endif
+ goto theend;
+ }
+
+ /*
+ * Split name up, it could be <name>:h<height>:w<width> etc.
+ */
+ for (p = name; *p && *p != ':'; p++)
+ {
+ if (p - name + 1 >= LF_FACESIZE)
+ goto theend; /* Name too long */
+ lf->lfFaceName[p - name] = *p;
+ }
+ if (p != name)
+ lf->lfFaceName[p - name] = NUL;
+
+ /* First set defaults */
+ lf->lfHeight = -12;
+ lf->lfWidth = 0;
+ lf->lfWeight = FW_NORMAL;
+ lf->lfItalic = FALSE;
+ lf->lfUnderline = FALSE;
+ lf->lfStrikeOut = FALSE;
+
+ /*
+ * If the font can't be found, try replacing '_' by ' '.
+ */
+ if (init_logfont(lf) == FAIL)
+ {
+ int did_replace = FALSE;
+
+ for (i = 0; lf->lfFaceName[i]; ++i)
+ if (IsDBCSLeadByte(lf->lfFaceName[i]))
+ ++i;
+ else if (lf->lfFaceName[i] == '_')
+ {
+ lf->lfFaceName[i] = ' ';
+ did_replace = TRUE;
+ }
+ if (!did_replace || init_logfont(lf) == FAIL)
+ goto theend;
+ }
+
+ while (*p == ':')
+ p++;
+
+ /* Set the values found after ':' */
+ while (*p)
+ {
+ switch (*p++)
+ {
+ case 'h':
+ lf->lfHeight = - points_to_pixels(p, &p, TRUE, (long_i)printer_dc);
+ break;
+ case 'w':
+ lf->lfWidth = points_to_pixels(p, &p, FALSE, (long_i)printer_dc);
+ break;
+ case 'b':
+ lf->lfWeight = FW_BOLD;
+ break;
+ case 'i':
+ lf->lfItalic = TRUE;
+ break;
+ case 'u':
+ lf->lfUnderline = TRUE;
+ break;
+ case 's':
+ lf->lfStrikeOut = TRUE;
+ break;
+ case 'c':
+ {
+ struct charset_pair *cp;
+
+ for (cp = charset_pairs; cp->name != NULL; ++cp)
+ if (STRNCMP(p, cp->name, strlen(cp->name)) == 0)
+ {
+ lf->lfCharSet = cp->charset;
+ p += strlen(cp->name);
+ break;
+ }
+ if (cp->name == NULL && verbose)
+ {
+ semsg(_("E244: Illegal charset name \"%s\" in font name \"%s\""), p, name);
+ break;
+ }
+ break;
+ }
+ case 'q':
+ {
+ struct quality_pair *qp;
+
+ for (qp = quality_pairs; qp->name != NULL; ++qp)
+ if (STRNCMP(p, qp->name, strlen(qp->name)) == 0)
+ {
+ lf->lfQuality = qp->quality;
+ p += strlen(qp->name);
+ break;
+ }
+ if (qp->name == NULL && verbose)
+ {
+ semsg(_("E244: Illegal quality name \"%s\" in font name \"%s\""), p, name);
+ break;
+ }
+ break;
+ }
+ default:
+ if (verbose)
+ semsg(_("E245: Illegal char '%c' in font name \"%s\""), p[-1], name);
+ goto theend;
+ }
+ while (*p == ':')
+ p++;
+ }
+ ret = OK;
+
+theend:
+ /* ron: init lastlf */
+ if (ret == OK && printer_dc == NULL)
+ {
+ vim_free(lastlf);
+ lastlf = (LOGFONT *)alloc(sizeof(LOGFONT));
+ if (lastlf != NULL)
+ mch_memmove(lastlf, lf, sizeof(LOGFONT));
+ }
+ vim_free(acpname);
+
+ return ret;
+}
+
+#endif /* defined(FEAT_GUI) || defined(FEAT_PRINTER) */
+
+#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
+/*
+ * Initialize the Winsock dll.
+ */
+ void
+channel_init_winsock(void)
+{
+ WSADATA wsaData;
+ int wsaerr;
+
+ if (WSInitialized)
+ return;
+
+ wsaerr = WSAStartup(MAKEWORD(2, 2), &wsaData);
+ if (wsaerr == 0)
+ WSInitialized = TRUE;
+}
+#endif
diff --git a/src/os_qnx.c b/src/os_qnx.c
new file mode 100644
index 0000000..b121f3d
--- /dev/null
+++ b/src/os_qnx.c
@@ -0,0 +1,157 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * QNX port by Julian Kinraid
+ *
+ * Do ":help uganda" in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ */
+
+/*
+ * os_qnx.c
+ */
+
+#include "vim.h"
+
+
+#if defined(FEAT_GUI_PHOTON)
+int is_photon_available;
+#endif
+
+void qnx_init(void)
+{
+#if defined(FEAT_GUI_PHOTON)
+ PhChannelParms_t parms;
+
+ memset(&parms, 0, sizeof(parms));
+ parms.flags = Ph_DYNAMIC_BUFFER;
+
+ is_photon_available = (PhAttach(NULL, &parms) != NULL) ? TRUE : FALSE;
+#endif
+}
+
+#if (defined(FEAT_GUI_PHOTON) && defined(FEAT_CLIPBOARD)) || defined(PROTO)
+
+#define CLIP_TYPE_VIM "VIMTYPE"
+#define CLIP_TYPE_TEXT "TEXT"
+
+/* Turn on the clipboard for a console vim when photon is running */
+void qnx_clip_init(void)
+{
+ if (is_photon_available == TRUE && !gui.in_use)
+ clip_init(TRUE);
+}
+
+/*****************************************************************************/
+/* Clipboard */
+
+/* No support for owning the clipboard */
+int
+clip_mch_own_selection(VimClipboard *cbd)
+{
+ return FALSE;
+}
+
+void
+clip_mch_lose_selection(VimClipboard *cbd)
+{
+}
+
+void
+clip_mch_request_selection(VimClipboard *cbd)
+{
+ int type = MLINE, clip_length = 0, is_type_set = FALSE;
+ void *cbdata;
+ PhClipHeader *clip_header;
+ char_u *clip_text = NULL;
+
+ cbdata = PhClipboardPasteStart(PhInputGroup(NULL));
+ if (cbdata != NULL)
+ {
+ /* Look for the vim specific clip first */
+ clip_header = PhClipboardPasteType(cbdata, CLIP_TYPE_VIM);
+ if (clip_header != NULL && clip_header->data != NULL)
+ {
+ switch(*(char *) clip_header->data)
+ {
+ default: /* fallthrough to line type */
+ case 'L': type = MLINE; break;
+ case 'C': type = MCHAR; break;
+ case 'B': type = MBLOCK; break;
+ }
+ is_type_set = TRUE;
+ }
+
+ /* Try for just normal text */
+ clip_header = PhClipboardPasteType(cbdata, CLIP_TYPE_TEXT);
+ if (clip_header != NULL)
+ {
+ clip_text = clip_header->data;
+ clip_length = clip_header->length - 1;
+
+ if (clip_text != NULL && is_type_set == FALSE)
+ type = MAUTO;
+ }
+
+ if ((clip_text != NULL) && (clip_length > 0))
+ {
+ clip_yank_selection(type, clip_text, clip_length, cbd);
+ }
+
+ PhClipboardPasteFinish(cbdata);
+ }
+}
+
+void
+clip_mch_set_selection(VimClipboard *cbd)
+{
+ int type;
+ long_u len;
+ char_u *text_clip, vim_clip[2], *str = NULL;
+ PhClipHeader clip_header[2];
+
+ /* Prevent recursion from clip_get_selection() */
+ if (cbd->owned == TRUE)
+ return;
+
+ cbd->owned = TRUE;
+ clip_get_selection(cbd);
+ cbd->owned = FALSE;
+
+ type = clip_convert_selection(&str, &len, cbd);
+ if (type >= 0)
+ {
+ text_clip = lalloc(len + 1, TRUE); /* Normal text */
+
+ if (text_clip && vim_clip)
+ {
+ memset(clip_header, 0, sizeof(clip_header));
+
+ STRNCPY(clip_header[0].type, CLIP_TYPE_VIM, 8);
+ clip_header[0].length = sizeof(vim_clip);
+ clip_header[0].data = vim_clip;
+
+ STRNCPY(clip_header[1].type, CLIP_TYPE_TEXT, 8);
+ clip_header[1].length = len + 1;
+ clip_header[1].data = text_clip;
+
+ switch(type)
+ {
+ default: /* fallthrough to MLINE */
+ case MLINE: *vim_clip = 'L'; break;
+ case MCHAR: *vim_clip = 'C'; break;
+ case MBLOCK: *vim_clip = 'B'; break;
+ }
+
+ vim_strncpy(text_clip, str, len);
+
+ vim_clip[ 1 ] = NUL;
+
+ PhClipboardCopy(PhInputGroup(NULL), 2, clip_header);
+ }
+ vim_free(text_clip);
+ }
+ vim_free(str);
+}
+#endif
diff --git a/src/os_qnx.h b/src/os_qnx.h
new file mode 100644
index 0000000..f98e311
--- /dev/null
+++ b/src/os_qnx.h
@@ -0,0 +1,19 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * Do ":help uganda" in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ */
+
+#ifdef __QNXNTO__
+# include <sys/procmgr.h>
+#endif
+
+#define USE_TMPNAM
+
+#define POSIX /* Used by pty.c */
+
+#if defined(FEAT_GUI_PHOTON)
+extern int is_photon_available;
+#endif
diff --git a/src/os_unix.c b/src/os_unix.c
new file mode 100644
index 0000000..a17abe3
--- /dev/null
+++ b/src/os_unix.c
@@ -0,0 +1,8113 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ * OS/2 port by Paul Slootman
+ * VMS merge by Zoltan Arpadffy
+ *
+ * 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.
+ */
+
+/*
+ * os_unix.c -- code for all flavors of Unix (BSD, SYSV, SVR4, POSIX, ...)
+ * Also for OS/2, using the excellent EMX package!!!
+ * Also for BeOS and Atari MiNT.
+ *
+ * A lot of this file was originally written by Juergen Weigert and later
+ * changed beyond recognition.
+ */
+
+#include "vim.h"
+
+#ifdef FEAT_MZSCHEME
+# include "if_mzsch.h"
+#endif
+
+#include "os_unixx.h" /* unix includes for os_unix.c only */
+
+#ifdef USE_XSMP
+# include <X11/SM/SMlib.h>
+#endif
+
+#ifdef HAVE_SELINUX
+# include <selinux/selinux.h>
+static int selinux_enabled = -1;
+#endif
+
+#ifdef HAVE_SMACK
+# include <attr/xattr.h>
+# include <linux/xattr.h>
+# ifndef SMACK_LABEL_LEN
+# define SMACK_LABEL_LEN 1024
+# endif
+#endif
+
+#ifdef __BEOS__
+# undef select
+# define select beos_select
+#endif
+
+#ifdef __CYGWIN__
+# ifndef WIN32
+# include <cygwin/version.h>
+# include <sys/cygwin.h> /* for cygwin_conv_to_posix_path() and/or
+ * for cygwin_conv_path() */
+# ifdef FEAT_CYGWIN_WIN32_CLIPBOARD
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+# include "winclip.pro"
+# endif
+# endif
+#endif
+
+#ifdef FEAT_MOUSE_GPM
+# include <gpm.h>
+/* <linux/keyboard.h> contains defines conflicting with "keymap.h",
+ * I just copied relevant defines here. A cleaner solution would be to put gpm
+ * code into separate file and include there linux/keyboard.h
+ */
+/* #include <linux/keyboard.h> */
+# define KG_SHIFT 0
+# define KG_CTRL 2
+# define KG_ALT 3
+# define KG_ALTGR 1
+# define KG_SHIFTL 4
+# define KG_SHIFTR 5
+# define KG_CTRLL 6
+# define KG_CTRLR 7
+# define KG_CAPSSHIFT 8
+
+static void gpm_close(void);
+static int gpm_open(void);
+static int mch_gpm_process(void);
+#endif
+
+#ifdef FEAT_SYSMOUSE
+# include <sys/consio.h>
+# include <sys/fbio.h>
+
+static int sysmouse_open(void);
+static void sysmouse_close(void);
+static RETSIGTYPE sig_sysmouse SIGPROTOARG;
+#endif
+
+/*
+ * end of autoconf section. To be extended...
+ */
+
+/* Are the following #ifdefs still required? And why? Is that for X11? */
+
+#if defined(ESIX) || defined(M_UNIX) && !defined(SCO)
+# ifdef SIGWINCH
+# undef SIGWINCH
+# endif
+# ifdef TIOCGWINSZ
+# undef TIOCGWINSZ
+# endif
+#endif
+
+#if defined(SIGWINDOW) && !defined(SIGWINCH) /* hpux 9.01 has it */
+# define SIGWINCH SIGWINDOW
+#endif
+
+#ifdef FEAT_X11
+# include <X11/Xlib.h>
+# include <X11/Xutil.h>
+# include <X11/Xatom.h>
+# ifdef FEAT_XCLIPBOARD
+# include <X11/Intrinsic.h>
+# include <X11/Shell.h>
+# include <X11/StringDefs.h>
+static Widget xterm_Shell = (Widget)0;
+static void clip_update(void);
+static void xterm_update(void);
+# endif
+
+# if defined(FEAT_XCLIPBOARD) || defined(FEAT_TITLE)
+Window x11_window = 0;
+# endif
+Display *x11_display = NULL;
+#endif
+
+#ifdef FEAT_TITLE
+static int get_x11_title(int);
+
+static char_u *oldtitle = NULL;
+static volatile sig_atomic_t oldtitle_outdated = FALSE;
+static int did_set_title = FALSE;
+static char_u *oldicon = NULL;
+static int did_set_icon = FALSE;
+#endif
+
+static void may_core_dump(void);
+
+#ifdef HAVE_UNION_WAIT
+typedef union wait waitstatus;
+#else
+typedef int waitstatus;
+#endif
+static int WaitForChar(long msec, int *interrupted, int ignore_input);
+static int WaitForCharOrMouse(long msec, int *interrupted, int ignore_input);
+#if defined(__BEOS__) || defined(VMS)
+int RealWaitForChar(int, long, int *, int *interrupted);
+#else
+static int RealWaitForChar(int, long, int *, int *interrupted);
+#endif
+
+#ifdef FEAT_XCLIPBOARD
+static int do_xterm_trace(void);
+# define XT_TRACE_DELAY 50 /* delay for xterm tracing */
+#endif
+
+static void handle_resize(void);
+
+#if defined(SIGWINCH)
+static RETSIGTYPE sig_winch SIGPROTOARG;
+#endif
+#if defined(SIGINT)
+static RETSIGTYPE catch_sigint SIGPROTOARG;
+#endif
+#if defined(SIGPWR)
+static RETSIGTYPE catch_sigpwr SIGPROTOARG;
+#endif
+#if defined(SIGALRM) && defined(FEAT_X11) \
+ && defined(FEAT_TITLE) && !defined(FEAT_GUI_GTK)
+# define SET_SIG_ALARM
+static RETSIGTYPE sig_alarm SIGPROTOARG;
+/* volatile because it is used in signal handler sig_alarm(). */
+static volatile sig_atomic_t sig_alarm_called;
+#endif
+static RETSIGTYPE deathtrap SIGPROTOARG;
+
+static void catch_int_signal(void);
+static void set_signals(void);
+static void catch_signals(RETSIGTYPE (*func_deadly)(), RETSIGTYPE (*func_other)());
+#ifdef HAVE_SIGPROCMASK
+# define SIGSET_DECL(set) sigset_t set;
+# define BLOCK_SIGNALS(set) block_signals(set)
+# define UNBLOCK_SIGNALS(set) unblock_signals(set)
+#else
+# define SIGSET_DECL(set)
+# define BLOCK_SIGNALS(set) do { /**/ } while (0)
+# define UNBLOCK_SIGNALS(set) do { /**/ } while (0)
+#endif
+static int have_wildcard(int, char_u **);
+static int have_dollars(int, char_u **);
+
+static int save_patterns(int num_pat, char_u **pat, int *num_file, char_u ***file);
+
+#ifndef SIG_ERR
+# define SIG_ERR ((RETSIGTYPE (*)())-1)
+#endif
+
+/* volatile because it is used in signal handler sig_winch(). */
+static volatile sig_atomic_t do_resize = FALSE;
+static char_u *extra_shell_arg = NULL;
+static int show_shell_mess = TRUE;
+/* volatile because it is used in signal handler deathtrap(). */
+static volatile sig_atomic_t deadly_signal = 0; /* The signal we caught */
+/* volatile because it is used in signal handler deathtrap(). */
+static volatile sig_atomic_t in_mch_delay = FALSE; /* sleeping in mch_delay() */
+
+#if defined(FEAT_JOB_CHANNEL) && !defined(USE_SYSTEM)
+static int dont_check_job_ended = 0;
+#endif
+
+static int curr_tmode = TMODE_COOK; /* contains current terminal mode */
+
+#ifdef USE_XSMP
+typedef struct
+{
+ SmcConn smcconn; /* The SM connection ID */
+ IceConn iceconn; /* The ICE connection ID */
+ char *clientid; /* The client ID for the current smc session */
+ Bool save_yourself; /* If we're in the middle of a save_yourself */
+ Bool shutdown; /* If we're in shutdown mode */
+} xsmp_config_T;
+
+static xsmp_config_T xsmp;
+#endif
+
+#ifdef SYS_SIGLIST_DECLARED
+/*
+ * I have seen
+ * extern char *_sys_siglist[NSIG];
+ * on Irix, Linux, NetBSD and Solaris. It contains a nice list of strings
+ * that describe the signals. That is nearly what we want here. But
+ * autoconf does only check for sys_siglist (without the underscore), I
+ * do not want to change everything today.... jw.
+ * This is why AC_DECL_SYS_SIGLIST is commented out in configure.ac.
+ */
+#endif
+
+static struct signalinfo
+{
+ int sig; /* Signal number, eg. SIGSEGV etc */
+ char *name; /* Signal name (not char_u!). */
+ char deadly; /* Catch as a deadly signal? */
+} signal_info[] =
+{
+#ifdef SIGHUP
+ {SIGHUP, "HUP", TRUE},
+#endif
+#ifdef SIGQUIT
+ {SIGQUIT, "QUIT", TRUE},
+#endif
+#ifdef SIGILL
+ {SIGILL, "ILL", TRUE},
+#endif
+#ifdef SIGTRAP
+ {SIGTRAP, "TRAP", TRUE},
+#endif
+#ifdef SIGABRT
+ {SIGABRT, "ABRT", TRUE},
+#endif
+#ifdef SIGEMT
+ {SIGEMT, "EMT", TRUE},
+#endif
+#ifdef SIGFPE
+ {SIGFPE, "FPE", TRUE},
+#endif
+#ifdef SIGBUS
+ {SIGBUS, "BUS", TRUE},
+#endif
+#if defined(SIGSEGV) && !defined(FEAT_MZSCHEME)
+ /* MzScheme uses SEGV in its garbage collector */
+ {SIGSEGV, "SEGV", TRUE},
+#endif
+#ifdef SIGSYS
+ {SIGSYS, "SYS", TRUE},
+#endif
+#ifdef SIGALRM
+ {SIGALRM, "ALRM", FALSE}, /* Perl's alarm() can trigger it */
+#endif
+#ifdef SIGTERM
+ {SIGTERM, "TERM", TRUE},
+#endif
+#if defined(SIGVTALRM) && !defined(FEAT_RUBY)
+ {SIGVTALRM, "VTALRM", TRUE},
+#endif
+#if defined(SIGPROF) && !defined(FEAT_MZSCHEME) && !defined(WE_ARE_PROFILING)
+ /* MzScheme uses SIGPROF for its own needs; On Linux with profiling
+ * this makes Vim exit. WE_ARE_PROFILING is defined in Makefile. */
+ {SIGPROF, "PROF", TRUE},
+#endif
+#ifdef SIGXCPU
+ {SIGXCPU, "XCPU", TRUE},
+#endif
+#ifdef SIGXFSZ
+ {SIGXFSZ, "XFSZ", TRUE},
+#endif
+#ifdef SIGUSR1
+ {SIGUSR1, "USR1", TRUE},
+#endif
+#if defined(SIGUSR2) && !defined(FEAT_SYSMOUSE)
+ /* Used for sysmouse handling */
+ {SIGUSR2, "USR2", TRUE},
+#endif
+#ifdef SIGINT
+ {SIGINT, "INT", FALSE},
+#endif
+#ifdef SIGWINCH
+ {SIGWINCH, "WINCH", FALSE},
+#endif
+#ifdef SIGTSTP
+ {SIGTSTP, "TSTP", FALSE},
+#endif
+#ifdef SIGPIPE
+ {SIGPIPE, "PIPE", FALSE},
+#endif
+ {-1, "Unknown!", FALSE}
+};
+
+ int
+mch_chdir(char *path)
+{
+ if (p_verbose >= 5)
+ {
+ verbose_enter();
+ smsg("chdir(%s)", path);
+ verbose_leave();
+ }
+# ifdef VMS
+ return chdir(vms_fixfilename(path));
+# else
+ return chdir(path);
+# endif
+}
+
+/* Why is NeXT excluded here (and not in os_unixx.h)? */
+#if defined(ECHOE) && defined(ICANON) \
+ && (defined(HAVE_TERMIO_H) || defined(HAVE_TERMIOS_H)) \
+ && !defined(__NeXT__)
+# define NEW_TTY_SYSTEM
+#endif
+
+/*
+ * Write s[len] to the screen (stdout).
+ */
+ void
+mch_write(char_u *s, int len)
+{
+ vim_ignored = (int)write(1, (char *)s, len);
+ if (p_wd) /* Unix is too fast, slow down a bit more */
+ RealWaitForChar(read_cmd_fd, p_wd, NULL, NULL);
+}
+
+/*
+ * Function passed to inchar_loop() to handle window resizing.
+ * If "check_only" is TRUE: Return whether there was a resize.
+ * If "check_only" is FALSE: Deal with the window resized.
+ */
+ static int
+resize_func(int check_only)
+{
+ if (check_only)
+ return do_resize;
+ while (do_resize)
+ handle_resize();
+ return FALSE;
+}
+
+/*
+ * mch_inchar(): low level input function.
+ * Get a characters from the keyboard.
+ * Return the number of characters that are available.
+ * If wtime == 0 do not wait for characters.
+ * If wtime == n wait a short time for characters.
+ * If wtime == -1 wait forever for characters.
+ */
+ int
+mch_inchar(
+ char_u *buf,
+ int maxlen,
+ long wtime, /* don't use "time", MIPS cannot handle it */
+ int tb_change_cnt)
+{
+ return inchar_loop(buf, maxlen, wtime, tb_change_cnt,
+ WaitForChar, resize_func);
+}
+
+ static void
+handle_resize(void)
+{
+ do_resize = FALSE;
+ shell_resized();
+}
+
+/*
+ * Return non-zero if a character is available.
+ */
+ int
+mch_char_avail(void)
+{
+ return WaitForChar(0L, NULL, FALSE);
+}
+
+#if defined(FEAT_TERMINAL) || defined(PROTO)
+/*
+ * Check for any pending input or messages.
+ */
+ int
+mch_check_messages(void)
+{
+ return WaitForChar(0L, NULL, TRUE);
+}
+#endif
+
+#if defined(HAVE_TOTAL_MEM) || defined(PROTO)
+# ifdef HAVE_SYS_RESOURCE_H
+# include <sys/resource.h>
+# endif
+# if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_SYSCTL)
+# include <sys/sysctl.h>
+# endif
+# if defined(HAVE_SYS_SYSINFO_H) && defined(HAVE_SYSINFO)
+# include <sys/sysinfo.h>
+# endif
+# ifdef MACOS_X
+# include <mach/mach_host.h>
+# include <mach/mach_port.h>
+# endif
+
+/*
+ * Return total amount of memory available in Kbyte.
+ * Doesn't change when memory has been allocated.
+ */
+ long_u
+mch_total_mem(int special UNUSED)
+{
+ long_u mem = 0;
+ long_u shiftright = 10; /* how much to shift "mem" right for Kbyte */
+
+# ifdef MACOS_X
+ {
+ /* Mac (Darwin) way of getting the amount of RAM available */
+ mach_port_t host = mach_host_self();
+ kern_return_t kret;
+# ifdef HOST_VM_INFO64
+ struct vm_statistics64 vm_stat;
+ natural_t count = HOST_VM_INFO64_COUNT;
+
+ kret = host_statistics64(host, HOST_VM_INFO64,
+ (host_info64_t)&vm_stat, &count);
+# else
+ struct vm_statistics vm_stat;
+ natural_t count = HOST_VM_INFO_COUNT;
+
+ kret = host_statistics(host, HOST_VM_INFO,
+ (host_info_t)&vm_stat, &count);
+# endif
+ if (kret == KERN_SUCCESS)
+ /* get the amount of user memory by summing each usage */
+ mem = (long_u)(vm_stat.free_count + vm_stat.active_count
+ + vm_stat.inactive_count
+# ifdef MAC_OS_X_VERSION_10_9
+ + vm_stat.compressor_page_count
+# endif
+ ) * sysconf(_SC_PAGESIZE);
+ mach_port_deallocate(mach_task_self(), host);
+ }
+# endif
+
+# ifdef HAVE_SYSCTL
+ if (mem == 0)
+ {
+ /* BSD way of getting the amount of RAM available. */
+ int mib[2];
+ size_t len = sizeof(long_u);
+# ifdef HW_USERMEM64
+ long_u physmem;
+# else
+ /* sysctl() may return 32 bit or 64 bit, accept both */
+ union {
+ int_u u32;
+ long_u u64;
+ } physmem;
+# endif
+
+ mib[0] = CTL_HW;
+# ifdef HW_USERMEM64
+ mib[1] = HW_USERMEM64;
+# else
+ mib[1] = HW_USERMEM;
+# endif
+ if (sysctl(mib, 2, &physmem, &len, NULL, 0) == 0)
+ {
+# ifdef HW_USERMEM64
+ mem = (long_u)physmem;
+# else
+ if (len == sizeof(physmem.u64))
+ mem = (long_u)physmem.u64;
+ else
+ mem = (long_u)physmem.u32;
+# endif
+ }
+ }
+# endif
+
+# if defined(HAVE_SYS_SYSINFO_H) && defined(HAVE_SYSINFO)
+ if (mem == 0)
+ {
+ struct sysinfo sinfo;
+
+ /* Linux way of getting amount of RAM available */
+ if (sysinfo(&sinfo) == 0)
+ {
+# ifdef HAVE_SYSINFO_MEM_UNIT
+ /* avoid overflow as much as possible */
+ while (shiftright > 0 && (sinfo.mem_unit & 1) == 0)
+ {
+ sinfo.mem_unit = sinfo.mem_unit >> 1;
+ --shiftright;
+ }
+ mem = sinfo.totalram * sinfo.mem_unit;
+# else
+ mem = sinfo.totalram;
+# endif
+ }
+ }
+# endif
+
+# ifdef HAVE_SYSCONF
+ if (mem == 0)
+ {
+ long pagesize, pagecount;
+
+ /* Solaris way of getting amount of RAM available */
+ pagesize = sysconf(_SC_PAGESIZE);
+ pagecount = sysconf(_SC_PHYS_PAGES);
+ if (pagesize > 0 && pagecount > 0)
+ {
+ /* avoid overflow as much as possible */
+ while (shiftright > 0 && (pagesize & 1) == 0)
+ {
+ pagesize = (long_u)pagesize >> 1;
+ --shiftright;
+ }
+ mem = (long_u)pagesize * pagecount;
+ }
+ }
+# endif
+
+ /* Return the minimum of the physical memory and the user limit, because
+ * using more than the user limit may cause Vim to be terminated. */
+# if defined(HAVE_SYS_RESOURCE_H) && defined(HAVE_GETRLIMIT)
+ {
+ struct rlimit rlp;
+
+ if (getrlimit(RLIMIT_DATA, &rlp) == 0
+ && rlp.rlim_cur < ((rlim_t)1 << (sizeof(long_u) * 8 - 1))
+# ifdef RLIM_INFINITY
+ && rlp.rlim_cur != RLIM_INFINITY
+# endif
+ && ((long_u)rlp.rlim_cur >> 10) < (mem >> shiftright)
+ )
+ {
+ mem = (long_u)rlp.rlim_cur;
+ shiftright = 10;
+ }
+ }
+# endif
+
+ if (mem > 0)
+ return mem >> shiftright;
+ return (long_u)0x1fffff;
+}
+#endif
+
+ void
+mch_delay(long msec, int ignoreinput)
+{
+ int old_tmode;
+#ifdef FEAT_MZSCHEME
+ long total = msec; /* remember original value */
+#endif
+
+ if (ignoreinput)
+ {
+ /* Go to cooked mode without echo, to allow SIGINT interrupting us
+ * here. But we don't want QUIT to kill us (CTRL-\ used in a
+ * shell may produce SIGQUIT). */
+ in_mch_delay = TRUE;
+ old_tmode = curr_tmode;
+ if (curr_tmode == TMODE_RAW)
+ settmode(TMODE_SLEEP);
+
+ /*
+ * Everybody sleeps in a different way...
+ * Prefer nanosleep(), some versions of usleep() can only sleep up to
+ * one second.
+ */
+#ifdef FEAT_MZSCHEME
+ do
+ {
+ /* if total is large enough, wait by portions in p_mzq */
+ if (total > p_mzq)
+ msec = p_mzq;
+ else
+ msec = total;
+ total -= msec;
+#endif
+#ifdef HAVE_NANOSLEEP
+ {
+ struct timespec ts;
+
+ ts.tv_sec = msec / 1000;
+ ts.tv_nsec = (msec % 1000) * 1000000;
+ (void)nanosleep(&ts, NULL);
+ }
+#else
+# ifdef HAVE_USLEEP
+ while (msec >= 1000)
+ {
+ usleep((unsigned int)(999 * 1000));
+ msec -= 999;
+ }
+ usleep((unsigned int)(msec * 1000));
+# else
+# ifndef HAVE_SELECT
+ poll(NULL, 0, (int)msec);
+# else
+ {
+ struct timeval tv;
+
+ tv.tv_sec = msec / 1000;
+ tv.tv_usec = (msec % 1000) * 1000;
+ /*
+ * NOTE: Solaris 2.6 has a bug that makes select() hang here. Get
+ * a patch from Sun to fix this. Reported by Gunnar Pedersen.
+ */
+ select(0, NULL, NULL, NULL, &tv);
+ }
+# endif /* HAVE_SELECT */
+# endif /* HAVE_NANOSLEEP */
+#endif /* HAVE_USLEEP */
+#ifdef FEAT_MZSCHEME
+ }
+ while (total > 0);
+#endif
+
+ settmode(old_tmode);
+ in_mch_delay = FALSE;
+ }
+ else
+ WaitForChar(msec, NULL, FALSE);
+}
+
+#if defined(HAVE_STACK_LIMIT) \
+ || (!defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGSTACK))
+# define HAVE_CHECK_STACK_GROWTH
+/*
+ * Support for checking for an almost-out-of-stack-space situation.
+ */
+
+/*
+ * Return a pointer to an item on the stack. Used to find out if the stack
+ * grows up or down.
+ */
+static int stack_grows_downwards;
+
+/*
+ * Find out if the stack grows upwards or downwards.
+ * "p" points to a variable on the stack of the caller.
+ */
+ static void
+check_stack_growth(char *p)
+{
+ int i;
+
+ stack_grows_downwards = (p > (char *)&i);
+}
+#endif
+
+#if defined(HAVE_STACK_LIMIT) || defined(PROTO)
+static char *stack_limit = NULL;
+
+#if defined(_THREAD_SAFE) && defined(HAVE_PTHREAD_NP_H)
+# include <pthread.h>
+# include <pthread_np.h>
+#endif
+
+/*
+ * Find out until how var the stack can grow without getting into trouble.
+ * Called when starting up and when switching to the signal stack in
+ * deathtrap().
+ */
+ static void
+get_stack_limit(void)
+{
+ struct rlimit rlp;
+ int i;
+ long lim;
+
+ /* Set the stack limit to 15/16 of the allowable size. Skip this when the
+ * limit doesn't fit in a long (rlim_cur might be "long long"). */
+ if (getrlimit(RLIMIT_STACK, &rlp) == 0
+ && rlp.rlim_cur < ((rlim_t)1 << (sizeof(long_u) * 8 - 1))
+# ifdef RLIM_INFINITY
+ && rlp.rlim_cur != RLIM_INFINITY
+# endif
+ )
+ {
+ lim = (long)rlp.rlim_cur;
+#if defined(_THREAD_SAFE) && defined(HAVE_PTHREAD_NP_H)
+ {
+ pthread_attr_t attr;
+ size_t size;
+
+ /* On FreeBSD the initial thread always has a fixed stack size, no
+ * matter what the limits are set to. Normally it's 1 Mbyte. */
+ pthread_attr_init(&attr);
+ if (pthread_attr_get_np(pthread_self(), &attr) == 0)
+ {
+ pthread_attr_getstacksize(&attr, &size);
+ if (lim > (long)size)
+ lim = (long)size;
+ }
+ pthread_attr_destroy(&attr);
+ }
+#endif
+ if (stack_grows_downwards)
+ {
+ stack_limit = (char *)((long)&i - (lim / 16L * 15L));
+ if (stack_limit >= (char *)&i)
+ /* overflow, set to 1/16 of current stack position */
+ stack_limit = (char *)((long)&i / 16L);
+ }
+ else
+ {
+ stack_limit = (char *)((long)&i + (lim / 16L * 15L));
+ if (stack_limit <= (char *)&i)
+ stack_limit = NULL; /* overflow */
+ }
+ }
+}
+
+/*
+ * Return FAIL when running out of stack space.
+ * "p" must point to any variable local to the caller that's on the stack.
+ */
+ int
+mch_stackcheck(char *p)
+{
+ if (stack_limit != NULL)
+ {
+ if (stack_grows_downwards)
+ {
+ if (p < stack_limit)
+ return FAIL;
+ }
+ else if (p > stack_limit)
+ return FAIL;
+ }
+ return OK;
+}
+#endif
+
+#if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
+/*
+ * Support for using the signal stack.
+ * This helps when we run out of stack space, which causes a SIGSEGV. The
+ * signal handler then must run on another stack, since the normal stack is
+ * completely full.
+ */
+
+#ifndef SIGSTKSZ
+# define SIGSTKSZ 8000 /* just a guess of how much stack is needed... */
+#endif
+
+# ifdef HAVE_SIGALTSTACK
+static stack_t sigstk; /* for sigaltstack() */
+# else
+static struct sigstack sigstk; /* for sigstack() */
+# endif
+
+static char *signal_stack;
+
+ static void
+init_signal_stack(void)
+{
+ if (signal_stack != NULL)
+ {
+# ifdef HAVE_SIGALTSTACK
+# ifdef HAVE_SS_BASE
+ sigstk.ss_base = signal_stack;
+# else
+ sigstk.ss_sp = signal_stack;
+# endif
+ sigstk.ss_size = SIGSTKSZ;
+ sigstk.ss_flags = 0;
+ (void)sigaltstack(&sigstk, NULL);
+# else
+ sigstk.ss_sp = signal_stack;
+ if (stack_grows_downwards)
+ sigstk.ss_sp += SIGSTKSZ - 1;
+ sigstk.ss_onstack = 0;
+ (void)sigstack(&sigstk, NULL);
+# endif
+ }
+}
+#endif
+
+/*
+ * We need correct prototypes for a signal function, otherwise mean compilers
+ * will barf when the second argument to signal() is ``wrong''.
+ * Let me try it with a few tricky defines from my own osdef.h (jw).
+ */
+#if defined(SIGWINCH)
+ static RETSIGTYPE
+sig_winch SIGDEFARG(sigarg)
+{
+ /* this is not required on all systems, but it doesn't hurt anybody */
+ signal(SIGWINCH, (RETSIGTYPE (*)())sig_winch);
+ do_resize = TRUE;
+ SIGRETURN;
+}
+#endif
+
+#if defined(SIGINT)
+ static RETSIGTYPE
+catch_sigint SIGDEFARG(sigarg)
+{
+ /* this is not required on all systems, but it doesn't hurt anybody */
+ signal(SIGINT, (RETSIGTYPE (*)())catch_sigint);
+ got_int = TRUE;
+ SIGRETURN;
+}
+#endif
+
+#if defined(SIGPWR)
+ static RETSIGTYPE
+catch_sigpwr SIGDEFARG(sigarg)
+{
+ /* this is not required on all systems, but it doesn't hurt anybody */
+ signal(SIGPWR, (RETSIGTYPE (*)())catch_sigpwr);
+ /*
+ * I'm not sure we get the SIGPWR signal when the system is really going
+ * down or when the batteries are almost empty. Just preserve the swap
+ * files and don't exit, that can't do any harm.
+ */
+ ml_sync_all(FALSE, FALSE);
+ SIGRETURN;
+}
+#endif
+
+#ifdef SET_SIG_ALARM
+/*
+ * signal function for alarm().
+ */
+ static RETSIGTYPE
+sig_alarm SIGDEFARG(sigarg)
+{
+ /* doesn't do anything, just to break a system call */
+ sig_alarm_called = TRUE;
+ SIGRETURN;
+}
+#endif
+
+#if (defined(HAVE_SETJMP_H) \
+ && ((defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) \
+ || defined(FEAT_LIBCALL))) \
+ || defined(PROTO)
+# define USING_SETJMP 1
+
+// argument to SETJMP()
+static JMP_BUF lc_jump_env;
+
+# ifdef SIGHASARG
+// Caught signal number, 0 when no was signal caught; used for mch_libcall().
+// Volatile because it is used in signal handlers.
+static volatile sig_atomic_t lc_signal;
+# endif
+
+// TRUE when lc_jump_env is valid.
+// Volatile because it is used in signal handler deathtrap().
+static volatile sig_atomic_t lc_active INIT(= FALSE);
+
+/*
+ * A simplistic version of setjmp() that only allows one level of using.
+ * Used to protect areas where we could crash.
+ * Don't call twice before calling mch_endjmp()!.
+ *
+ * Usage:
+ * mch_startjmp();
+ * if (SETJMP(lc_jump_env) != 0)
+ * {
+ * mch_didjmp();
+ * emsg("crash!");
+ * }
+ * else
+ * {
+ * do_the_work;
+ * mch_endjmp();
+ * }
+ * Note: Can't move SETJMP() here, because a function calling setjmp() must
+ * not return before the saved environment is used.
+ * Returns OK for normal return, FAIL when the protected code caused a
+ * problem and LONGJMP() was used.
+ */
+ static void
+mch_startjmp(void)
+{
+# ifdef SIGHASARG
+ lc_signal = 0;
+# endif
+ lc_active = TRUE;
+}
+
+ static void
+mch_endjmp(void)
+{
+ lc_active = FALSE;
+}
+
+ static void
+mch_didjmp(void)
+{
+# if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
+ // On FreeBSD the signal stack has to be reset after using siglongjmp(),
+ // otherwise catching the signal only works once.
+ init_signal_stack();
+# endif
+}
+#endif
+
+/*
+ * This function handles deadly signals.
+ * It tries to preserve any swap files and exit properly.
+ * (partly from Elvis).
+ * NOTE: Avoid unsafe functions, such as allocating memory, they can result in
+ * a deadlock.
+ */
+ static RETSIGTYPE
+deathtrap SIGDEFARG(sigarg)
+{
+ static int entered = 0; /* count the number of times we got here.
+ Note: when memory has been corrupted
+ this may get an arbitrary value! */
+#ifdef SIGHASARG
+ int i;
+#endif
+
+#if defined(USING_SETJMP)
+ /*
+ * Catch a crash in protected code.
+ * Restores the environment saved in lc_jump_env, which looks like
+ * SETJMP() returns 1.
+ */
+ if (lc_active)
+ {
+# if defined(SIGHASARG)
+ lc_signal = sigarg;
+# endif
+ lc_active = FALSE; /* don't jump again */
+ LONGJMP(lc_jump_env, 1);
+ /* NOTREACHED */
+ }
+#endif
+
+#ifdef SIGHASARG
+# ifdef SIGQUIT
+ /* While in mch_delay() we go to cooked mode to allow a CTRL-C to
+ * interrupt us. But in cooked mode we may also get SIGQUIT, e.g., when
+ * pressing CTRL-\, but we don't want Vim to exit then. */
+ if (in_mch_delay && sigarg == SIGQUIT)
+ SIGRETURN;
+# endif
+
+ /* When SIGHUP, SIGQUIT, etc. are blocked: postpone the effect and return
+ * here. This avoids that a non-reentrant function is interrupted, e.g.,
+ * free(). Calling free() again may then cause a crash. */
+ if (entered == 0
+ && (0
+# ifdef SIGHUP
+ || sigarg == SIGHUP
+# endif
+# ifdef SIGQUIT
+ || sigarg == SIGQUIT
+# endif
+# ifdef SIGTERM
+ || sigarg == SIGTERM
+# endif
+# ifdef SIGPWR
+ || sigarg == SIGPWR
+# endif
+# ifdef SIGUSR1
+ || sigarg == SIGUSR1
+# endif
+# ifdef SIGUSR2
+ || sigarg == SIGUSR2
+# endif
+ )
+ && !vim_handle_signal(sigarg))
+ SIGRETURN;
+#endif
+
+ /* Remember how often we have been called. */
+ ++entered;
+
+ /* Executing autocommands is likely to use more stack space than we have
+ * available in the signal stack. */
+ block_autocmds();
+
+#ifdef FEAT_EVAL
+ /* Set the v:dying variable. */
+ set_vim_var_nr(VV_DYING, (long)entered);
+#endif
+ v_dying = entered;
+
+#ifdef HAVE_STACK_LIMIT
+ /* Since we are now using the signal stack, need to reset the stack
+ * limit. Otherwise using a regexp will fail. */
+ get_stack_limit();
+#endif
+
+#if 0
+ /* This is for opening gdb the moment Vim crashes.
+ * You need to manually adjust the file name and Vim executable name.
+ * Suggested by SungHyun Nam. */
+ {
+# define VI_GDB_FILE "/tmp/vimgdb"
+# define VIM_NAME "/usr/bin/vim"
+ FILE *fp = fopen(VI_GDB_FILE, "w");
+ if (fp)
+ {
+ fprintf(fp,
+ "file %s\n"
+ "attach %d\n"
+ "set height 1000\n"
+ "bt full\n"
+ , VIM_NAME, getpid());
+ fclose(fp);
+ system("xterm -e gdb -x "VI_GDB_FILE);
+ unlink(VI_GDB_FILE);
+ }
+ }
+#endif
+
+#ifdef SIGHASARG
+ /* try to find the name of this signal */
+ for (i = 0; signal_info[i].sig != -1; i++)
+ if (sigarg == signal_info[i].sig)
+ break;
+ deadly_signal = sigarg;
+#endif
+
+ full_screen = FALSE; /* don't write message to the GUI, it might be
+ * part of the problem... */
+ /*
+ * If something goes wrong after entering here, we may get here again.
+ * When this happens, give a message and try to exit nicely (resetting the
+ * terminal mode, etc.)
+ * When this happens twice, just exit, don't even try to give a message,
+ * stack may be corrupt or something weird.
+ * When this still happens again (or memory was corrupted in such a way
+ * that "entered" was clobbered) use _exit(), don't try freeing resources.
+ */
+ if (entered >= 3)
+ {
+ reset_signals(); /* don't catch any signals anymore */
+ may_core_dump();
+ if (entered >= 4)
+ _exit(8);
+ exit(7);
+ }
+ if (entered == 2)
+ {
+ /* No translation, it may call malloc(). */
+ OUT_STR("Vim: Double signal, exiting\n");
+ out_flush();
+ getout(1);
+ }
+
+ /* No translation, it may call malloc(). */
+#ifdef SIGHASARG
+ sprintf((char *)IObuff, "Vim: Caught deadly signal %s\n",
+ signal_info[i].name);
+#else
+ sprintf((char *)IObuff, "Vim: Caught deadly signal\n");
+#endif
+
+ /* Preserve files and exit. This sets the really_exiting flag to prevent
+ * calling free(). */
+ preserve_exit();
+
+ /* NOTREACHED */
+
+#ifdef NBDEBUG
+ reset_signals();
+ may_core_dump();
+ abort();
+#endif
+
+ SIGRETURN;
+}
+
+/*
+ * Invoked after receiving SIGCONT. We don't know what happened while
+ * sleeping, deal with part of that.
+ */
+ static void
+after_sigcont(void)
+{
+# ifdef FEAT_TITLE
+ // Don't change "oldtitle" in a signal handler, set a flag to obtain it
+ // again later.
+ oldtitle_outdated = TRUE;
+# endif
+ settmode(TMODE_RAW);
+ need_check_timestamps = TRUE;
+ did_check_timestamps = FALSE;
+}
+
+#if defined(SIGCONT)
+static RETSIGTYPE sigcont_handler SIGPROTOARG;
+static volatile sig_atomic_t in_mch_suspend = FALSE;
+
+/*
+ * With multi-threading, suspending might not work immediately. Catch the
+ * SIGCONT signal, which will be used as an indication whether the suspending
+ * has been done or not.
+ *
+ * On Linux, signal is not always handled immediately either.
+ * See https://bugs.launchpad.net/bugs/291373
+ * Probably because the signal is handled in another thread.
+ *
+ * volatile because it is used in signal handler sigcont_handler().
+ */
+static volatile sig_atomic_t sigcont_received;
+static RETSIGTYPE sigcont_handler SIGPROTOARG;
+
+/*
+ * signal handler for SIGCONT
+ */
+ static RETSIGTYPE
+sigcont_handler SIGDEFARG(sigarg)
+{
+ if (in_mch_suspend)
+ {
+ sigcont_received = TRUE;
+ }
+ else
+ {
+ // We didn't suspend ourselves, assume we were stopped by a SIGSTOP
+ // signal (which can't be intercepted) and get a SIGCONT. Need to get
+ // back to a sane mode. We should redraw, but we can't really do that
+ // in a signal handler, do a redraw later.
+ after_sigcont();
+ redraw_later(CLEAR);
+ cursor_on_force();
+ out_flush();
+ }
+
+ SIGRETURN;
+}
+#endif
+
+#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
+# ifdef USE_SYSTEM
+static void *clip_star_save = NULL;
+static void *clip_plus_save = NULL;
+# endif
+
+/*
+ * Called when Vim is going to sleep or execute a shell command.
+ * We can't respond to requests for the X selections. Lose them, otherwise
+ * other applications will hang. But first copy the text to cut buffer 0.
+ */
+ static void
+loose_clipboard(void)
+{
+ if (clip_star.owned || clip_plus.owned)
+ {
+ x11_export_final_selection();
+ if (clip_star.owned)
+ clip_lose_selection(&clip_star);
+ if (clip_plus.owned)
+ clip_lose_selection(&clip_plus);
+ if (x11_display != NULL)
+ XFlush(x11_display);
+ }
+}
+
+# ifdef USE_SYSTEM
+/*
+ * Save clipboard text to restore later.
+ */
+ static void
+save_clipboard(void)
+{
+ if (clip_star.owned)
+ clip_star_save = get_register('*', TRUE);
+ if (clip_plus.owned)
+ clip_plus_save = get_register('+', TRUE);
+}
+
+/*
+ * Restore clipboard text if no one own the X selection.
+ */
+ static void
+restore_clipboard(void)
+{
+ if (clip_star_save != NULL)
+ {
+ if (!clip_gen_owner_exists(&clip_star))
+ put_register('*', clip_star_save);
+ else
+ free_register(clip_star_save);
+ clip_star_save = NULL;
+ }
+ if (clip_plus_save != NULL)
+ {
+ if (!clip_gen_owner_exists(&clip_plus))
+ put_register('+', clip_plus_save);
+ else
+ free_register(clip_plus_save);
+ clip_plus_save = NULL;
+ }
+}
+# endif
+#endif
+
+/*
+ * If the machine has job control, use it to suspend the program,
+ * otherwise fake it by starting a new shell.
+ */
+ void
+mch_suspend(void)
+{
+ /* BeOS does have SIGTSTP, but it doesn't work. */
+#if defined(SIGTSTP) && !defined(__BEOS__)
+ in_mch_suspend = TRUE;
+
+ out_flush(); /* needed to make cursor visible on some systems */
+ settmode(TMODE_COOK);
+ out_flush(); /* needed to disable mouse on some systems */
+
+# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
+ loose_clipboard();
+# endif
+# if defined(SIGCONT)
+ sigcont_received = FALSE;
+# endif
+
+ kill(0, SIGTSTP); /* send ourselves a STOP signal */
+
+# if defined(SIGCONT)
+ /*
+ * Wait for the SIGCONT signal to be handled. It generally happens
+ * immediately, but somehow not all the time, probably because it's handled
+ * in another thread. Do not call pause() because there would be race
+ * condition which would hang Vim if signal happened in between the test of
+ * sigcont_received and the call to pause(). If signal is not yet received,
+ * sleep 0, 1, 2, 3 ms. Don't bother waiting further if signal is not
+ * received after 1+2+3 ms (not expected to happen).
+ */
+ {
+ long wait_time;
+
+ for (wait_time = 0; !sigcont_received && wait_time <= 3L; wait_time++)
+ mch_delay(wait_time, FALSE);
+ }
+# endif
+ in_mch_suspend = FALSE;
+
+ after_sigcont();
+#else
+ suspend_shell();
+#endif
+}
+
+ void
+mch_init(void)
+{
+ Columns = 80;
+ Rows = 24;
+
+ out_flush();
+ set_signals();
+
+#ifdef MACOS_CONVERT
+ mac_conv_init();
+#endif
+#ifdef FEAT_CYGWIN_WIN32_CLIPBOARD
+ win_clip_init();
+#endif
+}
+
+ static void
+set_signals(void)
+{
+#if defined(SIGWINCH)
+ /*
+ * WINDOW CHANGE signal is handled with sig_winch().
+ */
+ signal(SIGWINCH, (RETSIGTYPE (*)())sig_winch);
+#endif
+
+ /*
+ * We want the STOP signal to work, to make mch_suspend() work.
+ * For "rvim" the STOP signal is ignored.
+ */
+#ifdef SIGTSTP
+ signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
+#endif
+#if defined(SIGCONT)
+ signal(SIGCONT, sigcont_handler);
+#endif
+
+ /*
+ * We want to ignore breaking of PIPEs.
+ */
+#ifdef SIGPIPE
+ signal(SIGPIPE, SIG_IGN);
+#endif
+
+#ifdef SIGINT
+ catch_int_signal();
+#endif
+
+ /*
+ * Ignore alarm signals (Perl's alarm() generates it).
+ */
+#ifdef SIGALRM
+ signal(SIGALRM, SIG_IGN);
+#endif
+
+ /*
+ * Catch SIGPWR (power failure?) to preserve the swap files, so that no
+ * work will be lost.
+ */
+#ifdef SIGPWR
+ signal(SIGPWR, (RETSIGTYPE (*)())catch_sigpwr);
+#endif
+
+ /*
+ * Arrange for other signals to gracefully shutdown Vim.
+ */
+ catch_signals(deathtrap, SIG_ERR);
+
+#if defined(FEAT_GUI) && defined(SIGHUP)
+ /*
+ * When the GUI is running, ignore the hangup signal.
+ */
+ if (gui.in_use)
+ signal(SIGHUP, SIG_IGN);
+#endif
+}
+
+#if defined(SIGINT) || defined(PROTO)
+/*
+ * Catch CTRL-C (only works while in Cooked mode).
+ */
+ static void
+catch_int_signal(void)
+{
+ signal(SIGINT, (RETSIGTYPE (*)())catch_sigint);
+}
+#endif
+
+ void
+reset_signals(void)
+{
+ catch_signals(SIG_DFL, SIG_DFL);
+#if defined(SIGCONT)
+ /* SIGCONT isn't in the list, because its default action is ignore */
+ signal(SIGCONT, SIG_DFL);
+#endif
+}
+
+ static void
+catch_signals(
+ RETSIGTYPE (*func_deadly)(),
+ RETSIGTYPE (*func_other)())
+{
+ int i;
+
+ for (i = 0; signal_info[i].sig != -1; i++)
+ if (signal_info[i].deadly)
+ {
+#if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGACTION)
+ struct sigaction sa;
+
+ /* Setup to use the alternate stack for the signal function. */
+ sa.sa_handler = func_deadly;
+ sigemptyset(&sa.sa_mask);
+# if defined(__linux__) && defined(_REENTRANT)
+ /* On Linux, with glibc compiled for kernel 2.2, there is a bug in
+ * thread handling in combination with using the alternate stack:
+ * pthread library functions try to use the stack pointer to
+ * identify the current thread, causing a SEGV signal, which
+ * recursively calls deathtrap() and hangs. */
+ sa.sa_flags = 0;
+# else
+ sa.sa_flags = SA_ONSTACK;
+# endif
+ sigaction(signal_info[i].sig, &sa, NULL);
+#else
+# if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGVEC)
+ struct sigvec sv;
+
+ /* Setup to use the alternate stack for the signal function. */
+ sv.sv_handler = func_deadly;
+ sv.sv_mask = 0;
+ sv.sv_flags = SV_ONSTACK;
+ sigvec(signal_info[i].sig, &sv, NULL);
+# else
+ signal(signal_info[i].sig, func_deadly);
+# endif
+#endif
+ }
+ else if (func_other != SIG_ERR)
+ signal(signal_info[i].sig, func_other);
+}
+
+#ifdef HAVE_SIGPROCMASK
+ static void
+block_signals(sigset_t *set)
+{
+ sigset_t newset;
+ int i;
+
+ sigemptyset(&newset);
+
+ for (i = 0; signal_info[i].sig != -1; i++)
+ sigaddset(&newset, signal_info[i].sig);
+
+# if defined(SIGCONT)
+ /* SIGCONT isn't in the list, because its default action is ignore */
+ sigaddset(&newset, SIGCONT);
+# endif
+
+ sigprocmask(SIG_BLOCK, &newset, set);
+}
+
+ static void
+unblock_signals(sigset_t *set)
+{
+ sigprocmask(SIG_SETMASK, set, NULL);
+}
+#endif
+
+/*
+ * Handling of SIGHUP, SIGQUIT and SIGTERM:
+ * "when" == a signal: when busy, postpone and return FALSE, otherwise
+ * return TRUE
+ * "when" == SIGNAL_BLOCK: Going to be busy, block signals
+ * "when" == SIGNAL_UNBLOCK: Going to wait, unblock signals, use postponed
+ * signal
+ * Returns TRUE when Vim should exit.
+ */
+ int
+vim_handle_signal(int sig)
+{
+ static int got_signal = 0;
+ static int blocked = TRUE;
+
+ switch (sig)
+ {
+ case SIGNAL_BLOCK: blocked = TRUE;
+ break;
+
+ case SIGNAL_UNBLOCK: blocked = FALSE;
+ if (got_signal != 0)
+ {
+ kill(getpid(), got_signal);
+ got_signal = 0;
+ }
+ break;
+
+ default: if (!blocked)
+ return TRUE; /* exit! */
+ got_signal = sig;
+#ifdef SIGPWR
+ if (sig != SIGPWR)
+#endif
+ got_int = TRUE; /* break any loops */
+ break;
+ }
+ return FALSE;
+}
+
+/*
+ * Check_win checks whether we have an interactive stdout.
+ */
+ int
+mch_check_win(int argc UNUSED, char **argv UNUSED)
+{
+ if (isatty(1))
+ return OK;
+ return FAIL;
+}
+
+/*
+ * Return TRUE if the input comes from a terminal, FALSE otherwise.
+ */
+ int
+mch_input_isatty(void)
+{
+ if (isatty(read_cmd_fd))
+ return TRUE;
+ return FALSE;
+}
+
+#ifdef FEAT_X11
+
+# if defined(ELAPSED_TIMEVAL) \
+ && (defined(FEAT_XCLIPBOARD) || defined(FEAT_TITLE))
+
+/*
+ * Give a message about the elapsed time for opening the X window.
+ */
+ static void
+xopen_message(long elapsed_msec)
+{
+ smsg(_("Opening the X display took %ld msec"), elapsed_msec);
+}
+# endif
+#endif
+
+#if defined(FEAT_X11) && (defined(FEAT_TITLE) || defined(FEAT_XCLIPBOARD))
+/*
+ * A few functions shared by X11 title and clipboard code.
+ */
+
+static int got_x_error = FALSE;
+
+/*
+ * X Error handler, otherwise X just exits! (very rude) -- webb
+ */
+ static int
+x_error_handler(Display *dpy, XErrorEvent *error_event)
+{
+ XGetErrorText(dpy, error_event->error_code, (char *)IObuff, IOSIZE);
+ STRCAT(IObuff, _("\nVim: Got X error\n"));
+
+ /* We cannot print a message and continue, because no X calls are allowed
+ * here (causes my system to hang). Silently continuing might be an
+ * alternative... */
+ preserve_exit(); /* preserve files and exit */
+
+ return 0; /* NOTREACHED */
+}
+
+/*
+ * Another X Error handler, just used to check for errors.
+ */
+ static int
+x_error_check(Display *dpy UNUSED, XErrorEvent *error_event UNUSED)
+{
+ got_x_error = TRUE;
+ return 0;
+}
+
+/*
+ * Return TRUE when connection to the X server is desired.
+ */
+ static int
+x_connect_to_server(void)
+{
+ // No point in connecting if we are exiting or dying.
+ if (exiting || v_dying)
+ return FALSE;
+
+#if defined(FEAT_CLIENTSERVER)
+ if (x_force_connect)
+ return TRUE;
+#endif
+ if (x_no_connect)
+ return FALSE;
+
+ // Check for a match with "exclude:" from 'clipboard'.
+ if (clip_exclude_prog != NULL)
+ {
+ // Just in case we get called recursively, return FALSE. This could
+ // happen if vpeekc() is used while executing the prog and it causes a
+ // related callback to be invoked.
+ if (regprog_in_use(clip_exclude_prog))
+ return FALSE;
+
+ if (vim_regexec_prog(&clip_exclude_prog, FALSE, T_NAME, (colnr_T)0))
+ return FALSE;
+ }
+ return TRUE;
+}
+
+#if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
+# if defined(USING_SETJMP)
+/*
+ * An X IO Error handler, used to catch error while opening the display.
+ */
+ static int
+x_IOerror_check(Display *dpy UNUSED)
+{
+ /* This function should not return, it causes exit(). Longjump instead. */
+ LONGJMP(lc_jump_env, 1);
+# if defined(VMS) || defined(__CYGWIN__) || defined(__CYGWIN32__)
+ return 0; /* avoid the compiler complains about missing return value */
+# endif
+}
+# endif
+
+/*
+ * An X IO Error handler, used to catch terminal errors.
+ */
+static int xterm_dpy_retry_count = 0;
+
+ static int
+x_IOerror_handler(Display *dpy UNUSED)
+{
+ xterm_dpy = NULL;
+ xterm_dpy_retry_count = 5; // Try reconnecting five times
+ x11_window = 0;
+ x11_display = NULL;
+ xterm_Shell = (Widget)0;
+
+ /* This function should not return, it causes exit(). Longjump instead. */
+ LONGJMP(x_jump_env, 1);
+# if defined(VMS) || defined(__CYGWIN__) || defined(__CYGWIN32__)
+ return 0; /* avoid the compiler complains about missing return value */
+# endif
+}
+
+/*
+ * If the X11 connection was lost try to restore it.
+ * Helps when the X11 server was stopped and restarted while Vim was inactive
+ * (e.g. through tmux).
+ */
+ static void
+may_restore_clipboard(void)
+{
+ // No point in restoring the connecting if we are exiting or dying.
+ if (!exiting && !v_dying && xterm_dpy_retry_count > 0)
+ {
+ --xterm_dpy_retry_count;
+
+# ifndef LESSTIF_VERSION
+ /* This has been reported to avoid Vim getting stuck. */
+ if (app_context != (XtAppContext)NULL)
+ {
+ XtDestroyApplicationContext(app_context);
+ app_context = (XtAppContext)NULL;
+ x11_display = NULL; /* freed by XtDestroyApplicationContext() */
+ }
+# endif
+
+ setup_term_clip();
+ get_x11_title(FALSE);
+ }
+}
+#endif
+
+/*
+ * Test if "dpy" and x11_window are valid by getting the window title.
+ * I don't actually want it yet, so there may be a simpler call to use, but
+ * this will cause the error handler x_error_check() to be called if anything
+ * is wrong, such as the window pointer being invalid (as can happen when the
+ * user changes his DISPLAY, but not his WINDOWID) -- webb
+ */
+ static int
+test_x11_window(Display *dpy)
+{
+ int (*old_handler)();
+ XTextProperty text_prop;
+
+ old_handler = XSetErrorHandler(x_error_check);
+ got_x_error = FALSE;
+ if (XGetWMName(dpy, x11_window, &text_prop))
+ XFree((void *)text_prop.value);
+ XSync(dpy, False);
+ (void)XSetErrorHandler(old_handler);
+
+ if (p_verbose > 0 && got_x_error)
+ verb_msg(_("Testing the X display failed"));
+
+ return (got_x_error ? FAIL : OK);
+}
+#endif
+
+#ifdef FEAT_TITLE
+
+#ifdef FEAT_X11
+
+static int get_x11_thing(int get_title, int test_only);
+
+/*
+ * try to get x11 window and display
+ *
+ * return FAIL for failure, OK otherwise
+ */
+ static int
+get_x11_windis(void)
+{
+ char *winid;
+ static int result = -1;
+#define XD_NONE 0 /* x11_display not set here */
+#define XD_HERE 1 /* x11_display opened here */
+#define XD_GUI 2 /* x11_display used from gui.dpy */
+#define XD_XTERM 3 /* x11_display used from xterm_dpy */
+ static int x11_display_from = XD_NONE;
+ static int did_set_error_handler = FALSE;
+
+ if (!did_set_error_handler)
+ {
+ /* X just exits if it finds an error otherwise! */
+ (void)XSetErrorHandler(x_error_handler);
+ did_set_error_handler = TRUE;
+ }
+
+#if defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK)
+ if (gui.in_use)
+ {
+ /*
+ * If the X11 display was opened here before, for the window where Vim
+ * was started, close that one now to avoid a memory leak.
+ */
+ if (x11_display_from == XD_HERE && x11_display != NULL)
+ {
+ XCloseDisplay(x11_display);
+ x11_display_from = XD_NONE;
+ }
+ if (gui_get_x11_windis(&x11_window, &x11_display) == OK)
+ {
+ x11_display_from = XD_GUI;
+ return OK;
+ }
+ x11_display = NULL;
+ return FAIL;
+ }
+ else if (x11_display_from == XD_GUI)
+ {
+ /* GUI must have stopped somehow, clear x11_display */
+ x11_window = 0;
+ x11_display = NULL;
+ x11_display_from = XD_NONE;
+ }
+#endif
+
+ /* When started with the "-X" argument, don't try connecting. */
+ if (!x_connect_to_server())
+ return FAIL;
+
+ /*
+ * If WINDOWID not set, should try another method to find out
+ * what the current window number is. The only code I know for
+ * this is very complicated.
+ * We assume that zero is invalid for WINDOWID.
+ */
+ if (x11_window == 0 && (winid = getenv("WINDOWID")) != NULL)
+ x11_window = (Window)atol(winid);
+
+#ifdef FEAT_XCLIPBOARD
+ if (xterm_dpy != NULL && x11_window != 0)
+ {
+ /* We may have checked it already, but Gnome terminal can move us to
+ * another window, so we need to check every time. */
+ if (x11_display_from != XD_XTERM)
+ {
+ /*
+ * If the X11 display was opened here before, for the window where
+ * Vim was started, close that one now to avoid a memory leak.
+ */
+ if (x11_display_from == XD_HERE && x11_display != NULL)
+ XCloseDisplay(x11_display);
+ x11_display = xterm_dpy;
+ x11_display_from = XD_XTERM;
+ }
+ if (test_x11_window(x11_display) == FAIL)
+ {
+ /* probably bad $WINDOWID */
+ x11_window = 0;
+ x11_display = NULL;
+ x11_display_from = XD_NONE;
+ return FAIL;
+ }
+ return OK;
+ }
+#endif
+
+ if (x11_window == 0 || x11_display == NULL)
+ result = -1;
+
+ if (result != -1) /* Have already been here and set this */
+ return result; /* Don't do all these X calls again */
+
+ if (x11_window != 0 && x11_display == NULL)
+ {
+#ifdef SET_SIG_ALARM
+ RETSIGTYPE (*sig_save)();
+#endif
+#ifdef ELAPSED_FUNC
+ elapsed_T start_tv;
+
+ if (p_verbose > 0)
+ ELAPSED_INIT(start_tv);
+#endif
+
+#ifdef SET_SIG_ALARM
+ /*
+ * Opening the Display may hang if the DISPLAY setting is wrong, or
+ * the network connection is bad. Set an alarm timer to get out.
+ */
+ sig_alarm_called = FALSE;
+ sig_save = (RETSIGTYPE (*)())signal(SIGALRM,
+ (RETSIGTYPE (*)())sig_alarm);
+ alarm(2);
+#endif
+ x11_display = XOpenDisplay(NULL);
+
+#ifdef SET_SIG_ALARM
+ alarm(0);
+ signal(SIGALRM, (RETSIGTYPE (*)())sig_save);
+ if (p_verbose > 0 && sig_alarm_called)
+ verb_msg(_("Opening the X display timed out"));
+#endif
+ if (x11_display != NULL)
+ {
+# ifdef ELAPSED_FUNC
+ if (p_verbose > 0)
+ {
+ verbose_enter();
+ xopen_message(ELAPSED_FUNC(start_tv));
+ verbose_leave();
+ }
+# endif
+ if (test_x11_window(x11_display) == FAIL)
+ {
+ /* Maybe window id is bad */
+ x11_window = 0;
+ XCloseDisplay(x11_display);
+ x11_display = NULL;
+ }
+ else
+ x11_display_from = XD_HERE;
+ }
+ }
+ if (x11_window == 0 || x11_display == NULL)
+ return (result = FAIL);
+
+# ifdef FEAT_EVAL
+ set_vim_var_nr(VV_WINDOWID, (long)x11_window);
+# endif
+
+ return (result = OK);
+}
+
+/*
+ * Determine original x11 Window Title
+ */
+ static int
+get_x11_title(int test_only)
+{
+ return get_x11_thing(TRUE, test_only);
+}
+
+/*
+ * Determine original x11 Window icon
+ */
+ static int
+get_x11_icon(int test_only)
+{
+ int retval = FALSE;
+
+ retval = get_x11_thing(FALSE, test_only);
+
+ /* could not get old icon, use terminal name */
+ if (oldicon == NULL && !test_only)
+ {
+ if (STRNCMP(T_NAME, "builtin_", 8) == 0)
+ oldicon = vim_strsave(T_NAME + 8);
+ else
+ oldicon = vim_strsave(T_NAME);
+ }
+
+ return retval;
+}
+
+ static int
+get_x11_thing(
+ int get_title, /* get title string */
+ int test_only)
+{
+ XTextProperty text_prop;
+ int retval = FALSE;
+ Status status;
+
+ if (get_x11_windis() == OK)
+ {
+ /* Get window/icon name if any */
+ if (get_title)
+ status = XGetWMName(x11_display, x11_window, &text_prop);
+ else
+ status = XGetWMIconName(x11_display, x11_window, &text_prop);
+
+ /*
+ * If terminal is xterm, then x11_window may be a child window of the
+ * outer xterm window that actually contains the window/icon name, so
+ * keep traversing up the tree until a window with a title/icon is
+ * found.
+ */
+ /* Previously this was only done for xterm and alikes. I don't see a
+ * reason why it would fail for other terminal emulators.
+ * if (term_is_xterm) */
+ {
+ Window root;
+ Window parent;
+ Window win = x11_window;
+ Window *children;
+ unsigned int num_children;
+
+ while (!status || text_prop.value == NULL)
+ {
+ if (!XQueryTree(x11_display, win, &root, &parent, &children,
+ &num_children))
+ break;
+ if (children)
+ XFree((void *)children);
+ if (parent == root || parent == 0)
+ break;
+
+ win = parent;
+ if (get_title)
+ status = XGetWMName(x11_display, win, &text_prop);
+ else
+ status = XGetWMIconName(x11_display, win, &text_prop);
+ }
+ }
+ if (status && text_prop.value != NULL)
+ {
+ retval = TRUE;
+ if (!test_only)
+ {
+ if (text_prop.encoding == XA_STRING && !has_mbyte)
+ {
+ if (get_title)
+ oldtitle = vim_strsave((char_u *)text_prop.value);
+ else
+ oldicon = vim_strsave((char_u *)text_prop.value);
+ }
+ else
+ {
+ char **cl;
+ Status transform_status;
+ int n = 0;
+
+ transform_status = XmbTextPropertyToTextList(x11_display,
+ &text_prop,
+ &cl, &n);
+ if (transform_status >= Success && n > 0 && cl[0])
+ {
+ if (get_title)
+ oldtitle = vim_strsave((char_u *) cl[0]);
+ else
+ oldicon = vim_strsave((char_u *) cl[0]);
+ XFreeStringList(cl);
+ }
+ else
+ {
+ if (get_title)
+ oldtitle = vim_strsave((char_u *)text_prop.value);
+ else
+ oldicon = vim_strsave((char_u *)text_prop.value);
+ }
+ }
+ }
+ XFree((void *)text_prop.value);
+ }
+ }
+ return retval;
+}
+
+/* Xutf8 functions are not available on older systems. Note that on some
+ * systems X_HAVE_UTF8_STRING may be defined in a header file but
+ * Xutf8SetWMProperties() is not in the X11 library. Configure checks for
+ * that and defines HAVE_XUTF8SETWMPROPERTIES. */
+#if defined(X_HAVE_UTF8_STRING)
+# if X_HAVE_UTF8_STRING && HAVE_XUTF8SETWMPROPERTIES
+# define USE_UTF8_STRING
+# endif
+#endif
+
+/*
+ * Set x11 Window Title
+ *
+ * get_x11_windis() must be called before this and have returned OK
+ */
+ static void
+set_x11_title(char_u *title)
+{
+ /* XmbSetWMProperties() and Xutf8SetWMProperties() should use a STRING
+ * when possible, COMPOUND_TEXT otherwise. COMPOUND_TEXT isn't
+ * supported everywhere and STRING doesn't work for multi-byte titles.
+ */
+#ifdef USE_UTF8_STRING
+ if (enc_utf8)
+ Xutf8SetWMProperties(x11_display, x11_window, (const char *)title,
+ NULL, NULL, 0, NULL, NULL, NULL);
+ else
+#endif
+ {
+#if XtSpecificationRelease >= 4
+# ifdef FEAT_XFONTSET
+ XmbSetWMProperties(x11_display, x11_window, (const char *)title,
+ NULL, NULL, 0, NULL, NULL, NULL);
+# else
+ XTextProperty text_prop;
+ char *c_title = (char *)title;
+
+ /* directly from example 3-18 "basicwin" of Xlib Programming Manual */
+ (void)XStringListToTextProperty(&c_title, 1, &text_prop);
+ XSetWMProperties(x11_display, x11_window, &text_prop,
+ NULL, NULL, 0, NULL, NULL, NULL);
+# endif
+#else
+ XStoreName(x11_display, x11_window, (char *)title);
+#endif
+ }
+ XFlush(x11_display);
+}
+
+/*
+ * Set x11 Window icon
+ *
+ * get_x11_windis() must be called before this and have returned OK
+ */
+ static void
+set_x11_icon(char_u *icon)
+{
+ /* See above for comments about using X*SetWMProperties(). */
+#ifdef USE_UTF8_STRING
+ if (enc_utf8)
+ Xutf8SetWMProperties(x11_display, x11_window, NULL, (const char *)icon,
+ NULL, 0, NULL, NULL, NULL);
+ else
+#endif
+ {
+#if XtSpecificationRelease >= 4
+# ifdef FEAT_XFONTSET
+ XmbSetWMProperties(x11_display, x11_window, NULL, (const char *)icon,
+ NULL, 0, NULL, NULL, NULL);
+# else
+ XTextProperty text_prop;
+ char *c_icon = (char *)icon;
+
+ (void)XStringListToTextProperty(&c_icon, 1, &text_prop);
+ XSetWMProperties(x11_display, x11_window, NULL, &text_prop,
+ NULL, 0, NULL, NULL, NULL);
+# endif
+#else
+ XSetIconName(x11_display, x11_window, (char *)icon);
+#endif
+ }
+ XFlush(x11_display);
+}
+
+#else /* FEAT_X11 */
+
+ static int
+get_x11_title(int test_only UNUSED)
+{
+ return FALSE;
+}
+
+ static int
+get_x11_icon(int test_only)
+{
+ if (!test_only)
+ {
+ if (STRNCMP(T_NAME, "builtin_", 8) == 0)
+ oldicon = vim_strsave(T_NAME + 8);
+ else
+ oldicon = vim_strsave(T_NAME);
+ }
+ return FALSE;
+}
+
+#endif /* FEAT_X11 */
+
+ int
+mch_can_restore_title(void)
+{
+ return get_x11_title(TRUE);
+}
+
+ int
+mch_can_restore_icon(void)
+{
+ return get_x11_icon(TRUE);
+}
+
+/*
+ * Set the window title and icon.
+ */
+ void
+mch_settitle(char_u *title, char_u *icon)
+{
+ int type = 0;
+ static int recursive = 0;
+
+ if (T_NAME == NULL) /* no terminal name (yet) */
+ return;
+ if (title == NULL && icon == NULL) /* nothing to do */
+ return;
+
+ /* When one of the X11 functions causes a deadly signal, we get here again
+ * recursively. Avoid hanging then (something is probably locked). */
+ if (recursive)
+ return;
+ ++recursive;
+
+ /*
+ * if the window ID and the display is known, we may use X11 calls
+ */
+#ifdef FEAT_X11
+ if (get_x11_windis() == OK)
+ type = 1;
+#else
+# if defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC) || defined(FEAT_GUI_GTK)
+ if (gui.in_use)
+ type = 1;
+# endif
+#endif
+
+ /*
+ * Note: if "t_ts" is set, title is set with escape sequence rather
+ * than x11 calls, because the x11 calls don't always work
+ */
+ if ((type || *T_TS != NUL) && title != NULL)
+ {
+ if (oldtitle_outdated)
+ {
+ oldtitle_outdated = FALSE;
+ VIM_CLEAR(oldtitle);
+ }
+ if (oldtitle == NULL
+#ifdef FEAT_GUI
+ && !gui.in_use
+#endif
+ ) /* first call but not in GUI, save title */
+ (void)get_x11_title(FALSE);
+
+ if (*T_TS != NUL) /* it's OK if t_fs is empty */
+ term_settitle(title);
+#ifdef FEAT_X11
+ else
+# ifdef FEAT_GUI_GTK
+ if (!gui.in_use) /* don't do this if GTK+ is running */
+# endif
+ set_x11_title(title); /* x11 */
+#endif
+#if defined(FEAT_GUI_GTK) \
+ || defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC)
+ else
+ gui_mch_settitle(title, icon);
+#endif
+ did_set_title = TRUE;
+ }
+
+ if ((type || *T_CIS != NUL) && icon != NULL)
+ {
+ if (oldicon == NULL
+#ifdef FEAT_GUI
+ && !gui.in_use
+#endif
+ ) /* first call, save icon */
+ get_x11_icon(FALSE);
+
+ if (*T_CIS != NUL)
+ {
+ out_str(T_CIS); /* set icon start */
+ out_str_nf(icon);
+ out_str(T_CIE); /* set icon end */
+ out_flush();
+ }
+#ifdef FEAT_X11
+ else
+# ifdef FEAT_GUI_GTK
+ if (!gui.in_use) /* don't do this if GTK+ is running */
+# endif
+ set_x11_icon(icon); /* x11 */
+#endif
+ did_set_icon = TRUE;
+ }
+ --recursive;
+}
+
+/*
+ * Restore the window/icon title.
+ * "which" is one of:
+ * SAVE_RESTORE_TITLE only restore title
+ * SAVE_RESTORE_ICON only restore icon
+ * SAVE_RESTORE_BOTH restore title and icon
+ */
+ void
+mch_restore_title(int which)
+{
+ /* only restore the title or icon when it has been set */
+ mch_settitle(((which & SAVE_RESTORE_TITLE) && did_set_title) ?
+ (oldtitle ? oldtitle : p_titleold) : NULL,
+ ((which & SAVE_RESTORE_ICON) && did_set_icon) ? oldicon : NULL);
+
+ // pop and push from/to the stack
+ term_pop_title(which);
+ term_push_title(which);
+}
+
+#endif /* FEAT_TITLE */
+
+/*
+ * Return TRUE if "name" looks like some xterm name.
+ * Seiichi Sato mentioned that "mlterm" works like xterm.
+ */
+ int
+vim_is_xterm(char_u *name)
+{
+ if (name == NULL)
+ return FALSE;
+ return (STRNICMP(name, "xterm", 5) == 0
+ || STRNICMP(name, "nxterm", 6) == 0
+ || STRNICMP(name, "kterm", 5) == 0
+ || STRNICMP(name, "mlterm", 6) == 0
+ || STRNICMP(name, "rxvt", 4) == 0
+ || STRNICMP(name, "screen.xterm", 12) == 0
+ || STRCMP(name, "builtin_xterm") == 0);
+}
+
+#if defined(FEAT_MOUSE_XTERM) || defined(PROTO)
+/*
+ * Return TRUE if "name" appears to be that of a terminal
+ * known to support the xterm-style mouse protocol.
+ * Relies on term_is_xterm having been set to its correct value.
+ */
+ int
+use_xterm_like_mouse(char_u *name)
+{
+ return (name != NULL
+ && (term_is_xterm
+ || STRNICMP(name, "screen", 6) == 0
+ || STRNICMP(name, "tmux", 4) == 0
+ || STRICMP(name, "st") == 0
+ || STRNICMP(name, "st-", 3) == 0
+ || STRNICMP(name, "stterm", 6) == 0));
+}
+#endif
+
+#if defined(FEAT_MOUSE_TTY) || defined(PROTO)
+/*
+ * Return non-zero when using an xterm mouse, according to 'ttymouse'.
+ * Return 1 for "xterm".
+ * Return 2 for "xterm2".
+ * Return 3 for "urxvt".
+ * Return 4 for "sgr".
+ */
+ int
+use_xterm_mouse(void)
+{
+ if (ttym_flags == TTYM_SGR)
+ return 4;
+ if (ttym_flags == TTYM_URXVT)
+ return 3;
+ if (ttym_flags == TTYM_XTERM2)
+ return 2;
+ if (ttym_flags == TTYM_XTERM)
+ return 1;
+ return 0;
+}
+#endif
+
+ int
+vim_is_iris(char_u *name)
+{
+ if (name == NULL)
+ return FALSE;
+ return (STRNICMP(name, "iris-ansi", 9) == 0
+ || STRCMP(name, "builtin_iris-ansi") == 0);
+}
+
+ int
+vim_is_vt300(char_u *name)
+{
+ if (name == NULL)
+ return FALSE; /* actually all ANSI comp. terminals should be here */
+ /* catch VT100 - VT5xx */
+ return ((STRNICMP(name, "vt", 2) == 0
+ && vim_strchr((char_u *)"12345", name[2]) != NULL)
+ || STRCMP(name, "builtin_vt320") == 0);
+}
+
+/*
+ * Return TRUE if "name" is a terminal for which 'ttyfast' should be set.
+ * This should include all windowed terminal emulators.
+ */
+ int
+vim_is_fastterm(char_u *name)
+{
+ if (name == NULL)
+ return FALSE;
+ if (vim_is_xterm(name) || vim_is_vt300(name) || vim_is_iris(name))
+ return TRUE;
+ return ( STRNICMP(name, "hpterm", 6) == 0
+ || STRNICMP(name, "sun-cmd", 7) == 0
+ || STRNICMP(name, "screen", 6) == 0
+ || STRNICMP(name, "tmux", 4) == 0
+ || STRNICMP(name, "dtterm", 6) == 0);
+}
+
+/*
+ * Insert user name in s[len].
+ * Return OK if a name found.
+ */
+ int
+mch_get_user_name(char_u *s, int len)
+{
+#ifdef VMS
+ vim_strncpy(s, (char_u *)cuserid(NULL), len - 1);
+ return OK;
+#else
+ return mch_get_uname(getuid(), s, len);
+#endif
+}
+
+/*
+ * Insert user name for "uid" in s[len].
+ * Return OK if a name found.
+ */
+ int
+mch_get_uname(uid_t uid, char_u *s, int len)
+{
+#if defined(HAVE_PWD_H) && defined(HAVE_GETPWUID)
+ struct passwd *pw;
+
+ if ((pw = getpwuid(uid)) != NULL
+ && pw->pw_name != NULL && *(pw->pw_name) != NUL)
+ {
+ vim_strncpy(s, (char_u *)pw->pw_name, len - 1);
+ return OK;
+ }
+#endif
+ sprintf((char *)s, "%d", (int)uid); /* assumes s is long enough */
+ return FAIL; /* a number is not a name */
+}
+
+/*
+ * Insert host name is s[len].
+ */
+
+#ifdef HAVE_SYS_UTSNAME_H
+ void
+mch_get_host_name(char_u *s, int len)
+{
+ struct utsname vutsname;
+
+ if (uname(&vutsname) < 0)
+ *s = NUL;
+ else
+ vim_strncpy(s, (char_u *)vutsname.nodename, len - 1);
+}
+#else /* HAVE_SYS_UTSNAME_H */
+
+# ifdef HAVE_SYS_SYSTEMINFO_H
+# define gethostname(nam, len) sysinfo(SI_HOSTNAME, nam, len)
+# endif
+
+ void
+mch_get_host_name(char_u *s, int len)
+{
+# ifdef VAXC
+ vaxc$gethostname((char *)s, len);
+# else
+ gethostname((char *)s, len);
+# endif
+ s[len - 1] = NUL; /* make sure it's terminated */
+}
+#endif /* HAVE_SYS_UTSNAME_H */
+
+/*
+ * return process ID
+ */
+ long
+mch_get_pid(void)
+{
+ return (long)getpid();
+}
+
+#if !defined(HAVE_STRERROR) && defined(USE_GETCWD)
+ static char *
+strerror(int err)
+{
+ extern int sys_nerr;
+ extern char *sys_errlist[];
+ static char er[20];
+
+ if (err > 0 && err < sys_nerr)
+ return (sys_errlist[err]);
+ sprintf(er, "Error %d", err);
+ return er;
+}
+#endif
+
+/*
+ * Get name of current directory into buffer 'buf' of length 'len' bytes.
+ * Return OK for success, FAIL for failure.
+ */
+ int
+mch_dirname(char_u *buf, int len)
+{
+#if defined(USE_GETCWD)
+ if (getcwd((char *)buf, len) == NULL)
+ {
+ STRCPY(buf, strerror(errno));
+ return FAIL;
+ }
+ return OK;
+#else
+ return (getwd((char *)buf) != NULL ? OK : FAIL);
+#endif
+}
+
+/*
+ * Get absolute file name into "buf[len]".
+ *
+ * return FAIL for failure, OK for success
+ */
+ int
+mch_FullName(
+ char_u *fname,
+ char_u *buf,
+ int len,
+ int force) /* also expand when already absolute path */
+{
+ int l;
+#ifdef HAVE_FCHDIR
+ int fd = -1;
+ static int dont_fchdir = FALSE; /* TRUE when fchdir() doesn't work */
+#endif
+ char_u olddir[MAXPATHL];
+ char_u *p;
+ int retval = OK;
+#ifdef __CYGWIN__
+ char_u posix_fname[MAXPATHL]; /* Cygwin docs mention MAX_PATH, but
+ it's not always defined */
+#endif
+
+#ifdef VMS
+ fname = vms_fixfilename(fname);
+#endif
+
+#ifdef __CYGWIN__
+ /*
+ * This helps for when "/etc/hosts" is a symlink to "c:/something/hosts".
+ */
+# if CYGWIN_VERSION_DLL_MAJOR >= 1007
+ /* Use CCP_RELATIVE to avoid that it sometimes returns a path that ends in
+ * a forward slash. */
+ cygwin_conv_path(CCP_WIN_A_TO_POSIX | CCP_RELATIVE,
+ fname, posix_fname, MAXPATHL);
+# else
+ cygwin_conv_to_posix_path(fname, posix_fname);
+# endif
+ fname = posix_fname;
+#endif
+
+ /* Expand it if forced or not an absolute path.
+ * Do not do it for "/file", the result is always "/". */
+ if ((force || !mch_isFullName(fname))
+ && ((p = vim_strrchr(fname, '/')) == NULL || p != fname))
+ {
+ /*
+ * If the file name has a path, change to that directory for a moment,
+ * and then do the getwd() (and get back to where we were).
+ * This will get the correct path name with "../" things.
+ */
+ if (p != NULL)
+ {
+#ifdef HAVE_FCHDIR
+ /*
+ * Use fchdir() if possible, it's said to be faster and more
+ * reliable. But on SunOS 4 it might not work. Check this by
+ * doing a fchdir() right now.
+ */
+ if (!dont_fchdir)
+ {
+ fd = open(".", O_RDONLY | O_EXTRA, 0);
+ if (fd >= 0 && fchdir(fd) < 0)
+ {
+ close(fd);
+ fd = -1;
+ dont_fchdir = TRUE; /* don't try again */
+ }
+ }
+#endif
+
+ /* Only change directory when we are sure we can return to where
+ * we are now. After doing "su" chdir(".") might not work. */
+ if (
+#ifdef HAVE_FCHDIR
+ fd < 0 &&
+#endif
+ (mch_dirname(olddir, MAXPATHL) == FAIL
+ || mch_chdir((char *)olddir) != 0))
+ {
+ p = NULL; /* can't get current dir: don't chdir */
+ retval = FAIL;
+ }
+ else
+ {
+ /* The directory is copied into buf[], to be able to remove
+ * the file name without changing it (could be a string in
+ * read-only memory) */
+ if (p - fname >= len)
+ retval = FAIL;
+ else
+ {
+ vim_strncpy(buf, fname, p - fname);
+ if (mch_chdir((char *)buf))
+ retval = FAIL;
+ else
+ fname = p + 1;
+ *buf = NUL;
+ }
+ }
+ }
+ if (mch_dirname(buf, len) == FAIL)
+ {
+ retval = FAIL;
+ *buf = NUL;
+ }
+ if (p != NULL)
+ {
+#ifdef HAVE_FCHDIR
+ if (fd >= 0)
+ {
+ if (p_verbose >= 5)
+ {
+ verbose_enter();
+ msg("fchdir() to previous dir");
+ verbose_leave();
+ }
+ l = fchdir(fd);
+ close(fd);
+ }
+ else
+#endif
+ l = mch_chdir((char *)olddir);
+ if (l != 0)
+ emsg(_(e_prev_dir));
+ }
+
+ l = STRLEN(buf);
+ if (l >= len - 1)
+ retval = FAIL; /* no space for trailing "/" */
+#ifndef VMS
+ else if (l > 0 && buf[l - 1] != '/' && *fname != NUL
+ && STRCMP(fname, ".") != 0)
+ STRCAT(buf, "/");
+#endif
+ }
+
+ /* Catch file names which are too long. */
+ if (retval == FAIL || (int)(STRLEN(buf) + STRLEN(fname)) >= len)
+ return FAIL;
+
+ /* Do not append ".", "/dir/." is equal to "/dir". */
+ if (STRCMP(fname, ".") != 0)
+ STRCAT(buf, fname);
+
+ return OK;
+}
+
+/*
+ * Return TRUE if "fname" does not depend on the current directory.
+ */
+ int
+mch_isFullName(char_u *fname)
+{
+#ifdef VMS
+ return ( fname[0] == '/' || fname[0] == '.' ||
+ strchr((char *)fname,':') || strchr((char *)fname,'"') ||
+ (strchr((char *)fname,'[') && strchr((char *)fname,']'))||
+ (strchr((char *)fname,'<') && strchr((char *)fname,'>')) );
+#else
+ return (*fname == '/' || *fname == '~');
+#endif
+}
+
+#if defined(USE_FNAME_CASE) || defined(PROTO)
+/*
+ * Set the case of the file name, if it already exists. This will cause the
+ * file name to remain exactly the same.
+ * Only required for file systems where case is ignored and preserved.
+ */
+ void
+fname_case(
+ char_u *name,
+ int len UNUSED) /* buffer size, only used when name gets longer */
+{
+ struct stat st;
+ char_u *slash, *tail;
+ DIR *dirp;
+ struct dirent *dp;
+
+ if (mch_lstat((char *)name, &st) >= 0)
+ {
+ /* Open the directory where the file is located. */
+ slash = vim_strrchr(name, '/');
+ if (slash == NULL)
+ {
+ dirp = opendir(".");
+ tail = name;
+ }
+ else
+ {
+ *slash = NUL;
+ dirp = opendir((char *)name);
+ *slash = '/';
+ tail = slash + 1;
+ }
+
+ if (dirp != NULL)
+ {
+ while ((dp = readdir(dirp)) != NULL)
+ {
+ /* Only accept names that differ in case and are the same byte
+ * length. TODO: accept different length name. */
+ if (STRICMP(tail, dp->d_name) == 0
+ && STRLEN(tail) == STRLEN(dp->d_name))
+ {
+ char_u newname[MAXPATHL + 1];
+ struct stat st2;
+
+ /* Verify the inode is equal. */
+ vim_strncpy(newname, name, MAXPATHL);
+ vim_strncpy(newname + (tail - name), (char_u *)dp->d_name,
+ MAXPATHL - (tail - name));
+ if (mch_lstat((char *)newname, &st2) >= 0
+ && st.st_ino == st2.st_ino
+ && st.st_dev == st2.st_dev)
+ {
+ STRCPY(tail, dp->d_name);
+ break;
+ }
+ }
+ }
+
+ closedir(dirp);
+ }
+ }
+}
+#endif
+
+/*
+ * Get file permissions for 'name'.
+ * Returns -1 when it doesn't exist.
+ */
+ long
+mch_getperm(char_u *name)
+{
+ struct stat statb;
+
+ /* Keep the #ifdef outside of stat(), it may be a macro. */
+#ifdef VMS
+ if (stat((char *)vms_fixfilename(name), &statb))
+#else
+ if (stat((char *)name, &statb))
+#endif
+ return -1;
+#ifdef __INTERIX
+ /* The top bit makes the value negative, which means the file doesn't
+ * exist. Remove the bit, we don't use it. */
+ return statb.st_mode & ~S_ADDACE;
+#else
+ return statb.st_mode;
+#endif
+}
+
+/*
+ * Set file permission for "name" to "perm".
+ * Return FAIL for failure, OK otherwise.
+ */
+ int
+mch_setperm(char_u *name, long perm)
+{
+ return (chmod((char *)
+#ifdef VMS
+ vms_fixfilename(name),
+#else
+ name,
+#endif
+ (mode_t)perm) == 0 ? OK : FAIL);
+}
+
+#if defined(HAVE_FCHMOD) || defined(PROTO)
+/*
+ * Set file permission for open file "fd" to "perm".
+ * Return FAIL for failure, OK otherwise.
+ */
+ int
+mch_fsetperm(int fd, long perm)
+{
+ return (fchmod(fd, (mode_t)perm) == 0 ? OK : FAIL);
+}
+#endif
+
+#if defined(HAVE_ACL) || defined(PROTO)
+# ifdef HAVE_SYS_ACL_H
+# include <sys/acl.h>
+# endif
+# ifdef HAVE_SYS_ACCESS_H
+# include <sys/access.h>
+# endif
+
+# ifdef HAVE_SOLARIS_ACL
+typedef struct vim_acl_solaris_T {
+ int acl_cnt;
+ aclent_t *acl_entry;
+} vim_acl_solaris_T;
+# endif
+
+#if defined(HAVE_SELINUX) || defined(PROTO)
+/*
+ * Copy security info from "from_file" to "to_file".
+ */
+ void
+mch_copy_sec(char_u *from_file, char_u *to_file)
+{
+ if (from_file == NULL)
+ return;
+
+ if (selinux_enabled == -1)
+ selinux_enabled = is_selinux_enabled();
+
+ if (selinux_enabled > 0)
+ {
+ security_context_t from_context = NULL;
+ security_context_t to_context = NULL;
+
+ if (getfilecon((char *)from_file, &from_context) < 0)
+ {
+ /* If the filesystem doesn't support extended attributes,
+ the original had no special security context and the
+ target cannot have one either. */
+ if (errno == EOPNOTSUPP)
+ return;
+
+ msg_puts(_("\nCould not get security context for "));
+ msg_outtrans(from_file);
+ msg_putchar('\n');
+ return;
+ }
+ if (getfilecon((char *)to_file, &to_context) < 0)
+ {
+ msg_puts(_("\nCould not get security context for "));
+ msg_outtrans(to_file);
+ msg_putchar('\n');
+ freecon (from_context);
+ return ;
+ }
+ if (strcmp(from_context, to_context) != 0)
+ {
+ if (setfilecon((char *)to_file, from_context) < 0)
+ {
+ msg_puts(_("\nCould not set security context for "));
+ msg_outtrans(to_file);
+ msg_putchar('\n');
+ }
+ }
+ freecon(to_context);
+ freecon(from_context);
+ }
+}
+#endif /* HAVE_SELINUX */
+
+#if defined(HAVE_SMACK) && !defined(PROTO)
+/*
+ * Copy security info from "from_file" to "to_file".
+ */
+ void
+mch_copy_sec(char_u *from_file, char_u *to_file)
+{
+ static const char * const smack_copied_attributes[] =
+ {
+ XATTR_NAME_SMACK,
+ XATTR_NAME_SMACKEXEC,
+ XATTR_NAME_SMACKMMAP
+ };
+
+ char buffer[SMACK_LABEL_LEN];
+ const char *name;
+ int index;
+ int ret;
+ ssize_t size;
+
+ if (from_file == NULL)
+ return;
+
+ for (index = 0 ; index < (int)(sizeof(smack_copied_attributes)
+ / sizeof(smack_copied_attributes)[0]) ; index++)
+ {
+ /* get the name of the attribute to copy */
+ name = smack_copied_attributes[index];
+
+ /* get the value of the attribute in buffer */
+ size = getxattr((char*)from_file, name, buffer, sizeof(buffer));
+ if (size >= 0)
+ {
+ /* copy the attribute value of buffer */
+ ret = setxattr((char*)to_file, name, buffer, (size_t)size, 0);
+ if (ret < 0)
+ {
+ vim_snprintf((char *)IObuff, IOSIZE,
+ _("Could not set security context %s for %s"),
+ name, to_file);
+ msg_outtrans(IObuff);
+ msg_putchar('\n');
+ }
+ }
+ else
+ {
+ /* what reason of not having the attribute value? */
+ switch (errno)
+ {
+ case ENOTSUP:
+ /* extended attributes aren't supported or enabled */
+ /* should a message be echoed? not sure... */
+ return; /* leave because it isn't useful to continue */
+
+ case ERANGE:
+ default:
+ /* no enough size OR unexpected error */
+ vim_snprintf((char *)IObuff, IOSIZE,
+ _("Could not get security context %s for %s. Removing it!"),
+ name, from_file);
+ msg_puts((char *)IObuff);
+ msg_putchar('\n');
+ /* FALLTHROUGH to remove the attribute */
+
+ case ENODATA:
+ /* no attribute of this name */
+ ret = removexattr((char*)to_file, name);
+ /* Silently ignore errors, apparently this happens when
+ * smack is not actually being used. */
+ break;
+ }
+ }
+ }
+}
+#endif /* HAVE_SMACK */
+
+/*
+ * Return a pointer to the ACL of file "fname" in allocated memory.
+ * Return NULL if the ACL is not available for whatever reason.
+ */
+ vim_acl_T
+mch_get_acl(char_u *fname UNUSED)
+{
+ vim_acl_T ret = NULL;
+#ifdef HAVE_POSIX_ACL
+ ret = (vim_acl_T)acl_get_file((char *)fname, ACL_TYPE_ACCESS);
+#else
+#ifdef HAVE_SOLARIS_ZFS_ACL
+ acl_t *aclent;
+
+ if (acl_get((char *)fname, 0, &aclent) < 0)
+ return NULL;
+ ret = (vim_acl_T)aclent;
+#else
+#ifdef HAVE_SOLARIS_ACL
+ vim_acl_solaris_T *aclent;
+
+ aclent = malloc(sizeof(vim_acl_solaris_T));
+ if ((aclent->acl_cnt = acl((char *)fname, GETACLCNT, 0, NULL)) < 0)
+ {
+ free(aclent);
+ return NULL;
+ }
+ aclent->acl_entry = malloc(aclent->acl_cnt * sizeof(aclent_t));
+ if (acl((char *)fname, GETACL, aclent->acl_cnt, aclent->acl_entry) < 0)
+ {
+ free(aclent->acl_entry);
+ free(aclent);
+ return NULL;
+ }
+ ret = (vim_acl_T)aclent;
+#else
+#if defined(HAVE_AIX_ACL)
+ int aclsize;
+ struct acl *aclent;
+
+ aclsize = sizeof(struct acl);
+ aclent = malloc(aclsize);
+ if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
+ {
+ if (errno == ENOSPC)
+ {
+ aclsize = aclent->acl_len;
+ aclent = realloc(aclent, aclsize);
+ if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
+ {
+ free(aclent);
+ return NULL;
+ }
+ }
+ else
+ {
+ free(aclent);
+ return NULL;
+ }
+ }
+ ret = (vim_acl_T)aclent;
+#endif /* HAVE_AIX_ACL */
+#endif /* HAVE_SOLARIS_ACL */
+#endif /* HAVE_SOLARIS_ZFS_ACL */
+#endif /* HAVE_POSIX_ACL */
+ return ret;
+}
+
+/*
+ * Set the ACL of file "fname" to "acl" (unless it's NULL).
+ */
+ void
+mch_set_acl(char_u *fname UNUSED, vim_acl_T aclent)
+{
+ if (aclent == NULL)
+ return;
+#ifdef HAVE_POSIX_ACL
+ acl_set_file((char *)fname, ACL_TYPE_ACCESS, (acl_t)aclent);
+#else
+#ifdef HAVE_SOLARIS_ZFS_ACL
+ acl_set((char *)fname, (acl_t *)aclent);
+#else
+#ifdef HAVE_SOLARIS_ACL
+ acl((char *)fname, SETACL, ((vim_acl_solaris_T *)aclent)->acl_cnt,
+ ((vim_acl_solaris_T *)aclent)->acl_entry);
+#else
+#ifdef HAVE_AIX_ACL
+ chacl((char *)fname, aclent, ((struct acl *)aclent)->acl_len);
+#endif /* HAVE_AIX_ACL */
+#endif /* HAVE_SOLARIS_ACL */
+#endif /* HAVE_SOLARIS_ZFS_ACL */
+#endif /* HAVE_POSIX_ACL */
+}
+
+ void
+mch_free_acl(vim_acl_T aclent)
+{
+ if (aclent == NULL)
+ return;
+#ifdef HAVE_POSIX_ACL
+ acl_free((acl_t)aclent);
+#else
+#ifdef HAVE_SOLARIS_ZFS_ACL
+ acl_free((acl_t *)aclent);
+#else
+#ifdef HAVE_SOLARIS_ACL
+ free(((vim_acl_solaris_T *)aclent)->acl_entry);
+ free(aclent);
+#else
+#ifdef HAVE_AIX_ACL
+ free(aclent);
+#endif /* HAVE_AIX_ACL */
+#endif /* HAVE_SOLARIS_ACL */
+#endif /* HAVE_SOLARIS_ZFS_ACL */
+#endif /* HAVE_POSIX_ACL */
+}
+#endif
+
+/*
+ * Set hidden flag for "name".
+ */
+ void
+mch_hide(char_u *name UNUSED)
+{
+ /* can't hide a file */
+}
+
+/*
+ * return TRUE if "name" is a directory or a symlink to a directory
+ * return FALSE if "name" is not a directory
+ * return FALSE for error
+ */
+ int
+mch_isdir(char_u *name)
+{
+ struct stat statb;
+
+ if (*name == NUL) /* Some stat()s don't flag "" as an error. */
+ return FALSE;
+ if (stat((char *)name, &statb))
+ return FALSE;
+ return (S_ISDIR(statb.st_mode) ? TRUE : FALSE);
+}
+
+/*
+ * return TRUE if "name" is a directory, NOT a symlink to a directory
+ * return FALSE if "name" is not a directory
+ * return FALSE for error
+ */
+ int
+mch_isrealdir(char_u *name)
+{
+ struct stat statb;
+
+ if (*name == NUL) /* Some stat()s don't flag "" as an error. */
+ return FALSE;
+ if (mch_lstat((char *)name, &statb))
+ return FALSE;
+ return (S_ISDIR(statb.st_mode) ? TRUE : FALSE);
+}
+
+/*
+ * Return 1 if "name" is an executable file, 0 if not or it doesn't exist.
+ */
+ static int
+executable_file(char_u *name)
+{
+ struct stat st;
+
+ if (stat((char *)name, &st))
+ return 0;
+#ifdef VMS
+ /* Like on Unix system file can have executable rights but not necessarily
+ * be an executable, but on Unix is not a default for an ordianry file to
+ * have an executable flag - on VMS it is in most cases.
+ * Therefore, this check does not have any sense - let keep us to the
+ * conventions instead:
+ * *.COM and *.EXE files are the executables - the rest are not. This is
+ * not ideal but better then it was.
+ */
+ int vms_executable = 0;
+ if (S_ISREG(st.st_mode) && mch_access((char *)name, X_OK) == 0)
+ {
+ if (strstr(vms_tolower((char*)name),".exe") != NULL
+ || strstr(vms_tolower((char*)name),".com")!= NULL)
+ vms_executable = 1;
+ }
+ return vms_executable;
+#else
+ return S_ISREG(st.st_mode) && mch_access((char *)name, X_OK) == 0;
+#endif
+}
+
+/*
+ * Return TRUE if "name" can be found in $PATH and executed, FALSE if not.
+ * If "use_path" is FALSE only check if "name" is executable.
+ * Return -1 if unknown.
+ */
+ int
+mch_can_exe(char_u *name, char_u **path, int use_path)
+{
+ char_u *buf;
+ char_u *p, *e;
+ int retval;
+
+ /* When "use_path" is false and if it's an absolute or relative path don't
+ * need to use $PATH. */
+ if (!use_path || mch_isFullName(name) || (name[0] == '.'
+ && (name[1] == '/' || (name[1] == '.' && name[2] == '/'))))
+ {
+ /* There must be a path separator, files in the current directory
+ * can't be executed. */
+ if (gettail(name) != name && executable_file(name))
+ {
+ if (path != NULL)
+ {
+ if (name[0] != '/')
+ *path = FullName_save(name, TRUE);
+ else
+ *path = vim_strsave(name);
+ }
+ return TRUE;
+ }
+ return FALSE;
+ }
+
+ p = (char_u *)getenv("PATH");
+ if (p == NULL || *p == NUL)
+ return -1;
+ buf = alloc((unsigned)(STRLEN(name) + STRLEN(p) + 2));
+ if (buf == NULL)
+ return -1;
+
+ /*
+ * Walk through all entries in $PATH to check if "name" exists there and
+ * is an executable file.
+ */
+ for (;;)
+ {
+ e = (char_u *)strchr((char *)p, ':');
+ if (e == NULL)
+ e = p + STRLEN(p);
+ if (e - p <= 1) /* empty entry means current dir */
+ STRCPY(buf, "./");
+ else
+ {
+ vim_strncpy(buf, p, e - p);
+ add_pathsep(buf);
+ }
+ STRCAT(buf, name);
+ retval = executable_file(buf);
+ if (retval == 1)
+ {
+ if (path != NULL)
+ {
+ if (buf[0] != '/')
+ *path = FullName_save(buf, TRUE);
+ else
+ *path = vim_strsave(buf);
+ }
+ break;
+ }
+
+ if (*e != ':')
+ break;
+ p = e + 1;
+ }
+
+ vim_free(buf);
+ return retval;
+}
+
+/*
+ * Check what "name" is:
+ * NODE_NORMAL: file or directory (or doesn't exist)
+ * NODE_WRITABLE: writable device, socket, fifo, etc.
+ * NODE_OTHER: non-writable things
+ */
+ int
+mch_nodetype(char_u *name)
+{
+ struct stat st;
+
+ if (stat((char *)name, &st))
+ return NODE_NORMAL;
+ if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))
+ return NODE_NORMAL;
+ if (S_ISBLK(st.st_mode)) /* block device isn't writable */
+ return NODE_OTHER;
+ /* Everything else is writable? */
+ return NODE_WRITABLE;
+}
+
+ void
+mch_early_init(void)
+{
+#ifdef HAVE_CHECK_STACK_GROWTH
+ int i;
+
+ check_stack_growth((char *)&i);
+
+# ifdef HAVE_STACK_LIMIT
+ get_stack_limit();
+# endif
+
+#endif
+
+ /*
+ * Setup an alternative stack for signals. Helps to catch signals when
+ * running out of stack space.
+ * Use of sigaltstack() is preferred, it's more portable.
+ * Ignore any errors.
+ */
+#if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
+ signal_stack = (char *)alloc(SIGSTKSZ);
+ init_signal_stack();
+#endif
+}
+
+#if defined(EXITFREE) || defined(PROTO)
+ void
+mch_free_mem(void)
+{
+# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
+ if (clip_star.owned)
+ clip_lose_selection(&clip_star);
+ if (clip_plus.owned)
+ clip_lose_selection(&clip_plus);
+# endif
+# if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
+ if (xterm_Shell != (Widget)0)
+ XtDestroyWidget(xterm_Shell);
+# ifndef LESSTIF_VERSION
+ /* Lesstif crashes here, lose some memory */
+ if (xterm_dpy != NULL)
+ XtCloseDisplay(xterm_dpy);
+ if (app_context != (XtAppContext)NULL)
+ {
+ XtDestroyApplicationContext(app_context);
+# ifdef FEAT_X11
+ x11_display = NULL; /* freed by XtDestroyApplicationContext() */
+# endif
+ }
+# endif
+# endif
+# if defined(FEAT_X11)
+ if (x11_display != NULL
+# ifdef FEAT_XCLIPBOARD
+ && x11_display != xterm_dpy
+# endif
+ )
+ XCloseDisplay(x11_display);
+# endif
+# if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
+ VIM_CLEAR(signal_stack);
+# endif
+# ifdef FEAT_TITLE
+ vim_free(oldtitle);
+ vim_free(oldicon);
+# endif
+}
+#endif
+
+/*
+ * Output a newline when exiting.
+ * Make sure the newline goes to the same stream as the text.
+ */
+ static void
+exit_scroll(void)
+{
+ if (silent_mode)
+ return;
+ if (newline_on_exit || msg_didout)
+ {
+ if (msg_use_printf())
+ {
+ if (info_message)
+ mch_msg("\n");
+ else
+ mch_errmsg("\r\n");
+ }
+ else
+ out_char('\n');
+ }
+ else
+ {
+ restore_cterm_colors(); /* get original colors back */
+ msg_clr_eos_force(); /* clear the rest of the display */
+ windgoto((int)Rows - 1, 0); /* may have moved the cursor */
+ }
+}
+
+ void
+mch_exit(int r)
+{
+ exiting = TRUE;
+
+#if defined(FEAT_X11) && defined(FEAT_CLIPBOARD)
+ x11_export_final_selection();
+#endif
+
+#ifdef FEAT_GUI
+ if (!gui.in_use)
+#endif
+ {
+ settmode(TMODE_COOK);
+#ifdef FEAT_TITLE
+ // restore xterm title and icon name
+ mch_restore_title(SAVE_RESTORE_BOTH);
+ term_pop_title(SAVE_RESTORE_BOTH);
+#endif
+ /*
+ * When t_ti is not empty but it doesn't cause swapping terminal
+ * pages, need to output a newline when msg_didout is set. But when
+ * t_ti does swap pages it should not go to the shell page. Do this
+ * before stoptermcap().
+ */
+ if (swapping_screen() && !newline_on_exit)
+ exit_scroll();
+
+ /* Stop termcap: May need to check for T_CRV response, which
+ * requires RAW mode. */
+ stoptermcap();
+
+ /*
+ * A newline is only required after a message in the alternate screen.
+ * This is set to TRUE by wait_return().
+ */
+ if (!swapping_screen() || newline_on_exit)
+ exit_scroll();
+
+ /* Cursor may have been switched off without calling starttermcap()
+ * when doing "vim -u vimrc" and vimrc contains ":q". */
+ if (full_screen)
+ cursor_on();
+ }
+ out_flush();
+ ml_close_all(TRUE); /* remove all memfiles */
+ may_core_dump();
+#ifdef FEAT_GUI
+ if (gui.in_use)
+ gui_exit(r);
+#endif
+
+#ifdef MACOS_CONVERT
+ mac_conv_cleanup();
+#endif
+
+#ifdef __QNX__
+ /* A core dump won't be created if the signal handler
+ * doesn't return, so we can't call exit() */
+ if (deadly_signal != 0)
+ return;
+#endif
+
+#ifdef FEAT_NETBEANS_INTG
+ netbeans_send_disconnect();
+#endif
+
+#ifdef EXITFREE
+ free_all_mem();
+#endif
+
+ exit(r);
+}
+
+ static void
+may_core_dump(void)
+{
+ if (deadly_signal != 0)
+ {
+ signal(deadly_signal, SIG_DFL);
+ kill(getpid(), deadly_signal); /* Die using the signal we caught */
+ }
+}
+
+#ifndef VMS
+
+/*
+ * Get the file descriptor to use for tty operations.
+ */
+ static int
+get_tty_fd(int fd)
+{
+ int tty_fd = fd;
+
+#if defined(HAVE_SVR4_PTYS) && defined(SUN_SYSTEM)
+ // On SunOS: Get the terminal parameters from "fd", or the slave device of
+ // "fd" when it is a master device.
+ if (mch_isatty(fd) > 1)
+ {
+ char *name;
+
+ name = ptsname(fd);
+ if (name == NULL)
+ return -1;
+
+ tty_fd = open(name, O_RDONLY | O_NOCTTY | O_EXTRA, 0);
+ if (tty_fd < 0)
+ return -1;
+ }
+#endif
+ return tty_fd;
+}
+
+ static int
+mch_tcgetattr(int fd, void *term)
+{
+ int tty_fd;
+ int retval = -1;
+
+ tty_fd = get_tty_fd(fd);
+ if (tty_fd >= 0)
+ {
+#ifdef NEW_TTY_SYSTEM
+# ifdef HAVE_TERMIOS_H
+ retval = tcgetattr(tty_fd, (struct termios *)term);
+# else
+ retval = ioctl(tty_fd, TCGETA, (struct termio *)term);
+# endif
+#else
+ // for "old" tty systems
+ retval = ioctl(tty_fd, TIOCGETP, (struct sgttyb *)term);
+#endif
+ if (tty_fd != fd)
+ close(tty_fd);
+ }
+ return retval;
+}
+
+ void
+mch_settmode(int tmode)
+{
+ static int first = TRUE;
+
+#ifdef NEW_TTY_SYSTEM
+# ifdef HAVE_TERMIOS_H
+ static struct termios told;
+ struct termios tnew;
+# else
+ static struct termio told;
+ struct termio tnew;
+# endif
+
+ if (first)
+ {
+ first = FALSE;
+ mch_tcgetattr(read_cmd_fd, &told);
+ }
+
+ tnew = told;
+ if (tmode == TMODE_RAW)
+ {
+ /*
+ * ~ICRNL enables typing ^V^M
+ */
+ tnew.c_iflag &= ~ICRNL;
+ tnew.c_lflag &= ~(ICANON | ECHO | ISIG | ECHOE
+# if defined(IEXTEN) && !defined(__MINT__)
+ | IEXTEN /* IEXTEN enables typing ^V on SOLARIS */
+ /* but it breaks function keys on MINT */
+# endif
+ );
+# ifdef ONLCR /* don't map NL -> CR NL, we do it ourselves */
+ tnew.c_oflag &= ~ONLCR;
+# endif
+ tnew.c_cc[VMIN] = 1; /* return after 1 char */
+ tnew.c_cc[VTIME] = 0; /* don't wait */
+ }
+ else if (tmode == TMODE_SLEEP)
+ {
+ /* Also reset ICANON here, otherwise on Solaris select() won't see
+ * typeahead characters. */
+ tnew.c_lflag &= ~(ICANON | ECHO);
+ tnew.c_cc[VMIN] = 1; /* return after 1 char */
+ tnew.c_cc[VTIME] = 0; /* don't wait */
+ }
+
+# if defined(HAVE_TERMIOS_H)
+ {
+ int n = 10;
+
+ /* A signal may cause tcsetattr() to fail (e.g., SIGCONT). Retry a
+ * few times. */
+ while (tcsetattr(read_cmd_fd, TCSANOW, &tnew) == -1
+ && errno == EINTR && n > 0)
+ --n;
+ }
+# else
+ ioctl(read_cmd_fd, TCSETA, &tnew);
+# endif
+
+#else
+ /*
+ * for "old" tty systems
+ */
+# ifndef TIOCSETN
+# define TIOCSETN TIOCSETP /* for hpux 9.0 */
+# endif
+ static struct sgttyb ttybold;
+ struct sgttyb ttybnew;
+
+ if (first)
+ {
+ first = FALSE;
+ mch_tcgetattr(read_cmd_fd, &ttybold);
+ }
+
+ ttybnew = ttybold;
+ if (tmode == TMODE_RAW)
+ {
+ ttybnew.sg_flags &= ~(CRMOD | ECHO);
+ ttybnew.sg_flags |= RAW;
+ }
+ else if (tmode == TMODE_SLEEP)
+ ttybnew.sg_flags &= ~(ECHO);
+ ioctl(read_cmd_fd, TIOCSETN, &ttybnew);
+#endif
+ curr_tmode = tmode;
+}
+
+/*
+ * Try to get the code for "t_kb" from the stty setting
+ *
+ * Even if termcap claims a backspace key, the user's setting *should*
+ * prevail. stty knows more about reality than termcap does, and if
+ * somebody's usual erase key is DEL (which, for most BSD users, it will
+ * be), they're going to get really annoyed if their erase key starts
+ * doing forward deletes for no reason. (Eric Fischer)
+ */
+ void
+get_stty(void)
+{
+ ttyinfo_T info;
+ char_u buf[2];
+ char_u *p;
+
+ if (get_tty_info(read_cmd_fd, &info) == OK)
+ {
+ intr_char = info.interrupt;
+ buf[0] = info.backspace;
+ buf[1] = NUL;
+ add_termcode((char_u *)"kb", buf, FALSE);
+
+ /* If <BS> and <DEL> are now the same, redefine <DEL>. */
+ p = find_termcode((char_u *)"kD");
+ if (p != NULL && p[0] == buf[0] && p[1] == buf[1])
+ do_fixdel(NULL);
+ }
+}
+
+/*
+ * Obtain the characters that Backspace and Enter produce on "fd".
+ * Returns OK or FAIL.
+ */
+ int
+get_tty_info(int fd, ttyinfo_T *info)
+{
+#ifdef NEW_TTY_SYSTEM
+# ifdef HAVE_TERMIOS_H
+ struct termios keys;
+# else
+ struct termio keys;
+# endif
+
+ if (mch_tcgetattr(fd, &keys) != -1)
+ {
+ info->backspace = keys.c_cc[VERASE];
+ info->interrupt = keys.c_cc[VINTR];
+ if (keys.c_iflag & ICRNL)
+ info->enter = NL;
+ else
+ info->enter = CAR;
+ if (keys.c_oflag & ONLCR)
+ info->nl_does_cr = TRUE;
+ else
+ info->nl_does_cr = FALSE;
+ return OK;
+ }
+#else
+ /* for "old" tty systems */
+ struct sgttyb keys;
+
+ if (mch_tcgetattr(fd, &keys) != -1)
+ {
+ info->backspace = keys.sg_erase;
+ info->interrupt = keys.sg_kill;
+ info->enter = CAR;
+ info->nl_does_cr = TRUE;
+ return OK;
+ }
+#endif
+ return FAIL;
+}
+
+#endif /* VMS */
+
+#if defined(FEAT_MOUSE_TTY) || defined(PROTO)
+static int mouse_ison = FALSE;
+
+/*
+ * Set mouse clicks on or off.
+ */
+ void
+mch_setmouse(int on)
+{
+# ifdef FEAT_BEVAL_TERM
+ static int bevalterm_ison = FALSE;
+# endif
+ int xterm_mouse_vers;
+
+# if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
+ if (!on)
+ // Make sure not tracing mouse movements. Important when a button-down
+ // was received but no release yet.
+ stop_xterm_trace();
+# endif
+
+ if (on == mouse_ison
+# ifdef FEAT_BEVAL_TERM
+ && p_bevalterm == bevalterm_ison
+# endif
+ )
+ /* return quickly if nothing to do */
+ return;
+
+ xterm_mouse_vers = use_xterm_mouse();
+
+# ifdef FEAT_MOUSE_URXVT
+ if (ttym_flags == TTYM_URXVT)
+ {
+ out_str_nf((char_u *)
+ (on
+ ? IF_EB("\033[?1015h", ESC_STR "[?1015h")
+ : IF_EB("\033[?1015l", ESC_STR "[?1015l")));
+ mouse_ison = on;
+ }
+# endif
+
+# ifdef FEAT_MOUSE_SGR
+ if (ttym_flags == TTYM_SGR)
+ {
+ /* SGR mode supports columns above 223 */
+ out_str_nf((char_u *)
+ (on
+ ? IF_EB("\033[?1006h", ESC_STR "[?1006h")
+ : IF_EB("\033[?1006l", ESC_STR "[?1006l")));
+ mouse_ison = on;
+ }
+# endif
+
+# ifdef FEAT_BEVAL_TERM
+ if (bevalterm_ison != (p_bevalterm && on))
+ {
+ bevalterm_ison = (p_bevalterm && on);
+ if (xterm_mouse_vers > 1 && !bevalterm_ison)
+ /* disable mouse movement events, enabling is below */
+ out_str_nf((char_u *)
+ (IF_EB("\033[?1003l", ESC_STR "[?1003l")));
+ }
+# endif
+
+ if (xterm_mouse_vers > 0)
+ {
+ if (on) /* enable mouse events, use mouse tracking if available */
+ out_str_nf((char_u *)
+ (xterm_mouse_vers > 1
+ ? (
+# ifdef FEAT_BEVAL_TERM
+ bevalterm_ison
+ ? IF_EB("\033[?1003h", ESC_STR "[?1003h") :
+# endif
+ IF_EB("\033[?1002h", ESC_STR "[?1002h"))
+ : IF_EB("\033[?1000h", ESC_STR "[?1000h")));
+ else /* disable mouse events, could probably always send the same */
+ out_str_nf((char_u *)
+ (xterm_mouse_vers > 1
+ ? IF_EB("\033[?1002l", ESC_STR "[?1002l")
+ : IF_EB("\033[?1000l", ESC_STR "[?1000l")));
+ mouse_ison = on;
+ }
+
+# ifdef FEAT_MOUSE_DEC
+ else if (ttym_flags == TTYM_DEC)
+ {
+ if (on) /* enable mouse events */
+ out_str_nf((char_u *)"\033[1;2'z\033[1;3'{");
+ else /* disable mouse events */
+ out_str_nf((char_u *)"\033['z");
+ mouse_ison = on;
+ }
+# endif
+
+# ifdef FEAT_MOUSE_GPM
+ else
+ {
+ if (on)
+ {
+ if (gpm_open())
+ mouse_ison = TRUE;
+ }
+ else
+ {
+ gpm_close();
+ mouse_ison = FALSE;
+ }
+ }
+# endif
+
+# ifdef FEAT_SYSMOUSE
+ else
+ {
+ if (on)
+ {
+ if (sysmouse_open() == OK)
+ mouse_ison = TRUE;
+ }
+ else
+ {
+ sysmouse_close();
+ mouse_ison = FALSE;
+ }
+ }
+# endif
+
+# ifdef FEAT_MOUSE_JSB
+ else
+ {
+ if (on)
+ {
+ /* D - Enable Mouse up/down messages
+ * L - Enable Left Button Reporting
+ * M - Enable Middle Button Reporting
+ * R - Enable Right Button Reporting
+ * K - Enable SHIFT and CTRL key Reporting
+ * + - Enable Advanced messaging of mouse moves and up/down messages
+ * Q - Quiet No Ack
+ * # - Numeric value of mouse pointer required
+ * 0 = Multiview 2000 cursor, used as standard
+ * 1 = Windows Arrow
+ * 2 = Windows I Beam
+ * 3 = Windows Hour Glass
+ * 4 = Windows Cross Hair
+ * 5 = Windows UP Arrow
+ */
+# ifdef JSBTERM_MOUSE_NONADVANCED
+ /* Disables full feedback of pointer movements */
+ out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK1Q\033\\",
+ ESC_STR "[0~ZwLMRK1Q" ESC_STR "\\"));
+# else
+ out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK+1Q\033\\",
+ ESC_STR "[0~ZwLMRK+1Q" ESC_STR "\\"));
+# endif
+ mouse_ison = TRUE;
+ }
+ else
+ {
+ out_str_nf((char_u *)IF_EB("\033[0~ZwQ\033\\",
+ ESC_STR "[0~ZwQ" ESC_STR "\\"));
+ mouse_ison = FALSE;
+ }
+ }
+# endif
+# ifdef FEAT_MOUSE_PTERM
+ else
+ {
+ /* 1 = button press, 6 = release, 7 = drag, 1h...9l = right button */
+ if (on)
+ out_str_nf("\033[>1h\033[>6h\033[>7h\033[>1h\033[>9l");
+ else
+ out_str_nf("\033[>1l\033[>6l\033[>7l\033[>1l\033[>9h");
+ mouse_ison = on;
+ }
+# endif
+}
+
+#if defined(FEAT_BEVAL_TERM) || defined(PROTO)
+/*
+ * Called when 'balloonevalterm' changed.
+ */
+ void
+mch_bevalterm_changed(void)
+{
+ mch_setmouse(mouse_ison);
+}
+#endif
+
+/*
+ * Set the mouse termcode, depending on the 'term' and 'ttymouse' options.
+ */
+ void
+check_mouse_termcode(void)
+{
+# ifdef FEAT_MOUSE_XTERM
+ if (use_xterm_mouse()
+# ifdef FEAT_MOUSE_URXVT
+ && use_xterm_mouse() != 3
+# endif
+# ifdef FEAT_GUI
+ && !gui.in_use
+# endif
+ )
+ {
+ set_mouse_termcode(KS_MOUSE, (char_u *)(term_is_8bit(T_NAME)
+ ? IF_EB("\233M", CSI_STR "M")
+ : IF_EB("\033[M", ESC_STR "[M")));
+ if (*p_mouse != NUL)
+ {
+ /* force mouse off and maybe on to send possibly new mouse
+ * activation sequence to the xterm, with(out) drag tracing. */
+ mch_setmouse(FALSE);
+ setmouse();
+ }
+ }
+ else
+ del_mouse_termcode(KS_MOUSE);
+# endif
+
+# ifdef FEAT_MOUSE_GPM
+ if (!use_xterm_mouse()
+# ifdef FEAT_GUI
+ && !gui.in_use
+# endif
+ )
+ set_mouse_termcode(KS_MOUSE, (char_u *)IF_EB("\033MG", ESC_STR "MG"));
+# endif
+
+# ifdef FEAT_SYSMOUSE
+ if (!use_xterm_mouse()
+# ifdef FEAT_GUI
+ && !gui.in_use
+# endif
+ )
+ set_mouse_termcode(KS_MOUSE, (char_u *)IF_EB("\033MS", ESC_STR "MS"));
+# endif
+
+# ifdef FEAT_MOUSE_JSB
+ /* Conflicts with xterm mouse: "\033[" and "\033[M" ??? */
+ if (!use_xterm_mouse()
+# ifdef FEAT_GUI
+ && !gui.in_use
+# endif
+ )
+ set_mouse_termcode(KS_JSBTERM_MOUSE,
+ (char_u *)IF_EB("\033[0~zw", ESC_STR "[0~zw"));
+ else
+ del_mouse_termcode(KS_JSBTERM_MOUSE);
+# endif
+
+# ifdef FEAT_MOUSE_NET
+ /* There is no conflict, but one may type "ESC }" from Insert mode. Don't
+ * define it in the GUI or when using an xterm. */
+ if (!use_xterm_mouse()
+# ifdef FEAT_GUI
+ && !gui.in_use
+# endif
+ )
+ set_mouse_termcode(KS_NETTERM_MOUSE,
+ (char_u *)IF_EB("\033}", ESC_STR "}"));
+ else
+ del_mouse_termcode(KS_NETTERM_MOUSE);
+# endif
+
+# ifdef FEAT_MOUSE_DEC
+ /* Conflicts with xterm mouse: "\033[" and "\033[M" */
+ if (!use_xterm_mouse()
+# ifdef FEAT_GUI
+ && !gui.in_use
+# endif
+ )
+ set_mouse_termcode(KS_DEC_MOUSE, (char_u *)(term_is_8bit(T_NAME)
+ ? IF_EB("\233", CSI_STR) : IF_EB("\033[", ESC_STR "[")));
+ else
+ del_mouse_termcode(KS_DEC_MOUSE);
+# endif
+# ifdef FEAT_MOUSE_PTERM
+ /* same conflict as the dec mouse */
+ if (!use_xterm_mouse()
+# ifdef FEAT_GUI
+ && !gui.in_use
+# endif
+ )
+ set_mouse_termcode(KS_PTERM_MOUSE,
+ (char_u *) IF_EB("\033[", ESC_STR "["));
+ else
+ del_mouse_termcode(KS_PTERM_MOUSE);
+# endif
+# ifdef FEAT_MOUSE_URXVT
+ if (use_xterm_mouse() == 3
+# ifdef FEAT_GUI
+ && !gui.in_use
+# endif
+ )
+ {
+ set_mouse_termcode(KS_URXVT_MOUSE, (char_u *)(term_is_8bit(T_NAME)
+ ? IF_EB("\233*M", CSI_STR "*M")
+ : IF_EB("\033[*M", ESC_STR "[*M")));
+
+ if (*p_mouse != NUL)
+ {
+ mch_setmouse(FALSE);
+ setmouse();
+ }
+ }
+ else
+ del_mouse_termcode(KS_URXVT_MOUSE);
+# endif
+# ifdef FEAT_MOUSE_SGR
+ if (use_xterm_mouse() == 4
+# ifdef FEAT_GUI
+ && !gui.in_use
+# endif
+ )
+ {
+ set_mouse_termcode(KS_SGR_MOUSE, (char_u *)(term_is_8bit(T_NAME)
+ ? IF_EB("\233<*M", CSI_STR "<*M")
+ : IF_EB("\033[<*M", ESC_STR "[<*M")));
+
+ set_mouse_termcode(KS_SGR_MOUSE_RELEASE, (char_u *)(term_is_8bit(T_NAME)
+ ? IF_EB("\233<*m", CSI_STR "<*m")
+ : IF_EB("\033[<*m", ESC_STR "[<*m")));
+
+ if (*p_mouse != NUL)
+ {
+ mch_setmouse(FALSE);
+ setmouse();
+ }
+ }
+ else
+ {
+ del_mouse_termcode(KS_SGR_MOUSE);
+ del_mouse_termcode(KS_SGR_MOUSE_RELEASE);
+ }
+# endif
+}
+#endif
+
+/*
+ * set screen mode, always fails.
+ */
+ int
+mch_screenmode(char_u *arg UNUSED)
+{
+ emsg(_(e_screenmode));
+ return FAIL;
+}
+
+#ifndef VMS
+
+/*
+ * Try to get the current window size:
+ * 1. with an ioctl(), most accurate method
+ * 2. from the environment variables LINES and COLUMNS
+ * 3. from the termcap
+ * 4. keep using the old values
+ * Return OK when size could be determined, FAIL otherwise.
+ */
+ int
+mch_get_shellsize(void)
+{
+ long rows = 0;
+ long columns = 0;
+ char_u *p;
+
+ /*
+ * 1. try using an ioctl. It is the most accurate method.
+ *
+ * Try using TIOCGWINSZ first, some systems that have it also define
+ * TIOCGSIZE but don't have a struct ttysize.
+ */
+# ifdef TIOCGWINSZ
+ {
+ struct winsize ws;
+ int fd = 1;
+
+ /* When stdout is not a tty, use stdin for the ioctl(). */
+ if (!isatty(fd) && isatty(read_cmd_fd))
+ fd = read_cmd_fd;
+ if (ioctl(fd, TIOCGWINSZ, &ws) == 0)
+ {
+ columns = ws.ws_col;
+ rows = ws.ws_row;
+ }
+ }
+# else /* TIOCGWINSZ */
+# ifdef TIOCGSIZE
+ {
+ struct ttysize ts;
+ int fd = 1;
+
+ /* When stdout is not a tty, use stdin for the ioctl(). */
+ if (!isatty(fd) && isatty(read_cmd_fd))
+ fd = read_cmd_fd;
+ if (ioctl(fd, TIOCGSIZE, &ts) == 0)
+ {
+ columns = ts.ts_cols;
+ rows = ts.ts_lines;
+ }
+ }
+# endif /* TIOCGSIZE */
+# endif /* TIOCGWINSZ */
+
+ /*
+ * 2. get size from environment
+ * When being POSIX compliant ('|' flag in 'cpoptions') this overrules
+ * the ioctl() values!
+ */
+ if (columns == 0 || rows == 0 || vim_strchr(p_cpo, CPO_TSIZE) != NULL)
+ {
+ if ((p = (char_u *)getenv("LINES")))
+ rows = atoi((char *)p);
+ if ((p = (char_u *)getenv("COLUMNS")))
+ columns = atoi((char *)p);
+ }
+
+#ifdef HAVE_TGETENT
+ /*
+ * 3. try reading "co" and "li" entries from termcap
+ */
+ if (columns == 0 || rows == 0)
+ getlinecol(&columns, &rows);
+#endif
+
+ /*
+ * 4. If everything fails, use the old values
+ */
+ if (columns <= 0 || rows <= 0)
+ return FAIL;
+
+ Rows = rows;
+ Columns = columns;
+ limit_screen_size();
+ return OK;
+}
+
+#if defined(FEAT_TERMINAL) || defined(PROTO)
+/*
+ * Report the windows size "rows" and "cols" to tty "fd".
+ */
+ int
+mch_report_winsize(int fd, int rows, int cols)
+{
+ int tty_fd;
+ int retval = -1;
+
+ tty_fd = get_tty_fd(fd);
+ if (tty_fd >= 0)
+ {
+# if defined(TIOCSWINSZ)
+ struct winsize ws;
+
+ ws.ws_col = cols;
+ ws.ws_row = rows;
+ ws.ws_xpixel = cols * 5;
+ ws.ws_ypixel = rows * 10;
+ retval = ioctl(tty_fd, TIOCSWINSZ, &ws);
+ ch_log(NULL, "ioctl(TIOCSWINSZ) %s",
+ retval == 0 ? "success" : "failed");
+# elif defined(TIOCSSIZE)
+ struct ttysize ts;
+
+ ts.ts_cols = cols;
+ ts.ts_lines = rows;
+ retval = ioctl(tty_fd, TIOCSSIZE, &ts);
+ ch_log(NULL, "ioctl(TIOCSSIZE) %s",
+ retval == 0 ? "success" : "failed");
+# endif
+ if (tty_fd != fd)
+ close(tty_fd);
+ }
+ return retval == 0 ? OK : FAIL;
+}
+#endif
+
+/*
+ * Try to set the window size to Rows and Columns.
+ */
+ void
+mch_set_shellsize(void)
+{
+ if (*T_CWS)
+ {
+ /*
+ * NOTE: if you get an error here that term_set_winsize() is
+ * undefined, check the output of configure. It could probably not
+ * find a ncurses, termcap or termlib library.
+ */
+ term_set_winsize((int)Rows, (int)Columns);
+ out_flush();
+ screen_start(); /* don't know where cursor is now */
+ }
+}
+
+#endif /* VMS */
+
+/*
+ * Rows and/or Columns has changed.
+ */
+ void
+mch_new_shellsize(void)
+{
+ /* Nothing to do. */
+}
+
+/*
+ * Wait for process "child" to end.
+ * Return "child" if it exited properly, <= 0 on error.
+ */
+ static pid_t
+wait4pid(pid_t child, waitstatus *status)
+{
+ pid_t wait_pid = 0;
+ long delay_msec = 1;
+
+ while (wait_pid != child)
+ {
+ /* When compiled with Python threads are probably used, in which case
+ * wait() sometimes hangs for no obvious reason. Use waitpid()
+ * instead and loop (like the GUI). Also needed for other interfaces,
+ * they might call system(). */
+# ifdef __NeXT__
+ wait_pid = wait4(child, status, WNOHANG, (struct rusage *)0);
+# else
+ wait_pid = waitpid(child, status, WNOHANG);
+# endif
+ if (wait_pid == 0)
+ {
+ /* Wait for 1 to 10 msec before trying again. */
+ mch_delay(delay_msec, TRUE);
+ if (++delay_msec > 10)
+ delay_msec = 10;
+ continue;
+ }
+ if (wait_pid <= 0
+# ifdef ECHILD
+ && errno == ECHILD
+# endif
+ )
+ break;
+ }
+ return wait_pid;
+}
+
+#if !defined(USE_SYSTEM) || defined(FEAT_JOB_CHANNEL)
+/*
+ * Set the environment for a child process.
+ */
+ static void
+set_child_environment(
+ long rows,
+ long columns,
+ char *term,
+ int is_terminal UNUSED)
+{
+# ifdef HAVE_SETENV
+ char envbuf[50];
+# else
+ static char envbuf_Term[30];
+ static char envbuf_Rows[20];
+ static char envbuf_Lines[20];
+ static char envbuf_Columns[20];
+ static char envbuf_Colors[20];
+# ifdef FEAT_TERMINAL
+ static char envbuf_Version[20];
+# endif
+# ifdef FEAT_CLIENTSERVER
+ static char envbuf_Servername[60];
+# endif
+# endif
+ long colors =
+# ifdef FEAT_GUI
+ gui.in_use ? 256*256*256 :
+# endif
+ t_colors;
+
+# ifdef HAVE_SETENV
+ setenv("TERM", term, 1);
+ sprintf((char *)envbuf, "%ld", rows);
+ setenv("ROWS", (char *)envbuf, 1);
+ sprintf((char *)envbuf, "%ld", rows);
+ setenv("LINES", (char *)envbuf, 1);
+ sprintf((char *)envbuf, "%ld", columns);
+ setenv("COLUMNS", (char *)envbuf, 1);
+ sprintf((char *)envbuf, "%ld", colors);
+ setenv("COLORS", (char *)envbuf, 1);
+# ifdef FEAT_TERMINAL
+ if (is_terminal)
+ {
+ sprintf((char *)envbuf, "%ld", (long)get_vim_var_nr(VV_VERSION));
+ setenv("VIM_TERMINAL", (char *)envbuf, 1);
+ }
+# endif
+# ifdef FEAT_CLIENTSERVER
+ setenv("VIM_SERVERNAME", serverName == NULL ? "" : (char *)serverName, 1);
+# endif
+# else
+ /*
+ * Putenv does not copy the string, it has to remain valid.
+ * Use a static array to avoid losing allocated memory.
+ * This won't work well when running multiple children...
+ */
+ vim_snprintf(envbuf_Term, sizeof(envbuf_Term), "TERM=%s", term);
+ putenv(envbuf_Term);
+ vim_snprintf(envbuf_Rows, sizeof(envbuf_Rows), "ROWS=%ld", rows);
+ putenv(envbuf_Rows);
+ vim_snprintf(envbuf_Lines, sizeof(envbuf_Lines), "LINES=%ld", rows);
+ putenv(envbuf_Lines);
+ vim_snprintf(envbuf_Columns, sizeof(envbuf_Columns),
+ "COLUMNS=%ld", columns);
+ putenv(envbuf_Columns);
+ vim_snprintf(envbuf_Colors, sizeof(envbuf_Colors), "COLORS=%ld", colors);
+ putenv(envbuf_Colors);
+# ifdef FEAT_TERMINAL
+ if (is_terminal)
+ {
+ vim_snprintf(envbuf_Version, sizeof(envbuf_Version),
+ "VIM_TERMINAL=%ld", (long)get_vim_var_nr(VV_VERSION));
+ putenv(envbuf_Version);
+ }
+# endif
+# ifdef FEAT_CLIENTSERVER
+ vim_snprintf(envbuf_Servername, sizeof(envbuf_Servername),
+ "VIM_SERVERNAME=%s", serverName == NULL ? "" : (char *)serverName);
+ putenv(envbuf_Servername);
+# endif
+# endif
+}
+
+ static void
+set_default_child_environment(int is_terminal)
+{
+ set_child_environment(Rows, Columns, "dumb", is_terminal);
+}
+#endif
+
+#if defined(FEAT_GUI) || defined(FEAT_JOB_CHANNEL)
+/*
+ * Open a PTY, with FD for the master and slave side.
+ * When failing "pty_master_fd" and "pty_slave_fd" are -1.
+ * When successful both file descriptors are stored.
+ */
+ static void
+open_pty(int *pty_master_fd, int *pty_slave_fd, char_u **namep)
+{
+ char *tty_name;
+
+ *pty_master_fd = mch_openpty(&tty_name); // open pty
+ if (*pty_master_fd >= 0)
+ {
+ /* Leaving out O_NOCTTY may lead to waitpid() always returning
+ * 0 on Mac OS X 10.7 thereby causing freezes. Let's assume
+ * adding O_NOCTTY always works when defined. */
+#ifdef O_NOCTTY
+ *pty_slave_fd = open(tty_name, O_RDWR | O_NOCTTY | O_EXTRA, 0);
+#else
+ *pty_slave_fd = open(tty_name, O_RDWR | O_EXTRA, 0);
+#endif
+ if (*pty_slave_fd < 0)
+ {
+ close(*pty_master_fd);
+ *pty_master_fd = -1;
+ }
+ else if (namep != NULL)
+ *namep = vim_strsave((char_u *)tty_name);
+ }
+}
+#endif
+
+/*
+ * Send SIGINT to a child process if "c" is an interrupt character.
+ */
+ void
+may_send_sigint(int c UNUSED, pid_t pid UNUSED, pid_t wpid UNUSED)
+{
+# ifdef SIGINT
+ if (c == Ctrl_C || c == intr_char)
+ {
+# ifdef HAVE_SETSID
+ kill(-pid, SIGINT);
+# else
+ kill(0, SIGINT);
+# endif
+ if (wpid > 0)
+ kill(wpid, SIGINT);
+ }
+# endif
+}
+
+#if !defined(USE_SYSTEM) || (defined(FEAT_GUI) && defined(FEAT_TERMINAL))
+
+ static int
+build_argv(
+ char_u *cmd,
+ char ***argvp,
+ char_u **sh_tofree,
+ char_u **shcf_tofree)
+{
+ char **argv = NULL;
+ int argc;
+
+ *sh_tofree = vim_strsave(p_sh);
+ if (*sh_tofree == NULL) /* out of memory */
+ return FAIL;
+
+ if (mch_parse_cmd(*sh_tofree, TRUE, &argv, &argc) == FAIL)
+ return FAIL;
+ *argvp = argv;
+
+ if (cmd != NULL)
+ {
+ char_u *s;
+ char_u *p;
+
+ if (extra_shell_arg != NULL)
+ argv[argc++] = (char *)extra_shell_arg;
+
+ /* Break 'shellcmdflag' into white separated parts. This doesn't
+ * handle quoted strings, they are very unlikely to appear. */
+ *shcf_tofree = alloc((unsigned)STRLEN(p_shcf) + 1);
+ if (*shcf_tofree == NULL) /* out of memory */
+ return FAIL;
+ s = *shcf_tofree;
+ p = p_shcf;
+ while (*p != NUL)
+ {
+ argv[argc++] = (char *)s;
+ while (*p && *p != ' ' && *p != TAB)
+ *s++ = *p++;
+ *s++ = NUL;
+ p = skipwhite(p);
+ }
+
+ argv[argc++] = (char *)cmd;
+ }
+ argv[argc] = NULL;
+ return OK;
+}
+#endif
+
+#if defined(FEAT_GUI) && defined(FEAT_TERMINAL)
+/*
+ * Use a terminal window to run a shell command in.
+ */
+ static int
+mch_call_shell_terminal(
+ char_u *cmd,
+ int options UNUSED) /* SHELL_*, see vim.h */
+{
+ jobopt_T opt;
+ char **argv = NULL;
+ char_u *tofree1 = NULL;
+ char_u *tofree2 = NULL;
+ int retval = -1;
+ buf_T *buf;
+ job_T *job;
+ aco_save_T aco;
+ oparg_T oa; /* operator arguments */
+
+ if (build_argv(cmd, &argv, &tofree1, &tofree2) == FAIL)
+ goto theend;
+
+ init_job_options(&opt);
+ ch_log(NULL, "starting terminal for system command '%s'", cmd);
+ buf = term_start(NULL, argv, &opt, TERM_START_SYSTEM);
+ if (buf == NULL)
+ goto theend;
+
+ job = term_getjob(buf->b_term);
+ ++job->jv_refcount;
+
+ /* Find a window to make "buf" curbuf. */
+ aucmd_prepbuf(&aco, buf);
+
+ clear_oparg(&oa);
+ while (term_use_loop())
+ {
+ if (oa.op_type == OP_NOP && oa.regname == NUL && !VIsual_active)
+ {
+ /* If terminal_loop() returns OK we got a key that is handled
+ * in Normal model. We don't do redrawing anyway. */
+ if (terminal_loop(TRUE) == OK)
+ normal_cmd(&oa, TRUE);
+ }
+ else
+ normal_cmd(&oa, TRUE);
+ }
+ retval = job->jv_exitval;
+ ch_log(NULL, "system command finished");
+
+ job_unref(job);
+
+ /* restore curwin/curbuf and a few other things */
+ aucmd_restbuf(&aco);
+
+ wait_return(TRUE);
+ do_buffer(DOBUF_WIPE, DOBUF_FIRST, FORWARD, buf->b_fnum, TRUE);
+
+theend:
+ vim_free(argv);
+ vim_free(tofree1);
+ vim_free(tofree2);
+ return retval;
+}
+#endif
+
+#ifdef USE_SYSTEM
+/*
+ * Use system() to start the shell: simple but slow.
+ */
+ static int
+mch_call_shell_system(
+ char_u *cmd,
+ int options) /* SHELL_*, see vim.h */
+{
+#ifdef VMS
+ char *ifn = NULL;
+ char *ofn = NULL;
+#endif
+ int tmode = cur_tmode;
+ char_u *newcmd; /* only needed for unix */
+ int x;
+
+ out_flush();
+
+ if (options & SHELL_COOKED)
+ settmode(TMODE_COOK); /* set to normal mode */
+
+# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
+ save_clipboard();
+ loose_clipboard();
+# endif
+
+ if (cmd == NULL)
+ x = system((char *)p_sh);
+ else
+ {
+# ifdef VMS
+ if (ofn = strchr((char *)cmd, '>'))
+ *ofn++ = '\0';
+ if (ifn = strchr((char *)cmd, '<'))
+ {
+ char *p;
+
+ *ifn++ = '\0';
+ p = strchr(ifn,' '); /* chop off any trailing spaces */
+ if (p)
+ *p = '\0';
+ }
+ if (ofn)
+ x = vms_sys((char *)cmd, ofn, ifn);
+ else
+ x = system((char *)cmd);
+# else
+ newcmd = lalloc(STRLEN(p_sh)
+ + (extra_shell_arg == NULL ? 0 : STRLEN(extra_shell_arg))
+ + STRLEN(p_shcf) + STRLEN(cmd) + 4, TRUE);
+ if (newcmd == NULL)
+ x = 0;
+ else
+ {
+ sprintf((char *)newcmd, "%s %s %s %s", p_sh,
+ extra_shell_arg == NULL ? "" : (char *)extra_shell_arg,
+ (char *)p_shcf,
+ (char *)cmd);
+ x = system((char *)newcmd);
+ vim_free(newcmd);
+ }
+# endif
+ }
+# ifdef VMS
+ x = vms_sys_status(x);
+# endif
+ if (emsg_silent)
+ ;
+ else if (x == 127)
+ msg_puts(_("\nCannot execute shell sh\n"));
+ else if (x && !(options & SHELL_SILENT))
+ {
+ msg_puts(_("\nshell returned "));
+ msg_outnum((long)x);
+ msg_putchar('\n');
+ }
+
+ if (tmode == TMODE_RAW)
+ settmode(TMODE_RAW); /* set to raw mode */
+# ifdef FEAT_TITLE
+ resettitle();
+# endif
+# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
+ restore_clipboard();
+# endif
+ return x;
+}
+
+#else /* USE_SYSTEM */
+
+# define EXEC_FAILED 122 /* Exit code when shell didn't execute. Don't use
+ 127, some shells use that already */
+# define OPEN_NULL_FAILED 123 /* Exit code if /dev/null can't be opened */
+
+/*
+ * Don't use system(), use fork()/exec().
+ */
+ static int
+mch_call_shell_fork(
+ char_u *cmd,
+ int options) /* SHELL_*, see vim.h */
+{
+ int tmode = cur_tmode;
+ pid_t pid;
+ pid_t wpid = 0;
+ pid_t wait_pid = 0;
+# ifdef HAVE_UNION_WAIT
+ union wait status;
+# else
+ int status = -1;
+# endif
+ int retval = -1;
+ char **argv = NULL;
+ char_u *tofree1 = NULL;
+ char_u *tofree2 = NULL;
+ int i;
+ int pty_master_fd = -1; /* for pty's */
+# ifdef FEAT_GUI
+ int pty_slave_fd = -1;
+# endif
+ int fd_toshell[2]; /* for pipes */
+ int fd_fromshell[2];
+ int pipe_error = FALSE;
+ int did_settmode = FALSE; /* settmode(TMODE_RAW) called */
+
+ out_flush();
+ if (options & SHELL_COOKED)
+ settmode(TMODE_COOK); /* set to normal mode */
+
+ if (build_argv(cmd, &argv, &tofree1, &tofree2) == FAIL)
+ goto error;
+
+ /*
+ * For the GUI, when writing the output into the buffer and when reading
+ * input from the buffer: Try using a pseudo-tty to get the stdin/stdout
+ * of the executed command into the Vim window. Or use a pipe.
+ */
+ if ((options & (SHELL_READ|SHELL_WRITE))
+# ifdef FEAT_GUI
+ || (gui.in_use && show_shell_mess)
+# endif
+ )
+ {
+# ifdef FEAT_GUI
+ /*
+ * Try to open a master pty.
+ * If this works, open the slave pty.
+ * If the slave can't be opened, close the master pty.
+ */
+ if (p_guipty && !(options & (SHELL_READ|SHELL_WRITE)))
+ open_pty(&pty_master_fd, &pty_slave_fd, NULL);
+ /*
+ * If not opening a pty or it didn't work, try using pipes.
+ */
+ if (pty_master_fd < 0)
+# endif
+ {
+ pipe_error = (pipe(fd_toshell) < 0);
+ if (!pipe_error) /* pipe create OK */
+ {
+ pipe_error = (pipe(fd_fromshell) < 0);
+ if (pipe_error) /* pipe create failed */
+ {
+ close(fd_toshell[0]);
+ close(fd_toshell[1]);
+ }
+ }
+ if (pipe_error)
+ {
+ msg_puts(_("\nCannot create pipes\n"));
+ out_flush();
+ }
+ }
+ }
+
+ if (!pipe_error) /* pty or pipe opened or not used */
+ {
+ SIGSET_DECL(curset)
+
+# ifdef __BEOS__
+ beos_cleanup_read_thread();
+# endif
+
+ BLOCK_SIGNALS(&curset);
+ pid = fork(); /* maybe we should use vfork() */
+ if (pid == -1)
+ {
+ UNBLOCK_SIGNALS(&curset);
+
+ msg_puts(_("\nCannot fork\n"));
+ if ((options & (SHELL_READ|SHELL_WRITE))
+# ifdef FEAT_GUI
+ || (gui.in_use && show_shell_mess)
+# endif
+ )
+ {
+# ifdef FEAT_GUI
+ if (pty_master_fd >= 0) /* close the pseudo tty */
+ {
+ close(pty_master_fd);
+ close(pty_slave_fd);
+ }
+ else /* close the pipes */
+# endif
+ {
+ close(fd_toshell[0]);
+ close(fd_toshell[1]);
+ close(fd_fromshell[0]);
+ close(fd_fromshell[1]);
+ }
+ }
+ }
+ else if (pid == 0) /* child */
+ {
+ reset_signals(); /* handle signals normally */
+ UNBLOCK_SIGNALS(&curset);
+
+# ifdef FEAT_JOB_CHANNEL
+ if (ch_log_active())
+ /* close the log file in the child */
+ ch_logfile((char_u *)"", (char_u *)"");
+# endif
+
+ if (!show_shell_mess || (options & SHELL_EXPAND))
+ {
+ int fd;
+
+ /*
+ * Don't want to show any message from the shell. Can't just
+ * close stdout and stderr though, because some systems will
+ * break if you try to write to them after that, so we must
+ * use dup() to replace them with something else -- webb
+ * Connect stdin to /dev/null too, so ":n `cat`" doesn't hang,
+ * waiting for input.
+ */
+ fd = open("/dev/null", O_RDWR | O_EXTRA, 0);
+ fclose(stdin);
+ fclose(stdout);
+ fclose(stderr);
+
+ /*
+ * If any of these open()'s and dup()'s fail, we just continue
+ * anyway. It's not fatal, and on most systems it will make
+ * no difference at all. On a few it will cause the execvp()
+ * to exit with a non-zero status even when the completion
+ * could be done, which is nothing too serious. If the open()
+ * or dup() failed we'd just do the same thing ourselves
+ * anyway -- webb
+ */
+ if (fd >= 0)
+ {
+ vim_ignored = dup(fd); /* To replace stdin (fd 0) */
+ vim_ignored = dup(fd); /* To replace stdout (fd 1) */
+ vim_ignored = dup(fd); /* To replace stderr (fd 2) */
+
+ /* Don't need this now that we've duplicated it */
+ close(fd);
+ }
+ }
+ else if ((options & (SHELL_READ|SHELL_WRITE))
+# ifdef FEAT_GUI
+ || gui.in_use
+# endif
+ )
+ {
+
+# ifdef HAVE_SETSID
+ /* Create our own process group, so that the child and all its
+ * children can be kill()ed. Don't do this when using pipes,
+ * because stdin is not a tty, we would lose /dev/tty. */
+ if (p_stmp)
+ {
+ (void)setsid();
+# if defined(SIGHUP)
+ /* When doing "!xterm&" and 'shell' is bash: the shell
+ * will exit and send SIGHUP to all processes in its
+ * group, killing the just started process. Ignore SIGHUP
+ * to avoid that. (suggested by Simon Schubert)
+ */
+ signal(SIGHUP, SIG_IGN);
+# endif
+ }
+# endif
+# ifdef FEAT_GUI
+ if (pty_slave_fd >= 0)
+ {
+ /* push stream discipline modules */
+ if (options & SHELL_COOKED)
+ setup_slavepty(pty_slave_fd);
+# ifdef TIOCSCTTY
+ /* Try to become controlling tty (probably doesn't work,
+ * unless run by root) */
+ ioctl(pty_slave_fd, TIOCSCTTY, (char *)NULL);
+# endif
+ }
+# endif
+ set_default_child_environment(FALSE);
+
+ /*
+ * stderr is only redirected when using the GUI, so that a
+ * program like gpg can still access the terminal to get a
+ * passphrase using stderr.
+ */
+# ifdef FEAT_GUI
+ if (pty_master_fd >= 0)
+ {
+ close(pty_master_fd); /* close master side of pty */
+
+ /* set up stdin/stdout/stderr for the child */
+ close(0);
+ vim_ignored = dup(pty_slave_fd);
+ close(1);
+ vim_ignored = dup(pty_slave_fd);
+ if (gui.in_use)
+ {
+ close(2);
+ vim_ignored = dup(pty_slave_fd);
+ }
+
+ close(pty_slave_fd); /* has been dupped, close it now */
+ }
+ else
+# endif
+ {
+ /* set up stdin for the child */
+ close(fd_toshell[1]);
+ close(0);
+ vim_ignored = dup(fd_toshell[0]);
+ close(fd_toshell[0]);
+
+ /* set up stdout for the child */
+ close(fd_fromshell[0]);
+ close(1);
+ vim_ignored = dup(fd_fromshell[1]);
+ close(fd_fromshell[1]);
+
+# ifdef FEAT_GUI
+ if (gui.in_use)
+ {
+ /* set up stderr for the child */
+ close(2);
+ vim_ignored = dup(1);
+ }
+# endif
+ }
+ }
+
+ /*
+ * There is no type cast for the argv, because the type may be
+ * different on different machines. This may cause a warning
+ * message with strict compilers, don't worry about it.
+ * Call _exit() instead of exit() to avoid closing the connection
+ * to the X server (esp. with GTK, which uses atexit()).
+ */
+ execvp(argv[0], argv);
+ _exit(EXEC_FAILED); /* exec failed, return failure code */
+ }
+ else /* parent */
+ {
+ /*
+ * While child is running, ignore terminating signals.
+ * Do catch CTRL-C, so that "got_int" is set.
+ */
+ catch_signals(SIG_IGN, SIG_ERR);
+ catch_int_signal();
+ UNBLOCK_SIGNALS(&curset);
+# ifdef FEAT_JOB_CHANNEL
+ ++dont_check_job_ended;
+# endif
+ /*
+ * For the GUI we redirect stdin, stdout and stderr to our window.
+ * This is also used to pipe stdin/stdout to/from the external
+ * command.
+ */
+ if ((options & (SHELL_READ|SHELL_WRITE))
+# ifdef FEAT_GUI
+ || (gui.in_use && show_shell_mess)
+# endif
+ )
+ {
+# define BUFLEN 100 /* length for buffer, pseudo tty limit is 128 */
+ char_u buffer[BUFLEN + 1];
+ int buffer_off = 0; /* valid bytes in buffer[] */
+ char_u ta_buf[BUFLEN + 1]; /* TypeAHead */
+ int ta_len = 0; /* valid bytes in ta_buf[] */
+ int len;
+ int p_more_save;
+ int old_State;
+ int c;
+ int toshell_fd;
+ int fromshell_fd;
+ garray_T ga;
+ int noread_cnt;
+# ifdef ELAPSED_FUNC
+ elapsed_T start_tv;
+# endif
+
+# ifdef FEAT_GUI
+ if (pty_master_fd >= 0)
+ {
+ fromshell_fd = pty_master_fd;
+ toshell_fd = dup(pty_master_fd);
+ }
+ else
+# endif
+ {
+ close(fd_toshell[0]);
+ close(fd_fromshell[1]);
+ toshell_fd = fd_toshell[1];
+ fromshell_fd = fd_fromshell[0];
+ }
+
+ /*
+ * Write to the child if there are typed characters.
+ * Read from the child if there are characters available.
+ * Repeat the reading a few times if more characters are
+ * available. Need to check for typed keys now and then, but
+ * not too often (delays when no chars are available).
+ * This loop is quit if no characters can be read from the pty
+ * (WaitForChar detected special condition), or there are no
+ * characters available and the child has exited.
+ * Only check if the child has exited when there is no more
+ * output. The child may exit before all the output has
+ * been printed.
+ *
+ * Currently this busy loops!
+ * This can probably dead-lock when the write blocks!
+ */
+ p_more_save = p_more;
+ p_more = FALSE;
+ old_State = State;
+ State = EXTERNCMD; /* don't redraw at window resize */
+
+ if ((options & SHELL_WRITE) && toshell_fd >= 0)
+ {
+ /* Fork a process that will write the lines to the
+ * external program. */
+ if ((wpid = fork()) == -1)
+ {
+ msg_puts(_("\nCannot fork\n"));
+ }
+ else if (wpid == 0) /* child */
+ {
+ linenr_T lnum = curbuf->b_op_start.lnum;
+ int written = 0;
+ char_u *lp = ml_get(lnum);
+ size_t l;
+
+ close(fromshell_fd);
+ for (;;)
+ {
+ l = STRLEN(lp + written);
+ if (l == 0)
+ len = 0;
+ else if (lp[written] == NL)
+ /* NL -> NUL translation */
+ len = write(toshell_fd, "", (size_t)1);
+ else
+ {
+ char_u *s = vim_strchr(lp + written, NL);
+
+ len = write(toshell_fd, (char *)lp + written,
+ s == NULL ? l
+ : (size_t)(s - (lp + written)));
+ }
+ if (len == (int)l)
+ {
+ /* Finished a line, add a NL, unless this line
+ * should not have one. */
+ if (lnum != curbuf->b_op_end.lnum
+ || (!curbuf->b_p_bin
+ && curbuf->b_p_fixeol)
+ || (lnum != curbuf->b_no_eol_lnum
+ && (lnum !=
+ curbuf->b_ml.ml_line_count
+ || curbuf->b_p_eol)))
+ vim_ignored = write(toshell_fd, "\n",
+ (size_t)1);
+ ++lnum;
+ if (lnum > curbuf->b_op_end.lnum)
+ {
+ /* finished all the lines, close pipe */
+ close(toshell_fd);
+ toshell_fd = -1;
+ break;
+ }
+ lp = ml_get(lnum);
+ written = 0;
+ }
+ else if (len > 0)
+ written += len;
+ }
+ _exit(0);
+ }
+ else /* parent */
+ {
+ close(toshell_fd);
+ toshell_fd = -1;
+ }
+ }
+
+ if (options & SHELL_READ)
+ ga_init2(&ga, 1, BUFLEN);
+
+ noread_cnt = 0;
+# ifdef ELAPSED_FUNC
+ ELAPSED_INIT(start_tv);
+# endif
+ for (;;)
+ {
+ /*
+ * Check if keys have been typed, write them to the child
+ * if there are any.
+ * Don't do this if we are expanding wild cards (would eat
+ * typeahead).
+ * Don't do this when filtering and terminal is in cooked
+ * mode, the shell command will handle the I/O. Avoids
+ * that a typed password is echoed for ssh or gpg command.
+ * Don't get characters when the child has already
+ * finished (wait_pid == 0).
+ * Don't read characters unless we didn't get output for a
+ * while (noread_cnt > 4), avoids that ":r !ls" eats
+ * typeahead.
+ */
+ len = 0;
+ if (!(options & SHELL_EXPAND)
+ && ((options &
+ (SHELL_READ|SHELL_WRITE|SHELL_COOKED))
+ != (SHELL_READ|SHELL_WRITE|SHELL_COOKED)
+# ifdef FEAT_GUI
+ || gui.in_use
+# endif
+ )
+ && wait_pid == 0
+ && (ta_len > 0 || noread_cnt > 4))
+ {
+ if (ta_len == 0)
+ {
+ /* Get extra characters when we don't have any.
+ * Reset the counter and timer. */
+ noread_cnt = 0;
+# ifdef ELAPSED_FUNC
+ ELAPSED_INIT(start_tv);
+# endif
+ len = ui_inchar(ta_buf, BUFLEN, 10L, 0);
+ }
+ if (ta_len > 0 || len > 0)
+ {
+ /*
+ * For pipes:
+ * Check for CTRL-C: send interrupt signal to child.
+ * Check for CTRL-D: EOF, close pipe to child.
+ */
+ if (len == 1 && (pty_master_fd < 0 || cmd != NULL))
+ {
+ /*
+ * Send SIGINT to the child's group or all
+ * processes in our group.
+ */
+ may_send_sigint(ta_buf[ta_len], pid, wpid);
+
+ if (pty_master_fd < 0 && toshell_fd >= 0
+ && ta_buf[ta_len] == Ctrl_D)
+ {
+ close(toshell_fd);
+ toshell_fd = -1;
+ }
+ }
+
+ /* replace K_BS by <BS> and K_DEL by <DEL> */
+ for (i = ta_len; i < ta_len + len; ++i)
+ {
+ if (ta_buf[i] == CSI && len - i > 2)
+ {
+ c = TERMCAP2KEY(ta_buf[i + 1], ta_buf[i + 2]);
+ if (c == K_DEL || c == K_KDEL || c == K_BS)
+ {
+ mch_memmove(ta_buf + i + 1, ta_buf + i + 3,
+ (size_t)(len - i - 2));
+ if (c == K_DEL || c == K_KDEL)
+ ta_buf[i] = DEL;
+ else
+ ta_buf[i] = Ctrl_H;
+ len -= 2;
+ }
+ }
+ else if (ta_buf[i] == '\r')
+ ta_buf[i] = '\n';
+ if (has_mbyte)
+ i += (*mb_ptr2len_len)(ta_buf + i,
+ ta_len + len - i) - 1;
+ }
+
+ /*
+ * For pipes: echo the typed characters.
+ * For a pty this does not seem to work.
+ */
+ if (pty_master_fd < 0)
+ {
+ for (i = ta_len; i < ta_len + len; ++i)
+ {
+ if (ta_buf[i] == '\n' || ta_buf[i] == '\b')
+ msg_putchar(ta_buf[i]);
+ else if (has_mbyte)
+ {
+ int l = (*mb_ptr2len)(ta_buf + i);
+
+ msg_outtrans_len(ta_buf + i, l);
+ i += l - 1;
+ }
+ else
+ msg_outtrans_len(ta_buf + i, 1);
+ }
+ windgoto(msg_row, msg_col);
+ out_flush();
+ }
+
+ ta_len += len;
+
+ /*
+ * Write the characters to the child, unless EOF has
+ * been typed for pipes. Write one character at a
+ * time, to avoid losing too much typeahead.
+ * When writing buffer lines, drop the typed
+ * characters (only check for CTRL-C).
+ */
+ if (options & SHELL_WRITE)
+ ta_len = 0;
+ else if (toshell_fd >= 0)
+ {
+ len = write(toshell_fd, (char *)ta_buf, (size_t)1);
+ if (len > 0)
+ {
+ ta_len -= len;
+ mch_memmove(ta_buf, ta_buf + len, ta_len);
+ }
+ }
+ }
+ }
+
+ if (got_int)
+ {
+ /* CTRL-C sends a signal to the child, we ignore it
+ * ourselves */
+# ifdef HAVE_SETSID
+ kill(-pid, SIGINT);
+# else
+ kill(0, SIGINT);
+# endif
+ if (wpid > 0)
+ kill(wpid, SIGINT);
+ got_int = FALSE;
+ }
+
+ /*
+ * Check if the child has any characters to be printed.
+ * Read them and write them to our window. Repeat this as
+ * long as there is something to do, avoid the 10ms wait
+ * for mch_inchar(), or sending typeahead characters to
+ * the external process.
+ * TODO: This should handle escape sequences, compatible
+ * to some terminal (vt52?).
+ */
+ ++noread_cnt;
+ while (RealWaitForChar(fromshell_fd, 10L, NULL, NULL))
+ {
+ len = read_eintr(fromshell_fd, buffer
+ + buffer_off, (size_t)(BUFLEN - buffer_off)
+ );
+ if (len <= 0) /* end of file or error */
+ goto finished;
+
+ noread_cnt = 0;
+ if (options & SHELL_READ)
+ {
+ /* Do NUL -> NL translation, append NL separated
+ * lines to the current buffer. */
+ for (i = 0; i < len; ++i)
+ {
+ if (buffer[i] == NL)
+ append_ga_line(&ga);
+ else if (buffer[i] == NUL)
+ ga_append(&ga, NL);
+ else
+ ga_append(&ga, buffer[i]);
+ }
+ }
+ else if (has_mbyte)
+ {
+ int l;
+ char_u *p;
+
+ len += buffer_off;
+ buffer[len] = NUL;
+
+ /* Check if the last character in buffer[] is
+ * incomplete, keep these bytes for the next
+ * round. */
+ for (p = buffer; p < buffer + len; p += l)
+ {
+ l = MB_CPTR2LEN(p);
+ if (l == 0)
+ l = 1; /* NUL byte? */
+ else if (MB_BYTE2LEN(*p) != l)
+ break;
+ }
+ if (p == buffer) /* no complete character */
+ {
+ /* avoid getting stuck at an illegal byte */
+ if (len >= 12)
+ ++p;
+ else
+ {
+ buffer_off = len;
+ continue;
+ }
+ }
+ c = *p;
+ *p = NUL;
+ msg_puts((char *)buffer);
+ if (p < buffer + len)
+ {
+ *p = c;
+ buffer_off = (buffer + len) - p;
+ mch_memmove(buffer, p, buffer_off);
+ continue;
+ }
+ buffer_off = 0;
+ }
+ else
+ {
+ buffer[len] = NUL;
+ msg_puts((char *)buffer);
+ }
+
+ windgoto(msg_row, msg_col);
+ cursor_on();
+ out_flush();
+ if (got_int)
+ break;
+
+# ifdef ELAPSED_FUNC
+ if (wait_pid == 0)
+ {
+ long msec = ELAPSED_FUNC(start_tv);
+
+ /* Avoid that we keep looping here without
+ * checking for a CTRL-C for a long time. Don't
+ * break out too often to avoid losing typeahead. */
+ if (msec > 2000)
+ {
+ noread_cnt = 5;
+ break;
+ }
+ }
+# endif
+ }
+
+ /* If we already detected the child has finished, continue
+ * reading output for a short while. Some text may be
+ * buffered. */
+ if (wait_pid == pid)
+ {
+ if (noread_cnt < 5)
+ continue;
+ break;
+ }
+
+ /*
+ * Check if the child still exists, before checking for
+ * typed characters (otherwise we would lose typeahead).
+ */
+# ifdef __NeXT__
+ wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *)0);
+# else
+ wait_pid = waitpid(pid, &status, WNOHANG);
+# endif
+ if ((wait_pid == (pid_t)-1 && errno == ECHILD)
+ || (wait_pid == pid && WIFEXITED(status)))
+ {
+ /* Don't break the loop yet, try reading more
+ * characters from "fromshell_fd" first. When using
+ * pipes there might still be something to read and
+ * then we'll break the loop at the "break" above. */
+ wait_pid = pid;
+ }
+ else
+ wait_pid = 0;
+
+# if defined(FEAT_XCLIPBOARD) && defined(FEAT_X11)
+ /* Handle any X events, e.g. serving the clipboard. */
+ clip_update();
+# endif
+ }
+finished:
+ p_more = p_more_save;
+ if (options & SHELL_READ)
+ {
+ if (ga.ga_len > 0)
+ {
+ append_ga_line(&ga);
+ /* remember that the NL was missing */
+ curbuf->b_no_eol_lnum = curwin->w_cursor.lnum;
+ }
+ else
+ curbuf->b_no_eol_lnum = 0;
+ ga_clear(&ga);
+ }
+
+ /*
+ * Give all typeahead that wasn't used back to ui_inchar().
+ */
+ if (ta_len)
+ ui_inchar_undo(ta_buf, ta_len);
+ State = old_State;
+ if (toshell_fd >= 0)
+ close(toshell_fd);
+ close(fromshell_fd);
+ }
+# if defined(FEAT_XCLIPBOARD) && defined(FEAT_X11)
+ else
+ {
+ long delay_msec = 1;
+
+ /*
+ * Similar to the loop above, but only handle X events, no
+ * I/O.
+ */
+ for (;;)
+ {
+ if (got_int)
+ {
+ /* CTRL-C sends a signal to the child, we ignore it
+ * ourselves */
+# ifdef HAVE_SETSID
+ kill(-pid, SIGINT);
+# else
+ kill(0, SIGINT);
+# endif
+ got_int = FALSE;
+ }
+# ifdef __NeXT__
+ wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *)0);
+# else
+ wait_pid = waitpid(pid, &status, WNOHANG);
+# endif
+ if ((wait_pid == (pid_t)-1 && errno == ECHILD)
+ || (wait_pid == pid && WIFEXITED(status)))
+ {
+ wait_pid = pid;
+ break;
+ }
+
+ /* Handle any X events, e.g. serving the clipboard. */
+ clip_update();
+
+ /* Wait for 1 to 10 msec. 1 is faster but gives the child
+ * less time. */
+ mch_delay(delay_msec, TRUE);
+ if (++delay_msec > 10)
+ delay_msec = 10;
+ }
+ }
+# endif
+
+ /*
+ * Wait until our child has exited.
+ * Ignore wait() returning pids of other children and returning
+ * because of some signal like SIGWINCH.
+ * Don't wait if wait_pid was already set above, indicating the
+ * child already exited.
+ */
+ if (wait_pid != pid)
+ wait_pid = wait4pid(pid, &status);
+
+# ifdef FEAT_GUI
+ /* Close slave side of pty. Only do this after the child has
+ * exited, otherwise the child may hang when it tries to write on
+ * the pty. */
+ if (pty_master_fd >= 0)
+ close(pty_slave_fd);
+# endif
+
+ /* Make sure the child that writes to the external program is
+ * dead. */
+ if (wpid > 0)
+ {
+ kill(wpid, SIGKILL);
+ wait4pid(wpid, NULL);
+ }
+
+# ifdef FEAT_JOB_CHANNEL
+ --dont_check_job_ended;
+# endif
+
+ /*
+ * Set to raw mode right now, otherwise a CTRL-C after
+ * catch_signals() will kill Vim.
+ */
+ if (tmode == TMODE_RAW)
+ settmode(TMODE_RAW);
+ did_settmode = TRUE;
+ set_signals();
+
+ if (WIFEXITED(status))
+ {
+ /* LINTED avoid "bitwise operation on signed value" */
+ retval = WEXITSTATUS(status);
+ if (retval != 0 && !emsg_silent)
+ {
+ if (retval == EXEC_FAILED)
+ {
+ msg_puts(_("\nCannot execute shell "));
+ msg_outtrans(p_sh);
+ msg_putchar('\n');
+ }
+ else if (!(options & SHELL_SILENT))
+ {
+ msg_puts(_("\nshell returned "));
+ msg_outnum((long)retval);
+ msg_putchar('\n');
+ }
+ }
+ }
+ else
+ msg_puts(_("\nCommand terminated\n"));
+ }
+ }
+
+error:
+ if (!did_settmode)
+ if (tmode == TMODE_RAW)
+ settmode(TMODE_RAW); /* set to raw mode */
+# ifdef FEAT_TITLE
+ resettitle();
+# endif
+ vim_free(argv);
+ vim_free(tofree1);
+ vim_free(tofree2);
+
+ return retval;
+}
+#endif /* USE_SYSTEM */
+
+ int
+mch_call_shell(
+ char_u *cmd,
+ int options) /* SHELL_*, see vim.h */
+{
+#if defined(FEAT_GUI) && defined(FEAT_TERMINAL)
+ if (gui.in_use && vim_strchr(p_go, GO_TERMINAL) != NULL)
+ return mch_call_shell_terminal(cmd, options);
+#endif
+#ifdef USE_SYSTEM
+ return mch_call_shell_system(cmd, options);
+#else
+ return mch_call_shell_fork(cmd, options);
+#endif
+}
+
+#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
+ void
+mch_job_start(char **argv, job_T *job, jobopt_T *options, int is_terminal)
+{
+ pid_t pid;
+ int fd_in[2] = {-1, -1}; /* for stdin */
+ int fd_out[2] = {-1, -1}; /* for stdout */
+ int fd_err[2] = {-1, -1}; /* for stderr */
+ int pty_master_fd = -1;
+ int pty_slave_fd = -1;
+ channel_T *channel = NULL;
+ int use_null_for_in = options->jo_io[PART_IN] == JIO_NULL;
+ int use_null_for_out = options->jo_io[PART_OUT] == JIO_NULL;
+ int use_null_for_err = options->jo_io[PART_ERR] == JIO_NULL;
+ int use_file_for_in = options->jo_io[PART_IN] == JIO_FILE;
+ int use_file_for_out = options->jo_io[PART_OUT] == JIO_FILE;
+ int use_file_for_err = options->jo_io[PART_ERR] == JIO_FILE;
+ int use_buffer_for_in = options->jo_io[PART_IN] == JIO_BUFFER;
+ int use_out_for_err = options->jo_io[PART_ERR] == JIO_OUT;
+ SIGSET_DECL(curset)
+
+ if (use_out_for_err && use_null_for_out)
+ use_null_for_err = TRUE;
+
+ /* default is to fail */
+ job->jv_status = JOB_FAILED;
+
+ if (options->jo_pty
+ && (!(use_file_for_in || use_null_for_in)
+ || !(use_file_for_in || use_null_for_out)
+ || !(use_out_for_err || use_file_for_err || use_null_for_err)))
+ {
+ open_pty(&pty_master_fd, &pty_slave_fd, &job->jv_tty_out);
+ if (job->jv_tty_out != NULL)
+ job->jv_tty_in = vim_strsave(job->jv_tty_out);
+ }
+
+ /* TODO: without the channel feature connect the child to /dev/null? */
+ /* Open pipes for stdin, stdout, stderr. */
+ if (use_file_for_in)
+ {
+ char_u *fname = options->jo_io_name[PART_IN];
+
+ fd_in[0] = mch_open((char *)fname, O_RDONLY, 0);
+ if (fd_in[0] < 0)
+ {
+ semsg(_(e_notopen), fname);
+ goto failed;
+ }
+ }
+ else
+ /* When writing buffer lines to the input don't use the pty, so that
+ * the pipe can be closed when all lines were written. */
+ if (!use_null_for_in && (pty_master_fd < 0 || use_buffer_for_in)
+ && pipe(fd_in) < 0)
+ goto failed;
+
+ if (use_file_for_out)
+ {
+ char_u *fname = options->jo_io_name[PART_OUT];
+
+ fd_out[1] = mch_open((char *)fname, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ if (fd_out[1] < 0)
+ {
+ semsg(_(e_notopen), fname);
+ goto failed;
+ }
+ }
+ else if (!use_null_for_out && pty_master_fd < 0 && pipe(fd_out) < 0)
+ goto failed;
+
+ if (use_file_for_err)
+ {
+ char_u *fname = options->jo_io_name[PART_ERR];
+
+ fd_err[1] = mch_open((char *)fname, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+ if (fd_err[1] < 0)
+ {
+ semsg(_(e_notopen), fname);
+ goto failed;
+ }
+ }
+ else if (!use_out_for_err && !use_null_for_err
+ && pty_master_fd < 0 && pipe(fd_err) < 0)
+ goto failed;
+
+ if (!use_null_for_in || !use_null_for_out || !use_null_for_err)
+ {
+ if (options->jo_set & JO_CHANNEL)
+ {
+ channel = options->jo_channel;
+ if (channel != NULL)
+ ++channel->ch_refcount;
+ }
+ else
+ channel = add_channel();
+ if (channel == NULL)
+ goto failed;
+ if (job->jv_tty_out != NULL)
+ ch_log(channel, "using pty %s on fd %d",
+ job->jv_tty_out, pty_master_fd);
+ }
+
+ BLOCK_SIGNALS(&curset);
+ pid = fork(); /* maybe we should use vfork() */
+ if (pid == -1)
+ {
+ /* failed to fork */
+ UNBLOCK_SIGNALS(&curset);
+ goto failed;
+ }
+ if (pid == 0)
+ {
+ int null_fd = -1;
+ int stderr_works = TRUE;
+
+ /* child */
+ reset_signals(); /* handle signals normally */
+ UNBLOCK_SIGNALS(&curset);
+
+# ifdef FEAT_JOB_CHANNEL
+ if (ch_log_active())
+ /* close the log file in the child */
+ ch_logfile((char_u *)"", (char_u *)"");
+# endif
+
+# ifdef HAVE_SETSID
+ /* Create our own process group, so that the child and all its
+ * children can be kill()ed. Don't do this when using pipes,
+ * because stdin is not a tty, we would lose /dev/tty. */
+ (void)setsid();
+# endif
+
+# ifdef FEAT_TERMINAL
+ if (options->jo_term_rows > 0)
+ {
+ char *term = (char *)T_NAME;
+
+#ifdef FEAT_GUI
+ if (term_is_gui(T_NAME))
+ /* In the GUI 'term' is not what we want, use $TERM. */
+ term = getenv("TERM");
+#endif
+ /* Use 'term' or $TERM if it starts with "xterm", otherwise fall
+ * back to "xterm". */
+ if (term == NULL || *term == NUL || STRNCMP(term, "xterm", 5) != 0)
+ term = "xterm";
+ set_child_environment(
+ (long)options->jo_term_rows,
+ (long)options->jo_term_cols,
+ term,
+ is_terminal);
+ }
+ else
+# endif
+ set_default_child_environment(is_terminal);
+
+ if (options->jo_env != NULL)
+ {
+ dict_T *dict = options->jo_env;
+ hashitem_T *hi;
+ int todo = (int)dict->dv_hashtab.ht_used;
+
+ for (hi = dict->dv_hashtab.ht_array; todo > 0; ++hi)
+ if (!HASHITEM_EMPTY(hi))
+ {
+ typval_T *item = &dict_lookup(hi)->di_tv;
+
+ vim_setenv((char_u*)hi->hi_key, tv_get_string(item));
+ --todo;
+ }
+ }
+
+ if (use_null_for_in || use_null_for_out || use_null_for_err)
+ {
+ null_fd = open("/dev/null", O_RDWR | O_EXTRA, 0);
+ if (null_fd < 0)
+ {
+ perror("opening /dev/null failed");
+ _exit(OPEN_NULL_FAILED);
+ }
+ }
+
+ if (pty_slave_fd >= 0)
+ {
+ /* push stream discipline modules */
+ setup_slavepty(pty_slave_fd);
+# ifdef TIOCSCTTY
+ /* Try to become controlling tty (probably doesn't work,
+ * unless run by root) */
+ ioctl(pty_slave_fd, TIOCSCTTY, (char *)NULL);
+# endif
+ }
+
+ /* set up stdin for the child */
+ close(0);
+ if (use_null_for_in && null_fd >= 0)
+ vim_ignored = dup(null_fd);
+ else if (fd_in[0] < 0)
+ vim_ignored = dup(pty_slave_fd);
+ else
+ vim_ignored = dup(fd_in[0]);
+
+ /* set up stderr for the child */
+ close(2);
+ if (use_null_for_err && null_fd >= 0)
+ {
+ vim_ignored = dup(null_fd);
+ stderr_works = FALSE;
+ }
+ else if (use_out_for_err)
+ vim_ignored = dup(fd_out[1]);
+ else if (fd_err[1] < 0)
+ vim_ignored = dup(pty_slave_fd);
+ else
+ vim_ignored = dup(fd_err[1]);
+
+ /* set up stdout for the child */
+ close(1);
+ if (use_null_for_out && null_fd >= 0)
+ vim_ignored = dup(null_fd);
+ else if (fd_out[1] < 0)
+ vim_ignored = dup(pty_slave_fd);
+ else
+ vim_ignored = dup(fd_out[1]);
+
+ if (fd_in[0] >= 0)
+ close(fd_in[0]);
+ if (fd_in[1] >= 0)
+ close(fd_in[1]);
+ if (fd_out[0] >= 0)
+ close(fd_out[0]);
+ if (fd_out[1] >= 0)
+ close(fd_out[1]);
+ if (fd_err[0] >= 0)
+ close(fd_err[0]);
+ if (fd_err[1] >= 0)
+ close(fd_err[1]);
+ if (pty_master_fd >= 0)
+ {
+ close(pty_master_fd); /* not used in the child */
+ close(pty_slave_fd); /* was duped above */
+ }
+
+ if (null_fd >= 0)
+ close(null_fd);
+
+ if (options->jo_cwd != NULL && mch_chdir((char *)options->jo_cwd) != 0)
+ _exit(EXEC_FAILED);
+
+ /* See above for type of argv. */
+ execvp(argv[0], argv);
+
+ if (stderr_works)
+ perror("executing job failed");
+# ifdef EXITFREE
+ /* calling free_all_mem() here causes problems. Ignore valgrind
+ * reporting possibly leaked memory. */
+# endif
+ _exit(EXEC_FAILED); /* exec failed, return failure code */
+ }
+
+ /* parent */
+ UNBLOCK_SIGNALS(&curset);
+
+ job->jv_pid = pid;
+ job->jv_status = JOB_STARTED;
+ job->jv_channel = channel; /* ch_refcount was set above */
+
+ if (pty_master_fd >= 0)
+ close(pty_slave_fd); /* not used in the parent */
+ /* close child stdin, stdout and stderr */
+ if (fd_in[0] >= 0)
+ close(fd_in[0]);
+ if (fd_out[1] >= 0)
+ close(fd_out[1]);
+ if (fd_err[1] >= 0)
+ close(fd_err[1]);
+ if (channel != NULL)
+ {
+ int in_fd = use_file_for_in || use_null_for_in
+ ? INVALID_FD : fd_in[1] < 0 ? pty_master_fd : fd_in[1];
+ int out_fd = use_file_for_out || use_null_for_out
+ ? INVALID_FD : fd_out[0] < 0 ? pty_master_fd : fd_out[0];
+ /* When using pty_master_fd only set it for stdout, do not duplicate it
+ * for stderr, it only needs to be read once. */
+ int err_fd = use_out_for_err || use_file_for_err || use_null_for_err
+ ? INVALID_FD
+ : fd_err[0] >= 0
+ ? fd_err[0]
+ : (out_fd == pty_master_fd
+ ? INVALID_FD
+ : pty_master_fd);
+
+ channel_set_pipes(channel, in_fd, out_fd, err_fd);
+ channel_set_job(channel, job, options);
+ }
+ else
+ {
+ if (fd_in[1] >= 0)
+ close(fd_in[1]);
+ if (fd_out[0] >= 0)
+ close(fd_out[0]);
+ if (fd_err[0] >= 0)
+ close(fd_err[0]);
+ if (pty_master_fd >= 0)
+ close(pty_master_fd);
+ }
+
+ /* success! */
+ return;
+
+failed:
+ channel_unref(channel);
+ if (fd_in[0] >= 0)
+ close(fd_in[0]);
+ if (fd_in[1] >= 0)
+ close(fd_in[1]);
+ if (fd_out[0] >= 0)
+ close(fd_out[0]);
+ if (fd_out[1] >= 0)
+ close(fd_out[1]);
+ if (fd_err[0] >= 0)
+ close(fd_err[0]);
+ if (fd_err[1] >= 0)
+ close(fd_err[1]);
+ if (pty_master_fd >= 0)
+ close(pty_master_fd);
+ if (pty_slave_fd >= 0)
+ close(pty_slave_fd);
+}
+
+ static char_u *
+get_signal_name(int sig)
+{
+ int i;
+ char_u numbuf[NUMBUFLEN];
+
+ if (sig == SIGKILL)
+ return vim_strsave((char_u *)"kill");
+
+ for (i = 0; signal_info[i].sig != -1; i++)
+ if (sig == signal_info[i].sig)
+ return strlow_save((char_u *)signal_info[i].name);
+
+ vim_snprintf((char *)numbuf, NUMBUFLEN, "%d", sig);
+ return vim_strsave(numbuf);
+}
+
+ char *
+mch_job_status(job_T *job)
+{
+# ifdef HAVE_UNION_WAIT
+ union wait status;
+# else
+ int status = -1;
+# endif
+ pid_t wait_pid = 0;
+
+# ifdef __NeXT__
+ wait_pid = wait4(job->jv_pid, &status, WNOHANG, (struct rusage *)0);
+# else
+ wait_pid = waitpid(job->jv_pid, &status, WNOHANG);
+# endif
+ if (wait_pid == -1)
+ {
+ /* process must have exited */
+ if (job->jv_status < JOB_ENDED)
+ ch_log(job->jv_channel, "Job no longer exists: %s",
+ strerror(errno));
+ goto return_dead;
+ }
+ if (wait_pid == 0)
+ return "run";
+ if (WIFEXITED(status))
+ {
+ /* LINTED avoid "bitwise operation on signed value" */
+ job->jv_exitval = WEXITSTATUS(status);
+ if (job->jv_status < JOB_ENDED)
+ ch_log(job->jv_channel, "Job exited with %d", job->jv_exitval);
+ goto return_dead;
+ }
+ if (WIFSIGNALED(status))
+ {
+ job->jv_exitval = -1;
+ job->jv_termsig = get_signal_name(WTERMSIG(status));
+ if (job->jv_status < JOB_ENDED && job->jv_termsig != NULL)
+ ch_log(job->jv_channel, "Job terminated by signal \"%s\"",
+ job->jv_termsig);
+ goto return_dead;
+ }
+ return "run";
+
+return_dead:
+ if (job->jv_status < JOB_ENDED)
+ job->jv_status = JOB_ENDED;
+ return "dead";
+}
+
+ job_T *
+mch_detect_ended_job(job_T *job_list)
+{
+# ifdef HAVE_UNION_WAIT
+ union wait status;
+# else
+ int status = -1;
+# endif
+ pid_t wait_pid = 0;
+ job_T *job;
+
+# ifndef USE_SYSTEM
+ /* Do not do this when waiting for a shell command to finish, we would get
+ * the exit value here (and discard it), the exit value obtained there
+ * would then be wrong. */
+ if (dont_check_job_ended > 0)
+ return NULL;
+# endif
+
+# ifdef __NeXT__
+ wait_pid = wait4(-1, &status, WNOHANG, (struct rusage *)0);
+# else
+ wait_pid = waitpid(-1, &status, WNOHANG);
+# endif
+ if (wait_pid <= 0)
+ /* no process ended */
+ return NULL;
+ for (job = job_list; job != NULL; job = job->jv_next)
+ {
+ if (job->jv_pid == wait_pid)
+ {
+ if (WIFEXITED(status))
+ /* LINTED avoid "bitwise operation on signed value" */
+ job->jv_exitval = WEXITSTATUS(status);
+ else if (WIFSIGNALED(status))
+ {
+ job->jv_exitval = -1;
+ job->jv_termsig = get_signal_name(WTERMSIG(status));
+ }
+ if (job->jv_status < JOB_ENDED)
+ {
+ ch_log(job->jv_channel, "Job ended");
+ job->jv_status = JOB_ENDED;
+ }
+ return job;
+ }
+ }
+ return NULL;
+}
+
+/*
+ * Send a (deadly) signal to "job".
+ * Return FAIL if "how" is not a valid name.
+ */
+ int
+mch_signal_job(job_T *job, char_u *how)
+{
+ int sig = -1;
+
+ if (*how == NUL || STRCMP(how, "term") == 0)
+ sig = SIGTERM;
+ else if (STRCMP(how, "hup") == 0)
+ sig = SIGHUP;
+ else if (STRCMP(how, "quit") == 0)
+ sig = SIGQUIT;
+ else if (STRCMP(how, "int") == 0)
+ sig = SIGINT;
+ else if (STRCMP(how, "kill") == 0)
+ sig = SIGKILL;
+#ifdef SIGWINCH
+ else if (STRCMP(how, "winch") == 0)
+ sig = SIGWINCH;
+#endif
+ else if (isdigit(*how))
+ sig = atoi((char *)how);
+ else
+ return FAIL;
+
+ // Never kill ourselves!
+ if (job->jv_pid != 0)
+ {
+ // TODO: have an option to only kill the process, not the group?
+ kill(-job->jv_pid, sig);
+ kill(job->jv_pid, sig);
+ }
+
+ return OK;
+}
+
+/*
+ * Clear the data related to "job".
+ */
+ void
+mch_clear_job(job_T *job)
+{
+ /* call waitpid because child process may become zombie */
+# ifdef __NeXT__
+ (void)wait4(job->jv_pid, NULL, WNOHANG, (struct rusage *)0);
+# else
+ (void)waitpid(job->jv_pid, NULL, WNOHANG);
+# endif
+}
+#endif
+
+#if defined(FEAT_TERMINAL) || defined(PROTO)
+ int
+mch_create_pty_channel(job_T *job, jobopt_T *options)
+{
+ int pty_master_fd = -1;
+ int pty_slave_fd = -1;
+ channel_T *channel;
+
+ open_pty(&pty_master_fd, &pty_slave_fd, &job->jv_tty_out);
+ if (job->jv_tty_out != NULL)
+ job->jv_tty_in = vim_strsave(job->jv_tty_out);
+ close(pty_slave_fd);
+
+ channel = add_channel();
+ if (channel == NULL)
+ {
+ close(pty_master_fd);
+ return FAIL;
+ }
+ if (job->jv_tty_out != NULL)
+ ch_log(channel, "using pty %s on fd %d",
+ job->jv_tty_out, pty_master_fd);
+ job->jv_channel = channel; /* ch_refcount was set by add_channel() */
+ channel->ch_keep_open = TRUE;
+
+ /* Only set the pty_master_fd for stdout, do not duplicate it for stderr,
+ * it only needs to be read once. */
+ channel_set_pipes(channel, pty_master_fd, pty_master_fd, INVALID_FD);
+ channel_set_job(channel, job, options);
+ return OK;
+}
+#endif
+
+/*
+ * Check for CTRL-C typed by reading all available characters.
+ * In cooked mode we should get SIGINT, no need to check.
+ */
+ void
+mch_breakcheck(int force)
+{
+ if ((curr_tmode == TMODE_RAW || force)
+ && RealWaitForChar(read_cmd_fd, 0L, NULL, NULL))
+ fill_input_buf(FALSE);
+}
+
+/*
+ * Wait "msec" msec until a character is available from the mouse, keyboard,
+ * from inbuf[].
+ * "msec" == -1 will block forever.
+ * Invokes timer callbacks when needed.
+ * When "ignore_input" is TRUE even check for pending input when input is
+ * already available.
+ * "interrupted" (if not NULL) is set to TRUE when no character is available
+ * but something else needs to be done.
+ * Returns TRUE when a character is available.
+ * When a GUI is being used, this will never get called -- webb
+ */
+ static int
+WaitForChar(long msec, int *interrupted, int ignore_input)
+{
+#ifdef FEAT_TIMERS
+ return ui_wait_for_chars_or_timer(
+ msec, WaitForCharOrMouse, interrupted, ignore_input) == OK;
+#else
+ return WaitForCharOrMouse(msec, interrupted, ignore_input);
+#endif
+}
+
+/*
+ * Wait "msec" msec until a character is available from the mouse or keyboard
+ * or from inbuf[].
+ * "msec" == -1 will block forever.
+ * for "ignore_input" see WaitForCharOr().
+ * "interrupted" (if not NULL) is set to TRUE when no character is available
+ * but something else needs to be done.
+ * When a GUI is being used, this will never get called -- webb
+ */
+ static int
+WaitForCharOrMouse(long msec, int *interrupted, int ignore_input)
+{
+#ifdef FEAT_MOUSE_GPM
+ int gpm_process_wanted;
+#endif
+#ifdef FEAT_XCLIPBOARD
+ int rest;
+#endif
+ int avail;
+
+ if (!ignore_input && input_available()) /* something in inbuf[] */
+ return 1;
+
+#if defined(FEAT_MOUSE_DEC)
+ /* May need to query the mouse position. */
+ if (WantQueryMouse)
+ {
+ WantQueryMouse = FALSE;
+ mch_write((char_u *)IF_EB("\033[1'|", ESC_STR "[1'|"), 5);
+ }
+#endif
+
+ /*
+ * For FEAT_MOUSE_GPM and FEAT_XCLIPBOARD we loop here to process mouse
+ * events. This is a bit complicated, because they might both be defined.
+ */
+#if defined(FEAT_MOUSE_GPM) || defined(FEAT_XCLIPBOARD)
+# ifdef FEAT_XCLIPBOARD
+ rest = 0;
+ if (do_xterm_trace())
+ rest = msec;
+# endif
+ do
+ {
+# ifdef FEAT_XCLIPBOARD
+ if (rest != 0)
+ {
+ msec = XT_TRACE_DELAY;
+ if (rest >= 0 && rest < XT_TRACE_DELAY)
+ msec = rest;
+ if (rest >= 0)
+ rest -= msec;
+ }
+# endif
+# ifdef FEAT_MOUSE_GPM
+ gpm_process_wanted = 0;
+ avail = RealWaitForChar(read_cmd_fd, msec,
+ &gpm_process_wanted, interrupted);
+# else
+ avail = RealWaitForChar(read_cmd_fd, msec, NULL, interrupted);
+# endif
+ if (!avail)
+ {
+ if (!ignore_input && input_available())
+ return 1;
+# ifdef FEAT_XCLIPBOARD
+ if (rest == 0 || !do_xterm_trace())
+# endif
+ break;
+ }
+ }
+ while (FALSE
+# ifdef FEAT_MOUSE_GPM
+ || (gpm_process_wanted && mch_gpm_process() == 0)
+# endif
+# ifdef FEAT_XCLIPBOARD
+ || (!avail && rest != 0)
+# endif
+ )
+ ;
+
+#else
+ avail = RealWaitForChar(read_cmd_fd, msec, NULL, interrupted);
+#endif
+ return avail;
+}
+
+#ifndef VMS
+/*
+ * Wait "msec" msec until a character is available from file descriptor "fd".
+ * "msec" == 0 will check for characters once.
+ * "msec" == -1 will block until a character is available.
+ * When a GUI is being used, this will not be used for input -- webb
+ * Or when a Linux GPM mouse event is waiting.
+ * Or when a clientserver message is on the queue.
+ * "interrupted" (if not NULL) is set to TRUE when no character is available
+ * but something else needs to be done.
+ */
+#if defined(__BEOS__)
+ int
+#else
+ static int
+#endif
+RealWaitForChar(int fd, long msec, int *check_for_gpm UNUSED, int *interrupted)
+{
+ int ret;
+ int result;
+#if defined(FEAT_XCLIPBOARD) || defined(USE_XSMP) || defined(FEAT_MZSCHEME)
+ static int busy = FALSE;
+
+ /* May retry getting characters after an event was handled. */
+# define MAY_LOOP
+
+# ifdef ELAPSED_FUNC
+ /* Remember at what time we started, so that we know how much longer we
+ * should wait after being interrupted. */
+ long start_msec = msec;
+ elapsed_T start_tv;
+
+ if (msec > 0)
+ ELAPSED_INIT(start_tv);
+# endif
+
+ /* Handle being called recursively. This may happen for the session
+ * manager stuff, it may save the file, which does a breakcheck. */
+ if (busy)
+ return 0;
+#endif
+
+#ifdef MAY_LOOP
+ for (;;)
+#endif
+ {
+#ifdef MAY_LOOP
+ int finished = TRUE; /* default is to 'loop' just once */
+# ifdef FEAT_MZSCHEME
+ int mzquantum_used = FALSE;
+# endif
+#endif
+#ifndef HAVE_SELECT
+ /* each channel may use in, out and err */
+ struct pollfd fds[6 + 3 * MAX_OPEN_CHANNELS];
+ int nfd;
+# ifdef FEAT_XCLIPBOARD
+ int xterm_idx = -1;
+# endif
+# ifdef FEAT_MOUSE_GPM
+ int gpm_idx = -1;
+# endif
+# ifdef USE_XSMP
+ int xsmp_idx = -1;
+# endif
+ int towait = (int)msec;
+
+# ifdef FEAT_MZSCHEME
+ mzvim_check_threads();
+ if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
+ {
+ towait = (int)p_mzq; /* don't wait longer than 'mzquantum' */
+ mzquantum_used = TRUE;
+ }
+# endif
+ fds[0].fd = fd;
+ fds[0].events = POLLIN;
+ nfd = 1;
+
+# ifdef FEAT_XCLIPBOARD
+ may_restore_clipboard();
+ if (xterm_Shell != (Widget)0)
+ {
+ xterm_idx = nfd;
+ fds[nfd].fd = ConnectionNumber(xterm_dpy);
+ fds[nfd].events = POLLIN;
+ nfd++;
+ }
+# endif
+# ifdef FEAT_MOUSE_GPM
+ if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
+ {
+ gpm_idx = nfd;
+ fds[nfd].fd = gpm_fd;
+ fds[nfd].events = POLLIN;
+ nfd++;
+ }
+# endif
+# ifdef USE_XSMP
+ if (xsmp_icefd != -1)
+ {
+ xsmp_idx = nfd;
+ fds[nfd].fd = xsmp_icefd;
+ fds[nfd].events = POLLIN;
+ nfd++;
+ }
+# endif
+#ifdef FEAT_JOB_CHANNEL
+ nfd = channel_poll_setup(nfd, &fds, &towait);
+#endif
+ if (interrupted != NULL)
+ *interrupted = FALSE;
+
+ ret = poll(fds, nfd, towait);
+
+ result = ret > 0 && (fds[0].revents & POLLIN);
+ if (result == 0 && interrupted != NULL && ret > 0)
+ *interrupted = TRUE;
+
+# ifdef FEAT_MZSCHEME
+ if (ret == 0 && mzquantum_used)
+ /* MzThreads scheduling is required and timeout occurred */
+ finished = FALSE;
+# endif
+
+# ifdef FEAT_XCLIPBOARD
+ if (xterm_Shell != (Widget)0 && (fds[xterm_idx].revents & POLLIN))
+ {
+ xterm_update(); /* Maybe we should hand out clipboard */
+ if (--ret == 0 && !input_available())
+ /* Try again */
+ finished = FALSE;
+ }
+# endif
+# ifdef FEAT_MOUSE_GPM
+ if (gpm_idx >= 0 && (fds[gpm_idx].revents & POLLIN))
+ {
+ *check_for_gpm = 1;
+ }
+# endif
+# ifdef USE_XSMP
+ if (xsmp_idx >= 0 && (fds[xsmp_idx].revents & (POLLIN | POLLHUP)))
+ {
+ if (fds[xsmp_idx].revents & POLLIN)
+ {
+ busy = TRUE;
+ xsmp_handle_requests();
+ busy = FALSE;
+ }
+ else if (fds[xsmp_idx].revents & POLLHUP)
+ {
+ if (p_verbose > 0)
+ verb_msg(_("XSMP lost ICE connection"));
+ xsmp_close();
+ }
+ if (--ret == 0)
+ finished = FALSE; /* Try again */
+ }
+# endif
+#ifdef FEAT_JOB_CHANNEL
+ /* also call when ret == 0, we may be polling a keep-open channel */
+ if (ret >= 0)
+ ret = channel_poll_check(ret, &fds);
+#endif
+
+#else /* HAVE_SELECT */
+
+ struct timeval tv;
+ struct timeval *tvp;
+ // These are static because they can take 8 Kbyte each and cause the
+ // signal stack to run out with -O3.
+ static fd_set rfds, wfds, efds;
+ int maxfd;
+ long towait = msec;
+
+# ifdef FEAT_MZSCHEME
+ mzvim_check_threads();
+ if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
+ {
+ towait = p_mzq; /* don't wait longer than 'mzquantum' */
+ mzquantum_used = TRUE;
+ }
+# endif
+
+ if (towait >= 0)
+ {
+ tv.tv_sec = towait / 1000;
+ tv.tv_usec = (towait % 1000) * (1000000/1000);
+ tvp = &tv;
+ }
+ else
+ tvp = NULL;
+
+ /*
+ * Select on ready for reading and exceptional condition (end of file).
+ */
+select_eintr:
+ FD_ZERO(&rfds);
+ FD_ZERO(&wfds);
+ FD_ZERO(&efds);
+ FD_SET(fd, &rfds);
+# if !defined(__QNX__) && !defined(__CYGWIN32__)
+ /* For QNX select() always returns 1 if this is set. Why? */
+ FD_SET(fd, &efds);
+# endif
+ maxfd = fd;
+
+# ifdef FEAT_XCLIPBOARD
+ may_restore_clipboard();
+ if (xterm_Shell != (Widget)0)
+ {
+ FD_SET(ConnectionNumber(xterm_dpy), &rfds);
+ if (maxfd < ConnectionNumber(xterm_dpy))
+ maxfd = ConnectionNumber(xterm_dpy);
+
+ /* An event may have already been read but not handled. In
+ * particulary, XFlush may cause this. */
+ xterm_update();
+ }
+# endif
+# ifdef FEAT_MOUSE_GPM
+ if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
+ {
+ FD_SET(gpm_fd, &rfds);
+ FD_SET(gpm_fd, &efds);
+ if (maxfd < gpm_fd)
+ maxfd = gpm_fd;
+ }
+# endif
+# ifdef USE_XSMP
+ if (xsmp_icefd != -1)
+ {
+ FD_SET(xsmp_icefd, &rfds);
+ FD_SET(xsmp_icefd, &efds);
+ if (maxfd < xsmp_icefd)
+ maxfd = xsmp_icefd;
+ }
+# endif
+# ifdef FEAT_JOB_CHANNEL
+ maxfd = channel_select_setup(maxfd, &rfds, &wfds, &tv, &tvp);
+# endif
+ if (interrupted != NULL)
+ *interrupted = FALSE;
+
+ ret = select(maxfd + 1, SELECT_TYPE_ARG234 &rfds,
+ SELECT_TYPE_ARG234 &wfds, SELECT_TYPE_ARG234 &efds, tvp);
+ result = ret > 0 && FD_ISSET(fd, &rfds);
+ if (result)
+ --ret;
+ else if (interrupted != NULL && ret > 0)
+ *interrupted = TRUE;
+
+# ifdef EINTR
+ if (ret == -1 && errno == EINTR)
+ {
+ /* Check whether window has been resized, EINTR may be caused by
+ * SIGWINCH. */
+ if (do_resize)
+ handle_resize();
+
+ /* Interrupted by a signal, need to try again. We ignore msec
+ * here, because we do want to check even after a timeout if
+ * characters are available. Needed for reading output of an
+ * external command after the process has finished. */
+ goto select_eintr;
+ }
+# endif
+# ifdef __TANDEM
+ if (ret == -1 && errno == ENOTSUP)
+ {
+ FD_ZERO(&rfds);
+ FD_ZERO(&efds);
+ ret = 0;
+ }
+# endif
+# ifdef FEAT_MZSCHEME
+ if (ret == 0 && mzquantum_used)
+ /* loop if MzThreads must be scheduled and timeout occurred */
+ finished = FALSE;
+# endif
+
+# ifdef FEAT_XCLIPBOARD
+ if (ret > 0 && xterm_Shell != (Widget)0
+ && FD_ISSET(ConnectionNumber(xterm_dpy), &rfds))
+ {
+ xterm_update(); /* Maybe we should hand out clipboard */
+ /* continue looping when we only got the X event and the input
+ * buffer is empty */
+ if (--ret == 0 && !input_available())
+ {
+ /* Try again */
+ finished = FALSE;
+ }
+ }
+# endif
+# ifdef FEAT_MOUSE_GPM
+ if (ret > 0 && gpm_flag && check_for_gpm != NULL && gpm_fd >= 0)
+ {
+ if (FD_ISSET(gpm_fd, &efds))
+ gpm_close();
+ else if (FD_ISSET(gpm_fd, &rfds))
+ *check_for_gpm = 1;
+ }
+# endif
+# ifdef USE_XSMP
+ if (ret > 0 && xsmp_icefd != -1)
+ {
+ if (FD_ISSET(xsmp_icefd, &efds))
+ {
+ if (p_verbose > 0)
+ verb_msg(_("XSMP lost ICE connection"));
+ xsmp_close();
+ if (--ret == 0)
+ finished = FALSE; /* keep going if event was only one */
+ }
+ else if (FD_ISSET(xsmp_icefd, &rfds))
+ {
+ busy = TRUE;
+ xsmp_handle_requests();
+ busy = FALSE;
+ if (--ret == 0)
+ finished = FALSE; /* keep going if event was only one */
+ }
+ }
+# endif
+#ifdef FEAT_JOB_CHANNEL
+ /* also call when ret == 0, we may be polling a keep-open channel */
+ if (ret >= 0)
+ ret = channel_select_check(ret, &rfds, &wfds);
+#endif
+
+#endif /* HAVE_SELECT */
+
+#ifdef MAY_LOOP
+ if (finished || msec == 0)
+ break;
+
+# ifdef FEAT_CLIENTSERVER
+ if (server_waiting())
+ break;
+# endif
+
+ /* We're going to loop around again, find out for how long */
+ if (msec > 0)
+ {
+# ifdef ELAPSED_FUNC
+ /* Compute remaining wait time. */
+ msec = start_msec - ELAPSED_FUNC(start_tv);
+# else
+ /* Guess we got interrupted halfway. */
+ msec = msec / 2;
+# endif
+ if (msec <= 0)
+ break; /* waited long enough */
+ }
+#endif
+ }
+
+ return result;
+}
+
+#ifndef NO_EXPANDPATH
+/*
+ * Expand a path into all matching files and/or directories. Handles "*",
+ * "?", "[a-z]", "**", etc.
+ * "path" has backslashes before chars that are not to be expanded.
+ * Returns the number of matches found.
+ */
+ int
+mch_expandpath(
+ garray_T *gap,
+ char_u *path,
+ int flags) /* EW_* flags */
+{
+ return unix_expandpath(gap, path, 0, flags, FALSE);
+}
+#endif
+
+/*
+ * mch_expand_wildcards() - this code does wild-card pattern matching using
+ * the shell
+ *
+ * return OK for success, FAIL for error (you may lose some memory) and put
+ * an error message in *file.
+ *
+ * num_pat is number of input patterns
+ * pat is array of pointers to input patterns
+ * num_file is pointer to number of matched file names
+ * file is pointer to array of pointers to matched file names
+ */
+
+#ifndef SEEK_SET
+# define SEEK_SET 0
+#endif
+#ifndef SEEK_END
+# define SEEK_END 2
+#endif
+
+#define SHELL_SPECIAL (char_u *)"\t \"&'$;<>()\\|"
+
+ int
+mch_expand_wildcards(
+ int num_pat,
+ char_u **pat,
+ int *num_file,
+ char_u ***file,
+ int flags) /* EW_* flags */
+{
+ int i;
+ size_t len;
+ long llen;
+ char_u *p;
+ int dir;
+
+ /*
+ * This is the non-OS/2 implementation (really Unix).
+ */
+ int j;
+ char_u *tempname;
+ char_u *command;
+ FILE *fd;
+ char_u *buffer;
+#define STYLE_ECHO 0 /* use "echo", the default */
+#define STYLE_GLOB 1 /* use "glob", for csh */
+#define STYLE_VIMGLOB 2 /* use "vimglob", for Posix sh */
+#define STYLE_PRINT 3 /* use "print -N", for zsh */
+#define STYLE_BT 4 /* `cmd` expansion, execute the pattern
+ * directly */
+ int shell_style = STYLE_ECHO;
+ int check_spaces;
+ static int did_find_nul = FALSE;
+ int ampersent = FALSE;
+ /* vimglob() function to define for Posix shell */
+ static char *sh_vimglob_func = "vimglob() { while [ $# -ge 1 ]; do echo \"$1\"; shift; done }; vimglob >";
+
+ *num_file = 0; /* default: no files found */
+ *file = NULL;
+
+ /*
+ * If there are no wildcards, just copy the names to allocated memory.
+ * Saves a lot of time, because we don't have to start a new shell.
+ */
+ if (!have_wildcard(num_pat, pat))
+ return save_patterns(num_pat, pat, num_file, file);
+
+# ifdef HAVE_SANDBOX
+ /* Don't allow any shell command in the sandbox. */
+ if (sandbox != 0 && check_secure())
+ return FAIL;
+# endif
+
+ /*
+ * Don't allow the use of backticks in secure and restricted mode.
+ */
+ if (secure || restricted)
+ for (i = 0; i < num_pat; ++i)
+ if (vim_strchr(pat[i], '`') != NULL
+ && (check_restricted() || check_secure()))
+ return FAIL;
+
+ /*
+ * get a name for the temp file
+ */
+ if ((tempname = vim_tempname('o', FALSE)) == NULL)
+ {
+ emsg(_(e_notmp));
+ return FAIL;
+ }
+
+ /*
+ * Let the shell expand the patterns and write the result into the temp
+ * file.
+ * STYLE_BT: NL separated
+ * If expanding `cmd` execute it directly.
+ * STYLE_GLOB: NUL separated
+ * If we use *csh, "glob" will work better than "echo".
+ * STYLE_PRINT: NL or NUL separated
+ * If we use *zsh, "print -N" will work better than "glob".
+ * STYLE_VIMGLOB: NL separated
+ * If we use *sh*, we define "vimglob()".
+ * STYLE_ECHO: space separated.
+ * A shell we don't know, stay safe and use "echo".
+ */
+ if (num_pat == 1 && *pat[0] == '`'
+ && (len = STRLEN(pat[0])) > 2
+ && *(pat[0] + len - 1) == '`')
+ shell_style = STYLE_BT;
+ else if ((len = STRLEN(p_sh)) >= 3)
+ {
+ if (STRCMP(p_sh + len - 3, "csh") == 0)
+ shell_style = STYLE_GLOB;
+ else if (STRCMP(p_sh + len - 3, "zsh") == 0)
+ shell_style = STYLE_PRINT;
+ }
+ if (shell_style == STYLE_ECHO && strstr((char *)gettail(p_sh),
+ "sh") != NULL)
+ shell_style = STYLE_VIMGLOB;
+
+ /* Compute the length of the command. We need 2 extra bytes: for the
+ * optional '&' and for the NUL.
+ * Worst case: "unset nonomatch; print -N >" plus two is 29 */
+ len = STRLEN(tempname) + 29;
+ if (shell_style == STYLE_VIMGLOB)
+ len += STRLEN(sh_vimglob_func);
+
+ for (i = 0; i < num_pat; ++i)
+ {
+ /* Count the length of the patterns in the same way as they are put in
+ * "command" below. */
+#ifdef USE_SYSTEM
+ len += STRLEN(pat[i]) + 3; /* add space and two quotes */
+#else
+ ++len; /* add space */
+ for (j = 0; pat[i][j] != NUL; ++j)
+ {
+ if (vim_strchr(SHELL_SPECIAL, pat[i][j]) != NULL)
+ ++len; /* may add a backslash */
+ ++len;
+ }
+#endif
+ }
+ command = alloc(len);
+ if (command == NULL)
+ {
+ /* out of memory */
+ vim_free(tempname);
+ return FAIL;
+ }
+
+ /*
+ * Build the shell command:
+ * - Set $nonomatch depending on EW_NOTFOUND (hopefully the shell
+ * recognizes this).
+ * - Add the shell command to print the expanded names.
+ * - Add the temp file name.
+ * - Add the file name patterns.
+ */
+ if (shell_style == STYLE_BT)
+ {
+ /* change `command; command& ` to (command; command ) */
+ STRCPY(command, "(");
+ STRCAT(command, pat[0] + 1); /* exclude first backtick */
+ p = command + STRLEN(command) - 1;
+ *p-- = ')'; /* remove last backtick */
+ while (p > command && VIM_ISWHITE(*p))
+ --p;
+ if (*p == '&') /* remove trailing '&' */
+ {
+ ampersent = TRUE;
+ *p = ' ';
+ }
+ STRCAT(command, ">");
+ }
+ else
+ {
+ if (flags & EW_NOTFOUND)
+ STRCPY(command, "set nonomatch; ");
+ else
+ STRCPY(command, "unset nonomatch; ");
+ if (shell_style == STYLE_GLOB)
+ STRCAT(command, "glob >");
+ else if (shell_style == STYLE_PRINT)
+ STRCAT(command, "print -N >");
+ else if (shell_style == STYLE_VIMGLOB)
+ STRCAT(command, sh_vimglob_func);
+ else
+ STRCAT(command, "echo >");
+ }
+
+ STRCAT(command, tempname);
+
+ if (shell_style != STYLE_BT)
+ for (i = 0; i < num_pat; ++i)
+ {
+ /* When using system() always add extra quotes, because the shell
+ * is started twice. Otherwise put a backslash before special
+ * characters, except inside ``. */
+#ifdef USE_SYSTEM
+ STRCAT(command, " \"");
+ STRCAT(command, pat[i]);
+ STRCAT(command, "\"");
+#else
+ int intick = FALSE;
+
+ p = command + STRLEN(command);
+ *p++ = ' ';
+ for (j = 0; pat[i][j] != NUL; ++j)
+ {
+ if (pat[i][j] == '`')
+ intick = !intick;
+ else if (pat[i][j] == '\\' && pat[i][j + 1] != NUL)
+ {
+ /* Remove a backslash, take char literally. But keep
+ * backslash inside backticks, before a special character
+ * and before a backtick. */
+ if (intick
+ || vim_strchr(SHELL_SPECIAL, pat[i][j + 1]) != NULL
+ || pat[i][j + 1] == '`')
+ *p++ = '\\';
+ ++j;
+ }
+ else if (!intick
+ && ((flags & EW_KEEPDOLLAR) == 0 || pat[i][j] != '$')
+ && vim_strchr(SHELL_SPECIAL, pat[i][j]) != NULL)
+ /* Put a backslash before a special character, but not
+ * when inside ``. And not for $var when EW_KEEPDOLLAR is
+ * set. */
+ *p++ = '\\';
+
+ /* Copy one character. */
+ *p++ = pat[i][j];
+ }
+ *p = NUL;
+#endif
+ }
+ if (flags & EW_SILENT)
+ show_shell_mess = FALSE;
+ if (ampersent)
+ STRCAT(command, "&"); /* put the '&' after the redirection */
+
+ /*
+ * Using zsh -G: If a pattern has no matches, it is just deleted from
+ * the argument list, otherwise zsh gives an error message and doesn't
+ * expand any other pattern.
+ */
+ if (shell_style == STYLE_PRINT)
+ extra_shell_arg = (char_u *)"-G"; /* Use zsh NULL_GLOB option */
+
+ /*
+ * If we use -f then shell variables set in .cshrc won't get expanded.
+ * vi can do it, so we will too, but it is only necessary if there is a "$"
+ * in one of the patterns, otherwise we can still use the fast option.
+ */
+ else if (shell_style == STYLE_GLOB && !have_dollars(num_pat, pat))
+ extra_shell_arg = (char_u *)"-f"; /* Use csh fast option */
+
+ /*
+ * execute the shell command
+ */
+ i = call_shell(command, SHELL_EXPAND | SHELL_SILENT);
+
+ /* When running in the background, give it some time to create the temp
+ * file, but don't wait for it to finish. */
+ if (ampersent)
+ mch_delay(10L, TRUE);
+
+ extra_shell_arg = NULL; /* cleanup */
+ show_shell_mess = TRUE;
+ vim_free(command);
+
+ if (i != 0) /* mch_call_shell() failed */
+ {
+ mch_remove(tempname);
+ vim_free(tempname);
+ /*
+ * With interactive completion, the error message is not printed.
+ * However with USE_SYSTEM, I don't know how to turn off error messages
+ * from the shell, so screen may still get messed up -- webb.
+ */
+#ifndef USE_SYSTEM
+ if (!(flags & EW_SILENT))
+#endif
+ {
+ redraw_later_clear(); /* probably messed up screen */
+ msg_putchar('\n'); /* clear bottom line quickly */
+ cmdline_row = Rows - 1; /* continue on last line */
+#ifdef USE_SYSTEM
+ if (!(flags & EW_SILENT))
+#endif
+ {
+ msg(_(e_wildexpand));
+ msg_start(); /* don't overwrite this message */
+ }
+ }
+ /* If a `cmd` expansion failed, don't list `cmd` as a match, even when
+ * EW_NOTFOUND is given */
+ if (shell_style == STYLE_BT)
+ return FAIL;
+ goto notfound;
+ }
+
+ /*
+ * read the names from the file into memory
+ */
+ fd = fopen((char *)tempname, READBIN);
+ if (fd == NULL)
+ {
+ /* Something went wrong, perhaps a file name with a special char. */
+ if (!(flags & EW_SILENT))
+ {
+ msg(_(e_wildexpand));
+ msg_start(); /* don't overwrite this message */
+ }
+ vim_free(tempname);
+ goto notfound;
+ }
+ fseek(fd, 0L, SEEK_END);
+ llen = ftell(fd); /* get size of temp file */
+ fseek(fd, 0L, SEEK_SET);
+ if (llen < 0)
+ /* just in case ftell() would fail */
+ buffer = NULL;
+ else
+ buffer = alloc(llen + 1);
+ if (buffer == NULL)
+ {
+ /* out of memory */
+ mch_remove(tempname);
+ vim_free(tempname);
+ fclose(fd);
+ return FAIL;
+ }
+ len = llen;
+ i = fread((char *)buffer, 1, len, fd);
+ fclose(fd);
+ mch_remove(tempname);
+ if (i != (int)len)
+ {
+ /* unexpected read error */
+ semsg(_(e_notread), tempname);
+ vim_free(tempname);
+ vim_free(buffer);
+ return FAIL;
+ }
+ vim_free(tempname);
+
+# if defined(__CYGWIN__) || defined(__CYGWIN32__)
+ /* Translate <CR><NL> into <NL>. Caution, buffer may contain NUL. */
+ p = buffer;
+ for (i = 0; i < (int)len; ++i)
+ if (!(buffer[i] == CAR && buffer[i + 1] == NL))
+ *p++ = buffer[i];
+ len = p - buffer;
+# endif
+
+
+ /* file names are separated with Space */
+ if (shell_style == STYLE_ECHO)
+ {
+ buffer[len] = '\n'; /* make sure the buffer ends in NL */
+ p = buffer;
+ for (i = 0; *p != '\n'; ++i) /* count number of entries */
+ {
+ while (*p != ' ' && *p != '\n')
+ ++p;
+ p = skipwhite(p); /* skip to next entry */
+ }
+ }
+ /* file names are separated with NL */
+ else if (shell_style == STYLE_BT || shell_style == STYLE_VIMGLOB)
+ {
+ buffer[len] = NUL; /* make sure the buffer ends in NUL */
+ p = buffer;
+ for (i = 0; *p != NUL; ++i) /* count number of entries */
+ {
+ while (*p != '\n' && *p != NUL)
+ ++p;
+ if (*p != NUL)
+ ++p;
+ p = skipwhite(p); /* skip leading white space */
+ }
+ }
+ /* file names are separated with NUL */
+ else
+ {
+ /*
+ * Some versions of zsh use spaces instead of NULs to separate
+ * results. Only do this when there is no NUL before the end of the
+ * buffer, otherwise we would never be able to use file names with
+ * embedded spaces when zsh does use NULs.
+ * When we found a NUL once, we know zsh is OK, set did_find_nul and
+ * don't check for spaces again.
+ */
+ check_spaces = FALSE;
+ if (shell_style == STYLE_PRINT && !did_find_nul)
+ {
+ /* If there is a NUL, set did_find_nul, else set check_spaces */
+ buffer[len] = NUL;
+ if (len && (int)STRLEN(buffer) < (int)len)
+ did_find_nul = TRUE;
+ else
+ check_spaces = TRUE;
+ }
+
+ /*
+ * Make sure the buffer ends with a NUL. For STYLE_PRINT there
+ * already is one, for STYLE_GLOB it needs to be added.
+ */
+ if (len && buffer[len - 1] == NUL)
+ --len;
+ else
+ buffer[len] = NUL;
+ i = 0;
+ for (p = buffer; p < buffer + len; ++p)
+ if (*p == NUL || (*p == ' ' && check_spaces)) /* count entry */
+ {
+ ++i;
+ *p = NUL;
+ }
+ if (len)
+ ++i; /* count last entry */
+ }
+ if (i == 0)
+ {
+ /*
+ * Can happen when using /bin/sh and typing ":e $NO_SUCH_VAR^I".
+ * /bin/sh will happily expand it to nothing rather than returning an
+ * error; and hey, it's good to check anyway -- webb.
+ */
+ vim_free(buffer);
+ goto notfound;
+ }
+ *num_file = i;
+ *file = (char_u **)alloc(sizeof(char_u *) * i);
+ if (*file == NULL)
+ {
+ /* out of memory */
+ vim_free(buffer);
+ return FAIL;
+ }
+
+ /*
+ * Isolate the individual file names.
+ */
+ p = buffer;
+ for (i = 0; i < *num_file; ++i)
+ {
+ (*file)[i] = p;
+ /* Space or NL separates */
+ if (shell_style == STYLE_ECHO || shell_style == STYLE_BT
+ || shell_style == STYLE_VIMGLOB)
+ {
+ while (!(shell_style == STYLE_ECHO && *p == ' ')
+ && *p != '\n' && *p != NUL)
+ ++p;
+ if (p == buffer + len) /* last entry */
+ *p = NUL;
+ else
+ {
+ *p++ = NUL;
+ p = skipwhite(p); /* skip to next entry */
+ }
+ }
+ else /* NUL separates */
+ {
+ while (*p && p < buffer + len) /* skip entry */
+ ++p;
+ ++p; /* skip NUL */
+ }
+ }
+
+ /*
+ * Move the file names to allocated memory.
+ */
+ for (j = 0, i = 0; i < *num_file; ++i)
+ {
+ /* Require the files to exist. Helps when using /bin/sh */
+ if (!(flags & EW_NOTFOUND) && mch_getperm((*file)[i]) < 0)
+ continue;
+
+ /* check if this entry should be included */
+ dir = (mch_isdir((*file)[i]));
+ if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
+ continue;
+
+ /* Skip files that are not executable if we check for that. */
+ if (!dir && (flags & EW_EXEC)
+ && !mch_can_exe((*file)[i], NULL, !(flags & EW_SHELLCMD)))
+ continue;
+
+ p = alloc((unsigned)(STRLEN((*file)[i]) + 1 + dir));
+ if (p)
+ {
+ STRCPY(p, (*file)[i]);
+ if (dir)
+ add_pathsep(p); /* add '/' to a directory name */
+ (*file)[j++] = p;
+ }
+ }
+ vim_free(buffer);
+ *num_file = j;
+
+ if (*num_file == 0) /* rejected all entries */
+ {
+ VIM_CLEAR(*file);
+ goto notfound;
+ }
+
+ return OK;
+
+notfound:
+ if (flags & EW_NOTFOUND)
+ return save_patterns(num_pat, pat, num_file, file);
+ return FAIL;
+}
+
+#endif /* VMS */
+
+ static int
+save_patterns(
+ int num_pat,
+ char_u **pat,
+ int *num_file,
+ char_u ***file)
+{
+ int i;
+ char_u *s;
+
+ *file = (char_u **)alloc(num_pat * sizeof(char_u *));
+ if (*file == NULL)
+ return FAIL;
+ for (i = 0; i < num_pat; i++)
+ {
+ s = vim_strsave(pat[i]);
+ if (s != NULL)
+ /* Be compatible with expand_filename(): halve the number of
+ * backslashes. */
+ backslash_halve(s);
+ (*file)[i] = s;
+ }
+ *num_file = num_pat;
+ return OK;
+}
+
+/*
+ * Return TRUE if the string "p" contains a wildcard that mch_expandpath() can
+ * expand.
+ */
+ int
+mch_has_exp_wildcard(char_u *p)
+{
+ for ( ; *p; MB_PTR_ADV(p))
+ {
+ if (*p == '\\' && p[1] != NUL)
+ ++p;
+ else
+ if (vim_strchr((char_u *)
+#ifdef VMS
+ "*?%"
+#else
+ "*?[{'"
+#endif
+ , *p) != NULL)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * Return TRUE if the string "p" contains a wildcard.
+ * Don't recognize '~' at the end as a wildcard.
+ */
+ int
+mch_has_wildcard(char_u *p)
+{
+ for ( ; *p; MB_PTR_ADV(p))
+ {
+ if (*p == '\\' && p[1] != NUL)
+ ++p;
+ else
+ if (vim_strchr((char_u *)
+#ifdef VMS
+ "*?%$"
+#else
+ "*?[{`'$"
+#endif
+ , *p) != NULL
+ || (*p == '~' && p[1] != NUL))
+ return TRUE;
+ }
+ return FALSE;
+}
+
+ static int
+have_wildcard(int num, char_u **file)
+{
+ int i;
+
+ for (i = 0; i < num; i++)
+ if (mch_has_wildcard(file[i]))
+ return 1;
+ return 0;
+}
+
+ static int
+have_dollars(int num, char_u **file)
+{
+ int i;
+
+ for (i = 0; i < num; i++)
+ if (vim_strchr(file[i], '$') != NULL)
+ return TRUE;
+ return FALSE;
+}
+
+#if !defined(HAVE_RENAME) || defined(PROTO)
+/*
+ * Scaled-down version of rename(), which is missing in Xenix.
+ * This version can only move regular files and will fail if the
+ * destination exists.
+ */
+ int
+mch_rename(const char *src, const char *dest)
+{
+ struct stat st;
+
+ if (stat(dest, &st) >= 0) /* fail if destination exists */
+ return -1;
+ if (link(src, dest) != 0) /* link file to new name */
+ return -1;
+ if (mch_remove(src) == 0) /* delete link to old name */
+ return 0;
+ return -1;
+}
+#endif /* !HAVE_RENAME */
+
+#ifdef FEAT_MOUSE_GPM
+/*
+ * Initializes connection with gpm (if it isn't already opened)
+ * Return 1 if succeeded (or connection already opened), 0 if failed
+ */
+ static int
+gpm_open(void)
+{
+ static Gpm_Connect gpm_connect; /* Must it be kept till closing ? */
+
+ if (!gpm_flag)
+ {
+ gpm_connect.eventMask = (GPM_UP | GPM_DRAG | GPM_DOWN);
+ gpm_connect.defaultMask = ~GPM_HARD;
+ /* Default handling for mouse move*/
+ gpm_connect.minMod = 0; /* Handle any modifier keys */
+ gpm_connect.maxMod = 0xffff;
+ if (Gpm_Open(&gpm_connect, 0) > 0)
+ {
+ /* gpm library tries to handling TSTP causes
+ * problems. Anyways, we close connection to Gpm whenever
+ * we are going to suspend or starting an external process
+ * so we shouldn't have problem with this
+ */
+# ifdef SIGTSTP
+ signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
+# endif
+ return 1; /* succeed */
+ }
+ if (gpm_fd == -2)
+ Gpm_Close(); /* We don't want to talk to xterm via gpm */
+ return 0;
+ }
+ return 1; /* already open */
+}
+
+/*
+ * Closes connection to gpm
+ */
+ static void
+gpm_close(void)
+{
+ if (gpm_flag && gpm_fd >= 0) /* if Open */
+ Gpm_Close();
+}
+
+/* Reads gpm event and adds special keys to input buf. Returns length of
+ * generated key sequence.
+ * This function is styled after gui_send_mouse_event().
+ */
+ static int
+mch_gpm_process(void)
+{
+ int button;
+ static Gpm_Event gpm_event;
+ char_u string[6];
+ int_u vim_modifiers;
+ int row,col;
+ unsigned char buttons_mask;
+ unsigned char gpm_modifiers;
+ static unsigned char old_buttons = 0;
+
+ Gpm_GetEvent(&gpm_event);
+
+#ifdef FEAT_GUI
+ /* Don't put events in the input queue now. */
+ if (hold_gui_events)
+ return 0;
+#endif
+
+ row = gpm_event.y - 1;
+ col = gpm_event.x - 1;
+
+ string[0] = ESC; /* Our termcode */
+ string[1] = 'M';
+ string[2] = 'G';
+ switch (GPM_BARE_EVENTS(gpm_event.type))
+ {
+ case GPM_DRAG:
+ string[3] = MOUSE_DRAG;
+ break;
+ case GPM_DOWN:
+ buttons_mask = gpm_event.buttons & ~old_buttons;
+ old_buttons = gpm_event.buttons;
+ switch (buttons_mask)
+ {
+ case GPM_B_LEFT:
+ button = MOUSE_LEFT;
+ break;
+ case GPM_B_MIDDLE:
+ button = MOUSE_MIDDLE;
+ break;
+ case GPM_B_RIGHT:
+ button = MOUSE_RIGHT;
+ break;
+ default:
+ return 0;
+ /*Don't know what to do. Can more than one button be
+ * reported in one event? */
+ }
+ string[3] = (char_u)(button | 0x20);
+ SET_NUM_MOUSE_CLICKS(string[3], gpm_event.clicks + 1);
+ break;
+ case GPM_UP:
+ string[3] = MOUSE_RELEASE;
+ old_buttons &= ~gpm_event.buttons;
+ break;
+ default:
+ return 0;
+ }
+ /*This code is based on gui_x11_mouse_cb in gui_x11.c */
+ gpm_modifiers = gpm_event.modifiers;
+ vim_modifiers = 0x0;
+ /* I ignore capslock stats. Aren't we all just hate capslock mixing with
+ * Vim commands ? Besides, gpm_event.modifiers is unsigned char, and
+ * K_CAPSSHIFT is defined 8, so it probably isn't even reported
+ */
+ if (gpm_modifiers & ((1 << KG_SHIFT) | (1 << KG_SHIFTR) | (1 << KG_SHIFTL)))
+ vim_modifiers |= MOUSE_SHIFT;
+
+ if (gpm_modifiers & ((1 << KG_CTRL) | (1 << KG_CTRLR) | (1 << KG_CTRLL)))
+ vim_modifiers |= MOUSE_CTRL;
+ if (gpm_modifiers & ((1 << KG_ALT) | (1 << KG_ALTGR)))
+ vim_modifiers |= MOUSE_ALT;
+ string[3] |= vim_modifiers;
+ string[4] = (char_u)(col + ' ' + 1);
+ string[5] = (char_u)(row + ' ' + 1);
+ add_to_input_buf(string, 6);
+ return 6;
+}
+#endif /* FEAT_MOUSE_GPM */
+
+#ifdef FEAT_SYSMOUSE
+/*
+ * Initialize connection with sysmouse.
+ * Let virtual console inform us with SIGUSR2 for pending sysmouse
+ * output, any sysmouse output than will be processed via sig_sysmouse().
+ * Return OK if succeeded, FAIL if failed.
+ */
+ static int
+sysmouse_open(void)
+{
+ struct mouse_info mouse;
+
+ mouse.operation = MOUSE_MODE;
+ mouse.u.mode.mode = 0;
+ mouse.u.mode.signal = SIGUSR2;
+ if (ioctl(1, CONS_MOUSECTL, &mouse) != -1)
+ {
+ signal(SIGUSR2, (RETSIGTYPE (*)())sig_sysmouse);
+ mouse.operation = MOUSE_SHOW;
+ ioctl(1, CONS_MOUSECTL, &mouse);
+ return OK;
+ }
+ return FAIL;
+}
+
+/*
+ * Stop processing SIGUSR2 signals, and also make sure that
+ * virtual console do not send us any sysmouse related signal.
+ */
+ static void
+sysmouse_close(void)
+{
+ struct mouse_info mouse;
+
+ signal(SIGUSR2, restricted ? SIG_IGN : SIG_DFL);
+ mouse.operation = MOUSE_MODE;
+ mouse.u.mode.mode = 0;
+ mouse.u.mode.signal = 0;
+ ioctl(1, CONS_MOUSECTL, &mouse);
+}
+
+/*
+ * Gets info from sysmouse and adds special keys to input buf.
+ */
+ static RETSIGTYPE
+sig_sysmouse SIGDEFARG(sigarg)
+{
+ struct mouse_info mouse;
+ struct video_info video;
+ char_u string[6];
+ int row, col;
+ int button;
+ int buttons;
+ static int oldbuttons = 0;
+
+#ifdef FEAT_GUI
+ /* Don't put events in the input queue now. */
+ if (hold_gui_events)
+ return;
+#endif
+
+ mouse.operation = MOUSE_GETINFO;
+ if (ioctl(1, FBIO_GETMODE, &video.vi_mode) != -1
+ && ioctl(1, FBIO_MODEINFO, &video) != -1
+ && ioctl(1, CONS_MOUSECTL, &mouse) != -1
+ && video.vi_cheight > 0 && video.vi_cwidth > 0)
+ {
+ row = mouse.u.data.y / video.vi_cheight;
+ col = mouse.u.data.x / video.vi_cwidth;
+ buttons = mouse.u.data.buttons;
+ string[0] = ESC; /* Our termcode */
+ string[1] = 'M';
+ string[2] = 'S';
+ if (oldbuttons == buttons && buttons != 0)
+ {
+ button = MOUSE_DRAG;
+ }
+ else
+ {
+ switch (buttons)
+ {
+ case 0:
+ button = MOUSE_RELEASE;
+ break;
+ case 1:
+ button = MOUSE_LEFT;
+ break;
+ case 2:
+ button = MOUSE_MIDDLE;
+ break;
+ case 4:
+ button = MOUSE_RIGHT;
+ break;
+ default:
+ return;
+ }
+ oldbuttons = buttons;
+ }
+ string[3] = (char_u)(button);
+ string[4] = (char_u)(col + ' ' + 1);
+ string[5] = (char_u)(row + ' ' + 1);
+ add_to_input_buf(string, 6);
+ }
+ return;
+}
+#endif /* FEAT_SYSMOUSE */
+
+#if defined(FEAT_LIBCALL) || defined(PROTO)
+typedef char_u * (*STRPROCSTR)(char_u *);
+typedef char_u * (*INTPROCSTR)(int);
+typedef int (*STRPROCINT)(char_u *);
+typedef int (*INTPROCINT)(int);
+
+/*
+ * Call a DLL routine which takes either a string or int param
+ * and returns an allocated string.
+ */
+ int
+mch_libcall(
+ char_u *libname,
+ char_u *funcname,
+ char_u *argstring, /* NULL when using a argint */
+ int argint,
+ char_u **string_result,/* NULL when using number_result */
+ int *number_result)
+{
+# if defined(USE_DLOPEN)
+ void *hinstLib;
+ char *dlerr = NULL;
+# else
+ shl_t hinstLib;
+# endif
+ STRPROCSTR ProcAdd;
+ INTPROCSTR ProcAddI;
+ char_u *retval_str = NULL;
+ int retval_int = 0;
+ int success = FALSE;
+
+ /*
+ * Get a handle to the DLL module.
+ */
+# if defined(USE_DLOPEN)
+ /* First clear any error, it's not cleared by the dlopen() call. */
+ (void)dlerror();
+
+ hinstLib = dlopen((char *)libname, RTLD_LAZY
+# ifdef RTLD_LOCAL
+ | RTLD_LOCAL
+# endif
+ );
+ if (hinstLib == NULL)
+ {
+ /* "dlerr" must be used before dlclose() */
+ dlerr = (char *)dlerror();
+ if (dlerr != NULL)
+ semsg(_("dlerror = \"%s\""), dlerr);
+ }
+# else
+ hinstLib = shl_load((const char*)libname, BIND_IMMEDIATE|BIND_VERBOSE, 0L);
+# endif
+
+ /* If the handle is valid, try to get the function address. */
+ if (hinstLib != NULL)
+ {
+# ifdef USING_SETJMP
+ /*
+ * Catch a crash when calling the library function. For example when
+ * using a number where a string pointer is expected.
+ */
+ mch_startjmp();
+ if (SETJMP(lc_jump_env) != 0)
+ {
+ success = FALSE;
+# if defined(USE_DLOPEN)
+ dlerr = NULL;
+# endif
+ mch_didjmp();
+ }
+ else
+# endif
+ {
+ retval_str = NULL;
+ retval_int = 0;
+
+ if (argstring != NULL)
+ {
+# if defined(USE_DLOPEN)
+ *(void **)(&ProcAdd) = dlsym(hinstLib, (const char *)funcname);
+ dlerr = (char *)dlerror();
+# else
+ if (shl_findsym(&hinstLib, (const char *)funcname,
+ TYPE_PROCEDURE, (void *)&ProcAdd) < 0)
+ ProcAdd = NULL;
+# endif
+ if ((success = (ProcAdd != NULL
+# if defined(USE_DLOPEN)
+ && dlerr == NULL
+# endif
+ )))
+ {
+ if (string_result == NULL)
+ retval_int = ((STRPROCINT)ProcAdd)(argstring);
+ else
+ retval_str = (ProcAdd)(argstring);
+ }
+ }
+ else
+ {
+# if defined(USE_DLOPEN)
+ *(void **)(&ProcAddI) = dlsym(hinstLib, (const char *)funcname);
+ dlerr = (char *)dlerror();
+# else
+ if (shl_findsym(&hinstLib, (const char *)funcname,
+ TYPE_PROCEDURE, (void *)&ProcAddI) < 0)
+ ProcAddI = NULL;
+# endif
+ if ((success = (ProcAddI != NULL
+# if defined(USE_DLOPEN)
+ && dlerr == NULL
+# endif
+ )))
+ {
+ if (string_result == NULL)
+ retval_int = ((INTPROCINT)ProcAddI)(argint);
+ else
+ retval_str = (ProcAddI)(argint);
+ }
+ }
+
+ /* Save the string before we free the library. */
+ /* Assume that a "1" or "-1" result is an illegal pointer. */
+ if (string_result == NULL)
+ *number_result = retval_int;
+ else if (retval_str != NULL
+ && retval_str != (char_u *)1
+ && retval_str != (char_u *)-1)
+ *string_result = vim_strsave(retval_str);
+ }
+
+# ifdef USING_SETJMP
+ mch_endjmp();
+# ifdef SIGHASARG
+ if (lc_signal != 0)
+ {
+ int i;
+
+ /* try to find the name of this signal */
+ for (i = 0; signal_info[i].sig != -1; i++)
+ if (lc_signal == signal_info[i].sig)
+ break;
+ semsg("E368: got SIG%s in libcall()", signal_info[i].name);
+ }
+# endif
+# endif
+
+# if defined(USE_DLOPEN)
+ /* "dlerr" must be used before dlclose() */
+ if (dlerr != NULL)
+ semsg(_("dlerror = \"%s\""), dlerr);
+
+ /* Free the DLL module. */
+ (void)dlclose(hinstLib);
+# else
+ (void)shl_unload(hinstLib);
+# endif
+ }
+
+ if (!success)
+ {
+ semsg(_(e_libcall), funcname);
+ return FAIL;
+ }
+
+ return OK;
+}
+#endif
+
+#if (defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) || defined(PROTO)
+static int xterm_trace = -1; /* default: disabled */
+static int xterm_button;
+
+/*
+ * Setup a dummy window for X selections in a terminal.
+ */
+ void
+setup_term_clip(void)
+{
+ int z = 0;
+ char *strp = "";
+ Widget AppShell;
+
+ if (!x_connect_to_server())
+ return;
+
+ open_app_context();
+ if (app_context != NULL && xterm_Shell == (Widget)0)
+ {
+ int (*oldhandler)();
+# if defined(USING_SETJMP)
+ int (*oldIOhandler)();
+# endif
+# ifdef ELAPSED_FUNC
+ elapsed_T start_tv;
+
+ if (p_verbose > 0)
+ ELAPSED_INIT(start_tv);
+# endif
+
+ /* Ignore X errors while opening the display */
+ oldhandler = XSetErrorHandler(x_error_check);
+
+# if defined(USING_SETJMP)
+ /* Ignore X IO errors while opening the display */
+ oldIOhandler = XSetIOErrorHandler(x_IOerror_check);
+ mch_startjmp();
+ if (SETJMP(lc_jump_env) != 0)
+ {
+ mch_didjmp();
+ xterm_dpy = NULL;
+ }
+ else
+# endif
+ {
+ xterm_dpy = XtOpenDisplay(app_context, xterm_display,
+ "vim_xterm", "Vim_xterm", NULL, 0, &z, &strp);
+ if (xterm_dpy != NULL)
+ xterm_dpy_retry_count = 0;
+# if defined(USING_SETJMP)
+ mch_endjmp();
+# endif
+ }
+
+# if defined(USING_SETJMP)
+ /* Now handle X IO errors normally. */
+ (void)XSetIOErrorHandler(oldIOhandler);
+# endif
+ /* Now handle X errors normally. */
+ (void)XSetErrorHandler(oldhandler);
+
+ if (xterm_dpy == NULL)
+ {
+ if (p_verbose > 0)
+ verb_msg(_("Opening the X display failed"));
+ return;
+ }
+
+ /* Catch terminating error of the X server connection. */
+ (void)XSetIOErrorHandler(x_IOerror_handler);
+
+# ifdef ELAPSED_FUNC
+ if (p_verbose > 0)
+ {
+ verbose_enter();
+ xopen_message(ELAPSED_FUNC(start_tv));
+ verbose_leave();
+ }
+# endif
+
+ /* Create a Shell to make converters work. */
+ AppShell = XtVaAppCreateShell("vim_xterm", "Vim_xterm",
+ applicationShellWidgetClass, xterm_dpy,
+ NULL);
+ if (AppShell == (Widget)0)
+ return;
+ xterm_Shell = XtVaCreatePopupShell("VIM",
+ topLevelShellWidgetClass, AppShell,
+ XtNmappedWhenManaged, 0,
+ XtNwidth, 1,
+ XtNheight, 1,
+ NULL);
+ if (xterm_Shell == (Widget)0)
+ return;
+
+ x11_setup_atoms(xterm_dpy);
+ x11_setup_selection(xterm_Shell);
+ if (x11_display == NULL)
+ x11_display = xterm_dpy;
+
+ XtRealizeWidget(xterm_Shell);
+ XSync(xterm_dpy, False);
+ xterm_update();
+ }
+ if (xterm_Shell != (Widget)0)
+ {
+ clip_init(TRUE);
+ if (x11_window == 0 && (strp = getenv("WINDOWID")) != NULL)
+ x11_window = (Window)atol(strp);
+ /* Check if $WINDOWID is valid. */
+ if (test_x11_window(xterm_dpy) == FAIL)
+ x11_window = 0;
+ if (x11_window != 0)
+ xterm_trace = 0;
+ }
+}
+
+ void
+start_xterm_trace(int button)
+{
+ if (x11_window == 0 || xterm_trace < 0 || xterm_Shell == (Widget)0)
+ return;
+ xterm_trace = 1;
+ xterm_button = button;
+ do_xterm_trace();
+}
+
+
+ void
+stop_xterm_trace(void)
+{
+ if (xterm_trace < 0)
+ return;
+ xterm_trace = 0;
+}
+
+/*
+ * Query the xterm pointer and generate mouse termcodes if necessary
+ * return TRUE if dragging is active, else FALSE
+ */
+ static int
+do_xterm_trace(void)
+{
+ Window root, child;
+ int root_x, root_y;
+ int win_x, win_y;
+ int row, col;
+ int_u mask_return;
+ char_u buf[50];
+ char_u *strp;
+ long got_hints;
+ static char_u *mouse_code;
+ static char_u mouse_name[2] = {KS_MOUSE, KE_FILLER};
+ static int prev_row = 0, prev_col = 0;
+ static XSizeHints xterm_hints;
+
+ if (xterm_trace <= 0)
+ return FALSE;
+
+ if (xterm_trace == 1)
+ {
+ /* Get the hints just before tracking starts. The font size might
+ * have changed recently. */
+ if (!XGetWMNormalHints(xterm_dpy, x11_window, &xterm_hints, &got_hints)
+ || !(got_hints & PResizeInc)
+ || xterm_hints.width_inc <= 1
+ || xterm_hints.height_inc <= 1)
+ {
+ xterm_trace = -1; /* Not enough data -- disable tracing */
+ return FALSE;
+ }
+
+ /* Rely on the same mouse code for the duration of this */
+ mouse_code = find_termcode(mouse_name);
+ prev_row = mouse_row;
+ prev_col = mouse_col;
+ xterm_trace = 2;
+
+ /* Find the offset of the chars, there might be a scrollbar on the
+ * left of the window and/or a menu on the top (eterm etc.) */
+ XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
+ &win_x, &win_y, &mask_return);
+ xterm_hints.y = win_y - (xterm_hints.height_inc * mouse_row)
+ - (xterm_hints.height_inc / 2);
+ if (xterm_hints.y <= xterm_hints.height_inc / 2)
+ xterm_hints.y = 2;
+ xterm_hints.x = win_x - (xterm_hints.width_inc * mouse_col)
+ - (xterm_hints.width_inc / 2);
+ if (xterm_hints.x <= xterm_hints.width_inc / 2)
+ xterm_hints.x = 2;
+ return TRUE;
+ }
+ if (mouse_code == NULL || STRLEN(mouse_code) > 45)
+ {
+ xterm_trace = 0;
+ return FALSE;
+ }
+
+ XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
+ &win_x, &win_y, &mask_return);
+
+ row = check_row((win_y - xterm_hints.y) / xterm_hints.height_inc);
+ col = check_col((win_x - xterm_hints.x) / xterm_hints.width_inc);
+ if (row == prev_row && col == prev_col)
+ return TRUE;
+
+ STRCPY(buf, mouse_code);
+ strp = buf + STRLEN(buf);
+ *strp++ = (xterm_button | MOUSE_DRAG) & ~0x20;
+ *strp++ = (char_u)(col + ' ' + 1);
+ *strp++ = (char_u)(row + ' ' + 1);
+ *strp = 0;
+ add_to_input_buf(buf, STRLEN(buf));
+
+ prev_row = row;
+ prev_col = col;
+ return TRUE;
+}
+
+# if defined(FEAT_GUI) || defined(PROTO)
+/*
+ * Destroy the display, window and app_context. Required for GTK.
+ */
+ void
+clear_xterm_clip(void)
+{
+ if (xterm_Shell != (Widget)0)
+ {
+ XtDestroyWidget(xterm_Shell);
+ xterm_Shell = (Widget)0;
+ }
+ if (xterm_dpy != NULL)
+ {
+# if 0
+ /* Lesstif and Solaris crash here, lose some memory */
+ XtCloseDisplay(xterm_dpy);
+# endif
+ if (x11_display == xterm_dpy)
+ x11_display = NULL;
+ xterm_dpy = NULL;
+ }
+# if 0
+ if (app_context != (XtAppContext)NULL)
+ {
+ /* Lesstif and Solaris crash here, lose some memory */
+ XtDestroyApplicationContext(app_context);
+ app_context = (XtAppContext)NULL;
+ }
+# endif
+}
+# endif
+
+/*
+ * Catch up with GUI or X events.
+ */
+ static void
+clip_update(void)
+{
+# ifdef FEAT_GUI
+ if (gui.in_use)
+ gui_mch_update();
+ else
+# endif
+ if (xterm_Shell != (Widget)0)
+ xterm_update();
+}
+
+/*
+ * 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.
+ */
+ static void
+xterm_update(void)
+{
+ XEvent event;
+
+ for (;;)
+ {
+ XtInputMask mask = XtAppPending(app_context);
+
+ if (mask == 0 || vim_is_input_buf_full())
+ break;
+
+ if (mask & XtIMXEvent)
+ {
+ /* There is an event to process. */
+ XtAppNextEvent(app_context, &event);
+#ifdef FEAT_CLIENTSERVER
+ {
+ XPropertyEvent *e = (XPropertyEvent *)&event;
+
+ if (e->type == PropertyNotify && e->window == commWindow
+ && e->atom == commProperty && e->state == PropertyNewValue)
+ serverEventProc(xterm_dpy, &event, 0);
+ }
+#endif
+ XtDispatchEvent(&event);
+ }
+ else
+ {
+ /* There is something else than an event to process. */
+ XtAppProcessEvent(app_context, mask);
+ }
+ }
+}
+
+ int
+clip_xterm_own_selection(VimClipboard *cbd)
+{
+ if (xterm_Shell != (Widget)0)
+ return clip_x11_own_selection(xterm_Shell, cbd);
+ return FAIL;
+}
+
+ void
+clip_xterm_lose_selection(VimClipboard *cbd)
+{
+ if (xterm_Shell != (Widget)0)
+ clip_x11_lose_selection(xterm_Shell, cbd);
+}
+
+ void
+clip_xterm_request_selection(VimClipboard *cbd)
+{
+ if (xterm_Shell != (Widget)0)
+ clip_x11_request_selection(xterm_Shell, xterm_dpy, cbd);
+}
+
+ void
+clip_xterm_set_selection(VimClipboard *cbd)
+{
+ clip_x11_set_selection(cbd);
+}
+#endif
+
+
+#if defined(USE_XSMP) || defined(PROTO)
+/*
+ * Code for X Session Management Protocol.
+ */
+
+# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
+/*
+ * This is our chance to ask the user if they want to save,
+ * or abort the logout
+ */
+ static void
+xsmp_handle_interaction(SmcConn smc_conn, SmPointer client_data UNUSED)
+{
+ cmdmod_T save_cmdmod;
+ int cancel_shutdown = False;
+
+ save_cmdmod = cmdmod;
+ cmdmod.confirm = TRUE;
+ if (check_changed_any(FALSE, FALSE))
+ /* Mustn't logout */
+ cancel_shutdown = True;
+ cmdmod = save_cmdmod;
+ setcursor(); /* position cursor */
+ out_flush();
+
+ /* Done interaction */
+ SmcInteractDone(smc_conn, cancel_shutdown);
+
+ /* Finish off
+ * Only end save-yourself here if we're not cancelling shutdown;
+ * we'll get a cancelled callback later in which we'll end it.
+ * Hopefully get around glitchy SMs (like GNOME-1)
+ */
+ if (!cancel_shutdown)
+ {
+ xsmp.save_yourself = False;
+ SmcSaveYourselfDone(smc_conn, True);
+ }
+}
+# endif
+
+/*
+ * Callback that starts save-yourself.
+ */
+ static void
+xsmp_handle_save_yourself(
+ SmcConn smc_conn,
+ SmPointer client_data UNUSED,
+ int save_type UNUSED,
+ Bool shutdown,
+ int interact_style UNUSED,
+ Bool fast UNUSED)
+{
+ /* Handle already being in saveyourself */
+ if (xsmp.save_yourself)
+ SmcSaveYourselfDone(smc_conn, True);
+ xsmp.save_yourself = True;
+ xsmp.shutdown = shutdown;
+
+ /* First up, preserve all files */
+ out_flush();
+ ml_sync_all(FALSE, FALSE); /* preserve all swap files */
+
+ if (p_verbose > 0)
+ verb_msg(_("XSMP handling save-yourself request"));
+
+# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
+ /* Now see if we can ask about unsaved files */
+ if (shutdown && !fast && gui.in_use)
+ /* Need to interact with user, but need SM's permission */
+ SmcInteractRequest(smc_conn, SmDialogError,
+ xsmp_handle_interaction, client_data);
+ else
+# endif
+ {
+ /* Can stop the cycle here */
+ SmcSaveYourselfDone(smc_conn, True);
+ xsmp.save_yourself = False;
+ }
+}
+
+
+/*
+ * Callback to warn us of imminent death.
+ */
+ static void
+xsmp_die(SmcConn smc_conn UNUSED, SmPointer client_data UNUSED)
+{
+ xsmp_close();
+
+ /* quit quickly leaving swapfiles for modified buffers behind */
+ getout_preserve_modified(0);
+}
+
+
+/*
+ * Callback to tell us that save-yourself has completed.
+ */
+ static void
+xsmp_save_complete(
+ SmcConn smc_conn UNUSED,
+ SmPointer client_data UNUSED)
+{
+ xsmp.save_yourself = False;
+}
+
+
+/*
+ * Callback to tell us that an instigated shutdown was cancelled
+ * (maybe even by us)
+ */
+ static void
+xsmp_shutdown_cancelled(
+ SmcConn smc_conn,
+ SmPointer client_data UNUSED)
+{
+ if (xsmp.save_yourself)
+ SmcSaveYourselfDone(smc_conn, True);
+ xsmp.save_yourself = False;
+ xsmp.shutdown = False;
+}
+
+
+/*
+ * Callback to tell us that a new ICE connection has been established.
+ */
+ static void
+xsmp_ice_connection(
+ IceConn iceConn,
+ IcePointer clientData UNUSED,
+ Bool opening,
+ IcePointer *watchData UNUSED)
+{
+ /* Intercept creation of ICE connection fd */
+ if (opening)
+ {
+ xsmp_icefd = IceConnectionNumber(iceConn);
+ IceRemoveConnectionWatch(xsmp_ice_connection, NULL);
+ }
+}
+
+
+/* Handle any ICE processing that's required; return FAIL if SM lost */
+ int
+xsmp_handle_requests(void)
+{
+ Bool rep;
+
+ if (IceProcessMessages(xsmp.iceconn, NULL, &rep)
+ == IceProcessMessagesIOError)
+ {
+ /* Lost ICE */
+ if (p_verbose > 0)
+ verb_msg(_("XSMP lost ICE connection"));
+ xsmp_close();
+ return FAIL;
+ }
+ else
+ return OK;
+}
+
+static int dummy;
+
+/* Set up X Session Management Protocol */
+ void
+xsmp_init(void)
+{
+ char errorstring[80];
+ SmcCallbacks smcallbacks;
+#if 0
+ SmPropValue smname;
+ SmProp smnameprop;
+ SmProp *smprops[1];
+#endif
+
+ if (p_verbose > 0)
+ verb_msg(_("XSMP opening connection"));
+
+ xsmp.save_yourself = xsmp.shutdown = False;
+
+ /* Set up SM callbacks - must have all, even if they're not used */
+ smcallbacks.save_yourself.callback = xsmp_handle_save_yourself;
+ smcallbacks.save_yourself.client_data = NULL;
+ smcallbacks.die.callback = xsmp_die;
+ smcallbacks.die.client_data = NULL;
+ smcallbacks.save_complete.callback = xsmp_save_complete;
+ smcallbacks.save_complete.client_data = NULL;
+ smcallbacks.shutdown_cancelled.callback = xsmp_shutdown_cancelled;
+ smcallbacks.shutdown_cancelled.client_data = NULL;
+
+ /* Set up a watch on ICE connection creations. The "dummy" argument is
+ * apparently required for FreeBSD (we get a BUS error when using NULL). */
+ if (IceAddConnectionWatch(xsmp_ice_connection, &dummy) == 0)
+ {
+ if (p_verbose > 0)
+ verb_msg(_("XSMP ICE connection watch failed"));
+ return;
+ }
+
+ /* Create an SM connection */
+ xsmp.smcconn = SmcOpenConnection(
+ NULL,
+ NULL,
+ SmProtoMajor,
+ SmProtoMinor,
+ SmcSaveYourselfProcMask | SmcDieProcMask
+ | SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask,
+ &smcallbacks,
+ NULL,
+ &xsmp.clientid,
+ sizeof(errorstring) - 1,
+ errorstring);
+ if (xsmp.smcconn == NULL)
+ {
+ char errorreport[132];
+
+ if (p_verbose > 0)
+ {
+ vim_snprintf(errorreport, sizeof(errorreport),
+ _("XSMP SmcOpenConnection failed: %s"), errorstring);
+ verb_msg(errorreport);
+ }
+ return;
+ }
+ xsmp.iceconn = SmcGetIceConnection(xsmp.smcconn);
+
+#if 0
+ /* ID ourselves */
+ smname.value = "vim";
+ smname.length = 3;
+ smnameprop.name = "SmProgram";
+ smnameprop.type = "SmARRAY8";
+ smnameprop.num_vals = 1;
+ smnameprop.vals = &smname;
+
+ smprops[0] = &smnameprop;
+ SmcSetProperties(xsmp.smcconn, 1, smprops);
+#endif
+}
+
+
+/* Shut down XSMP comms. */
+ void
+xsmp_close(void)
+{
+ if (xsmp_icefd != -1)
+ {
+ SmcCloseConnection(xsmp.smcconn, 0, NULL);
+ if (xsmp.clientid != NULL)
+ free(xsmp.clientid);
+ xsmp.clientid = NULL;
+ xsmp_icefd = -1;
+ }
+}
+#endif /* USE_XSMP */
+
+
+#ifdef EBCDIC
+/* Translate character to its CTRL- value */
+char CtrlTable[] =
+{
+/* 00 - 5E */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* ^ */ 0x1E,
+/* - */ 0x1F,
+/* 61 - 6C */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* _ */ 0x1F,
+/* 6E - 80 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* a */ 0x01,
+/* b */ 0x02,
+/* c */ 0x03,
+/* d */ 0x37,
+/* e */ 0x2D,
+/* f */ 0x2E,
+/* g */ 0x2F,
+/* h */ 0x16,
+/* i */ 0x05,
+/* 8A - 90 */
+ 0, 0, 0, 0, 0, 0, 0,
+/* j */ 0x15,
+/* k */ 0x0B,
+/* l */ 0x0C,
+/* m */ 0x0D,
+/* n */ 0x0E,
+/* o */ 0x0F,
+/* p */ 0x10,
+/* q */ 0x11,
+/* r */ 0x12,
+/* 9A - A1 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+/* s */ 0x13,
+/* t */ 0x3C,
+/* u */ 0x3D,
+/* v */ 0x32,
+/* w */ 0x26,
+/* x */ 0x18,
+/* y */ 0x19,
+/* z */ 0x3F,
+/* AA - AC */
+ 0, 0, 0,
+/* [ */ 0x27,
+/* AE - BC */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* ] */ 0x1D,
+/* BE - C0 */ 0, 0, 0,
+/* A */ 0x01,
+/* B */ 0x02,
+/* C */ 0x03,
+/* D */ 0x37,
+/* E */ 0x2D,
+/* F */ 0x2E,
+/* G */ 0x2F,
+/* H */ 0x16,
+/* I */ 0x05,
+/* CA - D0 */ 0, 0, 0, 0, 0, 0, 0,
+/* J */ 0x15,
+/* K */ 0x0B,
+/* L */ 0x0C,
+/* M */ 0x0D,
+/* N */ 0x0E,
+/* O */ 0x0F,
+/* P */ 0x10,
+/* Q */ 0x11,
+/* R */ 0x12,
+/* DA - DF */ 0, 0, 0, 0, 0, 0,
+/* \ */ 0x1C,
+/* E1 */ 0,
+/* S */ 0x13,
+/* T */ 0x3C,
+/* U */ 0x3D,
+/* V */ 0x32,
+/* W */ 0x26,
+/* X */ 0x18,
+/* Y */ 0x19,
+/* Z */ 0x3F,
+/* EA - FF*/ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+char MetaCharTable[]=
+{/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
+ 0, 0, 0, 0,'\\', 0,'F', 0,'W','M','N', 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,']', 0, 0,'G', 0, 0,'R','O', 0, 0, 0, 0,
+ '@','A','B','C','D','E', 0, 0,'H','I','J','K','L', 0, 0, 0,
+ 'P','Q', 0,'S','T','U','V', 0,'X','Y','Z','[', 0, 0,'^', 0
+};
+
+
+/* TODO: Use characters NOT numbers!!! */
+char CtrlCharTable[]=
+{/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
+ 124,193,194,195, 0,201, 0, 0, 0, 0, 0,210,211,212,213,214,
+ 215,216,217,226, 0,209,200, 0,231,232, 0, 0,224,189, 95,109,
+ 0, 0, 0, 0, 0, 0,230,173, 0, 0, 0, 0, 0,197,198,199,
+ 0, 0,229, 0, 0, 0, 0,196, 0, 0, 0, 0,227,228, 0,233,
+};
+
+
+#endif
diff --git a/src/os_unix.h b/src/os_unix.h
new file mode 100644
index 0000000..8919ff0
--- /dev/null
+++ b/src/os_unix.h
@@ -0,0 +1,494 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * Do ":help uganda" in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ */
+
+/*
+ * NextStep has a problem with configure, undefine a few things:
+ */
+#ifdef NeXT
+# ifdef HAVE_UTIME
+# undef HAVE_UTIME
+# endif
+# ifdef HAVE_SYS_UTSNAME_H
+# undef HAVE_SYS_UTSNAME_H
+# endif
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+
+#ifdef VAXC
+# include <types.h>
+# include <stat.h>
+#else
+# include <sys/types.h>
+# include <sys/stat.h>
+#endif
+
+#ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+#endif
+
+#if defined(__CYGWIN__) || defined(__CYGWIN32__)
+# define WIN32UNIX /* Compiling for Win32 using Unix files. */
+# define BINARY_FILE_IO
+
+# define CASE_INSENSITIVE_FILENAME
+# define USE_FNAME_CASE /* Fix filename case differences. */
+#endif
+
+/* On AIX 4.2 there is a conflicting prototype for ioctl() in stropts.h and
+ * unistd.h. This hack should fix that (suggested by Jeff George).
+ * But on AIX 4.3 it's alright (suggested by Jake Hamby). */
+#if defined(FEAT_GUI) && defined(_AIX) && !defined(_AIX43) && !defined(_NO_PROTO)
+# define _NO_PROTO
+#endif
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifdef HAVE_LIBC_H
+# include <libc.h> /* for NeXT */
+#endif
+
+#ifdef HAVE_SYS_PARAM_H
+# include <sys/param.h> /* defines BSD, if it's a BSD system */
+#endif
+
+/*
+ * Using getcwd() is preferred, because it checks for a buffer overflow.
+ * Don't use getcwd() on systems do use system("sh -c pwd"). There is an
+ * autoconf check for this.
+ * Use getcwd() anyway if getwd() isn't present.
+ */
+#if defined(HAVE_GETCWD) && !(defined(BAD_GETCWD) && defined(HAVE_GETWD))
+# define USE_GETCWD
+#endif
+
+/* always use unlink() to remove files */
+#ifndef PROTO
+# ifdef VMS
+# define mch_remove(x) delete((char *)(x))
+# define vim_mkdir(x, y) mkdir((char *)(x), y)
+# else
+# define vim_mkdir(x, y) mkdir((char *)(x), y)
+# define mch_rmdir(x) rmdir((char *)(x))
+# define mch_remove(x) unlink((char *)(x))
+# endif
+#endif
+
+/* The number of arguments to a signal handler is configured here. */
+/* It used to be a long list of almost all systems. Any system that doesn't
+ * have an argument??? */
+#define SIGHASARG
+
+/* List 3 arg systems here. I guess __sgi, please test and correct me. jw. */
+#if defined(__sgi) && defined(HAVE_SIGCONTEXT)
+# define SIGHAS3ARGS
+#endif
+
+#ifdef SIGHASARG
+# ifdef SIGHAS3ARGS
+# define SIGPROTOARG (int, int, struct sigcontext *)
+# define SIGDEFARG(s) (s, sig2, scont) int s, sig2; struct sigcontext *scont;
+# define SIGDUMMYARG 0, 0, (struct sigcontext *)0
+# else
+# define SIGPROTOARG (int)
+# define SIGDEFARG(s) (s) int s UNUSED;
+# define SIGDUMMYARG 0
+# endif
+#else
+# define SIGPROTOARG (void)
+# define SIGDEFARG(s) ()
+# define SIGDUMMYARG
+#endif
+
+#ifdef HAVE_DIRENT_H
+# include <dirent.h>
+# ifndef NAMLEN
+# define NAMLEN(dirent) strlen((dirent)->d_name)
+# endif
+#else
+# define dirent direct
+# define NAMLEN(dirent) (dirent)->d_namlen
+# if HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif
+# if HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif
+# if HAVE_NDIR_H
+# include <ndir.h>
+# endif
+#endif
+
+#if !defined(HAVE_SYS_TIME_H) || defined(TIME_WITH_SYS_TIME)
+# include <time.h> /* on some systems time.h should not be
+ included together with sys/time.h */
+#endif
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif
+
+#include <signal.h>
+
+#if defined(DIRSIZ) && !defined(MAXNAMLEN)
+# define MAXNAMLEN DIRSIZ
+#endif
+
+#if defined(UFS_MAXNAMLEN) && !defined(MAXNAMLEN)
+# define MAXNAMLEN UFS_MAXNAMLEN /* for dynix/ptx */
+#endif
+
+#if defined(NAME_MAX) && !defined(MAXNAMLEN)
+# define MAXNAMLEN NAME_MAX /* for Linux before .99p3 */
+#endif
+
+/*
+ * Note: if MAXNAMLEN has the wrong value, you will get error messages
+ * for not being able to open the swap file.
+ */
+#if !defined(MAXNAMLEN)
+# define MAXNAMLEN 512 /* for all other Unix */
+#endif
+
+#define BASENAMELEN (MAXNAMLEN - 5)
+
+#ifdef HAVE_PWD_H
+# include <pwd.h>
+#endif
+
+#if (defined(HAVE_SYS_RESOURCE_H) && defined(HAVE_GETRLIMIT)) \
+ || (defined(HAVE_SYS_SYSINFO_H) && defined(HAVE_SYSINFO)) \
+ || defined(HAVE_SYSCTL) || defined(HAVE_SYSCONF)
+# define HAVE_TOTAL_MEM
+#endif
+
+
+#ifndef PROTO
+
+#ifdef VMS
+# include <unixio.h>
+# include <unixlib.h>
+# include <signal.h>
+# include <file.h>
+# include <ssdef.h>
+# include <descrip.h>
+# include <libclidef.h>
+# include <lnmdef.h>
+# include <psldef.h>
+# include <prvdef.h>
+# include <dvidef.h>
+# include <dcdef.h>
+# include <stsdef.h>
+# include <iodef.h>
+# include <ttdef.h>
+# include <tt2def.h>
+# include <jpidef.h>
+# include <rms.h>
+# include <trmdef.h>
+# include <string.h>
+# include <starlet.h>
+# include <socket.h>
+# include <lib$routines.h>
+# include <libdef.h>
+# include <libdtdef.h>
+
+# ifdef FEAT_GUI_GTK
+# include "gui_gtk_vms.h"
+# endif
+#endif
+
+#endif /* PROTO */
+
+#ifdef VMS
+typedef struct dsc$descriptor DESC;
+#endif
+
+/*
+ * Unix system-dependent file names
+ */
+#ifndef SYS_VIMRC_FILE
+# define SYS_VIMRC_FILE "$VIM/vimrc"
+#endif
+#ifndef SYS_GVIMRC_FILE
+# define SYS_GVIMRC_FILE "$VIM/gvimrc"
+#endif
+#ifndef DFLT_HELPFILE
+# define DFLT_HELPFILE "$VIMRUNTIME/doc/help.txt"
+#endif
+#ifndef FILETYPE_FILE
+# define FILETYPE_FILE "filetype.vim"
+#endif
+#ifndef FTPLUGIN_FILE
+# define FTPLUGIN_FILE "ftplugin.vim"
+#endif
+#ifndef INDENT_FILE
+# define INDENT_FILE "indent.vim"
+#endif
+#ifndef FTOFF_FILE
+# define FTOFF_FILE "ftoff.vim"
+#endif
+#ifndef FTPLUGOF_FILE
+# define FTPLUGOF_FILE "ftplugof.vim"
+#endif
+#ifndef INDOFF_FILE
+# define INDOFF_FILE "indoff.vim"
+#endif
+#ifndef SYS_MENU_FILE
+# define SYS_MENU_FILE "$VIMRUNTIME/menu.vim"
+#endif
+
+#ifndef USR_EXRC_FILE
+# ifdef VMS
+# define USR_EXRC_FILE "sys$login:.exrc"
+# else
+# define USR_EXRC_FILE "$HOME/.exrc"
+# endif
+#endif
+
+#if !defined(USR_EXRC_FILE2) && defined(VMS)
+# define USR_EXRC_FILE2 "sys$login:_exrc"
+#endif
+
+#ifndef USR_VIMRC_FILE
+# ifdef VMS
+# define USR_VIMRC_FILE "sys$login:.vimrc"
+# else
+# define USR_VIMRC_FILE "$HOME/.vimrc"
+# endif
+#endif
+
+
+#if !defined(USR_VIMRC_FILE2)
+# ifdef VMS
+# define USR_VIMRC_FILE2 "sys$login:vimfiles/vimrc"
+# else
+# define USR_VIMRC_FILE2 "~/.vim/vimrc"
+# endif
+#endif
+
+#if !defined(USR_VIMRC_FILE3) && defined(VMS)
+# define USR_VIMRC_FILE3 "sys$login:_vimrc"
+#endif
+
+#ifndef USR_GVIMRC_FILE
+# ifdef VMS
+# define USR_GVIMRC_FILE "sys$login:.gvimrc"
+# else
+# define USR_GVIMRC_FILE "$HOME/.gvimrc"
+# endif
+#endif
+
+#ifndef USR_GVIMRC_FILE2
+# ifdef VMS
+# define USR_GVIMRC_FILE2 "sys$login:vimfiles/gvimrc"
+# else
+# define USR_GVIMRC_FILE2 "~/.vim/gvimrc"
+# endif
+#endif
+
+#ifdef VMS
+# ifndef USR_GVIMRC_FILE3
+# define USR_GVIMRC_FILE3 "sys$login:_gvimrc"
+# endif
+#endif
+
+#ifndef VIM_DEFAULTS_FILE
+# define VIM_DEFAULTS_FILE "$VIMRUNTIME/defaults.vim"
+#endif
+
+#ifndef EVIM_FILE
+# define EVIM_FILE "$VIMRUNTIME/evim.vim"
+#endif
+
+#ifdef FEAT_VIMINFO
+# ifndef VIMINFO_FILE
+# ifdef VMS
+# define VIMINFO_FILE "sys$login:.viminfo"
+# else
+# define VIMINFO_FILE "$HOME/.viminfo"
+# endif
+# endif
+# if !defined(VIMINFO_FILE2) && defined(VMS)
+# define VIMINFO_FILE2 "sys$login:_viminfo"
+# endif
+#endif
+
+#ifndef EXRC_FILE
+# define EXRC_FILE ".exrc"
+#endif
+
+#ifndef VIMRC_FILE
+# define VIMRC_FILE ".vimrc"
+#endif
+
+#ifdef FEAT_GUI
+# ifndef GVIMRC_FILE
+# define GVIMRC_FILE ".gvimrc"
+# endif
+#endif
+
+#ifndef SYNTAX_FNAME
+# define SYNTAX_FNAME "$VIMRUNTIME/syntax/%s.vim"
+#endif
+
+#ifndef DFLT_BDIR
+# ifdef VMS
+# define DFLT_BDIR "./,sys$login:,tmp:"
+# else
+# define DFLT_BDIR ".,~/tmp,~/" /* default for 'backupdir' */
+# endif
+#endif
+
+#ifndef DFLT_DIR
+# ifdef VMS
+# define DFLT_DIR "./,sys$login:,tmp:"
+# else
+# define DFLT_DIR ".,~/tmp,/var/tmp,/tmp" /* default for 'directory' */
+# endif
+#endif
+
+#ifndef DFLT_VDIR
+# ifdef VMS
+# define DFLT_VDIR "sys$login:vimfiles/view"
+# else
+# define DFLT_VDIR "$HOME/.vim/view" /* default for 'viewdir' */
+# endif
+#endif
+
+#define DFLT_ERRORFILE "errors.err"
+
+#ifdef VMS
+# define DFLT_RUNTIMEPATH "sys$login:vimfiles,$VIM/vimfiles,$VIMRUNTIME,$VIM/vimfiles/after,sys$login:vimfiles/after"
+# define CLEAN_RUNTIMEPATH "$VIM/vimfiles,$VIMRUNTIME,$VIM/vimfiles/after"
+#else
+# ifdef RUNTIME_GLOBAL
+# ifdef RUNTIME_GLOBAL_AFTER
+# define DFLT_RUNTIMEPATH "~/.vim," RUNTIME_GLOBAL ",$VIMRUNTIME," RUNTIME_GLOBAL_AFTER ",~/.vim/after"
+# define CLEAN_RUNTIMEPATH RUNTIME_GLOBAL ",$VIMRUNTIME," RUNTIME_GLOBAL_AFTER
+# else
+# define DFLT_RUNTIMEPATH "~/.vim," RUNTIME_GLOBAL ",$VIMRUNTIME," RUNTIME_GLOBAL "/after,~/.vim/after"
+# define CLEAN_RUNTIMEPATH RUNTIME_GLOBAL ",$VIMRUNTIME," RUNTIME_GLOBAL "/after"
+# endif
+# else
+# define DFLT_RUNTIMEPATH "~/.vim,$VIM/vimfiles,$VIMRUNTIME,$VIM/vimfiles/after,~/.vim/after"
+# define CLEAN_RUNTIMEPATH "$VIM/vimfiles,$VIMRUNTIME,$VIM/vimfiles/after"
+# endif
+#endif
+
+#ifdef VMS
+# ifndef VAX
+# define VMS_TEMPNAM /* to fix default .LIS extension */
+# endif
+# define TEMPNAME "TMP:v?XXXXXX.txt"
+# define TEMPNAMELEN 28
+#else
+/* Try several directories to put the temp files. */
+# define TEMPDIRNAMES "$TMPDIR", "/tmp", ".", "$HOME"
+# define TEMPNAMELEN 256
+#endif
+
+/* Special wildcards that need to be handled by the shell */
+#define SPECIAL_WILDCHAR "`'{"
+
+#ifndef HAVE_OPENDIR
+# define NO_EXPANDPATH
+#endif
+
+/*
+ * Unix has plenty of memory, use large buffers
+ */
+#define CMDBUFFSIZE 1024 /* size of the command processing buffer */
+
+/* Use the system path length if it makes sense. */
+#if defined(PATH_MAX) && (PATH_MAX > 1000)
+# define MAXPATHL PATH_MAX
+#else
+# define MAXPATHL 1024
+#endif
+
+#define CHECK_INODE /* used when checking if a swap file already
+ exists for a file */
+#ifdef VMS /* Use less memory because of older systems */
+# ifndef DFLT_MAXMEM
+# define DFLT_MAXMEM (2*1024)
+# endif
+# ifndef DFLT_MAXMEMTOT
+# define DFLT_MAXMEMTOT (5*1024)
+# endif
+#else
+# ifndef DFLT_MAXMEM
+# define DFLT_MAXMEM (5*1024) /* use up to 5 Mbyte for a buffer */
+# endif
+# ifndef DFLT_MAXMEMTOT
+# define DFLT_MAXMEMTOT (10*1024) /* use up to 10 Mbyte for Vim */
+# endif
+#endif
+
+/* memmove() is not present on all systems, use memmove, bcopy or memcpy.
+ * Some systems have (void *) arguments, some (char *). If we use (char *) it
+ * works for all */
+#if defined(USEMEMMOVE) || (!defined(USEBCOPY) && !defined(USEMEMCPY))
+# define mch_memmove(to, from, len) memmove((char *)(to), (char *)(from), len)
+#else
+# ifdef USEBCOPY
+# define mch_memmove(to, from, len) bcopy((char *)(from), (char *)(to), len)
+# else
+ /* ifdef USEMEMCPY */
+# define mch_memmove(to, from, len) memcpy((char *)(to), (char *)(from), len)
+# endif
+#endif
+
+#ifndef PROTO
+# ifdef HAVE_RENAME
+# define mch_rename(src, dst) rename(src, dst)
+# else
+int mch_rename(const char *src, const char *dest);
+# endif
+# ifndef VMS
+# ifdef __MVS__
+ /* on OS390 Unix getenv() doesn't return a pointer to persistent
+ * storage -> use __getenv() */
+# define mch_getenv(x) (char_u *)__getenv((char *)(x))
+# else
+# define mch_getenv(x) (char_u *)getenv((char *)(x))
+# endif
+# define mch_setenv(name, val, x) setenv(name, val, x)
+# endif
+#endif
+
+/* Note: Some systems need both string.h and strings.h (Savage). However,
+ * some systems can't handle both, only use string.h in that case. */
+#ifdef HAVE_STRING_H
+# include <string.h>
+#endif
+#if defined(HAVE_STRINGS_H) && !defined(NO_STRINGS_WITH_STRING_H)
+# include <strings.h>
+#endif
+
+#if defined(HAVE_SETJMP_H)
+# include <setjmp.h>
+# ifdef HAVE_SIGSETJMP
+# define JMP_BUF sigjmp_buf
+# define SETJMP(x) sigsetjmp((x), 1)
+# define LONGJMP siglongjmp
+# else
+# define JMP_BUF jmp_buf
+# define SETJMP(x) setjmp(x)
+# define LONGJMP longjmp
+# endif
+#endif
+
+#ifndef HAVE_DUP
+# define HAVE_DUP /* have dup() */
+#endif
+#define HAVE_ST_MODE /* have stat.st_mode */
+
+/* We have three kinds of ACL support. */
+#define HAVE_ACL (HAVE_POSIX_ACL || HAVE_SOLARIS_ACL || HAVE_AIX_ACL)
diff --git a/src/os_unixx.h b/src/os_unixx.h
new file mode 100644
index 0000000..edf7914
--- /dev/null
+++ b/src/os_unixx.h
@@ -0,0 +1,116 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * Do ":help uganda" in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ */
+
+/*
+ * os_unixx.h -- include files that are only used in os_unix.c
+ */
+
+/*
+ * Stuff for signals
+ */
+#if defined(HAVE_SIGSET) && !defined(signal)
+# define signal sigset
+#endif
+
+ /* Sun's sys/ioctl.h redefines symbols from termio world */
+#if defined(HAVE_SYS_IOCTL_H) && !defined(SUN_SYSTEM)
+# include <sys/ioctl.h>
+#endif
+
+#ifndef USE_SYSTEM /* use fork/exec to start the shell */
+
+# if defined(HAVE_SYS_WAIT_H) || defined(HAVE_UNION_WAIT)
+# include <sys/wait.h>
+# endif
+
+# ifndef WEXITSTATUS
+# ifdef HAVE_UNION_WAIT
+# define WEXITSTATUS(stat_val) ((stat_val).w_T.w_Retcode)
+# else
+# define WEXITSTATUS(stat_val) (((stat_val) >> 8) & 0377)
+# endif
+# endif
+
+# ifndef WIFEXITED
+# ifdef HAVE_UNION_WAIT
+# define WIFEXITED(stat_val) ((stat_val).w_T.w_Termsig == 0)
+# else
+# define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
+# endif
+# endif
+
+#endif /* !USE_SYSTEM */
+
+#ifdef HAVE_STROPTS_H
+#ifdef sinix
+#define buf_T __system_buf_t__
+#endif
+# include <stropts.h>
+#ifdef sinix
+#undef buf_T
+#endif
+#endif
+
+#ifdef HAVE_STRING_H
+# include <string.h>
+#endif
+
+#ifdef HAVE_SYS_STREAM_H
+# include <sys/stream.h>
+#endif
+
+#ifdef HAVE_SYS_UTSNAME_H
+# include <sys/utsname.h>
+#endif
+
+#ifdef HAVE_SYS_SYSTEMINFO_H
+/* <sys/systeminfo.h> uses SYS_NMLN but it may not be defined (CrayT3E). */
+# ifndef SYS_NMLN
+# define SYS_NMLN 32
+# endif
+
+# include <sys/systeminfo.h> /* for sysinfo */
+#endif
+
+/*
+ * We use termios.h if both termios.h and termio.h are available.
+ * Termios is supposed to be a superset of termio.h. Don't include them both,
+ * it may give problems on some systems (e.g. hpux).
+ * I don't understand why we don't want termios.h for apollo.
+ */
+#if defined(HAVE_TERMIOS_H) && !defined(apollo)
+# include <termios.h>
+#else
+# ifdef HAVE_TERMIO_H
+# include <termio.h>
+# else
+# ifdef HAVE_SGTTY_H
+# include <sgtty.h>
+# endif
+# endif
+#endif
+
+#ifdef HAVE_SYS_PTEM_H
+# include <sys/ptem.h> /* must be after termios.h for Sinix */
+# ifndef _IO_PTEM_H /* For UnixWare that should check for _IO_PT_PTEM_H */
+# define _IO_PTEM_H
+# endif
+#endif
+
+/* shared library access */
+#if defined(HAVE_DLFCN_H) && defined(USE_DLOPEN)
+# if defined(__MVS__) && !defined (__SUSV3)
+ /* needed to define RTLD_LAZY (Anthony Giorgio) */
+# define __SUSV3
+# endif
+# include <dlfcn.h>
+#else
+# if defined(HAVE_DL_H) && defined(HAVE_SHL_LOAD)
+# include <dl.h>
+# endif
+#endif
diff --git a/src/os_vms.c b/src/os_vms.c
new file mode 100644
index 0000000..61db3a8
--- /dev/null
+++ b/src/os_vms.c
@@ -0,0 +1,804 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ * VMS port by Henk Elbers
+ * VMS deport by Zoltan Arpadffy
+ *
+ * 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.
+ */
+
+#include "vim.h"
+
+/* define _generic_64 for use in time functions */
+#if !defined(VAX) && !defined(PROTO)
+# include <gen64def.h>
+#else
+/* based on Alpha's gen64def.h; the file is absent on VAX */
+typedef struct _generic_64 {
+# pragma __nomember_alignment
+ __union { /* You can treat me as... */
+ /* long long is not available on VAXen */
+ /* unsigned __int64 gen64$q_quadword; ...a single 64-bit value, or */
+
+ unsigned int gen64$l_longword [2]; /* ...two 32-bit values, or */
+ unsigned short int gen64$w_word [4]; /* ...four 16-bit values */
+ } gen64$r_quad_overlay;
+} GENERIC_64;
+#endif
+
+typedef struct
+{
+ char class;
+ char type;
+ short width;
+ union
+ {
+ struct
+ {
+ char _basic[3];
+ char length;
+ } y;
+ int basic;
+ } x;
+ int extended;
+} TT_MODE;
+
+typedef struct
+{
+ short buflen;
+ short itemcode;
+ char *bufadrs;
+ int *retlen;
+} ITEM;
+
+typedef struct
+{
+ ITEM equ;
+ int nul;
+} ITMLST1;
+
+typedef struct
+{
+ ITEM index;
+ ITEM string;
+ int nul;
+} ITMLST2;
+
+static TT_MODE orgmode;
+static short iochan; /* TTY I/O channel */
+static short iosb[4]; /* IO status block */
+
+static int vms_match_num = 0;
+static int vms_match_free = 0;
+static char_u **vms_fmatch = NULL;
+static char *Fspec_Rms; /* rms file spec, passed implicitly between routines */
+
+
+
+static TT_MODE get_tty(void);
+static void set_tty(int row, int col);
+
+#define EXPL_ALLOC_INC 64
+
+#define EQN(S1,S2,LN) (strncmp(S1,S2,LN) == 0)
+#define SKIP_FOLLOWING_SLASHES(Str) do { while (Str[1] == '/') ++Str; } while (0)
+
+
+/*
+ * vul_desc vult een descriptor met een string en de lengte
+ * hier van.
+ */
+ static void
+vul_desc(DESC *des, char *str)
+{
+ des->dsc$b_dtype = DSC$K_DTYPE_T;
+ des->dsc$b_class = DSC$K_CLASS_S;
+ des->dsc$a_pointer = str;
+ des->dsc$w_length = str ? strlen(str) : 0;
+}
+
+/*
+ * vul_item vult een item met een aantal waarden
+ */
+ static void
+vul_item(ITEM *itm, short len, short cod, char *adr, int *ret)
+{
+ itm->buflen = len;
+ itm->itemcode = cod;
+ itm->bufadrs = adr;
+ itm->retlen = ret;
+}
+
+ void
+mch_settmode(int tmode)
+{
+ int status;
+
+ if ( tmode == TMODE_RAW )
+ set_tty(0, 0);
+ else{
+ switch (orgmode.width)
+ {
+ case 132: OUT_STR_NF((char_u *)"\033[?3h\033>"); break;
+ case 80: OUT_STR_NF((char_u *)"\033[?3l\033>"); break;
+ default: break;
+ }
+ out_flush();
+ status = sys$qiow(0, iochan, IO$_SETMODE, iosb, 0, 0,
+ &orgmode, sizeof(TT_MODE), 0,0,0,0);
+ if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL)
+ return;
+ (void)sys$dassgn(iochan);
+ iochan = 0;
+ }
+}
+
+ static void
+set_tty(int row, int col)
+{
+ int status;
+ TT_MODE newmode; /* New TTY mode bits */
+ static short first_time = TRUE;
+
+ if (first_time)
+ {
+ orgmode = get_tty();
+ first_time = FALSE;
+ }
+ newmode = get_tty();
+ if (col)
+ newmode.width = col;
+ if (row)
+ newmode.x.y.length = row;
+ newmode.x.basic |= (TT$M_NOECHO | TT$M_HOSTSYNC);
+ newmode.x.basic &= ~TT$M_TTSYNC;
+ newmode.extended |= TT2$M_PASTHRU;
+ status = sys$qiow(0, iochan, IO$_SETMODE, iosb, 0, 0,
+ &newmode, sizeof(newmode), 0, 0, 0, 0);
+ if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL)
+ return;
+}
+
+ static TT_MODE
+get_tty(void)
+{
+
+ static $DESCRIPTOR(odsc,"SYS$OUTPUT"); /* output descriptor */
+
+ int status;
+ TT_MODE tt_mode;
+
+ if (!iochan)
+ status = sys$assign(&odsc,&iochan,0,0);
+
+ status = sys$qiow(0, iochan, IO$_SENSEMODE, iosb, 0, 0,
+ &tt_mode, sizeof(tt_mode), 0, 0, 0, 0);
+ if (status != SS$_NORMAL || (iosb[0] & 0xFFFF) != SS$_NORMAL)
+ {
+ tt_mode.width = 0;
+ tt_mode.type = 0;
+ tt_mode.class = 0;
+ tt_mode.x.basic = 0;
+ tt_mode.x.y.length = 0;
+ tt_mode.extended = 0;
+ }
+ return(tt_mode);
+}
+
+/*
+ * Get the current window size in Rows and Columns.
+ */
+ int
+mch_get_shellsize(void)
+{
+ TT_MODE tmode;
+
+ tmode = get_tty(); /* get size from VMS */
+ Columns = tmode.width;
+ Rows = tmode.x.y.length;
+ return OK;
+}
+
+/*
+ * Try to set the window size to Rows and new_Columns.
+ */
+ void
+mch_set_shellsize(void)
+{
+ set_tty(Rows, Columns);
+ switch (Columns)
+ {
+ case 132: OUT_STR_NF((char_u *)"\033[?3h\033>"); break;
+ case 80: OUT_STR_NF((char_u *)"\033[?3l\033>"); break;
+ default: break;
+ }
+ out_flush();
+ screen_start();
+}
+
+ char_u *
+mch_getenv(char_u *lognam)
+{
+ DESC d_file_dev, d_lognam ;
+ static char buffer[LNM$C_NAMLENGTH+1];
+ char_u *cp = NULL;
+ unsigned long attrib;
+ int lengte = 0, dum = 0, idx = 0;
+ ITMLST2 itmlst;
+ char *sbuf = NULL;
+
+ vul_desc(&d_lognam, (char *)lognam);
+ vul_desc(&d_file_dev, "LNM$FILE_DEV");
+ attrib = LNM$M_CASE_BLIND;
+ vul_item(&itmlst.index, sizeof(int), LNM$_INDEX, (char *)&idx, &dum);
+ vul_item(&itmlst.string, LNM$C_NAMLENGTH, LNM$_STRING, buffer, &lengte);
+ itmlst.nul = 0;
+ if (sys$trnlnm(&attrib, &d_file_dev, &d_lognam, NULL,&itmlst) == SS$_NORMAL)
+ {
+ buffer[lengte] = '\0';
+ if (cp = (char_u *)alloc((unsigned)(lengte+1)))
+ strcpy((char *)cp, buffer);
+ return(cp);
+ }
+ else if ((sbuf = getenv((char *)lognam)))
+ {
+ lengte = strlen(sbuf) + 1;
+ cp = (char_u *)alloc((size_t)lengte);
+ if (cp)
+ strcpy((char *)cp, sbuf);
+ return cp;
+ }
+ else
+ return(NULL);
+}
+
+/*
+ * mch_setenv VMS version of setenv()
+ */
+ int
+mch_setenv(char *var, char *value, int x)
+{
+ int res, dum;
+ long attrib = 0L;
+ char acmode = PSL$C_SUPER; /* needs SYSNAM privilege */
+ DESC tabnam, lognam;
+ ITMLST1 itmlst;
+
+ vul_desc(&tabnam, "LNM$JOB");
+ vul_desc(&lognam, var);
+ vul_item(&itmlst.equ, value ? strlen(value) : 0, value ? LNM$_STRING : 0,
+ value, &dum);
+ itmlst.nul = 0;
+ res = sys$crelnm(&attrib, &tabnam, &lognam, &acmode, &itmlst);
+ return((res == 1) ? 0 : -1);
+}
+
+ int
+vms_sys(char *cmd, char *out, char *inp)
+{
+ DESC cdsc, odsc, idsc;
+ long status;
+
+ if (cmd)
+ vul_desc(&cdsc, cmd);
+ if (out)
+ vul_desc(&odsc, out);
+ if (inp)
+ vul_desc(&idsc, inp);
+
+ lib$spawn(cmd ? &cdsc : NULL, /* command string */
+ inp ? &idsc : NULL, /* input file */
+ out ? &odsc : NULL, /* output file */
+ 0, 0, 0, &status, 0, 0, 0, 0, 0, 0);
+ return status;
+}
+
+/*
+ * Convert string to lowercase - most often filename
+ */
+ char *
+vms_tolower( char *name )
+{
+ int i,nlen = strlen(name);
+ for (i = 0; i < nlen; i++)
+ name[i] = TOLOWER_ASC(name[i]);
+ return name;
+}
+
+/*
+ * Convert VMS system() or lib$spawn() return code to Unix-like exit value.
+ */
+ int
+vms_sys_status(int status)
+{
+ if (status != SS$_NORMAL && (status & STS$M_SUCCESS) == 0)
+ return status; /* Command failed. */
+ return 0;
+}
+
+/*
+ * vms_read()
+ * function for low level char input
+ *
+ * Returns: input length
+ */
+ int
+vms_read(char *inbuf, size_t nbytes)
+{
+ int status, function, len;
+ TT_MODE tt_mode;
+ ITEM itmlst[2]; /* terminates on everything */
+ static long trm_mask[8] = {-1, -1, -1, -1, -1, -1, -1, -1};
+
+ /* whatever happened earlier we need an iochan here */
+ if (!iochan)
+ tt_mode = get_tty();
+
+ /* important: clean the inbuf */
+ memset(inbuf, 0, nbytes);
+
+ /* set up the itemlist for the first read */
+ vul_item(&itmlst[0], 0, TRM$_MODIFIERS,
+ (char *)( TRM$M_TM_NOECHO | TRM$M_TM_NOEDIT |
+ TRM$M_TM_NOFILTR | TRM$M_TM_TRMNOECHO |
+ TRM$M_TM_NORECALL) , 0);
+ vul_item(&itmlst[1], sizeof(trm_mask), TRM$_TERM, (char *)&trm_mask, 0);
+
+ /* wait forever for a char */
+ function = (IO$_READLBLK | IO$M_EXTEND);
+ status = sys$qiow(0, iochan, function, &iosb, 0, 0,
+ inbuf, nbytes-1, 0, 0, &itmlst, sizeof(itmlst));
+ len = strlen(inbuf); /* how many chars we got? */
+
+ /* read immediately the rest in the IO queue */
+ function = (IO$_READLBLK | IO$M_TIMED | IO$M_ESCAPE | IO$M_NOECHO | IO$M_NOFILTR);
+ status = sys$qiow(0, iochan, function, &iosb, 0, 0,
+ inbuf+len, nbytes-1-len, 0, 0, 0, 0);
+
+ len = strlen(inbuf); /* return the total length */
+
+ return len;
+}
+
+/*
+ * vms_wproc() is called for each matching filename by decc$to_vms().
+ * We want to save each match for later retrieval.
+ *
+ * Returns: 1 - continue finding matches
+ * 0 - stop trying to find any further matches
+ */
+ static int
+vms_wproc(char *name, int val)
+{
+ int i;
+ static int vms_match_alloced = 0;
+
+ if (val == DECC$K_FOREIGN ) /* foreign non VMS files are not counting */
+ return 1;
+
+ /* accept all DECC$K_FILE and DECC$K_DIRECTORY */
+ if (vms_match_num == 0) {
+ /* first time through, setup some things */
+ if (NULL == vms_fmatch) {
+ vms_fmatch = (char_u **)alloc(EXPL_ALLOC_INC * sizeof(char *));
+ if (!vms_fmatch)
+ return 0;
+ vms_match_alloced = EXPL_ALLOC_INC;
+ vms_match_free = EXPL_ALLOC_INC;
+ }
+ else {
+ /* re-use existing space */
+ vms_match_free = vms_match_alloced;
+ }
+ }
+
+ /* make matches look uniform */
+ vms_remove_version(name);
+ name=vms_tolower(name);
+
+ /* if name already exists, don't add it */
+ for (i = 0; i<vms_match_num; i++) {
+ if (0 == STRCMP((char_u *)name,vms_fmatch[i]))
+ return 1;
+ }
+ if (--vms_match_free == 0) {
+ /* add more space to store matches */
+ vms_match_alloced += EXPL_ALLOC_INC;
+ vms_fmatch = (char_u **)vim_realloc(vms_fmatch,
+ sizeof(char **) * vms_match_alloced);
+ if (!vms_fmatch)
+ return 0;
+ vms_match_free = EXPL_ALLOC_INC;
+ }
+ vms_fmatch[vms_match_num] = vim_strsave((char_u *)name);
+
+ ++vms_match_num;
+ return 1;
+}
+
+/*
+ * mch_expand_wildcards this code does wild-card pattern
+ * matching NOT using the shell
+ *
+ * return OK for success, FAIL for error (you may lose some
+ * memory) and put an error message in *file.
+ *
+ * num_pat number of input patterns
+ * pat array of pointers to input patterns
+ * num_file pointer to number of matched file names
+ * file pointer to array of pointers to matched file names
+ *
+ */
+ int
+mch_expand_wildcards(int num_pat, char_u **pat, int *num_file, char_u ***file, int flags)
+{
+ int i, cnt = 0;
+ char_u buf[MAXPATHL];
+ char *result;
+ int dir;
+ int files_alloced, files_free;
+
+ *num_file = 0; /* default: no files found */
+ files_alloced = EXPL_ALLOC_INC;
+ files_free = EXPL_ALLOC_INC;
+ *file = (char_u **) alloc(sizeof(char_u **) * files_alloced);
+ if (*file == NULL)
+ {
+ *num_file = 0;
+ return FAIL;
+ }
+ for (i = 0; i < num_pat; i++)
+ {
+ /* expand environment var or home dir */
+ if (vim_strchr(pat[i],'$') || vim_strchr(pat[i],'~'))
+ expand_env(pat[i],buf,MAXPATHL);
+ else
+ STRCPY(buf,pat[i]);
+
+ vms_match_num = 0; /* reset collection counter */
+ result = decc$translate_vms(vms_fixfilename(buf));
+ if ( (int) result == 0 || (int) result == -1 ) {
+ cnt = 0;
+ } else {
+ cnt = decc$to_vms(result, vms_wproc, 1 /*allow wild*/ , (flags & EW_DIR ? 0:1 ) /*allow directory*/) ;
+ }
+ if (cnt > 0)
+ cnt = vms_match_num;
+
+ if (cnt < 1)
+ continue;
+
+ for (i = 0; i < cnt; i++)
+ {
+ /* files should exist if expanding interactively */
+ if (!(flags & EW_NOTFOUND) && mch_getperm(vms_fmatch[i]) < 0)
+ continue;
+
+ /* do not include directories */
+ dir = (mch_isdir(vms_fmatch[i]));
+ if (( dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
+ continue;
+
+ /* Skip files that are not executable if we check for that. */
+ if (!dir && (flags & EW_EXEC)
+ && !mch_can_exe(vms_fmatch[i], NULL, !(flags & EW_SHELLCMD)))
+ continue;
+
+ /* allocate memory for pointers */
+ if (--files_free < 1)
+ {
+ files_alloced += EXPL_ALLOC_INC;
+ *file = (char_u **)vim_realloc(*file,
+ sizeof(char_u **) * files_alloced);
+ if (*file == NULL)
+ {
+ *file = (char_u **)"";
+ *num_file = 0;
+ return(FAIL);
+ }
+ files_free = EXPL_ALLOC_INC;
+ }
+
+ (*file)[*num_file++] = vms_fmatch[i];
+ }
+ }
+ return OK;
+}
+
+ int
+mch_expandpath(garray_T *gap, char_u *path, int flags)
+{
+ int i,cnt = 0;
+ char *result;
+
+ vms_match_num = 0;
+ /* the result from the decc$translate_vms needs to be handled */
+ /* otherwise it might create ACCVIO error in decc$to_vms */
+ result = decc$translate_vms(vms_fixfilename(path));
+ if ( (int) result == 0 || (int) result == -1 ) {
+ cnt = 0;
+ } else {
+ cnt = decc$to_vms(result, vms_wproc, 1 /*allow_wild*/, (flags & EW_DIR ? 0:1 ) /*allow directory*/);
+ }
+ if (cnt > 0)
+ cnt = vms_match_num;
+ for (i = 0; i < cnt; i++)
+ {
+ if (mch_getperm(vms_fmatch[i]) >= 0) /* add existing file */
+ addfile(gap, vms_fmatch[i], flags);
+ }
+ return cnt;
+}
+
+/*
+ * attempt to translate a mixed unix-vms file specification to pure vms
+ */
+ static void
+vms_unix_mixed_filespec(char *in, char *out)
+{
+ char *lastcolon;
+ char *end_of_dir;
+ char ch;
+ int len;
+ char *out_str=out;
+
+ /* copy vms filename portion up to last colon
+ * (node and/or disk)
+ */
+ lastcolon = strrchr(in, ':'); /* find last colon */
+ if (lastcolon != NULL) {
+ len = lastcolon - in + 1;
+ strncpy(out, in, len);
+ out += len;
+ in += len;
+ }
+
+ end_of_dir = NULL; /* default: no directory */
+
+ /* start of directory portion */
+ ch = *in;
+ if ((ch == '[') || (ch == '/') || (ch == '<')) { /* start of directory(s) ? */
+ ch = '[';
+ SKIP_FOLLOWING_SLASHES(in);
+ } else if (EQN(in, "../", 3)) { /* Unix parent directory? */
+ *out++ = '[';
+ *out++ = '-';
+ end_of_dir = out;
+ ch = '.';
+ in += 2;
+ SKIP_FOLLOWING_SLASHES(in);
+ } else { /* not a special character */
+ while (EQN(in, "./", 2)) { /* Ignore Unix "current dir" */
+ in += 2;
+ SKIP_FOLLOWING_SLASHES(in);
+ }
+ if (strchr(in, '/') == NULL) { /* any more Unix directories ? */
+ strcpy(out, in); /* No - get rest of the spec */
+ return;
+ } else {
+ *out++ = '['; /* Yes, denote a Vms subdirectory */
+ ch = '.';
+ --in;
+ }
+ }
+
+ /* if we get here, there is a directory part of the filename */
+
+ /* initialize output file spec */
+ *out++ = ch;
+ ++in;
+
+ while (*in != '\0') {
+ ch = *in;
+ if ((ch == ']') || (ch == '/') || (ch == '>') ) { /* end of (sub)directory ? */
+ end_of_dir = out;
+ ch = '.';
+ SKIP_FOLLOWING_SLASHES(in);
+ }
+ else if (EQN(in, "../", 3)) { /* Unix parent directory? */
+ *out++ = '-';
+ end_of_dir = out;
+ ch = '.';
+ in += 2;
+ SKIP_FOLLOWING_SLASHES(in);
+ }
+ else {
+ while (EQN(in, "./", 2)) { /* Ignore Unix "current dir" */
+ end_of_dir = out;
+ in += 2;
+ SKIP_FOLLOWING_SLASHES(in);
+ ch = *in;
+ }
+ }
+
+ /* Place next character into output file spec */
+ *out++ = ch;
+ ++in;
+ }
+
+ *out = '\0'; /* Terminate output file spec */
+
+ if (end_of_dir != NULL) /* Terminate directory portion */
+ *end_of_dir = ']';
+}
+
+/*
+ * for decc$to_vms in vms_fixfilename
+ */
+ static int
+vms_fspec_proc(char *fil, int val)
+{
+ strcpy(Fspec_Rms,fil);
+ return(1);
+}
+
+/*
+ * change unix and mixed filenames to VMS
+ */
+ void *
+vms_fixfilename(void *instring)
+{
+ static char *buf = NULL;
+ static size_t buflen = 0;
+ size_t len;
+
+ /* get a big-enough buffer */
+ len = strlen(instring) + 1;
+ if (len > buflen)
+ {
+ buflen = len + 128;
+ if (buf)
+ buf = (char *)vim_realloc(buf, buflen);
+ else
+ buf = (char *)alloc(buflen * sizeof(char));
+ }
+
+#ifdef DEBUG
+ char *tmpbuf = NULL;
+ tmpbuf = (char *)alloc(buflen * sizeof(char));
+ strcpy(tmpbuf, instring);
+#endif
+
+ Fspec_Rms = buf; /* for decc$to_vms */
+
+ if (strchr(instring,'/') == NULL)
+ /* It is already a VMS file spec */
+ strcpy(buf, instring);
+ else if (strchr(instring,'"') == NULL) /* password in the path? */
+ {
+ /* Seems it is a regular file, let guess that it is pure Unix fspec */
+ if (decc$to_vms(instring, vms_fspec_proc, 0, 0) <= 0)
+ /* No... it must be mixed */
+ vms_unix_mixed_filespec(instring, buf);
+ }
+ else
+ /* we have a password in the path */
+ /* decc$ functions can not handle */
+ /* this is our only hope to resolv */
+ vms_unix_mixed_filespec(instring, buf);
+
+ return buf;
+}
+
+/*
+ * Remove version number from file name
+ * we need it in some special cases as:
+ * creating swap file name and writing new file
+ */
+ void
+vms_remove_version(void * fname)
+{
+ char_u *cp;
+ char_u *fp;
+
+ if ((cp = vim_strchr( fname, ';')) != NULL) /* remove version */
+ *cp = '\0';
+ else if ((cp = vim_strrchr( fname, '.')) != NULL )
+ {
+ if ((fp = vim_strrchr( fname, ']')) != NULL ) {;}
+ else if ((fp = vim_strrchr( fname, '>')) != NULL ) {;}
+ else fp = fname;
+
+ while ( *fp != '\0' && fp < cp )
+ if ( *fp++ == '.' )
+ *cp = '\0';
+ }
+ return ;
+}
+
+struct typeahead_st {
+ unsigned short numchars;
+ unsigned char firstchar;
+ unsigned char reserved0;
+ unsigned long reserved1;
+} typeahead;
+
+/*
+ * Wait "msec" msec until a character is available from file descriptor "fd".
+ * "msec" == 0 will check for characters once.
+ * "msec" == -1 will block until a character is available.
+ */
+ int
+RealWaitForChar(
+ int fd UNUSED, /* always read from iochan */
+ long msec,
+ int *check_for_gpm UNUSED,
+ int *interrupted)
+{
+ int status;
+ struct _generic_64 time_curr;
+ struct _generic_64 time_diff;
+ struct _generic_64 time_out;
+ unsigned int convert_operation = LIB$K_DELTA_SECONDS_F;
+ float sec =(float) msec/1000;
+
+ /* make sure the iochan is set */
+ if (!iochan)
+ get_tty();
+
+ if (sec > 0) {
+ /* time-out specified; convert it to absolute time */
+ /* sec>0 requirement of lib$cvtf_to_internal_time()*/
+
+ /* get current time (number of 100ns ticks since the VMS Epoch) */
+ status = sys$gettim(&time_curr);
+ if (status != SS$_NORMAL)
+ return 0; /* error */
+ /* construct the delta time */
+#if __G_FLOAT==0
+# ifndef VAX
+ /* IEEE is default on IA64, but can be used on Alpha too - but not on VAX */
+ status = lib$cvts_to_internal_time(
+ &convert_operation, &sec, &time_diff);
+# endif
+#else /* default on Alpha and VAX */
+ status = lib$cvtf_to_internal_time(
+ &convert_operation, &sec, &time_diff);
+#endif
+ if (status != LIB$_NORMAL)
+ return 0; /* error */
+ /* add them up */
+ status = lib$add_times(
+ &time_curr,
+ &time_diff,
+ &time_out);
+ if (status != LIB$_NORMAL)
+ return 0; /* error */
+ }
+
+ while (TRUE) {
+ /* select() */
+ status = sys$qiow(0, iochan, IO$_SENSEMODE | IO$M_TYPEAHDCNT, iosb,
+ 0, 0, &typeahead, 8, 0, 0, 0, 0);
+ if (status != SS$_NORMAL || (iosb[0] & 0xFFFF) != SS$_NORMAL)
+ return 0; /* error */
+
+ if (typeahead.numchars)
+ return 1; /* ready to read */
+
+ /* there's nothing to read; what now? */
+ if (msec == 0) {
+ /* immediate time-out; return impatiently */
+ return 0;
+ } else if (msec < 0) {
+ /* no time-out; wait on indefinitely */
+ return 1; /* fakeout to force a wait in vms_read() */
+ } else {
+ /* time-out needs to be checked */
+ status = sys$gettim(&time_curr);
+ if (status != SS$_NORMAL)
+ return 0; /* error */
+
+ status = lib$sub_times(
+ &time_out,
+ &time_curr,
+ &time_diff);
+ if (status != LIB$_NORMAL)
+ return 0; /* error, incl. time_diff < 0 (i.e. time-out) */
+
+ /* otherwise wait some more */
+ }
+ }
+}
diff --git a/src/os_vms_conf.h b/src/os_vms_conf.h
new file mode 100644
index 0000000..6bc6efb
--- /dev/null
+++ b/src/os_vms_conf.h
@@ -0,0 +1,205 @@
+/* os_vms_conf.h. Replaces auto/config.h for VMS */
+
+#define CASE_INSENSITIVE_FILENAME /* Open VMS is case insensitive */
+#define SPACE_IN_FILENAME /* There could be space between user and passwd */
+#define FNAME_ILLEGAL "|*#?%" /* Illegal characters in a file name */
+#define BINARY_FILE_IO /* Use binary fileio */
+#define USE_GETCWD
+#define USE_SYSTEM
+#define XPMATTRIBUTES_TYPE XpmAttributes
+
+/* Define when terminfo support found */
+#undef TERMINFO
+
+/* Define when termcap.h contains ospeed */
+/* #define HAVE_OSPEED */
+
+/* Define when termcap.h contains UP, BC and PC */
+/* #define HAVE_UP_BC_PC */
+
+/* Define when termcap.h defines outfuntype */
+/*#define HAVE_OUTFUNTYPE */
+
+/* Define when __DATE__ " " __TIME__ can be used */
+#define HAVE_DATE_TIME
+
+/* Defined to the size of an int */
+#define VIM_SIZEOF_INT 4
+
+/* #undef USEBCOPY */
+#define USEMEMMOVE
+/* #undef USEMEMCPY */
+
+/* Define when "man -s 2" is to be used */
+/* #undef USEMAN_S */
+
+/* Define to empty if the keyword does not work. */
+/* #undef const */
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+/* #undef mode_t */
+
+/* Define to `long' if <sys/types.h> doesn't define. */
+/* #undef off_t */
+
+/* Define to `long' if <sys/types.h> doesn't define. */
+/* #undef pid_t */
+
+/* Define to `unsigned' if <sys/types.h> doesn't define. */
+/* #undef size_t */
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+/* #undef uid_t */
+
+/* Define to `unsigned int' or other type that is 32 bit. */
+#define UINT32_T unsigned int
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+/* #undef gid_t */
+
+/* Define to `long' if <sys/types.h> doesn't define. */
+/* #undef ino_t */
+
+/* Define if you have the nanosleep() function. */
+/* #undef HAVE_NANOSLEEP */
+
+/* Define if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME
+
+/* Define if you can safely include both <sys/time.h> and <sys/select.h>. */
+/* #undef SYS_SELECT_WITH_SYS_TIME */
+
+/* Define as the return type of signal handlers (int or void). */
+#define RETSIGTYPE void
+
+/* Define as the command at the end of signal handlers ("" or "return 0;"). */
+#define SIGRETURN return
+
+/* Define if struct sigcontext is present */
+#define HAVE_SIGCONTEXT
+
+/* Define if toupper/tolower only work on lower/uppercase characters */
+/* #define BROKEN_TOUPPER */
+
+/* Define if tgetstr() has a second argument that is (char *) */
+/* #undef TGETSTR_CHAR_P */
+
+/* Define if you have the sigset() function. */
+/* #undef HAVE_SIGSET */
+
+/* Define if you have the setpgid() function. */
+/* #undef HAVE_SETPGID */
+
+/* Define if you have the setsid() function. */
+/* #undef HAVE_SETSID */
+
+/* Define if you have the sigset() function. */
+/* #undef HAVE_SIGSET */
+
+#define TGETENT_ZERO_ERR
+#define HAVE_GETCWD
+#define HAVE_STRCSPN
+#define HAVE_STRTOL
+#define HAVE_TGETENT
+#define HAVE_MEMSET
+#define HAVE_STRERROR
+#define HAVE_FCHOWN
+#define HAVE_RENAME
+#define HAVE_QSORT
+#define HAVE_FSYNC
+#define HAVE_GETPWUID
+#define HAVE_GETPWNAM
+#define HAVE_STDLIB_H
+#define HAVE_STRING_H
+#define HAVE_ERRNO_H
+#define HAVE_OPENDIR
+#define HAVE_PUTENV
+#define HAVE_SETENV
+#define HAVE_SETJMP_H
+#define HAVE_MATH_H
+#define HAVE_FLOAT_FUNCS
+#define HAVE_GETTIMEOFDAY
+#define HAVE_PWD_H
+#define HAVE_NETDB_H
+#define HAVE_DIRENT_H
+
+#undef HAVE_SYS_NDIR_H
+#undef HAVE_SYS_DIR_H
+#undef HAVE_NDIR_H
+#undef HAVE_SYS_WAIT_H
+#undef HAVE_UNION_WAIT
+#undef HAVE_SYS_SELECT_H
+#undef HAVE_SYS_UTSNAME_H
+#undef HAVE_SYS_SYSTEMINFO_H
+#undef HAVE_TERMCAP_H
+#undef HAVE_SGTTY_H
+#undef HAVE_SYS_IOCTL_H
+#undef HAVE_TERMIO_H
+#undef HAVE_STROPTS_H
+#undef HAVE_SYS_STREAM_H
+#undef HAVE_SYS_PTEM_H
+#undef HAVE_TERMIOS_H
+#undef HAVE_LIBC_H
+#undef HAVE_SYS_STATFS_H
+#undef HAVE_SYS_POLL_H
+#undef HAVE_FCHDIR
+#undef HAVE_LSTAT
+
+/* Hardware specific */
+#ifdef VAX
+#undef HAVE_GETTIMEOFDAY
+#undef HAVE_USLEEP
+#undef HAVE_STRCASECMP
+#undef HAVE_STRINGS_H
+#undef HAVE_SIGSETJMP
+#undef HAVE_ISNAN
+#define HAVE_NO_LONG_LONG
+#define VIM_SIZEOF_LONG 4
+#else /* AXP and IA64 */
+#define HAVE_GETTIMEOFDAY
+#define HAVE_USLEEP
+#define HAVE_STRCASECMP
+#define HAVE_STRINGS_H
+#define HAVE_SIGSETJMP
+#define HAVE_ISNAN
+#define VIM_SIZEOF_LONG 8
+#endif
+
+/* Compiler specific */
+#ifdef VAXC
+#undef HAVE_SELECT
+#undef HAVE_FCNTL_H
+#undef HAVE_UNISTD_H
+#undef HAVE_SYS_TIME_H
+#undef HAVE_LOCALE_H
+#define BROKEN_LOCALE
+#undef DYNAMIC_ICONV
+#undef HAVE_STRFTIME
+#else
+#define HAVE_SELECT
+#define HAVE_FCNTL_H
+#define HAVE_UNISTD_H 1
+#define HAVE_SYS_TIME_H
+#define HAVE_LOCALE_H
+#define BROKEN_LOCALE
+#undef DYNAMIC_ICONV
+#define HAVE_STRFTIME
+#endif
+
+#if defined(USE_ICONV)
+#define HAVE_ICONV_H
+#define HAVE_ICONV
+#else
+#undef HAVE_ICONV_H
+#undef HAVE_ICONV
+#endif
+
+/* GUI support defines */
+#if defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_GTK)
+#define HAVE_X11
+#ifdef HAVE_XPM
+#define HAVE_X11_XPM_H
+#endif
+#define USE_FONTSET
+#undef X_LOCALE
+#endif
diff --git a/src/os_vms_fix.com b/src/os_vms_fix.com
new file mode 100644
index 0000000..5dd4d2b
--- /dev/null
+++ b/src/os_vms_fix.com
@@ -0,0 +1,276 @@
+$!
+$! OS_VMS_FIX.COM
+$! Copyright (C) 2000, Stephen P. Wall
+$!
+$! Filter files for "#if" line continuations using a '\' and convert
+$! them to use comments for the continuation. Necessary for VAXC - it
+$! doesn't understand the '\'.
+$!
+$! Yes, this is honkin' ugly code, but I deliberately avoided
+$! if ...
+$! then
+$! ....
+$! endif
+$! and call/subroutine/endsubroutine constructs, because I can still
+$! remember when DCL didn't have them, and I wanted this to be as
+$! portable as possible, so... If you want to structure it nicer for
+$! your own use, please feel free to do so. However, please only
+$! distribute it in its original form.
+$!
+$! I wrote it in DCL for portability and ease of use - a C version
+$! would definitely run faster, but then I'd have to deal with compiler
+$! differences, and users would have to deal with configuring and
+$! building it. With DCL, it runs out-of-the-box.
+$!
+$! Note that if you use this from a VMS system to modify files on a
+$! mounted network drive, f$search() may return only the first matching
+$! file when it tries to resolve wildcards. I have been unable to find
+$! a way around this. Either copy the files to a local disk, or specify
+$! each file individually (Keep in mind if you do this that VMS limits
+$! you to eight parameters, so you'll only be able to filter eight files
+$! at a time).
+$!
+$! Ideas...
+$! - Use 'search filespec "#","if","\"/mat=and' to quickly eliminate
+$! files that definitely don't need filtering. This should speed
+$! things up considerable. Reading and writing every line from every
+$! file takes quite a bit of time...
+$! - Error handling isn't great. Come up with something better....
+$!
+$! E-mail addresses:
+$! Steve Wall hitched97@velnet.com
+$! Zoltan Arpadffy arpadffy@polarhome.com
+$! John W. Hamill jhamill3@ford.com
+$!
+$! Modification History:
+$! 13Jul00 SWall Initial Version
+$! 14Jul00 ZArpadffy Display usage
+$! 06Mar01 JHamill Ctrl-M problem fix
+$!
+$! If no parameters, or "-h" for a parameter, print usage and exit
+$
+$ all = "''p1'''p2'''p3'''p4'''p5'''p6'''p7'''p8'"
+$ if (all .nes. "") .and. (p1 .nes. "-h") .and. (p1 .nes. "-H") then goto startup
+$
+$ write sys$output "OS_VMS_FIX - DECC->VAXC pre-processor directive convert script"
+$ write sys$output "Usage: @OS_VMS_FIX <filename_1> <filename_2> <...>"
+$ write sys$output " @OS_VMS_FIX <filename with wildcard> <...>"
+$ write sys$output ""
+$ write sys$output "Example: @OS_VMS_FIX *.c *.h [.proto]*.pro"
+$ write sys$output "Please note, you can define up to 8 parameters."
+$ write sys$output ""
+$ exit
+$
+$! Create an FDL file to convert VFC format files to Stream_LF.
+$! VMS OPEN/WRITE command creates VFC files. When VFC files are read
+$! out under unix, they appear to have binary data embedded in them.
+$! To be friendly, we'll convert them to Stream_LF, which reads just
+$! file on unix.
+$
+$startup:
+$ on control_y then goto stopfdl
+$ open/write fdl []convert.fdl
+$ write fdl "SYSTEM"
+$ write fdl " SOURCE VAX/VMS"
+$ write fdl "FILE"
+$ write fdl " ORGANIZATION SEQUENTIAL"
+$ write fdl "RECORD"
+$ write fdl " BLOCK_SPAN YES"
+$ write fdl " CARRIAGE_CONTROL CARRIAGE_RETURN"
+$ write fdl " FORMAT STREAM"
+$ write fdl " SIZE 0"
+$ close fdl
+$ on control_y then goto endparamloop
+$
+$! Some symbols for use later on...
+$
+$ spc = ""
+$ spc[0,8] = 32
+$ tab = ""
+$ tab[0,8] = 9
+$
+$! Scan all positional arguments, do wildcard expansion, and call the
+$! filter routine on each resulting filename.
+$
+$ cnt = 0
+$paramloop:
+$ cnt = cnt + 1
+$
+$! VMS only allows command line parameters P1 - P8, so stop after
+$! processing 8 arguments.
+$
+$ if cnt .eq. 9 then goto endparamloop
+$
+$! Skip any empty parameter.
+$
+$ if P'cnt' .eqs. "" then goto paramloop
+$
+$! Got a parameter - do wildcard expansion.
+$
+$ arg = f$parse(P'cnt')
+$ write sys$output "Parsing ''arg'..."
+$ last = ""
+$fileloop:
+$ file = f$search(arg, 1)
+$
+$! f$search() returns "" after the last of multiple matches.
+$
+$ if file .eqs. "" then goto endfileloop
+$
+$! Strip the version number.
+$
+$ file = f$parse(file,,,"DEVICE") + f$parse(file,,,"DIRECTORY") + -
+ f$parse(file,,,"NAME") + f$parse(file,,,"TYPE")
+$
+$! f$search() returns the same filename over and over if there are no
+$! wildcards in it.
+$
+$ if file .eqs. last then goto endfileloop
+$ last = file
+$
+$! Got a valid file - filter it.
+$
+$ gosub filter
+$
+$! Reset our error handling.
+$
+$ on control_y then goto endparamloop
+$
+$! See if there's another matching filename.
+$
+$ goto fileloop
+$endfileloop:
+$
+$! Check for another parameter.
+$
+$ goto paramloop
+$endparamloop:
+$
+$! Finished - delete the FDL file.
+$
+$ delete []convert.fdl;
+$
+$! So long, and thanks for all the fish...
+$
+$ exit
+$
+$
+$! User aborted with Control-Y during creation of FDL file.
+$! Close the file, delete it, and exit with an error status.
+$
+$stopfdl:
+$ close fdl
+$ delete []convert.fdl;
+$ exit %X10000000
+$
+$
+$! Filter a file.
+$
+$filter:
+$ write sys$output "Filtering ''file'..."
+$
+$! Get a temporary filename from the subroutine parameter.
+$
+$ tmp = f$parse(file,,,"DEVICE") + f$parse(file,,,"DIRECTORY") + -
+ "tmp_" + f$parse(file,,,"NAME") + f$parse(file,,,"TYPE")
+$ on control_y then goto aborted
+$ open /read input 'file'
+$ open /write output 'tmp'
+$ changed = 0
+$readloop:
+$ read/end_of_file=endreadloop/error=readlooperror input line
+$
+$! Get the first 3 non-blank character on the line.
+$
+$ start = f$extract(0,3,f$edit(line,"COLLAPSE,LOWERCASE"))
+$
+$! If the line doesn't start with some form of "#if", just write it to
+$! the temp file.
+$
+$ if start .nes. "#if" then goto writeit
+$chkbkslsh:
+$
+$! See if the line ends in a backslash. If not, write it to the temp file.
+$
+$ if f$extract(f$length(line)-1,1,line) .nes. "\" then goto writeit
+$
+$! Ok, got a line that needs to be modified. Mark this file as changed,
+$! then replace the backslash at the end with the beginning of a comment
+$! (/*), and write it to the temp file.
+$
+$ changed = 1
+$ line = f$extract(0,f$length(line)-1,line) + "/*"
+$ write/symbol output line
+$
+$! Get another line from the input.
+$
+$ read/end_of_file=endreadloop/error=readlooperror input line
+$
+$! Grab all the blank space from the beginning of the line.
+$
+$ spaces = ""
+$spaceloop:
+$ if (f$extract(0,1,line) .nes. spc) .and. (f$extract(0,1,line) .nes. tab) -
+ then goto endspaceloop
+$ spaces = spaces + f$extract(0,1,line)
+$ line = f$extract(1,f$length(line)-1,line)
+$ goto spaceloop
+$endspaceloop:
+$
+$! Stick an end-comment (*/) after the leading blanks, then go back and
+$! check for a trailing backslash again, to catch code that continues
+$! across multiple lines.
+$
+$ line = spaces + "*/ " + line
+$ goto chkbkslsh
+$
+$! Write the current line, (will either be an untouched line, or the
+$! last line of a continuation) to the temp file, and go back to look
+$! for more input.
+$!
+$writeit:
+$ write/symbol output line
+$ goto readloop
+$
+$! Hit EOF. Close the input & output, and if the file was marked as
+$! changed, convert it from VMS VFC format, to the more common Stream_LF
+$! format, so it doesn't show up full of garbage if someone tries to
+$! edit it on another OS.
+$!
+$endreadloop:
+$ close input
+$ close output
+$ if changed .eq. 0 then goto nocopy
+$ convert 'tmp' 'file' /fdl=[]convert.fdl
+$nocopy:
+$ delete 'tmp';
+$
+$! Exit this subroutine.
+$
+$ goto endfunc
+$
+$! Got a read error. Say so, and trash the temp file.
+$
+$readlooperror:
+$ write sys$error "Error processing file ''file'"
+$ goto errorend
+$
+$! Got an interrupt. Say so, and trash the temp file.
+$
+$aborted:
+$ write sys$error "Aborted while processing file ''file'"
+$
+$! Common code for read errors and interrupts.
+$
+$errorend:
+$ close input
+$ close output
+$ delete 'tmp';
+$ return %X10000000
+$
+$! End of filter subroutine.
+$
+$endfunc:
+$ return
+$
+$! EOF
diff --git a/src/os_vms_mms.c b/src/os_vms_mms.c
new file mode 100644
index 0000000..4da7b1a
--- /dev/null
+++ b/src/os_vms_mms.c
@@ -0,0 +1,77 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unixio.h>
+#include "vim.h"
+int main(int argc, char *argv[])
+{
+ FILE *fpi, *fpo;
+ char cmd[132], buf[BUFSIZ], *argp, *error_file, target[132], *mms;
+ int err = 0, err_line = 0;
+
+ mms = "mms";
+ argc--;
+ argv++;
+ while (argc-- > 0)
+ {
+ argp = *argv++;
+ if (*argp == '-')
+ {
+ switch (*++argp)
+ {
+ case 'm':
+ mms = ++argp;
+ break;
+ case 'e':
+ if (!*(error_file = ++argp))
+ {
+ error_file = *argv++;
+ argc--;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ if (*target)
+ strcat(target, " ");
+ strcat(target, argp);
+ }
+ }
+ vim_snprintf(cmd, sizeof(cmd), "%s/output=tmp:errors.vim_tmp %s",
+ mms, target);
+ system(cmd);
+ fpi = fopen("tmp:errors.vim_tmp", "r");
+ fpo = fopen(error_file, "w");
+ while (fgets(buf, BUFSIZ, fpi))
+ {
+ if (!memcmp(buf, "%CC-", 4))
+ {
+ err_line++;
+ buf[strlen(buf)-1] = '\0';
+ err++;
+ }
+ else
+ {
+ if (err_line)
+ {
+ if (strstr(buf, _("At line")))
+ {
+ err_line = 0;
+ fprintf(fpo, "@");
+ }
+ else
+ buf[strlen(buf)-1] = '\0';
+ }
+ }
+ fprintf(fpo, "%s", buf);
+ }
+ fclose(fpi);
+ fclose(fpo);
+ while (!delete("tmp:errors.vim_tmp"))
+ /*nop*/;
+ exit(err ? 44 : 1);
+ return(0);
+}
diff --git a/src/os_w32dll.c b/src/os_w32dll.c
new file mode 100644
index 0000000..5b94400
--- /dev/null
+++ b/src/os_w32dll.c
@@ -0,0 +1,24 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ * GUI support by Robert Webb
+ *
+ * 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.
+ */
+/*
+ * Windows GUI: main program (DLL) entry point:
+ *
+ * Ron Aaron <ronaharon@yahoo.com> wrote this and the DLL support code.
+ */
+#ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+
+BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+ return TRUE;
+}
+
diff --git a/src/os_w32exe.c b/src/os_w32exe.c
new file mode 100644
index 0000000..f96bff4
--- /dev/null
+++ b/src/os_w32exe.c
@@ -0,0 +1,137 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ * GUI support by Robert Webb
+ *
+ * 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.
+ */
+/*
+ * Windows GUI: main program (EXE) entry point:
+ *
+ * Ron Aaron <ronaharon@yahoo.com> wrote this and the DLL support code.
+ */
+#include "vim.h"
+
+#ifdef __MINGW32__
+# ifndef _cdecl
+# define _cdecl
+# endif
+#endif
+
+/* cproto doesn't create a prototype for main() */
+int _cdecl
+#if defined(FEAT_GUI_W32)
+VimMain
+#else
+ main
+#endif
+ (int argc, char **argv);
+static int (_cdecl *pmain)(int, char **);
+
+#ifndef PROTO
+#ifdef FEAT_GUI
+#ifndef VIMDLL
+void _cdecl SaveInst(HINSTANCE hInst);
+#endif
+static void (_cdecl *pSaveInst)(HINSTANCE);
+#endif
+
+ int WINAPI
+WinMain(
+ HINSTANCE hInstance UNUSED,
+ HINSTANCE hPrevInst UNUSED,
+ LPSTR lpszCmdLine,
+ int nCmdShow UNUSED)
+{
+ int argc = 0;
+ char **argv;
+ char *tofree;
+ char prog[256];
+#ifdef VIMDLL
+ char *p;
+ HANDLE hLib;
+#endif
+
+ /* Ron: added full path name so that the $VIM variable will get set to our
+ * startup path (so the .vimrc file can be found w/o a VIM env. var.) */
+ GetModuleFileName(NULL, prog, 255);
+
+ argc = get_cmd_args(prog, (char *)lpszCmdLine, &argv, &tofree);
+ if (argc == 0)
+ {
+ MessageBox(0, "Could not allocate memory for command line.",
+ "VIM Error", 0);
+ return 0;
+ }
+
+#ifdef DYNAMIC_GETTEXT
+ /* Initialize gettext library */
+ dyn_libintl_init();
+#endif
+
+#ifdef VIMDLL
+ // LoadLibrary - get name of dll to load in here:
+ p = strrchr(prog, '\\');
+ if (p != NULL)
+ {
+# ifdef DEBUG
+ strcpy(p+1, "vim32d.dll");
+# else
+ strcpy(p+1, "vim32.dll");
+# endif
+ }
+ hLib = LoadLibrary(prog);
+ if (hLib == NULL)
+ {
+ MessageBox(0, _("Could not load vim32.dll!"), _("VIM Error"), 0);
+ goto errout;
+ }
+ // fix up the function pointers
+# ifdef FEAT_GUI
+ pSaveInst = GetProcAddress(hLib, (LPCSTR)2);
+# endif
+ pmain = GetProcAddress(hLib, (LPCSTR)1);
+ if (pmain == NULL)
+ {
+ MessageBox(0, _("Could not fix up function pointers to the DLL!"),
+ _("VIM Error"),0);
+ goto errout;
+ }
+#else
+# ifdef FEAT_GUI
+ pSaveInst = SaveInst;
+# endif
+ pmain =
+# if defined(FEAT_GUI_W32)
+ //&& defined(__MINGW32__)
+ VimMain
+# else
+ main
+# endif
+ ;
+#endif
+#ifdef FEAT_GUI
+ pSaveInst(
+#ifdef __MINGW32__
+ GetModuleHandle(NULL)
+#else
+ hInstance
+#endif
+ );
+#endif
+ pmain(argc, argv);
+
+#ifdef VIMDLL
+ FreeLibrary(hLib);
+errout:
+#endif
+ free(argv);
+ if (tofree != NULL)
+ free(tofree);
+ free_cmd_argsW();
+
+ return 0;
+}
+#endif
diff --git a/src/os_win32.c b/src/os_win32.c
new file mode 100644
index 0000000..10ca418
--- /dev/null
+++ b/src/os_win32.c
@@ -0,0 +1,7880 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+/*
+ * os_win32.c
+ *
+ * Used for both the console version and the Win32 GUI. A lot of code is for
+ * the console version only, so there is a lot of "#ifndef FEAT_GUI_W32".
+ *
+ * Win32 (Windows NT and Windows 95) system-dependent routines.
+ * Portions lifted from the Win32 SDK samples, the MSDOS-dependent code,
+ * NetHack 3.1.3, GNU Emacs 19.30, and Vile 5.5.
+ *
+ * George V. Reilly <george@reilly.org> wrote most of this.
+ * Roger Knobbe <rogerk@wonderware.com> did the initial port of Vim 3.0.
+ */
+
+#include "vim.h"
+
+#ifdef FEAT_MZSCHEME
+# include "if_mzsch.h"
+#endif
+
+#include <sys/types.h>
+#include <signal.h>
+#include <limits.h>
+
+/* cproto fails on missing include files */
+#ifndef PROTO
+# include <process.h>
+#endif
+
+#undef chdir
+#ifdef __GNUC__
+# ifndef __MINGW32__
+# include <dirent.h>
+# endif
+#else
+# include <direct.h>
+#endif
+
+#ifndef PROTO
+# if defined(FEAT_TITLE) && !defined(FEAT_GUI_W32)
+# include <shellapi.h>
+# endif
+#endif
+
+#ifdef FEAT_JOB_CHANNEL
+# include <tlhelp32.h>
+#endif
+
+#ifdef __MINGW32__
+# ifndef FROM_LEFT_1ST_BUTTON_PRESSED
+# define FROM_LEFT_1ST_BUTTON_PRESSED 0x0001
+# endif
+# ifndef RIGHTMOST_BUTTON_PRESSED
+# define RIGHTMOST_BUTTON_PRESSED 0x0002
+# endif
+# ifndef FROM_LEFT_2ND_BUTTON_PRESSED
+# define FROM_LEFT_2ND_BUTTON_PRESSED 0x0004
+# endif
+# ifndef FROM_LEFT_3RD_BUTTON_PRESSED
+# define FROM_LEFT_3RD_BUTTON_PRESSED 0x0008
+# endif
+# ifndef FROM_LEFT_4TH_BUTTON_PRESSED
+# define FROM_LEFT_4TH_BUTTON_PRESSED 0x0010
+# endif
+
+/*
+ * EventFlags
+ */
+# ifndef MOUSE_MOVED
+# define MOUSE_MOVED 0x0001
+# endif
+# ifndef DOUBLE_CLICK
+# define DOUBLE_CLICK 0x0002
+# endif
+#endif
+
+/* Record all output and all keyboard & mouse input */
+/* #define MCH_WRITE_DUMP */
+
+#ifdef MCH_WRITE_DUMP
+FILE* fdDump = NULL;
+#endif
+
+/*
+ * When generating prototypes for Win32 on Unix, these lines make the syntax
+ * errors disappear. They do not need to be correct.
+ */
+#ifdef PROTO
+#define WINAPI
+typedef char * LPCSTR;
+typedef char * LPWSTR;
+typedef int ACCESS_MASK;
+typedef int BOOL;
+typedef int COLORREF;
+typedef int CONSOLE_CURSOR_INFO;
+typedef int COORD;
+typedef int DWORD;
+typedef int HANDLE;
+typedef int LPHANDLE;
+typedef int HDC;
+typedef int HFONT;
+typedef int HICON;
+typedef int HINSTANCE;
+typedef int HWND;
+typedef int INPUT_RECORD;
+typedef int INT;
+typedef int KEY_EVENT_RECORD;
+typedef int LOGFONT;
+typedef int LPBOOL;
+typedef int LPCTSTR;
+typedef int LPDWORD;
+typedef int LPSTR;
+typedef int LPTSTR;
+typedef int LPVOID;
+typedef int MOUSE_EVENT_RECORD;
+typedef int PACL;
+typedef int PDWORD;
+typedef int PHANDLE;
+typedef int PRINTDLG;
+typedef int PSECURITY_DESCRIPTOR;
+typedef int PSID;
+typedef int SECURITY_INFORMATION;
+typedef int SHORT;
+typedef int SMALL_RECT;
+typedef int TEXTMETRIC;
+typedef int TOKEN_INFORMATION_CLASS;
+typedef int TRUSTEE;
+typedef int WORD;
+typedef int WCHAR;
+typedef void VOID;
+typedef int BY_HANDLE_FILE_INFORMATION;
+typedef int SE_OBJECT_TYPE;
+typedef int PSNSECINFO;
+typedef int PSNSECINFOW;
+typedef int STARTUPINFO;
+typedef int PROCESS_INFORMATION;
+typedef int LPSECURITY_ATTRIBUTES;
+# define __stdcall /* empty */
+#endif
+
+#if defined(__BORLANDC__)
+/* Strangely Borland uses a non-standard name. */
+# define wcsicmp(a, b) wcscmpi((a), (b))
+#endif
+
+#ifndef FEAT_GUI_W32
+/* Win32 Console handles for input and output */
+static HANDLE g_hConIn = INVALID_HANDLE_VALUE;
+static HANDLE g_hConOut = INVALID_HANDLE_VALUE;
+
+/* Win32 Screen buffer,coordinate,console I/O information */
+static SMALL_RECT g_srScrollRegion;
+static COORD g_coord; /* 0-based, but external coords are 1-based */
+
+/* The attribute of the screen when the editor was started */
+static WORD g_attrDefault = 7; /* lightgray text on black background */
+static WORD g_attrCurrent;
+
+static int g_fCBrkPressed = FALSE; /* set by ctrl-break interrupt */
+static int g_fCtrlCPressed = FALSE; /* set when ctrl-C or ctrl-break detected */
+static int g_fForceExit = FALSE; /* set when forcefully exiting */
+
+static void scroll(unsigned cLines);
+static void set_scroll_region(unsigned left, unsigned top,
+ unsigned right, unsigned bottom);
+static void delete_lines(unsigned cLines);
+static void gotoxy(unsigned x, unsigned y);
+static void standout(void);
+static int s_cursor_visible = TRUE;
+static int did_create_conin = FALSE;
+#else
+static int s_dont_use_vimrun = TRUE;
+static int need_vimrun_warning = FALSE;
+static char *vimrun_path = "vimrun ";
+#endif
+
+static int win32_getattrs(char_u *name);
+static int win32_setattrs(char_u *name, int attrs);
+static int win32_set_archive(char_u *name);
+
+static int vtp_working = 0;
+static void vtp_flag_init();
+
+#ifndef FEAT_GUI_W32
+static void vtp_init();
+static void vtp_exit();
+static int vtp_printf(char *format, ...);
+static void vtp_sgr_bulk(int arg);
+static void vtp_sgr_bulks(int argc, int *argv);
+
+static guicolor_T save_console_bg_rgb;
+static guicolor_T save_console_fg_rgb;
+
+static int g_color_index_bg = 0;
+static int g_color_index_fg = 7;
+
+# ifdef FEAT_TERMGUICOLORS
+static int default_console_color_bg = 0x000000; // black
+static int default_console_color_fg = 0xc0c0c0; // white
+# endif
+
+# ifdef FEAT_TERMGUICOLORS
+# define USE_VTP (vtp_working && is_term_win32() && (p_tgc || (!p_tgc && t_colors >= 256)))
+# else
+# define USE_VTP 0
+# endif
+
+static void set_console_color_rgb(void);
+static void reset_console_color_rgb(void);
+#endif
+
+/* This flag is newly created from Windows 10 */
+#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
+# define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
+#endif
+
+#ifndef FEAT_GUI_W32
+static int suppress_winsize = 1; /* don't fiddle with console */
+#endif
+
+static char_u *exe_path = NULL;
+
+static BOOL win8_or_later = FALSE;
+
+#ifndef FEAT_GUI_W32
+/* Dynamic loading for portability */
+typedef struct _DYN_CONSOLE_SCREEN_BUFFER_INFOEX
+{
+ ULONG cbSize;
+ COORD dwSize;
+ COORD dwCursorPosition;
+ WORD wAttributes;
+ SMALL_RECT srWindow;
+ COORD dwMaximumWindowSize;
+ WORD wPopupAttributes;
+ BOOL bFullscreenSupported;
+ COLORREF ColorTable[16];
+} DYN_CONSOLE_SCREEN_BUFFER_INFOEX, *PDYN_CONSOLE_SCREEN_BUFFER_INFOEX;
+typedef BOOL (WINAPI *PfnGetConsoleScreenBufferInfoEx)(HANDLE, PDYN_CONSOLE_SCREEN_BUFFER_INFOEX);
+static PfnGetConsoleScreenBufferInfoEx pGetConsoleScreenBufferInfoEx;
+typedef BOOL (WINAPI *PfnSetConsoleScreenBufferInfoEx)(HANDLE, PDYN_CONSOLE_SCREEN_BUFFER_INFOEX);
+static PfnSetConsoleScreenBufferInfoEx pSetConsoleScreenBufferInfoEx;
+static BOOL has_csbiex = FALSE;
+#endif
+
+/*
+ * Get version number including build number
+ */
+typedef BOOL (WINAPI *PfnRtlGetVersion)(LPOSVERSIONINFOW);
+# define MAKE_VER(major, minor, build) \
+ (((major) << 24) | ((minor) << 16) | (build))
+
+ static DWORD
+get_build_number(void)
+{
+ OSVERSIONINFOW osver = {sizeof(OSVERSIONINFOW)};
+ HMODULE hNtdll;
+ PfnRtlGetVersion pRtlGetVersion;
+ DWORD ver = MAKE_VER(0, 0, 0);
+
+ hNtdll = GetModuleHandle("ntdll.dll");
+ if (hNtdll != NULL)
+ {
+ pRtlGetVersion =
+ (PfnRtlGetVersion)GetProcAddress(hNtdll, "RtlGetVersion");
+ pRtlGetVersion(&osver);
+ ver = MAKE_VER(min(osver.dwMajorVersion, 255),
+ min(osver.dwMinorVersion, 255),
+ min(osver.dwBuildNumber, 32767));
+ }
+ return ver;
+}
+
+#ifndef FEAT_GUI_W32
+/*
+ * Version of ReadConsoleInput() that works with IME.
+ * Works around problems on Windows 8.
+ */
+ static BOOL
+read_console_input(
+ HANDLE hInput,
+ INPUT_RECORD *lpBuffer,
+ DWORD nLength,
+ LPDWORD lpEvents)
+{
+ enum
+ {
+ IRSIZE = 10
+ };
+ static INPUT_RECORD s_irCache[IRSIZE];
+ static DWORD s_dwIndex = 0;
+ static DWORD s_dwMax = 0;
+ DWORD dwEvents;
+ int head;
+ int tail;
+ int i;
+
+ if (nLength == -2)
+ return (s_dwMax > 0) ? TRUE : FALSE;
+
+ if (!win8_or_later)
+ {
+ if (nLength == -1)
+ return PeekConsoleInputW(hInput, lpBuffer, 1, lpEvents);
+ return ReadConsoleInputW(hInput, lpBuffer, 1, &dwEvents);
+ }
+
+ if (s_dwMax == 0)
+ {
+ if (nLength == -1)
+ return PeekConsoleInputW(hInput, lpBuffer, 1, lpEvents);
+ if (!ReadConsoleInputW(hInput, s_irCache, IRSIZE, &dwEvents))
+ return FALSE;
+ s_dwIndex = 0;
+ s_dwMax = dwEvents;
+ if (dwEvents == 0)
+ {
+ *lpEvents = 0;
+ return TRUE;
+ }
+
+ if (s_dwMax > 1)
+ {
+ head = 0;
+ tail = s_dwMax - 1;
+ while (head != tail)
+ {
+ if (s_irCache[head].EventType == WINDOW_BUFFER_SIZE_EVENT
+ && s_irCache[head + 1].EventType
+ == WINDOW_BUFFER_SIZE_EVENT)
+ {
+ /* Remove duplicate event to avoid flicker. */
+ for (i = head; i < tail; ++i)
+ s_irCache[i] = s_irCache[i + 1];
+ --tail;
+ continue;
+ }
+ head++;
+ }
+ s_dwMax = tail + 1;
+ }
+ }
+
+ *lpBuffer = s_irCache[s_dwIndex];
+ if (!(nLength == -1 || nLength == -2) && ++s_dwIndex >= s_dwMax)
+ s_dwMax = 0;
+ *lpEvents = 1;
+ return TRUE;
+}
+
+/*
+ * Version of PeekConsoleInput() that works with IME.
+ */
+ static BOOL
+peek_console_input(
+ HANDLE hInput,
+ INPUT_RECORD *lpBuffer,
+ DWORD nLength,
+ LPDWORD lpEvents)
+{
+ return read_console_input(hInput, lpBuffer, -1, lpEvents);
+}
+
+# ifdef FEAT_CLIENTSERVER
+ static DWORD
+msg_wait_for_multiple_objects(
+ DWORD nCount,
+ LPHANDLE pHandles,
+ BOOL fWaitAll,
+ DWORD dwMilliseconds,
+ DWORD dwWakeMask)
+{
+ if (read_console_input(NULL, NULL, -2, NULL))
+ return WAIT_OBJECT_0;
+ return MsgWaitForMultipleObjects(nCount, pHandles, fWaitAll,
+ dwMilliseconds, dwWakeMask);
+}
+# endif
+
+# ifndef FEAT_CLIENTSERVER
+ static DWORD
+wait_for_single_object(
+ HANDLE hHandle,
+ DWORD dwMilliseconds)
+{
+ if (read_console_input(NULL, NULL, -2, NULL))
+ return WAIT_OBJECT_0;
+ return WaitForSingleObject(hHandle, dwMilliseconds);
+}
+# endif
+#endif
+
+ static void
+get_exe_name(void)
+{
+ /* Maximum length of $PATH is more than MAXPATHL. 8191 is often mentioned
+ * as the maximum length that works (plus a NUL byte). */
+#define MAX_ENV_PATH_LEN 8192
+ char temp[MAX_ENV_PATH_LEN];
+ char_u *p;
+
+ if (exe_name == NULL)
+ {
+ /* store the name of the executable, may be used for $VIM */
+ GetModuleFileName(NULL, temp, MAX_ENV_PATH_LEN - 1);
+ if (*temp != NUL)
+ exe_name = FullName_save((char_u *)temp, FALSE);
+ }
+
+ if (exe_path == NULL && exe_name != NULL)
+ {
+ exe_path = vim_strnsave(exe_name,
+ (int)(gettail_sep(exe_name) - exe_name));
+ if (exe_path != NULL)
+ {
+ /* Append our starting directory to $PATH, so that when doing
+ * "!xxd" it's found in our starting directory. Needed because
+ * SearchPath() also looks there. */
+ p = mch_getenv("PATH");
+ if (p == NULL
+ || STRLEN(p) + STRLEN(exe_path) + 2 < MAX_ENV_PATH_LEN)
+ {
+ if (p == NULL || *p == NUL)
+ temp[0] = NUL;
+ else
+ {
+ STRCPY(temp, p);
+ STRCAT(temp, ";");
+ }
+ STRCAT(temp, exe_path);
+ vim_setenv((char_u *)"PATH", (char_u *)temp);
+ }
+ }
+ }
+}
+
+/*
+ * Unescape characters in "p" that appear in "escaped".
+ */
+ static void
+unescape_shellxquote(char_u *p, char_u *escaped)
+{
+ int l = (int)STRLEN(p);
+ int n;
+
+ while (*p != NUL)
+ {
+ if (*p == '^' && vim_strchr(escaped, p[1]) != NULL)
+ mch_memmove(p, p + 1, l--);
+ n = (*mb_ptr2len)(p);
+ p += n;
+ l -= n;
+ }
+}
+
+/*
+ * Load library "name".
+ */
+ HINSTANCE
+vimLoadLib(char *name)
+{
+ HINSTANCE dll = NULL;
+
+ /* NOTE: Do not use mch_dirname() and mch_chdir() here, they may call
+ * vimLoadLib() recursively, which causes a stack overflow. */
+ if (exe_path == NULL)
+ get_exe_name();
+ if (exe_path != NULL)
+ {
+ WCHAR old_dirw[MAXPATHL];
+
+ if (GetCurrentDirectoryW(MAXPATHL, old_dirw) != 0)
+ {
+ /* Change directory to where the executable is, both to make
+ * sure we find a .dll there and to avoid looking for a .dll
+ * in the current directory. */
+ SetCurrentDirectory((LPCSTR)exe_path);
+ dll = LoadLibrary(name);
+ SetCurrentDirectoryW(old_dirw);
+ return dll;
+ }
+ }
+ return dll;
+}
+
+#if defined(DYNAMIC_ICONV) || defined(DYNAMIC_GETTEXT) || defined(PROTO)
+/*
+ * Get related information about 'funcname' which is imported by 'hInst'.
+ * If 'info' is 0, return the function address.
+ * If 'info' is 1, return the module name which the function is imported from.
+ */
+ static void *
+get_imported_func_info(HINSTANCE hInst, const char *funcname, int info)
+{
+ PBYTE pImage = (PBYTE)hInst;
+ PIMAGE_DOS_HEADER pDOS = (PIMAGE_DOS_HEADER)hInst;
+ PIMAGE_NT_HEADERS pPE;
+ PIMAGE_IMPORT_DESCRIPTOR pImpDesc;
+ PIMAGE_THUNK_DATA pIAT; /* Import Address Table */
+ PIMAGE_THUNK_DATA pINT; /* Import Name Table */
+ PIMAGE_IMPORT_BY_NAME pImpName;
+
+ if (pDOS->e_magic != IMAGE_DOS_SIGNATURE)
+ return NULL;
+ pPE = (PIMAGE_NT_HEADERS)(pImage + pDOS->e_lfanew);
+ if (pPE->Signature != IMAGE_NT_SIGNATURE)
+ return NULL;
+ pImpDesc = (PIMAGE_IMPORT_DESCRIPTOR)(pImage
+ + pPE->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
+ .VirtualAddress);
+ for (; pImpDesc->FirstThunk; ++pImpDesc)
+ {
+ if (!pImpDesc->OriginalFirstThunk)
+ continue;
+ pIAT = (PIMAGE_THUNK_DATA)(pImage + pImpDesc->FirstThunk);
+ pINT = (PIMAGE_THUNK_DATA)(pImage + pImpDesc->OriginalFirstThunk);
+ for (; pIAT->u1.Function; ++pIAT, ++pINT)
+ {
+ if (IMAGE_SNAP_BY_ORDINAL(pINT->u1.Ordinal))
+ continue;
+ pImpName = (PIMAGE_IMPORT_BY_NAME)(pImage
+ + (UINT_PTR)(pINT->u1.AddressOfData));
+ if (strcmp((char *)pImpName->Name, funcname) == 0)
+ {
+ switch (info)
+ {
+ case 0:
+ return (void *)pIAT->u1.Function;
+ case 1:
+ return (void *)(pImage + pImpDesc->Name);
+ default:
+ return NULL;
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+/*
+ * Get the module handle which 'funcname' in 'hInst' is imported from.
+ */
+ HINSTANCE
+find_imported_module_by_funcname(HINSTANCE hInst, const char *funcname)
+{
+ char *modulename;
+
+ modulename = (char *)get_imported_func_info(hInst, funcname, 1);
+ if (modulename != NULL)
+ return GetModuleHandleA(modulename);
+ return NULL;
+}
+
+/*
+ * Get the address of 'funcname' which is imported by 'hInst' DLL.
+ */
+ void *
+get_dll_import_func(HINSTANCE hInst, const char *funcname)
+{
+ return get_imported_func_info(hInst, funcname, 0);
+}
+#endif
+
+#if defined(DYNAMIC_GETTEXT) || defined(PROTO)
+# ifndef GETTEXT_DLL
+# define GETTEXT_DLL "libintl.dll"
+# define GETTEXT_DLL_ALT1 "libintl-8.dll"
+# define GETTEXT_DLL_ALT2 "intl.dll"
+# endif
+/* Dummy functions */
+static char *null_libintl_gettext(const char *);
+static char *null_libintl_ngettext(const char *, const char *, unsigned long n);
+static char *null_libintl_textdomain(const char *);
+static char *null_libintl_bindtextdomain(const char *, const char *);
+static char *null_libintl_bind_textdomain_codeset(const char *, const char *);
+static int null_libintl_putenv(const char *);
+static int null_libintl_wputenv(const wchar_t *);
+
+static HINSTANCE hLibintlDLL = NULL;
+char *(*dyn_libintl_gettext)(const char *) = null_libintl_gettext;
+char *(*dyn_libintl_ngettext)(const char *, const char *, unsigned long n)
+ = null_libintl_ngettext;
+char *(*dyn_libintl_textdomain)(const char *) = null_libintl_textdomain;
+char *(*dyn_libintl_bindtextdomain)(const char *, const char *)
+ = null_libintl_bindtextdomain;
+char *(*dyn_libintl_bind_textdomain_codeset)(const char *, const char *)
+ = null_libintl_bind_textdomain_codeset;
+int (*dyn_libintl_putenv)(const char *) = null_libintl_putenv;
+int (*dyn_libintl_wputenv)(const wchar_t *) = null_libintl_wputenv;
+
+ int
+dyn_libintl_init(void)
+{
+ int i;
+ static struct
+ {
+ char *name;
+ FARPROC *ptr;
+ } libintl_entry[] =
+ {
+ {"gettext", (FARPROC*)&dyn_libintl_gettext},
+ {"ngettext", (FARPROC*)&dyn_libintl_ngettext},
+ {"textdomain", (FARPROC*)&dyn_libintl_textdomain},
+ {"bindtextdomain", (FARPROC*)&dyn_libintl_bindtextdomain},
+ {NULL, NULL}
+ };
+ HINSTANCE hmsvcrt;
+
+ // No need to initialize twice.
+ if (hLibintlDLL != NULL)
+ return 1;
+ // Load gettext library (libintl.dll and other names).
+ hLibintlDLL = vimLoadLib(GETTEXT_DLL);
+#ifdef GETTEXT_DLL_ALT1
+ if (!hLibintlDLL)
+ hLibintlDLL = vimLoadLib(GETTEXT_DLL_ALT1);
+#endif
+#ifdef GETTEXT_DLL_ALT2
+ if (!hLibintlDLL)
+ hLibintlDLL = vimLoadLib(GETTEXT_DLL_ALT2);
+#endif
+ if (!hLibintlDLL)
+ {
+ if (p_verbose > 0)
+ {
+ verbose_enter();
+ semsg(_(e_loadlib), GETTEXT_DLL);
+ verbose_leave();
+ }
+ return 0;
+ }
+ for (i = 0; libintl_entry[i].name != NULL
+ && libintl_entry[i].ptr != NULL; ++i)
+ {
+ if ((*libintl_entry[i].ptr = (FARPROC)GetProcAddress(hLibintlDLL,
+ libintl_entry[i].name)) == NULL)
+ {
+ dyn_libintl_end();
+ if (p_verbose > 0)
+ {
+ verbose_enter();
+ semsg(_(e_loadfunc), libintl_entry[i].name);
+ verbose_leave();
+ }
+ return 0;
+ }
+ }
+
+ /* The bind_textdomain_codeset() function is optional. */
+ dyn_libintl_bind_textdomain_codeset = (void *)GetProcAddress(hLibintlDLL,
+ "bind_textdomain_codeset");
+ if (dyn_libintl_bind_textdomain_codeset == NULL)
+ dyn_libintl_bind_textdomain_codeset =
+ null_libintl_bind_textdomain_codeset;
+
+ /* _putenv() function for the libintl.dll is optional. */
+ hmsvcrt = find_imported_module_by_funcname(hLibintlDLL, "getenv");
+ if (hmsvcrt != NULL)
+ {
+ dyn_libintl_putenv = (void *)GetProcAddress(hmsvcrt, "_putenv");
+ dyn_libintl_wputenv = (void *)GetProcAddress(hmsvcrt, "_wputenv");
+ }
+ if (dyn_libintl_putenv == NULL || dyn_libintl_putenv == _putenv)
+ dyn_libintl_putenv = null_libintl_putenv;
+ if (dyn_libintl_wputenv == NULL || dyn_libintl_wputenv == _wputenv)
+ dyn_libintl_wputenv = null_libintl_wputenv;
+
+ return 1;
+}
+
+ void
+dyn_libintl_end(void)
+{
+ if (hLibintlDLL)
+ FreeLibrary(hLibintlDLL);
+ hLibintlDLL = NULL;
+ dyn_libintl_gettext = null_libintl_gettext;
+ dyn_libintl_ngettext = null_libintl_ngettext;
+ dyn_libintl_textdomain = null_libintl_textdomain;
+ dyn_libintl_bindtextdomain = null_libintl_bindtextdomain;
+ dyn_libintl_bind_textdomain_codeset = null_libintl_bind_textdomain_codeset;
+ dyn_libintl_putenv = null_libintl_putenv;
+ dyn_libintl_wputenv = null_libintl_wputenv;
+}
+
+ static char *
+null_libintl_gettext(const char *msgid)
+{
+ return (char*)msgid;
+}
+
+ static char *
+null_libintl_ngettext(
+ const char *msgid,
+ const char *msgid_plural,
+ unsigned long n)
+{
+ return (char *)(n == 1 ? msgid : msgid_plural);
+}
+
+ static char *
+null_libintl_bindtextdomain(
+ const char *domainname UNUSED,
+ const char *dirname UNUSED)
+{
+ return NULL;
+}
+
+ static char *
+null_libintl_bind_textdomain_codeset(
+ const char *domainname UNUSED,
+ const char *codeset UNUSED)
+{
+ return NULL;
+}
+
+ static char *
+null_libintl_textdomain(const char *domainname UNUSED)
+{
+ return NULL;
+}
+
+ static int
+null_libintl_putenv(const char *envstring UNUSED)
+{
+ return 0;
+}
+
+ static int
+null_libintl_wputenv(const wchar_t *envstring UNUSED)
+{
+ return 0;
+}
+
+#endif /* DYNAMIC_GETTEXT */
+
+/* This symbol is not defined in older versions of the SDK or Visual C++ */
+
+#ifndef VER_PLATFORM_WIN32_WINDOWS
+# define VER_PLATFORM_WIN32_WINDOWS 1
+#endif
+
+DWORD g_PlatformId;
+
+#ifdef HAVE_ACL
+# ifndef PROTO
+# include <aclapi.h>
+# endif
+# ifndef PROTECTED_DACL_SECURITY_INFORMATION
+# define PROTECTED_DACL_SECURITY_INFORMATION 0x80000000L
+# endif
+#endif
+
+#ifdef HAVE_ACL
+/*
+ * Enables or disables the specified privilege.
+ */
+ static BOOL
+win32_enable_privilege(LPTSTR lpszPrivilege, BOOL bEnable)
+{
+ BOOL bResult;
+ LUID luid;
+ HANDLE hToken;
+ TOKEN_PRIVILEGES tokenPrivileges;
+
+ if (!OpenProcessToken(GetCurrentProcess(),
+ TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
+ return FALSE;
+
+ if (!LookupPrivilegeValue(NULL, lpszPrivilege, &luid))
+ {
+ CloseHandle(hToken);
+ return FALSE;
+ }
+
+ tokenPrivileges.PrivilegeCount = 1;
+ tokenPrivileges.Privileges[0].Luid = luid;
+ tokenPrivileges.Privileges[0].Attributes = bEnable ?
+ SE_PRIVILEGE_ENABLED : 0;
+
+ bResult = AdjustTokenPrivileges(hToken, FALSE, &tokenPrivileges,
+ sizeof(TOKEN_PRIVILEGES), NULL, NULL);
+
+ CloseHandle(hToken);
+
+ return bResult && GetLastError() == ERROR_SUCCESS;
+}
+#endif
+
+/*
+ * Set g_PlatformId to VER_PLATFORM_WIN32_NT (NT) or
+ * VER_PLATFORM_WIN32_WINDOWS (Win95).
+ */
+ void
+PlatformId(void)
+{
+ static int done = FALSE;
+
+ if (!done)
+ {
+ OSVERSIONINFO ovi;
+
+ ovi.dwOSVersionInfoSize = sizeof(ovi);
+ GetVersionEx(&ovi);
+
+ g_PlatformId = ovi.dwPlatformId;
+
+ if ((ovi.dwMajorVersion == 6 && ovi.dwMinorVersion >= 2)
+ || ovi.dwMajorVersion > 6)
+ win8_or_later = TRUE;
+
+#ifdef HAVE_ACL
+ /* Enable privilege for getting or setting SACLs. */
+ win32_enable_privilege(SE_SECURITY_NAME, TRUE);
+#endif
+ done = TRUE;
+ }
+}
+
+#ifndef FEAT_GUI_W32
+
+#define SHIFT (SHIFT_PRESSED)
+#define CTRL (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED)
+#define ALT (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED)
+#define ALT_GR (RIGHT_ALT_PRESSED | LEFT_CTRL_PRESSED)
+
+
+/* When uChar.AsciiChar is 0, then we need to look at wVirtualKeyCode.
+ * We map function keys to their ANSI terminal equivalents, as produced
+ * by ANSI.SYS, for compatibility with the MS-DOS version of Vim. Any
+ * ANSI key with a value >= '\300' is nonstandard, but provided anyway
+ * so that the user can have access to all SHIFT-, CTRL-, and ALT-
+ * combinations of function/arrow/etc keys.
+ */
+
+static const struct
+{
+ WORD wVirtKey;
+ BOOL fAnsiKey;
+ int chAlone;
+ int chShift;
+ int chCtrl;
+ int chAlt;
+} VirtKeyMap[] =
+{
+// Key ANSI alone shift ctrl alt
+ { VK_ESCAPE,FALSE, ESC, ESC, ESC, ESC, },
+
+ { VK_F1, TRUE, ';', 'T', '^', 'h', },
+ { VK_F2, TRUE, '<', 'U', '_', 'i', },
+ { VK_F3, TRUE, '=', 'V', '`', 'j', },
+ { VK_F4, TRUE, '>', 'W', 'a', 'k', },
+ { VK_F5, TRUE, '?', 'X', 'b', 'l', },
+ { VK_F6, TRUE, '@', 'Y', 'c', 'm', },
+ { VK_F7, TRUE, 'A', 'Z', 'd', 'n', },
+ { VK_F8, TRUE, 'B', '[', 'e', 'o', },
+ { VK_F9, TRUE, 'C', '\\', 'f', 'p', },
+ { VK_F10, TRUE, 'D', ']', 'g', 'q', },
+ { VK_F11, TRUE, '\205', '\207', '\211', '\213', },
+ { VK_F12, TRUE, '\206', '\210', '\212', '\214', },
+
+ { VK_HOME, TRUE, 'G', '\302', 'w', '\303', },
+ { VK_UP, TRUE, 'H', '\304', '\305', '\306', },
+ { VK_PRIOR, TRUE, 'I', '\307', '\204', '\310', }, // PgUp
+ { VK_LEFT, TRUE, 'K', '\311', 's', '\312', },
+ { VK_RIGHT, TRUE, 'M', '\313', 't', '\314', },
+ { VK_END, TRUE, 'O', '\315', 'u', '\316', },
+ { VK_DOWN, TRUE, 'P', '\317', '\320', '\321', },
+ { VK_NEXT, TRUE, 'Q', '\322', 'v', '\323', }, // PgDn
+ { VK_INSERT,TRUE, 'R', '\324', '\325', '\326', },
+ { VK_DELETE,TRUE, 'S', '\327', '\330', '\331', },
+
+ { VK_SNAPSHOT,TRUE, 0, 0, 0, 'r', }, // PrtScrn
+
+#if 0
+ // Most people don't have F13-F20, but what the hell...
+ { VK_F13, TRUE, '\332', '\333', '\334', '\335', },
+ { VK_F14, TRUE, '\336', '\337', '\340', '\341', },
+ { VK_F15, TRUE, '\342', '\343', '\344', '\345', },
+ { VK_F16, TRUE, '\346', '\347', '\350', '\351', },
+ { VK_F17, TRUE, '\352', '\353', '\354', '\355', },
+ { VK_F18, TRUE, '\356', '\357', '\360', '\361', },
+ { VK_F19, TRUE, '\362', '\363', '\364', '\365', },
+ { VK_F20, TRUE, '\366', '\367', '\370', '\371', },
+#endif
+ { VK_ADD, TRUE, 'N', 'N', 'N', 'N', }, // keyp '+'
+ { VK_SUBTRACT, TRUE,'J', 'J', 'J', 'J', }, // keyp '-'
+ // { VK_DIVIDE, TRUE,'N', 'N', 'N', 'N', }, // keyp '/'
+ { VK_MULTIPLY, TRUE,'7', '7', '7', '7', }, // keyp '*'
+
+ { VK_NUMPAD0,TRUE, '\332', '\333', '\334', '\335', },
+ { VK_NUMPAD1,TRUE, '\336', '\337', '\340', '\341', },
+ { VK_NUMPAD2,TRUE, '\342', '\343', '\344', '\345', },
+ { VK_NUMPAD3,TRUE, '\346', '\347', '\350', '\351', },
+ { VK_NUMPAD4,TRUE, '\352', '\353', '\354', '\355', },
+ { VK_NUMPAD5,TRUE, '\356', '\357', '\360', '\361', },
+ { VK_NUMPAD6,TRUE, '\362', '\363', '\364', '\365', },
+ { VK_NUMPAD7,TRUE, '\366', '\367', '\370', '\371', },
+ { VK_NUMPAD8,TRUE, '\372', '\373', '\374', '\375', },
+ // Sorry, out of number space! <negri>
+ { VK_NUMPAD9,TRUE, '\376', '\377', '\377', '\367', },
+
+};
+
+
+#ifdef _MSC_VER
+// The ToAscii bug destroys several registers. Need to turn off optimization
+// or the GetConsoleKeyboardLayoutName hack will fail in non-debug versions
+# pragma warning(push)
+# pragma warning(disable: 4748)
+# pragma optimize("", off)
+#endif
+
+#if defined(__GNUC__) && !defined(__MINGW32__) && !defined(__CYGWIN__)
+# define UChar UnicodeChar
+#else
+# define UChar uChar.UnicodeChar
+#endif
+
+/* The return code indicates key code size. */
+ static int
+#ifdef __BORLANDC__
+ __stdcall
+#endif
+win32_kbd_patch_key(
+ KEY_EVENT_RECORD *pker)
+{
+ UINT uMods = pker->dwControlKeyState;
+ static int s_iIsDead = 0;
+ static WORD awAnsiCode[2];
+ static BYTE abKeystate[256];
+
+
+ if (s_iIsDead == 2)
+ {
+ pker->UChar = (WCHAR) awAnsiCode[1];
+ s_iIsDead = 0;
+ return 1;
+ }
+
+ if (pker->UChar != 0)
+ return 1;
+
+ vim_memset(abKeystate, 0, sizeof (abKeystate));
+
+ /* Clear any pending dead keys */
+ ToUnicode(VK_SPACE, MapVirtualKey(VK_SPACE, 0), abKeystate, awAnsiCode, 2, 0);
+
+ if (uMods & SHIFT_PRESSED)
+ abKeystate[VK_SHIFT] = 0x80;
+ if (uMods & CAPSLOCK_ON)
+ abKeystate[VK_CAPITAL] = 1;
+
+ if ((uMods & ALT_GR) == ALT_GR)
+ {
+ abKeystate[VK_CONTROL] = abKeystate[VK_LCONTROL] =
+ abKeystate[VK_MENU] = abKeystate[VK_RMENU] = 0x80;
+ }
+
+ s_iIsDead = ToUnicode(pker->wVirtualKeyCode, pker->wVirtualScanCode,
+ abKeystate, awAnsiCode, 2, 0);
+
+ if (s_iIsDead > 0)
+ pker->UChar = (WCHAR) awAnsiCode[0];
+
+ return s_iIsDead;
+}
+
+#ifdef _MSC_VER
+/* MUST switch optimization on again here, otherwise a call to
+ * decode_key_event() may crash (e.g. when hitting caps-lock) */
+# pragma optimize("", on)
+# pragma warning(pop)
+
+# if (_MSC_VER < 1100)
+/* MUST turn off global optimisation for this next function, or
+ * pressing ctrl-minus in insert mode crashes Vim when built with
+ * VC4.1. -- negri. */
+# pragma optimize("g", off)
+# endif
+#endif
+
+static BOOL g_fJustGotFocus = FALSE;
+
+/*
+ * Decode a KEY_EVENT into one or two keystrokes
+ */
+ static BOOL
+decode_key_event(
+ KEY_EVENT_RECORD *pker,
+ WCHAR *pch,
+ WCHAR *pch2,
+ int *pmodifiers,
+ BOOL fDoPost)
+{
+ int i;
+ const int nModifs = pker->dwControlKeyState & (SHIFT | ALT | CTRL);
+
+ *pch = *pch2 = NUL;
+ g_fJustGotFocus = FALSE;
+
+ /* ignore key up events */
+ if (!pker->bKeyDown)
+ return FALSE;
+
+ /* ignore some keystrokes */
+ switch (pker->wVirtualKeyCode)
+ {
+ /* modifiers */
+ case VK_SHIFT:
+ case VK_CONTROL:
+ case VK_MENU: /* Alt key */
+ return FALSE;
+
+ default:
+ break;
+ }
+
+ /* special cases */
+ if ((nModifs & CTRL) != 0 && (nModifs & ~CTRL) == 0 && pker->UChar == NUL)
+ {
+ /* Ctrl-6 is Ctrl-^ */
+ if (pker->wVirtualKeyCode == '6')
+ {
+ *pch = Ctrl_HAT;
+ return TRUE;
+ }
+ /* Ctrl-2 is Ctrl-@ */
+ else if (pker->wVirtualKeyCode == '2')
+ {
+ *pch = NUL;
+ return TRUE;
+ }
+ /* Ctrl-- is Ctrl-_ */
+ else if (pker->wVirtualKeyCode == 0xBD)
+ {
+ *pch = Ctrl__;
+ return TRUE;
+ }
+ }
+
+ /* Shift-TAB */
+ if (pker->wVirtualKeyCode == VK_TAB && (nModifs & SHIFT_PRESSED))
+ {
+ *pch = K_NUL;
+ *pch2 = '\017';
+ return TRUE;
+ }
+
+ for (i = sizeof(VirtKeyMap) / sizeof(VirtKeyMap[0]); --i >= 0; )
+ {
+ if (VirtKeyMap[i].wVirtKey == pker->wVirtualKeyCode)
+ {
+ if (nModifs == 0)
+ *pch = VirtKeyMap[i].chAlone;
+ else if ((nModifs & SHIFT) != 0 && (nModifs & ~SHIFT) == 0)
+ *pch = VirtKeyMap[i].chShift;
+ else if ((nModifs & CTRL) != 0 && (nModifs & ~CTRL) == 0)
+ *pch = VirtKeyMap[i].chCtrl;
+ else if ((nModifs & ALT) != 0 && (nModifs & ~ALT) == 0)
+ *pch = VirtKeyMap[i].chAlt;
+
+ if (*pch != 0)
+ {
+ if (VirtKeyMap[i].fAnsiKey)
+ {
+ *pch2 = *pch;
+ *pch = K_NUL;
+ }
+
+ return TRUE;
+ }
+ }
+ }
+
+ i = win32_kbd_patch_key(pker);
+
+ if (i < 0)
+ *pch = NUL;
+ else
+ {
+ *pch = (i > 0) ? pker->UChar : NUL;
+
+ if (pmodifiers != NULL)
+ {
+ /* Pass on the ALT key as a modifier, but only when not combined
+ * with CTRL (which is ALTGR). */
+ if ((nModifs & ALT) != 0 && (nModifs & CTRL) == 0)
+ *pmodifiers |= MOD_MASK_ALT;
+
+ /* Pass on SHIFT only for special keys, because we don't know when
+ * it's already included with the character. */
+ if ((nModifs & SHIFT) != 0 && *pch <= 0x20)
+ *pmodifiers |= MOD_MASK_SHIFT;
+
+ /* Pass on CTRL only for non-special keys, because we don't know
+ * when it's already included with the character. And not when
+ * combined with ALT (which is ALTGR). */
+ if ((nModifs & CTRL) != 0 && (nModifs & ALT) == 0
+ && *pch >= 0x20 && *pch < 0x80)
+ *pmodifiers |= MOD_MASK_CTRL;
+ }
+ }
+
+ return (*pch != NUL);
+}
+
+#ifdef _MSC_VER
+# pragma optimize("", on)
+#endif
+
+#endif /* FEAT_GUI_W32 */
+
+
+#ifdef FEAT_MOUSE
+
+/*
+ * For the GUI the mouse handling is in gui_w32.c.
+ */
+# ifdef FEAT_GUI_W32
+ void
+mch_setmouse(int on UNUSED)
+{
+}
+# else
+static int g_fMouseAvail = FALSE; /* mouse present */
+static int g_fMouseActive = FALSE; /* mouse enabled */
+static int g_nMouseClick = -1; /* mouse status */
+static int g_xMouse; /* mouse x coordinate */
+static int g_yMouse; /* mouse y coordinate */
+
+/*
+ * Enable or disable mouse input
+ */
+ void
+mch_setmouse(int on)
+{
+ DWORD cmodein;
+
+ if (!g_fMouseAvail)
+ return;
+
+ g_fMouseActive = on;
+ GetConsoleMode(g_hConIn, &cmodein);
+
+ if (g_fMouseActive)
+ cmodein |= ENABLE_MOUSE_INPUT;
+ else
+ cmodein &= ~ENABLE_MOUSE_INPUT;
+
+ SetConsoleMode(g_hConIn, cmodein);
+}
+
+
+#if defined(FEAT_BEVAL_TERM) || defined(PROTO)
+/*
+ * Called when 'balloonevalterm' changed.
+ */
+ void
+mch_bevalterm_changed(void)
+{
+ mch_setmouse(g_fMouseActive);
+}
+#endif
+
+/*
+ * Decode a MOUSE_EVENT. If it's a valid event, return MOUSE_LEFT,
+ * MOUSE_MIDDLE, or MOUSE_RIGHT for a click; MOUSE_DRAG for a mouse
+ * move with a button held down; and MOUSE_RELEASE after a MOUSE_DRAG
+ * or a MOUSE_LEFT, _MIDDLE, or _RIGHT. We encode the button type,
+ * the number of clicks, and the Shift/Ctrl/Alt modifiers in g_nMouseClick,
+ * and we return the mouse position in g_xMouse and g_yMouse.
+ *
+ * Every MOUSE_LEFT, _MIDDLE, or _RIGHT will be followed by zero or more
+ * MOUSE_DRAGs and one MOUSE_RELEASE. MOUSE_RELEASE will be followed only
+ * by MOUSE_LEFT, _MIDDLE, or _RIGHT.
+ *
+ * For multiple clicks, we send, say, MOUSE_LEFT/1 click, MOUSE_RELEASE,
+ * MOUSE_LEFT/2 clicks, MOUSE_RELEASE, MOUSE_LEFT/3 clicks, MOUSE_RELEASE, ....
+ *
+ * Windows will send us MOUSE_MOVED notifications whenever the mouse
+ * moves, even if it stays within the same character cell. We ignore
+ * all MOUSE_MOVED messages if the position hasn't really changed, and
+ * we ignore all MOUSE_MOVED messages where no button is held down (i.e.,
+ * we're only interested in MOUSE_DRAG).
+ *
+ * All of this is complicated by the code that fakes MOUSE_MIDDLE on
+ * 2-button mouses by pressing the left & right buttons simultaneously.
+ * In practice, it's almost impossible to click both at the same time,
+ * so we need to delay a little. Also, we tend not to get MOUSE_RELEASE
+ * in such cases, if the user is clicking quickly.
+ */
+ static BOOL
+decode_mouse_event(
+ MOUSE_EVENT_RECORD *pmer)
+{
+ static int s_nOldButton = -1;
+ static int s_nOldMouseClick = -1;
+ static int s_xOldMouse = -1;
+ static int s_yOldMouse = -1;
+ static linenr_T s_old_topline = 0;
+#ifdef FEAT_DIFF
+ static int s_old_topfill = 0;
+#endif
+ static int s_cClicks = 1;
+ static BOOL s_fReleased = TRUE;
+ static DWORD s_dwLastClickTime = 0;
+ static BOOL s_fNextIsMiddle = FALSE;
+
+ static DWORD cButtons = 0; /* number of buttons supported */
+
+ const DWORD LEFT = FROM_LEFT_1ST_BUTTON_PRESSED;
+ const DWORD MIDDLE = FROM_LEFT_2ND_BUTTON_PRESSED;
+ const DWORD RIGHT = RIGHTMOST_BUTTON_PRESSED;
+ const DWORD LEFT_RIGHT = LEFT | RIGHT;
+
+ int nButton;
+
+ if (cButtons == 0 && !GetNumberOfConsoleMouseButtons(&cButtons))
+ cButtons = 2;
+
+ if (!g_fMouseAvail || !g_fMouseActive)
+ {
+ g_nMouseClick = -1;
+ return FALSE;
+ }
+
+ /* get a spurious MOUSE_EVENT immediately after receiving focus; ignore */
+ if (g_fJustGotFocus)
+ {
+ g_fJustGotFocus = FALSE;
+ return FALSE;
+ }
+
+ /* unprocessed mouse click? */
+ if (g_nMouseClick != -1)
+ return TRUE;
+
+ nButton = -1;
+ g_xMouse = pmer->dwMousePosition.X;
+ g_yMouse = pmer->dwMousePosition.Y;
+
+ if (pmer->dwEventFlags == MOUSE_MOVED)
+ {
+ /* Ignore MOUSE_MOVED events if (x, y) hasn't changed. (We get these
+ * events even when the mouse moves only within a char cell.) */
+ if (s_xOldMouse == g_xMouse && s_yOldMouse == g_yMouse)
+ return FALSE;
+ }
+
+ /* If no buttons are pressed... */
+ if ((pmer->dwButtonState & ((1 << cButtons) - 1)) == 0)
+ {
+ nButton = MOUSE_RELEASE;
+
+ /* If the last thing returned was MOUSE_RELEASE, ignore this */
+ if (s_fReleased)
+ {
+#ifdef FEAT_BEVAL_TERM
+ /* do return mouse move events when we want them */
+ if (p_bevalterm)
+ nButton = MOUSE_DRAG;
+ else
+#endif
+ return FALSE;
+ }
+
+ s_fReleased = TRUE;
+ }
+ else /* one or more buttons pressed */
+ {
+ /* on a 2-button mouse, hold down left and right buttons
+ * simultaneously to get MIDDLE. */
+
+ if (cButtons == 2 && s_nOldButton != MOUSE_DRAG)
+ {
+ DWORD dwLR = (pmer->dwButtonState & LEFT_RIGHT);
+
+ /* if either left or right button only is pressed, see if the
+ * next mouse event has both of them pressed */
+ if (dwLR == LEFT || dwLR == RIGHT)
+ {
+ for (;;)
+ {
+ /* wait a short time for next input event */
+ if (WaitForSingleObject(g_hConIn, p_mouset / 3)
+ != WAIT_OBJECT_0)
+ break;
+ else
+ {
+ DWORD cRecords = 0;
+ INPUT_RECORD ir;
+ MOUSE_EVENT_RECORD* pmer2 = &ir.Event.MouseEvent;
+
+ peek_console_input(g_hConIn, &ir, 1, &cRecords);
+
+ if (cRecords == 0 || ir.EventType != MOUSE_EVENT
+ || !(pmer2->dwButtonState & LEFT_RIGHT))
+ break;
+ else
+ {
+ if (pmer2->dwEventFlags != MOUSE_MOVED)
+ {
+ read_console_input(g_hConIn, &ir, 1, &cRecords);
+
+ return decode_mouse_event(pmer2);
+ }
+ else if (s_xOldMouse == pmer2->dwMousePosition.X &&
+ s_yOldMouse == pmer2->dwMousePosition.Y)
+ {
+ /* throw away spurious mouse move */
+ read_console_input(g_hConIn, &ir, 1, &cRecords);
+
+ /* are there any more mouse events in queue? */
+ peek_console_input(g_hConIn, &ir, 1, &cRecords);
+
+ if (cRecords==0 || ir.EventType != MOUSE_EVENT)
+ break;
+ }
+ else
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (s_fNextIsMiddle)
+ {
+ nButton = (pmer->dwEventFlags == MOUSE_MOVED)
+ ? MOUSE_DRAG : MOUSE_MIDDLE;
+ s_fNextIsMiddle = FALSE;
+ }
+ else if (cButtons == 2 &&
+ ((pmer->dwButtonState & LEFT_RIGHT) == LEFT_RIGHT))
+ {
+ nButton = MOUSE_MIDDLE;
+
+ if (! s_fReleased && pmer->dwEventFlags != MOUSE_MOVED)
+ {
+ s_fNextIsMiddle = TRUE;
+ nButton = MOUSE_RELEASE;
+ }
+ }
+ else if ((pmer->dwButtonState & LEFT) == LEFT)
+ nButton = MOUSE_LEFT;
+ else if ((pmer->dwButtonState & MIDDLE) == MIDDLE)
+ nButton = MOUSE_MIDDLE;
+ else if ((pmer->dwButtonState & RIGHT) == RIGHT)
+ nButton = MOUSE_RIGHT;
+
+ if (! s_fReleased && ! s_fNextIsMiddle
+ && nButton != s_nOldButton && s_nOldButton != MOUSE_DRAG)
+ return FALSE;
+
+ s_fReleased = s_fNextIsMiddle;
+ }
+
+ if (pmer->dwEventFlags == 0 || pmer->dwEventFlags == DOUBLE_CLICK)
+ {
+ /* button pressed or released, without mouse moving */
+ if (nButton != -1 && nButton != MOUSE_RELEASE)
+ {
+ DWORD dwCurrentTime = GetTickCount();
+
+ if (s_xOldMouse != g_xMouse
+ || s_yOldMouse != g_yMouse
+ || s_nOldButton != nButton
+ || s_old_topline != curwin->w_topline
+#ifdef FEAT_DIFF
+ || s_old_topfill != curwin->w_topfill
+#endif
+ || (int)(dwCurrentTime - s_dwLastClickTime) > p_mouset)
+ {
+ s_cClicks = 1;
+ }
+ else if (++s_cClicks > 4)
+ {
+ s_cClicks = 1;
+ }
+
+ s_dwLastClickTime = dwCurrentTime;
+ }
+ }
+ else if (pmer->dwEventFlags == MOUSE_MOVED)
+ {
+ if (nButton != -1 && nButton != MOUSE_RELEASE)
+ nButton = MOUSE_DRAG;
+
+ s_cClicks = 1;
+ }
+
+ if (nButton == -1)
+ return FALSE;
+
+ if (nButton != MOUSE_RELEASE)
+ s_nOldButton = nButton;
+
+ g_nMouseClick = nButton;
+
+ if (pmer->dwControlKeyState & SHIFT_PRESSED)
+ g_nMouseClick |= MOUSE_SHIFT;
+ if (pmer->dwControlKeyState & (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED))
+ g_nMouseClick |= MOUSE_CTRL;
+ if (pmer->dwControlKeyState & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED))
+ g_nMouseClick |= MOUSE_ALT;
+
+ if (nButton != MOUSE_DRAG && nButton != MOUSE_RELEASE)
+ SET_NUM_MOUSE_CLICKS(g_nMouseClick, s_cClicks);
+
+ /* only pass on interesting (i.e., different) mouse events */
+ if (s_xOldMouse == g_xMouse
+ && s_yOldMouse == g_yMouse
+ && s_nOldMouseClick == g_nMouseClick)
+ {
+ g_nMouseClick = -1;
+ return FALSE;
+ }
+
+ s_xOldMouse = g_xMouse;
+ s_yOldMouse = g_yMouse;
+ s_old_topline = curwin->w_topline;
+#ifdef FEAT_DIFF
+ s_old_topfill = curwin->w_topfill;
+#endif
+ s_nOldMouseClick = g_nMouseClick;
+
+ return TRUE;
+}
+
+# endif /* FEAT_GUI_W32 */
+#endif /* FEAT_MOUSE */
+
+
+#ifdef MCH_CURSOR_SHAPE
+/*
+ * Set the shape of the cursor.
+ * 'thickness' can be from 1 (thin) to 99 (block)
+ */
+ static void
+mch_set_cursor_shape(int thickness)
+{
+ CONSOLE_CURSOR_INFO ConsoleCursorInfo;
+ ConsoleCursorInfo.dwSize = thickness;
+ ConsoleCursorInfo.bVisible = s_cursor_visible;
+
+ SetConsoleCursorInfo(g_hConOut, &ConsoleCursorInfo);
+ if (s_cursor_visible)
+ SetConsoleCursorPosition(g_hConOut, g_coord);
+}
+
+ void
+mch_update_cursor(void)
+{
+ int idx;
+ int thickness;
+
+ /*
+ * How the cursor is drawn depends on the current mode.
+ */
+ idx = get_shape_idx(FALSE);
+
+ if (shape_table[idx].shape == SHAPE_BLOCK)
+ thickness = 99; /* 100 doesn't work on W95 */
+ else
+ thickness = shape_table[idx].percentage;
+ mch_set_cursor_shape(thickness);
+}
+#endif
+
+#ifndef FEAT_GUI_W32 /* this isn't used for the GUI */
+/*
+ * Handle FOCUS_EVENT.
+ */
+ static void
+handle_focus_event(INPUT_RECORD ir)
+{
+ g_fJustGotFocus = ir.Event.FocusEvent.bSetFocus;
+ ui_focus_change((int)g_fJustGotFocus);
+}
+
+/*
+ * Wait until console input from keyboard or mouse is available,
+ * or the time is up.
+ * When "ignore_input" is TRUE even wait when input is available.
+ * Return TRUE if something is available FALSE if not.
+ */
+ static int
+WaitForChar(long msec, int ignore_input)
+{
+ DWORD dwNow = 0, dwEndTime = 0;
+ INPUT_RECORD ir;
+ DWORD cRecords;
+ WCHAR ch, ch2;
+#ifdef FEAT_TIMERS
+ int tb_change_cnt = typebuf.tb_change_cnt;
+#endif
+
+ if (msec > 0)
+ /* Wait until the specified time has elapsed. */
+ dwEndTime = GetTickCount() + msec;
+ else if (msec < 0)
+ /* Wait forever. */
+ dwEndTime = INFINITE;
+
+ // We need to loop until the end of the time period, because
+ // we might get multiple unusable mouse events in that time.
+ for (;;)
+ {
+ // Only process messages when waiting.
+ if (msec != 0)
+ {
+#ifdef MESSAGE_QUEUE
+ parse_queued_messages();
+#endif
+#ifdef FEAT_MZSCHEME
+ mzvim_check_threads();
+#endif
+#ifdef FEAT_CLIENTSERVER
+ serverProcessPendingMessages();
+#endif
+ }
+
+ if (0
+#ifdef FEAT_MOUSE
+ || g_nMouseClick != -1
+#endif
+#ifdef FEAT_CLIENTSERVER
+ || (!ignore_input && input_available())
+#endif
+ )
+ return TRUE;
+
+ if (msec > 0)
+ {
+ /* If the specified wait time has passed, return. Beware that
+ * GetTickCount() may wrap around (overflow). */
+ dwNow = GetTickCount();
+ if ((int)(dwNow - dwEndTime) >= 0)
+ break;
+ }
+ if (msec != 0)
+ {
+ DWORD dwWaitTime = dwEndTime - dwNow;
+
+#ifdef FEAT_JOB_CHANNEL
+ /* Check channel while waiting for input. */
+ if (dwWaitTime > 100)
+ {
+ dwWaitTime = 100;
+ /* If there is readahead then parse_queued_messages() timed out
+ * and we should call it again soon. */
+ if (channel_any_readahead())
+ dwWaitTime = 10;
+ }
+#endif
+#ifdef FEAT_BEVAL_GUI
+ if (p_beval && dwWaitTime > 100)
+ /* The 'balloonexpr' may indirectly invoke a callback while
+ * waiting for a character, need to check often. */
+ dwWaitTime = 100;
+#endif
+#ifdef FEAT_MZSCHEME
+ if (mzthreads_allowed() && p_mzq > 0
+ && (msec < 0 || (long)dwWaitTime > p_mzq))
+ dwWaitTime = p_mzq; /* don't wait longer than 'mzquantum' */
+#endif
+#ifdef FEAT_TIMERS
+ // When waiting very briefly don't trigger timers.
+ if (dwWaitTime > 10)
+ {
+ long due_time;
+
+ // Trigger timers and then get the time in msec until the next
+ // one is due. Wait up to that time.
+ due_time = check_due_timer();
+ if (typebuf.tb_change_cnt != tb_change_cnt)
+ {
+ // timer may have used feedkeys().
+ return FALSE;
+ }
+ if (due_time > 0 && dwWaitTime > (DWORD)due_time)
+ dwWaitTime = due_time;
+ }
+#endif
+ if (
+#ifdef FEAT_CLIENTSERVER
+ // Wait for either an event on the console input or a
+ // message in the client-server window.
+ msg_wait_for_multiple_objects(1, &g_hConIn, FALSE,
+ dwWaitTime, QS_SENDMESSAGE) != WAIT_OBJECT_0
+#else
+ wait_for_single_object(g_hConIn, dwWaitTime)
+ != WAIT_OBJECT_0
+#endif
+ )
+ continue;
+ }
+
+ cRecords = 0;
+ peek_console_input(g_hConIn, &ir, 1, &cRecords);
+
+#ifdef FEAT_MBYTE_IME
+ if (State & CMDLINE && msg_row == Rows - 1)
+ {
+ CONSOLE_SCREEN_BUFFER_INFO csbi;
+
+ if (GetConsoleScreenBufferInfo(g_hConOut, &csbi))
+ {
+ if (csbi.dwCursorPosition.Y != msg_row)
+ {
+ /* The screen is now messed up, must redraw the
+ * command line and later all the windows. */
+ redraw_all_later(CLEAR);
+ cmdline_row -= (msg_row - csbi.dwCursorPosition.Y);
+ redrawcmd();
+ }
+ }
+ }
+#endif
+
+ if (cRecords > 0)
+ {
+ if (ir.EventType == KEY_EVENT && ir.Event.KeyEvent.bKeyDown)
+ {
+#ifdef FEAT_MBYTE_IME
+ /* Windows IME sends two '\n's with only one 'ENTER'. First:
+ * wVirtualKeyCode == 13. second: wVirtualKeyCode == 0 */
+ if (ir.Event.KeyEvent.UChar == 0
+ && ir.Event.KeyEvent.wVirtualKeyCode == 13)
+ {
+ read_console_input(g_hConIn, &ir, 1, &cRecords);
+ continue;
+ }
+#endif
+ if (decode_key_event(&ir.Event.KeyEvent, &ch, &ch2,
+ NULL, FALSE))
+ return TRUE;
+ }
+
+ read_console_input(g_hConIn, &ir, 1, &cRecords);
+
+ if (ir.EventType == FOCUS_EVENT)
+ handle_focus_event(ir);
+ else if (ir.EventType == WINDOW_BUFFER_SIZE_EVENT)
+ {
+ /* Only call shell_resized() when the size actually change to
+ * avoid the screen is cleard. */
+ if (ir.Event.WindowBufferSizeEvent.dwSize.X != Columns
+ || ir.Event.WindowBufferSizeEvent.dwSize.Y != Rows)
+ shell_resized();
+ }
+#ifdef FEAT_MOUSE
+ else if (ir.EventType == MOUSE_EVENT
+ && decode_mouse_event(&ir.Event.MouseEvent))
+ return TRUE;
+#endif
+ }
+ else if (msec == 0)
+ break;
+ }
+
+#ifdef FEAT_CLIENTSERVER
+ /* Something might have been received while we were waiting. */
+ if (input_available())
+ return TRUE;
+#endif
+
+ return FALSE;
+}
+
+#ifndef FEAT_GUI_MSWIN
+/*
+ * return non-zero if a character is available
+ */
+ int
+mch_char_avail(void)
+{
+ return WaitForChar(0L, FALSE);
+}
+
+# if defined(FEAT_TERMINAL) || defined(PROTO)
+/*
+ * Check for any pending input or messages.
+ */
+ int
+mch_check_messages(void)
+{
+ return WaitForChar(0L, TRUE);
+}
+# endif
+#endif
+
+/*
+ * Create the console input. Used when reading stdin doesn't work.
+ */
+ static void
+create_conin(void)
+{
+ g_hConIn = CreateFile("CONIN$", GENERIC_READ|GENERIC_WRITE,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ (LPSECURITY_ATTRIBUTES) NULL,
+ OPEN_EXISTING, 0, (HANDLE)NULL);
+ did_create_conin = TRUE;
+}
+
+/*
+ * Get a keystroke or a mouse event, use a blocking wait.
+ */
+ static WCHAR
+tgetch(int *pmodifiers, WCHAR *pch2)
+{
+ WCHAR ch;
+
+ for (;;)
+ {
+ INPUT_RECORD ir;
+ DWORD cRecords = 0;
+
+#ifdef FEAT_CLIENTSERVER
+ (void)WaitForChar(-1L, FALSE);
+ if (input_available())
+ return 0;
+# ifdef FEAT_MOUSE
+ if (g_nMouseClick != -1)
+ return 0;
+# endif
+#endif
+ if (read_console_input(g_hConIn, &ir, 1, &cRecords) == 0)
+ {
+ if (did_create_conin)
+ read_error_exit();
+ create_conin();
+ continue;
+ }
+
+ if (ir.EventType == KEY_EVENT)
+ {
+ if (decode_key_event(&ir.Event.KeyEvent, &ch, pch2,
+ pmodifiers, TRUE))
+ return ch;
+ }
+ else if (ir.EventType == FOCUS_EVENT)
+ handle_focus_event(ir);
+ else if (ir.EventType == WINDOW_BUFFER_SIZE_EVENT)
+ shell_resized();
+#ifdef FEAT_MOUSE
+ else if (ir.EventType == MOUSE_EVENT)
+ {
+ if (decode_mouse_event(&ir.Event.MouseEvent))
+ return 0;
+ }
+#endif
+ }
+}
+#endif /* !FEAT_GUI_W32 */
+
+
+/*
+ * mch_inchar(): low-level input function.
+ * Get one or more characters from the keyboard or the mouse.
+ * If time == 0, do not wait for characters.
+ * If time == n, wait a short time for characters.
+ * If time == -1, wait forever for characters.
+ * Returns the number of characters read into buf.
+ */
+ int
+mch_inchar(
+ char_u *buf UNUSED,
+ int maxlen UNUSED,
+ long time UNUSED,
+ int tb_change_cnt UNUSED)
+{
+#ifndef FEAT_GUI_W32 /* this isn't used for the GUI */
+
+ int len;
+ int c;
+#define TYPEAHEADLEN 20
+ static char_u typeahead[TYPEAHEADLEN]; /* previously typed bytes. */
+ static int typeaheadlen = 0;
+
+ /* First use any typeahead that was kept because "buf" was too small. */
+ if (typeaheadlen > 0)
+ goto theend;
+
+ if (time >= 0)
+ {
+ if (!WaitForChar(time, FALSE)) /* no character available */
+ return 0;
+ }
+ else /* time == -1, wait forever */
+ {
+ mch_set_winsize_now(); /* Allow winsize changes from now on */
+
+ /*
+ * If there is no character available within 2 seconds (default)
+ * write the autoscript file to disk. Or cause the CursorHold event
+ * to be triggered.
+ */
+ if (!WaitForChar(p_ut, FALSE))
+ {
+ if (trigger_cursorhold() && maxlen >= 3)
+ {
+ buf[0] = K_SPECIAL;
+ buf[1] = KS_EXTRA;
+ buf[2] = (int)KE_CURSORHOLD;
+ return 3;
+ }
+ before_blocking();
+ }
+ }
+
+ /*
+ * Try to read as many characters as there are, until the buffer is full.
+ */
+
+ /* we will get at least one key. Get more if they are available. */
+ g_fCBrkPressed = FALSE;
+
+#ifdef MCH_WRITE_DUMP
+ if (fdDump)
+ fputc('[', fdDump);
+#endif
+
+ /* Keep looping until there is something in the typeahead buffer and more
+ * to get and still room in the buffer (up to two bytes for a char and
+ * three bytes for a modifier). */
+ while ((typeaheadlen == 0 || WaitForChar(0L, FALSE))
+ && typeaheadlen + 5 <= TYPEAHEADLEN)
+ {
+ if (typebuf_changed(tb_change_cnt))
+ {
+ /* "buf" may be invalid now if a client put something in the
+ * typeahead buffer and "buf" is in the typeahead buffer. */
+ typeaheadlen = 0;
+ break;
+ }
+#ifdef FEAT_MOUSE
+ if (g_nMouseClick != -1)
+ {
+# ifdef MCH_WRITE_DUMP
+ if (fdDump)
+ fprintf(fdDump, "{%02x @ %d, %d}",
+ g_nMouseClick, g_xMouse, g_yMouse);
+# endif
+ typeahead[typeaheadlen++] = ESC + 128;
+ typeahead[typeaheadlen++] = 'M';
+ typeahead[typeaheadlen++] = g_nMouseClick;
+ typeahead[typeaheadlen++] = g_xMouse + '!';
+ typeahead[typeaheadlen++] = g_yMouse + '!';
+ g_nMouseClick = -1;
+ }
+ else
+#endif
+ {
+ WCHAR ch2 = NUL;
+ int modifiers = 0;
+
+ c = tgetch(&modifiers, &ch2);
+
+ if (typebuf_changed(tb_change_cnt))
+ {
+ /* "buf" may be invalid now if a client put something in the
+ * typeahead buffer and "buf" is in the typeahead buffer. */
+ typeaheadlen = 0;
+ break;
+ }
+
+ if (c == Ctrl_C && ctrl_c_interrupts)
+ {
+#if defined(FEAT_CLIENTSERVER)
+ trash_input_buf();
+#endif
+ got_int = TRUE;
+ }
+
+#ifdef FEAT_MOUSE
+ if (g_nMouseClick == -1)
+#endif
+ {
+ int n = 1;
+
+ if (ch2 == NUL)
+ {
+ int i;
+ char_u *p;
+ WCHAR ch[2];
+
+ ch[0] = c;
+ if (c >= 0xD800 && c <= 0xDBFF) /* High surrogate */
+ {
+ ch[1] = tgetch(&modifiers, &ch2);
+ n++;
+ }
+ p = utf16_to_enc(ch, &n);
+ if (p != NULL)
+ {
+ for (i = 0; i < n; i++)
+ typeahead[typeaheadlen + i] = p[i];
+ vim_free(p);
+ }
+ }
+ else
+ typeahead[typeaheadlen] = c;
+ if (ch2 != NUL)
+ {
+ if (c == K_NUL)
+ {
+ switch (ch2)
+ {
+ case (WCHAR)'\324': // SHIFT+Insert
+ case (WCHAR)'\325': // CTRL+Insert
+ case (WCHAR)'\327': // SHIFT+Delete
+ case (WCHAR)'\330': // CTRL+Delete
+ typeahead[typeaheadlen + n] = (char_u)ch2;
+ n++;
+ break;
+
+ default:
+ typeahead[typeaheadlen + n] = 3;
+ typeahead[typeaheadlen + n + 1] = (char_u)ch2;
+ n += 2;
+ break;
+ }
+ }
+ else
+ {
+ typeahead[typeaheadlen + n] = 3;
+ typeahead[typeaheadlen + n + 1] = (char_u)ch2;
+ n += 2;
+ }
+ }
+
+ /* Use the ALT key to set the 8th bit of the character
+ * when it's one byte, the 8th bit isn't set yet and not
+ * using a double-byte encoding (would become a lead
+ * byte). */
+ if ((modifiers & MOD_MASK_ALT)
+ && n == 1
+ && (typeahead[typeaheadlen] & 0x80) == 0
+ && !enc_dbcs
+ )
+ {
+ n = (*mb_char2bytes)(typeahead[typeaheadlen] | 0x80,
+ typeahead + typeaheadlen);
+ modifiers &= ~MOD_MASK_ALT;
+ }
+
+ if (modifiers != 0)
+ {
+ /* Prepend modifiers to the character. */
+ mch_memmove(typeahead + typeaheadlen + 3,
+ typeahead + typeaheadlen, n);
+ typeahead[typeaheadlen++] = K_SPECIAL;
+ typeahead[typeaheadlen++] = (char_u)KS_MODIFIER;
+ typeahead[typeaheadlen++] = modifiers;
+ }
+
+ typeaheadlen += n;
+
+#ifdef MCH_WRITE_DUMP
+ if (fdDump)
+ fputc(c, fdDump);
+#endif
+ }
+ }
+ }
+
+#ifdef MCH_WRITE_DUMP
+ if (fdDump)
+ {
+ fputs("]\n", fdDump);
+ fflush(fdDump);
+ }
+#endif
+
+theend:
+ /* Move typeahead to "buf", as much as fits. */
+ len = 0;
+ while (len < maxlen && typeaheadlen > 0)
+ {
+ buf[len++] = typeahead[0];
+ mch_memmove(typeahead, typeahead + 1, --typeaheadlen);
+ }
+ return len;
+
+#else /* FEAT_GUI_W32 */
+ return 0;
+#endif /* FEAT_GUI_W32 */
+}
+
+#ifndef PROTO
+# ifndef __MINGW32__
+# include <shellapi.h> /* required for FindExecutable() */
+# endif
+#endif
+
+/*
+ * If "use_path" is TRUE: Return TRUE if "name" is in $PATH.
+ * If "use_path" is FALSE: Return TRUE if "name" exists.
+ * When returning TRUE and "path" is not NULL save the path and set "*path" to
+ * the allocated memory.
+ * TODO: Should somehow check if it's really executable.
+ */
+ static int
+executable_exists(char *name, char_u **path, int use_path)
+{
+ char *dum;
+ char fname[_MAX_PATH];
+ char *curpath, *newpath;
+ long n;
+
+ if (!use_path)
+ {
+ if (mch_getperm((char_u *)name) != -1 && !mch_isdir((char_u *)name))
+ {
+ if (path != NULL)
+ {
+ if (mch_isFullName((char_u *)name))
+ *path = vim_strsave((char_u *)name);
+ else
+ *path = FullName_save((char_u *)name, FALSE);
+ }
+ return TRUE;
+ }
+ return FALSE;
+ }
+
+ if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+ {
+ WCHAR *p = enc_to_utf16((char_u *)name, NULL);
+ WCHAR fnamew[_MAX_PATH];
+ WCHAR *dumw;
+ WCHAR *wcurpath, *wnewpath;
+
+ if (p != NULL)
+ {
+ wcurpath = _wgetenv(L"PATH");
+ wnewpath = (WCHAR*)alloc((unsigned)(wcslen(wcurpath) + 3)
+ * sizeof(WCHAR));
+ if (wnewpath == NULL)
+ return FALSE;
+ wcscpy(wnewpath, L".;");
+ wcscat(wnewpath, wcurpath);
+ n = (long)SearchPathW(wnewpath, p, NULL, _MAX_PATH, fnamew, &dumw);
+ vim_free(wnewpath);
+ vim_free(p);
+ if (n == 0)
+ return FALSE;
+ if (GetFileAttributesW(fnamew) & FILE_ATTRIBUTE_DIRECTORY)
+ return FALSE;
+ if (path != NULL)
+ *path = utf16_to_enc(fnamew, NULL);
+ return TRUE;
+ }
+ }
+
+ curpath = getenv("PATH");
+ newpath = (char*)alloc((unsigned)(STRLEN(curpath) + 3));
+ if (newpath == NULL)
+ return FALSE;
+ STRCPY(newpath, ".;");
+ STRCAT(newpath, curpath);
+ n = (long)SearchPath(newpath, name, NULL, _MAX_PATH, fname, &dum);
+ vim_free(newpath);
+ if (n == 0)
+ return FALSE;
+ if (mch_isdir((char_u *)fname))
+ return FALSE;
+ if (path != NULL)
+ *path = vim_strsave((char_u *)fname);
+ return TRUE;
+}
+
+#if ((defined(__MINGW32__) || defined (__CYGWIN32__)) && \
+ __MSVCRT_VERSION__ >= 0x800) || (defined(_MSC_VER) && _MSC_VER >= 1400)
+/*
+ * Bad parameter handler.
+ *
+ * Certain MS CRT functions will intentionally crash when passed invalid
+ * parameters to highlight possible security holes. Setting this function as
+ * the bad parameter handler will prevent the crash.
+ *
+ * In debug builds the parameters contain CRT information that might help track
+ * down the source of a problem, but in non-debug builds the arguments are all
+ * NULL/0. Debug builds will also produce assert dialogs from the CRT, it is
+ * worth allowing these to make debugging of issues easier.
+ */
+ static void
+bad_param_handler(const wchar_t *expression,
+ const wchar_t *function,
+ const wchar_t *file,
+ unsigned int line,
+ uintptr_t pReserved)
+{
+}
+
+# define SET_INVALID_PARAM_HANDLER \
+ ((void)_set_invalid_parameter_handler(bad_param_handler))
+#else
+# define SET_INVALID_PARAM_HANDLER
+#endif
+
+#ifdef FEAT_GUI_W32
+
+/*
+ * GUI version of mch_init().
+ */
+ void
+mch_init(void)
+{
+#ifndef __MINGW32__
+ extern int _fmode;
+#endif
+
+ /* Silently handle invalid parameters to CRT functions */
+ SET_INVALID_PARAM_HANDLER;
+
+ /* Let critical errors result in a failure, not in a dialog box. Required
+ * for the timestamp test to work on removed floppies. */
+ SetErrorMode(SEM_FAILCRITICALERRORS);
+
+ _fmode = O_BINARY; /* we do our own CR-LF translation */
+
+ /* Specify window size. Is there a place to get the default from? */
+ Rows = 25;
+ Columns = 80;
+
+ /* Look for 'vimrun' */
+ {
+ char_u vimrun_location[_MAX_PATH + 4];
+
+ /* First try in same directory as gvim.exe */
+ STRCPY(vimrun_location, exe_name);
+ STRCPY(gettail(vimrun_location), "vimrun.exe");
+ if (mch_getperm(vimrun_location) >= 0)
+ {
+ if (*skiptowhite(vimrun_location) != NUL)
+ {
+ /* Enclose path with white space in double quotes. */
+ mch_memmove(vimrun_location + 1, vimrun_location,
+ STRLEN(vimrun_location) + 1);
+ *vimrun_location = '"';
+ STRCPY(gettail(vimrun_location), "vimrun\" ");
+ }
+ else
+ STRCPY(gettail(vimrun_location), "vimrun ");
+
+ vimrun_path = (char *)vim_strsave(vimrun_location);
+ s_dont_use_vimrun = FALSE;
+ }
+ else if (executable_exists("vimrun.exe", NULL, TRUE))
+ s_dont_use_vimrun = FALSE;
+
+ /* Don't give the warning for a missing vimrun.exe right now, but only
+ * when vimrun was supposed to be used. Don't bother people that do
+ * not need vimrun.exe. */
+ if (s_dont_use_vimrun)
+ need_vimrun_warning = TRUE;
+ }
+
+ /*
+ * If "finstr.exe" doesn't exist, use "grep -n" for 'grepprg'.
+ * Otherwise the default "findstr /n" is used.
+ */
+ if (!executable_exists("findstr.exe", NULL, TRUE))
+ set_option_value((char_u *)"grepprg", 0, (char_u *)"grep -n", 0);
+
+#ifdef FEAT_CLIPBOARD
+ win_clip_init();
+#endif
+
+ vtp_flag_init();
+}
+
+
+#else /* FEAT_GUI_W32 */
+
+#define SRWIDTH(sr) ((sr).Right - (sr).Left + 1)
+#define SRHEIGHT(sr) ((sr).Bottom - (sr).Top + 1)
+
+/*
+ * ClearConsoleBuffer()
+ * Description:
+ * Clears the entire contents of the console screen buffer, using the
+ * specified attribute.
+ * Returns:
+ * TRUE on success
+ */
+ static BOOL
+ClearConsoleBuffer(WORD wAttribute)
+{
+ CONSOLE_SCREEN_BUFFER_INFO csbi;
+ COORD coord;
+ DWORD NumCells, dummy;
+
+ if (!GetConsoleScreenBufferInfo(g_hConOut, &csbi))
+ return FALSE;
+
+ NumCells = csbi.dwSize.X * csbi.dwSize.Y;
+ coord.X = 0;
+ coord.Y = 0;
+ if (!FillConsoleOutputCharacter(g_hConOut, ' ', NumCells,
+ coord, &dummy))
+ {
+ return FALSE;
+ }
+ if (!FillConsoleOutputAttribute(g_hConOut, wAttribute, NumCells,
+ coord, &dummy))
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/*
+ * FitConsoleWindow()
+ * Description:
+ * Checks if the console window will fit within given buffer dimensions.
+ * Also, if requested, will shrink the window to fit.
+ * Returns:
+ * TRUE on success
+ */
+ static BOOL
+FitConsoleWindow(
+ COORD dwBufferSize,
+ BOOL WantAdjust)
+{
+ CONSOLE_SCREEN_BUFFER_INFO csbi;
+ COORD dwWindowSize;
+ BOOL NeedAdjust = FALSE;
+
+ if (GetConsoleScreenBufferInfo(g_hConOut, &csbi))
+ {
+ /*
+ * A buffer resize will fail if the current console window does
+ * not lie completely within that buffer. To avoid this, we might
+ * have to move and possibly shrink the window.
+ */
+ if (csbi.srWindow.Right >= dwBufferSize.X)
+ {
+ dwWindowSize.X = SRWIDTH(csbi.srWindow);
+ if (dwWindowSize.X > dwBufferSize.X)
+ dwWindowSize.X = dwBufferSize.X;
+ csbi.srWindow.Right = dwBufferSize.X - 1;
+ csbi.srWindow.Left = dwBufferSize.X - dwWindowSize.X;
+ NeedAdjust = TRUE;
+ }
+ if (csbi.srWindow.Bottom >= dwBufferSize.Y)
+ {
+ dwWindowSize.Y = SRHEIGHT(csbi.srWindow);
+ if (dwWindowSize.Y > dwBufferSize.Y)
+ dwWindowSize.Y = dwBufferSize.Y;
+ csbi.srWindow.Bottom = dwBufferSize.Y - 1;
+ csbi.srWindow.Top = dwBufferSize.Y - dwWindowSize.Y;
+ NeedAdjust = TRUE;
+ }
+ if (NeedAdjust && WantAdjust)
+ {
+ if (!SetConsoleWindowInfo(g_hConOut, TRUE, &csbi.srWindow))
+ return FALSE;
+ }
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+typedef struct ConsoleBufferStruct
+{
+ BOOL IsValid;
+ CONSOLE_SCREEN_BUFFER_INFO Info;
+ PCHAR_INFO Buffer;
+ COORD BufferSize;
+ PSMALL_RECT Regions;
+ int NumRegions;
+} ConsoleBuffer;
+
+/*
+ * SaveConsoleBuffer()
+ * Description:
+ * Saves important information about the console buffer, including the
+ * actual buffer contents. The saved information is suitable for later
+ * restoration by RestoreConsoleBuffer().
+ * Returns:
+ * TRUE if all information was saved; FALSE otherwise
+ * If FALSE, still sets cb->IsValid if buffer characteristics were saved.
+ */
+ static BOOL
+SaveConsoleBuffer(
+ ConsoleBuffer *cb)
+{
+ DWORD NumCells;
+ COORD BufferCoord;
+ SMALL_RECT ReadRegion;
+ WORD Y, Y_incr;
+ int i, numregions;
+
+ if (cb == NULL)
+ return FALSE;
+
+ if (!GetConsoleScreenBufferInfo(g_hConOut, &cb->Info))
+ {
+ cb->IsValid = FALSE;
+ return FALSE;
+ }
+ cb->IsValid = TRUE;
+
+ /*
+ * Allocate a buffer large enough to hold the entire console screen
+ * buffer. If this ConsoleBuffer structure has already been initialized
+ * with a buffer of the correct size, then just use that one.
+ */
+ if (!cb->IsValid || cb->Buffer == NULL ||
+ cb->BufferSize.X != cb->Info.dwSize.X ||
+ cb->BufferSize.Y != cb->Info.dwSize.Y)
+ {
+ cb->BufferSize.X = cb->Info.dwSize.X;
+ cb->BufferSize.Y = cb->Info.dwSize.Y;
+ NumCells = cb->BufferSize.X * cb->BufferSize.Y;
+ vim_free(cb->Buffer);
+ cb->Buffer = (PCHAR_INFO)alloc(NumCells * sizeof(CHAR_INFO));
+ if (cb->Buffer == NULL)
+ return FALSE;
+ }
+
+ /*
+ * We will now copy the console screen buffer into our buffer.
+ * ReadConsoleOutput() seems to be limited as far as how much you
+ * can read at a time. Empirically, this number seems to be about
+ * 12000 cells (rows * columns). Start at position (0, 0) and copy
+ * in chunks until it is all copied. The chunks will all have the
+ * same horizontal characteristics, so initialize them now. The
+ * height of each chunk will be (12000 / width).
+ */
+ BufferCoord.X = 0;
+ ReadRegion.Left = 0;
+ ReadRegion.Right = cb->Info.dwSize.X - 1;
+ Y_incr = 12000 / cb->Info.dwSize.X;
+
+ numregions = (cb->Info.dwSize.Y + Y_incr - 1) / Y_incr;
+ if (cb->Regions == NULL || numregions != cb->NumRegions)
+ {
+ cb->NumRegions = numregions;
+ vim_free(cb->Regions);
+ cb->Regions = (PSMALL_RECT)alloc(cb->NumRegions * sizeof(SMALL_RECT));
+ if (cb->Regions == NULL)
+ {
+ VIM_CLEAR(cb->Buffer);
+ return FALSE;
+ }
+ }
+
+ for (i = 0, Y = 0; i < cb->NumRegions; i++, Y += Y_incr)
+ {
+ /*
+ * Read into position (0, Y) in our buffer.
+ */
+ BufferCoord.Y = Y;
+ /*
+ * Read the region whose top left corner is (0, Y) and whose bottom
+ * right corner is (width - 1, Y + Y_incr - 1). This should define
+ * a region of size width by Y_incr. Don't worry if this region is
+ * too large for the remaining buffer; it will be cropped.
+ */
+ ReadRegion.Top = Y;
+ ReadRegion.Bottom = Y + Y_incr - 1;
+ if (!ReadConsoleOutputW(g_hConOut, /* output handle */
+ cb->Buffer, /* our buffer */
+ cb->BufferSize, /* dimensions of our buffer */
+ BufferCoord, /* offset in our buffer */
+ &ReadRegion)) /* region to save */
+ {
+ VIM_CLEAR(cb->Buffer);
+ VIM_CLEAR(cb->Regions);
+ return FALSE;
+ }
+ cb->Regions[i] = ReadRegion;
+ }
+
+ return TRUE;
+}
+
+/*
+ * RestoreConsoleBuffer()
+ * Description:
+ * Restores important information about the console buffer, including the
+ * actual buffer contents, if desired. The information to restore is in
+ * the same format used by SaveConsoleBuffer().
+ * Returns:
+ * TRUE on success
+ */
+ static BOOL
+RestoreConsoleBuffer(
+ ConsoleBuffer *cb,
+ BOOL RestoreScreen)
+{
+ COORD BufferCoord;
+ SMALL_RECT WriteRegion;
+ int i;
+
+ if (cb == NULL || !cb->IsValid)
+ return FALSE;
+
+ /*
+ * Before restoring the buffer contents, clear the current buffer, and
+ * restore the cursor position and window information. Doing this now
+ * prevents old buffer contents from "flashing" onto the screen.
+ */
+ if (RestoreScreen)
+ ClearConsoleBuffer(cb->Info.wAttributes);
+
+ FitConsoleWindow(cb->Info.dwSize, TRUE);
+ if (!SetConsoleScreenBufferSize(g_hConOut, cb->Info.dwSize))
+ return FALSE;
+ if (!SetConsoleTextAttribute(g_hConOut, cb->Info.wAttributes))
+ return FALSE;
+
+ if (!RestoreScreen)
+ {
+ /*
+ * No need to restore the screen buffer contents, so we're done.
+ */
+ return TRUE;
+ }
+
+ if (!SetConsoleCursorPosition(g_hConOut, cb->Info.dwCursorPosition))
+ return FALSE;
+ if (!SetConsoleWindowInfo(g_hConOut, TRUE, &cb->Info.srWindow))
+ return FALSE;
+
+ /*
+ * Restore the screen buffer contents.
+ */
+ if (cb->Buffer != NULL)
+ {
+ for (i = 0; i < cb->NumRegions; i++)
+ {
+ BufferCoord.X = cb->Regions[i].Left;
+ BufferCoord.Y = cb->Regions[i].Top;
+ WriteRegion = cb->Regions[i];
+ if (!WriteConsoleOutputW(g_hConOut, /* output handle */
+ cb->Buffer, /* our buffer */
+ cb->BufferSize, /* dimensions of our buffer */
+ BufferCoord, /* offset in our buffer */
+ &WriteRegion)) /* region to restore */
+ {
+ return FALSE;
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+#define FEAT_RESTORE_ORIG_SCREEN
+#ifdef FEAT_RESTORE_ORIG_SCREEN
+static ConsoleBuffer g_cbOrig = { 0 };
+#endif
+static ConsoleBuffer g_cbNonTermcap = { 0 };
+static ConsoleBuffer g_cbTermcap = { 0 };
+
+#ifdef FEAT_TITLE
+#ifdef __BORLANDC__
+typedef HWND (__stdcall *GETCONSOLEWINDOWPROC)(VOID);
+#else
+typedef HWND (WINAPI *GETCONSOLEWINDOWPROC)(VOID);
+#endif
+char g_szOrigTitle[256] = { 0 };
+HWND g_hWnd = NULL; /* also used in os_mswin.c */
+static HICON g_hOrigIconSmall = NULL;
+static HICON g_hOrigIcon = NULL;
+static HICON g_hVimIcon = NULL;
+static BOOL g_fCanChangeIcon = FALSE;
+
+/* ICON* are not defined in VC++ 4.0 */
+#ifndef ICON_SMALL
+#define ICON_SMALL 0
+#endif
+#ifndef ICON_BIG
+#define ICON_BIG 1
+#endif
+/*
+ * GetConsoleIcon()
+ * Description:
+ * Attempts to retrieve the small icon and/or the big icon currently in
+ * use by a given window.
+ * Returns:
+ * TRUE on success
+ */
+ static BOOL
+GetConsoleIcon(
+ HWND hWnd,
+ HICON *phIconSmall,
+ HICON *phIcon)
+{
+ if (hWnd == NULL)
+ return FALSE;
+
+ if (phIconSmall != NULL)
+ *phIconSmall = (HICON)SendMessage(hWnd, WM_GETICON,
+ (WPARAM)ICON_SMALL, (LPARAM)0);
+ if (phIcon != NULL)
+ *phIcon = (HICON)SendMessage(hWnd, WM_GETICON,
+ (WPARAM)ICON_BIG, (LPARAM)0);
+ return TRUE;
+}
+
+/*
+ * SetConsoleIcon()
+ * Description:
+ * Attempts to change the small icon and/or the big icon currently in
+ * use by a given window.
+ * Returns:
+ * TRUE on success
+ */
+ static BOOL
+SetConsoleIcon(
+ HWND hWnd,
+ HICON hIconSmall,
+ HICON hIcon)
+{
+ if (hWnd == NULL)
+ return FALSE;
+
+ if (hIconSmall != NULL)
+ SendMessage(hWnd, WM_SETICON,
+ (WPARAM)ICON_SMALL, (LPARAM)hIconSmall);
+ if (hIcon != NULL)
+ SendMessage(hWnd, WM_SETICON,
+ (WPARAM)ICON_BIG, (LPARAM) hIcon);
+ return TRUE;
+}
+
+/*
+ * SaveConsoleTitleAndIcon()
+ * Description:
+ * Saves the current console window title in g_szOrigTitle, for later
+ * restoration. Also, attempts to obtain a handle to the console window,
+ * and use it to save the small and big icons currently in use by the
+ * console window. This is not always possible on some versions of Windows;
+ * nor is it possible when running Vim remotely using Telnet (since the
+ * console window the user sees is owned by a remote process).
+ */
+ static void
+SaveConsoleTitleAndIcon(void)
+{
+ /* Save the original title. */
+ if (!GetConsoleTitle(g_szOrigTitle, sizeof(g_szOrigTitle)))
+ return;
+
+ /*
+ * Obtain a handle to the console window using GetConsoleWindow() from
+ * KERNEL32.DLL; we need to handle in order to change the window icon.
+ * This function only exists on NT-based Windows, starting with Windows
+ * 2000. On older operating systems, we can't change the window icon
+ * anyway.
+ */
+ g_hWnd = GetConsoleWindow();
+ if (g_hWnd == NULL)
+ return;
+
+ /* Save the original console window icon. */
+ GetConsoleIcon(g_hWnd, &g_hOrigIconSmall, &g_hOrigIcon);
+ if (g_hOrigIconSmall == NULL || g_hOrigIcon == NULL)
+ return;
+
+ /* Extract the first icon contained in the Vim executable. */
+ if (mch_icon_load((HANDLE *)&g_hVimIcon) == FAIL || g_hVimIcon == NULL)
+ g_hVimIcon = ExtractIcon(NULL, (LPCSTR)exe_name, 0);
+ if (g_hVimIcon != NULL)
+ g_fCanChangeIcon = TRUE;
+}
+#endif
+
+static int g_fWindInitCalled = FALSE;
+static int g_fTermcapMode = FALSE;
+static CONSOLE_CURSOR_INFO g_cci;
+static DWORD g_cmodein = 0;
+static DWORD g_cmodeout = 0;
+
+/*
+ * non-GUI version of mch_init().
+ */
+ void
+mch_init(void)
+{
+#ifndef FEAT_RESTORE_ORIG_SCREEN
+ CONSOLE_SCREEN_BUFFER_INFO csbi;
+#endif
+#ifndef __MINGW32__
+ extern int _fmode;
+#endif
+
+ /* Silently handle invalid parameters to CRT functions */
+ SET_INVALID_PARAM_HANDLER;
+
+ /* Let critical errors result in a failure, not in a dialog box. Required
+ * for the timestamp test to work on removed floppies. */
+ SetErrorMode(SEM_FAILCRITICALERRORS);
+
+ _fmode = O_BINARY; /* we do our own CR-LF translation */
+ out_flush();
+
+ /* Obtain handles for the standard Console I/O devices */
+ if (read_cmd_fd == 0)
+ g_hConIn = GetStdHandle(STD_INPUT_HANDLE);
+ else
+ create_conin();
+ g_hConOut = GetStdHandle(STD_OUTPUT_HANDLE);
+
+#ifdef FEAT_RESTORE_ORIG_SCREEN
+ /* Save the initial console buffer for later restoration */
+ SaveConsoleBuffer(&g_cbOrig);
+ g_attrCurrent = g_attrDefault = g_cbOrig.Info.wAttributes;
+#else
+ /* Get current text attributes */
+ GetConsoleScreenBufferInfo(g_hConOut, &csbi);
+ g_attrCurrent = g_attrDefault = csbi.wAttributes;
+#endif
+ if (cterm_normal_fg_color == 0)
+ cterm_normal_fg_color = (g_attrCurrent & 0xf) + 1;
+ if (cterm_normal_bg_color == 0)
+ cterm_normal_bg_color = ((g_attrCurrent >> 4) & 0xf) + 1;
+
+ // Fg and Bg color index nunmber at startup
+ g_color_index_fg = g_attrDefault & 0xf;
+ g_color_index_bg = (g_attrDefault >> 4) & 0xf;
+
+ /* set termcap codes to current text attributes */
+ update_tcap(g_attrCurrent);
+
+ GetConsoleCursorInfo(g_hConOut, &g_cci);
+ GetConsoleMode(g_hConIn, &g_cmodein);
+ GetConsoleMode(g_hConOut, &g_cmodeout);
+
+#ifdef FEAT_TITLE
+ SaveConsoleTitleAndIcon();
+ /*
+ * Set both the small and big icons of the console window to Vim's icon.
+ * Note that Vim presently only has one size of icon (32x32), but it
+ * automatically gets scaled down to 16x16 when setting the small icon.
+ */
+ if (g_fCanChangeIcon)
+ SetConsoleIcon(g_hWnd, g_hVimIcon, g_hVimIcon);
+#endif
+
+ ui_get_shellsize();
+
+#ifdef MCH_WRITE_DUMP
+ fdDump = fopen("dump", "wt");
+
+ if (fdDump)
+ {
+ time_t t;
+
+ time(&t);
+ fputs(ctime(&t), fdDump);
+ fflush(fdDump);
+ }
+#endif
+
+ g_fWindInitCalled = TRUE;
+
+#ifdef FEAT_MOUSE
+ g_fMouseAvail = GetSystemMetrics(SM_MOUSEPRESENT);
+#endif
+
+#ifdef FEAT_CLIPBOARD
+ win_clip_init();
+#endif
+
+ vtp_flag_init();
+ vtp_init();
+}
+
+/*
+ * non-GUI version of mch_exit().
+ * Shut down and exit with status `r'
+ * Careful: mch_exit() may be called before mch_init()!
+ */
+ void
+mch_exit(int r)
+{
+ exiting = TRUE;
+
+ vtp_exit();
+
+ stoptermcap();
+ if (g_fWindInitCalled)
+ settmode(TMODE_COOK);
+
+ ml_close_all(TRUE); /* remove all memfiles */
+
+ if (g_fWindInitCalled)
+ {
+#ifdef FEAT_TITLE
+ mch_restore_title(SAVE_RESTORE_BOTH);
+ /*
+ * Restore both the small and big icons of the console window to
+ * what they were at startup. Don't do this when the window is
+ * closed, Vim would hang here.
+ */
+ if (g_fCanChangeIcon && !g_fForceExit)
+ SetConsoleIcon(g_hWnd, g_hOrigIconSmall, g_hOrigIcon);
+#endif
+
+#ifdef MCH_WRITE_DUMP
+ if (fdDump)
+ {
+ time_t t;
+
+ time(&t);
+ fputs(ctime(&t), fdDump);
+ fclose(fdDump);
+ }
+ fdDump = NULL;
+#endif
+ }
+
+ SetConsoleCursorInfo(g_hConOut, &g_cci);
+ SetConsoleMode(g_hConIn, g_cmodein);
+ SetConsoleMode(g_hConOut, g_cmodeout);
+
+#ifdef DYNAMIC_GETTEXT
+ dyn_libintl_end();
+#endif
+
+ exit(r);
+}
+#endif /* !FEAT_GUI_W32 */
+
+/*
+ * Do we have an interactive window?
+ */
+ int
+mch_check_win(
+ int argc UNUSED,
+ char **argv UNUSED)
+{
+ get_exe_name();
+
+#ifdef FEAT_GUI_W32
+ return OK; /* GUI always has a tty */
+#else
+ if (isatty(1))
+ return OK;
+ return FAIL;
+#endif
+}
+
+
+/*
+ * fname_casew(): Wide version of fname_case(). Set the case of the file name,
+ * if it already exists. When "len" is > 0, also expand short to long
+ * filenames.
+ * Return FAIL if wide functions are not available, OK otherwise.
+ * NOTE: much of this is identical to fname_case(), keep in sync!
+ */
+ static int
+fname_casew(
+ WCHAR *name,
+ int len)
+{
+ WCHAR szTrueName[_MAX_PATH + 2];
+ WCHAR szTrueNameTemp[_MAX_PATH + 2];
+ WCHAR *ptrue, *ptruePrev;
+ WCHAR *porig, *porigPrev;
+ int flen;
+ WIN32_FIND_DATAW fb;
+ HANDLE hFind = INVALID_HANDLE_VALUE;
+ int c;
+ int slen;
+
+ flen = (int)wcslen(name);
+ if (flen > _MAX_PATH)
+ return OK;
+
+ /* slash_adjust(name) not needed, already adjusted by fname_case(). */
+
+ /* Build the new name in szTrueName[] one component at a time. */
+ porig = name;
+ ptrue = szTrueName;
+
+ if (iswalpha(porig[0]) && porig[1] == L':')
+ {
+ /* copy leading drive letter */
+ *ptrue++ = *porig++;
+ *ptrue++ = *porig++;
+ }
+ *ptrue = NUL; /* in case nothing follows */
+
+ while (*porig != NUL)
+ {
+ /* copy \ characters */
+ while (*porig == psepc)
+ *ptrue++ = *porig++;
+
+ ptruePrev = ptrue;
+ porigPrev = porig;
+ while (*porig != NUL && *porig != psepc)
+ {
+ *ptrue++ = *porig++;
+ }
+ *ptrue = NUL;
+
+ /* To avoid a slow failure append "\*" when searching a directory,
+ * server or network share. */
+ wcscpy(szTrueNameTemp, szTrueName);
+ slen = (int)wcslen(szTrueNameTemp);
+ if (*porig == psepc && slen + 2 < _MAX_PATH)
+ wcscpy(szTrueNameTemp + slen, L"\\*");
+
+ /* Skip "", "." and "..". */
+ if (ptrue > ptruePrev
+ && (ptruePrev[0] != L'.'
+ || (ptruePrev[1] != NUL
+ && (ptruePrev[1] != L'.' || ptruePrev[2] != NUL)))
+ && (hFind = FindFirstFileW(szTrueNameTemp, &fb))
+ != INVALID_HANDLE_VALUE)
+ {
+ c = *porig;
+ *porig = NUL;
+
+ /* Only use the match when it's the same name (ignoring case) or
+ * expansion is allowed and there is a match with the short name
+ * and there is enough room. */
+ if (_wcsicoll(porigPrev, fb.cFileName) == 0
+ || (len > 0
+ && (_wcsicoll(porigPrev, fb.cAlternateFileName) == 0
+ && (int)(ptruePrev - szTrueName)
+ + (int)wcslen(fb.cFileName) < len)))
+ {
+ wcscpy(ptruePrev, fb.cFileName);
+
+ /* Look for exact match and prefer it if found. Must be a
+ * long name, otherwise there would be only one match. */
+ while (FindNextFileW(hFind, &fb))
+ {
+ if (*fb.cAlternateFileName != NUL
+ && (wcscoll(porigPrev, fb.cFileName) == 0
+ || (len > 0
+ && (_wcsicoll(porigPrev,
+ fb.cAlternateFileName) == 0
+ && (int)(ptruePrev - szTrueName)
+ + (int)wcslen(fb.cFileName) < len))))
+ {
+ wcscpy(ptruePrev, fb.cFileName);
+ break;
+ }
+ }
+ }
+ FindClose(hFind);
+ *porig = c;
+ ptrue = ptruePrev + wcslen(ptruePrev);
+ }
+ }
+
+ wcscpy(name, szTrueName);
+ return OK;
+}
+
+/*
+ * fname_case(): Set the case of the file name, if it already exists.
+ * When "len" is > 0, also expand short to long filenames.
+ * NOTE: much of this is identical to fname_casew(), keep in sync!
+ */
+ void
+fname_case(
+ char_u *name,
+ int len)
+{
+ char szTrueName[_MAX_PATH + 2];
+ char szTrueNameTemp[_MAX_PATH + 2];
+ char *ptrue, *ptruePrev;
+ char *porig, *porigPrev;
+ int flen;
+ WIN32_FIND_DATA fb;
+ HANDLE hFind;
+ int c;
+ int slen;
+
+ flen = (int)STRLEN(name);
+ if (flen == 0)
+ return;
+
+ slash_adjust(name);
+
+ if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+ {
+ WCHAR *p = enc_to_utf16(name, NULL);
+
+ if (p != NULL)
+ {
+ char_u *q;
+ WCHAR buf[_MAX_PATH + 1];
+
+ wcsncpy(buf, p, _MAX_PATH);
+ buf[_MAX_PATH] = L'\0';
+ vim_free(p);
+
+ if (fname_casew(buf, (len > 0) ? _MAX_PATH : 0) == OK)
+ {
+ q = utf16_to_enc(buf, NULL);
+ if (q != NULL)
+ {
+ vim_strncpy(name, q, (len > 0) ? len - 1 : flen);
+ vim_free(q);
+ return;
+ }
+ }
+ }
+ return;
+ }
+
+ /* If 'enc' is utf-8, flen can be larger than _MAX_PATH.
+ * So we should check this after calling wide function. */
+ if (flen > _MAX_PATH)
+ return;
+
+ /* Build the new name in szTrueName[] one component at a time. */
+ porig = (char *)name;
+ ptrue = szTrueName;
+
+ if (isalpha(porig[0]) && porig[1] == ':')
+ {
+ /* copy leading drive letter */
+ *ptrue++ = *porig++;
+ *ptrue++ = *porig++;
+ }
+ *ptrue = NUL; /* in case nothing follows */
+
+ while (*porig != NUL)
+ {
+ /* copy \ characters */
+ while (*porig == psepc)
+ *ptrue++ = *porig++;
+
+ ptruePrev = ptrue;
+ porigPrev = porig;
+ while (*porig != NUL && *porig != psepc)
+ {
+ int l;
+
+ if (enc_dbcs)
+ {
+ l = (*mb_ptr2len)((char_u *)porig);
+ while (--l >= 0)
+ *ptrue++ = *porig++;
+ }
+ else
+ *ptrue++ = *porig++;
+ }
+ *ptrue = NUL;
+
+ /* To avoid a slow failure append "\*" when searching a directory,
+ * server or network share. */
+ STRCPY(szTrueNameTemp, szTrueName);
+ slen = (int)strlen(szTrueNameTemp);
+ if (*porig == psepc && slen + 2 < _MAX_PATH)
+ STRCPY(szTrueNameTemp + slen, "\\*");
+
+ /* Skip "", "." and "..". */
+ if (ptrue > ptruePrev
+ && (ptruePrev[0] != '.'
+ || (ptruePrev[1] != NUL
+ && (ptruePrev[1] != '.' || ptruePrev[2] != NUL)))
+ && (hFind = FindFirstFile(szTrueNameTemp, &fb))
+ != INVALID_HANDLE_VALUE)
+ {
+ c = *porig;
+ *porig = NUL;
+
+ /* Only use the match when it's the same name (ignoring case) or
+ * expansion is allowed and there is a match with the short name
+ * and there is enough room. */
+ if (_stricoll(porigPrev, fb.cFileName) == 0
+ || (len > 0
+ && (_stricoll(porigPrev, fb.cAlternateFileName) == 0
+ && (int)(ptruePrev - szTrueName)
+ + (int)strlen(fb.cFileName) < len)))
+ {
+ STRCPY(ptruePrev, fb.cFileName);
+
+ /* Look for exact match and prefer it if found. Must be a
+ * long name, otherwise there would be only one match. */
+ while (FindNextFile(hFind, &fb))
+ {
+ if (*fb.cAlternateFileName != NUL
+ && (strcoll(porigPrev, fb.cFileName) == 0
+ || (len > 0
+ && (_stricoll(porigPrev,
+ fb.cAlternateFileName) == 0
+ && (int)(ptruePrev - szTrueName)
+ + (int)strlen(fb.cFileName) < len))))
+ {
+ STRCPY(ptruePrev, fb.cFileName);
+ break;
+ }
+ }
+ }
+ FindClose(hFind);
+ *porig = c;
+ ptrue = ptruePrev + strlen(ptruePrev);
+ }
+ }
+
+ STRCPY(name, szTrueName);
+}
+
+
+/*
+ * Insert user name in s[len].
+ */
+ int
+mch_get_user_name(
+ char_u *s,
+ int len)
+{
+ char szUserName[256 + 1]; /* UNLEN is 256 */
+ DWORD cch = sizeof szUserName;
+
+ if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+ {
+ WCHAR wszUserName[256 + 1]; /* UNLEN is 256 */
+ DWORD wcch = sizeof(wszUserName) / sizeof(WCHAR);
+
+ if (GetUserNameW(wszUserName, &wcch))
+ {
+ char_u *p = utf16_to_enc(wszUserName, NULL);
+
+ if (p != NULL)
+ {
+ vim_strncpy(s, p, len - 1);
+ vim_free(p);
+ return OK;
+ }
+ }
+ }
+ if (GetUserName(szUserName, &cch))
+ {
+ vim_strncpy(s, (char_u *)szUserName, len - 1);
+ return OK;
+ }
+ s[0] = NUL;
+ return FAIL;
+}
+
+
+/*
+ * Insert host name in s[len].
+ */
+ void
+mch_get_host_name(
+ char_u *s,
+ int len)
+{
+ DWORD cch = len;
+
+ if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+ {
+ WCHAR wszHostName[256 + 1];
+ DWORD wcch = sizeof(wszHostName) / sizeof(WCHAR);
+
+ if (GetComputerNameW(wszHostName, &wcch))
+ {
+ char_u *p = utf16_to_enc(wszHostName, NULL);
+
+ if (p != NULL)
+ {
+ vim_strncpy(s, p, len - 1);
+ vim_free(p);
+ return;
+ }
+ }
+ }
+ if (!GetComputerName((LPSTR)s, &cch))
+ vim_strncpy(s, (char_u *)"PC (Win32 Vim)", len - 1);
+}
+
+
+/*
+ * return process ID
+ */
+ long
+mch_get_pid(void)
+{
+ return (long)GetCurrentProcessId();
+}
+
+
+/*
+ * Get name of current directory into buffer 'buf' of length 'len' bytes.
+ * Return OK for success, FAIL for failure.
+ */
+ int
+mch_dirname(
+ char_u *buf,
+ int len)
+{
+ char_u abuf[_MAX_PATH + 1];
+ DWORD lfnlen;
+
+ /*
+ * Originally this was:
+ * return (getcwd(buf, len) != NULL ? OK : FAIL);
+ * But the Win32s known bug list says that getcwd() doesn't work
+ * so use the Win32 system call instead. <Negri>
+ */
+ if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+ {
+ WCHAR wbuf[_MAX_PATH + 1];
+
+ if (GetCurrentDirectoryW(_MAX_PATH, wbuf) != 0)
+ {
+ WCHAR wcbuf[_MAX_PATH + 1];
+ char_u *p = NULL;
+
+ if (GetLongPathNameW(wbuf, wcbuf, _MAX_PATH) != 0)
+ {
+ p = utf16_to_enc(wcbuf, NULL);
+ if (STRLEN(p) >= (size_t)len)
+ {
+ // long path name is too long, fall back to short one
+ vim_free(p);
+ p = NULL;
+ }
+ }
+ if (p == NULL)
+ p = utf16_to_enc(wbuf, NULL);
+
+ if (p != NULL)
+ {
+ vim_strncpy(buf, p, len - 1);
+ vim_free(p);
+ return OK;
+ }
+ }
+ return FAIL;
+ }
+ if (GetCurrentDirectory(len, (LPSTR)buf) == 0)
+ return FAIL;
+ lfnlen = GetLongPathNameA((LPCSTR)buf, (LPSTR)abuf, _MAX_PATH);
+ if (lfnlen == 0 || lfnlen >= (DWORD)len)
+ // Failed to get long path name or it's too long: fall back to the
+ // short path name.
+ return OK;
+
+ STRCPY(buf, abuf);
+ return OK;
+}
+
+/*
+ * Get file permissions for "name".
+ * Return mode_t or -1 for error.
+ */
+ long
+mch_getperm(char_u *name)
+{
+ stat_T st;
+ int n;
+
+ n = mch_stat((char *)name, &st);
+ return n == 0 ? (long)(unsigned short)st.st_mode : -1L;
+}
+
+
+/*
+ * Set file permission for "name" to "perm".
+ *
+ * Return FAIL for failure, OK otherwise.
+ */
+ int
+mch_setperm(char_u *name, long perm)
+{
+ long n = -1;
+
+ if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+ {
+ WCHAR *p = enc_to_utf16(name, NULL);
+
+ if (p != NULL)
+ {
+ n = _wchmod(p, perm);
+ vim_free(p);
+ if (n == -1)
+ return FAIL;
+ }
+ }
+ if (n == -1)
+ n = _chmod((const char *)name, perm);
+ if (n == -1)
+ return FAIL;
+
+ win32_set_archive(name);
+
+ return OK;
+}
+
+/*
+ * Set hidden flag for "name".
+ */
+ void
+mch_hide(char_u *name)
+{
+ int attrs = win32_getattrs(name);
+ if (attrs == -1)
+ return;
+
+ attrs |= FILE_ATTRIBUTE_HIDDEN;
+ win32_setattrs(name, attrs);
+}
+
+/*
+ * Return TRUE if file "name" exists and is hidden.
+ */
+ int
+mch_ishidden(char_u *name)
+{
+ int f = win32_getattrs(name);
+
+ if (f == -1)
+ return FALSE; /* file does not exist at all */
+
+ return (f & FILE_ATTRIBUTE_HIDDEN) != 0;
+}
+
+/*
+ * return TRUE if "name" is a directory
+ * return FALSE if "name" is not a directory or upon error
+ */
+ int
+mch_isdir(char_u *name)
+{
+ int f = win32_getattrs(name);
+
+ if (f == -1)
+ return FALSE; /* file does not exist at all */
+
+ return (f & FILE_ATTRIBUTE_DIRECTORY) != 0;
+}
+
+/*
+ * return TRUE if "name" is a directory, NOT a symlink to a directory
+ * return FALSE if "name" is not a directory
+ * return FALSE for error
+ */
+ int
+mch_isrealdir(char_u *name)
+{
+ return mch_isdir(name) && !mch_is_symbolic_link(name);
+}
+
+/*
+ * Create directory "name".
+ * Return 0 on success, -1 on error.
+ */
+ int
+mch_mkdir(char_u *name)
+{
+ if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+ {
+ WCHAR *p;
+ int retval;
+
+ p = enc_to_utf16(name, NULL);
+ if (p == NULL)
+ return -1;
+ retval = _wmkdir(p);
+ vim_free(p);
+ return retval;
+ }
+ return _mkdir((const char *)name);
+}
+
+/*
+ * Delete directory "name".
+ * Return 0 on success, -1 on error.
+ */
+ int
+mch_rmdir(char_u *name)
+{
+ if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+ {
+ WCHAR *p;
+ int retval;
+
+ p = enc_to_utf16(name, NULL);
+ if (p == NULL)
+ return -1;
+ retval = _wrmdir(p);
+ vim_free(p);
+ return retval;
+ }
+ return _rmdir((const char *)name);
+}
+
+/*
+ * Return TRUE if file "fname" has more than one link.
+ */
+ int
+mch_is_hard_link(char_u *fname)
+{
+ BY_HANDLE_FILE_INFORMATION info;
+
+ return win32_fileinfo(fname, &info) == FILEINFO_OK
+ && info.nNumberOfLinks > 1;
+}
+
+/*
+ * Return TRUE if "name" is a symbolic link (or a junction).
+ */
+ int
+mch_is_symbolic_link(char_u *name)
+{
+ HANDLE hFind;
+ int res = FALSE;
+ WIN32_FIND_DATAA findDataA;
+ DWORD fileFlags = 0, reparseTag = 0;
+ WCHAR *wn = NULL;
+ WIN32_FIND_DATAW findDataW;
+
+ if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+ wn = enc_to_utf16(name, NULL);
+ if (wn != NULL)
+ {
+ hFind = FindFirstFileW(wn, &findDataW);
+ vim_free(wn);
+ if (hFind != INVALID_HANDLE_VALUE)
+ {
+ fileFlags = findDataW.dwFileAttributes;
+ reparseTag = findDataW.dwReserved0;
+ }
+ }
+ else
+ {
+ hFind = FindFirstFile((LPCSTR)name, &findDataA);
+ if (hFind != INVALID_HANDLE_VALUE)
+ {
+ fileFlags = findDataA.dwFileAttributes;
+ reparseTag = findDataA.dwReserved0;
+ }
+ }
+
+ if (hFind != INVALID_HANDLE_VALUE)
+ FindClose(hFind);
+
+ if ((fileFlags & FILE_ATTRIBUTE_REPARSE_POINT)
+ && (reparseTag == IO_REPARSE_TAG_SYMLINK
+ || reparseTag == IO_REPARSE_TAG_MOUNT_POINT))
+ res = TRUE;
+
+ return res;
+}
+
+/*
+ * Return TRUE if file "fname" has more than one link or if it is a symbolic
+ * link.
+ */
+ int
+mch_is_linked(char_u *fname)
+{
+ if (mch_is_hard_link(fname) || mch_is_symbolic_link(fname))
+ return TRUE;
+ return FALSE;
+}
+
+/*
+ * Get the by-handle-file-information for "fname".
+ * Returns FILEINFO_OK when OK.
+ * returns FILEINFO_ENC_FAIL when enc_to_utf16() failed.
+ * Returns FILEINFO_READ_FAIL when CreateFile() failed.
+ * Returns FILEINFO_INFO_FAIL when GetFileInformationByHandle() failed.
+ */
+ int
+win32_fileinfo(char_u *fname, BY_HANDLE_FILE_INFORMATION *info)
+{
+ HANDLE hFile;
+ int res = FILEINFO_READ_FAIL;
+ WCHAR *wn = NULL;
+
+ if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+ {
+ wn = enc_to_utf16(fname, NULL);
+ if (wn == NULL)
+ return FILEINFO_ENC_FAIL;
+ }
+ if (wn != NULL)
+ {
+ hFile = CreateFileW(wn, /* file name */
+ GENERIC_READ, /* access mode */
+ FILE_SHARE_READ | FILE_SHARE_WRITE, /* share mode */
+ NULL, /* security descriptor */
+ OPEN_EXISTING, /* creation disposition */
+ FILE_FLAG_BACKUP_SEMANTICS, /* file attributes */
+ NULL); /* handle to template file */
+ vim_free(wn);
+ }
+ else
+ hFile = CreateFile((LPCSTR)fname, /* file name */
+ GENERIC_READ, /* access mode */
+ FILE_SHARE_READ | FILE_SHARE_WRITE, /* share mode */
+ NULL, /* security descriptor */
+ OPEN_EXISTING, /* creation disposition */
+ FILE_FLAG_BACKUP_SEMANTICS, /* file attributes */
+ NULL); /* handle to template file */
+
+ if (hFile != INVALID_HANDLE_VALUE)
+ {
+ if (GetFileInformationByHandle(hFile, info) != 0)
+ res = FILEINFO_OK;
+ else
+ res = FILEINFO_INFO_FAIL;
+ CloseHandle(hFile);
+ }
+
+ return res;
+}
+
+/*
+ * get file attributes for `name'
+ * -1 : error
+ * else FILE_ATTRIBUTE_* defined in winnt.h
+ */
+ static int
+win32_getattrs(char_u *name)
+{
+ int attr;
+ WCHAR *p = NULL;
+
+ if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+ p = enc_to_utf16(name, NULL);
+
+ if (p != NULL)
+ {
+ attr = GetFileAttributesW(p);
+ vim_free(p);
+ }
+ else
+ attr = GetFileAttributes((char *)name);
+
+ return attr;
+}
+
+/*
+ * set file attributes for `name' to `attrs'
+ *
+ * return -1 for failure, 0 otherwise
+ */
+ static int
+win32_setattrs(char_u *name, int attrs)
+{
+ int res;
+ WCHAR *p = NULL;
+
+ if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+ p = enc_to_utf16(name, NULL);
+
+ if (p != NULL)
+ {
+ res = SetFileAttributesW(p, attrs);
+ vim_free(p);
+ }
+ else
+ res = SetFileAttributes((char *)name, attrs);
+
+ return res ? 0 : -1;
+}
+
+/*
+ * Set archive flag for "name".
+ */
+ static int
+win32_set_archive(char_u *name)
+{
+ int attrs = win32_getattrs(name);
+ if (attrs == -1)
+ return -1;
+
+ attrs |= FILE_ATTRIBUTE_ARCHIVE;
+ return win32_setattrs(name, attrs);
+}
+
+/*
+ * Return TRUE if file or directory "name" is writable (not readonly).
+ * Strange semantics of Win32: a readonly directory is writable, but you can't
+ * delete a file. Let's say this means it is writable.
+ */
+ int
+mch_writable(char_u *name)
+{
+ int attrs = win32_getattrs(name);
+
+ return (attrs != -1 && (!(attrs & FILE_ATTRIBUTE_READONLY)
+ || (attrs & FILE_ATTRIBUTE_DIRECTORY)));
+}
+
+/*
+ * Return TRUE if "name" can be executed, FALSE if not.
+ * If "use_path" is FALSE only check if "name" is executable.
+ * When returning TRUE and "path" is not NULL save the path and set "*path" to
+ * the allocated memory.
+ */
+ int
+mch_can_exe(char_u *name, char_u **path, int use_path)
+{
+ char_u buf[_MAX_PATH];
+ int len = (int)STRLEN(name);
+ char_u *p, *saved;
+
+ if (len >= _MAX_PATH) /* safety check */
+ return FALSE;
+
+ /* Ty using the name directly when a Unix-shell like 'shell'. */
+ if (strstr((char *)gettail(p_sh), "sh") != NULL)
+ if (executable_exists((char *)name, path, use_path))
+ return TRUE;
+
+ /*
+ * Loop over all extensions in $PATHEXT.
+ */
+ p = mch_getenv("PATHEXT");
+ if (p == NULL)
+ p = (char_u *)".com;.exe;.bat;.cmd";
+ saved = vim_strsave(p);
+ if (saved == NULL)
+ return FALSE;
+ p = saved;
+ while (*p)
+ {
+ char_u *tmp = vim_strchr(p, ';');
+
+ if (tmp != NULL)
+ *tmp = NUL;
+ if (_stricoll((char *)name + len - STRLEN(p), (char *)p) == 0
+ && executable_exists((char *)name, path, use_path))
+ {
+ vim_free(saved);
+ return TRUE;
+ }
+ if (tmp == NULL)
+ break;
+ p = tmp + 1;
+ }
+ vim_free(saved);
+
+ vim_strncpy(buf, name, _MAX_PATH - 1);
+ p = mch_getenv("PATHEXT");
+ if (p == NULL)
+ p = (char_u *)".com;.exe;.bat;.cmd";
+ while (*p)
+ {
+ if (p[0] == '.' && (p[1] == NUL || p[1] == ';'))
+ {
+ /* A single "." means no extension is added. */
+ buf[len] = NUL;
+ ++p;
+ if (*p)
+ ++p;
+ }
+ else
+ copy_option_part(&p, buf + len, _MAX_PATH - len, ";");
+ if (executable_exists((char *)buf, path, use_path))
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * Check what "name" is:
+ * NODE_NORMAL: file or directory (or doesn't exist)
+ * NODE_WRITABLE: writable device, socket, fifo, etc.
+ * NODE_OTHER: non-writable things
+ */
+ int
+mch_nodetype(char_u *name)
+{
+ HANDLE hFile;
+ int type;
+ WCHAR *wn = NULL;
+
+ /* We can't open a file with a name "\\.\con" or "\\.\prn" and trying to
+ * read from it later will cause Vim to hang. Thus return NODE_WRITABLE
+ * here. */
+ if (STRNCMP(name, "\\\\.\\", 4) == 0)
+ return NODE_WRITABLE;
+
+ if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+ wn = enc_to_utf16(name, NULL);
+
+ if (wn != NULL)
+ {
+ hFile = CreateFileW(wn, /* file name */
+ GENERIC_WRITE, /* access mode */
+ 0, /* share mode */
+ NULL, /* security descriptor */
+ OPEN_EXISTING, /* creation disposition */
+ 0, /* file attributes */
+ NULL); /* handle to template file */
+ vim_free(wn);
+ }
+ else
+ hFile = CreateFile((LPCSTR)name, /* file name */
+ GENERIC_WRITE, /* access mode */
+ 0, /* share mode */
+ NULL, /* security descriptor */
+ OPEN_EXISTING, /* creation disposition */
+ 0, /* file attributes */
+ NULL); /* handle to template file */
+
+ if (hFile == INVALID_HANDLE_VALUE)
+ return NODE_NORMAL;
+
+ type = GetFileType(hFile);
+ CloseHandle(hFile);
+ if (type == FILE_TYPE_CHAR)
+ return NODE_WRITABLE;
+ if (type == FILE_TYPE_DISK)
+ return NODE_NORMAL;
+ return NODE_OTHER;
+}
+
+#ifdef HAVE_ACL
+struct my_acl
+{
+ PSECURITY_DESCRIPTOR pSecurityDescriptor;
+ PSID pSidOwner;
+ PSID pSidGroup;
+ PACL pDacl;
+ PACL pSacl;
+};
+#endif
+
+/*
+ * Return a pointer to the ACL of file "fname" in allocated memory.
+ * Return NULL if the ACL is not available for whatever reason.
+ */
+ vim_acl_T
+mch_get_acl(char_u *fname)
+{
+#ifndef HAVE_ACL
+ return (vim_acl_T)NULL;
+#else
+ struct my_acl *p = NULL;
+ DWORD err;
+
+ p = (struct my_acl *)alloc_clear((unsigned)sizeof(struct my_acl));
+ if (p != NULL)
+ {
+ WCHAR *wn = NULL;
+
+ if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+ wn = enc_to_utf16(fname, NULL);
+ if (wn != NULL)
+ {
+ /* Try to retrieve the entire security descriptor. */
+ err = GetNamedSecurityInfoW(
+ wn, // Abstract filename
+ SE_FILE_OBJECT, // File Object
+ OWNER_SECURITY_INFORMATION |
+ GROUP_SECURITY_INFORMATION |
+ DACL_SECURITY_INFORMATION |
+ SACL_SECURITY_INFORMATION,
+ &p->pSidOwner, // Ownership information.
+ &p->pSidGroup, // Group membership.
+ &p->pDacl, // Discretionary information.
+ &p->pSacl, // For auditing purposes.
+ &p->pSecurityDescriptor);
+ if (err == ERROR_ACCESS_DENIED ||
+ err == ERROR_PRIVILEGE_NOT_HELD)
+ {
+ /* Retrieve only DACL. */
+ (void)GetNamedSecurityInfoW(
+ wn,
+ SE_FILE_OBJECT,
+ DACL_SECURITY_INFORMATION,
+ NULL,
+ NULL,
+ &p->pDacl,
+ NULL,
+ &p->pSecurityDescriptor);
+ }
+ if (p->pSecurityDescriptor == NULL)
+ {
+ mch_free_acl((vim_acl_T)p);
+ p = NULL;
+ }
+ vim_free(wn);
+ }
+ else
+ {
+ /* Try to retrieve the entire security descriptor. */
+ err = GetNamedSecurityInfo(
+ (LPSTR)fname, // Abstract filename
+ SE_FILE_OBJECT, // File Object
+ OWNER_SECURITY_INFORMATION |
+ GROUP_SECURITY_INFORMATION |
+ DACL_SECURITY_INFORMATION |
+ SACL_SECURITY_INFORMATION,
+ &p->pSidOwner, // Ownership information.
+ &p->pSidGroup, // Group membership.
+ &p->pDacl, // Discretionary information.
+ &p->pSacl, // For auditing purposes.
+ &p->pSecurityDescriptor);
+ if (err == ERROR_ACCESS_DENIED ||
+ err == ERROR_PRIVILEGE_NOT_HELD)
+ {
+ /* Retrieve only DACL. */
+ (void)GetNamedSecurityInfo(
+ (LPSTR)fname,
+ SE_FILE_OBJECT,
+ DACL_SECURITY_INFORMATION,
+ NULL,
+ NULL,
+ &p->pDacl,
+ NULL,
+ &p->pSecurityDescriptor);
+ }
+ if (p->pSecurityDescriptor == NULL)
+ {
+ mch_free_acl((vim_acl_T)p);
+ p = NULL;
+ }
+ }
+ }
+
+ return (vim_acl_T)p;
+#endif
+}
+
+#ifdef HAVE_ACL
+/*
+ * Check if "acl" contains inherited ACE.
+ */
+ static BOOL
+is_acl_inherited(PACL acl)
+{
+ DWORD i;
+ ACL_SIZE_INFORMATION acl_info;
+ PACCESS_ALLOWED_ACE ace;
+
+ acl_info.AceCount = 0;
+ GetAclInformation(acl, &acl_info, sizeof(acl_info), AclSizeInformation);
+ for (i = 0; i < acl_info.AceCount; i++)
+ {
+ GetAce(acl, i, (LPVOID *)&ace);
+ if (ace->Header.AceFlags & INHERITED_ACE)
+ return TRUE;
+ }
+ return FALSE;
+}
+#endif
+
+/*
+ * Set the ACL of file "fname" to "acl" (unless it's NULL).
+ * Errors are ignored.
+ * This must only be called with "acl" equal to what mch_get_acl() returned.
+ */
+ void
+mch_set_acl(char_u *fname, vim_acl_T acl)
+{
+#ifdef HAVE_ACL
+ struct my_acl *p = (struct my_acl *)acl;
+ SECURITY_INFORMATION sec_info = 0;
+
+ if (p != NULL)
+ {
+ WCHAR *wn = NULL;
+
+ /* Set security flags */
+ if (p->pSidOwner)
+ sec_info |= OWNER_SECURITY_INFORMATION;
+ if (p->pSidGroup)
+ sec_info |= GROUP_SECURITY_INFORMATION;
+ if (p->pDacl)
+ {
+ sec_info |= DACL_SECURITY_INFORMATION;
+ /* Do not inherit its parent's DACL.
+ * If the DACL is inherited, Cygwin permissions would be changed.
+ */
+ if (!is_acl_inherited(p->pDacl))
+ sec_info |= PROTECTED_DACL_SECURITY_INFORMATION;
+ }
+ if (p->pSacl)
+ sec_info |= SACL_SECURITY_INFORMATION;
+
+ if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+ wn = enc_to_utf16(fname, NULL);
+ if (wn != NULL)
+ {
+ (void)SetNamedSecurityInfoW(
+ wn, // Abstract filename
+ SE_FILE_OBJECT, // File Object
+ sec_info,
+ p->pSidOwner, // Ownership information.
+ p->pSidGroup, // Group membership.
+ p->pDacl, // Discretionary information.
+ p->pSacl // For auditing purposes.
+ );
+ vim_free(wn);
+ }
+ else
+ {
+ (void)SetNamedSecurityInfo(
+ (LPSTR)fname, // Abstract filename
+ SE_FILE_OBJECT, // File Object
+ sec_info,
+ p->pSidOwner, // Ownership information.
+ p->pSidGroup, // Group membership.
+ p->pDacl, // Discretionary information.
+ p->pSacl // For auditing purposes.
+ );
+ }
+ }
+#endif
+}
+
+ void
+mch_free_acl(vim_acl_T acl)
+{
+#ifdef HAVE_ACL
+ struct my_acl *p = (struct my_acl *)acl;
+
+ if (p != NULL)
+ {
+ LocalFree(p->pSecurityDescriptor); // Free the memory just in case
+ vim_free(p);
+ }
+#endif
+}
+
+#ifndef FEAT_GUI_W32
+
+/*
+ * handler for ctrl-break, ctrl-c interrupts, and fatal events.
+ */
+ static BOOL WINAPI
+handler_routine(
+ DWORD dwCtrlType)
+{
+ INPUT_RECORD ir;
+ DWORD out;
+
+ switch (dwCtrlType)
+ {
+ case CTRL_C_EVENT:
+ if (ctrl_c_interrupts)
+ g_fCtrlCPressed = TRUE;
+ return TRUE;
+
+ case CTRL_BREAK_EVENT:
+ g_fCBrkPressed = TRUE;
+ ctrl_break_was_pressed = TRUE;
+ /* ReadConsoleInput is blocking, send a key event to continue. */
+ ir.EventType = KEY_EVENT;
+ ir.Event.KeyEvent.bKeyDown = TRUE;
+ ir.Event.KeyEvent.wRepeatCount = 1;
+ ir.Event.KeyEvent.wVirtualKeyCode = VK_CANCEL;
+ ir.Event.KeyEvent.wVirtualScanCode = 0;
+ ir.Event.KeyEvent.dwControlKeyState = 0;
+ ir.Event.KeyEvent.uChar.UnicodeChar = 0;
+ WriteConsoleInput(g_hConIn, &ir, 1, &out);
+ return TRUE;
+
+ /* fatal events: shut down gracefully */
+ case CTRL_CLOSE_EVENT:
+ case CTRL_LOGOFF_EVENT:
+ case CTRL_SHUTDOWN_EVENT:
+ windgoto((int)Rows - 1, 0);
+ g_fForceExit = TRUE;
+
+ vim_snprintf((char *)IObuff, IOSIZE, _("Vim: Caught %s event\n"),
+ (dwCtrlType == CTRL_CLOSE_EVENT
+ ? _("close")
+ : dwCtrlType == CTRL_LOGOFF_EVENT
+ ? _("logoff")
+ : _("shutdown")));
+#ifdef DEBUG
+ OutputDebugString(IObuff);
+#endif
+
+ preserve_exit(); /* output IObuff, preserve files and exit */
+
+ return TRUE; /* not reached */
+
+ default:
+ return FALSE;
+ }
+}
+
+
+/*
+ * set the tty in (raw) ? "raw" : "cooked" mode
+ */
+ void
+mch_settmode(int tmode)
+{
+ DWORD cmodein;
+ DWORD cmodeout;
+ BOOL bEnableHandler;
+
+ GetConsoleMode(g_hConIn, &cmodein);
+ GetConsoleMode(g_hConOut, &cmodeout);
+ if (tmode == TMODE_RAW)
+ {
+ cmodein &= ~(ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT |
+ ENABLE_ECHO_INPUT);
+#ifdef FEAT_MOUSE
+ if (g_fMouseActive)
+ cmodein |= ENABLE_MOUSE_INPUT;
+#endif
+ cmodeout &= ~(
+#ifdef FEAT_TERMGUICOLORS
+ /* Do not turn off the ENABLE_PROCESSRD_OUTPUT flag when using
+ * VTP. */
+ ((vtp_working) ? 0 : ENABLE_PROCESSED_OUTPUT) |
+#else
+ ENABLE_PROCESSED_OUTPUT |
+#endif
+ ENABLE_WRAP_AT_EOL_OUTPUT);
+ bEnableHandler = TRUE;
+ }
+ else /* cooked */
+ {
+ cmodein |= (ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT |
+ ENABLE_ECHO_INPUT);
+ cmodeout |= (ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT);
+ bEnableHandler = FALSE;
+ }
+ SetConsoleMode(g_hConIn, cmodein);
+ SetConsoleMode(g_hConOut, cmodeout);
+ SetConsoleCtrlHandler(handler_routine, bEnableHandler);
+
+#ifdef MCH_WRITE_DUMP
+ if (fdDump)
+ {
+ fprintf(fdDump, "mch_settmode(%s, in = %x, out = %x)\n",
+ tmode == TMODE_RAW ? "raw" :
+ tmode == TMODE_COOK ? "cooked" : "normal",
+ cmodein, cmodeout);
+ fflush(fdDump);
+ }
+#endif
+}
+
+
+/*
+ * Get the size of the current window in `Rows' and `Columns'
+ * Return OK when size could be determined, FAIL otherwise.
+ */
+ int
+mch_get_shellsize(void)
+{
+ CONSOLE_SCREEN_BUFFER_INFO csbi;
+
+ if (!g_fTermcapMode && g_cbTermcap.IsValid)
+ {
+ /*
+ * For some reason, we are trying to get the screen dimensions
+ * even though we are not in termcap mode. The 'Rows' and 'Columns'
+ * variables are really intended to mean the size of Vim screen
+ * while in termcap mode.
+ */
+ Rows = g_cbTermcap.Info.dwSize.Y;
+ Columns = g_cbTermcap.Info.dwSize.X;
+ }
+ else if (GetConsoleScreenBufferInfo(g_hConOut, &csbi))
+ {
+ Rows = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
+ Columns = csbi.srWindow.Right - csbi.srWindow.Left + 1;
+ }
+ else
+ {
+ Rows = 25;
+ Columns = 80;
+ }
+ return OK;
+}
+
+/*
+ * Resize console buffer to 'COORD'
+ */
+ static void
+ResizeConBuf(
+ HANDLE hConsole,
+ COORD coordScreen)
+{
+ if (!SetConsoleScreenBufferSize(hConsole, coordScreen))
+ {
+#ifdef MCH_WRITE_DUMP
+ if (fdDump)
+ {
+ fprintf(fdDump, "SetConsoleScreenBufferSize failed: %lx\n",
+ GetLastError());
+ fflush(fdDump);
+ }
+#endif
+ }
+}
+
+/*
+ * Resize console window size to 'srWindowRect'
+ */
+ static void
+ResizeWindow(
+ HANDLE hConsole,
+ SMALL_RECT srWindowRect)
+{
+ if (!SetConsoleWindowInfo(hConsole, TRUE, &srWindowRect))
+ {
+#ifdef MCH_WRITE_DUMP
+ if (fdDump)
+ {
+ fprintf(fdDump, "SetConsoleWindowInfo failed: %lx\n",
+ GetLastError());
+ fflush(fdDump);
+ }
+#endif
+ }
+}
+
+/*
+ * Set a console window to `xSize' * `ySize'
+ */
+ static void
+ResizeConBufAndWindow(
+ HANDLE hConsole,
+ int xSize,
+ int ySize)
+{
+ CONSOLE_SCREEN_BUFFER_INFO csbi; /* hold current console buffer info */
+ SMALL_RECT srWindowRect; /* hold the new console size */
+ COORD coordScreen;
+ static int resized = FALSE;
+
+#ifdef MCH_WRITE_DUMP
+ if (fdDump)
+ {
+ fprintf(fdDump, "ResizeConBufAndWindow(%d, %d)\n", xSize, ySize);
+ fflush(fdDump);
+ }
+#endif
+
+ /* get the largest size we can size the console window to */
+ coordScreen = GetLargestConsoleWindowSize(hConsole);
+
+ /* define the new console window size and scroll position */
+ srWindowRect.Left = srWindowRect.Top = (SHORT) 0;
+ srWindowRect.Right = (SHORT) (min(xSize, coordScreen.X) - 1);
+ srWindowRect.Bottom = (SHORT) (min(ySize, coordScreen.Y) - 1);
+
+ if (GetConsoleScreenBufferInfo(g_hConOut, &csbi))
+ {
+ int sx, sy;
+
+ sx = csbi.srWindow.Right - csbi.srWindow.Left + 1;
+ sy = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
+ if (sy < ySize || sx < xSize)
+ {
+ /*
+ * Increasing number of lines/columns, do buffer first.
+ * Use the maximal size in x and y direction.
+ */
+ if (sy < ySize)
+ coordScreen.Y = ySize;
+ else
+ coordScreen.Y = sy;
+ if (sx < xSize)
+ coordScreen.X = xSize;
+ else
+ coordScreen.X = sx;
+ SetConsoleScreenBufferSize(hConsole, coordScreen);
+ }
+ }
+
+ // define the new console buffer size
+ coordScreen.X = xSize;
+ coordScreen.Y = ySize;
+
+ // In the new console call API, only the first time in reverse order
+ if (!vtp_working || resized)
+ {
+ ResizeWindow(hConsole, srWindowRect);
+ ResizeConBuf(hConsole, coordScreen);
+ }
+ else
+ {
+ ResizeConBuf(hConsole, coordScreen);
+ ResizeWindow(hConsole, srWindowRect);
+ resized = TRUE;
+ }
+}
+
+
+/*
+ * Set the console window to `Rows' * `Columns'
+ */
+ void
+mch_set_shellsize(void)
+{
+ COORD coordScreen;
+
+ /* Don't change window size while still starting up */
+ if (suppress_winsize != 0)
+ {
+ suppress_winsize = 2;
+ return;
+ }
+
+ if (term_console)
+ {
+ coordScreen = GetLargestConsoleWindowSize(g_hConOut);
+
+ /* Clamp Rows and Columns to reasonable values */
+ if (Rows > coordScreen.Y)
+ Rows = coordScreen.Y;
+ if (Columns > coordScreen.X)
+ Columns = coordScreen.X;
+
+ ResizeConBufAndWindow(g_hConOut, Columns, Rows);
+ }
+}
+
+/*
+ * Rows and/or Columns has changed.
+ */
+ void
+mch_new_shellsize(void)
+{
+ set_scroll_region(0, 0, Columns - 1, Rows - 1);
+}
+
+
+/*
+ * Called when started up, to set the winsize that was delayed.
+ */
+ void
+mch_set_winsize_now(void)
+{
+ if (suppress_winsize == 2)
+ {
+ suppress_winsize = 0;
+ mch_set_shellsize();
+ shell_resized();
+ }
+ suppress_winsize = 0;
+}
+#endif /* FEAT_GUI_W32 */
+
+ static BOOL
+vim_create_process(
+ char *cmd,
+ BOOL inherit_handles,
+ DWORD flags,
+ STARTUPINFO *si,
+ PROCESS_INFORMATION *pi,
+ LPVOID *env,
+ char *cwd)
+{
+ if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+ {
+ BOOL ret;
+ WCHAR *wcmd, *wcwd = NULL;
+
+ wcmd = enc_to_utf16((char_u *)cmd, NULL);
+ if (wcmd == NULL)
+ goto fallback;
+ if (cwd != NULL)
+ {
+ wcwd = enc_to_utf16((char_u *)cwd, NULL);
+ if (wcwd == NULL)
+ {
+ vim_free(wcmd);
+ goto fallback;
+ }
+ }
+
+ ret = CreateProcessW(
+ NULL, /* Executable name */
+ wcmd, /* Command to execute */
+ NULL, /* Process security attributes */
+ NULL, /* Thread security attributes */
+ inherit_handles, /* Inherit handles */
+ flags, /* Creation flags */
+ env, /* Environment */
+ wcwd, /* Current directory */
+ (LPSTARTUPINFOW)si, /* Startup information */
+ pi); /* Process information */
+ vim_free(wcmd);
+ if (wcwd != NULL)
+ vim_free(wcwd);
+ return ret;
+ }
+fallback:
+ return CreateProcess(
+ NULL, /* Executable name */
+ cmd, /* Command to execute */
+ NULL, /* Process security attributes */
+ NULL, /* Thread security attributes */
+ inherit_handles, /* Inherit handles */
+ flags, /* Creation flags */
+ env, /* Environment */
+ cwd, /* Current directory */
+ si, /* Startup information */
+ pi); /* Process information */
+}
+
+
+ static HINSTANCE
+vim_shell_execute(
+ char *cmd,
+ INT n_show_cmd)
+{
+ if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+ {
+ WCHAR *wcmd = enc_to_utf16((char_u *)cmd, NULL);
+ if (wcmd != NULL)
+ {
+ HINSTANCE ret;
+ ret = ShellExecuteW(NULL, NULL, wcmd, NULL, NULL, n_show_cmd);
+ vim_free(wcmd);
+ return ret;
+ }
+ }
+ return ShellExecute(NULL, NULL, cmd, NULL, NULL, n_show_cmd);
+}
+
+
+#if defined(FEAT_GUI_W32) || defined(PROTO)
+
+/*
+ * Specialised version of system() for Win32 GUI mode.
+ * This version proceeds as follows:
+ * 1. Create a console window for use by the subprocess
+ * 2. Run the subprocess (it gets the allocated console by default)
+ * 3. Wait for the subprocess to terminate and get its exit code
+ * 4. Prompt the user to press a key to close the console window
+ */
+ static int
+mch_system_classic(char *cmd, int options)
+{
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+ DWORD ret = 0;
+ HWND hwnd = GetFocus();
+
+ si.cb = sizeof(si);
+ si.lpReserved = NULL;
+ si.lpDesktop = NULL;
+ si.lpTitle = NULL;
+ si.dwFlags = STARTF_USESHOWWINDOW;
+ /*
+ * It's nicer to run a filter command in a minimized window.
+ * Don't activate the window to keep focus on Vim.
+ */
+ if (options & SHELL_DOOUT)
+ si.wShowWindow = SW_SHOWMINNOACTIVE;
+ else
+ si.wShowWindow = SW_SHOWNORMAL;
+ si.cbReserved2 = 0;
+ si.lpReserved2 = NULL;
+
+ /* Now, run the command */
+ vim_create_process(cmd, FALSE,
+ CREATE_DEFAULT_ERROR_MODE | CREATE_NEW_CONSOLE,
+ &si, &pi, NULL, NULL);
+
+ /* Wait for the command to terminate before continuing */
+ {
+#ifdef FEAT_GUI
+ int delay = 1;
+
+ /* Keep updating the window while waiting for the shell to finish. */
+ for (;;)
+ {
+ MSG msg;
+
+ if (pPeekMessage(&msg, (HWND)NULL, 0, 0, PM_REMOVE))
+ {
+ TranslateMessage(&msg);
+ pDispatchMessage(&msg);
+ delay = 1;
+ continue;
+ }
+ if (WaitForSingleObject(pi.hProcess, delay) != WAIT_TIMEOUT)
+ break;
+
+ /* We start waiting for a very short time and then increase it, so
+ * that we respond quickly when the process is quick, and don't
+ * consume too much overhead when it's slow. */
+ if (delay < 50)
+ delay += 10;
+ }
+#else
+ WaitForSingleObject(pi.hProcess, INFINITE);
+#endif
+
+ /* Get the command exit code */
+ GetExitCodeProcess(pi.hProcess, &ret);
+ }
+
+ /* Close the handles to the subprocess, so that it goes away */
+ CloseHandle(pi.hThread);
+ CloseHandle(pi.hProcess);
+
+ /* Try to get input focus back. Doesn't always work though. */
+ PostMessage(hwnd, WM_SETFOCUS, 0, 0);
+
+ return ret;
+}
+
+/*
+ * Thread launched by the gui to send the current buffer data to the
+ * process. This way avoid to hang up vim totally if the children
+ * process take a long time to process the lines.
+ */
+ static unsigned int __stdcall
+sub_process_writer(LPVOID param)
+{
+ HANDLE g_hChildStd_IN_Wr = param;
+ linenr_T lnum = curbuf->b_op_start.lnum;
+ DWORD len = 0;
+ DWORD l;
+ char_u *lp = ml_get(lnum);
+ char_u *s;
+ int written = 0;
+
+ for (;;)
+ {
+ l = (DWORD)STRLEN(lp + written);
+ if (l == 0)
+ len = 0;
+ else if (lp[written] == NL)
+ {
+ /* NL -> NUL translation */
+ WriteFile(g_hChildStd_IN_Wr, "", 1, &len, NULL);
+ }
+ else
+ {
+ s = vim_strchr(lp + written, NL);
+ WriteFile(g_hChildStd_IN_Wr, (char *)lp + written,
+ s == NULL ? l : (DWORD)(s - (lp + written)),
+ &len, NULL);
+ }
+ if (len == (int)l)
+ {
+ /* Finished a line, add a NL, unless this line should not have
+ * one. */
+ if (lnum != curbuf->b_op_end.lnum
+ || (!curbuf->b_p_bin
+ && curbuf->b_p_fixeol)
+ || (lnum != curbuf->b_no_eol_lnum
+ && (lnum != curbuf->b_ml.ml_line_count
+ || curbuf->b_p_eol)))
+ {
+ WriteFile(g_hChildStd_IN_Wr, "\n", 1,
+ (LPDWORD)&vim_ignored, NULL);
+ }
+
+ ++lnum;
+ if (lnum > curbuf->b_op_end.lnum)
+ break;
+
+ lp = ml_get(lnum);
+ written = 0;
+ }
+ else if (len > 0)
+ written += len;
+ }
+
+ /* finished all the lines, close pipe */
+ CloseHandle(g_hChildStd_IN_Wr);
+ return 0;
+}
+
+
+# define BUFLEN 100 /* length for buffer, stolen from unix version */
+
+/*
+ * This function read from the children's stdout and write the
+ * data on screen or in the buffer accordingly.
+ */
+ static void
+dump_pipe(int options,
+ HANDLE g_hChildStd_OUT_Rd,
+ garray_T *ga,
+ char_u buffer[],
+ DWORD *buffer_off)
+{
+ DWORD availableBytes = 0;
+ DWORD i;
+ int ret;
+ DWORD len;
+ DWORD toRead;
+ int repeatCount;
+
+ /* we query the pipe to see if there is any data to read
+ * to avoid to perform a blocking read */
+ ret = PeekNamedPipe(g_hChildStd_OUT_Rd, /* pipe to query */
+ NULL, /* optional buffer */
+ 0, /* buffer size */
+ NULL, /* number of read bytes */
+ &availableBytes, /* available bytes total */
+ NULL); /* byteLeft */
+
+ repeatCount = 0;
+ /* We got real data in the pipe, read it */
+ while (ret != 0 && availableBytes > 0)
+ {
+ repeatCount++;
+ toRead = (DWORD)(BUFLEN - *buffer_off);
+ toRead = availableBytes < toRead ? availableBytes : toRead;
+ ReadFile(g_hChildStd_OUT_Rd, buffer + *buffer_off, toRead , &len, NULL);
+
+ /* If we haven't read anything, there is a problem */
+ if (len == 0)
+ break;
+
+ availableBytes -= len;
+
+ if (options & SHELL_READ)
+ {
+ /* Do NUL -> NL translation, append NL separated
+ * lines to the current buffer. */
+ for (i = 0; i < len; ++i)
+ {
+ if (buffer[i] == NL)
+ append_ga_line(ga);
+ else if (buffer[i] == NUL)
+ ga_append(ga, NL);
+ else
+ ga_append(ga, buffer[i]);
+ }
+ }
+ else if (has_mbyte)
+ {
+ int l;
+ int c;
+ char_u *p;
+
+ len += *buffer_off;
+ buffer[len] = NUL;
+
+ /* Check if the last character in buffer[] is
+ * incomplete, keep these bytes for the next
+ * round. */
+ for (p = buffer; p < buffer + len; p += l)
+ {
+ l = MB_CPTR2LEN(p);
+ if (l == 0)
+ l = 1; /* NUL byte? */
+ else if (MB_BYTE2LEN(*p) != l)
+ break;
+ }
+ if (p == buffer) /* no complete character */
+ {
+ /* avoid getting stuck at an illegal byte */
+ if (len >= 12)
+ ++p;
+ else
+ {
+ *buffer_off = len;
+ return;
+ }
+ }
+ c = *p;
+ *p = NUL;
+ msg_puts((char *)buffer);
+ if (p < buffer + len)
+ {
+ *p = c;
+ *buffer_off = (DWORD)((buffer + len) - p);
+ mch_memmove(buffer, p, *buffer_off);
+ return;
+ }
+ *buffer_off = 0;
+ }
+ else
+ {
+ buffer[len] = NUL;
+ msg_puts((char *)buffer);
+ }
+
+ windgoto(msg_row, msg_col);
+ cursor_on();
+ out_flush();
+ }
+}
+
+/*
+ * Version of system to use for windows NT > 5.0 (Win2K), use pipe
+ * for communication and doesn't open any new window.
+ */
+ static int
+mch_system_piped(char *cmd, int options)
+{
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+ DWORD ret = 0;
+
+ HANDLE g_hChildStd_IN_Rd = NULL;
+ HANDLE g_hChildStd_IN_Wr = NULL;
+ HANDLE g_hChildStd_OUT_Rd = NULL;
+ HANDLE g_hChildStd_OUT_Wr = NULL;
+
+ char_u buffer[BUFLEN + 1]; /* reading buffer + size */
+ DWORD len;
+
+ /* buffer used to receive keys */
+ char_u ta_buf[BUFLEN + 1]; /* TypeAHead */
+ int ta_len = 0; /* valid bytes in ta_buf[] */
+
+ DWORD i;
+ int c;
+ int noread_cnt = 0;
+ garray_T ga;
+ int delay = 1;
+ DWORD buffer_off = 0; /* valid bytes in buffer[] */
+ char *p = NULL;
+
+ SECURITY_ATTRIBUTES saAttr;
+
+ /* Set the bInheritHandle flag so pipe handles are inherited. */
+ saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
+ saAttr.bInheritHandle = TRUE;
+ saAttr.lpSecurityDescriptor = NULL;
+
+ if ( ! CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0)
+ /* Ensure the read handle to the pipe for STDOUT is not inherited. */
+ || ! SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0)
+ /* Create a pipe for the child process's STDIN. */
+ || ! CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr, 0)
+ /* Ensure the write handle to the pipe for STDIN is not inherited. */
+ || ! SetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0) )
+ {
+ CloseHandle(g_hChildStd_IN_Rd);
+ CloseHandle(g_hChildStd_IN_Wr);
+ CloseHandle(g_hChildStd_OUT_Rd);
+ CloseHandle(g_hChildStd_OUT_Wr);
+ msg_puts(_("\nCannot create pipes\n"));
+ }
+
+ si.cb = sizeof(si);
+ si.lpReserved = NULL;
+ si.lpDesktop = NULL;
+ si.lpTitle = NULL;
+ si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
+
+ /* set-up our file redirection */
+ si.hStdError = g_hChildStd_OUT_Wr;
+ si.hStdOutput = g_hChildStd_OUT_Wr;
+ si.hStdInput = g_hChildStd_IN_Rd;
+ si.wShowWindow = SW_HIDE;
+ si.cbReserved2 = 0;
+ si.lpReserved2 = NULL;
+
+ if (options & SHELL_READ)
+ ga_init2(&ga, 1, BUFLEN);
+
+ if (cmd != NULL)
+ {
+ p = (char *)vim_strsave((char_u *)cmd);
+ if (p != NULL)
+ unescape_shellxquote((char_u *)p, p_sxe);
+ else
+ p = cmd;
+ }
+
+ /* Now, run the command.
+ * About "Inherit handles" being TRUE: this command can be litigious,
+ * handle inheritance was deactivated for pending temp file, but, if we
+ * deactivate it, the pipes don't work for some reason. */
+ vim_create_process(p, TRUE, CREATE_DEFAULT_ERROR_MODE,
+ &si, &pi, NULL, NULL);
+
+ if (p != cmd)
+ vim_free(p);
+
+ /* Close our unused side of the pipes */
+ CloseHandle(g_hChildStd_IN_Rd);
+ CloseHandle(g_hChildStd_OUT_Wr);
+
+ if (options & SHELL_WRITE)
+ {
+ HANDLE thread = (HANDLE)
+ _beginthreadex(NULL, /* security attributes */
+ 0, /* default stack size */
+ sub_process_writer, /* function to be executed */
+ g_hChildStd_IN_Wr, /* parameter */
+ 0, /* creation flag, start immediately */
+ NULL); /* we don't care about thread id */
+ CloseHandle(thread);
+ g_hChildStd_IN_Wr = NULL;
+ }
+
+ /* Keep updating the window while waiting for the shell to finish. */
+ for (;;)
+ {
+ MSG msg;
+
+ if (pPeekMessage(&msg, (HWND)NULL, 0, 0, PM_REMOVE))
+ {
+ TranslateMessage(&msg);
+ pDispatchMessage(&msg);
+ }
+
+ /* write pipe information in the window */
+ if ((options & (SHELL_READ|SHELL_WRITE))
+# ifdef FEAT_GUI
+ || gui.in_use
+# endif
+ )
+ {
+ len = 0;
+ if (!(options & SHELL_EXPAND)
+ && ((options &
+ (SHELL_READ|SHELL_WRITE|SHELL_COOKED))
+ != (SHELL_READ|SHELL_WRITE|SHELL_COOKED)
+# ifdef FEAT_GUI
+ || gui.in_use
+# endif
+ )
+ && (ta_len > 0 || noread_cnt > 4))
+ {
+ if (ta_len == 0)
+ {
+ /* Get extra characters when we don't have any. Reset the
+ * counter and timer. */
+ noread_cnt = 0;
+ len = ui_inchar(ta_buf, BUFLEN, 10L, 0);
+ }
+ if (ta_len > 0 || len > 0)
+ {
+ /*
+ * For pipes: Check for CTRL-C: send interrupt signal to
+ * child. Check for CTRL-D: EOF, close pipe to child.
+ */
+ if (len == 1 && cmd != NULL)
+ {
+ if (ta_buf[ta_len] == Ctrl_C)
+ {
+ /* Learn what exit code is expected, for
+ * now put 9 as SIGKILL */
+ TerminateProcess(pi.hProcess, 9);
+ }
+ if (ta_buf[ta_len] == Ctrl_D)
+ {
+ CloseHandle(g_hChildStd_IN_Wr);
+ g_hChildStd_IN_Wr = NULL;
+ }
+ }
+
+ /* replace K_BS by <BS> and K_DEL by <DEL> */
+ for (i = ta_len; i < ta_len + len; ++i)
+ {
+ if (ta_buf[i] == CSI && len - i > 2)
+ {
+ c = TERMCAP2KEY(ta_buf[i + 1], ta_buf[i + 2]);
+ if (c == K_DEL || c == K_KDEL || c == K_BS)
+ {
+ mch_memmove(ta_buf + i + 1, ta_buf + i + 3,
+ (size_t)(len - i - 2));
+ if (c == K_DEL || c == K_KDEL)
+ ta_buf[i] = DEL;
+ else
+ ta_buf[i] = Ctrl_H;
+ len -= 2;
+ }
+ }
+ else if (ta_buf[i] == '\r')
+ ta_buf[i] = '\n';
+ if (has_mbyte)
+ i += (*mb_ptr2len_len)(ta_buf + i,
+ ta_len + len - i) - 1;
+ }
+
+ /*
+ * For pipes: echo the typed characters. For a pty this
+ * does not seem to work.
+ */
+ for (i = ta_len; i < ta_len + len; ++i)
+ {
+ if (ta_buf[i] == '\n' || ta_buf[i] == '\b')
+ msg_putchar(ta_buf[i]);
+ else if (has_mbyte)
+ {
+ int l = (*mb_ptr2len)(ta_buf + i);
+
+ msg_outtrans_len(ta_buf + i, l);
+ i += l - 1;
+ }
+ else
+ msg_outtrans_len(ta_buf + i, 1);
+ }
+ windgoto(msg_row, msg_col);
+ out_flush();
+
+ ta_len += len;
+
+ /*
+ * Write the characters to the child, unless EOF has been
+ * typed for pipes. Write one character at a time, to
+ * avoid losing too much typeahead. When writing buffer
+ * lines, drop the typed characters (only check for
+ * CTRL-C).
+ */
+ if (options & SHELL_WRITE)
+ ta_len = 0;
+ else if (g_hChildStd_IN_Wr != NULL)
+ {
+ WriteFile(g_hChildStd_IN_Wr, (char*)ta_buf,
+ 1, &len, NULL);
+ // if we are typing in, we want to keep things reactive
+ delay = 1;
+ if (len > 0)
+ {
+ ta_len -= len;
+ mch_memmove(ta_buf, ta_buf + len, ta_len);
+ }
+ }
+ }
+ }
+ }
+
+ if (ta_len)
+ ui_inchar_undo(ta_buf, ta_len);
+
+ if (WaitForSingleObject(pi.hProcess, delay) != WAIT_TIMEOUT)
+ {
+ dump_pipe(options, g_hChildStd_OUT_Rd, &ga, buffer, &buffer_off);
+ break;
+ }
+
+ ++noread_cnt;
+ dump_pipe(options, g_hChildStd_OUT_Rd, &ga, buffer, &buffer_off);
+
+ /* We start waiting for a very short time and then increase it, so
+ * that we respond quickly when the process is quick, and don't
+ * consume too much overhead when it's slow. */
+ if (delay < 50)
+ delay += 10;
+ }
+
+ /* Close the pipe */
+ CloseHandle(g_hChildStd_OUT_Rd);
+ if (g_hChildStd_IN_Wr != NULL)
+ CloseHandle(g_hChildStd_IN_Wr);
+
+ WaitForSingleObject(pi.hProcess, INFINITE);
+
+ /* Get the command exit code */
+ GetExitCodeProcess(pi.hProcess, &ret);
+
+ if (options & SHELL_READ)
+ {
+ if (ga.ga_len > 0)
+ {
+ append_ga_line(&ga);
+ /* remember that the NL was missing */
+ curbuf->b_no_eol_lnum = curwin->w_cursor.lnum;
+ }
+ else
+ curbuf->b_no_eol_lnum = 0;
+ ga_clear(&ga);
+ }
+
+ /* Close the handles to the subprocess, so that it goes away */
+ CloseHandle(pi.hThread);
+ CloseHandle(pi.hProcess);
+
+ return ret;
+}
+
+ static int
+mch_system(char *cmd, int options)
+{
+ /* if we can pipe and the shelltemp option is off */
+ if (!p_stmp)
+ return mch_system_piped(cmd, options);
+ else
+ return mch_system_classic(cmd, options);
+}
+#else
+
+ static int
+mch_system(char *cmd, int options)
+{
+ if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+ {
+ WCHAR *wcmd = enc_to_utf16((char_u *)cmd, NULL);
+ if (wcmd != NULL)
+ {
+ int ret = _wsystem(wcmd);
+ vim_free(wcmd);
+ return ret;
+ }
+ }
+ return system(cmd);
+}
+
+#endif
+
+#if defined(FEAT_GUI) && defined(FEAT_TERMINAL)
+/*
+ * Use a terminal window to run a shell command in.
+ */
+ static int
+mch_call_shell_terminal(
+ char_u *cmd,
+ int options UNUSED) /* SHELL_*, see vim.h */
+{
+ jobopt_T opt;
+ char_u *newcmd = NULL;
+ typval_T argvar[2];
+ long_u cmdlen;
+ int retval = -1;
+ buf_T *buf;
+ job_T *job;
+ aco_save_T aco;
+ oparg_T oa; /* operator arguments */
+
+ if (cmd == NULL)
+ cmdlen = STRLEN(p_sh) + 1;
+ else
+ cmdlen = STRLEN(p_sh) + STRLEN(p_shcf) + STRLEN(cmd) + 10;
+ newcmd = lalloc(cmdlen, TRUE);
+ if (newcmd == NULL)
+ return 255;
+ if (cmd == NULL)
+ {
+ STRCPY(newcmd, p_sh);
+ ch_log(NULL, "starting terminal to run a shell");
+ }
+ else
+ {
+ vim_snprintf((char *)newcmd, cmdlen, "%s %s %s", p_sh, p_shcf, cmd);
+ ch_log(NULL, "starting terminal for system command '%s'", cmd);
+ }
+
+ init_job_options(&opt);
+
+ argvar[0].v_type = VAR_STRING;
+ argvar[0].vval.v_string = newcmd;
+ argvar[1].v_type = VAR_UNKNOWN;
+ buf = term_start(argvar, NULL, &opt, TERM_START_SYSTEM);
+ if (buf == NULL)
+ return 255;
+
+ job = term_getjob(buf->b_term);
+ ++job->jv_refcount;
+
+ /* Find a window to make "buf" curbuf. */
+ aucmd_prepbuf(&aco, buf);
+
+ clear_oparg(&oa);
+ while (term_use_loop())
+ {
+ if (oa.op_type == OP_NOP && oa.regname == NUL && !VIsual_active)
+ {
+ /* If terminal_loop() returns OK we got a key that is handled
+ * in Normal model. We don't do redrawing anyway. */
+ if (terminal_loop(TRUE) == OK)
+ normal_cmd(&oa, TRUE);
+ }
+ else
+ normal_cmd(&oa, TRUE);
+ }
+ retval = job->jv_exitval;
+ ch_log(NULL, "system command finished");
+
+ job_unref(job);
+
+ /* restore curwin/curbuf and a few other things */
+ aucmd_restbuf(&aco);
+
+ wait_return(TRUE);
+ do_buffer(DOBUF_WIPE, DOBUF_FIRST, FORWARD, buf->b_fnum, TRUE);
+
+ vim_free(newcmd);
+ return retval;
+}
+#endif
+
+/*
+ * Either execute a command by calling the shell or start a new shell
+ */
+ int
+mch_call_shell(
+ char_u *cmd,
+ int options) /* SHELL_*, see vim.h */
+{
+ int x = 0;
+ int tmode = cur_tmode;
+#ifdef FEAT_TITLE
+ char szShellTitle[512];
+ int did_set_title = FALSE;
+
+ /* Change the title to reflect that we are in a subshell. */
+ if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+ {
+ WCHAR szShellTitle[512];
+
+ if (GetConsoleTitleW(szShellTitle,
+ sizeof(szShellTitle)/sizeof(WCHAR) - 4) > 0)
+ {
+ if (cmd == NULL)
+ wcscat(szShellTitle, L" :sh");
+ else
+ {
+ WCHAR *wn = enc_to_utf16((char_u *)cmd, NULL);
+
+ if (wn != NULL)
+ {
+ wcscat(szShellTitle, L" - !");
+ if ((wcslen(szShellTitle) + wcslen(wn) <
+ sizeof(szShellTitle)/sizeof(WCHAR)))
+ wcscat(szShellTitle, wn);
+ SetConsoleTitleW(szShellTitle);
+ vim_free(wn);
+ did_set_title = TRUE;
+ }
+ }
+ }
+ }
+ if (!did_set_title)
+ /* Change the title to reflect that we are in a subshell. */
+ if (GetConsoleTitle(szShellTitle, sizeof(szShellTitle) - 4) > 0)
+ {
+ if (cmd == NULL)
+ strcat(szShellTitle, " :sh");
+ else
+ {
+ strcat(szShellTitle, " - !");
+ if ((strlen(szShellTitle) + strlen((char *)cmd)
+ < sizeof(szShellTitle)))
+ strcat(szShellTitle, (char *)cmd);
+ }
+ SetConsoleTitle(szShellTitle);
+ }
+#endif
+
+ out_flush();
+
+#ifdef MCH_WRITE_DUMP
+ if (fdDump)
+ {
+ fprintf(fdDump, "mch_call_shell(\"%s\", %d)\n", cmd, options);
+ fflush(fdDump);
+ }
+#endif
+#if defined(FEAT_GUI) && defined(FEAT_TERMINAL)
+ /* TODO: make the terminal window work with input or output redirected. */
+ if (vim_strchr(p_go, GO_TERMINAL) != NULL
+ && (options & (SHELL_FILTER|SHELL_DOOUT|SHELL_WRITE|SHELL_READ)) == 0)
+ {
+ /* Use a terminal window to run the command in. */
+ x = mch_call_shell_terminal(cmd, options);
+# ifdef FEAT_TITLE
+ resettitle();
+# endif
+ return x;
+ }
+#endif
+
+ /*
+ * Catch all deadly signals while running the external command, because a
+ * CTRL-C, Ctrl-Break or illegal instruction might otherwise kill us.
+ */
+ signal(SIGINT, SIG_IGN);
+#if defined(__GNUC__) && !defined(__MINGW32__)
+ signal(SIGKILL, SIG_IGN);
+#else
+ signal(SIGBREAK, SIG_IGN);
+#endif
+ signal(SIGILL, SIG_IGN);
+ signal(SIGFPE, SIG_IGN);
+ signal(SIGSEGV, SIG_IGN);
+ signal(SIGTERM, SIG_IGN);
+ signal(SIGABRT, SIG_IGN);
+
+ if (options & SHELL_COOKED)
+ settmode(TMODE_COOK); /* set to normal mode */
+
+ if (cmd == NULL)
+ {
+ x = mch_system((char *)p_sh, options);
+ }
+ else
+ {
+ /* we use "command" or "cmd" to start the shell; slow but easy */
+ char_u *newcmd = NULL;
+ char_u *cmdbase = cmd;
+ long_u cmdlen;
+
+ /* Skip a leading ", ( and "(. */
+ if (*cmdbase == '"' )
+ ++cmdbase;
+ if (*cmdbase == '(')
+ ++cmdbase;
+
+ if ((STRNICMP(cmdbase, "start", 5) == 0) && VIM_ISWHITE(cmdbase[5]))
+ {
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+ DWORD flags = CREATE_NEW_CONSOLE;
+ INT n_show_cmd = SW_SHOWNORMAL;
+ char_u *p;
+
+ ZeroMemory(&si, sizeof(si));
+ si.cb = sizeof(si);
+ si.lpReserved = NULL;
+ si.lpDesktop = NULL;
+ si.lpTitle = NULL;
+ si.dwFlags = 0;
+ si.cbReserved2 = 0;
+ si.lpReserved2 = NULL;
+
+ cmdbase = skipwhite(cmdbase + 5);
+ if ((STRNICMP(cmdbase, "/min", 4) == 0)
+ && VIM_ISWHITE(cmdbase[4]))
+ {
+ cmdbase = skipwhite(cmdbase + 4);
+ si.dwFlags = STARTF_USESHOWWINDOW;
+ si.wShowWindow = SW_SHOWMINNOACTIVE;
+ n_show_cmd = SW_SHOWMINNOACTIVE;
+ }
+ else if ((STRNICMP(cmdbase, "/b", 2) == 0)
+ && VIM_ISWHITE(cmdbase[2]))
+ {
+ cmdbase = skipwhite(cmdbase + 2);
+ flags = CREATE_NO_WINDOW;
+ si.dwFlags = STARTF_USESTDHANDLES;
+ si.hStdInput = CreateFile("\\\\.\\NUL", // File name
+ GENERIC_READ, // Access flags
+ 0, // Share flags
+ NULL, // Security att.
+ OPEN_EXISTING, // Open flags
+ FILE_ATTRIBUTE_NORMAL, // File att.
+ NULL); // Temp file
+ si.hStdOutput = si.hStdInput;
+ si.hStdError = si.hStdInput;
+ }
+
+ /* Remove a trailing ", ) and )" if they have a match
+ * at the start of the command. */
+ if (cmdbase > cmd)
+ {
+ p = cmdbase + STRLEN(cmdbase);
+ if (p > cmdbase && p[-1] == '"' && *cmd == '"')
+ *--p = NUL;
+ if (p > cmdbase && p[-1] == ')'
+ && (*cmd =='(' || cmd[1] == '('))
+ *--p = NUL;
+ }
+
+ newcmd = cmdbase;
+ unescape_shellxquote(cmdbase, p_sxe);
+
+ /*
+ * If creating new console, arguments are passed to the
+ * 'cmd.exe' as-is. If it's not, arguments are not treated
+ * correctly for current 'cmd.exe'. So unescape characters in
+ * shellxescape except '|' for avoiding to be treated as
+ * argument to them. Pass the arguments to sub-shell.
+ */
+ if (flags != CREATE_NEW_CONSOLE)
+ {
+ char_u *subcmd;
+ char_u *cmd_shell = mch_getenv("COMSPEC");
+
+ if (cmd_shell == NULL || *cmd_shell == NUL)
+ cmd_shell = (char_u *)default_shell();
+
+ subcmd = vim_strsave_escaped_ext(cmdbase,
+ (char_u *)"|", '^', FALSE);
+ if (subcmd != NULL)
+ {
+ /* make "cmd.exe /c arguments" */
+ cmdlen = STRLEN(cmd_shell) + STRLEN(subcmd) + 5;
+ newcmd = lalloc(cmdlen, TRUE);
+ if (newcmd != NULL)
+ vim_snprintf((char *)newcmd, cmdlen, "%s /c %s",
+ cmd_shell, subcmd);
+ else
+ newcmd = cmdbase;
+ vim_free(subcmd);
+ }
+ }
+
+ /*
+ * Now, start the command as a process, so that it doesn't
+ * inherit our handles which causes unpleasant dangling swap
+ * files if we exit before the spawned process
+ */
+ if (vim_create_process((char *)newcmd, FALSE, flags,
+ &si, &pi, NULL, NULL))
+ x = 0;
+ else if (vim_shell_execute((char *)newcmd, n_show_cmd)
+ > (HINSTANCE)32)
+ x = 0;
+ else
+ {
+ x = -1;
+#ifdef FEAT_GUI_W32
+ emsg(_("E371: Command not found"));
+#endif
+ }
+
+ if (newcmd != cmdbase)
+ vim_free(newcmd);
+
+ if (si.dwFlags == STARTF_USESTDHANDLES && si.hStdInput != NULL)
+ {
+ /* Close the handle to \\.\NUL created above. */
+ CloseHandle(si.hStdInput);
+ }
+ /* Close the handles to the subprocess, so that it goes away */
+ CloseHandle(pi.hThread);
+ CloseHandle(pi.hProcess);
+ }
+ else
+ {
+ cmdlen = (
+#ifdef FEAT_GUI_W32
+ (!p_stmp ? 0 : STRLEN(vimrun_path)) +
+#endif
+ STRLEN(p_sh) + STRLEN(p_shcf) + STRLEN(cmd) + 10);
+
+ newcmd = lalloc(cmdlen, TRUE);
+ if (newcmd != NULL)
+ {
+#if defined(FEAT_GUI_W32)
+ if (need_vimrun_warning)
+ {
+ char *msg = _("VIMRUN.EXE not found in your $PATH.\n"
+ "External commands will not pause after completion.\n"
+ "See :help win32-vimrun for more information.");
+ char *title = _("Vim Warning");
+ if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+ {
+ WCHAR *wmsg = enc_to_utf16((char_u *)msg, NULL);
+ WCHAR *wtitle = enc_to_utf16((char_u *)title, NULL);
+
+ if (wmsg != NULL && wtitle != NULL)
+ MessageBoxW(NULL, wmsg, wtitle, MB_ICONWARNING);
+ vim_free(wmsg);
+ vim_free(wtitle);
+ }
+ else
+ MessageBox(NULL, msg, title, MB_ICONWARNING);
+ need_vimrun_warning = FALSE;
+ }
+ if (!s_dont_use_vimrun && p_stmp)
+ /* Use vimrun to execute the command. It opens a console
+ * window, which can be closed without killing Vim. */
+ vim_snprintf((char *)newcmd, cmdlen, "%s%s%s %s %s",
+ vimrun_path,
+ (msg_silent != 0 || (options & SHELL_DOOUT))
+ ? "-s " : "",
+ p_sh, p_shcf, cmd);
+ else
+#endif
+ vim_snprintf((char *)newcmd, cmdlen, "%s %s %s",
+ p_sh, p_shcf, cmd);
+ x = mch_system((char *)newcmd, options);
+ vim_free(newcmd);
+ }
+ }
+ }
+
+ if (tmode == TMODE_RAW)
+ settmode(TMODE_RAW); /* set to raw mode */
+
+ /* Print the return value, unless "vimrun" was used. */
+ if (x != 0 && !(options & SHELL_SILENT) && !emsg_silent
+#if defined(FEAT_GUI_W32)
+ && ((options & SHELL_DOOUT) || s_dont_use_vimrun || !p_stmp)
+#endif
+ )
+ {
+ smsg(_("shell returned %d"), x);
+ msg_putchar('\n');
+ }
+#ifdef FEAT_TITLE
+ resettitle();
+#endif
+
+ signal(SIGINT, SIG_DFL);
+#if defined(__GNUC__) && !defined(__MINGW32__)
+ signal(SIGKILL, SIG_DFL);
+#else
+ signal(SIGBREAK, SIG_DFL);
+#endif
+ signal(SIGILL, SIG_DFL);
+ signal(SIGFPE, SIG_DFL);
+ signal(SIGSEGV, SIG_DFL);
+ signal(SIGTERM, SIG_DFL);
+ signal(SIGABRT, SIG_DFL);
+
+ return x;
+}
+
+#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
+ static HANDLE
+job_io_file_open(
+ char_u *fname,
+ DWORD dwDesiredAccess,
+ DWORD dwShareMode,
+ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
+ DWORD dwCreationDisposition,
+ DWORD dwFlagsAndAttributes)
+{
+ HANDLE h;
+ WCHAR *wn = NULL;
+
+ if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+ {
+ wn = enc_to_utf16(fname, NULL);
+ if (wn != NULL)
+ {
+ h = CreateFileW(wn, dwDesiredAccess, dwShareMode,
+ lpSecurityAttributes, dwCreationDisposition,
+ dwFlagsAndAttributes, NULL);
+ vim_free(wn);
+ }
+ }
+ if (wn == NULL)
+ h = CreateFile((LPCSTR)fname, dwDesiredAccess, dwShareMode,
+ lpSecurityAttributes, dwCreationDisposition,
+ dwFlagsAndAttributes, NULL);
+ return h;
+}
+
+/*
+ * Turn the dictionary "env" into a NUL separated list that can be used as the
+ * environment argument of vim_create_process().
+ */
+ void
+win32_build_env(dict_T *env, garray_T *gap, int is_terminal)
+{
+ hashitem_T *hi;
+ long_u todo = env != NULL ? env->dv_hashtab.ht_used : 0;
+ LPVOID base = GetEnvironmentStringsW();
+
+ /* for last \0 */
+ if (ga_grow(gap, 1) == FAIL)
+ return;
+
+ if (base)
+ {
+ WCHAR *p = (WCHAR*) base;
+
+ /* for last \0 */
+ if (ga_grow(gap, 1) == FAIL)
+ return;
+
+ while (*p != 0 || *(p + 1) != 0)
+ {
+ if (ga_grow(gap, 1) == OK)
+ *((WCHAR*)gap->ga_data + gap->ga_len++) = *p;
+ p++;
+ }
+ FreeEnvironmentStrings(base);
+ *((WCHAR*)gap->ga_data + gap->ga_len++) = L'\0';
+ }
+
+ if (env != NULL)
+ {
+ for (hi = env->dv_hashtab.ht_array; todo > 0; ++hi)
+ {
+ if (!HASHITEM_EMPTY(hi))
+ {
+ typval_T *item = &dict_lookup(hi)->di_tv;
+ WCHAR *wkey = enc_to_utf16((char_u *)hi->hi_key, NULL);
+ WCHAR *wval = enc_to_utf16(tv_get_string(item), NULL);
+ --todo;
+ if (wkey != NULL && wval != NULL)
+ {
+ size_t n;
+ size_t lkey = wcslen(wkey);
+ size_t lval = wcslen(wval);
+
+ if (ga_grow(gap, (int)(lkey + lval + 2)) != OK)
+ continue;
+ for (n = 0; n < lkey; n++)
+ *((WCHAR*)gap->ga_data + gap->ga_len++) = wkey[n];
+ *((WCHAR*)gap->ga_data + gap->ga_len++) = L'=';
+ for (n = 0; n < lval; n++)
+ *((WCHAR*)gap->ga_data + gap->ga_len++) = wval[n];
+ *((WCHAR*)gap->ga_data + gap->ga_len++) = L'\0';
+ }
+ if (wkey != NULL) vim_free(wkey);
+ if (wval != NULL) vim_free(wval);
+ }
+ }
+ }
+
+# if defined(FEAT_CLIENTSERVER) || defined(FEAT_TERMINAL)
+ {
+# ifdef FEAT_CLIENTSERVER
+ char_u *servername = get_vim_var_str(VV_SEND_SERVER);
+ size_t servername_len = STRLEN(servername);
+# endif
+# ifdef FEAT_TERMINAL
+ char_u *version = get_vim_var_str(VV_VERSION);
+ size_t version_len = STRLEN(version);
+# endif
+ // size of "VIM_SERVERNAME=" and value,
+ // plus "VIM_TERMINAL=" and value,
+ // plus two terminating NULs
+ size_t n = 0
+# ifdef FEAT_CLIENTSERVER
+ + 15 + servername_len
+# endif
+# ifdef FEAT_TERMINAL
+ + 13 + version_len + 2
+# endif
+ ;
+
+ if (ga_grow(gap, (int)n) == OK)
+ {
+# ifdef FEAT_CLIENTSERVER
+ for (n = 0; n < 15; n++)
+ *((WCHAR*)gap->ga_data + gap->ga_len++) =
+ (WCHAR)"VIM_SERVERNAME="[n];
+ for (n = 0; n < servername_len; n++)
+ *((WCHAR*)gap->ga_data + gap->ga_len++) =
+ (WCHAR)servername[n];
+ *((WCHAR*)gap->ga_data + gap->ga_len++) = L'\0';
+# endif
+# ifdef FEAT_TERMINAL
+ if (is_terminal)
+ {
+ for (n = 0; n < 13; n++)
+ *((WCHAR*)gap->ga_data + gap->ga_len++) =
+ (WCHAR)"VIM_TERMINAL="[n];
+ for (n = 0; n < version_len; n++)
+ *((WCHAR*)gap->ga_data + gap->ga_len++) =
+ (WCHAR)version[n];
+ *((WCHAR*)gap->ga_data + gap->ga_len++) = L'\0';
+ }
+# endif
+ }
+ }
+# endif
+}
+
+/*
+ * Create a pair of pipes.
+ * Return TRUE for success, FALSE for failure.
+ */
+ static BOOL
+create_pipe_pair(HANDLE handles[2])
+{
+ static LONG s;
+ char name[64];
+ SECURITY_ATTRIBUTES sa;
+
+ sprintf(name, "\\\\?\\pipe\\vim-%08lx-%08lx",
+ GetCurrentProcessId(),
+ InterlockedIncrement(&s));
+
+ // Create named pipe. Max size of named pipe is 65535.
+ handles[1] = CreateNamedPipe(
+ name,
+ PIPE_ACCESS_OUTBOUND | FILE_FLAG_OVERLAPPED,
+ PIPE_TYPE_BYTE | PIPE_NOWAIT,
+ 1, MAX_NAMED_PIPE_SIZE, 0, 0, NULL);
+
+ if (handles[1] == INVALID_HANDLE_VALUE)
+ return FALSE;
+
+ sa.nLength = sizeof(sa);
+ sa.bInheritHandle = TRUE;
+ sa.lpSecurityDescriptor = NULL;
+
+ handles[0] = CreateFile(name,
+ FILE_GENERIC_READ,
+ FILE_SHARE_READ, &sa,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
+
+ if (handles[0] == INVALID_HANDLE_VALUE)
+ {
+ CloseHandle(handles[1]);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+ void
+mch_job_start(char *cmd, job_T *job, jobopt_T *options)
+{
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+ HANDLE jo;
+ SECURITY_ATTRIBUTES saAttr;
+ channel_T *channel = NULL;
+ HANDLE ifd[2];
+ HANDLE ofd[2];
+ HANDLE efd[2];
+ garray_T ga;
+
+ int use_null_for_in = options->jo_io[PART_IN] == JIO_NULL;
+ int use_null_for_out = options->jo_io[PART_OUT] == JIO_NULL;
+ int use_null_for_err = options->jo_io[PART_ERR] == JIO_NULL;
+ int use_file_for_in = options->jo_io[PART_IN] == JIO_FILE;
+ int use_file_for_out = options->jo_io[PART_OUT] == JIO_FILE;
+ int use_file_for_err = options->jo_io[PART_ERR] == JIO_FILE;
+ int use_out_for_err = options->jo_io[PART_ERR] == JIO_OUT;
+
+ if (use_out_for_err && use_null_for_out)
+ use_null_for_err = TRUE;
+
+ ifd[0] = INVALID_HANDLE_VALUE;
+ ifd[1] = INVALID_HANDLE_VALUE;
+ ofd[0] = INVALID_HANDLE_VALUE;
+ ofd[1] = INVALID_HANDLE_VALUE;
+ efd[0] = INVALID_HANDLE_VALUE;
+ efd[1] = INVALID_HANDLE_VALUE;
+ ga_init2(&ga, (int)sizeof(wchar_t), 500);
+
+ jo = CreateJobObject(NULL, NULL);
+ if (jo == NULL)
+ {
+ job->jv_status = JOB_FAILED;
+ goto failed;
+ }
+
+ if (options->jo_env != NULL)
+ win32_build_env(options->jo_env, &ga, FALSE);
+
+ ZeroMemory(&pi, sizeof(pi));
+ ZeroMemory(&si, sizeof(si));
+ si.cb = sizeof(si);
+ si.dwFlags |= STARTF_USESHOWWINDOW;
+ si.wShowWindow = SW_HIDE;
+
+ saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
+ saAttr.bInheritHandle = TRUE;
+ saAttr.lpSecurityDescriptor = NULL;
+
+ if (use_file_for_in)
+ {
+ char_u *fname = options->jo_io_name[PART_IN];
+
+ ifd[0] = job_io_file_open(fname, GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ &saAttr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL);
+ if (ifd[0] == INVALID_HANDLE_VALUE)
+ {
+ semsg(_(e_notopen), fname);
+ goto failed;
+ }
+ }
+ else if (!use_null_for_in
+ && (!create_pipe_pair(ifd)
+ || !SetHandleInformation(ifd[1], HANDLE_FLAG_INHERIT, 0)))
+ goto failed;
+
+ if (use_file_for_out)
+ {
+ char_u *fname = options->jo_io_name[PART_OUT];
+
+ ofd[1] = job_io_file_open(fname, GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ &saAttr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL);
+ if (ofd[1] == INVALID_HANDLE_VALUE)
+ {
+ semsg(_(e_notopen), fname);
+ goto failed;
+ }
+ }
+ else if (!use_null_for_out &&
+ (!CreatePipe(&ofd[0], &ofd[1], &saAttr, 0)
+ || !SetHandleInformation(ofd[0], HANDLE_FLAG_INHERIT, 0)))
+ goto failed;
+
+ if (use_file_for_err)
+ {
+ char_u *fname = options->jo_io_name[PART_ERR];
+
+ efd[1] = job_io_file_open(fname, GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ &saAttr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL);
+ if (efd[1] == INVALID_HANDLE_VALUE)
+ {
+ semsg(_(e_notopen), fname);
+ goto failed;
+ }
+ }
+ else if (!use_out_for_err && !use_null_for_err &&
+ (!CreatePipe(&efd[0], &efd[1], &saAttr, 0)
+ || !SetHandleInformation(efd[0], HANDLE_FLAG_INHERIT, 0)))
+ goto failed;
+
+ si.dwFlags |= STARTF_USESTDHANDLES;
+ si.hStdInput = ifd[0];
+ si.hStdOutput = ofd[1];
+ si.hStdError = use_out_for_err ? ofd[1] : efd[1];
+
+ if (!use_null_for_in || !use_null_for_out || !use_null_for_err)
+ {
+ if (options->jo_set & JO_CHANNEL)
+ {
+ channel = options->jo_channel;
+ if (channel != NULL)
+ ++channel->ch_refcount;
+ }
+ else
+ channel = add_channel();
+ if (channel == NULL)
+ goto failed;
+ }
+
+ if (!vim_create_process(cmd, TRUE,
+ CREATE_SUSPENDED |
+ CREATE_DEFAULT_ERROR_MODE |
+ CREATE_NEW_PROCESS_GROUP |
+ CREATE_UNICODE_ENVIRONMENT |
+ CREATE_NEW_CONSOLE,
+ &si, &pi,
+ ga.ga_data,
+ (char *)options->jo_cwd))
+ {
+ CloseHandle(jo);
+ job->jv_status = JOB_FAILED;
+ goto failed;
+ }
+
+ ga_clear(&ga);
+
+ if (!AssignProcessToJobObject(jo, pi.hProcess))
+ {
+ /* if failing, switch the way to terminate
+ * process with TerminateProcess. */
+ CloseHandle(jo);
+ jo = NULL;
+ }
+ ResumeThread(pi.hThread);
+ CloseHandle(pi.hThread);
+ job->jv_proc_info = pi;
+ job->jv_job_object = jo;
+ job->jv_status = JOB_STARTED;
+
+ CloseHandle(ifd[0]);
+ CloseHandle(ofd[1]);
+ if (!use_out_for_err && !use_null_for_err)
+ CloseHandle(efd[1]);
+
+ job->jv_channel = channel;
+ if (channel != NULL)
+ {
+ channel_set_pipes(channel,
+ use_file_for_in || use_null_for_in
+ ? INVALID_FD : (sock_T)ifd[1],
+ use_file_for_out || use_null_for_out
+ ? INVALID_FD : (sock_T)ofd[0],
+ use_out_for_err || use_file_for_err || use_null_for_err
+ ? INVALID_FD : (sock_T)efd[0]);
+ channel_set_job(channel, job, options);
+ }
+ return;
+
+failed:
+ CloseHandle(ifd[0]);
+ CloseHandle(ofd[0]);
+ CloseHandle(efd[0]);
+ CloseHandle(ifd[1]);
+ CloseHandle(ofd[1]);
+ CloseHandle(efd[1]);
+ channel_unref(channel);
+ ga_clear(&ga);
+}
+
+ char *
+mch_job_status(job_T *job)
+{
+ DWORD dwExitCode = 0;
+
+ if (!GetExitCodeProcess(job->jv_proc_info.hProcess, &dwExitCode)
+ || dwExitCode != STILL_ACTIVE)
+ {
+ job->jv_exitval = (int)dwExitCode;
+ if (job->jv_status < JOB_ENDED)
+ {
+ ch_log(job->jv_channel, "Job ended");
+ job->jv_status = JOB_ENDED;
+ }
+ return "dead";
+ }
+ return "run";
+}
+
+ job_T *
+mch_detect_ended_job(job_T *job_list)
+{
+ HANDLE jobHandles[MAXIMUM_WAIT_OBJECTS];
+ job_T *jobArray[MAXIMUM_WAIT_OBJECTS];
+ job_T *job = job_list;
+
+ while (job != NULL)
+ {
+ DWORD n;
+ DWORD result;
+
+ for (n = 0; n < MAXIMUM_WAIT_OBJECTS
+ && job != NULL; job = job->jv_next)
+ {
+ if (job->jv_status == JOB_STARTED)
+ {
+ jobHandles[n] = job->jv_proc_info.hProcess;
+ jobArray[n] = job;
+ ++n;
+ }
+ }
+ if (n == 0)
+ continue;
+ result = WaitForMultipleObjects(n, jobHandles, FALSE, 0);
+ if (result >= WAIT_OBJECT_0 && result < WAIT_OBJECT_0 + n)
+ {
+ job_T *wait_job = jobArray[result - WAIT_OBJECT_0];
+
+ if (STRCMP(mch_job_status(wait_job), "dead") == 0)
+ return wait_job;
+ }
+ }
+ return NULL;
+}
+
+ static BOOL
+terminate_all(HANDLE process, int code)
+{
+ PROCESSENTRY32 pe;
+ HANDLE h = INVALID_HANDLE_VALUE;
+ DWORD pid = GetProcessId(process);
+
+ if (pid != 0)
+ {
+ h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+ if (h != INVALID_HANDLE_VALUE)
+ {
+ pe.dwSize = sizeof(PROCESSENTRY32);
+ if (!Process32First(h, &pe))
+ goto theend;
+
+ do
+ {
+ if (pe.th32ParentProcessID == pid)
+ {
+ HANDLE ph = OpenProcess(
+ PROCESS_ALL_ACCESS, FALSE, pe.th32ProcessID);
+ if (ph != NULL)
+ {
+ terminate_all(ph, code);
+ CloseHandle(ph);
+ }
+ }
+ } while (Process32Next(h, &pe));
+
+ CloseHandle(h);
+ }
+ }
+
+theend:
+ return TerminateProcess(process, code);
+}
+
+/*
+ * Send a (deadly) signal to "job".
+ * Return FAIL if it didn't work.
+ */
+ int
+mch_signal_job(job_T *job, char_u *how)
+{
+ int ret;
+
+ if (STRCMP(how, "term") == 0 || STRCMP(how, "kill") == 0 || *how == NUL)
+ {
+ /* deadly signal */
+ if (job->jv_job_object != NULL)
+ {
+ if (job->jv_channel != NULL && job->jv_channel->ch_anonymous_pipe)
+ job->jv_channel->ch_killing = TRUE;
+ return TerminateJobObject(job->jv_job_object, 0) ? OK : FAIL;
+ }
+ return terminate_all(job->jv_proc_info.hProcess, 0) ? OK : FAIL;
+ }
+
+ if (!AttachConsole(job->jv_proc_info.dwProcessId))
+ return FAIL;
+ ret = GenerateConsoleCtrlEvent(
+ STRCMP(how, "int") == 0 ? CTRL_C_EVENT : CTRL_BREAK_EVENT,
+ job->jv_proc_info.dwProcessId)
+ ? OK : FAIL;
+ FreeConsole();
+ return ret;
+}
+
+/*
+ * Clear the data related to "job".
+ */
+ void
+mch_clear_job(job_T *job)
+{
+ if (job->jv_status != JOB_FAILED)
+ {
+ if (job->jv_job_object != NULL)
+ CloseHandle(job->jv_job_object);
+ CloseHandle(job->jv_proc_info.hProcess);
+ }
+}
+#endif
+
+
+#ifndef FEAT_GUI_W32
+
+/*
+ * Start termcap mode
+ */
+ static void
+termcap_mode_start(void)
+{
+ DWORD cmodein;
+
+ if (g_fTermcapMode)
+ return;
+
+ SaveConsoleBuffer(&g_cbNonTermcap);
+
+ if (g_cbTermcap.IsValid)
+ {
+ /*
+ * We've been in termcap mode before. Restore certain screen
+ * characteristics, including the buffer size and the window
+ * size. Since we will be redrawing the screen, we don't need
+ * to restore the actual contents of the buffer.
+ */
+ RestoreConsoleBuffer(&g_cbTermcap, FALSE);
+ reset_console_color_rgb();
+ SetConsoleWindowInfo(g_hConOut, TRUE, &g_cbTermcap.Info.srWindow);
+ Rows = g_cbTermcap.Info.dwSize.Y;
+ Columns = g_cbTermcap.Info.dwSize.X;
+ }
+ else
+ {
+ /*
+ * This is our first time entering termcap mode. Clear the console
+ * screen buffer, and resize the buffer to match the current window
+ * size. We will use this as the size of our editing environment.
+ */
+ ClearConsoleBuffer(g_attrCurrent);
+ set_console_color_rgb();
+ ResizeConBufAndWindow(g_hConOut, Columns, Rows);
+ }
+
+#ifdef FEAT_TITLE
+ resettitle();
+#endif
+
+ GetConsoleMode(g_hConIn, &cmodein);
+#ifdef FEAT_MOUSE
+ if (g_fMouseActive)
+ cmodein |= ENABLE_MOUSE_INPUT;
+ else
+ cmodein &= ~ENABLE_MOUSE_INPUT;
+#endif
+ cmodein |= ENABLE_WINDOW_INPUT;
+ SetConsoleMode(g_hConIn, cmodein);
+
+ redraw_later_clear();
+ g_fTermcapMode = TRUE;
+}
+
+
+/*
+ * End termcap mode
+ */
+ static void
+termcap_mode_end(void)
+{
+ DWORD cmodein;
+ ConsoleBuffer *cb;
+ COORD coord;
+ DWORD dwDummy;
+
+ if (!g_fTermcapMode)
+ return;
+
+ SaveConsoleBuffer(&g_cbTermcap);
+
+ GetConsoleMode(g_hConIn, &cmodein);
+ cmodein &= ~(ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT);
+ SetConsoleMode(g_hConIn, cmodein);
+
+#ifdef FEAT_RESTORE_ORIG_SCREEN
+ cb = exiting ? &g_cbOrig : &g_cbNonTermcap;
+#else
+ cb = &g_cbNonTermcap;
+#endif
+ RestoreConsoleBuffer(cb, p_rs);
+ reset_console_color_rgb();
+ SetConsoleCursorInfo(g_hConOut, &g_cci);
+
+ if (p_rs || exiting)
+ {
+ /*
+ * Clear anything that happens to be on the current line.
+ */
+ coord.X = 0;
+ coord.Y = (SHORT) (p_rs ? cb->Info.dwCursorPosition.Y : (Rows - 1));
+ FillConsoleOutputCharacter(g_hConOut, ' ',
+ cb->Info.dwSize.X, coord, &dwDummy);
+ /*
+ * The following is just for aesthetics. If we are exiting without
+ * restoring the screen, then we want to have a prompt string
+ * appear at the bottom line. However, the command interpreter
+ * seems to always advance the cursor one line before displaying
+ * the prompt string, which causes the screen to scroll. To
+ * counter this, move the cursor up one line before exiting.
+ */
+ if (exiting && !p_rs)
+ coord.Y--;
+ /*
+ * Position the cursor at the leftmost column of the desired row.
+ */
+ SetConsoleCursorPosition(g_hConOut, coord);
+ }
+
+ g_fTermcapMode = FALSE;
+}
+#endif /* FEAT_GUI_W32 */
+
+
+#ifdef FEAT_GUI_W32
+ void
+mch_write(
+ char_u *s UNUSED,
+ int len UNUSED)
+{
+ /* never used */
+}
+
+#else
+
+/*
+ * clear `n' chars, starting from `coord'
+ */
+ static void
+clear_chars(
+ COORD coord,
+ DWORD n)
+{
+ DWORD dwDummy;
+
+ FillConsoleOutputCharacter(g_hConOut, ' ', n, coord, &dwDummy);
+
+ if (!USE_VTP)
+ FillConsoleOutputAttribute(g_hConOut, g_attrCurrent, n, coord, &dwDummy);
+ else
+ {
+ set_console_color_rgb();
+ gotoxy(coord.X + 1, coord.Y + 1);
+ vtp_printf("\033[%dX", n);
+ }
+}
+
+
+/*
+ * Clear the screen
+ */
+ static void
+clear_screen(void)
+{
+ g_coord.X = g_coord.Y = 0;
+
+ if (!USE_VTP)
+ clear_chars(g_coord, Rows * Columns);
+ else
+ {
+ set_console_color_rgb();
+ gotoxy(1, 1);
+ vtp_printf("\033[2J");
+ }
+}
+
+
+/*
+ * Clear to end of display
+ */
+ static void
+clear_to_end_of_display(void)
+{
+ COORD save = g_coord;
+
+ if (!USE_VTP)
+ clear_chars(g_coord, (Rows - g_coord.Y - 1)
+ * Columns + (Columns - g_coord.X));
+ else
+ {
+ set_console_color_rgb();
+ gotoxy(g_coord.X + 1, g_coord.Y + 1);
+ vtp_printf("\033[0J");
+
+ gotoxy(save.X + 1, save.Y + 1);
+ g_coord = save;
+ }
+}
+
+
+/*
+ * Clear to end of line
+ */
+ static void
+clear_to_end_of_line(void)
+{
+ COORD save = g_coord;
+
+ if (!USE_VTP)
+ clear_chars(g_coord, Columns - g_coord.X);
+ else
+ {
+ set_console_color_rgb();
+ gotoxy(g_coord.X + 1, g_coord.Y + 1);
+ vtp_printf("\033[0K");
+
+ gotoxy(save.X + 1, save.Y + 1);
+ g_coord = save;
+ }
+}
+
+
+/*
+ * Scroll the scroll region up by `cLines' lines
+ */
+ static void
+scroll(unsigned cLines)
+{
+ COORD oldcoord = g_coord;
+
+ gotoxy(g_srScrollRegion.Left + 1, g_srScrollRegion.Top + 1);
+ delete_lines(cLines);
+
+ g_coord = oldcoord;
+}
+
+
+/*
+ * Set the scroll region
+ */
+ static void
+set_scroll_region(
+ unsigned left,
+ unsigned top,
+ unsigned right,
+ unsigned bottom)
+{
+ if (left >= right
+ || top >= bottom
+ || right > (unsigned) Columns - 1
+ || bottom > (unsigned) Rows - 1)
+ return;
+
+ g_srScrollRegion.Left = left;
+ g_srScrollRegion.Top = top;
+ g_srScrollRegion.Right = right;
+ g_srScrollRegion.Bottom = bottom;
+
+ if (USE_VTP)
+ vtp_printf("\033[%d;%dr", top + 1, bottom + 1);
+}
+
+
+/*
+ * Insert `cLines' lines at the current cursor position
+ */
+ static void
+insert_lines(unsigned cLines)
+{
+ SMALL_RECT source;
+ COORD dest;
+ CHAR_INFO fill;
+
+ dest.X = 0;
+ dest.Y = g_coord.Y + cLines;
+
+ source.Left = 0;
+ source.Top = g_coord.Y;
+ source.Right = g_srScrollRegion.Right;
+ source.Bottom = g_srScrollRegion.Bottom - cLines;
+
+ if (!USE_VTP)
+ {
+ fill.Char.AsciiChar = ' ';
+ fill.Attributes = g_attrCurrent;
+
+ ScrollConsoleScreenBuffer(g_hConOut, &source, NULL, dest, &fill);
+ }
+ else
+ {
+ set_console_color_rgb();
+
+ gotoxy(1, source.Top + 1);
+ vtp_printf("\033[%dT", cLines);
+ }
+
+ /* Here we have to deal with a win32 console flake: If the scroll
+ * region looks like abc and we scroll c to a and fill with d we get
+ * cbd... if we scroll block c one line at a time to a, we get cdd...
+ * vim expects cdd consistently... So we have to deal with that
+ * here... (this also occurs scrolling the same way in the other
+ * direction). */
+
+ if (source.Bottom < dest.Y)
+ {
+ COORD coord;
+
+ coord.X = 0;
+ coord.Y = source.Bottom;
+ clear_chars(coord, Columns * (dest.Y - source.Bottom));
+ }
+}
+
+
+/*
+ * Delete `cLines' lines at the current cursor position
+ */
+ static void
+delete_lines(unsigned cLines)
+{
+ SMALL_RECT source;
+ COORD dest;
+ CHAR_INFO fill;
+ int nb;
+
+ dest.X = 0;
+ dest.Y = g_coord.Y;
+
+ source.Left = 0;
+ source.Top = g_coord.Y + cLines;
+ source.Right = g_srScrollRegion.Right;
+ source.Bottom = g_srScrollRegion.Bottom;
+
+ if (!USE_VTP)
+ {
+ fill.Char.AsciiChar = ' ';
+ fill.Attributes = g_attrCurrent;
+
+ ScrollConsoleScreenBuffer(g_hConOut, &source, NULL, dest, &fill);
+ }
+ else
+ {
+ set_console_color_rgb();
+
+ gotoxy(1, source.Top + 1);
+ vtp_printf("\033[%dS", cLines);
+ }
+
+ /* Here we have to deal with a win32 console flake: If the scroll
+ * region looks like abc and we scroll c to a and fill with d we get
+ * cbd... if we scroll block c one line at a time to a, we get cdd...
+ * vim expects cdd consistently... So we have to deal with that
+ * here... (this also occurs scrolling the same way in the other
+ * direction). */
+
+ nb = dest.Y + (source.Bottom - source.Top) + 1;
+
+ if (nb < source.Top)
+ {
+ COORD coord;
+
+ coord.X = 0;
+ coord.Y = nb;
+ clear_chars(coord, Columns * (source.Top - nb));
+ }
+}
+
+
+/*
+ * Set the cursor position
+ */
+ static void
+gotoxy(
+ unsigned x,
+ unsigned y)
+{
+ if (x < 1 || x > (unsigned)Columns || y < 1 || y > (unsigned)Rows)
+ return;
+
+ /* external cursor coords are 1-based; internal are 0-based */
+ g_coord.X = x - 1;
+ g_coord.Y = y - 1;
+
+ if (!USE_VTP)
+ SetConsoleCursorPosition(g_hConOut, g_coord);
+ else
+ vtp_printf("\033[%d;%dH", y, x);
+}
+
+
+/*
+ * Set the current text attribute = (foreground | background)
+ * See ../doc/os_win32.txt for the numbers.
+ */
+ static void
+textattr(WORD wAttr)
+{
+ g_attrCurrent = wAttr & 0xff;
+
+ SetConsoleTextAttribute(g_hConOut, wAttr);
+}
+
+
+ static void
+textcolor(WORD wAttr)
+{
+ g_attrCurrent = (g_attrCurrent & 0xf0) + (wAttr & 0x0f);
+
+ if (!USE_VTP)
+ SetConsoleTextAttribute(g_hConOut, g_attrCurrent);
+ else
+ vtp_sgr_bulk(wAttr);
+}
+
+
+ static void
+textbackground(WORD wAttr)
+{
+ g_attrCurrent = (g_attrCurrent & 0x0f) + ((wAttr & 0x0f) << 4);
+
+ if (!USE_VTP)
+ SetConsoleTextAttribute(g_hConOut, g_attrCurrent);
+ else
+ vtp_sgr_bulk(wAttr);
+}
+
+
+/*
+ * restore the default text attribute (whatever we started with)
+ */
+ static void
+normvideo(void)
+{
+ if (!USE_VTP)
+ textattr(g_attrDefault);
+ else
+ vtp_sgr_bulk(0);
+}
+
+
+static WORD g_attrPreStandout = 0;
+
+/*
+ * Make the text standout, by brightening it
+ */
+ static void
+standout(void)
+{
+ g_attrPreStandout = g_attrCurrent;
+
+ textattr((WORD) (g_attrCurrent|FOREGROUND_INTENSITY|BACKGROUND_INTENSITY));
+}
+
+
+/*
+ * Turn off standout mode
+ */
+ static void
+standend(void)
+{
+ if (g_attrPreStandout)
+ textattr(g_attrPreStandout);
+
+ g_attrPreStandout = 0;
+}
+
+
+/*
+ * Set normal fg/bg color, based on T_ME. Called when t_me has been set.
+ */
+ void
+mch_set_normal_colors(void)
+{
+ char_u *p;
+ int n;
+
+ cterm_normal_fg_color = (g_attrDefault & 0xf) + 1;
+ cterm_normal_bg_color = ((g_attrDefault >> 4) & 0xf) + 1;
+ if (
+#ifdef FEAT_TERMGUICOLORS
+ !p_tgc &&
+#endif
+ T_ME[0] == ESC && T_ME[1] == '|')
+ {
+ p = T_ME + 2;
+ n = getdigits(&p);
+ if (*p == 'm' && n > 0)
+ {
+ cterm_normal_fg_color = (n & 0xf) + 1;
+ cterm_normal_bg_color = ((n >> 4) & 0xf) + 1;
+ }
+ }
+#ifdef FEAT_TERMGUICOLORS
+ cterm_normal_fg_gui_color = INVALCOLOR;
+ cterm_normal_bg_gui_color = INVALCOLOR;
+#endif
+}
+
+
+/*
+ * visual bell: flash the screen
+ */
+ static void
+visual_bell(void)
+{
+ COORD coordOrigin = {0, 0};
+ WORD attrFlash = ~g_attrCurrent & 0xff;
+
+ DWORD dwDummy;
+ LPWORD oldattrs = (LPWORD)alloc(Rows * Columns * sizeof(WORD));
+
+ if (oldattrs == NULL)
+ return;
+ ReadConsoleOutputAttribute(g_hConOut, oldattrs, Rows * Columns,
+ coordOrigin, &dwDummy);
+ FillConsoleOutputAttribute(g_hConOut, attrFlash, Rows * Columns,
+ coordOrigin, &dwDummy);
+
+ Sleep(15); /* wait for 15 msec */
+ if (!USE_VTP)
+ WriteConsoleOutputAttribute(g_hConOut, oldattrs, Rows * Columns,
+ coordOrigin, &dwDummy);
+ vim_free(oldattrs);
+}
+
+
+/*
+ * Make the cursor visible or invisible
+ */
+ static void
+cursor_visible(BOOL fVisible)
+{
+ s_cursor_visible = fVisible;
+#ifdef MCH_CURSOR_SHAPE
+ mch_update_cursor();
+#endif
+}
+
+
+/*
+ * Write "cbToWrite" bytes in `pchBuf' to the screen.
+ * Returns the number of bytes actually written (at least one).
+ */
+ static DWORD
+write_chars(
+ char_u *pchBuf,
+ DWORD cbToWrite)
+{
+ COORD coord = g_coord;
+ DWORD written;
+
+ if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+ {
+ static WCHAR *unicodebuf = NULL;
+ static int unibuflen = 0;
+ int length;
+ DWORD n, cchwritten, cells;
+
+ length = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)pchBuf, cbToWrite, 0, 0);
+ if (unicodebuf == NULL || length > unibuflen)
+ {
+ vim_free(unicodebuf);
+ unicodebuf = (WCHAR *)lalloc(length * sizeof(WCHAR), FALSE);
+ unibuflen = length;
+ }
+ MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)pchBuf, cbToWrite,
+ unicodebuf, unibuflen);
+
+ cells = mb_string2cells(pchBuf, cbToWrite);
+
+ if (!USE_VTP)
+ {
+ FillConsoleOutputAttribute(g_hConOut, g_attrCurrent, cells,
+ coord, &written);
+ /* When writing fails or didn't write a single character, pretend one
+ * character was written, otherwise we get stuck. */
+ if (WriteConsoleOutputCharacterW(g_hConOut, unicodebuf, length,
+ coord, &cchwritten) == 0
+ || cchwritten == 0)
+ cchwritten = 1;
+ }
+ else
+ {
+ if (WriteConsoleW(g_hConOut, unicodebuf, length, &cchwritten,
+ NULL) == 0 || cchwritten == 0)
+ cchwritten = 1;
+ }
+
+ if (cchwritten == length)
+ {
+ written = cbToWrite;
+ g_coord.X += (SHORT)cells;
+ }
+ else
+ {
+ char_u *p = pchBuf;
+ for (n = 0; n < cchwritten; n++)
+ MB_CPTR_ADV(p);
+ written = p - pchBuf;
+ g_coord.X += (SHORT)mb_string2cells(pchBuf, written);
+ }
+ }
+ else
+ {
+ if (!USE_VTP)
+ {
+ FillConsoleOutputAttribute(g_hConOut, g_attrCurrent, cbToWrite,
+ coord, &written);
+ /* When writing fails or didn't write a single character, pretend one
+ * character was written, otherwise we get stuck. */
+ if (WriteConsoleOutputCharacter(g_hConOut, (LPCSTR)pchBuf, cbToWrite,
+ coord, &written) == 0
+ || written == 0)
+ written = 1;
+ }
+ else
+ {
+ if (WriteConsole(g_hConOut, (LPCSTR)pchBuf, cbToWrite, &written,
+ NULL) == 0 || written == 0)
+ written = 1;
+ }
+
+ g_coord.X += (SHORT) written;
+ }
+
+ while (g_coord.X > g_srScrollRegion.Right)
+ {
+ g_coord.X -= (SHORT) Columns;
+ if (g_coord.Y < g_srScrollRegion.Bottom)
+ g_coord.Y++;
+ }
+
+ gotoxy(g_coord.X + 1, g_coord.Y + 1);
+
+ return written;
+}
+
+
+/*
+ * mch_write(): write the output buffer to the screen, translating ESC
+ * sequences into calls to console output routines.
+ */
+ void
+mch_write(
+ char_u *s,
+ int len)
+{
+ s[len] = NUL;
+
+ if (!term_console)
+ {
+ write(1, s, (unsigned)len);
+ return;
+ }
+
+ /* translate ESC | sequences into faked bios calls */
+ while (len--)
+ {
+ /* optimization: use one single write_chars for runs of text,
+ * rather than once per character It ain't curses, but it helps. */
+ DWORD prefix = (DWORD)strcspn((char *)s, "\n\r\b\a\033");
+
+ if (p_wd)
+ {
+ WaitForChar(p_wd, FALSE);
+ if (prefix != 0)
+ prefix = 1;
+ }
+
+ if (prefix != 0)
+ {
+ DWORD nWritten;
+
+ nWritten = write_chars(s, prefix);
+#ifdef MCH_WRITE_DUMP
+ if (fdDump)
+ {
+ fputc('>', fdDump);
+ fwrite(s, sizeof(char_u), nWritten, fdDump);
+ fputs("<\n", fdDump);
+ }
+#endif
+ len -= (nWritten - 1);
+ s += nWritten;
+ }
+ else if (s[0] == '\n')
+ {
+ /* \n, newline: go to the beginning of the next line or scroll */
+ if (g_coord.Y == g_srScrollRegion.Bottom)
+ {
+ scroll(1);
+ gotoxy(g_srScrollRegion.Left + 1, g_srScrollRegion.Bottom + 1);
+ }
+ else
+ {
+ gotoxy(g_srScrollRegion.Left + 1, g_coord.Y + 2);
+ }
+#ifdef MCH_WRITE_DUMP
+ if (fdDump)
+ fputs("\\n\n", fdDump);
+#endif
+ s++;
+ }
+ else if (s[0] == '\r')
+ {
+ /* \r, carriage return: go to beginning of line */
+ gotoxy(g_srScrollRegion.Left+1, g_coord.Y + 1);
+#ifdef MCH_WRITE_DUMP
+ if (fdDump)
+ fputs("\\r\n", fdDump);
+#endif
+ s++;
+ }
+ else if (s[0] == '\b')
+ {
+ /* \b, backspace: move cursor one position left */
+ if (g_coord.X > g_srScrollRegion.Left)
+ g_coord.X--;
+ else if (g_coord.Y > g_srScrollRegion.Top)
+ {
+ g_coord.X = g_srScrollRegion.Right;
+ g_coord.Y--;
+ }
+ gotoxy(g_coord.X + 1, g_coord.Y + 1);
+#ifdef MCH_WRITE_DUMP
+ if (fdDump)
+ fputs("\\b\n", fdDump);
+#endif
+ s++;
+ }
+ else if (s[0] == '\a')
+ {
+ /* \a, bell */
+ MessageBeep(0xFFFFFFFF);
+#ifdef MCH_WRITE_DUMP
+ if (fdDump)
+ fputs("\\a\n", fdDump);
+#endif
+ s++;
+ }
+ else if (s[0] == ESC && len >= 3-1 && s[1] == '|')
+ {
+#ifdef MCH_WRITE_DUMP
+ char_u *old_s = s;
+#endif
+ char_u *p;
+ int arg1 = 0, arg2 = 0, argc = 0, args[16];
+
+ switch (s[2])
+ {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ p = s + 1;
+ do
+ {
+ ++p;
+ args[argc] = getdigits(&p);
+ argc += (argc < 15) ? 1 : 0;
+ if (p > s + len)
+ break;
+ } while (*p == ';');
+
+ if (p > s + len)
+ break;
+
+ arg1 = args[0];
+ arg2 = args[1];
+ if (*p == 'm')
+ {
+ if (argc == 1 && args[0] == 0)
+ normvideo();
+ else if (argc == 1)
+ {
+ if (USE_VTP)
+ textcolor((WORD) arg1);
+ else
+ textattr((WORD) arg1);
+ }
+ else if (USE_VTP)
+ vtp_sgr_bulks(argc, args);
+ }
+ else if (argc == 2 && *p == 'H')
+ {
+ gotoxy(arg2, arg1);
+ }
+ else if (argc == 2 && *p == 'r')
+ {
+ set_scroll_region(0, arg1 - 1, Columns - 1, arg2 - 1);
+ }
+ else if (argc == 1 && *p == 'A')
+ {
+ gotoxy(g_coord.X + 1,
+ max(g_srScrollRegion.Top, g_coord.Y - arg1) + 1);
+ }
+ else if (argc == 1 && *p == 'b')
+ {
+ textbackground((WORD) arg1);
+ }
+ else if (argc == 1 && *p == 'C')
+ {
+ gotoxy(min(g_srScrollRegion.Right, g_coord.X + arg1) + 1,
+ g_coord.Y + 1);
+ }
+ else if (argc == 1 && *p == 'f')
+ {
+ textcolor((WORD) arg1);
+ }
+ else if (argc == 1 && *p == 'H')
+ {
+ gotoxy(1, arg1);
+ }
+ else if (argc == 1 && *p == 'L')
+ {
+ insert_lines(arg1);
+ }
+ else if (argc == 1 && *p == 'M')
+ {
+ delete_lines(arg1);
+ }
+
+ len -= (int)(p - s);
+ s = p + 1;
+ break;
+
+ case 'A':
+ gotoxy(g_coord.X + 1,
+ max(g_srScrollRegion.Top, g_coord.Y - 1) + 1);
+ goto got3;
+
+ case 'B':
+ visual_bell();
+ goto got3;
+
+ case 'C':
+ gotoxy(min(g_srScrollRegion.Right, g_coord.X + 1) + 1,
+ g_coord.Y + 1);
+ goto got3;
+
+ case 'E':
+ termcap_mode_end();
+ goto got3;
+
+ case 'F':
+ standout();
+ goto got3;
+
+ case 'f':
+ standend();
+ goto got3;
+
+ case 'H':
+ gotoxy(1, 1);
+ goto got3;
+
+ case 'j':
+ clear_to_end_of_display();
+ goto got3;
+
+ case 'J':
+ clear_screen();
+ goto got3;
+
+ case 'K':
+ clear_to_end_of_line();
+ goto got3;
+
+ case 'L':
+ insert_lines(1);
+ goto got3;
+
+ case 'M':
+ delete_lines(1);
+ goto got3;
+
+ case 'S':
+ termcap_mode_start();
+ goto got3;
+
+ case 'V':
+ cursor_visible(TRUE);
+ goto got3;
+
+ case 'v':
+ cursor_visible(FALSE);
+ goto got3;
+
+ got3:
+ s += 3;
+ len -= 2;
+ }
+
+#ifdef MCH_WRITE_DUMP
+ if (fdDump)
+ {
+ fputs("ESC | ", fdDump);
+ fwrite(old_s + 2, sizeof(char_u), s - old_s - 2, fdDump);
+ fputc('\n', fdDump);
+ }
+#endif
+ }
+ else
+ {
+ /* Write a single character */
+ DWORD nWritten;
+
+ nWritten = write_chars(s, 1);
+#ifdef MCH_WRITE_DUMP
+ if (fdDump)
+ {
+ fputc('>', fdDump);
+ fwrite(s, sizeof(char_u), nWritten, fdDump);
+ fputs("<\n", fdDump);
+ }
+#endif
+
+ len -= (nWritten - 1);
+ s += nWritten;
+ }
+ }
+
+#ifdef MCH_WRITE_DUMP
+ if (fdDump)
+ fflush(fdDump);
+#endif
+}
+
+#endif /* FEAT_GUI_W32 */
+
+
+/*
+ * Delay for "msec" milliseconds.
+ */
+ void
+mch_delay(
+ long msec,
+ int ignoreinput UNUSED)
+{
+#ifdef FEAT_GUI_W32
+ Sleep((int)msec); /* never wait for input */
+#else /* Console */
+ if (ignoreinput)
+# ifdef FEAT_MZSCHEME
+ if (mzthreads_allowed() && p_mzq > 0 && msec > p_mzq)
+ {
+ int towait = p_mzq;
+
+ /* if msec is large enough, wait by portions in p_mzq */
+ while (msec > 0)
+ {
+ mzvim_check_threads();
+ if (msec < towait)
+ towait = msec;
+ Sleep(towait);
+ msec -= towait;
+ }
+ }
+ else
+# endif
+ Sleep((int)msec);
+ else
+ WaitForChar(msec, FALSE);
+#endif
+}
+
+
+/*
+ * This version of remove is not scared by a readonly (backup) file.
+ * This can also remove a symbolic link like Unix.
+ * Return 0 for success, -1 for failure.
+ */
+ int
+mch_remove(char_u *name)
+{
+ WCHAR *wn = NULL;
+ int n;
+
+ /*
+ * On Windows, deleting a directory's symbolic link is done by
+ * RemoveDirectory(): mch_rmdir. It seems unnatural, but it is fact.
+ */
+ if (mch_isdir(name) && mch_is_symbolic_link(name))
+ return mch_rmdir(name);
+
+ win32_setattrs(name, FILE_ATTRIBUTE_NORMAL);
+
+ if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+ {
+ wn = enc_to_utf16(name, NULL);
+ if (wn != NULL)
+ {
+ n = DeleteFileW(wn) ? 0 : -1;
+ vim_free(wn);
+ return n;
+ }
+ }
+ return DeleteFile((LPCSTR)name) ? 0 : -1;
+}
+
+
+/*
+ * Check for an "interrupt signal": CTRL-break or CTRL-C.
+ */
+ void
+mch_breakcheck(int force)
+{
+#ifndef FEAT_GUI_W32 /* never used */
+ if (g_fCtrlCPressed || g_fCBrkPressed)
+ {
+ ctrl_break_was_pressed = g_fCBrkPressed;
+ g_fCtrlCPressed = g_fCBrkPressed = FALSE;
+ got_int = TRUE;
+ }
+#endif
+}
+
+/* physical RAM to leave for the OS */
+#define WINNT_RESERVE_BYTES (256*1024*1024)
+
+/*
+ * How much main memory in KiB that can be used by VIM.
+ */
+ long_u
+mch_total_mem(int special UNUSED)
+{
+ MEMORYSTATUSEX ms;
+
+ PlatformId();
+ /* Need to use GlobalMemoryStatusEx() when there is more memory than
+ * what fits in 32 bits. But it's not always available. */
+ ms.dwLength = sizeof(MEMORYSTATUSEX);
+ GlobalMemoryStatusEx(&ms);
+ if (ms.ullAvailVirtual < ms.ullTotalPhys)
+ {
+ /* Process address space fits in physical RAM, use all of it. */
+ return (long_u)(ms.ullAvailVirtual / 1024);
+ }
+ if (ms.ullTotalPhys <= WINNT_RESERVE_BYTES)
+ {
+ /* Catch old NT box or perverse hardware setup. */
+ return (long_u)((ms.ullTotalPhys / 2) / 1024);
+ }
+ /* Use physical RAM less reserve for OS + data. */
+ return (long_u)((ms.ullTotalPhys - WINNT_RESERVE_BYTES) / 1024);
+}
+
+/*
+ * Same code as below, but with wide functions and no comments.
+ * Return 0 for success, non-zero for failure.
+ */
+ int
+mch_wrename(WCHAR *wold, WCHAR *wnew)
+{
+ WCHAR *p;
+ int i;
+ WCHAR szTempFile[_MAX_PATH + 1];
+ WCHAR szNewPath[_MAX_PATH + 1];
+ HANDLE hf;
+
+ p = wold;
+ for (i = 0; wold[i] != NUL; ++i)
+ if ((wold[i] == '/' || wold[i] == '\\' || wold[i] == ':')
+ && wold[i + 1] != 0)
+ p = wold + i + 1;
+ if ((int)(wold + i - p) < 8 || p[6] != '~')
+ return (MoveFileW(wold, wnew) == 0);
+
+ if (GetFullPathNameW(wnew, _MAX_PATH, szNewPath, &p) == 0 || p == NULL)
+ return -1;
+ *p = NUL;
+
+ if (GetTempFileNameW(szNewPath, L"VIM", 0, szTempFile) == 0)
+ return -2;
+
+ if (!DeleteFileW(szTempFile))
+ return -3;
+
+ if (!MoveFileW(wold, szTempFile))
+ return -4;
+
+ if ((hf = CreateFileW(wold, GENERIC_WRITE, 0, NULL, CREATE_NEW,
+ FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE)
+ return -5;
+ if (!CloseHandle(hf))
+ return -6;
+
+ if (!MoveFileW(szTempFile, wnew))
+ {
+ (void)MoveFileW(szTempFile, wold);
+ return -7;
+ }
+
+ DeleteFileW(szTempFile);
+
+ if (!DeleteFileW(wold))
+ return -8;
+
+ return 0;
+}
+
+
+/*
+ * mch_rename() works around a bug in rename (aka MoveFile) in
+ * Windows 95: rename("foo.bar", "foo.bar~") will generate a
+ * file whose short file name is "FOO.BAR" (its long file name will
+ * be correct: "foo.bar~"). Because a file can be accessed by
+ * either its SFN or its LFN, "foo.bar" has effectively been
+ * renamed to "foo.bar", which is not at all what was wanted. This
+ * seems to happen only when renaming files with three-character
+ * extensions by appending a suffix that does not include ".".
+ * Windows NT gets it right, however, with an SFN of "FOO~1.BAR".
+ *
+ * There is another problem, which isn't really a bug but isn't right either:
+ * When renaming "abcdef~1.txt" to "abcdef~1.txt~", the short name can be
+ * "abcdef~1.txt" again. This has been reported on Windows NT 4.0 with
+ * service pack 6. Doesn't seem to happen on Windows 98.
+ *
+ * Like rename(), returns 0 upon success, non-zero upon failure.
+ * Should probably set errno appropriately when errors occur.
+ */
+ int
+mch_rename(
+ const char *pszOldFile,
+ const char *pszNewFile)
+{
+ char szTempFile[_MAX_PATH+1];
+ char szNewPath[_MAX_PATH+1];
+ char *pszFilePart;
+ HANDLE hf;
+ WCHAR *wold = NULL;
+ WCHAR *wnew = NULL;
+ int retval = -1;
+
+ if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+ {
+ wold = enc_to_utf16((char_u *)pszOldFile, NULL);
+ wnew = enc_to_utf16((char_u *)pszNewFile, NULL);
+ if (wold != NULL && wnew != NULL)
+ retval = mch_wrename(wold, wnew);
+ vim_free(wold);
+ vim_free(wnew);
+ return retval;
+ }
+
+ /*
+ * No need to play tricks unless the file name contains a "~" as the
+ * seventh character.
+ */
+ pszFilePart = (char *)gettail((char_u *)pszOldFile);
+ if (STRLEN(pszFilePart) < 8 || pszFilePart[6] != '~')
+ return rename(pszOldFile, pszNewFile);
+
+ /* Get base path of new file name. Undocumented feature: If pszNewFile is
+ * a directory, no error is returned and pszFilePart will be NULL. */
+ if (GetFullPathName(pszNewFile, _MAX_PATH, szNewPath, &pszFilePart) == 0
+ || pszFilePart == NULL)
+ return -1;
+ *pszFilePart = NUL;
+
+ /* Get (and create) a unique temporary file name in directory of new file */
+ if (GetTempFileName(szNewPath, "VIM", 0, szTempFile) == 0)
+ return -2;
+
+ /* blow the temp file away */
+ if (!DeleteFile(szTempFile))
+ return -3;
+
+ /* rename old file to the temp file */
+ if (!MoveFile(pszOldFile, szTempFile))
+ return -4;
+
+ /* now create an empty file called pszOldFile; this prevents the operating
+ * system using pszOldFile as an alias (SFN) if we're renaming within the
+ * same directory. For example, we're editing a file called
+ * filename.asc.txt by its SFN, filena~1.txt. If we rename filena~1.txt
+ * to filena~1.txt~ (i.e., we're making a backup while writing it), the
+ * SFN for filena~1.txt~ will be filena~1.txt, by default, which will
+ * cause all sorts of problems later in buf_write(). So, we create an
+ * empty file called filena~1.txt and the system will have to find some
+ * other SFN for filena~1.txt~, such as filena~2.txt
+ */
+ if ((hf = CreateFile(pszOldFile, GENERIC_WRITE, 0, NULL, CREATE_NEW,
+ FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE)
+ return -5;
+ if (!CloseHandle(hf))
+ return -6;
+
+ /* rename the temp file to the new file */
+ if (!MoveFile(szTempFile, pszNewFile))
+ {
+ /* Renaming failed. Rename the file back to its old name, so that it
+ * looks like nothing happened. */
+ (void)MoveFile(szTempFile, pszOldFile);
+
+ return -7;
+ }
+
+ /* Seems to be left around on Novell filesystems */
+ DeleteFile(szTempFile);
+
+ /* finally, remove the empty old file */
+ if (!DeleteFile(pszOldFile))
+ return -8;
+
+ return 0; /* success */
+}
+
+/*
+ * Get the default shell for the current hardware platform
+ */
+ char *
+default_shell(void)
+{
+ PlatformId();
+
+ return "cmd.exe";
+}
+
+/*
+ * mch_access() extends access() to do more detailed check on network drives.
+ * Returns 0 if file "n" has access rights according to "p", -1 otherwise.
+ */
+ int
+mch_access(char *n, int p)
+{
+ HANDLE hFile;
+ int retval = -1; /* default: fail */
+ WCHAR *wn = NULL;
+
+ if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+ wn = enc_to_utf16((char_u *)n, NULL);
+
+ if (mch_isdir((char_u *)n))
+ {
+ char TempName[_MAX_PATH + 16] = "";
+ WCHAR TempNameW[_MAX_PATH + 16] = L"";
+
+ if (p & R_OK)
+ {
+ /* Read check is performed by seeing if we can do a find file on
+ * the directory for any file. */
+ if (wn != NULL)
+ {
+ int i;
+ WIN32_FIND_DATAW d;
+
+ for (i = 0; i < _MAX_PATH && wn[i] != 0; ++i)
+ TempNameW[i] = wn[i];
+ if (TempNameW[i - 1] != '\\' && TempNameW[i - 1] != '/')
+ TempNameW[i++] = '\\';
+ TempNameW[i++] = '*';
+ TempNameW[i++] = 0;
+
+ hFile = FindFirstFileW(TempNameW, &d);
+ if (hFile == INVALID_HANDLE_VALUE)
+ goto getout;
+ else
+ (void)FindClose(hFile);
+ }
+ else
+ {
+ char *pch;
+ WIN32_FIND_DATA d;
+
+ vim_strncpy((char_u *)TempName, (char_u *)n, _MAX_PATH);
+ pch = TempName + STRLEN(TempName) - 1;
+ if (*pch != '\\' && *pch != '/')
+ *++pch = '\\';
+ *++pch = '*';
+ *++pch = NUL;
+
+ hFile = FindFirstFile(TempName, &d);
+ if (hFile == INVALID_HANDLE_VALUE)
+ goto getout;
+ (void)FindClose(hFile);
+ }
+ }
+
+ if (p & W_OK)
+ {
+ /* Trying to create a temporary file in the directory should catch
+ * directories on read-only network shares. However, in
+ * directories whose ACL allows writes but denies deletes will end
+ * up keeping the temporary file :-(. */
+ if (wn != NULL)
+ {
+ if (!GetTempFileNameW(wn, L"VIM", 0, TempNameW))
+ goto getout;
+ else
+ DeleteFileW(TempNameW);
+ }
+ else
+ {
+ if (!GetTempFileName(n, "VIM", 0, TempName))
+ goto getout;
+ mch_remove((char_u *)TempName);
+ }
+ }
+ }
+ else
+ {
+ // Don't consider a file read-only if another process has opened it.
+ DWORD share_mode = FILE_SHARE_READ | FILE_SHARE_WRITE;
+
+ /* Trying to open the file for the required access does ACL, read-only
+ * network share, and file attribute checks. */
+ DWORD access_mode = ((p & W_OK) ? GENERIC_WRITE : 0)
+ | ((p & R_OK) ? GENERIC_READ : 0);
+
+ if (wn != NULL)
+ hFile = CreateFileW(wn, access_mode, share_mode,
+ NULL, OPEN_EXISTING, 0, NULL);
+ else
+ hFile = CreateFile(n, access_mode, share_mode,
+ NULL, OPEN_EXISTING, 0, NULL);
+ if (hFile == INVALID_HANDLE_VALUE)
+ goto getout;
+ CloseHandle(hFile);
+ }
+
+ retval = 0; /* success */
+getout:
+ vim_free(wn);
+ return retval;
+}
+
+/*
+ * Version of open() that may use UTF-16 file name.
+ */
+ int
+mch_open(const char *name, int flags, int mode)
+{
+ /* _wopen() does not work with Borland C 5.5: creates a read-only file. */
+#ifndef __BORLANDC__
+ WCHAR *wn;
+ int f;
+
+ if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+ {
+ wn = enc_to_utf16((char_u *)name, NULL);
+ if (wn != NULL)
+ {
+ f = _wopen(wn, flags, mode);
+ vim_free(wn);
+ return f;
+ }
+ }
+#endif
+
+ /* open() can open a file which name is longer than _MAX_PATH bytes
+ * and shorter than _MAX_PATH characters successfully, but sometimes it
+ * causes unexpected error in another part. We make it an error explicitly
+ * here. */
+ if (strlen(name) >= _MAX_PATH)
+ return -1;
+
+ return open(name, flags, mode);
+}
+
+/*
+ * Version of fopen() that may use UTF-16 file name.
+ */
+ FILE *
+mch_fopen(const char *name, const char *mode)
+{
+ WCHAR *wn, *wm;
+ FILE *f = NULL;
+
+ if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+ {
+#if defined(DEBUG) && _MSC_VER >= 1400
+ /* Work around an annoying assertion in the Microsoft debug CRT
+ * when mode's text/binary setting doesn't match _get_fmode(). */
+ char newMode = mode[strlen(mode) - 1];
+ int oldMode = 0;
+
+ _get_fmode(&oldMode);
+ if (newMode == 't')
+ _set_fmode(_O_TEXT);
+ else if (newMode == 'b')
+ _set_fmode(_O_BINARY);
+#endif
+ wn = enc_to_utf16((char_u *)name, NULL);
+ wm = enc_to_utf16((char_u *)mode, NULL);
+ if (wn != NULL && wm != NULL)
+ f = _wfopen(wn, wm);
+ vim_free(wn);
+ vim_free(wm);
+
+#if defined(DEBUG) && _MSC_VER >= 1400
+ _set_fmode(oldMode);
+#endif
+ return f;
+ }
+
+ /* fopen() can open a file which name is longer than _MAX_PATH bytes
+ * and shorter than _MAX_PATH characters successfully, but sometimes it
+ * causes unexpected error in another part. We make it an error explicitly
+ * here. */
+ if (strlen(name) >= _MAX_PATH)
+ return NULL;
+
+ return fopen(name, mode);
+}
+
+/*
+ * SUB STREAM (aka info stream) handling:
+ *
+ * NTFS can have sub streams for each file. Normal contents of file is
+ * stored in the main stream, and extra contents (author information and
+ * title and so on) can be stored in sub stream. After Windows 2000, user
+ * can access and store those informations in sub streams via explorer's
+ * property menuitem in right click menu. Those informations in sub streams
+ * were lost when copying only the main stream. So we have to copy sub
+ * streams.
+ *
+ * Incomplete explanation:
+ * http://msdn.microsoft.com/library/en-us/dnw2k/html/ntfs5.asp
+ * More useful info and an example:
+ * http://www.sysinternals.com/ntw2k/source/misc.shtml#streams
+ */
+
+/*
+ * Copy info stream data "substream". Read from the file with BackupRead(sh)
+ * and write to stream "substream" of file "to".
+ * Errors are ignored.
+ */
+ static void
+copy_substream(HANDLE sh, void *context, WCHAR *to, WCHAR *substream, long len)
+{
+ HANDLE hTo;
+ WCHAR *to_name;
+
+ to_name = malloc((wcslen(to) + wcslen(substream) + 1) * sizeof(WCHAR));
+ wcscpy(to_name, to);
+ wcscat(to_name, substream);
+
+ hTo = CreateFileW(to_name, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL, NULL);
+ if (hTo != INVALID_HANDLE_VALUE)
+ {
+ long done;
+ DWORD todo;
+ DWORD readcnt, written;
+ char buf[4096];
+
+ /* Copy block of bytes at a time. Abort when something goes wrong. */
+ for (done = 0; done < len; done += written)
+ {
+ /* (size_t) cast for Borland C 5.5 */
+ todo = (DWORD)((size_t)(len - done) > sizeof(buf) ? sizeof(buf)
+ : (size_t)(len - done));
+ if (!BackupRead(sh, (LPBYTE)buf, todo, &readcnt,
+ FALSE, FALSE, context)
+ || readcnt != todo
+ || !WriteFile(hTo, buf, todo, &written, NULL)
+ || written != todo)
+ break;
+ }
+ CloseHandle(hTo);
+ }
+
+ free(to_name);
+}
+
+/*
+ * Copy info streams from file "from" to file "to".
+ */
+ static void
+copy_infostreams(char_u *from, char_u *to)
+{
+ WCHAR *fromw;
+ WCHAR *tow;
+ HANDLE sh;
+ WIN32_STREAM_ID sid;
+ int headersize;
+ WCHAR streamname[_MAX_PATH];
+ DWORD readcount;
+ void *context = NULL;
+ DWORD lo, hi;
+ int len;
+
+ /* Convert the file names to wide characters. */
+ fromw = enc_to_utf16(from, NULL);
+ tow = enc_to_utf16(to, NULL);
+ if (fromw != NULL && tow != NULL)
+ {
+ /* Open the file for reading. */
+ sh = CreateFileW(fromw, GENERIC_READ, FILE_SHARE_READ, NULL,
+ OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ if (sh != INVALID_HANDLE_VALUE)
+ {
+ /* Use BackupRead() to find the info streams. Repeat until we
+ * have done them all.*/
+ for (;;)
+ {
+ /* Get the header to find the length of the stream name. If
+ * the "readcount" is zero we have done all info streams. */
+ ZeroMemory(&sid, sizeof(WIN32_STREAM_ID));
+ headersize = (int)((char *)&sid.cStreamName - (char *)&sid.dwStreamId);
+ if (!BackupRead(sh, (LPBYTE)&sid, headersize,
+ &readcount, FALSE, FALSE, &context)
+ || readcount == 0)
+ break;
+
+ /* We only deal with streams that have a name. The normal
+ * file data appears to be without a name, even though docs
+ * suggest it is called "::$DATA". */
+ if (sid.dwStreamNameSize > 0)
+ {
+ /* Read the stream name. */
+ if (!BackupRead(sh, (LPBYTE)streamname,
+ sid.dwStreamNameSize,
+ &readcount, FALSE, FALSE, &context))
+ break;
+
+ /* Copy an info stream with a name ":anything:$DATA".
+ * Skip "::$DATA", it has no stream name (examples suggest
+ * it might be used for the normal file contents).
+ * Note that BackupRead() counts bytes, but the name is in
+ * wide characters. */
+ len = readcount / sizeof(WCHAR);
+ streamname[len] = 0;
+ if (len > 7 && wcsicmp(streamname + len - 6,
+ L":$DATA") == 0)
+ {
+ streamname[len - 6] = 0;
+ copy_substream(sh, &context, tow, streamname,
+ (long)sid.Size.u.LowPart);
+ }
+ }
+
+ /* Advance to the next stream. We might try seeking too far,
+ * but BackupSeek() doesn't skip over stream borders, thus
+ * that's OK. */
+ (void)BackupSeek(sh, sid.Size.u.LowPart, sid.Size.u.HighPart,
+ &lo, &hi, &context);
+ }
+
+ /* Clear the context. */
+ (void)BackupRead(sh, NULL, 0, &readcount, TRUE, FALSE, &context);
+
+ CloseHandle(sh);
+ }
+ }
+ vim_free(fromw);
+ vim_free(tow);
+}
+
+/*
+ * Copy file attributes from file "from" to file "to".
+ * For Windows NT and later we copy info streams.
+ * Always returns zero, errors are ignored.
+ */
+ int
+mch_copy_file_attribute(char_u *from, char_u *to)
+{
+ /* File streams only work on Windows NT and later. */
+ PlatformId();
+ copy_infostreams(from, to);
+ return 0;
+}
+
+#if defined(MYRESETSTKOFLW) || defined(PROTO)
+/*
+ * Recreate a destroyed stack guard page in win32.
+ * Written by Benjamin Peterson.
+ */
+
+/* These magic numbers are from the MS header files */
+# define MIN_STACK_WINNT 2
+
+/*
+ * This function does the same thing as _resetstkoflw(), which is only
+ * available in DevStudio .net and later.
+ * Returns 0 for failure, 1 for success.
+ */
+ int
+myresetstkoflw(void)
+{
+ BYTE *pStackPtr;
+ BYTE *pGuardPage;
+ BYTE *pStackBase;
+ BYTE *pLowestPossiblePage;
+ MEMORY_BASIC_INFORMATION mbi;
+ SYSTEM_INFO si;
+ DWORD nPageSize;
+ DWORD dummy;
+
+ PlatformId();
+
+ /* We need to know the system page size. */
+ GetSystemInfo(&si);
+ nPageSize = si.dwPageSize;
+
+ /* ...and the current stack pointer */
+ pStackPtr = (BYTE*)_alloca(1);
+
+ /* ...and the base of the stack. */
+ if (VirtualQuery(pStackPtr, &mbi, sizeof mbi) == 0)
+ return 0;
+ pStackBase = (BYTE*)mbi.AllocationBase;
+
+ /* ...and the page thats min_stack_req pages away from stack base; this is
+ * the lowest page we could use. */
+ pLowestPossiblePage = pStackBase + MIN_STACK_WINNT * nPageSize;
+
+ {
+ /* We want the first committed page in the stack Start at the stack
+ * base and move forward through memory until we find a committed block.
+ */
+ BYTE *pBlock = pStackBase;
+
+ for (;;)
+ {
+ if (VirtualQuery(pBlock, &mbi, sizeof mbi) == 0)
+ return 0;
+
+ pBlock += mbi.RegionSize;
+
+ if (mbi.State & MEM_COMMIT)
+ break;
+ }
+
+ /* mbi now describes the first committed block in the stack. */
+ if (mbi.Protect & PAGE_GUARD)
+ return 1;
+
+ /* decide where the guard page should start */
+ if ((long_u)(mbi.BaseAddress) < (long_u)pLowestPossiblePage)
+ pGuardPage = pLowestPossiblePage;
+ else
+ pGuardPage = (BYTE*)mbi.BaseAddress;
+
+ /* allocate the guard page */
+ if (!VirtualAlloc(pGuardPage, nPageSize, MEM_COMMIT, PAGE_READWRITE))
+ return 0;
+
+ /* apply the guard attribute to the page */
+ if (!VirtualProtect(pGuardPage, nPageSize, PAGE_READWRITE | PAGE_GUARD,
+ &dummy))
+ return 0;
+ }
+
+ return 1;
+}
+#endif
+
+
+/*
+ * The command line arguments in UCS2
+ */
+static int nArgsW = 0;
+static LPWSTR *ArglistW = NULL;
+static int global_argc = 0;
+static char **global_argv;
+
+static int used_file_argc = 0; /* last argument in global_argv[] used
+ for the argument list. */
+static int *used_file_indexes = NULL; /* indexes in global_argv[] for
+ command line arguments added to
+ the argument list */
+static int used_file_count = 0; /* nr of entries in used_file_indexes */
+static int used_file_literal = FALSE; /* take file names literally */
+static int used_file_full_path = FALSE; /* file name was full path */
+static int used_file_diff_mode = FALSE; /* file name was with diff mode */
+static int used_alist_count = 0;
+
+
+/*
+ * Get the command line arguments. Unicode version.
+ * Returns argc. Zero when something fails.
+ */
+ int
+get_cmd_argsW(char ***argvp)
+{
+ char **argv = NULL;
+ int argc = 0;
+ int i;
+
+ free_cmd_argsW();
+ ArglistW = CommandLineToArgvW(GetCommandLineW(), &nArgsW);
+ if (ArglistW != NULL)
+ {
+ argv = malloc((nArgsW + 1) * sizeof(char *));
+ if (argv != NULL)
+ {
+ argc = nArgsW;
+ argv[argc] = NULL;
+ for (i = 0; i < argc; ++i)
+ {
+ int len;
+
+ /* Convert each Unicode argument to the current codepage. */
+ WideCharToMultiByte_alloc(GetACP(), 0,
+ ArglistW[i], (int)wcslen(ArglistW[i]) + 1,
+ (LPSTR *)&argv[i], &len, 0, 0);
+ if (argv[i] == NULL)
+ {
+ /* Out of memory, clear everything. */
+ while (i > 0)
+ free(argv[--i]);
+ free(argv);
+ argv = NULL;
+ argc = 0;
+ }
+ }
+ }
+ }
+
+ global_argc = argc;
+ global_argv = argv;
+ if (argc > 0)
+ {
+ if (used_file_indexes != NULL)
+ free(used_file_indexes);
+ used_file_indexes = malloc(argc * sizeof(int));
+ }
+
+ if (argvp != NULL)
+ *argvp = argv;
+ return argc;
+}
+
+ void
+free_cmd_argsW(void)
+{
+ if (ArglistW != NULL)
+ {
+ GlobalFree(ArglistW);
+ ArglistW = NULL;
+ }
+}
+
+/*
+ * Remember "name" is an argument that was added to the argument list.
+ * This avoids that we have to re-parse the argument list when fix_arg_enc()
+ * is called.
+ */
+ void
+used_file_arg(char *name, int literal, int full_path, int diff_mode)
+{
+ int i;
+
+ if (used_file_indexes == NULL)
+ return;
+ for (i = used_file_argc + 1; i < global_argc; ++i)
+ if (STRCMP(global_argv[i], name) == 0)
+ {
+ used_file_argc = i;
+ used_file_indexes[used_file_count++] = i;
+ break;
+ }
+ used_file_literal = literal;
+ used_file_full_path = full_path;
+ used_file_diff_mode = diff_mode;
+}
+
+/*
+ * Remember the length of the argument list as it was. If it changes then we
+ * leave it alone when 'encoding' is set.
+ */
+ void
+set_alist_count(void)
+{
+ used_alist_count = GARGCOUNT;
+}
+
+/*
+ * Fix the encoding of the command line arguments. Invoked when 'encoding'
+ * has been changed while starting up. Use the UCS-2 command line arguments
+ * and convert them to 'encoding'.
+ */
+ void
+fix_arg_enc(void)
+{
+ int i;
+ int idx;
+ char_u *str;
+ int *fnum_list;
+
+ /* Safety checks:
+ * - if argument count differs between the wide and non-wide argument
+ * list, something must be wrong.
+ * - the file name arguments must have been located.
+ * - the length of the argument list wasn't changed by the user.
+ */
+ if (global_argc != nArgsW
+ || ArglistW == NULL
+ || used_file_indexes == NULL
+ || used_file_count == 0
+ || used_alist_count != GARGCOUNT)
+ return;
+
+ /* Remember the buffer numbers for the arguments. */
+ fnum_list = (int *)alloc((int)sizeof(int) * GARGCOUNT);
+ if (fnum_list == NULL)
+ return; /* out of memory */
+ for (i = 0; i < GARGCOUNT; ++i)
+ fnum_list[i] = GARGLIST[i].ae_fnum;
+
+ /* Clear the argument list. Make room for the new arguments. */
+ alist_clear(&global_alist);
+ if (ga_grow(&global_alist.al_ga, used_file_count) == FAIL)
+ return; /* out of memory */
+
+ for (i = 0; i < used_file_count; ++i)
+ {
+ idx = used_file_indexes[i];
+ str = utf16_to_enc(ArglistW[idx], NULL);
+ if (str != NULL)
+ {
+ int literal = used_file_literal;
+
+# ifdef FEAT_DIFF
+ /* When using diff mode may need to concatenate file name to
+ * directory name. Just like it's done in main(). */
+ if (used_file_diff_mode && mch_isdir(str) && GARGCOUNT > 0
+ && !mch_isdir(alist_name(&GARGLIST[0])))
+ {
+ char_u *r;
+
+ r = concat_fnames(str, gettail(alist_name(&GARGLIST[0])), TRUE);
+ if (r != NULL)
+ {
+ vim_free(str);
+ str = r;
+ }
+ }
+# endif
+ /* Re-use the old buffer by renaming it. When not using literal
+ * names it's done by alist_expand() below. */
+ if (used_file_literal)
+ buf_set_name(fnum_list[i], str);
+
+ /* Check backtick literal. backtick literal is already expanded in
+ * main.c, so this part add str as literal. */
+ if (literal == FALSE)
+ {
+ size_t len = STRLEN(str);
+
+ if (len > 2 && *str == '`' && *(str + len - 1) == '`')
+ literal = TRUE;
+ }
+ alist_add(&global_alist, str, literal ? 2 : 0);
+ }
+ }
+
+ if (!used_file_literal)
+ {
+ /* Now expand wildcards in the arguments. */
+ /* Temporarily add '(' and ')' to 'isfname'. These are valid
+ * filename characters but are excluded from 'isfname' to make
+ * "gf" work on a file name in parenthesis (e.g.: see vim.h).
+ * Also, unset wildignore to not be influenced by this option.
+ * The arguments specified in command-line should be kept even if
+ * encoding options were changed. */
+ do_cmdline_cmd((char_u *)":let SaVe_ISF = &isf|set isf+=(,)");
+ do_cmdline_cmd((char_u *)":let SaVe_WIG = &wig|set wig=");
+ alist_expand(fnum_list, used_alist_count);
+ do_cmdline_cmd((char_u *)":let &isf = SaVe_ISF|unlet SaVe_ISF");
+ do_cmdline_cmd((char_u *)":let &wig = SaVe_WIG|unlet SaVe_WIG");
+ }
+
+ /* If wildcard expansion failed, we are editing the first file of the
+ * arglist and there is no file name: Edit the first argument now. */
+ if (curwin->w_arg_idx == 0 && curbuf->b_fname == NULL)
+ {
+ do_cmdline_cmd((char_u *)":rewind");
+ if (GARGCOUNT == 1 && used_file_full_path)
+ (void)vim_chdirfile(alist_name(&GARGLIST[0]), "drop");
+ }
+
+ set_alist_count();
+}
+
+ int
+mch_setenv(char *var, char *value, int x)
+{
+ char_u *envbuf;
+
+ envbuf = alloc((unsigned)(STRLEN(var) + STRLEN(value) + 2));
+ if (envbuf == NULL)
+ return -1;
+
+ sprintf((char *)envbuf, "%s=%s", var, value);
+
+ if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+ {
+ WCHAR *p = enc_to_utf16(envbuf, NULL);
+
+ vim_free(envbuf);
+ if (p == NULL)
+ return -1;
+ _wputenv(p);
+#ifdef libintl_wputenv
+ libintl_wputenv(p);
+#endif
+ /* Unlike Un*x systems, we can free the string for _wputenv(). */
+ vim_free(p);
+ }
+ else
+ {
+ _putenv((char *)envbuf);
+#ifdef libintl_putenv
+ libintl_putenv((char *)envbuf);
+#endif
+ /* Unlike Un*x systems, we can free the string for _putenv(). */
+ vim_free(envbuf);
+ }
+
+ return 0;
+}
+
+/*
+ * Support for 256 colors and 24-bit colors was added in Windows 10
+ * version 1703 (Creators update).
+ */
+#define VTP_FIRST_SUPPORT_BUILD MAKE_VER(10, 0, 15063)
+
+/*
+ * Support for pseudo-console (ConPTY) was added in windows 10
+ * version 1809 (October 2018 update).
+ */
+#define CONPTY_FIRST_SUPPORT_BUILD MAKE_VER(10, 0, 17763)
+
+ static void
+vtp_flag_init(void)
+{
+ DWORD ver = get_build_number();
+#ifndef FEAT_GUI_W32
+ DWORD mode;
+ HANDLE out;
+
+ out = GetStdHandle(STD_OUTPUT_HANDLE);
+
+ vtp_working = (ver >= VTP_FIRST_SUPPORT_BUILD) ? 1 : 0;
+ GetConsoleMode(out, &mode);
+ mode |= (ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
+ if (SetConsoleMode(out, mode) == 0)
+ vtp_working = 0;
+#endif
+
+#ifdef FEAT_GUI_W32
+ if (ver >= CONPTY_FIRST_SUPPORT_BUILD)
+ vtp_working = 1;
+#endif
+
+}
+
+#ifndef FEAT_GUI_W32
+
+ static void
+vtp_init(void)
+{
+ HMODULE hKerneldll;
+ DYN_CONSOLE_SCREEN_BUFFER_INFOEX csbi;
+# ifdef FEAT_TERMGUICOLORS
+ COLORREF fg, bg;
+# endif
+
+ /* Use functions supported from Vista */
+ hKerneldll = GetModuleHandle("kernel32.dll");
+ if (hKerneldll != NULL)
+ {
+ pGetConsoleScreenBufferInfoEx =
+ (PfnGetConsoleScreenBufferInfoEx)GetProcAddress(
+ hKerneldll, "GetConsoleScreenBufferInfoEx");
+ pSetConsoleScreenBufferInfoEx =
+ (PfnSetConsoleScreenBufferInfoEx)GetProcAddress(
+ hKerneldll, "SetConsoleScreenBufferInfoEx");
+ if (pGetConsoleScreenBufferInfoEx != NULL
+ && pSetConsoleScreenBufferInfoEx != NULL)
+ has_csbiex = TRUE;
+ }
+
+ csbi.cbSize = sizeof(csbi);
+ if (has_csbiex)
+ pGetConsoleScreenBufferInfoEx(g_hConOut, &csbi);
+ save_console_bg_rgb = (guicolor_T)csbi.ColorTable[g_color_index_bg];
+ save_console_fg_rgb = (guicolor_T)csbi.ColorTable[g_color_index_fg];
+
+# ifdef FEAT_TERMGUICOLORS
+ bg = (COLORREF)csbi.ColorTable[g_color_index_bg];
+ fg = (COLORREF)csbi.ColorTable[g_color_index_fg];
+ bg = (GetRValue(bg) << 16) | (GetGValue(bg) << 8) | GetBValue(bg);
+ fg = (GetRValue(fg) << 16) | (GetGValue(fg) << 8) | GetBValue(fg);
+ default_console_color_bg = bg;
+ default_console_color_fg = fg;
+# endif
+
+ set_console_color_rgb();
+}
+
+ static void
+vtp_exit(void)
+{
+ reset_console_color_rgb();
+}
+
+ static int
+vtp_printf(
+ char *format,
+ ...)
+{
+ char_u buf[100];
+ va_list list;
+ DWORD result;
+
+ va_start(list, format);
+ vim_vsnprintf((char *)buf, 100, (char *)format, list);
+ va_end(list);
+ WriteConsoleA(g_hConOut, buf, (DWORD)STRLEN(buf), &result, NULL);
+ return (int)result;
+}
+
+ static void
+vtp_sgr_bulk(
+ int arg)
+{
+ int args[1];
+
+ args[0] = arg;
+ vtp_sgr_bulks(1, args);
+}
+
+ static void
+vtp_sgr_bulks(
+ int argc,
+ int *args
+)
+{
+ /* 2('\033[') + 4('255.') * 16 + NUL */
+ char_u buf[2 + (4 * 16) + 1];
+ char_u *p;
+ int i;
+
+ p = buf;
+ *p++ = '\033';
+ *p++ = '[';
+
+ for (i = 0; i < argc; ++i)
+ {
+ p += vim_snprintf((char *)p, 4, "%d", args[i] & 0xff);
+ *p++ = ';';
+ }
+ p--;
+ *p++ = 'm';
+ *p = NUL;
+ vtp_printf((char *)buf);
+}
+
+# ifdef FEAT_TERMGUICOLORS
+ static int
+ctermtoxterm(
+ int cterm)
+{
+ char_u r, g, b, idx;
+
+ cterm_color2rgb(cterm, &r, &g, &b, &idx);
+ return (((int)r << 16) | ((int)g << 8) | (int)b);
+}
+# endif
+
+ static void
+set_console_color_rgb(void)
+{
+# ifdef FEAT_TERMGUICOLORS
+ DYN_CONSOLE_SCREEN_BUFFER_INFOEX csbi;
+ int id;
+ guicolor_T fg = INVALCOLOR;
+ guicolor_T bg = INVALCOLOR;
+ int ctermfg;
+ int ctermbg;
+
+ if (!USE_VTP)
+ return;
+
+ id = syn_name2id((char_u *)"Normal");
+ if (id > 0)
+ syn_id2colors(id, &fg, &bg);
+ if (fg == INVALCOLOR)
+ {
+ ctermfg = -1;
+ if (id > 0)
+ syn_id2cterm_bg(id, &ctermfg, &ctermbg);
+ fg = ctermfg != -1 ? ctermtoxterm(ctermfg) : default_console_color_fg;
+ cterm_normal_fg_gui_color = fg;
+ }
+ if (bg == INVALCOLOR)
+ {
+ ctermbg = -1;
+ if (id > 0)
+ syn_id2cterm_bg(id, &ctermfg, &ctermbg);
+ bg = ctermbg != -1 ? ctermtoxterm(ctermbg) : default_console_color_bg;
+ cterm_normal_bg_gui_color = bg;
+ }
+ fg = (GetRValue(fg) << 16) | (GetGValue(fg) << 8) | GetBValue(fg);
+ bg = (GetRValue(bg) << 16) | (GetGValue(bg) << 8) | GetBValue(bg);
+
+ csbi.cbSize = sizeof(csbi);
+ if (has_csbiex)
+ pGetConsoleScreenBufferInfoEx(g_hConOut, &csbi);
+
+ csbi.cbSize = sizeof(csbi);
+ csbi.srWindow.Right += 1;
+ csbi.srWindow.Bottom += 1;
+ csbi.ColorTable[g_color_index_bg] = (COLORREF)bg;
+ csbi.ColorTable[g_color_index_fg] = (COLORREF)fg;
+ if (has_csbiex)
+ pSetConsoleScreenBufferInfoEx(g_hConOut, &csbi);
+# endif
+}
+
+ static void
+reset_console_color_rgb(void)
+{
+# ifdef FEAT_TERMGUICOLORS
+ DYN_CONSOLE_SCREEN_BUFFER_INFOEX csbi;
+
+ csbi.cbSize = sizeof(csbi);
+ if (has_csbiex)
+ pGetConsoleScreenBufferInfoEx(g_hConOut, &csbi);
+
+ csbi.cbSize = sizeof(csbi);
+ csbi.srWindow.Right += 1;
+ csbi.srWindow.Bottom += 1;
+ csbi.ColorTable[g_color_index_bg] = (COLORREF)save_console_bg_rgb;
+ csbi.ColorTable[g_color_index_fg] = (COLORREF)save_console_fg_rgb;
+ if (has_csbiex)
+ pSetConsoleScreenBufferInfoEx(g_hConOut, &csbi);
+# endif
+}
+
+ void
+control_console_color_rgb(void)
+{
+ if (USE_VTP)
+ set_console_color_rgb();
+ else
+ reset_console_color_rgb();
+}
+
+ int
+use_vtp(void)
+{
+ return USE_VTP;
+}
+
+ int
+is_term_win32(void)
+{
+ return T_NAME != NULL && STRCMP(T_NAME, "win32") == 0;
+}
+
+#endif
+
+ int
+has_vtp_working(void)
+{
+ return vtp_working;
+}
diff --git a/src/os_win32.h b/src/os_win32.h
new file mode 100644
index 0000000..6c4a349
--- /dev/null
+++ b/src/os_win32.h
@@ -0,0 +1,219 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * Do ":help uganda" in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ */
+
+/*
+ * Win32 (Windows NT and Windows 95) machine-dependent things.
+ */
+
+#include "os_dos.h" /* common MS-DOS and Win32 stuff */
+#ifndef __CYGWIN__
+/* cproto fails on missing include files */
+# ifndef PROTO
+# include <direct.h> /* for _mkdir() */
+# endif
+#endif
+
+/* Stop the VC2005 compiler from nagging. */
+#if _MSC_VER >= 1400
+# define _CRT_SECURE_NO_DEPRECATE
+# define _CRT_NONSTDC_NO_DEPRECATE
+#endif
+
+#define BINARY_FILE_IO
+#define USE_EXE_NAME /* use argv[0] for $VIM */
+#define USE_TERM_CONSOLE
+#ifndef HAVE_STRING_H
+# define HAVE_STRING_H
+#endif
+#ifndef HAVE_MATH_H
+# define HAVE_MATH_H
+#endif
+#define HAVE_STRCSPN
+#ifndef __GNUC__
+#define HAVE_STRICMP
+#define HAVE_STRNICMP
+#endif
+#ifndef HAVE_STRFTIME
+# define HAVE_STRFTIME /* guessed */
+#endif
+#define HAVE_MEMSET
+#ifndef HAVE_LOCALE_H
+# define HAVE_LOCALE_H 1
+#endif
+#ifndef HAVE_FCNTL_H
+# define HAVE_FCNTL_H
+#endif
+#define HAVE_QSORT
+#define HAVE_ST_MODE /* have stat.st_mode */
+
+#define FEAT_SHORTCUT /* resolve shortcuts */
+
+#if (!defined(__BORLANDC__) || __BORLANDC__ >= 0x550) \
+ && (!defined(_MSC_VER) || _MSC_VER > 1020)
+/*
+ * Access Control List (actually security info).
+ * Borland has the acl stuff only in version 5.5 and later.
+ * MSVC in 5.0, not in 4.2, don't know about 4.3.
+ */
+# define HAVE_ACL
+#endif
+
+#define USE_FNAME_CASE /* adjust case of file names */
+#if !defined(FEAT_CLIPBOARD) && defined(FEAT_MOUSE)
+# define FEAT_CLIPBOARD /* include clipboard support */
+#endif
+#if defined(__DATE__) && defined(__TIME__)
+# define HAVE_DATE_TIME
+#endif
+#ifndef FEAT_GUI_W32 /* GUI works different */
+# define BREAKCHECK_SKIP 1 /* call mch_breakcheck() each time, it's fast */
+#endif
+
+#define HAVE_TOTAL_MEM
+
+#define HAVE_PUTENV /* at least Bcc 5.2 and MSC have it */
+
+#ifdef FEAT_GUI_W32
+# define NO_CONSOLE /* don't included console-only code */
+#endif
+
+/* toupper() is not really broken, but it's very slow. Probably because of
+ * using Unicode characters on Windows NT */
+#define BROKEN_TOUPPER
+
+#define FNAME_ILLEGAL "\"*?><|" /* illegal characters in a file name */
+
+#include <signal.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sys/types.h>
+
+#ifndef STRICT
+# define STRICT
+#endif
+#ifndef COBJMACROS
+# define COBJMACROS /* For OLE: Enable "friendlier" access to objects */
+#endif
+#ifndef PROTO
+# include <windows.h>
+# ifndef SM_CXPADDEDBORDER
+# define SM_CXPADDEDBORDER 92
+# endif
+#endif
+
+/*
+ * Win32 has plenty of memory, use large buffers
+ */
+#define CMDBUFFSIZE 1024 /* size of the command processing buffer */
+
+/* _MAX_PATH is only 260 (stdlib.h), but we want more for the 'path' option,
+ * thus use a larger number. */
+#define MAXPATHL 1024
+
+#ifndef BASENAMELEN
+# define BASENAMELEN (_MAX_PATH - 5) /* length of base of file name */
+#endif
+
+#define TEMPNAMELEN _MAX_PATH /* length of temp file name path */
+
+#ifndef DFLT_MAXMEM
+# define DFLT_MAXMEM (2*1024) /* use up to 2 Mbyte for a buffer */
+#endif
+
+#ifndef DFLT_MAXMEMTOT
+# define DFLT_MAXMEMTOT (5*1024) /* use up to 5 Mbyte for Vim */
+#endif
+
+/*
+ * Reparse Point
+ */
+#ifndef FILE_ATTRIBUTE_REPARSE_POINT
+# define FILE_ATTRIBUTE_REPARSE_POINT 0x00000400
+#endif
+#ifndef IO_REPARSE_TAG_MOUNT_POINT
+# define IO_REPARSE_TAG_MOUNT_POINT 0xA0000003
+#endif
+#ifndef IO_REPARSE_TAG_SYMLINK
+# define IO_REPARSE_TAG_SYMLINK 0xA000000C
+#endif
+
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+ /* Support for __try / __except. All versions of MSVC and Borland C are
+ * expected to have this. Any other compilers that support it? */
+# define HAVE_TRY_EXCEPT 1
+# include <malloc.h> /* for _resetstkoflw() */
+# if defined(_MSC_VER) && (_MSC_VER >= 1300)
+# define RESETSTKOFLW _resetstkoflw
+# else
+# define RESETSTKOFLW myresetstkoflw
+# define MYRESETSTKOFLW
+# endif
+#endif
+
+/*
+ * Some simple debugging macros that look and behave a lot like their
+ * namesakes in MFC.
+ */
+
+#ifdef _DEBUG
+
+# if defined(_MSC_VER) && (_MSC_VER >= 1000)
+ /* Use the new debugging tools in Visual C++ 4.x */
+# include <crtdbg.h>
+# define ASSERT(f) _ASSERT(f)
+# else
+# include <assert.h>
+# define ASSERT(f) assert(f)
+# endif
+
+# define TRACE Trace
+# define TRACE0(sz) Trace(_T("%s"), _T(sz))
+# define TRACE1(sz, p1) Trace(_T(sz), p1)
+# define TRACE2(sz, p1, p2) Trace(_T(sz), p1, p2)
+# define TRACE3(sz, p1, p2, p3) Trace(_T(sz), p1, p2, p3)
+# define TRACE4(sz, p1, p2, p3, p4) Trace(_T(sz), p1, p2, p3, p4)
+
+/* In debug version, writes trace messages to debug stream */
+void __cdecl
+Trace(char *pszFormat, ...);
+
+#else /* !_DEBUG */
+
+ /* These macros should all compile away to nothing */
+# define ASSERT(f) ((void)0)
+# define TRACE 1 ? (void)0 : printf
+# define TRACE0(sz)
+# define TRACE1(sz, p1)
+# define TRACE2(sz, p1, p2)
+# define TRACE3(sz, p1, p2, p3)
+# define TRACE4(sz, p1, p2, p3, p4)
+
+#endif /* !_DEBUG */
+
+
+#define ASSERT_POINTER(p, type) \
+ ASSERT(((p) != NULL) && IsValidAddress((p), sizeof(type), FALSE))
+
+#define ASSERT_NULL_OR_POINTER(p, type) \
+ ASSERT(((p) == NULL) || IsValidAddress((p), sizeof(type), FALSE))
+
+#ifndef HAVE_SETENV
+# define HAVE_SETENV
+#endif
+#define mch_getenv(x) (char_u *)getenv((char *)(x))
+#ifdef __BORLANDC__
+# define vim_mkdir(x, y) mkdir(x)
+#else
+# define vim_mkdir(x, y) mch_mkdir(x)
+#endif
+
+/* Enable common dialogs input unicode from IME if possible. */
+#define pDispatchMessage DispatchMessageW
+#define pGetMessage GetMessageW
+#define pIsDialogMessage IsDialogMessageW
+#define pPeekMessage PeekMessageW
diff --git a/src/osdef.sh b/src/osdef.sh
new file mode 100755
index 0000000..59ef55d
--- /dev/null
+++ b/src/osdef.sh
@@ -0,0 +1,95 @@
+#! /bin/sh
+#
+# osdef.sh -- copy osdef.h.in to osdef.h while removing declarations
+# found in the system header files. Caution: weird sed magic going on here.
+# Warnings are printed if sed did not survive.
+#
+# (C) Michael Schroeder, Juergen Weigert
+#
+# osdef.h.in has been split into osdef1.h.in and osdef2.h.in, because some
+# sed's could not handle the amount of commands (is 50 commands the limit?).
+#
+# 31.10.95 jw.
+
+if test -z "$CC"; then
+ CC=cc
+fi
+if test -z "$srcdir"; then
+ srcdir=.
+fi
+
+rm -f core* *.core
+
+cat << EOF > osdef0.c
+#ifndef __APPLE__
+# define select select_declared_wrong
+#endif
+#define tgetstr tgetstr_declared_wrong
+#include "auto/config.h"
+#include "os_unix.h" /* bring in most header files, more follow below */
+#include "os_unixx.h" /* bring in header files for os_unix.c */
+
+#ifdef HAVE_TERMCAP_H
+# include <termcap.h> /* only for term.c */
+#endif
+
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h> /* only used in a few files */
+#endif
+
+#ifdef HAVE_SYS_STATFS_H
+# include <sys/types.h>
+# include <sys/statfs.h> /* only for memfile.c */
+#endif
+
+#ifdef HAVE_X11
+# include <X11/Intrinsic.h>
+#endif
+EOF
+
+$CC -I. -I$srcdir -E osdef0.c >osdef0.cc
+
+# insert a space in front of each line, so that a function name at the
+# start of the line is matched with "[)*, ]\1[ (]"
+sed < osdef0.cc -e '/\(..*\)/s// \1/' > osdef0.ccc
+
+sed < $srcdir/osdef1.h.in -n -e '/^extern/s@.*[)* ][)* ]*\([a-zA-Z_][a-zA-Z0-9_]*\)(.*@/[)*, ][(]*\1[)]*[ (]/i\\\
+\\/\\[^a-zA-Z_\\]\1(\\/d@p' > osdef11.sed
+
+sed < $srcdir/osdef2.h.in -n -e '/^extern/s@.*[)* ][)* ]*\([a-zA-Z_][a-zA-Z0-9_]*\)(.*@/[)*, ][(]*\1[)]*[ (]/i\\\
+\\/\\[^a-zA-Z_\\]\1(\\/d@p' > osdef21.sed
+
+cat << EOF > osdef2.sed
+1i\\
+/*
+1i\\
+ * osdef.h is automagically created from osdef?.h.in by osdef.sh -- DO NOT EDIT
+1i\\
+ */
+EOF
+
+cat osdef0.ccc | sed -n -f osdef11.sed >> osdef2.sed
+sed -f osdef2.sed < $srcdir/osdef1.h.in > auto/osdef.h
+
+cat osdef0.ccc | sed -n -f osdef21.sed > osdef2.sed
+sed -f osdef2.sed < $srcdir/osdef2.h.in >> auto/osdef.h
+
+rm osdef0.c osdef0.cc osdef0.ccc osdef11.sed osdef21.sed osdef2.sed
+
+if test -f core*; then
+ file core*
+ echo " Sorry, your sed is broken. Call the system administrator."
+ echo " Meanwhile, you may try to compile Vim with an empty osdef.h file."
+ echo " If you compiler complains about missing prototypes, move the needed"
+ echo " ones from osdef1.h.in and osdef2.h.in to osdef.h."
+ exit 1
+fi
+cat $srcdir/osdef1.h.in $srcdir/osdef2.h.in >osdefX.h.in
+if eval test "`diff auto/osdef.h osdefX.h.in | wc -l`" -eq 4; then
+ echo " Hmm, sed is very pessimistic about your system header files."
+ echo " But it did not dump core -- strange! Let's continue carefully..."
+ echo " If this fails, you may want to remove offending lines from osdef.h"
+ echo " or try with an empty osdef.h file, if your compiler can do without"
+ echo " function declarations."
+fi
+rm osdefX.h.in
diff --git a/src/osdef1.h.in b/src/osdef1.h.in
new file mode 100644
index 0000000..825fe94
--- /dev/null
+++ b/src/osdef1.h.in
@@ -0,0 +1,138 @@
+/* autoconf cannot fiddle out declarations. Use our homebrewn tools. (jw) */
+/*
+ * Declarations that may cause conflicts belong here so that osdef.sh
+ * can clean out the forest. Everything else belongs in os_unix.h
+ *
+ * How this works:
+ * - This file contains all unix prototypes that Vim might need.
+ * - The shell script osdef.sh is executed at compile time to remove all the
+ * prototypes that are in an include file. This results in osdef.h.
+ * - osdef.h is included in vim.h.
+ *
+ * sed cannot always handle so many commands, this is file 1 of 2
+ */
+
+extern int printf(char *, ...);
+extern int fprintf(FILE *, char *, ...);
+extern int sprintf(char *, char *, ...);
+extern int sscanf(char *, char *, ...);
+#ifndef fopen /* could be redefined to fopen64() */
+extern FILE *fopen(const char *, const char *);
+#endif
+extern int fclose(FILE *);
+extern int fseek(FILE *, long, int);
+#ifdef HAVE_FSEEKO
+extern int fseeko(FILE *, off_t, int);
+#endif
+extern long ftell(FILE *);
+#ifdef HAVE_FSEEKO
+extern off_t ftello(FILE *);
+#endif
+extern void rewind(FILE *);
+extern int fread(char *, int, int, FILE *);
+extern int fwrite(char *, int, int, FILE *);
+extern int fputs(char *, FILE *);
+#ifndef ferror /* let me say it again: "macros should never have prototypes" */
+extern int ferror(FILE *);
+#endif
+extern int fflush(FILE *);
+#if defined(sun) || defined(_SEQUENT_)
+/* used inside of stdio macros getc(), puts(), putchar()... */
+extern int _flsbuf(int, FILE *);
+extern int _filbuf(FILE *);
+#endif
+
+#if !defined(HAVE_SELECT)
+struct pollfd; /* for poll() */
+extern int poll(struct pollfd *, long, int);
+#endif
+
+#ifdef HAVE_MEMSET
+extern void *memset(void *, int, size_t);
+#endif
+extern int memcmp(const void *, const void *, size_t);
+#ifdef HAVE_STRPBRK
+extern char *strpbrk(const char *, const char *);
+#endif
+#ifdef USEBCOPY
+extern void bcopy(char *, char *, int);
+#else
+# ifdef USEMEMCPY
+extern void memcpy(char *, char *, int);
+# else
+# ifdef USEMEMMOVE
+extern void memmove(char *, char *, int);
+# endif
+# endif
+#endif
+#ifndef __BIONIC__ // Android's libc #defines bzero to memset.
+// used inside of FD_ZERO macro
+extern void bzero(void *, size_t);
+#endif
+#ifdef HAVE_SETSID
+extern pid_t setsid(void);
+#endif
+#ifdef HAVE_SETPGID
+extern int setpgid(pid_t, pid_t);
+#endif
+#ifdef HAVE_STRTOL
+extern int strtol(char *, char **, int);
+#endif
+#ifdef HAVE_STRFTIME
+extern size_t strftime(char *, size_t, char *, struct tm *);
+#endif
+#ifdef HAVE_STRCASECMP
+extern int strcasecmp(char *, char *);
+#endif
+#ifdef HAVE_STRNCASECMP
+extern int strncasecmp(char *, char *, size_t);
+#endif
+#ifndef strdup
+extern char *strdup(const char *);
+#endif
+extern int atoi(char *);
+extern int atol(char *);
+
+#ifndef USE_SYSTEM
+extern int fork(void);
+# ifndef __TANDEM
+extern int execvp(const char *, const char **);
+# endif
+extern int wait(int *); /* will this break things ...? */
+extern int waitpid(pid_t, int *, int);
+#endif
+
+extern int toupper(int);
+extern int tolower(int);
+
+extern RETSIGTYPE (*signal(int, RETSIGTYPE (*func) SIGPROTOARG)) SIGPROTOARG;
+#ifdef HAVE_SIGSET
+extern RETSIGTYPE (*sigset(int, RETSIGTYPE (*func) SIGPROTOARG)) SIGPROTOARG;
+#endif
+
+#if defined(HAVE_SETJMP_H)
+# ifdef HAVE_SIGSETJMP
+extern int sigsetjmp(sigjmp_buf, int);
+extern void siglongjmp(sigjmp_buf, int);
+# else
+extern int setjmp(jmp_buf);
+extern void longjmp(jmp_buf, int);
+# endif
+#endif
+
+extern int kill(int, int);
+
+#ifndef __TANDEM
+extern int access(char *, int);
+#endif
+extern int fsync(int);
+extern int fchown(int, int, int);
+#if defined(HAVE_GETCWD) && !defined(sun) && !defined(__TANDEM)
+extern char *getcwd(char *, int);
+#else
+extern char *getwd(char *);
+#endif
+#ifndef __alpha /* suggested by Campbell */
+extern int ioctl(int, int, ...);
+#endif
+extern int chmod(const char *, mode_t);
diff --git a/src/osdef2.h.in b/src/osdef2.h.in
new file mode 100644
index 0000000..f29451d
--- /dev/null
+++ b/src/osdef2.h.in
@@ -0,0 +1,100 @@
+/*
+ * osdef2.h.in - See osdef1.h.in for a description.
+ */
+
+extern int remove(const char *);
+extern int rename(const char *, const char *);
+extern int free(char *);
+extern char *malloc(unsigned int);
+extern char *realloc(char *, int);
+extern char *getenv(char *);
+#ifndef __TANDEM
+extern int setenv(char *, char *, int);
+#else
+extern int setenv(const char *, const char *, int);
+#endif
+extern int putenv(const char *);
+
+#ifndef __TANDEM
+extern int gethostname(char *, int);
+#endif
+extern void perror(char *);
+
+#ifndef __TANDEM
+extern int sleep(int);
+#endif
+extern int usleep(unsigned int);
+extern unsigned int alarm(unsigned int);
+#ifndef __TANDEM
+extern int chdir(char *);
+#endif
+extern int fchdir(int);
+#ifndef stat /* could be redefined to stat64() */
+extern int stat(const char *, struct stat *);
+#endif
+#ifndef lstat /* could be redefined to lstat64() */
+extern int lstat(const char *, struct stat *);
+#endif
+extern int fstat(int, struct stat *);
+extern int open(const char *, int, ...);
+extern int close(int);
+#ifndef __TANDEM
+extern int read(int, char *, size_t);
+extern int write(int, char *, size_t);
+#endif
+extern int pipe(int *);
+extern off_t lseek(int, off_t, int);
+extern void sync(void);
+extern uid_t getuid(void);
+extern gid_t getgid(void);
+extern void qsort(void *, size_t, size_t, int (*)(const void *, const void *));
+
+extern int isatty(int);
+extern int getpid(void);
+extern int dup(int);
+extern int unlink(const char *);
+extern int link(const char *, const char *);
+extern int mkdir(const char *, mode_t);
+extern int rmdir(const char *);
+
+extern int tgetent(char *, char *);
+extern int tgetnum(char *);
+extern int tgetflag(char *);
+extern char *tgoto(char *, int, int);
+extern int tputs(char *, int, int (*)(int));
+
+#ifdef HAVE_TERMIOS_H
+struct termios; /* for tcgetattr() */
+extern int tcgetattr(int, struct termios *);
+extern int tcsetattr(int, int, const struct termios *);
+#endif
+
+#ifdef HAVE_SYS_STATFS_H
+struct statfs; /* for fstatfs() */
+extern int fstatfs(int, struct statfs *, int, int);
+#endif
+
+#ifdef HAVE_GETTIMEOFDAY
+struct timeval; /* for gettimeofday() */
+struct timezone; /* for gettimeofday() */
+extern int gettimeofday(struct timeval *tp, struct timezone *tzp);
+extern time_t time(time_t *);
+#endif
+
+#ifdef HAVE_GETPWNAM
+struct passwd; /* for getpwnam() */
+extern struct passwd *getpwnam(const char *);
+#endif
+
+#ifdef USE_TMPNAM
+extern char *tmpnam(char *);
+#else
+extern char *mktemp(char *);
+#endif
+
+#ifdef ISC
+extern int _Xmblen(char const *, size_t);
+#else
+ /* This is different from the header but matches mblen() */
+extern int _Xmblen(char *, size_t);
+#endif
diff --git a/src/pathdef.sh b/src/pathdef.sh
new file mode 100755
index 0000000..b2a83a0
--- /dev/null
+++ b/src/pathdef.sh
@@ -0,0 +1,11 @@
+#! /bin/sh
+#
+# pathdef.sh: adjust pathdef.c for auto/link.sed, if it exists
+#
+if test -s auto/link.sed; then
+ cp auto/pathdef.c auto/pathdef.tmp
+ sed -f auto/link.sed <auto/pathdef.tmp >auto/pathdef.c
+ rm -f auto/pathdef.tmp
+fi
+
+# vim:set sw=2 et:
diff --git a/src/po/Make_all.mak b/src/po/Make_all.mak
new file mode 100644
index 0000000..e16b9ac
--- /dev/null
+++ b/src/po/Make_all.mak
@@ -0,0 +1,135 @@
+#
+# Common po Makefile, defines the list of languages.
+#
+
+LANGUAGES = \
+ af \
+ ca \
+ cs \
+ cs.cp1250 \
+ da \
+ de \
+ en_GB \
+ eo \
+ es \
+ fi \
+ fr \
+ ga \
+ it \
+ ja \
+ ja.euc-jp \
+ ja.sjis \
+ ko \
+ ko.UTF-8 \
+ lv \
+ nb \
+ nl \
+ no \
+ pl \
+ pl.UTF-8 \
+ pl.cp1250 \
+ pt_BR \
+ ru \
+ ru.cp1251 \
+ sk \
+ sk.cp1250 \
+ sr \
+ sv \
+ uk \
+ uk.cp1251 \
+ vi \
+ zh_CN \
+ zh_CN.UTF-8 \
+ zh_CN.cp936 \
+ zh_TW \
+ zh_TW.UTF-8 \
+
+
+MOFILES = \
+ af.mo \
+ ca.mo \
+ cs.mo \
+ da.mo \
+ de.mo \
+ en_GB.mo \
+ eo.mo \
+ es.mo \
+ fi.mo \
+ fr.mo \
+ ga.mo \
+ it.mo \
+ ja.mo \
+ ko.UTF-8.mo \
+ ko.mo \
+ lv.mo \
+ nb.mo \
+ nl.mo \
+ no.mo \
+ pl.mo \
+ pt_BR.mo \
+ ru.mo \
+ sk.mo \
+ sr.mo \
+ sv.mo \
+ uk.mo \
+ vi.mo \
+ zh_CN.UTF-8.mo \
+ zh_CN.mo \
+ zh_TW.UTF-8.mo \
+ zh_TW.mo \
+
+
+MOCONVERTED = \
+ cs.cp1250.mo \
+ ja.euc-jp.mo \
+ ja.sjis.mo \
+ pl.UTF-8.mo \
+ pl.cp1250.mo \
+ ru.cp1251.mo \
+ sk.cp1250.mo \
+ uk.cp1251.mo \
+ zh_CN.cp936.mo \
+
+
+CHECKFILES = \
+ af.ck \
+ ca.ck \
+ cs.ck \
+ cs.cp1250.ck \
+ da.ck \
+ de.ck \
+ en_GB.ck \
+ eo.ck \
+ es.ck \
+ fi.ck \
+ fr.ck \
+ ga.ck \
+ it.ck \
+ ja.ck \
+ ja.euc-jp.ck \
+ ja.sjis.ck \
+ ko.UTF-8.ck \
+ ko.ck \
+ lv.ck \
+ nb.ck \
+ nl.ck \
+ no.ck \
+ pl.UTF-8.ck \
+ pl.ck \
+ pl.cp1250.ck \
+ pt_BR.ck \
+ ru.ck \
+ ru.cp1251.ck \
+ sk.ck \
+ sk.cp1250.ck \
+ sr.ck \
+ sv.ck \
+ uk.ck \
+ uk.cp1251.ck \
+ vi.ck \
+ zh_CN.UTF-8.ck \
+ zh_CN.ck \
+ zh_CN.cp936.ck \
+ zh_TW.UTF-8.ck \
+ zh_TW.ck \
+
diff --git a/src/po/Make_cyg.mak b/src/po/Make_cyg.mak
new file mode 100644
index 0000000..3f85301
--- /dev/null
+++ b/src/po/Make_cyg.mak
@@ -0,0 +1,79 @@
+# Makefile for the Vim message translations for Cygwin
+# by Tony Mechelynck <antoine.mechelynck@skynet.be>
+# after Make_ming.mak by
+# Eduardo F. Amatria <eferna1@platea.pntic.mec.es>
+#
+# Read the README_ming.txt file before using it.
+#
+# Use at your own risk but with care, it could even kill your canary.
+#
+
+ifndef VIMRUNTIME
+VIMRUNTIME = ../../runtime
+endif
+
+# get LANGUAGES, MOFILES and MOCONVERTED
+include Make_all.mak
+
+PACKAGE = vim
+
+# Uncomment one of the lines below or modify it to put the path to your
+# gettext binaries
+ifndef GETTEXT_PATH
+#GETTEXT_PATH = C:/gettext.win32/bin/
+#GETTEXT_PATH = C:/gettext-0.10.35-w32/win32/Release/
+GETTEXT_PATH = /bin/
+endif
+
+# The OLD_PO_FILE_INPUT and OLD_PO_FILE_OUTPUT are for the new GNU gettext
+# tools 0.10.37, which use a slightly different .po file format that is not
+# compatible with Solaris (and old gettext implementations) unless these are
+# set. gettext 0.10.36 will not work!
+MSGFMT = OLD_PO_FILE_INPUT=yes $(GETTEXT_PATH)msgfmt -v
+XGETTEXT = OLD_PO_FILE_INPUT=yes OLD_PO_FILE_OUTPUT=yes $(GETTEXT_PATH)xgettext
+MSGMERGE = OLD_PO_FILE_INPUT=yes OLD_PO_FILE_OUTPUT=yes $(GETTEXT_PATH)msgmerge
+
+# MV = move
+# CP = copy
+# RM = del
+# MKD = mkdir
+MV = mv -f
+CP = cp -f
+RM = rm -f
+MKD = mkdir -p
+
+.SUFFIXES:
+.SUFFIXES: .po .mo .pot
+.PHONY: first_time all install clean $(LANGUAGES)
+
+.po.mo:
+ $(MSGFMT) -o $@ $<
+
+all: $(MOFILES) $(MOCONVERTED)
+
+first_time:
+ $(XGETTEXT) --default-domain=$(LANGUAGE) \
+ --add-comments --keyword=_ --keyword=N_ --keyword=NGETTEXT:1,2 $(wildcard ../*.c) ../if_perl.xs ../GvimExt/gvimext.cpp $(wildcard ../globals.h) ../if_py_both.h ../vim.h
+
+$(LANGUAGES):
+ $(XGETTEXT) --default-domain=$(PACKAGE) \
+ --add-comments --keyword=_ --keyword=N_ --keyword=NGETTEXT:1,2 $(wildcard ../*.c) ../if_perl.xs ../GvimExt/gvimext.cpp $(wildcard ../globals.h) ../if_py_both.h ../vim.h
+ $(MV) $(PACKAGE).po $(PACKAGE).pot
+ $(CP) $@.po $@.po.orig
+ $(MV) $@.po $@.po.old
+ $(MSGMERGE) $@.po.old $(PACKAGE).pot -o $@.po
+ $(RM) $@.po.old
+
+install: $(MOFILES) $(MOCONVERTED)
+ for TARGET in $(LANGUAGES); do \
+ $(MKD) $(VIMRUNTIME)/lang/$$TARGET/LC_MESSAGES ; \
+ $(CP) $$TARGET.mo $(VIMRUNTIME)/lang/$$TARGET/LC_MESSAGES/$(PACKAGE).mo ; \
+ done
+
+install-all: install
+
+clean:
+ $(RM) *.mo
+ $(RM) *.pot
+
+
diff --git a/src/po/Make_ming.mak b/src/po/Make_ming.mak
new file mode 100644
index 0000000..aa19306
--- /dev/null
+++ b/src/po/Make_ming.mak
@@ -0,0 +1,98 @@
+# Makefile for the Vim message translations for mingw32
+#
+# Eduardo F. Amatria <eferna1@platea.pntic.mec.es>
+#
+# Read the README_ming.txt file before using it.
+#
+# Use at your own risk but with care, it could even kill your canary.
+#
+# Previous to all you must have the environment variable LANGUAGE set to your
+# language (xx) and add it to the next three lines.
+#
+
+ifndef VIMRUNTIME
+ifeq (sh.exe, $(SHELL))
+VIMRUNTIME = ..\..\runtime
+else
+VIMRUNTIME = ../../runtime
+endif
+endif
+
+# get LANGUAGES, MOFILES and MOCONVERTED
+include Make_all.mak
+
+PACKAGE = vim
+
+# Uncomment one of the lines below or modify it to put the path to your
+# gettex binaries; I use the first
+#GETTEXT_PATH = C:/gettext.win32/bin/
+#GETTEXT_PATH = C:/gettext-0.10.35-w32/win32/Release/
+#GETTEXT_PATH = C:/cygwin/bin/
+
+ifeq (sh.exe, $(SHELL))
+MSGFMT = set OLD_PO_FILE_INPUT=yes && $(GETTEXT_PATH)msgfmt -v
+XGETTEXT = set OLD_PO_FILE_INPUT=yes && set OLD_PO_FILE_OUTPUT=yes && $(GETTEXT_PATH)xgettext
+MSGMERGE = set OLD_PO_FILE_INPUT=yes && set OLD_PO_FILE_OUTPUT=yes && $(GETTEXT_PATH)msgmerge
+else
+MSGFMT = LANG=C OLD_PO_FILE_INPUT=yes $(GETTEXT_PATH)msgfmt -v
+XGETTEXT = LANG=C OLD_PO_FILE_INPUT=yes OLD_PO_FILE_OUTPUT=yes $(GETTEXT_PATH)xgettext
+MSGMERGE = LANG=C OLD_PO_FILE_INPUT=yes OLD_PO_FILE_OUTPUT=yes $(GETTEXT_PATH)msgmerge
+endif
+
+ifeq (sh.exe, $(SHELL))
+MV = move
+CP = copy
+RM = del
+MKD = mkdir
+else
+MV = mv -f
+CP = cp -f
+RM = rm -f
+MKD = mkdir -p
+endif
+
+.SUFFIXES:
+.SUFFIXES: .po .mo .pot
+.PHONY: first_time all install clean $(LANGUAGES)
+
+.po.mo:
+ $(MSGFMT) -o $@ $<
+
+all: $(MOFILES) $(MOCONVERTED)
+
+first_time:
+ $(XGETTEXT) --default-domain=$(LANGUAGE) \
+ --add-comments --keyword=_ --keyword=N_ --keyword=NGETTEXT:1,2 $(wildcard ../*.c) ../if_perl.xs ../GvimExt/gvimext.cpp $(wildcard ../globals.h) ../if_py_both.h ../vim.h
+
+$(LANGUAGES):
+ $(XGETTEXT) --default-domain=$(PACKAGE) \
+ --add-comments --keyword=_ --keyword=N_ --keyword=NGETTEXT:1,2 $(wildcard ../*.c) ../if_perl.xs ../GvimExt/gvimext.cpp $(wildcard ../globals.h) ../if_py_both.h ../vim.h
+ $(MV) $(PACKAGE).po $(PACKAGE).pot
+ $(CP) $@.po $@.po.orig
+ $(MV) $@.po $@.po.old
+ $(MSGMERGE) $@.po.old $(PACKAGE).pot -o $@.po
+ $(RM) $@.po.old
+
+install:
+ $(MKD) $(VIMRUNTIME)\lang\$(LANGUAGE)
+ $(MKD) $(VIMRUNTIME)\lang\$(LANGUAGE)\LC_MESSAGES
+ $(CP) $(LANGUAGE).mo $(VIMRUNTIME)\lang\$(LANGUAGE)\LC_MESSAGES\$(PACKAGE).mo
+
+ifeq (sh.exe, $(SHELL))
+install-all: all
+ FOR %%l IN ($(LANGUAGES)) DO @IF NOT EXIST $(VIMRUNTIME)\lang\%%l $(MKD) $(VIMRUNTIME)\lang\%%l
+ FOR %%l IN ($(LANGUAGES)) DO @IF NOT EXIST $(VIMRUNTIME)\lang\%%l\LC_MESSAGES $(MKD) $(VIMRUNTIME)\lang\%%l\LC_MESSAGES
+ FOR %%l IN ($(LANGUAGES)) DO @$(CP) %%l.mo $(VIMRUNTIME)\lang\%%l\LC_MESSAGES\$(PACKAGE).mo
+else
+install-all: all
+ for TARGET in $(LANGUAGES); do \
+ $(MKD) $(VIMRUNTIME)/lang/$$TARGET/LC_MESSAGES ; \
+ $(CP) $$TARGET.mo $(VIMRUNTIME)/lang/$$TARGET/LC_MESSAGES/$(PACKAGE).mo ; \
+ done
+endif
+
+clean:
+ $(RM) *.mo
+ $(RM) *.pot
+
+
diff --git a/src/po/Make_mvc.mak b/src/po/Make_mvc.mak
new file mode 100644
index 0000000..43c805f
--- /dev/null
+++ b/src/po/Make_mvc.mak
@@ -0,0 +1,72 @@
+# Makefile for the Vim message translations for MSVC
+# (based on make_ming.mak)
+#
+# Mike Williams <mrw@eandem.co.uk>
+#
+# Please read README_mvc.txt before using this file.
+#
+
+!ifndef VIMRUNTIME
+VIMRUNTIME = ..\..\runtime
+!endif
+
+# get LANGUAGES, MOFILES and MOCONVERTED
+!include Make_all.mak
+
+PACKAGE = vim
+
+# Correct the following line for the directory where gettext et al is installed
+GETTEXT_PATH = H:\gettext.0.14.4\bin
+
+MSGFMT = $(GETTEXT_PATH)\msgfmt -v
+XGETTEXT = $(GETTEXT_PATH)\xgettext
+MSGMERGE = $(GETTEXT_PATH)\msgmerge
+
+MV = move
+CP = copy
+RM = del
+MKD = mkdir
+LS = dir
+
+LSFLAGS = /b /on /l /s
+
+INSTALLDIR = $(VIMRUNTIME)\lang\$(LANGUAGE)\LC_MESSAGES
+
+.SUFFIXES:
+.SUFFIXES: .po .mo .pot
+
+.po.mo:
+ set OLD_PO_FILE_INPUT=yes
+ $(MSGFMT) -o $@ $<
+
+all: $(MOFILES) $(MOCONVERTED)
+
+files:
+ $(LS) $(LSFLAGS) ..\*.c ..\if_perl.xs ..\GvimExt\gvimext.cpp ..\globals.h ..\if_py_both.h ..\vim.h > .\files
+
+first_time: files
+ set OLD_PO_FILE_INPUT=yes
+ set OLD_PO_FILE_OUTPUT=yes
+ $(XGETTEXT) --default-domain=$(LANGUAGE) --add-comments --keyword=_ --keyword=N_ --keyword=NGETTEXT:1,2 --files-from=.\files
+
+$(LANGUAGES): files
+ set OLD_PO_FILE_INPUT=yes
+ set OLD_PO_FILE_OUTPUT=yes
+ $(XGETTEXT) --default-domain=$(PACKAGE) --add-comments --keyword=_ --keyword=N_ --keyword=NGETTEXT:1,2 --files-from=.\files
+ $(MV) $(PACKAGE).po $(PACKAGE).pot
+ $(CP) $@.po $@.po.orig
+ $(MV) $@.po $@.po.old
+ $(MSGMERGE) $@.po.old $(PACKAGE).pot -o $@.po
+ $(RM) $@.po.old
+
+install:
+ if not exist $(INSTALLDIR) $(MKD) $(INSTALLDIR)
+ $(CP) $(LANGUAGE).mo $(INSTALLDIR)\$(PACKAGE).mo
+
+install-all: all
+ FOR %%l IN ($(LANGUAGES)) DO @IF NOT EXIST $(VIMRUNTIME)\lang\%%l\LC_MESSAGES $(MKD) $(VIMRUNTIME)\lang\%%l\LC_MESSAGES
+ FOR %%l IN ($(LANGUAGES)) DO @$(CP) %%l.mo $(VIMRUNTIME)\lang\%%l\LC_MESSAGES\$(PACKAGE).mo
+
+clean:
+ $(RM) *.mo
+ $(RM) *.pot
diff --git a/src/po/Makefile b/src/po/Makefile
new file mode 100644
index 0000000..c6758e2
--- /dev/null
+++ b/src/po/Makefile
@@ -0,0 +1,177 @@
+# Makefile for the Vim message translations.
+
+# Include stuff found by configure.
+include ../auto/config.mk
+
+# get LANGUAGES, MOFILES, MOCONVERTED and CHECKFILES
+include Make_all.mak
+
+# Note: ja.sjis, *.cp1250 and zh_CN.cp936 are only for MS-Windows, they are
+# not installed on Unix
+
+PACKAGE = vim
+SHELL = /bin/sh
+VIM = ../vim
+
+# The OLD_PO_FILE_INPUT and OLD_PO_FILE_OUTPUT are for the new GNU gettext
+# tools 0.10.37, which use a slightly different .po file format that is not
+# compatible with Solaris (and old gettext implementations) unless these are
+# set. gettext 0.10.36 will not work!
+MSGFMTCMD = OLD_PO_FILE_INPUT=yes $(MSGFMT) -v
+XGETTEXT = OLD_PO_FILE_INPUT=yes OLD_PO_FILE_OUTPUT=yes xgettext
+MSGMERGE = OLD_PO_FILE_INPUT=yes OLD_PO_FILE_OUTPUT=yes msgmerge
+
+.SUFFIXES:
+.SUFFIXES: .po .mo .pot .ck
+.PHONY: all install uninstall prefixcheck converted check clean checkclean distclean update-po $(LANGUAGES)
+
+.po.mo:
+ $(MSGFMTCMD) -o $@ $<
+
+.po.ck:
+ $(VIM) -u NONE -e -X -S check.vim -c "if error == 0 | q | endif" -c cq $<
+ touch $@
+
+all: $(MOFILES) $(MOCONVERTED)
+
+check: $(CHECKFILES)
+
+install: $(MOFILES) $(MOCONVERTED)
+ @$(MAKE) prefixcheck
+ for lang in $(LANGUAGES); do \
+ dir=$(LOCALEDIR)/$$lang/; \
+ if test ! -x "$$dir"; then \
+ mkdir $$dir; chmod 755 $$dir; \
+ fi; \
+ dir=$(LOCALEDIR)/$$lang/LC_MESSAGES; \
+ if test ! -x "$$dir"; then \
+ mkdir $$dir; chmod 755 $$dir; \
+ fi; \
+ if test -r $$lang.mo; then \
+ $(INSTALL_DATA) $$lang.mo $$dir/$(PACKAGE).mo; \
+ chmod $(FILEMOD) $$dir/$(PACKAGE).mo; \
+ fi; \
+ done
+
+uninstall:
+ @$(MAKE) prefixcheck
+ for cat in $(MOFILES) $(MOCONVERTED); do \
+ cat=`basename $$cat`; \
+ lang=`echo $$cat | sed 's/\$(CATOBJEXT)$$//'`; \
+ rm -f $(LOCALEDIR)/$$lang/LC_MESSAGES/$(PACKAGE).mo; \
+ done
+
+converted: $(MOCONVERTED)
+
+# nl.po was added later, if it does not exist use a file with just a # in it
+# (an empty file doesn't work with old msgfmt).
+nl.po:
+ @( echo \# > nl.po )
+
+# Norwegian/Bokmal: "nb" is an alias for "no".
+# Copying the file is not efficient, but I don't know of another way to make
+# this work.
+nb.po: no.po
+ cp no.po nb.po
+
+# Convert ja.po to create ja.sjis.po. Requires doubling backslashes in the
+# second byte. Don't depend on sjiscorr, it should only be compiled when
+# ja.sjis.po is outdated.
+ja.sjis.po: ja.po
+ @$(MAKE) sjiscorr
+ rm -f ja.sjis.po
+ iconv -f utf-8 -t cp932 ja.po | ./sjiscorr > ja.sjis.po
+
+sjiscorr: sjiscorr.c
+ $(CC) -o sjiscorr sjiscorr.c
+
+ja.euc-jp.po: ja.po
+ iconv -f utf-8 -t euc-jp ja.po | \
+ sed -e 's/charset=[uU][tT][fF]-8/charset=euc-jp/' -e 's/# Original translations/# Generated from ja.po, DO NOT EDIT/' > ja.euc-jp.po
+
+# Convert cs.po to create cs.cp1250.po.
+cs.cp1250.po: cs.po
+ rm -f cs.cp1250.po
+ iconv -f iso-8859-2 -t cp1250 cs.po | \
+ sed -e 's/charset=ISO-8859-2/charset=cp1250/' -e 's/# Original translations/# Generated from cs.po, DO NOT EDIT/' > cs.cp1250.po
+
+# Convert pl.po to create pl.cp1250.po.
+pl.cp1250.po: pl.po
+ rm -f pl.cp1250.po
+ iconv -f iso-8859-2 -t cp1250 pl.po | \
+ sed -e 's/charset=ISO-8859-2/charset=cp1250/' -e 's/# Original translations/# Generated from pl.po, DO NOT EDIT/' > pl.cp1250.po
+
+# Convert pl.po to create pl.UTF-8.po.
+pl.UTF-8.po: pl.po
+ rm -f pl.UTF-8.po
+ iconv -f iso-8859-2 -t utf-8 pl.po | \
+ sed -e 's/charset=ISO-8859-2/charset=UTF-8/' -e 's/# Original translations/# Generated from pl.po, DO NOT EDIT/' > pl.UTF-8.po
+
+# Convert sk.po to create sk.cp1250.po.
+sk.cp1250.po: sk.po
+ rm -f sk.cp1250.po
+ iconv -f iso-8859-2 -t cp1250 sk.po | \
+ sed -e 's/charset=ISO-8859-2/charset=cp1250/' -e 's/# Original translations/# Generated from sk.po, DO NOT EDIT/' > sk.cp1250.po
+
+# Convert zh_CN.UTF-8.po to create zh_CN.cp936.po.
+# Set 'charset' to gbk to avoid that msfmt generates a warning.
+# This used to convert from zh_CN.po, but that results in a conversion error.
+zh_CN.cp936.po: zh_CN.UTF-8.po
+ rm -f zh_CN.cp936.po
+ iconv -f UTF-8 -t cp936 zh_CN.UTF-8.po | \
+ sed -e 's/charset=[uU][tT][fF]-8/charset=gbk/' -e 's/# Original translations/# Generated from zh_CN.UTF-8.po, DO NOT EDIT/' > zh_CN.cp936.po
+
+# Convert ko.UTF-8.po to create ko.po.
+ko.po: ko.UTF-8.po
+ rm -f ko.po
+ iconv -f UTF-8 -t euc-kr ko.UTF-8.po | \
+ sed -e 's/charset=UTF-8/charset=euc-kr/' \
+ -e 's/# Korean translation for Vim/# Generated from ko.UTF-8.po, DO NOT EDIT/' \
+ > ko.po
+
+# Convert ru.po to create ru.cp1251.po.
+ru.cp1251.po: ru.po
+ rm -f ru.cp1251.po
+ iconv -f utf-8 -t cp1251 ru.po | \
+ sed -e 's/charset=[uU][tT][fF]-8/charset=cp1251/' -e 's/# Original translations/# Generated from ru.po, DO NOT EDIT/' > ru.cp1251.po
+
+# Convert uk.po to create uk.cp1251.po.
+uk.cp1251.po: uk.po
+ rm -f uk.cp1251.po
+ iconv -f utf-8 -t cp1251 uk.po | \
+ sed -e 's/charset=[uU][tT][fF]-8/charset=cp1251/' -e 's/# Original translations/# Generated from uk.po, DO NOT EDIT/' > uk.cp1251.po
+
+prefixcheck:
+ @if test "x" = "x$(prefix)"; then \
+ echo "******************************************"; \
+ echo " please use make from the src directory "; \
+ echo "******************************************"; \
+ exit 1; \
+ fi
+
+clean: checkclean
+ rm -f core core.* *.old.po *.mo *.pot sjiscorr
+
+distclean: clean
+
+checkclean:
+ rm -f *.ck
+
+$(PACKAGE).pot: ../*.c ../if_perl.xs ../GvimExt/gvimext.cpp ../globals.h ../if_py_both.h ../vim.h
+ cd ..; $(XGETTEXT) --default-domain=$(PACKAGE) \
+ --add-comments --keyword=_ --keyword=N_ --keyword=NGETTEXT:1,2 \
+ *.c if_perl.xs GvimExt/gvimext.cpp globals.h if_py_both.h vim.h
+ mv -f ../$(PACKAGE).po $(PACKAGE).pot
+
+update-po: $(LANGUAGES)
+
+# Don't add a dependency here, we only want to update the .po files manually
+$(LANGUAGES):
+ @$(MAKE) $(PACKAGE).pot
+ if test ! -f $@.po.orig; then cp $@.po $@.po.orig; fi
+ mv $@.po $@.po.old
+ if $(MSGMERGE) $@.po.old $(PACKAGE).pot -o $@.po; then \
+ rm -f $@.po.old; \
+ else \
+ echo "msgmerge for $@.po failed!"; mv $@.po.old $@.po; \
+ fi
diff --git a/src/po/README.txt b/src/po/README.txt
new file mode 100644
index 0000000..d283210
--- /dev/null
+++ b/src/po/README.txt
@@ -0,0 +1,146 @@
+TRANSLATING VIM MESSAGES
+
+In this directory you will find xx.po files, where "xx" is a language code.
+Each file contains the translation of English Vim messages for one language.
+The files are in "po" format, used by the gettext package. Please refer to
+the gettext documentation for more information.
+
+The GNU gettext library, starting with version 0.10.37, supports converting
+messages from one encoding to another. This requires that it was compiled
+with HAVE_ICONV. The result is that the messages may be in any encoding
+supported by iconv and will be automatically converted to the currently used
+encoding.
+
+The GNU gettext library, starting with version 0.10.36, uses a new format for
+some encodings. This follows the C99 standard for strings. It means that
+when a multi-byte character includes the 0x5c byte, this is not recognized as
+a backslash. Since this format is incompatible with Solaris, Vim uses the old
+format. This is done by setting the OLD_PO_FILE_OUTPUT and OLD_PO_FILE_INPUT
+environment variables. When you use the Makefile in this directory that will
+be done for you. This does NOT work with gettext 0.10.36. Don't use it, get
+0.10.37.
+
+
+ON MS-WINDOWS
+
+The distributed files are generated on Unix, but this should also be possible
+on MS-Windows. Download the gettext packages, for example from:
+
+ http://sourceforge.net/projects/gettext
+
+You might have to do the commands manually. Example:
+
+ cd c:\vim\vim71
+ mkdir runtime\lang\ja\LC_MESSAGES
+ msgfmt -o runtime\lang\ja\LC_MESSAGES\vim.mo src\po\ja.po
+
+
+WHEN THERE IS A MISTAKE
+
+If you find there is a mistake in one of the translations, please report this
+to the maintainer of the translation. His/her E-mail address is in the
+comments at the start of the file. You can also see this with the ":messages"
+command in Vim when the translation is being used.
+
+
+CREATING A NEW PO FILE
+
+We will use "xx.po" as an example here, replace "xx" with the name of your
+language.
+
+- Edit Makefile to add xx to LANGUAGES and xx.mo to MOFILES.
+- If you haven't done so already, run ./configure in the top vim directory
+ (i.e. go up two directories) and then come back here afterwards.
+- Execute these commands:
+ % make vim.pot
+ % msginit -l xx
+ % rm vim.pot
+ The first command will generate a vim.pot file which is used by msginit to
+ generate a correct xx.po file. After that vim.pot is not needed.
+- The remaining work is like updating, see the next section.
+
+
+UPDATING A PO FILE
+
+If you are the maintainer of a .po file, this is how you update the file. We
+will use "xx.po" as an example here, replace "xx" with the name of your
+language.
+
+(1) Add new and changed messages from the Vim sources:
+
+ make xx
+
+ This will extract all the strings from Vim and merge them in with the
+ existing translations. Requires the GNU gettext utilities.
+ Your original xx.po file will be copied to xx.po.orig
+
+ -- After you do this, you MUST do the next three steps! --
+
+(2) Translate
+ See the gettext documentation on how to do this. You can also find
+ examples in the other po files.
+ Search the po file for items that require translation:
+
+ /fuzzy\|^msgstr ""\(\n"\)\@!
+
+ Remove the "#, fuzzy" line after adding the translation.
+
+ There is one special message:
+ msgid "Messages maintainer: Bram Moolenaar <Bram@vim.org>"
+ You should include your name and E-mail address instead, for example:
+ msgstr "Berichten übersetzt bei: John Doe <john@doe.org>"
+
+(3) Remove unused messages (optional)
+ Remove messages that have been marked as obsolete.
+ Such messages start with "#~".
+
+ The cleanup script will also do that (see next step).
+
+(4) Clean up
+ This is very important to make sure the translation works on all systems.
+ Comment-out all non-translated strings. There are two types:
+ - items marked with "#, fuzzy"
+ - items with an empty msgstr
+ You can do this with the cleanup.vim script:
+
+ :source cleanup.vim
+
+ Background: on Solaris an empty msgstr results in an empty message; GNU
+ gettext ignores empty strings and items marked with "#, fuzzy".
+
+ This also removes the line numbers from the file, so that patches are not
+ messed up by changes in line numbers and show the actual changes in the
+ text.
+
+(5) Check:
+
+ While editing the .po file:
+ :source check.vim
+
+ From the command line:
+ vim -S check.vim xx.po
+ make xx.mo
+
+ Look out for syntax errors and fix them.
+
+
+USING GETTEXT WITHOUT ICONV
+
+When using gettext which doesn't support iconv, the encoding of the .mo file
+must match your active encoding. For that you must convert and change
+encoding of *.po file in advance of generating the *.mo file. For example, to
+convert ja.po to EUC-JP (supposed as your system encoding):
+
+(1) Convert the file encoding:
+
+ mv ja.po ja.po.orig
+ iconv -f utf-8 -t euc-jp ja.po.orig > ja.po
+
+(2) Rewrite charset declaration in the file:
+
+ Open ja.po find this line:
+ "Content-Type: text/plain; charset=utf-8\n"
+ You should change "charset" like this:
+ "Content-Type: text/plain; charset=euc-jp\n"
+
+There are examples in the Makefile for the conversions already supported.
diff --git a/src/po/README_mingw.txt b/src/po/README_mingw.txt
new file mode 100644
index 0000000..8052082
--- /dev/null
+++ b/src/po/README_mingw.txt
@@ -0,0 +1,105 @@
+TRANSLATING VIM MESSAGES
+
+This file explains how to create and maintain po files using
+gnu-gettext.win32, a MINGW32 Windows port of gettext by Franco Bez
+<franco.bez@gmx.de>. You can find it at:
+
+ http://home.a-city.de/franco.bez/gettext/gettext_win32_en.html
+
+First read the README.txt file for the general remarks
+
+
+The file that does the work is Make_ming.mak in the po directory. It is an
+adaptation of the Unix Makefile, but it does NOT test the presence of any po,
+pot, or mo files, so use it at your own risk but with care: it could even kill
+your canary. It has been tested by me several times (and with different
+languages) with success.
+
+The make utility must be run from the po directory.
+
+First of all you must set the environment variable LANGUAGE to xx, where xx is
+the name of your language. You can do it from the command line or adding a
+line to your autoexec.bat file: set LANGUAGE=xx. You must also add your
+language to the Make_ming.mak file in the lines LANGUAGES, MOFILES, AND
+POFILES.
+
+If you don't have a xx.po file, you must create it with the command:
+
+ make -f Make_ming.mak first_time
+
+This will produce a new brand xx.po file with all the messages in Vim ready
+for translation. Then you must source the cleanup.vim script from inside Vim;
+it will comment the untranslated messages (now, all). I recommend to use
+syntax highlighting so you can identify the untranslated messages easily.
+You also must remove the '..\' that prepends the name of the source files.
+(I don't no why, but make is unable to change the directory from po to src and
+back to po, so all the work must be done from the po dir, hence the '..\')
+
+Then you must go step (2) below.
+
+If you are updating a po file you must follow the next steps (they are nearly
+the same as in the Unix case, only the commands change):
+
+(1) Add new and changed messages from the Vim sources:
+
+ make -f Make_ming.mak xx
+
+ This will extract all the strings from Vim and merge them in with the
+ existing translations. Requires the GNU gettext utilities. Also requires
+ unpacking the extra archive.
+ Your original xx.po file will be copied to xx.po.orig
+
+ -- After you do this, you MUST do the next three steps! --
+
+(2) Translate
+ See the gettext documentation on how to do this. You can also find
+ examples in the other po files.
+ Search the po file for items that require translation:
+ /\#\~ and also the fuzzy translations, /\#, fuzzy
+ Remove "#~" and "#, fuzzy" after adding the translation.
+
+ There is one special message:
+ msgid "Messages maintainer: Bram Moolenaar <Bram@vim.org>"
+ You should include your name and E-mail address instead, for example:
+ msgstr "Berichten übersetzt bei: John Doe <john@doe.org>"
+
+(3) Clean up
+ This is very important to make sure the translation works on all systems.
+ Comment-out all non-translated strings. There are two types:
+ - items marked with "#, fuzzy"
+ - items with an empty msgstr
+ You can do this with the cleanup.vim script:
+
+ :source cleanup.vim
+
+(4) Check:
+
+ vim -S check.vim xx.po
+ make -f Make_ming.mak xx.mo
+
+ Look out for syntax errors and fix them.
+
+(5) This is an extra step, ;-). If you want the vim.mo file installed in your
+ system you must run:
+
+ make -f Make_ming.mak install
+
+ This will create the xx\LC_MESSAGES directory (if it does not exist) and
+ will copy vim.po to it.
+ You can also use the following command to install all languages:
+
+ make -f Make_ming.mak install-all
+
+(6) Another extra step ;-)). The command:
+
+ make -f Make_ming.mak clean
+
+ will delete the temp files created during the process.
+
+Suggestions will be welcomed.
+
+Eduardo F. Amatria <eferna1@platea.pntic.mec.es>
+
+Happy Vimming with NLS!!
+
+vim:tw=78:
diff --git a/src/po/README_mvc.txt b/src/po/README_mvc.txt
new file mode 100644
index 0000000..c63ad1f
--- /dev/null
+++ b/src/po/README_mvc.txt
@@ -0,0 +1,119 @@
+TRANSLATING VIM MESSAGES
+
+This file explains how to create and maintain po files using a number of
+GnuWin packages. You will need gettext, libiconv and libexpat. As of
+August 2010 the versions known to work are gettext 0.14.4, libiconv 1.9.2-1
+and expat 2.0.1. gettext and libiconv can be found at:
+
+ http://gnuwin32.sourceforge.net/
+
+expat can be found at:
+
+ http://sourceforge.net/projects/expat/
+
+expat will install into its own directory. You should copy libexpat.dll into
+the bin directory created from the gettext/libiconv packages.
+
+First read the README.txt file in this directory for general remarks on
+translating Vim messages.
+
+
+SETUP
+
+Set the environment variable LANGUAGE to the language code for the language
+you are translating Vim messages to. Language codes are typically two
+characters and you can find a list of them at:
+
+ http://www.geocities.com/click2speak/languages.html
+
+Another possibility is to use the gnuwin32 port of gettext. This is
+recommended especially if you use already gnuwin32 tools to gunzip, bunzip,
+patch etc. these files. You find the gnuwin32 version of gettext here:
+
+ http://gnuwin32.sourceforge.net/packages/gettext.htm
+
+Yet another very strait forward way is to get the sources of gettext from
+
+ http://www.gnu.org/software/gettext/gettext.html
+
+and build your own version of these tools. The documentation states that this
+should be possible with MSVC4.0, MSVC5.0, MSVC6.0 or MSVC7.0, but you can
+build it even successfully with MSVC8.0.
+
+The LANGUAGE environment variable can be set from the command line, by adding
+a line to your autoexec.bat file, or by defining a user variable from the
+Advanced tab in the System control panel.
+
+Next, edit Make_mvc.mak so that GETTEXT_PATH points the binary directory of
+the installation.
+
+
+CREATING A NEW TRANSLATION
+
+When creating a new translation you must add your language code to the
+Make_mvc.mak file in the lines defining LANGUAGES and MOFILES. To create the
+initial .po file for your language you must use the command:
+
+ make -f make_mvc.mak first_time
+
+Note: You need to be in the po directory when using this makefile.
+
+Once you have your new .po file load it into Vim and source cleanup.vim, this
+will convert untranslated messages to comments. If you have syntax
+highlighting turned on then untranslated messages will stand out more easily.
+
+You will also need to edit the file names in the comments in the .po file.
+You need to remove the absolute directory specification (which has the form
+c:\vim61\src\). You can do this in Vim with the following command with the
+appropriate directory specification for where you have installed the Vim
+source:
+
+ %s/c:\\vim61\\src\\//g
+
+
+UPDATING A TRANSLATION
+
+If there are new or changed messages in Vim that need translating, then the
+first thing to do is merge them into the existing translations. This is done
+with the following command:
+
+ nmake -f Make_mvc.mak xx.po
+
+where xx is the language code for the language needing translations. The
+original .po file is copied to xx.po.orig.
+
+
+DOING THE TRANSLATION
+
+Now that you have a .po file you can do the translations for all messages that
+need it. See README.txt for specific instructions.
+
+Once you have finished translating the messages you should make sure all
+non-translated strings are commented out. This can be done by sourcing
+cleanup.vim once again.
+
+
+CHECKING THE TRANSLATION
+
+Check the translation with the following command:
+
+ nmake -f make_mvc.mak xx.mo
+
+Correct any syntax errors reported. When there are no more errors, the
+translation is ready to be installed.
+
+
+INSTALLING THE TRANSLATION
+
+Install your translation with the following command:
+
+ nmake -f make_mvc.mak install
+
+This will create the xx\LC_MESSAGES directory in runtime\lang if it does not
+already exist.
+You can also use the following command to install all languages:
+
+ nmake -f make_mvc.mak install-all
+
+
+vim:tw=78:
diff --git a/src/po/af.po b/src/po/af.po
new file mode 100644
index 0000000..9b6fb0a
--- /dev/null
+++ b/src/po/af.po
@@ -0,0 +1,5393 @@
+# Afrikaans translation for Vim
+# Do ":help uganda" in Vim to read copying and usage conditions.
+# Do ":help credits" in Vim to see a list of people who contributed.
+# Danie Roux <droux@tuks.co.za>, 2001
+# Edited: Jean Jordaan (njj) <jean@upfrontsystems.co.za>, 10/01/2001
+# Edited by Danie on the 31st of October 2001
+# Edited by Danie on the 30th of July 2005
+#
+# njj: Save == Stoor. Write == Skryf.
+# njj: "deleted" == "geskrap"; "remove" == "verwyder"
+# njj: "source" == "uitvoer", want "sourced" lêers word uitgevoer
+# njj: "abort" == "staak"
+# close == sluit
+# Onseker:
+# X Display - vertoonskerm? (njj: ek dink dis reg.)
+# open vim in another GTK Widget - het vertaal as element (njj: OK, maar
+# 'n element is algemener as 'n widget: mens kry byvoorbeeld HTML
+# en XML elemente. Maar ek kan nie nou aan 'n spesifieker woord dink
+# nie.)
+# Printing aborted - drukkery gestaak? (njj: ek dink dis reg.)
+#
+# exception - uitsondering
+# abandon - weg gegooi
+# socket - WEET NIE
+msgid ""
+msgstr ""
+"Project-Id-Version: Vim 6.0\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2005-04-17 23:24+0200\n"
+"PO-Revision-Date: Wed Oct 31 13:41 SAST 2001\n"
+"Last-Translator: Danie Roux <droux@tuks.co.za>\n"
+"Language-Team: Danie Roux <droux@tuks.co.za>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO_8859-1\n"
+"Content-Transfer-Encoding: 8-bit\n"
+
+msgid "E82: Cannot allocate any buffer, exiting..."
+msgstr "E82: Kan nie buffer toeken nie, program sluit..."
+
+msgid "E83: Cannot allocate buffer, using other one..."
+msgstr "E83: Kan nie buffer toeken nie, gaan ander een gebruik..."
+
+msgid "E515: No buffers were unloaded"
+msgstr "E515: Geen buffers is uitgelaai nie"
+
+msgid "E516: No buffers were deleted"
+msgstr "E516: Geen buffers is geskrap nie"
+
+msgid "E517: No buffers were wiped out"
+msgstr "E517: Geen buffers is geskrap nie"
+
+msgid "1 buffer unloaded"
+msgstr "1 buffer uitgelaai"
+
+#, c-format
+msgid "%d buffers unloaded"
+msgstr "%d buffers uitgelaai"
+
+msgid "1 buffer deleted"
+msgstr "1 buffer geskrap"
+
+#, c-format
+msgid "%d buffers deleted"
+msgstr "%d buffers geskrap"
+
+msgid "1 buffer wiped out"
+msgstr "1 buffer geskrap"
+
+#, c-format
+msgid "%d buffers wiped out"
+msgstr "%d buffers geskrap"
+
+msgid "E84: No modified buffer found"
+msgstr "E84: Geen veranderde buffer gevind nie"
+
+#. back where we started, didn't find anything.
+msgid "E85: There is no listed buffer"
+msgstr "E85: Daar is geen gelyste buffer nie"
+
+msgid "E86: Buffer %ld does not exist"
+msgstr "E86: Buffer %ld bestaan nie"
+
+msgid "E87: Cannot go beyond last buffer"
+msgstr "E87: Kan nie verby laaste buffer gaan nie"
+
+msgid "E88: Cannot go before first buffer"
+msgstr "E88: Kan nie vóór eerste buffer gaan nie"
+
+msgid "E89: No write since last change for buffer %ld (add ! to override)"
+msgstr "E89: Buffer %ld nog ongestoor sedert vorige wysiging (gebruik ! om te dwing)"
+
+msgid "E90: Cannot unload last buffer"
+msgstr "E90: Kan nie laaste buffer uitlaai nie"
+
+msgid "W14: Warning: List of file names overflow"
+msgstr "W14: Waarskuwing: Lêerlys loop oor"
+
+#, c-format
+msgid "E92: Buffer %ld not found"
+msgstr "E92: buffer %ld kon nie gevind word nie"
+
+#, c-format
+msgid "E93: More than one match for %s"
+msgstr "E93: Meer as een treffer vir %s"
+
+#, c-format
+msgid "E94: No matching buffer for %s"
+msgstr "E94: Geen buffer wat by %s pas nie"
+
+#, c-format
+msgid "line %ld"
+msgstr "reël %ld"
+
+msgid "E95: Buffer with this name already exists"
+msgstr "E95: Buffer met hierdie naam bestaan alreeds"
+
+msgid " [Modified]"
+msgstr " [Gewysig]"
+
+msgid "[Not edited]"
+msgstr "[Ongewysig]"
+
+msgid "[New file]"
+msgstr "[Nuwe lêer]"
+
+msgid "[Read errors]"
+msgstr "[Leesfoute]"
+
+msgid "[readonly]"
+msgstr "[lees alleen]"
+
+#, c-format
+msgid "1 line --%d%%--"
+msgstr "1 reël --%d%%--"
+
+#, c-format
+msgid "%ld lines --%d%%--"
+msgstr "%ld reëls --%d%%--"
+
+#, c-format
+msgid "line %ld of %ld --%d%%-- col "
+msgstr "reël %ld van %ld --%d%%-- kolom "
+
+msgid "[No file]"
+msgstr "[Geen lêer]"
+
+#. must be a help buffer
+msgid "help"
+msgstr "help"
+
+msgid "[help]"
+msgstr "[help]"
+
+msgid "[Preview]"
+msgstr "[Voorskou]"
+
+msgid "All"
+msgstr "Alles"
+
+msgid "Bot"
+msgstr "Ond"
+
+msgid "Top"
+msgstr "Bo"
+
+#, c-format
+msgid ""
+"\n"
+"# Buffer list:\n"
+msgstr ""
+"\n"
+"# Buffer lys:\n"
+
+msgid "[Error List]"
+msgstr "[Foutlys]"
+
+msgid "[No File]"
+msgstr "[Geen lêer]"
+
+msgid ""
+"\n"
+"--- Signs ---"
+msgstr ""
+"\n"
+"--- Tekens ---"
+
+#, c-format
+msgid "Signs for %s:"
+msgstr "Tekens vir %s:"
+
+#, c-format
+msgid " line=%ld id=%d name=%s"
+msgstr " reël=%ld id=%d naam=%s"
+
+#, c-format
+msgid "E96: Can not diff more than %ld buffers"
+msgstr "E96: Kan nie meer as %ld buffers 'diff' nie"
+
+msgid "E97: Cannot create diffs"
+msgstr "E97: Kan nie 'diffs' skep nie "
+
+msgid "Patch file"
+msgstr "Laslap lêer"
+
+msgid "E98: Cannot read diff output"
+msgstr "E98: Kan nie 'diff' afvoer lees nie"
+
+msgid "E99: Current buffer is not in diff mode"
+msgstr "E99: Huidige buffer is nie in 'diff' modus nie"
+
+msgid "E100: No other buffer in diff mode"
+msgstr "E100: Geen ander buffer in 'diff' modus nie"
+
+msgid "E101: More than two buffers in diff mode, don't know which one to use"
+msgstr ""
+"E101: Meer as twee buffers in 'diff' modus, weet nie watter een om te "
+"gebruik nie"
+
+#, c-format
+msgid "E102: Can't find buffer \"%s\""
+msgstr "E102: Kan buffer %s nie vind nie"
+
+#, c-format
+msgid "E103: Buffer \"%s\" is not in diff mode"
+msgstr "E103: Buffer \"%s\" is nie in 'diff' modus nie"
+
+msgid "E104: Escape not allowed in digraph"
+msgstr "E104: 'Escape' nie toegelaat in digraaf nie"
+
+msgid "E544: Keymap file not found"
+msgstr "E544: Sleutelbindinglêer nie gevind nie"
+
+msgid "E105: Using :loadkeymap not in a sourced file"
+msgstr "E105: :loadkeymap word buite 'n uitvoerlêer gebruik"
+
+msgid " Keyword completion (^N^P)"
+msgstr " Sleutelwoord voltooiing (^N^P)"
+
+#. ctrl_x_mode == 0, ^P/^N compl.
+msgid " ^X mode (^E^Y^L^]^F^I^K^D^V^N^P)"
+msgstr " ^X modus (^E^Y^L^]^F^I^K^D^V^N^P)"
+
+#. Scroll has it's own msgs, in it's place there is the msg for local
+#. * ctrl_x_mode = 0 (eg continue_status & CONT_LOCAL) -- Acevedo
+msgid " Keyword Local completion (^N^P)"
+msgstr " Sleutelwoord Lokale voltooiing (^N^P)"
+
+msgid " Whole line completion (^L^N^P)"
+msgstr " Hele-reël voltooiing (^L^N^P)"
+
+msgid " File name completion (^F^N^P)"
+msgstr " Lêernaam voltooiing (^F^N^P)"
+
+msgid " Tag completion (^]^N^P)"
+msgstr " Etiketvoltooiing (^]^N^P)"
+
+msgid " Path pattern completion (^N^P)"
+msgstr " Gidspatroon voltooiing (^N^P)"
+
+msgid " Definition completion (^D^N^P)"
+msgstr " Definisievoltooiing (^D^N^P)"
+
+msgid " Dictionary completion (^K^N^P)"
+msgstr " Woordeboekvoltooiing (^K^N^P)"
+
+msgid " Thesaurus completion (^T^N^P)"
+msgstr " Tesourusvoltooiing (^T^N^P)"
+
+msgid " Command-line completion (^V^N^P)"
+msgstr " Bevelreëlvoltooiing (^V^N^P)"
+
+msgid "Hit end of paragraph"
+msgstr "Het einde van paragraaf getref"
+
+msgid "'thesaurus' option is empty"
+msgstr "'thesaurus' opsie is leeg"
+
+msgid "'dictionary' option is empty"
+msgstr "'dictionary' opsie is leeg"
+
+#, c-format
+msgid "Scanning dictionary: %s"
+msgstr "Deursoek woordeboek: %s"
+
+msgid " (insert) Scroll (^E/^Y)"
+msgstr " (invoeg) Rol (^E/^Y)"
+
+msgid " (replace) Scroll (^E/^Y)"
+msgstr " (vervang) Rol (^E/^Y)"
+
+#, c-format
+msgid "Scanning: %s"
+msgstr "Soek vir: %s"
+
+#, c-format
+msgid "Scanning tags."
+msgstr "Deursoek etikette."
+
+msgid " Adding"
+msgstr " Word bygevoeg"
+
+#. showmode might reset the internal line pointers, so it must
+#. * be called before line = ml_get(), or when this address is no
+#. * longer needed. -- Acevedo.
+#.
+msgid "-- Searching..."
+msgstr "-- Soekend..."
+
+msgid "Back at original"
+msgstr "Terug by oorspronklike"
+
+msgid "Word from other line"
+msgstr "Woord van ander reël"
+
+msgid "The only match"
+msgstr "Die enigste treffer"
+
+#, c-format
+msgid "match %d of %d"
+msgstr "treffer %d van %d"
+
+#, c-format
+msgid "match %d"
+msgstr "treffer %d"
+
+#. Skip further arguments but do continue to
+#. * search for a trailing command.
+#, c-format
+msgid "E106: Unknown variable: \"%s\""
+msgstr "E106: Onbekende veranderlike: \"%s\""
+
+#, c-format
+msgid "E107: Missing parentheses: %s"
+msgstr "E107: Ontbrekende hakies: %s"
+
+#, c-format
+msgid "E108: No such variable: \"%s\""
+msgstr "E108: Geen veranderlike: \"%s\""
+
+msgid "E109: Missing ':' after '?'"
+msgstr "E109: Ontbrekende ':' na '?'"
+
+msgid "E110: Missing ')'"
+msgstr "E110: Ontbrekende ')'"
+
+msgid "E111: Missing ']'"
+msgstr "E111: Ontbrekende ']'"
+
+#, c-format
+msgid "E112: Option name missing: %s"
+msgstr "E112: Opsienaam ontbreek: %s"
+
+#, c-format
+msgid "E113: Unknown option: %s"
+msgstr "E113: Onbekende opsie: %s"
+
+#, c-format
+msgid "E114: Missing quote: %s"
+msgstr "E114: Ontbrekende aanhalingsteken: %s"
+
+#, c-format
+msgid "E115: Missing quote: %s"
+msgstr "E115: Ontbrekende aanhalingsteken: %s"
+
+#, c-format
+msgid "E116: Invalid arguments for function %s"
+msgstr "E116: Ongeldige parameters vir funksie %s"
+
+#, c-format
+msgid "E117: Unknown function: %s"
+msgstr "E117: Onbekende funksie: %s"
+
+#, c-format
+msgid "E118: Too many arguments for function: %s"
+msgstr "E118: Te veel parameters vir funksie: %s"
+
+#, c-format
+msgid "E119: Not enough arguments for function: %s"
+msgstr "E119: Te min parameters vir funksie: %s"
+
+#, c-format
+msgid "E120: Using <SID> not in a script context: %s"
+msgstr "E120: <SID> word buite skripkonteks gebruik: %s"
+
+#.
+#. * Yes this is ugly, I don't particularly like it either. But doing it
+#. * this way has the compelling advantage that translations need not to
+#. * be touched at all. See below what 'ok' and 'ync' are used for.
+#.
+msgid "&Ok"
+msgstr "&Ok"
+
+#, c-format
+msgid "+-%s%3ld lines: "
+msgstr "+-%s%3ld reëls: "
+
+msgid ""
+"&OK\n"
+"&Cancel"
+msgstr ""
+"&OK\n"
+"&Kanselleer"
+
+msgid "called inputrestore() more often than inputsave()"
+msgstr "inputrestore() is meer gereeld as inputsave() geroep"
+
+msgid "E655: Too many symbolic links (cycle?)"
+msgstr "E655: Te veel simboliese skakels (siklus?)"
+
+msgid "E240: No connection to Vim server"
+msgstr "E240: Geen verbinding met Vim bediener"
+
+msgid "E277: Unable to read a server reply"
+msgstr "E277: Kon bediener-terugvoer nie lees nie"
+
+msgid "E258: Unable to send to client"
+msgstr "E258: Kan nie na kliënt stuur nie"
+
+#, c-format
+msgid "E241: Unable to send to %s"
+msgstr "E241: Kan nie na %s stuur nie"
+
+msgid "(Invalid)"
+msgstr "(Ongeldig)"
+
+#, c-format
+msgid "E121: Undefined variable: %s"
+msgstr "E121: Ongedefinieerde veranderlike: %s"
+
+msgid "E461: Illegal variable name: %s"
+msgstr "E461: Ongeldige veranderlikenaam: %s"
+
+msgid "E122: Function %s already exists, add ! to replace it"
+msgstr "E122: Funksie %s bestaan alreeds, gebruik ! om te vervang"
+
+#, c-format
+msgid "E123: Undefined function: %s"
+msgstr "E123: Ongedefinieerde funksie: %s"
+
+#, c-format
+msgid "E124: Missing '(': %s"
+msgstr "E124: Ontbrekende '(': %s"
+
+#, c-format
+msgid "E125: Illegal argument: %s"
+msgstr "E125: Ongeldige parameter: %s"
+
+msgid "E126: Missing :endfunction"
+msgstr "E126: Ontbrekende ':endfunction'"
+
+#, c-format
+msgid "E127: Cannot redefine function %s: It is in use"
+msgstr "E127: Kan funksie %s nie herdefinieer nie: Dit is in gebruik"
+
+msgid "E129: Function name required"
+msgstr "E129: Funksienaam vereis"
+
+#, c-format
+msgid "E128: Function name must start with a capital: %s"
+msgstr "E128: Funksienaam moet met 'n hoofletter begin: %s"
+
+#, c-format
+msgid "E130: Undefined function: %s"
+msgstr "E130: Ongedefinieerde funksie: %s"
+
+#, c-format
+msgid "E131: Cannot delete function %s: It is in use"
+msgstr "E131: Kan funksie %s nie verwyder nie: Dit is in gebruik"
+
+msgid "E132: Function call depth is higher than 'maxfuncdepth'"
+msgstr "E132: Funksieroepdiepte is groter as 'maxfuncdepth'"
+
+#. always scroll up, don't overwrite
+#, c-format
+msgid "calling %s"
+msgstr "roep %s"
+
+msgid "%s aborted"
+msgstr "%s gekanselleer"
+
+#, c-format
+msgid "%s returning #%ld"
+msgstr "%s lewer #%ld op"
+
+#, c-format
+msgid "%s returning \"%s\""
+msgstr "%s lewer \"%s\" op"
+
+#. always scroll up, don't overwrite
+#, c-format
+msgid "continuing in %s"
+msgstr "vervolg in %s"
+
+msgid "E133: :return not inside a function"
+msgstr "E133: ':return' buite funksie"
+
+#, c-format
+msgid ""
+"\n"
+"# global variables:\n"
+msgstr ""
+"\n"
+"# globale veranderlikes:\n"
+
+msgid "Entering Debug mode. Type \"cont\" to continue."
+msgstr "Ontfoutmodus begin nou. Tik \"cont\" om te verlaat."
+
+#, c-format
+msgid "line %ld: %s"
+msgstr "reël %ld: %s"
+
+#, c-format
+msgid "cmd: %s"
+msgstr "cmd: %s"
+
+#, c-format
+msgid "Breakpoint in \"%s%s\" line %ld"
+msgstr "Inspeksiepunt in \"%s%s\" reël %ld"
+
+#, c-format
+msgid "E161: Breakpoint not found: %s"
+msgstr "E161: Inspeksiepunt kon nie gevind word nie: %s"
+
+msgid "No breakpoints defined"
+msgstr "Geen inspeksiepunte gedefinieer nie"
+
+#, c-format
+msgid "%3d %s %s line %ld"
+msgstr "%3d %s %s reël %ld"
+
+msgid "Save As"
+msgstr "Stoor As"
+
+#, c-format
+msgid "Save changes to \"%.*s\"?"
+msgstr "Stoor veranderinge na \"%.*s\"?"
+
+msgid "Untitled"
+msgstr "Ongetiteld"
+
+#, c-format
+msgid "E162: No write since last change for buffer \"%s\""
+msgstr "E162: Buffer \"%s\" is nie geskryf sedert vorige wysiging nie"
+
+msgid "Warning: Entered other buffer unexpectedly (check autocommands)"
+msgstr "Waarskuwing: Ander buffer onverwags betree (kyk na outobevele)"
+
+msgid "E163: There is only one file to edit"
+msgstr "E163: Daar is net een lêer om te bewerk"
+
+msgid "E164: Cannot go before first file"
+msgstr "E164: Kan nie vóór die eerste lêer gaan nie"
+
+msgid "E165: Cannot go beyond last file"
+msgstr "E165: Kan nie verby die laaste lêer gaan nie"
+
+msgid "E666: compiler not supported: %s"
+msgstr "E666: vertaler word nie ondersteun nie: %s"
+
+#, c-format
+msgid "Searching for \"%s\" in \"%s\""
+msgstr "Besig om te soek vir \"%s\" in \"%s\""
+
+#, c-format
+msgid "Searching for \"%s\""
+msgstr "Besig om te soek vir \"%s\""
+
+#, c-format
+msgid "not found in 'runtimepath': \"%s\""
+msgstr "kon nie in 'runtimepath' gevind word nie: \"%s\""
+
+msgid "Source Vim script"
+msgstr "Voer Vim skrip uit"
+
+#, c-format
+msgid "Cannot source a directory: \"%s\""
+msgstr "Kan nie gids uitvoer nie: \"%s\""
+
+#, c-format
+msgid "could not source \"%s\""
+msgstr "kon nie \"%s\" uitvoer nie"
+
+#, c-format
+msgid "line %ld: could not source \"%s\""
+msgstr "reël %ld: kon nie \"%s\" uitvoer nie"
+
+#, c-format
+msgid "sourcing \"%s\""
+msgstr "besig om \"%s\" uit te voer"
+
+#, c-format
+msgid "line %ld: sourcing \"%s\""
+msgstr "reël %ld: voer nou \"%s\" uit"
+
+#, c-format
+msgid "finished sourcing %s"
+msgstr "%s klaar uitgevoer"
+
+msgid "W15: Warning: Wrong line separator, ^M may be missing"
+msgstr "W15: Waarskuwing: Verkeerde reëlskeiding, ^M ontbreek dalk"
+
+msgid "E167: :scriptencoding used outside of a sourced file"
+msgstr "E167: ':scriptencoding' buite 'n uitvoerlêer gebruik"
+
+msgid "E168: :finish used outside of a sourced file"
+msgstr "E168: ':finish' buite 'n uitvoerlêer gebruik"
+
+#, c-format
+msgid "Page %d"
+msgstr "Bladsy %d"
+
+msgid "No text to be printed"
+msgstr "Geen teks om te druk nie"
+
+#, c-format
+msgid "Printing page %d (%d%%)"
+msgstr "Druk nou bladsy %d (%d%%)"
+
+#, c-format
+msgid " Copy %d of %d"
+msgstr " Kopie %d van %d"
+
+#, c-format
+msgid "Printed: %s"
+msgstr "Gedruk: %s"
+
+#, c-format
+msgid "Printing aborted"
+msgstr "Drukkery gestaak"
+
+msgid "E455: Error writing to PostScript output file"
+msgstr "E455: Kan nie na 'PostScript' afvoerlêer skryf nie"
+
+msgid "E624: Can't open file \"%s\""
+msgstr "E624: Kan nie lêer \"%s\" oopmaak nie"
+
+#, c-format
+msgid "E457: Can't read PostScript resource file \"%s\""
+msgstr "E457: Kan nie 'PostScript' hulpbron-lêer \"%s\" lees nie"
+
+msgid "E618: file \"%s\" is not a PostScript resource file"
+msgstr "E618: Lêer \"%s\" is nie 'n 'PostScript' hulpbron-lêer nie"
+
+msgid "E619: file \"%s\" is not a supported PostScript resource file"
+msgstr "E619: Lêer \"%s\" is nie 'n ondersteunde 'PostScript' hulpbron-lêer nie"
+
+#, c-format
+msgid "E621: \"%s\" resource file has wrong version"
+msgstr "E621: \"%s\" die hulpbron lêer het die verkeerde weergawe"
+
+msgid "E324: Can't open PostScript output file"
+msgstr "E324: Kan nie 'PostScript' afvoerlêer oopmaak nie"
+
+#, c-format
+msgid "E456: Can't open file \"%s\""
+msgstr "E456: Kan nie lêer %s oopmaak nie"
+
+msgid "E456: Can't find PostScript resource file \"prolog.ps\""
+msgstr "E456: Kan nie 'PostScript' hulpbron-lêer \"prolog.ps\" lees nie"
+
+msgid "E456: Can't find PostScript resource file \"%s.ps\""
+msgstr "E456: Kan nie 'PostScript' hulpbron-lêer \"%s\" vind nie"
+
+#, c-format
+msgid "E620: Unable to convert from multi-byte to \"%s\" encoding"
+msgstr "E620: Kon nie van wye-greep na \"%s\" enkodering verander nie"
+
+msgid "Sending to printer..."
+msgstr "Besig om te stuur na drukker..."
+
+msgid "E365: Failed to print PostScript file"
+msgstr "E365: Kon nie 'PostScript' lêer druk nie"
+
+msgid "Print job sent."
+msgstr "Druktaak gestuur."
+
+#, c-format
+msgid "Current %slanguage: \"%s\""
+msgstr "Huidige %staal: \"%s\""
+
+#, c-format
+msgid "E197: Cannot set language to \"%s\""
+msgstr "E197: Kan nie taal na \"%s\" verander nie"
+
+#, c-format
+msgid "<%s>%s%s %d, Hex %02x, Octal %03o"
+msgstr "<%s>%s%s %d, Hex %02x, Oktaal %03o"
+
+msgid "> %d, Hex %04x, Octal %o"
+msgstr "> %d, Hex %04x, Oktaal %o"
+
+msgid "> %d, Hex %08x, Octal %o"
+msgstr "> %d, Hex %08x, Oktaal %o"
+
+msgid "E134: Move lines into themselves"
+msgstr "E134: Skuif reëls in hulself in"
+
+msgid "1 line moved"
+msgstr "1 reël geskuif"
+
+#, c-format
+msgid "%ld lines moved"
+msgstr "%ld reëls geskuif"
+
+#, c-format
+msgid "%ld lines filtered"
+msgstr "%ld reëls filtreer"
+
+msgid "E135: *Filter* Autocommands must not change current buffer"
+msgstr "E135: *Filter* Outobevele mag nie die huidige buffer verander nie"
+
+msgid "[No write since last change]\n"
+msgstr "[Ongestoor sedert vorige verandering]\n"
+
+msgid "%sviminfo: %s in line: "
+msgstr "%sviminfo: %s in reël: "
+
+msgid "E136: viminfo: Too many errors, skipping rest of file"
+msgstr "E136: viminfo: Te veel foute, slaan die res van die lêer oor"
+
+#, c-format
+msgid "Reading viminfo file \"%s\"%s%s%s"
+msgstr "Besig om viminfo lêer \"%s\"%s%s%s te lees"
+
+msgid " info"
+msgstr " inligting"
+
+msgid " marks"
+msgstr " merkers"
+
+msgid " FAILED"
+msgstr " GEFAAL"
+
+#, c-format
+msgid "E137: Viminfo file is not writable: %s"
+msgstr "E137: Viminfo lêer is nie skryfbaar nie: %s"
+
+#, c-format
+msgid "E138: Can't write viminfo file %s!"
+msgstr "E138: Kan nie viminfo lêer %s stoor nie!"
+
+#, c-format
+msgid "Writing viminfo file \"%s\""
+msgstr "Besig om viminfo lêer \"%s\" te stoor"
+
+#. Write the info:
+#, c-format
+msgid "# This viminfo file was generated by Vim %s.\n"
+msgstr "# Hierdie viminfo lêer is gegenereer deur Vim %s.\n"
+
+#, c-format
+msgid ""
+"# You may edit it if you're careful!\n"
+"\n"
+msgstr ""
+"# Jy mag dit wysig as jy versigtig is!\n"
+"\n"
+
+#, c-format
+msgid "# Value of 'encoding' when this file was written\n"
+msgstr "# Waarde van 'encoding' toe hierdie lêer gestoor is\n"
+
+msgid "Illegal starting char"
+msgstr "Ongeldige beginkarakter"
+
+#. Overwriting a file that is loaded in another buffer is not a
+#. * good idea.
+msgid "E139: File is loaded in another buffer"
+msgstr "E139: Lêer is gelaai in ander buffer"
+
+msgid "Write partial file?"
+msgstr "Skryf gedeeltelike lêer?"
+
+msgid "E140: Use ! to write partial buffer"
+msgstr "E140: Gebruik ! om gedeeltelike buffer te skryf"
+
+#, c-format
+msgid "Overwrite existing file \"%.*s\"?"
+msgstr "Oorskryf bestaande lêer \"%.*s\"?"
+
+#, c-format
+msgid "E141: No file name for buffer %ld"
+msgstr "E141: Geen lêernaam vir buffer %ld nie"
+
+msgid "E142: File not written: Writing is disabled by 'write' option"
+msgstr "E142: Lêer nie gestoor nie: Stoor is afgeskakel deur die 'write' opsie"
+
+#, c-format
+msgid ""
+"'readonly' option is set for \"%.*s\".\n"
+"Do you wish to write anyway?"
+msgstr ""
+"'readonly' opsie is aan vir \"%.*s\".\n"
+"Wil jy dit forseer?"
+
+msgid "Edit File"
+msgstr "Verander lêer"
+
+#, c-format
+msgid "E143: Autocommands unexpectedly deleted new buffer %s"
+msgstr "E143: Outobevele het nuwe buffer %s onverwags geskrap"
+
+msgid "E144: non-numeric argument to :z"
+msgstr "E144: nie-numeriese parameter vir :z"
+
+msgid "E145: Shell commands not allowed in rvim"
+msgstr "E145: Dop bevele nie toegelaat in rvim"
+
+msgid "E146: Regular expressions can't be delimited by letters"
+msgstr "E146: Patrone kan nie deur letters afgebaken word nie"
+
+#, c-format
+msgid "replace with %s (y/n/a/q/l/^E/^Y)?"
+msgstr "vervang met %s (y/n/a/q/l/^E/^Y)?"
+
+msgid "(Interrupted) "
+msgstr "(Onderbreek) "
+
+msgid "1 substitution"
+msgstr "1 vervanging"
+
+#, c-format
+msgid "%ld substitutions"
+msgstr "%ld vervangings"
+
+msgid " on 1 line"
+msgstr " op 1 reël"
+
+#, c-format
+msgid " on %ld lines"
+msgstr " op %ld reëls"
+
+msgid "E147: Cannot do :global recursive"
+msgstr "E147: Kan nie :global rekursief doen nie "
+
+msgid "E148: Regular expression missing from global"
+msgstr "E148: Patroon ontbreek uit globaal"
+
+#, c-format
+msgid "Pattern found in every line: %s"
+msgstr "Patroon gevind in elke reël: %s"
+
+#, c-format
+msgid ""
+"\n"
+"# Last Substitute String:\n"
+"$"
+msgstr ""
+"\n"
+"# Vorige Vervangstring:\n"
+"$"
+
+msgid "E478: Don't panic!"
+msgstr "E478: Bly kalm!"
+
+msgid "E661: Sorry, no '%s' help for %s"
+msgstr "E661: Jammer, geen '%s' hulp vir %s nie"
+
+#, c-format
+msgid "E149: Sorry, no help for %s"
+msgstr "E149: Jammer, geen hulp vir %s nie"
+
+#, c-format
+msgid "Sorry, help file \"%s\" not found"
+msgstr "Jammer, hulplêer \"%s\" kan nie gevind word nie"
+
+#, c-format
+msgid "E150: Not a directory: %s"
+msgstr "E150: Nie 'n gids nie: %s"
+
+#, c-format
+msgid "E152: Cannot open %s for writing"
+msgstr "E152: Kan nie %s oopmaak om te skryf nie"
+
+#, c-format
+msgid "E153: Unable to open %s for reading"
+msgstr "E153: Kan nie %s oop maak om te lees nie"
+
+#, c-format
+msgid "E670: Mix of help file encodings within a language: %s"
+msgstr "E670: 'n Mengsel van hulplêer enkoderings in 'n taal: %s"
+
+msgid "E154: Duplicate tag \"%s\" in file %s/%s"
+msgstr "E154: Duplikaat etiket \"%s\" in lêer %s/%s"
+
+#, c-format
+msgid "E160: Unknown sign command: %s"
+msgstr "E160: Onbekende funksie: %s"
+
+msgid "E156: Missing sign name"
+msgstr "E156: Ontbrekende tekennaam"
+
+msgid "E612: Too many signs defined"
+msgstr "E612: Te veel tekens gedefinieer"
+
+#, c-format
+msgid "E239: Invalid sign text: %s"
+msgstr "E239: Ongeldige tekenteks: %s"
+
+#, c-format
+msgid "E155: Unknown sign: %s"
+msgstr "E155: Onbekende opsie: %s"
+
+msgid "E159: Missing sign number"
+msgstr "E159: Ontbrekende tekennommer"
+
+#, c-format
+msgid "E158: Invalid buffer name: %s"
+msgstr "E158: Ongeldige buffernaam: %s"
+
+#, c-format
+msgid "E157: Invalid sign ID: %ld"
+msgstr "E157: Ongeldige teken ID: %ld"
+
+msgid " (NOT FOUND)"
+msgstr " (NIE GEVIND NIE)"
+
+msgid " (not supported)"
+msgstr " (word nie ondersteun nie)"
+
+msgid "[Deleted]"
+msgstr "[Geskrap]"
+
+msgid "Entering Ex mode. Type \"visual\" to go to Normal mode."
+msgstr "Betree Ex modus. Tik \"visual\" om na Normale modus terug te keer."
+
+#. must be at EOF
+msgid "E501: At end-of-file"
+msgstr "E501: By lêereinde"
+
+msgid "E169: Command too recursive"
+msgstr "E169: Bevel te rekursief"
+
+msgid "E605: Exception not caught: %s"
+msgstr "E605: Uitsondering nie gevang nie: %s"
+
+msgid "End of sourced file"
+msgstr "Einde van uitvoerlêer"
+
+msgid "End of function"
+msgstr "Einde van funksie "
+
+msgid "E464: Ambiguous use of user-defined command"
+msgstr "E464: Dubbelsinnige gebruik van gebruiker-gedefinieerde bevel"
+
+msgid "E492: Not an editor command"
+msgstr "E492: Nie 'n verwerkerbevel nie"
+
+msgid "E493: Backwards range given"
+msgstr "E493: Terugwaardse omvang gegee"
+
+msgid "Backwards range given, OK to swap"
+msgstr "Terugwaardse omvang gegee, OK om te ruil"
+
+msgid "E494: Use w or w>>"
+msgstr "E494: Gebruik w of w>>"
+
+msgid "E319: Sorry, the command is not available in this version"
+msgstr "E319: Jammer, die bevel is nie geïmplementeer nie"
+
+msgid "E172: Only one file name allowed"
+msgstr "E172: Slegs een lêernaam toegelaat"
+
+msgid "1 more file to edit. Quit anyway?"
+msgstr "Nog 1 lêer om te bewerk. Stop in elk geval?"
+
+#, c-format
+msgid "%d more files to edit. Quit anyway?"
+msgstr "Nog %d lêers om te bewerk. Stop in elk geval?"
+
+msgid "E173: 1 more file to edit"
+msgstr "E173: Nog 1 lêer om te bewerk"
+
+#, c-format
+msgid "E173: %ld more files to edit"
+msgstr "E173: Nog %ld lêers om te bewerk"
+
+msgid "E174: Command already exists: add ! to replace it"
+msgstr "E174: Bevel bestaan alreeds: gebruik ! om te herdefinieer"
+
+msgid ""
+"\n"
+" Name Args Range Complete Definition"
+msgstr ""
+"\n"
+" Naam Args Reeks Klaar Definisie"
+
+msgid "No user-defined commands found"
+msgstr "Geen gebruiker-gedefinieerde bevele gevind nie"
+
+msgid "E175: No attribute specified"
+msgstr "E175: Geen eienskappe gespesifiseer nie"
+
+msgid "E176: Invalid number of arguments"
+msgstr "E176: Ongeldige aantal parameters"
+
+msgid "E177: Count cannot be specified twice"
+msgstr "E177: Telling kan nie twee keer gespesifiseer word nie"
+
+msgid "E178: Invalid default value for count"
+msgstr "E178: Ongeldige verstekwaarde vir telling"
+
+msgid "E179: argument required for complete"
+msgstr "E179: parameter nodig vir voltooiing"
+
+#, c-format
+msgid "E180: Invalid complete value: %s"
+msgstr "E180: Ongeldige voltooiingswaarde: %s"
+
+msgid "E468: Completion argument only allowed for custom completion"
+msgstr "E468: Voltooiingsargument words slegs toegelaat vir eie voltooiing"
+
+msgid "E467: Custom completion requires a function argument"
+msgstr "E467: Eie voltooiing benodig 'n funksie parameter"
+
+#, c-format
+msgid "E181: Invalid attribute: %s"
+msgstr "E181: Ongeldige eienskap: %s"
+
+msgid "E182: Invalid command name"
+msgstr "E182: Ongeldige bevelnaam"
+
+msgid "E183: User defined commands must start with an uppercase letter"
+msgstr "E183: Gebruiker-gedefinieerde bevele moet met 'n hoofletter begin"
+
+#, c-format
+msgid "E184: No such user-defined command: %s"
+msgstr "E184: Geen gebruiker-gedefinieerde bevel nie: %s"
+
+#, c-format
+msgid "E185: Cannot find color scheme %s"
+msgstr "E185: Kan nie kleurskema %s vind nie"
+
+msgid "Greetings, Vim user!"
+msgstr "Goeiedag, Vim gebruiker!"
+
+msgid "Edit File in new window"
+msgstr "Bewerk lêer in nuwe venster"
+
+msgid "No swap file"
+msgstr "Geen ruillêer"
+
+msgid "Append File"
+msgstr "Las aan by lêer"
+
+msgid "E186: No previous directory"
+msgstr "E186: Geen vorige gids nie"
+
+msgid "E187: Unknown"
+msgstr "E187: Onbekend"
+
+msgid "E465: :winsize requires two number arguments"
+msgstr "E465: ':winsize' benodig twee nommer parameters"
+
+#, c-format
+msgid "Window position: X %d, Y %d"
+msgstr "Vensterposisie: X %d, Y %d"
+
+msgid "E188: Obtaining window position not implemented for this platform"
+msgstr ""
+"E188: Verkryging van vensterposisie is nie vir hierdie platform "
+"geïmplementeer nie"
+
+msgid "E466: :winpos requires two number arguments"
+msgstr "E466: :winpos benodig twee parameters"
+
+msgid "Save Redirection"
+msgstr "Stoor Herversturing"
+
+msgid "Save View"
+msgstr "Stoor Oorsig"
+
+msgid "Save Session"
+msgstr "Stoor Sessie"
+
+msgid "Save Setup"
+msgstr "Stoor konfigurasie"
+
+msgid "E189: \"%s\" exists (add ! to override)"
+msgstr "E189: \"%s\" bestaan (gebruik ! om te dwing)"
+
+#, c-format
+msgid "E190: Cannot open \"%s\" for writing"
+msgstr "E190: Kan \"%s\" nie oopmaak vir skryf nie"
+
+#. set mark
+msgid "E191: Argument must be a letter or forward/backward quote"
+msgstr ""
+"E191: Parameter moet 'n letter of 'n terug/vorentoe aanhalingsteken wees"
+
+msgid "E192: Recursive use of :normal too deep"
+msgstr "E192: Rekursiewe gebruik van ':normal' te diep"
+
+msgid "E194: No alternate file name to substitute for '#'"
+msgstr "E194: Geen alternatiewe lêernaam vir '#' nie"
+
+msgid "E495: no autocommand file name to substitute for \"<afile>\""
+msgstr "E495: geen outobevel-lêernaam om \"<afile>\" mee te vervang nie"
+
+msgid "E496: no autocommand buffer number to substitute for \"<abuf>\""
+msgstr "E496: geen outobevel buffernommer om \"<abuf>\" mee te vervang nie"
+
+msgid "E497: no autocommand match name to substitute for \"<amatch>\""
+msgstr "E497: geen outobevel treffernaam om \"<amatch>\" mee te vervang nie"
+
+msgid "E498: no :source file name to substitute for \"<sfile>\""
+msgstr "E498: geen ':source' lêernaam om \"<sfile>\" mee te vervang nie"
+
+msgid "E499: Empty file name for '%' or '#', only works with \":p:h\""
+msgstr "E499: Leë lêernaam vir '%' of '#', werk slegs met \":p:h\""
+
+msgid "E500: Evaluates to an empty string"
+msgstr "E500: Evalueer na 'n leë string"
+
+msgid "E195: Cannot open viminfo file for reading"
+msgstr "E195: Kan 'viminfo' lêer nie oopmaak om te lees nie"
+
+msgid "E196: No digraphs in this version"
+msgstr "E196: Geen digrawe in hierdie weergawe nie"
+
+msgid "E608: Cannot :throw exceptions with 'Vim' prefix"
+msgstr "E608: Kan nie uitsonderings ':throw' met 'Vim' voorvoegsel nie"
+
+#. always scroll up, don't overwrite
+#, c-format
+msgid "Exception thrown: %s"
+msgstr "Uitsondering gegooi: %s"
+
+#, c-format
+msgid "Exception finished: %s"
+msgstr "Uitsondering het klaar gemaak: %s"
+
+#, c-format
+msgid "Exception discarded: %s"
+msgstr "Uitsondering weg gegooi: %s"
+
+msgid "%s, line %ld"
+msgstr "%s, reël %ld"
+
+#. always scroll up, don't overwrite
+msgid "Exception caught: %s"
+msgstr "Uitsondering gevang: %s"
+
+#, c-format
+msgid "%s made pending"
+msgstr "%s is afwagtend gemaak"
+
+msgid "%s resumed"
+msgstr "%s teruggekeer"
+
+#, c-format
+msgid "%s discarded"
+msgstr "%s weg gegooi"
+
+msgid "Exception"
+msgstr "Uitsondering"
+
+msgid "Error and interrupt"
+msgstr "Fout en onderbreking"
+
+msgid "Error"
+msgstr "Fout"
+
+#. if (pending & CSTP_INTERRUPT)
+msgid "Interrupt"
+msgstr "Onderbreek"
+
+msgid "E579: :if nesting too deep"
+msgstr "E579: geneste ':if' te diep"
+
+msgid "E580: :endif without :if"
+msgstr "E580: ':endif' sonder ':if'"
+
+msgid "E581: :else without :if"
+msgstr "E581: ':else' sonder ':if'"
+
+msgid "E582: :elseif without :if"
+msgstr "E582: ':elseif' sonder ':if'"
+
+msgid "E583: multiple :else"
+msgstr "E583: meer as een ':else'"
+
+msgid "E584: :elseif after :else"
+msgstr "E584: ':elseif' na ':else'"
+
+msgid "E585: :while nesting too deep"
+msgstr "E585: ':while' te diep genes"
+
+msgid "E586: :continue without :while"
+msgstr "E586: ':continue' sonder ':while'"
+
+msgid "E587: :break without :while"
+msgstr "E587: ':break' sonder ':while'"
+
+msgid "E601: :try nesting too deep"
+msgstr "E601: geneste ':try' te diep"
+
+msgid "E603: :catch without :try"
+msgstr "E603: ':catch' sonder ':try'"
+
+#. Give up for a ":catch" after ":finally" and ignore it.
+#. * Just parse.
+msgid "E604: :catch after :finally"
+msgstr "E604: ':catch' na ':finally'"
+
+msgid "E606: :finally without :try"
+msgstr "E606: ':finally' sonder ':try'"
+
+#. Give up for a multiple ":finally" and ignore it.
+msgid "E607: multiple :finally"
+msgstr "E607: meer as een ':finally'"
+
+msgid "E602: :endtry without :try"
+msgstr "E602: ':endtry' sonder ':try'"
+
+msgid "E193: :endfunction not inside a function"
+msgstr "E193: ':endfunction' nie in 'n funksie nie"
+
+msgid "tagname"
+msgstr "etiketnaam"
+
+msgid " kind file\n"
+msgstr " tipe lêer\n"
+
+msgid "'history' option is zero"
+msgstr "'history' opsie is nul"
+
+#, c-format
+msgid ""
+"\n"
+"# %s History (newest to oldest):\n"
+msgstr ""
+"\n"
+"# %s Geskiedenis (van nuutste na oudste):\n"
+
+msgid "Command Line"
+msgstr "Bevelreël"
+
+msgid "Search String"
+msgstr "Soekstring"
+
+msgid "Expression"
+msgstr "Uitdrukking"
+
+msgid "Input Line"
+msgstr "Invoer Lyn"
+
+msgid "E198: cmd_pchar beyond the command length"
+msgstr "E198: 'cmd_pchar' verby die einde van opdraglengte"
+
+msgid "E199: Active window or buffer deleted"
+msgstr "E199: Aktiewe venster of buffer geskrap"
+
+msgid "Illegal file name"
+msgstr "Ongeldige lêernaam"
+
+msgid "is a directory"
+msgstr "is 'n gids"
+
+msgid "is not a file"
+msgstr "is nie 'n lêer nie"
+
+msgid "[New File]"
+msgstr "[Nuwe lêer]"
+
+msgid "[Permission Denied]"
+msgstr "[Toestemming Geweier]"
+
+msgid "E200: *ReadPre autocommands made the file unreadable"
+msgstr "E200: '*ReadPre' outobevele het die lêer onleesbaar gemaak"
+
+msgid "E201: *ReadPre autocommands must not change current buffer"
+msgstr "E201: '*ReadPre' outobevele mag nie die huidige buffer verander nie"
+
+msgid "Vim: Reading from stdin...\n"
+msgstr "Vim: Lees nou vanaf 'stdin'...\n"
+
+msgid "Reading from stdin..."
+msgstr "Lees nou vanaf stdin... "
+
+#. Re-opening the original file failed!
+msgid "E202: Conversion made file unreadable!"
+msgstr "E202: Omsetting het lêer onleesbaar gemaak!"
+
+msgid "[fifo/socket]"
+msgstr "[fifo/socket]"
+
+msgid "[fifo]"
+msgstr "[fifo]"
+
+msgid "[socket]"
+msgstr "[socket]"
+
+msgid "[RO]"
+msgstr "[RO]"
+
+msgid "[CR missing]"
+msgstr "[CR ontbreek]"
+
+msgid "[NL found]"
+msgstr "[NL gevind]"
+
+msgid "[long lines split]"
+msgstr "[lang reëls verdeel]"
+
+msgid "[NOT converted]"
+msgstr "[NIE omgesit nie]"
+
+msgid "[converted]"
+msgstr "[omgesit]"
+
+msgid "[crypted]"
+msgstr "[gekodeer]"
+
+msgid "[CONVERSION ERROR]"
+msgstr "[OMSETTINGSFOUT]"
+
+#, c-format
+msgid "[ILLEGAL BYTE in line %ld]"
+msgstr "[ONWETTIGE GREEP in reël %ld]"
+
+msgid "[READ ERRORS]"
+msgstr "[LEESFOUTE]"
+
+msgid "Can't find temp file for conversion"
+msgstr "Kan nie tydelike lêer vir omsetting vind nie"
+
+msgid "Conversion with 'charconvert' failed"
+msgstr "Omsetting met 'charconvert' het gefaal"
+
+msgid "can't read output of 'charconvert'"
+msgstr "kan afvoer van 'charconvert' nie lees nie"
+
+msgid "E203: Autocommands deleted or unloaded buffer to be written"
+msgstr "E203: Outobevele het die skryfbuffer geskrap of uitgelaai"
+
+msgid "E204: Autocommand changed number of lines in unexpected way"
+msgstr "E204: Outobevel het etlike reëls op onverwagse wyse verander "
+
+msgid "NetBeans disallows writes of unmodified buffers"
+msgstr "NetBeans laat nie skryf toe van onveranderde buffers nie"
+
+msgid "Partial writes disallowed for NetBeans buffers"
+msgstr "Gedeeltelike skryf word nie toegelaat vir NetBeans buffers nie"
+
+msgid "is not a file or writable device"
+msgstr "is nie 'n lêer of 'n skryfbare toestel nie"
+
+msgid "is read-only (add ! to override)"
+msgstr "is lees-alleen (gebruik ! om te dwing)"
+
+msgid "E506: Can't write to backup file (add ! to override)"
+msgstr "E506: Kan nie na rugsteunlêer skryf nie (gebruik ! om te dwing)"
+
+msgid "E507: Close error for backup file (add ! to override)"
+msgstr "E507: Sluitfout vir rugsteunlêer (gebruik ! om te dwing)"
+
+msgid "E508: Can't read file for backup (add ! to override)"
+msgstr "E508: Kan rugsteunlêer nie lees nie (gebruik ! om te dwing)"
+
+msgid "E509: Cannot create backup file (add ! to override)"
+msgstr "E509: Kan rugsteunlêer nie skep nie (gebruik ! om te dwing)"
+
+msgid "E510: Can't make backup file (add ! to override)"
+msgstr "E510: Kan rugsteunlêer nie skep nie (gebruik ! om te dwing)"
+
+msgid "E460: The resource fork would be lost (add ! to override)"
+msgstr "E460: Die hulpbronvurk sal verlore gaan (gebruik ! om te dwing)"
+
+msgid "E214: Can't find temp file for writing"
+msgstr "E214: Kan nie tydelike lêer vind vir skryf nie"
+
+msgid "E213: Cannot convert (add ! to write without conversion)"
+msgstr "E213: Kan nie omsit nie (gebruik ! om te skryf sonder omsetting)"
+
+msgid "E166: Can't open linked file for writing"
+msgstr "E166: Kan lêer nie oopmaak vir skryf nie"
+
+msgid "E212: Can't open file for writing"
+msgstr "E212: Kan lêer nie oopmaak vir skryf nie"
+
+msgid "E667: Fsync failed"
+msgstr "E667: 'Fsync' het gefaal"
+
+msgid "E512: Close failed"
+msgstr "E512: Sluiting gefaal"
+
+msgid "E513: write error, conversion failed"
+msgstr "E513: skryffout, omsetting gefaal"
+
+msgid "E514: write error (file system full?)"
+msgstr "E514: skryffout (lêerstelsel vol?)"
+
+msgid " CONVERSION ERROR"
+msgstr " OMSETTINGSFOUT"
+
+msgid "[Device]"
+msgstr "[Toestel]"
+
+msgid "[New]"
+msgstr "[Nuut]"
+
+msgid " [a]"
+msgstr " [a]"
+
+msgid " appended"
+msgstr " bygevoeg"
+
+msgid " [w]"
+msgstr " [w]"
+
+msgid " written"
+msgstr " geskryf"
+
+msgid "E205: Patchmode: can't save original file"
+msgstr "E205: patchmode: kan oorspronklike lêer nie stoor nie"
+
+msgid "E206: patchmode: can't touch empty original file"
+msgstr "E206: patchmode: kan leë oorspronglêer nie 'touch' nie"
+
+msgid "E207: Can't delete backup file"
+msgstr "E207: Kan rugsteunlêer nie verwyder nie"
+
+msgid ""
+"\n"
+"WARNING: Original file may be lost or damaged\n"
+msgstr ""
+"\n"
+"WAARSKUWING: Oorspronklike lêer mag verlore of beskadig wees\n"
+
+msgid "don't quit the editor until the file is successfully written!"
+msgstr "moenie die verwerker verlaat voor die lêer suksesvol geskryf is nie!"
+
+msgid "[dos]"
+msgstr "[dos]"
+
+msgid "[dos format]"
+msgstr "[dos formaat]"
+
+msgid "[mac]"
+msgstr "[mac]"
+
+msgid "[mac format]"
+msgstr "[mac formaat]"
+
+msgid "[unix]"
+msgstr "[unix]"
+
+msgid "[unix format]"
+msgstr "[unix formaat]"
+
+msgid "1 line, "
+msgstr "1 reël, "
+
+#, c-format
+msgid "%ld lines, "
+msgstr "%ld reëls, "
+
+msgid "1 character"
+msgstr "1 karakter"
+
+#, c-format
+msgid "%ld characters"
+msgstr "%ld karakters"
+
+msgid "[noeol]"
+msgstr "[noeol]"
+
+msgid "[Incomplete last line]"
+msgstr "[Onvoltooide laaste reël]"
+
+#. don't overwrite messages here
+#. must give this prompt
+#. don't use emsg() here, don't want to flush the buffers
+msgid "WARNING: The file has been changed since reading it!!!"
+msgstr "WAARSKUWING: Die lêer het verander sedert dit gelees is!!!"
+
+msgid "Do you really want to write to it"
+msgstr "Wil jy regtig soontoe skryf?"
+
+#, c-format
+msgid "E208: Error writing to \"%s\""
+msgstr "E208: Kan nie skryf na \"%s\""
+
+#, c-format
+msgid "E209: Error closing \"%s\""
+msgstr "E209: Kan \"%s\" nie sluit nie"
+
+#, c-format
+msgid "E210: Error reading \"%s\""
+msgstr "E210: Kan \"%s\" nie lees nie"
+
+msgid "E246: FileChangedShell autocommand deleted buffer"
+msgstr "E246: 'FileChangedShell' outobevel het buffer verwyder"
+
+#, c-format
+msgid "E211: Warning: File \"%s\" no longer available"
+msgstr "E211: Waarskuwing: Lêer \"%s\" is nie meer beskikbaar nie"
+
+#, c-format
+msgid ""
+"W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as "
+"well"
+msgstr ""
+"W12: Waarskuwing: Lêer \"%s\" het verander sedert bewerking begin het en die "
+"buffer in Vim het ook verander"
+
+#, c-format
+msgid "W11: Warning: File \"%s\" has changed since editing started"
+msgstr "W11: Waarskuwing: Lêer \"%s\" het verander sedert bewerking begin het"
+
+#, c-format
+msgid "W16: Warning: Mode of file \"%s\" has changed since editing started"
+msgstr ""
+"W16: Waarskuwing: Modus van lêer \"%s\" het verander sedert bewerking begin "
+"het"
+
+#, c-format
+msgid "W13: Warning: File \"%s\" has been created after editing started"
+msgstr "W13: Waarskuwing: Lêer \"%s\" is geskep sedert bewerking begin het"
+
+msgid "See \":help W11\" for more info."
+msgstr "Sien \":help W11\" vir meer inligting."
+
+msgid "Warning"
+msgstr "Waarskuwing"
+
+msgid ""
+"&OK\n"
+"&Load File"
+msgstr ""
+"&OK\n"
+"&Laai Lêer"
+
+msgid "E462: Could not prepare for reloading \"%s\""
+msgstr "E462: Kon nie voorberei vir herlaai nie \"%s\""
+
+#, c-format
+msgid "E321: Could not reload \"%s\""
+msgstr "E321: Kon nie \"%s\" herlaai nie"
+
+msgid "--Deleted--"
+msgstr "--Geskrap--"
+
+#. the group doesn't exist
+#, c-format
+msgid "E367: No such group: \"%s\""
+msgstr "E367: Geen sodanige groep nie: \"%s\""
+
+#, c-format
+msgid "E215: Illegal character after *: %s"
+msgstr "E215: Ongeldige karakter na *: %s"
+
+#, c-format
+msgid "E216: No such event: %s"
+msgstr "E216: Geen sodanige gebeurtenis nie: %s"
+
+msgid "E216: No such group or event: %s"
+msgstr "E216: Geen sodanige groep of gebeurtenis nie: %s"
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Autocommands ---"
+msgstr ""
+"\n"
+"--- Outobevele ---"
+
+msgid "E217: Can't execute autocommands for ALL events"
+msgstr "E217: Kan nie outobevele uitvoer vir 'ALL' gebeurtenisse nie"
+
+msgid "No matching autocommands"
+msgstr "Geen passende outobevele nie"
+
+msgid "E218: autocommand nesting too deep"
+msgstr "E218: outobevele te diep genes"
+
+#, c-format
+msgid "%s Autocommands for \"%s\""
+msgstr "%s outobevele vir \"%s\""
+
+#, c-format
+msgid "Executing %s"
+msgstr "Voer %s uit"
+
+#. always scroll up, don't overwrite
+#, c-format
+msgid "autocommand %s"
+msgstr "outobevel %s"
+
+msgid "E219: Missing {."
+msgstr "E219: Ontbrekende {."
+
+msgid "E220: Missing }."
+msgstr "E220: Ontbrekende }."
+
+msgid "E490: No fold found"
+msgstr "E490: Geen vou gevind nie"
+
+msgid "E350: Cannot create fold with current 'foldmethod'"
+msgstr "E350: Kan nie vou skep met huidige 'foldmethod' nie"
+
+msgid "E351: Cannot delete fold with current 'foldmethod'"
+msgstr "E351: Kan nie vou skrap met huidige 'foldmethod' nie"
+
+msgid "E222: Add to read buffer"
+msgstr "E222: Voeg by leesbuffer"
+
+msgid "E223: recursive mapping"
+msgstr "E223: rekursiewe binding"
+
+#, c-format
+msgid "E224: global abbreviation already exists for %s"
+msgstr "E224: globale afkorting bestaan alreeds vir %s"
+
+#, c-format
+msgid "E225: global mapping already exists for %s"
+msgstr "E225: globale binding bestaan alreeds vir %s"
+
+#, c-format
+msgid "E226: abbreviation already exists for %s"
+msgstr "E226: afkorting bestaan already vir %s"
+
+#, c-format
+msgid "E227: mapping already exists for %s"
+msgstr "E227: binding bestaan alreeds vir %s"
+
+msgid "No abbreviation found"
+msgstr "Geen afkorting gevind nie"
+
+msgid "No mapping found"
+msgstr "Geen binding gevind nie"
+
+msgid "E228: makemap: Illegal mode"
+msgstr "E228: makemap: Ongeldige modus"
+
+msgid "<cannot open> "
+msgstr "<kan nie oopmaak nie> "
+
+msgid "E616: vim_SelFile: can't get font %s"
+msgstr "E616: 'vim_SelFile': kan font %s nie kry nie"
+
+msgid "E614: vim_SelFile: can't return to current directory"
+msgstr "E614: 'vim_SelFile': Kan nie terugkeer na huidige gids nie"
+
+msgid "Pathname:"
+msgstr "Gidsnaam:"
+
+msgid "E615: vim_SelFile: can't get current directory"
+msgstr "E615: vim_SelFile: Kan nie huidige gids verkry nie"
+
+msgid "OK"
+msgstr "OK"
+
+msgid "Cancel"
+msgstr "Kanselleer"
+
+msgid "Vim dialog"
+msgstr "Vim dialooghokkie"
+
+msgid "Scrollbar Widget: Could not get geometry of thumb pixmap."
+msgstr "Rolstaafelement: Kon nie pikselmatriks-duimnael se geometrie kry nie"
+
+msgid "E232: Cannot create BalloonEval with both message and callback"
+msgstr "E232: Kan nie BalloonEval skep met beide boodskap en terugroep nie"
+
+msgid "E229: Cannot start the GUI"
+msgstr "E229: Kan nie die GUI begin nie"
+
+#, c-format
+msgid "E230: Cannot read from \"%s\""
+msgstr "E230: Kan nie lees uit \"%s\" nie"
+
+msgid "E665: Cannot start GUI, no valid font found"
+msgstr "E665: Kan nie GUI begin nie, geen geldige font gevind nie"
+
+msgid "E231: 'guifontwide' invalid"
+msgstr "E231: 'guifontwide' ongeldig"
+
+msgid "E599: Value of 'imactivatekey' is invalid"
+msgstr "E599: Waarde van 'imactivatekey' is ongeldig"
+
+#, c-format
+msgid "E254: Cannot allocate color %s"
+msgstr "E254: Kan nie kleur %s toeken nie"
+
+msgid "Vim dialog..."
+msgstr "Vim dialooghokkie..."
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"&Cancel"
+msgstr ""
+"&Ja\n"
+"&Nee\n"
+"&Kanselleer"
+
+msgid "Input _Methods"
+msgstr "Invoer _Metodes"
+
+msgid "VIM - Search and Replace..."
+msgstr "VIM - Soek en Vervang..."
+
+msgid "VIM - Search..."
+msgstr "VIM - Soek..."
+
+msgid "Find what:"
+msgstr "Soek na:"
+
+msgid "Replace with:"
+msgstr "Vervang met:"
+
+#. whole word only button
+msgid "Match whole word only"
+msgstr "Tref slegs presiese woord"
+
+#. match case button
+msgid "Match case"
+msgstr "Tref kas"
+
+msgid "Direction"
+msgstr "Rigting"
+
+#. 'Up' and 'Down' buttons
+msgid "Up"
+msgstr "Op"
+
+msgid "Down"
+msgstr "Af"
+
+msgid "Find Next"
+msgstr "Vind volgende"
+
+msgid "Replace"
+msgstr "Vervang"
+
+msgid "Replace All"
+msgstr "Vervang alles"
+
+msgid "Vim: Received \"die\" request from session manager\n"
+msgstr "Vim: Het die \"die\" opdrag ontvang van sessiebestuurder\n"
+
+msgid "Vim: Main window unexpectedly destroyed\n"
+msgstr "Vim: Hoofvenster onverwags verwoes\n"
+
+msgid "Font Selection"
+msgstr "Fontkeuse"
+
+msgid "Used CUT_BUFFER0 instead of empty selection"
+msgstr "'CUT_BUFFER0' is gebruik in plaas van leë seleksie"
+
+msgid "Filter"
+msgstr "Filter"
+
+msgid "Directories"
+msgstr "Gidse"
+
+msgid "Help"
+msgstr "Hulp"
+
+msgid "Files"
+msgstr "Lêers"
+
+msgid "Selection"
+msgstr "Seleksie"
+
+msgid "Undo"
+msgstr "Herroep"
+
+msgid "E671: Cannot find window title \"%s\""
+msgstr "E671: Kan nie venster titel vind nie \"%s\""
+
+#, c-format
+msgid "E243: Argument not supported: \"-%s\"; Use the OLE version."
+msgstr "E243: Parameter nie bekend: \"-%s\"; Gebruik die OLE weergawe."
+
+msgid "E672: Unable to open window inside MDI application"
+msgstr "E672: Kon nie venster oopmaak binne 'n MDI toepassing nie"
+
+msgid "Find string (use '\\\\' to find a '\\')"
+msgstr "Vind string (gebruik '\\\\' om 'n '\\' te vind"
+
+msgid "Find & Replace (use '\\\\' to find a '\\')"
+msgstr "Vind & vervang string (gebruik '\\\\' om 'n '\\' te vind"
+
+msgid "Vim E458: Cannot allocate colormap entry, some colors may be incorrect"
+msgstr ""
+"Vim E458: Kan nie kleurkaart-inskrywing toeken nie, sommige kleure mag "
+"verkeerd wees"
+
+#, c-format
+msgid "E250: Fonts for the following charsets are missing in fontset %s:"
+msgstr ""
+"E250: Fonte vir die volgende karakterstelle ontbreek in fontversameling %s:"
+
+#, c-format
+msgid "E252: Fontset name: %s"
+msgstr "E252: Fontstel naam: %s"
+
+#, c-format
+msgid "Font '%s' is not fixed-width"
+msgstr "Font '%s' is nie 'n vaste-wydte font nie"
+
+#, c-format
+msgid "E253: Fontset name: %s\n"
+msgstr "E253: Fonstel naam: %s\n"
+
+#, c-format
+msgid "Font0: %s\n"
+msgstr "Font0: %s\n"
+
+#, c-format
+msgid "Font1: %s\n"
+msgstr "Font1: %s\n"
+
+msgid "Font%ld width is not twice that of font0\n"
+msgstr "Font%ld wydte is nie twee keer díe van font0 nie\n"
+
+#, c-format
+msgid "Font0 width: %ld\n"
+msgstr "Font0 wydte: %ld\n"
+
+#, c-format
+msgid ""
+"Font1 width: %ld\n"
+"\n"
+msgstr ""
+"Font1 wydte: %ld\n"
+"\n"
+
+msgid "E256: Hangul automata ERROR"
+msgstr "E256: Hangul outomatiserings FOUT"
+
+msgid "Add a new database"
+msgstr "Voeg 'n nuwe databasis by"
+
+msgid "Query for a pattern"
+msgstr "Soek vir 'n patroon"
+
+msgid "Show this message"
+msgstr "Wys hierdie boodskap"
+
+msgid "Kill a connection"
+msgstr "Sluit 'n verbinding"
+
+msgid "Reinit all connections"
+msgstr "Herstel alle verbindings"
+
+msgid "Show connections"
+msgstr "Wys verbindings"
+
+msgid "E560: Usage: cs[cope] %s"
+msgstr "E560: Gebruik: cs[cope] %s"
+
+msgid "This cscope command does not support splitting the window.\n"
+msgstr ""
+"Hierdie 'cscope' bevel ondersteun nie die splitsing van die venster nie.\n"
+
+msgid "E562: Usage: cstag <ident>"
+msgstr "E562: Gebruik: 'cstag <ident>'"
+
+msgid "E257: cstag: tag not found"
+msgstr "E257: 'cstag': etiket nie gevind nie"
+
+msgid "E563: stat(%s) error: %d"
+msgstr "E563: 'stat(%s)' fout: %d"
+
+msgid "E563: stat error"
+msgstr "E563: 'stat' fout"
+
+msgid "E564: %s is not a directory or a valid cscope database"
+msgstr "E564: %s is nie 'n gids of 'n geldige 'cscope' databasis nie"
+
+#, c-format
+msgid "Added cscope database %s"
+msgstr "'cscope' databasis %s bygevoeg"
+
+msgid "E262: error reading cscope connection %ld"
+msgstr "E262: 'cscope' verbinding %ld kon nie gelees word nie"
+
+msgid "E561: unknown cscope search type"
+msgstr "E561: onbekende 'cscope' soektipe"
+
+msgid "E566: Could not create cscope pipes"
+msgstr "E566: Kon nie 'cscope' pype skep nie"
+
+msgid "E622: Could not fork for cscope"
+msgstr "E622: Kon nie vurk vir 'cscope' nie"
+
+msgid "cs_create_connection exec failed"
+msgstr "'cs_create_connection' uitvoering het misluk"
+
+msgid "E623: Could not spawn cscope process"
+msgstr "E623: Kon nie 'cscope' proses skep nie"
+
+msgid "cs_create_connection: fdopen for to_fp failed"
+msgstr "'cs_create_connection': 'fdopen' vir 'to_fp' het misluk"
+
+msgid "cs_create_connection: fdopen for fr_fp failed"
+msgstr "'cs_create_connection': 'fdopen' vir 'fr_fp' het misluk"
+
+msgid "E567: no cscope connections"
+msgstr "E567: geen 'cscope' verbindings nie"
+
+#, c-format
+msgid "E259: no matches found for cscope query %s of %s"
+msgstr "E259: geen treffers gevind vir 'cscope' versoek %s van %s nie"
+
+#, c-format
+msgid "E469: invalid cscopequickfix flag %c for %c"
+msgstr "E469: ongeldige 'cscopequickfix' vlag %c vir %c"
+
+msgid "cscope commands:\n"
+msgstr "'cscope' bevele:\n"
+
+msgid "%-5s: %-30s (Usage: %s)"
+msgstr "%-5s: %-30s: (Gebruik: %s)"
+
+msgid "E625: cannot open cscope database: %s"
+msgstr "E625: Kon nie 'cscope' databasis oopmaak nie: %s"
+
+msgid "E626: cannot get cscope database information"
+msgstr "E626: kan nie 'cscope' databasisinligting kry nie"
+
+msgid "E568: duplicate cscope database not added"
+msgstr "E568: duplikaat 'cscope' databasis nie bygevoeg nie"
+
+msgid "E569: maximum number of cscope connections reached"
+msgstr "E569: maksimum aantal 'cscope' verbindings bereik"
+
+#, c-format
+msgid "E261: cscope connection %s not found"
+msgstr "E261: 'cscope' verbinding %s nie gevind nie"
+
+msgid "cscope connection %s closed"
+msgstr "'cscope' verbinding %s gesluit"
+
+#. should not reach here
+msgid "E570: fatal error in cs_manage_matches"
+msgstr "E570: fatale fout in 'cs_manage_matches'"
+
+msgid "Cscope tag: %s"
+msgstr "Cscope etiket: %s"
+
+msgid ""
+"\n"
+" # line"
+msgstr ""
+"\n"
+" # reël"
+
+msgid "filename / context / line\n"
+msgstr "lêernaam / konteks / reël\n"
+
+msgid "E609: Cscope error: %s"
+msgstr "E609: Cscope fout: %s"
+
+msgid "All cscope databases reset"
+msgstr "Alle 'cscope' databasisse herstel"
+
+msgid "no cscope connections\n"
+msgstr "geen 'cscope' verbindings nie\n"
+
+msgid " # pid database name prepend path\n"
+msgstr " # pid databasis naam gidsvoorvoegsel\n"
+
+msgid ""
+"E263: Sorry, this command is disabled, the Python library could not be "
+"loaded."
+msgstr ""
+"E263: Jammer, hierdie bevel is afgeskakel, die Python biblioteek lêer kon "
+"nie gelaai word nie."
+
+msgid "E659: Cannot invoke Python recursively"
+msgstr "E659: Kan nie Python rekursief roep nie"
+
+msgid "can't delete OutputObject attributes"
+msgstr "kan nie 'OutputObject' eienskappe skrap nie"
+
+msgid "softspace must be an integer"
+msgstr "'softspace' moet 'n heelgetal wees"
+
+msgid "invalid attribute"
+msgstr "ongeldige eienskap"
+
+msgid "writelines() requires list of strings"
+msgstr "'writelines()' benodig 'n lys van stringe"
+
+msgid "E264: Python: Error initialising I/O objects"
+msgstr "E264: Python: Kon nie I/O objekte inwy nie"
+
+# njj: net 'n voorstel ..
+msgid "invalid expression"
+msgstr "ongeldige uitdrukking"
+
+msgid "expressions disabled at compile time"
+msgstr "uitdrukkings afgeskakel tydens kompilering"
+
+msgid "attempt to refer to deleted buffer"
+msgstr "poging om na 'n geskrapte buffer te verwys"
+
+msgid "line number out of range"
+msgstr "reëlnommer buite omvang"
+
+#, c-format
+msgid "<buffer object (deleted) at %8lX>"
+msgstr "<buffervoorwerp (geskrap) by %8lX>"
+
+msgid "invalid mark name"
+msgstr "onbekende merknaam"
+
+msgid "no such buffer"
+msgstr "buffer bestaan nie"
+
+msgid "attempt to refer to deleted window"
+msgstr "poging om na geskrapte venster te verwys"
+
+msgid "readonly attribute"
+msgstr "leesalleen eienskap"
+
+msgid "cursor position outside buffer"
+msgstr "loperposisie buite buffer"
+
+#, c-format
+msgid "<window object (deleted) at %.8lX>"
+msgstr "<venster voorwerp (geskrap) by %.8lX>"
+
+#, c-format
+msgid "<window object (unknown) at %.8lX>"
+msgstr "<verwyder voorwerp (onbekend) by %.8lX>"
+
+#, c-format
+msgid "<window %d>"
+msgstr "<venster %d>"
+
+msgid "no such window"
+msgstr "geen sodanige venster nie"
+
+msgid "cannot save undo information"
+msgstr "kan nie herwin-inligting stoor nie"
+
+msgid "cannot delete line"
+msgstr "kan reël nie verwyder nie"
+
+msgid "cannot replace line"
+msgstr "kan reël nie vervang nie"
+
+msgid "cannot insert line"
+msgstr "kan reël nie byvoeg nie"
+
+msgid "string cannot contain newlines"
+msgstr "string kan nie 'newlines' bevat nie"
+
+msgid ""
+"E266: Sorry, this command is disabled, the Ruby library could not be loaded."
+msgstr ""
+"E266: Jammer, hierdie bevel is afgeskakel, die Ruby biblioteeklêer kon nie "
+"gelaai word nie."
+
+#, c-format
+msgid "E273: unknown longjmp status %d"
+msgstr "E273: Onbekende 'longjmp' status %d"
+
+msgid "Toggle implementation/definition"
+msgstr "Stel en herstel implimentasie/definisie"
+
+msgid "Show base class of"
+msgstr "Wys basisklas van"
+
+msgid "Show overridden member function"
+msgstr "Wys vervangde lidfunksie"
+
+msgid "Retrieve from file"
+msgstr "Gaan haal uit lêer"
+
+msgid "Retrieve from project"
+msgstr "Gaan haal uit projek"
+
+msgid "Retrieve from all projects"
+msgstr "Gaan haal uit alle projekte"
+
+msgid "Retrieve"
+msgstr "Gaan haal"
+
+msgid "Show source of"
+msgstr "Wys kode van"
+
+msgid "Find symbol"
+msgstr "Vind simbool"
+
+msgid "Browse class"
+msgstr "Kyk klas deur"
+
+msgid "Show class in hierarchy"
+msgstr "Wys klas in hiërargie"
+
+msgid "Show class in restricted hierarchy"
+msgstr "Wys klas in beperkte hiërargie"
+
+msgid "Xref refers to"
+msgstr "Xref verwys na"
+
+msgid "Xref referred by"
+msgstr "Xref verwys deur"
+
+msgid "Xref has a"
+msgstr "Xref het 'n"
+
+msgid "Xref used by"
+msgstr "Xref gebruik deur"
+
+msgid "Show docu of"
+msgstr "Wys 'docu' van"
+
+msgid "Generate docu for"
+msgstr "Genereer 'docu' vir"
+
+msgid ""
+"Cannot connect to SNiFF+. Check environment (sniffemacs must be found in "
+"$PATH).\n"
+msgstr ""
+"Kan nie 'n verbinding met 'SNiFF+' maak nie. Kyk of die omgewing reg is "
+"('sniffemacs' moet in '$PATH' gevind word).\n"
+
+msgid "E274: Sniff: Error during read. Disconnected"
+msgstr "E274: Sniff: Fout gedurende lees. Verbinding gebreek"
+
+msgid "SNiFF+ is currently "
+msgstr "SNiFF+ is tans"
+
+msgid "not "
+msgstr "nie "
+
+msgid "connected"
+msgstr "gekonnekteer"
+
+#, c-format
+msgid "E275: Unknown SNiFF+ request: %s"
+msgstr "E275: Onbekende SNiFF+ versoek: %s"
+
+msgid "E276: Error connecting to SNiFF+"
+msgstr "E276: Fout in konnekteer met SNiFF+"
+
+msgid "E278: SNiFF+ not connected"
+msgstr "E278: SNiFF+ is nie gekonnekteer nie"
+
+msgid "E279: Not a SNiFF+ buffer"
+msgstr "E279: Nie 'n SNiFF+ buffer nie"
+
+msgid "Sniff: Error during write. Disconnected"
+msgstr "Sniff: Fout gedurende stoor. Verbinding gebreek"
+
+msgid "invalid buffer number"
+msgstr "ongeldige buffernommer"
+
+msgid "not implemented yet"
+msgstr "nog nie geïmplementeer nie"
+
+msgid "unknown option"
+msgstr "onbekende opsie"
+
+#. ???
+msgid "cannot set line(s)"
+msgstr "kan nie reël(s) stel nie"
+
+msgid "mark not set"
+msgstr "merker nie gestel nie"
+
+#, c-format
+msgid "row %d column %d"
+msgstr "ry %d kolom %d"
+
+msgid "cannot insert/append line"
+msgstr "kan nie reël invoeg/aanlas nie"
+
+msgid "unknown flag: "
+msgstr "onbekende vlag: "
+
+msgid "unknown vimOption"
+msgstr "onbekende 'vimOption'"
+
+msgid "keyboard interrupt"
+msgstr "sleutelbordonderbreking"
+
+msgid "vim error"
+msgstr "vim fout"
+
+msgid "cannot create buffer/window command: object is being deleted"
+msgstr "kan nie buffer/venster bevel skep nie: voorwerp word geskrap"
+
+msgid ""
+"cannot register callback command: buffer/window is already being deleted"
+msgstr ""
+"kan nie terugroepbevel registreer nie: buffer/venster word alreeds geskrap"
+
+#. This should never happen. Famous last word?
+msgid ""
+"E280: TCL FATAL ERROR: reflist corrupt!? Please report this to vim-dev@vim."
+"org"
+msgstr ""
+"E280: TCL FATALE FOUT: verwlys korrup!? Rapporteer dit asb. aan <vim-dev@vim."
+"org>"
+
+msgid "cannot register callback command: buffer/window reference not found"
+msgstr ""
+"kan terugroepbevel nie registreer nie: buffer/vensterverwysing nie gevind nie"
+
+msgid ""
+"E571: Sorry, this command is disabled: the Tcl library could not be loaded."
+msgstr ""
+"E571: Jammer, hierdie bevel is afgeskakel, die Tcl biblioteek kon nie gelaai "
+"word nie."
+
+msgid ""
+"E281: TCL ERROR: exit code is not int!? Please report this to vim-dev@vim.org"
+msgstr ""
+"E281: TCL FOUT: verlaatkode is nie 'n 'int'!? Rapporteer dit asb. aan <vim-"
+"dev@vim.org>"
+
+msgid "cannot get line"
+msgstr "kan nie reël kry nie"
+
+msgid "Unable to register a command server name"
+msgstr "Kon nie bevelbediener naam registreer nie"
+
+msgid "E248: Failed to send command to the destination program"
+msgstr "E248: Het gefaal om bevel na doel program te stuur"
+
+msgid "E573: Invalid server id used: %s"
+msgstr "E573: Ongeldige bediener-id gebruik: %s"
+
+msgid "E251: VIM instance registry property is badly formed. Deleted!"
+msgstr "E251: VIM instansie register-kenmerk is swak gevorm. Geskrap!"
+
+msgid "Unknown option"
+msgstr "Onbekende opsie"
+
+msgid "Too many edit arguments"
+msgstr "Te veel redigeer-parameters"
+
+msgid "Argument missing after"
+msgstr "Parameter ontbreek na"
+
+msgid "Garbage after option"
+msgstr "Gemors na opsie"
+
+msgid "Too many \"+command\", \"-c command\" or \"--cmd command\" arguments"
+msgstr "Te veel \"+command\", \"-c command\" of \"--cmd command\" parameters"
+
+msgid "Invalid argument for"
+msgstr "Ongeldige parameter vir"
+
+msgid "This Vim was not compiled with the diff feature."
+msgstr "Hierdie Vim is nie gekompileer met 'diff' funksionaliteit nie."
+
+msgid "Attempt to open script file again: \""
+msgstr "Probeer weer om skriplêer oop te maak: \""
+
+msgid "Cannot open for reading: \""
+msgstr "Kan nie oopmaak om te lees nie: \""
+
+msgid "Cannot open for script output: \""
+msgstr "Kan nie oopmaak vir skrip-afvoer nie: \""
+
+#, c-format
+msgid "%d files to edit\n"
+msgstr "%d lêers om te bewerk\n"
+
+msgid "Vim: Warning: Output is not to a terminal\n"
+msgstr "Vim: Waarskuwing: Afvoer gaan nie na 'n terminaal nie\n"
+
+msgid "Vim: Warning: Input is not from a terminal\n"
+msgstr "Vim: Waarskuwing: Invoer kom nie vanaf 'n terminaal nie\n"
+
+#. just in case..
+msgid "pre-vimrc command line"
+msgstr "vóór-'vimrc' bevelreël"
+
+#, c-format
+msgid "E282: Cannot read from \"%s\""
+msgstr "E282: Kan nie lees uit \"%s\" nie"
+
+msgid ""
+"\n"
+"More info with: \"vim -h\"\n"
+msgstr ""
+"\n"
+"Meer inligting met: \"vim -h\"\n"
+
+msgid "[file ..] edit specified file(s)"
+msgstr "[lêer ..] bewerk lêer(s)"
+
+msgid "- read text from stdin"
+msgstr "- lees teks uit 'stdin'"
+
+msgid "-t tag edit file where tag is defined"
+msgstr "-t tag bewerk lêer waar etiket gedefinieer is"
+
+msgid "-q [errorfile] edit file with first error"
+msgstr "-q [foutlêer] bewerk lêer met eerste fout"
+
+msgid ""
+"\n"
+"\n"
+"Usage:"
+msgstr ""
+"\n"
+"\n"
+"Gebruik:"
+
+msgid " vim [arguments] "
+msgstr " vim [parameters] "
+
+msgid ""
+"\n"
+" or:"
+msgstr ""
+"\n"
+" of:"
+
+msgid ""
+"\n"
+"\n"
+"Arguments:\n"
+msgstr ""
+"\n"
+"\n"
+"Parameters:\n"
+
+msgid "--\t\t\tOnly file names after this"
+msgstr "--\t\t\tSlegs lêername hierna"
+
+msgid "--literal\t\tDon't expand wildcards"
+msgstr "--literal\t\tMoet nie plekhouers uitbrei nie"
+
+msgid "-register\t\tRegister this gvim for OLE"
+msgstr "-register\t\tRegistreer hierdie gvim vir OLE"
+
+msgid "-unregister\t\tUnregister gvim for OLE"
+msgstr "-unregister\t\tOnregistreer gvim vir OLE"
+
+msgid "-g\t\t\tRun using GUI (like \"gvim\")"
+msgstr "-g\t\t\tVoer uit met die GUI (soos \"gvim\")"
+
+msgid "-f or --nofork\tForeground: Don't fork when starting GUI"
+msgstr "-f of --nofork\tVoorgrond: Moenie vurk wanneer GUI begin nie"
+
+msgid "-v\t\t\tVi mode (like \"vi\")"
+msgstr "-v\t\t\tVi modus (soos \"vi\")"
+
+msgid "-e\t\t\tEx mode (like \"ex\")"
+msgstr "-e\t\t\tEx modus (soos \"ex\")"
+
+msgid "-s\t\t\tSilent (batch) mode (only for \"ex\")"
+msgstr "-s\t\t\tStil (bondel) modus (slegs vir \"ex\")"
+
+msgid "-d\t\t\tDiff mode (like \"vimdiff\")"
+msgstr "-d\t\t\tDiff modus (soos \"vimdiff\")"
+
+msgid "-y\t\t\tEasy mode (like \"evim\", modeless)"
+msgstr "-y\t\t\tEasy modus (soos \"evim\", modusloos)"
+
+msgid "-R\t\t\tReadonly mode (like \"view\")"
+msgstr "-R\t\t\tLeesalleen modus (soos \"view\")"
+
+msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
+msgstr "-Z\t\t\tBeperkte modus (soos \"rvim\")"
+
+msgid "-m\t\t\tModifications (writing files) not allowed"
+msgstr "-m\t\t\tVeranderings (skryf van lêers) nie toegelaat nie"
+
+msgid "-M\t\t\tModifications in text not allowed"
+msgstr "-M\t\t\tVeranderings aan teks nie toegelaat nie"
+
+msgid "-b\t\t\tBinary mode"
+msgstr "-b\t\t\tBinêre modus"
+
+msgid "-l\t\t\tLisp mode"
+msgstr "-l\t\t\tLisp modus"
+
+msgid "-C\t\t\tCompatible with Vi: 'compatible'"
+msgstr "-C\t\t\tVersoenbaar met Vi: 'compatible'"
+
+msgid "-N\t\t\tNot fully Vi compatible: 'nocompatible'"
+msgstr "-N\t\t\tNie ten volle Vi-versoenbaar nie: 'nocompatible'"
+
+msgid "-V[N]\t\tVerbose level"
+msgstr "-V[N]\t\tOmslagtigheidsgraad"
+
+msgid "-D\t\t\tDebugging mode"
+msgstr "-D\t\t\tOntfoutmodus"
+
+msgid "-n\t\t\tNo swap file, use memory only"
+msgstr "-n\t\t\tGeen ruillêer, gebruik slegs geheue"
+
+msgid "-r\t\t\tList swap files and exit"
+msgstr "-r\t\t\tLys ruillêers en verlaat vim"
+
+msgid "-r (with file name)\tRecover crashed session"
+msgstr "-r (met lêer naam)\tHerwin ineengestorte sessie"
+
+msgid "-L\t\t\tSame as -r"
+msgstr "-L\t\t\tSelfde as -r"
+
+msgid "-f\t\t\tDon't use newcli to open window"
+msgstr "-f\t\t\tMoet nie 'newcli' gebruik om venster oop te maak nie"
+
+msgid "-dev <device>\t\tUse <device> for I/O"
+msgstr "-dev <toestel>\t\tGebruik <toestel> vir I/O"
+
+msgid "-A\t\t\tStart in Arabic mode"
+msgstr "-A\t\t\tBegin in Arabiese modus"
+
+msgid "-H\t\t\tStart in Hebrew mode"
+msgstr "-H\t\t\tBegin in Hebreeuse modus"
+
+msgid "-F\t\t\tStart in Farsi mode"
+msgstr "-F\t\t\tBegin in Farsi modus"
+
+msgid "-T <terminal>\tSet terminal type to <terminal>"
+msgstr "-T <terminaal>\tStel terminaaltipe na <terminaal>"
+
+msgid "-u <vimrc>\t\tUse <vimrc> instead of any .vimrc"
+msgstr "-u <vimrc>\t\tGebruik <vimrc> in plaas van enige ander .vimrc"
+
+msgid "-U <gvimrc>\t\tUse <gvimrc> instead of any .gvimrc"
+msgstr "-U <gvimrc>\t\tGebruik <gvimrc> in plaas van enige .gvimrc"
+
+msgid "--noplugin\t\tDon't load plugin scripts"
+msgstr "--noplugin\t\tMoet nie inpropskripte laai nie"
+
+msgid "-o[N]\t\tOpen N windows (default: one for each file)"
+msgstr "-o[N]\t\tMaak N vensters oop (verstek: een vir elke lêer)"
+
+msgid "-O[N]\t\tLike -o but split vertically"
+msgstr "-O[N]\t\tSoos -o maar verdeel vertikaal"
+
+msgid "+\t\t\tStart at end of file"
+msgstr "+\t\t\tBegin by einde van lêer"
+
+msgid "+<lnum>\t\tStart at line <lnum>"
+msgstr "+<lnum>\t\tBegin by reël <lnum>"
+
+msgid "--cmd <command>\tExecute <command> before loading any vimrc file"
+msgstr "--cmd <bevel>\tVoer <bevel> uit voor enige .vimrc-lêer gelaai word"
+
+msgid "-c <command>\t\tExecute <command> after loading the first file"
+msgstr "-c <bevel>\t\tVoer <bevel> uit na eerste lêer gelaai is"
+
+msgid "-S <session>\t\tSource file <session> after loading the first file"
+msgstr ""
+"-S <sessie>\t\tVoer bevele in lêer <sessie> uit na eerste lêer gelaai is"
+
+msgid "-s <scriptin>\tRead Normal mode commands from file <scriptin>"
+msgstr "-s <skripin>\t\tLees Normale-modus bevele van lêer <skripin>"
+
+msgid "-w <scriptout>\tAppend all typed commands to file <scriptout>"
+msgstr "-w <skripuit>\tLas alle getikte bevele aan by lêer <skripuit>"
+
+msgid "-W <scriptout>\tWrite all typed commands to file <scriptout>"
+msgstr "-W <skripuit>\tSkryf alle getikte bevele na lêer <skripuit>"
+
+msgid "-x\t\t\tEdit encrypted files"
+msgstr "-x\t\t\tBewerk geënkripteerde lêers"
+
+msgid "-display <display>\tConnect vim to this particular X-server"
+msgstr "-display <display>\tKoppel vim aan hierdie X-bediener"
+
+msgid "-X\t\t\tDo not connect to X server"
+msgstr "-X\t\t\tMoet nie verbinding met X-bediener maak nie"
+
+msgid "--remote <files>\tEdit <files> in a Vim server if possible"
+msgstr "--remote <lêers>\tWysig die <lêers> in a Vim bediener indien moontlik"
+
+msgid "--remote-silent <files> Same, don't complain if there is no server"
+msgstr "--remote-silent <lêers> Dieselfde, moet nie kla as daar nie so 'n bediener is nie"
+
+msgid ""
+"--remote-wait <files> As --remote but wait for files to have been edited"
+msgstr ""
+"--remote-wait <lêers> Soos '--remote', maar wag vir lêers om gewysig te word"
+
+msgid ""
+"--remote-wait-silent <files> Same, don't complain if there is no server"
+msgstr ""
+"--remote-wait-silent <lêers> Dieselfde, moet nie kla as daar nie so 'n bediener is nie"
+
+msgid "--remote-send <keys>\tSend <keys> to a Vim server and exit"
+msgstr ""
+"--remote-send <sleutels>\tStuur <sleutels> na 'n Vim-bediener en verlaat"
+
+msgid "--remote-expr <expr>\tEvaluate <expr> in a Vim server and print result"
+msgstr ""
+"--remote-expr <expr>\tEvalueer <expr> in 'n Vim-bediener en druk resultaat"
+
+msgid "--serverlist\t\tList available Vim server names and exit"
+msgstr "--serverlist\t\tLys beskikbare Vim-bediener name en verlaat"
+
+msgid "--servername <name>\tSend to/become the Vim server <name>"
+msgstr "--servername <naam>\tStuur na/word die Vim-bediener <naam>"
+
+msgid "-i <viminfo>\t\tUse <viminfo> instead of .viminfo"
+msgstr "-i <viminfo>\t\tGebruik <viminfo> in plaas van .viminfo"
+
+msgid "-h or --help\tPrint Help (this message) and exit"
+msgstr "-h of --help\tSkryf Hulp (hierdie boodskap) en sluit"
+
+msgid "--version\t\tPrint version information and exit"
+msgstr "--version\t\tSkryf weergawe-inligting en sluit"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Motif version):\n"
+msgstr ""
+"\n"
+"Parameters deur gvim herken (Motif weergawe):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (neXtaw version):\n"
+msgstr ""
+"\n"
+"Parameters deur gvim herken (neXtaw weergawe):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Athena version):\n"
+msgstr ""
+"\n"
+"Parameters deur gvim herken (Athena weergawe):\n"
+
+msgid "-display <display>\tRun vim on <display>"
+msgstr "-display <display>\tVoer vim op <display> uit"
+
+msgid "-iconic\t\tStart vim iconified"
+msgstr "-iconic\t\tBegin vim as ikoon"
+
+msgid "-name <name>\t\tUse resource as if vim was <name>"
+msgstr "-name <name>\t\tGebruik hulpbron asof vim <name> was"
+
+msgid "\t\t\t (Unimplemented)\n"
+msgstr "\t\t\t (Nog nie geïmplementeer nie)\n"
+
+msgid "-background <color>\tUse <color> for the background (also: -bg)"
+msgstr "-background <kleur>\tGebruik <kleur> vir die agtergrond (ook: -bg)"
+
+msgid "-foreground <color>\tUse <color> for normal text (also: -fg)"
+msgstr "-voorgrond <kleur>\tGebruik <kleur> vir normale teks (ook: -fg)"
+
+msgid "-font <font>\t\tUse <font> for normal text (also: -fn)"
+msgstr "-font <font>\t\tGebruik <font> vir normale teks (ook -fn)"
+
+msgid "-boldfont <font>\tUse <font> for bold text"
+msgstr "­boldfont <font>\t Gebruik <font> vir vetletter teks"
+
+msgid "-italicfont <font>\tUse <font> for italic text"
+msgstr "-italicfont <font>\tGebruik <font> vir kursiewe teks"
+
+msgid "-geometry <geom>\tUse <geom> for initial geometry (also: -geom)"
+msgstr "-geometry <geom>\tGebruik <geom> vir aanvanklike geometrie"
+
+msgid "-borderwidth <width>\tUse a border width of <width> (also: -bw)"
+msgstr "-borderwidth <wydte>\tGebruik 'n grenswydte van <wydte> (ook: -bw)"
+
+msgid "-scrollbarwidth <width> Use a scrollbar width of <width> (also: -sw)"
+msgstr ""
+"-scrollbarwidth <wydte>\tGebruik 'n rolstaafwydte van <wydte> (ook: -sw>"
+
+msgid "-menuheight <height>\tUse a menu bar height of <height> (also: -mh)"
+msgstr ""
+"-menuheight <hoogte>\tGebruik a kieslysstaafhoogte van <hoogte> (ook: -mh)"
+
+msgid "-reverse\t\tUse reverse video (also: -rv)"
+msgstr "-reverse\t\tGebruik tru-video (ook: -rv)"
+
+msgid "+reverse\t\tDon't use reverse video (also: +rv)"
+msgstr "+reverse\t\tMoet nie tru-video gebruik nie (ook: +rv)"
+
+msgid "-xrm <resource>\tSet the specified resource"
+msgstr "-xrm <hulpbron>\tStel die gespesifiseerde hulpbron"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (RISC OS version):\n"
+msgstr ""
+"\n"
+"Parameters wat gvim verstaan (RISC OS weergawe):\n"
+
+msgid "--columns <number>\tInitial width of window in columns"
+msgstr "--columns <aantal>\tAanvanklike wydte van venster in kolomme"
+
+msgid "--rows <number>\tInitial height of window in rows"
+msgstr "--rows <aantal>\tAanvanklike hoogte van venster in rye"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (GTK+ version):\n"
+msgstr ""
+"\n"
+"Parameters wat gvim verstaan (GTK+ weergawe):\n"
+
+msgid "-display <display>\tRun vim on <display> (also: --display)"
+msgstr "-display <skerm>\tVoer vim op <skerm> uit: (ook --display)"
+
+msgid "--role <role>\tSet a unique role to identify the main window"
+msgstr "--role <rol>\tStel 'n unieke rol om die hoofvenster te identifiseer"
+
+msgid "--socketid <xid>\tOpen Vim inside another GTK widget"
+msgstr "--socketid <xid>\tMaak Vim in 'n ander GTK element oop"
+
+msgid "-P <parent title>\tOpen Vim inside parent application"
+msgstr "-P <ouer title>\tMaak Vim oop binne 'n ouer toepassing"
+
+msgid "No display"
+msgstr "Geen vertoonskerm"
+
+#. Failed to send, abort.
+msgid ": Send failed.\n"
+msgstr ": Stuur het gefaal.\n"
+
+#. Let vim start normally.
+msgid ": Send failed. Trying to execute locally\n"
+msgstr ": Stuur het gefaal. Probeer om lokaal uit te voer\n"
+
+#, c-format
+msgid "%d of %d edited"
+msgstr "%d van %d lêers bewerk"
+
+msgid "No display: Send expression failed.\n"
+msgstr "Geen vertoonskerm: Stuur van uitdrukking het gefaal.\n"
+
+msgid ": Send expression failed.\n"
+msgstr ": Stuur van uitdrukking het gefaal.\n"
+
+msgid "No marks set"
+msgstr "Geen merkers gestel nie"
+
+#, c-format
+msgid "E283: No marks matching \"%s\""
+msgstr "E283: Geen merkers pas op \"%s\" nie"
+
+#. Highlight title
+msgid ""
+"\n"
+"mark line col file/text"
+msgstr ""
+"\n"
+"merk reël kol lêer/teks"
+
+#. Highlight title
+msgid ""
+"\n"
+" jump line col file/text"
+msgstr ""
+"\n"
+" spring reël kol lêer/teks"
+
+#. Highlight title
+msgid ""
+"\n"
+"change line col text"
+msgstr ""
+"\n"
+"verander reël kol teks"
+
+#, c-format
+msgid ""
+"\n"
+"# File marks:\n"
+msgstr ""
+"\n"
+"# Lêermerkers:\n"
+
+#. Write the jumplist with -'
+#, c-format
+msgid ""
+"\n"
+"# Jumplist (newest first):\n"
+msgstr ""
+"\n"
+"# Springlys (nuutste eerste):\n"
+
+#, c-format
+msgid ""
+"\n"
+"# History of marks within files (newest to oldest):\n"
+msgstr ""
+"\n"
+"# Geskiedenis van merkers in lêers (nuutste tot oudste):\n"
+
+msgid "Missing '>'"
+msgstr "Ontbrekende '>'"
+
+msgid "E543: Not a valid codepage"
+msgstr "E543: Nie 'n geldige kodeblad nie"
+
+msgid "E284: Cannot set IC values"
+msgstr "E284: Kan nie IC waardes stel nie"
+
+msgid "E285: Failed to create input context"
+msgstr "E285: Gefaal met die skep van invoerkonteks"
+
+msgid "E286: Failed to open input method"
+msgstr "E286: Gefaal om invoermetode oop te maak"
+
+msgid "E287: Warning: Could not set destroy callback to IM"
+msgstr "E287: Waarskuwing: Kon nie uitwis-terugroep na IM stel nie"
+
+msgid "E288: input method doesn't support any style"
+msgstr "E288: invoermetode ondersteun geen styl nie"
+
+msgid "E289: input method doesn't support my preedit type"
+msgstr "E289: invoermetode ondersteun nie my voor-bewerking tipe nie"
+
+msgid "E290: over-the-spot style requires fontset"
+msgstr "E290: oor-die-plek styl vereis fontstel"
+
+msgid "E291: Your GTK+ is older than 1.2.3. Status area disabled"
+msgstr "E291: Jou GTK+ is ouer as 1.2.3. Statusarea afgeskakel"
+
+msgid "E292: Input Method Server is not running"
+msgstr "E292: Invoermetodebediener voer nie uit nie"
+
+msgid "E293: block was not locked"
+msgstr "E293: blok was nie gesluit nie"
+
+msgid "E294: Seek error in swap file read"
+msgstr "E294: Soekfout in lees van ruillêer"
+
+msgid "E295: Read error in swap file"
+msgstr "E295: Leesfout in ruillêer"
+
+msgid "E296: Seek error in swap file write"
+msgstr "E296: Soekfout in skryf van ruillêer"
+
+msgid "E297: Write error in swap file"
+msgstr "E297: Skryffout in ruillêer"
+
+msgid "E300: Swap file already exists (symlink attack?)"
+msgstr "E300: Ruillêer bestaan alreeds! ('symlink' probleem?)"
+
+msgid "E298: Didn't get block nr 0?"
+msgstr "E298: Het nie blok no 0 gekry nie?"
+
+msgid "E298: Didn't get block nr 1?"
+msgstr "E298: Het nie blok no 1 gekry nie?"
+
+msgid "E298: Didn't get block nr 2?"
+msgstr "E298: Het nie blok no 2 gekry nie?"
+
+#. could not (re)open the swap file, what can we do????
+msgid "E301: Oops, lost the swap file!!!"
+msgstr "E301: Hiert, die ruillêer is weg!!!"
+
+msgid "E302: Could not rename swap file"
+msgstr "E302: Kon nie ruillêer vernoem nie"
+
+#, c-format
+msgid "E303: Unable to open swap file for \"%s\", recovery impossible"
+msgstr "E303: Kon nie ruillêer oopmaak vir \"%s\" nie, herwinning onmoontlik"
+
+msgid "E304: ml_timestamp: Didn't get block 0??"
+msgstr "E304: 'ml_timestamp': Het nie blok 0 gekry nie??"
+
+#, c-format
+msgid "E305: No swap file found for %s"
+msgstr "E305: Geen ruillêer gevind vir %s nie"
+
+msgid "Enter number of swap file to use (0 to quit): "
+msgstr "Tik die nommer van die ruillêer om te gebruik (0 om te stop)"
+
+#, c-format
+msgid "E306: Cannot open %s"
+msgstr "E306: Kan %s nie oopmaak nie"
+
+msgid "Unable to read block 0 from "
+msgstr "Kan nie blok 0 lees vanaf "
+
+msgid ""
+"\n"
+"Maybe no changes were made or Vim did not update the swap file."
+msgstr ""
+"\n"
+"Vim het die ruillêer nie opgedateer nie. Dalk was niks verander nie."
+
+msgid " cannot be used with this version of Vim.\n"
+msgstr " kan nie gebruik word met hierdie weergawe van Vim nie.\n"
+
+msgid "Use Vim version 3.0.\n"
+msgstr "Gebruik Vim weergawe 3.0.\n"
+
+#, c-format
+msgid "E307: %s does not look like a Vim swap file"
+msgstr "E307: %s lyk nie soos 'n Vim ruillêer nie"
+
+msgid " cannot be used on this computer.\n"
+msgstr " kan nie gebruik word op hierdie rekenaar nie.\n"
+
+msgid "The file was created on "
+msgstr "Die lêer is geskep op "
+
+msgid ""
+",\n"
+"or the file has been damaged."
+msgstr ""
+",\n"
+"of die lêer is beskadig."
+
+#, c-format
+msgid "Using swap file \"%s\""
+msgstr "Gebruik ruillêer \"%s\""
+
+#, c-format
+msgid "Original file \"%s\""
+msgstr "Oorspronklike lêer \"%s\""
+
+msgid "E308: Warning: Original file may have been changed"
+msgstr "E308: Waarskuwing: Oorspronklike lêer is dalk gewysig"
+
+#, c-format
+msgid "E309: Unable to read block 1 from %s"
+msgstr "E309: Kan nie block 1 lees van %s"
+
+msgid "???MANY LINES MISSING"
+msgstr "???BAIE REËLS WEG"
+
+msgid "???LINE COUNT WRONG"
+msgstr "???REËLTELLING FOUTIEF"
+
+msgid "???EMPTY BLOCK"
+msgstr "???LEË BLOK"
+
+msgid "???LINES MISSING"
+msgstr "???REËLS WEG"
+
+#, c-format
+msgid "E310: Block 1 ID wrong (%s not a .swp file?)"
+msgstr "E310: Blok 1 se ID is foutief (%s nie 'n .swp lêer nie?)"
+
+msgid "???BLOCK MISSING"
+msgstr "???BLOK WEG"
+
+msgid "??? from here until ???END lines may be messed up"
+msgstr "??? van hier tot ???END mag reëls deurmekaar wees"
+
+msgid "??? from here until ???END lines may have been inserted/deleted"
+msgstr "??? van hier tot ???END mag daar reëls ingevoeg/geskrap wees"
+
+msgid "???END"
+msgstr "???END"
+
+msgid "E311: Recovery Interrupted"
+msgstr "E311: Herwinning onderbreek"
+
+msgid ""
+"E312: Errors detected while recovering; look for lines starting with ???"
+msgstr ""
+"E312: Foute raakgesien gedurende herwinning; soek vir reëls wat begin met ???"
+
+msgid "See \":help E312\" for more information."
+msgstr "Sien \":help E312\" vir meer inligting."
+
+msgid "Recovery completed. You should check if everything is OK."
+msgstr "Herwinning is klaar. Kyk of alles reg is."
+
+msgid ""
+"\n"
+"(You might want to write out this file under another name\n"
+msgstr ""
+"\n"
+"(Jy wil dalk die lêer stoor onder 'n ander naam\n"
+
+msgid "and run diff with the original file to check for changes)\n"
+msgstr "en dit \"diff\" teen die oorspronklike lêer om wysigings te soek)\n"
+
+msgid ""
+"Delete the .swp file afterwards.\n"
+"\n"
+msgstr ""
+"Verwyder die .swp-lêer na die tyd.\n"
+"\n"
+
+#. use msg() to start the scrolling properly
+msgid "Swap files found:"
+msgstr "Ruillêers gevind:"
+
+msgid " In current directory:\n"
+msgstr " In huidige gids:\n"
+
+msgid " Using specified name:\n"
+msgstr " Wat gespesifiseerde naam gebruik:\n"
+
+msgid " In directory "
+msgstr " In gids "
+
+msgid " -- none --\n"
+msgstr " -- geen --\n"
+
+msgid " owned by: "
+msgstr " eienaar: "
+
+msgid " dated: "
+msgstr " gedateer: "
+
+msgid " dated: "
+msgstr " gedateer: "
+
+msgid " [from Vim version 3.0]"
+msgstr " [van Vim weergawe 3.0]"
+
+msgid " [does not look like a Vim swap file]"
+msgstr " [lyk nie soos 'n Vim ruillêer nie]"
+
+msgid " file name: "
+msgstr " lêernaam: "
+
+msgid ""
+"\n"
+" modified: "
+msgstr ""
+"\n"
+" gewysig: "
+
+msgid "YES"
+msgstr "JA"
+
+msgid "no"
+msgstr "nee"
+
+msgid ""
+"\n"
+" user name: "
+msgstr ""
+"\n"
+" gebruikersnaam: "
+
+msgid " host name: "
+msgstr " gasheernaam: "
+
+msgid ""
+"\n"
+" host name: "
+msgstr ""
+"\n"
+" gasheernaam: "
+
+msgid ""
+"\n"
+" process ID: "
+msgstr ""
+"\n"
+" proses ID: "
+
+msgid " (still running)"
+msgstr " (nog steeds aan die uitvoer)"
+
+msgid ""
+"\n"
+" [not usable with this version of Vim]"
+msgstr ""
+"\n"
+" [nie bruikbaar met hierdie weergawe van Vim nie]"
+
+msgid ""
+"\n"
+" [not usable on this computer]"
+msgstr ""
+"\n"
+" [nie bruikbaar op hierdie rekenaar nie]"
+
+msgid " [cannot be read]"
+msgstr " [kan nie gelees word nie]"
+
+msgid " [cannot be opened]"
+msgstr " [kan nie oopgemaak word nie]"
+
+msgid "E313: Cannot preserve, there is no swap file"
+msgstr "E313: Kan nie bewaar nie, daar is geen ruillêer nie"
+
+msgid "File preserved"
+msgstr "Lêer bewaar"
+
+msgid "E314: Preserve failed"
+msgstr "E314: Kon nie bewaar nie"
+
+#, c-format
+msgid "E315: ml_get: invalid lnum: %ld"
+msgstr "E315: 'ml_get': ongeldige 'lnum': %ld"
+
+#, c-format
+msgid "E316: ml_get: cannot find line %ld"
+msgstr "E316: 'ml_get': kan reël %ld nie vind nie"
+
+msgid "E317: pointer block id wrong 3"
+msgstr "E317: wyser blok id verkeerd 3"
+
+msgid "stack_idx should be 0"
+msgstr "'stack_idx' moet 0 wees"
+
+msgid "E318: Updated too many blocks?"
+msgstr "E318: Te veel blokke opgedateer?"
+
+msgid "E317: pointer block id wrong 4"
+msgstr "E317: wyser blok id verkeerd 4"
+
+msgid "deleted block 1?"
+msgstr "verwyder blok 1?"
+
+#, c-format
+msgid "E320: Cannot find line %ld"
+msgstr "E320: Kan nie reël %ld vind nie"
+
+msgid "E317: pointer block id wrong"
+msgstr "E317: wyser blok id verkeerd"
+
+msgid "pe_line_count is zero"
+msgstr "'pe_line_count' is nul"
+
+#, c-format
+msgid "E322: line number out of range: %ld past the end"
+msgstr "E322: reëlnommer buite perke: %ld verby die einde"
+
+#, c-format
+msgid "E323: line count wrong in block %ld"
+msgstr "E323: reëltelling mag verkeerd wees in blok %ld"
+
+msgid "Stack size increases"
+msgstr "Stapel grootte verhoog"
+
+msgid "E317: pointer block id wrong 2"
+msgstr "E317: wyser blok id verkeerd 2"
+
+msgid "E325: ATTENTION"
+msgstr "E325: LET OP"
+
+msgid ""
+"\n"
+"Found a swap file by the name \""
+msgstr ""
+"\n"
+"Het 'n ruillêer gevind met die naam \""
+
+msgid "While opening file \""
+msgstr "Tydens oopmaak van lêer \""
+
+msgid " NEWER than swap file!\n"
+msgstr " NUWER as die ruillêer!\n"
+
+#. Some of these messages are long to allow translation to
+#. * other languages.
+msgid ""
+"\n"
+"(1) Another program may be editing the same file.\n"
+" If this is the case, be careful not to end up with two\n"
+" different instances of the same file when making changes.\n"
+msgstr ""
+"\n"
+"(1) 'n Ander program mag besig wees met hierdie lêer.\n"
+" Indien wel, pas op om nie met twee verskillende weergawes\n"
+" van dieselfde lêer te sit wanneer veranderinge gemaak word nie.\n"
+
+msgid " Quit, or continue with caution.\n"
+msgstr " Stop, of gaan versigtig voort.\n"
+
+msgid ""
+"\n"
+"(2) An edit session for this file crashed.\n"
+msgstr ""
+"\n"
+"(2) 'n Bewerkingsessie van hierdie lêer het ineengestort.\n"
+
+msgid " If this is the case, use \":recover\" or \"vim -r "
+msgstr " Indien wel, gebruik \":recover\" of \"vim -r"
+
+msgid ""
+"\"\n"
+" to recover the changes (see \":help recovery\").\n"
+msgstr ""
+"\"\n"
+" om die veranderinge te herwin (sien \":help recovery\").\n"
+
+msgid " If you did this already, delete the swap file \""
+msgstr " Indien jy dit alreeds gedoen het, verwyder die ruillêer \""
+
+msgid ""
+"\"\n"
+" to avoid this message.\n"
+msgstr ""
+"\"\n"
+" om hierdie boodskap te vermy.\n"
+
+msgid "Swap file \""
+msgstr "Ruillêer \""
+
+msgid "\" already exists!"
+msgstr "\" bestaan alreeds!"
+
+msgid "VIM - ATTENTION"
+msgstr "VIM - LET OP"
+
+msgid "Swap file already exists!"
+msgstr "Ruillêer bestaan alreeds!"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"&Maak as lees-alleen oop\n"
+"&Bewerk in elk geval\n"
+"&Herwin\n"
+"&Verlaat\n"
+"&Stop"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Quit\n"
+"&Abort\n"
+"&Delete it"
+msgstr ""
+"&Maak as lees-alleen oop\n"
+"&Bewerk in elk geval\n"
+"&Herwin\n"
+"&Verlaat\n"
+"&Stop\n"
+"S&krap dit"
+
+msgid "E326: Too many swap files found"
+msgstr "E326: Te veel ruillêers gevind"
+
+msgid "E327: Part of menu-item path is not sub-menu"
+msgstr "E327: Deel van kieslys-item pad is nie 'n sub-kieslys nie"
+
+msgid "E328: Menu only exists in another mode"
+msgstr "E328: Kieslys bestaan slegs in 'n ander modus"
+
+msgid "E329: No menu of that name"
+msgstr "E329: Geen kieslys met daardie naam nie"
+
+msgid "E330: Menu path must not lead to a sub-menu"
+msgstr "E330: Kieslyspad moenie lei na 'n sub-kieslys nie"
+
+msgid "E331: Must not add menu items directly to menu bar"
+msgstr "E331: Moenie kieslysitems direk by kieslysstaaf voeg nie"
+
+msgid "E332: Separator cannot be part of a menu path"
+msgstr "E332: Verdeler kan nie deel wees van kieslyspad nie"
+
+#. Now we have found the matching menu, and we list the mappings
+#. Highlight title
+msgid ""
+"\n"
+"--- Menus ---"
+msgstr ""
+"\n"
+"--- Kieslyste ---"
+
+msgid "Tear off this menu"
+msgstr "Skeur die kieslys af"
+
+msgid "E333: Menu path must lead to a menu item"
+msgstr "E333: Kieslyspad moet lei na 'n kieslysitem"
+
+#, c-format
+msgid "E334: Menu not found: %s"
+msgstr "E334: Kieslys nie gevind nie: %s"
+
+#, c-format
+msgid "E335: Menu not defined for %s mode"
+msgstr "E335: Kieslys nie gedefinieer vir %s modus nie"
+
+msgid "E336: Menu path must lead to a sub-menu"
+msgstr "E336: Kieslyspad moet lei na 'n sub-kieslys"
+
+msgid "E337: Menu not found - check menu names"
+msgstr "E337: Kieslys nie gevind nie - maak seker oor die kieslys name"
+
+#, c-format
+msgid "Error detected while processing %s:"
+msgstr "Fout ontdek tydens verwerking van %s: "
+
+#, c-format
+msgid "line %4ld:"
+msgstr "reël %4ld:"
+
+msgid "[string too long]"
+msgstr "[string te lank]"
+
+msgid "Messages maintainer: Bram Moolenaar <Bram@vim.org>"
+msgstr "Boodskappe onderhouers: Danie Roux en Jean Jordaan <droux@tuks.co.za>"
+
+msgid "Interrupt: "
+msgstr "Onderbreek: "
+
+msgid "Hit ENTER to continue"
+msgstr "Druk ENTER om voort te gaan"
+
+msgid "Hit ENTER or type command to continue"
+msgstr "Druk ENTER of tik 'n bevel om voort te gaan"
+
+msgid "-- More --"
+msgstr "-- Meer --"
+
+msgid " (RET/BS: line, SPACE/b: page, d/u: half page, q: quit)"
+msgstr " (RET/BS: reël, SPACE/b: bladsy, d/u: halwe bladsy, q: los dit"
+
+msgid " (RET: line, SPACE: page, d: half page, q: quit)"
+msgstr " (RET: reël, SPACE: bladsy, d: halwe bladsy, q: los dit"
+
+msgid "Question"
+msgstr "Vraag"
+
+msgid ""
+"&Yes\n"
+"&No"
+msgstr ""
+"&Ja\n"
+"&Nee"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"Save &All\n"
+"&Discard All\n"
+"&Cancel"
+msgstr ""
+"&Ja\n"
+"&Nee\n"
+"Stoor &alles\n"
+"&Gooi alles weg\n"
+"&Kanselleer"
+
+msgid "Save File dialog"
+msgstr "Stoor Lêer dialooghokkie"
+
+msgid "Open File dialog"
+msgstr "Maak lêer oop dialooghokkie"
+
+#. TODO: non-GUI file selector here
+msgid "E338: Sorry, no file browser in console mode"
+msgstr "E338: Jammer, lêerblaaier nie beskikbaar in konsole-modus nie"
+
+msgid "W10: Warning: Changing a readonly file"
+msgstr "W10: Waarskuwing: Jy wysig aan 'n leesalleen lêer"
+
+msgid "1 more line"
+msgstr "1 reël meer"
+
+msgid "1 line less"
+msgstr "1 reël minder"
+
+#, c-format
+msgid "%ld more lines"
+msgstr "%ld meer reëls"
+
+#, c-format
+msgid "%ld fewer lines"
+msgstr "%ld minder reëls"
+
+msgid " (Interrupted)"
+msgstr " (Onderbreek)"
+
+msgid "Vim: preserving files...\n"
+msgstr "Vim: bewaar lêers...\n"
+
+#. close all memfiles, without deleting
+msgid "Vim: Finished.\n"
+msgstr "Vim: Klaar.\n"
+
+#, c-format
+msgid "ERROR: "
+msgstr "FOUT: "
+
+#, c-format
+msgid ""
+"\n"
+"[bytes] total alloc-freed %lu-%lu, in use %lu, peak use %lu\n"
+msgstr ""
+"\n"
+"[grepe] totaal 'alloc'-vrygelaat %lu-%lu, in gebruik %lu, piekgebruik %lu\n"
+
+#, c-format
+msgid ""
+"[calls] total re/malloc()'s %lu, total free()'s %lu\n"
+"\n"
+msgstr ""
+"[roepe] totaal re/malloc()'s %lu, totale free()'s %lu\n"
+"\n"
+
+msgid "E340: Line is becoming too long"
+msgstr "E340: Rëel word te lank"
+
+#, c-format
+msgid "E341: Internal error: lalloc(%ld, )"
+msgstr "E341: Interne fout: 'lalloc(%ld, )'"
+
+#, c-format
+msgid "E342: Out of memory! (allocating %lu bytes)"
+msgstr "E342: Geheue is op! (ken %lu grepe toe)"
+
+#, c-format
+msgid "Calling shell to execute: \"%s\""
+msgstr "Roep dop om uit te voer: \"%s\""
+
+msgid "E545: Missing colon"
+msgstr "E545: Ontbrekende dubbelpunt"
+
+msgid "E546: Illegal mode"
+msgstr "E546: Ongeldige modus"
+
+msgid "E547: Illegal mouseshape"
+msgstr "E547: Ongeldige muisvorm"
+
+msgid "E548: digit expected"
+msgstr "E548: syfer verwag"
+
+msgid "E549: Illegal percentage"
+msgstr "E549: Ongeldige persentasie"
+
+msgid "Enter encryption key: "
+msgstr "Voer enkripsie-sleutel in: "
+
+msgid "Enter same key again: "
+msgstr "Voer die sleutel weer in: "
+
+msgid "Keys don't match!"
+msgstr "Sleutels verskil!"
+
+#, c-format
+msgid ""
+"E343: Invalid path: '**[number]' must be at the end of the path or be "
+"followed by '%s'."
+msgstr ""
+"E343: Ongeldige pad: '**[nommer]' moet aan die einde van 'n pad wees of "
+"gevolg wees deur %s'."
+
+#, c-format
+msgid "E344: Can't find directory \"%s\" in cdpath"
+msgstr "E344: Kan nie gids \"%s\" in 'cdpath' vind nie"
+
+#, c-format
+msgid "E345: Can't find file \"%s\" in path"
+msgstr "E345: Kan lêer \"%s\" nie vind in pad nie"
+
+#, c-format
+msgid "E346: No more directory \"%s\" found in cdpath"
+msgstr "E346: Geen gids \"%s\" meer gevind in 'cdpath' nie"
+
+#, c-format
+msgid "E347: No more file \"%s\" found in path"
+msgstr "E347: Geen lêer \"%s\" meer gevind in pad nie"
+
+msgid "E550: Missing colon"
+msgstr "E550: Ontbrekende dubbelpunt"
+
+msgid "E551: Illegal component"
+msgstr "E551: Ongeldige komponent"
+
+msgid "E552: digit expected"
+msgstr "E552: syfer verwag"
+
+#. Get here when the server can't be found.
+msgid "Cannot connect to Netbeans #2"
+msgstr "Kan nie aan Netbeans #2 koppel nie"
+
+msgid "Cannot connect to Netbeans"
+msgstr "Kan nie aan Netbeans koppel nie"
+
+#, c-format
+msgid "E668: Wrong access mode for NetBeans connection info file: \"%s\""
+msgstr "E668: Verkeerde toegangsmodue vir NetBeans konneksie inligtingslêer: \"%s\""
+
+msgid "read from Netbeans socket"
+msgstr "lees vanaf Netbeans 'socket'"
+
+msgid "E658: NetBeans connection lost for buffer %ld"
+msgstr "E658: NetBeans konneksie vir buffer %ld verloor"
+
+msgid "Warning: terminal cannot highlight"
+msgstr "Waarskuwing: terminaal kan nie teks uitlig nie"
+
+msgid "E348: No string under cursor"
+msgstr "E348: Geen string onder loper nie"
+
+msgid "E349: No identifier under cursor"
+msgstr "E349: Geen identifiseerder onder loper nie"
+
+msgid "E352: Cannot erase folds with current 'foldmethod'"
+msgstr "E352: Kan nie voue verwyder met huidige 'foldmethod' nie"
+
+msgid "E664: changelist is empty"
+msgstr "E664: 'changelist' is leeg"
+
+msgid "E662: At start of changelist"
+msgstr "E662: By die begin van die veranderingslys"
+
+msgid "E663: At end of changelist"
+msgstr "E663: By die einde van die veranderingslys"
+
+msgid "Type :quit<Enter> to exit Vim"
+msgstr "Tik :quit<Enter> om Vim te verlaat"
+
+# Het te doen met < en >
+#, c-format
+msgid "1 line %sed 1 time"
+msgstr "1 reël 1 keer ge-%s"
+
+#, c-format
+msgid "1 line %sed %d times"
+msgstr "1 reël ge-%s %d keer"
+
+#, c-format
+msgid "%ld lines %sed 1 time"
+msgstr "%ld reëls 1 keer ge-%s"
+
+#, c-format
+msgid "%ld lines %sed %d times"
+msgstr "%ld reëls ge-%s %d keer"
+
+#, c-format
+msgid "%ld lines to indent... "
+msgstr "%ld reëls om in te keep..."
+
+msgid "1 line indented "
+msgstr "1 reël ingekeep "
+
+#, c-format
+msgid "%ld lines indented "
+msgstr "%ld reëls ingekeep "
+
+#. must display the prompt
+msgid "cannot yank; delete anyway"
+msgstr "kan nie pluk nie: verwyder in elk geval"
+
+msgid "1 line changed"
+msgstr "1 reël verander"
+
+msgid "%ld lines changed"
+msgstr "%ld reëls verander"
+
+#, c-format
+msgid "freeing %ld lines"
+msgstr "laat %ld reëls gaan"
+
+msgid "1 line yanked"
+msgstr "1 reël gepluk"
+
+#, c-format
+msgid "%ld lines yanked"
+msgstr "%ld reëls gepluk"
+
+#, c-format
+msgid "E353: Nothing in register %s"
+msgstr "E353: Niks in register %s nie"
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Registers ---"
+msgstr ""
+"\n"
+"--- Registers ---"
+
+msgid "Illegal register name"
+msgstr "Ongeldige registernaam"
+
+#, c-format
+msgid ""
+"\n"
+"# Registers:\n"
+msgstr ""
+"\n"
+"# Registers:\n"
+
+msgid "E574: Unknown register type %d"
+msgstr "E574: Onbekende registertipe %d"
+
+#, c-format
+msgid "E354: Invalid register name: '%s'"
+msgstr "E354: Ongeldige registernaam: '%s'"
+
+#, c-format
+msgid "%ld Cols; "
+msgstr "%ld Kolomme; "
+
+#, c-format
+msgid "Selected %s%ld of %ld Lines; %ld of %ld Words; %ld of %ld Bytes"
+msgstr "%s%ld van %ld reëls gekies; %ld van %ld Woorde; %ld van %ld Grepe"
+
+# njj: Karakters kan meerdere grepe wees, sien ':h multibyte'
+#, c-format
+msgid "Col %s of %s; Line %ld of %ld; Word %ld of %ld; Byte %ld of %ld"
+msgstr "Kol %s van %s; Reël %ld van %ld; Woord %ld van %ld; Greep %ld van %ld"
+
+#, c-format
+msgid "(+%ld for BOM)"
+msgstr "(+%ld vir 'BOM')"
+
+msgid "%<%f%h%m%=Page %N"
+msgstr "%<%f%h%m%=Bladsy %N"
+
+msgid "Thanks for flying Vim"
+msgstr "Dankie dat jy vlieg met Vim"
+
+msgid "E518: Unknown option"
+msgstr "E518: Onbekende opsie"
+
+msgid "E519: Option not supported"
+msgstr "E519: Opsie is nie ondersteun nie"
+
+msgid "E520: Not allowed in a modeline"
+msgstr "E520: Nie toegelaat in 'n moduslyn nie"
+
+msgid ""
+"\n"
+"\tLast set from "
+msgstr ""
+"\n"
+"\tLaas gestel vanaf "
+
+msgid "E521: Number required after ="
+msgstr "E521: Nommer vereis na ="
+
+msgid "E522: Not found in termcap"
+msgstr "E522: Nie gevind in 'termcap' nie"
+
+msgid "E539: Illegal character <%s>"
+msgstr "E539: Ongeldige karakter <%s>"
+
+msgid "E529: Cannot set 'term' to empty string"
+msgstr "E529: Kan nie 'term' stel na leë string nie"
+
+msgid "E530: Cannot change term in GUI"
+msgstr "E530: Kan nie 'term' verander in GUI nie"
+
+msgid "E531: Use \":gui\" to start the GUI"
+msgstr "E531: Gebruik \":gui\" om die GUI te begin"
+
+msgid "E589: 'backupext' and 'patchmode' are equal"
+msgstr "E589: 'backupext' en 'patchmode' is dieselfde"
+
+msgid "E617: Cannot be changed in the GTK+ 2 GUI"
+msgstr "E617: Kan nie 'term' verander in die GTK+ 2 GUI nie"
+
+msgid "E524: Missing colon"
+msgstr "E524: Ontbrekende dubbelpunt"
+
+msgid "E525: Zero length string"
+msgstr "E525: Nul-lengte string"
+
+msgid "E526: Missing number after <%s>"
+msgstr "E526: Ontbrekende nommer na <%s>"
+
+msgid "E527: Missing comma"
+msgstr "E527: Ontbrekende komma"
+
+msgid "E528: Must specify a ' value"
+msgstr "E528: Moet 'n ' waarde spesifiseer"
+
+msgid "E595: contains unprintable or wide character"
+msgstr "E595: bevat 'n ondrukbare of wye karakter"
+
+msgid "E596: Invalid font(s)"
+msgstr "E596: Ongeldige font(e)"
+
+msgid "E597: can't select fontset"
+msgstr "E597: kan nie fontstel kies nie"
+
+msgid "E598: Invalid fontset"
+msgstr "E598: Ongeldige fontstel"
+
+msgid "E533: can't select wide font"
+msgstr "E533: kan nie wye font kies nie"
+
+msgid "E534: Invalid wide font"
+msgstr "E534: Ongeldige wye font"
+
+msgid "E535: Illegal character after <%c>"
+msgstr "E535: Ongeldige karakter na <%c>"
+
+msgid "E536: comma required"
+msgstr "E536: komma benodig"
+
+msgid "E537: 'commentstring' must be empty or contain %s"
+msgstr "E537: 'commentstring' moet leeg wees of %s bevat"
+
+msgid "E538: No mouse support"
+msgstr "E538: Geen muisondersteuning nie"
+
+msgid "E540: Unclosed expression sequence"
+msgstr "E540: Onvoltooide uitdrukkingreeks"
+
+msgid "E541: too many items"
+msgstr "E541: te veel items"
+
+msgid "E542: unbalanced groups"
+msgstr "E542: ongebalanseerde groepe"
+
+msgid "E590: A preview window already exists"
+msgstr "E590: Daar bestaan reeds 'n voorskouvenster"
+
+msgid "W17: Arabic requires UTF-8, do ':set encoding=utf-8'"
+msgstr "W17: Arabies benodig UTF-8, doen ':set encoding=utf-8'"
+
+msgid "E593: Need at least %d lines"
+msgstr "E593: Benodig ten minste %d reëls"
+
+msgid "E594: Need at least %d columns"
+msgstr "E594: Benodig ten minste %d kolomme"
+
+#, c-format
+msgid "E355: Unknown option: %s"
+msgstr "E355: Onbekende opsie: %s"
+
+msgid ""
+"\n"
+"--- Terminal codes ---"
+msgstr ""
+"\n"
+"--- Terminaal kodes ---"
+
+msgid ""
+"\n"
+"--- Global option values ---"
+msgstr ""
+"\n"
+"--- Globale opsie waardes ---"
+
+msgid ""
+"\n"
+"--- Local option values ---"
+msgstr ""
+"\n"
+"--- Lokale opsie waardes ---"
+
+msgid ""
+"\n"
+"--- Options ---"
+msgstr ""
+"\n"
+"--- Opsies ---"
+
+msgid "E356: get_varp ERROR"
+msgstr "E356: 'get_varp' FOUT"
+
+#, c-format
+msgid "E357: 'langmap': Matching character missing for %s"
+msgstr "E357: 'langmap': Passende karakter ontbreek vir %s"
+
+#, c-format
+msgid "E358: 'langmap': Extra characters after semicolon: %s"
+msgstr "E358: 'langmap: Ekstra karakters na kommapunt: %s"
+
+msgid "cannot open "
+msgstr "kan nie oopmaak nie "
+
+msgid "VIM: Can't open window!\n"
+msgstr "VIM: Kan nie venster oopmaak nie!\n"
+
+msgid "Need Amigados version 2.04 or later\n"
+msgstr "Benodig Amigados weergawe 2.04 of later\n"
+
+#, c-format
+msgid "Need %s version %ld\n"
+msgstr "Benodig %s weergawe %ld\n"
+
+msgid "Cannot open NIL:\n"
+msgstr "Kan nie NIL: oopmaak nie\n"
+
+msgid "Cannot create "
+msgstr "Kan nie skep nie: "
+
+#, c-format
+msgid "Vim exiting with %d\n"
+msgstr "Vim stop met %d\n"
+
+msgid "cannot change console mode ?!\n"
+msgstr "kan konsole-modus nie verander nie ?!\n"
+
+msgid "mch_get_shellsize: not a console??\n"
+msgstr "'mch_get_shellsize': nie 'n konsole nie??\n"
+
+#. if Vim opened a window: Executing a shell may cause crashes
+msgid "E360: Cannot execute shell with -f option"
+msgstr "E360: Kan nie dop met -f opsie uitvoer nie"
+
+msgid "Cannot execute "
+msgstr "Kan nie uitvoer nie "
+
+msgid "shell "
+msgstr "dop "
+
+msgid " returned\n"
+msgstr " teruggekeer\n"
+
+msgid "ANCHOR_BUF_SIZE too small."
+msgstr "'ANCHOR_BUF_SIZE' is te klein"
+
+msgid "I/O ERROR"
+msgstr "I/O FOUT"
+
+msgid "...(truncated)"
+msgstr "...(afgekap)"
+
+msgid "'columns' is not 80, cannot execute external commands"
+msgstr "'columns' is nie 80 nie, kan nie eksterne bevele uitvoer nie"
+
+msgid "E237: Printer selection failed"
+msgstr "E237: Drukker-seleksie het gefaal"
+
+#, c-format
+msgid "to %s on %s"
+msgstr "na %s op %s"
+
+msgid "E613: Unknown printer font: %s"
+msgstr "E613: Onbekende drukker font: %s"
+
+#, c-format
+msgid "E238: Print error: %s"
+msgstr "E238: Drukfout: %s"
+
+msgid "Unknown"
+msgstr "Onbekend"
+
+#, c-format
+msgid "Printing '%s'"
+msgstr "Druk nou '%s'"
+
+#, c-format
+msgid "E244: Illegal charset name \"%s\" in font name \"%s\""
+msgstr "E244: Ongeldige karakterstelnaam \"%s\" in fontnaam \"%s\""
+
+#, c-format
+msgid "E245: Illegal char '%c' in font name \"%s\""
+msgstr "E245: Ongeldige karakter '%c' in fontnaam \"%s\""
+
+msgid "Vim: Double signal, exiting\n"
+msgstr "Vim: Dubbel sein, staak\n"
+
+#, c-format
+msgid "Vim: Caught deadly signal %s\n"
+msgstr "Vim: Het dodelike sein %s gevang\n"
+
+#, c-format
+msgid "Vim: Caught deadly signal\n"
+msgstr "Vim: Het dodelike sein gevang\n"
+
+#, c-format
+msgid "Opening the X display took %ld msec"
+msgstr "Om die X-vertoonskerm oop te maak het %ld msek gevat"
+
+msgid ""
+"\n"
+"Vim: Got X error\n"
+msgstr ""
+"\n"
+"Vim: Het X fout ontvang\n"
+
+msgid "Testing the X display failed"
+msgstr "Toetsing van die X-vertoonskerm het gefaal"
+
+msgid "Opening the X display timed out"
+msgstr "Oopmaak van die X-vertoonskerm het uitgetel"
+
+msgid ""
+"\n"
+"Cannot execute shell "
+msgstr ""
+"\n"
+"Kan nie dop uitvoer nie "
+
+msgid ""
+"\n"
+"Cannot execute shell sh\n"
+msgstr ""
+"\n"
+"Kan nie dop 'sh' uitvoer nie\n"
+
+msgid ""
+"\n"
+"shell returned "
+msgstr ""
+"\n"
+"dop lewer "
+
+msgid ""
+"\n"
+"Cannot create pipes\n"
+msgstr ""
+"\n"
+"Kan nie pype skep nie\n"
+
+msgid ""
+"\n"
+"Cannot fork\n"
+msgstr ""
+"\n"
+"Kan nie vurk nie\n"
+
+msgid ""
+"\n"
+"Command terminated\n"
+msgstr ""
+"\n"
+"Bevel beëindig\n"
+
+msgid "XSMP lost ICE connection"
+msgstr "XSMP het ICE konneksie verloor"
+
+msgid "Opening the X display failed"
+msgstr "Oopmaak van die X vertoonskerm het gefaal"
+
+msgid "XSMP handling save-yourself request"
+msgstr "XSMP hanteer 'save-yourself' versoek"
+
+msgid "XSMP opening connection"
+msgstr "XSMP maak nou konneksie oop"
+
+msgid "XSMP ICE connection watch failed"
+msgstr "XSMP ICE konneksie beloer het gefaal"
+
+#, c-format
+msgid "XSMP SmcOpenConnection failed: %s"
+msgstr "XSMP 'SmcOpenConnection' het gefaal: %s"
+
+msgid "At line"
+msgstr "By reël"
+
+msgid "Could not allocate memory for command line."
+msgstr "Kan nie geheue toeken vir bevelreël nie"
+
+msgid "VIM Error"
+msgstr "VIM Fout"
+
+msgid "Could not load vim32.dll!"
+msgstr "Kon nie 'vim32.dll' laai nie!"
+
+msgid "Could not fix up function pointers to the DLL!"
+msgstr "Kon nie funksiewysers na die DLL opstel nie!"
+
+#, c-format
+msgid "shell returned %d"
+msgstr "dop het %d gelewer"
+
+#, c-format
+msgid "Vim: Caught %s event\n"
+msgstr "Vim: Het %s gebeurtenis gevang\n"
+
+msgid "close"
+msgstr "maak toe"
+
+msgid "logoff"
+msgstr "teken uit"
+
+msgid "shutdown"
+msgstr "sit af"
+
+msgid "E371: Command not found"
+msgstr "E371: Bevel nie gevind nie"
+
+msgid ""
+"VIMRUN.EXE not found in your $PATH.\n"
+"External commands will not pause after completion.\n"
+"See :help win32-vimrun for more information."
+msgstr ""
+"'VIMRUN.EXE' nie gevind in '$PATH' nie.\n"
+"Eksterne opdragte sal nie wag na voltooiing nie\n"
+"Sien ':help win32-vimrun' vir meer inligting."
+
+msgid "Vim Warning"
+msgstr "Vim Waarskuwing"
+
+#, c-format
+msgid "E372: Too many %%%c in format string"
+msgstr "E372: Te veel %%%c in formaatstring"
+
+#, c-format
+msgid "E373: Unexpected %%%c in format string"
+msgstr "E373: Onverwagte %%%c in formaatstring"
+
+msgid "E374: Missing ] in format string"
+msgstr "E374: Ontbrekende ] in formaatstring"
+
+#, c-format
+msgid "E375: Unsupported %%%c in format string"
+msgstr "E375: Ongesteunde %%%c in formaatstring"
+
+#, c-format
+msgid "E376: Invalid %%%c in format string prefix"
+msgstr "E376: Ongeldige %%%c in formaatstringvoorvoegsel"
+
+#, c-format
+msgid "E377: Invalid %%%c in format string"
+msgstr "E377: Ongeldige %%%c in formaatstring"
+
+msgid "E378: 'errorformat' contains no pattern"
+msgstr "E378: 'errorformat' bevat geen patroon nie"
+
+msgid "E379: Missing or empty directory name"
+msgstr "E379: Ontbrekende of leë gidsnaam"
+
+msgid "E553: No more items"
+msgstr "E553: Geen items meer nie"
+
+#, c-format
+msgid "(%d of %d)%s%s: "
+msgstr "(%d van %d)%s%s: "
+
+msgid " (line deleted)"
+msgstr " (reël verwyder)"
+
+msgid "E380: At bottom of quickfix stack"
+msgstr "E380: Onder aan 'quickfix' stapel"
+
+msgid "E381: At top of quickfix stack"
+msgstr "E381: Bo aan 'quickfix' stapel"
+
+#, c-format
+msgid "error list %d of %d; %d errors"
+msgstr "foutelys %d van %d; %d foute"
+
+msgid "E382: Cannot write, 'buftype' option is set"
+msgstr "E382: Kan nie skryf nie, 'buftype' opsie is aan"
+
+msgid "E369: invalid item in %s%%[]"
+msgstr "E369: ongeldige item in %s%%[]"
+
+msgid "E339: Pattern too long"
+msgstr "E339: Patroon te lank"
+
+msgid "E50: Too many \\z("
+msgstr "E50: Te veel \\z("
+
+msgid "E51: Too many %s("
+msgstr "E51: Te veel %s("
+
+msgid "E52: Unmatched \\z("
+msgstr "E52: Onpaar \\z("
+
+msgid "E53: Unmatched %s%%("
+msgstr "E53: Onpaar %s%%("
+
+msgid "E54: Unmatched %s("
+msgstr "E54: Onpaar %s("
+
+msgid "E55: Unmatched %s)"
+msgstr "E55: Onpaar %s)"
+
+msgid "E56: %s* operand could be empty"
+msgstr "E56: %s* operand mag leeg wees"
+
+msgid "E57: %s+ operand could be empty"
+msgstr "E57: %s+ operand mag leeg wees"
+
+msgid "E59: invalid character after %s@"
+msgstr "E59: ongeldige karakter na %s@"
+
+msgid "E58: %s{ operand could be empty"
+msgstr "E58: %s{ operand mag leeg wees"
+
+msgid "E60: Too many complex %s{...}s"
+msgstr "E60: Te veel komplekse %s{...}ies"
+
+#, c-format
+msgid "E61: Nested %s*"
+msgstr "E61: Geneste %s*"
+
+#, c-format
+msgid "E62: Nested %s%c"
+msgstr "E62: Geneste %s%c"
+
+msgid "E63: invalid use of \\_"
+msgstr "E63: ongeldige gebruik van \\_"
+
+#, c-format
+msgid "E64: %s%c follows nothing"
+msgstr "E64: %s%c volg niks"
+
+msgid "E65: Illegal back reference"
+msgstr "E65: Ongeldige tru-verwysing"
+
+msgid "E66: \\z( not allowed here"
+msgstr "E66: \\z( nie hier toegelaat nie"
+
+msgid "E67: \\z1 - \\z9 not allowed here"
+msgstr "E67: \\z1 e.a. nie hier toegelaat nie"
+
+msgid "E68: Invalid character after \\z"
+msgstr "E68: ongeldige karakter na \\z"
+
+msgid "E69: Missing ] after %s%%["
+msgstr "E69: Ontbrekende ] na %s%%["
+
+msgid "E70: Empty %s%%[]"
+msgstr "E70: Leë %s%%[]"
+
+msgid "E71: Invalid character after %s%%"
+msgstr "E71: Ongeldige karakter na %s%%"
+
+msgid "E554: Syntax error in %s{...}"
+msgstr "E554: Sintaksfout in %s{...}"
+
+msgid "E361: Crash intercepted; regexp too complex?"
+msgstr "E361: Ineenstorting onderskep. Patroon te kompleks?"
+
+msgid "E363: pattern caused out-of-stack error"
+msgstr "E363: patroon het lëe-stapel fout veroorsaak"
+
+msgid "External submatches:\n"
+msgstr "Eksterne subtreffers:\n"
+
+#, c-format
+msgid "+--%3ld lines folded "
+msgstr "+--%3ld reëls gevou "
+
+msgid " VREPLACE"
+msgstr " VVERVANG"
+
+msgid " REPLACE"
+msgstr " VERVANG"
+
+msgid " REVERSE"
+msgstr " OMKEER"
+
+msgid " INSERT"
+msgstr " INVOEG"
+
+msgid " (insert)"
+msgstr " (invoeg)"
+
+msgid " (replace)"
+msgstr " (vervang)"
+
+msgid " (vreplace)"
+msgstr " (vvervang)"
+
+msgid " Hebrew"
+msgstr " Hebreeus"
+
+msgid " Arabic"
+msgstr " Arabies"
+
+msgid " (lang)"
+msgstr " (taal)"
+
+msgid " (paste)"
+msgstr " (plak)"
+
+msgid " VISUAL"
+msgstr " VISUELE"
+
+msgid " VISUAL LINE"
+msgstr " VISUELE REËL"
+
+msgid " VISUAL BLOCK"
+msgstr " VISUELE BLOK"
+
+msgid " SELECT"
+msgstr " KIES"
+
+msgid " SELECT LINE"
+msgstr " KIES REËL"
+
+msgid " SELECT BLOCK"
+msgstr " KIES BLOK"
+
+msgid "recording"
+msgstr "besig om op te neem"
+
+msgid "search hit TOP, continuing at BOTTOM"
+msgstr "soektog het BO getref, gaan voort van ONDER af"
+
+msgid "search hit BOTTOM, continuing at TOP"
+msgstr "soektog het ONDER getref, gaan voort van BO af"
+
+#, c-format
+msgid "E383: Invalid search string: %s"
+msgstr "E383: Ongeldige soekstring: %s"
+
+#, c-format
+msgid "E384: search hit TOP without match for: %s"
+msgstr "E384: soektog het BO getref sonder treffer vir: %s"
+
+#, c-format
+msgid "E385: search hit BOTTOM without match for: %s"
+msgstr "E385: soektog het ONDER getref sonder treffer vir: %s"
+
+msgid "E386: Expected '?' or '/' after ';'"
+msgstr "E386: Verwag '?' of '/' na ';'"
+
+msgid " (includes previously listed match)"
+msgstr " (sluit in vorige gelyste treffer)"
+
+#. cursor at status line
+msgid "--- Included files "
+msgstr "--- Ingeslote lêers"
+
+msgid "not found "
+msgstr "nie gevind nie "
+
+msgid "in path ---\n"
+msgstr "in pad ---\n"
+
+msgid " (Already listed)"
+msgstr " (Alreeds gelys)"
+
+msgid " NOT FOUND"
+msgstr " NIE GEVIND NIE"
+
+#, c-format
+msgid "Scanning included file: %s"
+msgstr "Deursoek ingeslote lêer: %s"
+
+msgid "E387: Match is on current line"
+msgstr "E387: Treffer is op huidige reël"
+
+msgid "All included files were found"
+msgstr "Alle ingeslote lêers is gevind"
+
+msgid "No included files"
+msgstr "Geen ingeslote lêers nie"
+
+msgid "E388: Couldn't find definition"
+msgstr "E388: Kon definisie nie vind nie"
+
+msgid "E389: Couldn't find pattern"
+msgstr "E389: Kon patroon nie vind nie"
+
+#, c-format
+msgid "E390: Illegal argument: %s"
+msgstr "E390: Ongeldige parameter: %s"
+
+#, c-format
+msgid "E391: No such syntax cluster: %s"
+msgstr "E391: Geen sodanige sintakskluster nie: %s"
+
+msgid "No Syntax items defined for this buffer"
+msgstr "Geen Sintaks-items gedefinieer vir hierdie buffer nie"
+
+msgid "syncing on C-style comments"
+msgstr "sinchroniseer met C-styl kommentaar"
+
+msgid "no syncing"
+msgstr "geen sinchronisering"
+
+msgid "syncing starts "
+msgstr "sinchronisasie begin "
+
+msgid " lines before top line"
+msgstr " reëls voor boonste lyn"
+
+msgid ""
+"\n"
+"--- Syntax sync items ---"
+msgstr ""
+"\n"
+"--- Sintaks sync items ---"
+
+msgid ""
+"\n"
+"syncing on items"
+msgstr ""
+"\n"
+"sinchronisering met items"
+
+msgid ""
+"\n"
+"--- Syntax items ---"
+msgstr ""
+"\n"
+"--- Sintaks items ---"
+
+#, c-format
+msgid "E392: No such syntax cluster: %s"
+msgstr "E392: Geen sodanige sintakskluster nie: %s"
+
+msgid "minimal "
+msgstr "minimaal "
+
+msgid "maximal "
+msgstr "maksimaal "
+
+msgid "; match "
+msgstr "; treffer "
+
+msgid " line breaks"
+msgstr " reël breuke"
+
+msgid "E393: group[t]here not accepted here"
+msgstr "E393: 'group[t]here' nie hier aanvaar nie"
+
+#, c-format
+msgid "E394: Didn't find region item for %s"
+msgstr "E394: Kon nie omgewingsitem vind vir %s nie"
+
+msgid "E395: contains argument not accepted here"
+msgstr "E395: bevat parameters nie hier aanvaar nie"
+
+msgid "E396: containedin argument not accepted here"
+msgstr "E396: 'containedin' parameter nie hier aanvaar nie"
+
+msgid "E397: Filename required"
+msgstr "E397: Lêernaam benodig"
+
+#, c-format
+msgid "E398: Missing '=': %s"
+msgstr "E398: Ontbrekende '=': %s"
+
+#, c-format
+msgid "E399: Not enough arguments: syntax region %s"
+msgstr "E399: Nie genoeg parameters nie: sintaksomgewing %s"
+
+msgid "E400: No cluster specified"
+msgstr "E400: Geen kluster gespesifiseer nie"
+
+#, c-format
+msgid "E401: Pattern delimiter not found: %s"
+msgstr "E401: Patroonbegrenser nie gevind nie: %s"
+
+#, c-format
+msgid "E402: Garbage after pattern: %s"
+msgstr "E402: Gemors na patroon: %s"
+
+msgid "E403: syntax sync: line continuations pattern specified twice"
+msgstr "E403: sintaks sync: reëlvoortgaanpatroon twee keer gespesifiseer"
+
+#, c-format
+msgid "E404: Illegal arguments: %s"
+msgstr "E404: Ongeldige parameters: %s"
+
+#, c-format
+msgid "E405: Missing equal sign: %s"
+msgstr "E405: Ontbrekende gelykaanteken: %s"
+
+#, c-format
+msgid "E406: Empty argument: %s"
+msgstr "E406: Leë parameter: %s"
+
+#, c-format
+msgid "E407: %s not allowed here"
+msgstr "E407: %s nie toegelaat hier nie"
+
+#, c-format
+msgid "E408: %s must be first in contains list"
+msgstr "E408: %s moet vóór in 'contains' lys wees"
+
+#, c-format
+msgid "E409: Unknown group name: %s"
+msgstr "E409: Onbekende groepnaam: %s"
+
+#, c-format
+msgid "E410: Invalid :syntax subcommand: %s"
+msgstr "E410: Ongeldige :syntax subbevel %s"
+
+msgid "E679: recursive loop loading syncolor.vim"
+msgstr "E679: rekursiewe lus gedurende laai van syncolor.vim"
+
+#, c-format
+msgid "E411: highlight group not found: %s"
+msgstr "E411: uitliggroep nie gevind nie: %s"
+
+#, c-format
+msgid "E412: Not enough arguments: \":highlight link %s\""
+msgstr "E412: Te min parameters: \":highlight link %s\""
+
+#, c-format
+msgid "E413: Too many arguments: \":highlight link %s\""
+msgstr "E413: Te veel parameters: \":highlight link %s\""
+
+msgid "E414: group has settings, highlight link ignored"
+msgstr ""
+"E414: groep het instellings, uitligskakel ('highlight link') geïgnoreer"
+
+#, c-format
+msgid "E415: unexpected equal sign: %s"
+msgstr "E415: onverwagte gelykaanteken: %s"
+
+#, c-format
+msgid "E416: missing equal sign: %s"
+msgstr "E416: ontbrekende gelykaanteken: %s"
+
+#, c-format
+msgid "E417: missing argument: %s"
+msgstr "E417: ontbrekende parameter: %s"
+
+#, c-format
+msgid "E418: Illegal value: %s"
+msgstr "E418: Ongeldige waarde: %s"
+
+msgid "E419: FG color unknown"
+msgstr "E419: FG kleur onbekend"
+
+msgid "E420: BG color unknown"
+msgstr "E420: BG kleur onbekend"
+
+#, c-format
+msgid "E421: Color name or number not recognized: %s"
+msgstr "E421: Kleurnaam of -nommer nie herken nie: %s"
+
+#, c-format
+msgid "E422: terminal code too long: %s"
+msgstr "E422: terminaalkode te lank: %s"
+
+#, c-format
+msgid "E423: Illegal argument: %s"
+msgstr "E423: Ongeldige parameter: %s"
+
+msgid "E424: Too many different highlighting attributes in use"
+msgstr "E424: Te veel verskillende uitlig-eienskappe in gebruik"
+
+msgid "E669: Unprintable character in group name"
+msgstr "E669: Onvertoonbare karakter in groepnaam"
+
+#. This is an error, but since there previously was no check only
+#. * give a warning.
+msgid "W18: Invalid character in group name"
+msgstr "W18: Ongeldige karakter groepnaam"
+
+msgid "E555: at bottom of tag stack"
+msgstr "E555: onderaan etiketstapel"
+
+msgid "E556: at top of tag stack"
+msgstr "E556: bo-aan etiketstapel"
+
+msgid "E425: Cannot go before first matching tag"
+msgstr "E425: Kan nie vóór eerste etiket-treffer gaan nie"
+
+#, c-format
+msgid "E426: tag not found: %s"
+msgstr "E426: etiket nie gevind nie: %s"
+
+msgid " # pri kind tag"
+msgstr " # pri tipe etiket"
+
+msgid "file\n"
+msgstr "lêer\n"
+
+#.
+#. * Ask to select a tag from the list.
+#. * When using ":silent" assume that <CR> was entered.
+#.
+msgid "Enter nr of choice (<CR> to abort): "
+msgstr "Sleutel nommer van keuse in (<CR> om te stop): "
+
+msgid "E427: There is only one matching tag"
+msgstr "E427: Daar is slegs een etiket-treffer"
+
+msgid "E428: Cannot go beyond last matching tag"
+msgstr "E428: Kan nie verby laaste etiket-treffer gaan nie"
+
+#, c-format
+msgid "File \"%s\" does not exist"
+msgstr "Lêer \"%s\" bestaan nie"
+
+#. Give an indication of the number of matching tags
+#, c-format
+msgid "tag %d of %d%s"
+msgstr "etiket %d van %d%s"
+
+msgid " or more"
+msgstr " of meer"
+
+msgid " Using tag with different case!"
+msgstr " Gaan etiket met ander kas gebruik!"
+
+#, c-format
+msgid "E429: File \"%s\" does not exist"
+msgstr "E429: Lêer \"%s\" bestaan nie"
+
+#. Highlight title
+msgid ""
+"\n"
+" # TO tag FROM line in file/text"
+msgstr ""
+"\n"
+" # NA etiket VAN reël in lêer/teks"
+
+#, c-format
+msgid "Searching tags file %s"
+msgstr "Deursoek etiketlêer %s"
+
+#, c-format
+msgid "E430: Tag file path truncated for %s\n"
+msgstr "E430: Etiketlêergids afgekap vir %s\n"
+
+#, c-format
+msgid "E431: Format error in tags file \"%s\""
+msgstr "E431: Formaatfout in etiketlêer \"%s\""
+
+#, c-format
+msgid "Before byte %ld"
+msgstr "Voor greep %ld"
+
+#, c-format
+msgid "E432: Tags file not sorted: %s"
+msgstr "E432: Etiketlêer ongesorteer: %s"
+
+#. never opened any tags file
+msgid "E433: No tags file"
+msgstr "E433: Geen etiketlêer nie"
+
+msgid "E434: Can't find tag pattern"
+msgstr "E434: Kan nie etiketpatroon vind nie"
+
+msgid "E435: Couldn't find tag, just guessing!"
+msgstr "E435: Kon nie etiket vind nie, ek raai maar!"
+
+msgid "' not known. Available builtin terminals are:"
+msgstr "' onbekend. Beskikbare ingeboude terminale is:"
+
+msgid "defaulting to '"
+msgstr "gebruik verstek '"
+
+msgid "E557: Cannot open termcap file"
+msgstr "E557: Kan nie 'termcap'-lêer oopmaak nie"
+
+msgid "E558: Terminal entry not found in terminfo"
+msgstr "E558: Terminaalinskrywing nie in 'terminfo' gevind nie"
+
+msgid "E559: Terminal entry not found in termcap"
+msgstr "E559: Terminaalinskrywing nie in 'termcap' gevind nie"
+
+#, c-format
+msgid "E436: No \"%s\" entry in termcap"
+msgstr "E436: Geen \"%s\" inskrywing in termcap nie"
+
+msgid "E437: terminal capability \"cm\" required"
+msgstr "E437: terminaalvermoë \"cm\" vereis"
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Terminal keys ---"
+msgstr ""
+"\n"
+"--- Terminaal sleutels ---"
+
+msgid "new shell started\n"
+msgstr "nuwe dop begin\n"
+
+msgid "Vim: Error reading input, exiting...\n"
+msgstr "Vim: Fout met lees van invoer, verlaat...\n"
+
+#. must display the prompt
+msgid "No undo possible; continue anyway"
+msgstr "Geen herstel moontlik; gaan in elk geval voort"
+
+msgid "E438: u_undo: line numbers wrong"
+msgstr "E438: u_undo: reëlnommers foutief"
+
+msgid "1 change"
+msgstr "1 verandering"
+
+#, c-format
+msgid "%ld changes"
+msgstr "%ld veranderinge"
+
+msgid "E439: undo list corrupt"
+msgstr "E439: herstellys korrup"
+
+msgid "E440: undo line missing"
+msgstr "E440: herstelreël ontbreek"
+
+#. Only MS VC 4.1 and earlier can do Win32s
+msgid ""
+"\n"
+"MS-Windows 16/32-bit GUI version"
+msgstr ""
+"\n"
+"MS-Windows 16/32-bis GUI weergawe"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit GUI version"
+msgstr ""
+"\n"
+"MS-Windows 32-bis GUI version"
+
+msgid " in Win32s mode"
+msgstr " in Win32s modus"
+
+msgid " with OLE support"
+msgstr " met OLE ondersteuning"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit console version"
+msgstr ""
+"\n"
+"MS-Windows 32-bis konsole weergawe"
+
+msgid ""
+"\n"
+"MS-Windows 16-bit version"
+msgstr ""
+"\n"
+"MS-Windows 16-bis weergawe"
+
+msgid ""
+"\n"
+"32-bit MS-DOS version"
+msgstr ""
+"\n"
+"32-bis MS-DOS weergawe"
+
+msgid ""
+"\n"
+"16-bit MS-DOS version"
+msgstr ""
+"\n"
+"16-bis MS-DOS weergawe"
+
+msgid ""
+"\n"
+"MacOS X (unix) version"
+msgstr ""
+"\n"
+"MacOS X (unix) weergawe"
+
+msgid ""
+"\n"
+"MacOS X version"
+msgstr ""
+"\n"
+"MacOS X weergawe"
+
+msgid ""
+"\n"
+"MacOS version"
+msgstr ""
+"\n"
+"MacOS weergawe"
+
+msgid ""
+"\n"
+"RISC OS version"
+msgstr ""
+"\n"
+"RISC OS weergawe"
+
+msgid ""
+"\n"
+"Included patches: "
+msgstr ""
+"\n"
+"Ingeslote laslappies:"
+
+msgid "Modified by "
+msgstr "Gewysig deur "
+
+msgid ""
+"\n"
+"Compiled "
+msgstr ""
+"\n"
+"Gekompileer op "
+
+msgid "by "
+msgstr "deur "
+
+msgid ""
+"\n"
+"Huge version "
+msgstr ""
+"\n"
+"Enorme weergawe "
+
+msgid ""
+"\n"
+"Big version "
+msgstr ""
+"\n"
+"Groot weergawe "
+
+msgid ""
+"\n"
+"Normal version "
+msgstr ""
+"\n"
+"Normale weergawe "
+
+msgid ""
+"\n"
+"Small version "
+msgstr ""
+"\n"
+"Klein weergawe "
+
+msgid ""
+"\n"
+"Tiny version "
+msgstr ""
+"\n"
+"Piepklein weergawe "
+
+msgid "without GUI."
+msgstr "sonder GUI."
+
+msgid "with GTK2-GNOME GUI."
+msgstr "met GTK2-GNOME GUI."
+
+msgid "with GTK-GNOME GUI."
+msgstr "met GTK-GNOME GUI."
+
+msgid "with GTK2 GUI."
+msgstr "met GTK2 GUI"
+
+msgid "with GTK GUI."
+msgstr "met GTK GUI"
+
+msgid "with X11-Motif GUI."
+msgstr "met X11-Motif GUI."
+
+msgid "with X11-neXtaw GUI."
+msgstr "met X11-neXtaw GUI"
+
+msgid "with X11-Athena GUI."
+msgstr "met X11-Athena GUI"
+
+msgid "with BeOS GUI."
+msgstr "met BeOS GUI"
+
+msgid "with Photon GUI."
+msgstr "met Photon GUI."
+
+msgid "with GUI."
+msgstr "met GUI."
+
+msgid "with Carbon GUI."
+msgstr "met Carbon GUI."
+
+msgid "with Cocoa GUI."
+msgstr "met Cocoa GUI."
+
+msgid "with (classic) GUI."
+msgstr "met (klassieke) GUI."
+
+msgid " Features included (+) or not (-):\n"
+msgstr " Kenmerke in- (+) of uitgesluit (-):\n"
+
+msgid " system vimrc file: \""
+msgstr " stelsel vimrc-lêer: \""
+
+msgid " user vimrc file: \""
+msgstr " gebruiker vimrc-lêer: \""
+
+msgid " 2nd user vimrc file: \""
+msgstr " 2de gebruiker vimrc-lêer \""
+
+msgid " 3rd user vimrc file: \""
+msgstr " 3de gebruiker vimrc-lêer \""
+
+msgid " user exrc file: \""
+msgstr " gebruiker exrc-lêer: \""
+
+msgid " 2nd user exrc file: \""
+msgstr " 2de gebruiker exrc-lêer: \""
+
+msgid " system gvimrc file: \""
+msgstr " stelsel gvimrc-lêer: \""
+
+msgid " user gvimrc file: \""
+msgstr " gebruiker gvimrc-lêer: \""
+
+msgid "2nd user gvimrc file: \""
+msgstr "2de gebruiker gvimrc-lêer: \""
+
+msgid "3rd user gvimrc file: \""
+msgstr "3de gebruiker gvimrc-lêer: \""
+
+msgid " system menu file: \""
+msgstr " stelsel kieslys-lêer: \""
+
+msgid " fall-back for $VIM: \""
+msgstr " bystand vir $VIM: \""
+
+msgid " f-b for $VIMRUNTIME: \""
+msgstr " bystand vir $VIMRUNTIME: \""
+
+msgid "Compilation: "
+msgstr "Kompilering: "
+
+msgid "Compiler: "
+msgstr "Kompileerder: "
+
+msgid "Linking: "
+msgstr "Koppeling: "
+
+msgid " DEBUG BUILD"
+msgstr " ONTFOUTINGS-KOMPILERING"
+
+msgid "VIM - Vi IMproved"
+msgstr "VIM - Vi Met skop"
+
+# njj: :))
+msgid "version "
+msgstr "Weergawe "
+
+msgid "by Bram Moolenaar et al."
+msgstr "deur Bram Moolenaar et al."
+
+msgid "Vim is open source and freely distributable"
+msgstr "Vim is vryekode, en vrylik verspreibaar"
+
+msgid "Help poor children in Uganda!"
+msgstr "Help arm kinders in Uganda!"
+
+msgid "type :help iccf<Enter> for information "
+msgstr "tik :help iccf<Enter> vir meer inligting hieroor "
+
+msgid "type :q<Enter> to exit "
+msgstr "tik :q<Enter> om program verlaat "
+
+msgid "type :help<Enter> or <F1> for on-line help"
+msgstr "tik :help<Enter> of <F1> vir aanlyn hulp "
+
+msgid "type :help version8<Enter> for version info"
+msgstr "tik :help version8<Enter> vir weergawe-inligting"
+
+msgid "Running in Vi compatible mode"
+msgstr "Voer tans uit in Vi-versoenbare modus"
+
+msgid "type :set nocp<Enter> for Vim defaults"
+msgstr "tik :set nocp<Enter> vir Vim verstekwaardes "
+
+msgid "type :help cp-default<Enter> for info on this"
+msgstr "tik :help cp-default<Enter> vir meer inligting hieroor"
+
+msgid "menu Help->Orphans for information "
+msgstr "menu Hulp->Weeskinders vir meer inligting hieroor "
+
+msgid "Running modeless, typed text is inserted"
+msgstr "Voer modus-loos uit, getikte teks word ingevoeg"
+
+msgid "menu Edit->Global Settings->Toggle Insert Mode "
+msgstr "menu Redigeer->Globale verstellings->Stel en herstel Invoeg Modus"
+
+msgid " for two modes "
+msgstr " vir twee modusse "
+
+msgid "menu Edit->Global Settings->Toggle Vi Compatible"
+msgstr "menu Redigeer->Global verstellings->Stel en herstel Vi Versoenbaar"
+
+msgid " for Vim defaults "
+msgstr " vir Vim verstekwaardes"
+
+msgid "Sponsor Vim development!"
+msgstr "Borg Vim ontwikkeling!"
+
+msgid "Become a registered Vim user!"
+msgstr "Word 'n geregistreerde Vim gebruiker!"
+
+msgid "type :help sponsor<Enter> for information "
+msgstr "tik :help sponsor<Enter> vir meer inligting hieroor "
+
+msgid "type :help register<Enter> for information "
+msgstr "tik :help register<Enter> vir meer inligting hieroor "
+
+msgid "menu Help->Sponsor/Register for information "
+msgstr "menu Hulp->Borg/Registreer vir meer inligting"
+
+msgid "WARNING: Windows 95/98/ME detected"
+msgstr "WAARSKUWING: Windows 95/98/ME bespeur"
+
+msgid "type :help windows95<Enter> for info on this"
+msgstr "tik :help windows95<Enter> vir meer inligting hieroor"
+
+msgid "E441: There is no preview window"
+msgstr "E441: Daar is nie 'n voorskou-venster nie"
+
+msgid "E442: Can't split topleft and botright at the same time"
+msgstr "E442: Kan nie bo-links en onder-regs terselfdertyd verdeel nie"
+
+msgid "E443: Cannot rotate when another window is split"
+msgstr "E443: Kan nie roteer terwyl 'n ander venster verdeel is nie"
+
+msgid "E444: Cannot close last window"
+msgstr "E444: Kan nie laaste venster toemaak nie"
+
+msgid "Already only one window"
+msgstr "Daar is alreeds slegs een venster"
+
+msgid "E445: Other window contains changes"
+msgstr "E445: Die ander venster bevat veranderinge"
+
+msgid "E446: No file name under cursor"
+msgstr "E446: Geen lêernaam onder loper"
+
+#, c-format
+msgid "E447: Can't find file \"%s\" in path"
+msgstr "E447: Kan lêer \"%s\" nie vind in pad nie"
+
+msgid "E370: Could not load library %s"
+msgstr "E370: Kon nie biblioteek laai nie %s"
+
+msgid "Sorry, this command is disabled: the Perl library could not be loaded."
+msgstr ""
+"Jammer, hierdie bevel is afgeskakel: die Perl biblioteek kon nie gelaai "
+"word nie."
+
+msgid "E299: Perl evaluation forbidden in sandbox without the Safe module"
+msgstr "E299: Perl evaluasie verbied in die sandput sonder die 'Safe' module"
+
+msgid "Edit with &multiple Vims"
+msgstr "Wysig met &meer as een Vim"
+
+msgid "Edit with single &Vim"
+msgstr "Wysig met 'n enkel &Vim"
+
+msgid "&Diff with Vim"
+msgstr "Wys verskille ('&diff') met Vim"
+
+msgid "Edit with &Vim"
+msgstr "Wysig met &Vim"
+
+#. Now concatenate
+msgid "Edit with existing Vim - &"
+msgstr "Wysig met bestaande Vim - &"
+
+msgid "Edits the selected file(s) with Vim"
+msgstr "Wysig die gekose lêer(s) met Vim"
+
+msgid "Error creating process: Check if gvim is in your path!"
+msgstr "FOut met die skep van proses: Kyk of gvim in jou pad is!"
+
+msgid "gvimext.dll error"
+msgstr "'gvimext.dll' fout"
+
+msgid "Path length too long!"
+msgstr "Pad-lengte te lank"
+
+msgid "--No lines in buffer--"
+msgstr "--Geen reëls in buffer--"
+
+#.
+#. * The error messages that can be shared are included here.
+#. * Excluded are errors that are only used once and debugging messages.
+#.
+msgid "E470: Command aborted"
+msgstr "E470: Bevel gekanselleer"
+
+msgid "E471: Argument required"
+msgstr "E471: Parameter benodig"
+
+msgid "E10: \\ should be followed by /, ? or &"
+msgstr "E10: \\ moet gevolg word deur /, ? of &"
+
+msgid "E11: Invalid in command-line window; <CR> executes, CTRL-C quits"
+msgstr "E11: Ongeldig in bevelreël venster: <CR> voer uit, CTRL-C stop"
+
+msgid "E12: Command not allowed from exrc/vimrc in current dir or tag search"
+msgstr ""
+"E12: Bevel uit exrc/vimrc nie toegelaat in huidige gids- of etiketsoektog nie"
+
+msgid "E171: Missing :endif"
+msgstr "E171: Ontbrekende ':endif'"
+
+msgid "E600: Missing :endtry"
+msgstr "E600: Ontbrekende ':endtry'"
+
+msgid "E170: Missing :endwhile"
+msgstr "E170: Ontbrekende ':endwhile'"
+
+msgid "E588: :endwhile without :while"
+msgstr "E588: ':endwhile' sonder ':while'"
+
+msgid "E13: File exists (add ! to override)"
+msgstr "E13: Lêer bestaan (gebruik ! om te dwing)"
+
+msgid "E472: Command failed"
+msgstr "E472: Bevel het gefaal"
+
+#, c-format
+msgid "E234: Unknown fontset: %s"
+msgstr "E234: Onbekende fontstel: %s"
+
+#, c-format
+msgid "E235: Unknown font: %s"
+msgstr "E235: Onbekende font: %s"
+
+#, c-format
+msgid "E236: Font \"%s\" is not fixed-width"
+msgstr "E236: Font \"%s\" is nie 'n vaste-wydte font nie"
+
+msgid "E473: Internal error"
+msgstr "E473: Interne fout"
+
+msgid "Interrupted"
+msgstr "Onderbreek"
+
+msgid "E14: Invalid address"
+msgstr "E14: Ongeldige adres"
+
+msgid "E474: Invalid argument"
+msgstr "E474: Ongeldige parameter"
+
+msgid "E475: Invalid argument: %s"
+msgstr "E475: Ongeldige parameter: %s"
+
+#, c-format
+msgid "E15: Invalid expression: %s"
+msgstr "E15: Ongeldige uitdrukking: %s"
+
+msgid "E16: Invalid range"
+msgstr "E16: Ongeldige omvang"
+
+msgid "E476: Invalid command"
+msgstr "E476: Ongeldige bevel"
+
+#, c-format
+msgid "E17: \"%s\" is a directory"
+msgstr "E17: \"%s\" is 'n gids"
+
+msgid "E18: Unexpected characters before '='"
+msgstr "E18: Onverwagte karakters voor '='"
+
+#, c-format
+msgid "E364: Library call failed for \"%s()\""
+msgstr "E364: Biblioteekroep het gefaal vir \"%s\"()"
+
+#, c-format
+msgid "E448: Could not load library function %s"
+msgstr "E448: Kon nie biblioteek funksie laai nie %s"
+
+msgid "E19: Mark has invalid line number"
+msgstr "E19: Merker het ongeldige reëlnommer"
+
+msgid "E20: Mark not set"
+msgstr "E20: Merker nie gestel nie"
+
+msgid "E21: Cannot make changes, 'modifiable' is off"
+msgstr "E21: Kan nie wysig nie, 'modifiable' is af"
+
+msgid "E22: Scripts nested too deep"
+msgstr "E22: Skripte te diep ge-nes"
+
+msgid "E23: No alternate file"
+msgstr "E23: Geen alternatiewe lêer nie"
+
+msgid "E24: No such abbreviation"
+msgstr "E24: Afkorting bestaan nie"
+
+msgid "E477: No ! allowed"
+msgstr "E477: Geen ! toegelaat nie"
+
+msgid "E25: GUI cannot be used: Not enabled at compile time"
+msgstr "E25: GUI kan nie gebruik word nie: Nie tydens kompilering gekies nie"
+
+msgid "E26: Hebrew cannot be used: Not enabled at compile time\n"
+msgstr ""
+"E26: Hebreeus kan nie gebruik word nie: Nie tydens kompilering gekies nie\n"
+
+msgid "E27: Farsi cannot be used: Not enabled at compile time\n"
+msgstr ""
+"E27: Farsi kan nie gebruik word nie: Nie tydens kompilering gekies nie\n"
+
+msgid "E800: Arabic cannot be used: Not enabled at compile time\n"
+msgstr ""
+"E800: Arabies kan nie gebruik word nie: Nie tydens kompilering gekies nie\n"
+
+#, c-format
+msgid "E28: No such highlight group name: %s"
+msgstr "E28: Geen sodanige uitliggroepnaam nie: %s"
+
+msgid "E29: No inserted text yet"
+msgstr "E29: Nog geen ingevoegde teks nie"
+
+msgid "E30: No previous command line"
+msgstr "E30: Geen vorige bevelreël nie"
+
+msgid "E31: No such mapping"
+msgstr "E31: Geen so 'n binding nie"
+
+msgid "E479: No match"
+msgstr "E479: Geen treffer nie"
+
+msgid "E480: No match: %s"
+msgstr "E480: Geen treffer: %s"
+
+msgid "E32: No file name"
+msgstr "E32: Geen lêernaam"
+
+msgid "E33: No previous substitute regular expression"
+msgstr "E33: Geen vorige vervangingspatroon nie"
+
+msgid "E34: No previous command"
+msgstr "E34: Geen vorige bevel nie"
+
+msgid "E35: No previous regular expression"
+msgstr "E35: Geen vorige patroon nie"
+
+msgid "E481: No range allowed"
+msgstr "E481: Geen omvang toegelaat nie"
+
+msgid "E36: Not enough room"
+msgstr "E36: Te min plek"
+
+#, c-format
+msgid "E247: no registered server named \"%s\""
+msgstr "E247: geen geregistreerde bediener genaamd \"%s\""
+
+msgid "E482: Can't create file %s"
+msgstr "E482: Kan nie lêer %s skep nie"
+
+msgid "E483: Can't get temp file name"
+msgstr "E483: Kan nie tydelike lêernaam kry nie"
+
+msgid "E484: Can't open file %s"
+msgstr "E484: Kan nie lêer %s oopmaak nie"
+
+msgid "E485: Can't read file %s"
+msgstr "E485: Kan nie lêer %s lees nie"
+
+msgid "E37: No write since last change (add ! to override)"
+msgstr "E37: Ongeskryf sedert vorige verandering (gebruik ! om te dwing)"
+
+msgid "E38: Null argument"
+msgstr "E38: Nul parameter"
+
+msgid "E39: Number expected"
+msgstr "E39: Nommer verwag"
+
+#, c-format
+msgid "E40: Can't open errorfile %s"
+msgstr "E40: Kan nie foutlêer %s oopmaak nie"
+
+msgid "E233: cannot open display"
+msgstr "E233: kan nie vertoonskerm oopmaak nie"
+
+msgid "E41: Out of memory!"
+msgstr "E41: Geheue op!"
+
+msgid "Pattern not found"
+msgstr "Patroon nie gevind nie"
+
+msgid "E486: Pattern not found: %s"
+msgstr "E486: Patroon nie gevind nie: %s"
+
+msgid "E487: Argument must be positive"
+msgstr "E487: Parameter moet positief wees"
+
+msgid "E459: Cannot go back to previous directory"
+msgstr "E459: Kan nie terug gaan na die vorige gids nie"
+
+msgid "E42: No Errors"
+msgstr "E42: Geen Foute"
+
+msgid "E43: Damaged match string"
+msgstr "E43: Beskadige trefferstring"
+
+msgid "E44: Corrupted regexp program"
+msgstr "E44: Korrupte patroonprogram"
+
+msgid "E45: 'readonly' option is set (add ! to override)"
+msgstr "E45: 'readonly' opsie is aan (gebruik ! om te dwing)"
+
+#, c-format
+msgid "E46: Cannot set read-only variable \"%s\""
+msgstr "E46: Kan nie lees-alleen veranderlike stel nie \"%s\""
+
+msgid "E47: Error while reading errorfile"
+msgstr "E47: Fout tydens lees van 'errorfile'"
+
+msgid "E48: Not allowed in sandbox"
+msgstr "E48: Nie toegelaat in sandput nie"
+
+msgid "E523: Not allowed here"
+msgstr "E523: Nie hier toegelaat nie"
+
+msgid "E359: Screen mode setting not supported"
+msgstr "E359: Skermmodus instelling nie ondersteun nie"
+
+msgid "E49: Invalid scroll size"
+msgstr "E49: Ongeldige rolgrootte"
+
+msgid "E91: 'shell' option is empty"
+msgstr "E91: 'shell' (dop) opsie is leeg"
+
+msgid "E255: Couldn't read in sign data!"
+msgstr "E255: Fout -- kon nie tekendata lees nie!"
+
+msgid "E72: Close error on swap file"
+msgstr "E72: Sluitfout met ruillêer"
+
+msgid "E73: tag stack empty"
+msgstr "E73: etiketstapel leeg"
+
+msgid "E74: Command too complex"
+msgstr "E74: Bevel te kompleks"
+
+msgid "E75: Name too long"
+msgstr "E75: Naam te lank"
+
+msgid "E76: Too many ["
+msgstr "E76: Te veel ["
+
+msgid "E77: Too many file names"
+msgstr "E77: Te veel lêername"
+
+msgid "E488: Trailing characters"
+msgstr "E488: Oorbodige karakters"
+
+msgid "E78: Unknown mark"
+msgstr "E78: Onbekende merker"
+
+msgid "E79: Cannot expand wildcards"
+msgstr "E79: Kan nie plekhouers uitbrei nie"
+
+msgid "E591: 'winheight' cannot be smaller than 'winminheight'"
+msgstr "E591: 'winheight' kan nie kleiner as 'winminheight' wees nie"
+
+msgid "E592: 'winwidth' cannot be smaller than 'winminwidth'"
+msgstr "E592: 'winwidth' kan nie kleiner as 'winminwidth' wees nie"
+
+msgid "E80: Error while writing"
+msgstr "E80: Fout tydens skryfoperasie"
+
+msgid "Zero count"
+msgstr "Nul telling"
+
+msgid "E81: Using <SID> not in a script context"
+msgstr "E81: Gebruik van '<SID>' buite skripkonteks"
+
+msgid "E449: Invalid expression received"
+msgstr "E449: Ongeldige uitdrukking ontvang"
+
+msgid "E463: Region is guarded, cannot modify"
+msgstr "E463: Omgewing is onder bewaking, kan nie verander nie"
+
+#~ msgid "function "
+#~ msgstr "funksie "
+
+#~ msgid "Run Macro"
+#~ msgstr "Voer Makro uit"
+
+#~ msgid "E221: 'commentstring' is empty"
+#~ msgstr "E221: 'commentstring' opsie is leeg"
+
+#~ msgid "E242: Color name not recognized: %s"
+#~ msgstr "E242: Kleurnaam is onbekend: %s"
+
+#~ msgid "E242: Missing color: %s"
+#~ msgstr "E242: Ontbrekende kleur: %s"
+
+#~ msgid "error reading cscope connection %d"
+#~ msgstr "'cscope' verbinding %d kon nie gelees word nie"
+
+#~ msgid "E260: cscope connection not found"
+#~ msgstr "E260: 'cscope' verbinding nie gevind nie"
+
+#~ msgid "cscope connection closed"
+#~ msgstr "'cscope' verbinding gesluit"
+
+# njj: dalk 'verbinding' ipv 'verbinding' orals?
+#~ msgid "couldn't malloc\n"
+#~ msgstr "kon nie 'malloc' nie\n"
+
+#~ msgid "%2d %-5ld %-34s <none>\n"
+#~ msgstr "%2d %-5ld %-34s <geen>\n"
+
+#~ msgid "E249: couldn't read VIM instance registry property"
+#~ msgstr "E249: kon nie VIM instansie register-kenmerk lees nie"
+
+#~ msgid "\"\n"
+#~ msgstr "\"\n"
+
+#~ msgid "--help\t\tShow Gnome arguments"
+#~ msgstr "--help\t\tWys Gnome parameters"
+
+#~ msgid "1 line ~ed"
+#~ msgstr "1 reël ge-~"
+
+#~ msgid "%ld lines ~ed"
+#~ msgstr "%ld reëls ge-~"
+
+#~ msgid " BLOCK"
+#~ msgstr " BLOK"
+
+#~ msgid " LINE"
+#~ msgstr " REËL"
+
+#~ msgid "Linear tag search"
+#~ msgstr "Liniêre etiketsoek"
+
+#~ msgid "Binary tag search"
+#~ msgstr "Binêre etiketsoek"
+
+#~ msgid "Can't open file %s"
+#~ msgstr "Kan nie lêer %s oopmaak nie"
+
+#~ msgid "E258: no matches found in cscope connections"
+#~ msgstr "E258: geen treffers gevind in 'cscope' verbindings nie"
+
+#~ msgid "No servers found for this display"
+#~ msgstr "Geen bedieners gevind vir die 'display' nie"
+
+#~ msgid "Missing filename"
+#~ msgstr "Ontbrekende lêernaam"
+
+#~ msgid "Invalid line number: %ld"
+#~ msgstr "Ongeldige reëlnommer: %ld"
+
+#~ msgid "Cannot use :normal from event handler"
+#~ msgstr "Kan ':normal' nie vanuit gebeurtenishanteerder gebruik nie"
+
+#~ msgid "%ldL, %ldC"
+#~ msgstr "%ldR, %ldK"
+
+#~ msgid "VIM - Help on..."
+#~ msgstr "VIM - Hulp met.."
+
+#~ msgid "Topic:"
+#~ msgstr "Onderwerp:"
+
+#~ msgid "Error: During loading fontset %s"
+#~ msgstr "Fout: Gedurende die laai van fontstel %s"
+
+#~ msgid "locale is not set correctly"
+#~ msgstr "lokaal is nie korrek gestel nie"
+
+#~ msgid "Set LANG environment variable to your locale"
+#~ msgstr "Stel die 'LANG' omgewingsveranderlike na jou lokaal toe"
+
+#~ msgid "For korean:"
+#~ msgstr "Vir Afrikaans:"
+
+#~ msgid " csh: setenv LANG ko"
+#~ msgstr " csh: setenv LANG af"
+
+#~ msgid " sh : export LANG=ko"
+#~ msgstr " sh: export LANG=af"
+
+#~ msgid "fontset name: %s"
+#~ msgstr "fontstel naam: %s"
+
+#~ msgid "Your language Font missing"
+#~ msgstr "Jou taal Font ontbreek"
+
+#~ msgid "loaded fontname: %s"
+#~ msgstr "gelaaide fontnaam: %s"
+
+#~ msgid "automata ERROR: internal"
+#~ msgstr "automata FOUT: intern"
+
+#~ msgid "cs_add_common: alloc fail #1"
+#~ msgstr "'cs_add_common': toeken onsuksesvol #1"
+
+#~ msgid "cs_add_common: alloc fail #2"
+#~ msgstr "'cs_add_common': toeken onsuksesvol #2"
+
+#~ msgid "cs_add_common: alloc fail #3"
+#~ msgstr "'cs_add_common': toeken onsuksesvol #3"
+
+#~ msgid "cs_add_common: alloc fail #4"
+#~ msgstr "'cs_add_common': toeken onsuksesvol #4"
+
+#~ msgid "Retrieve next symbol"
+#~ msgstr "Kry volgende simbool"
+
+#~ msgid "-- SNiFF+ commands --"
+#~ msgstr "-- SNiFF+ bevele --"
+
+#~ msgid "Unrecognized sniff request [%s]"
+#~ msgstr "Onbekende sniff versoek [%s]"
+
+#~ msgid "Can't create input context."
+#~ msgstr "Kan nie invoerkonteks skep nie."
+
+#~ msgid "Sorry, deleting a menu is not possible in the Athena version"
+#~ msgstr ""
+#~ "Jammer, in die Athena weergawe is dit onmoontlik om 'n kieslys te skrap"
+
+#~ msgid "Out of memory"
+#~ msgstr "Geheue op"
+
+#~ msgid "PC (32 bits Vim)"
+#~ msgstr "PC (32 bisse Vim)"
+
+#~ msgid "PC (16 bits Vim)"
+#~ msgstr "PC (16 bisse Vim)"
+
+#~ msgid "Unsupported screen mode"
+#~ msgstr "Ongesteunde skermmodus"
+
+#~ msgid "deadly signal"
+#~ msgstr "dodelike sein"
+
+#~ msgid "some"
+#~ msgstr "sommige"
+
+#~ msgid "Library call failed"
+#~ msgstr "Biblioteekfunksieroep het gefaal"
+
+#~ msgid "Cannot clear all highlight groups"
+#~ msgstr "Kan nie alle uitliggroepe leegmaak nie"
+
+#~ msgid "GUI is not running"
+#~ msgstr "GUI voer nie uit nie"
+
+#~ msgid "Command too long"
+#~ msgstr "Bevel te lank"
+
+#~ msgid "Ambiguous mapping"
+#~ msgstr "Dubbelsinnige binding"
+
+#~ msgid "Ambiguous mapping, conflicts with \"%s\""
+#~ msgstr "Dubbelsinnige binding, bots met \"%s\""
+
+#~ msgid "Too many \\("
+#~ msgstr "Te veel \\("
+
+#~ msgid "Unmatched \\("
+#~ msgstr "Onpaar \\("
+
+#~ msgid "Nested *, \\=, \\+, \\! or \\{"
+#~ msgstr "Geneste *, \\=, \\+, \\! of \\{"
+
+#~ msgid "\\= follows nothing"
+#~ msgstr "\\= volg niks"
+
+#~ msgid "\\+ follows nothing"
+#~ msgstr "\\+ volg niks"
+
+#~ msgid "\\@ follows nothing"
+#~ msgstr "\\@ volg niks"
+
+#~ msgid "\\{ follows nothing"
+#~ msgstr "\\{ volg niks"
+
+#~ msgid "\\* follows nothing"
+#~ msgstr "\\* volg niks"
+
+#~ msgid "Unexpected magic character; check META."
+#~ msgstr "Onverwagte toorkarakter; kyk na META."
+
+#~ msgid "type :help uganda<Enter> if you like Vim "
+#~ msgstr "tik :help uganda<Enter> as jy hou van Vim "
+
+#~ msgid " WARNING: Intel CPU detected. "
+#~ msgstr " WAARSKUWING: Intel SVE bespeur. "
+
+#~ msgid " PPC has a much better architecture. "
+#~ msgstr " PPC het 'n veel beter argitektuur. "
+
+#~ msgid "Security error: new viminfo file is a symbolic link"
+#~ msgstr "Sekuriteitsfout: nuwe viminfo lêer is a simboliese skakel"
+
+#~ msgid "line ~%ld: %s"
+#~ msgstr "reël ~%ld: %s"
+
+#~ msgid "makeef option not set"
+#~ msgstr "'makeef' opsie nie aan nie"
+
+#~ msgid "Security error: filter output is a symbolic link: %s"
+#~ msgstr "Sekuriteitsfout: filter afvoer is 'n simboliese skakel"
+
+#~ msgid "Security error: 'charconvert' output is a symbolic link"
+#~ msgstr "Sekuriteitsfout: 'charconvert' afvoer is 'n simboliese skakel"
+
+#~ msgid "Security error: filter input is a symbolic link: %s"
+#~ msgstr "Sekuriteitsfout: filter invoer is 'n simboliese skakel"
+
+#~ msgid "Fold must be at least two lines"
+#~ msgstr "'n Vou moet ten minste 2 reëls wees"
+
+#~ msgid "No fold at this line"
+#~ msgstr "Geen vou by hierdie reël nie"
+
+#~ msgid "Security error: shell command output is a symbolic link"
+#~ msgstr "Sekuriteitsfout: Dop-bevel afvoer is 'n simboliese skakel"
+
+#~ msgid "Warning: %s option changed from modeline"
+#~ msgstr "Waarskuwing: %s opsie verander vanaf moduslyn"
+
+#~ msgid "Change dir debugging enabled."
+#~ msgstr "Verandergids ontfouting in staat gestel"
+
+#~ msgid "Not a proper file name: '%s'"
+#~ msgstr "Nie 'n geldige lêernaam nie: '%s'"
+
+#~ msgid "File name '%s' is valid"
+#~ msgstr "lêernaam '%s is ongeldig"
+
+#~ msgid "Leave: %s"
+#~ msgstr "Verlaat: %s"
+
+#~ msgid "WARNING: tag command changed a buffer!!!"
+#~ msgstr "WAARSKUWING: etiketbevel het buffer verander!!!"
diff --git a/src/po/ca.po b/src/po/ca.po
new file mode 100644
index 0000000..8542a87
--- /dev/null
+++ b/src/po/ca.po
@@ -0,0 +1,6939 @@
+# Catalan messages for vim.
+# Copyright (C) 2003-2017 Ernest Adrogué <eadrogue@gmx.net>.
+# This file is distributed under the Vim License.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: vim 8.0\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2017-07-11 23:51+0200\n"
+"PO-Revision-Date: 2017-07-26 13:29+0200\n"
+"Last-Translator: Ernest Adrogué <eadrogue@gmx.net>\n"
+"Language-Team: Catalan <ca@dodds.net>\n"
+"Language: ca\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=iso-8859-1\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "E831: bf_key_init() called with empty password"
+msgstr "E831: s'ha cridat bf_key_init() amb una contrasenya buida"
+
+msgid "E820: sizeof(uint32_t) != 4"
+msgstr "E820: sizeof(uint32_t) != 4"
+
+msgid "E817: Blowfish big/little endian use wrong"
+msgstr "E817: ús de Blowfish amb una ordenació dels bytes incorrecta"
+
+msgid "E818: sha256 test failed"
+msgstr "E818: el test sha256 ha fallat"
+
+msgid "E819: Blowfish test failed"
+msgstr "E819: el test Blowfish ha fallat"
+
+msgid "[Location List]"
+msgstr "[Llista de posicions]"
+
+msgid "[Quickfix List]"
+msgstr "[Llista Quickfix]"
+
+msgid "E855: Autocommands caused command to abort"
+msgstr "E855: Una ordre automàtica a provocat que l'ordre avortés"
+
+msgid "E82: Cannot allocate any buffer, exiting..."
+msgstr "E82: No s'ha pogut assignar memòria per a cap buffer, sortint..."
+
+msgid "E83: Cannot allocate buffer, using other one..."
+msgstr "E83: No s'ha pogut assignar memòria per al buffer, usant-ne un altre..."
+
+msgid "E931: Buffer cannot be registered"
+msgstr "E931: No s'ha pogut registrar el buffer"
+
+msgid "E937: Attempt to delete a buffer that is in use"
+msgstr "E937: Intent d'eliminar un buffer que es troba en ús"
+
+# unload: treu el buffer de la memòria però el deixa a la llista
+# delete: treu el buffer de la memòria i de la llista de buffers
+# wipe out: elimina el buffer amb totes les opcions, marques, etc.
+msgid "E515: No buffers were unloaded"
+msgstr "E515: No s'ha alliberat cap buffer"
+
+msgid "E516: No buffers were deleted"
+msgstr "E516: No s'ha eliminat cap buffer"
+
+msgid "E517: No buffers were wiped out"
+msgstr "E517: No s'ha destruït cap buffer"
+
+msgid "1 buffer unloaded"
+msgstr "S'ha alliberat 1 buffer"
+
+#, c-format
+msgid "%d buffers unloaded"
+msgstr "S'han alliberat %d buffers"
+
+msgid "1 buffer deleted"
+msgstr "S'ha eliminat 1 buffer"
+
+#, c-format
+msgid "%d buffers deleted"
+msgstr "S'han eliminat %d buffers"
+
+msgid "1 buffer wiped out"
+msgstr "S'ha destruït 1 buffer"
+
+#, c-format
+msgid "%d buffers wiped out"
+msgstr "S'han destruït %d buffers"
+
+msgid "E90: Cannot unload last buffer"
+msgstr "E90: No es pot alliberar l'últim buffer"
+
+msgid "E84: No modified buffer found"
+msgstr "E84: No s'ha trobat cap buffer modificat"
+
+msgid "E85: There is no listed buffer"
+msgstr "E85: No hi ha cap buffer a la llista"
+
+msgid "E87: Cannot go beyond last buffer"
+msgstr "E87: No es pot anar més enllà de l'últim buffer"
+
+msgid "E88: Cannot go before first buffer"
+msgstr "E88: No es pot anar més enllà del primer buffer"
+
+#, c-format
+msgid "E89: No write since last change for buffer %ld (add ! to override)"
+msgstr "E89: No s'ha desat el buffer %ld (afegiu ! per a forçar)"
+
+msgid "W14: Warning: List of file names overflow"
+msgstr "W14: Atenció: S'ha desbordat la llista de noms de fitxers"
+
+#, c-format
+msgid "E92: Buffer %ld not found"
+msgstr "E92: No s'ha trobat el buffer %ld"
+
+#, c-format
+msgid "E93: More than one match for %s"
+msgstr "E93: Hi ha més d'una coincidència per a %s"
+
+#, c-format
+msgid "E94: No matching buffer for %s"
+msgstr "E94: No hi ha cap coincidència per a %s"
+
+#, c-format
+msgid "line %ld"
+msgstr "línia %ld"
+
+msgid "E95: Buffer with this name already exists"
+msgstr "E95: Ja existeix un buffer amb aquest nom"
+
+msgid " [Modified]"
+msgstr " [Modificat]"
+
+msgid "[Not edited]"
+msgstr "[No editat]"
+
+msgid "[New file]"
+msgstr "[Fitxer nou]"
+
+msgid "[Read errors]"
+msgstr "[Errors de lectura]"
+
+# ro == read only
+msgid "[RO]"
+msgstr "[NL]"
+
+msgid "[readonly]"
+msgstr "[només lectura]"
+
+#, c-format
+msgid "1 line --%d%%--"
+msgstr "1 línia --%d%%--"
+
+#, c-format
+msgid "%ld lines --%d%%--"
+msgstr "%ld línies --%d%%--"
+
+#, c-format
+msgid "line %ld of %ld --%d%%-- col "
+msgstr "línia %ld de %ld --%d%%-- col "
+
+msgid "[No Name]"
+msgstr "[Sense nom]"
+
+msgid "help"
+msgstr "ajuda"
+
+msgid "[Help]"
+msgstr "[Ajuda]"
+
+msgid "[Preview]"
+msgstr "[Vista prèvia]"
+
+msgid "All"
+msgstr "Tot"
+
+msgid "Bot"
+msgstr "Baix"
+
+msgid "Top"
+msgstr "Dalt"
+
+msgid ""
+"\n"
+"# Buffer list:\n"
+msgstr ""
+"\n"
+"# Llista de buffers:\n"
+
+# :h special-buffers
+msgid "[Scratch]"
+msgstr "[Esborrany]"
+
+# :sign place
+msgid ""
+"\n"
+"--- Signs ---"
+msgstr ""
+"\n"
+"--- Senyals ---"
+
+# :sign place
+#, c-format
+msgid "Signs for %s:"
+msgstr "Senyals a %s:"
+
+# :sign place
+#, c-format
+msgid " line=%ld id=%d name=%s"
+msgstr " línia=%ld id=%d nom=%s"
+
+msgid "E902: Cannot connect to port"
+msgstr "E902: No s'ha pogut connectar al port"
+
+msgid "E901: gethostbyname() in channel_open()"
+msgstr "E901: gethostbyname() a channel_open()"
+
+msgid "E898: socket() in channel_open()"
+msgstr "E898: socket() a channel_open()"
+
+msgid "E903: received command with non-string argument"
+msgstr "E903: s'ha rebut una ordre amb un argument que no és text"
+
+# expr i call són ordres (:h channel-commands)
+msgid "E904: last argument for expr/call must be a number"
+msgstr "E904: l'últim argument a expr/call ha de ser un número"
+
+msgid "E904: third argument for call must be a list"
+msgstr "E904: el tercer argument a call ha de ser una llista"
+
+#, c-format
+msgid "E905: received unknown command: %s"
+msgstr "E905: s'ha rebut una ordre desconeguda: %s"
+
+#, c-format
+msgid "E630: %s(): write while not connected"
+msgstr "E630: %s(): s'ha escrit sense estar connectat"
+
+#, c-format
+msgid "E631: %s(): write failed"
+msgstr "E631: %s(): l'escriptura ha fallat"
+
+#, c-format
+msgid "E917: Cannot use a callback with %s()"
+msgstr "E917: No es poden utilitzar callbacks amb %s()"
+
+msgid "E912: cannot use ch_evalexpr()/ch_sendexpr() with a raw or nl channel"
+msgstr "E912: no es pot usar ch_evalexpr()/ch_sendexpr() amb canals raw o nl"
+
+msgid "E906: not an open channel"
+msgstr "E906: el canal no està obert"
+
+msgid "E920: _io file requires _name to be set"
+msgstr "E920: els fitxers _io han de tenir l'atribut _name"
+
+msgid "E915: in_io buffer requires in_buf or in_name to be set"
+msgstr "E915: els buffers in_io han de tenir l'atribut in_buf o in_name"
+
+#, c-format
+msgid "E918: buffer must be loaded: %s"
+msgstr "E918: el buffer no està carregat: %s"
+
+msgid "E821: File is encrypted with unknown method"
+msgstr "E821: El fitxer està xifrat amb un mètode desconegut"
+
+msgid "Warning: Using a weak encryption method; see :help 'cm'"
+msgstr "Atenció: esteu utilitzant un xifrat poc potent; vegeu :help 'cm'"
+
+msgid "Enter encryption key: "
+msgstr "Introduïu la clau de xifrat: "
+
+msgid "Enter same key again: "
+msgstr "Introduïu la mateixa clau un altre cop: "
+
+msgid "Keys don't match!"
+msgstr "La claus no coincideixen!"
+
+msgid "[crypted]"
+msgstr "[xifrat]"
+
+# :let foo = {1 2}
+#, c-format
+msgid "E720: Missing colon in Dictionary: %s"
+msgstr "E720: Falta un caràcter ':': %s"
+
+#, c-format
+msgid "E721: Duplicate key in Dictionary: \"%s\""
+msgstr "E721: Clau duplicada: \"%s\""
+
+#, c-format
+msgid "E722: Missing comma in Dictionary: %s"
+msgstr "E722: Falta una coma: %s"
+
+#, c-format
+msgid "E723: Missing end of Dictionary '}': %s"
+msgstr "E723: Falta un '}': %s"
+
+# :let foo = [1,2]
+# :let bar = [3,4]
+# :lockvar foo
+# :echo extend(foo, bar)
+#
+# la forma fun() argument es repeteix més avall
+msgid "extend() argument"
+msgstr "argument a extend()"
+
+#, c-format
+msgid "E737: Key already exists: %s"
+msgstr "E737: La clau ja existeix: %s"
+
+#, c-format
+msgid "E96: Cannot diff more than %ld buffers"
+msgstr "E96: No es pot fer diff amb més de %ld buffers"
+
+msgid "E810: Cannot read or write temp files"
+msgstr "E810: No s'han pogut escriure o llegir fitxers temporals"
+
+msgid "E97: Cannot create diffs"
+msgstr "E97: No s'han pogut crear diffs"
+
+# És el nom d'un diàleg. Menú "Split patched by..."
+msgid "Patch file"
+msgstr "Fitxer de diferències"
+
+msgid "E816: Cannot read patch output"
+msgstr "E816: No s'ha pogut llegir la sortida de patch"
+
+msgid "E98: Cannot read diff output"
+msgstr "E98: No s'ha pogut llegir la sortida de diff"
+
+msgid "E99: Current buffer is not in diff mode"
+msgstr "E99: El buffer actual no es troba en mode diff"
+
+msgid "E793: No other buffer in diff mode is modifiable"
+msgstr "E793: No hi ha cap altre buffer en mode diff que sigui modificable"
+
+msgid "E100: No other buffer in diff mode"
+msgstr "E100: No hi ha cap altre buffer en mode diff"
+
+msgid "E101: More than two buffers in diff mode, don't know which one to use"
+msgstr "E101: Hi ha més de 2 buffers en mode diff"
+
+#, c-format
+msgid "E102: Can't find buffer \"%s\""
+msgstr "E102: No s'ha trobat el buffer \"%s\""
+
+#, c-format
+msgid "E103: Buffer \"%s\" is not in diff mode"
+msgstr "E103: El buffer \"%s\" no es troba en mode diff"
+
+msgid "E787: Buffer changed unexpectedly"
+msgstr "E787: El buffer ha canviat inesperadament"
+
+msgid "E104: Escape not allowed in digraph"
+msgstr "E104: El dígraf conté caràcters d'escapada"
+
+msgid "E544: Keymap file not found"
+msgstr "E544: No s'ha trobat el fitxer de mapa de tecles"
+
+# sourced file == script
+msgid "E105: Using :loadkeymap not in a sourced file"
+msgstr "E105: Ús de :loadkeymap fora d'un script"
+
+msgid "E791: Empty keymap entry"
+msgstr "E791: Entrada buida al mapa de tecles"
+
+msgid " Keyword completion (^N^P)"
+msgstr " Compleció de paraules clau (^N^P)"
+
+msgid " ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+msgstr " Mode ^X (^]^D^E^F^|^K^L^N^O^Ps^U^V^Y)"
+
+msgid " Whole line completion (^L^N^P)"
+msgstr " Compleció de línies senceres (^L^N^P)"
+
+msgid " File name completion (^F^N^P)"
+msgstr " Compleció de noms de fitxer (^F^N^P)"
+
+msgid " Tag completion (^]^N^P)"
+msgstr " Compleció d'etiquetes (^]^N^P)"
+
+msgid " Path pattern completion (^N^P)"
+msgstr " Compleció d'ubicacions (^N^P)"
+
+msgid " Definition completion (^D^N^P)"
+msgstr " Compleció de definicions (^D^N^P)"
+
+# todo: expecificar diccionari?
+msgid " Dictionary completion (^K^N^P)"
+msgstr " Compleció de paraules (^K^N^P)"
+
+msgid " Thesaurus completion (^T^N^P)"
+msgstr " Compleció de sinònims (^T^N^P)"
+
+msgid " Command-line completion (^V^N^P)"
+msgstr " Compleció de la línia d'ordres (^V^N^P)"
+
+msgid " User defined completion (^U^N^P)"
+msgstr " Compleció definida per l'usuari (^U^N^P)"
+
+msgid " Omni completion (^O^N^P)"
+msgstr " Omni-compleció (^O^N^P)"
+
+msgid " Spelling suggestion (s^N^P)"
+msgstr " Suggeriment d'ortografia (s^N^P)"
+
+# i C-x C-p
+msgid " Keyword Local completion (^N^P)"
+msgstr " Compleció de paraules clau locals (^N^P)"
+
+msgid "Hit end of paragraph"
+msgstr "S'ha arribat al final del paràgraf"
+
+msgid "E839: Completion function changed window"
+msgstr "E839: La funció de compleció ha modificat la finestra"
+
+msgid "E840: Completion function deleted text"
+msgstr "E840: La funció de compleció ha esborrat text"
+
+msgid "'dictionary' option is empty"
+msgstr "El paràmetre 'dictionary' està en blanc"
+
+msgid "'thesaurus' option is empty"
+msgstr "El paràmetre 'thesaurus' està en blanc"
+
+# i C-x C-k
+#, c-format
+msgid "Scanning dictionary: %s"
+msgstr "Cercant al diccionari: %s"
+
+# i C-x C-e
+msgid " (insert) Scroll (^E/^Y)"
+msgstr " (inserir) Desplaçament (^E/^Y)"
+
+msgid " (replace) Scroll (^E/^Y)"
+msgstr " (substituir) Desplaçament (^E/^Y)"
+
+#, c-format
+msgid "Scanning: %s"
+msgstr "Cercant: %s"
+
+msgid "Scanning tags."
+msgstr "Cercant etiquetes."
+
+msgid "match in file"
+msgstr "coincidència al fitxer"
+
+msgid " Adding"
+msgstr " Afegint"
+
+msgid "-- Searching..."
+msgstr "-- Cercant..."
+
+msgid "Back at original"
+msgstr "Original"
+
+msgid "Word from other line"
+msgstr "Paraula d'una altra línia"
+
+msgid "The only match"
+msgstr "L'única coincidència"
+
+#, c-format
+msgid "match %d of %d"
+msgstr "coincidència %d de %d"
+
+#, c-format
+msgid "match %d"
+msgstr "coincidència %d"
+
+msgid "E18: Unexpected characters in :let"
+msgstr "E18: Caràcters inesperats a :let"
+
+#, c-format
+msgid "E121: Undefined variable: %s"
+msgstr "E121: Variable no definida: %s"
+
+msgid "E111: Missing ']'"
+msgstr "E111: Falta un ']'"
+
+# :let foo={1: 2}
+# :let foo[1:3]=0
+msgid "E719: Cannot use [:] with a Dictionary"
+msgstr "E719: No es pot usar [:] amb un diccionari"
+
+# :let foo += 1
+#, c-format
+msgid "E734: Wrong variable type for %s="
+msgstr "E734: Tipus de variable incorrecte per a %s="
+
+#, c-format
+msgid "E461: Illegal variable name: %s"
+msgstr "E461: El nom de la variable és il·legal: %s"
+
+# semblant a eval.c:7120 i següents
+msgid "E806: using Float as a String"
+msgstr "E806: Ús de Float com a String"
+
+# :let [foo,bar] = [1]
+msgid "E687: Less targets than List items"
+msgstr "E687: Menys valors per assignar que elements a la llista"
+
+# :let [a,b]=[1,2,3]
+msgid "E688: More targets than List items"
+msgstr "E688: Més valors per assignar que elements a la llista"
+
+msgid "Double ; in list of variables"
+msgstr "La llista de variables conté un ; doble"
+
+#, c-format
+msgid "E738: Can't list variables for %s"
+msgstr "E738: No s'han pogut mostrar les variables de tipus %s"
+
+msgid "E689: Can only index a List or Dictionary"
+msgstr "E689: Només és possible indexar List i Dictionary"
+
+msgid "E708: [:] must come last"
+msgstr "E708: [:] ha d'anar al final"
+
+msgid "E709: [:] requires a List value"
+msgstr "E709: [:] requereix un valor List"
+
+msgid "E710: List value has more items than target"
+msgstr "E710: La llista conté més elements que valors per assignar"
+
+msgid "E711: List value has not enough items"
+msgstr "E711: La llista no conté prou elements"
+
+msgid "E690: Missing \"in\" after :for"
+msgstr "E690: Falta un \"in\" després de :for"
+
+#, c-format
+msgid "E108: No such variable: \"%s\""
+msgstr "E108: No existeix tal variable: \"%s\""
+
+#, c-format
+msgid "E940: Cannot lock or unlock variable %s"
+msgstr "E940: No s'ha pogut bloquejar o desbloquejar la variable %s"
+
+msgid "E743: variable nested too deep for (un)lock"
+msgstr "E743: el nivell d'imbricació de la variable és massa elevat"
+
+msgid "E109: Missing ':' after '?'"
+msgstr "E109: Falta un ':' després de '?'"
+
+msgid "E691: Can only compare List with List"
+msgstr "E691: List només es pot comparar amb List"
+
+msgid "E692: Invalid operation for List"
+msgstr "E692: Operació no vàlida amb llistes"
+
+msgid "E735: Can only compare Dictionary with Dictionary"
+msgstr "E735: Dictionary només es pot comparar amb Dictionary"
+
+msgid "E736: Invalid operation for Dictionary"
+msgstr "E736: Operació no vàlida per a Dictionary"
+
+msgid "E694: Invalid operation for Funcrefs"
+msgstr "E694: Operació no vàlida per a Funcref"
+
+msgid "E804: Cannot use '%' with Float"
+msgstr "E804: No és possible utilitzar '%' amb Float"
+
+msgid "E110: Missing ')'"
+msgstr "E110: Falta un ')'"
+
+msgid "E695: Cannot index a Funcref"
+msgstr "E695: No és possible indexar Funcref"
+
+msgid "E909: Cannot index a special variable"
+msgstr "E909: Les variables especials no són indexables"
+
+#, c-format
+msgid "E112: Option name missing: %s"
+msgstr "E112: Falta el nom de l'opció: %s"
+
+#, c-format
+msgid "E113: Unknown option: %s"
+msgstr "E113: Opció desconeguda: %s"
+
+#, c-format
+msgid "E114: Missing quote: %s"
+msgstr "E114: Falten cometes: %s"
+
+#, c-format
+msgid "E115: Missing quote: %s"
+msgstr "E115: Falten cometes: %s"
+
+msgid "Not enough memory to set references, garbage collection aborted!"
+msgstr "No hi ha prou memòria, s'avorta el col·lector de brossa!"
+
+# veure eval.c:2935
+msgid "E724: variable nested too deep for displaying"
+msgstr "E724: el nivell d'imbricació de la variable és massa elevat"
+
+msgid "E805: Using a Float as a Number"
+msgstr "E805: Ús de Float com a Number"
+
+msgid "E703: Using a Funcref as a Number"
+msgstr "E703: Ús de Funcref com a Number"
+
+msgid "E745: Using a List as a Number"
+msgstr "E745: Ús de List com a Number"
+
+msgid "E728: Using a Dictionary as a Number"
+msgstr "E728: Ús de Dictionary com a Number"
+
+msgid "E910: Using a Job as a Number"
+msgstr "E910: Ús de Job com a Number"
+
+msgid "E913: Using a Channel as a Number"
+msgstr "E913: Ús de Channel com a Number"
+
+msgid "E891: Using a Funcref as a Float"
+msgstr "E891: Ús de Funcref com a Float"
+
+msgid "E892: Using a String as a Float"
+msgstr "E892: Ús de String com a Float"
+
+msgid "E893: Using a List as a Float"
+msgstr "E893: Ús de List com a Float"
+
+msgid "E894: Using a Dictionary as a Float"
+msgstr "E894: Ús de Dictionary com a Float"
+
+msgid "E907: Using a special value as a Float"
+msgstr "E907: Ús de Special com a Float"
+
+msgid "E911: Using a Job as a Float"
+msgstr "E911: Ús de Job com a Float"
+
+msgid "E914: Using a Channel as a Float"
+msgstr "E914: Ús de Channel com a Float"
+
+msgid "E729: using Funcref as a String"
+msgstr "E729: Ús de Funcref com a String"
+
+msgid "E730: using List as a String"
+msgstr "E730: Ús de List com a String"
+
+msgid "E731: using Dictionary as a String"
+msgstr "E731: Ús de Dictionary com a String"
+
+msgid "E908: using an invalid value as a String"
+msgstr "E908: Ús d'un valor invàlid com a String"
+
+#, c-format
+msgid "E795: Cannot delete variable %s"
+msgstr "E795: No s'ha pogut eliminar la variable %s"
+
+#, c-format
+msgid "E704: Funcref variable name must start with a capital: %s"
+msgstr "E704: Les variables Funcref han de començar amb majúscula: %s"
+
+#, c-format
+msgid "E705: Variable name conflicts with existing function: %s"
+msgstr "E705: La variable entra en conflicte amb una funció existent: %s"
+
+#, c-format
+msgid "E741: Value is locked: %s"
+msgstr "E741: El valor està bloquejat: %s"
+
+msgid "Unknown"
+msgstr "Desconegut"
+
+#, c-format
+msgid "E742: Cannot change value of %s"
+msgstr "E742: No s'ha pogut canviar el valor de %s"
+
+msgid "E698: variable nested too deep for making a copy"
+msgstr "E698: el nivell d'imbricació de la variable és massa elevat"
+
+msgid ""
+"\n"
+"# global variables:\n"
+msgstr ""
+"\n"
+"# variables globals:\n"
+
+msgid ""
+"\n"
+"\tLast set from "
+msgstr ""
+"\n"
+"\tDefinit per últim cop a "
+
+msgid "map() argument"
+msgstr "argument a map()"
+
+msgid "filter() argument"
+msgstr "argument a filter()"
+
+#, c-format
+msgid "E686: Argument of %s must be a List"
+msgstr "E686: L'argument a %s ha de ser List"
+
+msgid "E928: String required"
+msgstr "E928: Es necessita String"
+
+msgid "E808: Number or Float required"
+msgstr "E808: Es necessita Number o Float"
+
+msgid "add() argument"
+msgstr "argument a add()"
+
+msgid "E785: complete() can only be used in Insert mode"
+msgstr "E785: complete() només es pot utilitzar en mode d'inserció"
+
+msgid "&Ok"
+msgstr "&D'acord"
+
+#, c-format
+msgid "E700: Unknown function: %s"
+msgstr "E700: Funció desconeguda: %s"
+
+msgid "E922: expected a dict"
+msgstr "E922: s'esperava un diccionari"
+
+msgid "E923: Second argument of function() must be a list or a dict"
+msgstr "E923: El segon argument a function() ha de ser una llista o diccionari"
+
+msgid ""
+"&OK\n"
+"&Cancel"
+msgstr ""
+"&D'acord\n"
+"&Cancel·la"
+
+msgid "called inputrestore() more often than inputsave()"
+msgstr "s'ha cridat inputrestore() més sovint que inputsave()"
+
+msgid "insert() argument"
+msgstr "argument a insert()"
+
+msgid "E786: Range not allowed"
+msgstr "E786: Interval no permès"
+
+msgid "E916: not a valid job"
+msgstr "E916: no és una feina vàlida"
+
+msgid "E701: Invalid type for len()"
+msgstr "E701: Tipus invàlid per a len()"
+
+#, c-format
+msgid "E798: ID is reserved for \":match\": %ld"
+msgstr "E798: ID reservat per a \":match\": %ld"
+
+msgid "E726: Stride is zero"
+msgstr "E726: L'increment és zero"
+
+msgid "E727: Start past end"
+msgstr "E727: Inici després del final"
+
+msgid "<empty>"
+msgstr "<buit>"
+
+msgid "E240: No connection to the X server"
+msgstr "E240: No hi ha connexió amb el servidor X"
+
+#, c-format
+msgid "E241: Unable to send to %s"
+msgstr "E241: No s'ha pogut enviar a %s"
+
+msgid "E277: Unable to read a server reply"
+msgstr "E277: No s'ha pogut llegir la resposta del servidor"
+
+msgid "E941: already started a server"
+msgstr "E941: ja s'ha iniciat un servidor"
+
+msgid "E942: +clientserver feature not available"
+msgstr "E942: la característica +clientserver no està disponible"
+
+msgid "remove() argument"
+msgstr "argument a remove()"
+
+msgid "E655: Too many symbolic links (cycle?)"
+msgstr "E655: Massa enllaços simbòlics (circulars?)"
+
+msgid "reverse() argument"
+msgstr "argument a reverse()"
+
+msgid "E258: Unable to send to client"
+msgstr "E258: No s'ha pogut enviar al client"
+
+#, c-format
+msgid "E927: Invalid action: '%s'"
+msgstr "E927: Acció invàlida: '%s'"
+
+msgid "sort() argument"
+msgstr "argument a sort()"
+
+msgid "uniq() argument"
+msgstr "argument a uniq()"
+
+msgid "E702: Sort compare function failed"
+msgstr "E702: La funció de comparació a sort() ha fallat"
+
+msgid "E882: Uniq compare function failed"
+msgstr "E882: La funció de comparació a unique() ha fallat"
+
+msgid "(Invalid)"
+msgstr "(No vàlid)"
+
+#, c-format
+msgid "E935: invalid submatch number: %d"
+msgstr "E935: referència invàlida a una coincidència: %d"
+
+msgid "E677: Error writing temp file"
+msgstr "E677: Error en escriure el fitxer temporal"
+
+msgid "E921: Invalid callback argument"
+msgstr "E921: L'argument del callback no és vàlid"
+
+# E.G: :ascii
+#, c-format
+msgid "<%s>%s%s %d, Hex %02x, Octal %03o"
+msgstr "<%s>%s%s %d, Hex %02x, Octal %03o"
+
+# E.G: :ascii
+#, c-format
+msgid "> %d, Hex %04x, Octal %o"
+msgstr "> %d, Hex %04x, Octal %o"
+
+# E.G: :ascii
+#, c-format
+msgid "> %d, Hex %08x, Octal %o"
+msgstr "> %d, Hex %08x, Octal %o"
+
+msgid "E134: Move lines into themselves"
+msgstr "E134: No es poden moure línies cap a elles mateixes"
+
+msgid "1 line moved"
+msgstr "1 línia desplaçada"
+
+#, c-format
+msgid "%ld lines moved"
+msgstr "%ld línies desplaçades"
+
+#, c-format
+msgid "%ld lines filtered"
+msgstr "%ld línies filtrades"
+
+msgid "E135: *Filter* Autocommands must not change current buffer"
+msgstr "E135: Les ordres automàtiques *Filter* han de no modificar el buffer"
+
+msgid "[No write since last change]\n"
+msgstr "[No s'han desat els últims canvis]\n"
+
+#, c-format
+msgid "%sviminfo: %s in line: "
+msgstr "%sviminfo: %s a la línia: "
+
+msgid "E136: viminfo: Too many errors, skipping rest of file"
+msgstr "E136: viminfo: Hi ha massa errors, s'omet la resta del fitxer"
+
+# vim -V5
+#, c-format
+msgid "Reading viminfo file \"%s\"%s%s%s"
+msgstr "Llegint el fitxer viminfo \"%s\"%s%s%s"
+
+msgid " info"
+msgstr " / info"
+
+msgid " marks"
+msgstr " / marques"
+
+msgid " oldfiles"
+msgstr " / fitxers vells"
+
+msgid " FAILED"
+msgstr " ERROR"
+
+#, c-format
+msgid "E137: Viminfo file is not writable: %s"
+msgstr "E137: El fitxer viminfo no és modificable: %s"
+
+#, c-format
+msgid "E929: Too many viminfo temp files, like %s!"
+msgstr "E929: Massa fitxers viminfo temporals, anomenats %s!"
+
+#, c-format
+msgid "E138: Can't write viminfo file %s!"
+msgstr "E138: No s'ha pogut escriure el fitxer viminfo %s!"
+
+#, c-format
+msgid "Writing viminfo file \"%s\""
+msgstr "Escrivint el fitxer viminfo \"%s\""
+
+#, c-format
+msgid "E886: Can't rename viminfo file to %s!"
+msgstr "E886: No s'ha pogut reanomenar el fitxer viminfo a %s!"
+
+#, c-format
+msgid "# This viminfo file was generated by Vim %s.\n"
+msgstr "# Aquest fitxer viminfo ha estat generat per Vim %s.\n"
+
+msgid ""
+"# You may edit it if you're careful!\n"
+"\n"
+msgstr ""
+"# El podeu editar si aneu amb compte!\n"
+"\n"
+
+msgid "# Value of 'encoding' when this file was written\n"
+msgstr "# Valor de 'encoding' en el moment d'escriure aquest fitxer\n"
+
+msgid "Illegal starting char"
+msgstr "Caràcter inicial il·legal"
+
+# viminfo
+msgid ""
+"\n"
+"# Bar lines, copied verbatim:\n"
+msgstr "\n# Línies copiades literalment sense modificar:\n"
+
+# GUI :browse w
+msgid "Save As"
+msgstr "Anomena i desa"
+
+msgid "Write partial file?"
+msgstr "Voleu escriure un fitxer parcial?"
+
+msgid "E140: Use ! to write partial buffer"
+msgstr "E140: Useu ! per a desar una part del buffer"
+
+#, c-format
+msgid "Overwrite existing file \"%s\"?"
+msgstr "Voleu sobreescriure el fitxer existent \"%s\"?"
+
+#, c-format
+msgid "Swap file \"%s\" exists, overwrite anyway?"
+msgstr "El fitxer d'intercanvi \"%s\" existeix, sobreescriure igualment?"
+
+#, c-format
+msgid "E768: Swap file exists: %s (:silent! overrides)"
+msgstr "E768: El fitxer d'intercanvi existeix: %s (:silent! per a forçar)"
+
+#, c-format
+msgid "E141: No file name for buffer %ld"
+msgstr "E141: No hi ha nom de fitxer per al buffer %ld"
+
+msgid "E142: File not written: Writing is disabled by 'write' option"
+msgstr "E142: No s'ha escrit el fitxer: El paràmetre 'write' ho impedeix"
+
+#, c-format
+msgid ""
+"'readonly' option is set for \"%s\".\n"
+"Do you wish to write anyway?"
+msgstr ""
+"S'ha establert l'opció 'readonly' per a \"%s\".\n"
+"Voleu escriure de totes maneres?"
+
+#, c-format
+msgid ""
+"File permissions of \"%s\" are read-only.\n"
+"It may still be possible to write it.\n"
+"Do you wish to try?"
+msgstr ""
+"El fitxer \"%s\" és de només lectura.\n"
+"Tot i això pot ser possible escriure-hi.\n"
+"Voleu intentar-ho?"
+
+#, c-format
+msgid "E505: \"%s\" is read-only (add ! to override)"
+msgstr "E505: \"%s\" és de només lectura (afegiu ! per a forçar)"
+
+# :browse edit
+msgid "Edit File"
+msgstr "Edita un fitxer"
+
+#, c-format
+msgid "E143: Autocommands unexpectedly deleted new buffer %s"
+msgstr "E143: Una ordre automàtica ha eliminat el nou buffer %s"
+
+msgid "E144: non-numeric argument to :z"
+msgstr "E144: Argument no numèric a :z"
+
+msgid "E145: Shell commands not allowed in rvim"
+msgstr "E145: El mode restringit no permet executar ordres de l'intèrpret"
+
+msgid "E146: Regular expressions can't be delimited by letters"
+msgstr "E146: Expressions regulars delimitades amb caràcters alfabètics"
+
+#, c-format
+msgid "replace with %s (y/n/a/q/l/^E/^Y)?"
+msgstr "substituir per %s (y/n/a/q/l/^E/^Y)?"
+
+msgid "(Interrupted) "
+msgstr "(Interromput) "
+
+msgid "1 match"
+msgstr "1 coincidència "
+
+msgid "1 substitution"
+msgstr "1 substitució"
+
+#, c-format
+msgid "%ld matches"
+msgstr "%ld coincidències"
+
+#, c-format
+msgid "%ld substitutions"
+msgstr "%ld substitucions"
+
+msgid " on 1 line"
+msgstr " en 1 línia"
+
+#, c-format
+msgid " on %ld lines"
+msgstr " en %ld línies"
+
+msgid "E147: Cannot do :global recursive with a range"
+msgstr "E147: No és possible usar :global recursivament amb un interval"
+
+# :g
+msgid "E148: Regular expression missing from global"
+msgstr "E148: Falta una expressió regular a :global"
+
+#, c-format
+msgid "Pattern found in every line: %s"
+msgstr "El patró apareix a totes les línies: %s"
+
+#, c-format
+msgid "Pattern not found: %s"
+msgstr "No s'ha trobat el patró: %s"
+
+msgid ""
+"\n"
+"# Last Substitute String:\n"
+"$"
+msgstr ""
+"\n"
+"# Última cadena substituïda:\n"
+"$"
+
+msgid "E478: Don't panic!"
+msgstr "E478: Mantingueu la calma!"
+
+#, c-format
+msgid "E661: Sorry, no '%s' help for %s"
+msgstr "E661: No hi ha ajuda en '%s' sobre %s"
+
+# :h zzzzzzzzz
+#, c-format
+msgid "E149: Sorry, no help for %s"
+msgstr "E149: No hi ha ajuda sobre %s"
+
+#, c-format
+msgid "Sorry, help file \"%s\" not found"
+msgstr "No s'ha trobat el fitxer d'ajuda \"%s\""
+
+#, c-format
+msgid "E151: No match: %s"
+msgstr "E151: Cap coincidència: %s"
+
+#, c-format
+msgid "E152: Cannot open %s for writing"
+msgstr "E152: No es obrir %s per a escriptura"
+
+#, c-format
+msgid "E153: Unable to open %s for reading"
+msgstr "E153: No es pot obrir %s per a lectura"
+
+#, c-format
+msgid "E670: Mix of help file encodings within a language: %s"
+msgstr "E670: Fitxers d'ajuda amb codificacions heterogènies: %s"
+
+#, c-format
+msgid "E154: Duplicate tag \"%s\" in file %s/%s"
+msgstr "E154: L'etiqueta \"%s\" està duplicada en el fitxer %s/%s"
+
+#, c-format
+msgid "E150: Not a directory: %s"
+msgstr "E150: No és un directori: %s"
+
+#, c-format
+msgid "E160: Unknown sign command: %s"
+msgstr "E160: Ordre de senyals desconeguda: %s"
+
+msgid "E156: Missing sign name"
+msgstr "E156: Falta el nom del senyal"
+
+msgid "E612: Too many signs defined"
+msgstr "E612: S'han definit massa senyals"
+
+#, c-format
+msgid "E239: Invalid sign text: %s"
+msgstr "E239: El text del senyal no és vàlid: %s"
+
+#, c-format
+msgid "E155: Unknown sign: %s"
+msgstr "E155: El senyal és desconegut: %s"
+
+msgid "E159: Missing sign number"
+msgstr "E159: Falta el número del senyal"
+
+#, c-format
+msgid "E158: Invalid buffer name: %s"
+msgstr "E158: El nom del buffer no és vàlid: %s"
+
+msgid "E934: Cannot jump to a buffer that does not have a name"
+msgstr "E934: No és possible saltar a un buffer que no té nom"
+
+#, c-format
+msgid "E157: Invalid sign ID: %ld"
+msgstr "E157: L'ID del senyal no és vàlid: %ld"
+
+#, c-format
+msgid "E885: Not possible to change sign %s"
+msgstr "E885: No és possible canviar el senyal %s"
+
+msgid " (NOT FOUND)"
+msgstr " (NO TROBAT)"
+
+msgid " (not supported)"
+msgstr " (no suportat)"
+
+msgid "[Deleted]"
+msgstr "[Eliminat]"
+
+msgid "No old files"
+msgstr "No hi ha fitxers antics"
+
+msgid "Entering Debug mode. Type \"cont\" to continue."
+msgstr "Mode de depuració. Escriviu \"cont\" per a continuar."
+
+#, c-format
+msgid "line %ld: %s"
+msgstr "línia %ld: %s"
+
+#, c-format
+msgid "cmd: %s"
+msgstr "ordre: %s"
+
+msgid "frame is zero"
+msgstr "el marc és zero"
+
+#, c-format
+msgid "frame at highest level: %d"
+msgstr "marc al nivell màxim: %d"
+
+#, c-format
+msgid "Breakpoint in \"%s%s\" line %ld"
+msgstr "Punt de ruptura a \"%s%s\" línia %ld"
+
+#, c-format
+msgid "E161: Breakpoint not found: %s"
+msgstr "E161: Punt de ruptura no trobat: %s"
+
+msgid "No breakpoints defined"
+msgstr "No s'han definit punts de ruptura"
+
+#, c-format
+msgid "%3d %s %s line %ld"
+msgstr "%3d %s %s línia %ld"
+
+msgid "E750: First use \":profile start {fname}\""
+msgstr "E750: Primer feu \":profile start {nomfitxer}\""
+
+#, c-format
+msgid "Save changes to \"%s\"?"
+msgstr "Voleu desar els canvis a \"%s\"?"
+
+msgid "Untitled"
+msgstr "Sense-nom"
+
+#, c-format
+msgid "E162: No write since last change for buffer \"%s\""
+msgstr "E162: No s'han desat els canvis en el buffer \"%s\""
+
+msgid "Warning: Entered other buffer unexpectedly (check autocommands)"
+msgstr "Atenció: S'ha canviat de buffer (reviseu les ordres automàtiques)"
+
+msgid "E163: There is only one file to edit"
+msgstr "E163: Només hi ha un fitxer per editar"
+
+msgid "E164: Cannot go before first file"
+msgstr "E164: No es pot anar més enllà del primer fitxer"
+
+msgid "E165: Cannot go beyond last file"
+msgstr "E165: No es pot anar més enllà de l'últim fitxer"
+
+#, c-format
+msgid "E666: compiler not supported: %s"
+msgstr "E666: el compilador no està suportat: %s"
+
+#, c-format
+msgid "Searching for \"%s\" in \"%s\""
+msgstr "Cercant \"%s\" a \"%s\""
+
+#, c-format
+msgid "Searching for \"%s\""
+msgstr "Cercant \"%s\""
+
+#, c-format
+msgid "not found in '%s': \"%s\""
+msgstr "no s'ha trobat a '%s': \"%s\""
+
+#, c-format
+msgid "W20: Required python version 2.x not supported, ignoring file: %s"
+msgstr "W20: la versió 2.x de Python està suportada, s'ignora: %s"
+
+#, c-format
+msgid "W21: Required python version 3.x not supported, ignoring file: %s"
+msgstr "W21: La versió 3.x de Python no està suportada, s'ignora: %s"
+
+# :browse source
+msgid "Source Vim script"
+msgstr "Executa un script Vim"
+
+#, c-format
+msgid "Cannot source a directory: \"%s\""
+msgstr "No és possible executar un directori: \"%s\""
+
+#, c-format
+msgid "could not source \"%s\""
+msgstr "no s'ha pogut executar \"%s\""
+
+#, c-format
+msgid "line %ld: could not source \"%s\""
+msgstr "línia %ld: no s'ha pogut executar \"%s\""
+
+#, c-format
+msgid "sourcing \"%s\""
+msgstr "executant \"%s\""
+
+#, c-format
+msgid "line %ld: sourcing \"%s\""
+msgstr "línia %ld: executant \"%s\""
+
+#, c-format
+msgid "finished sourcing %s"
+msgstr "ha finalitzat l'execució de %s"
+
+#, c-format
+msgid "continuing in %s"
+msgstr "continuant a %s"
+
+msgid "modeline"
+msgstr "línia de mode"
+
+msgid "--cmd argument"
+msgstr "argument --cmd"
+
+msgid "-c argument"
+msgstr "argument -c"
+
+msgid "environment variable"
+msgstr "variable d'entorn"
+
+# todo: handler
+msgid "error handler"
+msgstr "conductor d'errors"
+
+msgid "W15: Warning: Wrong line separator, ^M may be missing"
+msgstr "W15: Atenció: Separador de línia incorrecte, potser falta un ^M"
+
+msgid "E167: :scriptencoding used outside of a sourced file"
+msgstr "E167: ús de :scriptencoding fora d'un script"
+
+msgid "E168: :finish used outside of a sourced file"
+msgstr "E168: ús de :finish fora d'un script"
+
+#, c-format
+msgid "Current %slanguage: \"%s\""
+msgstr "Idioma actual ( %s): \"%s\""
+
+#, c-format
+msgid "E197: Cannot set language to \"%s\""
+msgstr "E197: No s'ha pogut canviar l'idioma a \"%s\""
+
+msgid "Entering Ex mode. Type \"visual\" to go to Normal mode."
+msgstr "Mode Ex. Escriviu \"visual\" per a tornar al mode Normal."
+
+msgid "E501: At end-of-file"
+msgstr "E501: Final del fitxer"
+
+msgid "E169: Command too recursive"
+msgstr "E169: L'ordre és massa recursiva"
+
+#, c-format
+msgid "E605: Exception not caught: %s"
+msgstr "E605: No s'ha interceptat l'excepció: %s"
+
+msgid "End of sourced file"
+msgstr "Final de l'script"
+
+msgid "End of function"
+msgstr "Final de la funció"
+
+msgid "E464: Ambiguous use of user-defined command"
+msgstr "E464: Ús ambigu d'una ordre definida per l'usuari"
+
+msgid "E492: Not an editor command"
+msgstr "E492: No és una ordre de l'editor"
+
+msgid "E493: Backwards range given"
+msgstr "E493: Interval decreixent"
+
+# és una pregunta.
+msgid "Backwards range given, OK to swap"
+msgstr "Interval decreixent. El voleu invertir"
+
+msgid "E494: Use w or w>>"
+msgstr "E494: Useu w o bé w>>"
+
+msgid "E943: Command table needs to be updated, run 'make cmdidxs'"
+msgstr "E943: La taula d'ordres s'ha d'actualitzar, executeu 'make cmdidxs'"
+
+msgid "E319: Sorry, the command is not available in this version"
+msgstr "E319: Aquesta ordre no està disponible en aquesta versió"
+
+msgid "E172: Only one file name allowed"
+msgstr "E172: Només podeu especificar un nom de fitxer"
+
+msgid "1 more file to edit. Quit anyway?"
+msgstr "Queda 1 fitxer per editar. Voleu sortir de totes maneres?"
+
+#, c-format
+msgid "%d more files to edit. Quit anyway?"
+msgstr "Queden %d fitxers per editar. Voleu sortir de totes maneres?"
+
+msgid "E173: 1 more file to edit"
+msgstr "E173: Queda 1 fitxer per editar"
+
+#, c-format
+msgid "E173: %ld more files to edit"
+msgstr "E173: Queden %ld fitxers per editar"
+
+msgid "E174: Command already exists: add ! to replace it"
+msgstr "E174: L'ordre ja existeix: afegiu ! per a substituir-la"
+
+# :command
+# <l><l><l><l><l>
+msgid ""
+"\n"
+" Name Args Address Complete Definition"
+msgstr "\n Nom Arguments Adreça Compleció Definició "
+
+msgid "No user-defined commands found"
+msgstr "No s'han trobat ordres definides per l'usuari"
+
+msgid "E175: No attribute specified"
+msgstr "E175: No heu especificat cap atribut"
+
+msgid "E176: Invalid number of arguments"
+msgstr "E176: El nombre d'arguments no és vàlid"
+
+msgid "E177: Count cannot be specified twice"
+msgstr "E177: El paràmetre de quantitat no es pot especificar dos cops"
+
+msgid "E178: Invalid default value for count"
+msgstr "E178: El valor per omissió del paràmetre de quantitat no és vàlid"
+
+# :command -complete Echo :echo "foo"
+msgid "E179: argument required for -complete"
+msgstr "E179: l'atribut -complete requereix un argument"
+
+msgid "E179: argument required for -addr"
+msgstr "E179: l'atribut -addr requereix un argument"
+
+# :command -foo Foo :echo "bar"
+#, c-format
+msgid "E181: Invalid attribute: %s"
+msgstr "E181: L'atribut no és vàlid: %s"
+
+msgid "E182: Invalid command name"
+msgstr "E182: El nom de l'ordre no és vàlid"
+
+msgid "E183: User defined commands must start with an uppercase letter"
+msgstr "E183: Les ordres definides per l'usuari han de començar amb majúscula"
+
+msgid "E841: Reserved name, cannot be used for user defined command"
+msgstr "E841: Nom reservat, no es pot usar com a ordre definida per l'usuari"
+
+#, c-format
+msgid "E184: No such user-defined command: %s"
+msgstr "E184: No existeix tal ordre definida per l'usuari: %s"
+
+# :command -addr=foo Bar :echo "bar"
+#, c-format
+msgid "E180: Invalid address type value: %s"
+msgstr "E180: El tipus d'adreça no és vàlid: %s"
+
+#, c-format
+msgid "E180: Invalid complete value: %s"
+msgstr "E180: El tipus de compleció no és vàlid: %s"
+
+msgid "E468: Completion argument only allowed for custom completion"
+msgstr "E468: La compleció estàndard no admet arguments"
+
+msgid "E467: Custom completion requires a function argument"
+msgstr "E467: La compleció no estàndard requereix una funció com a argument"
+
+# esquema de colors
+msgid "unknown"
+msgstr "desconegut"
+
+#, c-format
+msgid "E185: Cannot find color scheme '%s'"
+msgstr "E185: No s'ha trobat l'esquema de colors '%s'"
+
+msgid "Greetings, Vim user!"
+msgstr "Salutacions, usuari de Vim!"
+
+msgid "E784: Cannot close last tab page"
+msgstr "E784: No és possible tancar l'última pestanya"
+
+msgid "Already only one tab page"
+msgstr "Només hi ha una pestanya"
+
+# :browse split
+msgid "Edit File in new window"
+msgstr "Edita un fitxer en una finestra nova"
+
+#, c-format
+msgid "Tab page %d"
+msgstr "Pestanya %d"
+
+msgid "No swap file"
+msgstr "No existeix cap fitxer d'intercanvi"
+
+# :browse read
+msgid "Append File"
+msgstr "Afegeix un fitxer"
+
+msgid "E747: Cannot change directory, buffer is modified (add ! to override)"
+msgstr "E747: Buffer modificat, no es canvia de directori (! per a forçar)"
+
+msgid "E186: No previous directory"
+msgstr "E186: No hi ha cap directori anterior"
+
+msgid "E187: Unknown"
+msgstr "E187: Desconegut"
+
+msgid "E465: :winsize requires two number arguments"
+msgstr "E465: :winsize requereix dos arguments numèrics"
+
+#, c-format
+msgid "Window position: X %d, Y %d"
+msgstr "Posició de la finestra: X %d, Y %d"
+
+msgid "E188: Obtaining window position not implemented for this platform"
+msgstr "E188: Aquesta plataforma no permet obtenir la posició de la finestra"
+
+msgid "E466: :winpos requires two number arguments"
+msgstr "E466: :winpos requereix dos arguments numèrics"
+
+msgid "E930: Cannot use :redir inside execute()"
+msgstr "E930: No es pot utilitzar :redir a dins de execute()"
+
+msgid "Save Redirection"
+msgstr "Desa la redirecció"
+
+# :browse mkview
+msgid "Save View"
+msgstr "Desa la vista"
+
+# :browse mksession
+msgid "Save Session"
+msgstr "Desa la sessió"
+
+# :browse mkvimrc
+msgid "Save Setup"
+msgstr "Desa la configuració"
+
+#, c-format
+msgid "E739: Cannot create directory: %s"
+msgstr "E739: No s'ha pogut crear el directori: %s"
+
+#, c-format
+msgid "E189: \"%s\" exists (add ! to override)"
+msgstr "E189: \"%s\" existeix (afegiu ! per a forçar)"
+
+#, c-format
+msgid "E190: Cannot open \"%s\" for writing"
+msgstr "E190: No es pot obrir \"%s\" per a escriptura"
+
+msgid "E191: Argument must be a letter or forward/backward quote"
+msgstr "E191: L'argument ha de ser una lletra o bé un accent obert o tancat"
+
+msgid "E192: Recursive use of :normal too deep"
+msgstr "E192: Ús de :normal amb un grau de recursivitat massa elevat"
+
+msgid "E809: #< is not available without the +eval feature"
+msgstr "E809: #< no està disponible sense la característica +eval"
+
+msgid "E194: No alternate file name to substitute for '#'"
+msgstr "E194: no hi ha cap nom de fitxer alternatiu per substituir"
+
+msgid "E495: no autocommand file name to substitute for \"<afile>\""
+msgstr "E495: no hi ha cap nom de fitxer d'ordres automàtiques per substituir"
+
+msgid "E496: no autocommand buffer number to substitute for \"<abuf>\""
+msgstr "E496: no hi ha cap buffer d'ordres automàtiques per substituir"
+
+msgid "E497: no autocommand match name to substitute for \"<amatch>\""
+msgstr "E497: no hi ha cap coincidència d'ordre automàtica per substituir"
+
+msgid "E498: no :source file name to substitute for \"<sfile>\""
+msgstr "E498: no hi ha cap nom de fitxer :source per substituir"
+
+msgid "E842: no line number to use for \"<slnum>\""
+msgstr "E842: no hi ha cap script per substituir \"<sfile>\""
+
+#, no-c-format
+msgid "E499: Empty file name for '%' or '#', only works with \":p:h\""
+msgstr "E499: Nom de fitxer per a '%' o '#' en blanc, només funciona amb \":p:h\""
+
+msgid "E500: Evaluates to an empty string"
+msgstr "E500: L'avaluació és una cadena en blanc"
+
+msgid "E195: Cannot open viminfo file for reading"
+msgstr "E195: No s'ha pogut obrir el fitxer viminfo per a lectura"
+
+msgid "E196: No digraphs in this version"
+msgstr "E196: Aquesta versió no suporta dígrafs"
+
+msgid "E608: Cannot :throw exceptions with 'Vim' prefix"
+msgstr "E608: No és possible generar excepcions amb el prefix 'Vim'"
+
+#, c-format
+msgid "Exception thrown: %s"
+msgstr "Excepció generada: %s"
+
+#, c-format
+msgid "Exception finished: %s"
+msgstr "Excepció finalitzada: %s"
+
+#, c-format
+msgid "Exception discarded: %s"
+msgstr "Excepció descartada: %s"
+
+#, c-format
+msgid "%s, line %ld"
+msgstr "%s, línia %ld"
+
+#, c-format
+msgid "Exception caught: %s"
+msgstr "Excepció interceptada: %s"
+
+#, c-format
+msgid "%s made pending"
+msgstr "%s s'ha posposat"
+
+#, c-format
+msgid "%s resumed"
+msgstr "%s s'ha continuat"
+
+#, c-format
+msgid "%s discarded"
+msgstr "%s s'ha descartat"
+
+msgid "Exception"
+msgstr "Excepció"
+
+msgid "Error and interrupt"
+msgstr "Error i interrupció"
+
+msgid "Error"
+msgstr "Error"
+
+msgid "Interrupt"
+msgstr "Interrupció"
+
+msgid "E579: :if nesting too deep"
+msgstr "E579: nivell d'imbricació :if massa elevat"
+
+msgid "E580: :endif without :if"
+msgstr "E580: :endif sense :if"
+
+msgid "E581: :else without :if"
+msgstr "E581: :else sense :if"
+
+msgid "E582: :elseif without :if"
+msgstr "E582: :elseif sense :if"
+
+msgid "E583: multiple :else"
+msgstr "E583: múltiples :else"
+
+msgid "E584: :elseif after :else"
+msgstr "E584: :elseif després de :else"
+
+msgid "E585: :while/:for nesting too deep"
+msgstr "E585: nivell d'imbricació :while/:for massa elevat"
+
+msgid "E586: :continue without :while or :for"
+msgstr "E586: :continue sense :while o :for"
+
+msgid "E587: :break without :while or :for"
+msgstr "E587: :break sense :while"
+
+msgid "E732: Using :endfor with :while"
+msgstr "E732: Ús de :endfor amb :while"
+
+msgid "E733: Using :endwhile with :for"
+msgstr "E733: Ús de :endwhile amb :for"
+
+msgid "E601: :try nesting too deep"
+msgstr "E601: nivell d'imbricació :try massa elevat"
+
+msgid "E603: :catch without :try"
+msgstr "E603: :catch sense :try"
+
+msgid "E604: :catch after :finally"
+msgstr "E604: :catch després de :finally"
+
+msgid "E606: :finally without :try"
+msgstr "E606: :finally sense :try"
+
+msgid "E607: multiple :finally"
+msgstr "E607: múltiples :finally"
+
+msgid "E602: :endtry without :try"
+msgstr "E602: :endtry sense :try"
+
+msgid "E193: :endfunction not inside a function"
+msgstr "E193: :endfunction fora d'una funció"
+
+msgid "E788: Not allowed to edit another buffer now"
+msgstr "E788: No està permès editar un altre buffer ara"
+
+msgid "E811: Not allowed to change buffer information now"
+msgstr "E811: No està permès canviar la informació del buffer ara"
+
+# :set wop=tagfile
+# :ts <C-d>
+msgid "tagname"
+msgstr "etiqueta"
+
+# <r><l>
+msgid " kind file\n"
+msgstr " tip fitxer\n"
+
+msgid "'history' option is zero"
+msgstr "el paràmetre 'history' és zero"
+
+#, c-format
+msgid ""
+"\n"
+"# %s History (newest to oldest):\n"
+msgstr ""
+"\n"
+"# Historial %s (de més a menys recent):\n"
+
+msgid "Command Line"
+msgstr "de la línia d'ordres"
+
+msgid "Search String"
+msgstr "de cerques"
+
+msgid "Expression"
+msgstr "d'expressions"
+
+msgid "Input Line"
+msgstr "de línies d'entrada"
+
+msgid "Debug Line"
+msgstr "d'ordres de depuració"
+
+msgid "E198: cmd_pchar beyond the command length"
+msgstr "E198: cmd_pchar fora de l'àrea de l'ordre"
+
+msgid "E199: Active window or buffer deleted"
+msgstr "E199: S'ha eliminat la finestra o el buffer actiu"
+
+msgid "E812: Autocommands changed buffer or buffer name"
+msgstr "E812: Ordres automàtiques han canviat el buffer o el nom del buffer"
+
+msgid "Illegal file name"
+msgstr "El nom de fitxer és il·legal"
+
+msgid "is a directory"
+msgstr "és un directori"
+
+msgid "is not a file"
+msgstr "no és un fitxer"
+
+msgid "is a device (disabled with 'opendevice' option)"
+msgstr "és un dispositiu (deshabilitat amb el paràmetre 'opendevice')"
+
+msgid "[New File]"
+msgstr "[Fitxer nou]"
+
+msgid "[New DIRECTORY]"
+msgstr "[Nou DIRECTORI]"
+
+msgid "[File too big]"
+msgstr "[Fitxer massa gran]"
+
+msgid "[Permission Denied]"
+msgstr "[Permís denegat]"
+
+msgid "E200: *ReadPre autocommands made the file unreadable"
+msgstr "E200: Ordres automàtiques *ReadPre han deixat el fitxer illegible"
+
+msgid "E201: *ReadPre autocommands must not change current buffer"
+msgstr "E201: Les ordres automàtiques *ReadPre han de no modificar el buffer"
+
+msgid "Vim: Reading from stdin...\n"
+msgstr "Vim: Llegint l'entrada estàndard...\n"
+
+msgid "Reading from stdin..."
+msgstr "Llegint l'entrada estàndard..."
+
+msgid "E202: Conversion made file unreadable!"
+msgstr "E202: La conversió ha deixat el fitxer illegible!"
+
+msgid "[fifo/socket]"
+msgstr "[fifo/socket]"
+
+msgid "[fifo]"
+msgstr "[fifo]"
+
+msgid "[socket]"
+msgstr "[socket]"
+
+msgid "[character special]"
+msgstr "[caràcter especial]"
+
+msgid "[CR missing]"
+msgstr "[falta retorn-de-carro]"
+
+msgid "[long lines split]"
+msgstr "[línies llargues partides]"
+
+msgid "[NOT converted]"
+msgstr "[NO convertit]"
+
+msgid "[converted]"
+msgstr "[convertit]"
+
+#, c-format
+msgid "[CONVERSION ERROR in line %ld]"
+msgstr "[ERROR DE CONVERSIÓ a la línia %ld]"
+
+#, c-format
+msgid "[ILLEGAL BYTE in line %ld]"
+msgstr "[OCTET IL·LEGAL a la línia %ld]"
+
+msgid "[READ ERRORS]"
+msgstr "[ERRORS DE LECTURA]"
+
+msgid "Can't find temp file for conversion"
+msgstr "No s'ha trobat el fitxer temporal per a fer la conversió"
+
+msgid "Conversion with 'charconvert' failed"
+msgstr "La conversió amb 'charconvert' ha fallat"
+
+msgid "can't read output of 'charconvert'"
+msgstr "No s'ha pogut llegir la sortida de 'charconvert'"
+
+msgid "E676: No matching autocommands for acwrite buffer"
+msgstr "E676: No hi ha ordres automàtiques coincidents amb acwrite"
+
+msgid "E203: Autocommands deleted or unloaded buffer to be written"
+msgstr "E203: Ordres automàtiques han eliminat o alliberat el buffer"
+
+msgid "E204: Autocommand changed number of lines in unexpected way"
+msgstr "E204: Una ordre automàtica ha canviat el nombre de línies"
+
+msgid "NetBeans disallows writes of unmodified buffers"
+msgstr "NetBeans no permet escriure buffers no modificats"
+
+msgid "Partial writes disallowed for NetBeans buffers"
+msgstr "L'escriptura parcial no està permesa a buffers NetBeans"
+
+msgid "is not a file or writable device"
+msgstr "no és un fitxer o dispositiu que es pugui escriure"
+
+msgid "writing to device disabled with 'opendevice' option"
+msgstr "escriptura a dispositius deshabilitada amb el paràmetre 'opendevice'"
+
+msgid "is read-only (add ! to override)"
+msgstr "és de només lectura (afegiu ! per a forçar)"
+
+msgid "E506: Can't write to backup file (add ! to override)"
+msgstr "E506: No s'ha pogut escriure la còpia de seguretat (! per a forçar)"
+
+msgid "E507: Close error for backup file (add ! to override)"
+msgstr "E507: Error en tancar la còpia de seguretat (afegiu ! per a forçar)"
+
+msgid "E508: Can't read file for backup (add ! to override)"
+msgstr "E508: Error de lectura en fer la còpia de seguretat (! per a forçar)"
+
+msgid "E509: Cannot create backup file (add ! to override)"
+msgstr "E509: No s'ha pogut crear la còpia de seguretat (! per a forçar)"
+
+msgid "E510: Can't make backup file (add ! to override)"
+msgstr "E510: No s'ha pogut fer la còpia de seguretat (! per a forçar)"
+
+# MacOS
+msgid "E460: The resource fork would be lost (add ! to override)"
+msgstr "E460: La secció de recursos del fitxer es perdrà (afegiu ! per a forçar)"
+
+msgid "E214: Can't find temp file for writing"
+msgstr "E214: No s'ha trobat el fitxer temporal"
+
+msgid "E213: Cannot convert (add ! to write without conversion)"
+msgstr "E213: No s'ha pogut convertir (! per a desar sense convertir)"
+
+msgid "E166: Can't open linked file for writing"
+msgstr "E166: No s'ha pogut obrir el fitxer enllaçat"
+
+msgid "E212: Can't open file for writing"
+msgstr "E212: No s'ha pogut obrir el fitxer per a escriptura"
+
+msgid "E667: Fsync failed"
+msgstr "E667: Fsync ha fallat"
+
+msgid "E512: Close failed"
+msgstr "E512: Error en tancar"
+
+msgid "E513: write error, conversion failed (make 'fenc' empty to override)"
+msgstr "E513: ha fallat la conversió (anul·leu l'opció 'fenc' per a ometre)"
+
+#, c-format
+msgid ""
+"E513: write error, conversion failed in line %ld (make 'fenc' empty to "
+"override)"
+msgstr "E513: error de conversió, línia %ld (anul·leu l'opció 'fenc' per a ometre)"
+
+msgid "E514: write error (file system full?)"
+msgstr "E514: Error d'escriptura (sistema de fitxers ple?)"
+
+msgid " CONVERSION ERROR"
+msgstr " ERROR DE CONVERSIÓ"
+
+#, c-format
+msgid " in line %ld;"
+msgstr " a la línia %ld"
+
+msgid "[Device]"
+msgstr "[Dispositiu]"
+
+msgid "[New]"
+msgstr "[Nou]"
+
+msgid " [a]"
+msgstr " [a]"
+
+msgid " appended"
+msgstr " afegits"
+
+msgid " [w]"
+msgstr " [e]"
+
+msgid " written"
+msgstr " escrits"
+
+msgid "E205: Patchmode: can't save original file"
+msgstr "E205: patchmode: no s'ha pogut desar el fitxer original"
+
+msgid "E206: patchmode: can't touch empty original file"
+msgstr "E206: patchmode: no s'ha pogut fer un toc al fitxer original buit"
+
+msgid "E207: Can't delete backup file"
+msgstr "E207: No s'ha pogut eliminar la còpia de seguretat"
+
+msgid ""
+"\n"
+"WARNING: Original file may be lost or damaged\n"
+msgstr "\nATENCIÓ: El fitxer original es pot haver perdut o fet malbé\n"
+
+msgid "don't quit the editor until the file is successfully written!"
+msgstr "no sortiu de l'editor fins que s'hagi desat el fitxer amb èxit!"
+
+msgid "[dos]"
+msgstr "[dos]"
+
+msgid "[dos format]"
+msgstr "[format dos]"
+
+msgid "[mac]"
+msgstr "[mac]"
+
+msgid "[mac format]"
+msgstr "[format mac]"
+
+msgid "[unix]"
+msgstr "[unix]"
+
+msgid "[unix format]"
+msgstr "[format unix]"
+
+msgid "1 line, "
+msgstr "1 línia, "
+
+#, c-format
+msgid "%ld lines, "
+msgstr "%ld línies, "
+
+msgid "1 character"
+msgstr "1 caràcter"
+
+#, c-format
+msgid "%lld characters"
+msgstr "%lld caràcters"
+
+# eol = final de línia
+msgid "[noeol]"
+msgstr "[nofl]"
+
+msgid "[Incomplete last line]"
+msgstr "[Última línia incompleta]"
+
+msgid "WARNING: The file has been changed since reading it!!!"
+msgstr "ATENCIÓ: El fitxer ha canviat des de que s'ha llegit!!!"
+
+# pregunta ask_yesno()
+msgid "Do you really want to write to it"
+msgstr "Esteu segurs que voleu escriure'l"
+
+#, c-format
+msgid "E208: Error writing to \"%s\""
+msgstr "E208: Error en escriure \"%s\""
+
+#, c-format
+msgid "E209: Error closing \"%s\""
+msgstr "E209: Error en tancar \"%s\""
+
+#, c-format
+msgid "E210: Error reading \"%s\""
+msgstr "E210: Error en llegir \"%s\""
+
+msgid "E246: FileChangedShell autocommand deleted buffer"
+msgstr "E246: L'ordre automàtica FileChangedShell ha eliminat el buffer"
+
+#, c-format
+msgid "E211: File \"%s\" no longer available"
+msgstr "E211: El fitxer \"%s\" ha deixat d'estar disponible"
+
+#, c-format
+msgid ""
+"W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as "
+"well"
+msgstr "W12: Atenció: Tant el fitxer \"%s\" com el buffer del Vim han canviat"
+
+msgid "See \":help W12\" for more info."
+msgstr "Vegeu \":help W12\" per a més info."
+
+#, c-format
+msgid "W11: Warning: File \"%s\" has changed since editing started"
+msgstr "W11: Atenció: El fitxer \"%s\" ha canviat després de ser obert"
+
+msgid "See \":help W11\" for more info."
+msgstr "Vegeu \":help W11\" per a més info."
+
+#, c-format
+msgid "W16: Warning: Mode of file \"%s\" has changed since editing started"
+msgstr "W16: Atenció: Els permisos de \"%s\" han canviat després de ser obert"
+
+msgid "See \":help W16\" for more info."
+msgstr "Vegeu \":help W16\" per a més info."
+
+#, c-format
+msgid "W13: Warning: File \"%s\" has been created after editing started"
+msgstr "W13: Atenció: El fitxer \"%s\" ha estat creat després de ser obert"
+
+msgid "Warning"
+msgstr "Atenció"
+
+msgid ""
+"&OK\n"
+"&Load File"
+msgstr ""
+"&D'acord\n"
+"&Carrega el fitxer"
+
+#, c-format
+msgid "E462: Could not prepare for reloading \"%s\""
+msgstr "E462: No s'han pogut fer les preparacions per a rellegir \"%s\""
+
+#, c-format
+msgid "E321: Could not reload \"%s\""
+msgstr "E321: No s'ha pogut rellegir \"%s\""
+
+msgid "--Deleted--"
+msgstr "--Eliminat--"
+
+#, c-format
+msgid "auto-removing autocommand: %s <buffer=%d>"
+msgstr "s'elimina l'ordre automàtica: %s <buffer=%d>"
+
+#, c-format
+msgid "E367: No such group: \"%s\""
+msgstr "E367: No existeix tal grup: \"%s\""
+
+msgid "E936: Cannot delete the current group"
+msgstr "E936: No es pot eliminar el grup actual"
+
+msgid "W19: Deleting augroup that is still in use"
+msgstr "W19: S'elimina un grup d'ordres automàtiques que està en ús"
+
+#, c-format
+msgid "E215: Illegal character after *: %s"
+msgstr "E215: Caràcter il·legal després de *: %s"
+
+#, c-format
+msgid "E216: No such event: %s"
+msgstr "E216: No existeix tal esdeveniment: %s"
+
+#, c-format
+msgid "E216: No such group or event: %s"
+msgstr "E216: No existeix tal grup o esdeveniment: %s"
+
+msgid ""
+"\n"
+"--- Autocommands ---"
+msgstr "\n--- Ordres automàtiques ---"
+
+#, c-format
+msgid "E680: <buffer=%d>: invalid buffer number "
+msgstr "E680: <buffer=%d>: número de buffer no vàlid"
+
+# :do * Foo
+msgid "E217: Can't execute autocommands for ALL events"
+msgstr "E217: No es pot assignar una ordre a TOTS els esdeveniments"
+
+msgid "No matching autocommands"
+msgstr "No hi ha cap ordre automàtica coincident"
+
+msgid "E218: autocommand nesting too deep"
+msgstr "E218: nivell d'imbricació d'ordres automàtiques massa elevat"
+
+# todo: substitucions
+# <event> ... <pattern>
+#, c-format
+msgid "%s Autocommands for \"%s\""
+msgstr "Ordres automàtiques de %s per a \"%s\""
+
+#, c-format
+msgid "Executing %s"
+msgstr "Executant %s"
+
+#, c-format
+msgid "autocommand %s"
+msgstr "ordre automàtica %s"
+
+msgid "E219: Missing {."
+msgstr "E219: Falta un {."
+
+msgid "E220: Missing }."
+msgstr "E220: Falta un }."
+
+msgid "E490: No fold found"
+msgstr "E490: No s'ha trobat cap plec"
+
+msgid "E350: Cannot create fold with current 'foldmethod'"
+msgstr "E350: No és possible crear plecs amb el mètode seleccionat"
+
+msgid "E351: Cannot delete fold with current 'foldmethod'"
+msgstr "E351: No és possible eliminar plecs amb el mètode seleccionat"
+
+msgid "E222: Add to read buffer"
+msgstr "E222: No es pot modificar un buffer de lectura"
+
+msgid "E223: recursive mapping"
+msgstr "E223: assignació recursiva"
+
+#, c-format
+msgid "E224: global abbreviation already exists for %s"
+msgstr "E224: ja existeix una abreviació global per a %s"
+
+#, c-format
+msgid "E225: global mapping already exists for %s"
+msgstr "E225: ja existeix una assignació global per a %s"
+
+#, c-format
+msgid "E226: abbreviation already exists for %s"
+msgstr "E226: ja existeix una abreviació per a %s"
+
+#, c-format
+msgid "E227: mapping already exists for %s"
+msgstr "E227: ja existeix una assignació per a %s"
+
+msgid "No abbreviation found"
+msgstr "No s'ha trobat cap abreviació"
+
+msgid "No mapping found"
+msgstr "No s'ha trobat cap assignació"
+
+msgid "E228: makemap: Illegal mode"
+msgstr "E228: makemap: Mode il·legal"
+
+msgid "E851: Failed to create a new process for the GUI"
+msgstr "E851: No s'ha pogut crear un nou procés per a la interfície gràfica"
+
+msgid "E852: The child process failed to start the GUI"
+msgstr "E852: El procés fill no ha pogut crear la interfície gràfica"
+
+msgid "E229: Cannot start the GUI"
+msgstr "E229: No s'ha pogut iniciar la interfície gràfica"
+
+#, c-format
+msgid "E230: Cannot read from \"%s\""
+msgstr "E230: No s'ha pogut llegir \"%s\""
+
+msgid "E665: Cannot start GUI, no valid font found"
+msgstr "E665: Error en iniciar el GUI, no s'han trobat tipus de lletra"
+
+msgid "E231: 'guifontwide' invalid"
+msgstr "E231: El valor de 'guifontwide' no és vàlid"
+
+msgid "E599: Value of 'imactivatekey' is invalid"
+msgstr "E599: El valor de 'imactivatekey' no és vàlid"
+
+#, c-format
+msgid "E254: Cannot allocate color %s"
+msgstr "E254: No s'ha pogut assignar memòria per al color %s"
+
+msgid "No match at cursor, finding next"
+msgstr "Cap coincidència al cursor, cercant la següent"
+
+msgid "<cannot open> "
+msgstr "<no es pot obrir> "
+
+#, c-format
+msgid "E616: vim_SelFile: can't get font %s"
+msgstr "E616: vim_SelFile: no s'ha pogut obtenir la fosa %s"
+
+msgid "E614: vim_SelFile: can't return to current directory"
+msgstr "E614: vim_SelFile: no s'ha pogut tornar al directori actual"
+
+msgid "Pathname:"
+msgstr "Ubicació:"
+
+msgid "E615: vim_SelFile: can't get current directory"
+msgstr "E615: vim_SelFile: no s'ha pogut obtenir el directori actual"
+
+msgid "OK"
+msgstr "D'acord"
+
+msgid "Cancel"
+msgstr "Cancel·la"
+
+msgid "Scrollbar Widget: Could not get geometry of thumb pixmap."
+msgstr "Barra de desplaçament: No s'ha obtingut la mida del mapa de bits."
+
+msgid "Vim dialog"
+msgstr "Diàleg del Vim"
+
+msgid "E232: Cannot create BalloonEval with both message and callback"
+msgstr "E232: No es pot crear un BalloonEval amb missatge i callback alhora"
+
+msgid "_Cancel"
+msgstr "_Cancel·la"
+
+# :browse w
+msgid "_Save"
+msgstr "_Desa"
+
+msgid "_Open"
+msgstr "_Obre"
+
+msgid "_OK"
+msgstr "D'_acord"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"&Cancel"
+msgstr ""
+"&Sí\n"
+"&No\n"
+"&Cancel·la"
+
+msgid "Yes"
+msgstr "Sí"
+
+msgid "No"
+msgstr "No"
+
+msgid "Input _Methods"
+msgstr "_Mètodes d'entrada"
+
+msgid "VIM - Search and Replace..."
+msgstr "VIM - Cerca i substitueix..."
+
+msgid "VIM - Search..."
+msgstr "VIM - Cerca..."
+
+msgid "Find what:"
+msgstr "Cerca:"
+
+msgid "Replace with:"
+msgstr "Substitueix per:"
+
+msgid "Match whole word only"
+msgstr "Només paraules senceres"
+
+msgid "Match case"
+msgstr "Sensible a les majúscules"
+
+msgid "Direction"
+msgstr "Direcció"
+
+msgid "Up"
+msgstr "Amunt"
+
+msgid "Down"
+msgstr "Avall"
+
+msgid "Find Next"
+msgstr "Cerca el següent"
+
+msgid "Replace"
+msgstr "Substitueix"
+
+msgid "Replace All"
+msgstr "Substitueix-les totes"
+
+msgid "_Close"
+msgstr "_Tanca"
+
+msgid "Vim: Received \"die\" request from session manager\n"
+msgstr "Vim: S'ha rebut una petició \"die\" del gestor de sessions\n"
+
+msgid "Close tab"
+msgstr "Tanca la pestanya"
+
+msgid "New tab"
+msgstr "Nova pestanya"
+
+msgid "Open Tab..."
+msgstr "Obre una pestanya..."
+
+msgid "Vim: Main window unexpectedly destroyed\n"
+msgstr "Vim: La finestra principal s'ha destruït inesperadament\n"
+
+msgid "&Filter"
+msgstr "&Filtre"
+
+msgid "&Cancel"
+msgstr "&Cancel·la"
+
+msgid "Directories"
+msgstr "Directoris"
+
+msgid "Filter"
+msgstr "Filtre"
+
+msgid "&Help"
+msgstr "&Ajuda"
+
+msgid "Files"
+msgstr "Fitxers"
+
+msgid "&OK"
+msgstr "&D'acord"
+
+msgid "Selection"
+msgstr "Selecció"
+
+msgid "Find &Next"
+msgstr "&Cerca el següent"
+
+msgid "&Replace"
+msgstr "&Substitueix"
+
+msgid "Replace &All"
+msgstr "Substitueix-les &totes"
+
+msgid "&Undo"
+msgstr "&Desfés"
+
+msgid "Open tab..."
+msgstr "Obre una pestanya..."
+
+msgid "Find string (use '\\\\' to find a '\\')"
+msgstr "Cerca una cadena (useu '\\\\' per a cercar '\\')"
+
+msgid "Find & Replace (use '\\\\' to find a '\\')"
+msgstr "Cerca i substitueix (useu '\\\\' per a cercar '\\')"
+
+msgid "Not Used"
+msgstr "No Usat"
+
+msgid "Directory\t*.nothing\n"
+msgstr "Directori\t*.res\n"
+
+#, c-format
+msgid "E671: Cannot find window title \"%s\""
+msgstr "E671: No s'ha trobat el títol de finestra \"%s\""
+
+#, c-format
+msgid "E243: Argument not supported: \"-%s\"; Use the OLE version."
+msgstr "E243: Argument no suportat: \"-%s\"; Useu la versió OLE."
+
+msgid "E672: Unable to open window inside MDI application"
+msgstr "E672: No s'ha pogut obrir una finestra dins l'aplicació MDI"
+
+msgid "Vim E458: Cannot allocate colormap entry, some colors may be incorrect"
+msgstr "Vim E458: No es pot assignar memòria, els colors poden ser incorrectes"
+
+#, c-format
+msgid "E250: Fonts for the following charsets are missing in fontset %s:"
+msgstr "E250: Falten fonts per als jocs de caràcters del conjunt de fonts %s:"
+
+#, c-format
+msgid "E252: Fontset name: %s"
+msgstr "E252: Nom del conjunt de fonts: %s"
+
+#, c-format
+msgid "Font '%s' is not fixed-width"
+msgstr "La fosa '%s' no és d'amplada fixa"
+
+#, c-format
+msgid "E253: Fontset name: %s"
+msgstr "E253: Nom del conjunt de fonts: %s"
+
+#, c-format
+msgid "Font0: %s"
+msgstr "Fosa0: %s"
+
+#, c-format
+msgid "Font1: %s"
+msgstr "Fosa1: %s"
+
+#, c-format
+msgid "Font%ld width is not twice that of font0"
+msgstr "L'amplada de fosa%ld no és el doble que la de fosa0"
+
+#, c-format
+msgid "Font0 width: %ld"
+msgstr "Amplada de fosa0: %ld"
+
+#, c-format
+msgid "Font1 width: %ld"
+msgstr "Amplada de fosa1: %ld"
+
+msgid "Invalid font specification"
+msgstr "L'especificació de tipus de lletra no és vàlida"
+
+msgid "&Dismiss"
+msgstr "&Ignora"
+
+msgid "no specific match"
+msgstr "no hi ha coincidències"
+
+msgid "Vim - Font Selector"
+msgstr "Vim - Selector de fosa"
+
+msgid "Name:"
+msgstr "Nom:"
+
+msgid "Show size in Points"
+msgstr "Mostra la mida en punts"
+
+msgid "Encoding:"
+msgstr "Codificació:"
+
+msgid "Font:"
+msgstr "Fosa:"
+
+msgid "Style:"
+msgstr "Estil:"
+
+msgid "Size:"
+msgstr "Mida:"
+
+msgid "E256: Hangul automata ERROR"
+msgstr "E256: ERROR de l'autòmata hangul"
+
+msgid "E550: Missing colon"
+msgstr "E550: Falta un caràcter ':'"
+
+msgid "E551: Illegal component"
+msgstr "E551: Component il·legal"
+
+msgid "E552: digit expected"
+msgstr "E552: s'esperava un dígit"
+
+#, c-format
+msgid "Page %d"
+msgstr "Pàgina %d"
+
+msgid "No text to be printed"
+msgstr "No hi ha text per imprimir"
+
+#, c-format
+msgid "Printing page %d (%d%%)"
+msgstr "Imprimint la pàgina %d (%d%%)"
+
+#, c-format
+msgid " Copy %d of %d"
+msgstr " Còpia %d de %d"
+
+#, c-format
+msgid "Printed: %s"
+msgstr "S'ha imprès: %s"
+
+msgid "Printing aborted"
+msgstr "S'ha avortat la impressió"
+
+msgid "E455: Error writing to PostScript output file"
+msgstr "E455: Error en escriure el fitxer PostScript"
+
+#, c-format
+msgid "E624: Can't open file \"%s\""
+msgstr "E624: No s'ha pogut obrir el fitxer \"%s\""
+
+#, c-format
+msgid "E457: Can't read PostScript resource file \"%s\""
+msgstr "E457: No s'ha pogut llegir el fitxer de recursos PostScript \"%s\""
+
+#, c-format
+msgid "E618: file \"%s\" is not a PostScript resource file"
+msgstr "E618: El fitxer \"%s\" no és un fitxer de recursos PostScript"
+
+#, c-format
+msgid "E619: file \"%s\" is not a supported PostScript resource file"
+msgstr "E619: El fitxer de recursos PostScript \"%s\" no està suportat"
+
+#, c-format
+msgid "E621: \"%s\" resource file has wrong version"
+msgstr "E621: La versió del fitxer de recursos \"%s\" és incorrecta"
+
+msgid "E673: Incompatible multi-byte encoding and character set."
+msgstr "E673: El joc de caràcters no admet codificació multi-octet."
+
+msgid "E674: printmbcharset cannot be empty with multi-byte encoding."
+msgstr "E674: la codificació multi-octet requereix l'opció printmbcharset"
+
+msgid "E675: No default font specified for multi-byte printing."
+msgstr "E675: No hi ha cap font per defecte per a imprimir en mode multi-octet."
+
+msgid "E324: Can't open PostScript output file"
+msgstr "E324: No s'ha pogut obrir el fitxer PostScript de sortida"
+
+#, c-format
+msgid "E456: Can't open file \"%s\""
+msgstr "E456: No s'ha pogut obrir el fitxer \"%s\""
+
+msgid "E456: Can't find PostScript resource file \"prolog.ps\""
+msgstr "E456: No s'ha trobat el fitxer de recursos PostScript \"prolog.ps\""
+
+msgid "E456: Can't find PostScript resource file \"cidfont.ps\""
+msgstr "E456: No s'ha trobat el fitxer de recursos PostScript \"cidfont.ps\""
+
+#, c-format
+msgid "E456: Can't find PostScript resource file \"%s.ps\""
+msgstr "E456: No s'ha trobat el fitxer de recursos PostScript \"%s.ps\""
+
+#, c-format
+msgid "E620: Unable to convert to print encoding \"%s\""
+msgstr "E620: No s'ha pogut convertir a la codificació d'impressió \"%s\""
+
+msgid "Sending to printer..."
+msgstr "Enviant a la impressora..."
+
+msgid "E365: Failed to print PostScript file"
+msgstr "E365: Error en imprimir el fitxer PostScript"
+
+msgid "Print job sent."
+msgstr "S'ha enviat la feina d'impressió."
+
+msgid "Add a new database"
+msgstr "Afegeix una base de dades nova"
+
+msgid "Query for a pattern"
+msgstr "Cerca un patró"
+
+msgid "Show this message"
+msgstr "Mostra aquest missatge"
+
+msgid "Kill a connection"
+msgstr "Talla una connexió"
+
+msgid "Reinit all connections"
+msgstr "Reinicia totes les connexions"
+
+msgid "Show connections"
+msgstr "Mostra les connexions"
+
+#, c-format
+msgid "E560: Usage: cs[cope] %s"
+msgstr "E560: Sintaxi: cs[cope] %s"
+
+msgid "This cscope command does not support splitting the window.\n"
+msgstr "Aquesta ordre de cscope no suporta divisió de finestres.\n"
+
+msgid "E562: Usage: cstag <ident>"
+msgstr "E562: Sintaxi: cstag <despl>"
+
+msgid "E257: cstag: tag not found"
+msgstr "E257: cstag: No s'ha trobat l'etiqueta"
+
+#, c-format
+msgid "E563: stat(%s) error: %d"
+msgstr "E563: Error a stat(%s): %d"
+
+msgid "E563: stat error"
+msgstr "E563: Error a stat()"
+
+#, c-format
+msgid "E564: %s is not a directory or a valid cscope database"
+msgstr "E564: %s no és un directori o una base de dades cscope vàlida"
+
+#, c-format
+msgid "Added cscope database %s"
+msgstr "S'ha afegit la base de dades cscope %s"
+
+#, c-format
+msgid "E262: error reading cscope connection %ld"
+msgstr "E262: Error en llegir la connexió cscope %ld"
+
+msgid "E561: unknown cscope search type"
+msgstr "E561: Tipus de cerca cscope desconeguda"
+
+msgid "E566: Could not create cscope pipes"
+msgstr "E566: No s'han pogut crear canonades cscope"
+
+msgid "E622: Could not fork for cscope"
+msgstr "E622: No s'ha pogut crear el procés cscope"
+
+msgid "cs_create_connection setpgid failed"
+msgstr "cs_create_connection setpgid ha fallat"
+
+msgid "cs_create_connection exec failed"
+msgstr "cs_create_connection exec ha fallat"
+
+msgid "cs_create_connection: fdopen for to_fp failed"
+msgstr "cs_create_connection: fdopen per a to_fp ha fallat"
+
+msgid "cs_create_connection: fdopen for fr_fp failed"
+msgstr "cs_create_connection: fdopen per a fr_fp ha fallat"
+
+msgid "E623: Could not spawn cscope process"
+msgstr "E623: No s'ha pogut crear el procés cscope"
+
+msgid "E567: no cscope connections"
+msgstr "E567: No hi ha connexions cscope"
+
+#, c-format
+msgid "E469: invalid cscopequickfix flag %c for %c"
+msgstr "E469: paràmetre cscopequickfix %c no vàlid per a %c"
+
+#, c-format
+msgid "E259: no matches found for cscope query %s of %s"
+msgstr "E259: no hi ha coincidències per la cerca cscope %s de %s"
+
+msgid "cscope commands:\n"
+msgstr "ordres de cscope:\n"
+
+#, c-format
+msgid "%-5s: %s%*s (Usage: %s)"
+msgstr "%-5s: %s%*s (Sintaxi: %s)"
+
+msgid ""
+"\n"
+" a: Find assignments to this symbol\n"
+" c: Find functions calling this function\n"
+" d: Find functions called by this function\n"
+" e: Find this egrep pattern\n"
+" f: Find this file\n"
+" g: Find this definition\n"
+" i: Find files #including this file\n"
+" s: Find this C symbol\n"
+" t: Find this text string\n"
+msgstr ""
+"\n"
+" a: Cerca assignacions a aquest símbol\n"
+" c: Cerca funcions que criden aquesta funció\n"
+" d: Cerca funcions cridades per aquesta funció\n"
+" e: Cerca aquest patró egrep\n"
+" f: Cerca aquest fitxer\n"
+" g: Cerca aquesta definició\n"
+" i: Cerca fitxers que fan #include amb aquest fitxer\n"
+" s: Cerca aquest símbol C\n"
+" t: Cerca aquesta cadena de caràcters\n"
+
+#, c-format
+msgid "E625: cannot open cscope database: %s"
+msgstr "E625: no s'ha pogut obrir la base de dades cscope: %s"
+
+msgid "E626: cannot get cscope database information"
+msgstr "E626: no s'ha pogut obtenir informació de la base de dades cscope"
+
+msgid "E568: duplicate cscope database not added"
+msgstr "E568: no s'ha afegit una base de dades cscope duplicada"
+
+#, c-format
+msgid "E261: cscope connection %s not found"
+msgstr "E261: no s'ha trobat la connexió cscope %s"
+
+#, c-format
+msgid "cscope connection %s closed"
+msgstr "s'ha tancat la connexió cscope %s"
+
+msgid "E570: fatal error in cs_manage_matches"
+msgstr "E570: error fatal a cs_manage_matches"
+
+#, c-format
+msgid "Cscope tag: %s"
+msgstr "Etiqueta cscope: %s"
+
+msgid ""
+"\n"
+" # line"
+msgstr ""
+"\n"
+" # línia"
+
+msgid "filename / context / line\n"
+msgstr "fitxer / context / línia\n"
+
+#, c-format
+msgid "E609: Cscope error: %s"
+msgstr "E609: Error de cscope: %s"
+
+msgid "All cscope databases reset"
+msgstr "S'han restablert totes les bases de dades cscope"
+
+msgid "no cscope connections\n"
+msgstr "no hi ha connexions cscope\n"
+
+msgid " # pid database name prepend path\n"
+msgstr " # pid base de dades prefix d'ubicació\n"
+
+msgid "Lua library cannot be loaded."
+msgstr "No s'ha pogut carregar la biblioteca Lua."
+
+msgid "cannot save undo information"
+msgstr "no s'ha pogut desar la informació de desfer"
+
+msgid ""
+"E815: Sorry, this command is disabled, the MzScheme libraries could not be "
+"loaded."
+msgstr "E815: Ordre no disponible, no s'han carregat biblioteques MzScheme"
+
+msgid ""
+"E895: Sorry, this command is disabled, the MzScheme's racket/base module "
+"could not be loaded."
+msgstr "E895: Ordre no disponible, no s'ha carregat el mòdul base de MzScheme"
+
+msgid "invalid expression"
+msgstr "l'expressió no és vàlida"
+
+msgid "expressions disabled at compile time"
+msgstr "no s'ha compilat suport per a expressions"
+
+msgid "hidden option"
+msgstr "opció amagada"
+
+msgid "unknown option"
+msgstr "opció desconeguda"
+
+msgid "window index is out of range"
+msgstr "l'índex de la finestra està fora de l'interval"
+
+msgid "couldn't open buffer"
+msgstr "no s'ha pogut obrir el buffer"
+
+msgid "cannot delete line"
+msgstr "no s'ha pogut esborrar la línia"
+
+msgid "cannot replace line"
+msgstr "no s'ha pogut substituir la línia"
+
+msgid "cannot insert line"
+msgstr "no s'ha pogut inserir la línia"
+
+msgid "string cannot contain newlines"
+msgstr "la cadena no pot contenir salts de línia"
+
+msgid "error converting Scheme values to Vim"
+msgstr "error en convertir els valors de Scheme a Vim"
+
+msgid "Vim error: ~a"
+msgstr "Error del Vim: ~a"
+
+msgid "Vim error"
+msgstr "Error del Vim"
+
+msgid "buffer is invalid"
+msgstr "el buffer no és vàlid"
+
+msgid "window is invalid"
+msgstr "la finestra no és vàlida"
+
+msgid "linenr out of range"
+msgstr "número de línia fora de l'interval"
+
+msgid "not allowed in the Vim sandbox"
+msgstr "no permès a l'entorn d'execució del Vim"
+
+msgid "E836: This Vim cannot execute :python after using :py3"
+msgstr "E836: Aquest Vim no pot executar :python després de :py3"
+
+msgid ""
+"E263: Sorry, this command is disabled, the Python library could not be "
+"loaded."
+msgstr "E263: Ordre no disponible, no s'ha carregat la biblioteca Python."
+
+msgid ""
+"E887: Sorry, this command is disabled, the Python's site module could not be "
+"loaded."
+msgstr "E263: Ordre no disponible, no s'ha carregat el mòdul site de Python."
+
+msgid "E659: Cannot invoke Python recursively"
+msgstr "E659: No es pot invocar Python de forma recursiva"
+
+msgid "E837: This Vim cannot execute :py3 after using :python"
+msgstr "E837: Aquest Vim no pot executar :py3 després de :python"
+
+msgid "E265: $_ must be an instance of String"
+msgstr "E265: $_ ha de ser String"
+
+msgid ""
+"E266: Sorry, this command is disabled, the Ruby library could not be loaded."
+msgstr "E266: Ordre no disponible, no s'ha carregat la biblioteca Ruby."
+
+msgid "E267: unexpected return"
+msgstr "E267: retorn inesperat"
+
+msgid "E268: unexpected next"
+msgstr "E268: 'next' inesperat"
+
+msgid "E269: unexpected break"
+msgstr "E269: 'break' inesperat"
+
+msgid "E270: unexpected redo"
+msgstr "E270: 'redo' inesperat"
+
+msgid "E271: retry outside of rescue clause"
+msgstr "E271: 'retry' fora d'una clàusula de rescat"
+
+msgid "E272: unhandled exception"
+msgstr "E272: excepció no conduïda"
+
+#, c-format
+msgid "E273: unknown longjmp status %d"
+msgstr "E273: estat de longjmp %d desconegut"
+
+msgid "invalid buffer number"
+msgstr "número de buffer no vàlid"
+
+msgid "not implemented yet"
+msgstr "no implementat (de moment)"
+
+msgid "cannot set line(s)"
+msgstr "no s'han pogut establir les línies"
+
+msgid "invalid mark name"
+msgstr "nom de marca no vàlid"
+
+msgid "mark not set"
+msgstr "marca no establerta"
+
+#, c-format
+msgid "row %d column %d"
+msgstr "fila %d columna %d"
+
+msgid "cannot insert/append line"
+msgstr "no s'ha pogut inserir/afegir la línia"
+
+msgid "line number out of range"
+msgstr "número de línia fora de l'interval"
+
+msgid "unknown flag: "
+msgstr "paràmetre desconegut: "
+
+msgid "unknown vimOption"
+msgstr "opció del Vim desconeguda"
+
+msgid "keyboard interrupt"
+msgstr "interrupció de teclat"
+
+msgid "vim error"
+msgstr "error de vim"
+
+msgid "cannot create buffer/window command: object is being deleted"
+msgstr "no es pot crear l'ordre Tcl: l'objecte està sent eliminant"
+
+msgid ""
+"cannot register callback command: buffer/window is already being deleted"
+msgstr "no es pot registrar el callback: l'objecte està sent eliminant"
+
+msgid ""
+"E280: TCL FATAL ERROR: reflist corrupt!? Please report this to vim-dev@vim."
+"org"
+msgstr "E280: ERROR FATAL DE TCL: reflist corromput!? Comuniqueu el bug a vim-dev@vim.org."
+
+msgid "cannot register callback command: buffer/window reference not found"
+msgstr "no es pot registrar el callback: no s'ha trobat la referència"
+
+msgid ""
+"E571: Sorry, this command is disabled: the Tcl library could not be loaded."
+msgstr "E571: Ordre no disponible: no s'ha carregat la biblioteca Tcl."
+
+#, c-format
+msgid "E572: exit code %d"
+msgstr "E572: codi de sortida %d"
+
+msgid "cannot get line"
+msgstr "no s'ha pogut obtenir la línia"
+
+msgid "Unable to register a command server name"
+msgstr "No s'ha pogut registrar un nom de servidor d'ordres"
+
+msgid "E248: Failed to send command to the destination program"
+msgstr "E248: No s'ha pogut enviar l'ordre al programa destinatari"
+
+#, c-format
+msgid "E573: Invalid server id used: %s"
+msgstr "E573: ID de servidor no vàlid: %s"
+
+msgid "E251: VIM instance registry property is badly formed. Deleted!"
+msgstr "E251: La propietat 'VimRegistry' no és vàlida. S'ha esborrat!"
+
+#, c-format
+msgid "E938: Duplicate key in JSON: \"%s\""
+msgstr "E938: Clau duplicada a l'objecte JSON: \"%s\""
+
+#, c-format
+msgid "E696: Missing comma in List: %s"
+msgstr "E696: Falta una coma a la llista: %s"
+
+#, c-format
+msgid "E697: Missing end of List ']': %s"
+msgstr "E697: Falta ']' al final de la llista: %s"
+
+# vim --foo
+msgid "Unknown option argument"
+msgstr "Opció desconeguda"
+
+msgid "Too many edit arguments"
+msgstr "Sobren arguments d'edició"
+
+msgid "Argument missing after"
+msgstr "Falta un argument després de"
+
+# vim -Tx
+msgid "Garbage after option argument"
+msgstr "Caràcters sobrants després de l'opció"
+
+msgid "Too many \"+command\", \"-c command\" or \"--cmd command\" arguments"
+msgstr "Sobren arguments \"+ordre\", \"-c ordre\" o \"--cmd ordre\""
+
+msgid "Invalid argument for"
+msgstr "Argument no vàlid per a"
+
+#, c-format
+msgid "%d files to edit\n"
+msgstr "%d fitxers per editar\n"
+
+msgid "netbeans is not supported with this GUI\n"
+msgstr "aquesta interfície gràfica no suporta NetBeans\n"
+
+msgid "'-nb' cannot be used: not enabled at compile time\n"
+msgstr "'-nb' no està disponible: no s'ha compilat el suport\n"
+
+msgid "This Vim was not compiled with the diff feature."
+msgstr "Aquest Vim no ha estat compilat amb la característica diff."
+
+msgid "Attempt to open script file again: \""
+msgstr "Es torna a intentar obrir l'script: \""
+
+msgid "Cannot open for reading: \""
+msgstr "No es pot obrir per a lectura: \""
+
+msgid "Cannot open for script output: \""
+msgstr "No es pot obrir per a la sortida de l'script: \""
+
+msgid "Vim: Error: Failure to start gvim from NetBeans\n"
+msgstr "Vim: Error: No s'ha pogut iniciar gvim des de NetBeans\n"
+
+msgid "Vim: Error: This version of Vim does not run in a Cygwin terminal\n"
+msgstr "Vim: Error: Aquesta versió de Vim no funciona en terminals Cygwin\n"
+
+msgid "Vim: Warning: Output is not to a terminal\n"
+msgstr "Vim: Atenció: La sortida no està connectada a un terminal\n"
+
+msgid "Vim: Warning: Input is not from a terminal\n"
+msgstr "Vim: Atenció: L'entrada no està connectada a un terminal\n"
+
+msgid "pre-vimrc command line"
+msgstr "línia d'ordres prèvia a vimrc"
+
+#, c-format
+msgid "E282: Cannot read from \"%s\""
+msgstr "E282: No s'ha pogut llegir \"%s\""
+
+msgid ""
+"\n"
+"More info with: \"vim -h\"\n"
+msgstr ""
+"\n"
+"Més informació amb: \"vim -h\"\n"
+
+# max 56 caràcters
+msgid "[file ..] edit specified file(s)"
+msgstr "[fitxer ...] edita el(s) fitxer(s) especificat(s)"
+
+# max 56 caràcters
+msgid "- read text from stdin"
+msgstr "- edita el text de l'entrada estàndard"
+
+# max 56 caràcters
+msgid "-t tag edit file where tag is defined"
+msgstr "-t etiqueta edita el fitxer on hi ha l'etiqueta"
+
+# max 56 caràcters
+msgid "-q [errorfile] edit file with first error"
+msgstr "-q [ftxerrors] edita el fitxer on hi ha el primer error"
+
+# alineat amb main.c:3279
+msgid ""
+"\n"
+"\n"
+"Usage:"
+msgstr ""
+"\n"
+"\n"
+" ús:"
+
+msgid " vim [arguments] "
+msgstr " vim [arguments] "
+
+msgid ""
+"\n"
+" or:"
+msgstr ""
+"\n"
+"o bé:"
+
+# VMS
+msgid ""
+"\n"
+"Where case is ignored prepend / to make flag upper case"
+msgstr "\nOn no es distingeixen majúscules el prefix / indica majúscules"
+
+msgid ""
+"\n"
+"\n"
+"Arguments:\n"
+msgstr ""
+"\n"
+"\n"
+"Arguments:\n"
+
+msgid "--\t\t\tOnly file names after this"
+msgstr "--\t\t\tDesprés d'això només noms de fitxers"
+
+msgid "--literal\t\tDon't expand wildcards"
+msgstr "--literal\t\tNo expandeix patrons de noms"
+
+msgid "-register\t\tRegister this gvim for OLE"
+msgstr "-register\t\tRegistra aquest gvim a OLE"
+
+msgid "-unregister\t\tUnregister gvim for OLE"
+msgstr "-unregister\t\tDóna de baixa aquest gvim a OLE"
+
+msgid "-g\t\t\tRun using GUI (like \"gvim\")"
+msgstr "-g\t\t\tUsa la interfície gràfica (com \"gvim\")"
+
+msgid "-f or --nofork\tForeground: Don't fork when starting GUI"
+msgstr "-f o --nofork\tNo crea un procés nou per al GUI"
+
+msgid "-v\t\t\tVi mode (like \"vi\")"
+msgstr "-v\t\t\tMode Vi (com \"vi\")"
+
+msgid "-e\t\t\tEx mode (like \"ex\")"
+msgstr "-e\t\t\tMode Ex (com \"ex\")"
+
+msgid "-E\t\t\tImproved Ex mode"
+msgstr "-E\t\t\tMode Ex millorat"
+
+msgid "-s\t\t\tSilent (batch) mode (only for \"ex\")"
+msgstr "-s\t\t\tMode silenciós per lots (només per a \"ex\")"
+
+msgid "-d\t\t\tDiff mode (like \"vimdiff\")"
+msgstr "-d\t\t\tMode diff (com \"vimdiff\")"
+
+msgid "-y\t\t\tEasy mode (like \"evim\", modeless)"
+msgstr "-y\t\t\tMode senzill (com \"evim\", sense modes)"
+
+msgid "-R\t\t\tReadonly mode (like \"view\")"
+msgstr "-R\t\t\tMode només lectura (com \"view\")"
+
+msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
+msgstr "-Z\t\t\tMode restringit (com \"rvim)"
+
+msgid "-m\t\t\tModifications (writing files) not allowed"
+msgstr "-m\t\t\tNo permet modificar (escriure) fitxers"
+
+msgid "-M\t\t\tModifications in text not allowed"
+msgstr "-M\t\t\tNo permet modificar el text"
+
+msgid "-b\t\t\tBinary mode"
+msgstr "-b\t\t\tMode binari"
+
+msgid "-l\t\t\tLisp mode"
+msgstr "-l\t\t\tMode Lisp"
+
+msgid "-C\t\t\tCompatible with Vi: 'compatible'"
+msgstr "-C\t\t\tCompatible amb Vi: 'compatible'"
+
+msgid "-N\t\t\tNot fully Vi compatible: 'nocompatible'"
+msgstr "-N\t\t\tNo del tot compatible amb Vi: 'nocompatible'"
+
+msgid "-V[N][fname]\t\tBe verbose [level N] [log messages to fname]"
+msgstr "-V[N][nomf]\t\tLoquacitat [nivell N] [desa missatges a nomf]"
+
+msgid "-D\t\t\tDebugging mode"
+msgstr "-D\t\t\tMode de depuració"
+
+msgid "-n\t\t\tNo swap file, use memory only"
+msgstr "-n\t\t\tNo usa fitxers d'intercanvi, només memòria"
+
+msgid "-r\t\t\tList swap files and exit"
+msgstr "-r\t\t\tLlistat dels fitxers d'intercanvi"
+
+msgid "-r (with file name)\tRecover crashed session"
+msgstr "-r (amb nom de fitxer) Recupera una sessió accidentada"
+
+msgid "-L\t\t\tSame as -r"
+msgstr "-L\t\t\tIgual que -r"
+
+msgid "-f\t\t\tDon't use newcli to open window"
+msgstr "-f\t\t\tNo obre una finestra nova amb newcli"
+
+msgid "-dev <device>\t\tUse <device> for I/O"
+msgstr "-dev <dispositiu>\t\tUsa <dispositiu> per a l'E/S"
+
+msgid "-A\t\t\tStart in Arabic mode"
+msgstr "-A\t\t\tComença en mode aràbic"
+
+msgid "-H\t\t\tStart in Hebrew mode"
+msgstr "-H\t\t\tComença en mode hebreu"
+
+msgid "-F\t\t\tStart in Farsi mode"
+msgstr "-F\t\t\tComença en mode farsi"
+
+msgid "-T <terminal>\tSet terminal type to <terminal>"
+msgstr "-T <terminal>\tDefineix el tipus de terminal"
+
+msgid "--not-a-term\t\tSkip warning for input/output not being a terminal"
+msgstr "--not-a-term\t\tOmet avisos relacionats amb el terminal"
+
+msgid "--ttyfail\t\tExit if input or output is not a terminal"
+msgstr "--ttyfail\t\tSurt si l'entrada/sortida no són un terminal"
+
+msgid "-u <vimrc>\t\tUse <vimrc> instead of any .vimrc"
+msgstr "-u <vimrc>\t\tUsa <vimrc> en lloc de qualsevol altre .vimrc"
+
+msgid "-U <gvimrc>\t\tUse <gvimrc> instead of any .gvimrc"
+msgstr "-U <gvimrc>\t\tUsa <gvimrc> en lloc de qualsevol altre .gvimrc"
+
+msgid "--noplugin\t\tDon't load plugin scripts"
+msgstr "--noplugin\t\tNo carrega plugins"
+
+msgid "-p[N]\t\tOpen N tab pages (default: one for each file)"
+msgstr "-p[N]\t\tObre N pestanyes (per omissió: una per fitxer)"
+
+msgid "-o[N]\t\tOpen N windows (default: one for each file)"
+msgstr "-o[N]\t\tObre N finestres (per omissió: una per fitxer)"
+
+msgid "-O[N]\t\tLike -o but split vertically"
+msgstr "-O[N]\t\tCom -o però amb divisió vertical"
+
+msgid "+\t\t\tStart at end of file"
+msgstr "+\t\t\tComença al final del fitxer"
+
+msgid "+<lnum>\t\tStart at line <lnum>"
+msgstr "+<lnúm>\t\tComença a la línia <lnúm>"
+
+msgid "--cmd <command>\tExecute <command> before loading any vimrc file"
+msgstr "--cmd <ordre>\tExecuta <ordre> abans de llegir els fitxers vimrc"
+
+msgid "-c <command>\t\tExecute <command> after loading the first file"
+msgstr "-c <ordre>\t\tExecuta <ordre> després de carregar el primer fitxer"
+
+msgid "-S <session>\t\tSource file <session> after loading the first file"
+msgstr "-S <fitxer>\t\tExecuta <fitxer> un cop carregat el primer fitxer"
+
+msgid "-s <scriptin>\tRead Normal mode commands from file <scriptin>"
+msgstr "-s <script>\t\tLlegeix ordres del mode Normal del fitxer <script>"
+
+msgid "-w <scriptout>\tAppend all typed commands to file <scriptout>"
+msgstr "-w <script>\t\tAfegeix totes les ordres entrades al fitxer <script>"
+
+msgid "-W <scriptout>\tWrite all typed commands to file <scriptout>"
+msgstr "-W <script>\t\tEscriu totes les ordres entrades al fitxer <script>"
+
+msgid "-x\t\t\tEdit encrypted files"
+msgstr "-x\t\t\tEdita fitxers amb xifrat"
+
+msgid "-display <display>\tConnect vim to this particular X-server"
+msgstr "-display <pantalla>\tConnecta el Vim a un servidor X particular"
+
+msgid "-X\t\t\tDo not connect to X server"
+msgstr "-X\t\t\tNo es connecta al servidor X"
+
+msgid "--remote <files>\tEdit <files> in a Vim server if possible"
+msgstr "--remote <fitxers>\tEdita <fitxers> en un servidor Vim, si és possible"
+
+msgid "--remote-silent <files> Same, don't complain if there is no server"
+msgstr "--remote-silent <fitxers> Igual, no es queixa si no hi ha servidor"
+
+msgid ""
+"--remote-wait <files> As --remote but wait for files to have been edited"
+msgstr ""
+"--remote-wait <fitxers> Com --remote, però espera que s'editin els fitxers"
+
+msgid ""
+"--remote-wait-silent <files> Same, don't complain if there is no server"
+msgstr ""
+"--remote-wait-silent <fitxers> Igual, no es queixa si no hi ha servidor"
+
+msgid ""
+"--remote-tab[-wait][-silent] <files> As --remote but use tab page per file"
+msgstr ""
+"--remote-tab[-wait][-silent] <fitxers>\n"
+" Com --remote, però obre una pestanya per fitxer"
+
+msgid "--remote-send <keys>\tSend <keys> to a Vim server and exit"
+msgstr "--remote-send <tecles> Envia <tecles> a un servidor Vim i surt"
+
+msgid "--remote-expr <expr>\tEvaluate <expr> in a Vim server and print result"
+msgstr "--remote-expr <expr>\tAvalua <expr> en un servidor Vim i mostra el resultat"
+
+msgid "--serverlist\t\tList available Vim server names and exit"
+msgstr "--serverlist\t\tLlistat de servidors Vim disponibles"
+
+msgid "--servername <name>\tSend to/become the Vim server <name>"
+msgstr "--servername <nom>\tEnvia a/es converteix en servidor Vim <nom>"
+
+msgid "--startuptime <file>\tWrite startup timing messages to <file>"
+msgstr "--startuptime <fitxer> Desa la cronologia d'arrencada a <fitxer>"
+
+msgid "-i <viminfo>\t\tUse <viminfo> instead of .viminfo"
+msgstr "-i <viminfo>\t\tUsa <viminfo> en lloc de .viminfo"
+
+msgid "-h or --help\tPrint Help (this message) and exit"
+msgstr "-h o --help\tMostra aquesta ajuda i surt"
+
+msgid "--version\t\tPrint version information and exit"
+msgstr "--version\t\tMostra informació sobre la versió i surt"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Motif version):\n"
+msgstr ""
+"\n"
+"Arguments reconeguts pel gvim (versió Motif):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (neXtaw version):\n"
+msgstr "\nArguments reconeguts pel gvim (versió neXtaw):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Athena version):\n"
+msgstr ""
+"\n"
+"Arguments reconeguts pel gvim (versió Athena):\n"
+
+msgid "-display <display>\tRun vim on <display>"
+msgstr "-display <pantalla>\tExecuta vim a <pantalla>"
+
+msgid "-iconic\t\tStart vim iconified"
+msgstr "-iconic\t\tComença iconificat"
+
+msgid "-background <color>\tUse <color> for the background (also: -bg)"
+msgstr "-background <color>\tUsa <color> per al fons (també: -bg)"
+
+msgid "-foreground <color>\tUse <color> for normal text (also: -fg)"
+msgstr "-foreground <color>\tUsa <color> per al text normal (també: -fg)"
+
+msgid "-font <font>\t\tUse <font> for normal text (also: -fn)"
+msgstr "-font <fosa>\t\tUsa <fosa> per al text normal (també: -fn)"
+
+msgid "-boldfont <font>\tUse <font> for bold text"
+msgstr "-boldfont <fosa>\tUsa <fosa> per al text en negreta"
+
+msgid "-italicfont <font>\tUse <font> for italic text"
+msgstr "-italicfont <fosa>\tUsa <fosa> per al text en cursiva"
+
+msgid "-geometry <geom>\tUse <geom> for initial geometry (also: -geom)"
+msgstr "-geometry <geom>\tUsa <geom> com a geometria inicial (també: -geom)"
+
+msgid "-borderwidth <width>\tUse a border width of <width> (also: -bw)"
+msgstr "-borderwidth <amplada> Usa un marge d'amplada <amplada> (també: -bw) "
+
+msgid "-scrollbarwidth <width> Use a scrollbar width of <width> (also: -sw)"
+msgstr "-scrollbarwidth <amplada> Amplada de la barra de desplaçament (també: -sw)"
+
+msgid "-menuheight <height>\tUse a menu bar height of <height> (also: -mh)"
+msgstr "-menuheight <alçada>\tAlçada de la barra de menú (també: -mh)"
+
+msgid "-reverse\t\tUse reverse video (also: -rv)"
+msgstr "-reverse\t\tUsa el mode de video invers (també: -rv)"
+
+msgid "+reverse\t\tDon't use reverse video (also: +rv)"
+msgstr "+reverse\t\tNo usa el mode de video invers (també: +rv)"
+
+msgid "-xrm <resource>\tSet the specified resource"
+msgstr "-xrm <recurs>\tEstableix el recurs especificat"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (GTK+ version):\n"
+msgstr ""
+"\n"
+"Arguments reconeguts pel gvim (versió GTK+):\n"
+
+msgid "-display <display>\tRun vim on <display> (also: --display)"
+msgstr "-display <pantalla>\tExecuta vim a <pantalla> (també: --display)"
+
+msgid "--role <role>\tSet a unique role to identify the main window"
+msgstr "--role <rol>\t\tUsa un únic rol per a identificar la finestra principal"
+
+msgid "--socketid <xid>\tOpen Vim inside another GTK widget"
+msgstr "--socketid <xid>\tObre el vim dins d'un altre giny GTK"
+
+msgid "--echo-wid\t\tMake gvim echo the Window ID on stdout"
+msgstr "--echo-wid\t\tEscriu el Window ID a la sortida estàndard"
+
+msgid "-P <parent title>\tOpen Vim inside parent application"
+msgstr "-P <aplicació>\t\tObre el Vim dins d'una altra aplicació"
+
+msgid "--windowid <HWND>\tOpen Vim inside another win32 widget"
+msgstr "--windowid <HWND>\tObre el Vim dins d'un altre giny win32"
+
+msgid "No display"
+msgstr "No hi ha cap pantalla"
+
+msgid ": Send failed.\n"
+msgstr ": Error en enviar.\n"
+
+msgid ": Send failed. Trying to execute locally\n"
+msgstr ": Error en enviar. Intentant executar vim localment\n"
+
+#, c-format
+msgid "%d of %d edited"
+msgstr "editat %d de %d"
+
+msgid "No display: Send expression failed.\n"
+msgstr "No hi ha cap pantalla: Error en enviar l'expressió.\n"
+
+msgid ": Send expression failed.\n"
+msgstr ": Error en enviar l'expressió.\n"
+
+msgid "No marks set"
+msgstr "No hi ha marques definides"
+
+#, c-format
+msgid "E283: No marks matching \"%s\""
+msgstr "E283: Cap marca coincident amb \"%s\""
+
+# :marks
+msgid ""
+"\n"
+"mark line col file/text"
+msgstr ""
+"\n"
+"marca lín col fitxer/text"
+
+# :jumps
+# <c><r><r><l>
+msgid ""
+"\n"
+" jump line col file/text"
+msgstr ""
+"\n"
+" salt lín col fitxer/text"
+
+# :changes
+# <r><r><r><l>
+msgid ""
+"\n"
+"change line col text"
+msgstr "\ncanvi línia col text"
+
+# fitxer viminfo
+msgid ""
+"\n"
+"# File marks:\n"
+msgstr "\n# Marques:\n"
+
+# fitxer viminfo
+msgid ""
+"\n"
+"# Jumplist (newest first):\n"
+msgstr "\n# Salts (més recents primer):\n"
+
+# fitxer viminfo
+msgid ""
+"\n"
+"# History of marks within files (newest to oldest):\n"
+msgstr "\n# Historial de marques (més recents primer):\n"
+
+msgid "Missing '>'"
+msgstr "Falta un '>'"
+
+msgid "E543: Not a valid codepage"
+msgstr "E543: No és un codi de pàgina vàlid"
+
+msgid "E284: Cannot set IC values"
+msgstr "E284: No s'han pogut establir els valors del context d'entrada"
+
+msgid "E285: Failed to create input context"
+msgstr "E285: Error en crear el context d'entrada"
+
+msgid "E286: Failed to open input method"
+msgstr "E286: Error en obrir el mètode d'entrada"
+
+msgid "E287: Warning: Could not set destroy callback to IM"
+msgstr "E287: Atenció: Error en establir el callback de destrucció de l'IM"
+
+msgid "E288: input method doesn't support any style"
+msgstr "E288: el mètode d'entrada no suporta cap estil"
+
+msgid "E289: input method doesn't support my preedit type"
+msgstr "E289: el mètode d'entrada no suporta el tipus de preedició"
+
+msgid "E293: block was not locked"
+msgstr "E293: El bloc no estava bloquejat"
+
+msgid "E294: Seek error in swap file read"
+msgstr "E294: Error de posicionament en llegir el fitxer d'intercanvi"
+
+msgid "E295: Read error in swap file"
+msgstr "E295: Error de lectura en el fitxer d'intercanvi"
+
+msgid "E296: Seek error in swap file write"
+msgstr "E296: Error de posicionament en escriure el fitxer d'intercanvi"
+
+msgid "E297: Write error in swap file"
+msgstr "E297: Error d'escriptura en el fitxer d'intercanvi"
+
+msgid "E300: Swap file already exists (symlink attack?)"
+msgstr "E300: El fitxer d'intercanvi ja existeix (pot ser un atac?)"
+
+msgid "E298: Didn't get block nr 0?"
+msgstr "E298: No s'ha pogut obtenir el bloc 0?"
+
+msgid "E298: Didn't get block nr 1?"
+msgstr "E298: No s'ha pogut obtenir el bloc 1?"
+
+msgid "E298: Didn't get block nr 2?"
+msgstr "E298: No s'ha pogut obtenir el bloc 2?"
+
+# called after the crypt key or 'cryptmethod' was changed for "buf"
+msgid "E843: Error while updating swap file crypt"
+msgstr "E843: Error en actualitzar el xifrat del fitxer d'intercanvi"
+
+msgid "E301: Oops, lost the swap file!!!"
+msgstr "E301: El fitxer d'intercanvi ha desaparegut!!!"
+
+msgid "E302: Could not rename swap file"
+msgstr "E302: No s'ha pogut reanomenar el fitxer d'intercanvi"
+
+#, c-format
+msgid "E303: Unable to open swap file for \"%s\", recovery impossible"
+msgstr "E303: Error en obrir el fitxer .swp de \"%s\", no es pot recuperar"
+
+msgid "E304: ml_upd_block0(): Didn't get block 0??"
+msgstr "E304: ml_upd_block0(): No s'ha obtingut el bloc 0??"
+
+#, c-format
+msgid "E305: No swap file found for %s"
+msgstr "E305: No s'ha trobat el fitxer d'intercanvi de %s"
+
+msgid "Enter number of swap file to use (0 to quit): "
+msgstr "Entreu el número del fitxer .swp a utilitzar (0 per a sortir): "
+
+#, c-format
+msgid "E306: Cannot open %s"
+msgstr "E306: No s'ha pogut obrir %s"
+
+msgid "Unable to read block 0 from "
+msgstr "No s'ha pogut llegir el bloc 0 de "
+
+msgid ""
+"\n"
+"Maybe no changes were made or Vim did not update the swap file."
+msgstr "\nPotser no hi havia canvis o no es va desar el fitxer .swp."
+
+msgid " cannot be used with this version of Vim.\n"
+msgstr " no es pot utilitzar amb aquesta versió del Vim.\n"
+
+msgid "Use Vim version 3.0.\n"
+msgstr "Useu la versió 3.0 del Vim.\n"
+
+#, c-format
+msgid "E307: %s does not look like a Vim swap file"
+msgstr "E307: %s no sembla un fitxer d'intercanvi del Vim"
+
+msgid " cannot be used on this computer.\n"
+msgstr " no es pot utilitzar en aquesta màquina.\n"
+
+msgid "The file was created on "
+msgstr "El fitxer va ser creat el "
+
+msgid ""
+",\n"
+"or the file has been damaged."
+msgstr ""
+",\n"
+"o el fitxer està fet malbé."
+
+#, c-format
+msgid ""
+"E833: %s is encrypted and this version of Vim does not support encryption"
+msgstr "E833: %s està xifrat i aquesta versió de Vim no suporta xifratge"
+
+msgid " has been damaged (page size is smaller than minimum value).\n"
+msgstr " ha estat danyat (la mida de pàgina és inferior al valor mínim).\n"
+
+#, c-format
+msgid "Using swap file \"%s\""
+msgstr "S'utilitza el fitxer d'intercanvi \"%s\""
+
+#, c-format
+msgid "Original file \"%s\""
+msgstr "Fitxer original \"%s\""
+
+msgid "E308: Warning: Original file may have been changed"
+msgstr "E308: Atenció: El fitxer original pot haver canviat"
+
+#, c-format
+msgid "Swap file is encrypted: \"%s\""
+msgstr "El fitxer d'intercanvi està xifrat: \"%s\""
+
+msgid ""
+"\n"
+"If you entered a new crypt key but did not write the text file,"
+msgstr "\nSi vau entrar una nova clau de xifrat però no vau desar el fitxer,"
+
+msgid ""
+"\n"
+"enter the new crypt key."
+msgstr "\nentreu la nova clau."
+
+msgid ""
+"\n"
+"If you wrote the text file after changing the crypt key press enter"
+msgstr "\nSi vau desar el fitxer després de canviar la clau, premeu Entrar per a"
+
+msgid ""
+"\n"
+"to use the same key for text file and swap file"
+msgstr "\nusar la mateixa clau per al fitxer de text i per al fitxer d'intercanvi."
+
+#, c-format
+msgid "E309: Unable to read block 1 from %s"
+msgstr "E309: No s'ha pogut llegir el bloc 1 de %s"
+
+msgid "???MANY LINES MISSING"
+msgstr "???FALTEN MOLTES LÍNIES"
+
+msgid "???LINE COUNT WRONG"
+msgstr "???RECOMPTE DE LÍNIES INCORRECTE"
+
+msgid "???EMPTY BLOCK"
+msgstr "???BLOC BUIT"
+
+msgid "???LINES MISSING"
+msgstr "???FALTEN LÍNIES"
+
+#, c-format
+msgid "E310: Block 1 ID wrong (%s not a .swp file?)"
+msgstr "E310: L'ID del bloc 1 no és correcte (%s no és un fitxer .swp?)"
+
+msgid "???BLOCK MISSING"
+msgstr "???FALTA UN BLOC"
+
+msgid "??? from here until ???END lines may be messed up"
+msgstr "??? Des d'aquí fins a ???FINAL les línies poden ser incorrectes"
+
+msgid "??? from here until ???END lines may have been inserted/deleted"
+msgstr "??? Des d'aquí fins a ???FINAL hi pot haver línies inserides/eliminades"
+
+msgid "???END"
+msgstr "???FINAL"
+
+msgid "E311: Recovery Interrupted"
+msgstr "E311: S'ha interromput la recuperació"
+
+msgid ""
+"E312: Errors detected while recovering; look for lines starting with ???"
+msgstr "E312: Errors durant la recuperació; cerqueu línies amb la marca ???"
+
+msgid "See \":help E312\" for more information."
+msgstr "Vegeu \":help E312\" per a més informació."
+
+msgid "Recovery completed. You should check if everything is OK."
+msgstr "Recuperació completada. Hauríeu de revisar que tot sigui correcte."
+
+msgid ""
+"\n"
+"(You might want to write out this file under another name\n"
+msgstr ""
+"\n"
+"(Potser voleu desar aquest fitxer amb un altre nom\n"
+
+msgid "and run diff with the original file to check for changes)"
+msgstr "i fer un diff amb el fitxer original per a veure els canvis)"
+
+msgid "Recovery completed. Buffer contents equals file contents."
+msgstr "Recuperació completada. El buffer conté el mateix que el fitxer."
+
+msgid ""
+"\n"
+"You may want to delete the .swp file now.\n"
+"\n"
+msgstr "\nNormalment, ara hauríeu d'esborrar el fitxer .swp.\n\n"
+
+msgid "Using crypt key from swap file for the text file.\n"
+msgstr "S'usa la clau de xifrat del fitxer .swp per al fitxer de text.\n"
+
+msgid "Swap files found:"
+msgstr "Fitxers d'intercanvi trobats:"
+
+msgid " In current directory:\n"
+msgstr " En el directori actual:\n"
+
+msgid " Using specified name:\n"
+msgstr " Usant el nom especificat:\n"
+
+msgid " In directory "
+msgstr " En el directori "
+
+msgid " -- none --\n"
+msgstr " -- cap --\n"
+
+msgid " owned by: "
+msgstr " propietat de: "
+
+msgid " dated: "
+msgstr " amb data: "
+
+msgid " dated: "
+msgstr " amb data: "
+
+msgid " [from Vim version 3.0]"
+msgstr " [del Vim versió 3.0]"
+
+msgid " [does not look like a Vim swap file]"
+msgstr " [no sembla un fitxer .swp de Vim]"
+
+msgid " file name: "
+msgstr " nom del fitxer: "
+
+msgid ""
+"\n"
+" modified: "
+msgstr ""
+"\n"
+" modificat: "
+
+msgid "YES"
+msgstr "SÍ"
+
+msgid "no"
+msgstr "no"
+
+msgid ""
+"\n"
+" user name: "
+msgstr ""
+"\n"
+" nom de l'usuari: "
+
+msgid " host name: "
+msgstr " màquina: "
+
+msgid ""
+"\n"
+" host name: "
+msgstr ""
+"\n"
+" màquina: "
+
+msgid ""
+"\n"
+" process ID: "
+msgstr ""
+"\n"
+" ID del procés: "
+
+msgid " (still running)"
+msgstr " (executant-se)"
+
+msgid ""
+"\n"
+" [not usable with this version of Vim]"
+msgstr "\n [no usable amb aquesta versió del Vim]"
+
+msgid ""
+"\n"
+" [not usable on this computer]"
+msgstr "\n [no usable en aquesta màquina]"
+
+msgid " [cannot be read]"
+msgstr " [no es pot llegir]"
+
+msgid " [cannot be opened]"
+msgstr " [no es pot obrir]"
+
+msgid "E313: Cannot preserve, there is no swap file"
+msgstr "E313: No s'ha pogut preservar, no existeix cap fitxer d'intercanvi"
+
+msgid "File preserved"
+msgstr "S'ha preservat el fitxer"
+
+msgid "E314: Preserve failed"
+msgstr "E314: La preservació ha fallat"
+
+#, c-format
+msgid "E315: ml_get: invalid lnum: %ld"
+msgstr "E315: ml_get: lnum no vàlid: %ld"
+
+#, c-format
+msgid "E316: ml_get: cannot find line %ld"
+msgstr "E316: ml_get: no s'ha trobat la línia %ld"
+
+msgid "E317: pointer block id wrong 3"
+msgstr "E317: punter a id de bloc incorrecte 3"
+
+msgid "stack_idx should be 0"
+msgstr "stack_idx hauria de ser 0"
+
+msgid "E318: Updated too many blocks?"
+msgstr "E318: S'han actualitzat massa blocs?"
+
+msgid "E317: pointer block id wrong 4"
+msgstr "E317: Punter a id de bloc incorrecte 4"
+
+msgid "deleted block 1?"
+msgstr "s'ha eliminat el bloc 1?"
+
+#, c-format
+msgid "E320: Cannot find line %ld"
+msgstr "E320: No s'ha trobat la línia %ld"
+
+msgid "E317: pointer block id wrong"
+msgstr "E317: punter a id de bloc incorrecte"
+
+msgid "pe_line_count is zero"
+msgstr "po_line_count és zero"
+
+#, c-format
+msgid "E322: line number out of range: %ld past the end"
+msgstr "E322: número de línia fora de l'interval: %ld passat el final"
+
+#, c-format
+msgid "E323: line count wrong in block %ld"
+msgstr "E323: nombre de línies incorrecte al bloc %ld"
+
+msgid "Stack size increases"
+msgstr "S'augmenta la mida de la pila"
+
+msgid "E317: pointer block id wrong 2"
+msgstr "E317: punter a id de bloc incorrecte 2"
+
+#, c-format
+msgid "E773: Symlink loop for \"%s\""
+msgstr "E773: Enllaços simbòlics circulars per a \"%s\""
+
+msgid "E325: ATTENTION"
+msgstr "E325: ATENCIÓ"
+
+msgid ""
+"\n"
+"Found a swap file by the name \""
+msgstr "\nS'ha trobat un fitxer d'intercanvi amb nom \""
+
+msgid "While opening file \""
+msgstr "Mentre s'obria el fitxer \""
+
+msgid " NEWER than swap file!\n"
+msgstr " MÉS NOU que el fitxer d'intercanvi!\n"
+
+msgid ""
+"\n"
+"(1) Another program may be editing the same file. If this is the case,\n"
+" be careful not to end up with two different instances of the same\n"
+" file when making changes. Quit, or continue with caution.\n"
+msgstr ""
+"\n"
+"(1) Un altre programa pot estar editant aquest mateix fitxer. Si és\n"
+" aquest el cas, aneu amb compte de no acabar amb dues versions\n"
+" diferents del mateix fitxer quan feu canvis. Sortiu, o continueu\n"
+" amb precaució.\n"
+
+msgid "(2) An edit session for this file crashed.\n"
+msgstr "(2) El Vim es va estavellar mentre s'editava aquest fitxer.\n"
+
+msgid " If this is the case, use \":recover\" or \"vim -r "
+msgstr " En aquest cas, useu \":recover\" o bé \"vim -r "
+
+msgid ""
+"\"\n"
+" to recover the changes (see \":help recovery\").\n"
+msgstr ""
+"\"\n"
+" per a recuperar els canvis (vegeu \":help recovery\").\n"
+
+msgid " If you did this already, delete the swap file \""
+msgstr " Si ja ho heu fet, elimineu el fitxer \""
+
+msgid ""
+"\"\n"
+" to avoid this message.\n"
+msgstr ""
+"\"\n"
+" per a evitar aquest missatge.\n"
+
+msgid "Swap file \""
+msgstr "El fitxer d'intercanvi \""
+
+msgid "\" already exists!"
+msgstr "\" ja existeix!"
+
+msgid "VIM - ATTENTION"
+msgstr "VIM - ATENCIÓ"
+
+msgid "Swap file already exists!"
+msgstr "El fitxer d'intercanvi ja existeix!"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"&Obrir amb només lectura\n"
+"&Editar igualment\n"
+"&Recuperar\n"
+"&Sortir\n"
+"&Avortar"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Delete it\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"&Obrir amb només lectura\n"
+"&Editar igualment\n"
+"&Recuperar\n"
+"E&liminar\n"
+"&Sortir\n"
+"&Avortar"
+
+msgid "E326: Too many swap files found"
+msgstr "E326: S'han trobat massa fitxers d'intercanvi"
+
+# todo: menu path
+msgid "E327: Part of menu-item path is not sub-menu"
+msgstr "E327: Un component de l'ítem de menú no és un submenú"
+
+msgid "E328: Menu only exists in another mode"
+msgstr "E328: El menú només existeix en un altre mode"
+
+#, c-format
+msgid "E329: No menu \"%s\""
+msgstr "E329: No hi ha cap menú \"%s\""
+
+msgid "E792: Empty menu name"
+msgstr "E792: Nom de menú en blanc"
+
+# :menu Eines.Plecs :e
+msgid "E330: Menu path must not lead to a sub-menu"
+msgstr "E330: L'ítem de menú no pot ser un submenú"
+
+msgid "E331: Must not add menu items directly to menu bar"
+msgstr "E331: No és possible afegir ítems directament a la barra de menú"
+
+# :menu Fitxer.-Sep-.Foo.Foo :
+msgid "E332: Separator cannot be part of a menu path"
+msgstr "E332: Un component de l'ítem de menú és un separador"
+
+msgid ""
+"\n"
+"--- Menus ---"
+msgstr ""
+"\n"
+"--- Menús ---"
+
+msgid "Tear off this menu"
+msgstr "Desenganxa aquest menú"
+
+msgid "E333: Menu path must lead to a menu item"
+msgstr "E333: L'ítem de menú ha de portar a un element"
+
+#, c-format
+msgid "E334: Menu not found: %s"
+msgstr "E334: No s'ha trobat el menú: %s"
+
+#, c-format
+msgid "E335: Menu not defined for %s mode"
+msgstr "E335: El menú no està definit per al mode %s"
+
+msgid "E336: Menu path must lead to a sub-menu"
+msgstr "E336: L'ítem de menú ha de portar a un submenú"
+
+msgid "E337: Menu not found - check menu names"
+msgstr "E337: No s'ha trobat el menú - reviseu els noms dels menús"
+
+#, c-format
+msgid "Error detected while processing %s:"
+msgstr "S'ha detectat un error en processar %s:"
+
+#, c-format
+msgid "line %4ld:"
+msgstr "línia %4ld:"
+
+#, c-format
+msgid "E354: Invalid register name: '%s'"
+msgstr "E354: El nom de registre no és vàlid: '%s'"
+
+msgid "Messages maintainer: Bram Moolenaar <Bram@vim.org>"
+msgstr "Traducció dels missatges: Ernest Adrogué <eadrogue@gmx.net>"
+
+msgid "Interrupt: "
+msgstr "Interrupció: "
+
+msgid "Press ENTER or type command to continue"
+msgstr "Premeu ENTRAR o introduïu una ordre per a continuar"
+
+#, c-format
+msgid "%s line %ld"
+msgstr "%s línia %ld"
+
+msgid "-- More --"
+msgstr "-- Més --"
+
+msgid " SPACE/d/j: screen/page/line down, b/u/k: up, q: quit "
+msgstr " ESPAI/d/j: pantalla/pàgina/línia avall, b/u/k: amunt, q: sortir "
+
+msgid "Question"
+msgstr "Pregunta"
+
+msgid ""
+"&Yes\n"
+"&No"
+msgstr ""
+"&Sí\n"
+"&No"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"Save &All\n"
+"&Discard All\n"
+"&Cancel"
+msgstr ""
+"&Sí\n"
+"&No\n"
+"Desa-ho &tot\n"
+"&Descarta-ho tot\n"
+"&Cancel·la"
+
+msgid "Select Directory dialog"
+msgstr "Selecció de directori"
+
+msgid "Save File dialog"
+msgstr "Desar fitxer"
+
+msgid "Open File dialog"
+msgstr "Obrir fitxer"
+
+msgid "E338: Sorry, no file browser in console mode"
+msgstr "E338: L'explorador de fitxers no està disponible en mode consola"
+
+msgid "E766: Insufficient arguments for printf()"
+msgstr "E766: Falten arguments a printf()"
+
+msgid "E807: Expected Float argument for printf()"
+msgstr "E807: S'esperava un argument Float a printf()"
+
+msgid "E767: Too many arguments to printf()"
+msgstr "E767: Sobren arguments a printf()"
+
+msgid "W10: Warning: Changing a readonly file"
+msgstr "W10: Atenció: S'està modificant un fitxer de només lectura"
+
+# z=
+msgid "Type number and <Enter> or click with mouse (empty cancels): "
+msgstr "Entreu un número o feu clic (<Entrar> per a cancel·lar): "
+
+# z= (sense mouse)
+msgid "Type number and <Enter> (empty cancels): "
+msgstr "Entreu un número (<Entrar> per a cancel·lar): "
+
+msgid "1 more line"
+msgstr "1 línia més"
+
+msgid "1 line less"
+msgstr "1 línia menys"
+
+#, c-format
+msgid "%ld more lines"
+msgstr "%ld línies més"
+
+#, c-format
+msgid "%ld fewer lines"
+msgstr "%ld línies menys"
+
+msgid " (Interrupted)"
+msgstr " (Interromput)"
+
+msgid "Beep!"
+msgstr "Bip!"
+
+msgid "ERROR: "
+msgstr "ERROR: "
+
+#, c-format
+msgid ""
+"\n"
+"[bytes] total alloc-freed %lu-%lu, in use %lu, peak use %lu\n"
+msgstr ""
+"\n"
+"[octets] total assignat-alliberat %lu-%lu, en ús %lu, màxim ús %lu\n"
+
+#, c-format
+msgid ""
+"[calls] total re/malloc()'s %lu, total free()'s %lu\n"
+"\n"
+msgstr ""
+"[crides] total re/malloc() %lu, total free() %lu\n"
+"\n"
+
+msgid "E340: Line is becoming too long"
+msgstr "E340: La línia s'està fent massa llarga"
+
+#, c-format
+msgid "E341: Internal error: lalloc(%ld, )"
+msgstr "E341: Error intern: lalloc(%ld, )"
+
+#, c-format
+msgid "E342: Out of memory! (allocating %lu bytes)"
+msgstr "E342: Memòria exhaurida! (en assignar %lu octets)"
+
+#, c-format
+msgid "Calling shell to execute: \"%s\""
+msgstr "Es crida l'intèrpret d'ordres per a executar: \"%s\""
+
+msgid "E545: Missing colon"
+msgstr "E545: Falta un caràcter \":\""
+
+msgid "E546: Illegal mode"
+msgstr "E546: Mode il·legal"
+
+msgid "E547: Illegal mouseshape"
+msgstr "E547: La forma del punter del ratolí és il·legal"
+
+msgid "E548: digit expected"
+msgstr "E548: S'esperava un dígit"
+
+msgid "E549: Illegal percentage"
+msgstr "E549: Percentatge il·legal"
+
+msgid "E854: path too long for completion"
+msgstr "E854: la ubicació és massa llarga per a fer compleció"
+
+#, c-format
+msgid ""
+"E343: Invalid path: '**[number]' must be at the end of the path or be "
+"followed by '%s'."
+msgstr "E343: Ubicació no vàlida: '**[núm]' ha d'anar al final de la ubicació, o anar seguit de '%s'"
+
+#, c-format
+msgid "E344: Can't find directory \"%s\" in cdpath"
+msgstr "E344: No s'ha trobat el directori \"%s\" a cdpath"
+
+#, c-format
+msgid "E345: Can't find file \"%s\" in path"
+msgstr "E345: No s'ha trobat el fitxer \"%s\" a path"
+
+#, c-format
+msgid "E346: No more directory \"%s\" found in cdpath"
+msgstr "E346: No s'ha trobat cap més directori \"%s\" a cdpath"
+
+#, c-format
+msgid "E347: No more file \"%s\" found in path"
+msgstr "E347: No s'ha trobat cap més fitxer \"%s\" a path"
+
+#, c-format
+msgid "E668: Wrong access mode for NetBeans connection info file: \"%s\""
+msgstr "E668: El fitxer de connexió NetBeans té permisos incorrectes: \"%s\""
+
+#, c-format
+msgid "E658: NetBeans connection lost for buffer %ld"
+msgstr "E658: S'ha perdut la connexió NetBeans per al buffer %ld"
+
+msgid "E838: netbeans is not supported with this GUI"
+msgstr "E838: aquesta interfície gràfica no suporta NetBeans"
+
+msgid "E511: netbeans already connected"
+msgstr "E511: NetBeans ja està connectat"
+
+#, c-format
+msgid "E505: %s is read-only (add ! to override)"
+msgstr "E505: %s és de només lectura (afegiu ! per a forçar)"
+
+msgid "E349: No identifier under cursor"
+msgstr "E349: El cursor no es troba sobre un identificador"
+
+msgid "E774: 'operatorfunc' is empty"
+msgstr "E774: 'operatorfunc' està en blanc"
+
+msgid "E775: Eval feature not available"
+msgstr "E775: La característica eval no està disponible"
+
+msgid "Warning: terminal cannot highlight"
+msgstr "Atenció: el terminal no suporta ressaltat"
+
+msgid "E348: No string under cursor"
+msgstr "E348: El cursor no es troba sobre una cadena"
+
+msgid "E352: Cannot erase folds with current 'foldmethod'"
+msgstr "E352: No es poden eliminar plecs amb el mètode actual"
+
+msgid "E664: changelist is empty"
+msgstr "E664: La llista de canvis està buida"
+
+# g;
+msgid "E662: At start of changelist"
+msgstr "E662: Us trobeu a l'inici de la llista de canvis"
+
+# g,
+msgid "E663: At end of changelist"
+msgstr "E663: Us trobeu al final de la llista de canvis"
+
+msgid "Type :qa! and press <Enter> to abandon all changes and exit Vim"
+msgstr "Escriviu :qa! i premeu <Entrar> per a abandonar els canvis i sortir"
+
+# la substitució és ">" o "<"
+#, c-format
+msgid "1 line %sed 1 time"
+msgstr "1 línia %sada 1 vegada"
+
+#, c-format
+msgid "1 line %sed %d times"
+msgstr "1 línia %sada %d vegades"
+
+#, c-format
+msgid "%ld lines %sed 1 time"
+msgstr "%ld línies %sades 1 vegada"
+
+#, c-format
+msgid "%ld lines %sed %d times"
+msgstr "%ld línies %sades %d vegades"
+
+#, c-format
+msgid "%ld lines to indent... "
+msgstr "%ld línies a sagnar... "
+
+msgid "1 line indented "
+msgstr "1 línia sagnada "
+
+#, c-format
+msgid "%ld lines indented "
+msgstr "%ld línies sagnades "
+
+msgid "E748: No previously used register"
+msgstr "E748: No hi ha cap registre usat amb anterioritat"
+
+msgid "cannot yank; delete anyway"
+msgstr "no s'ha pogut copiar; voleu eliminar el text de totes maneres"
+
+msgid "1 line changed"
+msgstr "1 línia canviada"
+
+#, c-format
+msgid "%ld lines changed"
+msgstr "%ld línies canviades"
+
+#, c-format
+msgid "freeing %ld lines"
+msgstr "s'alliberen %ld línies"
+
+msgid "block of 1 line yanked"
+msgstr "bloc d'1 línia copiat"
+
+msgid "1 line yanked"
+msgstr "1 línia copiada"
+
+#, c-format
+msgid "block of %ld lines yanked"
+msgstr "bloc de %ld línies copiat"
+
+#, c-format
+msgid "%ld lines yanked"
+msgstr "%ld línies copiades"
+
+#, c-format
+msgid "E353: Nothing in register %s"
+msgstr "E353: No hi ha res en el registre %s"
+
+msgid ""
+"\n"
+"--- Registers ---"
+msgstr ""
+"\n"
+"--- Registres ---"
+
+msgid "Illegal register name"
+msgstr "Nom de registre il·legal"
+
+msgid ""
+"\n"
+"# Registers:\n"
+msgstr ""
+"\n"
+"# Registres:\n"
+
+#, c-format
+msgid "E574: Unknown register type %d"
+msgstr "E574: El tipus de registre %d és desconegut"
+
+msgid ""
+"E883: search pattern and expression register may not contain two or more "
+"lines"
+msgstr "E883: els registres d'expressió i de patró de cerca no poden contenir més d'una línia"
+
+#, c-format
+msgid "%ld Cols; "
+msgstr "%ld Cols; "
+
+# v g C-g
+#, c-format
+msgid "Selected %s%ld of %ld Lines; %lld of %lld Words; %lld of %lld Bytes"
+msgstr "Seleccionat %s%ld de %ld línies; %lld de %lld paraules; %lld de %lld octets"
+
+#, c-format
+msgid ""
+"Selected %s%ld of %ld Lines; %lld of %lld Words; %lld of %lld Chars; %lld of "
+"%lld Bytes"
+msgstr "Seleccionat %s%ld de %ld línies; %lld de %lld paraules; %lld de %lld caràcters; %lld de %lld octets"
+
+# g G-c
+#, c-format
+msgid "Col %s of %s; Line %ld of %ld; Word %lld of %lld; Byte %lld of %lld"
+msgstr "Columna %s de %s; línia %ld de %ld; paraula %lld de %lld; octet %lld de %lld"
+
+#, c-format
+msgid ""
+"Col %s of %s; Line %ld of %ld; Word %lld of %lld; Char %lld of %lld; Byte "
+"%lld of %lld"
+msgstr "Columna %s de %s; línia %ld de %ld; paraula %lld de %lld; caràcter %lld de %lld; octet %lld de %lld"
+
+#, c-format
+msgid "(+%ld for BOM)"
+msgstr "(+%ld per la BOM)"
+
+msgid "%<%f%h%m%=Page %N"
+msgstr "%<%f%h%m%=Pàgina %N"
+
+msgid "Thanks for flying Vim"
+msgstr "Gràcies per utilitzar el Vim"
+
+msgid "E518: Unknown option"
+msgstr "E518: L'opció és desconeguda"
+
+msgid "E519: Option not supported"
+msgstr "E519: L'opció no està suportada"
+
+msgid "E520: Not allowed in a modeline"
+msgstr "E520: No permès en una línia de mode"
+
+# :set t_kb=
+# :set t_kb
+msgid "E846: Key code not set"
+msgstr "E846: Codi de tecla no definit"
+
+msgid "E521: Number required after ="
+msgstr "E521: Falta un número després de ="
+
+msgid "E522: Not found in termcap"
+msgstr "E522: No trobat a la base de dades termcap"
+
+#, c-format
+msgid "E539: Illegal character <%s>"
+msgstr "E539: Caràcter il·legal <%s>"
+
+# error intern
+#, c-format
+msgid "For option %s"
+msgstr "Per a l'opció %s"
+
+msgid "E529: Cannot set 'term' to empty string"
+msgstr "E529: No és possible assignar 'term' a una cadena buida"
+
+msgid "E530: Cannot change term in GUI"
+msgstr "E530: No es pot canviar el terminal en mode GUI"
+
+msgid "E531: Use \":gui\" to start the GUI"
+msgstr "E531: Useu \":gui\" per a iniciar la interfície d'usuari gràfica"
+
+msgid "E589: 'backupext' and 'patchmode' are equal"
+msgstr "E589: Els paràmetres 'backupext' i 'patchmode' coincideixen"
+
+msgid "E834: Conflicts with value of 'listchars'"
+msgstr "E834: Conflicte amb el valor de 'listchars'"
+
+msgid "E835: Conflicts with value of 'fillchars'"
+msgstr "E835: Conflicte amb el valor de 'fillchars'"
+
+msgid "E617: Cannot be changed in the GTK+ 2 GUI"
+msgstr "E617: La interfície GTK+ 2 no permet canviar la codificació"
+
+msgid "E524: Missing colon"
+msgstr "E524: Falta un caràcter \":\""
+
+msgid "E525: Zero length string"
+msgstr "E525: Cadena de longitud zero"
+
+#, c-format
+msgid "E526: Missing number after <%s>"
+msgstr "E526: Falta un número després de <%s>"
+
+msgid "E527: Missing comma"
+msgstr "E527: Falta una coma"
+
+msgid "E528: Must specify a ' value"
+msgstr "E528: Heu d'especificar un valor '"
+
+msgid "E595: contains unprintable or wide character"
+msgstr "E595: Conté un caràcter no imprimible o ample"
+
+msgid "E596: Invalid font(s)"
+msgstr "E596: Fosa no vàlida"
+
+# necessita +xfontset
+msgid "E597: can't select fontset"
+msgstr "E597: No s'ha pogut seleccionar el conjunt de foses"
+
+msgid "E598: Invalid fontset"
+msgstr "E598: El conjunt de foses no és vàlid"
+
+msgid "E533: can't select wide font"
+msgstr "E533: No s'ha pogut seleccionar la fosa per a caràcters amples"
+
+msgid "E534: Invalid wide font"
+msgstr "E534: La fosa per a caràcters amples no és vàlida"
+
+#, c-format
+msgid "E535: Illegal character after <%c>"
+msgstr "E535: Caràcter il·legal després de <%c>"
+
+msgid "E536: comma required"
+msgstr "E536: Es requereix una coma"
+
+#, c-format
+msgid "E537: 'commentstring' must be empty or contain %s"
+msgstr "E537: 'commentstring' ha d'estar en blanc o contenir %s"
+
+msgid "E538: No mouse support"
+msgstr "E538: No hi ha suport per a ratolí"
+
+msgid "E540: Unclosed expression sequence"
+msgstr "E540: Seqüència d'expressions no tancada"
+
+msgid "E541: too many items"
+msgstr "E541: massa ítems"
+
+msgid "E542: unbalanced groups"
+msgstr "E542: grups desequilibrats"
+
+msgid "E590: A preview window already exists"
+msgstr "E590: Ja existeix una finestra de vista prèvia"
+
+msgid "W17: Arabic requires UTF-8, do ':set encoding=utf-8'"
+msgstr "W17: L'idioma àrab requereix UTF-8, feu ':set encoding=utf-8'"
+
+#, c-format
+msgid "E593: Need at least %d lines"
+msgstr "E593: Es necessiten com a mínim %d línies"
+
+#, c-format
+msgid "E594: Need at least %d columns"
+msgstr "E594: Es necessiten com a mínim %d columnes"
+
+#, c-format
+msgid "E355: Unknown option: %s"
+msgstr "E355: Opció desconeguda: %s"
+
+#, c-format
+msgid "E521: Number required: &%s = '%s'"
+msgstr "E521: Fa falta un número: &%s = '%s'"
+
+# :set termcap
+msgid ""
+"\n"
+"--- Terminal codes ---"
+msgstr "\n--- Codis del terminal ---"
+
+# :setglobal
+msgid ""
+"\n"
+"--- Global option values ---"
+msgstr ""
+"\n"
+"--- Valors de les opcions globals ---"
+
+# :setlocal
+msgid ""
+"\n"
+"--- Local option values ---"
+msgstr ""
+"\n"
+"--- Valors de les opcions locals ---"
+
+# :set all
+msgid ""
+"\n"
+"--- Options ---"
+msgstr ""
+"\n"
+"--- Opcions ---"
+
+msgid "E356: get_varp ERROR"
+msgstr "E356: Error a get_varp"
+
+#, c-format
+msgid "E357: 'langmap': Matching character missing for %s"
+msgstr "E357: 'langmap': Cap caràcter coincident per a %s"
+
+#, c-format
+msgid "E358: 'langmap': Extra characters after semicolon: %s"
+msgstr "E358: 'langmap': Sobren caràcters després del punt i coma: %s"
+
+# ... <biblioteca>
+msgid "cannot open "
+msgstr "no s'ha pogut obrir "
+
+msgid "VIM: Can't open window!\n"
+msgstr "VIM: No s'ha pogut obrir la finestra!\n"
+
+msgid "Need Amigados version 2.04 or later\n"
+msgstr "Es necessita Amigados, versió 2.04 o posterior\n"
+
+#, c-format
+msgid "Need %s version %ld\n"
+msgstr "Es necessita %s, versió %ld\n"
+
+msgid "Cannot open NIL:\n"
+msgstr "No s'ha pogut obrir NIL:\n"
+
+msgid "Cannot create "
+msgstr "No s'ha pogut crear "
+
+#, c-format
+msgid "Vim exiting with %d\n"
+msgstr "Vim ha finalitzat amb %d\n"
+
+msgid "cannot change console mode ?!\n"
+msgstr "no s'ha pogut canviar el mode de consola ?!\n"
+
+msgid "mch_get_shellsize: not a console??\n"
+msgstr "mch_get_shellsize: no és una consola??\n"
+
+msgid "E360: Cannot execute shell with -f option"
+msgstr "E360: No és possible executar l'intèrpret conjuntament amb l'opció -f"
+
+# ... shell|<cmd>
+msgid "Cannot execute "
+msgstr "No s'ha pogut executar "
+
+msgid "shell "
+msgstr "l'intèrpret d'ordres "
+
+msgid " returned\n"
+msgstr " ha retornat\n"
+
+msgid "ANCHOR_BUF_SIZE too small."
+msgstr "Valor de ANCHOR_BUF_SIZE massa petit."
+
+msgid "I/O ERROR"
+msgstr "ERROR d'E/S"
+
+msgid "Message"
+msgstr "Missatge"
+
+msgid "E237: Printer selection failed"
+msgstr "E237: Error en seleccionar la impressora"
+
+# todo
+# <impressora> <port>
+#, c-format
+msgid "to %s on %s"
+msgstr "a %s a %s"
+
+#, c-format
+msgid "E613: Unknown printer font: %s"
+msgstr "E613: Fosa d'impressió desconeguda: %s"
+
+#, c-format
+msgid "E238: Print error: %s"
+msgstr "E238: Error d'impressió: %s"
+
+#, c-format
+msgid "Printing '%s'"
+msgstr "Imprimint '%s'"
+
+#, c-format
+msgid "E244: Illegal charset name \"%s\" in font name \"%s\""
+msgstr "E244: Conjunt de caràcters \"%s\" il·legal a la fosa \"%s\""
+
+#, c-format
+msgid "E244: Illegal quality name \"%s\" in font name \"%s\""
+msgstr "E244: Tipus de qualitat \"%s\" il·legal a la fosa \"%s\""
+
+#, c-format
+msgid "E245: Illegal char '%c' in font name \"%s\""
+msgstr "E245: Caràcter '%c' il·legal a la fosa \"%s\""
+
+#, c-format
+msgid "Opening the X display took %ld msec"
+msgstr "Obrir la pantalla X ha tardat %ld mseg"
+
+msgid ""
+"\n"
+"Vim: Got X error\n"
+msgstr "\nVim: Error del sistema de finestres X\n"
+
+msgid "Testing the X display failed"
+msgstr "Error en realitzar els tests de la pantalla X"
+
+msgid "Opening the X display timed out"
+msgstr "Temps esgotat intentant obrir la pantalla X"
+
+msgid ""
+"\n"
+"Could not get security context for "
+msgstr "\nError en obtenir el context de seguretat per a "
+
+msgid ""
+"\n"
+"Could not set security context for "
+msgstr "\nError en establir el context de seguretat per a "
+
+#, c-format
+msgid "Could not set security context %s for %s"
+msgstr "Error en establir el context de seguretat %s per a %s"
+
+#, c-format
+msgid "Could not get security context %s for %s. Removing it!"
+msgstr "Error en obtenir el context de seguretat %s per a %s. Eliminat!"
+
+msgid ""
+"\n"
+"Cannot execute shell sh\n"
+msgstr "\nNo s'ha pogut executar l'intèrpret sh\n"
+
+# <codi de sortida>
+msgid ""
+"\n"
+"shell returned "
+msgstr "\nl'intèrpret ha retornat "
+
+msgid ""
+"\n"
+"Cannot create pipes\n"
+msgstr "\nNo es poden crear canonades\n"
+
+msgid ""
+"\n"
+"Cannot fork\n"
+msgstr "\nNo es pot fer fork\n"
+
+msgid ""
+"\n"
+"Cannot execute shell "
+msgstr "\nNo es pot executar l'intèrpret "
+
+msgid ""
+"\n"
+"Command terminated\n"
+msgstr ""
+"\n"
+"L'ordre ha finalitzat\n"
+
+msgid "XSMP lost ICE connection"
+msgstr "l'XSMP ha perdut la connexió ICE"
+
+#, c-format
+msgid "dlerror = \"%s\""
+msgstr "dlerror = \"%s\""
+
+msgid "Opening the X display failed"
+msgstr "Error en obrir la pantalla X"
+
+msgid "XSMP handling save-yourself request"
+msgstr "s'executa el procediment XSMP save-yourself"
+
+msgid "XSMP opening connection"
+msgstr "s'obre la connexió XSMP"
+
+msgid "XSMP ICE connection watch failed"
+msgstr "ha fallat la supervisió de la connexió XSMP ICE"
+
+#, c-format
+msgid "XSMP SmcOpenConnection failed: %s"
+msgstr "ha fallat la rutina XSMP SmcOpenConnection: %s"
+
+msgid "At line"
+msgstr "A la línia"
+
+msgid "Could not load vim32.dll!"
+msgstr "No s'ha pogut carregar vim32.dll!"
+
+msgid "VIM Error"
+msgstr "Error del VIM"
+
+msgid "Could not fix up function pointers to the DLL!"
+msgstr "No s'han pogut reassignar els punters de funcions a la DLL!"
+
+#, c-format
+msgid "Vim: Caught %s event\n"
+msgstr "Vim: S'ha atrapat un esdeveniment %s\n"
+
+msgid "close"
+msgstr "de finalització"
+
+msgid "logoff"
+msgstr "de final de sessió"
+
+msgid "shutdown"
+msgstr "d'apagament del sistema"
+
+msgid "E371: Command not found"
+msgstr "E371: No s'ha trobat l'ordre"
+
+msgid ""
+"VIMRUN.EXE not found in your $PATH.\n"
+"External commands will not pause after completion.\n"
+"See :help win32-vimrun for more information."
+msgstr ""
+"El programa VIMRUN.EXE no es troba en el $PATH.\n"
+"Les ordres externes no faran una pausa un cop finalitzades.\n"
+"Vegeu :help win32-vimrun per a més informació."
+
+msgid "Vim Warning"
+msgstr "Vim: Atenció"
+
+#, c-format
+msgid "shell returned %d"
+msgstr "l'intèrpret ha retornat %d"
+
+#, c-format
+msgid "E372: Too many %%%c in format string"
+msgstr "E372: Sobren %%%c a la cadena de format"
+
+#, c-format
+msgid "E373: Unexpected %%%c in format string"
+msgstr "E373: %%%c inesperat a la cadena de format"
+
+msgid "E374: Missing ] in format string"
+msgstr "E374: Falta un ] a la cadena de format"
+
+#, c-format
+msgid "E375: Unsupported %%%c in format string"
+msgstr "E375: %%%c no suportat a la cadena de format"
+
+#, c-format
+msgid "E376: Invalid %%%c in format string prefix"
+msgstr "E376: %%%c no vàlid en el prefix de la cadena de format"
+
+#, c-format
+msgid "E377: Invalid %%%c in format string"
+msgstr "E377: %%%c no vàlid a la cadena de format"
+
+msgid "E378: 'errorformat' contains no pattern"
+msgstr "E378: 'errorformat' no conté cap patró"
+
+msgid "E379: Missing or empty directory name"
+msgstr "E379: Falta un nom de directori"
+
+msgid "E553: No more items"
+msgstr "E553: No hi ha més ítems"
+
+msgid "E924: Current window was closed"
+msgstr "E924: S'ha tancat la finestra actual"
+
+msgid "E925: Current quickfix was changed"
+msgstr "E925: La llista quickfix ha canviat"
+
+msgid "E926: Current location list was changed"
+msgstr "E926: La llista d'ubicacions ha canviat"
+
+#, c-format
+msgid "(%d of %d)%s%s: "
+msgstr "(%d de %d)%s%s: "
+
+msgid " (line deleted)"
+msgstr " (línia eliminada)"
+
+# subst: " " | "> "
+#, c-format
+msgid "%serror list %d of %d; %d errors "
+msgstr "%sllista d'errors %d de %d; %d errors"
+
+msgid "E380: At bottom of quickfix stack"
+msgstr "E380: A baix de la pila quickfix"
+
+msgid "E381: At top of quickfix stack"
+msgstr "E381: A dalt de la pila quickfix"
+
+msgid "No entries"
+msgstr "No hi ha entrades"
+
+msgid "E382: Cannot write, 'buftype' option is set"
+msgstr "E382: No es pot escriure, 'buftype' està establert"
+
+# :browse :cfile
+msgid "Error file"
+msgstr "Fitxer d'errors"
+
+msgid "E683: File name missing or invalid pattern"
+msgstr "E683: Falta un nom de fitxer o el patró no és vàlid"
+
+#, c-format
+msgid "Cannot open file \"%s\""
+msgstr "No s'ha pogut obrir el fitxer \"%s\""
+
+msgid "E681: Buffer is not loaded"
+msgstr "E681: El buffer no està carregat"
+
+msgid "E777: String or List expected"
+msgstr "E777: S'esperava String o List"
+
+#, c-format
+msgid "E369: invalid item in %s%%[]"
+msgstr "E369: Ítem no vàlid a %s%%[]"
+
+#, c-format
+msgid "E769: Missing ] after %s["
+msgstr "E769: Falta un ] després de %s["
+
+msgid "E944: Reverse range in character class"
+msgstr "E944: Interval en ordre invers a la classe de caràcter"
+
+msgid "E945: Range too large in character class"
+msgstr "E945: Interval massa ample a la classe de caràcter"
+
+#, c-format
+msgid "E53: Unmatched %s%%("
+msgstr "E53: %s%%( desequilibrat"
+
+#, c-format
+msgid "E54: Unmatched %s("
+msgstr "E54: %s( desequilibrat"
+
+#, c-format
+msgid "E55: Unmatched %s)"
+msgstr "E55: %s) desequilibrat"
+
+msgid "E66: \\z( not allowed here"
+msgstr "E66: \\z( no està permès aquí"
+
+msgid "E67: \\z1 - \\z9 not allowed here"
+msgstr "E67: \\z1 - \\z9 no estan permesos aquí"
+
+#, c-format
+msgid "E69: Missing ] after %s%%["
+msgstr "E69: Falta un ] després de %s%%["
+
+#, c-format
+msgid "E70: Empty %s%%[]"
+msgstr "E70: %s%%[] buit"
+
+msgid "E65: Illegal back reference"
+msgstr "E65: Referència enrere il·legal"
+
+msgid "E339: Pattern too long"
+msgstr "E339: El patró és massa llarg"
+
+msgid "E50: Too many \\z("
+msgstr "E50: Sobren \\z("
+
+#, c-format
+msgid "E51: Too many %s("
+msgstr "E51: Sobren %s("
+
+msgid "E52: Unmatched \\z("
+msgstr "E52: \\z( desequilibrat"
+
+#, c-format
+msgid "E59: invalid character after %s@"
+msgstr "E59: caràcter no vàlid després de %s@"
+
+# complex braces
+#, c-format
+msgid "E60: Too many complex %s{...}s"
+msgstr "E60: Massa %s{...}s"
+
+# a\{}\{}
+#, c-format
+msgid "E61: Nested %s*"
+msgstr "E61: %s* imbricats"
+
+#, c-format
+msgid "E62: Nested %s%c"
+msgstr "E62: %s%c imbricats"
+
+msgid "E63: invalid use of \\_"
+msgstr "E63: Ús invàlid de \\_"
+
+#, c-format
+msgid "E64: %s%c follows nothing"
+msgstr "E64: %s%c no segueix res"
+
+msgid "E68: Invalid character after \\z"
+msgstr "E68: Caràcter invàlid després de \\z"
+
+#, c-format
+msgid "E678: Invalid character after %s%%[dxouU]"
+msgstr "E678: Caràcter invàlid després de %s%%[dxouU]"
+
+#, c-format
+msgid "E71: Invalid character after %s%%"
+msgstr "E71: Caràcter invàlid després de %s%%"
+
+#, c-format
+msgid "E554: Syntax error in %s{...}"
+msgstr "E554: Error de sintaxi a %s{...}"
+
+msgid "External submatches:\n"
+msgstr "Coincidències parcials externes:\n"
+
+#, c-format
+msgid "E888: (NFA regexp) cannot repeat %s"
+msgstr "E888: (NFA) no és possible repetir %s"
+
+msgid ""
+"E864: \\%#= can only be followed by 0, 1, or 2. The automatic engine will be "
+"used "
+msgstr "E864: \\%#= ha d'anar seguit de 0, 1 o 2. Es canvia al motor automàtic."
+
+msgid "Switching to backtracking RE engine for pattern: "
+msgstr "Es canvia al motor d'ER amb backtracking per al patró: "
+
+msgid "E865: (NFA) Regexp end encountered prematurely"
+msgstr "E865: (NFA) final prematur de l'expressió regular"
+
+#, c-format
+msgid "E866: (NFA regexp) Misplaced %c"
+msgstr "E866: (NFA) %c mal col·locat"
+
+#, c-format
+msgid "E877: (NFA regexp) Invalid character class: %ld"
+msgstr "E877: (NFA) Classe de caràcter invàlida: %ld"
+
+#, c-format
+msgid "E867: (NFA) Unknown operator '\\z%c'"
+msgstr "E867: (NFA) Operador desconegut '\\z%c'"
+
+#, c-format
+msgid "E867: (NFA) Unknown operator '\\%%%c'"
+msgstr "E867: (NFA) Operador desconegut '\\%%%c'"
+
+# todo
+msgid "E868: Error building NFA with equivalence class!"
+msgstr "E868: Error en construir l'NFA amb classe d'equivalència!"
+
+#, c-format
+msgid "E869: (NFA) Unknown operator '\\@%c'"
+msgstr "E869: (NFA) Operador desconegut '\\@%c'"
+
+msgid "E870: (NFA regexp) Error reading repetition limits"
+msgstr "E870: (NFA) Error en llegir els límits de repetició"
+
+msgid "E871: (NFA regexp) Can't have a multi follow a multi"
+msgstr "E871: (NFA) Diverses especificacions de multiplicitat seguides"
+
+msgid "E872: (NFA regexp) Too many '('"
+msgstr "E872: (NFA) Sobren '('"
+
+msgid "E879: (NFA regexp) Too many \\z("
+msgstr "E879: (NFA) Sobren \\z("
+
+msgid "E873: (NFA regexp) proper termination error"
+msgstr "E873: (NFA) parèntesi sense tancar"
+
+msgid "E874: (NFA) Could not pop the stack!"
+msgstr "E874: (NFA) No es poden treure elements de la pila !"
+
+msgid ""
+"E875: (NFA regexp) (While converting from postfix to NFA), too many states "
+"left on stack"
+msgstr "E875: (NFA) (En convertir de postfix a NFA), la pila conté massa estats"
+
+msgid "E876: (NFA regexp) Not enough space to store the whole NFA "
+msgstr "E876: (NFA) Espai insuficient per a desar l'NFA"
+
+msgid "E878: (NFA) Could not allocate memory for branch traversal!"
+msgstr "E878: (NFA) Memòria insuficient per a recórrer la branca!"
+
+msgid ""
+"Could not open temporary log file for writing, displaying on stderr... "
+msgstr "No es pot obrir un fitxer temporal de logs, s'escriu a stderr... "
+
+#, c-format
+msgid "(NFA) COULD NOT OPEN %s !"
+msgstr "(NFA) NO ES POT OBRIR %s !"
+
+msgid "Could not open temporary log file for writing "
+msgstr "Error en obrir un fitxer temporal per a logs "
+
+# gR
+msgid " VREPLACE"
+msgstr " SUBSTITUIRV"
+
+msgid " REPLACE"
+msgstr " SUBSTITUIR"
+
+# mode d'escriptura de dreta a esquerra: «REVERSE INSERT»
+msgid " REVERSE"
+msgstr " INVERS"
+
+# i
+msgid " INSERT"
+msgstr " INSERIR"
+
+msgid " (insert)"
+msgstr " (inserir)"
+
+msgid " (replace)"
+msgstr " (substituir)"
+
+msgid " (vreplace)"
+msgstr " (substituirv)"
+
+msgid " Hebrew"
+msgstr " Hebreu"
+
+msgid " Arabic"
+msgstr " Àrab"
+
+msgid " (paste)"
+msgstr " (enganxar)"
+
+msgid " VISUAL"
+msgstr " VISUAL"
+
+msgid " VISUAL LINE"
+msgstr " VISUAL LÍNIA"
+
+msgid " VISUAL BLOCK"
+msgstr " VISUAL BLOC"
+
+msgid " SELECT"
+msgstr " SELECCIONAR"
+
+msgid " SELECT LINE"
+msgstr " SELECCIONAR LÍNIA"
+
+msgid " SELECT BLOCK"
+msgstr " SELECCIONAR BLOC"
+
+msgid "recording"
+msgstr "enregistrant"
+
+#, c-format
+msgid "E383: Invalid search string: %s"
+msgstr "E383: Cadena de cerca no vàlida: %s"
+
+#, c-format
+msgid "E384: search hit TOP without match for: %s"
+msgstr "E384: la cerca ha arribat a DALT sense resultats per: %s"
+
+#, c-format
+msgid "E385: search hit BOTTOM without match for: %s"
+msgstr "E385: la cerca ha arribat a BAIX sense resultats per: %s"
+
+msgid "E386: Expected '?' or '/' after ';'"
+msgstr "E386: S'esperava '?' o '/' després de ';'"
+
+msgid " (includes previously listed match)"
+msgstr " (inclou resultats mostrats anteriorment)"
+
+# :checkpath
+# :checkpath!
+msgid "--- Included files "
+msgstr "--- Fitxers inclosos "
+
+# Included files ... not found ... in path
+msgid "not found "
+msgstr "no trobats "
+
+# todo: path
+msgid "in path ---\n"
+msgstr "al path ---\n"
+
+msgid " (Already listed)"
+msgstr " (Ja llistat)"
+
+msgid " NOT FOUND"
+msgstr " NO TROBAT"
+
+#, c-format
+msgid "Scanning included file: %s"
+msgstr "Examinant el fitxer inclòs: %s"
+
+# :isearch /BAR/
+# :checkpath!
+#, c-format
+msgid "Searching included file %s"
+msgstr "Cercant al fitxer inclòs %s"
+
+msgid "E387: Match is on current line"
+msgstr "E387: El resultat es troba a la línia actual"
+
+msgid "All included files were found"
+msgstr "S'han trobat tots els fitxers inclosos"
+
+msgid "No included files"
+msgstr "No hi ha fitxers inclosos"
+
+msgid "E388: Couldn't find definition"
+msgstr "E388: No s'ha trobat la definició"
+
+msgid "E389: Couldn't find pattern"
+msgstr "E389: No s'ha trobat el patró"
+
+# viminfo
+msgid "Substitute "
+msgstr " (substitució)"
+
+# Last <Substitute> Search Pattern
+#, c-format
+msgid ""
+"\n"
+"# Last %sSearch Pattern:\n"
+"~"
+msgstr ""
+"\n"
+"# Últim patró de cerca%s:\n"
+"~"
+
+msgid "E756: Spell checking is not enabled"
+msgstr "E756: La comprovació ortogràfica no està activada"
+
+#, c-format
+msgid "Warning: Cannot find word list \"%s_%s.spl\" or \"%s_ascii.spl\""
+msgstr "Atenció: No s'ha trobat \"%s_%s.spl\" ni \"%s_ascii.spl\""
+
+#, c-format
+msgid "Warning: Cannot find word list \"%s.%s.spl\" or \"%s.ascii.spl\""
+msgstr "Atenció: No s'ha trobat \"%s.%s.spl\" ni \"%s.ascii.spl\""
+
+msgid "E797: SpellFileMissing autocommand deleted buffer"
+msgstr "E797: L'ordre automàtica SpellFileMissing ha eliminat el buffer"
+
+#, c-format
+msgid "Warning: region %s not supported"
+msgstr "Atenció: no hi ha suport per a la regió %s"
+
+msgid "Sorry, no suggestions"
+msgstr "No hi ha suggeriments"
+
+#, c-format
+msgid "Sorry, only %ld suggestions"
+msgstr "Només hi ha %ld suggeriments"
+
+#, c-format
+msgid "Change \"%.*s\" to:"
+msgstr "Canviar \"%.*s\" per:"
+
+#, c-format
+msgid " < \"%.*s\""
+msgstr " < \"%.*s\""
+
+msgid "E752: No previous spell replacement"
+msgstr "E752: No hi ha cap correcció prèvia"
+
+#, c-format
+msgid "E753: Not found: %s"
+msgstr "E753: No trobat: %s"
+
+msgid "E758: Truncated spell file"
+msgstr "E758: Fitxer d'ortografia truncat"
+
+#, c-format
+msgid "Trailing text in %s line %d: %s"
+msgstr "Text sobrer a %s, línia %d: %s"
+
+#, c-format
+msgid "Affix name too long in %s line %d: %s"
+msgstr "Nom d'afix és massa llarg a %s, línia %d: %s"
+
+msgid "E761: Format error in affix file FOL, LOW or UPP"
+msgstr "E761: Error de format en el fitxer d'afixos FOL, LOW o UPP"
+
+msgid "E762: Character in FOL, LOW or UPP is out of range"
+msgstr "E762: Caràcter a FOL, LOW o UPP fora de l'interval"
+
+msgid "Compressing word tree..."
+msgstr "Comprimint l'arbre de paraules..."
+
+#, c-format
+msgid "Reading spell file \"%s\""
+msgstr "Llegint el fitxer d'ortografia \"%s\""
+
+msgid "E757: This does not look like a spell file"
+msgstr "E757: No és un fitxer d'ortografia"
+
+msgid "E771: Old spell file, needs to be updated"
+msgstr "E771: Fitxer d'ortografia obsolet, ha de ser actualitzat"
+
+msgid "E772: Spell file is for newer version of Vim"
+msgstr "E772: Fitxer d'ortografia per a una versió més recent del Vim"
+
+msgid "E770: Unsupported section in spell file"
+msgstr "E770: El fitxer d'ortografia conté una secció no suportada"
+
+#, c-format
+msgid "E778: This does not look like a .sug file: %s"
+msgstr "E778: No és un fitxer .sug: %s"
+
+#, c-format
+msgid "E779: Old .sug file, needs to be updated: %s"
+msgstr "E779: Fitxer .sug obsolet, ha de ser actualitzat: %s"
+
+#, c-format
+msgid "E780: .sug file is for newer version of Vim: %s"
+msgstr "E780: Fitxer .sug per a una versió més recent del Vim: %s"
+
+#, c-format
+msgid "E781: .sug file doesn't match .spl file: %s"
+msgstr "E781: El fitxer .sug no coincideix amb el fitxer .spl: %s"
+
+#, c-format
+msgid "E782: error while reading .sug file: %s"
+msgstr "E782: error en llegir el fitxer .sug: %s"
+
+#, c-format
+msgid "Reading affix file %s..."
+msgstr "Llegint el fitxer d'afixos %s..."
+
+#, c-format
+msgid "Conversion failure for word in %s line %d: %s"
+msgstr "No s'ha pogut convertir una paraula a %s, línia %d: %s"
+
+# <fname>
+#, c-format
+msgid "Conversion in %s not supported: from %s to %s"
+msgstr "La conversió a %s no està suportada: de %s a %s"
+
+#, c-format
+msgid "Conversion in %s not supported"
+msgstr "Conversió a %s no suportada"
+
+#, c-format
+msgid "Invalid value for FLAG in %s line %d: %s"
+msgstr "Valor de FLAG invàlid a %s, línia %d: %s"
+
+#, c-format
+msgid "FLAG after using flags in %s line %d: %s"
+msgstr "FLAG posterior a l'ús de flags %s, línia %d: %s"
+
+#, c-format
+msgid ""
+"Defining COMPOUNDFORBIDFLAG after PFX item may give wrong results in %s line "
+"%d"
+msgstr "Definir COMPOUNDFORBIDFLAG després de PFX, pot donar resultats incorrectes, a %s, línia %d"
+
+#, c-format
+msgid ""
+"Defining COMPOUNDPERMITFLAG after PFX item may give wrong results in %s line "
+"%d"
+msgstr "Definir COMPOUNDPERMITFLAG després de PFX, pot donar resultats incorrectes, a %s, línia %d"
+
+#, c-format
+msgid "Wrong COMPOUNDRULES value in %s line %d: %s"
+msgstr "Valor de COMPOUNDRULES incorrecte a %s, línia %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDWORDMAX value in %s line %d: %s"
+msgstr "Valor de COMPOUNDWORDMAX incorrecte a %s, línia %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDMIN value in %s line %d: %s"
+msgstr "Valor de COMPOUNDMIN incorrecte a %s, línia %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDSYLMAX value in %s line %d: %s"
+msgstr "Valor de COMPOUNDSYLMAX incorrecte a %s, línia %d: %s"
+
+#, c-format
+msgid "Wrong CHECKCOMPOUNDPATTERN value in %s line %d: %s"
+msgstr "Valor de CHECKCOMPOUNDPATTERN incorrecte a %s, línia %d: %s"
+
+#, c-format
+msgid "Different combining flag in continued affix block in %s line %d: %s"
+msgstr "Diferents tipus de combinació en bloc d'afixos a %s, línia %d: %s"
+
+#, c-format
+msgid "Duplicate affix in %s line %d: %s"
+msgstr "Afix duplicat a %s, línia %d: %s"
+
+#, c-format
+msgid ""
+"Affix also used for BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST in %s "
+"line %d: %s"
+msgstr "Mateix afix utilitzat per BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST a %s, línia %d: %s"
+
+#, c-format
+msgid "Expected Y or N in %s line %d: %s"
+msgstr "S'esperava Y o N a %s, línia %d: %s"
+
+#, c-format
+msgid "Broken condition in %s line %d: %s"
+msgstr "Condició errònia a %s, línia %d: %s"
+
+#, c-format
+msgid "Expected REP(SAL) count in %s line %d"
+msgstr "S'esperava un enter no negatiu per a REP(SAL) a %s, línia %d"
+
+#, c-format
+msgid "Expected MAP count in %s line %d"
+msgstr "S'esperava un enter no negatiu per a MAP a %s, línia %d"
+
+#, c-format
+msgid "Duplicate character in MAP in %s line %d"
+msgstr "Caràcter duplicat a MAP a %s, línia %d"
+
+#, c-format
+msgid "Unrecognized or duplicate item in %s line %d: %s"
+msgstr "Element no reconegut o duplicat a %s, línia %d: %s"
+
+#, c-format
+msgid "Missing FOL/LOW/UPP line in %s"
+msgstr "Falta una línia FOL/LOW/UPP a %s"
+
+msgid "COMPOUNDSYLMAX used without SYLLABLE"
+msgstr "Element COMPOUNDSYLMAX sense SYLLABLE"
+
+msgid "Too many postponed prefixes"
+msgstr "Sobren prefixes posposats"
+
+msgid "Too many compound flags"
+msgstr "Sobren flags de composició"
+
+msgid "Too many postponed prefixes and/or compound flags"
+msgstr "Sobren prefixes posposats i/o flags de composició"
+
+#, c-format
+msgid "Missing SOFO%s line in %s"
+msgstr "Falta una línia SOFO%s a %s"
+
+#, c-format
+msgid "Both SAL and SOFO lines in %s"
+msgstr "Línies SAL i SOFO alhora a %s"
+
+#, c-format
+msgid "Flag is not a number in %s line %d: %s"
+msgstr "Flag no numèric a %s, línia %d: %s"
+
+#, c-format
+msgid "Illegal flag in %s line %d: %s"
+msgstr "Flag il·legal a %s, línia %d: %s"
+
+#, c-format
+msgid "%s value differs from what is used in another .aff file"
+msgstr "el valor %s difereix de l'usat en un altre fitxer .aff"
+
+#, c-format
+msgid "Reading dictionary file %s..."
+msgstr "Llegint el fitxer de diccionari %s..."
+
+#, c-format
+msgid "E760: No word count in %s"
+msgstr "E760: Falta el nombre de paraules a %s"
+
+#, c-format
+msgid "line %6d, word %6d - %s"
+msgstr "línia %6d, paraula %6d - %s"
+
+#, c-format
+msgid "Duplicate word in %s line %d: %s"
+msgstr "Paraula duplicada a %s, línia %d: %s"
+
+#, c-format
+msgid "First duplicate word in %s line %d: %s"
+msgstr "Primera paraula duplicada a %s, línia %d: %s"
+
+#, c-format
+msgid "%d duplicate word(s) in %s"
+msgstr "%d paraula/es duplicada/es a %s"
+
+#, c-format
+msgid "Ignored %d word(s) with non-ASCII characters in %s"
+msgstr "S'ignora/en %d paraula/es amb caràcters no-ASCII a %s"
+
+#, c-format
+msgid "Reading word file %s..."
+msgstr "Llegint el fitxer de paraules %s..."
+
+#, c-format
+msgid "Duplicate /encoding= line ignored in %s line %d: %s"
+msgstr "S'ignora línia /encoding= duplicada a %s, línia %d: %s"
+
+#, c-format
+msgid "/encoding= line after word ignored in %s line %d: %s"
+msgstr "S'ignora línia /encoding= després de paraula a %s, línia %d: %s"
+
+#, c-format
+msgid "Duplicate /regions= line ignored in %s line %d: %s"
+msgstr "S'ignora línia /regions= duplicada a %s, línia %d: %s"
+
+#, c-format
+msgid "Too many regions in %s line %d: %s"
+msgstr "Sobren regions a %s, línia %d: %s"
+
+#, c-format
+msgid "/ line ignored in %s line %d: %s"
+msgstr "S'ignora línia / a %s, línia %d: %s"
+
+#, c-format
+msgid "Invalid region nr in %s line %d: %s"
+msgstr "Número de regió no vàlid a %s, línia %d: %s"
+
+#, c-format
+msgid "Unrecognized flags in %s line %d: %s"
+msgstr "Flags no reconeguts a %s, línia %d: %s"
+
+#, c-format
+msgid "Ignored %d words with non-ASCII characters"
+msgstr "S'ignoren %d paraules amb caràcters no-ASCII"
+
+msgid "E845: Insufficient memory, word list will be incomplete"
+msgstr "E845: Memòria insuficient, la llista de paraules serà incompleta"
+
+#, c-format
+msgid "Compressed %d of %d nodes; %d (%d%%) remaining"
+msgstr "Comprimits %d de %d nodes; %d (%d%%) pendents"
+
+msgid "Reading back spell file..."
+msgstr "Tornant a llegir el fitxer d'ortografia..."
+
+msgid "Performing soundfolding..."
+msgstr "Efectuant expansió per similitud fonètica..."
+
+#, c-format
+msgid "Number of words after soundfolding: %ld"
+msgstr "Nombre de paraules després de l'expansió per similitud fonètica: %ld"
+
+#, c-format
+msgid "Total number of words: %d"
+msgstr "Nombre total de paraules: %d"
+
+#, c-format
+msgid "Writing suggestion file %s..."
+msgstr "Escrivint el fitxer de suggeriments %s..."
+
+#, c-format
+msgid "Estimated runtime memory use: %d bytes"
+msgstr "Ús estimat de memòria durant l'execució: %d octets"
+
+msgid "E751: Output file name must not have region name"
+msgstr "E751: El fitxer de sortida no pot tenir un nom de regió"
+
+msgid "E754: Only up to 8 regions supported"
+msgstr "E754: Només es suporten fins a 8 regions"
+
+#, c-format
+msgid "E755: Invalid region in %s"
+msgstr "E755: Regió no vàlida a %s"
+
+msgid "Warning: both compounding and NOBREAK specified"
+msgstr "Atenció: s'ha especificat composició i NOBREAK alhora"
+
+#, c-format
+msgid "Writing spell file %s..."
+msgstr "Escrivint el fitxer d'ortografia %s..."
+
+msgid "Done!"
+msgstr "Fet!"
+
+#, c-format
+msgid "E765: 'spellfile' does not have %ld entries"
+msgstr "E765: 'spellfile' no té %ld entrades"
+
+#, c-format
+msgid "Word '%.*s' removed from %s"
+msgstr "Paraula '%.*s' eliminada de %s"
+
+#, c-format
+msgid "Word '%.*s' added to %s"
+msgstr "Paraula '%.*s' afegida a %s"
+
+msgid "E763: Word characters differ between spell files"
+msgstr "E763: Les llistes de caràcters constituents de paraula no coincideixen"
+
+msgid "E783: duplicate char in MAP entry"
+msgstr "E783: Caràcter duplicat a l'entrada MAP"
+
+msgid "No Syntax items defined for this buffer"
+msgstr "No s'han definit elements de sintaxi per a aquest buffer"
+
+msgid "syntax conceal on"
+msgstr "ocultació de sintaxi activada"
+
+msgid "syntax conceal off"
+msgstr "ocultació de sintaxi desactivada"
+
+#, c-format
+msgid "E390: Illegal argument: %s"
+msgstr "E390: L'argument és il·legal: %s"
+
+msgid "syntax case ignore"
+msgstr "la sintaxi distingeix majúscules"
+
+msgid "syntax case match"
+msgstr "la sintaxi no distingeix majúscules"
+
+msgid "syntax spell toplevel"
+msgstr "sintaxi amb revisió ortogràfica"
+
+msgid "syntax spell notoplevel"
+msgstr "sintaxi sense revisió ortogràfica"
+
+msgid "syntax spell default"
+msgstr "sintaxi amb revisió ortogràfica per defecte"
+
+# todo: not set
+# valor de 'iskeyword' o "not set"
+msgid "syntax iskeyword "
+msgstr "sintaxi 'iskeyword' "
+
+#, c-format
+msgid "E391: No such syntax cluster: %s"
+msgstr "E391: No existeix tal clúster de sintaxi: %s"
+
+msgid "syncing on C-style comments"
+msgstr "se sincronitza amb comentaris estil C"
+
+msgid "no syncing"
+msgstr "no es sincronitza"
+
+# junt amb el següent
+msgid "syncing starts "
+msgstr "la sincronització comença "
+
+# junt amb l'anterior
+msgid " lines before top line"
+msgstr " línies abans de la línia superior"
+
+msgid ""
+"\n"
+"--- Syntax sync items ---"
+msgstr "\n--- Elements de sincronització de sintaxi ---"
+
+msgid ""
+"\n"
+"syncing on items"
+msgstr "\nes sincronitza amb elements"
+
+msgid ""
+"\n"
+"--- Syntax items ---"
+msgstr "\n--- Elements de sintaxi ---"
+
+#, c-format
+msgid "E392: No such syntax cluster: %s"
+msgstr "E392: No existeix tal clúster de sintaxi: %s"
+
+# ... <lines before the top line>
+msgid "minimal "
+msgstr "mínim "
+
+msgid "maximal "
+msgstr "màxim "
+
+# match ... line breaks
+msgid "; match "
+msgstr "; coincident amb "
+
+msgid " line breaks"
+msgstr " salts de línia"
+
+msgid "E395: contains argument not accepted here"
+msgstr "E395: conté argument no vàlid en aquest context"
+
+msgid "E844: invalid cchar value"
+msgstr "E844: valor de cchar invàlid"
+
+msgid "E393: group[t]here not accepted here"
+msgstr "E393: grouphere/groupthere no és vàlid en aquest context"
+
+#, c-format
+msgid "E394: Didn't find region item for %s"
+msgstr "E394: No s'ha trobat cap element de regió per a %s"
+
+msgid "E397: Filename required"
+msgstr "E397: Necessita un nom de fitxer"
+
+msgid "E847: Too many syntax includes"
+msgstr "E847: Sobren inclusions de sintaxi"
+
+#, c-format
+msgid "E789: Missing ']': %s"
+msgstr "E789: Falta un ']': %s"
+
+#, c-format
+msgid "E890: trailing char after ']': %s]%s"
+msgstr "E890: caràcter sobrer després de ']': %s]%s"
+
+#, c-format
+msgid "E398: Missing '=': %s"
+msgstr "E398: Falta un '=': %s"
+
+# 'syntax region' és una ordre
+#, c-format
+msgid "E399: Not enough arguments: syntax region %s"
+msgstr "E399: Falten arguments: syntax region %s"
+
+msgid "E848: Too many syntax clusters"
+msgstr "E848: Sobren clústers de sintaxi"
+
+msgid "E400: No cluster specified"
+msgstr "E400: No s'ha especificat cap clúster"
+
+#, c-format
+msgid "E401: Pattern delimiter not found: %s"
+msgstr "E401: No s'ha trobat el delimitador: %s"
+
+#, c-format
+msgid "E402: Garbage after pattern: %s"
+msgstr "E402: Caràcters sobrants després del patró: %s"
+
+msgid "E403: syntax sync: line continuations pattern specified twice"
+msgstr "E403: syntax sync: patró de continuació de línia repetit"
+
+#, c-format
+msgid "E404: Illegal arguments: %s"
+msgstr "E404: Arguments il·legals: %s"
+
+#, c-format
+msgid "E405: Missing equal sign: %s"
+msgstr "E405: Falta un signe d'igual: %s"
+
+#, c-format
+msgid "E406: Empty argument: %s"
+msgstr "E406: Argument buit: %s"
+
+#, c-format
+msgid "E407: %s not allowed here"
+msgstr "E407: %s no permès en aquest context"
+
+#, c-format
+msgid "E408: %s must be first in contains list"
+msgstr "E408: %s ha d'anar al principi a 'contains'"
+
+#, c-format
+msgid "E409: Unknown group name: %s"
+msgstr "E409: Nom de grup desconegut: %s"
+
+#, c-format
+msgid "E410: Invalid :syntax subcommand: %s"
+msgstr "E410: Subordre de :syntax no vàlida: %s"
+
+# :syntime report
+msgid ""
+" TOTAL COUNT MATCH SLOWEST AVERAGE NAME PATTERN"
+msgstr " TOTAL FREQ COINC PITJOR MITJANA NOM PATRÓ"
+
+msgid "E679: recursive loop loading syncolor.vim"
+msgstr "E679: bucle infinit en carregar syncolor.vim"
+
+#, c-format
+msgid "E411: highlight group not found: %s"
+msgstr "E411: grup de ressaltat no trobat: %s"
+
+#, c-format
+msgid "E412: Not enough arguments: \":highlight link %s\""
+msgstr "E412: Falten arguments: \":highlight link %s\""
+
+#, c-format
+msgid "E413: Too many arguments: \":highlight link %s\""
+msgstr "E413: Sobren arguments: \":highlight link %s\""
+
+msgid "E414: group has settings, highlight link ignored"
+msgstr "E414: el grup ja té paràmetres, s'ignora l'enllaç"
+
+#, c-format
+msgid "E415: unexpected equal sign: %s"
+msgstr "E415: signe d'igualtat inesperat: %s"
+
+#, c-format
+msgid "E416: missing equal sign: %s"
+msgstr "E416: falta un signe d'igual: %s"
+
+#, c-format
+msgid "E417: missing argument: %s"
+msgstr "E417: falta un argument: %s"
+
+#, c-format
+msgid "E418: Illegal value: %s"
+msgstr "E418: Valor il·legal: %s"
+
+msgid "E419: FG color unknown"
+msgstr "E419: Color de primer terme desconegut"
+
+msgid "E420: BG color unknown"
+msgstr "E420: Color de segon terme desconegut"
+
+#, c-format
+msgid "E421: Color name or number not recognized: %s"
+msgstr "E421: Nom o número de color no reconegut: %s"
+
+#, c-format
+msgid "E422: terminal code too long: %s"
+msgstr "E422: codi de terminal massa llarg: %s"
+
+#, c-format
+msgid "E423: Illegal argument: %s"
+msgstr "E423: Argument il·legal: %s"
+
+msgid "E424: Too many different highlighting attributes in use"
+msgstr "E424: Hi ha massa atributs de ressaltat diferents en ús"
+
+msgid "E669: Unprintable character in group name"
+msgstr "E669: Caràcter no imprimible en el nom del grup"
+
+msgid "W18: Invalid character in group name"
+msgstr "W18: Hi ha un caràcter no vàlid en el nom del grup"
+
+msgid "E849: Too many highlight and syntax groups"
+msgstr "E849: Massa grups de sintaxi i de ressaltat"
+
+msgid "E555: at bottom of tag stack"
+msgstr "E555: a baix de la pila d'etiquetes"
+
+msgid "E556: at top of tag stack"
+msgstr "E556: a dalt de la pila d'etiquetes"
+
+msgid "E425: Cannot go before first matching tag"
+msgstr "E425: No es pot anar més enllà de la primera etiqueta coincident"
+
+#, c-format
+msgid "E426: tag not found: %s"
+msgstr "E426: No s'ha trobat l'etiqueta: %s"
+
+# :tselect
+# <c><l><?><l>
+msgid " # pri kind tag"
+msgstr " # pri tip etiqueta"
+
+# <l>
+msgid "file\n"
+msgstr "fitxer\n"
+
+msgid "E427: There is only one matching tag"
+msgstr "E427: Només hi ha una etiqueta coincident"
+
+msgid "E428: Cannot go beyond last matching tag"
+msgstr "E428: No es pot anar més enllà de l'última etiqueta coincident"
+
+#, c-format
+msgid "File \"%s\" does not exist"
+msgstr "El fitxer \"%s\" no existeix"
+
+#, c-format
+msgid "tag %d of %d%s"
+msgstr "etiqueta %d de %d%s"
+
+msgid " or more"
+msgstr " o més"
+
+msgid " Using tag with different case!"
+msgstr " No es fa distinció entre majúscules i minúscules!"
+
+#, c-format
+msgid "E429: File \"%s\" does not exist"
+msgstr "E429: El fitxer \"%s\" no existeix"
+
+# :tags
+# <c><l><l><r><l>
+msgid ""
+"\n"
+" # TO tag FROM line in file/text"
+msgstr "\n # A nom DES DE la línia al fitxer/text"
+
+#, c-format
+msgid "Searching tags file %s"
+msgstr "Cercant en el fitxer d'etiquetes %s"
+
+#, c-format
+msgid "E430: Tag file path truncated for %s\n"
+msgstr "E430: ubicació del fitxer d'etiquetes truncada per a %s\n"
+
+msgid "Ignoring long line in tags file"
+msgstr "S'ignora una línia llarga en el fitxer d'etiquetes"
+
+#, c-format
+msgid "E431: Format error in tags file \"%s\""
+msgstr "E431: Error de format en el fitxer d'etiquetes \"%s\""
+
+#, c-format
+msgid "Before byte %ld"
+msgstr "Abans de l'octet %ld"
+
+#, c-format
+msgid "E432: Tags file not sorted: %s"
+msgstr "E432: El fitxer d'etiquetes no està ordenat: %s"
+
+msgid "E433: No tags file"
+msgstr "E433: No hi ha cap fitxer d'etiquetes"
+
+msgid "E434: Can't find tag pattern"
+msgstr "E434: No s'ha trobat l'etiqueta"
+
+msgid "E435: Couldn't find tag, just guessing!"
+msgstr "E435: No s'ha trobat l'etiqueta exacta!"
+
+#, c-format
+msgid "Duplicate field name: %s"
+msgstr "Camp de nom duplicat: %s"
+
+# <terminal>
+msgid "' not known. Available builtin terminals are:"
+msgstr "' desconegut. Els terminals disponibles són:"
+
+msgid "defaulting to '"
+msgstr "se selecciona per omissió '"
+
+msgid "E557: Cannot open termcap file"
+msgstr "E557: No s'ha pogut obrir el fitxer termcap"
+
+msgid "E558: Terminal entry not found in terminfo"
+msgstr "E558: No s'ha trobat informació sobre el terminal a terminfo"
+
+msgid "E559: Terminal entry not found in termcap"
+msgstr "E559: No s'ha trobat informació sobre el terminal a termcap"
+
+#, c-format
+msgid "E436: No \"%s\" entry in termcap"
+msgstr "E436: No hi ha cap entrada \"%s\" al termcap"
+
+msgid "E437: terminal capability \"cm\" required"
+msgstr "E437: es necessita la capacitat \"cm\" per part del terminal"
+
+msgid ""
+"\n"
+"--- Terminal keys ---"
+msgstr ""
+"\n"
+"--- Tecles del terminal ---"
+
+msgid "Cannot open $VIMRUNTIME/rgb.txt"
+msgstr "No s'ha pogut obrir $VIMRUNTIME/rgb.txt"
+
+msgid "new shell started\n"
+msgstr "s'ha iniciat un nou intèrpret\n"
+
+msgid "Vim: Error reading input, exiting...\n"
+msgstr "Vim: Error en llegir l'entrada, sortint...\n"
+
+msgid "Used CUT_BUFFER0 instead of empty selection"
+msgstr "S'ha usat CUT_BUFFER0 en lloc d'una selecció buida"
+
+msgid "E881: Line count changed unexpectedly"
+msgstr "E881: El nombre de línies ha canviat inesperadament"
+
+msgid "No undo possible; continue anyway"
+msgstr "No es pot desfer res; voleu continuar"
+
+#, c-format
+msgid "E828: Cannot open undo file for writing: %s"
+msgstr "E828: No es pot obrir el fitxer de desfer per a escriptura: %s"
+
+#, c-format
+msgid "E825: Corrupted undo file (%s): %s"
+msgstr "E825: Fitxer de desfer corromput (%s): %s"
+
+msgid "Cannot write undo file in any directory in 'undodir'"
+msgstr "No s'ha pogut escriure el fitxer de desfer a cap dels directoris de 'undodir'"
+
+#, c-format
+msgid "Will not overwrite with undo file, cannot read: %s"
+msgstr "No se sobreescriurà el fitxer de desfer, error de lectura: %s"
+
+#, c-format
+msgid "Will not overwrite, this is not an undo file: %s"
+msgstr "No se sobreescriurà, no és un fitxer de desfer: %s"
+
+msgid "Skipping undo file write, nothing to undo"
+msgstr "No s'escriu el fitxer de desfer, no hi ha res per desfer"
+
+#, c-format
+msgid "Writing undo file: %s"
+msgstr "Desant el fitxer de desfer: %s"
+
+#, c-format
+msgid "E829: write error in undo file: %s"
+msgstr "E829: error d'escriptura en desar el fitxer de desfer: %s"
+
+#, c-format
+msgid "Not reading undo file, owner differs: %s"
+msgstr "No es llegeix el fitxer de desfer, el propietari és diferent: %s"
+
+#, c-format
+msgid "Reading undo file: %s"
+msgstr "Llegint el fitxer de desfer: %s"
+
+#, c-format
+msgid "E822: Cannot open undo file for reading: %s"
+msgstr "E822: Error en obrir el fitxer de desfer: %s"
+
+#, c-format
+msgid "E823: Not an undo file: %s"
+msgstr "E823: No és un fitxer de desfer: %s"
+
+#, c-format
+msgid "E832: Non-encrypted file has encrypted undo file: %s"
+msgstr "E832: Fitxer de desfer xifrat associat a un fitxer no xifrat: %s"
+
+#, c-format
+msgid "E826: Undo file decryption failed: %s"
+msgstr "E826: Error en desxifrar el fitxer de desfer: %s"
+
+#, c-format
+msgid "E827: Undo file is encrypted: %s"
+msgstr "E827: El fitxer de desfer està xifrat: %s"
+
+#, c-format
+msgid "E824: Incompatible undo file: %s"
+msgstr "E824: Fitxer de desfer incompatible: %s"
+
+msgid "File contents changed, cannot use undo info"
+msgstr "El contingut del fitxer ha canviat, no s'utilitza la informació de desfer."
+
+#, c-format
+msgid "Finished reading undo file %s"
+msgstr "S'ha completat la lectura del fitxer de desfer %s"
+
+msgid "Already at oldest change"
+msgstr "Ja us trobeu al canvi més antic"
+
+msgid "Already at newest change"
+msgstr "Ja us trobeu al canvi més recent"
+
+#, c-format
+msgid "E830: Undo number %ld not found"
+msgstr "E830: No s'ha trobat l'element de desfer número %ld"
+
+msgid "E438: u_undo: line numbers wrong"
+msgstr "E438: u_undo: els números de línia no són correctes"
+
+msgid "more line"
+msgstr "línia més"
+
+msgid "more lines"
+msgstr "línies més"
+
+# u
+msgid "line less"
+msgstr "línia menys"
+
+# u
+msgid "fewer lines"
+msgstr "línies menys"
+
+msgid "change"
+msgstr "canvi"
+
+msgid "changes"
+msgstr "canvis"
+
+#, c-format
+msgid "%ld %s; %s #%ld %s"
+msgstr "%ld %s; %s #%ld %s"
+
+# u
+msgid "before"
+msgstr "abans de"
+
+# u
+msgid "after"
+msgstr "després de"
+
+msgid "Nothing to undo"
+msgstr "No hi ha res per desfer"
+
+# :undolist
+# <r><r><l><l>
+msgid "number changes when saved"
+msgstr " núm canvis quan desat"
+
+# u
+#, c-format
+msgid "%ld seconds ago"
+msgstr "fa %ld segons"
+
+msgid "E790: undojoin is not allowed after undo"
+msgstr "E790: undojoin no està permès després de undo"
+
+msgid "E439: undo list corrupt"
+msgstr "E439: la llista de desfer està corrompuda"
+
+msgid "E440: undo line missing"
+msgstr "E440: falta una línia de desfer"
+
+#, c-format
+msgid "E122: Function %s already exists, add ! to replace it"
+msgstr "E122: La funció %s ja existeix, afegiu ! per a substituir-la"
+
+msgid "E717: Dictionary entry already exists"
+msgstr "E717: Ja existeix l'entrada al diccionari"
+
+msgid "E718: Funcref required"
+msgstr "E718: Es necessita Funcref"
+
+#, c-format
+msgid "E130: Unknown function: %s"
+msgstr "E130: Funció desconeguda: %s"
+
+#, c-format
+msgid "E125: Illegal argument: %s"
+msgstr "E125: Argument il·legal: %s"
+
+#, c-format
+msgid "E853: Duplicate argument name: %s"
+msgstr "E853: Argument duplicat: %s"
+
+#, c-format
+msgid "E740: Too many arguments for function %s"
+msgstr "E740: Sobren arguments a la funció %s"
+
+#, c-format
+msgid "E116: Invalid arguments for function %s"
+msgstr "E116: Arguments invàlids a la funció %s"
+
+msgid "E132: Function call depth is higher than 'maxfuncdepth'"
+msgstr "E132: El nombre de crides a funcions excedeix 'maxfuncdeptg'"
+
+#, c-format
+msgid "calling %s"
+msgstr "cridant %s"
+
+#, c-format
+msgid "%s aborted"
+msgstr "%s ha avortat"
+
+#, c-format
+msgid "%s returning #%ld"
+msgstr "%s ha retornat #%ld"
+
+#, c-format
+msgid "%s returning %s"
+msgstr "%s ha retornat \"%s\""
+
+msgid "E699: Too many arguments"
+msgstr "E699: Sobren arguments"
+
+#, c-format
+msgid "E117: Unknown function: %s"
+msgstr "E117: Funció desconeguda: %s"
+
+#, c-format
+msgid "E933: Function was deleted: %s"
+msgstr "E933: La funció s'ha eliminat: %s"
+
+#, c-format
+msgid "E119: Not enough arguments for function: %s"
+msgstr "E119: Falten arguments a la funció: %s"
+
+#, c-format
+msgid "E120: Using <SID> not in a script context: %s"
+msgstr "E120: Ús de <SID> en un context no vàlid: %s"
+
+#, c-format
+msgid "E725: Calling dict function without Dictionary: %s"
+msgstr "E725: Crida a una funció de diccionari sense diccionari: %s"
+
+msgid "E129: Function name required"
+msgstr "E129: Es necessita un nom de funció"
+
+#, c-format
+msgid "E128: Function name must start with a capital or \"s:\": %s"
+msgstr "E128: El nom de la funció ha de començar amb majúscula o \"s:\": %s"
+
+#, c-format
+msgid "E884: Function name cannot contain a colon: %s"
+msgstr "E884: El nom de la funció no pot contenir \":\": %s"
+
+#, c-format
+msgid "E123: Undefined function: %s"
+msgstr "E123: La funció no està definida: %s"
+
+#, c-format
+msgid "E124: Missing '(': %s"
+msgstr "E124: Falta un '(': %s"
+
+msgid "E862: Cannot use g: here"
+msgstr "E862: No és possible utilitzar g: en aquest context"
+
+#, c-format
+msgid "E932: Closure function should not be at top level: %s"
+msgstr "E932: Una funció amb clausura no pot estar al nivell superior: %s"
+
+msgid "E126: Missing :endfunction"
+msgstr "E126: Falta :endfunction"
+
+#, c-format
+msgid "W22: Text found after :endfunction: %s"
+msgstr "W22: Hi ha text després de :endfunction: %s"
+
+#, c-format
+msgid "E707: Function name conflicts with variable: %s"
+msgstr "E707: El nom de la funció entra en conflicte amb una variable: %s"
+
+#, c-format
+msgid "E127: Cannot redefine function %s: It is in use"
+msgstr "E127: No es pot redefinir la funció %s: es troba en ús"
+
+#, c-format
+msgid "E746: Function name does not match script file name: %s"
+msgstr "E746: El nom de la funció no coincideix amb el nom de l'script: %s"
+
+#, c-format
+msgid "E131: Cannot delete function %s: It is in use"
+msgstr "E131: No es pot eliminar la funció %s: es troba en ús"
+
+msgid "E133: :return not inside a function"
+msgstr "E133: :return fora d'una funció"
+
+#, c-format
+msgid "E107: Missing parentheses: %s"
+msgstr "E107: Falten parèntesis: %s"
+
+msgid ""
+"\n"
+"MS-Windows 64-bit GUI version"
+msgstr "\nVersió GUI per a MS-Windows de 64 bits"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit GUI version"
+msgstr "\nVersió GUI per a MS-Windows de 32 bits"
+
+msgid " with OLE support"
+msgstr " amb suport per a OLE"
+
+msgid ""
+"\n"
+"MS-Windows 64-bit console version"
+msgstr "\nVersió consola per a MS-Windows de 64 bits"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit console version"
+msgstr "\nVersió consola per a MS-Windows de 32 bits"
+
+msgid ""
+"\n"
+"MacOS X (unix) version"
+msgstr "\nVersió per a MacOS X (Unix)"
+
+msgid ""
+"\n"
+"MacOS X version"
+msgstr "\nVersió per a MacOS X"
+
+msgid ""
+"\n"
+"MacOS version"
+msgstr "\nVersió per a MacOS"
+
+msgid ""
+"\n"
+"OpenVMS version"
+msgstr "\nVersió per a OpenVMS"
+
+msgid ""
+"\n"
+"Included patches: "
+msgstr "\nCanvis inclosos: "
+
+msgid ""
+"\n"
+"Extra patches: "
+msgstr "\nCanvis addicionals: "
+
+msgid "Modified by "
+msgstr "Modificat per "
+
+msgid ""
+"\n"
+"Compiled "
+msgstr ""
+"\n"
+"Compilat "
+
+msgid "by "
+msgstr "per "
+
+msgid ""
+"\n"
+"Huge version "
+msgstr "\nVersió molt extensa "
+
+msgid ""
+"\n"
+"Big version "
+msgstr "\nVersió extensa "
+
+msgid ""
+"\n"
+"Normal version "
+msgstr ""
+"\n"
+"Versió normal "
+
+msgid ""
+"\n"
+"Small version "
+msgstr ""
+"\n"
+"Versió reduïda "
+
+msgid ""
+"\n"
+"Tiny version "
+msgstr "\nVersió minimalista "
+
+msgid "without GUI."
+msgstr "sense interfície gràfica."
+
+msgid "with GTK3 GUI."
+msgstr "amb interfície gràfica GTK3."
+
+msgid "with GTK2-GNOME GUI."
+msgstr "amb interfície gràfica GTK2-GNOME."
+
+msgid "with GTK2 GUI."
+msgstr "amb interfície gràfica GTK2."
+
+msgid "with X11-Motif GUI."
+msgstr "amb interfície gràfica X11-Motif."
+
+msgid "with X11-neXtaw GUI."
+msgstr "amb interfície gràfica X11-neXtaw."
+
+msgid "with X11-Athena GUI."
+msgstr "amb interfície gràfica X11-Athena."
+
+msgid "with Photon GUI."
+msgstr "amb interfície gràfica Photon."
+
+msgid "with GUI."
+msgstr "amb interfície gràfica."
+
+msgid "with Carbon GUI."
+msgstr "amb interfície gràfica Carbon."
+
+msgid "with Cocoa GUI."
+msgstr "amb interfície gràfica Cocoa."
+
+msgid "with (classic) GUI."
+msgstr "amb interfície gràfica (clàssica)."
+
+# vim --version
+msgid " Features included (+) or not (-):\n"
+msgstr "Característiques incloses (+) o excloses (-):\n"
+
+# 29 caràcters fins el ":" (inclòs)
+msgid " system vimrc file: \""
+msgstr " fitxer vimrc del sistema: \""
+
+# 29 caràcters fins el ":" (inclòs)
+msgid " user vimrc file: \""
+msgstr " fitxer vimrc de l'usuari: \""
+
+# 29 caràcters fins el ":" (inclòs)
+msgid " 2nd user vimrc file: \""
+msgstr " 2n fitxer vimrc de l'usuari: \""
+
+# 29 caràcters fins el ":" (inclòs)
+msgid " 3rd user vimrc file: \""
+msgstr " 3r fitxer vimrc de l'usuari: \""
+
+# 29 caràcters fins el ":" (inclòs)
+msgid " user exrc file: \""
+msgstr " fitxer exrc de l'usuari: \""
+
+# 29 caràcters fins el ":" (inclòs)
+msgid " 2nd user exrc file: \""
+msgstr " 2n fitxer exrc de l'usuari: \""
+
+# 29 caràcters fins el ":" (inclòs)
+msgid " system gvimrc file: \""
+msgstr " fitxer gvimrc del sistema: \""
+
+# 29 caràcters fins el ":" (inclòs)
+msgid " user gvimrc file: \""
+msgstr " fitxer gvimrc de l'usuari: \""
+
+# 29 caràcters fins el ":" (inclòs)
+msgid "2nd user gvimrc file: \""
+msgstr "2n fitxer gvimrc de l'usuari: \""
+
+# 29 caràcters fins el ":" (inclòs)
+msgid "3rd user gvimrc file: \""
+msgstr "3r fitxer gvimrc de l'usuari: \""
+
+# 29 caràcters fins el ":" (inclòs)
+msgid " defaults file: \""
+msgstr "fitxer de valors per defecte: \""
+
+# 29 caràcters fins el ":" (inclòs)
+msgid " system menu file: \""
+msgstr " fitxer de menú del sistema: \""
+
+# 29 caràcters fins el ":" (inclòs)
+msgid " fall-back for $VIM: \""
+msgstr " alternativa per a $VIM: \""
+
+# 29 caràcters fins el ":" (inclòs)
+msgid " f-b for $VIMRUNTIME: \""
+msgstr " altern. per a $VIMRUNTIME: \""
+
+msgid "Compilation: "
+msgstr "Compilat amb: "
+
+msgid "Compiler: "
+msgstr "Compilador: "
+
+msgid "Linking: "
+msgstr "Enllaçat amb: "
+
+msgid " DEBUG BUILD"
+msgstr " VERSIÓ DE DEPURACIÓ"
+
+msgid "VIM - Vi IMproved"
+msgstr "VIM - Vi IMproved"
+
+msgid "version "
+msgstr "versió "
+
+msgid "by Bram Moolenaar et al."
+msgstr "per Bram Moolenaar et al."
+
+msgid "Vim is open source and freely distributable"
+msgstr "Vim és un programa obert i de lliure distribució"
+
+msgid "Help poor children in Uganda!"
+msgstr "Ajudeu els nens pobres d'Uganda!"
+
+# amplada 53 caràcters
+msgid "type :help iccf<Enter> for information "
+msgstr "feu :help iccf<Entrar> per a més informació "
+
+# amplada 53 caràcters
+msgid "type :q<Enter> to exit "
+msgstr "feu :q<Entrar> per a sortir "
+
+# amplada 53 caràcters
+msgid "type :help<Enter> or <F1> for on-line help"
+msgstr "feu :help<Entrar> o <F1> per a obtenir ajuda "
+
+# amplada 53 caràcters
+msgid "type :help version8<Enter> for version info"
+msgstr "feu :help version8<Entrar> per a info de la versió "
+
+msgid "Running in Vi compatible mode"
+msgstr "Funcionant en mode compatible amb Vi"
+
+# amplada 53 caràcters
+msgid "type :set nocp<Enter> for Vim defaults"
+msgstr "feu :set nocp<Entrar> per al mode no compatible"
+
+# amplada 53 caràcters
+msgid "type :help cp-default<Enter> for info on this"
+msgstr "feu :help cp-default<Entrar> per a info sobre el tema "
+
+# amplada 53 caràcters
+msgid "menu Help->Orphans for information "
+msgstr "menú Ajuda->Orfes per a informació "
+
+msgid "Running modeless, typed text is inserted"
+msgstr "Funcionant sense modes, el text escrit s'insereix"
+
+# Això ha de lligar amb la traducció del menú
+# amplada 53 caràcters
+msgid "menu Edit->Global Settings->Toggle Insert Mode "
+msgstr "menú Edita->Opcions globals->Mode d'inserció "
+
+# amplada 53 caràcters
+msgid " for two modes "
+msgstr " per a dos modes "
+
+# Això ha de lligar amb la traducció del menú
+# amplada 53 caràcters
+msgid "menu Edit->Global Settings->Toggle Vi Compatible"
+msgstr "menú Edita->Opcions globals->Compatible amb Vi "
+
+# amplada 53 caràcters
+msgid " for Vim defaults "
+msgstr " per al mode compatible"
+
+msgid "Sponsor Vim development!"
+msgstr "Patrocineu el desenvolupament del Vim!"
+
+msgid "Become a registered Vim user!"
+msgstr "Feu-vos usuari de Vim registrat!"
+
+# amplada 53 caràcters
+msgid "type :help sponsor<Enter> for information "
+msgstr "feu :help sponsor<Entrar> per a informació "
+
+# amplada 53 caràcters
+msgid "type :help register<Enter> for information "
+msgstr "feu :help register<Entrar> per a informació "
+
+# amplada 53 caràcters
+msgid "menu Help->Sponsor/Register for information "
+msgstr "menú Ajuda->Patrocini/Registre per a informació "
+
+msgid "Already only one window"
+msgstr "Només hi ha una finestra"
+
+msgid "E441: There is no preview window"
+msgstr "E441: No hi ha cap finestra de previsualització"
+
+msgid "E442: Can't split topleft and botright at the same time"
+msgstr "E442: No es pot dividir horitzontal i verticalment alhora"
+
+msgid "E443: Cannot rotate when another window is split"
+msgstr "E443: No es pot rotar quan hi ha finestres dividides"
+
+msgid "E444: Cannot close last window"
+msgstr "E444: No es pot tancar l'última finestra"
+
+msgid "E813: Cannot close autocmd window"
+msgstr "E813: No es pot tancar la finestra autocmd"
+
+msgid "E814: Cannot close window, only autocmd window would remain"
+msgstr "E814: No es pot tancar la finestra, només romandria la finestra autocmd"
+
+msgid "E445: Other window contains changes"
+msgstr "E445: Hi han altres finestres que contenen canvis"
+
+msgid "E446: No file name under cursor"
+msgstr "E446: No hi ha cap nom de fitxer sota el cursor"
+
+#, c-format
+msgid "E447: Can't find file \"%s\" in path"
+msgstr "E447: No s'ha trobat el fitxer \"%s\" a path"
+
+#, c-format
+msgid "E799: Invalid ID: %ld (must be greater than or equal to 1)"
+msgstr "E799: ID invàlid: %ld (ha de ser més gran o igual que 1)"
+
+#, c-format
+msgid "E801: ID already taken: %ld"
+msgstr "E801: L'ID ja està agafat: %ld"
+
+msgid "List or number required"
+msgstr "Es necessita una llista o un número"
+
+#, c-format
+msgid "E802: Invalid ID: %ld (must be greater than or equal to 1)"
+msgstr "E802: ID invàlid: %ld (ha de ser més gran o igual que 1)"
+
+#, c-format
+msgid "E803: ID not found: %ld"
+msgstr "E803: ID no trobat: %ld"
+
+#, c-format
+msgid "E370: Could not load library %s"
+msgstr "E370: No s'ha pogut carregar la biblioteca %s"
+
+msgid "Sorry, this command is disabled: the Perl library could not be loaded."
+msgstr "Ordre no disponible: no s'ha pogut carregar la biblioteca Perl."
+
+msgid "E299: Perl evaluation forbidden in sandbox without the Safe module"
+msgstr "E299: No està permès executar Perl en un entorn aïllat sense el mòdul Safe"
+
+msgid "Edit with &multiple Vims"
+msgstr "Edita en &múltiples Vims"
+
+msgid "Edit with single &Vim"
+msgstr "Edita en un sol &Vim"
+
+msgid "Diff with Vim"
+msgstr "Mostra les diferències amb Vim"
+
+msgid "Edit with &Vim"
+msgstr "Edita amb el &Vim"
+
+msgid "Edit with existing Vim - "
+msgstr "Edita amb un Vim existent - "
+
+msgid "Edits the selected file(s) with Vim"
+msgstr "Edita el(s) fitxer(s) seleccionat(s) amb el Vim"
+
+msgid "Error creating process: Check if gvim is in your path!"
+msgstr "Error en crear el procés: Comproveu que gvim es troba al path!"
+
+msgid "gvimext.dll error"
+msgstr "error de la biblioteca gvimext.dll"
+
+msgid "Path length too long!"
+msgstr "La llargada del path és excessiva"
+
+msgid "--No lines in buffer--"
+msgstr "--Cap línia en el buffer--"
+
+msgid "E470: Command aborted"
+msgstr "E470: S'ha avortat l'ordre"
+
+msgid "E471: Argument required"
+msgstr "E471: Es requereix un argument"
+
+msgid "E10: \\ should be followed by /, ? or &"
+msgstr "E10: \\ hauria de continuar amb /, ? o &"
+
+msgid "E11: Invalid in command-line window; <CR> executes, CTRL-C quits"
+msgstr "E11: No vàlid a la línia d'ordres; <ENTRAR> executa, CTRL-C surt"
+
+msgid "E12: Command not allowed from exrc/vimrc in current dir or tag search"
+msgstr "E12: Ordre no permesa a exrc/vimrc al directori actual o en cerca d'etiquetes"
+
+msgid "E171: Missing :endif"
+msgstr "E171: Falta :endif"
+
+msgid "E600: Missing :endtry"
+msgstr "E600: Falta :endtry"
+
+msgid "E170: Missing :endwhile"
+msgstr "E170: Falta :endwhile"
+
+msgid "E170: Missing :endfor"
+msgstr "E170: Falta :endfor"
+
+msgid "E588: :endwhile without :while"
+msgstr "E588: :endwhile sense :while"
+
+msgid "E588: :endfor without :for"
+msgstr "E588: :endfor sense :for"
+
+msgid "E13: File exists (add ! to override)"
+msgstr "E13: El fitxer existeix (afegiu ! per a forçar)"
+
+msgid "E472: Command failed"
+msgstr "E472: L'ordre ha fallat"
+
+#, c-format
+msgid "E234: Unknown fontset: %s"
+msgstr "E234: Conjunt de foses desconegut: %s"
+
+#, c-format
+msgid "E235: Unknown font: %s"
+msgstr "E235: Fosa desconeguda: %s"
+
+#, c-format
+msgid "E236: Font \"%s\" is not fixed-width"
+msgstr "E236: La fosa \"%s\" no és d'amplada fixa"
+
+msgid "E473: Internal error"
+msgstr "E473: Error intern"
+
+#, c-format
+msgid "E685: Internal error: %s"
+msgstr "E685: Error intern: %s"
+
+msgid "Interrupted"
+msgstr "Interromput"
+
+msgid "E14: Invalid address"
+msgstr "E14: Adreça no vàlida"
+
+msgid "E474: Invalid argument"
+msgstr "E474: Argument no vàlid"
+
+#, c-format
+msgid "E475: Invalid argument: %s"
+msgstr "E475: Argument no vàlid: %s"
+
+#, c-format
+msgid "E15: Invalid expression: %s"
+msgstr "E15: Expressió no vàlida: %s"
+
+msgid "E16: Invalid range"
+msgstr "E16: Interval no vàlid"
+
+msgid "E476: Invalid command"
+msgstr "E476: Ordre no vàlida"
+
+#, c-format
+msgid "E17: \"%s\" is a directory"
+msgstr "E17: \"%s\" és un directori"
+
+#, c-format
+msgid "E364: Library call failed for \"%s()\""
+msgstr "E364: La crida a la biblioteca a fallat per a \"%s()\""
+
+#, c-format
+msgid "E448: Could not load library function %s"
+msgstr "E448: No s'ha pogut carregar la funció %s"
+
+msgid "E19: Mark has invalid line number"
+msgstr "E19: Marca amb número de línia no vàlid"
+
+msgid "E20: Mark not set"
+msgstr "E20: Marca no establerta"
+
+msgid "E21: Cannot make changes, 'modifiable' is off"
+msgstr "E21: No es poden fer canvis, el paràmetre 'modifiable' està desactivat"
+
+msgid "E22: Scripts nested too deep"
+msgstr "E22: Nivell d'imbricació de scripts massa elevat"
+
+msgid "E23: No alternate file"
+msgstr "E23: No hi ha cap fitxer alternatiu"
+
+msgid "E24: No such abbreviation"
+msgstr "E24: No existeix tal abreviació"
+
+msgid "E477: No ! allowed"
+msgstr "E477: ! no permès"
+
+msgid "E25: GUI cannot be used: Not enabled at compile time"
+msgstr "E25: No es pot usar GUI: No ha estat compilat"
+
+msgid "E26: Hebrew cannot be used: Not enabled at compile time\n"
+msgstr "E26: No es pot usar hebreu: No ha estat compilat\n"
+
+msgid "E27: Farsi cannot be used: Not enabled at compile time\n"
+msgstr "E27: No es pot usar farsi: No ha estat compilat\n"
+
+msgid "E800: Arabic cannot be used: Not enabled at compile time\n"
+msgstr "E800: No es pot usar àrab: No ha estat compilat\n"
+
+#, c-format
+msgid "E28: No such highlight group name: %s"
+msgstr "E28: No existeix tal grup de ressaltat: %s"
+
+msgid "E29: No inserted text yet"
+msgstr "E29: Encara no s'ha inserit text"
+
+msgid "E30: No previous command line"
+msgstr "E30: No hi ha cap ordre anterior"
+
+msgid "E31: No such mapping"
+msgstr "E31: No existeix tal assignació"
+
+msgid "E479: No match"
+msgstr "E479: Cap coincidència"
+
+#, c-format
+msgid "E480: No match: %s"
+msgstr "E480: Cap coincidència: %s"
+
+msgid "E32: No file name"
+msgstr "E32: Falta un nom de fitxer"
+
+msgid "E33: No previous substitute regular expression"
+msgstr "E33: No hi ha cap expressió de substitució anterior"
+
+msgid "E34: No previous command"
+msgstr "E34: No hi ha cap ordre anterior"
+
+msgid "E35: No previous regular expression"
+msgstr "E35: No hi ha cap expressió regular anterior"
+
+msgid "E481: No range allowed"
+msgstr "E481: No es permeten intervals"
+
+msgid "E36: Not enough room"
+msgstr "E36: No hi ha prou espai"
+
+#, c-format
+msgid "E247: no registered server named \"%s\""
+msgstr "E247: cap servidor registrat amb aquest nom \"%s\""
+
+#, c-format
+msgid "E482: Can't create file %s"
+msgstr "E482: No es pot crear el fitxer %s"
+
+msgid "E483: Can't get temp file name"
+msgstr "E483: No s'ha pogut obtenir el nom del fitxer temporal"
+
+#, c-format
+msgid "E484: Can't open file %s"
+msgstr "E484: No es pot obrir el fitxer %s"
+
+#, c-format
+msgid "E485: Can't read file %s"
+msgstr "E485: No es pot llegir el fitxer %s"
+
+msgid "E37: No write since last change (add ! to override)"
+msgstr "E37: No s'han desat els canvis (afegiu ! per a forçar)"
+
+msgid "E37: No write since last change"
+msgstr "E37: No s'han desat els canvis"
+
+msgid "E38: Null argument"
+msgstr "E38: Argument nul"
+
+msgid "E39: Number expected"
+msgstr "E39: S'esperava un número"
+
+#, c-format
+msgid "E40: Can't open errorfile %s"
+msgstr "E40: No s'ha pogut obrir el fitxer d'errors %s"
+
+msgid "E233: cannot open display"
+msgstr "E233: No s'ha pogut obrir la pantalla"
+
+msgid "E41: Out of memory!"
+msgstr "E41: Memòria exhaurida!"
+
+msgid "Pattern not found"
+msgstr "No s'ha trobat el patró"
+
+#, c-format
+msgid "E486: Pattern not found: %s"
+msgstr "E486: No s'ha trobat el patró: %s"
+
+msgid "E487: Argument must be positive"
+msgstr "E487: L'argument ha de ser un número positiu"
+
+msgid "E459: Cannot go back to previous directory"
+msgstr "E459: No es pot tornar al directori anterior"
+
+msgid "E42: No Errors"
+msgstr "E42: No hi ha errors"
+
+msgid "E776: No location list"
+msgstr "E776: No hi ha cap llista de posicions"
+
+msgid "E43: Damaged match string"
+msgstr "E43: Cadena de coincidència corrompuda"
+
+msgid "E44: Corrupted regexp program"
+msgstr "E44: Programa d'expressió regular corromput"
+
+msgid "E45: 'readonly' option is set (add ! to override)"
+msgstr "E45: 'readonly' està establert (afegiu ! per a forçar)"
+
+#, c-format
+msgid "E46: Cannot change read-only variable \"%s\""
+msgstr "E46: No es pot canviar la variable de només lectura \"%s\""
+
+#, c-format
+msgid "E794: Cannot set variable in the sandbox: \"%s\""
+msgstr "E794: No es pot definir la variable dins de l'entorn d'aïllament: \"%s\""
+
+msgid "E713: Cannot use empty key for Dictionary"
+msgstr "E713: No és possible utilitzar una clau buida en un diccionari"
+
+msgid "E715: Dictionary required"
+msgstr "E715: Es necessita Dictionary"
+
+#, c-format
+msgid "E684: list index out of range: %ld"
+msgstr "E684: índex de llista fora de l'interval: %ld"
+
+#, c-format
+msgid "E118: Too many arguments for function: %s"
+msgstr "E118: Sobren arguments a la funció: %s"
+
+#, c-format
+msgid "E716: Key not present in Dictionary: %s"
+msgstr "E716: La clau no existeix al diccionari: %s"
+
+msgid "E714: List required"
+msgstr "E714: Es necessita una llista"
+
+#, c-format
+msgid "E712: Argument of %s must be a List or Dictionary"
+msgstr "E712: L'argument de %s ha de ser List o Dictionary"
+
+msgid "E47: Error while reading errorfile"
+msgstr "E47: Error en llegir el fitxer d'errors"
+
+msgid "E48: Not allowed in sandbox"
+msgstr "E48: No està permès dins d'un entorn d'aïllament"
+
+msgid "E523: Not allowed here"
+msgstr "E523: No permès en aquest context"
+
+msgid "E359: Screen mode setting not supported"
+msgstr "E359: L'ajustament del mode de pantalla no està suportat"
+
+msgid "E49: Invalid scroll size"
+msgstr "E49: Distància de desplaçament no vàlida"
+
+msgid "E91: 'shell' option is empty"
+msgstr "E91: El paràmetre 'shell' està en blanc"
+
+msgid "E255: Couldn't read in sign data!"
+msgstr "E255: Error en obtenir les dades de senyals!"
+
+msgid "E72: Close error on swap file"
+msgstr "E72: Error en tancar el fitxer d'intercanvi"
+
+msgid "E73: tag stack empty"
+msgstr "E73: La pila d'etiquetes està buida"
+
+msgid "E74: Command too complex"
+msgstr "E74: L'ordre és massa complexa"
+
+msgid "E75: Name too long"
+msgstr "E75: El nom és massa llarg"
+
+msgid "E76: Too many ["
+msgstr "E76: Sobren ["
+
+msgid "E77: Too many file names"
+msgstr "E77: Sobren noms de fitxer"
+
+msgid "E488: Trailing characters"
+msgstr "E488: Sobren caràcters al final"
+
+msgid "E78: Unknown mark"
+msgstr "E78: Marca desconeguda"
+
+msgid "E79: Cannot expand wildcards"
+msgstr "E79: No s'ha pogut expandir el nom de fitxer"
+
+msgid "E591: 'winheight' cannot be smaller than 'winminheight'"
+msgstr "E591: El valor de 'winheight' no pot ser menor que 'winminheight'"
+
+msgid "E592: 'winwidth' cannot be smaller than 'winminwidth'"
+msgstr "E592: El valor de 'winwidth' no pot ser menor que 'winminwidth'"
+
+msgid "E80: Error while writing"
+msgstr "E80: Error d'escriptura"
+
+msgid "E939: Positive count required"
+msgstr "E939: Es necessita un número estrictament positiu"
+
+msgid "E81: Using <SID> not in a script context"
+msgstr "E81: Ús de <SID> en un context equivocat"
+
+msgid "E449: Invalid expression received"
+msgstr "E449: S'ha rebut una expressió no vàlida"
+
+msgid "E463: Region is guarded, cannot modify"
+msgstr "E463: La regió està protegida, no es pot modificar"
+
+msgid "E744: NetBeans does not allow changes in read-only files"
+msgstr "E744: NetBeans no permet canvis a fitxers de només lectura"
+
+msgid "E363: pattern uses more memory than 'maxmempattern'"
+msgstr "E363: el patró requereix més memòria que 'maxmempattern'"
+
+msgid "E749: empty buffer"
+msgstr "E749: buffer buit"
+
+#, c-format
+msgid "E86: Buffer %ld does not exist"
+msgstr "E86: El buffer %ld no existeix"
+
+msgid "E682: Invalid search pattern or delimiter"
+msgstr "E682: Patró de cerca o delimitador no vàlid"
+
+msgid "E139: File is loaded in another buffer"
+msgstr "E139: El fitxer està carregat en un altre buffer"
+
+#, c-format
+msgid "E764: Option '%s' is not set"
+msgstr "E764: El paràmetre '%s' no està establert"
+
+msgid "E850: Invalid register name"
+msgstr "E850: Nom de registre no vàlid"
+
+#, c-format
+msgid "E919: Directory not found in '%s': \"%s\""
+msgstr "E919: Directori no trobat a '%s': \"%s\""
+
+msgid "search hit TOP, continuing at BOTTOM"
+msgstr "la cerca ha arribat a DALT, es continua a BAIX"
+
+msgid "search hit BOTTOM, continuing at TOP"
+msgstr "la cerca ha arribat a BAIX, es continua a DALT"
+
+#, c-format
+msgid "Need encryption key for \"%s\""
+msgstr "Es necessita la clau de xifrat per a \"%s\""
+
+msgid "empty keys are not allowed"
+msgstr "no s'admeten claus en blanc"
+
+msgid "dictionary is locked"
+msgstr "el diccionari està bloquejat"
+
+msgid "list is locked"
+msgstr "la llista està bloquejada"
+
+#, c-format
+msgid "failed to add key '%s' to dictionary"
+msgstr "error en afegir la clau '%s' al diccionari"
+
+#, c-format
+msgid "index must be int or slice, not %s"
+msgstr "l'índex ha de ser un enter o un interval, no %s"
+
+#, c-format
+msgid "expected str() or unicode() instance, but got %s"
+msgstr "s'esperava una objecte str() o unicode(), s'ha rebut %s"
+
+#, c-format
+msgid "expected bytes() or str() instance, but got %s"
+msgstr "s'esperava un objecte bytes() o str(), s'ha rebut %s"
+
+#, c-format
+msgid ""
+"expected int(), long() or something supporting coercing to long(), but got %s"
+msgstr "s'esperava int(), long() o un objecte convertible a long(), s'ha rebut %s"
+
+#, c-format
+msgid "expected int() or something supporting coercing to int(), but got %s"
+msgstr "s'esperava int() o un objecte convertible a int(), s'ha rebut %s"
+
+msgid "value is too large to fit into C int type"
+msgstr "el valor és massa gran per al tipus int de C"
+
+msgid "value is too small to fit into C int type"
+msgstr "el valor és massa petit per al tipus int de C"
+
+msgid "number must be greater than zero"
+msgstr "el número ha de ser més gran que zero"
+
+msgid "number must be greater or equal to zero"
+msgstr "el número ha de ser més gran o igual que zero"
+
+msgid "can't delete OutputObject attributes"
+msgstr "no s'han pogut eliminar els atributs de OutputObject"
+
+#, c-format
+msgid "invalid attribute: %s"
+msgstr "atribut invàlid: %s"
+
+msgid "E264: Python: Error initialising I/O objects"
+msgstr "E264: Python: Error en inicialitzar els objectes d'E/S"
+
+msgid "failed to change directory"
+msgstr "error en canviar de directori"
+
+#, c-format
+msgid "expected 3-tuple as imp.find_module() result, but got %s"
+msgstr "s'esperava una 3-tupla, però imp.find_module() ha retornat %s"
+
+#, c-format
+msgid "expected 3-tuple as imp.find_module() result, but got tuple of size %d"
+msgstr "s'esperava una 3-tupla, però imp.find_module() retornat una %d-tupla"
+
+msgid "internal error: imp.find_module returned tuple with NULL"
+msgstr "error intern: imp.find_module ha retornat una tupla amb valors NULL"
+
+msgid "cannot delete vim.Dictionary attributes"
+msgstr "no s'han pogut eliminar els atributs de vim.Dictionary"
+
+msgid "cannot modify fixed dictionary"
+msgstr "no és possible modificar un diccionari fixat"
+
+#, c-format
+msgid "cannot set attribute %s"
+msgstr "no s'ha pogut establir l'atribut %s"
+
+msgid "hashtab changed during iteration"
+msgstr "hashtab ha canviat durant la iteració"
+
+#, c-format
+msgid "expected sequence element of size 2, but got sequence of size %d"
+msgstr "s'esperava una seqüència de mida 2, s'ha rebut una seqüència de mida %d"
+
+msgid "list constructor does not accept keyword arguments"
+msgstr "el constructor de llistes no accepta arguments amb nom"
+
+msgid "list index out of range"
+msgstr "índex de llista fora de l'interval"
+
+#, c-format
+msgid "internal error: failed to get vim list item %d"
+msgstr "error intern: error en obtenir l'element %d de la llista vim"
+
+msgid "slice step cannot be zero"
+msgstr "l'increment de l'interval no pot ser zero"
+
+#, c-format
+msgid "attempt to assign sequence of size greater than %d to extended slice"
+msgstr "intent d'assignar una seqüència de més de %d elements a un interval estès"
+
+#, c-format
+msgid "internal error: no vim list item %d"
+msgstr "error intern: no existeix l'element %d a la llista vim"
+
+msgid "internal error: not enough list items"
+msgstr "error intern: no hi ha prou elements a la llista"
+
+msgid "internal error: failed to add item to list"
+msgstr "error intern: error en afegir un element a la llista"
+
+#, c-format
+msgid "attempt to assign sequence of size %d to extended slice of size %d"
+msgstr "intent d'assignar una seqüència de %d elements a un interval estès de %d"
+
+msgid "failed to add item to list"
+msgstr "error en afegir un element a la llista"
+
+msgid "cannot delete vim.List attributes"
+msgstr "no s'han pogut eliminar els atributs de vim.List"
+
+msgid "cannot modify fixed list"
+msgstr "no es pot modificar una llista fixada"
+
+#, c-format
+msgid "unnamed function %s does not exist"
+msgstr "la funció sense nom %s no existeix"
+
+#, c-format
+msgid "function %s does not exist"
+msgstr "la funció %s no existeix"
+
+#, c-format
+msgid "failed to run function %s"
+msgstr "error en executar la funció %s"
+
+msgid "unable to get option value"
+msgstr "error en obtenir el valor de l'opció"
+
+msgid "internal error: unknown option type"
+msgstr "error intern: tipus d'opció desconegut"
+
+msgid "problem while switching windows"
+msgstr "problema en canviar de finestra"
+
+#, c-format
+msgid "unable to unset global option %s"
+msgstr "error en eliminar el valor de l'opció global %s"
+
+#, c-format
+msgid "unable to unset option %s which does not have global value"
+msgstr "error en eliminar el valor de l'opció %s que no té valor global"
+
+msgid "attempt to refer to deleted tab page"
+msgstr "referència a una pestanya eliminada"
+
+msgid "no such tab page"
+msgstr "no existeix tal pestanya"
+
+msgid "attempt to refer to deleted window"
+msgstr "referència a una finestra eliminada"
+
+msgid "readonly attribute: buffer"
+msgstr "atribut readonly: buffer"
+
+msgid "cursor position outside buffer"
+msgstr "posició del cursor fora del buffer"
+
+msgid "no such window"
+msgstr "no existeix tal finestra"
+
+msgid "attempt to refer to deleted buffer"
+msgstr "referència a un buffer eliminat"
+
+msgid "failed to rename buffer"
+msgstr "error en reanomenar el buffer"
+
+msgid "mark name must be a single character"
+msgstr "els noms de marques han ser un únic caràcter"
+
+#, c-format
+msgid "expected vim.Buffer object, but got %s"
+msgstr "s'esperava un objecte vim.Buffer object, s'ha rebut %s"
+
+#, c-format
+msgid "failed to switch to buffer %d"
+msgstr "error en canviar al buffer %d"
+
+#, c-format
+msgid "expected vim.Window object, but got %s"
+msgstr "s'esperava un objecte vim.Window, s'ha rebut %s"
+
+msgid "failed to find window in the current tab page"
+msgstr "no s'ha trobat la finestra a la pestanya actual"
+
+msgid "did not switch to the specified window"
+msgstr "no s'ha canviat a la finestra especificada"
+
+#, c-format
+msgid "expected vim.TabPage object, but got %s"
+msgstr "s'esperava un objecte vim.TabPage, s'ha rebut %s"
+
+msgid "did not switch to the specified tab page"
+msgstr "no s'ha canviat a la pestanya especificada"
+
+msgid "failed to run the code"
+msgstr "error en executar el codi"
+
+msgid "E858: Eval did not return a valid python object"
+msgstr "E858: Eval no ha retornat un objecte Python vàlid"
+
+msgid "E859: Failed to convert returned python object to vim value"
+msgstr "E859: Error en convertir l'objecte Python retornat a un valor Vim"
+
+#, c-format
+msgid "unable to convert %s to vim dictionary"
+msgstr "error en convertir %s en un diccionari Vim"
+
+#, c-format
+msgid "unable to convert %s to vim list"
+msgstr "error en convertir %s en una llista Vim"
+
+#, c-format
+msgid "unable to convert %s to vim structure"
+msgstr "error en convertir %s en una estructura Vim"
+
+msgid "internal error: NULL reference passed"
+msgstr "error intern: s'ha passat una referència amb valor NULL"
+
+msgid "internal error: invalid value type"
+msgstr "error intern: tipus de valor invàlid"
+
+# todo: path hook
+msgid ""
+"Failed to set path hook: sys.path_hooks is not a list\n"
+"You should now do the following:\n"
+"- append vim.path_hook to sys.path_hooks\n"
+"- append vim.VIM_SPECIAL_PATH to sys.path\n"
+msgstr ""
+"Error en establir les rutines de path: sys.path_hooks no és una llista\n"
+"Hauríeu de fer el següent:\n"
+"- afegir vim.path_hook a sys.path_hooks\n"
+"- afegir vim.VIM_SPECIAL_PATH a sys.path\n"
+
+msgid ""
+"Failed to set path: sys.path is not a list\n"
+"You should now append vim.VIM_SPECIAL_PATH to sys.path"
+msgstr ""
+"Error en establir el path: sys.path no és una llista\n"
+"Hauríeu d'afegir vim.VIM_SPECIAL_PATH a sys.path"
diff --git a/src/po/check.vim b/src/po/check.vim
new file mode 100644
index 0000000..672b4f3
--- /dev/null
+++ b/src/po/check.vim
@@ -0,0 +1,213 @@
+" Vim script for checking .po files.
+"
+" Go through the file and verify that:
+" - All %...s items in "msgid" are identical to the ones in "msgstr".
+" - An error or warning code in "msgid" matches the one in "msgstr".
+
+if 1 " Only execute this if the eval feature is available.
+
+" Function to get a split line at the cursor.
+" Used for both msgid and msgstr lines.
+" Removes all text except % items and returns the result.
+func! GetMline()
+ let idline = substitute(getline('.'), '"\(.*\)"$', '\1', '')
+ while line('.') < line('$')
+ +
+ let line = getline('.')
+ if line[0] != '"'
+ break
+ endif
+ let idline .= substitute(line, '"\(.*\)"$', '\1', '')
+ endwhile
+
+ " remove '%', not used for formatting.
+ let idline = substitute(idline, "'%'", '', 'g')
+
+ " remove '%' used for plural forms.
+ let idline = substitute(idline, '\\nPlural-Forms: .\+;\\n', '', '')
+
+ " remove everything but % items.
+ return substitute(idline, '[^%]*\(%[-+ #''.0-9*]*l\=[dsuxXpoc%]\)\=', '\1', 'g')
+endfunc
+
+" This only works when 'wrapscan' is not set.
+let s:save_wrapscan = &wrapscan
+set nowrapscan
+
+" Start at the first "msgid" line.
+let wsv = winsaveview()
+1
+/^msgid\>
+
+" When an error is detected this is set to the line number.
+" Note: this is used in the Makefile.
+let error = 0
+
+while 1
+ if getline(line('.') - 1) !~ "no-c-format"
+ " go over the "msgid" and "msgid_plural" lines
+ let prevfromline = 'foobar'
+ while 1
+ let fromline = GetMline()
+ if prevfromline != 'foobar' && prevfromline != fromline
+ echomsg 'Mismatching % in line ' . (line('.') - 1)
+ echomsg 'msgid: ' . prevfromline
+ echomsg 'msgid ' . fromline
+ if error == 0
+ let error = line('.')
+ endif
+ endif
+ if getline('.') !~ 'msgid_plural'
+ break
+ endif
+ let prevfromline = fromline
+ endwhile
+
+ if getline('.') !~ '^msgstr'
+ echomsg 'Missing "msgstr" in line ' . line('.')
+ if error == 0
+ let error = line('.')
+ endif
+ endif
+
+ " check all the 'msgstr' lines
+ while getline('.') =~ '^msgstr'
+ let toline = GetMline()
+ if fromline != toline
+ echomsg 'Mismatching % in line ' . (line('.') - 1)
+ echomsg 'msgid: ' . fromline
+ echomsg 'msgstr: ' . toline
+ if error == 0
+ let error = line('.')
+ endif
+ endif
+ if line('.') == line('$')
+ break
+ endif
+ endwhile
+ endif
+
+ " Find next msgid. Quit when there is no more.
+ let lnum = line('.')
+ silent! /^msgid\>
+ if line('.') == lnum
+ break
+ endif
+endwhile
+
+" Check that error code in msgid matches the one in msgstr.
+"
+" Examples of mismatches found with msgid "E123: ..."
+" - msgstr "E321: ..." error code mismatch
+" - msgstr "W123: ..." warning instead of error
+" - msgstr "E123 ..." missing colon
+" - msgstr "..." missing error code
+"
+1
+if search('msgid "\("\n"\)\?\([EW][0-9]\+:\).*\nmsgstr "\("\n"\)\?[^"]\@=\2\@!') > 0
+ echomsg 'Mismatching error/warning code in line ' . line('.')
+ if error == 0
+ let error = line('.')
+ endif
+endif
+
+func! CountNl(first, last)
+ let nl = 0
+ for lnum in range(a:first, a:last)
+ let nl += count(getline(lnum), "\n")
+ endfor
+ return nl
+endfunc
+
+" Check that the \n at the end of the msgid line is also present in the msgstr
+" line. Skip over the header.
+1
+/^"MIME-Version:
+while 1
+ let lnum = search('^msgid\>')
+ if lnum <= 0
+ break
+ endif
+ let strlnum = search('^msgstr\>')
+ let end = search('^$')
+ if end <= 0
+ let end = line('$') + 1
+ endif
+ let origcount = CountNl(lnum, strlnum - 1)
+ let transcount = CountNl(strlnum, end - 1)
+ " Allow for a few more or less line breaks when there are 2 or more
+ if origcount != transcount && (origcount <= 2 || transcount <= 2)
+ echomsg 'Mismatching "\n" in line ' . line('.')
+ if error == 0
+ let error = lnum
+ endif
+ endif
+endwhile
+
+" Check that the file is well formed according to msgfmts understanding
+if executable("msgfmt")
+ let filename = expand("%")
+ " Newer msgfmt does not take OLD_PO_FILE_INPUT argument, must be in
+ " environment.
+ let $OLD_PO_FILE_INPUT = 'yes'
+ let a = system("msgfmt --statistics " . filename)
+ if v:shell_error != 0
+ let error = matchstr(a, filename.':\zs\d\+\ze:')+0
+ for line in split(a, '\n') | echomsg line | endfor
+ endif
+endif
+
+" Check that the plural form is properly initialized
+1
+let plural = search('^msgid_plural ', 'n')
+if (plural && search('^"Plural-Forms: ', 'n') == 0) || (plural && search('^msgstr\[0\] ".\+"', 'n') != plural + 1)
+ if search('^"Plural-Forms: ', 'n') == 0
+ echomsg "Missing Plural header"
+ if error == 0
+ let error = search('\(^"[A-Za-z-_]\+: .*\\n"\n\)\+\zs', 'n') - 1
+ endif
+ elseif error == 0
+ let error = plural
+ endif
+elseif !plural && search('^"Plural-Forms: ', 'n')
+ " We allow for a stray plural header, msginit adds one.
+endif
+
+" Check that 8bit encoding is used instead of 8-bit
+let cte = search('^"Content-Transfer-Encoding:\s\+8-bit', 'n')
+let ctc = search('^"Content-Type:.*;\s\+\<charset=[iI][sS][oO]_', 'n')
+let ctu = search('^"Content-Type:.*;\s\+\<charset=utf-8', 'n')
+if cte
+ echomsg "Content-Transfer-Encoding should be 8bit instead of 8-bit"
+ " TODO: make this an error
+ " if error == 0
+ " let error = cte
+ " endif
+elseif ctc
+ echomsg "Content-Type charset should be 'ISO-...' instead of 'ISO_...'"
+ " TODO: make this an error
+ " if error == 0
+ " let error = ct
+ " endif
+elseif ctu
+ echomsg "Content-Type charset should be 'UTF-8' instead of 'utf-8'"
+ " TODO: make this an error
+ " if error == 0
+ " let error = ct
+ " endif
+endif
+
+
+if error == 0
+ " If all was OK restore the view.
+ call winrestview(wsv)
+ echomsg "OK"
+else
+ " Put the cursor on the line with the error.
+ exe error
+endif
+
+let &wrapscan = s:save_wrapscan
+unlet s:save_wrapscan
+
+endif
diff --git a/src/po/cleanup.vim b/src/po/cleanup.vim
new file mode 100644
index 0000000..b27d880
--- /dev/null
+++ b/src/po/cleanup.vim
@@ -0,0 +1,25 @@
+" Vim script to cleanup a .po file:
+" - Remove line numbers (avoids that diffs are messy).
+" - Comment-out fuzzy and empty messages.
+" - Make sure there is a space before the string (required for Solaris).
+" Requires Vim 6.0 or later (because of multi-line search patterns).
+
+" Disable diff mode, because it makes this very slow
+let s:was_diff = &diff
+setl nodiff
+
+" untranslated message preceded by c-format or comment
+silent g/^#, c-format\n#/.d
+silent g/^#\..*\n#/.d
+
+silent g/^#[:~] /d
+silent g/^#, fuzzy\(, .*\)\=\nmsgid ""\@!/.+1,/^$/-1s/^/#\~ /
+silent g/^msgstr"/s//msgstr "/
+silent g/^msgid"/s//msgid "/
+silent g/^msgstr ""\(\n"\)\@!/?^msgid?,.s/^/#\~ /
+
+silent g/^\n\n\n/.d
+
+if s:was_diff
+ setl diff
+endif
diff --git a/src/po/cs.cp1250.po b/src/po/cs.cp1250.po
new file mode 100644
index 0000000..1813401
--- /dev/null
+++ b/src/po/cs.cp1250.po
@@ -0,0 +1,4660 @@
+# Czech translation of vim
+# Jiøí Pavlovský <jpavlovsky@mbox.vol.cz>, 2000 - 2002.
+# Some completion for vim6.0 added by Jiøí Bøezina <brz@centrum.cz>
+# Some bugfixes by Tomáš Zellerin <zellerin@volny.cz>
+#
+# Generated from cs.po, DO NOT EDIT.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: vim-6.0\n"
+"POT-Creation-Date: 2001-10-08 08:27-0700\n"
+"PO-Revision-Date: 2002-02-06 22:29+0100\n"
+"Last-Translator: Jiøí Pavlovský <jpavlovsky@mbox.vol.cz>\n"
+"Language-Team: Czech <cs@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=cp1250\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "E82: Cannot allocate any buffer, exiting..."
+msgstr "E82: Nelze alokovat žádný buffer, konèím..."
+
+msgid "E83: Cannot allocate buffer, using other one..."
+msgstr "E83: Nelze alokovat buffer, použiji jiný..."
+
+msgid "No buffers were unloaded"
+msgstr "Žádný buffer nebyl deaktivován"
+
+msgid "No buffers were deleted"
+msgstr "Žádný buffer nebyl smazán"
+
+msgid "No buffers were wiped out"
+msgstr "Žádný buffer nebyl zahozen"
+
+msgid "1 buffer unloaded"
+msgstr "Poèet deaktivovaných bufferù: 1"
+
+#, c-format
+msgid "%d buffers unloaded"
+msgstr "Poèet deaktivovaných bufferù: %d"
+
+msgid "1 buffer deleted"
+msgstr "Poèet smazaných bufferù: 1"
+
+#, c-format
+msgid "%d buffers deleted"
+msgstr "Poèet smazaných bufferù: %d"
+
+msgid "1 buffer wiped out"
+msgstr "Poèet zahozených bufferù: 1"
+
+#, c-format
+msgid "%d buffers wiped out"
+msgstr "Poèet zahozených bufferù: %d"
+
+msgid "E84: No modified buffer found"
+msgstr "E84: Nebyl nalezen žádný zmìnìný buffer"
+
+#. back where we started, didn't find anything.
+msgid "E85: There is no listed buffer"
+msgstr "E85: Seznam bufferù je prázdný"
+
+#, c-format
+msgid "E86: Cannot go to buffer %ld"
+msgstr "E86: Nelze pøeskoèit na buffer %ld"
+
+msgid "E87: Cannot go beyond last buffer"
+msgstr "E87: Za poslední buffer nelze pøeskoèit"
+
+msgid "E88: Cannot go before first buffer"
+msgstr "E88: Pøed první buffer nelze pøeskoèit"
+
+#, c-format
+msgid "E89: No write since last change for buffer %ld (use ! to override)"
+msgstr "E89: Zmìny v bufferu %ld nebyly uloženy (! pro vynucení)"
+
+msgid "E90: Cannot unload last buffer"
+msgstr "E90: Poslední buffer nelze deaktivovat"
+
+msgid "W14: Warning: List of file names overflow"
+msgstr "W14: Varování: pøeteèení seznamu s názvy souborù"
+
+#, c-format
+msgid "E92: Buffer %ld not found"
+msgstr "E92: Buffer %ld nenalezen"
+
+#, c-format
+msgid "E93: More than one match for %s"
+msgstr "E93: Vzoru %s vyhovuje více bufferù"
+
+#, c-format
+msgid "E94: No matching buffer for %s"
+msgstr "E94: Vzoru %s nevyhovuje žádný buffer"
+
+#, c-format
+msgid "line %ld"
+msgstr "øádek %ld"
+
+msgid "E95: Buffer with this name already exists"
+msgstr "E95: Buffer tohoto jména již existuje"
+
+msgid " [Modified]"
+msgstr " [Zmìnìný]"
+
+msgid "[Not edited]"
+msgstr "[Needitovaný]"
+
+msgid "[New file]"
+msgstr "[Nový soubor]"
+
+msgid "[Read errors]"
+msgstr "[Chyby pøi ètení]"
+
+msgid "[readonly]"
+msgstr "[Pouze pro ètení]"
+
+msgid "1 line --%d%%--"
+msgstr "øádkù: --%d%%--"
+
+msgid "%ld lines --%d%%--"
+msgstr "øádkù: %ld --%d%%--"
+
+msgid "line %ld of %ld --%d%%-- col "
+msgstr "øádek %ld/%ld --%d%%-- sloupec"
+
+msgid "[No file]"
+msgstr "[Žádný soubor]"
+
+#. must be a help buffer
+msgid "help"
+msgstr "nápovìda"
+
+msgid "[help]"
+msgstr "[nápovìda]"
+
+msgid "[Preview]"
+msgstr "[náhled]"
+
+msgid "All"
+msgstr "Vše"
+
+msgid "Bot"
+msgstr "Konec"
+
+msgid "Top"
+msgstr "Zaèátek"
+
+msgid ""
+"\n"
+"# Buffer list:\n"
+msgstr ""
+"\n"
+"# Seznam bufferù:\n"
+
+msgid "[Error List]"
+msgstr "[seznam chyb]"
+
+msgid "[No File]"
+msgstr "[žádný soubor]"
+
+msgid ""
+"\n"
+"--- Signs ---"
+msgstr ""
+"\n"
+"--- Znaky ---"
+
+#, c-format
+msgid "Signs for %s:"
+msgstr "Znaky pro %s:"
+
+#, c-format
+msgid " line=%ld id=%d name=%s"
+msgstr " øádek=%ld id=%d jméno=%s"
+
+#, c-format
+msgid "E96: Can not diff more than %ld buffers"
+msgstr "E96: Nelze pøekroèit maximální poèet %ld diff bufferù"
+
+msgid "E97: Cannot create diffs"
+msgstr "E97: Nelze vytvoøit diffy"
+
+msgid "Patch file"
+msgstr "Soubor se záplatou"
+
+msgid "E98: Cannot read diff output"
+msgstr "E98: Nelze èíst výstup programu diff"
+
+msgid "E99: Current buffer is not in diff mode"
+msgstr "E99: Aktuální buffer není v diff režimu"
+
+msgid "E100: No other buffer in diff mode"
+msgstr "E100: To byl poslední buffer v diff režimu"
+
+msgid "E101: More than two buffers in diff mode, don't know which one to use"
+msgstr "E101: V diff režimu jsou více než dva buffery. Nevím, který mám použít."
+
+#, c-format
+msgid "E102: Can't find buffer \"%s\""
+msgstr "E102: Nelze nalézt buffer \"%s\""
+
+#, c-format
+msgid "E103: Buffer \"%s\" is not in diff mode"
+msgstr "E103: Buffer \"%s\" není v diff režimu"
+
+msgid "E104: Escape not allowed in digraph"
+msgstr "E104: digraph nesmí obsahovat Escape"
+
+msgid "Keymap file not found"
+msgstr "Soubor s mapou klávesnice nebyl nalezen"
+
+msgid "E105: Using :loadkeymap not in a sourced file"
+msgstr "E105: :loadkeymap mimo interpretovaný soubor"
+
+msgid " Keyword completion (^N/^P)"
+msgstr " Doplòování klíèových slov (^N/^P)"
+
+#. ctrl_x_mode == 0, ^P/^N compl.
+msgid " ^X mode (^E/^Y/^L/^]/^F/^I/^K/^D/^V/^N/^P)"
+msgstr " ^X režim (^E/^Y/^L/^]/^F/^I/^K/^D/^V/^N/^P)"
+
+#. Scroll has it's own msgs, in it's place there is the msg for local
+#. * ctrl_x_mode = 0 (eg continue_status & CONT_LOCAL) -- Acevedo
+msgid " Keyword Local completion (^N/^P)"
+msgstr " Lokální doplòování klíèových slov (^N/^P)"
+
+msgid " Whole line completion (^L/^N/^P)"
+msgstr " Doplòování celých øádkù (^L/^N/^P)"
+
+msgid " File name completion (^F/^N/^P)"
+msgstr " Doplòování názvù souborù (^F/^N/^P)"
+
+msgid " Tag completion (^]/^N/^P)"
+msgstr " Doplòování tagù (^I/^N/^P)"
+
+msgid " Path pattern completion (^N/^P)"
+msgstr " Doplòování vzoru cest (^N/^P)"
+
+msgid " Definition completion (^D/^N/^P)"
+msgstr " Doplòování definic (^D/^N/^P)"
+
+msgid " Dictionary completion (^K/^N/^P)"
+msgstr " Doplòování podle slovníku (^K/^N/^P)"
+
+msgid " Thesaurus completion (^T/^N/^P)"
+msgstr " Doplòování podle tezauru (^T/^N/^P)"
+
+msgid " Command-line completion (^V/^N/^P)"
+msgstr " Doplòování pøíkazové øádky (^I/^N/^P)"
+
+msgid "Hit end of paragraph"
+msgstr "Konec odstavce"
+
+msgid "'thesaurus' option is empty"
+msgstr "volba 'thesaurus' je prázdná"
+
+msgid "'dictionary' option is empty"
+msgstr "volba 'dictionary' je prázdná"
+
+#, c-format
+msgid "Scanning dictionary: %s"
+msgstr "Prohledávám slovník %s"
+
+msgid " (insert) Scroll (^E/^Y)"
+msgstr " (insert) Rolování (^E/^Y)"
+
+msgid " (replace) Scroll (^E/^Y)"
+msgstr " (replace) Rolování (^E/^Y)"
+
+#, c-format
+msgid "Scanning: %s"
+msgstr "Prohledávám %s"
+
+msgid "Scanning tags."
+msgstr "Prohledávám tagy"
+
+msgid " Adding"
+msgstr "Pøidávám"
+
+#. showmode might reset the internal line pointers, so it must
+#. * be called before line = ml_get(), or when this address is no
+#. * longer needed. -- Acevedo.
+#.
+msgid "-- Searching..."
+msgstr "-- Hledám..."
+
+msgid "Back at original"
+msgstr "Výchozí podoba"
+
+msgid "Word from other line"
+msgstr "Slovo z jiného øádku"
+
+msgid "The only match"
+msgstr "Jediná shoda"
+
+#, c-format
+msgid "match %d of %d"
+msgstr "shoda %d/%d"
+
+#, c-format
+msgid "match %d"
+msgstr "shoda %d"
+
+#, c-format
+msgid "E106: Unknown variable: \"%s\""
+msgstr "E106: Neznámá promìnná: \"%s\""
+
+#, c-format
+msgid "E107: Missing parentheses: %s"
+msgstr "E107: Chybí závorky: %s"
+
+#, c-format
+msgid "E108: No such variable: \"%s\""
+msgstr "E108: Promìnná \"%s\" neexistuje"
+
+msgid "E109: Missing ':' after '?'"
+msgstr "E109: Po '?' chybí ':'"
+
+msgid "E110: Missing ')'"
+msgstr "E110: Chybìjící ')'"
+
+msgid "E111: Missing ']'"
+msgstr "E111: Chybìjící ']'"
+
+#, c-format
+msgid "E112: Option name missing: %s"
+msgstr "E112: Chybí jméno volby: %s"
+
+#, c-format
+msgid "E113: Unknown option: %s"
+msgstr "E113: Neznámá volba: %s"
+
+#, c-format
+msgid "E114: Missing quote: %s"
+msgstr "E114: Chybí uvozovky: %s"
+
+#, c-format
+msgid "E115: Missing quote: %s"
+msgstr "E115: Chybí uvozovky: %s"
+
+#, c-format
+msgid "E116: Invalid arguments for function %s"
+msgstr "E116: Chybné argumenty pro funkci %s"
+
+#, c-format
+msgid "E117: Unknown function: %s"
+msgstr "E117: Neznámá funkce: %s"
+
+#, c-format
+msgid "E118: Too many arguments for function: %s"
+msgstr "E118: Pøíliš mnoho argumentù pro funkci %s"
+
+#, c-format
+msgid "E119: Not enough arguments for function: %s"
+msgstr "E119: Pøíliš málo argumentù pro funkci %s"
+
+#, c-format
+msgid "E120: Using <SID> not in a script context: %s"
+msgstr "E120: Použití <SID> mimo kontext skriptu: %s"
+
+#, c-format
+msgid "+-%s%3ld lines: "
+msgstr "+-%s%3ld øádkù:"
+
+msgid ""
+"&OK\n"
+"&Cancel"
+msgstr ""
+"&OK\n"
+"&Zrušit"
+
+msgid "E240: No connection to Vim server"
+msgstr "E240: Neexistuje pøipojení k Vim serveru"
+
+msgid "E277: Unable to read a server reply"
+msgstr "E277: Nelze èíst odpovìï serveru"
+
+msgid "E258: Unable to send to client"
+msgstr "E258: Nelze pøedat klientovi"
+
+#, c-format
+msgid "E241: Unable to send to %s"
+msgstr "E241: Nelze pøedat do %s"
+
+msgid "(Invalid)"
+msgstr "(Chybný)"
+
+#, c-format
+msgid "E121: Undefined variable: %s"
+msgstr "E121: Nedefinovaná promìnná: %s"
+
+#, c-format
+msgid "E122: Function %s already exists, use ! to replace"
+msgstr "E122: Funkce %s již existuje. Použijte ! pro její nahrazení."
+
+#, c-format
+msgid "E123: Undefined function: %s"
+msgstr "E123: Nedefinovaná funkce: %s"
+
+#, c-format
+msgid "E124: Missing '(': %s"
+msgstr "E124: Chybí '(': %s"
+
+#, c-format
+msgid "E125: Illegal argument: %s"
+msgstr "E125: Nepøípustný argument: %s"
+
+msgid "E126: Missing :endfunction"
+msgstr "E126: Chybí :endfunction"
+
+#, c-format
+msgid "E127: Cannot redefine function %s: It is in use"
+msgstr "E127: Nelze pøedefinovat funkci %s: je používána"
+
+#, c-format
+msgid "E128: Function name must start with a capital: %s"
+msgstr "E128: Název funkce musí zaèínat velkým písmenem: %s"
+
+msgid "E129: Function name required"
+msgstr "E129: Je vyžadováno jméno funkce"
+
+msgid "function "
+msgstr "funkce "
+
+#, c-format
+msgid "E130: Undefined function: %s"
+msgstr "E130: Nedefinovaná funkce: %s"
+
+#, c-format
+msgid "E131: Cannot delete function %s: It is in use"
+msgstr "E131: Nelze smazat funkci %s: je již používána"
+
+msgid "E132: Function call depth is higher than 'maxfuncdepth'"
+msgstr "E132: Zanoøení funkce je hlubší než 'maxfuncdepth'"
+
+#. always scroll up, don't overwrite
+#, c-format
+msgid "calling %s"
+msgstr "volám %s"
+
+#. always scroll up, don't overwrite
+#, c-format
+msgid "continuing in %s"
+msgstr "pokraèuji v %s"
+
+msgid "E133: :return not inside a function"
+msgstr "E133: :return mimo funkci"
+
+#, c-format
+msgid "%s returning #%ld"
+msgstr "dokonèeno provádìní %s. Návratová hodnota #%ld"
+
+#, c-format
+msgid "%s returning \"%s\""
+msgstr "dokonèeno provádìní %s. Návratová hodnota \"%s\""
+
+msgid ""
+"\n"
+"# global variables:\n"
+msgstr ""
+"\n"
+"# globální promìnné:\n"
+
+#, c-format
+msgid "<%s>%s%s %d, Hex %02x, Octal %03o"
+msgstr "<%s>%s%s %d, šestnáctkovì %02x, osmièkovì %03o"
+
+msgid "E134: Move lines into themselves"
+msgstr "E134: Nelze pøesunout øádky na pùvodní místo"
+
+msgid "1 line moved"
+msgstr "poèet pøesunutých øádkù: 1"
+
+#, c-format
+msgid "%ld lines moved"
+msgstr "Poèet pøesunutých øádkù: %ld"
+
+#, c-format
+msgid "%ld lines filtered"
+msgstr "Poèet filtrovaných øádkù: %ld"
+
+msgid "E135: *Filter* Autocommands must not change current buffer"
+msgstr "E135: Automatické pøíkazy *Filter* nesmí mìnit aktuální buffer"
+
+msgid "[No write since last change]\n"
+msgstr "[Neuložené zmìny]\n"
+
+#, c-format
+msgid "viminfo: %s in line: "
+msgstr "viminfo: %s na øádku: "
+
+msgid "E136: viminfo: Too many errors, skipping rest of file"
+msgstr "E136: viminfo: pøíliš mnoho chyb, pøeskakuji zbytek souboru"
+
+#, c-format
+msgid "Reading viminfo file \"%s\"%s%s%s"
+msgstr "Ètu viminfo soubor \"%s\"%s%s%s"
+
+msgid " info"
+msgstr " informace"
+
+msgid " marks"
+msgstr " znaèky"
+
+msgid " FAILED"
+msgstr " se nezdaøilo"
+
+#, c-format
+msgid "E137: Viminfo file is not writable: %s"
+msgstr "E137: do viminfo souboru %s nelze zapisovat"
+
+#, c-format
+msgid "E138: Can't write viminfo file %s!"
+msgstr "E138: Nelze uložit viminfo soubor %s!"
+
+#, c-format
+msgid "Writing viminfo file \"%s\""
+msgstr "Ukládám viminfo souboru \"%s\""
+
+#. Write the info:
+msgid "# This viminfo file was generated by Vim %s.\n"
+msgstr "# Tento viminfo soubor byl vytvoøen editorem Vim %s.\n"
+
+msgid ""
+"# You may edit it if you're careful!\n"
+"\n"
+msgstr ""
+"# Pokud budete opatrný, mùžete jej upravovat.\n"
+"\n"
+
+msgid "# Value of 'encoding' when this file was written\n"
+msgstr "# Hodnota volby 'encoding' v dobì uložení tohoto souboru\n"
+
+msgid "Illegal starting char"
+msgstr "Nepøípustný poèáteèní znak"
+
+msgid "Save As"
+msgstr "Uložit jako"
+
+#. Overwriting a file that is loaded in another buffer is not a
+#. * good idea.
+msgid "E139: File is loaded in another buffer"
+msgstr "E139: Soubor je nahrán v jiném bufferu"
+
+msgid "Write partial file?"
+msgstr "Uložit neúplný soubor?"
+
+msgid "E140: Use ! to write partial buffer"
+msgstr "E140: Použijte ! pro uložení neúplného bufferu"
+
+#, c-format
+msgid "Overwrite existing file \"%.*s\"?"
+msgstr "Pøepsat soubor \"%.*s\"?"
+
+#, c-format
+msgid "E141: No file name for buffer %ld"
+msgstr "E141: Žádný název souboru pro buffer %ld"
+
+msgid "E142: File not written: Writing is disabled by 'write' option"
+msgstr "E142: Soubor nebyl uložen: Ukládání je zakázáno volbou 'write'"
+
+#, c-format
+msgid ""
+"'readonly' option is set for \"%.*s\".\n"
+"Do you wish to write anyway?"
+msgstr ""
+"Pro \"%.*s\" je nastavena volba 'readonly'.\n"
+"Pøejete si ji potlaèit?"
+
+msgid "Edit File"
+msgstr "Editovat soubor"
+
+#, c-format
+msgid "E143: Autocommands unexpectedly deleted new buffer %s"
+msgstr "E143: Automatické pøíkazy neoèekávanì smazaly nový buffer %s"
+
+msgid "E144: non-numeric argument to :z"
+msgstr "E144: neèíselný argument pro :z"
+
+msgid "E145: Shell commands not allowed in rvim"
+msgstr "E145: rvim nepovoluje použití pøíkazù shellu"
+
+msgid "E146: Regular expressions can't be delimited by letters"
+msgstr "E146: Regulární výrazy nesmí být oddìleny písmeny"
+
+#, c-format
+msgid "replace with %s (y/n/a/q/l/^E/^Y)?"
+msgstr "nahradit za %s (y/n/a/q/l/^E/^Y)?"
+
+msgid "(Interrupted) "
+msgstr "(Pøerušeno) "
+
+msgid "1 substitution"
+msgstr "1 nahrazení"
+
+#, c-format
+msgid "%ld substitutions"
+msgstr "%ld nahrazení"
+
+msgid " on 1 line"
+msgstr " na jednom øádku"
+
+#, c-format
+msgid " on %ld lines"
+msgstr " na %ld øádcích"
+
+msgid "E147: Cannot do :global recursive"
+msgstr "E147: :global nelze volat rekurzivnì"
+
+msgid "E148: Regular expression missing from global"
+msgstr "E148: U pøíkazu 'global' chybí regulární výraz"
+
+#, c-format
+msgid "Pattern found in every line: %s"
+msgstr "Vzor nalezen na každém øádku: %s"
+
+msgid ""
+"\n"
+"# Last Substitute String:\n"
+"$"
+msgstr ""
+"\n"
+"# Poslední nahrazující øetìzec:\n"
+"$"
+
+#, c-format
+msgid "E149: Sorry, no help for %s"
+msgstr "E149: Lituji, pro %s není žádná nápovìda"
+
+#, c-format
+msgid "Sorry, help file \"%s\" not found"
+msgstr "Lituji, soubor \"%s\" s nápovìdou nebyl nalezen"
+
+#, c-format
+msgid "E150: Not a directory: %s"
+msgstr "E150: %s není adresáøem"
+
+#, c-format
+msgid "E152: Cannot open %s for writing"
+msgstr "E152: Nelze otevøít %s pro zápis"
+
+#, c-format
+msgid "E153: Unable to open %s for reading"
+msgstr "E153: Nelze otevøít %s pro zápis"
+
+#, c-format
+msgid "E154: Duplicate tag \"%s\" in file %s"
+msgstr "E154: Duplicitní tag \"%s\" v souboru %s"
+
+#, c-format
+msgid "E160: Unknown sign command: %s"
+msgstr "E160: Neznámá volba pøíkazu: %s"
+
+msgid "E156: Missing sign name"
+msgstr "E156: Chybí jméno volby"
+
+msgid "E255: Too many signs defined"
+msgstr "E255: Nastaveno pøíliš mnoho voleb"
+
+#, c-format
+msgid "E239: Invalid sign text: %s"
+msgstr "E239: Neplatný text volby: %s"
+
+#, c-format
+msgid "E155: Unknown sign: %s"
+msgstr "E155: Neznámá volba: %s"
+
+msgid "E159: Missing sign number"
+msgstr "E159: Chybí identifikátor volby"
+
+#, c-format
+msgid "E158: Invalid buffer name: %s"
+msgstr "E158: chybné jméno bufferu: %s"
+
+#, c-format
+msgid "E157: Invalid sign ID: %ld"
+msgstr "E157: Chybné ID volby: %ld"
+
+msgid "[Deleted]"
+msgstr "[Vymazáno]"
+
+msgid "Entering Debug mode. Type \"cont\" to leave."
+msgstr "Spouštím ladící režim. Pro ukonèení napište \"cont\"."
+
+#, c-format
+msgid "line %ld: %s"
+msgstr "øádek %ld: %s"
+
+#, c-format
+msgid "cmd: %s"
+msgstr "pøíkaz: %s"
+
+#, c-format
+msgid "Breakpoint in \"%s%s\" line %ld"
+msgstr "Bod pøerušení v \"%s%s\" na øádku %ld"
+
+#, c-format
+msgid "E161: Breakpoint not found: %s"
+msgstr "E161: Bod pøerušení nenalezen: %s"
+
+msgid "No breakpoints defined"
+msgstr "Nebyly definovánu žádné body pøerušení"
+
+#, c-format
+msgid "%3d %s %s line %ld"
+msgstr "%3d %s %s øádek %ld"
+
+#, c-format
+msgid "Save changes to \"%.*s\"?"
+msgstr "Uložit zmìny do \"%.*s\"?"
+
+msgid "Untitled"
+msgstr "Nepojmenováno"
+
+#, c-format
+msgid "E162: No write since last change for buffer \"%s\""
+msgstr "E162: Buffer \"%s\" obsahuje neuložené zmìny"
+
+msgid "Warning: Entered other buffer unexpectedly (check autocommands)"
+msgstr ""
+"Varování: Neèekaný vstup do jiného bufferu (zkontrolujte automatické pøíkazy)"
+
+msgid "E163: There is only one file to edit"
+msgstr "E163: Pro editaci byl zadán pouze jeden soubor"
+
+msgid "E164: Cannot go before first file"
+msgstr "E164: Pøed první soubor nelze pøeskoèit"
+
+msgid "E165: Cannot go beyond last file"
+msgstr "E165: Za poslední soubor nelze pøeskoèit"
+
+#, c-format
+msgid "Searching for \"%s\" in \"%s\""
+msgstr "Hledám \"%s\" v \"%s\""
+
+#, c-format
+msgid "Searching for \"%s\""
+msgstr "Hledám \"%s\""
+
+#, c-format
+msgid "not found in 'runtimepath': \"%s\""
+msgstr "soubor \"%s\" nebyl nalezen v 'runtimepath'"
+
+msgid "Run Macro"
+msgstr "Spustit makro"
+
+#, c-format
+msgid "Cannot source a directory: \"%s\""
+msgstr "nelze interpretovat adresáø: \"%s\""
+
+#, c-format
+msgid "could not source \"%s\""
+msgstr "nelze interpretovat \"%s\""
+
+#, c-format
+msgid "line %ld: could not source \"%s\""
+msgstr "øádek %ld: nelze interpretovat \"%s\""
+
+#, c-format
+msgid "sourcing \"%s\""
+msgstr "interpretuji \"%s\""
+
+#, c-format
+msgid "line %ld: sourcing \"%s\""
+msgstr "øádek %ld: interpretuji %s"
+
+#, c-format
+msgid "finished sourcing %s"
+msgstr "dokonèena interpretace %s"
+
+msgid "W15: Warning: Wrong line separator, ^M may be missing"
+msgstr "W15: Varování: chybný oddìlovaè øádkù. Možná chybí ^M."
+
+msgid "E167: :scriptencoding used outside of a sourced file"
+msgstr "E167: :scriptencoding použito mimo interpretovaný soubor"
+
+msgid "E168: :finish used outside of a sourced file"
+msgstr "E168: :finish použito mimo interpretovaný soubor"
+
+msgid "No text to be printed"
+msgstr "Žádný text k vytištìní"
+
+msgid "Printing page %d (%d%%)"
+msgstr "Tisknu stranu %d (%d%%)"
+
+#, c-format
+msgid " Copy %d of %d"
+msgstr " Kopie %d z %d"
+
+#, c-format
+msgid "Printed: %s"
+msgstr "Vytištìno: %s"
+
+msgid "Printing aborted"
+msgstr "Tisk zrušen"
+
+msgid "E455: Error writing to PostScript output file"
+msgstr "E455: Nelze zapisovat do výstupního PostScriptového souboru"
+
+msgid "E324: Can't open PostScript output file"
+msgstr "E324: Nelze otevøít výstupní PostScriptový soubor"
+
+msgid "E456: Can't open file \"%s\""
+msgstr "E456: Nelze otevøít soubor \"%s\""
+
+msgid "E457: Can't read PostScript resource file \"%s\""
+msgstr "E457: Nelze èíst zdrojový PostScriptový soubor \"%s\""
+
+msgid "Sending to printer..."
+msgstr "Odesílám na tiskárnu..."
+
+msgid "E365: Failed to print PostScript file"
+msgstr "E365: Selhal tisk PostScriptového souboru"
+
+msgid "Print job sent."
+msgstr "Tisková úloha odeslána."
+
+#, c-format
+msgid "Current %slanguage: \"%s\""
+msgstr "Aktuální %sjazyk: \"%s\""
+
+#, c-format
+msgid "E197: Cannot set language to \"%s\""
+msgstr "E197: Nelze nastavit jazyk na \"%s\""
+
+msgid "Entering Ex mode. Type \"visual\" to go to Normal mode."
+msgstr "Spouštím Ex mód. Napište \"visual\" pro návrat do normálního módu."
+
+#. must be at EOF
+msgid "At end-of-file"
+msgstr "Konec souboru"
+
+msgid "E169: Command too recursive"
+msgstr "E169: Pøíkaz je pøíliš rekurzivní"
+
+msgid "E170: Missing :endwhile"
+msgstr "E170: Chybí :endwhile"
+
+msgid "E171: Missing :endif"
+msgstr "E171: Chybí :endif"
+
+msgid "End of sourced file"
+msgstr "Konec interpretovaného souboru"
+
+msgid "End of function"
+msgstr "Konec funkce"
+
+msgid "Ambiguous use of user-defined command"
+msgstr "Nejednoznaèné použití uživatelsky definovaného pøíkazu"
+
+msgid "Not an editor command"
+msgstr "Není pøíkazem editoru"
+
+msgid "Don't panic!"
+msgstr "Nepanikaøte!"
+
+msgid "Backwards range given"
+msgstr "Zadán zpìtný rozsah"
+
+msgid "Backwards range given, OK to swap"
+msgstr "Zadán zpìtný rozsah. Prohodit hranice"
+
+msgid "Use w or w>>"
+msgstr "Použijte w èi w>>"
+
+msgid "E319: Sorry, the command is not available in this version"
+msgstr "E319: Pøíkaz není této verzi bohužel implementován"
+
+msgid "E172: Only one file name allowed"
+msgstr "E172: Pøípustný je pouze jeden název souboru"
+
+#, c-format
+msgid "%d more files to edit. Quit anyway?"
+msgstr "Ještì zbývají soubory k editaci (%d). Chcete pøesto ukonèit editor?"
+
+#, c-format
+msgid "E173: %ld more files to edit"
+msgstr "E173: Ještì zbývají soubory k editaci (%ld)."
+
+msgid "E174: Command already exists: use ! to redefine"
+msgstr "E174: Pøíkaz již existuje: použijte ! pro pøedefinování"
+
+msgid ""
+"\n"
+" Name Args Range Complete Definition"
+msgstr ""
+"\n"
+" Jméno Args Rozsah Úplnost Definice"
+
+msgid "No user-defined commands found"
+msgstr "Nebyly nalezeny žádné uživatelsky definované pøíkazy"
+
+msgid "E175: No attribute specified"
+msgstr "E175: Nebyly zadány žádné atributy"
+
+msgid "E176: Invalid number of arguments"
+msgstr "E176: Chybný poèet argumentù"
+
+msgid "E177: Count cannot be specified twice"
+msgstr "E177: Opakování nemùže být zadáno dvakrát"
+
+msgid "E178: Invalid default value for count"
+msgstr "E178: Chybná implicitní hodnota pro poèet"
+
+msgid "E179: argument required for complete"
+msgstr "E179: chybná implicitní hodnota pro opakování"
+
+#, c-format
+msgid "E180: Invalid complete value: %s"
+msgstr "E180: Chybná hodnota doplnìní: %s"
+
+#, c-format
+msgid "E181: Invalid attribute: %s"
+msgstr "E181: Chybný atribut: %s"
+
+msgid "E182: Invalid command name"
+msgstr "E182: Chybné jméno pøíkazu"
+
+msgid "E183: User defined commands must start with an uppercase letter"
+msgstr "E183: Uživatelsky definované pøíkazy musí zaèínat velikým písmenem."
+
+#, c-format
+msgid "E184: No such user-defined command: %s"
+msgstr "E184: Uživatelsky definovaný pøíkaz %s neexistuje"
+
+#, c-format
+msgid "E185: Cannot find color scheme %s"
+msgstr "E185: Nelze nalézt barevné schéma %s"
+
+msgid "Greetings, Vim user!"
+msgstr "Blahopøeji, uživateli Vimu!"
+
+msgid "Edit File in new window"
+msgstr "Editovat soubor v novém oknì"
+
+msgid "No swap file"
+msgstr "Žádný odkládací soubor"
+
+msgid "Append File"
+msgstr "Uložit soubor"
+
+msgid "E186: No previous directory"
+msgstr "E186: Žádný pøedchozí adresáø"
+
+msgid "E187: Unknown"
+msgstr "E187: Neznámý"
+
+#, c-format
+msgid "Window position: X %d, Y %d"
+msgstr "Umístìní okna: X %d, Y %d"
+
+msgid "E188: Obtaining window position not implemented for this platform"
+msgstr "E188: Na této platformì nelze umístìní okna zjistit"
+
+msgid "Save Redirection"
+msgstr "Uložit pøesmìrování"
+
+msgid "Save View"
+msgstr "Uložit pohled"
+
+msgid "Save Session"
+msgstr "Uložit sezení"
+
+msgid "Save Setup"
+msgstr "Uložit nastavení"
+
+#, c-format
+msgid "E189: \"%s\" exists (use ! to override)"
+msgstr "E189: \"%s\" existuje (použijte ! pro vynucení)"
+
+#, c-format
+msgid "E190: Cannot open \"%s\" for writing"
+msgstr "E190: Nelze otevøít \"%s\" pro zápis"
+
+#. set mark
+msgid "E191: Argument must be a letter or forward/backward quote"
+msgstr "E191: Argumentem mùže být pouze písmeno nebo pravý èi levý apostrof"
+
+msgid "E192: Recursive use of :normal too deep"
+msgstr "E192: Vnoøení :normal je pøíliš hluboké"
+
+msgid ":if nesting too deep"
+msgstr "vnoøení :if je pøíliš hluboké"
+
+msgid ":endif without :if"
+msgstr ":endif bez odpovídajícího :if"
+
+msgid ":else without :if"
+msgstr ":else bez odpovídajícího :if"
+
+msgid ":elseif without :if"
+msgstr ":elseif bez odpovídajícího :if"
+
+msgid ":while nesting too deep"
+msgstr "vnoøení :while je pøíliš hluboké"
+
+msgid ":continue without :while"
+msgstr ":continue bez odpovídajícího :while"
+
+msgid ":break without :while"
+msgstr ":break bez odpovídajícího :while"
+
+msgid ":endwhile without :while"
+msgstr ":endwhile bez odpovídajícího :while"
+
+msgid "E193: :endfunction not inside a function"
+msgstr "E193: :endfunction mimo funkci"
+
+msgid "E194: No alternate file name to substitute for '#'"
+msgstr ""
+"E194: Žádný alternativní název souboru, kterým by bylo možné nahradit '#'"
+
+msgid "no autocommand file name to substitute for \"<afile>\""
+msgstr "Žádný název souboru, kterým by bylo možné nahradit \"<afile>\""
+
+msgid "no autocommand buffer number to substitute for \"<abuf>\""
+msgstr "Žádné èíslo bufferu, kterým by bylo možné nahradit \"<abuf>\""
+
+msgid "no autocommand match name to substitute for \"<amatch>\""
+msgstr ""
+"Žádná shoda automatických pøíkazù, kterou by bylo možné nahradit \"<amatch>\""
+
+msgid "no :source file name to substitute for \"<sfile>\""
+msgstr "Žádný interpretovaný soubor, kterým by bylo možné nahradit \"<sfile>\""
+
+#, no-c-format
+msgid "Empty file name for '%' or '#', only works with \":p:h\""
+msgstr "Prázdný název souboru pro '%' èi '#' funguje pouze s \":p:h\""
+
+msgid "Evaluates to an empty string"
+msgstr "Výsledkem vyhodnocení je prázdný øetìzec"
+
+msgid "E195: Cannot open viminfo file for reading"
+msgstr "E195: Nelze otevøít pro ètení viminfo soubor"
+
+msgid "E196: No digraphs in this version"
+msgstr "E196: V této verzi nejsou spøežky podporovány"
+
+msgid "tagname"
+msgstr "jméno tagu"
+
+msgid " kind file\n"
+msgstr " typ soubor\n"
+
+msgid "'history' option is zero"
+msgstr "'volba 'history' je nastavena na nulu"
+
+#, c-format
+msgid ""
+"\n"
+"# %s History (newest to oldest):\n"
+msgstr ""
+"\n"
+"# Historie %s (poèínaje nejnovìjší položkou):\n"
+
+msgid "Command Line"
+msgstr "pøíkazové øádky"
+
+msgid "Search String"
+msgstr "vyhledávaných øetìzcù"
+
+msgid "Expression"
+msgstr "výrazù"
+
+msgid "Input Line"
+msgstr "vstupní øádky"
+
+msgid "E198: cmd_pchar beyond the command length"
+msgstr "E198: cmd_pchar pøekraèuje délku pøíkazu"
+
+msgid "E199: Active window or buffer deleted"
+msgstr "E199: Smazáno aktivní okno èi buffer"
+
+msgid "Illegal file name"
+msgstr "nepøípustný název souboru"
+
+msgid "is a directory"
+msgstr "je adresáøem"
+
+msgid "is not a file"
+msgstr "není souborem"
+
+msgid "[New File]"
+msgstr "[nový soubor]"
+
+msgid "[Permission Denied]"
+msgstr "[pøístup odmítnut]"
+
+msgid "E200: *ReadPre autocommands made the file unreadable"
+msgstr "E200: *ReadPre automatické pøíkazy uèinily soubor neèitelným"
+
+msgid "E201: *ReadPre autocommands must not change current buffer"
+msgstr "E201: *ReadPre automatické pøíkazy nesmí mìnit aktuální buffer"
+
+msgid "Vim: Reading from stdin...\n"
+msgstr "Vim: Ètu ze standardního vstupu...\n"
+
+msgid "Reading from stdin..."
+msgstr "Ètu ze standardního vstupu..."
+
+#. Re-opening the original file failed!
+msgid "E202: Conversion made file unreadable!"
+msgstr "E202: Po konverzi je soubor neèitelný!"
+
+msgid "[fifo/socket]"
+msgstr "[pojmenovaná roura/soket]"
+
+msgid "[fifo]"
+msgstr "[pojmenovaná roura]"
+
+msgid "[socket]"
+msgstr "[soket]"
+
+msgid "[RO]"
+msgstr "[RO]"
+
+msgid "[CR missing]"
+msgstr "[chybí CR]"
+
+msgid "[NL found]"
+msgstr "[nalezeno NL]"
+
+msgid "[long lines split]"
+msgstr "[dlouhé øádky zalomeny]"
+
+msgid "[NOT converted]"
+msgstr "[nezkonvertován]"
+
+msgid "[converted]"
+msgstr "[zkonvertován]"
+
+msgid "[crypted]"
+msgstr "[zašifrován]"
+
+msgid "[CONVERSION ERROR]"
+msgstr "[CHYBA PØEVODU]"
+
+msgid "[READ ERRORS]"
+msgstr "[CHYBY ÈTENÍ]"
+
+msgid "Can't find temp file for conversion"
+msgstr "Nelze nalézt doèasný soubor pro konverzi"
+
+msgid "Conversion with 'charconvert' failed"
+msgstr "Konverze s 'charconvert' se nezdaøila"
+
+msgid "can't read output of 'charconvert'"
+msgstr "nelze èíst výstup 'charconvert'"
+
+msgid "E203: Autocommands deleted or unloaded buffer to be written"
+msgstr ""
+"E203: Automatické pøíkazy smazaly èi deaktivovaly buffer, který mìl být "
+"uložen"
+
+msgid "E204: Autocommand changed number of lines in unexpected way"
+msgstr "E204: Automatický pøíkaz neèekaným zpùsobem zmìnil poèet øádkù"
+
+msgid "is not a file or writable device"
+msgstr "není souborem ani zaøízením na nìž lze zapisovat"
+
+msgid "is read-only (use ! to override)"
+msgstr "je pouze pro ètení (použijte ! pro vynucení)"
+
+msgid "Can't write to backup file (use ! to override)"
+msgstr "Nelze zapisovat do záložního souboru (použijte ! pro vynucení)"
+
+msgid "Close error for backup file (use ! to override)"
+msgstr "Chyba pøi uzavírání záložního souboru (použijte ! pro vynucení)"
+
+msgid "Can't read file for backup (use ! to override)"
+msgstr "Nelze naèíst soubor pro zálohu (použijte ! pro vynucení)"
+
+msgid "Cannot create backup file (use ! to override)"
+msgstr "Nelze vytvoøit záložní soubor (použijte ! pro vynucení)"
+
+msgid "Can't make backup file (use ! to override)"
+msgstr "Nelze vytvoøit záložní soubor (použijte ! pro vynucení)"
+
+# resource fork ?!
+msgid "The resource fork will be lost (use ! to override)"
+msgstr "'Resource fork' bude ztracen (použijte ! pro vynucení)"
+
+msgid "E214: Can't find temp file for writing"
+msgstr "E214: Nelze najít doèasný temp soubor pro zápis"
+
+msgid "E213: Cannot convert (use ! to write without conversion)"
+msgstr "E213: Nelze pøevést (použijte ! pro zápis bez pøevodu)"
+
+msgid "E166: Can't open linked file for writing"
+msgstr "E166: Nelze otevøít pøipojený soubor pro zápis"
+
+msgid "E212: Can't open file for writing"
+msgstr "E212: Nelze otevøít soubor pro zápis"
+
+msgid "Close failed"
+msgstr "Volání close selhalo"
+
+msgid "write error, conversion failed"
+msgstr "chyba pøi zápisu, konverze se nezdaøila"
+
+msgid "write error (file system full?)"
+msgstr "chyba pøi ukládání (je volné místo na disku?)"
+
+msgid " CONVERSION ERROR"
+msgstr " CHYBA PØEVODU"
+
+msgid "[Device]"
+msgstr "[zaøízení]"
+
+msgid "[New]"
+msgstr "[Nový]"
+
+msgid " [a]"
+msgstr " [p]"
+
+msgid " appended"
+msgstr " pøipojen"
+
+msgid " [w]"
+msgstr " [u]"
+
+msgid " written"
+msgstr " uložen"
+
+msgid "E205: Patchmode: can't save original file"
+msgstr "E205: patchmode: nelze uložit pùvodní soubor"
+
+msgid "E206: patchmode: can't touch empty original file"
+msgstr "E206: patchmode: nelze zapisovat do prázdného pùvodního souboru"
+
+msgid "E207: Can't delete backup file"
+msgstr "E207: Nelze smazat záložní soubor"
+
+msgid ""
+"\n"
+"WARNING: Original file may be lost or damaged\n"
+msgstr ""
+"\n"
+"VAROVÁNÍ: Obsah pùvodního souboru mùže být ztracen èi poškozen\n"
+
+msgid "don't quit the editor until the file is successfully written!"
+msgstr "neukonèujte editor døíve, než bude soubor úspìšnì uložen!"
+
+msgid "[dos]"
+msgstr "[dos]"
+
+msgid "[dos format]"
+msgstr "[dos formát]"
+
+msgid "[mac]"
+msgstr "[mac]"
+
+msgid "[mac format]"
+msgstr "[mac formát]"
+
+msgid "[unix]"
+msgstr "[unix]"
+
+msgid "[unix format]"
+msgstr "[unix formát]"
+
+msgid "1 line, "
+msgstr "1 øádek, "
+
+#, c-format
+msgid "%ld lines, "
+msgstr "%ld øádkù, "
+
+msgid "1 character"
+msgstr "1 znak"
+
+#, c-format
+msgid "%ld characters"
+msgstr "%ld znakù, "
+
+msgid "[noeol]"
+msgstr "[žádný eol]"
+
+msgid "[Incomplete last line]"
+msgstr "[neúplný poslední øádek]"
+
+#. don't overwrite messages here
+#. must give this prompt
+#. don't use emsg() here, don't want to flush the buffers
+msgid "WARNING: The file has been changed since reading it!!!"
+msgstr "VAROVÁNÍ: od jeho naètení byl obsah souboru zmìnìn!!!!"
+
+msgid "Do you really want to write to it"
+msgstr "Chcete jej opravdu uložit"
+
+#, c-format
+msgid "E208: Error writing to \"%s\""
+msgstr "E208: Chyba pøi zápisu do \"%s\""
+
+#, c-format
+msgid "E209: Error closing \"%s\""
+msgstr "E209: Chyb pøi uzavírání \"%s\""
+
+#, c-format
+msgid "E210: Error reading \"%s\""
+msgstr "E210: Chyba pøi ètení \"%s\""
+
+msgid "E246: FileChangedShell autocommand deleted buffer"
+msgstr "E246: FileChangedShell autocommand zrušil buffer"
+
+#, c-format
+msgid "E211: Warning: File \"%s\" no longer available"
+msgstr "E211: wa1: soubor \"%s\" již není dostupný"
+
+#, c-format
+msgid ""
+"W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as "
+"well"
+msgstr ""
+"W12: Varování: soubor \"%s\" byl po poèátku editace zmìnìn a buffer ve Vim "
+"také"
+
+#, c-format
+msgid "W11: Warning: File \"%s\" has changed since editing started"
+msgstr "W11: wc2: soubor \"%s\" byl po poèátku editace zmìnìn"
+
+#, c-format
+msgid "W16: Warning: Mode of file \"%s\" has changed since editing started"
+msgstr "W16: Varování: Mód souboru \"%s\" byl zmìnìn od zapoènutí editace"
+
+#, c-format
+msgid "W13: Warning: File \"%s\" has been created after editing started"
+msgstr "W13: wc4: po poèátku editace vytvoøen soubor \"%s\""
+
+msgid "Warning"
+msgstr "Varování"
+
+msgid ""
+"&OK\n"
+"&Load File"
+msgstr ""
+"&OK\n"
+"&Nahrát soubor"
+
+#, c-format
+msgid "E321: Could not reload \"%s\""
+msgstr "E321: Nelze znovuotevøít \"%s\""
+
+msgid "--Deleted--"
+msgstr "--Vymazáno--"
+
+#. the group doesn't exist
+#, c-format
+msgid "E367: No such group: \"%s\""
+msgstr "E367: Skupina \"%s\" neexistuje"
+
+#, c-format
+msgid "E215: Illegal character after *: %s"
+msgstr "E215: Nepøípustný znak po *: %s"
+
+#, c-format
+msgid "E216: No such event: %s"
+msgstr "E216: Událost %s neexistuje"
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Autocommands ---"
+msgstr ""
+"\n"
+"--- Automatické pøíkazy ---"
+
+msgid "E217: Can't execute autocommands for ALL events"
+msgstr "E217: Automatické pøíkazy nelze spustit pro VŠECHNY události"
+
+msgid "No matching autocommands"
+msgstr "Žádné vyhovující automatické pøíkazy"
+
+msgid "E218: autocommand nesting too deep"
+msgstr "E218: vnoøení automatického pøíkazu pøíliš hluboká"
+
+#, c-format
+msgid "%s Autocommands for \"%s\""
+msgstr "%s automatické pøíkazy pro \"%s\""
+
+#, c-format
+msgid "Executing %s"
+msgstr "spouštím %s"
+
+#. always scroll up, don't overwrite
+#, c-format
+msgid "autocommand %s"
+msgstr "Automatický pøíkaz %s"
+
+msgid "E219: Missing {."
+msgstr "E219: Chybí {."
+
+msgid "E220: Missing }."
+msgstr "E220: Chybí }."
+
+msgid "No fold found"
+msgstr "Žádný záhyb nebyl nalezen"
+
+msgid "E350: Cannot create fold with current 'foldmethod'"
+msgstr "E350: pomocí aktuální 'foldmethod' nelze vytvoøit záhyb"
+
+msgid "E351: Cannot delete fold with current 'foldmethod'"
+msgstr "E351: pomocí aktuální 'foldmethod' nelze vytvoøit záhyb"
+
+msgid "E221: 'commentstring' is empty"
+msgstr "E221: volba 'commentstring' je prázdná"
+
+msgid "E222: Add to read buffer"
+msgstr "E222: Pøidat do bufferu pro ètení"
+
+msgid "E223: recursive mapping"
+msgstr "E223: rekurzivní mapování"
+
+#, c-format
+msgid "E224: global abbreviation already exists for %s"
+msgstr "E224: pro %s již globální zkratka již existuje"
+
+#, c-format
+msgid "E225: global mapping already exists for %s"
+msgstr "E225: pro %s již globální mapování již existuje"
+
+#, c-format
+msgid "E226: abbreviation already exists for %s"
+msgstr "E226: pro %s již zkratka již existuje"
+
+#, c-format
+msgid "E227: mapping already exists for %s"
+msgstr "E227: pro %s již mapování již existuje"
+
+msgid "No abbreviation found"
+msgstr "Žádná zkratka nebyl nalezena"
+
+msgid "No mapping found"
+msgstr "Žádné mapování nebylo nalezeno"
+
+msgid "E228: makemap: Illegal mode"
+msgstr "E228: makemap: nepøípustný mód"
+
+msgid "E229: Cannot start the GUI"
+msgstr "E229: Nelze spustit GUI"
+
+#, c-format
+msgid "E230: Cannot read from \"%s\""
+msgstr "E230: Nelze èíst z \"%s\""
+
+msgid "E231: 'guifontwide' invalid"
+msgstr "E231: volba 'guifontwide' je chybnì nastavena"
+
+msgid "Error"
+msgstr "Chyba"
+
+msgid "&Ok"
+msgstr "&Ok"
+
+msgid "<cannot open> "
+msgstr "<nelze otevøít> "
+
+#, c-format
+msgid "vim_SelFile: can't get font %s"
+msgstr "vim_SelFile: písmo %s není dostupné"
+
+msgid "vim_SelFile: can't return to current directory"
+msgstr "vim_SelFile: nelze se vrátit do aktuálního adresáøe"
+
+msgid "Pathname:"
+msgstr "Název cesty:"
+
+msgid "vim_SelFile: can't get current directory"
+msgstr "vim_SelFile: nelze zjistit aktuální adresáø"
+
+msgid "OK"
+msgstr "OK"
+
+#. 'Cancel' button
+msgid "Cancel"
+msgstr "Zrušit"
+
+msgid "Scrollbar Widget: Could not get geometry of thumb pixmap."
+msgstr "Pøípravek posunovací lišty: nelze zjistit geometrii obrázku"
+
+msgid "Vim dialog"
+msgstr "Vim dialog"
+
+msgid "E232: Cannot create BalloonEval with both message and callback"
+msgstr "E232: BalloonEval nelze vytvoøit se zprávou a zároveò zpìtným voláním"
+
+msgid "Vim dialog..."
+msgstr "Vim dialog.."
+
+msgid "VIM - Search and Replace..."
+msgstr "VIM - Nalézt a nahradit..."
+
+msgid "VIM - Search..."
+msgstr "VIM - Nalézt..."
+
+msgid "Find what:"
+msgstr "Vyhledat:"
+
+msgid "Replace with:"
+msgstr "Nový text:"
+
+#. exact match only button
+msgid "Match exact word only"
+msgstr "hledat pouze celá slova"
+
+msgid "Direction"
+msgstr "Smìr"
+
+#. 'Up' and 'Down' buttons
+msgid "Up"
+msgstr "Nahoru"
+
+msgid "Down"
+msgstr "Dolù"
+
+#. 'Find Next' button
+msgid "Find Next"
+msgstr "Najít další"
+
+#. 'Replace' button
+msgid "Replace"
+msgstr "Nahradit"
+
+#. 'Replace All' button
+msgid "Replace All"
+msgstr "Nahradit vše"
+
+msgid "E233: cannot open display"
+msgstr "E233: nelze otevøít display"
+
+#, c-format
+msgid "E234: Unknown fontset: %s"
+msgstr "E234: Neznámá sada písem: %s"
+
+msgid "Font Selection"
+msgstr "Výbìr písma"
+
+#, c-format
+msgid "E235: Unknown font: %s"
+msgstr "E235: Neznámé písmo: %s"
+
+#, c-format
+msgid "E236: Font \"%s\" is not fixed-width"
+msgstr "E236: Písmo \"%s\" nemá pevnou šíøku"
+
+#, c-format
+msgid "E242: Color name not recognized: %s"
+msgstr "E242: Neznámé jméno barvy: %s"
+
+msgid "Used CUT_BUFFER0 instead of empty selection"
+msgstr "Místo prádné schránky použito CUT_BUFFER0"
+
+msgid "Filter"
+msgstr "Filtr"
+
+msgid "Directories"
+msgstr "Adresáøe"
+
+msgid "Help"
+msgstr "Nápovìda"
+
+msgid "Files"
+msgstr "Soubory"
+
+msgid "Selection"
+msgstr "Výbìr"
+
+msgid "Undo"
+msgstr "Zpìt"
+
+#, c-format
+msgid "E235: Can't load Zap font '%s'"
+msgstr "E235: Nelze naèíst Zap font '%s'"
+
+#, c-format
+msgid "E235: Can't use font %s"
+msgstr "E235: Nelze použít font %s"
+
+#, c-format
+msgid "E242: Missing color: %s"
+msgstr "E242: Chybí barva: %s"
+
+msgid ""
+"\n"
+"Sending message to terminate child process.\n"
+msgstr ""
+"\n"
+"Posílám signál k ukonèení synovského procesu.\n"
+
+#, c-format
+msgid "E243: Argument not supported: \"-%s\"; Use the OLE version."
+msgstr "E243: Argument nepodporován: \"-%s\"; Použijte OLE verzi."
+
+msgid "Find string (use '\\\\' to find a '\\')"
+msgstr "Najít øetìzec (použijte '\\\\' k nalezení '\\')"
+
+msgid "Find & Replace (use '\\\\' to find a '\\')"
+msgstr "Najít & Nahradit (použijte '\\\\' k nalezení '\\')"
+
+msgid "Vim E458: Cannot allocate colormap entry, some colors may be incorrect"
+msgstr ""
+"Vim E458: nelze alokovat položku barevné mapy. Nìkteré barvy mohou být "
+"nesprávné"
+
+#, c-format
+msgid "E250: Fonts for the following charsets are missing in fontset %s:"
+msgstr "E250: písma pro následující znakové sady chybí v sadì písem %s:"
+
+#, c-format
+msgid "E252: Fontset name: %s"
+msgstr "E252: název sady písem: %s"
+
+#, c-format
+msgid "Font '%s' is not fixed-width"
+msgstr "Písmo '%s' nemá pevnou šíøku"
+
+#, c-format
+msgid "E253: Fontset name: %s\n"
+msgstr "E253: název sady písem: %s\n"
+
+#, c-format
+msgid "Font0: %s\n"
+msgstr "Písmo0: %s\n"
+
+#, c-format
+msgid "Font1: %s\n"
+msgstr "Písmo1: %s\n"
+
+#, c-format
+msgid "Font%d width is not twice that of font0\n"
+msgstr "Šíøka písma%d není dvojnásoblem šíøky písma0\n"
+
+#, c-format
+msgid "Font0 width: %ld\n"
+msgstr "Šíøka písma0: %ld\n"
+
+#, c-format
+msgid ""
+"Font1 width: %ld\n"
+"\n"
+msgstr ""
+"Šíøka písma1: %ld\n"
+"\n"
+
+#, c-format
+msgid "E254: Cannot allocate color %s"
+msgstr "E254: nelze alokovat barvu %s"
+
+msgid "E255: Couldn't read in sign data!"
+msgstr "E255: Chyba -- nelze pøeèíst sign data!"
+
+msgid "E256: Hangul automata ERROR"
+msgstr "E256: CYBA Hangul automatu"
+
+msgid "Add a new database"
+msgstr "Pøidat novou databázi"
+
+msgid "Query for a pattern"
+msgstr "Hledání vzorku"
+
+msgid "Show this message"
+msgstr "Zobrazit tuto zprávu"
+
+msgid "Kill a connection"
+msgstr "Ukonèit spojení"
+
+msgid "Reinit all connections"
+msgstr "Znovu inicializovat všechna spojení"
+
+msgid "Show connections"
+msgstr "Zobrazit spojení"
+
+msgid "This cscope command does not support splitting the window.\n"
+msgstr "Tento cscope pøíkaz nepodporuje rozdìlení okna.\n"
+
+msgid "Usage: cstag <ident>"
+msgstr "Použití: cstag <odsazení>"
+
+msgid "E257: cstag: tag not found"
+msgstr "E257: cstag: tag nenalezen"
+
+#, c-format
+msgid "stat(%s) error: %d"
+msgstr "stat(%s) chyba: %d"
+
+#, c-format
+msgid "Added cscope database %s"
+msgstr "Pøidána cscope databáze %s"
+
+#, c-format
+msgid "%s is not a directory or a valid cscope database"
+msgstr "%s není ani adresáøem ani správnou cscope databází"
+
+#, c-format
+msgid "error reading cscope connection %d"
+msgstr "chyba pøi ètení cscope spojení %d"
+
+msgid "unknown cscope search type"
+msgstr "neznámý typ cscope hledání"
+
+msgid "Could not create cscope pipes"
+msgstr "nelze vytvoøit cscope roury"
+
+msgid "cs_create_connection exec failed"
+msgstr "spuštìní cs_create_connection selhalo"
+
+msgid "cs_create_connection: fdopen for to_fp failed"
+msgstr "cs_create_connection: volání fdopen pro to_fp selhalo"
+
+msgid "cs_create_connection: fdopen for fr_fp failed"
+msgstr "cs_create_connection: volání fdopen pro fr_fp selhalo"
+
+msgid "no cscope connections"
+msgstr "žádná cscope spojení"
+
+#, c-format
+msgid "E259: no matches found for cscope query %s of %s"
+msgstr "E259: cscope hledání %s vzorku %s nenašlo žádnou shodu"
+
+msgid "cscope commands:\n"
+msgstr "pøíkazy cscope:\n"
+
+#, c-format
+msgid "%-5s: %-30s (Usage: %s)\n"
+msgstr "%-5s: %-30s (Použití: %s)\n"
+
+msgid "duplicate cscope database not added"
+msgstr "duplicitní cscope databáze nebyla pøidána"
+
+msgid "maximum number of cscope connections reached"
+msgstr "dosažen maximální poèet cscope spojení"
+
+msgid "E260: cscope connection not found"
+msgstr "E260: connection spojení nenalezeno"
+
+#, c-format
+msgid "E261: cscope connection %s not found"
+msgstr "E261: connection spojení %s nenalezeno"
+
+msgid "cscope connection closed"
+msgstr "closed spojení uzavøeno"
+
+#, c-format
+msgid "cscope connection %s closed\n"
+msgstr "cscope spojení %s uzavøeno\n"
+
+#. should not reach here
+msgid "fatal error in cs_manage_matches"
+msgstr "osudová chyba v cs_manage_matches"
+
+#, c-format
+msgid "E262: error reading cscope connection %d"
+msgstr "E262: pøi ètení cscope spojení %d"
+
+msgid "couldn't malloc\n"
+msgstr "volání malloc selhalo\n"
+
+#, c-format
+msgid "Cscope tag: %s\n"
+msgstr "Cscope tag: %s\n"
+
+msgid " # line"
+msgstr " # øádek"
+
+msgid "filename / context / line\n"
+msgstr "název souboru/ kontext/ øádek\n"
+
+msgid "All cscope databases reset"
+msgstr "Všechny cscope databáze resetovány"
+
+msgid "no cscope connections\n"
+msgstr "žádné cscope spojení\n"
+
+msgid " # pid database name prepend path\n"
+msgstr " # pid název databáze pøedpona cesty\n"
+
+#, c-format
+msgid "%2d %-5ld %-34s <none>\n"
+msgstr "%2d %-5ld %-34s <žádný>\n"
+
+msgid ""
+"E263: Sorry, this command is disabled, the Python library could not be "
+"loaded."
+msgstr ""
+"E263: Lituji, tento pøíkaz je deaktivován; knihovnu jazyka Python nelze "
+"nahrát."
+
+msgid "can't delete OutputObject attributes"
+msgstr "nelze smazat atributy OutputObject"
+
+msgid "softspace must be an integer"
+msgstr "softspace musí být kladné celé èíslo"
+
+msgid "invalid attribute"
+msgstr "chybný atribut"
+
+msgid "writelines() requires list of strings"
+msgstr "writelines() vyžaduje seznam øetìzcù"
+
+msgid "E264: Python: Error initialising I/O objects"
+msgstr "E264: Python: chyba pøi inicializaci I/O objektù"
+
+msgid "invalid expression"
+msgstr "Chybný výraz"
+
+msgid "expressions disabled at compile time"
+msgstr "podpora výrazù byla vypnuta pøi pøekladu programu"
+
+msgid "attempt to refer to deleted buffer"
+msgstr "pokus o odkaz na smazaný buffer"
+
+msgid "line number out of range"
+msgstr "èíslo øádku mimo rozsah"
+
+#, c-format
+msgid "<buffer object (deleted) at %8lX>"
+msgstr "<buffer objekt (smazán) na %8lX>"
+
+msgid "invalid mark name"
+msgstr "chybné jméno znaèky"
+
+msgid "no such buffer"
+msgstr "žádný takový buffer"
+
+msgid "attempt to refer to deleted window"
+msgstr "pokus o odkaz na smazané okno"
+
+msgid "readonly attribute"
+msgstr "atribut pouze_pro_ètení"
+
+msgid "cursor position outside buffer"
+msgstr "umístìní kurzoru mimo buffer"
+
+#, c-format
+msgid "<window object (deleted) at %.8lX>"
+msgstr "<objekt okna (smazán) na %.8lX>"
+
+#, c-format
+msgid "<window object (unknown) at %.8lX>"
+msgstr "<objekt okna (neznámý) na %.8lX>"
+
+#, c-format
+msgid "<window %d>"
+msgstr "<okno %d>"
+
+msgid "no such window"
+msgstr "žádné takové okno"
+
+msgid "cannot save undo information"
+msgstr "nelze uložit informace pro pøíkaz undo"
+
+msgid "cannot delete line"
+msgstr "nelze smazat øádek"
+
+msgid "cannot replace line"
+msgstr "nelze nahradit øádek"
+
+msgid "cannot insert line"
+msgstr "nelze vložit øádek"
+
+msgid "string cannot contain newlines"
+msgstr "øetìzec nesmí obsahovat znaky nového øádku"
+
+msgid ""
+"E266: Sorry, this command is disabled, the Ruby library could not be loaded."
+msgstr ""
+"E266: Lituji, ale tento pøíkaz je deaktivován; knihovnu jazyka Ruby nelze "
+"nahrát."
+
+#, c-format
+msgid "E273: unknown longjmp status %d"
+msgstr "E273: neznámý longjmp stav %d"
+
+msgid "Toggle implementation/definition"
+msgstr "Prohození implementace/definice"
+
+msgid "Show base class of"
+msgstr "Zobrazení base class z"
+
+msgid "Show overridden member function"
+msgstr "Zobrazení overridden member funkce"
+
+msgid "Retrieve from file"
+msgstr "Znovuzískáno ze souboru"
+
+msgid "Retrieve from project"
+msgstr "Znovuzískáno z projektu"
+
+msgid "Retrieve from all projects"
+msgstr "Znovzískáno ze všech projektù"
+
+msgid "Retrieve"
+msgstr "Znovuzískáno"
+
+msgid "Show source of"
+msgstr "Zobrazení zdroje"
+
+msgid "Find symbol"
+msgstr "Najít symbol"
+
+msgid "Browse class"
+msgstr "Prohlížet class"
+
+msgid "Show class in hierarchy"
+msgstr "Zobrazení class v hierarchii"
+
+msgid "Show class in restricted hierarchy"
+msgstr "Zobrazení class v restricted hierarchii"
+
+msgid "Xref refers to"
+msgstr "Xref odkazuje na"
+
+msgid "Xref referred by"
+msgstr "Xref odkazoval na"
+
+msgid "Xref has a"
+msgstr "Xref má"
+
+msgid "Xref used by"
+msgstr "Xref použit"
+
+msgid "Show docu of"
+msgstr "Zobrazení documentace"
+
+msgid "Generate docu for"
+msgstr "Generována dokumentace pro"
+
+msgid ""
+"Cannot connect to SNiFF+. Check environment (sniffemacs must be found in "
+"$PATH).\n"
+msgstr ""
+"Nelze se pøipojit k SNiFF+. Zkontrolujte promìnné (sniffemacs musí "
+"být)uvedena v $PATH.\n"
+
+msgid "E274: Sniff: Error during read. Disconnected"
+msgstr "E274: Sniff: Chyba pøi ètení. Odpojeno"
+
+msgid "SNiFF+ is currently "
+msgstr "SNiFF+ je právì "
+
+msgid "not "
+msgstr "ne "
+
+msgid "connected"
+msgstr "pøipojen"
+
+#, c-format
+msgid "E275: Unknown SNiFF+ request: %s"
+msgstr "E275: Neznámý požadavek SNiFF+: %s"
+
+msgid "E276: Error connecting to SNiFF+"
+msgstr "E276: Chybné pøipojení k SNiFF+"
+
+msgid "E278: SNiFF+ not connected"
+msgstr "E278: SNiFF+ nepøipojen"
+
+msgid "E279: Not a SNiFF+ buffer"
+msgstr "E279: Není SNiFF+ buffer"
+
+msgid "Sniff: Error during write. Disconnected"
+msgstr "Sniff: Chyba pøi zápisu. Odpojeno."
+
+msgid "invalid buffer number"
+msgstr "chybný název bufferu"
+
+msgid "not implemented yet"
+msgstr "není ještì podporováno"
+
+msgid "unknown option"
+msgstr "neznámá volba"
+
+#. ???
+msgid "cannot set line(s)"
+msgstr "nelze nastavit øádky"
+
+msgid "mark not set"
+msgstr "znaèka není nastavena"
+
+#, c-format
+msgid "row %d column %d"
+msgstr "øádek %d sloupec %d"
+
+msgid "cannot insert/append line"
+msgstr "nelze vložit/pøipojit øádek"
+
+msgid "unknown flag: "
+msgstr "neznámý pøíznak: "
+
+msgid "unknown vimOption"
+msgstr "neznámá vimOption"
+
+msgid "keyboard interrupt"
+msgstr "pøerušení z klávesnice"
+
+msgid "vim error"
+msgstr "chyba vim"
+
+msgid "cannot create buffer/window command: object is being deleted"
+msgstr "nelze vytvoøit pøíkaz bufferu/okna: objekt smazán"
+
+msgid ""
+"cannot register callback command: buffer/window is already being deleted"
+msgstr ""
+"nelze zaregistrovat pøíkaz zpìtného volání: buffer/okno již bylo smazáno"
+
+#. This should never happen. Famous last word?
+msgid ""
+"E280: TCL FATAL ERROR: reflist corrupt!? Please report this to "
+"vim-dev@vim.org"
+msgstr ""
+"E280: TCL FATAL ERROR: reflist poškozen!? Oznamte, prosím, tuto chybu na "
+"vim-dev@vim.org"
+
+msgid "cannot register callback command: buffer/window reference not found"
+msgstr ""
+"nelze zaregistrovat pøíkaz zpìtného volání: odkaz na buffer/okno nenalezen"
+
+msgid "Sorry, this command is disabled: the Tcl library could not be loaded."
+msgstr ""
+"Lituji, ale tento pøíkaz je deaktivován; knihovnu jazyka Tcl nelze nahrát."
+
+msgid ""
+"E281: TCL ERROR: exit code is not int!? Please report this to vim-dev@vim.org"
+msgstr ""
+"E281: TCL CHYBA: návratový kód není celé èíslo!? Oznamte, prosím, tuto chybu "
+"na vim-dev@vim.org"
+
+msgid "cannot get line"
+msgstr "nelze pøeèíst øádek"
+
+msgid "Unable to register a command server name"
+msgstr "Není možné zaznamenat jméno command serveru"
+
+#, c-format
+msgid "E247: no registered server named \"%s\""
+msgstr "E247: Neexistuje registrovaný server jménem \"%s\""
+
+msgid "E248: Failed to send command to the destination program"
+msgstr "E248: Selhalo zaslání pøíkazu urèenému programu"
+
+#, c-format
+msgid "Invalid server id used: %s"
+msgstr "Použit chybný id serveru: %s"
+
+msgid "E249: couldn't read VIM instance registry property"
+msgstr "E249: nelze èíst VIM instanci registry property"
+
+msgid "E251: VIM instance registry property is badly formed. Deleted!"
+msgstr ""
+"E251: VIM instance registry property byla špatnì vytvoøenaa byla smazána!"
+
+msgid "Unknown option"
+msgstr "Neznámá volba"
+
+msgid "Too many edit arguments"
+msgstr "Pøíliš mnoho edit argumentù"
+
+msgid "Argument missing after"
+msgstr "Chybí argument po"
+
+msgid "Garbage after option"
+msgstr "Chyby za volbou"
+
+msgid "Too many \"+command\" or \"-c command\" arguments"
+msgstr "Pøíliš mnoho \"+pøíkaz\" èi \"-c pøíkaz\" argumentù"
+
+msgid "Invalid argument for"
+msgstr "Chybný argument pro"
+
+msgid "This Vim was not compiled with the diff feature."
+msgstr "VIM nebyl pøeložen s volbou +diff"
+
+msgid "Attempt to open script file again: \""
+msgstr "Pokus o opìtovné otevøení skriptu: \""
+
+msgid "\"\n"
+msgstr "\"\n"
+
+msgid "Cannot open for reading: \""
+msgstr "Nelze otevøít pro zápis: \""
+
+msgid "Cannot open for script output: \""
+msgstr "Nelze otevøít pro výstup skriptu: \""
+
+#, c-format
+msgid "%d files to edit\n"
+msgstr "poèet souborù pro editaci: %d\n"
+
+msgid "Vim: Warning: Output is not to a terminal\n"
+msgstr "Vim: Varování: výstup nesmìøuje na terminál\n"
+
+msgid "Vim: Warning: Input is not from a terminal\n"
+msgstr "Vim: Varování: vstup nepochází z terminálu\n"
+
+#. just in case..
+msgid "pre-vimrc command line"
+msgstr "pre-vimrc pøíkazový øádek"
+
+#, c-format
+msgid "E282: Cannot read from \"%s\""
+msgstr "E282: Nelze èíst z \"%s\""
+
+msgid ""
+"\n"
+"More info with: \"vim -h\"\n"
+msgstr ""
+"\n"
+"Podrobnìjší informace získáte pomocí \"vim -h\"\n"
+
+msgid "[file ..] edit specified file(s)"
+msgstr "[SOUBOR] .. editovat SOUBOR(y)"
+
+msgid "- read text from stdin"
+msgstr "- èíst text ze standardního vstupu"
+
+msgid "-t tag edit file where tag is defined"
+msgstr "-t TAG editovat soubor na místì definice TAGU"
+
+msgid "-q [errorfile] edit file with first error"
+msgstr "-q [chybový soubor] editovat soubor na místì výskytu první chyby"
+
+msgid ""
+"\n"
+"\n"
+"Usage:"
+msgstr ""
+"\n"
+"\n"
+"použití:"
+
+msgid " vim [arguments] "
+msgstr "vim [pøepínaèe] "
+
+msgid ""
+"\n"
+" or:"
+msgstr ""
+"\n"
+" nebo"
+
+msgid ""
+"\n"
+"\n"
+"Arguments:\n"
+msgstr ""
+"\n"
+"\n"
+"Argumenty:\n"
+
+msgid "--\t\t\tOnly file names after this"
+msgstr "--\t\t\tMohou následovat pouze názvy souborù"
+
+msgid "-register\t\tRegister this gvim for OLE"
+msgstr "-register\t\tpøihlásit gvim na OLE"
+
+msgid "-unregister\t\tUnregister gvim for OLE"
+msgstr "-register\t\todhlásit gvim z OLE"
+
+msgid "-g\t\t\tRun using GUI (like \"gvim\")"
+msgstr "-g\t\t\tspustit v GUI režimu (stejné jako \"gvim\")"
+
+msgid "-f\t\t\tForeground: Don't fork when starting GUI"
+msgstr "-f\t\t\tPopøedí: pøi startu GUI se neoddìlí od shellu"
+
+msgid "-v\t\t\tVi mode (like \"vi\")"
+msgstr "-v\t\t\tVi mód (stejné jako \"vi\")"
+
+msgid "-e\t\t\tEx mode (like \"ex\")"
+msgstr "-v\t\t\tEx mód (stejné jako \"ex\")"
+
+msgid "-s\t\t\tSilent (batch) mode (only for \"ex\")"
+msgstr "-s\t\t\tTichý (dávkový) režim (pouze pro \"ex\")"
+
+msgid "-d\t\t\tDiff mode (like \"vimdiff\")"
+msgstr "-d\t\t\tDiff režim (stejné jako \"vimdiff\")"
+
+msgid "-y\t\t\tEasy mode (like \"evim\", modeless)"
+msgstr "-v\t\t\tSnadný režim (stejné jako \"evim\", žádné módy )"
+
+msgid "-R\t\t\tReadonly mode (like \"view\")"
+msgstr "-R\t\t\tRežim pouze_pro_ètení (jako \"view\")"
+
+msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
+msgstr "-Z\t\t\tOmezený režim (stejné jako \"rvim\")"
+
+msgid "-m\t\t\tModifications (writing files) not allowed"
+msgstr "-m\t\t\tZmìny (ukládání souborù) zakázány"
+
+msgid "-M\t\t\tModifications in text not allowed"
+msgstr "-M\t\t\tZmìny (ukládání souborù) zakázány"
+
+msgid "-b\t\t\tBinary mode"
+msgstr "-b\t\t\tBinární režim"
+
+msgid "-l\t\t\tLisp mode"
+msgstr "-l\t\t\tLisp režim"
+
+msgid "-C\t\t\tCompatible with Vi: 'compatible'"
+msgstr "-C\t\t\tKompatabilní s Vi: 'compatible'"
+
+msgid "-N\t\t\tNot fully Vi compatible: 'nocompatible'"
+msgstr "-N\t\t\tKompatibilita s Vi vypnuta: 'nocompatible'"
+
+msgid "-V[N]\t\tVerbose level"
+msgstr "-V[N]\t\tÚroveò výpisu hlášek"
+
+msgid "-D\t\t\tDebugging mode"
+msgstr "-D\t\t\tLadící režim"
+
+msgid "-n\t\t\tNo swap file, use memory only"
+msgstr "-n\t\t\tNebude vytváøet odkládací soubor, bude používat pouze pamì"
+
+msgid "-r\t\t\tList swap files and exit"
+msgstr "-r\t\t\tVypíše seznam odkládacích souborù a skonèí"
+
+msgid "-r (with file name)\tRecover crashed session"
+msgstr "-r název souboru\tObnoví pøerušené sezení"
+
+msgid "-L\t\t\tSame as -r"
+msgstr "-L\t\t\tStejné jako -r"
+
+msgid "-f\t\t\tDon't use newcli to open window"
+msgstr "-f\t\t\tNebude používat newcli pro otevøení okna"
+
+msgid "-dev <device>\t\tUse <device> for I/O"
+msgstr "-dev <zaøízení>\t\tPoužít <zaøízení> pro I/O"
+
+msgid "-H\t\t\tstart in Hebrew mode"
+msgstr "-H\t\t\tnastartuje v hebrejském režimu"
+
+msgid "-F\t\t\tstart in Farsi mode"
+msgstr "-F\t\t\tnastartuje ve Farsi režimu"
+
+msgid "-T <terminal>\tSet terminal type to <terminal>"
+msgstr "-T <terminál>\tNastaví typ terminálu na <terminál>"
+
+msgid "-u <vimrc>\t\tUse <vimrc> instead of any .vimrc"
+msgstr "-u <vimrc>\t\tPoužije <vimrc> místo jakéhokoliv .vimrc"
+
+msgid "-U <gvimrc>\t\tUse <gvimrc> instead of any .gvimrc"
+msgstr "-U <gvimrc>\t\tPoužije <gvimrc> místo jakéhokoliv .gvimrc"
+
+msgid "--noplugin\t\tDon't load plugin scripts"
+msgstr "--noplugin\t\tNenahraje 'plugin' skripty"
+
+msgid "-o[N]\t\tOpen N windows (default: one for each file)"
+msgstr "-o[N]\t\tOtevøe N oken (implicitnì jedno pro každý soubor)"
+
+msgid "-O[N]\t\tlike -o but split vertically"
+msgstr "-O[N]\t\tJako -o but split vertically"
+
+msgid "+\t\t\tStart at end of file"
+msgstr "+\t\t\tNastaví kurzor na konec souboru"
+
+msgid "+<lnum>\t\tStart at line <lnum>"
+msgstr "+<øádek>\t\tNastaví kurzor na <øádek>"
+
+msgid "--cmd <command>\tExecute <command> before loading any vimrc file"
+msgstr "--cmd <pøíkaz>\tPo nahrání prvního souboru vykoná <pøíkaz>"
+
+msgid "-c <command>\t\tExecute <command> after loading the first file"
+msgstr "-c <pøíkaz>\t\tPo nahrání prvního souboru vykoná <pøíkaz>"
+
+msgid "-S <session>\t\tSource file <session> after loading the first file"
+msgstr ""
+"-S <sezení>\t\tPo nahrání prvního souboru vykoná pøíkazy v souboru <sezení>"
+
+msgid "-s <scriptin>\tRead Normal mode commands from file <scriptin>"
+msgstr "-s <skript>\t\tNaète pøíkazy normálního módu ze <skriptu>"
+
+msgid "-w <scriptout>\tAppend all typed commands to file <scriptout>"
+msgstr "-w <skript>\t\tPøipojí všechny napsané pøíkazy do souboru <skript>"
+
+msgid "-W <scriptout>\tWrite all typed commands to file <scriptout>"
+msgstr "-W <skript>\t\tUloží všechny napsané pøíkazy do souboru <skript>"
+
+msgid "-x\t\t\tEdit encrypted files"
+msgstr "-x\t\t\tEditace zašifrovaných souborù"
+
+msgid "-display <display>\tConnect vim to this particular X-server"
+msgstr "-display <display>\tSpustí vim na daný X-server"
+
+msgid "-X\t\t\tDo not connect to X server"
+msgstr "-X\t\t\tNepøipojí se k X serveru"
+
+msgid "--socketid <xid>\tOpen Vim inside another GTK widget"
+msgstr "--socketid <xid>\tOtevøe Vim uvnitø jiného GTK widgetu"
+
+msgid "--remote <files>\tEdit <files> in a Vim server and exit"
+msgstr "--remote <soubory>\tEdituje <soubory> na Vim serveru a skonèí"
+
+msgid ""
+"--remote-wait <files> As --remote but wait for files to have been edited"
+msgstr ""
+"--remote-wait <soubory> Jako --remote, ale èeká na soubory k editaci"
+
+msgid "--remote-send <keys>\tSend <keys> to a Vim server and exit"
+msgstr "--remote-send <klávesy>\tPøedá <klávesy> Vim serveru a skonèí"
+
+msgid "--remote-expr <expr>\tEvaluate <expr> in a Vim server and print result"
+msgstr "--remote-expr <výraz>\tProvede <výraz> na serveru a zobrazí výsledek"
+
+msgid "--serverlist\t\tList available Vim server names and exit"
+msgstr "--serverlist\t\tVypíše seznam dostupných Vim serverù a skonèí"
+
+msgid "--servername <name>\tSend to/become the Vim server <name>"
+msgstr ""
+"--servername <jméno>\tZašle serveru <jméno>/stane se Vim serverem <jméno>"
+
+msgid "-i <viminfo>\t\tUse <viminfo> instead of .viminfo"
+msgstr "-i <viminfo>\t\tPoužije <viminfo> místo jakéhokoliv .viminfo"
+
+msgid "-h\t\t\tprint Help (this message) and exit"
+msgstr "-h\t\t\tVypíše tuto nápovìdu a skonèí"
+
+msgid "--version\t\tprint version information and exit"
+msgstr "--version\t\tvypíše informace o verzi a skonèí"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Motif version):\n"
+msgstr ""
+"\n"
+"Pøepínaèe pro gvim (Motif verzi):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Athena version):\n"
+msgstr ""
+"\n"
+"Pøepínaèe pro gvim (Athena verzi):\n"
+
+msgid "-display <display>\tRun vim on <display>"
+msgstr "-display <display>\tSpustí vim na <display>"
+
+msgid "-iconic\t\tStart vim iconified"
+msgstr "-iconic\t\tSpustí vim minimalizované"
+
+msgid "-name <name>\t\tUse resource as if vim was <name>"
+msgstr "-name <název>\t\tPoužije resource jako by vim mìl <název>"
+
+msgid "\t\t\t (Unimplemented)\n"
+msgstr "\t\t\t (není implementováno)\n"
+
+msgid "-background <color>\tUse <color> for the background (also: -bg)"
+msgstr "-background <barva>\tNastaví <barvu> pozadí (také -bg)"
+
+msgid "-foreground <color>\tUse <color> for normal text (also: -fg)"
+msgstr "-foreground <barva>\tNastaví <barvu> popøedí (také -fg)"
+
+msgid "-font <font>\t\tUse <font> for normal text (also: -fn)"
+msgstr "-font <písmo>\t\tNastaví <písmo> normálního textu (také -fn)"
+
+msgid "-boldfont <font>\tUse <font> for bold text"
+msgstr "-boldfont <písmo>\tNastaví <písmo> pro zvýraznìný text"
+
+msgid "-italicfont <font>\tUse <font> for italic text"
+msgstr "-italicfont <písmo>\tNastaví <písmo> pro kurzívu"
+
+msgid "-geometry <geom>\tUse <geom> for initial geometry (also: -geom)"
+msgstr "-geometry <geometrie>\tNastaví <geometrii> (také -geom)"
+
+msgid "-borderwidth <width>\tUse a border width of <width> (also: -bw)"
+msgstr "-borderwidth <šíøka>\tNastaví <šíøku> okrajù (také -bw)"
+
+msgid "-scrollbarwidth <width> Use a scrollbar width of <width> (also: -sw)"
+msgstr "-scrollbarwidth <šíøku> Nastaví <šíøku> posunovací lišty (také: -sw)"
+
+msgid "-menuheight <height>\tUse a menu bar height of <height> (also: -mh)"
+msgstr "-menuheight <výška>\tNastaví <výšku> nabídky (také -mh)"
+
+msgid "-reverse\t\tUse reverse video (also: -rv)"
+msgstr "-reverse\t\tPoužije reverzní barvy (také -rv)"
+
+msgid "+reverse\t\tDon't use reverse video (also: +rv)"
+msgstr "+reverse\t\tNepoužije reverzní barvy (také +rv)"
+
+msgid "-xrm <resource>\tSet the specified resource"
+msgstr "-xrm <resource>\tNastaví zadaný <resource>"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (RISC OS version):\n"
+msgstr ""
+"\n"
+"Pøepínaèe pro gvim (RISC OS verzi):\n"
+
+msgid "--columns <number>\tInitial width of window in columns"
+msgstr "--columns <poèet>\t<poèet> sloupcù na okno"
+
+msgid "--rows <number>\tInitial height of window in rows"
+msgstr "--rows <poèet>\t<poèet> øádkù na okno"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (GTK+ version):\n"
+msgstr ""
+"\n"
+"Pøepínaèe pro gvim (GTK+ verzi):\n"
+
+msgid "-display <display>\tRun vim on <display> (also: --display)"
+msgstr "-display <display>\tSpustí vim na <display> (také --display)"
+
+msgid "--help\t\tShow Gnome arguments"
+msgstr "--help\t\tVypíše Gnome pøepínaèe"
+
+#. Failed to send, abort.
+msgid ""
+"\n"
+"Send failed.\n"
+msgstr ""
+"\n"
+"Pøedání výrazu selhalo.\n"
+
+#. Let vim start normally.
+msgid ""
+"\n"
+"Send failed. Trying to execute locally\n"
+msgstr ""
+"\n"
+"Pøedání selhalo. Zkouším provést lokálnì\n"
+
+#, c-format
+msgid "%d of %d edited"
+msgstr "%d z %d editováno"
+
+msgid "Send expression failed.\n"
+msgstr "Pøedání výrazu selhalo.\n"
+
+msgid "No marks set"
+msgstr "Nejsou nastaveny žádné znaèky"
+
+#, c-format
+msgid "E283: No marks matching \"%s\""
+msgstr "E283: \"%s\" nevyhovují žádné znaèky"
+
+#. Highlight title
+msgid ""
+"\n"
+"mark line col file/text"
+msgstr ""
+"\n"
+"znaèka øádek sloupec soubor/text"
+
+#. Highlight title
+msgid ""
+"\n"
+" jump line col file/text"
+msgstr ""
+"\n"
+" skok øádek sloupec soubor/text"
+
+msgid ""
+"\n"
+"# File marks:\n"
+msgstr ""
+"\n"
+"# Souborové znaèky:\n"
+
+#. Write the jumplist with -'
+msgid ""
+"\n"
+"# Jumplist (newest first):\n"
+msgstr ""
+"\n"
+"# Seznam skokù (poèínaje nejnovìjší položkou):\n"
+
+msgid ""
+"\n"
+"# History of marks within files (newest to oldest):\n"
+msgstr ""
+"\n"
+"# Historie znaèek v souborech (poèínaje nejnovìjší položkou):\n"
+
+msgid "Missing '>'"
+msgstr "Chybí '>'"
+
+msgid "Not a valid codepage"
+msgstr "Chybná kódová stránka"
+
+msgid "E284: Cannot set IC values"
+msgstr "E284: Nelze nastavit IC hodnoty"
+
+msgid "E285: Failed to create input context"
+msgstr "E285: Nepodaøilo se vytvoøit vstupní kontext"
+
+msgid "E286: Failed to open input method"
+msgstr "E286: Nepodaøilo se otevøít vstupní metodu"
+
+msgid "E287: Warning: Could not set destroy callback to IM"
+msgstr "E287: Varování: likvidaèní zpìtné volání nelze nastavit na IM"
+
+msgid "E288: input method doesn't support any style"
+msgstr "E288: vstupní metoda nepodporuje žádný styl"
+
+msgid "E289: input method doesn't support my preedit type"
+msgstr "E289: vstupní metoda nepodporuje mùj 'preedit' typ"
+
+msgid "E290: over-the-spot style requires fontset"
+msgstr "E290: Nadbodový styl vyžaduje fontset"
+
+msgid "E291: Your GTK+ is older than 1.2.3. Status area disabled"
+msgstr "E291: Máte GTK+ verze starší než 1.2.3. Stavová plocha vypnuta."
+
+msgid "E292: Input Method Server is not running"
+msgstr "E292: Server vstupních metod nebìží"
+
+msgid "E293: block was not locked"
+msgstr "E293: blok nebyl zamknut"
+
+msgid "E294: Seek error in swap file read"
+msgstr "E294: Chyba posunu ukazovátka pøi ètení odkládacího souboru"
+
+msgid "E295: Read error in swap file"
+msgstr "E295: Chyba pøi ètení odkládacího souboru"
+
+msgid "E296: Seek error in swap file write"
+msgstr "E296: Chyba posunu ukazovátka pøi ukládání do odkládacího souboru"
+
+msgid "E297: Write error in swap file"
+msgstr "E297: Chyba pøi ukládání do odkládacího souboru"
+
+msgid "E300: Swap file already exists (symlink attack?)"
+msgstr ""
+"E300: Odkládací soubor již existuje! (Nìkdo hackujepøes nastražený symlink?)"
+
+msgid "E298: Didn't get block nr 0?"
+msgstr "E298: Nelze získat blok 0?"
+
+msgid "E298: Didn't get block nr 1?"
+msgstr "E298: Nelze získat blok 1?"
+
+msgid "E298: Didn't get block nr 2?"
+msgstr "E298: nelze získat blok 2?"
+
+#. could not (re)open the swap file, what can we do????
+msgid "E301: Oops, lost the swap file!!!"
+msgstr "E301: Jéje, odkládací soubor byl ztracen!!!"
+
+msgid "E302: Could not rename swap file"
+msgstr "E302: Nelze pøejmenovat odkládací soubor"
+
+#, c-format
+msgid "E303: Unable to open swap file for \"%s\", recovery impossible"
+msgstr "E303: Nelze otevøít odkládací soubor pro \"%s\""
+
+msgid "E304: ml_timestamp: Didn't get block 0??"
+msgstr "E304: ml_timestamp: nelze získat blok 0??"
+
+#, c-format
+msgid "E305: No swap file found for %s"
+msgstr "E305: Odkládací soubor pro %s nebyl nalezen"
+
+msgid "Enter number of swap file to use (0 to quit): "
+msgstr ""
+"Zadejte èíslo odkládacího souboru, který se má použít (0 pro ukonèení): "
+
+#, c-format
+msgid "E306: Cannot open %s"
+msgstr "E306: Nelze otevøít %s"
+
+msgid "Unable to read block 0 from "
+msgstr "Nelze èíst blok 0 z "
+
+msgid ""
+"\n"
+"Maybe no changes were made or Vim did not update the swap file."
+msgstr ""
+"\n"
+"Možná nedošlo k žádným zmìnám, nebo Vim neaktualizoval odkládací soubor."
+
+msgid " cannot be used with this version of Vim.\n"
+msgstr " nelze použít s touto verzí Vim.\n"
+
+msgid "Use Vim version 3.0.\n"
+msgstr "Použijte Vim verze 3.0.\n"
+
+#, c-format
+msgid "E307: %s does not look like a Vim swap file"
+msgstr "E307: %s se nezdá být odkládacím souborem Vim"
+
+msgid " cannot be used on this computer.\n"
+msgstr " nelze použít na tomto poèítaèi.\n"
+
+msgid "The file was created on "
+msgstr "Soubor byl vytvoøen "
+
+msgid ""
+",\n"
+"or the file has been damaged."
+msgstr ""
+",\n"
+"nebo byl soubor poškozen."
+
+#, c-format
+msgid "Using swap file \"%s\""
+msgstr "Používám odkládací soubor \"%s\""
+
+#, c-format
+msgid "Original file \"%s\""
+msgstr "Pùvodní soubor \"%s\""
+
+msgid "E308: Warning: Original file may have been changed"
+msgstr "E308: Varování: Pùvodní soubor mohl být zmìnìn"
+
+#, c-format
+msgid "E309: Unable to read block 1 from %s"
+msgstr "E309: Nelze èíst blok 1 z %s"
+
+msgid "???MANY LINES MISSING"
+msgstr "???CHYBÍ MNOHO ØÁDKÙ"
+
+msgid "???LINE COUNT WRONG"
+msgstr "???CHYBNÝ POÈET ØÁDKÙ"
+
+msgid "???EMPTY BLOCK"
+msgstr "???PRÁZDNÝ BLOK"
+
+msgid "???LINES MISSING"
+msgstr "???CHYBÌJÍCÍ ØÁDKY"
+
+#, c-format
+msgid "E310: Block 1 ID wrong (%s not a .swp file?)"
+msgstr "E310: ID bloku 1 je chybné (je %s odkládacím souborem?)"
+
+msgid "???BLOCK MISSING"
+msgstr "???CHYBÍ BLOK"
+
+msgid "??? from here until ???END lines may be messed up"
+msgstr "od ??? po ???END mohou být øádky pomíchané"
+
+msgid "??? from here until ???END lines may have been inserted/deleted"
+msgstr "od ??? po ???END mohou být vložené/smazané øádky"
+
+msgid "???END"
+msgstr "???KONEC"
+
+msgid "E311: Recovery Interrupted"
+msgstr "E311: Obnova pøerušena"
+
+msgid ""
+"E312: Errors detected while recovering; look for lines starting with ???"
+msgstr ""
+"E312: V prùbìhu obnovy došlo k chybám; zkontrolujte øádky zaèínající na ???"
+
+msgid "Recovery completed. You should check if everything is OK."
+msgstr "Obnova dokonèena. Zkontrolujte, zda je vše v poøádku."
+
+msgid ""
+"\n"
+"(You might want to write out this file under another name\n"
+msgstr ""
+"\n"
+"(Zvažte uložení tohoto souboru pod jiným názvem\n"
+
+msgid "and run diff with the original file to check for changes)\n"
+msgstr "a kontrolu zmìn pomocí programu diff.)\n"
+
+#. use msg() to start the scrolling properly
+msgid "Swap files found:"
+msgstr "Nalezené odkládací soubory:"
+
+msgid " In current directory:\n"
+msgstr " V aktuálním adresáøi:\n"
+
+msgid " Using specified name:\n"
+msgstr " Se zadaným názvem:\n"
+
+msgid " In directory "
+msgstr " V adresáøi "
+
+msgid " -- none --\n"
+msgstr " -- žádné --\n"
+
+msgid " owned by: "
+msgstr " vlastník: "
+
+msgid " dated: "
+msgstr " datum vytvoøení: "
+
+msgid " dated: "
+msgstr " datum vytvoøení: "
+
+msgid " [from Vim version 3.0]"
+msgstr " [od Vim verze 3.0]"
+
+msgid " [does not look like a Vim swap file]"
+msgstr " [nevypadá jako odkládací soubor Vim]"
+
+msgid " file name: "
+msgstr " název souboru: "
+
+msgid ""
+"\n"
+" modified: "
+msgstr ""
+"\n"
+" datum zmìny: "
+
+msgid "YES"
+msgstr "ANO"
+
+msgid "no"
+msgstr "ne"
+
+msgid ""
+"\n"
+" user name: "
+msgstr ""
+"\n"
+" uživatelské jméno: "
+
+msgid " host name: "
+msgstr " název poèítaèe: "
+
+msgid ""
+"\n"
+" host name: "
+msgstr ""
+"\n"
+" název poèítaèe: "
+
+msgid ""
+"\n"
+" process ID: "
+msgstr ""
+"\n"
+" ID procesu : "
+
+msgid " (still running)"
+msgstr " (stále aktivní)"
+
+msgid ""
+"\n"
+" [not usable with this version of Vim]"
+msgstr ""
+"\n"
+" [nepoužitelné s touto verzí Vim]"
+
+msgid ""
+"\n"
+" [not usable on this computer]"
+msgstr ""
+"\n"
+" [nepoužitelné na tomto poèítaèi]"
+
+msgid " [cannot be read]"
+msgstr " [nelze pøeèíst]"
+
+msgid " [cannot be opened]"
+msgstr " [nelze otevøít]"
+
+msgid "E313: Cannot preserve, there is no swap file"
+msgstr "E313: Nelze zachovat - odkládací soubor neexistuje."
+
+msgid "File preserved"
+msgstr "Soubor zachován"
+
+msgid "E314: Preserve failed"
+msgstr "E314: Uchování se nezdaøilo"
+
+#, c-format
+msgid "E315: ml_get: invalid lnum: %ld"
+msgstr "E315: ml_get: chybné èíslo øádku: %ld"
+
+#, c-format
+msgid "E316: ml_get: cannot find line %ld"
+msgstr "E316: ml_get: nelze nalézt øádek %ld"
+
+msgid "E317: pointer block id wrong 3"
+msgstr "E317: chybné id ukazatele na blok 3"
+
+msgid "stack_idx should be 0"
+msgstr "stack_idx by mìlo mít hodnotu 3"
+
+msgid "E318: Updated too many blocks?"
+msgstr "E318: Aktualizováno pøíliš mnoho blokù?"
+
+msgid "E317: pointer block id wrong 4"
+msgstr "E317: chybné id ukazatele na blok 4"
+
+msgid "deleted block 1?"
+msgstr "smazán blok 1?"
+
+#, c-format
+msgid "E320: Cannot find line %ld"
+msgstr "E320: Nelze nalézt øádek %ld"
+
+msgid "E317: pointer block id wrong"
+msgstr "E317: chybné id ukazatele na blok"
+
+msgid "pe_line_count is zero"
+msgstr "pe_line_count má nulovou hodnotu"
+
+#, c-format
+msgid "E322: line number out of range: %ld past the end"
+msgstr "E322: poèet øádkù mimo rozsah: %ld > celkový poèet øádkù"
+
+#, c-format
+msgid "E323: line count wrong in block %ld"
+msgstr "E323: chybný poèet øádkù v bloku %ld"
+
+msgid "Stack size increases"
+msgstr "Nárùst velikosti zásobníku"
+
+msgid "E317: pointer block id wrong 2"
+msgstr "E317: chybné id ukazatele na blok 2"
+
+msgid "E325: ATTENTION"
+msgstr "E325: POZOR"
+
+msgid ""
+"\n"
+"Found a swap file by the name \""
+msgstr ""
+"\n"
+"Nalezen odkládací soubor se jménem \""
+
+msgid "While opening file \""
+msgstr "Pøi otevírání souboru\""
+
+msgid " NEWER than swap file!\n"
+msgstr " NOVÌJŠÍ než odkládací soubor!\n"
+
+#. Some of these messages are long to allow translation to
+#. * other languages.
+msgid ""
+"\n"
+"(1) Another program may be editing the same file.\n"
+" If this is the case, be careful not to end up with two\n"
+" different instances of the same file when making changes.\n"
+msgstr ""
+"\n"
+"(1) Soubor mùže být editován jiným programem.\n"
+" Je-li tomu tak, pak si dejte pozor, aby jste po uložení zmìn\n"
+" nemìli dvì rùzné verze téhož souboru.\n"
+
+msgid " Quit, or continue with caution.\n"
+msgstr " Ukonèete program, nebo opatrnì pokraèujte v editaci.\n"
+
+msgid ""
+"\n"
+"(2) An edit session for this file crashed.\n"
+msgstr ""
+"\n"
+"(2) Editace tohoto souboru byla pøerušena neèekaným ukonèením programu.\n"
+
+msgid " If this is the case, use \":recover\" or \"vim -r "
+msgstr " Je-li tomu tak, pak použijte \":recover\" èi \"vim -r "
+
+msgid ""
+"\"\n"
+" to recover the changes (see \":help recovery\").\n"
+msgstr ""
+"\"\n"
+" pro odstranìní zmìn (viz \":help recovery)\".\n"
+
+msgid " If you did this already, delete the swap file \""
+msgstr " Pokud jste tak již uèinil, tak smažte odkládací soubor \""
+
+msgid ""
+"\"\n"
+" to avoid this message.\n"
+msgstr ""
+"\"\n"
+" a tato zpráva se již nebude objevovat.\n"
+
+msgid "Swap file \""
+msgstr "Odkládací soubor \""
+
+msgid "\" already exists!"
+msgstr "\" již existuje!"
+
+msgid "VIM - ATTENTION"
+msgstr "VIM - POZOR"
+
+msgid "Swap file already exists!"
+msgstr "Odkládací soubor již existuje!"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Quit"
+msgstr ""
+"&Otevøít pouze pro ètení\n"
+"&Pokraèovat v editaci\n"
+"O&bnovit soubor\n"
+"&Konec"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Quit\n"
+"&Delete it"
+msgstr ""
+"&Otevøít pouze pro ètení\n"
+"&Pokraèovat v editaci\n"
+"O&bnovit soubor\n"
+"&Konec\n"
+"&Smazat"
+
+msgid "E326: Too many swap files found"
+msgstr "E326: Pøíliš mnoho odkládacích souborù"
+
+msgid "E327: Part of menu-item path is not sub-menu"
+msgstr "E327: Èásti cesty k pøedmìtu nabídky není podnabídkou"
+
+msgid "E328: Menu only exists in another mode"
+msgstr "E328: Nabídka existuje pouze v jiném módu"
+
+msgid "E329: No menu of that name"
+msgstr "E329: Nabídka tohoto jména neexistuje"
+
+msgid "E330: Menu path must not lead to a sub-menu"
+msgstr "E330: Cesta nabídkou nesmí vést do podnabídky"
+
+msgid "E331: Must not add menu items directly to menu bar"
+msgstr "E331: Položky nabídky nelze pøidávat pøímo na lištu"
+
+msgid "E332: Separator cannot be part of a menu path"
+msgstr "E332: Oddìlovaè nesmí být èástí cesty nabídkou"
+
+#. Now we have found the matching menu, and we list the mappings
+#. Highlight title
+msgid ""
+"\n"
+"--- Menus ---"
+msgstr ""
+"\n"
+"--- Nabídky ---"
+
+msgid "Tear off this menu"
+msgstr "Odtrhnout tuto nabídku"
+
+msgid "E333: Menu path must lead to a menu item"
+msgstr "E333: Cesta nabídkou musí vést k položce nabídky"
+
+#, c-format
+msgid "E334: Menu not found: %s"
+msgstr "E334: Vzor nenalezen: %s"
+
+#, c-format
+msgid "E335: Menu not defined for %s mode"
+msgstr "E335: V %s módu není nabídka definována"
+
+msgid "E336: Menu path must lead to a sub-menu"
+msgstr "E336: Cesta nabídkou musí vést do podnabídky"
+
+msgid "E337: Menu not found - check menu names"
+msgstr "E337: Nabídka nenalezena - zkontrolujte názvy nabídek"
+
+#, c-format
+msgid "Error detected while processing %s:"
+msgstr "Chyba pøi zpracování %s:"
+
+#, c-format
+msgid "line %4ld:"
+msgstr "øádek %4ld:"
+
+msgid "[string too long]"
+msgstr "[pøíliš dlouhý øetìzec]"
+
+msgid "Messages maintainer: Bram Moolenaar <Bram@vim.org>"
+msgstr "Správce zpráv: Bram Moolenaar <Bram@vim.org>"
+
+msgid "Interrupt: "
+msgstr "Pøerušení: "
+
+msgid "Hit ENTER to continue"
+msgstr "pokraèování stiskem ENTER"
+
+msgid "Hit ENTER or type command to continue"
+msgstr "Pro pokraèování stisknìte ENTER nebo zadejte pøíkaz"
+
+msgid "-- More --"
+msgstr "-- Pokraèování --"
+
+msgid " (RET/BS: line, SPACE/b: page, d/u: half page, q: quit)"
+msgstr " (RET/BS: øádek, MEZERNÍK/b: stránka, d/u: 0.5 stránky, q: konec)"
+
+msgid " (RET: line, SPACE: page, d: half page, q: quit)"
+msgstr " (RET: øádek, MEZERNÍK: stránka, d: 0.5 stránky, q: konec)"
+
+msgid "Question"
+msgstr "Otázka"
+
+msgid ""
+"&Yes\n"
+"&No"
+msgstr ""
+"&Ano\n"
+"&Ne"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"&Cancel"
+msgstr ""
+"&Ano\n"
+"&Ne\n"
+"&Zrušit"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"Save &All\n"
+"&Discard All\n"
+"&Cancel"
+msgstr ""
+"&Ano\n"
+"&Ne\n"
+"&Uložit vše\n"
+"Zahodit &vše\n"
+"&Zrušit"
+
+msgid "Save File dialog"
+msgstr "Dialog pro ukládání souborù"
+
+msgid "Open File dialog"
+msgstr "Dialog pro otevírání souborù"
+
+#. TODO: non-GUI file selector here
+msgid "E338: Sorry, no file browser in console mode"
+msgstr "E338: Lituji, ale konzolová verze nepodporuje prohlížeè souborù"
+
+msgid "W10: Warning: Changing a readonly file"
+msgstr "W10: wc1: mìním soubor pouze_pro_ètení"
+
+msgid "1 more line"
+msgstr "poèet nových øádkù: 1"
+
+msgid "1 line less"
+msgstr "poèet smazaných øádkù: 1"
+
+#, c-format
+msgid "%ld more lines"
+msgstr "poèet nových øádkù: %ld"
+
+#, c-format
+msgid "%ld fewer lines"
+msgstr "poèet smazaných øádkù: %ld"
+
+msgid " (Interrupted)"
+msgstr "(Pøerušeno)"
+
+msgid "Vim: preserving files...\n"
+msgstr "Vim: zachovávám soubory...\n"
+
+#. close all memfiles, without deleting
+msgid "Vim: Finished.\n"
+msgstr "Vim: ukonèen\n"
+
+msgid "ERROR: "
+msgstr "CHYBA: "
+
+#, c-format
+msgid ""
+"\n"
+"[bytes] total alloc-freed %lu-%lu, in use %lu, peak use %lu\n"
+msgstr ""
+"\n"
+"[bajtù] celkem uvolnìno-alokováno %lu-%lu, využito %lu, maximální využití "
+"%lu\n"
+
+#, c-format
+msgid ""
+"[calls] total re/malloc()'s %lu, total free()'s %lu\n"
+"\n"
+msgstr ""
+"[volání] celkem re/malloc(): %lu, celkem free() %lu\n"
+"\n"
+
+msgid "E340: Line is becoming too long"
+msgstr "E340: Øádek se stává pøíliš dlouhým"
+
+#, c-format
+msgid "E341: Internal error: lalloc(%ld, )"
+msgstr "E341: Vnitøní chyba: lalloc(%ld, )"
+
+#, c-format
+msgid "E342: Out of memory! (allocating %lu bytes)"
+msgstr "E342: Nedostatek pamìti! (potøebuji alokovat bajtù: %lu)"
+
+#, c-format
+msgid "Calling shell to execute: \"%s\""
+msgstr "Spouštím pøíkaz \"%s\" pomocí shellu"
+
+msgid "Missing colon"
+msgstr "Chybí dvojteèka"
+
+msgid "Illegal mode"
+msgstr "nepøípustný mód"
+
+msgid "Illegal mouseshape"
+msgstr "Chybný tvar myši"
+
+msgid "digit expected"
+msgstr "oèekávána èíslice"
+
+msgid "Illegal percentage"
+msgstr "nepøípustné procento"
+
+msgid "Enter encryption key: "
+msgstr "Zadejte šifrovací klíè: "
+
+msgid "Enter same key again: "
+msgstr "Zadejte ještì jednou tentýž klíè:"
+
+msgid "Keys don't match!"
+msgstr "Klíèe se neshodují"
+
+#, c-format
+msgid ""
+"E343: Invalid path: '**[number]' must be at the end of the path or be "
+"followed by '%s'."
+msgstr ""
+"E343: Chybná cesta: '**[èíslo] musí být buï na konci cesty, nebo musí být "
+"následováno'%s. Viz :help path."
+
+#, c-format
+msgid "E344: Can't find directory \"%s\" in cdpath"
+msgstr "E344: Adresáø \"%s\" nelze v cdpath nalézt"
+
+#, c-format
+msgid "E345: Can't find file \"%s\" in path"
+msgstr "E345: Soubor \"%s\" nelze v path nalézt"
+
+#, c-format
+msgid "E346: No more directory \"%s\" found in cdpath"
+msgstr "E346: Žádný další adresáø \"%s\" nebyl v cdpath nalezen"
+
+#, c-format
+msgid "E347: No more file \"%s\" found in path"
+msgstr "E347: Žádný další soubor \"%s\" nebyl v cestì nalezen"
+
+msgid "Illegal component"
+msgstr "nepøípustná souèást"
+
+msgid "Warning: terminal cannot highlight"
+msgstr "Varování: terminál nepodporuje zvýrazòování"
+
+msgid "E348: No string under cursor"
+msgstr "E348: pod kurzorem není žádný øetìzec"
+
+msgid "E349: No identifier under cursor"
+msgstr "E349: pod kurzorem není žádný identifikátor"
+
+msgid "E352: Cannot erase folds with current 'foldmethod'"
+msgstr "E352: pomocí aktuální 'foldmethod' nelze mazat záhyby"
+
+#, c-format
+msgid "1 line %sed 1 time"
+msgstr "poèet øádkù posunutých jednou pomocí %s : 1"
+
+#, c-format
+msgid "1 line %sed %d times"
+msgstr "Poèet øádkù posunutých pomocí %s %d-krát : 1"
+
+#, c-format
+msgid "%ld lines %sed 1 time"
+msgstr "Poèet øádkù: %ld (posunutých jednou pomocí %s)"
+
+#, c-format
+msgid "%ld lines %sed %d times"
+msgstr "Poèet øádkù: %ld (posunutých pomocí %s %d-krát)"
+
+#, c-format
+msgid "%ld lines to indent... "
+msgstr "poèet øádkù k odsazení: %ld"
+
+msgid "1 line indented "
+msgstr "poèet øádkù k odsazení: 1"
+
+#, c-format
+msgid "%ld lines indented "
+msgstr "poèet odsazených øádkù: %ld"
+
+#. must display the prompt
+msgid "cannot yank; delete anyway"
+msgstr "nelze kopírovat; pøesto smazáno"
+
+msgid "1 line changed"
+msgstr "poèet øádek se zmìnìnou velikostí písmen: 1"
+
+#, c-format
+msgid "%ld lines changed"
+msgstr "poèet øádek se zmìnìnou velikostí písmen: %ld"
+
+#, c-format
+msgid "freeing %ld lines"
+msgstr "poèet uvolòovaných øádkù: %ld"
+
+msgid "1 line yanked"
+msgstr "poèet zkopírovaných øádkù: 1"
+
+#, c-format
+msgid "%ld lines yanked"
+msgstr "poèet zkopírovaných øádkù: %ld"
+
+#, c-format
+msgid "E353: Nothing in register %s"
+msgstr "E353: Registr %s je prázdný"
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Registers ---"
+msgstr ""
+"\n"
+"--- Registry ---"
+
+msgid "Illegal register name"
+msgstr "nepøípustný název registru"
+
+msgid ""
+"\n"
+"# Registers:\n"
+msgstr ""
+"\n"
+"# Registry:\n"
+
+#, c-format
+msgid "Unknown register type %d"
+msgstr "%d není známým typem registru"
+
+#, c-format
+msgid "E354: Invalid register name: '%s'"
+msgstr "E354: '%s' není pøípustné jméno registru"
+
+#, c-format
+msgid "%ld Cols; "
+msgstr "øádkù: %ld;"
+
+#, c-format
+msgid "Selected %s%ld of %ld Lines; %ld of %ld Words; %ld of %ld Bytes"
+msgstr "Vybráno %s%ld z %ld øádkù; %ld z %ld slov; %ld z %ld Bytù"
+
+#, c-format
+msgid "Col %s of %s; Line %ld of %ld; Word %ld of %ld; Byte %ld of %ld"
+msgstr "Sloupec %s z %s; Øádek %ld z %ld; Slovo %ld z %ld; Byte %ld z %ld"
+
+#, c-format
+msgid "(+%ld for BOM)"
+msgstr "(+%ld pro BOM)"
+
+msgid "Thanks for flying Vim"
+msgstr "Dìkuji za použití Vim"
+
+msgid "Option not supported"
+msgstr "Volba není podporována"
+
+msgid "Not allowed in a modeline"
+msgstr "Není v modeline povoleno"
+
+msgid ""
+"\n"
+"\tLast set from "
+msgstr ""
+"\n"
+"\tNaposledy nastavena z "
+
+msgid "Number required after ="
+msgstr "Po = je vyžadováno èíslo"
+
+msgid "Not found in termcap"
+msgstr "Nenalezen v termcapu"
+
+#, c-format
+msgid "Illegal character <%s>"
+msgstr "Nepøípustný znak <%s>"
+
+msgid "Not allowed here"
+msgstr "Toto zde není povoleno"
+
+msgid "Cannot set 'term' to empty string"
+msgstr "volba 'term' nemùže být prázdná"
+
+msgid "Cannot change term in GUI"
+msgstr "V GUI nelze mìnit term"
+
+msgid "Use \":gui\" to start the GUI"
+msgstr "Použijte \"gui\" pro spuštìní GUI"
+
+msgid "'backupext' and 'patchmode' are equal"
+msgstr "volby 'backupext' a 'patchmode' mají stejnou hodnotu"
+
+msgid "Zero length string"
+msgstr "øetìzec o nulové délce"
+
+#, c-format
+msgid "Missing number after <%s>"
+msgstr "Po <%s> chybí èíslo"
+
+msgid "Missing comma"
+msgstr "Chybí èárka"
+
+msgid "Must specify a ' value"
+msgstr "Je nutné zadat hodnotu '"
+
+msgid "contains unprintable character"
+msgstr "obsahuje netisknutelné znaky"
+
+msgid "Invalid font(s)"
+msgstr "Chybná písma"
+
+msgid "can't select fontset"
+msgstr "nelze vybrat sadu písem"
+
+msgid "Invalid fontset"
+msgstr "chybná sada písem"
+
+msgid "can't select wide font"
+msgstr "nelze vybrat široký font"
+
+msgid "Invalid wide font"
+msgstr "Chybné široké písmo"
+
+#, c-format
+msgid "Illegal character after <%c>"
+msgstr "Nepøípustný znak po <%c>"
+
+msgid "comma required"
+msgstr "je nutná èárka"
+
+#, c-format
+msgid "'commentstring' must be empty or contain %s"
+msgstr "volba `commentstring` musí být buï prázdná nebo nastavená na %s"
+
+msgid "No mouse support"
+msgstr "Bez podpory myši"
+
+msgid "Unclosed expression sequence"
+msgstr "neuzavøená sekvence výrazù"
+
+msgid "too many items"
+msgstr "pøíliš mnoho položek"
+
+msgid "unbalanced groups"
+msgstr "nevyvážené skupiny"
+
+msgid "A preview window already exists"
+msgstr "Okno náhledu již existuje"
+
+msgid "'winheight' cannot be smaller than 'winminheight'"
+msgstr ""
+"hodnota volby 'winheight' nesmí být menší než hodnota volby 'winminheight'"
+
+msgid "'winwidth' cannot be smaller than 'winminwidth'"
+msgstr ""
+"hodnota volby 'winwidth' nesmí být menší než hodnota volby 'winminwidth'"
+
+#, c-format
+msgid "Need at least %d lines"
+msgstr "minimální potøebný poèet øádkù: %d"
+
+#, c-format
+msgid "Need at least %d columns"
+msgstr "minimální potøebný poèet sloupcù: %d"
+
+#, c-format
+msgid "E355: Unknown option: %s"
+msgstr "E355: Neznámá volba: %s"
+
+msgid ""
+"\n"
+"--- Terminal codes ---"
+msgstr ""
+"\n"
+"--- Kódy terminálu ---"
+
+msgid ""
+"\n"
+"--- Global option values ---"
+msgstr ""
+"\n"
+"--- Nastavení globálních voleb ---"
+
+msgid ""
+"\n"
+"--- Local option values ---"
+msgstr ""
+"\n"
+"--- Nastavení lokálních voleb ---"
+
+msgid ""
+"\n"
+"--- Options ---"
+msgstr ""
+"\n"
+"--- Volby ---"
+
+msgid "E356: get_varp ERROR"
+msgstr "E356: get_varp CHYBA"
+
+#, c-format
+msgid "E357: 'langmap': Matching character missing for %s"
+msgstr "E357: 'langmap': pro %s chybí vyhovující znak"
+
+#, c-format
+msgid "E358: 'langmap': Extra characters after semicolon: %s"
+msgstr "E358: 'langmap': nadbyteèné znaky po støedníku: %s"
+
+msgid "cannot open "
+msgstr "nelze otevøít "
+
+msgid "VIM: Can't open window!\n"
+msgstr "VIM: Nelze otevøít nové okno!\n"
+
+msgid "Need Amigados version 2.04 or later\n"
+msgstr "Vyžaduje Amigados verze 2.04 nebo vyšší\n"
+
+#, c-format
+msgid "Need %s version %ld\n"
+msgstr "Vyžaduje %s verze %ld\n"
+
+msgid "Cannot open NIL:\n"
+msgstr "Nelze otevøít NIL:\n"
+
+msgid "Cannot create "
+msgstr " Nelze vytvoøit "
+
+#, c-format
+msgid "Vim exiting with %d\n"
+msgstr "Vim bude ukonèen %d\n"
+
+msgid "cannot change console mode ?!\n"
+msgstr "Nelze zmìnit mód konzole ?!\n"
+
+msgid "E359: Screen mode setting not supported"
+msgstr "E359: Nastavování režimu obrazovky není podporováno"
+
+msgid "mch_get_shellsize: not a console??\n"
+msgstr "mch_get_shellsize: neni konzole??\n"
+
+#. if Vim opened a window: Executing a shell may cause crashes
+msgid "E360: Cannot execute shell with -f option"
+msgstr "E360: Nelze spustit shell s parametrem -f"
+
+msgid "Cannot execute "
+msgstr "Nelze spustit "
+
+msgid "shell "
+msgstr "shell "
+
+msgid " returned\n"
+msgstr " návratová hodnota shellu\n"
+
+msgid "ANCHOR_BUF_SIZE too small."
+msgstr "ANCHOR_BUF_SIZE je pøíliš malá."
+
+msgid "I/O ERROR"
+msgstr "I/O CHYBA"
+
+msgid "...(truncated)"
+msgstr "...(kráceno)"
+
+msgid "'columns' is not 80, cannot execute external commands"
+msgstr "'columns' není 80, nelze spustit externí pøíkaz"
+
+#, c-format
+msgid "E364: Library call failed for \"%s()\""
+msgstr "E364: Volání knihovní funkce \"%s()\" selhalo"
+
+msgid "E237: Printer selection failed"
+msgstr "E237: Nelze zvolit tiskárnu"
+
+#, c-format
+msgid "to %s on %s"
+msgstr "do %s v %s"
+
+#, c-format
+msgid "E238: Print error: %s"
+msgstr "E238: Chyba tisku: %s"
+
+msgid "Unknown"
+msgstr "Neznámý"
+
+#, c-format
+msgid "Printing '%s'"
+msgstr "Vytištìno '%s'"
+
+#, c-format
+msgid "E244: Illegal charset name \"%s\" in font name \"%s\""
+msgstr "E244: Nepøípustná jméno znakové sady \"%s\" ve fontu \"%s\""
+
+#, c-format
+msgid "E245: Illegal char '%c' in font name \"%s\""
+msgstr "E245: Nepøípustný znak '%c' ve fontu \"%s\""
+
+msgid "E366: Invalid 'osfiletype' option - using Text"
+msgstr "E366: Neplatný 'osfiletype' - použit Text"
+
+msgid "Vim: Double signal, exiting\n"
+msgstr "VIm: dvojitý signál, konèím\n"
+
+#, c-format
+msgid "Vim: Caught deadly signal %s\n"
+msgstr "Vim: Zachycen smrtelný signál %s\n"
+
+msgid "Vim: Caught deadly signal\n"
+msgstr "Vim: Zachycen smrtelný signál\n"
+
+#, c-format
+msgid "Opening the X display took %ld msec"
+msgstr "Doba otevírání X displeje (v ms): %ld"
+
+msgid ""
+"\n"
+"Vim: Got X error\n"
+msgstr ""
+"\n"
+"Vim: chyba X11\n"
+
+msgid "Testing the X display failed"
+msgstr "Test X displeje se nezdaøil"
+
+msgid "Opening the X display timed out"
+msgstr "Vypršel èas pøi èekání na otevøení X displeje"
+
+msgid ""
+"\n"
+"Cannot execute shell "
+msgstr ""
+"\n"
+"nelze spustit shell "
+
+msgid ""
+"\n"
+"Cannot execute shell sh\n"
+msgstr ""
+"\n"
+"Nelze spustit sh shell\n"
+
+msgid ""
+"\n"
+"shell returned "
+msgstr ""
+"\n"
+" návratová hodnota shellu "
+
+msgid ""
+"\n"
+"Cannot create pipes\n"
+msgstr ""
+"\n"
+"Nelze vytvoøit roury\n"
+
+msgid ""
+"\n"
+"Cannot fork\n"
+msgstr ""
+"\n"
+"Volání fork selhalo\n"
+
+msgid ""
+"\n"
+"Command terminated\n"
+msgstr ""
+"\n"
+"Pøíkaz ukonèen\n"
+
+msgid "Opening the X display failed"
+msgstr "Otevøení X displeje se nezdaøilo"
+
+msgid "At line"
+msgstr "Na øádku"
+
+msgid "Could not load vim32.dll!"
+msgstr "Nelze naèíst vim32.dll!"
+
+msgid "VIM Error"
+msgstr "Chyba VIMu"
+
+msgid "Could not fix up function pointers to the DLL!"
+msgstr "Nelze nastavit ukazatele funkcí na DLL"
+
+#, c-format
+msgid "shell returned %d"
+msgstr "návratová hodnota shellu %d"
+
+#, c-format
+msgid "Vim: Caught %s event\n"
+msgstr "Vim: Zachycen %s signál\n"
+
+msgid "close"
+msgstr "zavøít"
+
+msgid "logoff"
+msgstr "logoff"
+
+msgid "shutdown"
+msgstr "shutdown"
+
+msgid "E371: Command not found"
+msgstr "E371: Pøíkaz není k dispozici"
+
+msgid ""
+"VIMRUN.EXE not found in your $PATH.\n"
+"External commands will not pause after completion.\n"
+"See :help win32-vimrun for more information."
+msgstr ""
+"VIMRUN.EXE se nevyskytuje ve Vaší $PATH.\n"
+"Externí pøíkazy nebudou\n"
+"See :help win32-vimrun for more information."
+
+msgid "Vim Warning"
+msgstr "Varování"
+
+msgid "E372: Too many %%%c in format string"
+msgstr "E372: Pøíliš mnoho %%%c ve formátovacím øetìzci"
+
+msgid "E373: Unexpected %%%c in format string"
+msgstr "E373: Neoèekávaný výskyt %%%c ve formátovacím øetìzci"
+
+msgid "E374: Missing ] in format string"
+msgstr "E374: Ve formátovacím øetìzci chybí ]"
+
+msgid "E375: Unsupported %%%c in format string"
+msgstr "E375: %%%c Nepodporovaná formátová specifikace ve formátovacím øetìzci"
+
+msgid "E376: Invalid %%%c in format string prefix"
+msgstr "E376: Nepøípustné %%%c v prefixu formátovacího øetìzce"
+
+msgid "E377: Invalid %%%c in format string"
+msgstr "E377: Nepøípustné %%%c ve formátovacím øetìzci"
+
+msgid "E378: 'errorformat' contains no pattern"
+msgstr "E378: 'errorformat' neobsahuje žádný vzorek"
+
+msgid "E379: Missing or empty directory name"
+msgstr "E379: Chybìjící nebo prázdný název adresáøe"
+
+msgid "No more items"
+msgstr "Žádné další položky"
+
+#, c-format
+msgid "(%d of %d)%s%s: "
+msgstr "(%d/%d)%s%s: "
+
+msgid " (line deleted)"
+msgstr " (øádek smazán)"
+
+msgid "E380: At bottom of quickfix stack"
+msgstr "E380: Konec quickfix seznamu"
+
+msgid "E381: At top of quickfix stack"
+msgstr "E381: Zaèátek quickfix seznamu"
+
+#, c-format
+msgid "error list %d of %d; %d errors"
+msgstr "seznam chyb %d z %d; poèet chyb: %d"
+
+msgid "E382: Cannot write, 'buftype' option is set"
+msgstr "E382: Nelze uložit, je nastavena volba 'buftype'"
+
+msgid "E339: Pattern too long"
+msgstr "E339: Vzor je pøíliš dlouhý"
+
+#, c-format
+msgid "E61: Nested %s*"
+msgstr "E61: %s*"
+
+#, c-format
+msgid "E62: Nested %s%c"
+msgstr "E62: %s%c"
+
+#, c-format
+msgid "E64: %s%c follows nothing"
+msgstr "E64: %s%c nic není"
+
+#, c-format
+msgid "Syntax error in %s{...}"
+msgstr "Chyba syntaxe v %s{...}"
+
+msgid "E361: Crash intercepted; regexp too complex?"
+msgstr "E361: Zachyceno pøeteèení zásobníku: pøíliš složitý regulární výraz?"
+
+msgid "E363: pattern caused out-of-stack error"
+msgstr "E363: vzorek zpùsobil pøeteèení zásobníku"
+
+msgid "External submatches:\n"
+msgstr "Vnìjší podøazené shody:\n"
+
+#, c-format
+msgid "+--%3ld lines folded "
+msgstr "poèet øádkù v záhybu: %3ld"
+
+msgid " VREPLACE"
+msgstr " VREPLACE"
+
+msgid " REPLACE"
+msgstr " REPLACE"
+
+msgid " REVERSE"
+msgstr " REVERSE"
+
+msgid " INSERT"
+msgstr " INSERT"
+
+msgid " (insert)"
+msgstr " (insert)"
+
+msgid " (replace)"
+msgstr " (replace)"
+
+msgid " (vreplace)"
+msgstr " (vreplace)"
+
+msgid " Hebrew"
+msgstr " hebrejský"
+
+msgid " (lang)"
+msgstr " (lang)"
+
+msgid " (paste)"
+msgstr " (paste)"
+
+msgid " SELECT"
+msgstr " SHODY"
+
+msgid " VISUAL"
+msgstr " VIZUÁLNÍ"
+
+msgid " BLOCK"
+msgstr " BLOK"
+
+msgid " LINE"
+msgstr " ØÁDEK"
+
+msgid "recording"
+msgstr "nahrávám"
+
+msgid "search hit TOP, continuing at BOTTOM"
+msgstr "hledání dosáhlo zaèátku, pokraèování od konce"
+
+msgid "search hit BOTTOM, continuing at TOP"
+msgstr "hledání dosáhlo konce, pokraèování od zaèátku"
+
+#, c-format
+msgid "E383: Invalid search string: %s"
+msgstr "E383: Nepøípustný hledaný øetìzec: %s"
+
+#, c-format
+msgid "E384: search hit TOP without match for: %s"
+msgstr "E384: hledaný dosáhlo zaèátku bez nalezení %s"
+
+#, c-format
+msgid "E385: search hit BOTTOM without match for: %s"
+msgstr "E385: hledaný dosáhlo konce bez nalezení %s"
+
+msgid "E386: Expected '?' or '/' after ';'"
+msgstr "E386: Po ';' oèekávám '?' nebo '/'"
+
+msgid " (includes previously listed match)"
+msgstr " (vèetnì již vypsaných shod)"
+
+#. cursor at status line
+msgid "--- Included files "
+msgstr "--- Vložené soubory"
+
+msgid "not found "
+msgstr " nenalezeny"
+
+msgid "in path ---\n"
+msgstr "v cestì ---\n"
+
+msgid " (Already listed)"
+msgstr " (Již vypsáno)"
+
+msgid " NOT FOUND"
+msgstr " NENALEZENY"
+
+#, c-format
+msgid "Scanning included file: %s"
+msgstr "Prohledávám vložené soubory: %s"
+
+msgid "E387: Match is on current line"
+msgstr "E387: Shoda je na aktuálním øádku"
+
+msgid "All included files were found"
+msgstr "Všechny vložené soubory byly nalezeny"
+
+msgid "No included files"
+msgstr "Žádné vložené soubory"
+
+msgid "E388: Couldn't find definition"
+msgstr "E388: Nelze nalézt definici"
+
+msgid "E389: Couldn't find pattern"
+msgstr "E389: Nelze nalézt vzorek"
+
+#, c-format
+msgid "E390: Illegal argument: %s"
+msgstr "E390: nepøípustný argument: %s"
+
+#, c-format
+msgid "E391: No such syntax cluster: %s"
+msgstr "E391: Syntaktická sestava %s neexistuje"
+
+msgid "No Syntax items defined for this buffer"
+msgstr "Pro tento buffer nejsou definovány žádné pøedmìty syntaxe"
+
+msgid "syncing on C-style comments"
+msgstr "synchronizuji komentáøe v C stylu"
+
+msgid "no syncing"
+msgstr "žádná synchronizace"
+
+msgid "syncing starts "
+msgstr "synchronizace zaèíná "
+
+msgid " lines before top line"
+msgstr " øádkù pøed zaèátkem"
+
+msgid ""
+"\n"
+"--- Syntax sync items ---"
+msgstr ""
+"\n"
+"--- Položky synchronizace syntaxe ---"
+
+msgid ""
+"\n"
+"syncing on items"
+msgstr ""
+"\n"
+"synchronizuji pøedmìty"
+
+msgid ""
+"\n"
+"--- Syntax items ---"
+msgstr ""
+"\n"
+"--- Pøedmìty syntaxe ---"
+
+#, c-format
+msgid "E392: No such syntax cluster: %s"
+msgstr "E392: Syntaktická sestava %s neexistuje"
+
+msgid "minimal "
+msgstr "minimální "
+
+msgid "maximal "
+msgstr "maximální "
+
+msgid "E393: group[t]here not accepted here"
+msgstr "E393: group[t]here nesmí být na tomto místì"
+
+#, c-format
+msgid "E394: Didn't find region item for %s"
+msgstr "E394: Pro %s chybí položka regionu"
+
+msgid "E395: contains argument not accepted here"
+msgstr "E395: obsahuje argumenty, které zde nejsou povoleny"
+
+msgid "E396: containedin argument not accepted here"
+msgstr "E396: obsahuje argumenty, které zde nejsou povoleny"
+
+msgid "E397: Filename required"
+msgstr "E397: Vyžadován název souboru"
+
+#, c-format
+msgid "E398: Missing '=': %s"
+msgstr "E398: Chybí '=': %s"
+
+#, c-format
+msgid "E399: Not enough arguments: syntax region %s"
+msgstr "E399: Pøíliš málo argumentù: oblast syntaxe %s"
+
+msgid "E400: No cluster specified"
+msgstr "E400: Nebyla zadána žádná sestava"
+
+#, c-format
+msgid "E401: Pattern delimiter not found: %s"
+msgstr "E401: Oddìlovaè vzorku %s nenalezen"
+
+#, c-format
+msgid "E402: Garbage after pattern: %s"
+msgstr "E402: Chyba za vzorkem %s"
+
+msgid "E403: syntax sync: line continuations pattern specified twice"
+msgstr "E403: synchronizace syntaxe: vzorek pokraèování øádkù zadán dvakrát"
+
+#, c-format
+msgid "E404: Illegal arguments: %s"
+msgstr "E404: nepøípustný argument: %s"
+
+#, c-format
+msgid "E405: Missing equal sign: %s"
+msgstr "E405: Chybí rovnítko: %s"
+
+#, c-format
+msgid "E406: Empty argument: %s"
+msgstr "E406: Prázdný argument: %s"
+
+#, c-format
+msgid "E407: %s not allowed here"
+msgstr "E407: %s zde není povoleno"
+
+#, c-format
+msgid "E408: %s must be first in contains list"
+msgstr "E408: %s musí být první v 'contains' seznamu"
+
+#, c-format
+msgid "E409: Unknown group name: %s"
+msgstr "E409: Neznámá název skupiny: %s"
+
+#, c-format
+msgid "E410: Invalid :syntax subcommand: %s"
+msgstr "E410: chybný podøazený pøíkaz :syntax : %s "
+
+#, c-format
+msgid "E411: highlight group not found: %s"
+msgstr "E411: skupina zvýraznìní %s nebyla nalezena"
+
+#, c-format
+msgid "E412: Not enough arguments: \":highlight link %s\""
+msgstr "E412: Pøíliš málo argumentù: \":highlight link %s\""
+
+#, c-format
+msgid "E413: Too many arguments: \":highlight link %s\""
+msgstr "E413: Pøíliš mnoho argumentù: \":highlight link %s\""
+
+msgid "E414: group has settings, highlight link ignored"
+msgstr "E414: skupina je nastavena, odkaz na zvýrazòovací skupinu ignorován"
+
+#, c-format
+msgid "E415: unexpected equal sign: %s"
+msgstr "E415: neèekané rovnítko : %s"
+
+#, c-format
+msgid "E416: missing equal sign: %s"
+msgstr "E416: chybné rovnítko: %s"
+
+#, c-format
+msgid "E417: missing argument: %s"
+msgstr "E417: chybí argument: %s"
+
+#, c-format
+msgid "E418: Illegal value: %s"
+msgstr "E418: nepøípustná hodnota: %s"
+
+msgid "E419: FG color unknown"
+msgstr "E419: barva popøedí není známá"
+
+msgid "E420: BG color unknown"
+msgstr "E420: barva popøedí není známá"
+
+#, c-format
+msgid "E421: Color name or number not recognized: %s"
+msgstr "E421: název èi èíslo barvy %s nebylo rozpoznáno"
+
+#, c-format
+msgid "E422: terminal code too long: %s"
+msgstr "E422: terminálový kód %s je pøíliš dlouhý"
+
+#, c-format
+msgid "E423: Illegal argument: %s"
+msgstr "E423: nepøípustný argument: %s"
+
+msgid "E424: Too many different highlighting attributes in use"
+msgstr ""
+"E424: Je používáno pøíliš velké množství odlišných zvýrazòovacích atributù"
+
+msgid "at bottom of tag stack"
+msgstr "konec seznamu tagù"
+
+msgid "at top of tag stack"
+msgstr "zaèátek seznamu tagù"
+
+msgid "E425: Cannot go before first matching tag"
+msgstr "E425: Pøed první vyhovující tag nelze pøeskoèit"
+
+#, c-format
+msgid "E426: tag not found: %s"
+msgstr "E426: tag %s nenalezen"
+
+msgid " # pri kind tag"
+msgstr " # pri typ tag"
+
+msgid "file\n"
+msgstr "soubor\n"
+
+#.
+#. * Ask to select a tag from the list.
+#. * When using ":silent" assume that <CR> was entered.
+#.
+msgid "Enter nr of choice (<CR> to abort): "
+msgstr "Zadejte èíslo (<CR> pro ukonèení): "
+
+msgid "E427: There is only one matching tag"
+msgstr "E427: Vyhovuje pouze jeden tag"
+
+msgid "E428: Cannot go beyond last matching tag"
+msgstr "E428: Za poslední vyhovující tag nelze pøeskoèit"
+
+#, c-format
+msgid "File \"%s\" does not exist"
+msgstr "Soubor \"%s\" neexistuje"
+
+#. Give an indication of the number of matching tags
+#, c-format
+msgid "tag %d of %d%s"
+msgstr "tag %d z celkového poètu %d%s"
+
+msgid " or more"
+msgstr " nebo více"
+
+msgid " Using tag with different case!"
+msgstr " Používám tag s písmeny jiné velikosti!"
+
+#, c-format
+msgid "E429: File \"%s\" does not exist"
+msgstr "E429: \"%s\" neexistuje"
+
+#. Highlight title
+msgid ""
+"\n"
+" # TO tag FROM line in file/text"
+msgstr ""
+"\n"
+" # CÍL tag START øádek v souboru/textu"
+
+msgid "Linear tag search"
+msgstr "Lineární hledání tagu"
+
+msgid "Binary tag search"
+msgstr "Binární hledání tagu"
+
+#, c-format
+msgid "Searching tags file %s"
+msgstr "Prohledávám soubor tagù %s"
+
+#, c-format
+msgid "E430: Tag file path truncated for %s\n"
+msgstr "E430: Soubor tagù %s byl oøezán\n"
+
+#, c-format
+msgid "E431: Format error in tags file \"%s\""
+msgstr "E431: Chyba formátu v souboru tagù \"%s\""
+
+#, c-format
+msgid "Before byte %ld"
+msgstr "Pøed bajtem %ld"
+
+#, c-format
+msgid "E432: Tags file not sorted: %s"
+msgstr "E432: Obsah soubor tagù %s není seøazen"
+
+#. never opened any tags file
+msgid "E433: No tags file"
+msgstr "E433: Žádný soubor tagù"
+
+msgid "E434: Can't find tag pattern"
+msgstr "E434: Nelze najít vzorek tagù"
+
+msgid "E435: Couldn't find tag, just guessing!"
+msgstr "E435: Tag nelze nalézt, pouze hádám!"
+
+msgid "' not known. Available builtin terminals are:"
+msgstr "' není znám. Dostupné vestavìné terminály:"
+
+msgid "defaulting to '"
+msgstr "implicitní terminál '"
+
+msgid "Cannot open termcap file"
+msgstr "Nelze otevøít termcap"
+
+msgid "Terminal entry not found in terminfo"
+msgstr "Terminfo neobsahuje položku pro tento terminál"
+
+msgid "Terminal entry not found in termcap"
+msgstr "Termcap neobsahuje položku pro tento terminál"
+
+#, c-format
+msgid "E436: No \"%s\" entry in termcap"
+msgstr "E436: Termcap neobsahuje položku pro \"%s\""
+
+msgid "E437: terminal capability \"cm\" required"
+msgstr "E437: Terminál musí mít schopnost \"cm\""
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Terminal keys ---"
+msgstr ""
+"\n"
+"--- Klávesy terminálu ---"
+
+msgid "new shell started\n"
+msgstr "spuštìn nový shell\n"
+
+msgid "Vim: Error reading input, exiting...\n"
+msgstr "Vim: chyba pøi ètení vstupu, konèím...\n"
+
+#. must display the prompt
+msgid "No undo possible; continue anyway"
+msgstr "odstranìní zmìn není možné; chcete pøesto pokraèovat"
+
+msgid "E438: u_undo: line numbers wrong"
+msgstr "E438: u_undo: èísla øádkù jsou chybná"
+
+msgid "1 change"
+msgstr "poèet zmìn: 1"
+
+#, c-format
+msgid "%ld changes"
+msgstr "poèet zmìn: %ld"
+
+msgid "E439: undo list corrupt"
+msgstr "E439: záznam o zmìnách poškozen"
+
+msgid "E440: undo line missing"
+msgstr "E440: chybí undo øádek"
+
+#. Only MS VC 4.1 and earlier can do Win32s
+msgid ""
+"\n"
+"MS-Windows 16/32-bit GUI version"
+msgstr ""
+"\n"
+"16/32 bitová GUI verze pro MS Windows"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit GUI version"
+msgstr ""
+"\n"
+"32 bitová GUI verze pro MS Windows"
+
+msgid " in Win32s mode"
+msgstr " ve Win32s režimu"
+
+msgid " with OLE support"
+msgstr " s OLE podporou"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit console version"
+msgstr ""
+"\n"
+"32 bitová verze pro MS Windows konzolu"
+
+msgid ""
+"\n"
+"MS-Windows 16-bit version"
+msgstr ""
+"\n"
+"16 bitová verze pro MS Windows"
+
+msgid ""
+"\n"
+"32-bit MS-DOS version"
+msgstr ""
+"\n"
+"32 bitová verze pro MS Windows"
+
+msgid ""
+"\n"
+"16-bit MS-DOS version"
+msgstr ""
+"\n"
+"16 bitová MS-DOS verze"
+
+msgid ""
+"\n"
+"MacOS X (unix) version"
+msgstr ""
+"\n"
+"MacOS X (unix) verze"
+
+msgid ""
+"\n"
+"MacOS X version"
+msgstr ""
+"\n"
+"MacOS X verze"
+
+msgid ""
+"\n"
+"MacOS version"
+msgstr ""
+"\n"
+"MacOS verze"
+
+msgid ""
+"\n"
+"RISC OS version"
+msgstr ""
+"\n"
+"RISC OS verze"
+
+msgid ""
+"\n"
+"Included patches: "
+msgstr ""
+"\n"
+"Použité záplaty: "
+
+msgid ""
+"\n"
+"Compiled "
+msgstr ""
+"\n"
+"pøeložil "
+
+msgid "by "
+msgstr " "
+
+msgid ""
+"\n"
+"Huge version "
+msgstr ""
+"\n"
+"maximální verze"
+
+msgid ""
+"\n"
+"Big version "
+msgstr ""
+"\n"
+"velká verze "
+
+msgid ""
+"\n"
+"Normal version "
+msgstr ""
+"\n"
+"normální verze"
+
+msgid ""
+"\n"
+"Small version "
+msgstr ""
+"\n"
+"malá verze "
+
+msgid ""
+"\n"
+"Tiny version "
+msgstr ""
+"\n"
+"minimální verze"
+
+msgid "without GUI."
+msgstr "bez grafického rozhraní"
+
+msgid "with GTK-GNOME GUI."
+msgstr "s rozhraním GTK-GNOME"
+
+msgid "with GTK GUI."
+msgstr "s rozhraním GTK"
+
+msgid "with X11-Motif GUI."
+msgstr "s rozhraním X11-Motif"
+
+msgid "with X11-Athena GUI."
+msgstr "S rozhraním X11-Athena"
+
+msgid "with BeOS GUI."
+msgstr "s rozhraním BeOS"
+
+msgid "with Photon GUI."
+msgstr "s rozhraním Photon"
+
+msgid "with GUI."
+msgstr "s grafickým rozhraním"
+
+msgid "with Carbon GUI."
+msgstr "s grafickým rozhraním Carbon"
+
+msgid "with Cocoa GUI."
+msgstr "s grafickým rozhraním Cocoa"
+
+msgid "with (classic) GUI."
+msgstr "s (clasickým) grafickým rozhraním"
+
+msgid " Features included (+) or not (-):\n"
+msgstr " Vlastnosti zahrnuté (+) a nezahrnuté (-):\n"
+
+msgid " system vimrc file: \""
+msgstr " systémový vimrc soubor: \""
+
+msgid " user vimrc file: \""
+msgstr " uživatelský vimrc soubor: \""
+
+msgid " 2nd user vimrc file: \""
+msgstr " druhý uživatelský vimrc soubor: \""
+
+msgid " 3rd user vimrc file: \""
+msgstr " tøetí uživatelský vimrc soubor: \""
+
+msgid " user exrc file: \""
+msgstr " uživatelský exrc soubor: \""
+
+msgid " 2nd user exrc file: \""
+msgstr " druhý uživatelský exrc soubor: \""
+
+msgid " system gvimrc file: \""
+msgstr " systémový gvimrc soubor: \""
+
+msgid " user gvimrc file: \""
+msgstr " uživatelský gvimrc soubor: \""
+
+msgid "2nd user gvimrc file: \""
+msgstr "druhý uživatelský gvimrc soubor: \""
+
+msgid "3rd user gvimrc file: \""
+msgstr "tøetí uživatelský gvimrc soubor: \""
+
+msgid " system menu file: \""
+msgstr " systémový soubor s menu: \""
+
+msgid " fall-back for $VIM: \""
+msgstr " implicitní hodnota $VIM:\""
+
+msgid " f-b for $VIMRUNTIME: \""
+msgstr " implicitní hodnota $VIMRUNTIME: \""
+
+msgid "Compilation: "
+msgstr "Pøeklad: "
+
+msgid "Compiler: "
+msgstr "Pøekladaè: "
+
+msgid "Linking: "
+msgstr "Linkuji: "
+
+msgid " DEBUG BUILD"
+msgstr " PODPORA LADÌNÍ"
+
+msgid "VIM - Vi IMproved"
+msgstr "VIM - Vi IMproved"
+
+msgid "version "
+msgstr "verze "
+
+msgid "by Bram Moolenaar et al."
+msgstr "Autor: Bram Moolenaar a další"
+
+msgid "Vim is open source and freely distributable"
+msgstr "Vim je volnì šiøitelný program s otevøeným zdrojovým kódem"
+
+msgid "Help poor children in Uganda!"
+msgstr "Pomozte chudým dìtem v Ugandì!"
+
+msgid "type :help iccf<Enter> for information "
+msgstr "podrobnìjší informace získáte pomocí :help iccf<Enter>"
+
+msgid "type :q<Enter> to exit "
+msgstr "zadejte :q<Enter> pro ukonèení programu"
+
+msgid "type :help<Enter> or <F1> for on-line help"
+msgstr "zadejte :help<Enter> èi <F1> pro nápovìdu"
+
+msgid "type :help version8<Enter> for version info"
+msgstr "zadejte :help version8<Enter> pro informace o verzi 6"
+
+msgid "Running in Vi compatible mode"
+msgstr "Bìžím v režimu kompatibility s Vi"
+
+msgid "type :set nocp<Enter> for Vim defaults"
+msgstr "zadejte :set nocp<Enter> pro implicitní nastavení Vim"
+
+msgid "type :help cp-default<Enter> for info on this"
+msgstr "podrobnìjší informace získáte pomocí :help cp-default<Enter>"
+
+msgid "WARNING: Windows 95/98/ME detected"
+msgstr "VAROVÁNÍ: detekovány Windows 95/98/ME"
+
+msgid "type :help windows95<Enter> for info on this"
+msgstr "zadejte :help windows95<Enter> pro podrobnìjší informace"
+
+msgid "E441: There is no preview window"
+msgstr "E441: Není žádné preview okno není"
+
+msgid "E442: Can't split topleft and botright at the same time"
+msgstr "E442: Okno nelze rozdìlit zároveò topleft a botright"
+
+msgid "E443: Cannot rotate when another window is split"
+msgstr "E443: Nelze rotovat, pokud je jiné okno rozdìleno"
+
+msgid "E444: Cannot close last window"
+msgstr "E444: Poslední okno nelze uzavøít"
+
+msgid "Already only one window"
+msgstr "Již existuje pouze jedno okno"
+
+msgid "E445: Other window contains changes"
+msgstr "E445: Jiné okno obsahuje zmìny"
+
+msgid "E446: No file name under cursor"
+msgstr "E446: Pod kurzorem se nenachází název souboru"
+
+#, c-format
+msgid "E447: Can't find file \"%s\" in path"
+msgstr "E447: Soubor \"%s\" nelze v path nalézt"
+
+msgid "Edit with &multiple Vims"
+msgstr "Editace &multiple Vimy"
+
+msgid "Edit with single &Vim"
+msgstr "Editace jedním $Vim -em"
+
+msgid "Edit with &Vim"
+msgstr "Editace &Vim -em"
+
+msgid "Edit with existing Vim - &"
+msgstr "Editace existujícím Vimem - &"
+
+msgid "Edits the selected file(s) with Vim"
+msgstr "Editace vybraných souborù Vimem"
+
+msgid "Error creating process: Check if gvim is in your path!"
+msgstr "Chyba pøi spouštìní procesu: Zkontrolujte zdali je gvim v $PATH!"
+
+msgid "gvimext.dll error"
+msgstr "chyba gvimext.dll"
+
+msgid "Path length too long!"
+msgstr "Název (v path) je pøíliš dlouhý"
+
+msgid "--No lines in buffer--"
+msgstr "--Buffer neobsahuje žádný øádek--"
+
+#.
+#. * The error messages that can be shared are included here.
+#. * Excluded are errors that are only used once and debugging messages.
+#.
+msgid "Command aborted"
+msgstr "Pøíkaz pøerušen"
+
+msgid "Argument required"
+msgstr "Je vyžadován argument"
+
+msgid "E10: \\ should be followed by /, ? or &"
+msgstr "E10: po \\ by mìl následovat /. ? nebo &"
+
+msgid "E11: Invalid in command-line window; <CR> executes, CTRL-C quits"
+msgstr ""
+"E11: Chyba v oknì pøíkazové øádky; <CR> pro spuštšní, CTRL-C pro ukonèení"
+
+msgid "E12: Command not allowed from exrc/vimrc in current dir or tag search"
+msgstr ""
+"E12: Pøíkaz není z exrc/vimrc v aktuálním adresáøi èi pøi hledání tagu "
+"povolen."
+
+msgid "E13: File exists (add ! to override)"
+msgstr "E13: Soubor existuje (použijte ! pro vynucení)"
+
+msgid "Command failed"
+msgstr "Pøíkaz selhal"
+
+msgid "Internal error"
+msgstr "Vnitøní chyba"
+
+msgid "Interrupted"
+msgstr "Pøerušeno"
+
+msgid "E14: Invalid address"
+msgstr "E14: Chybná adresa"
+
+msgid "Invalid argument"
+msgstr "Chybný argument"
+
+#, c-format
+msgid "Invalid argument: %s"
+msgstr "Chybný argument: %s"
+
+#, c-format
+msgid "E15: Invalid expression: %s"
+msgstr "E15: Chybný výraz: %s"
+
+msgid "E16: Invalid range"
+msgstr "E16: Chybný rozsah"
+
+msgid "Invalid command"
+msgstr "Chybný pøíkaz"
+
+#, c-format
+msgid "E17: \"%s\" is a directory"
+msgstr "E17: \"%s\" je adresáøem"
+
+msgid "E18: Unexpected characters before '='"
+msgstr "E18: Neoèekávané znaky pøed '='"
+
+msgid "E19: Mark has invalid line number"
+msgstr "E19: Znaèka má chybné èíslo øádku"
+
+msgid "E20: Mark not set"
+msgstr "E20: není nastavena"
+
+msgid "E21: Cannot make changes, 'modifiable' is off"
+msgstr "E21: Nelze mìnit, je nastavena volba 'modifiable'"
+
+msgid "E22: Scripts nested too deep"
+msgstr "E22: Skript vnoøen pøíliš hluboko"
+
+msgid "E23: No alternate file"
+msgstr "E23: Žádný alternativní soubor"
+
+msgid "E24: No such abbreviation"
+msgstr "E24: Taková zkratka neexistuje"
+
+msgid "No ! allowed"
+msgstr "! není povoleno"
+
+msgid "E25: GUI cannot be used: Not enabled at compile time"
+msgstr "E25: Nelze použít GUI: nebylo zapnuto pøi pøekladu programu"
+
+msgid "E26: Hebrew cannot be used: Not enabled at compile time\n"
+msgstr ""
+"E26: nelze použít hebrejský režim: nebyl zapnut pøi pøekladu programu\n"
+
+msgid "E27: Farsi cannot be used: Not enabled at compile time\n"
+msgstr "E27: Nelze použít farsi režim: nebyl zapnut pøi pøekladu programu\n"
+
+#, c-format
+msgid "E28: No such highlight group name: %s"
+msgstr "E28: Skupina zvýraznìní %s neexistuje"
+
+msgid "E29: No inserted text yet"
+msgstr "E29: Zatím není žádný vložený text"
+
+msgid "E30: No previous command line"
+msgstr "E30: Žádná pøedchozí pøíkazová øádka"
+
+msgid "E31: No such mapping"
+msgstr "E31: Žádné takové mapování"
+
+msgid "No match"
+msgstr "Žádná shoda"
+
+#, c-format
+msgid "No match: %s"
+msgstr "Žádná shoda: %s"
+
+msgid "E32: No file name"
+msgstr "E32: Žádný název souboru"
+
+msgid "E33: No previous substitute regular expression"
+msgstr "E33: žádný pøedchozí regulární výraz"
+
+msgid "E34: No previous command"
+msgstr "E34: Žádný pøedchozí pøíkaz"
+
+msgid "E35: No previous regular expression"
+msgstr "E35: žádný pøedchozí regulární výraz"
+
+msgid "No range allowed"
+msgstr "Rozsah není povolen"
+
+msgid "E36: Not enough room"
+msgstr "E36: Nedostatek místa"
+
+#, c-format
+msgid "Can't create file %s"
+msgstr "Nelze vytvoøit soubor %s"
+
+msgid "Can't get temp file name"
+msgstr "Nelze získat název doèasného souboru"
+
+#, c-format
+msgid "Can't open file %s"
+msgstr "Nelze otevøít soubor %s"
+
+#, c-format
+msgid "Can't read file %s"
+msgstr "Nelze èíst soubor %s"
+
+msgid "E37: No write since last change (use ! to override)"
+msgstr "E37: Neuložené zmìny (použijte ! pro vynucení)"
+
+msgid "E38: Null argument"
+msgstr "E38: Nulový argument"
+
+msgid "E39: Number expected"
+msgstr "E39: Oèekáváno èíslo"
+
+#, c-format
+msgid "E40: Can't open errorfile %s"
+msgstr "E40: Nelze otevøít chybový soubor %s"
+
+msgid "E41: Out of memory!"
+msgstr "E41: Nedostatek pamìti!"
+
+msgid "Pattern not found"
+msgstr "Vzor nenalezen"
+
+#, c-format
+msgid "Pattern not found: %s"
+msgstr "Vzor nenalezen: %s"
+
+msgid "Argument must be positive"
+msgstr "Argument musí být kladný"
+
+msgid "E42: No Errors"
+msgstr "E42: Žádné chyby"
+
+msgid "E43: Damaged match string"
+msgstr "E43: Poškozený øetìzec pro vyhledávání"
+
+msgid "E44: Corrupted regexp program"
+msgstr "E44: poškozený regexp program"
+
+msgid "E45: 'readonly' option is set (use ! to override)"
+msgstr "E45: 'nastavena volba 'readonly' (použijte ! pro vynucení)"
+
+#, c-format
+msgid "E46: Cannot set read-only variable \"%s\""
+msgstr "E46: Nelze nastavit pouze_pro_ètení promìnnou \"%s\""
+
+msgid "E47: Error while reading errorfile"
+msgstr "E47: Chyba pøi ètení chybového souboru"
+
+msgid "E48: Not allowed in sandbox"
+msgstr "E48: Není v bezpeènostní schránce povoleno"
+
+msgid "E49: Invalid scroll size"
+msgstr "E49: Chybná hodnota volby 'scroll'"
+
+msgid "E91: 'shell' option is empty"
+msgstr "E91: volba 'shell' je prázdná"
+
+msgid "E72: Close error on swap file"
+msgstr "E72: Chyba pøi uzavírání odkládacího souboru"
+
+msgid "E73: tag stack empty"
+msgstr "E73: seznam tagù je prázdný"
+
+msgid "E74: Command too complex"
+msgstr "E74: Pøíkaz je pøíliš složitý"
+
+msgid "E75: Name too long"
+msgstr "E75: Název je pøíliš dlouhý"
+
+msgid "E76: Too many ["
+msgstr "E76: pøíliš mnoho ["
+
+msgid "E77: Too many file names"
+msgstr "E77: Pøíliš mnoho názvù souborù"
+
+msgid "Trailing characters"
+msgstr "Nadbyteèné znaky na konci"
+
+msgid "E78: Unknown mark"
+msgstr "E78: Neznámá znaèka"
+
+msgid "E79: Cannot expand wildcards"
+msgstr "E79: Nelze expandovat žolíkové znaky"
+
+msgid "E80: Error while writing"
+msgstr "E80: Chyba pøi ukládání"
+
+msgid "Zero count"
+msgstr "Nulový poèet"
+
+msgid "E81: Using <SID> not in a script context"
+msgstr "E81: Použití <SID> mimo kontext skriptu"
diff --git a/src/po/cs.po b/src/po/cs.po
new file mode 100644
index 0000000..5b9e686
--- /dev/null
+++ b/src/po/cs.po
@@ -0,0 +1,4660 @@
+# Czech translation of vim
+# Jiøí Pavlovský <jpavlovsky@mbox.vol.cz>, 2000 - 2002.
+# Some completion for vim6.0 added by Jiøí Bøezina <brz@centrum.cz>
+# Some bugfixes by Tomá¹ Zellerin <zellerin@volny.cz>
+#
+# Original translations.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: vim-6.0\n"
+"POT-Creation-Date: 2001-10-08 08:27-0700\n"
+"PO-Revision-Date: 2002-02-06 22:29+0100\n"
+"Last-Translator: Jiøí Pavlovský <jpavlovsky@mbox.vol.cz>\n"
+"Language-Team: Czech <cs@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-2\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "E82: Cannot allocate any buffer, exiting..."
+msgstr "E82: Nelze alokovat ¾ádný buffer, konèím..."
+
+msgid "E83: Cannot allocate buffer, using other one..."
+msgstr "E83: Nelze alokovat buffer, pou¾iji jiný..."
+
+msgid "No buffers were unloaded"
+msgstr "®ádný buffer nebyl deaktivován"
+
+msgid "No buffers were deleted"
+msgstr "®ádný buffer nebyl smazán"
+
+msgid "No buffers were wiped out"
+msgstr "®ádný buffer nebyl zahozen"
+
+msgid "1 buffer unloaded"
+msgstr "Poèet deaktivovaných bufferù: 1"
+
+#, c-format
+msgid "%d buffers unloaded"
+msgstr "Poèet deaktivovaných bufferù: %d"
+
+msgid "1 buffer deleted"
+msgstr "Poèet smazaných bufferù: 1"
+
+#, c-format
+msgid "%d buffers deleted"
+msgstr "Poèet smazaných bufferù: %d"
+
+msgid "1 buffer wiped out"
+msgstr "Poèet zahozených bufferù: 1"
+
+#, c-format
+msgid "%d buffers wiped out"
+msgstr "Poèet zahozených bufferù: %d"
+
+msgid "E84: No modified buffer found"
+msgstr "E84: Nebyl nalezen ¾ádný zmìnìný buffer"
+
+#. back where we started, didn't find anything.
+msgid "E85: There is no listed buffer"
+msgstr "E85: Seznam bufferù je prázdný"
+
+#, c-format
+msgid "E86: Cannot go to buffer %ld"
+msgstr "E86: Nelze pøeskoèit na buffer %ld"
+
+msgid "E87: Cannot go beyond last buffer"
+msgstr "E87: Za poslední buffer nelze pøeskoèit"
+
+msgid "E88: Cannot go before first buffer"
+msgstr "E88: Pøed první buffer nelze pøeskoèit"
+
+#, c-format
+msgid "E89: No write since last change for buffer %ld (use ! to override)"
+msgstr "E89: Zmìny v bufferu %ld nebyly ulo¾eny (! pro vynucení)"
+
+msgid "E90: Cannot unload last buffer"
+msgstr "E90: Poslední buffer nelze deaktivovat"
+
+msgid "W14: Warning: List of file names overflow"
+msgstr "W14: Varování: pøeteèení seznamu s názvy souborù"
+
+#, c-format
+msgid "E92: Buffer %ld not found"
+msgstr "E92: Buffer %ld nenalezen"
+
+#, c-format
+msgid "E93: More than one match for %s"
+msgstr "E93: Vzoru %s vyhovuje více bufferù"
+
+#, c-format
+msgid "E94: No matching buffer for %s"
+msgstr "E94: Vzoru %s nevyhovuje ¾ádný buffer"
+
+#, c-format
+msgid "line %ld"
+msgstr "øádek %ld"
+
+msgid "E95: Buffer with this name already exists"
+msgstr "E95: Buffer tohoto jména ji¾ existuje"
+
+msgid " [Modified]"
+msgstr " [Zmìnìný]"
+
+msgid "[Not edited]"
+msgstr "[Needitovaný]"
+
+msgid "[New file]"
+msgstr "[Nový soubor]"
+
+msgid "[Read errors]"
+msgstr "[Chyby pøi ètení]"
+
+msgid "[readonly]"
+msgstr "[Pouze pro ètení]"
+
+msgid "1 line --%d%%--"
+msgstr "øádkù: --%d%%--"
+
+msgid "%ld lines --%d%%--"
+msgstr "øádkù: %ld --%d%%--"
+
+msgid "line %ld of %ld --%d%%-- col "
+msgstr "øádek %ld/%ld --%d%%-- sloupec"
+
+msgid "[No file]"
+msgstr "[®ádný soubor]"
+
+#. must be a help buffer
+msgid "help"
+msgstr "nápovìda"
+
+msgid "[help]"
+msgstr "[nápovìda]"
+
+msgid "[Preview]"
+msgstr "[náhled]"
+
+msgid "All"
+msgstr "V¹e"
+
+msgid "Bot"
+msgstr "Konec"
+
+msgid "Top"
+msgstr "Zaèátek"
+
+msgid ""
+"\n"
+"# Buffer list:\n"
+msgstr ""
+"\n"
+"# Seznam bufferù:\n"
+
+msgid "[Error List]"
+msgstr "[seznam chyb]"
+
+msgid "[No File]"
+msgstr "[¾ádný soubor]"
+
+msgid ""
+"\n"
+"--- Signs ---"
+msgstr ""
+"\n"
+"--- Znaky ---"
+
+#, c-format
+msgid "Signs for %s:"
+msgstr "Znaky pro %s:"
+
+#, c-format
+msgid " line=%ld id=%d name=%s"
+msgstr " øádek=%ld id=%d jméno=%s"
+
+#, c-format
+msgid "E96: Can not diff more than %ld buffers"
+msgstr "E96: Nelze pøekroèit maximální poèet %ld diff bufferù"
+
+msgid "E97: Cannot create diffs"
+msgstr "E97: Nelze vytvoøit diffy"
+
+msgid "Patch file"
+msgstr "Soubor se záplatou"
+
+msgid "E98: Cannot read diff output"
+msgstr "E98: Nelze èíst výstup programu diff"
+
+msgid "E99: Current buffer is not in diff mode"
+msgstr "E99: Aktuální buffer není v diff re¾imu"
+
+msgid "E100: No other buffer in diff mode"
+msgstr "E100: To byl poslední buffer v diff re¾imu"
+
+msgid "E101: More than two buffers in diff mode, don't know which one to use"
+msgstr "E101: V diff re¾imu jsou více ne¾ dva buffery. Nevím, který mám pou¾ít."
+
+#, c-format
+msgid "E102: Can't find buffer \"%s\""
+msgstr "E102: Nelze nalézt buffer \"%s\""
+
+#, c-format
+msgid "E103: Buffer \"%s\" is not in diff mode"
+msgstr "E103: Buffer \"%s\" není v diff re¾imu"
+
+msgid "E104: Escape not allowed in digraph"
+msgstr "E104: digraph nesmí obsahovat Escape"
+
+msgid "Keymap file not found"
+msgstr "Soubor s mapou klávesnice nebyl nalezen"
+
+msgid "E105: Using :loadkeymap not in a sourced file"
+msgstr "E105: :loadkeymap mimo interpretovaný soubor"
+
+msgid " Keyword completion (^N/^P)"
+msgstr " Doplòování klíèových slov (^N/^P)"
+
+#. ctrl_x_mode == 0, ^P/^N compl.
+msgid " ^X mode (^E/^Y/^L/^]/^F/^I/^K/^D/^V/^N/^P)"
+msgstr " ^X re¾im (^E/^Y/^L/^]/^F/^I/^K/^D/^V/^N/^P)"
+
+#. Scroll has it's own msgs, in it's place there is the msg for local
+#. * ctrl_x_mode = 0 (eg continue_status & CONT_LOCAL) -- Acevedo
+msgid " Keyword Local completion (^N/^P)"
+msgstr " Lokální doplòování klíèových slov (^N/^P)"
+
+msgid " Whole line completion (^L/^N/^P)"
+msgstr " Doplòování celých øádkù (^L/^N/^P)"
+
+msgid " File name completion (^F/^N/^P)"
+msgstr " Doplòování názvù souborù (^F/^N/^P)"
+
+msgid " Tag completion (^]/^N/^P)"
+msgstr " Doplòování tagù (^I/^N/^P)"
+
+msgid " Path pattern completion (^N/^P)"
+msgstr " Doplòování vzoru cest (^N/^P)"
+
+msgid " Definition completion (^D/^N/^P)"
+msgstr " Doplòování definic (^D/^N/^P)"
+
+msgid " Dictionary completion (^K/^N/^P)"
+msgstr " Doplòování podle slovníku (^K/^N/^P)"
+
+msgid " Thesaurus completion (^T/^N/^P)"
+msgstr " Doplòování podle tezauru (^T/^N/^P)"
+
+msgid " Command-line completion (^V/^N/^P)"
+msgstr " Doplòování pøíkazové øádky (^I/^N/^P)"
+
+msgid "Hit end of paragraph"
+msgstr "Konec odstavce"
+
+msgid "'thesaurus' option is empty"
+msgstr "volba 'thesaurus' je prázdná"
+
+msgid "'dictionary' option is empty"
+msgstr "volba 'dictionary' je prázdná"
+
+#, c-format
+msgid "Scanning dictionary: %s"
+msgstr "Prohledávám slovník %s"
+
+msgid " (insert) Scroll (^E/^Y)"
+msgstr " (insert) Rolování (^E/^Y)"
+
+msgid " (replace) Scroll (^E/^Y)"
+msgstr " (replace) Rolování (^E/^Y)"
+
+#, c-format
+msgid "Scanning: %s"
+msgstr "Prohledávám %s"
+
+msgid "Scanning tags."
+msgstr "Prohledávám tagy"
+
+msgid " Adding"
+msgstr "Pøidávám"
+
+#. showmode might reset the internal line pointers, so it must
+#. * be called before line = ml_get(), or when this address is no
+#. * longer needed. -- Acevedo.
+#.
+msgid "-- Searching..."
+msgstr "-- Hledám..."
+
+msgid "Back at original"
+msgstr "Výchozí podoba"
+
+msgid "Word from other line"
+msgstr "Slovo z jiného øádku"
+
+msgid "The only match"
+msgstr "Jediná shoda"
+
+#, c-format
+msgid "match %d of %d"
+msgstr "shoda %d/%d"
+
+#, c-format
+msgid "match %d"
+msgstr "shoda %d"
+
+#, c-format
+msgid "E106: Unknown variable: \"%s\""
+msgstr "E106: Neznámá promìnná: \"%s\""
+
+#, c-format
+msgid "E107: Missing parentheses: %s"
+msgstr "E107: Chybí závorky: %s"
+
+#, c-format
+msgid "E108: No such variable: \"%s\""
+msgstr "E108: Promìnná \"%s\" neexistuje"
+
+msgid "E109: Missing ':' after '?'"
+msgstr "E109: Po '?' chybí ':'"
+
+msgid "E110: Missing ')'"
+msgstr "E110: Chybìjící ')'"
+
+msgid "E111: Missing ']'"
+msgstr "E111: Chybìjící ']'"
+
+#, c-format
+msgid "E112: Option name missing: %s"
+msgstr "E112: Chybí jméno volby: %s"
+
+#, c-format
+msgid "E113: Unknown option: %s"
+msgstr "E113: Neznámá volba: %s"
+
+#, c-format
+msgid "E114: Missing quote: %s"
+msgstr "E114: Chybí uvozovky: %s"
+
+#, c-format
+msgid "E115: Missing quote: %s"
+msgstr "E115: Chybí uvozovky: %s"
+
+#, c-format
+msgid "E116: Invalid arguments for function %s"
+msgstr "E116: Chybné argumenty pro funkci %s"
+
+#, c-format
+msgid "E117: Unknown function: %s"
+msgstr "E117: Neznámá funkce: %s"
+
+#, c-format
+msgid "E118: Too many arguments for function: %s"
+msgstr "E118: Pøíli¹ mnoho argumentù pro funkci %s"
+
+#, c-format
+msgid "E119: Not enough arguments for function: %s"
+msgstr "E119: Pøíli¹ málo argumentù pro funkci %s"
+
+#, c-format
+msgid "E120: Using <SID> not in a script context: %s"
+msgstr "E120: Pou¾ití <SID> mimo kontext skriptu: %s"
+
+#, c-format
+msgid "+-%s%3ld lines: "
+msgstr "+-%s%3ld øádkù:"
+
+msgid ""
+"&OK\n"
+"&Cancel"
+msgstr ""
+"&OK\n"
+"&Zru¹it"
+
+msgid "E240: No connection to Vim server"
+msgstr "E240: Neexistuje pøipojení k Vim serveru"
+
+msgid "E277: Unable to read a server reply"
+msgstr "E277: Nelze èíst odpovìï serveru"
+
+msgid "E258: Unable to send to client"
+msgstr "E258: Nelze pøedat klientovi"
+
+#, c-format
+msgid "E241: Unable to send to %s"
+msgstr "E241: Nelze pøedat do %s"
+
+msgid "(Invalid)"
+msgstr "(Chybný)"
+
+#, c-format
+msgid "E121: Undefined variable: %s"
+msgstr "E121: Nedefinovaná promìnná: %s"
+
+#, c-format
+msgid "E122: Function %s already exists, use ! to replace"
+msgstr "E122: Funkce %s ji¾ existuje. Pou¾ijte ! pro její nahrazení."
+
+#, c-format
+msgid "E123: Undefined function: %s"
+msgstr "E123: Nedefinovaná funkce: %s"
+
+#, c-format
+msgid "E124: Missing '(': %s"
+msgstr "E124: Chybí '(': %s"
+
+#, c-format
+msgid "E125: Illegal argument: %s"
+msgstr "E125: Nepøípustný argument: %s"
+
+msgid "E126: Missing :endfunction"
+msgstr "E126: Chybí :endfunction"
+
+#, c-format
+msgid "E127: Cannot redefine function %s: It is in use"
+msgstr "E127: Nelze pøedefinovat funkci %s: je pou¾ívána"
+
+#, c-format
+msgid "E128: Function name must start with a capital: %s"
+msgstr "E128: Název funkce musí zaèínat velkým písmenem: %s"
+
+msgid "E129: Function name required"
+msgstr "E129: Je vy¾adováno jméno funkce"
+
+msgid "function "
+msgstr "funkce "
+
+#, c-format
+msgid "E130: Undefined function: %s"
+msgstr "E130: Nedefinovaná funkce: %s"
+
+#, c-format
+msgid "E131: Cannot delete function %s: It is in use"
+msgstr "E131: Nelze smazat funkci %s: je ji¾ pou¾ívána"
+
+msgid "E132: Function call depth is higher than 'maxfuncdepth'"
+msgstr "E132: Zanoøení funkce je hlub¹í ne¾ 'maxfuncdepth'"
+
+#. always scroll up, don't overwrite
+#, c-format
+msgid "calling %s"
+msgstr "volám %s"
+
+#. always scroll up, don't overwrite
+#, c-format
+msgid "continuing in %s"
+msgstr "pokraèuji v %s"
+
+msgid "E133: :return not inside a function"
+msgstr "E133: :return mimo funkci"
+
+#, c-format
+msgid "%s returning #%ld"
+msgstr "dokonèeno provádìní %s. Návratová hodnota #%ld"
+
+#, c-format
+msgid "%s returning \"%s\""
+msgstr "dokonèeno provádìní %s. Návratová hodnota \"%s\""
+
+msgid ""
+"\n"
+"# global variables:\n"
+msgstr ""
+"\n"
+"# globální promìnné:\n"
+
+#, c-format
+msgid "<%s>%s%s %d, Hex %02x, Octal %03o"
+msgstr "<%s>%s%s %d, ¹estnáctkovì %02x, osmièkovì %03o"
+
+msgid "E134: Move lines into themselves"
+msgstr "E134: Nelze pøesunout øádky na pùvodní místo"
+
+msgid "1 line moved"
+msgstr "poèet pøesunutých øádkù: 1"
+
+#, c-format
+msgid "%ld lines moved"
+msgstr "Poèet pøesunutých øádkù: %ld"
+
+#, c-format
+msgid "%ld lines filtered"
+msgstr "Poèet filtrovaných øádkù: %ld"
+
+msgid "E135: *Filter* Autocommands must not change current buffer"
+msgstr "E135: Automatické pøíkazy *Filter* nesmí mìnit aktuální buffer"
+
+msgid "[No write since last change]\n"
+msgstr "[Neulo¾ené zmìny]\n"
+
+#, c-format
+msgid "viminfo: %s in line: "
+msgstr "viminfo: %s na øádku: "
+
+msgid "E136: viminfo: Too many errors, skipping rest of file"
+msgstr "E136: viminfo: pøíli¹ mnoho chyb, pøeskakuji zbytek souboru"
+
+#, c-format
+msgid "Reading viminfo file \"%s\"%s%s%s"
+msgstr "Ètu viminfo soubor \"%s\"%s%s%s"
+
+msgid " info"
+msgstr " informace"
+
+msgid " marks"
+msgstr " znaèky"
+
+msgid " FAILED"
+msgstr " se nezdaøilo"
+
+#, c-format
+msgid "E137: Viminfo file is not writable: %s"
+msgstr "E137: do viminfo souboru %s nelze zapisovat"
+
+#, c-format
+msgid "E138: Can't write viminfo file %s!"
+msgstr "E138: Nelze ulo¾it viminfo soubor %s!"
+
+#, c-format
+msgid "Writing viminfo file \"%s\""
+msgstr "Ukládám viminfo souboru \"%s\""
+
+#. Write the info:
+msgid "# This viminfo file was generated by Vim %s.\n"
+msgstr "# Tento viminfo soubor byl vytvoøen editorem Vim %s.\n"
+
+msgid ""
+"# You may edit it if you're careful!\n"
+"\n"
+msgstr ""
+"# Pokud budete opatrný, mù¾ete jej upravovat.\n"
+"\n"
+
+msgid "# Value of 'encoding' when this file was written\n"
+msgstr "# Hodnota volby 'encoding' v dobì ulo¾ení tohoto souboru\n"
+
+msgid "Illegal starting char"
+msgstr "Nepøípustný poèáteèní znak"
+
+msgid "Save As"
+msgstr "Ulo¾it jako"
+
+#. Overwriting a file that is loaded in another buffer is not a
+#. * good idea.
+msgid "E139: File is loaded in another buffer"
+msgstr "E139: Soubor je nahrán v jiném bufferu"
+
+msgid "Write partial file?"
+msgstr "Ulo¾it neúplný soubor?"
+
+msgid "E140: Use ! to write partial buffer"
+msgstr "E140: Pou¾ijte ! pro ulo¾ení neúplného bufferu"
+
+#, c-format
+msgid "Overwrite existing file \"%.*s\"?"
+msgstr "Pøepsat soubor \"%.*s\"?"
+
+#, c-format
+msgid "E141: No file name for buffer %ld"
+msgstr "E141: ®ádný název souboru pro buffer %ld"
+
+msgid "E142: File not written: Writing is disabled by 'write' option"
+msgstr "E142: Soubor nebyl ulo¾en: Ukládání je zakázáno volbou 'write'"
+
+#, c-format
+msgid ""
+"'readonly' option is set for \"%.*s\".\n"
+"Do you wish to write anyway?"
+msgstr ""
+"Pro \"%.*s\" je nastavena volba 'readonly'.\n"
+"Pøejete si ji potlaèit?"
+
+msgid "Edit File"
+msgstr "Editovat soubor"
+
+#, c-format
+msgid "E143: Autocommands unexpectedly deleted new buffer %s"
+msgstr "E143: Automatické pøíkazy neoèekávanì smazaly nový buffer %s"
+
+msgid "E144: non-numeric argument to :z"
+msgstr "E144: neèíselný argument pro :z"
+
+msgid "E145: Shell commands not allowed in rvim"
+msgstr "E145: rvim nepovoluje pou¾ití pøíkazù shellu"
+
+msgid "E146: Regular expressions can't be delimited by letters"
+msgstr "E146: Regulární výrazy nesmí být oddìleny písmeny"
+
+#, c-format
+msgid "replace with %s (y/n/a/q/l/^E/^Y)?"
+msgstr "nahradit za %s (y/n/a/q/l/^E/^Y)?"
+
+msgid "(Interrupted) "
+msgstr "(Pøeru¹eno) "
+
+msgid "1 substitution"
+msgstr "1 nahrazení"
+
+#, c-format
+msgid "%ld substitutions"
+msgstr "%ld nahrazení"
+
+msgid " on 1 line"
+msgstr " na jednom øádku"
+
+#, c-format
+msgid " on %ld lines"
+msgstr " na %ld øádcích"
+
+msgid "E147: Cannot do :global recursive"
+msgstr "E147: :global nelze volat rekurzivnì"
+
+msgid "E148: Regular expression missing from global"
+msgstr "E148: U pøíkazu 'global' chybí regulární výraz"
+
+#, c-format
+msgid "Pattern found in every line: %s"
+msgstr "Vzor nalezen na ka¾dém øádku: %s"
+
+msgid ""
+"\n"
+"# Last Substitute String:\n"
+"$"
+msgstr ""
+"\n"
+"# Poslední nahrazující øetìzec:\n"
+"$"
+
+#, c-format
+msgid "E149: Sorry, no help for %s"
+msgstr "E149: Lituji, pro %s není ¾ádná nápovìda"
+
+#, c-format
+msgid "Sorry, help file \"%s\" not found"
+msgstr "Lituji, soubor \"%s\" s nápovìdou nebyl nalezen"
+
+#, c-format
+msgid "E150: Not a directory: %s"
+msgstr "E150: %s není adresáøem"
+
+#, c-format
+msgid "E152: Cannot open %s for writing"
+msgstr "E152: Nelze otevøít %s pro zápis"
+
+#, c-format
+msgid "E153: Unable to open %s for reading"
+msgstr "E153: Nelze otevøít %s pro zápis"
+
+#, c-format
+msgid "E154: Duplicate tag \"%s\" in file %s"
+msgstr "E154: Duplicitní tag \"%s\" v souboru %s"
+
+#, c-format
+msgid "E160: Unknown sign command: %s"
+msgstr "E160: Neznámá volba pøíkazu: %s"
+
+msgid "E156: Missing sign name"
+msgstr "E156: Chybí jméno volby"
+
+msgid "E255: Too many signs defined"
+msgstr "E255: Nastaveno pøíli¹ mnoho voleb"
+
+#, c-format
+msgid "E239: Invalid sign text: %s"
+msgstr "E239: Neplatný text volby: %s"
+
+#, c-format
+msgid "E155: Unknown sign: %s"
+msgstr "E155: Neznámá volba: %s"
+
+msgid "E159: Missing sign number"
+msgstr "E159: Chybí identifikátor volby"
+
+#, c-format
+msgid "E158: Invalid buffer name: %s"
+msgstr "E158: chybné jméno bufferu: %s"
+
+#, c-format
+msgid "E157: Invalid sign ID: %ld"
+msgstr "E157: Chybné ID volby: %ld"
+
+msgid "[Deleted]"
+msgstr "[Vymazáno]"
+
+msgid "Entering Debug mode. Type \"cont\" to leave."
+msgstr "Spou¹tím ladící re¾im. Pro ukonèení napi¹te \"cont\"."
+
+#, c-format
+msgid "line %ld: %s"
+msgstr "øádek %ld: %s"
+
+#, c-format
+msgid "cmd: %s"
+msgstr "pøíkaz: %s"
+
+#, c-format
+msgid "Breakpoint in \"%s%s\" line %ld"
+msgstr "Bod pøeru¹ení v \"%s%s\" na øádku %ld"
+
+#, c-format
+msgid "E161: Breakpoint not found: %s"
+msgstr "E161: Bod pøeru¹ení nenalezen: %s"
+
+msgid "No breakpoints defined"
+msgstr "Nebyly definovánu ¾ádné body pøeru¹ení"
+
+#, c-format
+msgid "%3d %s %s line %ld"
+msgstr "%3d %s %s øádek %ld"
+
+#, c-format
+msgid "Save changes to \"%.*s\"?"
+msgstr "Ulo¾it zmìny do \"%.*s\"?"
+
+msgid "Untitled"
+msgstr "Nepojmenováno"
+
+#, c-format
+msgid "E162: No write since last change for buffer \"%s\""
+msgstr "E162: Buffer \"%s\" obsahuje neulo¾ené zmìny"
+
+msgid "Warning: Entered other buffer unexpectedly (check autocommands)"
+msgstr ""
+"Varování: Neèekaný vstup do jiného bufferu (zkontrolujte automatické pøíkazy)"
+
+msgid "E163: There is only one file to edit"
+msgstr "E163: Pro editaci byl zadán pouze jeden soubor"
+
+msgid "E164: Cannot go before first file"
+msgstr "E164: Pøed první soubor nelze pøeskoèit"
+
+msgid "E165: Cannot go beyond last file"
+msgstr "E165: Za poslední soubor nelze pøeskoèit"
+
+#, c-format
+msgid "Searching for \"%s\" in \"%s\""
+msgstr "Hledám \"%s\" v \"%s\""
+
+#, c-format
+msgid "Searching for \"%s\""
+msgstr "Hledám \"%s\""
+
+#, c-format
+msgid "not found in 'runtimepath': \"%s\""
+msgstr "soubor \"%s\" nebyl nalezen v 'runtimepath'"
+
+msgid "Run Macro"
+msgstr "Spustit makro"
+
+#, c-format
+msgid "Cannot source a directory: \"%s\""
+msgstr "nelze interpretovat adresáø: \"%s\""
+
+#, c-format
+msgid "could not source \"%s\""
+msgstr "nelze interpretovat \"%s\""
+
+#, c-format
+msgid "line %ld: could not source \"%s\""
+msgstr "øádek %ld: nelze interpretovat \"%s\""
+
+#, c-format
+msgid "sourcing \"%s\""
+msgstr "interpretuji \"%s\""
+
+#, c-format
+msgid "line %ld: sourcing \"%s\""
+msgstr "øádek %ld: interpretuji %s"
+
+#, c-format
+msgid "finished sourcing %s"
+msgstr "dokonèena interpretace %s"
+
+msgid "W15: Warning: Wrong line separator, ^M may be missing"
+msgstr "W15: Varování: chybný oddìlovaè øádkù. Mo¾ná chybí ^M."
+
+msgid "E167: :scriptencoding used outside of a sourced file"
+msgstr "E167: :scriptencoding pou¾ito mimo interpretovaný soubor"
+
+msgid "E168: :finish used outside of a sourced file"
+msgstr "E168: :finish pou¾ito mimo interpretovaný soubor"
+
+msgid "No text to be printed"
+msgstr "®ádný text k vyti¹tìní"
+
+msgid "Printing page %d (%d%%)"
+msgstr "Tisknu stranu %d (%d%%)"
+
+#, c-format
+msgid " Copy %d of %d"
+msgstr " Kopie %d z %d"
+
+#, c-format
+msgid "Printed: %s"
+msgstr "Vyti¹tìno: %s"
+
+msgid "Printing aborted"
+msgstr "Tisk zru¹en"
+
+msgid "E455: Error writing to PostScript output file"
+msgstr "E455: Nelze zapisovat do výstupního PostScriptového souboru"
+
+msgid "E324: Can't open PostScript output file"
+msgstr "E324: Nelze otevøít výstupní PostScriptový soubor"
+
+msgid "E456: Can't open file \"%s\""
+msgstr "E456: Nelze otevøít soubor \"%s\""
+
+msgid "E457: Can't read PostScript resource file \"%s\""
+msgstr "E457: Nelze èíst zdrojový PostScriptový soubor \"%s\""
+
+msgid "Sending to printer..."
+msgstr "Odesílám na tiskárnu..."
+
+msgid "E365: Failed to print PostScript file"
+msgstr "E365: Selhal tisk PostScriptového souboru"
+
+msgid "Print job sent."
+msgstr "Tisková úloha odeslána."
+
+#, c-format
+msgid "Current %slanguage: \"%s\""
+msgstr "Aktuální %sjazyk: \"%s\""
+
+#, c-format
+msgid "E197: Cannot set language to \"%s\""
+msgstr "E197: Nelze nastavit jazyk na \"%s\""
+
+msgid "Entering Ex mode. Type \"visual\" to go to Normal mode."
+msgstr "Spou¹tím Ex mód. Napi¹te \"visual\" pro návrat do normálního módu."
+
+#. must be at EOF
+msgid "At end-of-file"
+msgstr "Konec souboru"
+
+msgid "E169: Command too recursive"
+msgstr "E169: Pøíkaz je pøíli¹ rekurzivní"
+
+msgid "E170: Missing :endwhile"
+msgstr "E170: Chybí :endwhile"
+
+msgid "E171: Missing :endif"
+msgstr "E171: Chybí :endif"
+
+msgid "End of sourced file"
+msgstr "Konec interpretovaného souboru"
+
+msgid "End of function"
+msgstr "Konec funkce"
+
+msgid "Ambiguous use of user-defined command"
+msgstr "Nejednoznaèné pou¾ití u¾ivatelsky definovaného pøíkazu"
+
+msgid "Not an editor command"
+msgstr "Není pøíkazem editoru"
+
+msgid "Don't panic!"
+msgstr "Nepanikaøte!"
+
+msgid "Backwards range given"
+msgstr "Zadán zpìtný rozsah"
+
+msgid "Backwards range given, OK to swap"
+msgstr "Zadán zpìtný rozsah. Prohodit hranice"
+
+msgid "Use w or w>>"
+msgstr "Pou¾ijte w èi w>>"
+
+msgid "E319: Sorry, the command is not available in this version"
+msgstr "E319: Pøíkaz není této verzi bohu¾el implementován"
+
+msgid "E172: Only one file name allowed"
+msgstr "E172: Pøípustný je pouze jeden název souboru"
+
+#, c-format
+msgid "%d more files to edit. Quit anyway?"
+msgstr "Je¹tì zbývají soubory k editaci (%d). Chcete pøesto ukonèit editor?"
+
+#, c-format
+msgid "E173: %ld more files to edit"
+msgstr "E173: Je¹tì zbývají soubory k editaci (%ld)."
+
+msgid "E174: Command already exists: use ! to redefine"
+msgstr "E174: Pøíkaz ji¾ existuje: pou¾ijte ! pro pøedefinování"
+
+msgid ""
+"\n"
+" Name Args Range Complete Definition"
+msgstr ""
+"\n"
+" Jméno Args Rozsah Úplnost Definice"
+
+msgid "No user-defined commands found"
+msgstr "Nebyly nalezeny ¾ádné u¾ivatelsky definované pøíkazy"
+
+msgid "E175: No attribute specified"
+msgstr "E175: Nebyly zadány ¾ádné atributy"
+
+msgid "E176: Invalid number of arguments"
+msgstr "E176: Chybný poèet argumentù"
+
+msgid "E177: Count cannot be specified twice"
+msgstr "E177: Opakování nemù¾e být zadáno dvakrát"
+
+msgid "E178: Invalid default value for count"
+msgstr "E178: Chybná implicitní hodnota pro poèet"
+
+msgid "E179: argument required for complete"
+msgstr "E179: chybná implicitní hodnota pro opakování"
+
+#, c-format
+msgid "E180: Invalid complete value: %s"
+msgstr "E180: Chybná hodnota doplnìní: %s"
+
+#, c-format
+msgid "E181: Invalid attribute: %s"
+msgstr "E181: Chybný atribut: %s"
+
+msgid "E182: Invalid command name"
+msgstr "E182: Chybné jméno pøíkazu"
+
+msgid "E183: User defined commands must start with an uppercase letter"
+msgstr "E183: U¾ivatelsky definované pøíkazy musí zaèínat velikým písmenem."
+
+#, c-format
+msgid "E184: No such user-defined command: %s"
+msgstr "E184: U¾ivatelsky definovaný pøíkaz %s neexistuje"
+
+#, c-format
+msgid "E185: Cannot find color scheme %s"
+msgstr "E185: Nelze nalézt barevné schéma %s"
+
+msgid "Greetings, Vim user!"
+msgstr "Blahopøeji, u¾ivateli Vimu!"
+
+msgid "Edit File in new window"
+msgstr "Editovat soubor v novém oknì"
+
+msgid "No swap file"
+msgstr "®ádný odkládací soubor"
+
+msgid "Append File"
+msgstr "Ulo¾it soubor"
+
+msgid "E186: No previous directory"
+msgstr "E186: ®ádný pøedchozí adresáø"
+
+msgid "E187: Unknown"
+msgstr "E187: Neznámý"
+
+#, c-format
+msgid "Window position: X %d, Y %d"
+msgstr "Umístìní okna: X %d, Y %d"
+
+msgid "E188: Obtaining window position not implemented for this platform"
+msgstr "E188: Na této platformì nelze umístìní okna zjistit"
+
+msgid "Save Redirection"
+msgstr "Ulo¾it pøesmìrování"
+
+msgid "Save View"
+msgstr "Ulo¾it pohled"
+
+msgid "Save Session"
+msgstr "Ulo¾it sezení"
+
+msgid "Save Setup"
+msgstr "Ulo¾it nastavení"
+
+#, c-format
+msgid "E189: \"%s\" exists (use ! to override)"
+msgstr "E189: \"%s\" existuje (pou¾ijte ! pro vynucení)"
+
+#, c-format
+msgid "E190: Cannot open \"%s\" for writing"
+msgstr "E190: Nelze otevøít \"%s\" pro zápis"
+
+#. set mark
+msgid "E191: Argument must be a letter or forward/backward quote"
+msgstr "E191: Argumentem mù¾e být pouze písmeno nebo pravý èi levý apostrof"
+
+msgid "E192: Recursive use of :normal too deep"
+msgstr "E192: Vnoøení :normal je pøíli¹ hluboké"
+
+msgid ":if nesting too deep"
+msgstr "vnoøení :if je pøíli¹ hluboké"
+
+msgid ":endif without :if"
+msgstr ":endif bez odpovídajícího :if"
+
+msgid ":else without :if"
+msgstr ":else bez odpovídajícího :if"
+
+msgid ":elseif without :if"
+msgstr ":elseif bez odpovídajícího :if"
+
+msgid ":while nesting too deep"
+msgstr "vnoøení :while je pøíli¹ hluboké"
+
+msgid ":continue without :while"
+msgstr ":continue bez odpovídajícího :while"
+
+msgid ":break without :while"
+msgstr ":break bez odpovídajícího :while"
+
+msgid ":endwhile without :while"
+msgstr ":endwhile bez odpovídajícího :while"
+
+msgid "E193: :endfunction not inside a function"
+msgstr "E193: :endfunction mimo funkci"
+
+msgid "E194: No alternate file name to substitute for '#'"
+msgstr ""
+"E194: ®ádný alternativní název souboru, kterým by bylo mo¾né nahradit '#'"
+
+msgid "no autocommand file name to substitute for \"<afile>\""
+msgstr "®ádný název souboru, kterým by bylo mo¾né nahradit \"<afile>\""
+
+msgid "no autocommand buffer number to substitute for \"<abuf>\""
+msgstr "®ádné èíslo bufferu, kterým by bylo mo¾né nahradit \"<abuf>\""
+
+msgid "no autocommand match name to substitute for \"<amatch>\""
+msgstr ""
+"®ádná shoda automatických pøíkazù, kterou by bylo mo¾né nahradit \"<amatch>\""
+
+msgid "no :source file name to substitute for \"<sfile>\""
+msgstr "®ádný interpretovaný soubor, kterým by bylo mo¾né nahradit \"<sfile>\""
+
+#, no-c-format
+msgid "Empty file name for '%' or '#', only works with \":p:h\""
+msgstr "Prázdný název souboru pro '%' èi '#' funguje pouze s \":p:h\""
+
+msgid "Evaluates to an empty string"
+msgstr "Výsledkem vyhodnocení je prázdný øetìzec"
+
+msgid "E195: Cannot open viminfo file for reading"
+msgstr "E195: Nelze otevøít pro ètení viminfo soubor"
+
+msgid "E196: No digraphs in this version"
+msgstr "E196: V této verzi nejsou spøe¾ky podporovány"
+
+msgid "tagname"
+msgstr "jméno tagu"
+
+msgid " kind file\n"
+msgstr " typ soubor\n"
+
+msgid "'history' option is zero"
+msgstr "'volba 'history' je nastavena na nulu"
+
+#, c-format
+msgid ""
+"\n"
+"# %s History (newest to oldest):\n"
+msgstr ""
+"\n"
+"# Historie %s (poèínaje nejnovìj¹í polo¾kou):\n"
+
+msgid "Command Line"
+msgstr "pøíkazové øádky"
+
+msgid "Search String"
+msgstr "vyhledávaných øetìzcù"
+
+msgid "Expression"
+msgstr "výrazù"
+
+msgid "Input Line"
+msgstr "vstupní øádky"
+
+msgid "E198: cmd_pchar beyond the command length"
+msgstr "E198: cmd_pchar pøekraèuje délku pøíkazu"
+
+msgid "E199: Active window or buffer deleted"
+msgstr "E199: Smazáno aktivní okno èi buffer"
+
+msgid "Illegal file name"
+msgstr "nepøípustný název souboru"
+
+msgid "is a directory"
+msgstr "je adresáøem"
+
+msgid "is not a file"
+msgstr "není souborem"
+
+msgid "[New File]"
+msgstr "[nový soubor]"
+
+msgid "[Permission Denied]"
+msgstr "[pøístup odmítnut]"
+
+msgid "E200: *ReadPre autocommands made the file unreadable"
+msgstr "E200: *ReadPre automatické pøíkazy uèinily soubor neèitelným"
+
+msgid "E201: *ReadPre autocommands must not change current buffer"
+msgstr "E201: *ReadPre automatické pøíkazy nesmí mìnit aktuální buffer"
+
+msgid "Vim: Reading from stdin...\n"
+msgstr "Vim: Ètu ze standardního vstupu...\n"
+
+msgid "Reading from stdin..."
+msgstr "Ètu ze standardního vstupu..."
+
+#. Re-opening the original file failed!
+msgid "E202: Conversion made file unreadable!"
+msgstr "E202: Po konverzi je soubor neèitelný!"
+
+msgid "[fifo/socket]"
+msgstr "[pojmenovaná roura/soket]"
+
+msgid "[fifo]"
+msgstr "[pojmenovaná roura]"
+
+msgid "[socket]"
+msgstr "[soket]"
+
+msgid "[RO]"
+msgstr "[RO]"
+
+msgid "[CR missing]"
+msgstr "[chybí CR]"
+
+msgid "[NL found]"
+msgstr "[nalezeno NL]"
+
+msgid "[long lines split]"
+msgstr "[dlouhé øádky zalomeny]"
+
+msgid "[NOT converted]"
+msgstr "[nezkonvertován]"
+
+msgid "[converted]"
+msgstr "[zkonvertován]"
+
+msgid "[crypted]"
+msgstr "[za¹ifrován]"
+
+msgid "[CONVERSION ERROR]"
+msgstr "[CHYBA PØEVODU]"
+
+msgid "[READ ERRORS]"
+msgstr "[CHYBY ÈTENÍ]"
+
+msgid "Can't find temp file for conversion"
+msgstr "Nelze nalézt doèasný soubor pro konverzi"
+
+msgid "Conversion with 'charconvert' failed"
+msgstr "Konverze s 'charconvert' se nezdaøila"
+
+msgid "can't read output of 'charconvert'"
+msgstr "nelze èíst výstup 'charconvert'"
+
+msgid "E203: Autocommands deleted or unloaded buffer to be written"
+msgstr ""
+"E203: Automatické pøíkazy smazaly èi deaktivovaly buffer, který mìl být "
+"ulo¾en"
+
+msgid "E204: Autocommand changed number of lines in unexpected way"
+msgstr "E204: Automatický pøíkaz neèekaným zpùsobem zmìnil poèet øádkù"
+
+msgid "is not a file or writable device"
+msgstr "není souborem ani zaøízením na nì¾ lze zapisovat"
+
+msgid "is read-only (use ! to override)"
+msgstr "je pouze pro ètení (pou¾ijte ! pro vynucení)"
+
+msgid "Can't write to backup file (use ! to override)"
+msgstr "Nelze zapisovat do zálo¾ního souboru (pou¾ijte ! pro vynucení)"
+
+msgid "Close error for backup file (use ! to override)"
+msgstr "Chyba pøi uzavírání zálo¾ního souboru (pou¾ijte ! pro vynucení)"
+
+msgid "Can't read file for backup (use ! to override)"
+msgstr "Nelze naèíst soubor pro zálohu (pou¾ijte ! pro vynucení)"
+
+msgid "Cannot create backup file (use ! to override)"
+msgstr "Nelze vytvoøit zálo¾ní soubor (pou¾ijte ! pro vynucení)"
+
+msgid "Can't make backup file (use ! to override)"
+msgstr "Nelze vytvoøit zálo¾ní soubor (pou¾ijte ! pro vynucení)"
+
+# resource fork ?!
+msgid "The resource fork will be lost (use ! to override)"
+msgstr "'Resource fork' bude ztracen (pou¾ijte ! pro vynucení)"
+
+msgid "E214: Can't find temp file for writing"
+msgstr "E214: Nelze najít doèasný temp soubor pro zápis"
+
+msgid "E213: Cannot convert (use ! to write without conversion)"
+msgstr "E213: Nelze pøevést (pou¾ijte ! pro zápis bez pøevodu)"
+
+msgid "E166: Can't open linked file for writing"
+msgstr "E166: Nelze otevøít pøipojený soubor pro zápis"
+
+msgid "E212: Can't open file for writing"
+msgstr "E212: Nelze otevøít soubor pro zápis"
+
+msgid "Close failed"
+msgstr "Volání close selhalo"
+
+msgid "write error, conversion failed"
+msgstr "chyba pøi zápisu, konverze se nezdaøila"
+
+msgid "write error (file system full?)"
+msgstr "chyba pøi ukládání (je volné místo na disku?)"
+
+msgid " CONVERSION ERROR"
+msgstr " CHYBA PØEVODU"
+
+msgid "[Device]"
+msgstr "[zaøízení]"
+
+msgid "[New]"
+msgstr "[Nový]"
+
+msgid " [a]"
+msgstr " [p]"
+
+msgid " appended"
+msgstr " pøipojen"
+
+msgid " [w]"
+msgstr " [u]"
+
+msgid " written"
+msgstr " ulo¾en"
+
+msgid "E205: Patchmode: can't save original file"
+msgstr "E205: patchmode: nelze ulo¾it pùvodní soubor"
+
+msgid "E206: patchmode: can't touch empty original file"
+msgstr "E206: patchmode: nelze zapisovat do prázdného pùvodního souboru"
+
+msgid "E207: Can't delete backup file"
+msgstr "E207: Nelze smazat zálo¾ní soubor"
+
+msgid ""
+"\n"
+"WARNING: Original file may be lost or damaged\n"
+msgstr ""
+"\n"
+"VAROVÁNÍ: Obsah pùvodního souboru mù¾e být ztracen èi po¹kozen\n"
+
+msgid "don't quit the editor until the file is successfully written!"
+msgstr "neukonèujte editor døíve, ne¾ bude soubor úspì¹nì ulo¾en!"
+
+msgid "[dos]"
+msgstr "[dos]"
+
+msgid "[dos format]"
+msgstr "[dos formát]"
+
+msgid "[mac]"
+msgstr "[mac]"
+
+msgid "[mac format]"
+msgstr "[mac formát]"
+
+msgid "[unix]"
+msgstr "[unix]"
+
+msgid "[unix format]"
+msgstr "[unix formát]"
+
+msgid "1 line, "
+msgstr "1 øádek, "
+
+#, c-format
+msgid "%ld lines, "
+msgstr "%ld øádkù, "
+
+msgid "1 character"
+msgstr "1 znak"
+
+#, c-format
+msgid "%ld characters"
+msgstr "%ld znakù, "
+
+msgid "[noeol]"
+msgstr "[¾ádný eol]"
+
+msgid "[Incomplete last line]"
+msgstr "[neúplný poslední øádek]"
+
+#. don't overwrite messages here
+#. must give this prompt
+#. don't use emsg() here, don't want to flush the buffers
+msgid "WARNING: The file has been changed since reading it!!!"
+msgstr "VAROVÁNÍ: od jeho naètení byl obsah souboru zmìnìn!!!!"
+
+msgid "Do you really want to write to it"
+msgstr "Chcete jej opravdu ulo¾it"
+
+#, c-format
+msgid "E208: Error writing to \"%s\""
+msgstr "E208: Chyba pøi zápisu do \"%s\""
+
+#, c-format
+msgid "E209: Error closing \"%s\""
+msgstr "E209: Chyb pøi uzavírání \"%s\""
+
+#, c-format
+msgid "E210: Error reading \"%s\""
+msgstr "E210: Chyba pøi ètení \"%s\""
+
+msgid "E246: FileChangedShell autocommand deleted buffer"
+msgstr "E246: FileChangedShell autocommand zru¹il buffer"
+
+#, c-format
+msgid "E211: Warning: File \"%s\" no longer available"
+msgstr "E211: wa1: soubor \"%s\" ji¾ není dostupný"
+
+#, c-format
+msgid ""
+"W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as "
+"well"
+msgstr ""
+"W12: Varování: soubor \"%s\" byl po poèátku editace zmìnìn a buffer ve Vim "
+"také"
+
+#, c-format
+msgid "W11: Warning: File \"%s\" has changed since editing started"
+msgstr "W11: wc2: soubor \"%s\" byl po poèátku editace zmìnìn"
+
+#, c-format
+msgid "W16: Warning: Mode of file \"%s\" has changed since editing started"
+msgstr "W16: Varování: Mód souboru \"%s\" byl zmìnìn od zapoènutí editace"
+
+#, c-format
+msgid "W13: Warning: File \"%s\" has been created after editing started"
+msgstr "W13: wc4: po poèátku editace vytvoøen soubor \"%s\""
+
+msgid "Warning"
+msgstr "Varování"
+
+msgid ""
+"&OK\n"
+"&Load File"
+msgstr ""
+"&OK\n"
+"&Nahrát soubor"
+
+#, c-format
+msgid "E321: Could not reload \"%s\""
+msgstr "E321: Nelze znovuotevøít \"%s\""
+
+msgid "--Deleted--"
+msgstr "--Vymazáno--"
+
+#. the group doesn't exist
+#, c-format
+msgid "E367: No such group: \"%s\""
+msgstr "E367: Skupina \"%s\" neexistuje"
+
+#, c-format
+msgid "E215: Illegal character after *: %s"
+msgstr "E215: Nepøípustný znak po *: %s"
+
+#, c-format
+msgid "E216: No such event: %s"
+msgstr "E216: Událost %s neexistuje"
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Autocommands ---"
+msgstr ""
+"\n"
+"--- Automatické pøíkazy ---"
+
+msgid "E217: Can't execute autocommands for ALL events"
+msgstr "E217: Automatické pøíkazy nelze spustit pro V©ECHNY události"
+
+msgid "No matching autocommands"
+msgstr "®ádné vyhovující automatické pøíkazy"
+
+msgid "E218: autocommand nesting too deep"
+msgstr "E218: vnoøení automatického pøíkazu pøíli¹ hluboká"
+
+#, c-format
+msgid "%s Autocommands for \"%s\""
+msgstr "%s automatické pøíkazy pro \"%s\""
+
+#, c-format
+msgid "Executing %s"
+msgstr "spou¹tím %s"
+
+#. always scroll up, don't overwrite
+#, c-format
+msgid "autocommand %s"
+msgstr "Automatický pøíkaz %s"
+
+msgid "E219: Missing {."
+msgstr "E219: Chybí {."
+
+msgid "E220: Missing }."
+msgstr "E220: Chybí }."
+
+msgid "No fold found"
+msgstr "®ádný záhyb nebyl nalezen"
+
+msgid "E350: Cannot create fold with current 'foldmethod'"
+msgstr "E350: pomocí aktuální 'foldmethod' nelze vytvoøit záhyb"
+
+msgid "E351: Cannot delete fold with current 'foldmethod'"
+msgstr "E351: pomocí aktuální 'foldmethod' nelze vytvoøit záhyb"
+
+msgid "E221: 'commentstring' is empty"
+msgstr "E221: volba 'commentstring' je prázdná"
+
+msgid "E222: Add to read buffer"
+msgstr "E222: Pøidat do bufferu pro ètení"
+
+msgid "E223: recursive mapping"
+msgstr "E223: rekurzivní mapování"
+
+#, c-format
+msgid "E224: global abbreviation already exists for %s"
+msgstr "E224: pro %s ji¾ globální zkratka ji¾ existuje"
+
+#, c-format
+msgid "E225: global mapping already exists for %s"
+msgstr "E225: pro %s ji¾ globální mapování ji¾ existuje"
+
+#, c-format
+msgid "E226: abbreviation already exists for %s"
+msgstr "E226: pro %s ji¾ zkratka ji¾ existuje"
+
+#, c-format
+msgid "E227: mapping already exists for %s"
+msgstr "E227: pro %s ji¾ mapování ji¾ existuje"
+
+msgid "No abbreviation found"
+msgstr "®ádná zkratka nebyl nalezena"
+
+msgid "No mapping found"
+msgstr "®ádné mapování nebylo nalezeno"
+
+msgid "E228: makemap: Illegal mode"
+msgstr "E228: makemap: nepøípustný mód"
+
+msgid "E229: Cannot start the GUI"
+msgstr "E229: Nelze spustit GUI"
+
+#, c-format
+msgid "E230: Cannot read from \"%s\""
+msgstr "E230: Nelze èíst z \"%s\""
+
+msgid "E231: 'guifontwide' invalid"
+msgstr "E231: volba 'guifontwide' je chybnì nastavena"
+
+msgid "Error"
+msgstr "Chyba"
+
+msgid "&Ok"
+msgstr "&Ok"
+
+msgid "<cannot open> "
+msgstr "<nelze otevøít> "
+
+#, c-format
+msgid "vim_SelFile: can't get font %s"
+msgstr "vim_SelFile: písmo %s není dostupné"
+
+msgid "vim_SelFile: can't return to current directory"
+msgstr "vim_SelFile: nelze se vrátit do aktuálního adresáøe"
+
+msgid "Pathname:"
+msgstr "Název cesty:"
+
+msgid "vim_SelFile: can't get current directory"
+msgstr "vim_SelFile: nelze zjistit aktuální adresáø"
+
+msgid "OK"
+msgstr "OK"
+
+#. 'Cancel' button
+msgid "Cancel"
+msgstr "Zru¹it"
+
+msgid "Scrollbar Widget: Could not get geometry of thumb pixmap."
+msgstr "Pøípravek posunovací li¹ty: nelze zjistit geometrii obrázku"
+
+msgid "Vim dialog"
+msgstr "Vim dialog"
+
+msgid "E232: Cannot create BalloonEval with both message and callback"
+msgstr "E232: BalloonEval nelze vytvoøit se zprávou a zároveò zpìtným voláním"
+
+msgid "Vim dialog..."
+msgstr "Vim dialog.."
+
+msgid "VIM - Search and Replace..."
+msgstr "VIM - Nalézt a nahradit..."
+
+msgid "VIM - Search..."
+msgstr "VIM - Nalézt..."
+
+msgid "Find what:"
+msgstr "Vyhledat:"
+
+msgid "Replace with:"
+msgstr "Nový text:"
+
+#. exact match only button
+msgid "Match exact word only"
+msgstr "hledat pouze celá slova"
+
+msgid "Direction"
+msgstr "Smìr"
+
+#. 'Up' and 'Down' buttons
+msgid "Up"
+msgstr "Nahoru"
+
+msgid "Down"
+msgstr "Dolù"
+
+#. 'Find Next' button
+msgid "Find Next"
+msgstr "Najít dal¹í"
+
+#. 'Replace' button
+msgid "Replace"
+msgstr "Nahradit"
+
+#. 'Replace All' button
+msgid "Replace All"
+msgstr "Nahradit v¹e"
+
+msgid "E233: cannot open display"
+msgstr "E233: nelze otevøít display"
+
+#, c-format
+msgid "E234: Unknown fontset: %s"
+msgstr "E234: Neznámá sada písem: %s"
+
+msgid "Font Selection"
+msgstr "Výbìr písma"
+
+#, c-format
+msgid "E235: Unknown font: %s"
+msgstr "E235: Neznámé písmo: %s"
+
+#, c-format
+msgid "E236: Font \"%s\" is not fixed-width"
+msgstr "E236: Písmo \"%s\" nemá pevnou ¹íøku"
+
+#, c-format
+msgid "E242: Color name not recognized: %s"
+msgstr "E242: Neznámé jméno barvy: %s"
+
+msgid "Used CUT_BUFFER0 instead of empty selection"
+msgstr "Místo prádné schránky pou¾ito CUT_BUFFER0"
+
+msgid "Filter"
+msgstr "Filtr"
+
+msgid "Directories"
+msgstr "Adresáøe"
+
+msgid "Help"
+msgstr "Nápovìda"
+
+msgid "Files"
+msgstr "Soubory"
+
+msgid "Selection"
+msgstr "Výbìr"
+
+msgid "Undo"
+msgstr "Zpìt"
+
+#, c-format
+msgid "E235: Can't load Zap font '%s'"
+msgstr "E235: Nelze naèíst Zap font '%s'"
+
+#, c-format
+msgid "E235: Can't use font %s"
+msgstr "E235: Nelze pou¾ít font %s"
+
+#, c-format
+msgid "E242: Missing color: %s"
+msgstr "E242: Chybí barva: %s"
+
+msgid ""
+"\n"
+"Sending message to terminate child process.\n"
+msgstr ""
+"\n"
+"Posílám signál k ukonèení synovského procesu.\n"
+
+#, c-format
+msgid "E243: Argument not supported: \"-%s\"; Use the OLE version."
+msgstr "E243: Argument nepodporován: \"-%s\"; Pou¾ijte OLE verzi."
+
+msgid "Find string (use '\\\\' to find a '\\')"
+msgstr "Najít øetìzec (pou¾ijte '\\\\' k nalezení '\\')"
+
+msgid "Find & Replace (use '\\\\' to find a '\\')"
+msgstr "Najít & Nahradit (pou¾ijte '\\\\' k nalezení '\\')"
+
+msgid "Vim E458: Cannot allocate colormap entry, some colors may be incorrect"
+msgstr ""
+"Vim E458: nelze alokovat polo¾ku barevné mapy. Nìkteré barvy mohou být "
+"nesprávné"
+
+#, c-format
+msgid "E250: Fonts for the following charsets are missing in fontset %s:"
+msgstr "E250: písma pro následující znakové sady chybí v sadì písem %s:"
+
+#, c-format
+msgid "E252: Fontset name: %s"
+msgstr "E252: název sady písem: %s"
+
+#, c-format
+msgid "Font '%s' is not fixed-width"
+msgstr "Písmo '%s' nemá pevnou ¹íøku"
+
+#, c-format
+msgid "E253: Fontset name: %s\n"
+msgstr "E253: název sady písem: %s\n"
+
+#, c-format
+msgid "Font0: %s\n"
+msgstr "Písmo0: %s\n"
+
+#, c-format
+msgid "Font1: %s\n"
+msgstr "Písmo1: %s\n"
+
+#, c-format
+msgid "Font%d width is not twice that of font0\n"
+msgstr "©íøka písma%d není dvojnásoblem ¹íøky písma0\n"
+
+#, c-format
+msgid "Font0 width: %ld\n"
+msgstr "©íøka písma0: %ld\n"
+
+#, c-format
+msgid ""
+"Font1 width: %ld\n"
+"\n"
+msgstr ""
+"©íøka písma1: %ld\n"
+"\n"
+
+#, c-format
+msgid "E254: Cannot allocate color %s"
+msgstr "E254: nelze alokovat barvu %s"
+
+msgid "E255: Couldn't read in sign data!"
+msgstr "E255: Chyba -- nelze pøeèíst sign data!"
+
+msgid "E256: Hangul automata ERROR"
+msgstr "E256: CYBA Hangul automatu"
+
+msgid "Add a new database"
+msgstr "Pøidat novou databázi"
+
+msgid "Query for a pattern"
+msgstr "Hledání vzorku"
+
+msgid "Show this message"
+msgstr "Zobrazit tuto zprávu"
+
+msgid "Kill a connection"
+msgstr "Ukonèit spojení"
+
+msgid "Reinit all connections"
+msgstr "Znovu inicializovat v¹echna spojení"
+
+msgid "Show connections"
+msgstr "Zobrazit spojení"
+
+msgid "This cscope command does not support splitting the window.\n"
+msgstr "Tento cscope pøíkaz nepodporuje rozdìlení okna.\n"
+
+msgid "Usage: cstag <ident>"
+msgstr "Pou¾ití: cstag <odsazení>"
+
+msgid "E257: cstag: tag not found"
+msgstr "E257: cstag: tag nenalezen"
+
+#, c-format
+msgid "stat(%s) error: %d"
+msgstr "stat(%s) chyba: %d"
+
+#, c-format
+msgid "Added cscope database %s"
+msgstr "Pøidána cscope databáze %s"
+
+#, c-format
+msgid "%s is not a directory or a valid cscope database"
+msgstr "%s není ani adresáøem ani správnou cscope databází"
+
+#, c-format
+msgid "error reading cscope connection %d"
+msgstr "chyba pøi ètení cscope spojení %d"
+
+msgid "unknown cscope search type"
+msgstr "neznámý typ cscope hledání"
+
+msgid "Could not create cscope pipes"
+msgstr "nelze vytvoøit cscope roury"
+
+msgid "cs_create_connection exec failed"
+msgstr "spu¹tìní cs_create_connection selhalo"
+
+msgid "cs_create_connection: fdopen for to_fp failed"
+msgstr "cs_create_connection: volání fdopen pro to_fp selhalo"
+
+msgid "cs_create_connection: fdopen for fr_fp failed"
+msgstr "cs_create_connection: volání fdopen pro fr_fp selhalo"
+
+msgid "no cscope connections"
+msgstr "¾ádná cscope spojení"
+
+#, c-format
+msgid "E259: no matches found for cscope query %s of %s"
+msgstr "E259: cscope hledání %s vzorku %s nena¹lo ¾ádnou shodu"
+
+msgid "cscope commands:\n"
+msgstr "pøíkazy cscope:\n"
+
+#, c-format
+msgid "%-5s: %-30s (Usage: %s)\n"
+msgstr "%-5s: %-30s (Pou¾ití: %s)\n"
+
+msgid "duplicate cscope database not added"
+msgstr "duplicitní cscope databáze nebyla pøidána"
+
+msgid "maximum number of cscope connections reached"
+msgstr "dosa¾en maximální poèet cscope spojení"
+
+msgid "E260: cscope connection not found"
+msgstr "E260: connection spojení nenalezeno"
+
+#, c-format
+msgid "E261: cscope connection %s not found"
+msgstr "E261: connection spojení %s nenalezeno"
+
+msgid "cscope connection closed"
+msgstr "closed spojení uzavøeno"
+
+#, c-format
+msgid "cscope connection %s closed\n"
+msgstr "cscope spojení %s uzavøeno\n"
+
+#. should not reach here
+msgid "fatal error in cs_manage_matches"
+msgstr "osudová chyba v cs_manage_matches"
+
+#, c-format
+msgid "E262: error reading cscope connection %d"
+msgstr "E262: pøi ètení cscope spojení %d"
+
+msgid "couldn't malloc\n"
+msgstr "volání malloc selhalo\n"
+
+#, c-format
+msgid "Cscope tag: %s\n"
+msgstr "Cscope tag: %s\n"
+
+msgid " # line"
+msgstr " # øádek"
+
+msgid "filename / context / line\n"
+msgstr "název souboru/ kontext/ øádek\n"
+
+msgid "All cscope databases reset"
+msgstr "V¹echny cscope databáze resetovány"
+
+msgid "no cscope connections\n"
+msgstr "¾ádné cscope spojení\n"
+
+msgid " # pid database name prepend path\n"
+msgstr " # pid název databáze pøedpona cesty\n"
+
+#, c-format
+msgid "%2d %-5ld %-34s <none>\n"
+msgstr "%2d %-5ld %-34s <¾ádný>\n"
+
+msgid ""
+"E263: Sorry, this command is disabled, the Python library could not be "
+"loaded."
+msgstr ""
+"E263: Lituji, tento pøíkaz je deaktivován; knihovnu jazyka Python nelze "
+"nahrát."
+
+msgid "can't delete OutputObject attributes"
+msgstr "nelze smazat atributy OutputObject"
+
+msgid "softspace must be an integer"
+msgstr "softspace musí být kladné celé èíslo"
+
+msgid "invalid attribute"
+msgstr "chybný atribut"
+
+msgid "writelines() requires list of strings"
+msgstr "writelines() vy¾aduje seznam øetìzcù"
+
+msgid "E264: Python: Error initialising I/O objects"
+msgstr "E264: Python: chyba pøi inicializaci I/O objektù"
+
+msgid "invalid expression"
+msgstr "Chybný výraz"
+
+msgid "expressions disabled at compile time"
+msgstr "podpora výrazù byla vypnuta pøi pøekladu programu"
+
+msgid "attempt to refer to deleted buffer"
+msgstr "pokus o odkaz na smazaný buffer"
+
+msgid "line number out of range"
+msgstr "èíslo øádku mimo rozsah"
+
+#, c-format
+msgid "<buffer object (deleted) at %8lX>"
+msgstr "<buffer objekt (smazán) na %8lX>"
+
+msgid "invalid mark name"
+msgstr "chybné jméno znaèky"
+
+msgid "no such buffer"
+msgstr "¾ádný takový buffer"
+
+msgid "attempt to refer to deleted window"
+msgstr "pokus o odkaz na smazané okno"
+
+msgid "readonly attribute"
+msgstr "atribut pouze_pro_ètení"
+
+msgid "cursor position outside buffer"
+msgstr "umístìní kurzoru mimo buffer"
+
+#, c-format
+msgid "<window object (deleted) at %.8lX>"
+msgstr "<objekt okna (smazán) na %.8lX>"
+
+#, c-format
+msgid "<window object (unknown) at %.8lX>"
+msgstr "<objekt okna (neznámý) na %.8lX>"
+
+#, c-format
+msgid "<window %d>"
+msgstr "<okno %d>"
+
+msgid "no such window"
+msgstr "¾ádné takové okno"
+
+msgid "cannot save undo information"
+msgstr "nelze ulo¾it informace pro pøíkaz undo"
+
+msgid "cannot delete line"
+msgstr "nelze smazat øádek"
+
+msgid "cannot replace line"
+msgstr "nelze nahradit øádek"
+
+msgid "cannot insert line"
+msgstr "nelze vlo¾it øádek"
+
+msgid "string cannot contain newlines"
+msgstr "øetìzec nesmí obsahovat znaky nového øádku"
+
+msgid ""
+"E266: Sorry, this command is disabled, the Ruby library could not be loaded."
+msgstr ""
+"E266: Lituji, ale tento pøíkaz je deaktivován; knihovnu jazyka Ruby nelze "
+"nahrát."
+
+#, c-format
+msgid "E273: unknown longjmp status %d"
+msgstr "E273: neznámý longjmp stav %d"
+
+msgid "Toggle implementation/definition"
+msgstr "Prohození implementace/definice"
+
+msgid "Show base class of"
+msgstr "Zobrazení base class z"
+
+msgid "Show overridden member function"
+msgstr "Zobrazení overridden member funkce"
+
+msgid "Retrieve from file"
+msgstr "Znovuzískáno ze souboru"
+
+msgid "Retrieve from project"
+msgstr "Znovuzískáno z projektu"
+
+msgid "Retrieve from all projects"
+msgstr "Znovzískáno ze v¹ech projektù"
+
+msgid "Retrieve"
+msgstr "Znovuzískáno"
+
+msgid "Show source of"
+msgstr "Zobrazení zdroje"
+
+msgid "Find symbol"
+msgstr "Najít symbol"
+
+msgid "Browse class"
+msgstr "Prohlí¾et class"
+
+msgid "Show class in hierarchy"
+msgstr "Zobrazení class v hierarchii"
+
+msgid "Show class in restricted hierarchy"
+msgstr "Zobrazení class v restricted hierarchii"
+
+msgid "Xref refers to"
+msgstr "Xref odkazuje na"
+
+msgid "Xref referred by"
+msgstr "Xref odkazoval na"
+
+msgid "Xref has a"
+msgstr "Xref má"
+
+msgid "Xref used by"
+msgstr "Xref pou¾it"
+
+msgid "Show docu of"
+msgstr "Zobrazení documentace"
+
+msgid "Generate docu for"
+msgstr "Generována dokumentace pro"
+
+msgid ""
+"Cannot connect to SNiFF+. Check environment (sniffemacs must be found in "
+"$PATH).\n"
+msgstr ""
+"Nelze se pøipojit k SNiFF+. Zkontrolujte promìnné (sniffemacs musí "
+"být)uvedena v $PATH.\n"
+
+msgid "E274: Sniff: Error during read. Disconnected"
+msgstr "E274: Sniff: Chyba pøi ètení. Odpojeno"
+
+msgid "SNiFF+ is currently "
+msgstr "SNiFF+ je právì "
+
+msgid "not "
+msgstr "ne "
+
+msgid "connected"
+msgstr "pøipojen"
+
+#, c-format
+msgid "E275: Unknown SNiFF+ request: %s"
+msgstr "E275: Neznámý po¾adavek SNiFF+: %s"
+
+msgid "E276: Error connecting to SNiFF+"
+msgstr "E276: Chybné pøipojení k SNiFF+"
+
+msgid "E278: SNiFF+ not connected"
+msgstr "E278: SNiFF+ nepøipojen"
+
+msgid "E279: Not a SNiFF+ buffer"
+msgstr "E279: Není SNiFF+ buffer"
+
+msgid "Sniff: Error during write. Disconnected"
+msgstr "Sniff: Chyba pøi zápisu. Odpojeno."
+
+msgid "invalid buffer number"
+msgstr "chybný název bufferu"
+
+msgid "not implemented yet"
+msgstr "není je¹tì podporováno"
+
+msgid "unknown option"
+msgstr "neznámá volba"
+
+#. ???
+msgid "cannot set line(s)"
+msgstr "nelze nastavit øádky"
+
+msgid "mark not set"
+msgstr "znaèka není nastavena"
+
+#, c-format
+msgid "row %d column %d"
+msgstr "øádek %d sloupec %d"
+
+msgid "cannot insert/append line"
+msgstr "nelze vlo¾it/pøipojit øádek"
+
+msgid "unknown flag: "
+msgstr "neznámý pøíznak: "
+
+msgid "unknown vimOption"
+msgstr "neznámá vimOption"
+
+msgid "keyboard interrupt"
+msgstr "pøeru¹ení z klávesnice"
+
+msgid "vim error"
+msgstr "chyba vim"
+
+msgid "cannot create buffer/window command: object is being deleted"
+msgstr "nelze vytvoøit pøíkaz bufferu/okna: objekt smazán"
+
+msgid ""
+"cannot register callback command: buffer/window is already being deleted"
+msgstr ""
+"nelze zaregistrovat pøíkaz zpìtného volání: buffer/okno ji¾ bylo smazáno"
+
+#. This should never happen. Famous last word?
+msgid ""
+"E280: TCL FATAL ERROR: reflist corrupt!? Please report this to "
+"vim-dev@vim.org"
+msgstr ""
+"E280: TCL FATAL ERROR: reflist po¹kozen!? Oznamte, prosím, tuto chybu na "
+"vim-dev@vim.org"
+
+msgid "cannot register callback command: buffer/window reference not found"
+msgstr ""
+"nelze zaregistrovat pøíkaz zpìtného volání: odkaz na buffer/okno nenalezen"
+
+msgid "Sorry, this command is disabled: the Tcl library could not be loaded."
+msgstr ""
+"Lituji, ale tento pøíkaz je deaktivován; knihovnu jazyka Tcl nelze nahrát."
+
+msgid ""
+"E281: TCL ERROR: exit code is not int!? Please report this to vim-dev@vim.org"
+msgstr ""
+"E281: TCL CHYBA: návratový kód není celé èíslo!? Oznamte, prosím, tuto chybu "
+"na vim-dev@vim.org"
+
+msgid "cannot get line"
+msgstr "nelze pøeèíst øádek"
+
+msgid "Unable to register a command server name"
+msgstr "Není mo¾né zaznamenat jméno command serveru"
+
+#, c-format
+msgid "E247: no registered server named \"%s\""
+msgstr "E247: Neexistuje registrovaný server jménem \"%s\""
+
+msgid "E248: Failed to send command to the destination program"
+msgstr "E248: Selhalo zaslání pøíkazu urèenému programu"
+
+#, c-format
+msgid "Invalid server id used: %s"
+msgstr "Pou¾it chybný id serveru: %s"
+
+msgid "E249: couldn't read VIM instance registry property"
+msgstr "E249: nelze èíst VIM instanci registry property"
+
+msgid "E251: VIM instance registry property is badly formed. Deleted!"
+msgstr ""
+"E251: VIM instance registry property byla ¹patnì vytvoøenaa byla smazána!"
+
+msgid "Unknown option"
+msgstr "Neznámá volba"
+
+msgid "Too many edit arguments"
+msgstr "Pøíli¹ mnoho edit argumentù"
+
+msgid "Argument missing after"
+msgstr "Chybí argument po"
+
+msgid "Garbage after option"
+msgstr "Chyby za volbou"
+
+msgid "Too many \"+command\" or \"-c command\" arguments"
+msgstr "Pøíli¹ mnoho \"+pøíkaz\" èi \"-c pøíkaz\" argumentù"
+
+msgid "Invalid argument for"
+msgstr "Chybný argument pro"
+
+msgid "This Vim was not compiled with the diff feature."
+msgstr "VIM nebyl pøelo¾en s volbou +diff"
+
+msgid "Attempt to open script file again: \""
+msgstr "Pokus o opìtovné otevøení skriptu: \""
+
+msgid "\"\n"
+msgstr "\"\n"
+
+msgid "Cannot open for reading: \""
+msgstr "Nelze otevøít pro zápis: \""
+
+msgid "Cannot open for script output: \""
+msgstr "Nelze otevøít pro výstup skriptu: \""
+
+#, c-format
+msgid "%d files to edit\n"
+msgstr "poèet souborù pro editaci: %d\n"
+
+msgid "Vim: Warning: Output is not to a terminal\n"
+msgstr "Vim: Varování: výstup nesmìøuje na terminál\n"
+
+msgid "Vim: Warning: Input is not from a terminal\n"
+msgstr "Vim: Varování: vstup nepochází z terminálu\n"
+
+#. just in case..
+msgid "pre-vimrc command line"
+msgstr "pre-vimrc pøíkazový øádek"
+
+#, c-format
+msgid "E282: Cannot read from \"%s\""
+msgstr "E282: Nelze èíst z \"%s\""
+
+msgid ""
+"\n"
+"More info with: \"vim -h\"\n"
+msgstr ""
+"\n"
+"Podrobnìj¹í informace získáte pomocí \"vim -h\"\n"
+
+msgid "[file ..] edit specified file(s)"
+msgstr "[SOUBOR] .. editovat SOUBOR(y)"
+
+msgid "- read text from stdin"
+msgstr "- èíst text ze standardního vstupu"
+
+msgid "-t tag edit file where tag is defined"
+msgstr "-t TAG editovat soubor na místì definice TAGU"
+
+msgid "-q [errorfile] edit file with first error"
+msgstr "-q [chybový soubor] editovat soubor na místì výskytu první chyby"
+
+msgid ""
+"\n"
+"\n"
+"Usage:"
+msgstr ""
+"\n"
+"\n"
+"pou¾ití:"
+
+msgid " vim [arguments] "
+msgstr "vim [pøepínaèe] "
+
+msgid ""
+"\n"
+" or:"
+msgstr ""
+"\n"
+" nebo"
+
+msgid ""
+"\n"
+"\n"
+"Arguments:\n"
+msgstr ""
+"\n"
+"\n"
+"Argumenty:\n"
+
+msgid "--\t\t\tOnly file names after this"
+msgstr "--\t\t\tMohou následovat pouze názvy souborù"
+
+msgid "-register\t\tRegister this gvim for OLE"
+msgstr "-register\t\tpøihlásit gvim na OLE"
+
+msgid "-unregister\t\tUnregister gvim for OLE"
+msgstr "-register\t\todhlásit gvim z OLE"
+
+msgid "-g\t\t\tRun using GUI (like \"gvim\")"
+msgstr "-g\t\t\tspustit v GUI re¾imu (stejné jako \"gvim\")"
+
+msgid "-f\t\t\tForeground: Don't fork when starting GUI"
+msgstr "-f\t\t\tPopøedí: pøi startu GUI se neoddìlí od shellu"
+
+msgid "-v\t\t\tVi mode (like \"vi\")"
+msgstr "-v\t\t\tVi mód (stejné jako \"vi\")"
+
+msgid "-e\t\t\tEx mode (like \"ex\")"
+msgstr "-v\t\t\tEx mód (stejné jako \"ex\")"
+
+msgid "-s\t\t\tSilent (batch) mode (only for \"ex\")"
+msgstr "-s\t\t\tTichý (dávkový) re¾im (pouze pro \"ex\")"
+
+msgid "-d\t\t\tDiff mode (like \"vimdiff\")"
+msgstr "-d\t\t\tDiff re¾im (stejné jako \"vimdiff\")"
+
+msgid "-y\t\t\tEasy mode (like \"evim\", modeless)"
+msgstr "-v\t\t\tSnadný re¾im (stejné jako \"evim\", ¾ádné módy )"
+
+msgid "-R\t\t\tReadonly mode (like \"view\")"
+msgstr "-R\t\t\tRe¾im pouze_pro_ètení (jako \"view\")"
+
+msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
+msgstr "-Z\t\t\tOmezený re¾im (stejné jako \"rvim\")"
+
+msgid "-m\t\t\tModifications (writing files) not allowed"
+msgstr "-m\t\t\tZmìny (ukládání souborù) zakázány"
+
+msgid "-M\t\t\tModifications in text not allowed"
+msgstr "-M\t\t\tZmìny (ukládání souborù) zakázány"
+
+msgid "-b\t\t\tBinary mode"
+msgstr "-b\t\t\tBinární re¾im"
+
+msgid "-l\t\t\tLisp mode"
+msgstr "-l\t\t\tLisp re¾im"
+
+msgid "-C\t\t\tCompatible with Vi: 'compatible'"
+msgstr "-C\t\t\tKompatabilní s Vi: 'compatible'"
+
+msgid "-N\t\t\tNot fully Vi compatible: 'nocompatible'"
+msgstr "-N\t\t\tKompatibilita s Vi vypnuta: 'nocompatible'"
+
+msgid "-V[N]\t\tVerbose level"
+msgstr "-V[N]\t\tÚroveò výpisu hlá¹ek"
+
+msgid "-D\t\t\tDebugging mode"
+msgstr "-D\t\t\tLadící re¾im"
+
+msgid "-n\t\t\tNo swap file, use memory only"
+msgstr "-n\t\t\tNebude vytváøet odkládací soubor, bude pou¾ívat pouze pamì»"
+
+msgid "-r\t\t\tList swap files and exit"
+msgstr "-r\t\t\tVypí¹e seznam odkládacích souborù a skonèí"
+
+msgid "-r (with file name)\tRecover crashed session"
+msgstr "-r název souboru\tObnoví pøeru¹ené sezení"
+
+msgid "-L\t\t\tSame as -r"
+msgstr "-L\t\t\tStejné jako -r"
+
+msgid "-f\t\t\tDon't use newcli to open window"
+msgstr "-f\t\t\tNebude pou¾ívat newcli pro otevøení okna"
+
+msgid "-dev <device>\t\tUse <device> for I/O"
+msgstr "-dev <zaøízení>\t\tPou¾ít <zaøízení> pro I/O"
+
+msgid "-H\t\t\tstart in Hebrew mode"
+msgstr "-H\t\t\tnastartuje v hebrejském re¾imu"
+
+msgid "-F\t\t\tstart in Farsi mode"
+msgstr "-F\t\t\tnastartuje ve Farsi re¾imu"
+
+msgid "-T <terminal>\tSet terminal type to <terminal>"
+msgstr "-T <terminál>\tNastaví typ terminálu na <terminál>"
+
+msgid "-u <vimrc>\t\tUse <vimrc> instead of any .vimrc"
+msgstr "-u <vimrc>\t\tPou¾ije <vimrc> místo jakéhokoliv .vimrc"
+
+msgid "-U <gvimrc>\t\tUse <gvimrc> instead of any .gvimrc"
+msgstr "-U <gvimrc>\t\tPou¾ije <gvimrc> místo jakéhokoliv .gvimrc"
+
+msgid "--noplugin\t\tDon't load plugin scripts"
+msgstr "--noplugin\t\tNenahraje 'plugin' skripty"
+
+msgid "-o[N]\t\tOpen N windows (default: one for each file)"
+msgstr "-o[N]\t\tOtevøe N oken (implicitnì jedno pro ka¾dý soubor)"
+
+msgid "-O[N]\t\tlike -o but split vertically"
+msgstr "-O[N]\t\tJako -o but split vertically"
+
+msgid "+\t\t\tStart at end of file"
+msgstr "+\t\t\tNastaví kurzor na konec souboru"
+
+msgid "+<lnum>\t\tStart at line <lnum>"
+msgstr "+<øádek>\t\tNastaví kurzor na <øádek>"
+
+msgid "--cmd <command>\tExecute <command> before loading any vimrc file"
+msgstr "--cmd <pøíkaz>\tPo nahrání prvního souboru vykoná <pøíkaz>"
+
+msgid "-c <command>\t\tExecute <command> after loading the first file"
+msgstr "-c <pøíkaz>\t\tPo nahrání prvního souboru vykoná <pøíkaz>"
+
+msgid "-S <session>\t\tSource file <session> after loading the first file"
+msgstr ""
+"-S <sezení>\t\tPo nahrání prvního souboru vykoná pøíkazy v souboru <sezení>"
+
+msgid "-s <scriptin>\tRead Normal mode commands from file <scriptin>"
+msgstr "-s <skript>\t\tNaète pøíkazy normálního módu ze <skriptu>"
+
+msgid "-w <scriptout>\tAppend all typed commands to file <scriptout>"
+msgstr "-w <skript>\t\tPøipojí v¹echny napsané pøíkazy do souboru <skript>"
+
+msgid "-W <scriptout>\tWrite all typed commands to file <scriptout>"
+msgstr "-W <skript>\t\tUlo¾í v¹echny napsané pøíkazy do souboru <skript>"
+
+msgid "-x\t\t\tEdit encrypted files"
+msgstr "-x\t\t\tEditace za¹ifrovaných souborù"
+
+msgid "-display <display>\tConnect vim to this particular X-server"
+msgstr "-display <display>\tSpustí vim na daný X-server"
+
+msgid "-X\t\t\tDo not connect to X server"
+msgstr "-X\t\t\tNepøipojí se k X serveru"
+
+msgid "--socketid <xid>\tOpen Vim inside another GTK widget"
+msgstr "--socketid <xid>\tOtevøe Vim uvnitø jiného GTK widgetu"
+
+msgid "--remote <files>\tEdit <files> in a Vim server and exit"
+msgstr "--remote <soubory>\tEdituje <soubory> na Vim serveru a skonèí"
+
+msgid ""
+"--remote-wait <files> As --remote but wait for files to have been edited"
+msgstr ""
+"--remote-wait <soubory> Jako --remote, ale èeká na soubory k editaci"
+
+msgid "--remote-send <keys>\tSend <keys> to a Vim server and exit"
+msgstr "--remote-send <klávesy>\tPøedá <klávesy> Vim serveru a skonèí"
+
+msgid "--remote-expr <expr>\tEvaluate <expr> in a Vim server and print result"
+msgstr "--remote-expr <výraz>\tProvede <výraz> na serveru a zobrazí výsledek"
+
+msgid "--serverlist\t\tList available Vim server names and exit"
+msgstr "--serverlist\t\tVypí¹e seznam dostupných Vim serverù a skonèí"
+
+msgid "--servername <name>\tSend to/become the Vim server <name>"
+msgstr ""
+"--servername <jméno>\tZa¹le serveru <jméno>/stane se Vim serverem <jméno>"
+
+msgid "-i <viminfo>\t\tUse <viminfo> instead of .viminfo"
+msgstr "-i <viminfo>\t\tPou¾ije <viminfo> místo jakéhokoliv .viminfo"
+
+msgid "-h\t\t\tprint Help (this message) and exit"
+msgstr "-h\t\t\tVypí¹e tuto nápovìdu a skonèí"
+
+msgid "--version\t\tprint version information and exit"
+msgstr "--version\t\tvypí¹e informace o verzi a skonèí"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Motif version):\n"
+msgstr ""
+"\n"
+"Pøepínaèe pro gvim (Motif verzi):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Athena version):\n"
+msgstr ""
+"\n"
+"Pøepínaèe pro gvim (Athena verzi):\n"
+
+msgid "-display <display>\tRun vim on <display>"
+msgstr "-display <display>\tSpustí vim na <display>"
+
+msgid "-iconic\t\tStart vim iconified"
+msgstr "-iconic\t\tSpustí vim minimalizované"
+
+msgid "-name <name>\t\tUse resource as if vim was <name>"
+msgstr "-name <název>\t\tPou¾ije resource jako by vim mìl <název>"
+
+msgid "\t\t\t (Unimplemented)\n"
+msgstr "\t\t\t (není implementováno)\n"
+
+msgid "-background <color>\tUse <color> for the background (also: -bg)"
+msgstr "-background <barva>\tNastaví <barvu> pozadí (také -bg)"
+
+msgid "-foreground <color>\tUse <color> for normal text (also: -fg)"
+msgstr "-foreground <barva>\tNastaví <barvu> popøedí (také -fg)"
+
+msgid "-font <font>\t\tUse <font> for normal text (also: -fn)"
+msgstr "-font <písmo>\t\tNastaví <písmo> normálního textu (také -fn)"
+
+msgid "-boldfont <font>\tUse <font> for bold text"
+msgstr "-boldfont <písmo>\tNastaví <písmo> pro zvýraznìný text"
+
+msgid "-italicfont <font>\tUse <font> for italic text"
+msgstr "-italicfont <písmo>\tNastaví <písmo> pro kurzívu"
+
+msgid "-geometry <geom>\tUse <geom> for initial geometry (also: -geom)"
+msgstr "-geometry <geometrie>\tNastaví <geometrii> (také -geom)"
+
+msgid "-borderwidth <width>\tUse a border width of <width> (also: -bw)"
+msgstr "-borderwidth <¹íøka>\tNastaví <¹íøku> okrajù (také -bw)"
+
+msgid "-scrollbarwidth <width> Use a scrollbar width of <width> (also: -sw)"
+msgstr "-scrollbarwidth <¹íøku> Nastaví <¹íøku> posunovací li¹ty (také: -sw)"
+
+msgid "-menuheight <height>\tUse a menu bar height of <height> (also: -mh)"
+msgstr "-menuheight <vý¹ka>\tNastaví <vý¹ku> nabídky (také -mh)"
+
+msgid "-reverse\t\tUse reverse video (also: -rv)"
+msgstr "-reverse\t\tPou¾ije reverzní barvy (také -rv)"
+
+msgid "+reverse\t\tDon't use reverse video (also: +rv)"
+msgstr "+reverse\t\tNepou¾ije reverzní barvy (také +rv)"
+
+msgid "-xrm <resource>\tSet the specified resource"
+msgstr "-xrm <resource>\tNastaví zadaný <resource>"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (RISC OS version):\n"
+msgstr ""
+"\n"
+"Pøepínaèe pro gvim (RISC OS verzi):\n"
+
+msgid "--columns <number>\tInitial width of window in columns"
+msgstr "--columns <poèet>\t<poèet> sloupcù na okno"
+
+msgid "--rows <number>\tInitial height of window in rows"
+msgstr "--rows <poèet>\t<poèet> øádkù na okno"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (GTK+ version):\n"
+msgstr ""
+"\n"
+"Pøepínaèe pro gvim (GTK+ verzi):\n"
+
+msgid "-display <display>\tRun vim on <display> (also: --display)"
+msgstr "-display <display>\tSpustí vim na <display> (také --display)"
+
+msgid "--help\t\tShow Gnome arguments"
+msgstr "--help\t\tVypí¹e Gnome pøepínaèe"
+
+#. Failed to send, abort.
+msgid ""
+"\n"
+"Send failed.\n"
+msgstr ""
+"\n"
+"Pøedání výrazu selhalo.\n"
+
+#. Let vim start normally.
+msgid ""
+"\n"
+"Send failed. Trying to execute locally\n"
+msgstr ""
+"\n"
+"Pøedání selhalo. Zkou¹ím provést lokálnì\n"
+
+#, c-format
+msgid "%d of %d edited"
+msgstr "%d z %d editováno"
+
+msgid "Send expression failed.\n"
+msgstr "Pøedání výrazu selhalo.\n"
+
+msgid "No marks set"
+msgstr "Nejsou nastaveny ¾ádné znaèky"
+
+#, c-format
+msgid "E283: No marks matching \"%s\""
+msgstr "E283: \"%s\" nevyhovují ¾ádné znaèky"
+
+#. Highlight title
+msgid ""
+"\n"
+"mark line col file/text"
+msgstr ""
+"\n"
+"znaèka øádek sloupec soubor/text"
+
+#. Highlight title
+msgid ""
+"\n"
+" jump line col file/text"
+msgstr ""
+"\n"
+" skok øádek sloupec soubor/text"
+
+msgid ""
+"\n"
+"# File marks:\n"
+msgstr ""
+"\n"
+"# Souborové znaèky:\n"
+
+#. Write the jumplist with -'
+msgid ""
+"\n"
+"# Jumplist (newest first):\n"
+msgstr ""
+"\n"
+"# Seznam skokù (poèínaje nejnovìj¹í polo¾kou):\n"
+
+msgid ""
+"\n"
+"# History of marks within files (newest to oldest):\n"
+msgstr ""
+"\n"
+"# Historie znaèek v souborech (poèínaje nejnovìj¹í polo¾kou):\n"
+
+msgid "Missing '>'"
+msgstr "Chybí '>'"
+
+msgid "Not a valid codepage"
+msgstr "Chybná kódová stránka"
+
+msgid "E284: Cannot set IC values"
+msgstr "E284: Nelze nastavit IC hodnoty"
+
+msgid "E285: Failed to create input context"
+msgstr "E285: Nepodaøilo se vytvoøit vstupní kontext"
+
+msgid "E286: Failed to open input method"
+msgstr "E286: Nepodaøilo se otevøít vstupní metodu"
+
+msgid "E287: Warning: Could not set destroy callback to IM"
+msgstr "E287: Varování: likvidaèní zpìtné volání nelze nastavit na IM"
+
+msgid "E288: input method doesn't support any style"
+msgstr "E288: vstupní metoda nepodporuje ¾ádný styl"
+
+msgid "E289: input method doesn't support my preedit type"
+msgstr "E289: vstupní metoda nepodporuje mùj 'preedit' typ"
+
+msgid "E290: over-the-spot style requires fontset"
+msgstr "E290: Nadbodový styl vy¾aduje fontset"
+
+msgid "E291: Your GTK+ is older than 1.2.3. Status area disabled"
+msgstr "E291: Máte GTK+ verze star¹í ne¾ 1.2.3. Stavová plocha vypnuta."
+
+msgid "E292: Input Method Server is not running"
+msgstr "E292: Server vstupních metod nebì¾í"
+
+msgid "E293: block was not locked"
+msgstr "E293: blok nebyl zamknut"
+
+msgid "E294: Seek error in swap file read"
+msgstr "E294: Chyba posunu ukazovátka pøi ètení odkládacího souboru"
+
+msgid "E295: Read error in swap file"
+msgstr "E295: Chyba pøi ètení odkládacího souboru"
+
+msgid "E296: Seek error in swap file write"
+msgstr "E296: Chyba posunu ukazovátka pøi ukládání do odkládacího souboru"
+
+msgid "E297: Write error in swap file"
+msgstr "E297: Chyba pøi ukládání do odkládacího souboru"
+
+msgid "E300: Swap file already exists (symlink attack?)"
+msgstr ""
+"E300: Odkládací soubor ji¾ existuje! (Nìkdo hackujepøes nastra¾ený symlink?)"
+
+msgid "E298: Didn't get block nr 0?"
+msgstr "E298: Nelze získat blok 0?"
+
+msgid "E298: Didn't get block nr 1?"
+msgstr "E298: Nelze získat blok 1?"
+
+msgid "E298: Didn't get block nr 2?"
+msgstr "E298: nelze získat blok 2?"
+
+#. could not (re)open the swap file, what can we do????
+msgid "E301: Oops, lost the swap file!!!"
+msgstr "E301: Jéje, odkládací soubor byl ztracen!!!"
+
+msgid "E302: Could not rename swap file"
+msgstr "E302: Nelze pøejmenovat odkládací soubor"
+
+#, c-format
+msgid "E303: Unable to open swap file for \"%s\", recovery impossible"
+msgstr "E303: Nelze otevøít odkládací soubor pro \"%s\""
+
+msgid "E304: ml_timestamp: Didn't get block 0??"
+msgstr "E304: ml_timestamp: nelze získat blok 0??"
+
+#, c-format
+msgid "E305: No swap file found for %s"
+msgstr "E305: Odkládací soubor pro %s nebyl nalezen"
+
+msgid "Enter number of swap file to use (0 to quit): "
+msgstr ""
+"Zadejte èíslo odkládacího souboru, který se má pou¾ít (0 pro ukonèení): "
+
+#, c-format
+msgid "E306: Cannot open %s"
+msgstr "E306: Nelze otevøít %s"
+
+msgid "Unable to read block 0 from "
+msgstr "Nelze èíst blok 0 z "
+
+msgid ""
+"\n"
+"Maybe no changes were made or Vim did not update the swap file."
+msgstr ""
+"\n"
+"Mo¾ná nedo¹lo k ¾ádným zmìnám, nebo Vim neaktualizoval odkládací soubor."
+
+msgid " cannot be used with this version of Vim.\n"
+msgstr " nelze pou¾ít s touto verzí Vim.\n"
+
+msgid "Use Vim version 3.0.\n"
+msgstr "Pou¾ijte Vim verze 3.0.\n"
+
+#, c-format
+msgid "E307: %s does not look like a Vim swap file"
+msgstr "E307: %s se nezdá být odkládacím souborem Vim"
+
+msgid " cannot be used on this computer.\n"
+msgstr " nelze pou¾ít na tomto poèítaèi.\n"
+
+msgid "The file was created on "
+msgstr "Soubor byl vytvoøen "
+
+msgid ""
+",\n"
+"or the file has been damaged."
+msgstr ""
+",\n"
+"nebo byl soubor po¹kozen."
+
+#, c-format
+msgid "Using swap file \"%s\""
+msgstr "Pou¾ívám odkládací soubor \"%s\""
+
+#, c-format
+msgid "Original file \"%s\""
+msgstr "Pùvodní soubor \"%s\""
+
+msgid "E308: Warning: Original file may have been changed"
+msgstr "E308: Varování: Pùvodní soubor mohl být zmìnìn"
+
+#, c-format
+msgid "E309: Unable to read block 1 from %s"
+msgstr "E309: Nelze èíst blok 1 z %s"
+
+msgid "???MANY LINES MISSING"
+msgstr "???CHYBÍ MNOHO ØÁDKÙ"
+
+msgid "???LINE COUNT WRONG"
+msgstr "???CHYBNÝ POÈET ØÁDKÙ"
+
+msgid "???EMPTY BLOCK"
+msgstr "???PRÁZDNÝ BLOK"
+
+msgid "???LINES MISSING"
+msgstr "???CHYBÌJÍCÍ ØÁDKY"
+
+#, c-format
+msgid "E310: Block 1 ID wrong (%s not a .swp file?)"
+msgstr "E310: ID bloku 1 je chybné (je %s odkládacím souborem?)"
+
+msgid "???BLOCK MISSING"
+msgstr "???CHYBÍ BLOK"
+
+msgid "??? from here until ???END lines may be messed up"
+msgstr "od ??? po ???END mohou být øádky pomíchané"
+
+msgid "??? from here until ???END lines may have been inserted/deleted"
+msgstr "od ??? po ???END mohou být vlo¾ené/smazané øádky"
+
+msgid "???END"
+msgstr "???KONEC"
+
+msgid "E311: Recovery Interrupted"
+msgstr "E311: Obnova pøeru¹ena"
+
+msgid ""
+"E312: Errors detected while recovering; look for lines starting with ???"
+msgstr ""
+"E312: V prùbìhu obnovy do¹lo k chybám; zkontrolujte øádky zaèínající na ???"
+
+msgid "Recovery completed. You should check if everything is OK."
+msgstr "Obnova dokonèena. Zkontrolujte, zda je v¹e v poøádku."
+
+msgid ""
+"\n"
+"(You might want to write out this file under another name\n"
+msgstr ""
+"\n"
+"(Zva¾te ulo¾ení tohoto souboru pod jiným názvem\n"
+
+msgid "and run diff with the original file to check for changes)\n"
+msgstr "a kontrolu zmìn pomocí programu diff.)\n"
+
+#. use msg() to start the scrolling properly
+msgid "Swap files found:"
+msgstr "Nalezené odkládací soubory:"
+
+msgid " In current directory:\n"
+msgstr " V aktuálním adresáøi:\n"
+
+msgid " Using specified name:\n"
+msgstr " Se zadaným názvem:\n"
+
+msgid " In directory "
+msgstr " V adresáøi "
+
+msgid " -- none --\n"
+msgstr " -- ¾ádné --\n"
+
+msgid " owned by: "
+msgstr " vlastník: "
+
+msgid " dated: "
+msgstr " datum vytvoøení: "
+
+msgid " dated: "
+msgstr " datum vytvoøení: "
+
+msgid " [from Vim version 3.0]"
+msgstr " [od Vim verze 3.0]"
+
+msgid " [does not look like a Vim swap file]"
+msgstr " [nevypadá jako odkládací soubor Vim]"
+
+msgid " file name: "
+msgstr " název souboru: "
+
+msgid ""
+"\n"
+" modified: "
+msgstr ""
+"\n"
+" datum zmìny: "
+
+msgid "YES"
+msgstr "ANO"
+
+msgid "no"
+msgstr "ne"
+
+msgid ""
+"\n"
+" user name: "
+msgstr ""
+"\n"
+" u¾ivatelské jméno: "
+
+msgid " host name: "
+msgstr " název poèítaèe: "
+
+msgid ""
+"\n"
+" host name: "
+msgstr ""
+"\n"
+" název poèítaèe: "
+
+msgid ""
+"\n"
+" process ID: "
+msgstr ""
+"\n"
+" ID procesu : "
+
+msgid " (still running)"
+msgstr " (stále aktivní)"
+
+msgid ""
+"\n"
+" [not usable with this version of Vim]"
+msgstr ""
+"\n"
+" [nepou¾itelné s touto verzí Vim]"
+
+msgid ""
+"\n"
+" [not usable on this computer]"
+msgstr ""
+"\n"
+" [nepou¾itelné na tomto poèítaèi]"
+
+msgid " [cannot be read]"
+msgstr " [nelze pøeèíst]"
+
+msgid " [cannot be opened]"
+msgstr " [nelze otevøít]"
+
+msgid "E313: Cannot preserve, there is no swap file"
+msgstr "E313: Nelze zachovat - odkládací soubor neexistuje."
+
+msgid "File preserved"
+msgstr "Soubor zachován"
+
+msgid "E314: Preserve failed"
+msgstr "E314: Uchování se nezdaøilo"
+
+#, c-format
+msgid "E315: ml_get: invalid lnum: %ld"
+msgstr "E315: ml_get: chybné èíslo øádku: %ld"
+
+#, c-format
+msgid "E316: ml_get: cannot find line %ld"
+msgstr "E316: ml_get: nelze nalézt øádek %ld"
+
+msgid "E317: pointer block id wrong 3"
+msgstr "E317: chybné id ukazatele na blok 3"
+
+msgid "stack_idx should be 0"
+msgstr "stack_idx by mìlo mít hodnotu 3"
+
+msgid "E318: Updated too many blocks?"
+msgstr "E318: Aktualizováno pøíli¹ mnoho blokù?"
+
+msgid "E317: pointer block id wrong 4"
+msgstr "E317: chybné id ukazatele na blok 4"
+
+msgid "deleted block 1?"
+msgstr "smazán blok 1?"
+
+#, c-format
+msgid "E320: Cannot find line %ld"
+msgstr "E320: Nelze nalézt øádek %ld"
+
+msgid "E317: pointer block id wrong"
+msgstr "E317: chybné id ukazatele na blok"
+
+msgid "pe_line_count is zero"
+msgstr "pe_line_count má nulovou hodnotu"
+
+#, c-format
+msgid "E322: line number out of range: %ld past the end"
+msgstr "E322: poèet øádkù mimo rozsah: %ld > celkový poèet øádkù"
+
+#, c-format
+msgid "E323: line count wrong in block %ld"
+msgstr "E323: chybný poèet øádkù v bloku %ld"
+
+msgid "Stack size increases"
+msgstr "Nárùst velikosti zásobníku"
+
+msgid "E317: pointer block id wrong 2"
+msgstr "E317: chybné id ukazatele na blok 2"
+
+msgid "E325: ATTENTION"
+msgstr "E325: POZOR"
+
+msgid ""
+"\n"
+"Found a swap file by the name \""
+msgstr ""
+"\n"
+"Nalezen odkládací soubor se jménem \""
+
+msgid "While opening file \""
+msgstr "Pøi otevírání souboru\""
+
+msgid " NEWER than swap file!\n"
+msgstr " NOVÌJ©Í ne¾ odkládací soubor!\n"
+
+#. Some of these messages are long to allow translation to
+#. * other languages.
+msgid ""
+"\n"
+"(1) Another program may be editing the same file.\n"
+" If this is the case, be careful not to end up with two\n"
+" different instances of the same file when making changes.\n"
+msgstr ""
+"\n"
+"(1) Soubor mù¾e být editován jiným programem.\n"
+" Je-li tomu tak, pak si dejte pozor, aby jste po ulo¾ení zmìn\n"
+" nemìli dvì rùzné verze tého¾ souboru.\n"
+
+msgid " Quit, or continue with caution.\n"
+msgstr " Ukonèete program, nebo opatrnì pokraèujte v editaci.\n"
+
+msgid ""
+"\n"
+"(2) An edit session for this file crashed.\n"
+msgstr ""
+"\n"
+"(2) Editace tohoto souboru byla pøeru¹ena neèekaným ukonèením programu.\n"
+
+msgid " If this is the case, use \":recover\" or \"vim -r "
+msgstr " Je-li tomu tak, pak pou¾ijte \":recover\" èi \"vim -r "
+
+msgid ""
+"\"\n"
+" to recover the changes (see \":help recovery\").\n"
+msgstr ""
+"\"\n"
+" pro odstranìní zmìn (viz \":help recovery)\".\n"
+
+msgid " If you did this already, delete the swap file \""
+msgstr " Pokud jste tak ji¾ uèinil, tak sma¾te odkládací soubor \""
+
+msgid ""
+"\"\n"
+" to avoid this message.\n"
+msgstr ""
+"\"\n"
+" a tato zpráva se ji¾ nebude objevovat.\n"
+
+msgid "Swap file \""
+msgstr "Odkládací soubor \""
+
+msgid "\" already exists!"
+msgstr "\" ji¾ existuje!"
+
+msgid "VIM - ATTENTION"
+msgstr "VIM - POZOR"
+
+msgid "Swap file already exists!"
+msgstr "Odkládací soubor ji¾ existuje!"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Quit"
+msgstr ""
+"&Otevøít pouze pro ètení\n"
+"&Pokraèovat v editaci\n"
+"O&bnovit soubor\n"
+"&Konec"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Quit\n"
+"&Delete it"
+msgstr ""
+"&Otevøít pouze pro ètení\n"
+"&Pokraèovat v editaci\n"
+"O&bnovit soubor\n"
+"&Konec\n"
+"&Smazat"
+
+msgid "E326: Too many swap files found"
+msgstr "E326: Pøíli¹ mnoho odkládacích souborù"
+
+msgid "E327: Part of menu-item path is not sub-menu"
+msgstr "E327: Èásti cesty k pøedmìtu nabídky není podnabídkou"
+
+msgid "E328: Menu only exists in another mode"
+msgstr "E328: Nabídka existuje pouze v jiném módu"
+
+msgid "E329: No menu of that name"
+msgstr "E329: Nabídka tohoto jména neexistuje"
+
+msgid "E330: Menu path must not lead to a sub-menu"
+msgstr "E330: Cesta nabídkou nesmí vést do podnabídky"
+
+msgid "E331: Must not add menu items directly to menu bar"
+msgstr "E331: Polo¾ky nabídky nelze pøidávat pøímo na li¹tu"
+
+msgid "E332: Separator cannot be part of a menu path"
+msgstr "E332: Oddìlovaè nesmí být èástí cesty nabídkou"
+
+#. Now we have found the matching menu, and we list the mappings
+#. Highlight title
+msgid ""
+"\n"
+"--- Menus ---"
+msgstr ""
+"\n"
+"--- Nabídky ---"
+
+msgid "Tear off this menu"
+msgstr "Odtrhnout tuto nabídku"
+
+msgid "E333: Menu path must lead to a menu item"
+msgstr "E333: Cesta nabídkou musí vést k polo¾ce nabídky"
+
+#, c-format
+msgid "E334: Menu not found: %s"
+msgstr "E334: Vzor nenalezen: %s"
+
+#, c-format
+msgid "E335: Menu not defined for %s mode"
+msgstr "E335: V %s módu není nabídka definována"
+
+msgid "E336: Menu path must lead to a sub-menu"
+msgstr "E336: Cesta nabídkou musí vést do podnabídky"
+
+msgid "E337: Menu not found - check menu names"
+msgstr "E337: Nabídka nenalezena - zkontrolujte názvy nabídek"
+
+#, c-format
+msgid "Error detected while processing %s:"
+msgstr "Chyba pøi zpracování %s:"
+
+#, c-format
+msgid "line %4ld:"
+msgstr "øádek %4ld:"
+
+msgid "[string too long]"
+msgstr "[pøíli¹ dlouhý øetìzec]"
+
+msgid "Messages maintainer: Bram Moolenaar <Bram@vim.org>"
+msgstr "Správce zpráv: Bram Moolenaar <Bram@vim.org>"
+
+msgid "Interrupt: "
+msgstr "Pøeru¹ení: "
+
+msgid "Hit ENTER to continue"
+msgstr "pokraèování stiskem ENTER"
+
+msgid "Hit ENTER or type command to continue"
+msgstr "Pro pokraèování stisknìte ENTER nebo zadejte pøíkaz"
+
+msgid "-- More --"
+msgstr "-- Pokraèování --"
+
+msgid " (RET/BS: line, SPACE/b: page, d/u: half page, q: quit)"
+msgstr " (RET/BS: øádek, MEZERNÍK/b: stránka, d/u: 0.5 stránky, q: konec)"
+
+msgid " (RET: line, SPACE: page, d: half page, q: quit)"
+msgstr " (RET: øádek, MEZERNÍK: stránka, d: 0.5 stránky, q: konec)"
+
+msgid "Question"
+msgstr "Otázka"
+
+msgid ""
+"&Yes\n"
+"&No"
+msgstr ""
+"&Ano\n"
+"&Ne"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"&Cancel"
+msgstr ""
+"&Ano\n"
+"&Ne\n"
+"&Zru¹it"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"Save &All\n"
+"&Discard All\n"
+"&Cancel"
+msgstr ""
+"&Ano\n"
+"&Ne\n"
+"&Ulo¾it v¹e\n"
+"Zahodit &v¹e\n"
+"&Zru¹it"
+
+msgid "Save File dialog"
+msgstr "Dialog pro ukládání souborù"
+
+msgid "Open File dialog"
+msgstr "Dialog pro otevírání souborù"
+
+#. TODO: non-GUI file selector here
+msgid "E338: Sorry, no file browser in console mode"
+msgstr "E338: Lituji, ale konzolová verze nepodporuje prohlí¾eè souborù"
+
+msgid "W10: Warning: Changing a readonly file"
+msgstr "W10: wc1: mìním soubor pouze_pro_ètení"
+
+msgid "1 more line"
+msgstr "poèet nových øádkù: 1"
+
+msgid "1 line less"
+msgstr "poèet smazaných øádkù: 1"
+
+#, c-format
+msgid "%ld more lines"
+msgstr "poèet nových øádkù: %ld"
+
+#, c-format
+msgid "%ld fewer lines"
+msgstr "poèet smazaných øádkù: %ld"
+
+msgid " (Interrupted)"
+msgstr "(Pøeru¹eno)"
+
+msgid "Vim: preserving files...\n"
+msgstr "Vim: zachovávám soubory...\n"
+
+#. close all memfiles, without deleting
+msgid "Vim: Finished.\n"
+msgstr "Vim: ukonèen\n"
+
+msgid "ERROR: "
+msgstr "CHYBA: "
+
+#, c-format
+msgid ""
+"\n"
+"[bytes] total alloc-freed %lu-%lu, in use %lu, peak use %lu\n"
+msgstr ""
+"\n"
+"[bajtù] celkem uvolnìno-alokováno %lu-%lu, vyu¾ito %lu, maximální vyu¾ití "
+"%lu\n"
+
+#, c-format
+msgid ""
+"[calls] total re/malloc()'s %lu, total free()'s %lu\n"
+"\n"
+msgstr ""
+"[volání] celkem re/malloc(): %lu, celkem free() %lu\n"
+"\n"
+
+msgid "E340: Line is becoming too long"
+msgstr "E340: Øádek se stává pøíli¹ dlouhým"
+
+#, c-format
+msgid "E341: Internal error: lalloc(%ld, )"
+msgstr "E341: Vnitøní chyba: lalloc(%ld, )"
+
+#, c-format
+msgid "E342: Out of memory! (allocating %lu bytes)"
+msgstr "E342: Nedostatek pamìti! (potøebuji alokovat bajtù: %lu)"
+
+#, c-format
+msgid "Calling shell to execute: \"%s\""
+msgstr "Spou¹tím pøíkaz \"%s\" pomocí shellu"
+
+msgid "Missing colon"
+msgstr "Chybí dvojteèka"
+
+msgid "Illegal mode"
+msgstr "nepøípustný mód"
+
+msgid "Illegal mouseshape"
+msgstr "Chybný tvar my¹i"
+
+msgid "digit expected"
+msgstr "oèekávána èíslice"
+
+msgid "Illegal percentage"
+msgstr "nepøípustné procento"
+
+msgid "Enter encryption key: "
+msgstr "Zadejte ¹ifrovací klíè: "
+
+msgid "Enter same key again: "
+msgstr "Zadejte je¹tì jednou tentý¾ klíè:"
+
+msgid "Keys don't match!"
+msgstr "Klíèe se neshodují"
+
+#, c-format
+msgid ""
+"E343: Invalid path: '**[number]' must be at the end of the path or be "
+"followed by '%s'."
+msgstr ""
+"E343: Chybná cesta: '**[èíslo] musí být buï na konci cesty, nebo musí být "
+"následováno'%s. Viz :help path."
+
+#, c-format
+msgid "E344: Can't find directory \"%s\" in cdpath"
+msgstr "E344: Adresáø \"%s\" nelze v cdpath nalézt"
+
+#, c-format
+msgid "E345: Can't find file \"%s\" in path"
+msgstr "E345: Soubor \"%s\" nelze v path nalézt"
+
+#, c-format
+msgid "E346: No more directory \"%s\" found in cdpath"
+msgstr "E346: ®ádný dal¹í adresáø \"%s\" nebyl v cdpath nalezen"
+
+#, c-format
+msgid "E347: No more file \"%s\" found in path"
+msgstr "E347: ®ádný dal¹í soubor \"%s\" nebyl v cestì nalezen"
+
+msgid "Illegal component"
+msgstr "nepøípustná souèást"
+
+msgid "Warning: terminal cannot highlight"
+msgstr "Varování: terminál nepodporuje zvýrazòování"
+
+msgid "E348: No string under cursor"
+msgstr "E348: pod kurzorem není ¾ádný øetìzec"
+
+msgid "E349: No identifier under cursor"
+msgstr "E349: pod kurzorem není ¾ádný identifikátor"
+
+msgid "E352: Cannot erase folds with current 'foldmethod'"
+msgstr "E352: pomocí aktuální 'foldmethod' nelze mazat záhyby"
+
+#, c-format
+msgid "1 line %sed 1 time"
+msgstr "poèet øádkù posunutých jednou pomocí %s : 1"
+
+#, c-format
+msgid "1 line %sed %d times"
+msgstr "Poèet øádkù posunutých pomocí %s %d-krát : 1"
+
+#, c-format
+msgid "%ld lines %sed 1 time"
+msgstr "Poèet øádkù: %ld (posunutých jednou pomocí %s)"
+
+#, c-format
+msgid "%ld lines %sed %d times"
+msgstr "Poèet øádkù: %ld (posunutých pomocí %s %d-krát)"
+
+#, c-format
+msgid "%ld lines to indent... "
+msgstr "poèet øádkù k odsazení: %ld"
+
+msgid "1 line indented "
+msgstr "poèet øádkù k odsazení: 1"
+
+#, c-format
+msgid "%ld lines indented "
+msgstr "poèet odsazených øádkù: %ld"
+
+#. must display the prompt
+msgid "cannot yank; delete anyway"
+msgstr "nelze kopírovat; pøesto smazáno"
+
+msgid "1 line changed"
+msgstr "poèet øádek se zmìnìnou velikostí písmen: 1"
+
+#, c-format
+msgid "%ld lines changed"
+msgstr "poèet øádek se zmìnìnou velikostí písmen: %ld"
+
+#, c-format
+msgid "freeing %ld lines"
+msgstr "poèet uvolòovaných øádkù: %ld"
+
+msgid "1 line yanked"
+msgstr "poèet zkopírovaných øádkù: 1"
+
+#, c-format
+msgid "%ld lines yanked"
+msgstr "poèet zkopírovaných øádkù: %ld"
+
+#, c-format
+msgid "E353: Nothing in register %s"
+msgstr "E353: Registr %s je prázdný"
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Registers ---"
+msgstr ""
+"\n"
+"--- Registry ---"
+
+msgid "Illegal register name"
+msgstr "nepøípustný název registru"
+
+msgid ""
+"\n"
+"# Registers:\n"
+msgstr ""
+"\n"
+"# Registry:\n"
+
+#, c-format
+msgid "Unknown register type %d"
+msgstr "%d není známým typem registru"
+
+#, c-format
+msgid "E354: Invalid register name: '%s'"
+msgstr "E354: '%s' není pøípustné jméno registru"
+
+#, c-format
+msgid "%ld Cols; "
+msgstr "øádkù: %ld;"
+
+#, c-format
+msgid "Selected %s%ld of %ld Lines; %ld of %ld Words; %ld of %ld Bytes"
+msgstr "Vybráno %s%ld z %ld øádkù; %ld z %ld slov; %ld z %ld Bytù"
+
+#, c-format
+msgid "Col %s of %s; Line %ld of %ld; Word %ld of %ld; Byte %ld of %ld"
+msgstr "Sloupec %s z %s; Øádek %ld z %ld; Slovo %ld z %ld; Byte %ld z %ld"
+
+#, c-format
+msgid "(+%ld for BOM)"
+msgstr "(+%ld pro BOM)"
+
+msgid "Thanks for flying Vim"
+msgstr "Dìkuji za pou¾ití Vim"
+
+msgid "Option not supported"
+msgstr "Volba není podporována"
+
+msgid "Not allowed in a modeline"
+msgstr "Není v modeline povoleno"
+
+msgid ""
+"\n"
+"\tLast set from "
+msgstr ""
+"\n"
+"\tNaposledy nastavena z "
+
+msgid "Number required after ="
+msgstr "Po = je vy¾adováno èíslo"
+
+msgid "Not found in termcap"
+msgstr "Nenalezen v termcapu"
+
+#, c-format
+msgid "Illegal character <%s>"
+msgstr "Nepøípustný znak <%s>"
+
+msgid "Not allowed here"
+msgstr "Toto zde není povoleno"
+
+msgid "Cannot set 'term' to empty string"
+msgstr "volba 'term' nemù¾e být prázdná"
+
+msgid "Cannot change term in GUI"
+msgstr "V GUI nelze mìnit term"
+
+msgid "Use \":gui\" to start the GUI"
+msgstr "Pou¾ijte \"gui\" pro spu¹tìní GUI"
+
+msgid "'backupext' and 'patchmode' are equal"
+msgstr "volby 'backupext' a 'patchmode' mají stejnou hodnotu"
+
+msgid "Zero length string"
+msgstr "øetìzec o nulové délce"
+
+#, c-format
+msgid "Missing number after <%s>"
+msgstr "Po <%s> chybí èíslo"
+
+msgid "Missing comma"
+msgstr "Chybí èárka"
+
+msgid "Must specify a ' value"
+msgstr "Je nutné zadat hodnotu '"
+
+msgid "contains unprintable character"
+msgstr "obsahuje netisknutelné znaky"
+
+msgid "Invalid font(s)"
+msgstr "Chybná písma"
+
+msgid "can't select fontset"
+msgstr "nelze vybrat sadu písem"
+
+msgid "Invalid fontset"
+msgstr "chybná sada písem"
+
+msgid "can't select wide font"
+msgstr "nelze vybrat ¹iroký font"
+
+msgid "Invalid wide font"
+msgstr "Chybné ¹iroké písmo"
+
+#, c-format
+msgid "Illegal character after <%c>"
+msgstr "Nepøípustný znak po <%c>"
+
+msgid "comma required"
+msgstr "je nutná èárka"
+
+#, c-format
+msgid "'commentstring' must be empty or contain %s"
+msgstr "volba `commentstring` musí být buï prázdná nebo nastavená na %s"
+
+msgid "No mouse support"
+msgstr "Bez podpory my¹i"
+
+msgid "Unclosed expression sequence"
+msgstr "neuzavøená sekvence výrazù"
+
+msgid "too many items"
+msgstr "pøíli¹ mnoho polo¾ek"
+
+msgid "unbalanced groups"
+msgstr "nevyvá¾ené skupiny"
+
+msgid "A preview window already exists"
+msgstr "Okno náhledu ji¾ existuje"
+
+msgid "'winheight' cannot be smaller than 'winminheight'"
+msgstr ""
+"hodnota volby 'winheight' nesmí být men¹í ne¾ hodnota volby 'winminheight'"
+
+msgid "'winwidth' cannot be smaller than 'winminwidth'"
+msgstr ""
+"hodnota volby 'winwidth' nesmí být men¹í ne¾ hodnota volby 'winminwidth'"
+
+#, c-format
+msgid "Need at least %d lines"
+msgstr "minimální potøebný poèet øádkù: %d"
+
+#, c-format
+msgid "Need at least %d columns"
+msgstr "minimální potøebný poèet sloupcù: %d"
+
+#, c-format
+msgid "E355: Unknown option: %s"
+msgstr "E355: Neznámá volba: %s"
+
+msgid ""
+"\n"
+"--- Terminal codes ---"
+msgstr ""
+"\n"
+"--- Kódy terminálu ---"
+
+msgid ""
+"\n"
+"--- Global option values ---"
+msgstr ""
+"\n"
+"--- Nastavení globálních voleb ---"
+
+msgid ""
+"\n"
+"--- Local option values ---"
+msgstr ""
+"\n"
+"--- Nastavení lokálních voleb ---"
+
+msgid ""
+"\n"
+"--- Options ---"
+msgstr ""
+"\n"
+"--- Volby ---"
+
+msgid "E356: get_varp ERROR"
+msgstr "E356: get_varp CHYBA"
+
+#, c-format
+msgid "E357: 'langmap': Matching character missing for %s"
+msgstr "E357: 'langmap': pro %s chybí vyhovující znak"
+
+#, c-format
+msgid "E358: 'langmap': Extra characters after semicolon: %s"
+msgstr "E358: 'langmap': nadbyteèné znaky po støedníku: %s"
+
+msgid "cannot open "
+msgstr "nelze otevøít "
+
+msgid "VIM: Can't open window!\n"
+msgstr "VIM: Nelze otevøít nové okno!\n"
+
+msgid "Need Amigados version 2.04 or later\n"
+msgstr "Vy¾aduje Amigados verze 2.04 nebo vy¹¹í\n"
+
+#, c-format
+msgid "Need %s version %ld\n"
+msgstr "Vy¾aduje %s verze %ld\n"
+
+msgid "Cannot open NIL:\n"
+msgstr "Nelze otevøít NIL:\n"
+
+msgid "Cannot create "
+msgstr " Nelze vytvoøit "
+
+#, c-format
+msgid "Vim exiting with %d\n"
+msgstr "Vim bude ukonèen %d\n"
+
+msgid "cannot change console mode ?!\n"
+msgstr "Nelze zmìnit mód konzole ?!\n"
+
+msgid "E359: Screen mode setting not supported"
+msgstr "E359: Nastavování re¾imu obrazovky není podporováno"
+
+msgid "mch_get_shellsize: not a console??\n"
+msgstr "mch_get_shellsize: neni konzole??\n"
+
+#. if Vim opened a window: Executing a shell may cause crashes
+msgid "E360: Cannot execute shell with -f option"
+msgstr "E360: Nelze spustit shell s parametrem -f"
+
+msgid "Cannot execute "
+msgstr "Nelze spustit "
+
+msgid "shell "
+msgstr "shell "
+
+msgid " returned\n"
+msgstr " návratová hodnota shellu\n"
+
+msgid "ANCHOR_BUF_SIZE too small."
+msgstr "ANCHOR_BUF_SIZE je pøíli¹ malá."
+
+msgid "I/O ERROR"
+msgstr "I/O CHYBA"
+
+msgid "...(truncated)"
+msgstr "...(kráceno)"
+
+msgid "'columns' is not 80, cannot execute external commands"
+msgstr "'columns' není 80, nelze spustit externí pøíkaz"
+
+#, c-format
+msgid "E364: Library call failed for \"%s()\""
+msgstr "E364: Volání knihovní funkce \"%s()\" selhalo"
+
+msgid "E237: Printer selection failed"
+msgstr "E237: Nelze zvolit tiskárnu"
+
+#, c-format
+msgid "to %s on %s"
+msgstr "do %s v %s"
+
+#, c-format
+msgid "E238: Print error: %s"
+msgstr "E238: Chyba tisku: %s"
+
+msgid "Unknown"
+msgstr "Neznámý"
+
+#, c-format
+msgid "Printing '%s'"
+msgstr "Vyti¹tìno '%s'"
+
+#, c-format
+msgid "E244: Illegal charset name \"%s\" in font name \"%s\""
+msgstr "E244: Nepøípustná jméno znakové sady \"%s\" ve fontu \"%s\""
+
+#, c-format
+msgid "E245: Illegal char '%c' in font name \"%s\""
+msgstr "E245: Nepøípustný znak '%c' ve fontu \"%s\""
+
+msgid "E366: Invalid 'osfiletype' option - using Text"
+msgstr "E366: Neplatný 'osfiletype' - pou¾it Text"
+
+msgid "Vim: Double signal, exiting\n"
+msgstr "VIm: dvojitý signál, konèím\n"
+
+#, c-format
+msgid "Vim: Caught deadly signal %s\n"
+msgstr "Vim: Zachycen smrtelný signál %s\n"
+
+msgid "Vim: Caught deadly signal\n"
+msgstr "Vim: Zachycen smrtelný signál\n"
+
+#, c-format
+msgid "Opening the X display took %ld msec"
+msgstr "Doba otevírání X displeje (v ms): %ld"
+
+msgid ""
+"\n"
+"Vim: Got X error\n"
+msgstr ""
+"\n"
+"Vim: chyba X11\n"
+
+msgid "Testing the X display failed"
+msgstr "Test X displeje se nezdaøil"
+
+msgid "Opening the X display timed out"
+msgstr "Vypr¹el èas pøi èekání na otevøení X displeje"
+
+msgid ""
+"\n"
+"Cannot execute shell "
+msgstr ""
+"\n"
+"nelze spustit shell "
+
+msgid ""
+"\n"
+"Cannot execute shell sh\n"
+msgstr ""
+"\n"
+"Nelze spustit sh shell\n"
+
+msgid ""
+"\n"
+"shell returned "
+msgstr ""
+"\n"
+" návratová hodnota shellu "
+
+msgid ""
+"\n"
+"Cannot create pipes\n"
+msgstr ""
+"\n"
+"Nelze vytvoøit roury\n"
+
+msgid ""
+"\n"
+"Cannot fork\n"
+msgstr ""
+"\n"
+"Volání fork selhalo\n"
+
+msgid ""
+"\n"
+"Command terminated\n"
+msgstr ""
+"\n"
+"Pøíkaz ukonèen\n"
+
+msgid "Opening the X display failed"
+msgstr "Otevøení X displeje se nezdaøilo"
+
+msgid "At line"
+msgstr "Na øádku"
+
+msgid "Could not load vim32.dll!"
+msgstr "Nelze naèíst vim32.dll!"
+
+msgid "VIM Error"
+msgstr "Chyba VIMu"
+
+msgid "Could not fix up function pointers to the DLL!"
+msgstr "Nelze nastavit ukazatele funkcí na DLL"
+
+#, c-format
+msgid "shell returned %d"
+msgstr "návratová hodnota shellu %d"
+
+#, c-format
+msgid "Vim: Caught %s event\n"
+msgstr "Vim: Zachycen %s signál\n"
+
+msgid "close"
+msgstr "zavøít"
+
+msgid "logoff"
+msgstr "logoff"
+
+msgid "shutdown"
+msgstr "shutdown"
+
+msgid "E371: Command not found"
+msgstr "E371: Pøíkaz není k dispozici"
+
+msgid ""
+"VIMRUN.EXE not found in your $PATH.\n"
+"External commands will not pause after completion.\n"
+"See :help win32-vimrun for more information."
+msgstr ""
+"VIMRUN.EXE se nevyskytuje ve Va¹í $PATH.\n"
+"Externí pøíkazy nebudou\n"
+"See :help win32-vimrun for more information."
+
+msgid "Vim Warning"
+msgstr "Varování"
+
+msgid "E372: Too many %%%c in format string"
+msgstr "E372: Pøíli¹ mnoho %%%c ve formátovacím øetìzci"
+
+msgid "E373: Unexpected %%%c in format string"
+msgstr "E373: Neoèekávaný výskyt %%%c ve formátovacím øetìzci"
+
+msgid "E374: Missing ] in format string"
+msgstr "E374: Ve formátovacím øetìzci chybí ]"
+
+msgid "E375: Unsupported %%%c in format string"
+msgstr "E375: %%%c Nepodporovaná formátová specifikace ve formátovacím øetìzci"
+
+msgid "E376: Invalid %%%c in format string prefix"
+msgstr "E376: Nepøípustné %%%c v prefixu formátovacího øetìzce"
+
+msgid "E377: Invalid %%%c in format string"
+msgstr "E377: Nepøípustné %%%c ve formátovacím øetìzci"
+
+msgid "E378: 'errorformat' contains no pattern"
+msgstr "E378: 'errorformat' neobsahuje ¾ádný vzorek"
+
+msgid "E379: Missing or empty directory name"
+msgstr "E379: Chybìjící nebo prázdný název adresáøe"
+
+msgid "No more items"
+msgstr "®ádné dal¹í polo¾ky"
+
+#, c-format
+msgid "(%d of %d)%s%s: "
+msgstr "(%d/%d)%s%s: "
+
+msgid " (line deleted)"
+msgstr " (øádek smazán)"
+
+msgid "E380: At bottom of quickfix stack"
+msgstr "E380: Konec quickfix seznamu"
+
+msgid "E381: At top of quickfix stack"
+msgstr "E381: Zaèátek quickfix seznamu"
+
+#, c-format
+msgid "error list %d of %d; %d errors"
+msgstr "seznam chyb %d z %d; poèet chyb: %d"
+
+msgid "E382: Cannot write, 'buftype' option is set"
+msgstr "E382: Nelze ulo¾it, je nastavena volba 'buftype'"
+
+msgid "E339: Pattern too long"
+msgstr "E339: Vzor je pøíli¹ dlouhý"
+
+#, c-format
+msgid "E61: Nested %s*"
+msgstr "E61: %s*"
+
+#, c-format
+msgid "E62: Nested %s%c"
+msgstr "E62: %s%c"
+
+#, c-format
+msgid "E64: %s%c follows nothing"
+msgstr "E64: %s%c nic není"
+
+#, c-format
+msgid "Syntax error in %s{...}"
+msgstr "Chyba syntaxe v %s{...}"
+
+msgid "E361: Crash intercepted; regexp too complex?"
+msgstr "E361: Zachyceno pøeteèení zásobníku: pøíli¹ slo¾itý regulární výraz?"
+
+msgid "E363: pattern caused out-of-stack error"
+msgstr "E363: vzorek zpùsobil pøeteèení zásobníku"
+
+msgid "External submatches:\n"
+msgstr "Vnìj¹í podøazené shody:\n"
+
+#, c-format
+msgid "+--%3ld lines folded "
+msgstr "poèet øádkù v záhybu: %3ld"
+
+msgid " VREPLACE"
+msgstr " VREPLACE"
+
+msgid " REPLACE"
+msgstr " REPLACE"
+
+msgid " REVERSE"
+msgstr " REVERSE"
+
+msgid " INSERT"
+msgstr " INSERT"
+
+msgid " (insert)"
+msgstr " (insert)"
+
+msgid " (replace)"
+msgstr " (replace)"
+
+msgid " (vreplace)"
+msgstr " (vreplace)"
+
+msgid " Hebrew"
+msgstr " hebrejský"
+
+msgid " (lang)"
+msgstr " (lang)"
+
+msgid " (paste)"
+msgstr " (paste)"
+
+msgid " SELECT"
+msgstr " SHODY"
+
+msgid " VISUAL"
+msgstr " VIZUÁLNÍ"
+
+msgid " BLOCK"
+msgstr " BLOK"
+
+msgid " LINE"
+msgstr " ØÁDEK"
+
+msgid "recording"
+msgstr "nahrávám"
+
+msgid "search hit TOP, continuing at BOTTOM"
+msgstr "hledání dosáhlo zaèátku, pokraèování od konce"
+
+msgid "search hit BOTTOM, continuing at TOP"
+msgstr "hledání dosáhlo konce, pokraèování od zaèátku"
+
+#, c-format
+msgid "E383: Invalid search string: %s"
+msgstr "E383: Nepøípustný hledaný øetìzec: %s"
+
+#, c-format
+msgid "E384: search hit TOP without match for: %s"
+msgstr "E384: hledaný dosáhlo zaèátku bez nalezení %s"
+
+#, c-format
+msgid "E385: search hit BOTTOM without match for: %s"
+msgstr "E385: hledaný dosáhlo konce bez nalezení %s"
+
+msgid "E386: Expected '?' or '/' after ';'"
+msgstr "E386: Po ';' oèekávám '?' nebo '/'"
+
+msgid " (includes previously listed match)"
+msgstr " (vèetnì ji¾ vypsaných shod)"
+
+#. cursor at status line
+msgid "--- Included files "
+msgstr "--- Vlo¾ené soubory"
+
+msgid "not found "
+msgstr " nenalezeny"
+
+msgid "in path ---\n"
+msgstr "v cestì ---\n"
+
+msgid " (Already listed)"
+msgstr " (Ji¾ vypsáno)"
+
+msgid " NOT FOUND"
+msgstr " NENALEZENY"
+
+#, c-format
+msgid "Scanning included file: %s"
+msgstr "Prohledávám vlo¾ené soubory: %s"
+
+msgid "E387: Match is on current line"
+msgstr "E387: Shoda je na aktuálním øádku"
+
+msgid "All included files were found"
+msgstr "V¹echny vlo¾ené soubory byly nalezeny"
+
+msgid "No included files"
+msgstr "®ádné vlo¾ené soubory"
+
+msgid "E388: Couldn't find definition"
+msgstr "E388: Nelze nalézt definici"
+
+msgid "E389: Couldn't find pattern"
+msgstr "E389: Nelze nalézt vzorek"
+
+#, c-format
+msgid "E390: Illegal argument: %s"
+msgstr "E390: nepøípustný argument: %s"
+
+#, c-format
+msgid "E391: No such syntax cluster: %s"
+msgstr "E391: Syntaktická sestava %s neexistuje"
+
+msgid "No Syntax items defined for this buffer"
+msgstr "Pro tento buffer nejsou definovány ¾ádné pøedmìty syntaxe"
+
+msgid "syncing on C-style comments"
+msgstr "synchronizuji komentáøe v C stylu"
+
+msgid "no syncing"
+msgstr "¾ádná synchronizace"
+
+msgid "syncing starts "
+msgstr "synchronizace zaèíná "
+
+msgid " lines before top line"
+msgstr " øádkù pøed zaèátkem"
+
+msgid ""
+"\n"
+"--- Syntax sync items ---"
+msgstr ""
+"\n"
+"--- Polo¾ky synchronizace syntaxe ---"
+
+msgid ""
+"\n"
+"syncing on items"
+msgstr ""
+"\n"
+"synchronizuji pøedmìty"
+
+msgid ""
+"\n"
+"--- Syntax items ---"
+msgstr ""
+"\n"
+"--- Pøedmìty syntaxe ---"
+
+#, c-format
+msgid "E392: No such syntax cluster: %s"
+msgstr "E392: Syntaktická sestava %s neexistuje"
+
+msgid "minimal "
+msgstr "minimální "
+
+msgid "maximal "
+msgstr "maximální "
+
+msgid "E393: group[t]here not accepted here"
+msgstr "E393: group[t]here nesmí být na tomto místì"
+
+#, c-format
+msgid "E394: Didn't find region item for %s"
+msgstr "E394: Pro %s chybí polo¾ka regionu"
+
+msgid "E395: contains argument not accepted here"
+msgstr "E395: obsahuje argumenty, které zde nejsou povoleny"
+
+msgid "E396: containedin argument not accepted here"
+msgstr "E396: obsahuje argumenty, které zde nejsou povoleny"
+
+msgid "E397: Filename required"
+msgstr "E397: Vy¾adován název souboru"
+
+#, c-format
+msgid "E398: Missing '=': %s"
+msgstr "E398: Chybí '=': %s"
+
+#, c-format
+msgid "E399: Not enough arguments: syntax region %s"
+msgstr "E399: Pøíli¹ málo argumentù: oblast syntaxe %s"
+
+msgid "E400: No cluster specified"
+msgstr "E400: Nebyla zadána ¾ádná sestava"
+
+#, c-format
+msgid "E401: Pattern delimiter not found: %s"
+msgstr "E401: Oddìlovaè vzorku %s nenalezen"
+
+#, c-format
+msgid "E402: Garbage after pattern: %s"
+msgstr "E402: Chyba za vzorkem %s"
+
+msgid "E403: syntax sync: line continuations pattern specified twice"
+msgstr "E403: synchronizace syntaxe: vzorek pokraèování øádkù zadán dvakrát"
+
+#, c-format
+msgid "E404: Illegal arguments: %s"
+msgstr "E404: nepøípustný argument: %s"
+
+#, c-format
+msgid "E405: Missing equal sign: %s"
+msgstr "E405: Chybí rovnítko: %s"
+
+#, c-format
+msgid "E406: Empty argument: %s"
+msgstr "E406: Prázdný argument: %s"
+
+#, c-format
+msgid "E407: %s not allowed here"
+msgstr "E407: %s zde není povoleno"
+
+#, c-format
+msgid "E408: %s must be first in contains list"
+msgstr "E408: %s musí být první v 'contains' seznamu"
+
+#, c-format
+msgid "E409: Unknown group name: %s"
+msgstr "E409: Neznámá název skupiny: %s"
+
+#, c-format
+msgid "E410: Invalid :syntax subcommand: %s"
+msgstr "E410: chybný podøazený pøíkaz :syntax : %s "
+
+#, c-format
+msgid "E411: highlight group not found: %s"
+msgstr "E411: skupina zvýraznìní %s nebyla nalezena"
+
+#, c-format
+msgid "E412: Not enough arguments: \":highlight link %s\""
+msgstr "E412: Pøíli¹ málo argumentù: \":highlight link %s\""
+
+#, c-format
+msgid "E413: Too many arguments: \":highlight link %s\""
+msgstr "E413: Pøíli¹ mnoho argumentù: \":highlight link %s\""
+
+msgid "E414: group has settings, highlight link ignored"
+msgstr "E414: skupina je nastavena, odkaz na zvýrazòovací skupinu ignorován"
+
+#, c-format
+msgid "E415: unexpected equal sign: %s"
+msgstr "E415: neèekané rovnítko : %s"
+
+#, c-format
+msgid "E416: missing equal sign: %s"
+msgstr "E416: chybné rovnítko: %s"
+
+#, c-format
+msgid "E417: missing argument: %s"
+msgstr "E417: chybí argument: %s"
+
+#, c-format
+msgid "E418: Illegal value: %s"
+msgstr "E418: nepøípustná hodnota: %s"
+
+msgid "E419: FG color unknown"
+msgstr "E419: barva popøedí není známá"
+
+msgid "E420: BG color unknown"
+msgstr "E420: barva popøedí není známá"
+
+#, c-format
+msgid "E421: Color name or number not recognized: %s"
+msgstr "E421: název èi èíslo barvy %s nebylo rozpoznáno"
+
+#, c-format
+msgid "E422: terminal code too long: %s"
+msgstr "E422: terminálový kód %s je pøíli¹ dlouhý"
+
+#, c-format
+msgid "E423: Illegal argument: %s"
+msgstr "E423: nepøípustný argument: %s"
+
+msgid "E424: Too many different highlighting attributes in use"
+msgstr ""
+"E424: Je pou¾íváno pøíli¹ velké mno¾ství odli¹ných zvýrazòovacích atributù"
+
+msgid "at bottom of tag stack"
+msgstr "konec seznamu tagù"
+
+msgid "at top of tag stack"
+msgstr "zaèátek seznamu tagù"
+
+msgid "E425: Cannot go before first matching tag"
+msgstr "E425: Pøed první vyhovující tag nelze pøeskoèit"
+
+#, c-format
+msgid "E426: tag not found: %s"
+msgstr "E426: tag %s nenalezen"
+
+msgid " # pri kind tag"
+msgstr " # pri typ tag"
+
+msgid "file\n"
+msgstr "soubor\n"
+
+#.
+#. * Ask to select a tag from the list.
+#. * When using ":silent" assume that <CR> was entered.
+#.
+msgid "Enter nr of choice (<CR> to abort): "
+msgstr "Zadejte èíslo (<CR> pro ukonèení): "
+
+msgid "E427: There is only one matching tag"
+msgstr "E427: Vyhovuje pouze jeden tag"
+
+msgid "E428: Cannot go beyond last matching tag"
+msgstr "E428: Za poslední vyhovující tag nelze pøeskoèit"
+
+#, c-format
+msgid "File \"%s\" does not exist"
+msgstr "Soubor \"%s\" neexistuje"
+
+#. Give an indication of the number of matching tags
+#, c-format
+msgid "tag %d of %d%s"
+msgstr "tag %d z celkového poètu %d%s"
+
+msgid " or more"
+msgstr " nebo více"
+
+msgid " Using tag with different case!"
+msgstr " Pou¾ívám tag s písmeny jiné velikosti!"
+
+#, c-format
+msgid "E429: File \"%s\" does not exist"
+msgstr "E429: \"%s\" neexistuje"
+
+#. Highlight title
+msgid ""
+"\n"
+" # TO tag FROM line in file/text"
+msgstr ""
+"\n"
+" # CÍL tag START øádek v souboru/textu"
+
+msgid "Linear tag search"
+msgstr "Lineární hledání tagu"
+
+msgid "Binary tag search"
+msgstr "Binární hledání tagu"
+
+#, c-format
+msgid "Searching tags file %s"
+msgstr "Prohledávám soubor tagù %s"
+
+#, c-format
+msgid "E430: Tag file path truncated for %s\n"
+msgstr "E430: Soubor tagù %s byl oøezán\n"
+
+#, c-format
+msgid "E431: Format error in tags file \"%s\""
+msgstr "E431: Chyba formátu v souboru tagù \"%s\""
+
+#, c-format
+msgid "Before byte %ld"
+msgstr "Pøed bajtem %ld"
+
+#, c-format
+msgid "E432: Tags file not sorted: %s"
+msgstr "E432: Obsah soubor tagù %s není seøazen"
+
+#. never opened any tags file
+msgid "E433: No tags file"
+msgstr "E433: ®ádný soubor tagù"
+
+msgid "E434: Can't find tag pattern"
+msgstr "E434: Nelze najít vzorek tagù"
+
+msgid "E435: Couldn't find tag, just guessing!"
+msgstr "E435: Tag nelze nalézt, pouze hádám!"
+
+msgid "' not known. Available builtin terminals are:"
+msgstr "' není znám. Dostupné vestavìné terminály:"
+
+msgid "defaulting to '"
+msgstr "implicitní terminál '"
+
+msgid "Cannot open termcap file"
+msgstr "Nelze otevøít termcap"
+
+msgid "Terminal entry not found in terminfo"
+msgstr "Terminfo neobsahuje polo¾ku pro tento terminál"
+
+msgid "Terminal entry not found in termcap"
+msgstr "Termcap neobsahuje polo¾ku pro tento terminál"
+
+#, c-format
+msgid "E436: No \"%s\" entry in termcap"
+msgstr "E436: Termcap neobsahuje polo¾ku pro \"%s\""
+
+msgid "E437: terminal capability \"cm\" required"
+msgstr "E437: Terminál musí mít schopnost \"cm\""
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Terminal keys ---"
+msgstr ""
+"\n"
+"--- Klávesy terminálu ---"
+
+msgid "new shell started\n"
+msgstr "spu¹tìn nový shell\n"
+
+msgid "Vim: Error reading input, exiting...\n"
+msgstr "Vim: chyba pøi ètení vstupu, konèím...\n"
+
+#. must display the prompt
+msgid "No undo possible; continue anyway"
+msgstr "odstranìní zmìn není mo¾né; chcete pøesto pokraèovat"
+
+msgid "E438: u_undo: line numbers wrong"
+msgstr "E438: u_undo: èísla øádkù jsou chybná"
+
+msgid "1 change"
+msgstr "poèet zmìn: 1"
+
+#, c-format
+msgid "%ld changes"
+msgstr "poèet zmìn: %ld"
+
+msgid "E439: undo list corrupt"
+msgstr "E439: záznam o zmìnách po¹kozen"
+
+msgid "E440: undo line missing"
+msgstr "E440: chybí undo øádek"
+
+#. Only MS VC 4.1 and earlier can do Win32s
+msgid ""
+"\n"
+"MS-Windows 16/32-bit GUI version"
+msgstr ""
+"\n"
+"16/32 bitová GUI verze pro MS Windows"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit GUI version"
+msgstr ""
+"\n"
+"32 bitová GUI verze pro MS Windows"
+
+msgid " in Win32s mode"
+msgstr " ve Win32s re¾imu"
+
+msgid " with OLE support"
+msgstr " s OLE podporou"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit console version"
+msgstr ""
+"\n"
+"32 bitová verze pro MS Windows konzolu"
+
+msgid ""
+"\n"
+"MS-Windows 16-bit version"
+msgstr ""
+"\n"
+"16 bitová verze pro MS Windows"
+
+msgid ""
+"\n"
+"32-bit MS-DOS version"
+msgstr ""
+"\n"
+"32 bitová verze pro MS Windows"
+
+msgid ""
+"\n"
+"16-bit MS-DOS version"
+msgstr ""
+"\n"
+"16 bitová MS-DOS verze"
+
+msgid ""
+"\n"
+"MacOS X (unix) version"
+msgstr ""
+"\n"
+"MacOS X (unix) verze"
+
+msgid ""
+"\n"
+"MacOS X version"
+msgstr ""
+"\n"
+"MacOS X verze"
+
+msgid ""
+"\n"
+"MacOS version"
+msgstr ""
+"\n"
+"MacOS verze"
+
+msgid ""
+"\n"
+"RISC OS version"
+msgstr ""
+"\n"
+"RISC OS verze"
+
+msgid ""
+"\n"
+"Included patches: "
+msgstr ""
+"\n"
+"Pou¾ité záplaty: "
+
+msgid ""
+"\n"
+"Compiled "
+msgstr ""
+"\n"
+"pøelo¾il "
+
+msgid "by "
+msgstr " "
+
+msgid ""
+"\n"
+"Huge version "
+msgstr ""
+"\n"
+"maximální verze"
+
+msgid ""
+"\n"
+"Big version "
+msgstr ""
+"\n"
+"velká verze "
+
+msgid ""
+"\n"
+"Normal version "
+msgstr ""
+"\n"
+"normální verze"
+
+msgid ""
+"\n"
+"Small version "
+msgstr ""
+"\n"
+"malá verze "
+
+msgid ""
+"\n"
+"Tiny version "
+msgstr ""
+"\n"
+"minimální verze"
+
+msgid "without GUI."
+msgstr "bez grafického rozhraní"
+
+msgid "with GTK-GNOME GUI."
+msgstr "s rozhraním GTK-GNOME"
+
+msgid "with GTK GUI."
+msgstr "s rozhraním GTK"
+
+msgid "with X11-Motif GUI."
+msgstr "s rozhraním X11-Motif"
+
+msgid "with X11-Athena GUI."
+msgstr "S rozhraním X11-Athena"
+
+msgid "with BeOS GUI."
+msgstr "s rozhraním BeOS"
+
+msgid "with Photon GUI."
+msgstr "s rozhraním Photon"
+
+msgid "with GUI."
+msgstr "s grafickým rozhraním"
+
+msgid "with Carbon GUI."
+msgstr "s grafickým rozhraním Carbon"
+
+msgid "with Cocoa GUI."
+msgstr "s grafickým rozhraním Cocoa"
+
+msgid "with (classic) GUI."
+msgstr "s (clasickým) grafickým rozhraním"
+
+msgid " Features included (+) or not (-):\n"
+msgstr " Vlastnosti zahrnuté (+) a nezahrnuté (-):\n"
+
+msgid " system vimrc file: \""
+msgstr " systémový vimrc soubor: \""
+
+msgid " user vimrc file: \""
+msgstr " u¾ivatelský vimrc soubor: \""
+
+msgid " 2nd user vimrc file: \""
+msgstr " druhý u¾ivatelský vimrc soubor: \""
+
+msgid " 3rd user vimrc file: \""
+msgstr " tøetí u¾ivatelský vimrc soubor: \""
+
+msgid " user exrc file: \""
+msgstr " u¾ivatelský exrc soubor: \""
+
+msgid " 2nd user exrc file: \""
+msgstr " druhý u¾ivatelský exrc soubor: \""
+
+msgid " system gvimrc file: \""
+msgstr " systémový gvimrc soubor: \""
+
+msgid " user gvimrc file: \""
+msgstr " u¾ivatelský gvimrc soubor: \""
+
+msgid "2nd user gvimrc file: \""
+msgstr "druhý u¾ivatelský gvimrc soubor: \""
+
+msgid "3rd user gvimrc file: \""
+msgstr "tøetí u¾ivatelský gvimrc soubor: \""
+
+msgid " system menu file: \""
+msgstr " systémový soubor s menu: \""
+
+msgid " fall-back for $VIM: \""
+msgstr " implicitní hodnota $VIM:\""
+
+msgid " f-b for $VIMRUNTIME: \""
+msgstr " implicitní hodnota $VIMRUNTIME: \""
+
+msgid "Compilation: "
+msgstr "Pøeklad: "
+
+msgid "Compiler: "
+msgstr "Pøekladaè: "
+
+msgid "Linking: "
+msgstr "Linkuji: "
+
+msgid " DEBUG BUILD"
+msgstr " PODPORA LADÌNÍ"
+
+msgid "VIM - Vi IMproved"
+msgstr "VIM - Vi IMproved"
+
+msgid "version "
+msgstr "verze "
+
+msgid "by Bram Moolenaar et al."
+msgstr "Autor: Bram Moolenaar a dal¹í"
+
+msgid "Vim is open source and freely distributable"
+msgstr "Vim je volnì ¹iøitelný program s otevøeným zdrojovým kódem"
+
+msgid "Help poor children in Uganda!"
+msgstr "Pomozte chudým dìtem v Ugandì!"
+
+msgid "type :help iccf<Enter> for information "
+msgstr "podrobnìj¹í informace získáte pomocí :help iccf<Enter>"
+
+msgid "type :q<Enter> to exit "
+msgstr "zadejte :q<Enter> pro ukonèení programu"
+
+msgid "type :help<Enter> or <F1> for on-line help"
+msgstr "zadejte :help<Enter> èi <F1> pro nápovìdu"
+
+msgid "type :help version8<Enter> for version info"
+msgstr "zadejte :help version8<Enter> pro informace o verzi 6"
+
+msgid "Running in Vi compatible mode"
+msgstr "Bì¾ím v re¾imu kompatibility s Vi"
+
+msgid "type :set nocp<Enter> for Vim defaults"
+msgstr "zadejte :set nocp<Enter> pro implicitní nastavení Vim"
+
+msgid "type :help cp-default<Enter> for info on this"
+msgstr "podrobnìj¹í informace získáte pomocí :help cp-default<Enter>"
+
+msgid "WARNING: Windows 95/98/ME detected"
+msgstr "VAROVÁNÍ: detekovány Windows 95/98/ME"
+
+msgid "type :help windows95<Enter> for info on this"
+msgstr "zadejte :help windows95<Enter> pro podrobnìj¹í informace"
+
+msgid "E441: There is no preview window"
+msgstr "E441: Není ¾ádné preview okno není"
+
+msgid "E442: Can't split topleft and botright at the same time"
+msgstr "E442: Okno nelze rozdìlit zároveò topleft a botright"
+
+msgid "E443: Cannot rotate when another window is split"
+msgstr "E443: Nelze rotovat, pokud je jiné okno rozdìleno"
+
+msgid "E444: Cannot close last window"
+msgstr "E444: Poslední okno nelze uzavøít"
+
+msgid "Already only one window"
+msgstr "Ji¾ existuje pouze jedno okno"
+
+msgid "E445: Other window contains changes"
+msgstr "E445: Jiné okno obsahuje zmìny"
+
+msgid "E446: No file name under cursor"
+msgstr "E446: Pod kurzorem se nenachází název souboru"
+
+#, c-format
+msgid "E447: Can't find file \"%s\" in path"
+msgstr "E447: Soubor \"%s\" nelze v path nalézt"
+
+msgid "Edit with &multiple Vims"
+msgstr "Editace &multiple Vimy"
+
+msgid "Edit with single &Vim"
+msgstr "Editace jedním $Vim -em"
+
+msgid "Edit with &Vim"
+msgstr "Editace &Vim -em"
+
+msgid "Edit with existing Vim - &"
+msgstr "Editace existujícím Vimem - &"
+
+msgid "Edits the selected file(s) with Vim"
+msgstr "Editace vybraných souborù Vimem"
+
+msgid "Error creating process: Check if gvim is in your path!"
+msgstr "Chyba pøi spou¹tìní procesu: Zkontrolujte zdali je gvim v $PATH!"
+
+msgid "gvimext.dll error"
+msgstr "chyba gvimext.dll"
+
+msgid "Path length too long!"
+msgstr "Název (v path) je pøíli¹ dlouhý"
+
+msgid "--No lines in buffer--"
+msgstr "--Buffer neobsahuje ¾ádný øádek--"
+
+#.
+#. * The error messages that can be shared are included here.
+#. * Excluded are errors that are only used once and debugging messages.
+#.
+msgid "Command aborted"
+msgstr "Pøíkaz pøeru¹en"
+
+msgid "Argument required"
+msgstr "Je vy¾adován argument"
+
+msgid "E10: \\ should be followed by /, ? or &"
+msgstr "E10: po \\ by mìl následovat /. ? nebo &"
+
+msgid "E11: Invalid in command-line window; <CR> executes, CTRL-C quits"
+msgstr ""
+"E11: Chyba v oknì pøíkazové øádky; <CR> pro spu¹t¹ní, CTRL-C pro ukonèení"
+
+msgid "E12: Command not allowed from exrc/vimrc in current dir or tag search"
+msgstr ""
+"E12: Pøíkaz není z exrc/vimrc v aktuálním adresáøi èi pøi hledání tagu "
+"povolen."
+
+msgid "E13: File exists (add ! to override)"
+msgstr "E13: Soubor existuje (pou¾ijte ! pro vynucení)"
+
+msgid "Command failed"
+msgstr "Pøíkaz selhal"
+
+msgid "Internal error"
+msgstr "Vnitøní chyba"
+
+msgid "Interrupted"
+msgstr "Pøeru¹eno"
+
+msgid "E14: Invalid address"
+msgstr "E14: Chybná adresa"
+
+msgid "Invalid argument"
+msgstr "Chybný argument"
+
+#, c-format
+msgid "Invalid argument: %s"
+msgstr "Chybný argument: %s"
+
+#, c-format
+msgid "E15: Invalid expression: %s"
+msgstr "E15: Chybný výraz: %s"
+
+msgid "E16: Invalid range"
+msgstr "E16: Chybný rozsah"
+
+msgid "Invalid command"
+msgstr "Chybný pøíkaz"
+
+#, c-format
+msgid "E17: \"%s\" is a directory"
+msgstr "E17: \"%s\" je adresáøem"
+
+msgid "E18: Unexpected characters before '='"
+msgstr "E18: Neoèekávané znaky pøed '='"
+
+msgid "E19: Mark has invalid line number"
+msgstr "E19: Znaèka má chybné èíslo øádku"
+
+msgid "E20: Mark not set"
+msgstr "E20: není nastavena"
+
+msgid "E21: Cannot make changes, 'modifiable' is off"
+msgstr "E21: Nelze mìnit, je nastavena volba 'modifiable'"
+
+msgid "E22: Scripts nested too deep"
+msgstr "E22: Skript vnoøen pøíli¹ hluboko"
+
+msgid "E23: No alternate file"
+msgstr "E23: ®ádný alternativní soubor"
+
+msgid "E24: No such abbreviation"
+msgstr "E24: Taková zkratka neexistuje"
+
+msgid "No ! allowed"
+msgstr "! není povoleno"
+
+msgid "E25: GUI cannot be used: Not enabled at compile time"
+msgstr "E25: Nelze pou¾ít GUI: nebylo zapnuto pøi pøekladu programu"
+
+msgid "E26: Hebrew cannot be used: Not enabled at compile time\n"
+msgstr ""
+"E26: nelze pou¾ít hebrejský re¾im: nebyl zapnut pøi pøekladu programu\n"
+
+msgid "E27: Farsi cannot be used: Not enabled at compile time\n"
+msgstr "E27: Nelze pou¾ít farsi re¾im: nebyl zapnut pøi pøekladu programu\n"
+
+#, c-format
+msgid "E28: No such highlight group name: %s"
+msgstr "E28: Skupina zvýraznìní %s neexistuje"
+
+msgid "E29: No inserted text yet"
+msgstr "E29: Zatím není ¾ádný vlo¾ený text"
+
+msgid "E30: No previous command line"
+msgstr "E30: ®ádná pøedchozí pøíkazová øádka"
+
+msgid "E31: No such mapping"
+msgstr "E31: ®ádné takové mapování"
+
+msgid "No match"
+msgstr "®ádná shoda"
+
+#, c-format
+msgid "No match: %s"
+msgstr "®ádná shoda: %s"
+
+msgid "E32: No file name"
+msgstr "E32: ®ádný název souboru"
+
+msgid "E33: No previous substitute regular expression"
+msgstr "E33: ¾ádný pøedchozí regulární výraz"
+
+msgid "E34: No previous command"
+msgstr "E34: ®ádný pøedchozí pøíkaz"
+
+msgid "E35: No previous regular expression"
+msgstr "E35: ¾ádný pøedchozí regulární výraz"
+
+msgid "No range allowed"
+msgstr "Rozsah není povolen"
+
+msgid "E36: Not enough room"
+msgstr "E36: Nedostatek místa"
+
+#, c-format
+msgid "Can't create file %s"
+msgstr "Nelze vytvoøit soubor %s"
+
+msgid "Can't get temp file name"
+msgstr "Nelze získat název doèasného souboru"
+
+#, c-format
+msgid "Can't open file %s"
+msgstr "Nelze otevøít soubor %s"
+
+#, c-format
+msgid "Can't read file %s"
+msgstr "Nelze èíst soubor %s"
+
+msgid "E37: No write since last change (use ! to override)"
+msgstr "E37: Neulo¾ené zmìny (pou¾ijte ! pro vynucení)"
+
+msgid "E38: Null argument"
+msgstr "E38: Nulový argument"
+
+msgid "E39: Number expected"
+msgstr "E39: Oèekáváno èíslo"
+
+#, c-format
+msgid "E40: Can't open errorfile %s"
+msgstr "E40: Nelze otevøít chybový soubor %s"
+
+msgid "E41: Out of memory!"
+msgstr "E41: Nedostatek pamìti!"
+
+msgid "Pattern not found"
+msgstr "Vzor nenalezen"
+
+#, c-format
+msgid "Pattern not found: %s"
+msgstr "Vzor nenalezen: %s"
+
+msgid "Argument must be positive"
+msgstr "Argument musí být kladný"
+
+msgid "E42: No Errors"
+msgstr "E42: ®ádné chyby"
+
+msgid "E43: Damaged match string"
+msgstr "E43: Po¹kozený øetìzec pro vyhledávání"
+
+msgid "E44: Corrupted regexp program"
+msgstr "E44: po¹kozený regexp program"
+
+msgid "E45: 'readonly' option is set (use ! to override)"
+msgstr "E45: 'nastavena volba 'readonly' (pou¾ijte ! pro vynucení)"
+
+#, c-format
+msgid "E46: Cannot set read-only variable \"%s\""
+msgstr "E46: Nelze nastavit pouze_pro_ètení promìnnou \"%s\""
+
+msgid "E47: Error while reading errorfile"
+msgstr "E47: Chyba pøi ètení chybového souboru"
+
+msgid "E48: Not allowed in sandbox"
+msgstr "E48: Není v bezpeènostní schránce povoleno"
+
+msgid "E49: Invalid scroll size"
+msgstr "E49: Chybná hodnota volby 'scroll'"
+
+msgid "E91: 'shell' option is empty"
+msgstr "E91: volba 'shell' je prázdná"
+
+msgid "E72: Close error on swap file"
+msgstr "E72: Chyba pøi uzavírání odkládacího souboru"
+
+msgid "E73: tag stack empty"
+msgstr "E73: seznam tagù je prázdný"
+
+msgid "E74: Command too complex"
+msgstr "E74: Pøíkaz je pøíli¹ slo¾itý"
+
+msgid "E75: Name too long"
+msgstr "E75: Název je pøíli¹ dlouhý"
+
+msgid "E76: Too many ["
+msgstr "E76: pøíli¹ mnoho ["
+
+msgid "E77: Too many file names"
+msgstr "E77: Pøíli¹ mnoho názvù souborù"
+
+msgid "Trailing characters"
+msgstr "Nadbyteèné znaky na konci"
+
+msgid "E78: Unknown mark"
+msgstr "E78: Neznámá znaèka"
+
+msgid "E79: Cannot expand wildcards"
+msgstr "E79: Nelze expandovat ¾olíkové znaky"
+
+msgid "E80: Error while writing"
+msgstr "E80: Chyba pøi ukládání"
+
+msgid "Zero count"
+msgstr "Nulový poèet"
+
+msgid "E81: Using <SID> not in a script context"
+msgstr "E81: Pou¾ití <SID> mimo kontext skriptu"
diff --git a/src/po/da.po b/src/po/da.po
new file mode 100644
index 0000000..f5e11da
--- /dev/null
+++ b/src/po/da.po
@@ -0,0 +1,7098 @@
+# Danish translation for Vim
+# Copyright (C) 2018 The Vim authors
+# This file is distributed under the same license as the vim package.
+# scootergrisen, 2018.
+msgid ""
+msgstr ""
+"Project-Id-Version: Vim 8.1\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2018-07-18 21:20+0200\n"
+"PO-Revision-Date: 2018-08-17 00:15+0200\n"
+"Last-Translator: scootergrisen\n"
+"Language-Team: Danish\n"
+"Language: da\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+msgid "E831: bf_key_init() called with empty password"
+msgstr "E831: bf_key_init() kaldt med tom adgangskode"
+
+msgid "E820: sizeof(uint32_t) != 4"
+msgstr "E820: sizeof(uint32_t) != 4"
+
+msgid "E817: Blowfish big/little endian use wrong"
+msgstr "E817: Forkert brug af stor/lille byterækkefølge for blowfish"
+
+msgid "E818: sha256 test failed"
+msgstr "E818: sha256-test mislykkede"
+
+msgid "E819: Blowfish test failed"
+msgstr "E819: Blowfish-test mislykkede"
+
+msgid "[Location List]"
+msgstr "[Placeringsliste]"
+
+msgid "[Quickfix List]"
+msgstr "[Quickfix-liste]"
+
+msgid "E855: Autocommands caused command to abort"
+msgstr "E855: Autokommandoer forårsagede afbrydelse af kommando"
+
+msgid "E82: Cannot allocate any buffer, exiting..."
+msgstr "E82: Kan ikke allokere buffer, afslutter..."
+
+msgid "E83: Cannot allocate buffer, using other one..."
+msgstr "E83: Kan ikke allokere buffer, bruger en anden..."
+
+msgid "E931: Buffer cannot be registered"
+msgstr "E931: Buffer kan ikke registreres"
+
+msgid "E937: Attempt to delete a buffer that is in use"
+msgstr "E937: Forsøg på at slette en buffer som er i brug"
+
+msgid "E515: No buffers were unloaded"
+msgstr "E515: Ingen buffere blev udlæst"
+
+msgid "E516: No buffers were deleted"
+msgstr "E516: Ingen brugere blev slettet"
+
+msgid "E517: No buffers were wiped out"
+msgstr "E517: Ingen buffere blev ryddet"
+
+msgid "1 buffer unloaded"
+msgstr "1 buffer udlæst"
+
+#, c-format
+msgid "%d buffers unloaded"
+msgstr "%d buffere udlæst"
+
+msgid "1 buffer deleted"
+msgstr "1 buffer slettet"
+
+#, c-format
+msgid "%d buffers deleted"
+msgstr "%d buffere slettet"
+
+msgid "1 buffer wiped out"
+msgstr "1 buffer ryddet"
+
+#, c-format
+msgid "%d buffers wiped out"
+msgstr "%d buffere ryddet"
+
+msgid "E90: Cannot unload last buffer"
+msgstr "E90: Kan ikke udlæse sidste buffer"
+
+msgid "E84: No modified buffer found"
+msgstr "E84: Fandt ingen ændret buffer"
+
+msgid "E85: There is no listed buffer"
+msgstr "E85: Der er ingen oplistet buffer"
+
+msgid "E87: Cannot go beyond last buffer"
+msgstr "E87: Kan ikke gå over sidste buffer"
+
+msgid "E88: Cannot go before first buffer"
+msgstr "E88: Kan ikke gå før første buffer"
+
+#, c-format
+msgid "E89: No write since last change for buffer %ld (add ! to override)"
+msgstr ""
+"E89: Ingen skrivning siden sidste ændring for bufferen %ld (tilføj ! for at "
+"tilsidesætte)"
+
+msgid "E948: Job still running (add ! to end the job)"
+msgstr "E948: Job kører stadig (tilføj ! for at afslutte jobbet)"
+
+msgid "E37: No write since last change (add ! to override)"
+msgstr ""
+"E37: Ingen skrivning siden sidste ændring (tilføj ! for at tilsidesætte)"
+
+msgid "E948: Job still running"
+msgstr "E948: Job kører stadig"
+
+msgid "E37: No write since last change"
+msgstr "E37: Ingen skrivning siden sidste ændring"
+
+msgid "W14: Warning: List of file names overflow"
+msgstr "W14: Advarsel: Overløb i liste over filnavne"
+
+#, c-format
+msgid "E92: Buffer %ld not found"
+msgstr "E92: Bufferen %ld blev ikke fundet"
+
+#, c-format
+msgid "E93: More than one match for %s"
+msgstr "E93: Flere end ét match for %s"
+
+#, c-format
+msgid "E94: No matching buffer for %s"
+msgstr "E94: Ingen matchende buffer for %s"
+
+#, c-format
+msgid "line %ld"
+msgstr "linje %ld"
+
+msgid "E95: Buffer with this name already exists"
+msgstr "E95: Buffer med dette navn findes allerede"
+
+msgid " [Modified]"
+msgstr " [Ændret]"
+
+msgid "[Not edited]"
+msgstr "[Ikke redigeret]"
+
+msgid "[New file]"
+msgstr "[Ny fil]"
+
+msgid "[Read errors]"
+msgstr "[Læsefejl]"
+
+msgid "[RO]"
+msgstr "[SB]"
+
+msgid "[readonly]"
+msgstr "[skrivebeskyttet]"
+
+#, c-format
+msgid "1 line --%d%%--"
+msgstr "1 linje --%d%%--"
+
+#, c-format
+msgid "%ld lines --%d%%--"
+msgstr "%ld linjer --%d%%--"
+
+#, c-format
+msgid "line %ld of %ld --%d%%-- col "
+msgstr "linje %ld af %ld --%d%%-- kol "
+
+msgid "[No Name]"
+msgstr "[Intet navn]"
+
+msgid "help"
+msgstr "hjælp"
+
+msgid "[Help]"
+msgstr "[Hjælp]"
+
+msgid "[Preview]"
+msgstr "[Forhåndsvisning]"
+
+msgid "All"
+msgstr "Alt"
+
+msgid "Bot"
+msgstr "Nederst"
+
+msgid "Top"
+msgstr "Øverst"
+
+msgid ""
+"\n"
+"# Buffer list:\n"
+msgstr ""
+"\n"
+"# Bufferliste:\n"
+
+msgid "E382: Cannot write, 'buftype' option is set"
+msgstr "E382: Kan ikke skrive, 'buftype'-tilvalget er sat"
+
+msgid "[Prompt]"
+msgstr "[Prompt]"
+
+msgid "[Scratch]"
+msgstr "[Kladdeblok]"
+
+msgid ""
+"\n"
+"--- Signs ---"
+msgstr ""
+"\n"
+"--- Signs ---"
+
+#, c-format
+msgid "Signs for %s:"
+msgstr "Signs for %s:"
+
+#, c-format
+msgid " line=%ld id=%d name=%s"
+msgstr " linje=%ld id=%d navn=%s"
+
+msgid "E902: Cannot connect to port"
+msgstr "E902: Kan ikke oprette forbindelse til port"
+
+msgid "E901: gethostbyname() in channel_open()"
+msgstr "E901: gethostbyname() i channel_open()"
+
+msgid "E898: socket() in channel_open()"
+msgstr "E898: socket() i channel_open()"
+
+msgid "E903: received command with non-string argument"
+msgstr "E903: modtog kommando med argument som ikke er en streng"
+
+msgid "E904: last argument for expr/call must be a number"
+msgstr "E904: sidste argument for udtryk/kald skal være et nummer"
+
+msgid "E904: third argument for call must be a list"
+msgstr "E904: tredje argument for kald skal være en liste"
+
+#, c-format
+msgid "E905: received unknown command: %s"
+msgstr "E905: modtog ukendt kommando: %s"
+
+#, c-format
+msgid "E630: %s(): write while not connected"
+msgstr "E630: %s(): skrivning mens der ikke er forbindelse"
+
+#, c-format
+msgid "E631: %s(): write failed"
+msgstr "E631: %s(): skrivning mislykkedes"
+
+#, c-format
+msgid "E917: Cannot use a callback with %s()"
+msgstr "E917: Kan ikke bruge et callback med %s()"
+
+msgid "E912: cannot use ch_evalexpr()/ch_sendexpr() with a raw or nl channel"
+msgstr ""
+"E912: kan ikke bruge ch_evalexpr()/ch_sendexpr() med en rå- eller nl-kanal"
+
+msgid "E906: not an open channel"
+msgstr "E906: ikke en åben kanal"
+
+msgid "E920: _io file requires _name to be set"
+msgstr "E920: _io-fil kræver at _name er sat"
+
+msgid "E915: in_io buffer requires in_buf or in_name to be set"
+msgstr "E915: in_io-buffer kræver at in_buf eller in_name er sat"
+
+#, c-format
+msgid "E918: buffer must be loaded: %s"
+msgstr "E918: buffer skal være indlæst: %s"
+
+msgid "E821: File is encrypted with unknown method"
+msgstr "E821: Filen er krypteret med ukendt metode"
+
+msgid "Warning: Using a weak encryption method; see :help 'cm'"
+msgstr "Advarsel: Bruger en svag krypteringsmetode; se :help 'cm'"
+
+msgid "Enter encryption key: "
+msgstr "Indtast krypteringsnøgle: "
+
+msgid "Enter same key again: "
+msgstr "Indtast samme nøgle igen: "
+
+msgid "Keys don't match!"
+msgstr "Nøglerne er ikke ens!"
+
+msgid "[crypted]"
+msgstr "[crypted]"
+
+#, c-format
+msgid "E720: Missing colon in Dictionary: %s"
+msgstr "E720: Manglende kolon i ordbog: %s"
+
+#, c-format
+msgid "E721: Duplicate key in Dictionary: \"%s\""
+msgstr "E721: Duplikeret nøgle i ordbog: \"%s\""
+
+#, c-format
+msgid "E722: Missing comma in Dictionary: %s"
+msgstr "E722: Manglende komma i ordbog: %s"
+
+#, c-format
+msgid "E723: Missing end of Dictionary '}': %s"
+msgstr "E723: Manglende slutning på ordbog '}': %s"
+
+msgid "extend() argument"
+msgstr "extend()-argument"
+
+#, c-format
+msgid "E737: Key already exists: %s"
+msgstr "E737: Nøgle findes allerede: %s"
+
+#, c-format
+msgid "E96: Cannot diff more than %ld buffers"
+msgstr "E96: Kan ikke diff'e flere end %ld buffere"
+
+msgid "E810: Cannot read or write temp files"
+msgstr "E810: Kan ikke læse eller skrive midlertidige filer"
+
+msgid "E97: Cannot create diffs"
+msgstr "E97: Kan ikke oprette diff'er"
+
+msgid "Patch file"
+msgstr "Patch-fil"
+
+msgid "E816: Cannot read patch output"
+msgstr "E816: Kan ikke læse patch-output"
+
+msgid "E98: Cannot read diff output"
+msgstr "E98: Kan ikke læse diff-output"
+
+msgid "E99: Current buffer is not in diff mode"
+msgstr "E99: Nuværende buffer er ikke i diff-tilstand"
+
+msgid "E793: No other buffer in diff mode is modifiable"
+msgstr "E793: Ingen anden buffer i diff-tilstand kan ændres"
+
+msgid "E100: No other buffer in diff mode"
+msgstr "E100: Ingen anden buffer i diff-tilstand"
+
+msgid "E101: More than two buffers in diff mode, don't know which one to use"
+msgstr ""
+"E101: Mere end to buffere i diff-tilstand, ved ikke hvilke der skal bruges"
+
+#, c-format
+msgid "E102: Can't find buffer \"%s\""
+msgstr "E102: Kan ikke finde bufferen \"%s\""
+
+#, c-format
+msgid "E103: Buffer \"%s\" is not in diff mode"
+msgstr "E103: Bufferen \"%s\" er ikke i diff-tilstand"
+
+msgid "E787: Buffer changed unexpectedly"
+msgstr "E787: Buffer ændret uventet"
+
+msgid "E104: Escape not allowed in digraph"
+msgstr "E104: Escape ikke tilladt i digraf"
+
+msgid "E544: Keymap file not found"
+msgstr "E544: Keymap-fil ikke fundet"
+
+msgid "E105: Using :loadkeymap not in a sourced file"
+msgstr "E105: Bruger :loadkeymap ikke i en sourced fil"
+
+msgid "E791: Empty keymap entry"
+msgstr "E791: Tom keymap-post"
+
+msgid " Keyword completion (^N^P)"
+msgstr " Fuldførelse af nøgleord (^N^P)"
+
+msgid " ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+msgstr " ^X tilstand (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+
+msgid " Whole line completion (^L^N^P)"
+msgstr " Fuldførelse af hel linje (^L^N^P)"
+
+msgid " File name completion (^F^N^P)"
+msgstr " Fuldførelse af filnavn (^F^N^P)"
+
+msgid " Tag completion (^]^N^P)"
+msgstr " Fuldførelse af tag (^]^N^P)"
+
+msgid " Path pattern completion (^N^P)"
+msgstr " Fuldførelse af sti (^N^P)"
+
+msgid " Definition completion (^D^N^P)"
+msgstr " Fuldførelse af definition (^D^N^P)"
+
+msgid " Dictionary completion (^K^N^P)"
+msgstr " Fuldførelse af ordbog (^K^N^P)"
+
+msgid " Thesaurus completion (^T^N^P)"
+msgstr " Fuldførelse af tesaurus (^T^N^P)"
+
+msgid " Command-line completion (^V^N^P)"
+msgstr " Fuldførelse af kommandolinje (^V^N^P)"
+
+msgid " User defined completion (^U^N^P)"
+msgstr " Fuldførelse af brugerdefineret (^U^N^P)"
+
+msgid " Omni completion (^O^N^P)"
+msgstr " Fuldførelse af omni (^O^N^P)"
+
+msgid " Spelling suggestion (s^N^P)"
+msgstr " Staveforslag (s^N^P)"
+
+msgid " Keyword Local completion (^N^P)"
+msgstr " Fuldførelse af nøgleord local (^N^P)"
+
+msgid "Hit end of paragraph"
+msgstr "Stødte på slutningen af afsnit"
+
+msgid "E839: Completion function changed window"
+msgstr "E839: Fuldførelse-funktion ændrede vindue"
+
+msgid "E840: Completion function deleted text"
+msgstr "E840: Fuldførelse-funktion slettede tekst"
+
+msgid "'dictionary' option is empty"
+msgstr "'dictionary'-tilvalget er tomt"
+
+msgid "'thesaurus' option is empty"
+msgstr "'thesaurus'-tilvalget er tomt"
+
+#, c-format
+msgid "Scanning dictionary: %s"
+msgstr "Skanner ordbog: %s"
+
+msgid " (insert) Scroll (^E/^Y)"
+msgstr " (indsæt) Rul (^E/^Y)"
+
+msgid " (replace) Scroll (^E/^Y)"
+msgstr " (erstat) Rul (^E/^Y)"
+
+#, c-format
+msgid "Scanning: %s"
+msgstr "Skanner: %s"
+
+msgid "Scanning tags."
+msgstr "Skanner tags."
+
+msgid "match in file"
+msgstr "match i fil"
+
+msgid " Adding"
+msgstr " Tilføjer"
+
+msgid "-- Searching..."
+msgstr "-- Søger..."
+
+msgid "Back at original"
+msgstr "Tilbage ved original"
+
+msgid "Word from other line"
+msgstr "Ord fra anden linje"
+
+msgid "The only match"
+msgstr "Det eneste match"
+
+#, c-format
+msgid "match %d of %d"
+msgstr "match %d af %d"
+
+#, c-format
+msgid "match %d"
+msgstr "match %d"
+
+msgid "E18: Unexpected characters in :let"
+msgstr "E18: Uventede tegn i :let"
+
+#, c-format
+msgid "E121: Undefined variable: %s"
+msgstr "E121: Udefineret variabel: %s"
+
+msgid "E111: Missing ']'"
+msgstr "E111: Manglende ']'"
+
+msgid "E719: Cannot use [:] with a Dictionary"
+msgstr "E719: Kan ikke bruge [:] med en ordbog"
+
+#, c-format
+msgid "E734: Wrong variable type for %s="
+msgstr "E734: Forkert variabeltype for %s="
+
+#, c-format
+msgid "E461: Illegal variable name: %s"
+msgstr "E461: Ulovligt variabelnavn: %s"
+
+msgid "E806: using Float as a String"
+msgstr "E806: bruger flydende kommatal som en streng"
+
+msgid "E687: Less targets than List items"
+msgstr "E687: Færre mål end listepunkter"
+
+msgid "E688: More targets than List items"
+msgstr "E688: Flere mål end listepunkter"
+
+msgid "Double ; in list of variables"
+msgstr "Dobbelt ; i liste over variabler"
+
+#, c-format
+msgid "E738: Can't list variables for %s"
+msgstr "E738: Kan ikke opliste variabler for %s"
+
+msgid "E689: Can only index a List or Dictionary"
+msgstr "E689: Kan kun indeksere en liste eller ordbog"
+
+msgid "E708: [:] must come last"
+msgstr "E708: [:] skal være sidst"
+
+msgid "E709: [:] requires a List value"
+msgstr "E709: [:] kræver en listeværdi"
+
+msgid "E710: List value has more items than target"
+msgstr "E710: Listeværdi har flere punkter end mål"
+
+msgid "E711: List value has not enough items"
+msgstr "E711: Listeværdi har ikke nok punkter"
+
+msgid "E690: Missing \"in\" after :for"
+msgstr "E690: Manglende \"in\" efter :for"
+
+#, c-format
+msgid "E108: No such variable: \"%s\""
+msgstr "E108: Ingen sådan variabel: \"%s\""
+
+#, c-format
+msgid "E940: Cannot lock or unlock variable %s"
+msgstr "E940: Kan ikke låse eller låse op for variablen %s"
+
+msgid "E743: variable nested too deep for (un)lock"
+msgstr "E743: variabel indlejret for dybt til at blive låst/låst op"
+
+msgid "E109: Missing ':' after '?'"
+msgstr "E109: Manglende ':' efter '?'"
+
+msgid "E804: Cannot use '%' with Float"
+msgstr "E804: Kan ikke bruge '%' med flydende kommatal"
+
+msgid "E110: Missing ')'"
+msgstr "E110: Manglende ')'"
+
+msgid "E695: Cannot index a Funcref"
+msgstr "E695: Kan ikke indeksere en funcref"
+
+msgid "E909: Cannot index a special variable"
+msgstr "E909: Kan ikke indeksere en speciel variabel"
+
+#, c-format
+msgid "E112: Option name missing: %s"
+msgstr "E112: Tilvalgsnavn mangler: %s"
+
+#, c-format
+msgid "E113: Unknown option: %s"
+msgstr "E113: Ukendt tilvalg: %s"
+
+#, c-format
+msgid "E114: Missing quote: %s"
+msgstr "E114: Manglende citationstegn: %s"
+
+#, c-format
+msgid "E115: Missing quote: %s"
+msgstr "E115: Manglende citationstegn: %s"
+
+msgid "Not enough memory to set references, garbage collection aborted!"
+msgstr ""
+"Ikke nok hukommelse til at sætte referencer, affaldsindsamling afbrudt!"
+
+msgid "E724: variable nested too deep for displaying"
+msgstr "E724: variabel indlejret for dybt til at blive vist"
+
+msgid "E805: Using a Float as a Number"
+msgstr "E805: Bruger et flydende kommatal som et nummer"
+
+msgid "E703: Using a Funcref as a Number"
+msgstr "E703: Bruger en funcref som et nummer"
+
+msgid "E745: Using a List as a Number"
+msgstr "E745: Bruger en liste som et nummer"
+
+msgid "E728: Using a Dictionary as a Number"
+msgstr "E728: Bruger en ordbog som et nummer"
+
+msgid "E910: Using a Job as a Number"
+msgstr "E910: Bruger et job som et nummer"
+
+msgid "E913: Using a Channel as a Number"
+msgstr "E913: Bruger en kanal som et nummer"
+
+msgid "E891: Using a Funcref as a Float"
+msgstr "E891: Bruger en funcref som et fyldende kommatal"
+
+msgid "E892: Using a String as a Float"
+msgstr "E892: Bruger en streng som et flydende kommatal"
+
+msgid "E893: Using a List as a Float"
+msgstr "E893: Bruger en liste som et flydende kommatal"
+
+msgid "E894: Using a Dictionary as a Float"
+msgstr "E894: Bruger en ordbog som et flydende kommatal"
+
+msgid "E907: Using a special value as a Float"
+msgstr "E907: Bruger en speciel værdi som et flydende kommatal"
+
+msgid "E911: Using a Job as a Float"
+msgstr "E911: Bruger et job som et flydende kommatal"
+
+msgid "E914: Using a Channel as a Float"
+msgstr "E914: Bruger en kanal som et flydende kommatal"
+
+msgid "E729: using Funcref as a String"
+msgstr "E729: bruger funcref som en streng"
+
+msgid "E730: using List as a String"
+msgstr "E730: bruger liste som en streng"
+
+msgid "E731: using Dictionary as a String"
+msgstr "E731: bruger ordbog som en streng"
+
+msgid "E908: using an invalid value as a String"
+msgstr "E908: bruger en ugyldig værdi som en streng"
+
+#, c-format
+msgid "E795: Cannot delete variable %s"
+msgstr "E795: Kan ikke slette variablen %s"
+
+#, c-format
+msgid "E704: Funcref variable name must start with a capital: %s"
+msgstr "E704: Funcref-variabelnavn skal begynde med et stort bogstav: %s"
+
+#, c-format
+msgid "E705: Variable name conflicts with existing function: %s"
+msgstr "E705: Variabelnavn er i konflikt med eksisterende funktion: %s"
+
+#, c-format
+msgid "E741: Value is locked: %s"
+msgstr "E741: Værdien er låst: %s"
+
+msgid "Unknown"
+msgstr "Ukendt"
+
+#, c-format
+msgid "E742: Cannot change value of %s"
+msgstr "E742: Kan ikke ændre værdien af %s"
+
+msgid "E698: variable nested too deep for making a copy"
+msgstr "E698: variabel indlejret for dybt til at lave en kopi"
+
+msgid ""
+"\n"
+"# global variables:\n"
+msgstr ""
+"\n"
+"# globale variabler:\n"
+
+msgid ""
+"\n"
+"\tLast set from "
+msgstr ""
+"\n"
+"\tSidst sat fra "
+
+msgid "E691: Can only compare List with List"
+msgstr "E691: Kan kun sammenligne liste med liste"
+
+msgid "E692: Invalid operation for List"
+msgstr "E692: Ugyldig handling for liste"
+
+msgid "E735: Can only compare Dictionary with Dictionary"
+msgstr "E735: Kan kun sammenligne ordbog med ordbog"
+
+msgid "E736: Invalid operation for Dictionary"
+msgstr "E736: Ugyldig handling for ordbog"
+
+msgid "E694: Invalid operation for Funcrefs"
+msgstr "E694: Ugyldig handling for funcref'er"
+
+msgid "map() argument"
+msgstr "map()-argument"
+
+msgid "filter() argument"
+msgstr "filter()-argument"
+
+#, c-format
+msgid "E686: Argument of %s must be a List"
+msgstr "E686: Argument af %s skal være en liste"
+
+msgid "E928: String required"
+msgstr "E928: Streng kræves"
+
+msgid "E808: Number or Float required"
+msgstr "E808: Nummer eller flydende kommatal kræves"
+
+msgid "add() argument"
+msgstr "add()-argument"
+
+msgid "E785: complete() can only be used in Insert mode"
+msgstr "E785: complete() kan kun bruges i indsæt-tilstand"
+
+msgid "&Ok"
+msgstr "&Ok"
+
+#, c-format
+msgid "+-%s%3ld line: "
+msgid_plural "+-%s%3ld lines: "
+msgstr[0] "+-%s%3ld linje: "
+msgstr[1] "+-%s%3ld linjer: "
+
+#, c-format
+msgid "E700: Unknown function: %s"
+msgstr "E700: Ukendt funktion: %s"
+
+msgid "E922: expected a dict"
+msgstr "E922: ventede en ordbog"
+
+msgid "E923: Second argument of function() must be a list or a dict"
+msgstr "E923: Andet argument af function() skal være en liste eller en ordbog"
+
+msgid ""
+"&OK\n"
+"&Cancel"
+msgstr ""
+"&OK\n"
+"&Annuller"
+
+msgid "called inputrestore() more often than inputsave()"
+msgstr "kaldte inputrestore() flere gange end inputsave()"
+
+msgid "insert() argument"
+msgstr "insert()-argument"
+
+msgid "E786: Range not allowed"
+msgstr "E786: Område ikke tilladt"
+
+msgid "E916: not a valid job"
+msgstr "E916: ikke et gyldigt job"
+
+msgid "E701: Invalid type for len()"
+msgstr "E701: Ugyldig type for len()"
+
+#, c-format
+msgid "E798: ID is reserved for \":match\": %ld"
+msgstr "E798: ID er reserveret til \":match\": %ld"
+
+msgid "E726: Stride is zero"
+msgstr "E726: Stride er nul"
+
+msgid "E727: Start past end"
+msgstr "E727: Start efter slutningen"
+
+msgid "<empty>"
+msgstr "<tom>"
+
+msgid "E240: No connection to the X server"
+msgstr "E240: Ingen forbindelse til X-serveren"
+
+#, c-format
+msgid "E241: Unable to send to %s"
+msgstr "E241: Kan ikke sende til %s"
+
+msgid "E277: Unable to read a server reply"
+msgstr "E277: Kan ikke læse et serversvar"
+
+msgid "E941: already started a server"
+msgstr "E941: allerede startet en server"
+
+msgid "E942: +clientserver feature not available"
+msgstr "E942: +clientserver-funktionalitet ikke tilgængelig"
+
+msgid "remove() argument"
+msgstr "remove()-argument"
+
+msgid "E655: Too many symbolic links (cycle?)"
+msgstr "E655: For mange symbolske links (cyklus?)"
+
+msgid "reverse() argument"
+msgstr "reverse()-argument"
+
+msgid "E258: Unable to send to client"
+msgstr "E258: Kan ikke sende til klient"
+
+#, c-format
+msgid "E927: Invalid action: '%s'"
+msgstr "E927: Ugyldig handling: '%s'"
+
+msgid "sort() argument"
+msgstr "sort()-argument"
+
+msgid "uniq() argument"
+msgstr "uniq()-argument"
+
+msgid "E702: Sort compare function failed"
+msgstr "E702: Sort-sammenligningsfunktion mislykkedes"
+
+msgid "E882: Uniq compare function failed"
+msgstr "E882: Uniq-sammenligningsfunktion mislykkedes"
+
+msgid "(Invalid)"
+msgstr "(Ugyldig)"
+
+#, c-format
+msgid "E935: invalid submatch number: %d"
+msgstr "E935: ugyldigt undermatch-nummer: %d"
+
+msgid "E677: Error writing temp file"
+msgstr "E677: Fejl ved skrivning af midlertidig fil"
+
+msgid "E921: Invalid callback argument"
+msgstr "E921: Ugyldigt callback-argument"
+
+#, c-format
+msgid "<%s>%s%s %d, Hex %02x, Oct %03o, Digr %s"
+msgstr "<%s>%s%s %d, hex %02x, oct %03o, digr %s"
+
+#, c-format
+msgid "<%s>%s%s %d, Hex %02x, Octal %03o"
+msgstr "<%s>%s%s %d, hex %02x, octal %03o"
+
+#, c-format
+msgid "> %d, Hex %04x, Oct %o, Digr %s"
+msgstr "> %d, hex %04x, oct %o, digr %s"
+
+#, c-format
+msgid "> %d, Hex %08x, Oct %o, Digr %s"
+msgstr "> %d, hex %08x, oct %o, digr %s"
+
+#, c-format
+msgid "> %d, Hex %04x, Octal %o"
+msgstr "> %d, hex %04x, octal %o"
+
+#, c-format
+msgid "> %d, Hex %08x, Octal %o"
+msgstr "> %d, hex %08x, octal %o"
+
+msgid "E134: Move lines into themselves"
+msgstr "E134: flyt linjer ind i dem selv"
+
+msgid "1 line moved"
+msgstr "1 linje flyttet"
+
+#, c-format
+msgid "%ld lines moved"
+msgstr "%ld linjer flyttet"
+
+#, c-format
+msgid "%ld lines filtered"
+msgstr "%ld linjer filtreret"
+
+msgid "E135: *Filter* Autocommands must not change current buffer"
+msgstr "E135: *Filter*-autokommandoer må ikke ændre nuværende buffer"
+
+msgid "[No write since last change]\n"
+msgstr "[Ingen skrivning siden sidste ændring]\n"
+
+#, c-format
+msgid "%sviminfo: %s in line: "
+msgstr "%sviminfo: %s på linje: "
+
+msgid "E136: viminfo: Too many errors, skipping rest of file"
+msgstr "E136: viminfo: For mange fejl, springer resten af filen over"
+
+#, c-format
+msgid "Reading viminfo file \"%s\"%s%s%s"
+msgstr "Læser viminfo-filen \"%s\"%s%s%s"
+
+msgid " info"
+msgstr " info"
+
+msgid " marks"
+msgstr " mærker"
+
+msgid " oldfiles"
+msgstr " gamle filer"
+
+msgid " FAILED"
+msgstr " MISLYKKEDES"
+
+#, c-format
+msgid "E137: Viminfo file is not writable: %s"
+msgstr "E137: Viminfo-filen er skrivebeskyttet: %s"
+
+#, c-format
+msgid "E929: Too many viminfo temp files, like %s!"
+msgstr "E929: For mange midlertidige filer for viminfo, såsom %s!"
+
+#, c-format
+msgid "E138: Can't write viminfo file %s!"
+msgstr "E138: Kan ikke skrive viminfo-filen %s!"
+
+#, c-format
+msgid "Writing viminfo file \"%s\""
+msgstr "Skriver viminfo-filen \"%s\""
+
+#, c-format
+msgid "E886: Can't rename viminfo file to %s!"
+msgstr "E886: Kan ikke omdøbe viminfo-fil til %s!"
+
+#, c-format
+msgid "# This viminfo file was generated by Vim %s.\n"
+msgstr "# Denne viminfo-fil blev genereret af Vim %s.\n"
+
+msgid ""
+"# You may edit it if you're careful!\n"
+"\n"
+msgstr ""
+"# Du kan redigere den, hvis du er forsigtig!\n"
+"\n"
+
+msgid "# Value of 'encoding' when this file was written\n"
+msgstr "# Værdien af 'encoding' da filen blev skrevet\n"
+
+msgid "Illegal starting char"
+msgstr "Ulovligt tegn i begyndelsen"
+
+msgid ""
+"\n"
+"# Bar lines, copied verbatim:\n"
+msgstr ""
+"\n"
+"#-bjælkelinjer, kopieret ordret:\n"
+
+msgid "Save As"
+msgstr "Gem som"
+
+msgid "Write partial file?"
+msgstr "Skriv ufuldstændig fil?"
+
+msgid "E140: Use ! to write partial buffer"
+msgstr "E140: Brug ! til at skrive ufuldstændig buffer"
+
+#, c-format
+msgid "Overwrite existing file \"%s\"?"
+msgstr "Overskriv eksisterende fil \"%s\"?"
+
+#, c-format
+msgid "Swap file \"%s\" exists, overwrite anyway?"
+msgstr "Swap-filen \"%s\" findes, overskriv alligevel?"
+
+#, c-format
+msgid "E768: Swap file exists: %s (:silent! overrides)"
+msgstr "E768: Swap-filen findes: %s (:silent! tilsidesætter)"
+
+#, c-format
+msgid "E141: No file name for buffer %ld"
+msgstr "E141: Intet filnavn for buffer %ld"
+
+msgid "E142: File not written: Writing is disabled by 'write' option"
+msgstr "E142: Fil ikke skrevet: Skrivning er deaktiveret af 'write'-tilvalget"
+
+#, c-format
+msgid ""
+"'readonly' option is set for \"%s\".\n"
+"Do you wish to write anyway?"
+msgstr ""
+"'readonly'-tilvalget er sat for \"%s\".\n"
+"Vil du skrive alligevel?"
+
+#, c-format
+msgid ""
+"File permissions of \"%s\" are read-only.\n"
+"It may still be possible to write it.\n"
+"Do you wish to try?"
+msgstr ""
+"Filtilladelserne for \"%s\" er skrivebeskyttede.\n"
+"Der kan stadig være mulighed for at skrive den.\n"
+"Vil du prøve?"
+
+#, c-format
+msgid "E505: \"%s\" is read-only (add ! to override)"
+msgstr "E505: \"%s\" er skrivebeskyttet (tilføj ! for at tilsidesætte)"
+
+msgid "Edit File"
+msgstr "Rediger fil"
+
+#, c-format
+msgid "E143: Autocommands unexpectedly deleted new buffer %s"
+msgstr "E143: Autokommandoer slettede uventede ny buffer %s"
+
+msgid "E144: non-numeric argument to :z"
+msgstr "E144: ikke-numerisk argument til :z"
+
+msgid "E145: Shell commands not allowed in rvim"
+msgstr "E145: Skalkommandoer er ikke tilladt i rvim"
+
+msgid "E146: Regular expressions can't be delimited by letters"
+msgstr "E146: Regulære udtryk kan ikke afgrænses af bogstaver"
+
+#, c-format
+msgid "replace with %s (y/n/a/q/l/^E/^Y)?"
+msgstr "erstat med %s (y/n/a/q/l/^E/^Y)?"
+
+msgid "(Interrupted) "
+msgstr "(Afbrudt) "
+
+msgid "1 match"
+msgstr "1 match"
+
+msgid "1 substitution"
+msgstr "1 erstatning"
+
+#, c-format
+msgid "%ld matches"
+msgstr "%ld match"
+
+#, c-format
+msgid "%ld substitutions"
+msgstr "%ld erstatninger"
+
+msgid " on 1 line"
+msgstr " på 1 linje"
+
+#, c-format
+msgid " on %ld lines"
+msgstr " på %ld linjer"
+
+msgid "E147: Cannot do :global recursive with a range"
+msgstr "E147: Kan ikke foretage :global rekursivt med et område"
+
+msgid "E148: Regular expression missing from global"
+msgstr "E148: Regulære udtryk mangler fra global"
+
+#, c-format
+msgid "Pattern found in every line: %s"
+msgstr "Mønster fundet på hver linje: %s"
+
+#, c-format
+msgid "Pattern not found: %s"
+msgstr "Mønster ikke fundet: %s"
+
+msgid ""
+"\n"
+"# Last Substitute String:\n"
+"$"
+msgstr ""
+"\n"
+"# Sidste erstatningsstreng:\n"
+"$"
+
+msgid "E478: Don't panic!"
+msgstr "E478: Tag det bare helt roligt!"
+
+#, c-format
+msgid "E661: Sorry, no '%s' help for %s"
+msgstr "E661: Beklager, ingen '%s' hjælp til %s"
+
+#, c-format
+msgid "E149: Sorry, no help for %s"
+msgstr "E149: Beklager, ingen hjælp til %s"
+
+#, c-format
+msgid "Sorry, help file \"%s\" not found"
+msgstr "Beklager, hjælpfilen \"%s\" ikke fundet"
+
+#, c-format
+msgid "E151: No match: %s"
+msgstr "E151: Intet match: %s"
+
+#, c-format
+msgid "E152: Cannot open %s for writing"
+msgstr "E152: Kan ikke åbne %s til skrivning"
+
+#, c-format
+msgid "E153: Unable to open %s for reading"
+msgstr "E153: Kan ikke åbne %s til læsning"
+
+#, c-format
+msgid "E670: Mix of help file encodings within a language: %s"
+msgstr "E670: Blanding af kodninger for hjælpfiler i samme sprog: %s"
+
+#, c-format
+msgid "E154: Duplicate tag \"%s\" in file %s/%s"
+msgstr "E154: Duplikeret tag \"%s\" i fil %s/%s"
+
+#, c-format
+msgid "E150: Not a directory: %s"
+msgstr "E150: Ikke en mappe: %s"
+
+#, c-format
+msgid "E160: Unknown sign command: %s"
+msgstr "E160: Ukendt sign-kommando: %s"
+
+msgid "E156: Missing sign name"
+msgstr "E156: Manglende sign-navn"
+
+msgid "E612: Too many signs defined"
+msgstr "E612: For mange signs defineret"
+
+#, c-format
+msgid "E239: Invalid sign text: %s"
+msgstr "E239: Ugyldig sign-tekst: %s"
+
+#, c-format
+msgid "E155: Unknown sign: %s"
+msgstr "E155: Ukendt sign: %s"
+
+msgid "E159: Missing sign number"
+msgstr "E159: Manglende sign-nummer"
+
+#, c-format
+msgid "E158: Invalid buffer name: %s"
+msgstr "E158: Ugyldigt buffernavn: %s"
+
+msgid "E934: Cannot jump to a buffer that does not have a name"
+msgstr "E934: Kan ikke hoppe til en buffer som ikke har et navn"
+
+#, c-format
+msgid "E157: Invalid sign ID: %ld"
+msgstr "E157: Ugyldigt sign-ID: %ld"
+
+#, c-format
+msgid "E885: Not possible to change sign %s"
+msgstr "E885: Det er ikke muligt at ændre sign %s"
+
+msgid " (NOT FOUND)"
+msgstr " (IKKE FUNDET)"
+
+msgid " (not supported)"
+msgstr " (understøttes ikke)"
+
+msgid "[Deleted]"
+msgstr "[Slettet]"
+
+msgid "No old files"
+msgstr "Ingen gamle filer"
+
+msgid "Entering Debug mode. Type \"cont\" to continue."
+msgstr "Går i fejlretningstilstand. Skriv \"cont\" for at fortsætte."
+
+#, c-format
+msgid "Oldval = \"%s\""
+msgstr "Oldval = \"%s\""
+
+#, c-format
+msgid "Newval = \"%s\""
+msgstr "Newval = \"%s\""
+
+#, c-format
+msgid "line %ld: %s"
+msgstr "linje %ld: %s"
+
+#, c-format
+msgid "cmd: %s"
+msgstr "cmd: %s"
+
+msgid "frame is zero"
+msgstr "ramme er nul"
+
+#, c-format
+msgid "frame at highest level: %d"
+msgstr "ramme på højeste niveau: %d"
+
+#, c-format
+msgid "Breakpoint in \"%s%s\" line %ld"
+msgstr "Breakpoint i \"%s%s\" linje %ld"
+
+#, c-format
+msgid "E161: Breakpoint not found: %s"
+msgstr "E161: Breakpoint ikke fundet: %s"
+
+msgid "No breakpoints defined"
+msgstr "Ingen breakpoints defineret"
+
+#, c-format
+msgid "%3d %s %s line %ld"
+msgstr "%3d %s %s linje %ld"
+
+#, c-format
+msgid "%3d expr %s"
+msgstr "%3d udtryk %s"
+
+msgid "E750: First use \":profile start {fname}\""
+msgstr "E750: Brug først \":profile start {fname}\""
+
+#, c-format
+msgid "Save changes to \"%s\"?"
+msgstr "Gem ændringer til \"%s\"?"
+
+#, c-format
+msgid "E947: Job still running in buffer \"%s\""
+msgstr "E947: Job kører stadig i bufferen \"%s\""
+
+#, c-format
+msgid "E162: No write since last change for buffer \"%s\""
+msgstr "E162: Ingen skrivning siden sidste ændring for bufferen \"%s\""
+
+msgid "Warning: Entered other buffer unexpectedly (check autocommands)"
+msgstr "Advarsel: Indtastede anden buffer uventede (tjek autokommandoer)"
+
+msgid "E163: There is only one file to edit"
+msgstr "E163: Der er kun én fil at redigere"
+
+msgid "E164: Cannot go before first file"
+msgstr "E164: Kan ikke gå før første fil"
+
+msgid "E165: Cannot go beyond last file"
+msgstr "E165: Kan ikke gå over sidste fil"
+
+#, c-format
+msgid "E666: compiler not supported: %s"
+msgstr "E666: kompiler understøttes ikke: %s"
+
+#, c-format
+msgid "Searching for \"%s\" in \"%s\""
+msgstr "Søger efter \"%s\" i \"%s\""
+
+#, c-format
+msgid "Searching for \"%s\""
+msgstr "Søger efter \"%s\""
+
+#, c-format
+msgid "not found in '%s': \"%s\""
+msgstr "ikke fundet i '%s': \"%s\""
+
+#, c-format
+msgid "W20: Required python version 2.x not supported, ignoring file: %s"
+msgstr "W20: Krævede python-version 2.x understøttes ikke, ignorerer fil: %s"
+
+#, c-format
+msgid "W21: Required python version 3.x not supported, ignoring file: %s"
+msgstr "W21: Krævede python-version 3.x understøttes ikke, ignorerer fil: %s"
+
+msgid "Source Vim script"
+msgstr "Source Vim-script"
+
+#, c-format
+msgid "Cannot source a directory: \"%s\""
+msgstr "Kan ikke source en mappe: \"%s\""
+
+#, c-format
+msgid "could not source \"%s\""
+msgstr "kunne ikke source \"%s\""
+
+#, c-format
+msgid "line %ld: could not source \"%s\""
+msgstr "linje %ld: kunne ikke source \"%s\""
+
+#, c-format
+msgid "sourcing \"%s\""
+msgstr "sourcing \"%s\""
+
+#, c-format
+msgid "line %ld: sourcing \"%s\""
+msgstr "linje %ld: sourcing \"%s\""
+
+#, c-format
+msgid "finished sourcing %s"
+msgstr "færdig med sourcing af %s"
+
+#, c-format
+msgid "continuing in %s"
+msgstr "fortsætter i %s"
+
+msgid "modeline"
+msgstr "tilstandslinje"
+
+msgid "--cmd argument"
+msgstr "--cmd-argument"
+
+msgid "-c argument"
+msgstr "-c-argument"
+
+msgid "environment variable"
+msgstr "miljøvariabel"
+
+msgid "error handler"
+msgstr "fejlhåndtering"
+
+msgid "W15: Warning: Wrong line separator, ^M may be missing"
+msgstr "W15: Advarsel: Forkert linjeseparator, ^M mangler muligvis"
+
+msgid "E167: :scriptencoding used outside of a sourced file"
+msgstr "E167: :scriptencoding brugt udenfor en sourced fil"
+
+msgid "E168: :finish used outside of a sourced file"
+msgstr "E168: :finish udenfor en sourced fil"
+
+#, c-format
+msgid "Current %slanguage: \"%s\""
+msgstr "Nuværende %ssprog: \"%s\""
+
+#, c-format
+msgid "E197: Cannot set language to \"%s\""
+msgstr "E197: Kan ikke sætte sprog til \"%s\""
+
+msgid "Entering Ex mode. Type \"visual\" to go to Normal mode."
+msgstr "Går i Ex-tilstand. Skriv \"visual\" for at gå til normal tilstand."
+
+msgid "E501: At end-of-file"
+msgstr "E501: Ved filens slutning"
+
+msgid "E169: Command too recursive"
+msgstr "E169: Kommando for rekursiv"
+
+#, c-format
+msgid "E605: Exception not caught: %s"
+msgstr "E605: Undtagelse ikke fanget: %s"
+
+msgid "End of sourced file"
+msgstr "Slut på sourced fil"
+
+msgid "End of function"
+msgstr "Slutning af funktion"
+
+msgid "E464: Ambiguous use of user-defined command"
+msgstr "E464: Flertydig brug af brugerdefineret kommando"
+
+msgid "E492: Not an editor command"
+msgstr "E492: Ikke en editor-kommando"
+
+msgid "E493: Backwards range given"
+msgstr "E493: Baglæns område givet"
+
+msgid "Backwards range given, OK to swap"
+msgstr "Baglæns område givet, OK at bytte om"
+
+msgid "E494: Use w or w>>"
+msgstr "E494: Brug w eller w>>"
+
+msgid "E943: Command table needs to be updated, run 'make cmdidxs'"
+msgstr "E943: Kommandotabel skal opdateres, kør 'make cmdidxs'"
+
+msgid "E319: Sorry, the command is not available in this version"
+msgstr "E319: Beklager, kommandoen er ikke tilgængelig i denne version"
+
+msgid "1 more file to edit. Quit anyway?"
+msgstr "1 fil mere at redigere. Afslut alligevel?"
+
+#, c-format
+msgid "%d more files to edit. Quit anyway?"
+msgstr "%d filer mere at redigere. Afslut alligevel?"
+
+msgid "E173: 1 more file to edit"
+msgstr "E173: 1 fil mere at redigere"
+
+#, c-format
+msgid "E173: %ld more files to edit"
+msgstr "E173: %ld filer mere at redigere"
+
+msgid "E174: Command already exists: add ! to replace it"
+msgstr "E174: Kommandoen findes allerede: tilføj ! for at erstatte den"
+
+msgid ""
+"\n"
+" Name Args Address Complete Definition"
+msgstr ""
+"\n"
+" Navn Argumenter Adresse Fuldført Definition"
+
+msgid "No user-defined commands found"
+msgstr "Fandt ingen brugerdefinerede kommandoer"
+
+msgid "E175: No attribute specified"
+msgstr "E175: Ingen attribut angivet"
+
+msgid "E176: Invalid number of arguments"
+msgstr "E176: Ugyldigt antal argumenter"
+
+msgid "E177: Count cannot be specified twice"
+msgstr "E177: Tælling må ikke angives to gange"
+
+msgid "E178: Invalid default value for count"
+msgstr "E178: Ugyldig standardværdi for tælling"
+
+msgid "E179: argument required for -complete"
+msgstr "E179: argument kræves til -complete"
+
+msgid "E179: argument required for -addr"
+msgstr "E179: argument kræves til -addr"
+
+#, c-format
+msgid "E181: Invalid attribute: %s"
+msgstr "E181: Ugyldig attribut: %s"
+
+msgid "E182: Invalid command name"
+msgstr "E182: Ugyldigt kommandonavn"
+
+msgid "E183: User defined commands must start with an uppercase letter"
+msgstr "E183: Brugerdefinerede kommandoer skal begynde med et stort bogstav"
+
+msgid "E841: Reserved name, cannot be used for user defined command"
+msgstr "E841: Reserveret navn, kan ikke bruges til brugerdefineret kommando"
+
+#, c-format
+msgid "E184: No such user-defined command: %s"
+msgstr "E184: Ingen sådan brugerdefineret kommando: %s"
+
+#, c-format
+msgid "E180: Invalid address type value: %s"
+msgstr "E180: Ugyldig værdi for adressetype: %s"
+
+#, c-format
+msgid "E180: Invalid complete value: %s"
+msgstr "E180: Ugyldig complete-værdi: %s"
+
+msgid "E468: Completion argument only allowed for custom completion"
+msgstr "E468: Fuldførelse-argument kun tilladt for tilpasset fuldførelse"
+
+msgid "E467: Custom completion requires a function argument"
+msgstr "E467: Tilpasset fuldførelse kræver et funktion-argument"
+
+msgid "unknown"
+msgstr "ukendt"
+
+#, c-format
+msgid "E185: Cannot find color scheme '%s'"
+msgstr "E185: Kan ikke finde farveskemaet '%s'"
+
+msgid "Greetings, Vim user!"
+msgstr "Hejsa, Vim-bruger!"
+
+msgid "E784: Cannot close last tab page"
+msgstr "E784: Kan ikke lukke sidste fanebladsside"
+
+msgid "Already only one tab page"
+msgstr "Allerede kun én fanebladsside"
+
+msgid "Edit File in new tab page"
+msgstr "Rediger fil i ny fanebladsside"
+
+msgid "Edit File in new window"
+msgstr "Rediger fil i nyt vindue"
+
+#, c-format
+msgid "Tab page %d"
+msgstr "Fanebladsside %d"
+
+msgid "No swap file"
+msgstr "Ingen swap-fil"
+
+msgid "Append File"
+msgstr "Tilføj fil til slutningen"
+
+msgid "E747: Cannot change directory, buffer is modified (add ! to override)"
+msgstr ""
+"E747: Kan ikke skifte mappe, buffer er ændret (tilføj ! for at tilsidesætte)"
+
+msgid "E186: No previous directory"
+msgstr "E186: Ingen tidligere ordbog"
+
+msgid "E187: Unknown"
+msgstr "E187: Ukendt"
+
+msgid "E465: :winsize requires two number arguments"
+msgstr "E465: :winsize kræver to nummer-argumenter"
+
+#, c-format
+msgid "Window position: X %d, Y %d"
+msgstr "Vinduesplacering: X %d, Y %d"
+
+msgid "E188: Obtaining window position not implemented for this platform"
+msgstr ""
+"E188: Indhentelse af vinduesplacering ikke implementeret på denne platform"
+
+msgid "E466: :winpos requires two number arguments"
+msgstr "E466: :winpos kræver to nummer-argumenter"
+
+msgid "E930: Cannot use :redir inside execute()"
+msgstr "E930: Kan ikke bruge :redir i execute()"
+
+msgid "Save Redirection"
+msgstr "Gem omdirigering"
+
+msgid "Save View"
+msgstr "Gem visning"
+
+msgid "Save Session"
+msgstr "Gem session"
+
+msgid "Save Setup"
+msgstr "Gem opsætning"
+
+#, c-format
+msgid "E739: Cannot create directory: %s"
+msgstr "E739: Kan ikke oprette mappe: %s"
+
+#, c-format
+msgid "E189: \"%s\" exists (add ! to override)"
+msgstr "E189: \"%s\" findes (tilføj ! for at tilsidesætte)"
+
+#, c-format
+msgid "E190: Cannot open \"%s\" for writing"
+msgstr "E190: Kan ikke åbne \"%s\" til skrivning"
+
+msgid "E191: Argument must be a letter or forward/backward quote"
+msgstr ""
+"E191: Argument skal være et bogstav eller retvendt/omvendt citationstegn"
+
+msgid "E192: Recursive use of :normal too deep"
+msgstr "E192: Rekursiv brug af :normal for dyb"
+
+msgid "E809: #< is not available without the +eval feature"
+msgstr "E809: #< er ikke tilgængelig uden +eval-funktionaliteten"
+
+msgid "E194: No alternate file name to substitute for '#'"
+msgstr "E194: Intet alternate-filnavn til erstatning for '#'"
+
+msgid "E495: no autocommand file name to substitute for \"<afile>\""
+msgstr "E495: intet autokommando-filnavn til erstatning for \"<afile>\""
+
+msgid "E496: no autocommand buffer number to substitute for \"<abuf>\""
+msgstr "E496: intet autokommando-buffernummer til erstatning for \"<abuf>\""
+
+msgid "E497: no autocommand match name to substitute for \"<amatch>\""
+msgstr "E497: intet autokommando-matchnavn til erstatning for \"<amatch>\""
+
+msgid "E498: no :source file name to substitute for \"<sfile>\""
+msgstr "E498: intet :source-filnavn til erstatning for \"<sfile>\""
+
+msgid "E842: no line number to use for \"<slnum>\""
+msgstr "E842: intet linjenummer til brug for \"<slnum>\""
+
+#, no-c-format
+msgid "E499: Empty file name for '%' or '#', only works with \":p:h\""
+msgstr "E499: Tomt filnavn for '%' eller '#', virker kun med \":p:h\""
+
+msgid "E500: Evaluates to an empty string"
+msgstr "E500: Evaluerer til en tom streng"
+
+msgid "E195: Cannot open viminfo file for reading"
+msgstr "E195: Kan ikke åbne viminfo-fil til læsning"
+
+msgid "Untitled"
+msgstr "Unavngivet"
+
+msgid "E196: No digraphs in this version"
+msgstr "E196: Ingen digraffer i denne version"
+
+msgid "E608: Cannot :throw exceptions with 'Vim' prefix"
+msgstr "E608: Kan ikke :throw-undtagelser med 'Vim'-præfiks"
+
+#, c-format
+msgid "Exception thrown: %s"
+msgstr "Undtagelse kastet: %s"
+
+#, c-format
+msgid "Exception finished: %s"
+msgstr "Undtagelse færdig: %s"
+
+#, c-format
+msgid "Exception discarded: %s"
+msgstr "Undtagelse forkastet: %s"
+
+#, c-format
+msgid "%s, line %ld"
+msgstr "%s, linje %ld"
+
+#, c-format
+msgid "Exception caught: %s"
+msgstr "Undtagelse fanget: %s"
+
+#, c-format
+msgid "%s made pending"
+msgstr "%s gjort afventende"
+
+#, c-format
+msgid "%s resumed"
+msgstr "%s genoptaget"
+
+#, c-format
+msgid "%s discarded"
+msgstr "%s forkastet"
+
+msgid "Exception"
+msgstr "Undtagelse"
+
+msgid "Error and interrupt"
+msgstr "Fejl og afbryd"
+
+msgid "Error"
+msgstr "Fejl"
+
+msgid "Interrupt"
+msgstr "Afbryd"
+
+msgid "E579: :if nesting too deep"
+msgstr "E579: :if-indlejring for dyb"
+
+msgid "E580: :endif without :if"
+msgstr "E580: :endif uden :if"
+
+msgid "E581: :else without :if"
+msgstr "E581: :else uden :if"
+
+msgid "E582: :elseif without :if"
+msgstr "E582: :elseif uden :if"
+
+msgid "E583: multiple :else"
+msgstr "E583: flere :else"
+
+msgid "E584: :elseif after :else"
+msgstr "E584: :elseif efter :else"
+
+msgid "E585: :while/:for nesting too deep"
+msgstr "E585: :while/:for-indlejring for dyb"
+
+msgid "E586: :continue without :while or :for"
+msgstr "E586: :continue uden :while eller :for"
+
+msgid "E587: :break without :while or :for"
+msgstr "E587: :break uden :while eller :for"
+
+msgid "E732: Using :endfor with :while"
+msgstr "E732: Bruger :endfor med :while"
+
+msgid "E733: Using :endwhile with :for"
+msgstr "E733: Bruger :endwhile med :for"
+
+msgid "E601: :try nesting too deep"
+msgstr "E601: :try-indlejring for dyb"
+
+msgid "E603: :catch without :try"
+msgstr "E603: :catch uden :try"
+
+msgid "E604: :catch after :finally"
+msgstr "E604: :catch efter :finally"
+
+msgid "E606: :finally without :try"
+msgstr "E606: :finally uden :try"
+
+msgid "E607: multiple :finally"
+msgstr "E607: flere :finally"
+
+msgid "E602: :endtry without :try"
+msgstr "E602: :endtry uden :try"
+
+msgid "E193: :endfunction not inside a function"
+msgstr "E193: :endfunction ikke i en funktion"
+
+msgid "E788: Not allowed to edit another buffer now"
+msgstr "E788: Ikke tilladt at redigere anden buffer nu"
+
+msgid "E811: Not allowed to change buffer information now"
+msgstr "E811: Ikke tilladt at ændre bufferinformation nu"
+
+msgid "tagname"
+msgstr "tagnavn"
+
+msgid " kind file\n"
+msgstr " kind-fil\n"
+
+msgid "'history' option is zero"
+msgstr "'history'-tilvalget er nul"
+
+#, c-format
+msgid ""
+"\n"
+"# %s History (newest to oldest):\n"
+msgstr ""
+"\n"
+"# %s historik (nyeste til ældste):\n"
+
+msgid "Command Line"
+msgstr "Kommandolinje"
+
+msgid "Search String"
+msgstr "Søgestreng"
+
+msgid "Expression"
+msgstr "Udtryk"
+
+msgid "Input Line"
+msgstr "Inputlinje"
+
+msgid "Debug Line"
+msgstr "Fejlretningslinje"
+
+msgid "E198: cmd_pchar beyond the command length"
+msgstr "E198: cmd_pchar efter kommandolængden"
+
+msgid "E199: Active window or buffer deleted"
+msgstr "E199: Aktivt vindue eller buffer slettet"
+
+msgid "E812: Autocommands changed buffer or buffer name"
+msgstr "E812: Autokommandoer ændrede buffer eller buffernavn"
+
+msgid "Illegal file name"
+msgstr "Ulovligt filnavn"
+
+msgid "is a directory"
+msgstr "er en mappe"
+
+msgid "is not a file"
+msgstr "er ikke en fil"
+
+msgid "is a device (disabled with 'opendevice' option)"
+msgstr "er en enhed (deaktiveret med 'opendevice'-tilvalget)"
+
+msgid "[New File]"
+msgstr "[Ny fil]"
+
+msgid "[New DIRECTORY]"
+msgstr "[Ny MAPPE]"
+
+msgid "[File too big]"
+msgstr "[Filen er for stor]"
+
+msgid "[Permission Denied]"
+msgstr "[Tilladelse nægtet]"
+
+msgid "E200: *ReadPre autocommands made the file unreadable"
+msgstr "E200: *ReadPre-autokommandoer gjorde filen ulæselig"
+
+msgid "E201: *ReadPre autocommands must not change current buffer"
+msgstr "E201: *ReadPre-autokommandoer må ikke ændre nuværende buffer"
+
+msgid "Vim: Reading from stdin...\n"
+msgstr "Vim: Læser fra stdin...\n"
+
+msgid "Reading from stdin..."
+msgstr "Læser fra stdin..."
+
+msgid "E202: Conversion made file unreadable!"
+msgstr "E202: Konvertering gjorde filen ulæselig!"
+
+msgid "[fifo/socket]"
+msgstr "[fifo/sokkel]"
+
+msgid "[fifo]"
+msgstr "[fifo]"
+
+msgid "[socket]"
+msgstr "[sokkel]"
+
+msgid "[character special]"
+msgstr "[character special]"
+
+msgid "[CR missing]"
+msgstr "[CR mangler]"
+
+msgid "[long lines split]"
+msgstr "[opdeling af lange linjer]"
+
+msgid "[NOT converted]"
+msgstr "[IKKE konverteret]"
+
+msgid "[converted]"
+msgstr "[konverteret]"
+
+#, c-format
+msgid "[CONVERSION ERROR in line %ld]"
+msgstr "[KONVERTERINGSFEJL på linje %ld]"
+
+#, c-format
+msgid "[ILLEGAL BYTE in line %ld]"
+msgstr "[ULOVLIG BYTE på linje %ld]"
+
+msgid "[READ ERRORS]"
+msgstr "[LÆSEFEJL]"
+
+msgid "Can't find temp file for conversion"
+msgstr "Kan ikke finde midlertidig fil til konvertering"
+
+msgid "Conversion with 'charconvert' failed"
+msgstr "Konvertering med 'charconvert' mislykkedes"
+
+msgid "can't read output of 'charconvert'"
+msgstr "kan ikke læse output af 'charconvert'"
+
+msgid "E676: No matching autocommands for acwrite buffer"
+msgstr "E676: Ingen matchende autokommandoer for acwrite-buffer"
+
+msgid "E203: Autocommands deleted or unloaded buffer to be written"
+msgstr "E203: Autokommandoer slettet eller udlæste buffer som skal skrives"
+
+msgid "E204: Autocommand changed number of lines in unexpected way"
+msgstr "E204: Autokommando ændrede antal linjer på en uventede måde"
+
+msgid "NetBeans disallows writes of unmodified buffers"
+msgstr "NetBeans tillader ikke skrivninger af uændrede buffere"
+
+msgid "Partial writes disallowed for NetBeans buffers"
+msgstr "Ufuldstændige skrivninger er ikke tilladt for NetBeans-buffere"
+
+msgid "is not a file or writable device"
+msgstr "er ikke en fil eller enhed som der kan skrives til"
+
+msgid "writing to device disabled with 'opendevice' option"
+msgstr "skrivning til enhed er deaktiveret med 'opendevice'-tilvalget"
+
+msgid "is read-only (add ! to override)"
+msgstr "er skrivebeskyttet (tilføj ! for at tilsidesætte)"
+
+msgid "E506: Can't write to backup file (add ! to override)"
+msgstr ""
+"E506: Kan ikke skrive til sikkerhedskopieret fil (tilføj ! for at "
+"tilsidesætte)"
+
+msgid "E507: Close error for backup file (add ! to override)"
+msgstr ""
+"E507: Fejl ved lukning af sikkerhedskopieret fil (tilføj ! for at "
+"tilsidesætte)"
+
+msgid "E508: Can't read file for backup (add ! to override)"
+msgstr ""
+"E508: Kan ikke læse fil til sikkerhedskopiering (tilføj ! for at "
+"tilsidesætte)"
+
+msgid "E509: Cannot create backup file (add ! to override)"
+msgstr ""
+"E509: Kan ikke oprette (create) sikkerhedskopieret fil (tilføj ! for at "
+"tilsidesætte)"
+
+msgid "E510: Can't make backup file (add ! to override)"
+msgstr ""
+"E510: Kan ikke oprette (make) sikkerhedskopieret fil (tilføj ! for at "
+"tilsidesætte)"
+
+msgid "E214: Can't find temp file for writing"
+msgstr "E214: Kan ikke finde midlertidig fil til skrivning"
+
+msgid "E213: Cannot convert (add ! to write without conversion)"
+msgstr "E213: Kan ikke konvertere (tilføj ! for at skrive uden konvertering)"
+
+msgid "E166: Can't open linked file for writing"
+msgstr "E166: Kan ikke åbne linket fil til skrivning"
+
+msgid "E212: Can't open file for writing"
+msgstr "E212: Kan ikke åbne filen til skrivning"
+
+msgid "E949: File changed while writing"
+msgstr "E949: Filen blev ændret ved skrivning"
+
+msgid "E512: Close failed"
+msgstr "E512: Lukning mislykkedes"
+
+msgid "E513: write error, conversion failed (make 'fenc' empty to override)"
+msgstr ""
+"E513: fejl ved skrivning, konvertering mislykkedes (gør 'fenc' tom for at "
+"tilsidesætte)"
+
+#, c-format
+msgid ""
+"E513: write error, conversion failed in line %ld (make 'fenc' empty to "
+"override)"
+msgstr ""
+"E513: fejl ved skrivning, konvertering mislykkedes på linje %ld (gør 'fenc' "
+"tom for at tilsidesætte)"
+
+msgid "E514: write error (file system full?)"
+msgstr "E514: skrivefejl (er filsystemet fuldt?)"
+
+msgid " CONVERSION ERROR"
+msgstr " KONVERTERINGSFEJL"
+
+#, c-format
+msgid " in line %ld;"
+msgstr " på linje %ld;"
+
+msgid "[Device]"
+msgstr "[Enhed]"
+
+msgid "[New]"
+msgstr "[Ny]"
+
+msgid " [a]"
+msgstr " [a]"
+
+msgid " appended"
+msgstr " tilføjet i slutningen"
+
+msgid " [w]"
+msgstr " [s]"
+
+msgid " written"
+msgstr " skrevet"
+
+msgid "E205: Patchmode: can't save original file"
+msgstr "E205: Patchmode: kan ikke gemme original fil"
+
+msgid "E206: patchmode: can't touch empty original file"
+msgstr "E206: patchmode: kan ikke touch tom original fil"
+
+msgid "E207: Can't delete backup file"
+msgstr "E207: Kan ikke slette sikkerhedskopieret fil"
+
+msgid ""
+"\n"
+"WARNING: Original file may be lost or damaged\n"
+msgstr ""
+"\n"
+"ADVARSEL: Den originale fil kan man mistet eller beskadiget\n"
+
+msgid "don't quit the editor until the file is successfully written!"
+msgstr "afslut ikke editoren inden filen er blevet skrevet!"
+
+msgid "[dos]"
+msgstr "[dos]"
+
+msgid "[dos format]"
+msgstr "[dos-format]"
+
+msgid "[mac]"
+msgstr "[mac]"
+
+msgid "[mac format]"
+msgstr "[mac-format]"
+
+msgid "[unix]"
+msgstr "[unix]"
+
+msgid "[unix format]"
+msgstr "[unix-format]"
+
+msgid "1 line, "
+msgstr "1 linje, "
+
+#, c-format
+msgid "%ld lines, "
+msgstr "%ld linjer, "
+
+msgid "1 character"
+msgstr "1 tegn"
+
+#, c-format
+msgid "%lld characters"
+msgstr "%lld tegn"
+
+msgid "[noeol]"
+msgstr "[ingen eol]"
+
+msgid "[Incomplete last line]"
+msgstr "[Ufuldstændig sidste linje]"
+
+msgid "WARNING: The file has been changed since reading it!!!"
+msgstr "ADVARSEL: Filen er blevet ændret siden den blev læst!!!"
+
+msgid "Do you really want to write to it"
+msgstr "Vil du virkelig skrive den"
+
+#, c-format
+msgid "E208: Error writing to \"%s\""
+msgstr "E208: Fejl ved skrivning til \"%s\""
+
+#, c-format
+msgid "E209: Error closing \"%s\""
+msgstr "E209: Fejl ved lukning af \"%s\""
+
+#, c-format
+msgid "E210: Error reading \"%s\""
+msgstr "E210: Fejl ved læsning af \"%s\""
+
+msgid "E246: FileChangedShell autocommand deleted buffer"
+msgstr "E246: FileChangedShell-autokommando slettede buffer"
+
+#, c-format
+msgid "E211: File \"%s\" no longer available"
+msgstr "E211: Filen \"%s\" er ikke længere tilgængelig"
+
+#, c-format
+msgid ""
+"W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as "
+"well"
+msgstr ""
+"W12: Advarsel: Filen \"%s\" er blevet ændret og bufferen blev også ændret i "
+"Vim"
+
+msgid "See \":help W12\" for more info."
+msgstr "Se \":help W12\" for mere info."
+
+#, c-format
+msgid "W11: Warning: File \"%s\" has changed since editing started"
+msgstr ""
+"W11: Advarsel: Filen \"%s\" er blevet ændret siden redigeringen startede"
+
+msgid "See \":help W11\" for more info."
+msgstr "Se \":help W11\" for mere info."
+
+#, c-format
+msgid "W16: Warning: Mode of file \"%s\" has changed since editing started"
+msgstr ""
+"W16: Advarsel: Tilstanden af filen \"%s\" er blevet ændret siden "
+"redigeringen startede"
+
+msgid "See \":help W16\" for more info."
+msgstr "Se \":help W16\" for mere info."
+
+#, c-format
+msgid "W13: Warning: File \"%s\" has been created after editing started"
+msgstr ""
+"W13: Advarsel: Filen \"%s\" er blevet oprettet efter redigeringen startede"
+
+msgid "Warning"
+msgstr "Advarsel"
+
+msgid ""
+"&OK\n"
+"&Load File"
+msgstr ""
+"&OK\n"
+"&Indlæs fil"
+
+#, c-format
+msgid "E462: Could not prepare for reloading \"%s\""
+msgstr "E462: Kunne ikke forbedre til genindlæsning af \"%s\""
+
+#, c-format
+msgid "E321: Could not reload \"%s\""
+msgstr "E321: Kunne ikke genindlæse \"%s\""
+
+msgid "--Deleted--"
+msgstr "--Slettet--"
+
+#, c-format
+msgid "auto-removing autocommand: %s <buffer=%d>"
+msgstr "auto-removing-autokommando: %s <buffer=%d>"
+
+#, c-format
+msgid "E367: No such group: \"%s\""
+msgstr "E367: Ingen sådan gruppe: \"%s\""
+
+msgid "E936: Cannot delete the current group"
+msgstr "E936: Kan ikke slette den nuværende gruppe"
+
+msgid "W19: Deleting augroup that is still in use"
+msgstr "W19: Sletter augroup som stadig er i brug"
+
+#, c-format
+msgid "E215: Illegal character after *: %s"
+msgstr "E215: Ulovligt tegn efter *: %s"
+
+#, c-format
+msgid "E216: No such event: %s"
+msgstr "E216: Ingen sådan hændelse: %s"
+
+#, c-format
+msgid "E216: No such group or event: %s"
+msgstr "E216: Ingen sådan gruppe eller hændelse: %s"
+
+msgid ""
+"\n"
+"--- Autocommands ---"
+msgstr ""
+"\n"
+"--- Autokommandoer ---"
+
+#, c-format
+msgid "E680: <buffer=%d>: invalid buffer number "
+msgstr "E680: <buffer=%d>: ugyldigt buffernummer "
+
+msgid "E217: Can't execute autocommands for ALL events"
+msgstr "E217: Kan ikke udføre autokommandoer for ALLE hændelser"
+
+msgid "No matching autocommands"
+msgstr "Ingen matchende autokommandoer"
+
+msgid "E218: autocommand nesting too deep"
+msgstr "E218: autokommando indlejret for dyb"
+
+#, c-format
+msgid "%s Autocommands for \"%s\""
+msgstr "%s Autokommandoer for \"%s\""
+
+#, c-format
+msgid "Executing %s"
+msgstr "Udfører %s"
+
+#, c-format
+msgid "autocommand %s"
+msgstr "autokommando %s"
+
+msgid "E219: Missing {."
+msgstr "E219: Manglende {."
+
+msgid "E220: Missing }."
+msgstr "E220: Manglende }."
+
+msgid "E490: No fold found"
+msgstr "E490: Ingen sammenfoldning fundet"
+
+msgid "E350: Cannot create fold with current 'foldmethod'"
+msgstr "E350: Kan ikke oprette sammenfoldning med nuværende 'foldmethod'"
+
+msgid "E351: Cannot delete fold with current 'foldmethod'"
+msgstr "E351: Kan ikke slette sammenfoldning med nuværende 'foldmethod'"
+
+#, c-format
+msgid "+--%3ld line folded "
+msgid_plural "+--%3ld lines folded "
+msgstr[0] "+--%3ld linje sammenfoldet "
+msgstr[1] "+--%3ld linjer sammenfoldet "
+
+msgid "E222: Add to read buffer"
+msgstr "E222: Tilføj til læsebuffer"
+
+msgid "E223: recursive mapping"
+msgstr "E223: rekursiv mapping"
+
+#, c-format
+msgid "E224: global abbreviation already exists for %s"
+msgstr "E224: global forkortelse findes allerede for %s"
+
+#, c-format
+msgid "E225: global mapping already exists for %s"
+msgstr "E225: global mapping findes allerede for %s"
+
+#, c-format
+msgid "E226: abbreviation already exists for %s"
+msgstr "E226: forkortelse findes allerede for %s"
+
+#, c-format
+msgid "E227: mapping already exists for %s"
+msgstr "E227: mapping findes allerede for %s"
+
+msgid "No abbreviation found"
+msgstr "Ingen forkortelse fundet"
+
+msgid "No mapping found"
+msgstr "Ingen mapping fundet"
+
+msgid "E228: makemap: Illegal mode"
+msgstr "E228: makemap: Ulovlig tilstand"
+
+msgid "E851: Failed to create a new process for the GUI"
+msgstr "E851: Kunne ikke oprette en ny proces for GUI'en"
+
+msgid "E852: The child process failed to start the GUI"
+msgstr "E852: Barneprocessen kunne ikke starte GUI'en"
+
+msgid "E229: Cannot start the GUI"
+msgstr "E229: Kan ikke starte GUI'en"
+
+#, c-format
+msgid "E230: Cannot read from \"%s\""
+msgstr "E230: Kan ikke læse fra \"%s\""
+
+msgid "E665: Cannot start GUI, no valid font found"
+msgstr "E665: Kan ikke starte GUI, ingen gyldig skrifttype fundet"
+
+msgid "E231: 'guifontwide' invalid"
+msgstr "E231: 'guifontwide' ugyldig"
+
+msgid "E599: Value of 'imactivatekey' is invalid"
+msgstr "E599: Værdien af 'imactivatekey' er ugyldig"
+
+#, c-format
+msgid "E254: Cannot allocate color %s"
+msgstr "E254: Kan ikke allokere farven %s"
+
+msgid "No match at cursor, finding next"
+msgstr "Intet match ved markør, finder næste"
+
+msgid "<cannot open> "
+msgstr "<kan ikke åbne> "
+
+#, c-format
+msgid "E616: vim_SelFile: can't get font %s"
+msgstr "E616: vim_SelFile: kan ikke hente skrifttypen %s"
+
+msgid "E614: vim_SelFile: can't return to current directory"
+msgstr "E614: vim_SelFile: kan ikke vende tilbage til nuværende mappe"
+
+msgid "Pathname:"
+msgstr "Stinavn:"
+
+msgid "E615: vim_SelFile: can't get current directory"
+msgstr "E615: vim_SelFile: kan ikke hente nuværende mappe"
+
+msgid "OK"
+msgstr "OK"
+
+msgid "Cancel"
+msgstr "Annuller"
+
+msgid "Scrollbar Widget: Could not get geometry of thumb pixmap."
+msgstr ""
+"Rullebjælke-widget: Kunne ikke hente geometri eller pixelkort til miniature."
+
+msgid "Vim dialog"
+msgstr "Vim-dialog"
+
+msgid "E232: Cannot create BalloonEval with both message and callback"
+msgstr "E232: Kan ikke oprette BalloonEval med både meddelelse og callback"
+
+msgid "_Cancel"
+msgstr "_Annuller"
+
+msgid "_Save"
+msgstr "_Gem"
+
+msgid "_Open"
+msgstr "_Ã…bn"
+
+msgid "_OK"
+msgstr "_OK"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"&Cancel"
+msgstr ""
+"&Ja\n"
+"&Nej\n"
+"&Annuller"
+
+msgid "Yes"
+msgstr "Ja"
+
+msgid "No"
+msgstr "Nej"
+
+msgid "Input _Methods"
+msgstr "Input_metoder"
+
+msgid "VIM - Search and Replace..."
+msgstr "VIM - Søg og erstat..."
+
+msgid "VIM - Search..."
+msgstr "VIM - Søg..."
+
+msgid "Find what:"
+msgstr "Find hvad:"
+
+msgid "Replace with:"
+msgstr "Erstat med:"
+
+msgid "Match whole word only"
+msgstr "Match kun hele ord"
+
+msgid "Match case"
+msgstr "Der skelnes ikke mellem store og små bogstaver"
+
+msgid "Direction"
+msgstr "Retning"
+
+msgid "Up"
+msgstr "Op"
+
+msgid "Down"
+msgstr "Ned"
+
+msgid "Find Next"
+msgstr "Find næste"
+
+msgid "Replace"
+msgstr "Erstat"
+
+msgid "Replace All"
+msgstr "Erstat alle"
+
+msgid "_Close"
+msgstr "_Luk"
+
+msgid "Vim: Received \"die\" request from session manager\n"
+msgstr "Vim: Modtog \"die\"-anmodning fra sessionshåndtering\n"
+
+msgid "Close tab"
+msgstr "Luk faneblad"
+
+msgid "New tab"
+msgstr "Nyt faneblad"
+
+msgid "Open Tab..."
+msgstr "Ã…bn faneblad..."
+
+msgid "Vim: Main window unexpectedly destroyed\n"
+msgstr "Vim: Hovedvindue uventet ødelagt\n"
+
+msgid "&Filter"
+msgstr "&Filter"
+
+msgid "&Cancel"
+msgstr "&Annuller"
+
+msgid "Directories"
+msgstr "Mapper"
+
+msgid "Filter"
+msgstr "Filter"
+
+msgid "&Help"
+msgstr "&Hjælp"
+
+msgid "Files"
+msgstr "Filer"
+
+msgid "&OK"
+msgstr "&OK"
+
+msgid "Selection"
+msgstr "Markering"
+
+msgid "Find &Next"
+msgstr "Find &næste"
+
+msgid "&Replace"
+msgstr "&Erstat"
+
+msgid "Replace &All"
+msgstr "Erstat &alle"
+
+msgid "&Undo"
+msgstr "&Fortryd"
+
+msgid "Open tab..."
+msgstr "Ã…bn faneblad..."
+
+msgid "Find string (use '\\\\' to find a '\\')"
+msgstr "Find streng (brug '\\\\' til at finde et '\\')"
+
+msgid "Find & Replace (use '\\\\' to find a '\\')"
+msgstr "Find og erstat (brug '\\\\' til at finde et '\\')"
+
+msgid "Not Used"
+msgstr "Ikke brugt"
+
+msgid "Directory\t*.nothing\n"
+msgstr "Mappe\t\t*.nothing\n"
+
+#, c-format
+msgid "E671: Cannot find window title \"%s\""
+msgstr "E671: Kan ikke finde vinduestitlen \"%s\""
+
+#, c-format
+msgid "E243: Argument not supported: \"-%s\"; Use the OLE version."
+msgstr "E243: Argumentet understøttes ikke: \"-%s\"; Brug OLE-versionen."
+
+msgid "E672: Unable to open window inside MDI application"
+msgstr "E672: Kan ikke åbne vindue i MDI-program"
+
+msgid "Vim E458: Cannot allocate colormap entry, some colors may be incorrect"
+msgstr ""
+"Vim E458: Kan ikke allokere colormap-post, nogle farver kan være forkerte"
+
+#, c-format
+msgid "E250: Fonts for the following charsets are missing in fontset %s:"
+msgstr "E250: Skrifttyper for følgende tegnsæt mangler i skrifttypesættet %s:"
+
+#, c-format
+msgid "E252: Fontset name: %s"
+msgstr "E252: Skrifttypesætnavn: %s"
+
+#, c-format
+msgid "Font '%s' is not fixed-width"
+msgstr "Skrifttypen '%s' er ikke med fast bredde"
+
+#, c-format
+msgid "E253: Fontset name: %s"
+msgstr "E253: Skrifttypesætnavn: %s"
+
+#, c-format
+msgid "Font0: %s"
+msgstr "Skrifttype0: %s"
+
+#, c-format
+msgid "Font1: %s"
+msgstr "Skrifttype1: %s"
+
+#, c-format
+msgid "Font%ld width is not twice that of font0"
+msgstr "Bredden på skrifttype%ld er ikke det dobbelte af skrifttype0"
+
+#, c-format
+msgid "Font0 width: %ld"
+msgstr "Bredden på skrifttype0: %ld"
+
+#, c-format
+msgid "Font1 width: %ld"
+msgstr "Bredden på skrifttype1: %ld"
+
+msgid "Invalid font specification"
+msgstr "Ugyldig skrifttypespecifikation"
+
+msgid "&Dismiss"
+msgstr "&Luk"
+
+msgid "no specific match"
+msgstr "intet specifikt match"
+
+msgid "Vim - Font Selector"
+msgstr "Vim - Skrifttypevælger"
+
+msgid "Name:"
+msgstr "Navn:"
+
+msgid "Show size in Points"
+msgstr "Vis størrelse i punkter"
+
+msgid "Encoding:"
+msgstr "Kodning:"
+
+msgid "Font:"
+msgstr "Skrifttype:"
+
+msgid "Style:"
+msgstr "Stil:"
+
+msgid "Size:"
+msgstr "Størrelse:"
+
+msgid "E256: Hangul automata ERROR"
+msgstr "E256: FEJL ved Hangul automata"
+
+msgid "E550: Missing colon"
+msgstr "E550: Manglende kolon"
+
+msgid "E551: Illegal component"
+msgstr "E551: Ulovlig komponent"
+
+msgid "E552: digit expected"
+msgstr "E552: ciffer ventet"
+
+#, c-format
+msgid "Page %d"
+msgstr "Side %d"
+
+msgid "No text to be printed"
+msgstr "Ingen tekst at udskrive"
+
+#, c-format
+msgid "Printing page %d (%d%%)"
+msgstr "Udskriver side %d (%d%%)"
+
+#, c-format
+msgid " Copy %d of %d"
+msgstr " Kopi %d af %d"
+
+#, c-format
+msgid "Printed: %s"
+msgstr "Udskrev: %s"
+
+msgid "Printing aborted"
+msgstr "Udskrivning afbrudt"
+
+msgid "E455: Error writing to PostScript output file"
+msgstr "E455: Fejl ved skrivning til PostScript-output-fil"
+
+#, c-format
+msgid "E624: Can't open file \"%s\""
+msgstr "E624: Kan ikke åbne filen \"%s\""
+
+#, c-format
+msgid "E457: Can't read PostScript resource file \"%s\""
+msgstr "E457: Kan ikke læse PostScript-ressourcefilen \"%s\""
+
+#, c-format
+msgid "E618: file \"%s\" is not a PostScript resource file"
+msgstr "E618: filen \"%s\" er ikke en PostScript-ressourcefil"
+
+#, c-format
+msgid "E619: file \"%s\" is not a supported PostScript resource file"
+msgstr "E619: filen \"%s\" er ikke en understøttet PostScript-ressourcefil"
+
+#, c-format
+msgid "E621: \"%s\" resource file has wrong version"
+msgstr "E621: \"%s\"-ressourcefilen har forkert version"
+
+msgid "E673: Incompatible multi-byte encoding and character set."
+msgstr "E673: Inkompatibel multibyte-kodning og -tegnsæt."
+
+msgid "E674: printmbcharset cannot be empty with multi-byte encoding."
+msgstr "E674: printmbcharset må ikke være tom med multibyte-kodning."
+
+msgid "E675: No default font specified for multi-byte printing."
+msgstr "E675: Ingen standardskrifttype angivet for multibyte-udskrivning."
+
+msgid "E324: Can't open PostScript output file"
+msgstr "E324: Kan ikke åbne PostScript-output-fil"
+
+#, c-format
+msgid "E456: Can't open file \"%s\""
+msgstr "E456: Kan ikke åbne filen \"%s\""
+
+msgid "E456: Can't find PostScript resource file \"prolog.ps\""
+msgstr "E456: Kan ikke finde PostScript-ressourcefilen \"prolog.ps\""
+
+msgid "E456: Can't find PostScript resource file \"cidfont.ps\""
+msgstr "E456: Kan ikke finde PostScript-ressourcefilen \"cidfont.ps\""
+
+#, c-format
+msgid "E456: Can't find PostScript resource file \"%s.ps\""
+msgstr "E456: Kan ikke finde PostScript-ressourcefilen \"%s.ps\""
+
+#, c-format
+msgid "E620: Unable to convert to print encoding \"%s\""
+msgstr "E620: Kan ikke konvertere til udskrivningskodningen \"%s\""
+
+msgid "Sending to printer..."
+msgstr "Sender til printer..."
+
+msgid "E365: Failed to print PostScript file"
+msgstr "E365: Kunne ikke udskrive PostScript-fil"
+
+msgid "Print job sent."
+msgstr "Udskrivningsjob sendt."
+
+msgid "Add a new database"
+msgstr "Tilføj en ny database"
+
+msgid "Query for a pattern"
+msgstr "Forespørgsel til et mønster"
+
+msgid "Show this message"
+msgstr "Vis denne meddelelse"
+
+msgid "Kill a connection"
+msgstr "Dræb en forbindelse"
+
+msgid "Reinit all connections"
+msgstr "Geninitialisere alle forbindelser"
+
+msgid "Show connections"
+msgstr "Vis forbindelser"
+
+#, c-format
+msgid "E560: Usage: cs[cope] %s"
+msgstr "E560: Anvendelse: cs[cope] %s"
+
+msgid "This cscope command does not support splitting the window.\n"
+msgstr "Denne cscope-kommando understøtter ikke opdeling af vinduet.\n"
+
+msgid "E562: Usage: cstag <ident>"
+msgstr "E562: Anvendelse: cstag <ident>"
+
+msgid "E257: cstag: tag not found"
+msgstr "E257: cstag: tag ikke fundet"
+
+#, c-format
+msgid "E563: stat(%s) error: %d"
+msgstr "E563: fejl ved stat(%s): %d"
+
+msgid "E563: stat error"
+msgstr "E563: fejl ved stat"
+
+#, c-format
+msgid "E564: %s is not a directory or a valid cscope database"
+msgstr "E564: %s er ikke en mappe eller en gyldig cscope-database"
+
+#, c-format
+msgid "Added cscope database %s"
+msgstr "Tilføjede cscope-databasen %s"
+
+#, c-format
+msgid "E262: error reading cscope connection %ld"
+msgstr "E262: fejl ved læsning af cscope-forbindelse %ld"
+
+msgid "E561: unknown cscope search type"
+msgstr "E561: ukendt cscope-søgetype"
+
+msgid "E566: Could not create cscope pipes"
+msgstr "E566: Kunne ikke oprette cscope-pipes"
+
+msgid "E622: Could not fork for cscope"
+msgstr "E622: Kunne ikke fork for cscope"
+
+msgid "cs_create_connection setpgid failed"
+msgstr "cs_create_connection setpgid mislykkedes"
+
+msgid "cs_create_connection exec failed"
+msgstr "cs_create_connection exec mislykkedes"
+
+msgid "cs_create_connection: fdopen for to_fp failed"
+msgstr "cs_create_connection: fdopen for to_fp mislykkedes"
+
+msgid "cs_create_connection: fdopen for fr_fp failed"
+msgstr "cs_create_connection: fdopen for fr_fp mislykkedes"
+
+msgid "E623: Could not spawn cscope process"
+msgstr "E623: Kunne ikke spawn cscope-proces"
+
+msgid "E567: no cscope connections"
+msgstr "E567: ingen cscope-forbindelser"
+
+#, c-format
+msgid "E469: invalid cscopequickfix flag %c for %c"
+msgstr "E469: ugyldigt cscopequickfix-flag %c for %c"
+
+#, c-format
+msgid "E259: no matches found for cscope query %s of %s"
+msgstr "E259: ingen match fundet for cscope-forespørgsel %s af %s"
+
+msgid "cscope commands:\n"
+msgstr "cscope-kommandoer:\n"
+
+#, c-format
+msgid "%-5s: %s%*s (Usage: %s)"
+msgstr "%-5s: %s%*s (Anvendelse: %s)"
+
+msgid ""
+"\n"
+" a: Find assignments to this symbol\n"
+" c: Find functions calling this function\n"
+" d: Find functions called by this function\n"
+" e: Find this egrep pattern\n"
+" f: Find this file\n"
+" g: Find this definition\n"
+" i: Find files #including this file\n"
+" s: Find this C symbol\n"
+" t: Find this text string\n"
+msgstr ""
+"\n"
+" a: Find tildelinger til symbolet\n"
+" c: Find funktioner som kalder funktionen\n"
+" d: Find funktioner som kaldes af funktionen\n"
+" e: Find dette egrep-mønster\n"
+" f: Find filen\n"
+" g: Find definitionen\n"
+" i: Find filer som #inkludere filen\n"
+" s: Find C-symbolet\n"
+" t: Find tekststrengen\n"
+
+#, c-format
+msgid "E625: cannot open cscope database: %s"
+msgstr "E625: kan ikke åbne cscope-database: %s"
+
+msgid "E626: cannot get cscope database information"
+msgstr "E626: kan ikke hente information for cscope-database"
+
+msgid "E568: duplicate cscope database not added"
+msgstr "E568: duplikeret cscope-database ikke tilføjet"
+
+#, c-format
+msgid "E261: cscope connection %s not found"
+msgstr "E261: cscope-forbindelsen %s ikke fundet"
+
+#, c-format
+msgid "cscope connection %s closed"
+msgstr "cscope-forbindelsen %s lukket"
+
+msgid "E570: fatal error in cs_manage_matches"
+msgstr "E570: fatal fejl i cs_manage_matches"
+
+#, c-format
+msgid "Cscope tag: %s"
+msgstr "Cscope-tag: %s"
+
+msgid ""
+"\n"
+" # line"
+msgstr ""
+"\n"
+" # linje"
+
+msgid "filename / context / line\n"
+msgstr "filnavn/kontekst/linje\n"
+
+#, c-format
+msgid "E609: Cscope error: %s"
+msgstr "E609: Fejl ved cscope: %s"
+
+msgid "All cscope databases reset"
+msgstr "Alle cscope-databaser nulstillet"
+
+msgid "no cscope connections\n"
+msgstr "ingen cscope-forbindelser\n"
+
+msgid " # pid database name prepend path\n"
+msgstr " # pid databasenavn prepend-sti\n"
+
+msgid "Lua library cannot be loaded."
+msgstr "Lua-bibliotek kan ikke indlæses."
+
+msgid "cannot save undo information"
+msgstr "kan ikke gemme fortrydinformation"
+
+msgid ""
+"E815: Sorry, this command is disabled, the MzScheme libraries could not be "
+"loaded."
+msgstr ""
+"E815: Beklager, kommandoen er deaktiveret, MzScheme-bibliotekerne kunne ikke "
+"indlæses."
+
+msgid ""
+"E895: Sorry, this command is disabled, the MzScheme's racket/base module "
+"could not be loaded."
+msgstr ""
+"E895: Beklager, kommandoen er deaktiveret, MzScheme's racket-/base-modul "
+"kunne ikke indlæses."
+
+msgid "invalid expression"
+msgstr "ugyldigt udtryk"
+
+msgid "expressions disabled at compile time"
+msgstr "udtryk deaktiveret ved kompileringstid"
+
+msgid "hidden option"
+msgstr "skjult tilvalg"
+
+msgid "unknown option"
+msgstr "ukendt tilvalg"
+
+msgid "window index is out of range"
+msgstr "vinduesindeks udenfor område"
+
+msgid "couldn't open buffer"
+msgstr "kan ikke åbne buffer"
+
+msgid "cannot delete line"
+msgstr "kan ikke slette linje"
+
+msgid "cannot replace line"
+msgstr "kan ikke erstatte linje"
+
+msgid "cannot insert line"
+msgstr "kan ikke indsætte linje"
+
+msgid "string cannot contain newlines"
+msgstr "streng må ikke indeholde linjeskift"
+
+msgid "error converting Scheme values to Vim"
+msgstr "fejl ved konvertering af Scheme-værdier til Vim"
+
+msgid "Vim error: ~a"
+msgstr "Fejl ved Vim: ~a"
+
+msgid "Vim error"
+msgstr "Fejl ved Vim"
+
+msgid "buffer is invalid"
+msgstr "buffer er ugyldig"
+
+msgid "window is invalid"
+msgstr "vindue er ugyldigt"
+
+msgid "linenr out of range"
+msgstr "linjenummer udenfor område"
+
+msgid "not allowed in the Vim sandbox"
+msgstr "ikke tilladt i Vim-sandboksen"
+
+msgid "E836: This Vim cannot execute :python after using :py3"
+msgstr "E836: Denne Vim kan ikke udføre :python efter brug af :py3"
+
+msgid ""
+"E263: Sorry, this command is disabled, the Python library could not be "
+"loaded."
+msgstr ""
+"E263: Beklager, kommandoen er deaktiveret, Python-biblioteket kunne ikke "
+"indlæses."
+
+msgid ""
+"E887: Sorry, this command is disabled, the Python's site module could not be "
+"loaded."
+msgstr ""
+"E887: Beklager, kommandoen er deaktiveret, Python's site-modul kunne ikke "
+"indlæses."
+
+msgid "E659: Cannot invoke Python recursively"
+msgstr "E659: Kan ikke starte Python rekursivt"
+
+msgid "E837: This Vim cannot execute :py3 after using :python"
+msgstr "E837: Denne Vim kan ikke udføre :py3 efter brug af :python"
+
+msgid "E265: $_ must be an instance of String"
+msgstr "E265: $_ skal være en instans af streng"
+
+msgid ""
+"E266: Sorry, this command is disabled, the Ruby library could not be loaded."
+msgstr ""
+"E266: Beklager, kommandoen er deaktiveret, Ruby-biblioteket kunne ikke "
+"indlæses."
+
+msgid "E267: unexpected return"
+msgstr "E267: uventet return"
+
+msgid "E268: unexpected next"
+msgstr "E268: uventet next"
+
+msgid "E269: unexpected break"
+msgstr "E269: uventet break"
+
+msgid "E270: unexpected redo"
+msgstr "E270: uventet redo"
+
+msgid "E271: retry outside of rescue clause"
+msgstr "E271: prøv igen udenfor rescue clause"
+
+msgid "E272: unhandled exception"
+msgstr "E272: uhåndteret undtagelse"
+
+#, c-format
+msgid "E273: unknown longjmp status %d"
+msgstr "E273: ukendt longjmp-status %d"
+
+msgid "invalid buffer number"
+msgstr "ugyldigt buffernummer"
+
+msgid "not implemented yet"
+msgstr "endnu ikke implementeret"
+
+msgid "cannot set line(s)"
+msgstr "kan ikke sætte linje(r)"
+
+msgid "invalid mark name"
+msgstr "ugyldigt mærkenavn"
+
+msgid "mark not set"
+msgstr "mærke ikke sat"
+
+#, c-format
+msgid "row %d column %d"
+msgstr "række %d kolonne %d"
+
+msgid "cannot insert/append line"
+msgstr "kan ikke indsætte/tilføje linje"
+
+msgid "line number out of range"
+msgstr "linjenummer udenfor område"
+
+msgid "unknown flag: "
+msgstr "ukendt flag: "
+
+msgid "unknown vimOption"
+msgstr "ukendt vimOption"
+
+msgid "keyboard interrupt"
+msgstr "tastaturafbryd"
+
+msgid "vim error"
+msgstr "fejl ved vim"
+
+msgid "cannot create buffer/window command: object is being deleted"
+msgstr "kan ikke oprette buffer-/vindue-kommando: objekt slettes"
+
+msgid ""
+"cannot register callback command: buffer/window is already being deleted"
+msgstr ""
+"kan ikke registrere callback-kommando: buffer/vindue er allerede ved at "
+"blive slettet"
+
+msgid ""
+"E280: TCL FATAL ERROR: reflist corrupt!? Please report this to vim-dev@vim."
+"org"
+msgstr ""
+"E280: FATAL FEJL VED TCL: reflist korrupt!? Rapportér det venligst til vim-"
+"dev@vim.org"
+
+msgid "cannot register callback command: buffer/window reference not found"
+msgstr ""
+"kan ikke registrere callback-kommando: buffer-/vindue-reference ikke fundet"
+
+msgid ""
+"E571: Sorry, this command is disabled: the Tcl library could not be loaded."
+msgstr ""
+"E571: Beklager, kommandoen er deaktiveret: Tcl-biblioteket kunne ikke "
+"indlæses."
+
+#, c-format
+msgid "E572: exit code %d"
+msgstr "E572: afslutningskode %d"
+
+msgid "cannot get line"
+msgstr "kan ikke hente linje"
+
+msgid "Unable to register a command server name"
+msgstr "Kan ikke registrere et kommandoservernavn"
+
+msgid "E248: Failed to send command to the destination program"
+msgstr "E248: Kunne ikke sende kommando til destinationsprogrammet"
+
+#, c-format
+msgid "E573: Invalid server id used: %s"
+msgstr "E573: Ugyldigt server-id brugt: %s"
+
+msgid "E251: VIM instance registry property is badly formed. Deleted!"
+msgstr ""
+"E251: Registreringsegenskab for VIM-instans er dårligt udformet. Slettet!"
+
+#, c-format
+msgid "E938: Duplicate key in JSON: \"%s\""
+msgstr "E938: Duplikeret nøgle i JSON: \"%s\""
+
+#, c-format
+msgid "E696: Missing comma in List: %s"
+msgstr "E696: Manglende komma i liste: %s"
+
+#, c-format
+msgid "E697: Missing end of List ']': %s"
+msgstr "E697: Manglende slutning på List ']': %s"
+
+msgid "Unknown option argument"
+msgstr "Ukendt tilvalgsargument"
+
+msgid "Too many edit arguments"
+msgstr "For mange redigeringsargumenter"
+
+msgid "Argument missing after"
+msgstr "Argument mangler efter"
+
+msgid "Garbage after option argument"
+msgstr "Affald efter tilvalgsargument"
+
+msgid "Too many \"+command\", \"-c command\" or \"--cmd command\" arguments"
+msgstr ""
+"For mange \"+kommando\"-, \"-c kommando\"- eller \"--cmd kommando\"-"
+"argumenter"
+
+msgid "Invalid argument for"
+msgstr "Ugyldigt argument for"
+
+#, c-format
+msgid "%d files to edit\n"
+msgstr "%d filer at redigere\n"
+
+msgid "netbeans is not supported with this GUI\n"
+msgstr "netbeans understøttes ikke med denne GUI\n"
+
+msgid "'-nb' cannot be used: not enabled at compile time\n"
+msgstr "'-nb' kan ikke bruges: ikke aktiveret ved kompileringstid\n"
+
+msgid "This Vim was not compiled with the diff feature."
+msgstr "Denne Vim blev ikke kompileret med diff-funktionaliteten."
+
+msgid "Attempt to open script file again: \""
+msgstr "Forsøg på at åbne scriptfil igen: \""
+
+msgid "Cannot open for reading: \""
+msgstr "Kan ikke åbne til læsning: \""
+
+msgid "Cannot open for script output: \""
+msgstr "Kan ikke åbne for script-output: \""
+
+msgid "Vim: Error: Failure to start gvim from NetBeans\n"
+msgstr "Vim: Fejl: Kunne ikke starte gvim fra NetBeans\n"
+
+msgid "Vim: Error: This version of Vim does not run in a Cygwin terminal\n"
+msgstr "Vim: Fejl: Denne version af Vim kører ikke i en Cygwin-terminal\n"
+
+msgid "Vim: Warning: Output is not to a terminal\n"
+msgstr "Vim: Advarsel: Output er ikke til en terminal\n"
+
+msgid "Vim: Warning: Input is not from a terminal\n"
+msgstr "Vim: Advarsel: Input er ikke fra en terminal\n"
+
+msgid "pre-vimrc command line"
+msgstr "pre-vimrc-kommandolinje"
+
+#, c-format
+msgid "E282: Cannot read from \"%s\""
+msgstr "E282: Kan ikke læse fra \"%s\""
+
+msgid ""
+"\n"
+"More info with: \"vim -h\"\n"
+msgstr ""
+"\n"
+"Mere info med: \"vim -h\"\n"
+
+msgid "[file ..] edit specified file(s)"
+msgstr "[fil ..] rediger angivne fil(er)"
+
+msgid "- read text from stdin"
+msgstr "- læs tekst fra stdin"
+
+msgid "-t tag edit file where tag is defined"
+msgstr "-t tag rediger fil hvor tag er defineret"
+
+msgid "-q [errorfile] edit file with first error"
+msgstr "-q [fejlfil] rediger fil med første fejl"
+
+msgid ""
+"\n"
+"\n"
+"Usage:"
+msgstr ""
+"\n"
+"\n"
+"Anvendelse:"
+
+msgid " vim [arguments] "
+msgstr " vim [argumenter] "
+
+msgid ""
+"\n"
+" or:"
+msgstr ""
+"\n"
+" eller:"
+
+msgid ""
+"\n"
+"Where case is ignored prepend / to make flag upper case"
+msgstr ""
+"\n"
+"Når der ikke skelnes mellem store og små bogstaver, så tilføj / i "
+"begyndelsen for at gøre flag til store bogstaver"
+
+msgid ""
+"\n"
+"\n"
+"Arguments:\n"
+msgstr ""
+"\n"
+"\n"
+"Argumenter:\n"
+
+msgid "--\t\t\tOnly file names after this"
+msgstr "--\t\t\tKun filnavne herefter"
+
+msgid "--literal\t\tDon't expand wildcards"
+msgstr "--literal\t\tUdvid ikke jokertegn"
+
+msgid "-register\t\tRegister this gvim for OLE"
+msgstr "-register\t\tRegistrer denne gvim til OLE"
+
+msgid "-unregister\t\tUnregister gvim for OLE"
+msgstr "-unregister\t\tAfregistrer gvim for OLE"
+
+msgid "-g\t\t\tRun using GUI (like \"gvim\")"
+msgstr "-g\t\t\tKør med GUI (ligesom \"gvim\")"
+
+msgid "-f or --nofork\tForeground: Don't fork when starting GUI"
+msgstr "-f eller --nofork\tForgrund: Fork ikke når GUI startes"
+
+msgid "-v\t\t\tVi mode (like \"vi\")"
+msgstr "-v\t\t\tVi-tilstand (ligesom \"vi\")"
+
+msgid "-e\t\t\tEx mode (like \"ex\")"
+msgstr "-e\t\t\tEx-tilstand (ligesom \"ex\")"
+
+msgid "-E\t\t\tImproved Ex mode"
+msgstr "-E\t\t\tForbedret Ex-tilstand"
+
+msgid "-s\t\t\tSilent (batch) mode (only for \"ex\")"
+msgstr "-s\t\t\tStille (batch) tilstand (kun til \"ex\")"
+
+msgid "-d\t\t\tDiff mode (like \"vimdiff\")"
+msgstr "-d\t\t\tDiff-tilstand (ligesom \"vimdiff\")"
+
+msgid "-y\t\t\tEasy mode (like \"evim\", modeless)"
+msgstr "-y\t\t\tEasy-tilstand (ligesom \"evim\", tilstandsløs)"
+
+msgid "-R\t\t\tReadonly mode (like \"view\")"
+msgstr "-R\t\t\tSkrivebeskyttet tilstand (ligesom \"view\")"
+
+msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
+msgstr "-Z\t\t\tRestriktiv tilstand (ligesom \"rvim\")"
+
+msgid "-m\t\t\tModifications (writing files) not allowed"
+msgstr "-m\t\t\tÆndringer (skrivning af filer) ikke tilladt"
+
+msgid "-M\t\t\tModifications in text not allowed"
+msgstr "-M\t\t\tÆndringer i tekst ikke tilladt"
+
+msgid "-b\t\t\tBinary mode"
+msgstr "-b\t\t\tBinær tilstand"
+
+msgid "-l\t\t\tLisp mode"
+msgstr "-l\t\t\tLisp-tilstand"
+
+msgid "-C\t\t\tCompatible with Vi: 'compatible'"
+msgstr "-C\t\t\tKompatibel med Vi: 'compatible'"
+
+msgid "-N\t\t\tNot fully Vi compatible: 'nocompatible'"
+msgstr "-N\t\t\tIkke fuldt ud Vi-kompatibel: 'nocompatible'"
+
+msgid "-V[N][fname]\t\tBe verbose [level N] [log messages to fname]"
+msgstr "-V[N][fnavn]\t\tVær uddybende [niveau N] [log meddelelser til fnavn]"
+
+msgid "-D\t\t\tDebugging mode"
+msgstr "-D\t\t\tFejlretningstilstand"
+
+msgid "-n\t\t\tNo swap file, use memory only"
+msgstr "-n\t\t\tIngen swap-fil, brug kun hukommelse"
+
+msgid "-r\t\t\tList swap files and exit"
+msgstr "-r\t\t\tOplist swap-filer og afslut"
+
+msgid "-r (with file name)\tRecover crashed session"
+msgstr "-r (med filnavn)\tGendan session som holdt op med at virke"
+
+msgid "-L\t\t\tSame as -r"
+msgstr "-L\t\t\tSamme som -r"
+
+msgid "-f\t\t\tDon't use newcli to open window"
+msgstr "-f\t\t\tBrug ikke newcli til at åbne vindue"
+
+msgid "-dev <device>\t\tUse <device> for I/O"
+msgstr "-dev <enhed>\t\tBrug <enhed> til I/O"
+
+msgid "-A\t\t\tStart in Arabic mode"
+msgstr "-A\t\t\tStart i arabisk tilstand"
+
+msgid "-H\t\t\tStart in Hebrew mode"
+msgstr "-H\t\t\tStart i hebraisk tilstand"
+
+msgid "-F\t\t\tStart in Farsi mode"
+msgstr "-F\t\t\tStart i persisk tilstand"
+
+msgid "-T <terminal>\tSet terminal type to <terminal>"
+msgstr "-T <terminal>\tSæt terminaltype til <terminal>"
+
+msgid "--not-a-term\t\tSkip warning for input/output not being a terminal"
+msgstr ""
+"--not-a-term\t\tSpring advarsel over for input/output som ikke er en terminal"
+
+msgid "--ttyfail\t\tExit if input or output is not a terminal"
+msgstr "--ttyfail\t\tAfslut hvis input eller output ikke er en terminal"
+
+msgid "-u <vimrc>\t\tUse <vimrc> instead of any .vimrc"
+msgstr "-u <vimrc>\t\tBrug <vimrc> i stedet for nogen .vimrc"
+
+msgid "-U <gvimrc>\t\tUse <gvimrc> instead of any .gvimrc"
+msgstr "-U <gvimrc>\t\tBrug <gvimrc> i stedet for nogen .gvimrc"
+
+msgid "--noplugin\t\tDon't load plugin scripts"
+msgstr "--noplugin\t\tIndlæs ikke plugin-scripts"
+
+msgid "-p[N]\t\tOpen N tab pages (default: one for each file)"
+msgstr "-p[N]\t\tÅbn N fanebladssider (standard: én pr. fil)"
+
+msgid "-o[N]\t\tOpen N windows (default: one for each file)"
+msgstr "-o[N]\t\tÅbn N vinduer (standard: én pr. fil)"
+
+msgid "-O[N]\t\tLike -o but split vertically"
+msgstr "-O[N]\t\tLigesom -o men opdel lodret"
+
+msgid "+\t\t\tStart at end of file"
+msgstr "+\t\t\tBegynd ved slutningen af filen"
+
+msgid "+<lnum>\t\tStart at line <lnum>"
+msgstr "+<lnum>\t\tBegynd ved linje <lnum>"
+
+msgid "--cmd <command>\tExecute <command> before loading any vimrc file"
+msgstr "--cmd <kommando>\tUdfør <kommando> inden indlæsning af vimrc-filer"
+
+msgid "-c <command>\t\tExecute <command> after loading the first file"
+msgstr "-c <kommando>\tUdfør <kommando> efter indlæsning af den første fil"
+
+msgid "-S <session>\t\tSource file <session> after loading the first file"
+msgstr ""
+"-S <session>\t\tSource filen <session> efter indlæsning af den første fil"
+
+msgid "-s <scriptin>\tRead Normal mode commands from file <scriptin>"
+msgstr "-s <scriptind>\tLæs normal tilstand-kommandoer fra filen <scriptind>"
+
+msgid "-w <scriptout>\tAppend all typed commands to file <scriptout>"
+msgstr ""
+"-w <scriptud>\tTilføj alle indtastede kommandoer til slutningen af filen "
+"<scriptud>"
+
+msgid "-W <scriptout>\tWrite all typed commands to file <scriptout>"
+msgstr "-W <scriptud>\tSkriv alle indtastede kommandoer til filen <scriptud>"
+
+msgid "-x\t\t\tEdit encrypted files"
+msgstr "-x\t\t\tRediger krypterede filer"
+
+msgid "-display <display>\tConnect vim to this particular X-server"
+msgstr "-display <display>\tForbind vim til denne X-server"
+
+msgid "-X\t\t\tDo not connect to X server"
+msgstr "-X\t\t\tOpret ikke forbindelse til X-server"
+
+msgid "--remote <files>\tEdit <files> in a Vim server if possible"
+msgstr "--remote <filer>\tRediger <filer> i en Vim-server, hvis det er muligt"
+
+msgid "--remote-silent <files> Same, don't complain if there is no server"
+msgstr ""
+"--remote-silent <filer> Samme, men vær tavs hvis der ikke er nogen server"
+
+msgid ""
+"--remote-wait <files> As --remote but wait for files to have been edited"
+msgstr ""
+"--remote-wait <filer> Som --remote men vent på filer som skal redigeres"
+
+msgid ""
+"--remote-wait-silent <files> Same, don't complain if there is no server"
+msgstr ""
+"--remote-wait-silent <filer> Samme, men vær tavs hvis der ikke er nogen "
+"server"
+
+msgid ""
+"--remote-tab[-wait][-silent] <files> As --remote but use tab page per file"
+msgstr ""
+"--remote-tab[-wait][-silent] <filer> Som --remote men brug fanebladsside "
+"pr. fil"
+
+msgid "--remote-send <keys>\tSend <keys> to a Vim server and exit"
+msgstr "--remote-send <nøgler>\tSend <nøgler> til en Vim-server og afslut"
+
+msgid "--remote-expr <expr>\tEvaluate <expr> in a Vim server and print result"
+msgstr ""
+"--remote-expr <udtryk>\tEvaluér <udtryk> i en Vim-server og udskriv "
+"resultatet"
+
+msgid "--serverlist\t\tList available Vim server names and exit"
+msgstr "--serverlist\t\tOplist tilgængelige Vim-servernavne og afslut"
+
+msgid "--servername <name>\tSend to/become the Vim server <name>"
+msgstr "--servername <navn>\tSend til/bliv Vim-serveren <navn>"
+
+msgid "--startuptime <file>\tWrite startup timing messages to <file>"
+msgstr "--startuptime <fil>\tSkriv meddelelser om opstartstiming til <fil>"
+
+msgid "-i <viminfo>\t\tUse <viminfo> instead of .viminfo"
+msgstr "-i <viminfo>\t\tBrug <viminfo> i stedet for .viminfo"
+
+msgid "--clean\t\t'nocompatible', Vim defaults, no plugins, no viminfo"
+msgstr ""
+"--clean\t\t'nocompatible', Vim-standarder, ingen plugins, ingen viminfo"
+
+msgid "-h or --help\tPrint Help (this message) and exit"
+msgstr "-h eller --help\tUdskriv hjælp (denne meddelelse) og afslut"
+
+msgid "--version\t\tPrint version information and exit"
+msgstr "--version\t\tUdskriv versionsinformation og afslut"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Motif version):\n"
+msgstr ""
+"\n"
+"Argumenter som genkendes af gvim (Motif-version):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (neXtaw version):\n"
+msgstr ""
+"\n"
+"Argumenter som genkendes af gvim (neXtaw-version):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Athena version):\n"
+msgstr ""
+"\n"
+"Argumenter som genkendes af gvim (Athena-version):\n"
+
+msgid "-display <display>\tRun vim on <display>"
+msgstr "-display <display>\tKør vim på <display>"
+
+msgid "-iconic\t\tStart vim iconified"
+msgstr "-iconic\t\tStart vim som ikon"
+
+msgid "-background <color>\tUse <color> for the background (also: -bg)"
+msgstr "-background <farve>\tBrug <farve> til baggrunden (også: -bg)"
+
+msgid "-foreground <color>\tUse <color> for normal text (also: -fg)"
+msgstr "-foreground <farve>\tBrug <farve> til normal tekst (også: -fg)"
+
+msgid "-font <font>\t\tUse <font> for normal text (also: -fn)"
+msgstr "-font <skrifttype>\tBrug <skrifttype> til normal tekst (også: -fn)"
+
+msgid "-boldfont <font>\tUse <font> for bold text"
+msgstr "-boldfont <skrifttype>\tBrug <skrifttype> til fed tekst"
+
+msgid "-italicfont <font>\tUse <font> for italic text"
+msgstr "-italicfont <skriftt.>\tBrug <skrifttype> til kursiv tekst"
+
+msgid "-geometry <geom>\tUse <geom> for initial geometry (also: -geom)"
+msgstr "-geometry <geom>\tBrug <geom> for indledende geometri (også: -geom)"
+
+msgid "-borderwidth <width>\tUse a border width of <width> (also: -bw)"
+msgstr "-borderwidth <bredde>\tBrug en kantbredde på <bredde> (også: -bw)"
+
+msgid "-scrollbarwidth <width> Use a scrollbar width of <width> (also: -sw)"
+msgstr ""
+"-scrollbarwidth <bredde> Brug en rullebjælkebredde på <bredde> (også: -sw)"
+
+msgid "-menuheight <height>\tUse a menu bar height of <height> (also: -mh)"
+msgstr "-menuheight <højde>\tBrug en menulinjehøjde på <højde> (også: -mh)"
+
+msgid "-reverse\t\tUse reverse video (also: -rv)"
+msgstr "-reverse\t\tBrug omvendt grafik (også: -rv)"
+
+msgid "+reverse\t\tDon't use reverse video (also: +rv)"
+msgstr "+reverse\t\tBrug ikke omvendt grafik (også: +rv)"
+
+msgid "-xrm <resource>\tSet the specified resource"
+msgstr "-xrm <ressource>\tSæt den angivne ressource"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (GTK+ version):\n"
+msgstr ""
+"\n"
+"Argumenter genkendt af gvim (GTK+-version):\n"
+
+msgid "-display <display>\tRun vim on <display> (also: --display)"
+msgstr "-display <display>\tKør vim på <display> (også: --display)"
+
+msgid "--role <role>\tSet a unique role to identify the main window"
+msgstr "--role <rolle>\tSæt en unik rolle til at identificere hovedvinduet"
+
+msgid "--socketid <xid>\tOpen Vim inside another GTK widget"
+msgstr "--socketid <xid>\tÃ…bn Vim i en anden GTK-widget"
+
+msgid "--echo-wid\t\tMake gvim echo the Window ID on stdout"
+msgstr "--echo-wid\t\tFÃ¥ gvim til at skrive vinduets ID til stdout"
+
+msgid "-P <parent title>\tOpen Vim inside parent application"
+msgstr "-P <forældertitel>\tÅbn Vim i forælderprogram"
+
+msgid "--windowid <HWND>\tOpen Vim inside another win32 widget"
+msgstr "--windowid <HWND>\tÃ…bn Vim i en anden win32-widget"
+
+msgid "No display"
+msgstr "Intet display"
+
+msgid ": Send failed.\n"
+msgstr ": Sending mislykkedes.\n"
+
+msgid ": Send failed. Trying to execute locally\n"
+msgstr ": Sending mislykkedes. Prøver at udføre lokalt\n"
+
+#, c-format
+msgid "%d of %d edited"
+msgstr "%d af %d redigeret"
+
+msgid "No display: Send expression failed.\n"
+msgstr "Intet display: Send-udtryk mislykkedes.\n"
+
+msgid ": Send expression failed.\n"
+msgstr ": Send-udtryk mislykkedes.\n"
+
+msgid "No marks set"
+msgstr "Ingen mærker sat"
+
+#, c-format
+msgid "E283: No marks matching \"%s\""
+msgstr "E283: Ingen mærker matcher \"%s\""
+
+msgid ""
+"\n"
+"mark line col file/text"
+msgstr ""
+"\n"
+"mærke linje kol fil/tekst"
+
+msgid ""
+"\n"
+" jump line col file/text"
+msgstr ""
+"\n"
+" hop linje kol fil/tekst"
+
+msgid ""
+"\n"
+"change line col text"
+msgstr ""
+"\n"
+"skift linje kol tekst"
+
+msgid ""
+"\n"
+"# File marks:\n"
+msgstr ""
+"\n"
+"# Filmærker:\n"
+
+msgid ""
+"\n"
+"# Jumplist (newest first):\n"
+msgstr ""
+"\n"
+"# Hopliste (nyeste først):\n"
+
+msgid ""
+"\n"
+"# History of marks within files (newest to oldest):\n"
+msgstr ""
+"\n"
+"# Historik over mærker i filer (nyeste til ældste):\n"
+
+msgid "Missing '>'"
+msgstr "Manglende '>'"
+
+msgid "E543: Not a valid codepage"
+msgstr "E543: Ikke en gyldig tegnkodningstabel"
+
+msgid "E284: Cannot set IC values"
+msgstr "E284: Kan ikke sætte IC-værdier"
+
+msgid "E285: Failed to create input context"
+msgstr "E285: Kunne ikke oprette inputkontekst"
+
+msgid "E286: Failed to open input method"
+msgstr "E286: Kunne ikke åbne inputmetode"
+
+msgid "E287: Warning: Could not set destroy callback to IM"
+msgstr "E287: Advarsel: Kunne ikke sætte destroy callback til IM"
+
+msgid "E288: input method doesn't support any style"
+msgstr "E288: inputmetode understøtter ikke nogen stil"
+
+msgid "E289: input method doesn't support my preedit type"
+msgstr "E289: inputmetode understøtter ikke min preedit-type"
+
+msgid "E293: block was not locked"
+msgstr "E293: blok blev ikke låst"
+
+msgid "E294: Seek error in swap file read"
+msgstr "E294: Søgefejl ved læsning af swap-fil"
+
+msgid "E295: Read error in swap file"
+msgstr "E295: Læsefejl i swap-fil"
+
+msgid "E296: Seek error in swap file write"
+msgstr "E296: Søgefejl ved skrivning af swap-fil"
+
+msgid "E297: Write error in swap file"
+msgstr "E297: Skrivefejl i swap-fil"
+
+msgid "E300: Swap file already exists (symlink attack?)"
+msgstr "E300: Swap-filen findes allerede (symlink angreb?)"
+
+msgid "E298: Didn't get block nr 0?"
+msgstr "E298: Blev blok nr. 0 ikke hentet?"
+
+msgid "E298: Didn't get block nr 1?"
+msgstr "E298: Blev blok nr. 1 ikke hentet?"
+
+msgid "E298: Didn't get block nr 2?"
+msgstr "E298: Blev blok nr. 2 ikke hentet?"
+
+msgid "E843: Error while updating swap file crypt"
+msgstr "E843: Fejl ved opdatering af crypt for swap-fil"
+
+msgid "E301: Oops, lost the swap file!!!"
+msgstr "E301: Ups, mistede swap-filen!!!"
+
+msgid "E302: Could not rename swap file"
+msgstr "E302: Kunne ikke omdøbe swap-fil"
+
+#, c-format
+msgid "E303: Unable to open swap file for \"%s\", recovery impossible"
+msgstr "E303: Kan ikke åbne swap-filen for \"%s\", gendannelse er ikke muligt"
+
+msgid "E304: ml_upd_block0(): Didn't get block 0??"
+msgstr "E304: ml_upd_block0(): Blev blok 0 ikke hentet??"
+
+#, c-format
+msgid "E305: No swap file found for %s"
+msgstr "E305: Fandt ingen swap-fil for %s"
+
+msgid "Enter number of swap file to use (0 to quit): "
+msgstr "Indtast antal swap-filer som der skal bruges (0 for at afslutte): "
+
+#, c-format
+msgid "E306: Cannot open %s"
+msgstr "E306: Kan ikke åbne %s"
+
+msgid "Unable to read block 0 from "
+msgstr "Kan ikke læse blok 0 fra "
+
+msgid ""
+"\n"
+"Maybe no changes were made or Vim did not update the swap file."
+msgstr ""
+"\n"
+"Måske er der ikke foretaget nogen ændringer eller Vim opdaterede ikke swap-"
+"filen."
+
+msgid " cannot be used with this version of Vim.\n"
+msgstr " kan ikke bruges med denne version af Vim.\n"
+
+msgid "Use Vim version 3.0.\n"
+msgstr "Brug Vim version 3.0.\n"
+
+#, c-format
+msgid "E307: %s does not look like a Vim swap file"
+msgstr "E307: %s ligner ikke en Vim swap-fil"
+
+msgid " cannot be used on this computer.\n"
+msgstr " kan ikke bruges på denne computer.\n"
+
+msgid "The file was created on "
+msgstr "Filen blev oprettet på "
+
+msgid ""
+",\n"
+"or the file has been damaged."
+msgstr ""
+",\n"
+"eller filen er beskadiget."
+
+#, c-format
+msgid ""
+"E833: %s is encrypted and this version of Vim does not support encryption"
+msgstr ""
+"E833: %s er krypteret og denne version af Vim understøtter ikke kryptering"
+
+msgid " has been damaged (page size is smaller than minimum value).\n"
+msgstr " er beskadiget (sidestørrelsen er mindre end minimumsværdien).\n"
+
+#, c-format
+msgid "Using swap file \"%s\""
+msgstr "Bruger swap-filen \"%s\""
+
+#, c-format
+msgid "Original file \"%s\""
+msgstr "Den originale fil \"%s\""
+
+msgid "E308: Warning: Original file may have been changed"
+msgstr "E308: Advarsel: Den originale fil kan være ændret"
+
+#, c-format
+msgid "Swap file is encrypted: \"%s\""
+msgstr "Swap-filen er krypteret: \"%s\""
+
+msgid ""
+"\n"
+"If you entered a new crypt key but did not write the text file,"
+msgstr ""
+"\n"
+"Hvis du indtastede en ny krypteringsnøgle men ikke skrev tekstfilen,"
+
+msgid ""
+"\n"
+"enter the new crypt key."
+msgstr ""
+"\n"
+"så indtast den nye krypteringsnøgle."
+
+msgid ""
+"\n"
+"If you wrote the text file after changing the crypt key press enter"
+msgstr ""
+"\n"
+"Hvis du skrev tekstfilen efter krypteringsnøglen blev ændret, så tryk på "
+"enter"
+
+msgid ""
+"\n"
+"to use the same key for text file and swap file"
+msgstr ""
+"\n"
+"for at bruge den samme nøgle til tekstfilen og swap-filen"
+
+#, c-format
+msgid "E309: Unable to read block 1 from %s"
+msgstr "E309: Kan ikke læse blok 1 fra %s"
+
+msgid "???MANY LINES MISSING"
+msgstr "???MANGE LINJER MANGLER"
+
+msgid "???LINE COUNT WRONG"
+msgstr "???LINJEANTAL FORKERT"
+
+msgid "???EMPTY BLOCK"
+msgstr "???TOM BLOK"
+
+msgid "???LINES MISSING"
+msgstr "???LINJER MANGLER"
+
+#, c-format
+msgid "E310: Block 1 ID wrong (%s not a .swp file?)"
+msgstr "E310: Forkert ID for blok 1 (%s ikke en .swp-fil?)"
+
+msgid "???BLOCK MISSING"
+msgstr "???BLOK MANGLER"
+
+msgid "??? from here until ???END lines may be messed up"
+msgstr "??? herfra indtil ???SLUT kan linjer være rodet"
+
+msgid "??? from here until ???END lines may have been inserted/deleted"
+msgstr "??? herfra indtil ???SLUT kan linjer være indsat/slettet"
+
+msgid "???END"
+msgstr "???SLUT"
+
+msgid "E311: Recovery Interrupted"
+msgstr "E311: Gendannelse afbrudt"
+
+msgid ""
+"E312: Errors detected while recovering; look for lines starting with ???"
+msgstr ""
+"E312: Fejl registreret ved gendannelse; kig efter linjer som begynder med ???"
+
+msgid "See \":help E312\" for more information."
+msgstr "Se \":help E312\" for mere information."
+
+msgid "Recovery completed. You should check if everything is OK."
+msgstr "Gendannelse gennemført. Du bør tjekke om alt er OK."
+
+msgid ""
+"\n"
+"(You might want to write out this file under another name\n"
+msgstr ""
+"\n"
+"(Det kan være du vil skrive filen under et andet navn\n"
+
+msgid "and run diff with the original file to check for changes)"
+msgstr "og kør diff men den originale fil for at tjekke for ændringer)"
+
+msgid "Recovery completed. Buffer contents equals file contents."
+msgstr ""
+"Gendannelse gennemført. Bufferens indhold er det samme som filens indhold."
+
+msgid ""
+"\n"
+"You may want to delete the .swp file now.\n"
+"\n"
+msgstr ""
+"\n"
+"Det kan være du vil slette .swp-filen nu.\n"
+"\n"
+
+msgid "Using crypt key from swap file for the text file.\n"
+msgstr "Bruger krypteringsnøglen fra swap-filen til tekstfilen.\n"
+
+msgid "Swap files found:"
+msgstr "Swap-filer fundet:"
+
+msgid " In current directory:\n"
+msgstr " I nuværende mappe:\n"
+
+msgid " Using specified name:\n"
+msgstr " Bruger angivne navn:\n"
+
+msgid " In directory "
+msgstr " I mappe "
+
+msgid " -- none --\n"
+msgstr " -- ingen --\n"
+
+msgid " owned by: "
+msgstr " ejet af: "
+
+msgid " dated: "
+msgstr " dateret: "
+
+msgid " dated: "
+msgstr " dateret: "
+
+msgid " [from Vim version 3.0]"
+msgstr " [fra Vim version 3.0]"
+
+msgid " [does not look like a Vim swap file]"
+msgstr " [ligner ikke en Vim swap-fil]"
+
+msgid " file name: "
+msgstr " filnavn: "
+
+msgid ""
+"\n"
+" modified: "
+msgstr ""
+"\n"
+" ændret: "
+
+msgid "YES"
+msgstr "JA"
+
+msgid "no"
+msgstr "nej"
+
+msgid ""
+"\n"
+" user name: "
+msgstr ""
+"\n"
+" brugernavn: "
+
+msgid " host name: "
+msgstr " værtsnavn: "
+
+msgid ""
+"\n"
+" host name: "
+msgstr ""
+"\n"
+" værtsnavn: "
+
+msgid ""
+"\n"
+" process ID: "
+msgstr ""
+"\n"
+" proces-ID: "
+
+msgid " (still running)"
+msgstr " (kører stadig)"
+
+msgid ""
+"\n"
+" [not usable with this version of Vim]"
+msgstr ""
+"\n"
+" [ikke anvendelig med denne version af Vim]"
+
+msgid ""
+"\n"
+" [not usable on this computer]"
+msgstr ""
+"\n"
+" [ikke anvendelig på denne computer]"
+
+msgid " [cannot be read]"
+msgstr " [kan ikke læses]"
+
+msgid " [cannot be opened]"
+msgstr " [kan ikke åbnes]"
+
+msgid "E313: Cannot preserve, there is no swap file"
+msgstr "E313: Kan ikke bevares, der er ikke nogen swap-fil"
+
+msgid "File preserved"
+msgstr "Fil bevaret"
+
+msgid "E314: Preserve failed"
+msgstr "E314: Bevaring mislykkedes"
+
+#, c-format
+msgid "E315: ml_get: invalid lnum: %ld"
+msgstr "E315: ml_get: ugyldig lnum: %ld"
+
+#, c-format
+msgid "E316: ml_get: cannot find line %ld"
+msgstr "E316: ml_get: kan ikke finde linje %ld"
+
+msgid "E317: pointer block id wrong 3"
+msgstr "E317: forkert blok-id for pointer 3"
+
+msgid "stack_idx should be 0"
+msgstr "stack_idx skal være 0"
+
+msgid "E318: Updated too many blocks?"
+msgstr "E318: Opdaterede for mange blokke?"
+
+msgid "E317: pointer block id wrong 4"
+msgstr "E317: forkert blok-id for pointer 4"
+
+msgid "deleted block 1?"
+msgstr "slettede blok 1?"
+
+#, c-format
+msgid "E320: Cannot find line %ld"
+msgstr "E320: Kan ikke finde linje %ld"
+
+msgid "E317: pointer block id wrong"
+msgstr "E317: forkert blok-id for pointer"
+
+msgid "pe_line_count is zero"
+msgstr "pe_line_count er nul"
+
+#, c-format
+msgid "E322: line number out of range: %ld past the end"
+msgstr "E322: linjenummer udenfor område: %ld efter slutningen"
+
+#, c-format
+msgid "E323: line count wrong in block %ld"
+msgstr "E323: linje antal forkert i blok %ld"
+
+msgid "Stack size increases"
+msgstr "Stakstørrelse øges"
+
+msgid "E317: pointer block id wrong 2"
+msgstr "E317: forkert blok-id for pointer 2"
+
+#, c-format
+msgid "E773: Symlink loop for \"%s\""
+msgstr "E773: Symlink-løkke for \"%s\""
+
+msgid "E325: ATTENTION"
+msgstr "E325: OBS"
+
+msgid ""
+"\n"
+"Found a swap file by the name \""
+msgstr ""
+"\n"
+"Fandt en swap-fil ved navn \""
+
+msgid "While opening file \""
+msgstr "Ved åbning af filen \""
+
+msgid " NEWER than swap file!\n"
+msgstr " NYERE end swap-fil!\n"
+
+msgid ""
+"\n"
+"(1) Another program may be editing the same file. If this is the case,\n"
+" be careful not to end up with two different instances of the same\n"
+" file when making changes. Quit, or continue with caution.\n"
+msgstr ""
+"\n"
+"(1) Et andet program redigere muligvis den samme fil. Hvis det er "
+"tilfældet,\n"
+" så pas på ikke at ende med to forskellige instanser af den samme\n"
+" fil når der foretages ændringer. Afslut, eller fortsæt med "
+"forsigtighed.\n"
+
+msgid "(2) An edit session for this file crashed.\n"
+msgstr "(2) En redigeringssession for filen holdt op med at virke.\n"
+
+msgid " If this is the case, use \":recover\" or \"vim -r "
+msgstr " Hvis det er tilfældet, så brug \":recover\" eller \"vim -r "
+
+msgid ""
+"\"\n"
+" to recover the changes (see \":help recovery\").\n"
+msgstr ""
+"\"\n"
+" for at gendanne ændringerne (se \":help recovery\").\n"
+
+msgid " If you did this already, delete the swap file \""
+msgstr " Hvis du allerede har gjort det, så slet swap-filen \""
+
+msgid ""
+"\"\n"
+" to avoid this message.\n"
+msgstr ""
+"\"\n"
+" for at undgå denne meddelelse.\n"
+
+msgid "Swap file \""
+msgstr "Swap-filen \""
+
+msgid "\" already exists!"
+msgstr "\" findes allerede!"
+
+msgid "VIM - ATTENTION"
+msgstr "VIM - OBS"
+
+msgid "Swap file already exists!"
+msgstr "Swap-filen findes allerede!"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"&Ã…bn skrivebeskyttet\n"
+"&Rediger alligevel\n"
+"&Gendan\n"
+"&Afslut\n"
+"&Afbryd"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Delete it\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"&Ã…bn skrivebeskyttet\n"
+"&Rediger alligevel\n"
+"&Gendan\n"
+"&Slet den\n"
+"&Afslut\n"
+"&Afbryd"
+
+msgid "E326: Too many swap files found"
+msgstr "E326: For mange swap-filer fundet"
+
+msgid "E327: Part of menu-item path is not sub-menu"
+msgstr "E327: Del af sti til menupunkt er ikke undermenu"
+
+msgid "E328: Menu only exists in another mode"
+msgstr "E328: Menuen findes kun i en anden tilstand"
+
+#, c-format
+msgid "E329: No menu \"%s\""
+msgstr "E329: Ingen menu \"%s\""
+
+msgid "E792: Empty menu name"
+msgstr "E792: Tomt menunavn"
+
+msgid "E330: Menu path must not lead to a sub-menu"
+msgstr "E330: Menusti må ikke lede til en undermenu"
+
+msgid "E331: Must not add menu items directly to menu bar"
+msgstr "E331: Må ikke tilføje menupunkter direkte til menulinje"
+
+msgid "E332: Separator cannot be part of a menu path"
+msgstr "E332: Separator må ikke være del af en menusti"
+
+msgid ""
+"\n"
+"--- Menus ---"
+msgstr ""
+"\n"
+"--- Menuer ---"
+
+msgid "Tear off this menu"
+msgstr "Løsriv menuen"
+
+#, c-format
+msgid "E335: Menu not defined for %s mode"
+msgstr "E335: Menu ikke defineret for %s-tilstand"
+
+msgid "E333: Menu path must lead to a menu item"
+msgstr "E333: Menusti skal lede til et menupunkt"
+
+#, c-format
+msgid "E334: Menu not found: %s"
+msgstr "E334: Menu ikke fundet: %s"
+
+msgid "E336: Menu path must lead to a sub-menu"
+msgstr "E336: Menusti skal lede til en undermenu"
+
+msgid "E337: Menu not found - check menu names"
+msgstr "E337: Menu ikke fundet - tjek menunavne"
+
+#, c-format
+msgid "Error detected while processing %s:"
+msgstr "Fejl registreret ved behandling af %s:"
+
+#, c-format
+msgid "line %4ld:"
+msgstr "linje %4ld:"
+
+#, c-format
+msgid "E354: Invalid register name: '%s'"
+msgstr "E354: Ugyldigt registernavn: '%s'"
+
+msgid "Messages maintainer: Bram Moolenaar <Bram@vim.org>"
+msgstr "Oversætter: scootergrisen"
+
+msgid "Interrupt: "
+msgstr "Afbryd: "
+
+msgid "Press ENTER or type command to continue"
+msgstr "Tryk på ENTER eller skriv kommando for at fortsætte"
+
+#, c-format
+msgid "%s line %ld"
+msgstr "%s linje %ld"
+
+msgid "-- More --"
+msgstr "-- Mere --"
+
+msgid " SPACE/d/j: screen/page/line down, b/u/k: up, q: quit "
+msgstr " MELLEMRUM/d/j: skærm/side/linje ned, b/u/k: op, q: afslut "
+
+msgid "Question"
+msgstr "Spørgsmål"
+
+msgid ""
+"&Yes\n"
+"&No"
+msgstr ""
+"&Ja\n"
+"&Nej"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"Save &All\n"
+"&Discard All\n"
+"&Cancel"
+msgstr ""
+"&Ja\n"
+"&Nej\n"
+"Gem &alle\n"
+"&Forkast alle\n"
+"&Annuller"
+
+msgid "Select Directory dialog"
+msgstr "Vælg mappe-dialog"
+
+msgid "Save File dialog"
+msgstr "Gem fil-dialog"
+
+msgid "Open File dialog"
+msgstr "Ã…bn fil-dialog"
+
+msgid "E338: Sorry, no file browser in console mode"
+msgstr "E338: Beklager, ingen filbrowser i konsol-tilstand"
+
+msgid "E766: Insufficient arguments for printf()"
+msgstr "E766: Ikke nok argumenter for printf()"
+
+msgid "E807: Expected Float argument for printf()"
+msgstr "E807: Ventede flydende kommatal-argument for printf()"
+
+msgid "E767: Too many arguments to printf()"
+msgstr "E767: For mange argumenter til printf()"
+
+msgid "W10: Warning: Changing a readonly file"
+msgstr "W10: Advarsel: Ændre en skrivebeskyttet fil"
+
+msgid "Type number and <Enter> or click with mouse (empty cancels): "
+msgstr "Skriv nummer og <Enter> eller klik med musen (tom annullerer): "
+
+msgid "Type number and <Enter> (empty cancels): "
+msgstr "Skriv nummer og <Enter> (tom annullerer): "
+
+msgid "1 more line"
+msgstr "1 linje mere"
+
+msgid "1 line less"
+msgstr "1 linje mindre"
+
+#, c-format
+msgid "%ld more lines"
+msgstr "%ld linjer mere"
+
+#, c-format
+msgid "%ld fewer lines"
+msgstr "%ld linjere mindre"
+
+msgid " (Interrupted)"
+msgstr " (Afbrudt)"
+
+msgid "Beep!"
+msgstr "Bip!"
+
+msgid "ERROR: "
+msgstr "FEJL: "
+
+#, c-format
+msgid ""
+"\n"
+"[bytes] total alloc-freed %lu-%lu, in use %lu, peak use %lu\n"
+msgstr ""
+"\n"
+"[byte] samlet allok-frigivet %lu-%lu, i brug %lu, spidspunktsbrug %lu\n"
+
+#, c-format
+msgid ""
+"[calls] total re/malloc()'s %lu, total free()'s %lu\n"
+"\n"
+msgstr ""
+"[kald] samlet re/malloc()'er %lu, samlet free()'er %lu\n"
+"\n"
+
+msgid "E340: Line is becoming too long"
+msgstr "E340: Linje er ved at blive for lang"
+
+#, c-format
+msgid "E341: Internal error: lalloc(%ld, )"
+msgstr "E341: Intern fejl: lalloc(%ld, )"
+
+#, c-format
+msgid "E342: Out of memory! (allocating %lu bytes)"
+msgstr "E342: Ikke mere ledig hukommelse! (allokerer %lu byte)"
+
+#, c-format
+msgid "Calling shell to execute: \"%s\""
+msgstr "Kalder skal til udførelse af: \"%s\""
+
+msgid "E545: Missing colon"
+msgstr "E545: Manglende kolon"
+
+msgid "E546: Illegal mode"
+msgstr "E546: Ulovlig tilstand"
+
+msgid "E547: Illegal mouseshape"
+msgstr "E547: Ulovlig museform"
+
+msgid "E548: digit expected"
+msgstr "E548: ciffer ventet"
+
+msgid "E549: Illegal percentage"
+msgstr "E549: Ulovlig procent"
+
+msgid "E854: path too long for completion"
+msgstr "E854: sti for lang til fuldførelse"
+
+#, c-format
+msgid ""
+"E343: Invalid path: '**[number]' must be at the end of the path or be "
+"followed by '%s'."
+msgstr ""
+"E343: Ugyldig sti: '**[nummer]' skal være i slutningen af stien eller "
+"efterfølges af '%s'."
+
+#, c-format
+msgid "E344: Can't find directory \"%s\" in cdpath"
+msgstr "E344: Kan ikke finde mappen \"%s\" i cdpath"
+
+#, c-format
+msgid "E345: Can't find file \"%s\" in path"
+msgstr "E345: Kan ikke finde filen \"%s\" i path"
+
+#, c-format
+msgid "E346: No more directory \"%s\" found in cdpath"
+msgstr "E346: Ikke flere mappe \"%s\" fundet i cdpath"
+
+#, c-format
+msgid "E347: No more file \"%s\" found in path"
+msgstr "E347: Ikke flere fil \"%s\" fundet i path"
+
+#, c-format
+msgid "E668: Wrong access mode for NetBeans connection info file: \"%s\""
+msgstr ""
+"E668: Forkert adgangstilstand for NetBeans-forbindelsens info-fil: \"%s\""
+
+#, c-format
+msgid "E658: NetBeans connection lost for buffer %ld"
+msgstr "E658: NetBeans-forbindelse mistet for buffer %ld"
+
+msgid "E838: netbeans is not supported with this GUI"
+msgstr "E838: netbeans understøttes ikke med denne GUI"
+
+msgid "E511: netbeans already connected"
+msgstr "E511: netbeans allerede forbundet"
+
+#, c-format
+msgid "E505: %s is read-only (add ! to override)"
+msgstr "E505: %s er skrivebeskyttet (tilføj ! for at tilsidesætte)"
+
+msgid "E349: No identifier under cursor"
+msgstr "E349: Ingen identifikator under markør"
+
+msgid "E774: 'operatorfunc' is empty"
+msgstr "E774: 'operatorfunc' er tom"
+
+msgid "E775: Eval feature not available"
+msgstr "E775: Eval-funktionalitet ikke tilgængelig"
+
+msgid "Warning: terminal cannot highlight"
+msgstr "Advarsel: terminal kan ikke fremhæve"
+
+msgid "E348: No string under cursor"
+msgstr "E348: Ingen streng under markør"
+
+msgid "E352: Cannot erase folds with current 'foldmethod'"
+msgstr "E352: Kan ikke slette sammenfoldninger med nuværende 'foldmethod'"
+
+msgid "E664: changelist is empty"
+msgstr "E664: ændringsliste er tom"
+
+msgid "E662: At start of changelist"
+msgstr "E662: Ved begyndelsen af ændringsliste"
+
+msgid "E663: At end of changelist"
+msgstr "E663: Ved slutningen af ændringsliste"
+
+msgid "Type :qa! and press <Enter> to abandon all changes and exit Vim"
+msgstr ""
+"Skriv :qa! og tryk på <Enter> for at droppe alle ændringer og afslut Vim"
+
+#, c-format
+msgid "1 line %sed 1 time"
+msgstr "1 linje %sed 1 gang"
+
+#, c-format
+msgid "1 line %sed %d times"
+msgstr "1 linje %sed %d gange"
+
+#, c-format
+msgid "%ld lines %sed 1 time"
+msgstr "%ld linjer %sed 1 gang"
+
+#, c-format
+msgid "%ld lines %sed %d times"
+msgstr "%ld linjer %sed %d gange"
+
+#, c-format
+msgid "%ld lines to indent... "
+msgstr "%ld linjer at indrykke... "
+
+msgid "1 line indented "
+msgstr "1 linje indrykket "
+
+#, c-format
+msgid "%ld lines indented "
+msgstr "%ld linjer indrykket "
+
+msgid "E748: No previously used register"
+msgstr "E748: Intet tidligere brugt register"
+
+msgid "cannot yank; delete anyway"
+msgstr "kan ikke rykke; slet alligevel"
+
+msgid "1 line changed"
+msgstr "1 linje ændret"
+
+#, c-format
+msgid "%ld lines changed"
+msgstr "%ld linjer ændret"
+
+#, c-format
+msgid "freeing %ld lines"
+msgstr "frigør %ld linjer"
+
+#, c-format
+msgid " into \"%c"
+msgstr " i \"%c"
+
+#, c-format
+msgid "block of 1 line yanked%s"
+msgstr "blok på 1 linje rykket%s"
+
+#, c-format
+msgid "1 line yanked%s"
+msgstr "1 linje rykket%s"
+
+#, c-format
+msgid "block of %ld lines yanked%s"
+msgstr "blok på %ld linjer rykket%s"
+
+#, c-format
+msgid "%ld lines yanked%s"
+msgstr "%ld linjer rykket%s"
+
+#, c-format
+msgid "E353: Nothing in register %s"
+msgstr "E353: Intet i register %s"
+
+msgid ""
+"\n"
+"--- Registers ---"
+msgstr ""
+"\n"
+"--- Registre ---"
+
+msgid "Illegal register name"
+msgstr "Ulovligt registernavn"
+
+msgid ""
+"\n"
+"# Registers:\n"
+msgstr ""
+"\n"
+"# Registre:\n"
+
+#, c-format
+msgid "E574: Unknown register type %d"
+msgstr "E574: Ukendt registertype %d"
+
+msgid ""
+"E883: search pattern and expression register may not contain two or more "
+"lines"
+msgstr ""
+"E883: søgemønster og udtryksregister må ikke indeholde to eller flere linjer"
+
+#, c-format
+msgid "%ld Cols; "
+msgstr "%ld kolonner; "
+
+#, c-format
+msgid "Selected %s%ld of %ld Lines; %lld of %lld Words; %lld of %lld Bytes"
+msgstr "Markerede %s%ld af %ld linje; %lld af %lld ord; %lld af %lld byte"
+
+#, c-format
+msgid ""
+"Selected %s%ld of %ld Lines; %lld of %lld Words; %lld of %lld Chars; %lld of "
+"%lld Bytes"
+msgstr ""
+"Markerede %s%ld af %ld linje; %lld af %lld ord; %lld af %lld tegn; %lld af "
+"%lld byte"
+
+#, c-format
+msgid "Col %s of %s; Line %ld of %ld; Word %lld of %lld; Byte %lld of %lld"
+msgstr "Kol %s af %s; Linje %ld af %ld; Ord %lld af %lld; Byte %lld af %lld"
+
+#, c-format
+msgid ""
+"Col %s of %s; Line %ld of %ld; Word %lld of %lld; Char %lld of %lld; Byte "
+"%lld of %lld"
+msgstr ""
+"Kol %s af %s; Linje %ld af %ld; Ord %lld af %lld; Tegn %lld af %lld; Byte "
+"%lld af %lld"
+
+#, c-format
+msgid "(+%lld for BOM)"
+msgstr "(+%lld for BOM)"
+
+msgid "Thanks for flying Vim"
+msgstr "Tak fordi du fløj med Vim"
+
+msgid "E518: Unknown option"
+msgstr "E518: Ukendt tilvalg"
+
+msgid "E519: Option not supported"
+msgstr "E519: Tilvalg understøttes ikke"
+
+msgid "E520: Not allowed in a modeline"
+msgstr "E520: Ikke tilladt på en tilstandslinje"
+
+msgid "E846: Key code not set"
+msgstr "E846: Tastekode ikke sat"
+
+msgid "E521: Number required after ="
+msgstr "E521: Nummer kræves efter ="
+
+msgid "E522: Not found in termcap"
+msgstr "E522: Ikke fundet i termcap"
+
+#, c-format
+msgid "E539: Illegal character <%s>"
+msgstr "E539: Ulovligt tegn <%s>"
+
+#, c-format
+msgid "For option %s"
+msgstr "For tilvalget %s"
+
+msgid "E529: Cannot set 'term' to empty string"
+msgstr "E529: Kan ikke sætte 'term' til tom streng"
+
+msgid "E530: Cannot change term in GUI"
+msgstr "E530: Kan ikke skifte term i GUI"
+
+msgid "E531: Use \":gui\" to start the GUI"
+msgstr "E531: Brug \":gui\" til at starte GUI'en"
+
+msgid "E589: 'backupext' and 'patchmode' are equal"
+msgstr "E589: 'backupext' og 'patchmode' er ens"
+
+msgid "E834: Conflicts with value of 'listchars'"
+msgstr "E834: Er i konflikt med værdien af 'listchars'"
+
+msgid "E835: Conflicts with value of 'fillchars'"
+msgstr "E835: Er i konflikt med værdien af 'fillchars'"
+
+msgid "E617: Cannot be changed in the GTK+ 2 GUI"
+msgstr "E617: Kan ikke ændres i GTK+ 2 GUI'en"
+
+#, c-format
+msgid "E950: Cannot convert between %s and %s"
+msgstr "E950: Kan ikke konvertere mellem %s og %s"
+
+msgid "E524: Missing colon"
+msgstr "E524: Manglende kolon"
+
+msgid "E525: Zero length string"
+msgstr "E525: Streng uden længde"
+
+#, c-format
+msgid "E526: Missing number after <%s>"
+msgstr "E526: Manglende nummer efter <%s>"
+
+msgid "E527: Missing comma"
+msgstr "E527: Manglende komma"
+
+msgid "E528: Must specify a ' value"
+msgstr "E528: Skal angive en '-værdi"
+
+msgid "E595: contains unprintable or wide character"
+msgstr "E595: indeholder tegn som ikke kan udskrives eller er bredt"
+
+msgid "E596: Invalid font(s)"
+msgstr "E596: Ugyldig skrifttype(r)"
+
+msgid "E597: can't select fontset"
+msgstr "E597: kan ikke vælge skrifttypesæt"
+
+msgid "E598: Invalid fontset"
+msgstr "E598: Ugyldigt skrifttypesæt"
+
+msgid "E533: can't select wide font"
+msgstr "E533: kan ikke vælge bred skrifttype"
+
+msgid "E534: Invalid wide font"
+msgstr "E534: Ugyldig bred skrifttype"
+
+#, c-format
+msgid "E535: Illegal character after <%c>"
+msgstr "E535: Ulovligt tegn efter <%c>"
+
+msgid "E536: comma required"
+msgstr "E536: komma kræves"
+
+#, c-format
+msgid "E537: 'commentstring' must be empty or contain %s"
+msgstr "E537: 'commentstring' skal være tom eller indeholde %s"
+
+msgid "E538: No mouse support"
+msgstr "E538: Ingen understøttelse af mus"
+
+msgid "E540: Unclosed expression sequence"
+msgstr "E540: Ulukket udtryk-sekvens"
+
+msgid "E541: too many items"
+msgstr "E541: for mange punkter"
+
+msgid "E542: unbalanced groups"
+msgstr "E542: ubalancerede grupper"
+
+msgid "E946: Cannot make a terminal with running job modifiable"
+msgstr "E946: Kan ikke gøre en terminal med kørende job ændringsbar"
+
+msgid "E590: A preview window already exists"
+msgstr "E590: Der findes allerede et forhåndsvisningsvindue"
+
+msgid "W17: Arabic requires UTF-8, do ':set encoding=utf-8'"
+msgstr "W17: Arabisk kræver UTF-8, brug ':set encoding=utf-8'"
+
+msgid "E954: 24-bit colors are not supported on this environment"
+msgstr "E954: 24-bit farver understøttes ikke i dette miljø"
+
+#, c-format
+msgid "E593: Need at least %d lines"
+msgstr "E593: Skal være mindst %d linjer"
+
+#, c-format
+msgid "E594: Need at least %d columns"
+msgstr "E594: Skal være mindst %d kolonner"
+
+#, c-format
+msgid "E355: Unknown option: %s"
+msgstr "E355: Ukendt tilvalg: %s"
+
+#, c-format
+msgid "E521: Number required: &%s = '%s'"
+msgstr "E521: Nummer kræves: &%s = '%s'"
+
+msgid ""
+"\n"
+"--- Terminal codes ---"
+msgstr ""
+"\n"
+"--- Terminal-koder ---"
+
+msgid ""
+"\n"
+"--- Global option values ---"
+msgstr ""
+"\n"
+"--- Værdier for globale tilvalg ---"
+
+msgid ""
+"\n"
+"--- Local option values ---"
+msgstr ""
+"\n"
+"--- Værdier for lokale tilvalg ---"
+
+msgid ""
+"\n"
+"--- Options ---"
+msgstr ""
+"\n"
+"--- Tilvalg ---"
+
+msgid "E356: get_varp ERROR"
+msgstr "E356: Fejl ved get_varp"
+
+#, c-format
+msgid "E357: 'langmap': Matching character missing for %s"
+msgstr "E357: 'langmap': Matchende tegn mangler for %s"
+
+#, c-format
+msgid "E358: 'langmap': Extra characters after semicolon: %s"
+msgstr "E358: 'langmap': Ekstra tegn efter semikolon: %s"
+
+msgid "cannot open "
+msgstr "kan ikke åbne "
+
+msgid "VIM: Can't open window!\n"
+msgstr "VIM: Kan ikke åbne vindue!\n"
+
+msgid "Need Amigados version 2.04 or later\n"
+msgstr "Behøver Amigados version 2.04 eller senere\n"
+
+#, c-format
+msgid "Need %s version %ld\n"
+msgstr "Behøver %s version %ld\n"
+
+msgid "Cannot open NIL:\n"
+msgstr "Kan ikke åbne NIL:\n"
+
+msgid "Cannot create "
+msgstr "Kan ikke oprette "
+
+#, c-format
+msgid "Vim exiting with %d\n"
+msgstr "Vim afsluttede med %d\n"
+
+msgid "cannot change console mode ?!\n"
+msgstr "kan ikke skifte konsoltilstand ?!\n"
+
+msgid "mch_get_shellsize: not a console??\n"
+msgstr "mch_get_shellsize: ikke en konsol??\n"
+
+msgid "E360: Cannot execute shell with -f option"
+msgstr "E360: Kan ikke udføre skal med -f-tilvalget"
+
+msgid "Cannot execute "
+msgstr "Kan ikke udføre "
+
+msgid "shell "
+msgstr "skal "
+
+msgid " returned\n"
+msgstr " returnerede\n"
+
+msgid "ANCHOR_BUF_SIZE too small."
+msgstr "ANCHOR_BUF_SIZE for lille."
+
+msgid "I/O ERROR"
+msgstr "FEJL VED I/O"
+
+msgid "Message"
+msgstr "Meddelelse"
+
+msgid "E237: Printer selection failed"
+msgstr "E237: Valg af printer mislykkedes"
+
+#, c-format
+msgid "to %s on %s"
+msgstr "til %s på %s"
+
+#, c-format
+msgid "E613: Unknown printer font: %s"
+msgstr "E613: Ukendt skrifttype til printer: %s"
+
+#, c-format
+msgid "E238: Print error: %s"
+msgstr "E238: Fejl ved udskrivning: %s"
+
+#, c-format
+msgid "Printing '%s'"
+msgstr "Udskriver '%s'"
+
+#, c-format
+msgid "E244: Illegal charset name \"%s\" in font name \"%s\""
+msgstr "E244: Ulovligt tegnsætnavn \"%s\" i skrifttypenavnet \"%s\""
+
+#, c-format
+msgid "E244: Illegal quality name \"%s\" in font name \"%s\""
+msgstr "E244: Ulovligt kvalitetsnavn \"%s\" i skrifttypenavnet \"%s\""
+
+#, c-format
+msgid "E245: Illegal char '%c' in font name \"%s\""
+msgstr "E245: Ulovligt tegn '%c' i skrifttypenavnet \"%s\""
+
+#, c-format
+msgid "Opening the X display took %ld msec"
+msgstr "Ã…bningen af X-displayet tog %ld ms"
+
+msgid ""
+"\n"
+"Vim: Got X error\n"
+msgstr ""
+"\n"
+"Vim: Fik fejl ved X\n"
+
+msgid "Testing the X display failed"
+msgstr "Test af X-displayet mislykkedes"
+
+msgid "Opening the X display timed out"
+msgstr "Ã…bningen af X-displayet fik timeout"
+
+msgid ""
+"\n"
+"Could not get security context for "
+msgstr ""
+"\n"
+"Kunne ikke hente sikkerhedskontekst for "
+
+msgid ""
+"\n"
+"Could not set security context for "
+msgstr ""
+"\n"
+"Kunne ikke sætte sikkerhedskontekst for "
+
+#, c-format
+msgid "Could not set security context %s for %s"
+msgstr "Kunne ikke sætte sikkerhedskonteksten %s for %s"
+
+#, c-format
+msgid "Could not get security context %s for %s. Removing it!"
+msgstr "Kunne ikke hente sikkerhedskonteksten %s for %s. Fjerner den!"
+
+msgid ""
+"\n"
+"Cannot execute shell sh\n"
+msgstr ""
+"\n"
+"Kan ikke udføre skallen sh\n"
+
+msgid ""
+"\n"
+"shell returned "
+msgstr ""
+"\n"
+"skal returnerede "
+
+msgid ""
+"\n"
+"Cannot create pipes\n"
+msgstr ""
+"\n"
+"Kan ikke oprette pipes\n"
+
+msgid ""
+"\n"
+"Cannot fork\n"
+msgstr ""
+"\n"
+"Kan ikke fork\n"
+
+msgid ""
+"\n"
+"Cannot execute shell "
+msgstr ""
+"\n"
+"Kan ikke udføre skallen "
+
+msgid ""
+"\n"
+"Command terminated\n"
+msgstr ""
+"\n"
+"Kommando termineret\n"
+
+msgid "XSMP lost ICE connection"
+msgstr "XSMP mistede ICE-forbindelse"
+
+#, c-format
+msgid "dlerror = \"%s\""
+msgstr "dlerror = \"%s\""
+
+msgid "Opening the X display failed"
+msgstr "Ã…bningen af X-displayet mislykkedes"
+
+msgid "XSMP handling save-yourself request"
+msgstr "XSMP-håndtering save-yourself-anmodning"
+
+msgid "XSMP opening connection"
+msgstr "XSMP åbner forbindelse"
+
+msgid "XSMP ICE connection watch failed"
+msgstr "XSMP ICE-forbindelse watch mislykkedes"
+
+#, c-format
+msgid "XSMP SmcOpenConnection failed: %s"
+msgstr "XSMP SmcOpenConnection mislykkedes: %s"
+
+msgid "At line"
+msgstr "PÃ¥ linje"
+
+msgid "Could not load vim32.dll!"
+msgstr "Kunne ikke indlæse vim32.dll!"
+
+msgid "VIM Error"
+msgstr "Fejl ved VIM"
+
+msgid "Could not fix up function pointers to the DLL!"
+msgstr "Kunne ikke rette op på funktion-pointere til DLL'en!"
+
+#, c-format
+msgid "Vim: Caught %s event\n"
+msgstr "Vim: Fangede %s-hændelse\n"
+
+msgid "close"
+msgstr "luk"
+
+msgid "logoff"
+msgstr "log ud"
+
+msgid "shutdown"
+msgstr "luk ned"
+
+msgid "E371: Command not found"
+msgstr "E371: Kommando ikke fundet"
+
+msgid ""
+"VIMRUN.EXE not found in your $PATH.\n"
+"External commands will not pause after completion.\n"
+"See :help win32-vimrun for more information."
+msgstr ""
+"VIMRUN.EXE ikke fundet i din $PATH.\n"
+"Eksterne kommandoer sættes ikke på pause efter fuldførelse.\n"
+"Se :help win32-vimrun for mere information."
+
+msgid "Vim Warning"
+msgstr "Advarsel ved Vim"
+
+#, c-format
+msgid "shell returned %d"
+msgstr "skal returnerede %d"
+
+msgid "E926: Current location list was changed"
+msgstr "E926: Nuværende placeringsliste blev ændret"
+
+#, c-format
+msgid "E372: Too many %%%c in format string"
+msgstr "E372: For mange %%%c i formatet streng"
+
+#, c-format
+msgid "E373: Unexpected %%%c in format string"
+msgstr "E373: Uventet %%%c i formatet streng"
+
+msgid "E374: Missing ] in format string"
+msgstr "E374: Manglende ] i formatet streng"
+
+#, c-format
+msgid "E375: Unsupported %%%c in format string"
+msgstr "E375: Ikke-understøttet %%%c i formatet streng"
+
+#, c-format
+msgid "E376: Invalid %%%c in format string prefix"
+msgstr "E376: Ugyldig %%%c i præfiks for formatet streng"
+
+#, c-format
+msgid "E377: Invalid %%%c in format string"
+msgstr "E377: Ugyldig %%%c i formatet streng"
+
+msgid "E378: 'errorformat' contains no pattern"
+msgstr "E378: 'errorformat' indeholder ikke noget mønter"
+
+msgid "E379: Missing or empty directory name"
+msgstr "E379: Manglende eller tomt mappenavn"
+
+msgid "E553: No more items"
+msgstr "E553: Ikke flere punkter"
+
+msgid "E924: Current window was closed"
+msgstr "E924: Nuværende vindue blev lukket"
+
+msgid "E925: Current quickfix was changed"
+msgstr "E925: Nuværende quickfix blev ændret"
+
+#, c-format
+msgid "(%d of %d)%s%s: "
+msgstr "(%d af %d)%s%s: "
+
+msgid " (line deleted)"
+msgstr " (linje slettet)"
+
+#, c-format
+msgid "%serror list %d of %d; %d errors "
+msgstr "%sfejlliste %d af %d; %d fejl "
+
+msgid "E380: At bottom of quickfix stack"
+msgstr "E380: Nederst i quickfix-stakken"
+
+msgid "E381: At top of quickfix stack"
+msgstr "E381: Øverst i quickfix-stakken"
+
+msgid "No entries"
+msgstr "Ingen poster"
+
+msgid "Error file"
+msgstr "Fejlfil"
+
+msgid "E683: File name missing or invalid pattern"
+msgstr "E683: Filnavn mangler eller ugyldigt mønster"
+
+#, c-format
+msgid "Cannot open file \"%s\""
+msgstr "Kan ikke åbne filen \"%s\""
+
+msgid "E681: Buffer is not loaded"
+msgstr "E681: Buffer er ikke indlæst"
+
+msgid "E777: String or List expected"
+msgstr "E777: Streng eller liste ventet"
+
+#, c-format
+msgid "E369: invalid item in %s%%[]"
+msgstr "E369: ugyldigt punkt i %s%%[]"
+
+#, c-format
+msgid "E769: Missing ] after %s["
+msgstr "E769: Manglende ] efter %s["
+
+msgid "E944: Reverse range in character class"
+msgstr "E944: Baglæns område i tegnklasse"
+
+msgid "E945: Range too large in character class"
+msgstr "E945: Område for stort i tegnklasse"
+
+#, c-format
+msgid "E53: Unmatched %s%%("
+msgstr "E53: Ikke-matchet %s%%("
+
+#, c-format
+msgid "E54: Unmatched %s("
+msgstr "E54: Ikke-matchet %s("
+
+#, c-format
+msgid "E55: Unmatched %s)"
+msgstr "E55: Ikke-matchet %s)"
+
+msgid "E66: \\z( not allowed here"
+msgstr "E66: \\z( ikke tilladt her"
+
+msgid "E67: \\z1 - \\z9 not allowed here"
+msgstr "E67: \\z1 - \\z9 ikke tilladt her"
+
+#, c-format
+msgid "E69: Missing ] after %s%%["
+msgstr "E69: Manglende ] efter %s%%["
+
+#, c-format
+msgid "E70: Empty %s%%[]"
+msgstr "E70: Tom %s%%[]"
+
+msgid "E956: Cannot use pattern recursively"
+msgstr "E956: Kan ikke bruge mønster rekursivt"
+
+msgid "E65: Illegal back reference"
+msgstr "E65: Ulovlig tilbage-reference"
+
+msgid "E339: Pattern too long"
+msgstr "E339: Mønster for langt"
+
+msgid "E50: Too many \\z("
+msgstr "E50: For mange \\z("
+
+#, c-format
+msgid "E51: Too many %s("
+msgstr "E51: For mange %s("
+
+msgid "E52: Unmatched \\z("
+msgstr "E52: Ikke-matchet \\z("
+
+#, c-format
+msgid "E59: invalid character after %s@"
+msgstr "E59: ugyldigt tegn efter %s@"
+
+#, c-format
+msgid "E60: Too many complex %s{...}s"
+msgstr "E60: For mange komplekse %s{...}s"
+
+#, c-format
+msgid "E61: Nested %s*"
+msgstr "E61: Indlejret %s*"
+
+#, c-format
+msgid "E62: Nested %s%c"
+msgstr "E62: Indlejret %s%c"
+
+msgid "E63: invalid use of \\_"
+msgstr "E63: ugyldig brug af \\_"
+
+#, c-format
+msgid "E64: %s%c follows nothing"
+msgstr "E64: %s%c efterfølger intet"
+
+msgid "E68: Invalid character after \\z"
+msgstr "E68: Ugyldigt tegn efter \\z"
+
+#, c-format
+msgid "E678: Invalid character after %s%%[dxouU]"
+msgstr "E678: Ugyldigt tegn efter %s%%[dxouU]"
+
+#, c-format
+msgid "E71: Invalid character after %s%%"
+msgstr "E71: Ugyldigt tegn efter %s%%"
+
+#, c-format
+msgid "E554: Syntax error in %s{...}"
+msgstr "E554: Fejl ved syntaks i %s{...}"
+
+msgid "External submatches:\n"
+msgstr "Eksterne undermatch:\n"
+
+#, c-format
+msgid "E888: (NFA regexp) cannot repeat %s"
+msgstr "E888: (NFA regexp) kan ikke gentage %s"
+
+msgid ""
+"E864: \\%#= can only be followed by 0, 1, or 2. The automatic engine will be "
+"used "
+msgstr ""
+"E864: \\%#= må kun efterfølges af 0, 1 eller 2. Bruger den automatiske motor "
+
+msgid "Switching to backtracking RE engine for pattern: "
+msgstr "Skifter til backtracking RE-motor for mønster: "
+
+msgid "E865: (NFA) Regexp end encountered prematurely"
+msgstr "E865: (NFA) Mødte slutningen på regulært udtryk for tidligt"
+
+#, c-format
+msgid "E866: (NFA regexp) Misplaced %c"
+msgstr "E866: (NFA regexp) Forkert placeret %c"
+
+#, c-format
+msgid "E877: (NFA regexp) Invalid character class: %ld"
+msgstr "E877: (NFA regexp) Ugyldig tegnklasse: %ld"
+
+#, c-format
+msgid "E867: (NFA) Unknown operator '\\z%c'"
+msgstr "E867: (NFA) Ukendt operator '\\z%c'"
+
+msgid "E951: \\% value too large"
+msgstr "E951: \\%-værdi for stor"
+
+#, c-format
+msgid "E867: (NFA) Unknown operator '\\%%%c'"
+msgstr "E867: (NFA) Ukendt operator '\\%%%c'"
+
+msgid "E868: Error building NFA with equivalence class!"
+msgstr "E868: Fejl ved bygning af NFA med ligestillet klasse!"
+
+#, c-format
+msgid "E869: (NFA) Unknown operator '\\@%c'"
+msgstr "E869: (NFA) Ukendt operator '\\@%c'"
+
+msgid "E870: (NFA regexp) Error reading repetition limits"
+msgstr "E870: (NFA regexp) Fejl ved læsning af gentagelsesgrænser"
+
+msgid "E871: (NFA regexp) Can't have a multi follow a multi"
+msgstr "E871: (NFA regexp) En multi må ikke efterfølges af en multi"
+
+msgid "E872: (NFA regexp) Too many '('"
+msgstr "E872: (NFA regexp) For mange '('"
+
+msgid "E879: (NFA regexp) Too many \\z("
+msgstr "E879: (NFA regexp) For mange \\z("
+
+msgid "E873: (NFA regexp) proper termination error"
+msgstr "E873: (NFA regexp) fejl ved korrekt terminering"
+
+msgid "Could not open temporary log file for writing, displaying on stderr... "
+msgstr "Kunne ikke åbne midlertidig logfil til skrivning, viser på stderr... "
+
+msgid "E874: (NFA) Could not pop the stack!"
+msgstr "E874: (NFA) Kunne ikke pop'e stakken!"
+
+msgid ""
+"E875: (NFA regexp) (While converting from postfix to NFA), too many states "
+"left on stack"
+msgstr ""
+"E875: (NFA regexp) (Ved konvertering fra postfix til NFA), for mange "
+"tilstande tilbage på stak"
+
+msgid "E876: (NFA regexp) Not enough space to store the whole NFA "
+msgstr "E876: (NFA regexp) Ikke nok plads til at lagre hele NFA'en "
+
+msgid "E878: (NFA) Could not allocate memory for branch traversal!"
+msgstr "E878: (NFA) Kunne ikke allokere hukommelse til gennemgang af gren!"
+
+msgid " VREPLACE"
+msgstr " VERSTAT"
+
+msgid " REPLACE"
+msgstr " ERSTAT"
+
+msgid " REVERSE"
+msgstr " BAGLÆNS"
+
+msgid " INSERT"
+msgstr " INDSÆT"
+
+msgid " (insert)"
+msgstr " (indsæt)"
+
+msgid " (replace)"
+msgstr " (erstat)"
+
+msgid " (vreplace)"
+msgstr " (verstat)"
+
+msgid " Hebrew"
+msgstr " Hebraisk"
+
+msgid " Arabic"
+msgstr " Arabisk"
+
+msgid " (paste)"
+msgstr " (indsæt)"
+
+msgid " VISUAL"
+msgstr " VISUEL"
+
+msgid " VISUAL LINE"
+msgstr " VISUEL LINJE"
+
+msgid " VISUAL BLOCK"
+msgstr " VISUEL BLOK"
+
+msgid " SELECT"
+msgstr " VÆLG"
+
+msgid " SELECT LINE"
+msgstr " VÆLG LINJE"
+
+msgid " SELECT BLOCK"
+msgstr " VÆLG BLOK"
+
+msgid "recording"
+msgstr "optager"
+
+#, c-format
+msgid "E383: Invalid search string: %s"
+msgstr "E383: Ugyldig søgestreng: %s"
+
+#, c-format
+msgid "E384: search hit TOP without match for: %s"
+msgstr "E384: søgning ramte ØVERST uden match for: %s"
+
+#, c-format
+msgid "E385: search hit BOTTOM without match for: %s"
+msgstr "E385: søgning ramte NEDERST uden match for: %s"
+
+msgid "E386: Expected '?' or '/' after ';'"
+msgstr "E386: Ventede '?' eller '/' efter ';'"
+
+msgid " (includes previously listed match)"
+msgstr " (inkluderer tidligere oplistet match)"
+
+msgid "--- Included files "
+msgstr "--- Inkluderede filer "
+
+msgid "not found "
+msgstr "ikke fundet "
+
+msgid "in path ---\n"
+msgstr "i sti ---\n"
+
+msgid " (Already listed)"
+msgstr " (Allerede oplistet)"
+
+msgid " NOT FOUND"
+msgstr " IKKE FUNDET"
+
+#, c-format
+msgid "Scanning included file: %s"
+msgstr "Skanner inkluderede filer: %s"
+
+#, c-format
+msgid "Searching included file %s"
+msgstr "Søger efter inkluderede fil %s"
+
+msgid "E387: Match is on current line"
+msgstr "E387: Match er på nuværende linje"
+
+msgid "All included files were found"
+msgstr "Alle inkluderede filer blev fundet"
+
+msgid "No included files"
+msgstr "Ingen inkluderede filer"
+
+msgid "E388: Couldn't find definition"
+msgstr "E388: Kunne ikke finde definition"
+
+msgid "E389: Couldn't find pattern"
+msgstr "E389: Kunne ikke finde mønster"
+
+msgid "Substitute "
+msgstr "Erstatning "
+
+# scootergrisen: find ud af om "Søgemønster" skal være med stort eller lille
+#, c-format
+msgid ""
+"\n"
+"# Last %sSearch Pattern:\n"
+"~"
+msgstr ""
+"\n"
+"# Sidste %sSøgemønster:\n"
+"~"
+
+msgid "E756: Spell checking is not enabled"
+msgstr "E756: Stavekontrol er ikke aktiveret"
+
+#, c-format
+msgid "Warning: Cannot find word list \"%s_%s.spl\" or \"%s_ascii.spl\""
+msgstr ""
+"Advarsel: Kan ikke finde ordlisten \"%s_%s.spl\" eller \"%s_ascii.spl\""
+
+#, c-format
+msgid "Warning: Cannot find word list \"%s.%s.spl\" or \"%s.ascii.spl\""
+msgstr ""
+"Advarsel: Kan ikke finde ordlisten \"%s.%s.spl\" eller \"%s.ascii.spl\""
+
+msgid "E797: SpellFileMissing autocommand deleted buffer"
+msgstr "E797: SpellFileMissing-autokommando slettede buffer"
+
+#, c-format
+msgid "Warning: region %s not supported"
+msgstr "Advarsel: regionen %s understøttes ikke"
+
+msgid "Sorry, no suggestions"
+msgstr "Beklager, ingen forslag"
+
+#, c-format
+msgid "Sorry, only %ld suggestions"
+msgstr "Beklager, kun %ld forslag"
+
+#, c-format
+msgid "Change \"%.*s\" to:"
+msgstr "Ændr \"%.*s\" til:"
+
+#, c-format
+msgid " < \"%.*s\""
+msgstr " < \"%.*s\""
+
+msgid "E752: No previous spell replacement"
+msgstr "E752: Ingen tidligere staveerstatning"
+
+#, c-format
+msgid "E753: Not found: %s"
+msgstr "E753: Ikke fundet: %s"
+
+msgid "E758: Truncated spell file"
+msgstr "E758: Afkortet spell-fil"
+
+#, c-format
+msgid "Trailing text in %s line %d: %s"
+msgstr "Efterstillede tekst i %s linje %d: %s"
+
+#, c-format
+msgid "Affix name too long in %s line %d: %s"
+msgstr "Affix-navn for langt i %s linje %d: %s"
+
+msgid "E761: Format error in affix file FOL, LOW or UPP"
+msgstr "E761: Fejl i format i affix-filens FOL, LOW eller UPP"
+
+msgid "E762: Character in FOL, LOW or UPP is out of range"
+msgstr "E762: Tegn i FOL, LOW eller UPP er udenfor område"
+
+msgid "Compressing word tree..."
+msgstr "Komprimerer ordtræ..."
+
+#, c-format
+msgid "Reading spell file \"%s\""
+msgstr "Læser spell-filen \"%s\""
+
+msgid "E757: This does not look like a spell file"
+msgstr "E757: Det ligner ikke en spell-fil"
+
+msgid "E771: Old spell file, needs to be updated"
+msgstr "E771: Gammel spell-fil, som skal opdateres"
+
+msgid "E772: Spell file is for newer version of Vim"
+msgstr "E772: Spell-filen er til en nyere version af Vim"
+
+msgid "E770: Unsupported section in spell file"
+msgstr "E770: Ikke-understøttet sektion i spell-fil"
+
+#, c-format
+msgid "E778: This does not look like a .sug file: %s"
+msgstr "E778: ligner ikke en .sug-fil: %s"
+
+#, c-format
+msgid "E779: Old .sug file, needs to be updated: %s"
+msgstr "E779: Gammel .sug-fil, som skal opdateres: %s"
+
+#, c-format
+msgid "E780: .sug file is for newer version of Vim: %s"
+msgstr "E780: .sug-filen er til en nyere version af Vim: %s"
+
+#, c-format
+msgid "E781: .sug file doesn't match .spl file: %s"
+msgstr "E781: .sug-filen matcher ikke .spl-filen: %s"
+
+#, c-format
+msgid "E782: error while reading .sug file: %s"
+msgstr "E782: fejl ved læsning af .sug-fil: %s"
+
+#, c-format
+msgid "Reading affix file %s..."
+msgstr "Læser affix-filen %s..."
+
+#, c-format
+msgid "Conversion failure for word in %s line %d: %s"
+msgstr "Mislykkede konvertering for ordet %s linje %d: %s"
+
+#, c-format
+msgid "Conversion in %s not supported: from %s to %s"
+msgstr "Konvertering i %s understøttes ikke: fra %s til %s"
+
+#, c-format
+msgid "Conversion in %s not supported"
+msgstr "Konvertering i %s understøttes ikke"
+
+#, c-format
+msgid "Invalid value for FLAG in %s line %d: %s"
+msgstr "Ugyldig værdi for FLAG i %s linje %d: %s"
+
+#, c-format
+msgid "FLAG after using flags in %s line %d: %s"
+msgstr "FLAG efter brug af flag i %s linje %d: %s"
+
+#, c-format
+msgid ""
+"Defining COMPOUNDFORBIDFLAG after PFX item may give wrong results in %s line "
+"%d"
+msgstr ""
+"Definering af COMPOUNDFORBIDFLAG efter PFX-punkt kan give forkerte "
+"resultater i %s linje %d"
+
+#, c-format
+msgid ""
+"Defining COMPOUNDPERMITFLAG after PFX item may give wrong results in %s line "
+"%d"
+msgstr ""
+"Definering af COMPOUNDPERMITFLAG efter PFX-punkt kan give forkerte "
+"resultater i %s linje %d"
+
+#, c-format
+msgid "Wrong COMPOUNDRULES value in %s line %d: %s"
+msgstr "Forkert COMPOUNDRULES-værdi i %s linje %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDWORDMAX value in %s line %d: %s"
+msgstr "Forkert COMPOUNDWORDMAX-værdi i %s linje %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDMIN value in %s line %d: %s"
+msgstr "Forkert COMPOUNDMIN-værdi i %s linje %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDSYLMAX value in %s line %d: %s"
+msgstr "Forkert COMPOUNDSYLMAX-værdi i %s linje %d: %s"
+
+#, c-format
+msgid "Wrong CHECKCOMPOUNDPATTERN value in %s line %d: %s"
+msgstr "Forkert CHECKCOMPOUNDPATTERN-værdi i %s linje %d: %s"
+
+#, c-format
+msgid "Different combining flag in continued affix block in %s line %d: %s"
+msgstr "Forskellige kombineringsflag i fortsat affix-blok i %s linje %d: %s"
+
+#, c-format
+msgid "Duplicate affix in %s line %d: %s"
+msgstr "Duplikeret affix i %s linje %d: %s"
+
+#, c-format
+msgid ""
+"Affix also used for BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST in %s "
+"line %d: %s"
+msgstr ""
+"Affix også brugt for BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST i %s "
+"linje %d: %s"
+
+#, c-format
+msgid "Expected Y or N in %s line %d: %s"
+msgstr "Ventede Y eller N i %s linje %d: %s"
+
+#, c-format
+msgid "Broken condition in %s line %d: %s"
+msgstr "Ødelagt betingelse i %s linje %d: %s"
+
+#, c-format
+msgid "Expected REP(SAL) count in %s line %d"
+msgstr "Ventede REP(SAL)-tælling i %s linje %d"
+
+#, c-format
+msgid "Expected MAP count in %s line %d"
+msgstr "Ventede MAP-tælling i %s linje %d"
+
+#, c-format
+msgid "Duplicate character in MAP in %s line %d"
+msgstr "Duplikeret tegn i MAP i %s linje %d"
+
+#, c-format
+msgid "Unrecognized or duplicate item in %s line %d: %s"
+msgstr "Ikke-genkendt eller duplikeret punkt i %s linje %d: %s"
+
+#, c-format
+msgid "Missing FOL/LOW/UPP line in %s"
+msgstr "Manglende FOL-/LOW-/UPP-linje i %s"
+
+msgid "COMPOUNDSYLMAX used without SYLLABLE"
+msgstr "COMPOUNDSYLMAX brugt uden SYLLABLE"
+
+msgid "Too many postponed prefixes"
+msgstr "For mange udskudte præfikser"
+
+msgid "Too many compound flags"
+msgstr "For mange compound-flag"
+
+msgid "Too many postponed prefixes and/or compound flags"
+msgstr "For mange udskudte præfikser og/eller compound-flag"
+
+#, c-format
+msgid "Missing SOFO%s line in %s"
+msgstr "Manglende SOFO%s-linje i %s"
+
+#, c-format
+msgid "Both SAL and SOFO lines in %s"
+msgstr "BÃ¥de SAL- og SOFO-linjer i %s"
+
+#, c-format
+msgid "Flag is not a number in %s line %d: %s"
+msgstr "Flag er ikke et nummer i %s linje %d: %s"
+
+#, c-format
+msgid "Illegal flag in %s line %d: %s"
+msgstr "Ulovligt flag i %s linje %d: %s"
+
+#, c-format
+msgid "%s value differs from what is used in another .aff file"
+msgstr "%s-værdi er ikke den samme som bruges i en anden .aff-fil"
+
+#, c-format
+msgid "Reading dictionary file %s..."
+msgstr "Læser ordbogsfilen %s..."
+
+#, c-format
+msgid "E760: No word count in %s"
+msgstr "E760: Ingen ordtælling i %s"
+
+#, c-format
+msgid "line %6d, word %6ld - %s"
+msgstr "linje %6d, ord %6ld - %s"
+
+#, c-format
+msgid "Duplicate word in %s line %d: %s"
+msgstr "Duplikeret ord i %s linje %d: %s"
+
+#, c-format
+msgid "First duplicate word in %s line %d: %s"
+msgstr "Første duplikeret ord i %s linje %d: %s"
+
+#, c-format
+msgid "%d duplicate word(s) in %s"
+msgstr "%d duplikeret ord i %s"
+
+#, c-format
+msgid "Ignored %d word(s) with non-ASCII characters in %s"
+msgstr "Ignorerede %d ord med ikke-ASCII-tegn i %s"
+
+#, c-format
+msgid "Reading word file %s..."
+msgstr "Læser ordfilen %s..."
+
+#, c-format
+msgid "Duplicate /encoding= line ignored in %s line %d: %s"
+msgstr "Duplikeret /encoding=-linje ignoreret i %s linje %d: %s"
+
+#, c-format
+msgid "/encoding= line after word ignored in %s line %d: %s"
+msgstr "/encoding=-linje efter ord ignoreret i %s linje %d: %s"
+
+#, c-format
+msgid "Duplicate /regions= line ignored in %s line %d: %s"
+msgstr "Duplikerede /regions=-linjer ignoreret i %s linje %d: %s"
+
+#, c-format
+msgid "Too many regions in %s line %d: %s"
+msgstr "For mange regioner i %s linje %d: %s"
+
+#, c-format
+msgid "/ line ignored in %s line %d: %s"
+msgstr "/-linje ignoreret i %s linje %d: %s"
+
+#, c-format
+msgid "Invalid region nr in %s line %d: %s"
+msgstr "Ugyldigt regisionsnummer i %s linje %d: %s"
+
+#, c-format
+msgid "Unrecognized flags in %s line %d: %s"
+msgstr "Ugenkendte flag i %s linje %d: %s"
+
+#, c-format
+msgid "Ignored %d words with non-ASCII characters"
+msgstr "Ignorerer %d ord med ikke-ASCII-tegn"
+
+msgid "E845: Insufficient memory, word list will be incomplete"
+msgstr "E845: Ikke nok hukommelse, ordlisten vil være ufuldstændig"
+
+#, c-format
+msgid "Compressed %d of %d nodes; %d (%d%%) remaining"
+msgstr "Komprimerede %d af %d punkter; %d (%d%%) tilbage"
+
+msgid "Reading back spell file..."
+msgstr "Læser spell-fil tilbage..."
+
+msgid "Performing soundfolding..."
+msgstr "Udfører lydsammenfoldning..."
+
+#, c-format
+msgid "Number of words after soundfolding: %ld"
+msgstr "Antal ord efter lydsammenfoldning: %ld"
+
+#, c-format
+msgid "Total number of words: %d"
+msgstr "Samlet antal ord: %d"
+
+#, c-format
+msgid "Writing suggestion file %s..."
+msgstr "Skriver forslagsfilen %s..."
+
+#, c-format
+msgid "Estimated runtime memory use: %d bytes"
+msgstr "Anslået brug af afviklingshukommelse: %d byte"
+
+msgid "E751: Output file name must not have region name"
+msgstr "E751: Outputfilnavn må ikke have regionsnavn"
+
+#, c-format
+msgid "E754: Only up to %ld regions supported"
+msgstr "E754: Kun op til %ld regioner understøttes"
+
+#, c-format
+msgid "E755: Invalid region in %s"
+msgstr "E755: Ugyldig region i %s"
+
+msgid "Warning: both compounding and NOBREAK specified"
+msgstr "Advarsel: både compounding og NOBREAK angivet"
+
+#, c-format
+msgid "Writing spell file %s..."
+msgstr "Skriver spell-filen %s..."
+
+msgid "Done!"
+msgstr "Færdig!"
+
+#, c-format
+msgid "E765: 'spellfile' does not have %ld entries"
+msgstr "E765: 'spellfile' har ingen %ld-poster"
+
+#, c-format
+msgid "Word '%.*s' removed from %s"
+msgstr "Ordet '%.*s' fjernet fra %s"
+
+#, c-format
+msgid "Word '%.*s' added to %s"
+msgstr "Ordet '%.*s' tilføjet til %s"
+
+msgid "E763: Word characters differ between spell files"
+msgstr "E763: Ordtegn er ikke ens i spell-filer"
+
+msgid "E783: duplicate char in MAP entry"
+msgstr "E783: duplikeret tegn i MAP-post"
+
+msgid "No Syntax items defined for this buffer"
+msgstr "Ingen syntakspunkter defineret for denne buffer"
+
+msgid "syntax conceal on"
+msgstr "syntax conceal til"
+
+msgid "syntax conceal off"
+msgstr "syntax conceal fra"
+
+#, c-format
+msgid "E390: Illegal argument: %s"
+msgstr "E390: Ulovligt argument: %s"
+
+msgid "syntax case ignore"
+msgstr "syntax case ignore"
+
+msgid "syntax case match"
+msgstr "syntax case match"
+
+msgid "syntax spell toplevel"
+msgstr "syntax spell toplevel"
+
+msgid "syntax spell notoplevel"
+msgstr "syntax spell notoplevel"
+
+msgid "syntax spell default"
+msgstr "syntax spell default"
+
+msgid "syntax iskeyword "
+msgstr "syntax iskeyword "
+
+#, c-format
+msgid "E391: No such syntax cluster: %s"
+msgstr "E391: Ingen sådan syntaks-cluster: %s"
+
+msgid "syncing on C-style comments"
+msgstr "synkronisering på C-style-kommentarer"
+
+msgid "no syncing"
+msgstr "ingen synkronisering"
+
+msgid "syncing starts "
+msgstr "synkronisering starter "
+
+msgid " lines before top line"
+msgstr " linjer inden øverste linje"
+
+msgid ""
+"\n"
+"--- Syntax sync items ---"
+msgstr ""
+"\n"
+"--- Syntaks-synkroniseringspunkter ---"
+
+msgid ""
+"\n"
+"syncing on items"
+msgstr ""
+"\n"
+"synkroniserer på punkter"
+
+msgid ""
+"\n"
+"--- Syntax items ---"
+msgstr ""
+"\n"
+"--- Syntakspunkter ---"
+
+#, c-format
+msgid "E392: No such syntax cluster: %s"
+msgstr "E392: Ingen sådan syntaks-cluster: %s"
+
+msgid "minimal "
+msgstr "minimal "
+
+msgid "maximal "
+msgstr "maksimal "
+
+msgid "; match "
+msgstr "; match "
+
+msgid " line breaks"
+msgstr " linjeombrydninger"
+
+msgid "E395: contains argument not accepted here"
+msgstr "E395: indeholder argument som ikke accepteres her"
+
+msgid "E844: invalid cchar value"
+msgstr "E844: ugyldig cchar-værdi"
+
+msgid "E393: group[t]here not accepted here"
+msgstr "E393: group[t]here accepteres ikke her"
+
+#, c-format
+msgid "E394: Didn't find region item for %s"
+msgstr "E394: Find ikke regionspunkter for %s"
+
+msgid "E397: Filename required"
+msgstr "E397: Filnavn kræves"
+
+msgid "E847: Too many syntax includes"
+msgstr "E847: For mange syntaks inkluderinger"
+
+#, c-format
+msgid "E789: Missing ']': %s"
+msgstr "E789: Manglende ']': %s"
+
+#, c-format
+msgid "E890: trailing char after ']': %s]%s"
+msgstr "E890: efterstillede tegn efter ']': %s]%s"
+
+#, c-format
+msgid "E398: Missing '=': %s"
+msgstr "E398: Manglende '=': %s"
+
+#, c-format
+msgid "E399: Not enough arguments: syntax region %s"
+msgstr "E399: For mange argumenter: syntaks region %s"
+
+msgid "E848: Too many syntax clusters"
+msgstr "E848: For mange syntaks-clusters"
+
+msgid "E400: No cluster specified"
+msgstr "E400: Ingen cluster angivet"
+
+#, c-format
+msgid "E401: Pattern delimiter not found: %s"
+msgstr "E401: Mønsterafgrænser ikke fundet: %s"
+
+#, c-format
+msgid "E402: Garbage after pattern: %s"
+msgstr "E402: Affald efter mønster: %s"
+
+msgid "E403: syntax sync: line continuations pattern specified twice"
+msgstr ""
+"E403: syntaks synkronisering: linjefortsættelsesmønster angivet to gange"
+
+#, c-format
+msgid "E404: Illegal arguments: %s"
+msgstr "E404: Ulovlige argumenter: %s"
+
+#, c-format
+msgid "E405: Missing equal sign: %s"
+msgstr "E405: Manglende lighedstegn: %s"
+
+#, c-format
+msgid "E406: Empty argument: %s"
+msgstr "E406: Tomt argument: %s"
+
+#, c-format
+msgid "E407: %s not allowed here"
+msgstr "E407: %s ikke tilladt her"
+
+#, c-format
+msgid "E408: %s must be first in contains list"
+msgstr "E408: %s skal være først i contains-liste"
+
+#, c-format
+msgid "E409: Unknown group name: %s"
+msgstr "E409: Ukendt gruppenavn: %s"
+
+#, c-format
+msgid "E410: Invalid :syntax subcommand: %s"
+msgstr "E410: Ugyldig :syntax-underkommando: %s"
+
+msgid ""
+" TOTAL COUNT MATCH SLOWEST AVERAGE NAME PATTERN"
+msgstr ""
+" SAMLET ANTAL MATCH LANGSOMST GENNEMS. NAVN MØNSTER"
+
+msgid "E679: recursive loop loading syncolor.vim"
+msgstr "E679: rekursiv løkke ved indlæsning af syncolor.vim"
+
+#, c-format
+msgid "E411: highlight group not found: %s"
+msgstr "E411: fremhævningsgruppe ikke fundet: %s"
+
+#, c-format
+msgid "E412: Not enough arguments: \":highlight link %s\""
+msgstr "E412: Ikke nok argumenter: \":highlight link %s\""
+
+#, c-format
+msgid "E413: Too many arguments: \":highlight link %s\""
+msgstr "E413: For mange argumenter: \":highlight link %s\""
+
+msgid "E414: group has settings, highlight link ignored"
+msgstr "E414: gruppe har indstillinger, highlight link ignoreret"
+
+#, c-format
+msgid "E415: unexpected equal sign: %s"
+msgstr "E415: uventet lighedstegn: %s"
+
+#, c-format
+msgid "E416: missing equal sign: %s"
+msgstr "E416: manglende lighedstegn: %s"
+
+#, c-format
+msgid "E417: missing argument: %s"
+msgstr "E417: manglende argument: %s"
+
+#, c-format
+msgid "E418: Illegal value: %s"
+msgstr "E418: Ulovlig værdi: %s"
+
+msgid "E419: FG color unknown"
+msgstr "E419: Forgrundsfarve ukendt"
+
+msgid "E420: BG color unknown"
+msgstr "E420: Baggrundsfarve ukendt"
+
+#, c-format
+msgid "E421: Color name or number not recognized: %s"
+msgstr "E421: Farvenavn eller -nummer ikke genkendt: %s"
+
+#, c-format
+msgid "E422: terminal code too long: %s"
+msgstr "E422: terminalkode for lang: %s"
+
+#, c-format
+msgid "E423: Illegal argument: %s"
+msgstr "E423: Ulovligt argument: %s"
+
+msgid "E424: Too many different highlighting attributes in use"
+msgstr "E424: For mange forskellige fremhævningsattributter i brug"
+
+msgid "E669: Unprintable character in group name"
+msgstr "E669: Tegn som ikke kan udskrives i gruppenavn"
+
+msgid "W18: Invalid character in group name"
+msgstr "W18: Ugyldige tegn i gruppenavn"
+
+msgid "E849: Too many highlight and syntax groups"
+msgstr "E849: For mange fremhævnings- og syntaksgrupper"
+
+msgid "E555: at bottom of tag stack"
+msgstr "E555: nederst i tag-stak"
+
+msgid "E556: at top of tag stack"
+msgstr "E556: øverst i tag-stak"
+
+msgid "E425: Cannot go before first matching tag"
+msgstr "E425: Kan ikke gå efter første matchende tag"
+
+#, c-format
+msgid "E426: tag not found: %s"
+msgstr "E426: tag ikke fundet: %s"
+
+msgid " # pri kind tag"
+msgstr " # pri kind tag"
+
+msgid "file\n"
+msgstr "fil\n"
+
+msgid "E427: There is only one matching tag"
+msgstr "E427: Der er kun ét matchende tag"
+
+msgid "E428: Cannot go beyond last matching tag"
+msgstr "E428: Kan ikke gå efter sidste matchende tag"
+
+#, c-format
+msgid "File \"%s\" does not exist"
+msgstr "Filen \"%s\" findes ikke"
+
+#, c-format
+msgid "tag %d of %d%s"
+msgstr "tag %d af %d%s"
+
+msgid " or more"
+msgstr " eller flere"
+
+msgid " Using tag with different case!"
+msgstr " Bruger tag med anden versaltype!"
+
+#, c-format
+msgid "E429: File \"%s\" does not exist"
+msgstr "E429: Filen \"%s\" findes ikke"
+
+msgid ""
+"\n"
+" # TO tag FROM line in file/text"
+msgstr ""
+"\n"
+" # TIL tag FRA linje i fil/tekst"
+
+#, c-format
+msgid "Searching tags file %s"
+msgstr "Søger i tags-filen %s"
+
+#, c-format
+msgid "E430: Tag file path truncated for %s\n"
+msgstr "E430: Tag-filens sti afkortet for %s\n"
+
+msgid "Ignoring long line in tags file"
+msgstr "Ignorerer lang linje i tags-fil"
+
+#, c-format
+msgid "E431: Format error in tags file \"%s\""
+msgstr "E431: Fejl ved format i tags-filen \"%s\""
+
+#, c-format
+msgid "Before byte %ld"
+msgstr "Inden byte %ld"
+
+#, c-format
+msgid "E432: Tags file not sorted: %s"
+msgstr "E432: Tags-fil ikke sorteret: %s"
+
+msgid "E433: No tags file"
+msgstr "E433: Ingen tags-fil"
+
+msgid "E434: Can't find tag pattern"
+msgstr "E434: Kan ikke finde tag-mønster"
+
+msgid "E435: Couldn't find tag, just guessing!"
+msgstr "E435: Kunne ikke finde tag, gætter bare!"
+
+#, c-format
+msgid "Duplicate field name: %s"
+msgstr "Duplikeret feltnavn: %s"
+
+msgid "' not known. Available builtin terminals are:"
+msgstr "' ikke kendt. Tilgængelige indbyggede terminaler:"
+
+msgid "defaulting to '"
+msgstr "bruger standarden '"
+
+msgid "E557: Cannot open termcap file"
+msgstr "E557: Kan ikke åbne termcap-fil"
+
+msgid "E558: Terminal entry not found in terminfo"
+msgstr "E558: Terminal-post ikke fundet i terminfo"
+
+msgid "E559: Terminal entry not found in termcap"
+msgstr "E559: Terminal-post ikke fundet i termcap"
+
+#, c-format
+msgid "E436: No \"%s\" entry in termcap"
+msgstr "E436: Ingen \"%s\"-post i termcap"
+
+msgid "E437: terminal capability \"cm\" required"
+msgstr "E437: terminal-formåenheden \"cm\" kræves"
+
+msgid ""
+"\n"
+"--- Terminal keys ---"
+msgstr ""
+"\n"
+"--- Terminal-taster ---"
+
+msgid "Cannot open $VIMRUNTIME/rgb.txt"
+msgstr "Kan ikke åbne $VIMRUNTIME/rgb.txt"
+
+#, c-format
+msgid "Kill job in \"%s\"?"
+msgstr "Dræb job i \"%s\"?"
+
+msgid "Terminal"
+msgstr "Terminal"
+
+msgid "Terminal-finished"
+msgstr "Terminal-færdig"
+
+msgid "active"
+msgstr "aktiv"
+
+msgid "running"
+msgstr "køre"
+
+msgid "finished"
+msgstr "færdig"
+
+#, c-format
+msgid "E953: File exists: %s"
+msgstr "E953: Filen findes: %s"
+
+msgid "E955: Not a terminal buffer"
+msgstr "E955: Ikke en terminal-buffer"
+
+msgid "new shell started\n"
+msgstr "ny skal startet\n"
+
+msgid "Vim: Error reading input, exiting...\n"
+msgstr "Vim: Fejl ved læsning af input, afslutter...\n"
+
+msgid "Used CUT_BUFFER0 instead of empty selection"
+msgstr "Brugte CUT_BUFFER0 i stedet for tom markering"
+
+msgid "E881: Line count changed unexpectedly"
+msgstr "E881: Linjeantal ændret uventet"
+
+msgid "No undo possible; continue anyway"
+msgstr "Ingen fortryd mulig; fortsætter alligevel"
+
+#, c-format
+msgid "E828: Cannot open undo file for writing: %s"
+msgstr "E828: Kan ikke åbne fortrydelsesfil til skrivning: %s"
+
+#, c-format
+msgid "E825: Corrupted undo file (%s): %s"
+msgstr "E825: Korrupt fortrydelsesfil (%s): %s"
+
+msgid "Cannot write undo file in any directory in 'undodir'"
+msgstr "Kan ikke skrive fortrydelsesfil i nogen mappe i 'undodir'"
+
+#, c-format
+msgid "Will not overwrite with undo file, cannot read: %s"
+msgstr "Overskriver ikke med fortrydelsesfil, kan ikke læse: %s"
+
+#, c-format
+msgid "Will not overwrite, this is not an undo file: %s"
+msgstr "Overskriver ikke, det er ikke en fortrydelsesfil: %s"
+
+msgid "Skipping undo file write, nothing to undo"
+msgstr "Springer skrivning af fortrydelsesfil over, intet at fortryde"
+
+#, c-format
+msgid "Writing undo file: %s"
+msgstr "Skriver fortrydelsesfil: %s"
+
+#, c-format
+msgid "E829: write error in undo file: %s"
+msgstr "E829: fejl ved skrivning i fortrydelsesfil: %s"
+
+#, c-format
+msgid "Not reading undo file, owner differs: %s"
+msgstr "Læser ikke fortrydelsesfil, ejer er ikke den samme: %s"
+
+#, c-format
+msgid "Reading undo file: %s"
+msgstr "Læser fortrydelsesfil: %s"
+
+#, c-format
+msgid "E822: Cannot open undo file for reading: %s"
+msgstr "E822: Kan ikke åbne fortrydelsesfil til læsning: %s"
+
+#, c-format
+msgid "E823: Not an undo file: %s"
+msgstr "E823: Ikke en fortrydelsesfil: %s"
+
+#, c-format
+msgid "E832: Non-encrypted file has encrypted undo file: %s"
+msgstr "E832: Ikke-krypteret fil har krypteret fortrydelsesfil: %s"
+
+#, c-format
+msgid "E826: Undo file decryption failed: %s"
+msgstr "E826: Dekryptering af fortrydelsesfil mislykkedes: %s"
+
+#, c-format
+msgid "E827: Undo file is encrypted: %s"
+msgstr "E827: Fortrydelsesfilen er krypteret: %s"
+
+#, c-format
+msgid "E824: Incompatible undo file: %s"
+msgstr "E824: Inkompatibel fortrydelsesfil: %s"
+
+msgid "File contents changed, cannot use undo info"
+msgstr "Filindholdet ændret, kan ikke bruge fortrydelsesinfo"
+
+#, c-format
+msgid "Finished reading undo file %s"
+msgstr "Færdig med at læse fortrydelsesfilen %s"
+
+msgid "Already at oldest change"
+msgstr "Allerede ved ældste ændring"
+
+msgid "Already at newest change"
+msgstr "Allerede ved nyeste ændring"
+
+#, c-format
+msgid "E830: Undo number %ld not found"
+msgstr "E830: Fortrydelsesnummer %ld ikke fundet"
+
+msgid "E438: u_undo: line numbers wrong"
+msgstr "E438: u_undo: linjenumre forkerte"
+
+msgid "more line"
+msgstr "linje mere"
+
+msgid "more lines"
+msgstr "linjer mere"
+
+msgid "line less"
+msgstr "linje mindre"
+
+msgid "fewer lines"
+msgstr "linjere mindre"
+
+msgid "change"
+msgstr "ændring"
+
+msgid "changes"
+msgstr "ændringer"
+
+#, c-format
+msgid "%ld %s; %s #%ld %s"
+msgstr "%ld %s; %s #%ld %s"
+
+msgid "before"
+msgstr "inden"
+
+msgid "after"
+msgstr "efter"
+
+msgid "Nothing to undo"
+msgstr "Intet at fortryde"
+
+msgid "number changes when saved"
+msgstr "nummer ændrin. hvornår gemt"
+
+#, c-format
+msgid "%ld seconds ago"
+msgstr "%ld sekunder siden"
+
+msgid "E790: undojoin is not allowed after undo"
+msgstr "E790: undojoin ikke tilladt efter undo"
+
+msgid "E439: undo list corrupt"
+msgstr "E439: fortrydelsesliste korrupt"
+
+msgid "E440: undo line missing"
+msgstr "E440: fortrydelseslinje mangler"
+
+#, c-format
+msgid "E122: Function %s already exists, add ! to replace it"
+msgstr "E122: Funktionen %s findes allerede, tilføj ! for at erstatte den"
+
+msgid "E717: Dictionary entry already exists"
+msgstr "E717: Ordbog-post findes allerede"
+
+msgid "E718: Funcref required"
+msgstr "E718: Funcref kræves"
+
+#, c-format
+msgid "E130: Unknown function: %s"
+msgstr "E130: Ukendt funktion: %s"
+
+#, c-format
+msgid "E125: Illegal argument: %s"
+msgstr "E125: Ulovligt argument: %s"
+
+#, c-format
+msgid "E853: Duplicate argument name: %s"
+msgstr "E853: Duplikeret argumentnavn: %s"
+
+#, c-format
+msgid "E740: Too many arguments for function %s"
+msgstr "E740: For mange argumenter til funktionen %s"
+
+#, c-format
+msgid "E116: Invalid arguments for function %s"
+msgstr "E116: Ugyldige argumenter til funktionen %s"
+
+msgid "E132: Function call depth is higher than 'maxfuncdepth'"
+msgstr "E132: Dybden af funktionskald er større end 'maxfuncdepth'"
+
+#, c-format
+msgid "calling %s"
+msgstr "kalder %s"
+
+#, c-format
+msgid "%s aborted"
+msgstr "%s afbrudt"
+
+#, c-format
+msgid "%s returning #%ld"
+msgstr "%s returnerer #%ld"
+
+#, c-format
+msgid "%s returning %s"
+msgstr "%s returnerer %s"
+
+msgid "E699: Too many arguments"
+msgstr "E699: For mange argumenter"
+
+#, c-format
+msgid "E117: Unknown function: %s"
+msgstr "E117: Ukendt funktion: %s"
+
+#, c-format
+msgid "E933: Function was deleted: %s"
+msgstr "E933: Funktion blev slettet: %s"
+
+#, c-format
+msgid "E119: Not enough arguments for function: %s"
+msgstr "E119: Ikke nok argumenter til funktionen: %s"
+
+#, c-format
+msgid "E120: Using <SID> not in a script context: %s"
+msgstr "E120: Bruger <SID> ikke i et script kontekst: %s"
+
+#, c-format
+msgid "E725: Calling dict function without Dictionary: %s"
+msgstr "E725: Kalder dict-funktion uden ordbog: %s"
+
+msgid "E129: Function name required"
+msgstr "E129: Funktionsnavn kræves"
+
+#, c-format
+msgid "E128: Function name must start with a capital or \"s:\": %s"
+msgstr ""
+"E128: Funktionsnavnet skal begynde med et stort bogstav eller \"s:\": %s"
+
+#, c-format
+msgid "E884: Function name cannot contain a colon: %s"
+msgstr "E884: Funktionsnavnet må ikke indeholdet et kolon: %s"
+
+#, c-format
+msgid "E123: Undefined function: %s"
+msgstr "E123: Udefineret funktion: %s"
+
+#, c-format
+msgid "E124: Missing '(': %s"
+msgstr "E124: Manglende '(': %s"
+
+msgid "E862: Cannot use g: here"
+msgstr "E862: Kan ikke bruge g: her"
+
+#, c-format
+msgid "E932: Closure function should not be at top level: %s"
+msgstr "E932: Closure-funktion skal ikke være på topniveau: %s"
+
+msgid "E126: Missing :endfunction"
+msgstr "E126: Manglende :endfunction"
+
+#, c-format
+msgid "W22: Text found after :endfunction: %s"
+msgstr "W22: Tekst fundet efter :endfunction: %s"
+
+#, c-format
+msgid "E707: Function name conflicts with variable: %s"
+msgstr "E707: Funktionsnavnet er i konflikt med variablen: %s"
+
+#, c-format
+msgid "E127: Cannot redefine function %s: It is in use"
+msgstr "E127: Kan ikke redefinere funktionen %s: Den er i brug"
+
+#, c-format
+msgid "E746: Function name does not match script file name: %s"
+msgstr "E746: Funktionsnavn matcher ikke scriptfilnavn: %s"
+
+#, c-format
+msgid "E131: Cannot delete function %s: It is in use"
+msgstr "E131: Kan ikke slette funktionen %s: Den er i brug"
+
+msgid "E133: :return not inside a function"
+msgstr "E133: :return ikke i en funktion"
+
+#, c-format
+msgid "E107: Missing parentheses: %s"
+msgstr "E107: Manglende parenteser: %s"
+
+#, c-format
+msgid "%s (%s, compiled %s)"
+msgstr "%s (%s, kompileret %s)"
+
+msgid ""
+"\n"
+"MS-Windows 64-bit GUI version"
+msgstr ""
+"\n"
+"MS-Windows 64-bit GUI-version"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit GUI version"
+msgstr ""
+"\n"
+"MS-Windows 32-bit GUI-version"
+
+msgid " with OLE support"
+msgstr " med understøttelse af OLE"
+
+msgid ""
+"\n"
+"MS-Windows 64-bit console version"
+msgstr ""
+"\n"
+"MS-Windows 64-bit konsol-version"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit console version"
+msgstr ""
+"\n"
+"MS-Windows 32-bit konsol-version"
+
+msgid ""
+"\n"
+"macOS version"
+msgstr ""
+"\n"
+"macOS-version"
+
+msgid ""
+"\n"
+"macOS version w/o darwin feat."
+msgstr ""
+"\n"
+"macOS-version med/uden darwin-funktionalitet."
+
+msgid ""
+"\n"
+"OpenVMS version"
+msgstr ""
+"\n"
+"OpenVMS-version"
+
+msgid ""
+"\n"
+"Included patches: "
+msgstr ""
+"\n"
+"Rettelser som er med: "
+
+msgid ""
+"\n"
+"Extra patches: "
+msgstr ""
+"\n"
+"Ekstra rettelser: "
+
+msgid "Modified by "
+msgstr "Ændret af "
+
+msgid ""
+"\n"
+"Compiled "
+msgstr ""
+"\n"
+"Kompileret "
+
+msgid "by "
+msgstr "af "
+
+msgid ""
+"\n"
+"Huge version "
+msgstr ""
+"\n"
+"Huge-version "
+
+msgid ""
+"\n"
+"Big version "
+msgstr ""
+"\n"
+"Big-version "
+
+msgid ""
+"\n"
+"Normal version "
+msgstr ""
+"\n"
+"Normal-version "
+
+msgid ""
+"\n"
+"Small version "
+msgstr ""
+"\n"
+"Small-version "
+
+msgid ""
+"\n"
+"Tiny version "
+msgstr ""
+"\n"
+"Tiny-version "
+
+msgid "without GUI."
+msgstr "uden GUI."
+
+msgid "with GTK3 GUI."
+msgstr "med GTK3-GUI."
+
+msgid "with GTK2-GNOME GUI."
+msgstr "med GTK2-GNOME-GUI."
+
+msgid "with GTK2 GUI."
+msgstr "med GTK2-GUI."
+
+msgid "with X11-Motif GUI."
+msgstr "med X11-Motif-GUI."
+
+msgid "with X11-neXtaw GUI."
+msgstr "med X11-neXtaw-GUI."
+
+msgid "with X11-Athena GUI."
+msgstr "med X11-Athena-GUI."
+
+msgid "with Photon GUI."
+msgstr "med Photon-GUI."
+
+msgid "with GUI."
+msgstr "med GUI."
+
+msgid "with Carbon GUI."
+msgstr "med Carbon-GUI."
+
+msgid "with Cocoa GUI."
+msgstr "med Cocoa-GUI."
+
+msgid " Features included (+) or not (-):\n"
+msgstr " Funktionaliteter som er med (+) eller ikke (-):\n"
+
+msgid " system vimrc file: \""
+msgstr " system vimrc-fil: \""
+
+msgid " user vimrc file: \""
+msgstr " bruger vimrc-fil: \""
+
+msgid " 2nd user vimrc file: \""
+msgstr " 2. bruger vimrc-fil: \""
+
+msgid " 3rd user vimrc file: \""
+msgstr " 3. bruger vimrc-fil: \""
+
+msgid " user exrc file: \""
+msgstr " bruger exrc-fil: \""
+
+msgid " 2nd user exrc file: \""
+msgstr " 2. bruger exrc-fil: \""
+
+msgid " system gvimrc file: \""
+msgstr " system gvimrc-fil: \""
+
+msgid " user gvimrc file: \""
+msgstr " bruger gvimrc-fil: \""
+
+msgid "2nd user gvimrc file: \""
+msgstr "2. bruger gvimrc-fil: \""
+
+msgid "3rd user gvimrc file: \""
+msgstr "3. bruger gvimrc-fil: \""
+
+msgid " defaults file: \""
+msgstr " defaults-fil: \""
+
+msgid " system menu file: \""
+msgstr " system menu-fil: \""
+
+msgid " fall-back for $VIM: \""
+msgstr " fall-back for $VIM: \""
+
+msgid " f-b for $VIMRUNTIME: \""
+msgstr " f-b for $VIMRUNTIME: \""
+
+msgid "Compilation: "
+msgstr "Kompilering: "
+
+msgid "Compiler: "
+msgstr "Kompiler: "
+
+msgid "Linking: "
+msgstr "Linking: "
+
+msgid " DEBUG BUILD"
+msgstr " FEJLRETNINGSBYG"
+
+msgid "VIM - Vi IMproved"
+msgstr "VIM - Vi IMproved"
+
+msgid "version "
+msgstr "version "
+
+msgid "by Bram Moolenaar et al."
+msgstr "af Bram Moolenaar og andre"
+
+msgid "Vim is open source and freely distributable"
+msgstr "Vim er open source og kan frit distribueres"
+
+msgid "Help poor children in Uganda!"
+msgstr "Hjælp fattige børn i Uganda!"
+
+msgid "type :help iccf<Enter> for information "
+msgstr "skriv :help iccf<Enter> for information "
+
+msgid "type :q<Enter> to exit "
+msgstr "skriv :q<Enter> for at afslutte "
+
+msgid "type :help<Enter> or <F1> for on-line help"
+msgstr "skriv :help<Enter> eller <F1> for onlinehjælp "
+
+msgid "type :help version8<Enter> for version info"
+msgstr "skriv :help version8<Enter> for versionsinfo"
+
+msgid "Running in Vi compatible mode"
+msgstr "Kører i Vi-kompatibel tilstand"
+
+msgid "type :set nocp<Enter> for Vim defaults"
+msgstr "skriv :set nocp<Enter> for Vim-standarder"
+
+msgid "type :help cp-default<Enter> for info on this"
+msgstr "skriv :help cp-default<Enter> for info om det "
+
+msgid "menu Help->Orphans for information "
+msgstr "menu Hjælp->Forældreløse børnfor information "
+
+msgid "Running modeless, typed text is inserted"
+msgstr "Kører tilstandsløs, skrevet tekst indsættes"
+
+msgid "menu Edit->Global Settings->Toggle Insert Mode "
+msgstr "menu Rediger->Globale indstillinger->Indsæt-tilstand til/fra "
+
+msgid " for two modes "
+msgstr " for to-tilstande "
+
+msgid "menu Edit->Global Settings->Toggle Vi Compatible"
+msgstr "menu Rediger->Globale indstillinger->Vi-kompatibel til/fra"
+
+msgid " for Vim defaults "
+msgstr " for Vim-standarder "
+
+msgid "Sponsor Vim development!"
+msgstr "Sponsorer udviklingen af Vim!"
+
+msgid "Become a registered Vim user!"
+msgstr "Bliv en registreret Vim-bruger!"
+
+msgid "type :help sponsor<Enter> for information "
+msgstr "skriv :help sponsor<Enter> for information "
+
+msgid "type :help register<Enter> for information "
+msgstr "skriv :help register<Enter> for information "
+
+msgid "menu Help->Sponsor/Register for information "
+msgstr "menu Hjælp->Sponsorer/registrer for information "
+
+msgid "Already only one window"
+msgstr "Allerede kun ét vindue"
+
+msgid "E441: There is no preview window"
+msgstr "E441: Der er ikke noget forhåndsvisningsvindue"
+
+msgid "E442: Can't split topleft and botright at the same time"
+msgstr "E442: Kan ikke opdele øverste venstre og nederste højre på samme tid"
+
+msgid "E443: Cannot rotate when another window is split"
+msgstr "E443: Kan ikke rotere når et andet vindue er opdelt"
+
+msgid "E444: Cannot close last window"
+msgstr "E444: Kan ikke lukke sidste vindue"
+
+msgid "E813: Cannot close autocmd window"
+msgstr "E813: Kan ikke lukke autocmd-vindue"
+
+msgid "E814: Cannot close window, only autocmd window would remain"
+msgstr "E814: Kan ikke lukke vindue, kun autocmd-vindue ville være tilbage"
+
+msgid "E445: Other window contains changes"
+msgstr "E445: Et andet vindue indeholder ændringer"
+
+msgid "E446: No file name under cursor"
+msgstr "E446: Intet filnavn under markør"
+
+#, c-format
+msgid "E447: Can't find file \"%s\" in path"
+msgstr "E447: Kan ikke finde filen \"%s\" i sti"
+
+#, c-format
+msgid "E799: Invalid ID: %ld (must be greater than or equal to 1)"
+msgstr "E799: Ugyldigt ID: %ld (skal være større end eller lig med 1)"
+
+#, c-format
+msgid "E801: ID already taken: %ld"
+msgstr "E801: ID allerede taget: %ld"
+
+msgid "List or number required"
+msgstr "Liste eller nummer kræves"
+
+#, c-format
+msgid "E802: Invalid ID: %ld (must be greater than or equal to 1)"
+msgstr "E802: Ugyldigt ID: %ld (skal være større end eller lig med 1)"
+
+#, c-format
+msgid "E803: ID not found: %ld"
+msgstr "E803: ID ikke fundet: %ld"
+
+#, c-format
+msgid "E370: Could not load library %s"
+msgstr "E370: Kunne ikke indlæse biblioteket %s"
+
+msgid "Sorry, this command is disabled: the Perl library could not be loaded."
+msgstr ""
+"Beklager, kommandoen er deaktiveret: Perl-biblioteket kunne ikke indlæses."
+
+msgid "E299: Perl evaluation forbidden in sandbox without the Safe module"
+msgstr "E299: Perl-evaluering forbudt i sandbox uden Safe-modulet"
+
+msgid "Edit with &multiple Vims"
+msgstr "Rediger med &flere Vim'er"
+
+msgid "Edit with single &Vim"
+msgstr "Rediger med én &Vim"
+
+msgid "Diff with Vim"
+msgstr "Diff med Vim"
+
+msgid "Edit with &Vim"
+msgstr "Rediger med &Vim"
+
+msgid "Edit with existing Vim - "
+msgstr "Rediger med eksisterende Vim - "
+
+msgid "Edits the selected file(s) with Vim"
+msgstr "Redigerer den valgt fil(er) med Vim"
+
+msgid "Error creating process: Check if gvim is in your path!"
+msgstr "Fejl ved oprettelse af proces: Tjek om gvim er i din sti!"
+
+msgid "gvimext.dll error"
+msgstr "fejl ved gvimext.dll"
+
+msgid "Path length too long!"
+msgstr "Stiens længde er for lang!"
+
+msgid "--No lines in buffer--"
+msgstr "--Ingen linjer i buffer--"
+
+msgid "E470: Command aborted"
+msgstr "E470: Kommando afbrudt"
+
+msgid "E471: Argument required"
+msgstr "E471: Argument kræves"
+
+msgid "E10: \\ should be followed by /, ? or &"
+msgstr "E10: \\ skal efterføles af /, ? eller &"
+
+msgid "E11: Invalid in command-line window; <CR> executes, CTRL-C quits"
+msgstr "E11: Ugyldig i kommandolinjevindue; <CR> udfører, CTRL-C afslutter"
+
+msgid "E12: Command not allowed from exrc/vimrc in current dir or tag search"
+msgstr ""
+"E12: Kommando ikke tilladt fra exrc/vimrc i nuværende mappe- eller tagsøgning"
+
+msgid "E171: Missing :endif"
+msgstr "E171: Manglende :endif"
+
+msgid "E600: Missing :endtry"
+msgstr "E600: Manglende :endtry"
+
+msgid "E170: Missing :endwhile"
+msgstr "E170: Manglende :endwhile"
+
+msgid "E170: Missing :endfor"
+msgstr "E170: Manglende :endfor"
+
+msgid "E588: :endwhile without :while"
+msgstr "E588: :endwhile uden :while"
+
+msgid "E588: :endfor without :for"
+msgstr "E588: :endfor uden :for"
+
+msgid "E13: File exists (add ! to override)"
+msgstr "E13: Filen findes (tilføj ! for at tilsidesætte)"
+
+msgid "E472: Command failed"
+msgstr "E472: Kommando mislykkede"
+
+#, c-format
+msgid "E234: Unknown fontset: %s"
+msgstr "E234: Ukendt skrifttypesæt: %s"
+
+#, c-format
+msgid "E235: Unknown font: %s"
+msgstr "E235: Ukendt skrifttype: %s"
+
+#, c-format
+msgid "E236: Font \"%s\" is not fixed-width"
+msgstr "E236: Skrifttypen \"%s\" er ikke med fast bredde"
+
+msgid "E473: Internal error"
+msgstr "E473: Intern fejl"
+
+#, c-format
+msgid "E685: Internal error: %s"
+msgstr "E685: Intern fejl: %s"
+
+msgid "Interrupted"
+msgstr "Afbrudt"
+
+msgid "E14: Invalid address"
+msgstr "E14: Ugyldig adresse"
+
+msgid "E474: Invalid argument"
+msgstr "E474: Ugyldigt argument"
+
+#, c-format
+msgid "E475: Invalid argument: %s"
+msgstr "E475: Ugyldigt argument: %s"
+
+#, c-format
+msgid "E475: Invalid value for argument %s"
+msgstr "E475: Ugyldig værdi for argumentet %s"
+
+#, c-format
+msgid "E475: Invalid value for argument %s: %s"
+msgstr "E475: Ugyldig værdi for argumentet %s: %s"
+
+#, c-format
+msgid "E15: Invalid expression: %s"
+msgstr "E15: Ugyldigt udtryk: %s"
+
+msgid "E16: Invalid range"
+msgstr "E16: Ugyldigt område"
+
+msgid "E476: Invalid command"
+msgstr "E476: Ugyldig kommando"
+
+#, c-format
+msgid "E17: \"%s\" is a directory"
+msgstr "E17: \"%s\" er en mappe"
+
+#, c-format
+msgid "E364: Library call failed for \"%s()\""
+msgstr "E364: Kald af bibliotek mislykkedes for \"%s()\""
+
+msgid "E667: Fsync failed"
+msgstr "E667: Fsync mislykkedes"
+
+#, c-format
+msgid "E448: Could not load library function %s"
+msgstr "E448: Kunne ikke indlæse biblioteksfunktionen %s"
+
+msgid "E19: Mark has invalid line number"
+msgstr "E19: Mærke har ugyldigt linjenummer"
+
+msgid "E20: Mark not set"
+msgstr "E20: Mærke ikke sat"
+
+msgid "E21: Cannot make changes, 'modifiable' is off"
+msgstr "E21: Kan ikke foretage ændringer, 'modifiable' er slået fra"
+
+msgid "E22: Scripts nested too deep"
+msgstr "E22: Scripts indlejret for dybt"
+
+msgid "E23: No alternate file"
+msgstr "E23: Ingen alternate-fil"
+
+msgid "E24: No such abbreviation"
+msgstr "E24: Ingen sådan forkortelse"
+
+msgid "E477: No ! allowed"
+msgstr "E477: Ingen ! tilladt"
+
+msgid "E25: GUI cannot be used: Not enabled at compile time"
+msgstr "E25: GUI kan ikke bruges: Ikke aktiveret ved kompileringstid"
+
+msgid "E26: Hebrew cannot be used: Not enabled at compile time\n"
+msgstr "E26: Hebraisk kan ikke bruges: Ikke aktiveret ved kompileringstid\n"
+
+msgid "E27: Farsi cannot be used: Not enabled at compile time\n"
+msgstr "E27: Persisk kan ikke bruges: Ikke aktiveret ved kompileringstid\n"
+
+msgid "E800: Arabic cannot be used: Not enabled at compile time\n"
+msgstr "E800: Arabisk kan ikke bruges: Ikke aktiveret ved kompileringstid\n"
+
+#, c-format
+msgid "E28: No such highlight group name: %s"
+msgstr "E28: Intet sådan fremhævningsgruppenavn: %s"
+
+msgid "E29: No inserted text yet"
+msgstr "E29: Endnu ingen indsat tekst"
+
+msgid "E30: No previous command line"
+msgstr "E30: Ingen tidligere kommandolinje"
+
+msgid "E31: No such mapping"
+msgstr "E31: Ingen sådan mapping"
+
+msgid "E479: No match"
+msgstr "E479: Intet match"
+
+#, c-format
+msgid "E480: No match: %s"
+msgstr "E480: Intet match: %s"
+
+msgid "E32: No file name"
+msgstr "E32: Intet filnavn"
+
+msgid "E33: No previous substitute regular expression"
+msgstr "E33: Ingen tidligere erstatnings regulært udtryk"
+
+msgid "E34: No previous command"
+msgstr "E34: Ingen tidligere kommando"
+
+msgid "E35: No previous regular expression"
+msgstr "E35: Ingen tidligere regulære udtryk"
+
+msgid "E481: No range allowed"
+msgstr "E481: Intet område tilladt"
+
+msgid "E36: Not enough room"
+msgstr "E36: Ikke plads nok"
+
+#, c-format
+msgid "E247: no registered server named \"%s\""
+msgstr "E247: ingen registreret server ved navn \"%s\""
+
+#, c-format
+msgid "E482: Can't create file %s"
+msgstr "E482: Kan ikke oprette filen %s"
+
+msgid "E483: Can't get temp file name"
+msgstr "E483: Kan ikke hente midlertidigt filnavn"
+
+#, c-format
+msgid "E484: Can't open file %s"
+msgstr "E484: Kan ikke åbne filen %s"
+
+#, c-format
+msgid "E485: Can't read file %s"
+msgstr "E485: Kan ikke læse filen %s"
+
+msgid "E38: Null argument"
+msgstr "E38: Null-argument"
+
+msgid "E39: Number expected"
+msgstr "E39: Nummer ventet"
+
+#, c-format
+msgid "E40: Can't open errorfile %s"
+msgstr "E40: Kan ikke åbne fejlfilen %s"
+
+msgid "E233: cannot open display"
+msgstr "E233: kan ikke åbne display"
+
+msgid "E41: Out of memory!"
+msgstr "E41: Ikke mere ledig hukommelse!"
+
+msgid "Pattern not found"
+msgstr "Mønster ikke fundet"
+
+#, c-format
+msgid "E486: Pattern not found: %s"
+msgstr "E486: Mønster ikke fundet: %s"
+
+msgid "E487: Argument must be positive"
+msgstr "E487: Argument skal være positivt"
+
+msgid "E459: Cannot go back to previous directory"
+msgstr "E459: Kan ikke gå tilbage til tidligere mappe"
+
+msgid "E42: No Errors"
+msgstr "E42: Ingen fejl"
+
+msgid "E776: No location list"
+msgstr "E776: Ingen placeringsliste"
+
+msgid "E43: Damaged match string"
+msgstr "E43: Beskadiget matchstreng"
+
+msgid "E44: Corrupted regexp program"
+msgstr "E44: Korrupt regexp-program"
+
+msgid "E45: 'readonly' option is set (add ! to override)"
+msgstr "E45: 'readonly'-tilvalget er sat (tilføj ! for at tilsidesætte)"
+
+#, c-format
+msgid "E46: Cannot change read-only variable \"%s\""
+msgstr "E46: Kan ikke ændre skrivebeskyttet variabel \"%s\""
+
+#, c-format
+msgid "E794: Cannot set variable in the sandbox: \"%s\""
+msgstr "E794: Kan ikke sætte variabel i sandboksen: \"%s\""
+
+msgid "E713: Cannot use empty key for Dictionary"
+msgstr "E713: Kan ikke bruge tom nøgle til ordbog"
+
+msgid "E715: Dictionary required"
+msgstr "E715: Ordbog kræves"
+
+#, c-format
+msgid "E684: list index out of range: %ld"
+msgstr "E684: listeindeks udenfor område: %ld"
+
+#, c-format
+msgid "E118: Too many arguments for function: %s"
+msgstr "E118: For mange argumenter til funktion: %s"
+
+#, c-format
+msgid "E716: Key not present in Dictionary: %s"
+msgstr "E716: Nøgle findes ikke i ordbog: %s"
+
+msgid "E714: List required"
+msgstr "E714: Liste kræves"
+
+#, c-format
+msgid "E712: Argument of %s must be a List or Dictionary"
+msgstr "E712: Argument af %s skal være en liste eller ordbog"
+
+msgid "E47: Error while reading errorfile"
+msgstr "E47: Fejl ved læsning af fejlfil"
+
+msgid "E48: Not allowed in sandbox"
+msgstr "E48: Ikke tilladt i sandboks"
+
+msgid "E523: Not allowed here"
+msgstr "E523: Ikke tilladt her"
+
+msgid "E359: Screen mode setting not supported"
+msgstr "E359: Skærmtilstand-indstilling understøttes ikke"
+
+msgid "E49: Invalid scroll size"
+msgstr "E49: Ugyldig rullestørrelse"
+
+msgid "E91: 'shell' option is empty"
+msgstr "E91: 'shell'-tilvalget er tomt"
+
+msgid "E255: Couldn't read in sign data!"
+msgstr "E255: Kunne ikke læse i sign-data!"
+
+msgid "E72: Close error on swap file"
+msgstr "E72: Fejl ved lukning af swap-fil"
+
+msgid "E73: tag stack empty"
+msgstr "E73: tag-stak tom"
+
+msgid "E74: Command too complex"
+msgstr "E74: Kommando for kompleks"
+
+msgid "E75: Name too long"
+msgstr "E75: Navn for langt"
+
+msgid "E76: Too many ["
+msgstr "E76: For mange ["
+
+msgid "E77: Too many file names"
+msgstr "E77: For mange filnavne"
+
+msgid "E488: Trailing characters"
+msgstr "E488: Efterstillede tegn"
+
+msgid "E78: Unknown mark"
+msgstr "E78: Ukendt mærke"
+
+msgid "E79: Cannot expand wildcards"
+msgstr "E79: Kan ikke udvide jokertegn"
+
+msgid "E591: 'winheight' cannot be smaller than 'winminheight'"
+msgstr "E591: 'winheight' må ikke være mindre end 'winminheight'"
+
+msgid "E592: 'winwidth' cannot be smaller than 'winminwidth'"
+msgstr "E592: 'winwidth' må ikke være mindre end 'winminwidth'"
+
+msgid "E80: Error while writing"
+msgstr "E80: Fejl ved skrivning"
+
+msgid "E939: Positive count required"
+msgstr "E939: Positiv tælling kræves"
+
+msgid "E81: Using <SID> not in a script context"
+msgstr "E81: Bruger <SID> ikke i et script kontekst"
+
+msgid "E449: Invalid expression received"
+msgstr "E449: Ugyldigt udtryk modtaget"
+
+msgid "E463: Region is guarded, cannot modify"
+msgstr "E463: Regionen er beskyttet, kan ikke ændre"
+
+msgid "E744: NetBeans does not allow changes in read-only files"
+msgstr "E744: NetBeans tillader ikke ændringer i skrivebeskyttede filer"
+
+msgid "E363: pattern uses more memory than 'maxmempattern'"
+msgstr "E363: mønster bruger mere hukommelse end 'maxmempattern'"
+
+msgid "E749: empty buffer"
+msgstr "E749: tom buffer"
+
+#, c-format
+msgid "E86: Buffer %ld does not exist"
+msgstr "E86: Bufferen %ld findes ikke"
+
+msgid "E682: Invalid search pattern or delimiter"
+msgstr "E682: Ugyldigt søgemønster eller -afgrænser"
+
+msgid "E139: File is loaded in another buffer"
+msgstr "E139: Filen er indlæst i en anden buffer"
+
+#, c-format
+msgid "E764: Option '%s' is not set"
+msgstr "E764: Tilvalget '%s' er ikke sat"
+
+msgid "E850: Invalid register name"
+msgstr "E850: Ugyldigt registernavn"
+
+#, c-format
+msgid "E919: Directory not found in '%s': \"%s\""
+msgstr "E919: Mappe ikke fundet i '%s': \"%s\""
+
+msgid "E952: Autocommand caused recursive behavior"
+msgstr "E952: Autokommando forårsagede rekursiv opførsel"
+
+msgid "search hit TOP, continuing at BOTTOM"
+msgstr "søgning ramte ØVERST, fortsætter ved NEDERST"
+
+msgid "search hit BOTTOM, continuing at TOP"
+msgstr "søgning ramte NEDERST, fortsætter ved ØVERST"
+
+#, c-format
+msgid "Need encryption key for \"%s\""
+msgstr "Behøver krypteringsnøgle til \"%s\""
+
+msgid "empty keys are not allowed"
+msgstr "tomme nøgler er ikke tilladt"
+
+msgid "dictionary is locked"
+msgstr "ordbog er låst"
+
+msgid "list is locked"
+msgstr "liste er låst"
+
+#, c-format
+msgid "failed to add key '%s' to dictionary"
+msgstr "kunne ikke tilføje nøglen '%s' til ordbog"
+
+#, c-format
+msgid "index must be int or slice, not %s"
+msgstr "indeks skal være heltal eller slice, ikke %s"
+
+#, c-format
+msgid "expected str() or unicode() instance, but got %s"
+msgstr "ventede str()- eller unicode()-instans, men fik %s"
+
+#, c-format
+msgid "expected bytes() or str() instance, but got %s"
+msgstr "ventede bytes()- eller str()-instans, min fik %s"
+
+#, c-format
+msgid ""
+"expected int(), long() or something supporting coercing to long(), but got %s"
+msgstr ""
+"ventede int(), long() eller noget som understøtter coercing til long(), min "
+"fik %s"
+
+#, c-format
+msgid "expected int() or something supporting coercing to int(), but got %s"
+msgstr ""
+"ventede int() eller noget som understøtter coercing til int(), min fik %s"
+
+msgid "value is too large to fit into C int type"
+msgstr "værdi er for stor til at passe i C-heltalstype"
+
+msgid "value is too small to fit into C int type"
+msgstr "værdi er for lille til at passe i C-heltalstype"
+
+msgid "number must be greater than zero"
+msgstr "nummer skal være større end nul"
+
+msgid "number must be greater or equal to zero"
+msgstr "nummer skal være større end eller lig med nul"
+
+msgid "can't delete OutputObject attributes"
+msgstr "kan ikke slette OutputObject-attributter"
+
+#, c-format
+msgid "invalid attribute: %s"
+msgstr "ugyldig attribut: %s"
+
+msgid "E264: Python: Error initialising I/O objects"
+msgstr "E264: Python: Fejl ved initialisering af I/O-objekter"
+
+msgid "failed to change directory"
+msgstr "kunne ikke skifte mappe"
+
+#, c-format
+msgid "expected 3-tuple as imp.find_module() result, but got %s"
+msgstr "ventede 3-tuple som imp.find_module() resultat, men fik %s"
+
+#, c-format
+msgid "expected 3-tuple as imp.find_module() result, but got tuple of size %d"
+msgstr ""
+"ventede 3-tuple som imp.find_module() resultat, men fik tuple af størrelse %d"
+
+msgid "internal error: imp.find_module returned tuple with NULL"
+msgstr "intern fejl: imp.find_module returnerede tuple med NULL"
+
+msgid "cannot delete vim.Dictionary attributes"
+msgstr "kan ikke slette vim.Dictionary-attributter"
+
+msgid "cannot modify fixed dictionary"
+msgstr "kan ikke ændre fast ordbog"
+
+#, c-format
+msgid "cannot set attribute %s"
+msgstr "kan ikke sætte attributten %s"
+
+msgid "hashtab changed during iteration"
+msgstr "hashtab ændret under gennemløb"
+
+#, c-format
+msgid "expected sequence element of size 2, but got sequence of size %d"
+msgstr "ventede sekvenselement af størrelse 2, men fik sekvens af størrelse %d"
+
+msgid "list constructor does not accept keyword arguments"
+msgstr "liste-constructor accepterer ikke nøgleord-argumenter"
+
+msgid "list index out of range"
+msgstr "listeindeks udenfor område"
+
+#, c-format
+msgid "internal error: failed to get vim list item %d"
+msgstr "intern fejl: kunne ikke hente vim-listepunkt %d"
+
+msgid "slice step cannot be zero"
+msgstr "slice-trin må ikke være nul"
+
+#, c-format
+msgid "attempt to assign sequence of size greater than %d to extended slice"
+msgstr "forsøg på at tildele sekvens som er større end %d til udvidet slice"
+
+#, c-format
+msgid "internal error: no vim list item %d"
+msgstr "intern fejl: intet vim-listepunkt %d"
+
+msgid "internal error: not enough list items"
+msgstr "intern fejl: ikke nok listepunkter"
+
+msgid "internal error: failed to add item to list"
+msgstr "intern fejl: kunne ikke tilføje punkt til liste"
+
+#, c-format
+msgid "attempt to assign sequence of size %d to extended slice of size %d"
+msgstr ""
+"forsøg på at tildele sekvens af størrelsen %d til udvidet slice af "
+"størrelsen %d"
+
+msgid "failed to add item to list"
+msgstr "kunne ikke tilføje punkt til liste"
+
+msgid "cannot delete vim.List attributes"
+msgstr "kan ikke slette vim.List-attributter"
+
+msgid "cannot modify fixed list"
+msgstr "kan ikke ændre fast liste"
+
+#, c-format
+msgid "unnamed function %s does not exist"
+msgstr "unavngivet funktion %s findes ikke"
+
+#, c-format
+msgid "function %s does not exist"
+msgstr "funktionen %s findes ikke"
+
+#, c-format
+msgid "failed to run function %s"
+msgstr "kunne ikke køre funktionen %s"
+
+msgid "unable to get option value"
+msgstr "kan ikke hente tilvalgsværdi"
+
+msgid "internal error: unknown option type"
+msgstr "intern fejl: ukendt tilvalgstype"
+
+msgid "problem while switching windows"
+msgstr "problem ved skift af vinduer"
+
+#, c-format
+msgid "unable to unset global option %s"
+msgstr "kan ikke fjerne det globale tilvalg %s"
+
+#, c-format
+msgid "unable to unset option %s which does not have global value"
+msgstr "kan ikke fjerne tilvalget %s som ikke har global værdi"
+
+msgid "attempt to refer to deleted tab page"
+msgstr "forsøg på at referere til slettet fanebladsside"
+
+msgid "no such tab page"
+msgstr "ingen sådan fanebladsside"
+
+msgid "attempt to refer to deleted window"
+msgstr "forsøg på at referere til slettet vindue"
+
+msgid "readonly attribute: buffer"
+msgstr "skrivebeskyttet attribut: buffer"
+
+msgid "cursor position outside buffer"
+msgstr "markørposition udenfor buffer"
+
+msgid "no such window"
+msgstr "intet sådan vindue"
+
+msgid "attempt to refer to deleted buffer"
+msgstr "forsøg på at referere til slettet buffer"
+
+msgid "failed to rename buffer"
+msgstr "kunne ikke omdøbe bufferen"
+
+msgid "mark name must be a single character"
+msgstr "mærkenavn skal være ét tegn"
+
+#, c-format
+msgid "expected vim.Buffer object, but got %s"
+msgstr "ventede vim.Buffer-objekt, men fik %s"
+
+#, c-format
+msgid "failed to switch to buffer %d"
+msgstr "kunne ikke skifte til bufferen %d"
+
+#, c-format
+msgid "expected vim.Window object, but got %s"
+msgstr "ventede vim.Window-objekt, men fik %s"
+
+msgid "failed to find window in the current tab page"
+msgstr "kunne ikke finde vindue i den nuværende fanebladsside"
+
+msgid "did not switch to the specified window"
+msgstr "skiftede ikke til det angivne vindue"
+
+#, c-format
+msgid "expected vim.TabPage object, but got %s"
+msgstr "ventede vim.TabPage-objekt, men fik %s"
+
+msgid "did not switch to the specified tab page"
+msgstr "skiftede ikke til den angivne fanebladsside"
+
+msgid "failed to run the code"
+msgstr "kunne ikke køre koden"
+
+msgid "E858: Eval did not return a valid python object"
+msgstr "E858: Eval returnerede ikke et gyldigt python-objekt"
+
+msgid "E859: Failed to convert returned python object to vim value"
+msgstr "E859: Kunne ikke konvertere returnerede python-objekt til vim-værdi"
+
+#, c-format
+msgid "unable to convert %s to vim dictionary"
+msgstr "kan ikke konvertere %s til vim-ordbog"
+
+#, c-format
+msgid "unable to convert %s to vim list"
+msgstr "kan ikke konvertere %s til vim-liste"
+
+#, c-format
+msgid "unable to convert %s to vim structure"
+msgstr "kan ikke konvertere %s til vim-struktur"
+
+msgid "internal error: NULL reference passed"
+msgstr "intern fejl: NULL-reference givet"
+
+msgid "internal error: invalid value type"
+msgstr "intern fejl: ugyldig værditype"
+
+msgid ""
+"Failed to set path hook: sys.path_hooks is not a list\n"
+"You should now do the following:\n"
+"- append vim.path_hook to sys.path_hooks\n"
+"- append vim.VIM_SPECIAL_PATH to sys.path\n"
+msgstr ""
+"Kunne ikke sætte sti-hook: sys.path_hooks er ikke en liste\n"
+"Du bør nu gøre følgende:\n"
+"- tilføj vim.path_hook til slutningen af sys.path_hooks\n"
+"- tilføj vim.VIM_SPECIAL_PATH til slutningen af sys.path\n"
+
+msgid ""
+"Failed to set path: sys.path is not a list\n"
+"You should now append vim.VIM_SPECIAL_PATH to sys.path"
+msgstr ""
+"Kunne ikke sætte sti: sys.path er ikke en liste\n"
+"Du bør nu tilføje vim.VIM_SPECIAL_PATH til slutningen af sys.path"
+
+msgid ""
+"Vim macro files (*.vim)\t*.vim\n"
+"All Files (*.*)\t*.*\n"
+msgstr ""
+"Vim-makrofiler (*.vim)\t*.vim\n"
+"Alle filer (*.*)\t*.*\n"
+
+msgid "All Files (*.*)\t*.*\n"
+msgstr "Alle filer (*.*)\t*.*\n"
+
+msgid ""
+"All Files (*.*)\t*.*\n"
+"C source (*.c, *.h)\t*.c;*.h\n"
+"C++ source (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"VB code (*.bas, *.frm)\t*.bas;*.frm\n"
+"Vim files (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
+msgstr ""
+"Alle filer (*.*)\t*.*\n"
+"C-kildekode (*.c, *.h)\t*.c;*.h\n"
+"C++-kildekode (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"VB-kode (*.bas, *.frm)\t*.bas;*.frm\n"
+"Vim-filer (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
+
+msgid ""
+"Vim macro files (*.vim)\t*.vim\n"
+"All Files (*)\t*\n"
+msgstr ""
+"Vim-makrofiler (*.vim)\t*.vim\n"
+"Alle filer (*)\t*\n"
+
+msgid "All Files (*)\t*\n"
+msgstr "Alle filer (*)\t*\n"
+
+msgid ""
+"All Files (*)\t*\n"
+"C source (*.c, *.h)\t*.c;*.h\n"
+"C++ source (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"Vim files (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
+msgstr ""
+"Alle filer (*)\t*\n"
+"C-kildekode (*.c, *.h)\t*.c;*.h\n"
+"C++-kildekode (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"Vim-filer (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
diff --git a/src/po/de.po b/src/po/de.po
new file mode 100644
index 0000000..a2eb9d4
--- /dev/null
+++ b/src/po/de.po
@@ -0,0 +1,7381 @@
+# German translation for Vim
+#
+# Do ":help uganda" in Vim to read copying and usage conditions.
+# Do ":help credits" in Vim to see a list of people who contributed.
+#
+# Previous-Translator(s):
+# Georg Dahn <georg.dahn@gmail.com>
+# Johannes Zellner <johannes@zellner.org>
+# Gerfried Fuchs <alfie@ist.org>
+msgid ""
+msgstr ""
+"Project-Id-Version: Vim\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2019-01-28 19:23+0100\n"
+"PO-Revision-Date: 2008-05-24 17:26+0200\n"
+"Last-Translator: Christian Brabandt <cb@256bit.org>\n"
+"Language-Team: German\n"
+"Language: de\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-1\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+msgid "--Deleted--"
+msgstr "--gelöscht--"
+
+#, c-format
+msgid "auto-removing autocommand: %s <buffer=%d>"
+msgstr "Entferne Autokommando: %s <buffer=%d>"
+
+#, c-format
+msgid "E367: No such group: \"%s\""
+msgstr "E367: Keine solche Gruppe: \"%s\""
+
+msgid "E936: Cannot delete the current group"
+msgstr "E936: Kann die aktuelle Gruppe nicht löschen."
+
+msgid "W19: Deleting augroup that is still in use"
+msgstr "W19: Lösche Autogruppe, die noch in Benutzung ist."
+
+#, c-format
+msgid "E215: Illegal character after *: %s"
+msgstr "E215: Unzulässiges Zeichen nach *: %s"
+
+#, c-format
+msgid "E216: No such event: %s"
+msgstr "E216: Kein derartiges Ereignis: %s"
+
+#, c-format
+msgid "E216: No such group or event: %s"
+msgstr "E216: Keine solche Gruppe oder Ereignis: %s"
+
+msgid ""
+"\n"
+"--- Autocommands ---"
+msgstr ""
+"\n"
+"--- Autokommandos ---"
+
+#, c-format
+msgid "E680: <buffer=%d>: invalid buffer number "
+msgstr "E680: <buffer=%d>: Ungültige Puffer Nummer "
+
+msgid "E217: Can't execute autocommands for ALL events"
+msgstr "E217: Autokommandos können nicht für ALL Ereignisse ausgeführt werden"
+
+msgid "No matching autocommands"
+msgstr "Keine passenden Autokommandos"
+
+msgid "E218: autocommand nesting too deep"
+msgstr "E218: Autokommando-Schachtelung zu tief"
+
+#, c-format
+msgid "%s Autocommands for \"%s\""
+msgstr "%s Autokommandos für \"%s\""
+
+#, c-format
+msgid "Executing %s"
+msgstr "Ausführung von %s"
+
+#, c-format
+msgid "autocommand %s"
+msgstr "Autokommando %s"
+
+msgid "E831: bf_key_init() called with empty password"
+msgstr "E831: bf_key_init() mit leerem Passwort aufgerufen."
+
+msgid "E820: sizeof(uint32_t) != 4"
+msgstr "E820: sizeof(uint32_t) ungleich 4."
+
+msgid "E817: Blowfish big/little endian use wrong"
+msgstr "E817: Blowfish Big-/Little-Endian falsch."
+
+msgid "E818: sha256 test failed"
+msgstr "E818: Test sha256 fehlgeschlagen"
+
+msgid "E819: Blowfish test failed"
+msgstr "E819: Blowfish Test fehlgeschlagen"
+
+msgid "[Location List]"
+msgstr "[Positionsliste]"
+
+msgid "[Quickfix List]"
+msgstr "[Quickfix-Liste]"
+
+msgid "E855: Autocommands caused command to abort"
+msgstr "E855: Autokommandos führten zu einem Abbruch."
+
+msgid "E82: Cannot allocate any buffer, exiting..."
+msgstr "E82: Kann keinen Puffer zuweisen; beende..."
+
+msgid "E83: Cannot allocate buffer, using other one..."
+msgstr "E83: Kann den Puffer nicht zuweisen; benutze einen anderen..."
+
+msgid "E931: Buffer cannot be registered"
+msgstr "E931: Puffer kann nicht registriert werden."
+
+msgid "E937: Attempt to delete a buffer that is in use"
+msgstr "E937: Versuch, Puffer zu löschen, der noch benutzt wird."
+
+msgid "E515: No buffers were unloaded"
+msgstr "E515: Kein Puffer wurde entladen."
+
+msgid "E516: No buffers were deleted"
+msgstr "E516: Kein Puffer wurde gelöscht."
+
+msgid "E517: No buffers were wiped out"
+msgstr "E517: Kein Puffer wurde vollständig gelöscht."
+
+#, c-format
+msgid "%d buffer unloaded"
+msgid_plural "%d buffers unloaded"
+msgstr[0] "%d Puffer entladen"
+msgstr[1] "%d Puffer entladen"
+
+#, c-format
+msgid "%d buffer deleted"
+msgid_plural "%d buffers deleted"
+msgstr[0] "%d Puffer gelöscht"
+msgstr[1] "%d Puffer gelöscht"
+
+#, c-format
+msgid "%d buffer wiped out"
+msgid_plural "%d buffers wiped out"
+msgstr[0] "%d Puffer vollständig gelöscht"
+msgstr[1] "%d Puffer vollständig gelöscht"
+
+msgid "E90: Cannot unload last buffer"
+msgstr "E90: Kann letzten Puffer nicht entladen"
+
+msgid "E84: No modified buffer found"
+msgstr "E84: Keinen veränderter Puffer gefunden"
+
+msgid "E85: There is no listed buffer"
+msgstr "E85: Es gibt keine angezeigten Puffer."
+
+msgid "E87: Cannot go beyond last buffer"
+msgstr "E87: Kann nicht über den letzten Puffer hinaus gehen."
+
+msgid "E88: Cannot go before first buffer"
+msgstr "E88: Kann nicht vor den ersten Puffer gehen."
+
+#, c-format
+msgid "E89: No write since last change for buffer %d (add ! to override)"
+msgstr ""
+"E89: Puffer %d seit der letzten Änderung nicht gesichert (erzwinge mit !)"
+
+msgid "E948: Job still running (add ! to end the job)"
+msgstr "E948: Job läuft noch (Beenden mit !)"
+
+msgid "E37: No write since last change (add ! to override)"
+msgstr "E37: Kein Schreibvorgang seit der letzten Änderung (erzwinge mit !)"
+
+msgid "E948: Job still running"
+msgstr "E948: Job läuft noch"
+
+msgid "E37: No write since last change"
+msgstr "E37: Nicht geschrieben seit letzter Änderung"
+
+msgid "W14: Warning: List of file names overflow"
+msgstr "W14: Achtung: Überlauf der Dateinamensliste."
+
+#, c-format
+msgid "E92: Buffer %d not found"
+msgstr "E92: Puffer %d nicht gefunden."
+
+#, c-format
+msgid "E93: More than one match for %s"
+msgstr "E93: Mehr als ein Treffer für %s."
+
+#, c-format
+msgid "E94: No matching buffer for %s"
+msgstr "E94: Kein übereinstimmender Puffer für %s."
+
+#, c-format
+msgid "line %ld"
+msgstr "Zeile %ld"
+
+msgid "E95: Buffer with this name already exists"
+msgstr "E95: Ein Puffer mit diesem Namen existiert bereits."
+
+msgid " [Modified]"
+msgstr " [Verändert]"
+
+msgid "[Not edited]"
+msgstr "[Nicht editiert]"
+
+msgid "[New file]"
+msgstr "[Neue Datei]"
+
+msgid "[Read errors]"
+msgstr "[Lesefehler]"
+
+msgid "[RO]"
+msgstr "[RO]"
+
+msgid "[readonly]"
+msgstr "[Schreibgeschützt]"
+
+#, c-format
+msgid "%ld line --%d%%--"
+msgid_plural "%ld lines --%d%%--"
+msgstr[0] "%ld Zeile --%d%%--"
+msgstr[1] "%ld Zeilen --%d%%--"
+
+#, c-format
+msgid "line %ld of %ld --%d%%-- col "
+msgstr "Zeile %ld von %ld --%d%%-- Spalte "
+
+msgid "[No Name]"
+msgstr "[Unbenannt]"
+
+msgid "help"
+msgstr "Hilfe"
+
+msgid "[Help]"
+msgstr "[Hilfe]"
+
+msgid "[Preview]"
+msgstr "[Vorschau]"
+
+msgid "All"
+msgstr "Alles"
+
+msgid "Bot"
+msgstr "Ende"
+
+msgid "Top"
+msgstr "Anfang"
+
+msgid ""
+"\n"
+"# Buffer list:\n"
+msgstr ""
+"\n"
+"# Liste der Puffer:\n"
+
+msgid "E382: Cannot write, 'buftype' option is set"
+msgstr "E382: Kann nicht schreiben, 'buftype'-Option ist gesetzt"
+
+msgid "[Prompt]"
+msgstr "[Prompt]"
+
+msgid "[Scratch]"
+msgstr "[Scratch]"
+
+msgid "E902: Cannot connect to port"
+msgstr "E902: Kann keine Verbindung zu Port herstellen."
+
+msgid "E901: gethostbyname() in channel_open()"
+msgstr "E901: gethostbyname() in channel_open()"
+
+msgid "E898: socket() in channel_open()"
+msgstr "E898: socket() in channel_open()"
+
+msgid "E903: received command with non-string argument"
+msgstr "E903: Befehl mit Nicht-String Argument empfangen."
+
+msgid "E904: last argument for expr/call must be a number"
+msgstr "E904: Letztes Argument für expr/call muss eine Zahl sein."
+
+msgid "E904: third argument for call must be a list"
+msgstr "E904: Drittes Argument für call muss eine Liste sein."
+
+#, c-format
+msgid "E905: received unknown command: %s"
+msgstr "E905: Unbekannter Befehl empfangen: %s."
+
+#, c-format
+msgid "E630: %s(): write while not connected"
+msgstr "E630: %s(): geschrieben ohne eine Verbindung hergestellt zu haben."
+
+#, c-format
+msgid "E631: %s(): write failed"
+msgstr "E631: %s(): Schreiben fehlgeschlagen."
+
+#, c-format
+msgid "E917: Cannot use a callback with %s()"
+msgstr "E917: Kann keinen Callback mit %s() durchführen."
+
+msgid "E912: cannot use ch_evalexpr()/ch_sendexpr() with a raw or nl channel"
+msgstr ""
+"E912: Kann ch_evalexpr()/ch_sendexpr() nicht mit einem Raw oder NL Channel "
+"benutzen."
+
+msgid "E906: not an open channel"
+msgstr "E906: Kein offener Channel"
+
+msgid "E920: _io file requires _name to be set"
+msgstr "E920: Für _io Datei muss _name gesetzt ist."
+
+msgid "E915: in_io buffer requires in_buf or in_name to be set"
+msgstr "E915: Für in_io Puffer muss in_buf oder in_name gesetzt sein."
+
+#, c-format
+msgid "E918: buffer must be loaded: %s"
+msgstr "E918: Puffer muss geladen sein: %s."
+
+msgid "E821: File is encrypted with unknown method"
+msgstr "E821: Datei ist mit unbekannter Verschlüsselungsart verschlüsselt."
+
+msgid "Warning: Using a weak encryption method; see :help 'cm'"
+msgstr "Achtung: Benutze eine schwache Verschlüsselungsart; siehe :help 'cm'."
+
+msgid "Enter encryption key: "
+msgstr "Geben Sie bitte den Schlüssel ein: "
+
+msgid "Enter same key again: "
+msgstr "Geben Sie den gleichen Schlüssel nochmals ein:"
+
+msgid "Keys don't match!"
+msgstr "Die Schlüssel stimmen nicht überein!"
+
+msgid "[crypted]"
+msgstr "[verschlüsselt]"
+
+#, c-format
+msgid "E720: Missing colon in Dictionary: %s"
+msgstr "E720: Fehlender Doppelpunkt im Dictionary: %s"
+
+#, c-format
+msgid "E721: Duplicate key in Dictionary: \"%s\""
+msgstr "E721: Doppelter Schlüssel im Dictionary: \"%s\""
+
+#, c-format
+msgid "E722: Missing comma in Dictionary: %s"
+msgstr "E722: Fehlendes Komma im Dictionary: %s"
+
+#, c-format
+msgid "E723: Missing end of Dictionary '}': %s"
+msgstr "E723: Fehlendes Ende des Dictionary '}': %s"
+
+msgid "extend() argument"
+msgstr "extend() Argument"
+
+#, c-format
+msgid "E737: Key already exists: %s"
+msgstr "E737: Schlüssel existiert bereits: %s"
+
+#, c-format
+msgid "E96: Cannot diff more than %d buffers"
+msgstr "E96: Kann Diff für mehr als %d Puffer nicht erstellen."
+
+#, c-format
+msgid "Not enough memory to use internal diff for buffer \"%s\""
+msgstr ""
+"Nicht genügend Speicher vorhanden, um Puffer \"%s\" mit internem "
+"Diffalgorithmus zu nutzen."
+
+msgid "E810: Cannot read or write temp files"
+msgstr "E810: Kann temporäre Datei nicht lesen oder schreiben."
+
+msgid "E97: Cannot create diffs"
+msgstr "E97: Kann keinen Diff erstellen."
+
+msgid "E960: Problem creating the internal diff"
+msgstr "E960: Problem internen Diffalgorithmus anzuwenden"
+
+msgid "Patch file"
+msgstr "Patch-Datei"
+
+msgid "E816: Cannot read patch output"
+msgstr "E816: Patch-Ausgabe kann nicht gelesen werden."
+
+msgid "E98: Cannot read diff output"
+msgstr "E98: Diff-Ausgabe kann nicht gelesen werden."
+
+msgid "E959: Invalid diff format."
+msgstr "E959: Ungültiges Diff-Format"
+
+msgid "E99: Current buffer is not in diff mode"
+msgstr "E99: Aktueller Puffer ist nicht im Diff-Modus."
+
+msgid "E793: No other buffer in diff mode is modifiable"
+msgstr "E793: Kein weiterer Puffer im diff-Modues ist modifizierbar."
+
+msgid "E100: No other buffer in diff mode"
+msgstr "E100: Kein weiterer Puffer ist im Diff-Modus."
+
+msgid "E101: More than two buffers in diff mode, don't know which one to use"
+msgstr "E101: Mehrdeutigkeit: Mehr als zwei Puffer im Diff-Modus."
+
+#, c-format
+msgid "E102: Can't find buffer \"%s\""
+msgstr "E102: Kann Puffer \"%s\" nicht finden."
+
+#, c-format
+msgid "E103: Buffer \"%s\" is not in diff mode"
+msgstr "E103: Puffer \"%s\" ist nicht im Diff-Modus."
+
+msgid "E787: Buffer changed unexpectedly"
+msgstr "E787: Puffer änderte sich unerwartet."
+
+msgid "E104: Escape not allowed in digraph"
+msgstr "E104: <Escape> ist in einem Digraphen nicht erlaubt."
+
+msgid "Custom"
+msgstr "Benutzerdefinierte Digraphs"
+
+msgid "Latin supplement"
+msgstr "Lateinisch Ergänzung"
+
+msgid "Greek and Coptic"
+msgstr "Griechisch und Koptisch"
+
+msgid "Cyrillic"
+msgstr "Kyrillisch"
+
+msgid "Hebrew"
+msgstr "Hebräisch"
+
+msgid "Arabic"
+msgstr "Arabisch"
+
+msgid "Latin extended"
+msgstr "Lateinisch Zusatz"
+
+msgid "Greek extended"
+msgstr "Griechisch Zusatz"
+
+msgid "Punctuation"
+msgstr "Interpunktion"
+
+msgid "Super- and subscripts"
+msgstr "Hoch- und tiefgestellte Zeichen"
+
+msgid "Currency"
+msgstr "Währungszeichen"
+
+msgid "Other"
+msgstr "Andere Zeichen"
+
+msgid "Roman numbers"
+msgstr "Römische Ziffern"
+
+msgid "Arrows"
+msgstr "Pfeile"
+
+msgid "Mathematical operators"
+msgstr "Mathematische Operatoren"
+
+msgid "Technical"
+msgstr "Technische Zeichen"
+
+msgid "Box drawing"
+msgstr "Rahmenzeichen"
+
+msgid "Block elements"
+msgstr "Blockelemente"
+
+msgid "Geometric shapes"
+msgstr "Geometrische Formen"
+
+msgid "Symbols"
+msgstr "Verschiedene Symbole"
+
+msgid "Dingbats"
+msgstr "Dingbats"
+
+msgid "CJK symbols and punctuation"
+msgstr "CJK Symbole und Interpunktion"
+
+msgid "Hiragana"
+msgstr "Hiragana"
+
+msgid "Katakana"
+msgstr "Katakana"
+
+msgid "Bopomofo"
+msgstr "Bopomofo"
+
+msgid "E544: Keymap file not found"
+msgstr "E544: Keymap-Datei für die Tastaturbelegung nicht gefunden."
+
+msgid "E105: Using :loadkeymap not in a sourced file"
+msgstr "E105: :loadkeymap außerhalb einer eingelesenen Datei."
+
+msgid "E791: Empty keymap entry"
+msgstr "E791: Leerer keymap Eintrag"
+
+msgid " Keyword completion (^N^P)"
+msgstr " Stichwort Vervollständigung (^N^P)"
+
+msgid " ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+msgstr " ^X Modus (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+
+msgid " Whole line completion (^L^N^P)"
+msgstr " Zeilen-Vervollständigung (^L^N^P)"
+
+msgid " File name completion (^F^N^P)"
+msgstr " Dateinamen-Vervollständigung (^F^N^P)"
+
+msgid " Tag completion (^]^N^P)"
+msgstr " Tag-Vervollständigung (^]^N^P)"
+
+msgid " Path pattern completion (^N^P)"
+msgstr " Pfad-Vervollständigung (^N^P)"
+
+msgid " Definition completion (^D^N^P)"
+msgstr " Definitions-Vervollständigung (^D^N^P)"
+
+msgid " Dictionary completion (^K^N^P)"
+msgstr " Dictionary-Vervollständigung (^K^N^P) "
+
+msgid " Thesaurus completion (^T^N^P)"
+msgstr " Thesaurus-Vervollständigung (^T^N^P)"
+
+msgid " Command-line completion (^V^N^P)"
+msgstr " Kommandozeilen-Vervollständigung (^V^N^P)"
+
+msgid " User defined completion (^U^N^P)"
+msgstr " Benutzerdefinierte Vervollständigung (^U^N^P)"
+
+msgid " Omni completion (^O^N^P)"
+msgstr " Omni-Vervollständigung (^O^N^P)"
+
+msgid " Spelling suggestion (s^N^P)"
+msgstr " Vorschlag der Rechtschreibprüfung (s^N^P)"
+
+msgid " Keyword Local completion (^N^P)"
+msgstr " Lokale Stichwort-Vervollständigung(^N^P)"
+
+msgid "Hit end of paragraph"
+msgstr "Absatzende erreicht"
+
+msgid "E839: Completion function changed window"
+msgstr "E839: Vervollständigungsfunktion änderte Fenster."
+
+msgid "E840: Completion function deleted text"
+msgstr "E840: Vervollständigungsfunktion hat Text gelöscht."
+
+msgid "'dictionary' option is empty"
+msgstr "Die Option 'dictionary' ist leer."
+
+msgid "'thesaurus' option is empty"
+msgstr "Die Option 'thesaurus' ist leer."
+
+#, c-format
+msgid "Scanning dictionary: %s"
+msgstr "Durchsuchen des Wörterbuchs: %s"
+
+msgid " (insert) Scroll (^E/^Y)"
+msgstr " (Einfügen) Scrollen (^E/^Y)"
+
+msgid " (replace) Scroll (^E/^Y)"
+msgstr " (Ersetzen) Scrollen (^E/^Y)"
+
+#, c-format
+msgid "Scanning: %s"
+msgstr "Durchsuche: %s"
+
+msgid "Scanning tags."
+msgstr "Durchsuche Tags"
+
+msgid "match in file"
+msgstr "Treffer in Datei"
+
+msgid " Adding"
+msgstr " Füge hinzu"
+
+msgid "-- Searching..."
+msgstr "-- Suche..."
+
+msgid "Back at original"
+msgstr "Zurück am Ursprung"
+
+msgid "Word from other line"
+msgstr "Wort aus anderer Zeile"
+
+msgid "The only match"
+msgstr "Einziger Treffer"
+
+#, c-format
+msgid "match %d of %d"
+msgstr "Treffer %d von %d"
+
+#, c-format
+msgid "match %d"
+msgstr "Treffer %d"
+
+msgid "E18: Unexpected characters in :let"
+msgstr "E18: Unerwartete Zeichen in :let"
+
+#, c-format
+msgid "E121: Undefined variable: %s"
+msgstr "E121: Undefinierte Variable: %s"
+
+msgid "E111: Missing ']'"
+msgstr "E111: Fehlende ']'"
+
+msgid "E719: Cannot use [:] with a Dictionary"
+msgstr "E719: Kann [:] nicht mit einem Dictionary verwenden"
+
+#, c-format
+msgid "E734: Wrong variable type for %s="
+msgstr "E734: Falscher Variablentyp für %s="
+
+#, c-format
+msgid "E461: Illegal variable name: %s"
+msgstr "E461: Unzulässiger Variablenname: %s"
+
+msgid "E806: using Float as a String"
+msgstr "E806: Float als String benutzt."
+
+msgid "E687: Less targets than List items"
+msgstr "E687: Weniger Ziele als Einträge in der Liste."
+
+msgid "E688: More targets than List items"
+msgstr "E688: Mehr Ziele als Einträge in der Liste."
+
+msgid "Double ; in list of variables"
+msgstr "Doppeltes ; in der Liste von Variablen"
+
+#, c-format
+msgid "E738: Can't list variables for %s"
+msgstr "E738: Kann Variablen nicht auflisten: %s"
+
+msgid "E689: Can only index a List, Dictionary or Blob"
+msgstr "E689: Kann nur Listen, Dictionary oder Blob indizieren"
+
+msgid "E708: [:] must come last"
+msgstr "E708: [:] muss am Schluss kommen."
+
+msgid "E709: [:] requires a List or Blob value"
+msgstr "E709: [:] benötigt einen Listen- oder Blobwert"
+
+msgid "E972: Blob value does not have the right number of bytes"
+msgstr "E972: Blobwert hat nicht die richtige Anzahl an Bytes"
+
+msgid "E710: List value has more items than target"
+msgstr "E710: Listenwert hat mehr Einträge als das Ziel."
+
+msgid "E711: List value has not enough items"
+msgstr "E711: Listenwert hat nicht genügend Einträge."
+
+msgid "E690: Missing \"in\" after :for"
+msgstr "E690: Fehlendes \"in\" nach :for"
+
+#, c-format
+msgid "E108: No such variable: \"%s\""
+msgstr "E108: Keine solche Variable: \"%s\""
+
+#, c-format
+msgid "E940: Cannot lock or unlock variable %s"
+msgstr "E940: Kann Variable \"%s\" nicht sperren bzw. entsperren."
+
+msgid "E743: variable nested too deep for (un)lock"
+msgstr "E743: Variable ist zu tief verschachtelt zum (ent)sperren."
+
+msgid "E109: Missing ':' after '?'"
+msgstr "E109: Fehlender ':' nach '?'"
+
+msgid "E804: Cannot use '%' with Float"
+msgstr "E804: Kann '%' mit Floats benutzen."
+
+msgid "E973: Blob literal should have an even number of hex characters"
+msgstr "E973: Blob-Literal sollte eine gerade Anzahl von Hex-Zeichen haben"
+
+msgid "E110: Missing ')'"
+msgstr "E110: Fehlendes ')'"
+
+msgid "E695: Cannot index a Funcref"
+msgstr "E695: Kann keine Funktionsreferenz indizieren."
+
+msgid "E909: Cannot index a special variable"
+msgstr "E909: Kann Spezialvariable nicht indexieren."
+
+#, c-format
+msgid "E112: Option name missing: %s"
+msgstr "E112: Optionsname fehlt: %s"
+
+#, c-format
+msgid "E113: Unknown option: %s"
+msgstr "E113: Unbekannte Option: %s"
+
+#, c-format
+msgid "E114: Missing quote: %s"
+msgstr "E114: Fehlendes Anführungszeichen: %s"
+
+#, c-format
+msgid "E115: Missing quote: %s"
+msgstr "E115: Fehlendes Anführungszeichen: %s"
+
+msgid "Not enough memory to set references, garbage collection aborted!"
+msgstr ""
+"Nicht genügend Speicher um Referenzen zu setzen, Garbagecollection "
+"abgebrochen!"
+
+msgid "E724: variable nested too deep for displaying"
+msgstr "E724: Variable ist zu tief verschachtelt für die Anzeige"
+
+msgid "E805: Using a Float as a Number"
+msgstr "E805: Benutze Float als Nummer."
+
+msgid "E703: Using a Funcref as a Number"
+msgstr "E703: Funktionsreferenz als Zahl verwendet"
+
+msgid "E745: Using a List as a Number"
+msgstr "E745: Liste als Zahl verwendet."
+
+msgid "E728: Using a Dictionary as a Number"
+msgstr "E728: Dictionary als Zahl verwendet."
+
+msgid "E910: Using a Job as a Number"
+msgstr "E910: Job als Zahl verwendet."
+
+msgid "E913: Using a Channel as a Number"
+msgstr "E913: Channel als Zahl verwendet."
+
+msgid "E974: Using a Blob as a Number"
+msgstr "E974: Blob als Zahl verwendet."
+
+msgid "E891: Using a Funcref as a Float"
+msgstr "E891: Funktionsreferenz als Float verwendet."
+
+msgid "E892: Using a String as a Float"
+msgstr "E892: String als Float verwendet."
+
+msgid "E893: Using a List as a Float"
+msgstr "E893: Liste als Float verwendet."
+
+msgid "E894: Using a Dictionary as a Float"
+msgstr "E894: Dictionary als Float verwendet."
+
+msgid "E907: Using a special value as a Float"
+msgstr "E907: Benutze Spezialvariable als Float."
+
+msgid "E911: Using a Job as a Float"
+msgstr "E911: Job als Float verwendet"
+
+msgid "E914: Using a Channel as a Float"
+msgstr "E914: Channel als Float verwendet"
+
+msgid "E975: Using a Blob as a Float"
+msgstr "E975: Blob als Float verwendet"
+
+msgid "E729: using Funcref as a String"
+msgstr "E729: Funktionsreferenz als String verwendet"
+
+msgid "E730: using List as a String"
+msgstr "E730: Liste als String verwendet"
+
+msgid "E731: using Dictionary as a String"
+msgstr "E731: Dictionary als String verwendet"
+
+msgid "E976: using Blob as a String"
+msgstr "E976: Blob als String verwendet"
+
+msgid "E908: using an invalid value as a String"
+msgstr "E908: Ungültiger Wert als String verwendet."
+
+#, c-format
+msgid "E963: setting %s to value with wrong type"
+msgstr "E963: %s auf Wert mit falschem Typ gesetzt"
+
+#, c-format
+msgid "E795: Cannot delete variable %s"
+msgstr "E795: Kann Variable nicht löschen: %s"
+
+#, c-format
+msgid "E704: Funcref variable name must start with a capital: %s"
+msgstr ""
+"E704: Funktionsreferenz-Variable muss mit einem Großbuchstaben beginnen: %s"
+
+#, c-format
+msgid "E705: Variable name conflicts with existing function: %s"
+msgstr "E705: Konflikt eines Variablennamens mit bestehender Funktion: %s"
+
+#, c-format
+msgid "E741: Value is locked: %s"
+msgstr "E741: Wert ist gesperrt: %s"
+
+msgid "Unknown"
+msgstr "Unbekannt"
+
+#, c-format
+msgid "E742: Cannot change value of %s"
+msgstr "E742: Kann Wert nicht ändern: %s"
+
+msgid "E698: variable nested too deep for making a copy"
+msgstr "E698: Variable ist zu tief verschachtelt für eine Kopie"
+
+msgid ""
+"\n"
+"# global variables:\n"
+msgstr ""
+"\n"
+"# globale Variablen:\n"
+
+msgid ""
+"\n"
+"\tLast set from "
+msgstr ""
+"\n"
+"\tZuletzt gesetzt in "
+
+msgid " line "
+msgstr " Zeile "
+
+msgid "E977: Can only compare Blob with Blob"
+msgstr "E977: Kann nur einen Blob mit einem Blob vergleichen"
+
+msgid "E691: Can only compare List with List"
+msgstr "E691: Kann nur eine Liste mit einer Liste vergleichen"
+
+msgid "E692: Invalid operation for List"
+msgstr "E692: Unzulässige Operation für Listen"
+
+msgid "E735: Can only compare Dictionary with Dictionary"
+msgstr "E735: Kann nur ein Dictionary mit einem Dictionary vergleichen"
+
+msgid "E736: Invalid operation for Dictionary"
+msgstr "E736: Unzulässige Funktion für ein Dictionary"
+
+msgid "E694: Invalid operation for Funcrefs"
+msgstr "E694: Unzulässige Operation für Funktionsreferenzen"
+
+msgid "map() argument"
+msgstr "map() Argument"
+
+msgid "filter() argument"
+msgstr "filter() Argument"
+
+#, c-format
+msgid "E686: Argument of %s must be a List"
+msgstr "E686: Argument von %s muss eine Liste sein."
+
+#, c-format
+msgid "E899: Argument of %s must be a List or Blob"
+msgstr "E899: Argument von %s muss eine Liste oder ein Blob sein."
+
+msgid "E928: String required"
+msgstr "E928: String wird benötigt."
+
+msgid "E808: Number or Float required"
+msgstr "E808: Zahl oder Float benötigt."
+
+msgid "add() argument"
+msgstr "add() Argument"
+
+#, c-format
+msgid "E158: Invalid buffer name: %s"
+msgstr "E158: ungültige Puffernummer: %s"
+
+msgid "E785: complete() can only be used in Insert mode"
+msgstr "E785: complete() kann nur im Einfüge-Modus verwendet werden."
+
+msgid "&Ok"
+msgstr "&Ok"
+
+msgid "E980: lowlevel input not supported"
+msgstr "E980: Low-Level Eingabe wird nicht unterstützt"
+
+#, c-format
+msgid "+-%s%3ld line: "
+msgid_plural "+-%s%3ld lines: "
+msgstr[0] "+-%s%3ld Zeile: "
+msgstr[1] "+-%s%3ld Zeilen: "
+
+#, c-format
+msgid "E700: Unknown function: %s"
+msgstr "E700: Unbekannte Funktion: %s"
+
+msgid "E922: expected a dict"
+msgstr "E922: Erwarte ein Dictionary."
+
+msgid "E923: Second argument of function() must be a list or a dict"
+msgstr ""
+"E923: Zweites Argument von function() muss eine Liste oder ein Dictionary "
+"sein."
+
+msgid ""
+"&OK\n"
+"&Cancel"
+msgstr ""
+"&OK\n"
+"&Abbrechen"
+
+msgid "called inputrestore() more often than inputsave()"
+msgstr "inputrestore() wurde häufiger als inputsave() aufgerufen."
+
+msgid "insert() argument"
+msgstr "insert() Argument"
+
+msgid "E786: Range not allowed"
+msgstr "E786: Bereich nicht erlaubt"
+
+msgid "E916: not a valid job"
+msgstr "E916: kein gültiger Job"
+
+msgid "E701: Invalid type for len()"
+msgstr "E701: Unzulässiger Typ für len()"
+
+msgid "E957: Invalid window number"
+msgstr "E957: Ungültige Fensternummer"
+
+#, c-format
+msgid "E798: ID is reserved for \":match\": %d"
+msgstr "E798: ID ist für \":match\" reserviert: %d"
+
+msgid "E726: Stride is zero"
+msgstr "E726: Stride ist Null"
+
+msgid "E727: Start past end"
+msgstr "E727: Start hinter dem Ende"
+
+msgid "<empty>"
+msgstr "<leer>"
+
+msgid "E240: No connection to the X server"
+msgstr "E240: Keine Verbindung zum X-Server"
+
+#, c-format
+msgid "E241: Unable to send to %s"
+msgstr "E241: Kann nicht zu %s senden"
+
+msgid "E277: Unable to read a server reply"
+msgstr "E277: Server-Antwort kann nicht gelesen werden."
+
+msgid "E941: already started a server"
+msgstr "E941: Server bereits gestartet."
+
+msgid "E942: +clientserver feature not available"
+msgstr "E942: +clientserver Eigenschaft nicht verfügbar"
+
+msgid "remove() argument"
+msgstr "remove() Argument"
+
+msgid "E655: Too many symbolic links (cycle?)"
+msgstr "E655: Zu viele symbolische Links (zirkulär?)"
+
+msgid "reverse() argument"
+msgstr "reverse() Argument"
+
+msgid "E258: Unable to send to client"
+msgstr "E258: Kann nicht zum Client senden."
+
+#, c-format
+msgid "E927: Invalid action: '%s'"
+msgstr "E927: Ungültige Aktion '%s'"
+
+#, c-format
+msgid "E962: Invalid action: '%s'"
+msgstr "E962: Ungültige Aktion '%s'"
+
+msgid "sort() argument"
+msgstr "sort() Argument"
+
+msgid "uniq() argument"
+msgstr "uniq() Argument"
+
+msgid "E702: Sort compare function failed"
+msgstr "E702: Die Vergleichsfunktion der Sortierung ist fehlgeschlagen."
+
+msgid "E882: Uniq compare function failed"
+msgstr "E882: Die Uniq Vergleichsfunktion ist fehlgeschlagen."
+
+msgid "(Invalid)"
+msgstr "(Ungültig)"
+
+#, c-format
+msgid "E935: invalid submatch number: %d"
+msgstr "E935: Ungültige Submatch Nummer: %d"
+
+msgid "E677: Error writing temp file"
+msgstr "E677: Fehler beim Schreiben einer temporären Datei"
+
+msgid "E921: Invalid callback argument"
+msgstr "E921: Ungülgültiges Callback Argument"
+
+#, c-format
+msgid "<%s>%s%s %d, Hex %02x, Oct %03o, Digr %s"
+msgstr "<%s>%s%s %d, Hex %02x, Oktal %03o, Digr %s"
+
+#, c-format
+msgid "<%s>%s%s %d, Hex %02x, Octal %03o"
+msgstr "<%s>%s%s %d, Hex %02x, Oktal %03o"
+
+#, c-format
+msgid "> %d, Hex %04x, Oct %o, Digr %s"
+msgstr "> %d, Hex %04x, Oktal %o, Digr %s"
+
+#, c-format
+msgid "> %d, Hex %08x, Oct %o, Digr %s"
+msgstr "> %d, Hex %08x, Oktal %o, Digr %s"
+
+#, c-format
+msgid "> %d, Hex %04x, Octal %o"
+msgstr "> %d, Hex %04x, Oktal %o"
+
+#, c-format
+msgid "> %d, Hex %08x, Octal %o"
+msgstr "> %d, Hex %08x, Oktal %o"
+
+msgid "E134: Cannot move a range of lines into itself"
+msgstr "E134: Kann Bereich von Zeilen nicht in sich selbst verschieben"
+
+#, c-format
+msgid "%ld line moved"
+msgid_plural "%ld lines moved"
+msgstr[0] "%ld Zeile verschoben"
+msgstr[1] "%ld Zeilen verschoben"
+
+#, c-format
+msgid "%ld lines filtered"
+msgstr "%ld Zeilen gefiltert"
+
+msgid "E135: *Filter* Autocommands must not change current buffer"
+msgstr "E135: *Filter*-Autokommandos dürfen den aktuellen Puffer nicht ändern"
+
+msgid "[No write since last change]\n"
+msgstr "[Nicht geschrieben seit der letzten Änderung]\n"
+
+#, c-format
+msgid "%sviminfo: %s in line: "
+msgstr "%sviminfo: %s in Zeile: "
+
+msgid "E136: viminfo: Too many errors, skipping rest of file"
+msgstr "E136: viminfo: Zu viele Fehler; überspringe Rest der Datei"
+
+#, c-format
+msgid "Reading viminfo file \"%s\"%s%s%s"
+msgstr "Lesen der viminfo-Datei \"%s\"%s%s%s"
+
+msgid " info"
+msgstr " Information"
+
+msgid " marks"
+msgstr " Markierungen"
+
+msgid " oldfiles"
+msgstr " oldfiles"
+
+msgid " FAILED"
+msgstr " FEHLGESCHLAGEN"
+
+#, c-format
+msgid "E137: Viminfo file is not writable: %s"
+msgstr "E137: Viminfo-Datei ist nicht schreibbar: %s"
+
+#, c-format
+msgid "E929: Too many viminfo temp files, like %s!"
+msgstr "E929: Zu viele temporäre viminfo Dateien (wie %s)!"
+
+#, c-format
+msgid "E138: Can't write viminfo file %s!"
+msgstr "E138: Schreiben der viminfo-Datei %s ist nicht möglich!"
+
+#, c-format
+msgid "Writing viminfo file \"%s\""
+msgstr "Schreiben der viminfo-Datei \"%s\""
+
+#, c-format
+msgid "E886: Can't rename viminfo file to %s!"
+msgstr "E886: Kann viminfo Datei nicht in %s umbenennen!"
+
+#, c-format
+msgid "# This viminfo file was generated by Vim %s.\n"
+msgstr "# Diese viminfo-Datei wurde von Vim %s generiert.\n"
+
+msgid ""
+"# You may edit it if you're careful!\n"
+"\n"
+msgstr ""
+"# Sie können sie verändern, wenn Sie vorsichtig vorgehen!\n"
+"\n"
+
+msgid "# Value of 'encoding' when this file was written\n"
+msgstr "# Wert von 'encoding', als diese Datei geschrieben wurde\n"
+
+msgid "Illegal starting char"
+msgstr "Unzulässiges Zeichen am Anfang"
+
+msgid ""
+"\n"
+"# Bar lines, copied verbatim:\n"
+msgstr ""
+"\n"
+"# |-Zeilen, wortwörtlich kopiert:\n"
+
+msgid "Save As"
+msgstr "Speichern als"
+
+msgid "Write partial file?"
+msgstr "Partielle Datei schreiben?"
+
+msgid "E140: Use ! to write partial buffer"
+msgstr "E140: Zum Schreiben von partiellen Puffern ! verwenden"
+
+#, c-format
+msgid "Overwrite existing file \"%s\"?"
+msgstr "Überschreibe existierende Datei \"%s\"?"
+
+#, c-format
+msgid "Swap file \"%s\" exists, overwrite anyway?"
+msgstr "Auslagerungsdatei \"%s\" existiert bereits. Überschreiben?"
+
+#, c-format
+msgid "E768: Swap file exists: %s (:silent! overrides)"
+msgstr "E768: Auslagerungsdatei existiert bereits: %s (mit :silent! erzwingen)"
+
+#, c-format
+msgid "E141: No file name for buffer %ld"
+msgstr "E141: Kein Dateiname für Puffer %ld"
+
+msgid "E142: File not written: Writing is disabled by 'write' option"
+msgstr ""
+"E142: Datei wurde nicht geschrieben: Schreiben ist durch die 'write' Option "
+"deaktiviert"
+
+#, c-format
+msgid ""
+"'readonly' option is set for \"%s\".\n"
+"Do you wish to write anyway?"
+msgstr ""
+"'readonly'-Option ist für \"%s\" gesetzt.\n"
+"Möchten Sie trotzdem schreiben?"
+
+#, c-format
+msgid ""
+"File permissions of \"%s\" are read-only.\n"
+"It may still be possible to write it.\n"
+"Do you wish to try?"
+msgstr ""
+"Dateiberechtigung von \"%s\" ist nur-lesbar.\n"
+"Möglicherweise kann die Datei dennoch geschrieben werden.\n"
+"Fortsetzen?"
+
+#, c-format
+msgid "E505: \"%s\" is read-only (add ! to override)"
+msgstr "E505: \"%s\" ist Schreibgeschützt (erzwinge mit !)"
+
+msgid "Edit File"
+msgstr "Öffne Datei"
+
+#, c-format
+msgid "E143: Autocommands unexpectedly deleted new buffer %s"
+msgstr "E143: Autokommandos löschten unerwartet neuen Puffer %s"
+
+msgid "E144: non-numeric argument to :z"
+msgstr "E144: Nicht-numerisches Argument für :z"
+
+msgid "E145: Shell commands not allowed in rvim"
+msgstr "E145: Shell-Befehle sind in rvim nicht erlaubt."
+
+msgid "E146: Regular expressions can't be delimited by letters"
+msgstr ""
+"E146: Reguläre Ausdrücke können nicht durch Buchstaben begrenzt werden."
+
+#, c-format
+msgid "replace with %s (y/n/a/q/l/^E/^Y)?"
+msgstr "ersetze durch %s (y/n/a/q/l/^E/^Y)?"
+
+msgid "(Interrupted) "
+msgstr "(Unterbrochen) "
+
+#, c-format
+msgid "%ld match on %ld line"
+msgid_plural "%ld matches on %ld line"
+msgstr[0] " %ld Treffer in %ld Zeile"
+msgstr[1] " %ld Treffer in %ld Zeile"
+
+#, c-format
+msgid "%ld substitution on %ld line"
+msgid_plural "%ld substitutions on %ld line"
+msgstr[0] "%ld Ersetzung in %ld Zeile"
+msgstr[1] "%ld Ersetzungen in %ld Zeile"
+
+#, c-format
+msgid "%ld match on %ld lines"
+msgid_plural "%ld matches on %ld lines"
+msgstr[0] " %ld Treffer in %ld Zeilen"
+msgstr[1] " %ld Treffer in %ld Zeilen"
+
+#, c-format
+msgid "%ld substitution on %ld lines"
+msgid_plural "%ld substitutions on %ld lines"
+msgstr[0] "%ld Ersetzungen in %ld Zeilen"
+msgstr[1] "%ld Ersetzungen in %ld Zeilen"
+
+msgid "E147: Cannot do :global recursive with a range"
+msgstr "E147: Kann :global nicht rekursiv mit einem Bereich ausführen."
+
+msgid "E148: Regular expression missing from global"
+msgstr "E148: Regulärer Ausdruck fehlt in global"
+
+#, c-format
+msgid "Pattern found in every line: %s"
+msgstr "Muster in jeder Zeile gefunden: %s"
+
+#, c-format
+msgid "Pattern not found: %s"
+msgstr "Muster nicht gefunden: %s"
+
+msgid ""
+"\n"
+"# Last Substitute String:\n"
+"$"
+msgstr ""
+"\n"
+"# Letzte ersetzte Zeichenkette:\n"
+"$"
+
+msgid "E478: Don't panic!"
+msgstr "E478: Nur keine Panik!"
+
+#, c-format
+msgid "E661: Sorry, no '%s' help for %s"
+msgstr "E661: Schade, keine '%s' Hilfe für %s"
+
+#, c-format
+msgid "E149: Sorry, no help for %s"
+msgstr "E149: Schade, keine Hilfe für %s"
+
+#, c-format
+msgid "Sorry, help file \"%s\" not found"
+msgstr "Hilfe-Datei \"%s\" nicht gefunden"
+
+#, c-format
+msgid "E151: No match: %s"
+msgstr "E151: Kein Treffer: %s"
+
+#, c-format
+msgid "E152: Cannot open %s for writing"
+msgstr "E152: %s kann nicht zum Schreiben geöffnet werden."
+
+#, c-format
+msgid "E153: Unable to open %s for reading"
+msgstr "E153: %s kann nicht zum Lesen geöffnet werden."
+
+#, c-format
+msgid "E670: Mix of help file encodings within a language: %s"
+msgstr ""
+"E670: Mischung von Kodierungen einer Hilfedatei innerhalb einer Sprache: %s"
+
+#, c-format
+msgid "E154: Duplicate tag \"%s\" in file %s/%s"
+msgstr "E154: Doppelter Tag \"%s\" in der Datei %s/%s"
+
+#, c-format
+msgid "E150: Not a directory: %s"
+msgstr "E150: Kein Verzeichnis: %s"
+
+msgid "No old files"
+msgstr "Keine Alt-Dateien"
+
+msgid "Entering Debug mode. Type \"cont\" to continue."
+msgstr "Debug-Modus. Geben Sie \"cont\" zum Fortsetzen ein."
+
+#, c-format
+msgid "Oldval = \"%s\""
+msgstr "Alter Wert = \"%s\""
+
+#, c-format
+msgid "Newval = \"%s\""
+msgstr "Neuer Wert = \"%s\""
+
+#, c-format
+msgid "line %ld: %s"
+msgstr "Zeile %ld: %s"
+
+#, c-format
+msgid "cmd: %s"
+msgstr "Befehl: %s"
+
+msgid "frame is zero"
+msgstr "Frame ist Null"
+
+#, c-format
+msgid "frame at highest level: %d"
+msgstr "Frame auf letzter Ebene: %d"
+
+#, c-format
+msgid "Breakpoint in \"%s%s\" line %ld"
+msgstr "Haltepunkt in \"%s%s\" Zeile %ld"
+
+#, c-format
+msgid "E161: Breakpoint not found: %s"
+msgstr "E161: Haltepunkt nicht gefunden: %s"
+
+msgid "No breakpoints defined"
+msgstr "Keine Haltepunkte definiert"
+
+#, c-format
+msgid "%3d %s %s line %ld"
+msgstr "%3d %s %s Zeile %ld"
+
+#, c-format
+msgid "%3d expr %s"
+msgstr "%3d expr %s"
+
+msgid "E750: First use \":profile start {fname}\""
+msgstr "E750: Benutze vorher :profile start <fname>"
+
+#, c-format
+msgid "Save changes to \"%s\"?"
+msgstr "Änderungen in \"%s\" speichern?"
+
+#, c-format
+msgid "E947: Job still running in buffer \"%s\""
+msgstr "E947: Job noch aktiv in Puffer \"%s\""
+
+#, c-format
+msgid "E162: No write since last change for buffer \"%s\""
+msgstr "E162: Puffer \"%s\" wurde seit der letzten Änderung nicht geschrieben."
+
+msgid "Warning: Entered other buffer unexpectedly (check autocommands)"
+msgstr ""
+"Achtung: Unerwartetet einen andren Puffer geöffnet (überprüfen Sie die "
+"Autokommandos)"
+
+msgid "E163: There is only one file to edit"
+msgstr "E163: Es gibt nur eine Datei zum Editieren."
+
+msgid "E164: Cannot go before first file"
+msgstr "E164: Kann nicht vor die erste Datei hinausgehen."
+
+msgid "E165: Cannot go beyond last file"
+msgstr "E165: Kann nicht über die letzte Datei hinausgehen"
+
+#, c-format
+msgid "E666: compiler not supported: %s"
+msgstr "E666: Compiler nicht unterstützt: %s"
+
+#, c-format
+msgid "Searching for \"%s\" in \"%s\""
+msgstr "Suche nach \"%s\" in \"%s\""
+
+#, c-format
+msgid "Searching for \"%s\""
+msgstr "Suche nach \"%s\""
+
+#, c-format
+msgid "not found in '%s': \"%s\""
+msgstr "in '%s' nicht gefunden: \"%s\""
+
+#, c-format
+msgid "W20: Required python version 2.x not supported, ignoring file: %s"
+msgstr ""
+"W20: Erforderliche Python Version 2.x nicht unterstützt, ignoriere Datei: %s"
+
+#, c-format
+msgid "W21: Required python version 3.x not supported, ignoring file: %s"
+msgstr ""
+"W21: Erforderliche Python Version 3.x nicht unterstützt, ignoriere Datei: %s"
+
+msgid "Source Vim script"
+msgstr "Lese Vim-Skript"
+
+#, c-format
+msgid "Cannot source a directory: \"%s\""
+msgstr "Kann kein Verzeichnis einlesen: \"%s\""
+
+#, c-format
+msgid "could not source \"%s\""
+msgstr "\"%s\" konnte nicht gelesen werden"
+
+#, c-format
+msgid "line %ld: could not source \"%s\""
+msgstr "Zeile %ld: \"%s\" konnte nicht gelesen werden"
+
+#, c-format
+msgid "sourcing \"%s\""
+msgstr "lese \"%s\""
+
+#, c-format
+msgid "line %ld: sourcing \"%s\""
+msgstr "Zeile %ld: lese \"%s\""
+
+#, c-format
+msgid "finished sourcing %s"
+msgstr "Lesen von %s beendet"
+
+#, c-format
+msgid "continuing in %s"
+msgstr "weiter in %s"
+
+msgid "modeline"
+msgstr "modeline"
+
+msgid "--cmd argument"
+msgstr "--cmd Argument"
+
+msgid "-c argument"
+msgstr "-c Argument"
+
+msgid "environment variable"
+msgstr "Umgebungsvariable"
+
+msgid "error handler"
+msgstr "Error-Handler"
+
+msgid "W15: Warning: Wrong line separator, ^M may be missing"
+msgstr "W15: Achtung: Falscher Zeilentrenner, vielleicht fehlt ein ^M"
+
+msgid "E167: :scriptencoding used outside of a sourced file"
+msgstr "E167: :scriptencoding außerhalb einer eingelesenen Datei"
+
+msgid "E168: :finish used outside of a sourced file"
+msgstr "E168: :finish außerhalb einer eingelesenen Datei"
+
+#, c-format
+msgid "Current %slanguage: \"%s\""
+msgstr "Momentane %sSprache: \"%s\""
+
+#, c-format
+msgid "E197: Cannot set language to \"%s\""
+msgstr "E197: Sprache kann nicht auf \"%s\" gesetzt werden"
+
+msgid "Entering Ex mode. Type \"visual\" to go to Normal mode."
+msgstr ""
+"Ex-Modus. Geben Sie \"visual\" ein, um zum Normal-Modus zurückzukehren."
+
+msgid "E501: At end-of-file"
+msgstr "E501: Am Dateiende"
+
+msgid "E169: Command too recursive"
+msgstr "E169: Befehl zu rekursiv"
+
+#, c-format
+msgid "E605: Exception not caught: %s"
+msgstr "E605: Exception nicht gefangen: %s"
+
+msgid "End of sourced file"
+msgstr "Ende der eingelesenen Datei"
+
+msgid "End of function"
+msgstr "Ende der Funktion"
+
+msgid "E464: Ambiguous use of user-defined command"
+msgstr "E464: Mehrdeutige Verwendung eines benutzerdefinierten Befehls"
+
+msgid "E492: Not an editor command"
+msgstr "E492: Kein Editorbefehl"
+
+msgid "E493: Backwards range given"
+msgstr "E493: Bereichsgrenzen rückwärts"
+
+msgid "Backwards range given, OK to swap"
+msgstr "Bereichsgrenzen rückwärts; vertauschen"
+
+msgid "E494: Use w or w>>"
+msgstr "E494: Verwenden Sie w oder w>>"
+
+msgid "E943: Command table needs to be updated, run 'make cmdidxs'"
+msgstr ""
+"E943: Befehlstabelle muss aktualisiert werden, führe 'make cmdidxs' aus"
+
+msgid "E319: Sorry, the command is not available in this version"
+msgstr "E319: Der Befehl ist in dieser Version nicht implementiert"
+
+#, c-format
+msgid "%d more file to edit. Quit anyway?"
+msgid_plural "%d more files to edit. Quit anyway?"
+msgstr[0] "%d weitere Datei zum Editieren. Trotzdem beenden?"
+msgstr[1] "%d weitere Dateien zum Editieren. Trotzdem beenden?"
+
+#, c-format
+msgid "E173: %d more file to edit"
+msgid_plural "E173: %d more files to edit"
+msgstr[0] "E173: %d weitere Datei zum Editieren"
+msgstr[1] "E173: %d weitere Dateien zum Editieren"
+
+#, c-format
+msgid "E174: Command already exists: add ! to replace it: %s"
+msgstr "E174: Befehl '%s' existiert bereits: ! zum Ersetzen hinzufügen"
+
+msgid ""
+"\n"
+" Name Args Address Complete Definition"
+msgstr ""
+"\n"
+" Name Args Adresse Vervollständigung Definition"
+
+msgid "No user-defined commands found"
+msgstr "Keine vom Benutzer definierten Befehle gefunden"
+
+msgid "E175: No attribute specified"
+msgstr "E175: Kein Attribut angegeben"
+
+msgid "E176: Invalid number of arguments"
+msgstr "E176: Falsche Anzahl von Argumenten"
+
+msgid "E177: Count cannot be specified twice"
+msgstr "E177: Zähler kann nicht zweimal angegeben werden"
+
+msgid "E178: Invalid default value for count"
+msgstr "E178: Ungültige Voreinstellung für den Zähler"
+
+msgid "E179: argument required for -complete"
+msgstr "E179: Argument benötigt für -complete"
+
+msgid "E179: argument required for -addr"
+msgstr "E179: Argument benötigt für -addr"
+
+#, c-format
+msgid "E181: Invalid attribute: %s"
+msgstr "E181: Ungültiges Attribut: %s"
+
+msgid "E182: Invalid command name"
+msgstr "E182: Ungültiger Befehls-Name"
+
+msgid "E183: User defined commands must start with an uppercase letter"
+msgstr "E183: Benutzerdefinierte Befehle müssen mit Großbuchstaben beginnen."
+
+msgid "E841: Reserved name, cannot be used for user defined command"
+msgstr ""
+"E841: Reservierter Name kann nicht für benutzerdefinierten Befehl verwendet "
+"werden."
+
+#, c-format
+msgid "E184: No such user-defined command: %s"
+msgstr "E184: Unbekannter benutzerdefinierter Befehl: %s"
+
+#, c-format
+msgid "E180: Invalid address type value: %s"
+msgstr "E180: Ungültiger Adresstyp: %s"
+
+#, c-format
+msgid "E180: Invalid complete value: %s"
+msgstr "E180: Ungültiger Wert der Vervollständigung: %s"
+
+msgid "E468: Completion argument only allowed for custom completion"
+msgstr ""
+"E468: Argument für Vervollständigung nur für benutzerdefinierte "
+"Vervollständigung erlaubt."
+
+msgid "E467: Custom completion requires a function argument"
+msgstr ""
+"E467: Benutzerdefinierte Vervollständigung benötigt eine Funktion als "
+"Argument."
+
+msgid "unknown"
+msgstr "unbekannt"
+
+#, c-format
+msgid "E185: Cannot find color scheme '%s'"
+msgstr "E185: Kann Farbschema '%s' nicht finden"
+
+msgid "Greetings, Vim user!"
+msgstr "Herzliche Grüße, Vim Benutzer!"
+
+msgid "E784: Cannot close last tab page"
+msgstr "E784: Kann letzten Reiter nicht schließen."
+
+msgid "Already only one tab page"
+msgstr "Es existiert nur ein Reiter"
+
+msgid "Edit File in new tab page"
+msgstr "Öffne Datei in einem neuen Reiter"
+
+msgid "Edit File in new window"
+msgstr "Öffne Datei in einem neuen Fenster"
+
+#, c-format
+msgid "Tab page %d"
+msgstr "Reiter %d"
+
+msgid "No swap file"
+msgstr "Keine Auslagerungsdatei"
+
+msgid "Append File"
+msgstr "Füge Datei an"
+
+msgid "E747: Cannot change directory, buffer is modified (add ! to override)"
+msgstr ""
+"E747: Kann das Verzeichnis nicht wechseln, da der Puffer verändert wurde "
+"(erzwinge mit !)"
+
+msgid "E186: No previous directory"
+msgstr "E186: Kein vorheriges Verzeichnis"
+
+msgid "E187: Unknown"
+msgstr "E187: Unbekannt"
+
+msgid "E465: :winsize requires two number arguments"
+msgstr "E465: :winsize benötigt zwei numerische Argumente"
+
+#, c-format
+msgid "Window position: X %d, Y %d"
+msgstr "Fenster-Position: X %d, Y %d"
+
+msgid "E188: Obtaining window position not implemented for this platform"
+msgstr ""
+"E188: Die Bestimmung der Fensterposition ist für diese Plattform nicht "
+"implementiert."
+
+msgid "E466: :winpos requires two number arguments"
+msgstr "E466: :winpos benötigt zwei numerische Argumente."
+
+msgid "E930: Cannot use :redir inside execute()"
+msgstr "E930: Kann :redir nicht innerhalb von execute() verwenden."
+
+msgid "Save Redirection"
+msgstr "Umleitung Speichern"
+
+msgid "Save View"
+msgstr "Ansichten Speichern"
+
+msgid "Save Session"
+msgstr "Sitzung Speichern"
+
+msgid "Save Setup"
+msgstr "Einstellungen Speichern"
+
+#, c-format
+msgid "E739: Cannot create directory: %s"
+msgstr "E739: Kann Verzeichnis nicht erstellen: %s"
+
+#, c-format
+msgid "E189: \"%s\" exists (add ! to override)"
+msgstr "E189: \"%s\" existiert (erzwinge mit !)"
+
+#, c-format
+msgid "E190: Cannot open \"%s\" for writing"
+msgstr "E190: \"%s\" kann nicht zum Schreiben geöffnet werden."
+
+msgid "E191: Argument must be a letter or forward/backward quote"
+msgstr ""
+"E191: Argument muss ein Buchstabe oder vorwärts/rückwärts-Anführungszeichen "
+"sein"
+
+msgid "E192: Recursive use of :normal too deep"
+msgstr "E192: Rekursive Verwendung von :normal zu tief"
+
+msgid "E809: #< is not available without the +eval feature"
+msgstr "E809: #< is ohne +eval Eigenschaft nicht verfügbar"
+
+msgid "E194: No alternate file name to substitute for '#'"
+msgstr "E194: Kein anderer Dateiname zur Ersetzung mit '#'"
+
+msgid "E495: no autocommand file name to substitute for \"<afile>\""
+msgstr "E495: Kein Autokommando-Dateiname zur Ersetzung mit \"<afile>\""
+
+msgid "E496: no autocommand buffer number to substitute for \"<abuf>\""
+msgstr "E496: Keine Autokommando-Puffernummer zur Ersetzung mit \"<abuf>\""
+
+msgid "E497: no autocommand match name to substitute for \"<amatch>\""
+msgstr ""
+"E497: Kein passender Name eines Autokommandos zur Ersetzung mit \"<amatch>\""
+
+msgid "E498: no :source file name to substitute for \"<sfile>\""
+msgstr "E498: kein :source Dateiname zur Ersetzung mit \"<sfile>\""
+
+msgid "E842: no line number to use for \"<slnum>\""
+msgstr "E842: Keine Zeilennummer für \"<slnum>\" vorhanden."
+
+msgid "E961: no line number to use for \"<sflnum>\""
+msgstr "E961: Keine Zeilennummer für \"<slnum>\" vorhanden."
+
+#, no-c-format
+msgid "E499: Empty file name for '%' or '#', only works with \":p:h\""
+msgstr "E499: Leerer Dateiname für '%' oder '#', funktioniert nur mit \":p:h\""
+
+msgid "E500: Evaluates to an empty string"
+msgstr "E500: Ergibt eine leere Zeichenkette"
+
+msgid "E195: Cannot open viminfo file for reading"
+msgstr "E195: viminfo kann nicht zum Lesen geöffnet werden."
+
+msgid "Untitled"
+msgstr "Unbenannt"
+
+msgid "E196: No digraphs in this version"
+msgstr "E196: Keine Digraphen in dieser Version."
+
+msgid "E608: Cannot :throw exceptions with 'Vim' prefix"
+msgstr "E608: Kann nicht Exceptions mit 'Vim' Präfix werfen (:throw)"
+
+#, c-format
+msgid "Exception thrown: %s"
+msgstr "Exception geworfen: %s"
+
+#, c-format
+msgid "Exception finished: %s"
+msgstr "Exception beendet: %s"
+
+#, c-format
+msgid "Exception discarded: %s"
+msgstr "Exception verworfen: %s"
+
+#, c-format
+msgid "%s, line %ld"
+msgstr "%s, Zeile %ld"
+
+#, c-format
+msgid "Exception caught: %s"
+msgstr "Exception gefangen: %s"
+
+#, c-format
+msgid "%s made pending"
+msgstr "%s schwebend gemacht"
+
+#, c-format
+msgid "%s resumed"
+msgstr "%s wieder aufgenommen"
+
+#, c-format
+msgid "%s discarded"
+msgstr "%s verworfen"
+
+msgid "Exception"
+msgstr "Exception"
+
+msgid "Error and interrupt"
+msgstr "Fehler und Unterbrechung"
+
+msgid "Error"
+msgstr "Fehler"
+
+msgid "Interrupt"
+msgstr "Unterbrechung"
+
+msgid "E579: :if nesting too deep"
+msgstr "E579: :if Schachtelung zu tief"
+
+msgid "E580: :endif without :if"
+msgstr "E580: :endif ohne :if"
+
+msgid "E581: :else without :if"
+msgstr "E581: :else ohne :if"
+
+msgid "E582: :elseif without :if"
+msgstr "E582: :elseif ohne :if"
+
+msgid "E583: multiple :else"
+msgstr "E583: Mehrere :else"
+
+msgid "E584: :elseif after :else"
+msgstr "E584: :elseif nach :else"
+
+msgid "E585: :while/:for nesting too deep"
+msgstr "E585: :while/:for Schachtelung zu tief"
+
+msgid "E586: :continue without :while or :for"
+msgstr "E586: :continue ohne :while or :for"
+
+msgid "E587: :break without :while or :for"
+msgstr "E587: :break ohne :while oder :for"
+
+msgid "E732: Using :endfor with :while"
+msgstr "E732: Nutzung von :endfor mit :while"
+
+msgid "E733: Using :endwhile with :for"
+msgstr "E733: Nutzung von :endwhile mit :for"
+
+msgid "E601: :try nesting too deep"
+msgstr "E601: :try Schachtelung zu tief"
+
+msgid "E603: :catch without :try"
+msgstr "E603: :catch ohne :try"
+
+msgid "E604: :catch after :finally"
+msgstr "E604: :catch nach :finally"
+
+msgid "E606: :finally without :try"
+msgstr "E606: :finally ohne :try"
+
+msgid "E607: multiple :finally"
+msgstr "E607: Mehrere :finally"
+
+msgid "E602: :endtry without :try"
+msgstr "E602: :endtry ohne :try"
+
+msgid "E193: :endfunction not inside a function"
+msgstr "E193: :endfunction außerhalb einer Funktion"
+
+msgid "E788: Not allowed to edit another buffer now"
+msgstr "E788: Einen weiteren Puffer zu editieren ist im Moment nicht erlaubt"
+
+msgid "E811: Not allowed to change buffer information now"
+msgstr "E811: Puffer Information darf momentan nicht geändert werden."
+
+msgid "tagname"
+msgstr "Tag-Name"
+
+msgid " kind file\n"
+msgstr " Typ Datei\n"
+
+msgid "'history' option is zero"
+msgstr "Option 'history' ist Null"
+
+#, c-format
+msgid ""
+"\n"
+"# %s History (newest to oldest):\n"
+msgstr ""
+"\n"
+"# %s Geschichte (neueste bis älteste):\n"
+
+msgid "Command Line"
+msgstr "Befehlszeile"
+
+msgid "Search String"
+msgstr "Suchausdruck"
+
+msgid "Expression"
+msgstr "Ausdruck"
+
+msgid "Input Line"
+msgstr "Eingabe-Zeile"
+
+msgid "Debug Line"
+msgstr "Debug-Zeile"
+
+msgid "E198: cmd_pchar beyond the command length"
+msgstr "E198: cmd_pchar über die Länge des Befehls hinaus"
+
+msgid "E199: Active window or buffer deleted"
+msgstr "E199: Aktives Fenster oder Puffer gelöscht"
+
+msgid "E812: Autocommands changed buffer or buffer name"
+msgstr "E812: Autokommandos veränderten Puffer oder Puffername."
+
+msgid "Illegal file name"
+msgstr "Unzulässiger Dateiname"
+
+msgid "is a directory"
+msgstr "ist ein Verzeichnis"
+
+msgid "is not a file"
+msgstr "ist keine Datei"
+
+msgid "is a device (disabled with 'opendevice' option)"
+msgstr "ist ein Gerät (durch 'opendevice' Option deaktiviert)"
+
+msgid "[New File]"
+msgstr "[Neue Datei]"
+
+msgid "[New DIRECTORY]"
+msgstr "[Neues VERZEICHNIS]"
+
+msgid "[File too big]"
+msgstr "[Datei zu groß]"
+
+msgid "[Permission Denied]"
+msgstr "[Keine Erlaubnis]"
+
+msgid "E200: *ReadPre autocommands made the file unreadable"
+msgstr "E200: *ReadPre Autokommandos haben die Datei unlesbar gemacht"
+
+msgid "E201: *ReadPre autocommands must not change current buffer"
+msgstr ""
+"E201: *ReadPre Autokommandos dürfen nicht den aktuellen Puffer wechseln"
+
+msgid "Vim: Reading from stdin...\n"
+msgstr "Vim: Lese von stdin...\n"
+
+msgid "Reading from stdin..."
+msgstr "Lese von stdin..."
+
+msgid "E202: Conversion made file unreadable!"
+msgstr "E202: Datei wurde durch Konvertierung unlesbar!"
+
+msgid "[fifo]"
+msgstr "[fifo]"
+
+msgid "[socket]"
+msgstr "[socket]"
+
+msgid "[character special]"
+msgstr "[Zeichen spezial]"
+
+msgid "[CR missing]"
+msgstr "[CR fehlt]"
+
+msgid "[long lines split]"
+msgstr "[lange Zeilen geteilt]"
+
+msgid "[NOT converted]"
+msgstr "[NICHT konvertiert]"
+
+msgid "[converted]"
+msgstr "[konvertiert]"
+
+#, c-format
+msgid "[CONVERSION ERROR in line %ld]"
+msgstr "UMWANDLUNGSFEHLER in Zeile %ld]"
+
+#, c-format
+msgid "[ILLEGAL BYTE in line %ld]"
+msgstr "[UNZULÄSSIGES BYTE in Zeile %ld]"
+
+msgid "[READ ERRORS]"
+msgstr "[LESE-FEHLER]"
+
+msgid "Can't find temp file for conversion"
+msgstr "temporäre Datei kann nicht zum Umwandeln geöffnet werden"
+
+msgid "Conversion with 'charconvert' failed"
+msgstr "Fehler bei der Umwandlung mit 'charconvert'"
+
+msgid "can't read output of 'charconvert'"
+msgstr "Ausgabe von 'charconvert' kann nicht gelesen werden"
+
+msgid "E676: No matching autocommands for acwrite buffer"
+msgstr "E676: Keine übereinstimmenden Autokommandos für acwrite Puffer"
+
+msgid "E203: Autocommands deleted or unloaded buffer to be written"
+msgstr ""
+"E203: Autokommandos haben den zu schreibenden Puffer gelöscht oder entladen"
+
+msgid "E204: Autocommand changed number of lines in unexpected way"
+msgstr ""
+"E204: Autokommandos haben die Anzahl der Zeilen in unerwarteter Weise "
+"verändert"
+
+msgid "NetBeans disallows writes of unmodified buffers"
+msgstr "NetBeans verweigert das Schreiben von unveränderten Puffern."
+
+msgid "Partial writes disallowed for NetBeans buffers"
+msgstr "Partielles Schreiben für NetBeans Puffer verweigert"
+
+msgid "is not a file or writable device"
+msgstr "ist keine Datei oder beschreibbares Device"
+
+msgid "writing to device disabled with 'opendevice' option"
+msgstr "Schreiben auf Gerät durch 'opendevice' Option deaktiviert."
+
+msgid "is read-only (add ! to override)"
+msgstr "ist schreibgeschützt (erzwinge mit !)"
+
+msgid "E506: Can't write to backup file (add ! to override)"
+msgstr "E506: Sicherungsdatei kann nicht geschrieben werden (erzwinge mit !)"
+
+msgid "E507: Close error for backup file (add ! to override)"
+msgstr "E507: Fehler beim Schließen der Sicherungsdatei (erzwinge mit !)"
+
+msgid "E508: Can't read file for backup (add ! to override)"
+msgstr "E508: Sicherungsdatei kann nicht gelesen werden (erzwinge mit !)"
+
+msgid "E509: Cannot create backup file (add ! to override)"
+msgstr "E509: Sicherungsdatei kann nicht angelegt werden (erzwinge mit !)"
+
+msgid "E510: Can't make backup file (add ! to override)"
+msgstr "E510: Sicherungsdatei kann nicht erstellt werden (erzwinge mit !)"
+
+msgid "E214: Can't find temp file for writing"
+msgstr "E214: Temporäre Datei kann nicht zum Schreiben geöffnet werden"
+
+msgid "E213: Cannot convert (add ! to write without conversion)"
+msgstr "E213: Fehler bei der Umwandlung (schreibe ohne Umwandlung mit !)"
+
+msgid "E166: Can't open linked file for writing"
+msgstr "E166: Gelinkte Datei kann nicht zum Schreiben geöffnet werden"
+
+msgid "E212: Can't open file for writing"
+msgstr "E212: Datei kann nicht zum Schreiben geöffnet werden"
+
+msgid "E949: File changed while writing"
+msgstr "E949: Datei wurde während des Schreibens verändert"
+
+msgid "E512: Close failed"
+msgstr "E512: Fehler beim Schließen"
+
+msgid "E513: write error, conversion failed (make 'fenc' empty to override)"
+msgstr ""
+"E513: Schreibfehler, Umwandlung schlug fehl (leere 'fenc' um es zu erzwingen)"
+
+#, c-format
+msgid ""
+"E513: write error, conversion failed in line %ld (make 'fenc' empty to "
+"override)"
+msgstr ""
+"E513: Schreibfehler, Konvertierung in Zeile %ld fehlgeschlagen (leere 'fenc' "
+"um es zu erzwingen)"
+
+msgid "E514: write error (file system full?)"
+msgstr "E514: Schreibfehler (Dateisystem voll?)"
+
+msgid " CONVERSION ERROR"
+msgstr "KONVERTIERUNGSFEHLER"
+
+#, c-format
+msgid " in line %ld;"
+msgstr " in Zeile %ld"
+
+msgid "[Device]"
+msgstr "[Ausgabegerät]"
+
+msgid "[New]"
+msgstr "[Neu]"
+
+msgid " [a]"
+msgstr " [a]"
+
+msgid " appended"
+msgstr " angefügt"
+
+msgid " [w]"
+msgstr " [w]"
+
+msgid " written"
+msgstr " geschrieben"
+
+msgid "E205: Patchmode: can't save original file"
+msgstr "E205: patchmode: Original-Datei kann nicht gespeichert werden"
+
+msgid "E206: patchmode: can't touch empty original file"
+msgstr "E206: patchmode: leere Original-Datei kann nicht verändert werden"
+
+msgid "E207: Can't delete backup file"
+msgstr "E207: Backup-Datei kann nicht gelöscht werden"
+
+msgid ""
+"\n"
+"WARNING: Original file may be lost or damaged\n"
+msgstr ""
+"\n"
+"ACHTUNG: Original-Datei könnte verloren oder beschädigt sein\n"
+
+msgid "don't quit the editor until the file is successfully written!"
+msgstr ""
+"beenden Sie nicht den Editor bis die Datei erfolgreich geschrieben wurde!"
+
+msgid "[dos]"
+msgstr "[dos]"
+
+msgid "[dos format]"
+msgstr "[dos Format]"
+
+msgid "[mac]"
+msgstr "[mac]"
+
+msgid "[mac format]"
+msgstr "[mac Format]"
+
+msgid "[unix]"
+msgstr "[unix]"
+
+msgid "[unix format]"
+msgstr "[unix Format]"
+
+#, c-format
+msgid "%ld line, "
+msgid_plural "%ld lines, "
+msgstr[0] "%ld Zeile, "
+msgstr[1] "%ld Zeilen, "
+
+#, c-format
+msgid "%lld character"
+msgid_plural "%lld characters"
+msgstr[0] "%lld Zeichen"
+msgstr[1] "%lld Zeichen"
+
+msgid "[noeol]"
+msgstr "[noeol]"
+
+msgid "[Incomplete last line]"
+msgstr "[Unvollständige letzte Zeile]"
+
+msgid "WARNING: The file has been changed since reading it!!!"
+msgstr "ACHTUNG: Die Datei wurde seit dem letzten Lesen geändert!!!"
+
+msgid "Do you really want to write to it"
+msgstr "Möchten Sie sie wirklich schreiben"
+
+#, c-format
+msgid "E208: Error writing to \"%s\""
+msgstr "E208: Fehler während des Schreibens nach \"%s\""
+
+#, c-format
+msgid "E209: Error closing \"%s\""
+msgstr "E209: Fehler beim Schließen von \"%s\""
+
+#, c-format
+msgid "E210: Error reading \"%s\""
+msgstr "E210: Fehler beim Lesen von \"%s\""
+
+msgid "E246: FileChangedShell autocommand deleted buffer"
+msgstr "E246: FileChangedShell-Autokommando löschte Puffer"
+
+#, c-format
+msgid "E211: File \"%s\" no longer available"
+msgstr "E211: Datei \"%s\" ist nicht länger vorhanden"
+
+#, c-format
+msgid ""
+"W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as "
+"well"
+msgstr ""
+"W12: Achtung: Datei \"%s\" wurde verändert und der Puffer wurde in Vim "
+"ebenfalls verändert"
+
+msgid "See \":help W12\" for more info."
+msgstr "Siehe \":help W12\" für mehr Information"
+
+#, c-format
+msgid "W11: Warning: File \"%s\" has changed since editing started"
+msgstr ""
+"W11: Achtung: Datei \"%s\" wurde verändert, seit mit dem Editieren "
+"angefangen wurde"
+
+msgid "See \":help W11\" for more info."
+msgstr "Siehe \":help W11\" für mehr Information"
+
+#, c-format
+msgid "W16: Warning: Mode of file \"%s\" has changed since editing started"
+msgstr ""
+"W16: Achtung: Mode der Datei \"%s\" wurde verändert seit mit dem Editieren "
+"angefangen wurde"
+
+msgid "See \":help W16\" for more info."
+msgstr "Siehe \":help W16\" für mehr Information"
+
+#, c-format
+msgid "W13: Warning: File \"%s\" has been created after editing started"
+msgstr ""
+"W13: Achtung: Datei \"%s\" wurde erstellt, nachdem mit dem Editieren "
+"begonnen wurde"
+
+msgid "Warning"
+msgstr "Achtung"
+
+msgid ""
+"&OK\n"
+"&Load File"
+msgstr ""
+"&OK\n"
+"&Lies Datei"
+
+#, c-format
+msgid "E462: Could not prepare for reloading \"%s\""
+msgstr "E462: Konnte das Neuladen von \"%s\" nicht vorbereiten"
+
+#, c-format
+msgid "E321: Could not reload \"%s\""
+msgstr "E321: \"%s\" konnte nicht neu geladen werden"
+
+msgid "E219: Missing {."
+msgstr "E219: Es fehlt ein {."
+
+msgid "E220: Missing }."
+msgstr "E220: Es fehlt ein }."
+
+msgid "E490: No fold found"
+msgstr "E490: Keine Faltung gefunden"
+
+msgid "E350: Cannot create fold with current 'foldmethod'"
+msgstr ""
+"E350: Faltung kann mit der aktuellen Faltungsmethode nicht erzeugt werden"
+
+msgid "E351: Cannot delete fold with current 'foldmethod'"
+msgstr ""
+"E351: Faltung kann mit der aktuellen Faltungsmethode nicht gelöscht werden"
+
+#, c-format
+msgid "+--%3ld line folded "
+msgid_plural "+--%3ld lines folded "
+msgstr[0] "%3ld Zeile gefaltet "
+msgstr[1] "%3ld Zeilen gefaltet "
+
+msgid "E222: Add to read buffer"
+msgstr "E222: Zum Lesepuffer hinzufügen"
+
+msgid "E223: recursive mapping"
+msgstr "E223: rekursives Mapping"
+
+#, c-format
+msgid "E224: global abbreviation already exists for %s"
+msgstr "E224: Globale Kurzform für %s existiert bereits"
+
+#, c-format
+msgid "E225: global mapping already exists for %s"
+msgstr "E225: Globales Mapping für %s existiert bereits"
+
+#, c-format
+msgid "E226: abbreviation already exists for %s"
+msgstr "E226: Kurzform %s existiert bereits"
+
+#, c-format
+msgid "E227: mapping already exists for %s"
+msgstr "E227: Mapping für %s existiert bereits"
+
+msgid "No abbreviation found"
+msgstr "Keine Kurzform gefunden"
+
+msgid "No mapping found"
+msgstr "Kein Mapping gefunden"
+
+msgid "E228: makemap: Illegal mode"
+msgstr "E228: makemap: Unzulässiger Modus"
+
+msgid "E851: Failed to create a new process for the GUI"
+msgstr "E851: Erstellung des GUI-Prozesses fehlgeschlagen"
+
+msgid "E852: The child process failed to start the GUI"
+msgstr "E852: Der Kindprozess zum Starten der GUI fehlgeschlagen."
+
+msgid "E229: Cannot start the GUI"
+msgstr "E229: GUI kann nicht gestartet werden."
+
+#, c-format
+msgid "E230: Cannot read from \"%s\""
+msgstr "E230: Kann nicht von \"%s\" lesen"
+
+msgid "E665: Cannot start GUI, no valid font found"
+msgstr "E665: GUI kann nicht gestartet werden, keine gültige Schrift gefunden."
+
+msgid "E231: 'guifontwide' invalid"
+msgstr "E231: 'guifontwide' ungültig"
+
+msgid "E599: Value of 'imactivatekey' is invalid"
+msgstr "E599: Wert von 'imactivatekey' ist ungültig"
+
+#, c-format
+msgid "E254: Cannot allocate color %s"
+msgstr "E254: Kann die Farbe %s nicht zuweisen."
+
+msgid "No match at cursor, finding next"
+msgstr "Kein Treffer beim Cursor, finde den nächsten"
+
+msgid "<cannot open> "
+msgstr "<kann nicht öffnen> "
+
+#, c-format
+msgid "E616: vim_SelFile: can't get font %s"
+msgstr "E616: vim_SelFile: kann Schriftart %s nicht erhalten"
+
+msgid "E614: vim_SelFile: can't return to current directory"
+msgstr "E614: vim_SelFile: kann nicht zum aktuellen Verzeichnis zurückkehren."
+
+msgid "Pathname:"
+msgstr "Pfadname:"
+
+msgid "E615: vim_SelFile: can't get current directory"
+msgstr "E615: vim_SelFile: aktuelles Verzeichnis kann nicht ermittelt werden."
+
+msgid "OK"
+msgstr "OK"
+
+msgid "Cancel"
+msgstr "Abbrechen"
+
+msgid "Scrollbar Widget: Could not get geometry of thumb pixmap."
+msgstr "Scrollbar Widget: Geometrie des Bildchens kann nicht ermittelt werden."
+
+msgid "Vim dialog"
+msgstr "Vim-Dialog"
+
+msgid "E232: Cannot create BalloonEval with both message and callback"
+msgstr ""
+"E232: BalloonEval kann nicht sowohl mit \"message\" als auch \"callback\" "
+"erzeugt werden"
+
+msgid "_Cancel"
+msgstr "_Abbrechen"
+
+msgid "_Save"
+msgstr "_Speichern"
+
+msgid "_Open"
+msgstr "_Öffnen"
+
+msgid "_OK"
+msgstr "_OK"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"&Cancel"
+msgstr ""
+"&Ja\n"
+"&Nein\n"
+"&Abbrechen"
+
+msgid "Yes"
+msgstr "Ja"
+
+msgid "No"
+msgstr "Nein"
+
+msgid "Input _Methods"
+msgstr "Eingabe _Methoden"
+
+msgid "VIM - Search and Replace..."
+msgstr "VIM - Suchen und Ersetzen..."
+
+msgid "VIM - Search..."
+msgstr "VIM - Suchen..."
+
+msgid "Find what:"
+msgstr "Wonach suchen:"
+
+msgid "Replace with:"
+msgstr "Ersetzen mit:"
+
+msgid "Match whole word only"
+msgstr "Nur ganzes Wort suchen"
+
+msgid "Match case"
+msgstr "Groß-/Kleinschreibung"
+
+msgid "Direction"
+msgstr "Richtung"
+
+msgid "Up"
+msgstr "Aufwärts"
+
+msgid "Down"
+msgstr "Abwärts"
+
+msgid "Find Next"
+msgstr "Suche Nächstes"
+
+msgid "Replace"
+msgstr "Ersetzen"
+
+msgid "Replace All"
+msgstr "Alle ersetzen"
+
+msgid "_Close"
+msgstr "_Schließen"
+
+msgid "Vim: Received \"die\" request from session manager\n"
+msgstr "Vim: \"die\"-Request von Session-Manager erhalten\n"
+
+msgid "Close tab"
+msgstr "Reiter schließen"
+
+msgid "New tab"
+msgstr "Neuer Reiter"
+
+msgid "Open Tab..."
+msgstr "Öffne Reiter..."
+
+msgid "Vim: Main window unexpectedly destroyed\n"
+msgstr "Vim: Hauptfenster unerwartet zerstört\n"
+
+msgid "&Filter"
+msgstr "&Filter"
+
+msgid "&Cancel"
+msgstr "&Abbrechen"
+
+msgid "Directories"
+msgstr "Verzeichnisse"
+
+msgid "Filter"
+msgstr "Filter"
+
+msgid "&Help"
+msgstr "&Hilfe"
+
+msgid "Files"
+msgstr "Dateien"
+
+msgid "&OK"
+msgstr "&OK"
+
+msgid "Selection"
+msgstr "Auswahl"
+
+msgid "Find &Next"
+msgstr "&Nächste"
+
+msgid "&Replace"
+msgstr "&Ersetze"
+
+msgid "Replace &All"
+msgstr "Ersetze &alles"
+
+msgid "&Undo"
+msgstr "&Rückgängig"
+
+msgid "Open tab..."
+msgstr "Öffne Reiter..."
+
+msgid "Find string"
+msgstr "Suche Zeichenkette"
+
+msgid "Find & Replace"
+msgstr "Suche & Ersetze"
+
+msgid "Not Used"
+msgstr "Nicht verwendet"
+
+msgid "Directory\t*.nothing\n"
+msgstr "Verzeichnis\t*.nichts\n"
+
+#, c-format
+msgid "E671: Cannot find window title \"%s\""
+msgstr "E671: Kann Fenstertitel \"%s\" nicht finden"
+
+#, c-format
+msgid "E243: Argument not supported: \"-%s\"; Use the OLE version."
+msgstr ""
+"E243: Argument wird nicht unterstützt: \"-%s\"; verwende die OLE Version."
+
+msgid "E672: Unable to open window inside MDI application"
+msgstr "E672: Kann Fenster nicht innerhalb einer MDI Anwendung öffnen"
+
+msgid "Vim E458: Cannot allocate colormap entry, some colors may be incorrect"
+msgstr ""
+"Vim E458: \"Colormap\"-Eintrag kann nicht zugewiesen werden, einige Farben "
+"können falsch sein"
+
+#, c-format
+msgid "E250: Fonts for the following charsets are missing in fontset %s:"
+msgstr ""
+"E250: Schriftarten für die folgenden Zeichensätze fehlen im Fontset %s:"
+
+#, c-format
+msgid "E252: Fontset name: %s"
+msgstr "E252: Fontset Name: %s"
+
+#, c-format
+msgid "Font '%s' is not fixed-width"
+msgstr "Schriftart '%s' hat keine feste Breite"
+
+#, c-format
+msgid "E253: Fontset name: %s"
+msgstr "E253: Fontset Name: %s"
+
+#, c-format
+msgid "Font0: %s"
+msgstr "Schriftart 0: %s"
+
+#, c-format
+msgid "Font%d: %s"
+msgstr "Schriftart %d: %s"
+
+#, c-format
+msgid "Font%d width is not twice that of font0"
+msgstr "Breite der Schriftart%d ist nicht doppelt so breit wie Schriftart0"
+
+#, c-format
+msgid "Font0 width: %d"
+msgstr "Schriftart 0 Breite: %d"
+
+#, c-format
+msgid "Font%d width: %d"
+msgstr "Schriftart %d Breite: %d"
+
+msgid "Invalid font specification"
+msgstr "Ungültige Spezifikation der Schriftart"
+
+msgid "&Dismiss"
+msgstr "&Aufheben"
+
+msgid "no specific match"
+msgstr "keine spezifische Übereinstimmung"
+
+msgid "Vim - Font Selector"
+msgstr "Vim - Auswahl der Schriftart"
+
+msgid "Name:"
+msgstr "Name:"
+
+msgid "Show size in Points"
+msgstr "Zeige Größe in Punkten"
+
+msgid "Encoding:"
+msgstr "Zeichensatz:"
+
+msgid "Font:"
+msgstr "Schriftart:"
+
+msgid "Style:"
+msgstr "Stil:"
+
+msgid "Size:"
+msgstr "Größe:"
+
+msgid "E256: Hangul automata ERROR"
+msgstr "E256: Hangul-Automat Fehler"
+
+msgid "E550: Missing colon"
+msgstr "E550: Fehlender Doppelpunkt"
+
+msgid "E551: Illegal component"
+msgstr "E551: Unzulässige Komponente"
+
+msgid "E552: digit expected"
+msgstr "E552: Ziffer erwartet"
+
+#, c-format
+msgid "Page %d"
+msgstr "Seite %d"
+
+msgid "No text to be printed"
+msgstr "Kein Text zum Drucken"
+
+#, c-format
+msgid "Printing page %d (%d%%)"
+msgstr "Drucke Seite %d (%d%%)"
+
+#, c-format
+msgid " Copy %d of %d"
+msgstr " Kopiere %d von %d"
+
+#, c-format
+msgid "Printed: %s"
+msgstr "Gedruckt: %s"
+
+msgid "Printing aborted"
+msgstr "Ausdruck abgebrochen"
+
+msgid "E455: Error writing to PostScript output file"
+msgstr "E455: Fehler beim Schreiben der PostScript-Ausgabedatei"
+
+#, c-format
+msgid "E624: Can't open file \"%s\""
+msgstr "E624: Datei \"%s\" kann nicht geöffnet werden."
+
+#, c-format
+msgid "E457: Can't read PostScript resource file \"%s\""
+msgstr "E457: PostScript Ressource-Datei \"%s\" kann nicht gelesen werden."
+
+#, c-format
+msgid "E618: file \"%s\" is not a PostScript resource file"
+msgstr "E618: Datei \"%s\" ist keine PostScript Ressource-Datei."
+
+#, c-format
+msgid "E619: file \"%s\" is not a supported PostScript resource file"
+msgstr "E619: Datei \"%s\" ist keine unterstützte PostScript Ressource-Datei."
+
+#, c-format
+msgid "E621: \"%s\" resource file has wrong version"
+msgstr "E621: \"%s\" Ressource-Datei hat die falsche Version."
+
+msgid "E673: Incompatible multi-byte encoding and character set."
+msgstr "E673: Inkompatible Multi-Byte Kodierung und Zeichensatz"
+
+msgid "E674: printmbcharset cannot be empty with multi-byte encoding."
+msgstr "E674: printmbcharset darf nicht leer sein mit Multi-Byte Kodierung."
+
+msgid "E675: No default font specified for multi-byte printing."
+msgstr "E675: Keine Standardschriftart angegeben für Multi-Byte Ausdruck."
+
+msgid "E324: Can't open PostScript output file"
+msgstr "E324: PostScript Ausgabe-Datei kann nicht geöffnet werden"
+
+#, c-format
+msgid "E456: Can't open file \"%s\""
+msgstr "E456: Datei \"%s\" kann nicht geöffnet werden."
+
+msgid "E456: Can't find PostScript resource file \"prolog.ps\""
+msgstr "E456: PostScript Ressource-Datei \"prolog.ps\" nicht gefunden."
+
+msgid "E456: Can't find PostScript resource file \"cidfont.ps\""
+msgstr "E456: PostScript Ressource-Datei \"cidfont.ps\" nicht gefunden."
+
+#, c-format
+msgid "E456: Can't find PostScript resource file \"%s.ps\""
+msgstr "E456: PostScript Ressource-Datei \"%s\" nicht gefunden"
+
+#, c-format
+msgid "E620: Unable to convert to print encoding \"%s\""
+msgstr ""
+"E620: Umwandlung nach dem Zeichensatz für den Ausdruck \"%s\" fehlgeschlagen"
+
+msgid "Sending to printer..."
+msgstr "Schicke zum Drucker..."
+
+msgid "E365: Failed to print PostScript file"
+msgstr "E365: Druck der PostScript-Datei schlug fehl"
+
+msgid "Print job sent."
+msgstr "Druckauftrag abgeschickt"
+
+msgid "Add a new database"
+msgstr "Eine neue Datenbank hinzufügen"
+
+msgid "Query for a pattern"
+msgstr "Muster suchen"
+
+msgid "Show this message"
+msgstr "diese Nachricht anzeigen"
+
+msgid "Kill a connection"
+msgstr "Verbindung beenden"
+
+msgid "Reinit all connections"
+msgstr "Verbindungen reinitialisieren"
+
+msgid "Show connections"
+msgstr "Verbindungen anzeigen"
+
+#, c-format
+msgid "E560: Usage: cs[cope] %s"
+msgstr "E560: Verwendung: cs[cope] %s"
+
+msgid "This cscope command does not support splitting the window.\n"
+msgstr "Dieser cscope-Befehl unterstützt nicht das Teilen des Fensters.\n"
+
+msgid "E562: Usage: cstag <ident>"
+msgstr "E562: Verwendung: cstag <ident>"
+
+msgid "E257: cstag: tag not found"
+msgstr "E257: cstag: Tag nicht gefunden"
+
+#, c-format
+msgid "E563: stat(%s) error: %d"
+msgstr "E563: stat(%s) Fehler: %d"
+
+msgid "E563: stat error"
+msgstr "E563: 'stat' Fehler"
+
+#, c-format
+msgid "E564: %s is not a directory or a valid cscope database"
+msgstr "E564: %s ist kein Verzeichnis oder eine gültige cscope Datenbank"
+
+#, c-format
+msgid "Added cscope database %s"
+msgstr "csope Datenbank %s hinzugefügt"
+
+#, c-format
+msgid "E262: error reading cscope connection %d"
+msgstr "E262: Fehler beim Lesen der cscope Verbindung %d"
+
+msgid "E561: unknown cscope search type"
+msgstr "E561: Unbekannter cscope Suchtyp"
+
+msgid "E566: Could not create cscope pipes"
+msgstr "E566: cscope Pipes konnten nicht angelegt werden"
+
+msgid "E622: Could not fork for cscope"
+msgstr "E622: Konnte Fork für cscope nicht erstellen."
+
+msgid "cs_create_connection setpgid failed"
+msgstr "cs_create_connection setpgid fehlgeschlagen"
+
+msgid "cs_create_connection exec failed"
+msgstr "cs_create_connection exec fehlgeschlagen"
+
+msgid "cs_create_connection: fdopen for to_fp failed"
+msgstr "cs_create_connection: fdopen von to_fp fehlgeschlagen"
+
+msgid "cs_create_connection: fdopen for fr_fp failed"
+msgstr "cs_create_connection: fdopen von fr_fp fehlgeschlagen"
+
+msgid "E623: Could not spawn cscope process"
+msgstr "E623: Konnte cscope Prozess nicht starten"
+
+msgid "E567: no cscope connections"
+msgstr "E567: Keine cscope Verbindungen"
+
+#, c-format
+msgid "E469: invalid cscopequickfix flag %c for %c"
+msgstr "E469: Unzulässiges cscopequickfix Flag %c für %c"
+
+#, c-format
+msgid "E259: no matches found for cscope query %s of %s"
+msgstr "E259: keine Übereinstimmungen gefunden für cscope Abfrage %s aus %s"
+
+msgid "cscope commands:\n"
+msgstr "cscope Befehle:\n"
+
+#, c-format
+msgid "%-5s: %s%*s (Usage: %s)"
+msgstr "%-5s: %s%*s (Verwendung: %s)"
+
+msgid ""
+"\n"
+" a: Find assignments to this symbol\n"
+" c: Find functions calling this function\n"
+" d: Find functions called by this function\n"
+" e: Find this egrep pattern\n"
+" f: Find this file\n"
+" g: Find this definition\n"
+" i: Find files #including this file\n"
+" s: Find this C symbol\n"
+" t: Find this text string\n"
+msgstr ""
+"\n"
+" a: Finde Zuweisungen dieses Symbols\n"
+" c: Finde Funktionen, die diese Funktion aufrufen\n"
+" d: Finde Funktionen, die von dieser Funktion aufgerufen werden\n"
+" e: Finde dieses egrep Muster\n"
+" f: Finde diese Datei\n"
+" g: Finde diese Definition\n"
+" i: Finde Dateien, die diese Datei #inkludieren\n"
+" s: Finde dieses C Symbol\n"
+" t: Finde diese Zeichenkette\n"
+
+#, c-format
+msgid "E625: cannot open cscope database: %s"
+msgstr "E625: Kann cscope Datenbank nicht öffnen: %s"
+
+msgid "E626: cannot get cscope database information"
+msgstr "E626: Kann cscope Datenbank-Informationen nicht bekommen"
+
+msgid "E568: duplicate cscope database not added"
+msgstr "E568: doppelte cscope Datenbank nicht hinzugefügt"
+
+#, c-format
+msgid "E261: cscope connection %s not found"
+msgstr "E261: cscope Verbindung %s nicht gefunden"
+
+#, c-format
+msgid "cscope connection %s closed"
+msgstr "cscope Verbindung %s geschlossen"
+
+msgid "E570: fatal error in cs_manage_matches"
+msgstr "E570: Fataler Fehler in cs_manage_matches"
+
+#, c-format
+msgid "Cscope tag: %s"
+msgstr "Cscope Tag: %s"
+
+msgid ""
+"\n"
+" # line"
+msgstr ""
+"\n"
+" # Zeile"
+
+msgid "filename / context / line\n"
+msgstr "Dateiname / Kontext / Zeile\n"
+
+#, c-format
+msgid "E609: Cscope error: %s"
+msgstr "E609: Cscope Fehler: %s"
+
+msgid "All cscope databases reset"
+msgstr "Alle cscope Datenbanken zurückgesetzt"
+
+msgid "no cscope connections\n"
+msgstr "keine cscope-Verbindungen\n"
+
+msgid " # pid database name prepend path\n"
+msgstr " # pid Datenbank Name\t führender Pfad\n"
+
+msgid "Lua library cannot be loaded."
+msgstr "Lua bibliothek kann nicht geladen werden."
+
+msgid "cannot save undo information"
+msgstr "kann Information für die Wiederherstellung nicht speichern"
+
+msgid ""
+"E815: Sorry, this command is disabled, the MzScheme libraries could not be "
+"loaded."
+msgstr ""
+"E815: Dieser Befehl ist nicht verfügbar, da die MzScheme Bibliotheken nicht "
+"geladen werden konnte."
+
+msgid ""
+"E895: Sorry, this command is disabled, the MzScheme's racket/base module "
+"could not be loaded."
+msgstr ""
+"E895 Dieser Befehl ist nicht verfügbar, da die MzScheme racket/basis Module "
+"nicht geladen werden konnten."
+
+msgid "invalid expression"
+msgstr "ungültiger Ausdruck"
+
+msgid "expressions disabled at compile time"
+msgstr "Ausdrücke wurden zur Zeit des Übersetzens nicht zugelassen"
+
+msgid "hidden option"
+msgstr "versteckte Option"
+
+msgid "unknown option"
+msgstr "unbekannte Option"
+
+msgid "window index is out of range"
+msgstr "Fensterindex außerhalb des zulässigen Bereichs"
+
+msgid "couldn't open buffer"
+msgstr "konnte Puffer nicht öffnen"
+
+msgid "cannot delete line"
+msgstr "Zeile kann nicht gelöscht werden"
+
+msgid "cannot replace line"
+msgstr "Zeile kann nicht ersetzt werden"
+
+msgid "cannot insert line"
+msgstr "Zeile kann nicht eingefügt werden"
+
+msgid "string cannot contain newlines"
+msgstr "Zeichenfolge kann keine Zeilenwechsel enthalten"
+
+msgid "error converting Scheme values to Vim"
+msgstr "Fehler beim Konvertieren der Scheme Werte nach Vim."
+
+msgid "Vim error: ~a"
+msgstr "Vim Fehler: ~a"
+
+msgid "Vim error"
+msgstr "Vim Fehler"
+
+msgid "buffer is invalid"
+msgstr "ungültiger Puffer"
+
+msgid "window is invalid"
+msgstr "ungültiges Fenster"
+
+msgid "linenr out of range"
+msgstr "Zeilennummer außerhalb des zulässigen Bereichs"
+
+msgid "not allowed in the Vim sandbox"
+msgstr "innerhalb der Vim-Sandbox nicht erlaubt"
+
+msgid "E836: This Vim cannot execute :python after using :py3"
+msgstr "E836: Dieser Vim kann :python nicht nach :py3 ausführen."
+
+msgid ""
+"E263: Sorry, this command is disabled, the Python library could not be "
+"loaded."
+msgstr ""
+"E263: Dieser Befehl ist nicht verfügbar, die Python-Bibliothek konnte nicht "
+"geladen werden"
+
+msgid ""
+"E887: Sorry, this command is disabled, the Python's site module could not be "
+"loaded."
+msgstr ""
+"E887: Dieser Befehl ist nicht verfügbar, da das Python site Module nicht "
+"geladen werden konnte."
+
+msgid "E659: Cannot invoke Python recursively"
+msgstr "E659: Kann Python nicht rekursiv ausführen"
+
+msgid "E837: This Vim cannot execute :py3 after using :python"
+msgstr "E837: Dieser Vim kann :py3 nicht nach :python ausführen."
+
+msgid "E265: $_ must be an instance of String"
+msgstr "E265: $_ muss eine Instanz einer Zeichenkette sein"
+
+msgid ""
+"E266: Sorry, this command is disabled, the Ruby library could not be loaded."
+msgstr ""
+"E266: Dieser Befehl ist nicht verfügbar, die Ruby Bibliothek konnte nicht "
+"geladen werden"
+
+msgid "E267: unexpected return"
+msgstr "E267: Unerwartetes 'return'"
+
+msgid "E268: unexpected next"
+msgstr "E268: Unerwartetes 'next'"
+
+msgid "E269: unexpected break"
+msgstr "E269: Unerwartetes 'break'"
+
+msgid "E270: unexpected redo"
+msgstr "E270: Unerwartetes 'redo'"
+
+msgid "E271: retry outside of rescue clause"
+msgstr "E271: 'retry' außerhalb der 'rescue clause'"
+
+msgid "E272: unhandled exception"
+msgstr "E272: Unbehandelte Exception"
+
+#, c-format
+msgid "E273: unknown longjmp status %d"
+msgstr "E273: Unbekannter longjmp Status %d"
+
+msgid "invalid buffer number"
+msgstr "ungültige Puffernummer"
+
+msgid "not implemented yet"
+msgstr "nicht implementiert"
+
+msgid "cannot set line(s)"
+msgstr "kann Zeile(n) nicht setzen"
+
+msgid "invalid mark name"
+msgstr "ungültiger Name einer Markierung"
+
+msgid "mark not set"
+msgstr "Markierung nicht gesetzt"
+
+#, c-format
+msgid "row %d column %d"
+msgstr "Zeile %d Spalte %d"
+
+msgid "cannot insert/append line"
+msgstr "kann Zeile nicht ein-/anfügen"
+
+msgid "line number out of range"
+msgstr "Zeilennummer außerhalb des zulässigen Bereichs"
+
+msgid "unknown flag: "
+msgstr "unbekanntes Flag: "
+
+msgid "unknown vimOption"
+msgstr "unbekannte vimOption"
+
+msgid "keyboard interrupt"
+msgstr "Tastatur-Interrupt"
+
+msgid "vim error"
+msgstr "vim Fehler"
+
+msgid "cannot create buffer/window command: object is being deleted"
+msgstr ""
+"Puffer/Fenster-Befehl kann nicht ausgeführt werden: das Objekt wird gelöscht"
+
+msgid ""
+"cannot register callback command: buffer/window is already being deleted"
+msgstr ""
+"kann keinen Callback-Befehl registrieren: Puffer/Fenster ist bereits gelöscht"
+
+msgid ""
+"E280: TCL FATAL ERROR: reflist corrupt!? Please report this to vim-dev@vim."
+"org"
+msgstr ""
+"E280: TCL FATALER FEHLER: reflist kaputt!? Bitte vim-dev@vim.org "
+"benachrichtigen."
+
+msgid "cannot register callback command: buffer/window reference not found"
+msgstr ""
+"kann keinen Callback-Befehl registrieren: Puffer/Fenster-Referenz nicht "
+"gefunden"
+
+msgid ""
+"E571: Sorry, this command is disabled: the Tcl library could not be loaded."
+msgstr ""
+"E571: Dieser Befehl ist nicht verfügbar: die Tcl Bibliothek konnte nicht "
+"geladen werden"
+
+#, c-format
+msgid "E572: exit code %d"
+msgstr "E572: Exit-Code %d"
+
+msgid "cannot get line"
+msgstr "kann Zeile nicht erhalten"
+
+msgid "Unable to register a command server name"
+msgstr "Befehls-Server Name kann nicht registriert werden"
+
+msgid "E248: Failed to send command to the destination program"
+msgstr "E248: Schicken des Befehls zum Ziel-Programm schlug fehl"
+
+#, c-format
+msgid "E573: Invalid server id used: %s"
+msgstr "E573: Ungültige Server ID verwendet: %s"
+
+msgid "E251: VIM instance registry property is badly formed. Deleted!"
+msgstr "E251: Registry-Eigenschaft der VIM Instanz ist fehlerhaft. Gelöscht!"
+
+#, c-format
+msgid "E938: Duplicate key in JSON: \"%s\""
+msgstr "E938: Doppelter Schlüssel im JSON: \"%s\""
+
+#, c-format
+msgid "E696: Missing comma in List: %s"
+msgstr "E696: Fehlendes Komma in der Liste: %s"
+
+#, c-format
+msgid "E697: Missing end of List ']': %s"
+msgstr "E697: Fehlendes Ende der Liste ']': %s"
+
+msgid "Unknown option argument"
+msgstr "Unbekanntes Optionsargument"
+
+msgid "Too many edit arguments"
+msgstr "Zu viele Editor-Argumente"
+
+msgid "Argument missing after"
+msgstr "Argument fehlt nach"
+
+msgid "Garbage after option argument"
+msgstr "Schrott nach dem Optionsargument"
+
+msgid "Too many \"+command\", \"-c command\" or \"--cmd command\" arguments"
+msgstr "Zu viele \"+command\", \"-c command\" oder \"--cmd command\" Argumente"
+
+msgid "Invalid argument for"
+msgstr "Ungültiges Argument für"
+
+#, c-format
+msgid "%d files to edit\n"
+msgstr "%d Dateien zum Editieren\n"
+
+msgid "netbeans is not supported with this GUI\n"
+msgstr "netbeans wird in dieser GUI nicht unterstützt\n"
+
+msgid "'-nb' cannot be used: not enabled at compile time\n"
+msgstr ""
+"'-nb' kann nicht benutzt werden: Wurde zum Zeitpunkt des Übersetzens "
+"deaktiviert.\n"
+
+msgid "This Vim was not compiled with the diff feature."
+msgstr "Vim wurde nicht mit der \"diff\"-Eigenschaft übersetzt."
+
+msgid "Attempt to open script file again: \""
+msgstr "Versuche, die Skript-Datei erneut zu öffnen: \""
+
+msgid "Cannot open for reading: \""
+msgstr "kann nicht zum Lesen geöffnet werden: \""
+
+msgid "Cannot open for script output: \""
+msgstr "kann nicht zur Skript-Ausgabe geöffnet werden: \""
+
+msgid "Vim: Error: Failure to start gvim from NetBeans\n"
+msgstr "Vim: Fehler: Konnte gvim nicht von NetBeans aus starten\n"
+
+msgid "Vim: Error: This version of Vim does not run in a Cygwin terminal\n"
+msgstr ""
+"Vim: Fehler: Diese Version von Vim kann nicht in einem Cygwin Terminal "
+"ausgeführt werden\n"
+
+msgid "Vim: Warning: Output is not to a terminal\n"
+msgstr "Vim: Achtung: Die Ausgabe erfolgt nicht auf einem Terminal\n"
+
+msgid "Vim: Warning: Input is not from a terminal\n"
+msgstr "Vim: Achtung: Die Eingabe kommt nicht von einem Terminal\n"
+
+msgid "pre-vimrc command line"
+msgstr "pre-vimrc Befehls-Zeile"
+
+#, c-format
+msgid "E282: Cannot read from \"%s\""
+msgstr "E282: Kann nicht von \"%s\" lesen"
+
+msgid ""
+"\n"
+"More info with: \"vim -h\"\n"
+msgstr ""
+"\n"
+"Weitere Informationen mit: \"vim -h\"\n"
+
+msgid "[file ..] edit specified file(s)"
+msgstr "[Datei ..] editiere die angegebenen Datei(-en)"
+
+msgid "- read text from stdin"
+msgstr "- lese Text von stdin"
+
+msgid "-t tag edit file where tag is defined"
+msgstr "-t tag öffne Datei in der der Tag definiert wurde"
+
+msgid "-q [errorfile] edit file with first error"
+msgstr "-q [Fehler-Datei] öffne Datei mit erstem Fehler"
+
+msgid ""
+"\n"
+"\n"
+"Usage:"
+msgstr ""
+"\n"
+"\n"
+"Verwendung:"
+
+msgid " vim [arguments] "
+msgstr " vim [Argumente] "
+
+msgid ""
+"\n"
+" or:"
+msgstr ""
+"\n"
+" oder:"
+
+msgid ""
+"\n"
+"Where case is ignored prepend / to make flag upper case"
+msgstr ""
+"\n"
+"Wo Groß/Kleinschreibung ignoriert wird, füge / am Anfang hinzu um das Flag "
+"groß zuschreiben."
+
+msgid ""
+"\n"
+"\n"
+"Arguments:\n"
+msgstr ""
+"\n"
+"\n"
+"Argumente:\n"
+
+msgid "--\t\t\tOnly file names after this"
+msgstr "--\t\t\tHiernach nur Dateinamen"
+
+msgid "--literal\t\tDon't expand wildcards"
+msgstr "--literal\t\tPlatzhalter werden nicht ausgewertet"
+
+msgid "-register\t\tRegister this gvim for OLE"
+msgstr "-register\t\tRegistriere diesen gvim in OLE"
+
+msgid "-unregister\t\tUnregister gvim for OLE"
+msgstr "-unregister\t\tDeregistriere gvim aus OLE"
+
+msgid "-g\t\t\tRun using GUI (like \"gvim\")"
+msgstr "-g\t\t\tStart als GUI (wie \"gvim\")"
+
+msgid "-f or --nofork\tForeground: Don't fork when starting GUI"
+msgstr "-f\t\t\tVordergrund: Kein \"fork\" beim Start der GUI"
+
+msgid "-v\t\t\tVi mode (like \"vi\")"
+msgstr "-v\t\t\tVi Modus (wie \"vi\")"
+
+msgid "-e\t\t\tEx mode (like \"ex\")"
+msgstr "-e\t\t\tEx Modus (wie \"ex\")"
+
+msgid "-E\t\t\tImproved Ex mode"
+msgstr "-E\t\t\tVerbesserter Ex Modus"
+
+msgid "-s\t\t\tSilent (batch) mode (only for \"ex\")"
+msgstr "-s\t\t\tLeiser (Batch) Modus (nur für \"ex\")"
+
+msgid "-d\t\t\tDiff mode (like \"vimdiff\")"
+msgstr "-d\t\t\tDiff Modus (wie \"vimdiff\")"
+
+msgid "-y\t\t\tEasy mode (like \"evim\", modeless)"
+msgstr "-y\t\t\tLeichter Modus (wie \"evim\", ohne Modi)"
+
+msgid "-R\t\t\tReadonly mode (like \"view\")"
+msgstr "-R\t\t\tNur Lese-Modus (wie \"view\")"
+
+msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
+msgstr "-Z\t\t\tEingeschränkter Modus (wie \"rvim\")"
+
+msgid "-m\t\t\tModifications (writing files) not allowed"
+msgstr "-m\t\t\tModifikationen (Schreiben von Dateien) sind nicht erlaubt"
+
+msgid "-M\t\t\tModifications in text not allowed"
+msgstr "-M\t\t\tModifikationen im Text nicht erlaubt"
+
+msgid "-b\t\t\tBinary mode"
+msgstr "-b\t\t\tBinärmodus"
+
+msgid "-l\t\t\tLisp mode"
+msgstr "-l\t\t\tLisp Modus"
+
+msgid "-C\t\t\tCompatible with Vi: 'compatible'"
+msgstr "-C\t\t\tKompatibel zu Vi: 'compatible'"
+
+msgid "-N\t\t\tNot fully Vi compatible: 'nocompatible'"
+msgstr "-N\t\t\tNicht ganz kompatibel zu Vi: 'nocompatible'"
+
+msgid "-V[N][fname]\t\tBe verbose [level N] [log messages to fname]"
+msgstr "-V[N][Datei]\t\tVerbose [level N] [Logge nach Datei]"
+
+msgid "-D\t\t\tDebugging mode"
+msgstr "-D\t\t\tDebug-Modus"
+
+msgid "-n\t\t\tNo swap file, use memory only"
+msgstr "-n\t\t\tKeine Auslagerungsdatei, verwende nur Speicher"
+
+msgid "-r\t\t\tList swap files and exit"
+msgstr "-r\t\t\tListe nur Auslagerungsdateien auf"
+
+msgid "-r (with file name)\tRecover crashed session"
+msgstr "-r (mit Dateiname)\tStelle abgestürzte Session wieder her"
+
+msgid "-L\t\t\tSame as -r"
+msgstr "-L\t\t\tGenauso wie -r"
+
+msgid "-f\t\t\tDon't use newcli to open window"
+msgstr "-f\t\t\tVerwende nicht newcli zum Öffnen eines neuen Fensters"
+
+msgid "-dev <device>\t\tUse <device> for I/O"
+msgstr "-dev <device>\t\tVerwende <device> for I/O"
+
+msgid "-A\t\t\tStart in Arabic mode"
+msgstr "-A\t\t\tStart im Arabischen Modus"
+
+msgid "-H\t\t\tStart in Hebrew mode"
+msgstr "-H\t\t\tStart im Hebräischen Modus"
+
+msgid "-F\t\t\tStart in Farsi mode"
+msgstr "-F\t\t\tStart im Farsi Modus"
+
+msgid "-T <terminal>\tSet terminal type to <terminal>"
+msgstr "-T <terminal>\tSetze Terminaltyp auf <terminal>"
+
+msgid "--not-a-term\t\tSkip warning for input/output not being a terminal"
+msgstr ""
+"--not-a-term\t\tKeine Warnung ausgeben, wenn Eingabe/Ausgabe nicht auf einem "
+"Terminal ausgegeben wird"
+
+msgid "--ttyfail\t\tExit if input or output is not a terminal"
+msgstr ""
+"--ttyfail\t\tBeende, wenn Ein- oder Ausgabe nicht auf einem Terminal "
+"ausgegeben wird"
+
+msgid "-u <vimrc>\t\tUse <vimrc> instead of any .vimrc"
+msgstr "-u <vimrc>\t\tBenutze <vimrc> anstatt jeglicher .vimrc"
+
+msgid "-U <gvimrc>\t\tUse <gvimrc> instead of any .gvimrc"
+msgstr "-U <gvimrc>\t\tBenutze <gvimrc> anstatt jeglicher .gvimrc"
+
+msgid "--noplugin\t\tDon't load plugin scripts"
+msgstr "--noplugin\t\tlade keine \"plugin\"-Skripte"
+
+msgid "-p[N]\t\tOpen N tab pages (default: one for each file)"
+msgstr "-p[N]\t\tÖffne N Reiter (Vorgabe: einen für jede Datei)"
+
+msgid "-o[N]\t\tOpen N windows (default: one for each file)"
+msgstr "-o[N]\t\tÖffne N Fenster (Vorgabe: für jede Datei eins)"
+
+msgid "-O[N]\t\tLike -o but split vertically"
+msgstr "-O[N]\t\tWie -o, aber teile vertikal"
+
+msgid "+\t\t\tStart at end of file"
+msgstr "+\t\t\tStarte am Ende der Datei"
+
+msgid "+<lnum>\t\tStart at line <lnum>"
+msgstr "+<lnum>\t\tStart in Zeile <lnum>"
+
+msgid "--cmd <command>\tExecute <command> before loading any vimrc file"
+msgstr "--cmd <Befehl>\tFühre <Befehl> vor dem Laden jeglicher vimrc-Datei aus"
+
+msgid "-c <command>\t\tExecute <command> after loading the first file"
+msgstr "-c <Befehl>\t\tFühre <Befehl> nach dem Laden der ersten Datei aus"
+
+msgid "-S <session>\t\tSource file <session> after loading the first file"
+msgstr "-S <session>\t\tLese Datei <session> nach dem Laden der ersten Datei"
+
+msgid "-s <scriptin>\tRead Normal mode commands from file <scriptin>"
+msgstr ""
+"-s <scriptin>\tLese Normal-Modus Befehle aus der Skript-Datei <scriptin>"
+
+msgid "-w <scriptout>\tAppend all typed commands to file <scriptout>"
+msgstr ""
+"-w <scriptout>\tAlle getippten Befehle der Skript-Datei <scriptout> anfügen"
+
+msgid "-W <scriptout>\tWrite all typed commands to file <scriptout>"
+msgstr ""
+"-W <scriptout>\tSchreibe getippte Befehle in die Skript-Datei <scriptout>"
+
+msgid "-x\t\t\tEdit encrypted files"
+msgstr "-x\t\t\tEditiere verschlüsselte Dateien"
+
+msgid "-display <display>\tConnect vim to this particular X-server"
+msgstr "-display <display>\tStarte vim <display>"
+
+msgid "-X\t\t\tDo not connect to X server"
+msgstr "-X\t\t\tStelle keine Verbindung zum X-server her"
+
+msgid "--remote <files>\tEdit <files> in a Vim server if possible"
+msgstr ""
+"--remote <Dateien>\tEditiere <Dateien> in einem Vim-Server falls möglich"
+
+msgid "--remote-silent <files> Same, don't complain if there is no server"
+msgstr ""
+"--remote-silent <Dateien> Dasselbe ohne Warnung, wenn kein Server vorhanden "
+"ist"
+
+msgid ""
+"--remote-wait <files> As --remote but wait for files to have been edited"
+msgstr ""
+"--remote-wait <Dateien> Wie --remote, aber warte, bis die <Dateien> "
+"editiert wurden"
+
+msgid ""
+"--remote-wait-silent <files> Same, don't complain if there is no server"
+msgstr ""
+"--remote-wait-silent <files> Dasselbe ohne Warnung, wenn kein Server "
+"vorhanden ist"
+
+msgid ""
+"--remote-tab[-wait][-silent] <files> As --remote but use tab page per file"
+msgstr ""
+"--remote-tab[-wait][-silent] <Dateien> Wie --remote, aber öffne ein Reiter "
+"für jede Datei."
+
+msgid "--remote-send <keys>\tSend <keys> to a Vim server and exit"
+msgstr "--remote-send <keys>\tSchicke <keys> zu einem Vim Server und beende"
+
+msgid "--remote-expr <expr>\tEvaluate <expr> in a Vim server and print result"
+msgstr ""
+"--remote-expr <Ausdruck>\tFühre <Ausdruck> in einem Vim-Server aus und "
+"drucke das Ergebnis"
+
+msgid "--serverlist\t\tList available Vim server names and exit"
+msgstr "--serverlist\t\tAuflisten verfügbarer Vim-Server-Namen und beende"
+
+msgid "--servername <name>\tSend to/become the Vim server <name>"
+msgstr "--servername <Name>\tBenutze den Vim-Server <Name>"
+
+msgid "--startuptime <file>\tWrite startup timing messages to <file>"
+msgstr "--startuptime <Datei>\tSchreibe Start Zeitmessung in <Datei>"
+
+msgid "-i <viminfo>\t\tUse <viminfo> instead of .viminfo"
+msgstr "-i <viminfo>\t\tBenutze <viminfo> statt .viminfo"
+
+msgid "--clean\t\t'nocompatible', Vim defaults, no plugins, no viminfo"
+msgstr ""
+"--clean\t\t'nocompatible', Vim Standardwerte, keine Plugins, keine Viminfo"
+
+msgid "-h or --help\tPrint Help (this message) and exit"
+msgstr "-h or --help\tAnzeigen der Hilfe (diesen Text) und beenden"
+
+msgid "--version\t\tPrint version information and exit"
+msgstr "--version\t\tVersionsinformation anzeigen und beenden"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Motif version):\n"
+msgstr ""
+"\n"
+"Argumente für den gvim (Motif Version):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (neXtaw version):\n"
+msgstr ""
+"\n"
+"Argumente für den gvim (neXtaw Version):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Athena version):\n"
+msgstr ""
+"\n"
+"Argumente für den gvim (Athena Version):\n"
+
+msgid "-display <display>\tRun vim on <display>"
+msgstr "-display <display>\tStarte vim auf <display>"
+
+msgid "-iconic\t\tStart vim iconified"
+msgstr "-iconic\t\tStarte vim als Icon"
+
+msgid "-background <color>\tUse <color> for the background (also: -bg)"
+msgstr ""
+"-background <Farbe>\tBenutze <Farbe> für den Hintergrund (auch mit: -bg)"
+
+msgid "-foreground <color>\tUse <color> for normal text (also: -fg)"
+msgstr ""
+"-foreground <Farbe>\tBenutze <Farbe> für den Text Vordergrund (auch mit: -fg)"
+
+msgid "-font <font>\t\tUse <font> for normal text (also: -fn)"
+msgstr ""
+"-font <Schriftart>\tBenutze <Schriftart> für normalen Text (auch mit: -fn)"
+
+msgid "-boldfont <font>\tUse <font> for bold text"
+msgstr "-boldfont <Schriftart>\tBenutze <Schriftart> für Fettschrift"
+
+msgid "-italicfont <font>\tUse <font> for italic text"
+msgstr "-italicfont <Schriftart>\tBenutze <Schriftart> für geneigten Text"
+
+msgid "-geometry <geom>\tUse <geom> for initial geometry (also: -geom)"
+msgstr ""
+"-geometry <geom>\tBenutze <geom> für die Anfangs Abmessungen (auch mit: -"
+"geom)"
+
+msgid "-borderwidth <width>\tUse a border width of <width> (also: -bw)"
+msgstr ""
+"-borderwidth <Breite>\tBenutze einen Rahmen der Breite <Breite> (auch mit: -"
+"bw)"
+
+msgid "-scrollbarwidth <width> Use a scrollbar width of <width> (also: -sw)"
+msgstr ""
+"-scrollbarwidth <Breite> Benutze eine Scrollbar der Breite <Breite> (auch "
+"mit: -sw)"
+
+msgid "-menuheight <height>\tUse a menu bar height of <height> (also: -mh)"
+msgstr ""
+"-menuheight <Höhe>\tBenutze einen Menü-Balken der Höhe <Höhe> (auch mit: -mh)"
+
+msgid "-reverse\t\tUse reverse video (also: -rv)"
+msgstr "-reverse\t\tBenutze invertierte Farben (auch mit: -rv)"
+
+msgid "+reverse\t\tDon't use reverse video (also: +rv)"
+msgstr "+reverse\t\tBenutze keine invertierten Farben (auch mit: +rv)"
+
+msgid "-xrm <resource>\tSet the specified resource"
+msgstr "-xrm <resource>\tSetze die gegebene Ressource"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (GTK+ version):\n"
+msgstr ""
+"\n"
+"Argumente für gvim GTK+ Version:\n"
+
+msgid "-display <display>\tRun vim on <display> (also: --display)"
+msgstr "-display <display>\tStarte vim auf <display> (auch mit: --display)"
+
+msgid "--role <role>\tSet a unique role to identify the main window"
+msgstr ""
+"--role <role>\tSetze eine eindeutige Rolle, um das Hauptfenster zu "
+"identifizieren"
+
+msgid "--socketid <xid>\tOpen Vim inside another GTK widget"
+msgstr "--socketid <xid>\tÖffne Vim in einem anderen GTK widget"
+
+msgid "--echo-wid\t\tMake gvim echo the Window ID on stdout"
+msgstr "--echo-wid\t\tSchreibe die Window ID auf Standard Ausgabe."
+
+msgid "-P <parent title>\tOpen Vim inside parent application"
+msgstr "-P <parent title>\tÖffne Vim innerhalb der Vater-Applikation"
+
+msgid "--windowid <HWND>\tOpen Vim inside another win32 widget"
+msgstr "--windowid <HWND>\tÖffne Vim in einem anderen Win32 widget"
+
+msgid "No display"
+msgstr "Keine Anzeige"
+
+msgid ": Send failed.\n"
+msgstr ": Versendung fehlgeschlagen.\n"
+
+msgid ": Send failed. Trying to execute locally\n"
+msgstr ": Versendung fehlgeschlagen. Versuche lokale Ausführung\n"
+
+#, c-format
+msgid "%d of %d edited"
+msgstr "%d von %d bearbeitet"
+
+msgid "No display: Send expression failed.\n"
+msgstr "Keine Anzeige: Versenden des Ausdrucks fehlgeschlagen.\n"
+
+msgid ": Send expression failed.\n"
+msgstr ": Versenden des Ausdrucks fehlgeschlagen.\n"
+
+msgid "No marks set"
+msgstr "Keine Markierungen gesetzt"
+
+#, c-format
+msgid "E283: No marks matching \"%s\""
+msgstr "E283: Keine Markierungen passen auf \"%s\""
+
+msgid ""
+"\n"
+"mark line col file/text"
+msgstr ""
+"\n"
+"Mark Zeile Sp Datei/Text"
+
+msgid ""
+"\n"
+" jump line col file/text"
+msgstr ""
+"\n"
+" Sprung Zeile Sp Datei/Text"
+
+msgid ""
+"\n"
+"change line col text"
+msgstr ""
+"\n"
+"Änder. Zeile Sp Text"
+
+msgid ""
+"\n"
+"# File marks:\n"
+msgstr ""
+"\n"
+"# Datei-Markierungen:\n"
+
+msgid ""
+"\n"
+"# Jumplist (newest first):\n"
+msgstr ""
+"\n"
+"# Jumplist (neueste zuerst):\n"
+
+msgid ""
+"\n"
+"# History of marks within files (newest to oldest):\n"
+msgstr ""
+"\n"
+"# Geschichte der Markierungen innerhalb von Dateien (neueste zuerst):\n"
+
+msgid "Missing '>'"
+msgstr "'>' fehlt"
+
+msgid "E543: Not a valid codepage"
+msgstr "E543: Keine zulässige Codepage"
+
+msgid "E284: Cannot set IC values"
+msgstr "E284: Kann die IC Werte nicht setzen"
+
+msgid "E285: Failed to create input context"
+msgstr "E285: Eingabe-Kontext konnte nicht erzeugt werden"
+
+msgid "E286: Failed to open input method"
+msgstr "E286: Eingabemethode konnte nicht geöffnet werden"
+
+msgid "E287: Warning: Could not set destroy callback to IM"
+msgstr "E287: Achtung: Destroy Callback konnte nicht auf IM gesetzt werden"
+
+msgid "E288: input method doesn't support any style"
+msgstr "E288: Eingabemethode unterstützt keinen einzigen Stil"
+
+msgid "E289: input method doesn't support my preedit type"
+msgstr "E289: Eingabemethode unterstützt nicht meinen Voreditier-Typen"
+
+msgid "E293: block was not locked"
+msgstr "E293: Block war nicht gesperrt"
+
+msgid "E294: Seek error in swap file read"
+msgstr "E294: Positionierungsfehler beim Lesen der Auslagerungsdatei"
+
+msgid "E295: Read error in swap file"
+msgstr "E295: Lesefehler in der Auslagerungsdatei"
+
+msgid "E296: Seek error in swap file write"
+msgstr "E296: Positionierungsfehler beim Schreiben in die Auslagerungsdatei"
+
+msgid "E297: Write error in swap file"
+msgstr "E297: Fehler beim Schreiben in die Auslagerungsdatei"
+
+msgid "E300: Swap file already exists (symlink attack?)"
+msgstr "E300: Auslagerungsdatei ist bereits vorhanden (symlink Attacke?)"
+
+msgid "E298: Didn't get block nr 0?"
+msgstr "E298: Block Nr. 0 nicht erhalten?"
+
+msgid "E298: Didn't get block nr 1?"
+msgstr "E298: Block Nr. 1 nicht erhalten?"
+
+msgid "E298: Didn't get block nr 2?"
+msgstr "E298: Block Nr. 2 nicht erhalten?"
+
+msgid "E843: Error while updating swap file crypt"
+msgstr ""
+"E843: Fehler beim Aktualisieren der Verschlüsselung der Auslagerungsdatei."
+
+msgid "E301: Oops, lost the swap file!!!"
+msgstr "E301: Upps, Verlust der Auslagerungsdatei!!!"
+
+msgid "E302: Could not rename swap file"
+msgstr "E302: Auslagerungsdatei konnte nicht umbenannt werden"
+
+#, c-format
+msgid "E303: Unable to open swap file for \"%s\", recovery impossible"
+msgstr ""
+"E303: Auslagerungsdatei für \"%s\" konnte nicht geöffnet werden, "
+"Wiederherstellung unmöglich"
+
+msgid "E304: ml_upd_block0(): Didn't get block 0??"
+msgstr "E304: ml_upd_block0(): Block Nr. 0 nicht erhalten?"
+
+#, c-format
+msgid "E305: No swap file found for %s"
+msgstr "E305: Keine Auslagerungsdatei für %s gefunden"
+
+msgid "Enter number of swap file to use (0 to quit): "
+msgstr ""
+"Geben Sie die Nummer der Auslagerungsdatei ein die verwendet werden soll (0 "
+"um abzubrechen): "
+
+#, c-format
+msgid "E306: Cannot open %s"
+msgstr "E306: %s kann nicht geöffnet werden"
+
+msgid "Unable to read block 0 from "
+msgstr "Block 0 kann nicht gelesen werden aus "
+
+msgid ""
+"\n"
+"Maybe no changes were made or Vim did not update the swap file."
+msgstr ""
+"\n"
+"Vielleicht wurden keine Änderungen vorgenommen oder Vim hatte die "
+"Auslagerungsdatei nicht aktualisiert."
+
+msgid " cannot be used with this version of Vim.\n"
+msgstr " kann nicht zusammen mit dieser Vim Version verwendet werden.\n"
+
+msgid "Use Vim version 3.0.\n"
+msgstr "Benutze Vim Version 3.0.\n"
+
+#, c-format
+msgid "E307: %s does not look like a Vim swap file"
+msgstr "E307: %s sieht nicht wie eine Vim Auslagerungsdatei aus"
+
+msgid " cannot be used on this computer.\n"
+msgstr " kann auf diesem Rechner nicht verwendet werden.\n"
+
+msgid "The file was created on "
+msgstr "Die Datei wurde erstellt am "
+
+msgid ""
+",\n"
+"or the file has been damaged."
+msgstr ""
+",\n"
+"oder die Datei wurde beschädigt."
+
+#, c-format
+msgid ""
+"E833: %s is encrypted and this version of Vim does not support encryption"
+msgstr ""
+"E833: %s ist verschlüsselt, aber diese Version von Vim unterstützt "
+"Verschlüsselung nicht."
+
+msgid " has been damaged (page size is smaller than minimum value).\n"
+msgstr " wurde beschädigt (Pagesize kleiner als das Minimum).\n"
+
+#, c-format
+msgid "Using swap file \"%s\""
+msgstr "Verwende Auslagerungsdatei \"%s\""
+
+#, c-format
+msgid "Original file \"%s\""
+msgstr "Original-Datei \"%s\""
+
+msgid "E308: Warning: Original file may have been changed"
+msgstr "E308: Achtung: Die Originaldatei könnte verändert worden sein"
+
+#, c-format
+msgid "Swap file is encrypted: \"%s\""
+msgstr "Swap Datei ist verschlüsselt: \"%s\""
+
+msgid ""
+"\n"
+"If you entered a new crypt key but did not write the text file,"
+msgstr ""
+"\n"
+"Wenn Sie einen neuen Schlüssel eingegeben haben, aber die Textdatei nicht "
+"geschrieben haben,"
+
+msgid ""
+"\n"
+"enter the new crypt key."
+msgstr ""
+"\n"
+"geben Sie bitte den Schlüssel ein: "
+
+msgid ""
+"\n"
+"If you wrote the text file after changing the crypt key press enter"
+msgstr ""
+"\n"
+"Wenn Sie die Textdatei geschrieben haben, nachdem der Schlüssel geändert "
+"wurde, drücke Enter."
+
+msgid ""
+"\n"
+"to use the same key for text file and swap file"
+msgstr ""
+"\n"
+"um den gleichen Schlüssel für die Textdatei und die Swap Datei zu nutzen."
+
+#, c-format
+msgid "E309: Unable to read block 1 from %s"
+msgstr "E309: Block 1 von %s kann nicht gelesen werden"
+
+msgid "???MANY LINES MISSING"
+msgstr "???VIELE ZEILEN FEHLEN"
+
+msgid "???LINE COUNT WRONG"
+msgstr "???ZEILENANZAHL FALSCH"
+
+msgid "???EMPTY BLOCK"
+msgstr "???LEERER BLOCK"
+
+msgid "???LINES MISSING"
+msgstr "???ZEILEN FEHLEN"
+
+#, c-format
+msgid "E310: Block 1 ID wrong (%s not a .swp file?)"
+msgstr "E310: Block 1 ID falsch (ist %s keine .swp-Datei?)"
+
+msgid "???BLOCK MISSING"
+msgstr "???BLOCK FEHLT"
+
+msgid "??? from here until ???END lines may be messed up"
+msgstr "??? von hier bis ???ENDE könnten die Zeilen falsch sein"
+
+msgid "??? from here until ???END lines may have been inserted/deleted"
+msgstr "??? von hier bis ???ENDE könnten Zeilen eingefügt oder gelöscht sein"
+
+msgid "???END"
+msgstr "???ENDE"
+
+msgid "E311: Recovery Interrupted"
+msgstr "E311: Wiederherstellung unterbrochen"
+
+msgid ""
+"E312: Errors detected while recovering; look for lines starting with ???"
+msgstr ""
+"E312: Fehler wurden festgestellt während der Wiederherstellung: suche nach "
+"Zeilen die mit ??? beginnen"
+
+msgid "See \":help E312\" for more information."
+msgstr "Lesen Sie \":help E312\" für weitere Informationen."
+
+msgid "Recovery completed. You should check if everything is OK."
+msgstr "Wiederherstellung beendet. Prüfen Sie, ob alles OK ist."
+
+msgid ""
+"\n"
+"(You might want to write out this file under another name\n"
+msgstr ""
+"\n"
+"(Wollen Sie vielleicht diese Datei unter einem neuen Namen speichern\n"
+
+msgid "and run diff with the original file to check for changes)"
+msgstr ""
+"und \"diff\" mit der Original-Datei ausführen, um Änderungen zu prüfen)"
+
+msgid "Recovery completed. Buffer contents equals file contents."
+msgstr "Recovery durchgeführt. Pufferinhalt entspricht Dateiinhalt."
+
+msgid ""
+"\n"
+"You may want to delete the .swp file now.\n"
+"\n"
+msgstr ""
+"\n"
+"Sie können die Swap Datei jetzt löschen.\n"
+"\n"
+
+msgid "Using crypt key from swap file for the text file.\n"
+msgstr "Benutze den Schlüssel der Swap Datei für die Textdatei.\n"
+
+msgid "Swap files found:"
+msgstr "Auslagerungsdateien gefunden:"
+
+msgid " In current directory:\n"
+msgstr " Im aktuellen Verzeichnis:\n"
+
+msgid " Using specified name:\n"
+msgstr " Benutze gegebenen Namen:\n"
+
+msgid " In directory "
+msgstr " Im Verzeichnis "
+
+msgid " -- none --\n"
+msgstr " -- Nichts --\n"
+
+msgid " owned by: "
+msgstr " Eigentum von: "
+
+msgid " dated: "
+msgstr " vom: "
+
+msgid " dated: "
+msgstr " vom: "
+
+msgid " [from Vim version 3.0]"
+msgstr " [von Vim Version 3.0]"
+
+msgid " [does not look like a Vim swap file]"
+msgstr " [sieht nicht wie eine Vim Auslagerungsdatei aus]"
+
+msgid " file name: "
+msgstr " Dateiname: "
+
+msgid ""
+"\n"
+" modified: "
+msgstr ""
+"\n"
+" verändert: "
+
+msgid "YES"
+msgstr "JA"
+
+msgid "no"
+msgstr "nein"
+
+msgid ""
+"\n"
+" user name: "
+msgstr ""
+"\n"
+" Benutzer-Name: "
+
+msgid " host name: "
+msgstr " Hostname: "
+
+msgid ""
+"\n"
+" host name: "
+msgstr ""
+"\n"
+" Hostname: "
+
+msgid ""
+"\n"
+" process ID: "
+msgstr ""
+"\n"
+" Process-ID: "
+
+msgid " (STILL RUNNING)"
+msgstr " (LÄUFT NOCH)"
+
+msgid ""
+"\n"
+" [not usable with this version of Vim]"
+msgstr ""
+"\n"
+" [nicht verwendbar mit dieser Vim-Version]"
+
+msgid ""
+"\n"
+" [not usable on this computer]"
+msgstr ""
+"\n"
+" [nicht verwendbar auf diesem Rechner]"
+
+msgid " [cannot be read]"
+msgstr " [kann nicht gelesen werden]"
+
+msgid " [cannot be opened]"
+msgstr " [kann nicht geöffnet werden]"
+
+msgid "E313: Cannot preserve, there is no swap file"
+msgstr "E313: Kann nicht absichern, es gibt keine Auslagerungsdatei"
+
+msgid "File preserved"
+msgstr "Datei gesichert"
+
+msgid "E314: Preserve failed"
+msgstr "E314: Absicherung fehlgeschlagen"
+
+#, c-format
+msgid "E315: ml_get: invalid lnum: %ld"
+msgstr "E315: ml_get: unzulässige Zeilennummer: %ld"
+
+#, c-format
+msgid "E316: ml_get: cannot find line %ld"
+msgstr "E316: ml_get: kann Zeile %ld nicht finden"
+
+msgid "E317: pointer block id wrong 3"
+msgstr "E317: Zeiger Block id falsch 3"
+
+msgid "stack_idx should be 0"
+msgstr "stack_idx sollte 0 sein"
+
+msgid "E318: Updated too many blocks?"
+msgstr "E318: Zu viele Blöcke aktualisiert?"
+
+msgid "E317: pointer block id wrong 4"
+msgstr "E317: Zeiger Block id falsch 4"
+
+msgid "deleted block 1?"
+msgstr "Block 1 gelöscht?"
+
+#, c-format
+msgid "E320: Cannot find line %ld"
+msgstr "E320: Kann Zeile %ld nicht finden"
+
+msgid "E317: pointer block id wrong"
+msgstr "E317: Zeiger Block id ist falsch"
+
+msgid "pe_line_count is zero"
+msgstr "pe_line_count ist Null"
+
+#, c-format
+msgid "E322: line number out of range: %ld past the end"
+msgstr "E322: Zeilennummer nicht im zulässigen Bereich: %ld nach dem Ende"
+
+#, c-format
+msgid "E323: line count wrong in block %ld"
+msgstr "E323: Zeilenanzahl falsch in Block %ld"
+
+msgid "Stack size increases"
+msgstr "Stapel Größe wächst"
+
+msgid "E317: pointer block id wrong 2"
+msgstr "E317: Zeiger Block id falsch 2"
+
+#, c-format
+msgid "E773: Symlink loop for \"%s\""
+msgstr "E773: Symlink Schleife für \"%s\""
+
+msgid "E325: ATTENTION"
+msgstr "E325: ACHTUNG"
+
+msgid ""
+"\n"
+"Found a swap file by the name \""
+msgstr ""
+"\n"
+"Auslagerungsdatei mit folgendem Namen gefunden: \""
+
+msgid "While opening file \""
+msgstr "Beim Öffnen der Datei \""
+
+msgid " CANNOT BE FOUND"
+msgstr " WURDE NICHT GEFUNDEN"
+
+msgid " NEWER than swap file!\n"
+msgstr " NEUER als Auslagerungsdatei!\n"
+
+msgid ""
+"\n"
+"(1) Another program may be editing the same file. If this is the case,\n"
+" be careful not to end up with two different instances of the same\n"
+" file when making changes. Quit, or continue with caution.\n"
+msgstr ""
+"\n"
+"(1) Ein anderes Programm editiert möglicherweise diese Datei. Wenn dies\n"
+" der Fall ist, sollten Sie vorsichtig sein, damit es nicht zu\n"
+" Überschneidungen kommt. Beende oder fahre vorsichtig fort.\n"
+
+msgid "(2) An edit session for this file crashed.\n"
+msgstr "(2) Eine Editiersitzung für diese Datei ist abgestürzt.\n"
+
+msgid " If this is the case, use \":recover\" or \"vim -r "
+msgstr ""
+" Wenn dies der Fall ist, so verwenden Sie \":recover\" oder \"vim -r "
+
+msgid ""
+"\"\n"
+" to recover the changes (see \":help recovery\").\n"
+msgstr ""
+"\"\n"
+" um die Änderungen wiederherzustellen (siehe \":help recovery\").\n"
+
+msgid " If you did this already, delete the swap file \""
+msgstr ""
+" Wenn dies bereits geschehen ist, löschen Sie die Auslagerungsdatei \""
+
+msgid ""
+"\"\n"
+" to avoid this message.\n"
+msgstr ""
+"\"\n"
+" um diese Nachricht zu vermeiden.\n"
+
+msgid "Swap file \""
+msgstr "Auslagerungsdatei \""
+
+msgid "\" already exists!"
+msgstr "\" ist bereits vorhanden!"
+
+msgid "VIM - ATTENTION"
+msgstr "VIM - ACHTUNG"
+
+msgid "Swap file already exists!"
+msgstr "Auslagerungsdatei ist bereits vorhanden!"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"Nur zum &Lesen öffnen\n"
+"Trotzdem &editieren\n"
+"&Wiederherstellen\n"
+"&Beenden\n"
+"&Abbrechen"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Delete it\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"Nur zum &Lesen öffnen\n"
+"Trotzdem &editieren\n"
+"&Wiederherstellen\n"
+"&Datei Löschen\n"
+"&Beenden\n"
+"&Abbrechen"
+
+msgid "E326: Too many swap files found"
+msgstr "E326: Zu viele Auslagerungsdateien gefunden"
+
+msgid "E327: Part of menu-item path is not sub-menu"
+msgstr "E327: Teil des Menüpunkt-Pfades muss zum Untermenü führen"
+
+#, c-format
+msgid "E329: No menu \"%s\""
+msgstr "E329: Kein Menü \"%s\""
+
+msgid "E792: Empty menu name"
+msgstr "E792: Leerer Menüname"
+
+msgid "E330: Menu path must not lead to a sub-menu"
+msgstr "E330: Menü-Pfad darf nicht zum Untermenü führen"
+
+msgid "E331: Must not add menu items directly to menu bar"
+msgstr ""
+"E331: Menüpunkte können nicht direkt zum Menü-Balken hinzugefügt werden"
+
+msgid "E332: Separator cannot be part of a menu path"
+msgstr "E332: Trenner kann nicht Teil des Menü-Pfades sein"
+
+msgid ""
+"\n"
+"--- Menus ---"
+msgstr ""
+"\n"
+"--- Menüs ---"
+
+msgid "Tear off this menu"
+msgstr "Reiße dieses Menü ab"
+
+#, c-format
+msgid "E335: Menu not defined for %s mode"
+msgstr "E335: Menü ist für Modus %s nicht definiert"
+
+msgid "E333: Menu path must lead to a menu item"
+msgstr "E333: Menü-Pfad muss zu einem Menüpunkt führen"
+
+#, c-format
+msgid "E334: Menu not found: %s"
+msgstr "E334: Menü nicht gefunden: %s"
+
+msgid "E336: Menu path must lead to a sub-menu"
+msgstr "E336: Menü-Pfad muss zum Untermenü führen"
+
+msgid "E337: Menu not found - check menu names"
+msgstr "E337: Menü nicht gefunden - überprüfe Menü-Namen"
+
+#, c-format
+msgid "Error detected while processing %s:"
+msgstr "Fehler beim Ausführen von \"%s\":"
+
+#, c-format
+msgid "line %4ld:"
+msgstr "Zeile %4ld:"
+
+#, c-format
+msgid "E354: Invalid register name: '%s'"
+msgstr "E354: Ungültiger Register Name: '%s'"
+
+msgid "Messages maintainer: Bram Moolenaar <Bram@vim.org>"
+msgstr "Übersetzt von Christian Brabandt <cb@256bit.org>"
+
+msgid "Interrupt: "
+msgstr "Unterbrechung: "
+
+msgid "Press ENTER or type command to continue"
+msgstr "Betätigen Sie die EINGABETASTE oder geben Sie einen Befehl ein"
+
+#, c-format
+msgid "%s line %ld"
+msgstr "%s Zeile %ld"
+
+msgid "-- More --"
+msgstr "-- Mehr --"
+
+msgid " SPACE/d/j: screen/page/line down, b/u/k: up, q: quit "
+msgstr ""
+" LEERZEICHEN/d/j: Seite/halbe Seite/Zeile vorwärts, b/u/k: rückwärts, q: "
+"Ende "
+
+msgid "Question"
+msgstr "Frage"
+
+msgid ""
+"&Yes\n"
+"&No"
+msgstr ""
+"&Ja\n"
+"&Nein"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"Save &All\n"
+"&Discard All\n"
+"&Cancel"
+msgstr ""
+"&Ja\n"
+"&Nein\n"
+"Alle &Speichern\n"
+"Alle &Verwerfen\n"
+"&Abbrechen"
+
+msgid "Select Directory dialog"
+msgstr "Verzeichnis Auswahl Dialog"
+
+msgid "Save File dialog"
+msgstr "Datei Speichern Dialog"
+
+msgid "Open File dialog"
+msgstr "Datei Öffnen Dialog"
+
+msgid "E338: Sorry, no file browser in console mode"
+msgstr "E338: Kein Datei-Dialog im Konsole-Modus"
+
+msgid "E766: Insufficient arguments for printf()"
+msgstr "E766: Zu wenige Argumente für printf()"
+
+msgid "E807: Expected Float argument for printf()"
+msgstr "E807: Erwarte Float Argument für printf()"
+
+msgid "E767: Too many arguments to printf()"
+msgstr "E767: Zu viele Argumente für printf()"
+
+msgid "W10: Warning: Changing a readonly file"
+msgstr "W10: Achtung: Ändern einer schreibgeschützten Datei"
+
+msgid "Type number and <Enter> or click with mouse (empty cancels): "
+msgstr ""
+"Bitte Nummer und <Enter> eingeben oder mit der Maus auswählen (abbrechen mit "
+"<Enter>): "
+
+msgid "Type number and <Enter> (empty cancels): "
+msgstr "Gewünschte Nummer und <Enter> eingeben (abbrechen mit <Enter>): "
+
+#, c-format
+msgid "%ld more line"
+msgid_plural "%ld more lines"
+msgstr[0] "%ld Zeile mehr"
+msgstr[1] "%ld Zeilen mehr"
+
+#, c-format
+msgid "%ld line less"
+msgid_plural "%ld fewer lines"
+msgstr[0] "%ld Zeile weniger"
+msgstr[1] "%ld Zeilen weniger"
+
+msgid " (Interrupted)"
+msgstr " (Unterbrochen)"
+
+msgid "Beep!"
+msgstr "Beep!"
+
+msgid "ERROR: "
+msgstr "FEHLER: "
+
+#, c-format
+msgid ""
+"\n"
+"[bytes] total alloc-freed %lu-%lu, in use %lu, peak use %lu\n"
+msgstr ""
+"\n"
+"[Bytes] gesamt alloc-frei %lu-%lu, in Verwendung %lu, maximale Verwendung "
+"%lu\n"
+
+#, c-format
+msgid ""
+"[calls] total re/malloc()'s %lu, total free()'s %lu\n"
+"\n"
+msgstr ""
+"[Aufrufe] gesamt re/malloc()s %lu, gesamt free()s %lu\n"
+"\n"
+
+msgid "E340: Line is becoming too long"
+msgstr "E340: Zeile wird zu lang"
+
+#, c-format
+msgid "E341: Internal error: lalloc(%ld, )"
+msgstr "E341: Interner Fehler: lalloc(%ld, )"
+
+#, c-format
+msgid "E342: Out of memory! (allocating %lu bytes)"
+msgstr "E342: Kein Speicherplatz mehr vorhanden (%lu Bytes reserviert)"
+
+#, c-format
+msgid "Calling shell to execute: \"%s\""
+msgstr "Rufe Shell auf, um \"%s\" auszuführen"
+
+msgid "E545: Missing colon"
+msgstr "E545: Fehlender Doppelpunkt"
+
+msgid "E546: Illegal mode"
+msgstr "E546: Unzulässiger Modus"
+
+msgid "E547: Illegal mouseshape"
+msgstr "E547: Unzulässiger Mauszeigerform"
+
+msgid "E548: digit expected"
+msgstr "E548: Ziffer erwartet"
+
+msgid "E549: Illegal percentage"
+msgstr "E549: Unzulässige Prozentangabe"
+
+msgid "E854: path too long for completion"
+msgstr "E854: Pfad für Vervollständigung zu lang."
+
+#, c-format
+msgid ""
+"E343: Invalid path: '**[number]' must be at the end of the path or be "
+"followed by '%s'."
+msgstr ""
+"E343: Ungültiger Pfad: '**[Nummer]' muss am Ende des Pfads sein, oder von "
+"'%s' gefolgt werden. Siehe \":help path\"."
+
+#, c-format
+msgid "E344: Can't find directory \"%s\" in cdpath"
+msgstr "E344: Kann Verzeichnis \"%s\" nicht im 'cdpath' finden"
+
+#, c-format
+msgid "E345: Can't find file \"%s\" in path"
+msgstr "E345: Kann Datei \"%s\" nicht im Pfad finden"
+
+#, c-format
+msgid "E346: No more directory \"%s\" found in cdpath"
+msgstr "E346: Kein weiteres Verzeichnis \"%s\" im 'cdpath' gefunden"
+
+#, c-format
+msgid "E347: No more file \"%s\" found in path"
+msgstr "E347: Keine weitere Datei \"%s\" im Pfad gefunden"
+
+#, c-format
+msgid "E668: Wrong access mode for NetBeans connection info file: \"%s\""
+msgstr ""
+"E668: Falscher Zugriffsmodus auf die NetBeans Zugriff-Informationsdatei: \"%s"
+"\""
+
+#, c-format
+msgid "E658: NetBeans connection lost for buffer %d"
+msgstr "E658: Verbindung zu NetBeans für Puffer %d verloren"
+
+msgid "E838: netbeans is not supported with this GUI"
+msgstr "E838: netbeans wird nicht unterstützt mit dieser GUI."
+
+msgid "E511: netbeans already connected"
+msgstr "E511: netbeans ist bereits verbunden"
+
+#, c-format
+msgid "E505: %s is read-only (add ! to override)"
+msgstr "E505: %s ist schreibgeschützt (erzwinge mit !)"
+
+# Identifizierungszeichen/merkmal, Bezeichner
+msgid "E349: No identifier under cursor"
+msgstr "E349: Kein Merkmal unter dem Cursor"
+
+msgid "E774: 'operatorfunc' is empty"
+msgstr "E774: 'operatorfunc' is empty"
+
+msgid "E775: Eval feature not available"
+msgstr "E775: Eval Eigenschaft nicht verfügbar"
+
+msgid "Warning: terminal cannot highlight"
+msgstr "Achtung: Terminal unterstützt keine Hervorhebung"
+
+msgid "E348: No string under cursor"
+msgstr "E348: Keine Zeichenkette unter dem Cursor"
+
+msgid "E352: Cannot erase folds with current 'foldmethod'"
+msgstr ""
+"E352: Faltung kann mit der eingestellten Faltungsmethode nicht gelöscht "
+"werden"
+
+msgid "E664: changelist is empty"
+msgstr "E664: Liste der Änderungen ist leer"
+
+msgid "E662: At start of changelist"
+msgstr "E662: Am Anfang der Änderungsliste"
+
+msgid "E663: At end of changelist"
+msgstr "E663: Am Ende der Änderungsliste"
+
+msgid "Type :qa! and press <Enter> to abandon all changes and exit Vim"
+msgstr ""
+"Tippe: :qa! und drücke <Enter> um alle Änderungen zu verwerfen und Vim zu "
+"beenden"
+
+#, c-format
+msgid "%ld line %sed %d time"
+msgid_plural "%ld line %sed %d times"
+msgstr[0] "%ld Zeile %s %d Mal"
+msgstr[1] "%ld Zeile %s %d Mal"
+
+#, c-format
+msgid "%ld lines %sed %d time"
+msgid_plural "%ld lines %sed %d times"
+msgstr[0] "%ld Zeilen %s %d Mal"
+msgstr[1] "%ld Zeilen %s %d Mal"
+
+#, c-format
+msgid "%ld lines to indent... "
+msgstr "%ld Zeilen zum Einrücken... "
+
+#, c-format
+msgid "%ld line indented "
+msgid_plural "%ld lines indented "
+msgstr[0] "%ld Zeile eingerückt... "
+msgstr[1] "%ld Zeilen eingerückt... "
+
+msgid "E748: No previously used register"
+msgstr "E748: Kein bereits verwendetes Register"
+
+msgid "cannot yank; delete anyway"
+msgstr "kann nicht kopieren; lösche trotzdem"
+
+#, c-format
+msgid "%ld line changed"
+msgid_plural "%ld lines changed"
+msgstr[0] "%ld Zeile geändert"
+msgstr[1] "%ld Zeilen geändert"
+
+#, c-format
+msgid "freeing %ld lines"
+msgstr "gebe %ld Zeilen frei"
+
+#, c-format
+msgid " into \"%c"
+msgstr " in \"%c"
+
+#, c-format
+msgid "block of %ld line yanked%s"
+msgid_plural "block of %ld lines yanked%s"
+msgstr[0] "Block von %ld Zeile kopiert%s"
+msgstr[1] "Block von %ld Zeilen kopiert%s"
+
+#, c-format
+msgid "%ld line yanked%s"
+msgid_plural "%ld lines yanked%s"
+msgstr[0] "%ld Zeile kopiert%s"
+msgstr[1] "%ld Zeilen kopiert%s"
+
+#, c-format
+msgid "E353: Nothing in register %s"
+msgstr "E353: Register %s ist leer"
+
+msgid ""
+"\n"
+"--- Registers ---"
+msgstr ""
+"\n"
+"--- Register ---"
+
+msgid "Illegal register name"
+msgstr "Unzulässiger Register Name"
+
+msgid ""
+"\n"
+"# Registers:\n"
+msgstr ""
+"\n"
+"# Register:\n"
+
+#, c-format
+msgid "E574: Unknown register type %d"
+msgstr "E574: Unbekannter Register Typ %d"
+
+msgid ""
+"E883: search pattern and expression register may not contain two or more "
+"lines"
+msgstr ""
+"E883: Suchmuster- und Ausdrucksregister dürfen nicht mehr als 1 Zeile "
+"enthalten."
+
+#, c-format
+msgid "%ld Cols; "
+msgstr "%ld Spalten; "
+
+#, c-format
+msgid "Selected %s%ld of %ld Lines; %lld of %lld Words; %lld of %lld Bytes"
+msgstr ""
+"%s%ld von %ld Zeilen; %lld von %lld Wörtern; %lld von %lld Bytes ausgewählt"
+
+#, c-format
+msgid ""
+"Selected %s%ld of %ld Lines; %lld of %lld Words; %lld of %lld Chars; %lld of "
+"%lld Bytes"
+msgstr ""
+"%s%ld von %ld Zeilen; %lld von %lld Wörtern; %lld von %lld Zeichen; %lld von "
+"%lld Bytes ausgewählt"
+
+#, c-format
+msgid "Col %s of %s; Line %ld of %ld; Word %lld of %lld; Byte %lld of %lld"
+msgstr ""
+"Sp %s von %s; Zeile %ld von %ld; Wort %lld von %lld; Byte %lld von %lld"
+
+#, c-format
+msgid ""
+"Col %s of %s; Line %ld of %ld; Word %lld of %lld; Char %lld of %lld; Byte "
+"%lld of %lld"
+msgstr ""
+"Sp %s von %s; Zeile %ld von %ld; Wort %lld von %lld; Zeichen %lld von %lld; "
+"Byte %lld von %lld"
+
+#, c-format
+msgid "(+%lld for BOM)"
+msgstr "(+%lld für BOM)"
+
+msgid "Thanks for flying Vim"
+msgstr "Danke für die Benutzung von Vim"
+
+msgid "E518: Unknown option"
+msgstr "E518: Unbekannte Option"
+
+msgid "E519: Option not supported"
+msgstr "E519: Option nicht unterstützt"
+
+msgid "E520: Not allowed in a modeline"
+msgstr "E520: Nicht erlaubt in einer Modeline"
+
+msgid "E846: Key code not set"
+msgstr "E846: Tastencode nicht gesetzt"
+
+msgid "E521: Number required after ="
+msgstr "E521: Zahl benötigt nach ="
+
+msgid "E522: Not found in termcap"
+msgstr "E522: Nicht gefunden in 'termcap'"
+
+#, c-format
+msgid "E539: Illegal character <%s>"
+msgstr "E539: Unzulässiges Zeichen <%s>"
+
+#, c-format
+msgid "For option %s"
+msgstr "Für Option %s"
+
+msgid "E529: Cannot set 'term' to empty string"
+msgstr "E529: 'term' darf keine leere Zeichenkette sein"
+
+msgid "E530: Cannot change term in GUI"
+msgstr "E530: Kann Terminal in der GUI nicht verändern"
+
+msgid "E531: Use \":gui\" to start the GUI"
+msgstr "E531: Verwende \":gui\", um die GUI-Version zu starten"
+
+msgid "E589: 'backupext' and 'patchmode' are equal"
+msgstr "E589: 'backupext' und 'patchmode' sind gleich"
+
+msgid "E834: Conflicts with value of 'listchars'"
+msgstr "E834: Widerspricht Wert aus 'listchars'"
+
+msgid "E835: Conflicts with value of 'fillchars'"
+msgstr "E835: Widerspricht Wert aus 'fillchars'"
+
+msgid "E617: Cannot be changed in the GTK+ 2 GUI"
+msgstr "E617: Kann in der GTK+ 2 GUI nicht verändert werden"
+
+#, c-format
+msgid "E950: Cannot convert between %s and %s"
+msgstr "E950: Kann nicht zwischen %s und %s konvertieren."
+
+msgid "E524: Missing colon"
+msgstr "E524: Fehlender Doppelpunkt"
+
+msgid "E525: Zero length string"
+msgstr "E525: Zeichenkette der Länge Null"
+
+#, c-format
+msgid "E526: Missing number after <%s>"
+msgstr "E526: Fehlende Zahl nach <%s>"
+
+msgid "E527: Missing comma"
+msgstr "E527: Fehlendes Komma"
+
+msgid "E528: Must specify a ' value"
+msgstr "E528: Ein ' Wert muss angegeben werden"
+
+msgid "E595: contains unprintable or wide character"
+msgstr "E595: Enthält nicht-druckbare oder Multi-Byte Zeichen"
+
+msgid "E596: Invalid font(s)"
+msgstr "E596: Ungültige Schriftart(en)"
+
+msgid "E597: can't select fontset"
+msgstr "E597: Kann \"Fontset\" nicht auswählen"
+
+msgid "E598: Invalid fontset"
+msgstr "E598: Ungültiges \"Fontset\""
+
+msgid "E533: can't select wide font"
+msgstr "E533: Kann Breitschrift nicht auswählen"
+
+msgid "E534: Invalid wide font"
+msgstr "E534: Ungültige Breitschrift"
+
+#, c-format
+msgid "E535: Illegal character after <%c>"
+msgstr "E535: Ungültiges Zeichen nach <%c>"
+
+msgid "E536: comma required"
+msgstr "E536: Komma benötigt"
+
+#, c-format
+msgid "E537: 'commentstring' must be empty or contain %s"
+msgstr "E537: 'commentstring' muss leer sein oder %s enthalten"
+
+msgid "E538: No mouse support"
+msgstr "E538: Keine Maus-Unterstützung"
+
+msgid "E540: Unclosed expression sequence"
+msgstr "E540: Nicht-geschlossene Ausdrucksfolge"
+
+msgid "E541: too many items"
+msgstr "E541: Zu viele Elemente"
+
+msgid "E542: unbalanced groups"
+msgstr "E542: Unausgewogene Gruppen"
+
+msgid "E946: Cannot make a terminal with running job modifiable"
+msgstr "E946: Kann ein Terminal mit einem laufenden Job nicht modifizieren"
+
+msgid "E590: A preview window already exists"
+msgstr "E590: Ein Vorschaufenster existiert bereits"
+
+msgid "W17: Arabic requires UTF-8, do ':set encoding=utf-8'"
+msgstr "W17: Arabisch benötigt UTF-8, bitte ':set encoding=utf-8' ausführen"
+
+msgid "E954: 24-bit colors are not supported on this environment"
+msgstr "E954: 24-bit Farben werden in dieser Umgebung nicht unterstützt"
+
+#, c-format
+msgid "E593: Need at least %d lines"
+msgstr "E593: Mindestens %d Zeilen werden benötigt"
+
+#, c-format
+msgid "E594: Need at least %d columns"
+msgstr "E594: Mindestens %d Spalten werden benötigt"
+
+#, c-format
+msgid "E355: Unknown option: %s"
+msgstr "E355: Unbekannte Option: %s"
+
+#, c-format
+msgid "E521: Number required: &%s = '%s'"
+msgstr "E521: Zahl benötigt: &%s = '%s'"
+
+msgid ""
+"\n"
+"--- Terminal codes ---"
+msgstr ""
+"\n"
+"--- Terminal Codes ---"
+
+msgid ""
+"\n"
+"--- Global option values ---"
+msgstr ""
+"\n"
+"--- Globale Optionswerte ---"
+
+msgid ""
+"\n"
+"--- Local option values ---"
+msgstr ""
+"\n"
+"--- Lokale Optionswerte ---"
+
+msgid ""
+"\n"
+"--- Options ---"
+msgstr ""
+"\n"
+"--- Optionen ---"
+
+msgid "E356: get_varp ERROR"
+msgstr "E356: get_varp FEHLER"
+
+#, c-format
+msgid "E357: 'langmap': Matching character missing for %s"
+msgstr "E357: 'langmap': Passendes Zeichen fehlt für %s"
+
+#, c-format
+msgid "E358: 'langmap': Extra characters after semicolon: %s"
+msgstr "E358: 'langmap': Überschüssige Zeichen nach dem Semikolon: %s"
+
+msgid "cannot open "
+msgstr "kann nicht öffnen"
+
+msgid "VIM: Can't open window!\n"
+msgstr "VIM: Fenster kann nicht geöffnet werden!\n"
+
+msgid "Need Amigados version 2.04 or later\n"
+msgstr "Brauche Amigados Version 2.04 oder neuere\n"
+
+#, c-format
+msgid "Need %s version %ld\n"
+msgstr "Benötige %s Version %ld\n"
+
+msgid "Cannot open NIL:\n"
+msgstr "Kann NIL nicht öffnen:\n"
+
+msgid "Cannot create "
+msgstr "Kann nicht erstellen "
+
+#, c-format
+msgid "Vim exiting with %d\n"
+msgstr "Vim beendet mit %d\n"
+
+msgid "cannot change console mode ?!\n"
+msgstr "kann Konsolenmodus nicht wechseln ?!\n"
+
+msgid "mch_get_shellsize: not a console??\n"
+msgstr "mch_get_winsize: keine Konsole??\n"
+
+msgid "E360: Cannot execute shell with -f option"
+msgstr "E360: Kann Shell nicht mit der -f Option ausführen"
+
+msgid "Cannot execute "
+msgstr "Kann nicht ausführen "
+
+msgid "shell "
+msgstr "Shell "
+
+msgid " returned\n"
+msgstr " zurückgegeben\n"
+
+msgid "ANCHOR_BUF_SIZE too small."
+msgstr "ANCHOR_BUF_SIZE zu klein."
+
+msgid "I/O ERROR"
+msgstr "I/O FEHLER"
+
+msgid "Message"
+msgstr "Nachricht"
+
+msgid "E237: Printer selection failed"
+msgstr "E237: Drucker-Auswahl fehlgeschlagen"
+
+#, c-format
+msgid "to %s on %s"
+msgstr "nach %s auf %s"
+
+#, c-format
+msgid "E613: Unknown printer font: %s"
+msgstr "E613: Unbekannte Druckerschriftart: %s"
+
+#, c-format
+msgid "E238: Print error: %s"
+msgstr "E238: Fehler beim Drucken: %s"
+
+#, c-format
+msgid "Printing '%s'"
+msgstr "Drucke '%s'"
+
+#, c-format
+msgid "E244: Illegal charset name \"%s\" in font name \"%s\""
+msgstr "E244: Unzulässiger Zeichensatz-Name \"%s\" im Schriftart-Namen \"%s\""
+
+#, c-format
+msgid "E244: Illegal quality name \"%s\" in font name \"%s\""
+msgstr ""
+"E244: Unzulässiger Eigenschaften-Name \"%s\" im Schriftart-Namen \"%s\""
+
+#, c-format
+msgid "E245: Illegal char '%c' in font name \"%s\""
+msgstr "E245: Unzulässiges Zeichen '%c' in der Schriftart \"%s\""
+
+#, c-format
+msgid "Opening the X display took %ld msec"
+msgstr "Öffnen des X-Displays dauerte %ld msec"
+
+msgid ""
+"\n"
+"Vim: Got X error\n"
+msgstr ""
+"\n"
+"Vim: ein X11 Fehler trat auf\n"
+
+msgid "Testing the X display failed"
+msgstr "Test des X-Displays schlug fehl"
+
+msgid "Opening the X display timed out"
+msgstr "Zeitüberschreitung während des Öffnens des X-Displays"
+
+msgid ""
+"\n"
+"Could not get security context for "
+msgstr ""
+"\n"
+"Konnte Security Context nicht erhalten für "
+
+msgid ""
+"\n"
+"Could not set security context for "
+msgstr ""
+"\n"
+"Konnte Security Context nicht setzen für "
+
+#, c-format
+msgid "Could not set security context %s for %s"
+msgstr "Konnte Security Context %s für %s nicht setzen."
+
+#, c-format
+msgid "Could not get security context %s for %s. Removing it!"
+msgstr "Konnte Security Context %s für %s nicht erhalten. Entferne ihn!"
+
+msgid ""
+"\n"
+"Cannot execute shell sh\n"
+msgstr ""
+"\n"
+"Shell sh kann nicht ausführt werden\n"
+
+msgid ""
+"\n"
+"shell returned "
+msgstr ""
+"\n"
+"Shell beendet "
+
+msgid ""
+"\n"
+"Cannot create pipes\n"
+msgstr ""
+"\n"
+"Pipes können nicht angelegt werden\n"
+
+msgid ""
+"\n"
+"Cannot fork\n"
+msgstr ""
+"\n"
+"'fork' schlug fehl\n"
+
+msgid ""
+"\n"
+"Cannot execute shell "
+msgstr ""
+"\n"
+"Shell kann nicht ausführt werden "
+
+msgid ""
+"\n"
+"Command terminated\n"
+msgstr ""
+"\n"
+"Befehl beendet\n"
+
+msgid "XSMP lost ICE connection"
+msgstr "XSMP verlor ICE Verbindung"
+
+#, c-format
+msgid "dlerror = \"%s\""
+msgstr "dlerror = \"%s\""
+
+msgid "Opening the X display failed"
+msgstr "Öffnen des X-Displays schlug fehl"
+
+msgid "XSMP handling save-yourself request"
+msgstr "XSMP verarbeitet 'save-yourself request'"
+
+msgid "XSMP opening connection"
+msgstr "XSMP öffnet Verbindung"
+
+msgid "XSMP ICE connection watch failed"
+msgstr "XSMP ICE Verbindungsüberwachung fehlgeschlagen"
+
+#, c-format
+msgid "XSMP SmcOpenConnection failed: %s"
+msgstr "XSMP SmcOpenConnection fehlgeschlagen: %s"
+
+msgid "At line"
+msgstr "In Zeile"
+
+msgid "Could not load vim32.dll!"
+msgstr "Konnte vim32.dll nicht laden!"
+
+msgid "VIM Error"
+msgstr "VIM Fehler"
+
+msgid "Could not fix up function pointers to the DLL!"
+msgstr "Konnte Funktions-Zeiger in der DLL nicht korrigieren!"
+
+#, c-format
+msgid "Vim: Caught %s event\n"
+msgstr "Vim: Fing Ereignis %s ein\n"
+
+msgid "close"
+msgstr "schließe"
+
+msgid "logoff"
+msgstr "ausloggen"
+
+msgid "shutdown"
+msgstr "beenden"
+
+msgid "E371: Command not found"
+msgstr "E371: Befehl nicht gefunden"
+
+msgid ""
+"VIMRUN.EXE not found in your $PATH.\n"
+"External commands will not pause after completion.\n"
+"See :help win32-vimrun for more information."
+msgstr ""
+"VIMRUN.EXE wurde im Pfad $PATH nicht gefunden.\n"
+"Externe Befehle werden nach Ausführung nicht anhalten.\n"
+"Siehe :help win32-vimrun für weitere Informationen."
+
+msgid "Vim Warning"
+msgstr "Vim Achtung"
+
+#, c-format
+msgid "shell returned %d"
+msgstr "Shell gab %d zurück"
+
+msgid "E926: Current location list was changed"
+msgstr "E926: Aktuelle Positionsliste wurde geändert."
+
+#, c-format
+msgid "E372: Too many %%%c in format string"
+msgstr "E372: Zu viele %%%c im Format"
+
+#, c-format
+msgid "E373: Unexpected %%%c in format string"
+msgstr "E373: Unerwartetes %%%c im Format"
+
+msgid "E374: Missing ] in format string"
+msgstr "E374: Fehlende ] im Format"
+
+#, c-format
+msgid "E375: Unsupported %%%c in format string"
+msgstr "E375: %%%c wird im Format nicht unterstützt"
+
+#, c-format
+msgid "E376: Invalid %%%c in format string prefix"
+msgstr "E376: Unzulässiges %%%c im Prefix des Formats"
+
+#, c-format
+msgid "E377: Invalid %%%c in format string"
+msgstr "E377: Unzulässiges %%%c im Format"
+
+msgid "E378: 'errorformat' contains no pattern"
+msgstr "E378: 'errorformat' enthält kein Muster"
+
+msgid "E379: Missing or empty directory name"
+msgstr "E379: Fehlender oder leerer Verzeichnisname"
+
+msgid "E553: No more items"
+msgstr "E553: Keine weiteren Einträge"
+
+msgid "E924: Current window was closed"
+msgstr "E924: Aktuelles Fenster wurde geschlossen."
+
+msgid "E925: Current quickfix was changed"
+msgstr "E925: Aktuelle Quickfix wurde geändert."
+
+#, c-format
+msgid "(%d of %d)%s%s: "
+msgstr "(%d aus %d)%s%s: "
+
+msgid " (line deleted)"
+msgstr " (Zeile gelöscht)"
+
+#, c-format
+msgid "%serror list %d of %d; %d errors "
+msgstr "%s Fehlerliste %d von %d; %d Fehler"
+
+msgid "E380: At bottom of quickfix stack"
+msgstr "E380: Am Anfang der Quickfix Liste"
+
+msgid "E381: At top of quickfix stack"
+msgstr "E381: An Ende der Quickfix Liste"
+
+msgid "No entries"
+msgstr "Keine Einträge"
+
+msgid "Error file"
+msgstr "Fehlerdatei"
+
+msgid "E683: File name missing or invalid pattern"
+msgstr "E683: Dateiname fehlt oder ungültiges Muster"
+
+#, c-format
+msgid "Cannot open file \"%s\""
+msgstr "Kann Datei \"%s\" nicht öffnen"
+
+msgid "E681: Buffer is not loaded"
+msgstr "E681: Puffer ist nicht geladen"
+
+msgid "E777: String or List expected"
+msgstr "E777: Zeichenkette oder Liste erwartet"
+
+#, c-format
+msgid "E369: invalid item in %s%%[]"
+msgstr "E369: Ungültiges Element in %s%%[]"
+
+#, c-format
+msgid "E769: Missing ] after %s["
+msgstr "E769: Fehlende ] nach %s["
+
+msgid "E944: Reverse range in character class"
+msgstr "E944: Bereich in Zeichenklasse rückwärts"
+
+msgid "E945: Range too large in character class"
+msgstr "E945: Bereich in Zeichenklasse zu groß"
+
+#, c-format
+msgid "E53: Unmatched %s%%("
+msgstr "E53: %s%%( ohne Gegenstück"
+
+#, c-format
+msgid "E54: Unmatched %s("
+msgstr "E54: %s( ohne Gegenstück"
+
+#, c-format
+msgid "E55: Unmatched %s)"
+msgstr "E55: %s) ohne Gegenstück"
+
+msgid "E66: \\z( not allowed here"
+msgstr "E66: \\z( ist hier nicht erlaubt"
+
+msgid "E67: \\z1 - \\z9 not allowed here"
+msgstr "E67: \\z1 - \\z9 ist hier nicht erlaubt"
+
+#, c-format
+msgid "E69: Missing ] after %s%%["
+msgstr "E69: Fehlende ] nach %s%%["
+
+#, c-format
+msgid "E70: Empty %s%%[]"
+msgstr "E70: %s%%[] ist leer"
+
+msgid "E956: Cannot use pattern recursively"
+msgstr "E956: Kann Muster nicht rekursiv ausführen"
+
+msgid "E65: Illegal back reference"
+msgstr "E65: Ungültige Rückreferenz"
+
+msgid "E339: Pattern too long"
+msgstr "E339: Muster zu lang"
+
+msgid "E50: Too many \\z("
+msgstr "E50: Zu viele \\z("
+
+#, c-format
+msgid "E51: Too many %s("
+msgstr "E51: Zu viele %s("
+
+msgid "E52: Unmatched \\z("
+msgstr "E52: \\z( ohne Gegenstück"
+
+#, c-format
+msgid "E59: invalid character after %s@"
+msgstr "E59: Ungültiges Zeichen nach %s@"
+
+#, c-format
+msgid "E60: Too many complex %s{...}s"
+msgstr "E60: Zu viele komplexe %s{...}s"
+
+#, c-format
+msgid "E61: Nested %s*"
+msgstr "E61: Verschachteltes %s*"
+
+#, c-format
+msgid "E62: Nested %s%c"
+msgstr "E62: Verschachteltes %s%c"
+
+msgid "E63: invalid use of \\_"
+msgstr "E63: Ungültige Verwendung von \\_"
+
+#, c-format
+msgid "E64: %s%c follows nothing"
+msgstr "E64: %s%c nach Nichts"
+
+msgid "E68: Invalid character after \\z"
+msgstr "E68: Ungültiges Zeichen nach \\z"
+
+#, c-format
+msgid "E678: Invalid character after %s%%[dxouU]"
+msgstr "E678: Ungültiges Zeichen nach %s%%[dxouU]"
+
+#, c-format
+msgid "E71: Invalid character after %s%%"
+msgstr "E71: Ungültiges Zeichen nach %s%%"
+
+#, c-format
+msgid "E554: Syntax error in %s{...}"
+msgstr "E554: Syntaxfehler in %s{...}"
+
+msgid "External submatches:\n"
+msgstr "Externe 'submatches':\n"
+
+#, c-format
+msgid "E888: (NFA regexp) cannot repeat %s"
+msgstr "E888: (NFA regexp) kann nicht wiederholt werden %s"
+
+msgid ""
+"E864: \\%#= can only be followed by 0, 1, or 2. The automatic engine will be "
+"used "
+msgstr ""
+"E864: Auf \\%#= muss 0, 1, oder 2 folgen. Die automatische Engine wird "
+"genutzt "
+
+msgid "Switching to backtracking RE engine for pattern: "
+msgstr "Wechsele zur Backtracking RE Engine für Muster: "
+
+msgid "E865: (NFA) Regexp end encountered prematurely"
+msgstr "E865: (NFA) Regexp Ende verfrüht aufgetreten"
+
+#, c-format
+msgid "E866: (NFA regexp) Misplaced %c"
+msgstr "E866: (NFA regexp) Deplatziert %c"
+
+#, c-format
+msgid "E877: (NFA regexp) Invalid character class: %ld"
+msgstr "E877: (NFA regexp) Ungültige Zeichenklasse: %ld"
+
+#, c-format
+msgid "E867: (NFA) Unknown operator '\\z%c'"
+msgstr "E867: (NFA) Unbekannter Operator '\\z%c'"
+
+msgid "E951: \\% value too large"
+msgstr "E951: \\% Wert zu groß"
+
+#, c-format
+msgid "E867: (NFA) Unknown operator '\\%%%c'"
+msgstr "E867: (NFA) Unbekannter Operator '\\%%%c'"
+
+msgid "E868: Error building NFA with equivalence class!"
+msgstr "E868: Fehler beim Erstellen der NFA für Äquivalenzklasse!"
+
+#, c-format
+msgid "E869: (NFA) Unknown operator '\\@%c'"
+msgstr "E869: (NFA) Unbekannter Operator '\\@%c'"
+
+msgid "E870: (NFA regexp) Error reading repetition limits"
+msgstr "E870: (NFA regexp) Fehler beim Lesen der Wiederholungsbeschränkung."
+
+msgid "E871: (NFA regexp) Can't have a multi follow a multi"
+msgstr "E871: (NFA regexp) Ein Multi darf nicht auf ein Multi folgen!"
+
+msgid "E872: (NFA regexp) Too many '('"
+msgstr "E872: (NFA regexp) Zu viele '('"
+
+msgid "E879: (NFA regexp) Too many \\z("
+msgstr "E879: (NFA regexp) Zu viele \\z("
+
+msgid "E873: (NFA regexp) proper termination error"
+msgstr "E873: (NFA regexp) geeigneter Abschlussfehler"
+
+msgid "Could not open temporary log file for writing, displaying on stderr... "
+msgstr ""
+"Konnte temporäre Datei nicht zum Schreiben öffnen, zeige auf Standard "
+"Fehlerausgabe... "
+
+msgid "E874: (NFA) Could not pop the stack!"
+msgstr "E874: (NFA) Konnte nicht vom Stack herausnehmen!"
+
+msgid ""
+"E875: (NFA regexp) (While converting from postfix to NFA), too many states "
+"left on stack"
+msgstr ""
+"E875: (NFA regexp) (Beim Konvertieren von postfix zu NFA), zu viele Zustände "
+"auf Stack enthalten"
+
+msgid "E876: (NFA regexp) Not enough space to store the whole NFA "
+msgstr "E876: (NFA regexp) Nicht genug Speicher zum Speichern der NFA"
+
+msgid "E878: (NFA) Could not allocate memory for branch traversal!"
+msgstr "E878: (NFA) Konnte nicht Speicher allokieren um Äste zu durchlaufen!"
+
+msgid " VREPLACE"
+msgstr " V-ERSETZEN"
+
+msgid " REPLACE"
+msgstr " ERSETZEN"
+
+msgid " REVERSE"
+msgstr " INVERTIERT"
+
+msgid " INSERT"
+msgstr " EINFÜGEN"
+
+msgid " (insert)"
+msgstr " (einfügen)"
+
+msgid " (replace)"
+msgstr " (ersetzen)"
+
+msgid " (vreplace)"
+msgstr " (v-ersetzen)"
+
+msgid " Hebrew"
+msgstr " Hebräisch"
+
+msgid " Arabic"
+msgstr " Arabisch"
+
+msgid " (paste)"
+msgstr " (paste)"
+
+msgid " VISUAL"
+msgstr " VISUELL"
+
+msgid " VISUAL LINE"
+msgstr " VISUELL ZEILE"
+
+msgid " VISUAL BLOCK"
+msgstr " VISUELL BLOCK"
+
+msgid " SELECT"
+msgstr " AUSWAHL"
+
+msgid " SELECT LINE"
+msgstr " AUSWAHL ZEILE"
+
+msgid " SELECT BLOCK"
+msgstr " AUSWAHL BLOCK"
+
+msgid "recording"
+msgstr "aufzeichnen"
+
+#, c-format
+msgid "E383: Invalid search string: %s"
+msgstr "E383: Unzulässiges Suchmuster: %s"
+
+#, c-format
+msgid "E384: search hit TOP without match for: %s"
+msgstr "E384: Suche erreichte den ANFANG ohne Treffer für: %s"
+
+#, c-format
+msgid "E385: search hit BOTTOM without match for: %s"
+msgstr "E385: Suche erreichte das ENDE ohne Treffer für: %s"
+
+msgid "E386: Expected '?' or '/' after ';'"
+msgstr "E386: Erwarte '?' oder '/' nach ';'"
+
+msgid " (includes previously listed match)"
+msgstr " (enthält bereits vorher aufgezählte Treffer)"
+
+msgid "--- Included files "
+msgstr "--- Eingefügte Dateien "
+
+msgid "not found "
+msgstr "nicht gefunden "
+
+msgid "in path ---\n"
+msgstr "im Pfad ---\n"
+
+msgid " (Already listed)"
+msgstr " (Bereits aufgelistet)"
+
+msgid " NOT FOUND"
+msgstr " NICHT GEFUNDEN"
+
+#, c-format
+msgid "Scanning included file: %s"
+msgstr "Durchsuche inkludierte Datei: %s"
+
+#, c-format
+msgid "Searching included file %s"
+msgstr "Suche inkludierte Datei %s"
+
+msgid "E387: Match is on current line"
+msgstr "E387: Treffer ist auf der momentanen Zeile"
+
+msgid "All included files were found"
+msgstr "Alle inkludierten Dateien wurden gefunden"
+
+msgid "No included files"
+msgstr "Keine inkludierten Dateien"
+
+msgid "E388: Couldn't find definition"
+msgstr "E388: Konnte Definition nicht finden"
+
+msgid "E389: Couldn't find pattern"
+msgstr "E389: Konnte Muster nicht finden"
+
+msgid "Substitute "
+msgstr "Ersetze"
+
+#, c-format
+msgid ""
+"\n"
+"# Last %sSearch Pattern:\n"
+"~"
+msgstr ""
+"\n"
+"# Letztes %sSuchmuster:\n"
+"~"
+
+msgid "[Deleted]"
+msgstr "[Gelöscht]"
+
+msgid ""
+"\n"
+"--- Signs ---"
+msgstr ""
+"\n"
+"--- Zeichen ---"
+
+#, c-format
+msgid "Signs for %s:"
+msgstr "Zeichen für %s:"
+
+#, c-format
+msgid " group=%s"
+msgstr " Gruppe=%s"
+
+#, c-format
+msgid " line=%ld id=%d%s name=%s priority=%d"
+msgstr " Zeile=%ld id=%d%s Name=%s Priorität=%d"
+
+msgid "E612: Too many signs defined"
+msgstr "E612: Zu viele Zeichen definiert"
+
+#, c-format
+msgid "E239: Invalid sign text: %s"
+msgstr "E239: Ungültiger Text für ein Zeichen: %s"
+
+#, c-format
+msgid "E155: Unknown sign: %s"
+msgstr "E155: Unbekanntes Zeichen: %s"
+
+#, c-format
+msgid "E885: Not possible to change sign %s"
+msgstr "E885: Nicht möglich Zeichen %s zu ändern."
+
+msgid "E159: Missing sign number"
+msgstr "E159: Fehlende Zeichennummer"
+
+#, c-format
+msgid "E157: Invalid sign ID: %d"
+msgstr "E157: Ungültige Zeichen-ID: %d"
+
+msgid "E934: Cannot jump to a buffer that does not have a name"
+msgstr "E934: Kann nicht zu einem Puffer ohne Namen springen."
+
+#, c-format
+msgid "E160: Unknown sign command: %s"
+msgstr "E160: Unbekannter \"sign\"-Befehl: %s"
+
+msgid "E156: Missing sign name"
+msgstr "E156: Name des Zeichens fehlt"
+
+msgid " (NOT FOUND)"
+msgstr " (NICHT GEFUNDEN)"
+
+msgid " (not supported)"
+msgstr " (nicht unterstützt)"
+
+msgid "E756: Spell checking is not enabled"
+msgstr "E756: Rechtschreibprüfung ist nicht aktiviert"
+
+#, c-format
+msgid "Warning: Cannot find word list \"%s_%s.spl\" or \"%s_ascii.spl\""
+msgstr ""
+"Achtung: Kann Wortliste \"%s_%s.spl\" oder \"%s_ascii.spl\" nicht finden"
+
+#, c-format
+msgid "Warning: Cannot find word list \"%s.%s.spl\" or \"%s.ascii.spl\""
+msgstr ""
+"Achtung: Kann Wortliste \"%s.%s.spl\" oder \"%s.ascii.spl\" nicht finden"
+
+msgid "E797: SpellFileMissing autocommand deleted buffer"
+msgstr "E797: SpellFileMissing-Autokommando löschte Puffer"
+
+#, c-format
+msgid "Warning: region %s not supported"
+msgstr "Achtung: Region %s nicht unterstützt"
+
+msgid "Sorry, no suggestions"
+msgstr "Leider keine Vorschläge"
+
+#, c-format
+msgid "Sorry, only %ld suggestions"
+msgstr "Leider nur %ld Vorschläge"
+
+#, c-format
+msgid "Change \"%.*s\" to:"
+msgstr "Ändere \"%.*s\" nach:"
+
+#, c-format
+msgid " < \"%.*s\""
+msgstr " < \"%.*s\""
+
+msgid "E752: No previous spell replacement"
+msgstr "E752: Keine vorhergehende Ersetzung"
+
+#, c-format
+msgid "E753: Not found: %s"
+msgstr "E753: Nicht gefunden: %s"
+
+msgid "E758: Truncated spell file"
+msgstr "E758: Abgeschnittenes Rechtschreibwörterbuch"
+
+#, c-format
+msgid "Trailing text in %s line %d: %s"
+msgstr "Überschüssiger Text in %s Zeile %d: %s"
+
+#, c-format
+msgid "Affix name too long in %s line %d: %s"
+msgstr "Affix Name zu lang in %s Zeile %d: %s"
+
+msgid "E761: Format error in affix file FOL, LOW or UPP"
+msgstr "E761: Format-Fehler in Affix-Datei FOL, LOW oder UPP"
+
+msgid "E762: Character in FOL, LOW or UPP is out of range"
+msgstr "E762: Zeichen in FOL, LOW oder UPP außerhalb des zulässigen Bereichs"
+
+msgid "Compressing word tree..."
+msgstr "Komprimiere Wörter-Baum..."
+
+#, c-format
+msgid "Reading spell file \"%s\""
+msgstr "Lese Rechtschreibwörterbuch \"%s\" ein"
+
+msgid "E757: This does not look like a spell file"
+msgstr "E757: Das sieht nicht nach einem Rechtschreibwörterbuch aus"
+
+msgid "E771: Old spell file, needs to be updated"
+msgstr "E771: Altes Rechtschreibwörterbuch, benötigt Aktualisierung"
+
+msgid "E772: Spell file is for newer version of Vim"
+msgstr "E772: Rechtschreibwörterbuch ist für eine neuere Version von Vim"
+
+msgid "E770: Unsupported section in spell file"
+msgstr "E770: Nicht unterstützter Abschnitt im Rechtschreibwörterbuch"
+
+#, c-format
+msgid "E778: This does not look like a .sug file: %s"
+msgstr "E778: Das sieht nicht nach einer .sug Datei aus: %s"
+
+#, c-format
+msgid "E779: Old .sug file, needs to be updated: %s"
+msgstr "E779: Veraltete .sug Datei; Aktualisierung erforderlich: %s"
+
+#, c-format
+msgid "E780: .sug file is for newer version of Vim: %s"
+msgstr "E780: .sug Datei ist für eine neuere Version von Vim: %s"
+
+#, c-format
+msgid "E781: .sug file doesn't match .spl file: %s"
+msgstr "E781: .sug Datei passt nicht zur .spl Datei: %s"
+
+#, c-format
+msgid "E782: error while reading .sug file: %s"
+msgstr "E782: Fehler beim Lesen der .sug Datei: %s"
+
+#, c-format
+msgid "Reading affix file %s..."
+msgstr "Lese Affix-Datei %s..."
+
+#, c-format
+msgid "Conversion failure for word in %s line %d: %s"
+msgstr "Umwandlungsfehler beim Wort in %s Zeile %d: %s"
+
+#, c-format
+msgid "Conversion in %s not supported: from %s to %s"
+msgstr "Umwandlung in %s nicht unterstützt: von %s nach %s"
+
+#, c-format
+msgid "Invalid value for FLAG in %s line %d: %s"
+msgstr "Ungültiger Wert von FLAG in %s Zeile %d: %s"
+
+#, c-format
+msgid "FLAG after using flags in %s line %d: %s"
+msgstr "FLAG nach dem Gebrauch von Flags in %s Zeile %d: %s"
+
+#, c-format
+msgid ""
+"Defining COMPOUNDFORBIDFLAG after PFX item may give wrong results in %s line "
+"%d"
+msgstr ""
+"Die Definition von COMPOUNDFORBIDFLAG nach dem PFX Element kann falsches "
+"Ergebnis in Zeile %s ergeben %d"
+
+#, c-format
+msgid ""
+"Defining COMPOUNDPERMITFLAG after PFX item may give wrong results in %s line "
+"%d"
+msgstr ""
+"Die Definition von COMPOUNDPERMITFLAG nach dem PFX Element kann falsches "
+"Ergebnis in Zeile %s ergeben %d"
+
+#, c-format
+msgid "Wrong COMPOUNDRULES value in %s line %d: %s"
+msgstr "Falscher COMPOUNDRULES-Wert in %s Zeile %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDWORDMAX value in %s line %d: %s"
+msgstr "Falscher COMPOUNDWORDMAX-Wert in %s Zeile %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDMIN value in %s line %d: %s"
+msgstr "Falscher COMPOUNDMIN-Wert in %s Zeile %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDSYLMAX value in %s line %d: %s"
+msgstr "Falscher COMPOUNDSYLMAX-Wert in %s Zeile %d: %s"
+
+#, c-format
+msgid "Wrong CHECKCOMPOUNDPATTERN value in %s line %d: %s"
+msgstr "Falscher CHECKCOMPOUNDPATTERN-Wert in %s Zeile %d: %s"
+
+#, c-format
+msgid "Different combining flag in continued affix block in %s line %d: %s"
+msgstr ""
+"Unterschiedliches verknüpfendes Flag im fortgesetzten Affix-Block in %s "
+"Zeile %d: %s"
+
+#, c-format
+msgid "Duplicate affix in %s line %d: %s"
+msgstr "Doppeltes Affix in %s Zeile %d: %s"
+
+#, c-format
+msgid ""
+"Affix also used for BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST in %s "
+"line %d: %s"
+msgstr ""
+"Affix wird auch für BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST "
+"verwendet in %s Zeile %d: %s"
+
+#, c-format
+msgid "Expected Y or N in %s line %d: %s"
+msgstr "Y oder N erwartet in %s Zeile %d: %s"
+
+#, c-format
+msgid "Broken condition in %s line %d: %s"
+msgstr "Bedingung verletzt in %s Zeile %d: %s"
+
+#, c-format
+msgid "Expected REP(SAL) count in %s line %d"
+msgstr "Erwartetes REP(SAL) gezählt in %s Zeile %d"
+
+#, c-format
+msgid "Expected MAP count in %s line %d"
+msgstr "Erwartetes MAP gezählt in %s Zeile %d"
+
+#, c-format
+msgid "Duplicate character in MAP in %s line %d"
+msgstr "Doppeltes Zeichen in MAP in %s Zeile %d"
+
+#, c-format
+msgid "Unrecognized or duplicate item in %s line %d: %s"
+msgstr "Nicht erkanntes oder doppeltes Element in %s Zeile %d: %s"
+
+#, c-format
+msgid "Missing FOL/LOW/UPP line in %s"
+msgstr "Fehlende FOL/LOW/UPP Zeile in %s"
+
+msgid "COMPOUNDSYLMAX used without SYLLABLE"
+msgstr "COMPOUNDSYLMAX ohne SYLLABLE verwendet"
+
+msgid "Too many postponed prefixes"
+msgstr "Zu viele zurück gestellte Präfixe"
+
+msgid "Too many compound flags"
+msgstr "Zu viele zusammengesetzte Flags"
+
+msgid "Too many postponed prefixes and/or compound flags"
+msgstr "Zu viele zurück gestellte Präfixe und/oder zusammengesetzte Flags"
+
+#, c-format
+msgid "Missing SOFO%s line in %s"
+msgstr "Fehlende SOFO%s Zeile in %s"
+
+#, c-format
+msgid "Both SAL and SOFO lines in %s"
+msgstr "Sowohl SAL als auch SOFO Zeilen in %s"
+
+#, c-format
+msgid "Flag is not a number in %s line %d: %s"
+msgstr "Flag ist keine Zahl in %s Zeile %d: %s"
+
+#, c-format
+msgid "Illegal flag in %s line %d: %s"
+msgstr "Unerlaubtes Flag in %s Zeile %d: %s"
+
+#, c-format
+msgid "%s value differs from what is used in another .aff file"
+msgstr ""
+"%s Wert unterscheidet sich von dem, was in einer anderen .aff Datei "
+"verwendet wird"
+
+#, c-format
+msgid "Reading dictionary file %s..."
+msgstr "Lese Wörterbuch-Datei %s..."
+
+#, c-format
+msgid "E760: No word count in %s"
+msgstr "E760: Kein Wortanzahl in %s"
+
+#, c-format
+msgid "line %6d, word %6ld - %s"
+msgstr "Zeile %6d, Wort %6ld - %s"
+
+#, c-format
+msgid "Duplicate word in %s line %d: %s"
+msgstr "Doppeltes Wort in %s Zeile %d: %s"
+
+#, c-format
+msgid "First duplicate word in %s line %d: %s"
+msgstr "Erstes doppeltes Wort in %s Zeile %d: %s"
+
+#, c-format
+msgid "%d duplicate word(s) in %s"
+msgstr "%d doppelte(s) Wort(e) in %s"
+
+#, c-format
+msgid "Ignored %d word(s) with non-ASCII characters in %s"
+msgstr "%d Wort(e) mit nicht-ASCII Zeichen ignoriert in %s"
+
+#, c-format
+msgid "Reading word file %s..."
+msgstr "Lese Wort-Datei %s..."
+
+#, c-format
+msgid "Duplicate /encoding= line ignored in %s line %d: %s"
+msgstr "Doppelte /encoding= Zeile ignoriert in %s Zeile %d: %s"
+
+#, c-format
+msgid "/encoding= line after word ignored in %s line %d: %s"
+msgstr "/encoding= Zeile nach Wort ignoriert in %s Zeile %d: %s"
+
+#, c-format
+msgid "Duplicate /regions= line ignored in %s line %d: %s"
+msgstr "Doppelte /regions= Zeile ignoriert in %s Zeile %d: %s"
+
+#, c-format
+msgid "Too many regions in %s line %d: %s"
+msgstr "Zu viele Regionen in %s Zeile %d: %s"
+
+#, c-format
+msgid "/ line ignored in %s line %d: %s"
+msgstr "/ Zeile ignoriert in %s Zeile %d: %s"
+
+#, c-format
+msgid "Invalid region nr in %s line %d: %s"
+msgstr "Ungültige Regionsnummer in %s Zeile %d: %s"
+
+#, c-format
+msgid "Unrecognized flags in %s line %d: %s"
+msgstr "Nicht erkanntes Flag in %s Zeile %d: %s"
+
+#, c-format
+msgid "Ignored %d words with non-ASCII characters"
+msgstr "%d Wörter mit nicht-ASCII Zeichen ignoriert"
+
+msgid "E845: Insufficient memory, word list will be incomplete"
+msgstr "E845: Nicht ausreichend Speicher, Wortliste wird unvollständig sein"
+
+#, c-format
+msgid "Compressed %d of %d nodes; %d (%d%%) remaining"
+msgstr "%d von %d Knoten komprimiert; %d (%d%%) übrig"
+
+msgid "Reading back spell file..."
+msgstr "Lese Rechtschreibwörterbuch zurück..."
+
+msgid "Performing soundfolding..."
+msgstr "Führe 'Soundfolding' durch..."
+
+#, c-format
+msgid "Number of words after soundfolding: %ld"
+msgstr "Anzahl der Wörter nach 'Soundfolding': %ld"
+
+#, c-format
+msgid "Total number of words: %d"
+msgstr "Gesamte Anzahl von Wörtern: %d"
+
+#, c-format
+msgid "Writing suggestion file %s..."
+msgstr "Schreibe Datei %s für Vorschläge..."
+
+#, c-format
+msgid "Estimated runtime memory use: %d bytes"
+msgstr "Geschätzter Speicher zur Laufzeit: %d Bytes"
+
+msgid "E751: Output file name must not have region name"
+msgstr "E751: Ausgabedatei darf keinen Regionsnamen haben"
+
+#, c-format
+msgid "E754: Only up to %d regions supported"
+msgstr "E754: Maximal %d Regionen unterstützt"
+
+#, c-format
+msgid "E755: Invalid region in %s"
+msgstr "E755: Ungültige Region in %s"
+
+msgid "Warning: both compounding and NOBREAK specified"
+msgstr "Achtung: Sowohl zusammengesetzte Wörter als auch NOBREAK angegeben"
+
+#, c-format
+msgid "Writing spell file %s..."
+msgstr "Schreibe Rechtschreibwörterbuch %s..."
+
+msgid "Done!"
+msgstr "Fertig!"
+
+#, c-format
+msgid "E765: 'spellfile' does not have %d entries"
+msgstr "E765: 'spellfile' hat nicht %d Einträge"
+
+#, c-format
+msgid "Word '%.*s' removed from %s"
+msgstr "Wort '%.*s' entfernt von %s"
+
+#, c-format
+msgid "Word '%.*s' added to %s"
+msgstr "Wort '%.*s' hinzugefügt zu %s"
+
+msgid "E763: Word characters differ between spell files"
+msgstr ""
+"E763: 'Word Characters' unterscheiden sich zwischen Rechtschreibwörterbüchern"
+
+msgid "E783: duplicate char in MAP entry"
+msgstr "E783: Doppeltes Zeichen im MAP Eintrag"
+
+msgid "No Syntax items defined for this buffer"
+msgstr "Keine Syntax-Elemente für diesen Puffer definiert"
+
+msgid "'redrawtime' exceeded, syntax highlighting disabled"
+msgstr "'redrawtime' überschritten, Syntaxhighlighting deaktiviert"
+
+msgid "syntax conceal on"
+msgstr "Syntax conceal aktiviert"
+
+msgid "syntax conceal off"
+msgstr "Syntax conceal deaktiviert"
+
+#, c-format
+msgid "E390: Illegal argument: %s"
+msgstr "E390: Unerlaubtes Argument: %s"
+
+msgid "syntax case ignore"
+msgstr "Syntax ignoriere Groß-/Kleinschreibung"
+
+msgid "syntax case match"
+msgstr "Syntax unterscheide Groß-/Kleinschreibung"
+
+msgid "syntax spell toplevel"
+msgstr "Prüfe Rechtschreibung von Text ohne zugehörige Syntaxgruppe"
+
+msgid "syntax spell notoplevel"
+msgstr "Prüfe keine Rechtschreibung von Text ohne zugehörige Syntaxgruppe"
+
+msgid "syntax spell default"
+msgstr ""
+"Prüfe Rechtschreibung von Text ohne zugehörige Syntaxgruppen nur bei @Spell/"
+"@NoSpell Attribut."
+
+msgid "syntax iskeyword "
+msgstr "syntax iskeyword "
+
+msgid "syntax iskeyword not set"
+msgstr "syntax iskeyword nicht gesetzt"
+
+#, c-format
+msgid "E391: No such syntax cluster: %s"
+msgstr "E391: Kein solcher Syntax Cluster: %s"
+
+msgid "syncing on C-style comments"
+msgstr "Synchronisation an C-Stil Kommentaren"
+
+msgid "no syncing"
+msgstr "keine Synchronisation"
+
+msgid "syncing starts "
+msgstr "Synchronisation beginnt "
+
+msgid " lines before top line"
+msgstr " Zeilen vor der obersten Zeile"
+
+msgid ""
+"\n"
+"--- Syntax sync items ---"
+msgstr ""
+"\n"
+"--- Syntax Synchronisations-Elemente ---"
+
+msgid ""
+"\n"
+"syncing on items"
+msgstr ""
+"\n"
+"Synchronisation an Elementen"
+
+msgid ""
+"\n"
+"--- Syntax items ---"
+msgstr ""
+"\n"
+"--- Syntax-Elemente ---"
+
+#, c-format
+msgid "E392: No such syntax cluster: %s"
+msgstr "E392: Kein solcher Syntax-Cluster: %s"
+
+msgid "minimal "
+msgstr "minimal "
+
+msgid "maximal "
+msgstr "maximal "
+
+msgid "; match "
+msgstr "; Treffer "
+
+msgid " line breaks"
+msgstr " Zeilenumbrüche"
+
+msgid "E395: contains argument not accepted here"
+msgstr "E395: \"contains\"-Argument ist an dieser Stelle ungültig"
+
+msgid "E844: invalid cchar value"
+msgstr "E844: Ungültiger cchar Wert"
+
+msgid "E393: group[t]here not accepted here"
+msgstr "E393: \"group[t]here\" ist an dieser Stelle ungültig"
+
+#, c-format
+msgid "E394: Didn't find region item for %s"
+msgstr "E394: Konnte kein \"region\"-Element für \"%s\" finden"
+
+msgid "E397: Filename required"
+msgstr "E397: Dateiname wird benötigt"
+
+msgid "E847: Too many syntax includes"
+msgstr "E847: Zu viele Syntax Includedateien"
+
+#, c-format
+msgid "E789: Missing ']': %s"
+msgstr "E789: Fehlende ']': %s"
+
+#, c-format
+msgid "E890: trailing char after ']': %s]%s"
+msgstr "E890: Überschüssige Zeichen nach ']': %s]%s"
+
+#, c-format
+msgid "E398: Missing '=': %s"
+msgstr "E398: Fehlendes '=': %s"
+
+#, c-format
+msgid "E399: Not enough arguments: syntax region %s"
+msgstr "E399: Nicht ausreichend viele Argumente: syntax region %s"
+
+msgid "E848: Too many syntax clusters"
+msgstr "E848: Zu viele Syntax Cluster"
+
+msgid "E400: No cluster specified"
+msgstr "E400: Kein Cluster angegeben"
+
+#, c-format
+msgid "E401: Pattern delimiter not found: %s"
+msgstr "E401: Muster-Begrenzer nicht gefunden: %s"
+
+#, c-format
+msgid "E402: Garbage after pattern: %s"
+msgstr "E402: Schrott nach Muster: %s"
+
+msgid "E403: syntax sync: line continuations pattern specified twice"
+msgstr "E403: Syntax sync: Zeilen-Fortsetzungsmuster zweifach angegeben"
+
+#, c-format
+msgid "E404: Illegal arguments: %s"
+msgstr "E404: Unzulässige Argumente; %s"
+
+#, c-format
+msgid "E405: Missing equal sign: %s"
+msgstr "E405: Gleichheitszeichen fehlt: %s"
+
+#, c-format
+msgid "E406: Empty argument: %s"
+msgstr "E406: Leeres Argument: %s"
+
+#, c-format
+msgid "E407: %s not allowed here"
+msgstr "E407: %s ist hier nicht erlaubt"
+
+#, c-format
+msgid "E408: %s must be first in contains list"
+msgstr ""
+"E408: %s muss als Erstes in der Liste der enthaltenen Elemente auftreten"
+
+#, c-format
+msgid "E409: Unknown group name: %s"
+msgstr "E409: Unbekannter Gruppenname: %s"
+
+#, c-format
+msgid "E410: Invalid :syntax subcommand: %s"
+msgstr "E410: Ungültiger :syntax Befehl: %s"
+
+msgid ""
+" TOTAL COUNT MATCH SLOWEST AVERAGE NAME PATTERN"
+msgstr ""
+" TOTAL ANZAHL MATCH LANGSAMST DURCHSCHN NAME MUSTER"
+
+msgid "E679: recursive loop loading syncolor.vim"
+msgstr "E679: Rekursive Schleife beim Laden von syncolor.vim"
+
+#, c-format
+msgid "E411: highlight group not found: %s"
+msgstr "E411: Hervorhebungsgruppe nicht gefunden: %s"
+
+#, c-format
+msgid "E412: Not enough arguments: \":highlight link %s\""
+msgstr "E412: Nicht genügend Argumente: \":highlight link %s\""
+
+#, c-format
+msgid "E413: Too many arguments: \":highlight link %s\""
+msgstr "E413: Zu viele Argumente: \":highlight link %s\""
+
+msgid "E414: group has settings, highlight link ignored"
+msgstr "E414: Gruppe hat Einstellungen, highlight link ignoriert"
+
+#, c-format
+msgid "E415: unexpected equal sign: %s"
+msgstr "E415: Unerwartetes Gleichheitszeichen: %s"
+
+#, c-format
+msgid "E416: missing equal sign: %s"
+msgstr "E416: fehlendes Gleichheitszeichen: %s"
+
+#, c-format
+msgid "E417: missing argument: %s"
+msgstr "E417: Fehlendes Argument: %s"
+
+#, c-format
+msgid "E418: Illegal value: %s"
+msgstr "E418: Unzulässiger Wert: %s"
+
+msgid "E419: FG color unknown"
+msgstr "E419: Vordergrundfarbe unbekannt"
+
+msgid "E420: BG color unknown"
+msgstr "E420: Hintergrundfarbe unbekannt"
+
+#, c-format
+msgid "E421: Color name or number not recognized: %s"
+msgstr "E421: Unbekannte Farbbezeichnung oder -Nummer: %s"
+
+#, c-format
+msgid "E422: terminal code too long: %s"
+msgstr "E422: Terminal-Code zu lang: %s"
+
+#, c-format
+msgid "E423: Illegal argument: %s"
+msgstr "E423: Unzulässiges Argument: %s"
+
+msgid "E424: Too many different highlighting attributes in use"
+msgstr "E424: Zu viele verschieden Hervorhebungsattribute in Gebrauch"
+
+msgid "E669: Unprintable character in group name"
+msgstr "E669: Nicht druckbare Zeichen im Namen der Gruppe"
+
+msgid "W18: Invalid character in group name"
+msgstr "W18: Ungültiges Zeichen im Namen der Gruppe"
+
+msgid "E849: Too many highlight and syntax groups"
+msgstr "E849: Zu viele Highlight- und Syntaxgruppen"
+
+msgid "E555: at bottom of tag stack"
+msgstr "E555: Am Ende des Tag-Stacks"
+
+msgid "E556: at top of tag stack"
+msgstr "E556: Am Anfang des Tag-Stacks"
+
+msgid "E425: Cannot go before first matching tag"
+msgstr "E425: Kann nicht vor den ersten passenden Tag hinausgehen"
+
+#, c-format
+msgid "E426: tag not found: %s"
+msgstr "E426: Konnte Tag \"%s\" nicht finden"
+
+msgid " # pri kind tag"
+msgstr " # Prio Art Tag"
+
+msgid "file\n"
+msgstr "Datei\n"
+
+msgid "E427: There is only one matching tag"
+msgstr "E427: Es gibt nur einen passenden Tag"
+
+msgid "E428: Cannot go beyond last matching tag"
+msgstr "E428: Kann nicht über den letzten passenden Tag hinausgehen"
+
+#, c-format
+msgid "File \"%s\" does not exist"
+msgstr "Die Datei \"%s\" existiert nicht"
+
+#, c-format
+msgid "tag %d of %d%s"
+msgstr "Tag %d aus %d%s"
+
+msgid " or more"
+msgstr " oder mehr"
+
+msgid " Using tag with different case!"
+msgstr " Verwendung eines Tags mit abgewandelter Groß-/Klein-Schreibung"
+
+#, c-format
+msgid "E429: File \"%s\" does not exist"
+msgstr "E429: Die Datei \"%s\" existiert nicht"
+
+msgid ""
+"\n"
+" # TO tag FROM line in file/text"
+msgstr ""
+"\n"
+" # NACH TAG VON Zeile in Datei/Text"
+
+#, c-format
+msgid "Searching tags file %s"
+msgstr "Tag-Datei %s wird durchsucht"
+
+#, c-format
+msgid "E430: Tag file path truncated for %s\n"
+msgstr "E430: Tag-Dateipfad wurde abgeschnitten für %s\n"
+
+msgid "Ignoring long line in tags file"
+msgstr "Ignoriere zu lange Zeile in Tag-Datei"
+
+#, c-format
+msgid "E431: Format error in tags file \"%s\""
+msgstr "E431: Format Fehler in Tag-Datei \"%s\""
+
+#, c-format
+msgid "Before byte %ld"
+msgstr "Vor Byte %ld"
+
+#, c-format
+msgid "E432: Tags file not sorted: %s"
+msgstr "E432: Tag-Datei ist nicht sortiert: %s"
+
+msgid "E433: No tags file"
+msgstr "E433: Keine Tag-Datei"
+
+msgid "E434: Can't find tag pattern"
+msgstr "E434: Kann Tag-Muster nicht finden"
+
+msgid "E435: Couldn't find tag, just guessing!"
+msgstr "E435: Konnte Tag möglicherweise nicht finden!"
+
+#, c-format
+msgid "Duplicate field name: %s"
+msgstr "Doppelter Feldname: %s"
+
+msgid "' not known. Available builtin terminals are:"
+msgstr ""
+"' nicht bekannt. Die folgenden eingebauten Terminals stehen zur Verfügung:"
+
+msgid "defaulting to '"
+msgstr "Voreinstellung '"
+
+msgid "E557: Cannot open termcap file"
+msgstr "E557: Termcap-Datei kann nicht geöffnet werden"
+
+msgid "E558: Terminal entry not found in terminfo"
+msgstr "E558: Kein Terminal-Eintrag in der Terminfo-Datenbank gefunden"
+
+msgid "E559: Terminal entry not found in termcap"
+msgstr "E559: Kein Terminal-Eintrag in der Termcap-Datei gefunden"
+
+#, c-format
+msgid "E436: No \"%s\" entry in termcap"
+msgstr "E436: Kein \"%s\" Eintrag in der Termcap-Datei"
+
+msgid "E437: terminal capability \"cm\" required"
+msgstr "E437: Terminalfähigkeit \"cm\" wird benötigt"
+
+msgid ""
+"\n"
+"--- Terminal keys ---"
+msgstr ""
+"\n"
+"--- Terminal Tasten ---"
+
+msgid "Cannot open $VIMRUNTIME/rgb.txt"
+msgstr "Kann Datei $VIMRUNTIME/rgb.txt nicht öffnen."
+
+#, c-format
+msgid "Kill job in \"%s\"?"
+msgstr "Beende job in \"%s\"?"
+
+msgid "Terminal"
+msgstr "Terminal"
+
+msgid "Terminal-finished"
+msgstr "Terminal beendet"
+
+msgid "active"
+msgstr "aktiv"
+
+msgid "running"
+msgstr "führe aus"
+
+msgid "finished"
+msgstr "beendet"
+
+msgid "E958: Job already finished"
+msgstr "E958: Job bereits beendet"
+
+#, c-format
+msgid "E953: File exists: %s"
+msgstr "E953: Datei existiert bereits: %s"
+
+msgid "E955: Not a terminal buffer"
+msgstr "E955: Kein Terminal Puffer"
+
+#, c-format
+msgid "E971: Property type %s does not exist"
+msgstr "E971: Der Eigenschaftstyp %s existiert nicht"
+
+#, c-format
+msgid "E964: Invalid column number: %ld"
+msgstr "E964: Ungültige Spaltennummer: %ld"
+
+#, c-format
+msgid "E966: Invalid line number: %ld"
+msgstr "E966: Ungültige Zeilennummer: %ld"
+
+msgid "E965: missing property type name"
+msgstr "E965: Fehlender Eigenschaften Typname"
+
+msgid "E967: text property info corrupted"
+msgstr "E967: Texteigenschaft-Info beschädigt"
+
+msgid "E968: Need at least one of 'id' or 'type'"
+msgstr "E968: Benötige entweder 'id' oder 'type'"
+
+#, c-format
+msgid "E969: Property type %s already defined"
+msgstr "E969: Eigenschaftentyp %s bereits definiert"
+
+#, c-format
+msgid "E970: Unknown highlight group name: '%s'"
+msgstr "E970: Unbekannter Highlighting-Gruppenname: '%s'"
+
+msgid "new shell started\n"
+msgstr "neue Shell gestartet\n"
+
+msgid "Vim: Error reading input, exiting...\n"
+msgstr "Vim: Fehler beim Lesen der Eingabe, Abbruch...\n"
+
+msgid "Used CUT_BUFFER0 instead of empty selection"
+msgstr "CUT_BUFFER0 anstatt der leeren Auswahl benutzt"
+
+msgid "E881: Line count changed unexpectedly"
+msgstr "E881: Zeilenanzahl änderte sich unerwartet"
+
+msgid "No undo possible; continue anyway"
+msgstr "Wiederherstellung nicht möglich; setze trotzdem fort"
+
+#, c-format
+msgid "E828: Cannot open undo file for writing: %s"
+msgstr "E828: Undo-Datei kann nicht zum Schreiben geöffnet werden: %s"
+
+#, c-format
+msgid "E825: Corrupted undo file (%s): %s"
+msgstr "E825: Beschädigte Undo-Datei (%s): %s"
+
+msgid "Cannot write undo file in any directory in 'undodir'"
+msgstr ""
+"Undo-Datei kann in keines der Verzeichnisse aus 'undodir' geschrieben werden."
+
+#, c-format
+msgid "Will not overwrite with undo file, cannot read: %s"
+msgstr "Überschreibe nicht mit Undo-Datei, nicht lesbar: %s"
+
+#, c-format
+msgid "Will not overwrite, this is not an undo file: %s"
+msgstr "Überschreibe nicht, dies ist keine Undo-Datei: %s"
+
+msgid "Skipping undo file write, nothing to undo"
+msgstr ""
+"Überspringe Schreiben der Undo-Datei, es gibt nichts zum rückgängig machen."
+
+#, c-format
+msgid "Writing undo file: %s"
+msgstr "Schreiben der Undo-Datei %s"
+
+#, c-format
+msgid "E829: write error in undo file: %s"
+msgstr "E829: Fehler beim Schreiben in Undo-Datei: %s"
+
+#, c-format
+msgid "Not reading undo file, owner differs: %s"
+msgstr "Lese nicht Undo-Datei, Besitzer unterscheidet sich: %s"
+
+#, c-format
+msgid "Reading undo file: %s"
+msgstr "Lese Undo-Datei: %s"
+
+#, c-format
+msgid "E822: Cannot open undo file for reading: %s"
+msgstr "E822: Undo-Datei kann nicht zum Lesen geöffnet werden: %s"
+
+#, c-format
+msgid "E823: Not an undo file: %s"
+msgstr "E823: Keine Undo-Datei: %s"
+
+#, c-format
+msgid "E832: Non-encrypted file has encrypted undo file: %s"
+msgstr "E832: Unverschlüsselte Datei besitzt verschlüsselte Undo-Datei: %s"
+
+#, c-format
+msgid "E826: Undo file decryption failed: %s"
+msgstr "E826: Entschlüsselung der Undo-Datei fehlgeschlagen: %s"
+
+#, c-format
+msgid "E827: Undo file is encrypted: %s"
+msgstr "E827: Undo-Datei ist verschlüsselt: %s"
+
+#, c-format
+msgid "E824: Incompatible undo file: %s"
+msgstr "E824: Inkompatible Undo-Datei: %s"
+
+msgid "File contents changed, cannot use undo info"
+msgstr "Dateiinhalt hat sich geändert, kann Undo Informationen nicht nutzen."
+
+#, c-format
+msgid "Finished reading undo file %s"
+msgstr "Lesen der Undo-Datei %s abgeschlossen"
+
+msgid "Already at oldest change"
+msgstr "Bereits bei der ältesten Änderung"
+
+msgid "Already at newest change"
+msgstr "Bereits bei der jüngsten Änderung"
+
+#, c-format
+msgid "E830: Undo number %ld not found"
+msgstr "E830: Undo Nummer %ld nicht gefunden"
+
+msgid "E438: u_undo: line numbers wrong"
+msgstr "E438: u_undo: Zeilennummer falsch"
+
+msgid "more line"
+msgstr "Zeile mehr"
+
+msgid "more lines"
+msgstr "Zeilen mehr"
+
+msgid "line less"
+msgstr "Zeile weniger"
+
+msgid "fewer lines"
+msgstr "Zeilen weniger"
+
+msgid "change"
+msgstr "Änderung"
+
+msgid "changes"
+msgstr "Änderungen"
+
+#, c-format
+msgid "%ld %s; %s #%ld %s"
+msgstr "%ld %s; %s #%ld %s"
+
+msgid "before"
+msgstr "vor"
+
+msgid "after"
+msgstr "nach"
+
+msgid "Nothing to undo"
+msgstr "Nichts zum Wiederherstellen"
+
+msgid "number changes when saved"
+msgstr "Nummer Änderung Wann Gesichert"
+
+#, c-format
+msgid "%ld second ago"
+msgid_plural "%ld seconds ago"
+msgstr[0] "vor %ld Sekunde"
+msgstr[1] "vor %ld Sekunden"
+
+msgid "E790: undojoin is not allowed after undo"
+msgstr "E790: 'undojoin' ist nicht erlaubt nach 'undo'"
+
+msgid "E439: undo list corrupt"
+msgstr "E439: Liste der Wiederherstellungen fehlerhaft"
+
+msgid "E440: undo line missing"
+msgstr "E440: Wiederherstellungszeile fehlt"
+
+#, c-format
+msgid "E122: Function %s already exists, add ! to replace it"
+msgstr "E122: Funktion %s existiert bereits; zum Ersetzen ! hinzufügen"
+
+msgid "E717: Dictionary entry already exists"
+msgstr "E717: Dictionary-Eintrag existiert bereits"
+
+msgid "E718: Funcref required"
+msgstr "E718: Funktionsreferenz benötigt"
+
+#, c-format
+msgid "E130: Unknown function: %s"
+msgstr "E130: Unbekannte Funktion: %s"
+
+#, c-format
+msgid "E125: Illegal argument: %s"
+msgstr "E125: Unzulässiges Argument: %s"
+
+#, c-format
+msgid "E853: Duplicate argument name: %s"
+msgstr "E853: Doppelter Argumentname: %s"
+
+#, c-format
+msgid "E740: Too many arguments for function %s"
+msgstr "E740: Zu viele Argumente für Funktion %s"
+
+#, c-format
+msgid "E116: Invalid arguments for function %s"
+msgstr "E116: Ungültige Argumente für die Funktion %s"
+
+msgid "E132: Function call depth is higher than 'maxfuncdepth'"
+msgstr "E132: Funktionsaufrufstiefe überschreitet 'maxfuncdepth'"
+
+#, c-format
+msgid "calling %s"
+msgstr "rufe %s auf"
+
+#, c-format
+msgid "%s aborted"
+msgstr "%s abgebrochen"
+
+#, c-format
+msgid "%s returning #%ld"
+msgstr "%s lieferte #%ld zurück"
+
+#, c-format
+msgid "%s returning %s"
+msgstr "%s lieferte \"%s\" zurück"
+
+msgid "E699: Too many arguments"
+msgstr "E699: Zu viele Argumente"
+
+#, c-format
+msgid "E117: Unknown function: %s"
+msgstr "E117: Unbekannte Funktion: %s"
+
+#, c-format
+msgid "E933: Function was deleted: %s"
+msgstr "E933: Funktion wurde gelöscht: %s"
+
+#, c-format
+msgid "E119: Not enough arguments for function: %s"
+msgstr "E119: Zu wenige Argumente für Funktion: %s"
+
+#, c-format
+msgid "E120: Using <SID> not in a script context: %s"
+msgstr "E120: <SID> wurde nicht in einer Skript-Umgebung benutzt: %s"
+
+#, c-format
+msgid "E725: Calling dict function without Dictionary: %s"
+msgstr "E725: Aufruf der 'dict' Funktion ohne Dictionary: %s"
+
+msgid "E129: Function name required"
+msgstr "E129: Funktionsname wird benötigt"
+
+# #msgid "E129: Function name required"
+# #msgstr "E129: Funktionsname wird verlangt"
+#, c-format
+msgid "E128: Function name must start with a capital or \"s:\": %s"
+msgstr ""
+"E128: Funktionsname muss mit einem Großbuchstaben oder \"s:\" beginnen: %s"
+
+#, c-format
+msgid "E884: Function name cannot contain a colon: %s"
+msgstr "E884: Funktionsname darf keinen Doppelpunkt enthalten: %s"
+
+#, c-format
+msgid "E123: Undefined function: %s"
+msgstr "E123: Undefinierte Funktion: %s"
+
+#, c-format
+msgid "E124: Missing '(': %s"
+msgstr "E124: Fehlendes '(': %s"
+
+msgid "E862: Cannot use g: here"
+msgstr "E862: g: kann hier nicht benutzt werden"
+
+#, c-format
+msgid "E932: Closure function should not be at top level: %s"
+msgstr ""
+"E932: Closure Funktion kann nicht auf äussersten Level definiert sein: %s"
+
+msgid "E126: Missing :endfunction"
+msgstr "E126: Fehlendes :endfunction"
+
+#, c-format
+msgid "W22: Text found after :endfunction: %s"
+msgstr "W22: Überschüssiger Text nach :endfunction: %s"
+
+#, c-format
+msgid "E707: Function name conflicts with variable: %s"
+msgstr "E707: Funktionsname kollidiert mit Variable: %s"
+
+#, c-format
+msgid "E127: Cannot redefine function %s: It is in use"
+msgstr "E127: Funktion %s kann nicht umdefiniert werden, da noch in Verwendung"
+
+#, c-format
+msgid "E746: Function name does not match script file name: %s"
+msgstr ""
+"E746: Funktionsname stimmt mit dem Namen der Skript-Datei nicht überein: %s."
+
+#, c-format
+msgid "E131: Cannot delete function %s: It is in use"
+msgstr "E131: Funktion %s kann nicht gelöscht werden: sie ist in Verwendung"
+
+msgid "E133: :return not inside a function"
+msgstr "E133: :return außerhalb einer Funktion"
+
+#, c-format
+msgid "E107: Missing parentheses: %s"
+msgstr "E107: Fehlende Klammern: %s"
+
+#, c-format
+msgid "%s (%s, compiled %s)"
+msgstr "%s (%s kompiliert am %s)"
+
+msgid ""
+"\n"
+"MS-Windows 64-bit GUI version"
+msgstr ""
+"\n"
+"MS-Windows 64 Bit GUI Version"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit GUI version"
+msgstr ""
+"\n"
+"MS-Windows 32 Bit GUI Version"
+
+msgid " with OLE support"
+msgstr " mit OLE-Unterstützung"
+
+msgid ""
+"\n"
+"MS-Windows 64-bit console version"
+msgstr ""
+"\n"
+"MS-Windows 64 Bit Konsolen-Version"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit console version"
+msgstr ""
+"\n"
+"MS-Windows 32 Bit Konsolen-Version"
+
+msgid ""
+"\n"
+"macOS version"
+msgstr ""
+"\n"
+"MacOS Version"
+
+msgid ""
+"\n"
+"macOS version w/o darwin feat."
+msgstr ""
+"\n"
+"MacOS Version ohne Darwin"
+
+msgid ""
+"\n"
+"OpenVMS version"
+msgstr ""
+"\n"
+"OpenVMS Version"
+
+msgid ""
+"\n"
+"Included patches: "
+msgstr ""
+"\n"
+"Inklusive der Patches: "
+
+msgid ""
+"\n"
+"Extra patches: "
+msgstr ""
+"\n"
+"Extra Patches: "
+
+msgid "Modified by "
+msgstr "Verändert von "
+
+msgid ""
+"\n"
+"Compiled "
+msgstr ""
+"\n"
+"Übersetzt "
+
+msgid "by "
+msgstr "von "
+
+msgid ""
+"\n"
+"Huge version "
+msgstr ""
+"\n"
+"Riesige Version "
+
+msgid ""
+"\n"
+"Big version "
+msgstr ""
+"\n"
+"Große Version "
+
+msgid ""
+"\n"
+"Normal version "
+msgstr ""
+"\n"
+"Normale Version "
+
+msgid ""
+"\n"
+"Small version "
+msgstr ""
+"\n"
+"Kleine Version "
+
+msgid ""
+"\n"
+"Tiny version "
+msgstr ""
+"\n"
+"Winzige Version "
+
+msgid "without GUI."
+msgstr "ohne GUI."
+
+msgid "with GTK3 GUI."
+msgstr "mit GTK3 GUI."
+
+msgid "with GTK2-GNOME GUI."
+msgstr "mit GTK2-GNOME GUI."
+
+msgid "with GTK2 GUI."
+msgstr "mit GTK2 GUI."
+
+msgid "with X11-Motif GUI."
+msgstr "mit X11-Motif GUI."
+
+msgid "with X11-neXtaw GUI."
+msgstr "mit X11-neXtaw GUI."
+
+msgid "with X11-Athena GUI."
+msgstr "mit X11-Athena GUI."
+
+msgid "with Photon GUI."
+msgstr "mit Photon GUI."
+
+msgid "with GUI."
+msgstr "mit GUI."
+
+msgid "with Carbon GUI."
+msgstr "mit Carbon GUI."
+
+msgid "with Cocoa GUI."
+msgstr "mit Cocoa GUI."
+
+msgid " Features included (+) or not (-):\n"
+msgstr " Ein- (+) oder ausschließlich (-) der Eigenschaften:\n"
+
+msgid " system vimrc file: \""
+msgstr " System-vimrc-Datei: \""
+
+msgid " user vimrc file: \""
+msgstr " Benutzer-vimrc-Datei: \""
+
+msgid " 2nd user vimrc file: \""
+msgstr " zweite Benutzer-vimrc-Datei: \""
+
+msgid " 3rd user vimrc file: \""
+msgstr " dritte Benutzer-vimrc-Datei: \""
+
+msgid " user exrc file: \""
+msgstr " Benutzer-exrc-Datei: \""
+
+msgid " 2nd user exrc file: \""
+msgstr " zweite Benutzer-exrc-Datei: \""
+
+msgid " system gvimrc file: \""
+msgstr " System-gvimrc-Datei: \""
+
+msgid " user gvimrc file: \""
+msgstr " Benutzer-gvimrc-Datei: \""
+
+msgid "2nd user gvimrc file: \""
+msgstr "zweite Benutzer-gvimrc-Datei: \""
+
+msgid "3rd user gvimrc file: \""
+msgstr "dritte Benutzer-gvimrc-Datei: \""
+
+msgid " defaults file: \""
+msgstr " defaults Datei: \""
+
+msgid " system menu file: \""
+msgstr " System-Menü-Datei: \""
+
+msgid " fall-back for $VIM: \""
+msgstr " Voreinstellung für $VIM: \""
+
+msgid " f-b for $VIMRUNTIME: \""
+msgstr " und für $VIMRUNTIME: \""
+
+msgid "Compilation: "
+msgstr "Übersetzt: "
+
+msgid "Compiler: "
+msgstr "Compiler: "
+
+msgid "Linking: "
+msgstr "Linken: "
+
+msgid " DEBUG BUILD"
+msgstr " DEBUG-VERSION"
+
+msgid "VIM - Vi IMproved"
+msgstr "VIM - verbesserter Vi"
+
+msgid "version "
+msgstr "Version "
+
+msgid "by Bram Moolenaar et al."
+msgstr "von Bram Moolenaar und Anderen"
+
+msgid "Vim is open source and freely distributable"
+msgstr "Vim ist Open Source und kann frei weitergegeben werden"
+
+msgid "Help poor children in Uganda!"
+msgstr "Hilf armen Kindern in Uganda!"
+
+msgid "type :help iccf<Enter> for information "
+msgstr "Tippe :help iccf<Enter> für Informationen darüber "
+
+msgid "type :q<Enter> to exit "
+msgstr "Tippe :q<Enter> zum Beenden "
+
+msgid "type :help<Enter> or <F1> for on-line help"
+msgstr "Tippe :help<Enter> oder <F1> für Online Hilfe "
+
+msgid "type :help version8<Enter> for version info"
+msgstr "Tippe :help version8<Enter> für Versions-Informationen"
+
+msgid "Running in Vi compatible mode"
+msgstr "Vi kompatible Einstellung"
+
+msgid "type :set nocp<Enter> for Vim defaults"
+msgstr "Tippe :set nocp<Enter> für Vim-Voreinstellungen "
+
+msgid "type :help cp-default<Enter> for info on this"
+msgstr "Tippe :help cp-default<Enter> für Informationen darüber "
+
+msgid "menu Help->Orphans for information "
+msgstr "Menü Hilfe->Waisen für Informationen darüber "
+
+msgid "Running modeless, typed text is inserted"
+msgstr "Mode-freier Betrieb, getippter Text wird eingefügt"
+
+msgid "menu Edit->Global Settings->Toggle Insert Mode "
+msgstr ""
+"Menü Editieren->Globale Einstellung->Einfüge-Modus ein- und ausschalten "
+
+msgid " for two modes "
+msgstr " für zwei Modi "
+
+msgid "menu Edit->Global Settings->Toggle Vi Compatible"
+msgstr ""
+"Menü Editieren->Globale Einstellung->Vi-Kompatibilität ein- und ausschalten"
+
+msgid " for Vim defaults "
+msgstr " für Vim Voreinstellungen "
+
+msgid "Sponsor Vim development!"
+msgstr "Unterstützen Sie die Entwicklung von Vim"
+
+msgid "Become a registered Vim user!"
+msgstr "Werd ein registrierter Vim-Nutzer!"
+
+msgid "type :help sponsor<Enter> for information "
+msgstr "Tippe :help sponsor<Enter> für mehr Informationen "
+
+msgid "type :help register<Enter> for information "
+msgstr "Tippe :help register<Enter> für mehr Informationen "
+
+msgid "menu Help->Sponsor/Register for information "
+msgstr "Menü Hilfe->Sponsor/Register für mehr Informationen "
+
+msgid "Already only one window"
+msgstr "Bereits nur ein Fenster"
+
+#, c-format
+msgid "E92: Buffer %ld not found"
+msgstr "E92: Puffer %ld nicht gefunden."
+
+msgid "E441: There is no preview window"
+msgstr "E441: Es gibt kein Vorschaufenster"
+
+# should read: topleft / botright
+msgid "E442: Can't split topleft and botright at the same time"
+msgstr "E442: topleft und botright können nicht gleichzeitig verwendet werden"
+
+msgid "E443: Cannot rotate when another window is split"
+msgstr "E443: Rotieren nicht möglich wenn ein anderes Fenster geteilt ist"
+
+msgid "E444: Cannot close last window"
+msgstr "E444: Letztes Fenster kann nicht geschlossen werden"
+
+msgid "E813: Cannot close autocmd window"
+msgstr "E813: Autokommando-Fenster kann nicht geschlossen werden"
+
+msgid "E814: Cannot close window, only autocmd window would remain"
+msgstr ""
+"E814: Kann Fenster nicht schließen, da nur Autokommando-Fenster übrig "
+"bleiben würde"
+
+msgid "E445: Other window contains changes"
+msgstr "E445: Anderes Fenster enthält Änderungen"
+
+# Cursor: Schreibmarke Positionsmarke
+msgid "E446: No file name under cursor"
+msgstr "E446: Kein Dateiname unter dem Cursor"
+
+#, c-format
+msgid "E447: Can't find file \"%s\" in path"
+msgstr "E447: Kann Datei \"%s\" nicht im Pfad finden"
+
+#, c-format
+msgid "E799: Invalid ID: %d (must be greater than or equal to 1)"
+msgstr "E799: Ungültige ID: %d (muss größer gleich 1 sein)"
+
+#, c-format
+msgid "E801: ID already taken: %d"
+msgstr "E801: ID bereits benutzt: %d"
+
+msgid "List or number required"
+msgstr "Liste oder Nummer erforderlich"
+
+#, c-format
+msgid "E802: Invalid ID: %d (must be greater than or equal to 1)"
+msgstr "E802: Ungültige ID: %d (muss größer gleich 1 sein)"
+
+#, c-format
+msgid "E803: ID not found: %d"
+msgstr "E803: ID nicht gefunden: %d"
+
+#, c-format
+msgid "E370: Could not load library %s"
+msgstr "E370: Konnte Bibliothek %s nicht laden"
+
+msgid "Sorry, this command is disabled: the Perl library could not be loaded."
+msgstr ""
+"Dieser Befehl ist nicht verfügbar, da die Perl-Bibliothek nicht geladen "
+"werden konnte"
+
+msgid "E299: Perl evaluation forbidden in sandbox without the Safe module"
+msgstr "E299: Perl-Evaluierung in der Sandbox ohne dem 'Safe' Modul"
+
+msgid "Edit with &multiple Vims"
+msgstr "Editiere mit &mehreren Vims"
+
+msgid "Edit with single &Vim"
+msgstr "Editiere mit einem &Vim"
+
+msgid "Diff with Vim"
+msgstr "Differenz mit Vim"
+
+msgid "Edit with &Vim"
+msgstr "Editiere mit &Vim"
+
+msgid "Edit with existing Vim"
+msgstr "Editiere mit vorhandenem Vim"
+
+msgid "Edit with existing Vim - "
+msgstr "Editiere mit vorhandenem Vim - "
+
+msgid "Edits the selected file(s) with Vim"
+msgstr "Editiert die ausgewählte(n) Datei(en) mit Vim"
+
+msgid "Error creating process: Check if gvim is in your path!"
+msgstr ""
+"Fehler beim Erzeugen des Prozesses: Überprüfen Sie, ob gvim in Ihrem Pfad "
+"ist!"
+
+msgid "gvimext.dll error"
+msgstr "gvimext.dll Fehler"
+
+msgid "Path length too long!"
+msgstr "Die Länge des Pfads ist zu groß!"
+
+msgid "--No lines in buffer--"
+msgstr "--Keine Zeilen im Puffer--"
+
+msgid "E470: Command aborted"
+msgstr "E470: Befehl abgebrochen"
+
+msgid "E471: Argument required"
+msgstr "E471: Argument benötigt"
+
+msgid "E10: \\ should be followed by /, ? or &"
+msgstr "E10: \\ sollte von /, ? oder & gefolgt werden"
+
+msgid "E11: Invalid in command-line window; <CR> executes, CTRL-C quits"
+msgstr "E11: Ungültig im Kommandozeilenfenster; <CR> führt aus, CTRL-C beendet"
+
+msgid "E12: Command not allowed from exrc/vimrc in current dir or tag search"
+msgstr ""
+"E12: Befehl nicht zulässig vom exrc/vimrc in der momentanen Verzeichnis- "
+"oder Tag-Suche"
+
+msgid "E171: Missing :endif"
+msgstr "E171: Fehlendes :endif"
+
+msgid "E600: Missing :endtry"
+msgstr "E600: Fehlendes :endtry"
+
+msgid "E170: Missing :endwhile"
+msgstr "E170: fehlendes :endwhile"
+
+msgid "E170: Missing :endfor"
+msgstr "E170: Fehlendes :endfor"
+
+msgid "E588: :endwhile without :while"
+msgstr "E588: :endwhile ohne :while"
+
+msgid "E588: :endfor without :for"
+msgstr "E588: :endfor ohne :for"
+
+msgid "E13: File exists (add ! to override)"
+msgstr "E13: Datei existiert bereits (erzwinge mit !)"
+
+msgid "E472: Command failed"
+msgstr "E472: Befehl fehlgeschlagen"
+
+#, c-format
+msgid "E234: Unknown fontset: %s"
+msgstr "E234: Unbekannter Fontset: %s"
+
+#, c-format
+msgid "E235: Unknown font: %s"
+msgstr "E235: Unbekannte Schriftart: %s"
+
+#, c-format
+msgid "E236: Font \"%s\" is not fixed-width"
+msgstr "E236: Schriftart \"%s\" hat keine feste Breite"
+
+msgid "E473: Internal error"
+msgstr "E473: Interner Fehler"
+
+#, c-format
+msgid "E685: Internal error: %s"
+msgstr "E685: Interner Fehler: %s"
+
+msgid "Interrupted"
+msgstr "Unterbrochen"
+
+msgid "E14: Invalid address"
+msgstr "E14: Ungültige Adresse"
+
+msgid "E474: Invalid argument"
+msgstr "E474: Ungültiges Argument"
+
+#, c-format
+msgid "E475: Invalid argument: %s"
+msgstr "E475: Ungültiges Argument: %s"
+
+#, c-format
+msgid "E475: Invalid value for argument %s"
+msgstr "E475: Ungültiger Wert für Argument: %s"
+
+#, c-format
+msgid "E475: Invalid value for argument %s: %s"
+msgstr "E475: Ungültiger Wert für Argument %s: %s"
+
+#, c-format
+msgid "E15: Invalid expression: %s"
+msgstr "E15: ungültiger Ausdruck: %s"
+
+msgid "E16: Invalid range"
+msgstr "E16: Ungültiger Bereich"
+
+msgid "E476: Invalid command"
+msgstr "E476: Ungültiger Befehl"
+
+#, c-format
+msgid "E17: \"%s\" is a directory"
+msgstr "E17: \"%s\" ist ein Verzeichnis"
+
+#, c-format
+msgid "E364: Library call failed for \"%s()\""
+msgstr "E364: Bibliotheksaufruf für \"%s()\" schlug fehl"
+
+msgid "E667: Fsync failed"
+msgstr "E667: Fsync fehlgeschlagen"
+
+#, c-format
+msgid "E448: Could not load library function %s"
+msgstr "E448: Bibliotheksfunktion %s konnte nicht geladen werden"
+
+msgid "E19: Mark has invalid line number"
+msgstr "E19: Markierung hat ungültige Zeilennummer"
+
+msgid "E20: Mark not set"
+msgstr "E20: Markierung nicht gesetzt"
+
+msgid "E21: Cannot make changes, 'modifiable' is off"
+msgstr "E21: Kann keine Änderungen machen, 'modifiable' ist aus"
+
+msgid "E22: Scripts nested too deep"
+msgstr "E22: Skript ist zu tief verschachtelt"
+
+msgid "E23: No alternate file"
+msgstr "E23: Keine alternative Datei"
+
+msgid "E24: No such abbreviation"
+msgstr "E24: Diese Kurzform nicht gefunden"
+
+msgid "E477: No ! allowed"
+msgstr "E477: Kein ! erlaubt"
+
+msgid "E25: GUI cannot be used: Not enabled at compile time"
+msgstr ""
+"E25: GUI kann nicht benutzt werden: wurde zum Zeitpunkt des Übersetzens "
+"nicht eingeschaltet."
+
+msgid "E26: Hebrew cannot be used: Not enabled at compile time\n"
+msgstr ""
+"E26: Hebräisch kann nicht benutzt werden: wurde zum Zeitpunkt des "
+"Übersetzens nicht eingeschaltet.\n"
+
+msgid "E27: Farsi cannot be used: Not enabled at compile time\n"
+msgstr ""
+"E27: Farsi kann nicht benutzt werden: wurde zum Zeitpunkt des Übersetzens "
+"nicht eingeschaltet.\n"
+
+msgid "E800: Arabic cannot be used: Not enabled at compile time\n"
+msgstr ""
+"E800: Arabisch kann nicht benutzt werden: wurde zum Zeitpunkt des "
+"Übersetzens nicht eingeschaltet.\n"
+
+#, c-format
+msgid "E28: No such highlight group name: %s"
+msgstr "E28: Hervorhebungsgruppe existiert nicht: %s"
+
+msgid "E29: No inserted text yet"
+msgstr "E29: Noch kein eingefügter Text"
+
+msgid "E30: No previous command line"
+msgstr "E30: Keine vorherige Befehlszeile"
+
+msgid "E31: No such mapping"
+msgstr "E31: Kein Mapping gefunden"
+
+msgid "E479: No match"
+msgstr "E479: Kein Treffer"
+
+#, c-format
+msgid "E480: No match: %s"
+msgstr "E480: Kein Treffer: %s"
+
+msgid "E32: No file name"
+msgstr "E32: Kein Dateiname"
+
+msgid "E33: No previous substitute regular expression"
+msgstr "E33: Kein vorheriger regulärer Ersetzungsausdruck"
+
+msgid "E34: No previous command"
+msgstr "E34: Kein vorheriger Befehl"
+
+msgid "E35: No previous regular expression"
+msgstr "E35: Keine vorheriger regulärer Ausdruck"
+
+msgid "E481: No range allowed"
+msgstr "E481: Kein Bereich erlaubt"
+
+msgid "E36: Not enough room"
+msgstr "E36: Zu wenig Platz"
+
+#, c-format
+msgid "E247: no registered server named \"%s\""
+msgstr "E247: Kein registrierter Servername \"%s\""
+
+#, c-format
+msgid "E482: Can't create file %s"
+msgstr "E482: Kann Datei %s nicht erzeugen"
+
+msgid "E483: Can't get temp file name"
+msgstr "E483: Kann den Namen der temporären Datei nicht ermitteln"
+
+#, c-format
+msgid "E484: Can't open file %s"
+msgstr "E484: Kann die Datei %s nicht öffnen"
+
+#, c-format
+msgid "E485: Can't read file %s"
+msgstr "E485: Kann Datei %s nicht lesen"
+
+msgid "E38: Null argument"
+msgstr "E38: Null-Argument"
+
+msgid "E39: Number expected"
+msgstr "E39: Nummer erwartet"
+
+#, c-format
+msgid "E40: Can't open errorfile %s"
+msgstr "E40: Fehlerdatei %s kann nicht geöffnet werden"
+
+msgid "E233: cannot open display"
+msgstr "E233: Display kann nicht geöffnet werden"
+
+msgid "E41: Out of memory!"
+msgstr "E41: Speicher erschöpft!"
+
+msgid "Pattern not found"
+msgstr "Muster nicht gefunden"
+
+#, c-format
+msgid "E486: Pattern not found: %s"
+msgstr "E486: Muster nicht gefunden: %s"
+
+msgid "E487: Argument must be positive"
+msgstr "E487: Argument muss positiv sein"
+
+msgid "E459: Cannot go back to previous directory"
+msgstr "E459: Kann nicht ins vorhergehende Verzeichnis wechseln"
+
+msgid "E42: No Errors"
+msgstr "E42: Keine Fehler"
+
+msgid "E776: No location list"
+msgstr "E776: Keine Positionsliste"
+
+msgid "E43: Damaged match string"
+msgstr "E43: Beschädigter Suchausdruck"
+
+msgid "E44: Corrupted regexp program"
+msgstr "E44: schadhaftes regexp Programm"
+
+msgid "E45: 'readonly' option is set (add ! to override)"
+msgstr "E45: Die Option 'readonly' ist gesetzt (erzwinge mit !)"
+
+#, c-format
+msgid "E46: Cannot change read-only variable \"%s\""
+msgstr "E46: Variable \"%s\" kann nur gelesen werden"
+
+#, c-format
+msgid "E794: Cannot set variable in the sandbox: \"%s\""
+msgstr "E794: Variable kann nicht in der Sandbox gesetzt werden: \"%s\""
+
+msgid "E713: Cannot use empty key for Dictionary"
+msgstr "E713: Der Schlüssel für das Dictionary darf nicht leer sein"
+
+msgid "E715: Dictionary required"
+msgstr "E715: Dictionary benötigt"
+
+#, c-format
+msgid "E684: list index out of range: %ld"
+msgstr "E684: Index der Liste außerhalb des zulässigen Bereichs: %ld"
+
+#, c-format
+msgid "E979: Blob index out of range: %ld"
+msgstr "E979: Blobindex außerhalb des Bereichs: %ld"
+
+msgid "E978: Invalid operation for Blob"
+msgstr "E978: Unzulässige Operation für Blob"
+
+#, c-format
+msgid "E118: Too many arguments for function: %s"
+msgstr "E118: Zu viele Argumente für Funktion: %s"
+
+#, c-format
+msgid "E716: Key not present in Dictionary: %s"
+msgstr "E716: Schlüssel %s nicht im Dictionary vorhanden."
+
+msgid "E714: List required"
+msgstr "E714: Liste benötigt"
+
+msgid "E897: List or Blob required"
+msgstr "E897: Liste oder Blob benötigt"
+
+#, c-format
+msgid "E712: Argument of %s must be a List or Dictionary"
+msgstr "E712: Argument von %s muss eine Liste oder ein Dictionary sein."
+
+#, c-format
+msgid "E896: Argument of %s must be a List, Dictionary or Blob"
+msgstr "E896: Argument von %s muss eine Liste, Dictionary oder ein Blob sein."
+
+msgid "E47: Error while reading errorfile"
+msgstr "E47: Fehler während des Lesens der Fehlerdatei"
+
+msgid "E48: Not allowed in sandbox"
+msgstr "E48: In einer Sandbox nicht erlaubt"
+
+msgid "E523: Not allowed here"
+msgstr "E523: Hier nicht erlaubt"
+
+msgid "E359: Screen mode setting not supported"
+msgstr "E359: Bildschirm-Modus wird nicht unterstützt"
+
+msgid "E49: Invalid scroll size"
+msgstr "E49: Ungültige Scroll-Größe"
+
+msgid "E91: 'shell' option is empty"
+msgstr "E91: Die Option 'shell' ist leer"
+
+msgid "E255: Couldn't read in sign data!"
+msgstr "E255: Fehler -- Sign-Daten konnten nicht gelesen werden"
+
+msgid "E72: Close error on swap file"
+msgstr "E72: Fehler beim Schließen der Auslagerungsdatei"
+
+msgid "E73: tag stack empty"
+msgstr "E73: Tag Stapel leer."
+
+msgid "E74: Command too complex"
+msgstr "E74: Befehl zu komplex"
+
+msgid "E75: Name too long"
+msgstr "E75: Name zu lang"
+
+msgid "E76: Too many ["
+msgstr "E76: Zu viele ["
+
+msgid "E77: Too many file names"
+msgstr "E77: Zu viele Dateinamen"
+
+msgid "E488: Trailing characters"
+msgstr "E488: Überschüssige Zeichen"
+
+msgid "E78: Unknown mark"
+msgstr "E78: Unbekannte Markierung"
+
+msgid "E79: Cannot expand wildcards"
+msgstr "E79: Kann die Platzhalter nicht erweitern"
+
+msgid "E591: 'winheight' cannot be smaller than 'winminheight'"
+msgstr "E591: 'winheight' darf nicht kleiner sein als 'winminheight'"
+
+msgid "E592: 'winwidth' cannot be smaller than 'winminwidth'"
+msgstr "E592: 'winwidth' darf nicht kleiner sein als 'winminwidth'"
+
+msgid "E80: Error while writing"
+msgstr "E80: Fehler während des Schreibens"
+
+msgid "E939: Positive count required"
+msgstr "E939: Positive Zahl benötigt"
+
+msgid "E81: Using <SID> not in a script context"
+msgstr "E81: <SID> wurde nicht in einer Skript-Umgebung benutzt"
+
+msgid "E449: Invalid expression received"
+msgstr "E449: Ungültiger Ausdruck"
+
+msgid "E463: Region is guarded, cannot modify"
+msgstr "E463: Region ist geschützt; keine Änderung möglich"
+
+msgid "E744: NetBeans does not allow changes in read-only files"
+msgstr "E744: NetBeans erlaubt keine Änderungen in schreibgeschützten Dateien"
+
+msgid "E363: pattern uses more memory than 'maxmempattern'"
+msgstr "E363: Muster benötigt mehr Speicher als 'maxmempattern'"
+
+msgid "E749: empty buffer"
+msgstr "E749: Leerer Puffer"
+
+#, c-format
+msgid "E86: Buffer %ld does not exist"
+msgstr "E86: Puffer %ld existiert nicht."
+
+msgid "E682: Invalid search pattern or delimiter"
+msgstr "E682: Ungültiges Suchmuster oder Trennzeichen"
+
+msgid "E139: File is loaded in another buffer"
+msgstr "E139: Datei ist in einem anderen Puffer geladen"
+
+#, c-format
+msgid "E764: Option '%s' is not set"
+msgstr "E764: Option '%s' ist nicht gesetzt"
+
+msgid "E850: Invalid register name"
+msgstr "E850: Ungültiger Register Name"
+
+#, c-format
+msgid "E919: Directory not found in '%s': \"%s\""
+msgstr "E919: Verzeichnis nicht gefunden in '%s': \"%s\""
+
+msgid "E952: Autocommand caused recursive behavior"
+msgstr "E952: Autokommando verursachten Rekursion"
+
+msgid "E328: Menu only exists in another mode"
+msgstr "E328: Menü existiert nur in anderen Modi"
+
+msgid "search hit TOP, continuing at BOTTOM"
+msgstr "Suche erreichte den ANFANG und wurde am ENDE fortgesetzt"
+
+msgid "search hit BOTTOM, continuing at TOP"
+msgstr "Suche erreichte das ENDE und wurde am ANFANG fortgesetzt"
+
+#, c-format
+msgid "Need encryption key for \"%s\""
+msgstr "Geben Sie bitte den Schlüssel für \"%s\" ein: "
+
+msgid "empty keys are not allowed"
+msgstr "Leerer Schlüssel nicht erlaubt"
+
+msgid "dictionary is locked"
+msgstr "Dictionary ist gesperrt"
+
+msgid "list is locked"
+msgstr "Liste ist gesperrt"
+
+#, c-format
+msgid "failed to add key '%s' to dictionary"
+msgstr "Konnte Schlüssel '%s' zu Dictionary nicht hinzufügen."
+
+#, c-format
+msgid "index must be int or slice, not %s"
+msgstr "Index muss eine Int oder Slice sein, nicht %s"
+
+#, c-format
+msgid "expected str() or unicode() instance, but got %s"
+msgstr "erwartete str() oder unicode() Instanz, erhielt jedoch %s"
+
+#, c-format
+msgid "expected bytes() or str() instance, but got %s"
+msgstr "Erwartete bytes() oder str() Instanz, erhielt jedoch %s"
+
+#, c-format
+msgid ""
+"expected int(), long() or something supporting coercing to long(), but got %s"
+msgstr ""
+"erwartete int(), long() or etwas was sich zu long() wandeln lässt, erhielt "
+"jedoch %s"
+
+#, c-format
+msgid "expected int() or something supporting coercing to int(), but got %s"
+msgstr ""
+"erwartete int() oder etwas was sich zu int() wandeln lässt, erhielt jedoch %s"
+
+msgid "value is too large to fit into C int type"
+msgstr "Wert zu groß für einen C Integerwert"
+
+msgid "value is too small to fit into C int type"
+msgstr "Wert zu klein für einen C Integerwert"
+
+msgid "number must be greater than zero"
+msgstr "Nummer muss größer als 0 sein"
+
+msgid "number must be greater or equal to zero"
+msgstr "Nummer muss größer gleich 0 sein"
+
+msgid "can't delete OutputObject attributes"
+msgstr "OutputObject-Attribute können nicht gelöscht werden"
+
+#, c-format
+msgid "invalid attribute: %s"
+msgstr "unzulässiges Attribut: %s"
+
+msgid "E264: Python: Error initialising I/O objects"
+msgstr "E264: Python: Fehler bei der Initialisierung von I/O Objekten"
+
+msgid "failed to change directory"
+msgstr "Verzeichniswechsel fehlgeschlagen"
+
+#, c-format
+msgid "expected 3-tuple as imp.find_module() result, but got %s"
+msgstr ""
+"erwartete 3 Tuple als Ergebnis von imp.find_module(), erhielt jedoch %s"
+
+#, c-format
+msgid "expected 3-tuple as imp.find_module() result, but got tuple of size %d"
+msgstr ""
+"erwartete 3 Tuple als Ergebnis von find_module(), but erhielt Tuple der "
+"Größe %d"
+
+msgid "internal error: imp.find_module returned tuple with NULL"
+msgstr "interner Fehler: imp.find_module gab Tuple mit NULL zurück"
+
+msgid "cannot delete vim.Dictionary attributes"
+msgstr "kann vim.Dictionary Attribute nicht löschen"
+
+msgid "cannot modify fixed dictionary"
+msgstr "Kann festes Dictionary nicht ändern"
+
+#, c-format
+msgid "cannot set attribute %s"
+msgstr "Kann nicht Attribut %s setzen"
+
+msgid "hashtab changed during iteration"
+msgstr "Hashtab veränderte sich während der Initialisierung"
+
+#, c-format
+msgid "expected sequence element of size 2, but got sequence of size %d"
+msgstr ""
+"erwartete Sequenz Element der Größe 2, erhielt jedoch Sequenz der Größe %d"
+
+msgid "list constructor does not accept keyword arguments"
+msgstr "Listen Konstruktor akzeptiert keine Keyword Argumente"
+
+msgid "list index out of range"
+msgstr "Listen Index außerhalb des gültigen Bereichs"
+
+#, c-format
+msgid "internal error: failed to get vim list item %d"
+msgstr "interner Fehler: Zugriff auf Vim Listobjekt %d fehlgeschlagen"
+
+msgid "slice step cannot be zero"
+msgstr "Slice Schritt kann nicht Null sein"
+
+#, c-format
+msgid "attempt to assign sequence of size greater than %d to extended slice"
+msgstr ""
+"Versuch der Zuweisung von Sequenzgröße größer als %d zu erweiterten Slice"
+
+#, c-format
+msgid "internal error: no vim list item %d"
+msgstr "interner Fehler: Kein Vim Listobjekt %d"
+
+msgid "internal error: not enough list items"
+msgstr "interner Fehler: nicht genügend Listobjekte"
+
+msgid "internal error: failed to add item to list"
+msgstr "interner Fehler: konnte Objekt nicht Liste hinzufügen"
+
+#, c-format
+msgid "attempt to assign sequence of size %d to extended slice of size %d"
+msgstr ""
+"Versuch der Zuweisung von Sequenzgröße %d zu erweiterten Slice der Größe %d"
+
+msgid "failed to add item to list"
+msgstr "Hinzufügen von Objekt zu Liste fehlgeschlagen"
+
+msgid "cannot delete vim.List attributes"
+msgstr "kann vim.List Attribute nicht löschen"
+
+msgid "cannot modify fixed list"
+msgstr "kann feste Liste nicht modifizieren"
+
+#, c-format
+msgid "unnamed function %s does not exist"
+msgstr "Unbenannte Funktion %s existiert nicht"
+
+#, c-format
+msgid "function %s does not exist"
+msgstr "Funktion %s existiert nicht"
+
+#, c-format
+msgid "failed to run function %s"
+msgstr "Fehler beim Ausführen der Funktion %s"
+
+msgid "unable to get option value"
+msgstr "konnte Optionswert nicht erhalten"
+
+msgid "internal error: unknown option type"
+msgstr "interner Fehler: unbekannter Optionstyp"
+
+msgid "problem while switching windows"
+msgstr "Problem beim Wechseln der Fenster"
+
+#, c-format
+msgid "unable to unset global option %s"
+msgstr "Konnte globale Option %s nicht aufheben"
+
+#, c-format
+msgid "unable to unset option %s which does not have global value"
+msgstr "konnte Option %s nicht aufheben, da sie keinen globalen Wert hat"
+
+msgid "attempt to refer to deleted tab page"
+msgstr "Versuch, Bezug auf einen gelöschten Reiter zu nehmen"
+
+msgid "no such tab page"
+msgstr "kein solcher Reiter vorhanden"
+
+msgid "attempt to refer to deleted window"
+msgstr "Versuch, Bezug auf eine gelöschtes Fenster zu nehmen"
+
+msgid "readonly attribute: buffer"
+msgstr "nur-Lesen Attribut: Puffer"
+
+msgid "cursor position outside buffer"
+msgstr "Cursor Position außerhalb des Puffers"
+
+msgid "no such window"
+msgstr "ungültiges Fenster"
+
+msgid "attempt to refer to deleted buffer"
+msgstr "Versuch, Bezug auf einen gelöschten Puffer zu nehmen"
+
+msgid "failed to rename buffer"
+msgstr "Umbenennen des Puffers fehlgeschlagen"
+
+msgid "mark name must be a single character"
+msgstr "Markierung muss ein einzelner Buchstabe sein"
+
+#, c-format
+msgid "expected vim.Buffer object, but got %s"
+msgstr "erwartete vim.Puffer Objekt, erhielt jedoch %s"
+
+#, c-format
+msgid "failed to switch to buffer %d"
+msgstr "Wechsel zu Puffer %d fehlgeschlagen"
+
+#, c-format
+msgid "expected vim.Window object, but got %s"
+msgstr "erwartete vim.Window Objekt, erhielt jedoch %s"
+
+msgid "failed to find window in the current tab page"
+msgstr "konnte Fenster im aktuellen Reiter nicht finden"
+
+msgid "did not switch to the specified window"
+msgstr "konnte nicht zu spezifizierten Fenster wechseln"
+
+#, c-format
+msgid "expected vim.TabPage object, but got %s"
+msgstr "erwartete vim.TabPage Objekt, erhielt jedoch %s"
+
+msgid "did not switch to the specified tab page"
+msgstr "konnte nicht zu spezifiziertem Reiter wechseln"
+
+msgid "failed to run the code"
+msgstr "Ausführen des Codes fehlgeschlagen."
+
+msgid "E858: Eval did not return a valid python object"
+msgstr "E858: Eval hat kein gültiges Pythonobjekt zurückgegeben"
+
+msgid "E859: Failed to convert returned python object to vim value"
+msgstr ""
+"E859: Konvertierung von zurückgegebenen Pythonobjekt zu Vim Wert "
+"fehlgeschlagen"
+
+#, c-format
+msgid "unable to convert %s to vim dictionary"
+msgstr "konnte nicht %s zu Vim Dictionary konvertieren"
+
+#, c-format
+msgid "unable to convert %s to vim list"
+msgstr "konnte %s nicht zu Vim Liste konvertieren"
+
+#, c-format
+msgid "unable to convert %s to vim structure"
+msgstr "konnte %s nicht zu Vim Struktur konvertieren"
+
+msgid "internal error: NULL reference passed"
+msgstr "interner Fehler: NULL Referenz übermittelt"
+
+msgid "internal error: invalid value type"
+msgstr "interner Fehler: ungültiger Werttyp"
+
+msgid ""
+"Failed to set path hook: sys.path_hooks is not a list\n"
+"You should now do the following:\n"
+"- append vim.path_hook to sys.path_hooks\n"
+"- append vim.VIM_SPECIAL_PATH to sys.path\n"
+msgstr ""
+"Fehler beim setzen des Path hooks: sys.path_hooks ist keine Liste\n"
+"Sie sollten jetzt eine der folgenden Alternativen tun:\n"
+"- vim.path_hook zu sys.path_hooks hinzufügen\n"
+"- vim.VIM_SPECIAL_PATH zu sys.path hinzufügen\n"
+
+msgid ""
+"Failed to set path: sys.path is not a list\n"
+"You should now append vim.VIM_SPECIAL_PATH to sys.path"
+msgstr ""
+"Fehler beim setzen des Pfades: sys.path ist keine Liste\n"
+"Fügen Sie vim.VIM_SPECIAL_PATH zu sys.path hinzu"
+
+msgid ""
+"Vim macro files (*.vim)\t*.vim\n"
+"All Files (*.*)\t*.*\n"
+msgstr ""
+"Vim Dateien (*.vim)\t*.vim\n"
+"Alle Dateien (*.*)\t*.*\n"
+
+msgid "All Files (*.*)\t*.*\n"
+msgstr "Alle Dateien (*.*)\t*.*\n"
+
+msgid ""
+"All Files (*.*)\t*.*\n"
+"C source (*.c, *.h)\t*.c;*.h\n"
+"C++ source (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"VB code (*.bas, *.frm)\t*.bas;*.frm\n"
+"Vim files (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
+msgstr ""
+"Alle Dateien (*.*)\t*.*\n"
+"C Quellcode (*.c, *.h)\t*.c;*.h\n"
+"C++ Quellcode (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"VB Quellcode (*.bas, *.frm)\t*.bas;*.frm\n"
+"Vim Dateien (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
+
+msgid ""
+"Vim macro files (*.vim)\t*.vim\n"
+"All Files (*)\t*\n"
+msgstr ""
+"Vim Dateien (*.vim)\t*.vim\n"
+"Alle Dateien (*)\t*\n"
+
+msgid "All Files (*)\t*\n"
+msgstr "Alle Dateien (*)\t*\n"
+
+msgid ""
+"All Files (*)\t*\n"
+"C source (*.c, *.h)\t*.c;*.h\n"
+"C++ source (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"Vim files (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
+msgstr ""
+"Alle Dateien (*)\t*\n"
+"C Quellcode (*.c, *.h)\t*.c;*.h\n"
+"C++ Quellcode (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"Vim Dateien (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
diff --git a/src/po/en_GB.po b/src/po/en_GB.po
new file mode 100644
index 0000000..fcee297
--- /dev/null
+++ b/src/po/en_GB.po
@@ -0,0 +1,767 @@
+# UK English Translation for Vim vim:set foldmethod=marker:
+#
+# Do ":help uganda" in Vim to read copying and usage conditions.
+# Do ":help credits" in Vim to see a list of people who contributed.
+#
+# FIRST AUTHOR Mike Williams <mrw@eandem.co.uk>, 2003.
+#
+# Style Guide:
+# o English spelling!
+# o Colour, not color
+# o -ise, not -ize.
+# o No contractions.
+# o Cannot, not can not.
+# o Backward (no s) when used as an adjective.
+# o Consistent capitalisation for first word after Ennn:
+# o Consistent capitalisation of NetBeans
+# o TBC ...
+#
+# As with all guides, they should be followed unless there is a reason why they
+# should not be for a particular message.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Vim(UK English)\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2017-07-16 13:34+0100\n"
+"PO-Revision-Date: 2003-02-25 11:05+0000\n"
+"Last-Translator: Mike Williams <mrw@eandem.co.uk>\n"
+"Language-Team: Mike Williams <mrw@eandem.co.uk>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO_8859-1\n"
+"Content-Transfer-Encoding: 7bit\n"
+
+
+msgid "E903: received command with non-string argument"
+msgstr "E903: Received command with non-string argument"
+
+msgid "E904: last argument for expr/call must be a number"
+msgstr "E904: Last argument for expr/call must be a number"
+
+msgid "E904: third argument for call must be a list"
+msgstr "E904: Third argument for call must be a list"
+
+#, c-format
+msgid "E905: received unknown command: %s"
+msgstr "E905: Received unknown command: %s"
+
+
+msgid "E912: cannot use ch_evalexpr()/ch_sendexpr() with a raw or nl channel"
+msgstr "E912: Cannot use ch_evalexpr()/ch_sendexpr() with a raw or nl channel"
+
+msgid "E906: not an open channel"
+msgstr "E906: Not an open channel"
+
+
+#, c-format
+msgid "E918: buffer must be loaded: %s"
+msgstr "E918: Buffer must be loaded: %s"
+
+
+msgid "Keys don't match!"
+msgstr "Keys do not match!"
+
+
+msgid "E101: More than two buffers in diff mode, don't know which one to use"
+msgstr "E101: More than two buffers in diff mode, do not know which one to use"
+
+#, c-format
+msgid "E102: Can't find buffer \"%s\""
+msgstr "E102: Cannot find buffer \"%s\""
+
+
+msgid "E806: using Float as a String"
+msgstr "E806: Using Float as a String"
+
+
+#, c-format
+msgid "E738: Can't list variables for %s"
+msgstr "E738: Cannot list variables for %s"
+
+
+msgid "E743: variable nested too deep for (un)lock"
+msgstr "E743: Variable nested too deep for (un)lock"
+
+
+msgid "E724: variable nested too deep for displaying"
+msgstr "E724: Variable nested too deep for displaying"
+
+
+msgid "E729: using Funcref as a String"
+msgstr "E729: Using Funcref as a String"
+
+msgid "E730: using List as a String"
+msgstr "E730: Using List as a String"
+
+msgid "E731: using Dictionary as a String"
+msgstr "E731: Using Dictionary as a String"
+
+msgid "E908: using an invalid value as a String"
+msgstr "E908: Using an invalid value as a String"
+
+
+msgid "E698: variable nested too deep for making a copy"
+msgstr "E698: Variable nested too deep for making a copy"
+
+
+msgid "E785: complete() can only be used in Insert mode"
+msgstr "E785: Complete() can only be used in Insert mode"
+
+
+msgid "E922: expected a dict"
+msgstr "E922: Expected a dict"
+
+
+msgid "E916: not a valid job"
+msgstr "E916: Not a valid job"
+
+
+msgid "E941: already started a server"
+msgstr "E941: Already started a server"
+
+
+#, c-format
+msgid "E935: invalid submatch number: %d"
+msgstr "E935: Invalid submatch number: %d"
+
+
+#, c-format
+msgid "E138: Can't write viminfo file %s!"
+msgstr "E138: Cannot write viminfo file %s!"
+
+
+#, c-format
+msgid "E886: Can't rename viminfo file to %s!"
+msgstr "E886: Cannot rename viminfo file to %s!"
+
+
+msgid ""
+"# You may edit it if you're careful!\n"
+"\n"
+msgstr ""
+"# You may edit it if you are careful!\n"
+"\n"
+
+
+msgid "E144: non-numeric argument to :z"
+msgstr "E144: Non-numeric argument to :z"
+
+
+msgid "E146: Regular expressions can't be delimited by letters"
+msgstr "E146: Regular expressions cannot be delimited by letters"
+
+
+#, c-format
+msgid "E666: compiler not supported: %s"
+msgstr "E666: Compiler not supported: %s"
+
+
+msgid "E493: Backwards range given"
+msgstr "E493: Backward range given"
+
+msgid "Backwards range given, OK to swap"
+msgstr "Backward range given, OK to swap"
+
+
+msgid "E179: argument required for -complete"
+msgstr "E179: Argument required for -complete"
+
+msgid "E179: argument required for -addr"
+msgstr "E179: Argument required for -addr"
+
+
+#, c-format
+msgid "E185: Cannot find color scheme '%s'"
+msgstr "E185: Cannot find colour scheme '%s'"
+
+
+msgid "E495: no autocommand file name to substitute for \"<afile>\""
+msgstr "E495: No autocommand file name to substitute for \"<afile>\""
+
+msgid "E496: no autocommand buffer number to substitute for \"<abuf>\""
+msgstr "E496: No autocommand buffer number to substitute for \"<abuf>\""
+
+msgid "E497: no autocommand match name to substitute for \"<amatch>\""
+msgstr "E497: No autocommand match name to substitute for \"<amatch>\""
+
+msgid "E498: no :source file name to substitute for \"<sfile>\""
+msgstr "E498: No :source file name to substitute for \"<sfile>\""
+
+msgid "E842: no line number to use for \"<slnum>\""
+msgstr "E842: No line number to use for \"<slnum>\""
+
+#, no-c-format
+
+
+msgid "E583: multiple :else"
+msgstr "E583: Multiple :else"
+
+
+#. Give up for a multiple ":finally" and ignore it.
+msgid "E607: multiple :finally"
+msgstr "E607: Multiple :finally"
+
+
+msgid "Can't find temp file for conversion"
+msgstr "Cannot find temp file for conversion"
+
+
+msgid "can't read output of 'charconvert'"
+msgstr "cannot read output of 'charconvert'"
+
+
+msgid "E506: Can't write to backup file (add ! to override)"
+msgstr "E506: Cannot write to backup file (add ! to override)"
+
+
+msgid "E508: Can't read file for backup (add ! to override)"
+msgstr "E508: Cannot read file for backup (add ! to override)"
+
+
+msgid "E510: Can't make backup file (add ! to override)"
+msgstr "E510: Cannot make backup file (add ! to override)"
+
+
+msgid "E214: Can't find temp file for writing"
+msgstr "E214: Cannot find temp file for writing"
+
+
+msgid "E166: Can't open linked file for writing"
+msgstr "E166: Cannot open linked file for writing"
+
+msgid "E212: Can't open file for writing"
+msgstr "E212: Cannot open file for writing"
+
+
+msgid "E513: write error, conversion failed (make 'fenc' empty to override)"
+msgstr "E513: Write error, conversion failed (make 'fenc' empty to override)"
+
+#, c-format
+msgid ""
+"E513: write error, conversion failed in line %ld (make 'fenc' empty to "
+"override)"
+msgstr "E513: Write error, conversion failed in line %ld (make 'fenc' empty to override)"
+
+msgid "E514: write error (file system full?)"
+msgstr "E514: Write error (file system full?)"
+
+
+msgid "E205: Patchmode: can't save original file"
+msgstr "E205: Patchmode: cannot save original file"
+
+msgid "E206: patchmode: can't touch empty original file"
+msgstr "E206: Patchmode: cannot touch empty original file"
+
+msgid "E207: Can't delete backup file"
+msgstr "E207: Cannot delete backup file"
+
+
+msgid "don't quit the editor until the file is successfully written!"
+msgstr "do not quit the editor until the file is successfully written!"
+
+
+msgid "E217: Can't execute autocommands for ALL events"
+msgstr "E217: Cannot execute autocommands for ALL events"
+
+
+msgid "E223: recursive mapping"
+msgstr "E223: Recursive mapping"
+
+#, c-format
+msgid "E224: global abbreviation already exists for %s"
+msgstr "E224: Global abbreviation already exists for %s"
+
+#, c-format
+msgid "E225: global mapping already exists for %s"
+msgstr "E225: Global mapping already exists for %s"
+
+#, c-format
+msgid "E226: abbreviation already exists for %s"
+msgstr "E226: Abbreviation already exists for %s"
+
+#, c-format
+msgid "E227: mapping already exists for %s"
+msgstr "E227: Mapping already exists for %s"
+
+
+#, c-format
+msgid "E254: Cannot allocate color %s"
+msgstr "E254: Cannot allocate colour %s"
+
+
+#, c-format
+msgid "E616: vim_SelFile: can't get font %s"
+msgstr "E616: vim_SelFile: cannot get font %s"
+
+msgid "E614: vim_SelFile: can't return to current directory"
+msgstr "E614: vim_SelFile: cannot return to current directory"
+
+
+msgid "E615: vim_SelFile: can't get current directory"
+msgstr "E615: vim_SelFile: cannot get current directory"
+
+
+msgid "Vim E458: Cannot allocate colormap entry, some colors may be incorrect"
+msgstr ""
+"Vim E458: Cannot allocate colourmap entry, some colours may be incorrect"
+
+
+msgid "E552: digit expected"
+msgstr "E552: Digit expected"
+
+
+#, c-format
+msgid "E624: Can't open file \"%s\""
+msgstr "E624: Cannot open file \"%s\""
+
+#, c-format
+msgid "E457: Can't read PostScript resource file \"%s\""
+msgstr "E457: Cannot read PostScript resource file \"%s\""
+
+#, c-format
+msgid "E618: file \"%s\" is not a PostScript resource file"
+msgstr "E618: File \"%s\" is not a PostScript resource file"
+
+#, c-format
+msgid "E619: file \"%s\" is not a supported PostScript resource file"
+msgstr "E619: File \"%s\" is not a supported PostScript resource file"
+
+
+msgid "E324: Can't open PostScript output file"
+msgstr "E324: Cannot open PostScript output file"
+
+#, c-format
+msgid "E456: Can't open file \"%s\""
+msgstr "E456: Cannot open file \"%s\""
+
+msgid "E456: Can't find PostScript resource file \"prolog.ps\""
+msgstr "E456: Cannot find PostScript resource file \"prolog.ps\""
+
+msgid "E456: Can't find PostScript resource file \"cidfont.ps\""
+msgstr "E456: Cannot find PostScript resource file \"cidfont.ps\""
+
+#, c-format
+msgid "E456: Can't find PostScript resource file \"%s.ps\""
+msgstr "E456: Cannot find PostScript resource file \"%s.ps\""
+
+
+#, c-format
+msgid "E262: error reading cscope connection %ld"
+msgstr "E262: Error reading cscope connection %ld"
+
+msgid "E561: unknown cscope search type"
+msgstr "E561: Unknown cscope search type"
+
+
+msgid "E567: no cscope connections"
+msgstr "E567: No cscope connections"
+
+#, c-format
+msgid "E469: invalid cscopequickfix flag %c for %c"
+msgstr "E469: Invalid cscopequickfix flag %c for %c"
+
+#, c-format
+msgid "E259: no matches found for cscope query %s of %s"
+msgstr "E259: No matches found for cscope query %s of %s"
+
+
+#, c-format
+msgid "E625: cannot open cscope database: %s"
+msgstr "E625: Cannot open cscope database: %s"
+
+msgid "E626: cannot get cscope database information"
+msgstr "E626: Cannot get cscope database information"
+
+msgid "E568: duplicate cscope database not added"
+msgstr "E568: Duplicate cscope database not added"
+
+
+#. should not reach here
+msgid "E570: fatal error in cs_manage_matches"
+msgstr "E570: Fatal error in cs_manage_matches"
+
+
+msgid "couldn't open buffer"
+msgstr "could not open buffer"
+
+
+msgid "E267: unexpected return"
+msgstr "E267: Unexpected return"
+
+msgid "E268: unexpected next"
+msgstr "E268: Unexpected next"
+
+msgid "E269: unexpected break"
+msgstr "E269: Unexpected break"
+
+msgid "E270: unexpected redo"
+msgstr "E270: Unexpected redo"
+
+msgid "E271: retry outside of rescue clause"
+msgstr "E271: Retry outside of rescue clause"
+
+msgid "E272: unhandled exception"
+msgstr "E272: Unhandled exception"
+
+#, c-format
+msgid "E273: unknown longjmp status %d"
+msgstr "E273: Unknown longjmp status %d"
+
+
+#, c-format
+msgid "E572: exit code %d"
+msgstr "E572: Exit code %d"
+
+
+msgid "netbeans is not supported with this GUI\n"
+msgstr "NetBeans is not supported with this GUI\n"
+
+
+msgid "--literal\t\tDon't expand wildcards"
+msgstr "--literal\t\tDo not expand wildcards"
+
+
+msgid "-f or --nofork\tForeground: Don't fork when starting GUI"
+msgstr "-f or --nofork\tForeground: Do not fork when starting GUI"
+
+
+msgid "-f\t\t\tDon't use newcli to open window"
+msgstr "-f\t\t\tDo not use newcli to open window"
+
+
+msgid "--noplugin\t\tDon't load plugin scripts"
+msgstr "--noplugin\t\tDo not load plugin scripts"
+
+
+msgid "--remote-silent <files> Same, don't complain if there is no server"
+msgstr "--remote-silent <files> Same, do not complain if there is no server"
+
+
+msgid ""
+"--remote-wait-silent <files> Same, don't complain if there is no server"
+msgstr ""
+"--remote-wait-silent <files> Same, do not complain if there is no server"
+
+
+msgid "-background <color>\tUse <color> for the background (also: -bg)"
+msgstr "-background <colour>\tUse <colour> for the background (also: -bg)"
+
+msgid "-foreground <color>\tUse <color> for normal text (also: -fg)"
+msgstr "-foreground <colour>\tUse <colour> for normal text (also: -fg)"
+
+
+msgid "+reverse\t\tDon't use reverse video (also: +rv)"
+msgstr "+reverse\t\tDo not use reverse video (also: +rv)"
+
+
+msgid "E288: input method doesn't support any style"
+msgstr "E288: Input method does not support any style"
+
+msgid "E289: input method doesn't support my preedit type"
+msgstr "E289: Input method does not support my preedit type"
+
+msgid "E293: block was not locked"
+msgstr "E293: Block was not locked"
+
+
+msgid "E298: Didn't get block nr 0?"
+msgstr "E298: Did not get block nr 0?"
+
+msgid "E298: Didn't get block nr 1?"
+msgstr "E298: Did not get block nr 1?"
+
+msgid "E298: Didn't get block nr 2?"
+msgstr "E298: Did not get block nr 2?"
+
+
+msgid "E304: ml_upd_block0(): Didn't get block 0??"
+msgstr "E304: ml_upd_block0(): Did not get block 0??"
+
+
+msgid "E317: pointer block id wrong 3"
+msgstr "E317: Pointer block id wrong 3"
+
+
+msgid "E317: pointer block id wrong 4"
+msgstr "E317: Pointer block id wrong 4"
+
+
+msgid "E317: pointer block id wrong"
+msgstr "E317: Pointer block id wrong"
+
+
+#, c-format
+msgid "E322: line number out of range: %ld past the end"
+msgstr "E322: Line number out of range: %ld past the end"
+
+#, c-format
+msgid "E323: line count wrong in block %ld"
+msgstr "E323: Line count wrong in block %ld"
+
+
+msgid "E317: pointer block id wrong 2"
+msgstr "E317: Pointer block id wrong 2"
+
+
+msgid "Messages maintainer: Bram Moolenaar <Bram@vim.org>"
+msgstr "Messages maintainer: Mike Williams <mrw@eandem.co.uk>"
+
+
+msgid "E548: digit expected"
+msgstr "E548: Digit expected"
+
+
+msgid "E854: path too long for completion"
+msgstr "E854: Path too long for completion"
+
+
+#, c-format
+msgid "E344: Can't find directory \"%s\" in cdpath"
+msgstr "E344: Cannot find directory \"%s\" in cdpath"
+
+#, c-format
+msgid "E345: Can't find file \"%s\" in path"
+msgstr "E345: Cannot find file \"%s\" in path"
+
+
+msgid "E838: netbeans is not supported with this GUI"
+msgstr "E838: NetBeans is not supported with this GUI"
+
+msgid "E511: netbeans already connected"
+msgstr "E511: NetBeans already connected"
+
+
+msgid "E664: changelist is empty"
+msgstr "E664: Changelist is empty"
+
+
+msgid ""
+"E883: search pattern and expression register may not contain two or more "
+"lines"
+msgstr "E883: Search pattern and expression register may not contain two or more lines"
+
+
+msgid "E595: contains unprintable or wide character"
+msgstr "E595: Contains unprintable or wide character"
+
+
+msgid "E597: can't select fontset"
+msgstr "E597: Cannot select fontset"
+
+
+msgid "E533: can't select wide font"
+msgstr "E533: Cannot select wide font"
+
+
+msgid "E536: comma required"
+msgstr "E536: Comma required"
+
+
+msgid "E541: too many items"
+msgstr "E541: Too many items"
+
+msgid "E542: unbalanced groups"
+msgstr "E542: Unbalanced groups"
+
+
+msgid "VIM: Can't open window!\n"
+msgstr "VIM: Cannot open window!\n"
+
+
+#, c-format
+msgid "E369: invalid item in %s%%[]"
+msgstr "E369: Invalid item in %s%%[]"
+
+
+#, c-format
+msgid "E59: invalid character after %s@"
+msgstr "E59: Invalid character after %s@"
+
+
+msgid "E63: invalid use of \\_"
+msgstr "E63: Invalid use of \\_"
+
+
+#. Can't have a multi follow a multi.
+msgid "E871: (NFA regexp) Can't have a multi follow a multi"
+msgstr "E871: (NFA regexp) Cannot have a multi follow a multi"
+
+
+#, c-format
+msgid "E384: search hit TOP without match for: %s"
+msgstr "E384: Search hit TOP without match for: %s"
+
+#, c-format
+msgid "E385: search hit BOTTOM without match for: %s"
+msgstr "E385: Search hit BOTTOM without match for: %s"
+
+
+msgid "E388: Couldn't find definition"
+msgstr "E388: Could not find definition"
+
+msgid "E389: Couldn't find pattern"
+msgstr "E389: Could not find pattern"
+
+
+#, c-format
+msgid "E781: .sug file doesn't match .spl file: %s"
+msgstr "E781: .sug file does not match .spl file: %s"
+
+#, c-format
+msgid "E782: error while reading .sug file: %s"
+msgstr "E782: Error while reading .sug file: %s"
+
+
+#, c-format
+msgid "Unrecognized or duplicate item in %s line %d: %s"
+msgstr "Unrecognised or duplicate item in %s line %d: %s"
+
+
+#, c-format
+msgid "Unrecognized flags in %s line %d: %s"
+msgstr "Unrecognised flags in %s line %d: %s"
+
+
+#. * file.
+msgid "E783: duplicate char in MAP entry"
+msgstr "E783: Duplicate char in MAP entry"
+
+
+msgid "E395: contains argument not accepted here"
+msgstr "E395: Contains argument not accepted here"
+
+msgid "E844: invalid cchar value"
+msgstr "E844: Invalid cchar value"
+
+
+#, c-format
+msgid "E394: Didn't find region item for %s"
+msgstr "E394: Did not find region item for %s"
+
+
+#, c-format
+msgid "E890: trailing char after ']': %s]%s"
+msgstr "E890: Trailing char after ']': %s]%s"
+
+
+msgid "E679: recursive loop loading syncolor.vim"
+msgstr "E679: Recursive loop loading syncolor.vim"
+
+#, c-format
+msgid "E411: highlight group not found: %s"
+msgstr "E411: Highlight group not found: %s"
+
+
+#, c-format
+msgid "E415: unexpected equal sign: %s"
+msgstr "E415: Unexpected equal sign: %s"
+
+#, c-format
+msgid "E416: missing equal sign: %s"
+msgstr "E416: Missing equal sign: %s"
+
+#, c-format
+msgid "E417: missing argument: %s"
+msgstr "E417: Missing argument: %s"
+
+
+msgid "E419: FG color unknown"
+msgstr "E419: FG colour unknown"
+
+msgid "E420: BG color unknown"
+msgstr "E420: BG colour unknown"
+
+#, c-format
+msgid "E421: Color name or number not recognized: %s"
+msgstr "E421: Colour name or number not recognised: %s"
+
+#, c-format
+msgid "E422: terminal code too long: %s"
+msgstr "E422: Terminal code too long: %s"
+
+
+msgid "E555: at bottom of tag stack"
+msgstr "E555: At bottom of tag stack"
+
+msgid "E556: at top of tag stack"
+msgstr "E556: At top of tag stack"
+
+
+#, c-format
+msgid "E426: tag not found: %s"
+msgstr "E426: Tag not found: %s"
+
+
+msgid "E434: Can't find tag pattern"
+msgstr "E434: Cannot find tag pattern"
+
+msgid "E435: Couldn't find tag, just guessing!"
+msgstr "E435: Could not find tag, just guessing!"
+
+
+msgid "E437: terminal capability \"cm\" required"
+msgstr "E437: Terminal capability \"cm\" required"
+
+
+#, c-format
+msgid "E829: write error in undo file: %s"
+msgstr "E829: Write error in undo file: %s"
+
+
+msgid "E442: Can't split topleft and botright at the same time"
+msgstr "E442: Cannot split topleft and botright at the same time"
+
+
+#, c-format
+msgid "E447: Can't find file \"%s\" in path"
+msgstr "E447: Cannot find file \"%s\" in path"
+
+
+#, c-format
+msgid "E247: no registered server named \"%s\""
+msgstr "E247: No registered server named \"%s\""
+
+#, c-format
+msgid "E482: Can't create file %s"
+msgstr "E482: Cannot create file %s"
+
+msgid "E483: Can't get temp file name"
+msgstr "E483: Cannot get temp file name"
+
+#, c-format
+msgid "E484: Can't open file %s"
+msgstr "E484: Cannot open file %s"
+
+#, c-format
+msgid "E485: Can't read file %s"
+msgstr "E485: Cannot read file %s"
+
+
+#, c-format
+msgid "E40: Can't open errorfile %s"
+msgstr "E40: Cannot open errorfile %s"
+
+msgid "E233: cannot open display"
+msgstr "E233: Cannot open display"
+
+
+#, c-format
+msgid "E684: list index out of range: %ld"
+msgstr "E684: List index out of range: %ld"
+
+
+msgid "E255: Couldn't read in sign data!"
+msgstr "E255: Could not read in sign data!"
+
+
+msgid "E363: pattern uses more memory than 'maxmempattern'"
+msgstr "E363: Pattern uses more memory than 'maxmempattern'"
+
+msgid "E749: empty buffer"
+msgstr "E749: Empty buffer"
+
+
+msgid "can't delete OutputObject attributes"
+msgstr "cannot delete OutputObject attributes"
+
+
diff --git a/src/po/eo.po b/src/po/eo.po
new file mode 100644
index 0000000..657389c
--- /dev/null
+++ b/src/po/eo.po
@@ -0,0 +1,7146 @@
+# Esperanto Translation for Vim
+#
+# Do ":help uganda" in Vim to read copying and usage conditions.
+# Do ":help credits" in Vim to see a list of people who contributed.
+#
+# UNUA TRADUKISTO Dominique PELLE <dominique.pelle ĉe gmail.com>
+# PROVLEGANTO(J) Felipe CASTRO <fefcas ĉe gmail.com>
+# Antono MECHELYNCK <antoine.mechelynck ĉe gmail.com>
+# Yves NEVELSTEEN
+#
+# Uzitaj vortaroj kaj fakvortaroj:
+# Revo: http://www.reta-vortaro.de/revo/
+# Komputeko: http://komputeko.net/index_eo.php
+# Komputada leksikono: http://bertilow.com/div/komputada_leksikono/
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Vim 8.1\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2018-10-30 09:47+0100\n"
+"PO-Revision-Date: 2018-10-30 10:02+0100\n"
+"Last-Translator: Dominique PELLÉ <dominique.pelle@gmail.com>\n"
+"Language-Team: Esperanto\n"
+"Language: eo\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+msgid "E831: bf_key_init() called with empty password"
+msgstr "E831: bf_key_init() alvokita kun malplena pasvorto"
+
+msgid "E820: sizeof(uint32_t) != 4"
+msgstr "E820: sizeof(uint32_t) != 4"
+
+msgid "E817: Blowfish big/little endian use wrong"
+msgstr "E817: Misuzo de pezkomenca/pezfina en blowfish"
+
+msgid "E818: sha256 test failed"
+msgstr "E818: Testo de sha256 malsukcesis"
+
+msgid "E819: Blowfish test failed"
+msgstr "E819: Testo de blowfish malsukcesis"
+
+msgid "[Location List]"
+msgstr "[Listo de lokoj]"
+
+# DP: Ĉu vere indas traduki Quickfix?
+msgid "[Quickfix List]"
+msgstr "[Listo de rapidriparoj]"
+
+msgid "E855: Autocommands caused command to abort"
+msgstr "E855: AÅ­tokomandoj haltigis komandon"
+
+msgid "E82: Cannot allocate any buffer, exiting..."
+msgstr "E82: Ne eblas disponigi iun ajn bufron, nun eliras..."
+
+msgid "E83: Cannot allocate buffer, using other one..."
+msgstr "E83: Ne eblas disponigi bufron, nun uzas alian..."
+
+msgid "E931: Buffer cannot be registered"
+msgstr "E931: Bufro ne povas esti registrita"
+
+msgid "E937: Attempt to delete a buffer that is in use"
+msgstr "E937: Provo de forviÅo de bufro, kiu estas en uzo"
+
+msgid "E515: No buffers were unloaded"
+msgstr "E515: Neniu bufro estis malÅargita"
+
+msgid "E516: No buffers were deleted"
+msgstr "E516: Neniu bufro estis forviÅita"
+
+msgid "E517: No buffers were wiped out"
+msgstr "E517: Neniu bufro estis detruita"
+
+#, c-format
+msgid "%d buffer unloaded"
+msgid_plural "%d buffers unloaded"
+msgstr[0] "%d bufro malÅargita"
+msgstr[1] "%d bufroj malÅargitaj"
+
+#, c-format
+msgid "%d buffer deleted"
+msgid_plural "%d buffers deleted"
+msgstr[0] "%d bufro forviÅita"
+msgstr[1] "%d bufroj forviÅitaj"
+
+#, c-format
+msgid "%d buffer wiped out"
+msgid_plural "%d buffers wiped out"
+msgstr[0] "%d bufro detruita"
+msgstr[1] "%d bufroj detruitaj"
+
+msgid "E90: Cannot unload last buffer"
+msgstr "E90: Ne eblas malÅargi la lastan bufron"
+
+msgid "E84: No modified buffer found"
+msgstr "E84: Neniu modifita bufro trovita"
+
+msgid "E85: There is no listed buffer"
+msgstr "E85: Estas neniu listigita bufro"
+
+msgid "E87: Cannot go beyond last buffer"
+msgstr "E87: Ne eblas iri preter la lastan bufron"
+
+msgid "E88: Cannot go before first buffer"
+msgstr "E88: Ne eblas iri antaÅ­ la unuan bufron"
+
+#, c-format
+msgid "E89: No write since last change for buffer %ld (add ! to override)"
+msgstr ""
+"E89: Neniu skribo de post la lasta ÅanÄo de la bufro %ld (aldonu ! por "
+"transpasi)"
+
+msgid "E948: Job still running (add ! to end the job)"
+msgstr "E948: Tasko ankoraÅ­ aktiva (aldonu ! por fini la taskon)"
+
+msgid "E37: No write since last change (add ! to override)"
+msgstr "E37: Neniu skribo de post lasta ÅanÄo (aldonu ! por transpasi)"
+
+msgid "E948: Job still running"
+msgstr "E948: Tasko ankoraÅ­ aktiva"
+
+msgid "E37: No write since last change"
+msgstr "E37: Neniu skribo de post lasta ÅanÄo"
+
+msgid "W14: Warning: List of file names overflow"
+msgstr "W14: Averto: Listo de dosiernomoj troas"
+
+#, c-format
+msgid "E92: Buffer %ld not found"
+msgstr "E92: Bufro %ld ne trovita"
+
+#, c-format
+msgid "E93: More than one match for %s"
+msgstr "E93: Pli ol unu kongruo kun %s"
+
+#, c-format
+msgid "E94: No matching buffer for %s"
+msgstr "E94: Neniu bufro kongruas kun %s"
+
+#, c-format
+msgid "line %ld"
+msgstr "linio %ld"
+
+msgid "E95: Buffer with this name already exists"
+msgstr "E95: Bufro kun tiu nomo jam ekzistas"
+
+msgid " [Modified]"
+msgstr "[Modifita]"
+
+msgid "[Not edited]"
+msgstr "[Ne redaktita]"
+
+msgid "[New file]"
+msgstr "[Nova dosiero]"
+
+msgid "[Read errors]"
+msgstr "[Eraroj de legado]"
+
+msgid "[RO]"
+msgstr "[Nurlegebla]"
+
+msgid "[readonly]"
+msgstr "[nurlegebla]"
+
+#, c-format
+msgid "%ld line --%d%%--"
+msgid_plural "%ld lines --%d%%--"
+msgstr[0] "%ld linio --%d%%--"
+msgstr[1] "%ld linioj --%d%%--"
+
+#, c-format
+msgid "line %ld of %ld --%d%%-- col "
+msgstr "linio %ld de %ld --%d%%-- kol "
+
+msgid "[No Name]"
+msgstr "[Neniu nomo]"
+
+msgid "help"
+msgstr "helpo"
+
+msgid "[Help]"
+msgstr "[Helpo]"
+
+msgid "[Preview]"
+msgstr "[AntaÅ­vido]"
+
+msgid "All"
+msgstr "Ĉio"
+
+msgid "Bot"
+msgstr "Subo"
+
+msgid "Top"
+msgstr "Supro"
+
+msgid ""
+"\n"
+"# Buffer list:\n"
+msgstr ""
+"\n"
+"# Listo de bufroj:\n"
+
+msgid "E382: Cannot write, 'buftype' option is set"
+msgstr "E382: Ne eblas skribi, opcio 'buftype' estas Åaltita"
+
+msgid "[Prompt]"
+msgstr "[Invito]"
+
+msgid "[Scratch]"
+msgstr "[Malneto]"
+
+# DP: Vidu ":help sign-support" por klarigo pri "Sign"
+msgid ""
+"\n"
+"--- Signs ---"
+msgstr ""
+"\n"
+"--- Emfazaj simbolaĵoj ---"
+
+#, c-format
+msgid "Signs for %s:"
+msgstr "Emfazaj simbolaĵoj de %s:"
+
+#, c-format
+msgid " line=%ld id=%d name=%s"
+msgstr " linio=%ld id=%d nomo=%s"
+
+msgid "E902: Cannot connect to port"
+msgstr "E902: Ne eblas konekti al pordo"
+
+msgid "E901: gethostbyname() in channel_open()"
+msgstr "E901: gethostbyname() en channel_open()"
+
+msgid "E898: socket() in channel_open()"
+msgstr "E898: gethostbyname() en channel_open()"
+
+msgid "E903: received command with non-string argument"
+msgstr "E903: ricevis komandon kun argumento, kiu ne estas ĉeno"
+
+msgid "E904: last argument for expr/call must be a number"
+msgstr "E904: lasta argumento de \"expr/call\" devas esti nombro"
+
+msgid "E904: third argument for call must be a list"
+msgstr "E904: tria argumento de \"call\" devas esti listo"
+
+#, c-format
+msgid "E905: received unknown command: %s"
+msgstr "E905: nekonata komando ricevita: %s"
+
+#, c-format
+msgid "E630: %s(): write while not connected"
+msgstr "E630: %s(): konservo dum nekonektita"
+
+#, c-format
+msgid "E631: %s(): write failed"
+msgstr "E631: %s(): Konservo malsukcesis"
+
+#, c-format
+msgid "E917: Cannot use a callback with %s()"
+msgstr "E917: Ne eblas uzi reagfunkcion kun %s()"
+
+msgid "E912: cannot use ch_evalexpr()/ch_sendexpr() with a raw or nl channel"
+msgstr "E912: ne eblas uzi ch_evalexpr()/ch_sendexpr() kun kruda aÅ­ nl kanalo"
+
+msgid "E906: not an open channel"
+msgstr "E906: ne estas malfermita kanalo"
+
+msgid "E920: _io file requires _name to be set"
+msgstr "E920: dosiero _io bezonas _name"
+
+msgid "E915: in_io buffer requires in_buf or in_name to be set"
+msgstr "E915: bufro in_io bezonas in_buf aÅ­ in_name"
+
+#, c-format
+msgid "E918: buffer must be loaded: %s"
+msgstr "E918: bufro devas esti Åargita: %s"
+
+msgid "E821: File is encrypted with unknown method"
+msgstr "E821: Dosiero estas ĉifrita per nekonata metodo"
+
+msgid "Warning: Using a weak encryption method; see :help 'cm'"
+msgstr "Averto: uzo de malfortika ĉifrada metodo; vidu :help 'cm'"
+
+msgid "Enter encryption key: "
+msgstr "Tajpu la Ålosilon de ĉifrado: "
+
+msgid "Enter same key again: "
+msgstr "Tajpu la Ålosilon denove: "
+
+msgid "Keys don't match!"
+msgstr "Åœlosiloj ne kongruas!"
+
+msgid "[crypted]"
+msgstr "[ĉifrita]"
+
+#, c-format
+msgid "E720: Missing colon in Dictionary: %s"
+msgstr "E720: Mankas dupunkto en la vortaro: %s"
+
+#, c-format
+msgid "E721: Duplicate key in Dictionary: \"%s\""
+msgstr "E721: Ripetita Ålosilo en la vortaro: \"%s\""
+
+#, c-format
+msgid "E722: Missing comma in Dictionary: %s"
+msgstr "E722: Mankas komo en la vortaro: %s"
+
+#, c-format
+msgid "E723: Missing end of Dictionary '}': %s"
+msgstr "E723: Mankas fino de vortaro '}': %s"
+
+msgid "extend() argument"
+msgstr "argumento de extend()"
+
+#, c-format
+msgid "E737: Key already exists: %s"
+msgstr "E737: Åœlosilo jam ekzistas: %s"
+
+#, c-format
+msgid "E96: Cannot diff more than %ld buffers"
+msgstr "E96: Ne eblas dosierdiferenci pli ol %ld bufrojn"
+
+#, c-format
+msgid "Not enough memory to use internal diff for buffer \"%s\""
+msgstr "Ne sufiĉa memoro por uzi internan dosierdiferencilon por bufro \"%s\""
+
+msgid "E810: Cannot read or write temp files"
+msgstr "E810: Ne eblas legi aÅ­ skribi provizorajn dosierojn"
+
+msgid "E97: Cannot create diffs"
+msgstr "E97: Ne eblas krei dosierdiferencojn"
+
+msgid "E960: Problem creating the internal diff"
+msgstr "E960: Problemo dum kreado de la interna dosierdiferencilo"
+
+msgid "Patch file"
+msgstr "Flika dosiero"
+
+msgid "E816: Cannot read patch output"
+msgstr "E816: Ne eblas legi eliron de flikilo \"patch\""
+
+msgid "E98: Cannot read diff output"
+msgstr "E98: Ne eblas legi eliron de dosierdiferencilo \"diff\""
+
+msgid "E959: Invalid diff format."
+msgstr "E959: Nevalida formato de dosierdiferenco"
+
+msgid "E99: Current buffer is not in diff mode"
+msgstr "E99: Aktuala bufro ne estas en dosierdiferenca reÄimo"
+
+msgid "E793: No other buffer in diff mode is modifiable"
+msgstr "E793: Neniu alia bufro en dosierdiferenca reÄimo estas modifebla"
+
+msgid "E100: No other buffer in diff mode"
+msgstr "E100: Neniu alia bufro en dosierdiferenca reÄimo"
+
+msgid "E101: More than two buffers in diff mode, don't know which one to use"
+msgstr "E101: Pli ol du bufroj en dosierdiferenca reÄimo, ne scias kiun uzi"
+
+#, c-format
+msgid "E102: Can't find buffer \"%s\""
+msgstr "E102: Ne eblas trovi bufron \"%s\""
+
+#, c-format
+msgid "E103: Buffer \"%s\" is not in diff mode"
+msgstr "E103: Bufro \"%s\" ne estas en dosierdiferenca reÄimo"
+
+msgid "E787: Buffer changed unexpectedly"
+msgstr "E787: Bufro ÅanÄiÄis neatendite"
+
+msgid "E104: Escape not allowed in digraph"
+msgstr "E104: Eskapsigno nepermesebla en duliteraĵo"
+
+msgid "E544: Keymap file not found"
+msgstr "E544: Dosiero de klavmapo ne troveblas"
+
+msgid "E105: Using :loadkeymap not in a sourced file"
+msgstr "E105: Uzo de \":loadkeymap\" nur eblas en vim-skripto"
+
+msgid "E791: Empty keymap entry"
+msgstr "E791: Malplena rikordo en klavmapo"
+
+msgid " Keyword completion (^N^P)"
+msgstr " Kompletigo de Ålosilvorto (^N^P)"
+
+msgid " ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+msgstr " ReÄimo ^X (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+
+msgid " Whole line completion (^L^N^P)"
+msgstr " Kompletigo de tuta linio (^L^N^P)"
+
+msgid " File name completion (^F^N^P)"
+msgstr " Kompletigo de dosiernomo (^F^N^P)"
+
+msgid " Tag completion (^]^N^P)"
+msgstr " Kompletigo de etikedo (^]^N^P)"
+
+msgid " Path pattern completion (^N^P)"
+msgstr " Kompletigo de Åablona dosierindiko (^N^P)"
+
+msgid " Definition completion (^D^N^P)"
+msgstr " Kompletigo de difino (^D^N^P)"
+
+msgid " Dictionary completion (^K^N^P)"
+msgstr " Kompletigo de vortaro (^K^N^P)"
+
+msgid " Thesaurus completion (^T^N^P)"
+msgstr " Kompletigo de tezaÅ­ro (^T^N^P)"
+
+msgid " Command-line completion (^V^N^P)"
+msgstr " Kompletigo de komanda linio (^V^N^P)"
+
+msgid " User defined completion (^U^N^P)"
+msgstr " Kompletigo difinita de uzanto (^U^N^P)"
+
+# DP: Ĉu eblas trovi pli bonan tradukon?
+msgid " Omni completion (^O^N^P)"
+msgstr " Kompletigo Omni (^O^N^P)"
+
+msgid " Spelling suggestion (s^N^P)"
+msgstr " Sugesto de literumo (s^N^P)"
+
+msgid " Keyword Local completion (^N^P)"
+msgstr " Kompletigo loka de Ålosilvorto (^N/^P)"
+
+msgid "Hit end of paragraph"
+msgstr "Atingis finon de alineo"
+
+msgid "E839: Completion function changed window"
+msgstr "E839: Kompletiga funkcio ÅanÄis la fenestron"
+
+msgid "E840: Completion function deleted text"
+msgstr "E840: Kompletiga funkcio forviÅis tekston"
+
+msgid "'dictionary' option is empty"
+msgstr "La opcio 'dictionary' estas malplena"
+
+msgid "'thesaurus' option is empty"
+msgstr "La opcio 'thesaurus' estas malplena"
+
+#, c-format
+msgid "Scanning dictionary: %s"
+msgstr "Analizas vortaron: %s"
+
+msgid " (insert) Scroll (^E/^Y)"
+msgstr " (enmeto) Rulumo (^E/^Y)"
+
+msgid " (replace) Scroll (^E/^Y)"
+msgstr " (anstataÅ­igo) Rulumo (^E/^Y)"
+
+#, c-format
+msgid "Scanning: %s"
+msgstr "Analizas: %s"
+
+msgid "Scanning tags."
+msgstr "Analizas etikedojn."
+
+msgid "match in file"
+msgstr "kongruo en dosiero"
+
+msgid " Adding"
+msgstr " Aldonanta"
+
+msgid "-- Searching..."
+msgstr "-- Serĉanta..."
+
+msgid "Back at original"
+msgstr "Reveninta al originalo"
+
+msgid "Word from other line"
+msgstr "Vorto el alia linio"
+
+msgid "The only match"
+msgstr "La sola kongruo"
+
+#, c-format
+msgid "match %d of %d"
+msgstr "kongruo %d de %d"
+
+#, c-format
+msgid "match %d"
+msgstr "kongruo %d"
+
+msgid "E18: Unexpected characters in :let"
+msgstr "E18: Neatenditaj signoj en \":let\""
+
+#, c-format
+msgid "E121: Undefined variable: %s"
+msgstr "E121: Nedifinita variablo: %s"
+
+msgid "E111: Missing ']'"
+msgstr "E111: Mankas ']'"
+
+msgid "E719: Cannot use [:] with a Dictionary"
+msgstr "E719: Uzo de [:] ne eblas kun Vortaro"
+
+#, c-format
+msgid "E734: Wrong variable type for %s="
+msgstr "E734: Nevalida datumtipo de variablo de %s="
+
+#, c-format
+msgid "E461: Illegal variable name: %s"
+msgstr "E461: Nevalida nomo de variablo: %s"
+
+msgid "E806: using Float as a String"
+msgstr "E806: uzo de Glitpunktnombro kiel Ĉeno"
+
+msgid "E687: Less targets than List items"
+msgstr "E687: Malpli da celoj ol Listeroj"
+
+msgid "E688: More targets than List items"
+msgstr "E688: Pli da celoj ol Listeroj"
+
+msgid "Double ; in list of variables"
+msgstr "Duobla ; en listo de variabloj"
+
+#, c-format
+msgid "E738: Can't list variables for %s"
+msgstr "E738: Ne eblas listigi variablojn de %s"
+
+msgid "E689: Can only index a List or Dictionary"
+msgstr "E689: Nur eblas indeksi Liston aÅ­ Vortaron"
+
+msgid "E708: [:] must come last"
+msgstr "E708: [:] devas esti laste"
+
+msgid "E709: [:] requires a List value"
+msgstr "E709: [:] bezonas listan valoron"
+
+msgid "E710: List value has more items than target"
+msgstr "E710: Lista valoro havas pli da eroj ol la celo"
+
+msgid "E711: List value has not enough items"
+msgstr "E711: Lista valoro ne havas sufiĉe da eroj"
+
+msgid "E690: Missing \"in\" after :for"
+msgstr "E690: \"in\" mankas malantaÅ­ \":for\""
+
+#, c-format
+msgid "E108: No such variable: \"%s\""
+msgstr "E108: Ne estas tia variablo: \"%s\""
+
+#, c-format
+msgid "E940: Cannot lock or unlock variable %s"
+msgstr "E940: Ne eblas Ålosi aÅ­ malÅlosi variablon %s"
+
+msgid "E743: variable nested too deep for (un)lock"
+msgstr "E743: variablo ingita tro profunde por (mal)Ålosi"
+
+msgid "E109: Missing ':' after '?'"
+msgstr "E109: Mankas ':' malantaÅ­ '?'"
+
+msgid "E804: Cannot use '%' with Float"
+msgstr "E804: Ne eblas uzi '%' kun Glitpunktnombro"
+
+msgid "E110: Missing ')'"
+msgstr "E110: Mankas ')'"
+
+msgid "E695: Cannot index a Funcref"
+msgstr "E695: Ne eblas indeksi Funcref"
+
+msgid "E909: Cannot index a special variable"
+msgstr "E909: Ne eblas indeksi specialan variablon"
+
+#, c-format
+msgid "E112: Option name missing: %s"
+msgstr "E112: Mankas nomo de opcio: %s"
+
+#, c-format
+msgid "E113: Unknown option: %s"
+msgstr "E113: Nekonata opcio: %s"
+
+#, c-format
+msgid "E114: Missing quote: %s"
+msgstr "E114: Mankas citilo: %s"
+
+#, c-format
+msgid "E115: Missing quote: %s"
+msgstr "E115: Mankas citilo: %s"
+
+msgid "Not enough memory to set references, garbage collection aborted!"
+msgstr "Ne sufiĉa memoro por valorigi referencojn, senrubigado ĉesigita!"
+
+msgid "E724: variable nested too deep for displaying"
+msgstr "E724: variablo ingita tro profunde por vidigi"
+
+msgid "E805: Using a Float as a Number"
+msgstr "E805: Uzo de Glitpunktnombro kiel Nombro"
+
+msgid "E703: Using a Funcref as a Number"
+msgstr "E703: Uzo de Funcref kiel Nombro"
+
+msgid "E745: Using a List as a Number"
+msgstr "E745: Uzo de Listo kiel Nombro"
+
+msgid "E728: Using a Dictionary as a Number"
+msgstr "E728: Uzo de Vortaro kiel Nombro"
+
+msgid "E910: Using a Job as a Number"
+msgstr "E910: Uzo de Tasko kiel Nombro"
+
+msgid "E913: Using a Channel as a Number"
+msgstr "E913: Uzo de Kanalo kiel Nombro"
+
+msgid "E891: Using a Funcref as a Float"
+msgstr "E891: Uzo de Funcref kiel Glitpunktnombro"
+
+msgid "E892: Using a String as a Float"
+msgstr "E892: Uzo de Ĉeno kiel Glitpunktnombro"
+
+msgid "E893: Using a List as a Float"
+msgstr "E893: Uzo de Listo kiel Glitpunktnombro"
+
+msgid "E894: Using a Dictionary as a Float"
+msgstr "E894: Uzo de Vortaro kiel Glitpunktnombro"
+
+msgid "E907: Using a special value as a Float"
+msgstr "E907: Uzo de speciala valoro kiel Glitpunktnombro"
+
+msgid "E911: Using a Job as a Float"
+msgstr "E911: Uzo de Tasko kiel Glitpunktnombro"
+
+msgid "E914: Using a Channel as a Float"
+msgstr "E914: Uzo de Kanalo kiel Glitpunktnombro"
+
+msgid "E729: using Funcref as a String"
+msgstr "E729: uzo de Funcref kiel Ĉeno"
+
+msgid "E730: using List as a String"
+msgstr "E730: uzo de Listo kiel Ĉeno"
+
+msgid "E731: using Dictionary as a String"
+msgstr "E731: uzo de Vortaro kiel Ĉeno"
+
+msgid "E908: using an invalid value as a String"
+msgstr "E908: uzo de nevalida valoro kiel Ĉeno"
+
+#, c-format
+msgid "E795: Cannot delete variable %s"
+msgstr "E795: Ne eblas forviÅi variablon %s"
+
+#, c-format
+msgid "E704: Funcref variable name must start with a capital: %s"
+msgstr "E704: Nomo de variablo Funcref devas eki per majusklo: %s"
+
+#, c-format
+msgid "E705: Variable name conflicts with existing function: %s"
+msgstr "E705: Nomo de variablo konfliktas kun ekzistanta funkcio: %s"
+
+#, c-format
+msgid "E741: Value is locked: %s"
+msgstr "E741: Valoro estas Ålosita: %s"
+
+msgid "Unknown"
+msgstr "Nekonata"
+
+#, c-format
+msgid "E742: Cannot change value of %s"
+msgstr "E742: Ne eblas ÅanÄi valoron de %s"
+
+msgid "E698: variable nested too deep for making a copy"
+msgstr "E698: variablo ingita tro profunde por fari kopion"
+
+msgid ""
+"\n"
+"# global variables:\n"
+msgstr ""
+"\n"
+"# mallokaj variabloj:\n"
+
+msgid ""
+"\n"
+"\tLast set from "
+msgstr ""
+"\n"
+"\tLaste Åaltita de "
+
+msgid " line "
+msgstr " linio "
+
+msgid "E691: Can only compare List with List"
+msgstr "E691: Eblas nur kompari Liston kun Listo"
+
+msgid "E692: Invalid operation for List"
+msgstr "E692: Nevalida operacio de Listoj"
+
+msgid "E735: Can only compare Dictionary with Dictionary"
+msgstr "E735: Eblas nur kompari Vortaron kun Vortaro"
+
+msgid "E736: Invalid operation for Dictionary"
+msgstr "E736: Nevalida operacio de Vortaro"
+
+msgid "E694: Invalid operation for Funcrefs"
+msgstr "E694: Nevalida operacio de Funcref-oj"
+
+msgid "map() argument"
+msgstr "argumento de map()"
+
+msgid "filter() argument"
+msgstr "argumento de filter()"
+
+#, c-format
+msgid "E686: Argument of %s must be a List"
+msgstr "E686: Argumento de %s devas esti Listo"
+
+msgid "E928: String required"
+msgstr "E928: Ĉeno bezonata"
+
+msgid "E808: Number or Float required"
+msgstr "E808: Nombro aÅ­ Glitpunktnombro bezonata"
+
+msgid "add() argument"
+msgstr "argumento de add()"
+
+msgid "E785: complete() can only be used in Insert mode"
+msgstr "E785: complete() uzeblas nur en Enmeta reÄimo"
+
+msgid "&Ok"
+msgstr "&Bone"
+
+#, c-format
+msgid "+-%s%3ld line: "
+msgid_plural "+-%s%3ld lines: "
+msgstr[0] "+-%s%3ld linio: "
+msgstr[1] "+-%s%3ld linioj: "
+
+#, c-format
+msgid "E700: Unknown function: %s"
+msgstr "E700: Nekonata funkcio: %s"
+
+msgid "E922: expected a dict"
+msgstr "E922: vortaro atendita"
+
+msgid "E923: Second argument of function() must be a list or a dict"
+msgstr "E923: Dua argumento de function() devas esti listo aÅ­ Vortaro"
+
+msgid ""
+"&OK\n"
+"&Cancel"
+msgstr ""
+"&Bone\n"
+"&Rezigni"
+
+msgid "called inputrestore() more often than inputsave()"
+msgstr "alvokis inputrestore() pli ofte ol inputsave()"
+
+msgid "insert() argument"
+msgstr "argumento de insert()"
+
+msgid "E786: Range not allowed"
+msgstr "E786: Amplekso nepermesebla"
+
+msgid "E916: not a valid job"
+msgstr "E916: nevalida tasko"
+
+msgid "E701: Invalid type for len()"
+msgstr "E701: Nevalida datumtipo de len()"
+
+msgid "E957: Invalid window number"
+msgstr "E957: Nevalida numero de vindozo"
+
+#, c-format
+msgid "E798: ID is reserved for \":match\": %ld"
+msgstr "E798: ID estas rezervita por \":match\": %ld"
+
+msgid "E726: Stride is zero"
+msgstr "E726: PaÅo estas nul"
+
+msgid "E727: Start past end"
+msgstr "E727: Komenco preter fino"
+
+msgid "<empty>"
+msgstr "<malplena>"
+
+msgid "E240: No connection to the X server"
+msgstr "E240: Neniu konekto al X-servilo"
+
+#, c-format
+msgid "E241: Unable to send to %s"
+msgstr "E241: Ne eblas sendi al %s"
+
+msgid "E277: Unable to read a server reply"
+msgstr "E277: Ne eblas legi respondon de servilo"
+
+msgid "E941: already started a server"
+msgstr "E941: servilo jam lanĉita"
+
+msgid "E942: +clientserver feature not available"
+msgstr "E942: la eblo +clientserver ne disponeblas"
+
+msgid "remove() argument"
+msgstr "argumento de remove()"
+
+msgid "E655: Too many symbolic links (cycle?)"
+msgstr "E655: Tro da simbolaj ligiloj (ĉu estas ciklo?)"
+
+msgid "reverse() argument"
+msgstr "argumento de reverse()"
+
+msgid "E258: Unable to send to client"
+msgstr "E258: Ne eblas sendi al kliento"
+
+#, c-format
+msgid "E927: Invalid action: '%s'"
+msgstr "E927: Nevalida ago: '%s'"
+
+msgid "sort() argument"
+msgstr "argumento de sort()"
+
+msgid "uniq() argument"
+msgstr "argumento de uniq()"
+
+msgid "E702: Sort compare function failed"
+msgstr "E702: Ordiga funkcio malsukcesis"
+
+msgid "E882: Uniq compare function failed"
+msgstr "E882: kompara funkcio de uniq() malsukcesis"
+
+msgid "(Invalid)"
+msgstr "(Nevalida)"
+
+#, c-format
+msgid "E935: invalid submatch number: %d"
+msgstr "E935: nevalida indekso de \"submatch\": %d"
+
+msgid "E677: Error writing temp file"
+msgstr "E677: Eraro dum skribo de provizora dosiero"
+
+msgid "E921: Invalid callback argument"
+msgstr "E921: Nevalida argumento de reagfunctio"
+
+#, c-format
+msgid "<%s>%s%s %d, Hex %02x, Oct %03o, Digr %s"
+msgstr "<%s>%s%s %d, Deksesuma %02x, Okuma %03o, Digr %s"
+
+#, c-format
+msgid "<%s>%s%s %d, Hex %02x, Octal %03o"
+msgstr "<%s>%s%s %d, Deksesuma %02x, Okuma %03o"
+
+#, c-format
+msgid "> %d, Hex %04x, Oct %o, Digr %s"
+msgstr "> %d, Deksesuma %04x, Okuma %o, Digr %s"
+
+#, c-format
+msgid "> %d, Hex %08x, Oct %o, Digr %s"
+msgstr "> %d, Deksesuma %08x, Okuma %o, Digr %s"
+
+#, c-format
+msgid "> %d, Hex %04x, Octal %o"
+msgstr "> %d, Deksesuma %04x, Okuma %o"
+
+#, c-format
+msgid "> %d, Hex %08x, Octal %o"
+msgstr "> %d, Deksesuma %08x, Okuma %o"
+
+msgid "E134: Move lines into themselves"
+msgstr "E134: Movas liniojn en ilin mem"
+
+#, c-format
+msgid "%ld line moved"
+msgid_plural "%ld lines moved"
+msgstr[0] "%ld linio movita"
+msgstr[1] "%ld linioj movitaj"
+
+#, c-format
+msgid "%ld lines filtered"
+msgstr "%ld linioj filtritaj"
+
+msgid "E135: *Filter* Autocommands must not change current buffer"
+msgstr "E135: *Filtraj* AÅ­tokomandoj ne rajtas ÅanÄi aktualan bufron"
+
+msgid "[No write since last change]\n"
+msgstr "[Neniu skribo de post lasta ÅanÄo]\n"
+
+#, c-format
+msgid "%sviminfo: %s in line: "
+msgstr "%sviminfo: %s en linio: "
+
+msgid "E136: viminfo: Too many errors, skipping rest of file"
+msgstr "E136: viminfo: Tro da eraroj, nun ignoras la reston de la dosiero"
+
+#, c-format
+msgid "Reading viminfo file \"%s\"%s%s%s"
+msgstr "Legado de dosiero viminfo \"%s\"%s%s%s"
+
+msgid " info"
+msgstr " informo"
+
+msgid " marks"
+msgstr " markoj"
+
+msgid " oldfiles"
+msgstr " malnovaj dosieroj"
+
+msgid " FAILED"
+msgstr " MALSUKCESIS"
+
+#, c-format
+msgid "E137: Viminfo file is not writable: %s"
+msgstr "E137: Dosiero viminfo ne skribeblas: %s"
+
+#, c-format
+msgid "E929: Too many viminfo temp files, like %s!"
+msgstr "E929: Tro da provizoraj dosieroj viminfo, kiel %s!"
+
+#, c-format
+msgid "E138: Can't write viminfo file %s!"
+msgstr "E138: Ne eblas skribi dosieron viminfo %s!"
+
+#, c-format
+msgid "Writing viminfo file \"%s\""
+msgstr "Skribas dosieron viminfo \"%s\""
+
+#, c-format
+msgid "E886: Can't rename viminfo file to %s!"
+msgstr "E886: Ne eblas renomi dosieron viminfo al %s!"
+
+#, c-format
+msgid "# This viminfo file was generated by Vim %s.\n"
+msgstr "# Tiu dosiero viminfo estis kreita de Vim %s.\n"
+
+msgid ""
+"# You may edit it if you're careful!\n"
+"\n"
+msgstr ""
+"# Vi povas redakti Äin se vi estas singarda.\n"
+"\n"
+
+msgid "# Value of 'encoding' when this file was written\n"
+msgstr "# Valoro de 'encoding' kiam tiu dosiero estis kreita\n"
+
+msgid "Illegal starting char"
+msgstr "Nevalida eka signo"
+
+msgid ""
+"\n"
+"# Bar lines, copied verbatim:\n"
+msgstr ""
+"\n"
+"# Linioj komencantaj per |, kopiitaj sen ÅanÄo:\n"
+
+msgid "Save As"
+msgstr "Konservi kiel"
+
+msgid "Write partial file?"
+msgstr "Ĉu skribi partan dosieron?"
+
+msgid "E140: Use ! to write partial buffer"
+msgstr "E140: Uzu ! por skribi partan bufron"
+
+#, c-format
+msgid "Overwrite existing file \"%s\"?"
+msgstr "Ĉu anstataŭigi ekzistantan dosieron \"%s\"?"
+
+#, c-format
+msgid "Swap file \"%s\" exists, overwrite anyway?"
+msgstr "Permutodosiero .swp \"%s\" ekzistas, ĉu tamen anstataÅ­igi Äin?"
+
+#, c-format
+msgid "E768: Swap file exists: %s (:silent! overrides)"
+msgstr "E768: Permutodosiero .swp ekzistas: %s (:silent! por transpasi)"
+
+#, c-format
+msgid "E141: No file name for buffer %ld"
+msgstr "E141: Neniu dosiernomo de bufro %ld"
+
+msgid "E142: File not written: Writing is disabled by 'write' option"
+msgstr "E142: Dosiero ne skribita: Skribo malÅaltita per la opcio 'write'"
+
+#, c-format
+msgid ""
+"'readonly' option is set for \"%s\".\n"
+"Do you wish to write anyway?"
+msgstr ""
+"La opcio 'readonly' estas Åaltita por \"%s\".\n"
+"Ĉu vi tamen volas skribi?"
+
+#, c-format
+msgid ""
+"File permissions of \"%s\" are read-only.\n"
+"It may still be possible to write it.\n"
+"Do you wish to try?"
+msgstr ""
+"Permesoj de dosiero \"%s\" estas nur-legeblaj.\n"
+"BonÅance Äi eble skribeblus.\n"
+"Ĉu vi volas provi?"
+
+#, c-format
+msgid "E505: \"%s\" is read-only (add ! to override)"
+msgstr "E505: \"%s\" estas nurlegebla (aldonu ! por transpasi)"
+
+msgid "Edit File"
+msgstr "Redakti dosieron"
+
+#, c-format
+msgid "E143: Autocommands unexpectedly deleted new buffer %s"
+msgstr "E143: AÅ­tokomandoj neatendite forviÅis novan bufron %s"
+
+msgid "E144: non-numeric argument to :z"
+msgstr "E144: nenumera argumento de :z"
+
+msgid "E145: Shell commands not allowed in rvim"
+msgstr "E145: Åœelkomandoj nepermeseblaj en rvim"
+
+msgid "E146: Regular expressions can't be delimited by letters"
+msgstr "E146: Ne eblas limigi regulesprimon per literoj"
+
+#, c-format
+msgid "replace with %s (y/n/a/q/l/^E/^Y)?"
+msgstr "ĉu anstataŭigi per %s (y/n/a/q/l/^E/^Y)?"
+
+msgid "(Interrupted) "
+msgstr "(Interrompita) "
+
+#, c-format
+msgid "%ld match on %ld line"
+msgid_plural "%ld matches on %ld line"
+msgstr[0] "%ld kongruo en %ld linio"
+msgstr[1] "%ld kongruoj en %ld linio"
+
+#, c-format
+msgid "%ld substitution on %ld line"
+msgid_plural "%ld substitutions on %ld line"
+msgstr[0] "%ld anstataÅ­igo en %ld linio"
+msgstr[1] "%ld anstataÅ­igoj en %ld linio"
+
+#, c-format
+msgid "%ld match on %ld lines"
+msgid_plural "%ld matches on %ld lines"
+msgstr[0] "%ld kongruo en %ld linioj"
+msgstr[1] "%ld kongruoj en %ld linioj"
+
+#, c-format
+msgid "%ld substitution on %ld lines"
+msgid_plural "%ld substitutions on %ld lines"
+msgstr[0] "%ld anstataÅ­igo en %ld linioj"
+msgstr[1] "%ld anstataÅ­igoj en %ld linioj"
+
+msgid "E147: Cannot do :global recursive with a range"
+msgstr "E147: Ne eblas fari \":global\" rekursie kun amplekso"
+
+# DP: global estas por ":global" do mi ne tradukis Äin
+msgid "E148: Regular expression missing from global"
+msgstr "E148: Regulesprimo mankas el global"
+
+#, c-format
+msgid "Pattern found in every line: %s"
+msgstr "Ŝablono trovita en ĉiuj linioj: %s"
+
+#, c-format
+msgid "Pattern not found: %s"
+msgstr "Åœablono ne trovita: %s"
+
+msgid ""
+"\n"
+"# Last Substitute String:\n"
+"$"
+msgstr ""
+"\n"
+"# Lasta anstataŭigita ĉeno:\n"
+"$"
+
+# This message should *so* be E42!
+msgid "E478: Don't panic!"
+msgstr "E478: Ne paniku!"
+
+#, c-format
+msgid "E661: Sorry, no '%s' help for %s"
+msgstr "E661: BedaÅ­rinde estas neniu helpo '%s' por %s"
+
+#, c-format
+msgid "E149: Sorry, no help for %s"
+msgstr "E149: BedaÅ­rinde estas neniu helpo por %s"
+
+#, c-format
+msgid "Sorry, help file \"%s\" not found"
+msgstr "BedaÅ­rinde, la helpdosiero \"%s\" ne troveblas"
+
+#, c-format
+msgid "E151: No match: %s"
+msgstr "E151: Neniu kongruo: %s"
+
+#, c-format
+msgid "E152: Cannot open %s for writing"
+msgstr "E152: Ne eblas malfermi %s en skribreÄimo"
+
+#, c-format
+msgid "E153: Unable to open %s for reading"
+msgstr "E153: Ne eblas malfermi %s en legreÄimo"
+
+#, c-format
+msgid "E670: Mix of help file encodings within a language: %s"
+msgstr "E670: Miksaĵo de kodoprezento de helpa dosiero en lingvo: %s"
+
+#, c-format
+msgid "E154: Duplicate tag \"%s\" in file %s/%s"
+msgstr "E154: Ripetita etikedo \"%s\" en dosiero %s/%s"
+
+#, c-format
+msgid "E150: Not a directory: %s"
+msgstr "E150: Ne estas dosierujo: %s"
+
+#, c-format
+msgid "E160: Unknown sign command: %s"
+msgstr "E160: Nekonata simbola komando: %s"
+
+msgid "E156: Missing sign name"
+msgstr "E156: Mankas nomo de simbolo"
+
+msgid "E612: Too many signs defined"
+msgstr "E612: Tro da simboloj estas difinitaj"
+
+#, c-format
+msgid "E239: Invalid sign text: %s"
+msgstr "E239: Nevalida teksto de simbolo: %s"
+
+#, c-format
+msgid "E155: Unknown sign: %s"
+msgstr "E155: Nekonata simbolo: %s"
+
+msgid "E159: Missing sign number"
+msgstr "E159: Mankas numero de simbolo"
+
+#, c-format
+msgid "E158: Invalid buffer name: %s"
+msgstr "E158: Nevalida nomo de bufro: %s"
+
+msgid "E934: Cannot jump to a buffer that does not have a name"
+msgstr "E934: Ne eblas salti al sennoma bufro"
+
+#, c-format
+msgid "E157: Invalid sign ID: %ld"
+msgstr "E157: Nevalida identigilo de simbolo: %ld"
+
+#, c-format
+msgid "E885: Not possible to change sign %s"
+msgstr "E885: Ne eblas ÅanÄi simbolon %s"
+
+msgid " (NOT FOUND)"
+msgstr " (NETROVITA)"
+
+msgid " (not supported)"
+msgstr " (nesubtenata)"
+
+msgid "[Deleted]"
+msgstr "[ForviÅita]"
+
+msgid "No old files"
+msgstr "Neniu malnova dosiero"
+
+msgid "Entering Debug mode. Type \"cont\" to continue."
+msgstr "Eniras sencimigan reÄimon. Tajpu \"cont\" por daÅ­rigi."
+
+#, c-format
+msgid "Oldval = \"%s\""
+msgstr "Malnovaval = \"%s\""
+
+#, c-format
+msgid "Newval = \"%s\""
+msgstr "Novaval = \"%s\""
+
+#, c-format
+msgid "line %ld: %s"
+msgstr "linio %ld: %s"
+
+#, c-format
+msgid "cmd: %s"
+msgstr "kmd: %s"
+
+msgid "frame is zero"
+msgstr "kadro estas nul"
+
+#, c-format
+msgid "frame at highest level: %d"
+msgstr "kadro je la plej alta nivelo: %d"
+
+#, c-format
+msgid "Breakpoint in \"%s%s\" line %ld"
+msgstr "Kontrolpunkto en \"%s%s\" linio %ld"
+
+#, c-format
+msgid "E161: Breakpoint not found: %s"
+msgstr "E161: Kontrolpunkto ne trovita: %s"
+
+msgid "No breakpoints defined"
+msgstr "Neniu kontrolpunkto estas difinita"
+
+#, c-format
+msgid "%3d %s %s line %ld"
+msgstr "%3d %s %s linio %ld"
+
+#, c-format
+msgid "%3d expr %s"
+msgstr "%3d espr %s"
+
+msgid "E750: First use \":profile start {fname}\""
+msgstr "E750: Uzu unue \":profile start {dosiernomo}\""
+
+#, c-format
+msgid "Save changes to \"%s\"?"
+msgstr "Ĉu konservi ÅanÄojn al \"%s\"?"
+
+#, c-format
+msgid "E947: Job still running in buffer \"%s\""
+msgstr "E947: Tasko ankoraÅ­ aktiva en la bufro \"%s\""
+
+#, c-format
+msgid "E162: No write since last change for buffer \"%s\""
+msgstr "E162: Neniu skribo de post la lasta ÅanÄo por bufro \"%s\""
+
+msgid "Warning: Entered other buffer unexpectedly (check autocommands)"
+msgstr "Averto: Eniris neatendite alian bufron (kontrolu aÅ­tokomandojn)"
+
+msgid "E163: There is only one file to edit"
+msgstr "E163: Estas nur unu redaktenda dosiero"
+
+msgid "E164: Cannot go before first file"
+msgstr "E164: Ne eblas iri antaÅ­ ol la unuan dosieron"
+
+msgid "E165: Cannot go beyond last file"
+msgstr "E165: Ne eblas iri preter la lastan dosieron"
+
+#, c-format
+msgid "E666: compiler not supported: %s"
+msgstr "E666: kompililo nesubtenata: %s"
+
+#, c-format
+msgid "Searching for \"%s\" in \"%s\""
+msgstr "Serĉado de \"%s\" en \"%s\""
+
+#, c-format
+msgid "Searching for \"%s\""
+msgstr "Serĉado de \"%s\""
+
+#, c-format
+msgid "not found in '%s': \"%s\""
+msgstr "ne trovita en '%s: \"%s\""
+
+#, c-format
+msgid "W20: Required python version 2.x not supported, ignoring file: %s"
+msgstr "W20: Pitono versio 2.x bezonata sed nesubtenata, ignoro de dosiero: %s"
+
+#, c-format
+msgid "W21: Required python version 3.x not supported, ignoring file: %s"
+msgstr "W21: pitono versio 3.x bezonata sed nesubtenata, ignoro de dosiero: %s"
+
+msgid "Source Vim script"
+msgstr "Ruli Vim-skripton"
+
+#, c-format
+msgid "Cannot source a directory: \"%s\""
+msgstr "Ne eblas ruli dosierujon: \"%s\""
+
+#, c-format
+msgid "could not source \"%s\""
+msgstr "ne eblis ruli \"%s\""
+
+#, c-format
+msgid "line %ld: could not source \"%s\""
+msgstr "linio %ld: ne eblis ruli \"%s\""
+
+#, c-format
+msgid "sourcing \"%s\""
+msgstr "rulas \"%s\""
+
+#, c-format
+msgid "line %ld: sourcing \"%s\""
+msgstr "linio %ld: rulas \"%s\""
+
+#, c-format
+msgid "finished sourcing %s"
+msgstr "finis ruli %s"
+
+#, c-format
+msgid "continuing in %s"
+msgstr "daÅ­rigas en %s"
+
+msgid "modeline"
+msgstr "reÄimlinio"
+
+msgid "--cmd argument"
+msgstr "--cmd argumento"
+
+msgid "-c argument"
+msgstr "-c argumento"
+
+msgid "environment variable"
+msgstr "medivariablo"
+
+msgid "error handler"
+msgstr "erartraktilo"
+
+msgid "W15: Warning: Wrong line separator, ^M may be missing"
+msgstr "W15: Averto: NeÄusta disigilo de linio, ^M eble mankas"
+
+msgid "E167: :scriptencoding used outside of a sourced file"
+msgstr "E167: \":scriptencoding\" uzita ekster rulita dosiero"
+
+msgid "E168: :finish used outside of a sourced file"
+msgstr "E168: \":finish\" uzita ekster rulita dosiero"
+
+#, c-format
+msgid "Current %slanguage: \"%s\""
+msgstr "Aktuala %slingvo: \"%s\""
+
+#, c-format
+msgid "E197: Cannot set language to \"%s\""
+msgstr "E197: Ne eblas ÅanÄi la lingvon al \"%s\""
+
+msgid "Entering Ex mode. Type \"visual\" to go to Normal mode."
+msgstr "Eniras reÄimon Ex. Tajpu \"visual\" por iri al reÄimo Normala."
+
+msgid "E501: At end-of-file"
+msgstr "E501: Ĉe fino-de-dosiero"
+
+msgid "E169: Command too recursive"
+msgstr "E169: Komando tro rekursia"
+
+#, c-format
+msgid "E605: Exception not caught: %s"
+msgstr "E605: Escepto nekaptita: %s"
+
+msgid "End of sourced file"
+msgstr "Fino de rulita dosiero"
+
+msgid "End of function"
+msgstr "Fino de funkcio"
+
+msgid "E464: Ambiguous use of user-defined command"
+msgstr "E464: Ambigua uzo de komando difinita de uzanto"
+
+msgid "E492: Not an editor command"
+msgstr "E492: Ne estas redaktila komando"
+
+msgid "E493: Backwards range given"
+msgstr "E493: Inversa amplekso donita"
+
+msgid "Backwards range given, OK to swap"
+msgstr "Inversa amplekso donita, permuteblas"
+
+msgid "E494: Use w or w>>"
+msgstr "E494: Uzu w aÅ­ w>>"
+
+msgid "E943: Command table needs to be updated, run 'make cmdidxs'"
+msgstr "E943: Tabulo de komandoj estas Äisdatigenda, lanĉu 'make cmdidx'"
+
+msgid "E319: Sorry, the command is not available in this version"
+msgstr "E319: BedaÅ­rinde, tiu komando ne haveblas en tiu versio"
+
+#, c-format
+msgid "%d more file to edit. Quit anyway?"
+msgid_plural "%d more files to edit. Quit anyway?"
+msgstr[0] "%d plia redaktenda dosiero. Ĉu tamen eliri?"
+msgstr[1] "%d pliaj redaktendaj dosieroj. Ĉu tamen eliri?"
+
+#, c-format
+msgid "E173: %ld more file to edit"
+msgid_plural "E173: %ld more files to edit"
+msgstr[0] "E173: %ld plia redaktenda dosiero"
+msgstr[1] "E173: %ld pliaj redaktendaj dosieroj"
+
+msgid "E174: Command already exists: add ! to replace it"
+msgstr "E174: La komando jam ekzistas: aldonu ! por anstataÅ­igi Äin"
+
+msgid ""
+"\n"
+" Name Args Address Complete Definition"
+msgstr ""
+"\n"
+" Nomo Argumentoj Adreso Kompleto Difino"
+
+msgid "No user-defined commands found"
+msgstr "Neniu komando difinita de uzanto trovita"
+
+msgid "E175: No attribute specified"
+msgstr "E175: Neniu atributo specifita"
+
+msgid "E176: Invalid number of arguments"
+msgstr "E176: Nevalida nombro de argumentoj"
+
+msgid "E177: Count cannot be specified twice"
+msgstr "E177: Kvantoro ne povas aperi dufoje"
+
+msgid "E178: Invalid default value for count"
+msgstr "E178: Nevalida defaÅ­lta valoro de kvantoro"
+
+msgid "E179: argument required for -complete"
+msgstr "E179: argumento bezonata por -complete"
+
+msgid "E179: argument required for -addr"
+msgstr "E179: argumento bezonata por -addr"
+
+#, c-format
+msgid "E181: Invalid attribute: %s"
+msgstr "E181: Nevalida atributo: %s"
+
+msgid "E182: Invalid command name"
+msgstr "E182: Nevalida komanda nomo"
+
+msgid "E183: User defined commands must start with an uppercase letter"
+msgstr "E183: Komandoj difinataj de uzanto devas eki per majusklo"
+
+msgid "E841: Reserved name, cannot be used for user defined command"
+msgstr "E841: Rezervita nomo, neuzebla por komando difinita de uzanto"
+
+#, c-format
+msgid "E184: No such user-defined command: %s"
+msgstr "E184: Neniu komando-difinita-de-uzanto kiel: %s"
+
+#, c-format
+msgid "E180: Invalid address type value: %s"
+msgstr "E180: Nevalida valoro de tipo de adreso: %s"
+
+#, c-format
+msgid "E180: Invalid complete value: %s"
+msgstr "E180: Nevalida valoro de kompletigo: %s"
+
+msgid "E468: Completion argument only allowed for custom completion"
+msgstr ""
+"E468: Argumento de kompletigo nur permesebla por kompletigo difinita de "
+"uzanto"
+
+msgid "E467: Custom completion requires a function argument"
+msgstr "E467: Uzula kompletigo bezonas funkcian argumenton"
+
+msgid "unknown"
+msgstr "nekonata"
+
+#, c-format
+msgid "E185: Cannot find color scheme '%s'"
+msgstr "E185: Ne eblas trovi agordaron de koloroj '%s'"
+
+msgid "Greetings, Vim user!"
+msgstr "Bonvenon, uzanto de Vim!"
+
+msgid "E784: Cannot close last tab page"
+msgstr "E784: Ne eblas fermi lastan langeton"
+
+msgid "Already only one tab page"
+msgstr "Jam nur unu langeto"
+
+msgid "Edit File in new tab page"
+msgstr "Redakti Dosieron en nova langeto"
+
+msgid "Edit File in new window"
+msgstr "Redakti Dosieron en nova fenestro"
+
+#, c-format
+msgid "Tab page %d"
+msgstr "Langeto %d"
+
+msgid "No swap file"
+msgstr "Neniu permutodosiero .swp"
+
+msgid "Append File"
+msgstr "Postaldoni dosieron"
+
+msgid "E747: Cannot change directory, buffer is modified (add ! to override)"
+msgstr ""
+"E747: Ne eblas ÅanÄi dosierujon, bufro estas ÅanÄita (aldonu ! por transpasi)"
+
+msgid "E186: No previous directory"
+msgstr "E186: Neniu antaÅ­a dosierujo"
+
+msgid "E187: Unknown"
+msgstr "E187: Nekonata"
+
+msgid "E465: :winsize requires two number arguments"
+msgstr "E465: \":winsize\" bezonas du numerajn argumentojn"
+
+#, c-format
+msgid "Window position: X %d, Y %d"
+msgstr "Pozicio de fenestro: X %d, Y %d"
+
+msgid "E188: Obtaining window position not implemented for this platform"
+msgstr ""
+"E188: Akiro de pozicio de fenestro ne estas realigita por tiu platformo"
+
+msgid "E466: :winpos requires two number arguments"
+msgstr "E466: \":winpos\" bezonas du numerajn argumentojn"
+
+msgid "E930: Cannot use :redir inside execute()"
+msgstr "E930: Ne eblas uzi :redir en execute()"
+
+msgid "Save Redirection"
+msgstr "Konservi alidirekton"
+
+# DP: mi ne certas pri superflugo
+msgid "Save View"
+msgstr "Konservi superflugon"
+
+msgid "Save Session"
+msgstr "Konservi seancon"
+
+msgid "Save Setup"
+msgstr "Konservi agordaron"
+
+#, c-format
+msgid "E739: Cannot create directory: %s"
+msgstr "E739: Ne eblas krei dosierujon %s"
+
+#, c-format
+msgid "E189: \"%s\" exists (add ! to override)"
+msgstr "E189: \"%s\" ekzistas (aldonu ! por transpasi)"
+
+#, c-format
+msgid "E190: Cannot open \"%s\" for writing"
+msgstr "E190: Ne eblas malfermi \"%s\" por skribi"
+
+msgid "E191: Argument must be a letter or forward/backward quote"
+msgstr "E191: Argumento devas esti litero, citilo aÅ­ retrocitilo"
+
+msgid "E192: Recursive use of :normal too deep"
+msgstr "E192: Tro profunda rekursia alvoko de \":normal\""
+
+msgid "E809: #< is not available without the +eval feature"
+msgstr "E809: #< ne haveblas sen la eblo +eval"
+
+msgid "E194: No alternate file name to substitute for '#'"
+msgstr "E194: Neniu alterna dosiernomo por anstataÅ­igi al '#'"
+
+msgid "E495: no autocommand file name to substitute for \"<afile>\""
+msgstr "E495: neniu dosiernomo de aÅ­tokomando por anstataÅ­igi al \"<afile>\""
+
+msgid "E496: no autocommand buffer number to substitute for \"<abuf>\""
+msgstr ""
+"E496: neniu numero de bufro de aÅ­tokomando por anstataÅ­igi al \"<abuf>\""
+
+# DP: ĉu match estas verbo aŭ nomo en la angla version?
+# AM: ĉi tie, nomo, Åajnas al mi
+msgid "E497: no autocommand match name to substitute for \"<amatch>\""
+msgstr ""
+"E497: neniu nomo de kongruo de aÅ­tokomando por anstataÅ­igi al \"<amatch>\""
+
+msgid "E498: no :source file name to substitute for \"<sfile>\""
+msgstr "E498: neniu dosiernomo \":source\" por anstataÅ­igi al \"<sfile>\""
+
+msgid "E842: no line number to use for \"<slnum>\""
+msgstr "E842: neniu uzebla numero de linio por \"<slnum>\""
+
+msgid "E961: no line number to use for \"<sflnum>\""
+msgstr "E961: neniu uzebla numero de linio por \"<sflnum>\""
+
+#, no-c-format
+msgid "E499: Empty file name for '%' or '#', only works with \":p:h\""
+msgstr "E499: Malplena dosiernomo por '%' aÅ­ '#', nur funkcias kun \":p:h\""
+
+msgid "E500: Evaluates to an empty string"
+msgstr "E500: Liveras malplenan ĉenon"
+
+msgid "E195: Cannot open viminfo file for reading"
+msgstr "E195: Ne eblas malfermi dosieron viminfo en lega reÄimo"
+
+msgid "Untitled"
+msgstr "Sen titolo"
+
+msgid "E196: No digraphs in this version"
+msgstr "E196: Neniu duliteraĵo en tiu versio"
+
+msgid "E608: Cannot :throw exceptions with 'Vim' prefix"
+msgstr "E608: Ne eblas lanĉi (:throw) escepton kun prefikso 'Vim'"
+
+#, c-format
+msgid "Exception thrown: %s"
+msgstr "Escepto lanĉita: %s"
+
+#, c-format
+msgid "Exception finished: %s"
+msgstr "Escepto finiÄis: %s"
+
+#, c-format
+msgid "Exception discarded: %s"
+msgstr "Escepto ne konservita: %s"
+
+#, c-format
+msgid "%s, line %ld"
+msgstr "%s, linio %ld"
+
+#, c-format
+msgid "Exception caught: %s"
+msgstr "Kaptis escepton: %s"
+
+#, c-format
+msgid "%s made pending"
+msgstr "%s iÄis atendanta(j)"
+
+#, c-format
+msgid "%s resumed"
+msgstr "%s daÅ­rigita(j)"
+
+#, c-format
+msgid "%s discarded"
+msgstr "%s ne konservita(j)"
+
+msgid "Exception"
+msgstr "Escepto"
+
+msgid "Error and interrupt"
+msgstr "Eraro kaj interrompo"
+
+msgid "Error"
+msgstr "Eraro"
+
+msgid "Interrupt"
+msgstr "Interrompo"
+
+msgid "E579: :if nesting too deep"
+msgstr "E579: \":if\" tro profunde ingita"
+
+msgid "E580: :endif without :if"
+msgstr "E580: \":endif\" sen \":if\""
+
+msgid "E581: :else without :if"
+msgstr "E581: \":else\" sen \":if\""
+
+msgid "E582: :elseif without :if"
+msgstr "E582: \":elseif\" sen \":if\""
+
+msgid "E583: multiple :else"
+msgstr "E583: pluraj \":else\""
+
+msgid "E584: :elseif after :else"
+msgstr "E584: \":elseif\" malantaÅ­ \":else\""
+
+msgid "E585: :while/:for nesting too deep"
+msgstr "E585: \":while/:for\" ingita tro profunde"
+
+msgid "E586: :continue without :while or :for"
+msgstr "E586: \":continue\" sen \":while\" aÅ­ \":for\""
+
+msgid "E587: :break without :while or :for"
+msgstr "E587: \":break\" sen \":while\" aÅ­ \":for\""
+
+msgid "E732: Using :endfor with :while"
+msgstr "E732: Uzo de \":endfor\" kun \":while\""
+
+msgid "E733: Using :endwhile with :for"
+msgstr "E733: Uzo de \":endwhile\" kun \":for\""
+
+msgid "E601: :try nesting too deep"
+msgstr "E601: \":try\" ingita tro profunde"
+
+msgid "E603: :catch without :try"
+msgstr "E603: \":catch\" sen \":try\""
+
+msgid "E604: :catch after :finally"
+msgstr "E604: \":catch\" malantaÅ­ \":finally\""
+
+msgid "E606: :finally without :try"
+msgstr "E606: \":finally\" sen \":try\""
+
+msgid "E607: multiple :finally"
+msgstr "E607: pluraj \":finally\""
+
+msgid "E602: :endtry without :try"
+msgstr "E602: \":endtry\" sen \":try\""
+
+msgid "E193: :endfunction not inside a function"
+msgstr "E193: \":endfunction\" ekster funkcio"
+
+msgid "E788: Not allowed to edit another buffer now"
+msgstr "E788: Ne eblas redakti alian bufron nun"
+
+msgid "E811: Not allowed to change buffer information now"
+msgstr "E811: Ne eblas ÅanÄi informon de bufro nun"
+
+msgid "tagname"
+msgstr "nomo de etikedo"
+
+msgid " kind file\n"
+msgstr " tipo de dosiero\n"
+
+msgid "'history' option is zero"
+msgstr "opcio 'history' estas nul"
+
+#, c-format
+msgid ""
+"\n"
+"# %s History (newest to oldest):\n"
+msgstr ""
+"\n"
+"# Historio %s (de plej nova al plej malnova):\n"
+
+msgid "Command Line"
+msgstr "Komanda linio"
+
+msgid "Search String"
+msgstr "Serĉa ĉeno"
+
+msgid "Expression"
+msgstr "Esprimo"
+
+msgid "Input Line"
+msgstr "Eniga linio"
+
+msgid "Debug Line"
+msgstr "Sencimiga linio"
+
+msgid "E198: cmd_pchar beyond the command length"
+msgstr "E198: cmd_pchar preter la longo de komando"
+
+msgid "E199: Active window or buffer deleted"
+msgstr "E199: Aktiva fenestro aÅ­ bufro forviÅita"
+
+msgid "E812: Autocommands changed buffer or buffer name"
+msgstr "E812: AÅ­tokomandoj ÅanÄis bufron aÅ­ nomon de bufro"
+
+msgid "Illegal file name"
+msgstr "Nevalida dosiernomo"
+
+msgid "is a directory"
+msgstr "estas dosierujo"
+
+msgid "is not a file"
+msgstr "ne estas dosiero"
+
+msgid "is a device (disabled with 'opendevice' option)"
+msgstr "estas aparatdosiero (malÅaltita per la opcio 'opendevice')"
+
+msgid "[New File]"
+msgstr "[Nova dosiero]"
+
+msgid "[New DIRECTORY]"
+msgstr "[Nova DOSIERUJO]"
+
+msgid "[File too big]"
+msgstr "[Dosiero tro granda]"
+
+msgid "[Permission Denied]"
+msgstr "[Permeso rifuzita]"
+
+msgid "E200: *ReadPre autocommands made the file unreadable"
+msgstr "E200: La aÅ­tokomandoj *ReadPre igis la dosieron nelegebla"
+
+msgid "E201: *ReadPre autocommands must not change current buffer"
+msgstr "E201: La aÅ­tokomandoj *ReadPre ne rajtas ÅanÄi la aktualan bufron"
+
+msgid "Vim: Reading from stdin...\n"
+msgstr "Vim: Legado el stdin...\n"
+
+msgid "Reading from stdin..."
+msgstr "Legado el stdin..."
+
+msgid "E202: Conversion made file unreadable!"
+msgstr "E202: Konverto igis la dosieron nelegebla!"
+
+msgid "[fifo]"
+msgstr "[rektvica memoro]"
+
+msgid "[socket]"
+msgstr "[kontaktoskatolo]"
+
+msgid "[character special]"
+msgstr "[speciala signo]"
+
+msgid "[CR missing]"
+msgstr "[CR mankas]"
+
+msgid "[long lines split]"
+msgstr "[divido de longaj linioj]"
+
+msgid "[NOT converted]"
+msgstr "[NE konvertita]"
+
+msgid "[converted]"
+msgstr "[konvertita]"
+
+#, c-format
+msgid "[CONVERSION ERROR in line %ld]"
+msgstr "[ERARO DE KONVERTO en linio %ld]"
+
+#, c-format
+msgid "[ILLEGAL BYTE in line %ld]"
+msgstr "[NEVALIDA BAJTO en linio %ld]"
+
+msgid "[READ ERRORS]"
+msgstr "[ERAROJ DE LEGADO]"
+
+msgid "Can't find temp file for conversion"
+msgstr "Ne eblas trovi provizoran dosieron por konverti"
+
+msgid "Conversion with 'charconvert' failed"
+msgstr "Konverto kun 'charconvert' malsukcesis"
+
+msgid "can't read output of 'charconvert'"
+msgstr "ne eblas legi la eligon de 'charconvert'"
+
+msgid "E676: No matching autocommands for acwrite buffer"
+msgstr "E676: Neniu kongrua aÅ­tokomando por la bufro acwrite"
+
+msgid "E203: Autocommands deleted or unloaded buffer to be written"
+msgstr "E203: AÅ­tokomandoj forviÅis aÅ­ malÅargis la skribendan bufron"
+
+msgid "E204: Autocommand changed number of lines in unexpected way"
+msgstr "E204: AÅ­tokomando ÅanÄis la nombron de linioj neatendite"
+
+msgid "NetBeans disallows writes of unmodified buffers"
+msgstr "NetBeans malpermesas skribojn de neÅanÄitaj bufroj"
+
+msgid "Partial writes disallowed for NetBeans buffers"
+msgstr "Partaj skriboj malpermesitaj ĉe bufroj NetBeans"
+
+msgid "is not a file or writable device"
+msgstr "ne estas dosiero aÅ­ skribebla aparatdosiero"
+
+msgid "writing to device disabled with 'opendevice' option"
+msgstr "skribo al aparatdosiero malÅaltita per la opcio 'opendevice'"
+
+msgid "is read-only (add ! to override)"
+msgstr "estas nurlegebla (aldonu ! por transpasi)"
+
+msgid "E506: Can't write to backup file (add ! to override)"
+msgstr "E506: Ne eblas skribi restaÅ­rkopion (aldonu ! por transpasi)"
+
+msgid "E507: Close error for backup file (add ! to override)"
+msgstr "E507: Eraro dum fermo de restaÅ­rkopio (aldonu ! transpasi)"
+
+msgid "E508: Can't read file for backup (add ! to override)"
+msgstr "E508: Ne eblas legi restaÅ­rkopion (aldonu ! por transpasi)"
+
+msgid "E509: Cannot create backup file (add ! to override)"
+msgstr "E509: Ne eblas krei restaÅ­rkopion (aldonu ! por transpasi)"
+
+msgid "E510: Can't make backup file (add ! to override)"
+msgstr "E510: Ne eblas krei restaÅ­rkopion (aldonu ! por transpasi)"
+
+msgid "E214: Can't find temp file for writing"
+msgstr "E214: Ne eblas trovi provizoran dosieron por skribi"
+
+msgid "E213: Cannot convert (add ! to write without conversion)"
+msgstr "E213: Ne eblas konverti (aldonu ! por skribi sen konverto)"
+
+msgid "E166: Can't open linked file for writing"
+msgstr "E166: Ne eblas malfermi ligitan dosieron por skribi"
+
+msgid "E212: Can't open file for writing"
+msgstr "E212: Ne eblas malfermi la dosieron por skribi"
+
+msgid "E949: File changed while writing"
+msgstr "E949: Dosiero ÅanÄiÄis dum skribo"
+
+msgid "E512: Close failed"
+msgstr "E512: Fermo malsukcesis"
+
+msgid "E513: write error, conversion failed (make 'fenc' empty to override)"
+msgstr ""
+"E513: skriberaro, konverto malsukcesis (igu 'fenc' malplena por transpasi)"
+
+#, c-format
+msgid ""
+"E513: write error, conversion failed in line %ld (make 'fenc' empty to "
+"override)"
+msgstr ""
+"E513: skriberaro, konverto malsukcesis en linio %ld (igu 'fenc' malplena "
+"por transpasi)"
+
+msgid "E514: write error (file system full?)"
+msgstr "E514: skriberaro (ĉu plena dosiersistemo?)"
+
+msgid " CONVERSION ERROR"
+msgstr " ERARO DE KONVERTO"
+
+#, c-format
+msgid " in line %ld;"
+msgstr " en linio %ld;"
+
+msgid "[Device]"
+msgstr "[Aparatdosiero]"
+
+msgid "[New]"
+msgstr "[Nova]"
+
+msgid " [a]"
+msgstr " [a]"
+
+msgid " appended"
+msgstr " postaldonita(j)"
+
+msgid " [w]"
+msgstr " [s]"
+
+msgid " written"
+msgstr " skribita(j)"
+
+msgid "E205: Patchmode: can't save original file"
+msgstr "E205: Patchmode: ne eblas konservi originalan dosieron"
+
+msgid "E206: patchmode: can't touch empty original file"
+msgstr "E206: patchmode: ne eblas tuÅi malplenan originalan dosieron"
+
+msgid "E207: Can't delete backup file"
+msgstr "E207: Ne eblas forviÅi restaÅ­rkopion"
+
+msgid ""
+"\n"
+"WARNING: Original file may be lost or damaged\n"
+msgstr ""
+"\n"
+"AVERTO: Originala dosiero estas eble perdita aÅ­ difekta\n"
+
+msgid "don't quit the editor until the file is successfully written!"
+msgstr "ne eliru el la redaktilo Äis kiam la dosiero estas sukcese konservita!"
+
+msgid "[dos]"
+msgstr "[dos]"
+
+msgid "[dos format]"
+msgstr "[formato dos]"
+
+msgid "[mac]"
+msgstr "[mac]"
+
+msgid "[mac format]"
+msgstr "[formato mac]"
+
+msgid "[unix]"
+msgstr "[unikso]"
+
+msgid "[unix format]"
+msgstr "[formato unikso]"
+
+#, c-format
+msgid "%ld line, "
+msgid_plural "%ld lines, "
+msgstr[0] "%ld linio, "
+msgstr[1] "%ld linioj, "
+
+#, c-format
+msgid "%lld character"
+msgid_plural "%lld characters"
+msgstr[0] "%lld signo"
+msgstr[1] "%lld signoj"
+
+msgid "[noeol]"
+msgstr "[sen EOL]"
+
+msgid "[Incomplete last line]"
+msgstr "[Nekompleta lasta linio]"
+
+msgid "WARNING: The file has been changed since reading it!!!"
+msgstr "AVERTO: La dosiero estas ÅanÄita de post kiam Äi estis legita!!!"
+
+msgid "Do you really want to write to it"
+msgstr "Ĉu vi vere volas skribi al Äi"
+
+#, c-format
+msgid "E208: Error writing to \"%s\""
+msgstr "E208: Eraro dum skribo de \"%s\""
+
+#, c-format
+msgid "E209: Error closing \"%s\""
+msgstr "E209: Eraro dum fermo de \"%s\""
+
+#, c-format
+msgid "E210: Error reading \"%s\""
+msgstr "E210: Eraro dum lego de \"%s\""
+
+msgid "E246: FileChangedShell autocommand deleted buffer"
+msgstr "E246: AÅ­tokomando FileChangedShell forviÅis bufron"
+
+#, c-format
+msgid "E211: File \"%s\" no longer available"
+msgstr "E211: Dosiero \"%s\" ne plu haveblas"
+
+#, c-format
+msgid ""
+"W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as "
+"well"
+msgstr ""
+"W12: Averto: Dosiero \"%s\" ÅanÄiÄis kaj la bufro estis ÅanÄita ankaÅ­ en Vim"
+
+msgid "See \":help W12\" for more info."
+msgstr "Vidu \":help W12\" por pliaj informoj."
+
+#, c-format
+msgid "W11: Warning: File \"%s\" has changed since editing started"
+msgstr "W11: Averto: La dosiero \"%s\" ÅanÄiÄis ekde redakti Äin"
+
+msgid "See \":help W11\" for more info."
+msgstr "Vidu \":help W11\" por pliaj informoj."
+
+#, c-format
+msgid "W16: Warning: Mode of file \"%s\" has changed since editing started"
+msgstr "W16: Averto: Permeso de dosiero \"%s\" ÅanÄiÄis ekde redakti Äin"
+
+msgid "See \":help W16\" for more info."
+msgstr "Vidu \":help W16\" por pliaj informoj."
+
+#, c-format
+msgid "W13: Warning: File \"%s\" has been created after editing started"
+msgstr "W13: Averto: Dosiero \"%s\" kreiÄis post la komenco de redaktado"
+
+msgid "Warning"
+msgstr "Averto"
+
+msgid ""
+"&OK\n"
+"&Load File"
+msgstr ""
+"&Bone\n"
+"Ŝ&argi Dosieron"
+
+#, c-format
+msgid "E462: Could not prepare for reloading \"%s\""
+msgstr "E462: Ne eblis prepari por reÅargi \"%s\""
+
+#, c-format
+msgid "E321: Could not reload \"%s\""
+msgstr "E321: Ne eblis reÅargi \"%s\""
+
+msgid "--Deleted--"
+msgstr "--ForviÅita--"
+
+#, c-format
+msgid "auto-removing autocommand: %s <buffer=%d>"
+msgstr "aÅ­to-forviÅas aÅ­tokomandon: %s <bufro=%d>"
+
+#, c-format
+msgid "E367: No such group: \"%s\""
+msgstr "E367: Ne ekzistas tia grupo: \"%s\""
+
+msgid "E936: Cannot delete the current group"
+msgstr "E936: Ne eblas forviÅi la aktualan grupon"
+
+msgid "W19: Deleting augroup that is still in use"
+msgstr "W19: ForviÅo de augroup kiu estas ankoraÅ­ uzata"
+
+#, c-format
+msgid "E215: Illegal character after *: %s"
+msgstr "E215: Nevalida signo malantaÅ­ *: %s"
+
+#, c-format
+msgid "E216: No such event: %s"
+msgstr "E216: Ne estas tia evento: %s"
+
+#, c-format
+msgid "E216: No such group or event: %s"
+msgstr "E216: Ne ekzistas tia grupo aÅ­ evento: %s"
+
+msgid ""
+"\n"
+"--- Autocommands ---"
+msgstr ""
+"\n"
+"--- AÅ­to-Komandoj ---"
+
+#, c-format
+msgid "E680: <buffer=%d>: invalid buffer number "
+msgstr "E680: <bufro=%d>: nevalida numero de bufro "
+
+msgid "E217: Can't execute autocommands for ALL events"
+msgstr "E217: Ne eblas plenumi aŭtokomandojn por ĈIUJ eventoj"
+
+msgid "No matching autocommands"
+msgstr "Neniu kongrua aÅ­tokomando"
+
+msgid "E218: autocommand nesting too deep"
+msgstr "E218: aÅ­tokomando tro ingita"
+
+#, c-format
+msgid "%s Autocommands for \"%s\""
+msgstr "%s AÅ­tokomandoj por \"%s\""
+
+#, c-format
+msgid "Executing %s"
+msgstr "Plenumado de %s"
+
+#, c-format
+msgid "autocommand %s"
+msgstr "aÅ­tokomando %s"
+
+msgid "E219: Missing {."
+msgstr "E219: Mankas {."
+
+msgid "E220: Missing }."
+msgstr "E220: Mankas }."
+
+msgid "E490: No fold found"
+msgstr "E490: Neniu faldo trovita"
+
+msgid "E350: Cannot create fold with current 'foldmethod'"
+msgstr "E350: Ne eblas krei faldon per la aktuala 'foldmethod'"
+
+msgid "E351: Cannot delete fold with current 'foldmethod'"
+msgstr "E351: Ne eblas forviÅi faldon per la aktuala 'foldmethod'"
+
+#, c-format
+msgid "+--%3ld line folded "
+msgid_plural "+--%3ld lines folded "
+msgstr[0] "+--%3ld linio faldita"
+msgstr[1] "+--%3ld linioj falditaj"
+
+msgid "E222: Add to read buffer"
+msgstr "E222: Aldoni al lega bufro"
+
+msgid "E223: recursive mapping"
+msgstr "E223: rikura mapo"
+
+#, c-format
+msgid "E224: global abbreviation already exists for %s"
+msgstr "E224: malloka mallongigo jam ekzistas por %s"
+
+#, c-format
+msgid "E225: global mapping already exists for %s"
+msgstr "E225: malloka mapo jam ekzistas por %s"
+
+#, c-format
+msgid "E226: abbreviation already exists for %s"
+msgstr "E226: mallongigo jam ekzistas por %s"
+
+#, c-format
+msgid "E227: mapping already exists for %s"
+msgstr "E227: mapo jam ekzistas por %s"
+
+msgid "No abbreviation found"
+msgstr "Neniu mallongigo trovita"
+
+msgid "No mapping found"
+msgstr "Neniu mapo trovita"
+
+msgid "E228: makemap: Illegal mode"
+msgstr "E228: makemap: Nevalida reÄimo"
+
+msgid "E851: Failed to create a new process for the GUI"
+msgstr "E851: Malsukcesis krei novan procezon por la grafika interfaco"
+
+msgid "E852: The child process failed to start the GUI"
+msgstr "E852: La ida procezo malsukcesis startigi la grafikan interfacon"
+
+msgid "E229: Cannot start the GUI"
+msgstr "E229: Ne eblas lanĉi la grafikan interfacon"
+
+#, c-format
+msgid "E230: Cannot read from \"%s\""
+msgstr "E230: Ne eblas legi el \"%s\""
+
+msgid "E665: Cannot start GUI, no valid font found"
+msgstr ""
+"E665: Ne eblas startigi grafikan interfacon, neniu valida tiparo trovita"
+
+msgid "E231: 'guifontwide' invalid"
+msgstr "E231: 'guifontwide' nevalida"
+
+msgid "E599: Value of 'imactivatekey' is invalid"
+msgstr "E599: Valoro de 'imactivatekey' estas nevalida"
+
+#, c-format
+msgid "E254: Cannot allocate color %s"
+msgstr "E254: Ne eblas disponigi koloron %s"
+
+msgid "No match at cursor, finding next"
+msgstr "Neniu kongruo ĉe kursorpozicio, trovas sekvan"
+
+msgid "<cannot open> "
+msgstr "<ne eblas malfermi> "
+
+#, c-format
+msgid "E616: vim_SelFile: can't get font %s"
+msgstr "E616: vim_SelFile: ne eblas akiri tiparon %s"
+
+msgid "E614: vim_SelFile: can't return to current directory"
+msgstr "E614: vim_SelFile: ne eblas reveni al la aktuala dosierujo"
+
+msgid "Pathname:"
+msgstr "Serĉvojo:"
+
+msgid "E615: vim_SelFile: can't get current directory"
+msgstr "E615: vim_SelFile: ne eblas akiri aktualan dosierujon"
+
+msgid "OK"
+msgstr "Bone"
+
+msgid "Cancel"
+msgstr "Rezigni"
+
+msgid "Scrollbar Widget: Could not get geometry of thumb pixmap."
+msgstr ""
+"Fenestraĵo de rulumskalo: Ne eblis akiri geometrion de reduktita rastrumbildo"
+
+msgid "Vim dialog"
+msgstr "Vim dialogo"
+
+msgid "E232: Cannot create BalloonEval with both message and callback"
+msgstr "E232: Ne eblas krei BalloonEval kun ambaÅ­ mesaÄo kaj reagfunkcio"
+
+msgid "_Cancel"
+msgstr "_Rezigni"
+
+msgid "_Save"
+msgstr "_Konservi"
+
+msgid "_Open"
+msgstr "_Malfermi"
+
+msgid "_OK"
+msgstr "_Bone"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"&Cancel"
+msgstr ""
+"&Jes\n"
+"&Ne\n"
+"&Rezigni"
+
+msgid "Yes"
+msgstr "Jes"
+
+msgid "No"
+msgstr "Ne"
+
+# todo '_' is for hotkey, i guess?
+msgid "Input _Methods"
+msgstr "Enigaj _metodoj"
+
+msgid "VIM - Search and Replace..."
+msgstr "VIM - Serĉi kaj anstataŭigi..."
+
+msgid "VIM - Search..."
+msgstr "VIM- Serĉi..."
+
+msgid "Find what:"
+msgstr "Serĉi kion:"
+
+msgid "Replace with:"
+msgstr "AnstataÅ­igi per:"
+
+msgid "Match whole word only"
+msgstr "Kongrui kun nur plena vorto"
+
+msgid "Match case"
+msgstr "Uskleca kongruo"
+
+msgid "Direction"
+msgstr "Direkto"
+
+msgid "Up"
+msgstr "Supren"
+
+msgid "Down"
+msgstr "Suben"
+
+msgid "Find Next"
+msgstr "Trovi sekvantan"
+
+msgid "Replace"
+msgstr "AnstataÅ­igi"
+
+msgid "Replace All"
+msgstr "Anstataŭigi ĉiujn"
+
+msgid "_Close"
+msgstr "_Fermi"
+
+msgid "Vim: Received \"die\" request from session manager\n"
+msgstr "Vim: Ricevis peton \"die\" (morti) el la seanca administrilo\n"
+
+msgid "Close tab"
+msgstr "Fermi langeton"
+
+msgid "New tab"
+msgstr "Nova langeto"
+
+msgid "Open Tab..."
+msgstr "Malfermi langeton..."
+
+msgid "Vim: Main window unexpectedly destroyed\n"
+msgstr "Vim: Ĉefa fenestro neatendite detruiÄis\n"
+
+msgid "&Filter"
+msgstr "&Filtri"
+
+msgid "&Cancel"
+msgstr "&Rezigni"
+
+msgid "Directories"
+msgstr "Dosierujoj"
+
+msgid "Filter"
+msgstr "Filtri"
+
+msgid "&Help"
+msgstr "&Helpo"
+
+msgid "Files"
+msgstr "Dosieroj"
+
+msgid "&OK"
+msgstr "&Bone"
+
+msgid "Selection"
+msgstr "Apartigo"
+
+msgid "Find &Next"
+msgstr "Trovi &Sekvanta"
+
+msgid "&Replace"
+msgstr "&AnstataÅ­igi"
+
+msgid "Replace &All"
+msgstr "Anstataŭigi ĉi&on"
+
+msgid "&Undo"
+msgstr "&Malfari"
+
+msgid "Open tab..."
+msgstr "Malfermi langeton..."
+
+msgid "Find string"
+msgstr "Trovi ĉenon"
+
+msgid "Find & Replace"
+msgstr "Trovi & AnstataÅ­igi"
+
+msgid "Not Used"
+msgstr "Ne uzata"
+
+msgid "Directory\t*.nothing\n"
+msgstr "Dosierujo\t*.nenio\n"
+
+#, c-format
+msgid "E671: Cannot find window title \"%s\""
+msgstr "E671: Ne eblas trovi titolon de fenestro \"%s\""
+
+#, c-format
+msgid "E243: Argument not supported: \"-%s\"; Use the OLE version."
+msgstr "E243: Ne subtenata argumento: \"-%s\"; Uzu la version OLE."
+
+msgid "E672: Unable to open window inside MDI application"
+msgstr "E672: Ne eblas malfermi fenestron interne de aplikaĵo MDI"
+
+msgid "Vim E458: Cannot allocate colormap entry, some colors may be incorrect"
+msgstr ""
+"Vim E458: Ne eblas disponigi rikordon de kolormapo, iuj koloroj estas eble "
+"neÄustaj"
+
+#, c-format
+msgid "E250: Fonts for the following charsets are missing in fontset %s:"
+msgstr "E250: Tiparoj de tiuj signaroj mankas en aro de tiparo %s:"
+
+#, c-format
+msgid "E252: Fontset name: %s"
+msgstr "E252: Nomo de tiparo: %s"
+
+#, c-format
+msgid "Font '%s' is not fixed-width"
+msgstr "Tiparo '%s' ne estas egallarÄa"
+
+#, c-format
+msgid "E253: Fontset name: %s"
+msgstr "E253: Nomo de tiparo: %s"
+
+#, c-format
+msgid "Font0: %s"
+msgstr "Font0: %s"
+
+#, c-format
+msgid "Font1: %s"
+msgstr "Font1: %s"
+
+#, c-format
+msgid "Font%ld width is not twice that of font0"
+msgstr "Font%ld ne estas duoble pli larÄa ol font0"
+
+#, c-format
+msgid "Font0 width: %ld"
+msgstr "LarÄo de font0: %ld"
+
+#, c-format
+msgid "Font1 width: %ld"
+msgstr "LarÄo de Font1: %ld"
+
+msgid "Invalid font specification"
+msgstr "Nevalida tiparo specifita"
+
+msgid "&Dismiss"
+msgstr "&Forlasi"
+
+msgid "no specific match"
+msgstr "Neniu specifa kongruo"
+
+msgid "Vim - Font Selector"
+msgstr "Vim - Elektilo de tiparo"
+
+msgid "Name:"
+msgstr "Nomo:"
+
+msgid "Show size in Points"
+msgstr "Montri grandon en punktoj"
+
+msgid "Encoding:"
+msgstr "Kodoprezento:"
+
+msgid "Font:"
+msgstr "Tiparo:"
+
+msgid "Style:"
+msgstr "Stilo:"
+
+msgid "Size:"
+msgstr "Grando:"
+
+msgid "E256: Hangul automata ERROR"
+msgstr "E256: ERARO en aÅ­tomato de korea alfabeto"
+
+msgid "E550: Missing colon"
+msgstr "E550: Mankas dupunkto"
+
+msgid "E551: Illegal component"
+msgstr "E551: Nevalida komponento"
+
+msgid "E552: digit expected"
+msgstr "E552: cifero atendita"
+
+#, c-format
+msgid "Page %d"
+msgstr "PaÄo %d"
+
+msgid "No text to be printed"
+msgstr "Neniu presenda teksto"
+
+#, c-format
+msgid "Printing page %d (%d%%)"
+msgstr "Presas paÄon %d (%d%%)"
+
+#, c-format
+msgid " Copy %d of %d"
+msgstr " Kopio %d de %d"
+
+#, c-format
+msgid "Printed: %s"
+msgstr "Presis: %s"
+
+msgid "Printing aborted"
+msgstr "Presado ĉesigita"
+
+msgid "E455: Error writing to PostScript output file"
+msgstr "E455: Eraro dum skribo de PostSkripta eliga dosiero"
+
+#, c-format
+msgid "E624: Can't open file \"%s\""
+msgstr "E624: Ne eblas malfermi dosieron \"%s\""
+
+#, c-format
+msgid "E457: Can't read PostScript resource file \"%s\""
+msgstr "E457: Ne eblas legi dosieron de PostSkripta rimedo \"%s\""
+
+#, c-format
+msgid "E618: file \"%s\" is not a PostScript resource file"
+msgstr "E618: \"%s\" ne estas dosiero de PostSkripta rimedo"
+
+#, c-format
+msgid "E619: file \"%s\" is not a supported PostScript resource file"
+msgstr "E619: \"%s\" ne estas subtenata dosiero de PostSkripta rimedo"
+
+#, c-format
+msgid "E621: \"%s\" resource file has wrong version"
+msgstr "E621: \"%s\" dosiero de rimedo havas neÄustan version"
+
+msgid "E673: Incompatible multi-byte encoding and character set."
+msgstr "E673: Nekongrua plurbajta kodoprezento kaj signaro."
+
+msgid "E674: printmbcharset cannot be empty with multi-byte encoding."
+msgstr ""
+"E674: printmbcharset ne rajtas esti malplena kun plurbajta kodoprezento."
+
+msgid "E675: No default font specified for multi-byte printing."
+msgstr "E675: Neniu defaÅ­lta tiparo specifita por plurbajta presado."
+
+msgid "E324: Can't open PostScript output file"
+msgstr "E324: Ne eblas malfermi eligan PostSkriptan dosieron"
+
+#, c-format
+msgid "E456: Can't open file \"%s\""
+msgstr "E456: Ne eblas malfermi dosieron \"%s\""
+
+msgid "E456: Can't find PostScript resource file \"prolog.ps\""
+msgstr "E456: Dosiero de PostSkripta rimedo \"prolog.ps\" ne troveblas"
+
+msgid "E456: Can't find PostScript resource file \"cidfont.ps\""
+msgstr "E456: Dosiero de PostSkripta rimedo \"cidfont.ps\" ne troveblas"
+
+#, c-format
+msgid "E456: Can't find PostScript resource file \"%s.ps\""
+msgstr "E456: Dosiero de PostSkripta rimedo \"%s.ps\" ne troveblas"
+
+#, c-format
+msgid "E620: Unable to convert to print encoding \"%s\""
+msgstr "E620: Ne eblas konverti al la presa kodoprezento \"%s\""
+
+msgid "Sending to printer..."
+msgstr "Sendas al presilo..."
+
+msgid "E365: Failed to print PostScript file"
+msgstr "E365: Presado de PostSkripta dosiero malsukcesis"
+
+msgid "Print job sent."
+msgstr "Laboro de presado sendita."
+
+msgid "Add a new database"
+msgstr "Aldoni novan datumbazon"
+
+msgid "Query for a pattern"
+msgstr "Serĉi Åablonon"
+
+msgid "Show this message"
+msgstr "Montri tiun mesaÄon"
+
+msgid "Kill a connection"
+msgstr "Ĉesigi konekton"
+
+msgid "Reinit all connections"
+msgstr "Repravalorizi ĉiujn konektojn"
+
+msgid "Show connections"
+msgstr "Montri konektojn"
+
+#, c-format
+msgid "E560: Usage: cs[cope] %s"
+msgstr "E560: Uzo: cs[cope] %s"
+
+msgid "This cscope command does not support splitting the window.\n"
+msgstr "Tiu ĉi komando de cscope ne subtenas dividon de fenestro.\n"
+
+msgid "E562: Usage: cstag <ident>"
+msgstr "E562: Uzo: cstag <ident>"
+
+msgid "E257: cstag: tag not found"
+msgstr "E257: cstag: etikedo netrovita"
+
+#, c-format
+msgid "E563: stat(%s) error: %d"
+msgstr "E563: Eraro de stat(%s): %d"
+
+msgid "E563: stat error"
+msgstr "E563: Eraro de stat"
+
+#, c-format
+msgid "E564: %s is not a directory or a valid cscope database"
+msgstr "E564: %s ne estas dosierujo aÅ­ valida datumbazo de cscope"
+
+#, c-format
+msgid "Added cscope database %s"
+msgstr "Aldonis datumbazon de cscope %s"
+
+#, c-format
+msgid "E262: error reading cscope connection %ld"
+msgstr "E262: eraro dum legado de konekto de cscope %ld"
+
+msgid "E561: unknown cscope search type"
+msgstr "E561: nekonata tipo de serĉo de cscope"
+
+msgid "E566: Could not create cscope pipes"
+msgstr "E566: Ne eblis krei duktojn de cscope"
+
+msgid "E622: Could not fork for cscope"
+msgstr "E622: Ne eblis forki cscope"
+
+msgid "cs_create_connection setpgid failed"
+msgstr "plenumo de cs_create_connection-setgpid malsukcesis"
+
+msgid "cs_create_connection exec failed"
+msgstr "plenumo de cs_create_connection malsukcesis"
+
+msgid "cs_create_connection: fdopen for to_fp failed"
+msgstr "cs_create_connection: fdopen de to_fp malsukcesis"
+
+msgid "cs_create_connection: fdopen for fr_fp failed"
+msgstr "cs_create_connection: fdopen de fr_fp malsukcesis"
+
+msgid "E623: Could not spawn cscope process"
+msgstr "E623: Ne eblis naskigi procezon cscope"
+
+msgid "E567: no cscope connections"
+msgstr "E567: neniu konekto al cscope"
+
+#, c-format
+msgid "E469: invalid cscopequickfix flag %c for %c"
+msgstr "E469: nevalida flago cscopequickfix %c de %c"
+
+#, c-format
+msgid "E259: no matches found for cscope query %s of %s"
+msgstr "E259: neniu kongruo trovita por serĉo per cscope %s de %s"
+
+msgid "cscope commands:\n"
+msgstr "komandoj de cscope:\n"
+
+#, c-format
+msgid "%-5s: %s%*s (Usage: %s)"
+msgstr "%-5s: %s%*s (Uzo: %s)"
+
+msgid ""
+"\n"
+" a: Find assignments to this symbol\n"
+" c: Find functions calling this function\n"
+" d: Find functions called by this function\n"
+" e: Find this egrep pattern\n"
+" f: Find this file\n"
+" g: Find this definition\n"
+" i: Find files #including this file\n"
+" s: Find this C symbol\n"
+" t: Find this text string\n"
+msgstr ""
+"\n"
+" a: Trovi valorizojn al tiu simbolo\n"
+" c: Trovi funkciojn, kiuj alvokas tiun funkcion\n"
+" d: Trovi funkciojn alvokataj de tiu funkcio\n"
+" e: Trovi tiun egrep-Åablonon\n"
+" f: Trovi tiun dosieron\n"
+" g: Trovi tiun difinon\n"
+" i: Trovi dosierojn, kiuj inkluzivas (#include) tiun dosieron\n"
+" s: Trovi tiun C-simbolon\n"
+" t: Trovi tiun ĉenon\n"
+
+#, c-format
+msgid "E625: cannot open cscope database: %s"
+msgstr "E625: ne eblas malfermi datumbazon de cscope: %s"
+
+msgid "E626: cannot get cscope database information"
+msgstr "E626: ne eblas akiri informojn pri la datumbazo de cscope"
+
+msgid "E568: duplicate cscope database not added"
+msgstr "E568: ripetita datumbazo de cscope ne aldonita"
+
+#, c-format
+msgid "E261: cscope connection %s not found"
+msgstr "E261: konekto cscope %s netrovita"
+
+#, c-format
+msgid "cscope connection %s closed"
+msgstr "konekto cscope %s fermita"
+
+msgid "E570: fatal error in cs_manage_matches"
+msgstr "E570: neriparebla eraro en cs_manage_matches"
+
+#, c-format
+msgid "Cscope tag: %s"
+msgstr "Etikedo de cscope: %s"
+
+msgid ""
+"\n"
+" # line"
+msgstr ""
+"\n"
+" nro linio"
+
+msgid "filename / context / line\n"
+msgstr "dosiernomo / kunteksto / linio\n"
+
+#, c-format
+msgid "E609: Cscope error: %s"
+msgstr "E609: Eraro de cscope: %s"
+
+msgid "All cscope databases reset"
+msgstr "ReÅargo de ĉiuj datumbazoj de cscope"
+
+msgid "no cscope connections\n"
+msgstr "neniu konekto de cscope\n"
+
+msgid " # pid database name prepend path\n"
+msgstr " # pid nomo de datumbazo prefiksa vojo\n"
+
+msgid "Lua library cannot be loaded."
+msgstr "La biblioteko Lua no Åargeblis."
+
+msgid "cannot save undo information"
+msgstr "ne eblas konservi informojn de malfaro"
+
+msgid ""
+"E815: Sorry, this command is disabled, the MzScheme libraries could not be "
+"loaded."
+msgstr ""
+"E815: BedaÅ­rinde, tiu komando estas malÅaltita, ne eblis Åargi la "
+"bibliotekojn."
+
+msgid ""
+"E895: Sorry, this command is disabled, the MzScheme's racket/base module "
+"could not be loaded."
+msgstr ""
+"E895: BedaÅ­rinde, tiu komando estas malÅaltita, ne eblis Åargi la modulon de "
+"MzScheme racket/base."
+
+msgid "invalid expression"
+msgstr "nevalida esprimo"
+
+msgid "expressions disabled at compile time"
+msgstr "esprimoj malÅaltitaj dum kompilado"
+
+msgid "hidden option"
+msgstr "kaÅita opcio"
+
+msgid "unknown option"
+msgstr "nekonata opcio"
+
+msgid "window index is out of range"
+msgstr "indekso de fenestro estas ekster limoj"
+
+msgid "couldn't open buffer"
+msgstr "ne eblis malfermi bufron"
+
+msgid "cannot delete line"
+msgstr "ne eblas forviÅi linion"
+
+msgid "cannot replace line"
+msgstr "ne eblas anstataÅ­igi linion"
+
+msgid "cannot insert line"
+msgstr "ne eblas enmeti linion"
+
+msgid "string cannot contain newlines"
+msgstr "ĉeno ne rajtas enhavi liniavancojn"
+
+msgid "error converting Scheme values to Vim"
+msgstr "eraro dum konverto de Scheme-valoro al Vim"
+
+msgid "Vim error: ~a"
+msgstr "Eraro de Vim: ~a"
+
+msgid "Vim error"
+msgstr "Eraro de Vim"
+
+msgid "buffer is invalid"
+msgstr "bufro estas nevalida"
+
+msgid "window is invalid"
+msgstr "fenestro estas nevalida"
+
+msgid "linenr out of range"
+msgstr "numero de linio ekster limoj"
+
+msgid "not allowed in the Vim sandbox"
+msgstr "nepermesebla en sabloludejo de Vim"
+
+msgid "E836: This Vim cannot execute :python after using :py3"
+msgstr "E836: Vim ne povas plenumi :python post uzo de :py3"
+
+msgid ""
+"E263: Sorry, this command is disabled, the Python library could not be "
+"loaded."
+msgstr ""
+"E263: BedaÅ­rinde tiu komando estas malÅaltita: la biblioteko de Pitono ne "
+"Åargeblis."
+
+msgid ""
+"E887: Sorry, this command is disabled, the Python's site module could not be "
+"loaded."
+msgstr ""
+"E887` BedaÅ­rinde tiu komando estas malÅaltita: la biblioteko de Pitono ne "
+"Åargeblis."
+
+msgid "E659: Cannot invoke Python recursively"
+msgstr "E659: Ne eblas alvoki Pitonon rekursie"
+
+msgid "E837: This Vim cannot execute :py3 after using :python"
+msgstr "E837: Vim ne povas plenumi :py3 post uzo de :python"
+
+msgid "E265: $_ must be an instance of String"
+msgstr "E265: $_ devas esti apero de Ĉeno"
+
+msgid ""
+"E266: Sorry, this command is disabled, the Ruby library could not be loaded."
+msgstr ""
+"E266: BedaÅ­rinde tiu komando estas malÅaltita, la biblioteko Ruby ne "
+"Åargeblis."
+
+msgid "E267: unexpected return"
+msgstr "E267: \"return\" neatendita"
+
+msgid "E268: unexpected next"
+msgstr "E268: \"next\" neatendita"
+
+msgid "E269: unexpected break"
+msgstr "E269: \"break\" neatendita"
+
+msgid "E270: unexpected redo"
+msgstr "E270: \"redo\" neatendita"
+
+msgid "E271: retry outside of rescue clause"
+msgstr "E271: \"retry\" ekster klaÅ­zo \"rescue\""
+
+msgid "E272: unhandled exception"
+msgstr "E272: netraktita escepto"
+
+#, c-format
+msgid "E273: unknown longjmp status %d"
+msgstr "E273: nekonata stato de longjmp: %d"
+
+msgid "invalid buffer number"
+msgstr "nevalida numero de bufro"
+
+msgid "not implemented yet"
+msgstr "ankoraÅ­ ne realigita"
+
+msgid "cannot set line(s)"
+msgstr "ne eblas meti la linio(j)n"
+
+msgid "invalid mark name"
+msgstr "nevalida nomo de marko"
+
+msgid "mark not set"
+msgstr "marko ne estas metita"
+
+#, c-format
+msgid "row %d column %d"
+msgstr "linio %d kolumno %d"
+
+msgid "cannot insert/append line"
+msgstr "ne eblas enmeti/postaldoni linion"
+
+msgid "line number out of range"
+msgstr "numero de linio ekster limoj"
+
+msgid "unknown flag: "
+msgstr "nekonata flago: "
+
+# DP: ĉu traduki vimOption
+msgid "unknown vimOption"
+msgstr "nekonata vimOption"
+
+msgid "keyboard interrupt"
+msgstr "klavara interrompo"
+
+msgid "vim error"
+msgstr "eraro de Vim"
+
+msgid "cannot create buffer/window command: object is being deleted"
+msgstr "ne eblas krei komandon de bufro/fenestro: objekto estas forviÅiÄanta"
+
+msgid ""
+"cannot register callback command: buffer/window is already being deleted"
+msgstr ""
+"ne eblas registri postalvokan komandon: bufro/fenestro estas jam forviÅiÄanta"
+
+msgid ""
+"E280: TCL FATAL ERROR: reflist corrupt!? Please report this to vim-dev@vim."
+"org"
+msgstr ""
+"E280: NERIPAREBLA TCL-ERARO: reflist difekta!? Bv. retpoÅti al vim-dev@vim."
+"org"
+
+msgid "cannot register callback command: buffer/window reference not found"
+msgstr ""
+"ne eblas registri postalvokan komandon: referenco de bufro/fenestro ne "
+"troveblas"
+
+msgid ""
+"E571: Sorry, this command is disabled: the Tcl library could not be loaded."
+msgstr ""
+"E571: BedaÅ­rinde tiu komando estas malÅaltita: la biblioteko Tcl ne "
+"Åargeblis."
+
+#, c-format
+msgid "E572: exit code %d"
+msgstr "E572: elira kodo %d"
+
+msgid "cannot get line"
+msgstr "ne eblas akiri linion"
+
+msgid "Unable to register a command server name"
+msgstr "Ne eblas registri nomon de komanda servilo"
+
+msgid "E248: Failed to send command to the destination program"
+msgstr "E248: Sendo de komando al cela programo malsukcesis"
+
+#, c-format
+msgid "E573: Invalid server id used: %s"
+msgstr "E573: Nevalida identigilo de servilo uzita: %s"
+
+msgid "E251: VIM instance registry property is badly formed. Deleted!"
+msgstr ""
+"E251: Ecoj de registro de apero de VIM estas nevalide formata. ForviÅita!"
+
+#, c-format
+msgid "E938: Duplicate key in JSON: \"%s\""
+msgstr "E938: Ripetita Ålosilo en JSON: \"%s\""
+
+#, c-format
+msgid "E696: Missing comma in List: %s"
+msgstr "E696: Mankas komo en Listo: %s"
+
+#, c-format
+msgid "E697: Missing end of List ']': %s"
+msgstr "E697: Mankas fino de Listo ']': %s"
+
+msgid "Unknown option argument"
+msgstr "Nekonata argumento de opcio"
+
+msgid "Too many edit arguments"
+msgstr "Tro da argumentoj de redakto"
+
+msgid "Argument missing after"
+msgstr "Argumento mankas malantaÅ­"
+
+msgid "Garbage after option argument"
+msgstr "Forĵetindaĵo malantaŭ argumento de opcio"
+
+msgid "Too many \"+command\", \"-c command\" or \"--cmd command\" arguments"
+msgstr "Tro da argumentoj \"+komando\", \"-c komando\" aÅ­ \"--cmd komando\""
+
+msgid "Invalid argument for"
+msgstr "Nevalida argumento por"
+
+#, c-format
+msgid "%d files to edit\n"
+msgstr "%d redaktendaj dosieroj\n"
+
+msgid "netbeans is not supported with this GUI\n"
+msgstr "netbeans ne estas subtenata kun tiu grafika interfaco\n"
+
+msgid "'-nb' cannot be used: not enabled at compile time\n"
+msgstr "'-nb' ne uzeblas: malÅaltita dum kompilado\n"
+
+msgid "This Vim was not compiled with the diff feature."
+msgstr "Tiu Vim ne estis kompilita kun la kompara eblo."
+
+msgid "Attempt to open script file again: \""
+msgstr "Provas malfermi skriptan dosieron denove: \""
+
+msgid "Cannot open for reading: \""
+msgstr "Ne eblas malfermi en lega reÄimo: \""
+
+msgid "Cannot open for script output: \""
+msgstr "Ne eblas malfermi por eligo de skripto: \""
+
+msgid "Vim: Error: Failure to start gvim from NetBeans\n"
+msgstr "Vim: Eraro: malsukcesis lanĉi gvim el NetBeans\n"
+
+msgid "Vim: Error: This version of Vim does not run in a Cygwin terminal\n"
+msgstr "Vim: Eraro: Tiu versio de Vim ne ruliÄas en terminalo Cygwin\n"
+
+msgid "Vim: Warning: Output is not to a terminal\n"
+msgstr "Vim: Averto: Eligo ne estas al terminalo\n"
+
+msgid "Vim: Warning: Input is not from a terminal\n"
+msgstr "Vim: Averto: Enigo ne estas el terminalo\n"
+
+msgid "pre-vimrc command line"
+msgstr "komanda linio pre-vimrc"
+
+#, c-format
+msgid "E282: Cannot read from \"%s\""
+msgstr "E282: Ne eblas legi el \"%s\""
+
+msgid ""
+"\n"
+"More info with: \"vim -h\"\n"
+msgstr ""
+"\n"
+"Pliaj informoj per: \"vim -h\"\n"
+
+# DP: tajpu "vim --help" por testi tiujn mesaÄojn
+msgid "[file ..] edit specified file(s)"
+msgstr "[dosiero...] redakti specifita(j)n dosiero(j)n"
+
+msgid "- read text from stdin"
+msgstr "- legi tekston el stdin"
+
+msgid "-t tag edit file where tag is defined"
+msgstr "-t etikedo redakti dosieron kie etikedo estas difinata"
+
+msgid "-q [errorfile] edit file with first error"
+msgstr "-q [erardosiero] redakti dosieron kun unua eraro"
+
+msgid ""
+"\n"
+"\n"
+"Usage:"
+msgstr ""
+"\n"
+"\n"
+" uzo:"
+
+msgid " vim [arguments] "
+msgstr " vim [argumentoj] "
+
+msgid ""
+"\n"
+" or:"
+msgstr ""
+"\n"
+" aÅ­:"
+
+msgid ""
+"\n"
+"Where case is ignored prepend / to make flag upper case"
+msgstr ""
+"\n"
+"Kie uskleco estas ignorita antaÅ­aldonu / por igi flagon majuskla"
+
+msgid ""
+"\n"
+"\n"
+"Arguments:\n"
+msgstr ""
+"\n"
+"\n"
+"Argumentoj:\n"
+
+msgid "--\t\t\tOnly file names after this"
+msgstr "--\t\t\tNur dosiernomoj malantaÅ­ tio"
+
+msgid "--literal\t\tDon't expand wildcards"
+msgstr "--literal\t\tNe malvolvi ĵokerojn"
+
+msgid "-register\t\tRegister this gvim for OLE"
+msgstr "-register\t\tRegistri tiun gvim al OLE"
+
+msgid "-unregister\t\tUnregister gvim for OLE"
+msgstr "-unregister\t\tMalregistri gvim de OLE"
+
+msgid "-g\t\t\tRun using GUI (like \"gvim\")"
+msgstr "-g\t\t\tRuli per grafika interfaco (kiel \"gvim\")"
+
+msgid "-f or --nofork\tForeground: Don't fork when starting GUI"
+msgstr "-f aŭ --nofork\tMalfono: ne forki kiam lanĉas grafikan interfacon"
+
+msgid "-v\t\t\tVi mode (like \"vi\")"
+msgstr "-v\t\t\tReÄimo Vi (kiel \"vi\")"
+
+msgid "-e\t\t\tEx mode (like \"ex\")"
+msgstr "-e\t\t\tReÄimo Ex (kiel \"ex\")"
+
+msgid "-E\t\t\tImproved Ex mode"
+msgstr "-E\t\t\tPlibonigita Ex-reÄimo"
+
+msgid "-s\t\t\tSilent (batch) mode (only for \"ex\")"
+msgstr "-s\t\t\tSilenta (stapla) reÄimo (nur por \"ex\")"
+
+msgid "-d\t\t\tDiff mode (like \"vimdiff\")"
+msgstr "-d\t\t\tKompara reÄimo (kiel \"vimdiff\")"
+
+msgid "-y\t\t\tEasy mode (like \"evim\", modeless)"
+msgstr "-y\t\t\tFacila reÄimo (kiel \"evim\", senreÄima)"
+
+msgid "-R\t\t\tReadonly mode (like \"view\")"
+msgstr "-R\t\t\tNurlegebla reÄimo (kiel \"view\")"
+
+msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
+msgstr "-Z\t\t\tLimigita reÄimo (kiel \"rvim\")"
+
+msgid "-m\t\t\tModifications (writing files) not allowed"
+msgstr "-m\t\t\tÅœanÄoj (skribo al dosieroj) nepermeseblaj"
+
+msgid "-M\t\t\tModifications in text not allowed"
+msgstr "-M\t\t\tÅœanÄoj al teksto nepermeseblaj"
+
+msgid "-b\t\t\tBinary mode"
+msgstr "-b\t\t\tDuuma reÄimo"
+
+msgid "-l\t\t\tLisp mode"
+msgstr "-l\t\t\tReÄimo Lisp"
+
+msgid "-C\t\t\tCompatible with Vi: 'compatible'"
+msgstr "-C\t\t\tKongrua kun Vi: 'compatible'"
+
+msgid "-N\t\t\tNot fully Vi compatible: 'nocompatible'"
+msgstr "-N\t\t\tNe tute kongrua kun Vi: 'nocompatible'"
+
+msgid "-V[N][fname]\t\tBe verbose [level N] [log messages to fname]"
+msgstr ""
+"-V[N][dosiernomo]\tEsti babilema [nivelo N] [konservi mesaÄojn al dosiernomo]"
+
+msgid "-D\t\t\tDebugging mode"
+msgstr "-D\t\t\tSencimiga reÄimo"
+
+msgid "-n\t\t\tNo swap file, use memory only"
+msgstr "-n\t\t\tNeniu permutodosiero .swp, uzas nur memoron"
+
+msgid "-r\t\t\tList swap files and exit"
+msgstr "-r\t\t\tListigi permutodosierojn .swp kaj eliri"
+
+msgid "-r (with file name)\tRecover crashed session"
+msgstr "-r (kun dosiernomo)\tRestaÅ­ri kolapsintan seancon"
+
+msgid "-L\t\t\tSame as -r"
+msgstr "-L\t\t\tKiel -r"
+
+msgid "-f\t\t\tDon't use newcli to open window"
+msgstr "-f\t\t\tNe uzi newcli por malfermi fenestrojn"
+
+msgid "-dev <device>\t\tUse <device> for I/O"
+msgstr "-dev <aparatdosiero>\t\tUzi <aparatdosiero>-n por eneligo"
+
+msgid "-A\t\t\tStart in Arabic mode"
+msgstr "-A\t\t\tKomenci en araba reÄimo"
+
+msgid "-H\t\t\tStart in Hebrew mode"
+msgstr "-H\t\t\tKomenci en hebrea reÄimo"
+
+msgid "-F\t\t\tStart in Farsi mode"
+msgstr "-F\t\t\tKomenci en persa reÄimo"
+
+msgid "-T <terminal>\tSet terminal type to <terminal>"
+msgstr "-T <terminalo>\tAgordi terminalon al <terminalo>"
+
+msgid "--not-a-term\t\tSkip warning for input/output not being a terminal"
+msgstr ""
+"--not-a-term\t\tPreterpasi averton por enigo/eligo, kiu ne estas terminalo"
+
+msgid "--ttyfail\t\tExit if input or output is not a terminal"
+msgstr "--ttyfail\t\tEliri se la eniro aÅ­ eliro ne estas terminalo"
+
+msgid "-u <vimrc>\t\tUse <vimrc> instead of any .vimrc"
+msgstr "-u <vimrc>\t\tUzi <vimrc> anstataÅ­ iun ajn .vimrc"
+
+msgid "-U <gvimrc>\t\tUse <gvimrc> instead of any .gvimrc"
+msgstr "-U <gvimrc>\t\tUzi <gvimrc> anstataÅ­ iun ajn .gvimrc"
+
+msgid "--noplugin\t\tDon't load plugin scripts"
+msgstr "--noplugin\t\tNe Åargi kromaĵajn skriptojn"
+
+msgid "-p[N]\t\tOpen N tab pages (default: one for each file)"
+msgstr "-p[N]\t\tMalfermi N langetojn (defaŭlto: po unu por ĉiu dosiero)"
+
+msgid "-o[N]\t\tOpen N windows (default: one for each file)"
+msgstr "-o[N]\t\tMalfermi N fenestrojn (defaŭlto: po unu por ĉiu dosiero)"
+
+msgid "-O[N]\t\tLike -o but split vertically"
+msgstr "-O[N]\t\tKiel -o sed dividi vertikale"
+
+msgid "+\t\t\tStart at end of file"
+msgstr "+\t\t\tKomenci ĉe la fino de la dosiero"
+
+msgid "+<lnum>\t\tStart at line <lnum>"
+msgstr "+<numL>\t\tKomenci ĉe linio <numL>"
+
+msgid "--cmd <command>\tExecute <command> before loading any vimrc file"
+msgstr ""
+"--cmd <komando>\tPlenumi <komando>-n antaÅ­ ol Åargi iun ajn dosieron vimrc"
+
+msgid "-c <command>\t\tExecute <command> after loading the first file"
+msgstr "-c <komando>\t\tPlenumi <komando>-n post kiam la unua dosiero ÅargiÄis"
+
+msgid "-S <session>\t\tSource file <session> after loading the first file"
+msgstr ""
+"-S <seanco>\t\tRuli dosieron <seanco>-n post kiam la unua dosiero ÅargiÄis"
+
+msgid "-s <scriptin>\tRead Normal mode commands from file <scriptin>"
+msgstr "-s <skripto>\t\tLegi komandojn en Normala reÄimo el dosiero <skripto>"
+
+msgid "-w <scriptout>\tAppend all typed commands to file <scriptout>"
+msgstr ""
+"-w <eligaskripto>\tPostaldoni ĉiujn tajpitajn komandojn al dosiero "
+"<eligaskripto>"
+
+msgid "-W <scriptout>\tWrite all typed commands to file <scriptout>"
+msgstr ""
+"-W <eligaskripto>\tSkribi ĉiujn tajpitajn komandojn al dosiero <eligaskripto>"
+
+msgid "-x\t\t\tEdit encrypted files"
+msgstr "-x\t\t\tRedakti ĉifradan dosieron"
+
+msgid "-display <display>\tConnect vim to this particular X-server"
+msgstr "-display <ekrano>\tKonekti Vim al tiu X-servilo"
+
+msgid "-X\t\t\tDo not connect to X server"
+msgstr "-X\t\t\tNe konekti al X-servilo"
+
+msgid "--remote <files>\tEdit <files> in a Vim server if possible"
+msgstr "--remote <dosieroj>\tRedakti <dosieroj>-n en Vim-servilo se eblas"
+
+msgid "--remote-silent <files> Same, don't complain if there is no server"
+msgstr "--remote-silent <dosieroj> Same, sed ne plendi se ne estas servilo"
+
+msgid ""
+"--remote-wait <files> As --remote but wait for files to have been edited"
+msgstr ""
+"--remote-wait <dosieroj> Kiel --remote sed atendi Äis dosieroj estas "
+"redaktitaj"
+
+msgid ""
+"--remote-wait-silent <files> Same, don't complain if there is no server"
+msgstr ""
+"--remote-wait-silent <dosieroj> Same, sed ne plendi se ne estas servilo"
+
+msgid ""
+"--remote-tab[-wait][-silent] <files> As --remote but use tab page per file"
+msgstr ""
+"--remote-tab[-wait][-silent] <dosieroj> Kiel --remote sed uzi langeton por "
+"ĉiu dosiero"
+
+msgid "--remote-send <keys>\tSend <keys> to a Vim server and exit"
+msgstr "--remote-send <klavoj> Sendi <klavoj>-n al Vim-servilo kaj eliri"
+
+msgid "--remote-expr <expr>\tEvaluate <expr> in a Vim server and print result"
+msgstr "--remote-expr <espr>\tKomputi <espr> en Vim-servilo kaj afiÅi rezulton"
+
+msgid "--serverlist\t\tList available Vim server names and exit"
+msgstr "--serverlist\t\tListigi haveblajn nomojn de Vim-serviloj kaj eliri"
+
+msgid "--servername <name>\tSend to/become the Vim server <name>"
+msgstr "--servername <nomo>\tSendu al/iÄi la Vim-servilo <nomo>"
+
+msgid "--startuptime <file>\tWrite startup timing messages to <file>"
+msgstr ""
+"--startuptime <dosiero> Skribi mesaÄojn de komenca tempomezurado al "
+"<dosiero>"
+
+msgid "-i <viminfo>\t\tUse <viminfo> instead of .viminfo"
+msgstr "-i <viminfo>\t\tUzi <viminfo> anstataÅ­ .viminfo"
+
+msgid "--clean\t\t'nocompatible', Vim defaults, no plugins, no viminfo"
+msgstr "--clean\t\t'nocompatible', defaÅ­ltaj agordoj de Vim, neniu viminfo"
+
+msgid "-h or --help\tPrint Help (this message) and exit"
+msgstr "-h aÅ­ --help\tAfiÅi Helpon (tiun mesaÄon) kaj eliri"
+
+msgid "--version\t\tPrint version information and exit"
+msgstr "--version\t\tAfiÅi informon de versio kaj eliri"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Motif version):\n"
+msgstr ""
+"\n"
+"Argumentoj agnoskitaj de gvim (versio Motif):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (neXtaw version):\n"
+msgstr ""
+"\n"
+"Argumentoj agnoskitaj de gvim (versio neXtaw):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Athena version):\n"
+msgstr ""
+"\n"
+"Argumentoj agnoskitaj de gvim (versio Athena):\n"
+
+msgid "-display <display>\tRun vim on <display>"
+msgstr "-display <ekrano>\tLanĉi vim sur <ekrano>"
+
+msgid "-iconic\t\tStart vim iconified"
+msgstr "-iconic\t\tLanĉi vim piktograme"
+
+msgid "-background <color>\tUse <color> for the background (also: -bg)"
+msgstr "-background <koloro>\tUzi <koloro>-n por la fona koloro (ankaÅ­: -bg)"
+
+msgid "-foreground <color>\tUse <color> for normal text (also: -fg)"
+msgstr ""
+"-foreground <koloro>\tUzi <koloro>-n por la malfona koloro (ankaÅ­: -fg)"
+
+msgid "-font <font>\t\tUse <font> for normal text (also: -fn)"
+msgstr "-font <tiparo>\tUzi <tiparo>-n por normala teksto (ankaÅ­: -fn)"
+
+msgid "-boldfont <font>\tUse <font> for bold text"
+msgstr "-boldfont <tiparo>\tUzi <tiparo>-n por grasa teksto"
+
+msgid "-italicfont <font>\tUse <font> for italic text"
+msgstr "-italicfont <tiparo>\tUzi <tiparo>-n por kursiva teksto"
+
+msgid "-geometry <geom>\tUse <geom> for initial geometry (also: -geom)"
+msgstr "-geometry <geom>\tUzi <geom> kiel komenca geometrio (ankaÅ­: -geom)"
+
+msgid "-borderwidth <width>\tUse a border width of <width> (also: -bw)"
+msgstr "-borderwidth <larÄo>\tUzi <larÄo>-n kiel larÄo de bordero (ankaÅ­: -bw)"
+
+msgid "-scrollbarwidth <width> Use a scrollbar width of <width> (also: -sw)"
+msgstr ""
+"-scrollbarwidth <larÄo> Uzi <larÄo>-n kiel larÄo de rulumskalo (ankaÅ­: -sw)"
+
+msgid "-menuheight <height>\tUse a menu bar height of <height> (also: -mh)"
+msgstr ""
+"-menuheight <alto>\tUzi <alto>-n kiel alto de menuzona alto (ankaÅ­: -mh)"
+
+msgid "-reverse\t\tUse reverse video (also: -rv)"
+msgstr "-reverse\t\tUzi inversan videon (ankaÅ­: -rv)"
+
+msgid "+reverse\t\tDon't use reverse video (also: +rv)"
+msgstr "+reverse\t\tNe uzi inversan videon (ankaÅ­: +rv)"
+
+msgid "-xrm <resource>\tSet the specified resource"
+msgstr "-xrm <rimedo>\tAgordi la specifitan <rimedo>-n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (GTK+ version):\n"
+msgstr ""
+"\n"
+"Argumentoj agnoskitaj de gvim (versio GTK+):\n"
+
+msgid "-display <display>\tRun vim on <display> (also: --display)"
+msgstr "-display <ekrano>\tLanĉi Vim sur tiu <ekrano> (ankaŭ: --display)"
+
+msgid "--role <role>\tSet a unique role to identify the main window"
+msgstr "--role <rolo>\tDoni unikan rolon por identigi la ĉefan fenestron"
+
+msgid "--socketid <xid>\tOpen Vim inside another GTK widget"
+msgstr "--socketid <xid>\tMalfermi Vim en alia GTK fenestraĵo"
+
+msgid "--echo-wid\t\tMake gvim echo the Window ID on stdout"
+msgstr "--echo-wid\t\tIgas gvim afiÅi la identigilon de vindozo sur stdout"
+
+msgid "-P <parent title>\tOpen Vim inside parent application"
+msgstr "-P <gepatra titolo>\tMalfermi Vim en gepatra aplikaĵo"
+
+msgid "--windowid <HWND>\tOpen Vim inside another win32 widget"
+msgstr "--windowid <HWND>\tMalfermi Vim en alia win32 fenestraĵo"
+
+msgid "No display"
+msgstr "Neniu ekrano"
+
+msgid ": Send failed.\n"
+msgstr ": Sendo malsukcesis.\n"
+
+msgid ": Send failed. Trying to execute locally\n"
+msgstr ": Sendo malsukcesis. Provo de loka plenumo\n"
+
+#, c-format
+msgid "%d of %d edited"
+msgstr "%d de %d redaktita(j)"
+
+msgid "No display: Send expression failed.\n"
+msgstr "Neniu ekrano: Sendado de esprimo malsukcesis.\n"
+
+msgid ": Send expression failed.\n"
+msgstr ": Sendado de esprimo malsukcesis.\n"
+
+msgid "No marks set"
+msgstr "Neniu marko"
+
+#, c-format
+msgid "E283: No marks matching \"%s\""
+msgstr "E283: Neniu marko kongruas kun \"%s\""
+
+msgid ""
+"\n"
+"mark line col file/text"
+msgstr ""
+"\n"
+"mark linio kol dosiero/teksto"
+
+msgid ""
+"\n"
+" jump line col file/text"
+msgstr ""
+"\n"
+" salt linio kol dosiero/teksto"
+
+msgid ""
+"\n"
+"change line col text"
+msgstr ""
+"\n"
+"ÅanÄo linio kol teksto"
+
+msgid ""
+"\n"
+"# File marks:\n"
+msgstr ""
+"\n"
+"# Markoj de dosiero:\n"
+
+msgid ""
+"\n"
+"# Jumplist (newest first):\n"
+msgstr ""
+"\n"
+"# Saltlisto (plej novaj unue):\n"
+
+msgid ""
+"\n"
+"# History of marks within files (newest to oldest):\n"
+msgstr ""
+"\n"
+"# Historio de markoj en dosieroj (de plej nova al plej malnova):\n"
+
+msgid "Missing '>'"
+msgstr "Mankas '>'"
+
+msgid "E543: Not a valid codepage"
+msgstr "E543: Nevalida kodpaÄo"
+
+msgid "E284: Cannot set IC values"
+msgstr "E284: Ne eblas agordi valorojn de IC"
+
+msgid "E285: Failed to create input context"
+msgstr "E285: Kreado de eniga kunteksto malsukcesis"
+
+msgid "E286: Failed to open input method"
+msgstr "E286: Malfermo de eniga metodo malsukcesis"
+
+msgid "E287: Warning: Could not set destroy callback to IM"
+msgstr "E287: Averto: Ne eblis agordi detruan reagfunkcion al IM"
+
+msgid "E288: input method doesn't support any style"
+msgstr "E288: eniga metodo subtenas neniun stilon"
+
+# DP: mi ne scias, kio estas "preedit"
+msgid "E289: input method doesn't support my preedit type"
+msgstr "E289: eniga metodo ne subtenas mian antaÅ­redaktan tipon"
+
+msgid "E293: block was not locked"
+msgstr "E293: bloko ne estis Ålosita"
+
+msgid "E294: Seek error in swap file read"
+msgstr "E294: Eraro de enpoziciigo dum lego de permutodosiero .swp"
+
+msgid "E295: Read error in swap file"
+msgstr "E295: Eraro de lego en permutodosiero .swp"
+
+msgid "E296: Seek error in swap file write"
+msgstr "E296: Eraro de enpoziciigo dum skribo de permutodosiero .swp"
+
+msgid "E297: Write error in swap file"
+msgstr "E297: Skriberaro en permutodosiero .swp"
+
+msgid "E300: Swap file already exists (symlink attack?)"
+msgstr "E300: Permutodosiero .swp jam ekzistas (ĉu atako per simbola ligilo?)"
+
+msgid "E298: Didn't get block nr 0?"
+msgstr "E298: Ĉu ne akiris blokon n-ro 0?"
+
+msgid "E298: Didn't get block nr 1?"
+msgstr "E298: Ĉu ne akiris blokon n-ro 1?"
+
+msgid "E298: Didn't get block nr 2?"
+msgstr "E298: Ĉu ne akiris blokon n-ro 2?"
+
+msgid "E843: Error while updating swap file crypt"
+msgstr "E843: Eraro dum Äisdatigo de ĉifrada permutodosiero .swp"
+
+msgid "E301: Oops, lost the swap file!!!"
+msgstr "E301: Ve, perdis la permutodosieron .swp!!!"
+
+msgid "E302: Could not rename swap file"
+msgstr "E302: Ne eblis renomi la permutodosieron .swp"
+
+#, c-format
+msgid "E303: Unable to open swap file for \"%s\", recovery impossible"
+msgstr ""
+"E303: Ne eblas malfermi permutodosieron .swp de \"%s\", restaÅ­ro neeblas"
+
+msgid "E304: ml_upd_block0(): Didn't get block 0??"
+msgstr "E304: ml_upd_block0(): Ne akiris blokon 0??"
+
+#, c-format
+msgid "E305: No swap file found for %s"
+msgstr "E305: Neniu permutodosiero .swp trovita por %s"
+
+msgid "Enter number of swap file to use (0 to quit): "
+msgstr "Entajpu la uzendan numeron de permutodosiero .swp (0 por eliri): "
+
+#, c-format
+msgid "E306: Cannot open %s"
+msgstr "E306: Ne eblas malfermi %s"
+
+msgid "Unable to read block 0 from "
+msgstr "Ne eblas legi blokon 0 de "
+
+msgid ""
+"\n"
+"Maybe no changes were made or Vim did not update the swap file."
+msgstr ""
+"\n"
+"Eble neniu ÅanÄo estis farita aÅ­ Vim ne Äisdatigis la permutodosieron .swp."
+
+msgid " cannot be used with this version of Vim.\n"
+msgstr " ne uzeblas per tiu versio de vim.\n"
+
+msgid "Use Vim version 3.0.\n"
+msgstr "Uzu version 3.0 de Vim\n"
+
+#, c-format
+msgid "E307: %s does not look like a Vim swap file"
+msgstr "E307: %s ne aspektas kiel permutodosiero .swp de Vim"
+
+msgid " cannot be used on this computer.\n"
+msgstr " ne uzeblas per tiu komputilo.\n"
+
+msgid "The file was created on "
+msgstr "La dosiero estas kreita je "
+
+msgid ""
+",\n"
+"or the file has been damaged."
+msgstr ""
+",\n"
+"aÅ­ la dosiero estas difekta."
+
+#, c-format
+msgid ""
+"E833: %s is encrypted and this version of Vim does not support encryption"
+msgstr "E833: %s estas ĉifrita kaj tiu versio de Vim ne subtenas ĉifradon"
+
+msgid " has been damaged (page size is smaller than minimum value).\n"
+msgstr " difektiÄis (paÄa grando pli malgranda ol minimuma valoro).\n"
+
+#, c-format
+msgid "Using swap file \"%s\""
+msgstr "Uzado de permutodosiero .swp \"%s\""
+
+#, c-format
+msgid "Original file \"%s\""
+msgstr "Originala dosiero \"%s\""
+
+msgid "E308: Warning: Original file may have been changed"
+msgstr "E308: Averto: Originala dosiero eble ÅanÄiÄis"
+
+#, c-format
+msgid "Swap file is encrypted: \"%s\""
+msgstr "Permutodosiero .swp estas ĉifrita: \"%s\""
+
+msgid ""
+"\n"
+"If you entered a new crypt key but did not write the text file,"
+msgstr ""
+"\n"
+"Se vi tajpis novan Ålosilon de ĉifrado sed ne skribis la tekstan dosieron,"
+
+msgid ""
+"\n"
+"enter the new crypt key."
+msgstr ""
+"\n"
+"tajpu la novan Ålosilon de ĉifrado."
+
+msgid ""
+"\n"
+"If you wrote the text file after changing the crypt key press enter"
+msgstr ""
+"\n"
+"Se vi skribis la tekstan dosieron post ÅanÄo de la Ålosilo de ĉifrado, premu "
+"enenklavon"
+
+msgid ""
+"\n"
+"to use the same key for text file and swap file"
+msgstr ""
+"\n"
+"por uzi la saman Ålosilon por la teksta dosiero kaj permutodosiero .swp"
+
+#, c-format
+msgid "E309: Unable to read block 1 from %s"
+msgstr "E309: Ne eblas legi blokon 1 de %s"
+
+msgid "???MANY LINES MISSING"
+msgstr "???MULTAJ LINIOJ MANKAS"
+
+msgid "???LINE COUNT WRONG"
+msgstr "???NOMBRO DE LINIOJ NE ÄœUSTAS"
+
+msgid "???EMPTY BLOCK"
+msgstr "???MALPLENA BLOKO"
+
+msgid "???LINES MISSING"
+msgstr "???LINIOJ MANKANTAJ"
+
+#, c-format
+msgid "E310: Block 1 ID wrong (%s not a .swp file?)"
+msgstr ""
+"E310: Nevalida identigilo de bloko 1 (ĉu %s ne estas permutodosiero .swp?)"
+
+msgid "???BLOCK MISSING"
+msgstr "???MANKAS BLOKO"
+
+msgid "??? from here until ???END lines may be messed up"
+msgstr "??? ekde tie Äis ???FINO linioj estas eble difektaj"
+
+msgid "??? from here until ???END lines may have been inserted/deleted"
+msgstr "??? ekde tie Äis ???FINO linioj estas eble enmetitaj/forviÅitaj"
+
+msgid "???END"
+msgstr "???FINO"
+
+msgid "E311: Recovery Interrupted"
+msgstr "E311: RestaÅ­ro interrompita"
+
+msgid ""
+"E312: Errors detected while recovering; look for lines starting with ???"
+msgstr "E312: Eraroj dum restaÅ­ro; rigardu liniojn komencantajn per ???"
+
+msgid "See \":help E312\" for more information."
+msgstr "Vidu \":help E312\" por pliaj informoj."
+
+msgid "Recovery completed. You should check if everything is OK."
+msgstr "RestaÅ­ro finiÄis. Indus kontroli ĉu ĉio estas en ordo."
+
+msgid ""
+"\n"
+"(You might want to write out this file under another name\n"
+msgstr ""
+"\n"
+"(Indas konservi tiun dosieron per alia nomo\n"
+
+msgid "and run diff with the original file to check for changes)"
+msgstr "kaj lanĉi diff kun la originala dosiero por kontroli la ÅanÄojn)"
+
+msgid "Recovery completed. Buffer contents equals file contents."
+msgstr ""
+"RestaÅ­ro finiÄis. La enhavo de la bufro samas kun la enhavo de la dosiero."
+
+msgid ""
+"\n"
+"You may want to delete the .swp file now.\n"
+"\n"
+msgstr ""
+"\n"
+"La dosiero .swp nun forviÅindas.\n"
+"\n"
+
+msgid "Using crypt key from swap file for the text file.\n"
+msgstr ""
+"Uzas Ålosilon de ĉifrado el permutodosiero .swp por la teksta dosiero.\n"
+
+msgid "Swap files found:"
+msgstr "Permutodosiero .swp trovita:"
+
+msgid " In current directory:\n"
+msgstr " En la aktuala dosierujo:\n"
+
+msgid " Using specified name:\n"
+msgstr " Uzado de specifita nomo:\n"
+
+msgid " In directory "
+msgstr " En dosierujo "
+
+msgid " -- none --\n"
+msgstr " -- nenio --\n"
+
+msgid " owned by: "
+msgstr " posedata de: "
+
+msgid " dated: "
+msgstr " dato: "
+
+msgid " dated: "
+msgstr " dato: "
+
+msgid " [from Vim version 3.0]"
+msgstr " [de Vim versio 3.0]"
+
+msgid " [does not look like a Vim swap file]"
+msgstr " [ne aspektas kiel permutodosiero .swp de Vim]"
+
+msgid " file name: "
+msgstr " dosiernomo: "
+
+msgid ""
+"\n"
+" modified: "
+msgstr ""
+"\n"
+" modifita: "
+
+msgid "YES"
+msgstr "JES"
+
+msgid "no"
+msgstr "ne"
+
+msgid ""
+"\n"
+" user name: "
+msgstr ""
+"\n"
+" uzantonomo: "
+
+msgid " host name: "
+msgstr " komputila nomo: "
+
+msgid ""
+"\n"
+" host name: "
+msgstr ""
+"\n"
+" komputila nomo: "
+
+msgid ""
+"\n"
+" process ID: "
+msgstr ""
+"\n"
+" proceza ID: "
+
+msgid " (STILL RUNNING)"
+msgstr " (ANKORAŬ RULIĜAS)"
+
+msgid ""
+"\n"
+" [not usable with this version of Vim]"
+msgstr ""
+"\n"
+" [ne uzebla per tiu versio de Vim]"
+
+msgid ""
+"\n"
+" [not usable on this computer]"
+msgstr ""
+"\n"
+" [neuzebla per tiu komputilo]"
+
+msgid " [cannot be read]"
+msgstr " [nelegebla]"
+
+msgid " [cannot be opened]"
+msgstr " [nemalfermebla]"
+
+msgid "E313: Cannot preserve, there is no swap file"
+msgstr "E313: Ne eblas konservi, ne estas permutodosiero .swp"
+
+msgid "File preserved"
+msgstr "Dosiero konservita"
+
+msgid "E314: Preserve failed"
+msgstr "E314: Konservo malsukcesis"
+
+#, c-format
+msgid "E315: ml_get: invalid lnum: %ld"
+msgstr "E315: ml_get: nevalida lnum: %ld"
+
+#, c-format
+msgid "E316: ml_get: cannot find line %ld"
+msgstr "E316: ml_get: ne eblas trovi linion %ld"
+
+msgid "E317: pointer block id wrong 3"
+msgstr "E317: nevalida referenco de bloko id 3"
+
+msgid "stack_idx should be 0"
+msgstr "stack_idx devus esti 0"
+
+msgid "E318: Updated too many blocks?"
+msgstr "E318: Ĉu Äisdatigis tro da blokoj?"
+
+msgid "E317: pointer block id wrong 4"
+msgstr "E317: nevalida referenco de bloko id 4"
+
+msgid "deleted block 1?"
+msgstr "ĉu forviÅita bloko 1?"
+
+#, c-format
+msgid "E320: Cannot find line %ld"
+msgstr "E320: Ne eblas trovi linion %ld"
+
+msgid "E317: pointer block id wrong"
+msgstr "E317: nevalida referenco de bloko id"
+
+msgid "pe_line_count is zero"
+msgstr "pe_line_count estas nul"
+
+#, c-format
+msgid "E322: line number out of range: %ld past the end"
+msgstr "E322: numero de linio ekster limoj: %ld preter la fino"
+
+#, c-format
+msgid "E323: line count wrong in block %ld"
+msgstr "E323: nevalida nombro de linioj en bloko %ld"
+
+msgid "Stack size increases"
+msgstr "Stako pligrandiÄas"
+
+msgid "E317: pointer block id wrong 2"
+msgstr "E317: nevalida referenco de bloko id 2"
+
+#, c-format
+msgid "E773: Symlink loop for \"%s\""
+msgstr "E773: Buklo de simbolaj ligiloj por \"%s\""
+
+msgid "E325: ATTENTION"
+msgstr "E325: ATENTO"
+
+msgid ""
+"\n"
+"Found a swap file by the name \""
+msgstr ""
+"\n"
+"Trovis permutodosieron .swp kun la nomo \""
+
+msgid "While opening file \""
+msgstr "Dum malfermo de dosiero \""
+
+msgid " CANNOT BE FOUND"
+msgstr " NETROVITA"
+
+msgid " NEWER than swap file!\n"
+msgstr " PLI NOVA ol permutodosiero .swp!\n"
+
+msgid ""
+"\n"
+"(1) Another program may be editing the same file. If this is the case,\n"
+" be careful not to end up with two different instances of the same\n"
+" file when making changes. Quit, or continue with caution.\n"
+msgstr ""
+"\n"
+"(1) Alia programo eble redaktas la saman dosieron. Se jes, estu singarda\n"
+" por ne havi du malsamajn aperojn de la sama dosiero, kiam vi faros\n"
+" ÅanÄojn. Eliru aÅ­ daÅ­rigu singarde.\n"
+
+msgid "(2) An edit session for this file crashed.\n"
+msgstr "(2) Redakta seanco de tiu dosiero kolapsis.\n"
+
+msgid " If this is the case, use \":recover\" or \"vim -r "
+msgstr " Se veras, uzu \":recover\" aÅ­ \"vim -r "
+
+msgid ""
+"\"\n"
+" to recover the changes (see \":help recovery\").\n"
+msgstr ""
+"\"\n"
+" por restaÅ­ri la ÅanÄojn (vidu \":help recovery\").\n"
+
+msgid " If you did this already, delete the swap file \""
+msgstr " Se vi jam faris Äin, forviÅu la permutodosieron .swp \""
+
+msgid ""
+"\"\n"
+" to avoid this message.\n"
+msgstr ""
+"\"\n"
+" por eviti tiun mesaÄon.\n"
+
+msgid "Swap file \""
+msgstr "Permutodosiero .swp \""
+
+msgid "\" already exists!"
+msgstr "\" jam ekzistas!"
+
+msgid "VIM - ATTENTION"
+msgstr "VIM - ATENTO"
+
+msgid "Swap file already exists!"
+msgstr "Permutodosiero .swp jam ekzistas!"
+
+# AM: ĉu Vim konvertos la unuliterajn respondojn de la uzulo?
+# DP: jes, la '&' respondoj bone funkcias (mi kontrolis)
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"&Malfermi nurlegreÄime\n"
+"Tamen &redakti\n"
+"Res&taÅ­ri\n"
+"&Eliri\n"
+"Ĉe&sigi"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Delete it\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"&Malfermi nurlegreÄime\n"
+"Tamen &redakti\n"
+"Res&taÅ­ri\n"
+"&ForviÅi\n"
+"&Eliri\n"
+"Ĉe&sigi"
+
+msgid "E326: Too many swap files found"
+msgstr "E326: Tro da dosieroj trovitaj"
+
+msgid "E327: Part of menu-item path is not sub-menu"
+msgstr "E327: Parto de vojo de menuero ne estas sub-menuo"
+
+msgid "E328: Menu only exists in another mode"
+msgstr "E328: Menuo nur ekzistas en alia reÄimo"
+
+#, c-format
+msgid "E329: No menu \"%s\""
+msgstr "E329: Neniu menuo \"%s\""
+
+msgid "E792: Empty menu name"
+msgstr "E792: Malplena nomo de menuo"
+
+msgid "E330: Menu path must not lead to a sub-menu"
+msgstr "E330: Vojo de menuo ne rajtas konduki al sub-menuo"
+
+msgid "E331: Must not add menu items directly to menu bar"
+msgstr "E331: Aldono de menueroj direkte al menuzono estas malpermesita"
+
+msgid "E332: Separator cannot be part of a menu path"
+msgstr "E332: Disigilo ne rajtas esti ero de vojo de menuo"
+
+msgid ""
+"\n"
+"--- Menus ---"
+msgstr ""
+"\n"
+"--- Menuoj ---"
+
+msgid "Tear off this menu"
+msgstr "Disigi tiun menuon"
+
+#, c-format
+msgid "E335: Menu not defined for %s mode"
+msgstr "E335: Menuo ne estas difinita por reÄimo %s"
+
+msgid "E333: Menu path must lead to a menu item"
+msgstr "E333: Vojo de menuo devas konduki al menuero"
+
+#, c-format
+msgid "E334: Menu not found: %s"
+msgstr "E334: Menuo netrovita: %s"
+
+msgid "E336: Menu path must lead to a sub-menu"
+msgstr "E336: Vojo de menuo devas konduki al sub-menuo"
+
+msgid "E337: Menu not found - check menu names"
+msgstr "E337: Menuo ne trovita - kontrolu nomojn de menuoj"
+
+#, c-format
+msgid "Error detected while processing %s:"
+msgstr "Eraro okazis dum traktado de %s:"
+
+#, c-format
+msgid "line %4ld:"
+msgstr "linio %4ld:"
+
+#, c-format
+msgid "E354: Invalid register name: '%s'"
+msgstr "E354: Nevalida nomo de reÄistro: '%s'"
+
+msgid "Messages maintainer: Bram Moolenaar <Bram@vim.org>"
+msgstr "Flegado de mesaÄoj: Dominique PELLÉ <dominique.pelle@gmail.com>"
+
+msgid "Interrupt: "
+msgstr "Interrompo: "
+
+msgid "Press ENTER or type command to continue"
+msgstr "Premu ENEN-KLAVON aÅ­ tajpu komandon por daÅ­rigi"
+
+#, c-format
+msgid "%s line %ld"
+msgstr "%s linio %ld"
+
+msgid "-- More --"
+msgstr "-- Pli --"
+
+msgid " SPACE/d/j: screen/page/line down, b/u/k: up, q: quit "
+msgstr " SPACETO/d/j: ekrano/paÄo/sub linio, b/u/k: supre, q: eliri "
+
+msgid "Question"
+msgstr "Demando"
+
+msgid ""
+"&Yes\n"
+"&No"
+msgstr ""
+"&Jes\n"
+"&Ne"
+
+# AM: ĉu Vim konvertos unuliterajn respondojn?
+# DP: jes, '&' bone funkcias (mi kontrolis)
+msgid ""
+"&Yes\n"
+"&No\n"
+"Save &All\n"
+"&Discard All\n"
+"&Cancel"
+msgstr ""
+"&Jes\n"
+"&Ne\n"
+"&Konservi Ĉion\n"
+"&Forlasi Ĉion\n"
+"&Rezigni"
+
+msgid "Select Directory dialog"
+msgstr "Dialogujo de dosiera elekto"
+
+msgid "Save File dialog"
+msgstr "Dialogujo de dosiera konservo"
+
+msgid "Open File dialog"
+msgstr "Dialogujo de dosiera malfermo"
+
+msgid "E338: Sorry, no file browser in console mode"
+msgstr "E338: BedaÅ­rinde ne estas dosierfoliumilo en konzola reÄimo"
+
+msgid "E766: Insufficient arguments for printf()"
+msgstr "E766: Ne sufiĉaj argumentoj por printf()"
+
+msgid "E807: Expected Float argument for printf()"
+msgstr "E807: Atendis Glitpunktnombron kiel argumenton de printf()"
+
+msgid "E767: Too many arguments to printf()"
+msgstr "E767: Tro da argumentoj al printf()"
+
+msgid "W10: Warning: Changing a readonly file"
+msgstr "W10: Averto: ÅœanÄo de nurlegebla dosiero"
+
+msgid "Type number and <Enter> or click with mouse (empty cancels): "
+msgstr ""
+"Tajpu nombron kaj <Enenklavon> aÅ­ alklaku per la muso (malpleno rezignas): "
+
+msgid "Type number and <Enter> (empty cancels): "
+msgstr "Tajpu nombron kaj <Enenklavon> (malpleno rezignas): "
+
+#, c-format
+msgid "%ld more line"
+msgid_plural "%ld more lines"
+msgstr[0] "%ld plia linio"
+msgstr[1] "%ld pliaj linioj"
+
+#, c-format
+msgid "%ld line less"
+msgid_plural "%ld fewer lines"
+msgstr[0] "%ld malplia linio"
+msgstr[1] "%ld malpliaj linioj"
+
+msgid " (Interrupted)"
+msgstr " (Interrompita)"
+
+msgid "Beep!"
+msgstr "Bip!"
+
+msgid "ERROR: "
+msgstr "ERARO: "
+
+#, c-format
+msgid ""
+"\n"
+"[bytes] total alloc-freed %lu-%lu, in use %lu, peak use %lu\n"
+msgstr ""
+"\n"
+"[bajtoj] totalaj disponigitaj/maldisponigitaj %lu-%lu, nun uzataj %lu, "
+"kulmina uzo %lu\n"
+
+#, c-format
+msgid ""
+"[calls] total re/malloc()'s %lu, total free()'s %lu\n"
+"\n"
+msgstr ""
+"[alvokoj] totalaj re/malloc() %lu, totalaj free() %lu\n"
+"\n"
+
+msgid "E340: Line is becoming too long"
+msgstr "E340: Linio iÄas tro longa"
+
+#, c-format
+msgid "E341: Internal error: lalloc(%ld, )"
+msgstr "E341: Interna eraro: lalloc(%ld, )"
+
+#, c-format
+msgid "E342: Out of memory! (allocating %lu bytes)"
+msgstr "E342: Ne plu restas memoro! (disponigo de %lu bajtoj)"
+
+#, c-format
+msgid "Calling shell to execute: \"%s\""
+msgstr "Alvokas Åelon por plenumi: \"%s\""
+
+msgid "E545: Missing colon"
+msgstr "E545: Mankas dupunkto"
+
+msgid "E546: Illegal mode"
+msgstr "E546: ReÄimo nepermesata"
+
+msgid "E547: Illegal mouseshape"
+msgstr "E547: Nevalida formo de muskursoro"
+
+msgid "E548: digit expected"
+msgstr "E548: cifero atendata"
+
+msgid "E549: Illegal percentage"
+msgstr "E549: Nevalida procento"
+
+msgid "E854: path too long for completion"
+msgstr "E854: tro longa vojo por kompletigo"
+
+#, c-format
+msgid ""
+"E343: Invalid path: '**[number]' must be at the end of the path or be "
+"followed by '%s'."
+msgstr ""
+"E343: Nevalida vojo: '**[nombro]' devas esti ĉe la fino de la vojo aŭ "
+"sekvita de '%s'."
+
+#, c-format
+msgid "E344: Can't find directory \"%s\" in cdpath"
+msgstr "E344: Ne eblas trovi dosierujon \"%s\" en cdpath"
+
+#, c-format
+msgid "E345: Can't find file \"%s\" in path"
+msgstr "E345: Ne eblas trovi dosieron \"%s\" en serĉvojo"
+
+#, c-format
+msgid "E346: No more directory \"%s\" found in cdpath"
+msgstr "E346: Ne plu trovis dosierujon \"%s\" en cdpath"
+
+#, c-format
+msgid "E347: No more file \"%s\" found in path"
+msgstr "E347: Ne plu trovis dosieron \"%s\" en serĉvojo"
+
+#, c-format
+msgid "E668: Wrong access mode for NetBeans connection info file: \"%s\""
+msgstr ""
+"E668: Nevalida permeso de dosiero de informo de konekto NetBeans: \"%s\""
+
+#, c-format
+msgid "E658: NetBeans connection lost for buffer %ld"
+msgstr "E658: Konekto de NetBeans perdita por bufro %ld"
+
+msgid "E838: netbeans is not supported with this GUI"
+msgstr "E838: netbeans ne estas subtenata kun tiu grafika interfaco"
+
+msgid "E511: netbeans already connected"
+msgstr "E511: nebeans jam konektata"
+
+#, c-format
+msgid "E505: %s is read-only (add ! to override)"
+msgstr "E505: %s estas nurlegebla (aldonu ! por transpasi)"
+
+msgid "E349: No identifier under cursor"
+msgstr "E349: Neniu identigilo sub la kursoro"
+
+msgid "E774: 'operatorfunc' is empty"
+msgstr "E774: 'operatorfunc' estas malplena"
+
+# DP: ĉu Eval devas esti tradukita?
+msgid "E775: Eval feature not available"
+msgstr "E775: Eval eblo ne disponeblas"
+
+msgid "Warning: terminal cannot highlight"
+msgstr "Averto: terminalo ne povas emfazi"
+
+msgid "E348: No string under cursor"
+msgstr "E348: Neniu ĉeno sub la kursoro"
+
+msgid "E352: Cannot erase folds with current 'foldmethod'"
+msgstr "E352: Ne eblas forviÅi faldon per aktuala 'foldmethod'"
+
+msgid "E664: changelist is empty"
+msgstr "E664: Listo de ÅanÄoj estas malplena"
+
+msgid "E662: At start of changelist"
+msgstr "E662: Ĉe komenco de ÅanÄlisto"
+
+msgid "E663: At end of changelist"
+msgstr "E663: Ĉe fino de ÅanÄlisto"
+
+msgid "Type :qa! and press <Enter> to abandon all changes and exit Vim"
+msgstr ""
+"Tajpu :qa! kaj premu <Enenklavon> por forlasi ĉiujn ÅanÄojn kaj eliri el "
+"Vim"
+
+#, c-format
+msgid "%ld line %sed %d time"
+msgid_plural "%ld line %sed %d times"
+msgstr[0] "%ld linio %sita %d foje"
+msgstr[1] "%ld linio %sita %d foje"
+
+#, c-format
+msgid "%ld lines %sed %d time"
+msgid_plural "%ld lines %sed %d times"
+msgstr[0] "%ld linioj %sitaj %d foje"
+msgstr[1] "%ld linioj %sitaj %d foje"
+
+#, c-format
+msgid "%ld lines to indent... "
+msgstr "%ld krommarÄenendaj linioj... "
+
+#, c-format
+msgid "%ld line indented "
+msgid_plural "%ld lines indented "
+msgstr[0] "%ld linio krommarÄenita "
+msgstr[1] "%ld linioj krommarÄenitaj "
+
+msgid "E748: No previously used register"
+msgstr "E748: Neniu reÄistro antaÅ­e uzata"
+
+msgid "cannot yank; delete anyway"
+msgstr "ne eblas kopii; tamen forviÅi"
+
+#, c-format
+msgid "%ld line changed"
+msgid_plural "%ld lines changed"
+msgstr[0] "%ld linio ÅanÄita"
+msgstr[1] "%ld linioj ÅanÄitaj"
+
+#, c-format
+msgid "freeing %ld lines"
+msgstr "malokupas %ld liniojn"
+
+#, c-format
+msgid " into \"%c"
+msgstr " en \"%c"
+
+#, c-format
+msgid "block of %ld line yanked%s"
+msgid_plural "block of %ld lines yanked%s"
+msgstr[0] "bloko de %ld linio kopiita%s"
+msgstr[1] "bloko de %ld linioj kopiitaj%s"
+
+#, c-format
+msgid "%ld line yanked%s"
+msgid_plural "%ld lines yanked%s"
+msgstr[0] "%ld linio kopiita%s"
+msgstr[1] "%ld linioj kopiitaj%s"
+
+#, c-format
+msgid "E353: Nothing in register %s"
+msgstr "E353: Nenio en reÄistro %s"
+
+msgid ""
+"\n"
+"--- Registers ---"
+msgstr ""
+"\n"
+"--- ReÄistroj ---"
+
+msgid "Illegal register name"
+msgstr "Nevalida nomo de reÄistro"
+
+msgid ""
+"\n"
+"# Registers:\n"
+msgstr ""
+"\n"
+"# ReÄistroj:\n"
+
+#, c-format
+msgid "E574: Unknown register type %d"
+msgstr "E574: Nekonata tipo de reÄistro %d"
+
+msgid ""
+"E883: search pattern and expression register may not contain two or more "
+"lines"
+msgstr ""
+"E883: serĉa Åablono kaj esprima reÄistro ne povas enhavi du aÅ­ pliajn liniojn"
+
+#, c-format
+msgid "%ld Cols; "
+msgstr "%ld Kolumnoj; "
+
+#, c-format
+msgid "Selected %s%ld of %ld Lines; %lld of %lld Words; %lld of %lld Bytes"
+msgstr ""
+"Apartigis %s%ld de %ld Linioj; %lld de %lld Vortoj; %lld de %lld Bajtoj"
+
+#, c-format
+msgid ""
+"Selected %s%ld of %ld Lines; %lld of %lld Words; %lld of %lld Chars; %lld of "
+"%lld Bytes"
+msgstr ""
+"Apartigis %s%ld de %ld Linioj; %lld de %lld Vortoj; %lld de %lld Signoj; "
+"%lld de %lld Bajtoj"
+
+#, c-format
+msgid "Col %s of %s; Line %ld of %ld; Word %lld of %lld; Byte %lld of %lld"
+msgstr "Kol %s de %s; Linio %ld de %ld; Vorto %lld de %lld; Bajto %lld de %lld"
+
+#, c-format
+msgid ""
+"Col %s of %s; Line %ld of %ld; Word %lld of %lld; Char %lld of %lld; Byte "
+"%lld of %lld"
+msgstr ""
+"Kol %s de %s; Linio %ld de %ld; Vorto %lld de %lld; Signo %lld de %lld; "
+"Bajto %lld de %lld"
+
+#, c-format
+msgid "(+%lld for BOM)"
+msgstr "(+%lld por BOM)"
+
+msgid "Thanks for flying Vim"
+msgstr "Dankon pro flugi per Vim"
+
+msgid "E518: Unknown option"
+msgstr "E518: Nekonata opcio"
+
+msgid "E519: Option not supported"
+msgstr "E519: Opcio ne subtenata"
+
+msgid "E520: Not allowed in a modeline"
+msgstr "E520: Nepermesebla en reÄimlinio"
+
+msgid "E846: Key code not set"
+msgstr "E846: Klavkodo ne agordita"
+
+msgid "E521: Number required after ="
+msgstr "E521: Nombro bezonata malantaÅ­ ="
+
+msgid "E522: Not found in termcap"
+msgstr "E522: Netrovita en termcap"
+
+#, c-format
+msgid "E539: Illegal character <%s>"
+msgstr "E539: Nevalida signo <%s>"
+
+#, c-format
+msgid "For option %s"
+msgstr "Por opcio %s"
+
+msgid "E529: Cannot set 'term' to empty string"
+msgstr "E529: Ne eblas agordi 'term' al malplena ĉeno"
+
+msgid "E530: Cannot change term in GUI"
+msgstr "E530: term ne ÅanÄeblas en grafika interfaco"
+
+msgid "E531: Use \":gui\" to start the GUI"
+msgstr "E531: Uzu \":gui\" por lanĉi la grafikan interfacon"
+
+msgid "E589: 'backupext' and 'patchmode' are equal"
+msgstr "E589: 'backupext' kaj 'patchmode' estas egalaj"
+
+msgid "E834: Conflicts with value of 'listchars'"
+msgstr "E834: Konfliktoj kun la valoro de 'listchars'"
+
+msgid "E835: Conflicts with value of 'fillchars'"
+msgstr "E835: Konfliktoj kun la valoro de 'fillchars'"
+
+msgid "E617: Cannot be changed in the GTK+ 2 GUI"
+msgstr "E617: Ne ÅanÄeblas en la grafika interfaco GTK+ 2"
+
+#, c-format
+msgid "E950: Cannot convert between %s and %s"
+msgstr "E950: Ne eblas konverti de %s al %s"
+
+msgid "E524: Missing colon"
+msgstr "E524: Mankas dupunkto"
+
+msgid "E525: Zero length string"
+msgstr "E525: Ĉeno de nula longo"
+
+#, c-format
+msgid "E526: Missing number after <%s>"
+msgstr "E526: Mankas nombro malantaÅ­ <%s>"
+
+msgid "E527: Missing comma"
+msgstr "E527: Mankas komo"
+
+msgid "E528: Must specify a ' value"
+msgstr "E528: Devas specifi ' valoron"
+
+msgid "E595: contains unprintable or wide character"
+msgstr "E595: enhavas nepreseblan aÅ­ plurĉellarÄan signon"
+
+msgid "E596: Invalid font(s)"
+msgstr "E596: Nevalida(j) tiparo(j)"
+
+msgid "E597: can't select fontset"
+msgstr "E597: ne eblas elekti tiparon"
+
+msgid "E598: Invalid fontset"
+msgstr "E598: Nevalida tiparo"
+
+msgid "E533: can't select wide font"
+msgstr "E533: ne eblas elekti larÄan tiparon"
+
+msgid "E534: Invalid wide font"
+msgstr "E534: Nevalida larÄa tiparo"
+
+#, c-format
+msgid "E535: Illegal character after <%c>"
+msgstr "E535: Nevalida signo malantaÅ­ <%c>"
+
+msgid "E536: comma required"
+msgstr "E536: komo bezonata"
+
+#, c-format
+msgid "E537: 'commentstring' must be empty or contain %s"
+msgstr "E537: 'commentstring' devas esti malplena aÅ­ enhavi %s"
+
+msgid "E538: No mouse support"
+msgstr "E538: Neniu muso subtenata"
+
+msgid "E540: Unclosed expression sequence"
+msgstr "E540: '}' mankas"
+
+msgid "E541: too many items"
+msgstr "E541: tro da elementoj"
+
+msgid "E542: unbalanced groups"
+msgstr "E542: misekvilibraj grupoj"
+
+msgid "E946: Cannot make a terminal with running job modifiable"
+msgstr "E946: Ne eblas igi modifebla terminalon kun aktiva tasko"
+
+msgid "E590: A preview window already exists"
+msgstr "E590: AntaÅ­vida fenestro jam ekzistas"
+
+msgid "W17: Arabic requires UTF-8, do ':set encoding=utf-8'"
+msgstr "W17: La araba bezonas UTF-8, tajpu \":set encoding=utf-8\""
+
+msgid "E954: 24-bit colors are not supported on this environment"
+msgstr "E954: 24-bitaj koloroj ne estas subtenataj en tiu sistemo"
+
+#, c-format
+msgid "E593: Need at least %d lines"
+msgstr "E593: Bezonas almenaÅ­ %d liniojn"
+
+#, c-format
+msgid "E594: Need at least %d columns"
+msgstr "E594: Bezonas almenaÅ­ %d kolumnojn"
+
+#, c-format
+msgid "E355: Unknown option: %s"
+msgstr "E355: Nekonata opcio: %s"
+
+#, c-format
+msgid "E521: Number required: &%s = '%s'"
+msgstr "E521: Nombro bezonata: &%s = '%s'"
+
+msgid ""
+"\n"
+"--- Terminal codes ---"
+msgstr ""
+"\n"
+"--- Kodoj de terminalo ---"
+
+msgid ""
+"\n"
+"--- Global option values ---"
+msgstr ""
+"\n"
+"--- Mallokaj opcioj ---"
+
+msgid ""
+"\n"
+"--- Local option values ---"
+msgstr ""
+"\n"
+"--- Valoroj de lokaj opcioj ---"
+
+msgid ""
+"\n"
+"--- Options ---"
+msgstr ""
+"\n"
+"--- Opcioj ---"
+
+msgid "E356: get_varp ERROR"
+msgstr "E356: ERARO get_varp"
+
+#, c-format
+msgid "E357: 'langmap': Matching character missing for %s"
+msgstr "E357: 'langmap': Kongrua signo mankas por %s"
+
+#, c-format
+msgid "E358: 'langmap': Extra characters after semicolon: %s"
+msgstr "E358: 'langmap': Ekstraj signoj malantaÅ­ punktokomo: %s"
+
+msgid "cannot open "
+msgstr "ne eblas malfermi "
+
+msgid "VIM: Can't open window!\n"
+msgstr "VIM: Ne eblas malfermi fenestron!\n"
+
+msgid "Need Amigados version 2.04 or later\n"
+msgstr "Bezonas version 2.04 de Amigados aÅ­ pli novan\n"
+
+#, c-format
+msgid "Need %s version %ld\n"
+msgstr "Bezonas %s-on versio %ld\n"
+
+msgid "Cannot open NIL:\n"
+msgstr "Ne eblas malfermi NIL:\n"
+
+msgid "Cannot create "
+msgstr "Ne eblas krei "
+
+#, c-format
+msgid "Vim exiting with %d\n"
+msgstr "Vim eliras kun %d\n"
+
+msgid "cannot change console mode ?!\n"
+msgstr "ne eblas ÅanÄi reÄimon de konzolo?!\n"
+
+msgid "mch_get_shellsize: not a console??\n"
+msgstr "mch_get_shellsize: ne estas konzolo??\n"
+
+msgid "E360: Cannot execute shell with -f option"
+msgstr "E360: Ne eblas plenumi Åelon kun opcio -f"
+
+msgid "Cannot execute "
+msgstr "Ne eblas plenumi "
+
+msgid "shell "
+msgstr "Åelo "
+
+msgid " returned\n"
+msgstr " liveris\n"
+
+msgid "ANCHOR_BUF_SIZE too small."
+msgstr "ANCHOR_BUF_SIZE tro malgranda."
+
+msgid "I/O ERROR"
+msgstr "ERARO DE ENIGO/ELIGO"
+
+msgid "Message"
+msgstr "MesaÄo"
+
+msgid "E237: Printer selection failed"
+msgstr "E237: Elekto de presilo malsukcesis"
+
+#, c-format
+msgid "to %s on %s"
+msgstr "al %s de %s"
+
+#, c-format
+msgid "E613: Unknown printer font: %s"
+msgstr "E613: Nekonata tiparo de presilo: %s"
+
+#, c-format
+msgid "E238: Print error: %s"
+msgstr "E238: Eraro de presado: %s"
+
+#, c-format
+msgid "Printing '%s'"
+msgstr "Presas '%s'"
+
+#, c-format
+msgid "E244: Illegal charset name \"%s\" in font name \"%s\""
+msgstr "E244: Nevalida nomo de signaro \"%s\" en nomo de tiparo \"%s\""
+
+#, c-format
+msgid "E244: Illegal quality name \"%s\" in font name \"%s\""
+msgstr "E244: Nevalida nomo de kvalito \"%s\" en nomo de tiparo \"%s\""
+
+#, c-format
+msgid "E245: Illegal char '%c' in font name \"%s\""
+msgstr "E245: Nevalida signo '%c' en nomo de tiparo \"%s\""
+
+#, c-format
+msgid "Opening the X display took %ld msec"
+msgstr "Malfermo de vidigo X daÅ­ris %ld msek"
+
+msgid ""
+"\n"
+"Vim: Got X error\n"
+msgstr ""
+"\n"
+"Vim: Alvenis X eraro\n"
+
+msgid "Testing the X display failed"
+msgstr "Testo de la vidigo X malsukcesis"
+
+msgid "Opening the X display timed out"
+msgstr "Tempolimo okazis dum malfermo de vidigo X"
+
+msgid ""
+"\n"
+"Could not get security context for "
+msgstr ""
+"\n"
+"Ne povis akiri kuntekston de sekureco por "
+
+msgid ""
+"\n"
+"Could not set security context for "
+msgstr ""
+"\n"
+"Ne povis Åalti kuntekston de sekureco por "
+
+#, c-format
+msgid "Could not set security context %s for %s"
+msgstr "Ne povis Åalti kuntekston de sekureco %s por %s"
+
+#, c-format
+msgid "Could not get security context %s for %s. Removing it!"
+msgstr ""
+"Ne povis akiri kuntekston de sekureco %s por %s. Äœi nun estas forigata!"
+
+msgid ""
+"\n"
+"Cannot execute shell sh\n"
+msgstr ""
+"\n"
+"Ne eblas plenumi Åelon sh\n"
+
+msgid ""
+"\n"
+"shell returned "
+msgstr ""
+"\n"
+"Åelo liveris "
+
+msgid ""
+"\n"
+"Cannot create pipes\n"
+msgstr ""
+"\n"
+"Ne eblas krei duktojn\n"
+
+msgid ""
+"\n"
+"Cannot fork\n"
+msgstr ""
+"\n"
+"Ne eblas forki\n"
+
+msgid ""
+"\n"
+"Cannot execute shell "
+msgstr ""
+"\n"
+"Ne eblas plenumi Åelon "
+
+msgid ""
+"\n"
+"Command terminated\n"
+msgstr ""
+"\n"
+"Komando terminigita\n"
+
+msgid "XSMP lost ICE connection"
+msgstr "XSMP perdis la konekton ICE"
+
+#, c-format
+msgid "dlerror = \"%s\""
+msgstr "dlerror = \"%s\""
+
+msgid "Opening the X display failed"
+msgstr "Malfermo de vidigo X malsukcesis"
+
+msgid "XSMP handling save-yourself request"
+msgstr "XSMP: traktado de peto konservi-mem"
+
+msgid "XSMP opening connection"
+msgstr "XSMP: malfermo de konekto"
+
+msgid "XSMP ICE connection watch failed"
+msgstr "XSMP: kontrolo de konekto ICE malsukcesis"
+
+#, c-format
+msgid "XSMP SmcOpenConnection failed: %s"
+msgstr "XSMP: SmcOpenConnection malsukcesis: %s"
+
+msgid "At line"
+msgstr "Ĉe linio"
+
+msgid "Could not load vim32.dll!"
+msgstr "Ne eblis Åargi vim32.dll!"
+
+msgid "VIM Error"
+msgstr "Eraro de VIM"
+
+msgid "Could not fix up function pointers to the DLL!"
+msgstr "Ne eblis ripari referencojn de funkcioj al la DLL!"
+
+# DP: la eventoj estas tiuj, kiuj estas en la sekvantaj ĉenoj
+#, c-format
+msgid "Vim: Caught %s event\n"
+msgstr "Vim: Kaptis eventon %s\n"
+
+msgid "close"
+msgstr "fermo"
+
+msgid "logoff"
+msgstr "elsaluto"
+
+msgid "shutdown"
+msgstr "sistemfermo"
+
+msgid "E371: Command not found"
+msgstr "E371: Netrovebla komando"
+
+msgid ""
+"VIMRUN.EXE not found in your $PATH.\n"
+"External commands will not pause after completion.\n"
+"See :help win32-vimrun for more information."
+msgstr ""
+"VIMRUN.EXE ne troveblas en via $PATH.\n"
+"Eksteraj komandoj ne paÅ­zos post kompletigo.\n"
+"Vidu :help win32-vimrun por pliaj informoj."
+
+msgid "Vim Warning"
+msgstr "Averto de Vim"
+
+#, c-format
+msgid "shell returned %d"
+msgstr "la Åelo liveris %d"
+
+msgid "E926: Current location list was changed"
+msgstr "E926: Aktuala listo de lokoj ÅanÄiÄis"
+
+#, c-format
+msgid "E372: Too many %%%c in format string"
+msgstr "E372: Tro da %%%c en formata ĉeno"
+
+#, c-format
+msgid "E373: Unexpected %%%c in format string"
+msgstr "E373: Neatendita %%%c en formata ĉeno"
+
+msgid "E374: Missing ] in format string"
+msgstr "E374: Mankas ] en formata ĉeno"
+
+#, c-format
+msgid "E375: Unsupported %%%c in format string"
+msgstr "E375: Nesubtenata %%%c en formata ĉeno"
+
+#, c-format
+msgid "E376: Invalid %%%c in format string prefix"
+msgstr "E376: Nevalida %%%c en prefikso de formata ĉeno"
+
+#, c-format
+msgid "E377: Invalid %%%c in format string"
+msgstr "E377: Nevalida %%%c en formata ĉeno"
+
+msgid "E378: 'errorformat' contains no pattern"
+msgstr "E378: 'errorformat' enhavas neniun Åablonon"
+
+msgid "E379: Missing or empty directory name"
+msgstr "E379: Nomo de dosierujo mankas aÅ­ estas malplena"
+
+msgid "E553: No more items"
+msgstr "E553: Ne plu estas eroj"
+
+msgid "E924: Current window was closed"
+msgstr "E924: Aktuala vindozo fermiÄis"
+
+msgid "E925: Current quickfix was changed"
+msgstr "E925: Aktuala rapidriparo ÅanÄiÄis"
+
+#, c-format
+msgid "(%d of %d)%s%s: "
+msgstr "(%d de %d)%s%s: "
+
+msgid " (line deleted)"
+msgstr " (forviÅita linio)"
+
+#, c-format
+msgid "%serror list %d of %d; %d errors "
+msgstr "%slisto de eraroj %d de %d; %d eraroj"
+
+msgid "E380: At bottom of quickfix stack"
+msgstr "E380: Ĉe la subo de stako de rapidriparo"
+
+msgid "E381: At top of quickfix stack"
+msgstr "E381: Ĉe la supro de stako de rapidriparo"
+
+msgid "No entries"
+msgstr "Neniu ano"
+
+msgid "Error file"
+msgstr "Erara Dosiero"
+
+msgid "E683: File name missing or invalid pattern"
+msgstr "E683: Dosiernomo mankas aÅ­ nevalida Åablono"
+
+#, c-format
+msgid "Cannot open file \"%s\""
+msgstr "Ne eblas malfermi dosieron \"%s\""
+
+msgid "E681: Buffer is not loaded"
+msgstr "E681: Bufro ne estas Åargita"
+
+msgid "E777: String or List expected"
+msgstr "E777: Ĉeno aŭ Listo atendita"
+
+#, c-format
+msgid "E369: invalid item in %s%%[]"
+msgstr "E369: nevalida ano en %s%%[]"
+
+#, c-format
+msgid "E769: Missing ] after %s["
+msgstr "E769: Mankas ] malantaÅ­ %s["
+
+msgid "E944: Reverse range in character class"
+msgstr "E944: Inversa amplekso en klaso de signoj"
+
+msgid "E945: Range too large in character class"
+msgstr "E945: tro larÄa amplekso de klaso de signoj"
+
+#, c-format
+msgid "E53: Unmatched %s%%("
+msgstr "E53: Neekvilibra %s%%("
+
+#, c-format
+msgid "E54: Unmatched %s("
+msgstr "E54: Neekvilibra %s("
+
+#, c-format
+msgid "E55: Unmatched %s)"
+msgstr "E55: Neekvilibra %s"
+
+msgid "E66: \\z( not allowed here"
+msgstr "E66: \\z( estas nepermesebla tie"
+
+# DP: vidu http://www.thefreedictionary.com/et+al.
+msgid "E67: \\z1 - \\z9 not allowed here"
+msgstr "E67: \\z1 kaj aliaj estas nepermeseblaj tie"
+
+#, c-format
+msgid "E69: Missing ] after %s%%["
+msgstr "E69: Mankas ] malantaÅ­ %s%%["
+
+#, c-format
+msgid "E70: Empty %s%%[]"
+msgstr "E70: Malplena %s%%[]"
+
+msgid "E956: Cannot use pattern recursively"
+msgstr "E956: Ne eblas uzi Åablonon rekursie"
+
+msgid "E65: Illegal back reference"
+msgstr "E65: Nevalida retro-referenco"
+
+msgid "E339: Pattern too long"
+msgstr "E339: Åœablono tro longa"
+
+msgid "E50: Too many \\z("
+msgstr "E50: Tro da \\z("
+
+#, c-format
+msgid "E51: Too many %s("
+msgstr "E51: Tro da %s("
+
+msgid "E52: Unmatched \\z("
+msgstr "E52: Neekvilibra \\z("
+
+#, c-format
+msgid "E59: invalid character after %s@"
+msgstr "E59: nevalida signo malantaÅ­ %s@"
+
+#, c-format
+msgid "E60: Too many complex %s{...}s"
+msgstr "E60: Tro da kompleksaj %s{...}-oj"
+
+#, c-format
+msgid "E61: Nested %s*"
+msgstr "E61: Ingita %s*"
+
+#, c-format
+msgid "E62: Nested %s%c"
+msgstr "E62: Ingita %s%c"
+
+msgid "E63: invalid use of \\_"
+msgstr "E63: nevalida uzo de \\_"
+
+#, c-format
+msgid "E64: %s%c follows nothing"
+msgstr "E64: %s%c sekvas nenion"
+
+msgid "E68: Invalid character after \\z"
+msgstr "E68: Nevalida signo malantaÅ­ \\z"
+
+#, c-format
+msgid "E678: Invalid character after %s%%[dxouU]"
+msgstr "E678: Nevalida signo malantaÅ­ %s%%[dxouU]"
+
+#, c-format
+msgid "E71: Invalid character after %s%%"
+msgstr "E71: Nevalida signo malantaÅ­ %s%%"
+
+#, c-format
+msgid "E554: Syntax error in %s{...}"
+msgstr "E554: Sintaksa eraro en %s{...}"
+
+msgid "External submatches:\n"
+msgstr "Eksteraj subkongruoj:\n"
+
+#, c-format
+msgid "E888: (NFA regexp) cannot repeat %s"
+msgstr "E888: (NFA-regulesprimo) ne eblas ripeti %s"
+
+msgid ""
+"E864: \\%#= can only be followed by 0, 1, or 2. The automatic engine will be "
+"used "
+msgstr ""
+"E864: \\%#= povas nur esti sekvita de 0, 1, aÅ­ 2. La aÅ­tomata motoro de "
+"regulesprimo estos uzata "
+
+msgid "Switching to backtracking RE engine for pattern: "
+msgstr "ÅœanÄas al malavanca motoro de regulesprimo por Åablono: "
+
+msgid "E865: (NFA) Regexp end encountered prematurely"
+msgstr "E865: (NFA) Trovis finon de regulesprimo tro frue"
+
+#, c-format
+msgid "E866: (NFA regexp) Misplaced %c"
+msgstr "E866: (NFA-regulesprimo) Mispoziciigita %c"
+
+#, c-format
+msgid "E877: (NFA regexp) Invalid character class: %ld"
+msgstr "E877: (NFA-regulesprimo) Nevalida klaso de signoj: %ld"
+
+#, c-format
+msgid "E867: (NFA) Unknown operator '\\z%c'"
+msgstr "E867: (NFA) Nekonata operatoro '\\z%c'"
+
+msgid "E951: \\% value too large"
+msgstr "E951: tro larÄa valoro de \\%"
+
+#, c-format
+msgid "E867: (NFA) Unknown operator '\\%%%c'"
+msgstr "E867: (NFA) Nekonata operatoro '\\%%%c'"
+
+msgid "E868: Error building NFA with equivalence class!"
+msgstr "E868: Eraro dum prekomputado de NFA kun ekvivalentoklaso!"
+
+#, c-format
+msgid "E869: (NFA) Unknown operator '\\@%c'"
+msgstr "E869: (NFA) Nekonata operatoro '\\@%c'"
+
+msgid "E870: (NFA regexp) Error reading repetition limits"
+msgstr "E870: (NFS-regulesprimo) Eraro dum legado de limoj de ripeto"
+
+msgid "E871: (NFA regexp) Can't have a multi follow a multi"
+msgstr ""
+"E871: (NFA-regulesprimo) Ne povas havi mult-selekton tuj post alia mult-"
+"selekto"
+
+msgid "E872: (NFA regexp) Too many '('"
+msgstr "E872: (NFA-regulesprimo) tro da '('"
+
+msgid "E879: (NFA regexp) Too many \\z("
+msgstr "E879: (NFA-regulesprimo) tro da \\z("
+
+msgid "E873: (NFA regexp) proper termination error"
+msgstr "E873: (NFA-regulesprimo) propra end-eraro"
+
+msgid "Could not open temporary log file for writing, displaying on stderr... "
+msgstr ""
+"Ne povis malfermi provizoran protokolan dosieron por skribi, nun montras sur "
+"stderr..."
+
+msgid "E874: (NFA) Could not pop the stack!"
+msgstr "E874: (NFA) Ne povis elpreni de la staplo!"
+
+msgid ""
+"E875: (NFA regexp) (While converting from postfix to NFA), too many states "
+"left on stack"
+msgstr ""
+"E875: (NFA-regulesprimo) (dum konverto de postmeto al NFA), restas tro da "
+"statoj en la staplo"
+
+msgid "E876: (NFA regexp) Not enough space to store the whole NFA "
+msgstr "E876: (NFA-regulesprimo) ne sufiĉa spaco por enmemorigi la tutan NFA "
+
+msgid "E878: (NFA) Could not allocate memory for branch traversal!"
+msgstr "E878: (NFA) Ne povis asigni memoron por traigi branĉojn!"
+
+msgid " VREPLACE"
+msgstr " V-ANSTATAŬIGO"
+
+msgid " REPLACE"
+msgstr " ANSTATAŬIGO"
+
+msgid " REVERSE"
+msgstr " INVERSI"
+
+msgid " INSERT"
+msgstr " ENMETO"
+
+msgid " (insert)"
+msgstr " (enmeto)"
+
+msgid " (replace)"
+msgstr " (anstataÅ­igo)"
+
+msgid " (vreplace)"
+msgstr " (v-anstataÅ­igo)"
+
+msgid " Hebrew"
+msgstr " hebrea"
+
+msgid " Arabic"
+msgstr " araba"
+
+msgid " (paste)"
+msgstr " (algluo)"
+
+msgid " VISUAL"
+msgstr " VIDUMA"
+
+msgid " VISUAL LINE"
+msgstr " VIDUMA LINIO"
+
+msgid " VISUAL BLOCK"
+msgstr " VIDUMA BLOKO"
+
+msgid " SELECT"
+msgstr " APARTIGO"
+
+msgid " SELECT LINE"
+msgstr " APARTIGITA LINIO"
+
+msgid " SELECT BLOCK"
+msgstr " APARTIGITA BLOKO"
+
+msgid "recording"
+msgstr "registrado"
+
+#, c-format
+msgid "E383: Invalid search string: %s"
+msgstr "E383: Nevalida serĉenda ĉeno: %s"
+
+#, c-format
+msgid "E384: search hit TOP without match for: %s"
+msgstr "E384: serĉo atingis SUPRON sen trovi: %s"
+
+#, c-format
+msgid "E385: search hit BOTTOM without match for: %s"
+msgstr "E385: serĉo atingis SUBON sen trovi: %s"
+
+msgid "E386: Expected '?' or '/' after ';'"
+msgstr "E386: Atendis '?' aÅ­ '/' malantaÅ­ ';'"
+
+msgid " (includes previously listed match)"
+msgstr " (enhavas antaÅ­e listigitajn kongruojn)"
+
+msgid "--- Included files "
+msgstr "--- Inkluzivitaj dosieroj "
+
+msgid "not found "
+msgstr "netrovitaj "
+
+msgid "in path ---\n"
+msgstr "en serĉvojo ---\n"
+
+msgid " (Already listed)"
+msgstr " (Jam listigita)"
+
+msgid " NOT FOUND"
+msgstr " NETROVITA"
+
+#, c-format
+msgid "Scanning included file: %s"
+msgstr "Skanado de inkluzivitaj dosieroj: %s"
+
+#, c-format
+msgid "Searching included file %s"
+msgstr "Serĉado de inkluzivitaj dosieroj %s"
+
+msgid "E387: Match is on current line"
+msgstr "E387: Kongruo estas ĉe aktuala linio"
+
+msgid "All included files were found"
+msgstr "Ĉiuj inkluzivitaj dosieroj estis trovitaj"
+
+msgid "No included files"
+msgstr "Neniu inkluzivita dosiero"
+
+msgid "E388: Couldn't find definition"
+msgstr "E388: Ne eblis trovi difinon"
+
+msgid "E389: Couldn't find pattern"
+msgstr "E389: Ne eblis trovi Åablonon"
+
+msgid "Substitute "
+msgstr "AnstataÅ­igi "
+
+#, c-format
+msgid ""
+"\n"
+"# Last %sSearch Pattern:\n"
+"~"
+msgstr ""
+"\n"
+"# Lasta serĉa Åablono %s:\n"
+"~"
+
+msgid "E756: Spell checking is not enabled"
+msgstr "E756: Literumilo ne estas Åaltita"
+
+#, c-format
+msgid "Warning: Cannot find word list \"%s_%s.spl\" or \"%s_ascii.spl\""
+msgstr "Averto: Ne eblas trovi vortliston \"%s_%s.spl\" aÅ­ \"%s_ascii.spl\""
+
+#, c-format
+msgid "Warning: Cannot find word list \"%s.%s.spl\" or \"%s.ascii.spl\""
+msgstr "Averto: Ne eblas trovi vortliston \"%s.%s.spl\" aÅ­ \"%s.ascii.spl\""
+
+msgid "E797: SpellFileMissing autocommand deleted buffer"
+msgstr "E797: AÅ­tokomando SpellFileMissing forviÅis bufron"
+
+#, c-format
+msgid "Warning: region %s not supported"
+msgstr "Averto: regiono %s ne subtenata"
+
+msgid "Sorry, no suggestions"
+msgstr "BedaÅ­rinde ne estas sugestoj"
+
+#, c-format
+msgid "Sorry, only %ld suggestions"
+msgstr "BedaÅ­rinde estas nur %ld sugestoj"
+
+#, c-format
+msgid "Change \"%.*s\" to:"
+msgstr "AnstataÅ­igi \"%.*s\" per:"
+
+#, c-format
+msgid " < \"%.*s\""
+msgstr " < \"%.*s\""
+
+msgid "E752: No previous spell replacement"
+msgstr "E752: Neniu antaÅ­a literuma anstataÅ­igo"
+
+#, c-format
+msgid "E753: Not found: %s"
+msgstr "E753: Netrovita: %s"
+
+msgid "E758: Truncated spell file"
+msgstr "E758: Trunkita literuma dosiero"
+
+#, c-format
+msgid "Trailing text in %s line %d: %s"
+msgstr "Vosta teksto en %s linio %d: %s"
+
+#, c-format
+msgid "Affix name too long in %s line %d: %s"
+msgstr "Nomo de afikso tro longa en %s linio %d: %s"
+
+msgid "E761: Format error in affix file FOL, LOW or UPP"
+msgstr "E761: Eraro de formato en afiksa dosiero FOL, LOW aÅ­ UPP"
+
+msgid "E762: Character in FOL, LOW or UPP is out of range"
+msgstr "E762: Signo en FOL, LOW aÅ­ UPP estas ekster limoj"
+
+msgid "Compressing word tree..."
+msgstr "Densigas arbon de vortoj..."
+
+#, c-format
+msgid "Reading spell file \"%s\""
+msgstr "Legado de literuma dosiero \"%s\""
+
+msgid "E757: This does not look like a spell file"
+msgstr "E757: Tio ne Åajnas esti literuma dosiero"
+
+msgid "E771: Old spell file, needs to be updated"
+msgstr "E771: Malnova literuma dosiero, Äisdatigo bezonata"
+
+msgid "E772: Spell file is for newer version of Vim"
+msgstr "E772: Literuma dosiero estas por pli nova versio de Vim"
+
+msgid "E770: Unsupported section in spell file"
+msgstr "E770: Nesubtenata sekcio en literuma dosiero"
+
+#, c-format
+msgid "E778: This does not look like a .sug file: %s"
+msgstr "E778: Tio ne Åajnas esti dosiero .sug: %s"
+
+#, c-format
+msgid "E779: Old .sug file, needs to be updated: %s"
+msgstr "E779: Malnova dosiero .sug, bezonas Äisdatigon: %s"
+
+#, c-format
+msgid "E780: .sug file is for newer version of Vim: %s"
+msgstr "E780: Dosiero .sug estas por pli nova versio de Vim: %s"
+
+#, c-format
+msgid "E781: .sug file doesn't match .spl file: %s"
+msgstr "E781: Dosiero .sug ne kongruas kun dosiero .spl: %s"
+
+#, c-format
+msgid "E782: error while reading .sug file: %s"
+msgstr "E782: eraro dum legado de dosiero .sug: %s"
+
+#, c-format
+msgid "Reading affix file %s..."
+msgstr "Legado de afiksa dosiero %s..."
+
+#, c-format
+msgid "Conversion failure for word in %s line %d: %s"
+msgstr "Malsukceso dum konverto de vorto en %s linio %d: %s"
+
+#, c-format
+msgid "Conversion in %s not supported: from %s to %s"
+msgstr "Konverto en %s nesubtenata: de %s al %s"
+
+#, c-format
+msgid "Conversion in %s not supported"
+msgstr "Konverto en %s nesubtenata"
+
+#, c-format
+msgid "Invalid value for FLAG in %s line %d: %s"
+msgstr "Nevalida valoro de FLAG en %s linio %d: %s"
+
+#, c-format
+msgid "FLAG after using flags in %s line %d: %s"
+msgstr "FLAG post flagoj en %s linio %d: %s"
+
+#, c-format
+msgid ""
+"Defining COMPOUNDFORBIDFLAG after PFX item may give wrong results in %s line "
+"%d"
+msgstr ""
+"Difino de COMPOUNDFORBIDFLAG post ano PFX povas doni neÄustajn rezultojn en "
+"%s linio %d"
+
+#, c-format
+msgid ""
+"Defining COMPOUNDPERMITFLAG after PFX item may give wrong results in %s line "
+"%d"
+msgstr ""
+"Difino de COMPOUNDPERMITFLAG post ano PFX povas doni neÄustajn rezultojn en "
+"%s linio %d"
+
+#, c-format
+msgid "Wrong COMPOUNDRULES value in %s line %d: %s"
+msgstr "Nevalida valoro de COMPOUNDRULES en %s linio %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDWORDMAX value in %s line %d: %s"
+msgstr "Nevalida valoro de COMPOUNDWORDMAX en %s linio %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDMIN value in %s line %d: %s"
+msgstr "Nevalida valoro de COMPOUNDMIN en %s linio %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDSYLMAX value in %s line %d: %s"
+msgstr "Nevalida valoro de COMPOUNDSYLMAX en %s linio %d: %s"
+
+#, c-format
+msgid "Wrong CHECKCOMPOUNDPATTERN value in %s line %d: %s"
+msgstr "Nevalida valoro de CHECKCOMPOUNDPATTERN en %s linio %d: %s"
+
+#, c-format
+msgid "Different combining flag in continued affix block in %s line %d: %s"
+msgstr "Malsama flago de kombino en daÅ­ra bloko de afikso en %s linio %d: %s"
+
+#, c-format
+msgid "Duplicate affix in %s line %d: %s"
+msgstr "Ripetita afikso en %s linio %d: %s"
+
+#, c-format
+msgid ""
+"Affix also used for BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST in %s "
+"line %d: %s"
+msgstr ""
+"Afikso ankaÅ­ uzata por BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST en "
+"%s linio %d: %s"
+
+#, c-format
+msgid "Expected Y or N in %s line %d: %s"
+msgstr "Y aÅ­ N atendita en %s linio %d: %s"
+
+#, c-format
+msgid "Broken condition in %s line %d: %s"
+msgstr "Nevalida kondiĉo en %s linio %d: %s"
+
+#, c-format
+msgid "Expected REP(SAL) count in %s line %d"
+msgstr "Neatendita nombro REP(SAL) en %s linio %d"
+
+#, c-format
+msgid "Expected MAP count in %s line %d"
+msgstr "Neatendita nombro de MAPen %s linio %d"
+
+#, c-format
+msgid "Duplicate character in MAP in %s line %d"
+msgstr "Ripetita signo en MAP en %s linio %d"
+
+#, c-format
+msgid "Unrecognized or duplicate item in %s line %d: %s"
+msgstr "Neagnoskita aÅ­ ripetita ano en %s linio %d: %s"
+
+#, c-format
+msgid "Missing FOL/LOW/UPP line in %s"
+msgstr "Mankas linio FOL/LOW/UPP en %s"
+
+msgid "COMPOUNDSYLMAX used without SYLLABLE"
+msgstr "COMPOUNDSYLMAX uzita sen SYLLABLE"
+
+msgid "Too many postponed prefixes"
+msgstr "Tro da prokrastitaj prefiksoj"
+
+msgid "Too many compound flags"
+msgstr "Tro da kunmetitaj flagoj"
+
+msgid "Too many postponed prefixes and/or compound flags"
+msgstr "Tro da prokrastitaj prefiksoj kaj/aÅ­ kunmetitaj flagoj"
+
+#, c-format
+msgid "Missing SOFO%s line in %s"
+msgstr "Mankas SOFO%s-aj linioj en %s"
+
+#, c-format
+msgid "Both SAL and SOFO lines in %s"
+msgstr "AmbaÅ­ SAL kaj SOFO linioj en %s"
+
+#, c-format
+msgid "Flag is not a number in %s line %d: %s"
+msgstr "Flago ne estas nombro en %s linio %d: %s"
+
+#, c-format
+msgid "Illegal flag in %s line %d: %s"
+msgstr "Nevalida flago en %s linio %d: %s"
+
+#, c-format
+msgid "%s value differs from what is used in another .aff file"
+msgstr "Valoro de %s malsamas ol tiu en alia dosiero .aff"
+
+#, c-format
+msgid "Reading dictionary file %s..."
+msgstr "Legado de vortardosiero %s..."
+
+#, c-format
+msgid "E760: No word count in %s"
+msgstr "E760: Ne estas nombro de vortoj en %s"
+
+#, c-format
+msgid "line %6d, word %6ld - %s"
+msgstr "linio %6d, vorto %6ld - %s"
+
+#, c-format
+msgid "Duplicate word in %s line %d: %s"
+msgstr "Ripetita vorto en %s linio %d: %s"
+
+#, c-format
+msgid "First duplicate word in %s line %d: %s"
+msgstr "Unua ripetita vorto en %s linio %d: %s"
+
+#, c-format
+msgid "%d duplicate word(s) in %s"
+msgstr "%d ripetita(j) vorto(j) en %s"
+
+#, c-format
+msgid "Ignored %d word(s) with non-ASCII characters in %s"
+msgstr "%d ignorita(j) vorto(j) kun neaskiaj signoj en %s"
+
+#, c-format
+msgid "Reading word file %s..."
+msgstr "Legado de dosiero de vortoj %s..."
+
+#, c-format
+msgid "Duplicate /encoding= line ignored in %s line %d: %s"
+msgstr "Ripetita linio /encoding= ignorita en %s linio %d: %s"
+
+#, c-format
+msgid "/encoding= line after word ignored in %s line %d: %s"
+msgstr "Linio /encoding= post vorto ignorita en %s linio %d: %s"
+
+#, c-format
+msgid "Duplicate /regions= line ignored in %s line %d: %s"
+msgstr "Ripetita linio /regions= ignorita en %s linio %d: %s"
+
+#, c-format
+msgid "Too many regions in %s line %d: %s"
+msgstr "Tro da regionoj en %s linio %d: %s"
+
+#, c-format
+msgid "/ line ignored in %s line %d: %s"
+msgstr "Linio / ignorita en %s linio %d: %s"
+
+#, c-format
+msgid "Invalid region nr in %s line %d: %s"
+msgstr "Nevalida regiono nr en %s linio %d: %s"
+
+#, c-format
+msgid "Unrecognized flags in %s line %d: %s"
+msgstr "Nekonata flago en %s linio %d: %s"
+
+#, c-format
+msgid "Ignored %d words with non-ASCII characters"
+msgstr "Ignoris %d vorto(j)n kun neaskiaj signoj"
+
+msgid "E845: Insufficient memory, word list will be incomplete"
+msgstr "E845: Ne sufiĉe da memoro, vortlisto estos nekompleta."
+
+#, c-format
+msgid "Compressed %d of %d nodes; %d (%d%%) remaining"
+msgstr "Densigis %d de %d nodoj; %d (%d%%) restantaj"
+
+msgid "Reading back spell file..."
+msgstr "Relegas la dosieron de literumo..."
+
+msgid "Performing soundfolding..."
+msgstr "Fonetika analizado..."
+
+#, c-format
+msgid "Number of words after soundfolding: %ld"
+msgstr "Nombro de vortoj post fonetika analizado: %ld"
+
+#, c-format
+msgid "Total number of words: %d"
+msgstr "Totala nombro de vortoj: %d"
+
+#, c-format
+msgid "Writing suggestion file %s..."
+msgstr "Skribado de dosiero de sugesto %s..."
+
+#, c-format
+msgid "Estimated runtime memory use: %d bytes"
+msgstr "Evaluo de memoro uzata: %d bajtoj"
+
+msgid "E751: Output file name must not have region name"
+msgstr "E751: Nomo de eliga dosiero ne devas havi nomon de regiono"
+
+#, c-format
+msgid "E754: Only up to %ld regions supported"
+msgstr "E754: Nur Äis %ld regionoj subtenataj"
+
+#, c-format
+msgid "E755: Invalid region in %s"
+msgstr "E755: Nevalida regiono en %s"
+
+msgid "Warning: both compounding and NOBREAK specified"
+msgstr "Averto: ambaÅ­ NOBREAK kaj NOBREAK specifitaj"
+
+#, c-format
+msgid "Writing spell file %s..."
+msgstr "Skribado de literuma dosiero %s..."
+
+msgid "Done!"
+msgstr "Farita!"
+
+#, c-format
+msgid "E765: 'spellfile' does not have %ld entries"
+msgstr "E765: 'spellfile' ne havas %ld rikordojn"
+
+#, c-format
+msgid "Word '%.*s' removed from %s"
+msgstr "Vorto '%.*s' fortirita el %s"
+
+#, c-format
+msgid "Word '%.*s' added to %s"
+msgstr "Vorto '%.*s' aldonita al %s"
+
+msgid "E763: Word characters differ between spell files"
+msgstr "E763: Signoj de vorto malsamas tra literumaj dosieroj"
+
+msgid "E783: duplicate char in MAP entry"
+msgstr "E783: ripetita signo en rikordo MAP"
+
+msgid "No Syntax items defined for this buffer"
+msgstr "Neniu sintaksa elemento difinita por tiu bufro"
+
+msgid "'redrawtime' exceeded, syntax highlighting disabled"
+msgstr "'redrawtime' transpasita, sintaksa emfazo malÅaltita"
+
+msgid "syntax conceal on"
+msgstr "sintakso de conceal Åaltata"
+
+msgid "syntax conceal off"
+msgstr "sintakso de conceal malÅaltita"
+
+#, c-format
+msgid "E390: Illegal argument: %s"
+msgstr "E390: Nevalida argumento: %s"
+
+msgid "syntax case ignore"
+msgstr "sintakso ignoras usklecon"
+
+msgid "syntax case match"
+msgstr "sintakso konsideras usklecon"
+
+msgid "syntax spell toplevel"
+msgstr "literumado en teksto sen sintaksa grupo"
+
+msgid "syntax spell notoplevel"
+msgstr "sen literumado en teksto sen sintaksa grupo"
+
+msgid "syntax spell default"
+msgstr ""
+"literumado en teksto sen sintaksa grupo, nur se ne estas @Spell aÅ­ @NoSpell"
+
+msgid "syntax iskeyword "
+msgstr "sintakso iskeyword "
+
+msgid "syntax iskeyword not set"
+msgstr "sintakso iskeyword ne Åaltita"
+
+#, c-format
+msgid "E391: No such syntax cluster: %s"
+msgstr "E391: Nenia sintaksa fasko: %s"
+
+msgid "syncing on C-style comments"
+msgstr "sinkronigo per C-stilaj komentoj"
+
+msgid "no syncing"
+msgstr "neniu sinkronigo"
+
+msgid "syncing starts "
+msgstr "sinkronigo ekas "
+
+msgid " lines before top line"
+msgstr " linioj antaÅ­ supra linio"
+
+msgid ""
+"\n"
+"--- Syntax sync items ---"
+msgstr ""
+"\n"
+"--- Eroj de sintaksa sinkronigo ---"
+
+msgid ""
+"\n"
+"syncing on items"
+msgstr ""
+"\n"
+"sinkronigo per eroj"
+
+msgid ""
+"\n"
+"--- Syntax items ---"
+msgstr ""
+"\n"
+"--- Sintakseroj ---"
+
+#, c-format
+msgid "E392: No such syntax cluster: %s"
+msgstr "E392: Nenia sintaksa fasko: %s"
+
+msgid "minimal "
+msgstr "minimuma "
+
+msgid "maximal "
+msgstr "maksimuma "
+
+msgid "; match "
+msgstr "; kongruo "
+
+msgid " line breaks"
+msgstr " liniavancoj"
+
+msgid "E395: contains argument not accepted here"
+msgstr "E395: La argumento \"contains\" ne akcepteblas tie"
+
+msgid "E844: invalid cchar value"
+msgstr "E844: nevalida valoro de cchar"
+
+msgid "E393: group[t]here not accepted here"
+msgstr "E393: La argumento \"group[t]here\" ne akcepteblas tie"
+
+#, c-format
+msgid "E394: Didn't find region item for %s"
+msgstr "E394: Ne trovis regionan elementon por %s"
+
+msgid "E397: Filename required"
+msgstr "E397: Dosiernomo bezonata"
+
+msgid "E847: Too many syntax includes"
+msgstr "E847: Tro da sintaksaj inkluzivoj"
+
+#, c-format
+msgid "E789: Missing ']': %s"
+msgstr "E789: Mankas ']': %s"
+
+#, c-format
+msgid "E890: trailing char after ']': %s]%s"
+msgstr "E890: vosta signo malantaÅ­ ']': %s]%s"
+
+#, c-format
+msgid "E398: Missing '=': %s"
+msgstr "E398: Mankas '=': %s"
+
+#, c-format
+msgid "E399: Not enough arguments: syntax region %s"
+msgstr "E399: Ne sufiĉaj argumentoj: sintaksa regiono %s"
+
+msgid "E848: Too many syntax clusters"
+msgstr "E848: Tro da sintaksaj grupoj"
+
+msgid "E400: No cluster specified"
+msgstr "E400: Neniu fasko specifita"
+
+#, c-format
+msgid "E401: Pattern delimiter not found: %s"
+msgstr "E401: Disigilo de Åablono netrovita: %s"
+
+#, c-format
+msgid "E402: Garbage after pattern: %s"
+msgstr "E402: Forĵetindaĵo malantaÅ­ Åablono: %s"
+
+msgid "E403: syntax sync: line continuations pattern specified twice"
+msgstr "E403: sintaksa sinkronigo: Åablono de linia daÅ­rigo specifita dufoje"
+
+#, c-format
+msgid "E404: Illegal arguments: %s"
+msgstr "E404: Nevalidaj argumentoj: %s"
+
+#, c-format
+msgid "E405: Missing equal sign: %s"
+msgstr "E405: Mankas egalsigno: %s"
+
+#, c-format
+msgid "E406: Empty argument: %s"
+msgstr "E406: Malplena argumento: %s"
+
+#, c-format
+msgid "E407: %s not allowed here"
+msgstr "E407: %s ne estas permesebla tie"
+
+#, c-format
+msgid "E408: %s must be first in contains list"
+msgstr "E408: %s devas esti la unua ano de la listo \"contains\""
+
+#, c-format
+msgid "E409: Unknown group name: %s"
+msgstr "E409: Nekonata nomo de grupo: %s"
+
+#, c-format
+msgid "E410: Invalid :syntax subcommand: %s"
+msgstr "E410: Nevalida \":syntax\" subkomando: %s"
+
+msgid ""
+" TOTAL COUNT MATCH SLOWEST AVERAGE NAME PATTERN"
+msgstr ""
+" TOTALO NOMBRO KONGRUO PLEJ MALRAPID MEZA NOMO ÅœABLONO"
+
+msgid "E679: recursive loop loading syncolor.vim"
+msgstr "E679: rekursia buklo dum Åargo de syncolor.vim"
+
+#, c-format
+msgid "E411: highlight group not found: %s"
+msgstr "E411: emfaza grupo netrovita: %s"
+
+#, c-format
+msgid "E412: Not enough arguments: \":highlight link %s\""
+msgstr "E412: Ne sufiĉaj argumentoj: \":highlight link %s\""
+
+#, c-format
+msgid "E413: Too many arguments: \":highlight link %s\""
+msgstr "E413: Tro da argumentoj: \":highlight link %s\""
+
+msgid "E414: group has settings, highlight link ignored"
+msgstr "E414: grupo havas agordojn, ligilo de emfazo ignorita"
+
+#, c-format
+msgid "E415: unexpected equal sign: %s"
+msgstr "E415: neatendita egalsigno: %s"
+
+#, c-format
+msgid "E416: missing equal sign: %s"
+msgstr "E416: mankas egalsigno: %s"
+
+#, c-format
+msgid "E417: missing argument: %s"
+msgstr "E417: mankas argumento: %s"
+
+#, c-format
+msgid "E418: Illegal value: %s"
+msgstr "E418: Nevalida valoro: %s"
+
+msgid "E419: FG color unknown"
+msgstr "E419: Nekonata malfona koloro"
+
+msgid "E420: BG color unknown"
+msgstr "E420: Nekonata fona koloro"
+
+#, c-format
+msgid "E421: Color name or number not recognized: %s"
+msgstr "E421: Kolora nomo aÅ­ nombro nerekonita: %s"
+
+#, c-format
+msgid "E422: terminal code too long: %s"
+msgstr "E422: kodo de terminalo estas tro longa: %s"
+
+#, c-format
+msgid "E423: Illegal argument: %s"
+msgstr "E423: Nevalida argumento: %s"
+
+msgid "E424: Too many different highlighting attributes in use"
+msgstr "E424: Tro da malsamaj atributoj de emfazo uzataj"
+
+msgid "E669: Unprintable character in group name"
+msgstr "E669: Nepresebla signo en nomo de grupo"
+
+msgid "W18: Invalid character in group name"
+msgstr "W18: Nevalida signo en nomo de grupo"
+
+msgid "E849: Too many highlight and syntax groups"
+msgstr "E849: Tro da emfazaj kaj sintaksaj grupoj"
+
+msgid "E555: at bottom of tag stack"
+msgstr "E555: ĉe subo de stako de etikedoj"
+
+msgid "E556: at top of tag stack"
+msgstr "E556: ĉe supro de stako de etikedoj"
+
+msgid "E425: Cannot go before first matching tag"
+msgstr "E425: Ne eblas iri antaÅ­ la unuan kongruan etikedon"
+
+#, c-format
+msgid "E426: tag not found: %s"
+msgstr "E426: etikedo netrovita: %s"
+
+# DP: "pri" estas "priority"
+msgid " # pri kind tag"
+msgstr "nro pri tipo etikedo"
+
+msgid "file\n"
+msgstr "dosiero\n"
+
+msgid "E427: There is only one matching tag"
+msgstr "E427: Estas nur unu kongrua etikedo"
+
+msgid "E428: Cannot go beyond last matching tag"
+msgstr "E428: Ne eblas iri preter lastan kongruan etikedon"
+
+#, c-format
+msgid "File \"%s\" does not exist"
+msgstr "La dosiero \"%s\" ne ekzistas"
+
+#, c-format
+msgid "tag %d of %d%s"
+msgstr "etikedo %d de %d%s"
+
+msgid " or more"
+msgstr " aÅ­ pli"
+
+msgid " Using tag with different case!"
+msgstr " Uzo de etikedo kun malsama uskleco!"
+
+#, c-format
+msgid "E429: File \"%s\" does not exist"
+msgstr "E429: Dosiero \"%s\" ne ekzistas"
+
+msgid ""
+"\n"
+" # TO tag FROM line in file/text"
+msgstr ""
+"\n"
+"nro AL etikedo DE linio en dosiero/teksto"
+
+#, c-format
+msgid "Searching tags file %s"
+msgstr "Serĉado de dosiero de etikedoj %s"
+
+#, c-format
+msgid "E430: Tag file path truncated for %s\n"
+msgstr "E430: Vojo de etikeda dosiero trunkita por %s\n"
+
+msgid "Ignoring long line in tags file"
+msgstr "Ignoro de longa linio en etikeda dosiero"
+
+#, c-format
+msgid "E431: Format error in tags file \"%s\""
+msgstr "E431: Eraro de formato en etikeda dosiero \"%s\""
+
+#, c-format
+msgid "Before byte %ld"
+msgstr "AntaÅ­ bajto %ld"
+
+#, c-format
+msgid "E432: Tags file not sorted: %s"
+msgstr "E432: Etikeda dosiero ne estas ordigita: %s"
+
+msgid "E433: No tags file"
+msgstr "E433: Neniu etikeda dosiero"
+
+msgid "E434: Can't find tag pattern"
+msgstr "E434: Ne eblas trovi Åablonon de etikedo"
+
+msgid "E435: Couldn't find tag, just guessing!"
+msgstr "E435: Ne eblis trovi etikedon, nur divenas!"
+
+#, c-format
+msgid "Duplicate field name: %s"
+msgstr "Ripetita kamponomo: %s"
+
+msgid "' not known. Available builtin terminals are:"
+msgstr "' nekonata. Haveblaj terminaloj estas:"
+
+msgid "defaulting to '"
+msgstr "defaÅ­lto al '"
+
+msgid "E557: Cannot open termcap file"
+msgstr "E557: Ne eblas malfermi la dosieron termcap"
+
+msgid "E558: Terminal entry not found in terminfo"
+msgstr "E558: Ne trovis rikordon de terminalo terminfo"
+
+msgid "E559: Terminal entry not found in termcap"
+msgstr "E559: Ne trovis rikordon de terminalo en termcap"
+
+#, c-format
+msgid "E436: No \"%s\" entry in termcap"
+msgstr "E436: Neniu rikordo \"%s\" en termcap"
+
+msgid "E437: terminal capability \"cm\" required"
+msgstr "E437: kapablo de terminalo \"cm\" bezonata"
+
+msgid ""
+"\n"
+"--- Terminal keys ---"
+msgstr ""
+"\n"
+"--- Klavoj de terminalo ---"
+
+msgid "Cannot open $VIMRUNTIME/rgb.txt"
+msgstr "Ne povas malfermi $VIMRUNTIME/rgb.txt"
+
+#, c-format
+msgid "Kill job in \"%s\"?"
+msgstr "Ĉu ĉesigi taskon en \"%s\"?"
+
+msgid "Terminal"
+msgstr "Terminalo"
+
+msgid "Terminal-finished"
+msgstr "Terminalo-finiÄis"
+
+msgid "active"
+msgstr "aktiva"
+
+msgid "running"
+msgstr "ruliÄas"
+
+msgid "finished"
+msgstr "finiÄis"
+
+msgid "E958: Job already finished"
+msgstr "E958: Tasko jam finiÄis"
+
+#, c-format
+msgid "E953: File exists: %s"
+msgstr "E953: Dosiero jam ekzistas: %s"
+
+msgid "E955: Not a terminal buffer"
+msgstr "E955: Ne estas bufro de terminalo"
+
+msgid "new shell started\n"
+msgstr "nova Åelo lanĉita\n"
+
+msgid "Vim: Error reading input, exiting...\n"
+msgstr "Vim: Eraro dum legado de eniro, elironta...\n"
+
+msgid "Used CUT_BUFFER0 instead of empty selection"
+msgstr "Uzis CUT_BUFFER0 anstataÅ­ malplenan apartigon"
+
+msgid "E881: Line count changed unexpectedly"
+msgstr "E881: Nombro de linioj ÅanÄiÄis neatendite"
+
+msgid "No undo possible; continue anyway"
+msgstr "Malfaro neebla; tamen daÅ­rigi"
+
+#, c-format
+msgid "E828: Cannot open undo file for writing: %s"
+msgstr "E828: Ne eblas malfermi la malfaran dosieron por skribi: %s"
+
+#, c-format
+msgid "E825: Corrupted undo file (%s): %s"
+msgstr "E825: Difektita malfara dosiero (%s): %s"
+
+msgid "Cannot write undo file in any directory in 'undodir'"
+msgstr "Ne eblis skribi malfaran dosieron en iu dosiero ajn de 'undodir'"
+
+#, c-format
+msgid "Will not overwrite with undo file, cannot read: %s"
+msgstr "Ne superskribos malfaran dosieron, ne eblis legi: %s"
+
+#, c-format
+msgid "Will not overwrite, this is not an undo file: %s"
+msgstr "Ne superskribos, tio ne estas malfara dosiero: %s"
+
+msgid "Skipping undo file write, nothing to undo"
+msgstr "Preterpasas skribon de malfara dosiero, nenio por malfari"
+
+#, c-format
+msgid "Writing undo file: %s"
+msgstr "Skribas malfaran dosieron: %s"
+
+#, c-format
+msgid "E829: write error in undo file: %s"
+msgstr "E829: Skriberaro en malfara dosiero: %s"
+
+#, c-format
+msgid "Not reading undo file, owner differs: %s"
+msgstr "Ne legas malfaran dosieron, posedanto malsamas: %s"
+
+#, c-format
+msgid "Reading undo file: %s"
+msgstr "Legado de malfara dosiero: %s"
+
+#, c-format
+msgid "E822: Cannot open undo file for reading: %s"
+msgstr "E822: Ne eblas malfermi malfaran dosieron por legi: %s"
+
+#, c-format
+msgid "E823: Not an undo file: %s"
+msgstr "E823: Ne estas malfara dosiero: %s"
+
+#, c-format
+msgid "E832: Non-encrypted file has encrypted undo file: %s"
+msgstr "E832: Ne ĉifrita dosiero havas ĉifritan malfaran dosieron: %s"
+
+#, c-format
+msgid "E826: Undo file decryption failed: %s"
+msgstr "E826: Malĉifrado de malfara dosiero malsukcesis: %s"
+
+#, c-format
+msgid "E827: Undo file is encrypted: %s"
+msgstr "E827: Malfara dosiero estas ĉifrita: %s"
+
+#, c-format
+msgid "E824: Incompatible undo file: %s"
+msgstr "E824: Malkongrua malfara dosiero: %s"
+
+msgid "File contents changed, cannot use undo info"
+msgstr "Enhavo de dosiero ÅanÄiÄis, ne eblas uzi malfarajn informojn"
+
+#, c-format
+msgid "Finished reading undo file %s"
+msgstr "Finis legi malfaran dosieron %s"
+
+msgid "Already at oldest change"
+msgstr "Jam al la plej malnova ÅanÄo"
+
+msgid "Already at newest change"
+msgstr "Jam al la plej nova ÅanÄo"
+
+#, c-format
+msgid "E830: Undo number %ld not found"
+msgstr "E830: Malfara numero %ld netrovita"
+
+msgid "E438: u_undo: line numbers wrong"
+msgstr "E438: u_undo: nevalidaj numeroj de linioj"
+
+msgid "more line"
+msgstr "plia linio"
+
+msgid "more lines"
+msgstr "pliaj linioj"
+
+msgid "line less"
+msgstr "malpli linio"
+
+msgid "fewer lines"
+msgstr "malpli linioj"
+
+msgid "change"
+msgstr "ÅanÄo"
+
+msgid "changes"
+msgstr "ÅanÄoj"
+
+#, c-format
+msgid "%ld %s; %s #%ld %s"
+msgstr "%ld %s; %s #%ld %s"
+
+msgid "before"
+msgstr "antaÅ­"
+
+msgid "after"
+msgstr "post"
+
+msgid "Nothing to undo"
+msgstr "Nenio por malfari"
+
+msgid "number changes when saved"
+msgstr "numero ÅanÄoj tempo konservita"
+
+#, c-format
+msgid "%ld second ago"
+msgid_plural "%ld seconds ago"
+msgstr[0] "antaÅ­ %ld sekundo"
+msgstr[1] "antaÅ­ %ld sekundoj"
+
+msgid "E790: undojoin is not allowed after undo"
+msgstr "E790: undojoin estas nepermesebla post malfaro"
+
+msgid "E439: undo list corrupt"
+msgstr "E439: listo de malfaro estas difekta"
+
+msgid "E440: undo line missing"
+msgstr "E440: linio de malfaro mankas"
+
+#, c-format
+msgid "E122: Function %s already exists, add ! to replace it"
+msgstr "E122: La funkcio %s jam ekzistas (aldonu ! por anstataÅ­igi Äin)"
+
+msgid "E717: Dictionary entry already exists"
+msgstr "E717: Rikordo de vortaro jam ekzistas"
+
+msgid "E718: Funcref required"
+msgstr "E718: Funcref bezonata"
+
+#, c-format
+msgid "E130: Unknown function: %s"
+msgstr "E130: Nekonata funkcio: %s"
+
+#, c-format
+msgid "E125: Illegal argument: %s"
+msgstr "E125: Nevalida argumento: %s"
+
+#, c-format
+msgid "E853: Duplicate argument name: %s"
+msgstr "E853: Ripetita nomo de argumento: %s"
+
+#, c-format
+msgid "E740: Too many arguments for function %s"
+msgstr "E740: Tro da argumentoj por funkcio: %s"
+
+#, c-format
+msgid "E116: Invalid arguments for function %s"
+msgstr "E116: Nevalidaj argumentoj por funkcio: %s"
+
+msgid "E132: Function call depth is higher than 'maxfuncdepth'"
+msgstr "E132: Profundo de funkcia alvoko superas 'maxfuncdepth'"
+
+#, c-format
+msgid "calling %s"
+msgstr "alvokas %s"
+
+#, c-format
+msgid "%s aborted"
+msgstr "%s ĉesigita"
+
+#, c-format
+msgid "%s returning #%ld"
+msgstr "%s liveras #%ld"
+
+#, c-format
+msgid "%s returning %s"
+msgstr "%s liveras %s"
+
+msgid "E699: Too many arguments"
+msgstr "E699: Tro da argumentoj"
+
+#, c-format
+msgid "E117: Unknown function: %s"
+msgstr "E117: Nekonata funkcio: %s"
+
+#, c-format
+msgid "E933: Function was deleted: %s"
+msgstr "E933: funkcio estis forviÅita: %s"
+
+#, c-format
+msgid "E119: Not enough arguments for function: %s"
+msgstr "E119: Ne sufiĉe da argumentoj por funkcio: %s"
+
+#, c-format
+msgid "E120: Using <SID> not in a script context: %s"
+msgstr "E120: <SID> estas uzata ekster kunteksto de skripto: %s"
+
+#, c-format
+msgid "E725: Calling dict function without Dictionary: %s"
+msgstr "E725: Alvoko de funkcio dict sen Vortaro: %s"
+
+msgid "E129: Function name required"
+msgstr "E129: Nomo de funkcio bezonata"
+
+#, c-format
+msgid "E128: Function name must start with a capital or \"s:\": %s"
+msgstr "E128: Nomo de funkcio devas eki per majusklo aÅ­ per \"s:\": %s"
+
+#, c-format
+msgid "E884: Function name cannot contain a colon: %s"
+msgstr "E884: Nomo de funkcio ne povas enhavi dupunkton: %s"
+
+#, c-format
+msgid "E123: Undefined function: %s"
+msgstr "E123: Nedifinita funkcio: %s"
+
+#, c-format
+msgid "E124: Missing '(': %s"
+msgstr "E124: Mankas '(': %s"
+
+msgid "E862: Cannot use g: here"
+msgstr "E862: Ne eblas uzi g: ĉi tie"
+
+#, c-format
+msgid "E932: Closure function should not be at top level: %s"
+msgstr "E932: Fermo-funkcio devus esti je la plej alta nivelo: %s"
+
+msgid "E126: Missing :endfunction"
+msgstr "E126: Mankas \":endfunction\""
+
+#, c-format
+msgid "W22: Text found after :endfunction: %s"
+msgstr "W22: Teksto trovita malantaÅ­ :endfunction: %s"
+
+#, c-format
+msgid "E707: Function name conflicts with variable: %s"
+msgstr "E707: Nomo de funkcio konfliktas kun variablo: %s"
+
+#, c-format
+msgid "E127: Cannot redefine function %s: It is in use"
+msgstr "E127: Ne eblas redifini funkcion %s: Estas nuntempe uzata"
+
+#, c-format
+msgid "E746: Function name does not match script file name: %s"
+msgstr "E746: Nomo de funkcio ne kongruas kun dosiernomo de skripto: %s"
+
+#, c-format
+msgid "E131: Cannot delete function %s: It is in use"
+msgstr "E131: Ne eblas forviÅi funkcion %s: Estas nuntempe uzata"
+
+msgid "E133: :return not inside a function"
+msgstr "E133: \":return\" ekster funkcio"
+
+#, c-format
+msgid "E107: Missing parentheses: %s"
+msgstr "E107: Mankas krampoj: %s"
+
+#, c-format
+msgid "%s (%s, compiled %s)"
+msgstr "%s (%s, kompilita %s)"
+
+msgid ""
+"\n"
+"MS-Windows 64-bit GUI version"
+msgstr ""
+"\n"
+"Grafika versio MS-Vindozo 64-bitoj"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit GUI version"
+msgstr ""
+"\n"
+"Grafika versio MS-Vindozo 32-bitoj"
+
+msgid " with OLE support"
+msgstr " kun subteno de OLE"
+
+msgid ""
+"\n"
+"MS-Windows 64-bit console version"
+msgstr ""
+"\n"
+"Versio konzola MS-Vindozo 64-bitoj"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit console version"
+msgstr ""
+"\n"
+"Versio konzola MS-Vindozo 32-bitoj"
+
+msgid ""
+"\n"
+"macOS version"
+msgstr ""
+"\n"
+"Versio makOS"
+
+msgid ""
+"\n"
+"macOS version w/o darwin feat."
+msgstr ""
+"\n"
+"Versio makOS sen ebloj de darwin."
+
+msgid ""
+"\n"
+"OpenVMS version"
+msgstr ""
+"\n"
+"Versio OpenVMS"
+
+msgid ""
+"\n"
+"Included patches: "
+msgstr ""
+"\n"
+"Flikaĵoj inkluzivitaj: "
+
+msgid ""
+"\n"
+"Extra patches: "
+msgstr ""
+"\n"
+"Ekstraj flikaĵoj: "
+
+msgid "Modified by "
+msgstr "Modifita de "
+
+msgid ""
+"\n"
+"Compiled "
+msgstr ""
+"\n"
+"Kompilita "
+
+msgid "by "
+msgstr "de "
+
+msgid ""
+"\n"
+"Huge version "
+msgstr ""
+"\n"
+"Grandega versio "
+
+msgid ""
+"\n"
+"Big version "
+msgstr ""
+"\n"
+"Granda versio "
+
+msgid ""
+"\n"
+"Normal version "
+msgstr ""
+"\n"
+"Normala versio "
+
+msgid ""
+"\n"
+"Small version "
+msgstr ""
+"\n"
+"Malgranda versio "
+
+msgid ""
+"\n"
+"Tiny version "
+msgstr ""
+"\n"
+"Malgrandega versio "
+
+msgid "without GUI."
+msgstr "sen grafika interfaco."
+
+msgid "with GTK3 GUI."
+msgstr "kun grafika interfaco GTK3."
+
+msgid "with GTK2-GNOME GUI."
+msgstr "kun grafika interfaco GTK2-GNOME."
+
+msgid "with GTK2 GUI."
+msgstr "kun grafika interfaco GTK2."
+
+msgid "with X11-Motif GUI."
+msgstr "kun grafika interfaco X11-Motif."
+
+msgid "with X11-neXtaw GUI."
+msgstr "kun grafika interfaco X11-neXtaw."
+
+msgid "with X11-Athena GUI."
+msgstr "kun grafika interfaco X11-Athena."
+
+msgid "with Photon GUI."
+msgstr "kun grafika interfaco Photon."
+
+msgid "with GUI."
+msgstr "sen grafika interfaco."
+
+msgid "with Carbon GUI."
+msgstr "kun grafika interfaco Carbon."
+
+msgid "with Cocoa GUI."
+msgstr "kun grafika interfaco Cocoa."
+
+msgid " Features included (+) or not (-):\n"
+msgstr " Ebloj inkluzivitaj (+) aÅ­ ne (-):\n"
+
+msgid " system vimrc file: \""
+msgstr " sistema dosiero vimrc: \""
+
+msgid " user vimrc file: \""
+msgstr " dosiero vimrc de uzanto: \""
+
+msgid " 2nd user vimrc file: \""
+msgstr " 2-a dosiero vimrc de uzanto: \""
+
+msgid " 3rd user vimrc file: \""
+msgstr " 3-a dosiero vimrc de uzanto: \""
+
+msgid " user exrc file: \""
+msgstr " dosiero exrc de uzanto: \""
+
+msgid " 2nd user exrc file: \""
+msgstr " 2-a dosiero exrc de uzanto: \""
+
+msgid " system gvimrc file: \""
+msgstr " sistema dosiero gvimrc: \""
+
+msgid " user gvimrc file: \""
+msgstr " dosiero gvimrc de uzanto: \""
+
+msgid "2nd user gvimrc file: \""
+msgstr " 2-a dosiero gvimrc de uzanto: \""
+
+msgid "3rd user gvimrc file: \""
+msgstr " 3-a dosiero gvimrc de uzanto: \""
+
+msgid " defaults file: \""
+msgstr " dosiero de defaÅ­ltoj: \""
+
+msgid " system menu file: \""
+msgstr " dosiero de sistema menuo: \""
+
+msgid " fall-back for $VIM: \""
+msgstr " defaÅ­lto de $VIM: \""
+
+msgid " f-b for $VIMRUNTIME: \""
+msgstr " defaÅ­lto de VIMRUNTIME: \""
+
+msgid "Compilation: "
+msgstr "Kompilado: "
+
+msgid "Compiler: "
+msgstr "Kompililo: "
+
+msgid "Linking: "
+msgstr "Ligado: "
+
+msgid " DEBUG BUILD"
+msgstr " SENCIMIGA MUNTO"
+
+msgid "VIM - Vi IMproved"
+msgstr "VIM - Vi plibonigita"
+
+msgid "version "
+msgstr "versio "
+
+# DP: vidu http://www.thefreedictionary.com/et+al.
+msgid "by Bram Moolenaar et al."
+msgstr "de Bram Moolenaar kaj aliuloj"
+
+msgid "Vim is open source and freely distributable"
+msgstr "Vim estas libera programo kaj disdoneblas libere"
+
+msgid "Help poor children in Uganda!"
+msgstr "Helpu malriĉajn infanojn en Ugando!"
+
+# DP: atentu al la spacetoj: ĉiuj ĉenoj devas havi la saman longon
+msgid "type :help iccf<Enter> for information "
+msgstr "tajpu :help iccf<Enenklavo> por pliaj informoj "
+
+# DP: atentu al la spacetoj: ĉiuj ĉenoj devas havi la saman longon
+msgid "type :q<Enter> to exit "
+msgstr "tajpu :q<Enenklavo> por eliri "
+
+# DP: atentu al la spacetoj: ĉiuj ĉenoj devas havi la saman longon
+msgid "type :help<Enter> or <F1> for on-line help"
+msgstr "tajpu :help<Enenklavo> aÅ­ <F1> por aliri la helpon "
+
+# DP: atentu al la spacetoj: ĉiuj ĉenoj devas havi la saman longon
+msgid "type :help version8<Enter> for version info"
+msgstr "tajpu :help version8<Enenklavo> por informo de versio"
+
+msgid "Running in Vi compatible mode"
+msgstr "RuliÄas en reÄimo kongrua kun Vi"
+
+# DP: atentu al la spacetoj: ĉiuj ĉenoj devas havi la saman longon
+msgid "type :set nocp<Enter> for Vim defaults"
+msgstr "tajpu :set nocp<Enenklavo> por Vim defaÅ­ltoj "
+
+# DP: atentu al la spacetoj: ĉiuj ĉenoj devas havi la saman longon
+msgid "type :help cp-default<Enter> for info on this"
+msgstr "tajpu :help cp-default<Enenklavo> por pliaj informoj "
+
+# DP: atentu al la spacetoj: ĉiuj ĉenoj devas havi la saman longon
+msgid "menu Help->Orphans for information "
+msgstr "menuo Help->Orfinoj por pliaj informoj "
+
+msgid "Running modeless, typed text is inserted"
+msgstr "RuliÄas senreÄime, tajpita teksto estas enmetita"
+
+# DP: atentu al la spacetoj: ĉiuj ĉenoj devas havi la saman longon
+msgid "menu Edit->Global Settings->Toggle Insert Mode "
+msgstr "menuo Redakti->Mallokaj Agordoj->Baskuligi Enmetan ReÄimon"
+
+# DP: atentu al la spacetoj: ĉiuj ĉenoj devas havi la saman longon
+msgid " for two modes "
+msgstr " por du reÄimoj "
+
+# DP: tiu ĉeno pli longas (mi ne volas igi ĉiujn aliajn ĉenojn
+# pli longajn)
+msgid "menu Edit->Global Settings->Toggle Vi Compatible"
+msgstr "menuo Redakti->Mallokaj Agordoj->Baskuligi ReÄimon Kongruan kun Vi"
+
+# DP: atentu al la spacetoj: ĉiuj ĉenoj devas havi la saman longon
+msgid " for Vim defaults "
+msgstr " por defaÅ­ltoj de Vim "
+
+msgid "Sponsor Vim development!"
+msgstr "Subtenu la programadon de Vim!"
+
+msgid "Become a registered Vim user!"
+msgstr "IÄu registrita uzanto de Vim!"
+
+# DP: atentu al la spacetoj: ĉiuj ĉenoj devas havi la saman longon
+msgid "type :help sponsor<Enter> for information "
+msgstr "tajpu :help sponsor<Enenklavo> por pliaj informoj "
+
+# DP: atentu al la spacetoj: ĉiuj ĉenoj devas havi la saman longon
+msgid "type :help register<Enter> for information "
+msgstr "tajpu :help register<Enenklavo> por pliaj informoj "
+
+# DP: atentu al la spacetoj: ĉiuj ĉenoj devas havi la saman longon
+msgid "menu Help->Sponsor/Register for information "
+msgstr "menuo Helpo->Subteni/Registri por pliaj informoj "
+
+msgid "Already only one window"
+msgstr "Jam nur unu fenestro"
+
+msgid "E441: There is no preview window"
+msgstr "E441: Ne estas antaÅ­vida fenestro"
+
+msgid "E442: Can't split topleft and botright at the same time"
+msgstr "E442: Ne eblas dividi supralivan kaj subdekstran samtempe"
+
+msgid "E443: Cannot rotate when another window is split"
+msgstr "E443: Ne eblas rotacii kiam alia fenestro estas dividita"
+
+msgid "E444: Cannot close last window"
+msgstr "E444: Ne eblas fermi la lastan fenestron"
+
+msgid "E813: Cannot close autocmd window"
+msgstr "E813: Ne eblas fermi la fenestron de aÅ­tokomandoj"
+
+msgid "E814: Cannot close window, only autocmd window would remain"
+msgstr "E814: Ne eblas fermi fenestron, nur la fenestro de aÅ­tokomandoj restus"
+
+msgid "E445: Other window contains changes"
+msgstr "E445: La alia fenestro enhavas ÅanÄojn"
+
+msgid "E446: No file name under cursor"
+msgstr "E446: Neniu dosiernomo sub la kursoro"
+
+#, c-format
+msgid "E447: Can't find file \"%s\" in path"
+msgstr "E447: Ne eblas trovi dosieron \"%s\" en serĉvojo"
+
+#, c-format
+msgid "E799: Invalid ID: %ld (must be greater than or equal to 1)"
+msgstr "E799: Nevalida ID: %ld (devas esti egala aÅ­ pli granda ol 1)"
+
+#, c-format
+msgid "E801: ID already taken: %ld"
+msgstr "E801: ID jam uzata: %ld"
+
+msgid "List or number required"
+msgstr "Listo aÅ­ nombro bezonata"
+
+#, c-format
+msgid "E802: Invalid ID: %ld (must be greater than or equal to 1)"
+msgstr "E802: Nevalida ID: %ld (devas esti egala aÅ­ pli granda ol 1)"
+
+#, c-format
+msgid "E803: ID not found: %ld"
+msgstr "E803: ID netrovita: %ld"
+
+#, c-format
+msgid "E370: Could not load library %s"
+msgstr "E370: Ne eblis Åargi bibliotekon %s"
+
+msgid "Sorry, this command is disabled: the Perl library could not be loaded."
+msgstr ""
+"BedaÅ­rinde tiu komando estas malÅaltita: la biblioteko de Perl ne Åargeblis."
+
+msgid "E299: Perl evaluation forbidden in sandbox without the Safe module"
+msgstr ""
+"E299: Plenumo de Perl esprimoj malpermesata en sabloludejo sen la modulo Safe"
+
+msgid "Edit with &multiple Vims"
+msgstr "Redakti per &pluraj Vim-oj"
+
+msgid "Edit with single &Vim"
+msgstr "Redakti per unuopa &Vim"
+
+msgid "Diff with Vim"
+msgstr "Kompari per Vim"
+
+msgid "Edit with &Vim"
+msgstr "Redakti per &Vim"
+
+msgid "Edit with existing Vim"
+msgstr "Redakti per ekzistanta Vim"
+
+msgid "Edit with existing Vim - "
+msgstr "Redakti per ekzistanta Vim - "
+
+msgid "Edits the selected file(s) with Vim"
+msgstr "Redakti la apartigita(j)n dosiero(j)n per Vim"
+
+msgid "Error creating process: Check if gvim is in your path!"
+msgstr "Eraro dum kreo de procezo: Kontrolu ĉu gvim estas en via serĉvojo!"
+
+msgid "gvimext.dll error"
+msgstr "Eraro de gvimext.dll"
+
+msgid "Path length too long!"
+msgstr "Serĉvojo estas tro longa!"
+
+msgid "--No lines in buffer--"
+msgstr "--Neniu linio en bufro--"
+
+msgid "E470: Command aborted"
+msgstr "E470: komando ĉesigita"
+
+msgid "E471: Argument required"
+msgstr "E471: Argumento bezonata"
+
+msgid "E10: \\ should be followed by /, ? or &"
+msgstr "E10: \\ devus esti sekvita de /, ? aÅ­ &"
+
+msgid "E11: Invalid in command-line window; <CR> executes, CTRL-C quits"
+msgstr ""
+"E11: Nevalida en fenestro de komanda linio; <CR> plenumas, CTRL-C eliras"
+
+msgid "E12: Command not allowed from exrc/vimrc in current dir or tag search"
+msgstr ""
+"E12: Nepermesebla komando el exrc/vimrc en aktuala dosierujo aŭ etikeda serĉo"
+
+msgid "E171: Missing :endif"
+msgstr "E171: Mankas \":endif\""
+
+msgid "E600: Missing :endtry"
+msgstr "E600: Mankas \":endtry\""
+
+msgid "E170: Missing :endwhile"
+msgstr "E170: Mankas \":endwhile\""
+
+msgid "E170: Missing :endfor"
+msgstr "E170: Mankas \":endfor\""
+
+msgid "E588: :endwhile without :while"
+msgstr "E588: \":endwhile\" sen \":while\""
+
+msgid "E588: :endfor without :for"
+msgstr "E588: \":endfor\" sen \":for\""
+
+msgid "E13: File exists (add ! to override)"
+msgstr "E13: Dosiero ekzistas (aldonu ! por transpasi)"
+
+msgid "E472: Command failed"
+msgstr "E472: La komando malsukcesis"
+
+#, c-format
+msgid "E234: Unknown fontset: %s"
+msgstr "E234: Nekonata familio de tiparo: %s"
+
+#, c-format
+msgid "E235: Unknown font: %s"
+msgstr "E235: Nekonata tiparo: %s"
+
+#, c-format
+msgid "E236: Font \"%s\" is not fixed-width"
+msgstr "E236: La tiparo \"%s\" ne estas egallarÄa"
+
+msgid "E473: Internal error"
+msgstr "E473: Interna eraro"
+
+#, c-format
+msgid "E685: Internal error: %s"
+msgstr "E685: Interna eraro: %s"
+
+msgid "Interrupted"
+msgstr "Interrompita"
+
+msgid "E14: Invalid address"
+msgstr "E14: Nevalida adreso"
+
+msgid "E474: Invalid argument"
+msgstr "E474: Nevalida argumento"
+
+#, c-format
+msgid "E475: Invalid argument: %s"
+msgstr "E475: Nevalida argumento: %s"
+
+#, c-format
+msgid "E475: Invalid value for argument %s"
+msgstr "E475: Nevalida valoro de argumento: %s"
+
+#, c-format
+msgid "E475: Invalid value for argument %s: %s"
+msgstr "E475: Nevalida valoro de argumento %s: %s"
+
+#, c-format
+msgid "E15: Invalid expression: %s"
+msgstr "E15: Nevalida esprimo: %s"
+
+msgid "E16: Invalid range"
+msgstr "E16: Nevalida amplekso"
+
+msgid "E476: Invalid command"
+msgstr "E476: Nevalida komando"
+
+#, c-format
+msgid "E17: \"%s\" is a directory"
+msgstr "E17: \"%s\" estas dosierujo"
+
+#, c-format
+msgid "E364: Library call failed for \"%s()\""
+msgstr "E364: Alvoko al biblioteko malsukcesis por \"%s()\""
+
+# AM: fsync: ne traduku (nomo de C-komando)
+msgid "E667: Fsync failed"
+msgstr "E667: Fsync malsukcesis"
+
+#, c-format
+msgid "E448: Could not load library function %s"
+msgstr "E448: Ne eblis Åargi bibliotekan funkcion %s"
+
+msgid "E19: Mark has invalid line number"
+msgstr "E19: Marko havas nevalidan numeron de linio"
+
+msgid "E20: Mark not set"
+msgstr "E20: Marko ne estas agordita"
+
+msgid "E21: Cannot make changes, 'modifiable' is off"
+msgstr "E21: Ne eblas fari ÅanÄojn, 'modifiable' estas malÅaltita"
+
+msgid "E22: Scripts nested too deep"
+msgstr "E22: Tro profunde ingitaj skriptoj"
+
+msgid "E23: No alternate file"
+msgstr "E23: Neniu alterna dosiero"
+
+msgid "E24: No such abbreviation"
+msgstr "E24: Ne estas tia mallongigo"
+
+msgid "E477: No ! allowed"
+msgstr "E477: Neniu ! permesebla"
+
+msgid "E25: GUI cannot be used: Not enabled at compile time"
+msgstr "E25: Grafika interfaco ne uzeblas: MalÅaltita dum kompilado"
+
+msgid "E26: Hebrew cannot be used: Not enabled at compile time\n"
+msgstr "E26: La hebrea ne uzeblas: MalÅaltita dum kompilado\n"
+
+msgid "E27: Farsi cannot be used: Not enabled at compile time\n"
+msgstr "E27: La persa ne uzeblas: MalÅaltita dum kompilado\n"
+
+msgid "E800: Arabic cannot be used: Not enabled at compile time\n"
+msgstr "E800: La araba ne uzeblas: MalÅaltita dum kompilado\n"
+
+#, c-format
+msgid "E28: No such highlight group name: %s"
+msgstr "E28: Neniu grupo de emfazo kiel: %s"
+
+msgid "E29: No inserted text yet"
+msgstr "E29: AnkoraÅ­ neniu enmetita teksto"
+
+msgid "E30: No previous command line"
+msgstr "E30: Neniu antaÅ­a komanda linio"
+
+msgid "E31: No such mapping"
+msgstr "E31: Neniu tiel mapo"
+
+msgid "E479: No match"
+msgstr "E479: Neniu kongruo"
+
+#, c-format
+msgid "E480: No match: %s"
+msgstr "E480: Neniu kongruo: %s"
+
+msgid "E32: No file name"
+msgstr "E32: Neniu dosiernomo"
+
+msgid "E33: No previous substitute regular expression"
+msgstr "E33: Neniu antaÅ­a regulesprimo de anstataÅ­igo"
+
+msgid "E34: No previous command"
+msgstr "E34: Neniu antaÅ­a komando"
+
+msgid "E35: No previous regular expression"
+msgstr "E35: Neniu antaÅ­a regulesprimo"
+
+msgid "E481: No range allowed"
+msgstr "E481: Amplekso nepermesebla"
+
+msgid "E36: Not enough room"
+msgstr "E36: Ne sufiĉe da spaco"
+
+#, c-format
+msgid "E247: no registered server named \"%s\""
+msgstr "E247: neniu registrita servilo nomita \"%s\""
+
+#, c-format
+msgid "E482: Can't create file %s"
+msgstr "E482: Ne eblas krei dosieron %s"
+
+msgid "E483: Can't get temp file name"
+msgstr "E483: Ne eblas akiri provizoran dosiernomon"
+
+#, c-format
+msgid "E484: Can't open file %s"
+msgstr "E484: Ne eblas malfermi dosieron %s"
+
+#, c-format
+msgid "E485: Can't read file %s"
+msgstr "E485: Ne eblas legi dosieron %s"
+
+msgid "E38: Null argument"
+msgstr "E38: Nula argumento"
+
+msgid "E39: Number expected"
+msgstr "E39: Nombro atendita"
+
+#, c-format
+msgid "E40: Can't open errorfile %s"
+msgstr "E40: Ne eblas malfermi eraran dosieron %s"
+
+msgid "E233: cannot open display"
+msgstr "E233: ne eblas malfermi vidigon"
+
+msgid "E41: Out of memory!"
+msgstr "E41: Ne plu restas memoro!"
+
+msgid "Pattern not found"
+msgstr "Åœablono ne trovita"
+
+#, c-format
+msgid "E486: Pattern not found: %s"
+msgstr "E486: Åœablono ne trovita: %s"
+
+msgid "E487: Argument must be positive"
+msgstr "E487: La argumento devas esti pozitiva"
+
+msgid "E459: Cannot go back to previous directory"
+msgstr "E459: Ne eblas reiri al antaÅ­a dosierujo"
+
+msgid "E42: No Errors"
+msgstr "E42: Neniu eraro"
+
+msgid "E776: No location list"
+msgstr "E776: Neniu listo de lokoj"
+
+msgid "E43: Damaged match string"
+msgstr "E43: Difekta kongruenda ĉeno"
+
+msgid "E44: Corrupted regexp program"
+msgstr "E44: Difekta programo de regulesprimo"
+
+msgid "E45: 'readonly' option is set (add ! to override)"
+msgstr "E45: La opcio 'readonly' estas Åaltita '(aldonu ! por transpasi)"
+
+#, c-format
+msgid "E46: Cannot change read-only variable \"%s\""
+msgstr "E46: Ne eblas ÅanÄi nurlegeblan variablon \"%s\""
+
+#, c-format
+msgid "E794: Cannot set variable in the sandbox: \"%s\""
+msgstr "E794: Ne eblas agordi variablon en la sabloludejo: \"%s\""
+
+msgid "E713: Cannot use empty key for Dictionary"
+msgstr "E713: Ne eblas uzi malplenan Ålosilon de Vortaro"
+
+msgid "E715: Dictionary required"
+msgstr "E715: Vortaro bezonata"
+
+#, c-format
+msgid "E684: list index out of range: %ld"
+msgstr "E684: indekso de listo ekster limoj: %ld"
+
+#, c-format
+msgid "E118: Too many arguments for function: %s"
+msgstr "E118: Tro da argumentoj por funkcio: %s"
+
+#, c-format
+msgid "E716: Key not present in Dictionary: %s"
+msgstr "E716: Åœlosilo malekzistas en Vortaro: %s"
+
+msgid "E714: List required"
+msgstr "E714: Listo bezonata"
+
+#, c-format
+msgid "E712: Argument of %s must be a List or Dictionary"
+msgstr "E712: Argumento de %s devas esti Listo aÅ­ Vortaro"
+
+msgid "E47: Error while reading errorfile"
+msgstr "E47: Eraro dum legado de erardosiero"
+
+msgid "E48: Not allowed in sandbox"
+msgstr "E48: Nepermesebla en sabloludejo"
+
+msgid "E523: Not allowed here"
+msgstr "E523: Nepermesebla tie"
+
+msgid "E359: Screen mode setting not supported"
+msgstr "E359: ReÄimo de ekrano ne subtenata"
+
+msgid "E49: Invalid scroll size"
+msgstr "E49: Nevalida grando de rulumo"
+
+msgid "E91: 'shell' option is empty"
+msgstr "E91: La opcio 'shell' estas malplena"
+
+msgid "E255: Couldn't read in sign data!"
+msgstr "E255: Ne eblis legi datumojn de simboloj!"
+
+msgid "E72: Close error on swap file"
+msgstr "E72: Eraro dum malfermo de permutodosiero .swp"
+
+msgid "E73: tag stack empty"
+msgstr "E73: malplena stako de etikedo"
+
+msgid "E74: Command too complex"
+msgstr "E74: Komando tro kompleksa"
+
+msgid "E75: Name too long"
+msgstr "E75: Nomo tro longa"
+
+msgid "E76: Too many ["
+msgstr "E76: Tro da ["
+
+msgid "E77: Too many file names"
+msgstr "E77: Tro da dosiernomoj"
+
+msgid "E488: Trailing characters"
+msgstr "E488: Vostaj signoj"
+
+msgid "E78: Unknown mark"
+msgstr "E78: Nekonata marko"
+
+msgid "E79: Cannot expand wildcards"
+msgstr "E79: Ne eblas malvolvi ĵokerojn"
+
+msgid "E591: 'winheight' cannot be smaller than 'winminheight'"
+msgstr "E591: 'winheight' ne rajtas esti malpli ol 'winminheight'"
+
+msgid "E592: 'winwidth' cannot be smaller than 'winminwidth'"
+msgstr "E592: 'winwidth' ne rajtas esti malpli ol 'winminwidth'"
+
+msgid "E80: Error while writing"
+msgstr "E80: Eraro dum skribado"
+
+msgid "E939: Positive count required"
+msgstr "E939: Pozitiva kvantoro bezonata"
+
+msgid "E81: Using <SID> not in a script context"
+msgstr "E81: Uzo de <SID> ekster kunteksto de skripto"
+
+msgid "E449: Invalid expression received"
+msgstr "E449: Nevalida esprimo ricevita"
+
+msgid "E463: Region is guarded, cannot modify"
+msgstr "E463: Regiono estas gardita, ne eblas ÅanÄi"
+
+msgid "E744: NetBeans does not allow changes in read-only files"
+msgstr "E744: NetBeans ne permesas ÅanÄojn en nurlegeblaj dosieroj"
+
+msgid "E363: pattern uses more memory than 'maxmempattern'"
+msgstr "E363: Åablono uzas pli da memoro ol 'maxmempattern'"
+
+msgid "E749: empty buffer"
+msgstr "E749: malplena bufro"
+
+#, c-format
+msgid "E86: Buffer %ld does not exist"
+msgstr "E86: La bufro %ld ne ekzistas"
+
+msgid "E682: Invalid search pattern or delimiter"
+msgstr "E682: Nevalida serĉa Åablono aÅ­ disigilo"
+
+msgid "E139: File is loaded in another buffer"
+msgstr "E139: Dosiero estas Åargita en alia bufro"
+
+#, c-format
+msgid "E764: Option '%s' is not set"
+msgstr "E764: La opcio '%s' ne estas Åaltita"
+
+msgid "E850: Invalid register name"
+msgstr "E850: Nevalida nomo de reÄistro"
+
+#, c-format
+msgid "E919: Directory not found in '%s': \"%s\""
+msgstr "E919: Dosierujo ne trovita en '%s': \"%s\""
+
+msgid "E952: Autocommand caused recursive behavior"
+msgstr "E952: AÅ­tokomandoj kaÅ­zis rikiran konduton"
+
+msgid "search hit TOP, continuing at BOTTOM"
+msgstr "serĉo atingis SUPRON, daŭrigonte al SUBO"
+
+msgid "search hit BOTTOM, continuing at TOP"
+msgstr "serĉo atingis SUBON, daŭrigonte al SUPRO"
+
+#, c-format
+msgid "Need encryption key for \"%s\""
+msgstr "Ŝlosilo de ĉifrado bezonata por \"%s\""
+
+msgid "empty keys are not allowed"
+msgstr "malplenaj Ålosiloj nepermeseblaj"
+
+msgid "dictionary is locked"
+msgstr "vortaro estas Ålosita"
+
+msgid "list is locked"
+msgstr "listo estas Ålosita"
+
+#, c-format
+msgid "failed to add key '%s' to dictionary"
+msgstr "aldono de Ålosilo '%s' al vortaro malsukcesis"
+
+#, c-format
+msgid "index must be int or slice, not %s"
+msgstr "indekso devas esti 'int' aÅ­ 'slice', ne %s"
+
+#, c-format
+msgid "expected str() or unicode() instance, but got %s"
+msgstr "atendis aperon de str() aÅ­ unicode(), sed ricevis %s"
+
+#, c-format
+msgid "expected bytes() or str() instance, but got %s"
+msgstr "atendis aperon de bytes() aÅ­ str(), sed ricevis %s"
+
+#, c-format
+msgid ""
+"expected int(), long() or something supporting coercing to long(), but got %s"
+msgstr "atendis int(), long() aÅ­ ion konverteblan al long(), sed ricevis %s"
+
+#, c-format
+msgid "expected int() or something supporting coercing to int(), but got %s"
+msgstr "atendis int() aÅ­ ion konverteblan al int(), sed ricevis %s"
+
+msgid "value is too large to fit into C int type"
+msgstr "valoro estas tro grada por C-tipo 'int'"
+
+msgid "value is too small to fit into C int type"
+msgstr "valoro estas tro malgranda por C-tipo 'int'"
+
+msgid "number must be greater than zero"
+msgstr "nombro devas esti pli granda ol nul"
+
+msgid "number must be greater or equal to zero"
+msgstr "nombro devas esti egala aÅ­ pli granda ol nul"
+
+msgid "can't delete OutputObject attributes"
+msgstr "ne eblas forviÅi atributojn de OutputObject"
+
+#, c-format
+msgid "invalid attribute: %s"
+msgstr "nevalida atributo: %s"
+
+msgid "E264: Python: Error initialising I/O objects"
+msgstr "E264: Pitono: Eraro de pravalorizo de eneligaj objektoj"
+
+msgid "failed to change directory"
+msgstr "malsukcesis ÅanÄi dosierujon"
+
+#, c-format
+msgid "expected 3-tuple as imp.find_module() result, but got %s"
+msgstr "atendis 3-opon kiel rezulto de imp.find_module(), sed ricevis %s"
+
+#, c-format
+msgid "expected 3-tuple as imp.find_module() result, but got tuple of size %d"
+msgstr "atendis 3-opon kiel rezulto de imp.find_module(), sed ricevis %d-opon"
+
+msgid "internal error: imp.find_module returned tuple with NULL"
+msgstr "interna eraro: imp.find_module liveris opon kun NULL"
+
+msgid "cannot delete vim.Dictionary attributes"
+msgstr "ne eblas forviÅi atributojn de 'vim.Dictionary'"
+
+msgid "cannot modify fixed dictionary"
+msgstr "ne eblas ÅanÄi fiksan vortaron"
+
+#, c-format
+msgid "cannot set attribute %s"
+msgstr "ne eblas agordi atributon %s"
+
+msgid "hashtab changed during iteration"
+msgstr "hakettabelo ÅanÄiÄis dum iteracio"
+
+#, c-format
+msgid "expected sequence element of size 2, but got sequence of size %d"
+msgstr "atendis 2-longan sekvencon, sed ricevis %d-longan sekvencon"
+
+msgid "list constructor does not accept keyword arguments"
+msgstr "konstruilo de listo ne akceptas Ålosilvortajn argumentojn"
+
+msgid "list index out of range"
+msgstr "indekso de listo ekster limoj"
+
+#, c-format
+msgid "internal error: failed to get vim list item %d"
+msgstr "interna eraro: obteno de vim-a listero %d malsukcesis"
+
+msgid "slice step cannot be zero"
+msgstr "paÅo de sekco ne povas esti nul"
+
+#, c-format
+msgid "attempt to assign sequence of size greater than %d to extended slice"
+msgstr "provis valorizi sekvencon kun pli ol %d eroj en etendita sekco"
+
+#, c-format
+msgid "internal error: no vim list item %d"
+msgstr "interna eraro: neniu vim-a listero %d"
+
+msgid "internal error: not enough list items"
+msgstr "interna eraro: ne sufiĉaj listeroj"
+
+msgid "internal error: failed to add item to list"
+msgstr "interna eraro: aldono de listero malsukcesis"
+
+#, c-format
+msgid "attempt to assign sequence of size %d to extended slice of size %d"
+msgstr "provis valorizi sekvencon kun %d eroj al etendita sekco kun %d eroj"
+
+msgid "failed to add item to list"
+msgstr "aldono de listero malsukcesis"
+
+msgid "cannot delete vim.List attributes"
+msgstr "ne eblas forviÅi atributojn de 'vim.List'"
+
+msgid "cannot modify fixed list"
+msgstr "ne eblas ÅanÄi fiksan liston"
+
+#, c-format
+msgid "unnamed function %s does not exist"
+msgstr "sennoma funkcio %s ne ekzistas"
+
+#, c-format
+msgid "function %s does not exist"
+msgstr "funkcio %s ne ekzistas"
+
+#, c-format
+msgid "failed to run function %s"
+msgstr "malsukcesis ruli funkcion %s"
+
+msgid "unable to get option value"
+msgstr "malsukcesis akiri valoron de opcio"
+
+msgid "internal error: unknown option type"
+msgstr "interna eraro: nekonata tipo de opcio"
+
+msgid "problem while switching windows"
+msgstr "problemo dum salto al vindozoj"
+
+#, c-format
+msgid "unable to unset global option %s"
+msgstr "ne povis malÅalti mallokan opcion %s"
+
+#, c-format
+msgid "unable to unset option %s which does not have global value"
+msgstr "ne povis malÅalti opcion %s, kiu ne havas mallokan valoron"
+
+msgid "attempt to refer to deleted tab page"
+msgstr "provo de referenco al forviÅita langeto"
+
+msgid "no such tab page"
+msgstr "ne estas tia langeto"
+
+msgid "attempt to refer to deleted window"
+msgstr "provo de referenco al forviÅita fenestro"
+
+msgid "readonly attribute: buffer"
+msgstr "nurlegebla atributo: buffer"
+
+msgid "cursor position outside buffer"
+msgstr "kursoro poziciita ekster bufro"
+
+msgid "no such window"
+msgstr "ne estas tia fenestro"
+
+msgid "attempt to refer to deleted buffer"
+msgstr "provo de referenco al forviÅita bufro"
+
+msgid "failed to rename buffer"
+msgstr "malsukcesis renomi bufron"
+
+msgid "mark name must be a single character"
+msgstr "nomo de marko devas esti unuopa signo"
+
+#, c-format
+msgid "expected vim.Buffer object, but got %s"
+msgstr "atendis objekton vim.Buffer, sed ricevis %s"
+
+#, c-format
+msgid "failed to switch to buffer %d"
+msgstr "salto al la bufro %d malsukcesis"
+
+#, c-format
+msgid "expected vim.Window object, but got %s"
+msgstr "atendis objekton vim.window, sed ricevis %s"
+
+msgid "failed to find window in the current tab page"
+msgstr "malsukcesis trovi vindozon en la nuna langeto"
+
+msgid "did not switch to the specified window"
+msgstr "ne saltis al la specifita vindozo"
+
+#, c-format
+msgid "expected vim.TabPage object, but got %s"
+msgstr "atendis objekton vim.TabPage, sed ricevis %s"
+
+msgid "did not switch to the specified tab page"
+msgstr "ne saltis al la specifita langeto"
+
+msgid "failed to run the code"
+msgstr "malsukcesis ruli la kodon"
+
+msgid "E858: Eval did not return a valid python object"
+msgstr "E858: Eval ne revenis kun valida python-objekto"
+
+msgid "E859: Failed to convert returned python object to vim value"
+msgstr "E859: Konverto de revena python-objekto al vim-valoro malsukcesis"
+
+#, c-format
+msgid "unable to convert %s to vim dictionary"
+msgstr "ne povis konverti %s al vim-vortaro"
+
+#, c-format
+msgid "unable to convert %s to vim list"
+msgstr "ne povis konverti %s al vim-listo"
+
+#, c-format
+msgid "unable to convert %s to vim structure"
+msgstr "ne povis konverti %s al vim-strukturo"
+
+msgid "internal error: NULL reference passed"
+msgstr "interna eraro: NULL-referenco argumento"
+
+msgid "internal error: invalid value type"
+msgstr "interna eraro: nevalida tipo de valoro"
+
+msgid ""
+"Failed to set path hook: sys.path_hooks is not a list\n"
+"You should now do the following:\n"
+"- append vim.path_hook to sys.path_hooks\n"
+"- append vim.VIM_SPECIAL_PATH to sys.path\n"
+msgstr ""
+"Valorizo de sys.path_hooks malsukcesis: sys.path_hooks ne estas listo\n"
+"Vi nun devas fari tion:\n"
+"- postaldoni vim.path_hook al sys.path_hooks\n"
+"- postaldoni vim.VIM_SPECIAL_PATH al sys.path\n"
+
+msgid ""
+"Failed to set path: sys.path is not a list\n"
+"You should now append vim.VIM_SPECIAL_PATH to sys.path"
+msgstr ""
+"Agordo de serĉvojo malsukcesis: sys.path ne estas listo\n"
+"Vi nun devas aldoni vim.VIM_SPECIAL_PATH al sys.path"
+
+msgid ""
+"Vim macro files (*.vim)\t*.vim\n"
+"All Files (*.*)\t*.*\n"
+msgstr ""
+"Dosierioj de vim-makrooj (*.vim)\t*.vim\n"
+"Ĉiuj dosieroj (*.*)\t*.*\n"
+
+msgid "All Files (*.*)\t*.*\n"
+msgstr "Ĉiuj dosieroj (*.*)\t*.*\n"
+
+msgid ""
+"All Files (*.*)\t*.*\n"
+"C source (*.c, *.h)\t*.c;*.h\n"
+"C++ source (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"VB code (*.bas, *.frm)\t*.bas;*.frm\n"
+"Vim files (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
+msgstr ""
+"Ĉiuj dosieroj (*.*)\t*.*\n"
+"Dosieroj C (*.c, *.h)\t*.c;*.h\n"
+"Dosieroj C++ (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"Fonto VB (*.bas, *.frm)\t.bas;*.frm\n"
+"Dosieroj Vim (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
+
+msgid ""
+"Vim macro files (*.vim)\t*.vim\n"
+"All Files (*)\t*\n"
+msgstr ""
+"Dosierioj de vim-makrooj (*.vim)\t*.vim\n"
+"Ĉiuj dosieroj (*)\t*\n"
+
+msgid "All Files (*)\t*\n"
+msgstr "Ĉiuj dosieroj (*)\t*\n"
+
+msgid ""
+"All Files (*)\t*\n"
+"C source (*.c, *.h)\t*.c;*.h\n"
+"C++ source (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"Vim files (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
+msgstr ""
+"Ĉiuj dosieroj (*)\t*\n"
+"Dosieroj C (*.c, *.h)\t*.c;*.h\n"
+"Dosieroj C++ (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"Dosieroj Vim (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
diff --git a/src/po/es.po b/src/po/es.po
new file mode 100644
index 0000000..e4efdf9
--- /dev/null
+++ b/src/po/es.po
@@ -0,0 +1,8277 @@
+# Vim7/src/po/vim.pot translation to Spanish.
+#
+# Translation project homepage:
+# vim-doc-es http://www.assembla.com/wiki/show/vim-doc-es
+#
+# Last translators:
+# Pedro A. López-Valencia <vorbote@users.sourceforge.net>, 2003-06,2009
+# Omar Campagne Polaino <ocampagne@gmail.com> 2009
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Vim 7.2.284 (rev 1692)\n"
+"Report-Msgid-Bugs-To: vim@bugs.org\n"
+"POT-Creation-Date: 2009-11-25 02:05+0100\n"
+"PO-Revision-Date: 2009-12-04 18:52+0100\n"
+"Last-Translator: Omar Campagne <ocampagne@gmail.com>\n"
+"Language-Team: vim-doc-es http://www.assembla.com/wiki/show/vim-doc-es\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: octect-stream\n"
+
+#: buffer.c:102
+msgid "E82: Cannot allocate any buffer, exiting..."
+msgstr "E82: No se pudo asignar memoria para ningún búfer, saliendo..."
+
+#: buffer.c:105
+msgid "E83: Cannot allocate buffer, using other one..."
+msgstr "E83: No se pudo asignar memoria para el búfer, usando otro..."
+
+#: buffer.c:879
+msgid "E515: No buffers were unloaded"
+msgstr "E515: No se descargó ningún búfer"
+
+#: buffer.c:881
+msgid "E516: No buffers were deleted"
+msgstr "E516: No se borró ningún búfer"
+
+#: buffer.c:883
+msgid "E517: No buffers were wiped out"
+msgstr "E517: No se eliminó ningún búfer"
+
+#: buffer.c:891
+msgid "1 buffer unloaded"
+msgstr "Se descargó un (1) búfer"
+
+#: buffer.c:893
+#, c-format
+msgid "%d buffers unloaded"
+msgstr "Se descargaron %d búfers"
+
+#: buffer.c:898
+msgid "1 buffer deleted"
+msgstr "Se suprimió un (1) búfer"
+
+#: buffer.c:900
+#, c-format
+msgid "%d buffers deleted"
+msgstr "Se suprimieron %d búfers"
+
+#: buffer.c:905
+msgid "1 buffer wiped out"
+msgstr "Se eliminó un (1) búfer"
+
+#: buffer.c:907
+#, c-format
+msgid "%d buffers wiped out"
+msgstr "Se eliminaron %d búfers"
+
+#: buffer.c:965
+msgid "E84: No modified buffer found"
+msgstr "E84: No se encontró ningún búfer modificado"
+
+# back where we started, didn't find anything.
+#. back where we started, didn't find anything.
+#: buffer.c:1004
+msgid "E85: There is no listed buffer"
+msgstr "E85: No hay búfers en la lista"
+
+#: buffer.c:1016
+#, c-format
+msgid "E86: Buffer %ld does not exist"
+msgstr "E86: El búfer %ld no existe"
+
+#: buffer.c:1019
+msgid "E87: Cannot go beyond last buffer"
+msgstr "E87: No se pudo ir más allá del último búfer"
+
+#: buffer.c:1021
+msgid "E88: Cannot go before first buffer"
+msgstr "E88: No se pudo regresar antes del primer búfer"
+
+#: buffer.c:1063
+#, c-format
+msgid "E89: No write since last change for buffer %ld (add ! to override)"
+msgstr ""
+"E89: No se guardó el archivo desde el último cambio del búfer %ld (añada \"!"
+"\" para forzar)"
+
+#: buffer.c:1080
+msgid "E90: Cannot unload last buffer"
+msgstr "E90: No se pudo descargar el último búfer"
+
+#: buffer.c:1651
+msgid "W14: Warning: List of file names overflow"
+msgstr "W14: Advertencia: La lista de nombres de archivos es muy larga"
+
+#: buffer.c:1850 quickfix.c:3632
+#, c-format
+msgid "E92: Buffer %ld not found"
+msgstr "E92: No se encontró el búfer %ld"
+
+#: buffer.c:2125
+#, c-format
+msgid "E93: More than one match for %s"
+msgstr "E93: Hay más de una coincidencia con %s"
+
+#: buffer.c:2127
+#, c-format
+msgid "E94: No matching buffer for %s"
+msgstr "E94: No hay un búfer que coincida con %s"
+
+#: buffer.c:2579
+#, c-format
+msgid "line %ld"
+msgstr "línea %ld"
+
+#: buffer.c:2666
+msgid "E95: Buffer with this name already exists"
+msgstr "E95: Ya existe un búfer con este nombre"
+
+#: buffer.c:2993
+msgid " [Modified]"
+msgstr " [Modificado]"
+
+#: buffer.c:2998
+msgid "[Not edited]"
+msgstr "[Sin editar]"
+
+#: buffer.c:3003
+msgid "[New file]"
+msgstr "[Archivo nuevo]"
+
+#: buffer.c:3004
+msgid "[Read errors]"
+msgstr "[Errores de lectura]"
+
+#: buffer.c:3006 fileio.c:2391 netbeans.c:3632
+msgid "[readonly]"
+msgstr "[Sólo lectura]"
+
+#: buffer.c:3029
+#, c-format
+msgid "1 line --%d%%--"
+msgstr "1 línea --%d%%--"
+
+#: buffer.c:3032
+#, c-format
+msgid "%ld lines --%d%%--"
+msgstr "%ld líneas --%d%%--"
+
+#: buffer.c:3039
+#, c-format
+msgid "line %ld of %ld --%d%%-- col "
+msgstr "línea %ld de %ld --%d%%-- col "
+
+#: buffer.c:3160 buffer.c:5126 memline.c:1727
+msgid "[No Name]"
+msgstr "[Sin nombre]"
+
+# must be a help buffer
+#. must be a help buffer
+#: buffer.c:3198
+msgid "help"
+msgstr "ayuda"
+
+#: buffer.c:3826 screen.c:5817
+msgid "[Help]"
+msgstr "[Ayuda]"
+
+#: buffer.c:3860 screen.c:5823
+msgid "[Preview]"
+msgstr "[Vista previa]"
+
+#: buffer.c:4182
+msgid "All"
+msgstr "Todo"
+
+#: buffer.c:4182
+msgid "Bot"
+msgstr "Final"
+
+#: buffer.c:4185
+msgid "Top"
+msgstr "Comienzo"
+
+#: buffer.c:5061
+#, c-format
+msgid ""
+"\n"
+"# Buffer list:\n"
+msgstr ""
+"\n"
+"# Lista de búfers:\n"
+
+#: buffer.c:5110
+msgid "[Location List]"
+msgstr "[Lista de ubicaciones]"
+
+#: buffer.c:5112
+msgid "[Quickfix List]"
+msgstr "[Lista de cambios rápidos]"
+
+#: buffer.c:5122
+msgid "[Scratch]"
+msgstr "[De cero]"
+
+#: buffer.c:5439
+msgid ""
+"\n"
+"--- Signs ---"
+msgstr ""
+"\n"
+"--- Signos ---"
+
+#: buffer.c:5449
+#, c-format
+msgid "Signs for %s:"
+msgstr "Signos para %s:"
+
+#: buffer.c:5455
+#, c-format
+msgid " line=%ld id=%d name=%s"
+msgstr " línea=%ld id=%d nombre=%s"
+
+#: diff.c:141
+#, c-format
+msgid "E96: Can not diff more than %ld buffers"
+msgstr "E96: No se puede usar \"diff\" con más de %ld búfers"
+
+#: diff.c:777
+msgid "E810: Cannot read or write temp files"
+msgstr "E810: No se puede leer o escribir en archivos temporales"
+
+#: diff.c:778
+msgid "E97: Cannot create diffs"
+msgstr "E97: No se pudieron crear las \"diffs\" (diferencias)"
+
+#: diff.c:901
+msgid "Patch file"
+msgstr "Archivo de parches"
+
+#: diff.c:1005
+msgid "E816: Cannot read patch output"
+msgstr "E816: No se pudo leer la salida del parche"
+
+#: diff.c:1227
+msgid "E98: Cannot read diff output"
+msgstr "E98: No se pudo leer la salida de \"diff\""
+
+#: diff.c:2086
+msgid "E99: Current buffer is not in diff mode"
+msgstr "E99: El búfer actual no está en modo de diferencias"
+
+#: diff.c:2105
+msgid "E793: No other buffer in diff mode is modifiable"
+msgstr "E793: Ningún otro búfer está en modo de diferencias"
+
+#: diff.c:2107
+msgid "E100: No other buffer in diff mode"
+msgstr "E100: Ningún otro búfer está en modo de diferencias"
+
+#: diff.c:2117
+msgid "E101: More than two buffers in diff mode, don't know which one to use"
+msgstr "E101: Más de dos búfers en modo de diferencias, no se cual usar"
+
+#: diff.c:2140
+#, c-format
+msgid "E102: Can't find buffer \"%s\""
+msgstr "E102: No se pudo encontrar el búfer %s"
+
+#: diff.c:2148
+#, c-format
+msgid "E103: Buffer \"%s\" is not in diff mode"
+msgstr "E103: El búfer \"%s\" no está en modo de diferencias"
+
+#: diff.c:2192
+msgid "E787: Buffer changed unexpectedly"
+msgstr "E787: El búfer cambió inesperadamente"
+
+#: digraph.c:2251
+msgid "E104: Escape not allowed in digraph"
+msgstr "E104: El código de escape no se permite en un dígrafo"
+
+#: digraph.c:2444
+msgid "E544: Keymap file not found"
+msgstr "E544: No se encontró el archivo \"keymap\""
+
+#: digraph.c:2471
+msgid "E105: Using :loadkeymap not in a sourced file"
+msgstr "E105: Usando \":loadkeymap\" en el archivo suministrado"
+
+#: digraph.c:2510
+msgid "E791: Empty keymap entry"
+msgstr "E791: Definición de \"keymap\" vacía"
+
+#: edit.c:42
+msgid " Keyword completion (^N^P)"
+msgstr " Completar palabra clave (^N^P)"
+
+# ctrl_x_mode == 0, ^P/^N compl.
+#. ctrl_x_mode == 0, ^P/^N compl.
+#: edit.c:43
+msgid " ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+msgstr " Modo ^X (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+
+#: edit.c:45
+msgid " Whole line completion (^L^N^P)"
+msgstr " Completar toda la línea (^L^N^P)"
+
+#: edit.c:46
+msgid " File name completion (^F^N^P)"
+msgstr " Completar nombre de archivo (^F^N^P)"
+
+#: edit.c:47
+msgid " Tag completion (^]^N^P)"
+msgstr " Completar etiquetas (^]^N^P)"
+
+#: edit.c:48
+msgid " Path pattern completion (^N^P)"
+msgstr " Completar patrón de ruta (^N^P)"
+
+#: edit.c:49
+msgid " Definition completion (^D^N^P)"
+msgstr " Completar definición (^D^N^P)"
+
+#: edit.c:51
+msgid " Dictionary completion (^K^N^P)"
+msgstr " Completar diccionario (^K^N^P)"
+
+#: edit.c:52
+msgid " Thesaurus completion (^T^N^P)"
+msgstr " Completar palabras con tesauro (^T^N^P)"
+
+#: edit.c:53
+msgid " Command-line completion (^V^N^P)"
+msgstr " Compleción de línea de órdenes (^V^N^P)"
+
+#: edit.c:54
+msgid " User defined completion (^U^N^P)"
+msgstr " Completar definido por usuario (^U^N^P)"
+
+#: edit.c:55
+msgid " Omni completion (^O^N^P)"
+msgstr " Completar con método Omni (^O^N^P)"
+
+#: edit.c:56
+msgid " Spelling suggestion (s^N^P)"
+msgstr " Sugerencia de ortografía (s^N^P)"
+
+# Scroll has it's own msgs, in it's place there is the msg for local
+# * ctrl_x_mode = 0 (eg continue_status & CONT_LOCAL) -- Acevedo
+#: edit.c:57
+msgid " Keyword Local completion (^N^P)"
+msgstr " Completar palabra clave local (^N^P)"
+
+#: edit.c:60
+msgid "Hit end of paragraph"
+msgstr "Se llegó al final del párrafo"
+
+#: edit.c:2038
+msgid "'dictionary' option is empty"
+msgstr "La opción 'dictionary' está vacía"
+
+#: edit.c:2039
+msgid "'thesaurus' option is empty"
+msgstr "La opción 'thesaurus' (tesauro) está vacía"
+
+#: edit.c:2999
+#, c-format
+msgid "Scanning dictionary: %s"
+msgstr "Buscando en el diccionario: %s"
+
+#: edit.c:3484
+msgid " (insert) Scroll (^E/^Y)"
+msgstr " (insertar) Desplazamiento (^E/^Y)"
+
+#: edit.c:3486
+msgid " (replace) Scroll (^E/^Y)"
+msgstr " (reemplazar) Desplazamiento (^E/^Y)"
+
+#: edit.c:3963
+#, c-format
+msgid "Scanning: %s"
+msgstr "Buscando: %s"
+
+#: edit.c:3998
+msgid "Scanning tags."
+msgstr "Buscando etiquetas."
+
+#: edit.c:5010
+msgid " Adding"
+msgstr "Añadiendo"
+
+# showmode might reset the internal line pointers, so it must
+# * be called before line = ml_get(), or when this address is no
+# * longer needed. -- Acevedo.
+#
+#. showmode might reset the internal line pointers, so it must
+#. * be called before line = ml_get(), or when this address is no
+#. * longer needed. -- Acevedo.
+#.
+#: edit.c:5057
+msgid "-- Searching..."
+msgstr "-- Buscando..."
+
+#: edit.c:5116
+msgid "Back at original"
+msgstr "De vuelta al original"
+
+#: edit.c:5121
+msgid "Word from other line"
+msgstr "Palabra proveniente de otra línea"
+
+#: edit.c:5126
+msgid "The only match"
+msgstr "La única coincidencia"
+
+#: edit.c:5191
+#, c-format
+msgid "match %d of %d"
+msgstr "coincidencia %d de %d"
+
+#: edit.c:5195
+#, c-format
+msgid "match %d"
+msgstr "coincidencia %d"
+
+#: eval.c:96
+msgid "E18: Unexpected characters in :let"
+msgstr "E18: Caracteres inesperados en :let"
+
+#: eval.c:97
+#, c-format
+msgid "E684: list index out of range: %ld"
+msgstr "E684: índice de lista fuera de rango: %ld"
+
+#: eval.c:98
+#, c-format
+msgid "E121: Undefined variable: %s"
+msgstr "E121: Variable sin definir: %s"
+
+#: eval.c:99
+msgid "E111: Missing ']'"
+msgstr "E111: Falta un \"]\""
+
+#: eval.c:100
+#, c-format
+msgid "E686: Argument of %s must be a List"
+msgstr "E686: El argumento de %s debe ser una lista"
+
+#: eval.c:101
+#, c-format
+msgid "E712: Argument of %s must be a List or Dictionary"
+msgstr "E712: El argumento de %s debe ser una lista o un diccionario"
+
+#: eval.c:102
+msgid "E713: Cannot use empty key for Dictionary"
+msgstr "E713: No se puede usar una llave vacía para el diccionario"
+
+#: eval.c:103
+msgid "E714: List required"
+msgstr "E714: Se requiere una lista"
+
+#: eval.c:104
+msgid "E715: Dictionary required"
+msgstr "E715: Se requiere de un diccionario"
+
+#: eval.c:105
+#, c-format
+msgid "E118: Too many arguments for function: %s"
+msgstr "E118: Demasiados argumentos para la función: %s"
+
+#: eval.c:106
+#, c-format
+msgid "E716: Key not present in Dictionary: %s"
+msgstr "E716: No se encuentra la llave en el diccionario. %s"
+
+#: eval.c:107
+#, c-format
+msgid "E122: Function %s already exists, add ! to replace it"
+msgstr "E122: La función %s ya existe, añada \"!\" para reemplazarla"
+
+#: eval.c:108
+msgid "E717: Dictionary entry already exists"
+msgstr "E717: Esta entrada ya existe en el diccionario"
+
+#: eval.c:109
+msgid "E718: Funcref required"
+msgstr "E718: Se requiere una referencia de función"
+
+# if Vim opened a window: Executing a shell may cause crashes
+#: eval.c:110
+msgid "E719: Cannot use [:] with a Dictionary"
+msgstr "E719: No puede usar [:] con un diccionario"
+
+#: eval.c:111
+#, c-format
+msgid "E734: Wrong variable type for %s="
+msgstr "E734: Tipo de variable incorrecta para %s="
+
+#: eval.c:112
+#, c-format
+msgid "E130: Unknown function: %s"
+msgstr "E130: Función desconocida: %s"
+
+#: eval.c:113
+#, c-format
+msgid "E461: Illegal variable name: %s"
+msgstr "E461: Nombre ilegal para una variable: %s"
+
+#: eval.c:1898
+msgid "E687: Less targets than List items"
+msgstr "E687: Menos blancos que elementos en la lista"
+
+#: eval.c:1903
+msgid "E688: More targets than List items"
+msgstr "E688: Más blancos que elementos en la lista"
+
+#: eval.c:1989
+msgid "Double ; in list of variables"
+msgstr "Duplicado ; en la lista de variables"
+
+#: eval.c:2208
+#, c-format
+msgid "E738: Can't list variables for %s"
+msgstr "E738: No se pudo enumerar las variables de %s"
+
+#: eval.c:2554
+msgid "E689: Can only index a List or Dictionary"
+msgstr "E689: Solo puedo indexar una lista o un diccionario"
+
+#: eval.c:2560
+msgid "E708: [:] must come last"
+msgstr "E708: [:] debe ir al final"
+
+#: eval.c:2612
+msgid "E709: [:] requires a List value"
+msgstr "E709: [:] requiere un valor de la lista"
+
+#: eval.c:2848
+msgid "E710: List value has more items than target"
+msgstr "E710: La lista de valores tiene más elementos que blancos"
+
+#: eval.c:2852
+msgid "E711: List value has not enough items"
+msgstr "E711: La lista de valores no tiene suficientes elementos"
+
+#: eval.c:3087
+msgid "E690: Missing \"in\" after :for"
+msgstr "E690: Falta \"in\" después de :for"
+
+#: eval.c:3320
+#, c-format
+msgid "E107: Missing parentheses: %s"
+msgstr "E107: Faltan paréntesis: %s"
+
+#: eval.c:3559
+#, c-format
+msgid "E108: No such variable: \"%s\""
+msgstr "E108: No existe la variable: \"%s\""
+
+#: eval.c:3646
+msgid "E743: variable nested too deep for (un)lock"
+msgstr "E743: La variable está anidada muy profundamente para (des)bloquear"
+
+#: eval.c:3994
+msgid "E109: Missing ':' after '?'"
+msgstr "E109: Falta un \":\" después de \"?\""
+
+#: eval.c:4296
+msgid "E691: Can only compare List with List"
+msgstr "E691: Solo se puede comparar una lista con otra lista"
+
+#: eval.c:4298
+msgid "E692: Invalid operation for List"
+msgstr "E692: Operación inválida para lista"
+
+#: eval.c:4325
+msgid "E735: Can only compare Dictionary with Dictionary"
+msgstr "E735: Solo se puede comparar un diccionario con otro diccionario"
+
+#: eval.c:4327
+msgid "E736: Invalid operation for Dictionary"
+msgstr "E736: Operación inválida para diccionario"
+
+#: eval.c:4347
+msgid "E693: Can only compare Funcref with Funcref"
+msgstr "E693: Solo se puede comparar un \"Funref\" con otro \"Funcref\""
+
+#: eval.c:4349
+msgid "E694: Invalid operation for Funcrefs"
+msgstr "E694: Operación inválida para \"Funcrefs\""
+
+# if Vim opened a window: Executing a shell may cause crashes
+#: eval.c:4769
+msgid "E804: Cannot use '%' with Float"
+msgstr "E804: No se puede usar '%' con \"Float\""
+
+#: eval.c:4989
+msgid "E110: Missing ')'"
+msgstr "E110: Falta un \")\""
+
+#: eval.c:5141
+msgid "E695: Cannot index a Funcref"
+msgstr "E695: No se puede crear un índice de un \"Funcref\""
+
+#: eval.c:5398
+#, c-format
+msgid "E112: Option name missing: %s"
+msgstr "E112: Falta el nombre de la opción: %s"
+
+#: eval.c:5416
+#, c-format
+msgid "E113: Unknown option: %s"
+msgstr "E113: Opción desconocida: %s"
+
+#: eval.c:5482
+#, c-format
+msgid "E114: Missing quote: %s"
+msgstr "E114: Faltan las comillas: %s"
+
+#: eval.c:5618
+#, c-format
+msgid "E115: Missing quote: %s"
+msgstr "E115: Faltan las comillas: %s"
+
+#: eval.c:5697
+#, c-format
+msgid "E696: Missing comma in List: %s"
+msgstr "E696: Falta una coma en la lista: %s"
+
+#: eval.c:5705
+#, c-format
+msgid "E697: Missing end of List ']': %s"
+msgstr "E697: Falta una marca de final de lista ']': %s"
+
+#: eval.c:7195
+#, c-format
+msgid "E720: Missing colon in Dictionary: %s"
+msgstr "E720: Falta una marca de dos puntos en el diccionario: %s"
+
+#: eval.c:7224
+#, c-format
+msgid "E721: Duplicate key in Dictionary: \"%s\""
+msgstr "E721: Llave duplicada en el diccionario: %s"
+
+#: eval.c:7244
+#, c-format
+msgid "E722: Missing comma in Dictionary: %s"
+msgstr "E722: Falta una coma en el diccionario: %s"
+
+#: eval.c:7252
+#, c-format
+msgid "E723: Missing end of Dictionary '}': %s"
+msgstr "E723: Falta una marca de cierre '}' en el diccionario: %s"
+
+#: eval.c:7290
+msgid "E724: variable nested too deep for displaying"
+msgstr "E724: La variable está anidada demasiado profundamente para mostrarla"
+
+#: eval.c:7974
+#, c-format
+msgid "E740: Too many arguments for function %s"
+msgstr "E740: Demasiados argumentos para la función: %s"
+
+#: eval.c:7976
+#, c-format
+msgid "E116: Invalid arguments for function %s"
+msgstr "E116: Argumentos inválidos para la función: %s"
+
+#: eval.c:8181
+#, c-format
+msgid "E117: Unknown function: %s"
+msgstr "E117: Función desconocida: %s"
+
+#: eval.c:8187
+#, c-format
+msgid "E119: Not enough arguments for function: %s"
+msgstr "E119: No hay suficientes argumentos para la función: %s"
+
+#: eval.c:8191
+#, c-format
+msgid "E120: Using <SID> not in a script context: %s"
+msgstr "E120: Usando <SID> en un contexto que no es de \"script\": %s"
+
+#: eval.c:8195
+#, c-format
+msgid "E725: Calling dict function without Dictionary: %s"
+msgstr "E725: Llamando una función \"dict\" sin un diccionario: %s"
+
+#: eval.c:8423
+msgid "E808: Number or Float required"
+msgstr "E808: Se requiere \"Number\" o \"Float\""
+
+#: eval.c:8808
+msgid "E699: Too many arguments"
+msgstr "E699: Demasiados argumentos"
+
+#: eval.c:8977
+msgid "E785: complete() can only be used in Insert mode"
+msgstr "E785: complete() solo se puede usar en modo \"Insert\""
+
+#.
+#. * Yes this is ugly, I don't particularly like it either. But doing it
+#. * this way has the compelling advantage that translations need not to
+#. * be touched at all. See below what 'ok' and 'ync' are used for.
+#.
+#: eval.c:9077 gui.c:4871 gui_gtk.c:2144 os_mswin.c:598
+msgid "&Ok"
+msgstr "&Ok"
+
+#: eval.c:9727
+#, c-format
+msgid "E737: Key already exists: %s"
+msgstr "E737: Ya existe una llave: %s"
+
+#: eval.c:10301
+#, c-format
+msgid "+-%s%3ld lines: "
+msgstr "+-%s%3ld líneas: "
+
+#: eval.c:10389
+#, c-format
+msgid "E700: Unknown function: %s"
+msgstr "E700: Función desconocida: %s"
+
+#: eval.c:12379
+msgid ""
+"&OK\n"
+"&Cancel"
+msgstr ""
+"&Aceptar\n"
+"&Cancelar"
+
+#: eval.c:12461
+msgid "called inputrestore() more often than inputsave()"
+msgstr "Se invocó \"inputrestore()\" más veces que \"inputsave()\""
+
+#: eval.c:12595
+msgid "E786: Range not allowed"
+msgstr "E786: El rango no está permitido"
+
+#: eval.c:12795
+msgid "E701: Invalid type for len()"
+msgstr "E701: No es un tipo válido para len()"
+
+#: eval.c:13788
+msgid "E726: Stride is zero"
+msgstr "E726: El largo es cero"
+
+#: eval.c:13790
+msgid "E727: Start past end"
+msgstr "E727: El inicio está más allá del final"
+
+#: eval.c:13843 eval.c:17576
+msgid "<empty>"
+msgstr "<vacio>"
+
+#: eval.c:14077
+msgid "E240: No connection to Vim server"
+msgstr "E240: No hay conexión al servidor Vim"
+
+#: eval.c:14125
+#, c-format
+msgid "E241: Unable to send to %s"
+msgstr "E241: Incapaz de enviar a %s"
+
+#: eval.c:14272
+msgid "E277: Unable to read a server reply"
+msgstr "E277: Incapaz de leer una respuesta del servidor"
+
+#: eval.c:14522
+msgid "E655: Too many symbolic links (cycle?)"
+msgstr "E655: Demasiados enlaces simbólicos (¿referencia circular?)"
+
+#: eval.c:15243
+msgid "E258: Unable to send to client"
+msgstr "E258: Incapaz de enviar al cliente"
+
+#: eval.c:15950
+msgid "E702: Sort compare function failed"
+msgstr "E702: Fallo al ordenar funciones comparadas"
+
+#: eval.c:16275
+msgid "(Invalid)"
+msgstr "(No es válido)"
+
+#: eval.c:16760
+msgid "E677: Error writing temp file"
+msgstr "E677: Error al escribir el archivo temporal"
+
+#: eval.c:18602
+msgid "E805: Using a Float as a Number"
+msgstr "E805: Usando \"Float\" como un \"Number\""
+
+#: eval.c:18606
+msgid "E703: Using a Funcref as a Number"
+msgstr "E703: Usando una función de referencia como \"Number\""
+
+#: eval.c:18614
+msgid "E745: Using a List as a Number"
+msgstr "E745: Usando una \"Lista\" como \"Number\""
+
+#: eval.c:18617
+msgid "E728: Using a Dictionary as a Number"
+msgstr "E728: Usando un Diccionario como \"Number\""
+
+#: eval.c:18720
+msgid "E729: using Funcref as a String"
+msgstr "E729: Usando una Función de referencia como \"String\""
+
+#: eval.c:18723
+msgid "E730: using List as a String"
+msgstr "E730: Usando una \"List\" como \"String\""
+
+#: eval.c:18726
+msgid "E731: using Dictionary as a String"
+msgstr "E731: Usando un Diccionario como \"String\""
+
+#: eval.c:18730
+msgid "E806: using Float as a String"
+msgstr "E806: Usando \"Float\" como \"String\""
+
+#: eval.c:19090
+#, c-format
+msgid "E704: Funcref variable name must start with a capital: %s"
+msgstr ""
+"E704: El nombre de una variable de Función de referencia debe empezar con "
+"mayúscula: %s"
+
+#: eval.c:19095
+#, c-format
+msgid "E705: Variable name conflicts with existing function: %s"
+msgstr "E705: Nombre de variable en conflicto con una función existente: %s"
+
+#: eval.c:19128
+#, c-format
+msgid "E706: Variable type mismatch for: %s"
+msgstr "E706: Tipo de variable no concuerda con : %s"
+
+#: eval.c:19237
+#, c-format
+msgid "E795: Cannot delete variable %s"
+msgstr "E795: No se pudo borrar la variable %s"
+
+#: eval.c:19254
+#, c-format
+msgid "E741: Value is locked: %s"
+msgstr "E741: El valor está bloqueado: %s"
+
+#: eval.c:19255 eval.c:19261 message.c:2132 os_mswin.c:2258
+msgid "Unknown"
+msgstr "Desconocido"
+
+#: eval.c:19260
+#, c-format
+msgid "E742: Cannot change value of %s"
+msgstr "E742: No se pudo cambiar el valor de %s"
+
+#: eval.c:19345
+msgid "E698: variable nested too deep for making a copy"
+msgstr "E698: La variable está anidada muy profundamente para hacer una copia"
+
+#: eval.c:19818
+#, c-format
+msgid "E123: Undefined function: %s"
+msgstr "E123: Función indefinida: %s"
+
+#: eval.c:19831
+#, c-format
+msgid "E124: Missing '(': %s"
+msgstr "E124: Falta un \"(\": %s"
+
+#: eval.c:19887
+#, c-format
+msgid "E125: Illegal argument: %s"
+msgstr "E125: Argumento ilegal: %s"
+
+#: eval.c:19997
+msgid "E126: Missing :endfunction"
+msgstr "E126: Falta un \":endfunction\""
+
+#: eval.c:20134
+#, c-format
+msgid "E707: Function name conflicts with variable: %s"
+msgstr "E707: El nombre de la función entran en conflicto con la variable: %s"
+
+#: eval.c:20149
+#, c-format
+msgid "E127: Cannot redefine function %s: It is in use"
+msgstr "E127: No se puede redefinir la función %s: Está en uso"
+
+#: eval.c:20214
+#, c-format
+msgid "E746: Function name does not match script file name: %s"
+msgstr "E746: Nombre de función no concuerda con el nombre de archivo: %s"
+
+#: eval.c:20332
+msgid "E129: Function name required"
+msgstr "E129: Se requiere el nombre de la función"
+
+#: eval.c:20452
+#, c-format
+msgid "E128: Function name must start with a capital or contain a colon: %s"
+msgstr ""
+"E128: El nombre de una función debe empezar con mayúscula o contener el "
+"signo de dos puntos: %s"
+
+#: eval.c:20984
+#, c-format
+msgid "E131: Cannot delete function %s: It is in use"
+msgstr "E131: No se pudo eliminar la función %s: Está en uso"
+
+#: eval.c:21104
+msgid "E132: Function call depth is higher than 'maxfuncdepth'"
+msgstr ""
+"E132: La recursión de llamada de la función es mayor que \"maxfuncdepth\""
+
+# always scroll up, don't overwrite
+#: eval.c:21243
+#, c-format
+msgid "calling %s"
+msgstr "Invocando %s"
+
+#: eval.c:21335
+#, c-format
+msgid "%s aborted"
+msgstr "Abortada la ejecución de %s"
+
+#: eval.c:21337
+#, c-format
+msgid "%s returning #%ld"
+msgstr "%s devuelve #%ld"
+
+#: eval.c:21353
+#, c-format
+msgid "%s returning %s"
+msgstr "%s devuelve %s"
+
+# always scroll up, don't overwrite
+#: eval.c:21377 ex_cmds2.c:3145
+#, c-format
+msgid "continuing in %s"
+msgstr "continuando en %s"
+
+#: eval.c:21496
+msgid "E133: :return not inside a function"
+msgstr "E133: \":return\" no está dentro de una función"
+
+#: eval.c:21909
+#, c-format
+msgid ""
+"\n"
+"# global variables:\n"
+msgstr ""
+"\n"
+"# variables globales:\n"
+
+#: eval.c:22026
+msgid ""
+"\n"
+"\tLast set from "
+msgstr ""
+"\n"
+"\tSe definió por última vez en "
+
+#: eval.c:22046
+msgid "No old files"
+msgstr "No hay archivos antiguos"
+
+#: ex_cmds.c:101
+#, c-format
+msgid "<%s>%s%s %d, Hex %02x, Octal %03o"
+msgstr "<%s>%s%s %d, Hex %02x, Octal %03o"
+
+#: ex_cmds.c:128
+#, c-format
+msgid "> %d, Hex %04x, Octal %o"
+msgstr "> %d, Hex %04x, Octal %o"
+
+#: ex_cmds.c:129
+#, c-format
+msgid "> %d, Hex %08x, Octal %o"
+msgstr "> %d, Hex %08x, Octal %o"
+
+#: ex_cmds.c:739
+msgid "E134: Move lines into themselves"
+msgstr "E134: Moviendo líneas sobre sí mismas"
+
+#: ex_cmds.c:808
+msgid "1 line moved"
+msgstr "1 línea movida"
+
+#: ex_cmds.c:810
+#, c-format
+msgid "%ld lines moved"
+msgstr "%ld líneas movidas"
+
+#: ex_cmds.c:1305
+#, c-format
+msgid "%ld lines filtered"
+msgstr "%ld líneas filtradas"
+
+#: ex_cmds.c:1329
+msgid "E135: *Filter* Autocommands must not change current buffer"
+msgstr "E135: *Filtro* Las auto-órdenes no deben cambiar el búfer en uso"
+
+#: ex_cmds.c:1414
+msgid "[No write since last change]\n"
+msgstr "[No se ha escrito nada al disco desde el último cambio]\n"
+
+#: ex_cmds.c:1672
+#, c-format
+msgid "%sviminfo: %s in line: "
+msgstr "%sviminfo: %s en la línea: "
+
+#: ex_cmds.c:1680
+msgid "E136: viminfo: Too many errors, skipping rest of file"
+msgstr "E136: viminfo: Demasiados errores, omitiendo el resto del archivo"
+
+#: ex_cmds.c:1709
+#, c-format
+msgid "Reading viminfo file \"%s\"%s%s%s"
+msgstr "Leyendo el archivo \"viminfo\" \"%s\"%s%s%s"
+
+#: ex_cmds.c:1711
+msgid " info"
+msgstr " info"
+
+#: ex_cmds.c:1712
+msgid " marks"
+msgstr " marcas"
+
+#: ex_cmds.c:1713
+msgid " oldfiles"
+msgstr " archivos antiguos"
+
+#: ex_cmds.c:1714
+msgid " FAILED"
+msgstr " FALLÓ"
+
+#. avoid a wait_return for this message, it's annoying
+#: ex_cmds.c:1810
+#, c-format
+msgid "E137: Viminfo file is not writable: %s"
+msgstr "E137: No hay permisos de escritura para el archivo \"viminfo\": %s"
+
+#: ex_cmds.c:1963
+#, c-format
+msgid "E138: Can't write viminfo file %s!"
+msgstr "E138: ¡No se pudo escribir el archivo \"viminfo\" %s!"
+
+#: ex_cmds.c:1973
+#, c-format
+msgid "Writing viminfo file \"%s\""
+msgstr "Escribiendo archivo \"viminfo\" \"%s\""
+
+# Write the info:
+#. Write the info:
+#: ex_cmds.c:2081
+#, c-format
+msgid "# This viminfo file was generated by Vim %s.\n"
+msgstr "# Vim %s generó este archivo \"viminfo\".\n"
+
+#: ex_cmds.c:2083
+#, c-format
+msgid ""
+"# You may edit it if you're careful!\n"
+"\n"
+msgstr ""
+"# Puede editarlo, ¡sólo si tiene cuidado!\n"
+"\n"
+
+#: ex_cmds.c:2085
+#, c-format
+msgid "# Value of 'encoding' when this file was written\n"
+msgstr "# Valor de 'encoding' cuando se escribió este archivo\n"
+
+#: ex_cmds.c:2185
+msgid "Illegal starting char"
+msgstr "Carácter de comienzo ilegal"
+
+#: ex_cmds.c:2551 ex_cmds2.c:1407
+msgid "Save As"
+msgstr "Guardar como"
+
+#: ex_cmds.c:2628
+msgid "Write partial file?"
+msgstr "¿Escribir un archivo parcial?"
+
+#: ex_cmds.c:2635
+msgid "E140: Use ! to write partial buffer"
+msgstr "E140: Use \"!\" para escribir un búfer parcial"
+
+#: ex_cmds.c:2777
+#, c-format
+msgid "Overwrite existing file \"%s\"?"
+msgstr "¿Escribir sobre el archivo existente \"%s\"?"
+
+#: ex_cmds.c:2820
+#, c-format
+msgid "Swap file \"%s\" exists, overwrite anyway?"
+msgstr "Ya existe un archivo de intercambio \"%s\", desea sobreescribirlo? "
+
+#: ex_cmds.c:2833
+#, c-format
+msgid "E768: Swap file exists: %s (:silent! overrides)"
+msgstr ""
+"E768: El archivo de intercambio ya existe: %s (use ! para sobreescribir)"
+
+#: ex_cmds.c:2901
+#, c-format
+msgid "E141: No file name for buffer %ld"
+msgstr "E141: No existe un nombre de archivo para el búfer %ld"
+
+#: ex_cmds.c:2940
+msgid "E142: File not written: Writing is disabled by 'write' option"
+msgstr ""
+"E142: No se ha escrito el archivo: escritura desactivada por "
+"la opción 'write'"
+
+#: ex_cmds.c:2970
+#, c-format
+msgid ""
+"'readonly' option is set for \"%s\".\n"
+"Do you wish to write anyway?"
+msgstr ""
+"Se ha activado la opción de solo lectura ('readonly') para %s.\n"
+"¿Desea escribir de todas formas?"
+
+#: ex_cmds.c:2973
+#, c-format
+msgid ""
+"File permissions of \"%s\" are read-only.\n"
+"It may still be possible to write it.\n"
+"Do you wish to try?"
+msgstr ""
+"Los permisos del archivo \"%s\" son de\n"
+"sólo lectura. Cabe la posibilidad de escribir\n"
+"en él. ¿Desea intentarlo?"
+
+#: ex_cmds.c:2990
+#, c-format
+msgid "E505: \"%s\" is read-only (add ! to override)"
+msgstr "E505: \"%s\" es de solo lectura (añada ! para sobreescribir)"
+
+#: ex_cmds.c:3177
+msgid "Edit File"
+msgstr "Editar archivo"
+
+#: ex_cmds.c:3847
+#, c-format
+msgid "E143: Autocommands unexpectedly deleted new buffer %s"
+msgstr "E143: Las auto-órdenes han eliminado al nuevo búfer %s"
+
+#: ex_cmds.c:4063
+msgid "E144: non-numeric argument to :z"
+msgstr "E144: Argumento no numérico para \":z\""
+
+#: ex_cmds.c:4162
+msgid "E145: Shell commands not allowed in rvim"
+msgstr "E145: No se permiten órdenes de consola en rvim"
+
+#: ex_cmds.c:4261
+msgid "E146: Regular expressions can't be delimited by letters"
+msgstr "E146: Las expresiones regulares no se pueden delimitar con letras"
+
+#: ex_cmds.c:4721
+#, c-format
+msgid "replace with %s (y/n/a/q/l/^E/^Y)?"
+msgstr "¿Reemplazar con %s (y/n/a/q/l/^E/^Y)?"
+
+#: ex_cmds.c:5166
+msgid "(Interrupted) "
+msgstr "(Interrumpido)"
+
+#: ex_cmds.c:5171
+msgid "1 match"
+msgstr "Una (1) coincidencia"
+
+#: ex_cmds.c:5171
+msgid "1 substitution"
+msgstr "Una (1) sustitución"
+
+#: ex_cmds.c:5174
+#, c-format
+msgid "%ld matches"
+msgstr "%ld coincidencias"
+
+#: ex_cmds.c:5174
+#, c-format
+msgid "%ld substitutions"
+msgstr "%ld sustituciones"
+
+#: ex_cmds.c:5179
+msgid " on 1 line"
+msgstr " en una (1) línea"
+
+#: ex_cmds.c:5182
+#, c-format
+msgid " on %ld lines"
+msgstr " en %ld líneas"
+
+#: ex_cmds.c:5229
+msgid "E147: Cannot do :global recursive"
+msgstr "E147: \":global\" no puede ser recursivo"
+
+#: ex_cmds.c:5264
+msgid "E148: Regular expression missing from global"
+msgstr "E148: Falta una expresión regular en \":global\""
+
+#: ex_cmds.c:5313
+#, c-format
+msgid "Pattern found in every line: %s"
+msgstr "Patrón encontrado en cada línea: %s"
+
+#: ex_cmds.c:5398
+#, c-format
+msgid ""
+"\n"
+"# Last Substitute String:\n"
+"$"
+msgstr ""
+"\n"
+"# Última cadena de sustitución:\n"
+"$"
+
+#: ex_cmds.c:5511
+msgid "E478: Don't panic!"
+msgstr "E478: ¡No entre en pánico!"
+
+#: ex_cmds.c:5557
+#, c-format
+msgid "E661: Sorry, no '%s' help for %s"
+msgstr "E661: Lo siento, no hay ayuda '%s' para \"%s\""
+
+#: ex_cmds.c:5560
+#, c-format
+msgid "E149: Sorry, no help for %s"
+msgstr "E149: Lo siento, no hay ayuda para \"%s\""
+
+#: ex_cmds.c:5602
+#, c-format
+msgid "Sorry, help file \"%s\" not found"
+msgstr "Lo siento, no encuentro el archivo de ayuda \"%s\""
+
+#: ex_cmds.c:6180
+#, c-format
+msgid "E150: Not a directory: %s"
+msgstr "E150: No es un directorio: %s"
+
+#: ex_cmds.c:6323
+#, c-format
+msgid "E152: Cannot open %s for writing"
+msgstr "E152: No se pudo abrir %s para escritura"
+
+#: ex_cmds.c:6360
+#, c-format
+msgid "E153: Unable to open %s for reading"
+msgstr "E153: Incapaz de abrir %s para lectura"
+
+#: ex_cmds.c:6396
+#, c-format
+msgid "E670: Mix of help file encodings within a language: %s"
+msgstr ""
+"E670: Mezcla de codificaciones en archivos de ayuda dentro de un lenguaje: %s"
+
+#: ex_cmds.c:6474
+#, c-format
+msgid "E154: Duplicate tag \"%s\" in file %s/%s"
+msgstr "E154: Etiqueta \"%s\" duplicada en el archivo %s/%s"
+
+#: ex_cmds.c:6610
+#, c-format
+msgid "E160: Unknown sign command: %s"
+msgstr "E160: Orden de signo desconocida: %s"
+
+#: ex_cmds.c:6627
+msgid "E156: Missing sign name"
+msgstr "E156: Falta el nombre del signo"
+
+#: ex_cmds.c:6673
+msgid "E612: Too many signs defined"
+msgstr "E612: Demasiados signos definidos"
+
+#: ex_cmds.c:6741
+#, c-format
+msgid "E239: Invalid sign text: %s"
+msgstr "E239: El texto de signo no es válido: %s"
+
+#: ex_cmds.c:6772 ex_cmds.c:6947
+#, c-format
+msgid "E155: Unknown sign: %s"
+msgstr "E155: Signo desconocido: %s"
+
+#: ex_cmds.c:6805
+msgid "E159: Missing sign number"
+msgstr "E159: Falta el número del signo"
+
+#: ex_cmds.c:6887
+#, c-format
+msgid "E158: Invalid buffer name: %s"
+msgstr "E158: El nombre del búfer no es válido: %s"
+
+#: ex_cmds.c:6926
+#, c-format
+msgid "E157: Invalid sign ID: %ld"
+msgstr "E157: La identificación del signo no es válida: %ld"
+
+#: ex_cmds.c:6996
+msgid " (NOT FOUND)"
+msgstr " (NO ENCONTRADO)"
+
+#: ex_cmds.c:6998
+msgid " (not supported)"
+msgstr " (no hay apoyo para la función pedida)"
+
+#: ex_cmds.c:7122
+msgid "[Deleted]"
+msgstr "[Suprimido]"
+
+#: ex_cmds2.c:138
+msgid "Entering Debug mode. Type \"cont\" to continue."
+msgstr "Iniciando modo de depuración. Escriba \"cont\" para continuar."
+
+#: ex_cmds2.c:142 ex_docmd.c:1081
+#, c-format
+msgid "line %ld: %s"
+msgstr "línea %ld: %s"
+
+#: ex_cmds2.c:144
+#, c-format
+msgid "cmd: %s"
+msgstr "cmd: %s"
+
+#: ex_cmds2.c:344
+#, c-format
+msgid "Breakpoint in \"%s%s\" line %ld"
+msgstr "\"Breakpoint\" en \"%s%s\" línea %ld"
+
+#: ex_cmds2.c:656
+#, c-format
+msgid "E161: Breakpoint not found: %s"
+msgstr "E161: No se ha encontrado el \"breakpoint\": %s"
+
+#: ex_cmds2.c:692
+msgid "No breakpoints defined"
+msgstr "No se han definido \"breakpoints\""
+
+#: ex_cmds2.c:697
+#, c-format
+msgid "%3d %s %s line %ld"
+msgstr "%3d %s %s línea %ld"
+
+#: ex_cmds2.c:1095
+msgid "E750: First use :profile start <fname>"
+msgstr "E750: Primero use \":profile start <nombre_de_archivo>\""
+
+#: ex_cmds2.c:1432
+#, c-format
+msgid "Save changes to \"%s\"?"
+msgstr "¿Guardar los cambios en \"%s\"?"
+
+#: ex_cmds2.c:1434 ex_docmd.c:10814
+msgid "Untitled"
+msgstr "Sin título"
+
+#: ex_cmds2.c:1563
+#, c-format
+msgid "E162: No write since last change for buffer \"%s\""
+msgstr "E162: No se ha grabado nada desde el último cambio en el búfer \"%s\""
+
+#: ex_cmds2.c:1634
+msgid "Warning: Entered other buffer unexpectedly (check autocommands)"
+msgstr ""
+"Advertencia: se ha entrado en otro búfer de forma inesperada (verifique las "
+"auto-órdenes)"
+
+#: ex_cmds2.c:2078
+msgid "E163: There is only one file to edit"
+msgstr "E163: Hay sólo un archivo para editar"
+
+#: ex_cmds2.c:2080
+msgid "E164: Cannot go before first file"
+msgstr "E164: No se pudo regresar antes del primer archivo"
+
+#: ex_cmds2.c:2082
+msgid "E165: Cannot go beyond last file"
+msgstr "E165: No se pudo ir más allá del último archivo"
+
+#: ex_cmds2.c:2511
+#, c-format
+msgid "E666: compiler not supported: %s"
+msgstr "E666: El compilador no es compatible en esta versión: %s"
+
+#: ex_cmds2.c:2612
+#, c-format
+msgid "Searching for \"%s\" in \"%s\""
+msgstr "Buscando \"%s\" en \"%s\""
+
+#: ex_cmds2.c:2639
+#, c-format
+msgid "Searching for \"%s\""
+msgstr "Buscando \"%s\""
+
+#: ex_cmds2.c:2665
+#, c-format
+msgid "not found in 'runtimepath': \"%s\""
+msgstr "No se ha encontrado en 'runtimepath': %s"
+
+#: ex_cmds2.c:2700
+msgid "Source Vim script"
+msgstr "Ejecute archivo de órdenes de Vim"
+
+#: ex_cmds2.c:2875
+#, c-format
+msgid "Cannot source a directory: \"%s\""
+msgstr "No se pudo ejecutar un directorio: %s"
+
+#: ex_cmds2.c:2932
+#, c-format
+msgid "could not source \"%s\""
+msgstr "No pude ejecutar %s"
+
+#: ex_cmds2.c:2934
+#, c-format
+msgid "line %ld: could not source \"%s\""
+msgstr "línea %ld: no se pudo ejecutar %s"
+
+#: ex_cmds2.c:2950
+#, c-format
+msgid "sourcing \"%s\""
+msgstr "ejecutando %s"
+
+#: ex_cmds2.c:2952
+#, c-format
+msgid "line %ld: sourcing \"%s\""
+msgstr "línea %ld: ejecutando %s"
+
+#: ex_cmds2.c:3143
+#, c-format
+msgid "finished sourcing %s"
+msgstr "La ejecución de %s ha terminado"
+
+#: ex_cmds2.c:3224
+msgid "modeline"
+msgstr "modeline"
+
+#: ex_cmds2.c:3226
+msgid "--cmd argument"
+msgstr "--cmd [argumentos]"
+
+#: ex_cmds2.c:3228
+msgid "-c argument"
+msgstr "-c [argumentos]"
+
+#: ex_cmds2.c:3230
+msgid "environment variable"
+msgstr "variable de entorno"
+
+#: ex_cmds2.c:3232
+msgid "error handler"
+msgstr "administrador de errores"
+
+#: ex_cmds2.c:3524
+msgid "W15: Warning: Wrong line separator, ^M may be missing"
+msgstr "W15: Advertencia: separador de línea incorrecto, puede que falte ^M"
+
+#: ex_cmds2.c:3657
+msgid "E167: :scriptencoding used outside of a sourced file"
+msgstr ""
+"E167: Ha usado \":scriptencoding\" fuera de un archivo de instrucciones "
+"ejecutables"
+
+#: ex_cmds2.c:3690
+msgid "E168: :finish used outside of a sourced file"
+msgstr ""
+"E168: Ha usado \":finish\" fuera de un archivo de instrucciones ejecutables"
+
+#: ex_cmds2.c:4012
+#, c-format
+msgid "Current %slanguage: \"%s\""
+msgstr "Idioma actual %s: \"%s\""
+
+#: ex_cmds2.c:4029
+#, c-format
+msgid "E197: Cannot set language to \"%s\""
+msgstr "E197: No se pudo establecer la opción del idioma a \"%s\""
+
+#: ex_docmd.c:626
+msgid "Entering Ex mode. Type \"visual\" to go to Normal mode."
+msgstr "Entrando al modo Ex. Escriba \"visual\" para ir al modo Normal"
+
+# must be at EOF
+#: ex_docmd.c:681
+msgid "E501: At end-of-file"
+msgstr "E501: Estoy al final del archivo"
+
+#: ex_docmd.c:780
+msgid "E169: Command too recursive"
+msgstr "E169: Orden demasiado recursiva"
+
+#: ex_docmd.c:1359
+#, c-format
+msgid "E605: Exception not caught: %s"
+msgstr "E605: La excepción %s no se atrapó"
+
+#: ex_docmd.c:1447
+msgid "End of sourced file"
+msgstr "Fin del archivo de instrucciones ejecutables"
+
+#: ex_docmd.c:1448
+msgid "End of function"
+msgstr "Fin de la función"
+
+#: ex_docmd.c:2096
+msgid "E464: Ambiguous use of user-defined command"
+msgstr "E464: Uso ambiguo de una orden definida por el usuario"
+
+#: ex_docmd.c:2110
+msgid "E492: Not an editor command"
+msgstr "E492: No es una orden del editor"
+
+#: ex_docmd.c:2242
+msgid "E493: Backwards range given"
+msgstr "E493: Me ha dado un rango invertido"
+
+#: ex_docmd.c:2246
+msgid "Backwards range given, OK to swap"
+msgstr "Se devolvió un rango invertido, ¿puedo intercambiarlo?"
+
+#: ex_docmd.c:2309
+msgid "E494: Use w or w>>"
+msgstr "E494: Use \"w\" o \"w>>\""
+
+#: ex_docmd.c:4076
+msgid "E319: Sorry, the command is not available in this version"
+msgstr "E319: Lo siento, esa orden no está disponible en esta versión"
+
+#: ex_docmd.c:4425
+msgid "E172: Only one file name allowed"
+msgstr "E172: Solo se permite un nombre de archivo"
+
+#: ex_docmd.c:5036
+msgid "1 more file to edit. Quit anyway?"
+msgstr "Un (1) archivo más para editar. ¿Cerrar de todas formas?"
+
+#: ex_docmd.c:5039
+#, c-format
+msgid "%d more files to edit. Quit anyway?"
+msgstr "Hay %d archivos más en edición. ¿Cerrar de todas formas?"
+
+#: ex_docmd.c:5046
+msgid "E173: 1 more file to edit"
+msgstr "E173: Un (1) archivo más para editar"
+
+#: ex_docmd.c:5048
+#, c-format
+msgid "E173: %ld more files to edit"
+msgstr "E173: Hay %ld archivos en edición"
+
+#: ex_docmd.c:5142
+msgid "E174: Command already exists: add ! to replace it"
+msgstr "E174: Ya existe esa orden. Añada \"!\" para reemplazarla"
+
+#: ex_docmd.c:5264
+msgid ""
+"\n"
+" Name Args Range Complete Definition"
+msgstr ""
+"\n"
+" Nombre Args Rango Completar Definición"
+
+#: ex_docmd.c:5357
+msgid "No user-defined commands found"
+msgstr "No se han encontrado órdenes definidos por el usuario"
+
+#: ex_docmd.c:5389
+msgid "E175: No attribute specified"
+msgstr "E175: No se ha especificado el atributo"
+
+#: ex_docmd.c:5441
+msgid "E176: Invalid number of arguments"
+msgstr "E176: El número de argumentos no es válido"
+
+#: ex_docmd.c:5456
+msgid "E177: Count cannot be specified twice"
+msgstr "E177: El recuento no se puede especificar dos veces"
+
+#: ex_docmd.c:5466
+msgid "E178: Invalid default value for count"
+msgstr "E178: El valor predeterminado para el recuento no es válido"
+
+#: ex_docmd.c:5494
+msgid "E179: argument required for -complete"
+msgstr "E179: se necesita un argumento para \"-complete\""
+
+#: ex_docmd.c:5506
+#, c-format
+msgid "E181: Invalid attribute: %s"
+msgstr "E181: El atributo no es válido: %s"
+
+#: ex_docmd.c:5552
+msgid "E182: Invalid command name"
+msgstr "E182: El nombre de la orden no es válido"
+
+#: ex_docmd.c:5567
+msgid "E183: User defined commands must start with an uppercase letter"
+msgstr ""
+"E183: Las órdenes definidas por el usuario deben comenzar con mayúscula"
+
+#: ex_docmd.c:5635
+#, c-format
+msgid "E184: No such user-defined command: %s"
+msgstr "E184: No existe esa orden definida por el usuario: %s"
+
+#: ex_docmd.c:6187
+#, c-format
+msgid "E180: Invalid complete value: %s"
+msgstr "E180: El valor para completar no es válido: %s"
+
+#: ex_docmd.c:6198
+msgid "E468: Completion argument only allowed for custom completion"
+msgstr ""
+"E468: El argumento de finalización solo se permite en finalizaciones "
+"definidas por el usuario"
+
+#: ex_docmd.c:6206
+msgid "E467: Custom completion requires a function argument"
+msgstr ""
+"E467: Las finalizaciones definidas por el usuario requieren de un argumento "
+"de función"
+
+#: ex_docmd.c:6222
+#, c-format
+msgid "E185: Cannot find color scheme %s"
+msgstr "E185: No se pudo encontrar el esquema de colores %s"
+
+#: ex_docmd.c:6230
+msgid "Greetings, Vim user!"
+msgstr "¡Saludos, usuario de Vim!"
+
+#: ex_docmd.c:6448
+msgid "E784: Cannot close last tab page"
+msgstr "E784: No se pudo cerrar la última ventana"
+
+#: ex_docmd.c:6490
+msgid "Already only one tab page"
+msgstr "Solo hay una ventana"
+
+#: ex_docmd.c:7177
+msgid "Edit File in new window"
+msgstr "Editar archivo en una ventana nueva"
+
+#: ex_docmd.c:7303
+#, c-format
+msgid "Tab page %d"
+msgstr "Página %d"
+
+#: ex_docmd.c:7695
+msgid "No swap file"
+msgstr "No hay archivo de intercambio"
+
+#: ex_docmd.c:7800
+msgid "Append File"
+msgstr "Añadir archivo"
+
+#: ex_docmd.c:7899
+msgid "E747: Cannot change directory, buffer is modified (add ! to override)"
+msgstr ""
+"E747: No se pudo cambiar de directorio, el búfer fue modificado (añada ! "
+"para forzar la orden)"
+
+#: ex_docmd.c:7908
+msgid "E186: No previous directory"
+msgstr "E186: No hay un directorio previo"
+
+#: ex_docmd.c:7989
+msgid "E187: Unknown"
+msgstr "E187: Desconocido"
+
+#: ex_docmd.c:8084
+msgid "E465: :winsize requires two number arguments"
+msgstr "E465: \":winsize\" requiere de dos argumentos numéricos"
+
+#: ex_docmd.c:8146
+#, c-format
+msgid "Window position: X %d, Y %d"
+msgstr "Posición de la ventana: X %d, Y %d"
+
+#: ex_docmd.c:8151
+msgid "E188: Obtaining window position not implemented for this platform"
+msgstr ""
+"E188: Obtener la posición de la ventana no está implementado en esta "
+"plataforma"
+
+#: ex_docmd.c:8161
+msgid "E466: :winpos requires two number arguments"
+msgstr "E466: \":winpos\" requiere de dos argumentos numéricos"
+
+#: ex_docmd.c:8499
+msgid "Save Redirection"
+msgstr "Guardar redirección"
+
+#: ex_docmd.c:8730
+msgid "Save View"
+msgstr "Guardar vista"
+
+#: ex_docmd.c:8731
+msgid "Save Session"
+msgstr "Guardar sesión"
+
+#: ex_docmd.c:8733
+msgid "Save Setup"
+msgstr "Guardar configuración"
+
+#: ex_docmd.c:8889
+#, c-format
+msgid "E739: Cannot create directory: %s"
+msgstr "E739: No se pudo crear directorio: %s"
+
+#: ex_docmd.c:8918
+#, c-format
+msgid "E189: \"%s\" exists (add ! to override)"
+msgstr "E189: \"%s\" ya existe (añada ! para sobreescribir.)"
+
+#: ex_docmd.c:8923
+#, c-format
+msgid "E190: Cannot open \"%s\" for writing"
+msgstr "E190: No se pudo abrir \"%s\" para escrbir"
+
+# set mark
+#. set mark
+#: ex_docmd.c:8947
+msgid "E191: Argument must be a letter or forward/backward quote"
+msgstr ""
+"E191: El argumento debe ser una letra o una comilla simple/comilla simple "
+"invertida"
+
+#: ex_docmd.c:8994
+msgid "E192: Recursive use of :normal too deep"
+msgstr "E192: Excesivo uso recursivo de \":normal\""
+
+#: ex_docmd.c:9593
+msgid "E809: #< is not available without the +eval feature"
+msgstr "E809: #< no está disponible sin la característica \"+eval\""
+
+#: ex_docmd.c:9602
+msgid "E194: No alternate file name to substitute for '#'"
+msgstr "E194: No hay un nombre de archivo alterno que sustituya a '#'"
+
+#: ex_docmd.c:9643
+msgid "E495: no autocommand file name to substitute for \"<afile>\""
+msgstr ""
+"E495: No se ha dado un nombre de archivo de auto-órdenes para sustituir a "
+"\"<afile>\""
+
+#: ex_docmd.c:9652
+msgid "E496: no autocommand buffer number to substitute for \"<abuf>\""
+msgstr "E496: No existe un búfer de auto-órdenes para sustituir por \"<abuf>\""
+
+#: ex_docmd.c:9663
+msgid "E497: no autocommand match name to substitute for \"<amatch>\""
+msgstr ""
+"E497: Ningún nombre de auto-orden concuerda para sustituir \"<amatch>\""
+
+#: ex_docmd.c:9673
+msgid "E498: no :source file name to substitute for \"<sfile>\""
+msgstr ""
+"E498: No hay un nombre de archivo \":source\" que sustituya a \"<sfile>\""
+
+#: ex_docmd.c:9715
+#, no-c-format
+msgid "E499: Empty file name for '%' or '#', only works with \":p:h\""
+msgstr ""
+"E499: Un nombre de archivo vacío para \"%\" o \"#\" solo funciona con \":p:h"
+"\""
+
+#: ex_docmd.c:9717
+msgid "E500: Evaluates to an empty string"
+msgstr "E500: La expresión evalúa a una cadena vacía"
+
+#: ex_docmd.c:10794
+msgid "E195: Cannot open viminfo file for reading"
+msgstr "E195: No se pudo abrir el archivo \"viminfo\" para lectura"
+
+#: ex_docmd.c:10964
+msgid "E196: No digraphs in this version"
+msgstr "E196: No hay dígrafos en esta versión"
+
+#: ex_eval.c:441
+msgid "E608: Cannot :throw exceptions with 'Vim' prefix"
+msgstr ""
+"E608: No se pudo lanzar (':throw') excepciones si tienen el prefijo 'Vim'"
+
+# always scroll up, don't overwrite
+#. always scroll up, don't overwrite
+#: ex_eval.c:534
+#, c-format
+msgid "Exception thrown: %s"
+msgstr "Excepción lanzada: %s"
+
+#: ex_eval.c:588
+#, c-format
+msgid "Exception finished: %s"
+msgstr "Excepción terminada: %s"
+
+#: ex_eval.c:589
+#, c-format
+msgid "Exception discarded: %s"
+msgstr "Excepción descartada: %s"
+
+#: ex_eval.c:635 ex_eval.c:687
+#, c-format
+msgid "%s, line %ld"
+msgstr "%s, en la línea %ld"
+
+# always scroll up, don't overwrite
+#. always scroll up, don't overwrite
+#: ex_eval.c:657
+#, c-format
+msgid "Exception caught: %s"
+msgstr "Excepción atrapada: %s"
+
+#: ex_eval.c:737
+#, c-format
+msgid "%s made pending"
+msgstr "%s ha pasado a la lista de pendientes"
+
+#: ex_eval.c:740
+#, c-format
+msgid "%s resumed"
+msgstr "%s continuado"
+
+#: ex_eval.c:744
+#, c-format
+msgid "%s discarded"
+msgstr "%s descartado"
+
+#: ex_eval.c:771
+msgid "Exception"
+msgstr "Excepción"
+
+#: ex_eval.c:777
+msgid "Error and interrupt"
+msgstr "Error e interrupción"
+
+#: ex_eval.c:779 gui.c:4870 gui_xmdlg.c:689 gui_xmdlg.c:808 os_mswin.c:597
+msgid "Error"
+msgstr "Error"
+
+# if (pending & CSTP_INTERRUPT)
+#. if (pending & CSTP_INTERRUPT)
+#: ex_eval.c:781
+msgid "Interrupt"
+msgstr "Interrupción"
+
+#: ex_eval.c:873
+msgid "E579: :if nesting too deep"
+msgstr "E579: ¡\":if\" anidado en exceso!"
+
+#: ex_eval.c:910
+msgid "E580: :endif without :if"
+msgstr "E580: ¡\":endif\" sin un \":if\"!"
+
+#: ex_eval.c:955
+msgid "E581: :else without :if"
+msgstr "E581: ¡\":else\" sin un \":if\"!"
+
+#: ex_eval.c:958
+msgid "E582: :elseif without :if"
+msgstr "E582: ¡\":elseif\" sin un \":if\"!"
+
+#: ex_eval.c:965
+msgid "E583: multiple :else"
+msgstr "E583: ¡\":else\" múltiple!"
+
+#: ex_eval.c:968
+msgid "E584: :elseif after :else"
+msgstr "E584: ¡\":elseif\" después de \":else\"!"
+
+#: ex_eval.c:1035
+msgid "E585: :while/:for nesting too deep"
+msgstr "E585: ¡\":while\" anidado en exceso!"
+
+#: ex_eval.c:1133
+msgid "E586: :continue without :while or :for"
+msgstr "E586: ¡\":continue\" sin un \":while\" o \":for\"!"
+
+#: ex_eval.c:1172
+msgid "E587: :break without :while or :for"
+msgstr "E587: ¡\":break\" sin \":while\" o \":for\"!"
+
+#: ex_eval.c:1222
+msgid "E732: Using :endfor with :while"
+msgstr "E732: Usando \":endfor\" con \":while\""
+
+#: ex_eval.c:1224
+msgid "E733: Using :endwhile with :for"
+msgstr "E733: Usando \":endwhile\" con \":for\""
+
+#: ex_eval.c:1399
+msgid "E601: :try nesting too deep"
+msgstr "E601: ¡\":try\" anidado en exceso!"
+
+#: ex_eval.c:1479
+msgid "E603: :catch without :try"
+msgstr "E603: ¡\":catch\" sin un \":try\"!"
+
+# Give up for a ":catch" after ":finally" and ignore it.
+# * Just parse.
+#. Give up for a ":catch" after ":finally" and ignore it.
+#. * Just parse.
+#: ex_eval.c:1498
+msgid "E604: :catch after :finally"
+msgstr "E604: ¡\":catch\" después de \":finally\"!"
+
+#: ex_eval.c:1632
+msgid "E606: :finally without :try"
+msgstr "E606: ¡\":finally\" sin un \":try\"!"
+
+# Give up for a multiple ":finally" and ignore it.
+#. Give up for a multiple ":finally" and ignore it.
+#: ex_eval.c:1652
+msgid "E607: multiple :finally"
+msgstr "E607: ¡\":finally\" múltiple!"
+
+#: ex_eval.c:1762
+msgid "E602: :endtry without :try"
+msgstr "E602: ¡\":endtry\" sin un \":try\"!"
+
+#: ex_eval.c:2267
+msgid "E193: :endfunction not inside a function"
+msgstr "E193: ¡\":endfunction\" no está dentro de una función!"
+
+#: ex_getln.c:2010
+msgid "E788: Not allowed to edit another buffer now"
+msgstr "E788: No se permite editar otro búfer en este momento"
+
+#: ex_getln.c:2025
+msgid "E811: Not allowed to change buffer information now"
+msgstr "E811: No se permite cambiar la información del búfer en este momento"
+
+#: ex_getln.c:3924
+msgid "tagname"
+msgstr "Nombre de la etiqueta (\"tagname\")"
+
+#: ex_getln.c:3927
+msgid " kind file\n"
+msgstr " tipo de archivo\n"
+
+#: ex_getln.c:5676
+msgid "'history' option is zero"
+msgstr "La opción 'history' (historia) es cero"
+
+#: ex_getln.c:5947
+#, c-format
+msgid ""
+"\n"
+"# %s History (newest to oldest):\n"
+msgstr ""
+"\n"
+"# Historia de %s (de lo más nuevo a lo más antiguo):\n"
+
+#: ex_getln.c:5948
+msgid "Command Line"
+msgstr "Línea de órdenes"
+
+#: ex_getln.c:5949
+msgid "Search String"
+msgstr "Cadena de búsqueda"
+
+#: ex_getln.c:5950
+msgid "Expression"
+msgstr "Expresión"
+
+#: ex_getln.c:5951
+msgid "Input Line"
+msgstr "Línea de entrada"
+
+#: ex_getln.c:5989
+msgid "E198: cmd_pchar beyond the command length"
+msgstr "E198: \"cmd_pchar\" más allá de la longitud de la orden"
+
+#: ex_getln.c:6190
+msgid "E199: Active window or buffer deleted"
+msgstr "E199: Se borró la ventana o el búfer activo"
+
+#: fileio.c:153
+msgid "E812: Autocommands changed buffer or buffer name"
+msgstr "E812: *Filtro* Las auto-órdenes no deben cambiar el búfer en uso"
+
+#: fileio.c:408
+msgid "Illegal file name"
+msgstr "Nombre de archivo ilegal"
+
+#: fileio.c:437 fileio.c:591 fileio.c:3320 fileio.c:3371
+msgid "is a directory"
+msgstr "es un directorio"
+
+#: fileio.c:439
+msgid "is not a file"
+msgstr "no es un archivo"
+
+#: fileio.c:452
+msgid "is a device (disabled with 'opendevice' option)"
+msgstr "es un dispositivo (desactivado con la opción 'opendevice')"
+
+#: fileio.c:628 fileio.c:4605
+msgid "[New File]"
+msgstr "[Archivo nuevo]"
+
+#: fileio.c:631
+msgid "[New DIRECTORY]"
+msgstr "[Directorio nuevo]"
+
+#: fileio.c:665
+msgid "[File too big]"
+msgstr "[El archivo es demasiado grande]"
+
+#: fileio.c:667
+msgid "[Permission Denied]"
+msgstr "[Permiso denegado]"
+
+#: fileio.c:800
+msgid "E200: *ReadPre autocommands made the file unreadable"
+msgstr "E200: Las auto-órdenes \"*ReadPre\" hicieron ilegible el archivo"
+
+#: fileio.c:802
+msgid "E201: *ReadPre autocommands must not change current buffer"
+msgstr "E201: Las auto-órdenes \"*ReadPre\" no deben cambiar el búfer en uso"
+
+#: fileio.c:823
+msgid "Vim: Reading from stdin...\n"
+msgstr "Vim: Leyendo la entrada estándar...\n"
+
+#: fileio.c:829
+msgid "Reading from stdin..."
+msgstr "Leyendo la entrada estándar..."
+
+# Re-opening the original file failed!
+#. Re-opening the original file failed!
+#: fileio.c:1128
+msgid "E202: Conversion made file unreadable!"
+msgstr "E202: ¡La conversión ha hecho ilegible el archivo!"
+
+#: fileio.c:2362
+msgid "[fifo/socket]"
+msgstr "[fifo/socket]"
+
+#: fileio.c:2369
+msgid "[fifo]"
+msgstr "[fifo]"
+
+#: fileio.c:2376
+msgid "[socket]"
+msgstr "[socket]"
+
+#: fileio.c:2384
+msgid "[character special]"
+msgstr "[carácter especial]"
+
+#: fileio.c:2391 netbeans.c:3632
+msgid "[RO]"
+msgstr "[RO]"
+
+#: fileio.c:2401
+msgid "[CR missing]"
+msgstr "[Falta un CR]"
+
+#: fileio.c:2406
+msgid "[long lines split]"
+msgstr "[se han dividido las líneas largas]"
+
+#: fileio.c:2412 fileio.c:4589
+msgid "[NOT converted]"
+msgstr "[NO se ha convertido]"
+
+#: fileio.c:2417 fileio.c:4594
+msgid "[converted]"
+msgstr "[convertido]"
+
+#: fileio.c:2424 fileio.c:4619
+msgid "[crypted]"
+msgstr "[cifrado]"
+
+#: fileio.c:2432
+#, c-format
+msgid "[CONVERSION ERROR in line %ld]"
+msgstr "[ERROR DE CONVERSIÓN en línea %ld]"
+
+#: fileio.c:2438
+#, c-format
+msgid "[ILLEGAL BYTE in line %ld]"
+msgstr "[BYTE ILEGAL en la línea %ld]"
+
+#: fileio.c:2445
+msgid "[READ ERRORS]"
+msgstr "[ERRORES DE LECTURA]"
+
+#: fileio.c:2723
+msgid "Can't find temp file for conversion"
+msgstr "No se pudo encontrar el archivo temporal para la conversión"
+
+#: fileio.c:2730
+msgid "Conversion with 'charconvert' failed"
+msgstr "Falló la conversión con 'charconvert'"
+
+#: fileio.c:2733
+msgid "can't read output of 'charconvert'"
+msgstr "No se pudo leer el resultado de 'charconvert'"
+
+#: fileio.c:3165
+msgid "E676: No matching autocommands for acwrite buffer"
+msgstr "E676: No coincide ninguna auto-orden para \"acwrite\"en el búfer"
+
+#: fileio.c:3200
+msgid "E203: Autocommands deleted or unloaded buffer to be written"
+msgstr ""
+"E203: Las auto-órdenes fueron suprimidas o el búfer se descargó para ser "
+"grabado en disco"
+
+#: fileio.c:3223
+msgid "E204: Autocommand changed number of lines in unexpected way"
+msgstr ""
+"E204: La auto-orden ha cambiado el número de líneas en forma inesperada"
+
+#: fileio.c:3263
+msgid "NetBeans disallows writes of unmodified buffers"
+msgstr "NetBeans no permite que se escriba sobre búfers sin modificar"
+
+#: fileio.c:3271
+msgid "Partial writes disallowed for NetBeans buffers"
+msgstr "No se permite la escritura parcial de los búfers de NetBeans"
+
+#: fileio.c:3326 fileio.c:3344
+msgid "is not a file or writable device"
+msgstr "no es un archivo o dispositivo en el que se pueda escribir"
+
+#: fileio.c:3355
+msgid "writing to device disabled with 'opendevice' option"
+msgstr ""
+"se ha desactivado la escritura en dispositivo con la opción 'opendevice'"
+
+#: fileio.c:3397 netbeans.c:3694
+msgid "is read-only (add ! to override)"
+msgstr "es de solo lectura (añada ! para sobreescribir)"
+
+#: fileio.c:3761
+msgid "E506: Can't write to backup file (add ! to override)"
+msgstr ""
+"E506: No se pudo escribir en el archivo de recuperación "
+"(añada ! para forzar la orden)"
+
+#: fileio.c:3773
+msgid "E507: Close error for backup file (add ! to override)"
+msgstr ""
+"E507: Error al cerrar el archivo de la copia de seguridad (añada ! para "
+"forzar la orden)"
+
+#: fileio.c:3775
+msgid "E508: Can't read file for backup (add ! to override)"
+msgstr ""
+"E508: No se pudo leer el archivo para crear la copia de seguridad (añada ! "
+"para forzar la orden)"
+
+#: fileio.c:3794
+msgid "E509: Cannot create backup file (add ! to override)"
+msgstr ""
+"E509: No se pudo crear el archivo para la copia de seguridad (añada ! para "
+"forzar la orden)"
+
+#: fileio.c:3896
+msgid "E510: Can't make backup file (add ! to override)"
+msgstr ""
+"E510: No se pudo hacer un archivo de copia de seguridad (añada ! para forzar "
+"la orden)"
+
+#: fileio.c:3958
+msgid "E460: The resource fork would be lost (add ! to override)"
+msgstr ""
+"E460: Se perdería el segmento (\"fork\") de recursos (añada ! para forzar la "
+"orden)"
+
+#: fileio.c:4067
+msgid "E214: Can't find temp file for writing"
+msgstr "E214: No se pudo encontrar el archivo temporal para escribir en él"
+
+#: fileio.c:4085
+msgid "E213: Cannot convert (add ! to write without conversion)"
+msgstr ""
+"E213: No se pudo convertir (añada \"!\" para escribir el archivo sin "
+"conversión)"
+
+#: fileio.c:4120
+msgid "E166: Can't open linked file for writing"
+msgstr "E166: No se pudo abrir el archivo enlazado para escribir"
+
+#: fileio.c:4124
+msgid "E212: Can't open file for writing"
+msgstr "E212: No se pudo abrir el archivo para escribir en él"
+
+#: fileio.c:4405
+msgid "E667: Fsync failed"
+msgstr "E667: Falló \"fsync\" (sincronización de archivo)"
+
+#: fileio.c:4444
+msgid "E512: Close failed"
+msgstr "E512: Falló el cierre del archivo"
+
+#: fileio.c:4496
+msgid "E513: write error, conversion failed (make 'fenc' empty to override)"
+msgstr ""
+"E513: Error de escritura, la conversión falló (vacíe 'fenc' para forzar)."
+
+#: fileio.c:4501
+#, c-format
+msgid ""
+"E513: write error, conversion failed in line %ld (make 'fenc' empty to "
+"override)"
+msgstr ""
+"E513: Error de escritura, la conversión falló en la línea %ld(vacíe 'fenc' "
+"para forzar)"
+
+#: fileio.c:4510
+msgid "E514: write error (file system full?)"
+msgstr "E514: Error de escritura (¿Sistema de archivos lleno?)"
+
+#: fileio.c:4578
+msgid " CONVERSION ERROR"
+msgstr " ERROR DE CONVERSIÓN"
+
+#: fileio.c:4583
+#, c-format
+msgid " in line %ld;"
+msgstr "en la línea %ld"
+
+#: fileio.c:4600
+msgid "[Device]"
+msgstr "[Dispositivo]"
+
+#: fileio.c:4605
+msgid "[New]"
+msgstr "[Nuevo]"
+
+#: fileio.c:4627
+msgid " [a]"
+msgstr " [a]"
+
+#: fileio.c:4627
+msgid " appended"
+msgstr " añadido"
+
+#: fileio.c:4629
+msgid " [w]"
+msgstr " [w]"
+
+#: fileio.c:4629
+msgid " written"
+msgstr " escritos"
+
+#: fileio.c:4684
+msgid "E205: Patchmode: can't save original file"
+msgstr "E205: Modo de parcheo: no se puede guardar el archivo original"
+
+#: fileio.c:4707
+msgid "E206: patchmode: can't touch empty original file"
+msgstr "E206: Modo de parcheo: no se puede tocar el archivo original vacío"
+
+#: fileio.c:4722
+msgid "E207: Can't delete backup file"
+msgstr "E207: No se pudo borrar el archivo de respaldo"
+
+#: fileio.c:4788
+msgid ""
+"\n"
+"WARNING: Original file may be lost or damaged\n"
+msgstr ""
+"\n"
+"ADVERTENCIA: el archivo original puede haberse perdido o dañado\n"
+
+#: fileio.c:4790
+msgid "don't quit the editor until the file is successfully written!"
+msgstr "¡no salga del editor hasta que el archivo se haya escrito!"
+
+#: fileio.c:4932
+msgid "[dos]"
+msgstr "[DOS]"
+
+#: fileio.c:4932
+msgid "[dos format]"
+msgstr "[formato DOS]"
+
+#: fileio.c:4939
+msgid "[mac]"
+msgstr "[Mac]"
+
+#: fileio.c:4939
+msgid "[mac format]"
+msgstr "[formato Mac]"
+
+#: fileio.c:4946
+msgid "[unix]"
+msgstr "[UNIX]"
+
+#: fileio.c:4946
+msgid "[unix format]"
+msgstr "[formato UNIX]"
+
+#: fileio.c:4973
+msgid "1 line, "
+msgstr "1 línea, "
+
+#: fileio.c:4975
+#, c-format
+msgid "%ld lines, "
+msgstr "%ld líneas, "
+
+#: fileio.c:4978
+msgid "1 character"
+msgstr "1 carácter"
+
+#: fileio.c:4980
+#, c-format
+msgid "%ld characters"
+msgstr "%ld caracteres"
+
+#: fileio.c:4990 netbeans.c:3637
+msgid "[noeol]"
+msgstr "[no hay fin de línea]"
+
+#: fileio.c:4990 netbeans.c:3637
+msgid "[Incomplete last line]"
+msgstr "[Última línea incompleta]"
+
+# don't overwrite messages here
+# must give this prompt
+# don't use emsg() here, don't want to flush the buffers
+#. don't overwrite messages here
+#. must give this prompt
+#. don't use emsg() here, don't want to flush the buffers
+#: fileio.c:5009
+msgid "WARNING: The file has been changed since reading it!!!"
+msgstr "ADVERTENCIA: ¡¡¡El archivo ha cambiado desde que se leyó!!!"
+
+#: fileio.c:5011
+msgid "Do you really want to write to it"
+msgstr "¿Desea realmente escribir al archivo?"
+
+#: fileio.c:6375
+#, c-format
+msgid "E208: Error writing to \"%s\""
+msgstr "E208: Error al escribir a \"%s\""
+
+#: fileio.c:6382
+#, c-format
+msgid "E209: Error closing \"%s\""
+msgstr "E209: Error al cerrar \"%s\""
+
+#: fileio.c:6385
+#, c-format
+msgid "E210: Error reading \"%s\""
+msgstr "E210: Error al leer \"%s\""
+
+#: fileio.c:6647
+msgid "E246: FileChangedShell autocommand deleted buffer"
+msgstr "E246: La auto-orden \"FileChangedShell\" ha borrado el búfer"
+
+#: fileio.c:6662
+#, c-format
+msgid "E211: File \"%s\" no longer available"
+msgstr "E211: El archivo \"%s\" ya no está disponible"
+
+#: fileio.c:6677
+#, c-format
+msgid ""
+"W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as "
+"well"
+msgstr ""
+"W12: Advertencia: el archivo \"%s\" ha cambiado y el búfer se modificó "
+"también en Vim"
+
+#: fileio.c:6678
+msgid "See \":help W12\" for more info."
+msgstr "Véase \":help W12\" para más información"
+
+#: fileio.c:6682
+#, c-format
+msgid "W11: Warning: File \"%s\" has changed since editing started"
+msgstr ""
+"W11: Advertencia: el archivo \"%s\" ha cambiado desde que comenzó la edición"
+
+#: fileio.c:6683
+msgid "See \":help W11\" for more info."
+msgstr "Véase \":help W11\" para más información."
+
+#: fileio.c:6687
+#, c-format
+msgid "W16: Warning: Mode of file \"%s\" has changed since editing started"
+msgstr ""
+"W16: Advertencia: el modo del archivo \"%s\" ha cambiado desde que comenzó "
+"la edición"
+
+#: fileio.c:6688
+msgid "See \":help W16\" for more info."
+msgstr "Véase \":help W16\" para más información."
+
+#: fileio.c:6703
+#, c-format
+msgid "W13: Warning: File \"%s\" has been created after editing started"
+msgstr ""
+"W13: Advertencia: la creación del archivo \"%s\" es posterior al inicio de "
+"la edición"
+
+#: fileio.c:6733
+msgid "Warning"
+msgstr "Advertencia"
+
+#: fileio.c:6734
+msgid ""
+"&OK\n"
+"&Load File"
+msgstr ""
+"&OK\n"
+"&Cargar archivo"
+
+#: fileio.c:6857
+#, c-format
+msgid "E462: Could not prepare for reloading \"%s\""
+msgstr "E462: No pude prepararme para recargar \"%s\""
+
+#: fileio.c:6876
+#, c-format
+msgid "E321: Could not reload \"%s\""
+msgstr "E321: No pude recargar \"%s\""
+
+#: fileio.c:7490
+msgid "--Deleted--"
+msgstr "--Suprimido--"
+
+#: fileio.c:7643
+#, c-format
+msgid "auto-removing autocommand: %s <buffer=%d>"
+msgstr "Auto-removiendo autocomando: %s <búfer=%d>"
+
+# the group doesn't exist
+#. the group doesn't exist
+#: fileio.c:7689
+#, c-format
+msgid "E367: No such group: \"%s\""
+msgstr "E367: No existe el grupo: %s"
+
+#: fileio.c:7836
+#, c-format
+msgid "E215: Illegal character after *: %s"
+msgstr "E215: Carácter ilegal después de *: %s"
+
+#: fileio.c:7848
+#, c-format
+msgid "E216: No such event: %s"
+msgstr "E216: No existe tal evento: %s"
+
+#: fileio.c:7850
+#, c-format
+msgid "E216: No such group or event: %s"
+msgstr "E216: No existe tal grupo o evento: %s"
+
+# Highlight title
+#. Highlight title
+#: fileio.c:8058
+msgid ""
+"\n"
+"--- Autocommands ---"
+msgstr ""
+"\n"
+"--- Auto-órdenes ---"
+
+#: fileio.c:8294
+#, c-format
+msgid "E680: <buffer=%d>: invalid buffer number "
+msgstr "E680: número de <búfer=%d> no válido"
+
+#: fileio.c:8391
+msgid "E217: Can't execute autocommands for ALL events"
+msgstr "E217: No se pueden ejecutar las auto-órdenes para TODOS los eventos"
+
+#: fileio.c:8414
+msgid "No matching autocommands"
+msgstr "No coincide ninguna auto-orden"
+
+#: fileio.c:8862
+msgid "E218: autocommand nesting too deep"
+msgstr "E218: La auto-orden se anida en exceso"
+
+#: fileio.c:9215
+#, c-format
+msgid "%s Autocommands for \"%s\""
+msgstr "%s Auto-órdenes para \"%s\""
+
+#: fileio.c:9225
+#, c-format
+msgid "Executing %s"
+msgstr "Ejecutando %s"
+
+# always scroll up, don't overwrite
+#: fileio.c:9294
+#, c-format
+msgid "autocommand %s"
+msgstr "auto-orden %s"
+
+#: fileio.c:9977
+msgid "E219: Missing {."
+msgstr "E219: Falta un {."
+
+#: fileio.c:9979
+msgid "E220: Missing }."
+msgstr "E220: Falta un }."
+
+#: fold.c:68
+msgid "E490: No fold found"
+msgstr "E490: No se encontró ningún pliegue"
+
+#: fold.c:593
+msgid "E350: Cannot create fold with current 'foldmethod'"
+msgstr "E350: No se puede crear el pliegue con el 'foldmethod' actual activo"
+
+#: fold.c:595
+msgid "E351: Cannot delete fold with current 'foldmethod'"
+msgstr "E351: No se puede borrar el pliegue con el 'foldmethod' activo"
+
+#: fold.c:1999
+#, c-format
+msgid "+--%3ld lines folded "
+msgstr "+--%3ld líneas plegadas"
+
+#: getchar.c:252
+msgid "E222: Add to read buffer"
+msgstr "E222: Añadir al búfer de lectura"
+
+#: getchar.c:2407
+msgid "E223: recursive mapping"
+msgstr "E223: Asociación recursiva"
+
+#: getchar.c:3366
+#, c-format
+msgid "E224: global abbreviation already exists for %s"
+msgstr "E224: Ya existe una abreviatura global para %s"
+
+#: getchar.c:3369
+#, c-format
+msgid "E225: global mapping already exists for %s"
+msgstr "E225: Ya existe una asociación global para %s"
+
+#: getchar.c:3501
+#, c-format
+msgid "E226: abbreviation already exists for %s"
+msgstr "E226: Ya existe una abreviatura para %s"
+
+#: getchar.c:3504
+#, c-format
+msgid "E227: mapping already exists for %s"
+msgstr "E227: Ya existe una asociación para %s"
+
+#: getchar.c:3572
+msgid "No abbreviation found"
+msgstr "No se encontró ninguna abreviatura"
+
+#: getchar.c:3574
+msgid "No mapping found"
+msgstr "No se encontró ninguna asociación de teclado"
+
+#: getchar.c:4687
+msgid "E228: makemap: Illegal mode"
+msgstr "E228: \"makemap\": modo ilegal"
+
+#: gui.c:226
+msgid "E229: Cannot start the GUI"
+msgstr "E229: No se pudo iniciar la interfaz gráfica"
+
+#: gui.c:361
+#, c-format
+msgid "E230: Cannot read from \"%s\""
+msgstr "E230: No se pudo leer desde \"%s\""
+
+#: gui.c:487
+msgid "E665: Cannot start GUI, no valid font found"
+msgstr ""
+"E665: No se pudo iniciar la interfaz gráfica (GUI), no se encontró ninguna "
+"tipografía de impresión válida"
+
+#: gui.c:492
+msgid "E231: 'guifontwide' invalid"
+msgstr "E231: El valor de 'guifontwide' no es válido"
+
+#: gui.c:603
+msgid "E599: Value of 'imactivatekey' is invalid"
+msgstr "E599: El valor de 'imactivatekey' no es válido"
+
+#: gui.c:4526
+#, c-format
+msgid "E254: Cannot allocate color %s"
+msgstr "E254: No se pudo asignar el color %s"
+
+#: gui.c:5107
+msgid "No match at cursor, finding next"
+msgstr ""
+"No hay correspondencia en la posición del cursor, buscando la siguiente"
+
+#: gui_at_fs.c:300
+msgid "<cannot open> "
+msgstr "<no se puede abrir> "
+
+#: gui_at_fs.c:1133
+#, c-format
+msgid "E616: vim_SelFile: can't get font %s"
+msgstr ""
+"E616: \"vim_SelFile\": No se puede hallar la tipografía de impresión %s"
+
+#: gui_at_fs.c:2764
+msgid "E614: vim_SelFile: can't return to current directory"
+msgstr "E614: \"vim_SelFile\": no puedo regresar al directorio actual"
+
+#: gui_at_fs.c:2784
+msgid "Pathname:"
+msgstr "Nombre de la ruta:"
+
+#: gui_at_fs.c:2790
+msgid "E615: vim_SelFile: can't get current directory"
+msgstr ""
+"E615: \"vim_SelFile\": No se pudo obtener la ubicación del directorio actual"
+
+#: gui_at_fs.c:2798 gui_xmdlg.c:931
+msgid "OK"
+msgstr "OK"
+
+#: gui_at_fs.c:2798 gui_gtk.c:2831 gui_xmdlg.c:940
+msgid "Cancel"
+msgstr "Cancelar"
+
+#: gui_at_sb.c:490
+msgid "Scrollbar Widget: Could not get geometry of thumb pixmap."
+msgstr ""
+"Scrollbar Widget: No pude obtener la geometría de la miniatura \"pixmap\""
+
+#: gui_athena.c:2160 gui_motif.c:2588
+msgid "Vim dialog"
+msgstr "Diálogo de Vim"
+
+#: gui_beval.c:200 gui_w32.c:4728
+msgid "E232: Cannot create BalloonEval with both message and callback"
+msgstr ""
+"E232: No se pudo crear un \"BalloonEval\" que contenga tanto el mensaje como "
+"la llamada de retorno"
+
+#: gui_gtk.c:1694
+msgid "Vim dialog..."
+msgstr "Diálogo de Vim..."
+
+#: gui_gtk.c:2145 message.c:3654
+msgid ""
+"&Yes\n"
+"&No\n"
+"&Cancel"
+msgstr ""
+"&Si\n"
+"&No\n"
+"&Cancelar"
+
+#: gui_gtk.c:2356
+msgid "Input _Methods"
+msgstr "Métodos de Entrada (\"Input Methods\")"
+
+#: gui_gtk.c:2634 gui_motif.c:3760
+msgid "VIM - Search and Replace..."
+msgstr "VIM - Buscar y reemplazar..."
+
+#: gui_gtk.c:2642 gui_motif.c:3762
+msgid "VIM - Search..."
+msgstr "VIM - Buscar..."
+
+#: gui_gtk.c:2674 gui_motif.c:3871
+msgid "Find what:"
+msgstr "¿Encontrar qué?:"
+
+#: gui_gtk.c:2692 gui_motif.c:3904
+msgid "Replace with:"
+msgstr "Reemplazar con:"
+
+# whole word only button
+#. whole word only button
+#: gui_gtk.c:2724 gui_motif.c:4025
+msgid "Match whole word only"
+msgstr "Encontrar solo palabras completas"
+
+# match case button
+#. match case button
+#: gui_gtk.c:2735 gui_motif.c:4037
+msgid "Match case"
+msgstr "La única coincidencia"
+
+#: gui_gtk.c:2745 gui_motif.c:3976
+msgid "Direction"
+msgstr "Dirección"
+
+# 'Up' and 'Down' buttons
+#. 'Up' and 'Down' buttons
+#: gui_gtk.c:2757 gui_motif.c:3989
+msgid "Up"
+msgstr "Hacia arriba"
+
+#: gui_gtk.c:2761 gui_motif.c:3998
+msgid "Down"
+msgstr "Hacia abajo"
+
+#: gui_gtk.c:2783 gui_gtk.c:2785
+msgid "Find Next"
+msgstr "Encontrar siguiente"
+
+#: gui_gtk.c:2802 gui_gtk.c:2804
+msgid "Replace"
+msgstr "Reemplazar"
+
+#: gui_gtk.c:2815 gui_gtk.c:2817
+msgid "Replace All"
+msgstr "Reemplazar todos"
+
+#: gui_gtk_x11.c:2417
+msgid "Vim: Received \"die\" request from session manager\n"
+msgstr "Vim: Recibí una solicitud \"die\" del administrador de sesiones.\n"
+
+#: gui_gtk_x11.c:3244
+msgid "Close"
+msgstr "Cerrar"
+
+#: gui_gtk_x11.c:3245 gui_w48.c:2375
+msgid "New tab"
+msgstr "Pestaña nueva"
+
+#: gui_gtk_x11.c:3246
+msgid "Open Tab..."
+msgstr "Abrir pestaña..."
+
+#: gui_gtk_x11.c:4025
+msgid "Vim: Main window unexpectedly destroyed\n"
+msgstr "Vim: La ventana principal fue destruida inesperadamente.\n"
+
+#: gui_gtk_x11.c:4746
+msgid "Font Selection"
+msgstr "Selección de tipos de letra"
+
+#: gui_motif.c:2355
+msgid "&Filter"
+msgstr "&Filtro"
+
+#: gui_motif.c:2356 gui_motif.c:3839
+msgid "&Cancel"
+msgstr "&Cancelar"
+
+#: gui_motif.c:2357
+msgid "Directories"
+msgstr "Directorios"
+
+#: gui_motif.c:2358
+msgid "Filter"
+msgstr "Filtro"
+
+#: gui_motif.c:2359
+msgid "&Help"
+msgstr "&Ayuda"
+
+#: gui_motif.c:2360
+msgid "Files"
+msgstr "Archivos"
+
+#: gui_motif.c:2361
+msgid "&OK"
+msgstr "&OK"
+
+#: gui_motif.c:2362
+msgid "Selection"
+msgstr "Selección"
+
+#: gui_motif.c:3791
+msgid "Find &Next"
+msgstr "Encontrar &Siguiente"
+
+#: gui_motif.c:3806
+msgid "&Replace"
+msgstr "&Reemplazar"
+
+#: gui_motif.c:3817
+msgid "Replace &All"
+msgstr "Reemplazar &Todos"
+
+#: gui_motif.c:3828
+msgid "&Undo"
+msgstr "&Deshacer"
+
+#: gui_w32.c:1177
+#, c-format
+msgid "E671: Cannot find window title \"%s\""
+msgstr "E671: No se pudo encontrar el título de la ventana \"%s\""
+
+#: gui_w32.c:1190
+#, c-format
+msgid "E243: Argument not supported: \"-%s\"; Use the OLE version."
+msgstr "E243: Argumento no admitido: \"-%s\"; use la versión OLE."
+
+#: gui_w32.c:1442
+msgid "E672: Unable to open window inside MDI application"
+msgstr "E672: Incapaz de abrir ventana dentro de la aplicación MDI"
+
+#: gui_w48.c:2374
+msgid "Close tab"
+msgstr "Cerrar Ventana"
+
+#: gui_w48.c:2377
+msgid "Open tab..."
+msgstr "Abrir pestaña..."
+
+#: gui_w48.c:2633
+msgid "Find string (use '\\\\' to find a '\\')"
+msgstr "Buscar cadena (use '\\\\' para encontrar un '\\')"
+
+#: gui_w48.c:2669
+msgid "Find & Replace (use '\\\\' to find a '\\')"
+msgstr "Buscar y reemplazar (use '\\\\' para encontrar un '\\')"
+
+#. We fake this: Use a filter that doesn't select anything and a default
+#. * file name that won't be used.
+#: gui_w48.c:3463
+msgid "Not Used"
+msgstr "Sin usar"
+
+#: gui_w48.c:3464
+msgid "Directory\t*.nothing\n"
+msgstr "Directorio\t*.nada\n"
+
+#: gui_x11.c:1546
+msgid "Vim E458: Cannot allocate colormap entry, some colors may be incorrect"
+msgstr ""
+"Vim E458: no se puede asignar una entrada al mapa de colores; algunos "
+"colores tal vez no sean correctos"
+
+#: gui_x11.c:2138
+#, c-format
+msgid "E250: Fonts for the following charsets are missing in fontset %s:"
+msgstr ""
+"E250: Faltan los tipos de letras para los siguientes conjuntos de caracteres "
+"en el conjunto de fuentes %s:"
+
+#: gui_x11.c:2181
+#, c-format
+msgid "E252: Fontset name: %s"
+msgstr "E252: Nombre del conjunto de tipos de letra: %s"
+
+#: gui_x11.c:2182
+#, c-format
+msgid "Font '%s' is not fixed-width"
+msgstr "La tipografía de impresión '%s' no es de ancho fijo"
+
+#: gui_x11.c:2201
+#, c-format
+msgid "E253: Fontset name: %s\n"
+msgstr "E253: Nombre del conjunto de tipografías de impresión: %s\n"
+
+#: gui_x11.c:2202
+#, c-format
+msgid "Font0: %s\n"
+msgstr "Tipo de letra de impresión 0: %s\n"
+
+#: gui_x11.c:2203
+#, c-format
+msgid "Font1: %s\n"
+msgstr "Tipo de letra de impresión 1: %s\n"
+
+#: gui_x11.c:2204
+#, c-format
+msgid "Font%ld width is not twice that of font0\n"
+msgstr ""
+"La anchura del tipo de letra de impresión %ld no es el doble de la "
+"de la tipografía de impresión 0\n"
+
+#: gui_x11.c:2205
+#, c-format
+msgid "Font0 width: %ld\n"
+msgstr "Anchura del tipo de letra de impresión 0: %ld\n"
+
+#: gui_x11.c:2206
+#, c-format
+msgid ""
+"Font1 width: %ld\n"
+"\n"
+msgstr ""
+"Anchura del tipo de letra de impresión 1: %ld\n"
+"\n"
+
+#: gui_xmdlg.c:690 gui_xmdlg.c:809
+msgid "Invalid font specification"
+msgstr "La especificación de tipo de letra no es válida"
+
+#: gui_xmdlg.c:691 gui_xmdlg.c:810
+msgid "&Dismiss"
+msgstr "&Cerrar"
+
+#: gui_xmdlg.c:700
+msgid "no specific match"
+msgstr "no hay una coincidencia especifica"
+
+#: gui_xmdlg.c:909
+msgid "Vim - Font Selector"
+msgstr "Vim - Selector de tipos de letra"
+
+#: gui_xmdlg.c:978
+msgid "Name:"
+msgstr "Nombre:"
+
+#. create toggle button
+#: gui_xmdlg.c:1018
+msgid "Show size in Points"
+msgstr "Mostrar tamaño en puntos"
+
+#: gui_xmdlg.c:1037
+msgid "Encoding:"
+msgstr "Codificando:"
+
+#: gui_xmdlg.c:1083
+msgid "Font:"
+msgstr "Tipo de letra:"
+
+#: gui_xmdlg.c:1116
+msgid "Style:"
+msgstr "Estilo:"
+
+#: gui_xmdlg.c:1148
+msgid "Size:"
+msgstr "Tamaño:"
+
+#: hangulin.c:610
+msgid "E256: Hangul automata ERROR"
+msgstr "E256: ERROR del autómata Hangul"
+
+#: hardcopy.c:210
+msgid "E550: Missing colon"
+msgstr "E550: Falta un símbolo de dos puntos"
+
+#: hardcopy.c:222
+msgid "E551: Illegal component"
+msgstr "E551: Componente ilegal"
+
+#: hardcopy.c:230
+msgid "E552: digit expected"
+msgstr "E552: Se esperaba un dígito"
+
+#: hardcopy.c:501
+#, c-format
+msgid "Page %d"
+msgstr "Página %d"
+
+#: hardcopy.c:658
+msgid "No text to be printed"
+msgstr "No hay texto que imprimir"
+
+#: hardcopy.c:736
+#, c-format
+msgid "Printing page %d (%d%%)"
+msgstr "Imprimiendo la página %d (%d%%)"
+
+#: hardcopy.c:748
+#, c-format
+msgid " Copy %d of %d"
+msgstr "Copia %d de %d"
+
+#: hardcopy.c:806
+#, c-format
+msgid "Printed: %s"
+msgstr "Impreso: %s"
+
+#: hardcopy.c:814
+msgid "Printing aborted"
+msgstr "Impresión interrumpida"
+
+#: hardcopy.c:1469
+msgid "E455: Error writing to PostScript output file"
+msgstr "E455: Error escribiendo al archivo PostScript de salida"
+
+#: hardcopy.c:1931
+#, c-format
+msgid "E624: Can't open file \"%s\""
+msgstr "E624: No se pudo abrir el archivo \"%s\""
+
+#: hardcopy.c:1941 hardcopy.c:2822
+#, c-format
+msgid "E457: Can't read PostScript resource file \"%s\""
+msgstr "E457: No se pudo leer el archivo de recursos de PostScript \"%s\""
+
+#: hardcopy.c:1957
+#, c-format
+msgid "E618: file \"%s\" is not a PostScript resource file"
+msgstr "E618: El archivo \"%s\" no es un archivo de recursos PostScript"
+
+#: hardcopy.c:1975 hardcopy.c:1994 hardcopy.c:2037
+#, c-format
+msgid "E619: file \"%s\" is not a supported PostScript resource file"
+msgstr "E619: El archivo \"%s\" no es un recurso PostScript que pueda usar"
+
+#: hardcopy.c:2056
+#, c-format
+msgid "E621: \"%s\" resource file has wrong version"
+msgstr "E621: La versión del archivo de recursos \"%s\" es incorrecta"
+
+#: hardcopy.c:2543
+msgid "E673: Incompatible multi-byte encoding and character set."
+msgstr "E673: Codificación y set de caracteres multi-byte incompatibles"
+
+#: hardcopy.c:2560
+msgid "E674: printmbcharset cannot be empty with multi-byte encoding."
+msgstr ""
+"E674: \"printmbcharset\" no puede estar vacío en una codificación multi-byte"
+
+#: hardcopy.c:2578
+msgid "E675: No default font specified for multi-byte printing."
+msgstr ""
+"E675: No se ha definido un tipo de letra predeterminado para impresión "
+"multi-byte"
+
+#: hardcopy.c:2771
+msgid "E324: Can't open PostScript output file"
+msgstr "E324: No se pudo abrir el archivo PostScript de salida"
+
+#: hardcopy.c:2808
+#, c-format
+msgid "E456: Can't open file \"%s\""
+msgstr "E456: No se pudo abrir el archivo %s"
+
+#: hardcopy.c:2942
+msgid "E456: Can't find PostScript resource file \"prolog.ps\""
+msgstr "E456: No se encontró el archivo de recursos PostScript \"prolog.ps\""
+
+#: hardcopy.c:2955
+msgid "E456: Can't find PostScript resource file \"cidfont.ps\""
+msgstr "E456: No se encontró el archivo de recursos PostScript \"cidfont.ps\""
+
+#: hardcopy.c:2993 hardcopy.c:3015 hardcopy.c:3044
+#, c-format
+msgid "E456: Can't find PostScript resource file \"%s.ps\""
+msgstr "E456: No se encontró el archivo de recursos PostScript \"%s.ps\""
+
+#: hardcopy.c:3031
+#, c-format
+msgid "E620: Unable to convert to print encoding \"%s\""
+msgstr "E620: No se pudo convertir a la codificación de impresión \"%s\""
+
+#: hardcopy.c:3285
+msgid "Sending to printer..."
+msgstr "Enviando a la impresora..."
+
+#: hardcopy.c:3289
+msgid "E365: Failed to print PostScript file"
+msgstr "E365: Falló la impresión del archivo PostScript"
+
+#: hardcopy.c:3291
+msgid "Print job sent."
+msgstr "Se ha enviado la tarea de impresión."
+
+#: if_cscope.c:77
+msgid "Add a new database"
+msgstr "Añadir una nueva base de datos"
+
+#: if_cscope.c:79
+msgid "Query for a pattern"
+msgstr "Petición de un patrón"
+
+#: if_cscope.c:81
+msgid "Show this message"
+msgstr "Mostrar este mensaje"
+
+#: if_cscope.c:83
+msgid "Kill a connection"
+msgstr "Matar una conexión"
+
+#: if_cscope.c:85
+msgid "Reinit all connections"
+msgstr "Reiniciar todas las conexiones"
+
+#: if_cscope.c:87
+msgid "Show connections"
+msgstr "Mostrar las conexiones"
+
+#: if_cscope.c:95
+#, c-format
+msgid "E560: Usage: cs[cope] %s"
+msgstr "E560: Forma de uso: cs[cope] %s"
+
+#: if_cscope.c:236
+msgid "This cscope command does not support splitting the window.\n"
+msgstr "Esta orden \"cscope\" no admite la división de la ventana.\n"
+
+#: if_cscope.c:287
+msgid "E562: Usage: cstag <ident>"
+msgstr "E562: Forma de uso: cstag <identificador>"
+
+#: if_cscope.c:345
+msgid "E257: cstag: tag not found"
+msgstr "E257: cstag: no se encontró la etiqueta"
+
+#: if_cscope.c:515
+#, c-format
+msgid "E563: stat(%s) error: %d"
+msgstr "E563: Error en stat(%s): %d"
+
+#: if_cscope.c:525
+msgid "E563: stat error"
+msgstr "E563: error en la función \"stat\""
+
+#: if_cscope.c:622
+#, c-format
+msgid "E564: %s is not a directory or a valid cscope database"
+msgstr "E564: \"%s\" no es un directorio ni una base de datos válida de cscope"
+
+#: if_cscope.c:640
+#, c-format
+msgid "Added cscope database %s"
+msgstr "Se ha añadido la base de datos \"cscope\" %s"
+
+#: if_cscope.c:695
+#, c-format
+msgid "E262: error reading cscope connection %ld"
+msgstr "E262: Error al leer la conexión %ld con \"cscope\""
+
+#: if_cscope.c:802
+msgid "E561: unknown cscope search type"
+msgstr "E561: Tipo de búsqueda desconocido para \"cscope\""
+
+#: if_cscope.c:866 if_cscope.c:905
+msgid "E566: Could not create cscope pipes"
+msgstr "E566: Falló la conexión \"pipe\" para comunicarse con \"cscope\""
+
+#: if_cscope.c:882
+msgid "E622: Could not fork for cscope"
+msgstr ""
+"E622: No se pudo crear un nuevo proceso (\"fork\") para usar \"cscope\""
+
+#: if_cscope.c:992 if_cscope.c:1029
+msgid "cs_create_connection exec failed"
+msgstr "Falló la ejecución de \"cs_create_connection\""
+
+#: if_cscope.c:1002 if_cscope.c:1042
+msgid "cs_create_connection: fdopen for to_fp failed"
+msgstr "\"cs_create_connection\": Falló \"fdopen\" para \"to_fp\""
+
+#: if_cscope.c:1004 if_cscope.c:1046
+msgid "cs_create_connection: fdopen for fr_fp failed"
+msgstr "\"cs_create_connection\": Falló \"fdopen\" para \"fr_fp\""
+
+#: if_cscope.c:1030
+msgid "E623: Could not spawn cscope process"
+msgstr "E623: No se pudo crear un nuevo proceso (\"spawn\") de \"cscope\""
+
+#: if_cscope.c:1074
+msgid "E567: no cscope connections"
+msgstr "E567: No hay conexiones con \"cscope\""
+
+#: if_cscope.c:1154
+#, c-format
+msgid "E259: no matches found for cscope query %s of %s"
+msgstr ""
+"E259: No se encontraron coincidencias para la búsqueda \"cscope\" %s de %s"
+
+#: if_cscope.c:1215
+#, c-format
+msgid "E469: invalid cscopequickfix flag %c for %c"
+msgstr "E469: La marca \"cscopequickfix\" %c para %c no es válida"
+
+#: if_cscope.c:1307
+msgid "cscope commands:\n"
+msgstr "órdenes de \"cscope\":\n"
+
+#: if_cscope.c:1316
+#, c-format
+msgid "%-5s: %s%*s (Usage: %s)"
+msgstr "%-5s: %s%*s (Modo de uso: %s)"
+
+#: if_cscope.c:1321
+msgid ""
+"\n"
+" c: Find functions calling this function\n"
+" d: Find functions called by this function\n"
+" e: Find this egrep pattern\n"
+" f: Find this file\n"
+" g: Find this definition\n"
+" i: Find files #including this file\n"
+" s: Find this C symbol\n"
+" t: Find assignments to\n"
+msgstr ""
+"\n"
+" c: Encontrar funciones que invocan esta función\n"
+" d: Encontrar funciones invocados por esta función\n"
+" e: Encontrar este patrón egrep\n"
+" f: Encontrar este archivo\n"
+" g: Encontrar esta definición\n"
+" i: Encontrar archivos #incluyendo este archivo\n"
+" s: Encontrar este símbolo de C\n"
+" t: Encontrar asignaciones a\n"
+
+#: if_cscope.c:1409
+#, c-format
+msgid "E625: cannot open cscope database: %s"
+msgstr "E625: No se pudo abrir la base de datos \"cscope\": %s"
+
+#: if_cscope.c:1427
+msgid "E626: cannot get cscope database information"
+msgstr ""
+"E626: No se pudo obtener información acerca de la base de datos \"cscope\""
+
+#: if_cscope.c:1452
+msgid "E568: duplicate cscope database not added"
+msgstr "E568: Intentó añadir una base de datos de \"cscope\" duplicada"
+
+#: if_cscope.c:1597
+#, c-format
+msgid "E261: cscope connection %s not found"
+msgstr "E261: No se ha encontrado la conexión \"cscope\" %s"
+
+#: if_cscope.c:1631
+#, c-format
+msgid "cscope connection %s closed"
+msgstr "Conexión \"cscope\" %s cerrada"
+
+# should not reach here
+#. should not reach here
+#: if_cscope.c:1771
+msgid "E570: fatal error in cs_manage_matches"
+msgstr "E570: Error fatal en \"cs_manage_matches\""
+
+#: if_cscope.c:2033
+#, c-format
+msgid "Cscope tag: %s"
+msgstr "Etiqueta de \"cscope\": %s"
+
+#: if_cscope.c:2055
+msgid ""
+"\n"
+" # line"
+msgstr ""
+"\n"
+" # línea"
+
+#: if_cscope.c:2057
+msgid "filename / context / line\n"
+msgstr "nombre del archivo / contexto / línea\n"
+
+#: if_cscope.c:2169
+#, c-format
+msgid "E609: Cscope error: %s"
+msgstr "E609: Error de \"cscope\": %s"
+
+#: if_cscope.c:2438
+msgid "All cscope databases reset"
+msgstr "Se han vaciado todas las bases de datos de \"cscope\""
+
+#: if_cscope.c:2505
+msgid "no cscope connections\n"
+msgstr "no hay conexiones \"cscope\"\n"
+
+#: if_cscope.c:2509
+msgid " # pid database name prepend path\n"
+msgstr " nº pid base de datos prefijo ruta\n"
+
+#: if_mzsch.c:1045
+msgid ""
+"E815: Sorry, this command is disabled, the MzScheme libraries could not be "
+"loaded."
+msgstr ""
+"E815: Lo siento, esta orden está desactivada, no se pudo cargar las "
+"bibliotecas de MzScheme"
+
+#: if_mzsch.c:1469 if_python.c:1271 if_tcl.c:1404
+msgid "invalid expression"
+msgstr "expresión no válida"
+
+#: if_mzsch.c:1477 if_python.c:1290 if_tcl.c:1409
+msgid "expressions disabled at compile time"
+msgstr "expresiones desactivadas al compilar"
+
+#: if_mzsch.c:1566
+msgid "hidden option"
+msgstr "opción oculta"
+
+#: if_mzsch.c:1568 if_tcl.c:501
+msgid "unknown option"
+msgstr "opción desconocida"
+
+#: if_mzsch.c:1727
+msgid "window index is out of range"
+msgstr "indice de ventana fuera del rango"
+
+#: if_mzsch.c:1887
+msgid "couldn't open buffer"
+msgstr "No se pudo abrir el búfer"
+
+#: if_mzsch.c:2167 if_mzsch.c:2197 if_mzsch.c:2294 if_mzsch.c:2358
+#: if_mzsch.c:2479 if_mzsch.c:2536 if_python.c:2508 if_python.c:2542
+#: if_python.c:2601 if_python.c:2668 if_python.c:2790 if_python.c:2842
+#: if_tcl.c:684 if_tcl.c:729 if_tcl.c:803 if_tcl.c:875 if_tcl.c:2017
+msgid "cannot save undo information"
+msgstr "No se pudo guardar la información para deshacer"
+
+#: if_mzsch.c:2172 if_mzsch.c:2302 if_mzsch.c:2372 if_python.c:2510
+#: if_python.c:2608 if_python.c:2679
+msgid "cannot delete line"
+msgstr "no puedo suprimir la línea"
+
+#: if_mzsch.c:2203 if_mzsch.c:2387 if_python.c:2547 if_python.c:2695
+#: if_tcl.c:690 if_tcl.c:2039
+msgid "cannot replace line"
+msgstr "no se pudo reemplazar la línea"
+
+#: if_mzsch.c:2402 if_mzsch.c:2485 if_mzsch.c:2546 if_python.c:2713
+#: if_python.c:2792 if_python.c:2850
+msgid "cannot insert line"
+msgstr "no se pudo insertar la línea"
+
+#: if_mzsch.c:2637 if_python.c:2962
+msgid "string cannot contain newlines"
+msgstr "La cadena no puede contener quiebres de línea"
+
+#: if_mzsch.c:2859
+msgid "Vim error: ~a"
+msgstr "Error de Vim: ~a"
+
+#: if_mzsch.c:2892
+msgid "Vim error"
+msgstr "Error de Vim"
+
+#: if_mzsch.c:2958
+msgid "buffer is invalid"
+msgstr "El búfer no es valido"
+
+#: if_mzsch.c:2967
+msgid "window is invalid"
+msgstr "La ventana no es válida"
+
+#: if_mzsch.c:2987
+msgid "linenr out of range"
+msgstr "El número de la línea está fuera del rango"
+
+#: if_mzsch.c:3138 if_mzsch.c:3180
+msgid "not allowed in the Vim sandbox"
+msgstr "No permitido en la \"sandbox\" de vim"
+
+#: if_python.c:517
+msgid ""
+"E263: Sorry, this command is disabled, the Python library could not be "
+"loaded."
+msgstr ""
+"E263: Lo siento, esta orden está desactivada, no se pudo cargar la "
+"biblioteca de Python"
+
+#: if_python.c:583
+msgid "E659: Cannot invoke Python recursively"
+msgstr "E659: No se pudo invocar a Python recursivamente"
+
+#: if_python.c:776
+msgid "can't delete OutputObject attributes"
+msgstr "No se pueden borrar los atributos de \"OutputObject\""
+
+#: if_python.c:783
+msgid "softspace must be an integer"
+msgstr "\"softspace\" debe ser un entero"
+
+#: if_python.c:791
+msgid "invalid attribute"
+msgstr "Atributo no válido"
+
+#: if_python.c:830 if_python.c:844
+msgid "writelines() requires list of strings"
+msgstr "\"writelines()\" requiere una lista de cadenas"
+
+#: if_python.c:970
+msgid "E264: Python: Error initialising I/O objects"
+msgstr "E264: Python: error de iniciación de los objetos de I/O"
+
+#: if_python.c:1303
+msgid "attempt to refer to deleted buffer"
+msgstr "Intento de referirse a un búfer suprimido"
+
+#: if_python.c:1318 if_python.c:1359 if_python.c:1423 if_tcl.c:1216
+msgid "line number out of range"
+msgstr "El número de la línea está fuera del rango"
+
+#: if_python.c:1558
+#, c-format
+msgid "<buffer object (deleted) at %p>"
+msgstr "<objeto de búfer (suprimido) en %p>"
+
+#: if_python.c:1649 if_tcl.c:836
+msgid "invalid mark name"
+msgstr "Nombre de marca no válido"
+
+#: if_python.c:1927
+msgid "no such buffer"
+msgstr "No existe tal búfer"
+
+#: if_python.c:2015
+msgid "attempt to refer to deleted window"
+msgstr "Intento de referirse a una ventana suprimida"
+
+#: if_python.c:2060
+msgid "readonly attribute"
+msgstr "Atributo de solo lectura"
+
+#: if_python.c:2074
+msgid "cursor position outside buffer"
+msgstr "Posición del cursor fuera del búfer"
+
+#: if_python.c:2157
+#, c-format
+msgid "<window object (deleted) at %p>"
+msgstr "<objeto ventana (suprimido) en %p>"
+
+#: if_python.c:2169
+#, c-format
+msgid "<window object (unknown) at %p>"
+msgstr "<objeto ventana (desconocido) en %p>"
+
+#: if_python.c:2172
+#, c-format
+msgid "<window %d>"
+msgstr "<ventana %d>"
+
+#: if_python.c:2246
+msgid "no such window"
+msgstr "No existe tal ventana"
+
+#: if_ruby.c:365
+msgid "E265: $_ must be an instance of String"
+msgstr "E265: $_ debe ser una instancia de \"String\""
+
+#: if_ruby.c:426
+msgid ""
+"E266: Sorry, this command is disabled, the Ruby library could not be loaded."
+msgstr ""
+"E266: Lo siento, esta orden está desactivada, no se pudo cargar "
+"la biblioteca de Ruby"
+
+#: if_ruby.c:455
+msgid "E267: unexpected return"
+msgstr "E267: \"return\" inesperado"
+
+#: if_ruby.c:458
+msgid "E268: unexpected next"
+msgstr "E268: \"next\" inesperado"
+
+#: if_ruby.c:461
+msgid "E269: unexpected break"
+msgstr "E269: \"break\" inesperado"
+
+#: if_ruby.c:464
+msgid "E270: unexpected redo"
+msgstr "E270: \"redo\" inesperado"
+
+#: if_ruby.c:467
+msgid "E271: retry outside of rescue clause"
+msgstr "E271: \"retry\" fuera de una cláusula \"rescue\""
+
+#: if_ruby.c:474
+msgid "E272: unhandled exception"
+msgstr "E272: excepción sin manejar"
+
+#: if_ruby.c:489
+#, c-format
+msgid "E273: unknown longjmp status %d"
+msgstr "E273: El estado %d de \"longjmp\" es desconocido"
+
+#: if_sniff.c:64
+msgid "Toggle implementation/definition"
+msgstr "Intercambiar implementación/definición"
+
+#: if_sniff.c:65
+msgid "Show base class of"
+msgstr "Mostrar la clase base de"
+
+#: if_sniff.c:66
+msgid "Show overridden member function"
+msgstr "Mostrar la función miembro que se ha sobrepasado con el código nuevo"
+
+#: if_sniff.c:67
+msgid "Retrieve from file"
+msgstr "Restaurar del archivo"
+
+#: if_sniff.c:68
+msgid "Retrieve from project"
+msgstr "Restaurar del proyecto"
+
+#: if_sniff.c:70
+msgid "Retrieve from all projects"
+msgstr "Restaurar de todos los proyectos"
+
+#: if_sniff.c:71
+msgid "Retrieve"
+msgstr "Restaurar"
+
+#: if_sniff.c:72
+msgid "Show source of"
+msgstr "Mostrar el origen de "
+
+#: if_sniff.c:73
+msgid "Find symbol"
+msgstr "Buscar símbolo"
+
+#: if_sniff.c:74
+msgid "Browse class"
+msgstr "Navegador de Clases"
+
+#: if_sniff.c:75
+msgid "Show class in hierarchy"
+msgstr "Mostrar la clase en su jerarquía"
+
+#: if_sniff.c:76
+msgid "Show class in restricted hierarchy"
+msgstr "Mostrar la clase en jerarquía restringida"
+
+#: if_sniff.c:77
+msgid "Xref refers to"
+msgstr "Xref se refiere a"
+
+#: if_sniff.c:78
+msgid "Xref referred by"
+msgstr "Xref referida por"
+
+#: if_sniff.c:79
+msgid "Xref has a"
+msgstr "Xref tiene un"
+
+#: if_sniff.c:80
+msgid "Xref used by"
+msgstr "Xref usada por"
+
+#: if_sniff.c:81
+msgid "Show docu of"
+msgstr "Mostrar \"docu\" de"
+
+#: if_sniff.c:82
+msgid "Generate docu for"
+msgstr "Generar \"docu\" de"
+
+#: if_sniff.c:94
+msgid ""
+"Cannot connect to SNiFF+. Check environment (sniffemacs must be found in "
+"$PATH).\n"
+msgstr ""
+"No se pudo conectar a SNiFF+. Verifique el entorno (\"sniffemacs\" debe "
+"estar en \"$PATH\").\n"
+
+#: if_sniff.c:422
+msgid "E274: Sniff: Error during read. Disconnected"
+msgstr "E274: Sniff: Error al leer. Desconectado"
+
+#: if_sniff.c:550
+msgid "SNiFF+ is currently "
+msgstr "SNiFF+ está actualmente "
+
+#: if_sniff.c:552
+msgid "not "
+msgstr "no "
+
+#: if_sniff.c:553
+msgid "connected"
+msgstr "conectado"
+
+#: if_sniff.c:589
+#, c-format
+msgid "E275: Unknown SNiFF+ request: %s"
+msgstr "E275: Petición de SNiFF+ desconocida: %s"
+
+#: if_sniff.c:602
+msgid "E276: Error connecting to SNiFF+"
+msgstr "E276: Error al conectarme a SNiFF+"
+
+#: if_sniff.c:1013
+msgid "E278: SNiFF+ not connected"
+msgstr "E278: SNiFF+ no está conectado"
+
+#: if_sniff.c:1022
+msgid "E279: Not a SNiFF+ buffer"
+msgstr "E279: No es un búfer de SNiFF+"
+
+#: if_sniff.c:1089
+msgid "Sniff: Error during write. Disconnected"
+msgstr "Sniff: error al escribir. Desconectado"
+
+#: if_tcl.c:419
+msgid "invalid buffer number"
+msgstr "Número de búfer no válido"
+
+#: if_tcl.c:465 if_tcl.c:935 if_tcl.c:1115
+msgid "not implemented yet"
+msgstr "Aún no implementado"
+
+# ???
+#. ???
+#: if_tcl.c:774
+msgid "cannot set line(s)"
+msgstr "No se puede(n) definir la/s línea/s"
+
+#: if_tcl.c:845
+msgid "mark not set"
+msgstr "Marca sin definir"
+
+#: if_tcl.c:852 if_tcl.c:1071
+#, c-format
+msgid "row %d column %d"
+msgstr "fila %d columna %d"
+
+#: if_tcl.c:884
+msgid "cannot insert/append line"
+msgstr "No se puede insertar/añadir línea"
+
+#: if_tcl.c:1270
+msgid "unknown flag: "
+msgstr "Indicador desconocido: "
+
+#: if_tcl.c:1340
+msgid "unknown vimOption"
+msgstr "\"vimOption\" desconocida"
+
+#: if_tcl.c:1425
+msgid "keyboard interrupt"
+msgstr "Interrupción desde el teclado"
+
+#: if_tcl.c:1430
+msgid "vim error"
+msgstr "Error de Vim"
+
+#: if_tcl.c:1474
+msgid "cannot create buffer/window command: object is being deleted"
+msgstr "No se pudo crear la orden de búfer/ventana: el objeto se suprimirá"
+
+#: if_tcl.c:1550
+msgid ""
+"cannot register callback command: buffer/window is already being deleted"
+msgstr ""
+"No se pudo registrar el orden \"callback\": El búfer o la ventana ya se "
+"eliminó"
+
+# This should never happen. Famous last word?
+#. This should never happen. Famous last word?
+#: if_tcl.c:1569
+msgid ""
+"E280: TCL FATAL ERROR: reflist corrupt!? Please report this to vim-dev@vim."
+"org"
+msgstr ""
+"E280: ERROR FATAL DE TCL: ¿¡\"reflist\" dañada!? Por favor, informe de "
+"esto a vim-dev@vim.org"
+
+#: if_tcl.c:1570
+msgid "cannot register callback command: buffer/window reference not found"
+msgstr ""
+"No se pudo registrar la orden de retorno de llamada: No se pudo encontrar "
+"la referencia al búfer o la ventana"
+
+#: if_tcl.c:1742
+msgid ""
+"E571: Sorry, this command is disabled: the Tcl library could not be loaded."
+msgstr ""
+"E571: Lo siento, esta orden está desactivada pues no se pudo "
+"cargar la biblioteca de Tcl"
+
+#: if_tcl.c:1904
+msgid ""
+"E281: TCL ERROR: exit code is not int!? Please report this to vim-dev@vim.org"
+msgstr ""
+"E281: ERROR DE TCL: ¿¡el código de salida no es \"int\"!? Por favor "
+"informe a vim-dev@vim.org"
+
+#: if_tcl.c:1909
+#, c-format
+msgid "E572: exit code %d"
+msgstr "E572: código de salida %d"
+
+#: if_tcl.c:2025
+msgid "cannot get line"
+msgstr "No puedo obtener la línea"
+
+#: if_xcmdsrv.c:233
+msgid "Unable to register a command server name"
+msgstr "Incapaz de registrar un nombre de servidor de órdenes"
+
+#: if_xcmdsrv.c:492
+msgid "E248: Failed to send command to the destination program"
+msgstr "E248: No pude enviar la orden al programa de destino"
+
+#: if_xcmdsrv.c:765
+#, c-format
+msgid "E573: Invalid server id used: %s"
+msgstr "E573: El ID de usuario no es válido en el servidor: %s"
+
+#: if_xcmdsrv.c:1146
+msgid "E251: VIM instance registry property is badly formed. Deleted!"
+msgstr "E251: La propiedad de registro de VIM es incorrecta. ¡Eliminada!"
+
+#: main.c:138
+msgid "Unknown option argument"
+msgstr "Opción de argumento desconocida"
+
+#: main.c:140
+msgid "Too many edit arguments"
+msgstr "Demasiados argumentos de edición"
+
+#: main.c:142
+msgid "Argument missing after"
+msgstr "Falta el argumento después de"
+
+#: main.c:144
+msgid "Garbage after option argument"
+msgstr "Basura después de la opción"
+
+#: main.c:146
+msgid "Too many \"+command\", \"-c command\" or \"--cmd command\" arguments"
+msgstr ""
+"Demasiados argumentos tales como: \"+orden\", \"-c orden\" "
+"o \"--cmd orden\""
+
+#: main.c:148
+msgid "Invalid argument for"
+msgstr "Argumento no válido para"
+
+#: main.c:514
+#, c-format
+msgid "%d files to edit\n"
+msgstr "%d archivos que editar\n"
+
+#: main.c:1510
+msgid "This Vim was not compiled with the diff feature."
+msgstr "Este Vim no se ha compilado con la opción \"diff\""
+
+#: main.c:1612
+msgid "'-nb' cannot be used: not enabled at compile time\n"
+msgstr "'-nb' no se puede usar: no se ha activado al compilar\n"
+
+#: main.c:2135
+msgid "Attempt to open script file again: \""
+msgstr "Intento de abrir de nuevo el archivo de órdenes: \""
+
+#: main.c:2144
+msgid "Cannot open for reading: \""
+msgstr "No se pudo abrir para leer: \""
+
+#: main.c:2198
+msgid "Cannot open for script output: \""
+msgstr "No se pudo abrir para escribir la salida del archivo de órdenes: \""
+
+#: main.c:2364
+msgid "Vim: Error: Failure to start gvim from NetBeans\n"
+msgstr "Vim: Error: Imposible iniciar gvim para NetBeans\n"
+
+#: main.c:2369
+msgid "Vim: Warning: Output is not to a terminal\n"
+msgstr "Vim: Advertencia: la salida no es un terminal\n"
+
+#: main.c:2371
+msgid "Vim: Warning: Input is not from a terminal\n"
+msgstr "Vim: Advertencia: la entrada no es desde un terminal\n"
+
+# just in case..
+#. just in case..
+#: main.c:2688
+msgid "pre-vimrc command line"
+msgstr "Línea de órdenes previa a \"vimrc\""
+
+#: main.c:2785
+#, c-format
+msgid "E282: Cannot read from \"%s\""
+msgstr "E282: No se pudo leer desde \"%s\""
+
+#: main.c:3002
+msgid ""
+"\n"
+"More info with: \"vim -h\"\n"
+msgstr ""
+"\n"
+"Más información con: \"vim -h\"\n"
+
+#: main.c:3035
+msgid "[file ..] edit specified file(s)"
+msgstr "[archivo ..] Editar el/los archivos/s especificado/s"
+
+#: main.c:3036
+msgid "- read text from stdin"
+msgstr "- Leer texto de la entrada estándar"
+
+#: main.c:3037
+msgid "-t tag edit file where tag is defined"
+msgstr "-t etiqueta Editar el archivo donde está definida la etiqueta"
+
+#: main.c:3039
+msgid "-q [errorfile] edit file with first error"
+msgstr "-q [fich. err.] Editar el archivo con el primer error"
+
+#: main.c:3048
+msgid ""
+"\n"
+"\n"
+"Usage:"
+msgstr ""
+"\n"
+"\n"
+"Uso:"
+
+#: main.c:3051
+msgid " vim [arguments] "
+msgstr " vim [argumentos]"
+
+#: main.c:3055
+msgid ""
+"\n"
+" or:"
+msgstr ""
+"\n"
+" o:"
+
+#: main.c:3058
+msgid ""
+"\n"
+"Where case is ignored prepend / to make flag upper case"
+msgstr ""
+"\n"
+"Cuando mayúscula y minúscula son ignoradas añada \"/\" para "
+"cambiar la marca (\"flag\") a mayúscula"
+
+#: main.c:3061
+msgid ""
+"\n"
+"\n"
+"Arguments:\n"
+msgstr ""
+"\n"
+"\n"
+"Argumentos:\n"
+
+#: main.c:3062
+msgid "--\t\t\tOnly file names after this"
+msgstr "--\t\t\tSolo nombres de archivos a partir de aquí"
+
+#: main.c:3064
+msgid "--literal\t\tDon't expand wildcards"
+msgstr "--literal\t\tNo expandir comodines"
+
+#: main.c:3067
+msgid "-register\t\tRegister this gvim for OLE"
+msgstr "-register\t\tRegistrar este \"gvim\" para \"OLE\""
+
+#: main.c:3068
+msgid "-unregister\t\tUnregister gvim for OLE"
+msgstr "-unregister\t\tSuprimir el registro de \"gvim\" para \"OLE\""
+
+#: main.c:3071
+msgid "-g\t\t\tRun using GUI (like \"gvim\")"
+msgstr "-g\t\t\tEjecutar usando el GUI (como \"gvim\")"
+
+#: main.c:3072
+msgid "-f or --nofork\tForeground: Don't fork when starting GUI"
+msgstr ""
+"-f o --nofork\tPrimer plano: No separarse (\"fork\") cuando se "
+"inicia la interfaz gráfica (GUI)"
+
+#: main.c:3074
+msgid "-v\t\t\tVi mode (like \"vi\")"
+msgstr "-v\t\t\tModo vi"
+
+#: main.c:3075
+msgid "-e\t\t\tEx mode (like \"ex\")"
+msgstr "-e\t\t\tModo ex"
+
+#: main.c:3076
+msgid "-s\t\t\tSilent (batch) mode (only for \"ex\")"
+msgstr "-s\t\t\tModo silencioso de ejecución por lotes (\"ex\")"
+
+#: main.c:3078
+msgid "-d\t\t\tDiff mode (like \"vimdiff\")"
+msgstr "-d\t\t\tModo de diferencias (como \"vimdiff\")"
+
+#: main.c:3080
+msgid "-y\t\t\tEasy mode (like \"evim\", modeless)"
+msgstr "-y\t\t\tModo fácil (como \"evim\", sin modo)"
+
+#: main.c:3081
+msgid "-R\t\t\tReadonly mode (like \"view\")"
+msgstr "-R\t\t\tModo de solo lectura (como \"view\")"
+
+#: main.c:3082
+msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
+msgstr "-Z\t\t\tModo restringido (como \"rvim\")"
+
+#: main.c:3083
+msgid "-m\t\t\tModifications (writing files) not allowed"
+msgstr "-m\t\t\tModificación de archivos desactivada"
+
+#: main.c:3084
+msgid "-M\t\t\tModifications in text not allowed"
+msgstr "-M\t\t\tModificación de texto desactivada"
+
+#: main.c:3085
+msgid "-b\t\t\tBinary mode"
+msgstr "-b\t\t\tModo binario"
+
+#: main.c:3087
+msgid "-l\t\t\tLisp mode"
+msgstr "-l\t\t\tModo LISP"
+
+#: main.c:3089
+msgid "-C\t\t\tCompatible with Vi: 'compatible'"
+msgstr "-C\t\t\tCompatible con vi: \"compatible\""
+
+#: main.c:3090
+msgid "-N\t\t\tNot fully Vi compatible: 'nocompatible'"
+msgstr "-N\t\t\tParcialmente compatible con vi: \"nocompatible\""
+
+#: main.c:3091
+msgid "-V[N][fname]\t\tBe verbose [level N] [log messages to fname]"
+msgstr ""
+"-V[N][nombre_archivo]\t\tCon verbosidad [nivel N] [guardar mensajes en "
+"nombre_archivo]"
+
+#: main.c:3093
+msgid "-D\t\t\tDebugging mode"
+msgstr "-D\t\t\tModo de depuración"
+
+#: main.c:3095
+msgid "-n\t\t\tNo swap file, use memory only"
+msgstr "-n\t\t\tSin archivo de intercambio, solo usa RAM"
+
+#: main.c:3096
+msgid "-r\t\t\tList swap files and exit"
+msgstr "-r\t\t\tDar una lista de los archivo de intercambio y salir"
+
+#: main.c:3097
+msgid "-r (with file name)\tRecover crashed session"
+msgstr "-r \"archivo\"\tRecuperar sesión fallida"
+
+#: main.c:3098
+msgid "-L\t\t\tSame as -r"
+msgstr "-L\t\t\tIgual que \"-r\""
+
+#: main.c:3100
+msgid "-f\t\t\tDon't use newcli to open window"
+msgstr "-f\t\t\tNo usar \"newcli\" para abrir ventanas"
+
+#: main.c:3101
+msgid "-dev <device>\t\tUse <device> for I/O"
+msgstr "-dev <dispositivo>\t\tUsar <dispositivo> para I/O"
+
+#: main.c:3104
+msgid "-A\t\t\tStart in Arabic mode"
+msgstr "-A\t\t\tIniciar en modo árabe"
+
+#: main.c:3107
+msgid "-H\t\t\tStart in Hebrew mode"
+msgstr "-H\t\t\tIniciar en modo hebreo"
+
+#: main.c:3110
+msgid "-F\t\t\tStart in Farsi mode"
+msgstr "-F\t\t\tIniciar en modo persa (farsi)"
+
+#: main.c:3112
+msgid "-T <terminal>\tSet terminal type to <terminal>"
+msgstr "-T <terminal>\tEstablecer el tipo de salida visual a <terminal>"
+
+#: main.c:3113
+msgid "-u <vimrc>\t\tUse <vimrc> instead of any .vimrc"
+msgstr "-u <vimrc>\t\tUsar <vimrc> en lugar de cualquier \".vimrc\""
+
+#: main.c:3115
+msgid "-U <gvimrc>\t\tUse <gvimrc> instead of any .gvimrc"
+msgstr "-U <gvimrc>\t\tUsar <gvimrc> en lugar de otro \".gvimrc\""
+
+#: main.c:3117
+msgid "--noplugin\t\tDon't load plugin scripts"
+msgstr "--noplugin\t\tNo cargar los módulos de expansión"
+
+#: main.c:3119
+msgid "-p[N]\t\tOpen N tab pages (default: one for each file)"
+msgstr "-p[N]\t\tAbrir N ventanas (valor predeterminado: una por archivo)"
+
+#: main.c:3120
+msgid "-o[N]\t\tOpen N windows (default: one for each file)"
+msgstr "-o[N]\t\tAbrir N ventanas (valor predeterminado: una por archivo)"
+
+#: main.c:3121
+msgid "-O[N]\t\tLike -o but split vertically"
+msgstr "-O[N]\t\tComo \"-o\" pero divide las ventanas verticalmente"
+
+#: main.c:3123
+msgid "+\t\t\tStart at end of file"
+msgstr "+\t\t\tComenzar al final del archivo"
+
+#: main.c:3124
+msgid "+<lnum>\t\tStart at line <lnum>"
+msgstr "+<número_de_línea>\tComienza en la línea <número_de_línea>"
+
+#: main.c:3125
+msgid "--cmd <command>\tExecute <command> before loading any vimrc file"
+msgstr "--cmd <orden>\tEjecutar la <orden> antes de cargar algún archivo vimrc"
+
+#: main.c:3126
+msgid "-c <command>\t\tExecute <command> after loading the first file"
+msgstr "-c <orden>\t\tEjecutar <orden> después de cargar el primer archivo"
+
+#: main.c:3127
+msgid "-S <session>\t\tSource file <session> after loading the first file"
+msgstr ""
+"-S <sesión>\t\tEjecutar las órdenes del archivo <sesión> después "
+"de cargar el primer archivo"
+
+#: main.c:3128
+msgid "-s <scriptin>\tRead Normal mode commands from file <scriptin>"
+msgstr ""
+"-s <scriptin>\tLeer las órdenes en modo Normal del archivo "
+"\"módulo de expansión\" de entrada>"
+
+#: main.c:3129
+msgid "-w <scriptout>\tAppend all typed commands to file <scriptout>"
+msgstr ""
+"-w <scriptout>\tAñadir todas las órdenes escritas al archivo "
+"\"módulo de expansión\" de salida"
+
+#: main.c:3130
+msgid "-W <scriptout>\tWrite all typed commands to file <scriptout>"
+msgstr ""
+"-W <scriptout>\tGrabar todas las órdenes escritas al archivo "
+"\"módulo de expansión\" de salida"
+
+#: main.c:3132
+msgid "-x\t\t\tEdit encrypted files"
+msgstr "-x\t\t\tEditar archivos cifrados"
+
+#: main.c:3136
+msgid "-display <display>\tConnect vim to this particular X-server"
+msgstr "-display <pantalla>\tConectar vim a este servidor X en particular"
+
+#: main.c:3138
+msgid "-X\t\t\tDo not connect to X server"
+msgstr "-X\t\t\tEvitar la conexión al servidor X"
+
+#: main.c:3141
+msgid "--remote <files>\tEdit <files> in a Vim server if possible"
+msgstr ""
+"--remote <archivos>\tEditar <archivos> en un servidor Vim si es posible"
+
+#: main.c:3142
+msgid "--remote-silent <files> Same, don't complain if there is no server"
+msgstr ""
+"--remote-silent \"archivos\"\tLo mismo pero no se queja si no existe un "
+"servidor disponible"
+
+#: main.c:3143
+msgid ""
+"--remote-wait <files> As --remote but wait for files to have been edited"
+msgstr ""
+"--remote-wait \"archivos\"\tComo --remote pero espera a que los archivos "
+"terminen de editarse"
+
+#: main.c:3144
+msgid ""
+"--remote-wait-silent <files> Same, don't complain if there is no server"
+msgstr ""
+"--remote-wait-silent \"archivos\"\tLo mismo pero no se queja si no hay un "
+"servidor disponible"
+
+#: main.c:3146
+msgid ""
+"--remote-tab[-wait][-silent] <files> As --remote but use tab page per file"
+msgstr ""
+"--remote-tab[-wait][-silent] <archivos> Como \"--remote\" pero usa una "
+"pestaña por página"
+
+#: main.c:3148
+msgid "--remote-send <keys>\tSend <keys> to a Vim server and exit"
+msgstr "--remote-send <teclas>\tEnvíar <teclas> a un servidor Vim y cerrar"
+
+#: main.c:3149
+msgid "--remote-expr <expr>\tEvaluate <expr> in a Vim server and print result"
+msgstr ""
+"--remote-expr <expr>\tEvaluar <expr> en un servidor Vim e imprimir el "
+"resultado"
+
+#: main.c:3150
+msgid "--serverlist\t\tList available Vim server names and exit"
+msgstr ""
+"--serverlist\t\tEmitir una lista de los servidores Vim disponibles y cerrar"
+
+#: main.c:3151
+msgid "--servername <name>\tSend to/become the Vim server <name>"
+msgstr ""
+"--servername \"nombre\"\tEnvíar a/se convierte en el servidor Vim con <nombre>"
+
+#: main.c:3154
+msgid "--startuptime <file>\tWrite startup timing messages to <file>"
+msgstr "-- startuptime <archivo>\tGuardar los mensajes de tiempo de inicio "
+"a <archivo>."
+
+#: main.c:3157
+msgid "-i <viminfo>\t\tUse <viminfo> instead of .viminfo"
+msgstr "-i <viminfo>\t\tUsar <viminfo> en lugar de \".viminfo\""
+
+#: main.c:3159
+msgid "-h or --help\tPrint Help (this message) and exit"
+msgstr "-h or --help\tImpresión de la ayuda (este mensaje) y cerrar"
+
+#: main.c:3160
+msgid "--version\t\tPrint version information and exit"
+msgstr "--version\t\tImpresión de la información de versión y cerrar"
+
+#: main.c:3164
+msgid ""
+"\n"
+"Arguments recognised by gvim (Motif version):\n"
+msgstr ""
+"\n"
+"Argumentos reconocidos por gvim (versión Motif):\n"
+
+#: main.c:3168
+msgid ""
+"\n"
+"Arguments recognised by gvim (neXtaw version):\n"
+msgstr ""
+"\n"
+"Argumentos reconocidos por gvim (versión neXtaw):\n"
+
+#: main.c:3170
+msgid ""
+"\n"
+"Arguments recognised by gvim (Athena version):\n"
+msgstr ""
+"\n"
+"Argumentos reconocidos por gvim (versión Athena):\n"
+
+#: main.c:3174
+msgid "-display <display>\tRun vim on <display>"
+msgstr "-display <pantalla>\tEjecuta vim en <pantalla>"
+
+#: main.c:3175
+msgid "-iconic\t\tStart vim iconified"
+msgstr "-iconic\t\tArranca vim \"iconizado\""
+
+#: main.c:3177
+msgid "-name <name>\t\tUse resource as if vim was <name>"
+msgstr "-name <nombre>\t\tUsa un recurso como si vim fuese <nombre>"
+
+#: main.c:3178
+msgid "\t\t\t (Unimplemented)\n"
+msgstr "\t\t\t (Sin implementar)\n"
+
+#: main.c:3180
+msgid "-background <color>\tUse <color> for the background (also: -bg)"
+msgstr "-background <color>\tUsa <color> para el fondo (también: -bg)"
+
+#: main.c:3181
+msgid "-foreground <color>\tUse <color> for normal text (also: -fg)"
+msgstr "-foreground <color>\tUsa <color> para el texto normal (también: -fg)"
+
+#: main.c:3182 main.c:3202
+msgid "-font <font>\t\tUse <font> for normal text (also: -fn)"
+msgstr ""
+"-font <tipo>\t\tUse <tipo de letra de impresión> para el texto normal "
+"(también: -fn)"
+
+#: main.c:3183
+msgid "-boldfont <font>\tUse <font> for bold text"
+msgstr ""
+"-boldfont <tipo>\tUsa <tipo de letra de impresión> para texto en "
+"negrita"
+
+#: main.c:3184
+msgid "-italicfont <font>\tUse <font> for italic text"
+msgstr ""
+"-italicfont <tipo>\tUse <tipo de letra de impresión> para texto "
+"en cursiva"
+
+#: main.c:3185 main.c:3203
+msgid "-geometry <geom>\tUse <geom> for initial geometry (also: -geom)"
+msgstr ""
+"-geometry <geom>\tUse <geom> para la geometría inicial (también: -geom)"
+
+#: main.c:3186
+msgid "-borderwidth <width>\tUse a border width of <width> (also: -bw)"
+msgstr "-borderwidth <ancho>\tUsa un ancho de borde de <ancho> (también: -bw)"
+
+#: main.c:3187
+msgid "-scrollbarwidth <width> Use a scrollbar width of <width> (also: -sw)"
+msgstr ""
+"-scrollbarwidth <ancho>\tUsa una barra de desplazamiento de ancho <ancho> "
+"(también: -sw)"
+
+#: main.c:3189
+msgid "-menuheight <height>\tUse a menu bar height of <height> (also: -mh)"
+msgstr ""
+"-menuheight <alt>\tUsa una barra de menú de altura <alt> (también: -mh)"
+
+#: main.c:3191 main.c:3204
+msgid "-reverse\t\tUse reverse video (also: -rv)"
+msgstr "-reverse\t\tUsar vídeo inverso (también: -rv)"
+
+#: main.c:3192
+msgid "+reverse\t\tDon't use reverse video (also: +rv)"
+msgstr "+reverse\t\tNo usar vídeo inverso (también: +rv)"
+
+#: main.c:3193
+msgid "-xrm <resource>\tSet the specified resource"
+msgstr "-xrm <recurso>\tEstablece el recurso especificado"
+
+#: main.c:3196
+msgid ""
+"\n"
+"Arguments recognised by gvim (RISC OS version):\n"
+msgstr ""
+"\n"
+"Argumentos reconocidos por gvim (versión para RISC OS):\n"
+
+#: main.c:3197
+msgid "--columns <number>\tInitial width of window in columns"
+msgstr "--columns <número>\tAnchura inicial de la ventana, en columnas"
+
+#: main.c:3198
+msgid "--rows <number>\tInitial height of window in rows"
+msgstr "--rows <número>\tAltura inicial de la ventana, en filas"
+
+#: main.c:3201
+msgid ""
+"\n"
+"Arguments recognised by gvim (GTK+ version):\n"
+msgstr ""
+"\n"
+"Argumentos reconocidos por gvim (versión GTK+):\n"
+
+#: main.c:3205
+msgid "-display <display>\tRun vim on <display> (also: --display)"
+msgstr "-display <pantalla>\tEjecuta vim en <pantalla> (también: --display)"
+
+#: main.c:3207
+msgid "--role <role>\tSet a unique role to identify the main window"
+msgstr ""
+"--role <role>\tDefine un rol único para identificar la ventana principal"
+
+#: main.c:3209
+msgid "--socketid <xid>\tOpen Vim inside another GTK widget"
+msgstr "--socketid <xid>\tAbre a Vim dentro de otro \"widget\" GTK"
+
+#: main.c:3212
+msgid "-P <parent title>\tOpen Vim inside parent application"
+msgstr "-P <título ventana padre>\tAbrir a Vim dentro de la aplicación padre"
+
+#: main.c:3213
+msgid "--windowid <HWND>\tOpen Vim inside another win32 widget"
+msgstr "--windowid <HWND>\tAbrir Vim dentro de otro objeto de win32"
+
+#: main.c:3557
+msgid "No display"
+msgstr "No hay una ventana"
+
+# Failed to send, abort.
+#. Failed to send, abort.
+#: main.c:3572
+msgid ": Send failed.\n"
+msgstr ": Falló el envío.\n"
+
+# Let vim start normally.
+#. Let vim start normally.
+#: main.c:3578
+msgid ": Send failed. Trying to execute locally\n"
+msgstr ""
+": Falló el inicio de sesión remota (\"send\"). Intentado una "
+"ejecución local\n"
+
+#: main.c:3616 main.c:3637
+#, c-format
+msgid "%d of %d edited"
+msgstr "%d de %d editados"
+
+#: main.c:3659
+msgid "No display: Send expression failed.\n"
+msgstr "No hay una ventana en el destino: El envío de la expresión falló.\n"
+
+#: main.c:3671
+msgid ": Send expression failed.\n"
+msgstr ": Falló el envío de la expresión.\n"
+
+#: mark.c:761
+msgid "No marks set"
+msgstr "No se han fijado marcas"
+
+#: mark.c:763
+#, c-format
+msgid "E283: No marks matching \"%s\""
+msgstr "E283: No hay marcas que coincidan con %s"
+
+# Highlight title
+#. Highlight title
+#: mark.c:774
+msgid ""
+"\n"
+"mark line col file/text"
+msgstr ""
+"\n"
+"marca línea col archivo/texto"
+
+# Highlight title
+#. Highlight title
+#: mark.c:896
+msgid ""
+"\n"
+" jump line col file/text"
+msgstr ""
+"\n"
+" salto línea col archivo/texto"
+
+# Highlight title
+#. Highlight title
+#: mark.c:943
+msgid ""
+"\n"
+"change line col text"
+msgstr ""
+"\n"
+"cambio línea col archivo/texto"
+
+#: mark.c:1437
+#, c-format
+msgid ""
+"\n"
+"# File marks:\n"
+msgstr ""
+"\n"
+"# Marcas en el archivo:\n"
+
+# Write the jumplist with -'
+#. Write the jumplist with -'
+#: mark.c:1472
+#, c-format
+msgid ""
+"\n"
+"# Jumplist (newest first):\n"
+msgstr ""
+"\n"
+"# Lista de saltos (el más reciente va primero):\n"
+
+#: mark.c:1573
+#, c-format
+msgid ""
+"\n"
+"# History of marks within files (newest to oldest):\n"
+msgstr ""
+"\n"
+"# Historia de las marcas en los archivos (de la más reciente a la más "
+"antigua):\n"
+
+#: mark.c:1677
+msgid "Missing '>'"
+msgstr "Falta \">\""
+
+#: mbyte.c:532
+msgid "E543: Not a valid codepage"
+msgstr "E543: No es una página de código válida"
+
+#: mbyte.c:4852
+msgid "E284: Cannot set IC values"
+msgstr "E284: No se pudo fijar los valores IC"
+
+#: mbyte.c:5004
+msgid "E285: Failed to create input context"
+msgstr "E285: Falló la creación del contexto de entrada"
+
+#: mbyte.c:5162
+msgid "E286: Failed to open input method"
+msgstr "E286: Falló la apertura del método de entrada"
+
+#: mbyte.c:5175
+msgid "E287: Warning: Could not set destroy callback to IM"
+msgstr ""
+"E287: Advertencia: No pude crear una llamada de retorno "
+"de destrucción al IM"
+
+#: mbyte.c:5181
+msgid "E288: input method doesn't support any style"
+msgstr "E288: el método de entrada no admite ningún estilo"
+
+#: mbyte.c:5240
+msgid "E289: input method doesn't support my preedit type"
+msgstr "E289: El método de entrada no soporta mi tipo de pre-edición"
+
+#: mbyte.c:5316
+msgid "E290: over-the-spot style requires fontset"
+msgstr "E290: El estilo \"sobre el punto\" requiere del uso de un \"fontset\""
+
+#: mbyte.c:5352
+msgid "E291: Your GTK+ is older than 1.2.3. Status area disabled"
+msgstr ""
+"E291: Su versión de GTK+ es anterior a 1.2.3. Ãrea de estado "
+"desactivada"
+
+#: mbyte.c:5663
+msgid "E292: Input Method Server is not running"
+msgstr "E292: El servidor de método de entrada (IME) no está funcionando"
+
+#: memfile.c:501
+msgid "E293: block was not locked"
+msgstr "E293: El bloque no estaba asegurado"
+
+#: memfile.c:1044
+msgid "E294: Seek error in swap file read"
+msgstr "E294: Error de búsqueda al leer el archivo de intercambio"
+
+#: memfile.c:1049
+msgid "E295: Read error in swap file"
+msgstr "E295: Error de lectura en el archivo de intercambio"
+
+#: memfile.c:1101
+msgid "E296: Seek error in swap file write"
+msgstr "E296: Error de búsqueda al escribir en el archivo de intercambio"
+
+#: memfile.c:1119
+msgid "E297: Write error in swap file"
+msgstr "E297: Error de escritura en el archivo de intercambio"
+
+#: memfile.c:1316
+msgid "E300: Swap file already exists (symlink attack?)"
+msgstr ""
+"E300: Ya existe un archivo de intercambio (¿ataque de enlace simbólico?)"
+
+#: memline.c:312
+msgid "E298: Didn't get block nr 0?"
+msgstr "E298: ¿No se obtuvo el bloque Nº 0?"
+
+#: memline.c:359
+msgid "E298: Didn't get block nr 1?"
+msgstr "E298: ¿No se obtuvo el bloque Nº 1?"
+
+#: memline.c:377
+msgid "E298: Didn't get block nr 2?"
+msgstr "E298: ¿No se obtuvo el bloque Nº 2?"
+
+# could not (re)open the swap file, what can we do????
+#. could not (re)open the swap file, what can we do????
+#: memline.c:490
+msgid "E301: Oops, lost the swap file!!!"
+msgstr "E301: ¡¡¡Perdí el archivo de intercambio!!!"
+
+#: memline.c:502
+msgid "E302: Could not rename swap file"
+msgstr "E302: No pude cambiar el nombre del archivo de intercambio"
+
+#: memline.c:592
+#, c-format
+msgid "E303: Unable to open swap file for \"%s\", recovery impossible"
+msgstr ""
+"E303: Incapaz de abrir el archivo de intercambio para %s, "
+"recuperación imposible"
+
+#: memline.c:703
+msgid "E304: ml_upd_block0(): Didn't get block 0??"
+msgstr "E304: \"ml_upd_block0()\": ¿No se obtuvo el bloque 0?"
+
+#: memline.c:904
+#, c-format
+msgid "E305: No swap file found for %s"
+msgstr "E305: No se encontró el archivo de intercambio para %s"
+
+#: memline.c:914
+msgid "Enter number of swap file to use (0 to quit): "
+msgstr ""
+"Introduzca el número del archivo de intercambio a usar (0 para salir): "
+
+#: memline.c:959
+#, c-format
+msgid "E306: Cannot open %s"
+msgstr "E306: No se pudo abrir %s"
+
+#: memline.c:981
+msgid "Unable to read block 0 from "
+msgstr "Incapaz de leer el bloque 0 de "
+
+#: memline.c:984
+msgid ""
+"\n"
+"Maybe no changes were made or Vim did not update the swap file."
+msgstr ""
+"\n"
+"Tal vez no hay cambios o Vim no actualizó el archivo de intercambio."
+
+#: memline.c:994 memline.c:1011
+msgid " cannot be used with this version of Vim.\n"
+msgstr " no puede usarse con esta versión de Vim.\n"
+
+#: memline.c:996
+msgid "Use Vim version 3.0.\n"
+msgstr "Use la versión 3.0 de Vim.\n"
+
+#: memline.c:1002
+#, c-format
+msgid "E307: %s does not look like a Vim swap file"
+msgstr "E307: %s no parece un archivo de intercambio de Vim"
+
+#: memline.c:1015
+msgid " cannot be used on this computer.\n"
+msgstr "no puede usarse en este ordenador.\n"
+
+#: memline.c:1017
+msgid "The file was created on "
+msgstr "El archivo se creó el "
+
+#: memline.c:1021
+msgid ""
+",\n"
+"or the file has been damaged."
+msgstr ""
+",\n"
+"o el archivo se ha dañado"
+
+#: memline.c:1039
+msgid " has been damaged (page size is smaller than minimum value).\n"
+msgstr " se ha dañado (el tamaño de la página es menor al valor minimo).\n"
+
+#: memline.c:1071
+#, c-format
+msgid "Using swap file \"%s\""
+msgstr "Usando el archivo de intercambio \"%s\""
+
+#: memline.c:1077
+#, c-format
+msgid "Original file \"%s\""
+msgstr "Archivo original %s"
+
+#: memline.c:1090
+msgid "E308: Warning: Original file may have been changed"
+msgstr "E308: Advertencia: el archivo original puede haber cambiado"
+
+#: memline.c:1164
+#, c-format
+msgid "E309: Unable to read block 1 from %s"
+msgstr "E309: Incapaz de leer el bloque 1 de %s"
+
+#: memline.c:1168
+msgid "???MANY LINES MISSING"
+msgstr "???FALTAN MUCHAS LÃNEAS"
+
+#: memline.c:1184
+msgid "???LINE COUNT WRONG"
+msgstr "???RECUENTO DE LÃNEAS EQUIVOCADO"
+
+#: memline.c:1191
+msgid "???EMPTY BLOCK"
+msgstr "???BLOQUE VACÃO"
+
+#: memline.c:1217
+msgid "???LINES MISSING"
+msgstr "???FALTAN LÃNEAS"
+
+#: memline.c:1249
+#, c-format
+msgid "E310: Block 1 ID wrong (%s not a .swp file?)"
+msgstr "E310: El ID del bloque 1 es incorrecto (¿No es %s un archivo .swp?)"
+
+#: memline.c:1254
+msgid "???BLOCK MISSING"
+msgstr "???FALTA UN BLOQUE"
+
+#: memline.c:1270
+msgid "??? from here until ???END lines may be messed up"
+msgstr "??? desde aquí hasta ???FIN las líneas pueden estar desordenadas"
+
+#: memline.c:1286
+msgid "??? from here until ???END lines may have been inserted/deleted"
+msgstr ""
+"??? desde aquí hasta ???FIN las líneas pueden haber sido "
+"insertadas/borradas"
+
+#: memline.c:1306
+msgid "???END"
+msgstr "???FIN"
+
+#: memline.c:1333
+msgid "E311: Recovery Interrupted"
+msgstr "E311: Recuperación interrumpida"
+
+#: memline.c:1338
+msgid ""
+"E312: Errors detected while recovering; look for lines starting with ???"
+msgstr ""
+"E312: Se han detectado errores al recuperar; busque líneas que "
+"empiecen con ???"
+
+#: memline.c:1340
+msgid "See \":help E312\" for more information."
+msgstr "Vea \":help E312\" para más información."
+
+#: memline.c:1345
+msgid "Recovery completed. You should check if everything is OK."
+msgstr "Recuperación completa. Ud. debería comprobar que todo está bien"
+
+#: memline.c:1346
+msgid ""
+"\n"
+"(You might want to write out this file under another name\n"
+msgstr ""
+"\n"
+"(Podría querer guardar este archivo con otro nombre\n"
+
+#: memline.c:1347
+msgid "and run diff with the original file to check for changes)\n"
+msgstr ""
+"y ejecutar \"diff\" con el archivo original para comprobar los cambios)\n"
+
+#: memline.c:1348
+msgid ""
+"Delete the .swp file afterwards.\n"
+"\n"
+msgstr ""
+"Elimine el archivo .swp después de terminar.\n"
+"\n"
+
+# use msg() to start the scrolling properly
+#. use msg() to start the scrolling properly
+#: memline.c:1408
+msgid "Swap files found:"
+msgstr "Se han encontrado los siguientes archivos de intercambio:"
+
+#: memline.c:1593
+msgid " In current directory:\n"
+msgstr " En el directorio actual:\n"
+
+#: memline.c:1595
+msgid " Using specified name:\n"
+msgstr " Usando el nombre especificado:\n"
+
+#: memline.c:1599
+msgid " In directory "
+msgstr " En el directorio "
+
+#: memline.c:1617
+msgid " -- none --\n"
+msgstr " -- ninguno --\n"
+
+#: memline.c:1692
+msgid " owned by: "
+msgstr " propiedad de: "
+
+#: memline.c:1694
+msgid " dated: "
+msgstr " de fecha: "
+
+#: memline.c:1698 memline.c:3736
+msgid " dated: "
+msgstr " de fecha: "
+
+#: memline.c:1717
+msgid " [from Vim version 3.0]"
+msgstr " [desde la versión 3.0 de Vim]"
+
+#: memline.c:1721
+msgid " [does not look like a Vim swap file]"
+msgstr " [no parece un archivo de intercambio de Vim]"
+
+#: memline.c:1725
+msgid " file name: "
+msgstr " nombre del archivo: "
+
+#: memline.c:1731
+msgid ""
+"\n"
+" modified: "
+msgstr ""
+"\n"
+" modificado: "
+
+#: memline.c:1732
+msgid "YES"
+msgstr "SI"
+
+#: memline.c:1732
+msgid "no"
+msgstr "no"
+
+#: memline.c:1736
+msgid ""
+"\n"
+" user name: "
+msgstr ""
+"\n"
+" nombre del usuario: "
+
+#: memline.c:1743
+msgid " host name: "
+msgstr " nombre del servidor: "
+
+#: memline.c:1745
+msgid ""
+"\n"
+" host name: "
+msgstr ""
+"\n"
+" nombre del servidor: "
+
+#: memline.c:1751
+msgid ""
+"\n"
+" process ID: "
+msgstr ""
+"\n"
+" ID del proceso: "
+
+#: memline.c:1757
+msgid " (still running)"
+msgstr " (aún en ejecución)"
+
+#: memline.c:1769
+msgid ""
+"\n"
+" [not usable with this version of Vim]"
+msgstr ""
+"\n"
+" [no se puede usar con esta versión de Vim]"
+
+#: memline.c:1772
+msgid ""
+"\n"
+" [not usable on this computer]"
+msgstr ""
+"\n"
+" [no se puede usar en este ordenador]"
+
+#: memline.c:1777
+msgid " [cannot be read]"
+msgstr " [no se puede leer]"
+
+#: memline.c:1781
+msgid " [cannot be opened]"
+msgstr " [no se puede abrir]"
+
+#: memline.c:1971
+msgid "E313: Cannot preserve, there is no swap file"
+msgstr "E313: No se pudo preservar, no existe un archivo de intercambio"
+
+#: memline.c:2024
+msgid "File preserved"
+msgstr "Archivo preservado"
+
+#: memline.c:2026
+msgid "E314: Preserve failed"
+msgstr "E314: Falló la preservación del archivo"
+
+#: memline.c:2103
+#, c-format
+msgid "E315: ml_get: invalid lnum: %ld"
+msgstr "E315: \"ml_get\": número de línea no válido: %ld"
+
+#: memline.c:2138
+#, c-format
+msgid "E316: ml_get: cannot find line %ld"
+msgstr "E316: \"ml_get\": no se pudo encontrar la línea %ld"
+
+#: memline.c:2552
+msgid "E317: pointer block id wrong 3"
+msgstr "E317: El id del bloque de punteros es incorrecto. 3"
+
+#: memline.c:2632
+msgid "stack_idx should be 0"
+msgstr "\"stack_idx\" debería ser 0"
+
+#: memline.c:2694
+msgid "E318: Updated too many blocks?"
+msgstr "E318: ¿Demasiados bloques actualizados?"
+
+#: memline.c:2874
+msgid "E317: pointer block id wrong 4"
+msgstr "E317: El id del bloque de punteros es incorrecto. 4"
+
+#: memline.c:2901
+msgid "deleted block 1?"
+msgstr "¿bloque 1 suprimido?"
+
+#: memline.c:3101
+#, c-format
+msgid "E320: Cannot find line %ld"
+msgstr "E320: No se pudo encontrar la línea %ld"
+
+#: memline.c:3347
+msgid "E317: pointer block id wrong"
+msgstr "E317: El id del bloque de punteros es incorrecto"
+
+#: memline.c:3363
+msgid "pe_line_count is zero"
+msgstr "\"pe_line_count\" es cero"
+
+#: memline.c:3392
+#, c-format
+msgid "E322: line number out of range: %ld past the end"
+msgstr "E322: número de línea fuera de rango: %ld más allá del final"
+
+#: memline.c:3396
+#, c-format
+msgid "E323: line count wrong in block %ld"
+msgstr "E323: recuento de líneas erróneo en el bloque %ld"
+
+#: memline.c:3445
+msgid "Stack size increases"
+msgstr "El tamaño de la pila aumenta"
+
+#: memline.c:3492
+msgid "E317: pointer block id wrong 2"
+msgstr "E317: El id del bloque de punteros es incorrecto. 2"
+
+#: memline.c:3531
+#, c-format
+msgid "E773: Symlink loop for \"%s\""
+msgstr "E773: Bucle de symlinks para \"%s\""
+
+#: memline.c:3726
+msgid "E325: ATTENTION"
+msgstr "E325: ATENCIÓN"
+
+#: memline.c:3727
+msgid ""
+"\n"
+"Found a swap file by the name \""
+msgstr ""
+"\n"
+"Se ha encontrado un archivo de intercambio con el nombre \""
+
+#: memline.c:3731
+msgid "While opening file \""
+msgstr "al abrir el archivo \""
+
+#: memline.c:3744
+msgid " NEWER than swap file!\n"
+msgstr " MÃS NUEVO que el archivo de intercambio!\n"
+
+# Some of these messages are long to allow translation to
+# * other languages.
+#. Some of these messages are long to allow translation to
+#. * other languages.
+#: memline.c:3748
+msgid ""
+"\n"
+"(1) Another program may be editing the same file.\n"
+" If this is the case, be careful not to end up with two\n"
+" different instances of the same file when making changes.\n"
+msgstr ""
+"\n"
+"(1) Puede que otro programa esté editando el mismo archivo.\n"
+" De ser así, tenga cuidado de no acabar con dos\n"
+" ejemplares diferentes del mismo archivo al hacer cambios.\n"
+
+#: memline.c:3749
+msgid " Quit, or continue with caution.\n"
+msgstr " Salga del programa o continúe con precaución.\n"
+
+#: memline.c:3750
+msgid ""
+"\n"
+"(2) An edit session for this file crashed.\n"
+msgstr ""
+"\n"
+"(2) Falló una sesión de edición de este archivo.\n"
+
+#: memline.c:3751
+msgid " If this is the case, use \":recover\" or \"vim -r "
+msgstr " Si es así, use \":recover\" o \"vim -r "
+
+#: memline.c:3753
+msgid ""
+"\"\n"
+" to recover the changes (see \":help recovery\").\n"
+msgstr ""
+"\"\n"
+" para recuperar los cambios (véa \":help recovery\").\n"
+
+#: memline.c:3754
+msgid " If you did this already, delete the swap file \""
+msgstr " Si Ud. ya ha hecho esto, borre el archivo de intercambio \""
+
+#: memline.c:3756
+msgid ""
+"\"\n"
+" to avoid this message.\n"
+msgstr ""
+"\"\n"
+" para evitar este mensaje.\n"
+
+#: memline.c:4175 memline.c:4179
+msgid "Swap file \""
+msgstr "¡El archivo de intercambio \""
+
+#: memline.c:4176 memline.c:4182
+msgid "\" already exists!"
+msgstr "\" ya existe!"
+
+#: memline.c:4185
+msgid "VIM - ATTENTION"
+msgstr "VIM - ATENCIÓN"
+
+#: memline.c:4187
+msgid "Swap file already exists!"
+msgstr "¡Ya existe un archivo de intercambio!"
+
+#: memline.c:4191
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"&Abrir para lectura únicamente\n"
+"&Editar de todas formas\n"
+"&Recuperar\n"
+"&Salir\n"
+"A&bortar"
+
+#: memline.c:4193
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Delete it\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"&Abrir para lectura únicamente\n"
+"&Editar de todas formas\n"
+"&Recuperar\n"
+"&Borrar\n"
+"&Salir\n"
+"&Abortar"
+
+#: memline.c:4264
+msgid "E326: Too many swap files found"
+msgstr "E326: Se han encontrado demasiados archivos de intercambio"
+
+#: menu.c:64
+msgid "E327: Part of menu-item path is not sub-menu"
+msgstr "E327: Parte de la ruta del item del menú no es un sub-menú"
+
+#: menu.c:65
+msgid "E328: Menu only exists in another mode"
+msgstr "E328: El menú solo existe en otro modo de operación"
+
+#: menu.c:66
+#, c-format
+msgid "E329: No menu \"%s\""
+msgstr "E329: No existe el menú \"%s\""
+
+#. Only a mnemonic or accelerator is not valid.
+#: menu.c:519
+msgid "E792: Empty menu name"
+msgstr "E792: Nombre de menú vacío"
+
+#: menu.c:537
+msgid "E330: Menu path must not lead to a sub-menu"
+msgstr "E330: La ruta del menú no debe conducir a un sub-menú"
+
+#: menu.c:576
+msgid "E331: Must not add menu items directly to menu bar"
+msgstr ""
+"E331: No se deben añadir elementos del menú directamente a la barra del menú"
+
+#: menu.c:582
+msgid "E332: Separator cannot be part of a menu path"
+msgstr "E332: El separador no puede ser parte de una ruta de menú"
+
+# Now we have found the matching menu, and we list the mappings
+# Highlight title
+#. Now we have found the matching menu, and we list the mappings
+#. Highlight title
+#: menu.c:1127
+msgid ""
+"\n"
+"--- Menus ---"
+msgstr ""
+"\n"
+"--- Menús ---"
+
+#: menu.c:2090
+msgid "Tear off this menu"
+msgstr "Desprender y flotar este menú"
+
+#: menu.c:2155
+msgid "E333: Menu path must lead to a menu item"
+msgstr "E333: La ruta del menú debe conducir a un item del menú"
+
+#: menu.c:2175
+#, c-format
+msgid "E334: Menu not found: %s"
+msgstr "E334: No se ha encontrado el menú: %s"
+
+#: menu.c:2257
+#, c-format
+msgid "E335: Menu not defined for %s mode"
+msgstr "E335: El menú no está definido para el modo %s"
+
+#: menu.c:2295
+msgid "E336: Menu path must lead to a sub-menu"
+msgstr "E336: La ruta del menú debe conducir a un sub-menú"
+
+#: menu.c:2316
+msgid "E337: Menu not found - check menu names"
+msgstr "E337: No se ha encontrado el menú - verifique los nombres de los menús"
+
+#: message.c:462
+#, c-format
+msgid "Error detected while processing %s:"
+msgstr "Se ha detectado un error al procesar %s:"
+
+#: message.c:487
+#, c-format
+msgid "line %4ld:"
+msgstr "línea %4ld"
+
+#: message.c:685
+#, c-format
+msgid "E354: Invalid register name: '%s'"
+msgstr "E354: Nombre de registro no válido: '%s'"
+
+#: message.c:833
+msgid "Messages maintainer: Bram Moolenaar <Bram@vim.org>"
+msgstr ""
+"Traducción: Proyecto vim-doc-es <http://www.assembla.com/wiki/show/vim-doc-es>"
+
+#: message.c:1090
+msgid "Interrupt: "
+msgstr "Interrupción: "
+
+#: message.c:1092
+msgid "Press ENTER or type command to continue"
+msgstr "Pulse INTRO o escriba una orden para continuar"
+
+#: message.c:2139
+#, c-format
+msgid "%s line %ld"
+msgstr "%s, en la línea %ld"
+
+#: message.c:2839
+msgid "-- More --"
+msgstr "-- Más --"
+
+#: message.c:2845
+msgid " SPACE/d/j: screen/page/line down, b/u/k: up, q: quit "
+msgstr " ESPACIO/d/j: pantalla/página/línea abajo, b/u/k: arriba, q: salir "
+
+#: message.c:3637 message.c:3652
+msgid "Question"
+msgstr "Pregunta"
+
+#: message.c:3639
+msgid ""
+"&Yes\n"
+"&No"
+msgstr ""
+"&Si\n"
+"&No"
+
+#: message.c:3672
+msgid ""
+"&Yes\n"
+"&No\n"
+"Save &All\n"
+"&Discard All\n"
+"&Cancel"
+msgstr ""
+"&Si\n"
+"&No\n"
+"&Guardar todo\n"
+"&Descartar todo\n"
+"&Cancelar"
+
+#: message.c:3713
+msgid "Select Directory dialog"
+msgstr "Diálogo: Selección de directorio"
+
+#: message.c:3715
+msgid "Save File dialog"
+msgstr "Diálogo: Guardar Archivos"
+
+#: message.c:3717
+msgid "Open File dialog"
+msgstr "Diálogo: Abrir Archivos"
+
+# TODO: non-GUI file selector here
+#. TODO: non-GUI file selector here
+#: message.c:3817
+msgid "E338: Sorry, no file browser in console mode"
+msgstr "E338: Lo siento, no hay navegador de archivos en el modo de consola"
+
+#: message.c:3848
+msgid "E766: Insufficient arguments for printf()"
+msgstr "E766: Argumentos insuficientes para printf()"
+
+#: message.c:3924
+msgid "E807: Expected Float argument for printf()"
+msgstr "E807: Se esperaba un argumento \"Float\" para printf()"
+
+#: message.c:4812
+msgid "E767: Too many arguments to printf()"
+msgstr "E767: Demasiados argumentos para printf()"
+
+#: misc1.c:2975
+msgid "W10: Warning: Changing a readonly file"
+msgstr "W10: Advertencia: cambiando un archivo de sólo lectura"
+
+#: misc1.c:3269
+msgid "Type number and <Enter> or click with mouse (empty cancels): "
+msgstr "Escriba un número e <Intro> o pulse con el ratón (la omisión cancela) "
+
+#: misc1.c:3271
+msgid "Type number and <Enter> (empty cancels): "
+msgstr "Escoja un número e <Intro> (la omisión cancela la acción): "
+
+#: misc1.c:3323
+msgid "1 more line"
+msgstr "1 línea más"
+
+#: misc1.c:3325
+msgid "1 line less"
+msgstr "1 línea menos"
+
+#: misc1.c:3330
+#, c-format
+msgid "%ld more lines"
+msgstr "%ld líneas más"
+
+#: misc1.c:3332
+#, c-format
+msgid "%ld fewer lines"
+msgstr "%ld líneas menos"
+
+#: misc1.c:3335
+msgid " (Interrupted)"
+msgstr " (Interrumpido)"
+
+#: misc1.c:3400
+msgid "Beep!"
+msgstr "¡Bip!"
+
+#: misc1.c:8380
+msgid "Vim: preserving files...\n"
+msgstr "Vim: preservando archivos...\n"
+
+# close all memfiles, without deleting
+#. close all memfiles, without deleting
+#: misc1.c:8390
+msgid "Vim: Finished.\n"
+msgstr "Vim: Finalizado.\n"
+
+#: misc2.c:718 misc2.c:734
+#, c-format
+msgid "ERROR: "
+msgstr "ERROR: "
+
+#: misc2.c:738
+#, c-format
+msgid ""
+"\n"
+"[bytes] total alloc-freed %lu-%lu, in use %lu, peak use %lu\n"
+msgstr ""
+"\n"
+"[bytes] total liberados por alloc: %lu-%lu, en uso: %lu, uso máximo: %lu\n"
+
+#: misc2.c:740
+#, c-format
+msgid ""
+"[calls] total re/malloc()'s %lu, total free()'s %lu\n"
+"\n"
+msgstr ""
+"[llamadas] total re/malloc(): %lu, total free(): %lu\n"
+"\n"
+
+#: misc2.c:795
+msgid "E340: Line is becoming too long"
+msgstr "E340: La línea se está haciendo demasiado larga"
+
+#: misc2.c:839
+#, c-format
+msgid "E341: Internal error: lalloc(%ld, )"
+msgstr "E341: Error interno: lalloc(%ld, )"
+
+#: misc2.c:953
+#, c-format
+msgid "E342: Out of memory! (allocating %lu bytes)"
+msgstr "E342: ¡Memoria agotada! (al asignar %lu bytes)"
+
+#: misc2.c:3033
+#, c-format
+msgid "Calling shell to execute: \"%s\""
+msgstr "Invocando al intérprete de órdenes para ejecutar: %s"
+
+#: misc2.c:3302
+msgid "E545: Missing colon"
+msgstr "E545: Falta un símbolo de dos puntos"
+
+#: misc2.c:3304 misc2.c:3331
+msgid "E546: Illegal mode"
+msgstr "E546: Modo de operación ilegal"
+
+#: misc2.c:3370
+msgid "E547: Illegal mouseshape"
+msgstr "E547: El \"mouseshape\" no es válido"
+
+#: misc2.c:3410
+msgid "E548: digit expected"
+msgstr "E548: Se esperaba un dígito"
+
+#: misc2.c:3415
+msgid "E549: Illegal percentage"
+msgstr "E549: Porcentaje ilegal"
+
+#: misc2.c:3737
+msgid "Enter encryption key: "
+msgstr "Introduzca la clave de cifrado: "
+
+#: misc2.c:3738
+msgid "Enter same key again: "
+msgstr "Introduzca la misma clave de cifrado otra vez: "
+
+#: misc2.c:3749
+msgid "Keys don't match!"
+msgstr "¡Las claves de cifrado no coinciden!"
+
+#: misc2.c:4290
+#, c-format
+msgid ""
+"E343: Invalid path: '**[number]' must be at the end of the path or be "
+"followed by '%s'."
+msgstr ""
+"E343: Ruta no válida: '**[número]' debe estar al final de la ruta "
+"o seguido de %s."
+
+#: misc2.c:5585
+#, c-format
+msgid "E344: Can't find directory \"%s\" in cdpath"
+msgstr "E344: No se pudo encontrar el directorio \"%s\" en \"cdpath\""
+
+#: misc2.c:5588
+#, c-format
+msgid "E345: Can't find file \"%s\" in path"
+msgstr "E345: No se pudo encontrar el archivo %s en la ruta"
+
+#: misc2.c:5594
+#, c-format
+msgid "E346: No more directory \"%s\" found in cdpath"
+msgstr "E346: No se han encontrado mas directorios \"%s\" en \"cdpath\""
+
+#: misc2.c:5597
+#, c-format
+msgid "E347: No more file \"%s\" found in path"
+msgstr "E347: No se han encontrado mas archivos \"%s\" en la ruta"
+
+# Get here when the server can't be found.
+#: netbeans.c:406
+msgid "Cannot connect to Netbeans #2"
+msgstr "No se pudo conectar a NetBeans #2"
+
+#: netbeans.c:415
+msgid "Cannot connect to Netbeans"
+msgstr "No se pudo conectar a NetBeans"
+
+# c-format
+#: netbeans.c:461
+#, c-format
+msgid "E668: Wrong access mode for NetBeans connection info file: \"%s\""
+msgstr "E668: El dueño/a del archivo de conexión NetBeans no es válido: %s"
+
+#: netbeans.c:770
+msgid "read from Netbeans socket"
+msgstr "leído del socket NetBeans"
+
+#: netbeans.c:1872
+#, c-format
+msgid "E658: NetBeans connection lost for buffer %ld"
+msgstr "E658: Se perdió la conexión NetBeans para el búfer %ld"
+
+#: netbeans.c:3692
+msgid "E505: "
+msgstr "E505: "
+
+#: normal.c:186
+msgid "E349: No identifier under cursor"
+msgstr "E349: No hay ningún identificador bajo el cursor"
+
+#: normal.c:2198
+msgid "E774: 'operatorfunc' is empty"
+msgstr "E774: 'operatorfunc' está vacío"
+
+#: normal.c:2217
+msgid "E775: Eval feature not available"
+msgstr "E775: La característica \"eval\" no está disponible"
+
+#: normal.c:3221
+msgid "Warning: terminal cannot highlight"
+msgstr "Advertencia: la terminal no puede resaltar el texto"
+
+#: normal.c:3516
+msgid "E348: No string under cursor"
+msgstr "E348: No hay ninguna cadena bajo el cursor"
+
+#: normal.c:4868
+msgid "E352: Cannot erase folds with current 'foldmethod'"
+msgstr "E352: No se pudo borrar pliegues con el 'folmethod' actual"
+
+#: normal.c:7365
+msgid "E664: changelist is empty"
+msgstr "E664: La lista de cambios está vacía"
+
+#: normal.c:7367
+msgid "E662: At start of changelist"
+msgstr "E662: Al comienzo de la lista de cambios"
+
+#: normal.c:7369
+msgid "E663: At end of changelist"
+msgstr "E663: Al final de la lista de cambios"
+
+#: normal.c:8734
+msgid "Type :quit<Enter> to exit Vim"
+msgstr "Escriba \":quit<intro>\" para salir de Vim"
+
+#: ops.c:293
+#, c-format
+msgid "1 line %sed 1 time"
+msgstr "1 línea %sed 1 vez"
+
+#: ops.c:295
+#, c-format
+msgid "1 line %sed %d times"
+msgstr "1 línea %sed %d veces"
+
+#: ops.c:300
+#, c-format
+msgid "%ld lines %sed 1 time"
+msgstr "%ld líneas %sed 1 vez"
+
+#: ops.c:303
+#, c-format
+msgid "%ld lines %sed %d times"
+msgstr "%ld líneas %sed %d veces"
+
+#: ops.c:691
+#, c-format
+msgid "%ld lines to indent... "
+msgstr "%ld líneas por sangrar..."
+
+#: ops.c:742
+msgid "1 line indented "
+msgstr "1 línea sangrada"
+
+#: ops.c:744
+#, c-format
+msgid "%ld lines indented "
+msgstr "%ld líneas sangradas"
+
+#: ops.c:1170
+msgid "E748: No previously used register"
+msgstr "E748: No hay registro previamente en uso"
+
+# must display the prompt
+#. must display the prompt
+#: ops.c:1734
+msgid "cannot yank; delete anyway"
+msgstr "No se pudo copiar \"yank\"; ¿Lo borro de todas formas?"
+
+#: ops.c:2331
+msgid "1 line changed"
+msgstr "1 línea cambiada"
+
+#: ops.c:2333
+#, c-format
+msgid "%ld lines changed"
+msgstr "%ld líneas cambiadas"
+
+#: ops.c:2788
+#, c-format
+msgid "freeing %ld lines"
+msgstr "liberando %ld líneas"
+
+#: ops.c:3073
+msgid "block of 1 line yanked"
+msgstr "bloque de 1 línea copiada"
+
+#: ops.c:3076
+msgid "1 line yanked"
+msgstr "1 línea copiada"
+
+#: ops.c:3080
+#, c-format
+msgid "block of %ld lines yanked"
+msgstr "bloque de %ld líneas copiadas"
+
+#: ops.c:3083
+#, c-format
+msgid "%ld lines yanked"
+msgstr "%ld líneas copiadas"
+
+#: ops.c:3378
+#, c-format
+msgid "E353: Nothing in register %s"
+msgstr "E353: No hay nada en el registro %s"
+
+# Highlight title
+#. Highlight title
+#: ops.c:3970
+msgid ""
+"\n"
+"--- Registers ---"
+msgstr ""
+"\n"
+"--- Registros ---"
+
+#: ops.c:5344
+msgid "Illegal register name"
+msgstr "Nombre de registro ilegal"
+
+#: ops.c:5440
+#, c-format
+msgid ""
+"\n"
+"# Registers:\n"
+msgstr ""
+"\n"
+"# Registros:\n"
+
+#: ops.c:5497
+#, c-format
+msgid "E574: Unknown register type %d"
+msgstr "E574: Registro desconocido de tipo %d"
+
+#: ops.c:6435
+#, c-format
+msgid "%ld Cols; "
+msgstr "%ld Cols; "
+
+#: ops.c:6444
+#, c-format
+msgid "Selected %s%ld of %ld Lines; %ld of %ld Words; %ld of %ld Bytes"
+msgstr ""
+"Selección %s%ld de %ld Líneas; %ld de %ld Palabras; %ld de %ld Caracteres"
+
+#: ops.c:6451
+#, c-format
+msgid ""
+"Selected %s%ld of %ld Lines; %ld of %ld Words; %ld of %ld Chars; %ld of %ld "
+"Bytes"
+msgstr ""
+"Selección %s%ld de %ld Líneas; %ld de %ld Palabras; %ld de %ld Caracteres; %"
+"ld de %ld Bytes"
+
+#: ops.c:6470
+#, c-format
+msgid "Col %s of %s; Line %ld of %ld; Word %ld of %ld; Byte %ld of %ld"
+msgstr "Col %s de %s; Línea %ld de %ld; Palabra %ld de %ld; Byte %ld de %ld"
+
+#: ops.c:6478
+#, c-format
+msgid ""
+"Col %s of %s; Line %ld of %ld; Word %ld of %ld; Char %ld of %ld; Byte %ld of "
+"%ld"
+msgstr ""
+"Col %s de %s; Línea %ld de %ld; Palabra %ld de %ld; Carácter %ld de %ld Byte "
+"%ld de %ld"
+
+#: ops.c:6490
+#, c-format
+msgid "(+%ld for BOM)"
+msgstr "(+%ld para BOM)"
+
+#: option.c:1953
+msgid "%<%f%h%m%=Page %N"
+msgstr "%<%f%h%m%=Página %N"
+
+#: option.c:2524
+msgid "Thanks for flying Vim"
+msgstr "Gracias por volar con Vim"
+
+#: option.c:4099 option.c:4242
+msgid "E518: Unknown option"
+msgstr "E518: Opción desconocida"
+
+#: option.c:4112
+msgid "E519: Option not supported"
+msgstr "E519: Opción no admitida"
+
+#: option.c:4150
+msgid "E520: Not allowed in a modeline"
+msgstr "E520: No permitido en una \"modeline\""
+
+#: option.c:4368
+msgid "E521: Number required after ="
+msgstr "E521: Debe introducir un número después de \"=\""
+
+#: option.c:4693 option.c:5499
+msgid "E522: Not found in termcap"
+msgstr "E522: No lo encontré en el \"termcap\""
+
+#: option.c:4810
+#, c-format
+msgid "E539: Illegal character <%s>"
+msgstr "E539: Carácter ilegal <%s>"
+
+#: option.c:5491
+msgid "E529: Cannot set 'term' to empty string"
+msgstr "E529: No se pudo definir \"term\" como una cadena de caracteres vacía"
+
+#: option.c:5494
+msgid "E530: Cannot change term in GUI"
+msgstr "E530: No se pudo cambiar \"term\" en la interfaz gráfica"
+
+#: option.c:5496
+msgid "E531: Use \":gui\" to start the GUI"
+msgstr "E531: Use \":gui\" para iniciar la interfaz gráfica"
+
+#: option.c:5525
+msgid "E589: 'backupext' and 'patchmode' are equal"
+msgstr "E589: \"backupext\" y \"patchmode\" son iguales"
+
+#: option.c:5753
+msgid "E617: Cannot be changed in the GTK+ 2 GUI"
+msgstr "E617: No puede cambiarse en la interfaz gráfica de GTK+ 2"
+
+#: option.c:5931
+msgid "E524: Missing colon"
+msgstr "E524: Falta un símbolo de dos puntos"
+
+#: option.c:5933
+msgid "E525: Zero length string"
+msgstr "E525: Cadena de caracteres de largo cero"
+
+#: option.c:6016
+#, c-format
+msgid "E526: Missing number after <%s>"
+msgstr "E526: Falta el número después de <%s>"
+
+#: option.c:6030
+msgid "E527: Missing comma"
+msgstr "E527: Falta una coma"
+
+#: option.c:6037
+msgid "E528: Must specify a ' value"
+msgstr "E528: Debe especificar un valor "
+
+#: option.c:6086
+msgid "E595: contains unprintable or wide character"
+msgstr "E595: Contiene un carácter no imprimible o de más de un byte"
+
+#: option.c:6130
+msgid "E596: Invalid font(s)"
+msgstr "E596: Las fuente/s de impresión no son válidas"
+
+#: option.c:6139
+msgid "E597: can't select fontset"
+msgstr "E597: No se pudo seleccionar ese \"fontset\""
+
+#: option.c:6141
+msgid "E598: Invalid fontset"
+msgstr "E598: El conjunto de tipos de letra de impresión no es válido"
+
+#: option.c:6149
+msgid "E533: can't select wide font"
+msgstr ""
+"E533: No se pudo seleccionar el tipo de letra de impresión \"ancho\" (de "
+"\"byte\" doble)"
+
+#: option.c:6151
+msgid "E534: Invalid wide font"
+msgstr "E534: Tipo de letra de impresión \"ancho\" inválida"
+
+#: option.c:6477
+#, c-format
+msgid "E535: Illegal character after <%c>"
+msgstr "E535: Carácter ilegal después de <%c>"
+
+#: option.c:6597
+msgid "E536: comma required"
+msgstr "E536: necesita una coma"
+
+#: option.c:6607
+#, c-format
+msgid "E537: 'commentstring' must be empty or contain %s"
+msgstr "E537: 'commentstring' debe estar vacío o contener %s"
+
+#: option.c:6688
+msgid "E538: No mouse support"
+msgstr "E538: No hay soporte para el ratón"
+
+#: option.c:7007
+msgid "E540: Unclosed expression sequence"
+msgstr "E540: Secuencia de expresión sin cerrar"
+
+#: option.c:7011
+msgid "E541: too many items"
+msgstr "E541: Demasiados elementos"
+
+#: option.c:7013
+msgid "E542: unbalanced groups"
+msgstr "E542: Grupos sin equilibrar"
+
+#: option.c:7349
+msgid "E590: A preview window already exists"
+msgstr "E590: Ya existe una ventana de visualización previa"
+
+#: option.c:7605
+msgid "W17: Arabic requires UTF-8, do ':set encoding=utf-8'"
+msgstr "W17: La opción árabe necesita de UTF-8, use \":set encoding=utf-8\""
+
+#: option.c:8028
+#, c-format
+msgid "E593: Need at least %d lines"
+msgstr "E593: Necesita al menos %d líneas"
+
+#: option.c:8038
+#, c-format
+msgid "E594: Need at least %d columns"
+msgstr "E594: Necesita al menos %d columnas"
+
+#: option.c:8357
+#, c-format
+msgid "E355: Unknown option: %s"
+msgstr "E355: Opción desconocida: %s"
+
+#. There's another character after zeros or the string
+#. * is empty. In both cases, we are trying to set a
+#. * num option using a string.
+#: option.c:8389
+#, c-format
+msgid "E521: Number required: &%s = '%s'"
+msgstr "E521: Debe introducir un número: &%s = '%s'"
+
+#: option.c:8513
+msgid ""
+"\n"
+"--- Terminal codes ---"
+msgstr ""
+"\n"
+"--- Códigos de terminal ---"
+
+#: option.c:8515
+msgid ""
+"\n"
+"--- Global option values ---"
+msgstr ""
+"\n"
+"--- Valores de las opciones globales ---"
+
+#: option.c:8517
+msgid ""
+"\n"
+"--- Local option values ---"
+msgstr ""
+"\n"
+"--- Valores de las opciones locales ---"
+
+#: option.c:8519
+msgid ""
+"\n"
+"--- Options ---"
+msgstr ""
+"\n"
+"--- Opciones ---"
+
+#: option.c:9332
+msgid "E356: get_varp ERROR"
+msgstr "E356: ERROR en \"get_varp\""
+
+#: option.c:10431
+#, c-format
+msgid "E357: 'langmap': Matching character missing for %s"
+msgstr "E357: \"langmap\": falta carácter coincidente para %s"
+
+#: option.c:10463
+#, c-format
+msgid "E358: 'langmap': Extra characters after semicolon: %s"
+msgstr "E358: \"langmap\": caracteres extra después del punto y coma: %s"
+
+#: os_amiga.c:278
+msgid "cannot open "
+msgstr "No se pudo abrir"
+
+#: os_amiga.c:313
+msgid "VIM: Can't open window!\n"
+msgstr "VIM: ¡No se pudo abrir la ventana!\n"
+
+#: os_amiga.c:340
+msgid "Need Amigados version 2.04 or later\n"
+msgstr "Necesito Amigados 2.04 o una versión posterior\n"
+
+#: os_amiga.c:346
+#, c-format
+msgid "Need %s version %ld\n"
+msgstr "Necesito %s versión %ld\n"
+
+#: os_amiga.c:419
+msgid "Cannot open NIL:\n"
+msgstr "No se pudo abrir NIL:\n"
+
+#: os_amiga.c:437
+msgid "Cannot create "
+msgstr "No se pudo crear "
+
+#: os_amiga.c:943
+#, c-format
+msgid "Vim exiting with %d\n"
+msgstr "Saliendo de Vim con %d\n"
+
+#: os_amiga.c:979
+msgid "cannot change console mode ?!\n"
+msgstr "¡¿No se pudo cambiar el modo de la consola?!\n"
+
+#: os_amiga.c:1057
+msgid "mch_get_shellsize: not a console??\n"
+msgstr "\"mch_get_shellsize\": ¿No es una consola?\n"
+
+# if Vim opened a window: Executing a shell may cause crashes
+#. if Vim opened a window: Executing a shell may cause crashes
+#: os_amiga.c:1212
+msgid "E360: Cannot execute shell with -f option"
+msgstr "E360: No se pudo ejecutar el intérprete de órdenes con la opción -f"
+
+#: os_amiga.c:1253 os_amiga.c:1343
+msgid "Cannot execute "
+msgstr "No se puede ejecutar "
+
+#: os_amiga.c:1256 os_amiga.c:1353
+msgid "shell "
+msgstr "shell "
+
+#: os_amiga.c:1276 os_amiga.c:1378
+msgid " returned\n"
+msgstr " devolvió\n"
+
+#: os_amiga.c:1540
+msgid "ANCHOR_BUF_SIZE too small."
+msgstr "\"ANCHOR_BUF_SIZE\" demasiado pequeño."
+
+#: os_amiga.c:1544
+msgid "I/O ERROR"
+msgstr "ERROR I/O"
+
+#: os_mswin.c:595
+msgid "Message"
+msgstr "Mensaje"
+
+#: os_mswin.c:710
+msgid "'columns' is not 80, cannot execute external commands"
+msgstr "\"columns\" no es 80, no puede ejecutar órdenes externas"
+
+#: os_mswin.c:2143
+msgid "E237: Printer selection failed"
+msgstr "E237: Falló la selección de impresora"
+
+#: os_mswin.c:2183
+#, c-format
+msgid "to %s on %s"
+msgstr "para %s en %s"
+
+#: os_mswin.c:2198
+#, c-format
+msgid "E613: Unknown printer font: %s"
+msgstr "E613: Tipo de letra de impresión desconocida en la impresora: %s"
+
+#: os_mswin.c:2247 os_mswin.c:2257
+#, c-format
+msgid "E238: Print error: %s"
+msgstr "E238: Error de impresión: %s"
+
+#: os_mswin.c:2285
+#, c-format
+msgid "Printing '%s'"
+msgstr "Imprimiendo %s"
+
+#: os_mswin.c:3461
+#, c-format
+msgid "E244: Illegal charset name \"%s\" in font name \"%s\""
+msgstr ""
+"E244: El nombre del conjunto de caracteres \"%s\" no es válido en el "
+"nombre del tipo de letra de impresión \"%s\""
+
+#: os_mswin.c:3471
+#, c-format
+msgid "E245: Illegal char '%c' in font name \"%s\""
+msgstr ""
+"E245: Carácter '%c' ilegal en el nombre del tipo de letra de "
+"impresión %s"
+
+#: os_unix.c:1065
+msgid "Vim: Double signal, exiting\n"
+msgstr "Vim: Señal doble, saliendo\n"
+
+#: os_unix.c:1071
+#, c-format
+msgid "Vim: Caught deadly signal %s\n"
+msgstr "Vim: Capté una señal mortal %s\n"
+
+#: os_unix.c:1074
+#, c-format
+msgid "Vim: Caught deadly signal\n"
+msgstr "Vim: Capté una señal mortal\n"
+
+#: os_unix.c:1412
+#, c-format
+msgid "Opening the X display took %ld msec"
+msgstr "Abrir la pantalla X tomó %ld mseg"
+
+#: os_unix.c:1439
+msgid ""
+"\n"
+"Vim: Got X error\n"
+msgstr ""
+"\n"
+"Vim: Hay un error de X\n"
+
+#: os_unix.c:1544
+msgid "Testing the X display failed"
+msgstr "Falló la prueba del sistema X"
+
+#: os_unix.c:1684
+msgid "Opening the X display timed out"
+msgstr "El \"display\" de X tardó demasiado en abrirse"
+
+#: os_unix.c:2658 os_unix.c:2665
+msgid ""
+"\n"
+"Could not get security context for "
+msgstr ""
+"\n"
+"No se pudo obtener el contexto de seguridad para "
+
+#: os_unix.c:2675
+msgid ""
+"\n"
+"Could not set security context for "
+msgstr ""
+"\n"
+"No se pudo definir el contexto de seguridad para "
+
+#: os_unix.c:3695 os_unix.c:4620
+msgid ""
+"\n"
+"Cannot execute shell "
+msgstr ""
+"\n"
+"No se pudo ejecutar el intérprete de órdenes "
+
+#: os_unix.c:3743
+msgid ""
+"\n"
+"Cannot execute shell sh\n"
+msgstr ""
+"\n"
+"No se pudo ejecutar el intérprete de órdenes \"sh\"\n"
+
+#: os_unix.c:3747 os_unix.c:4626
+msgid ""
+"\n"
+"shell returned "
+msgstr ""
+"\n"
+"El intérprete de órdenes devolvió "
+
+#: os_unix.c:3891
+msgid ""
+"\n"
+"Cannot create pipes\n"
+msgstr ""
+"\n"
+"No se pudo crear \"pipes\"\n"
+
+#: os_unix.c:3905 os_unix.c:4169
+msgid ""
+"\n"
+"Cannot fork\n"
+msgstr ""
+"\n"
+"No se pudo crear proceso secundario \"fork\"\n"
+
+#: os_unix.c:4633
+msgid ""
+"\n"
+"Command terminated\n"
+msgstr ""
+"\n"
+"La orden fue terminada\n"
+
+#: os_unix.c:4919 os_unix.c:5069 os_unix.c:6792
+msgid "XSMP lost ICE connection"
+msgstr "XSMP perdió la conexión ICE"
+
+#: os_unix.c:6192 os_unix.c:6295
+#, c-format
+msgid "dlerror = \"%s\""
+msgstr "dlerror = \"%s\""
+
+#: os_unix.c:6377
+msgid "Opening the X display failed"
+msgstr "Falló la apertura de la pantalla de X"
+
+#: os_unix.c:6701
+msgid "XSMP handling save-yourself request"
+msgstr "XSMP está manejando una solicitud de \"guardelo usted mismo\""
+
+#: os_unix.c:6815
+msgid "XSMP opening connection"
+msgstr "XSMP está abriendo una conexión"
+
+#: os_unix.c:6834
+msgid "XSMP ICE connection watch failed"
+msgstr "XSMP Falló el supervisión de la conexión ICE"
+
+#: os_unix.c:6858
+#, c-format
+msgid "XSMP SmcOpenConnection failed: %s"
+msgstr "XSMP SmcOpenConnection falló: %s"
+
+#: os_vms_mms.c:60
+msgid "At line"
+msgstr "En la línea"
+
+#: os_w32exe.c:89
+msgid "Could not load vim32.dll!"
+msgstr "¡No se pudo cargar \"vim32.dll\"!"
+
+#: os_w32exe.c:89 os_w32exe.c:100
+msgid "VIM Error"
+msgstr "Error de Vim"
+
+#: os_w32exe.c:99
+msgid "Could not fix up function pointers to the DLL!"
+msgstr "¡No se pudo conectar los punteros de la función a la DLL!"
+
+#: os_win16.c:342 os_win32.c:3399
+#, c-format
+msgid "shell returned %d"
+msgstr "El intérprete de órdenes ha devuelto %d"
+
+#: os_win32.c:2856
+#, c-format
+msgid "Vim: Caught %s event\n"
+msgstr "Vim: Capté el evento %s\n"
+
+#: os_win32.c:2858
+msgid "close"
+msgstr "cerrar"
+
+#: os_win32.c:2860
+msgid "logoff"
+msgstr "cerrar la sesión"
+
+#: os_win32.c:2861
+msgid "shutdown"
+msgstr "apagar"
+
+#: os_win32.c:3351
+msgid "E371: Command not found"
+msgstr "E371: No se encontró la orden"
+
+#: os_win32.c:3364
+msgid ""
+"VIMRUN.EXE not found in your $PATH.\n"
+"External commands will not pause after completion.\n"
+"See :help win32-vimrun for more information."
+msgstr ""
+"VIMRUN.EXE no se encuentra en su $PATH.\n"
+"Las órdenes externas no harán una pausa al finalizar.\n"
+"Véase \":help win32-vimrun\" para más información"
+
+#: os_win32.c:3367
+msgid "Vim Warning"
+msgstr "Advertencia de Vim"
+
+#: quickfix.c:330
+#, c-format
+msgid "E372: Too many %%%c in format string"
+msgstr "E372: Demasiados %%%c en la cadena de formato"
+
+#: quickfix.c:343
+#, c-format
+msgid "E373: Unexpected %%%c in format string"
+msgstr "E373: %%%c inesperado en la cadena de formato"
+
+#: quickfix.c:405
+msgid "E374: Missing ] in format string"
+msgstr "E374: Falta ] en la cadena de formato"
+
+#: quickfix.c:419
+#, c-format
+msgid "E375: Unsupported %%%c in format string"
+msgstr "E375: %%%c no admitido en cadena de formato"
+
+#: quickfix.c:439
+#, c-format
+msgid "E376: Invalid %%%c in format string prefix"
+msgstr "E376: %%%c no es válido en el prefijo de una cadena de formato"
+
+#: quickfix.c:447
+#, c-format
+msgid "E377: Invalid %%%c in format string"
+msgstr "E377: %%%c no es válido en una cadena de formato"
+
+#: quickfix.c:473
+msgid "E378: 'errorformat' contains no pattern"
+msgstr "E378: 'errorformat' no contiene un patrón"
+
+#: quickfix.c:706
+msgid "E379: Missing or empty directory name"
+msgstr "E379: Hace falta el nombre del directorio"
+
+#: quickfix.c:1408
+msgid "E553: No more items"
+msgstr "E553: No hay más elementos"
+
+#: quickfix.c:1830
+#, c-format
+msgid "(%d of %d)%s%s: "
+msgstr "(%d de %d)%s%s: "
+
+#: quickfix.c:1832
+msgid " (line deleted)"
+msgstr " (línea borrada)"
+
+#: quickfix.c:2061
+msgid "E380: At bottom of quickfix stack"
+msgstr "E380: Al final de la pila de corrección rápida"
+
+#: quickfix.c:2070
+msgid "E381: At top of quickfix stack"
+msgstr "E381: Al principio de la pila de corrección rápida"
+
+#: quickfix.c:2084
+#, c-format
+msgid "error list %d of %d; %d errors"
+msgstr "lista de errores %d de %d: %d errores"
+
+#: quickfix.c:2670
+msgid "E382: Cannot write, 'buftype' option is set"
+msgstr "E382: No se pudo escribir, la opción \"buftype\" está activa"
+
+#: quickfix.c:3074
+msgid "E683: File name missing or invalid pattern"
+msgstr "E683: Falta el nombre del archivo o el patrón no es válido"
+
+#: quickfix.c:3172
+#, c-format
+msgid "Cannot open file \"%s\""
+msgstr "No se pudo abrir el archivo %s"
+
+#: quickfix.c:3705
+msgid "E681: Buffer is not loaded"
+msgstr "E681: El búfer no está cargado"
+
+#: quickfix.c:3766
+msgid "E777: String or List expected"
+msgstr "E777: Se esperaba una lista o una cadena de caracteres"
+
+#: regexp.c:331
+#, c-format
+msgid "E369: invalid item in %s%%[]"
+msgstr "E369: El elemento en %s%%[] no es válido"
+
+#: regexp.c:1017
+msgid "E339: Pattern too long"
+msgstr "E339: Patrón demasiado largo"
+
+#: regexp.c:1189
+msgid "E50: Too many \\z("
+msgstr "E50: Demasiados \\z("
+
+#: regexp.c:1200
+#, c-format
+msgid "E51: Too many %s("
+msgstr "E51: Hay demasiados %s("
+
+#: regexp.c:1257
+msgid "E52: Unmatched \\z("
+msgstr "E52: \\z( sin complemento"
+
+#: regexp.c:1261
+#, c-format
+msgid "E53: Unmatched %s%%("
+msgstr "E53: %s%%( sin complemento"
+
+#: regexp.c:1263
+#, c-format
+msgid "E54: Unmatched %s("
+msgstr "E54: %s( sin complemento"
+
+#: regexp.c:1268
+#, c-format
+msgid "E55: Unmatched %s)"
+msgstr "E55: %s) sin complemento"
+
+#: regexp.c:1484
+#, c-format
+msgid "E59: invalid character after %s@"
+msgstr "E59: Carácter inválido después de %s@"
+
+#: regexp.c:1518
+#, c-format
+msgid "E60: Too many complex %s{...}s"
+msgstr "E60: Hay demasiados %s{...}s complejos"
+
+#: regexp.c:1534
+#, c-format
+msgid "E61: Nested %s*"
+msgstr "E61: Anidado %s*"
+
+#: regexp.c:1537
+#, c-format
+msgid "E62: Nested %s%c"
+msgstr "E62: Anidado %s%c"
+
+#: regexp.c:1657
+msgid "E63: invalid use of \\_"
+msgstr "E63: Uso inválido de \\_"
+
+#: regexp.c:1713
+#, c-format
+msgid "E64: %s%c follows nothing"
+msgstr "E64: %s%c no sigue a nada"
+
+#: regexp.c:1769
+msgid "E65: Illegal back reference"
+msgstr "E65: Referencia inversa ilegal"
+
+#: regexp.c:1782
+msgid "E66: \\z( not allowed here"
+msgstr "E66: No se permite \\z( aquí"
+
+#: regexp.c:1801
+msgid "E67: \\z1 - \\z9 not allowed here"
+msgstr "E67: \\z1 - \\z9 no se permiten aquí"
+
+# Es preferible traducir "invalid" por "no [es] válido" pues "inválido" no es lo suficientemente claro. Además, no es políticamente correcto :-) ALV
+#: regexp.c:1813
+msgid "E68: Invalid character after \\z"
+msgstr "E68: Hay un carácter no válido después de \\z"
+
+#: regexp.c:1865
+#, c-format
+msgid "E69: Missing ] after %s%%["
+msgstr "E69: Falta ] después de %s%%["
+
+#: regexp.c:1881
+#, c-format
+msgid "E70: Empty %s%%[]"
+msgstr "E70: %s%%[] vacío"
+
+#: regexp.c:1926
+#, c-format
+msgid "E678: Invalid character after %s%%[dxouU]"
+msgstr "E678: Carácter no válido después de %s%%[dxouU]"
+
+#: regexp.c:1997
+#, c-format
+msgid "E71: Invalid character after %s%%"
+msgstr "E71: Carácter ilegal después de %s%%"
+
+#: regexp.c:2290
+#, c-format
+msgid "E769: Missing ] after %s["
+msgstr "E769: Falta ] después de %s["
+
+#: regexp.c:2978
+#, c-format
+msgid "E554: Syntax error in %s{...}"
+msgstr "E554: Error de sintaxis en %s{...}"
+
+#: regexp.c:3821
+msgid "External submatches:\n"
+msgstr "Sub-coincidencias externas:\n"
+
+#: screen.c:9072
+msgid " VREPLACE"
+msgstr " REEMPLAZO VIRTUAL"
+
+#: screen.c:9076
+msgid " REPLACE"
+msgstr " REEMPLAZAR"
+
+#: screen.c:9081
+msgid " REVERSE"
+msgstr " INVERTIR"
+
+#: screen.c:9083
+msgid " INSERT"
+msgstr " INSERTAR"
+
+#: screen.c:9086
+msgid " (insert)"
+msgstr " (insertar)"
+
+#: screen.c:9088
+msgid " (replace)"
+msgstr " (reemplazar)"
+
+#: screen.c:9090
+msgid " (vreplace)"
+msgstr " (reemplazo virtual)"
+
+#: screen.c:9093
+msgid " Hebrew"
+msgstr " hebreo"
+
+#: screen.c:9104
+msgid " Arabic"
+msgstr " árabe"
+
+#: screen.c:9107
+msgid " (lang)"
+msgstr " (idioma)"
+
+#: screen.c:9111
+msgid " (paste)"
+msgstr " (pegar)"
+
+#: screen.c:9124
+msgid " VISUAL"
+msgstr " VISUAL"
+
+#: screen.c:9125
+msgid " VISUAL LINE"
+msgstr " LÃNEA VISUAL"
+
+#: screen.c:9126
+msgid " VISUAL BLOCK"
+msgstr " BLOQUE VISUAL"
+
+#: screen.c:9127
+msgid " SELECT"
+msgstr " SELECCIONAR"
+
+#: screen.c:9128
+msgid " SELECT LINE"
+msgstr " SELECCIONAR LÃNEA"
+
+#: screen.c:9129
+msgid " SELECT BLOCK"
+msgstr " SELECCIONAR BLOQUE"
+
+#: screen.c:9145 screen.c:9211
+msgid "recording"
+msgstr "grabando"
+
+#: search.c:562
+#, c-format
+msgid "E383: Invalid search string: %s"
+msgstr "E383: La cadena de búsqueda no es válida: %s"
+
+#: search.c:983
+#, c-format
+msgid "E384: search hit TOP without match for: %s"
+msgstr "E384: La búsqueda ha llegado al PRINCIPIO sin coincidir con: %s"
+
+#: search.c:986
+#, c-format
+msgid "E385: search hit BOTTOM without match for: %s"
+msgstr "E385: La búsqueda ha llegado al FINAL sin coincidir con: %s"
+
+#: search.c:1415
+msgid "E386: Expected '?' or '/' after ';'"
+msgstr "E386: Esperaba \"?\" o \"/\" después de \";\""
+
+#: search.c:4681
+msgid " (includes previously listed match)"
+msgstr " (incluye la coincidencia mostrada previamente)"
+
+# cursor at status line
+#. cursor at status line
+#: search.c:4701
+msgid "--- Included files "
+msgstr "--- Archivos incluidos "
+
+#: search.c:4703
+msgid "not found "
+msgstr "no se encontrṕ"
+
+#: search.c:4704
+msgid "in path ---\n"
+msgstr "en la ruta ---\n"
+
+#: search.c:4761
+msgid " (Already listed)"
+msgstr " (Ya está listado)"
+
+#: search.c:4763
+msgid " NOT FOUND"
+msgstr " NO SE ENCONTRÓ"
+
+#: search.c:4817
+#, c-format
+msgid "Scanning included file: %s"
+msgstr "Explorando el archivo incluido: %s"
+
+#: search.c:4826
+#, c-format
+msgid "Searching included file %s"
+msgstr "Buscando en el archivo incluido: %s"
+
+#: search.c:5049
+msgid "E387: Match is on current line"
+msgstr "E387: La coincidencia está en la línea bajo el cursor"
+
+#: search.c:5193
+msgid "All included files were found"
+msgstr "Se han encontrado todos los archivos incluidos"
+
+#: search.c:5195
+msgid "No included files"
+msgstr "No hay archivos incluidos"
+
+#: search.c:5211
+msgid "E388: Couldn't find definition"
+msgstr "E388: La definición no se encontró"
+
+#: search.c:5213
+msgid "E389: Couldn't find pattern"
+msgstr "E389: El patrón no se encontró"
+
+#: search.c:5391
+msgid "Substitute "
+msgstr "Sustitución"
+
+#: search.c:5404
+#, c-format
+msgid ""
+"\n"
+"# Last %sSearch Pattern:\n"
+"~"
+msgstr ""
+"\n"
+"# Último %sPatrón de búsqueda:\n"
+"~"
+
+#: spell.c:989
+msgid "E759: Format error in spell file"
+msgstr "E759: Error de formato en el archivo de ortografía"
+
+#: spell.c:990
+msgid "E758: Truncated spell file"
+msgstr "E758: Archivo de ortografía truncado"
+
+#: spell.c:991
+#, c-format
+msgid "Trailing text in %s line %d: %s"
+msgstr "Texto sobrante en %s línea %d: %s"
+
+#: spell.c:992
+#, c-format
+msgid "Affix name too long in %s line %d: %s"
+msgstr "Nombre de afijo demasiado largo en %s línea %d: %s"
+
+#: spell.c:993
+msgid "E761: Format error in affix file FOL, LOW or UPP"
+msgstr "E761: Error de formato en el archivo de afijos FOL, LOW o UPP"
+
+#: spell.c:994
+msgid "E762: Character in FOL, LOW or UPP is out of range"
+msgstr "E762: El carácter en FOL, LOW o UPP está fuera de rango"
+
+#: spell.c:995
+msgid "Compressing word tree..."
+msgstr "Comprimiendo el árbol de palabras..."
+
+#: spell.c:2149
+msgid "E756: Spell checking is not enabled"
+msgstr "E756: La corrección ortográfica está desactivada"
+
+#: spell.c:2502
+#, c-format
+msgid "Warning: Cannot find word list \"%s.%s.spl\" or \"%s.ascii.spl\""
+msgstr ""
+"Advertencia: No se pudo hallar la lista de palabras \"%s.%s.spl\" "
+"or \"%s.ascii.spl\""
+
+#: spell.c:2776
+#, c-format
+msgid "Reading spell file \"%s\""
+msgstr "Leyendo archivo de ortografía \"%s\""
+
+#: spell.c:2808
+msgid "E757: This does not look like a spell file"
+msgstr "E757: Esto no parece un archivo de ortografía"
+
+#: spell.c:2814
+msgid "E771: Old spell file, needs to be updated"
+msgstr "E771: Archivo de ortografía obsoleto, debe actualizarlo"
+
+#: spell.c:2819
+msgid "E772: Spell file is for newer version of Vim"
+msgstr "E772: El archivo de ortografía es para una versión de Vim más reciente"
+
+#: spell.c:2922
+msgid "E770: Unsupported section in spell file"
+msgstr "E770: Sección no compatible en el archivo de ortografía"
+
+#: spell.c:4417
+#, c-format
+msgid "Warning: region %s not supported"
+msgstr "Advertencia: la región %s no es compatible"
+
+#: spell.c:5307
+#, c-format
+msgid "Reading affix file %s..."
+msgstr "Leyendo el archivo de afijos \"%s\"..."
+
+#: spell.c:5355 spell.c:6699 spell.c:7278
+#, c-format
+msgid "Conversion failure for word in %s line %d: %s"
+msgstr "La conversión falló para la palabra en %s línea %d: %s"
+
+#: spell.c:5403 spell.c:7313
+#, c-format
+msgid "Conversion in %s not supported: from %s to %s"
+msgstr "La conversión en %s no es posible: de %s a %s"
+
+#: spell.c:5407 spell.c:7318
+#, c-format
+msgid "Conversion in %s not supported"
+msgstr "La conversión a %s no es posible en esta versión"
+
+#: spell.c:5420
+#, c-format
+msgid "Invalid value for FLAG in %s line %d: %s"
+msgstr "El valor para \"FLAG\" no es válido en la %s línea %d: %s"
+
+#: spell.c:5433
+#, c-format
+msgid "FLAG after using flags in %s line %d: %s"
+msgstr "\"FLAG\" después de usar parámetros en %s línea %d: %s"
+
+#: spell.c:5524
+#, c-format
+msgid ""
+"Defining COMPOUNDFORBIDFLAG after PFX item may give wrong results in %s line "
+"%d"
+msgstr ""
+"Definir COMPOUNDFORBIDFLAG después de un elemento PFX puede dar resultados "
+"erróneos en %s línea %d"
+
+#: spell.c:5533
+#, c-format
+msgid ""
+"Defining COMPOUNDPERMITFLAG after PFX item may give wrong results in %s line "
+"%d"
+msgstr ""
+"Definir COMPOUNDPERMITFLAG después de un ítem PFX puede dar resultados "
+"erróneos en %s línea %d"
+
+#: spell.c:5554
+#, c-format
+msgid "Wrong COMPOUNDRULES value in %s line %d: %s"
+msgstr "Valor equivocado de COMPOUNDRULES %s línea %d: %s"
+
+#: spell.c:5581
+#, c-format
+msgid "Wrong COMPOUNDWORDMAX value in %s line %d: %s"
+msgstr "Valor equivocado de COMPOUNDWORDMAX en %s línea %d: %s"
+
+#: spell.c:5589
+#, c-format
+msgid "Wrong COMPOUNDMIN value in %s line %d: %s"
+msgstr "Valor equivocado de COMPOUNDMIN en %s línea %d: %s"
+
+#: spell.c:5597
+#, c-format
+msgid "Wrong COMPOUNDSYLMAX value in %s line %d: %s"
+msgstr "Valor equivocado de COMPOUNDSYLMAX en %s línea %d: %s"
+
+#: spell.c:5619
+#, c-format
+msgid "Wrong CHECKCOMPOUNDPATTERN value in %s line %d: %s"
+msgstr "Valor equivocado de CHECKCOMPOUNDPATTERN en %s línea %d: %s"
+
+#: spell.c:5685
+#, c-format
+msgid "Different combining flag in continued affix block in %s line %d: %s"
+msgstr ""
+"Marca de combinación diferente en el bloque de afijos continuo "
+"en %s línea %d: %s"
+
+#: spell.c:5688
+#, c-format
+msgid "Duplicate affix in %s line %d: %s"
+msgstr "Afijo duplicado en %s línea %d: %s"
+
+#: spell.c:5710
+#, c-format
+msgid ""
+"Affix also used for BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST in %s "
+"line %d: %s"
+msgstr ""
+"Afijo usado también para BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST "
+"en %s línea %d: %s"
+
+#: spell.c:5734
+#, c-format
+msgid "Expected Y or N in %s line %d: %s"
+msgstr "Esperaba Y o N en %s línea %d: %s"
+
+#: spell.c:5818
+#, c-format
+msgid "Broken condition in %s line %d: %s"
+msgstr "Condición inválida en %s línea %d: %s"
+
+#: spell.c:5966
+#, c-format
+msgid "Expected REP(SAL) count in %s line %d"
+msgstr "Esperaba conteo REP(SAL) en %s línea %d"
+
+#: spell.c:6001
+#, c-format
+msgid "Expected MAP count in %s line %d"
+msgstr "Esperaba conteo MAP en %s línea %d"
+
+#: spell.c:6020
+#, c-format
+msgid "Duplicate character in MAP in %s line %d"
+msgstr "Carácter duplicado en MAP en %s línea %d"
+
+#: spell.c:6077
+#, c-format
+msgid "Unrecognized or duplicate item in %s line %d: %s"
+msgstr "Elemento no reconocido o duplicado en %s línea %d: %s"
+
+#: spell.c:6105
+#, c-format
+msgid "Missing FOL/LOW/UPP line in %s"
+msgstr "Falta una línea FOL/LOW/UPP en %s"
+
+#: spell.c:6131
+msgid "COMPOUNDSYLMAX used without SYLLABLE"
+msgstr "COMPOUNDSYLMAX usado sin SYLLABLE"
+
+#: spell.c:6149
+msgid "Too many postponed prefixes"
+msgstr "Hay demasiados prefijos postpuestos"
+
+#: spell.c:6151
+msgid "Too many compound flags"
+msgstr "Demasiados parámetros compuestos"
+
+#: spell.c:6153
+msgid "Too many postponed prefixes and/or compound flags"
+msgstr "Demasiados prefijos postpuestos y/o \"flags\" compuestos"
+
+#: spell.c:6165
+#, c-format
+msgid "Missing SOFO%s line in %s"
+msgstr "Falta una línea SOFO%s en %s"
+
+#: spell.c:6168
+#, c-format
+msgid "Both SAL and SOFO lines in %s"
+msgstr "Líneas SAL y SOFO en %s"
+
+#: spell.c:6275
+#, c-format
+msgid "Flag is not a number in %s line %d: %s"
+msgstr "La marca no es un número en %s línea %d: %s"
+
+#: spell.c:6278
+#, c-format
+msgid "Illegal flag in %s line %d: %s"
+msgstr "Marca ilegal en %s line %d: %s"
+
+#: spell.c:6495 spell.c:6508
+#, c-format
+msgid "%s value differs from what is used in another .aff file"
+msgstr "El valor %s difiere de los que se usa en otro archivo .aff"
+
+#: spell.c:6660
+#, c-format
+msgid "Reading dictionary file %s..."
+msgstr "Leyendo el archivo de diccionario %s..."
+
+#: spell.c:6669
+#, c-format
+msgid "E760: No word count in %s"
+msgstr "E760: No hay cuenta de palabras en %s"
+
+#: spell.c:6740
+#, c-format
+msgid "line %6d, word %6d - %s"
+msgstr "línea %6d, palabra %6d - %s"
+
+#: spell.c:6764
+#, c-format
+msgid "Duplicate word in %s line %d: %s"
+msgstr "Palabra duplicada en %s línea %d: %s"
+
+#: spell.c:6767
+#, c-format
+msgid "First duplicate word in %s line %d: %s"
+msgstr "Primera palabra duplicada en %s line %d: %s"
+
+#: spell.c:6822
+#, c-format
+msgid "%d duplicate word(s) in %s"
+msgstr "%d palabra(s) duplicada(s) en %s"
+
+#: spell.c:6824
+#, c-format
+msgid "Ignored %d word(s) with non-ASCII characters in %s"
+msgstr "Ignorando %d palabra(s) con caracteres no-ASCII en %s"
+
+#: spell.c:7247
+#, c-format
+msgid "Reading word file %s..."
+msgstr "Leyendo archivo de palabras \"%s\"..."
+
+#: spell.c:7297
+#, c-format
+msgid "Duplicate /encoding= line ignored in %s line %d: %s"
+msgstr "Ignorando línea /encoding= duplicada en %s line %d: %s"
+
+#: spell.c:7300
+#, c-format
+msgid "/encoding= line after word ignored in %s line %d: %s"
+msgstr "Ignorando línea /encoding= después de palabra en %s línea %d: %s"
+
+#: spell.c:7327
+#, c-format
+msgid "Duplicate /regions= line ignored in %s line %d: %s"
+msgstr "Ignorando línea /regions= en %s línea %d: %s"
+
+#: spell.c:7333
+#, c-format
+msgid "Too many regions in %s line %d: %s"
+msgstr "Demasiadas regiones en %s línea %d: %s"
+
+#: spell.c:7347
+#, c-format
+msgid "/ line ignored in %s line %d: %s"
+msgstr "Ignorando línea / en %s línea %d: %s"
+
+#: spell.c:7377
+#, c-format
+msgid "Invalid region nr in %s line %d: %s"
+msgstr "Región nr no válida en %s línea %d: %s"
+
+#: spell.c:7385
+#, c-format
+msgid "Unrecognized flags in %s line %d: %s"
+msgstr "Parámetros no reconocidos en %s línea %d: %s"
+
+#: spell.c:7415
+#, c-format
+msgid "Ignored %d words with non-ASCII characters"
+msgstr "Ignorando %d palabras con caracteres no-ASCII"
+
+#: spell.c:7876
+#, c-format
+msgid "Compressed %d of %d nodes; %d (%d%%) remaining"
+msgstr "Comprimiendo %d de %d nodos; faltan %d (%d%%)"
+
+#: spell.c:8720
+msgid "Reading back spell file..."
+msgstr "Releyendo el archivo de ortografía ..."
+
+#.
+#. * Go through the trie of good words, soundfold each word and add it to
+#. * the soundfold trie.
+#.
+#: spell.c:8741
+msgid "Performing soundfolding..."
+msgstr "Ejecutando compresión fonética"
+
+#: spell.c:8754
+#, c-format
+msgid "Number of words after soundfolding: %ld"
+msgstr "Número de palabras después de la compresión fonética: %ld"
+
+#: spell.c:8879
+#, c-format
+msgid "Total number of words: %d"
+msgstr "Número total de palabras: %d"
+
+#: spell.c:9096
+#, c-format
+msgid "Writing suggestion file %s..."
+msgstr "Escribiendo el archivo de sugerencias %s..."
+
+#: spell.c:9157 spell.c:9418
+#, c-format
+msgid "Estimated runtime memory use: %d bytes"
+msgstr "Uso de memoria estimado al usar: %d bytes"
+
+#: spell.c:9289
+msgid "E751: Output file name must not have region name"
+msgstr ""
+"E751: El nombre del archivo de salida no debe contener un nombre de región"
+
+#: spell.c:9291
+msgid "E754: Only up to 8 regions supported"
+msgstr "E754: Solo se pueden usar hasta 8 regiones"
+
+#: spell.c:9321
+#, c-format
+msgid "E755: Invalid region in %s"
+msgstr "E755: Región no válida en %s"
+
+#: spell.c:9392
+msgid "Warning: both compounding and NOBREAK specified"
+msgstr "Advertencia: Se especificó \"compounding\" y NOBREAK"
+
+#: spell.c:9411
+#, c-format
+msgid "Writing spell file %s..."
+msgstr "Escribiendo archivo de ortografía \"%s\"..."
+
+#: spell.c:9416
+msgid "Done!"
+msgstr "¡Listo!"
+
+#: spell.c:9543
+#, c-format
+msgid "E765: 'spellfile' does not have %ld entries"
+msgstr "E765: 'spellfile' no tiene entradas %ld"
+
+#: spell.c:9588
+#, c-format
+msgid "Word removed from %s"
+msgstr "Eliminando palabra de %s"
+
+#: spell.c:9633
+#, c-format
+msgid "Word added to %s"
+msgstr "Añadiendo palabra en \"%s\""
+
+#: spell.c:9946
+msgid "E763: Word characters differ between spell files"
+msgstr ""
+"E763: Los caracteres de la palabra difieren entre archivos de ortografía"
+
+#: spell.c:10321
+msgid "Sorry, no suggestions"
+msgstr "Lo siento, no hay sugerencias"
+
+#: spell.c:10325
+#, c-format
+msgid "Sorry, only %ld suggestions"
+msgstr "Lo siento, solo hay %ld sugerencias"
+
+#. for when 'cmdheight' > 1
+#. avoid more prompt
+#: spell.c:10346
+#, c-format
+msgid "Change \"%.*s\" to:"
+msgstr "\"%.*s\" cambió a:"
+
+#: spell.c:10386
+#, c-format
+msgid " < \"%.*s\""
+msgstr " < \"%.*s\""
+
+#: spell.c:10562
+msgid "E752: No previous spell replacement"
+msgstr "E752: No hay un reemplazo de ortografía previo"
+
+#: spell.c:10612
+#, c-format
+msgid "E753: Not found: %s"
+msgstr "E753: No se encontró: %s"
+
+#: spell.c:11032
+#, c-format
+msgid "E778: This does not look like a .sug file: %s"
+msgstr "E778: Esto no se parece a un archivo .sug: %s"
+
+#: spell.c:11039
+#, c-format
+msgid "E779: Old .sug file, needs to be updated: %s"
+msgstr "E779: Archivo .sug obsoleto, necesita una actualización: %s"
+
+#: spell.c:11045
+#, c-format
+msgid "E780: .sug file is for newer version of Vim: %s"
+msgstr "E780: El archivo .sug es para una versión más reciente de Vim: %s"
+
+#: spell.c:11055
+#, c-format
+msgid "E781: .sug file doesn't match .spl file: %s"
+msgstr "E781: El archivo .sug no corresponde al archivo .spl: %s"
+
+#: spell.c:11068
+#, c-format
+msgid "E782: error while reading .sug file: %s"
+msgstr "E782: Error al leer archivo .sig: %s"
+
+#. This should have been checked when generating the .spl
+#. * file.
+#: spell.c:13765
+msgid "E783: duplicate char in MAP entry"
+msgstr "E783: carácter duplicado en entrada MAP"
+
+#: syntax.c:3245 syntax.c:3271
+#, c-format
+msgid "E390: Illegal argument: %s"
+msgstr "E390: Argumento ilegal: %s"
+
+#: syntax.c:3453
+#, c-format
+msgid "E391: No such syntax cluster: %s"
+msgstr "E391: No existe tal agrupamiento sintáctico: %s"
+
+#: syntax.c:3612
+msgid "No Syntax items defined for this buffer"
+msgstr "No hay elementos sintácticos definidos para este búfer"
+
+#: syntax.c:3620
+msgid "syncing on C-style comments"
+msgstr "Sincronizando con los comentarios de estilo \"C\""
+
+#: syntax.c:3628
+msgid "no syncing"
+msgstr "no hay sincronización"
+
+#: syntax.c:3631
+msgid "syncing starts "
+msgstr "Comenzando sincronización"
+
+#: syntax.c:3633 syntax.c:3708
+msgid " lines before top line"
+msgstr " líneas antes de la línea superior"
+
+#: syntax.c:3638
+msgid ""
+"\n"
+"--- Syntax sync items ---"
+msgstr ""
+"\n"
+"--- Elementos de sincronización de sintaxis ---"
+
+#: syntax.c:3643
+msgid ""
+"\n"
+"syncing on items"
+msgstr ""
+"\n"
+"sincronizando con los elementos"
+
+#: syntax.c:3649
+msgid ""
+"\n"
+"--- Syntax items ---"
+msgstr ""
+"\n"
+"--- Elementos sintácticos ---"
+
+#: syntax.c:3672
+#, c-format
+msgid "E392: No such syntax cluster: %s"
+msgstr "E392: No existe tal agrupamiento sintáctico: %s"
+
+#: syntax.c:3698
+msgid "minimal "
+msgstr "mínimo"
+
+#: syntax.c:3705
+msgid "maximal "
+msgstr "máximo"
+
+#: syntax.c:3717
+msgid "; match "
+msgstr "; coincide"
+
+#: syntax.c:3719
+msgid " line breaks"
+msgstr " líneas de quiebre"
+
+#: syntax.c:4347
+msgid "E395: contains argument not accepted here"
+msgstr "E395: el contenido del argumento no se acepta aquí"
+
+#: syntax.c:4358
+msgid "E396: containedin argument not accepted here"
+msgstr "E396: el argumento \"containedin\" no se acepta aquí"
+
+#: syntax.c:4380
+msgid "E393: group[t]here not accepted here"
+msgstr "E393: \"grouphere\" y \"groupthere\" no son válidos aquí"
+
+#: syntax.c:4404
+#, c-format
+msgid "E394: Didn't find region item for %s"
+msgstr "E394: No se encuentra el elemento de la región para %s"
+
+#: syntax.c:4481
+msgid "E397: Filename required"
+msgstr "E397: Debe proporcionar un nombre de archivo"
+
+#: syntax.c:4603
+#, c-format
+msgid "E789: Missing ']': %s"
+msgstr "E789: Falta un ']': %s"
+
+#: syntax.c:4843
+#, c-format
+msgid "E398: Missing '=': %s"
+msgstr "E398: Falta un '=': %s"
+
+#: syntax.c:5002
+#, c-format
+msgid "E399: Not enough arguments: syntax region %s"
+msgstr "E399: Argumentos insuficientes: región de sintaxis %s"
+
+#: syntax.c:5336
+msgid "E400: No cluster specified"
+msgstr "E400: No se ha especificado una agrupación"
+
+#: syntax.c:5373
+#, c-format
+msgid "E401: Pattern delimiter not found: %s"
+msgstr "E401: No hay un delimitador de patrón: %s"
+
+#: syntax.c:5448
+#, c-format
+msgid "E402: Garbage after pattern: %s"
+msgstr "E402: Basura después del patrón: %s"
+
+#: syntax.c:5537
+msgid "E403: syntax sync: line continuations pattern specified twice"
+msgstr ""
+"E403: Sincronización de sintaxis: Se especificó dos veces un "
+"patrón de continuación de línea"
+
+#: syntax.c:5594
+#, c-format
+msgid "E404: Illegal arguments: %s"
+msgstr "E404: Argumentos ilegales: %s"
+
+#: syntax.c:5644
+#, c-format
+msgid "E405: Missing equal sign: %s"
+msgstr "E405: Falta el signo igual: %s"
+
+#: syntax.c:5650
+#, c-format
+msgid "E406: Empty argument: %s"
+msgstr "E406: Argumento vacío: %s"
+
+#: syntax.c:5676
+#, c-format
+msgid "E407: %s not allowed here"
+msgstr "E407: %s no se permite aquí"
+
+#: syntax.c:5683
+#, c-format
+msgid "E408: %s must be first in contains list"
+msgstr "E408: %s debe ser el primero en la lista de contenido"
+
+#: syntax.c:5753
+#, c-format
+msgid "E409: Unknown group name: %s"
+msgstr "E409: Nombre de grupo desconocido: %s"
+
+#: syntax.c:5988
+#, c-format
+msgid "E410: Invalid :syntax subcommand: %s"
+msgstr "E410: Suborden \":syntax\" no válido: %s"
+
+#: syntax.c:6475
+msgid "E679: recursive loop loading syncolor.vim"
+msgstr "E679: bucle recursivo al cargar \"syncolor.vim\""
+
+#: syntax.c:6602
+#, c-format
+msgid "E411: highlight group not found: %s"
+msgstr "E411: grupo de resaltado no encontrado: %s"
+
+#: syntax.c:6626
+#, c-format
+msgid "E412: Not enough arguments: \":highlight link %s\""
+msgstr "E412: Argumentos insuficientes: \":highlight link %s\""
+
+#: syntax.c:6633
+#, c-format
+msgid "E413: Too many arguments: \":highlight link %s\""
+msgstr "E413: Demasiados argumentos: \":highlight link %s\""
+
+#: syntax.c:6653
+msgid "E414: group has settings, highlight link ignored"
+msgstr "E414: Esta grupo está configurado, se ignora el enlace resaltado"
+
+#: syntax.c:6785
+#, c-format
+msgid "E415: unexpected equal sign: %s"
+msgstr "E415: Signo \"=\" inesperado: %s"
+
+#: syntax.c:6821
+#, c-format
+msgid "E416: missing equal sign: %s"
+msgstr "E416: Falta el signo \"=\": %s"
+
+#: syntax.c:6849
+#, c-format
+msgid "E417: missing argument: %s"
+msgstr "E417: Falta el argumento: %s"
+
+#: syntax.c:6886
+#, c-format
+msgid "E418: Illegal value: %s"
+msgstr "E418: Valor ilegal: %s"
+
+#: syntax.c:7005
+msgid "E419: FG color unknown"
+msgstr "E419: Color en primer plano desconocido"
+
+#: syntax.c:7016
+msgid "E420: BG color unknown"
+msgstr "E420: Color de fondo desconocido"
+
+#: syntax.c:7077
+#, c-format
+msgid "E421: Color name or number not recognized: %s"
+msgstr "E421: Nombre o número de color desconocido: %s"
+
+#: syntax.c:7304
+#, c-format
+msgid "E422: terminal code too long: %s"
+msgstr "E422: Código de terminal demasiado largo: %s"
+
+#: syntax.c:7351
+#, c-format
+msgid "E423: Illegal argument: %s"
+msgstr "E423: Argumento ilegal: %s"
+
+#: syntax.c:7912
+msgid "E424: Too many different highlighting attributes in use"
+msgstr "E424: Hay demasiados atributos de resaltado sintáctico en uso"
+
+#: syntax.c:8649
+msgid "E669: Unprintable character in group name"
+msgstr "E669: Carácter no imprimible en el nombre del grupo"
+
+# This is an error, but since there previously was no check only
+# * give a warning.
+#: syntax.c:8657
+msgid "W18: Invalid character in group name"
+msgstr "W18: Hay un carácter no válido en el nombre del grupo"
+
+#: tag.c:85
+msgid "E555: at bottom of tag stack"
+msgstr "E555: En el final de la pila de etiquetas"
+
+#: tag.c:86
+msgid "E556: at top of tag stack"
+msgstr "E556: En el principio de la pila de etiquetas"
+
+#: tag.c:434
+msgid "E425: Cannot go before first matching tag"
+msgstr "E425: No se pudo ir antes de la primer etiqueta coincidente"
+
+#: tag.c:583
+#, c-format
+msgid "E426: tag not found: %s"
+msgstr "E426: No se encontró la etiqueta: %s"
+
+#: tag.c:616
+msgid " # pri kind tag"
+msgstr " # etiqueta tipo \"pri\""
+
+#: tag.c:619
+msgid "file\n"
+msgstr "archivo\n"
+
+#: tag.c:953
+msgid "E427: There is only one matching tag"
+msgstr "E427: Sólo coincide una etiqueta"
+
+#: tag.c:955
+msgid "E428: Cannot go beyond last matching tag"
+msgstr "E428: No se pudo ir más allá de la última etiqueta coincidente"
+
+#: tag.c:979
+#, c-format
+msgid "File \"%s\" does not exist"
+msgstr "No existe el archivo \"%s\""
+
+# Give an indication of the number of matching tags
+#. Give an indication of the number of matching tags
+#: tag.c:991
+#, c-format
+msgid "tag %d of %d%s"
+msgstr "etiqueta %d de %d%s"
+
+#: tag.c:994
+msgid " or more"
+msgstr " o más"
+
+#: tag.c:996
+msgid " Using tag with different case!"
+msgstr ""
+" ¡Está usando una etiqueta con mayúsculas y minúsculas que no coinciden!"
+
+#: tag.c:1051
+#, c-format
+msgid "E429: File \"%s\" does not exist"
+msgstr "E429: El archivo \"%s\" no existe"
+
+# Highlight title
+#. Highlight title
+#: tag.c:1119
+msgid ""
+"\n"
+" # TO tag FROM line in file/text"
+msgstr ""
+"\n"
+" # A etiqueta DESDE la línea en el archivo/texto"
+
+#: tag.c:1546
+#, c-format
+msgid "Searching tags file %s"
+msgstr "Buscando el archivo de etiquetas %s"
+
+#: tag.c:1737
+#, c-format
+msgid "E430: Tag file path truncated for %s\n"
+msgstr "E430: La ruta del archivo de etiquetas %s está truncada\n"
+
+#: tag.c:2388
+#, c-format
+msgid "E431: Format error in tags file \"%s\""
+msgstr "E431: Error de formato en el archivo de etiquetas \"%s\""
+
+#: tag.c:2392
+#, c-format
+msgid "Before byte %ld"
+msgstr "Adelante del byte %ld"
+
+#: tag.c:2425
+#, c-format
+msgid "E432: Tags file not sorted: %s"
+msgstr "E432: Archivo de etiquetas sin ordenar: %s"
+
+# never opened any tags file
+#. never opened any tags file
+#: tag.c:2469
+msgid "E433: No tags file"
+msgstr "E433: No hay archivo de etiquetas"
+
+#: tag.c:2748
+msgid "Ignoring long line in tags file"
+msgstr "Ignorando la línea larga en el archivo de etiquetas"
+
+#: tag.c:3257
+msgid "E434: Can't find tag pattern"
+msgstr "E434: No se pudo encontrar el patrón de la etiqueta"
+
+#: tag.c:3268
+msgid "E435: Couldn't find tag, just guessing!"
+msgstr "E435: No se pudo encontrar la etiqueta. ¡Estoy adivinando!"
+
+#: term.c:1793
+msgid "' not known. Available builtin terminals are:"
+msgstr "' desconocido. Los terminales incorporados disponibles son:"
+
+#: term.c:1817
+msgid "defaulting to '"
+msgstr "Usando ' por defecto"
+
+#: term.c:2172
+msgid "E557: Cannot open termcap file"
+msgstr "E557: No se pudo abrir el archivo \"termcap\""
+
+#: term.c:2176
+msgid "E558: Terminal entry not found in terminfo"
+msgstr "E558: No he encontrado la definición del terminal en \"terminfo\""
+
+#: term.c:2178
+msgid "E559: Terminal entry not found in termcap"
+msgstr "E559: No he encontrado la definición del terminal en \"termcap\""
+
+#: term.c:2337
+#, c-format
+msgid "E436: No \"%s\" entry in termcap"
+msgstr "E436: la entrada %s no existe en el archivo \"termcap\""
+
+#: term.c:2811
+msgid "E437: terminal capability \"cm\" required"
+msgstr "E437: Se necesita la capacidad \"cm\" en el terminal"
+
+# Highlight title
+#. Highlight title
+#: term.c:5280
+msgid ""
+"\n"
+"--- Terminal keys ---"
+msgstr ""
+"\n"
+"--- Teclas de la terminal ---"
+
+#: ui.c:284
+msgid "new shell started\n"
+msgstr "Iniciado nuevo intérprete de órdenes\n"
+
+#: ui.c:1886
+msgid "Vim: Error reading input, exiting...\n"
+msgstr "Vim: error al leer la entrada, saliendo...\n"
+
+#: ui.c:2409
+msgid "Used CUT_BUFFER0 instead of empty selection"
+msgstr "Se ha usado \"CUT_BUFFER0\" en vez de una selección vacía"
+
+# must display the prompt
+#. must display the prompt
+#: undo.c:645
+msgid "No undo possible; continue anyway"
+msgstr "No es posible deshacer; continuando de todos modos"
+
+#: undo.c:727 undo.c:937
+msgid "Already at oldest change"
+msgstr "Este es el cambio más antiguo"
+
+#: undo.c:742 undo.c:939
+msgid "Already at newest change"
+msgstr "Este es el cambio más nuevo"
+
+#: undo.c:930
+#, c-format
+msgid "Undo number %ld not found"
+msgstr "No se encontró el número de \"deshacer\" %ld"
+
+#: undo.c:1100
+msgid "E438: u_undo: line numbers wrong"
+msgstr "E438: \"u_undo\": números de línea erróneos"
+
+#: undo.c:1338
+msgid "more line"
+msgstr "Una línea más"
+
+#: undo.c:1340
+msgid "more lines"
+msgstr "líneas más"
+
+#: undo.c:1342
+msgid "line less"
+msgstr "una línea menos"
+
+#: undo.c:1344
+msgid "fewer lines"
+msgstr "líneas menos"
+
+#: undo.c:1349
+msgid "change"
+msgstr "cambio"
+
+#: undo.c:1351
+msgid "changes"
+msgstr "cambios"
+
+#: undo.c:1375
+#, c-format
+msgid "%ld %s; %s #%ld %s"
+msgstr "%ld %s; %s #%ld %s"
+
+#: undo.c:1378
+msgid "before"
+msgstr "antes"
+
+#: undo.c:1378
+msgid "after"
+msgstr "después"
+
+#: undo.c:1486
+msgid "Nothing to undo"
+msgstr "Nada que hacer"
+
+#: undo.c:1492
+msgid "number changes time"
+msgstr "el número modifica el tiempo"
+
+#: undo.c:1525
+#, c-format
+msgid "%ld seconds ago"
+msgstr "hace %ld segundos"
+
+#: undo.c:1541
+msgid "E790: undojoin is not allowed after undo"
+msgstr "E790: \"undojoin\" no está permitido después de \"undo\""
+
+#: undo.c:1591
+msgid "E439: undo list corrupt"
+msgstr "E439: la lista de deshacer se ha dañado"
+
+#: undo.c:1623
+msgid "E440: undo line missing"
+msgstr "E440: falta la línea deshacer"
+
+# Only MS VC 4.1 and earlier can do Win32s
+#. Only MS VC 4.1 and earlier can do Win32s
+#: version.c:1366
+msgid ""
+"\n"
+"MS-Windows 16/32-bit GUI version"
+msgstr ""
+"\n"
+"Versión de interfaz gráfica de 16/32 bits para MS-Windows"
+
+#: version.c:1369
+msgid ""
+"\n"
+"MS-Windows 64-bit GUI version"
+msgstr ""
+"\n"
+"Versión de interfaz gráfica de 64 bits para MS-Windows"
+
+#: version.c:1371
+msgid ""
+"\n"
+"MS-Windows 32-bit GUI version"
+msgstr ""
+"\n"
+"Versión de interfaz gráfica de 32 bits para MS-Windows"
+
+#: version.c:1375
+msgid " in Win32s mode"
+msgstr " en modo Win32s"
+
+#: version.c:1377
+msgid " with OLE support"
+msgstr " con compatibilidad con OLE"
+
+#: version.c:1381
+msgid ""
+"\n"
+"MS-Windows 64-bit console version"
+msgstr ""
+"\n"
+"Versión de 64 bits para consola de MS-Windows"
+
+#: version.c:1383
+msgid ""
+"\n"
+"MS-Windows 32-bit console version"
+msgstr ""
+"\n"
+"Versión de 32 bits para consola de MS-Windows"
+
+#: version.c:1388
+msgid ""
+"\n"
+"MS-Windows 16-bit version"
+msgstr ""
+"\n"
+"Versión de 16 bits para MS-Windows"
+
+#: version.c:1392
+msgid ""
+"\n"
+"32-bit MS-DOS version"
+msgstr ""
+"\n"
+"Versión de 32 bits para MS-DOS"
+
+#: version.c:1394
+msgid ""
+"\n"
+"16-bit MS-DOS version"
+msgstr ""
+"\n"
+"Versión de 16 bits para MS-DOS"
+
+#: version.c:1400
+msgid ""
+"\n"
+"MacOS X (unix) version"
+msgstr ""
+"\n"
+"Versión para X (Unix) para MacOS"
+
+#: version.c:1402
+msgid ""
+"\n"
+"MacOS X version"
+msgstr ""
+"\n"
+"Versión para MacOS X"
+
+#: version.c:1405
+msgid ""
+"\n"
+"MacOS version"
+msgstr ""
+"\n"
+"Versión para MacOS"
+
+#: version.c:1410
+msgid ""
+"\n"
+"RISC OS version"
+msgstr ""
+"\n"
+"Versión para RISC OS"
+
+#: version.c:1413
+msgid ""
+"\n"
+"OpenVMS version"
+msgstr ""
+"\n"
+"Versión para OpenVMS"
+
+#: version.c:1428
+msgid ""
+"\n"
+"Included patches: "
+msgstr ""
+"\n"
+"Parches incluidos: "
+
+#: version.c:1455
+msgid ""
+"\n"
+"Extra patches: "
+msgstr ""
+"\n"
+"Parches adicionales: "
+
+#: version.c:1467 version.c:1831
+msgid "Modified by "
+msgstr "Modificado por "
+
+#: version.c:1474
+msgid ""
+"\n"
+"Compiled "
+msgstr ""
+"\n"
+"Compilado "
+
+#: version.c:1477
+msgid "by "
+msgstr "por "
+
+#: version.c:1489
+msgid ""
+"\n"
+"Huge version "
+msgstr ""
+"\n"
+"Versión \"enorme\" "
+
+#: version.c:1492
+msgid ""
+"\n"
+"Big version "
+msgstr ""
+"\n"
+"Versión \"grande\" "
+
+#: version.c:1495
+msgid ""
+"\n"
+"Normal version "
+msgstr ""
+"\n"
+"Versión \"normal\" "
+
+#: version.c:1498
+msgid ""
+"\n"
+"Small version "
+msgstr ""
+"\n"
+"Versión \"pequeña\" "
+
+#: version.c:1500
+msgid ""
+"\n"
+"Tiny version "
+msgstr ""
+"\n"
+"Versión \"diminuta\" "
+
+#: version.c:1506
+msgid "without GUI."
+msgstr "sin interfaz gráfica (GUI)."
+
+#: version.c:1511
+msgid "with GTK2-GNOME GUI."
+msgstr "con interfaz gráfica para GTK2-GNOME."
+
+#: version.c:1513
+msgid "with GTK-GNOME GUI."
+msgstr "con interfaz gráfica para GTK-GNOME."
+
+#: version.c:1517
+msgid "with GTK2 GUI."
+msgstr "con interfaz gráfica de GTK2."
+
+#: version.c:1519
+msgid "with GTK GUI."
+msgstr "con interfaz gráfica de GTK."
+
+#: version.c:1524
+msgid "with X11-Motif GUI."
+msgstr "con interfaz gráfica para X11-Motif."
+
+#: version.c:1528
+msgid "with X11-neXtaw GUI."
+msgstr "con interfaz gráfica de X11-neXtaw."
+
+#: version.c:1530
+msgid "with X11-Athena GUI."
+msgstr "con interfaz gráfica de X11-Athena."
+
+#: version.c:1534
+msgid "with Photon GUI."
+msgstr "con interfaz gráfica para Photon."
+
+#: version.c:1537
+msgid "with GUI."
+msgstr "con interfaz gráfica de usuario."
+
+#: version.c:1540
+msgid "with Carbon GUI."
+msgstr "con GUI Carbon."
+
+#: version.c:1543
+msgid "with Cocoa GUI."
+msgstr "con interfaz gráfica para Cocoa."
+
+#: version.c:1546
+msgid "with (classic) GUI."
+msgstr "con interfaz gráfica (clásica)."
+
+#: version.c:1556
+msgid " Features included (+) or not (-):\n"
+msgstr " Aspectos incluidos (+) o no (-):\n"
+
+#: version.c:1568
+msgid " system vimrc file: \""
+msgstr " archivo \"vimrc\" del sistema: \""
+
+#: version.c:1573
+msgid " user vimrc file: \""
+msgstr " archivo \"vimrc\" del usuario: \""
+
+#: version.c:1578
+msgid " 2nd user vimrc file: \""
+msgstr " 2º archivo \"vimrc\" del usuario: \""
+
+#: version.c:1583
+msgid " 3rd user vimrc file: \""
+msgstr " 3er archivo \"vimrc\" del usuario: \""
+
+#: version.c:1588
+msgid " user exrc file: \""
+msgstr " archivo \"exrc\" del usuario: \""
+
+#: version.c:1593
+msgid " 2nd user exrc file: \""
+msgstr " 2º archivo \"exrc\" del usuario: \""
+
+#: version.c:1599
+msgid " system gvimrc file: \""
+msgstr " archivo \"gvimrc\" del sistema: \""
+
+#: version.c:1603
+msgid " user gvimrc file: \""
+msgstr " archivo \"gvimrc\" del usuario: \""
+
+#: version.c:1607
+msgid "2nd user gvimrc file: \""
+msgstr " 2º archivo \"gvimrc\" del usuario: \""
+
+#: version.c:1612
+msgid "3rd user gvimrc file: \""
+msgstr "3er archivo \"gvimrc\" del usuario: \""
+
+#: version.c:1619
+msgid " system menu file: \""
+msgstr " archivo de menú del sistema: \""
+
+#: version.c:1627
+msgid " fall-back for $VIM: \""
+msgstr " predefinido para $VIM: \""
+
+#: version.c:1633
+msgid " f-b for $VIMRUNTIME: \""
+msgstr " predefinido para $VIMRUNTIME: \""
+
+#: version.c:1637
+msgid "Compilation: "
+msgstr "Compilación: "
+
+#: version.c:1643
+msgid "Compiler: "
+msgstr "Compilador: "
+
+#: version.c:1648
+msgid "Linking: "
+msgstr "Enlazado: "
+
+#: version.c:1653
+msgid " DEBUG BUILD"
+msgstr " COMPILACIÓN CON SÃMBOLOS DE DEPURACIÓN"
+
+#: version.c:1692
+msgid "VIM - Vi IMproved"
+msgstr "VIM - VI Mejorado"
+
+#: version.c:1694
+msgid "version "
+msgstr "versión "
+
+#: version.c:1695
+msgid "by Bram Moolenaar et al."
+msgstr "por Bram Moolenaar et al."
+
+#: version.c:1699
+msgid "Vim is open source and freely distributable"
+msgstr "Vim es código abierto y se puede distribuir libremente"
+
+#: version.c:1701
+msgid "Help poor children in Uganda!"
+msgstr "¡Ayude a los niños pobres de Uganda!"
+
+#: version.c:1702
+msgid "type :help iccf<Enter> for information "
+msgstr "escriba «:help iccf<Intro>» para más información "
+
+#: version.c:1704
+msgid "type :q<Enter> to exit "
+msgstr "escriba «:q<Intro>» para salir "
+
+#: version.c:1705
+msgid "type :help<Enter> or <F1> for on-line help"
+msgstr "escriba «:help<Intro>» o <F1> para obtener ayuda "
+
+#: version.c:1706
+msgid "type :help version8<Enter> for version info"
+msgstr "escriba «:help version8<Intro>» para información de la versión"
+
+#: version.c:1709
+msgid "Running in Vi compatible mode"
+msgstr "Ejecutando en modo compatible con Vi"
+
+#: version.c:1710
+msgid "type :set nocp<Enter> for Vim defaults"
+msgstr "escriba «:set nocp<Intro>» para los valores predefinidos de Vim"
+
+#: version.c:1711
+msgid "type :help cp-default<Enter> for info on this"
+msgstr "escriba «:help cp-default<Intro>» para más información"
+
+#: version.c:1726
+msgid "menu Help->Orphans for information "
+msgstr "menú Ayuda->Ayude a los niños huérfanos para más información "
+
+#: version.c:1728
+msgid "Running modeless, typed text is inserted"
+msgstr "Ejecución no modal, el texto escrito se inserta directamente"
+
+#: version.c:1729
+msgid "menu Edit->Global Settings->Toggle Insert Mode "
+msgstr "menú Editar->Opciones globales->Activar/Desactivar modo de inserción"
+
+#: version.c:1730
+msgid " for two modes "
+msgstr " para dos modos "
+
+#: version.c:1734
+msgid "menu Edit->Global Settings->Toggle Vi Compatible"
+msgstr ""
+"menú Editar->Opciones globales->Activar/Desactivar compatibilidad con Vi"
+
+#: version.c:1735
+msgid " for Vim defaults "
+msgstr ""
+" para los valores predeterminados de Vim"
+
+#: version.c:1782
+msgid "Sponsor Vim development!"
+msgstr "¡Patrocine el desarrollo de Vim!"
+
+#: version.c:1783
+msgid "Become a registered Vim user!"
+msgstr "¡Conviértase en un usuario registrado de Vim!"
+
+#: version.c:1786
+msgid "type :help sponsor<Enter> for information "
+msgstr "escriba «:help sponsor<Intro>» para más información "
+
+#: version.c:1787
+msgid "type :help register<Enter> for information "
+msgstr "escriba «:help register<Intro>» para más información "
+
+#: version.c:1789
+msgid "menu Help->Sponsor/Register for information "
+msgstr "menú Ayuda->Benefactor/Regístrese para más información"
+
+#: version.c:1799
+msgid "WARNING: Windows 95/98/ME detected"
+msgstr "ADVERTENCIA: se ha detectado Windows 95/98/ME"
+
+#: version.c:1802
+msgid "type :help windows95<Enter> for info on this"
+msgstr "escriba «:help windows95<Intro>» para más información"
+
+#: window.c:88
+msgid "Already only one window"
+msgstr "Solo hay una ventana"
+
+#: window.c:237
+msgid "E441: There is no preview window"
+msgstr "E441: No hay una ventana de vista previa"
+
+#: window.c:672
+msgid "E442: Can't split topleft and botright at the same time"
+msgstr "E442: No se puede dividir arriba izq. y abajo der. al mismo tiempo"
+
+#: window.c:1484
+msgid "E443: Cannot rotate when another window is split"
+msgstr "E443: No se puede rotar cuando otra ventana está dividida"
+
+#: window.c:2113
+msgid "E444: Cannot close last window"
+msgstr "E444: No se puede cerrar la última ventana"
+
+#: window.c:2120
+msgid "E813: Cannot close autocmd window"
+msgstr "E813: No se puede cerrar la ventana de autocmd"
+
+#: window.c:2125
+msgid "E814: Cannot close window, only autocmd window would remain"
+msgstr ""
+"E814: No se pudo cerrar la última ventana, solo quedará "
+"la ventana de autocmd"
+
+#: window.c:3188
+msgid "E445: Other window contains changes"
+msgstr "E445: Otra ventana contiene cambios"
+
+#: window.c:5868
+msgid "E446: No file name under cursor"
+msgstr "E446: No hay un nombre de archivo bajo el cursor"
+
+#: window.c:6005
+#, c-format
+msgid "E447: Can't find file \"%s\" in path"
+msgstr "E447: No se pudo encontrar el archivo \"%s\" en la ruta"
+
+#: if_perl.xs:420 globals.h:1420
+#, c-format
+msgid "E370: Could not load library %s"
+msgstr "E370: No se pudo cargar la biblioteca dinámica %s"
+
+#: if_perl.xs:671
+msgid "Sorry, this command is disabled: the Perl library could not be loaded."
+msgstr "Esta orden está desactivada, no se pudo cargar la biblioteca de Perl"
+
+#: if_perl.xs:726
+msgid "E299: Perl evaluation forbidden in sandbox without the Safe module"
+msgstr ""
+"E299: No se permite la evaluación de código Perl en la caja de "
+"arena sin el uso del módulo \"Safe\""
+
+#: GvimExt/gvimext.cpp:587
+msgid "Edit with &multiple Vims"
+msgstr "Editar con &múltiples Vims"
+
+#: GvimExt/gvimext.cpp:593
+msgid "Edit with single &Vim"
+msgstr "Editar con un solo &Vim"
+
+#: GvimExt/gvimext.cpp:602
+msgid "Diff with Vim"
+msgstr "Diff con Vim"
+
+#: GvimExt/gvimext.cpp:615
+msgid "Edit with &Vim"
+msgstr "Editar con &Vim"
+
+# Now concatenate
+#. Now concatenate
+#: GvimExt/gvimext.cpp:637
+msgid "Edit with existing Vim - "
+msgstr "Editar con un Vim en ejecución -"
+
+#: GvimExt/gvimext.cpp:752
+msgid "Edits the selected file(s) with Vim"
+msgstr "Editar el(los) archivos seleccionado/s con Vim"
+
+#: GvimExt/gvimext.cpp:891 GvimExt/gvimext.cpp:972
+msgid "Error creating process: Check if gvim is in your path!"
+msgstr ""
+"Error al crear el proceso: ¡Asegúrese de que gvim esta en su ruta de acceso!"
+
+#: GvimExt/gvimext.cpp:892 GvimExt/gvimext.cpp:906 GvimExt/gvimext.cpp:973
+msgid "gvimext.dll error"
+msgstr "error de \"gvimext.dll\""
+
+#: GvimExt/gvimext.cpp:905
+msgid "Path length too long!"
+msgstr "¡La ruta de acceso es demasiado larga!"
+
+#: globals.h:1174
+msgid "--No lines in buffer--"
+msgstr "--No hay líneas en el búfer--"
+
+#
+# * The error messages that can be shared are included here.
+# * Excluded are errors that are only used once and debugging messages.
+#
+#.
+#. * The error messages that can be shared are included here.
+#. * Excluded are errors that are only used once and debugging messages.
+#.
+#: globals.h:1374
+msgid "E470: Command aborted"
+msgstr "E470: La orden se ha interrumpido"
+
+#: globals.h:1375
+msgid "E471: Argument required"
+msgstr "E471: Es necesario un argumento"
+
+#: globals.h:1376
+msgid "E10: \\ should be followed by /, ? or &"
+msgstr "E10: \\ debería ir seguido de \"/\", \"?\" o \"&\""
+
+#: globals.h:1378
+msgid "E11: Invalid in command-line window; <CR> executes, CTRL-C quits"
+msgstr ""
+"E11: Inválido en la ventana de la línea de órdenes: <CR> ejecuta, CTRL-C "
+"cierra"
+
+#: globals.h:1380
+msgid "E12: Command not allowed from exrc/vimrc in current dir or tag search"
+msgstr ""
+"E12: Orden no permitida desde exrc/vimrc en el directorio "
+"en uso o al buscar etiquetas"
+
+#: globals.h:1382
+msgid "E171: Missing :endif"
+msgstr "E171: Falta \":endif\""
+
+#: globals.h:1383
+msgid "E600: Missing :endtry"
+msgstr "E600: Falta \":endtry\""
+
+#: globals.h:1384
+msgid "E170: Missing :endwhile"
+msgstr "E170: Falta \":endwhile\""
+
+#: globals.h:1385
+msgid "E170: Missing :endfor"
+msgstr "E170: Falta \":endfor\""
+
+#: globals.h:1386
+msgid "E588: :endwhile without :while"
+msgstr "E588: \":endwhile\" sin \":while\""
+
+#: globals.h:1387
+msgid "E588: :endfor without :for"
+msgstr "E588: \":endfor\" sin un \":for\""
+
+#: globals.h:1389
+msgid "E13: File exists (add ! to override)"
+msgstr "E13: El archivo ya existe (use \"!\" para sobreescribir)"
+
+#: globals.h:1390
+msgid "E472: Command failed"
+msgstr "E472: La orden falló"
+
+#: globals.h:1392
+#, c-format
+msgid "E234: Unknown fontset: %s"
+msgstr "E234: Conjunto de tipos de letra de impresión desconocido: %s"
+
+#: globals.h:1396
+#, c-format
+msgid "E235: Unknown font: %s"
+msgstr "E235: Tipo de letra de impresión desconocida: %s"
+
+#: globals.h:1399
+#, c-format
+msgid "E236: Font \"%s\" is not fixed-width"
+msgstr "E236: El tipo de letra de impresión \"%s\" no es de ancho fijo"
+
+#: globals.h:1401
+msgid "E473: Internal error"
+msgstr "E473: Error interno"
+
+#: globals.h:1402
+msgid "Interrupted"
+msgstr "Interrumpido"
+
+#: globals.h:1403
+msgid "E14: Invalid address"
+msgstr "E14: La dirección no es válida"
+
+#: globals.h:1404
+msgid "E474: Invalid argument"
+msgstr "E474: El argumento no es válido"
+
+#: globals.h:1405
+#, c-format
+msgid "E475: Invalid argument: %s"
+msgstr "E475: El argumento no es válido: %s"
+
+#: globals.h:1407
+#, c-format
+msgid "E15: Invalid expression: %s"
+msgstr "E15: La expresión no es válida: %s"
+
+#: globals.h:1409
+msgid "E16: Invalid range"
+msgstr "E16: El rango no es válido"
+
+#: globals.h:1410
+msgid "E476: Invalid command"
+msgstr "E476: La orden no es válida"
+
+#: globals.h:1412
+#, c-format
+msgid "E17: \"%s\" is a directory"
+msgstr "E17: \"%s\" es un directorio"
+
+#: globals.h:1415
+#, c-format
+msgid "E364: Library call failed for \"%s()\""
+msgstr "E364: Falló la llamada a la biblioteca para \"%s()\""
+
+#: globals.h:1421
+#, c-format
+msgid "E448: Could not load library function %s"
+msgstr "E448: No pude cargar la biblioteca de funciones %s"
+
+#: globals.h:1423
+msgid "E19: Mark has invalid line number"
+msgstr "E19: El número de línea de la marca no es válido"
+
+#: globals.h:1424
+msgid "E20: Mark not set"
+msgstr "E20: No se ha colocado una marca"
+
+#: globals.h:1425
+msgid "E21: Cannot make changes, 'modifiable' is off"
+msgstr "E21: No se pudo modificar, 'modifiable' está desactivado"
+
+#: globals.h:1426
+msgid "E22: Scripts nested too deep"
+msgstr "E22: Demasiados archivos de órdenes anidados"
+
+#: globals.h:1427
+msgid "E23: No alternate file"
+msgstr "E23: No hay un archivo alterno"
+
+#: globals.h:1428
+msgid "E24: No such abbreviation"
+msgstr "E24: No existe esa abreviatura"
+
+#: globals.h:1429
+msgid "E477: No ! allowed"
+msgstr "E477: \"!\" no está permitido"
+
+#: globals.h:1431
+msgid "E25: GUI cannot be used: Not enabled at compile time"
+msgstr ""
+"E25: No se puede usar la interfaz gráfica de usuario: No se activó al "
+"compilar"
+
+#: globals.h:1434
+msgid "E26: Hebrew cannot be used: Not enabled at compile time\n"
+msgstr "E26: No se pudo usar el hebreo: no se activó al compilar\n"
+
+#: globals.h:1437
+msgid "E27: Farsi cannot be used: Not enabled at compile time\n"
+msgstr "E27: No se pudo usar el persa (farsi): no se activó al compilar\n"
+
+#: globals.h:1440
+msgid "E800: Arabic cannot be used: Not enabled at compile time\n"
+msgstr "E800: No se pudo usar el árabe: no se activó al compilar\n"
+
+#: globals.h:1443
+#, c-format
+msgid "E28: No such highlight group name: %s"
+msgstr "E28: No existe un grupo de resaltado de nombre: %s"
+
+#: globals.h:1445
+msgid "E29: No inserted text yet"
+msgstr "E29: Aún no ha insertado texto"
+
+#: globals.h:1446
+msgid "E30: No previous command line"
+msgstr "E30: No hay una línea de órdenes previa"
+
+#: globals.h:1447
+msgid "E31: No such mapping"
+msgstr "E31: No existe tal asociación"
+
+#: globals.h:1448
+msgid "E479: No match"
+msgstr "E479: No hay coincidencia"
+
+#: globals.h:1449
+#, c-format
+msgid "E480: No match: %s"
+msgstr "E480: No coincide: %s"
+
+#: globals.h:1450
+msgid "E32: No file name"
+msgstr "E32: No hay un nombre de archivo"
+
+#: globals.h:1451
+msgid "E33: No previous substitute regular expression"
+msgstr "E33: No existe una expresión regular de sustitución previa"
+
+#: globals.h:1452
+msgid "E34: No previous command"
+msgstr "E34: No existe una orden previa"
+
+#: globals.h:1453
+msgid "E35: No previous regular expression"
+msgstr "E35: No existe una expresión regular previa"
+
+#: globals.h:1454
+msgid "E481: No range allowed"
+msgstr "E481: El rango no está permitido"
+
+#: globals.h:1456
+msgid "E36: Not enough room"
+msgstr "E36: No hay espacio suficiente"
+
+#: globals.h:1459
+#, c-format
+msgid "E247: no registered server named \"%s\""
+msgstr "E247: El servidor llamado \"%s\" no está registrado"
+
+#: globals.h:1461
+#, c-format
+msgid "E482: Can't create file %s"
+msgstr "E482: No se pudo crear el archivo \"%s\""
+
+#: globals.h:1462
+msgid "E483: Can't get temp file name"
+msgstr "E483: No se pudo obtener el nombre del archivo temporal"
+
+#: globals.h:1463
+#, c-format
+msgid "E484: Can't open file %s"
+msgstr "E484: No se pudo abrir el archivo \"%s\""
+
+#: globals.h:1464
+#, c-format
+msgid "E485: Can't read file %s"
+msgstr "E485: No se pudo leer el archivo \"%s\""
+
+#: globals.h:1465
+msgid "E37: No write since last change (add ! to override)"
+msgstr ""
+"E37: No guardó el archivo desde el último cambio (añada \"!\" para forzar)"
+
+#: globals.h:1466
+msgid "E38: Null argument"
+msgstr "E38: Argumento nulo"
+
+#: globals.h:1468
+msgid "E39: Number expected"
+msgstr "E39: Se esperaba un número"
+
+#: globals.h:1471
+#, c-format
+msgid "E40: Can't open errorfile %s"
+msgstr "E40: No se pudo abrir el archivo de errores \"%s\""
+
+#: globals.h:1474
+msgid "E233: cannot open display"
+msgstr "E233: No se pudo abrir la pantalla"
+
+#: globals.h:1476
+msgid "E41: Out of memory!"
+msgstr "E41: ¡Memoria agotada!"
+
+#: globals.h:1478
+msgid "Pattern not found"
+msgstr "No se encontró el patrón de búsqueda"
+
+#: globals.h:1480
+#, c-format
+msgid "E486: Pattern not found: %s"
+msgstr "E486: No se encontró el patrón de búsqueda: %s"
+
+#: globals.h:1481
+msgid "E487: Argument must be positive"
+msgstr "E487: El argumento debe ser positivo"
+
+#: globals.h:1483
+msgid "E459: Cannot go back to previous directory"
+msgstr "E459: No se pudo regresar al directorio previo"
+
+#: globals.h:1487
+msgid "E42: No Errors"
+msgstr "E42: No hay errores"
+
+#: globals.h:1488
+msgid "E776: No location list"
+msgstr "E776: No hay una lista de posiciones"
+
+#: globals.h:1490
+msgid "E43: Damaged match string"
+msgstr "E43: Cadena de coincidencia dañada"
+
+#: globals.h:1491
+msgid "E44: Corrupted regexp program"
+msgstr "E44: El programa \"regexp\" está corrupto"
+
+#: globals.h:1492
+msgid "E45: 'readonly' option is set (add ! to override)"
+msgstr "E45: La opción 'readonly' está activada (añada \"!\" para forzar)"
+
+#: globals.h:1494
+#, c-format
+msgid "E46: Cannot change read-only variable \"%s\""
+msgstr "E46: No puede cambiar la variable de solo lectura \"%s\""
+
+#: globals.h:1495
+#, c-format
+msgid "E794: Cannot set variable in the sandbox: \"%s\""
+msgstr "E794: No se puede definir la variable en el \"sandbox\": \"%s\""
+
+#: globals.h:1498
+msgid "E47: Error while reading errorfile"
+msgstr "E47: Error al leer el archivo de errores"
+
+#: globals.h:1501
+msgid "E48: Not allowed in sandbox"
+msgstr "E48: No se permite en el ambiente protegido"
+
+#: globals.h:1503
+msgid "E523: Not allowed here"
+msgstr "E523: No se permite aquí"
+
+#: globals.h:1506
+msgid "E359: Screen mode setting not supported"
+msgstr "E359: La configuración de la pantalla no es válida"
+
+#: globals.h:1508
+msgid "E49: Invalid scroll size"
+msgstr "E49: La longitud de desplazamiento no es válida"
+
+#: globals.h:1509
+msgid "E91: 'shell' option is empty"
+msgstr "E91: La opción 'shell' (intérprete de órdenes) está vacía"
+
+#: globals.h:1511
+msgid "E255: Couldn't read in sign data!"
+msgstr "E255: ¡No se pudo cargar los signos!"
+
+#: globals.h:1513
+msgid "E72: Close error on swap file"
+msgstr "E72: Error de cierre en el archivo de intercambio"
+
+#: globals.h:1514
+msgid "E73: tag stack empty"
+msgstr "E73: La pila de etiquetas ('tagstack') está vacía"
+
+#: globals.h:1515
+msgid "E74: Command too complex"
+msgstr "E74: La orden es demasiado compleja"
+
+#: globals.h:1516
+msgid "E75: Name too long"
+msgstr "E75: El nombre es demasiado largo"
+
+#: globals.h:1517
+msgid "E76: Too many ["
+msgstr "E76: Hay demasiados ["
+
+#: globals.h:1518
+msgid "E77: Too many file names"
+msgstr "E77: Hay demasiados nombres de archivos"
+
+#: globals.h:1519
+msgid "E488: Trailing characters"
+msgstr "E488: Caracteres en exceso al final de la línea"
+
+#: globals.h:1520
+msgid "E78: Unknown mark"
+msgstr "E78: Marca desconocida"
+
+#: globals.h:1521
+msgid "E79: Cannot expand wildcards"
+msgstr "E79: No se pudo expandir los comodines"
+
+#: globals.h:1523
+msgid "E591: 'winheight' cannot be smaller than 'winminheight'"
+msgstr "E591: \"winheight\" no puede ser más pequeño que \"winminheight\""
+
+#: globals.h:1525
+msgid "E592: 'winwidth' cannot be smaller than 'winminwidth'"
+msgstr "E592: \"winwidth\" no puede ser más pequeño que \"winminwidth\""
+
+#: globals.h:1528
+msgid "E80: Error while writing"
+msgstr "E80: Error al escribir el archivo"
+
+#: globals.h:1529
+msgid "Zero count"
+msgstr "El recuento es cero"
+
+#: globals.h:1531
+msgid "E81: Using <SID> not in a script context"
+msgstr "E81: Usando <SID> en un contexto que no es de archivo de órdenes"
+
+#: globals.h:1534
+msgid "E449: Invalid expression received"
+msgstr "E449: Se recibió una expresión inválida"
+
+#: globals.h:1537
+msgid "E463: Region is guarded, cannot modify"
+msgstr "E463: La región está protegida, no se puede modificar"
+
+#: globals.h:1538
+msgid "E744: NetBeans does not allow changes in read-only files"
+msgstr "E744: NetBeans no permite cambios a archivos de sólo lectura"
+
+#: globals.h:1540
+#, c-format
+msgid "E685: Internal error: %s"
+msgstr "E685: Error interno: %s"
+
+#: globals.h:1541
+msgid "E363: pattern uses more memory than 'maxmempattern'"
+msgstr "E363: El patrón usa más memoria que 'maxmempattern'"
+
+#: globals.h:1542
+msgid "E749: empty buffer"
+msgstr "E749: Búfer vacío"
+
+#: globals.h:1545
+msgid "E682: Invalid search pattern or delimiter"
+msgstr "E682: Patrón de búsqueda o delimitador no válido"
+
+# Overwriting a file that is loaded in another buffer is not a
+# * good idea.
+#: globals.h:1547
+msgid "E139: File is loaded in another buffer"
+msgstr "E139: El archivo ya se ha cargado en otro búfer"
+
+#: globals.h:1550
+#, c-format
+msgid "E764: Option '%s' is not set"
+msgstr "E764: No se ha definido la opción '%s'"
+
+#: globals.h:1557
+msgid "search hit TOP, continuing at BOTTOM"
+msgstr "La búsqueda ha llegado al PRINCIPIO, continuando desde el FINAL"
+
+#: globals.h:1558
+msgid "search hit BOTTOM, continuing at TOP"
+msgstr "La búsqueda ha llegado al FINAL, continuando desde el PRINCIPIO"
+
+#~ msgid "[NL found]"
+#~ msgstr "[NL encontrado]"
+
+#~ msgid "E569: maximum number of cscope connections reached"
+#~ msgstr "E569: Se ha alcanzado el número máximo de conexiones con \"cscope\""
+
+#~ msgid "-V[N]\t\tVerbose level"
+#~ msgstr "-V[N]\t\tNivel de verbosidad (traza de ejecución)"
diff --git a/src/po/fi.po b/src/po/fi.po
new file mode 100644
index 0000000..e40c008
--- /dev/null
+++ b/src/po/fi.po
@@ -0,0 +1,6993 @@
+# Finnish translation for Vim.
+# Copyright (C) 2003-2006 Free Software Foundation, Inc.
+# 2007-2018, Flammie Pirinen <flammie@iki.fi>
+#
+# Jargonia ei ole yritetty suotta kotoperäistää missä teknisempi lainasanasto
+# tulee paremmin kyseeseen.
+#
+# Sanastosta:
+# * Fold on sellainen moderneissa ohjelmointi-IDE:issä oleva toiminto, jolla
+# lohko koodia esim. funktio piilotetaan näkymästä: suom. taitos alkup.
+# analogian mukaan
+# * source, v. lataa tiedoston, kuten bash-komento source (tai .)
+# * dictionary (dict) on vaihtelevasti sanakirja tai tietorakenne
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Vim 7\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2017-10-04 17:59+0200\n"
+"PO-Revision-Date: 2017-10-05 11:17+0200\n"
+"Last-Translator: Flammie A Pirinen <flammie@iki.fi>\n"
+"Language-Team: Finnish <laatu@lokalisointi.org>\n"
+"Language: fi\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+msgid "E831: bf_key_init() called with empty password"
+msgstr "E831: bf_key_init() tyhjällä salasanalla"
+
+msgid "E820: sizeof(uint32_t) != 4"
+msgstr "E820: sizeof(uint32_t) != 4"
+
+msgid "E817: Blowfish big/little endian use wrong"
+msgstr "E817: Blowfishin tavujärjestys väärä"
+
+msgid "E818: sha256 test failed"
+msgstr "E818: sha256-testi epäonnistui failed"
+
+msgid "E819: Blowfish test failed"
+msgstr "E819: Blowfish-testi epäonnistui"
+
+msgid "[Location List]"
+msgstr "[Sijaintiluettelo]"
+
+msgid "[Quickfix List]"
+msgstr "[Pikakorjausluettelo]"
+
+msgid "E855: Autocommands caused command to abort"
+msgstr "E855: Autocommands lopetti komennon"
+
+msgid "E82: Cannot allocate any buffer, exiting..."
+msgstr "E82: Mitään puskuria ei voitu varata, lopetetaan..."
+
+msgid "E83: Cannot allocate buffer, using other one..."
+msgstr "E83: Puskuria ei voitu varata, käytetään toista..."
+
+msgid "E931: Buffer cannot be registered"
+msgstr "E931: Puskuria ei voi rekisteröidä"
+
+msgid "E937: Attempt to delete a buffer that is in use"
+msgstr "E937: Ei voida poistaa puskuria joka on käytössä"
+
+msgid "E515: No buffers were unloaded"
+msgstr "E515: Puskureita ei vapautettu"
+
+msgid "E516: No buffers were deleted"
+msgstr "E516: Puskureita ei poistettu"
+
+msgid "E517: No buffers were wiped out"
+msgstr "E517: Puskureita ei pyyhitty"
+
+msgid "1 buffer unloaded"
+msgstr "1 puskuri vapautettiin"
+
+#, c-format
+msgid "%d buffers unloaded"
+msgstr "%d puskuria vapautettiin"
+
+msgid "1 buffer deleted"
+msgstr "1 puskuri poistettu"
+
+#, c-format
+msgid "%d buffers deleted"
+msgstr "%d puskuria poistettu"
+
+msgid "1 buffer wiped out"
+msgstr "1 puskuri pyyhitty"
+
+#, c-format
+msgid "%d buffers wiped out"
+msgstr "%d puskuria pyyhitty"
+
+msgid "E90: Cannot unload last buffer"
+msgstr "E90: Ei voi vapauttaa viimeistä puskuria"
+
+msgid "E84: No modified buffer found"
+msgstr "E84: Ei muokattuja puskureita"
+
+msgid "E85: There is no listed buffer"
+msgstr "E85: Luetteloitua puskuria ei ole"
+
+msgid "E87: Cannot go beyond last buffer"
+msgstr "E87: Viimeisen puskurin ohi ei voi edetä"
+
+msgid "E88: Cannot go before first buffer"
+msgstr "E88: Ensimmäisen puskurin ohi ei voi edetä"
+
+#, c-format
+msgid "E89: No write since last change for buffer %ld (add ! to override)"
+msgstr ""
+"E89: Puskurin %ld muutoksia ei ole tallennettu (lisää komentoon ! "
+"ohittaaksesi)"
+
+msgid "E948: Job still running (add ! to end the job)"
+msgstr "E948: Komento on kesken (lisää loppuun ! lopettaaksesi komennon)"
+
+msgid "E37: No write since last change (add ! to override)"
+msgstr ""
+"E37: Viimeisen muutoksen jälkeen ei ole kirjoitettu (lisää ! ohittaaksesi)"
+
+msgid "E948: Job still running"
+msgstr "E948: Komento on vielä käynnissä"
+
+msgid "E37: No write since last change"
+msgstr "E37: Viimeisimmän muutoksen jälkeen ei ole kirjoitettu mitään"
+
+msgid "W14: Warning: List of file names overflow"
+msgstr "W14: Varoitus: Tiedostonimiluettelon ylivuoto"
+
+#, c-format
+msgid "E92: Buffer %ld not found"
+msgstr "E92: Puskuria %ld ei löydy"
+
+#, c-format
+msgid "E93: More than one match for %s"
+msgstr "E93: %s täsmää useampaan kuin yhteen puskuriin"
+
+#, c-format
+msgid "E94: No matching buffer for %s"
+msgstr "E94: %s ei täsmää yhteenkään puskuriin"
+
+#, c-format
+msgid "line %ld"
+msgstr "rivi %ld"
+
+msgid "E95: Buffer with this name already exists"
+msgstr "E95: Samanniminen puskuri on jo olemassa"
+
+msgid " [Modified]"
+msgstr " [Muokattu]"
+
+msgid "[Not edited]"
+msgstr "[Muokkaamaton]"
+
+msgid "[New file]"
+msgstr "[Uusi tiedosto]"
+
+msgid "[Read errors]"
+msgstr "[Lukuvirheitä]"
+
+msgid "[RO]"
+msgstr "[Luku]"
+
+msgid "[readonly]"
+msgstr "[kirjoitussuojattu]"
+
+#, c-format
+msgid "1 line --%d%%--"
+msgstr "1 rivi --%d %%--"
+
+#, c-format
+msgid "%ld lines --%d%%--"
+msgstr "%ld riviä --%d %%--"
+
+#, c-format
+msgid "line %ld of %ld --%d%%-- col "
+msgstr "rivi %ld/%ld --%d %%-- sarake "
+
+msgid "[No Name]"
+msgstr "[Nimetön]"
+
+msgid "help"
+msgstr "ohje"
+
+msgid "[Help]"
+msgstr "[Ohje]"
+
+msgid "[Preview]"
+msgstr "[Esikatselu]"
+
+# sijainti tiedostossa -indikaattoreja:
+# 4 merkkiä sais riittää
+msgid "All"
+msgstr "Kaik"
+
+msgid "Bot"
+msgstr "Loppu"
+
+msgid "Top"
+msgstr "Alku"
+
+msgid ""
+"\n"
+"# Buffer list:\n"
+msgstr ""
+"\n"
+"# Puskuriluettelo:\n"
+
+msgid "E382: Cannot write, 'buftype' option is set"
+msgstr "E382: Ei voi kirjoittaa, buftype asetettu"
+
+msgid "[Scratch]"
+msgstr "[Raapust]"
+
+msgid ""
+"\n"
+"--- Signs ---"
+msgstr ""
+"\n"
+"--- Merkit ---"
+
+#, c-format
+msgid "Signs for %s:"
+msgstr "Merkit kohteelle %s:"
+
+#, c-format
+msgid " line=%ld id=%d name=%s"
+msgstr " rivi=%ld id=%d nimi=%s"
+
+msgid "E902: Cannot connect to port"
+msgstr "E902: Ei voi yhdistää porttiin"
+
+msgid "E901: gethostbyname() in channel_open()"
+msgstr "E901: gethostbyname() funktiossa channel_open()"
+
+msgid "E898: socket() in channel_open()"
+msgstr "E898: socket() funktiossa channel_open()"
+
+msgid "E903: received command with non-string argument"
+msgstr "E903: komennolla ei-merkkijonoargumentti"
+
+msgid "E904: last argument for expr/call must be a number"
+msgstr "E904: viimeisen expr/call-argumentin pitää olla numero"
+
+msgid "E904: third argument for call must be a list"
+msgstr "E904: kolmannen argumentin pitää olla lista"
+
+#, c-format
+msgid "E905: received unknown command: %s"
+msgstr "E905: tuntematon komento: %s"
+
+#, c-format
+msgid "E630: %s(): write while not connected"
+msgstr "E630: %s(): ei voi kirjoittaa ilman yhteyttä"
+
+#, c-format
+msgid "E631: %s(): write failed"
+msgstr "E631: %s(): kirjoitus epäonnistui"
+
+#, c-format
+msgid "E917: Cannot use a callback with %s()"
+msgstr "E917: Ei voitu käyttää callbackia %s()"
+
+msgid "E912: cannot use ch_evalexpr()/ch_sendexpr() with a raw or nl channel"
+msgstr ""
+"E912: ei voida käyttää funktioita ch_evalexpr(), ch_sendexpr() raa'an tai nl-"
+"kanavan kanssa"
+
+msgid "E906: not an open channel"
+msgstr "E906: ei ole avoin kanava"
+
+msgid "E920: _io file requires _name to be set"
+msgstr "E920: _io-tiedostolla pitää olla _name asetettu"
+
+msgid "E915: in_io buffer requires in_buf or in_name to be set"
+msgstr "E915: in_io-puskurilla pitää olla in_buf tai in_name asetettu"
+
+#, c-format
+msgid "E918: buffer must be loaded: %s"
+msgstr "E918: puskuria ei voi ladata: %s"
+
+msgid "E821: File is encrypted with unknown method"
+msgstr "E821: Tiedoston salaus on tuntematon"
+
+msgid "Warning: Using a weak encryption method; see :help 'cm'"
+msgstr "Varoitus: Käytetään heikkoa salausmenetelmää, ks. :help 'cm'"
+
+msgid "Enter encryption key: "
+msgstr "Anna salausavain: "
+
+msgid "Enter same key again: "
+msgstr "Anna sama avain uudestaan: "
+
+msgid "Keys don't match!"
+msgstr "Avaimet eivät täsmää!"
+
+msgid "[crypted]"
+msgstr "[salattu]"
+
+#, c-format
+msgid "E720: Missing colon in Dictionary: %s"
+msgstr "E720: Sanakirjasta puuttuu kaksoispiste: %s"
+
+#, c-format
+msgid "E721: Duplicate key in Dictionary: \"%s\""
+msgstr "E721: Kaksi samaa avainta sanakirjassa: %s"
+
+#, c-format
+msgid "E722: Missing comma in Dictionary: %s"
+msgstr "E722: Sanakirjasta puuttuu pilkku: %s"
+
+#, c-format
+msgid "E723: Missing end of Dictionary '}': %s"
+msgstr "E723: Sanakirjan lopusta puuttuu }: %s"
+
+msgid "extend() argument"
+msgstr "extend()-argumentti"
+
+#, c-format
+msgid "E737: Key already exists: %s"
+msgstr "E737: Avain on jo olemassa: %s"
+
+#, c-format
+msgid "E96: Cannot diff more than %ld buffers"
+msgstr "E96: Ei voi diffata enempää kuin %ld puskuria"
+
+msgid "E810: Cannot read or write temp files"
+msgstr "E810: Ei voi lukea tai kirjoittaa väliaikaistiedostoja"
+
+msgid "E97: Cannot create diffs"
+msgstr "E97: Ei voi luoda diffejä"
+
+msgid "Patch file"
+msgstr "Patch-tiedosto"
+
+msgid "E816: Cannot read patch output"
+msgstr "E816: Ei voi lukea patchin tulostetta"
+
+msgid "E98: Cannot read diff output"
+msgstr "E98: Ei voi lukea diffin tulostetta"
+
+msgid "E99: Current buffer is not in diff mode"
+msgstr "E99: Tämä puskuri ei ole diff-tilassa"
+
+msgid "E793: No other buffer in diff mode is modifiable"
+msgstr "E793: Yksikään muu diff-tilan puskurit ei ole muokattavissa"
+
+msgid "E100: No other buffer in diff mode"
+msgstr "E100: Yksikään muu puskuri ei ole diff-tilassa"
+
+msgid "E101: More than two buffers in diff mode, don't know which one to use"
+msgstr "E101: Monta puskuria on diff-tilassa, käytettävän valinta ei onnistu"
+
+#, c-format
+msgid "E102: Can't find buffer \"%s\""
+msgstr "E102: Puskuria %s ei löydy"
+
+#, c-format
+msgid "E103: Buffer \"%s\" is not in diff mode"
+msgstr "E103: Puskuri %s ei ole diff-tilassa"
+
+msgid "E787: Buffer changed unexpectedly"
+msgstr "E787: Puskuri vaihtui odottamatta"
+
+msgid "E104: Escape not allowed in digraph"
+msgstr "E104: Escapea ei voi käyttää digraafissa"
+
+msgid "E544: Keymap file not found"
+msgstr "E544: Näppäinkarttaa ei löydy"
+
+msgid "E105: Using :loadkeymap not in a sourced file"
+msgstr "E105: Käytetään :loadkeymapia ladatun tiedoston ulkopuolella"
+
+msgid "E791: Empty keymap entry"
+msgstr "E791: Tyhjä keymap-kenttä"
+
+msgid " Keyword completion (^N^P)"
+msgstr " Avainsanatäydennys (^N^P)"
+
+msgid " ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+msgstr " ^X-tila (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+
+msgid " Whole line completion (^L^N^P)"
+msgstr " Täysrivitäydennys (^L^N^P)"
+
+msgid " File name completion (^F^N^P)"
+msgstr " Tiedostonimitäydennys (^F^N^P)"
+
+msgid " Tag completion (^]^N^P)"
+msgstr " Tägitäydennys (^]^N^P)"
+
+msgid " Path pattern completion (^N^P)"
+msgstr " Polkukuviotäydennys (^N^P)"
+
+msgid " Definition completion (^D^N^P)"
+msgstr " Määritelmätäydennys (^D^N^P)"
+
+msgid " Dictionary completion (^K^N^P)"
+msgstr " Sanakirjatäydennys (^K^N^P)"
+
+msgid " Thesaurus completion (^T^N^P)"
+msgstr " Thesaurus-täydennys (^T^N^P)"
+
+msgid " Command-line completion (^V^N^P)"
+msgstr " Komentorivitäydennys (^V^N^P)"
+
+msgid " User defined completion (^U^N^P)"
+msgstr " Käyttäjän määrittelemä täydennys (^U^N^P)"
+
+msgid " Omni completion (^O^N^P)"
+msgstr " Omnitäydennys (^O^N^P)"
+
+msgid " Spelling suggestion (s^N^P)"
+msgstr " Oikaisulukuehdotus (s^N^P)"
+
+msgid " Keyword Local completion (^N^P)"
+msgstr " Avainsanan paikallinen täydennys (^N^P)"
+
+msgid "Hit end of paragraph"
+msgstr "Kappaleen loppu tuli vastaan"
+
+msgid "E839: Completion function changed window"
+msgstr "E839: Täydennys vaihtoi ikkunaa"
+
+msgid "E840: Completion function deleted text"
+msgstr "E840: Täydennys poisti tekstiä"
+
+msgid "'dictionary' option is empty"
+msgstr "dictionary-asetus on tyhjä"
+
+msgid "'thesaurus' option is empty"
+msgstr "thesaurus-asetus on tyhjä"
+
+#, c-format
+msgid "Scanning dictionary: %s"
+msgstr "Luetaan sanakirjaa: %s"
+
+msgid " (insert) Scroll (^E/^Y)"
+msgstr " (syöttö) Vieritys (^E/^Y)"
+
+msgid " (replace) Scroll (^E/^Y)"
+msgstr " (korvaus) Vieritys (^E/^Y)"
+
+#, c-format
+msgid "Scanning: %s"
+msgstr "Luetaan: %s"
+
+msgid "Scanning tags."
+msgstr "Luetaan tägejä."
+
+msgid "match in file"
+msgstr "täsmäys tiedostossa"
+
+msgid " Adding"
+msgstr " Lisätään"
+
+msgid "-- Searching..."
+msgstr "-- Haetaan..."
+
+msgid "Back at original"
+msgstr "Takaisin lähtöpisteessä"
+
+msgid "Word from other line"
+msgstr "Sana toisella rivillä"
+
+msgid "The only match"
+msgstr "Ainoa täsmäys"
+
+#, c-format
+msgid "match %d of %d"
+msgstr "täsmäys %d/%d"
+
+#, c-format
+msgid "match %d"
+msgstr "täsmäys %d"
+
+msgid "E18: Unexpected characters in :let"
+msgstr "E18: Odottamattomia merkkejä komennossa :let"
+
+#, c-format
+msgid "E121: Undefined variable: %s"
+msgstr "E121: Määrittelemätön muuttuja: %s"
+
+msgid "E111: Missing ']'"
+msgstr "E111: ] puuttuu"
+
+msgid "E719: Cannot use [:] with a Dictionary"
+msgstr "E719: Sanakirjassa ei voi käyttää merkintää [:]"
+
+#, c-format
+msgid "E734: Wrong variable type for %s="
+msgstr "E734: Väärä muuttujatyyppi muuttujalle %s="
+
+#, c-format
+msgid "E461: Illegal variable name: %s"
+msgstr "E461: Virheellinen muuttujanimi: %s"
+
+msgid "E806: using Float as a String"
+msgstr "E806: Float ei käy merkkijonosta"
+
+msgid "E687: Less targets than List items"
+msgstr "E687: Kohteita on vähemmän kuin listan alkioita"
+
+msgid "E688: More targets than List items"
+msgstr "E688: Kohteita on enemmän kuin listan alkioita"
+
+msgid "Double ; in list of variables"
+msgstr "Kaksi ;:ttä listan muuttujissa"
+
+#, c-format
+msgid "E738: Can't list variables for %s"
+msgstr "E738: Kohteen %s muuttujia ei voi listata"
+
+msgid "E689: Can only index a List or Dictionary"
+msgstr "E689: Vain listalla ja sanakirjalla voi olla indeksejä"
+
+msgid "E708: [:] must come last"
+msgstr "E708: [:]:n pitää olla viimeisenä"
+
+msgid "E709: [:] requires a List value"
+msgstr "E709: [:] toimii vain listalla"
+
+msgid "E710: List value has more items than target"
+msgstr "E710: Listalla on enemmän alkioita kuin kohteella"
+
+msgid "E711: List value has not enough items"
+msgstr "E711: Listalla ei ole tarpeeksi alkioita"
+
+msgid "E690: Missing \"in\" after :for"
+msgstr "E690: :for-kommenolta puuttuu in"
+
+#, c-format
+msgid "E108: No such variable: \"%s\""
+msgstr "E108: Muuttujaa %s ei ole"
+
+#, c-format
+msgid "E940: Cannot lock or unlock variable %s"
+msgstr "E940: Muuttujaa %s ei voi lukita tai avata"
+
+msgid "E743: variable nested too deep for (un)lock"
+msgstr "E743: muuttujassa liian monta tasoa lukituksen käsittelyyn"
+
+msgid "E109: Missing ':' after '?'"
+msgstr "E109: ?:n jälkeen puuttuu :"
+
+msgid "E691: Can only compare List with List"
+msgstr "E691: Listaa voi verrata vain listaan"
+
+msgid "E692: Invalid operation for List"
+msgstr "E692: Virheellinen toiminto listalle"
+
+msgid "E735: Can only compare Dictionary with Dictionary"
+msgstr "E735: Sanakirjaa voi verrata vain sanakirjaan"
+
+msgid "E736: Invalid operation for Dictionary"
+msgstr "E736: Virheellinen toiminto sanakirjalle"
+
+msgid "E694: Invalid operation for Funcrefs"
+msgstr "E694: Virheellinen toiminto funcrefille"
+
+msgid "E804: Cannot use '%' with Float"
+msgstr "E804: Ei voi käyttää '%':a Floatin kanssa"
+
+msgid "E110: Missing ')'"
+msgstr "E110: ) puuttuu"
+
+msgid "E695: Cannot index a Funcref"
+msgstr "E695: Funcrefiä ei voi indeksoida"
+
+msgid "E909: Cannot index a special variable"
+msgstr "E909: erikoismuuttujaa ei voi indeksoida"
+
+#, c-format
+msgid "E112: Option name missing: %s"
+msgstr "E112: Asetuksen nimi puuttuu: %s"
+
+#, c-format
+msgid "E113: Unknown option: %s"
+msgstr "E113: Tuntematon asetus: %s"
+
+#, c-format
+msgid "E114: Missing quote: %s"
+msgstr "E114: Puuttuva lainausmerkki: %s"
+
+#, c-format
+msgid "E115: Missing quote: %s"
+msgstr "E115: Puuttuva lainausmerkki: %s"
+
+msgid "Not enough memory to set references, garbage collection aborted!"
+msgstr ""
+"Ei tarpeeksi muistia viitteiden asettamista varten, roskiekeruu peruttiin."
+
+msgid "E724: variable nested too deep for displaying"
+msgstr "E724: muuttuja on upotettu liian syvälle näytettäväksi"
+
+msgid "E805: Using a Float as a Number"
+msgstr "E805: Float ei käy Numberista"
+
+msgid "E703: Using a Funcref as a Number"
+msgstr "E703: Funcref ei käy Numberista"
+
+msgid "E745: Using a List as a Number"
+msgstr "E745: Lista ei käy Numberista"
+
+msgid "E728: Using a Dictionary as a Number"
+msgstr "E728: Sanakirja ei käy Numberista"
+
+msgid "E910: Using a Job as a Number"
+msgstr "E910: Job ei käy Numberista"
+
+msgid "E913: Using a Channel as a Number"
+msgstr "E913: Channel ei käy Numberista"
+
+msgid "E891: Using a Funcref as a Float"
+msgstr "E891: Funcref ei käy Floatista"
+
+msgid "E892: Using a String as a Float"
+msgstr "E892: String ei käy Floatista"
+
+msgid "E893: Using a List as a Float"
+msgstr "E893: Lista ei käy Floatista"
+
+msgid "E894: Using a Dictionary as a Float"
+msgstr "E894: Sanakirja ei käy Floatista"
+
+msgid "E907: Using a special value as a Float"
+msgstr "E907: Käytettiin erikoisarvoa Floattina"
+
+msgid "E911: Using a Job as a Float"
+msgstr "E911: Job ei käy Floatista"
+
+msgid "E914: Using a Channel as a Float"
+msgstr "E914: Käytettiin Channelia Floattina"
+
+msgid "E729: using Funcref as a String"
+msgstr "E729: Funcref ei käy merkkijonosta"
+
+msgid "E730: using List as a String"
+msgstr "E730: Lista ei käy merkkijonosta"
+
+msgid "E731: using Dictionary as a String"
+msgstr "E731: Sanakirja ei käy merkkijonosta"
+
+msgid "E908: using an invalid value as a String"
+msgstr "E908: huono arvo merkkijonolle"
+
+#, c-format
+msgid "E795: Cannot delete variable %s"
+msgstr "E795: Muuttujaa %s ei voi poistaa"
+
+#, c-format
+msgid "E704: Funcref variable name must start with a capital: %s"
+msgstr "E704: Funcrefin muuttujanimen pitää alkaa suuraakkosella: %s"
+
+#, c-format
+msgid "E705: Variable name conflicts with existing function: %s"
+msgstr "E705: Muuttujanimi on sama kuin olemassaolevan funktion: %s"
+
+#, c-format
+msgid "E741: Value is locked: %s"
+msgstr "E741: Arvo on lukittu: %s"
+
+msgid "Unknown"
+msgstr "Tuntematon"
+
+#, c-format
+msgid "E742: Cannot change value of %s"
+msgstr "E742: Ei voi muuttaa muuttujan %s arvoa"
+
+msgid "E698: variable nested too deep for making a copy"
+msgstr "E698: muuttuja on upotettu liian syvälle kopioitavaksi"
+
+msgid ""
+"\n"
+"# global variables:\n"
+msgstr ""
+"\n"
+"# globaalit muuttujat:\n"
+
+msgid ""
+"\n"
+"\tLast set from "
+msgstr ""
+"\n"
+"\tViimeksi asetettu kohteesta "
+
+msgid "map() argument"
+msgstr "map()-argumentti"
+
+msgid "filter() argument"
+msgstr "filter()-argumentti"
+
+#, c-format
+msgid "E686: Argument of %s must be a List"
+msgstr "E686: Argumentin %s pitää olla lista"
+
+msgid "E928: String required"
+msgstr "E928: Merkkijono puuttuu"
+
+msgid "E808: Number or Float required"
+msgstr "E808: Number tai Float vaaditaan"
+
+msgid "add() argument"
+msgstr "add()-argumentti"
+
+msgid "E785: complete() can only be used in Insert mode"
+msgstr "E785: complete() toimii vain syöttötilassa"
+
+msgid "&Ok"
+msgstr "&Ok"
+
+#, c-format
+msgid "E700: Unknown function: %s"
+msgstr "E700: Tuntematon funktio: %s"
+
+msgid "E922: expected a dict"
+msgstr "E922: odotettiin dictiä"
+
+# datarakenteita
+msgid "E923: Second argument of function() must be a list or a dict"
+msgstr "E923: toisen function()-argumentin pitää olla lista tai sanakirja"
+
+msgid ""
+"&OK\n"
+"&Cancel"
+msgstr ""
+"&OK\n"
+"&Peru"
+
+msgid "called inputrestore() more often than inputsave()"
+msgstr "inputrestore() suoritettu useammin kuin inputsave()"
+
+msgid "insert() argument"
+msgstr "insert()-argumentti"
+
+msgid "E786: Range not allowed"
+msgstr "E786: Aluetta ei voi käyttää"
+
+msgid "E916: not a valid job"
+msgstr "E916: ei ole job"
+
+msgid "E701: Invalid type for len()"
+msgstr "E701: Virheellinen tyyppi funktiolle len()"
+
+#, c-format
+msgid "E798: ID is reserved for \":match\": %ld"
+msgstr "E798: ID on varattu kohteelle \":match\": %ld"
+
+msgid "E726: Stride is zero"
+msgstr "E726: Stride on nolla"
+
+msgid "E727: Start past end"
+msgstr "E727: Alku on lopun jälkeen"
+
+msgid "<empty>"
+msgstr "<tyhjä>"
+
+msgid "E240: No connection to the X server"
+msgstr "E240: Ei yhteyttä X-palvelimeen"
+
+#, c-format
+msgid "E241: Unable to send to %s"
+msgstr "E241: Kohteeseen %s lähettäminen ei onnistunut"
+
+msgid "E277: Unable to read a server reply"
+msgstr "E277: Palvelimen vastauksen lukeminen ei onnistunut"
+
+msgid "E941: already started a server"
+msgstr "E941: palvelin on jo käynnissä"
+
+msgid "E942: +clientserver feature not available"
+msgstr "E942: +clientserver-toiminto ei ole saatavilla"
+
+msgid "remove() argument"
+msgstr "remove()-argumentti"
+
+msgid "E655: Too many symbolic links (cycle?)"
+msgstr "E655: Liikaa symbolisia linkkejä (mahdollinen sykli)"
+
+msgid "reverse() argument"
+msgstr "reverse()-argumentti"
+
+msgid "E258: Unable to send to client"
+msgstr "E258: Asiakkaalle lähetys ei onnistunut"
+
+#, c-format
+msgid "E927: Invalid action: '%s'"
+msgstr "E927: Viallinen toiminto: %s"
+
+msgid "sort() argument"
+msgstr "sort()-argumentti"
+
+msgid "uniq() argument"
+msgstr "uniq()-argumentti"
+
+msgid "E702: Sort compare function failed"
+msgstr "E702: Lajittelun vertausfunktio ei onnistunut"
+
+msgid "E882: Uniq compare function failed"
+msgstr "E882: Uniqin vertausfunktio ei onnistunut"
+
+msgid "(Invalid)"
+msgstr "(Virheellinen)"
+
+#, c-format
+msgid "E935: invalid submatch number: %d"
+msgstr "E935: Virheellinen alitäsmäyksen numero: %d"
+
+msgid "E677: Error writing temp file"
+msgstr "E677: Väliaikaistiedostoon kirjoittaminen ei onnistunut"
+
+msgid "E921: Invalid callback argument"
+msgstr "E921: Virheellinen callback-argumentti"
+
+msgid "Entering Debug mode. Type \"cont\" to continue."
+msgstr "Siirrytään vianetsintätilaan, kirjoita cont jatkaaksesi."
+
+#, c-format
+msgid "line %ld: %s"
+msgstr "rivi %ld: %s"
+
+#, c-format
+msgid "cmd: %s"
+msgstr "kmnt: %s"
+
+msgid "frame is zero"
+msgstr "kehys on nolla"
+
+#, c-format
+msgid "frame at highest level: %d"
+msgstr "kehys ylimmällä tasolla: %d"
+
+#, c-format
+msgid "Breakpoint in \"%s%s\" line %ld"
+msgstr "Katkaisukohta %s%s rivillä %ld"
+
+#, c-format
+msgid "E161: Breakpoint not found: %s"
+msgstr "E161: Katkaisukohta puuttuu: %s"
+
+msgid "No breakpoints defined"
+msgstr "Ei katkaisukohtia"
+
+#, c-format
+msgid "%3d %s %s line %ld"
+msgstr "%3d %s %s rivi %ld"
+
+msgid "E750: First use \":profile start {fname}\""
+msgstr "E750: Aloita käskyllä :profile start {fname}"
+
+msgid "Save As"
+msgstr "Tallenna nimellä"
+
+#, c-format
+msgid "Save changes to \"%s\"?"
+msgstr "Tallennetaanko muutokset tiedostoon %s?"
+
+#, c-format
+msgid "E947: Job still running in buffer \"%s\""
+msgstr "E947: Komento on vielä käynnissä puskurissa \"%s\""
+
+#, c-format
+msgid "E162: No write since last change for buffer \"%s\""
+msgstr "E162: Muutoksia ei ole kirjoitettu puskurin %s viime muutoksen jälkeen"
+
+msgid "Warning: Entered other buffer unexpectedly (check autocommands)"
+msgstr "Varoitus: Puskuri vaihtui odottamatta (tarkista autocommands)"
+
+msgid "E163: There is only one file to edit"
+msgstr "E163: Vain yksi tiedosto muokattavana"
+
+msgid "E164: Cannot go before first file"
+msgstr "E164: Ensimmäisen tiedoston ohi ei voi mennä"
+
+msgid "E165: Cannot go beyond last file"
+msgstr "E165: Viimeisen tiedoston ohi ei voi mennä"
+
+#, c-format
+msgid "E666: compiler not supported: %s"
+msgstr "E666: kääntäjää ei tueta: %s"
+
+#, c-format
+msgid "Searching for \"%s\" in \"%s\""
+msgstr "Etsitään ilmausta %s kohteesta %s"
+
+#, c-format
+msgid "Searching for \"%s\""
+msgstr "Etsitään ilmausta %s"
+
+#, c-format
+msgid "not found in '%s': \"%s\""
+msgstr "'%s' ei löydy kohteesta: %s"
+
+#, c-format
+msgid "W20: Required python version 2.x not supported, ignoring file: %s"
+msgstr "W20: Vaadittu python-versio 2.x ei ole tuettu. Ohitetaan: %s"
+
+#, c-format
+msgid "W21: Required python version 3.x not supported, ignoring file: %s"
+msgstr "W21: Vaadittu python-versio 3.x ei ole tuettu. Ohitetaan: %s"
+
+msgid "Source Vim script"
+msgstr "Lataa vim-skripti"
+
+#, c-format
+msgid "Cannot source a directory: \"%s\""
+msgstr "Hakemistoa ei voi ladata: %s"
+
+#, c-format
+msgid "could not source \"%s\""
+msgstr "ei voitu ladata %s"
+
+#, c-format
+msgid "line %ld: could not source \"%s\""
+msgstr "rivi %ld: ei voitu ladata %s"
+
+#, c-format
+msgid "sourcing \"%s\""
+msgstr "ladataan %s"
+
+#, c-format
+msgid "line %ld: sourcing \"%s\""
+msgstr "rivi %ld: ladataan %s"
+
+#, c-format
+msgid "finished sourcing %s"
+msgstr "ladattu %s"
+
+#, c-format
+msgid "continuing in %s"
+msgstr "jatkaa kohdassa %s"
+
+msgid "modeline"
+msgstr "mode-rivi"
+
+msgid "--cmd argument"
+msgstr "--cmd-argumentti"
+
+msgid "-c argument"
+msgstr "-c-argumentti"
+
+msgid "environment variable"
+msgstr "ympäristömuuttuja"
+
+msgid "error handler"
+msgstr "virhekäsittelin"
+
+msgid "W15: Warning: Wrong line separator, ^M may be missing"
+msgstr "W15: Varoitus: Väärä rivierotin, ^M saattaa puuttua"
+
+msgid "E167: :scriptencoding used outside of a sourced file"
+msgstr "E167: :scriptencoding ladatun tiedoston ulkopuolella"
+
+msgid "E168: :finish used outside of a sourced file"
+msgstr "E168: :finish ladatun tiedoston ulkopuolella"
+
+#, c-format
+msgid "Current %slanguage: \"%s\""
+msgstr "Käytössä oleva %skieli: %s"
+
+#, c-format
+msgid "E197: Cannot set language to \"%s\""
+msgstr "E197: Kieleksi ei voitu asettaa kieltä %s"
+
+# puhutaan merkin ulkoasusta snprintf(..., c, c, c, c)
+#, c-format
+msgid "<%s>%s%s %d, Hex %02x, Octal %03o"
+msgstr "<%s>%s%s %d, heksana %02x, oktaalina %03o"
+
+#, c-format
+msgid "> %d, Hex %04x, Octal %o"
+msgstr "> %d, heksana %04x, oktaalina %o"
+
+#, c-format
+msgid "> %d, Hex %08x, Octal %o"
+msgstr "> %d, hekdana %08x, oktaalina %o"
+
+msgid "E134: Move lines into themselves"
+msgstr "E134: Rivien siirto itsejensä päälle"
+
+msgid "1 line moved"
+msgstr "1 rivi siirretty"
+
+#, c-format
+msgid "%ld lines moved"
+msgstr "%ld riviä siirretty"
+
+#, c-format
+msgid "%ld lines filtered"
+msgstr "%ld riviä suodatettu"
+
+msgid "E135: *Filter* Autocommands must not change current buffer"
+msgstr "E135: *Filter*-autocommand ei voi vaihtaa puskuria"
+
+msgid "[No write since last change]\n"
+msgstr "[Viimeisintä muutosta ei ole kirjoitettu]\n"
+
+#, c-format
+msgid "%sviminfo: %s in line: "
+msgstr "%sviminfo: %s rivillä: "
+
+msgid "E136: viminfo: Too many errors, skipping rest of file"
+msgstr "E136: viminfo: liikaa virheitä, ohitetaan lopputiedosto"
+
+#, c-format
+msgid "Reading viminfo file \"%s\"%s%s%s"
+msgstr "Luetaan viminfo-tiedostoa \"%s\"%s%s%s"
+
+msgid " info"
+msgstr " info"
+
+msgid " marks"
+msgstr " merkit"
+
+msgid " oldfiles"
+msgstr " vanhaatiedostoa"
+
+msgid " FAILED"
+msgstr " EPÄONNISTUI"
+
+#, c-format
+msgid "E137: Viminfo file is not writable: %s"
+msgstr "E137: Viminfo-tiedostoon ei voitu kirjoittaa: %s"
+
+#, c-format
+msgid "E929: Too many viminfo temp files, like %s!"
+msgstr "E929: liikaa viminfo-väliaikaistiedostoja, kuten %s."
+
+#, c-format
+msgid "E138: Can't write viminfo file %s!"
+msgstr "E138: Viminfo-tiedoston kirjoittaminen ei onnistu %s"
+
+#, c-format
+msgid "Writing viminfo file \"%s\""
+msgstr "Kirjoitetaan viminfo-tiedostoa %s"
+
+#, c-format
+msgid "E886: Can't rename viminfo file to %s!"
+msgstr "E886: Viminfo-tiedostoa ei voit uudelleennimetä nimelle %s"
+
+#, c-format
+msgid "# This viminfo file was generated by Vim %s.\n"
+msgstr "# Vimin %s generoima viminfo-tiedosto.\n"
+
+msgid ""
+"# You may edit it if you're careful!\n"
+"\n"
+msgstr ""
+"# Muokkaa varovasti!\n"
+"\n"
+
+msgid "# Value of 'encoding' when this file was written\n"
+msgstr "# encoding-muuttujan arvo tiedostoa kirjoitettaessa\n"
+
+msgid "Illegal starting char"
+msgstr "Virheellinen aloitusmerkki"
+
+msgid ""
+"\n"
+"# Bar lines, copied verbatim:\n"
+msgstr ""
+"\n"
+"# Bar-rivit, kopiotu sellaisenaan:\n"
+
+msgid "Write partial file?"
+msgstr "Kirjoita osittainen tiedosto"
+
+msgid "E140: Use ! to write partial buffer"
+msgstr "E140: Käytä !-komentoa osittaisen puskurin kirjoittamiseen"
+
+#, c-format
+msgid "Overwrite existing file \"%s\"?"
+msgstr "Ylikirjoitetaanko olemassaoleva tiedosto %s?"
+
+#, c-format
+msgid "Swap file \"%s\" exists, overwrite anyway?"
+msgstr "Swap-tiedosto %s on olemassa, ylikirjoitetaanko?"
+
+#, c-format
+msgid "E768: Swap file exists: %s (:silent! overrides)"
+msgstr "E768: Swap-tiedosto on jo olemassa: %s (komento :silent! ohittaa)"
+
+#, c-format
+msgid "E141: No file name for buffer %ld"
+msgstr "E141: Ei tiedostonimeä puskurille %ld"
+
+msgid "E142: File not written: Writing is disabled by 'write' option"
+msgstr ""
+"E142: Tiedostoa ei kirjoitettu; write-asetus poistaa kirjoituksen käytöstä"
+
+#, c-format
+msgid ""
+"'readonly' option is set for \"%s\".\n"
+"Do you wish to write anyway?"
+msgstr ""
+"readonly asetettu tiedostolle \"%s\".\n"
+"Kirjoitetaanko?"
+
+#, c-format
+msgid ""
+"File permissions of \"%s\" are read-only.\n"
+"It may still be possible to write it.\n"
+"Do you wish to try?"
+msgstr ""
+"Tiedosto %s on kirjoitussuojattu.\n"
+"Siihen saattaa voida silti kirjoittaa.\n"
+"Yritetäänkö?"
+
+#, c-format
+msgid "E505: \"%s\" is read-only (add ! to override)"
+msgstr "E505: %s on kirjoitussuojattu (lisää komentoon ! ohittaaksesi)"
+
+msgid "Edit File"
+msgstr "Muokkaa tiedostoa"
+
+#, c-format
+msgid "E143: Autocommands unexpectedly deleted new buffer %s"
+msgstr "E143: Autocommand poisti uuden puskurin odotuksen vastaisesti %s"
+
+msgid "E144: non-numeric argument to :z"
+msgstr "E144: :z:n argumentti ei ole numero"
+
+msgid "E145: Shell commands not allowed in rvim"
+msgstr "E145: Kuoren komennot eivät toimi rvimissä"
+
+msgid "E146: Regular expressions can't be delimited by letters"
+msgstr "E146: Säännöllistä ilmausta ei voi rajata kirjaimilla"
+
+#, c-format
+msgid "replace with %s (y/n/a/q/l/^E/^Y)?"
+msgstr "korvaa kohteella %s (y/n/a/q/l/^E/^Y)?"
+
+msgid "(Interrupted) "
+msgstr "(Keskeytetty)"
+
+msgid "1 match"
+msgstr "1 täsmäys"
+
+msgid "1 substitution"
+msgstr "1 korvaus"
+
+#, c-format
+msgid "%ld matches"
+msgstr "%ld täsmäystä"
+
+#, c-format
+msgid "%ld substitutions"
+msgstr "%ld korvausta"
+
+msgid " on 1 line"
+msgstr " 1 rivillä"
+
+#, c-format
+msgid " on %ld lines"
+msgstr " %ld rivillä"
+
+msgid "E147: Cannot do :global recursive with a range"
+msgstr "E147: :globalia ei voi suorittaa rekursiivisesti"
+
+msgid "E148: Regular expression missing from global"
+msgstr "E148: Säännöllinen ilmaus puuttuu globaalista"
+
+#, c-format
+msgid "Pattern found in every line: %s"
+msgstr "Kuvio löytyi joka riviltä: %s"
+
+#, c-format
+msgid "Pattern not found: %s"
+msgstr "Kuviota ei löydy: %s"
+
+msgid ""
+"\n"
+"# Last Substitute String:\n"
+"$"
+msgstr ""
+"\n"
+"# Viimeisin korvausmerkkijono:\n"
+"$"
+
+msgid "E478: Don't panic!"
+msgstr "E478: Älä panikoi."
+
+#, c-format
+msgid "E661: Sorry, no '%s' help for %s"
+msgstr "E661: ei löydy %s-ohjetta kohteelle %s"
+
+#, c-format
+msgid "E149: Sorry, no help for %s"
+msgstr "E149: ei löydy ohjetta kohteelle %s"
+
+#, c-format
+msgid "Sorry, help file \"%s\" not found"
+msgstr "ohjetiedostoa %s ei löydy"
+
+#, c-format
+msgid "E151: No match: %s"
+msgstr "E151: Ei täsmää: %s"
+
+#, c-format
+msgid "E152: Cannot open %s for writing"
+msgstr "E152: Ei voi avata tiedostoa %s kirjoittamista varten"
+
+#, c-format
+msgid "E153: Unable to open %s for reading"
+msgstr "E153: Ei voi avata tiedostoa %s lukemista varten"
+
+#, c-format
+msgid "E670: Mix of help file encodings within a language: %s"
+msgstr "E670: Monia ohjetiedostokoodauksia kielessä: %s"
+
+#, c-format
+msgid "E154: Duplicate tag \"%s\" in file %s/%s"
+msgstr "E154: Kaksoiskappale tägistä %s tiedostossa %s/%s"
+
+#, c-format
+msgid "E150: Not a directory: %s"
+msgstr "E150: Ei ole hakemisto: %s"
+
+#, c-format
+msgid "E160: Unknown sign command: %s"
+msgstr "E160: Tuntematon merkkikomento: %s"
+
+msgid "E156: Missing sign name"
+msgstr "E156: Merkki puuttuu"
+
+msgid "E612: Too many signs defined"
+msgstr "E612: Liikaa merkkejä määritelty"
+
+#, c-format
+msgid "E239: Invalid sign text: %s"
+msgstr "E239: Virheellinen merkkiteksti: %s"
+
+#, c-format
+msgid "E155: Unknown sign: %s"
+msgstr "E155: Tuntematon merkki: %s"
+
+msgid "E159: Missing sign number"
+msgstr "E159: Merkin numero puuttuu"
+
+#, c-format
+msgid "E158: Invalid buffer name: %s"
+msgstr "E158: Virheellinen puskurin nimi: %s"
+
+msgid "E934: Cannot jump to a buffer that does not have a name"
+msgstr "E934: Ei voida hypätä puskuriin jolla ei ole nimeä"
+
+#, c-format
+msgid "E157: Invalid sign ID: %ld"
+msgstr "E157: Virheellinen merkin tunnus: %ld"
+
+#, c-format
+msgid "E885: Not possible to change sign %s"
+msgstr "E885: Ei voida muuttaa merkkiä %s"
+
+msgid " (NOT FOUND)"
+msgstr " (EI LÖYTYNYT)"
+
+msgid " (not supported)"
+msgstr " (ei tuettu)"
+
+msgid "[Deleted]"
+msgstr "[Poistettu]"
+
+msgid "No old files"
+msgstr "Ei vanhoja tiedostoja"
+
+msgid "Entering Ex mode. Type \"visual\" to go to Normal mode."
+msgstr "Siirrytään Ex-tilaan, kirjoita visual palataksesi normaaliin tilaan."
+
+msgid "E501: At end-of-file"
+msgstr "E501: Tiedoston lopussa"
+
+msgid "E169: Command too recursive"
+msgstr "E169: Liian rekursiivinen komento"
+
+#, c-format
+msgid "E605: Exception not caught: %s"
+msgstr "E605: Kiinniottamaton poikkeus: %s"
+
+msgid "End of sourced file"
+msgstr "Ladatun tiedoston loppu"
+
+msgid "End of function"
+msgstr "Funktion loppu"
+
+msgid "E464: Ambiguous use of user-defined command"
+msgstr "E464: Käyttäjän määrittelemän komennon monimerkityksinen käyttö"
+
+msgid "E492: Not an editor command"
+msgstr "E492: Ei ole editorikomento"
+
+msgid "E493: Backwards range given"
+msgstr "E493: Takaperoinen arvoalue annettu"
+
+msgid "Backwards range given, OK to swap"
+msgstr "Takaperoinen arvoalue annettu, OK kääntää"
+
+msgid "E494: Use w or w>>"
+msgstr "E494: Käytä w:tä tai w>>:aa"
+
+msgid "E943: Command table needs to be updated, run 'make cmdidxs'"
+msgstr "E943: Komentotaulukko pitää päivittää komennolla 'make cmdidxs'"
+
+msgid "E319: Sorry, the command is not available in this version"
+msgstr "E319: Komento ei ole käytettävissä tässä versiossa"
+
+msgid "E172: Only one file name allowed"
+msgstr "E172: Vain yksi tiedostonimi sallitaan"
+
+msgid "1 more file to edit. Quit anyway?"
+msgstr "vielä 1 tiedosto muokattavana, lopetaanko silti?"
+
+#, c-format
+msgid "%d more files to edit. Quit anyway?"
+msgstr "vielä %d tiedostoa muokattavana, lopetetaanko silti?"
+
+msgid "E173: 1 more file to edit"
+msgstr "E173: vielä 1 tiedosto muokattavana"
+
+#, c-format
+msgid "E173: %ld more files to edit"
+msgstr "E173: vielä %ld tiedostoa muokattavana"
+
+msgid "E174: Command already exists: add ! to replace it"
+msgstr "E174: Komento on jo olemassa, käytä !:ä korvataksesi"
+
+msgid ""
+"\n"
+" Name Args Address Complete Definition"
+msgstr ""
+"\n"
+" Nimi Argumentit Osoite Valmis Määritelmä"
+
+msgid "No user-defined commands found"
+msgstr "Ei käyttäjän määrittelemiä komentoja"
+
+msgid "E175: No attribute specified"
+msgstr "E175: Ei attribuutteja määriteltynä"
+
+msgid "E176: Invalid number of arguments"
+msgstr "E176: Väärä määrä attribuutteja"
+
+msgid "E177: Count cannot be specified twice"
+msgstr "E177: Lukumäärää ei voi määritellä kahdesti"
+
+msgid "E178: Invalid default value for count"
+msgstr "E178: Lukumäärän oletusarvo on väärä"
+
+msgid "E179: argument required for -complete"
+msgstr "E179: -complete vaatii argumentin"
+
+msgid "E179: argument required for -addr"
+msgstr "E179: -addr vaatii argumentin"
+
+#, c-format
+msgid "E181: Invalid attribute: %s"
+msgstr "E181: Virheellinen attribuutti: %s"
+
+msgid "E182: Invalid command name"
+msgstr "E182: Virheellinen komennon nimi"
+
+msgid "E183: User defined commands must start with an uppercase letter"
+msgstr "E183: Käyttäjän määrittelemän komennon pitää alkaa suuraakkosella"
+
+msgid "E841: Reserved name, cannot be used for user defined command"
+msgstr "E841: Varattua nimeä ei voi käyttää käyttäjän määrittelemänä komentona"
+
+#, c-format
+msgid "E184: No such user-defined command: %s"
+msgstr "E184: Käyttäjän komentoa ei ole olemassa: %s"
+
+#, c-format
+msgid "E180: Invalid address type value: %s"
+msgstr "E180: Virheellinen osoitetyyppiarvo: %s"
+
+#, c-format
+msgid "E180: Invalid complete value: %s"
+msgstr "E180: Virheellinen täydennysarvo: %s"
+
+msgid "E468: Completion argument only allowed for custom completion"
+msgstr "E468: Täydennysargumentti sopii vain itse määriteltyyn täydennykseen"
+
+msgid "E467: Custom completion requires a function argument"
+msgstr "E467: Itse määritelty täydennys vaatii funktioargumentin"
+
+msgid "unknown"
+msgstr "tuntematon"
+
+#, c-format
+msgid "E185: Cannot find color scheme '%s'"
+msgstr "E185: Väriteemaa %s ei löydy"
+
+msgid "Greetings, Vim user!"
+msgstr "Tervehdys, Vimin käyttäjä."
+
+msgid "E784: Cannot close last tab page"
+msgstr "E784: Viimeistä välilehteä ei voi sulkea"
+
+msgid "Already only one tab page"
+msgstr "Vain yksi välilehti jäljellä enää"
+
+msgid "Edit File in new window"
+msgstr "Muokkaa uudessa ikkunassa"
+
+#, c-format
+msgid "Tab page %d"
+msgstr "Tabisivu %d"
+
+msgid "No swap file"
+msgstr "Ei swap-tiedostoa"
+
+msgid "Append File"
+msgstr "Lisää tiedostoon"
+
+msgid "E747: Cannot change directory, buffer is modified (add ! to override)"
+msgstr ""
+"E747: Hakemistoa ei voida muuttaa, puskuria on muokattu (lisää komentoon ! "
+"ohittaaksesi"
+
+msgid "E186: No previous directory"
+msgstr "E186: Ei edellistä hakemistoa"
+
+msgid "E187: Unknown"
+msgstr "E187: Tuntematon"
+
+msgid "E465: :winsize requires two number arguments"
+msgstr "E465: :winsize vaatii kaksi numeroargumenttia"
+
+#, c-format
+msgid "Window position: X %d, Y %d"
+msgstr "Ikkunan sijainti: X %d, Y %d"
+
+msgid "E188: Obtaining window position not implemented for this platform"
+msgstr "E188: Ikkunan sijainnin selvitys ei toimi tällä alustalla"
+
+msgid "E466: :winpos requires two number arguments"
+msgstr "E466: :winpos vaatii kaksi lukuargumenttia"
+
+msgid "E930: Cannot use :redir inside execute()"
+msgstr "E930: Komentoa :redir ei voi käyttää funktion execute() sisällä"
+
+msgid "Save Redirection"
+msgstr "Tallenna uudelleenosoitus"
+
+msgid "Save View"
+msgstr "Tallenna näkymä"
+
+msgid "Save Session"
+msgstr "Tallenna sessio"
+
+msgid "Save Setup"
+msgstr "Tallenna asetukset"
+
+#, c-format
+msgid "E739: Cannot create directory: %s"
+msgstr "E739: hakemistoa ei voi luoda: %s"
+
+#, c-format
+msgid "E189: \"%s\" exists (add ! to override)"
+msgstr "E189: %s on jo olemassa (lisää komentoon ! ohittaaksesi)"
+
+#, c-format
+msgid "E190: Cannot open \"%s\" for writing"
+msgstr "E190: Tiedostoa %s ei voitu avata kirjoittamista varten"
+
+msgid "E191: Argument must be a letter or forward/backward quote"
+msgstr "E191: Argumentin eteen- tai taaksepäin lainaukseen pitää olla kirjain"
+
+msgid "E192: Recursive use of :normal too deep"
+msgstr "E192: :normalin liian syvä rekursio"
+
+msgid "E809: #< is not available without the +eval feature"
+msgstr "E809: #< ei ole käytössä jollei +eval ole päällä"
+
+msgid "E194: No alternate file name to substitute for '#'"
+msgstr "E194: Ei vaihtoehtoista tiedostonimeä #:lle"
+
+msgid "E495: no autocommand file name to substitute for \"<afile>\""
+msgstr "E495: ei autocommand-tiedostoa kohteelle <afile>"
+
+msgid "E496: no autocommand buffer number to substitute for \"<abuf>\""
+msgstr "E496: ei autocommand-puskurinumeroa kohteelle <abuf>"
+
+msgid "E497: no autocommand match name to substitute for \"<amatch>\""
+msgstr "E497: ei autocommand-täsmäysnimeä kohteella <amatch>"
+
+msgid "E498: no :source file name to substitute for \"<sfile>\""
+msgstr "E498: ei :source-tiedostonimeä kohteelle <sfile>"
+
+msgid "E842: no line number to use for \"<slnum>\""
+msgstr "E842: ei rivinumeroa kohteelle <slnum>"
+
+#, no-c-format
+msgid "E499: Empty file name for '%' or '#', only works with \":p:h\""
+msgstr "E499: Tyhjä tiedostonimi kohteissa % tai # toimii vain :p:h"
+
+msgid "E500: Evaluates to an empty string"
+msgstr "E500: Loppuarvo on tyhjä merkkijono"
+
+msgid "E195: Cannot open viminfo file for reading"
+msgstr "E195: Viminfoa ei voi avata lukemista varten"
+
+msgid "Untitled"
+msgstr "Nimetön"
+
+msgid "E196: No digraphs in this version"
+msgstr "E196: Digraafeja ei ole tässä versiossa"
+
+msgid "E608: Cannot :throw exceptions with 'Vim' prefix"
+msgstr "E608: Vim-alkuisia poikkeuksia ei voi heittää :throw-komennolla"
+
+#, c-format
+msgid "Exception thrown: %s"
+msgstr "Poikkeus heitetty: %s"
+
+#, c-format
+msgid "Exception finished: %s"
+msgstr "Poikkeus lopeteltu: %s"
+
+#, c-format
+msgid "Exception discarded: %s"
+msgstr "Poikkeus poistettu: %s"
+
+#, c-format
+msgid "%s, line %ld"
+msgstr "%s, rivi %ld"
+
+#, c-format
+msgid "Exception caught: %s"
+msgstr "Poikkeus otettu kiinni: %s"
+
+#, c-format
+msgid "%s made pending"
+msgstr "%s odotutettu"
+
+#, c-format
+msgid "%s resumed"
+msgstr "%s palautettu"
+
+#, c-format
+msgid "%s discarded"
+msgstr "%s poistettu"
+
+msgid "Exception"
+msgstr "Poikkeus"
+
+msgid "Error and interrupt"
+msgstr "Virhe ja keskeytys"
+
+msgid "Error"
+msgstr "Virhe"
+
+msgid "Interrupt"
+msgstr "Keskeytys"
+
+msgid "E579: :if nesting too deep"
+msgstr "E579: liian monta kerrosta :if-komennossa"
+
+msgid "E580: :endif without :if"
+msgstr "E580: :endif ilman komentoa :if"
+
+msgid "E581: :else without :if"
+msgstr "E581: :else ilman komentoa :if"
+
+msgid "E582: :elseif without :if"
+msgstr "E582: :elseif ilman komentoa :if"
+
+msgid "E583: multiple :else"
+msgstr "E583: :else monta kertaa"
+
+msgid "E584: :elseif after :else"
+msgstr "E584: :elseif komennon :else jälkeen"
+
+msgid "E585: :while/:for nesting too deep"
+msgstr "E585: liian monta tasoa :while- tai :for-komennoissa"
+
+msgid "E586: :continue without :while or :for"
+msgstr "E586: :continue ilman komentoa :while tai :for"
+
+msgid "E587: :break without :while or :for"
+msgstr "E587: :break ilman komentoa :while tai :for"
+
+msgid "E732: Using :endfor with :while"
+msgstr "E732: :endfor ilman komentoa :while"
+
+msgid "E733: Using :endwhile with :for"
+msgstr "E733: :endwhile ilman komentoa :for"
+
+msgid "E601: :try nesting too deep"
+msgstr "E601: liian monta tasoa :try-komennossa"
+
+msgid "E603: :catch without :try"
+msgstr "E603: :catch ilman komentoa :try"
+
+msgid "E604: :catch after :finally"
+msgstr "E604: :catch ilman komentoa :finally"
+
+msgid "E606: :finally without :try"
+msgstr "E606: :finally ilman komentoa :try"
+
+msgid "E607: multiple :finally"
+msgstr "E607: :finally monta kertaa"
+
+msgid "E602: :endtry without :try"
+msgstr "E602: :endtry ilman komentoa :try"
+
+msgid "E193: :endfunction not inside a function"
+msgstr "E193: :endfunction funktion ulkopuolella"
+
+msgid "E788: Not allowed to edit another buffer now"
+msgstr "E788: Puskuria ei voi muokata nyt"
+
+msgid "E811: Not allowed to change buffer information now"
+msgstr "E811: Puskuria ei voi vaihtaa nyt"
+
+msgid "tagname"
+msgstr "täginimi"
+
+msgid " kind file\n"
+msgstr " -tiedostotyyppi\n"
+
+msgid "'history' option is zero"
+msgstr "history-asetus on nolla"
+
+#, c-format
+msgid ""
+"\n"
+"# %s History (newest to oldest):\n"
+msgstr ""
+"\n"
+"# %s Historia (uusimmasta alkaen):\n"
+
+msgid "Command Line"
+msgstr "Komentorivi"
+
+msgid "Search String"
+msgstr "Hakujono"
+
+msgid "Expression"
+msgstr "Ilmaus"
+
+msgid "Input Line"
+msgstr "Syöterivi"
+
+msgid "Debug Line"
+msgstr "Vianetsintärivi"
+
+msgid "E198: cmd_pchar beyond the command length"
+msgstr "E198: cmd_pchar komennon pituuden ulkopuolella"
+
+msgid "E199: Active window or buffer deleted"
+msgstr "E199: Aktiivinen ikkuna tai puskuri poistettu"
+
+msgid "E812: Autocommands changed buffer or buffer name"
+msgstr "E812: Autocommands muutti puskurin tai sen nimen"
+
+msgid "Illegal file name"
+msgstr "Virheellinen tiedostonimi"
+
+msgid "is a directory"
+msgstr "on hakemisto"
+
+msgid "is not a file"
+msgstr "ei ole tiedosto"
+
+msgid "is a device (disabled with 'opendevice' option)"
+msgstr "on laite (ei käytössä opendevice-asetuksen takia)"
+
+msgid "[New File]"
+msgstr "[Uusi tiedosto]"
+
+msgid "[New DIRECTORY]"
+msgstr "[uusi HAKEMISTO]"
+
+msgid "[File too big]"
+msgstr "[Liian iso tiedosto]"
+
+msgid "[Permission Denied]"
+msgstr "[Lupa kielletty]"
+
+msgid "E200: *ReadPre autocommands made the file unreadable"
+msgstr ""
+"E200: *ReadPre-autocommand-komennot tekivät tiedostosta lukukelvottoman"
+
+msgid "E201: *ReadPre autocommands must not change current buffer"
+msgstr "E201: *ReadPre-autocommand-komennot eivät saa muuttaa puskuria"
+
+msgid "Vim: Reading from stdin...\n"
+msgstr "Vim: Luetaan vakiosyötteestä...\n"
+
+msgid "Reading from stdin..."
+msgstr "Luetaan vakiosyötteestä"
+
+msgid "E202: Conversion made file unreadable!"
+msgstr "E202: Muunnos teki tiedostosta lukukelvottoman."
+
+msgid "[fifo/socket]"
+msgstr "[fifo t. soketti]"
+
+msgid "[fifo]"
+msgstr "[fifo]"
+
+msgid "[socket]"
+msgstr "[soketti]"
+
+msgid "[character special]"
+msgstr "[merkki erikoinen]"
+
+# Carriage Return elikkä rivinvaihtomerkin eräs muoto/osa (vrt. LF)
+msgid "[CR missing]"
+msgstr "[CR puuttuu]"
+
+msgid "[long lines split]"
+msgstr "[pitkät rivit hajotettu]"
+
+msgid "[NOT converted]"
+msgstr "[EI muunnettu]"
+
+msgid "[converted]"
+msgstr "[muunnettu]"
+
+#, c-format
+msgid "[CONVERSION ERROR in line %ld]"
+msgstr "[MUUNNOSVIRHE rivillä %ld]"
+
+#, c-format
+msgid "[ILLEGAL BYTE in line %ld]"
+msgstr "[VIRHEELLINEN OKTETTI rivillä %ld]"
+
+msgid "[READ ERRORS]"
+msgstr "[LUKUVIRHEITÄ]"
+
+msgid "Can't find temp file for conversion"
+msgstr "Ei voi löytää väliaikaistiedstoa muuntamiseksi"
+
+msgid "Conversion with 'charconvert' failed"
+msgstr "Muunnos charconvert epäonnistui"
+
+msgid "can't read output of 'charconvert'"
+msgstr "charconvertin tulostetta ei voida lukea"
+
+msgid "E676: No matching autocommands for acwrite buffer"
+msgstr "E676: Ei autocommand-komentoa acwrite-puskurille"
+
+msgid "E203: Autocommands deleted or unloaded buffer to be written"
+msgstr ""
+"E203: Autocommand-komennot poistivat tai vapauttivat puskurin, johon piti "
+"kirjoittaa"
+
+msgid "E204: Autocommand changed number of lines in unexpected way"
+msgstr "E204: Autocommand-komento muutti rivien määrä odottamatta"
+
+msgid "NetBeans disallows writes of unmodified buffers"
+msgstr "NetBeans ei salli kirjoittaa muokkaamattomiin puskureihin"
+
+msgid "Partial writes disallowed for NetBeans buffers"
+msgstr "Osittaiset kirjoitukset kielletty NetBeans-puskureissa"
+
+msgid "is not a file or writable device"
+msgstr "ei ole tiedosto tai kirjoitettava laite"
+
+msgid "writing to device disabled with 'opendevice' option"
+msgstr "laitteeseen kirjoittaminen pois käytöstä opendevice-asetuksella"
+
+msgid "is read-only (add ! to override)"
+msgstr "on kirjoitussuojattu (lisää komentoon ! ohittaaksesi)"
+
+msgid "E506: Can't write to backup file (add ! to override)"
+msgstr ""
+"E506: Ei voi kirjoittaa varmuuskopiotiedostoon (lisää komentoon ! "
+"ohittaaksesi)"
+
+msgid "E507: Close error for backup file (add ! to override)"
+msgstr ""
+"E507: Varmuuskopiotiedoston sulkeminen ei onnistu (lisää komentoon ! "
+"ohittaaksesi)"
+
+msgid "E508: Can't read file for backup (add ! to override)"
+msgstr ""
+"E508: Varmuuskopiotiedostoa ei voi lukea (lisää komentoon ! ohittaaksesi)"
+
+msgid "E509: Cannot create backup file (add ! to override)"
+msgstr ""
+"E509: Ei voi luoda varmuuskopiotiedostoa (lisää komentoon ! ohittaaksesi)"
+
+msgid "E510: Can't make backup file (add ! to override)"
+msgstr ""
+"E510: Ei voi tehdä varmuuskopiotiedostoa (lisää komentoon ! ohittaaksesi)"
+
+# tietääkseni resurssiforkki on applen tiedostojärjestelmän tunnistejuttujuttu
+msgid "E460: The resource fork would be lost (add ! to override)"
+msgstr "E460: resurssiosa häviäisi (lisää komentoon ! ohittaaksesi)"
+
+msgid "E214: Can't find temp file for writing"
+msgstr "E214: Ei voi löytää väliaikaistiedostoa kirjoitettavaksi"
+
+msgid "E213: Cannot convert (add ! to write without conversion)"
+msgstr ""
+"E213: Muunnos ei onnistu (lisää komentoon ! kirjoittaaksesi muuntamatta)"
+
+msgid "E166: Can't open linked file for writing"
+msgstr "E166: Linkitetyn tiedoston avaus kirjoittamista varten ei onnistu"
+
+msgid "E212: Can't open file for writing"
+msgstr "E212: Tiedoston avaus kirjoittamista varten ei onnistu"
+
+msgid "E667: Fsync failed"
+msgstr "E667: Fsync ei onnistunut"
+
+msgid "E512: Close failed"
+msgstr "E512: Sulkeminen ei onnistunut"
+
+msgid "E513: write error, conversion failed (make 'fenc' empty to override)"
+msgstr "E513: kirjoitusvirhe, muunnos epäonnistui (tyhjää fenc ohittaaksesi)"
+
+#, c-format
+msgid ""
+"E513: write error, conversion failed in line %ld (make 'fenc' empty to "
+"override)"
+msgstr ""
+"E513: kirjoitusvirhe, muunnos epäonnistui rivillä %ld(tyhjää fenc "
+"ohittaaksesi)"
+
+msgid "E514: write error (file system full?)"
+msgstr "E514: kirjoitusvirhe (tiedostojärjestelmä täysi)"
+
+msgid " CONVERSION ERROR"
+msgstr " MUUNNOSVIRHE"
+
+#, c-format
+msgid " in line %ld;"
+msgstr " rivillä %ld"
+
+msgid "[Device]"
+msgstr "[Laite]"
+
+msgid "[New]"
+msgstr "[Uusi]"
+
+msgid " [a]"
+msgstr " [a]"
+
+msgid " appended"
+msgstr " lisätty"
+
+msgid " [w]"
+msgstr " [w]"
+
+msgid " written"
+msgstr " kirjoitettu"
+
+msgid "E205: Patchmode: can't save original file"
+msgstr "E205: Patch-tilassa ei voi tallentaa alkuperäistiedostoa"
+
+msgid "E206: patchmode: can't touch empty original file"
+msgstr "E206: patch-tilassa ei voi muuttaa tyhjää alkuperäistiedostoa"
+
+msgid "E207: Can't delete backup file"
+msgstr "E207: Ei voi poistaa varmuuskopiota"
+
+msgid ""
+"\n"
+"WARNING: Original file may be lost or damaged\n"
+msgstr ""
+"\n"
+"VAROITUS: Alkuperäistiedosto voi hävitä tai vahingoittua\n"
+
+msgid "don't quit the editor until the file is successfully written!"
+msgstr "älä lopeta editoria kesken tallentamisen."
+
+msgid "[dos]"
+msgstr "[dos]"
+
+msgid "[dos format]"
+msgstr "[dos-muoto]"
+
+msgid "[mac]"
+msgstr "[mac]"
+
+msgid "[mac format]"
+msgstr "[mac-muoto]"
+
+msgid "[unix]"
+msgstr "[unix]"
+
+msgid "[unix format]"
+msgstr "[unix-muoto]"
+
+msgid "1 line, "
+msgstr "1 rivi, "
+
+#, c-format
+msgid "%ld lines, "
+msgstr "%ld riviä, "
+
+msgid "1 character"
+msgstr "1 merkki"
+
+#, c-format
+msgid "%lld characters"
+msgstr "%lld merkkiä"
+
+# ei rivinvaihtoja
+msgid "[noeol]"
+msgstr "[eiriviv.]"
+
+msgid "[Incomplete last line]"
+msgstr "[Vajaa viimeinen rivi]"
+
+# Jos aukiolevaa tiedostoa sörkkii toisella ohjelmalla
+msgid "WARNING: The file has been changed since reading it!!!"
+msgstr "VAROITUS: tiedosto on muuttunut viime lukukerran jälkeen!"
+
+msgid "Do you really want to write to it"
+msgstr "Kirjoitetaanko"
+
+#, c-format
+msgid "E208: Error writing to \"%s\""
+msgstr "E208: Virhe kirjoitettaessa tiedostoon %s"
+
+#, c-format
+msgid "E209: Error closing \"%s\""
+msgstr "E209: Virhe suljettaessa tiedostoa %s"
+
+#, c-format
+msgid "E210: Error reading \"%s\""
+msgstr "E210: Virhe luettaessa tiedostoa %s"
+
+msgid "E246: FileChangedShell autocommand deleted buffer"
+msgstr "E246: FileChangedShell-autocommand poisti puskurin"
+
+#, c-format
+msgid "E211: File \"%s\" no longer available"
+msgstr "E211: Tiedostoa %s ei ole enää"
+
+#, c-format
+msgid ""
+"W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as "
+"well"
+msgstr ""
+"W12: Varoitus: Tiedostoa %s on muutettu ja Vimin puskurissa on muutoksia "
+"tiedostoon"
+
+msgid "See \":help W12\" for more info."
+msgstr ":help W12 kertoo lisätietoja."
+
+#, c-format
+msgid "W11: Warning: File \"%s\" has changed since editing started"
+msgstr "W11: Varoitus: Tiedostoa %s on muutettu muokkauksen aloituksen jälkeen"
+
+msgid "See \":help W11\" for more info."
+msgstr ":help W11 kertoo lisätietoja."
+
+#, c-format
+msgid "W16: Warning: Mode of file \"%s\" has changed since editing started"
+msgstr ""
+"W16: Varoitus: Tiedoston %s oikeuksia on muutettu muokkauksen aloituksen "
+"jälkeen"
+
+msgid "See \":help W16\" for more info."
+msgstr ":help W16 kertoo lisätietoja."
+
+#, c-format
+msgid "W13: Warning: File \"%s\" has been created after editing started"
+msgstr "W13: Varoitus: Tiedosto %s on luotu muokkauksen aloituksen jälkeen"
+
+msgid "Warning"
+msgstr "Varoitus"
+
+# yllä olevien varoitusten ratkaisut
+msgid ""
+"&OK\n"
+"&Load File"
+msgstr ""
+"&OK\n"
+"&Avaa tiedosto uudelleen"
+
+#, c-format
+msgid "E462: Could not prepare for reloading \"%s\""
+msgstr "E462: Ei voitu valmistella uudelleen avausta %s"
+
+#, c-format
+msgid "E321: Could not reload \"%s\""
+msgstr "E321: Ei voitu uudelleenavata %s"
+
+msgid "--Deleted--"
+msgstr "--Poistettu--"
+
+#, c-format
+msgid "auto-removing autocommand: %s <buffer=%d>"
+msgstr "poistetaan autocommand automaattisesti: %s <puskuri=%d>"
+
+#, c-format
+msgid "E367: No such group: \"%s\""
+msgstr "E367: Ryhmää ei ole: %s"
+
+msgid "E936: Cannot delete the current group"
+msgstr "E936: Nykyistä ryhmää ei voi poistaa"
+
+msgid "W19: Deleting augroup that is still in use"
+msgstr "W19: käytössä oleva augroup poistetaan"
+
+#, c-format
+msgid "E215: Illegal character after *: %s"
+msgstr "E215: Virheellinen merkki *:n jälkeen: %s"
+
+#, c-format
+msgid "E216: No such event: %s"
+msgstr "E216: Eventtiä ei ole: %s"
+
+#, c-format
+msgid "E216: No such group or event: %s"
+msgstr "E216: Ryhmää tai eventtiä ei ole: %s"
+
+msgid ""
+"\n"
+"--- Autocommands ---"
+msgstr ""
+"\n"
+"--- Autocommandit ---"
+
+#, c-format
+msgid "E680: <buffer=%d>: invalid buffer number "
+msgstr "E680: <puskuri=%d>: virheellinen puskurinumero"
+
+msgid "E217: Can't execute autocommands for ALL events"
+msgstr "E217: Ei voi suorittaa autocommandsia kaikille eventeille"
+
+msgid "No matching autocommands"
+msgstr "Ei täsmääviä autocommandsia"
+
+msgid "E218: autocommand nesting too deep"
+msgstr "E218: liian monta tasoa autocommandissa"
+
+#, c-format
+msgid "%s Autocommands for \"%s\""
+msgstr "%s Autocommands kohteelle %s"
+
+#, c-format
+msgid "Executing %s"
+msgstr "Suoritetaan %s"
+
+#, c-format
+msgid "autocommand %s"
+msgstr "autocommand %s"
+
+msgid "E219: Missing {."
+msgstr "E219: { puuttuu."
+
+msgid "E220: Missing }."
+msgstr "E220: } puuttuu."
+
+msgid "E490: No fold found"
+msgstr "E490: taitos puuttuu"
+
+msgid "E350: Cannot create fold with current 'foldmethod'"
+msgstr "E350: Taitoksia ei voi tehdä tällä foldmethodilla"
+
+msgid "E351: Cannot delete fold with current 'foldmethod'"
+msgstr "E351: Taitosta ei voi poistaa tällä foldmethodilla"
+
+msgid "E222: Add to read buffer"
+msgstr "E222: Lisää lukupuskuriin"
+
+msgid "E223: recursive mapping"
+msgstr "E223: rekursiivinen kuvaus"
+
+#, c-format
+msgid "E224: global abbreviation already exists for %s"
+msgstr "E224: globaali lyhenne merkinnälle %s on jo olemassa"
+
+#, c-format
+msgid "E225: global mapping already exists for %s"
+msgstr "E225: globaali kuvaus merkinnälle %s on jo olemassa"
+
+#, c-format
+msgid "E226: abbreviation already exists for %s"
+msgstr "E226: lyhenne on jo olemassa %s"
+
+#, c-format
+msgid "E227: mapping already exists for %s"
+msgstr "E227: kuvaus on jo olemassa %s"
+
+msgid "No abbreviation found"
+msgstr "Lyhennettä ei löydy"
+
+msgid "No mapping found"
+msgstr "Kuvausta ei löydy"
+
+msgid "E228: makemap: Illegal mode"
+msgstr "E228: makemap: Virheellinen tila"
+
+msgid "<cannot open> "
+msgstr "<ei voi avata> "
+
+#, c-format
+msgid "E616: vim_SelFile: can't get font %s"
+msgstr "E616: vim_SelFile: ei saada fonttia %s"
+
+msgid "E614: vim_SelFile: can't return to current directory"
+msgstr "E614: vim_SelFile: nykyiseen hakemistoon ei voi palata"
+
+msgid "Pathname:"
+msgstr "Polku:"
+
+msgid "E615: vim_SelFile: can't get current directory"
+msgstr "E615: vim_SelFile: nykyistä hakemistoa ei saada selville"
+
+msgid "OK"
+msgstr "OK"
+
+msgid "Cancel"
+msgstr "Peru"
+
+msgid "Vim dialog"
+msgstr "Vim-ikkuna"
+
+msgid "Scrollbar Widget: Could not get geometry of thumb pixmap."
+msgstr "Vierityspalkki: Pixmapin geometria ei selviä"
+
+msgid "E232: Cannot create BalloonEval with both message and callback"
+msgstr "E232: Ei voi luoda BalloonEvalia viestille ja callbackille"
+
+msgid "E851: Failed to create a new process for the GUI"
+msgstr "E851: Ei voitu luoda uutta prosessia käyttöliittymälle"
+
+msgid "E852: The child process failed to start the GUI"
+msgstr "E852: Lapsiprosesi ei voinut käynnistää käyttöliittymää"
+
+msgid "E229: Cannot start the GUI"
+msgstr "E229: GUIn käynnistys ei onnistu"
+
+#, c-format
+msgid "E230: Cannot read from \"%s\""
+msgstr "E230: Ei voi lukea kohteesta %s"
+
+msgid "E665: Cannot start GUI, no valid font found"
+msgstr "E665: Ei voi avata GUIta, sopivaa fonttia ei löydy"
+
+msgid "E231: 'guifontwide' invalid"
+msgstr "E231: guifontwide virheellinen"
+
+msgid "E599: Value of 'imactivatekey' is invalid"
+msgstr "E599: imactivatekeyn arvo on virheellinen"
+
+#, c-format
+msgid "E254: Cannot allocate color %s"
+msgstr "E254: Väriä %s ei voi määritellä"
+
+msgid "No match at cursor, finding next"
+msgstr "Ei täsmäystä kursorin alla, etsitään seuraava"
+
+msgid "_Cancel"
+msgstr "_Peru"
+
+msgid "_Save"
+msgstr "_Tallenna"
+
+msgid "_Open"
+msgstr "_Avaa"
+
+msgid "_OK"
+msgstr "_OK"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"&Cancel"
+msgstr ""
+"&Kyllä\n"
+"&Ei\n"
+"&Peru"
+
+msgid "Yes"
+msgstr "Kyllä"
+
+msgid "No"
+msgstr "Ei"
+
+msgid "Input _Methods"
+msgstr "Syöte_menetelmät"
+
+msgid "VIM - Search and Replace..."
+msgstr "VIM - Etsi ja korvaa..."
+
+msgid "VIM - Search..."
+msgstr "VIM - Etsi..."
+
+msgid "Find what:"
+msgstr "Etsi:"
+
+msgid "Replace with:"
+msgstr "Korvaa:"
+
+msgid "Match whole word only"
+msgstr "Korvaa kokonaisia sanoja"
+
+msgid "Match case"
+msgstr "Kirjaintaso"
+
+msgid "Direction"
+msgstr "Suunta"
+
+msgid "Up"
+msgstr "Ylös"
+
+msgid "Down"
+msgstr "Alas"
+
+msgid "Find Next"
+msgstr "Etsi seuraava"
+
+msgid "Replace"
+msgstr "Korvaa"
+
+msgid "Replace All"
+msgstr "Korvaa kaikki"
+
+msgid "_Close"
+msgstr "_Sulje"
+
+msgid "Vim: Received \"die\" request from session manager\n"
+msgstr "Vim: sessiomanageri lähetti die-pyynnön\n"
+
+msgid "Close tab"
+msgstr "Sulje välilehti"
+
+msgid "New tab"
+msgstr "Uusi välilehti"
+
+msgid "Open Tab..."
+msgstr "Avaa välilehti..."
+
+msgid "Vim: Main window unexpectedly destroyed\n"
+msgstr "Vim: Pääikkuna tuhoutui odottamatta\n"
+
+msgid "&Filter"
+msgstr "&Suodata"
+
+msgid "&Cancel"
+msgstr "&Peru"
+
+msgid "Directories"
+msgstr "Hakemistot"
+
+msgid "Filter"
+msgstr "Suodatus"
+
+msgid "&Help"
+msgstr "O&hje"
+
+msgid "Files"
+msgstr "Tiedostot"
+
+msgid "&OK"
+msgstr "&Ok"
+
+msgid "Selection"
+msgstr "Valinta"
+
+msgid "Find &Next"
+msgstr "Hae &seuraava"
+
+msgid "&Replace"
+msgstr "Ko&rvaa"
+
+msgid "Replace &All"
+msgstr "Korvaa k&aikki"
+
+msgid "&Undo"
+msgstr "&Kumoa"
+
+msgid "Open tab..."
+msgstr "Avaa välilehti..."
+
+msgid "Find string (use '\\\\' to find a '\\')"
+msgstr "Etsi merkkijonoa (\\\\:llä löytää \\:t)"
+
+msgid "Find & Replace (use '\\\\' to find a '\\')"
+msgstr "Etsi ja korvaa (\\\\:llä löytää \\:t)"
+
+msgid "Not Used"
+msgstr "Ei käytössä"
+
+msgid "Directory\t*.nothing\n"
+msgstr "Hakemisto\t*.nothing\n"
+
+#, c-format
+msgid "E671: Cannot find window title \"%s\""
+msgstr "E671: Ikkunan otsikkoa ei löydy %s"
+
+# OLE on object linking and embedding på windowska
+#, c-format
+msgid "E243: Argument not supported: \"-%s\"; Use the OLE version."
+msgstr "E243: Argumenttia ei tueta: -%s, käytä OLE-versiota"
+
+# MDI eli windowsin moni-ikkunasovellus
+msgid "E672: Unable to open window inside MDI application"
+msgstr "E672: Ikkunaa ei voitu avata MDI-sovellukseen"
+
+msgid "Vim E458: Cannot allocate colormap entry, some colors may be incorrect"
+msgstr "Vim E458: Ei voi varata värikartan alkiota, värit voivat mennä väärin"
+
+#, c-format
+msgid "E250: Fonts for the following charsets are missing in fontset %s:"
+msgstr "E250: Seuraavien merkistöjoukkojen fontit puuttuvat fontsetistä %s:"
+
+#, c-format
+msgid "E252: Fontset name: %s"
+msgstr "E252: Fontsetin nimi: %s"
+
+#, c-format
+msgid "Font '%s' is not fixed-width"
+msgstr "Fontti %s ei ole tasavälinen"
+
+#, c-format
+msgid "E253: Fontset name: %s"
+msgstr "E253: Fontsetin nimi: %s"
+
+#, c-format
+msgid "Font0: %s"
+msgstr "Fontti0: %s"
+
+#, c-format
+msgid "Font1: %s"
+msgstr "Fontti1: %s"
+
+#, c-format
+msgid "Font%ld width is not twice that of font0"
+msgstr "Fontti%ld:n leveys ei ole kaksi kertaa fontti0:n"
+
+#, c-format
+msgid "Font0 width: %ld"
+msgstr "Fontti0:n leveys: %ld"
+
+#, c-format
+msgid "Font1 width: %ld"
+msgstr "Fontti1:n leveys: %ld"
+
+msgid "Invalid font specification"
+msgstr "Virheellinen fonttimääritys"
+
+msgid "&Dismiss"
+msgstr "&Ohita"
+
+msgid "no specific match"
+msgstr "ei tarkkaa täsmäystä"
+
+msgid "Vim - Font Selector"
+msgstr "Vim - fonttivalitsin"
+
+msgid "Name:"
+msgstr "Nimi:"
+
+msgid "Show size in Points"
+msgstr "Näytä koko pisteinä"
+
+msgid "Encoding:"
+msgstr "Koodaus:"
+
+msgid "Font:"
+msgstr "Fontti:"
+
+msgid "Style:"
+msgstr "Tyyli:"
+
+msgid "Size:"
+msgstr "Koko:"
+
+msgid "E256: Hangul automata ERROR"
+msgstr "E256: Hangu-automaattivirhe"
+
+msgid "E550: Missing colon"
+msgstr "E550: kaksoispiste puuttuu"
+
+msgid "E551: Illegal component"
+msgstr "E551: Virheellinen komponentti"
+
+msgid "E552: digit expected"
+msgstr "E552: pitäisi olla numero"
+
+#, c-format
+msgid "Page %d"
+msgstr "Sivu %d"
+
+msgid "No text to be printed"
+msgstr "Ei tekstiä tulostettavaksi"
+
+#, c-format
+msgid "Printing page %d (%d%%)"
+msgstr "Tulostetaan sivua %d (%d %%)"
+
+#, c-format
+msgid " Copy %d of %d"
+msgstr " Kopio %d/%d"
+
+#, c-format
+msgid "Printed: %s"
+msgstr "Tulostettu: %s"
+
+msgid "Printing aborted"
+msgstr "Tulostus peruttu"
+
+msgid "E455: Error writing to PostScript output file"
+msgstr "E455: Virhe kirjoitettaessa PostScriptiä tiedostoon"
+
+#, c-format
+msgid "E624: Can't open file \"%s\""
+msgstr "E624: Ei voi avata tiedostoa %s"
+
+#, c-format
+msgid "E457: Can't read PostScript resource file \"%s\""
+msgstr "E457: Ei voi lukea PostScript-resurssitiedostoa %s"
+
+#, c-format
+msgid "E618: file \"%s\" is not a PostScript resource file"
+msgstr "E618: tiedosto %s ei ole PostScript-resurssitiedosto"
+
+#, c-format
+msgid "E619: file \"%s\" is not a supported PostScript resource file"
+msgstr "E619: tiedosto %s ei ole tuettu PostScript-resurssitiedosto"
+
+#, c-format
+msgid "E621: \"%s\" resource file has wrong version"
+msgstr "E621: resurssitiedoston %s versio on väärä"
+
+msgid "E673: Incompatible multi-byte encoding and character set."
+msgstr "E673: Tukematon monitvauinen merkistökoodaus ja merkistö."
+
+msgid "E674: printmbcharset cannot be empty with multi-byte encoding."
+msgstr "E674: printmbcharset ei voi olla tyhjä monitavuiselle koodaukselle."
+
+msgid "E675: No default font specified for multi-byte printing."
+msgstr "E675: Ei oletusfonttia monitavuiseen tulostukseen"
+
+msgid "E324: Can't open PostScript output file"
+msgstr "E324: PostScript-tulostetiedoston avaus ei onnistu"
+
+#, c-format
+msgid "E456: Can't open file \"%s\""
+msgstr "E456: Tiedoston %s avaus ei onnistu"
+
+msgid "E456: Can't find PostScript resource file \"prolog.ps\""
+msgstr "E456: PostScript-resurssitiedostoa prolog.ps ei löydy"
+
+msgid "E456: Can't find PostScript resource file \"cidfont.ps\""
+msgstr "E456: PostScript-resurssitiedostoa cidfont.ps ei löydy"
+
+#, c-format
+msgid "E456: Can't find PostScript resource file \"%s.ps\""
+msgstr "E456: Postscript-resurssitiedosta %s.ps ei löydy"
+
+#, c-format
+msgid "E620: Unable to convert to print encoding \"%s\""
+msgstr "E620: Tulostuskoodaukseen %s muunto ei onnistu"
+
+msgid "Sending to printer..."
+msgstr "Lähetetään tulostimelle..."
+
+msgid "E365: Failed to print PostScript file"
+msgstr "E365: PostScript-tiedoston tulostus epäonnistui"
+
+msgid "Print job sent."
+msgstr "Tulostustyö lähetetty."
+
+msgid "Add a new database"
+msgstr "Lisää uusi tietokanta"
+
+msgid "Query for a pattern"
+msgstr "Hae kuviota"
+
+msgid "Show this message"
+msgstr "Näytä tämä viesti"
+
+msgid "Kill a connection"
+msgstr "Tapa yhteys"
+
+msgid "Reinit all connections"
+msgstr "Alusta uudelleen yhteydet"
+
+msgid "Show connections"
+msgstr "Näytä yhteydet"
+
+#, c-format
+msgid "E560: Usage: cs[cope] %s"
+msgstr "E560: Käyttö: cs[cope] %s"
+
+msgid "This cscope command does not support splitting the window.\n"
+msgstr "Tämä cscope-komento ei tue ikkunan jakamista.\n"
+
+msgid "E562: Usage: cstag <ident>"
+msgstr "E562: Käyttö: cstag <ident>"
+
+msgid "E257: cstag: tag not found"
+msgstr "E257: cstag: tägia ei löydy"
+
+#, c-format
+msgid "E563: stat(%s) error: %d"
+msgstr "E563: stat(%s)-virhe: %d"
+
+msgid "E563: stat error"
+msgstr "E563: stat-virhe"
+
+#, c-format
+msgid "E564: %s is not a directory or a valid cscope database"
+msgstr "E564: %s ei ole hakemisto eikä cscope-tietokanta"
+
+#, c-format
+msgid "Added cscope database %s"
+msgstr "Lisätty cscope-tietokanta %s"
+
+#, c-format
+msgid "E262: error reading cscope connection %ld"
+msgstr "E262: Virhe luettaessa cscope-yhteyttä %ld"
+
+msgid "E561: unknown cscope search type"
+msgstr "E561: tuntematon cscope-hakutyyppi"
+
+msgid "E566: Could not create cscope pipes"
+msgstr "E566: Ei voitu luoda cscope-putkia"
+
+msgid "E622: Could not fork for cscope"
+msgstr "E622: Ei voitu haarauttaa cscopea"
+
+msgid "cs_create_connection setpgid failed"
+msgstr "cs_create_connection setpgid epäonnistui"
+
+msgid "cs_create_connection exec failed"
+msgstr "cs_create_connection epäonnistui"
+
+msgid "cs_create_connection: fdopen for to_fp failed"
+msgstr "cs_create_connection: fdopen to_fp epäonnistui"
+
+msgid "cs_create_connection: fdopen for fr_fp failed"
+msgstr "cs_create_connection: fdopen fr_fp epäonnistui"
+
+msgid "E623: Could not spawn cscope process"
+msgstr "E623: Cscope-prosessin luonti epäonnistui"
+
+msgid "E567: no cscope connections"
+msgstr "E567: ei cscope-yhteyksiä"
+
+#, c-format
+msgid "E469: invalid cscopequickfix flag %c for %c"
+msgstr "E469: virheellinen cscopequickfix-asetus %c kohteelle %c"
+
+#, c-format
+msgid "E259: no matches found for cscope query %s of %s"
+msgstr "E259: ei täsmäyksiä cscope-hakuun %s/%s"
+
+msgid "cscope commands:\n"
+msgstr "cscope-komennot:\n"
+
+#, c-format
+msgid "%-5s: %s%*s (Usage: %s)"
+msgstr "%-5s: %s%*s (Käyttö: %s)"
+
+msgid ""
+"\n"
+" a: Find assignments to this symbol\n"
+" c: Find functions calling this function\n"
+" d: Find functions called by this function\n"
+" e: Find this egrep pattern\n"
+" f: Find this file\n"
+" g: Find this definition\n"
+" i: Find files #including this file\n"
+" s: Find this C symbol\n"
+" t: Find this text string\n"
+msgstr ""
+"\n"
+" a: Etsi sijotukset tähän symboliin\n"
+" c: Etsi tätä funktiota kutsuvat funktiot\n"
+" d: Etsi tämän funktion kutsumat funktiot\n"
+" e: Etsi tämä egrep-lauseke\n"
+" f: Etsi tämä tiedosto\n"
+" g: Etsi tämä määritys\n"
+" i: Etsi tiedostoja jotka #inkluudaavat tämän\n"
+" s: Etsi tämä C-symboli\n"
+" t: Etsi sijoitukset muuttujaan \n"
+
+#, c-format
+msgid "E625: cannot open cscope database: %s"
+msgstr "E625: ei voi avata cscope-tietokantaa: %s"
+
+msgid "E626: cannot get cscope database information"
+msgstr "E626: ei voi hakea cscope-tietokannan tietoja"
+
+msgid "E568: duplicate cscope database not added"
+msgstr "E568: kaksoiskappaletta cscope-tietokannasta ei lisätty"
+
+#, c-format
+msgid "E261: cscope connection %s not found"
+msgstr "E261: cscope-yhteys %s puuttuu"
+
+#, c-format
+msgid "cscope connection %s closed"
+msgstr "cscope-yhteys %s on katkaistu"
+
+msgid "E570: fatal error in cs_manage_matches"
+msgstr "E570: kriittinen virhe cs_manage_matches-funktiossa"
+
+#, c-format
+msgid "Cscope tag: %s"
+msgstr "Cscope-tägi: %s"
+
+msgid ""
+"\n"
+" # line"
+msgstr ""
+"\n"
+" # rivi"
+
+msgid "filename / context / line\n"
+msgstr "tiedosto / konteksti / rivi\n"
+
+#, c-format
+msgid "E609: Cscope error: %s"
+msgstr "E609: Cscope-virhe: %s"
+
+msgid "All cscope databases reset"
+msgstr "Kaikki cscope-tietokannat nollattu"
+
+msgid "no cscope connections\n"
+msgstr "ei cscope-yhteyksiä\n"
+
+msgid " # pid database name prepend path\n"
+msgstr " # pid tietokanta lisäyspolku\n"
+
+msgid "Lua library cannot be loaded."
+msgstr "Luan kirjastoa ei voitu ladata."
+
+msgid "cannot save undo information"
+msgstr "ei voitu tallentaa kumoustietoja"
+
+msgid ""
+"E815: Sorry, this command is disabled, the MzScheme libraries could not be "
+"loaded."
+msgstr "E815: komento ei toimi, MzScheme-kirjastoa ei voitu ladata."
+
+msgid ""
+"E895: Sorry, this command is disabled, the MzScheme's racket/base module "
+"could not be loaded."
+msgstr "E895: Komento ei toimi, MzScheme-moduulia racket/base ei voitu ladata."
+
+msgid "invalid expression"
+msgstr "virheellinen ilmaus"
+
+msgid "expressions disabled at compile time"
+msgstr "ilmaukset poistettu käytöstä käännösaikana"
+
+msgid "hidden option"
+msgstr "piilotettu asetus"
+
+msgid "unknown option"
+msgstr "tuntematon asetus"
+
+msgid "window index is out of range"
+msgstr "ikkunan indeksi alueen ulkopuolella"
+
+msgid "couldn't open buffer"
+msgstr "ei voitu avata puskuria"
+
+msgid "cannot delete line"
+msgstr "ei voitu poistaa riviä"
+
+msgid "cannot replace line"
+msgstr "ei voitu korvata riviä"
+
+msgid "cannot insert line"
+msgstr "ei voitu lisätä riviä"
+
+msgid "string cannot contain newlines"
+msgstr "merkkijono ei saa sisältää rivinvaihtoja"
+
+msgid "error converting Scheme values to Vim"
+msgstr "virhe Schemestä Vimiin konversiossa"
+
+msgid "Vim error: ~a"
+msgstr "Vim-virhe: ~a"
+
+msgid "Vim error"
+msgstr "Vim-virhe"
+
+msgid "buffer is invalid"
+msgstr "puskuri on virheellinen"
+
+msgid "window is invalid"
+msgstr "ikkuna on virheellinen"
+
+msgid "linenr out of range"
+msgstr "rivinumero arvoalueen ulkopuolelta"
+
+msgid "not allowed in the Vim sandbox"
+msgstr "ei sallittu Vimin hiekkalaatikossa"
+
+msgid "E837: This Vim cannot execute :py3 after using :python"
+msgstr "E837: Python: Ei voi käyttää komentoja :py ja :py3 samassa istunnossa"
+
+msgid ""
+"E263: Sorry, this command is disabled, the Python library could not be "
+"loaded."
+msgstr "E263: komento ei toimi, Python-kirjaston lataaminen ei onnistunut."
+
+msgid "E836: This Vim cannot execute :python after using :py3"
+msgstr "E836: Python: Ei voi käyttää komentoja :py ja :py3 samassa istunnossa"
+
+msgid ""
+"E887: Sorry, this command is disabled, the Python's site module could not be "
+"loaded."
+msgstr ""
+"E887: Komento ei toimi, Pythonin site-moduulien lataaminen ei onnistunut."
+
+msgid "E659: Cannot invoke Python recursively"
+msgstr "E659: Pythonia ei voi kutsua rekursiivisesti"
+
+msgid "E265: $_ must be an instance of String"
+msgstr "E265: muuttujan $_ pitää olla Stringin instanssi"
+
+msgid ""
+"E266: Sorry, this command is disabled, the Ruby library could not be loaded."
+msgstr "E266: komento ei toimi, Ruby-kirjastoa ei voitu ladata."
+
+msgid "E267: unexpected return"
+msgstr "E267: odotuksenvastainen return"
+
+msgid "E268: unexpected next"
+msgstr "E268: Odotuksenvastainen next"
+
+msgid "E269: unexpected break"
+msgstr "E269: Odotuksenvastainen break"
+
+msgid "E270: unexpected redo"
+msgstr "E270: odotuksenvastainen redo"
+
+msgid "E271: retry outside of rescue clause"
+msgstr "E271: retry rescuen ulkopuolella"
+
+msgid "E272: unhandled exception"
+msgstr "E272: käsittelemätön poikkeus"
+
+#, c-format
+msgid "E273: unknown longjmp status %d"
+msgstr "E273: tuntematon longjmp-tila %d"
+
+msgid "invalid buffer number"
+msgstr "virheellinen puskurinumero"
+
+msgid "not implemented yet"
+msgstr "ei toteutettu"
+
+msgid "cannot set line(s)"
+msgstr "ei voi asettaa rivejä"
+
+msgid "invalid mark name"
+msgstr "virheellinen merkin nimi"
+
+msgid "mark not set"
+msgstr "merkko ei ole asetettu"
+
+#, c-format
+msgid "row %d column %d"
+msgstr "rivi %d sarake %d"
+
+msgid "cannot insert/append line"
+msgstr "rivin lisäys ei onnistu"
+
+msgid "line number out of range"
+msgstr "rivinumero arvoalueen ulkopuolella"
+
+msgid "unknown flag: "
+msgstr "tuntematon asetus: "
+
+msgid "unknown vimOption"
+msgstr "tuntematon vimOption"
+
+msgid "keyboard interrupt"
+msgstr "näppäimistökeskeytys"
+
+msgid "vim error"
+msgstr "vim-virhe"
+
+msgid "cannot create buffer/window command: object is being deleted"
+msgstr "ei voi luoda puskuri- tai ikkunakomentoa, olio on poistumassa"
+
+msgid ""
+"cannot register callback command: buffer/window is already being deleted"
+msgstr "callbackia ei voi rekisteröidä: puskuri tai ikkuna on poistettu"
+
+msgid ""
+"E280: TCL FATAL ERROR: reflist corrupt!? Please report this to vim-dev@vim."
+"org"
+msgstr ""
+"E280: kriittinen TCL-virhe: reflist hajalla? Ilmoita asiasta "
+"postituslistalle vim-dev@vim.org"
+
+msgid "cannot register callback command: buffer/window reference not found"
+msgstr "callbackia ei voi rekisteröidä: puskurin tai ikkunan viitettä ei löydy"
+
+msgid ""
+"E571: Sorry, this command is disabled: the Tcl library could not be loaded."
+msgstr "E571: komento ei toimi, Tcl-kirjastoa ei voitu ladata."
+
+#, c-format
+msgid "E572: exit code %d"
+msgstr "E572: palautusarvo %d"
+
+msgid "cannot get line"
+msgstr "ei voida hakea riviä"
+
+msgid "Unable to register a command server name"
+msgstr "Komentopalvelimen nimen rekisteröinti ei onnistu"
+
+msgid "E248: Failed to send command to the destination program"
+msgstr "E248: Komennon lähetys kohdeohjelmalle ei onnistu"
+
+#, c-format
+msgid "E573: Invalid server id used: %s"
+msgstr "E573: Virheellinen palvelimen tunniste: %s"
+
+msgid "E251: VIM instance registry property is badly formed. Deleted!"
+msgstr "E251: VIMin instanssin rekisteriarvo on virheellinen, poistettiin."
+
+#, c-format
+msgid "E938: Duplicate key in JSON: \"%s\""
+msgstr "E938: Kaksi samaa avainta JSONissa: %s"
+
+#, c-format
+msgid "E696: Missing comma in List: %s"
+msgstr "E696: Listasta puuttuu pilkku: %s"
+
+#, c-format
+msgid "E697: Missing end of List ']': %s"
+msgstr "E697: Listan lopusta puuttuu ]: %s"
+
+msgid "Unknown option argument"
+msgstr "Tuntematon asetusargumentti"
+
+msgid "Too many edit arguments"
+msgstr "Liikaa muokkausargumentteja"
+
+msgid "Argument missing after"
+msgstr "Argumentti puuttuu kohdasta"
+
+msgid "Garbage after option argument"
+msgstr "Roskaa argumentin perässä"
+
+msgid "Too many \"+command\", \"-c command\" or \"--cmd command\" arguments"
+msgstr "Liikaa +komentoja, -c-komentoja tai --cmd-komentoja"
+
+msgid "Invalid argument for"
+msgstr "Väärä argumentti valitsimelle"
+
+#, c-format
+msgid "%d files to edit\n"
+msgstr "%d tiedostoa muokattavana\n"
+
+msgid "netbeans is not supported with this GUI\n"
+msgstr "netbeans ei toimi tässä käyttöliittymässä\n"
+
+msgid "'-nb' cannot be used: not enabled at compile time\n"
+msgstr "-nb:tä ei voi käyttää, koska sitä ei käännetty mukaan\n"
+
+msgid "This Vim was not compiled with the diff feature."
+msgstr "Tähän Vimiin ei ole käännetty diff-toimintoja mukaan."
+
+msgid "Attempt to open script file again: \""
+msgstr "Yritettiin avata skriptitiedostoa uudestaan:"
+
+msgid "Cannot open for reading: \""
+msgstr "Ei voi avata luettavaksi: "
+
+msgid "Cannot open for script output: \""
+msgstr "Ei voi avata skriptin tulostetta varten: "
+
+msgid "Vim: Error: Failure to start gvim from NetBeans\n"
+msgstr "Vim: Virhe: Gvimin käynnistys NetBeansistä ei onnistu\n"
+
+msgid "Vim: Error: This version of Vim does not run in a Cygwin terminal\n"
+msgstr "Vim: Virhe: Tämä versio Vimistä ei toimi Cygwinin terminaalissa\n"
+
+msgid "Vim: Warning: Output is not to a terminal\n"
+msgstr "Vim: Varoitus: Tuloste ei mene terminaalille\n"
+
+msgid "Vim: Warning: Input is not from a terminal\n"
+msgstr "Vim: Varoitus: Syöte ei tule terminaalilta\n"
+
+msgid "pre-vimrc command line"
+msgstr "esi-vimrc-komentorivi"
+
+#, c-format
+msgid "E282: Cannot read from \"%s\""
+msgstr "E282: Ei voida lukea kohteesta %s"
+
+msgid ""
+"\n"
+"More info with: \"vim -h\"\n"
+msgstr ""
+"\n"
+"Lisätietoja: \"vim -h\"\n"
+
+msgid "[file ..] edit specified file(s)"
+msgstr "[tiedosto ..] muokkaa tiedostoja"
+
+msgid "- read text from stdin"
+msgstr "- lue vakiosyötteestä"
+
+msgid "-t tag edit file where tag is defined"
+msgstr "-t tägi muokkaa tiedostoa tägistä"
+
+msgid "-q [errorfile] edit file with first error"
+msgstr "-q [virhetiedosto] muokkaa tiedostoa ensimmäisestä virheestä"
+
+msgid ""
+"\n"
+"\n"
+"Usage:"
+msgstr ""
+"\n"
+"\n"
+"käyttö:"
+
+msgid " vim [arguments] "
+msgstr " vim [argumentit] "
+
+msgid ""
+"\n"
+" or:"
+msgstr ""
+"\n"
+" tai:"
+
+msgid ""
+"\n"
+"Where case is ignored prepend / to make flag upper case"
+msgstr ""
+"\n"
+"Jos aakkoslaji on ohitettu, lisää alkuun / tehdäksesi asetuksesta "
+"suuraakkosia"
+
+msgid ""
+"\n"
+"\n"
+"Arguments:\n"
+msgstr ""
+"\n"
+"\n"
+"Argumentit:\n"
+
+msgid "--\t\t\tOnly file names after this"
+msgstr "--\t\t\tvain tiedostonimiä tämän jälkeen"
+
+msgid "--literal\t\tDon't expand wildcards"
+msgstr "--literal\t\tÄlä käsittele jokerimerkkejä "
+
+msgid "-register\t\tRegister this gvim for OLE"
+msgstr "-register\t\trekisteröi gvim OLEa varten"
+
+msgid "-unregister\t\tUnregister gvim for OLE"
+msgstr "-unregister\t\tPoista gvim OLE-rekisteristä"
+
+msgid "-g\t\t\tRun using GUI (like \"gvim\")"
+msgstr "-g\t\t\tAvaa GUI (kuten gvimillä)"
+
+msgid "-f or --nofork\tForeground: Don't fork when starting GUI"
+msgstr "-f tai --nofork\tEdustalle: Älä haarauta GUIn käynnistyksessä"
+
+msgid "-v\t\t\tVi mode (like \"vi\")"
+msgstr "-v\t\t\tVi-tila (kuten villä)"
+
+msgid "-e\t\t\tEx mode (like \"ex\")"
+msgstr "-e\t\t\tEx-tila (kute exillä)"
+
+msgid "-E\t\t\tImproved Ex mode"
+msgstr "-E\t\t\tParanneltu Ex-tila"
+
+msgid "-s\t\t\tSilent (batch) mode (only for \"ex\")"
+msgstr "-s\t\t\tHiljainen (eräajo)tila (vain exillä)"
+
+msgid "-d\t\t\tDiff mode (like \"vimdiff\")"
+msgstr "-d\t\t\tDiff-tila (kuten vimdiffillä)"
+
+msgid "-y\t\t\tEasy mode (like \"evim\", modeless)"
+msgstr "-y\t\t\tHelppokäyttötila (kuten evimissä, ilman tiloja)"
+
+msgid "-R\t\t\tReadonly mode (like \"view\")"
+msgstr "-R\t\t\tKirjoitussuojattu tila (kuten view'lla)"
+
+msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
+msgstr "-Z\t\t\tRajoitettu tila (kuten rvimillä)"
+
+msgid "-m\t\t\tModifications (writing files) not allowed"
+msgstr "-m\t\t\tMuokkaukset (kirjoittaminen tiedostoon) pois käytöstä"
+
+msgid "-M\t\t\tModifications in text not allowed"
+msgstr "-M\t\t\tTekstin muokkaus pois käytöstä"
+
+msgid "-b\t\t\tBinary mode"
+msgstr "-b\t\t\tBinääritila"
+
+msgid "-l\t\t\tLisp mode"
+msgstr "-l\t\t\tLisp-tila"
+
+msgid "-C\t\t\tCompatible with Vi: 'compatible'"
+msgstr "-C\t\t\tVi-yhteensopivuustila: compatible"
+
+msgid "-N\t\t\tNot fully Vi compatible: 'nocompatible'"
+msgstr "-N\t\t\tEi Vi-yhteensopivuutta: nocompatible"
+
+msgid "-V[N][fname]\t\tBe verbose [level N] [log messages to fname]"
+msgstr ""
+"-V[N][tnimi]\t\tMonisanainen tuloste [Taso N] [kirjoita tuloste tnimeen] "
+
+msgid "-D\t\t\tDebugging mode"
+msgstr "-D\t\t\tVianetsintätila"
+
+msgid "-n\t\t\tNo swap file, use memory only"
+msgstr "-n\t\t\tEi swap-tiedostoja, käytä muistia"
+
+msgid "-r\t\t\tList swap files and exit"
+msgstr "-r\t\t\tLuetteloi swap-tiedostot ja poistu"
+
+msgid "-r (with file name)\tRecover crashed session"
+msgstr "-r (tiedostonimi)\tPalauta kaatunut sessio"
+
+msgid "-L\t\t\tSame as -r"
+msgstr "-L\t\t\tkuten -r"
+
+msgid "-f\t\t\tDon't use newcli to open window"
+msgstr "-f\t\t\tÄlä käytä newcli:tä ikkunan avaamiseen"
+
+msgid "-dev <device>\t\tUse <device> for I/O"
+msgstr "-dev <laite>\t\tKäytä <laitetta> IO:hon"
+
+msgid "-A\t\t\tStart in Arabic mode"
+msgstr "-A\t\t\tkäynnistä arabia-tilassa"
+
+msgid "-H\t\t\tStart in Hebrew mode"
+msgstr "-H\t\t\tkäynnistä heprea-tilassa"
+
+msgid "-F\t\t\tStart in Farsi mode"
+msgstr "-F\t\t\tkäynnistä farsi-tilassa"
+
+msgid "-T <terminal>\tSet terminal type to <terminal>"
+msgstr "-T <terminaali>\tAseta terminaalin tyypiksi <terminaali>"
+
+msgid "--not-a-term\t\tSkip warning for input/output not being a terminal"
+msgstr "--not-a-term\t\tOhita varoitus siitä että i/o ei ole terminaali"
+
+msgid "--ttyfail\t\tExit if input or output is not a terminal"
+msgstr "--ttyfail\t\tLopeta jos syöttö tai tuloste ei tule terminaalista tai "
+"terminaaliin vastaavasti"
+
+msgid "-u <vimrc>\t\tUse <vimrc> instead of any .vimrc"
+msgstr "-u <vimrc>\t\tKäytä <vimrc>-tiedostoa .vimrc:iden sijasta"
+
+msgid "-U <gvimrc>\t\tUse <gvimrc> instead of any .gvimrc"
+msgstr "-U <gvimrc>\t\tKäytä <gvimrc>-tiedostoa .gvimrc:iden sijasta"
+
+msgid "--noplugin\t\tDon't load plugin scripts"
+msgstr "--noplugin\t\tÄlä lataa liitännäisiä"
+
+msgid "-p[N]\t\tOpen N tab pages (default: one for each file)"
+msgstr "-p[N]\t\tAvaa N välilehteä (oletus: yksi per tiedosto)"
+
+msgid "-o[N]\t\tOpen N windows (default: one for each file)"
+msgstr "-o[N]\t\tAvaa N ikkunaa (oletus: yksi per tiedosto)"
+
+msgid "-O[N]\t\tLike -o but split vertically"
+msgstr "-O[N]\t\tKuten -o, mutta jaa pystysuunnassa"
+
+msgid "+\t\t\tStart at end of file"
+msgstr "+\t\t\tAloita tiedoston lopusta"
+
+msgid "+<lnum>\t\tStart at line <lnum>"
+msgstr "+<rivi>\t\t\tAloita riviltä <rivi>"
+
+msgid "--cmd <command>\tExecute <command> before loading any vimrc file"
+msgstr "--cmd <komento>\tSuorita <komento> ennen vimrc:iden latausta"
+
+msgid "-c <command>\t\tExecute <command> after loading the first file"
+msgstr "-c <komento>\t\tSuorita <komento> ensimmäisen tiedoston latauduttua"
+
+msgid "-S <session>\t\tSource file <session> after loading the first file"
+msgstr "-S <sessio>\t\tLataa <sessio> ensimmäisen tiedoston latauduttua"
+
+msgid "-s <scriptin>\tRead Normal mode commands from file <scriptin>"
+msgstr "-s <skripti>\tLue normaalitilan komentoja <skripti>-tiedostosta"
+
+msgid "-w <scriptout>\tAppend all typed commands to file <scriptout>"
+msgstr "-w <skripti>\tLisää kirjoitetut komennot <skripti>-tiedostoon"
+
+msgid "-W <scriptout>\tWrite all typed commands to file <scriptout>"
+msgstr "-W <skripti>\tKirjoita komennot <skripti>-tiedostoon"
+
+msgid "-x\t\t\tEdit encrypted files"
+msgstr "-x\t\t\tMuokkaa salattua tiedostoa"
+
+msgid "-display <display>\tConnect vim to this particular X-server"
+msgstr "-display <näyttö>\tYhdistä vim tiettyyn X-palvelimeen"
+
+msgid "-X\t\t\tDo not connect to X server"
+msgstr "-X\t\t\tÄlä yhdistä X-palvelimeen"
+
+msgid "--remote <files>\tEdit <files> in a Vim server if possible"
+msgstr ""
+"--remote <tiedostoja>\tMuokkaa <tiedostoja> Vim-palvelimessa, jos mahdollista"
+
+msgid "--remote-silent <files> Same, don't complain if there is no server"
+msgstr ""
+"--remote-silent <tiedostoja>\tSama, mutta älä ilmoita puuttuvasta "
+"palvelimesta"
+
+msgid ""
+"--remote-wait <files> As --remote but wait for files to have been edited"
+msgstr ""
+"--remote-wait <tiedostoja> kuten --remote, mutta odota tiedostojen "
+"muokkaamista"
+
+msgid ""
+"--remote-wait-silent <files> Same, don't complain if there is no server"
+msgstr ""
+"--remote-wait-silent <tiedostoja> sama, mutta älä ilmoita puuttuvasta "
+"palvelimesta"
+
+msgid ""
+"--remote-tab[-wait][-silent] <files> As --remote but use tab page per file"
+msgstr ""
+"--remote-tab[-wait][-silent] <tiedostoja> kuten --remote, mutta avaa "
+"välilehti joka tiedostolle"
+
+msgid "--remote-send <keys>\tSend <keys> to a Vim server and exit"
+msgstr ""
+"--remote-send <näppäimiä>\tLähetä <näppäimiä> painalluksina Vimille ja lopeta"
+
+msgid "--remote-expr <expr>\tEvaluate <expr> in a Vim server and print result"
+msgstr ""
+"--remote-expr <ilmaus>\tKäsittele <ilmaus> Vim-palvelimella ja tulosta tulos"
+
+msgid "--serverlist\t\tList available Vim server names and exit"
+msgstr "--serverlist\t\tLuettele Vim-palvelinten nimet ja lopeta"
+
+msgid "--servername <name>\tSend to/become the Vim server <name>"
+msgstr "--servername <nimi>\tLähetä Vim-palvelimelle <nimi> tai luo se"
+
+msgid "--startuptime <file>\tWrite startup timing messages to <file>"
+msgstr "--startuptime <file>\tKirjoita käynnistysaikaviestit tiedostoon <file>"
+
+msgid "-i <viminfo>\t\tUse <viminfo> instead of .viminfo"
+msgstr "-i <viminfo>\t\tKäytä <viminfo>-tiedostoa .viminfon sijaan"
+
+msgid "--clean\t\t'nocompatible', Vim defaults, no plugins, no viminfo"
+msgstr "--clean\t\t'nocompatible', Vimin oletukset,"
+"ei liitännäisiä tai viminfoa"
+
+msgid "-h or --help\tPrint Help (this message) and exit"
+msgstr "-h tai --help\tTulosta ohje (tämä viesti) ja lopeta"
+
+msgid "--version\t\tPrint version information and exit"
+msgstr "--version\t\t\tTulosta versiotiedot ja lopeta"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Motif version):\n"
+msgstr ""
+"\n"
+"Gvimin (Motif-version) tuntemat argumentit:\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (neXtaw version):\n"
+msgstr ""
+"\n"
+"Gvimin (neXtaw-version) tuntemat argumentit:\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Athena version):\n"
+msgstr ""
+"\n"
+"Gvimin (Athena-version) tuntemat argumentit:\n"
+
+msgid "-display <display>\tRun vim on <display>"
+msgstr "-display <näyttö>\tSuorita vim <näytössä>"
+
+msgid "-iconic\t\tStart vim iconified"
+msgstr "-iconic\t\tKäynnistä pienennettynä"
+
+msgid "-background <color>\tUse <color> for the background (also: -bg)"
+msgstr "-background <väri>\tKäytä <väriä> taustavärinä (myös: -bg)"
+
+msgid "-foreground <color>\tUse <color> for normal text (also: -fg)"
+msgstr "-foreground <väri>\tKäytä <väriä> tekstin värinä (myös: -fg)"
+
+msgid "-font <font>\t\tUse <font> for normal text (also: -fn)"
+msgstr "-font <fontti>\t\tKäytä <fonttia> tekstissä (myös: -fn)"
+
+msgid "-boldfont <font>\tUse <font> for bold text"
+msgstr "-boldfont <fontti>\tKäytä <fonttia> lihavoidussa tekstissä"
+
+msgid "-italicfont <font>\tUse <font> for italic text"
+msgstr "-italicfont <fontti>\tKäytä <fonttia> kursivoidussa tekstissä"
+
+msgid "-geometry <geom>\tUse <geom> for initial geometry (also: -geom)"
+msgstr ""
+"-geometry <geom>\tKäytä mittoja <geom> ikkunan asetteluun (myös: -geom)"
+
+msgid "-borderwidth <width>\tUse a border width of <width> (also: -bw)"
+msgstr "-borderwidt <leveys>\tKäytä <leveyttä> reunuksissa (myös: -bw) "
+
+msgid "-scrollbarwidth <width> Use a scrollbar width of <width> (also: -sw)"
+msgstr ""
+"-scrollbarwidth <leveys> Käytä <leveyttä> vierityspalkissa (myös: -sw)"
+
+msgid "-menuheight <height>\tUse a menu bar height of <height> (also: -mh)"
+msgstr "-menuheight <korkeus>\tKäytä <korkeutta> valikossa (myös: -mh)"
+
+msgid "-reverse\t\tUse reverse video (also: -rv)"
+msgstr "-reverse\t\tKäytä käänteisvärejä (myös: -rv) "
+
+msgid "+reverse\t\tDon't use reverse video (also: +rv)"
+msgstr "+reverse\t\tÄlä käytä käänteisvärejä (myös: +rv)"
+
+msgid "-xrm <resource>\tSet the specified resource"
+msgstr "-xrm <resurssi>\tAseta resurssi"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (GTK+ version):\n"
+msgstr ""
+"\n"
+"Gvimin (GTK+-version) tuntemat argumentit:\n"
+
+msgid "-display <display>\tRun vim on <display> (also: --display)"
+msgstr "-display <näyttö>\tSuorita vim näytöllä <näyttö> (myös: --display)"
+
+# X-ikkunointijärjestelmässä saman sovelluksen saman luokan ikkunat
+# tunnistetaan rooliresursseista
+msgid "--role <role>\tSet a unique role to identify the main window"
+msgstr "--role <rooli>\tAseta pääikkunalle ainutlaatuinen rooli tunnisteeksi"
+
+msgid "--socketid <xid>\tOpen Vim inside another GTK widget"
+msgstr "--socketid <xid>\tAvaa Vim annettuun GTK-olioon "
+
+msgid "--echo-wid\t\tMake gvim echo the Window ID on stdout"
+msgstr "--echo-wid\t\tTulosta gvimin Window ID vakiotulosteeseen"
+
+msgid "-P <parent title>\tOpen Vim inside parent application"
+msgstr "-P <otsikko>\tAvaa Vim isäntäohjelman sisään"
+
+msgid "--windowid <HWND>\tOpen Vim inside another win32 widget"
+msgstr "--windowid <HWND>\tAvaa Vim annettuun win32-olioon "
+
+msgid "No display"
+msgstr "Ei näyttöä"
+
+msgid ": Send failed.\n"
+msgstr ": Lähetys epäonnistui.\n"
+
+msgid ": Send failed. Trying to execute locally\n"
+msgstr ": Lähetys epäonnistui. Yritetään suorittaa paikallisena\n"
+
+#, c-format
+msgid "%d of %d edited"
+msgstr "%d/%d muokattu"
+
+msgid "No display: Send expression failed.\n"
+msgstr "Ei näyttöä: Ilmauksen lähetys epäonnistui.\n"
+
+msgid ": Send expression failed.\n"
+msgstr ": Ilmauksen lähetys epäonnistui.\n"
+
+msgid "No marks set"
+msgstr "Ei asetettuja merkkejä"
+
+#, c-format
+msgid "E283: No marks matching \"%s\""
+msgstr "E283: Mikään merkki ei täsmää ilmaukseen \"%s\""
+
+msgid ""
+"\n"
+"mark line col file/text"
+msgstr ""
+"\n"
+"merkki rivi sarake tiedosto/teksti"
+
+msgid ""
+"\n"
+" jump line col file/text"
+msgstr ""
+"\n"
+"hyppy rivi sarake tiedosto/teksti"
+
+msgid ""
+"\n"
+"change line col text"
+msgstr ""
+"\n"
+"muutos rivi sarake teksti"
+
+msgid ""
+"\n"
+"# File marks:\n"
+msgstr ""
+"\n"
+"# Tiedoston merkit:\n"
+
+msgid ""
+"\n"
+"# Jumplist (newest first):\n"
+msgstr ""
+"\n"
+"# Hyppylista (uusin ensiksi):\n"
+
+msgid ""
+"\n"
+"# History of marks within files (newest to oldest):\n"
+msgstr ""
+"\n"
+"# Tiedostojen merkkien historia (uusimmasta vanhimpaan):\n"
+
+msgid "Missing '>'"
+msgstr "> puuttuu"
+
+msgid "E543: Not a valid codepage"
+msgstr "E543: Koodisivu ei ole käypä"
+
+msgid "E284: Cannot set IC values"
+msgstr "E284: Ei voi asettaa IC-arvoja"
+
+msgid "E285: Failed to create input context"
+msgstr "E285: Syötekontekstin luonti ei onnistu"
+
+msgid "E286: Failed to open input method"
+msgstr "E286: Syötemetodin avaus ei onnistu"
+
+msgid "E287: Warning: Could not set destroy callback to IM"
+msgstr ""
+"E287: Varoitus: Ei voitu asettaa destroy-kutsua syötemetodipalvelimelle"
+
+msgid "E288: input method doesn't support any style"
+msgstr "E288: syötemetodi ei tue tyylejä"
+
+msgid "E289: input method doesn't support my preedit type"
+msgstr "E289: syötemetodi ei tue tätä preedit-tyyppiä"
+
+msgid "E293: block was not locked"
+msgstr "E293: lohkoa ei ole lukittu"
+
+msgid "E294: Seek error in swap file read"
+msgstr "E294: Hakuvirhe swap-tiedostoa luettaessa"
+
+msgid "E295: Read error in swap file"
+msgstr "E295: Lukuvirhe swap-tiedostossa"
+
+msgid "E296: Seek error in swap file write"
+msgstr "E296: Hakuvirhe swap-tiedostoa kirjoitettaessa"
+
+msgid "E297: Write error in swap file"
+msgstr "E297: Kirjoitusvirhe swap-tiedostossa"
+
+msgid "E300: Swap file already exists (symlink attack?)"
+msgstr "E300: Swaptiedosto on jo olemassa (symlink-hyökkäys?)"
+
+msgid "E298: Didn't get block nr 0?"
+msgstr "E298: Lohko 0:aa ei saatu?"
+
+msgid "E298: Didn't get block nr 1?"
+msgstr "E298: Lohko 1:tä ei saatu?"
+
+msgid "E298: Didn't get block nr 2?"
+msgstr "E298: Lohko 2:ta ei saatu?"
+
+msgid "E843: Error while updating swap file crypt"
+msgstr "E843: Virhe päivitettäessä swapin kryptausta"
+
+msgid "E301: Oops, lost the swap file!!!"
+msgstr "E301: Hups, swap-tiedosto hävisi!"
+
+msgid "E302: Could not rename swap file"
+msgstr "E302: Swap-tiedoston uudellennimeys ei onnistu"
+
+#, c-format
+msgid "E303: Unable to open swap file for \"%s\", recovery impossible"
+msgstr "E303: Swap-tiedostoa %s ei voi avata, palautus ei onnistu"
+
+msgid "E304: ml_upd_block0(): Didn't get block 0??"
+msgstr "E304: ml_upd_block0(): Lohko 0:aa ei saatu?"
+
+#, c-format
+msgid "E305: No swap file found for %s"
+msgstr "E305: Ei swap-tiedostoa tiedostolle %s"
+
+msgid "Enter number of swap file to use (0 to quit): "
+msgstr "Anna swap-tiedoston numero tai 0 lopettaaksesi: "
+
+#, c-format
+msgid "E306: Cannot open %s"
+msgstr "E306: Ei voi avata tiedostoa %s"
+
+msgid "Unable to read block 0 from "
+msgstr "Ei voi lukea lohkoa 0 kohteesta "
+
+msgid ""
+"\n"
+"Maybe no changes were made or Vim did not update the swap file."
+msgstr ""
+"\n"
+"Muutoksia ei tehty, tai Vim ei päivittänyt swap-tiedostoa."
+
+msgid " cannot be used with this version of Vim.\n"
+msgstr " ei toimi tämän version Vimin kanssa.\n"
+
+msgid "Use Vim version 3.0.\n"
+msgstr "Käytä Vimin versiota 3.0\n"
+
+#, c-format
+msgid "E307: %s does not look like a Vim swap file"
+msgstr "E307: %s ei ole Vimin swap-tiedosto"
+
+msgid " cannot be used on this computer.\n"
+msgstr " ei toimi tällä koneella.\n"
+
+msgid "The file was created on "
+msgstr "Tiedosto luotiin "
+
+msgid ""
+",\n"
+"or the file has been damaged."
+msgstr ""
+",\n"
+"tai tiedosto on vahingoittunut."
+
+#, c-format
+msgid ""
+"E833: %s is encrypted and this version of Vim does not support encryption"
+msgstr "E833: %s on salattu eikä tämä Vim tue salausta"
+
+msgid " has been damaged (page size is smaller than minimum value).\n"
+msgstr " on vioittunut (sivun koko on vähimmäisarvoa pienempi).\n"
+
+#, c-format
+msgid "Using swap file \"%s\""
+msgstr "Käytetään swap-tiedostoa %s"
+
+#, c-format
+msgid "Original file \"%s\""
+msgstr "Alkuperäinen tiedosto %s"
+
+msgid "E308: Warning: Original file may have been changed"
+msgstr "E308: Varoitus: Alkuperäistä tiedostoa saattaa olla muutettu"
+
+#, c-format
+msgid "Swap file is encrypted: \"%s\""
+msgstr "Swap-tiedosto on salattu: %s"
+
+msgid ""
+"\n"
+"If you entered a new crypt key but did not write the text file,"
+msgstr ""
+"\n"
+"Jos käytit uutta salausavainta muttet kirjoittanut tekstitiedostoa,"
+
+msgid ""
+"\n"
+"enter the new crypt key."
+msgstr ""
+"\n"
+"anna uusi salausavain."
+
+msgid ""
+"\n"
+"If you wrote the text file after changing the crypt key press enter"
+msgstr ""
+"\n"
+"Jos kirjoitit tekstitiedoston salausavaimen vaihdon jälkeen paina enteriä"
+
+msgid ""
+"\n"
+"to use the same key for text file and swap file"
+msgstr ""
+"\n"
+"käyttääksesi samaa avainta teksti- ja swäppitiedostoille"
+
+#, c-format
+msgid "E309: Unable to read block 1 from %s"
+msgstr "E309: Ei voitu lukea lohkoa 1 tiedostosta %s"
+
+msgid "???MANY LINES MISSING"
+msgstr "???PALJON RIVEJÄ PUUTTUU"
+
+msgid "???LINE COUNT WRONG"
+msgstr "???RIVIMÄÄRÄ PIELESSÄ"
+
+msgid "???EMPTY BLOCK"
+msgstr "???TYHJÄ LOHKO"
+
+msgid "???LINES MISSING"
+msgstr "???RIVEJÄ PUUTTUU"
+
+#, c-format
+msgid "E310: Block 1 ID wrong (%s not a .swp file?)"
+msgstr "E310: Lohon 1 tunniste väärä (%s ei ole .swp-tiedosto?)"
+
+msgid "???BLOCK MISSING"
+msgstr "???LOHKO PUUTTUU"
+
+msgid "??? from here until ???END lines may be messed up"
+msgstr "??? tästä kohtaan ???LOPPU rivejä sekaisin"
+
+msgid "??? from here until ???END lines may have been inserted/deleted"
+msgstr "??? tästä kohtaan ???LOPPU rivejä saattaa olla lisätty tai poistettu"
+
+msgid "???END"
+msgstr "???LOPPU"
+
+msgid "E311: Recovery Interrupted"
+msgstr "E311: Palautus keskeytetty"
+
+msgid ""
+"E312: Errors detected while recovering; look for lines starting with ???"
+msgstr "E312: Palautuksessa oli virheitä, etsi rivejä, jotka alkavat ???"
+
+msgid "See \":help E312\" for more information."
+msgstr ":help E312 kertoo lisätietoja"
+
+msgid "Recovery completed. You should check if everything is OK."
+msgstr "Palautus onnistui. Tarkista, että kaikki on kunnossa."
+
+msgid ""
+"\n"
+"(You might want to write out this file under another name\n"
+msgstr ""
+"\n"
+"(Saattaa kannattaa kirjoittaa tämä tiedosto toisella nimellä\n"
+
+msgid "and run diff with the original file to check for changes)"
+msgstr "ja katso diffillä muutokset alkuperäiseen tiedostoon)"
+
+msgid "Recovery completed. Buffer contents equals file contents."
+msgstr "Palautus onnistui. Puskurin ja tiedoston sisällöt täsmäävät."
+
+msgid ""
+"\n"
+"You may want to delete the .swp file now.\n"
+"\n"
+msgstr ""
+"\n"
+"Voit poistaa .swp-tiedosto nyt.\n"
+"\n"
+
+msgid "Using crypt key from swap file for the text file.\n"
+msgstr "Käytetään swäpin salausavainta tekstitiedostolle\n"
+
+msgid "Swap files found:"
+msgstr "Swap-tiedostoja löytyi:"
+
+msgid " In current directory:\n"
+msgstr " Tässä hakemistossa:\n"
+
+msgid " Using specified name:\n"
+msgstr " Määritellyllä nimellä:\n"
+
+msgid " In directory "
+msgstr " Hakemistossa "
+
+msgid " -- none --\n"
+msgstr " -- ei mitään --\n"
+
+msgid " owned by: "
+msgstr " omistaja: "
+
+msgid " dated: "
+msgstr " ajalta: "
+
+msgid " dated: "
+msgstr " ajalta:"
+
+msgid " [from Vim version 3.0]"
+msgstr " [Vimin 3.0-versiosta]"
+
+msgid " [does not look like a Vim swap file]"
+msgstr " [ei näytä Vimin swap-tiedostolta]"
+
+msgid " file name: "
+msgstr " tiedostonimi: "
+
+msgid ""
+"\n"
+" modified: "
+msgstr ""
+"\n"
+" muokattu: "
+
+msgid "YES"
+msgstr "KYLLÄ"
+
+msgid "no"
+msgstr "ei"
+
+msgid ""
+"\n"
+" user name: "
+msgstr ""
+"\n"
+" käyttäjänimi: "
+
+msgid " host name: "
+msgstr " laitenimi: "
+
+msgid ""
+"\n"
+" host name: "
+msgstr ""
+"\n"
+" laitenimi: "
+
+msgid ""
+"\n"
+" process ID: "
+msgstr ""
+"\n"
+" prosessin tunniste: "
+
+msgid " (still running)"
+msgstr " (käynnissä)"
+
+msgid ""
+"\n"
+" [not usable with this version of Vim]"
+msgstr ""
+"\n"
+" [ei toimi tämän Vim-version kanssa]"
+
+msgid ""
+"\n"
+" [not usable on this computer]"
+msgstr ""
+"\n"
+" [ei toimi tällä koneella]"
+
+msgid " [cannot be read]"
+msgstr " [ei voi lukea]"
+
+msgid " [cannot be opened]"
+msgstr " [ei voi avata]"
+
+msgid "E313: Cannot preserve, there is no swap file"
+msgstr "E313: Ei voi säilyttää, swap-tiedostoa ei ole"
+
+msgid "File preserved"
+msgstr "Tiedosto säilytetty"
+
+msgid "E314: Preserve failed"
+msgstr "E314: Säilyttäminen epäonnistui"
+
+#, c-format
+msgid "E315: ml_get: invalid lnum: %ld"
+msgstr "E315: ml_get: virheellinen lnum: %ld"
+
+#, c-format
+msgid "E316: ml_get: cannot find line %ld"
+msgstr "E316: ml_get: riviä %ld ei löydy"
+
+msgid "E317: pointer block id wrong 3"
+msgstr "E317: osoitinlohkon tunnus väärä 3"
+
+msgid "stack_idx should be 0"
+msgstr "stack_idx pitää olla 0"
+
+msgid "E318: Updated too many blocks?"
+msgstr "E318: Päivitetty liikaa lohkoja"
+
+msgid "E317: pointer block id wrong 4"
+msgstr "E317: osoitinlohkon tunnus väärä 4"
+
+msgid "deleted block 1?"
+msgstr "poistettu lohko 1?"
+
+#, c-format
+msgid "E320: Cannot find line %ld"
+msgstr "E320: Riviä %ld ei löydy"
+
+msgid "E317: pointer block id wrong"
+msgstr "E317: osoitinlohkon tunnus väärä"
+
+msgid "pe_line_count is zero"
+msgstr "pe_line_count on nolla"
+
+#, c-format
+msgid "E322: line number out of range: %ld past the end"
+msgstr "E322: rivinumero arvoalueen ulkopuoleta: %ld on loppua suurempi"
+
+#, c-format
+msgid "E323: line count wrong in block %ld"
+msgstr "E323: rivimäärä väärin lohkossa %ld"
+
+msgid "Stack size increases"
+msgstr "Pinon koko kasvaa"
+
+msgid "E317: pointer block id wrong 2"
+msgstr "E317: osoitinlohon tunnus väärä 2"
+
+#, c-format
+msgid "E773: Symlink loop for \"%s\""
+msgstr "E773: Symlinkkisilmukka kohteelle %s"
+
+msgid "E325: ATTENTION"
+msgstr "E325: HUOMAA"
+
+msgid ""
+"\n"
+"Found a swap file by the name \""
+msgstr ""
+"\n"
+"Swap-tiedosto löytyi: \""
+
+msgid "While opening file \""
+msgstr "Avattaessa tiedostoa "
+
+msgid " NEWER than swap file!\n"
+msgstr " joka on UUDEMPI kuin swap-tiedosto!\n"
+
+msgid ""
+"\n"
+"(1) Another program may be editing the same file. If this is the case,\n"
+" be careful not to end up with two different instances of the same\n"
+" file when making changes. Quit, or continue with caution.\n"
+msgstr ""
+"\n"
+"(1) Toinen ohjelma saattaa käyttää samaa tiedostoa.\n"
+" Jos näin on, varo, ettet muokkaa saman tiedoston\n"
+" kahta instanssia yhtä aikaa. Lopeta tai jatka varoen.\n"
+
+msgid "(2) An edit session for this file crashed.\n"
+msgstr "(2) Tiedostonmuokkausistunto on kaatunut.\n"
+
+msgid " If this is the case, use \":recover\" or \"vim -r "
+msgstr " Jos näin on, käytä komentoa :recover tai vim -r "
+
+msgid ""
+"\"\n"
+" to recover the changes (see \":help recovery\").\n"
+msgstr ""
+"\"\n"
+" palauttaaksesi muutokset (lisätietoja: \":help recovery\").\n"
+
+msgid " If you did this already, delete the swap file \""
+msgstr " Jos teit jo näin, poista swap-tiedosto "
+
+msgid ""
+"\"\n"
+" to avoid this message.\n"
+msgstr ""
+"\"\n"
+" välttääksesi tämän viestin.\n"
+
+msgid "Swap file \""
+msgstr "Swap-tiedosto "
+
+msgid "\" already exists!"
+msgstr " on jo olemassa"
+
+msgid "VIM - ATTENTION"
+msgstr "VIM - HUOMAUTUS"
+
+msgid "Swap file already exists!"
+msgstr "Swap-tiedosto on jo olemassa"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"&Avaa kirjoitussuojattuna\n"
+"&Muokkaa\n"
+"&Palauta\n"
+"&Lopeta\n"
+"P&eru"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Delete it\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"&Avaa kirjoitussuojattuna\n"
+"&Muokkaa\n"
+"&Palauta\n"
+"P&oista\n"
+"&Lopeta\n"
+"P&eru"
+
+msgid "E326: Too many swap files found"
+msgstr "E326: Liian monta swap-tiedostoa"
+
+msgid "E327: Part of menu-item path is not sub-menu"
+msgstr "E327: Valikkokohtapolun osa ei ole alivalikko"
+
+msgid "E328: Menu only exists in another mode"
+msgstr "E328: Valikko on olemassa vain toisessa tilassa"
+
+#, c-format
+msgid "E329: No menu \"%s\""
+msgstr "E329: Ei valikkoa %s"
+
+msgid "E792: Empty menu name"
+msgstr "E792: tyhjä valikkonimi"
+
+msgid "E330: Menu path must not lead to a sub-menu"
+msgstr "E330: Valikkopolku ei saa johtaa alivalikkoon"
+
+msgid "E331: Must not add menu items directly to menu bar"
+msgstr "E331: Valikkokohtia ei saa lisätä suoraan valikkopalkkiin"
+
+msgid "E332: Separator cannot be part of a menu path"
+msgstr "E332: Erotin ei voi olla valikkopolun osa"
+
+msgid ""
+"\n"
+"--- Menus ---"
+msgstr ""
+"\n"
+"--- Valikot ---"
+
+msgid "Tear off this menu"
+msgstr "Repäise valikko irti"
+
+#, c-format
+msgid "E335: Menu not defined for %s mode"
+msgstr "E335: Valikkoa ei ole määritelty %s-tilassa"
+
+msgid "E333: Menu path must lead to a menu item"
+msgstr "E333: Valikkopolun on johdettava valikkokohtaan"
+
+#, c-format
+msgid "E334: Menu not found: %s"
+msgstr "E334: Valikkoa ei löydy: %s"
+
+msgid "E336: Menu path must lead to a sub-menu"
+msgstr "E336: Valikkopolun pitää johtaa alivalikkoon"
+
+msgid "E337: Menu not found - check menu names"
+msgstr "E337: Valikkoa ei löytynyt - tarkista valikkojen nimet"
+
+#, c-format
+msgid "Error detected while processing %s:"
+msgstr "Virhe suoritettaessa komentoja %s:"
+
+#, c-format
+msgid "line %4ld:"
+msgstr "rivi %4ld:"
+
+#, c-format
+msgid "E354: Invalid register name: '%s'"
+msgstr "E354: Virheellinen rekisterin nimi: %s"
+
+msgid "Messages maintainer: Bram Moolenaar <Bram@vim.org>"
+msgstr "Käännöksen ylläpitäjä: Flammie Pirinen <flammie@iki.fi>"
+
+msgid "Interrupt: "
+msgstr "Keskeytys: "
+
+msgid "Press ENTER or type command to continue"
+msgstr "Paina enteriä tai kirjoita komento aloittaaksesi "
+
+#, c-format
+msgid "%s line %ld"
+msgstr "%s rivi %ld"
+
+msgid "-- More --"
+msgstr "-- Lisää --"
+
+msgid " SPACE/d/j: screen/page/line down, b/u/k: up, q: quit "
+msgstr " SPACE/d/j: ruutu/sivu/rivi alas, b/u/k: ylös, q: lopeta "
+
+msgid "Question"
+msgstr "Kysymys"
+
+msgid ""
+"&Yes\n"
+"&No"
+msgstr ""
+"&Kyllä\n"
+"&Ei"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"Save &All\n"
+"&Discard All\n"
+"&Cancel"
+msgstr ""
+"&Kyllä\n"
+"&Ei\n"
+"&Tallenna kaikki\n"
+"T&uhoa kaikki\n"
+"&Peru"
+
+msgid "Select Directory dialog"
+msgstr "Hakemiston valintaikkuna"
+
+msgid "Save File dialog"
+msgstr "Tallennusikkuna"
+
+msgid "Open File dialog"
+msgstr "Avausikkuna"
+
+msgid "E338: Sorry, no file browser in console mode"
+msgstr "E338: tiedostonselain puuttuu konsolitilasta"
+
+msgid "E766: Insufficient arguments for printf()"
+msgstr "E766: printf():lle ei annettu tarpeeksi argumentteja"
+
+msgid "E807: Expected Float argument for printf()"
+msgstr "E807: Odotettiin Float-argumenttia printf():lle"
+
+msgid "E767: Too many arguments to printf()"
+msgstr "E767: printf():lle annettiin liikaa argumentteja"
+
+msgid "W10: Warning: Changing a readonly file"
+msgstr "W10: Varoitus: Muutetaan kirjoitussuojattua tiedostoa"
+
+msgid "Type number and <Enter> or click with mouse (empty cancels): "
+msgstr "Kirjoita numero ja <Enter> tai valitse hiirellä (tyhjä peruu): "
+
+msgid "Type number and <Enter> (empty cancels): "
+msgstr "Valitse numero ja <Enter> (tyhjä peruu): "
+
+msgid "1 more line"
+msgstr "1 rivi lisää"
+
+msgid "1 line less"
+msgstr "1 rivi vähemmän"
+
+#, c-format
+msgid "%ld more lines"
+msgstr "%ld riviä lisää"
+
+#, c-format
+msgid "%ld fewer lines"
+msgstr "%ld riviä vähemmän"
+
+msgid " (Interrupted)"
+msgstr " (Keskeytetty)"
+
+msgid "Beep!"
+msgstr "Piip!"
+
+msgid "ERROR: "
+msgstr "VIRHE: "
+
+#, c-format
+msgid ""
+"\n"
+"[bytes] total alloc-freed %lu-%lu, in use %lu, peak use %lu\n"
+msgstr ""
+"\n"
+"[tavua] yht. alloc-free %lu-%lu, käytössä %lu, käyttöhuippu %lu\n"
+
+#, c-format
+msgid ""
+"[calls] total re/malloc()'s %lu, total free()'s %lu\n"
+"\n"
+msgstr ""
+"[kutsut] yht. re/malloc() %lu, yht. free() %lu\n"
+"\n"
+
+msgid "E340: Line is becoming too long"
+msgstr "E340: Rivistä tulee liian pitkä"
+
+#, c-format
+msgid "E341: Internal error: lalloc(%ld, )"
+msgstr "E341: Sisäinen virhe: lalloc(%ld, )"
+
+#, c-format
+msgid "E342: Out of memory! (allocating %lu bytes)"
+msgstr "E342: Muisti loppui! (varattaessa %lu tavua)"
+
+#, c-format
+msgid "Calling shell to execute: \"%s\""
+msgstr "Kutsutaan kuorta suorittamaan: %s"
+
+msgid "E545: Missing colon"
+msgstr "E545: Kaksoispiste puuttuu"
+
+msgid "E546: Illegal mode"
+msgstr "E546: Virheellinen tila"
+
+msgid "E547: Illegal mouseshape"
+msgstr "E547: Virheellinen hiiren muoto"
+
+msgid "E548: digit expected"
+msgstr "E548: pitää olla numero"
+
+msgid "E549: Illegal percentage"
+msgstr "E549: Virheellinen prosenttiluku"
+
+msgid "E854: path too long for completion"
+msgstr "E854: polku on liian pitkä täydennykseen"
+
+#, c-format
+msgid ""
+"E343: Invalid path: '**[number]' must be at the end of the path or be "
+"followed by '%s'."
+msgstr ""
+"E343: Virheellinen polku: '**[numero]' kuuluu polun loppuun tai ennen kohtaa "
+"%s."
+
+#, c-format
+msgid "E344: Can't find directory \"%s\" in cdpath"
+msgstr "E344: Hakemistoa %s ei löydy cdpathista"
+
+#, c-format
+msgid "E345: Can't find file \"%s\" in path"
+msgstr "E345: Tiedostoa %s ei löydy polulta"
+
+#, c-format
+msgid "E346: No more directory \"%s\" found in cdpath"
+msgstr "E346: Hakemisto %s ei ole enää cdpathissa"
+
+#, c-format
+msgid "E347: No more file \"%s\" found in path"
+msgstr "E347: Tiedosto %s ei ole enää polulla"
+
+#, c-format
+msgid "E668: Wrong access mode for NetBeans connection info file: \"%s\""
+msgstr "E668: Väärä avaustila NetBeans-yhteyden infotiedostolle: %s"
+
+#, c-format
+msgid "E658: NetBeans connection lost for buffer %ld"
+msgstr "E658: NetBeans-yhteys katkesi puskurille %ld"
+
+msgid "E838: netbeans is not supported with this GUI"
+msgstr "E838: netbeans ei toimi tässä käyttöliittymässä"
+
+msgid "E511: netbeans already connected"
+msgstr "E511: netbeans on yhdistetty jo"
+
+#, c-format
+msgid "E505: %s is read-only (add ! to override)"
+msgstr "E505: %s on kirjoitussuojattu (lisää komentoon ! ohittaaksesi)"
+
+msgid "E349: No identifier under cursor"
+msgstr "E349: Ei tunnistetta osoittimen alla"
+
+msgid "E774: 'operatorfunc' is empty"
+msgstr "E774: operatorfunc on tyhjä"
+
+msgid "E775: Eval feature not available"
+msgstr "E775: Eval ei ole käytettävissä"
+
+msgid "Warning: terminal cannot highlight"
+msgstr "Varoitus: terminaalista puuttuu korostus"
+
+msgid "E348: No string under cursor"
+msgstr "E348: Ei merkkijonoa kursorin alla"
+
+msgid "E352: Cannot erase folds with current 'foldmethod'"
+msgstr "E352: taitoksia ei voi poistaa tällä foldmethodilla"
+
+msgid "E664: changelist is empty"
+msgstr "E664: muutoslista on tyhjä"
+
+msgid "E662: At start of changelist"
+msgstr "E662: Muutoslistan alussa"
+
+msgid "E663: At end of changelist"
+msgstr "E663: Muutoslistan lopussa"
+
+msgid "Type :qa! and press <Enter> to abandon all changes and exit Vim"
+msgstr "Kirjoita :qa! ja <Enter> niin hylkäät muutokset ja lopetat Vimin"
+
+#, c-format
+msgid "1 line %sed 1 time"
+msgstr "1 riviä %s kerran"
+
+#, c-format
+msgid "1 line %sed %d times"
+msgstr "1 riviä %s %d kertaa"
+
+#, c-format
+msgid "%ld lines %sed 1 time"
+msgstr "%ld riviä %s kerran"
+
+#, c-format
+msgid "%ld lines %sed %d times"
+msgstr "%ld riviä %s %d kertaa"
+
+#, c-format
+msgid "%ld lines to indent... "
+msgstr "%ld riviä sisennettävänä..."
+
+msgid "1 line indented "
+msgstr "1 rivi sisennetty "
+
+#, c-format
+msgid "%ld lines indented "
+msgstr "%ld riviä sisennetty "
+
+msgid "E748: No previously used register"
+msgstr "E748: Ei aiemmin käytettyjä rekisterejä"
+
+msgid "cannot yank; delete anyway"
+msgstr "Ei voi kopioida; poista joka tapauksessa"
+
+msgid "1 line changed"
+msgstr "1 rivi muuttui"
+
+#, c-format
+msgid "%ld lines changed"
+msgstr "%ld riviä muuttui"
+
+#, c-format
+msgid "freeing %ld lines"
+msgstr "vapautetaan %ld riviä"
+
+#, c-format
+msgid " into \"%c"
+msgstr " kohteeksi \"%c"
+
+#, c-format
+msgid "block of 1 line yanked%s"
+msgstr "1 rivin lohko kopioitu%s"
+
+#, c-format
+msgid "1 line yanked%s"
+msgstr "1 rivi kopioitu%s"
+
+#, c-format
+msgid "block of %ld lines yanked%s"
+msgstr "lohko %ld riviltä kopioitu%s"
+
+#, c-format
+msgid "%ld lines yanked%s"
+msgstr "%ld riviä kopioitu%s"
+
+#, c-format
+msgid "E353: Nothing in register %s"
+msgstr "E353: Rekisterissä %s ei ole mitään"
+
+msgid ""
+"\n"
+"--- Registers ---"
+msgstr ""
+"\n"
+"--- Rekisterit ---"
+
+msgid "Illegal register name"
+msgstr "Virheellinen rekisterin nimi"
+
+msgid ""
+"\n"
+"# Registers:\n"
+msgstr ""
+"\n"
+"# Rekisterit:\n"
+
+#, c-format
+msgid "E574: Unknown register type %d"
+msgstr "E574: Tuntematon rekisterityyppi %d"
+
+msgid ""
+"E883: search pattern and expression register may not contain two or more "
+"lines"
+msgstr ""
+"E883: hakulauseke- ja -ilmausrekisteri ei voi sisältää kahta tai useampaa "
+"riviä"
+
+#, c-format
+msgid "%ld Cols; "
+msgstr "%ld saraketta, "
+
+#, c-format
+msgid "Selected %s%ld of %ld Lines; %lld of %lld Words; %lld of %lld Bytes"
+msgstr "Valittu %s%ld/%ld riviä, %lld/%lld sanaa, %lld/%lld tavua"
+
+#, c-format
+msgid ""
+"Selected %s%ld of %ld Lines; %lld of %lld Words; %lld of %lld Chars; %lld of "
+"%lld Bytes"
+msgstr ""
+"Valittu %s%ld/%ld riviä, %lld/%lld sanaa, %lld/%lld merkkiä, %lld/%lld tavua"
+
+#, c-format
+msgid "Col %s of %s; Line %ld of %ld; Word %lld of %lld; Byte %lld of %lld"
+msgstr "Sarake %s/%s, Rivi %ld/%ld, sana %lld/%lld, tavu %lld/%lld"
+
+#, c-format
+msgid ""
+"Col %s of %s; Line %ld of %ld; Word %lld of %lld; Char %lld of %lld; Byte "
+"%lld of %lld"
+msgstr ""
+"Sarake %s/%s, rivi %ld/%ld, sana %lld/%lld, merkki %lld/%lld, tavu %lld/%lld"
+
+# Unicode Byte Order Mark
+#, c-format
+msgid "(+%ld for BOM)"
+msgstr "(+%ld BOMista)"
+
+msgid "Thanks for flying Vim"
+msgstr "Kiitos että ajoit Vimiä"
+
+msgid "E518: Unknown option"
+msgstr "E518: Tuntematon asetus"
+
+msgid "E519: Option not supported"
+msgstr "E519: Asetusta ei tueta"
+
+msgid "E520: Not allowed in a modeline"
+msgstr "E520: Ei sallitu modeline-rivillä"
+
+msgid "E846: Key code not set"
+msgstr "E846: Avainkoodi puuttuu"
+
+msgid "E521: Number required after ="
+msgstr "E521: =:n jälkeen tarvitaan luku"
+
+msgid "E522: Not found in termcap"
+msgstr "E522: Puuttuu termcapista"
+
+#, c-format
+msgid "E539: Illegal character <%s>"
+msgstr "E539: Virheellinen merkki <%s>"
+
+#, c-format
+msgid "For option %s"
+msgstr "Asetukselle %s"
+
+msgid "E529: Cannot set 'term' to empty string"
+msgstr "E529: Termiä ei voi asettaa tyhjäksi merkkijonoksi"
+
+msgid "E530: Cannot change term in GUI"
+msgstr "E530: Ei voi vaihtaa termiä GUIssa"
+
+msgid "E531: Use \":gui\" to start the GUI"
+msgstr "E531: Käytä komentoa :gui GUIn käynnistämiseen"
+
+msgid "E589: 'backupext' and 'patchmode' are equal"
+msgstr "E589: backupext ja patchmod ovat samat"
+
+msgid "E834: Conflicts with value of 'listchars'"
+msgstr "E834: listcharsin arvoissa on ristiriitoja"
+
+msgid "E835: Conflicts with value of 'fillchars'"
+msgstr "E835: fillcharsin arvossa on ristiriitoja"
+
+msgid "E617: Cannot be changed in the GTK+ 2 GUI"
+msgstr "E617: Ei voi muuttaa GTK+2-GUIssa"
+
+msgid "E524: Missing colon"
+msgstr "E524: Kaksoispiste puuttuu"
+
+msgid "E525: Zero length string"
+msgstr "E525: Nollan pituinen merkkijono"
+
+#, c-format
+msgid "E526: Missing number after <%s>"
+msgstr "E526: Lukuarvo puuttuu merkkijonon <%s> jälkeen"
+
+msgid "E527: Missing comma"
+msgstr "E527: Pilkku puuttuu"
+
+msgid "E528: Must specify a ' value"
+msgstr "E528: '-arvo pitää antaa"
+
+msgid "E595: contains unprintable or wide character"
+msgstr "E595: Sisältää tulostumattomia tai leveitä merkkejä"
+
+msgid "E596: Invalid font(s)"
+msgstr "E596: Viallisia fontteja"
+
+msgid "E597: can't select fontset"
+msgstr "E597: Fontsetin valinta ei onnistu"
+
+msgid "E598: Invalid fontset"
+msgstr "E598: Viallinen fontset"
+
+msgid "E533: can't select wide font"
+msgstr "E533: Leveän fontin valinta ei onnistu"
+
+msgid "E534: Invalid wide font"
+msgstr "E534: Viallinen leveä fontti"
+
+#, c-format
+msgid "E535: Illegal character after <%c>"
+msgstr "E535: Virheellinen merkki merkin <%c> jälkeen"
+
+msgid "E536: comma required"
+msgstr "E536: pilkku puuttuu"
+
+#, c-format
+msgid "E537: 'commentstring' must be empty or contain %s"
+msgstr "E537: commentstringin pitää olla tyhjä tai sisältää %s"
+
+msgid "E538: No mouse support"
+msgstr "E538: Hiirtä ei tueta"
+
+msgid "E540: Unclosed expression sequence"
+msgstr "E540: Sulkematon lausekesarja"
+
+msgid "E541: too many items"
+msgstr "E541: liikaa kohteita"
+
+msgid "E542: unbalanced groups"
+msgstr "E542: epätasapainoisia ryhmiä"
+
+msgid "E946: Cannot make a terminal with running job modifiable"
+msgstr "E946: Terminaalia jossa suoritetaan komentoa ei voi tehdä muokattavaksi"
+
+msgid "E590: A preview window already exists"
+msgstr "E590: Esikatseluikkuna on jo olemassa"
+
+msgid "W17: Arabic requires UTF-8, do ':set encoding=utf-8'"
+msgstr "W17: Arabialle pitää olla UTF-8:aa, aseta :set encoding=utf-8"
+
+#, c-format
+msgid "E593: Need at least %d lines"
+msgstr "E593: Tarvitaan ainakin %d riviä"
+
+#, c-format
+msgid "E594: Need at least %d columns"
+msgstr "E594: Tarvitaan ainakin %d saraketta"
+
+#, c-format
+msgid "E355: Unknown option: %s"
+msgstr "E355: Tuntematon asetus: %s"
+
+#, c-format
+msgid "E521: Number required: &%s = '%s'"
+msgstr "E521: tarvitaan luku: &%s = '%s'"
+
+msgid ""
+"\n"
+"--- Terminal codes ---"
+msgstr ""
+"\n"
+"--- Terminaalikoodit ---"
+
+msgid ""
+"\n"
+"--- Global option values ---"
+msgstr ""
+"\n"
+"--- Globaalit asetukset ---"
+
+msgid ""
+"\n"
+"--- Local option values ---"
+msgstr ""
+"\n"
+"--- Paikalliset asetukset ---"
+
+msgid ""
+"\n"
+"--- Options ---"
+msgstr ""
+"\n"
+"--- Asetukset ---"
+
+msgid "E356: get_varp ERROR"
+msgstr "E356: get_varp-virhe"
+
+#, c-format
+msgid "E357: 'langmap': Matching character missing for %s"
+msgstr "E357: langmap: Merkkiin %s täsmäävä merkki puuttuu"
+
+#, c-format
+msgid "E358: 'langmap': Extra characters after semicolon: %s"
+msgstr "E358: langmap: ylimääräisiä merkkejä puolipisteen jälkeen: %s"
+
+msgid "cannot open "
+msgstr "ei voi avata "
+
+msgid "VIM: Can't open window!\n"
+msgstr "VIM: Ei voi avata ikkunaa\n"
+
+msgid "Need Amigados version 2.04 or later\n"
+msgstr "Amigados 2.04 tai uudempi tarvitaan\n"
+
+#, c-format
+msgid "Need %s version %ld\n"
+msgstr "Tarvitaan %s versio %ld\n"
+
+msgid "Cannot open NIL:\n"
+msgstr "Ei voi avata NILiä:\n"
+
+msgid "Cannot create "
+msgstr "Ei voi luoda "
+
+#, c-format
+msgid "Vim exiting with %d\n"
+msgstr "Vim sulkeutuu koodilla %d\n"
+
+msgid "cannot change console mode ?!\n"
+msgstr "ei voi vaihtaa konsolitilaa?\n"
+
+msgid "mch_get_shellsize: not a console??\n"
+msgstr "mch_get_shellsize: ei ole konsoli?\n"
+
+msgid "E360: Cannot execute shell with -f option"
+msgstr "E360: Kuorta ei voi avata asetuksella -f"
+
+msgid "Cannot execute "
+msgstr "Ei voi suorittaa "
+
+msgid "shell "
+msgstr "kuori "
+
+msgid " returned\n"
+msgstr " palautti\n"
+
+msgid "ANCHOR_BUF_SIZE too small."
+msgstr "ANCHOR_BUF_SIZE liian pieni."
+
+msgid "I/O ERROR"
+msgstr "IO-virhe"
+
+msgid "Message"
+msgstr "Viesti"
+
+msgid "E237: Printer selection failed"
+msgstr "E237: Tulostimen valinta epäonnistui"
+
+#, c-format
+msgid "to %s on %s"
+msgstr "tulostimelle %s kohteessa %s"
+
+#, c-format
+msgid "E613: Unknown printer font: %s"
+msgstr "E613: Tuntematon tulostimen fontti: %s"
+
+#, c-format
+msgid "E238: Print error: %s"
+msgstr "E238: Tulostinvirhe: %s"
+
+#, c-format
+msgid "Printing '%s'"
+msgstr "Tulostetaan %s"
+
+#, c-format
+msgid "E244: Illegal charset name \"%s\" in font name \"%s\""
+msgstr "E244: Virheellinen merkistön nimi %s fontin nimessä %s"
+
+#, c-format
+msgid "E244: Illegal quality name \"%s\" in font name \"%s\""
+msgstr "E244: Virheellinen laatunimi %s fontin nimessä %s"
+
+#, c-format
+msgid "E245: Illegal char '%c' in font name \"%s\""
+msgstr "E245: Virheellinen merkki %c fontin nimessä %s"
+
+#, c-format
+msgid "Opening the X display took %ld msec"
+msgstr "X-näytön avaus vei %ld millisekuntia"
+
+msgid ""
+"\n"
+"Vim: Got X error\n"
+msgstr ""
+"\n"
+"Vim: X-virhe\n"
+
+msgid "Testing the X display failed"
+msgstr "X-näytön testaus epäonnistui"
+
+msgid "Opening the X display timed out"
+msgstr "X-näytön avaus aikakatkaistiin"
+
+# mikä security context?
+msgid ""
+"\n"
+"Could not get security context for "
+msgstr ""
+"\n"
+"Ei saatu turvallisuuskontekstia kohteelle "
+
+msgid ""
+"\n"
+"Could not set security context for "
+msgstr ""
+"\n"
+"Ei voitu asettaa turvallisuuskontekstia kohteelle "
+
+#, c-format
+msgid "Could not set security context %s for %s"
+msgstr "Ei voitu asettaa turvallisuuskontekstia %s kohteelle %s"
+
+# mikä security context?
+#, c-format
+msgid "Could not get security context %s for %s. Removing it!"
+msgstr "Ei saatu turvallisuuskontekstia %s kohteelle %s ja se poistetaan"
+
+msgid ""
+"\n"
+"Cannot execute shell sh\n"
+msgstr ""
+"\n"
+"Kuoren sh suoritus ei onnistu\n"
+
+msgid ""
+"\n"
+"shell returned "
+msgstr ""
+"\n"
+"kuoren palautusarvo "
+
+msgid ""
+"\n"
+"Cannot create pipes\n"
+msgstr ""
+"\n"
+"Putkia ei voi tehdä\n"
+
+msgid ""
+"\n"
+"Cannot fork\n"
+msgstr ""
+"\n"
+"Ei voi haarauttaa\n"
+
+msgid ""
+"\n"
+"Cannot execute shell "
+msgstr ""
+"\n"
+"Kuoren suoritus ei onnistu "
+
+msgid ""
+"\n"
+"Command terminated\n"
+msgstr ""
+"\n"
+"Komento loppui\n"
+
+msgid "XSMP lost ICE connection"
+msgstr "XSMP kadotti ICE-yhteyden"
+
+#, c-format
+msgid "dlerror = \"%s\""
+msgstr "dlerror = %s"
+
+msgid "Opening the X display failed"
+msgstr "X-näytön avaus epäonnistui"
+
+msgid "XSMP handling save-yourself request"
+msgstr "XSMP käsittelee save-yourself-pyyntöä"
+
+msgid "XSMP opening connection"
+msgstr "XSMP avaa yhteyttä"
+
+msgid "XSMP ICE connection watch failed"
+msgstr "XSMP:n ICE-yhteyden tarkkailu epäonnistui"
+
+#, c-format
+msgid "XSMP SmcOpenConnection failed: %s"
+msgstr "XSMP SmcOpenConnection epäonnistui: %s"
+
+msgid "At line"
+msgstr "Rivillä"
+
+msgid "Could not load vim32.dll!"
+msgstr "Vim32.dll:ää ei voitu ladata"
+
+msgid "VIM Error"
+msgstr "VIM-virhe"
+
+msgid "Could not fix up function pointers to the DLL!"
+msgstr "Ei voitu korjata funktio-osoittimia DLL:ssä"
+
+#, c-format
+msgid "Vim: Caught %s event\n"
+msgstr "Vim: Napattiin %s\n"
+
+msgid "close"
+msgstr "sulkeminen"
+
+msgid "logoff"
+msgstr "uloskirjautuminen"
+
+msgid "shutdown"
+msgstr "sammutus"
+
+msgid "E371: Command not found"
+msgstr "E371: Komentoa ei löydy"
+
+msgid ""
+"VIMRUN.EXE not found in your $PATH.\n"
+"External commands will not pause after completion.\n"
+"See :help win32-vimrun for more information."
+msgstr ""
+"VIMRUN.EXEä ei löydy muuttujasta $PATH.\n"
+"Ulkoiset komennot eivät pysähdy suorituksen lopussa.\n"
+"Lisätietoja komennolla :help win32-vimrun"
+
+msgid "Vim Warning"
+msgstr "Vim-varoitus"
+
+#, c-format
+msgid "shell returned %d"
+msgstr "kuori palautti arvon %d"
+
+#, c-format
+msgid "E372: Too many %%%c in format string"
+msgstr "E372: Liikaa %%%c-juttuja muotoilumerkkijonossa"
+
+#, c-format
+msgid "E373: Unexpected %%%c in format string"
+msgstr "E373: Odottamaton %%%c muotoilumerkkijonossa"
+
+msgid "E374: Missing ] in format string"
+msgstr "E374: ] puuttuu muotoilemerkkijonosta"
+
+#, c-format
+msgid "E375: Unsupported %%%c in format string"
+msgstr "E375: Tukematon %%%c muotoilumerkkijonossa"
+
+#, c-format
+msgid "E376: Invalid %%%c in format string prefix"
+msgstr "E376: Virheellinen %%%c muotoilumerkkijonon alussa"
+
+#, c-format
+msgid "E377: Invalid %%%c in format string"
+msgstr "E377: Virheellinen %%%c muotoilumerkkijonossa"
+
+msgid "E378: 'errorformat' contains no pattern"
+msgstr "E378: errorformatissa ei ole kuvioita"
+
+msgid "E379: Missing or empty directory name"
+msgstr "E379: Puuttuva tai tyhjä hakemiston nimi"
+
+msgid "E553: No more items"
+msgstr "E553: Ei enää kohteita"
+
+msgid "E924: Current window was closed"
+msgstr "E924: Nykyinen ikkuna on suljettu"
+
+msgid "E925: Current quickfix was changed"
+msgstr "E925: Nykyinen quickfix on muuttunut"
+
+msgid "E926: Current location list was changed"
+msgstr "E926: Nykyinen sijaintiluettelo on muuttunut"
+
+#, c-format
+msgid "(%d of %d)%s%s: "
+msgstr "(%d/%d)%s%s: "
+
+msgid " (line deleted)"
+msgstr " (rivi poistettu)"
+
+#, c-format
+msgid "%serror list %d of %d; %d errors "
+msgstr "%svirhelista %d/%d, %d virhettä"
+
+msgid "E380: At bottom of quickfix stack"
+msgstr "E380: quickfix-pinon pohjalla"
+
+msgid "E381: At top of quickfix stack"
+msgstr "E381: quickfix-pinon huipulla"
+
+msgid "No entries"
+msgstr "Ei kenttiä"
+
+msgid "Error file"
+msgstr "Virhetiedosto"
+
+msgid "E683: File name missing or invalid pattern"
+msgstr "E683: Tiedostonimi puuttuu tai kuvio on viallinen"
+
+#, c-format
+msgid "Cannot open file \"%s\""
+msgstr "Tiedostoa %s ei voi avata"
+
+msgid "E681: Buffer is not loaded"
+msgstr "E681: Puskuria ei ole ladattu"
+
+msgid "E777: String or List expected"
+msgstr "E777: Pitää olla merkkijono tai lista"
+
+#, c-format
+msgid "E369: invalid item in %s%%[]"
+msgstr "E369: virheellinen olio kohdassa %s%%[]"
+
+#, c-format
+msgid "E769: Missing ] after %s["
+msgstr "E769: ] puuttuu merkinnän %s[ jäljestä"
+
+msgid "E944: Reverse range in character class"
+msgstr "E944: Merkiluokan arvoalua on takaperin"
+
+msgid "E945: Range too large in character class"
+msgstr "E945: Liian laaja valikoima merkkiluokassa"
+
+#, c-format
+msgid "E53: Unmatched %s%%("
+msgstr "E53: Pariton %s%%("
+
+#, c-format
+msgid "E54: Unmatched %s("
+msgstr "E54: Pariton %s("
+
+#, c-format
+msgid "E55: Unmatched %s)"
+msgstr "E55: Pariton %s)"
+
+msgid "E66: \\z( not allowed here"
+msgstr "E66: \\z( ei ole sallittu tässä"
+
+msgid "E67: \\z1 - \\z9 not allowed here"
+msgstr "E67: \\z1 jne. ei ole sallittu tässä"
+
+#, c-format
+msgid "E69: Missing ] after %s%%["
+msgstr "E69: ] puuttuu merkinnän %s%%[ jäljestä"
+
+#, c-format
+msgid "E70: Empty %s%%[]"
+msgstr "E70: Tyhjä %s%%[]"
+
+msgid "E65: Illegal back reference"
+msgstr "E65: Virheellinen täsmäysviittaus"
+
+msgid "E339: Pattern too long"
+msgstr "E339: Liian pitkä kuvio"
+
+msgid "E50: Too many \\z("
+msgstr "E50: Liikaa merkkejä \\z("
+
+#, c-format
+msgid "E51: Too many %s("
+msgstr "E51: Liikaa merkkejä %s("
+
+msgid "E52: Unmatched \\z("
+msgstr "E52: Pariton \\z("
+
+#, c-format
+msgid "E59: invalid character after %s@"
+msgstr "E59: virheellinen merkki kohdan %s@ jälkeen"
+
+#, c-format
+msgid "E60: Too many complex %s{...}s"
+msgstr "E60: Liikaa monimutkaisia ilmauksia %s{...}s"
+
+#, c-format
+msgid "E61: Nested %s*"
+msgstr "E61: Sisäkkäistetty %s*"
+
+#, c-format
+msgid "E62: Nested %s%c"
+msgstr "E62: Sisäkkäistetty %s%c"
+
+msgid "E63: invalid use of \\_"
+msgstr "E63: väärinkäytetty \\_"
+
+#, c-format
+msgid "E64: %s%c follows nothing"
+msgstr "E64: %s%c jälkeen ei minkään"
+
+msgid "E68: Invalid character after \\z"
+msgstr "E68: Virheellinen merkki ilmauksen \\z jälkeen"
+
+#, c-format
+msgid "E678: Invalid character after %s%%[dxouU]"
+msgstr "E678: Virheellinen merkki merkinnän %s%%[dxouU] jäljessä"
+
+#, c-format
+msgid "E71: Invalid character after %s%%"
+msgstr "E71: Virheellinen merkki merkinnän %s%% jäljessä"
+
+#, c-format
+msgid "E554: Syntax error in %s{...}"
+msgstr "E554: Syntaksivirhe ilmauksessa %s{...}"
+
+msgid "External submatches:\n"
+msgstr "Ulkoisia alitäsmäyksiä:\n"
+
+#, c-format
+msgid "E888: (NFA regexp) cannot repeat %s"
+msgstr "E888: (NFA-säänn. ilmaus) ei voi toistaa kohdetta %s"
+
+msgid ""
+"E864: \\%#= can only be followed by 0, 1, or 2. The automatic engine will be "
+"used "
+msgstr ""
+"E864: \\%#=-merkkien perään voi tulla vain 0, 1 tai 2. Käytetään "
+"automaattista engineä "
+
+msgid "Switching to backtracking RE engine for pattern: "
+msgstr "Vaihdetaan käyttämään backtrackkaavaa RE-engineä ilmaukselle: "
+
+msgid "E865: (NFA) Regexp end encountered prematurely"
+msgstr "E865: (NFA) Säännöllisen ilmauksen ennenaikainen loppu"
+
+#, c-format
+msgid "E866: (NFA regexp) Misplaced %c"
+msgstr "E866: (NFA-regexp) %c väärässä paikassa"
+
+#, c-format
+msgid "E877: (NFA regexp) Invalid character class: %ld"
+msgstr "E877: (NFA regexp) Virheellinen merkkiluokka: %ld"
+
+#, c-format
+msgid "E867: (NFA) Unknown operator '\\z%c'"
+msgstr "E867: (NFA) Tuntematon operaattori '\\z%c'"
+
+#, c-format
+msgid "E867: (NFA) Unknown operator '\\%%%c'"
+msgstr "E867: (NFA) Tuntematon operaattori '\\%%%c'"
+
+msgid "E868: Error building NFA with equivalence class!"
+msgstr "E868: Virhe NFA:n ekvivalenssiluokkia tekemisessä"
+
+#, c-format
+msgid "E869: (NFA) Unknown operator '\\@%c'"
+msgstr "E869: (NFA) Tuntematon operaattori '\\@%c'"
+
+msgid "E870: (NFA regexp) Error reading repetition limits"
+msgstr "E870: (NFA regexp) Virhe luettaessa toiston määriä"
+
+msgid "E871: (NFA regexp) Can't have a multi follow a multi"
+msgstr "E871: (NFA regexp) Multi ei voi seurata multia"
+
+msgid "E872: (NFA regexp) Too many '('"
+msgstr "E872: (NFA regexp) Liian monta suljetta '('"
+
+msgid "E879: (NFA regexp) Too many \\z("
+msgstr "E879: (NFA regexp) Liikaa merkkejä \\z("
+
+msgid "E873: (NFA regexp) proper termination error"
+msgstr "E873: (NFA regexp) oikea lopetusvirhe"
+
+msgid "E874: (NFA) Could not pop the stack!"
+msgstr "E874: (NFA) Ei voida poistaa pinosta"
+
+msgid ""
+"E875: (NFA regexp) (While converting from postfix to NFA), too many states "
+"left on stack"
+msgstr ""
+"E875: (NFA regexp) (Muunnettaessa postfixistä NFA:ksi), liikaa tiloja "
+"jäljellä pinossa"
+
+msgid "E876: (NFA regexp) Not enough space to store the whole NFA "
+msgstr "E876: (NFA regexp) Tila ei riitä NFA:n tallentamiseen"
+
+msgid "E878: (NFA) Could not allocate memory for branch traversal!"
+msgstr "E878: (NFA) Ei voitu allokoida muistia polkujen läpikäyntiin"
+
+msgid ""
+"Could not open temporary log file for writing, displaying on stderr... "
+msgstr ""
+"Ei voitu avata väliaikaislokitiedosta kirjoittamista varten, joten virheet "
+"näytetään vakiovirhevirrassa. "
+
+#, c-format
+msgid "(NFA) COULD NOT OPEN %s !"
+msgstr "(NFA) EI VOI AVATA KOHDETTA %s"
+
+msgid "Could not open temporary log file for writing "
+msgstr "Väliaikaislokitiedoston avaus kirjoittamista varten ei onnistu"
+
+# tiloja
+msgid " VREPLACE"
+msgstr " VKORVAUS"
+
+msgid " REPLACE"
+msgstr " KORVAUS"
+
+msgid " REVERSE"
+msgstr " KÄÄNTEIS"
+
+msgid " INSERT"
+msgstr " SYÖTTÖ"
+
+msgid " (insert)"
+msgstr " (syöttö)"
+
+msgid " (replace)"
+msgstr " (korvaus)"
+
+msgid " (vreplace)"
+msgstr " (vkorvaus)"
+
+msgid " Hebrew"
+msgstr " Heprea"
+
+msgid " Arabic"
+msgstr " Arabia"
+
+msgid " (paste)"
+msgstr " (liitos)"
+
+msgid " VISUAL"
+msgstr " VALINTA"
+
+msgid " VISUAL LINE"
+msgstr " VALINTARIVI"
+
+msgid " VISUAL BLOCK"
+msgstr " VALINTALOHKO"
+
+msgid " SELECT"
+msgstr " WALINTA"
+
+msgid " SELECT LINE"
+msgstr " WALINTARIVI"
+
+msgid " SELECT BLOCK"
+msgstr " WALINTALOHKO"
+
+msgid "recording"
+msgstr "tallennetaan"
+
+#, c-format
+msgid "E383: Invalid search string: %s"
+msgstr "E383: Viallinen hakujono: %s"
+
+#, c-format
+msgid "E384: search hit TOP without match for: %s"
+msgstr "E384: Haku pääsi alkuun löytämättä jonoa: %s"
+
+#, c-format
+msgid "E385: search hit BOTTOM without match for: %s"
+msgstr "E385: Haku pääsi loppuun löytämättä jonoa: %s"
+
+msgid "E386: Expected '?' or '/' after ';'"
+msgstr "E386: ;:n jälkeen pitää olla ? tai /"
+
+msgid " (includes previously listed match)"
+msgstr " (sisältää viimeksi luetellun täsmäyksen)"
+
+msgid "--- Included files "
+msgstr "--- Sisällytetyt tiedostot "
+
+msgid "not found "
+msgstr "ei löytynyt "
+
+msgid "in path ---\n"
+msgstr "polusta ---\n"
+
+msgid " (Already listed)"
+msgstr " (Jo lueteltu)"
+
+msgid " NOT FOUND"
+msgstr " EI LÖYTYNYT"
+
+#, c-format
+msgid "Scanning included file: %s"
+msgstr "Haku sisälsi tiedoston: %s"
+
+#, c-format
+msgid "Searching included file %s"
+msgstr "Haku sisälsi tiedoston %s"
+
+msgid "E387: Match is on current line"
+msgstr "E387: Täsmäys tällä rivillä"
+
+msgid "All included files were found"
+msgstr "Kaikki sisällytetyt rivit löytyivät"
+
+msgid "No included files"
+msgstr "Ei sisällytettyjä tiedostoja"
+
+msgid "E388: Couldn't find definition"
+msgstr "E388: Määritelmä ei löydy"
+
+msgid "E389: Couldn't find pattern"
+msgstr "E389: kuvio ei löydy"
+
+msgid "Substitute "
+msgstr "Korvaa "
+
+#, c-format
+msgid ""
+"\n"
+"# Last %sSearch Pattern:\n"
+"~"
+msgstr ""
+"\n"
+"# Edellinen %sHakulauseke:\n"
+"~"
+
+msgid "E756: Spell checking is not enabled"
+msgstr "E756: Oikaisuluku ei ole päällä"
+
+#, c-format
+msgid "Warning: Cannot find word list \"%s_%s.spl\" or \"%s_ascii.spl\""
+msgstr "Varoitus: Ei löydetty sanalistaa %s_%s.spl tai %s_ascii.spl"
+
+#, c-format
+msgid "Warning: Cannot find word list \"%s.%s.spl\" or \"%s.ascii.spl\""
+msgstr "Varoitus: Ei löydetty sanalistaa %s.%s.spl tai %s.ascii.spl"
+
+msgid "E797: SpellFileMissing autocommand deleted buffer"
+msgstr "E797: SpellFileMissing autocommand poisti puskurin"
+
+#, c-format
+msgid "Warning: region %s not supported"
+msgstr "Varoitus: osaa %s ei tueta"
+
+msgid "Sorry, no suggestions"
+msgstr "ei ehdotuksia"
+
+#, c-format
+msgid "Sorry, only %ld suggestions"
+msgstr "vain %ld ehdotusta"
+
+#, c-format
+msgid "Change \"%.*s\" to:"
+msgstr "Muuta %.*s:"
+
+#, c-format
+msgid " < \"%.*s\""
+msgstr " < %.*s"
+
+msgid "E752: No previous spell replacement"
+msgstr "E752: Ei edellistä oikaisulukukorjausta"
+
+#, c-format
+msgid "E753: Not found: %s"
+msgstr "E753: Ei löytynyt: %s"
+
+msgid "E758: Truncated spell file"
+msgstr "E758: Oikolukutiedosto katkaistu"
+
+#, c-format
+msgid "Trailing text in %s line %d: %s"
+msgstr "Tekstiä rivin perässä tiedostossa %s rivillä %d: %s"
+
+#, c-format
+msgid "Affix name too long in %s line %d: %s"
+msgstr "Affiksin nimi on liian pitkä tiedostossa %s rivillä %d: %s"
+
+msgid "E761: Format error in affix file FOL, LOW or UPP"
+msgstr "E761: Affiksitiedoston FOL-, LOW- tai UPP-muotovirhe "
+
+msgid "E762: Character in FOL, LOW or UPP is out of range"
+msgstr "E762: Merkki FOL:ssä, LOW:ssä tai UPP:ssä ei kuulu arvoalueeseen"
+
+msgid "Compressing word tree..."
+msgstr "Tiivistetään sanapuuta..."
+
+#, c-format
+msgid "Reading spell file \"%s\""
+msgstr "Luetaan oikaisulukutiedosta %s"
+
+msgid "E757: This does not look like a spell file"
+msgstr "E757: Ei vaikuta oikaisulukutiedostolta"
+
+msgid "E771: Old spell file, needs to be updated"
+msgstr "E771: Vanha oikaisulukutiedosto vaatii päivittämistä"
+
+msgid "E772: Spell file is for newer version of Vim"
+msgstr "E772: Oikaisulukutiedosto on uudemmalle Vimille"
+
+msgid "E770: Unsupported section in spell file"
+msgstr "E770: Tukematon osio oikaisulukutiedostossa"
+
+#, c-format
+msgid "E778: This does not look like a .sug file: %s"
+msgstr "E778: Ei vaikuta .sug-tiedostolta: %s"
+
+#, c-format
+msgid "E779: Old .sug file, needs to be updated: %s"
+msgstr "E779: Vanha .sug-tiedosto pitää päivittää: %s"
+
+#, c-format
+msgid "E780: .sug file is for newer version of Vim: %s"
+msgstr "E780: .sug-tiedosto on uudemmalle Vimille: %s"
+
+#, c-format
+msgid "E781: .sug file doesn't match .spl file: %s"
+msgstr "E781: .sug-tiedosto ei täsmää .spl-tiedostoon: %s"
+
+#, c-format
+msgid "E782: error while reading .sug file: %s"
+msgstr "E782: virhe luettaessa .sug-tiedostoa: %s"
+
+#, c-format
+msgid "Reading affix file %s..."
+msgstr "Luetaan affiksitiedostoa %s..."
+
+#, c-format
+msgid "Conversion failure for word in %s line %d: %s"
+msgstr "Muunnosvirhe sanalle %s rivillä %d: %s"
+
+#, c-format
+msgid "Conversion in %s not supported: from %s to %s"
+msgstr "Muunnosta kohteessa %s ei tueta: kohteesta %s kohteeseen %s"
+
+#, c-format
+msgid "Conversion in %s not supported"
+msgstr "Muutosta kohteessa %s ei tueta"
+
+#, c-format
+msgid "Invalid value for FLAG in %s line %d: %s"
+msgstr "Tuntematon FLAG kohteessa %s rivillä %d: %s"
+
+#, c-format
+msgid "FLAG after using flags in %s line %d: %s"
+msgstr "FLAG kohteessa %s lippujen jälkeen rivillä %d: %s"
+
+#, c-format
+msgid ""
+"Defining COMPOUNDFORBIDFLAG after PFX item may give wrong results in %s line "
+"%d"
+msgstr ""
+"COMPOUNDFORBIDFLAG PFX:n jälkeen voi antaa vääriä tuloksia kohteessa %s "
+"rivillä %d"
+
+#, c-format
+msgid ""
+"Defining COMPOUNDPERMITFLAG after PFX item may give wrong results in %s line "
+"%d"
+msgstr ""
+"COMPOUNDPERMITFLAG PFX:n jälkeen voi antaa vääriä tuloksia kohteessa %s "
+"rivillä %d"
+
+#, c-format
+msgid "Wrong COMPOUNDRULES value in %s line %d: %s"
+msgstr "Väärä COMPOUNDRULES-arvo kohteessa %s rivillä %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDWORDMAX value in %s line %d: %s"
+msgstr "Väärä COMPOUNDWORDMAX-arvo kohteessa %s rivillä %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDMIN value in %s line %d: %s"
+msgstr "Väärä COMPOUNDMIN-arvo kohteessa %s rivillä %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDSYLMAX value in %s line %d: %s"
+msgstr "Väärä COMPOUNDSYLMAX-arvo kohteessa %s rivillä %d: %s"
+
+#, c-format
+msgid "Wrong CHECKCOMPOUNDPATTERN value in %s line %d: %s"
+msgstr "Väärä CHECKCOMPOUNDPATTERN-arvo kohteessa %s rivillä %d: %s"
+
+#, c-format
+msgid "Different combining flag in continued affix block in %s line %d: %s"
+msgstr ""
+"Eri yhdistelmälippu jatketussa affiksilohkossa kohteessa %s rivillä %d: %s"
+
+#, c-format
+msgid "Duplicate affix in %s line %d: %s"
+msgstr "Kaksoiskappale affiksista kohteessa %s rivillä %d: %s"
+
+#, c-format
+msgid ""
+"Affix also used for BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST in %s "
+"line %d: %s"
+msgstr ""
+"Affiksia käytetty myös BAD-, RARE-, KEEPCASE-, NEEDAFFIX-, NEEDCOMPOUND- tai "
+"NOSUGGEST-arvossa kohteessa %s rivillä %d: %s"
+
+#, c-format
+msgid "Expected Y or N in %s line %d: %s"
+msgstr "Odotettiin Y:tä tai N:ää kohteessa %s rivillä %d: %s"
+
+#, c-format
+msgid "Broken condition in %s line %d: %s"
+msgstr "Viallinen ehto kohteessa %s rivillä %d: %s"
+
+#, c-format
+msgid "Expected REP(SAL) count in %s line %d"
+msgstr "Odotettiin REP(SAL)-arvoa kohteessa %s rivillä %d"
+
+#, c-format
+msgid "Expected MAP count in %s line %d"
+msgstr "Odotettiin MAP-arvoa kohteessa %s rivillä %d"
+
+#, c-format
+msgid "Duplicate character in MAP in %s line %d"
+msgstr "Kaksoiskappale merkistä MAP:ssä kohteessa %s rivillä %d"
+
+#, c-format
+msgid "Unrecognized or duplicate item in %s line %d: %s"
+msgstr "Tunnistamaton tai kaksoiskappale arvosta kohteessa %s rivillä %d: %s"
+
+#, c-format
+msgid "Missing FOL/LOW/UPP line in %s"
+msgstr "Puuttuva FOL, LOW tai UPP rivi kohteessa %s"
+
+msgid "COMPOUNDSYLMAX used without SYLLABLE"
+msgstr "COMPOUNDSYLMAX ilman SYLLABLEa"
+
+msgid "Too many postponed prefixes"
+msgstr "Liikaa jälkikäteistettyjä prefiksejä"
+
+msgid "Too many compound flags"
+msgstr "Liikaa yhdyssanalippuja"
+
+msgid "Too many postponed prefixes and/or compound flags"
+msgstr "Liikaa jälkikäteistettyjä prefiksejä tai yhdyssanalippuja"
+
+#, c-format
+msgid "Missing SOFO%s line in %s"
+msgstr "Puuttuva SOFO%s-rivi kohteessa %s"
+
+#, c-format
+msgid "Both SAL and SOFO lines in %s"
+msgstr "SAL- ja SOFO-rivit kohteessa %s"
+
+#, c-format
+msgid "Flag is not a number in %s line %d: %s"
+msgstr "Lippu ei ole lukuarvo kohteessa %s rivillä %d: %s"
+
+#, c-format
+msgid "Illegal flag in %s line %d: %s"
+msgstr "Tuntematon lippu kohteessa %s rivillä %d: %s"
+
+#, c-format
+msgid "%s value differs from what is used in another .aff file"
+msgstr "%s-arvo eroaa toisessa .aff-tiedostossa olevasta"
+
+#, c-format
+msgid "Reading dictionary file %s..."
+msgstr "Luetaan sanakirjatiedostoa %s"
+
+#, c-format
+msgid "E760: No word count in %s"
+msgstr "E760: Ei sanalaskuria kohteessa %s"
+
+#, c-format
+msgid "line %6d, word %6d - %s"
+msgstr "rivi %6d, sana %6d - %s"
+
+#, c-format
+msgid "Duplicate word in %s line %d: %s"
+msgstr "Toistettu sana kohteessa %s rivillä %d: %s"
+
+#, c-format
+msgid "First duplicate word in %s line %d: %s"
+msgstr "Ensimmäinen kappale kohteessa %s rivillä %d: %s"
+
+#, c-format
+msgid "%d duplicate word(s) in %s"
+msgstr "toistettuja sanoja %d kohteessa %s"
+
+#, c-format
+msgid "Ignored %d word(s) with non-ASCII characters in %s"
+msgstr "Ei-ASCII-merkkien takia ohitettuja sanoja %d kohteessa %s"
+
+#, c-format
+msgid "Reading word file %s..."
+msgstr "Luetaan sanatiedostoa %s..."
+
+#, c-format
+msgid "Duplicate /encoding= line ignored in %s line %d: %s"
+msgstr "Toistettu /encoding= ohitettu kohteessa %s rivillä %d: %s"
+
+#, c-format
+msgid "/encoding= line after word ignored in %s line %d: %s"
+msgstr "/encoding= sanojen jälkeen ohitettu kohteessa %s rivillä %d: %s"
+
+#, c-format
+msgid "Duplicate /regions= line ignored in %s line %d: %s"
+msgstr "Toistettu /regions= ohitettu kohteessa %s rivillä %d: %s"
+
+#, c-format
+msgid "Too many regions in %s line %d: %s"
+msgstr "Liikaa regionseja kohteessa %s rivillä %d: %s"
+
+#, c-format
+msgid "/ line ignored in %s line %d: %s"
+msgstr "/ ohitettu kohteessa %s rivillä %d: %s"
+
+#, c-format
+msgid "Invalid region nr in %s line %d: %s"
+msgstr "Virheellinen region-luku kohteessa %s rivillä %d: %s"
+
+#, c-format
+msgid "Unrecognized flags in %s line %d: %s"
+msgstr "Tunnistamaton lippu kohteessa %s rivillä %d: %s"
+
+#, c-format
+msgid "Ignored %d words with non-ASCII characters"
+msgstr "Ei-ASCIIn takia ohitettuja sanoja %d"
+
+msgid "E845: Insufficient memory, word list will be incomplete"
+msgstr "E845: Muisti ei riitä, sanalista jää keskeneräiseksi"
+
+#, c-format
+msgid "Compressed %d of %d nodes; %d (%d%%) remaining"
+msgstr "Tiivistetty %d/%d noodia. %d (%d %%) jäljellä"
+
+msgid "Reading back spell file..."
+msgstr "Luetaan taas oikaisulukutiedostoa..."
+
+msgid "Performing soundfolding..."
+msgstr "Ääntämyksen mukaan yhdistellään..."
+
+#, c-format
+msgid "Number of words after soundfolding: %ld"
+msgstr "Sanoja ääntämysyhdistelyn jälkeen: %ld"
+
+#, c-format
+msgid "Total number of words: %d"
+msgstr "Sanoja yhteensä: %d"
+
+#, c-format
+msgid "Writing suggestion file %s..."
+msgstr "Kirjoitetaan ehdotustiedostoa %s..."
+
+#, c-format
+msgid "Estimated runtime memory use: %d bytes"
+msgstr "Arvioitu käyttömuisti: %d tavua"
+
+msgid "E751: Output file name must not have region name"
+msgstr "E751: Tulostetiedostonimessä ei saa olla alueen nimeä"
+
+msgid "E754: Only up to 8 regions supported"
+msgstr "E754: Enintään 8 aluetta tuetaan"
+
+#, c-format
+msgid "E755: Invalid region in %s"
+msgstr "E755: Virheellinen alue kohteelle %s"
+
+msgid "Warning: both compounding and NOBREAK specified"
+msgstr "Varoitus: sekä yhdyssanamuodostus että NOBREAK käytössä"
+
+#, c-format
+msgid "Writing spell file %s..."
+msgstr "Kirjoitetaan oikaisulukutiedostoa %s..."
+
+msgid "Done!"
+msgstr "Valmista."
+
+#, c-format
+msgid "E765: 'spellfile' does not have %ld entries"
+msgstr "E765: spellfile ei sisällä %ld kohtaa"
+
+#, c-format
+msgid "Word '%.*s' removed from %s"
+msgstr "Sana %.*s poistettu kohteesta %s"
+
+#, c-format
+msgid "Word '%.*s' added to %s"
+msgstr "Sana %.*s lisätty kohteeseen %s"
+
+msgid "E763: Word characters differ between spell files"
+msgstr "E763: Sanan merkit muuttuvat oikaisulukutiedostojen välillä"
+
+msgid "E783: duplicate char in MAP entry"
+msgstr "E783: kaksoiskappale merkistä MAP-kohdassa"
+
+msgid "No Syntax items defined for this buffer"
+msgstr "Ei syntaksikohteita tälle puskurille"
+
+msgid "syntax conceal on"
+msgstr "syntaksin piilotus päällä"
+
+msgid "syntax conceal off"
+msgstr "syntaksin piilotus pois"
+
+#, c-format
+msgid "E390: Illegal argument: %s"
+msgstr "E390: Virheellinen argumentti: %s"
+
+msgid "syntax case ignore"
+msgstr "syntaksin merkkitason ohitus "
+
+msgid "syntax case match"
+msgstr "syntaksin merkkitason täsmäys"
+
+msgid "syntax spell toplevel"
+msgstr "syntaksin oikaisuluku päätasolla"
+
+msgid "syntax spell notoplevel"
+msgstr "syntaksin oikaisuluku ei-päätasolla"
+
+msgid "syntax spell default"
+msgstr "syntaksin oikaisuluku oletusarvolla"
+
+msgid "syntax iskeyword "
+msgstr "syntax iskeyword "
+
+#, c-format
+msgid "E391: No such syntax cluster: %s"
+msgstr "E391: Syntaksiklusteri puuttuu: %s"
+
+msgid "syncing on C-style comments"
+msgstr "synkkaa C-tyylin kommentteihin"
+
+msgid "no syncing"
+msgstr "ei synkkausta"
+
+msgid "syncing starts "
+msgstr "synkkaus aloitettu "
+
+msgid " lines before top line"
+msgstr " riviä ennen alkua"
+
+msgid ""
+"\n"
+"--- Syntax sync items ---"
+msgstr ""
+"\n"
+"--- Syntax sync -kohteet ---"
+
+msgid ""
+"\n"
+"syncing on items"
+msgstr ""
+"\n"
+"synkataan kohteisiin"
+
+msgid ""
+"\n"
+"--- Syntax items ---"
+msgstr ""
+"\n"
+"--- Syntax-kohteet ---"
+
+#, c-format
+msgid "E392: No such syntax cluster: %s"
+msgstr "E392: syntaksiklusteria ei ole: %s"
+
+msgid "minimal "
+msgstr "vähintään "
+
+msgid "maximal "
+msgstr "enitntään "
+
+msgid "; match "
+msgstr "; täsmää "
+
+msgid " line breaks"
+msgstr " rivinvaihdot"
+
+msgid "E395: contains argument not accepted here"
+msgstr "E395: contains ei sovi tähän"
+
+msgid "E844: invalid cchar value"
+msgstr "E844: Virheellinen cchar-arvo"
+
+msgid "E393: group[t]here not accepted here"
+msgstr "E393: group[t]here ei sovi tähän"
+
+#, c-format
+msgid "E394: Didn't find region item for %s"
+msgstr "E394: Aluetta nimelle %s ei löydy"
+
+msgid "E397: Filename required"
+msgstr "E397: Tiedostonimi puuttuu"
+
+msgid "E847: Too many syntax includes"
+msgstr "E847: Liikaa syntax includeja"
+
+#, c-format
+msgid "E789: Missing ']': %s"
+msgstr "E789: ] puuttuu: %s"
+
+#, c-format
+msgid "E890: trailing char after ']': %s]%s"
+msgstr "E890: Ylimääräisiä merkkejä merkin ] perässä: %s]%s"
+
+#, c-format
+msgid "E398: Missing '=': %s"
+msgstr "E398: = puuttuu: %s"
+
+#, c-format
+msgid "E399: Not enough arguments: syntax region %s"
+msgstr "E399: Argumentteja puuttuu: syntaksialue %s"
+
+msgid "E848: Too many syntax clusters"
+msgstr "E848: Liikaa syntaksiklustereita"
+
+msgid "E400: No cluster specified"
+msgstr "E400: klusteri määrittelemättä"
+
+#, c-format
+msgid "E401: Pattern delimiter not found: %s"
+msgstr "E401: Kuvoin erotin puuttuu: %s"
+
+#, c-format
+msgid "E402: Garbage after pattern: %s"
+msgstr "E402: Roskia kuvion jäljessä: %s"
+
+msgid "E403: syntax sync: line continuations pattern specified twice"
+msgstr "E403: syntax sync: rivinjatkamiskuvio määritelty kahdesti"
+
+#, c-format
+msgid "E404: Illegal arguments: %s"
+msgstr "E404: Virheelliset argumentit: %s"
+
+#, c-format
+msgid "E405: Missing equal sign: %s"
+msgstr "E405: = puuttuu: %s"
+
+#, c-format
+msgid "E406: Empty argument: %s"
+msgstr "E406: Tyhjä argumentti: %s"
+
+#, c-format
+msgid "E407: %s not allowed here"
+msgstr "E407: %s ei sovi tähän"
+
+#, c-format
+msgid "E408: %s must be first in contains list"
+msgstr "E408: %s kuuluu contains-listan alkuun"
+
+#, c-format
+msgid "E409: Unknown group name: %s"
+msgstr "E409: Tuntematon ryhmän nimi: %s"
+
+#, c-format
+msgid "E410: Invalid :syntax subcommand: %s"
+msgstr "E410: Virheelluinen :syntax-osakomento: %s"
+
+msgid ""
+" TOTAL COUNT MATCH SLOWEST AVERAGE NAME PATTERN"
+msgstr ""
+" KAIKKI MÄÄRÄ TÄSMÄYS HITAIN KEKSIARVO NIMI ILMAUS"
+
+msgid "E679: recursive loop loading syncolor.vim"
+msgstr "E679: rekursiivinen silmukka syncolor.vimissä"
+
+#, c-format
+msgid "E411: highlight group not found: %s"
+msgstr "E411: korostusryhmää ei löytynyt: %s"
+
+#, c-format
+msgid "E412: Not enough arguments: \":highlight link %s\""
+msgstr "E412: Argumentteja puuttuu: :highlight link %s"
+
+#, c-format
+msgid "E413: Too many arguments: \":highlight link %s\""
+msgstr "E413: Liikaa argumentteja: :highlight link %s"
+
+msgid "E414: group has settings, highlight link ignored"
+msgstr "E414: ryhmällä on asetuksia, highlight link -komento ohitetaan"
+
+#, c-format
+msgid "E415: unexpected equal sign: %s"
+msgstr "E415: odotuksenvastainen =-merkki: %s"
+
+#, c-format
+msgid "E416: missing equal sign: %s"
+msgstr "E416: puuttuva =-merkki: %s"
+
+#, c-format
+msgid "E417: missing argument: %s"
+msgstr "E417: puuttuva argumentti: %s"
+
+#, c-format
+msgid "E418: Illegal value: %s"
+msgstr "E418: Viallinen arvo: %s"
+
+msgid "E419: FG color unknown"
+msgstr "E419: edustaväri tuntematon"
+
+msgid "E420: BG color unknown"
+msgstr "E420: taustaväri tuntematon"
+
+#, c-format
+msgid "E421: Color name or number not recognized: %s"
+msgstr "E421: Värin nimi tai numero tuntematon: %s"
+
+#, c-format
+msgid "E422: terminal code too long: %s"
+msgstr "E422: terminaalikoodi liian pitkä: %s"
+
+#, c-format
+msgid "E423: Illegal argument: %s"
+msgstr "E423: Virheellinen argumentti: %s"
+
+msgid "E424: Too many different highlighting attributes in use"
+msgstr "E424: Liikaa eri korostusattribuutteja"
+
+msgid "E669: Unprintable character in group name"
+msgstr "E669: Tulostuskelvoton merkki ryhmän nimessä"
+
+msgid "W18: Invalid character in group name"
+msgstr "W18: Virheellinen merkki ryhmän nimessä"
+
+msgid "E849: Too many highlight and syntax groups"
+msgstr "E849: Liikaa korostuksia ja syntaksiryhmiä"
+
+msgid "E555: at bottom of tag stack"
+msgstr "E555: tägipinon pohja"
+
+msgid "E556: at top of tag stack"
+msgstr "E556: tägipinon huippu"
+
+msgid "E425: Cannot go before first matching tag"
+msgstr "E425: Ei voida mennä ensimmäistä täsmäävää tägiä alummaksi"
+
+#, c-format
+msgid "E426: tag not found: %s"
+msgstr "E426: tägi puuttuu: %s"
+
+msgid " # pri kind tag"
+msgstr " # arvo tyyppi tägi"
+
+msgid "file\n"
+msgstr "tiedosto\n"
+
+msgid "E427: There is only one matching tag"
+msgstr "E427: Vain yksi tägi täsmää"
+
+msgid "E428: Cannot go beyond last matching tag"
+msgstr "E428: Ei voida edetä viimeisen täsmäävän tägin ohi"
+
+#, c-format
+msgid "File \"%s\" does not exist"
+msgstr "Tiedostoa %s ei ole"
+
+#, c-format
+msgid "tag %d of %d%s"
+msgstr "tägi %d/%d%s"
+
+msgid " or more"
+msgstr " tai useammasta"
+
+msgid " Using tag with different case!"
+msgstr " Tägissä eri kirjaintaso"
+
+#, c-format
+msgid "E429: File \"%s\" does not exist"
+msgstr "E429: Tiedostoa %s ei ole"
+
+msgid ""
+"\n"
+" # TO tag FROM line in file/text"
+msgstr ""
+"\n"
+" # TILL tagg FRÃ…N LINJE i fil/text"
+
+#, c-format
+msgid "Searching tags file %s"
+msgstr "Etsitään tägitiedostoa %s"
+
+#, c-format
+msgid "E430: Tag file path truncated for %s\n"
+msgstr "E430: Tägitiedoston polku katkaistu kohdassa %s\n"
+
+msgid "Ignoring long line in tags file"
+msgstr "Ohitetaan pitkä rivi tägitiedostossa"
+
+#, c-format
+msgid "E431: Format error in tags file \"%s\""
+msgstr "E431: Muotovirh tägitiedostossa %s"
+
+#, c-format
+msgid "Before byte %ld"
+msgstr "Ennen tavua %ld"
+
+#, c-format
+msgid "E432: Tags file not sorted: %s"
+msgstr "E432: Tägitiedosto ei ole järjestetty: %s"
+
+msgid "E433: No tags file"
+msgstr "E433: Ei tägitiedostoja"
+
+msgid "E434: Can't find tag pattern"
+msgstr "E434: Tägikuviota ei löydy"
+
+msgid "E435: Couldn't find tag, just guessing!"
+msgstr "E435: Tägiä ei löydy, arvataan."
+
+#, c-format
+msgid "Duplicate field name: %s"
+msgstr "Kaksoiskappale kentän nimestä: %s"
+
+msgid "' not known. Available builtin terminals are:"
+msgstr " ei tunnettu. Tuetut terminaalit:"
+
+msgid "defaulting to '"
+msgstr "oletusarvona "
+
+msgid "E557: Cannot open termcap file"
+msgstr "E557: Ei voi avata termcap-tiedostoa"
+
+msgid "E558: Terminal entry not found in terminfo"
+msgstr "E558: Terminaalia ei löytynyt terminfosta"
+
+msgid "E559: Terminal entry not found in termcap"
+msgstr "E559: Terminaalia ei löytynyt termcapista"
+
+#, c-format
+msgid "E436: No \"%s\" entry in termcap"
+msgstr "E436: %s ei löytynyt termcapista"
+
+msgid "E437: terminal capability \"cm\" required"
+msgstr "E437: terminaalilla pitää olla cm kyvyissään"
+
+msgid ""
+"\n"
+"--- Terminal keys ---"
+msgstr ""
+"\n"
+"--- Terminaalinäppäimet ---"
+
+msgid "Cannot open $VIMRUNTIME/rgb.txt"
+msgstr "Ei voida avata tiedostoa $VIMRUNTIME/rgb.txt"
+
+msgid "Terminal"
+msgstr "Terminaali"
+
+msgid "Terminal-finished"
+msgstr "Terminaali-lopetettu"
+
+msgid "active"
+msgstr "aktiivinen"
+
+msgid "running"
+msgstr "suoritetaan"
+
+msgid "finished"
+msgstr "lopetettu"
+
+msgid "new shell started\n"
+msgstr "uusi kuori avattu\n"
+
+msgid "Vim: Error reading input, exiting...\n"
+msgstr "Vim: Virhe luettaessa syötettä, poistutaan...\n"
+
+msgid "Used CUT_BUFFER0 instead of empty selection"
+msgstr "Käytettiin CUT_BUFFER0:aa tyhjän valinnan sijaan"
+
+msgid "E881: Line count changed unexpectedly"
+msgstr "E881: Rivimäärä vaihtui odottamatta"
+
+msgid "No undo possible; continue anyway"
+msgstr "Ei voi kumota, jatketaan silti"
+
+#, c-format
+msgid "E828: Cannot open undo file for writing: %s"
+msgstr "E828: Kumoustiedoston avaus kirjoittamista varten ei onnistu: %s"
+
+#, c-format
+msgid "E825: Corrupted undo file (%s): %s"
+msgstr "E825: Pilaanntunut kumoustiedosto (%s): %s"
+
+msgid "Cannot write undo file in any directory in 'undodir'"
+msgstr "Ei voitu lukea kumoustiedostoa mistään undodir-muuttujan hakemistosta"
+
+#, c-format
+msgid "Will not overwrite with undo file, cannot read: %s"
+msgstr "Ei ylikirjoitetat kumoustiedostolla, koska ei voida lukea: %s"
+
+#, c-format
+msgid "Will not overwrite, this is not an undo file: %s"
+msgstr "Ei ylikirjoiteta, koska tämä ei ole kumoustiedosto: %s"
+
+msgid "Skipping undo file write, nothing to undo"
+msgstr "Ohitetaan kumoustiedoston kirjoitus, koska ei ole peruutettavia"
+
+#, c-format
+msgid "Writing undo file: %s"
+msgstr "Kirjoitetaan kumoustiedostoa: %s"
+
+#, c-format
+msgid "E829: write error in undo file: %s"
+msgstr "E829: Kirjoitusvirhe kumoustiedostossa: %s"
+
+#, c-format
+msgid "Not reading undo file, owner differs: %s"
+msgstr "Ei lueta kumoustiedosto jonka omistaja on eri: %s"
+
+#, c-format
+msgid "Reading undo file: %s"
+msgstr "Luetaan kumoustiedostoa: %s"
+
+#, c-format
+msgid "E822: Cannot open undo file for reading: %s"
+msgstr "E822: Kumoustiedostoa ei voi avata lukemista varten: %s"
+
+#, c-format
+msgid "E823: Not an undo file: %s"
+msgstr "E823: Ei ole kumoustiedosto: %s"
+
+#, c-format
+msgid "E832: Non-encrypted file has encrypted undo file: %s"
+msgstr "E832: Salaamattomalla tiedostolla on salattu kumoustiedosto: %s"
+
+#, c-format
+msgid "E826: Undo file decryption failed: %s"
+msgstr "E826: Kumoustiedoston purku epäonnistui: %s"
+
+#, c-format
+msgid "E827: Undo file is encrypted: %s"
+msgstr "E827: Kumoustiedosto on salattu: %s"
+
+#, c-format
+msgid "E824: Incompatible undo file: %s"
+msgstr "E824: Epäyhteensopiva kumoustiedosto: %s"
+
+msgid "File contents changed, cannot use undo info"
+msgstr ""
+"Tiedoston sisältö on muuttunut, joen kumoustiedot ovat käyttökelvottomia"
+
+#, c-format
+msgid "Finished reading undo file %s"
+msgstr "Ladattu kumoustiedoto %s"
+
+msgid "Already at oldest change"
+msgstr "Vanhimmassa muutoksessa"
+
+msgid "Already at newest change"
+msgstr "Nuorimmassa muutoksessa"
+
+#, c-format
+msgid "E830: Undo number %ld not found"
+msgstr "E830: Kumouslukua %ld ei löydy"
+
+msgid "E438: u_undo: line numbers wrong"
+msgstr "E438: u_undo: väärät rivinumerot"
+
+msgid "more line"
+msgstr "rivi lisää"
+
+msgid "more lines"
+msgstr "riviä lisää"
+
+msgid "line less"
+msgstr "rivi vähemmän"
+
+msgid "fewer lines"
+msgstr "riviä vähemmän"
+
+msgid "change"
+msgstr "muutos"
+
+msgid "changes"
+msgstr "muutosta"
+
+# eka %s yläpuolelta, toka %s alapuolelta, kolmas %s aika
+#, c-format
+msgid "%ld %s; %s #%ld %s"
+msgstr "%ld %s, %s #%ld %s"
+
+msgid "before"
+msgstr "ennen muutosta"
+
+msgid "after"
+msgstr "jälkeen muutoksen"
+
+msgid "Nothing to undo"
+msgstr "Ei kumottavaa"
+
+msgid "number changes when saved"
+msgstr "numero muutoksia aika tallennettu"
+
+#, c-format
+msgid "%ld seconds ago"
+msgstr "%ld sekuntia sitten"
+
+msgid "E790: undojoin is not allowed after undo"
+msgstr "E790: undojoin ei toimi undon jälkeen"
+
+msgid "E439: undo list corrupt"
+msgstr "E439: kumouslista rikki"
+
+msgid "E440: undo line missing"
+msgstr "E440: kumousrivi puuttuu"
+
+#, c-format
+msgid "E122: Function %s already exists, add ! to replace it"
+msgstr "E122: Funktio %s on jo olemassa, lisää ! korvataksesi"
+
+msgid "E717: Dictionary entry already exists"
+msgstr "E717: Sanakirja-alkio on jo olemassa"
+
+msgid "E718: Funcref required"
+msgstr "E718: Funcref tarvitaan"
+
+#, c-format
+msgid "E130: Unknown function: %s"
+msgstr "E130: Tuntematon funktio: %s"
+
+#, c-format
+msgid "E125: Illegal argument: %s"
+msgstr "E125: Virheellinen argumentti: %s"
+
+#, c-format
+msgid "E853: Duplicate argument name: %s"
+msgstr "E853: Kaksoiskappale argumentin nimestä: %s"
+
+#, c-format
+msgid "E740: Too many arguments for function %s"
+msgstr "E740: Liikaa argumentteja funktiolle %s"
+
+#, c-format
+msgid "E116: Invalid arguments for function %s"
+msgstr "E116: Vääriä argumentteja funktiolle %s"
+
+msgid "E132: Function call depth is higher than 'maxfuncdepth'"
+msgstr "E132: Funktiokutsujen syvyys on enemmän kuin maxfuncdepth"
+
+#, c-format
+msgid "calling %s"
+msgstr "kutsutaan funktiota %s"
+
+#, c-format
+msgid "%s aborted"
+msgstr "%s keskeytettiin"
+
+#, c-format
+msgid "%s returning #%ld"
+msgstr "%s palaa kohdassa #%ld"
+
+#, c-format
+msgid "%s returning %s"
+msgstr "%s palaa kohdassa %s"
+
+msgid "E699: Too many arguments"
+msgstr "E699: Liikaa argumentteja"
+
+#, c-format
+msgid "E117: Unknown function: %s"
+msgstr "E117: Tuntematon funktio: %s"
+
+#, c-format
+msgid "E933: Function was deleted: %s"
+msgstr "E933: Funktion nimi poistettu: %s"
+
+#, c-format
+msgid "E119: Not enough arguments for function: %s"
+msgstr "E119: Liikaa argumentteja funktiolle %s"
+
+#, c-format
+msgid "E120: Using <SID> not in a script context: %s"
+msgstr "E120: <SID> skriptin ulkopuolella: %s"
+
+#, c-format
+msgid "E725: Calling dict function without Dictionary: %s"
+msgstr "E725: dict-funktio ilman sanakirjaa: %s"
+
+msgid "E129: Function name required"
+msgstr "E129: Funktion nimi puuttuu"
+
+#, c-format
+msgid "E128: Function name must start with a capital or \"s:\": %s"
+msgstr "E128: Funktion nimen pitää alkaa suuraakkosella tai merkeillä ’s:’: %s"
+
+#, c-format
+msgid "E884: Function name cannot contain a colon: %s"
+msgstr "E884: Funktion nimessä ei saa olla kaksoispistettä: %s"
+
+#, c-format
+msgid "E123: Undefined function: %s"
+msgstr "E123: Tuntematon funktio: %s"
+
+#, c-format
+msgid "E124: Missing '(': %s"
+msgstr "E124: ( puuttuu: %s"
+
+msgid "E862: Cannot use g: here"
+msgstr "E862: g: ei toimi täällä"
+
+#, c-format
+msgid "E932: Closure function should not be at top level: %s"
+msgstr "E932: Sulkeumafunktion ei pitäisi olla uloimmalla tasolla: %s"
+
+msgid "E126: Missing :endfunction"
+msgstr "E126: :endfunction puuttuu"
+
+#, c-format
+msgid "W22: Text found after :endfunction: %s"
+msgstr "W22: Ylimääräistä tekstiä :endfunction jälkeen: %s"
+
+#, c-format
+msgid "E707: Function name conflicts with variable: %s"
+msgstr "E707: Funktion nimi on ristiriidassa muuttujan kanssa: %s"
+
+#, c-format
+msgid "E127: Cannot redefine function %s: It is in use"
+msgstr "E127: Funktiota %s ei voi määritellä uudestaan, koska se on käytössä"
+
+#, c-format
+msgid "E746: Function name does not match script file name: %s"
+msgstr "E746: Funktion nimi ei ole sama kuin skriptin tiedostonnimi: %s"
+
+#, c-format
+msgid "E131: Cannot delete function %s: It is in use"
+msgstr "E131: Funktiota %s ei voi poistaa"
+
+msgid "E133: :return not inside a function"
+msgstr "E133: :return ei ole funktion sisällä"
+
+#, c-format
+msgid "E107: Missing parentheses: %s"
+msgstr "E107: Sulkeita puuttuu: %s"
+
+msgid ""
+"\n"
+"MS-Windows 64-bit GUI version"
+msgstr ""
+"\n"
+"MS-Windows 64-bittinen GUI-versio"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit GUI version"
+msgstr ""
+"\n"
+"MS-Windows 32-bittinen GUI-version"
+
+msgid " with OLE support"
+msgstr " OLE-tuella"
+
+msgid ""
+"\n"
+"MS-Windows 64-bit console version"
+msgstr ""
+"\n"
+"MS-Windows 32-bittinen konsoliversio"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit console version"
+msgstr ""
+"\n"
+"MS-Windows 32-bittinen konsoliversio"
+
+msgid ""
+"\n"
+"MacOS X (unix) version"
+msgstr ""
+"\n"
+"MacOS X-version (unix)"
+
+msgid ""
+"\n"
+"MacOS X version"
+msgstr ""
+"\n"
+"MacOS X-version"
+
+msgid ""
+"\n"
+"MacOS version"
+msgstr ""
+"\n"
+"MacOS-version"
+
+msgid ""
+"\n"
+"OpenVMS version"
+msgstr ""
+"\n"
+"OpenVMS-version"
+
+msgid ""
+"\n"
+"Included patches: "
+msgstr ""
+"\n"
+"Pätsit: "
+
+msgid ""
+"\n"
+"Extra patches: "
+msgstr ""
+"\n"
+"Muita pätsejä: "
+
+msgid "Modified by "
+msgstr "Muokannut "
+
+msgid ""
+"\n"
+"Compiled "
+msgstr ""
+"\n"
+"Kääntänyt "
+
+msgid "by "
+msgstr ": "
+
+msgid ""
+"\n"
+"Huge version "
+msgstr ""
+"\n"
+"Huge-versio "
+
+msgid ""
+"\n"
+"Big version "
+msgstr ""
+"\n"
+"Big-version "
+
+msgid ""
+"\n"
+"Normal version "
+msgstr ""
+"\n"
+"Normal-versio "
+
+msgid ""
+"\n"
+"Small version "
+msgstr ""
+"\n"
+"Small-versio "
+
+msgid ""
+"\n"
+"Tiny version "
+msgstr ""
+"\n"
+"Tiny-versio "
+
+msgid "without GUI."
+msgstr "ilman GUIta."
+
+msgid "with GTK3 GUI."
+msgstr "GTK3-GUIlla."
+
+msgid "with GTK2-GNOME GUI."
+msgstr "GTK2-Gnome-GUIlla."
+
+msgid "with GTK2 GUI."
+msgstr "GTK2-GUIlla."
+
+msgid "with X11-Motif GUI."
+msgstr "X11-Motif-GUIlla."
+
+msgid "with X11-neXtaw GUI."
+msgstr "X11-neXtaw-GUIlla."
+
+msgid "with X11-Athena GUI."
+msgstr "X11-Athena-GUIlla."
+
+msgid "with Photon GUI."
+msgstr "Photon-GUIlla."
+
+msgid "with GUI."
+msgstr "GUIlla."
+
+msgid "with Carbon GUI."
+msgstr "Carbon-GUIlla."
+
+msgid "with Cocoa GUI."
+msgstr "Cocoa-GUIlla."
+
+msgid "with (classic) GUI."
+msgstr "perinteisellä GUIlla."
+
+msgid " Features included (+) or not (-):\n"
+msgstr " Ominaisuudet mukana (+) ja poissa (-):\n"
+
+msgid " system vimrc file: \""
+msgstr " järjestelmän vimrc: \""
+
+msgid " user vimrc file: \""
+msgstr " käyttäjän vimrc: \""
+
+msgid " 2nd user vimrc file: \""
+msgstr " 2. käyttäjän vimrc: \""
+
+msgid " 3rd user vimrc file: \""
+msgstr " 3. käyttäjän vimrc: \""
+
+msgid " user exrc file: \""
+msgstr " käyttäjän exrc: \""
+
+msgid " 2nd user exrc file: \""
+msgstr " 2. käyttäjän exrc: \""
+
+msgid " system gvimrc file: \""
+msgstr " järjestelmän gvimrc: \""
+
+msgid " user gvimrc file: \""
+msgstr " käyttäjän gvimrc: \""
+
+msgid "2nd user gvimrc file: \""
+msgstr "2. käyttäjän gvimrc: \""
+
+msgid "3rd user gvimrc file: \""
+msgstr "3. käyttäjän gvimrc: \""
+
+msgid " defaults file: \""
+msgstr " defaults-tiedosto: \""
+
+msgid " system menu file: \""
+msgstr " järjestelmävalikko: \""
+
+msgid " fall-back for $VIM: \""
+msgstr " $VIMin fallback: \""
+
+msgid " f-b for $VIMRUNTIME: \""
+msgstr " $VIMRUNTIMEn f-b: \""
+
+msgid "Compilation: "
+msgstr "Käännös: "
+
+msgid "Compiler: "
+msgstr "Käännin: "
+
+msgid "Linking: "
+msgstr "Linkitys: "
+
+msgid " DEBUG BUILD"
+msgstr " DEBUG-versio"
+
+msgid "VIM - Vi IMproved"
+msgstr "VIM - Vi IMproved"
+
+msgid "version "
+msgstr "versio "
+
+msgid "by Bram Moolenaar et al."
+msgstr "tekijät Bram Moolenaar et al."
+
+msgid "Vim is open source and freely distributable"
+msgstr "Vim on avointa lähdekoodia ja vapaasti jaossa"
+
+msgid "Help poor children in Uganda!"
+msgstr "Auta Ugandan köyhiä lapsia"
+
+msgid "type :help iccf<Enter> for information "
+msgstr "kirjoita :help iccf<Enter> lisätietoa varten "
+
+msgid "type :q<Enter> to exit "
+msgstr "kirjoita :q<Enter> lopettaaksesi "
+
+msgid "type :help<Enter> or <F1> for on-line help"
+msgstr "kirjoita :help<Enter> tai <F1> ohjetta varten "
+
+msgid "type :help version8<Enter> for version info"
+msgstr "kirjoita :help version8<Enter> versiotietoja varten "
+
+msgid "Running in Vi compatible mode"
+msgstr "Suoritetaan Vi-yhteensopivuustilaa"
+
+msgid "type :set nocp<Enter> for Vim defaults"
+msgstr "kirjoita :set nocp<Enter> Vimin oletuksiin "
+
+msgid "type :help cp-default<Enter> for info on this"
+msgstr "kirjoita :help cp-default<Enter> ohjetta oletuksista varten"
+
+msgid "menu Help->Orphans for information "
+msgstr "valikko Ohje->Orvot lisätietoja varten "
+
+msgid "Running modeless, typed text is inserted"
+msgstr "Suoritetaan tilattomana, kirjoitettu teksti syötetään"
+
+msgid "menu Edit->Global Settings->Toggle Insert Mode "
+msgstr "valikko Muokkaa->Yleiset asetukset->Vaihda syötetilaa"
+
+msgid " for two modes "
+msgstr " kahta tilaa varten "
+
+msgid "menu Edit->Global Settings->Toggle Vi Compatible"
+msgstr "valikko Muokkaa->Yleiset asetukset->Vaihda Vi-yhteensopivuutta"
+
+msgid " for Vim defaults "
+msgstr " Vim-oletuksia varten"
+
+msgid "Sponsor Vim development!"
+msgstr "Tue Vimin kehitystä"
+
+msgid "Become a registered Vim user!"
+msgstr "Rekisteröidy Vim-käyttäjäksi."
+
+msgid "type :help sponsor<Enter> for information "
+msgstr "kirjoita :help sponsor<Enter> lisätietoja varten"
+
+msgid "type :help register<Enter> for information "
+msgstr "kirjoita :help register<Enter> lisätietoja varten"
+
+msgid "menu Help->Sponsor/Register for information "
+msgstr "valikko Ohje->Sponsoroi/Rekisteröi lisätietoja varten"
+
+msgid "Already only one window"
+msgstr "Enää yksi ikkuna jäljellä"
+
+msgid "E441: There is no preview window"
+msgstr "E441: Ei esikatseluikkunaa"
+
+msgid "E442: Can't split topleft and botright at the same time"
+msgstr "E442: Ei voi jakaa vasenta ylänurkkaa ja oikeaa alanurkkaa yhtäaikaa"
+
+msgid "E443: Cannot rotate when another window is split"
+msgstr "E443: Ei voi kiertää kun toinen ikkuna on jaettu"
+
+msgid "E444: Cannot close last window"
+msgstr "E444: Ei voi sulkea viimeistä ikkunaa"
+
+msgid "E813: Cannot close autocmd window"
+msgstr "E813: Ei voi sulkea autocmd-ikkunaa"
+
+msgid "E814: Cannot close window, only autocmd window would remain"
+msgstr "E814: Ei voi sulkea viimeistä ikkunaa, joka ei ole autocmd-ikkuna"
+
+msgid "E445: Other window contains changes"
+msgstr "E445: Toinen ikkuna sisältää muutoksia"
+
+msgid "E446: No file name under cursor"
+msgstr "E446: Ei tiedostonimeä kursorin alla"
+
+#, c-format
+msgid "E447: Can't find file \"%s\" in path"
+msgstr "E447: Tiedosto %s ei löydy polulta"
+
+#, c-format
+msgid "E799: Invalid ID: %ld (must be greater than or equal to 1)"
+msgstr "E799: Käyttökelvoton ID: %ld (pitää olla vähintään 1)"
+
+#, c-format
+msgid "E801: ID already taken: %ld"
+msgstr "E801: ID jo käytössä: %ld"
+
+msgid "List or number required"
+msgstr "Lista tai luku tarvitaan"
+
+#, c-format
+msgid "E802: Invalid ID: %ld (must be greater than or equal to 1)"
+msgstr "E802: Käyttöklvoton ID: %ld (pitää olla vähintään 1)"
+
+#, c-format
+msgid "E803: ID not found: %ld"
+msgstr "E803: ID:tä ei löydy: %ld"
+
+#, c-format
+msgid "E370: Could not load library %s"
+msgstr "E370: Kirjaston %s lataaminen ei onnistu"
+
+msgid "Sorry, this command is disabled: the Perl library could not be loaded."
+msgstr "komento ei toimi, Perl kirjastoa ei voinut ladata."
+
+msgid "E299: Perl evaluation forbidden in sandbox without the Safe module"
+msgstr "E299: Perl-suoritus kielletty hiekkalaatikossa ilman Safe-moduulia"
+
+msgid "Edit with &multiple Vims"
+msgstr "&Muokkaa usealla Vimillä"
+
+msgid "Edit with single &Vim"
+msgstr "Muokkaa yhdellä &Vimillä"
+
+msgid "Diff with Vim"
+msgstr "Diffi Vimillä"
+
+msgid "Edit with &Vim"
+msgstr "Muokkaa &Vimillä"
+
+msgid "Edit with existing Vim - "
+msgstr "Muokkaa olemassaolevalla Vimillä - "
+
+msgid "Edits the selected file(s) with Vim"
+msgstr "Muokkaa valittuja tiedostoja Vimillä"
+
+msgid "Error creating process: Check if gvim is in your path!"
+msgstr "Virhe prosessin käynnistämisessä, varmista että gvim on polulla"
+
+msgid "gvimext.dll error"
+msgstr "gvimext.dll-virhe"
+
+msgid "Path length too long!"
+msgstr "Liian pitkä polku"
+
+msgid "--No lines in buffer--"
+msgstr "--Ei rivejä puskurissa--"
+
+msgid "E470: Command aborted"
+msgstr "E470: Komento peruttu"
+
+msgid "E471: Argument required"
+msgstr "E471: Argumentti puuttuu"
+
+msgid "E10: \\ should be followed by /, ? or &"
+msgstr "E10: \\:n jälkeen pitää tulla /, ? tai &"
+
+msgid "E11: Invalid in command-line window; <CR> executes, CTRL-C quits"
+msgstr "E11: Virheellinen komentorivi-ikkuna, <CR> suorittaa, Ctrl C lopettaa"
+
+msgid "E12: Command not allowed from exrc/vimrc in current dir or tag search"
+msgstr ""
+"E12: Komentoa ei tueta exrc:ssä tai vimrc:ssä tässä hakemistossa tai "
+"tägihaussa"
+
+msgid "E171: Missing :endif"
+msgstr "E171: :endif puuttuu"
+
+msgid "E600: Missing :endtry"
+msgstr "E600: :endtry puuttuu"
+
+msgid "E170: Missing :endwhile"
+msgstr "E170: :endwhile puuttuu"
+
+msgid "E170: Missing :endfor"
+msgstr "E170: :endfor puuttuu"
+
+msgid "E588: :endwhile without :while"
+msgstr "E588: :endwhile ilman komentoa :while"
+
+msgid "E588: :endfor without :for"
+msgstr "E588: :endfor ilman komentoa :for"
+
+msgid "E13: File exists (add ! to override)"
+msgstr "E13: Tiedosto on jo olemassa (lisää ! ohittaaksesi)"
+
+msgid "E472: Command failed"
+msgstr "E472: Komento epäonnistui"
+
+#, c-format
+msgid "E234: Unknown fontset: %s"
+msgstr "E234: Tuntematon fontset: %s"
+
+#, c-format
+msgid "E235: Unknown font: %s"
+msgstr "E235: Tuntematon fontti: %s"
+
+#, c-format
+msgid "E236: Font \"%s\" is not fixed-width"
+msgstr "E236: Fontti %s ei ole tasavälinen"
+
+msgid "E473: Internal error"
+msgstr "E473: Sisäinen virhe"
+
+#, c-format
+msgid "E685: Internal error: %s"
+msgstr "E685: Sisäinen virhe: %s"
+
+msgid "Interrupted"
+msgstr "Keskeytetty"
+
+msgid "E14: Invalid address"
+msgstr "E14: Virheellinen osoite"
+
+msgid "E474: Invalid argument"
+msgstr "E474: Virheellinen argumentti"
+
+#, c-format
+msgid "E475: Invalid argument: %s"
+msgstr "E475: Virheellinen argumentti: %s"
+
+#, c-format
+msgid "E15: Invalid expression: %s"
+msgstr "E15: Virheellinen ilmaus: %s"
+
+msgid "E16: Invalid range"
+msgstr "E16: Virheellinen arvoalue"
+
+msgid "E476: Invalid command"
+msgstr "E476: Virheellinen komento"
+
+#, c-format
+msgid "E17: \"%s\" is a directory"
+msgstr "E17: %s on hakemisto"
+
+#, c-format
+msgid "E364: Library call failed for \"%s()\""
+msgstr "E364: Kirjastukutsu %s() epäonnistui"
+
+#, c-format
+msgid "E448: Could not load library function %s"
+msgstr "E448: Ei voitu ladta kirjastofunktiota %s"
+
+msgid "E19: Mark has invalid line number"
+msgstr "E19: Merkillä on virheellinen rivinumero"
+
+msgid "E20: Mark not set"
+msgstr "E20: Merkkiä ei asetettu"
+
+msgid "E21: Cannot make changes, 'modifiable' is off"
+msgstr "E21: Ei voi tehdä muutoksia, modifiable on pois päältä"
+
+msgid "E22: Scripts nested too deep"
+msgstr "E22: Liian monta tasoa skripteissä"
+
+msgid "E23: No alternate file"
+msgstr "E23: Eo vaihtoehtoista tiedostoa"
+
+msgid "E24: No such abbreviation"
+msgstr "E24: Lyhennettä ei ole"
+
+msgid "E477: No ! allowed"
+msgstr "E477: ! ei sallittu"
+
+msgid "E25: GUI cannot be used: Not enabled at compile time"
+msgstr "E25: GUIta ei voi käyttää, koska sitä ei käännetty mukaan"
+
+msgid "E26: Hebrew cannot be used: Not enabled at compile time\n"
+msgstr "E26: Hepreaa ei voi käyttää, koska sitä ei käännetty mukaan\n"
+
+msgid "E27: Farsi cannot be used: Not enabled at compile time\n"
+msgstr "E27: Farsia ei voi käyttää, koska sitä ei käännetty mukaan\n"
+
+msgid "E800: Arabic cannot be used: Not enabled at compile time\n"
+msgstr "E800: Arabiaa ei voi käyttää, koska sitä ei käännetty mukaan\n"
+
+#, c-format
+msgid "E28: No such highlight group name: %s"
+msgstr "E28: Korostusryhmää ei ole nimellä: %s"
+
+msgid "E29: No inserted text yet"
+msgstr "E29: Tekstiä ei ole syötetty vielä"
+
+msgid "E30: No previous command line"
+msgstr "E30: Ei edellistä komentoriviä"
+
+msgid "E31: No such mapping"
+msgstr "E31: Kuvausta ei ole"
+
+msgid "E479: No match"
+msgstr "E479: Ei täsmää"
+
+#, c-format
+msgid "E480: No match: %s"
+msgstr "E480: Ei tsämää: %s"
+
+msgid "E32: No file name"
+msgstr "E32: Ei tiedostonimeä"
+
+msgid "E33: No previous substitute regular expression"
+msgstr "E33: Ei edellistä korvausta säännölliselle ilmaukselle"
+
+msgid "E34: No previous command"
+msgstr "E34: Ei edellistä komentoa"
+
+msgid "E35: No previous regular expression"
+msgstr "E35: Ei edellistä säännöllistä ilmausta"
+
+msgid "E481: No range allowed"
+msgstr "E481: Arvoalue ei sallittu"
+
+msgid "E36: Not enough room"
+msgstr "E36: Tila ei riitä"
+
+#, c-format
+msgid "E247: no registered server named \"%s\""
+msgstr "E247: palvelinta %s ei ole rekisteröitynä"
+
+#, c-format
+msgid "E482: Can't create file %s"
+msgstr "E482: Tiedostoa %s ei voi luoda"
+
+msgid "E483: Can't get temp file name"
+msgstr "E483: väliaikaistiedoston nimeä ei saada selville"
+
+#, c-format
+msgid "E484: Can't open file %s"
+msgstr "E484: Ei voi avata tiedostoa %s"
+
+#, c-format
+msgid "E485: Can't read file %s"
+msgstr "E485: Ei voi lukea tiedostoa %s"
+
+msgid "E38: Null argument"
+msgstr "E38: Null-argumentti"
+
+msgid "E39: Number expected"
+msgstr "E39: Pitää olla numero"
+
+#, c-format
+msgid "E40: Can't open errorfile %s"
+msgstr "E40: virhetiedostoa %s ei voi avata"
+
+msgid "E233: cannot open display"
+msgstr "E233: näyttöä ei voi avata"
+
+msgid "E41: Out of memory!"
+msgstr "E41: Muisti loppui"
+
+msgid "Pattern not found"
+msgstr "Kuviota ei löydy"
+
+#, c-format
+msgid "E486: Pattern not found: %s"
+msgstr "E486: Kuviota ei löydy: %s"
+
+msgid "E487: Argument must be positive"
+msgstr "E487: Argumentin pitää olla positiivinen"
+
+msgid "E459: Cannot go back to previous directory"
+msgstr "E459: Ei voi siirtyä edelliseen hakemistoon"
+
+# ;-)
+msgid "E42: No Errors"
+msgstr "E42: Ei virheitä"
+
+msgid "E776: No location list"
+msgstr "E776: Ei sijaintilistaa"
+
+msgid "E43: Damaged match string"
+msgstr "E43: Viallinen täsmäysmerkkijono"
+
+msgid "E44: Corrupted regexp program"
+msgstr "E44: Viallinen regexp-ohjelma"
+
+msgid "E45: 'readonly' option is set (add ! to override)"
+msgstr "E45: readonly asetettu (lisää ! ohittaaksesi)"
+
+#, c-format
+msgid "E46: Cannot change read-only variable \"%s\""
+msgstr "E46: Kirjoitussuojattua muuttujaa %s ei voi muuttaa"
+
+#, c-format
+msgid "E794: Cannot set variable in the sandbox: \"%s\""
+msgstr "E794: Muuttujaa ei voi asettaa hiekkalaatikossa: %s"
+
+msgid "E713: Cannot use empty key for Dictionary"
+msgstr "E713: Sanakirjassa ei voi olla tyhjiä avaimia"
+
+msgid "E715: Dictionary required"
+msgstr "E715: Sanakirja tarvitaan"
+
+#, c-format
+msgid "E684: list index out of range: %ld"
+msgstr "E684: Indeksi %ld luettelon rajojen ulkopuolella"
+
+#, c-format
+msgid "E118: Too many arguments for function: %s"
+msgstr "E118: Liikaa argumentteja funktiolle: %s"
+
+#, c-format
+msgid "E716: Key not present in Dictionary: %s"
+msgstr "E716: Avainta %s ei ole sanakirjassa"
+
+msgid "E714: List required"
+msgstr "E714: Lista tarvitaan"
+
+# datarakenteita
+#, c-format
+msgid "E712: Argument of %s must be a List or Dictionary"
+msgstr "E712: Argumentin %s pitää olla lista tai sanakirja"
+
+msgid "E47: Error while reading errorfile"
+msgstr "E47: Virhe virhetiedostoa luettaessa"
+
+msgid "E48: Not allowed in sandbox"
+msgstr "E48: Ei sallittu hiekkalaatikossa"
+
+msgid "E523: Not allowed here"
+msgstr "E523: Ei sallittu täällä"
+
+msgid "E359: Screen mode setting not supported"
+msgstr "E359: Näyttötila-asetus ei tuettu"
+
+msgid "E49: Invalid scroll size"
+msgstr "E49: Virheellinen vierityskoko"
+
+msgid "E91: 'shell' option is empty"
+msgstr "E91: shell-asetus on tyhjä"
+
+msgid "E255: Couldn't read in sign data!"
+msgstr "E255: Merkkidatan luku ei onnistu"
+
+msgid "E72: Close error on swap file"
+msgstr "E72: Swap-tiedoston sulkemisvirhe"
+
+msgid "E73: tag stack empty"
+msgstr "E73: tägipino tyhjä"
+
+msgid "E74: Command too complex"
+msgstr "E74: Liian monimutkainen komento"
+
+msgid "E75: Name too long"
+msgstr "E75: Liian pitkä nimi"
+
+msgid "E76: Too many ["
+msgstr "E76: Liian monta [:a"
+
+msgid "E77: Too many file names"
+msgstr "E77: Liikaa tiedostonimiä"
+
+msgid "E488: Trailing characters"
+msgstr "E488: Ylimääräisiä merkkejä perässä"
+
+msgid "E78: Unknown mark"
+msgstr "E78: Tuntematon merkki"
+
+msgid "E79: Cannot expand wildcards"
+msgstr "E79: Jokerimerkkien avaus ei onnistu"
+
+msgid "E591: 'winheight' cannot be smaller than 'winminheight'"
+msgstr "E591: winheight ei voi olla pienempi kuin winminheight"
+
+msgid "E592: 'winwidth' cannot be smaller than 'winminwidth'"
+msgstr "E592: winwidth ei voi olla pienempi kuin winminwidth"
+
+msgid "E80: Error while writing"
+msgstr "E80: Kirjoitusvirhe"
+
+msgid "E939: Positive count required"
+msgstr "E939: Positiivinen luku tarvitaan"
+
+msgid "E81: Using <SID> not in a script context"
+msgstr "E81: <SID> skriptin ulkopuolella"
+
+msgid "E449: Invalid expression received"
+msgstr "E449: Virheellinen ilmaus saatu"
+
+msgid "E463: Region is guarded, cannot modify"
+msgstr "E463: Alue on suojattu, muuttaminen ei onnistu"
+
+msgid "E744: NetBeans does not allow changes in read-only files"
+msgstr "E744: NetBeans ei tue muutoksia kirjoitussuojattuihin tiedostoihin"
+
+msgid "E363: pattern uses more memory than 'maxmempattern'"
+msgstr "E363: kuvio käyttää enemmän muistia kuin maxmempattern on"
+
+msgid "E749: empty buffer"
+msgstr "E749: tyhjä puskuri"
+
+#, c-format
+msgid "E86: Buffer %ld does not exist"
+msgstr "E86: Puskuria %ld ei ole"
+
+msgid "E682: Invalid search pattern or delimiter"
+msgstr "E682: Virheellinen hakulauseke tai erotin"
+
+msgid "E139: File is loaded in another buffer"
+msgstr "E139: Tiedosto on ladattu toiseen puskuriin"
+
+#, c-format
+msgid "E764: Option '%s' is not set"
+msgstr "E764: Asetus %s on asettamatta"
+
+msgid "E850: Invalid register name"
+msgstr "E850: Virheellinen rekisterin nimi"
+
+#, c-format
+msgid "E919: Directory not found in '%s': \"%s\""
+msgstr "E919: Hakemisto puuttuu kohteesta %s: %s"
+
+msgid "search hit TOP, continuing at BOTTOM"
+msgstr "haku pääsi ALKUUN, jatketaan LOPUSTA"
+
+msgid "search hit BOTTOM, continuing at TOP"
+msgstr "haku pääsi LOPPUUN, jatketaan ALUSTA"
+
+#, c-format
+msgid "Need encryption key for \"%s\""
+msgstr "Tarvitaan salausavain kohteelle %s "
+
+msgid "empty keys are not allowed"
+msgstr "tyhjiä avaimia ei voi käyttää"
+
+msgid "dictionary is locked"
+msgstr "dictionary on lukittu"
+
+msgid "list is locked"
+msgstr "luettelo on lukittu"
+
+#, c-format
+msgid "failed to add key '%s' to dictionary"
+msgstr "avaimen %s lisääminen sanakirjaan ei onnistu"
+
+#, c-format
+msgid "index must be int or slice, not %s"
+msgstr "indeksin pitää olla int tai slice, ei %s"
+
+#, c-format
+msgid "expected str() or unicode() instance, but got %s"
+msgstr "odottettiin insanssia tyypeistä str() tai unicode(), ei %s"
+
+#, c-format
+msgid "expected bytes() or str() instance, but got %s"
+msgstr "odotettiin instanssia tyypeistä bytes() tai str(), ei %s"
+
+#, c-format
+msgid ""
+"expected int(), long() or something supporting coercing to long(), but got %s"
+msgstr ""
+"odotettiin instanssia tyypeistä int(), long() tai mitä tahansa joka "
+"muuntuisi tyyppiin long(), ei %s"
+
+#, c-format
+msgid "expected int() or something supporting coercing to int(), but got %s"
+msgstr "odotettiin tyyppiä int() tai jotain joka muuntuu tyyppiin int(), ei %s"
+
+msgid "value is too large to fit into C int type"
+msgstr "arvo on liian suuri mahtumaan C:n int-tyyppiin"
+
+msgid "value is too small to fit into C int type"
+msgstr "arvo on liian pieni mahtumaan C:n int-tyyppiin"
+
+msgid "number must be greater than zero"
+msgstr "luvun on oltava nollaa suurempi"
+
+msgid "number must be greater or equal to zero"
+msgstr "luvun on oltava yhtä suuri tai suurempi kuin nolla"
+
+msgid "can't delete OutputObject attributes"
+msgstr "ei voi poistaa OutputObject-attribuutteja"
+
+#, c-format
+msgid "invalid attribute: %s"
+msgstr "virheellinen attribuutti: %s"
+
+msgid "E264: Python: Error initialising I/O objects"
+msgstr "E264: Python: Virhe IO-olioiden alustuksessa"
+
+msgid "failed to change directory"
+msgstr "hakemistoa ei voitu muuttaa"
+
+#, c-format
+msgid "expected 3-tuple as imp.find_module() result, but got %s"
+msgstr "odotettiin 3-tuplea tuloksena imp.find_module()-kutsulle, ei %s"
+
+#, c-format
+msgid "expected 3-tuple as imp.find_module() result, but got tuple of size %d"
+msgstr ""
+"odotettiin 3-tuple tuloksnea imp.find_module()-kutsulle, mutta tuplen koko "
+"onkin %d"
+
+msgid "internal error: imp.find_module returned tuple with NULL"
+msgstr "sisäinen virhe: imp.find_module palautti tuplen joka sisältää nullin"
+
+msgid "cannot delete vim.Dictionary attributes"
+msgstr "ei voi poistaa vim.Dictionary-attribuutteja"
+
+msgid "cannot modify fixed dictionary"
+msgstr "ei voida muuttaa kiinnitettyä sanakirjaa"
+
+#, c-format
+msgid "cannot set attribute %s"
+msgstr "ei voi asettaa attribuuttia %s"
+
+msgid "hashtab changed during iteration"
+msgstr "hashtab muuttui kesken iteraation"
+
+#, c-format
+msgid "expected sequence element of size 2, but got sequence of size %d"
+msgstr "sekvenssin elementin koon pitäisi olla 2, ei %d"
+
+msgid "list constructor does not accept keyword arguments"
+msgstr "listakonstruktori ei tue avainsanaparametrejä"
+
+msgid "list index out of range"
+msgstr "listaindeksi arvoalueen ulkopuolelta"
+
+#, c-format
+msgid "internal error: failed to get vim list item %d"
+msgstr "sisäinen virhe: ei pystytty hakea vimin listan indeksiä %d"
+
+msgid "slice step cannot be zero"
+msgstr "slicen askel ei voi olla nolla"
+
+#, c-format
+msgid "attempt to assign sequence of size greater than %d to extended slice"
+msgstr "yritettiin sijoittaa sekvenssiä jonka koko on enemmän kuin %d sliceen"
+
+#, c-format
+msgid "internal error: no vim list item %d"
+msgstr "sisäinen virhe: ei vim-listan indeksiä %d"
+
+msgid "internal error: not enough list items"
+msgstr "sisäinen virhe: ei tarpeeksi listan kohtia"
+
+msgid "internal error: failed to add item to list"
+msgstr "sisäinen virhe: ei voitu lisätä kohtaa listaan"
+
+#, c-format
+msgid "attempt to assign sequence of size %d to extended slice of size %d"
+msgstr ""
+"yritettiin asettaa sekvenssiä jonka koko on %d sliceen jonka koko on %d"
+
+msgid "failed to add item to list"
+msgstr "ei voitu lisätä kohtaa listaan"
+
+msgid "cannot delete vim.List attributes"
+msgstr "ei voi poistaa vim.List-attribuutteja"
+
+msgid "cannot modify fixed list"
+msgstr "ei voida muokata kiinitettyä listaa"
+
+#, c-format
+msgid "unnamed function %s does not exist"
+msgstr "nimetöntä funktiota %s ei ole"
+
+#, c-format
+msgid "function %s does not exist"
+msgstr "funktiota %s ei ole"
+
+#, c-format
+msgid "failed to run function %s"
+msgstr "ei voitu suorittaa funktiota %s"
+
+msgid "unable to get option value"
+msgstr "ei voitu hakea asetuksen arvoa"
+
+msgid "internal error: unknown option type"
+msgstr "sisäinen virhe: tuntematon asetustyyppi"
+
+msgid "problem while switching windows"
+msgstr "virhe ikkunaa vaihtaessa"
+
+#, c-format
+msgid "unable to unset global option %s"
+msgstr "ei voi tyhjentää yleistä asetusta %s"
+
+#, c-format
+msgid "unable to unset option %s which does not have global value"
+msgstr "ei voi tyhjentää asetusta %s jolla ei ole yleistä arvoa"
+
+msgid "attempt to refer to deleted tab page"
+msgstr "yritettiin viitata poistettuun välilehteen"
+
+msgid "no such tab page"
+msgstr "välilehteä ei ole"
+
+msgid "attempt to refer to deleted window"
+msgstr "yritettiin viitata poistettuun ikkunaan"
+
+msgid "readonly attribute: buffer"
+msgstr "kirjoitussuojausattribuutti: puskuri"
+
+msgid "cursor position outside buffer"
+msgstr "kursorin sijainti puskurin ulkopuolella"
+
+msgid "no such window"
+msgstr "ikkunaa ei ole"
+
+msgid "attempt to refer to deleted buffer"
+msgstr "yritettiin viitata poistettuun puskuriin"
+
+msgid "failed to rename buffer"
+msgstr "ei voity uudelleennimetä puskuria"
+
+msgid "mark name must be a single character"
+msgstr "merkin nimen pitää olla yksi merkki"
+
+#, c-format
+msgid "expected vim.Buffer object, but got %s"
+msgstr "odotettiin vim.Buffer-oliota, ei %s"
+
+#, c-format
+msgid "failed to switch to buffer %d"
+msgstr "ei voitu vaihtaa puskuriin %d"
+
+#, c-format
+msgid "expected vim.Window object, but got %s"
+msgstr "odotettiin vim.Window-oliota, saatiin %s"
+
+msgid "failed to find window in the current tab page"
+msgstr "ei voitu löytää ikkunaa nykyiselle välilehtisivulle"
+
+msgid "did not switch to the specified window"
+msgstr "ei vaihdettu annettuun ikkunaan"
+
+#, c-format
+msgid "expected vim.TabPage object, but got %s"
+msgstr "odotettiin vim.TabPage-oliota, saatiin %s"
+
+msgid "did not switch to the specified tab page"
+msgstr "ei voitu vaihtaa annetulle välilehtisivulle"
+
+msgid "failed to run the code"
+msgstr "ei voitu suorittaa koodia"
+
+msgid "E858: Eval did not return a valid python object"
+msgstr "E858: Eval ei palauttanut python-oliota"
+
+msgid "E859: Failed to convert returned python object to vim value"
+msgstr "E859: Ei voitu konvertoida python-oliota vim-arvoksi"
+
+#, c-format
+msgid "unable to convert %s to vim dictionary"
+msgstr "ei voitu konvertoida oliota %s vim-sanakirjaksi"
+
+#, c-format
+msgid "unable to convert %s to vim list"
+msgstr "ei voitu konvertoida tyypistä %s vim-listaksi"
+
+#, c-format
+msgid "unable to convert %s to vim structure"
+msgstr "ei voi konvertoida oliota %s vim-tietorakenteeksi"
+
+msgid "internal error: NULL reference passed"
+msgstr "sisäinen virhe: NULL-viite annettu"
+
+msgid "internal error: invalid value type"
+msgstr "sisäinen virhe: huono arvotyyppi"
+
+msgid ""
+"Failed to set path hook: sys.path_hooks is not a list\n"
+"You should now do the following:\n"
+"- append vim.path_hook to sys.path_hooks\n"
+"- append vim.VIM_SPECIAL_PATH to sys.path\n"
+msgstr ""
+"Ei voitu asettaa polkukoukkua: sys.path_hooks ei ole lista\n"
+"Koeta seuraavaa:\n"
+"- lisää vim.path_hook muuttujaan sys.path_hooks\n"
+"- lisää vim.VIM_SPECIAL_PATH muuttujaan sys.path\n"
+
+msgid ""
+"Failed to set path: sys.path is not a list\n"
+"You should now append vim.VIM_SPECIAL_PATH to sys.path"
+msgstr ""
+"Ei onnistuttu asettaman polkua: sys.path ei ole list\n"
+"Lisää vim.VIM_SPECIAL_PATH muuttujaan sys.path"
diff --git a/src/po/fr.po b/src/po/fr.po
new file mode 100644
index 0000000..30d8b8e
--- /dev/null
+++ b/src/po/fr.po
@@ -0,0 +1,7429 @@
+# French Translation for Vim
+#
+# Do ":help uganda" in Vim to read copying and usage conditions.
+# Do ":help credits" in Vim to see a list of people who contributed.
+#
+# FIRST AUTHOR DindinX <David.Odin@bigfoot.com> 2000.
+# SECOND AUTHOR Adrien Beau <version.francaise@free.fr> 2002, 2003.
+# THIRD AUTHOR David Blanchet <david.blanchet@free.fr> 2006, 2008.
+# FOURTH AUTHOR Dominique Pellé <dominique.pelle@gmail.com> 2008, 2018.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Vim 8.1\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2018-10-30 09:47+0100\n"
+"PO-Revision-Date: 2018-10-30 10:09+0100\n"
+"Last-Translator: Dominique Pellé <dominique.pelle@gmail.com>\n"
+"Language-Team: French\n"
+"Language: fr\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-15\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\n"
+
+msgid "E831: bf_key_init() called with empty password"
+msgstr "E831: bf_key_init() appelée avec un mot de passe vide"
+
+msgid "E820: sizeof(uint32_t) != 4"
+msgstr "E820: sizeof(uint32_t) != 4"
+
+msgid "E817: Blowfish big/little endian use wrong"
+msgstr "E817: petit/gros boutisme incorrect dans blowfish"
+
+msgid "E818: sha256 test failed"
+msgstr "E818: le test de sha256 a échoué"
+
+msgid "E819: Blowfish test failed"
+msgstr "E819: le test de blowfish a échoué"
+
+# DB - TODO : Trouver une traduction valable et attestée pour "location".
+msgid "[Location List]"
+msgstr "[Liste des emplacements]"
+
+msgid "[Quickfix List]"
+msgstr "[Liste Quickfix]"
+
+msgid "E855: Autocommands caused command to abort"
+msgstr "E855: Des autocommandes ont causé la terminaison de la commande"
+
+# AB - Il faut respecter l'esprit plus que la lettre.
+msgid "E82: Cannot allocate any buffer, exiting..."
+msgstr "E82: Aucun tampon ne peut être alloué, Vim doit s'arrêter"
+
+# AB - La situation est probablement plus grave que la version anglaise ne le
+# laisse entendre (voir l'aide en ligne). La version française est plus
+# explicite.
+msgid "E83: Cannot allocate buffer, using other one..."
+msgstr ""
+"E83: L'allocation du tampon a échoué : arrêtez Vim, libérez de la mémoire"
+
+msgid "E931: Buffer cannot be registered"
+msgstr "E931: Le tampon ne peut pas être enregistré"
+
+msgid "E937: Attempt to delete a buffer that is in use"
+msgstr "E937: Tentative de suppression d'un tampon en cours d'utilisation"
+
+msgid "E515: No buffers were unloaded"
+msgstr "E515: Aucun tampon n'a été déchargé"
+
+msgid "E516: No buffers were deleted"
+msgstr "E516: Aucun tampon n'a été effacé"
+
+msgid "E517: No buffers were wiped out"
+msgstr "E517: Aucun tampon n'a été détruit"
+
+#, c-format
+msgid "%d buffer unloaded"
+msgid_plural "%d buffers unloaded"
+msgstr[0] "%d tampon a été déchargé"
+msgstr[1] "%d tampons ont été déchargés"
+
+#, c-format
+msgid "%d buffer deleted"
+msgid_plural "%d buffers deleted"
+msgstr[0] "%d tampon a été effacé"
+msgstr[1] "%d tampons ont été effacés"
+
+#, c-format
+msgid "%d buffer wiped out"
+msgid_plural "%d buffers wiped out"
+msgstr[0] "%d tampon a été détruit"
+msgstr[1] "%d tampons ont été détruits"
+
+msgid "E90: Cannot unload last buffer"
+msgstr "E90: Impossible de décharger le dernier tampon"
+
+# AB - La version française est meilleure que la version anglaise.
+msgid "E84: No modified buffer found"
+msgstr "E84: Aucun tampon n'est modifié"
+
+msgid "E85: There is no listed buffer"
+msgstr "E85: Aucun tampon n'est listé"
+
+# AB - Je ne suis pas sûr que l'on puisse obtenir ce message.
+msgid "E87: Cannot go beyond last buffer"
+msgstr "E87: Impossible d'aller après le dernier tampon"
+
+# AB - Je ne suis pas sûr que l'on puisse obtenir ce message.
+msgid "E88: Cannot go before first buffer"
+msgstr "E88: Impossible d'aller avant le premier tampon"
+
+#, c-format
+msgid "E89: No write since last change for buffer %ld (add ! to override)"
+msgstr ""
+"E89: Le tampon %ld n'a pas été enregistré (ajoutez ! pour passer outre)"
+
+msgid "E948: Job still running (add ! to end the job)"
+msgstr "E948: Tâche en cours d'exécution (ajouter ! pour terminer la tâche)"
+
+msgid "E37: No write since last change (add ! to override)"
+msgstr "E37: Modifications non enregistrées (ajoutez ! pour passer outre)"
+
+msgid "E948: Job still running"
+msgstr "E948: Tâche en cours d'exécution"
+
+msgid "E37: No write since last change"
+msgstr "E37: Modifications non enregistrées"
+
+msgid "W14: Warning: List of file names overflow"
+msgstr "W14: Alerte : La liste des noms de fichier déborde"
+
+# AB - Vu le code source, la version française est meilleure que la
+# version anglaise. Ce message est similaire au message E86.
+#, c-format
+msgid "E92: Buffer %ld not found"
+msgstr "E92: Le tampon %ld n'existe pas"
+
+# AB - Il faut respecter l'esprit plus que la lettre.
+#, c-format
+msgid "E93: More than one match for %s"
+msgstr "E93: Plusieurs tampons correspondent à %s"
+
+#, c-format
+msgid "E94: No matching buffer for %s"
+msgstr "E94: Aucun tampon ne correspond à %s"
+
+#, c-format
+msgid "line %ld"
+msgstr "ligne %ld"
+
+msgid "E95: Buffer with this name already exists"
+msgstr "E95: Un tampon porte déjà ce nom"
+
+msgid " [Modified]"
+msgstr "[Modifié]"
+
+# AB - "[Inédité]" est plus correct, mais sonne faux.
+msgid "[Not edited]"
+msgstr "[Non édité]"
+
+msgid "[New file]"
+msgstr "[Nouveau fichier]"
+
+msgid "[Read errors]"
+msgstr "[Erreurs de lecture]"
+
+msgid "[RO]"
+msgstr "[RO]"
+
+# AB - La version courte, "[RO]", devrait-elle être traduite par "[LS]" ?
+# Il faudrait faire un sondage auprès des utilisateurs francophones.
+msgid "[readonly]"
+msgstr "[lecture-seule]"
+
+#, c-format
+msgid "%ld line --%d%%--"
+msgid_plural "%ld lines --%d%%--"
+msgstr[0] "%ld ligne --%d%%--"
+msgstr[1] "%ld lignes --%d%%--"
+
+# AB - Faut-il remplacer "sur" par "de" ?
+# DB - Mon avis : oui.
+#, c-format
+msgid "line %ld of %ld --%d%%-- col "
+msgstr "ligne %ld sur %ld --%d%%-- col "
+
+# DB - Je trouvais [Aucun fichier] (VO : [No file]) plus naturel
+# lors du lancement de Vim en mode graphique (ce message
+# apparaît notamment dans le titre de la fenêtre).
+msgid "[No Name]"
+msgstr "[Aucun nom]"
+
+msgid "help"
+msgstr "aide"
+
+msgid "[Help]"
+msgstr "[Aide]"
+
+# AB - "Prévisualisation" prend beaucoup de place. "Prévision" est une
+# traduction littérale et brève, mais qui risque fort d'être mal comprise.
+# J'ai finalement choisi d'utiliser une abréviation, mais cela ne me
+# satisfait pas.
+msgid "[Preview]"
+msgstr "[Prévisu]"
+
+msgid "All"
+msgstr "Tout"
+
+msgid "Bot"
+msgstr "Bas"
+
+# AB - Attention, on passe de trois à quatre lettres.
+msgid "Top"
+msgstr "Haut"
+
+msgid ""
+"\n"
+"# Buffer list:\n"
+msgstr ""
+"\n"
+"# Liste des tampons :\n"
+
+msgid "E382: Cannot write, 'buftype' option is set"
+msgstr "E382: Écriture impossible, l'option 'buftype' est activée"
+
+msgid "[Prompt]"
+msgstr "[Invite]"
+
+msgid "[Scratch]"
+msgstr "[Brouillon]"
+
+msgid ""
+"\n"
+"--- Signs ---"
+msgstr ""
+"\n"
+"--- Symboles ---"
+
+#, c-format
+msgid "Signs for %s:"
+msgstr "Symboles dans %s :"
+
+#, c-format
+msgid " line=%ld id=%d name=%s"
+msgstr " ligne=%ld id=%d nom=%s"
+
+msgid "E902: Cannot connect to port"
+msgstr "E902: Impossible de se connecter au port"
+
+msgid "E901: gethostbyname() in channel_open()"
+msgstr "E901: gethostbyname() dans channel_open()"
+
+msgid "E898: socket() in channel_open()"
+msgstr "E898: socket() dans channel_open()"
+
+msgid "E903: received command with non-string argument"
+msgstr "E903: commande reçue avec un argument qui n'est pas une chaîne"
+
+msgid "E904: last argument for expr/call must be a number"
+msgstr "E904: le dernier argument de expr/call doit être un nombre"
+
+msgid "E904: third argument for call must be a list"
+msgstr "E904: le troisième argument de \"call\" doit être une liste"
+
+#, c-format
+msgid "E905: received unknown command: %s"
+msgstr "E905: commande inconnue reçue : %s"
+
+#, c-format
+msgid "E630: %s(): write while not connected"
+msgstr "E630: %s() : écriture sans être connecté"
+
+#, c-format
+msgid "E631: %s(): write failed"
+msgstr "E631: %s() : erreur d'écriture"
+
+#, c-format
+msgid "E917: Cannot use a callback with %s()"
+msgstr "E917: Impossible d'utiliser un callback avec %s()"
+
+msgid "E912: cannot use ch_evalexpr()/ch_sendexpr() with a raw or nl channel"
+msgstr ""
+"E912: Impossible d'utiliser ch_evalexpr()/ch_sendexpr() avec un canal brut "
+"ou nl"
+
+msgid "E906: not an open channel"
+msgstr "E906: pas un canal ouvert"
+
+msgid "E920: _io file requires _name to be set"
+msgstr "E920: fichier _io nécessite _name"
+
+msgid "E915: in_io buffer requires in_buf or in_name to be set"
+msgstr "E915: tampon in_io nécessite in_buf ou in_name "
+
+#, c-format
+msgid "E918: buffer must be loaded: %s"
+msgstr "E918: le tampon doit être chargé : %s"
+
+msgid "E821: File is encrypted with unknown method"
+msgstr "E821: Le fichier est chiffré avec une méthode inconnue"
+
+msgid "Warning: Using a weak encryption method; see :help 'cm'"
+msgstr ""
+"Alerte : utilisation d'une méthode de chiffrage faible ; consultez :help 'cm'"
+
+msgid "Enter encryption key: "
+msgstr "Tapez la clé de chiffrement : "
+
+msgid "Enter same key again: "
+msgstr "Tapez la clé à nouveau : "
+
+msgid "Keys don't match!"
+msgstr "Les clés ne correspondent pas !"
+
+msgid "[crypted]"
+msgstr "[chiffré]"
+
+#, c-format
+msgid "E720: Missing colon in Dictionary: %s"
+msgstr "E720: Il manque ':' dans le Dictionnaire %s"
+
+#, c-format
+msgid "E721: Duplicate key in Dictionary: \"%s\""
+msgstr "E721: Clé dupliquée dans le Dictionnaire : %s"
+
+#, c-format
+msgid "E722: Missing comma in Dictionary: %s"
+msgstr "E722: Il manque une virgule dans le Dictionnaire : %s"
+
+#, c-format
+msgid "E723: Missing end of Dictionary '}': %s"
+msgstr "E723: Il manque '}' à la fin du Dictionnaire : %s"
+
+msgid "extend() argument"
+msgstr "argument de extend()"
+
+#, c-format
+msgid "E737: Key already exists: %s"
+msgstr "E737: La clé existe déjà : %s"
+
+#, c-format
+msgid "E96: Cannot diff more than %ld buffers"
+msgstr "E96: Impossible d'utiliser diff sur plus de %ld tampons"
+
+#, c-format
+msgid "Not enough memory to use internal diff for buffer \"%s\""
+msgstr "Pas assez de mémoire pour utiliser l'outil diff interne pour le tampon \"%s\""
+
+msgid "E810: Cannot read or write temp files"
+msgstr "E810: Impossible de lire ou écrire des fichiers temporaires"
+
+# AB - La version française est meilleure que la version anglaise.
+msgid "E97: Cannot create diffs"
+msgstr "E97: diff ne fonctionne pas"
+
+msgid "E960: Problem creating the internal diff"
+msgstr "E960: Problème lors de la création de l'outil diff interne"
+
+msgid "Patch file"
+msgstr "Fichier rustine"
+
+msgid "E816: Cannot read patch output"
+msgstr "E816: Le fichier intermédiaire produit par patch n'a pu être lu"
+
+msgid "E98: Cannot read diff output"
+msgstr "E98: Le fichier intermédiaire produit par diff n'a pu être lu"
+
+msgid "E959: Invalid diff format."
+msgstr "E959: Format diff invalide."
+
+msgid "E99: Current buffer is not in diff mode"
+msgstr "E99: Le tampon courant n'est pas en mode diff"
+
+msgid "E793: No other buffer in diff mode is modifiable"
+msgstr "E793: Aucun autre tampon en mode diff n'est modifiable"
+
+msgid "E100: No other buffer in diff mode"
+msgstr "E100: Aucun autre tampon n'est en mode diff"
+
+# AB - La version française est meilleure que la version anglaise, mais elle
+# peut être améliorée.
+msgid "E101: More than two buffers in diff mode, don't know which one to use"
+msgstr "E101: Plus de deux tampons sont en mode diff, soyez plus précis"
+
+#, c-format
+msgid "E102: Can't find buffer \"%s\""
+msgstr "E102: Le tampon %s est introuvable"
+
+#, c-format
+msgid "E103: Buffer \"%s\" is not in diff mode"
+msgstr "E103: Le tampon %s n'est pas en mode diff"
+
+msgid "E787: Buffer changed unexpectedly"
+msgstr "E787: Le tampon a été modifié inopinément"
+
+# AB - Je cherche une traduction plus concise pour "escape".
+msgid "E104: Escape not allowed in digraph"
+msgstr "E104: Un digraphe ne peut contenir le caractère d'échappement"
+
+# AB - La version française est trop verbeuse.
+msgid "E544: Keymap file not found"
+msgstr "E544: Le fichier descripteur de clavier est introuvable"
+
+# AB - La version française est meilleure que la version anglaise.
+msgid "E105: Using :loadkeymap not in a sourced file"
+msgstr "E105: :loadkeymap ne peut être utilisé que dans un script Vim"
+
+msgid "E791: Empty keymap entry"
+msgstr "E791: Entrée du descripteur de clavier (keymap) vide"
+
+# AB - Remplacer "complétion" par "complètement" ? Voir l'éthymologie
+# d'"accrétion".
+msgid " Keyword completion (^N^P)"
+msgstr " Complètement de mot-clé (^N^P)"
+
+# DB - todo : Faut-il une majuscule à "mode" ?
+msgid " ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+msgstr " mode ^X (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+
+msgid " Whole line completion (^L^N^P)"
+msgstr " Complètement de ligne entière (^L^N^P)"
+
+msgid " File name completion (^F^N^P)"
+msgstr " Complètement de nom de fichier (^F^N^P)"
+
+msgid " Tag completion (^]^N^P)"
+msgstr " Complètement de marqueur (^]^N^P)"
+
+# AB - J'ai dû avoir une bonne raison de faire une version française aussi
+# différente de la version anglaise. Il me faut la retrouver.
+# DB - TODO
+msgid " Path pattern completion (^N^P)"
+msgstr " Complètement global de mot-clé (^N^P)"
+
+msgid " Definition completion (^D^N^P)"
+msgstr " Complètement de définition (^D^N^P)"
+
+# AB - Trouver une meilleure formulation que "selon le".
+# DB : proposition : "avec"
+msgid " Dictionary completion (^K^N^P)"
+msgstr " Complètement avec le dictionnaire (^K^N^P)"
+
+# AB - Trouver une meilleure formulation que "selon le".
+msgid " Thesaurus completion (^T^N^P)"
+msgstr " Complètement avec le thésaurus (^T^N^P)"
+
+# AB - La version française est meilleure que la version anglaise.
+# DB : Suggestion.
+msgid " Command-line completion (^V^N^P)"
+msgstr " Complètement de ligne de commande (^V^N^P)"
+
+msgid " User defined completion (^U^N^P)"
+msgstr " Complètement défini par l'utilisateur (^U^N^P)"
+
+# DB : On doit pouvoir trouver nettement mieux que ça.
+msgid " Omni completion (^O^N^P)"
+msgstr " Complètement selon le type de fichier (Omni) (^O^N^P)"
+
+msgid " Spelling suggestion (s^N^P)"
+msgstr " Suggestion d'orthographe (s^N^P)"
+
+msgid " Keyword Local completion (^N^P)"
+msgstr " Complètement local de mot-clé (^N/^P)"
+
+# AB - Ce texte s'ajoute à la fin d'un des messages de complétion ci-dessus.
+# Il faut éviter de le faire trop long. Je pense que la version française
+# est suffisamment compréhensible dans le contexte dans lequel elle est
+# affichée.
+msgid "Hit end of paragraph"
+msgstr "Fin du paragraphe"
+
+msgid "E839: Completion function changed window"
+msgstr "E839: La fonction de complètement a changé la fenêtre"
+
+msgid "E840: Completion function deleted text"
+msgstr "E840: La fonction de complètement a effacé du texte"
+
+msgid "'dictionary' option is empty"
+msgstr "L'option 'dictionary' est vide"
+
+msgid "'thesaurus' option is empty"
+msgstr "L'option 'thesaurus' est vide"
+
+#, c-format
+msgid "Scanning dictionary: %s"
+msgstr "Examen du dictionnaire : %s"
+
+msgid " (insert) Scroll (^E/^Y)"
+msgstr " (insertion) Défilement (^E/^Y)"
+
+msgid " (replace) Scroll (^E/^Y)"
+msgstr " (remplacement) Défilement (^E/^Y)"
+
+#, c-format
+msgid "Scanning: %s"
+msgstr "Examen : %s"
+
+msgid "Scanning tags."
+msgstr "Examen des marqueurs."
+
+msgid "match in file"
+msgstr "correspondance dans le fichier"
+
+# AB - Cette chaîne de caractères est ajoutée en début de ligne lorsqu'une
+# opération de complétion est répétée (typiquement avec CTRL-X CTRL-N).
+# Que ce soit en anglais ou en français, il y a un problème de majuscules.
+# Bien qu'insatisfaisante, cette traduction semble optimale.
+msgid " Adding"
+msgstr " Ajout"
+
+msgid "-- Searching..."
+msgstr "-- Recherche en cours..."
+
+# AB - Ce texte s'ajoute à la fin d'un des messages de complétion ci-dessus.
+# AB - Faut-il utiliser "origine" ou "originel" au lieu d'"original" ?
+# DB : Suggestion.
+msgid "Back at original"
+msgstr "Retour au point de départ"
+
+# AB - Ce texte s'ajoute à la fin d'un des messages de complétion ci-dessus.
+msgid "Word from other line"
+msgstr "Mot d'une autre ligne"
+
+# AB - Ce texte s'ajoute à la fin d'un des messages de complétion ci-dessus.
+msgid "The only match"
+msgstr "La seule correspondance"
+
+# AB - Ce texte s'ajoute à la fin d'un des messages de complétion ci-dessus.
+# AB - Faut-il remplacer "sur" par "de" ?
+# DB : Pour moi, non.
+#, c-format
+msgid "match %d of %d"
+msgstr "Correspondance %d sur %d"
+
+# AB - Ce texte s'ajoute à la fin d'un des messages de complétion ci-dessus.
+# DB - todo : la VO n'a pas de majuscule.
+#, c-format
+msgid "match %d"
+msgstr "Correspondance %d"
+
+msgid "E18: Unexpected characters in :let"
+msgstr "E18: Caractères inattendus avant '='"
+
+#, c-format
+msgid "E121: Undefined variable: %s"
+msgstr "E121: Variable non définie : %s"
+
+msgid "E111: Missing ']'"
+msgstr "E111: ']' manquant"
+
+msgid "E719: Cannot use [:] with a Dictionary"
+msgstr "E719: Utilisation de [:] impossible avec un Dictionnaire"
+
+#, c-format
+msgid "E734: Wrong variable type for %s="
+msgstr "E734: Type de variable erroné avec %s="
+
+#, c-format
+msgid "E461: Illegal variable name: %s"
+msgstr "E461: Nom de variable invalide : %s"
+
+msgid "E806: using Float as a String"
+msgstr "E806: Utilisation d'un Flottant comme une Chaîne"
+
+# DB - todo : trouver mieux que "destinations".
+msgid "E687: Less targets than List items"
+msgstr "E687: Moins de destinations que d'éléments dans la Liste"
+
+# DB - todo : trouver mieux que "destinations".
+msgid "E688: More targets than List items"
+msgstr "E688: Plus de destinations que d'éléments dans la Liste"
+
+msgid "Double ; in list of variables"
+msgstr "Double ; dans une liste de variables"
+
+#, c-format
+msgid "E738: Can't list variables for %s"
+msgstr "E738: Impossible de lister les variables de %s"
+
+msgid "E689: Can only index a List or Dictionary"
+msgstr "E689: Seul une Liste ou un Dictionnaire peut être indexé"
+
+msgid "E708: [:] must come last"
+msgstr "E708: [:] ne peut être spécifié qu'en dernier"
+
+msgid "E709: [:] requires a List value"
+msgstr "E709: [:] nécessite une Liste"
+
+msgid "E710: List value has more items than target"
+msgstr "E710: La Liste a plus d'éléments que la destination"
+
+msgid "E711: List value has not enough items"
+msgstr "E711: La Liste n'a pas assez d'éléments"
+
+msgid "E690: Missing \"in\" after :for"
+msgstr "E690: \"in\" manquant après :for"
+
+#, c-format
+msgid "E108: No such variable: \"%s\""
+msgstr "E108: Variable inexistante : %s"
+
+#, c-format
+msgid "E940: Cannot lock or unlock variable %s"
+msgstr "E940: Impossible de (dé)verrouiller la variable %s"
+
+msgid "E743: variable nested too deep for (un)lock"
+msgstr "E743: variable trop imbriquée pour la (dé)verrouiller"
+
+# AB - Je suis partagé entre la concision d'une traduction assez littérale et
+# la lourdeur d'une traduction plus correcte.
+msgid "E109: Missing ':' after '?'"
+msgstr "E109: Il manque ':' après '?'"
+
+msgid "E804: Cannot use '%' with Float"
+msgstr "E804: Impossible d'utiliser '%' avec un Flottant"
+
+msgid "E110: Missing ')'"
+msgstr "E110: ')' manquant"
+
+msgid "E695: Cannot index a Funcref"
+msgstr "E695: Impossible d'indexer une Funcref"
+
+msgid "E909: Cannot index a special variable"
+msgstr "E909: Impossible d'indexer une variable spéciale"
+
+# AB - La version française est meilleure que la version anglaise.
+#, c-format
+msgid "E112: Option name missing: %s"
+msgstr "E112: Il manque un nom d'option après %s"
+
+#, c-format
+msgid "E113: Unknown option: %s"
+msgstr "E113: Option inconnue : %s"
+
+# AB - La version française est meilleure que la version anglaise, qui est
+# erronée, d'ailleurs : il s'agit d'une "double quote" et non d'une
+# "quote".
+#, c-format
+msgid "E114: Missing quote: %s"
+msgstr "E114: Il manque \" à la fin de %s"
+
+# AB - La version française est meilleure que la version anglaise.
+#, c-format
+msgid "E115: Missing quote: %s"
+msgstr "E115: Il manque ' à la fin de %s"
+
+msgid "Not enough memory to set references, garbage collection aborted!"
+msgstr ""
+"Pas assez de mémoire pour les références, arrêt du ramassage de miètes !"
+
+msgid "E724: variable nested too deep for displaying"
+msgstr "E724: variable trop imbriquée pour être affichée"
+
+msgid "E805: Using a Float as a Number"
+msgstr "E805: Utilisation d'un Flottant comme un Nombre"
+
+msgid "E703: Using a Funcref as a Number"
+msgstr "E703: Utilisation d'une Funcref comme un Nombre"
+
+msgid "E745: Using a List as a Number"
+msgstr "E745: Utilisation d'une Liste comme un Nombre"
+
+msgid "E728: Using a Dictionary as a Number"
+msgstr "E728: Utilisation d'un Dictionnaire comme un Nombre"
+
+msgid "E910: Using a Job as a Number"
+msgstr "E910: Utilisation d'une Tâche comme un Nombre"
+
+msgid "E913: Using a Channel as a Number"
+msgstr "E913: Utilisation d'un Canal comme un Nombre"
+
+msgid "E891: Using a Funcref as a Float"
+msgstr "E891: Utilisation d'une Funcref comme un Flottant"
+
+msgid "E892: Using a String as a Float"
+msgstr "E892: Utilisation d'une Chaîne comme un Flottant"
+
+msgid "E893: Using a List as a Float"
+msgstr "E893: Utilisation d'une Liste comme un Flottant"
+
+msgid "E894: Using a Dictionary as a Float"
+msgstr "E894: Utilisation d'un Dictionnaire comme un Flottant"
+
+msgid "E907: Using a special value as a Float"
+msgstr "E907: Utilisation d'une valeur spéciale comme un Flottant"
+
+msgid "E911: Using a Job as a Float"
+msgstr "E911: Utilisation d'une Tâche comme un Flottant"
+
+msgid "E914: Using a Channel as a Float"
+msgstr "E914: Utilisation d'un Canal comme un Flottant"
+
+msgid "E729: using Funcref as a String"
+msgstr "E729: Utilisation d'une Funcref comme une Chaîne"
+
+msgid "E730: using List as a String"
+msgstr "E730: Utilisation d'une Liste comme une Chaîne"
+
+msgid "E731: using Dictionary as a String"
+msgstr "E731: Utilisation d'un Dictionnaire comme une Chaîne"
+
+msgid "E908: using an invalid value as a String"
+msgstr "E908: Utilisation d'une valeur invalide comme une Chaîne"
+
+#, c-format
+msgid "E795: Cannot delete variable %s"
+msgstr "E795: Impossible de supprimer la variable %s"
+
+#, c-format
+msgid "E704: Funcref variable name must start with a capital: %s"
+msgstr "E704: Le nom d'une Funcref doit commencer par une majuscule : %s"
+
+#, c-format
+msgid "E705: Variable name conflicts with existing function: %s"
+msgstr "E705: Le nom d'une variable entre en conflit avec la fonction %s"
+
+#, c-format
+msgid "E741: Value is locked: %s"
+msgstr "E741: La valeur de %s est verrouillée"
+
+msgid "Unknown"
+msgstr "Inconnu"
+
+#, c-format
+msgid "E742: Cannot change value of %s"
+msgstr "E742: Impossible de modifier la valeur de %s"
+
+msgid "E698: variable nested too deep for making a copy"
+msgstr "E698: variable trop imbriquée pour en faire une copie"
+
+# AB - La version française est capitalisée pour être en accord avec les autres
+# commentaires enregistrés dans le fichier viminfo.
+msgid ""
+"\n"
+"# global variables:\n"
+msgstr ""
+"\n"
+"# Variables globales:\n"
+
+# DB - Plus précis ("la dernière fois") ?
+msgid ""
+"\n"
+"\tLast set from "
+msgstr ""
+"\n"
+"\tModifié la dernière fois dans "
+
+msgid " line "
+msgstr " ligne "
+
+msgid "E691: Can only compare List with List"
+msgstr "E691: Une Liste ne peut être comparée qu'avec une Liste"
+
+msgid "E692: Invalid operation for List"
+msgstr "E692: Opération invalide avec les Liste"
+
+msgid "E735: Can only compare Dictionary with Dictionary"
+msgstr "E735: Un Dictionnaire ne peut être comparé qu'avec un Dictionnaire"
+
+msgid "E736: Invalid operation for Dictionary"
+msgstr "E736: Opération invalide avec les Dictionnaires"
+
+msgid "E694: Invalid operation for Funcrefs"
+msgstr "E694: Opération invalide avec les Funcrefs"
+
+msgid "map() argument"
+msgstr "argument de map()"
+
+msgid "filter() argument"
+msgstr "argument de filter()"
+
+#, c-format
+msgid "E686: Argument of %s must be a List"
+msgstr "E686: L'argument de %s doit être une Liste"
+
+msgid "E928: String required"
+msgstr "E928: Chaîne requis"
+
+msgid "E808: Number or Float required"
+msgstr "E808: Nombre ou Flottant requis"
+
+msgid "add() argument"
+msgstr "argument de add()"
+
+msgid "E785: complete() can only be used in Insert mode"
+msgstr "E785: complete() n'est utilisable que dans le mode Insertion"
+
+# AB - Texte par défaut du bouton de la boîte de dialogue affichée par la
+# fonction confirm().
+msgid "&Ok"
+msgstr "&Ok"
+
+#, c-format
+msgid "+-%s%3ld line: "
+msgid_plural "+-%s%3ld lines: "
+msgstr[0] "+-%s%3ld ligne : "
+msgstr[1] "+-%s%3ld lignes : "
+
+#, c-format
+msgid "E700: Unknown function: %s"
+msgstr "E700: Fonction inconnue : %s"
+
+msgid "E922: expected a dict"
+msgstr "E922: dictionnaire attendu"
+
+msgid "E923: Second argument of function() must be a list or a dict"
+msgstr ""
+"E923: Le second argument de function() doit être une liste ou un dictionnaire"
+
+# AB - Textes des boutons de la boîte de dialogue affichée par inputdialog().
+msgid ""
+"&OK\n"
+"&Cancel"
+msgstr ""
+"&Ok\n"
+"&Annuler"
+
+# AB - La version française est meilleure que la version anglaise.
+msgid "called inputrestore() more often than inputsave()"
+msgstr "inputrestore() a été appelé plus de fois qu'inputsave()"
+
+msgid "insert() argument"
+msgstr "argument de insert()"
+
+msgid "E786: Range not allowed"
+msgstr "E786: Les plages ne sont pas autorisées"
+
+msgid "E916: not a valid job"
+msgstr "E916: tâche invalide"
+
+msgid "E701: Invalid type for len()"
+msgstr "E701: Type invalide avec len()"
+
+msgid "E957: Invalid window number"
+msgstr "E957: numéro de fenêtre invalide"
+
+#, c-format
+msgid "E798: ID is reserved for \":match\": %ld"
+msgstr "E798: ID est réservé pour \":match\": %ld"
+
+msgid "E726: Stride is zero"
+msgstr "E726: Le pas est nul"
+
+msgid "E727: Start past end"
+msgstr "E727: Début au-delà de la fin"
+
+msgid "<empty>"
+msgstr "<vide>"
+
+msgid "E240: No connection to the X server"
+msgstr "E240: Pas de connexion au serveur X"
+
+# AB - La version française est meilleure que la version anglaise.
+#, c-format
+msgid "E241: Unable to send to %s"
+msgstr "E241: L'envoi au serveur %s a échoué"
+
+msgid "E277: Unable to read a server reply"
+msgstr "E277: Impossible de lire la réponse du serveur"
+
+msgid "E941: already started a server"
+msgstr "E941: serveur déjà démarré"
+
+msgid "E942: +clientserver feature not available"
+msgstr "E942: La fonctionnalité +clientserver n'est pas disponible"
+
+msgid "remove() argument"
+msgstr "argument de remove()"
+
+msgid "E655: Too many symbolic links (cycle?)"
+msgstr "E655: Trop de liens symboliques (cycle ?)"
+
+msgid "reverse() argument"
+msgstr "argument de reverse()"
+
+# AB - La version française est meilleure que la version anglaise.
+msgid "E258: Unable to send to client"
+msgstr "E258: La réponse n'a pas pu être envoyée au client"
+
+#, c-format
+msgid "E927: Invalid action: '%s'"
+msgstr "E927: Action invalide : « %s »"
+
+msgid "sort() argument"
+msgstr "argument de sort()"
+
+msgid "uniq() argument"
+msgstr "argument de uniq()"
+
+msgid "E702: Sort compare function failed"
+msgstr "E702: La fonction de comparaison de sort() a échoué"
+
+msgid "E882: Uniq compare function failed"
+msgstr "E882: La fonction de comparaison de uniq() a échoué"
+
+msgid "(Invalid)"
+msgstr "(Invalide)"
+
+#, c-format
+msgid "E935: invalid submatch number: %d"
+msgstr "E935: numéro de submatch invalide : %d"
+
+msgid "E677: Error writing temp file"
+msgstr "E677: Erreur lors de l'écriture du fichier temporaire"
+
+msgid "E921: Invalid callback argument"
+msgstr "E921: Argument de callback invalide"
+
+#, c-format
+msgid "<%s>%s%s %d, Hex %02x, Oct %03o, Digr %s"
+msgstr "<%s>%s%s %d, Hexa %02x, Octal %03o, Digr %s"
+
+#, c-format
+msgid "<%s>%s%s %d, Hex %02x, Octal %03o"
+msgstr "<%s>%s%s %d, Hexa %02x, Octal %03o"
+
+#, c-format
+msgid "> %d, Hex %04x, Oct %o, Digr %s"
+msgstr "> %d, Hexa %04x, Octal %o, Digr %s"
+
+#, c-format
+msgid "> %d, Hex %08x, Oct %o, Digr %s"
+msgstr "> %d, Hexa %08x, Octal %o, Digr %s"
+
+#, c-format
+msgid "> %d, Hex %04x, Octal %o"
+msgstr "> %d, Hexa %04x, Octal %o"
+
+#, c-format
+msgid "> %d, Hex %08x, Octal %o"
+msgstr "> %d, Hexa %08x, Octal %o"
+
+# AB - La version anglaise est très mauvaise, ce qui m'oblige a inventer une
+# version française.
+msgid "E134: Move lines into themselves"
+msgstr "E134: La destination est dans la plage d'origine"
+
+#, c-format
+msgid "%ld line moved"
+msgid_plural "%ld lines moved"
+msgstr[0] "%ld ligne déplacée"
+msgstr[1] "%ld lignes déplacées"
+
+#, c-format
+msgid "%ld lines filtered"
+msgstr "%ld lignes filtrées"
+
+# AB - J'ai volontairement omis l'astérisque initiale car je pense que le
+# motif "Filter*" décrit plus clairement les quatre autocommandes liées
+# au filtrage (FilterReadPre, FilterReadPost, FilterWritePre et
+# FilterWritePost) que "*Filter*" que l'on confond avec une tentative de
+# mise en valeur.
+msgid "E135: *Filter* Autocommands must not change current buffer"
+msgstr ""
+"E135: Les autocommandes Filter* ne doivent pas changer le tampon courant"
+
+# AB - Il faut respecter l'esprit plus que la lettre. Dans le cas présent,
+# nettement plus.
+msgid "[No write since last change]\n"
+msgstr "[Attention : tout n'est pas enregistré]\n"
+
+# AB - Le numéro et le message d'erreur (%s ci-dessous) et le "numéro" de ligne
+# sont des chaînes de caractères dont le contenu est à la discrétion de
+# l'appelant de la fonction viminfo_error().
+#, c-format
+msgid "%sviminfo: %s in line: "
+msgstr "%sviminfo : %s à la ligne "
+
+# AB - La version française est meilleure que la version anglaise.
+msgid "E136: viminfo: Too many errors, skipping rest of file"
+msgstr ""
+"E136: Il y a trop d'erreurs ; interruption de la lecture du fichier viminfo"
+
+# AB - Ce texte fait partie d'un message de débogage.
+# DB - ... dont les valeurs possibles sont les messages
+# qui suivent.
+#, c-format
+msgid "Reading viminfo file \"%s\"%s%s%s"
+msgstr "Lecture du fichier viminfo \"%s\"%s%s%s"
+
+# AB - Ce texte fait partie d'un message de débogage.
+# DB - Voir ci-dessus.
+msgid " info"
+msgstr " info"
+
+# AB - Ce texte fait partie d'un message de débogage.
+# DB - Voir ci-dessus.
+msgid " marks"
+msgstr " marques"
+
+msgid " oldfiles"
+msgstr " vieux fichiers"
+
+# AB - Ce texte fait partie d'un message de débogage.
+# DB - Voir ci-dessus.
+msgid " FAILED"
+msgstr " ÉCHEC"
+
+# AB - J'espère que la plupart des utilisateurs aura l'idée d'aller vérifier
+# ses droits d'accès.
+# AB - Le mot "viminfo" a été retiré pour que le message ne dépasse pas 80
+# caractères dans le cas courant où %s = /home/12345678/.viminfo
+#, c-format
+msgid "E137: Viminfo file is not writable: %s"
+msgstr "E137: L'écriture dans le fichier %s est interdite"
+
+#, c-format
+msgid "E929: Too many viminfo temp files, like %s!"
+msgstr "E929: Trop de fichiers temporaires viminfo, comme %s!"
+
+# AB - Le point d'exclamation est superflu.
+# AB - Le mot "viminfo" a été retiré pour que le message ne dépasse pas 80
+# caractères dans le cas courant où %s = /home/12345678/.viminfo
+#, c-format
+msgid "E138: Can't write viminfo file %s!"
+msgstr "E138: Impossible d'écrire le fichier %s"
+
+# AB - Ce texte est un message de débogage.
+#, c-format
+msgid "Writing viminfo file \"%s\""
+msgstr "Écriture du fichier viminfo \"%s\""
+
+#, c-format
+msgid "E886: Can't rename viminfo file to %s!"
+msgstr "E886: Impossible de renommer viminfo en %s"
+
+#, c-format
+msgid "# This viminfo file was generated by Vim %s.\n"
+msgstr "# Ce fichier viminfo a été généré par Vim %s.\n"
+
+# AB - Les deux versions, bien que différentes, se valent.
+msgid ""
+"# You may edit it if you're careful!\n"
+"\n"
+msgstr ""
+"# Vous pouvez l'éditer, mais soyez prudent.\n"
+"\n"
+
+msgid "# Value of 'encoding' when this file was written\n"
+msgstr "# 'encoding' dans lequel ce fichier a été écrit\n"
+
+# AB - Ce texte est passé en argument à la fonction viminfo_error().
+# AB - "illégal" est un terme trop fort à mon goût.
+msgid "Illegal starting char"
+msgstr "Caractère initial non valide"
+
+msgid ""
+"\n"
+"# Bar lines, copied verbatim:\n"
+msgstr ""
+"\n"
+"# Lignes commençant par |, copiées littéralement :\n"
+
+# AB - Ceci est un titre de boîte de dialogue. Vérifier que la version
+# française est correcte pour les trois références ; j'ai un doute quant
+# à la troisième.
+msgid "Save As"
+msgstr "Enregistrer sous - Vim"
+
+# AB - Ceci est un contenu de boîte de dialogue (éventuellement en mode texte).
+# AB - La version française est meilleure que la version anglaise.
+msgid "Write partial file?"
+msgstr "Perdre une partie du fichier ?"
+
+# AB - La version française est nettement meilleure que la version anglaise.
+msgid "E140: Use ! to write partial buffer"
+msgstr ""
+"E140: Une partie du fichier serait perdue (ajoutez ! pour passer outre)"
+
+#, c-format
+msgid "Overwrite existing file \"%s\"?"
+msgstr "Écraser le fichier %s existant ?"
+
+#, c-format
+msgid "Swap file \"%s\" exists, overwrite anyway?"
+msgstr "Le fichier d'échange \"%s\" existe déjà, l'écraser ?"
+
+# DB - Un peu long à mon avis.
+#, c-format
+msgid "E768: Swap file exists: %s (:silent! overrides)"
+msgstr "E768: Le fichier d'échange %s existe déjà (:silent! pour passer outre)"
+
+#, c-format
+msgid "E141: No file name for buffer %ld"
+msgstr "E141: Pas de nom de fichier pour le tampon %ld"
+
+# AB - Il faut respecter l'esprit plus que la lettre.
+msgid "E142: File not written: Writing is disabled by 'write' option"
+msgstr ""
+"E142: L'option 'nowrite' est activée et empêche toute écriture du fichier"
+
+# AB - Ceci est un contenu de boîte de dialogue (éventuellement en mode texte).
+# AB - "activée pour" n'est pas une formulation très heureuse.
+#, c-format
+msgid ""
+"'readonly' option is set for \"%s\".\n"
+"Do you wish to write anyway?"
+msgstr ""
+"L'option 'readonly' est activée pour \"%s\".\n"
+"Voulez-vous tout de même enregistrer ?"
+
+#, c-format
+msgid ""
+"File permissions of \"%s\" are read-only.\n"
+"It may still be possible to write it.\n"
+"Do you wish to try?"
+msgstr ""
+"Les droits du fichier \"%s\" sont restreints à la lecture seule.\n"
+"Il peut être possible de l'écrire tout de même.\n"
+"Tenter ?"
+
+#, c-format
+msgid "E505: \"%s\" is read-only (add ! to override)"
+msgstr "E505: \"%s\" est en lecture seule (ajoutez ! pour passer outre)"
+
+# AB - Ceci est un titre de boîte de dialogue.
+msgid "Edit File"
+msgstr "Ouvrir un fichier - Vim"
+
+# AB - Il faut respecter l'esprit plus que la lettre.
+# AB - J'hésite à ajouter "à sa création" après le nom du tampon. Ce message
+# devrait n'être affiché qu'après une tentative d'ouverture de fichier,
+# la version actuelle devrait donc suffire.
+# DB - Suggestion : "nouveau tampon" ?
+#, c-format
+msgid "E143: Autocommands unexpectedly deleted new buffer %s"
+msgstr "E143: Une autocommande a effacé le nouveau tampon %s"
+
+msgid "E144: non-numeric argument to :z"
+msgstr "E144: L'argument de :z n'est pas numérique"
+
+# AB - La version française fera peut-être mieux passer l'amère pilule.
+# La consultation de l'aide donnera l'explication complète à ceux qui
+# ne comprendraient pas à quoi ce message est dû.
+msgid "E145: Shell commands not allowed in rvim"
+msgstr "E145: Les commandes externes sont indisponibles dans rvim"
+
+msgid "E146: Regular expressions can't be delimited by letters"
+msgstr ""
+"E146: Les expressions régulières ne peuvent pas être délimitées par des "
+"lettres"
+
+#, c-format
+msgid "replace with %s (y/n/a/q/l/^E/^Y)?"
+msgstr "remplacer par %s (y/n/a/q/l/^E/^Y)?"
+
+msgid "(Interrupted) "
+msgstr "(Interrompu) "
+
+#, c-format
+msgid "%ld match on %ld line"
+msgid_plural "%ld matches on %ld line"
+msgstr[0] "%ld correspondance sur %ld ligne"
+msgstr[1] "%ld correspondances sur %ld ligne"
+
+#, c-format
+msgid "%ld substitution on %ld line"
+msgid_plural "%ld substitutions on %ld line"
+msgstr[0] "%ld substitution sur %ld ligne"
+msgstr[1] "%ld substitutions sur %ld ligne"
+
+#, c-format
+msgid "%ld match on %ld lines"
+msgid_plural "%ld matches on %ld lines"
+msgstr[0] "%ld correspondance sur %ld lignes"
+msgstr[1] "%ld correspondances sur %ld lignes"
+
+#, c-format
+msgid "%ld substitution on %ld lines"
+msgid_plural "%ld substitutions on %ld lines"
+msgstr[0] "%ld substitution sur %ld lignes"
+msgstr[1] "%ld substitutions sur %ld lignes"
+
+# AB - Il faut respecter l'esprit plus que la lettre.
+# AB - Ce message devrait contenir une référence à :vglobal.
+msgid "E147: Cannot do :global recursive with a range"
+msgstr "E147: :global ne peut pas exécuter :global avec une plage"
+
+# AB - Ce message devrait contenir une référence à :vglobal.
+msgid "E148: Regular expression missing from global"
+msgstr "E148: :global doit être suivi par une expression régulière"
+
+# AB - Ce message est utilisé lorsque :vglobal ne trouve rien. Lorsque :global
+# ne trouve rien, c'est "Pattern not found: %s" / "Motif introuvable: %s"
+# qui est utilisé.
+#, c-format
+msgid "Pattern found in every line: %s"
+msgstr "Motif trouvé dans toutes les lignes : %s"
+
+#, c-format
+msgid "Pattern not found: %s"
+msgstr "Motif introuvable: %s"
+
+# AB - Ne pas traduire le dollar.
+# AB - Ce message n'est volontairement pas traduit. En effet, il fait partie
+# d'un groupe de trois messages dans viminfo, dont deux ne sont pas soumis
+# à internationalisation. J'attends que les deux autres messages soient
+# traduisibles pour traduire celui-ci.
+# DB - TODO : Qu'en est-il à présent ?
+msgid ""
+"\n"
+"# Last Substitute String:\n"
+"$"
+msgstr ""
+"\n"
+"# Dernières chaînes de substitution :\n"
+"$"
+
+# This message should *so* be E42!
+msgid "E478: Don't panic!"
+msgstr "E478: Pas de panique !"
+
+#, c-format
+msgid "E661: Sorry, no '%s' help for %s"
+msgstr "E661: Désolé, aucune aide en langue '%s' pour %s"
+
+#, c-format
+msgid "E149: Sorry, no help for %s"
+msgstr "E149: Désolé, aucune aide pour %s"
+
+#, c-format
+msgid "Sorry, help file \"%s\" not found"
+msgstr "Désolé, le fichier d'aide \"%s\" est introuvable"
+
+#, c-format
+msgid "E151: No match: %s"
+msgstr "E151: Aucune correspondance : %s"
+
+#, c-format
+msgid "E152: Cannot open %s for writing"
+msgstr "E152: Impossible d'ouvrir %s en écriture"
+
+#, c-format
+msgid "E153: Unable to open %s for reading"
+msgstr "E153: Impossible d'ouvrir %s en lecture"
+
+#, c-format
+msgid "E670: Mix of help file encodings within a language: %s"
+msgstr "E670: Encodages différents dans les fichiers d'aide en langue %s"
+
+# AB - L'étiquette la plus longue fait 27 caractères. Le nom de fichier le plus
+# long fait 12 caractères. Il faudrait donc idéalement faire une
+# traduction de 40 caractères ou moins. Ce qui est loin d'être le cas
+# présent.
+# DB - Suggestion.
+#, c-format
+msgid "E154: Duplicate tag \"%s\" in file %s/%s"
+msgstr "E154: Marqueur \"%s\" dupliqué dans le fichier %s/%s"
+
+#, c-format
+msgid "E150: Not a directory: %s"
+msgstr "E150: %s n'est pas un répertoire"
+
+# AB - Il faut respecter l'esprit plus que la lettre.
+#, c-format
+msgid "E160: Unknown sign command: %s"
+msgstr "E160: Commande inconnue : :sign %s"
+
+# AB - La version française est meilleure que la version anglaise.
+msgid "E156: Missing sign name"
+msgstr "E156: Il manque le nom du symbole"
+
+msgid "E612: Too many signs defined"
+msgstr "E612: Trop de symboles sont définis"
+
+# AB - Cette traduction ne me satisfait pas.
+# DB - Suggestion.
+#, c-format
+msgid "E239: Invalid sign text: %s"
+msgstr "E239: Le texte du symbole est invalide : %s"
+
+#, c-format
+msgid "E155: Unknown sign: %s"
+msgstr "E155: Symbole inconnu : %s"
+
+# AB - La version française est meilleure que la version anglaise.
+msgid "E159: Missing sign number"
+msgstr "E159: Il manque l'ID du symbole"
+
+# AB - Vu le code source, la version française est meilleure que la
+# version anglaise. Ce message est similaire au message E102.
+#, c-format
+msgid "E158: Invalid buffer name: %s"
+msgstr "E158: Le tampon %s est introuvable"
+
+msgid "E934: Cannot jump to a buffer that does not have a name"
+msgstr "E934: Impossible de sauter à un tampon sans nom"
+
+# AB - Vu le code source, la version française est meilleure que la
+# version anglaise.
+#, c-format
+msgid "E157: Invalid sign ID: %ld"
+msgstr "E157: Le symbole %ld est introuvable"
+
+#, c-format
+msgid "E885: Not possible to change sign %s"
+msgstr "E885: Impossible de changer le symbole %s"
+
+msgid " (NOT FOUND)"
+msgstr " (INTROUVABLE)"
+
+msgid " (not supported)"
+msgstr " (non supporté)"
+
+msgid "[Deleted]"
+msgstr "[Effacé]"
+
+msgid "No old files"
+msgstr "Aucun vieux fichier"
+
+# AB - La version française de la première phrase ne me satisfait pas.
+# DB - Suggestion.
+msgid "Entering Debug mode. Type \"cont\" to continue."
+msgstr "Mode débogage activé. Tapez \"cont\" pour continuer."
+
+#, c-format
+msgid "Oldval = \"%s\""
+msgstr "Ancienneval = \"%s\""
+
+#, c-format
+msgid "Newval = \"%s\""
+msgstr "Nouvelleval = \"%s\""
+
+#, c-format
+msgid "line %ld: %s"
+msgstr "ligne %ld : %s"
+
+#, c-format
+msgid "cmd: %s"
+msgstr "cmde : %s"
+
+msgid "frame is zero"
+msgstr "le cadre de pile est zéro"
+
+#, c-format
+msgid "frame at highest level: %d"
+msgstr "cadre de pile au niveau le plus haut : %d"
+
+#, c-format
+msgid "Breakpoint in \"%s%s\" line %ld"
+msgstr "Point d'arrêt dans %s%s ligne %ld"
+
+#, c-format
+msgid "E161: Breakpoint not found: %s"
+msgstr "E161: Le point d'arrêt %s est introuvable"
+
+msgid "No breakpoints defined"
+msgstr "Aucun point d'arrêt n'est défini"
+
+# AB - Le deuxième %s est remplacé par "func" ou "file" sans que l'on puisse
+# traduire ces mots.
+#, c-format
+msgid "%3d %s %s line %ld"
+msgstr "%3d %s %s ligne %ld"
+
+#, c-format
+msgid "%3d expr %s"
+msgstr "%3d expr %s"
+
+msgid "E750: First use \":profile start {fname}\""
+msgstr "E750: Utilisez d'abord \":profile start {nomfichier}\""
+
+# AB - "changes to" est redondant et a été omis de la version française.
+#, c-format
+msgid "Save changes to \"%s\"?"
+msgstr "Enregistrer \"%s\" ?"
+
+#, c-format
+msgid "E947: Job still running in buffer \"%s\""
+msgstr "E947: Tâche en cours d'exécution dans le buffer \"%s\""
+
+# AB - Il faut respecter l'esprit plus que la lettre.
+# AB - Ce message est similaire au message E89.
+#, c-format
+msgid "E162: No write since last change for buffer \"%s\""
+msgstr "E162: Le tampon %s n'a pas été enregistré"
+
+msgid "Warning: Entered other buffer unexpectedly (check autocommands)"
+msgstr ""
+"Alerte : Entrée inattendue dans un autre tampon (vérifier autocommandes)"
+
+msgid "E163: There is only one file to edit"
+msgstr "E163: Il n'y a qu'un seul fichier à éditer"
+
+msgid "E164: Cannot go before first file"
+msgstr "E164: Impossible d'aller avant le premier fichier"
+
+msgid "E165: Cannot go beyond last file"
+msgstr "E165: Impossible d'aller au-delà du dernier fichier"
+
+#, c-format
+msgid "E666: compiler not supported: %s"
+msgstr "E666: Compilateur %s non supporté"
+
+#, c-format
+msgid "Searching for \"%s\" in \"%s\""
+msgstr "Recherche de \"%s\" dans \"%s\""
+
+#, c-format
+msgid "Searching for \"%s\""
+msgstr "Recherche de \"%s\""
+
+#, c-format
+msgid "not found in '%s': \"%s\""
+msgstr "introuvable dans '%s' : \"%s\""
+
+#, c-format
+msgid "W20: Required python version 2.x not supported, ignoring file: %s"
+msgstr "W20: Python version 2.x non supporté, fichier %s ignoré"
+
+#, c-format
+msgid "W21: Required python version 3.x not supported, ignoring file: %s"
+msgstr "W21: Python 3.x non supporté, fichier %s ignoré"
+
+msgid "Source Vim script"
+msgstr "Sourcer un script - Vim"
+
+#, c-format
+msgid "Cannot source a directory: \"%s\""
+msgstr "Impossible de sourcer un répertoire : \"%s\""
+
+#, c-format
+msgid "could not source \"%s\""
+msgstr "impossible de sourcer \"%s\""
+
+#, c-format
+msgid "line %ld: could not source \"%s\""
+msgstr "ligne %ld : impossible de sourcer \"%s\""
+
+#, c-format
+msgid "sourcing \"%s\""
+msgstr "sourcement \"%s\""
+
+#, c-format
+msgid "line %ld: sourcing \"%s\""
+msgstr "ligne %ld : sourcement de \"%s\""
+
+#, c-format
+msgid "finished sourcing %s"
+msgstr "fin du sourcement de %s"
+
+# AB - Ce texte fait partie d'un message de débogage.
+#, c-format
+msgid "continuing in %s"
+msgstr "de retour dans %s"
+
+msgid "modeline"
+msgstr "ligne de mode"
+
+msgid "--cmd argument"
+msgstr "argument --cmd"
+
+msgid "-c argument"
+msgstr "argument -c"
+
+msgid "environment variable"
+msgstr "variable d'environnement"
+
+msgid "error handler"
+msgstr "gestionnaire d'erreur"
+
+msgid "W15: Warning: Wrong line separator, ^M may be missing"
+msgstr "W15: Alerte : Séparateur de ligne erroné, ^M possiblement manquant"
+
+msgid "E167: :scriptencoding used outside of a sourced file"
+msgstr "E167: :scriptencoding utilisé en dehors d'un fichier sourcé"
+
+msgid "E168: :finish used outside of a sourced file"
+msgstr "E168: :finish utilisé en dehors d'un fichier sourcé"
+
+# DB - Le premier %s est, au choix : "time ", "ctype " ou "messages ",
+# sans qu'il soit possible de les traduire.
+#, c-format
+msgid "Current %slanguage: \"%s\""
+msgstr "Langue courante pour %s : \"%s\""
+
+#, c-format
+msgid "E197: Cannot set language to \"%s\""
+msgstr "E197: Impossible de choisir la langue \"%s\""
+
+msgid "Entering Ex mode. Type \"visual\" to go to Normal mode."
+msgstr "Mode Ex activé. Tapez \"visual\" pour passer en mode Normal."
+
+msgid "E501: At end-of-file"
+msgstr "E501: À la fin du fichier"
+
+msgid "E169: Command too recursive"
+msgstr "E169: Commande trop récursive"
+
+#, c-format
+msgid "E605: Exception not caught: %s"
+msgstr "E605: Exception non interceptée : %s"
+
+msgid "End of sourced file"
+msgstr "Fin du fichier sourcé"
+
+msgid "End of function"
+msgstr "Fin de la fonction"
+
+msgid "E464: Ambiguous use of user-defined command"
+msgstr "E464: Utilisation ambiguë d'une commande définie par l'utilisateur"
+
+msgid "E492: Not an editor command"
+msgstr "E492: Commande inconnue"
+
+msgid "E493: Backwards range given"
+msgstr "E493: La plage spécifiée est inversée"
+
+msgid "Backwards range given, OK to swap"
+msgstr "La plage spécifiée est inversée, OK pour l'inverser"
+
+msgid "E494: Use w or w>>"
+msgstr "E494: Utilisez w ou w>>"
+
+msgid "E943: Command table needs to be updated, run 'make cmdidxs'"
+msgstr ""
+"E943: La table des commandes doit être mise à jour, lancez 'make cmdidxs'"
+
+msgid "E319: Sorry, the command is not available in this version"
+msgstr "E319: Désolé, cette commande n'est pas disponible dans cette version"
+
+#, c-format
+msgid "%d more file to edit. Quit anyway?"
+msgid_plural "%d more files to edit. Quit anyway?"
+msgstr[0] "Encore %d fichier à éditer. Quitter tout de même ?"
+msgstr[1] "Encore %d fichiers à éditer. Quitter tout de même ?"
+
+#, c-format
+msgid "E173: %ld more file to edit"
+msgid_plural "E173: %ld more files to edit"
+msgstr[0] "E173: encore %ld fichier à éditer"
+msgstr[1] "E173: encore %ld fichiers à éditer"
+
+msgid "E174: Command already exists: add ! to replace it"
+msgstr "E174: La commande existe déjà : ajoutez ! pour la redéfinir"
+
+msgid ""
+"\n"
+" Name Args Address Complete Definition"
+msgstr ""
+"\n"
+" Nom Args Adresse Complet. Définition"
+
+msgid "No user-defined commands found"
+msgstr "Aucune commande définie par l'utilisateur trouvée"
+
+msgid "E175: No attribute specified"
+msgstr "E175: Pas d'attribut spécifié"
+
+msgid "E176: Invalid number of arguments"
+msgstr "E176: Nombre d'arguments invalide"
+
+msgid "E177: Count cannot be specified twice"
+msgstr "E177: Le quantificateur ne peut être spécifié deux fois"
+
+msgid "E178: Invalid default value for count"
+msgstr "E178: La valeur par défaut du quantificateur est invalide"
+
+msgid "E179: argument required for -complete"
+msgstr "E179: argument requis avec -complete"
+
+msgid "E179: argument required for -addr"
+msgstr "E179: argument requis avec -addr"
+
+#, c-format
+msgid "E181: Invalid attribute: %s"
+msgstr "E181: Attribut invalide : %s"
+
+msgid "E182: Invalid command name"
+msgstr "E182: Nom de commande invalide"
+
+msgid "E183: User defined commands must start with an uppercase letter"
+msgstr "E183: Les commandes utilisateur doivent commencer par une majuscule"
+
+msgid "E841: Reserved name, cannot be used for user defined command"
+msgstr ""
+"E841: Nom réservé, ne peux pas être utilisé pour une commande utilisateur"
+
+#, c-format
+msgid "E184: No such user-defined command: %s"
+msgstr "E184: Aucune commande %s définie par l'utilisateur"
+
+#, c-format
+msgid "E180: Invalid address type value: %s"
+msgstr "E180: Valeur de type d'adresse invalide : %s"
+
+#, c-format
+msgid "E180: Invalid complete value: %s"
+msgstr "E180: Valeur invalide pour \"-complete=\" : %s"
+
+msgid "E468: Completion argument only allowed for custom completion"
+msgstr "E468: Seul le complètement personnalisé accepte un argument"
+
+msgid "E467: Custom completion requires a function argument"
+msgstr "E467: Le complètement personnalisé nécessite une fonction en argument"
+
+msgid "unknown"
+msgstr "inconnu"
+
+#, c-format
+msgid "E185: Cannot find color scheme '%s'"
+msgstr "E185: Impossible de trouver le jeu de couleurs '%s'"
+
+msgid "Greetings, Vim user!"
+msgstr "Bienvenue, utilisateur de Vim !"
+
+msgid "E784: Cannot close last tab page"
+msgstr "E784: Impossible de fermer le dernier onglet"
+
+msgid "Already only one tab page"
+msgstr "Il ne reste déjà plus qu'un seul onglet"
+
+msgid "Edit File in new tab page"
+msgstr "Ouvrir un fichier dans un nouvel onglet"
+
+msgid "Edit File in new window"
+msgstr "Ouvrir un fichier dans une nouvelle fenêtre - Vim"
+
+#, c-format
+msgid "Tab page %d"
+msgstr "Onglet %d"
+
+msgid "No swap file"
+msgstr "Pas de fichier d'échange"
+
+msgid "Append File"
+msgstr "Ajouter fichier"
+
+msgid "E747: Cannot change directory, buffer is modified (add ! to override)"
+msgstr ""
+"E747: Tampon modifié : impossible de changer de répertoire (ajoutez ! pour "
+"passer outre)"
+
+msgid "E186: No previous directory"
+msgstr "E186: Pas de répertoire précédent"
+
+msgid "E187: Unknown"
+msgstr "E187: Inconnu"
+
+msgid "E465: :winsize requires two number arguments"
+msgstr "E465: :winsize nécessite deux arguments numériques"
+
+#, c-format
+msgid "Window position: X %d, Y %d"
+msgstr "Position de la fenêtre : X %d, Y %d"
+
+# DB : Suggestion, sans doute perfectible.
+msgid "E188: Obtaining window position not implemented for this platform"
+msgstr ""
+"E188: Récupérer la position de la fenêtre non implémenté dans cette version"
+
+msgid "E466: :winpos requires two number arguments"
+msgstr "E466: :winpos nécessite deux arguments numériques"
+
+msgid "E930: Cannot use :redir inside execute()"
+msgstr "E930: Impossible d'utiliser :redir dans execute()"
+
+msgid "Save Redirection"
+msgstr "Enregistrer la redirection"
+
+msgid "Save View"
+msgstr "Enregistrer la vue - Vim"
+
+msgid "Save Session"
+msgstr "Enregistrer la session - Vim"
+
+msgid "Save Setup"
+msgstr "Enregistrer les réglages - Vim"
+
+#, c-format
+msgid "E739: Cannot create directory: %s"
+msgstr "E739: Impossible de créer le répertoire \"%s\""
+
+#, c-format
+msgid "E189: \"%s\" exists (add ! to override)"
+msgstr "E189: \"%s\" existe (ajoutez ! pour passer outre)"
+
+#, c-format
+msgid "E190: Cannot open \"%s\" for writing"
+msgstr "E190: Impossible d'ouvrir \"%s\" pour y écrire"
+
+msgid "E191: Argument must be a letter or forward/backward quote"
+msgstr "E191: L'argument doit être une lettre ou une (contre-)apostrophe"
+
+msgid "E192: Recursive use of :normal too deep"
+msgstr "E192: Appel récursif de :normal trop important"
+
+msgid "E809: #< is not available without the +eval feature"
+msgstr "E809: #< n'est pas disponible sans la fonctionnalité +eval"
+
+msgid "E194: No alternate file name to substitute for '#'"
+msgstr "E194: Aucun nom de fichier alternatif à substituer à '#'"
+
+msgid "E495: no autocommand file name to substitute for \"<afile>\""
+msgstr "E495: Aucun nom de ficher d'autocommande à substituer à \"<afile>\""
+
+msgid "E496: no autocommand buffer number to substitute for \"<abuf>\""
+msgstr "E496: Aucun numéro de tampon d'autocommande à substituer à \"<abuf>\""
+
+msgid "E497: no autocommand match name to substitute for \"<amatch>\""
+msgstr "E497: Aucune correspondance d'autocommande à substituer à \"<amatch>\""
+
+msgid "E498: no :source file name to substitute for \"<sfile>\""
+msgstr "E498: Aucun nom de fichier :source à substituer à \"<sfile>\""
+
+msgid "E842: no line number to use for \"<slnum>\""
+msgstr "E842: aucun numéro de ligne à utiliser pour \"<slnum>\""
+
+msgid "E961: no line number to use for \"<sflnum>\""
+msgstr "E961: aucun numéro de ligne à utiliser pour \"<sflnum>\""
+
+#, no-c-format
+msgid "E499: Empty file name for '%' or '#', only works with \":p:h\""
+msgstr "E499: Nom de fichier vide pour '%' ou '#', ne marche qu'avec \":p:h\""
+
+msgid "E500: Evaluates to an empty string"
+msgstr "E500: Évalué en une chaîne vide"
+
+msgid "E195: Cannot open viminfo file for reading"
+msgstr "E195: Impossible d'ouvrir le viminfo en lecture"
+
+# AB - Si les parenthèses posent problème, il faudra remettre les guillemets
+# ci-dessus.
+msgid "Untitled"
+msgstr "(sans titre)"
+
+msgid "E196: No digraphs in this version"
+msgstr "E196: Pas de digraphes dans cette version"
+
+msgid "E608: Cannot :throw exceptions with 'Vim' prefix"
+msgstr "E608: Impossible d'émettre des exceptions avec 'Vim' comme préfixe"
+
+#, c-format
+msgid "Exception thrown: %s"
+msgstr "Exception émise : %s"
+
+#, c-format
+msgid "Exception finished: %s"
+msgstr "Exception terminée : %s"
+
+#, c-format
+msgid "Exception discarded: %s"
+msgstr "Exception éliminée : %s"
+
+#, c-format
+msgid "%s, line %ld"
+msgstr "%s, ligne %ld"
+
+#, c-format
+msgid "Exception caught: %s"
+msgstr "Exception interceptée : %s"
+
+# DB - Le c-format est féminin, singulier ou pluriel (cf. 3 messages plus bas).
+#, c-format
+msgid "%s made pending"
+msgstr "%s mise(s) en attente"
+
+#, c-format
+msgid "%s resumed"
+msgstr "%s ré-émise(s)"
+
+#, c-format
+msgid "%s discarded"
+msgstr "%s éliminée(s)"
+
+msgid "Exception"
+msgstr "Exception"
+
+msgid "Error and interrupt"
+msgstr "Erreur et interruption"
+
+msgid "Error"
+msgstr "Erreur"
+
+msgid "Interrupt"
+msgstr "Interruption"
+
+msgid "E579: :if nesting too deep"
+msgstr "E579: Imbrication de :if trop importante"
+
+msgid "E580: :endif without :if"
+msgstr "E580: :endif sans :if"
+
+msgid "E581: :else without :if"
+msgstr "E581: :else sans :if"
+
+msgid "E582: :elseif without :if"
+msgstr "E582: :elseif sans :if"
+
+msgid "E583: multiple :else"
+msgstr "E583: Il ne peut y avoir qu'un seul :else"
+
+msgid "E584: :elseif after :else"
+msgstr "E584: :elseif après :else"
+
+msgid "E585: :while/:for nesting too deep"
+msgstr "E585: Imbrication de :while ou :for trop importante"
+
+msgid "E586: :continue without :while or :for"
+msgstr "E586: :continue sans :while ou :for"
+
+msgid "E587: :break without :while or :for"
+msgstr "E587: :break sans :while ou :for"
+
+msgid "E732: Using :endfor with :while"
+msgstr "E732: Utilisation de :endfor avec :while"
+
+msgid "E733: Using :endwhile with :for"
+msgstr "E733: Utilisation de :endwhile avec :for"
+
+msgid "E601: :try nesting too deep"
+msgstr "E601: Imbrication de :try trop importante"
+
+msgid "E603: :catch without :try"
+msgstr "E603: :catch sans :try"
+
+msgid "E604: :catch after :finally"
+msgstr "E604: :catch après :finally"
+
+msgid "E606: :finally without :try"
+msgstr "E606: :finally sans :try"
+
+msgid "E607: multiple :finally"
+msgstr "E607: Il ne peut y avoir qu'un seul :finally"
+
+msgid "E602: :endtry without :try"
+msgstr "E602: :endtry sans :try"
+
+msgid "E193: :endfunction not inside a function"
+msgstr "E193: :endfunction en dehors d'une fonction"
+
+msgid "E788: Not allowed to edit another buffer now"
+msgstr "E788: L'édition d'un autre tampon n'est plus permise"
+
+msgid "E811: Not allowed to change buffer information now"
+msgstr ""
+"E811: Changement des informations du tampon n'est pas permise maintenant"
+
+# DB - TODO : Pas compris le message ni comment le déclencher malgré une visite
+# dans le code.
+msgid "tagname"
+msgstr "nom du marqueur"
+
+# DB - TODO : Idem précédent.
+msgid " kind file\n"
+msgstr " type de fichier\n"
+
+msgid "'history' option is zero"
+msgstr "l'option 'history' vaut zéro"
+
+# DB - Messages et les suivants : fichier .viminfo.
+# Pas de majuscule nécessaire pour les messages d'après.
+#, c-format
+msgid ""
+"\n"
+"# %s History (newest to oldest):\n"
+msgstr ""
+"\n"
+"# Historique %s (chronologie décroissante) :\n"
+
+msgid "Command Line"
+msgstr "ligne de commande"
+
+msgid "Search String"
+msgstr "chaîne de recherche"
+
+msgid "Expression"
+msgstr "expression"
+
+msgid "Input Line"
+msgstr "ligne de saisie"
+
+msgid "Debug Line"
+msgstr "Ligne de débogage"
+
+msgid "E198: cmd_pchar beyond the command length"
+msgstr "E198: cmd_pchar au-delà de la longueur de la commande"
+
+msgid "E199: Active window or buffer deleted"
+msgstr "E199: Fenêtre ou tampon actif effacé"
+
+msgid "E812: Autocommands changed buffer or buffer name"
+msgstr "E812: Des autocommandes ont changé le tampon ou le nom du tampon"
+
+msgid "Illegal file name"
+msgstr "Nom de fichier invalide"
+
+msgid "is a directory"
+msgstr "est un répertoire"
+
+msgid "is not a file"
+msgstr "n'est pas un fichier"
+
+msgid "is a device (disabled with 'opendevice' option)"
+msgstr "est un périphérique (désactivé par l'option 'opendevice')"
+
+msgid "[New File]"
+msgstr "[Nouveau fichier]"
+
+msgid "[New DIRECTORY]"
+msgstr "[Nouveau RÉPERTOIRE]"
+
+msgid "[File too big]"
+msgstr "[Fichier trop volumineux]"
+
+msgid "[Permission Denied]"
+msgstr "[Permission refusée]"
+
+msgid "E200: *ReadPre autocommands made the file unreadable"
+msgstr "E200: Les autocommandes *ReadPre ont rendu le fichier illisible"
+
+msgid "E201: *ReadPre autocommands must not change current buffer"
+msgstr ""
+"E201: Autocommandes *ReadPre ne doivent pas modifier le contenu du tampon "
+"courant"
+
+msgid "Vim: Reading from stdin...\n"
+msgstr "Vim : Lecture de stdin...\n"
+
+msgid "Reading from stdin..."
+msgstr "Lecture de stdin..."
+
+msgid "E202: Conversion made file unreadable!"
+msgstr "E202: La conversion a rendu le fichier illisible !"
+
+msgid "[fifo]"
+msgstr "[fifo]"
+
+msgid "[socket]"
+msgstr "[socket]"
+
+msgid "[character special]"
+msgstr "[caractère spécial]"
+
+msgid "[CR missing]"
+msgstr "[CR manquant]"
+
+msgid "[long lines split]"
+msgstr "[lignes longues coupées]"
+
+msgid "[NOT converted]"
+msgstr "[NON converti]"
+
+msgid "[converted]"
+msgstr "[converti]"
+
+#, c-format
+msgid "[CONVERSION ERROR in line %ld]"
+msgstr "[ERREUR DE CONVERSION à la ligne %ld]"
+
+#, c-format
+msgid "[ILLEGAL BYTE in line %ld]"
+msgstr "[OCTET INVALIDE à la ligne %ld]"
+
+msgid "[READ ERRORS]"
+msgstr "[ERREURS DE LECTURE]"
+
+msgid "Can't find temp file for conversion"
+msgstr "Impossible de générer un fichier temporaire pour la conversion"
+
+msgid "Conversion with 'charconvert' failed"
+msgstr "La conversion avec 'charconvert' a échoué"
+
+# DB : Pas de majuscule ?
+msgid "can't read output of 'charconvert'"
+msgstr "Impossible de lire la sortie de 'charconvert'"
+
+msgid "E676: No matching autocommands for acwrite buffer"
+msgstr "E676: Pas d'autocommande correspondante pour le tampon acwrite"
+
+msgid "E203: Autocommands deleted or unloaded buffer to be written"
+msgstr "E203: Des autocommandes ont effacé ou déchargé le tampon à écrire"
+
+msgid "E204: Autocommand changed number of lines in unexpected way"
+msgstr ""
+"E204: L'autocommande a modifié le nombre de lignes de manière inattendue"
+
+msgid "NetBeans disallows writes of unmodified buffers"
+msgstr "NetBeans interdit l'écriture des tampons non modifiés"
+
+msgid "Partial writes disallowed for NetBeans buffers"
+msgstr "Netbeans interdit l'écriture partielle de ses tampons"
+
+msgid "is not a file or writable device"
+msgstr "n'est pas un fichier ou un périphérique inscriptible"
+
+msgid "writing to device disabled with 'opendevice' option"
+msgstr "écriture vers un périphérique désactivé par l'option 'opendevice'"
+
+msgid "is read-only (add ! to override)"
+msgstr "est en lecture seule (ajoutez ! pour passer outre)"
+
+msgid "E506: Can't write to backup file (add ! to override)"
+msgstr "E506: Impossible d'écrire la copie de secours (! pour passer outre)"
+
+msgid "E507: Close error for backup file (add ! to override)"
+msgstr "E507: Erreur de fermeture de la copie de secours (! pour passer outre)"
+
+msgid "E508: Can't read file for backup (add ! to override)"
+msgstr ""
+"E508: Impossible de lire le fichier pour la copie de secours (ajoutez ! pour "
+"passer outre)"
+
+msgid "E509: Cannot create backup file (add ! to override)"
+msgstr ""
+"E509: Impossible de créer la copie de secours (ajoutez ! pour passer outre)"
+
+msgid "E510: Can't make backup file (add ! to override)"
+msgstr ""
+"E510: Impossible de générer la copie de secours (ajoutez ! pour passer outre)"
+
+msgid "E214: Can't find temp file for writing"
+msgstr "E214: Impossible de générer un fichier temporaire pour y écrire"
+
+msgid "E213: Cannot convert (add ! to write without conversion)"
+msgstr "E213: Impossible de convertir (ajoutez ! pour écrire sans convertir)"
+
+msgid "E166: Can't open linked file for writing"
+msgstr "E166: Impossible d'ouvrir le lien pour y écrire"
+
+msgid "E212: Can't open file for writing"
+msgstr "E212: Impossible d'ouvrir le fichier pour y écrire"
+
+msgid "E949: File changed while writing"
+msgstr "E949: Fichier modifié après écriture"
+
+msgid "E512: Close failed"
+msgstr "E512: Erreur de fermeture de fichier"
+
+msgid "E513: write error, conversion failed (make 'fenc' empty to override)"
+msgstr ""
+"E513: Erreur d'écriture, échec de conversion (videz 'fenc' pour passer outre)"
+
+#, c-format
+msgid ""
+"E513: write error, conversion failed in line %ld (make 'fenc' empty to "
+"override)"
+msgstr ""
+"E513: Erreur d'écriture, échec de conversion à la ligne %ld (videz 'fenc' "
+"pour passer outre)"
+
+msgid "E514: write error (file system full?)"
+msgstr "E514: erreur d'écriture (système de fichiers plein ?)"
+
+msgid " CONVERSION ERROR"
+msgstr " ERREUR DE CONVERSION"
+
+#, c-format
+msgid " in line %ld;"
+msgstr " à la ligne %ld"
+
+msgid "[Device]"
+msgstr "[Périph.]"
+
+msgid "[New]"
+msgstr "[Nouveau]"
+
+msgid " [a]"
+msgstr " [a]"
+
+msgid " appended"
+msgstr " ajouté(s)"
+
+msgid " [w]"
+msgstr " [e]"
+
+msgid " written"
+msgstr " écrit(s)"
+
+msgid "E205: Patchmode: can't save original file"
+msgstr "E205: Patchmode : impossible d'enregistrer le fichier original"
+
+msgid "E206: patchmode: can't touch empty original file"
+msgstr "E206: patchmode : impossible de créer le fichier original vide"
+
+msgid "E207: Can't delete backup file"
+msgstr "E207: Impossible d'effacer la copie de secours"
+
+msgid ""
+"\n"
+"WARNING: Original file may be lost or damaged\n"
+msgstr ""
+"\n"
+"ALERTE: Le fichier original est peut-être perdu ou endommagé\n"
+
+# DB - todo : un peu long...
+msgid "don't quit the editor until the file is successfully written!"
+msgstr ""
+"ne quittez pas l'éditeur tant que le fichier n'est pas correctement "
+"enregistré !"
+
+msgid "[dos]"
+msgstr "[dos]"
+
+msgid "[dos format]"
+msgstr "[format dos]"
+
+msgid "[mac]"
+msgstr "[mac]"
+
+msgid "[mac format]"
+msgstr "[format mac]"
+
+msgid "[unix]"
+msgstr "[unix]"
+
+msgid "[unix format]"
+msgstr "[format unix]"
+
+#, c-format
+msgid "%ld line, "
+msgid_plural "%ld lines, "
+msgstr[0] "%ld ligne, "
+msgstr[1] "%ld lignes, "
+
+#, c-format
+msgid "%lld character"
+msgid_plural "%lld characters"
+msgstr[0] "%lld caractère"
+msgstr[1] "%lld caractères"
+
+msgid "[noeol]"
+msgstr "[noeol]"
+
+msgid "[Incomplete last line]"
+msgstr "[Dernière ligne incomplète]"
+
+msgid "WARNING: The file has been changed since reading it!!!"
+msgstr "ALERTE : Le fichier a été modifié depuis que Vim l'a lu !"
+
+msgid "Do you really want to write to it"
+msgstr "Voulez-vous vraiment écrire dedans"
+
+#, c-format
+msgid "E208: Error writing to \"%s\""
+msgstr "E208: Erreur lors de l'écriture dans \"%s\""
+
+#, c-format
+msgid "E209: Error closing \"%s\""
+msgstr "E209: Erreur lors de la fermeture de \"%s\""
+
+#, c-format
+msgid "E210: Error reading \"%s\""
+msgstr "E210: Erreur lors de la lecture de \"%s\""
+
+msgid "E246: FileChangedShell autocommand deleted buffer"
+msgstr "E246: L'autocommande FileChangedShell a effacé le tampon"
+
+#, c-format
+msgid "E211: File \"%s\" no longer available"
+msgstr "E211: Le fichier \"%s\" n'est plus disponible"
+
+# DB - todo : Suggestion. Bof bof, à améliorer.
+#, c-format
+msgid ""
+"W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as "
+"well"
+msgstr ""
+"W12: Alerte : Le fichier \"%s\" a été modifié, ainsi que le tampon dans Vim"
+
+msgid "See \":help W12\" for more info."
+msgstr "Consultez \":help W12\" pour plus d'information."
+
+#, c-format
+msgid "W11: Warning: File \"%s\" has changed since editing started"
+msgstr "W11: Alerte : Le fichier \"%s\" a changé depuis le début de l'édition"
+
+msgid "See \":help W11\" for more info."
+msgstr "Consultez \":help W11\" pour plus d'information."
+
+#, c-format
+msgid "W16: Warning: Mode of file \"%s\" has changed since editing started"
+msgstr ""
+"W16: Alerte : Les permissions de \"%s\" ont changé depuis le début de "
+"l'édition"
+
+msgid "See \":help W16\" for more info."
+msgstr "Consultez \":help W16\" pour plus d'information."
+
+#, c-format
+msgid "W13: Warning: File \"%s\" has been created after editing started"
+msgstr "W13: Alerte : Le fichier \"%s\" a été créé après le début de l'édition"
+
+msgid "Warning"
+msgstr "Alerte"
+
+msgid ""
+"&OK\n"
+"&Load File"
+msgstr ""
+"&Ok\n"
+"&Charger le fichier"
+
+#, c-format
+msgid "E462: Could not prepare for reloading \"%s\""
+msgstr "E462: Impossible de préparer le rechargement de \"%s\""
+
+#, c-format
+msgid "E321: Could not reload \"%s\""
+msgstr "E321: Impossible de recharger \"%s\""
+
+msgid "--Deleted--"
+msgstr "--Effacé--"
+
+#, c-format
+msgid "auto-removing autocommand: %s <buffer=%d>"
+msgstr "Autocommandes marquées pour auto-suppression : %s <tampon=%d>"
+
+#, c-format
+msgid "E367: No such group: \"%s\""
+msgstr "E367: Aucun groupe \"%s\""
+
+msgid "E936: Cannot delete the current group"
+msgstr "E936: Impossible de supprimer le groupe courant"
+
+msgid "W19: Deleting augroup that is still in use"
+msgstr "W19: Effacement d'augroup toujours en usage"
+
+#, c-format
+msgid "E215: Illegal character after *: %s"
+msgstr "E215: Caractère non valide après * : %s"
+
+#, c-format
+msgid "E216: No such event: %s"
+msgstr "E216: Aucun événement %s"
+
+#, c-format
+msgid "E216: No such group or event: %s"
+msgstr "E216: Aucun événement ou groupe %s"
+
+msgid ""
+"\n"
+"--- Autocommands ---"
+msgstr ""
+"\n"
+"--- Auto-commandes ---"
+
+#, c-format
+msgid "E680: <buffer=%d>: invalid buffer number "
+msgstr "E680: <buffer=%d> : numéro de tampon invalide"
+
+msgid "E217: Can't execute autocommands for ALL events"
+msgstr ""
+"E217: Impossible d'exécuter les autocommandes pour TOUS les événements (ALL)"
+
+msgid "No matching autocommands"
+msgstr "Aucune autocommande correspondante"
+
+msgid "E218: autocommand nesting too deep"
+msgstr "E218: autocommandes trop imbriquées"
+
+#, c-format
+msgid "%s Autocommands for \"%s\""
+msgstr "Autocommandes %s pour \"%s\""
+
+#, c-format
+msgid "Executing %s"
+msgstr "Exécution de %s"
+
+#, c-format
+msgid "autocommand %s"
+msgstr "autocommande %s"
+
+msgid "E219: Missing {."
+msgstr "E219: { manquant."
+
+msgid "E220: Missing }."
+msgstr "E220: } manquant."
+
+msgid "E490: No fold found"
+msgstr "E490: Aucun repli trouvé"
+
+msgid "E350: Cannot create fold with current 'foldmethod'"
+msgstr "E350: Impossible de créer un repli avec la 'foldmethod'e actuelle"
+
+msgid "E351: Cannot delete fold with current 'foldmethod'"
+msgstr "E351: Impossible de supprimer un repli avec la 'foldmethod'e actuelle"
+
+#, c-format
+msgid "+--%3ld line folded "
+msgid_plural "+--%3ld lines folded "
+msgstr[0] "+--%3ld ligne déplacée "
+msgstr[1] "+--%3ld lignes déplacées "
+
+msgid "E222: Add to read buffer"
+msgstr "E222: Ajout au tampon de lecture"
+
+msgid "E223: recursive mapping"
+msgstr "E223: mappage récursif"
+
+#, c-format
+msgid "E224: global abbreviation already exists for %s"
+msgstr "E224: une abréviation globale existe déjà pour %s"
+
+#, c-format
+msgid "E225: global mapping already exists for %s"
+msgstr "E225: un mappage global existe déjà pour %s"
+
+#, c-format
+msgid "E226: abbreviation already exists for %s"
+msgstr "E226: une abréviation existe déjà pour %s"
+
+#, c-format
+msgid "E227: mapping already exists for %s"
+msgstr "E227: un mappage existe déjà pour %s"
+
+msgid "No abbreviation found"
+msgstr "Aucune abréviation trouvée"
+
+msgid "No mapping found"
+msgstr "Aucun mappage trouvé"
+
+msgid "E228: makemap: Illegal mode"
+msgstr "E228: makemap : mode invalide"
+
+msgid "E851: Failed to create a new process for the GUI"
+msgstr ""
+"E851: Échec lors de la création d'un nouveau processus pour l'interface "
+"graphique"
+
+msgid "E852: The child process failed to start the GUI"
+msgstr ""
+"E852: Le processus fils n'a pas réussi à démarrer l'interface graphique"
+
+msgid "E229: Cannot start the GUI"
+msgstr "E229: Impossible de démarrer l'interface graphique"
+
+#, c-format
+msgid "E230: Cannot read from \"%s\""
+msgstr "E230: Impossible de lire \"%s\""
+
+msgid "E665: Cannot start GUI, no valid font found"
+msgstr ""
+"E665: Impossible de démarrer l'IHM graphique, aucune police valide trouvée"
+
+msgid "E231: 'guifontwide' invalid"
+msgstr "E231: 'guifontwide' est invalide"
+
+msgid "E599: Value of 'imactivatekey' is invalid"
+msgstr "E599: Valeur de 'imactivatekey' invalide"
+
+#, c-format
+msgid "E254: Cannot allocate color %s"
+msgstr "E254: Impossible d'allouer la couleur %s"
+
+msgid "No match at cursor, finding next"
+msgstr "Aucune correspondance sous le curseur, recherche de la suivante"
+
+msgid "<cannot open> "
+msgstr "<impossible d'ouvrir> "
+
+#, c-format
+msgid "E616: vim_SelFile: can't get font %s"
+msgstr "E616: vim_SelFile : impossible d'obtenir la police %s"
+
+msgid "E614: vim_SelFile: can't return to current directory"
+msgstr "E614: vim_SelFile : impossible de revenir dans le répertoire courant"
+
+msgid "Pathname:"
+msgstr "Chemin :"
+
+msgid "E615: vim_SelFile: can't get current directory"
+msgstr "E615: vim_SelFile : impossible d'obtenir le répertoire courant"
+
+msgid "OK"
+msgstr "Ok"
+
+msgid "Cancel"
+msgstr "Annuler"
+
+msgid "Scrollbar Widget: Could not get geometry of thumb pixmap."
+msgstr "Widget scrollbar : Impossible d'obtenir la géométrie du pixmap 'thumb'"
+
+msgid "Vim dialog"
+msgstr "Vim"
+
+msgid "E232: Cannot create BalloonEval with both message and callback"
+msgstr "E232: Impossible de créer un BalloonEval avec message ET callback"
+
+msgid "_Cancel"
+msgstr "_Annuler"
+
+msgid "_Save"
+msgstr "_Enregistrer"
+
+msgid "_Open"
+msgstr "_Ouvrir"
+
+msgid "_OK"
+msgstr "_Ok"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"&Cancel"
+msgstr ""
+"&Oui\n"
+"&Non\n"
+"&Annuler"
+
+msgid "Yes"
+msgstr "Oui"
+
+msgid "No"
+msgstr "Non"
+
+# todo '_' is for hotkey, i guess?
+msgid "Input _Methods"
+msgstr "_Méthodes de saisie"
+
+msgid "VIM - Search and Replace..."
+msgstr "Remplacer - Vim"
+
+msgid "VIM - Search..."
+msgstr "Rechercher - Vim"
+
+msgid "Find what:"
+msgstr "Rechercher :"
+
+msgid "Replace with:"
+msgstr "Remplacer par :"
+
+msgid "Match whole word only"
+msgstr "Mots entiers seulement"
+
+msgid "Match case"
+msgstr "Respecter la casse"
+
+msgid "Direction"
+msgstr "Direction"
+
+msgid "Up"
+msgstr "Haut"
+
+msgid "Down"
+msgstr "Bas"
+
+msgid "Find Next"
+msgstr "Suivant"
+
+msgid "Replace"
+msgstr "Remplacer"
+
+msgid "Replace All"
+msgstr "Remplacer tout"
+
+msgid "_Close"
+msgstr "_Fermer"
+
+msgid "Vim: Received \"die\" request from session manager\n"
+msgstr "Vim : Une requête \"die\" a été reçue par le gestionnaire de session\n"
+
+msgid "Close tab"
+msgstr "Fermer l'onglet"
+
+msgid "New tab"
+msgstr "Nouvel onglet"
+
+# DB - todo : un peu long. Cet entrée de menu permet d'ouvrir un fichier
+# dans un nouvel onglet via le sélecteur de fichiers graphique.
+msgid "Open Tab..."
+msgstr "Ouvrir dans un onglet..."
+
+msgid "Vim: Main window unexpectedly destroyed\n"
+msgstr "Vim : Fenêtre principale détruite inopinément\n"
+
+msgid "&Filter"
+msgstr "&Filtrer"
+
+msgid "&Cancel"
+msgstr "&Annuler"
+
+msgid "Directories"
+msgstr "Répertoires"
+
+msgid "Filter"
+msgstr "Filtre"
+
+msgid "&Help"
+msgstr "&Aide"
+
+msgid "Files"
+msgstr "Fichiers"
+
+msgid "&OK"
+msgstr "&Ok"
+
+msgid "Selection"
+msgstr "Sélection"
+
+msgid "Find &Next"
+msgstr "Suiva&nt"
+
+msgid "&Replace"
+msgstr "&Remplacer"
+
+msgid "Replace &All"
+msgstr "Rempl&acer tout"
+
+msgid "&Undo"
+msgstr "Ann&uler"
+
+msgid "Open tab..."
+msgstr "Ouvrir dans un onglet..."
+
+msgid "Find string"
+msgstr "Trouver une chaîne"
+
+msgid "Find & Replace"
+msgstr "Trouver & remplacer"
+
+# DB - Traduction non indispensable puisque le code indique qu'il s'agit d'un
+# paramétrage bidon afin de sélectionner un répertoire plutôt qu'un
+# fichier.
+msgid "Not Used"
+msgstr "Non utilisé"
+
+# DB - Traduction non indispensable puisque le code indique qu'il s'agit d'un
+# paramétrage bidon afin de sélectionner un répertoire plutôt qu'un
+# fichier.
+msgid "Directory\t*.nothing\n"
+msgstr "Répertoire\t*.rien\n"
+
+#, c-format
+msgid "E671: Cannot find window title \"%s\""
+msgstr "E671: Titre de fenêtre \"%s\" introuvable"
+
+#, c-format
+msgid "E243: Argument not supported: \"-%s\"; Use the OLE version."
+msgstr "E243: Argument non supporté : \"-%s\" ; Utilisez la version OLE."
+
+msgid "E672: Unable to open window inside MDI application"
+msgstr "E672: Impossible d'ouvrir une fenêtre dans une application MDI"
+
+# DB - todo : perfectible.
+msgid "Vim E458: Cannot allocate colormap entry, some colors may be incorrect"
+msgstr ""
+"Vim E458: Erreur d'allocation de couleurs, couleurs possiblement incorrectes"
+
+# DB - todo : La VF est-elle compréhensible ?
+#, c-format
+msgid "E250: Fonts for the following charsets are missing in fontset %s:"
+msgstr ""
+"E250: Des polices manquent dans %s pour les jeux de caractères suivants :"
+
+#, c-format
+msgid "E252: Fontset name: %s"
+msgstr "E252: Nom du jeu de polices : %s"
+
+#, c-format
+msgid "Font '%s' is not fixed-width"
+msgstr "La police '%s' n'a pas une largeur fixe"
+
+#, c-format
+msgid "E253: Fontset name: %s"
+msgstr "E253: Nom du jeu de polices : %s"
+
+#, c-format
+msgid "Font0: %s"
+msgstr "Font0: %s"
+
+#, c-format
+msgid "Font1: %s"
+msgstr "Font1: %s"
+
+#, c-format
+msgid "Font%ld width is not twice that of font0"
+msgstr "La largeur de Font%ld n'est pas le double de celle de Font0"
+
+#, c-format
+msgid "Font0 width: %ld"
+msgstr "Largeur de Font0 : %ld"
+
+#, c-format
+msgid "Font1 width: %ld"
+msgstr "Largeur de Font1 : %ld"
+
+# DB - todo : Pas certain de mon coup, ici...
+msgid "Invalid font specification"
+msgstr "La spécification de la police est invalide"
+
+msgid "&Dismiss"
+msgstr "Aban&donner"
+
+# DB - todo : Pas certain de mon coup, ici...
+msgid "no specific match"
+msgstr "aucune correspondance particulière"
+
+msgid "Vim - Font Selector"
+msgstr "Choisir une police - Vim"
+
+msgid "Name:"
+msgstr "Nom :"
+
+msgid "Show size in Points"
+msgstr "Afficher la taille en Points"
+
+msgid "Encoding:"
+msgstr "Encodage :"
+
+msgid "Font:"
+msgstr "Police :"
+
+msgid "Style:"
+msgstr "Style :"
+
+msgid "Size:"
+msgstr "Taille :"
+
+msgid "E256: Hangul automata ERROR"
+msgstr "E256: ERREUR dans l'automate Hangul"
+
+msgid "E550: Missing colon"
+msgstr "E550: ':' manquant"
+
+# DB - Il s'agit ici d'un problème lors du parsing d'une option dont le contenu
+# est une liste d'éléments séparés par des virgules.
+msgid "E551: Illegal component"
+msgstr "E551: élément invalide"
+
+msgid "E552: digit expected"
+msgstr "E552: chiffre attendu"
+
+#, c-format
+msgid "Page %d"
+msgstr "Page %d"
+
+msgid "No text to be printed"
+msgstr "Aucun texte à imprimer"
+
+#, c-format
+msgid "Printing page %d (%d%%)"
+msgstr "Impression de la page %d (%d%%)"
+
+#, c-format
+msgid " Copy %d of %d"
+msgstr " Copie %d sur %d"
+
+#, c-format
+msgid "Printed: %s"
+msgstr "Imprimé : %s"
+
+msgid "Printing aborted"
+msgstr "Impression interrompue"
+
+msgid "E455: Error writing to PostScript output file"
+msgstr "E455: Erreur lors de l'écriture du fichier PostScript"
+
+#, c-format
+msgid "E624: Can't open file \"%s\""
+msgstr "E624: Impossible d'ouvrir le fichier \"%s\""
+
+#, c-format
+msgid "E457: Can't read PostScript resource file \"%s\""
+msgstr "E457: Impossible de lire le fichier de ressource PostScript \"%s\""
+
+#, c-format
+msgid "E618: file \"%s\" is not a PostScript resource file"
+msgstr "E618: \"%s\" n'est pas un fichier de ressource PostScript"
+
+#, c-format
+msgid "E619: file \"%s\" is not a supported PostScript resource file"
+msgstr "E619: \"%s\" n'est pas un fichier de ressource PostScript supporté"
+
+#, c-format
+msgid "E621: \"%s\" resource file has wrong version"
+msgstr "E621: La version du fichier de ressource \"%s\" est erronée"
+
+msgid "E673: Incompatible multi-byte encoding and character set."
+msgstr "E673: Jeu de caractères et encodage multi-octets incompatibles"
+
+msgid "E674: printmbcharset cannot be empty with multi-byte encoding."
+msgstr ""
+"E674: 'printmbcharset' ne peut pas être vide avec un encodage multi-octets"
+
+msgid "E675: No default font specified for multi-byte printing."
+msgstr "E675: Aucune police par défaut pour l'impression multi-octets"
+
+msgid "E324: Can't open PostScript output file"
+msgstr "E324: Impossible d'ouvrir le fichier PostScript de sortie"
+
+#, c-format
+msgid "E456: Can't open file \"%s\""
+msgstr "E456: Impossible d'ouvrir le fichier \"%s\""
+
+msgid "E456: Can't find PostScript resource file \"prolog.ps\""
+msgstr "E456: Le fichier de ressource PostScript \"prolog.ps\" est introuvable"
+
+msgid "E456: Can't find PostScript resource file \"cidfont.ps\""
+msgstr ""
+"E456: Le fichier de ressource PostScript \"cidfont.ps\" est introuvable"
+
+#, c-format
+msgid "E456: Can't find PostScript resource file \"%s.ps\""
+msgstr "E456: Le fichier de ressource PostScript \"%s.ps\" est introuvable"
+
+#, c-format
+msgid "E620: Unable to convert to print encoding \"%s\""
+msgstr "E620: La conversion pour imprimer dans l'encodage \"%s\" a échoué"
+
+msgid "Sending to printer..."
+msgstr "Envoi à l'imprimante..."
+
+msgid "E365: Failed to print PostScript file"
+msgstr "E365: L'impression du fichier PostScript a échoué"
+
+msgid "Print job sent."
+msgstr "Tâche d'impression envoyée."
+
+msgid "Add a new database"
+msgstr "Ajouter une base de données"
+
+msgid "Query for a pattern"
+msgstr "Rechercher un motif"
+
+msgid "Show this message"
+msgstr "Afficher ce message"
+
+msgid "Kill a connection"
+msgstr "Fermer une connexion"
+
+msgid "Reinit all connections"
+msgstr "Réinitialiser toutes les connexions"
+
+msgid "Show connections"
+msgstr "Afficher les connexions"
+
+#, c-format
+msgid "E560: Usage: cs[cope] %s"
+msgstr "E560: Utilisation : cs[cope] %s"
+
+msgid "This cscope command does not support splitting the window.\n"
+msgstr "Cette commande cscope ne supporte pas le partage de la fenêtre.\n"
+
+msgid "E562: Usage: cstag <ident>"
+msgstr "E562: Utilisation : cstag <ident>"
+
+msgid "E257: cstag: tag not found"
+msgstr "E257: cstag : marqueur introuvable"
+
+#, c-format
+msgid "E563: stat(%s) error: %d"
+msgstr "E563: Erreur stat(%s) : %d"
+
+msgid "E563: stat error"
+msgstr "E563: Erreur stat"
+
+#, c-format
+msgid "E564: %s is not a directory or a valid cscope database"
+msgstr "E564: %s n'est pas un répertoire ou une base de données cscope valide"
+
+#, c-format
+msgid "Added cscope database %s"
+msgstr "Base de données cscope %s ajoutée"
+
+#, c-format
+msgid "E262: error reading cscope connection %ld"
+msgstr "E262: erreur lors de la lecture de la connexion cscope %ld"
+
+msgid "E561: unknown cscope search type"
+msgstr "E561: type de recherche cscope inconnu"
+
+msgid "E566: Could not create cscope pipes"
+msgstr "E566: Impossible de créer les tuyaux (pipes) cscope"
+
+msgid "E622: Could not fork for cscope"
+msgstr "E622: Impossible de forker pour cscope"
+
+msgid "cs_create_connection setpgid failed"
+msgstr "cs_create_connection setpgid a échoué"
+
+msgid "cs_create_connection exec failed"
+msgstr "exec de cs_create_connection a échoué"
+
+msgid "cs_create_connection: fdopen for to_fp failed"
+msgstr "cs_create_connection : fdopen pour to_fp a échoué"
+
+msgid "cs_create_connection: fdopen for fr_fp failed"
+msgstr "cs_create_connection : fdopen pour fr_fp a échoué"
+
+msgid "E623: Could not spawn cscope process"
+msgstr "E623: Impossible d'engendrer le processus cscope"
+
+msgid "E567: no cscope connections"
+msgstr "E567: Aucune connexion cscope"
+
+#, c-format
+msgid "E469: invalid cscopequickfix flag %c for %c"
+msgstr "E469: Drapeau cscopequickfix %c invalide pour %c"
+
+# DB - todo
+#, c-format
+msgid "E259: no matches found for cscope query %s of %s"
+msgstr "E259: aucune correspondance trouvée pour la requête cscope %s de %s"
+
+msgid "cscope commands:\n"
+msgstr "commandes cscope :\n"
+
+#, c-format
+msgid "%-5s: %s%*s (Usage: %s)"
+msgstr "%-5s: %s%*s (Utilisation : %s)"
+
+msgid ""
+"\n"
+" a: Find assignments to this symbol\n"
+" c: Find functions calling this function\n"
+" d: Find functions called by this function\n"
+" e: Find this egrep pattern\n"
+" f: Find this file\n"
+" g: Find this definition\n"
+" i: Find files #including this file\n"
+" s: Find this C symbol\n"
+" t: Find this text string\n"
+msgstr ""
+"\n"
+" a: Trouver les affectations à ce symbole\n"
+" c: Trouver les fonctions appelant cette fonction\n"
+" d: Trouver les fonctions appelées par cette fonction\n"
+" e: Trouver ce motif egrep\n"
+" f: Trouver ce fichier\n"
+" g: Trouver cette définition\n"
+" i: Trouver les fichiers qui #incluent ce fichier\n"
+" s: Trouver ce symbole C\n"
+" t: Trouver cette chaîne\n"
+
+#, c-format
+msgid "E625: cannot open cscope database: %s"
+msgstr "E625: impossible d'ouvrir la base de données cscope %s"
+
+msgid "E626: cannot get cscope database information"
+msgstr ""
+"E626: impossible d'obtenir des informations sur la base de données cscope"
+
+msgid "E568: duplicate cscope database not added"
+msgstr "E568: base de données cscope redondante non ajoutée"
+
+#, c-format
+msgid "E261: cscope connection %s not found"
+msgstr "E261: Connexion cscope %s introuvable"
+
+#, c-format
+msgid "cscope connection %s closed"
+msgstr "connexion cscope %s fermée"
+
+msgid "E570: fatal error in cs_manage_matches"
+msgstr "E570: erreur fatale dans cs_manage_matches"
+
+#, c-format
+msgid "Cscope tag: %s"
+msgstr "Marqueur cscope : %s"
+
+msgid ""
+"\n"
+" # line"
+msgstr ""
+"\n"
+" # ligne"
+
+# DB - todo : Faut-il respecter l'alignement ici ?
+msgid "filename / context / line\n"
+msgstr "nom / contexte/ ligne\n"
+
+#, c-format
+msgid "E609: Cscope error: %s"
+msgstr "E609: Erreur cscope : %s"
+
+msgid "All cscope databases reset"
+msgstr "Toutes les bases de données cscope ont été réinitialisées"
+
+msgid "no cscope connections\n"
+msgstr "aucune connexion cscope\n"
+
+msgid " # pid database name prepend path\n"
+msgstr " # pid nom de la base de données chemin\n"
+
+msgid "Lua library cannot be loaded."
+msgstr "La bibliothèque Lua n'a pas pu être chargée."
+
+msgid "cannot save undo information"
+msgstr "impossible d'enregistrer les informations d'annulation"
+
+msgid ""
+"E815: Sorry, this command is disabled, the MzScheme libraries could not be "
+"loaded."
+msgstr ""
+"E815: Désolé, cette commande est désactivée : les bibliothèques MzScheme "
+"n'ont pas pu être chargées."
+
+msgid ""
+"E895: Sorry, this command is disabled, the MzScheme's racket/base module "
+"could not be loaded."
+msgstr ""
+"E895: Désolé, cette commande est désactivée : le module MzScheme racket/base "
+"ne peut pas être chargé."
+
+msgid "invalid expression"
+msgstr "expression invalide"
+
+msgid "expressions disabled at compile time"
+msgstr "expressions désactivées lors de la compilation"
+
+msgid "hidden option"
+msgstr "option cachée"
+
+msgid "unknown option"
+msgstr "option inconnue"
+
+msgid "window index is out of range"
+msgstr "numéro de fenêtre hors limites"
+
+msgid "couldn't open buffer"
+msgstr "impossible d'ouvrir le tampon"
+
+msgid "cannot delete line"
+msgstr "impossible d'effacer la ligne"
+
+msgid "cannot replace line"
+msgstr "impossible de remplacer la ligne"
+
+msgid "cannot insert line"
+msgstr "impossible d'insérer la ligne"
+
+msgid "string cannot contain newlines"
+msgstr "une chaîne ne peut pas contenir de saut-de-ligne"
+
+msgid "error converting Scheme values to Vim"
+msgstr "erreur lors de la conversion d'une valeur de Scheme à Vim"
+
+msgid "Vim error: ~a"
+msgstr "Erreur Vim : ~a"
+
+msgid "Vim error"
+msgstr "Erreur Vim"
+
+msgid "buffer is invalid"
+msgstr "tampon invalide"
+
+msgid "window is invalid"
+msgstr "fenêtre invalide"
+
+msgid "linenr out of range"
+msgstr "numéro de ligne hors limites"
+
+msgid "not allowed in the Vim sandbox"
+msgstr "non autorisé dans le bac à sable"
+
+msgid "E836: This Vim cannot execute :python after using :py3"
+msgstr "E836: Vim ne peut pas exécuter :python après avoir utilisé :py3"
+
+msgid ""
+"E263: Sorry, this command is disabled, the Python library could not be "
+"loaded."
+msgstr ""
+"E263: Désolé, commande désactivée : la bibliothèque Python n'a pas pu être "
+"chargée."
+
+msgid ""
+"E887: Sorry, this command is disabled, the Python's site module could not be "
+"loaded."
+msgstr ""
+"E887: Désolé, commande désactivée : la bibliothèque Python n'a pas pu être "
+"chargée."
+
+msgid "E659: Cannot invoke Python recursively"
+msgstr "E659: Impossible d'invoquer Python récursivement"
+
+msgid "E837: This Vim cannot execute :py3 after using :python"
+msgstr "E837: Vim ne peut pas exécuter :py3 après avoir utilisé :python"
+
+msgid "E265: $_ must be an instance of String"
+msgstr "E265: $_ doit être une instance de chaîne (String)"
+
+msgid ""
+"E266: Sorry, this command is disabled, the Ruby library could not be loaded."
+msgstr ""
+"E266: Désolé, commande désactivée : la bibliothèque Ruby n'a pas pu être "
+"chargée."
+
+msgid "E267: unexpected return"
+msgstr "E267: « return » inattendu"
+
+msgid "E268: unexpected next"
+msgstr "E268: « next » inattendu"
+
+msgid "E269: unexpected break"
+msgstr "E269: « break » inattendu"
+
+msgid "E270: unexpected redo"
+msgstr "E270: « redo » inattendu"
+
+msgid "E271: retry outside of rescue clause"
+msgstr "E271: « retry » hors d'une clause « rescue »"
+
+msgid "E272: unhandled exception"
+msgstr "E272: Exception non prise en charge"
+
+# DB - todo
+#, c-format
+msgid "E273: unknown longjmp status %d"
+msgstr "E273: contexte de longjmp inconnu : %d"
+
+msgid "invalid buffer number"
+msgstr "numéro de tampon invalide"
+
+msgid "not implemented yet"
+msgstr "pas encore implémenté"
+
+# DB - TODO : le contexte est celui d'une annulation.
+msgid "cannot set line(s)"
+msgstr "Impossible de remettre la/les ligne(s)"
+
+msgid "invalid mark name"
+msgstr "nom de marque invalide"
+
+msgid "mark not set"
+msgstr "marque non positionnée"
+
+#, c-format
+msgid "row %d column %d"
+msgstr "ligne %d colonne %d"
+
+msgid "cannot insert/append line"
+msgstr "Impossible d'insérer/ajouter de lignes"
+
+msgid "line number out of range"
+msgstr "numéro de ligne hors limites"
+
+msgid "unknown flag: "
+msgstr "drapeau inconnu : "
+
+msgid "unknown vimOption"
+msgstr "vimOption inconnue"
+
+msgid "keyboard interrupt"
+msgstr "interruption clavier"
+
+msgid "vim error"
+msgstr "erreur Vim"
+
+msgid "cannot create buffer/window command: object is being deleted"
+msgstr ""
+"Impossible de créer commande de tampon/fenêtre : objet en cours d'effacement"
+
+msgid ""
+"cannot register callback command: buffer/window is already being deleted"
+msgstr ""
+"Impossible d'inscrire la commande de rappel : tampon/fenêtre en effacement"
+
+msgid ""
+"E280: TCL FATAL ERROR: reflist corrupt!? Please report this to vim-dev@vim."
+"org"
+msgstr ""
+"E280: ERREUR FATALE TCL: reflist corrompue ?! Contactez vim-dev@vim.org, SVP."
+
+msgid "cannot register callback command: buffer/window reference not found"
+msgstr ""
+"Impossible d'inscrire la commande de rappel : réf. tampon/fenêtre introuvable"
+
+msgid ""
+"E571: Sorry, this command is disabled: the Tcl library could not be loaded."
+msgstr ""
+"E571: Désolé, commande désactivée: la bibliothèque Tcl n'a pas pu être "
+"chargée."
+
+#, c-format
+msgid "E572: exit code %d"
+msgstr "E572: code de sortie %d"
+
+msgid "cannot get line"
+msgstr "Impossible d'obtenir la ligne"
+
+msgid "Unable to register a command server name"
+msgstr "Impossible d'inscrire un nom de serveur de commande"
+
+msgid "E248: Failed to send command to the destination program"
+msgstr "E248: Échec de l'envoi de la commande au programme cible"
+
+#, c-format
+msgid "E573: Invalid server id used: %s"
+msgstr "E573: Id utilisé pour le serveur invalide : %s"
+
+msgid "E251: VIM instance registry property is badly formed. Deleted!"
+msgstr "E251: Entrée registre de l'instance de Vim mal formatée. Suppression !"
+
+#, c-format
+msgid "E938: Duplicate key in JSON: \"%s\""
+msgstr "E938: Clé dupliquée dans le document JSON : \"%s\""
+
+#, c-format
+msgid "E696: Missing comma in List: %s"
+msgstr "E696: Il manque une virgule dans la Liste %s"
+
+#, c-format
+msgid "E697: Missing end of List ']': %s"
+msgstr "E697: Il manque ']' à la fin de la Liste %s"
+
+msgid "Unknown option argument"
+msgstr "Option inconnue"
+
+msgid "Too many edit arguments"
+msgstr "Trop d'arguments d'édition"
+
+msgid "Argument missing after"
+msgstr "Argument manquant après"
+
+msgid "Garbage after option argument"
+msgstr "arguments en trop après l'option"
+
+msgid "Too many \"+command\", \"-c command\" or \"--cmd command\" arguments"
+msgstr "Trop d'arguments \"+command\", \"-c command\" ou \"--cmd command\""
+
+msgid "Invalid argument for"
+msgstr "Argument invalide pour"
+
+#, c-format
+msgid "%d files to edit\n"
+msgstr "%d fichiers à éditer\n"
+
+msgid "netbeans is not supported with this GUI\n"
+msgstr "netbeans n'est pas supporté avec cette interface graphique\n"
+
+msgid "'-nb' cannot be used: not enabled at compile time\n"
+msgstr "'-nb' ne peut pas être utilisé : désactivé à la compilation\n"
+
+msgid "This Vim was not compiled with the diff feature."
+msgstr "Ce Vim n'a pas été compilé avec la fonctionnalité diff"
+
+msgid "Attempt to open script file again: \""
+msgstr "Nouvelle tentative pour ouvrir le script : \""
+
+msgid "Cannot open for reading: \""
+msgstr "Impossible d'ouvrir en lecture : \""
+
+msgid "Cannot open for script output: \""
+msgstr "Impossible d'ouvrir pour la sortie script : \""
+
+msgid "Vim: Error: Failure to start gvim from NetBeans\n"
+msgstr "Vim : Erreur : Impossible de démarrer gvim depuis NetBeans\n"
+
+msgid "Vim: Error: This version of Vim does not run in a Cygwin terminal\n"
+msgstr ""
+"Vim : Erreur : Cette version de Vim ne fonctionne pas dans un terminal "
+"Cygwin\n"
+
+msgid "Vim: Warning: Output is not to a terminal\n"
+msgstr "Vim : Alerte : La sortie ne s'effectue pas sur un terminal\n"
+
+msgid "Vim: Warning: Input is not from a terminal\n"
+msgstr "Vim : Alerte : L'entrée ne se fait pas sur un terminal\n"
+
+msgid "pre-vimrc command line"
+msgstr "ligne de commande pre-vimrc"
+
+#, c-format
+msgid "E282: Cannot read from \"%s\""
+msgstr "E282: Impossible de lire \"%s\""
+
+msgid ""
+"\n"
+"More info with: \"vim -h\"\n"
+msgstr ""
+"\n"
+"Plus d'info avec : \"vim -h\"\n"
+
+msgid "[file ..] edit specified file(s)"
+msgstr "[fichier ...] ouvrir le ou les fichiers spécifiés"
+
+msgid "- read text from stdin"
+msgstr "- lire le texte à partir de stdin"
+
+msgid "-t tag edit file where tag is defined"
+msgstr "-t marqueur ouvrir le fichier qui contient le marqueur"
+
+msgid "-q [errorfile] edit file with first error"
+msgstr "-q [fichErr] ouvrir à l'endroit de la première erreur"
+
+msgid ""
+"\n"
+"\n"
+"Usage:"
+msgstr ""
+"\n"
+"\n"
+"Utilisation :"
+
+msgid " vim [arguments] "
+msgstr " vim [args] "
+
+msgid ""
+"\n"
+" or:"
+msgstr ""
+"\n"
+" ou :"
+
+# DB - todo (VMS uniquement).
+msgid ""
+"\n"
+"Where case is ignored prepend / to make flag upper case"
+msgstr ""
+"\n"
+"pour lesquels la casse est indifférente (/ pour que le drapeau soit "
+"majuscule)"
+
+msgid ""
+"\n"
+"\n"
+"Arguments:\n"
+msgstr ""
+"\n"
+"\n"
+"Arguments :\n"
+
+msgid "--\t\t\tOnly file names after this"
+msgstr "--\t\tSeuls des noms de fichier sont spécifiés après ceci"
+
+msgid "--literal\t\tDon't expand wildcards"
+msgstr "--literal\tNe pas développer les métacaractères"
+
+msgid "-register\t\tRegister this gvim for OLE"
+msgstr "-register\tInscrire ce gvim pour OLE"
+
+msgid "-unregister\t\tUnregister gvim for OLE"
+msgstr "-unregister\tDésinscrire gvim de OLE"
+
+msgid "-g\t\t\tRun using GUI (like \"gvim\")"
+msgstr "-g\t\tLancer l'interface graphique (comme \"gvim\")"
+
+msgid "-f or --nofork\tForeground: Don't fork when starting GUI"
+msgstr ""
+"-f, --nofork\tPremier-plan : ne pas détacher l'interface graphique du "
+"terminal"
+
+msgid "-v\t\t\tVi mode (like \"vi\")"
+msgstr "-v\t\tMode Vi (comme \"vi\")"
+
+msgid "-e\t\t\tEx mode (like \"ex\")"
+msgstr "-e\t\tMode Ex (comme \"ex\")"
+
+msgid "-E\t\t\tImproved Ex mode"
+msgstr "-E\t\t\tMode Ex amélioré"
+
+msgid "-s\t\t\tSilent (batch) mode (only for \"ex\")"
+msgstr "-s\t\tMode silencieux (batch) (seulement pour \"ex\")"
+
+msgid "-d\t\t\tDiff mode (like \"vimdiff\")"
+msgstr "-d\t\tMode diff (comme \"vimdiff\")"
+
+msgid "-y\t\t\tEasy mode (like \"evim\", modeless)"
+msgstr "-y\t\tMode facile (comme \"evim\", vim sans modes)"
+
+msgid "-R\t\t\tReadonly mode (like \"view\")"
+msgstr "-R\t\tMode lecture seule (comme \"view\")"
+
+msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
+msgstr "-Z\t\tMode restreint (comme \"rvim\")"
+
+msgid "-m\t\t\tModifications (writing files) not allowed"
+msgstr "-m\t\tInterdire l'enregistrement des fichiers"
+
+msgid "-M\t\t\tModifications in text not allowed"
+msgstr "-M\t\tInterdire toute modification de texte"
+
+msgid "-b\t\t\tBinary mode"
+msgstr "-b\t\tMode binaire"
+
+msgid "-l\t\t\tLisp mode"
+msgstr "-l\t\tMode lisp"
+
+msgid "-C\t\t\tCompatible with Vi: 'compatible'"
+msgstr "-C\t\tCompatible avec Vi : 'compatible'"
+
+msgid "-N\t\t\tNot fully Vi compatible: 'nocompatible'"
+msgstr "-N\t\tPas totalement compatible avec Vi : 'nocompatible'"
+
+msgid "-V[N][fname]\t\tBe verbose [level N] [log messages to fname]"
+msgstr "-V[N][<fichier>]\tMode verbeux [niveau N] [dans <fichier>]"
+
+msgid "-D\t\t\tDebugging mode"
+msgstr "-D\t\tMode débogage"
+
+msgid "-n\t\t\tNo swap file, use memory only"
+msgstr "-n\t\tNe pas utiliser de fichier d'échange, seulement la mémoire"
+
+msgid "-r\t\t\tList swap files and exit"
+msgstr "-r\t\tLister les fichiers d'échange et quitter"
+
+msgid "-r (with file name)\tRecover crashed session"
+msgstr "-r <fichier>\tRécupérer une session plantée"
+
+msgid "-L\t\t\tSame as -r"
+msgstr "-L\t\tComme -r"
+
+msgid "-f\t\t\tDon't use newcli to open window"
+msgstr "-f\t\tNe pas utiliser newcli pour l'ouverture des fenêtres"
+
+msgid "-dev <device>\t\tUse <device> for I/O"
+msgstr "-dev <périph>\tUtiliser <périphérique> pour les E/S"
+
+msgid "-A\t\t\tStart in Arabic mode"
+msgstr "-A\t\tDémarrer en mode arabe"
+
+msgid "-H\t\t\tStart in Hebrew mode"
+msgstr "-H\t\tDémarrer en mode hébreu"
+
+msgid "-F\t\t\tStart in Farsi mode"
+msgstr "-F\t\tDémarrer en mode farsi"
+
+msgid "-T <terminal>\tSet terminal type to <terminal>"
+msgstr "-T <term>\tRégler le type du terminal sur <terminal>"
+
+msgid "--not-a-term\t\tSkip warning for input/output not being a terminal"
+msgstr ""
+"--no-a-term\t\tAucun avertissement si l'entrée/sortie n'est pas un terminal"
+
+msgid "--ttyfail\t\tExit if input or output is not a terminal"
+msgstr "--ttyfail\t\tQuitte si l'entrée ou la sortie ne sont pas un terminal"
+
+msgid "-u <vimrc>\t\tUse <vimrc> instead of any .vimrc"
+msgstr "-u <vimrc>\tUtiliser <vimrc> au lieu du vimrc habituel"
+
+msgid "-U <gvimrc>\t\tUse <gvimrc> instead of any .gvimrc"
+msgstr "-U <gvimrc>\tUtiliser <gvimrc> au lieu du gvimrc habituel"
+
+msgid "--noplugin\t\tDon't load plugin scripts"
+msgstr "--noplugin\tNe charger aucun greffon"
+
+msgid "-p[N]\t\tOpen N tab pages (default: one for each file)"
+msgstr "-p[N]\tOuvrir N onglets (défaut : un pour chaque fichier)"
+
+msgid "-o[N]\t\tOpen N windows (default: one for each file)"
+msgstr "-o[N]\tOuvrir N fenêtres (défaut : une pour chaque fichier)"
+
+msgid "-O[N]\t\tLike -o but split vertically"
+msgstr "-O[N]\tComme -o, mais partager verticalement"
+
+msgid "+\t\t\tStart at end of file"
+msgstr "+\t\tOuvrir à la fin du fichier"
+
+msgid "+<lnum>\t\tStart at line <lnum>"
+msgstr "+<numL>\tOuvrir le fichier à la ligne <numL>"
+
+msgid "--cmd <command>\tExecute <command> before loading any vimrc file"
+msgstr "--cmd <cmde>\tExécuter <commande> avant de charger les fichiers vimrc"
+
+msgid "-c <command>\t\tExecute <command> after loading the first file"
+msgstr "-c <cmde>\tExécuter <commande> une fois le 1er fichier chargé"
+
+msgid "-S <session>\t\tSource file <session> after loading the first file"
+msgstr ""
+"-S <session>\tSourcer le fichier <session> une fois le 1er fichier chargé"
+
+msgid "-s <scriptin>\tRead Normal mode commands from file <scriptin>"
+msgstr "-s <src>\tLire les commandes du mode Normal à partir du fichier <src>"
+
+msgid "-w <scriptout>\tAppend all typed commands to file <scriptout>"
+msgstr "-w <dest>\tAjouter toutes les commandes tapées dans le fichier <dest>"
+
+msgid "-W <scriptout>\tWrite all typed commands to file <scriptout>"
+msgstr "-W <dest>\tÉcrire toutes les commandes tapées dans le fichier <dest>"
+
+msgid "-x\t\t\tEdit encrypted files"
+msgstr "-x\t\t\tÉditer des fichiers chiffrés"
+
+msgid "-display <display>\tConnect vim to this particular X-server"
+msgstr "-display <display>\tConnecter Vim au serveur X spécifié"
+
+msgid "-X\t\t\tDo not connect to X server"
+msgstr "-X\t\t\tNe pas se connecter à un serveur X"
+
+msgid "--remote <files>\tEdit <files> in a Vim server if possible"
+msgstr "--remote <fich>\tÉditer les <fichiers> dans un serveur Vim si possible"
+
+msgid "--remote-silent <files> Same, don't complain if there is no server"
+msgstr ""
+"--remote-silent ...\tPareil, mais pas d'erreur s'il n'y a aucun serveur"
+
+msgid ""
+"--remote-wait <files> As --remote but wait for files to have been edited"
+msgstr ""
+"--remote-wait <fich>\tComme --remote mais ne quitter qu'à la fin de l'édition"
+
+msgid ""
+"--remote-wait-silent <files> Same, don't complain if there is no server"
+msgstr ""
+"--remote-wait-silent\tPareil, mais pas d'erreur s'il n'y a aucun serveur"
+
+msgid ""
+"--remote-tab[-wait][-silent] <files> As --remote but use tab page per file"
+msgstr ""
+"--remote-tab[-wait][-silent] <fich>\tComme --remote mais ouvrir un onglet "
+"pour chaque fichier"
+
+msgid "--remote-send <keys>\tSend <keys> to a Vim server and exit"
+msgstr "--remote-send <tche>\tEnvoyer <touches> à un serveur Vim puis quitter"
+
+msgid "--remote-expr <expr>\tEvaluate <expr> in a Vim server and print result"
+msgstr ""
+"--remote-expr <expr>\tÉvaluer <expr> dans un serveur Vim, afficher le "
+"résultat"
+
+msgid "--serverlist\t\tList available Vim server names and exit"
+msgstr ""
+"--serverlist\t\tLister les noms des serveurs Vim disponibles et quitter"
+
+msgid "--servername <name>\tSend to/become the Vim server <name>"
+msgstr "--servername <nom>\tEnvoyer au/devenir le serveur Vim nommé <nom>"
+
+msgid "--startuptime <file>\tWrite startup timing messages to <file>"
+msgstr ""
+"--startuptime <fich>\tÉcrire les messages d'horodatage au démarrage dans "
+"<fich>"
+
+msgid "-i <viminfo>\t\tUse <viminfo> instead of .viminfo"
+msgstr "-i <viminfo>\t\tUtiliser <viminfo> au lieu du viminfo habituel"
+
+msgid "--clean\t\t'nocompatible', Vim defaults, no plugins, no viminfo"
+msgstr ""
+"--clean\t\t'nocompatible', réglages par défaut, aucun greffon ni viminfo"
+
+msgid "-h or --help\tPrint Help (this message) and exit"
+msgstr "-h ou --help\t\tAfficher l'aide (ce message) puis quitter"
+
+msgid "--version\t\tPrint version information and exit"
+msgstr "--version\t\tAfficher les informations de version et quitter"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Motif version):\n"
+msgstr ""
+"\n"
+"Arguments reconnus par gvim (version Motif) :\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (neXtaw version):\n"
+msgstr ""
+"\n"
+"Arguments reconnus par gvim (version neXtaw) :\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Athena version):\n"
+msgstr ""
+"\n"
+"Arguments reconnus par gvim (version Athena) :\n"
+
+msgid "-display <display>\tRun vim on <display>"
+msgstr "-display <écran>\tLancer Vim sur ce <display>"
+
+msgid "-iconic\t\tStart vim iconified"
+msgstr "-iconic\t\tIconifier Vim au démarrage"
+
+msgid "-background <color>\tUse <color> for the background (also: -bg)"
+msgstr ""
+"-background <coul>\tUtiliser <couleur> pour l'arrière-plan\t (abrv : -bg)"
+
+msgid "-foreground <color>\tUse <color> for normal text (also: -fg)"
+msgstr ""
+"-foreground <coul>\tUtiliser <couleur> pour le texte normal\t (abrv : -fg)"
+
+msgid "-font <font>\t\tUse <font> for normal text (also: -fn)"
+msgstr "-font <fonte>\tUtiliser <fonte> pour le texte normal\t (abrv : -fn)"
+
+msgid "-boldfont <font>\tUse <font> for bold text"
+msgstr "-boldfont <fonte>\tUtiliser <fonte> pour le texte gras"
+
+msgid "-italicfont <font>\tUse <font> for italic text"
+msgstr "-italicfont <fonte>\tUtiliser <fonte> pour le texte italique"
+
+msgid "-geometry <geom>\tUse <geom> for initial geometry (also: -geom)"
+msgstr "-geometry <géom>\tUtiliser cette <géométrie> initiale\t (abrv : -geom)"
+
+msgid "-borderwidth <width>\tUse a border width of <width> (also: -bw)"
+msgstr ""
+"-borderwidth <épais>\tUtiliser cette <épaisseur> de bordure\t (abrv : -bw)"
+
+msgid "-scrollbarwidth <width> Use a scrollbar width of <width> (also: -sw)"
+msgstr ""
+"-scrollbarwidth <lg>\tUtiliser cette <largeur> de barre de défil. (abrv: -sw)"
+
+msgid "-menuheight <height>\tUse a menu bar height of <height> (also: -mh)"
+msgstr "-menuheight <haut>\tUtiliser cette <hauteur> de menu\t (abrv : -mh)"
+
+msgid "-reverse\t\tUse reverse video (also: -rv)"
+msgstr "-reverse\t\tUtiliser la vidéo inverse\t\t (abrv : -rv)"
+
+msgid "+reverse\t\tDon't use reverse video (also: +rv)"
+msgstr "+reverse\t\tNe pas utiliser de vidéo inverse\t (abrv : +rv)"
+
+msgid "-xrm <resource>\tSet the specified resource"
+msgstr "-xrm <ressource>\tConfigurer la <ressource> spécifiée"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (GTK+ version):\n"
+msgstr ""
+"\n"
+"Arguments reconnus par gvim (version GTK+) :\n"
+
+msgid "-display <display>\tRun vim on <display> (also: --display)"
+msgstr ""
+"-display <display>\tLancer Vim sur ce <display>\t(également : --display)"
+
+msgid "--role <role>\tSet a unique role to identify the main window"
+msgstr "--role <rôle>\tDonner un rôle pour identifier la fenêtre principale"
+
+msgid "--socketid <xid>\tOpen Vim inside another GTK widget"
+msgstr "--socketid <xid>\tOuvrir Vim dans un autre widget GTK"
+
+msgid "--echo-wid\t\tMake gvim echo the Window ID on stdout"
+msgstr "--echo-wid\t\tGvim affiche l'ID de la fenêtre sur stdout"
+
+msgid "-P <parent title>\tOpen Vim inside parent application"
+msgstr "-P <titre parent>\tOuvrir Vim dans une application parente"
+
+msgid "--windowid <HWND>\tOpen Vim inside another win32 widget"
+msgstr "--windowid <HWND>\tOuvrir Vim dans un autre widget win32"
+
+msgid "No display"
+msgstr "Aucun display"
+
+msgid ": Send failed.\n"
+msgstr " : L'envoi a échoué.\n"
+
+msgid ": Send failed. Trying to execute locally\n"
+msgstr " : L'envoi a échoué. Tentative d'exécution locale\n"
+
+#, c-format
+msgid "%d of %d edited"
+msgstr "%d édités sur %d"
+
+msgid "No display: Send expression failed.\n"
+msgstr "Aucun display : L'envoi de l'expression a échoué.\n"
+
+msgid ": Send expression failed.\n"
+msgstr " : L'envoi de l'expression a échoué.\n"
+
+msgid "No marks set"
+msgstr "Aucune marque positionnée"
+
+#, c-format
+msgid "E283: No marks matching \"%s\""
+msgstr "E283: Aucune marque ne correspond à \"%s\""
+
+msgid ""
+"\n"
+"mark line col file/text"
+msgstr ""
+"\n"
+"marq ligne col fichier/texte"
+
+msgid ""
+"\n"
+" jump line col file/text"
+msgstr ""
+"\n"
+" saut ligne col fichier/texte"
+
+msgid ""
+"\n"
+"change line col text"
+msgstr ""
+"\n"
+"modif ligne col fichier/texte"
+
+msgid ""
+"\n"
+"# File marks:\n"
+msgstr ""
+"\n"
+"# Marques dans le fichier :\n"
+
+msgid ""
+"\n"
+"# Jumplist (newest first):\n"
+msgstr ""
+"\n"
+"# Liste de sauts (le plus récent en premier) :\n"
+
+msgid ""
+"\n"
+"# History of marks within files (newest to oldest):\n"
+msgstr ""
+"\n"
+"# Historique des marques dans les fichiers (les plus récentes en premier) :\n"
+
+msgid "Missing '>'"
+msgstr "'>' manquant"
+
+msgid "E543: Not a valid codepage"
+msgstr "E543: Page de codes non valide"
+
+msgid "E284: Cannot set IC values"
+msgstr "E284: Impossible de régler les valeurs IC"
+
+msgid "E285: Failed to create input context"
+msgstr "E285: Échec de la création du contexte de saisie"
+
+msgid "E286: Failed to open input method"
+msgstr "E286: Échec de l'ouverture de la méthode de saisie"
+
+msgid "E287: Warning: Could not set destroy callback to IM"
+msgstr ""
+"E287: Alerte : Impossible d'inscrire le callback de destruction dans la MS"
+
+msgid "E288: input method doesn't support any style"
+msgstr "E288: la méthode de saisie ne supporte aucun style"
+
+msgid "E289: input method doesn't support my preedit type"
+msgstr ""
+"E289: le type de préédition de Vim n'est pas supporté par la méthode de "
+"saisie"
+
+msgid "E293: block was not locked"
+msgstr "E293: le bloc n'était pas verrouillé"
+
+msgid "E294: Seek error in swap file read"
+msgstr "E294: Erreur de positionnement lors de la lecture du fichier d'échange"
+
+msgid "E295: Read error in swap file"
+msgstr "E295: Erreur de lecture dans le fichier d'échange"
+
+msgid "E296: Seek error in swap file write"
+msgstr "E296: Erreur de positionnement lors de l'écriture du fichier d'échange"
+
+msgid "E297: Write error in swap file"
+msgstr "E297: Erreur d'écriture dans le fichier d'échange"
+
+msgid "E300: Swap file already exists (symlink attack?)"
+msgstr "E300: Le fichier d'échange existe déjà (attaque par symlink ?)"
+
+msgid "E298: Didn't get block nr 0?"
+msgstr "E298: Bloc n°0 non récupéré ?"
+
+msgid "E298: Didn't get block nr 1?"
+msgstr "E298: Bloc n°1 non récupéré ?"
+
+msgid "E298: Didn't get block nr 2?"
+msgstr "E298: Bloc n°2 non récupéré ?"
+
+msgid "E843: Error while updating swap file crypt"
+msgstr "E843: Erreur lors de la mise à jour du fichier d'échange crypté"
+
+msgid "E301: Oops, lost the swap file!!!"
+msgstr "E301: Oups, le fichier d'échange a disparu !"
+
+msgid "E302: Could not rename swap file"
+msgstr "E302: Impossible de renommer le fichier d'échange"
+
+#, c-format
+msgid "E303: Unable to open swap file for \"%s\", recovery impossible"
+msgstr "E303: Impossible d'ouvrir fichier .swp pour \"%s\", récup. impossible"
+
+msgid "E304: ml_upd_block0(): Didn't get block 0??"
+msgstr "E304: ml_upd_block0() : bloc 0 non récupéré ?!"
+
+#, c-format
+msgid "E305: No swap file found for %s"
+msgstr "E305: Aucun fichier d'échange trouvé pour %s"
+
+msgid "Enter number of swap file to use (0 to quit): "
+msgstr "Entrez le numéro du fichier d'échange à utiliser (0 pour quitter) : "
+
+#, c-format
+msgid "E306: Cannot open %s"
+msgstr "E306: Impossible d'ouvrir %s"
+
+msgid "Unable to read block 0 from "
+msgstr "Impossible de lire le bloc 0 de "
+
+msgid ""
+"\n"
+"Maybe no changes were made or Vim did not update the swap file."
+msgstr ""
+"\n"
+"Il est possible qu'aucune modification n'a été faite ou que Vim n'a pas mis "
+"à jour le fichier d'échange."
+
+msgid " cannot be used with this version of Vim.\n"
+msgstr " ne peut pas être utilisé avec cette version de Vim.\n"
+
+msgid "Use Vim version 3.0.\n"
+msgstr "Utilisez Vim version 3.0.\n"
+
+#, c-format
+msgid "E307: %s does not look like a Vim swap file"
+msgstr "E307: %s ne semble pas être un fichier d'échange de Vim"
+
+msgid " cannot be used on this computer.\n"
+msgstr " ne peut pas être utilisé sur cet ordinateur.\n"
+
+msgid "The file was created on "
+msgstr "Le fichier a été créé le "
+
+msgid ""
+",\n"
+"or the file has been damaged."
+msgstr ""
+",\n"
+"ou le fichier a été endommagé."
+
+#, c-format
+msgid ""
+"E833: %s is encrypted and this version of Vim does not support encryption"
+msgstr ""
+"E833: %s est chiffré et cette version de Vim ne supporte pas le chiffrement"
+
+msgid " has been damaged (page size is smaller than minimum value).\n"
+msgstr " a été endommagé (taille de page inférieure à la valeur minimale).\n"
+
+#, c-format
+msgid "Using swap file \"%s\""
+msgstr "Utilisation du fichier d'échange \"%s\""
+
+#, c-format
+msgid "Original file \"%s\""
+msgstr "Fichier original \"%s\""
+
+msgid "E308: Warning: Original file may have been changed"
+msgstr "E308: Alerte : Le fichier original a pu être modifié"
+
+#, c-format
+msgid "Swap file is encrypted: \"%s\""
+msgstr "Fichier d'échange chiffré : \"%s\""
+
+msgid ""
+"\n"
+"If you entered a new crypt key but did not write the text file,"
+msgstr ""
+"\n"
+"Si vous avez tapé une nouvelle clé de chiffrement mais n'avez pas enregistré "
+"le fichier texte,"
+
+msgid ""
+"\n"
+"enter the new crypt key."
+msgstr ""
+"\n"
+"tapez la nouvelle clé de chiffrement."
+
+msgid ""
+"\n"
+"If you wrote the text file after changing the crypt key press enter"
+msgstr ""
+"\n"
+"Si vous avez écrit le fichier texte après avoir changé la clé de "
+"chiffrement, appuyez sur entrée"
+
+msgid ""
+"\n"
+"to use the same key for text file and swap file"
+msgstr ""
+"\n"
+"afin d'utiliser la même clé pour le fichier texte et le fichier d'échange"
+
+#, c-format
+msgid "E309: Unable to read block 1 from %s"
+msgstr "E309: Impossible de lire le bloc 1 de %s"
+
+msgid "???MANY LINES MISSING"
+msgstr "???DE NOMBREUSES LIGNES MANQUENT"
+
+msgid "???LINE COUNT WRONG"
+msgstr "???NOMBRE DE LIGNES ERRONÉ"
+
+msgid "???EMPTY BLOCK"
+msgstr "???BLOC VIDE"
+
+msgid "???LINES MISSING"
+msgstr "???LIGNES MANQUANTES"
+
+#, c-format
+msgid "E310: Block 1 ID wrong (%s not a .swp file?)"
+msgstr "E310: ID du bloc 1 erroné (%s n'est pas un fichier d'échange ?)"
+
+msgid "???BLOCK MISSING"
+msgstr "???BLOC MANQUANT"
+
+msgid "??? from here until ???END lines may be messed up"
+msgstr "??? d'ici jusqu'à ???FIN des lignes peuvent être corrompues"
+
+msgid "??? from here until ???END lines may have been inserted/deleted"
+msgstr "??? d'ici jusqu'à ???FIN des lignes ont pu être insérées/effacées"
+
+msgid "???END"
+msgstr "???FIN"
+
+msgid "E311: Recovery Interrupted"
+msgstr "E311: Récupération interrompue"
+
+msgid ""
+"E312: Errors detected while recovering; look for lines starting with ???"
+msgstr ""
+"E312: Erreurs lors de la récupération ; examinez les lignes commençant "
+"par ???"
+
+msgid "See \":help E312\" for more information."
+msgstr "Consultez \":help E312\" pour plus d'information."
+
+msgid "Recovery completed. You should check if everything is OK."
+msgstr "Récupération achevée. Vérifiez que tout est correct."
+
+msgid ""
+"\n"
+"(You might want to write out this file under another name\n"
+msgstr ""
+"\n"
+"(Vous voudrez peut-être enregistrer ce fichier sous un autre nom\n"
+
+msgid "and run diff with the original file to check for changes)"
+msgstr "et lancer diff avec le fichier original pour repérer les changements)"
+
+msgid "Recovery completed. Buffer contents equals file contents."
+msgstr ""
+"Récupération achevée. Le contenu du tampon est identique au contenu du "
+"fichier."
+
+msgid ""
+"\n"
+"You may want to delete the .swp file now.\n"
+"\n"
+msgstr ""
+"\n"
+"Il est conseillé d'effacer maintenant le fichier .swp.\n"
+"\n"
+
+msgid "Using crypt key from swap file for the text file.\n"
+msgstr ""
+"Utilisation de la clé de chiffrement du fichier d'échange pour le fichier "
+"texte.\n"
+
+msgid "Swap files found:"
+msgstr "Fichiers d'échange trouvés :"
+
+msgid " In current directory:\n"
+msgstr " Dans le répertoire courant :\n"
+
+msgid " Using specified name:\n"
+msgstr "Utilisant le nom indiqué :\n"
+
+msgid " In directory "
+msgstr " Dans le répertoire "
+
+msgid " -- none --\n"
+msgstr " -- aucun --\n"
+
+msgid " owned by: "
+msgstr " propriété de : "
+
+msgid " dated: "
+msgstr " daté : "
+
+msgid " dated: "
+msgstr " daté : "
+
+msgid " [from Vim version 3.0]"
+msgstr " [de Vim version 3.0]"
+
+msgid " [does not look like a Vim swap file]"
+msgstr " [ne semble pas être un fichier d'échange Vim]"
+
+msgid " file name: "
+msgstr " nom de fichier : "
+
+msgid ""
+"\n"
+" modified: "
+msgstr ""
+"\n"
+" modifié : "
+
+msgid "YES"
+msgstr "OUI"
+
+msgid "no"
+msgstr "non"
+
+msgid ""
+"\n"
+" user name: "
+msgstr ""
+"\n"
+" nom d'utilisateur : "
+
+msgid " host name: "
+msgstr " nom d'hôte : "
+
+msgid ""
+"\n"
+" host name: "
+msgstr ""
+"\n"
+" nom d'hôte : "
+
+msgid ""
+"\n"
+" process ID: "
+msgstr ""
+"\n"
+" processus n° : "
+
+msgid " (STILL RUNNING)"
+msgstr " (EN COURS D'EXÉCUTION)"
+
+msgid ""
+"\n"
+" [not usable with this version of Vim]"
+msgstr ""
+"\n"
+" [inutilisable avec cette version de Vim]"
+
+msgid ""
+"\n"
+" [not usable on this computer]"
+msgstr ""
+"\n"
+" [inutilisable sur cet ordinateur]"
+
+msgid " [cannot be read]"
+msgstr " [ne peut être lu]"
+
+msgid " [cannot be opened]"
+msgstr " [ne peut être ouvert]"
+
+msgid "E313: Cannot preserve, there is no swap file"
+msgstr "E313: Préservation impossible, il n'y a pas de fichier d'échange"
+
+msgid "File preserved"
+msgstr "Fichier préservé"
+
+msgid "E314: Preserve failed"
+msgstr "E314: Échec de la préservation"
+
+#, c-format
+msgid "E315: ml_get: invalid lnum: %ld"
+msgstr "E315: ml_get : numéro de ligne invalide : %ld"
+
+#, c-format
+msgid "E316: ml_get: cannot find line %ld"
+msgstr "E316: ml_get : ligne %ld introuvable"
+
+msgid "E317: pointer block id wrong 3"
+msgstr "E317: mauvais id de pointeur de bloc 3"
+
+msgid "stack_idx should be 0"
+msgstr "stack_idx devrait être 0"
+
+msgid "E318: Updated too many blocks?"
+msgstr "E318: Trop de blocs mis à jour ?"
+
+msgid "E317: pointer block id wrong 4"
+msgstr "E317: mauvais id de pointeur de bloc 4"
+
+msgid "deleted block 1?"
+msgstr "bloc 1 effacé ?"
+
+#, c-format
+msgid "E320: Cannot find line %ld"
+msgstr "E320: Ligne %ld introuvable"
+
+msgid "E317: pointer block id wrong"
+msgstr "E317: mauvais id de pointeur de bloc"
+
+msgid "pe_line_count is zero"
+msgstr "pe_line_count vaut zéro"
+
+#, c-format
+msgid "E322: line number out of range: %ld past the end"
+msgstr "E322: numéro de ligne hors limites : %ld au-delà de la fin"
+
+#, c-format
+msgid "E323: line count wrong in block %ld"
+msgstr "E323: nombre de lignes erroné dans le bloc %ld"
+
+msgid "Stack size increases"
+msgstr "La taille de la pile s'accroît"
+
+msgid "E317: pointer block id wrong 2"
+msgstr "E317: mauvais id de pointeur de block 2"
+
+#, c-format
+msgid "E773: Symlink loop for \"%s\""
+msgstr "E773: cycle de liens symboliques avec \"%s\""
+
+msgid "E325: ATTENTION"
+msgstr "E325: ATTENTION"
+
+msgid ""
+"\n"
+"Found a swap file by the name \""
+msgstr ""
+"\n"
+"Trouvé un fichier d'échange nommé \""
+
+msgid "While opening file \""
+msgstr "Lors de l'ouverture du fichier \""
+
+msgid " CANNOT BE FOUND"
+msgstr " INTROUVABLE"
+
+msgid " NEWER than swap file!\n"
+msgstr " PLUS RÉCENT que le fichier d'échange !\n"
+
+msgid ""
+"\n"
+"(1) Another program may be editing the same file. If this is the case,\n"
+" be careful not to end up with two different instances of the same\n"
+" file when making changes. Quit, or continue with caution.\n"
+msgstr ""
+"\n"
+"(1) Un autre programme est peut-être en train d'éditer ce fichier.\n"
+" Si c'est le cas, faites attention à ne pas vous retrouver avec\n"
+" deux versions différentes du même fichier en faisant des modifications.\n"
+" Quitter ou continuer avec attention.\n"
+
+msgid "(2) An edit session for this file crashed.\n"
+msgstr "(2) Une session d'édition de ce fichier a planté.\n"
+
+msgid " If this is the case, use \":recover\" or \"vim -r "
+msgstr " Si c'est le cas, utilisez \":recover\" ou \"vim -r "
+
+msgid ""
+"\"\n"
+" to recover the changes (see \":help recovery\").\n"
+msgstr ""
+"\"\n"
+" pour récupérer le fichier (consultez \":help recovery\").\n"
+
+msgid " If you did this already, delete the swap file \""
+msgstr " Si vous l'avez déjà fait, effacez le fichier d'échange \""
+
+msgid ""
+"\"\n"
+" to avoid this message.\n"
+msgstr ""
+"\"\n"
+" pour éviter ce message.\n"
+
+msgid "Swap file \""
+msgstr "Le fichier d'échange \""
+
+msgid "\" already exists!"
+msgstr "\" existe déjà !"
+
+msgid "VIM - ATTENTION"
+msgstr "VIM - ATTENTION"
+
+msgid "Swap file already exists!"
+msgstr "Un fichier d'échange existe déjà !"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"&Ouvrir en lecture seule\n"
+"&Editer quand même\n"
+"&Récupérer\n"
+"&Quitter\n"
+"&Abandonner"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Delete it\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"&Ouvrir en lecture seule\n"
+"&Editer quand même\n"
+"&Récupérer\n"
+"Le &supprimer\n"
+"&Quitter\n"
+"&Abandonner"
+
+msgid "E326: Too many swap files found"
+msgstr "E326: Trop de fichiers d'échange trouvés"
+
+msgid "E327: Part of menu-item path is not sub-menu"
+msgstr "E327: Une partie du chemin de l'élément de menu n'est pas un sous-menu"
+
+# DB - todo : J'hésite avec
+# msgstr "E328: Le menu n'existe pas dans ce mode"
+msgid "E328: Menu only exists in another mode"
+msgstr "E328: Le menu n'existe que dans un autre mode"
+
+#, c-format
+msgid "E329: No menu \"%s\""
+msgstr "E329: Aucun menu \"%s\""
+
+msgid "E792: Empty menu name"
+msgstr "E792: Nom de menu vide"
+
+msgid "E330: Menu path must not lead to a sub-menu"
+msgstr "E330: Le chemin de menu ne doit pas conduire à un sous-menu"
+
+msgid "E331: Must not add menu items directly to menu bar"
+msgstr "E331: Ajout d'éléments de menu directement dans barre de menu interdit"
+
+msgid "E332: Separator cannot be part of a menu path"
+msgstr "E332: Un séparateur ne peut faire partie d'un chemin de menu"
+
+msgid ""
+"\n"
+"--- Menus ---"
+msgstr ""
+"\n"
+"--- Menus ---"
+
+msgid "Tear off this menu"
+msgstr "Détacher ce menu"
+
+#, c-format
+msgid "E335: Menu not defined for %s mode"
+msgstr "E335: Le menu n'est pas défini pour le mode %s"
+
+msgid "E333: Menu path must lead to a menu item"
+msgstr "E333: Le chemin du menu doit conduire à un élément de menu"
+
+#, c-format
+msgid "E334: Menu not found: %s"
+msgstr "E334: Menu introuvable : %s"
+
+msgid "E336: Menu path must lead to a sub-menu"
+msgstr "E336: Le chemin du menu doit conduire à un sous-menu"
+
+msgid "E337: Menu not found - check menu names"
+msgstr "E337: Menu introuvable - vérifiez les noms des menus"
+
+#, c-format
+msgid "Error detected while processing %s:"
+msgstr "Erreur détectée en traitant %s :"
+
+#, c-format
+msgid "line %4ld:"
+msgstr "ligne %4ld :"
+
+#, c-format
+msgid "E354: Invalid register name: '%s'"
+msgstr "E354: Nom de registre invalide : '%s'"
+
+# DB - todo : mettre à jour ?
+msgid "Messages maintainer: Bram Moolenaar <Bram@vim.org>"
+msgstr "Maintenance des messages : Dominique Pellé <dominique.pelle@gmail.com>"
+
+msgid "Interrupt: "
+msgstr "Interruption : "
+
+msgid "Press ENTER or type command to continue"
+msgstr "Appuyez sur ENTRÉE ou tapez une commande pour continuer"
+
+#, c-format
+msgid "%s line %ld"
+msgstr "%s, ligne %ld"
+
+msgid "-- More --"
+msgstr "-- Plus --"
+
+msgid " SPACE/d/j: screen/page/line down, b/u/k: up, q: quit "
+msgstr ""
+"ESPACE/d/j : écran/page/ligne vers le bas, b/u/k : vers le haut, q : quitter"
+
+msgid "Question"
+msgstr "Question"
+
+msgid ""
+"&Yes\n"
+"&No"
+msgstr ""
+"&Oui\n"
+"&Non"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"Save &All\n"
+"&Discard All\n"
+"&Cancel"
+msgstr ""
+"&Oui\n"
+"&Non\n"
+"Tout &enregistrer\n"
+"Tout aban&donner\n"
+"&Annuler"
+
+# DB : Les trois messages qui suivent sont des titres de boîtes
+# de dialogue par défaut.
+msgid "Select Directory dialog"
+msgstr "Sélecteur de répertoire"
+
+msgid "Save File dialog"
+msgstr "Enregistrer un fichier"
+
+msgid "Open File dialog"
+msgstr "Ouvrir un fichier"
+
+msgid "E338: Sorry, no file browser in console mode"
+msgstr "E338: Désolé, pas de sélecteur de fichiers en mode console"
+
+msgid "E766: Insufficient arguments for printf()"
+msgstr "E766: Pas assez d'arguments pour printf()"
+
+msgid "E807: Expected Float argument for printf()"
+msgstr "E807: printf() attend un argument de type Flottant"
+
+msgid "E767: Too many arguments to printf()"
+msgstr "E767: Trop d'arguments pour printf()"
+
+msgid "W10: Warning: Changing a readonly file"
+msgstr "W10: Alerte : Modification d'un fichier en lecture seule"
+
+msgid "Type number and <Enter> or click with mouse (empty cancels): "
+msgstr "Tapez un nombre et <Entrée> ou cliquez avec la souris (rien annule) :"
+
+msgid "Type number and <Enter> (empty cancels): "
+msgstr "Tapez un nombre et <Entrée> (rien annule) :"
+
+#, c-format
+msgid "%ld more line"
+msgid_plural "%ld more lines"
+msgstr[0] "%ld ligne en plus"
+msgstr[1] "%ld lignes en plus"
+
+#, c-format
+msgid "%ld line less"
+msgid_plural "%ld fewer lines"
+msgstr[0] "%ld ligne en moins"
+msgstr[1] "%ld lignes en moins"
+
+msgid " (Interrupted)"
+msgstr " (Interrompu)"
+
+msgid "Beep!"
+msgstr "Bip !"
+
+msgid "ERROR: "
+msgstr "ERREUR : "
+
+#, c-format
+msgid ""
+"\n"
+"[bytes] total alloc-freed %lu-%lu, in use %lu, peak use %lu\n"
+msgstr ""
+"\n"
+"[octets] total alloué-libéré %lu-%lu, utilisé %lu, pic %lu\n"
+
+#, c-format
+msgid ""
+"[calls] total re/malloc()'s %lu, total free()'s %lu\n"
+"\n"
+msgstr ""
+"[appels] total re/malloc() %lu, total free() %lu\n"
+"\n"
+
+msgid "E340: Line is becoming too long"
+msgstr "E340: La ligne devient trop longue"
+
+#, c-format
+msgid "E341: Internal error: lalloc(%ld, )"
+msgstr "E341: Erreur interne : lalloc(%ld, )"
+
+#, c-format
+msgid "E342: Out of memory! (allocating %lu bytes)"
+msgstr "E342: Mémoire épuisée ! (allocation de %lu octets)"
+
+#, c-format
+msgid "Calling shell to execute: \"%s\""
+msgstr "Appel du shell pour exécuter : \"%s\""
+
+msgid "E545: Missing colon"
+msgstr "E545: ':' manquant"
+
+msgid "E546: Illegal mode"
+msgstr "E546: Mode non autorisé"
+
+msgid "E547: Illegal mouseshape"
+msgstr "E547: Forme de curseur invalide"
+
+msgid "E548: digit expected"
+msgstr "E548: chiffre attendu"
+
+msgid "E549: Illegal percentage"
+msgstr "E549: Pourcentage non autorisé"
+
+msgid "E854: path too long for completion"
+msgstr "E854: chemin trop long pour complètement"
+
+#, c-format
+msgid ""
+"E343: Invalid path: '**[number]' must be at the end of the path or be "
+"followed by '%s'."
+msgstr ""
+"E343: Chemin invalide : '**[nombre]' doit être à la fin du chemin ou être "
+"suivi de '%s'."
+
+#, c-format
+msgid "E344: Can't find directory \"%s\" in cdpath"
+msgstr "E344: Répertoire \"%s\" introuvable dans 'cdpath'"
+
+#, c-format
+msgid "E345: Can't find file \"%s\" in path"
+msgstr "E345: Fichier \"%s\" introuvable dans 'path'"
+
+#, c-format
+msgid "E346: No more directory \"%s\" found in cdpath"
+msgstr "E346: Plus de répertoire \"%s\" dans 'cdpath'"
+
+#, c-format
+msgid "E347: No more file \"%s\" found in path"
+msgstr "E347: Plus de fichier \"%s\" dans 'path'"
+
+#, c-format
+msgid "E668: Wrong access mode for NetBeans connection info file: \"%s\""
+msgstr ""
+"E668: Mode d'accès incorrect au fichier d'infos de connexion NetBeans : \"%s"
+"\""
+
+#, c-format
+msgid "E658: NetBeans connection lost for buffer %ld"
+msgstr "E658: Connexion NetBeans perdue pour le tampon %ld"
+
+msgid "E838: netbeans is not supported with this GUI"
+msgstr "E838: netbeans n'est pas supporté avec cette interface graphique"
+
+msgid "E511: netbeans already connected"
+msgstr "E511: netbeans déjà connecté"
+
+#, c-format
+msgid "E505: %s is read-only (add ! to override)"
+msgstr "E505: %s est en lecture seule (ajoutez ! pour passer outre)"
+
+msgid "E349: No identifier under cursor"
+msgstr "E349: Aucun identifiant sous le curseur"
+
+msgid "E774: 'operatorfunc' is empty"
+msgstr "E774: 'operatorfunc' est vide"
+
+msgid "E775: Eval feature not available"
+msgstr "E775: La fonctionnalité d'évaluation n'est pas disponible"
+
+# DB : Il est ici question du mode Visuel.
+msgid "Warning: terminal cannot highlight"
+msgstr "Alerte : le terminal ne peut pas surligner"
+
+msgid "E348: No string under cursor"
+msgstr "E348: Aucune chaîne sous le curseur"
+
+msgid "E352: Cannot erase folds with current 'foldmethod'"
+msgstr "E352: Impossible d'effacer des replis avec la 'foldmethod'e actuelle"
+
+msgid "E664: changelist is empty"
+msgstr "E664: La liste des modifications (changelist) est vide"
+
+msgid "E662: At start of changelist"
+msgstr "E662: Au début de la liste des modifications"
+
+msgid "E663: At end of changelist"
+msgstr "E663: À la fin de la liste des modifications"
+
+msgid "Type :qa! and press <Enter> to abandon all changes and exit Vim"
+msgstr ""
+"Tapez :qa! puis <Entrée> pour abandonner tous les changements et quitter "
+"Vim"
+
+#, c-format
+msgid "%ld line %sed %d time"
+msgid_plural "%ld line %sed %d times"
+msgstr[0] "%ld lignes %sées %d fois"
+msgstr[1] "%ld lignes %sées %d fois"
+
+#, c-format
+msgid "%ld lines %sed %d time"
+msgid_plural "%ld lines %sed %d times"
+msgstr[0] "%ld lignes %sées %d fois"
+msgstr[1] "%ld lignes %sées %d fois"
+
+#, c-format
+msgid "%ld lines to indent... "
+msgstr "%ld lignes à indenter... "
+
+#, c-format
+msgid "%ld line indented "
+msgid_plural "%ld lines indented "
+msgstr[0] "%ld ligne indentée "
+msgstr[1] "%ld lignes indentées "
+
+msgid "E748: No previously used register"
+msgstr "E748: Aucun registre n'a été précédemment utilisé"
+
+# DB - Question O/N.
+msgid "cannot yank; delete anyway"
+msgstr "impossible de réaliser une copie ; effacer tout de même"
+
+#, c-format
+msgid "%ld line changed"
+msgid_plural "%ld lines changed"
+msgstr[0] "%ld ligne modifiée"
+msgstr[1] "%ld lignes modifiées"
+
+#, c-format
+msgid "freeing %ld lines"
+msgstr "libération de %ld lignes"
+
+#, c-format
+msgid " into \"%c"
+msgstr " dans \"%c"
+
+#, c-format
+msgid "block of %ld line yanked%s"
+msgid_plural "block of %ld lines yanked%s"
+msgstr[0] "bloc de %ld ligne copié%s"
+msgstr[1] "bloc de %ld lignes copié%s"
+
+#, c-format
+msgid "%ld line yanked%s"
+msgid_plural "%ld lines yanked%s"
+msgstr[0] "%ld ligne copiée%s"
+msgstr[1] "%ld lignes copiées%s"
+
+#, c-format
+msgid "E353: Nothing in register %s"
+msgstr "E353: Le registre %s est vide"
+
+msgid ""
+"\n"
+"--- Registers ---"
+msgstr ""
+"\n"
+"--- Registres ---"
+
+msgid "Illegal register name"
+msgstr "Nom de registre invalide"
+
+msgid ""
+"\n"
+"# Registers:\n"
+msgstr ""
+"\n"
+"# Registres :\n"
+
+#, c-format
+msgid "E574: Unknown register type %d"
+msgstr "E574: Type de registre %d inconnu"
+
+msgid ""
+"E883: search pattern and expression register may not contain two or more "
+"lines"
+msgstr ""
+"E883: le motif de recherche et le registre d'expression ne peuvent pas "
+"contenir deux lignes ou plus"
+
+#, c-format
+msgid "%ld Cols; "
+msgstr "%ld Colonnes ; "
+
+#, c-format
+msgid "Selected %s%ld of %ld Lines; %lld of %lld Words; %lld of %lld Bytes"
+msgstr ""
+"%s%ld sur %ld Lignes ; %lld sur %lld Mots ; %lld sur %lld Octets sélectionnés"
+
+#, c-format
+msgid ""
+"Selected %s%ld of %ld Lines; %lld of %lld Words; %lld of %lld Chars; %lld of "
+"%lld Bytes"
+msgstr ""
+"%s%ld sur %ld Lignes ; %lld sur %lld Mots ; %lld sur %lld Caractères ; %lld "
+"sur %lld octets sélectionnés"
+
+#, c-format
+msgid "Col %s of %s; Line %ld of %ld; Word %lld of %lld; Byte %lld of %lld"
+msgstr ""
+"Colonne %s sur %s ; Ligne %ld sur %ld ; Mot %lld sur %lld ; Octet %lld sur "
+"%lld"
+
+#, c-format
+msgid ""
+"Col %s of %s; Line %ld of %ld; Word %lld of %lld; Char %lld of %lld; Byte "
+"%lld of %lld"
+msgstr ""
+"Colonne %s sur %s ; Ligne %ld sur %ld ; Mot %lld sur %lld ; Caractère %lld "
+"sur %lld ; Octet %lld sur %lld"
+
+#, c-format
+msgid "(+%lld for BOM)"
+msgstr "(+%lld pour le BOM)"
+
+msgid "Thanks for flying Vim"
+msgstr "Merci d'avoir choisi Vim"
+
+msgid "E518: Unknown option"
+msgstr "E518: Option inconnue"
+
+msgid "E519: Option not supported"
+msgstr "E519: Option non supportée"
+
+msgid "E520: Not allowed in a modeline"
+msgstr "E520: Non autorisé dans une ligne de mode"
+
+msgid "E846: Key code not set"
+msgstr "E846: Le code de touche n'est pas configuré"
+
+msgid "E521: Number required after ="
+msgstr "E521: Nombre requis après ="
+
+msgid "E522: Not found in termcap"
+msgstr "E522: Introuvable dans termcap"
+
+#, c-format
+msgid "E539: Illegal character <%s>"
+msgstr "E539: Caractère <%s> invalide"
+
+#, c-format
+msgid "For option %s"
+msgstr "Pour l'option %s"
+
+msgid "E529: Cannot set 'term' to empty string"
+msgstr "E529: 'term' ne doit pas être une chaîne vide"
+
+msgid "E530: Cannot change term in GUI"
+msgstr "E530: Impossible de modifier term dans l'interface graphique"
+
+msgid "E531: Use \":gui\" to start the GUI"
+msgstr "E531: Utilisez \":gui\" pour démarrer l'interface graphique"
+
+msgid "E589: 'backupext' and 'patchmode' are equal"
+msgstr "E589: 'backupext' et 'patchmode' sont égaux"
+
+msgid "E834: Conflicts with value of 'listchars'"
+msgstr "E834: Conflits avec la valeur de 'listchars'"
+
+msgid "E835: Conflicts with value of 'fillchars'"
+msgstr "E835: Conflits avec la valeur de 'fillchars'"
+
+msgid "E617: Cannot be changed in the GTK+ 2 GUI"
+msgstr "E617: Non modifiable dans l'interface graphique GTK+ 2"
+
+#, c-format
+msgid "E950: Cannot convert between %s and %s"
+msgstr "E950: Impossible de convertir de %s à %s"
+
+msgid "E524: Missing colon"
+msgstr "E524: ':' manquant"
+
+msgid "E525: Zero length string"
+msgstr "E525: Chaîne de longueur nulle"
+
+#, c-format
+msgid "E526: Missing number after <%s>"
+msgstr "E526: Nombre manquant après <%s>"
+
+msgid "E527: Missing comma"
+msgstr "E527: Virgule manquante"
+
+msgid "E528: Must specify a ' value"
+msgstr "E528: Une valeur ' doit être spécifiée"
+
+msgid "E595: contains unprintable or wide character"
+msgstr "E595: contient des caractères à largeur double non-imprimables"
+
+msgid "E596: Invalid font(s)"
+msgstr "E596: Police(s) invalide(s)"
+
+msgid "E597: can't select fontset"
+msgstr "E597: Impossible de sélectionner un jeu de polices"
+
+msgid "E598: Invalid fontset"
+msgstr "E598: Jeu de polices invalide"
+
+msgid "E533: can't select wide font"
+msgstr "E533: Impossible de sélectionner une police à largeur double"
+
+msgid "E534: Invalid wide font"
+msgstr "E534: Police à largeur double invalide"
+
+#, c-format
+msgid "E535: Illegal character after <%c>"
+msgstr "E535: Caractère invalide après <%c>"
+
+msgid "E536: comma required"
+msgstr "E536: virgule requise"
+
+#, c-format
+msgid "E537: 'commentstring' must be empty or contain %s"
+msgstr "E537: 'commentstring' doit être vide ou contenir %s"
+
+msgid "E538: No mouse support"
+msgstr "E538: La souris n'est pas supportée"
+
+# DB - Le code est sans ambiguïté sur le caractère manquant.
+# À défaut d'une traduction valable, au moins comprend-on
+# ce qui se passe.
+msgid "E540: Unclosed expression sequence"
+msgstr "E540: '}' manquant"
+
+msgid "E541: too many items"
+msgstr "E541: trop d'éléments"
+
+msgid "E542: unbalanced groups"
+msgstr "E542: parenthèses non équilibrées"
+
+msgid "E946: Cannot make a terminal with running job modifiable"
+msgstr ""
+"E946: terminal avec tâche en cours d'exécution ne peut pas être modifiable"
+
+msgid "E590: A preview window already exists"
+msgstr "E590: Il existe déjà une fenêtre de prévisualisation"
+
+msgid "W17: Arabic requires UTF-8, do ':set encoding=utf-8'"
+msgstr "W17: L'arabe nécessite l'UTF-8, tapez ':set encoding=utf-8'"
+
+msgid "E954: 24-bit colors are not supported on this environment"
+msgstr "E954: Couleurs en 24-bits non-supportées sur cet environnement."
+
+#, c-format
+msgid "E593: Need at least %d lines"
+msgstr "E593: Au moins %d lignes sont nécessaires"
+
+#, c-format
+msgid "E594: Need at least %d columns"
+msgstr "E594: Au moins %d colonnes sont nécessaires"
+
+#, c-format
+msgid "E355: Unknown option: %s"
+msgstr "E355: Option inconnue : %s"
+
+#, c-format
+msgid "E521: Number required: &%s = '%s'"
+msgstr "E521: Nombre requis : &%s = '%s'"
+
+msgid ""
+"\n"
+"--- Terminal codes ---"
+msgstr ""
+"\n"
+"--- Codes de terminal ---"
+
+msgid ""
+"\n"
+"--- Global option values ---"
+msgstr ""
+"\n"
+"--- Valeur des options globales ---"
+
+msgid ""
+"\n"
+"--- Local option values ---"
+msgstr ""
+"\n"
+"--- Valeur des options locales ---"
+
+msgid ""
+"\n"
+"--- Options ---"
+msgstr ""
+"\n"
+"--- Options ---"
+
+msgid "E356: get_varp ERROR"
+msgstr "E356: ERREUR get_varp"
+
+#, c-format
+msgid "E357: 'langmap': Matching character missing for %s"
+msgstr "E357: 'langmap' : Aucun caractère correspondant pour %s"
+
+#, c-format
+msgid "E358: 'langmap': Extra characters after semicolon: %s"
+msgstr "E358: 'langmap' : Caractères surnuméraires après point-virgule : %s"
+
+msgid "cannot open "
+msgstr "impossible d'ouvrir "
+
+msgid "VIM: Can't open window!\n"
+msgstr "VIM : Impossible d'ouvrir la fenêtre !\n"
+
+msgid "Need Amigados version 2.04 or later\n"
+msgstr "Amigados version 2.04 ou ultérieure est nécessaire\n"
+
+#, c-format
+msgid "Need %s version %ld\n"
+msgstr "%s version %ld est nécessaire\n"
+
+msgid "Cannot open NIL:\n"
+msgstr "Impossible d'ouvrir NIL :\n"
+
+msgid "Cannot create "
+msgstr "Impossible de créer "
+
+#, c-format
+msgid "Vim exiting with %d\n"
+msgstr "Vim quitte avec %d\n"
+
+msgid "cannot change console mode ?!\n"
+msgstr "Impossible de modifier le mode de la console ?!\n"
+
+msgid "mch_get_shellsize: not a console??\n"
+msgstr "mch_get_shellsize : pas une console ?!\n"
+
+msgid "E360: Cannot execute shell with -f option"
+msgstr "E360: Impossible d'exécuter un shell avec l'option -f"
+
+msgid "Cannot execute "
+msgstr "Impossible d'exécuter "
+
+msgid "shell "
+msgstr "le shell "
+
+msgid " returned\n"
+msgstr " a été retourné\n"
+
+msgid "ANCHOR_BUF_SIZE too small."
+msgstr "ANCHOR_BUF_SIZE trop petit."
+
+msgid "I/O ERROR"
+msgstr "ERREUR d'E/S"
+
+msgid "Message"
+msgstr "Message"
+
+msgid "E237: Printer selection failed"
+msgstr "E237: La sélection de l'imprimante a échoué"
+
+# DB - Contenu des c-formats : Imprimante puis Port.
+#, c-format
+msgid "to %s on %s"
+msgstr "vers %s sur %s"
+
+#, c-format
+msgid "E613: Unknown printer font: %s"
+msgstr "E613: Police d'imprimante inconnue : %s"
+
+#, c-format
+msgid "E238: Print error: %s"
+msgstr "E238: Erreur d'impression : %s"
+
+#, c-format
+msgid "Printing '%s'"
+msgstr "Impression de '%s'"
+
+#, c-format
+msgid "E244: Illegal charset name \"%s\" in font name \"%s\""
+msgstr "E244: Jeu de caractères \"%s\" invalide dans le nom de fonte \"%s\""
+
+#, c-format
+msgid "E244: Illegal quality name \"%s\" in font name \"%s\""
+msgstr "E244: Nom de qualité \"%s\" invalide dans le nom de fonte \"%s\""
+
+#, c-format
+msgid "E245: Illegal char '%c' in font name \"%s\""
+msgstr "E245: Caractère '%c' invalide dans le nom de fonte \"%s\""
+
+#, c-format
+msgid "Opening the X display took %ld msec"
+msgstr "L'ouverture du display X a pris %ld ms"
+
+msgid ""
+"\n"
+"Vim: Got X error\n"
+msgstr ""
+"\n"
+"Vim : Réception d'une erreur X\n"
+
+msgid "Testing the X display failed"
+msgstr "Le test du display X a échoué"
+
+msgid "Opening the X display timed out"
+msgstr "L'ouverture du display X a dépassé le délai d'attente"
+
+msgid ""
+"\n"
+"Could not get security context for "
+msgstr ""
+"\n"
+"Impossible d'obtenir le contexte de sécurité pour "
+
+msgid ""
+"\n"
+"Could not set security context for "
+msgstr ""
+"\n"
+"Impossible de modifier le contexte de sécurité pour "
+
+#, c-format
+msgid "Could not set security context %s for %s"
+msgstr "Impossible d'initialiser le contexte de sécurité %s pour %s"
+
+#, c-format
+msgid "Could not get security context %s for %s. Removing it!"
+msgstr ""
+"Impossible d'obtenir le contexte de sécurité %s pour %s. Il sera supprimé !"
+
+msgid ""
+"\n"
+"Cannot execute shell sh\n"
+msgstr ""
+"\n"
+"Impossible d'exécuter le shell sh\n"
+
+msgid ""
+"\n"
+"shell returned "
+msgstr ""
+"\n"
+"le shell a retourné "
+
+msgid ""
+"\n"
+"Cannot create pipes\n"
+msgstr ""
+"\n"
+"Impossible de créer des tuyaux (pipes)\n"
+
+msgid ""
+"\n"
+"Cannot fork\n"
+msgstr ""
+"\n"
+"Impossible de forker\n"
+
+msgid ""
+"\n"
+"Cannot execute shell "
+msgstr ""
+"\n"
+"Impossible d'exécuter le shell "
+
+msgid ""
+"\n"
+"Command terminated\n"
+msgstr ""
+"\n"
+"Commande interrompue\n"
+
+msgid "XSMP lost ICE connection"
+msgstr "XSMP a perdu la connexion ICE"
+
+#, c-format
+msgid "dlerror = \"%s\""
+msgstr "dlerror = \"%s\""
+
+msgid "Opening the X display failed"
+msgstr "L'ouverture du display X a échoué"
+
+msgid "XSMP handling save-yourself request"
+msgstr "XSMP : prise en charge d'une requête save-yourself"
+
+msgid "XSMP opening connection"
+msgstr "XSMP : ouverture de la connexion"
+
+msgid "XSMP ICE connection watch failed"
+msgstr "XSMP : échec de la surveillance de connexion ICE"
+
+#, c-format
+msgid "XSMP SmcOpenConnection failed: %s"
+msgstr "XSMP : SmcOpenConnection a échoué : %s"
+
+msgid "At line"
+msgstr "À la ligne"
+
+msgid "Could not load vim32.dll!"
+msgstr "Impossible de charger vim32.dll !"
+
+msgid "VIM Error"
+msgstr "Erreur VIM"
+
+msgid "Could not fix up function pointers to the DLL!"
+msgstr "Impossible d'initialiser les pointeurs de fonction vers la DLL !"
+
+# DB - Les événements en question sont ceux des messages qui suivent.
+#, c-format
+msgid "Vim: Caught %s event\n"
+msgstr "Vim : Événement %s intercepté\n"
+
+msgid "close"
+msgstr "de fermeture"
+
+msgid "logoff"
+msgstr "de déconnexion"
+
+msgid "shutdown"
+msgstr "d'arrêt"
+
+msgid "E371: Command not found"
+msgstr "E371: Commande introuvable"
+
+msgid ""
+"VIMRUN.EXE not found in your $PATH.\n"
+"External commands will not pause after completion.\n"
+"See :help win32-vimrun for more information."
+msgstr ""
+"VIMRUN.EXE est introuvable votre $PATH.\n"
+"Les commandes externes ne feront pas de pause une fois terminées.\n"
+"Consultez :help win32-vimrun pour plus d'informations."
+
+msgid "Vim Warning"
+msgstr "Alerte Vim"
+
+#, c-format
+msgid "shell returned %d"
+msgstr "le shell a retourné %d"
+
+msgid "E926: Current location list was changed"
+msgstr "E926: La liste d'emplacements courante a changé"
+
+#, c-format
+msgid "E372: Too many %%%c in format string"
+msgstr "E372: Trop de %%%c dans la chaîne de format"
+
+#, c-format
+msgid "E373: Unexpected %%%c in format string"
+msgstr "E373: %%%c inattendu dans la chaîne de format"
+
+msgid "E374: Missing ] in format string"
+msgstr "E374: ] manquant dans la chaîne de format"
+
+#, c-format
+msgid "E375: Unsupported %%%c in format string"
+msgstr "E375: %%%c non supporté dans la chaîne de format"
+
+#, c-format
+msgid "E376: Invalid %%%c in format string prefix"
+msgstr "E376: %%%c invalide dans le préfixe de la chaîne de format"
+
+#, c-format
+msgid "E377: Invalid %%%c in format string"
+msgstr "E377: %%%c invalide dans la chaîne de format"
+
+msgid "E378: 'errorformat' contains no pattern"
+msgstr "E378: 'errorformat' ne contient aucun motif"
+
+msgid "E379: Missing or empty directory name"
+msgstr "E379: Nom de répertoire vide ou absent"
+
+msgid "E553: No more items"
+msgstr "E553: Plus d'éléments"
+
+msgid "E924: Current window was closed"
+msgstr "E924: La fenêtre courante doit être fermée"
+
+msgid "E925: Current quickfix was changed"
+msgstr "E925: Le quickfix courant a changé"
+
+#, c-format
+msgid "(%d of %d)%s%s: "
+msgstr "(%d sur %d)%s%s : "
+
+msgid " (line deleted)"
+msgstr " (ligne effacée)"
+
+#, c-format
+msgid "%serror list %d of %d; %d errors "
+msgstr "%sliste d'erreurs %d sur %d ; %d erreurs"
+
+msgid "E380: At bottom of quickfix stack"
+msgstr "E380: En bas de la pile quickfix"
+
+msgid "E381: At top of quickfix stack"
+msgstr "E381: Au sommet de la pile quickfix"
+
+msgid "No entries"
+msgstr "Aucune entrée"
+
+msgid "Error file"
+msgstr "Fichier d'erreurs"
+
+msgid "E683: File name missing or invalid pattern"
+msgstr "E683: Nom de fichier manquant ou motif invalide"
+
+#, c-format
+msgid "Cannot open file \"%s\""
+msgstr "Impossible d'ouvrir le fichier \"%s\""
+
+msgid "E681: Buffer is not loaded"
+msgstr "E681: le tampon n'est pas chargé"
+
+msgid "E777: String or List expected"
+msgstr "E777: Chaîne ou Liste attendue"
+
+#, c-format
+msgid "E369: invalid item in %s%%[]"
+msgstr "E369: élément invalide dans %s%%[]"
+
+#, c-format
+msgid "E769: Missing ] after %s["
+msgstr "E769: ']' manquant après %s["
+
+msgid "E944: Reverse range in character class"
+msgstr "E944: Classe de caractères inversée"
+
+msgid "E945: Range too large in character class"
+msgstr "E945: Plage de classe de caractères trop large"
+
+#, c-format
+msgid "E53: Unmatched %s%%("
+msgstr "E53: Pas de correspondance pour %s%%("
+
+#, c-format
+msgid "E54: Unmatched %s("
+msgstr "E54: %s( ouvrante non fermée"
+
+#, c-format
+msgid "E55: Unmatched %s)"
+msgstr "E55: %s) fermante non ouverte"
+
+msgid "E66: \\z( not allowed here"
+msgstr "E66: \\z( n'est pas autorisé ici"
+
+msgid "E67: \\z1 - \\z9 not allowed here"
+msgstr "E67: \\z1 et co. ne sont pas autorisés ici"
+
+#, c-format
+msgid "E69: Missing ] after %s%%["
+msgstr "E69: ']' manquant après %s%%["
+
+#, c-format
+msgid "E70: Empty %s%%[]"
+msgstr "E70: %s%%[] vide"
+
+msgid "E956: Cannot use pattern recursively"
+msgstr "E956: Impossible d'utiliser le motif récursivement"
+
+msgid "E65: Illegal back reference"
+msgstr "E65: post-référence invalide"
+
+msgid "E339: Pattern too long"
+msgstr "E339: Motif trop long"
+
+msgid "E50: Too many \\z("
+msgstr "E50: Trop de \\z("
+
+#, c-format
+msgid "E51: Too many %s("
+msgstr "E51: Trop de %s("
+
+msgid "E52: Unmatched \\z("
+msgstr "E52: Pas de correspondance pour \\z("
+
+#, c-format
+msgid "E59: invalid character after %s@"
+msgstr "E59: caractère invalide après %s@"
+
+#, c-format
+msgid "E60: Too many complex %s{...}s"
+msgstr "E60: Trop de %s{...}s complexes"
+
+#, c-format
+msgid "E61: Nested %s*"
+msgstr "E61: %s* imbriqués"
+
+#, c-format
+msgid "E62: Nested %s%c"
+msgstr "E62: %s%c imbriqués"
+
+msgid "E63: invalid use of \\_"
+msgstr "E63: utilisation invalide de \\_"
+
+#, c-format
+msgid "E64: %s%c follows nothing"
+msgstr "E64: %s%c ne suit aucun atome"
+
+msgid "E68: Invalid character after \\z"
+msgstr "E68: Caractère invalide après \\z"
+
+#, c-format
+msgid "E678: Invalid character after %s%%[dxouU]"
+msgstr "E678: Caractère invalide après %s%%[dxouU]"
+
+#, c-format
+msgid "E71: Invalid character after %s%%"
+msgstr "E71: Caractère invalide après %s%%"
+
+#, c-format
+msgid "E554: Syntax error in %s{...}"
+msgstr "E554: Erreur de syntaxe dans %s{...}"
+
+msgid "External submatches:\n"
+msgstr "Sous-correspondances externes :\n"
+
+#, c-format
+msgid "E888: (NFA regexp) cannot repeat %s"
+msgstr "E888: (regexp NFA) %s ne peut pas être répété"
+
+msgid ""
+"E864: \\%#= can only be followed by 0, 1, or 2. The automatic engine will be "
+"used "
+msgstr ""
+"E864: \\%#= peut être suivi uniquement de 0, 1 ou 2. Le moteur automatique "
+"sera utilisé "
+
+msgid "Switching to backtracking RE engine for pattern: "
+msgstr "Moteur RE avec backtracking utilisé pour le motif : "
+
+msgid "E865: (NFA) Regexp end encountered prematurely"
+msgstr "E865: (NFA) Fin de regexp rencontrée prématurément"
+
+#, c-format
+msgid "E866: (NFA regexp) Misplaced %c"
+msgstr "E866: (regexp NFA) %c au mauvais endroit"
+
+#, c-format
+msgid "E877: (NFA regexp) Invalid character class: %ld"
+msgstr "E877: (regexp NFA) Classe de caractère invalide : %ld"
+
+#, c-format
+msgid "E867: (NFA) Unknown operator '\\z%c'"
+msgstr "E867: (NFA) Opérateur inconnu '\\z%c'"
+
+msgid "E951: \\% value too large"
+msgstr "E951: valeur \\% trop grande"
+
+#, c-format
+msgid "E867: (NFA) Unknown operator '\\%%%c'"
+msgstr "E867: (NFA) Opérateur inconnu '\\%%%c'"
+
+msgid "E868: Error building NFA with equivalence class!"
+msgstr "E868: Erreur lors de la construction du NFA avec classe d'équivalence"
+
+#, c-format
+msgid "E869: (NFA) Unknown operator '\\@%c'"
+msgstr "E869: (NFA) Opérateur inconnu '\\@%c'"
+
+msgid "E870: (NFA regexp) Error reading repetition limits"
+msgstr "E870: (regexp NFA) Erreur à la lecture des limites de répétition"
+
+msgid "E871: (NFA regexp) Can't have a multi follow a multi"
+msgstr "E871: (regexp NFA) Un multi ne peut pas suivre un multi"
+
+msgid "E872: (NFA regexp) Too many '('"
+msgstr "E872: (regexp NFA) Trop de '('"
+
+msgid "E879: (NFA regexp) Too many \\z("
+msgstr "E879: (regexp NFA) Trop de \\z("
+
+msgid "E873: (NFA regexp) proper termination error"
+msgstr "E873: (NFA regexp) erreur de terminaison"
+
+msgid "Could not open temporary log file for writing, displaying on stderr... "
+msgstr ""
+"Impossible d'ouvrir le fichier de log temporaire en écriture, affichage sur "
+"stderr... "
+
+msgid "E874: (NFA) Could not pop the stack!"
+msgstr "E874: (NFA) Impossible de dépiler !"
+
+msgid ""
+"E875: (NFA regexp) (While converting from postfix to NFA), too many states "
+"left on stack"
+msgstr ""
+"E875: (regexp NFA) (lors de la conversion de postfix à NFA), il reste trop "
+"d'états sur la pile"
+
+msgid "E876: (NFA regexp) Not enough space to store the whole NFA "
+msgstr "E876: (regexp NFA) Pas assez de mémoire pour stocker le NFA"
+
+msgid "E878: (NFA) Could not allocate memory for branch traversal!"
+msgstr ""
+"E878: (NFA) Impossible d'allouer la mémoire pour parcourir les branches !"
+
+msgid " VREPLACE"
+msgstr " VREMPLACEMENT"
+
+msgid " REPLACE"
+msgstr " REMPLACEMENT"
+
+# DB - todo
+msgid " REVERSE"
+msgstr " REVERSE"
+
+msgid " INSERT"
+msgstr " INSERTION"
+
+msgid " (insert)"
+msgstr " (insertion)"
+
+msgid " (replace)"
+msgstr " (remplacement)"
+
+msgid " (vreplace)"
+msgstr " (vremplacement)"
+
+msgid " Hebrew"
+msgstr " hébreu"
+
+msgid " Arabic"
+msgstr " arabe"
+
+msgid " (paste)"
+msgstr " (collage)"
+
+msgid " VISUAL"
+msgstr " VISUEL"
+
+msgid " VISUAL LINE"
+msgstr " VISUEL LIGNE"
+
+msgid " VISUAL BLOCK"
+msgstr " VISUEL BLOC"
+
+msgid " SELECT"
+msgstr " SÉLECTION"
+
+msgid " SELECT LINE"
+msgstr " SÉLECTION LIGNE"
+
+msgid " SELECT BLOCK"
+msgstr " SÉLECTION BLOC"
+
+msgid "recording"
+msgstr "Enregistrement"
+
+#, c-format
+msgid "E383: Invalid search string: %s"
+msgstr "E383: Chaîne de recherche invalide : %s"
+
+#, c-format
+msgid "E384: search hit TOP without match for: %s"
+msgstr "E384: la recherche a atteint le HAUT sans trouver : %s"
+
+#, c-format
+msgid "E385: search hit BOTTOM without match for: %s"
+msgstr "E385: la recherche a atteint le BAS sans trouver : %s"
+
+msgid "E386: Expected '?' or '/' after ';'"
+msgstr "E386: '?' ou '/' attendu après ';'"
+
+msgid " (includes previously listed match)"
+msgstr " (inclut des correspondances listées précédemment)"
+
+msgid "--- Included files "
+msgstr "--- Fichiers inclus "
+
+msgid "not found "
+msgstr "introuvables "
+
+msgid "in path ---\n"
+msgstr "dans le chemin ---\n"
+
+msgid " (Already listed)"
+msgstr " (Déjà listé)"
+
+msgid " NOT FOUND"
+msgstr " INTROUVABLE"
+
+#, c-format
+msgid "Scanning included file: %s"
+msgstr "Examen des fichiers inclus : %s"
+
+#, c-format
+msgid "Searching included file %s"
+msgstr "Recherche du fichier inclus %s"
+
+msgid "E387: Match is on current line"
+msgstr "E387: La correspondance est sur la ligne courante"
+
+msgid "All included files were found"
+msgstr "Tous les fichiers inclus ont été trouvés"
+
+msgid "No included files"
+msgstr "Aucun fichier inclus"
+
+msgid "E388: Couldn't find definition"
+msgstr "E388: Impossible de trouver la définition"
+
+msgid "E389: Couldn't find pattern"
+msgstr "E389: Impossible de trouver le motif"
+
+msgid "Substitute "
+msgstr "Substitue "
+
+#, c-format
+msgid ""
+"\n"
+"# Last %sSearch Pattern:\n"
+"~"
+msgstr ""
+"\n"
+"# Dernier motif de recherche %s :\n"
+"~"
+
+msgid "E756: Spell checking is not enabled"
+msgstr "E756: La vérification orthographique n'est pas activée"
+
+#, c-format
+msgid "Warning: Cannot find word list \"%s_%s.spl\" or \"%s_ascii.spl\""
+msgstr "Alerte : Liste de mots \"%s_%s.spl\" ou \"%s_ascii.spl\" introuvable"
+
+#, c-format
+msgid "Warning: Cannot find word list \"%s.%s.spl\" or \"%s.ascii.spl\""
+msgstr "Alerte : Liste de mots \"%s.%s.spl\" ou \"%s.ascii.spl\" introuvable"
+
+msgid "E797: SpellFileMissing autocommand deleted buffer"
+msgstr "E797: L'autocommande SpellFileMissing a effacé le tampon"
+
+#, c-format
+msgid "Warning: region %s not supported"
+msgstr "Alerte : région %s non supportée"
+
+msgid "Sorry, no suggestions"
+msgstr "Désolé, aucune suggestion"
+
+#, c-format
+msgid "Sorry, only %ld suggestions"
+msgstr "Désolé, seulement %ld suggestions"
+
+#, c-format
+msgid "Change \"%.*s\" to:"
+msgstr "Remplacer \"%.*s\" par :"
+
+# DB - todo : l'intérêt de traduire ce message m'échappe.
+#, c-format
+msgid " < \"%.*s\""
+msgstr " < \"%.*s\""
+
+msgid "E752: No previous spell replacement"
+msgstr "E752: Pas de suggestion orthographique précédente"
+
+#, c-format
+msgid "E753: Not found: %s"
+msgstr "E753: Introuvable : %s"
+
+msgid "E758: Truncated spell file"
+msgstr "E758: Fichier orthographique tronqué"
+
+#, c-format
+msgid "Trailing text in %s line %d: %s"
+msgstr "Texte en trop dans %s ligne %d : %s"
+
+#, c-format
+msgid "Affix name too long in %s line %d: %s"
+msgstr "Nom d'affixe trop long dans %s ligne %d : %s"
+
+msgid "E761: Format error in affix file FOL, LOW or UPP"
+msgstr "E761: Erreur de format dans le fichier d'affixe FOL, LOW et UPP"
+
+msgid "E762: Character in FOL, LOW or UPP is out of range"
+msgstr "E762: Un caractère dans FOL, LOW ou UPP est hors-limites"
+
+msgid "Compressing word tree..."
+msgstr "Compression de l'arbre des mots"
+
+#, c-format
+msgid "Reading spell file \"%s\""
+msgstr "Lecture du fichier orthographique \"%s\""
+
+msgid "E757: This does not look like a spell file"
+msgstr "E757: Le fichier ne ressemble pas à un fichier orthographique"
+
+msgid "E771: Old spell file, needs to be updated"
+msgstr "E771: Fichier orthographique obsolète, sa mise à jour est nécessaire"
+
+msgid "E772: Spell file is for newer version of Vim"
+msgstr "E772: Le fichier est prévu pour une version de Vim plus récente"
+
+msgid "E770: Unsupported section in spell file"
+msgstr "E770: Section non supportée dans le fichier orthographique"
+
+#, c-format
+msgid "E778: This does not look like a .sug file: %s"
+msgstr "E778: %s ne semble pas être un fichier .sug"
+
+#, c-format
+msgid "E779: Old .sug file, needs to be updated: %s"
+msgstr "E779: Fichier de suggestions obsolète, mise à jour nécessaire : %s"
+
+#, c-format
+msgid "E780: .sug file is for newer version of Vim: %s"
+msgstr "E780: Fichier .sug prévu pour une version de Vim plus récente : %s"
+
+#, c-format
+msgid "E781: .sug file doesn't match .spl file: %s"
+msgstr "E781: Le fichier .sug ne correspond pas au fichier .spl : %s"
+
+#, c-format
+msgid "E782: error while reading .sug file: %s"
+msgstr "E782: Erreur lors de la lecture de fichier de suggestions : %s"
+
+#, c-format
+msgid "Reading affix file %s..."
+msgstr "Lecture du fichier d'affixes %s..."
+
+#, c-format
+msgid "Conversion failure for word in %s line %d: %s"
+msgstr "Échec de conversion du mot dans %s ligne %d : %s"
+
+#, c-format
+msgid "Conversion in %s not supported: from %s to %s"
+msgstr "La conversion dans %s non supportée : de %s vers %s"
+
+#, c-format
+msgid "Conversion in %s not supported"
+msgstr "La conversion dans %s non supportée"
+
+#, c-format
+msgid "Invalid value for FLAG in %s line %d: %s"
+msgstr "Valeur de FLAG invalide dans %s ligne %d : %s"
+
+#, c-format
+msgid "FLAG after using flags in %s line %d: %s"
+msgstr "FLAG trouvé après des drapeaux dans %s ligne %d : %s"
+
+#, c-format
+msgid ""
+"Defining COMPOUNDFORBIDFLAG after PFX item may give wrong results in %s line "
+"%d"
+msgstr ""
+"Définir COMPOUNDFORBIDFLAG après des PFX peut donner des résultats erronés "
+"dans %s ligne %d"
+
+#, c-format
+msgid ""
+"Defining COMPOUNDPERMITFLAG after PFX item may give wrong results in %s line "
+"%d"
+msgstr ""
+"Définir COMPOUNDPERMITFLAG après des PFX peut donner des résultats erronés "
+"dans %s ligne %d"
+
+#, c-format
+msgid "Wrong COMPOUNDRULES value in %s line %d: %s"
+msgstr "Valeur de COMPOUNDRULES erronée dans %s ligne %d : %s"
+
+#, c-format
+msgid "Wrong COMPOUNDWORDMAX value in %s line %d: %s"
+msgstr "Valeur de COMPOUNDWORDMAX erronée dans %s ligne %d : %s"
+
+#, c-format
+msgid "Wrong COMPOUNDMIN value in %s line %d: %s"
+msgstr "Valeur de COMPOUNDMIN erronée dans %s ligne %d : %s"
+
+#, c-format
+msgid "Wrong COMPOUNDSYLMAX value in %s line %d: %s"
+msgstr "Valeur de COMPOUNDSYLMAX erronée dans %s ligne %d : %s"
+
+#, c-format
+msgid "Wrong CHECKCOMPOUNDPATTERN value in %s line %d: %s"
+msgstr "Valeur de CHECKCOMPOUNDPATTERN erronée dans %s ligne %d : %s"
+
+# DB - TODO
+#, c-format
+msgid "Different combining flag in continued affix block in %s line %d: %s"
+msgstr ""
+"Drapeaux de composition différents dans un bloc d'affixes continu dans %s "
+"ligne %d : %s"
+
+#, c-format
+msgid "Duplicate affix in %s line %d: %s"
+msgstr "Affixe dupliqué dans %s ligne %d : %s"
+
+#, c-format
+msgid ""
+"Affix also used for BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST in %s "
+"line %d: %s"
+msgstr ""
+"Affixe aussi utilisée pour BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/"
+"NOSUGGEST dans %s ligne %d : %s"
+
+#, c-format
+msgid "Expected Y or N in %s line %d: %s"
+msgstr "Y ou N attendu dans %s ligne %d : %s"
+
+# DB - todo (regexp impossible à compiler...)
+#, c-format
+msgid "Broken condition in %s line %d: %s"
+msgstr "Condition non valide dans %s ligne %d : %s"
+
+#, c-format
+msgid "Expected REP(SAL) count in %s line %d"
+msgstr "Nombre de REP(SAL) attendu dans %s ligne %d"
+
+#, c-format
+msgid "Expected MAP count in %s line %d"
+msgstr "Nombre de MAP attendu dans %s ligne %d"
+
+#, c-format
+msgid "Duplicate character in MAP in %s line %d"
+msgstr "Caractère dupliqué dans MAP dans %s ligne %d"
+
+#, c-format
+msgid "Unrecognized or duplicate item in %s line %d: %s"
+msgstr "Élément non reconnu ou dupliqué dans %s ligne %d : %s"
+
+#, c-format
+msgid "Missing FOL/LOW/UPP line in %s"
+msgstr "Ligne FOL/LOW/UPP manquante dans %s"
+
+msgid "COMPOUNDSYLMAX used without SYLLABLE"
+msgstr "Utilisation de COMPOUNDSYLMAX sans SYLLABLE"
+
+msgid "Too many postponed prefixes"
+msgstr "Trop de préfixes reportés (PFXPOSTPONE)"
+
+msgid "Too many compound flags"
+msgstr "Trop de drapeaux de composition"
+
+msgid "Too many postponed prefixes and/or compound flags"
+msgstr "Trop de préfixes reportés et/ou de drapeaux de composition"
+
+#, c-format
+msgid "Missing SOFO%s line in %s"
+msgstr "Ligne SOFO%s manquante dans %s"
+
+#, c-format
+msgid "Both SAL and SOFO lines in %s"
+msgstr "Lignes SAL et lignes SOFO présentes dans %s"
+
+#, c-format
+msgid "Flag is not a number in %s line %d: %s"
+msgstr "Le drapeau n'est pas un nombre dans %s ligne %d : %s"
+
+#, c-format
+msgid "Illegal flag in %s line %d: %s"
+msgstr "Drapeau non autorisé dans %s ligne %d : %s"
+
+#, c-format
+msgid "%s value differs from what is used in another .aff file"
+msgstr "La valeur de %s est différente de celle d'un autre fichier .aff"
+
+#, c-format
+msgid "Reading dictionary file %s..."
+msgstr "Lecture du fichier orthographique %s..."
+
+#, c-format
+msgid "E760: No word count in %s"
+msgstr "E760: Nombre de mots non indiqué dans %s"
+
+#, c-format
+msgid "line %6d, word %6ld - %s"
+msgstr "ligne %6d, mot %6ld - %s"
+
+#, c-format
+msgid "Duplicate word in %s line %d: %s"
+msgstr "Mot dupliqué dans %s ligne %d : %s"
+
+#, c-format
+msgid "First duplicate word in %s line %d: %s"
+msgstr "Premier mot dupliqué dans %s ligne %d : %s"
+
+#, c-format
+msgid "%d duplicate word(s) in %s"
+msgstr "%d mot(s) dupliqué(s) dans %s"
+
+#, c-format
+msgid "Ignored %d word(s) with non-ASCII characters in %s"
+msgstr "%d mot(s) ignoré(s) avec des caractères non-ASCII dans %s"
+
+#, c-format
+msgid "Reading word file %s..."
+msgstr "Lecture de la liste de mots %s..."
+
+#, c-format
+msgid "Duplicate /encoding= line ignored in %s line %d: %s"
+msgstr "Ligne /encoding= en double ignorée dans %s ligne %d : %s"
+
+#, c-format
+msgid "/encoding= line after word ignored in %s line %d: %s"
+msgstr "Ligne /encoding= après des mots ignorée dans %s ligne %d : %s"
+
+#, c-format
+msgid "Duplicate /regions= line ignored in %s line %d: %s"
+msgstr "Ligne /regions= en double ignorée dans %s ligne %d : %s"
+
+#, c-format
+msgid "Too many regions in %s line %d: %s"
+msgstr "Trop de régions dans %s ligne %d : %s"
+
+#, c-format
+msgid "/ line ignored in %s line %d: %s"
+msgstr "Ligne / ignorée dans %s ligne %d : %s"
+
+#, c-format
+msgid "Invalid region nr in %s line %d: %s"
+msgstr "Numéro de région invalide dans %s ligne %d : %s"
+
+#, c-format
+msgid "Unrecognized flags in %s line %d: %s"
+msgstr "Drapeaux non reconnus dans %s ligne %d : %s"
+
+#, c-format
+msgid "Ignored %d words with non-ASCII characters"
+msgstr "%d mot(s) ignoré(s) avec des caractères non-ASCII"
+
+msgid "E845: Insufficient memory, word list will be incomplete"
+msgstr "E845: mémoire insuffisante, liste de mots peut-être incomplète"
+
+#, c-format
+msgid "Compressed %d of %d nodes; %d (%d%%) remaining"
+msgstr "%d noeuds compressés sur %d ; %d (%d%%) restants "
+
+msgid "Reading back spell file..."
+msgstr "Relecture du fichier orthographique"
+
+msgid "Performing soundfolding..."
+msgstr "Analyse phonétique en cours..."
+
+#, c-format
+msgid "Number of words after soundfolding: %ld"
+msgstr "Nombre de mots après l'analyse phonétique : %ld"
+
+#, c-format
+msgid "Total number of words: %d"
+msgstr "Nombre total de mots : %d"
+
+#, c-format
+msgid "Writing suggestion file %s..."
+msgstr "Écriture du fichier de suggestions %s..."
+
+#, c-format
+msgid "Estimated runtime memory use: %d bytes"
+msgstr "Estimation de mémoire consommée : %d octets"
+
+msgid "E751: Output file name must not have region name"
+msgstr "E751: Le nom du fichier ne doit pas contenir de nom de région"
+
+#, c-format
+msgid "E754: Only up to %ld regions supported"
+msgstr "E754: %ld régions au maximum supportées"
+
+#, c-format
+msgid "E755: Invalid region in %s"
+msgstr "E755: Région invalide dans %s"
+
+msgid "Warning: both compounding and NOBREAK specified"
+msgstr "Alerte : la composition et NOBREAK sont tous les deux spécifiés"
+
+#, c-format
+msgid "Writing spell file %s..."
+msgstr "Écriture du fichier orthographique %s..."
+
+msgid "Done!"
+msgstr "Terminé !"
+
+# DB - todo : perfectible.
+#, c-format
+msgid "E765: 'spellfile' does not have %ld entries"
+msgstr "E765: 'spellfile' n'a pas %ld entrées"
+
+#, c-format
+msgid "Word '%.*s' removed from %s"
+msgstr "Mot '%.*s' retiré de %s"
+
+#, c-format
+msgid "Word '%.*s' added to %s"
+msgstr "Mot '%.*s' ajouté dans %s"
+
+msgid "E763: Word characters differ between spell files"
+msgstr ""
+"E763: Les caractères de mots diffèrent entre les fichiers orthographiques"
+
+msgid "E783: duplicate char in MAP entry"
+msgstr "E783: caractère dupliqué dans l'entrée MAP"
+
+msgid "No Syntax items defined for this buffer"
+msgstr "Aucun élément de syntaxe défini pour ce tampon"
+
+msgid "'redrawtime' exceeded, syntax highlighting disabled"
+msgstr "'redrawtime' écoulé, surbrillance de syntaxe désactivée"
+
+msgid "syntax conceal on"
+msgstr "\"syntax conceal\" activée"
+
+msgid "syntax conceal off"
+msgstr "\"syntax conceal\" désactivée"
+
+#, c-format
+msgid "E390: Illegal argument: %s"
+msgstr "E390: Argument invalide : %s"
+
+msgid "syntax case ignore"
+msgstr "syntaxe ignore la casse"
+
+msgid "syntax case match"
+msgstr "syntaxe respecte la casse"
+
+msgid "syntax spell toplevel"
+msgstr "contrôle orthographique dans le texte sans groupe syntaxique"
+
+msgid "syntax spell notoplevel"
+msgstr "pas de contrôle orthographique dans le texte sans groupe syntaxique"
+
+msgid "syntax spell default"
+msgstr ""
+"contrôle orthographique dans le texte sans groupe syntaxique, sauf si @Spell/"
+"@NoSpell"
+
+msgid "syntax iskeyword "
+msgstr "syntaxe iskeyword "
+
+msgid "syntax iskeyword not set"
+msgstr "iskeyword n'est pas activé"
+
+#, c-format
+msgid "E391: No such syntax cluster: %s"
+msgstr "E391: Aucune grappe de syntaxe %s"
+
+msgid "syncing on C-style comments"
+msgstr "synchronisation sur les commentaires de type C"
+
+msgid "no syncing"
+msgstr "Aucune synchronisation"
+
+# DB - Les deux messages qui suivent vont ensemble.
+msgid "syncing starts "
+msgstr "La synchronisation débute "
+
+msgid " lines before top line"
+msgstr " lignes avant la ligne du haut"
+
+msgid ""
+"\n"
+"--- Syntax sync items ---"
+msgstr ""
+"\n"
+"--- Éléments de synchronisation syntaxique ---"
+
+msgid ""
+"\n"
+"syncing on items"
+msgstr ""
+"\n"
+"synchronisation sur éléments"
+
+msgid ""
+"\n"
+"--- Syntax items ---"
+msgstr ""
+"\n"
+"--- Éléments de syntaxe ---"
+
+#, c-format
+msgid "E392: No such syntax cluster: %s"
+msgstr "E392: Aucune grappe de syntaxe %s"
+
+msgid "minimal "
+msgstr "minimum "
+
+msgid "maximal "
+msgstr "maximum "
+
+# DB - todo
+msgid "; match "
+msgstr "; correspond avec "
+
+# DB - todo
+msgid " line breaks"
+msgstr " coupures de ligne"
+
+msgid "E395: contains argument not accepted here"
+msgstr "E395: L'argument « contains » n'est pas accepté ici"
+
+msgid "E844: invalid cchar value"
+msgstr "E844: valeur de cchar invalide"
+
+msgid "E393: group[t]here not accepted here"
+msgstr "E393: L'argument « group[t]here » n'est pas accepté ici"
+
+#, c-format
+msgid "E394: Didn't find region item for %s"
+msgstr "E394: Aucun élément de type région trouvé pour %s"
+
+msgid "E397: Filename required"
+msgstr "E397: Nom de fichier requis"
+
+msgid "E847: Too many syntax includes"
+msgstr "E847: Trop d'inclusions de syntaxe"
+
+#, c-format
+msgid "E789: Missing ']': %s"
+msgstr "E789: ']' manquant : %s"
+
+#, c-format
+msgid "E890: trailing char after ']': %s]%s"
+msgstr "E890: Caractère surnuméraire après ']': %s]%s"
+
+#, c-format
+msgid "E398: Missing '=': %s"
+msgstr "E398: '=' manquant : %s"
+
+#, c-format
+msgid "E399: Not enough arguments: syntax region %s"
+msgstr "E399: Pas assez d'arguments : syntax region %s"
+
+msgid "E848: Too many syntax clusters"
+msgstr "E848: Trop de grappes de syntaxe"
+
+msgid "E400: No cluster specified"
+msgstr "E400: Aucune grappe spécifiée"
+
+#, c-format
+msgid "E401: Pattern delimiter not found: %s"
+msgstr "E401: Délimiteur de motif introuvable : %s"
+
+#, c-format
+msgid "E402: Garbage after pattern: %s"
+msgstr "E402: caractères en trop après le motif : %s"
+
+msgid "E403: syntax sync: line continuations pattern specified twice"
+msgstr ""
+"E403: synchro syntax : motif de continuation de ligne présent deux fois"
+
+#, c-format
+msgid "E404: Illegal arguments: %s"
+msgstr "E404: Arguments invalides : %s"
+
+#, c-format
+msgid "E405: Missing equal sign: %s"
+msgstr "E405: '=' manquant : %s"
+
+#, c-format
+msgid "E406: Empty argument: %s"
+msgstr "E406: Argument vide : %s"
+
+#, c-format
+msgid "E407: %s not allowed here"
+msgstr "E407: %s n'est pas autorisé ici"
+
+#, c-format
+msgid "E408: %s must be first in contains list"
+msgstr "E408: %s doit être le premier élément d'une liste « contains »"
+
+#, c-format
+msgid "E409: Unknown group name: %s"
+msgstr "E409: Nom de groupe inconnu : %s"
+
+#, c-format
+msgid "E410: Invalid :syntax subcommand: %s"
+msgstr "E410: Sous-commande de :syntax invalide : %s"
+
+msgid ""
+" TOTAL COUNT MATCH SLOWEST AVERAGE NAME PATTERN"
+msgstr ""
+" TOTAL NOMBRE MATCH PLUS LENT MOYEN NOM MOTIF"
+
+msgid "E679: recursive loop loading syncolor.vim"
+msgstr "E679: boucle récursive lors du chargement de syncolor.vim"
+
+#, c-format
+msgid "E411: highlight group not found: %s"
+msgstr "E411: groupe de surbrillance introuvable : %s"
+
+#, c-format
+msgid "E412: Not enough arguments: \":highlight link %s\""
+msgstr "E412: Trop peu d'arguments : \":highlight link %s\""
+
+#, c-format
+msgid "E413: Too many arguments: \":highlight link %s\""
+msgstr "E413: Trop d'arguments : \":highlight link %s\""
+
+msgid "E414: group has settings, highlight link ignored"
+msgstr "E414: le groupe a déjà des attributs, lien de surbrillance ignoré"
+
+#, c-format
+msgid "E415: unexpected equal sign: %s"
+msgstr "E415: signe égal inattendu : %s"
+
+#, c-format
+msgid "E416: missing equal sign: %s"
+msgstr "E416: '=' manquant : %s"
+
+#, c-format
+msgid "E417: missing argument: %s"
+msgstr "E417: argument manquant : %s"
+
+#, c-format
+msgid "E418: Illegal value: %s"
+msgstr "E418: Valeur invalide : %s"
+
+msgid "E419: FG color unknown"
+msgstr "E419: Couleur de premier plan inconnue"
+
+msgid "E420: BG color unknown"
+msgstr "E420: Couleur d'arrière-plan inconnue"
+
+#, c-format
+msgid "E421: Color name or number not recognized: %s"
+msgstr "E421: Nom ou numéro de couleur non reconnu : %s"
+
+#, c-format
+msgid "E422: terminal code too long: %s"
+msgstr "E422: le code de terminal est trop long : %s"
+
+#, c-format
+msgid "E423: Illegal argument: %s"
+msgstr "E423: Argument invalide : %s"
+
+msgid "E424: Too many different highlighting attributes in use"
+msgstr ""
+"E424: Trop d'attributs de surbrillance différents en cours d'utilisation"
+
+msgid "E669: Unprintable character in group name"
+msgstr "E669: Caractère non-imprimable dans un nom de groupe"
+
+msgid "W18: Invalid character in group name"
+msgstr "W18: Caractère invalide dans un nom de groupe"
+
+msgid "E849: Too many highlight and syntax groups"
+msgstr "E849: Trop de groupes de surbrillance et de syntaxe"
+
+msgid "E555: at bottom of tag stack"
+msgstr "E555: En bas de la pile de marqueurs"
+
+msgid "E556: at top of tag stack"
+msgstr "E556: Au sommet de la pile de marqueurs"
+
+msgid "E425: Cannot go before first matching tag"
+msgstr "E425: Impossible d'aller avant le premier marqueur correspondant"
+
+#, c-format
+msgid "E426: tag not found: %s"
+msgstr "E426: Marqueur introuvable : %s"
+
+msgid " # pri kind tag"
+msgstr " # pri type marqueur"
+
+msgid "file\n"
+msgstr "fichier\n"
+
+msgid "E427: There is only one matching tag"
+msgstr "E427: Il n'y a qu'un marqueur correspondant"
+
+msgid "E428: Cannot go beyond last matching tag"
+msgstr "E428: Impossible d'aller au-delà du dernier marqueur correspondant"
+
+#, c-format
+msgid "File \"%s\" does not exist"
+msgstr "Le fichier \"%s\" n'existe pas"
+
+#, c-format
+msgid "tag %d of %d%s"
+msgstr "marqueur %d sur %d%s"
+
+msgid " or more"
+msgstr " ou plus"
+
+msgid " Using tag with different case!"
+msgstr " Utilisation d'un marqueur avec une casse différente !"
+
+#, c-format
+msgid "E429: File \"%s\" does not exist"
+msgstr "E429: Le fichier \"%s\" n'existe pas"
+
+msgid ""
+"\n"
+" # TO tag FROM line in file/text"
+msgstr ""
+"\n"
+" # VERS marqueur DE ligne dans le fichier/texte"
+
+#, c-format
+msgid "Searching tags file %s"
+msgstr "Examen du fichier de marqueurs %s"
+
+#, c-format
+msgid "E430: Tag file path truncated for %s\n"
+msgstr "E430: Chemin de fichiers de marqueurs tronqué pour %s\n"
+
+msgid "Ignoring long line in tags file"
+msgstr "Ignore longue ligne dans le fichier de marqueurs"
+
+#, c-format
+msgid "E431: Format error in tags file \"%s\""
+msgstr "E431: Erreur de format dans le fichier de marqueurs \"%s\""
+
+#, c-format
+msgid "Before byte %ld"
+msgstr "Avant l'octet %ld"
+
+#, c-format
+msgid "E432: Tags file not sorted: %s"
+msgstr "E432: Le fichier de marqueurs %s n'est pas ordonné"
+
+msgid "E433: No tags file"
+msgstr "E433: Aucun fichier de marqueurs"
+
+msgid "E434: Can't find tag pattern"
+msgstr "E434: Le motif de marqueur est introuvable"
+
+msgid "E435: Couldn't find tag, just guessing!"
+msgstr "E435: Marqueur introuvable, tentative pour deviner !"
+
+#, c-format
+msgid "Duplicate field name: %s"
+msgstr "Nom de champ dupliqué : %s"
+
+msgid "' not known. Available builtin terminals are:"
+msgstr "' inconnu. Les terminaux intégrés sont :"
+
+msgid "defaulting to '"
+msgstr "utilisation par défaut de '"
+
+msgid "E557: Cannot open termcap file"
+msgstr "E557: Impossible d'ouvrir le fichier termcap"
+
+msgid "E558: Terminal entry not found in terminfo"
+msgstr "E558: La description du terminal est introuvable dans terminfo"
+
+msgid "E559: Terminal entry not found in termcap"
+msgstr "E559: La description du terminal est introuvable dans termcap"
+
+#, c-format
+msgid "E436: No \"%s\" entry in termcap"
+msgstr "E436: Aucune entrée \"%s\" dans termcap"
+
+# DB - todo : Comment améliorer ?
+msgid "E437: terminal capability \"cm\" required"
+msgstr "E437: capacité de terminal \"cm\" requise"
+
+msgid ""
+"\n"
+"--- Terminal keys ---"
+msgstr ""
+"\n"
+"--- Touches du terminal ---"
+
+msgid "Cannot open $VIMRUNTIME/rgb.txt"
+msgstr "Impossible d'ouvrir $VIMRUNTIME/rgb.txt"
+
+#, c-format
+msgid "Kill job in \"%s\"?"
+msgstr "Terminer la tâche d'exécution dans \"%s\"?"
+
+msgid "Terminal"
+msgstr "Terminal"
+
+msgid "Terminal-finished"
+msgstr "Terminal-fini"
+
+msgid "active"
+msgstr "actif"
+
+msgid "running"
+msgstr "en cours"
+
+msgid "finished"
+msgstr "fini"
+
+msgid "E958: Job already finished"
+msgstr "E958: Tâche déjà finie"
+
+#, c-format
+msgid "E953: File exists: %s"
+msgstr "E953: Le fichier existe déjà : %s"
+
+msgid "E955: Not a terminal buffer"
+msgstr "E955: Ce n'est pas un buffer de terminal"
+
+msgid "new shell started\n"
+msgstr "nouveau shell démarré\n"
+
+msgid "Vim: Error reading input, exiting...\n"
+msgstr "Vim : Erreur lors de la lecture de l'entrée, sortie...\n"
+
+# DB - Message de débogage.
+msgid "Used CUT_BUFFER0 instead of empty selection"
+msgstr "CUT_BUFFER0 utilisé plutôt qu'une sélection vide"
+
+msgid "E881: Line count changed unexpectedly"
+msgstr "E881: Le nombre de lignes a été changé inopinément"
+
+# DB - Question O/N.
+msgid "No undo possible; continue anyway"
+msgstr "Annulation impossible ; continuer"
+
+#, c-format
+msgid "E828: Cannot open undo file for writing: %s"
+msgstr "E828: Impossible d'ouvrir le fichier d'annulations en écriture : %s"
+
+#, c-format
+msgid "E825: Corrupted undo file (%s): %s"
+msgstr "E825: Fichier d'annulations corrompu (%s) : %s"
+
+msgid "Cannot write undo file in any directory in 'undodir'"
+msgstr ""
+"Impossible d'écrire le fichier d'annulations dans n'importe quel répertoire "
+"de 'undodir'"
+
+#, c-format
+msgid "Will not overwrite with undo file, cannot read: %s"
+msgstr "Le fichier d'annulations ne sera pas écrasé, impossible de lire : %s"
+
+#, c-format
+msgid "Will not overwrite, this is not an undo file: %s"
+msgstr "Fichier ne sera pas écrasé, ce n'est pas un fichier d'annulations : %s"
+
+msgid "Skipping undo file write, nothing to undo"
+msgstr "Le fichier d'annulations n'est pas écrit, rien à annuler"
+
+#, c-format
+msgid "Writing undo file: %s"
+msgstr "Écriture du fichier d'annulations : %s"
+
+#, c-format
+msgid "E829: write error in undo file: %s"
+msgstr "E829: Erreur d'écriture dans le fichier d'annulations : %s"
+
+#, c-format
+msgid "Not reading undo file, owner differs: %s"
+msgstr "Le fichier d'annulations n'est pas lu, propriétaire différent : %s"
+
+#, c-format
+msgid "Reading undo file: %s"
+msgstr "Lecture du fichier d'annulations : %s..."
+
+#, c-format
+msgid "E822: Cannot open undo file for reading: %s"
+msgstr "E822: Impossible d'ouvrir le fichier d'annulations en lecture : %s"
+
+#, c-format
+msgid "E823: Not an undo file: %s"
+msgstr "E823: Ce n'est pas un fichier d'annulations : %s"
+
+#, c-format
+msgid "E832: Non-encrypted file has encrypted undo file: %s"
+msgstr "E832: Fichier non-chiffré a un fichier d'annulations chiffré : %s"
+
+#, c-format
+msgid "E826: Undo file decryption failed: %s"
+msgstr "E826: Déchiffrage du fichier d'annulation a échoué : %s"
+
+#, c-format
+msgid "E827: Undo file is encrypted: %s"
+msgstr "E827: Le fichier d'annulations est chiffré : %s"
+
+#, c-format
+msgid "E824: Incompatible undo file: %s"
+msgstr "E824: Fichier d'annulations incompatible : %s"
+
+msgid "File contents changed, cannot use undo info"
+msgstr ""
+"Le contenu du fichier a changé, impossible d'utiliser les informations "
+"d'annulation"
+
+#, c-format
+msgid "Finished reading undo file %s"
+msgstr "Fin de lecture du fichier d'annulations %s"
+
+msgid "Already at oldest change"
+msgstr "Déjà à la modification la plus ancienne"
+
+msgid "Already at newest change"
+msgstr "Déjà à la modification la plus récente"
+
+#, c-format
+msgid "E830: Undo number %ld not found"
+msgstr "E830: Annulation n° %ld introuvable"
+
+msgid "E438: u_undo: line numbers wrong"
+msgstr "E438: u_undo : numéros de ligne erronés"
+
+msgid "more line"
+msgstr "ligne en plus"
+
+msgid "more lines"
+msgstr "lignes en plus"
+
+msgid "line less"
+msgstr "ligne en moins"
+
+msgid "fewer lines"
+msgstr "lignes en moins"
+
+msgid "change"
+msgstr "modification"
+
+msgid "changes"
+msgstr "modifications"
+
+#, c-format
+msgid "%ld %s; %s #%ld %s"
+msgstr "%ld %s ; %s #%ld ; %s"
+
+msgid "before"
+msgstr "avant"
+
+msgid "after"
+msgstr "après"
+
+msgid "Nothing to undo"
+msgstr "Rien à annuler"
+
+# DB - Les deux premières colonnes sont alignées à droite.
+msgid "number changes when saved"
+msgstr "numéro modif. instant enregistré"
+
+#, c-format
+msgid "%ld second ago"
+msgid_plural "%ld seconds ago"
+msgstr[0] "il y a %ld seconde"
+msgstr[1] "il y a %ld secondes"
+
+msgid "E790: undojoin is not allowed after undo"
+msgstr "E790: undojoin n'est pas autorisé après une annulation"
+
+msgid "E439: undo list corrupt"
+msgstr "E439: la liste d'annulation est corrompue"
+
+msgid "E440: undo line missing"
+msgstr "E440: ligne d'annulation manquante"
+
+#, c-format
+msgid "E122: Function %s already exists, add ! to replace it"
+msgstr "E122: La fonction %s existe déjà (ajoutez ! pour la remplacer)"
+
+msgid "E717: Dictionary entry already exists"
+msgstr "E717: Une entrée du Dictionnaire porte déjà ce nom"
+
+msgid "E718: Funcref required"
+msgstr "E718: Référence de fonction (Funcref) requise"
+
+#, c-format
+msgid "E130: Unknown function: %s"
+msgstr "E130: Fonction inconnue : %s"
+
+#, c-format
+msgid "E125: Illegal argument: %s"
+msgstr "E125: Argument invalide : %s"
+
+#, c-format
+msgid "E853: Duplicate argument name: %s"
+msgstr "E853: Nom d'argument dupliqué : %s"
+
+#, c-format
+msgid "E740: Too many arguments for function %s"
+msgstr "E740: Trop d'arguments pour la fonction %s"
+
+#, c-format
+msgid "E116: Invalid arguments for function %s"
+msgstr "E116: Arguments invalides pour la fonction %s"
+
+# AB - Vérifier dans la littérature technique s'il n'existe pas une meilleure
+# traduction pour "function call depth".
+msgid "E132: Function call depth is higher than 'maxfuncdepth'"
+msgstr ""
+"E132: La profondeur d'appel de fonction est supérieure à 'maxfuncdepth'"
+
+# AB - Ce texte fait partie d'un message de débogage.
+#, c-format
+msgid "calling %s"
+msgstr "appel de %s"
+
+# AB - Vérifier.
+#, c-format
+msgid "%s aborted"
+msgstr "%s annulée"
+
+# AB - Ce texte fait partie d'un message de débogage.
+#, c-format
+msgid "%s returning #%ld"
+msgstr "%s a retourné #%ld"
+
+# AB - Ce texte fait partie d'un message de débogage.
+#, c-format
+msgid "%s returning %s"
+msgstr "%s a retourné \"%s\""
+
+msgid "E699: Too many arguments"
+msgstr "E699: Trop d'arguments"
+
+#, c-format
+msgid "E117: Unknown function: %s"
+msgstr "E117: Fonction inconnue : %s"
+
+#, c-format
+msgid "E933: Function was deleted: %s"
+msgstr "E933: La fonction a été effacée: %s"
+
+#, c-format
+msgid "E119: Not enough arguments for function: %s"
+msgstr "E119: La fonction %s n'a pas reçu assez d'arguments"
+
+#, c-format
+msgid "E120: Using <SID> not in a script context: %s"
+msgstr "E120: <SID> utilisé en dehors d'un script : %s"
+
+#, c-format
+msgid "E725: Calling dict function without Dictionary: %s"
+msgstr "E725: Appel d'une fonction « dict » sans Dictionnaire : %s"
+
+msgid "E129: Function name required"
+msgstr "E129: Nom de fonction requis"
+
+#, c-format
+msgid "E128: Function name must start with a capital or \"s:\": %s"
+msgstr ""
+"E128: Le nom de la fonction doit commencer par une majuscule ou \"s:\": %s"
+
+#, c-format
+msgid "E884: Function name cannot contain a colon: %s"
+msgstr ""
+"E884: Le nom de la fonction ne peut pas contenir le caractère deux-points : "
+"%s"
+
+#, c-format
+msgid "E123: Undefined function: %s"
+msgstr "E123: Fonction non définie : %s"
+
+# AB - La version française est plus consistante que la version anglaise.
+# AB - Je suis partagé entre la concision d'une traduction assez littérale et
+# la lourdeur d'une traduction plus correcte.
+#, c-format
+msgid "E124: Missing '(': %s"
+msgstr "E124: Il manque '(' après %s"
+
+msgid "E862: Cannot use g: here"
+msgstr "E862: Impossible d'utiliser g: ici"
+
+#, c-format
+msgid "E932: Closure function should not be at top level: %s"
+msgstr ""
+"E932: une fonction fermeture ne devrait pas être au niveau principal : %s"
+
+msgid "E126: Missing :endfunction"
+msgstr "E126: Il manque :endfunction"
+
+#, c-format
+msgid "W22: Text found after :endfunction: %s"
+msgstr "W22: Texte trouvé après :endfunction: %s"
+
+#, c-format
+msgid "E707: Function name conflicts with variable: %s"
+msgstr "E707: Le nom de fonction entre en conflit avec la variable : %s"
+
+#, c-format
+msgid "E127: Cannot redefine function %s: It is in use"
+msgstr "E127: Impossible de redéfinir fonction %s : déjà utilisée"
+
+# DB - Le contenu du "c-format" est le nom de la fonction.
+#, c-format
+msgid "E746: Function name does not match script file name: %s"
+msgstr "E746: Le nom de la fonction %s ne correspond pas le nom du script"
+
+# AB - Il est difficile de créer une version française qui fasse moins de 80
+# caractères de long, nom de la fonction compris : "It is in use" est une
+# expression très dense. Traductions possibles : "elle est utilisée",
+# "elle s'exécute" ou "elle est occupée".
+#, c-format
+msgid "E131: Cannot delete function %s: It is in use"
+msgstr "E131: Impossible d'effacer %s : cette fonction est utilisée"
+
+msgid "E133: :return not inside a function"
+msgstr "E133: :return en dehors d'une fonction"
+
+#, c-format
+msgid "E107: Missing parentheses: %s"
+msgstr "E107: Parenthèses manquantes : %s"
+
+#, c-format
+msgid "%s (%s, compiled %s)"
+msgstr "%s (%s, compilé %s)"
+
+msgid ""
+"\n"
+"MS-Windows 64-bit GUI version"
+msgstr ""
+"\n"
+"Version graphique MS-Windows 64 bits"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit GUI version"
+msgstr ""
+"\n"
+"Version graphique MS-Windows 32 bits"
+
+msgid " with OLE support"
+msgstr " supportant l'OLE"
+
+msgid ""
+"\n"
+"MS-Windows 64-bit console version"
+msgstr ""
+"\n"
+"Version console MS-Windows 64 bits"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit console version"
+msgstr ""
+"\n"
+"Version console MS-Windows 32 bits"
+
+msgid ""
+"\n"
+"macOS version"
+msgstr ""
+"\n"
+"Version macOS"
+
+msgid ""
+"\n"
+"macOS version w/o darwin feat."
+msgstr ""
+"\n"
+"Version macOS sans fonctionalités darwin"
+
+msgid ""
+"\n"
+"OpenVMS version"
+msgstr ""
+"\n"
+"Version OpenVMS"
+
+msgid ""
+"\n"
+"Included patches: "
+msgstr ""
+"\n"
+"Rustines incluses : "
+
+msgid ""
+"\n"
+"Extra patches: "
+msgstr ""
+"\n"
+"Rustines extra : "
+
+msgid "Modified by "
+msgstr "Modifié par "
+
+msgid ""
+"\n"
+"Compiled "
+msgstr ""
+"\n"
+"Compilé "
+
+msgid "by "
+msgstr "par "
+
+msgid ""
+"\n"
+"Huge version "
+msgstr ""
+"\n"
+"Énorme version "
+
+msgid ""
+"\n"
+"Big version "
+msgstr ""
+"\n"
+"Grosse version "
+
+msgid ""
+"\n"
+"Normal version "
+msgstr ""
+"\n"
+"Version normale "
+
+msgid ""
+"\n"
+"Small version "
+msgstr ""
+"\n"
+"Petite version "
+
+msgid ""
+"\n"
+"Tiny version "
+msgstr ""
+"\n"
+"Version minuscule "
+
+msgid "without GUI."
+msgstr "sans interface graphique."
+
+msgid "with GTK3 GUI."
+msgstr "avec interface graphique GTK3."
+
+msgid "with GTK2-GNOME GUI."
+msgstr "avec interface graphique GTK2-GNOME."
+
+msgid "with GTK2 GUI."
+msgstr "avec interface graphique GTK2."
+
+msgid "with X11-Motif GUI."
+msgstr "avec interface graphique X11-Motif."
+
+msgid "with X11-neXtaw GUI."
+msgstr "avec interface graphique X11-neXtaw."
+
+msgid "with X11-Athena GUI."
+msgstr "avec interface graphique X11-Athena."
+
+msgid "with Photon GUI."
+msgstr "avec interface graphique Photon."
+
+msgid "with GUI."
+msgstr "avec une interface graphique."
+
+msgid "with Carbon GUI."
+msgstr "avec interface graphique Carbon."
+
+msgid "with Cocoa GUI."
+msgstr "avec interface graphique Cocoa."
+
+msgid " Features included (+) or not (-):\n"
+msgstr " Fonctionnalités incluses (+) ou non (-) :\n"
+
+msgid " system vimrc file: \""
+msgstr " fichier vimrc système : \""
+
+msgid " user vimrc file: \""
+msgstr " fichier vimrc utilisateur : \""
+
+msgid " 2nd user vimrc file: \""
+msgstr " 2me fichier vimrc utilisateur : \""
+
+msgid " 3rd user vimrc file: \""
+msgstr " 3me fichier vimrc utilisateur : \""
+
+msgid " user exrc file: \""
+msgstr " fichier exrc utilisateur : \""
+
+msgid " 2nd user exrc file: \""
+msgstr " 2me fichier exrc utilisateur : \""
+
+msgid " system gvimrc file: \""
+msgstr " fichier gvimrc système : \""
+
+msgid " user gvimrc file: \""
+msgstr " fichier gvimrc utilisateur : \""
+
+msgid "2nd user gvimrc file: \""
+msgstr "2me fichier gvimrc utilisateur : \""
+
+msgid "3rd user gvimrc file: \""
+msgstr "3me fichier gvimrc utilisateur : \""
+
+msgid " defaults file: \""
+msgstr " fichier de valeurs par défaut : \""
+
+msgid " system menu file: \""
+msgstr " fichier menu système : \""
+
+msgid " fall-back for $VIM: \""
+msgstr " $VIM par défaut : \""
+
+msgid " f-b for $VIMRUNTIME: \""
+msgstr " $VIMRUNTIME par défaut : \""
+
+msgid "Compilation: "
+msgstr "Compilation : "
+
+msgid "Compiler: "
+msgstr "Compilateur : "
+
+msgid "Linking: "
+msgstr "Édition de liens : "
+
+msgid " DEBUG BUILD"
+msgstr " VERSION DE DÉBOGAGE"
+
+msgid "VIM - Vi IMproved"
+msgstr "VIM - Vi Amélioré"
+
+msgid "version "
+msgstr "version "
+
+msgid "by Bram Moolenaar et al."
+msgstr "par Bram Moolenaar et al."
+
+msgid "Vim is open source and freely distributable"
+msgstr "Vim est un logiciel libre"
+
+msgid "Help poor children in Uganda!"
+msgstr "Aidez les enfants pauvres d'Ouganda !"
+
+msgid "type :help iccf<Enter> for information "
+msgstr "tapez :help iccf<Entrée> pour plus d'informations "
+
+msgid "type :q<Enter> to exit "
+msgstr "tapez :q<Entrée> pour sortir du programme "
+
+msgid "type :help<Enter> or <F1> for on-line help"
+msgstr "tapez :help<Entrée> ou <F1> pour accéder à l'aide en ligne "
+
+msgid "type :help version8<Enter> for version info"
+msgstr "tapez :help version8<Entrée> pour lire les notes de mise à jour"
+
+# DB - Pour les trois messages qui suivent :
+# :set cp
+# :intro
+msgid "Running in Vi compatible mode"
+msgstr "Compatibilité avec Vi activée"
+
+msgid "type :set nocp<Enter> for Vim defaults"
+msgstr "tapez :set nocp<Entrée> pour la désactiver"
+
+msgid "type :help cp-default<Enter> for info on this"
+msgstr "tapez :help cp-default<Entrée> pour plus d'info"
+
+msgid "menu Help->Orphans for information "
+msgstr "menu Aide->Orphelins pour plus d'info"
+
+msgid "Running modeless, typed text is inserted"
+msgstr "Les modes sont désactivés, le texte saisi est inséré"
+
+msgid "menu Edit->Global Settings->Toggle Insert Mode "
+msgstr "menu Édition->Réglages Globaux->Insertion Permanente"
+
+# DB - todo
+msgid " for two modes "
+msgstr " pour les modes "
+
+# DB - todo
+msgid "menu Edit->Global Settings->Toggle Vi Compatible"
+msgstr "menu Édition->Réglages Globaux->Compatibilité Vi"
+
+# DB - todo
+msgid " for Vim defaults "
+msgstr " pour déf. de Vim "
+
+msgid "Sponsor Vim development!"
+msgstr "Sponsorisez le développement de Vim !"
+
+msgid "Become a registered Vim user!"
+msgstr "Devenez un utilisateur de Vim enregistré !"
+
+msgid "type :help sponsor<Enter> for information "
+msgstr "tapez :help sponsor<Entrée> pour plus d'informations "
+
+msgid "type :help register<Enter> for information "
+msgstr "tapez :help register<Entrée> pour plus d'informations "
+
+msgid "menu Help->Sponsor/Register for information "
+msgstr "menu Aide->Sponsor/Enregistrement pour plus d'info"
+
+msgid "Already only one window"
+msgstr "Il n'y a déjà plus qu'une fenêtre"
+
+msgid "E441: There is no preview window"
+msgstr "E441: Il n'y a pas de fenêtre de prévisualisation"
+
+msgid "E442: Can't split topleft and botright at the same time"
+msgstr "E442: Impossible de partager topleft et botright en même temps"
+
+msgid "E443: Cannot rotate when another window is split"
+msgstr "E443: Rotation impossible quand une autre fenêtre est partagée"
+
+msgid "E444: Cannot close last window"
+msgstr "E444: Impossible de fermer la dernière fenêtre"
+
+msgid "E813: Cannot close autocmd window"
+msgstr "E813: Impossible de fermer la fenêtre des autocommandes"
+
+msgid "E814: Cannot close window, only autocmd window would remain"
+msgstr ""
+"E814: Impossible de fermer la fenêtre, seule la fenêtre des autocommandes "
+"resterait"
+
+msgid "E445: Other window contains changes"
+msgstr "E445: Les modifications de l'autre fenêtre n'ont pas été enregistrées"
+
+msgid "E446: No file name under cursor"
+msgstr "E446: Aucun nom de fichier sous le curseur"
+
+#, c-format
+msgid "E447: Can't find file \"%s\" in path"
+msgstr "E447: Le fichier \"%s\" est introuvable dans 'path'"
+
+#, c-format
+msgid "E799: Invalid ID: %ld (must be greater than or equal to 1)"
+msgstr "E799: ID invalide : %ld (doit être plus grand ou égal à 1)"
+
+#, c-format
+msgid "E801: ID already taken: %ld"
+msgstr "E801: ID déjà pris: %ld"
+
+msgid "List or number required"
+msgstr "Liste ou nombre requis"
+
+#, c-format
+msgid "E802: Invalid ID: %ld (must be greater than or equal to 1)"
+msgstr "E802: ID invalide : %ld (doit être plus grand ou égal à 1)"
+
+#, c-format
+msgid "E803: ID not found: %ld"
+msgstr "E803: ID introuvable : %ld"
+
+#, c-format
+msgid "E370: Could not load library %s"
+msgstr "E370: Impossible de charger la bibliothèque %s"
+
+msgid "Sorry, this command is disabled: the Perl library could not be loaded."
+msgstr ""
+"Désolé, commande désactivée : la bibliothèque Perl n'a pas pu être chargée."
+
+msgid "E299: Perl evaluation forbidden in sandbox without the Safe module"
+msgstr "E299: Évaluation Perl interdite dans bac à sable sans le module Safe"
+
+msgid "Edit with &multiple Vims"
+msgstr "Éditer dans &plusieurs Vims"
+
+msgid "Edit with single &Vim"
+msgstr "Éditer dans un seul &Vim"
+
+msgid "Diff with Vim"
+msgstr "&Comparer avec Vim"
+
+msgid "Edit with &Vim"
+msgstr "Éditer dans &Vim"
+
+msgid "Edit with existing Vim"
+msgstr "Éditer dans le Vim existant"
+
+msgid "Edit with existing Vim - "
+msgstr "Éditer dans le Vim existant - "
+
+msgid "Edits the selected file(s) with Vim"
+msgstr "Édites le(s) fichier(s) sélectionné(s) avec Vim"
+
+# DB - MessageBox win32, la longueur n'est pas un problème !
+msgid "Error creating process: Check if gvim is in your path!"
+msgstr ""
+"Erreur de création du processus : vérifiez que gvim est bien dans votre "
+"chemin !"
+
+msgid "gvimext.dll error"
+msgstr "Erreur de gvimext.dll"
+
+msgid "Path length too long!"
+msgstr "Le chemin est trop long !"
+
+# msgstr "--Pas de lignes dans le tampon--"
+# DB - todo : ou encore : msgstr "--Aucune ligne dans le tampon--"
+msgid "--No lines in buffer--"
+msgstr "--Le tampon est vide--"
+
+msgid "E470: Command aborted"
+msgstr "E470: Commande annulée"
+
+msgid "E471: Argument required"
+msgstr "E471: Argument requis"
+
+msgid "E10: \\ should be followed by /, ? or &"
+msgstr "E10: \\ devrait être suivi de /, ? ou &"
+
+msgid "E11: Invalid in command-line window; <CR> executes, CTRL-C quits"
+msgstr ""
+"E11: Invalide dans la fenêtre ligne-de-commande ; <CR> exécute, CTRL-C quitte"
+
+msgid "E12: Command not allowed from exrc/vimrc in current dir or tag search"
+msgstr ""
+"E12: commande non autorisée depuis un exrc/vimrc dans répertoire courant ou "
+"une recherche de marqueur"
+
+msgid "E171: Missing :endif"
+msgstr "E171: :endif manquant"
+
+msgid "E600: Missing :endtry"
+msgstr "E600: :endtry manquant"
+
+msgid "E170: Missing :endwhile"
+msgstr "E170: :endwhile manquant"
+
+msgid "E170: Missing :endfor"
+msgstr "E170: :endfor manquant"
+
+msgid "E588: :endwhile without :while"
+msgstr "E588: :endwhile sans :while"
+
+msgid "E588: :endfor without :for"
+msgstr "E588: :endfor sans :for"
+
+msgid "E13: File exists (add ! to override)"
+msgstr "E13: Le fichier existe déjà (ajoutez ! pour passer outre)"
+
+msgid "E472: Command failed"
+msgstr "E472: La commande a échoué"
+
+#, c-format
+msgid "E234: Unknown fontset: %s"
+msgstr "E234: Jeu de police inconnu : %s"
+
+#, c-format
+msgid "E235: Unknown font: %s"
+msgstr "E235: Police inconnue : %s"
+
+#, c-format
+msgid "E236: Font \"%s\" is not fixed-width"
+msgstr "E236: La police \"%s\" n'a pas une chasse (largeur) fixe"
+
+msgid "E473: Internal error"
+msgstr "E473: Erreur interne"
+
+#, c-format
+msgid "E685: Internal error: %s"
+msgstr "E685: Erreur interne : %s"
+
+msgid "Interrupted"
+msgstr "Interrompu"
+
+msgid "E14: Invalid address"
+msgstr "E14: Adresse invalide"
+
+msgid "E474: Invalid argument"
+msgstr "E474: Argument invalide"
+
+#, c-format
+msgid "E475: Invalid argument: %s"
+msgstr "E475: Argument invalide : %s"
+
+#, c-format
+msgid "E475: Invalid value for argument %s"
+msgstr "E475: Valeur d'argument invalide : %s"
+
+#, c-format
+msgid "E475: Invalid value for argument %s: %s"
+msgstr "E475: Valeur d'argument invalide %s : %s"
+
+#, c-format
+msgid "E15: Invalid expression: %s"
+msgstr "E15: Expression invalide : %s"
+
+msgid "E16: Invalid range"
+msgstr "E16: Plage invalide"
+
+msgid "E476: Invalid command"
+msgstr "E476: Commande invalide"
+
+#, c-format
+msgid "E17: \"%s\" is a directory"
+msgstr "E17: \"%s\" est un répertoire"
+
+#, c-format
+msgid "E364: Library call failed for \"%s()\""
+msgstr "E364: L'appel à la bibliothèque a échoué pour \"%s()\""
+
+msgid "E667: Fsync failed"
+msgstr "E667: Fsynch a échoué"
+
+#, c-format
+msgid "E448: Could not load library function %s"
+msgstr "E448: Impossible de charger la fonction %s de la bibliothèque"
+
+msgid "E19: Mark has invalid line number"
+msgstr "E19: La marque a un numéro de ligne invalide"
+
+msgid "E20: Mark not set"
+msgstr "E20: Marque non positionnée"
+
+msgid "E21: Cannot make changes, 'modifiable' is off"
+msgstr "E21: Impossible de modifier, 'modifiable' est désactivé"
+
+msgid "E22: Scripts nested too deep"
+msgstr "E22: Trop de récursion dans les scripts"
+
+msgid "E23: No alternate file"
+msgstr "E23: Pas de fichier alternatif"
+
+msgid "E24: No such abbreviation"
+msgstr "E24: Cette abréviation n'existe pas"
+
+msgid "E477: No ! allowed"
+msgstr "E477: Le ! n'est pas autorisé"
+
+msgid "E25: GUI cannot be used: Not enabled at compile time"
+msgstr "E25: L'interface graphique n'a pas été compilée dans cette version"
+
+msgid "E26: Hebrew cannot be used: Not enabled at compile time\n"
+msgstr "E26: Le support de l'hébreu n'a pas été compilé dans cette version\n"
+
+msgid "E27: Farsi cannot be used: Not enabled at compile time\n"
+msgstr "E27: Le support du farsi n'a pas été compilé dans cette version\n"
+
+msgid "E800: Arabic cannot be used: Not enabled at compile time\n"
+msgstr "E800: Le support de l'arabe n'a pas été compilé dans cette version\n"
+
+#, c-format
+msgid "E28: No such highlight group name: %s"
+msgstr "E28: Aucun nom de groupe de surbrillance %s"
+
+msgid "E29: No inserted text yet"
+msgstr "E29: Pas encore de texte inséré"
+
+msgid "E30: No previous command line"
+msgstr "E30: Aucune ligne de commande précédente"
+
+msgid "E31: No such mapping"
+msgstr "E31: Mappage inexistant"
+
+msgid "E479: No match"
+msgstr "E479: Aucune correspondance"
+
+#, c-format
+msgid "E480: No match: %s"
+msgstr "E480: Aucune correspondance : %s"
+
+msgid "E32: No file name"
+msgstr "E32: Aucun nom de fichier"
+
+msgid "E33: No previous substitute regular expression"
+msgstr "E33: Aucune expression régulière de substitution précédente"
+
+msgid "E34: No previous command"
+msgstr "E34: Aucune commande précédente"
+
+msgid "E35: No previous regular expression"
+msgstr "E35: Aucune expression régulière précédente"
+
+msgid "E481: No range allowed"
+msgstr "E481: Les plages ne sont pas autorisées"
+
+msgid "E36: Not enough room"
+msgstr "E36: Pas assez de place"
+
+#, c-format
+msgid "E247: no registered server named \"%s\""
+msgstr "E247: aucun serveur nommé \"%s\" n'est enregistré"
+
+#, c-format
+msgid "E482: Can't create file %s"
+msgstr "E482: Impossible de créer le fichier %s"
+
+msgid "E483: Can't get temp file name"
+msgstr "E483: Impossible d'obtenir un nom de fichier temporaire"
+
+#, c-format
+msgid "E484: Can't open file %s"
+msgstr "E484: Impossible d'ouvrir le fichier \"%s\""
+
+#, c-format
+msgid "E485: Can't read file %s"
+msgstr "E485: Impossible de lire le fichier %s"
+
+msgid "E38: Null argument"
+msgstr "E38: Argument null"
+
+msgid "E39: Number expected"
+msgstr "E39: Nombre attendu"
+
+#, c-format
+msgid "E40: Can't open errorfile %s"
+msgstr "E40: Impossible d'ouvrir le fichier d'erreurs %s"
+
+msgid "E233: cannot open display"
+msgstr "E233: ouverture du display impossible"
+
+msgid "E41: Out of memory!"
+msgstr "E41: Mémoire épuisée"
+
+msgid "Pattern not found"
+msgstr "Motif introuvable"
+
+#, c-format
+msgid "E486: Pattern not found: %s"
+msgstr "E486: Motif introuvable : %s"
+
+msgid "E487: Argument must be positive"
+msgstr "E487: L'argument doit être positif"
+
+msgid "E459: Cannot go back to previous directory"
+msgstr "E459: Impossible de retourner au répertoire précédent"
+
+msgid "E42: No Errors"
+msgstr "E42: Aucune erreur"
+
+# DB - TODO : trouver une traduction valable et attestée pour "location".
+msgid "E776: No location list"
+msgstr "E776: Aucune liste d'emplacements"
+
+msgid "E43: Damaged match string"
+msgstr "E43: La chaîne de recherche est endommagée"
+
+msgid "E44: Corrupted regexp program"
+msgstr "E44: L'automate de regexp est corrompu"
+
+msgid "E45: 'readonly' option is set (add ! to override)"
+msgstr "E45: L'option 'readonly' est activée (ajoutez ! pour passer outre)"
+
+#, c-format
+msgid "E46: Cannot change read-only variable \"%s\""
+msgstr "E46: La variable \"%s\" est en lecture seule"
+
+#, c-format
+msgid "E794: Cannot set variable in the sandbox: \"%s\""
+msgstr ""
+"E794: Impossible de modifier une variable depuis le bac à sable : \"%s\""
+
+msgid "E713: Cannot use empty key for Dictionary"
+msgstr "E713: Impossible d'utiliser une clé vide dans un Dictionnaire"
+
+msgid "E715: Dictionary required"
+msgstr "E715: Dictionnaire requis"
+
+#, c-format
+msgid "E684: list index out of range: %ld"
+msgstr "E684: index de Liste hors limites : %ld au-delà de la fin"
+
+# DB : Suggestion
+#, c-format
+msgid "E118: Too many arguments for function: %s"
+msgstr "E118: La fonction %s a reçu trop d'arguments"
+
+#, c-format
+msgid "E716: Key not present in Dictionary: %s"
+msgstr "E716: La clé %s n'existe pas dans le Dictionnaire"
+
+msgid "E714: List required"
+msgstr "E714: Liste requise"
+
+#, c-format
+msgid "E712: Argument of %s must be a List or Dictionary"
+msgstr "E712: L'argument de %s doit être une Liste ou un Dictionnaire"
+
+msgid "E47: Error while reading errorfile"
+msgstr "E47: Erreur lors de la lecture du fichier d'erreurs"
+
+msgid "E48: Not allowed in sandbox"
+msgstr "E48: Opération interdite dans le bac à sable"
+
+msgid "E523: Not allowed here"
+msgstr "E523: Interdit à cet endroit"
+
+msgid "E359: Screen mode setting not supported"
+msgstr "E359: Choix du mode d'écran non supporté"
+
+msgid "E49: Invalid scroll size"
+msgstr "E49: Valeur de défilement invalide"
+
+msgid "E91: 'shell' option is empty"
+msgstr "E91: L'option 'shell' est vide"
+
+msgid "E255: Couldn't read in sign data!"
+msgstr "E255: Impossible de lire les données du symbole !"
+
+msgid "E72: Close error on swap file"
+msgstr "E72: Erreur lors de la fermeture du fichier d'échange"
+
+msgid "E73: tag stack empty"
+msgstr "E73: La pile des marqueurs est vide"
+
+msgid "E74: Command too complex"
+msgstr "E74: Commande trop complexe"
+
+msgid "E75: Name too long"
+msgstr "E75: Nom trop long"
+
+msgid "E76: Too many ["
+msgstr "E76: Trop de ["
+
+msgid "E77: Too many file names"
+msgstr "E77: Trop de noms de fichiers"
+
+msgid "E488: Trailing characters"
+msgstr "E488: Caractères surnuméraires"
+
+msgid "E78: Unknown mark"
+msgstr "E78: Marque inconnue"
+
+msgid "E79: Cannot expand wildcards"
+msgstr "E79: Impossible de développer les métacaractères"
+
+msgid "E591: 'winheight' cannot be smaller than 'winminheight'"
+msgstr "E591: 'winheight' ne peut pas être plus petit que 'winminheight'"
+
+msgid "E592: 'winwidth' cannot be smaller than 'winminwidth'"
+msgstr "E592: 'winwidth' ne peut pas être plus petit que 'winminwidth'"
+
+msgid "E80: Error while writing"
+msgstr "E80: Erreur lors de l'écriture"
+
+msgid "E939: Positive count required"
+msgstr "E939: Quantificateur positif requis"
+
+msgid "E81: Using <SID> not in a script context"
+msgstr "E81: <SID> utilisé en dehors d'un script"
+
+msgid "E449: Invalid expression received"
+msgstr "E449: Expression invalide reçue"
+
+msgid "E463: Region is guarded, cannot modify"
+msgstr "E463: Cette zone est verrouillée et ne peut pas être modifiée"
+
+msgid "E744: NetBeans does not allow changes in read-only files"
+msgstr ""
+"E744: NetBeans n'autorise pas la modification des fichiers en lecture seule"
+
+msgid "E363: pattern uses more memory than 'maxmempattern'"
+msgstr "E363: le motif utilise plus de mémoire que 'maxmempattern'"
+
+msgid "E749: empty buffer"
+msgstr "E749: tampon vide"
+
+#, c-format
+msgid "E86: Buffer %ld does not exist"
+msgstr "E86: Le tampon %ld n'existe pas"
+
+msgid "E682: Invalid search pattern or delimiter"
+msgstr "E682: Délimiteur ou motif de recherche invalide"
+
+msgid "E139: File is loaded in another buffer"
+msgstr "E139: Le fichier est chargé dans un autre tampon"
+
+#, c-format
+msgid "E764: Option '%s' is not set"
+msgstr "E764: L'option '%s' n'est pas activée"
+
+msgid "E850: Invalid register name"
+msgstr "E850: Nom de registre invalide"
+
+#, c-format
+msgid "E919: Directory not found in '%s': \"%s\""
+msgstr "E919: Répertoire introuvable dans '%s' : \"%s\""
+
+msgid "E952: Autocommand caused recursive behavior"
+msgstr "E952: Une autocommande a causé une récursivité"
+
+msgid "search hit TOP, continuing at BOTTOM"
+msgstr "La recherche a atteint le HAUT, et continue en BAS"
+
+msgid "search hit BOTTOM, continuing at TOP"
+msgstr "La recherche a atteint le BAS, et continue en HAUT"
+
+#, c-format
+msgid "Need encryption key for \"%s\""
+msgstr "Besoin de la clé de chiffrement pour \"%s\""
+
+msgid "empty keys are not allowed"
+msgstr "les clés vides ne sont pas autorisées"
+
+msgid "dictionary is locked"
+msgstr "dictionnaire est verrouillé"
+
+msgid "list is locked"
+msgstr "liste verrouillée"
+
+#, c-format
+msgid "failed to add key '%s' to dictionary"
+msgstr "l'ajout de clé '%s' au dictionnaire a échoué"
+
+#, c-format
+msgid "index must be int or slice, not %s"
+msgstr "index doit être int ou slice, et non %s"
+
+#, c-format
+msgid "expected str() or unicode() instance, but got %s"
+msgstr "attendu instance de str() ou unicode(), mais reçu %s"
+
+#, c-format
+msgid "expected bytes() or str() instance, but got %s"
+msgstr "attendu instance de bytes() ou str(), mais reçu %s"
+
+#, c-format
+msgid ""
+"expected int(), long() or something supporting coercing to long(), but got %s"
+msgstr ""
+"attendu int(), long() ou quelque chose qui peut être transformé en long(), "
+"mais reçu %s"
+
+#, c-format
+msgid "expected int() or something supporting coercing to int(), but got %s"
+msgstr ""
+"attendu int() ou quelque chose qui peut être transformé en int(), mais reçu "
+"%s"
+
+msgid "value is too large to fit into C int type"
+msgstr "valeur trop grande pour être stockée dans le type C int"
+
+msgid "value is too small to fit into C int type"
+msgstr "valeur trop petite pour être stockée dans le type C int"
+
+msgid "number must be greater than zero"
+msgstr "le nombre doit être plus grand que zéro"
+
+msgid "number must be greater or equal to zero"
+msgstr "le nombre doit être plus grand ou égal à zéro"
+
+msgid "can't delete OutputObject attributes"
+msgstr "impossible d'effacer les attributs d'OutputObject"
+
+#, c-format
+msgid "invalid attribute: %s"
+msgstr "attribut invalide : %s"
+
+msgid "E264: Python: Error initialising I/O objects"
+msgstr "E264: Python : Erreur d'initialisation des objets d'E/S"
+
+msgid "failed to change directory"
+msgstr "changement de répertoire a échoué"
+
+#, c-format
+msgid "expected 3-tuple as imp.find_module() result, but got %s"
+msgstr "attendu un 3-tuple comme résultat de imp.find_module(), mais reçu %s"
+
+#, c-format
+msgid "expected 3-tuple as imp.find_module() result, but got tuple of size %d"
+msgstr ""
+"attendu un 3-tuple comme résultat de imp.find_module(), mais reçu un tuple "
+"de taille %d"
+
+msgid "internal error: imp.find_module returned tuple with NULL"
+msgstr "erreur interne : imp.find_module a retourné un tuple contenant NULL"
+
+msgid "cannot delete vim.Dictionary attributes"
+msgstr "impossible d'effacer les attributs de vim.Dictionary"
+
+msgid "cannot modify fixed dictionary"
+msgstr "impossible de modifier un dictionnaire fixe"
+
+#, c-format
+msgid "cannot set attribute %s"
+msgstr "impossible d'initialiser l'attribut %s"
+
+msgid "hashtab changed during iteration"
+msgstr "la table de hachage a été changée pendant une itération"
+
+#, c-format
+msgid "expected sequence element of size 2, but got sequence of size %d"
+msgstr ""
+"attendu une séquence d'éléments de taille 2, mais reçu une séquence de "
+"taille %d"
+
+msgid "list constructor does not accept keyword arguments"
+msgstr "le constructeur de liste n'accepte pas les arguments nommés"
+
+msgid "list index out of range"
+msgstr "index de liste hors limites"
+
+#, c-format
+msgid "internal error: failed to get vim list item %d"
+msgstr "erreur interne : accès à un élément %d de liste a échoué"
+
+msgid "slice step cannot be zero"
+msgstr "le pas du découpage en tranche ne peut pas être zéro"
+
+#, c-format
+msgid "attempt to assign sequence of size greater than %d to extended slice"
+msgstr ""
+"tentative d'assigner une séquence de taille plus grande que %d à un "
+"découpage en tranche étendu "
+
+#, c-format
+msgid "internal error: no vim list item %d"
+msgstr "erreur interne : pas d'élément %d de liste vim"
+
+msgid "internal error: not enough list items"
+msgstr "erreur interne : pas assez d'éléments de liste"
+
+msgid "internal error: failed to add item to list"
+msgstr "erreur interne : ajout d'élément à la liste a échoué"
+
+#, c-format
+msgid "attempt to assign sequence of size %d to extended slice of size %d"
+msgstr ""
+"tentative d'assigner une séquence de taille %d à un découpage en tranche "
+"étendu de taille %d"
+
+msgid "failed to add item to list"
+msgstr "ajout à la liste a échoué"
+
+msgid "cannot delete vim.List attributes"
+msgstr "impossible d'effacer les attributs de vim.List"
+
+msgid "cannot modify fixed list"
+msgstr "impossible de modifier une liste fixe"
+
+#, c-format
+msgid "unnamed function %s does not exist"
+msgstr "la fonction sans nom %s n'existe pas"
+
+#, c-format
+msgid "function %s does not exist"
+msgstr "la fonction %s n'existe pas"
+
+#, c-format
+msgid "failed to run function %s"
+msgstr "exécution de la fonction %s a échoué"
+
+msgid "unable to get option value"
+msgstr "impossible d'obtenir la valeur d'une option"
+
+msgid "internal error: unknown option type"
+msgstr "erreur interne : type d'option inconnu"
+
+msgid "problem while switching windows"
+msgstr "problème lors du changement de fenêtres"
+
+#, c-format
+msgid "unable to unset global option %s"
+msgstr "impossible de désactiver une option globale %s"
+
+#, c-format
+msgid "unable to unset option %s which does not have global value"
+msgstr "impossible de désactiver l'option %s qui n'a pas de valeur globale"
+
+msgid "attempt to refer to deleted tab page"
+msgstr "tentative de référencer un onglet effacé"
+
+msgid "no such tab page"
+msgstr "cet onglet n'existe pas"
+
+msgid "attempt to refer to deleted window"
+msgstr "tentative de référencer une fenêtre effacée"
+
+msgid "readonly attribute: buffer"
+msgstr "attribut en lecture seule : tampon"
+
+msgid "cursor position outside buffer"
+msgstr "curseur positionné en dehors du tampon"
+
+msgid "no such window"
+msgstr "Cette fenêtre n'existe pas"
+
+msgid "attempt to refer to deleted buffer"
+msgstr "tentative de référencer un tampon effacé"
+
+msgid "failed to rename buffer"
+msgstr "impossible de renommer le tampon"
+
+msgid "mark name must be a single character"
+msgstr "le nom de marque doit être un seul caractère"
+
+#, c-format
+msgid "expected vim.Buffer object, but got %s"
+msgstr "attendu un objet vim.Buffer, mais reçu %s"
+
+#, c-format
+msgid "failed to switch to buffer %d"
+msgstr "impossible de se déplacer au tampon %d"
+
+#, c-format
+msgid "expected vim.Window object, but got %s"
+msgstr "attendu un objet vim.Window, mais reçu %s"
+
+msgid "failed to find window in the current tab page"
+msgstr "impossible de trouver une fenêtre dans l'onglet courant"
+
+msgid "did not switch to the specified window"
+msgstr "ne s'est pas déplacé à la fenêtre spécifiée"
+
+#, c-format
+msgid "expected vim.TabPage object, but got %s"
+msgstr "attendu un objet vim.TabPage, mais reçu %s"
+
+msgid "did not switch to the specified tab page"
+msgstr "impossible de se déplacer à l'onglet spécifié"
+
+msgid "failed to run the code"
+msgstr "exécution du code a échoué"
+
+msgid "E858: Eval did not return a valid python object"
+msgstr "E858: Eval n'a pas retourné un objet python valide"
+
+msgid "E859: Failed to convert returned python object to vim value"
+msgstr "E859: Conversion d'objet python à une valeur de vim a échoué"
+
+#, c-format
+msgid "unable to convert %s to vim dictionary"
+msgstr "impossible de convertir %s à un dictionnaire vim"
+
+#, c-format
+msgid "unable to convert %s to vim list"
+msgstr "impossible de convertir %s à une liste de vim"
+
+#, c-format
+msgid "unable to convert %s to vim structure"
+msgstr "impossible de convertir %s à une structure de vim"
+
+msgid "internal error: NULL reference passed"
+msgstr "erreur interne : référence NULL passée"
+
+msgid "internal error: invalid value type"
+msgstr "erreur interne : type de valeur invalide"
+
+msgid ""
+"Failed to set path hook: sys.path_hooks is not a list\n"
+"You should now do the following:\n"
+"- append vim.path_hook to sys.path_hooks\n"
+"- append vim.VIM_SPECIAL_PATH to sys.path\n"
+msgstr ""
+"Impossible d'initialiser sys.path_hook qui n'est pas un liste\n"
+"Vous devez maintenant :\n"
+"- ajouter vim.path_hook à sys.path_hooks\n"
+"- ajouter vim.VIM_SPECIAL_PATH à sys.path\n"
+
+msgid ""
+"Failed to set path: sys.path is not a list\n"
+"You should now append vim.VIM_SPECIAL_PATH to sys.path"
+msgstr ""
+"Impossible d'initialiser le chemin : sys.math n'est pas une liste\n"
+"Vous devez maintenant ajouter vim.VIM_SPECIAL_PATH à sys.path"
+
+msgid ""
+"Vim macro files (*.vim)\t*.vim\n"
+"All Files (*.*)\t*.*\n"
+msgstr ""
+"Fichiers de macros Vim (*.vim)\t*.vim\n"
+"Tous les fichiers (*.*)\t*.*\n"
+
+msgid "All Files (*.*)\t*.*\n"
+msgstr "Tous les fichiers (*.)\t*.*\n"
+
+msgid ""
+"All Files (*.*)\t*.*\n"
+"C source (*.c, *.h)\t*.c;*.h\n"
+"C++ source (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"VB code (*.bas, *.frm)\t*.bas;*.frm\n"
+"Vim files (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
+msgstr ""
+"Tous les fichiers (*.*)\t*.*\n"
+"Source C (*.c, *.h)\t*.c;*.h\n"
+"Source C++ (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"Code VB (*.bas, *.frm)\t*.bas;*.frm\n"
+"Fichiers Vim (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
+
+msgid ""
+"Vim macro files (*.vim)\t*.vim\n"
+"All Files (*)\t*\n"
+msgstr ""
+"Fichiers de macros Vim (*.vim)\t*.vim\n"
+"Tous les fichiers (*)\t*\n"
+
+msgid "All Files (*)\t*\n"
+msgstr "Tous les fichiers (*)\t*\n"
+
+msgid ""
+"All Files (*)\t*\n"
+"C source (*.c, *.h)\t*.c;*.h\n"
+"C++ source (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"Vim files (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
+msgstr ""
+"Tous les fichiers (*)\t*\n"
+"Source C (*.c, *.h)\t*.c;*.h\n"
+"Source C++ (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"Fichiers Vim (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
diff --git a/src/po/ga.po b/src/po/ga.po
new file mode 100644
index 0000000..617b805
--- /dev/null
+++ b/src/po/ga.po
@@ -0,0 +1,7511 @@
+# Irish translations for vim.
+# This file is distributed under the same license as the vim package.
+# Kevin Patrick Scannell <kscanne@gmail.com>, 2005, 2006, 2008, 2010.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: vim 7.0\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2017-07-11 15:45-0500\n"
+"PO-Revision-Date: 2010-04-14 10:01-0500\n"
+"Last-Translator: Kevin Patrick Scannell <kscanne@gmail.com>\n"
+"Language-Team: Irish <gaeilge-gnulinux@lists.sourceforge.net>\n"
+"Language: ga\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-1\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=5; plural=n==1 ? 0 : n==2 ? 1 : (n>2 && n<7) ? 2 :"
+"(n>6 && n<11) ? 3 : 4;\n"
+
+msgid "E831: bf_key_init() called with empty password"
+msgstr "E831: cuireadh glaoch ar bf_key_init() le focal faire folamh"
+
+msgid "E820: sizeof(uint32_t) != 4"
+msgstr "E820: sizeof(uint32_t) != 4"
+
+msgid "E817: Blowfish big/little endian use wrong"
+msgstr "E817: Úsáid mhícheart Blowfish mórcheannach/caolcheannach"
+
+msgid "E818: sha256 test failed"
+msgstr "E818: Theip ar thástáil sha256"
+
+msgid "E819: Blowfish test failed"
+msgstr "E819: Theip ar thástáil Blowfish"
+
+msgid "[Location List]"
+msgstr "[Liosta Suíomh]"
+
+msgid "[Quickfix List]"
+msgstr "[Liosta Mearcheartúchán]"
+
+msgid "E855: Autocommands caused command to abort"
+msgstr "E855: Tobscoireadh an t-ordú mar gheall ar uathorduithe"
+
+msgid "E82: Cannot allocate any buffer, exiting..."
+msgstr "E82: Ní féidir maolán a dháileadh, ag scor..."
+
+msgid "E83: Cannot allocate buffer, using other one..."
+msgstr "E83: Ní féidir maolán a dháileadh, ag úsáid cinn eile..."
+
+msgid "E931: Buffer cannot be registered"
+msgstr "E931: Ní féidir an maolán a chlárú"
+
+msgid "E937: Attempt to delete a buffer that is in use"
+msgstr "E937: Iarracht ar mhaolán in úsáid a scriosadh"
+
+msgid "E515: No buffers were unloaded"
+msgstr "E515: Ní raibh aon mhaolán díluchtaithe"
+
+msgid "E516: No buffers were deleted"
+msgstr "E516: Ní raibh aon mhaolán scriosta"
+
+msgid "E517: No buffers were wiped out"
+msgstr "E517: Ní raibh aon mhaolán bánaithe"
+
+msgid "1 buffer unloaded"
+msgstr "Bhí maolán amháin díluchtaithe"
+
+#, c-format
+msgid "%d buffers unloaded"
+msgstr "%d maolán folmhaithe"
+
+msgid "1 buffer deleted"
+msgstr "Bhí maolán amháin scriosta"
+
+#, c-format
+msgid "%d buffers deleted"
+msgstr "%d maolán scriosta"
+
+msgid "1 buffer wiped out"
+msgstr "Bhí maolán amháin bánaithe"
+
+#, c-format
+msgid "%d buffers wiped out"
+msgstr "%d maolán bánaithe"
+
+msgid "E90: Cannot unload last buffer"
+msgstr "E90: Ní féidir an maolán deireanach a dhíluchtú"
+
+msgid "E84: No modified buffer found"
+msgstr "E84: Níor aimsíodh maolán mionathraithe"
+
+#. back where we started, didn't find anything.
+msgid "E85: There is no listed buffer"
+msgstr "E85: Níl aon mhaolán liostaithe ann"
+
+msgid "E87: Cannot go beyond last buffer"
+msgstr "E87: Ní féidir a dhul thar an maolán deireanach"
+
+msgid "E88: Cannot go before first buffer"
+msgstr "E88: Ní féidir a dhul roimh an chéad mhaolán"
+
+#, c-format
+msgid "E89: No write since last change for buffer %ld (add ! to override)"
+msgstr ""
+"E89: Athraíodh maolán %ld ach nach bhfuil sé sábháilte ó shin (cuir ! leis "
+"an ordú chun sárú)"
+
+msgid "W14: Warning: List of file names overflow"
+msgstr "W14: Rabhadh: Liosta ainmneacha comhaid thar maoil"
+
+#, c-format
+msgid "E92: Buffer %ld not found"
+msgstr "E92: Maolán %ld gan aimsiú"
+
+#, c-format
+msgid "E93: More than one match for %s"
+msgstr "E93: Níos mó ná teaghrán amháin comhoiriúnaithe le %s"
+
+#, c-format
+msgid "E94: No matching buffer for %s"
+msgstr "E94: Níl aon mhaolán comhoiriúnaithe le %s"
+
+#, c-format
+msgid "line %ld"
+msgstr "líne %ld:"
+
+msgid "E95: Buffer with this name already exists"
+msgstr "E95: Tá maolán ann leis an ainm seo cheana"
+
+msgid " [Modified]"
+msgstr " [Mionathraithe]"
+
+msgid "[Not edited]"
+msgstr "[Gan eagrú]"
+
+msgid "[New file]"
+msgstr "[Comhad nua]"
+
+msgid "[Read errors]"
+msgstr "[Earráidí léimh]"
+
+msgid "[RO]"
+msgstr "[L-A]"
+
+msgid "[readonly]"
+msgstr "[inléite amháin]"
+
+#, c-format
+msgid "1 line --%d%%--"
+msgstr "1 líne --%d%%--"
+
+#, c-format
+msgid "%ld lines --%d%%--"
+msgstr "%ld líne --%d%%--"
+
+#, c-format
+msgid "line %ld of %ld --%d%%-- col "
+msgstr "líne %ld de %ld --%d%%-- col "
+
+msgid "[No Name]"
+msgstr "[Gan Ainm]"
+
+#. must be a help buffer
+msgid "help"
+msgstr "cabhair"
+
+msgid "[Help]"
+msgstr "[Cabhair]"
+
+msgid "[Preview]"
+msgstr "[Réamhamharc]"
+
+msgid "All"
+msgstr "Uile"
+
+msgid "Bot"
+msgstr "Bun"
+
+msgid "Top"
+msgstr "Barr"
+
+msgid ""
+"\n"
+"# Buffer list:\n"
+msgstr ""
+"\n"
+"# Liosta maoláin:\n"
+
+msgid "[Scratch]"
+msgstr "[Sealadach]"
+
+msgid ""
+"\n"
+"--- Signs ---"
+msgstr ""
+"\n"
+"--- Comharthaí ---"
+
+#, c-format
+msgid "Signs for %s:"
+msgstr "Comharthaí do %s:"
+
+#, c-format
+msgid " line=%ld id=%d name=%s"
+msgstr " líne=%ld id=%d ainm=%s"
+
+msgid "E902: Cannot connect to port"
+msgstr "E902: Ní féidir ceangal leis an bport"
+
+msgid "E901: gethostbyname() in channel_open()"
+msgstr "E901: gethostbyname() in channel_open()"
+
+msgid "E898: socket() in channel_open()"
+msgstr "E898: socket() in channel_open()"
+
+msgid "E903: received command with non-string argument"
+msgstr "E903: fuarthas ordú le hargóint nach bhfuil ina theaghrán"
+
+msgid "E904: last argument for expr/call must be a number"
+msgstr "E904: ní mór don argóint dheireanach ar expr/call a bheith ina huimhir"
+
+msgid "E904: third argument for call must be a list"
+msgstr "E904: Caithfidh an tríú argóint a bheith ina liosta"
+
+#, c-format
+msgid "E905: received unknown command: %s"
+msgstr "E905: fuarthas ordú anaithnid: %s"
+
+#, c-format
+msgid "E630: %s(): write while not connected"
+msgstr "E630: %s(): scríobh gan ceangal a bheith ann"
+
+#, c-format
+msgid "E631: %s(): write failed"
+msgstr "E631: %s(): theip ar scríobh"
+
+#, c-format
+msgid "E917: Cannot use a callback with %s()"
+msgstr "E917: Ní féidir aisghlaoch a úsáid le %s()"
+
+msgid "E912: cannot use ch_evalexpr()/ch_sendexpr() with a raw or nl channel"
+msgstr ""
+"E912: ní féidir ch_evalexpr()/ch_sendexpr() a úsáid le cainéal raw nó nl"
+
+msgid "E906: not an open channel"
+msgstr "E906: ní cainéal oscailte é"
+
+msgid "E920: _io file requires _name to be set"
+msgstr "E920: caithfear _name a shocrú chun comhad _io a úsáid"
+
+msgid "E915: in_io buffer requires in_buf or in_name to be set"
+msgstr "E915: caithfear in_buf nó in_name a shocrú chun maolán in_io a úsáid"
+
+#, c-format
+msgid "E918: buffer must be loaded: %s"
+msgstr "E918: ní mór an maolán a luchtú: %s"
+
+msgid "E821: File is encrypted with unknown method"
+msgstr "E821: Comhad criptithe le modh anaithnid"
+
+msgid "Warning: Using a weak encryption method; see :help 'cm'"
+msgstr "Rabhadh: Criptiúchán lag; féach :help 'cm'"
+
+msgid "Enter encryption key: "
+msgstr "Iontráil eochair chriptiúcháin: "
+
+msgid "Enter same key again: "
+msgstr "Iontráil an eochair arís: "
+
+msgid "Keys don't match!"
+msgstr "Níl na heochracha comhoiriúnach le chéile!"
+
+msgid "[crypted]"
+msgstr "[criptithe]"
+
+#, c-format
+msgid "E720: Missing colon in Dictionary: %s"
+msgstr "E720: Idirstad ar iarraidh i bhFoclóir: %s"
+
+#, c-format
+msgid "E721: Duplicate key in Dictionary: \"%s\""
+msgstr "E721: Eochair dhúblach i bhFoclóir: \"%s\""
+
+#, c-format
+msgid "E722: Missing comma in Dictionary: %s"
+msgstr "E722: Camóg ar iarraidh i bhFoclóir: %s"
+
+#, c-format
+msgid "E723: Missing end of Dictionary '}': %s"
+msgstr "E723: '}' ar iarraidh ag deireadh foclóra: %s"
+
+msgid "extend() argument"
+msgstr "argóint extend()"
+
+#, c-format
+msgid "E737: Key already exists: %s"
+msgstr "E737: Tá eochair ann cheana: %s"
+
+#, c-format
+msgid "E96: Cannot diff more than %ld buffers"
+msgstr "E96: Ní féidir diff a dhéanamh ar níos mó ná %ld maolán"
+
+msgid "E810: Cannot read or write temp files"
+msgstr "E810: Ní féidir comhaid shealadacha a léamh nó a scríobh"
+
+msgid "E97: Cannot create diffs"
+msgstr "E97: Ní féidir diffeanna a chruthú"
+
+msgid "Patch file"
+msgstr "Comhad paiste"
+
+msgid "E816: Cannot read patch output"
+msgstr "E816: Ní féidir aschur ó 'patch' a léamh"
+
+msgid "E98: Cannot read diff output"
+msgstr "E98: Ní féidir aschur ó 'diff' a léamh"
+
+msgid "E99: Current buffer is not in diff mode"
+msgstr "E99: Níl an maolán reatha sa mhód diff"
+
+msgid "E793: No other buffer in diff mode is modifiable"
+msgstr "E793: Ní féidir aon mhaolán eile a athrú sa mhód diff"
+
+msgid "E100: No other buffer in diff mode"
+msgstr "E100: Níl aon mhaolán eile sa mhód diff"
+
+msgid "E101: More than two buffers in diff mode, don't know which one to use"
+msgstr ""
+"E101: Tá níos mó ná dhá mhaolán sa mhód diff, níl fhios agam cé acu ba chóir "
+"a úsáid"
+
+#, c-format
+msgid "E102: Can't find buffer \"%s\""
+msgstr "E102: Tá maolán \"%s\" gan aimsiú"
+
+#, c-format
+msgid "E103: Buffer \"%s\" is not in diff mode"
+msgstr "E103: Níl maolán \"%s\" i mód diff"
+
+msgid "E787: Buffer changed unexpectedly"
+msgstr "E787: Athraíodh an maolán gan choinne"
+
+msgid "E104: Escape not allowed in digraph"
+msgstr "E104: Ní cheadaítear carachtair éalúcháin i ndéghraf"
+
+msgid "E544: Keymap file not found"
+msgstr "E544: Comhad eochairmhapála gan aimsiú"
+
+msgid "E105: Using :loadkeymap not in a sourced file"
+msgstr "E105: Ag úsáid :loadkeymap ach ní comhad foinsithe é seo"
+
+msgid "E791: Empty keymap entry"
+msgstr "E791: Iontráil fholamh eochairmhapála"
+
+msgid " Keyword completion (^N^P)"
+msgstr " Comhlánú lorgfhocal (^N^P)"
+
+#. ctrl_x_mode == 0, ^P/^N compl.
+msgid " ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+msgstr " mód ^X (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+
+msgid " Whole line completion (^L^N^P)"
+msgstr " Comhlánú Línte Ina Iomlán (^L^N^P)"
+
+msgid " File name completion (^F^N^P)"
+msgstr " Comhlánú de na hainmneacha comhaid (^F^N^P)"
+
+msgid " Tag completion (^]^N^P)"
+msgstr " Comhlánú clibeanna (^]/^N/^P)"
+
+msgid " Path pattern completion (^N^P)"
+msgstr " Comhlánú Conaire (^N^P)"
+
+msgid " Definition completion (^D^N^P)"
+msgstr " Comhlánú de na sainmhínithe (^D^N^P)"
+
+msgid " Dictionary completion (^K^N^P)"
+msgstr " Comhlánú foclóra (^K^N^P)"
+
+msgid " Thesaurus completion (^T^N^P)"
+msgstr " Comhlánú teasárais (^T^N^P)"
+
+msgid " Command-line completion (^V^N^P)"
+msgstr " Comhlánú den líne ordaithe (^V^N^P)"
+
+msgid " User defined completion (^U^N^P)"
+msgstr " Comhlánú saincheaptha (^U^N^P)"
+
+msgid " Omni completion (^O^N^P)"
+msgstr " Comhlánú Omni (^O^N^P)"
+
+msgid " Spelling suggestion (s^N^P)"
+msgstr " Moladh litrithe (s^N^P)"
+
+msgid " Keyword Local completion (^N^P)"
+msgstr " Comhlánú logánta lorgfhocal (^N^P)"
+
+msgid "Hit end of paragraph"
+msgstr "Sroicheadh críoch an pharagraif"
+
+msgid "E839: Completion function changed window"
+msgstr "E839: D'athraigh an fheidhm chomhlánaithe an fhuinneog"
+
+msgid "E840: Completion function deleted text"
+msgstr "E840: Scrios an fheidhm chomhlánaithe roinnt téacs"
+
+msgid "'dictionary' option is empty"
+msgstr "tá an rogha 'dictionary' folamh"
+
+msgid "'thesaurus' option is empty"
+msgstr "tá an rogha 'thesaurus' folamh"
+
+#, c-format
+msgid "Scanning dictionary: %s"
+msgstr "Foclóir á scanadh: %s"
+
+msgid " (insert) Scroll (^E/^Y)"
+msgstr " (ionsáigh) Scrollaigh (^E/^Y)"
+
+msgid " (replace) Scroll (^E/^Y)"
+msgstr " (ionadaigh) Scrollaigh (^E/^Y)"
+
+#, c-format
+msgid "Scanning: %s"
+msgstr "%s á scanadh"
+
+msgid "Scanning tags."
+msgstr "Clibeanna á scanadh."
+
+msgid "match in file"
+msgstr "meaitseáil sa chomhad"
+
+msgid " Adding"
+msgstr " Méadú"
+
+#. showmode might reset the internal line pointers, so it must
+#. * be called before line = ml_get(), or when this address is no
+#. * longer needed. -- Acevedo.
+#.
+msgid "-- Searching..."
+msgstr "-- Ag Cuardach..."
+
+msgid "Back at original"
+msgstr "Ar ais ag an mbunáit"
+
+msgid "Word from other line"
+msgstr "Focal as líne eile"
+
+msgid "The only match"
+msgstr "An t-aon teaghrán amháin comhoiriúnaithe"
+
+#, c-format
+msgid "match %d of %d"
+msgstr "comhoiriúnú %d as %d"
+
+#, c-format
+msgid "match %d"
+msgstr "comhoiriúnú %d"
+
+#. maximum nesting of lists and dicts
+msgid "E18: Unexpected characters in :let"
+msgstr "E18: Carachtair gan choinne i :let"
+
+#, c-format
+msgid "E121: Undefined variable: %s"
+msgstr "E121: Athróg gan sainmhíniú: %s"
+
+msgid "E111: Missing ']'"
+msgstr "E111: `]' ar iarraidh"
+
+msgid "E719: Cannot use [:] with a Dictionary"
+msgstr "E719: Ní féidir [:] a úsáid le foclóir"
+
+#, c-format
+msgid "E734: Wrong variable type for %s="
+msgstr "E734: Cineál mícheart athróige le haghaidh %s="
+
+#, c-format
+msgid "E461: Illegal variable name: %s"
+msgstr "E461: Ainm athróige neamhcheadaithe: %s"
+
+msgid "E806: using Float as a String"
+msgstr "E806: Snámhphointe á úsáid mar Theaghrán"
+
+msgid "E687: Less targets than List items"
+msgstr "E687: Níos lú spriocanna ná míreanna Liosta"
+
+msgid "E688: More targets than List items"
+msgstr "E688: Níos mó spriocanna ná míreanna Liosta"
+
+msgid "Double ; in list of variables"
+msgstr "; dúblach i liosta na n-athróg"
+
+#, c-format
+msgid "E738: Can't list variables for %s"
+msgstr "E738: Ní féidir athróga do %s a thaispeáint"
+
+msgid "E689: Can only index a List or Dictionary"
+msgstr "E689: Is féidir Liosta nó Foclóir amháin a innéacsú"
+
+msgid "E708: [:] must come last"
+msgstr "E708: caithfidh [:] a bheith ar deireadh"
+
+msgid "E709: [:] requires a List value"
+msgstr "E709: ní foláir Liosta a thabhairt le [:]"
+
+msgid "E710: List value has more items than target"
+msgstr "E710: Tá níos mó míreanna ag an Liosta ná an sprioc"
+
+msgid "E711: List value has not enough items"
+msgstr "E711: Níl go leor míreanna ag an Liosta"
+
+msgid "E690: Missing \"in\" after :for"
+msgstr "E690: \"in\" ar iarraidh i ndiaidh :for"
+
+#, c-format
+msgid "E108: No such variable: \"%s\""
+msgstr "E108: Níl a leithéid d'athróg: \"%s\""
+
+#. For historic reasons this error is not given for a list or dict.
+#. * E.g., the b: dict could be locked/unlocked.
+#, c-format
+msgid "E940: Cannot lock or unlock variable %s"
+msgstr "E940: Ní féidir athróg %s a ghlasáil nó a dhíghlasáil"
+
+msgid "E743: variable nested too deep for (un)lock"
+msgstr "E743: athróg neadaithe ródhomhain chun í a (dí)ghlasáil"
+
+msgid "E109: Missing ':' after '?'"
+msgstr "E109: ':' ar iarraidh i ndiaidh '?'"
+
+msgid "E691: Can only compare List with List"
+msgstr "E691: Is féidir Liosta a chur i gcomparáid le Liosta eile amháin"
+
+msgid "E692: Invalid operation for List"
+msgstr "E692: Oibríocht neamhbhailí ar Liostaí"
+
+msgid "E735: Can only compare Dictionary with Dictionary"
+msgstr "E735: Is féidir Foclóir a chur i gcomparáid le Foclóir eile amháin"
+
+msgid "E736: Invalid operation for Dictionary"
+msgstr "E736: Oibríocht neamhbhailí ar Fhoclóir"
+
+msgid "E694: Invalid operation for Funcrefs"
+msgstr "E694: Oibríocht neamhbhailí ar Funcref"
+
+msgid "E804: Cannot use '%' with Float"
+msgstr "E804: Ní féidir '%' a úsáid le Snámhphointe"
+
+msgid "E110: Missing ')'"
+msgstr "E110: ')' ar iarraidh"
+
+msgid "E695: Cannot index a Funcref"
+msgstr "E695: Ní féidir Funcref a innéacsú"
+
+msgid "E909: Cannot index a special variable"
+msgstr "E909: Ní féidir athróg speisialta a innéacsú"
+
+#, c-format
+msgid "E112: Option name missing: %s"
+msgstr "E112: Ainm rogha ar iarraidh: %s"
+
+#, c-format
+msgid "E113: Unknown option: %s"
+msgstr "E113: Rogha anaithnid: %s"
+
+#, c-format
+msgid "E114: Missing quote: %s"
+msgstr "E114: Comhartha athfhriotail ar iarraidh: %s"
+
+#, c-format
+msgid "E115: Missing quote: %s"
+msgstr "E115: Comhartha athfhriotail ar iarraidh: %s"
+
+msgid "Not enough memory to set references, garbage collection aborted!"
+msgstr ""
+"Níl go leor cuimhne ann le tagairtí a shocrú; bailiú dramhaíola á thobscor!"
+
+msgid "E724: variable nested too deep for displaying"
+msgstr "E724: athróg neadaithe ródhomhain chun í a thaispeáint"
+
+msgid "E805: Using a Float as a Number"
+msgstr "E805: Snámhphointe á úsáid mar Uimhir"
+
+msgid "E703: Using a Funcref as a Number"
+msgstr "E703: Funcref á úsáid mar Uimhir"
+
+msgid "E745: Using a List as a Number"
+msgstr "E745: Liosta á úsáid mar Uimhir"
+
+msgid "E728: Using a Dictionary as a Number"
+msgstr "E728: Foclóir á úsáid mar Uimhir"
+
+msgid "E910: Using a Job as a Number"
+msgstr "E910: Jab á úsáid mar Uimhir"
+
+msgid "E913: Using a Channel as a Number"
+msgstr "E913: Cainéal á úsáid mar Uimhir"
+
+msgid "E891: Using a Funcref as a Float"
+msgstr "E891: Funcref á úsáid mar Shnámhphointe"
+
+msgid "E892: Using a String as a Float"
+msgstr "E892: Teaghrán á úsáid mar Shnámhphointe"
+
+msgid "E893: Using a List as a Float"
+msgstr "E893: Liosta á úsáid mar Shnámhphointe"
+
+msgid "E894: Using a Dictionary as a Float"
+msgstr "E894: Foclóir á úsáid mar Shnámhphointe"
+
+msgid "E907: Using a special value as a Float"
+msgstr "E907: Luach speisialta á úsáid mar Shnámhphointe"
+
+msgid "E911: Using a Job as a Float"
+msgstr "E911: Jab á úsáid mar Shnámhphointe"
+
+msgid "E914: Using a Channel as a Float"
+msgstr "E914: Cainéal á úsáid mar Shnámhphointe"
+
+msgid "E729: using Funcref as a String"
+msgstr "E729: Funcref á úsáid mar Theaghrán"
+
+msgid "E730: using List as a String"
+msgstr "E730: Liosta á úsáid mar Theaghrán"
+
+msgid "E731: using Dictionary as a String"
+msgstr "E731: Foclóir á úsáid mar Theaghrán"
+
+msgid "E908: using an invalid value as a String"
+msgstr "E908: luach neamhbhailí á úsáid mar Theaghrán"
+
+#, c-format
+msgid "E795: Cannot delete variable %s"
+msgstr "E795: Ní féidir athróg %s a scriosadh"
+
+#, c-format
+msgid "E704: Funcref variable name must start with a capital: %s"
+msgstr "E704: Caithfidh ceannlitir a bheith ar dtús ainm Funcref: %s"
+
+#, c-format
+msgid "E705: Variable name conflicts with existing function: %s"
+msgstr "E705: Tagann ainm athróige salach ar fheidhm atá ann cheana: %s"
+
+#, c-format
+msgid "E741: Value is locked: %s"
+msgstr "E741: Tá an luach faoi ghlas: %s"
+
+msgid "Unknown"
+msgstr "Anaithnid"
+
+#, c-format
+msgid "E742: Cannot change value of %s"
+msgstr "E742: Ní féidir an luach de %s a athrú"
+
+msgid "E698: variable nested too deep for making a copy"
+msgstr "E698: athróg neadaithe ródhomhain chun í a chóipeáil"
+
+msgid ""
+"\n"
+"# global variables:\n"
+msgstr ""
+"\n"
+"# athróga comhchoiteanna:\n"
+
+msgid ""
+"\n"
+"\tLast set from "
+msgstr ""
+"\n"
+"\tSocraithe is déanaí ó "
+
+msgid "map() argument"
+msgstr "argóint map()"
+
+msgid "filter() argument"
+msgstr "argóint filter()"
+
+#, c-format
+msgid "E686: Argument of %s must be a List"
+msgstr "E686: Caithfidh argóint de %s a bheith ina Liosta"
+
+msgid "E928: String required"
+msgstr "E928: Teaghrán de dhíth"
+
+msgid "E808: Number or Float required"
+msgstr "E808: Uimhir nó Snámhphointe de dhíth"
+
+msgid "add() argument"
+msgstr "argóint add()"
+
+msgid "E785: complete() can only be used in Insert mode"
+msgstr "E785: is féidir complete() a úsáid sa mhód Ionsáite amháin"
+
+#.
+#. * Yes this is ugly, I don't particularly like it either. But doing it
+#. * this way has the compelling advantage that translations need not to
+#. * be touched at all. See below what 'ok' and 'ync' are used for.
+#.
+msgid "&Ok"
+msgstr "&Ok"
+
+#, c-format
+msgid "E700: Unknown function: %s"
+msgstr "E700: Feidhm anaithnid: %s"
+
+msgid "E922: expected a dict"
+msgstr "E922: bhíothas ag súil le foclóir"
+
+msgid "E923: Second argument of function() must be a list or a dict"
+msgstr ""
+"E923: Caithfidh an dara hargóint de function() a bheith ina liosta nó ina "
+"foclóir"
+
+msgid ""
+"&OK\n"
+"&Cancel"
+msgstr ""
+"&OK\n"
+"&Cealaigh"
+
+msgid "called inputrestore() more often than inputsave()"
+msgstr "Glaodh inputrestore() níos minice ná inputsave()"
+
+msgid "insert() argument"
+msgstr "argóint insert()"
+
+msgid "E786: Range not allowed"
+msgstr "E786: Ní cheadaítear an raon"
+
+msgid "E916: not a valid job"
+msgstr "E916: ní jab bailí é"
+
+msgid "E701: Invalid type for len()"
+msgstr "E701: Cineál neamhbhailí le haghaidh len()"
+
+#, c-format
+msgid "E798: ID is reserved for \":match\": %ld"
+msgstr "E798: Aitheantas in áirithe do \":match\": %ld"
+
+msgid "E726: Stride is zero"
+msgstr "E726: Is nialas í an chéim"
+
+msgid "E727: Start past end"
+msgstr "E727: Tosach thar dheireadh"
+
+msgid "<empty>"
+msgstr "<folamh>"
+
+msgid "E240: No connection to the X server"
+msgstr "E240: Níl aon cheangal leis an bhfreastalaí X"
+
+#, c-format
+msgid "E241: Unable to send to %s"
+msgstr "E241: Ní féidir aon rud a sheoladh chuig %s"
+
+msgid "E277: Unable to read a server reply"
+msgstr "E277: Ní féidir freagra ón fhreastalaí a léamh"
+
+msgid "E941: already started a server"
+msgstr "E941: tosaíodh freastalaí cheana"
+
+msgid "E942: +clientserver feature not available"
+msgstr "E942: níl an ghné +clientserver ar fáil"
+
+msgid "remove() argument"
+msgstr "argóint remove()"
+
+msgid "E655: Too many symbolic links (cycle?)"
+msgstr "E655: An iomarca naisc shiombalacha (ciogal?)"
+
+msgid "reverse() argument"
+msgstr "argóint reverse()"
+
+msgid "E258: Unable to send to client"
+msgstr "E258: Ní féidir aon rud a sheoladh chuig an chliant"
+
+#, c-format
+msgid "E927: Invalid action: '%s'"
+msgstr "E927: Gníomh neamhbhailí: '%s'"
+
+msgid "sort() argument"
+msgstr "argóint sort()"
+
+msgid "uniq() argument"
+msgstr "argóint uniq()"
+
+msgid "E702: Sort compare function failed"
+msgstr "E702: Theip ar fheidhm chomparáide le linn sórtála"
+
+msgid "E882: Uniq compare function failed"
+msgstr "E882: Theip ar fheidhm chomparáide Uniq"
+
+msgid "(Invalid)"
+msgstr "(Neamhbhailí)"
+
+#, c-format
+msgid "E935: invalid submatch number: %d"
+msgstr "E935: uimhir fho-mheaitseála neamhbhailí: %d"
+
+msgid "E677: Error writing temp file"
+msgstr "E677: Earráid agus comhad sealadach á scríobh"
+
+msgid "E921: Invalid callback argument"
+msgstr "E921: Argóint neamhbhailí ar aisghlaoch"
+
+#, c-format
+msgid "<%s>%s%s %d, Hex %02x, Octal %03o"
+msgstr "<%s>%s%s %d, Heics %02x, Ocht %03o"
+
+#, c-format
+msgid "> %d, Hex %04x, Octal %o"
+msgstr "> %d, Heics %04x, Ocht %o"
+
+#, c-format
+msgid "> %d, Hex %08x, Octal %o"
+msgstr "> %d, Heics %08x, Ocht %o"
+
+msgid "E134: Move lines into themselves"
+msgstr "E134: Bog línte isteach iontu féin"
+
+msgid "1 line moved"
+msgstr "Bogadh líne amháin"
+
+#, c-format
+msgid "%ld lines moved"
+msgstr "Bogadh %ld líne"
+
+#, c-format
+msgid "%ld lines filtered"
+msgstr "Scagadh %ld líne"
+
+msgid "E135: *Filter* Autocommands must not change current buffer"
+msgstr ""
+"E135: Ní cheadaítear d'uathorduithe *scagaire* an maolán reatha a athrú"
+
+msgid "[No write since last change]\n"
+msgstr "[Athraithe agus nach sábháilte ó shin]\n"
+
+#, c-format
+msgid "%sviminfo: %s in line: "
+msgstr "%sviminfo: %s i líne: "
+
+msgid "E136: viminfo: Too many errors, skipping rest of file"
+msgstr ""
+"E136: viminfo: An iomarca earráidí, ag scipeáil an chuid eile den chomhad"
+
+#, c-format
+msgid "Reading viminfo file \"%s\"%s%s%s"
+msgstr "Comhad viminfo \"%s\"%s%s%s á léamh"
+
+msgid " info"
+msgstr " eolas"
+
+msgid " marks"
+msgstr " marcanna"
+
+msgid " oldfiles"
+msgstr " seanchomhad"
+
+msgid " FAILED"
+msgstr " TEIPTHE"
+
+#. avoid a wait_return for this message, it's annoying
+#, c-format
+msgid "E137: Viminfo file is not writable: %s"
+msgstr "E137: Níl an comhad Viminfo inscríofa: %s"
+
+#, c-format
+msgid "E929: Too many viminfo temp files, like %s!"
+msgstr "E929: An iomarca comhad sealadach viminfo, mar shampla %s!"
+
+#, c-format
+msgid "E138: Can't write viminfo file %s!"
+msgstr "E138: Ní féidir comhad viminfo %s a scríobh!"
+
+#, c-format
+msgid "Writing viminfo file \"%s\""
+msgstr "Comhad viminfo \"%s\" á scríobh"
+
+#, c-format
+msgid "E886: Can't rename viminfo file to %s!"
+msgstr "E886: Ní féidir ainm %s a chur ar an gcomhad viminfo!"
+
+#. Write the info:
+#, c-format
+msgid "# This viminfo file was generated by Vim %s.\n"
+msgstr "# Chruthaigh Vim an comhad viminfo seo %s.\n"
+
+msgid ""
+"# You may edit it if you're careful!\n"
+"\n"
+msgstr ""
+"# Is féidir leat an comhad seo a chur in eagar ach bí cúramach!\n"
+"\n"
+
+msgid "# Value of 'encoding' when this file was written\n"
+msgstr "# Luach 'encoding' agus an comhad seo á scríobh\n"
+
+msgid "Illegal starting char"
+msgstr "Carachtar neamhcheadaithe tosaigh"
+
+msgid ""
+"\n"
+"# Bar lines, copied verbatim:\n"
+msgstr ""
+"\n"
+"# Barralínte, cóipeáilte focal ar fhocal:\n"
+
+msgid "Save As"
+msgstr "Sábháil Mar"
+
+msgid "Write partial file?"
+msgstr "Scríobh comhad neamhiomlán?"
+
+msgid "E140: Use ! to write partial buffer"
+msgstr "E140: Bain úsáid as ! chun maolán neamhiomlán a scríobh"
+
+#, c-format
+msgid "Overwrite existing file \"%s\"?"
+msgstr "Forscríobh comhad \"%s\" atá ann cheana?"
+
+#, c-format
+msgid "Swap file \"%s\" exists, overwrite anyway?"
+msgstr "Tá comhad babhtála \"%s\" ann cheana; forscríobh mar sin féin?"
+
+#, c-format
+msgid "E768: Swap file exists: %s (:silent! overrides)"
+msgstr "E768: Tá comhad babhtála ann cheana: %s (úsáid :silent! chun sárú)"
+
+#, c-format
+msgid "E141: No file name for buffer %ld"
+msgstr "E141: Níl aon ainm ar mhaolán %ld"
+
+msgid "E142: File not written: Writing is disabled by 'write' option"
+msgstr "E142: Níor scríobhadh an comhad: díchumasaithe leis an rogha 'write'"
+
+#, c-format
+msgid ""
+"'readonly' option is set for \"%s\".\n"
+"Do you wish to write anyway?"
+msgstr ""
+"tá an rogha 'readonly' socraithe do \"%s\".\n"
+"Ar mhaith leat é a scríobh mar sin féin?"
+
+#, c-format
+msgid ""
+"File permissions of \"%s\" are read-only.\n"
+"It may still be possible to write it.\n"
+"Do you wish to try?"
+msgstr ""
+"Tá comhad \"%s\" inléite amháin.\n"
+"Seans gurbh fhéidir scríobh ann mar sin féin.\n"
+"An bhfuil fonn ort triail a bhaint as?"
+
+#, c-format
+msgid "E505: \"%s\" is read-only (add ! to override)"
+msgstr "E505: is inléite amháin é \"%s\" (cuir ! leis an ordú chun sárú)"
+
+msgid "Edit File"
+msgstr "Cuir Comhad in Eagar"
+
+#, c-format
+msgid "E143: Autocommands unexpectedly deleted new buffer %s"
+msgstr "E143: Scrios na huathorduithe maolán nua %s go tobann"
+
+msgid "E144: non-numeric argument to :z"
+msgstr "E144: argóint neamhuimhriúil chun :z"
+
+msgid "E145: Shell commands not allowed in rvim"
+msgstr "E145: Ní cheadaítear orduithe blaoisce i rvim"
+
+msgid "E146: Regular expressions can't be delimited by letters"
+msgstr ""
+"E146: Ní cheadaítear litreacha mar theormharcóirí ar shloinn ionadaíochta"
+
+#, c-format
+msgid "replace with %s (y/n/a/q/l/^E/^Y)?"
+msgstr "cuir %s ina ionad (y/n/a/q/l/^E/^Y)?"
+
+msgid "(Interrupted) "
+msgstr "(Idirbhriste) "
+
+msgid "1 match"
+msgstr "1 rud comhoiriúnach"
+
+msgid "1 substitution"
+msgstr "1 ionadaíocht"
+
+#, c-format
+msgid "%ld matches"
+msgstr "%ld rud comhoiriúnach"
+
+#, c-format
+msgid "%ld substitutions"
+msgstr "%ld ionadaíocht"
+
+msgid " on 1 line"
+msgstr " ar líne amháin"
+
+#, c-format
+msgid " on %ld lines"
+msgstr " ar %ld líne"
+
+#. will increment global_busy to break out of the loop
+msgid "E147: Cannot do :global recursive with a range"
+msgstr "E147: Ní cheadaítear :global athchúrsach le raon"
+
+# should have ":"
+msgid "E148: Regular expression missing from global"
+msgstr "E148: Slonn ionadaíochta ar iarraidh ó :global"
+
+#, c-format
+msgid "Pattern found in every line: %s"
+msgstr "Aimsíodh an patrún i ngach líne: %s"
+
+#, c-format
+msgid "Pattern not found: %s"
+msgstr "Patrún gan aimsiú: %s"
+
+msgid ""
+"\n"
+"# Last Substitute String:\n"
+"$"
+msgstr ""
+"\n"
+"# Teaghrán Ionadach Is Déanaí:\n"
+"$"
+
+msgid "E478: Don't panic!"
+msgstr "E478: Ná téigh i scaoll!"
+
+#, c-format
+msgid "E661: Sorry, no '%s' help for %s"
+msgstr "E661: Tá brón orm, ní aon chabhair '%s' do %s"
+
+#, c-format
+msgid "E149: Sorry, no help for %s"
+msgstr "E149: Tá brón orm, níl aon chabhair do %s"
+
+#, c-format
+msgid "Sorry, help file \"%s\" not found"
+msgstr "Tá brón orm, comhad cabhrach \"%s\" gan aimsiú"
+
+#, c-format
+msgid "E151: No match: %s"
+msgstr "E151: Gan meaitseáil: %s"
+
+#, c-format
+msgid "E152: Cannot open %s for writing"
+msgstr "E152: Ní féidir %s a oscailt chun scríobh ann"
+
+#, c-format
+msgid "E153: Unable to open %s for reading"
+msgstr "E153: Ní féidir %s a oscailt chun é a léamh"
+
+#, c-format
+msgid "E670: Mix of help file encodings within a language: %s"
+msgstr "E670: Ionchóduithe éagsúla do chomhaid chabhracha i dteanga aonair: %s"
+
+#, c-format
+msgid "E154: Duplicate tag \"%s\" in file %s/%s"
+msgstr "E154: Clib dhúblach \"%s\" i gcomhad %s/%s"
+
+#, c-format
+msgid "E150: Not a directory: %s"
+msgstr "E150: Ní comhadlann é: %s"
+
+#, c-format
+msgid "E160: Unknown sign command: %s"
+msgstr "E160: Ordú anaithnid comhartha: %s"
+
+msgid "E156: Missing sign name"
+msgstr "E156: Ainm comhartha ar iarraidh"
+
+msgid "E612: Too many signs defined"
+msgstr "E612: An iomarca comharthaí sainmhínithe"
+
+#, c-format
+msgid "E239: Invalid sign text: %s"
+msgstr "E239: Téacs neamhbhailí comhartha: %s"
+
+#, c-format
+msgid "E155: Unknown sign: %s"
+msgstr "E155: Comhartha anaithnid: %s"
+
+msgid "E159: Missing sign number"
+msgstr "E159: Uimhir chomhartha ar iarraidh"
+
+#, c-format
+msgid "E158: Invalid buffer name: %s"
+msgstr "E158: Ainm maoláin neamhbhailí: %s"
+
+msgid "E934: Cannot jump to a buffer that does not have a name"
+msgstr "E934: Ní féidir léim go maolán gan ainm"
+
+#, c-format
+msgid "E157: Invalid sign ID: %ld"
+msgstr "E157: ID neamhbhailí comhartha: %ld"
+
+#, c-format
+msgid "E885: Not possible to change sign %s"
+msgstr "E885: Ní féidir an comhartha a athrú: %s"
+
+msgid " (NOT FOUND)"
+msgstr " (AR IARRAIDH)"
+
+msgid " (not supported)"
+msgstr " (níl an rogha seo ar fáil)"
+
+msgid "[Deleted]"
+msgstr "[Scriosta]"
+
+msgid "No old files"
+msgstr "Gan seanchomhaid"
+
+msgid "Entering Debug mode. Type \"cont\" to continue."
+msgstr "Mód dífhabhtaithe á thosú. Clóscríobh \"cont\" chun leanúint."
+
+#, c-format
+msgid "line %ld: %s"
+msgstr "líne %ld: %s"
+
+#, c-format
+msgid "cmd: %s"
+msgstr "ordú: %s"
+
+msgid "frame is zero"
+msgstr "is nialas é an fráma"
+
+#, c-format
+msgid "frame at highest level: %d"
+msgstr "fráma ag an leibhéal is airde: %d"
+
+#, c-format
+msgid "Breakpoint in \"%s%s\" line %ld"
+msgstr "Brisphointe i \"%s%s\" líne %ld"
+
+#, c-format
+msgid "E161: Breakpoint not found: %s"
+msgstr "E161: Brisphointe gan aimsiú: %s"
+
+msgid "No breakpoints defined"
+msgstr "Níl aon bhrisphointe socraithe"
+
+#, c-format
+msgid "%3d %s %s line %ld"
+msgstr "%3d %s %s líne %ld"
+
+msgid "E750: First use \":profile start {fname}\""
+msgstr "E750: Úsáid \":profile start {ainm}\" ar dtús"
+
+#, c-format
+msgid "Save changes to \"%s\"?"
+msgstr "Sábháil athruithe ar \"%s\"?"
+
+msgid "Untitled"
+msgstr "Gan Teideal"
+
+#, c-format
+msgid "E162: No write since last change for buffer \"%s\""
+msgstr "E162: Athraíodh maolán \"%s\" ach nach bhfuil sé sábháilte ó shin"
+
+msgid "Warning: Entered other buffer unexpectedly (check autocommands)"
+msgstr "Rabhadh: Chuathas i maolán eile go tobann (seiceáil na huathorduithe)"
+
+msgid "E163: There is only one file to edit"
+msgstr "E163: Níl ach aon chomhad amháin le cur in eagar"
+
+msgid "E164: Cannot go before first file"
+msgstr "E164: Ní féidir a dhul roimh an chéad chomhad"
+
+msgid "E165: Cannot go beyond last file"
+msgstr "E165: Ní féidir a dhul thar an gcomhad deireanach"
+
+#, c-format
+msgid "E666: compiler not supported: %s"
+msgstr "E666: ní ghlactar leis an tiomsaitheoir: %s"
+
+#, c-format
+msgid "Searching for \"%s\" in \"%s\""
+msgstr "Ag déanamh cuardach ar \"%s\" i \"%s\""
+
+#, c-format
+msgid "Searching for \"%s\""
+msgstr "Ag déanamh cuardach ar \"%s\""
+
+#, c-format
+msgid "not found in '%s': \"%s\""
+msgstr "gan aimsiú in '%s': \"%s\""
+
+#, c-format
+msgid "W20: Required python version 2.x not supported, ignoring file: %s"
+msgstr "W20: Níl leagan 2.x de Python ar fáil; ag déanamh neamhaird de %s"
+
+#, c-format
+msgid "W21: Required python version 3.x not supported, ignoring file: %s"
+msgstr "W21: Níl leagan 3.x de Python ar fáil; ag déanamh neamhaird de %s"
+
+msgid "Source Vim script"
+msgstr "Foinsigh script Vim"
+
+#, c-format
+msgid "Cannot source a directory: \"%s\""
+msgstr "Ní féidir comhadlann a léamh: \"%s\""
+
+#, c-format
+msgid "could not source \"%s\""
+msgstr "níorbh fhéidir \"%s\" a léamh"
+
+#, c-format
+msgid "line %ld: could not source \"%s\""
+msgstr "líne %ld: níorbh fhéidir \"%s\" a fhoinsiú"
+
+#, c-format
+msgid "sourcing \"%s\""
+msgstr "\"%s\" á fhoinsiú"
+
+#, c-format
+msgid "line %ld: sourcing \"%s\""
+msgstr "líne %ld: \"%s\" á fhoinsiú"
+
+#, c-format
+msgid "finished sourcing %s"
+msgstr "deireadh ag foinsiú %s"
+
+#, c-format
+msgid "continuing in %s"
+msgstr "ag leanúint i %s"
+
+msgid "modeline"
+msgstr "módlíne"
+
+msgid "--cmd argument"
+msgstr "argóint --cmd"
+
+msgid "-c argument"
+msgstr "argóint -c"
+
+msgid "environment variable"
+msgstr "athróg thimpeallachta"
+
+msgid "error handler"
+msgstr "láimhseálaí earráidí"
+
+msgid "W15: Warning: Wrong line separator, ^M may be missing"
+msgstr ""
+"W15: Rabhadh: Deighilteoir línte mícheart, is féidir go bhfuil ^M ar iarraidh"
+
+msgid "E167: :scriptencoding used outside of a sourced file"
+msgstr "E167: ní úsáidtear :scriptencoding ach i gcomhad foinsithe"
+
+msgid "E168: :finish used outside of a sourced file"
+msgstr "E168: ní úsáidtear :finish ach i gcomhaid foinsithe"
+
+#, c-format
+msgid "Current %slanguage: \"%s\""
+msgstr "%sTeanga faoi láthair: \"%s\""
+
+#, c-format
+msgid "E197: Cannot set language to \"%s\""
+msgstr "E197: Ní féidir an teanga a shocrú mar \"%s\""
+
+msgid "Entering Ex mode. Type \"visual\" to go to Normal mode."
+msgstr "Mód Ex á thosú. Clóscríobh \"visual\" le haghaidh an ghnáthmhód."
+
+# in FARF -KPS
+msgid "E501: At end-of-file"
+msgstr "E501: Ag an chomhadchríoch"
+
+msgid "E169: Command too recursive"
+msgstr "E169: Ordú ró-athchúrsach"
+
+#, c-format
+msgid "E605: Exception not caught: %s"
+msgstr "E605: Eisceacht gan láimhseáil: %s"
+
+msgid "End of sourced file"
+msgstr "Críoch chomhaid foinsithe"
+
+msgid "End of function"
+msgstr "Críoch fheidhme"
+
+msgid "E464: Ambiguous use of user-defined command"
+msgstr "E464: Úsáid athbhríoch d'ordú saincheaptha"
+
+msgid "E492: Not an editor command"
+msgstr "E492: Níl ina ordú eagarthóra"
+
+msgid "E493: Backwards range given"
+msgstr "E493: Raon droim ar ais"
+
+msgid "Backwards range given, OK to swap"
+msgstr "Raon droim ar ais, babhtáil"
+
+msgid "E494: Use w or w>>"
+msgstr "E494: Bain úsáid as w nó w>>"
+
+msgid "E943: Command table needs to be updated, run 'make cmdidxs'"
+msgstr "E943: Caithfear tábla na n-orduithe a nuashonrú; rith 'make cmdidxs'"
+
+msgid "E319: Sorry, the command is not available in this version"
+msgstr "E319: Tá brón orm, níl an t-ordú ar fáil sa leagan seo"
+
+msgid "E172: Only one file name allowed"
+msgstr "E172: Ní cheadaítear ach aon ainm comhaid amháin"
+
+msgid "1 more file to edit. Quit anyway?"
+msgstr "1 comhad le cur in eagar fós. Scoir mar sin féin?"
+
+#, c-format
+msgid "%d more files to edit. Quit anyway?"
+msgstr "%d comhad le cur in eagar fós. Scoir mar sin féin?"
+
+msgid "E173: 1 more file to edit"
+msgstr "E173: 1 chomhad le heagrú fós"
+
+#, c-format
+msgid "E173: %ld more files to edit"
+msgstr "E173: %ld comhad le cur in eagar"
+
+msgid "E174: Command already exists: add ! to replace it"
+msgstr "E174: Tá an t-ordú ann cheana: cuir ! leis chun sárú"
+
+msgid ""
+"\n"
+" Name Args Address Complete Definition"
+msgstr ""
+"\n"
+" Ainm Arg Seoladh Iomlán Sainmhíniú"
+
+msgid "No user-defined commands found"
+msgstr "Níl aon ordú aimsithe atá sainithe ag an úsáideoir"
+
+msgid "E175: No attribute specified"
+msgstr "E175: Níl aon aitreabúid sainithe"
+
+msgid "E176: Invalid number of arguments"
+msgstr "E176: Tá líon na n-argóintí mícheart"
+
+msgid "E177: Count cannot be specified twice"
+msgstr "E177: Ní cheadaítear an t-áireamh a bheith tugtha faoi dhó"
+
+msgid "E178: Invalid default value for count"
+msgstr "E178: Luach réamhshocraithe neamhbhailí ar áireamh"
+
+msgid "E179: argument required for -complete"
+msgstr "E179: tá gá le hargóint i ndiaidh -complete"
+
+msgid "E179: argument required for -addr"
+msgstr "E179: tá gá le hargóint i ndiaidh -addr"
+
+#, c-format
+msgid "E181: Invalid attribute: %s"
+msgstr "E181: Aitreabúid neamhbhailí: %s"
+
+msgid "E182: Invalid command name"
+msgstr "E182: Ainm neamhbhailí ordaithe"
+
+msgid "E183: User defined commands must start with an uppercase letter"
+msgstr ""
+"E183: Caithfidh ceannlitir a bheith ar dtús orduithe atá sainithe ag an "
+"úsáideoir"
+
+msgid "E841: Reserved name, cannot be used for user defined command"
+msgstr ""
+"E841: Ainm in áirithe, ní féidir é a chur ar ordú sainithe ag an úsáideoir"
+
+#, c-format
+msgid "E184: No such user-defined command: %s"
+msgstr "E184: Níl a leithéid d'ordú saincheaptha: %s"
+
+#, c-format
+msgid "E180: Invalid address type value: %s"
+msgstr "E180: Cineál neamhbhailí seolta: %s"
+
+#, c-format
+msgid "E180: Invalid complete value: %s"
+msgstr "E180: Luach iomlán neamhbhailí: %s"
+
+msgid "E468: Completion argument only allowed for custom completion"
+msgstr ""
+"E468: Ní cheadaítear argóint chomhlánaithe ach le comhlánú saincheaptha"
+
+msgid "E467: Custom completion requires a function argument"
+msgstr "E467: Tá gá le hargóint fheidhme le comhlánú saincheaptha"
+
+msgid "unknown"
+msgstr "anaithnid"
+
+#, c-format
+msgid "E185: Cannot find color scheme '%s'"
+msgstr "E185: Scéim dathanna '%s' gan aimsiú"
+
+msgid "Greetings, Vim user!"
+msgstr "Dia duit, a úsáideoir Vim!"
+
+msgid "E784: Cannot close last tab page"
+msgstr "E784: Ní féidir an leathanach cluaisíní deiridh a dhúnadh"
+
+msgid "Already only one tab page"
+msgstr "Níl ach leathanach cluaisíní amháin cheana féin"
+
+msgid "Edit File in new window"
+msgstr "Cuir comhad in eagar i bhfuinneog nua"
+
+#, c-format
+msgid "Tab page %d"
+msgstr "Leathanach cluaisín %d"
+
+msgid "No swap file"
+msgstr "Níl aon chomhad babhtála ann"
+
+msgid "Append File"
+msgstr "Ceangail Comhad ag an Deireadh"
+
+msgid "E747: Cannot change directory, buffer is modified (add ! to override)"
+msgstr ""
+"E747: Ní féidir an chomhadlann a athrú, mionathraíodh an maolán (cuir ! leis "
+"an ordú chun sárú)"
+
+msgid "E186: No previous directory"
+msgstr "E186: Níl aon chomhadlann roimhe seo"
+
+msgid "E187: Unknown"
+msgstr "E187: Anaithnid"
+
+msgid "E465: :winsize requires two number arguments"
+msgstr "E465: ní foláir dhá argóint uimhriúla le :winsize"
+
+#, c-format
+msgid "Window position: X %d, Y %d"
+msgstr "Ionad na fuinneoige: X %d, Y %d"
+
+msgid "E188: Obtaining window position not implemented for this platform"
+msgstr "E188: Ní féidir ionad na fuinneoige a fháil amach ar an gcóras seo"
+
+msgid "E466: :winpos requires two number arguments"
+msgstr "E466: dhá argóint uimhriúla de dhíth le :winpos"
+
+msgid "E930: Cannot use :redir inside execute()"
+msgstr "E930: Ní féidir :redir a úsáid laistigh de execute()"
+
+msgid "Save Redirection"
+msgstr "Sábháil Atreorú"
+
+msgid "Save View"
+msgstr "Sábháil an tAmharc"
+
+msgid "Save Session"
+msgstr "Sábháil an Seisiún"
+
+msgid "Save Setup"
+msgstr "Sábháil an Socrú"
+
+#, c-format
+msgid "E739: Cannot create directory: %s"
+msgstr "E739: Ní féidir comhadlann a chruthú: %s"
+
+#, c-format
+msgid "E189: \"%s\" exists (add ! to override)"
+msgstr "E189: Tá \"%s\" ann cheana (cuir ! leis an ordú chun sárú)"
+
+#, c-format
+msgid "E190: Cannot open \"%s\" for writing"
+msgstr "E190: Ní féidir \"%s\" a oscailt chun léamh"
+
+#. set mark
+msgid "E191: Argument must be a letter or forward/backward quote"
+msgstr "E191: Caithfidh an argóint a bheith litir nó comhartha athfhriotal"
+
+msgid "E192: Recursive use of :normal too deep"
+msgstr "E192: athchúrsáil :normal ródhomhain"
+
+msgid "E809: #< is not available without the +eval feature"
+msgstr "E809: níl #< ar fáil gan ghné +eval"
+
+msgid "E194: No alternate file name to substitute for '#'"
+msgstr "E194: Níl aon ainm comhaid a chur in ionad '#'"
+
+msgid "E495: no autocommand file name to substitute for \"<afile>\""
+msgstr "E495: níl aon ainm comhaid uathordaithe le cur in ionad \"<afile>\""
+
+msgid "E496: no autocommand buffer number to substitute for \"<abuf>\""
+msgstr "E496: níl aon uimhir mhaolán uathordaithe le cur in ionad \"<abuf>\""
+
+msgid "E497: no autocommand match name to substitute for \"<amatch>\""
+msgstr ""
+"E497: níl aon ainm meaitseála uathordaithe le cur in ionad \"<amatch>\""
+
+msgid "E498: no :source file name to substitute for \"<sfile>\""
+msgstr "E498: níl aon ainm comhaid :source le cur in ionad \"<sfile>\""
+
+msgid "E842: no line number to use for \"<slnum>\""
+msgstr "E842: níl aon líne-uimhir ar fáil le haghaidh \"<slnum>\""
+
+#, no-c-format
+msgid "E499: Empty file name for '%' or '#', only works with \":p:h\""
+msgstr ""
+"E499: Ainm comhaid folamh le haghaidh '%' nó '#', oibreoidh sé le \":p:h\" "
+"amháin"
+
+msgid "E500: Evaluates to an empty string"
+msgstr "E500: Luacháiltear é seo mar theaghrán folamh"
+
+msgid "E195: Cannot open viminfo file for reading"
+msgstr "E195: Ní féidir an comhad viminfo a oscailt chun léamh"
+
+msgid "E196: No digraphs in this version"
+msgstr "E196: Ní cheadaítear déghraif sa leagan seo"
+
+msgid "E608: Cannot :throw exceptions with 'Vim' prefix"
+msgstr "E608: Ní féidir eisceachtaí a :throw le réimír 'Vim'"
+
+#. always scroll up, don't overwrite
+#, c-format
+msgid "Exception thrown: %s"
+msgstr "Gineadh eisceacht: %s"
+
+#, c-format
+msgid "Exception finished: %s"
+msgstr "Eisceacht curtha i gcrích: %s"
+
+#, c-format
+msgid "Exception discarded: %s"
+msgstr "Eisceacht curtha i leataobh: %s"
+
+#, c-format
+msgid "%s, line %ld"
+msgstr "%s, líne %ld"
+
+#. always scroll up, don't overwrite
+#, c-format
+msgid "Exception caught: %s"
+msgstr "Láimhseáladh eisceacht: %s"
+
+#, c-format
+msgid "%s made pending"
+msgstr "%s ar feitheamh anois"
+
+#, c-format
+msgid "%s resumed"
+msgstr "atosaíodh %s"
+
+#, c-format
+msgid "%s discarded"
+msgstr "%s curtha i leataobh"
+
+msgid "Exception"
+msgstr "Eisceacht"
+
+msgid "Error and interrupt"
+msgstr "Earráid agus idirbhriseadh"
+
+msgid "Error"
+msgstr "Earráid"
+
+#. if (pending & CSTP_INTERRUPT)
+msgid "Interrupt"
+msgstr "Idirbhriseadh"
+
+msgid "E579: :if nesting too deep"
+msgstr "E579: :if neadaithe ródhomhain"
+
+msgid "E580: :endif without :if"
+msgstr "E580: :endif gan :if"
+
+msgid "E581: :else without :if"
+msgstr "E581: :else gan :if"
+
+msgid "E582: :elseif without :if"
+msgstr "E582: :elseif gan :if"
+
+msgid "E583: multiple :else"
+msgstr "E583: :else iomadúla"
+
+msgid "E584: :elseif after :else"
+msgstr "E584: :elseif i ndiaidh :else"
+
+msgid "E585: :while/:for nesting too deep"
+msgstr "E585: :while/:for neadaithe ródhomhain"
+
+msgid "E586: :continue without :while or :for"
+msgstr "E586: :continue gan :while ná :for"
+
+msgid "E587: :break without :while or :for"
+msgstr "E587: :break gan :while ná :for"
+
+msgid "E732: Using :endfor with :while"
+msgstr "E732: :endfor á úsáid le :while"
+
+msgid "E733: Using :endwhile with :for"
+msgstr "E733: :endwhile á úsáid le :for"
+
+msgid "E601: :try nesting too deep"
+msgstr "E601: :try neadaithe ródhomhain"
+
+msgid "E603: :catch without :try"
+msgstr "E603: :catch gan :try"
+
+#. Give up for a ":catch" after ":finally" and ignore it.
+#. * Just parse.
+msgid "E604: :catch after :finally"
+msgstr "E604: :catch i ndiaidh :finally"
+
+msgid "E606: :finally without :try"
+msgstr "E606: :finally gan :try"
+
+#. Give up for a multiple ":finally" and ignore it.
+msgid "E607: multiple :finally"
+msgstr "E607: :finally iomadúla"
+
+msgid "E602: :endtry without :try"
+msgstr "E602: :endtry gan :try"
+
+msgid "E193: :endfunction not inside a function"
+msgstr "E193: Caithfidh :endfunction a bheith isteach i bhfeidhm"
+
+msgid "E788: Not allowed to edit another buffer now"
+msgstr "E788: Níl cead agat maolán eile a chur in eagar anois"
+
+msgid "E811: Not allowed to change buffer information now"
+msgstr "E811: Níl cead agat faisnéis an mhaoláin a athrú anois"
+
+msgid "tagname"
+msgstr "clibainm"
+
+msgid " kind file\n"
+msgstr " cineál comhaid\n"
+
+msgid "'history' option is zero"
+msgstr "tá an rogha 'history' nialas"
+
+#, c-format
+msgid ""
+"\n"
+"# %s History (newest to oldest):\n"
+msgstr ""
+"\n"
+"# %s Stair (is nuaí go dtí is sine):\n"
+
+# this gets plugged into the %s in the previous string,
+# hence the colon
+msgid "Command Line"
+msgstr "Líne na nOrduithe:"
+
+msgid "Search String"
+msgstr "Teaghrán Cuardaigh"
+
+msgid "Expression"
+msgstr "Sloinn:"
+
+msgid "Input Line"
+msgstr "Líne an Ionchuir:"
+
+msgid "Debug Line"
+msgstr "Líne Dhífhabhtaithe"
+
+msgid "E198: cmd_pchar beyond the command length"
+msgstr "E198: cmd_pchar os cionn fad an ordaithe"
+
+msgid "E199: Active window or buffer deleted"
+msgstr "E199: Scriosadh an fhuinneog reatha nó an maolán reatha"
+
+msgid "E812: Autocommands changed buffer or buffer name"
+msgstr "E812: Bhí maolán nó ainm maoláin athraithe ag orduithe uathoibríocha"
+
+msgid "Illegal file name"
+msgstr "Ainm comhaid neamhcheadaithe"
+
+msgid "is a directory"
+msgstr "is comhadlann é"
+
+msgid "is not a file"
+msgstr "ní comhad é"
+
+msgid "is a device (disabled with 'opendevice' option)"
+msgstr "is gléas é seo (díchumasaithe le rogha 'opendevice')"
+
+msgid "[New File]"
+msgstr "[Comhad Nua]"
+
+msgid "[New DIRECTORY]"
+msgstr "[COMHADLANN nua]"
+
+msgid "[File too big]"
+msgstr "[Comhad rómhór]"
+
+msgid "[Permission Denied]"
+msgstr "[Cead Diúltaithe]"
+
+msgid "E200: *ReadPre autocommands made the file unreadable"
+msgstr "E200: Rinne uathorduithe *ReadPre praiseach as an chomhad"
+
+msgid "E201: *ReadPre autocommands must not change current buffer"
+msgstr "E201: Ní cheadaítear d'uathorduithe *ReadPre an maolán reatha a athrú"
+
+msgid "Vim: Reading from stdin...\n"
+msgstr "Vim: Ag léamh ón ionchur caighdeánach...\n"
+
+msgid "Reading from stdin..."
+msgstr "Ag léamh ón ionchur caighdeánach..."
+
+#. Re-opening the original file failed!
+msgid "E202: Conversion made file unreadable!"
+msgstr "E202: Comhad doléite i ndiaidh an tiontaithe!"
+
+msgid "[fifo/socket]"
+msgstr "[fifo/soicéad]"
+
+# `TITA' ?! -KPS
+msgid "[fifo]"
+msgstr "[fifo]"
+
+msgid "[socket]"
+msgstr "[soicéad]"
+
+msgid "[character special]"
+msgstr "[comhad speisialta den chineál carachtar]"
+
+msgid "[CR missing]"
+msgstr "[CR ar iarraidh]"
+
+msgid "[long lines split]"
+msgstr "[línte fada deighilte]"
+
+msgid "[NOT converted]"
+msgstr "[NÍ tiontaithe]"
+
+msgid "[converted]"
+msgstr "[tiontaithe]"
+
+#, c-format
+msgid "[CONVERSION ERROR in line %ld]"
+msgstr "[EARRÁID TIONTAITHE i líne %ld]"
+
+#, c-format
+msgid "[ILLEGAL BYTE in line %ld]"
+msgstr "[BEART NEAMHCHEADAITHE i líne %ld]"
+
+msgid "[READ ERRORS]"
+msgstr "[EARRÁIDÍ LÉIMH]"
+
+msgid "Can't find temp file for conversion"
+msgstr "Ní féidir comhad sealadach a aimsiú le haghaidh tiontaithe"
+
+msgid "Conversion with 'charconvert' failed"
+msgstr "Theip ar thiontú le 'charconvert'"
+
+msgid "can't read output of 'charconvert'"
+msgstr "ní féidir an t-aschur ó 'charconvert' a léamh"
+
+msgid "E676: No matching autocommands for acwrite buffer"
+msgstr "E676: Níl aon uathordú comhoiriúnaithe le haghaidh maoláin acwrite"
+
+msgid "E203: Autocommands deleted or unloaded buffer to be written"
+msgstr "E203: Scrios nó dhíluchtaigh uathorduithe an maolán le scríobh"
+
+msgid "E204: Autocommand changed number of lines in unexpected way"
+msgstr "E204: D'athraigh uathordú líon na línte gan choinne"
+
+msgid "NetBeans disallows writes of unmodified buffers"
+msgstr "Ní cheadaíonn NetBeans maoláin gan athrú a bheith scríofa"
+
+msgid "Partial writes disallowed for NetBeans buffers"
+msgstr "Ní cheadaítear maoláin NetBeans a bheith scríofa go neamhiomlán"
+
+msgid "is not a file or writable device"
+msgstr "ní comhad ná gléas inscríofa á"
+
+msgid "writing to device disabled with 'opendevice' option"
+msgstr "díchumasaíodh scríobh chuig gléas le rogha 'opendevice'"
+
+msgid "is read-only (add ! to override)"
+msgstr "is inléite amháin é (cuir ! leis an ordú chun sárú)"
+
+msgid "E506: Can't write to backup file (add ! to override)"
+msgstr ""
+"E506: Ní féidir scríobh a dhéanamh sa chomhad cúltaca (úsáid ! chun sárú)"
+
+msgid "E507: Close error for backup file (add ! to override)"
+msgstr ""
+"E507: Earráid agus comhad cúltaca á dhúnadh (cuir ! leis an ordú chun sárú)"
+
+msgid "E508: Can't read file for backup (add ! to override)"
+msgstr ""
+"E508: Ní féidir an comhad cúltaca a léamh (cuir ! leis an ordú chun sárú)"
+
+msgid "E509: Cannot create backup file (add ! to override)"
+msgstr ""
+"E509: Ní féidir comhad cúltaca a chruthú (cuir ! leis an ordú chun sárú)"
+
+msgid "E510: Can't make backup file (add ! to override)"
+msgstr ""
+"E510: Ní féidir comhad cúltaca a chruthú (cuir ! leis an ordú chun sárú)"
+
+msgid "E460: The resource fork would be lost (add ! to override)"
+msgstr "E460: Chaillfí an forc acmhainne (cuir ! leis an ordú chun sárú)"
+
+msgid "E214: Can't find temp file for writing"
+msgstr "E214: Ní féidir comhad sealadach a aimsiú chun scríobh ann"
+
+msgid "E213: Cannot convert (add ! to write without conversion)"
+msgstr "E213: Ní féidir tiontú (cuir ! leis an ordú chun scríobh gan tiontú)"
+
+msgid "E166: Can't open linked file for writing"
+msgstr "E166: Ní féidir comhad nasctha a oscailt chun scríobh ann"
+
+msgid "E212: Can't open file for writing"
+msgstr "E212: Ní féidir comhad a oscailt chun scríobh ann"
+
+msgid "E667: Fsync failed"
+msgstr "E667: Theip ar fsync"
+
+msgid "E512: Close failed"
+msgstr "E512: Theip ar dúnadh"
+
+msgid "E513: write error, conversion failed (make 'fenc' empty to override)"
+msgstr ""
+"E513: earráid le linn scríobh, theip ar thiontú (úsáid 'fenc' folamh chun "
+"sárú)"
+
+#, c-format
+msgid ""
+"E513: write error, conversion failed in line %ld (make 'fenc' empty to "
+"override)"
+msgstr ""
+"E513: earráid le linn scríofa, theip ar thiontú ar líne %ld (úsáid 'fenc' "
+"folamh le sárú)"
+
+msgid "E514: write error (file system full?)"
+msgstr "E514: earráid le linn scríofa (an bhfuil an córas comhaid lán?)"
+
+msgid " CONVERSION ERROR"
+msgstr " EARRÁID TIONTAITHE"
+
+#, c-format
+msgid " in line %ld;"
+msgstr " ar líne %ld;"
+
+msgid "[Device]"
+msgstr "[Gléas]"
+
+msgid "[New]"
+msgstr "[Nua]"
+
+msgid " [a]"
+msgstr " [a]"
+
+msgid " appended"
+msgstr " iarcheangailte"
+
+msgid " [w]"
+msgstr " [w]"
+
+msgid " written"
+msgstr " scríofa"
+
+msgid "E205: Patchmode: can't save original file"
+msgstr "E205: Patchmode: ní féidir an comhad bunúsach a shábháil"
+
+msgid "E206: patchmode: can't touch empty original file"
+msgstr "E206: patchmode: ní féidir an comhad bunúsach folamh a theagmháil"
+
+msgid "E207: Can't delete backup file"
+msgstr "E207: Ní féidir an comhad cúltaca a scriosadh"
+
+msgid ""
+"\n"
+"WARNING: Original file may be lost or damaged\n"
+msgstr ""
+"\n"
+"RABHADH: Is féidir gur caillte nó loite an comhad bunúsach\n"
+
+msgid "don't quit the editor until the file is successfully written!"
+msgstr "ná scoir go dtí go scríobhfaí an comhad!"
+
+msgid "[dos]"
+msgstr "[dos]"
+
+msgid "[dos format]"
+msgstr "[formáid dos]"
+
+msgid "[mac]"
+msgstr "[mac]"
+
+msgid "[mac format]"
+msgstr "[formáid mac]"
+
+msgid "[unix]"
+msgstr "[unix]"
+
+msgid "[unix format]"
+msgstr "[formáid unix]"
+
+msgid "1 line, "
+msgstr "1 líne, "
+
+#, c-format
+msgid "%ld lines, "
+msgstr "%ld líne, "
+
+msgid "1 character"
+msgstr "1 carachtar"
+
+#, c-format
+msgid "%lld characters"
+msgstr "%lld carachtar"
+
+msgid "[noeol]"
+msgstr "[ganEOL]"
+
+msgid "[Incomplete last line]"
+msgstr "[Is neamhiomlán an líne dheireanach]"
+
+#. don't overwrite messages here
+#. must give this prompt
+#. don't use emsg() here, don't want to flush the buffers
+msgid "WARNING: The file has been changed since reading it!!!"
+msgstr "RABHADH: Athraíodh an comhad ó léadh é!!!"
+
+msgid "Do you really want to write to it"
+msgstr "An bhfuil tú cinnte gur mhaith leat é a scríobh"
+
+#, c-format
+msgid "E208: Error writing to \"%s\""
+msgstr "E208: Earráid agus \"%s\" á scríobh"
+
+#, c-format
+msgid "E209: Error closing \"%s\""
+msgstr "E209: Earráid agus \"%s\" á dhúnadh"
+
+#, c-format
+msgid "E210: Error reading \"%s\""
+msgstr "E210: Earráid agus \"%s\" á léamh"
+
+msgid "E246: FileChangedShell autocommand deleted buffer"
+msgstr "E246: Scrios uathordú FileChangedShell an maolán"
+
+#, c-format
+msgid "E211: File \"%s\" no longer available"
+msgstr "E211: Níl comhad \"%s\" ar fáil feasta"
+
+#, c-format
+msgid ""
+"W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as "
+"well"
+msgstr ""
+"W12: Rabhadh: Athraíodh comhad \"%s\" agus athraíodh an maolán i Vim fosta"
+
+msgid "See \":help W12\" for more info."
+msgstr "Bain triail as \":help W12\" chun tuilleadh eolais a fháil."
+
+#, c-format
+msgid "W11: Warning: File \"%s\" has changed since editing started"
+msgstr "W11: Rabhadh: Athraíodh comhad \"%s\" ó tosaíodh é a chur in eagar"
+
+msgid "See \":help W11\" for more info."
+msgstr "Bain triail as \":help W11\" chun tuilleadh eolais a fháil."
+
+#, c-format
+msgid "W16: Warning: Mode of file \"%s\" has changed since editing started"
+msgstr ""
+"W16: Rabhadh: Athraíodh mód an chomhaid \"%s\" ó tosaíodh é a chur in eagar"
+
+msgid "See \":help W16\" for more info."
+msgstr "Bain triail as \":help W16\" chun tuilleadh eolais a fháil."
+
+#, c-format
+msgid "W13: Warning: File \"%s\" has been created after editing started"
+msgstr "W13: Rabhadh: Cruthaíodh comhad \"%s\" ó tosaíodh é a chur in eagar"
+
+msgid "Warning"
+msgstr "Rabhadh"
+
+msgid ""
+"&OK\n"
+"&Load File"
+msgstr ""
+"&OK\n"
+"&Luchtaigh Comhad"
+
+#, c-format
+msgid "E462: Could not prepare for reloading \"%s\""
+msgstr "E462: Ní féidir \"%s\" a ullmhú le haghaidh athluchtaithe"
+
+#, c-format
+msgid "E321: Could not reload \"%s\""
+msgstr "E321: Ní féidir \"%s\" a athluchtú"
+
+msgid "--Deleted--"
+msgstr "--Scriosta--"
+
+#, c-format
+msgid "auto-removing autocommand: %s <buffer=%d>"
+msgstr "uathordú á bhaint go huathoibríoch: %s <maolán=%d>"
+
+#. the group doesn't exist
+#, c-format
+msgid "E367: No such group: \"%s\""
+msgstr "E367: Níl a leithéid de ghrúpa: \"%s\""
+
+msgid "E936: Cannot delete the current group"
+msgstr "E936: Ní féidir an grúpa reatha a scriosadh"
+
+msgid "W19: Deleting augroup that is still in use"
+msgstr "W19: Iarracht ar augroup atá fós in úsáid a scriosadh"
+
+#, c-format
+msgid "E215: Illegal character after *: %s"
+msgstr "E215: Carachtar neamhcheadaithe i ndiaidh *: %s"
+
+#, c-format
+msgid "E216: No such event: %s"
+msgstr "E216: Níl a leithéid de theagmhas: %s"
+
+#, c-format
+msgid "E216: No such group or event: %s"
+msgstr "E216: Níl a leithéid de ghrúpa nó theagmhas: %s"
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Autocommands ---"
+msgstr ""
+"\n"
+"--- Uathorduithe ---"
+
+#, c-format
+msgid "E680: <buffer=%d>: invalid buffer number "
+msgstr "E680: <maolán=%d>: uimhir neamhbhailí mhaoláin "
+
+msgid "E217: Can't execute autocommands for ALL events"
+msgstr "E217: Ní féidir uathorduithe a rith i gcomhair teagmhas UILE"
+
+msgid "No matching autocommands"
+msgstr "Níl aon uathordú comhoiriúnaithe"
+
+msgid "E218: autocommand nesting too deep"
+msgstr "E218: uathordú neadaithe ródhomhain"
+
+#, c-format
+msgid "%s Autocommands for \"%s\""
+msgstr "%s Uathorduithe do \"%s\""
+
+#, c-format
+msgid "Executing %s"
+msgstr "%s á rith"
+
+#, c-format
+msgid "autocommand %s"
+msgstr "uathordú %s"
+
+msgid "E219: Missing {."
+msgstr "E219: { ar iarraidh."
+
+msgid "E220: Missing }."
+msgstr "E220: } ar iarraidh."
+
+msgid "E490: No fold found"
+msgstr "E490: Níor aimsíodh aon fhilleadh"
+
+msgid "E350: Cannot create fold with current 'foldmethod'"
+msgstr "E350: Ní féidir filleadh a chruthú leis an 'foldmethod' reatha"
+
+msgid "E351: Cannot delete fold with current 'foldmethod'"
+msgstr "E351: Ní féidir filleadh a scriosadh leis an 'foldmethod' reatha"
+
+msgid "E222: Add to read buffer"
+msgstr "E222: Cuir leis an maolán léite"
+
+msgid "E223: recursive mapping"
+msgstr "E223: mapáil athchúrsach"
+
+#, c-format
+msgid "E224: global abbreviation already exists for %s"
+msgstr "E224: tá giorrúchán comhchoiteann ann cheana le haghaidh %s"
+
+#, c-format
+msgid "E225: global mapping already exists for %s"
+msgstr "E225: tá mapáil chomhchoiteann ann cheana le haghaidh %s"
+
+#, c-format
+msgid "E226: abbreviation already exists for %s"
+msgstr "E226: tá giorrúchán ann cheana le haghaidh %s"
+
+#, c-format
+msgid "E227: mapping already exists for %s"
+msgstr "E227: tá mapáil ann cheana le haghaidh %s"
+
+msgid "No abbreviation found"
+msgstr "Níor aimsíodh aon ghiorrúchán"
+
+msgid "No mapping found"
+msgstr "Níor aimsíodh aon mhapáil"
+
+msgid "E228: makemap: Illegal mode"
+msgstr "E228: makemap: Mód neamhcheadaithe"
+
+msgid "E851: Failed to create a new process for the GUI"
+msgstr "E851: Níorbh fhéidir próiseas nua a chruthú don GUI"
+
+msgid "E852: The child process failed to start the GUI"
+msgstr "E852: Theip ar an macphróiseas an GUI a thosú"
+
+msgid "E229: Cannot start the GUI"
+msgstr "E229: Ní féidir an GUI a chur ag obair"
+
+#, c-format
+msgid "E230: Cannot read from \"%s\""
+msgstr "E230: Ní féidir léamh ó \"%s\""
+
+msgid "E665: Cannot start GUI, no valid font found"
+msgstr ""
+"E665: Ní féidir an GUI a chur ag obair, níl aon chlófhoireann bhailí ann"
+
+msgid "E231: 'guifontwide' invalid"
+msgstr "E231: 'guifontwide' neamhbhailí"
+
+msgid "E599: Value of 'imactivatekey' is invalid"
+msgstr "E599: Luach neamhbhailí ar 'imactivatekey'"
+
+#, c-format
+msgid "E254: Cannot allocate color %s"
+msgstr "E254: Ní féidir dath %s a dháileadh"
+
+msgid "No match at cursor, finding next"
+msgstr "Níl a leithéid ag an chúrsóir, ag cuardach ar an chéad cheann eile"
+
+msgid "<cannot open> "
+msgstr "<ní féidir a oscailt> "
+
+#, c-format
+msgid "E616: vim_SelFile: can't get font %s"
+msgstr "E616: vim_SelFile: níl aon fháil ar an chlófhoireann %s"
+
+msgid "E614: vim_SelFile: can't return to current directory"
+msgstr "E614: vim_SelFile: ní féidir dul ar ais go dtí an chomhadlann reatha"
+
+msgid "Pathname:"
+msgstr "Conair:"
+
+msgid "E615: vim_SelFile: can't get current directory"
+msgstr "E615: vim_SelFile: níl an chomhadlann reatha ar fáil"
+
+msgid "OK"
+msgstr "OK"
+
+msgid "Cancel"
+msgstr "Cealaigh"
+
+msgid "Scrollbar Widget: Could not get geometry of thumb pixmap."
+msgstr ""
+"Giuirléid Scrollbharra: Ní féidir céimseata an mhapa picteilíní a fháil."
+
+msgid "Vim dialog"
+msgstr "Dialóg Vim"
+
+msgid "E232: Cannot create BalloonEval with both message and callback"
+msgstr ""
+"E232: Ní féidir BalloonEval a chruthú le teachtaireacht agus aisghlaoch araon"
+
+msgid "_Cancel"
+msgstr "_Cealaigh"
+
+msgid "_Save"
+msgstr "_Sábháil"
+
+msgid "_Open"
+msgstr "_Oscail"
+
+msgid "_OK"
+msgstr "_OK"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"&Cancel"
+msgstr ""
+"&Tá\n"
+"&Níl\n"
+"&Cealaigh"
+
+msgid "Yes"
+msgstr "Tá"
+
+msgid "No"
+msgstr "Níl"
+
+msgid "Input _Methods"
+msgstr "_Modhanna ionchuir"
+
+# in OLT --KPS
+msgid "VIM - Search and Replace..."
+msgstr "VIM - Cuardaigh agus Athchuir..."
+
+msgid "VIM - Search..."
+msgstr "VIM - Cuardaigh..."
+
+msgid "Find what:"
+msgstr "Aimsigh:"
+
+msgid "Replace with:"
+msgstr "Le cur in ionad:"
+
+#. whole word only button
+msgid "Match whole word only"
+msgstr "Focal iomlán amháin"
+
+#. match case button
+msgid "Match case"
+msgstr "Meaitseáil an cás"
+
+msgid "Direction"
+msgstr "Treo"
+
+#. 'Up' and 'Down' buttons
+msgid "Up"
+msgstr "Suas"
+
+msgid "Down"
+msgstr "Síos"
+
+msgid "Find Next"
+msgstr "An Chéad Cheann Eile"
+
+msgid "Replace"
+msgstr "Ionadaigh"
+
+msgid "Replace All"
+msgstr "Ionadaigh Uile"
+
+msgid "_Close"
+msgstr "_Dún"
+
+msgid "Vim: Received \"die\" request from session manager\n"
+msgstr "Vim: Fuarthas iarratas \"die\" ó bhainisteoir an tseisiúin\n"
+
+msgid "Close tab"
+msgstr "Dún cluaisín"
+
+msgid "New tab"
+msgstr "Cluaisín nua"
+
+msgid "Open Tab..."
+msgstr "Oscail Cluaisín..."
+
+msgid "Vim: Main window unexpectedly destroyed\n"
+msgstr "Vim: Milleadh an príomhfhuinneog gan choinne\n"
+
+msgid "&Filter"
+msgstr "&Scagaire"
+
+msgid "&Cancel"
+msgstr "&Cealaigh"
+
+msgid "Directories"
+msgstr "Comhadlanna"
+
+msgid "Filter"
+msgstr "Scagaire"
+
+msgid "&Help"
+msgstr "&Cabhair"
+
+msgid "Files"
+msgstr "Comhaid"
+
+msgid "&OK"
+msgstr "&OK"
+
+msgid "Selection"
+msgstr "Roghnú"
+
+msgid "Find &Next"
+msgstr "An Chéad Chea&nn Eile"
+
+msgid "&Replace"
+msgstr "&Ionadaigh"
+
+msgid "Replace &All"
+msgstr "Ionadaigh &Uile"
+
+msgid "&Undo"
+msgstr "&Cealaigh"
+
+msgid "Open tab..."
+msgstr "Oscail cluaisín..."
+
+msgid "Find string (use '\\\\' to find a '\\')"
+msgstr "Aimsigh teaghrán (bain úsáid as '\\\\' chun '\\' a aimsiú)"
+
+msgid "Find & Replace (use '\\\\' to find a '\\')"
+msgstr "Aimsigh & Athchuir (úsáid '\\\\' chun '\\' a aimsiú)"
+
+#. We fake this: Use a filter that doesn't select anything and a default
+#. * file name that won't be used.
+msgid "Not Used"
+msgstr "Gan Úsáid"
+
+msgid "Directory\t*.nothing\n"
+msgstr "Comhadlann\t*.neamhní\n"
+
+#, c-format
+msgid "E671: Cannot find window title \"%s\""
+msgstr "E671: Ní féidir teideal na fuinneoige \"%s\" a aimsiú"
+
+#, c-format
+msgid "E243: Argument not supported: \"-%s\"; Use the OLE version."
+msgstr "E243: Argóint gan tacaíocht: \"-%s\"; Bain úsáid as an leagan OLE."
+
+msgid "E672: Unable to open window inside MDI application"
+msgstr "E672: Ní féidir fuinneog a oscailt isteach i bhfeidhmchlár MDI"
+
+msgid "Vim E458: Cannot allocate colormap entry, some colors may be incorrect"
+msgstr ""
+"Vim E458: Ní féidir iontráil dathmhapála a dháileadh, is féidir go mbeidh "
+"dathanna míchearta ann"
+
+#, c-format
+msgid "E250: Fonts for the following charsets are missing in fontset %s:"
+msgstr ""
+"E250: Clónna ar iarraidh le haghaidh na dtacar carachtar i dtacar cló %s:"
+
+#, c-format
+msgid "E252: Fontset name: %s"
+msgstr "E252: Ainm an tacar cló: %s"
+
+#, c-format
+msgid "Font '%s' is not fixed-width"
+msgstr "Ní cló aonleithid é '%s'"
+
+#, c-format
+msgid "E253: Fontset name: %s"
+msgstr "E253: Ainm an tacar cló: %s"
+
+#, c-format
+msgid "Font0: %s"
+msgstr "Cló0: %s"
+
+#, c-format
+msgid "Font1: %s"
+msgstr "Cló1: %s"
+
+#, c-format
+msgid "Font%ld width is not twice that of font0"
+msgstr "Níl Cló%ld níos leithne faoi dhó ná cló0"
+
+#, c-format
+msgid "Font0 width: %ld"
+msgstr "Leithead Cló0: %ld"
+
+#, c-format
+msgid "Font1 width: %ld"
+msgstr "Leithead cló1: %ld"
+
+msgid "Invalid font specification"
+msgstr "Sonrú neamhbhailí cló"
+
+msgid "&Dismiss"
+msgstr "&Ruaig"
+
+msgid "no specific match"
+msgstr "níl a leithéid ann"
+
+msgid "Vim - Font Selector"
+msgstr "Vim - Roghnú Cló"
+
+msgid "Name:"
+msgstr "Ainm:"
+
+#. create toggle button
+msgid "Show size in Points"
+msgstr "Taispeáin méid (Pointí)"
+
+msgid "Encoding:"
+msgstr "Ionchódú:"
+
+msgid "Font:"
+msgstr "Cló:"
+
+msgid "Style:"
+msgstr "Stíl:"
+
+msgid "Size:"
+msgstr "Méid:"
+
+msgid "E256: Hangul automata ERROR"
+msgstr "E256: EARRÁID leis na huathoibreáin Hangul"
+
+msgid "E550: Missing colon"
+msgstr "E550: Idirstad ar iarraidh"
+
+msgid "E551: Illegal component"
+msgstr "E551: Comhpháirt neamhcheadaithe"
+
+msgid "E552: digit expected"
+msgstr "E552: ag súil le digit"
+
+#, c-format
+msgid "Page %d"
+msgstr "Leathanach %d"
+
+msgid "No text to be printed"
+msgstr "Níl aon téacs le priontáil"
+
+#, c-format
+msgid "Printing page %d (%d%%)"
+msgstr "Leathanach %d (%d%%) á phriontáil"
+
+#, c-format
+msgid " Copy %d of %d"
+msgstr " Cóip %d de %d"
+
+#, c-format
+msgid "Printed: %s"
+msgstr "Priontáilte: %s"
+
+msgid "Printing aborted"
+msgstr "Priontáil tobscortha"
+
+msgid "E455: Error writing to PostScript output file"
+msgstr "E455: Earráid le linn scríobh chuig aschomhad PostScript"
+
+#, c-format
+msgid "E624: Can't open file \"%s\""
+msgstr "E624: Ní féidir an comhad \"%s\" a oscailt"
+
+#, c-format
+msgid "E457: Can't read PostScript resource file \"%s\""
+msgstr "E457: Ní féidir comhad acmhainne PostScript \"%s\" a léamh"
+
+#, c-format
+msgid "E618: file \"%s\" is not a PostScript resource file"
+msgstr "E618: Níl comhad \"%s\" ina chomhad acmhainne PostScript"
+
+#, c-format
+msgid "E619: file \"%s\" is not a supported PostScript resource file"
+msgstr "E619: Tá \"%s\" ina chomhad acmhainne PostScript gan tacú"
+
+#, c-format
+msgid "E621: \"%s\" resource file has wrong version"
+msgstr "E621: Tá an leagan mícheart ar an gcomhad acmhainne \"%s\""
+
+msgid "E673: Incompatible multi-byte encoding and character set."
+msgstr "E673: Ionchódú agus tacar carachtar ilbhirt neamh-chomhoiriúnach."
+
+msgid "E674: printmbcharset cannot be empty with multi-byte encoding."
+msgstr ""
+"E674: ní cheadaítear printmbcharset a bheith folamh le hionchódú ilbhirt."
+
+msgid "E675: No default font specified for multi-byte printing."
+msgstr "E675: Níor réamhshocraíodh cló le haghaidh priontála ilbhirt."
+
+msgid "E324: Can't open PostScript output file"
+msgstr "E324: Ní féidir aschomhad PostScript a oscailt"
+
+#, c-format
+msgid "E456: Can't open file \"%s\""
+msgstr "E456: Ní féidir an comhad \"%s\" a oscailt"
+
+msgid "E456: Can't find PostScript resource file \"prolog.ps\""
+msgstr "E456: Comhad acmhainne PostScript \"prolog.ps\" gan aimsiú"
+
+msgid "E456: Can't find PostScript resource file \"cidfont.ps\""
+msgstr "E456: Comhad acmhainne PostScript \"cidfont.ps\" gan aimsiú"
+
+#, c-format
+msgid "E456: Can't find PostScript resource file \"%s.ps\""
+msgstr "E456: Comhad acmhainne PostScript \"%s.ps\" gan aimsiú"
+
+#, c-format
+msgid "E620: Unable to convert to print encoding \"%s\""
+msgstr "E620: Ní féidir an t-ionchódú priontála \"%s\" a thiontú"
+
+msgid "Sending to printer..."
+msgstr "Á sheoladh chuig an phrintéir..."
+
+msgid "E365: Failed to print PostScript file"
+msgstr "E365: Theip ar phriontáil comhaid PostScript"
+
+msgid "Print job sent."
+msgstr "Seoladh jab priontála."
+
+msgid "Add a new database"
+msgstr "Bunachar sonraí nua"
+
+msgid "Query for a pattern"
+msgstr "Iarratas ar phatrún"
+
+msgid "Show this message"
+msgstr "Taispeáin an teachtaireacht seo"
+
+msgid "Kill a connection"
+msgstr "Maraigh nasc"
+
+msgid "Reinit all connections"
+msgstr "Atúsaigh gach nasc"
+
+msgid "Show connections"
+msgstr "Taispeáin naisc"
+
+#, c-format
+msgid "E560: Usage: cs[cope] %s"
+msgstr "E560: Úsáid: cs[cope] %s"
+
+msgid "This cscope command does not support splitting the window.\n"
+msgstr "Ní féidir fuinneoga a scoilteadh leis an ordú seo `cscope'.\n"
+
+msgid "E562: Usage: cstag <ident>"
+msgstr "E562: Úsáid: cstag <ident>"
+
+msgid "E257: cstag: tag not found"
+msgstr "E257: cstag: clib gan aimsiú"
+
+#, c-format
+msgid "E563: stat(%s) error: %d"
+msgstr "E563: earráid stat(%s): %d"
+
+msgid "E563: stat error"
+msgstr "E563: earráid stat"
+
+#, c-format
+msgid "E564: %s is not a directory or a valid cscope database"
+msgstr "E564: Níl %s ina comhadlann nó bunachar sonraí cscope bailí"
+
+#, c-format
+msgid "Added cscope database %s"
+msgstr "Bunachar sonraí nua cscope: %s"
+
+#, c-format
+msgid "E262: error reading cscope connection %ld"
+msgstr "E262: earráid agus an nasc cscope %ld á léamh"
+
+msgid "E561: unknown cscope search type"
+msgstr "E561: cineál anaithnid cuardaigh cscope"
+
+msgid "E566: Could not create cscope pipes"
+msgstr "E566: Níorbh fhéidir píopaí cscope a chruthú"
+
+msgid "E622: Could not fork for cscope"
+msgstr "E622: Níorbh fhéidir forc a dhéanamh le haghaidh cscope"
+
+msgid "cs_create_connection setpgid failed"
+msgstr "theip ar setpgid do cs_create_connection"
+
+msgid "cs_create_connection exec failed"
+msgstr "theip ar rith cs_create_connection"
+
+msgid "cs_create_connection: fdopen for to_fp failed"
+msgstr "cs_create_connection: theip ar fdopen le haghaidh to_fp"
+
+msgid "cs_create_connection: fdopen for fr_fp failed"
+msgstr "cs_create_connection: theip ar fdopen le haghaidh fr_fp"
+
+msgid "E623: Could not spawn cscope process"
+msgstr "E623: Níorbh fhéidir próiseas cscope a sceitheadh"
+
+msgid "E567: no cscope connections"
+msgstr "E567: níl aon nasc cscope ann"
+
+#, c-format
+msgid "E469: invalid cscopequickfix flag %c for %c"
+msgstr "E469: bratach neamhbhailí cscopequickfix %c le haghaidh %c"
+
+#, c-format
+msgid "E259: no matches found for cscope query %s of %s"
+msgstr ""
+"E259: níor aimsíodh aon rud comhoiriúnach leis an iarratas cscope %s de %s"
+
+msgid "cscope commands:\n"
+msgstr "Orduithe cscope:\n"
+
+#, c-format
+msgid "%-5s: %s%*s (Usage: %s)"
+msgstr "%-5s: %s%*s (Úsáid: %s)"
+
+msgid ""
+"\n"
+" a: Find assignments to this symbol\n"
+" c: Find functions calling this function\n"
+" d: Find functions called by this function\n"
+" e: Find this egrep pattern\n"
+" f: Find this file\n"
+" g: Find this definition\n"
+" i: Find files #including this file\n"
+" s: Find this C symbol\n"
+" t: Find this text string\n"
+msgstr ""
+"\n"
+" a: Aimsigh ráitis sannacháin leis an tsiombail seo\n"
+" c: Aimsigh feidhmeanna a chuireann glaoch ar an bhfeidhm seo\n"
+" d: Aimsigh feidhmeanna a gcuireann an fheidhm seo glaoch orthu\n"
+" e: Aimsigh an patrún egrep seo\n"
+" f: Aimsigh an comhad seo\n"
+" g: Aimsigh an sainmhíniú seo\n"
+" i: Aimsigh comhaid a #include-áil an comhad seo\n"
+" s: Aimsigh an tsiombail C seo\n"
+" t: Aimsigh an teaghrán téacs seo\n"
+
+#, c-format
+msgid "E625: cannot open cscope database: %s"
+msgstr "E625: ní féidir bunachar sonraí cscope a oscailt: %s"
+
+msgid "E626: cannot get cscope database information"
+msgstr "E626: ní féidir eolas a fháil faoin bhunachar sonraí cscope"
+
+msgid "E568: duplicate cscope database not added"
+msgstr "E568: níor cuireadh bunachar sonraí dúblach cscope leis"
+
+#, c-format
+msgid "E261: cscope connection %s not found"
+msgstr "E261: nasc cscope %s gan aimsiú"
+
+#, c-format
+msgid "cscope connection %s closed"
+msgstr "Dúnadh nasc cscope %s"
+
+#. should not reach here
+msgid "E570: fatal error in cs_manage_matches"
+msgstr "E570: earráid mharfach i cs_manage_matches"
+
+#, c-format
+msgid "Cscope tag: %s"
+msgstr "Clib cscope: %s"
+
+msgid ""
+"\n"
+" # line"
+msgstr ""
+"\n"
+" # líne"
+
+msgid "filename / context / line\n"
+msgstr "ainm comhaid / comhthéacs / líne\n"
+
+#, c-format
+msgid "E609: Cscope error: %s"
+msgstr "E609: Earráid cscope: %s"
+
+msgid "All cscope databases reset"
+msgstr "Athshocraíodh gach bunachar sonraí cscope"
+
+msgid "no cscope connections\n"
+msgstr "níl aon nasc cscope\n"
+
+msgid " # pid database name prepend path\n"
+msgstr " # pid ainm bunachair conair thosaigh\n"
+
+msgid "Lua library cannot be loaded."
+msgstr "Ní féidir an leabharlann Lua a luchtú."
+
+msgid "cannot save undo information"
+msgstr "ní féidir eolas cealaithe a shábháil"
+
+msgid ""
+"E815: Sorry, this command is disabled, the MzScheme libraries could not be "
+"loaded."
+msgstr ""
+"E815: Tá brón orm, bhí an t-ordú seo díchumasaithe, níorbh fhéidir "
+"leabharlanna MzScheme a luchtú."
+
+msgid ""
+"E895: Sorry, this command is disabled, the MzScheme's racket/base module "
+"could not be loaded."
+msgstr ""
+"E895: Ár leithscéal, tá an t-ordú seo díchumasaithe; níorbh fhéidir modúl "
+"racket/base MzScheme a luchtú."
+
+msgid "invalid expression"
+msgstr "slonn neamhbhailí"
+
+msgid "expressions disabled at compile time"
+msgstr "díchumasaíodh sloinn ag am an tiomsaithe"
+
+msgid "hidden option"
+msgstr "rogha fholaithe"
+
+msgid "unknown option"
+msgstr "rogha anaithnid"
+
+msgid "window index is out of range"
+msgstr "innéacs fuinneoige as raon"
+
+msgid "couldn't open buffer"
+msgstr "ní féidir maolán a oscailt"
+
+msgid "cannot delete line"
+msgstr "ní féidir an líne a scriosadh"
+
+msgid "cannot replace line"
+msgstr "ní féidir an líne a athchur"
+
+msgid "cannot insert line"
+msgstr "ní féidir líne a ionsá"
+
+msgid "string cannot contain newlines"
+msgstr "ní cheadaítear carachtair líne nua sa teaghrán"
+
+msgid "error converting Scheme values to Vim"
+msgstr "earráid agus luach Scheme á thiontú go Vim"
+
+msgid "Vim error: ~a"
+msgstr "earráid Vim: ~a"
+
+msgid "Vim error"
+msgstr "earráid Vim"
+
+msgid "buffer is invalid"
+msgstr "maolán neamhbhailí"
+
+msgid "window is invalid"
+msgstr "fuinneog neamhbhailí"
+
+msgid "linenr out of range"
+msgstr "líne-uimhir as raon"
+
+msgid "not allowed in the Vim sandbox"
+msgstr "ní cheadaítear é seo i mbosca gainimh Vim"
+
+msgid "E836: This Vim cannot execute :python after using :py3"
+msgstr ""
+"E836: Ní féidir leis an leagan seo de Vim :python a rith tar éis :py3 a úsáid"
+
+msgid ""
+"E263: Sorry, this command is disabled, the Python library could not be "
+"loaded."
+msgstr ""
+"E263: Tá brón orm, níl an t-ordú seo le fáil, níorbh fhéidir an leabharlann "
+"Python a luchtú."
+
+msgid ""
+"E887: Sorry, this command is disabled, the Python's site module could not be "
+"loaded."
+msgstr ""
+"E887: Ár leithscéal, níl an t-ordú seo le fáil, níorbh fhéidir an modúl "
+"Python a luchtú."
+
+msgid "E659: Cannot invoke Python recursively"
+msgstr "E659: Ní féidir Python a rith go hathchúrsach"
+
+msgid "E837: This Vim cannot execute :py3 after using :python"
+msgstr ""
+"E837: Ní féidir leis an leagan seo de Vim :py3 a rith tar éis :python a úsáid"
+
+msgid "E265: $_ must be an instance of String"
+msgstr "E265: caithfidh $_ a bheith cineál Teaghráin"
+
+msgid ""
+"E266: Sorry, this command is disabled, the Ruby library could not be loaded."
+msgstr ""
+"E266: Tá brón orm, níl an t-ordú seo le fáil, níorbh fhéidir an leabharlann "
+"Ruby a luchtú."
+
+msgid "E267: unexpected return"
+msgstr "E267: \"return\" gan choinne"
+
+msgid "E268: unexpected next"
+msgstr "E268: \"next\" gan choinne"
+
+msgid "E269: unexpected break"
+msgstr "E269: \"break\" gan choinne"
+
+msgid "E270: unexpected redo"
+msgstr "E270: \"redo\" gan choinne"
+
+msgid "E271: retry outside of rescue clause"
+msgstr "E271: \"retry\" taobh amuigh de chlásal tarrthála"
+
+msgid "E272: unhandled exception"
+msgstr "E272: eisceacht gan láimhseáil"
+
+#, c-format
+msgid "E273: unknown longjmp status %d"
+msgstr "E273: stádas anaithnid longjmp %d"
+
+msgid "invalid buffer number"
+msgstr "uimhir neamhbhailí mhaoláin"
+
+msgid "not implemented yet"
+msgstr "níl ar fáil"
+
+#. ???
+msgid "cannot set line(s)"
+msgstr "ní féidir lín(t)e a shocrú"
+
+msgid "invalid mark name"
+msgstr "ainm neamhbhailí mairc"
+
+msgid "mark not set"
+msgstr "marc gan socrú"
+
+#, c-format
+msgid "row %d column %d"
+msgstr "líne %d colún %d"
+
+msgid "cannot insert/append line"
+msgstr "ní féidir líne a ionsá/iarcheangal"
+
+msgid "line number out of range"
+msgstr "líne-uimhir as raon"
+
+msgid "unknown flag: "
+msgstr "bratach anaithnid: "
+
+msgid "unknown vimOption"
+msgstr "vimOption anaithnid"
+
+msgid "keyboard interrupt"
+msgstr "idirbhriseadh méarchláir"
+
+msgid "vim error"
+msgstr "earráid vim"
+
+msgid "cannot create buffer/window command: object is being deleted"
+msgstr "ní féidir ordú maoláin/fuinneoige a chruthú: réad á scriosadh"
+
+msgid ""
+"cannot register callback command: buffer/window is already being deleted"
+msgstr "ní féidir ordú aisghlaoch a chlárú: maolán/fuinneog á scriosadh cheana"
+
+#. This should never happen. Famous last word?
+msgid ""
+"E280: TCL FATAL ERROR: reflist corrupt!? Please report this to vim-dev@vim."
+"org"
+msgstr ""
+"E280: EARRÁID MHARFACH TCL: liosta truaillithe tagartha!? Seol tuairisc "
+"fhabht chuig <vim-dev@vim.org> le do thoil"
+
+msgid "cannot register callback command: buffer/window reference not found"
+msgstr ""
+"ní féidir ordú aisghlaoch a chlárú: tagairt mhaolán/fhuinneoige gan aimsiú"
+
+msgid ""
+"E571: Sorry, this command is disabled: the Tcl library could not be loaded."
+msgstr ""
+"E571: Tá brón orm, níl an t-ordú seo le fáil: níorbh fhéidir an leabharlann "
+"Tcl a luchtú."
+
+#, c-format
+msgid "E572: exit code %d"
+msgstr "E572: cód scortha %d"
+
+msgid "cannot get line"
+msgstr "ní féidir an líne a fháil"
+
+msgid "Unable to register a command server name"
+msgstr "Ní féidir ainm fhreastalaí ordaithe a chlárú"
+
+msgid "E248: Failed to send command to the destination program"
+msgstr "E248: Theip ar sheoladh ordú chuig an sprioc-chlár"
+
+#, c-format
+msgid "E573: Invalid server id used: %s"
+msgstr "E573: Aitheantas neamhbhailí freastalaí in úsáid: %s"
+
+msgid "E251: VIM instance registry property is badly formed. Deleted!"
+msgstr "E251: Airí míchumtha sa chlárlann áisc VIM. Scriosta!"
+
+#, c-format
+msgid "E938: Duplicate key in JSON: \"%s\""
+msgstr "E938: Eochair dhúblach in JSON: \"%s\""
+
+#, c-format
+msgid "E696: Missing comma in List: %s"
+msgstr "E696: Camóg ar iarraidh i Liosta: %s"
+
+#, c-format
+msgid "E697: Missing end of List ']': %s"
+msgstr "E697: ']' ar iarraidh ag deireadh liosta: %s"
+
+msgid "Unknown option argument"
+msgstr "Argóint anaithnid rogha"
+
+msgid "Too many edit arguments"
+msgstr "An iomarca argóintí eagarthóireachta"
+
+msgid "Argument missing after"
+msgstr "Argóint ar iarraidh i ndiaidh"
+
+msgid "Garbage after option argument"
+msgstr "Dramhaíl i ndiaidh argóinte rogha"
+
+msgid "Too many \"+command\", \"-c command\" or \"--cmd command\" arguments"
+msgstr ""
+"An iomarca argóintí den chineál \"+ordú\", \"-c ordú\" nó \"--cmd ordú\""
+
+msgid "Invalid argument for"
+msgstr "Argóint neamhbhailí do"
+
+#, c-format
+msgid "%d files to edit\n"
+msgstr "%d comhad le heagrú\n"
+
+msgid "netbeans is not supported with this GUI\n"
+msgstr "Ní thacaítear le netbeans sa GUI seo\n"
+
+msgid "'-nb' cannot be used: not enabled at compile time\n"
+msgstr "Ní féidir '-nb' a úsáid: níor cumasaíodh é ag am tiomsaithe\n"
+
+msgid "This Vim was not compiled with the diff feature."
+msgstr "Níor tiomsaíodh an leagan Vim seo le `diff' ar fáil."
+
+msgid "Attempt to open script file again: \""
+msgstr "Déan iarracht ar oscailt na scripte arís: \""
+
+msgid "Cannot open for reading: \""
+msgstr "Ní féidir é a oscailt chun léamh: \""
+
+msgid "Cannot open for script output: \""
+msgstr "Ní féidir a oscailt le haghaidh an aschuir scripte: \""
+
+msgid "Vim: Error: Failure to start gvim from NetBeans\n"
+msgstr "Vim: Earráid: Theip ar thosú gvim ó NetBeans\n"
+
+msgid "Vim: Error: This version of Vim does not run in a Cygwin terminal\n"
+msgstr ""
+"Vim: Earráid: Ní féidir an leagan seo de Vim a rith i dteirminéal Cygwin\n"
+
+msgid "Vim: Warning: Output is not to a terminal\n"
+msgstr "Vim: Rabhadh: Níl an t-aschur ag dul chuig teirminéal\n"
+
+msgid "Vim: Warning: Input is not from a terminal\n"
+msgstr "Vim: Rabhadh: Níl an t-ionchur ag teacht ó theirminéal\n"
+
+#. just in case..
+msgid "pre-vimrc command line"
+msgstr "líne na n-orduithe pre-vimrc"
+
+#, c-format
+msgid "E282: Cannot read from \"%s\""
+msgstr "E282: Ní féidir léamh ó \"%s\""
+
+msgid ""
+"\n"
+"More info with: \"vim -h\"\n"
+msgstr ""
+"\n"
+"Tuilleadh eolais: \"vim -h\"\n"
+
+msgid "[file ..] edit specified file(s)"
+msgstr "[comhad ..] cuir na comhaid ceaptha in eagar"
+
+msgid "- read text from stdin"
+msgstr "- scríobh téacs ó stdin"
+
+msgid "-t tag edit file where tag is defined"
+msgstr "-t tag cuir an comhad ina bhfuil an chlib in eagar"
+
+msgid "-q [errorfile] edit file with first error"
+msgstr "-q [comhadearr] cuir comhad leis an chéad earráid in eagar"
+
+msgid ""
+"\n"
+"\n"
+"Usage:"
+msgstr ""
+"\n"
+"\n"
+"úsáid:"
+
+msgid " vim [arguments] "
+msgstr " vim [argóintí] "
+
+msgid ""
+"\n"
+" or:"
+msgstr ""
+"\n"
+" nó:"
+
+msgid ""
+"\n"
+"Where case is ignored prepend / to make flag upper case"
+msgstr ""
+"\n"
+"Nuair nach cásíogair é, cuir '/' ag tosach na brataí chun í a chur sa chás "
+"uachtair"
+
+msgid ""
+"\n"
+"\n"
+"Arguments:\n"
+msgstr ""
+"\n"
+"\n"
+"Argóintí:\n"
+
+msgid "--\t\t\tOnly file names after this"
+msgstr "--\t\t\tNí cheadaítear ach ainmneacha comhaid i ndiaidh é seo"
+
+msgid "--literal\t\tDon't expand wildcards"
+msgstr "--literal\t\tNá leathnaigh saoróga"
+
+msgid "-register\t\tRegister this gvim for OLE"
+msgstr "-register\t\tCláraigh an gvim seo le haghaidh OLE"
+
+msgid "-unregister\t\tUnregister gvim for OLE"
+msgstr "-unregister\t\tDíchláraigh an gvim seo le haghaidh OLE"
+
+msgid "-g\t\t\tRun using GUI (like \"gvim\")"
+msgstr "-g\t\t\tRith agus úsáid an GUI (mar \"gvim\")"
+
+msgid "-f or --nofork\tForeground: Don't fork when starting GUI"
+msgstr "-f nó --nofork\tTulra: Ná déan forc agus an GUI á thosú"
+
+msgid "-v\t\t\tVi mode (like \"vi\")"
+msgstr "-v\t\t\tMód Vi (mar \"vi\")"
+
+msgid "-e\t\t\tEx mode (like \"ex\")"
+msgstr "-e\t\t\tMód Ex (mar \"ex\")"
+
+msgid "-E\t\t\tImproved Ex mode"
+msgstr "-E\t\t\tMód Ex feabhsaithe"
+
+msgid "-s\t\t\tSilent (batch) mode (only for \"ex\")"
+msgstr "-s\t\t\tMód ciúin (baiscphróiseála) (do \"ex\" amháin)"
+
+msgid "-d\t\t\tDiff mode (like \"vimdiff\")"
+msgstr "-d\t\t\tMód diff (mar \"vimdiff\")"
+
+msgid "-y\t\t\tEasy mode (like \"evim\", modeless)"
+msgstr "-y\t\t\tMód éasca (mar \"evim\", gan mhóid)"
+
+msgid "-R\t\t\tReadonly mode (like \"view\")"
+msgstr "-R\t\t\tMód inléite amháin (mar \"view\")"
+
+msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
+msgstr "-Z\t\t\tMód srianta (mar \"rvim\")"
+
+msgid "-m\t\t\tModifications (writing files) not allowed"
+msgstr "-m\t\t\tNí cheadaítear athruithe (.i. scríobh na gcomhad)"
+
+msgid "-M\t\t\tModifications in text not allowed"
+msgstr "-M\t\t\tNí cheadaítear athruithe sa téacs"
+
+msgid "-b\t\t\tBinary mode"
+msgstr "-b\t\t\tMód dénártha"
+
+msgid "-l\t\t\tLisp mode"
+msgstr "-l\t\t\tMód Lisp"
+
+msgid "-C\t\t\tCompatible with Vi: 'compatible'"
+msgstr "-C\t\t\tComhoiriúnach le Vi: 'compatible'"
+
+msgid "-N\t\t\tNot fully Vi compatible: 'nocompatible'"
+msgstr "-N\t\t\tNí comhoiriúnaithe le Vi go hiomlán: 'nocompatible'"
+
+msgid "-V[N][fname]\t\tBe verbose [level N] [log messages to fname]"
+msgstr ""
+"-V[N][fname]\t\tBí foclach [leibhéal N] [logáil teachtaireachtaí i fname]"
+
+msgid "-D\t\t\tDebugging mode"
+msgstr "-D\t\t\tMód dífhabhtaithe"
+
+msgid "-n\t\t\tNo swap file, use memory only"
+msgstr "-n\t\t\tNá húsáid comhad babhtála .i. ná húsáid ach an chuimhne"
+
+msgid "-r\t\t\tList swap files and exit"
+msgstr "-r\t\t\tTaispeáin comhaid bhabhtála agus scoir"
+
+msgid "-r (with file name)\tRecover crashed session"
+msgstr "-r (le hainm comhaid)\tAthshlánaigh ó chliseadh"
+
+msgid "-L\t\t\tSame as -r"
+msgstr "-L\t\t\tAr comhbhrí le -r"
+
+msgid "-f\t\t\tDon't use newcli to open window"
+msgstr "-f\t\t\tNá húsáid newcli chun fuinneog a oscailt"
+
+msgid "-dev <device>\t\tUse <device> for I/O"
+msgstr "-dev <gléas>\t\tBain úsáid as <gléas> do I/A"
+
+msgid "-A\t\t\tStart in Arabic mode"
+msgstr "-A\t\t\tTosaigh sa mhód Araibise"
+
+msgid "-H\t\t\tStart in Hebrew mode"
+msgstr "-H\t\t\tTosaigh sa mhód Eabhraise"
+
+msgid "-F\t\t\tStart in Farsi mode"
+msgstr "-F\t\t\tTosaigh sa mhód Pheirsise"
+
+msgid "-T <terminal>\tSet terminal type to <terminal>"
+msgstr "-T <teirminéal>\tSocraigh cineál teirminéal"
+
+msgid "--not-a-term\t\tSkip warning for input/output not being a terminal"
+msgstr ""
+"--not-a-term\t\tNá bac le rabhadh faoi ionchur/aschur gan a bheith ón "
+"teirminéal"
+
+msgid "--ttyfail\t\tExit if input or output is not a terminal"
+msgstr "--ttyfail\t\tScoir mura bhfuil ionchur agus aschur ina dteirminéil"
+
+msgid "-u <vimrc>\t\tUse <vimrc> instead of any .vimrc"
+msgstr "-u <vimrc>\t\tÚsáid <vimrc> in ionad aon .vimrc"
+
+msgid "-U <gvimrc>\t\tUse <gvimrc> instead of any .gvimrc"
+msgstr "-U <gvimrc>\t\tBain úsáid as <gvimrc> in ionad aon .gvimrc"
+
+msgid "--noplugin\t\tDon't load plugin scripts"
+msgstr "--noplugin\t\tNá luchtaigh breiseáin"
+
+msgid "-p[N]\t\tOpen N tab pages (default: one for each file)"
+msgstr "-p[N]\t\tOscail N leathanach cluaisíní (default: ceann do gach comhad)"
+
+msgid "-o[N]\t\tOpen N windows (default: one for each file)"
+msgstr "-o[N]\t\tOscail N fuinneog (réamhshocrú: ceann do gach comhad)"
+
+msgid "-O[N]\t\tLike -o but split vertically"
+msgstr "-O[N]\t\tMar -o, ach roinn go hingearach"
+
+msgid "+\t\t\tStart at end of file"
+msgstr "+\t\t\tTosaigh ag an chomhadchríoch"
+
+msgid "+<lnum>\t\tStart at line <lnum>"
+msgstr "+<lnum>\t\tTosaigh ar líne <lnum>"
+
+msgid "--cmd <command>\tExecute <command> before loading any vimrc file"
+msgstr "--cmd <ordú>\tRith <ordú> roimh aon chomhad vimrc a luchtú"
+
+msgid "-c <command>\t\tExecute <command> after loading the first file"
+msgstr "-c <ordú>\t\tRith <ordú> i ndiaidh luchtú an chéad chomhad"
+
+msgid "-S <session>\t\tSource file <session> after loading the first file"
+msgstr ""
+"-S <seisiún>\t\tLéigh comhad <seisiún> i ndiaidh an chéad chomhad á léamh"
+
+msgid "-s <scriptin>\tRead Normal mode commands from file <scriptin>"
+msgstr "-s <script>\tLéigh orduithe gnáthmhóid ón chomhad <script>"
+
+msgid "-w <scriptout>\tAppend all typed commands to file <scriptout>"
+msgstr ""
+"-w <script>\tIarcheangail gach ordú iontráilte leis an gcomhad <script>"
+
+msgid "-W <scriptout>\tWrite all typed commands to file <scriptout>"
+msgstr "-W <aschur>\tScríobh gach ordú clóscríofa sa chomhad <aschur>"
+
+msgid "-x\t\t\tEdit encrypted files"
+msgstr "-x\t\t\tCuir comhaid chriptithe in eagar"
+
+msgid "-display <display>\tConnect vim to this particular X-server"
+msgstr "-display <freastalaí>\tNasc vim leis an bhfreastalaí-X seo"
+
+msgid "-X\t\t\tDo not connect to X server"
+msgstr "-X\t\t\tNá naisc leis an bhfreastalaí X"
+
+msgid "--remote <files>\tEdit <files> in a Vim server if possible"
+msgstr ""
+"--remote <comhaid>\tCuir <comhaid> in eagar le freastalaí Vim más féidir"
+
+msgid "--remote-silent <files> Same, don't complain if there is no server"
+msgstr ""
+"--remote-silent <comhaid> Mar an gcéanna, ná déan gearán mura bhfuil "
+"freastalaí ann"
+
+msgid ""
+"--remote-wait <files> As --remote but wait for files to have been edited"
+msgstr ""
+"--remote-wait <comhaid> Mar --remote ach fan leis na comhaid a bheith "
+"curtha in eagar"
+
+msgid ""
+"--remote-wait-silent <files> Same, don't complain if there is no server"
+msgstr ""
+"--remote-wait-silent <comhaid> Mar an gcéanna, ná déan gearán mura bhfuil "
+"freastalaí ann"
+
+msgid ""
+"--remote-tab[-wait][-silent] <files> As --remote but use tab page per file"
+msgstr ""
+"--remote-tab[-wait][-silent] <comhaid> Cosúil le --remote ach oscail "
+"cluaisín do gach comhad"
+
+msgid "--remote-send <keys>\tSend <keys> to a Vim server and exit"
+msgstr ""
+"--remote-send <eochracha>\tSeol <eochracha> chuig freastalaí Vim agus scoir"
+
+msgid "--remote-expr <expr>\tEvaluate <expr> in a Vim server and print result"
+msgstr ""
+"--remote-expr <slonn>\tLuacháil <slonn> le freastalaí Vim agus taispeáin an "
+"toradh"
+
+msgid "--serverlist\t\tList available Vim server names and exit"
+msgstr "--serverlist\t\tTaispeáin freastalaithe Vim atá ar fáil agus scoir"
+
+msgid "--servername <name>\tSend to/become the Vim server <name>"
+msgstr "--servername <ainm>\tSeol chuig/Téigh i do fhreastalaí Vim <ainm>"
+
+msgid "--startuptime <file>\tWrite startup timing messages to <file>"
+msgstr ""
+"--startuptime <comhad>\tScríobh faisnéis maidir le tréimhse tosaithe i "
+"<comhad>"
+
+msgid "-i <viminfo>\t\tUse <viminfo> instead of .viminfo"
+msgstr "-i <viminfo>\t\tÚsáid <viminfo> in ionad .viminfo"
+
+msgid "-h or --help\tPrint Help (this message) and exit"
+msgstr "-h nó --help\tTaispeáin an chabhair seo agus scoir"
+
+msgid "--version\t\tPrint version information and exit"
+msgstr "--version\t\tTaispeáin eolas faoin leagan agus scoir"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Motif version):\n"
+msgstr ""
+"\n"
+"Argóintí ar eolas do gvim (leagan Motif):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (neXtaw version):\n"
+msgstr ""
+"\n"
+"Argóintí ar eolas do gvim (leagan neXtaw):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Athena version):\n"
+msgstr ""
+"\n"
+"Argóintí ar eolas do gvim (leagan Athena):\n"
+
+msgid "-display <display>\tRun vim on <display>"
+msgstr "-display <scáileán>\tRith vim ar <scáileán>"
+
+msgid "-iconic\t\tStart vim iconified"
+msgstr "-iconic\t\tTosaigh vim sa mhód íoslaghdaithe"
+
+msgid "-background <color>\tUse <color> for the background (also: -bg)"
+msgstr "-background <dath>\tBain úsáid as <dath> don chúlra (-bg fosta)"
+
+msgid "-foreground <color>\tUse <color> for normal text (also: -fg)"
+msgstr "-foreground <dath>\tÚsáid <dath> le haghaidh gnáth-théacs (fosta: -fg)"
+
+msgid "-font <font>\t\tUse <font> for normal text (also: -fn)"
+msgstr "-font <cló>\t\tÚsáid <cló> le haghaidh gnáth-théacs (fosta: -fn)"
+
+msgid "-boldfont <font>\tUse <font> for bold text"
+msgstr "-boldfont <cló>\tBain úsáid as <cló> do chló trom"
+
+msgid "-italicfont <font>\tUse <font> for italic text"
+msgstr "-italicfont <cló>\tÚsáid <cló> le haghaidh téacs iodálach"
+
+msgid "-geometry <geom>\tUse <geom> for initial geometry (also: -geom)"
+msgstr ""
+"-geometry <geoim>\tÚsáid <geoim> le haghaidh na céimseatan tosaigh (fosta: -"
+"geom)"
+
+msgid "-borderwidth <width>\tUse a border width of <width> (also: -bw)"
+msgstr "-borderwidth <leithead>\tSocraigh <leithead> na himlíne (-bw fosta)"
+
+msgid "-scrollbarwidth <width> Use a scrollbar width of <width> (also: -sw)"
+msgstr ""
+"-scrollbarwidth <leithead> Socraigh leithead na scrollbharraí a bheith "
+"<leithead> (fosta: -sw)"
+
+msgid "-menuheight <height>\tUse a menu bar height of <height> (also: -mh)"
+msgstr ""
+"-menuheight <airde>\tSocraigh airde an bharra roghchláir a bheith <airde> "
+"(fosta: -mh)"
+
+msgid "-reverse\t\tUse reverse video (also: -rv)"
+msgstr "-reverse\t\tÚsáid fís aisiompaithe (fosta: -rv)"
+
+msgid "+reverse\t\tDon't use reverse video (also: +rv)"
+msgstr "+reverse\t\tNá húsáid fís aisiompaithe (fosta: +rv)"
+
+msgid "-xrm <resource>\tSet the specified resource"
+msgstr "-xrm <acmhainn>\tSocraigh an acmhainn sainithe"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (GTK+ version):\n"
+msgstr ""
+"\n"
+"Argóintí ar eolas do gvim (leagan GTK+):\n"
+
+msgid "-display <display>\tRun vim on <display> (also: --display)"
+msgstr "-display <scáileán>\tRith vim ar <scáileán> (fosta: --display)"
+
+msgid "--role <role>\tSet a unique role to identify the main window"
+msgstr "--role <ról>\tSocraigh ról sainiúil chun an phríomhfhuinneog a aithint"
+
+msgid "--socketid <xid>\tOpen Vim inside another GTK widget"
+msgstr "--socketid <xid>\tOscail Vim isteach i ngiuirléid GTK eile"
+
+msgid "--echo-wid\t\tMake gvim echo the Window ID on stdout"
+msgstr "--echo-wid\t\tTaispeánann gvim aitheantas na fuinneoige ar stdout"
+
+msgid "-P <parent title>\tOpen Vim inside parent application"
+msgstr "-P <máthairchlár>\tOscail Vim isteach sa mháthairchlár"
+
+msgid "--windowid <HWND>\tOpen Vim inside another win32 widget"
+msgstr "--windowid <HWND>\tOscail Vim isteach i ngiuirléid win32 eile"
+
+msgid "No display"
+msgstr "Gan taispeáint"
+
+#. Failed to send, abort.
+msgid ": Send failed.\n"
+msgstr ": Theip ar seoladh.\n"
+
+#. Let vim start normally.
+msgid ": Send failed. Trying to execute locally\n"
+msgstr ": Theip ar seoladh. Ag baint triail as go logánta\n"
+
+#, c-format
+msgid "%d of %d edited"
+msgstr "%d as %d déanta"
+
+msgid "No display: Send expression failed.\n"
+msgstr "Gan taispeáint: Theip ar sheoladh sloinn.\n"
+
+msgid ": Send expression failed.\n"
+msgstr ": Theip ar sheoladh sloinn.\n"
+
+msgid "No marks set"
+msgstr "Níl aon mharc socraithe"
+
+#, c-format
+msgid "E283: No marks matching \"%s\""
+msgstr "E283: Níl aon mharc comhoiriúnaithe le \"%s\""
+
+#. Highlight title
+msgid ""
+"\n"
+"mark line col file/text"
+msgstr ""
+"\n"
+"marc líne col comhad/téacs"
+
+#. Highlight title
+msgid ""
+"\n"
+" jump line col file/text"
+msgstr ""
+"\n"
+" léim líne col comhad/téacs"
+
+#. Highlight title
+msgid ""
+"\n"
+"change line col text"
+msgstr ""
+"\n"
+"athrú líne col téacs"
+
+msgid ""
+"\n"
+"# File marks:\n"
+msgstr ""
+"\n"
+"# Marcanna comhaid:\n"
+
+#. Write the jumplist with -'
+msgid ""
+"\n"
+"# Jumplist (newest first):\n"
+msgstr ""
+"\n"
+"# Liosta léimeanna (is nuaí i dtosach):\n"
+
+msgid ""
+"\n"
+"# History of marks within files (newest to oldest):\n"
+msgstr ""
+"\n"
+"# Stair na marcanna i gcomhaid (is nuaí ar dtús):\n"
+
+msgid "Missing '>'"
+msgstr "`>' ar iarraidh"
+
+msgid "E543: Not a valid codepage"
+msgstr "E543: Ní códleathanach bailí é"
+
+msgid "E284: Cannot set IC values"
+msgstr "E284: Ní féidir luachanna IC a shocrú"
+
+msgid "E285: Failed to create input context"
+msgstr "E285: Theip ar chruthú comhthéacs ionchuir"
+
+msgid "E286: Failed to open input method"
+msgstr "E286: Theip ar oscailt mhodh ionchuir"
+
+msgid "E287: Warning: Could not set destroy callback to IM"
+msgstr "E287: Rabhadh: Níorbh fhéidir aisghlaoch léirscriosta a shocrú le IM"
+
+msgid "E288: input method doesn't support any style"
+msgstr "E288: Ní thacaíonn an modh ionchuir aon stíl"
+
+msgid "E289: input method doesn't support my preedit type"
+msgstr "E289: ní thacaíonn an modh ionchuir mo chineál réamheagair"
+
+msgid "E293: block was not locked"
+msgstr "E293: ní raibh an bloc faoi ghlas"
+
+msgid "E294: Seek error in swap file read"
+msgstr "E294: Earráid chuardaigh agus comhad babhtála á léamh"
+
+msgid "E295: Read error in swap file"
+msgstr "E295: Earráid sa léamh i gcomhad babhtála"
+
+msgid "E296: Seek error in swap file write"
+msgstr "E296: Earráid chuardaigh agus comhad babhtála á scríobh"
+
+msgid "E297: Write error in swap file"
+msgstr "E297: Earráid sa scríobh i gcomhad babhtála"
+
+msgid "E300: Swap file already exists (symlink attack?)"
+msgstr "E300: Tá comhad babhtála ann cheana (ionsaí le naisc shiombalacha?)"
+
+msgid "E298: Didn't get block nr 0?"
+msgstr "E298: Ní bhfuarthas bloc 0?"
+
+msgid "E298: Didn't get block nr 1?"
+msgstr "E298: Ní bhfuarthas bloc a haon?"
+
+msgid "E298: Didn't get block nr 2?"
+msgstr "E298: Ní bhfuarthas bloc a dó?"
+
+msgid "E843: Error while updating swap file crypt"
+msgstr "E843: Earráid agus criptiú an chomhaid bhabhtála á nuashonrú"
+
+#. could not (re)open the swap file, what can we do????
+msgid "E301: Oops, lost the swap file!!!"
+msgstr "E301: Úps, cailleadh an comhad babhtála!!!"
+
+msgid "E302: Could not rename swap file"
+msgstr "E302: Níorbh fhéidir an comhad babhtála a athainmniú"
+
+#, c-format
+msgid "E303: Unable to open swap file for \"%s\", recovery impossible"
+msgstr ""
+"E303: Ní féidir comhad babhtála le haghaidh \"%s\" a oscailt, ní féidir "
+"athshlánú"
+
+msgid "E304: ml_upd_block0(): Didn't get block 0??"
+msgstr "E304: ml_upd_block0(): Ní bhfuarthas bloc 0??"
+
+#, c-format
+msgid "E305: No swap file found for %s"
+msgstr "E305: Níor aimsíodh comhad babhtála le haghaidh %s"
+
+msgid "Enter number of swap file to use (0 to quit): "
+msgstr "Iontráil uimhir an chomhaid babhtála le húsáid (0 = scoir): "
+
+#, c-format
+msgid "E306: Cannot open %s"
+msgstr "E306: Ní féidir %s a oscailt"
+
+msgid "Unable to read block 0 from "
+msgstr "Ní féidir bloc 0 a léamh ó "
+
+msgid ""
+"\n"
+"Maybe no changes were made or Vim did not update the swap file."
+msgstr ""
+"\n"
+"B'fhéidir nach raibh aon athrú á dhéanamh, nó tá an comhad "
+"babhtála as dáta."
+
+msgid " cannot be used with this version of Vim.\n"
+msgstr " níl ar fáil leis an leagan seo de Vim.\n"
+
+msgid "Use Vim version 3.0.\n"
+msgstr "Bain úsáid as Vim, leagan 3.0.\n"
+
+#, c-format
+msgid "E307: %s does not look like a Vim swap file"
+msgstr "E307: Níl %s cosúil le comhad babhtála Vim"
+
+msgid " cannot be used on this computer.\n"
+msgstr " níl ar fáil ar an ríomhaire seo.\n"
+
+msgid "The file was created on "
+msgstr "Cruthaíodh an comhad seo ar "
+
+msgid ""
+",\n"
+"or the file has been damaged."
+msgstr ""
+",\n"
+"is é sin nó rinneadh dochar don chomhad."
+
+#, c-format
+msgid ""
+"E833: %s is encrypted and this version of Vim does not support encryption"
+msgstr ""
+"E833: tá %s criptithe agus ní thacaíonn an leagan seo de Vim le criptiú"
+
+msgid " has been damaged (page size is smaller than minimum value).\n"
+msgstr " rinneadh dochar dó (méid an leathanaigh níos lú ná an íosmhéid).\n"
+
+#, c-format
+msgid "Using swap file \"%s\""
+msgstr "Comhad babhtála \"%s\" á úsáid"
+
+#, c-format
+msgid "Original file \"%s\""
+msgstr "Comhad bunúsach \"%s\""
+
+msgid "E308: Warning: Original file may have been changed"
+msgstr "E308: Rabhadh: Is féidir gur athraíodh an comhad bunúsach"
+
+#, c-format
+msgid "Swap file is encrypted: \"%s\""
+msgstr "Tá an comhad babhtála criptithe: \"%s\""
+
+msgid ""
+"\n"
+"If you entered a new crypt key but did not write the text file,"
+msgstr ""
+"\n"
+"Má chuir tú eochair nua chriptiúcháin isteach, ach mura scríobh tú an "
+"téacschomhad,"
+
+msgid ""
+"\n"
+"enter the new crypt key."
+msgstr ""
+"\n"
+"cuir isteach an eochair nua chriptiúcháin."
+
+msgid ""
+"\n"
+"If you wrote the text file after changing the crypt key press enter"
+msgstr ""
+"\n"
+"Má scríobh tú an téacschomhad tar éis duit an eochair chriptiúcháín a athrú, "
+"brúigh Enter"
+
+msgid ""
+"\n"
+"to use the same key for text file and swap file"
+msgstr ""
+"\n"
+"chun an eochair chéanna a úsáid don téacschomhad agus an comhad babhtála"
+
+#, c-format
+msgid "E309: Unable to read block 1 from %s"
+msgstr "E309: Ní féidir bloc a haon a léamh ó %s"
+
+msgid "???MANY LINES MISSING"
+msgstr "???GO LEOR LÍNTE AR IARRAIDH"
+
+msgid "???LINE COUNT WRONG"
+msgstr "???LÍON MÍCHEART NA LÍNTE"
+
+msgid "???EMPTY BLOCK"
+msgstr "???BLOC FOLAMH"
+
+msgid "???LINES MISSING"
+msgstr "???LÍNTE AR IARRAIDH"
+
+#, c-format
+msgid "E310: Block 1 ID wrong (%s not a .swp file?)"
+msgstr "E310: Aitheantas mícheart ar bhloc a haon (níl %s ina chomhad .swp?)"
+
+msgid "???BLOCK MISSING"
+msgstr "???BLOC AR IARRAIDH"
+
+msgid "??? from here until ???END lines may be messed up"
+msgstr "??? is féidir go ndearnadh praiseach de línte ó anseo go ???END"
+
+msgid "??? from here until ???END lines may have been inserted/deleted"
+msgstr "??? is féidir go bhfuil línte ionsáite/scriosta ó anseo go ???END"
+
+msgid "???END"
+msgstr "???DEIREADH"
+
+msgid "E311: Recovery Interrupted"
+msgstr "E311: Idirbhriseadh an t-athshlánú"
+
+msgid ""
+"E312: Errors detected while recovering; look for lines starting with ???"
+msgstr ""
+"E312: Braitheadh earráidí le linn athshlánaithe; féach ar na línte le ??? ar "
+"tosach"
+
+msgid "See \":help E312\" for more information."
+msgstr "Bain triail as \":help E312\" chun tuilleadh eolais a fháil."
+
+msgid "Recovery completed. You should check if everything is OK."
+msgstr "Athshlánaíodh. Ba chóir duit gach rud a sheiceáil uair amháin eile."
+
+msgid ""
+"\n"
+"(You might want to write out this file under another name\n"
+msgstr ""
+"\n"
+"(B'fhéidir gur mian leat an comhad seo a shábháil de réir ainm eile\n"
+
+msgid "and run diff with the original file to check for changes)"
+msgstr "agus déan comparáid leis an mbunchomhad chun athruithe a lorg)"
+
+msgid "Recovery completed. Buffer contents equals file contents."
+msgstr ""
+"Athshlánú críochnaithe. Is ionann an t-ábhar sa mhaolán agus an t-ábhar sa "
+"chomhad."
+
+msgid ""
+"\n"
+"You may want to delete the .swp file now.\n"
+"\n"
+msgstr ""
+"\n"
+"B'fhéidir gur mhaith leat an comhad .swp a scriosadh anois.\n"
+"\n"
+
+msgid "Using crypt key from swap file for the text file.\n"
+msgstr ""
+"Eochair chriptiúcháin ón gcomhad babhtála á húsáid ar an téacschomhad.\n"
+
+#. use msg() to start the scrolling properly
+msgid "Swap files found:"
+msgstr "Comhaid bhabhtála aimsithe:"
+
+msgid " In current directory:\n"
+msgstr " Sa chomhadlann reatha:\n"
+
+msgid " Using specified name:\n"
+msgstr " Ag baint úsáid as ainm socraithe:\n"
+
+msgid " In directory "
+msgstr " Sa chomhadlann "
+
+msgid " -- none --\n"
+msgstr " -- neamhní --\n"
+
+msgid " owned by: "
+msgstr " úinéir: "
+
+msgid " dated: "
+msgstr " dátaithe: "
+
+msgid " dated: "
+msgstr " dátaithe: "
+
+msgid " [from Vim version 3.0]"
+msgstr " [ó leagan 3.0 Vim]"
+
+msgid " [does not look like a Vim swap file]"
+msgstr " [ní cosúil le comhad babhtála Vim]"
+
+msgid " file name: "
+msgstr " ainm comhaid: "
+
+msgid ""
+"\n"
+" modified: "
+msgstr ""
+"\n"
+" mionathraithe: "
+
+msgid "YES"
+msgstr "IS SEA"
+
+msgid "no"
+msgstr "ní hea"
+
+msgid ""
+"\n"
+" user name: "
+msgstr ""
+"\n"
+" úsáideoir: "
+
+msgid " host name: "
+msgstr " ainm an óstríomhaire: "
+
+msgid ""
+"\n"
+" host name: "
+msgstr ""
+"\n"
+" óstainm: "
+
+msgid ""
+"\n"
+" process ID: "
+msgstr ""
+"\n"
+" PID: "
+
+msgid " (still running)"
+msgstr " (ag rith fós)"
+
+msgid ""
+"\n"
+" [not usable with this version of Vim]"
+msgstr ""
+"\n"
+" [ní inúsáidte leis an leagan seo Vim]"
+
+msgid ""
+"\n"
+" [not usable on this computer]"
+msgstr ""
+"\n"
+" [ní inúsáidte ar an ríomhaire seo]"
+
+msgid " [cannot be read]"
+msgstr " [ní féidir a léamh]"
+
+msgid " [cannot be opened]"
+msgstr " [ní féidir oscailt]"
+
+msgid "E313: Cannot preserve, there is no swap file"
+msgstr "E313: Ní féidir é a chaomhnú, níl aon chomhad babhtála ann"
+
+msgid "File preserved"
+msgstr "Caomhnaíodh an comhad"
+
+msgid "E314: Preserve failed"
+msgstr "E314: Theip ar chaomhnú"
+
+#, c-format
+msgid "E315: ml_get: invalid lnum: %ld"
+msgstr "E315: ml_get: lnum neamhbhailí: %ld"
+
+#, c-format
+msgid "E316: ml_get: cannot find line %ld"
+msgstr "E316: ml_get: líne %ld gan aimsiú"
+
+msgid "E317: pointer block id wrong 3"
+msgstr "E317: aitheantas mícheart ar an mbloc pointeora 3"
+
+msgid "stack_idx should be 0"
+msgstr "ba chóir do stack_idx a bheith 0"
+
+msgid "E318: Updated too many blocks?"
+msgstr "E318: An iomarca bloic nuashonraithe?"
+
+msgid "E317: pointer block id wrong 4"
+msgstr "E317: aitheantas mícheart ar an mbloc pointeora 4"
+
+msgid "deleted block 1?"
+msgstr "bloc a haon scriosta?"
+
+#, c-format
+msgid "E320: Cannot find line %ld"
+msgstr "E320: Líne %ld gan aimsiú"
+
+msgid "E317: pointer block id wrong"
+msgstr "E317: aitheantas mícheart ar an mbloc pointeora"
+
+msgid "pe_line_count is zero"
+msgstr "is 0 pe_line_count\""
+
+#, c-format
+msgid "E322: line number out of range: %ld past the end"
+msgstr "E322: líne-uimhir as raon: %ld thar dheireadh"
+
+#, c-format
+msgid "E323: line count wrong in block %ld"
+msgstr "E323: líon mícheart na línte i mbloc %ld"
+
+msgid "Stack size increases"
+msgstr "Méadaíonn an chruach"
+
+msgid "E317: pointer block id wrong 2"
+msgstr "E317: aitheantas mícheart ar an mbloc pointeora 2"
+
+#, c-format
+msgid "E773: Symlink loop for \"%s\""
+msgstr "E773: Ciogal i naisc shiombalacha le haghaidh \"%s\""
+
+msgid "E325: ATTENTION"
+msgstr "E325: AIRE"
+
+msgid ""
+"\n"
+"Found a swap file by the name \""
+msgstr ""
+"\n"
+"Fuarthas comhad babhtála darbh ainm \""
+
+msgid "While opening file \""
+msgstr "Agus an comhad seo á oscailt: \""
+
+msgid " NEWER than swap file!\n"
+msgstr " NÍOS NUAÍ ná comhad babhtála!\n"
+
+#. Some of these messages are long to allow translation to
+#. * other languages.
+msgid ""
+"\n"
+"(1) Another program may be editing the same file. If this is the case,\n"
+" be careful not to end up with two different instances of the same\n"
+" file when making changes. Quit, or continue with caution.\n"
+msgstr ""
+"\n"
+"(1) Seans go bhfuil an comhad seo á chur in eagar ag clár eile. Má tá,\n"
+" bí cúramach nach bhfuil dhá leagan den chomhad céanna agat nuair\n"
+" a athraíonn tú é. Scoir anois, nó lean ort go faichilleach.\n"
+
+msgid "(2) An edit session for this file crashed.\n"
+msgstr "(2) Thuairteáil seisiún eagarthóireachta.\n"
+
+msgid " If this is the case, use \":recover\" or \"vim -r "
+msgstr " Más amhlaidh, bain úsáid as \":recover\" nó \"vim -r "
+
+msgid ""
+"\"\n"
+" to recover the changes (see \":help recovery\").\n"
+msgstr ""
+"\"\n"
+" chun na hathruithe a fháil ar ais (féach \":help recovery\").\n"
+
+msgid " If you did this already, delete the swap file \""
+msgstr " Má tá sé seo déanta cheana agat, scrios an comhad babhtála \""
+
+msgid ""
+"\"\n"
+" to avoid this message.\n"
+msgstr ""
+"\"\n"
+" chun an teachtaireacht seo a sheachaint.\n"
+
+msgid "Swap file \""
+msgstr "Comhad babhtála \""
+
+msgid "\" already exists!"
+msgstr "\" tá sé ann cheana!"
+
+msgid "VIM - ATTENTION"
+msgstr "VIM - AIRE"
+
+msgid "Swap file already exists!"
+msgstr "Tá comhad babhtála ann cheana!"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"&Oscail Inléite Amháin\n"
+"&Eagraigh mar sin féin\n"
+"&Athshlánaigh\n"
+"&Scoir\n"
+"&Tobscoir"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Delete it\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"&Oscail Inléite Amháin\n"
+"&Eagraigh mar sin féin\n"
+"&Athshlánaigh\n"
+"S&crios é\n"
+"&Scoir\n"
+"&Tobscoir"
+
+msgid "E326: Too many swap files found"
+msgstr "E326: Aimsíodh an iomarca comhaid bhabhtála"
+
+msgid "E327: Part of menu-item path is not sub-menu"
+msgstr "E327: Ní fo-roghchlár í páirt de chonair roghchláir"
+
+msgid "E328: Menu only exists in another mode"
+msgstr "E328: Níl an roghchlár ar fáil sa mhód seo"
+
+#, c-format
+msgid "E329: No menu \"%s\""
+msgstr "E329: Níl aon roghchlár darbh ainm \"%s\""
+
+#. Only a mnemonic or accelerator is not valid.
+msgid "E792: Empty menu name"
+msgstr "E792: Ainm folamh ar an roghchlár"
+
+msgid "E330: Menu path must not lead to a sub-menu"
+msgstr "E330: Ní cheadaítear conair roghchláir a threoraíonn go fo-roghchlár"
+
+msgid "E331: Must not add menu items directly to menu bar"
+msgstr ""
+"E331: Ní cheadaítear míreanna roghchláir a chur le barra roghchláir go "
+"díreach"
+
+msgid "E332: Separator cannot be part of a menu path"
+msgstr "E332: Ní cheadaítear deighilteoir mar pháirt de chonair roghchláir"
+
+#. Now we have found the matching menu, and we list the mappings
+#. Highlight title
+msgid ""
+"\n"
+"--- Menus ---"
+msgstr ""
+"\n"
+"--- Roghchláir ---"
+
+msgid "Tear off this menu"
+msgstr "Bain an roghchlár seo"
+
+msgid "E333: Menu path must lead to a menu item"
+msgstr "E333: Ní mór conair roghchláir a threorú chun mír roghchláir"
+
+#, c-format
+msgid "E334: Menu not found: %s"
+msgstr "E334: Roghchlár gan aimsiú: %s"
+
+#, c-format
+msgid "E335: Menu not defined for %s mode"
+msgstr "E335: Níl an roghchlár ar fáil sa mhód %s"
+
+msgid "E336: Menu path must lead to a sub-menu"
+msgstr "E336: Ní mór conair roghchláir a threorú chun fo-roghchlár"
+
+msgid "E337: Menu not found - check menu names"
+msgstr "E337: Roghchlár gan aimsiú - deimhnigh ainmneacha na roghchlár"
+
+#, c-format
+msgid "Error detected while processing %s:"
+msgstr "Earráid agus %s á phróiseáil:"
+
+#, c-format
+msgid "line %4ld:"
+msgstr "líne %4ld:"
+
+#, c-format
+msgid "E354: Invalid register name: '%s'"
+msgstr "E354: Ainm neamhbhailí tabhaill: '%s'"
+
+msgid "Messages maintainer: Bram Moolenaar <Bram@vim.org>"
+msgstr ""
+"Cothaitheoir na dteachtaireachtaí: Kevin P. Scannell <scannell@slu.edu>"
+
+msgid "Interrupt: "
+msgstr "Idirbhriseadh: "
+
+msgid "Press ENTER or type command to continue"
+msgstr "Brúigh ENTER nó iontráil ordú le leanúint"
+
+#, c-format
+msgid "%s line %ld"
+msgstr "%s líne %ld"
+
+msgid "-- More --"
+msgstr "-- Tuilleadh --"
+
+msgid " SPACE/d/j: screen/page/line down, b/u/k: up, q: quit "
+msgstr " SPÁS/d/j: scáileán/leathanach/líne síos, b/u/k: suas, q: scoir "
+
+msgid "Question"
+msgstr "Ceist"
+
+msgid ""
+"&Yes\n"
+"&No"
+msgstr ""
+"&Tá\n"
+"&Níl"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"Save &All\n"
+"&Discard All\n"
+"&Cancel"
+msgstr ""
+"&Tá\n"
+"&Níl\n"
+"Sábháil &Uile\n"
+"&Dealaigh Uile\n"
+"&Cealaigh"
+
+msgid "Select Directory dialog"
+msgstr "Dialóg `Roghnaigh Comhadlann'"
+
+msgid "Save File dialog"
+msgstr "Dialóg `Sábháil Comhad'"
+
+msgid "Open File dialog"
+msgstr "Dialóg `Oscail Comhad'"
+
+#. TODO: non-GUI file selector here
+msgid "E338: Sorry, no file browser in console mode"
+msgstr "E338: Níl brabhsálaí comhaid ar fáil sa mhód consóil"
+
+msgid "E766: Insufficient arguments for printf()"
+msgstr "E766: Easpa argóintí d'fheidhm printf()"
+
+msgid "E807: Expected Float argument for printf()"
+msgstr "E807: Bhíothas ag súil le hargóint Snámhphointe d'fheidhm printf()"
+
+msgid "E767: Too many arguments to printf()"
+msgstr "E767: An iomarca argóintí d'fheidhm printf()"
+
+msgid "W10: Warning: Changing a readonly file"
+msgstr "W10: Rabhadh: Comhad inléite amháin á athrú"
+
+msgid "Type number and <Enter> or click with mouse (empty cancels): "
+msgstr ""
+"Clóscríobh uimhir agus <Enter> nó cliceáil leis an luch (fág folamh le "
+"cealú): "
+
+msgid "Type number and <Enter> (empty cancels): "
+msgstr "Clóscríobh uimhir agus <Enter> (fág folamh le cealú): "
+
+msgid "1 more line"
+msgstr "1 líne eile"
+
+msgid "1 line less"
+msgstr "1 líne níos lú"
+
+#, c-format
+msgid "%ld more lines"
+msgstr "%ld líne eile"
+
+#, c-format
+msgid "%ld fewer lines"
+msgstr "%ld líne níos lú"
+
+msgid " (Interrupted)"
+msgstr " (Idirbhriste)"
+
+msgid "Beep!"
+msgstr "Bíp!"
+
+msgid "ERROR: "
+msgstr "EARRÁID: "
+
+#, c-format
+msgid ""
+"\n"
+"[bytes] total alloc-freed %lu-%lu, in use %lu, peak use %lu\n"
+msgstr ""
+"\n"
+"[beart] iomlán dáilte-saor %lu-%lu, in úsáid %lu, buaic %lu\n"
+
+#, c-format
+msgid ""
+"[calls] total re/malloc()'s %lu, total free()'s %lu\n"
+"\n"
+msgstr ""
+"[glaonna] re/malloc(): %lu, free(): %lu\n"
+"\n"
+
+msgid "E340: Line is becoming too long"
+msgstr "E340: Tá an líne ag éirí rófhada"
+
+#, c-format
+msgid "E341: Internal error: lalloc(%ld, )"
+msgstr "E341: Earráid inmheánach: lalloc(%ld, )"
+
+#, c-format
+msgid "E342: Out of memory! (allocating %lu bytes)"
+msgstr "E342: Cuimhne ídithe! (%lu beart á ndáileadh)"
+
+#, c-format
+msgid "Calling shell to execute: \"%s\""
+msgstr "An t-ordú seo á rith leis an bhlaosc: \"%s\""
+
+msgid "E545: Missing colon"
+msgstr "E545: Idirstad ar iarraidh"
+
+msgid "E546: Illegal mode"
+msgstr "E546: Mód neamhcheadaithe"
+
+msgid "E547: Illegal mouseshape"
+msgstr "E547: Cruth neamhcheadaithe luiche"
+
+msgid "E548: digit expected"
+msgstr "E548: ag súil le digit"
+
+msgid "E549: Illegal percentage"
+msgstr "E549: Céatadán neamhcheadaithe"
+
+msgid "E854: path too long for completion"
+msgstr "E854: conair rófhada le comhlánú"
+
+#, c-format
+msgid ""
+"E343: Invalid path: '**[number]' must be at the end of the path or be "
+"followed by '%s'."
+msgstr ""
+"E343: Conair neamhbhailí: ní mór '**[uimhir]' a bheith ag deireadh na "
+"conaire, nó le '%s' ina dhiaidh."
+
+#, c-format
+msgid "E344: Can't find directory \"%s\" in cdpath"
+msgstr "E344: Ní féidir comhadlann \"%s\" a aimsiú sa cdpath"
+
+#, c-format
+msgid "E345: Can't find file \"%s\" in path"
+msgstr "E345: Ní féidir comhad \"%s\" a aimsiú sa chonair"
+
+#, c-format
+msgid "E346: No more directory \"%s\" found in cdpath"
+msgstr "E346: Níl comhadlann \"%s\" sa cdpath a thuilleadh"
+
+#, c-format
+msgid "E347: No more file \"%s\" found in path"
+msgstr "E347: Níl comhad \"%s\" sa chonair a thuilleadh"
+
+#, c-format
+msgid "E668: Wrong access mode for NetBeans connection info file: \"%s\""
+msgstr "E668: Mód mícheart rochtana ar an chomhad eolas naisc NetBeans: \"%s\""
+
+#, c-format
+msgid "E658: NetBeans connection lost for buffer %ld"
+msgstr "E658: Cailleadh nasc NetBeans le haghaidh maoláin %ld"
+
+msgid "E838: netbeans is not supported with this GUI"
+msgstr "E838: Ní thacaítear le netbeans sa GUI seo"
+
+msgid "E511: netbeans already connected"
+msgstr "E511: Tá netbeans ceangailte cheana"
+
+#, c-format
+msgid "E505: %s is read-only (add ! to override)"
+msgstr "E505: Tá %s inléite amháin (cuir ! leis chun sárú)"
+
+msgid "E349: No identifier under cursor"
+msgstr "E349: Níl aitheantóir faoin chúrsóir"
+
+msgid "E774: 'operatorfunc' is empty"
+msgstr "E774: 'operatorfunc' folamh"
+
+msgid "E775: Eval feature not available"
+msgstr "E775: Níl an ghné Eval le fáil"
+
+msgid "Warning: terminal cannot highlight"
+msgstr "Rabhadh: ní féidir leis an teirminéal aibhsiú"
+
+msgid "E348: No string under cursor"
+msgstr "E348: Níl teaghrán faoin chúrsóir"
+
+msgid "E352: Cannot erase folds with current 'foldmethod'"
+msgstr "E352: Ní féidir fillteacha a léirscriosadh leis an 'foldmethod' reatha"
+
+msgid "E664: changelist is empty"
+msgstr "E664: tá liosta na n-athruithe folamh"
+
+msgid "E662: At start of changelist"
+msgstr "E662: Ag tosach liosta na n-athruithe"
+
+msgid "E663: At end of changelist"
+msgstr "E663: Ag deireadh liosta na n-athruithe"
+
+msgid "Type :qa! and press <Enter> to abandon all changes and exit Vim"
+msgstr "Clóscríobh :qa! agus brúigh <Enter> le fágáil ó Vim gan athruithe a shábháil"
+
+# ouch - English -ed ?
+#, c-format
+msgid "1 line %sed 1 time"
+msgstr "1 líne %s uair amháin"
+
+# ouch - English -ed ?
+#, c-format
+msgid "1 line %sed %d times"
+msgstr "1 líne %s %d uair"
+
+# ouch - English -ed ?
+#, c-format
+msgid "%ld lines %sed 1 time"
+msgstr "%ld líne %sed uair amháin"
+
+# ouch - English -ed ?
+#, c-format
+msgid "%ld lines %sed %d times"
+msgstr "%ld líne %sed %d uair"
+
+#, c-format
+msgid "%ld lines to indent... "
+msgstr "%ld líne le heangú... "
+
+msgid "1 line indented "
+msgstr "eangaíodh líne amháin "
+
+#, c-format
+msgid "%ld lines indented "
+msgstr "%ld líne eangaithe "
+
+msgid "E748: No previously used register"
+msgstr "E748: Níl aon tabhall úsáidte roimhe seo"
+
+#. must display the prompt
+msgid "cannot yank; delete anyway"
+msgstr "ní féidir a sracadh; scrios mar sin féin"
+
+msgid "1 line changed"
+msgstr "athraíodh líne amháin"
+
+#, c-format
+msgid "%ld lines changed"
+msgstr "athraíodh %ld líne"
+
+#, c-format
+msgid "freeing %ld lines"
+msgstr "%ld líne á saoradh"
+
+msgid "block of 1 line yanked"
+msgstr "sracadh bloc de líne amháin"
+
+msgid "1 line yanked"
+msgstr "sracadh líne amháin"
+
+#, c-format
+msgid "block of %ld lines yanked"
+msgstr "sracadh bloc de %ld líne"
+
+#, c-format
+msgid "%ld lines yanked"
+msgstr "%ld líne sractha"
+
+#, c-format
+msgid "E353: Nothing in register %s"
+msgstr "E353: Tabhall folamh %s"
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Registers ---"
+msgstr ""
+"\n"
+"--- Tabhaill ---"
+
+msgid "Illegal register name"
+msgstr "Ainm neamhcheadaithe tabhaill"
+
+msgid ""
+"\n"
+"# Registers:\n"
+msgstr ""
+"\n"
+"# Tabhaill:\n"
+
+#, c-format
+msgid "E574: Unknown register type %d"
+msgstr "E574: Cineál anaithnid tabhaill %d"
+
+msgid ""
+"E883: search pattern and expression register may not contain two or more "
+"lines"
+msgstr ""
+"E883: ní cheadaítear níos mó ná líne amháin i bpatrún cuardaigh ná sa "
+"slonntabhall"
+
+#, c-format
+msgid "%ld Cols; "
+msgstr "%ld Colún; "
+
+#, c-format
+msgid "Selected %s%ld of %ld Lines; %lld of %lld Words; %lld of %lld Bytes"
+msgstr "Roghnaíodh %s%ld as %ld Líne; %lld as %lld Focal; %lld as %lld Beart"
+
+#, c-format
+msgid ""
+"Selected %s%ld of %ld Lines; %lld of %lld Words; %lld of %lld Chars; %lld of "
+"%lld Bytes"
+msgstr ""
+"Roghnaíodh %s%ld as %ld Líne; %lld as %lld Focal; %lld as %lld Carachtar; "
+"%lld as %lld Beart"
+
+#, c-format
+msgid "Col %s of %s; Line %ld of %ld; Word %lld of %lld; Byte %lld of %lld"
+msgstr "Col %s as %s; Líne %ld as %ld; Focal %lld as %lld; Beart %lld as %lld"
+
+#, c-format
+msgid ""
+"Col %s of %s; Line %ld of %ld; Word %lld of %lld; Char %lld of %lld; Byte "
+"%lld of %lld"
+msgstr ""
+"Col %s as %s; Líne %ld as %ld; Focal %lld as %lld; Carachtar %lld as %lld; "
+"Beart %lld as %lld"
+
+#, c-format
+msgid "(+%ld for BOM)"
+msgstr "(+%ld do BOM)"
+
+msgid "%<%f%h%m%=Page %N"
+msgstr "%<%f%h%m%=Leathanach %N"
+
+msgid "Thanks for flying Vim"
+msgstr "Go raibh míle maith agat as Vim a úsáid"
+
+msgid "E518: Unknown option"
+msgstr "E518: Rogha anaithnid"
+
+msgid "E519: Option not supported"
+msgstr "E519: Níl an rogha seo ar fáil"
+
+msgid "E520: Not allowed in a modeline"
+msgstr "E520: Ní cheadaithe i módlíne"
+
+msgid "E846: Key code not set"
+msgstr "E846: Cód eochrach gan socrú"
+
+msgid "E521: Number required after ="
+msgstr "E521: Tá gá le huimhir i ndiaidh ="
+
+msgid "E522: Not found in termcap"
+msgstr "E522: Gan aimsiú sa termcap"
+
+#, c-format
+msgid "E539: Illegal character <%s>"
+msgstr "E539: Carachtar neamhcheadaithe <%s>"
+
+#, c-format
+msgid "For option %s"
+msgstr "Le haghaidh rogha %s"
+
+msgid "E529: Cannot set 'term' to empty string"
+msgstr "E529: Ní féidir 'term' a shocrú mar theaghrán folamh"
+
+msgid "E530: Cannot change term in GUI"
+msgstr "E530: Ní féidir 'term' a athrú sa GUI"
+
+msgid "E531: Use \":gui\" to start the GUI"
+msgstr "E531: Úsáid \":gui\" chun an GUI a chur ag obair"
+
+msgid "E589: 'backupext' and 'patchmode' are equal"
+msgstr "E589: is ionann iad 'backupext' agus 'patchmode'"
+
+msgid "E834: Conflicts with value of 'listchars'"
+msgstr "E834: Tagann sé salach ar luach de 'listchars'"
+
+msgid "E835: Conflicts with value of 'fillchars'"
+msgstr "E835: Tagann sé salach ar luach de 'fillchars'"
+
+msgid "E617: Cannot be changed in the GTK+ 2 GUI"
+msgstr "E617: Ní féidir é a athrú sa GUI GTK+ 2"
+
+msgid "E524: Missing colon"
+msgstr "E524: Idirstad ar iarraidh"
+
+msgid "E525: Zero length string"
+msgstr "E525: Teaghrán folamh"
+
+#, c-format
+msgid "E526: Missing number after <%s>"
+msgstr "E526: Uimhir ar iarraidh i ndiaidh <%s>"
+
+msgid "E527: Missing comma"
+msgstr "E527: Camóg ar iarraidh"
+
+msgid "E528: Must specify a ' value"
+msgstr "E528: Caithfidh luach ' a shonrú"
+
+msgid "E595: contains unprintable or wide character"
+msgstr "E595: tá carachtar neamhghrafach nó leathan ann"
+
+msgid "E596: Invalid font(s)"
+msgstr "E596: Cló(nna) neamhbhailí"
+
+msgid "E597: can't select fontset"
+msgstr "E597: ní féidir tacar cló a roghnú"
+
+msgid "E598: Invalid fontset"
+msgstr "E598: Tacar cló neamhbhailí"
+
+msgid "E533: can't select wide font"
+msgstr "E533: ní féidir cló leathan a roghnú"
+
+msgid "E534: Invalid wide font"
+msgstr "E534: Cló leathan neamhbhailí"
+
+#, c-format
+msgid "E535: Illegal character after <%c>"
+msgstr "E535: Carachtar neamhbhailí i ndiaidh <%c>"
+
+msgid "E536: comma required"
+msgstr "E536: tá gá le camóg"
+
+#, c-format
+msgid "E537: 'commentstring' must be empty or contain %s"
+msgstr ""
+"E537: ní mór %s a bheith i 'commentstring', is é sin nó ní mór dó a bheith "
+"folamh"
+
+msgid "E538: No mouse support"
+msgstr "E538: Gan tacaíocht luiche"
+
+msgid "E540: Unclosed expression sequence"
+msgstr "E540: Seicheamh gan dúnadh"
+
+msgid "E541: too many items"
+msgstr "E541: an iomarca míreanna"
+
+msgid "E542: unbalanced groups"
+msgstr "E542: grúpaí neamhchothromaithe"
+
+msgid "E590: A preview window already exists"
+msgstr "E590: Tá fuinneog réamhamhairc ann cheana"
+
+msgid "W17: Arabic requires UTF-8, do ':set encoding=utf-8'"
+msgstr ""
+"W17: Tá UTF-8 ag teastáil le haghaidh Araibise, socraigh é le ':set "
+"encoding=utf-8'"
+
+#, c-format
+msgid "E593: Need at least %d lines"
+msgstr "E593: Tá gá le %d líne ar a laghad"
+
+#, c-format
+msgid "E594: Need at least %d columns"
+msgstr "E594: Tá gá le %d colún ar a laghad"
+
+#, c-format
+msgid "E355: Unknown option: %s"
+msgstr "E355: Rogha anaithnid: %s"
+
+#. There's another character after zeros or the string
+#. * is empty. In both cases, we are trying to set a
+#. * num option using a string.
+#, c-format
+msgid "E521: Number required: &%s = '%s'"
+msgstr "E521: Uimhir de dhíth: &%s = '%s'"
+
+msgid ""
+"\n"
+"--- Terminal codes ---"
+msgstr ""
+"\n"
+"--- Cóid teirminéil ---"
+
+msgid ""
+"\n"
+"--- Global option values ---"
+msgstr ""
+"\n"
+"--- Luachanna na roghanna comhchoiteann ---"
+
+msgid ""
+"\n"
+"--- Local option values ---"
+msgstr ""
+"\n"
+"--- Luachanna na roghanna logánta ---"
+
+msgid ""
+"\n"
+"--- Options ---"
+msgstr ""
+"\n"
+"--- Roghanna ---"
+
+msgid "E356: get_varp ERROR"
+msgstr "E356: EARRÁID get_varp"
+
+#, c-format
+msgid "E357: 'langmap': Matching character missing for %s"
+msgstr "E357: 'langmap': Carachtar comhoiriúnach ar iarraidh le haghaidh %s"
+
+#, c-format
+msgid "E358: 'langmap': Extra characters after semicolon: %s"
+msgstr "E358: 'langmap': Carachtair breise i ndiaidh an idirstad: %s"
+
+msgid "cannot open "
+msgstr "ní féidir a oscailt: "
+
+msgid "VIM: Can't open window!\n"
+msgstr "VIM: Ní féidir fuinneog a oscailt!\n"
+
+msgid "Need Amigados version 2.04 or later\n"
+msgstr "Tá gá le Amigados leagan 2.04 nó níos déanaí\n"
+
+#, c-format
+msgid "Need %s version %ld\n"
+msgstr "Tá gá le %s, leagan %ld\n"
+
+msgid "Cannot open NIL:\n"
+msgstr "Ní féidir NIL a oscailt:\n"
+
+msgid "Cannot create "
+msgstr "Ní féidir a chruthú: "
+
+#, c-format
+msgid "Vim exiting with %d\n"
+msgstr "Vim á scor le stádas %d\n"
+
+msgid "cannot change console mode ?!\n"
+msgstr "ní féidir mód consóil a athrú ?!\n"
+
+msgid "mch_get_shellsize: not a console??\n"
+msgstr "mch_get_shellsize: ní consól é seo??\n"
+
+#. if Vim opened a window: Executing a shell may cause crashes
+msgid "E360: Cannot execute shell with -f option"
+msgstr "E360: Ní féidir blaosc a rith le rogha -f"
+
+msgid "Cannot execute "
+msgstr "Ní féidir blaosc a rith: "
+
+msgid "shell "
+msgstr "blaosc "
+
+msgid " returned\n"
+msgstr " aisfhilleadh\n"
+
+msgid "ANCHOR_BUF_SIZE too small."
+msgstr "ANCHOR_BUF_SIZE róbheag."
+
+msgid "I/O ERROR"
+msgstr "EARRÁID I/A"
+
+msgid "Message"
+msgstr "Teachtaireacht"
+
+msgid "E237: Printer selection failed"
+msgstr "E237: Theip ar roghnú printéara"
+
+#, c-format
+msgid "to %s on %s"
+msgstr "go %s ar %s"
+
+#, c-format
+msgid "E613: Unknown printer font: %s"
+msgstr "E613: Clófhoireann anaithnid printéara: %s"
+
+#, c-format
+msgid "E238: Print error: %s"
+msgstr "E238: Earráid phriontála: %s"
+
+#, c-format
+msgid "Printing '%s'"
+msgstr "'%s' á phriontáil"
+
+#, c-format
+msgid "E244: Illegal charset name \"%s\" in font name \"%s\""
+msgstr ""
+"E244: Ainm neamhcheadaithe ar thacar carachtar \"%s\" mar pháirt d'ainm cló "
+"\"%s\""
+
+#, c-format
+msgid "E244: Illegal quality name \"%s\" in font name \"%s\""
+msgstr "E244: Ainm neamhcheadaithe ar cháilíocht \"%s\" in ainm cló \"%s\""
+
+#, c-format
+msgid "E245: Illegal char '%c' in font name \"%s\""
+msgstr "E245: Carachtar neamhcheadaithe '%c' mar pháirt d'ainm cló \"%s\""
+
+#, c-format
+msgid "Opening the X display took %ld msec"
+msgstr "Thóg %ld ms chun an scáileán X a oscailt"
+
+msgid ""
+"\n"
+"Vim: Got X error\n"
+msgstr ""
+"\n"
+"Vim: Fuarthas earráid ó X\n"
+
+msgid "Testing the X display failed"
+msgstr "Theip ar thástáil an scáileáin X"
+
+msgid "Opening the X display timed out"
+msgstr "Oscailt an scáileáin X thar am"
+
+msgid ""
+"\n"
+"Could not get security context for "
+msgstr ""
+"\n"
+"Níorbh fhéidir comhthéacs slándála a fháil le haghaidh "
+
+msgid ""
+"\n"
+"Could not set security context for "
+msgstr ""
+"\n"
+"Níorbh fhéidir comhthéacs slándála a shocrú le haghaidh "
+
+#, c-format
+msgid "Could not set security context %s for %s"
+msgstr "Níorbh fhéidir comhthéacs slándála %s a shocrú le haghaidh %s"
+
+#, c-format
+msgid "Could not get security context %s for %s. Removing it!"
+msgstr ""
+"Níorbh fhéidir comhthéacs slándála %s a fháil le haghaidh %s. Á bhaint!"
+
+msgid ""
+"\n"
+"Cannot execute shell sh\n"
+msgstr ""
+"\n"
+"Ní féidir an bhlaosc sh a rith\n"
+
+msgid ""
+"\n"
+"shell returned "
+msgstr ""
+"\n"
+"d'aisfhill an bhlaosc "
+
+msgid ""
+"\n"
+"Cannot create pipes\n"
+msgstr ""
+"\n"
+"Ní féidir píopaí a chruthú\n"
+
+# "fork" not in standard refs/corpus. Maybe want a "gabhl*" word instead? -KPS
+msgid ""
+"\n"
+"Cannot fork\n"
+msgstr ""
+"\n"
+"Ní féidir forc a dhéanamh\n"
+
+msgid ""
+"\n"
+"Cannot execute shell "
+msgstr ""
+"\n"
+"Ní féidir blaosc a rith "
+
+msgid ""
+"\n"
+"Command terminated\n"
+msgstr ""
+"\n"
+"Ordú críochnaithe\n"
+
+msgid "XSMP lost ICE connection"
+msgstr "Chaill XSMP an nasc ICE"
+
+#, c-format
+msgid "dlerror = \"%s\""
+msgstr "dlerror = \"%s\""
+
+msgid "Opening the X display failed"
+msgstr "Theip ar oscailt an scáileáin X"
+
+msgid "XSMP handling save-yourself request"
+msgstr "Iarratas sábháil-do-féin á láimhseáil ag XSMP"
+
+msgid "XSMP opening connection"
+msgstr "Nasc á oscailt ag XSMP"
+
+msgid "XSMP ICE connection watch failed"
+msgstr "Theip ar fhaire nasc ICE XSMP"
+
+#, c-format
+msgid "XSMP SmcOpenConnection failed: %s"
+msgstr "Theip ar XSMP SmcOpenConnection: %s"
+
+msgid "At line"
+msgstr "Ag líne"
+
+msgid "Could not load vim32.dll!"
+msgstr "Níorbh fhéidir vim32.dll a luchtú!"
+
+msgid "VIM Error"
+msgstr "Earráid VIM"
+
+msgid "Could not fix up function pointers to the DLL!"
+msgstr "Níorbh fhéidir pointeoirí feidhme a chóiriú i gcomhair an DLL!"
+
+#, c-format
+msgid "Vim: Caught %s event\n"
+msgstr "Vim: Fuarthas teagmhas %s\n"
+
+msgid "close"
+msgstr "dún"
+
+msgid "logoff"
+msgstr "logáil amach"
+
+msgid "shutdown"
+msgstr "múchadh"
+
+msgid "E371: Command not found"
+msgstr "E371: Ní bhfuarthas an t-ordú"
+
+msgid ""
+"VIMRUN.EXE not found in your $PATH.\n"
+"External commands will not pause after completion.\n"
+"See :help win32-vimrun for more information."
+msgstr ""
+"Níor aimsíodh VIMRUN.EXE i do $PATH.\n"
+"Ní mhoilleoidh orduithe seachtracha agus iad curtha i gcrích.\n"
+"Féach ar :help win32-vimrun chun níos mó eolas a fháil."
+
+msgid "Vim Warning"
+msgstr "Rabhadh Vim"
+
+#, c-format
+msgid "shell returned %d"
+msgstr "d'aisfhill an bhlaosc %d"
+
+#, c-format
+msgid "E372: Too many %%%c in format string"
+msgstr "E372: An iomarca %%%c i dteaghrán formáide"
+
+#, c-format
+msgid "E373: Unexpected %%%c in format string"
+msgstr "E373: %%%c gan choinne i dteaghrán formáide"
+
+msgid "E374: Missing ] in format string"
+msgstr "E374: ] ar iarraidh i dteaghrán formáide"
+
+#, c-format
+msgid "E375: Unsupported %%%c in format string"
+msgstr "E375: %%%c gan tacaíocht i dteaghrán formáide"
+
+#, c-format
+msgid "E376: Invalid %%%c in format string prefix"
+msgstr "E376: %%%c neamhbhailí i réimír an teaghráin formáide"
+
+#, c-format
+msgid "E377: Invalid %%%c in format string"
+msgstr "E377: %%%c neamhbhailí i dteaghrán formáide"
+
+#. nothing found
+msgid "E378: 'errorformat' contains no pattern"
+msgstr "E378: Níl aon phatrún i 'errorformat'"
+
+msgid "E379: Missing or empty directory name"
+msgstr "E379: Ainm comhadlainne ar iarraidh, nó folamh"
+
+msgid "E553: No more items"
+msgstr "E553: Níl aon mhír eile"
+
+msgid "E924: Current window was closed"
+msgstr "E924: Dúnadh an fhuinneog reatha"
+
+msgid "E925: Current quickfix was changed"
+msgstr "E925: Athraíodh an mearcheartúchán reatha"
+
+msgid "E926: Current location list was changed"
+msgstr "E926: Athraíodh an liosta suíomh reatha"
+
+#, c-format
+msgid "(%d of %d)%s%s: "
+msgstr "(%d as %d)%s%s: "
+
+msgid " (line deleted)"
+msgstr " (líne scriosta)"
+
+#, c-format
+msgid "%serror list %d of %d; %d errors "
+msgstr "%sliosta earráidí %d as %d; %d earráid "
+
+msgid "E380: At bottom of quickfix stack"
+msgstr "E380: In íochtar chruach na mearcheartúchán"
+
+msgid "E381: At top of quickfix stack"
+msgstr "E381: In uachtar chruach na mearcheartúchán"
+
+msgid "No entries"
+msgstr "Gan iontráil"
+
+msgid "E382: Cannot write, 'buftype' option is set"
+msgstr "E382: Ní féidir scríobh, rogha 'buftype' socraithe"
+
+msgid "Error file"
+msgstr "Comhad earráide"
+
+msgid "E683: File name missing or invalid pattern"
+msgstr "E683: Ainm comhaid ar iarraidh, nó patrún neamhbhailí"
+
+#, c-format
+msgid "Cannot open file \"%s\""
+msgstr "Ní féidir comhad \"%s\" a oscailt"
+
+msgid "E681: Buffer is not loaded"
+msgstr "E681: Níl an maolán luchtaithe"
+
+msgid "E777: String or List expected"
+msgstr "E777: Bhíothas ag súil le Teaghrán nó Liosta"
+
+#, c-format
+msgid "E369: invalid item in %s%%[]"
+msgstr "E369: mír neamhbhailí i %s%%[]"
+
+#, c-format
+msgid "E769: Missing ] after %s["
+msgstr "E769: ] ar iarraidh i ndiaidh %s["
+
+msgid "E944: Reverse range in character class"
+msgstr "E944: Raon aisiompaithe in aicme carachtar"
+
+msgid "E945: Range too large in character class"
+msgstr "E945: Raon rómhór in aicme carachtar"
+
+#, c-format
+msgid "E53: Unmatched %s%%("
+msgstr "E53: %s%%( corr"
+
+#, c-format
+msgid "E54: Unmatched %s("
+msgstr "E54: %s( corr"
+
+#, c-format
+msgid "E55: Unmatched %s)"
+msgstr "E55: %s) corr"
+
+msgid "E66: \\z( not allowed here"
+msgstr "E66: ní cheadaítear \\z( anseo"
+
+msgid "E67: \\z1 - \\z9 not allowed here"
+msgstr "E67: ní cheadaítear \\z1 - \\z9 anseo"
+
+#, c-format
+msgid "E69: Missing ] after %s%%["
+msgstr "E69: ] ar iarraidh i ndiaidh %s%%["
+
+#, c-format
+msgid "E70: Empty %s%%[]"
+msgstr "E70: %s%%[] folamh"
+
+msgid "E65: Illegal back reference"
+msgstr "E65: Cúltagairt neamhbhailí"
+
+msgid "E339: Pattern too long"
+msgstr "E339: Slonn rófhada"
+
+msgid "E50: Too many \\z("
+msgstr "E50: an iomarca \\z("
+
+#, c-format
+msgid "E51: Too many %s("
+msgstr "E51: an iomarca %s("
+
+msgid "E52: Unmatched \\z("
+msgstr "E52: \\z( corr"
+
+#, c-format
+msgid "E59: invalid character after %s@"
+msgstr "E59: carachtar neamhbhailí i ndiaidh %s@"
+
+#, c-format
+msgid "E60: Too many complex %s{...}s"
+msgstr "E60: An iomarca %s{...} coimpléascach"
+
+#, c-format
+msgid "E61: Nested %s*"
+msgstr "E61: %s* neadaithe"
+
+#, c-format
+msgid "E62: Nested %s%c"
+msgstr "E62: %s%c neadaithe"
+
+msgid "E63: invalid use of \\_"
+msgstr "E63: úsáid neamhbhailí de \\_"
+
+#, c-format
+msgid "E64: %s%c follows nothing"
+msgstr "E64: níl aon rud roimh %s%c"
+
+msgid "E68: Invalid character after \\z"
+msgstr "E68: Carachtar neamhbhailí i ndiaidh \\z"
+
+#, c-format
+msgid "E678: Invalid character after %s%%[dxouU]"
+msgstr "E678: Carachtar neamhbhailí i ndiaidh %s%%[dxouU]"
+
+#, c-format
+msgid "E71: Invalid character after %s%%"
+msgstr "E71: Carachtar neamhbhailí i ndiaidh %s%%"
+
+#, c-format
+msgid "E554: Syntax error in %s{...}"
+msgstr "E554: Earráid chomhréire i %s{...}"
+
+msgid "External submatches:\n"
+msgstr "Fo-mheaitseáil sheachtrach:\n"
+
+#, c-format
+msgid "E888: (NFA regexp) cannot repeat %s"
+msgstr "E888: (slonn NFA) ní féidir %s a athdhéanamh"
+
+msgid ""
+"E864: \\%#= can only be followed by 0, 1, or 2. The automatic engine will be "
+"used "
+msgstr ""
+"E864: Ní cheadaítear ach 0, 1, nó 2 tar éis \\%#=. Úsáidfear an t-inneall "
+"uathoibríoch "
+
+msgid "Switching to backtracking RE engine for pattern: "
+msgstr ""
+"Ag athrú go dtí an t-inneall rianaithe siar le haghaidh an phatrúin seo: "
+
+msgid "E865: (NFA) Regexp end encountered prematurely"
+msgstr "E865: (NFA) Thángthas ar dheireadh an tsloinn gan súil leis"
+
+#, c-format
+msgid "E866: (NFA regexp) Misplaced %c"
+msgstr "E866: (slonn NFA) %c as áit"
+
+#, c-format
+msgid "E877: (NFA regexp) Invalid character class: %ld"
+msgstr "E877: (slonn NFA) Aicme carachtar neamhbhailí: %ld"
+
+#, c-format
+msgid "E867: (NFA) Unknown operator '\\z%c'"
+msgstr "E867: (NFA) Oibreoir anaithnid '\\z%c'"
+
+#, c-format
+msgid "E867: (NFA) Unknown operator '\\%%%c'"
+msgstr "E867: (NFA) Oibreoir anaithnid '\\%%%c'"
+
+#. should never happen
+msgid "E868: Error building NFA with equivalence class!"
+msgstr "E868: Earráid agus NFA á thógáil le haicme coibhéise!"
+
+#, c-format
+msgid "E869: (NFA) Unknown operator '\\@%c'"
+msgstr "E869: (NFA) Oibreoir anaithnid '\\@%c'"
+
+msgid "E870: (NFA regexp) Error reading repetition limits"
+msgstr "E870: (slonn NFA) Earráid agus teorainneacha athdhéanta á léamh"
+
+#. Can't have a multi follow a multi.
+msgid "E871: (NFA regexp) Can't have a multi follow a multi"
+msgstr "E871: (slonn NFA) Ní cheadaítear ilchodach tar éis ilchodach"
+
+#. Too many `('
+msgid "E872: (NFA regexp) Too many '('"
+msgstr "E872: (slonn NFA) An iomarca '('"
+
+msgid "E879: (NFA regexp) Too many \\z("
+msgstr "E879: (slonn NFA) An iomarca \\z("
+
+msgid "E873: (NFA regexp) proper termination error"
+msgstr "E873: (slonn NFA) críochnú neamhoiriúnach"
+
+msgid "E874: (NFA) Could not pop the stack!"
+msgstr "E874: (NFA) Níorbh fhéidir an chruach a phlobadh!"
+
+msgid ""
+"E875: (NFA regexp) (While converting from postfix to NFA), too many states "
+"left on stack"
+msgstr ""
+"E875: (slonn NFA) (Le linn tiontaithe ó postfix go NFA), an iomarca "
+"staideanna fágtha ar an gcruach"
+
+msgid "E876: (NFA regexp) Not enough space to store the whole NFA "
+msgstr "E876: (slonn NFA) Níl go leor spáis ann don NFA iomlán "
+
+msgid "E878: (NFA) Could not allocate memory for branch traversal!"
+msgstr ""
+"E878: (NFA) Níorbh fhéidir cuimhne a leithdháileadh leis an gcraobh a "
+"thrasnaíl!"
+
+msgid ""
+"Could not open temporary log file for writing, displaying on stderr... "
+msgstr ""
+"Níorbh fhéidir logchomhad sealadach a oscailt le scríobh ann, á thaispeáint "
+"ar stderr..."
+
+#, c-format
+msgid "(NFA) COULD NOT OPEN %s !"
+msgstr "(NFA) NÍORBH FHÉIDIR %s A OSCAILT!"
+
+msgid "Could not open temporary log file for writing "
+msgstr "Níorbh fhéidir logchomhad sealadach a oscailt le scríobh ann "
+
+msgid " VREPLACE"
+msgstr " V-IONADAIGH"
+
+msgid " REPLACE"
+msgstr " ATHCHUR"
+
+msgid " REVERSE"
+msgstr " TIONTÚ"
+
+msgid " INSERT"
+msgstr " IONSÁ"
+
+msgid " (insert)"
+msgstr " (ionsáigh)"
+
+msgid " (replace)"
+msgstr " (ionadaigh)"
+
+msgid " (vreplace)"
+msgstr " (v-ionadaigh)"
+
+msgid " Hebrew"
+msgstr " Eabhrais"
+
+msgid " Arabic"
+msgstr " Araibis"
+
+msgid " (paste)"
+msgstr " (greamaigh)"
+
+msgid " VISUAL"
+msgstr " RADHARCACH"
+
+msgid " VISUAL LINE"
+msgstr " LÍNE RADHARCACH"
+
+msgid " VISUAL BLOCK"
+msgstr " BLOC RADHARCACH"
+
+msgid " SELECT"
+msgstr " ROGHNÚ"
+
+msgid " SELECT LINE"
+msgstr " SELECT LINE"
+
+msgid " SELECT BLOCK"
+msgstr " SELECT BLOCK"
+
+msgid "recording"
+msgstr "á thaifeadadh"
+
+#, c-format
+msgid "E383: Invalid search string: %s"
+msgstr "E383: Teaghrán cuardaigh neamhbhailí: %s"
+
+#, c-format
+msgid "E384: search hit TOP without match for: %s"
+msgstr "E384: bhuail an cuardach an BARR gan teaghrán comhoiriúnach le %s"
+
+#, c-format
+msgid "E385: search hit BOTTOM without match for: %s"
+msgstr "E385: bhuail an cuardach an BUN gan teaghrán comhoiriúnach le %s"
+
+msgid "E386: Expected '?' or '/' after ';'"
+msgstr "E386: Ag súil le '?' nó '/' i ndiaidh ';'"
+
+msgid " (includes previously listed match)"
+msgstr " (tá an teaghrán comhoiriúnaithe roimhe seo san áireamh)"
+
+#. cursor at status line
+msgid "--- Included files "
+msgstr "--- Comhaid cheanntáisc "
+
+msgid "not found "
+msgstr "gan aimsiú"
+
+msgid "in path ---\n"
+msgstr "i gconair ---\n"
+
+msgid " (Already listed)"
+msgstr " (Liostaithe cheana féin)"
+
+msgid " NOT FOUND"
+msgstr " AR IARRAIDH"
+
+#, c-format
+msgid "Scanning included file: %s"
+msgstr "Comhad ceanntáisc á scanadh: %s"
+
+#, c-format
+msgid "Searching included file %s"
+msgstr "Comhad ceanntáisc %s á chuardach"
+
+msgid "E387: Match is on current line"
+msgstr "E387: Tá an teaghrán comhoiriúnaithe ar an líne reatha"
+
+msgid "All included files were found"
+msgstr "Aimsíodh gach comhad ceanntáisc"
+
+msgid "No included files"
+msgstr "Gan comhaid cheanntáisc"
+
+msgid "E388: Couldn't find definition"
+msgstr "E388: Sainmhíniú gan aimsiú"
+
+msgid "E389: Couldn't find pattern"
+msgstr "E389: Patrún gan aimsiú"
+
+msgid "Substitute "
+msgstr "Ionadú "
+
+# in .viminfo
+#, c-format
+msgid ""
+"\n"
+"# Last %sSearch Pattern:\n"
+"~"
+msgstr ""
+"\n"
+"# %sPatrún Cuardaigh Is Déanaí:\n"
+"~"
+
+msgid "E756: Spell checking is not enabled"
+msgstr "E756: Níl seiceáil litrithe cumasaithe"
+
+#, c-format
+msgid "Warning: Cannot find word list \"%s_%s.spl\" or \"%s_ascii.spl\""
+msgstr ""
+"Rabhadh: Ní féidir liosta focal \"%s_%s.spl\" nó \"%s_ascii.spl\" a aimsiú"
+
+#, c-format
+msgid "Warning: Cannot find word list \"%s.%s.spl\" or \"%s.ascii.spl\""
+msgstr ""
+"Rabhadh: Ní féidir liosta focal \"%s.%s.spl\" nó \"%s.ascii.spl\" a aimsiú"
+
+msgid "E797: SpellFileMissing autocommand deleted buffer"
+msgstr "E797: Scrios uathordú SpellFileMissing an maolán"
+
+#, c-format
+msgid "Warning: region %s not supported"
+msgstr "Rabhadh: réigiún %s gan tacaíocht"
+
+msgid "Sorry, no suggestions"
+msgstr "Tá brón orm, níl aon mholadh ann"
+
+#, c-format
+msgid "Sorry, only %ld suggestions"
+msgstr "Tá brón orm, níl ach %ld moladh ann"
+
+#. for when 'cmdheight' > 1
+#. avoid more prompt
+#, c-format
+msgid "Change \"%.*s\" to:"
+msgstr "Athraigh \"%.*s\" go:"
+
+#, c-format
+msgid " < \"%.*s\""
+msgstr " < \"%.*s\""
+
+msgid "E752: No previous spell replacement"
+msgstr "E752: Níl aon ionadaí litrithe roimhe seo"
+
+#, c-format
+msgid "E753: Not found: %s"
+msgstr "E753: Gan aimsiú: %s"
+
+msgid "E758: Truncated spell file"
+msgstr "E758: Comhad teasctha litrithe"
+
+#, c-format
+msgid "Trailing text in %s line %d: %s"
+msgstr "Téacs chun deiridh i %s líne %d: %s"
+
+#, c-format
+msgid "Affix name too long in %s line %d: %s"
+msgstr "Ainm foircinn rófhada i %s líne %d: %s"
+
+msgid "E761: Format error in affix file FOL, LOW or UPP"
+msgstr "E761: Earráid fhormáide i gcomhad foircinn FOL, LOW, nó UPP"
+
+msgid "E762: Character in FOL, LOW or UPP is out of range"
+msgstr "E762: Carachtar i FOL, LOW nó UPP as raon"
+
+msgid "Compressing word tree..."
+msgstr "Crann focal á chomhbhrú..."
+
+#, c-format
+msgid "Reading spell file \"%s\""
+msgstr "Comhad litrithe \"%s\" á léamh"
+
+msgid "E757: This does not look like a spell file"
+msgstr "E757: Níl sé cosúil le comhad litrithe"
+
+msgid "E771: Old spell file, needs to be updated"
+msgstr "E771: Seanchomhad litrithe, tá gá lena nuashonrú"
+
+msgid "E772: Spell file is for newer version of Vim"
+msgstr "E772: Oibríonn an comhad litrithe le leagan níos nuaí de Vim"
+
+msgid "E770: Unsupported section in spell file"
+msgstr "E770: Rannán gan tacaíocht i gcomhad litrithe"
+
+#, c-format
+msgid "E778: This does not look like a .sug file: %s"
+msgstr "E778: Níl sé cosúil le comhad .sug: %s"
+
+#, c-format
+msgid "E779: Old .sug file, needs to be updated: %s"
+msgstr "E779: Seanchomhad .sug, tá gá lena nuashonrú: %s"
+
+#, c-format
+msgid "E780: .sug file is for newer version of Vim: %s"
+msgstr "E780: Oibríonn an comhad .sug le leagan níos nuaí de Vim: %s"
+
+#, c-format
+msgid "E781: .sug file doesn't match .spl file: %s"
+msgstr "E781: Níl an comhad .sug comhoiriúnach leis an gcomhad .spl: %s"
+
+#, c-format
+msgid "E782: error while reading .sug file: %s"
+msgstr "E782: earráid agus comhad .sug á léamh: %s"
+
+#, c-format
+msgid "Reading affix file %s..."
+msgstr "Comhad foircinn %s á léamh..."
+
+#, c-format
+msgid "Conversion failure for word in %s line %d: %s"
+msgstr "Theip ar thiontú focail i %s líne %d: %s"
+
+#, c-format
+msgid "Conversion in %s not supported: from %s to %s"
+msgstr "Tiontú i %s gan tacaíocht: ó %s go %s"
+
+#, c-format
+msgid "Conversion in %s not supported"
+msgstr "Tiontú i %s gan tacaíocht"
+
+#, c-format
+msgid "Invalid value for FLAG in %s line %d: %s"
+msgstr "Luach neamhbhailí ar FLAG i %s líne %d: %s"
+
+#, c-format
+msgid "FLAG after using flags in %s line %d: %s"
+msgstr "FLAG i ndiaidh bratacha in úsáid i %s líne %d: %s"
+
+#, c-format
+msgid ""
+"Defining COMPOUNDFORBIDFLAG after PFX item may give wrong results in %s line "
+"%d"
+msgstr ""
+"Seans go bhfaighfidh tú torthaí míchearta má chuireann tú COMPOUNDFORBIDFLAG "
+"tar éis míre PFX i %s líne %d"
+
+#, c-format
+msgid ""
+"Defining COMPOUNDPERMITFLAG after PFX item may give wrong results in %s line "
+"%d"
+msgstr ""
+"Seans go bhfaighfidh tú torthaí míchearta má chuireann tú COMPOUNDPERMITFLAG "
+"tar éis míre PFX i %s líne %d"
+
+#, c-format
+msgid "Wrong COMPOUNDRULES value in %s line %d: %s"
+msgstr "Luach mícheart ar COMPOUNDRULES i %s líne %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDWORDMAX value in %s line %d: %s"
+msgstr "Luach mícheart ar COMPOUNDWORDMAX i %s líne %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDMIN value in %s line %d: %s"
+msgstr "Luach mícheart ar COMPOUNDMIN i %s líne %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDSYLMAX value in %s line %d: %s"
+msgstr "Luach mícheart ar COMPOUNDSYLMAX i %s líne %d: %s"
+
+#, c-format
+msgid "Wrong CHECKCOMPOUNDPATTERN value in %s line %d: %s"
+msgstr "Luach mícheart ar CHECKCOMPOUNDPATTERN i %s líne %d: %s"
+
+#, c-format
+msgid "Different combining flag in continued affix block in %s line %d: %s"
+msgstr "Bratach dhifriúil cheangail i mbloc leanta foircinn i %s líne %d: %s"
+
+#, c-format
+msgid "Duplicate affix in %s line %d: %s"
+msgstr "Clib dhúblach i %s líne %d: %s"
+
+#, c-format
+msgid ""
+"Affix also used for BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST in %s "
+"line %d: %s"
+msgstr ""
+"Foirceann in úsáid le haghaidh BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/"
+"NOSUGGEST freisin i %s líne %d: %s"
+
+#, c-format
+msgid "Expected Y or N in %s line %d: %s"
+msgstr "Bhíothas ag súil le `Y' nó `N' i %s líne %d: %s"
+
+#, c-format
+msgid "Broken condition in %s line %d: %s"
+msgstr "Coinníoll briste i %s líne %d: %s"
+
+#, c-format
+msgid "Expected REP(SAL) count in %s line %d"
+msgstr "Bhíothas ag súil le líon na REP(SAL) i %s líne %d"
+
+#, c-format
+msgid "Expected MAP count in %s line %d"
+msgstr "Bhíothas ag súil le líon na MAP i %s líne %d"
+
+#, c-format
+msgid "Duplicate character in MAP in %s line %d"
+msgstr "Carachtar dúblach i MAP i %s líne %d"
+
+#, c-format
+msgid "Unrecognized or duplicate item in %s line %d: %s"
+msgstr "Mír anaithnid nó dhúblach i %s líne %d: %s"
+
+#, c-format
+msgid "Missing FOL/LOW/UPP line in %s"
+msgstr "Líne FOL/LOW/UPP ar iarraidh i %s"
+
+msgid "COMPOUNDSYLMAX used without SYLLABLE"
+msgstr "COMPOUNDSYLMAX in úsáid gan SYLLABLE"
+
+msgid "Too many postponed prefixes"
+msgstr "An iomarca réimíreanna curtha siar"
+
+msgid "Too many compound flags"
+msgstr "An iomarca bratach comhfhocail"
+
+msgid "Too many postponed prefixes and/or compound flags"
+msgstr "An iomarca réimíreanna curtha siar agus/nó bratacha comhfhocal"
+
+#, c-format
+msgid "Missing SOFO%s line in %s"
+msgstr "Líne SOFO%s ar iarraidh i %s"
+
+#, c-format
+msgid "Both SAL and SOFO lines in %s"
+msgstr "Línte SAL agus SOFO araon i %s"
+
+#, c-format
+msgid "Flag is not a number in %s line %d: %s"
+msgstr "Ní uimhir í an bhratach i %s líne %d: %s"
+
+#, c-format
+msgid "Illegal flag in %s line %d: %s"
+msgstr "Bratach neamhcheadaithe i %s líne %d: %s"
+
+#, c-format
+msgid "%s value differs from what is used in another .aff file"
+msgstr "Tá difear idir luach %s agus an luach i gcomhad .aff eile"
+
+#, c-format
+msgid "Reading dictionary file %s..."
+msgstr "Foclóir %s á léamh..."
+
+#, c-format
+msgid "E760: No word count in %s"
+msgstr "E760: Líon na bhfocal ar iarraidh i %s"
+
+#, c-format
+msgid "line %6d, word %6d - %s"
+msgstr "líne %6d, focal %6d - %s"
+
+#, c-format
+msgid "Duplicate word in %s line %d: %s"
+msgstr "Focal dúblach i %s líne %d: %s"
+
+#, c-format
+msgid "First duplicate word in %s line %d: %s"
+msgstr "An chéad fhocal dúblach i %s líne %d: %s"
+
+#, c-format
+msgid "%d duplicate word(s) in %s"
+msgstr "%d focal dúblach i %s"
+
+#, c-format
+msgid "Ignored %d word(s) with non-ASCII characters in %s"
+msgstr "Rinneadh neamhshuim ar %d focal le carachtair neamh-ASCII i %s"
+
+#, c-format
+msgid "Reading word file %s..."
+msgstr "Comhad focail %s á léamh..."
+
+#, c-format
+msgid "Duplicate /encoding= line ignored in %s line %d: %s"
+msgstr "Rinneadh neamhshuim ar líne dhúblach `/encoding=' i %s líne %d: %s"
+
+#, c-format
+msgid "/encoding= line after word ignored in %s line %d: %s"
+msgstr ""
+"Rinneadh neamhshuim ar líne `/encoding=' i ndiaidh focail i %s líne %d: %s"
+
+#, c-format
+msgid "Duplicate /regions= line ignored in %s line %d: %s"
+msgstr "Rinneadh neamhshuim ar líne `/regions=' i %s líne %d: %s"
+
+#, c-format
+msgid "Too many regions in %s line %d: %s"
+msgstr "An iomarca réigiún i %s líne %d: %s"
+
+#, c-format
+msgid "/ line ignored in %s line %d: %s"
+msgstr "Rinneadh neamhshuim ar líne `/' i %s líne %d: %s"
+
+#, c-format
+msgid "Invalid region nr in %s line %d: %s"
+msgstr "Uimhir neamhbhailí réigiúin i %s líne %d: %s"
+
+#, c-format
+msgid "Unrecognized flags in %s line %d: %s"
+msgstr "Bratacha anaithnide i %s líne %d: %s"
+
+#, c-format
+msgid "Ignored %d words with non-ASCII characters"
+msgstr "Rinneadh neamhshuim ar %d focal le carachtair neamh-ASCII"
+
+msgid "E845: Insufficient memory, word list will be incomplete"
+msgstr "E845: Easpa cuimhne, beidh an liosta focal neamhiomlán"
+
+#, c-format
+msgid "Compressed %d of %d nodes; %d (%d%%) remaining"
+msgstr "Comhbhrúdh %d as %d nód; %d (%d%%) fágtha"
+
+msgid "Reading back spell file..."
+msgstr "Comhad litrithe á léamh arís..."
+
+#.
+#. * Go through the trie of good words, soundfold each word and add it to
+#. * the soundfold trie.
+#.
+msgid "Performing soundfolding..."
+msgstr "Fuaimfhilleadh..."
+
+#, c-format
+msgid "Number of words after soundfolding: %ld"
+msgstr "Líon na bhfocal tar éis fuaimfhillte: %ld"
+
+#, c-format
+msgid "Total number of words: %d"
+msgstr "Líon iomlán na bhfocal: %d"
+
+#, c-format
+msgid "Writing suggestion file %s..."
+msgstr "Comhad moltaí %s á scríobh..."
+
+#, c-format
+msgid "Estimated runtime memory use: %d bytes"
+msgstr "Cuimhne measta a bheith in úsáid le linn rite: %d beart"
+
+msgid "E751: Output file name must not have region name"
+msgstr "E751: Ní cheadaítear ainm réigiúin in ainm an aschomhaid"
+
+msgid "E754: Only up to 8 regions supported"
+msgstr "E754: Ní thacaítear le níos mó ná 8 réigiún"
+
+#, c-format
+msgid "E755: Invalid region in %s"
+msgstr "E755: Réigiún neamhbhailí i %s"
+
+msgid "Warning: both compounding and NOBREAK specified"
+msgstr "Rabhadh: sonraíodh comhfhocail agus NOBREAK araon"
+
+#, c-format
+msgid "Writing spell file %s..."
+msgstr "Comhad litrithe %s á scríobh..."
+
+msgid "Done!"
+msgstr "Críochnaithe!"
+
+#, c-format
+msgid "E765: 'spellfile' does not have %ld entries"
+msgstr "E765: níl %ld iontráil i 'spellfile'"
+
+#, c-format
+msgid "Word '%.*s' removed from %s"
+msgstr "Baineadh focal '%.*s' ó %s"
+
+#, c-format
+msgid "Word '%.*s' added to %s"
+msgstr "Cuireadh focal '%.*s' le %s"
+
+msgid "E763: Word characters differ between spell files"
+msgstr "E763: Tá carachtair dhifriúla fhocail sna comhaid litrithe"
+
+#. This should have been checked when generating the .spl
+#. * file.
+msgid "E783: duplicate char in MAP entry"
+msgstr "E783: carachtar dúblach in iontráil MAP"
+
+msgid "No Syntax items defined for this buffer"
+msgstr "Níl aon mhír chomhréire sainmhínithe le haghaidh an mhaoláin seo"
+
+msgid "syntax conceal on"
+msgstr "syntax conceal on"
+
+msgid "syntax conceal off"
+msgstr "syntax conceal off"
+
+#, c-format
+msgid "E390: Illegal argument: %s"
+msgstr "E390: Argóint neamhcheadaithe: %s"
+
+msgid "syntax case ignore"
+msgstr "syntax case ignore"
+
+msgid "syntax case match"
+msgstr "syntax case match"
+
+msgid "syntax spell toplevel"
+msgstr "syntax spell toplevel"
+
+msgid "syntax spell notoplevel"
+msgstr "syntax spell notoplevel"
+
+msgid "syntax spell default"
+msgstr "syntax spell default"
+
+msgid "syntax iskeyword "
+msgstr "syntax iskeyword "
+
+#, c-format
+msgid "E391: No such syntax cluster: %s"
+msgstr "E391: Níl a leithéid de mhogall comhréire: %s"
+
+msgid "syncing on C-style comments"
+msgstr "ag sioncrónú ar nóta den nós C"
+
+msgid "no syncing"
+msgstr "gan sioncrónú"
+
+msgid "syncing starts "
+msgstr "tosaíonn an sioncrónú "
+
+msgid " lines before top line"
+msgstr " línte roimh an bharr"
+
+msgid ""
+"\n"
+"--- Syntax sync items ---"
+msgstr ""
+"\n"
+"--- Míreanna Comhréire Sionc ---"
+
+msgid ""
+"\n"
+"syncing on items"
+msgstr ""
+"\n"
+"ag sioncrónú ar mhíreanna"
+
+msgid ""
+"\n"
+"--- Syntax items ---"
+msgstr ""
+"\n"
+"--- Míreanna comhréire ---"
+
+#, c-format
+msgid "E392: No such syntax cluster: %s"
+msgstr "E392: Níl a leithéid de mhogall comhréire: %s"
+
+msgid "minimal "
+msgstr "íosta "
+
+msgid "maximal "
+msgstr "uasta "
+
+msgid "; match "
+msgstr "; meaitseáil "
+
+msgid " line breaks"
+msgstr " bristeacha líne"
+
+msgid "E395: contains argument not accepted here"
+msgstr "E395: tá argóint ann nach nglactar leis anseo"
+
+msgid "E844: invalid cchar value"
+msgstr "E844: luach neamhbhailí cchar"
+
+msgid "E393: group[t]here not accepted here"
+msgstr "E393: ní ghlactar le group[t]here anseo"
+
+#, c-format
+msgid "E394: Didn't find region item for %s"
+msgstr "E394: Níor aimsíodh mír réigiúin le haghaidh %s"
+
+msgid "E397: Filename required"
+msgstr "E397: Tá gá le hainm comhaid"
+
+msgid "E847: Too many syntax includes"
+msgstr "E847: An iomarca comhad comhréire in úsáid"
+
+#, c-format
+msgid "E789: Missing ']': %s"
+msgstr "E789: ']' ar iarraidh: %s"
+
+#, c-format
+msgid "E890: trailing char after ']': %s]%s"
+msgstr "E890: carachtar tar éis ']': %s]%s"
+
+#, c-format
+msgid "E398: Missing '=': %s"
+msgstr "E398: '=' ar iarraidh: %s"
+
+#, c-format
+msgid "E399: Not enough arguments: syntax region %s"
+msgstr "E399: Níl go leor argóintí ann: réigiún comhréire %s"
+
+msgid "E848: Too many syntax clusters"
+msgstr "E848: An iomarca mogall comhréire"
+
+msgid "E400: No cluster specified"
+msgstr "E400: Níor sonraíodh mogall"
+
+#, c-format
+msgid "E401: Pattern delimiter not found: %s"
+msgstr "E401: Teormharcóir patrúin gan aimsiú: %s"
+
+#, c-format
+msgid "E402: Garbage after pattern: %s"
+msgstr "E402: Dramhaíl i ndiaidh patrúin: %s"
+
+msgid "E403: syntax sync: line continuations pattern specified twice"
+msgstr "E403: comhréir sionc: tugadh patrún leanúint líne faoi dhó"
+
+#, c-format
+msgid "E404: Illegal arguments: %s"
+msgstr "E404: Argóintí neamhcheadaithe: %s"
+
+#, c-format
+msgid "E405: Missing equal sign: %s"
+msgstr "E405: Sín chothroime ar iarraidh: %s"
+
+#, c-format
+msgid "E406: Empty argument: %s"
+msgstr "E406: Argóint fholamh: %s"
+
+#, c-format
+msgid "E407: %s not allowed here"
+msgstr "E407: ní cheadaítear %s anseo"
+
+#, c-format
+msgid "E408: %s must be first in contains list"
+msgstr "E408: ní foláir %s a thabhairt ar dtús sa liosta `contains'"
+
+#, c-format
+msgid "E409: Unknown group name: %s"
+msgstr "E409: Ainm anaithnid grúpa: %s"
+
+#, c-format
+msgid "E410: Invalid :syntax subcommand: %s"
+msgstr "E410: Fo-ordú neamhbhailí :syntax: %s"
+
+msgid ""
+" TOTAL COUNT MATCH SLOWEST AVERAGE NAME PATTERN"
+msgstr ""
+" IOMLÁN LÍON MEAITS IS MOILLE MEÁN AINM PATRÚN"
+
+msgid "E679: recursive loop loading syncolor.vim"
+msgstr "E679: lúb athchúrsach agus syncolor.vim á luchtú"
+
+#, c-format
+msgid "E411: highlight group not found: %s"
+msgstr "E411: Grúpa aibhsithe gan aimsiú: %s"
+
+#, c-format
+msgid "E412: Not enough arguments: \":highlight link %s\""
+msgstr "E412: Easpa argóintí: \":highlight link %s\""
+
+#, c-format
+msgid "E413: Too many arguments: \":highlight link %s\""
+msgstr "E413: An iomarca argóintí: \":highlight link %s\""
+
+msgid "E414: group has settings, highlight link ignored"
+msgstr ""
+"E414: tá socruithe ag an ghrúpa, ag déanamh neamhshuim ar nasc aibhsithe"
+
+#, c-format
+msgid "E415: unexpected equal sign: %s"
+msgstr "E415: sín chothroime gan choinne: %s"
+
+#, c-format
+msgid "E416: missing equal sign: %s"
+msgstr "E416: sín chothroime ar iarraidh: %s"
+
+#, c-format
+msgid "E417: missing argument: %s"
+msgstr "E417: argóint ar iarraidh: %s"
+
+#, c-format
+msgid "E418: Illegal value: %s"
+msgstr "E418: Luach neamhcheadaithe: %s"
+
+msgid "E419: FG color unknown"
+msgstr "E419: Dath anaithnid an chúlra"
+
+msgid "E420: BG color unknown"
+msgstr "E420: Dath anaithnid an tulra"
+
+#, c-format
+msgid "E421: Color name or number not recognized: %s"
+msgstr "E421: Níor aithníodh ainm/uimhir an datha: %s"
+
+#, c-format
+msgid "E422: terminal code too long: %s"
+msgstr "E422: cód teirminéil rófhada: %s"
+
+#, c-format
+msgid "E423: Illegal argument: %s"
+msgstr "E423: Argóint neamhcheadaithe: %s"
+
+msgid "E424: Too many different highlighting attributes in use"
+msgstr "E424: An iomarca tréithe aibhsithe in úsáid"
+
+msgid "E669: Unprintable character in group name"
+msgstr "E669: Carachtar neamhghrafach in ainm grúpa"
+
+msgid "W18: Invalid character in group name"
+msgstr "W18: Carachtar neamhbhailí in ainm grúpa"
+
+msgid "E849: Too many highlight and syntax groups"
+msgstr "E849: An iomarca grúpaí aibhsithe agus comhréire"
+
+msgid "E555: at bottom of tag stack"
+msgstr "E555: in íochtar na cruaiche clibeanna"
+
+msgid "E556: at top of tag stack"
+msgstr "E556: in uachtar na cruaiche clibeanna"
+
+msgid "E425: Cannot go before first matching tag"
+msgstr "E425: Ní féidir a dhul roimh an chéad chlib chomhoiriúnach"
+
+#, c-format
+msgid "E426: tag not found: %s"
+msgstr "E426: clib gan aimsiú: %s"
+
+msgid " # pri kind tag"
+msgstr " # tos cin clib"
+
+msgid "file\n"
+msgstr "comhad\n"
+
+msgid "E427: There is only one matching tag"
+msgstr "E427: Tá aon chlib chomhoiriúnach amháin"
+
+msgid "E428: Cannot go beyond last matching tag"
+msgstr "E428: Ní féidir a dhul thar an chlib chomhoiriúnach deireanach"
+
+#, c-format
+msgid "File \"%s\" does not exist"
+msgstr "Níl a leithéid de chomhad \"%s\" ann"
+
+#. Give an indication of the number of matching tags
+#, c-format
+msgid "tag %d of %d%s"
+msgstr "clib %d as %d%s"
+
+msgid " or more"
+msgstr " nó os a chionn"
+
+msgid " Using tag with different case!"
+msgstr " Ag úsáid clib le cás eile!"
+
+#, c-format
+msgid "E429: File \"%s\" does not exist"
+msgstr "E429: Níl a leithéid de chomhad \"%s\""
+
+#. Highlight title
+msgid ""
+"\n"
+" # TO tag FROM line in file/text"
+msgstr ""
+"\n"
+" # Go clib Ó líne i gcomhad/téacs"
+
+#, c-format
+msgid "Searching tags file %s"
+msgstr "Comhad clibeanna %s á chuardach"
+
+#, c-format
+msgid "E430: Tag file path truncated for %s\n"
+msgstr "E430: Teascadh conair an chomhaid clibeanna le haghaidh %s\n"
+
+msgid "Ignoring long line in tags file"
+msgstr "Ag déanamh neamhaird de líne fhada sa chomhad clibeanna"
+
+#, c-format
+msgid "E431: Format error in tags file \"%s\""
+msgstr "E431: Earráid fhormáide i gcomhad clibeanna \"%s\""
+
+#, c-format
+msgid "Before byte %ld"
+msgstr "Roimh bheart %ld"
+
+#, c-format
+msgid "E432: Tags file not sorted: %s"
+msgstr "E432: Comhad clibeanna gan sórtáil: %s"
+
+#. never opened any tags file
+msgid "E433: No tags file"
+msgstr "E433: Níl aon chomhad clibeanna"
+
+msgid "E434: Can't find tag pattern"
+msgstr "E434: Patrún clibe gan aimsiú"
+
+msgid "E435: Couldn't find tag, just guessing!"
+msgstr "E435: Clib gan aimsiú, ag tabhairt buille faoi thuairim!"
+
+#, c-format
+msgid "Duplicate field name: %s"
+msgstr "Ainm réimse dúbailte: %s"
+
+msgid "' not known. Available builtin terminals are:"
+msgstr "' anaithnid. Is iad seo na teirminéil insuite:"
+
+msgid "defaulting to '"
+msgstr "réamhshocrú = '"
+
+msgid "E557: Cannot open termcap file"
+msgstr "E557: Ní féidir an comhad termcap a oscailt"
+
+msgid "E558: Terminal entry not found in terminfo"
+msgstr "E558: Iontráil teirminéil gan aimsiú sa terminfo"
+
+msgid "E559: Terminal entry not found in termcap"
+msgstr "E559: Iontráil teirminéil gan aimsiú sa termcap"
+
+#, c-format
+msgid "E436: No \"%s\" entry in termcap"
+msgstr "E436: Níl aon iontráil \"%s\" sa termcap"
+
+msgid "E437: terminal capability \"cm\" required"
+msgstr "E437: tá gá leis an chumas teirminéil \"cm\""
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Terminal keys ---"
+msgstr ""
+"\n"
+"--- Eochracha teirminéil ---"
+
+msgid "Cannot open $VIMRUNTIME/rgb.txt"
+msgstr "Ní féidir $VIMRUNTIME/rgb.txt a oscailt"
+
+msgid "new shell started\n"
+msgstr "tosaíodh blaosc nua\n"
+
+msgid "Vim: Error reading input, exiting...\n"
+msgstr "Vim: Earráid agus an t-inchomhad á léamh; ag scor...\n"
+
+msgid "Used CUT_BUFFER0 instead of empty selection"
+msgstr "Úsáideadh CUT_BUFFER0 in ionad roghnúcháin folaimh"
+
+#. This happens when the FileChangedRO autocommand changes the
+#. * file in a way it becomes shorter.
+msgid "E881: Line count changed unexpectedly"
+msgstr "E881: Athraíodh líon na línte gan súil leis"
+
+#. must display the prompt
+msgid "No undo possible; continue anyway"
+msgstr "Ní féidir a chealú; lean ar aghaidh mar sin féin"
+
+#, c-format
+msgid "E828: Cannot open undo file for writing: %s"
+msgstr "E828: Ní féidir comhad staire a oscailt le scríobh ann: %s"
+
+#, c-format
+msgid "E825: Corrupted undo file (%s): %s"
+msgstr "E825: Comhad staire truaillithe (%s): %s"
+
+msgid "Cannot write undo file in any directory in 'undodir'"
+msgstr "Ní féidir comhad staire a shábháil in aon chomhadlann in 'undodir'"
+
+#, c-format
+msgid "Will not overwrite with undo file, cannot read: %s"
+msgstr "Ní forscríobhfar le comhad staire, ní féidir é a léamh: %s"
+
+#, c-format
+msgid "Will not overwrite, this is not an undo file: %s"
+msgstr "Ní forscríobhfar é, ní comhad staire é seo: %s"
+
+msgid "Skipping undo file write, nothing to undo"
+msgstr "Ní scríobhfar an comhad staire, níl aon stair ann"
+
+#, c-format
+msgid "Writing undo file: %s"
+msgstr "Comhad staire á scríobh: %s"
+
+#, c-format
+msgid "E829: write error in undo file: %s"
+msgstr "E829: earráid le linn scríofa i gcomhad staire: %s"
+
+#, c-format
+msgid "Not reading undo file, owner differs: %s"
+msgstr "Níor léadh an comhad staire; úinéir difriúil: %s"
+
+#, c-format
+msgid "Reading undo file: %s"
+msgstr "Comhad staire á léamh: %s"
+
+#, c-format
+msgid "E822: Cannot open undo file for reading: %s"
+msgstr "E822: Ní féidir an comhad staire a oscailt lena léamh: %s"
+
+#, c-format
+msgid "E823: Not an undo file: %s"
+msgstr "E823: Ní comhad staire é: %s"
+
+#, c-format
+msgid "E832: Non-encrypted file has encrypted undo file: %s"
+msgstr "E832: Comhad neamhchriptithe le comhad staire criptithe: %s"
+
+#, c-format
+msgid "E826: Undo file decryption failed: %s"
+msgstr "E826: Níorbh fhéidir an comhad staire a dhíchriptiú: %s"
+
+#, c-format
+msgid "E827: Undo file is encrypted: %s"
+msgstr "E827: Tá an comhad staire criptithe: %s"
+
+#, c-format
+msgid "E824: Incompatible undo file: %s"
+msgstr "E824: Comhad staire neamh-chomhoiriúnach: %s"
+
+msgid "File contents changed, cannot use undo info"
+msgstr "Athraíodh ábhar an chomhaid, ní féidir comhad staire a úsáid"
+
+#, c-format
+msgid "Finished reading undo file %s"
+msgstr "Comhad staire %s léite"
+
+msgid "Already at oldest change"
+msgstr "Ag an athrú is sine cheana"
+
+msgid "Already at newest change"
+msgstr "Ag an athrú is nuaí cheana"
+
+#, c-format
+msgid "E830: Undo number %ld not found"
+msgstr "E830: Mír staire %ld gan aimsiú"
+
+msgid "E438: u_undo: line numbers wrong"
+msgstr "E438: u_undo: líne-uimhreacha míchearta"
+
+msgid "more line"
+msgstr "líne eile"
+
+msgid "more lines"
+msgstr "líne eile"
+
+msgid "line less"
+msgstr "líne níos lú"
+
+msgid "fewer lines"
+msgstr "líne níos lú"
+
+msgid "change"
+msgstr "athrú"
+
+msgid "changes"
+msgstr "athrú"
+
+#, c-format
+msgid "%ld %s; %s #%ld %s"
+msgstr "%ld %s; %s #%ld %s"
+
+msgid "before"
+msgstr "roimh"
+
+msgid "after"
+msgstr "tar éis"
+
+msgid "Nothing to undo"
+msgstr "Níl faic le cealú"
+
+msgid "number changes when saved"
+msgstr "athraíonn an uimhir ag am sábhála"
+
+#, c-format
+msgid "%ld seconds ago"
+msgstr "%ld soicind ó shin"
+
+msgid "E790: undojoin is not allowed after undo"
+msgstr "E790: ní cheadaítear \"undojoin\" tar éis \"undo\""
+
+msgid "E439: undo list corrupt"
+msgstr "E439: tá an liosta cealaithe truaillithe"
+
+msgid "E440: undo line missing"
+msgstr "E440: líne chealaithe ar iarraidh"
+
+#, c-format
+msgid "E122: Function %s already exists, add ! to replace it"
+msgstr "E122: Tá feidhm %s ann cheana, cuir ! leis an ordú chun é a asáitiú"
+
+msgid "E717: Dictionary entry already exists"
+msgstr "E717: Tá an iontráil foclóra seo ann cheana"
+
+msgid "E718: Funcref required"
+msgstr "E718: Tá gá le Funcref"
+
+#, c-format
+msgid "E130: Unknown function: %s"
+msgstr "E130: Feidhm anaithnid: %s"
+
+#, c-format
+msgid "E125: Illegal argument: %s"
+msgstr "E125: Argóint neamhcheadaithe: %s"
+
+#, c-format
+msgid "E853: Duplicate argument name: %s"
+msgstr "E853: Argóint dhúbailte: %s"
+
+#, c-format
+msgid "E740: Too many arguments for function %s"
+msgstr "E740: An iomarca argóintí d'fheidhm %s"
+
+#, c-format
+msgid "E116: Invalid arguments for function %s"
+msgstr "E116: Argóintí neamhbhailí d'fheidhm %s"
+
+msgid "E132: Function call depth is higher than 'maxfuncdepth'"
+msgstr "E132: Doimhneacht na nglaonna níos mó ná 'maxfuncdepth'"
+
+#, c-format
+msgid "calling %s"
+msgstr "%s á glao"
+
+#, c-format
+msgid "%s aborted"
+msgstr "%s tobscortha"
+
+#, c-format
+msgid "%s returning #%ld"
+msgstr "%s ag aisfhilleadh #%ld"
+
+#, c-format
+msgid "%s returning %s"
+msgstr "%s ag aisfhilleadh %s"
+
+msgid "E699: Too many arguments"
+msgstr "E699: An iomarca argóintí"
+
+#, c-format
+msgid "E117: Unknown function: %s"
+msgstr "E117: Feidhm anaithnid: %s"
+
+#, c-format
+msgid "E933: Function was deleted: %s"
+msgstr "E933: Scriosadh an fheidhm: %s"
+
+#, c-format
+msgid "E119: Not enough arguments for function: %s"
+msgstr "E119: Níl go leor feidhmeanna d'fheidhm: %s"
+
+#, c-format
+msgid "E120: Using <SID> not in a script context: %s"
+msgstr "E120: <SID> á úsáid ach gan a bheith i gcomhthéacs scripte: %s"
+
+#, c-format
+msgid "E725: Calling dict function without Dictionary: %s"
+msgstr "E725: Feidhm 'dict' á ghlao gan Foclóir: %s"
+
+msgid "E129: Function name required"
+msgstr "E129: Tá gá le hainm feidhme"
+
+#, c-format
+msgid "E128: Function name must start with a capital or \"s:\": %s"
+msgstr ""
+"E128: Caithfidh ceannlitir a bheith ar dtús ainm feidhme, nó \"s:\": %s"
+
+#, c-format
+msgid "E884: Function name cannot contain a colon: %s"
+msgstr "E884: Ní cheadaítear idirstad in ainm feidhme: %s"
+
+#, c-format
+msgid "E123: Undefined function: %s"
+msgstr "E123: Feidhm gan sainmhíniú: %s"
+
+#, c-format
+msgid "E124: Missing '(': %s"
+msgstr "E124: '(' ar iarraidh: %s"
+
+msgid "E862: Cannot use g: here"
+msgstr "E862: Ní féidir g: a úsáid anseo"
+
+#, c-format
+msgid "E932: Closure function should not be at top level: %s"
+msgstr "E932: Ní mór don chlabhsúr a bheith ag an mbarrleibhéal: %s"
+
+msgid "E126: Missing :endfunction"
+msgstr "E126: :endfunction ar iarraidh"
+
+#, c-format
+msgid "W22: Text found after :endfunction: %s"
+msgstr "W22: Aimsíodh téacs tar éis :endfunction: %s"
+
+#, c-format
+msgid "E707: Function name conflicts with variable: %s"
+msgstr "E707: Tagann ainm na feidhme salach ar athróg: %s"
+
+#, c-format
+msgid "E127: Cannot redefine function %s: It is in use"
+msgstr ""
+"E127: Ní féidir sainmhíniú nua a dhéanamh ar fheidhm %s: In úsáid cheana"
+
+#, c-format
+msgid "E746: Function name does not match script file name: %s"
+msgstr ""
+"E746: Níl ainm na feidhme comhoiriúnach le hainm comhaid na scripte: %s"
+
+#, c-format
+msgid "E131: Cannot delete function %s: It is in use"
+msgstr "E131: Ní féidir feidhm %s a scriosadh: Tá sé in úsáid faoi láthair"
+
+msgid "E133: :return not inside a function"
+msgstr "E133: Caithfidh :return a bheith isteach i bhfeidhm"
+
+#, c-format
+msgid "E107: Missing parentheses: %s"
+msgstr "E107: Lúibíní ar iarraidh: %s"
+
+msgid ""
+"\n"
+"MS-Windows 64-bit GUI version"
+msgstr ""
+"\n"
+"Leagan GUI 64 giotán MS-Windows"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit GUI version"
+msgstr ""
+"\n"
+"Leagan GUI 32 giotán MS-Windows"
+
+msgid " with OLE support"
+msgstr " le tacaíocht OLE"
+
+msgid ""
+"\n"
+"MS-Windows 64-bit console version"
+msgstr ""
+"\n"
+"Leagan consóil 64 giotán MS-Windows"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit console version"
+msgstr ""
+"\n"
+"Leagan consóil 32 giotán MS-Windows"
+
+msgid ""
+"\n"
+"MacOS X (unix) version"
+msgstr ""
+"\n"
+"Leagan MacOS X (unix)"
+
+msgid ""
+"\n"
+"MacOS X version"
+msgstr ""
+"\n"
+"Leagan MacOS X"
+
+msgid ""
+"\n"
+"MacOS version"
+msgstr ""
+"\n"
+"Leagan MacOS"
+
+msgid ""
+"\n"
+"OpenVMS version"
+msgstr ""
+"\n"
+"Leagan OpenVMS"
+
+msgid ""
+"\n"
+"Included patches: "
+msgstr ""
+"\n"
+"Paistí san áireamh: "
+
+msgid ""
+"\n"
+"Extra patches: "
+msgstr ""
+"\n"
+"Paistí sa bhreis: "
+
+msgid "Modified by "
+msgstr "Mionathraithe ag "
+
+msgid ""
+"\n"
+"Compiled "
+msgstr ""
+"\n"
+"Tiomsaithe "
+
+# with "Tiomsaithe"
+msgid "by "
+msgstr "ag "
+
+msgid ""
+"\n"
+"Huge version "
+msgstr ""
+"\n"
+"Leagan ollmhór "
+
+msgid ""
+"\n"
+"Big version "
+msgstr ""
+"\n"
+"Leagan mór "
+
+msgid ""
+"\n"
+"Normal version "
+msgstr ""
+"\n"
+"Leagan coitianta "
+
+msgid ""
+"\n"
+"Small version "
+msgstr ""
+"\n"
+"Leagan beag "
+
+msgid ""
+"\n"
+"Tiny version "
+msgstr ""
+"\n"
+"Leagan beag bídeach "
+
+msgid "without GUI."
+msgstr "gan GUI."
+
+msgid "with GTK3 GUI."
+msgstr "le GUI GTK3."
+
+msgid "with GTK2-GNOME GUI."
+msgstr "le GUI GTK2-GNOME."
+
+msgid "with GTK2 GUI."
+msgstr "le GUI GTK2."
+
+msgid "with X11-Motif GUI."
+msgstr "le GUI X11-Motif."
+
+msgid "with X11-neXtaw GUI."
+msgstr "le GUI X11-neXtaw."
+
+msgid "with X11-Athena GUI."
+msgstr "le GUI X11-Athena."
+
+msgid "with Photon GUI."
+msgstr "le GUI Photon."
+
+msgid "with GUI."
+msgstr "le GUI."
+
+msgid "with Carbon GUI."
+msgstr "le GUI Carbon."
+
+msgid "with Cocoa GUI."
+msgstr "le GUI Cocoa."
+
+msgid "with (classic) GUI."
+msgstr "le GUI (clasaiceach)."
+
+msgid " Features included (+) or not (-):\n"
+msgstr " Gnéithe san áireamh (+) nó nach bhfuil (-):\n"
+
+msgid " system vimrc file: \""
+msgstr " comhad vimrc an chórais: \""
+
+msgid " user vimrc file: \""
+msgstr " comhad vimrc úsáideora: \""
+
+msgid " 2nd user vimrc file: \""
+msgstr " dara comhad vimrc úsáideora: \""
+
+msgid " 3rd user vimrc file: \""
+msgstr " tríú comhad vimrc úsáideora: \""
+
+msgid " user exrc file: \""
+msgstr " comhad exrc úsáideora: \""
+
+msgid " 2nd user exrc file: \""
+msgstr " dara comhad úsáideora exrc: \""
+
+msgid " system gvimrc file: \""
+msgstr " comhad gvimrc córais: \""
+
+msgid " user gvimrc file: \""
+msgstr " comhad gvimrc úsáideora: \""
+
+msgid "2nd user gvimrc file: \""
+msgstr "dara comhad gvimrc úsáideora: \""
+
+msgid "3rd user gvimrc file: \""
+msgstr "tríú comhad gvimrc úsáideora: \""
+
+msgid " defaults file: \""
+msgstr " comhad na réamhshocruithe: \""
+
+msgid " system menu file: \""
+msgstr " comhad roghchláir an chórais: \""
+
+msgid " fall-back for $VIM: \""
+msgstr " rogha thánaisteach do $VIM: \""
+
+msgid " f-b for $VIMRUNTIME: \""
+msgstr " f-b do $VIMRUNTIME: \""
+
+msgid "Compilation: "
+msgstr "Tiomsú: "
+
+msgid "Compiler: "
+msgstr "Tiomsaitheoir: "
+
+msgid "Linking: "
+msgstr "Nascáil: "
+
+msgid " DEBUG BUILD"
+msgstr " LEAGAN DÍFHABHTAITHE"
+
+msgid "VIM - Vi IMproved"
+msgstr "VIM - Vi IMproved"
+
+msgid "version "
+msgstr "leagan "
+
+msgid "by Bram Moolenaar et al."
+msgstr "le Bram Moolenaar et al."
+
+msgid "Vim is open source and freely distributable"
+msgstr "Is saorbhogearra é Vim"
+
+msgid "Help poor children in Uganda!"
+msgstr "Tabhair cabhair do pháistí bochta in Uganda!"
+
+msgid "type :help iccf<Enter> for information "
+msgstr "clóscríobh :help iccf<Enter> chun eolas a fháil "
+
+msgid "type :q<Enter> to exit "
+msgstr "clóscríobh :q<Enter> chun scoir "
+
+msgid "type :help<Enter> or <F1> for on-line help"
+msgstr "clóscríobh :help<Enter> nó <F1> le haghaidh cabhrach ar líne"
+
+msgid "type :help version8<Enter> for version info"
+msgstr "clóscríobh :help version8<Enter> le haghaidh eolais faoin leagan"
+
+msgid "Running in Vi compatible mode"
+msgstr "Sa mhód comhoiriúnachta Vi"
+
+msgid "type :set nocp<Enter> for Vim defaults"
+msgstr ""
+"clóscríobh :set nocp<Enter> chun na réamhshocruithe Vim a thaispeáint"
+
+msgid "type :help cp-default<Enter> for info on this"
+msgstr ""
+"clóscríobh :help cp-default<Enter> chun níos mó eolas faoi seo a fháil"
+
+# don't see where to localize "Help->Orphans"? --kps
+msgid "menu Help->Orphans for information "
+msgstr "roghchlár Help->Orphans chun eolas a fháil "
+
+msgid "Running modeless, typed text is inserted"
+msgstr "Á rith gan mhóid, ag ionsá an téacs atá iontráilte"
+
+# same problem --kps
+msgid "menu Edit->Global Settings->Toggle Insert Mode "
+msgstr "roghchlár Edit->Global Settings->Toggle Insert Mode "
+
+msgid " for two modes "
+msgstr " do dhá mhód "
+
+# same problem --kps
+msgid "menu Edit->Global Settings->Toggle Vi Compatible"
+msgstr "roghchlár Edit->Global Settings->Toggle Vi Compatible"
+
+msgid " for Vim defaults "
+msgstr " le haghaidh réamhshocruithe Vim "
+
+msgid "Sponsor Vim development!"
+msgstr "Bí i d'urraitheoir Vim!"
+
+msgid "Become a registered Vim user!"
+msgstr "Bí i d'úsáideoir cláraithe Vim!"
+
+msgid "type :help sponsor<Enter> for information "
+msgstr "clóscríobh :help sponsor<Enter> chun eolas a fháil "
+
+msgid "type :help register<Enter> for information "
+msgstr "clóscríobh :help register<Enter> chun eolas a fháil "
+
+msgid "menu Help->Sponsor/Register for information "
+msgstr "roghchlár Help->Sponsor/Register chun eolas a fháil "
+
+msgid "Already only one window"
+msgstr "Níl ach aon fhuinneog amháin ann cheana"
+
+msgid "E441: There is no preview window"
+msgstr "E441: Níl aon fhuinneog réamhamhairc ann"
+
+msgid "E442: Can't split topleft and botright at the same time"
+msgstr "E442: Ní féidir a scoilteadh topleft agus botright san am céanna"
+
+msgid "E443: Cannot rotate when another window is split"
+msgstr "E443: Ní féidir rothlú nuair atá fuinneog eile scoilte"
+
+msgid "E444: Cannot close last window"
+msgstr "E444: Ní féidir an fhuinneog dheiridh a dhúnadh"
+
+msgid "E813: Cannot close autocmd window"
+msgstr "E813: Ní féidir fuinneog autocmd a dhúnadh"
+
+msgid "E814: Cannot close window, only autocmd window would remain"
+msgstr ""
+"E814: Ní féidir an fhuinneog a dhúnadh, ní bheadh ach fuinneog autocmd fágtha"
+
+msgid "E445: Other window contains changes"
+msgstr "E445: Tá athruithe ann san fhuinneog eile"
+
+msgid "E446: No file name under cursor"
+msgstr "E446: Níl ainm comhaid faoin chúrsóir"
+
+#, c-format
+msgid "E447: Can't find file \"%s\" in path"
+msgstr "E447: Níl aon fháil ar chomhad \"%s\" sa chonair"
+
+#, c-format
+msgid "E799: Invalid ID: %ld (must be greater than or equal to 1)"
+msgstr "E799: Aitheantas neamhbhailí: %ld (ní mór dó a bheith >= 1)"
+
+#, c-format
+msgid "E801: ID already taken: %ld"
+msgstr "E801: Aitheantas in úsáid cheana: %ld"
+
+msgid "List or number required"
+msgstr "Tá gá le liosta nó uimhir"
+
+#, c-format
+msgid "E802: Invalid ID: %ld (must be greater than or equal to 1)"
+msgstr "E802: Aitheantas neamhbhailí: %ld (ní mór dó a bheith >= 1)"
+
+#, c-format
+msgid "E803: ID not found: %ld"
+msgstr "E803: Aitheantas gan aimsiú: %ld"
+
+#, c-format
+msgid "E370: Could not load library %s"
+msgstr "E370: Níorbh fhéidir an leabharlann %s a oscailt"
+
+msgid "Sorry, this command is disabled: the Perl library could not be loaded."
+msgstr ""
+"Tá brón orm, níl an t-ordú seo le fáil: níorbh fhéidir an leabharlann Perl a "
+"luchtú."
+
+msgid "E299: Perl evaluation forbidden in sandbox without the Safe module"
+msgstr "E299: Ní cheadaítear luacháil Perl i mbosca gainimh gan an modúl Safe"
+
+msgid "Edit with &multiple Vims"
+msgstr "Cuir in eagar le Vimeanna io&madúla"
+
+msgid "Edit with single &Vim"
+msgstr "Cuir in eagar le &Vim aonair"
+
+msgid "Diff with Vim"
+msgstr "Diff le Vim"
+
+msgid "Edit with &Vim"
+msgstr "Cuir in Eagar le &Vim"
+
+#. Now concatenate
+msgid "Edit with existing Vim - "
+msgstr "Cuir in Eagar le Vim beo - "
+
+msgid "Edits the selected file(s) with Vim"
+msgstr "Cuir an comhad roghnaithe in eagar le Vim"
+
+msgid "Error creating process: Check if gvim is in your path!"
+msgstr ""
+"Earráid agus próiseas á chruthú: Deimhnigh go bhfuil gvim i do chonair!"
+
+msgid "gvimext.dll error"
+msgstr "earráid gvimext.dll"
+
+msgid "Path length too long!"
+msgstr "Conair rófhada!"
+
+msgid "--No lines in buffer--"
+msgstr "--Tá an maolán folamh--"
+
+#.
+#. * The error messages that can be shared are included here.
+#. * Excluded are errors that are only used once and debugging messages.
+#.
+msgid "E470: Command aborted"
+msgstr "E470: Ordú tobscortha"
+
+msgid "E471: Argument required"
+msgstr "E471: Tá gá le hargóint"
+
+msgid "E10: \\ should be followed by /, ? or &"
+msgstr "E10: Ba chóir /, ? nó & a chur i ndiaidh \\"
+
+msgid "E11: Invalid in command-line window; <CR> executes, CTRL-C quits"
+msgstr ""
+"E11: Neamhbhailí i bhfuinneog líne na n-orduithe; <CR>=rith, CTRL-C=scoir"
+
+msgid "E12: Command not allowed from exrc/vimrc in current dir or tag search"
+msgstr ""
+"E12: Ní cheadaítear ordú ó exrc/vimrc sa chomhadlann reatha ná ó chuardach "
+"clibe"
+
+msgid "E171: Missing :endif"
+msgstr "E171: :endif ar iarraidh"
+
+msgid "E600: Missing :endtry"
+msgstr "E600: :endtry ar iarraidh"
+
+msgid "E170: Missing :endwhile"
+msgstr "E170: :endwhile ar iarraidh"
+
+msgid "E170: Missing :endfor"
+msgstr "E170: :endfor ar iarraidh"
+
+msgid "E588: :endwhile without :while"
+msgstr "E588: :endwhile gan :while"
+
+msgid "E588: :endfor without :for"
+msgstr "E588: :endfor gan :for"
+
+msgid "E13: File exists (add ! to override)"
+msgstr "E13: Tá comhad ann cheana (cuir ! leis an ordú chun forscríobh)"
+
+msgid "E472: Command failed"
+msgstr "E472: Theip ar ordú"
+
+#, c-format
+msgid "E234: Unknown fontset: %s"
+msgstr "E234: Tacar cló anaithnid: %s"
+
+#, c-format
+msgid "E235: Unknown font: %s"
+msgstr "E235: Clófhoireann anaithnid: %s"
+
+#, c-format
+msgid "E236: Font \"%s\" is not fixed-width"
+msgstr "E236: Ní cló aonleithid é \"%s\""
+
+msgid "E473: Internal error"
+msgstr "E473: Earráid inmheánach"
+
+#, c-format
+msgid "E685: Internal error: %s"
+msgstr "E685: Earráid inmheánach: %s"
+
+msgid "Interrupted"
+msgstr "Idirbhriste"
+
+msgid "E14: Invalid address"
+msgstr "E14: Drochsheoladh"
+
+msgid "E474: Invalid argument"
+msgstr "E474: Argóint neamhbhailí"
+
+#, c-format
+msgid "E475: Invalid argument: %s"
+msgstr "E475: Argóint neamhbhailí: %s"
+
+#, c-format
+msgid "E15: Invalid expression: %s"
+msgstr "E15: Slonn neamhbhailí: %s"
+
+msgid "E16: Invalid range"
+msgstr "E16: Raon neamhbhailí"
+
+msgid "E476: Invalid command"
+msgstr "E476: Ordú neamhbhailí"
+
+#, c-format
+msgid "E17: \"%s\" is a directory"
+msgstr "E17: is comhadlann \"%s\""
+
+#, c-format
+msgid "E364: Library call failed for \"%s()\""
+msgstr "E364: Theip ar ghlao leabharlainne \"%s()\""
+
+#, c-format
+msgid "E448: Could not load library function %s"
+msgstr "E448: Ní féidir feidhm %s leabharlainne a luchtú"
+
+msgid "E19: Mark has invalid line number"
+msgstr "E19: Tá líne-uimhir neamhbhailí ag an mharc"
+
+msgid "E20: Mark not set"
+msgstr "E20: Marc gan socrú"
+
+msgid "E21: Cannot make changes, 'modifiable' is off"
+msgstr ""
+"E21: Ní féidir athruithe a chur i bhfeidhm, níl an bhratach 'modifiable' "
+"socraithe"
+
+msgid "E22: Scripts nested too deep"
+msgstr "E22: scripteanna neadaithe ródhomhain"
+
+msgid "E23: No alternate file"
+msgstr "E23: Níl aon chomhad malartach"
+
+msgid "E24: No such abbreviation"
+msgstr "E24: Níl a leithéid de ghiorrúchán ann"
+
+msgid "E477: No ! allowed"
+msgstr "E477: Ní cheadaítear !"
+
+msgid "E25: GUI cannot be used: Not enabled at compile time"
+msgstr "E25: Ní féidir an GUI a úsáid: Níor cumasaíodh é ag am tiomsaithe"
+
+msgid "E26: Hebrew cannot be used: Not enabled at compile time\n"
+msgstr ""
+"E26: Níl tacaíocht Eabhraise ar fáil: Níor cumasaíodh é ag am tiomsaithe\n"
+
+msgid "E27: Farsi cannot be used: Not enabled at compile time\n"
+msgstr ""
+"E27: Níl tacaíocht Pheirsise ar fáil: Níor cumasaíodh é ag am tiomsaithe\n"
+
+msgid "E800: Arabic cannot be used: Not enabled at compile time\n"
+msgstr ""
+"E800: Níl tacaíocht Araibise ar fáil: Níor cumasaíodh é ag am tiomsaithe\n"
+
+#, c-format
+msgid "E28: No such highlight group name: %s"
+msgstr "E28: Níl a leithéid d'ainm grúpa aibhsithe: %s"
+
+msgid "E29: No inserted text yet"
+msgstr "E29: Níl aon téacs ionsáite go dtí seo"
+
+msgid "E30: No previous command line"
+msgstr "E30: Níl aon líne na n-orduithe roimhe seo"
+
+msgid "E31: No such mapping"
+msgstr "E31: Níl a leithéid de mhapáil"
+
+msgid "E479: No match"
+msgstr "E479: Níl aon rud comhoiriúnach ann"
+
+#, c-format
+msgid "E480: No match: %s"
+msgstr "E480: Níl aon rud comhoiriúnach ann: %s"
+
+msgid "E32: No file name"
+msgstr "E32: Níl aon ainm comhaid"
+
+msgid "E33: No previous substitute regular expression"
+msgstr "E33: Níl aon slonn ionadaíochta roimhe seo"
+
+msgid "E34: No previous command"
+msgstr "E34: Níl aon ordú roimhe seo"
+
+msgid "E35: No previous regular expression"
+msgstr "E35: Níl aon slonn ionadaíochta roimhe seo"
+
+msgid "E481: No range allowed"
+msgstr "E481: Ní cheadaítear raon"
+
+msgid "E36: Not enough room"
+msgstr "E36: Níl slí a dhóthain ann"
+
+#, c-format
+msgid "E247: no registered server named \"%s\""
+msgstr "E247: níl aon fhreastalaí cláraithe leis an ainm \"%s\""
+
+#, c-format
+msgid "E482: Can't create file %s"
+msgstr "E482: Ní féidir comhad %s a chruthú"
+
+msgid "E483: Can't get temp file name"
+msgstr "E483: Níl aon fháil ar ainm comhaid sealadach"
+
+#, c-format
+msgid "E484: Can't open file %s"
+msgstr "E484: Ní féidir comhad %s a oscailt"
+
+#, c-format
+msgid "E485: Can't read file %s"
+msgstr "E485: Ní féidir comhad %s a léamh"
+
+msgid "E37: No write since last change (add ! to override)"
+msgstr "E37: Tá athruithe ann gan sábháil (cuir ! leis an ordú chun sárú)"
+
+msgid "E37: No write since last change"
+msgstr "E37: Gan scríobh ón athrú is déanaí"
+
+msgid "E38: Null argument"
+msgstr "E38: Argóint nialasach"
+
+msgid "E39: Number expected"
+msgstr "E39: Ag súil le huimhir"
+
+#, c-format
+msgid "E40: Can't open errorfile %s"
+msgstr "E40: Ní féidir an comhad earráide %s a oscailt"
+
+msgid "E233: cannot open display"
+msgstr "E233: ní féidir an scáileán a oscailt"
+
+msgid "E41: Out of memory!"
+msgstr "E41: Cuimhne ídithe!"
+
+msgid "Pattern not found"
+msgstr "Patrún gan aimsiú"
+
+#, c-format
+msgid "E486: Pattern not found: %s"
+msgstr "E486: Patrún gan aimsiú: %s"
+
+msgid "E487: Argument must be positive"
+msgstr "E487: Argóint dheimhneach de dhíth"
+
+msgid "E459: Cannot go back to previous directory"
+msgstr "E459: Ní féidir a fhilleadh ar an chomhadlann roimhe seo"
+
+msgid "E42: No Errors"
+msgstr "E42: Níl Aon Earráid Ann"
+
+msgid "E776: No location list"
+msgstr "E776: Gan liosta suíomh"
+
+msgid "E43: Damaged match string"
+msgstr "E43: Teaghrán cuardaigh loite"
+
+msgid "E44: Corrupted regexp program"
+msgstr "E44: Clár na sloinn ionadaíochta truaillithe"
+
+msgid "E45: 'readonly' option is set (add ! to override)"
+msgstr "E45: tá an rogha 'readonly' socraithe (cuir ! leis an ordú chun sárú)"
+
+#, c-format
+msgid "E46: Cannot change read-only variable \"%s\""
+msgstr "E46: Ní féidir athróg inléite amháin \"%s\" a athrú"
+
+#, c-format
+msgid "E794: Cannot set variable in the sandbox: \"%s\""
+msgstr "E794: Ní féidir athróg a shocrú sa bhosca gainimh: \"%s\""
+
+msgid "E713: Cannot use empty key for Dictionary"
+msgstr "E713: Ní féidir eochair fholamh a úsáid le Foclóir"
+
+msgid "E715: Dictionary required"
+msgstr "E715: Tá gá le foclóir"
+
+#, c-format
+msgid "E684: list index out of range: %ld"
+msgstr "E684: innéacs liosta as raon: %ld"
+
+#, c-format
+msgid "E118: Too many arguments for function: %s"
+msgstr "E118: An iomarca argóintí d'fheidhm: %s"
+
+#, c-format
+msgid "E716: Key not present in Dictionary: %s"
+msgstr "E716: Níl an eochair seo san Fhoclóir: %s"
+
+msgid "E714: List required"
+msgstr "E714: Tá gá le liosta"
+
+#, c-format
+msgid "E712: Argument of %s must be a List or Dictionary"
+msgstr "E712: Caithfidh argóint de %s a bheith ina Liosta nó Foclóir"
+
+msgid "E47: Error while reading errorfile"
+msgstr "E47: Earráid agus comhad earráide á léamh"
+
+msgid "E48: Not allowed in sandbox"
+msgstr "E48: Ní cheadaítear é seo i mbosca gainimh"
+
+msgid "E523: Not allowed here"
+msgstr "E523: Ní cheadaítear é anseo"
+
+msgid "E359: Screen mode setting not supported"
+msgstr "E359: Ní féidir an mód scáileáin a shocrú"
+
+msgid "E49: Invalid scroll size"
+msgstr "E49: Méid neamhbhailí scrollaithe"
+
+msgid "E91: 'shell' option is empty"
+msgstr "E91: rogha 'shell' folamh"
+
+msgid "E255: Couldn't read in sign data!"
+msgstr "E255: Níorbh fhéidir na sonraí comhartha a léamh!"
+
+msgid "E72: Close error on swap file"
+msgstr "E72: Earráid agus comhad babhtála á dhúnadh"
+
+msgid "E73: tag stack empty"
+msgstr "E73: tá cruach na gclibeanna folamh"
+
+msgid "E74: Command too complex"
+msgstr "E74: Ordú róchasta"
+
+msgid "E75: Name too long"
+msgstr "E75: Ainm rófhada"
+
+msgid "E76: Too many ["
+msgstr "E76: an iomarca ["
+
+msgid "E77: Too many file names"
+msgstr "E77: An iomarca ainmneacha comhaid"
+
+msgid "E488: Trailing characters"
+msgstr "E488: Carachtair chun deiridh"
+
+msgid "E78: Unknown mark"
+msgstr "E78: Marc anaithnid"
+
+msgid "E79: Cannot expand wildcards"
+msgstr "E79: Ní féidir saoróga a leathnú"
+
+msgid "E591: 'winheight' cannot be smaller than 'winminheight'"
+msgstr "E591: ní cheadaítear 'winheight' a bheith níos lú ná 'winminheight'"
+
+msgid "E592: 'winwidth' cannot be smaller than 'winminwidth'"
+msgstr "E592: ní cheadaítear 'winwidth' a bheith níos lú ná 'winminwidth'"
+
+msgid "E80: Error while writing"
+msgstr "E80: Earráid agus á scríobh"
+
+msgid "E939: Positive count required"
+msgstr "E939: Uimhir dheimhneach de dhíth"
+
+msgid "E81: Using <SID> not in a script context"
+msgstr "E81: <SID> á úsáid nach i gcomhthéacs scripte"
+
+msgid "E449: Invalid expression received"
+msgstr "E449: Fuarthas slonn neamhbhailí"
+
+msgid "E463: Region is guarded, cannot modify"
+msgstr "E463: Réigiún cosanta, ní féidir é a athrú"
+
+msgid "E744: NetBeans does not allow changes in read-only files"
+msgstr "E744: Ní cheadaíonn NetBeans aon athrú i gcomhaid inléite amháin"
+
+msgid "E363: pattern uses more memory than 'maxmempattern'"
+msgstr "E363: úsáideann an patrún níos mó cuimhne ná 'maxmempattern'"
+
+msgid "E749: empty buffer"
+msgstr "E749: maolán folamh"
+
+#, c-format
+msgid "E86: Buffer %ld does not exist"
+msgstr "E86: Níl a leithéid de mhaolán %ld"
+
+msgid "E682: Invalid search pattern or delimiter"
+msgstr "E682: Patrún nó teormharcóir neamhbhailí cuardaigh"
+
+msgid "E139: File is loaded in another buffer"
+msgstr "E139: Tá an comhad luchtaithe i maolán eile"
+
+#, c-format
+msgid "E764: Option '%s' is not set"
+msgstr "E764: Rogha '%s' gan socrú"
+
+msgid "E850: Invalid register name"
+msgstr "E850: Ainm neamhbhailí tabhaill"
+
+#, c-format
+msgid "E919: Directory not found in '%s': \"%s\""
+msgstr "E919: Comhadlann gan aimsiú in '%s': \"%s\""
+
+msgid "search hit TOP, continuing at BOTTOM"
+msgstr "Buaileadh an BARR le linn an chuardaigh, ag leanúint ag an CHRÍOCH"
+
+msgid "search hit BOTTOM, continuing at TOP"
+msgstr "Buaileadh an BUN le linn an chuardaigh, ag leanúint ag an BHARR"
+
+#, c-format
+msgid "Need encryption key for \"%s\""
+msgstr "Eochair chriptiúcháin le haghaidh \"%s\" de dhíth"
+
+msgid "empty keys are not allowed"
+msgstr "ní cheadaítear eochracha folmha"
+
+msgid "dictionary is locked"
+msgstr "tá an foclóir faoi ghlas"
+
+msgid "list is locked"
+msgstr "tá an liosta faoi ghlas"
+
+#, c-format
+msgid "failed to add key '%s' to dictionary"
+msgstr "níorbh fhéidir eochair '%s' a chur leis an bhfoclóir"
+
+#, c-format
+msgid "index must be int or slice, not %s"
+msgstr "ní mór don innéacs a bheith ina shlánuimhir nó ina shlisne, seachas %s"
+
+#, c-format
+msgid "expected str() or unicode() instance, but got %s"
+msgstr "bhíothas ag súil le str() nó unicode(), ach fuarthas %s"
+
+#, c-format
+msgid "expected bytes() or str() instance, but got %s"
+msgstr "bhíothas ag súil le bytes() nó str(), ach fuarthas %s"
+
+#, c-format
+msgid ""
+"expected int(), long() or something supporting coercing to long(), but got %s"
+msgstr ""
+"bhíothas ag súil le int(), long(), nó rud éigin inathraithe ina long(), ach "
+"fuarthas %s"
+
+#, c-format
+msgid "expected int() or something supporting coercing to int(), but got %s"
+msgstr ""
+"bhíothas ag súil le int() nó rud éigin inathraithe ina int(), ach fuarthas %s"
+
+msgid "value is too large to fit into C int type"
+msgstr "tá an luach níos mó ná athróg int sa teanga C"
+
+msgid "value is too small to fit into C int type"
+msgstr "tá an luach níos lú ná athróg int sa teanga C"
+
+msgid "number must be greater than zero"
+msgstr "ní mór don uimhir a bheith deimhneach"
+
+msgid "number must be greater or equal to zero"
+msgstr "ní mór don uimhir a bheith >= 0"
+
+msgid "can't delete OutputObject attributes"
+msgstr "ní féidir tréithe OutputObject a scriosadh"
+
+#, c-format
+msgid "invalid attribute: %s"
+msgstr "aitreabúid neamhbhailí: %s"
+
+msgid "E264: Python: Error initialising I/O objects"
+msgstr "E264: Python: Earráid agus réada I/A á dtúsú"
+
+msgid "failed to change directory"
+msgstr "níorbh fhéidir an chomhadlann a athrú"
+
+#, c-format
+msgid "expected 3-tuple as imp.find_module() result, but got %s"
+msgstr ""
+"bhíothas ag súil le 3-chodach mar thoradh ar imp.find_module(), ach fuarthas "
+"%s"
+
+#, c-format
+msgid "expected 3-tuple as imp.find_module() result, but got tuple of size %d"
+msgstr ""
+"bhíothas ag súil le 3-chodach mar thoradh ar imp.find_module(), ach fuarthas "
+"%d-chodach"
+
+msgid "internal error: imp.find_module returned tuple with NULL"
+msgstr "earráid inmheánach: fuarthas codach NULL ar ais ó imp.find_module"
+
+msgid "cannot delete vim.Dictionary attributes"
+msgstr "ní féidir tréithe vim.Dictionary a scriosadh"
+
+msgid "cannot modify fixed dictionary"
+msgstr "ní féidir foclóir socraithe a athrú"
+
+#, c-format
+msgid "cannot set attribute %s"
+msgstr "ní féidir tréith %s a shocrú"
+
+msgid "hashtab changed during iteration"
+msgstr "athraíodh an haistáb le linn atriallta"
+
+#, c-format
+msgid "expected sequence element of size 2, but got sequence of size %d"
+msgstr "bhíothas ag súil le heilimint de mhéid 2, ach fuarthas méid %d"
+
+msgid "list constructor does not accept keyword arguments"
+msgstr "ní ghlacann cruthaitheoir an liosta le hargóintí eochairfhocail"
+
+msgid "list index out of range"
+msgstr "innéacs liosta as raon"
+
+#. No more suitable format specifications in python-2.3
+#, c-format
+msgid "internal error: failed to get vim list item %d"
+msgstr "earráid inmheánach: níl aon fháil ar mhír %d sa liosta vim"
+
+msgid "slice step cannot be zero"
+msgstr "ní cheadaítear slisne le céim 0"
+
+#, c-format
+msgid "attempt to assign sequence of size greater than %d to extended slice"
+msgstr "iarracht ar sheicheamh níos mó ná %d a shannadh do shlisne fadaithe"
+
+#, c-format
+msgid "internal error: no vim list item %d"
+msgstr "earráid inmheánach: níl aon mhír %d sa liosta vim"
+
+msgid "internal error: not enough list items"
+msgstr "earráid inmheánach: níl go leor míreanna liosta ann"
+
+msgid "internal error: failed to add item to list"
+msgstr "earráid inmheánach: níorbh fhéidir mír a chur leis an liosta"
+
+#, c-format
+msgid "attempt to assign sequence of size %d to extended slice of size %d"
+msgstr "iarracht ar sheicheamh de mhéid %d a shannadh do shlisne de mhéid %d"
+
+msgid "failed to add item to list"
+msgstr "níorbh fhéidir mír a chur leis an liosta"
+
+msgid "cannot delete vim.List attributes"
+msgstr "ní féidir tréithe vim.List a scriosadh"
+
+msgid "cannot modify fixed list"
+msgstr "ní féidir liosta socraithe a athrú"
+
+#, c-format
+msgid "unnamed function %s does not exist"
+msgstr "níl feidhm %s gan ainm ann"
+
+#, c-format
+msgid "function %s does not exist"
+msgstr "níl feidhm %s ann"
+
+#, c-format
+msgid "failed to run function %s"
+msgstr "níorbh fhéidir feidhm %s a rith"
+
+msgid "unable to get option value"
+msgstr "ní féidir luach na rogha a fháil"
+
+msgid "internal error: unknown option type"
+msgstr "earráid inmheánach: cineál rogha anaithnid"
+
+msgid "problem while switching windows"
+msgstr "tharla earráid agus an fhuinneog á hathrú"
+
+#, c-format
+msgid "unable to unset global option %s"
+msgstr "ní féidir rogha chomhchoiteann %s a dhíshocrú"
+
+#, c-format
+msgid "unable to unset option %s which does not have global value"
+msgstr "ní féidir rogha %s gan luach comhchoiteann a dhíshocrú"
+
+msgid "attempt to refer to deleted tab page"
+msgstr "tagairt déanta do leathanach cluaisíní scriosta"
+
+msgid "no such tab page"
+msgstr "níl a leithéid de leathanach cluaisíní ann"
+
+msgid "attempt to refer to deleted window"
+msgstr "rinneadh iarracht ar fhuinneog scriosta a rochtain"
+
+msgid "readonly attribute: buffer"
+msgstr "tréith inléite amháin: maolán"
+
+msgid "cursor position outside buffer"
+msgstr "cúrsóir taobh amuigh den mhaolán"
+
+msgid "no such window"
+msgstr "níl a leithéid d'fhuinneog ann"
+
+msgid "attempt to refer to deleted buffer"
+msgstr "rinneadh iarracht ar mhaolán scriosta a rochtain"
+
+msgid "failed to rename buffer"
+msgstr "níorbh fhéidir ainm nua a chur ar an maolán"
+
+msgid "mark name must be a single character"
+msgstr "ní cheadaítear ach carachtar amháin in ainm an mhairc"
+
+#, c-format
+msgid "expected vim.Buffer object, but got %s"
+msgstr "bhíothas ag súil le réad vim.Buffer, ach fuarthas %s"
+
+#, c-format
+msgid "failed to switch to buffer %d"
+msgstr "níorbh fhéidir athrú go dtí maolán a %d"
+
+#, c-format
+msgid "expected vim.Window object, but got %s"
+msgstr "bhíothas ag súil le réad vim.Window, ach fuarthas %s"
+
+msgid "failed to find window in the current tab page"
+msgstr "níor aimsíodh fuinneog sa leathanach cluaisíní reatha"
+
+msgid "did not switch to the specified window"
+msgstr "níor athraíodh go dtí an fhuinneog roghnaithe"
+
+#, c-format
+msgid "expected vim.TabPage object, but got %s"
+msgstr "bhíothas ag súil le réad vim.TabPage, ach fuarthas %s"
+
+msgid "did not switch to the specified tab page"
+msgstr "níor athraíodh go dtí an leathanach cluaisíní roghnaithe"
+
+msgid "failed to run the code"
+msgstr "níorbh fhéidir an cód a chur ar siúl"
+
+msgid "E858: Eval did not return a valid python object"
+msgstr "E858: Ní bhfuarthas réad bailí python ar ais ó Eval"
+
+msgid "E859: Failed to convert returned python object to vim value"
+msgstr "E859: Níorbh fhéidir luach vim a dhéanamh as an réad python"
+
+#, c-format
+msgid "unable to convert %s to vim dictionary"
+msgstr "ní féidir foclóir vim a dhéanamh as %s"
+
+#, c-format
+msgid "unable to convert %s to vim list"
+msgstr "ní féidir liosta vim a dhéanamh as %s"
+
+#, c-format
+msgid "unable to convert %s to vim structure"
+msgstr "ní féidir struchtúr vim a dhéanamh as %s"
+
+msgid "internal error: NULL reference passed"
+msgstr "earráid inmheánach: tagairt NULL seolta"
+
+msgid "internal error: invalid value type"
+msgstr "earráid inmheánach: cineál neamhbhailí"
+
+msgid ""
+"Failed to set path hook: sys.path_hooks is not a list\n"
+"You should now do the following:\n"
+"- append vim.path_hook to sys.path_hooks\n"
+"- append vim.VIM_SPECIAL_PATH to sys.path\n"
+msgstr ""
+"Níorbh fhéidir path_hook a shocrú: ní liosta é sys.path_hooks\n"
+"Ba chóir duit na rudaí seo a leanas a dhéanamh:\n"
+"- cuir vim.path_hook le deireadh sys.path_hooks\n"
+"- cuir vim.VIM_SPECIAL_PATH le deireadh sys.path\n"
+
+msgid ""
+"Failed to set path: sys.path is not a list\n"
+"You should now append vim.VIM_SPECIAL_PATH to sys.path"
+msgstr ""
+"Níorbh fhéidir an chonair a shocrú: ní liosta é sys.path\n"
+"Ba chóir duit vim.VIM_SPECIAL_PATH a cheangal le deireadh sys.path"
+
+#~ msgid "+-%s%3ld line: "
+#~ msgid_plural "+-%s%3ld lines: "
+#~ msgstr[0] "+-%s%3ld líne: "
+#~ msgstr[1] "+-%s%3ld líne: "
+#~ msgstr[2] "+-%s%3ld líne: "
+#~ msgstr[3] "+-%s%3ld líne: "
+#~ msgstr[4] "+-%s%3ld líne: "
+
+#~ msgid "+--%3ld line folded "
+#~ msgid_plural "+--%3ld lines folded "
+#~ msgstr[0] "+--%3ld líne fillte "
+#~ msgstr[1] "+--%3ld líne fillte "
+#~ msgstr[2] "+--%3ld líne fillte "
+#~ msgstr[3] "+--%3ld líne fillte "
+#~ msgstr[4] "+--%3ld líne fillte "
+
+#~ msgid "Type :quit<Enter> to exit Vim"
+#~ msgstr "Clóscríobh :quit<Enter> chun Vim a scor"
+
+#~ msgid "Zero count"
+#~ msgstr "Nialas"
+
+#~ msgid "E693: Can only compare Funcref with Funcref"
+#~ msgstr "E693: Is féidir Funcref a chur i gcomparáid le Funcref eile amháin"
+
+#~ msgid "E706: Variable type mismatch for: %s"
+#~ msgstr "E706: Mímheaitseáil idir cineálacha athróige: %s"
+
+#~ msgid "%ld characters"
+#~ msgstr "%ld carachtar"
+
+#~ msgid "Toggle implementation/definition"
+#~ msgstr "Scoránaigh feidhmiú/sainmhíniú"
+
+#~ msgid "Show base class of"
+#~ msgstr "Taispeáin an bunaicme de"
+
+#~ msgid "Show overridden member function"
+#~ msgstr "Taispeáin ballfheidhm sáraithe"
+
+#~ msgid "Retrieve from file"
+#~ msgstr "Aisghabh ó chomhad"
+
+#~ msgid "Retrieve from project"
+#~ msgstr "Aisghabh ó thionscadal"
+
+#~ msgid "Retrieve from all projects"
+#~ msgstr "Aisghabh ó gach tionscadal"
+
+#~ msgid "Retrieve"
+#~ msgstr "Aisghabh"
+
+#~ msgid "Show source of"
+#~ msgstr "Taispeáin foinse"
+
+#~ msgid "Find symbol"
+#~ msgstr "Aimsigh siombail"
+
+#~ msgid "Browse class"
+#~ msgstr "Brabhsáil aicme"
+
+#~ msgid "Show class in hierarchy"
+#~ msgstr "Taispeáin an aicme in ordlathas"
+
+#~ msgid "Show class in restricted hierarchy"
+#~ msgstr "Taispeáin an aicme in ordlathas srianta"
+
+#~ msgid "Xref refers to"
+#~ msgstr "Tagraíonn Xref do"
+
+#~ msgid "Xref referred by"
+#~ msgstr "Xref tagartha ag"
+
+#~ msgid "Xref has a"
+#~ msgstr "Rud atá ag Xref:"
+
+#~ msgid "Xref used by"
+#~ msgstr "Xref á úsáid ag"
+
+#~ msgid "Show docu of"
+#~ msgstr "Taispeáin eolas faoi"
+
+#~ msgid "Generate docu for"
+#~ msgstr "Gin eolas faoi"
+
+#~ msgid ""
+#~ "Cannot connect to SNiFF+. Check environment (sniffemacs must be found in "
+#~ "$PATH).\n"
+#~ msgstr ""
+#~ "Ní féidir nasc a dhéanamh le SNiFF+. Seiceáil do chuid athróga "
+#~ "thimpeallachta (caithfidh tú sniffemacs a chur i do $PATH).\n"
+
+#~ msgid "E274: Sniff: Error during read. Disconnected"
+#~ msgstr "E274: Sniff: Earráid sa léamh. Dínasctha"
+
+#~ msgid "SNiFF+ is currently "
+#~ msgstr "SNiFF+ stádas faoi láthair: "
+
+#~ msgid "not "
+#~ msgstr "ní "
+
+#~ msgid "connected"
+#~ msgstr "nasctha"
+
+#~ msgid "E275: Unknown SNiFF+ request: %s"
+#~ msgstr "E275: Iarratas anaithnid SNiFF+: %s"
+
+#~ msgid "E276: Error connecting to SNiFF+"
+#~ msgstr "E276: Earráid ag nascadh le SNiFF+"
+
+#~ msgid "E278: SNiFF+ not connected"
+#~ msgstr "E278: SNiFF+ gan nasc"
+
+#~ msgid "E279: Not a SNiFF+ buffer"
+#~ msgstr "E279: Ní maolán SNiFF+ é"
+
+#~ msgid "Sniff: Error during write. Disconnected"
+#~ msgstr "Sniff: Earráid sa scríobh. Dínasctha"
+
+#~ msgid " Quit, or continue with caution.\n"
+#~ msgstr " Scoir, nó lean ar aghaidh go hairdeallach.\n"
+
+#~ msgid "Cannot connect to Netbeans #2"
+#~ msgstr "Ní féidir nascadh le Netbeans #2"
+
+#~ msgid "read from Netbeans socket"
+#~ msgstr "léadh ó shoicéad Netbeans"
+
+#~ msgid "'columns' is not 80, cannot execute external commands"
+#~ msgstr "ní 80 é 'columns', ní féidir orduithe seachtracha a rith"
+
+#~ msgid "Could not set security context "
+#~ msgstr "Níorbh fhéidir comhthéacs slándála a shocrú "
+
+#~ msgid " for "
+#~ msgstr " le haghaidh "
+
+#~ msgid "Could not get security context "
+#~ msgstr "Níorbh fhéidir comhthéacs slándála a fháil "
+
+#~ msgid ". Removing it!\n"
+#~ msgstr ". Á scriosadh!\n"
+
+#~ msgid " (lang)"
+#~ msgstr " (teanga)"
+
+#~ msgid "E759: Format error in spell file"
+#~ msgstr "E759: Earráid fhormáide i gcomhad litrithe"
+
+#~ msgid ""
+#~ "\n"
+#~ "MS-Windows 16/32-bit GUI version"
+#~ msgstr ""
+#~ "\n"
+#~ "Leagan GUI 16/32 giotán MS-Windows"
+
+#~ msgid " in Win32s mode"
+#~ msgstr " i mód Win32s"
+
+#~ msgid ""
+#~ "\n"
+#~ "MS-Windows 16-bit version"
+#~ msgstr ""
+#~ "\n"
+#~ "Leagan 16 giotán MS-Windows"
+
+#~ msgid ""
+#~ "\n"
+#~ "32-bit MS-DOS version"
+#~ msgstr ""
+#~ "\n"
+#~ "Leagan 32 giotán MS-DOS"
+
+#~ msgid ""
+#~ "\n"
+#~ "16-bit MS-DOS version"
+#~ msgstr ""
+#~ "\n"
+#~ "Leagan 16 giotán MS-DOS"
+
+#~ msgid "WARNING: Windows 95/98/ME detected"
+#~ msgstr "RABHADH: Braitheadh Windows 95/98/ME"
+
+#~ msgid "type :help windows95<Enter> for info on this"
+#~ msgstr "clóscríobh :help windows95<Enter> chun eolas a fháil "
+
+#~ msgid "function constructor does not accept keyword arguments"
+#~ msgstr "ní ghlacann cruthaitheoir na feidhme le hargóintí eochairfhocail"
+
+#~ msgid "Vim dialog..."
+#~ msgstr "Dialóg Vim..."
+
+#~ msgid "Font Selection"
+#~ msgstr "Roghnú Cló"
+
+#~ msgid "softspace must be an integer"
+#~ msgstr "caithfidh softspace a bheith ina shlánuimhir"
+
+#~ msgid "writelines() requires list of strings"
+#~ msgstr "liosta teaghrán ag teastáil ó writelines()"
+
+#~ msgid "<buffer object (deleted) at %p>"
+#~ msgstr "<réad maoláin (scriosta) ag %p>"
+
+#~ msgid "<window object (deleted) at %p>"
+#~ msgstr "<réad fuinneoige (scriosta) ag %p>"
+
+#~ msgid "<window object (unknown) at %p>"
+#~ msgstr "<réad fuinneoige (anaithnid) ag %p>"
+
+#~ msgid "<window %d>"
+#~ msgstr "<fuinneog %d>"
+
+#~ msgid ""
+#~ "E281: TCL ERROR: exit code is not int!? Please report this to vim-dev@vim."
+#~ "org"
+#~ msgstr ""
+#~ "E281: EARRÁID TCL: níl an cód scortha ina shlánuimhir!? Seol tuairisc "
+#~ "fhabht chuig <vim-dev@vim.org> le do thoil"
+
+#~ msgid "-name <name>\t\tUse resource as if vim was <name>"
+#~ msgstr "-name <ainm>\t\tÚsáid acmhainn mar a bheadh vim <ainm>"
+
+#~ msgid "\t\t\t (Unimplemented)\n"
+#~ msgstr "\t\t\t (Níl ar fáil)\n"
+
+#~ msgid ""
+#~ "\n"
+#~ "Arguments recognised by gvim (RISC OS version):\n"
+#~ msgstr ""
+#~ "\n"
+#~ "Argóintí ar eolas do gvim (leagan RISC OS):\n"
+
+#~ msgid "--columns <number>\tInitial width of window in columns"
+#~ msgstr "--columns <uimhir>\tLeithead fuinneoige i dtosach (colúin)"
+
+#~ msgid "--rows <number>\tInitial height of window in rows"
+#~ msgstr "--rows <uimhir>\tAirde fhuinneoige i dtosach (rónna)"
+
+#~ msgid "E290: over-the-spot style requires fontset"
+#~ msgstr "E290: tacar cló ag teastáil ó stíl thar-an-spota"
+
+#~ msgid "E291: Your GTK+ is older than 1.2.3. Status area disabled"
+#~ msgstr ""
+#~ "E291: Tá an GTK+ atá agat níos sine ná leagan 1.2.3. Díchumasaítear an "
+#~ "limistéar stádais"
+
+#~ msgid "E292: Input Method Server is not running"
+#~ msgstr "E292: Níl an Freastalaí Mhodh Ionchuir ag rith"
+
+#~ msgid "Vim: preserving files...\n"
+#~ msgstr "Vim: comhaid á gcaomhnú...\n"
+
+#~ msgid "Vim: Finished.\n"
+#~ msgstr "Vim: Críochnaithe.\n"
+
+#~ msgid "E505: "
+#~ msgstr "E505: "
+
+#~ msgid "Vim: Double signal, exiting\n"
+#~ msgstr "Vim: Comhartha dúbailte, ag scor\n"
+
+#~ msgid "Vim: Caught deadly signal %s\n"
+#~ msgstr "Vim: Fuarthas comhartha marfach %s\n"
+
+#~ msgid "Vim: Caught deadly signal\n"
+#~ msgstr "Vim: Fuarthas comhartha marfach\n"
+
+#~ msgid "E396: containedin argument not accepted here"
+#~ msgstr "E396: ní ghlactar leis an argóint containedin anseo"
+
+# columns?
+#~ msgid "number changes time"
+#~ msgstr "uimhir athruithe am"
+
+#~ msgid ""
+#~ "\n"
+#~ "RISC OS version"
+#~ msgstr ""
+#~ "\n"
+#~ "Leagan RISC OS"
+
+#~ msgid "with GTK-GNOME GUI."
+#~ msgstr "le GUI GTK-GNOME."
+
+#~ msgid "E569: maximum number of cscope connections reached"
+#~ msgstr "E569: ní cheadaítear níos mó ná an líon uasta nasc cscope"
+
+#~ msgid "[NL found]"
+#~ msgstr "[NL aimsithe]"
+
+#~ msgid "-V[N]\t\tVerbose level"
+#~ msgstr "-V[N]\t\tFoclachas"
+
+#~ msgid "[Error List]"
+#~ msgstr "[Liosta Earráidí]"
+
+#~ msgid ""
+#~ "\n"
+#~ "Arguments recognised by kvim (KDE version):\n"
+#~ msgstr ""
+#~ "\n"
+#~ "Argóintí ar eolas do kvim (leagan KDE):\n"
+
+#~ msgid "-black\t\tUse reverse video"
+#~ msgstr "-black\t\tÚsáid fís aisiompaithe"
+
+#~ msgid "-tip\t\t\tDisplay the tip dialog on startup"
+#~ msgstr "-tip\t\t\tTaispeáin an dialóg leide ar tosach"
+
+#~ msgid "-notip\t\tDisable the tip dialog"
+#~ msgstr "-notip\t\tDíchumasaigh an dialóg leide"
+
+#~ msgid "--display <display>\tRun vim on <display>"
+#~ msgstr "--display <scáileán>\tRith vim ar <scáileán>"
+
+#~ msgid ""
+#~ "&Open Read-Only\n"
+#~ "&Edit anyway\n"
+#~ "&Recover\n"
+#~ "&Quit\n"
+#~ "&Abort\n"
+#~ "&Delete it"
+#~ msgstr ""
+#~ "&Oscail Inléite Amháin\n"
+#~ "&Eagraigh mar sin féin\n"
+#~ "&Athshlánaigh\n"
+#~ "S&coir\n"
+#~ "&Tobscoir\n"
+#~ "&Scrios é"
+
+#~ msgid "...(truncated)"
+#~ msgstr "...(teasctha)"
+
+#~ msgid ""
+#~ "\n"
+#~ "Vim: Got X error but we continue...\n"
+#~ msgstr ""
+#~ "\n"
+#~ "Vim: Fuarthas earráid X ach ar aghaidh linn...\n"
+
+#~ msgid "Character used for SLASH must be ASCII; in %s line %d: %s"
+#~ msgstr ""
+#~ "Ní mór do charachtar a úsáidtear ar SLASH a bheith ASCII; i %s líne %d: %s"
+
+#~ msgid "%ld changes"
+#~ msgstr "%ld athrú"
+
+#~ msgid "with KDE GUI."
+#~ msgstr "le GUI KDE."
+
+#~ msgid "E757: Wrong file ID in spell file"
+#~ msgstr "E757: Aitheantas mícheart comhaid i gcomhad litrithe"
+
+#~ msgid "Duplicate FOL in %s line %d"
+#~ msgstr "FOL dúblach i %s líne %d"
+
+#~ msgid "Duplicate LOW in %s line %d"
+#~ msgstr "LOW dúblach i %s líne %d"
+
+#~ msgid "Duplicate UPP in %s line %d"
+#~ msgstr "UPP dúblach i %s líne %d"
+
+#~ msgid "[string too long]"
+#~ msgstr "[teaghrán rófhada]"
+
+#~ msgid "Hit ENTER to continue"
+#~ msgstr "Brúigh ENTER le leanúint"
+
+#~ msgid " (RET/BS: line, SPACE/b: page, d/u: half page, q: quit)"
+#~ msgstr " (RET/BS: líne, SPÁS/b: lch, d/u: leathlch, q: scoir)"
+
+#~ msgid " (RET: line, SPACE: page, d: half page, q: quit)"
+#~ msgstr " (RET: líne, SPÁS: lch, d: leathlch, q: scoir)"
+
+#~ msgid "E56: %s* operand could be empty"
+#~ msgstr "E56: is féidir go bhfuil an t-oibreann %s* folamh"
+
+#~ msgid "E57: %s+ operand could be empty"
+#~ msgstr "E57: is féidir go bhfuil an t-oibreann %s+ folamh"
+
+#~ msgid "E58: %s{ operand could be empty"
+#~ msgstr "E58: is féidir go bhfuil an t-oibreann %s( folamh"
+
+#~ msgid "Enter nr of choice (<CR> to abort): "
+#~ msgstr "Iontráil uimhir do rogha (<Enter>=tobscor): "
+
+#~ msgid "E361: Crash intercepted; regexp too complex?"
+#~ msgstr "E361: Ceapadh tuairt; slonn ionadaíochta róchasta?"
+
+#~ msgid "E363: pattern caused out-of-stack error"
+#~ msgstr "E363: ghin an patrún earráid as-an-chruach"
diff --git a/src/po/it.po b/src/po/it.po
new file mode 100644
index 0000000..9f85852
--- /dev/null
+++ b/src/po/it.po
@@ -0,0 +1,6553 @@
+# Italian translation for Vim
+#
+# Antonio Colombo <azc100@gmail.com>, 2000
+# Vlad Sandrini <vlad.gently@gmail.com>, 2002
+# Luciano Montanaro <mikelima@cirulla.net>, 2006
+#
+# Ogni commento è benvenuto...
+# Every remark is very welcome...
+#
+# Translation done under Linux and using an Italian keyboard.
+# English words left in the text are unmodified at plural.
+# Option names are mostly left untouched.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: vim 8.1\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2018-06-26 09:09+0200\n"
+"PO-Revision-Date: 2018-06-26 15:33+0200\n"
+"Last-Translator: Antonio Colombo <azc100@gmail.com>\n"
+"Language-Team: Italian\n"
+"Language: it\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-1\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+msgid "E831: bf_key_init() called with empty password"
+msgstr "E831: chiamata a bf_key_init() con password nulla"
+
+msgid "E820: sizeof(uint32_t) != 4"
+msgstr "E820: sizeof(uint32_t) != 4"
+
+msgid "E817: Blowfish big/little endian use wrong"
+msgstr "E817: uso errato di big/little endian in Blowfish"
+
+msgid "E818: sha256 test failed"
+msgstr "E818: test sha256 fallito"
+
+msgid "E819: Blowfish test failed"
+msgstr "E819: test Blowfish fallito"
+
+msgid "[Location List]"
+msgstr "[Lista Locazioni]"
+
+msgid "[Quickfix List]"
+msgstr "[Lista Quickfix]"
+
+msgid "E855: Autocommands caused command to abort"
+msgstr "E855: Comando non completato a causa di autocomandi"
+
+msgid "E82: Cannot allocate any buffer, exiting..."
+msgstr "E82: Non riesco ad allocare alcun buffer, esco..."
+
+msgid "E83: Cannot allocate buffer, using other one..."
+msgstr "E83: Non riesco ad allocare un buffer, uso l'altro..."
+
+msgid "E931: Buffer cannot be registered"
+msgstr "E931: Non riesco a registrare il buffer"
+
+msgid "E937: Attempt to delete a buffer that is in use"
+msgstr "E937: Tentativo di eliminare un buffer ancora usato"
+
+msgid "E515: No buffers were unloaded"
+msgstr "E515: Nessun buffer scaricato"
+
+msgid "E516: No buffers were deleted"
+msgstr "E516: Nessun buffer tolto dalla lista"
+
+msgid "E517: No buffers were wiped out"
+msgstr "E517: Nessun buffer cancellato"
+
+msgid "1 buffer unloaded"
+msgstr "1 buffer scaricato"
+
+msgid "%d buffers unloaded"
+msgstr "%d buffer scaricati"
+
+msgid "1 buffer deleted"
+msgstr "1 buffer tolto dalla lista"
+
+msgid "%d buffers deleted"
+msgstr "%d buffer tolti dalla lista"
+
+msgid "1 buffer wiped out"
+msgstr "1 buffer cancellato"
+
+msgid "%d buffers wiped out"
+msgstr "%d buffer cancellati"
+
+msgid "E90: Cannot unload last buffer"
+msgstr "E90: Non riesco a scaricare l'ultimo buffer"
+
+msgid "E84: No modified buffer found"
+msgstr "E84: Nessun buffer risulta modificato"
+
+msgid "E85: There is no listed buffer"
+msgstr "E85: Non c'è alcun buffer elencato"
+
+msgid "E87: Cannot go beyond last buffer"
+msgstr "E87: Non posso oltrepassare l'ultimo buffer"
+
+msgid "E88: Cannot go before first buffer"
+msgstr "E88: Non posso andare prima del primo buffer"
+
+msgid "E89: No write since last change for buffer %ld (add ! to override)"
+msgstr ""
+"E89: Buffer %ld non salvato dopo modifica (aggiungi ! per eseguire comunque)"
+
+msgid "E948: Job still running (add ! to end the job)"
+msgstr "E948: Lavoro ancora in esecuzione (aggiungi! per terminarlo)"
+
+msgid "E37: No write since last change (add ! to override)"
+msgstr "E37: Non salvato dopo modifica (aggiungi ! per eseguire comunque)"
+
+msgid "E948: Job still running"
+msgstr "E948: Lavoro ancora attivo"
+
+msgid "E37: No write since last change"
+msgstr "E37: Non salvato dopo l'ultima modifica"
+
+msgid "W14: Warning: List of file names overflow"
+msgstr "W14: Avviso: Superato limite della lista dei nomi di file"
+
+msgid "E92: Buffer %ld not found"
+msgstr "E92: Buffer %ld non trovato"
+
+msgid "E93: More than one match for %s"
+msgstr "E93: Più di una corrispondenza per %s"
+
+msgid "E94: No matching buffer for %s"
+msgstr "E94: Nessun buffer corrispondente a %s"
+
+msgid "line %ld"
+msgstr "riga %ld"
+
+msgid "E95: Buffer with this name already exists"
+msgstr "E95: C'è già un buffer con questo nome"
+
+msgid " [Modified]"
+msgstr " [Modificato]"
+
+msgid "[Not edited]"
+msgstr "[Non elaborato]"
+
+msgid "[New file]"
+msgstr "[File nuovo]"
+
+msgid "[Read errors]"
+msgstr "[Errori in lettura]"
+
+msgid "[RO]"
+msgstr "[Sola Lettura]"
+
+msgid "[readonly]"
+msgstr "[in sola lettura]"
+
+msgid "1 line --%d%%--"
+msgstr "1 riga --%d%%--"
+
+msgid "%ld lines --%d%%--"
+msgstr "%ld righe --%d%%--"
+
+msgid "line %ld of %ld --%d%%-- col "
+msgstr "riga %ld di %ld --%d%%-- col "
+
+msgid "[No Name]"
+msgstr "[Senza nome]"
+
+msgid "help"
+msgstr "aiuto"
+
+msgid "[Help]"
+msgstr "[Aiuto]"
+
+msgid "[Preview]"
+msgstr "[Anteprima]"
+
+msgid "All"
+msgstr "Tut"
+
+msgid "Bot"
+msgstr "Fon"
+
+msgid "Top"
+msgstr "Cim"
+
+msgid ""
+"\n"
+"# Buffer list:\n"
+msgstr ""
+"\n"
+"# Lista Buffer:\n"
+
+msgid "E382: Cannot write, 'buftype' option is set"
+msgstr "E382: Non posso scrivere, l'opzione 'buftype' è impostata"
+
+msgid "[Prompt]"
+msgstr "[Richiesta]"
+
+msgid "[Scratch]"
+msgstr "[Volatile]"
+
+msgid ""
+"\n"
+"--- Signs ---"
+msgstr ""
+"\n"
+"--- Segni ---"
+
+msgid "Signs for %s:"
+msgstr "Segni per %s:"
+
+msgid " line=%ld id=%d name=%s"
+msgstr " riga=%ld id=%d, nome=%s"
+
+msgid "E902: Cannot connect to port"
+msgstr "E902: Non posso commettermi alla porta"
+
+msgid "E901: gethostbyname() in channel_open()"
+msgstr "E901: gethostbyname() in channel_open()"
+
+msgid "E898: socket() in channel_open()"
+msgstr "E898: socket() in channel_open()"
+
+msgid "E903: received command with non-string argument"
+msgstr "E903: il comando ricevuto non aveva come argomento una stringa"
+
+msgid "E904: last argument for expr/call must be a number"
+msgstr "E904: l'ultimo argomento per espressione/chiamata dev'essere numerico"
+
+msgid "E904: third argument for call must be a list"
+msgstr "E904: il terzo argomento della chiamata dev'essere una Lista"
+
+msgid "E905: received unknown command: %s"
+msgstr "E905: recevuto comando non conosciuto: %s"
+
+msgid "E630: %s(): write while not connected"
+msgstr "E630: %s(): scrittura in mancanza di connessione"
+
+msgid "E631: %s(): write failed"
+msgstr "E631: %s(): scrittura non riuscita"
+
+msgid "E917: Cannot use a callback with %s()"
+msgstr "E917: Non posso usare callback con %s()"
+
+msgid "E912: cannot use ch_evalexpr()/ch_sendexpr() with a raw or nl channel"
+msgstr "E912: non posso usare ch_evalexpr() con un canale grezzo o nl"
+
+msgid "E906: not an open channel"
+msgstr "E906: canale non aperto"
+
+msgid "E920: _io file requires _name to be set"
+msgstr "E920: il file _io necessita di impostare _name"
+
+msgid "E915: in_io buffer requires in_buf or in_name to be set"
+msgstr "E915: il buffer in_io necessita di impostare in_buf o in_name"
+
+msgid "E918: buffer must be loaded: %s"
+msgstr "E918: il buffer dev'essere caricato: %s"
+
+msgid "E821: File is encrypted with unknown method"
+msgstr "E821: File cifrato con metodo sconosciuto"
+
+msgid "Warning: Using a weak encryption method; see :help 'cm'"
+msgstr "Avviso: Metodo di cifratura debole in uso; vedere :help 'cm'"
+
+msgid "Enter encryption key: "
+msgstr "Immetti chiave di cifratura: "
+
+msgid "Enter same key again: "
+msgstr "Ribatti per conferma la stessa chiave: "
+
+msgid "Keys don't match!"
+msgstr "Le chiavi non corrispondono!"
+
+msgid "[crypted]"
+msgstr "[cifrato]"
+
+msgid "E720: Missing colon in Dictionary: %s"
+msgstr "E720: Manca ':' nel Dizionario: %s"
+
+msgid "E721: Duplicate key in Dictionary: \"%s\""
+msgstr "E721: Chiave duplicata nel Dizionario: \"%s\""
+
+msgid "E722: Missing comma in Dictionary: %s"
+msgstr "E722: Manca virgola nel Dizionario: %s"
+
+msgid "E723: Missing end of Dictionary '}': %s"
+msgstr "E723: Manca '}' a fine Dizionario: %s"
+
+msgid "extend() argument"
+msgstr "argomento di extend()"
+
+msgid "E737: Key already exists: %s"
+msgstr "E737: Chiave già esistente: %s"
+
+msgid "E96: Cannot diff more than %ld buffers"
+msgstr "E96: Non supporto differenze fra più di %ld buffer"
+
+msgid "E810: Cannot read or write temp files"
+msgstr "E810: Non riesco a leggere o scrivere file temporanei"
+
+msgid "E97: Cannot create diffs"
+msgstr "E97: Non riesco a creare differenze"
+
+msgid "Patch file"
+msgstr "File di differenze"
+
+msgid "E816: Cannot read patch output"
+msgstr "E816: Non riesco a leggere output del comando 'patch'"
+
+msgid "E98: Cannot read diff output"
+msgstr "E98: Non riesco a leggere output del comando 'diff'"
+
+msgid "E99: Current buffer is not in diff mode"
+msgstr "E99: Buffer corrente non in modalità 'diff'"
+
+msgid "E793: No other buffer in diff mode is modifiable"
+msgstr "E793: Nessun altro buffer è modificabile in modalità 'diff'"
+
+msgid "E100: No other buffer in diff mode"
+msgstr "E100: Non c'è nessun altro buffer in modalità 'diff'"
+
+msgid "E101: More than two buffers in diff mode, don't know which one to use"
+msgstr "E101: Più di due buffer in modalità 'diff', non so quale usare"
+
+msgid "E102: Can't find buffer \"%s\""
+msgstr "E102: Non riesco a trovare il buffer: \"%s\""
+
+msgid "E103: Buffer \"%s\" is not in diff mode"
+msgstr "E103: Il buffer \"%s\" non è in modalità 'diff'"
+
+msgid "E787: Buffer changed unexpectedly"
+msgstr "E787: Il buffer è variato inaspettatamente"
+
+msgid "E104: Escape not allowed in digraph"
+msgstr "E104: Escape not ammesso nei digrammi"
+
+msgid "E544: Keymap file not found"
+msgstr "E544: File keymap non trovato"
+
+msgid "E105: Using :loadkeymap not in a sourced file"
+msgstr "E105: Uso di :loadkeymap fuori da un file di comandi"
+
+msgid "E791: Empty keymap entry"
+msgstr "E791: Nessuna keymap per questo tasto"
+
+msgid " Keyword completion (^N^P)"
+msgstr " Completamento Keyword (^N^P)"
+
+msgid " ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+msgstr " modalità ^X (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+
+msgid " Whole line completion (^L^N^P)"
+msgstr " Completamento riga intera (^L^N^P)"
+
+msgid " File name completion (^F^N^P)"
+msgstr " Completamento nomi file (^F^N^P)"
+
+msgid " Tag completion (^]^N^P)"
+msgstr " Completamento Tag (^]^N^P)"
+
+msgid " Path pattern completion (^N^P)"
+msgstr " Completamento modello Path (^N^P)"
+
+msgid " Definition completion (^D^N^P)"
+msgstr " Completamento Definizione (^D^N^P)"
+
+msgid " Dictionary completion (^K^N^P)"
+msgstr " Completamento Dizionario (^K^N^P)"
+
+msgid " Thesaurus completion (^T^N^P)"
+msgstr " Completamento Thesaurus (^T^N^P)"
+
+msgid " Command-line completion (^V^N^P)"
+msgstr " Completamento riga comandi (^V^N^P)"
+
+msgid " User defined completion (^U^N^P)"
+msgstr " Completamento definito dall'utente (^U^N^P)"
+
+msgid " Omni completion (^O^N^P)"
+msgstr " Completamento globale (^O^N^P)"
+
+msgid " Spelling suggestion (s^N^P)"
+msgstr " Suggerimento ortografico (s^N^P)"
+
+msgid " Keyword Local completion (^N^P)"
+msgstr " Completamento Keyword Locale (^N^P)"
+
+msgid "Hit end of paragraph"
+msgstr "Giunto alla fine del paragrafo"
+
+msgid "E839: Completion function changed window"
+msgstr "E839: La funzione di completamento ha modificato la finestra"
+
+msgid "E840: Completion function deleted text"
+msgstr "E840: La funzione di completamento ha eliminato del testo"
+
+msgid "'dictionary' option is empty"
+msgstr "l'opzione 'dictionary' non è impostata"
+
+msgid "'thesaurus' option is empty"
+msgstr "l'opzione 'thesaurus' non è impostata"
+
+msgid "Scanning dictionary: %s"
+msgstr "Scansione dizionario: %s"
+
+msgid " (insert) Scroll (^E/^Y)"
+msgstr " (inserisci) Scroll (^E/^Y)"
+
+msgid " (replace) Scroll (^E/^Y)"
+msgstr " (sostituisci) Scroll (^E/^Y)"
+
+msgid "Scanning: %s"
+msgstr "Scansione: %s"
+
+msgid "Scanning tags."
+msgstr "Scansione tag."
+
+msgid "match in file"
+msgstr "corrispondenza nel file"
+
+msgid " Adding"
+msgstr " Aggiungo"
+
+msgid "-- Searching..."
+msgstr "-- Ricerca..."
+
+msgid "Back at original"
+msgstr "Ritorno all'originale"
+
+msgid "Word from other line"
+msgstr "Parola da un'altra riga"
+
+msgid "The only match"
+msgstr "L'unica corrispondenza"
+
+msgid "match %d of %d"
+msgstr "corrispondenza %d di %d"
+
+msgid "match %d"
+msgstr "corrispondenza %d"
+
+msgid "E18: Unexpected characters in :let"
+msgstr "E18: Caratteri non previsti in :let"
+
+msgid "E121: Undefined variable: %s"
+msgstr "E121: Variabile non definita: %s"
+
+msgid "E111: Missing ']'"
+msgstr "E111: Manca ']'"
+
+msgid "E719: Cannot use [:] with a Dictionary"
+msgstr "E719: Non posso usare [:] con un Dizionario"
+
+msgid "E734: Wrong variable type for %s="
+msgstr "E734: Tipo di variabile errato per %s="
+
+msgid "E461: Illegal variable name: %s"
+msgstr "E461: Nome di variabile non ammesso: %s"
+
+msgid "E806: using Float as a String"
+msgstr "E806: uso di un Numero-a-virgola-mobile come Stringa"
+
+msgid "E687: Less targets than List items"
+msgstr "E687: Destinazioni più numerose degli elementi di Lista"
+
+msgid "E688: More targets than List items"
+msgstr "E688: Destinazioni meno numerose degli elementi di Lista"
+
+msgid "Double ; in list of variables"
+msgstr "Doppio ; nella lista di variabili"
+
+msgid "E738: Can't list variables for %s"
+msgstr "E738: Non riesco a elencare le variabili per %s"
+
+msgid "E689: Can only index a List or Dictionary"
+msgstr "E689: Posso indicizzare solo una Lista o un Dizionario"
+
+msgid "E708: [:] must come last"
+msgstr "E708: [:] deve essere alla fine"
+
+msgid "E709: [:] requires a List value"
+msgstr "E709: [:] necessita un valore Lista"
+
+msgid "E710: List value has more items than target"
+msgstr "E710: Il valore Lista ha più elementi della destinazione"
+
+msgid "E711: List value has not enough items"
+msgstr "E711: Il valore Lista non ha elementi sufficienti"
+
+msgid "E690: Missing \"in\" after :for"
+msgstr "E690: Manca \"in\" dopo :for"
+
+msgid "E108: No such variable: \"%s\""
+msgstr "E108: Variabile inesistente: \"%s\""
+
+msgid "E940: Cannot lock or unlock variable %s"
+msgstr "E940: Non riesco a bloccare o sbloccare la variabile %s"
+
+msgid "E743: variable nested too deep for (un)lock"
+msgstr "E743: variabile troppo nidificata per lock/unlock"
+
+msgid "E109: Missing ':' after '?'"
+msgstr "E109: Manca ':' dopo '?'"
+
+msgid "E804: Cannot use '%' with Float"
+msgstr "E804: Non si può usare '%' con un Numero-a-virgola-mobile"
+
+msgid "E110: Missing ')'"
+msgstr "E110: Manca ')'"
+
+msgid "E695: Cannot index a Funcref"
+msgstr "E695: Non posso indicizzare un Funcref"
+
+msgid "E909: Cannot index a special variable"
+msgstr "E909: Non posso indicizzare una variabile speciale"
+
+msgid "E112: Option name missing: %s"
+msgstr "E112: Nome Opzione mancante: %s"
+
+msgid "E113: Unknown option: %s"
+msgstr "E113: Opzione inesistente: %s"
+
+msgid "E114: Missing quote: %s"
+msgstr "E114: Manca '\"': %s"
+
+msgid "E115: Missing quote: %s"
+msgstr "E115: Manca apostrofo: %s"
+
+msgid "Not enough memory to set references, garbage collection aborted!"
+msgstr "Memoria insufficiente per impostarlo, recupero memoria fallito!"
+
+msgid "E724: variable nested too deep for displaying"
+msgstr "E724: variabile troppo nidificata per la visualizzazione"
+
+msgid "E805: Using a Float as a Number"
+msgstr "E805: Uso di un Numero-a-virgola-mobile come Numero"
+
+msgid "E703: Using a Funcref as a Number"
+msgstr "E703: Uso di Funcref come Numero"
+
+msgid "E745: Using a List as a Number"
+msgstr "E745: Uso di Lista come Numero"
+
+msgid "E728: Using a Dictionary as a Number"
+msgstr "E728: Uso di Dizionario come Numero"
+
+msgid "E910: Using a Job as a Number"
+msgstr "E910: Uso di Job come Numero"
+
+msgid "E913: Using a Channel as a Number"
+msgstr "E913: Uso di Canale come Numero"
+
+msgid "E891: Using a Funcref as a Float"
+msgstr "E891: Uso di Funcref come Numero-a-virgola-mobile"
+
+msgid "E892: Using a String as a Float"
+msgstr "E892: Uso di Stringa come Numero-a-virgola-mobile"
+
+msgid "E893: Using a List as a Float"
+msgstr "E893: Uso di Lista come Numero-a-virgola-mobile"
+
+msgid "E894: Using a Dictionary as a Float"
+msgstr "E894: Uso di Dizionario come Numero-a-virgola-mobile"
+
+msgid "E907: Using a special value as a Float"
+msgstr "E907: Uso di valore speciale come Numero-a-virgola-mobile"
+
+msgid "E911: Using a Job as a Float"
+msgstr "E911: Uso di Job come Numero-a-virgola-mobile"
+
+msgid "E914: Using a Channel as a Float"
+msgstr "E914: Uso di Canale come Numero-a-virgola-mobile"
+
+msgid "E729: using Funcref as a String"
+msgstr "E729: uso di Funcref come Stringa"
+
+msgid "E730: using List as a String"
+msgstr "E730: uso di Lista come Stringa"
+
+msgid "E731: using Dictionary as a String"
+msgstr "E731: uso di Dizionario come Stringa"
+
+msgid "E908: using an invalid value as a String"
+msgstr "E908: uso di un valore non valido come Stringa"
+
+msgid "E795: Cannot delete variable %s"
+msgstr "E795: Non posso cancellare la variabile %s"
+
+msgid "E704: Funcref variable name must start with a capital: %s"
+msgstr ""
+"E704: Il nome della variabile Funcref deve iniziare con una maiuscola: %s"
+
+msgid "E705: Variable name conflicts with existing function: %s"
+msgstr "E705: Nome di variabile in conflitto con una funzione esistente: %s"
+
+msgid "E741: Value is locked: %s"
+msgstr "E741: Valore di %s non modificabile"
+
+msgid "Unknown"
+msgstr "Sconosciuto"
+
+msgid "E742: Cannot change value of %s"
+msgstr "E742: Non riesco a cambiare il valore di %s"
+
+msgid "E698: variable nested too deep for making a copy"
+msgstr "E698: Variabile troppo nidificata per poterla copiare"
+
+msgid ""
+"\n"
+"# global variables:\n"
+msgstr ""
+"\n"
+"# variabili globali:\n"
+
+msgid ""
+"\n"
+"\tLast set from "
+msgstr ""
+"\n"
+"\tImpostata l'ultima volta da "
+
+msgid "E691: Can only compare List with List"
+msgstr "E691: Posso confrontare una Lista solo con un'altra Lista"
+
+msgid "E692: Invalid operation for List"
+msgstr "E692: Operazione non valida per Liste"
+
+msgid "E735: Can only compare Dictionary with Dictionary"
+msgstr "E735: Posso confrontare un Dizionario solo con un altro Dizionario"
+
+msgid "E736: Invalid operation for Dictionary"
+msgstr "E736: Operazione non valida per Dizionari"
+
+msgid "E694: Invalid operation for Funcrefs"
+msgstr "E694: Operazione non valida per Funcref"
+
+msgid "map() argument"
+msgstr "argomento di map()"
+
+msgid "filter() argument"
+msgstr "argomento di filter()"
+
+msgid "E686: Argument of %s must be a List"
+msgstr "E686: L'argomento di %s deve essere una Lista"
+
+msgid "E928: String required"
+msgstr "E928: Stringa necessaria"
+
+msgid "E808: Number or Float required"
+msgstr "E808: Ci vuole un Numero o un Numero-a-virgola-mobile"
+
+msgid "add() argument"
+msgstr "argomento di add()"
+
+msgid "E785: complete() can only be used in Insert mode"
+msgstr "E785: complete() può essere usata solo in modalità inserimento"
+
+msgid "&Ok"
+msgstr "&OK"
+
+msgid "+-%s%3ld line: "
+msgid_plural "+-%s%3ld lines: "
+msgstr[0] "+-%s%3ld riga: "
+msgstr[1] "+-%s%3ld righe: "
+
+msgid "E700: Unknown function: %s"
+msgstr "E700: Funzione sconosciuta: %s"
+
+msgid "E922: expected a dict"
+msgstr "E922: aspettavo un Dizionario"
+
+msgid "E923: Second argument of function() must be a list or a dict"
+msgstr ""
+"E923: Il secondo argomento di function() dev'essere una Lista o un Dizionario"
+
+msgid ""
+"&OK\n"
+"&Cancel"
+msgstr ""
+"&OK\n"
+"&Non eseguire"
+
+msgid "called inputrestore() more often than inputsave()"
+msgstr "inputrestore() chiamata più volte di inputsave()"
+
+msgid "insert() argument"
+msgstr "argomento di insert()"
+
+msgid "E786: Range not allowed"
+msgstr "E786: Intervallo non consentito"
+
+msgid "E916: not a valid job"
+msgstr "E916: job non valido"
+
+msgid "E701: Invalid type for len()"
+msgstr "E701: Tipo non valido per len()"
+
+msgid "E798: ID is reserved for \":match\": %ld"
+msgstr "E798: ID riservato per \":match\": %ld"
+
+msgid "E726: Stride is zero"
+msgstr "E726: Incremento indice a zero"
+
+msgid "E727: Start past end"
+msgstr "E727: Indice iniziale superiore a quello finale"
+
+msgid "<empty>"
+msgstr "<vuoto>"
+
+msgid "E240: No connection to the X server"
+msgstr "E240: Manca connessione con server Vim"
+
+msgid "E241: Unable to send to %s"
+msgstr "E241: Impossibile inviare a %s"
+
+msgid "E277: Unable to read a server reply"
+msgstr "E277: Non riesco a leggere una risposta del server"
+
+msgid "E941: already started a server"
+msgstr "E941: un server è già stato predisposto"
+
+msgid "E942: +clientserver feature not available"
+msgstr "E942: funzionalità +clientserver non disponibile"
+
+msgid "remove() argument"
+msgstr "argomento di remove()"
+
+msgid "E655: Too many symbolic links (cycle?)"
+msgstr "E655: Troppi link simbolici (circolarità?)"
+
+msgid "reverse() argument"
+msgstr "argomento di reverse()"
+
+msgid "E258: Unable to send to client"
+msgstr "E258: Impossibile inviare al client"
+
+msgid "E927: Invalid action: '%s'"
+msgstr "E927: Azione non valida: '%s'"
+
+msgid "sort() argument"
+msgstr "argomento di sort()"
+
+msgid "uniq() argument"
+msgstr "argomento di uniq()"
+
+msgid "E702: Sort compare function failed"
+msgstr "E702: Funzione confronto nel sort non riuscita"
+
+msgid "E882: Uniq compare function failed"
+msgstr "E882: Funzione confronto in uniq non riuscita"
+
+msgid "(Invalid)"
+msgstr "(Non valido)"
+
+msgid "E935: invalid submatch number: %d"
+msgstr "E935: nomeri di sotto-corrispondenza non valido: %d"
+
+msgid "E677: Error writing temp file"
+msgstr "E677: Errore in scrittura su file temporaneo"
+
+msgid "E921: Invalid callback argument"
+msgstr "E921: Argomento callback non valido"
+
+msgid "<%s>%s%s %d, Hex %02x, Oct %03o, Digr %s"
+msgstr "<%s>%s%s %d, Esa %02x, Ottale %03o, Digr %s"
+
+msgid "<%s>%s%s %d, Hex %02x, Octal %03o"
+msgstr "<%s>%s%s %d, Esa %02x, Ottale %03o"
+
+msgid "> %d, Hex %04x, Oct %o, Digr %s"
+msgstr "> %d, Esa %04x, Ottale %o, Digr %s"
+
+msgid "> %d, Hex %08x, Oct %o, Digr %s"
+msgstr "> %d, Esa %08x, Ottale %o, Digr %s"
+
+msgid "> %d, Hex %04x, Octal %o"
+msgstr "> %d, Esa %04x, Ottale %o"
+
+msgid "> %d, Hex %08x, Octal %o"
+msgstr "> %d, Esa %08x, Ottale %o"
+
+msgid "E134: Move lines into themselves"
+msgstr "E134: Movimento di righe verso se stesse"
+
+msgid "1 line moved"
+msgstr "1 riga mossa"
+
+msgid "%ld lines moved"
+msgstr "%ld righe mosse"
+
+msgid "%ld lines filtered"
+msgstr "%ld righe filtrate"
+
+msgid "E135: *Filter* Autocommands must not change current buffer"
+msgstr "E135: *Filter* Gli autocomandi non devono modificare il buffer in uso"
+
+msgid "[No write since last change]\n"
+msgstr "[Non salvato dopo l'ultima modifica]\n"
+
+msgid "%sviminfo: %s in line: "
+msgstr "%sviminfo: %s nella riga: "
+
+msgid "E136: viminfo: Too many errors, skipping rest of file"
+msgstr "E136: viminfo: Troppi errori, ignoro il resto del file"
+
+msgid "Reading viminfo file \"%s\"%s%s%s"
+msgstr "Lettura file viminfo \"%s\"%s%s%s"
+
+msgid " info"
+msgstr " informazione"
+
+msgid " marks"
+msgstr " mark"
+
+msgid " oldfiles"
+msgstr " file elaborati in precedenza"
+
+msgid " FAILED"
+msgstr " FALLITO"
+
+msgid "E137: Viminfo file is not writable: %s"
+msgstr "E137: File viminfo \"%s\" inaccessibile in scrittura"
+
+msgid "E929: Too many viminfo temp files, like %s!"
+msgstr "E929: Troppi file temporanei viminfo, come %s!"
+
+msgid "E138: Can't write viminfo file %s!"
+msgstr "E138: Non riesco a scrivere il file viminfo %s!"
+
+msgid "Writing viminfo file \"%s\""
+msgstr "Scrivo file viminfo \"%s\""
+
+msgid "E886: Can't rename viminfo file to %s!"
+msgstr "E886: Non riesco a rinominare il file viminfo a %s!"
+
+msgid "# This viminfo file was generated by Vim %s.\n"
+msgstr "# Questo file viminfo è stato generato da Vim %s.\n"
+
+msgid ""
+"# You may edit it if you're careful!\n"
+"\n"
+msgstr ""
+"# File modificabile, attento a quel che fai!\n"
+"\n"
+
+msgid "# Value of 'encoding' when this file was written\n"
+msgstr "# Valore di 'encoding' al momento della scrittura di questo file\n"
+
+msgid "Illegal starting char"
+msgstr "Carattere iniziale non ammesso"
+
+msgid ""
+"\n"
+"# Bar lines, copied verbatim:\n"
+msgstr ""
+"\n"
+"# Righe che iniziano con '|', semplicemente copiate:\n"
+
+msgid "Save As"
+msgstr "Salva con Nome"
+
+msgid "Write partial file?"
+msgstr "Scrivo il file incompleto?"
+
+msgid "E140: Use ! to write partial buffer"
+msgstr "E140: Usa ! per scrivere il buffer incompleto"
+
+msgid "Overwrite existing file \"%s\"?"
+msgstr "Riscrittura del file esistente \"%s\"?"
+
+msgid "Swap file \"%s\" exists, overwrite anyway?"
+msgstr "Il file swap \"%s\" esiste già, sovrascrivo?"
+
+msgid "E768: Swap file exists: %s (:silent! overrides)"
+msgstr "E768: File swap esistente: %s (:silent! per sovrascriverlo)"
+
+msgid "E141: No file name for buffer %ld"
+msgstr "E141: Manca nome file per il buffer %ld"
+
+msgid "E142: File not written: Writing is disabled by 'write' option"
+msgstr "E142: File non scritto: Scrittura inibita da opzione 'write'"
+
+msgid ""
+"'readonly' option is set for \"%s\".\n"
+"Do you wish to write anyway?"
+msgstr ""
+"opzione 'readonly' attiva per \"%s\".\n"
+"Vuoi scrivere comunque?"
+
+msgid ""
+"File permissions of \"%s\" are read-only.\n"
+"It may still be possible to write it.\n"
+"Do you wish to try?"
+msgstr ""
+"I permessi di \"%s\" sono di sola lettura.\n"
+"Questo potrebbe non impedire la scrittura.\n"
+"Vuoi provare?"
+
+msgid "E505: \"%s\" is read-only (add ! to override)"
+msgstr "E505: \"%s\" è in sola lettura (aggiungi ! per eseguire comunque)"
+
+msgid "Edit File"
+msgstr "Elabora File"
+
+msgid "E143: Autocommands unexpectedly deleted new buffer %s"
+msgstr ""
+"E143: Gli autocomandi hanno inaspettatamente cancellato il nuovo buffer %s"
+
+msgid "E144: non-numeric argument to :z"
+msgstr "E144: argomento non-numerico a :z"
+
+msgid "E145: Shell commands not allowed in rvim"
+msgstr "E145: Comandi Shell non permessi in rvim"
+
+msgid "E146: Regular expressions can't be delimited by letters"
+msgstr "E146: Le espressioni regolari non possono essere delimitate da lettere"
+
+msgid "replace with %s (y/n/a/q/l/^E/^Y)?"
+msgstr "sostituire con %s (y/n/a/q/l/^E/^Y)?"
+
+msgid "(Interrupted) "
+msgstr "(Interrotto) "
+
+msgid "1 match"
+msgstr "1 corrisp."
+
+msgid "1 substitution"
+msgstr "1 sostituzione"
+
+msgid "%ld matches"
+msgstr "%ld corrisp."
+
+msgid "%ld substitutions"
+msgstr "%ld sostituzioni"
+
+msgid " on 1 line"
+msgstr " in 1 riga"
+
+msgid " on %ld lines"
+msgstr " in %ld righe"
+
+msgid "E147: Cannot do :global recursive with a range"
+msgstr "E147: :global non può essere usato ricorsivamente con un intervallo"
+
+msgid "E148: Regular expression missing from global"
+msgstr "E148: Manca espressione regolare nel comando 'global'"
+
+msgid "Pattern found in every line: %s"
+msgstr "Espressione trovata su ogni riga: %s"
+
+msgid "Pattern not found: %s"
+msgstr "Espressione non trovata: %s"
+
+msgid ""
+"\n"
+"# Last Substitute String:\n"
+"$"
+msgstr ""
+"\n"
+"# Ultima Stringa Sostituzione:\n"
+"$"
+
+msgid "E478: Don't panic!"
+msgstr "E478: Non lasciarti prendere dal panico!"
+
+msgid "E661: Sorry, no '%s' help for %s"
+msgstr "E661: Spiacente, nessun aiuto '%s' per %s"
+
+msgid "E149: Sorry, no help for %s"
+msgstr "E149: Spiacente, nessun aiuto per %s"
+
+msgid "Sorry, help file \"%s\" not found"
+msgstr "Spiacente, non trovo file di aiuto \"%s\""
+
+msgid "E151: No match: %s"
+msgstr "E151: Nessuna corrispondenza: %s"
+
+msgid "E152: Cannot open %s for writing"
+msgstr "E152: Non posso aprire %s in scrittura"
+
+msgid "E153: Unable to open %s for reading"
+msgstr "E153: Non riesco ad aprire %s in lettura"
+
+msgid "E670: Mix of help file encodings within a language: %s"
+msgstr "E670: Codifiche diverse fra file di aiuto nella stessa lingua: %s"
+
+msgid "E154: Duplicate tag \"%s\" in file %s/%s"
+msgstr "E154: Tag duplicato \"%s\" nel file %s/%s"
+
+msgid "E150: Not a directory: %s"
+msgstr "E150: %s non è una directory"
+
+msgid "E160: Unknown sign command: %s"
+msgstr "E160: Comando 'sign' sconosciuto: %s"
+
+msgid "E156: Missing sign name"
+msgstr "E156: Manca nome 'sign'"
+
+msgid "E612: Too many signs defined"
+msgstr "E612: Troppi 'sign' definiti"
+
+msgid "E239: Invalid sign text: %s"
+msgstr "E239: Testo 'sign' non valido: %s"
+
+msgid "E155: Unknown sign: %s"
+msgstr "E155: 'sign' sconosciuto: %s"
+
+msgid "E159: Missing sign number"
+msgstr "E159: Manca numero 'sign'"
+
+msgid "E158: Invalid buffer name: %s"
+msgstr "E158: Nome buffer non valido: %s"
+
+msgid "E934: Cannot jump to a buffer that does not have a name"
+msgstr "E934: Impossibile passare a un buffer che non ha un nome"
+
+msgid "E157: Invalid sign ID: %ld"
+msgstr "E157: ID 'sign' non valido: %ld"
+
+msgid "E885: Not possible to change sign %s"
+msgstr "E885: Impossibile cambiare segno %s"
+
+msgid " (NOT FOUND)"
+msgstr " (NON TROVATO)"
+
+msgid " (not supported)"
+msgstr " (non supportata)"
+
+msgid "[Deleted]"
+msgstr "[Cancellato]"
+
+msgid "No old files"
+msgstr "Nessun file elaborato in precedenza"
+
+msgid "Entering Debug mode. Type \"cont\" to continue."
+msgstr "Entro modalità Debug. Batti \"cont\" per continuare."
+
+msgid "Oldval = \"%s\""
+msgstr "Vecchioval = \"%s\""
+
+msgid "Newval = \"%s\""
+msgstr "Nuovoval = \"%s\""
+
+msgid "line %ld: %s"
+msgstr "riga %ld: %s"
+
+msgid "cmd: %s"
+msgstr "com: %s"
+
+msgid "frame is zero"
+msgstr "al livello zero"
+
+msgid "frame at highest level: %d"
+msgstr "al livello più alto: %d"
+
+msgid "Breakpoint in \"%s%s\" line %ld"
+msgstr "Pausa in \"%s%s\" riga %ld"
+
+msgid "E161: Breakpoint not found: %s"
+msgstr "E161: Breakpoint %s non trovato"
+
+msgid "No breakpoints defined"
+msgstr "Nessun 'breakpoint' definito"
+
+msgid "%3d %s %s line %ld"
+msgstr "%3d %s %s riga %ld"
+
+msgid "%3d expr %s"
+msgstr "%3d espr %s"
+
+msgid "E750: First use \":profile start {fname}\""
+msgstr "E750: Usare prima \":profile start {fname}\""
+
+msgid "Save changes to \"%s\"?"
+msgstr "Salvare modifiche a \"%s\"?"
+
+msgid "E947: Job still running in buffer \"%s\""
+msgstr "E947: Lavoro ancora in esecuzione nel buffer \"%s\""
+
+msgid "E162: No write since last change for buffer \"%s\""
+msgstr "E162: Buffer \"%s\" non salvato dopo modifica"
+
+msgid "Warning: Entered other buffer unexpectedly (check autocommands)"
+msgstr ""
+"Avviso: Entrato in altro buffer inaspettatamente (controllare autocomandi)"
+
+msgid "E163: There is only one file to edit"
+msgstr "E163: C'è un solo file da elaborare"
+
+msgid "E164: Cannot go before first file"
+msgstr "E164: Non posso andare davanti al primo file"
+
+msgid "E165: Cannot go beyond last file"
+msgstr "E165: Non posso oltrepassare l'ultimo file"
+
+msgid "E666: compiler not supported: %s"
+msgstr "E666: compilatore non supportato: %s"
+
+msgid "Searching for \"%s\" in \"%s\""
+msgstr "Cerco \"%s\" in \"%s\""
+
+msgid "Searching for \"%s\""
+msgstr "Cerco \"%s\""
+
+msgid "not found in '%s': \"%s\""
+msgstr "non trovato in '%s': \"%s\""
+
+msgid "W20: Required python version 2.x not supported, ignoring file: %s"
+msgstr ""
+"W20: Versione richiesta di python 2.x non supportata, ignoro il file: %s"
+
+msgid "W21: Required python version 3.x not supported, ignoring file: %s"
+msgstr ""
+"W21: Versione richiesta di python 3.x non supportata, ignoro il file: %s"
+
+msgid "Source Vim script"
+msgstr "Esegui script Vim"
+
+msgid "Cannot source a directory: \"%s\""
+msgstr "Non riesco ad eseguire una directory: \"%s\""
+
+msgid "could not source \"%s\""
+msgstr "non riesco ad eseguire \"%s\""
+
+msgid "line %ld: could not source \"%s\""
+msgstr "riga %ld: non riesco ad eseguire \"%s\""
+
+msgid "sourcing \"%s\""
+msgstr "eseguo \"%s\""
+
+msgid "line %ld: sourcing \"%s\""
+msgstr "riga %ld: eseguo \"%s\""
+
+msgid "finished sourcing %s"
+msgstr "esecuzione di %s terminata"
+
+msgid "continuing in %s"
+msgstr "continuo in %s"
+
+msgid "modeline"
+msgstr "modeline"
+
+msgid "--cmd argument"
+msgstr "argomento --cmd"
+
+msgid "-c argument"
+msgstr "argomento -c"
+
+msgid "environment variable"
+msgstr "variabile d'ambiente"
+
+msgid "error handler"
+msgstr "gestore di errore"
+
+msgid "W15: Warning: Wrong line separator, ^M may be missing"
+msgstr "W15: Avviso: Separatore di riga errato, forse manca ^M"
+
+msgid "E167: :scriptencoding used outside of a sourced file"
+msgstr "E167: :scriptencoding usato fuori da un file di comandi"
+
+msgid "E168: :finish used outside of a sourced file"
+msgstr "E168: :finish usato fuori da file di comandi"
+
+msgid "Current %slanguage: \"%s\""
+msgstr "Lingua %sin uso: \"%s\""
+
+msgid "E197: Cannot set language to \"%s\""
+msgstr "E197: Non posso impostare lingua a \"%s\""
+
+msgid "Entering Ex mode. Type \"visual\" to go to Normal mode."
+msgstr "Entro modalità Ex. Batti \"visual\" per tornare a modalità Normale."
+
+msgid "E501: At end-of-file"
+msgstr "E501: Alla fine-file"
+
+msgid "E169: Command too recursive"
+msgstr "E169: Comando troppo ricorsivo"
+
+msgid "E605: Exception not caught: %s"
+msgstr "E605: Eccezione non intercettata: %s"
+
+msgid "End of sourced file"
+msgstr "Fine del file di comandi"
+
+msgid "End of function"
+msgstr "Fine funzione"
+
+msgid "E464: Ambiguous use of user-defined command"
+msgstr "E464: Uso ambiguo di comando definito dall'utente"
+
+msgid "E492: Not an editor command"
+msgstr "E492: Non è un comando dell'editor"
+
+msgid "E493: Backwards range given"
+msgstr "E493: Intervallo rovesciato"
+
+msgid "Backwards range given, OK to swap"
+msgstr "Intervallo rovesciato, OK invertirlo"
+
+msgid "E494: Use w or w>>"
+msgstr "E494: Usa w oppure w>>"
+
+msgid "E943: Command table needs to be updated, run 'make cmdidxs'"
+msgstr "E943: Tabella dei comandi da aggiornare, eseguire 'make cmdidxs'"
+
+msgid "E319: Sorry, the command is not available in this version"
+msgstr "E319: Spiacente, comando non disponibile in questa versione"
+
+msgid "1 more file to edit. Quit anyway?"
+msgstr "1 ulteriore file da elaborare. Esco lo stesso?"
+
+msgid "%d more files to edit. Quit anyway?"
+msgstr "%d ulteriori file da elaborare. Esco lo stesso?"
+
+msgid "E173: 1 more file to edit"
+msgstr "E173: ancora 1 file da elaborare"
+
+msgid "E173: %ld more files to edit"
+msgstr "E173: ancora %ld file da elaborare"
+
+msgid "E174: Command already exists: add ! to replace it"
+msgstr "E174: Il comando esiste già: aggiungi ! per sostituirlo"
+
+msgid ""
+"\n"
+" Name Args Address Complete Definition"
+msgstr ""
+"\n"
+" Nome Arg. Indir. Completo Definizione"
+
+msgid "No user-defined commands found"
+msgstr "Non trovo comandi definiti dall'utente"
+
+msgid "E175: No attribute specified"
+msgstr "E175: Nessun attributo specificato"
+
+msgid "E176: Invalid number of arguments"
+msgstr "E176: Numero di argomenti non valido"
+
+msgid "E177: Count cannot be specified twice"
+msgstr "E177: Non si può specificare due volte il contatore"
+
+msgid "E178: Invalid default value for count"
+msgstr "E178: Valore predefinito del contatore non valido"
+
+msgid "E179: argument required for -complete"
+msgstr "E179: argomento necessario per -complete"
+
+msgid "E179: argument required for -addr"
+msgstr "E179: argomento necessario per -addr"
+
+msgid "E181: Invalid attribute: %s"
+msgstr "E181: Attributo non valido: %s"
+
+msgid "E182: Invalid command name"
+msgstr "E182: Nome comando non valido"
+
+msgid "E183: User defined commands must start with an uppercase letter"
+msgstr ""
+"E183: I comandi definiti dall'utente devono iniziare con lettera maiuscola"
+
+msgid "E841: Reserved name, cannot be used for user defined command"
+msgstr "E841: Nome riservato, non usabile in un comando definito dall'utente"
+
+msgid "E184: No such user-defined command: %s"
+msgstr "E184: Comando definito dall'utente %s inesistente"
+
+msgid "E180: Invalid address type value: %s"
+msgstr "E180: Tipo di indirizzo non valido: %s"
+
+msgid "E180: Invalid complete value: %s"
+msgstr "E180: Valore %s non valido per 'complete'"
+
+msgid "E468: Completion argument only allowed for custom completion"
+msgstr ""
+"E468: Argomento di completamento consentito solo per completamento "
+"personalizzato"
+
+msgid "E467: Custom completion requires a function argument"
+msgstr ""
+"E467: Il completamento personalizzato richiede un argomento di funzione"
+
+msgid "unknown"
+msgstr "sconosciuto"
+
+msgid "E185: Cannot find color scheme '%s'"
+msgstr "E185: Non riesco a trovare schema colore '%s'"
+
+msgid "Greetings, Vim user!"
+msgstr "Salve, utente Vim!"
+
+msgid "E784: Cannot close last tab page"
+msgstr "E784: Non posso chiudere l'ultima linguetta"
+
+msgid "Already only one tab page"
+msgstr "C'è già una linguetta sola"
+
+msgid "Edit File in new tab page"
+msgstr "Apri il File in una nuova finestra"
+
+msgid "Edit File in new window"
+msgstr "Apri il File in una nuova finestra"
+
+msgid "Tab page %d"
+msgstr "Linguetta %d"
+
+msgid "No swap file"
+msgstr "Non posso creare un file di swap"
+
+msgid "Append File"
+msgstr "In aggiunta al File"
+
+msgid "E747: Cannot change directory, buffer is modified (add ! to override)"
+msgstr ""
+"E747: Non posso cambiare directory, buffer modificato (aggiungi ! per "
+"eseguire comunque)"
+
+msgid "E186: No previous directory"
+msgstr "E186: Non c'è una directory precedente"
+
+msgid "E187: Unknown"
+msgstr "E187: Sconosciuto"
+
+msgid "E465: :winsize requires two number arguments"
+msgstr "E465: :winsize richiede due argomenti numerici"
+
+msgid "Window position: X %d, Y %d"
+msgstr "Posizione finestra: X %d, Y %d"
+
+msgid "E188: Obtaining window position not implemented for this platform"
+msgstr ""
+"E188: Informazioni posizione finestra non disponibili su questa piattaforma"
+
+msgid "E466: :winpos requires two number arguments"
+msgstr "E466: :winpos richiede due argomenti numerici"
+
+msgid "E930: Cannot use :redir inside execute()"
+msgstr "E930: Non è possibile usare :redir all'interno di execute()"
+
+msgid "Save Redirection"
+msgstr "Salva Redirezione"
+
+msgid "Save View"
+msgstr "Salva Veduta"
+
+msgid "Save Session"
+msgstr "Salva Sessione"
+
+msgid "Save Setup"
+msgstr "Salva Setup"
+
+msgid "E739: Cannot create directory: %s"
+msgstr "E739: Non posso creare la directory: %s"
+
+msgid "E189: \"%s\" exists (add ! to override)"
+msgstr "E189: \"%s\" esiste (aggiungi ! per eseguire comunque)"
+
+msgid "E190: Cannot open \"%s\" for writing"
+msgstr "E190: Non riesco ad aprire \"%s\" in scrittura"
+
+msgid "E191: Argument must be a letter or forward/backward quote"
+msgstr ""
+"E191: L'argomento deve essere una lettera, oppure un apice/apice retroverso"
+
+msgid "E192: Recursive use of :normal too deep"
+msgstr "E192: Uso ricorsivo di :normal troppo esteso"
+
+msgid "E809: #< is not available without the +eval feature"
+msgstr "E809: #< non disponibile se Vim è compilato senza +eval"
+
+msgid "E194: No alternate file name to substitute for '#'"
+msgstr "E194: Nessun nome file alternativo da sostituire a '#'"
+
+msgid "E495: no autocommand file name to substitute for \"<afile>\""
+msgstr "E495: nessun file di autocomandi da sostituire per \"<afile>\""
+
+msgid "E496: no autocommand buffer number to substitute for \"<abuf>\""
+msgstr ""
+"E496: nessun numero di buffer di autocomandi da sostituire per \"<abuf>\""
+
+msgid "E497: no autocommand match name to substitute for \"<amatch>\""
+msgstr ""
+"E497: nessun nome di autocomandi trovato da sostituire per \"<amatch>\""
+
+msgid "E498: no :source file name to substitute for \"<sfile>\""
+msgstr ""
+"E498: nessun nome di file :source trovato da sostituire per \"<sfile>\""
+
+msgid "E842: no line number to use for \"<slnum>\""
+msgstr "E842: nessun numero di riga da usare per \"<slnum>\""
+
+msgid "E499: Empty file name for '%' or '#', only works with \":p:h\""
+msgstr "E499: Un nome di file nullo per '%' o '#', va bene solo con \":p:h\""
+
+msgid "E500: Evaluates to an empty string"
+msgstr "E500: Il valore è una stringa nulla"
+
+msgid "E195: Cannot open viminfo file for reading"
+msgstr "E195: Non posso aprire il file viminfo in lettura"
+
+msgid "Untitled"
+msgstr "Senza Nome"
+
+msgid "E196: No digraphs in this version"
+msgstr "E196: Digrammi non supportati in questa versione"
+
+msgid "E608: Cannot :throw exceptions with 'Vim' prefix"
+msgstr "E608: Impossibile lanciare eccezioni con prefisso 'Vim'"
+
+msgid "Exception thrown: %s"
+msgstr "Eccezione lanciata: %s"
+
+msgid "Exception finished: %s"
+msgstr "Eccezione finita: %s"
+
+msgid "Exception discarded: %s"
+msgstr "Eccezione scartata: %s"
+
+msgid "%s, line %ld"
+msgstr "%s, riga %ld"
+
+msgid "Exception caught: %s"
+msgstr "Eccezione intercettata: %s"
+
+msgid "%s made pending"
+msgstr "%s reso 'pending'"
+
+msgid "%s resumed"
+msgstr "%s ripristinato"
+
+msgid "%s discarded"
+msgstr "%s scartato"
+
+msgid "Exception"
+msgstr "Eccezione"
+
+msgid "Error and interrupt"
+msgstr "Errore ed interruzione"
+
+msgid "Error"
+msgstr "Errore"
+
+msgid "Interrupt"
+msgstr "Interruzione"
+
+msgid "E579: :if nesting too deep"
+msgstr "E579: nidificazione di :if troppo estesa"
+
+msgid "E580: :endif without :if"
+msgstr "E580: :endif senza :if"
+
+msgid "E581: :else without :if"
+msgstr "E581: :else senza :if"
+
+msgid "E582: :elseif without :if"
+msgstr "E582: :elseif senza :if"
+
+msgid "E583: multiple :else"
+msgstr "E583: :else multipli"
+
+msgid "E584: :elseif after :else"
+msgstr "E584: :elseif dopo :else"
+
+msgid "E585: :while/:for nesting too deep"
+msgstr "E585: nidificazione di :while/:for troppo estesa"
+
+msgid "E586: :continue without :while or :for"
+msgstr "E586: :continue senza :while o :for"
+
+msgid "E587: :break without :while or :for"
+msgstr "E587: :break senza :while o :for"
+
+msgid "E732: Using :endfor with :while"
+msgstr "E732: Uso di :endfor con :while"
+
+msgid "E733: Using :endwhile with :for"
+msgstr "E733: Uso di :endwhile con :for"
+
+msgid "E601: :try nesting too deep"
+msgstr "E601: nidificazione di :try troppo estesa"
+
+msgid "E603: :catch without :try"
+msgstr "E603: :catch senza :try"
+
+msgid "E604: :catch after :finally"
+msgstr "E604: :catch dopo :finally"
+
+msgid "E606: :finally without :try"
+msgstr "E606: :finally senza :try"
+
+msgid "E607: multiple :finally"
+msgstr "E607: :finally multipli"
+
+msgid "E602: :endtry without :try"
+msgstr "E602: :endtry senza :try"
+
+msgid "E193: :endfunction not inside a function"
+msgstr "E193: :endfunction non contenuto in una funzione"
+
+msgid "E788: Not allowed to edit another buffer now"
+msgstr "E788: Non si può aprire ora un altro buffer"
+
+msgid "E811: Not allowed to change buffer information now"
+msgstr "E811: Non consentito modificare informazioni del buffer ora"
+
+msgid "tagname"
+msgstr "nome_tag"
+
+msgid " kind file\n"
+msgstr " tipo file\n"
+
+msgid "'history' option is zero"
+msgstr "l'opzione 'history' è a zero"
+
+msgid ""
+"\n"
+"# %s History (newest to oldest):\n"
+msgstr ""
+"\n"
+"# %s Storia (da più recente a meno recente):\n"
+
+msgid "Command Line"
+msgstr "Riga di Comando"
+
+msgid "Search String"
+msgstr "Stringa di Ricerca"
+
+msgid "Expression"
+msgstr "Espressione"
+
+msgid "Input Line"
+msgstr "Riga di Input"
+
+msgid "Debug Line"
+msgstr "Riga di Debug"
+
+msgid "E198: cmd_pchar beyond the command length"
+msgstr "E198: cmd_pchar dopo la fine del comando"
+
+msgid "E199: Active window or buffer deleted"
+msgstr "E199: Finestra attiva o buffer cancellato"
+
+msgid "E812: Autocommands changed buffer or buffer name"
+msgstr "E812: Gli autocomandi hanno modificato il buffer o il nome del buffer"
+
+msgid "Illegal file name"
+msgstr "Nome di file non ammesso"
+
+msgid "is a directory"
+msgstr "è una directory"
+
+msgid "is not a file"
+msgstr "non è un file"
+
+msgid "is a device (disabled with 'opendevice' option)"
+msgstr "è una periferica (disabilitata con l'opzione 'opendevice')"
+
+msgid "[New File]"
+msgstr "[File nuovo]"
+
+msgid "[New DIRECTORY]"
+msgstr "[Nuova DIRECTORY]"
+
+msgid "[File too big]"
+msgstr "[File troppo grande]"
+
+msgid "[Permission Denied]"
+msgstr "[Tipo di accesso non consentito]"
+
+msgid "E200: *ReadPre autocommands made the file unreadable"
+msgstr "E200: Gli autocomandi *ReadPre hanno reso il file illeggibile"
+
+msgid "E201: *ReadPre autocommands must not change current buffer"
+msgstr "E201: Gli autocomandi *ReadPre non devono modificare il buffer in uso"
+
+msgid "Vim: Reading from stdin...\n"
+msgstr "Vim: Leggo da 'stdin'...\n"
+
+msgid "Reading from stdin..."
+msgstr "Leggo da 'stdin'..."
+
+msgid "E202: Conversion made file unreadable!"
+msgstr "E202: La conversione ha reso il file illeggibile!"
+
+msgid "[fifo/socket]"
+msgstr "[fifo/socket]"
+
+msgid "[fifo]"
+msgstr "[fifo]"
+
+msgid "[socket]"
+msgstr "[socket]"
+
+msgid "[character special]"
+msgstr "[character special]"
+
+msgid "[CR missing]"
+msgstr "[manca CR]"
+
+msgid "[long lines split]"
+msgstr "[righe lunghe divise]"
+
+msgid "[NOT converted]"
+msgstr "[NON convertito]"
+
+msgid "[converted]"
+msgstr "[convertito]"
+
+msgid "[CONVERSION ERROR in line %ld]"
+msgstr "[ERRORE DI CONVERSIONE alla riga %ld]"
+
+msgid "[ILLEGAL BYTE in line %ld]"
+msgstr "[BYTE NON VALIDO alla riga %ld]"
+
+msgid "[READ ERRORS]"
+msgstr "[ERRORI IN LETTURA]"
+
+msgid "Can't find temp file for conversion"
+msgstr "Non riesco a trovare il file temp per leggerlo"
+
+msgid "Conversion with 'charconvert' failed"
+msgstr "Conversione fallita con 'charconvert'"
+
+msgid "can't read output of 'charconvert'"
+msgstr "non riesco a leggere il risultato di 'charconvert'"
+
+msgid "E676: No matching autocommands for acwrite buffer"
+msgstr "E676: Nessun autocomando corrispondente per buffer acwrite"
+
+msgid "E203: Autocommands deleted or unloaded buffer to be written"
+msgstr "E203: Buffer in scrittura cancellato o scaricato dagli autocomandi"
+
+msgid "E204: Autocommand changed number of lines in unexpected way"
+msgstr "E204: L'autocomando ha modificato numero righe in maniera imprevista"
+
+msgid "NetBeans disallows writes of unmodified buffers"
+msgstr "NetBeans non permette la scrittura di un buffer non modificato"
+
+msgid "Partial writes disallowed for NetBeans buffers"
+msgstr "Scrittura parziale disabilitata per i buffer di NetBeans"
+
+msgid "is not a file or writable device"
+msgstr "non è un file o un dispositivo su cui si possa scrivere"
+
+msgid "writing to device disabled with 'opendevice' option"
+msgstr "scrittura su periferica disabilitata con l'opzione 'opendevice'"
+
+msgid "is read-only (add ! to override)"
+msgstr "è in sola lettura (aggiungi ! per eseguire comunque)"
+
+msgid "E506: Can't write to backup file (add ! to override)"
+msgstr ""
+"E506: Non posso scrivere sul file di backup (aggiungi ! per eseguire "
+"comunque)"
+
+msgid "E507: Close error for backup file (add ! to override)"
+msgstr ""
+"E507: Errore in chiusura sul file di backup (aggiungi ! per eseguire "
+"comunque)"
+
+msgid "E508: Can't read file for backup (add ! to override)"
+msgstr ""
+"E508: Non riesco a leggere il file di backup (aggiungi ! per eseguire "
+"comunque)"
+
+msgid "E509: Cannot create backup file (add ! to override)"
+msgstr ""
+"E509: Non posso creare il file di backup (aggiungi ! per eseguire comunque)"
+
+msgid "E510: Can't make backup file (add ! to override)"
+msgstr ""
+"E510: Non posso fare il file di backup (aggiungi ! per eseguire comunque)"
+
+msgid "E214: Can't find temp file for writing"
+msgstr "E214: Non riesco a trovare un file 'temp' su cui scrivere"
+
+msgid "E213: Cannot convert (add ! to write without conversion)"
+msgstr ""
+"E213: Non riesco a convertire (aggiungi ! per scrivere senza conversione)"
+
+msgid "E166: Can't open linked file for writing"
+msgstr "E166: Non posso aprire il file collegato ('linked') in scrittura"
+
+msgid "E212: Can't open file for writing"
+msgstr "E212: Non posso aprire il file in scrittura"
+
+msgid "E949: File changed while writing"
+msgstr "E949: File modificato in fase di riscrittura"
+
+msgid "E512: Close failed"
+msgstr "E512: Chiusura fallita"
+
+msgid "E513: write error, conversion failed (make 'fenc' empty to override)"
+msgstr ""
+"E513: errore in scrittura, conversione fallita (rendere 'fenc' nullo per "
+"eseguire comunque)"
+
+msgid ""
+"E513: write error, conversion failed in line %ld (make 'fenc' empty to "
+"override)"
+msgstr ""
+"E513: errore in scrittura, conversione fallita alla riga %ld (rendere 'fenc' "
+"nullo per eseguire comunque)"
+
+msgid "E514: write error (file system full?)"
+msgstr "E514: errore in scrittura ('File System' pieno?)"
+
+msgid " CONVERSION ERROR"
+msgstr " ERRORE DI CONVERSIONE"
+
+msgid " in line %ld;"
+msgstr " alla riga %ld;"
+
+msgid "[Device]"
+msgstr "[Dispositivo]"
+
+msgid "[New]"
+msgstr "[Nuovo]"
+
+msgid " [a]"
+msgstr " [a]"
+
+msgid " appended"
+msgstr " aggiunto in fondo"
+
+msgid " [w]"
+msgstr " [s]"
+
+msgid " written"
+msgstr " scritti"
+
+msgid "E205: Patchmode: can't save original file"
+msgstr "E205: Patchmode: non posso salvare il file originale"
+
+msgid "E206: patchmode: can't touch empty original file"
+msgstr "E206: patchmode: non posso alterare il file vuoto originale"
+
+msgid "E207: Can't delete backup file"
+msgstr "E207: Non riesco a cancellare il file di backup"
+
+msgid ""
+"\n"
+"WARNING: Original file may be lost or damaged\n"
+msgstr ""
+"\n"
+"AVVISO: Il file originale può essere perso o danneggiato\n"
+
+msgid "don't quit the editor until the file is successfully written!"
+msgstr "non uscire dall'editor prima della fine della scrittura del file!"
+
+msgid "[dos]"
+msgstr "[DOS]"
+
+msgid "[dos format]"
+msgstr "[in formato DOS]"
+
+msgid "[mac]"
+msgstr "[Mac]"
+
+msgid "[mac format]"
+msgstr "[in formato Mac]"
+
+msgid "[unix]"
+msgstr "[Unix]"
+
+msgid "[unix format]"
+msgstr "[in formato Unix]"
+
+msgid "1 line, "
+msgstr "1 riga, "
+
+msgid "%ld lines, "
+msgstr "%ld righe,"
+
+msgid "1 character"
+msgstr "1 carattere"
+
+msgid "%lld characters"
+msgstr "%lld caratteri"
+
+msgid "[noeol]"
+msgstr "[noeol]"
+
+msgid "[Incomplete last line]"
+msgstr "[Manca carattere di fine riga]"
+
+msgid "WARNING: The file has been changed since reading it!!!"
+msgstr "AVVISO: File modificato dopo essere stato letto!!!"
+
+msgid "Do you really want to write to it"
+msgstr "Vuoi davvero riscriverlo"
+
+msgid "E208: Error writing to \"%s\""
+msgstr "E208: Errore in scrittura di \"%s\""
+
+msgid "E209: Error closing \"%s\""
+msgstr "E209: Errore in chiusura di \"%s\""
+
+msgid "E210: Error reading \"%s\""
+msgstr "E210: Errore in lettura di \"%s\""
+
+msgid "E246: FileChangedShell autocommand deleted buffer"
+msgstr "E246: L'autocomando 'FileChangedShell' ha cancellato il buffer"
+
+msgid "E211: File \"%s\" no longer available"
+msgstr "E211: Il file \"%s\" non esiste più"
+
+msgid ""
+"W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as "
+"well"
+msgstr ""
+"W12: Avviso: File \"%s\" modificato su disco ed anche nel buffer di Vim"
+
+msgid "See \":help W12\" for more info."
+msgstr "Vedere \":help W12\" per ulteriori informazioni."
+
+msgid "W11: Warning: File \"%s\" has changed since editing started"
+msgstr "W11: Avviso: File \"%s\" modificato dopo l'apertura"
+
+msgid "See \":help W11\" for more info."
+msgstr "Vedere \":help W11\" per ulteriori informazioni."
+
+msgid "W16: Warning: Mode of file \"%s\" has changed since editing started"
+msgstr "W16: Avviso: Modo File \"%s\" modificato dopo l'apertura"
+
+msgid "See \":help W16\" for more info."
+msgstr "Vedere \":help W16\" per ulteriori informazioni."
+
+msgid "W13: Warning: File \"%s\" has been created after editing started"
+msgstr "W13: Avviso: Il file \"%s\" risulta creato dopo l'apertura"
+
+msgid "Warning"
+msgstr "Avviso"
+
+msgid ""
+"&OK\n"
+"&Load File"
+msgstr ""
+"&OK\n"
+"&Carica File"
+
+msgid "E462: Could not prepare for reloading \"%s\""
+msgstr "E462: Non riesco a preparare per ri-caricare \"%s\""
+
+msgid "E321: Could not reload \"%s\""
+msgstr "E321: Non riesco a ri-caricare \"%s\""
+
+msgid "--Deleted--"
+msgstr "--Cancellato--"
+
+msgid "auto-removing autocommand: %s <buffer=%d>"
+msgstr "auto-rimozione dell'autocomando: %s <buffer=%d>"
+
+msgid "E367: No such group: \"%s\""
+msgstr "E367: Gruppo inesistente: \"%s\""
+
+msgid "E936: Cannot delete the current group"
+msgstr "E936: Non posso cancellare il gruppo corrente"
+
+msgid "W19: Deleting augroup that is still in use"
+msgstr "W19: Cancello augroup, ma è ancora in uso"
+
+msgid "E215: Illegal character after *: %s"
+msgstr "E215: Carattere non ammesso dopo *: %s"
+
+msgid "E216: No such event: %s"
+msgstr "E216: Evento inesistente: %s"
+
+msgid "E216: No such group or event: %s"
+msgstr "E216: Evento o gruppo inesistente: %s"
+
+msgid ""
+"\n"
+"--- Autocommands ---"
+msgstr ""
+"\n"
+"--- Autocomandi ---"
+
+msgid "E680: <buffer=%d>: invalid buffer number "
+msgstr "E680: <buffer=%d>: numero buffer non valido"
+
+msgid "E217: Can't execute autocommands for ALL events"
+msgstr "E217: Non posso eseguire autocomandi for TUTTI gli eventi"
+
+msgid "No matching autocommands"
+msgstr "Nessun autocomando corrispondente"
+
+msgid "E218: autocommand nesting too deep"
+msgstr "E218: nidificazione dell'autocomando troppo estesa"
+
+msgid "%s Autocommands for \"%s\""
+msgstr "%s Autocomandi per \"%s\""
+
+msgid "Executing %s"
+msgstr "Eseguo %s"
+
+msgid "autocommand %s"
+msgstr "autocomando %s"
+
+msgid "E219: Missing {."
+msgstr "E219: Manca {."
+
+msgid "E220: Missing }."
+msgstr "E220: Manca }."
+
+msgid "E490: No fold found"
+msgstr "E490: Non trovo alcuna piegatura"
+
+msgid "E350: Cannot create fold with current 'foldmethod'"
+msgstr "E350: Non posso creare piegatura con il 'foldmethod' in uso"
+
+msgid "E351: Cannot delete fold with current 'foldmethod'"
+msgstr "E351: Non posso cancellare piegatura con il 'foldmethod' in uso"
+
+msgid "+--%3ld line folded "
+msgid_plural "+--%3ld lines folded "
+msgstr[0] "+--%3ld riga piegata "
+msgstr[1] "+--%3ld righe piegate "
+
+msgid "E222: Add to read buffer"
+msgstr "E222: Aggiunto al buffer di lettura"
+
+msgid "E223: recursive mapping"
+msgstr "E223: mapping ricorsivo"
+
+msgid "E224: global abbreviation already exists for %s"
+msgstr "E224: una abbreviazione globale già esiste per %s"
+
+msgid "E225: global mapping already exists for %s"
+msgstr "E225: un mapping globale già esiste per %s"
+
+msgid "E226: abbreviation already exists for %s"
+msgstr "E226: una abbreviazione già esiste per %s"
+
+msgid "E227: mapping already exists for %s"
+msgstr "E227: un mapping già esiste per %s"
+
+msgid "No abbreviation found"
+msgstr "Non trovo l'abbreviazione"
+
+msgid "No mapping found"
+msgstr "Non trovo il mapping"
+
+msgid "E228: makemap: Illegal mode"
+msgstr "E228: makemap: modo non consentito"
+
+msgid "E851: Failed to create a new process for the GUI"
+msgstr "E851: Creazione di un nuovo processo fallita per la GUI"
+
+msgid "E852: The child process failed to start the GUI"
+msgstr "E852: Il processo figlio non è riuscito a far partire la GUI"
+
+msgid "E229: Cannot start the GUI"
+msgstr "E229: Non posso inizializzare la GUI"
+
+msgid "E230: Cannot read from \"%s\""
+msgstr "E230: Non posso leggere da \"%s\""
+
+msgid "E665: Cannot start GUI, no valid font found"
+msgstr "E665: Non posso inizializzare la GUI, nessun font valido trovato"
+
+msgid "E231: 'guifontwide' invalid"
+msgstr "E231: 'guifontwide' non valido"
+
+msgid "E599: Value of 'imactivatekey' is invalid"
+msgstr "E599: Il valore di 'imactivatekey' non è valido"
+
+msgid "E254: Cannot allocate color %s"
+msgstr "E254: Non riesco ad allocare il colore %s"
+
+msgid "No match at cursor, finding next"
+msgstr "Nessuna corrispondenza al cursore, cerco la prossima"
+
+msgid "<cannot open> "
+msgstr "<non posso aprire> "
+
+msgid "E616: vim_SelFile: can't get font %s"
+msgstr "E616: vim_SelFile: non riesco a trovare il font %s"
+
+msgid "E614: vim_SelFile: can't return to current directory"
+msgstr "E614: vim_SelFile: non posso tornare alla directory in uso"
+
+msgid "Pathname:"
+msgstr "Nome percorso:"
+
+msgid "E615: vim_SelFile: can't get current directory"
+msgstr "E615: vim_SelFile: non riesco ad ottenere la directory in uso"
+
+msgid "OK"
+msgstr "OK"
+
+msgid "Cancel"
+msgstr "Non eseguire"
+
+msgid "Scrollbar Widget: Could not get geometry of thumb pixmap."
+msgstr "Scrollbar Widget: Non riesco a ottenere geometria del 'thumb pixmap'."
+
+msgid "Vim dialog"
+msgstr "Dialogo Vim"
+
+msgid "E232: Cannot create BalloonEval with both message and callback"
+msgstr "E232: Non riesco a creare 'BalloonEval' con sia messaggio che callback"
+
+msgid "_Cancel"
+msgstr "_Annulla"
+
+msgid "_Save"
+msgstr "_Salva"
+
+msgid "_Open"
+msgstr "_Apri"
+
+msgid "_OK"
+msgstr "_OK"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"&Cancel"
+msgstr ""
+"&Y Sì\n"
+"&No\n"
+"&C Ignora"
+
+msgid "Yes"
+msgstr "Sì"
+
+msgid "No"
+msgstr "No"
+
+msgid "Input _Methods"
+msgstr "_Metodi di inserimento"
+
+msgid "VIM - Search and Replace..."
+msgstr "VIM - Sostituisci..."
+
+msgid "VIM - Search..."
+msgstr "VIM - Cerca..."
+
+msgid "Find what:"
+msgstr "Trova cosa:"
+
+msgid "Replace with:"
+msgstr "Sostituisci con:"
+
+msgid "Match whole word only"
+msgstr "Cerca solo la parola intera"
+
+msgid "Match case"
+msgstr "Maiuscole/minuscole"
+
+msgid "Direction"
+msgstr "Direzione"
+
+msgid "Up"
+msgstr "Su"
+
+msgid "Down"
+msgstr "Giù"
+
+msgid "Find Next"
+msgstr "Trova il Prossimo"
+
+msgid "Replace"
+msgstr "Sostituisci"
+
+msgid "Replace All"
+msgstr "Sostituisci Tutto"
+
+msgid "_Close"
+msgstr "_Chiudi"
+
+msgid "Vim: Received \"die\" request from session manager\n"
+msgstr "Vim: Ricevuta richiesta \"die\" dal session manager\n"
+
+msgid "Close tab"
+msgstr "Chiudi linguetta"
+
+msgid "New tab"
+msgstr "Nuova linguetta"
+
+msgid "Open Tab..."
+msgstr "Apri linguetta..."
+
+msgid "Vim: Main window unexpectedly destroyed\n"
+msgstr "Vim: Finestra principale distrutta inaspettatamente\n"
+
+msgid "&Filter"
+msgstr "&Filtro"
+
+msgid "&Cancel"
+msgstr "&C Non eseguire"
+
+msgid "Directories"
+msgstr "Directory"
+
+msgid "Filter"
+msgstr "Filtro"
+
+msgid "&Help"
+msgstr "&H Aiuto"
+
+msgid "Files"
+msgstr "File"
+
+msgid "&OK"
+msgstr "&OK"
+
+msgid "Selection"
+msgstr "Selezione"
+
+msgid "Find &Next"
+msgstr "&N Trova il Prossimo"
+
+msgid "&Replace"
+msgstr "&R Sostituisci"
+
+msgid "Replace &All"
+msgstr "&A Sostituisci Tutto"
+
+msgid "&Undo"
+msgstr "&U Disfa"
+
+msgid "Open tab..."
+msgstr "Apri linguetta..."
+
+msgid "Find string (use '\\\\' to find a '\\')"
+msgstr "Stringa di ricerca (usa '\\\\' per cercare un '\\')"
+
+msgid "Find & Replace (use '\\\\' to find a '\\')"
+msgstr "Sostituisci (usa '\\\\' per cercare un '\\')"
+
+msgid "Not Used"
+msgstr "Non Utilizzato"
+
+msgid "Directory\t*.nothing\n"
+msgstr "Directory\t*.nothing\n"
+
+msgid "E671: Cannot find window title \"%s\""
+msgstr "E671: Non trovo il titolo della finestra \"%s\""
+
+msgid "E243: Argument not supported: \"-%s\"; Use the OLE version."
+msgstr "E243: Argomento non supportato: \"-%s\"; Usa la versione OLE."
+
+msgid "E672: Unable to open window inside MDI application"
+msgstr "E672: Non posso aprire la finestra in un'applicazione MDI"
+
+msgid "Vim E458: Cannot allocate colormap entry, some colors may be incorrect"
+msgstr ""
+"Vim E458: Non riesco ad allocare elemento di colormap, possibili colori "
+"errati"
+
+msgid "E250: Fonts for the following charsets are missing in fontset %s:"
+msgstr "E250: Mancano descrizioni per i seguenti caratteri nel font: %s"
+
+msgid "E252: Fontset name: %s"
+msgstr "E252: Nome fontset: %s"
+
+msgid "Font '%s' is not fixed-width"
+msgstr "Il font '%s' non di larghezza fissa"
+
+msgid "E253: Fontset name: %s"
+msgstr "E253: Nome fontset: %s"
+
+msgid "Font0: %s"
+msgstr "Font0: %s"
+
+msgid "Font1: %s"
+msgstr "Font1: %s"
+
+msgid "Font%ld width is not twice that of font0"
+msgstr "La larghezza di font%ld non è doppia di quella di font0"
+
+msgid "Font0 width: %ld"
+msgstr "Larghezza di Font0: %ld"
+
+msgid "Font1 width: %ld"
+msgstr "Larghezza di Font1: %ld"
+
+msgid "Invalid font specification"
+msgstr "Specifica di font non valida"
+
+msgid "&Dismiss"
+msgstr "&D Non ora"
+
+msgid "no specific match"
+msgstr "nessuna corrispondenza specifica"
+
+msgid "Vim - Font Selector"
+msgstr "Vim - Selettore Font"
+
+msgid "Name:"
+msgstr "Nome:"
+
+msgid "Show size in Points"
+msgstr "Mostra dimensione in Punti"
+
+msgid "Encoding:"
+msgstr "Codifica:"
+
+msgid "Font:"
+msgstr "Font:"
+
+msgid "Style:"
+msgstr "Stile:"
+
+msgid "Size:"
+msgstr "Dimensione:"
+
+msgid "E256: Hangul automata ERROR"
+msgstr "E256: ERRORE processore Hangul"
+
+msgid "E550: Missing colon"
+msgstr "E550: Manca ':'"
+
+msgid "E551: Illegal component"
+msgstr "E551: Componente non valido"
+
+msgid "E552: digit expected"
+msgstr "E552: aspettavo un numero"
+
+msgid "Page %d"
+msgstr "Pagina %d"
+
+msgid "No text to be printed"
+msgstr "Manca testo da stampare"
+
+msgid "Printing page %d (%d%%)"
+msgstr "Sto stampando pagina %d (%d%%)"
+
+msgid " Copy %d of %d"
+msgstr " Copia %d di %d"
+
+msgid "Printed: %s"
+msgstr "Stampato: %s"
+
+msgid "Printing aborted"
+msgstr "Stampa non completata"
+
+msgid "E455: Error writing to PostScript output file"
+msgstr "E455: Errore in scrittura a file PostScript di output"
+
+msgid "E624: Can't open file \"%s\""
+msgstr "E624: Non riesco ad aprire il file \"%s\""
+
+msgid "E457: Can't read PostScript resource file \"%s\""
+msgstr "E457: Non riesco a leggere file risorse PostScript \"%s\""
+
+msgid "E618: file \"%s\" is not a PostScript resource file"
+msgstr "E618: file \"%s\" non è un file di risorse PostScript"
+
+msgid "E619: file \"%s\" is not a supported PostScript resource file"
+msgstr "E619: file \"%s\" non è un file di risorse PostScript supportato"
+
+msgid "E621: \"%s\" resource file has wrong version"
+msgstr "E621: il file di risorse \"%s\" ha una versione sbagliata"
+
+msgid "E673: Incompatible multi-byte encoding and character set."
+msgstr "E673: Codifica e set di caratteri multi-byte non compatibili."
+
+msgid "E674: printmbcharset cannot be empty with multi-byte encoding."
+msgstr "E674: printmbcharset non può essere nullo con codifica multi-byte."
+
+msgid "E675: No default font specified for multi-byte printing."
+msgstr "E675: Font predefinito non specificato per stampa multi-byte."
+
+msgid "E324: Can't open PostScript output file"
+msgstr "E324: Non riesco ad aprire file PostScript di output"
+
+msgid "E456: Can't open file \"%s\""
+msgstr "E456: Non riesco ad aprire il file \"%s\""
+
+msgid "E456: Can't find PostScript resource file \"prolog.ps\""
+msgstr "E456: Non trovo file risorse PostScript \"prolog.ps\""
+
+msgid "E456: Can't find PostScript resource file \"cidfont.ps\""
+msgstr "E456: Non trovo file risorse PostScript \"cidfont.ps\""
+
+msgid "E456: Can't find PostScript resource file \"%s.ps\""
+msgstr "E456: Non trovo file risorse PostScript \"%s.ps\""
+
+msgid "E620: Unable to convert to print encoding \"%s\""
+msgstr "E620: Impossibile convertire a codifica di stampa \"%s\""
+
+msgid "Sending to printer..."
+msgstr "Invio a stampante..."
+
+msgid "E365: Failed to print PostScript file"
+msgstr "E365: Non riesco ad aprire file PostScript"
+
+msgid "Print job sent."
+msgstr "Richiesta di stampa inviata."
+
+msgid "Add a new database"
+msgstr "Aggiungi un nuovo database"
+
+msgid "Query for a pattern"
+msgstr "Cerca un modello"
+
+msgid "Show this message"
+msgstr "Visualizza questo messaggio"
+
+msgid "Kill a connection"
+msgstr "Termina una connessione"
+
+msgid "Reinit all connections"
+msgstr "Reinizializza tutte le connessioni"
+
+msgid "Show connections"
+msgstr "Visualizza connessioni"
+
+msgid "E560: Usage: cs[cope] %s"
+msgstr "E560: Uso: cs[cope] %s"
+
+msgid "This cscope command does not support splitting the window.\n"
+msgstr "Questo comando cscope non gestisce la divisione delle schermo.\n"
+
+msgid "E562: Usage: cstag <ident>"
+msgstr "E562: Uso: cstag <ident>"
+
+msgid "E257: cstag: tag not found"
+msgstr "E257: cstag: tag non trovato"
+
+msgid "E563: stat(%s) error: %d"
+msgstr "E563: errore stat(%s): %d"
+
+msgid "E563: stat error"
+msgstr "E563: errore stat"
+
+msgid "E564: %s is not a directory or a valid cscope database"
+msgstr "E564: %s non è una directory o un database cscope valido"
+
+msgid "Added cscope database %s"
+msgstr "Aggiunto database cscope %s"
+
+msgid "E262: error reading cscope connection %ld"
+msgstr "E262: errore leggendo connessione cscope %ld"
+
+msgid "E561: unknown cscope search type"
+msgstr "E561: tipo di ricerca cscope sconosciuta"
+
+msgid "E566: Could not create cscope pipes"
+msgstr "E566: Non riesco a creare pipes cscope"
+
+msgid "E622: Could not fork for cscope"
+msgstr "E622: Non riesco a fare fork per cscope"
+
+msgid "cs_create_connection setpgid failed"
+msgstr "cs_create_connection setpgid fallita"
+
+msgid "cs_create_connection exec failed"
+msgstr "cs_create_connection exec fallita"
+
+msgid "cs_create_connection: fdopen for to_fp failed"
+msgstr "cs_create_connection: fdopen di to_fp fallita"
+
+msgid "cs_create_connection: fdopen for fr_fp failed"
+msgstr "cs_create_connection: fdopen di fr_fp fallita"
+
+msgid "E623: Could not spawn cscope process"
+msgstr "E623: Non riesco a generare processo cscope"
+
+msgid "E567: no cscope connections"
+msgstr "E567: nessuna connessione cscope"
+
+msgid "E469: invalid cscopequickfix flag %c for %c"
+msgstr "E469: flag cscopequickfix %c non valido per %c"
+
+msgid "E259: no matches found for cscope query %s of %s"
+msgstr "E259: nessuna corrispondenza trovata per la richiesta cscope %s di %s"
+
+msgid "cscope commands:\n"
+msgstr "comandi cscope:\n"
+
+msgid "%-5s: %s%*s (Usage: %s)"
+msgstr "%-5s: %s%*s (Uso: %s)"
+
+msgid ""
+"\n"
+" a: Find assignments to this symbol\n"
+" c: Find functions calling this function\n"
+" d: Find functions called by this function\n"
+" e: Find this egrep pattern\n"
+" f: Find this file\n"
+" g: Find this definition\n"
+" i: Find files #including this file\n"
+" s: Find this C symbol\n"
+" t: Find this text string\n"
+msgstr ""
+"\n"
+" a: Trova assegnazioni a questo simbolo\n"
+" c: Trova funzioni che chiamano questa\n"
+" d: Trova funzioni chiamate da questa\n"
+" e: Trova questa espressione egrep\n"
+" f: Trova questo file\n"
+" g: Trova questa definizione\n"
+" i: Trova file che #includono questo file\n"
+" s: Trova questo simbolo C\n"
+" t: Trova questa stringa di testo\n"
+
+msgid "E625: cannot open cscope database: %s"
+msgstr "E625: impossibile aprire database cscope: %s"
+
+msgid "E626: cannot get cscope database information"
+msgstr "E626: impossibile leggere informazioni sul database cscope"
+
+msgid "E568: duplicate cscope database not added"
+msgstr "E568: database cscope duplicato, non aggiunto"
+
+msgid "E261: cscope connection %s not found"
+msgstr "E261: connessione cscope %s non trovata"
+
+msgid "cscope connection %s closed"
+msgstr "connessione cscope %s chiusa"
+
+msgid "E570: fatal error in cs_manage_matches"
+msgstr "E570: errore irreparabile in cs_manage_matches"
+
+msgid "Cscope tag: %s"
+msgstr "Tag cscope: %s"
+
+msgid ""
+"\n"
+" # line"
+msgstr ""
+"\n"
+" # riga"
+
+msgid "filename / context / line\n"
+msgstr "nomefile / contest / riga\n"
+
+msgid "E609: Cscope error: %s"
+msgstr "E609: Errore cscope: %s"
+
+msgid "All cscope databases reset"
+msgstr "Tutti i database cscope annullati"
+
+msgid "no cscope connections\n"
+msgstr "nessuna connessione cscope\n"
+
+msgid " # pid database name prepend path\n"
+msgstr " # pid database nome prepend path\n"
+
+msgid "Lua library cannot be loaded."
+msgstr "Non riesco a caricare libreria Lua."
+
+msgid "cannot save undo information"
+msgstr "non riesco a salvare informazioni per 'undo'"
+
+msgid ""
+"E815: Sorry, this command is disabled, the MzScheme libraries could not be "
+"loaded."
+msgstr ""
+"E815: Spiacente, comando non disponibile, non riesco a caricare librerie "
+"programmi MzScheme."
+
+msgid ""
+"E895: Sorry, this command is disabled, the MzScheme's racket/base module "
+"could not be loaded."
+msgstr ""
+"E815: Spiacente, comando non disponibile, non riesco a caricare modulo "
+"racket/base di MzScheme."
+
+msgid "invalid expression"
+msgstr "espressione non valida"
+
+msgid "expressions disabled at compile time"
+msgstr "espressioni disabilitate in compilazione"
+
+msgid "hidden option"
+msgstr "opzione nascosta"
+
+msgid "unknown option"
+msgstr "opzione inesistente"
+
+msgid "window index is out of range"
+msgstr "indice della finestra non nell'intervallo"
+
+msgid "couldn't open buffer"
+msgstr "non sono riuscito ad aprire il buffer"
+
+msgid "cannot delete line"
+msgstr "non posso cancellare la riga"
+
+msgid "cannot replace line"
+msgstr "non posso sostituire la riga"
+
+msgid "cannot insert line"
+msgstr "non posso inserire la riga"
+
+msgid "string cannot contain newlines"
+msgstr "la stringa non può contenere caratteri 'A CAPO'"
+
+msgid "error converting Scheme values to Vim"
+msgstr "errore nel convertire i valori Scheme a Vim"
+
+msgid "Vim error: ~a"
+msgstr "Errore Vim: ~a"
+
+msgid "Vim error"
+msgstr "Errore Vim"
+
+msgid "buffer is invalid"
+msgstr "buffer non valido"
+
+msgid "window is invalid"
+msgstr "finestra non valida"
+
+msgid "linenr out of range"
+msgstr "numero riga non nell'intervallo"
+
+msgid "not allowed in the Vim sandbox"
+msgstr "non ammesso in ambiente protetto"
+
+msgid "E836: This Vim cannot execute :python after using :py3"
+msgstr "E836: Python: Impossibile usare :py e :py3 nella stessa sessione"
+
+msgid ""
+"E263: Sorry, this command is disabled, the Python library could not be "
+"loaded."
+msgstr ""
+"E263: Spiacente, comando non disponibile, non riesco a caricare libreria "
+"programmi Python."
+
+msgid ""
+"E887: Sorry, this command is disabled, the Python's site module could not be "
+"loaded."
+msgstr ""
+"E887: Spiacente, comando non disponibile, non riesco a caricare il modulo "
+"Python locale."
+
+msgid "E659: Cannot invoke Python recursively"
+msgstr "E659: Python non può essere chiamato ricorsivamente"
+
+msgid "E837: This Vim cannot execute :py3 after using :python"
+msgstr "E837: Impossibile usare ora :py3 dopo aver usato :python"
+
+msgid "E265: $_ must be an instance of String"
+msgstr "E265: $_ deve essere un'istanza di String"
+
+msgid ""
+"E266: Sorry, this command is disabled, the Ruby library could not be loaded."
+msgstr ""
+"E266: Spiacente, comando non disponibile, non riesco a caricare libreria "
+"programmi Ruby."
+
+msgid "E267: unexpected return"
+msgstr "E267: return imprevisto"
+
+msgid "E268: unexpected next"
+msgstr "E268: next imprevisto"
+
+msgid "E269: unexpected break"
+msgstr "E269: break imprevisto"
+
+msgid "E270: unexpected redo"
+msgstr "E270: redo imprevisto"
+
+msgid "E271: retry outside of rescue clause"
+msgstr "E271: retry fuori da clausola rescue"
+
+msgid "E272: unhandled exception"
+msgstr "E272: eccezione non gestita"
+
+msgid "E273: unknown longjmp status %d"
+msgstr "E273: tipo sconosciuto di salto nel programma %d"
+
+msgid "invalid buffer number"
+msgstr "numero buffer non valido"
+
+msgid "not implemented yet"
+msgstr "non ancora implementato"
+
+msgid "cannot set line(s)"
+msgstr "non posso impostare riga(he)"
+
+msgid "invalid mark name"
+msgstr "nome di mark non valido"
+
+msgid "mark not set"
+msgstr "mark non impostato"
+
+msgid "row %d column %d"
+msgstr "riga %d colonna %d"
+
+msgid "cannot insert/append line"
+msgstr "non riesco a inserire/aggiungere riga"
+
+msgid "line number out of range"
+msgstr "numero riga non nell'intervallo"
+
+msgid "unknown flag: "
+msgstr "opzione inesistente: "
+
+msgid "unknown vimOption"
+msgstr "'vimOption' inesistente"
+
+msgid "keyboard interrupt"
+msgstr "interruzione dalla tastiera"
+
+msgid "vim error"
+msgstr "errore vim"
+
+msgid "cannot create buffer/window command: object is being deleted"
+msgstr ""
+"non riesco a creare comando buffer/finestra: oggetto in via di cancellazione"
+
+msgid ""
+"cannot register callback command: buffer/window is already being deleted"
+msgstr ""
+"non posso registrare comando callback: buffer/finestra già in cancellazione"
+
+msgid ""
+"E280: TCL FATAL ERROR: reflist corrupt!? Please report this to vim-dev@vim."
+"org"
+msgstr ""
+"E280: ERRORE FATALE TCL: reflist corrotta!? Si prega notificare a vim-"
+"dev@vim.org"
+
+msgid "cannot register callback command: buffer/window reference not found"
+msgstr ""
+"non posso registrare comando callback: riferimento a buffer/finestra "
+"inesistente"
+
+msgid ""
+"E571: Sorry, this command is disabled: the Tcl library could not be loaded."
+msgstr ""
+"E571: Spiacente, comando non disponibile, non riesco a caricare libreria "
+"programmi Tcl."
+
+msgid "E572: exit code %d"
+msgstr "E572: codice di uscita %d"
+
+msgid "cannot get line"
+msgstr "non riesco a ottenere la riga"
+
+msgid "Unable to register a command server name"
+msgstr "Non riesco a registrare un nome di server comando"
+
+msgid "E248: Failed to send command to the destination program"
+msgstr "E248: Fallito invio comando a programma destinatario"
+
+msgid "E573: Invalid server id used: %s"
+msgstr "E573: Identificativo di server non valido: %s"
+
+msgid "E251: VIM instance registry property is badly formed. Deleted!"
+msgstr "E251: Proprietà registry relative a VIM non adeguate. Cancellate!"
+
+msgid "E938: Duplicate key in JSON: \"%s\""
+msgstr "E938: Chiave duplicata in JSON: \"%s\""
+
+msgid "E696: Missing comma in List: %s"
+msgstr "E696: Manca virgola nella Lista: %s"
+
+msgid "E697: Missing end of List ']': %s"
+msgstr "E697: Manca ']' a fine Lista: %s"
+
+msgid "Unknown option argument"
+msgstr "Argomento di opzione sconosciuto"
+
+msgid "Too many edit arguments"
+msgstr "Troppi argomenti di edit"
+
+msgid "Argument missing after"
+msgstr "Argomento mancante dopo"
+
+msgid "Garbage after option argument"
+msgstr "Spazzatura dopo argomento di opzione"
+
+msgid "Too many \"+command\", \"-c command\" or \"--cmd command\" arguments"
+msgstr "Troppi argomenti \"+command\", \"-c command\" o \"--cmd command\""
+
+msgid "Invalid argument for"
+msgstr "Argomento non valido per"
+
+msgid "%d files to edit\n"
+msgstr "%d file da elaborare\n"
+
+msgid "netbeans is not supported with this GUI\n"
+msgstr "netbeans non è supportato con questa GUI\n"
+
+msgid "'-nb' cannot be used: not enabled at compile time\n"
+msgstr "'-nb' non disponibile: non abilitato in compilazione\n"
+
+msgid "This Vim was not compiled with the diff feature."
+msgstr "Vim non compilato con funzionalità 'diff'."
+
+msgid "Attempt to open script file again: \""
+msgstr "Tento di riaprire lo script file: \""
+
+msgid "Cannot open for reading: \""
+msgstr "Non posso aprire in lettura: \""
+
+msgid "Cannot open for script output: \""
+msgstr "Non posso aprire come script output: \""
+
+msgid "Vim: Error: Failure to start gvim from NetBeans\n"
+msgstr "Vim: Errore: Avvio di gvim da NetBeans non riuscito\n"
+
+msgid "Vim: Error: This version of Vim does not run in a Cygwin terminal\n"
+msgstr ""
+"Vim: Errore: Questa versione di Vim non funziona in un terminale Cygwin\n"
+
+msgid "Vim: Warning: Output is not to a terminal\n"
+msgstr "Vim: Avviso: Output non diretto a un terminale\n"
+
+msgid "Vim: Warning: Input is not from a terminal\n"
+msgstr "Vim: Avviso: Input non proveniente da un terminale\n"
+
+msgid "pre-vimrc command line"
+msgstr "riga comandi prima di vimrc"
+
+msgid "E282: Cannot read from \"%s\""
+msgstr "E282: Non posso leggere da \"%s\""
+
+msgid ""
+"\n"
+"More info with: \"vim -h\"\n"
+msgstr ""
+"\n"
+"Maggiori informazioni con: \"vim -h\"\n"
+
+msgid "[file ..] edit specified file(s)"
+msgstr "[file ..] apri file(s) specificati"
+
+msgid "- read text from stdin"
+msgstr "- leggi testo da 'stdin'"
+
+msgid "-t tag edit file where tag is defined"
+msgstr "-t tag apri file in cui è definito il tag"
+
+msgid "-q [errorfile] edit file with first error"
+msgstr "-q [errorfile] apri file col primo errore"
+
+msgid ""
+"\n"
+"\n"
+"Usage:"
+msgstr ""
+"\n"
+"\n"
+" Uso:"
+
+msgid " vim [arguments] "
+msgstr " vim [argomenti] "
+
+msgid ""
+"\n"
+" or:"
+msgstr ""
+"\n"
+" o:"
+
+msgid ""
+"\n"
+"Where case is ignored prepend / to make flag upper case"
+msgstr ""
+"\n"
+"Quando si ignorano maiusc./minusc. preporre / per rendere il flag maiusc."
+
+msgid ""
+"\n"
+"\n"
+"Arguments:\n"
+msgstr ""
+"\n"
+"\n"
+"Argomenti:\n"
+
+msgid "--\t\t\tOnly file names after this"
+msgstr "--\t\t\tSolo nomi file da qui in poi"
+
+msgid "--literal\t\tDon't expand wildcards"
+msgstr "--literal\t\tNon espandere wildcard"
+
+msgid "-register\t\tRegister this gvim for OLE"
+msgstr "-register\t\tRegistra questo gvim a OLE"
+
+msgid "-unregister\t\tUnregister gvim for OLE"
+msgstr "-unregister\t\tDeregistra gvim a OLE"
+
+msgid "-g\t\t\tRun using GUI (like \"gvim\")"
+msgstr "-g\t\t\tEsegui usando GUI (come \"gvim\")"
+
+msgid "-f or --nofork\tForeground: Don't fork when starting GUI"
+msgstr "-f opp. --nofork\tForeground: Non usare 'fork' inizializzando GUI"
+
+msgid "-v\t\t\tVi mode (like \"vi\")"
+msgstr "-v\t\t\tModalità Vi (come \"vi\")"
+
+msgid "-e\t\t\tEx mode (like \"ex\")"
+msgstr "-e\t\t\tModalità Ex (come \"ex\")"
+
+msgid "-E\t\t\tImproved Ex mode"
+msgstr "-E\t\t\tModalità Ex migliorata"
+
+msgid "-s\t\t\tSilent (batch) mode (only for \"ex\")"
+msgstr "-s\t\t\tModalità Silenziosa (batch) (solo per \"ex\")"
+
+msgid "-d\t\t\tDiff mode (like \"vimdiff\")"
+msgstr "-d\t\t\tModalità Diff (come \"vimdiff\")"
+
+msgid "-y\t\t\tEasy mode (like \"evim\", modeless)"
+msgstr "-y\t\t\tModalità Facile (come \"evim\", senza modalità)"
+
+msgid "-R\t\t\tReadonly mode (like \"view\")"
+msgstr "-R\t\t\tModalità Sola Lettura (come \"view\")"
+
+msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
+msgstr "-Z\t\t\tModalità Ristretta (come \"rvim\")"
+
+msgid "-m\t\t\tModifications (writing files) not allowed"
+msgstr "-m\t\t\tRiscritture del file non permesse"
+
+msgid "-M\t\t\tModifications in text not allowed"
+msgstr "-M\t\t\tModifiche nel file non permesse"
+
+msgid "-b\t\t\tBinary mode"
+msgstr "-b\t\t\tModalità Binaria"
+
+msgid "-l\t\t\tLisp mode"
+msgstr "-l\t\t\tModalità Lisp"
+
+msgid "-C\t\t\tCompatible with Vi: 'compatible'"
+msgstr "-C\t\t\tCompatibile con Vi: 'compatible'"
+
+msgid "-N\t\t\tNot fully Vi compatible: 'nocompatible'"
+msgstr "-N\t\t\tNon interamente compatibile con Vi: 'nocompatible'"
+
+msgid "-V[N][fname]\t\tBe verbose [level N] [log messages to fname]"
+msgstr "-V[N][fname]\t\tVerbosità [livello N] [log su file fname]"
+
+msgid "-D\t\t\tDebugging mode"
+msgstr "-D\t\t\tModalità Debug"
+
+msgid "-n\t\t\tNo swap file, use memory only"
+msgstr "-n\t\t\tNiente file di swap, usa solo memoria"
+
+msgid "-r\t\t\tList swap files and exit"
+msgstr "-r\t\t\tLista swap file ed esci"
+
+msgid "-r (with file name)\tRecover crashed session"
+msgstr "-r (e nome file)\tRecupera da sessione finita male"
+
+msgid "-L\t\t\tSame as -r"
+msgstr "-L\t\t\tCome -r"
+
+msgid "-f\t\t\tDon't use newcli to open window"
+msgstr "-f\t\t\tNon usare newcli per aprire finestra"
+
+msgid "-dev <device>\t\tUse <device> for I/O"
+msgstr "-dev <dispositivo>\t\tUsa <dispositivo> per I/O"
+
+msgid "-A\t\t\tStart in Arabic mode"
+msgstr "-A\t\t\tComincia in modalità Araba"
+
+msgid "-H\t\t\tStart in Hebrew mode"
+msgstr "-H\t\t\tComincia in modalità Ebraica"
+
+msgid "-F\t\t\tStart in Farsi mode"
+msgstr "-F\t\t\tComincia in modalità Farsi (Persiano)"
+
+msgid "-T <terminal>\tSet terminal type to <terminal>"
+msgstr "-T <terminale>\tImposta tipo terminale a <terminale>"
+
+msgid "--not-a-term\t\tSkip warning for input/output not being a terminal"
+msgstr "--not-a-term\t\tNon avvisare se input/output non da terminale"
+
+msgid "--ttyfail\t\tExit if input or output is not a terminal"
+msgstr "--ttyfail\t\tEsce se l'input o l'output non sono da un terminale"
+
+msgid "-u <vimrc>\t\tUse <vimrc> instead of any .vimrc"
+msgstr "-u <vimrc>\t\tUsa <vimrc> invece di qualche .vimrc"
+
+msgid "-U <gvimrc>\t\tUse <gvimrc> instead of any .gvimrc"
+msgstr "-U <gvimrc>\t\tUsa <gvimrc> invece di qualche .gvimrc"
+
+msgid "--noplugin\t\tDon't load plugin scripts"
+msgstr "--noplugin\t\tNon caricare script plugin"
+
+msgid "-p[N]\t\tOpen N tab pages (default: one for each file)"
+msgstr "-o[N]\t\tApri N linguette (predefinito: una per ogni file)"
+
+msgid "-o[N]\t\tOpen N windows (default: one for each file)"
+msgstr "-o[N]\t\tApri N finestre (predefinito: una per ogni file)"
+
+msgid "-O[N]\t\tLike -o but split vertically"
+msgstr "-O[N]\t\tCome -o ma dividi le finestre in verticale"
+
+msgid "+\t\t\tStart at end of file"
+msgstr "+\t\t\tPosizionati alla fine del file"
+
+msgid "+<lnum>\t\tStart at line <lnum>"
+msgstr "+<lnum>\t\tPosizionati alla riga <lnum>"
+
+msgid "--cmd <command>\tExecute <command> before loading any vimrc file"
+msgstr ""
+"--cmd <comando>\t\tEsegui <comando> prima di caricare eventuali file vimrc"
+
+msgid "-c <command>\t\tExecute <command> after loading the first file"
+msgstr "-c <comando>\t\tEsegui <comando> dopo caricamento primo file"
+
+msgid "-S <session>\t\tSource file <session> after loading the first file"
+msgstr ""
+"-S <sessione>\tEsegui comandi in file <sessione> dopo caricamento primo file"
+
+msgid "-s <scriptin>\tRead Normal mode commands from file <scriptin>"
+msgstr "-s <scriptin>\tLeggi comandi in modalità normale da file <scriptin>"
+
+msgid "-w <scriptout>\tAppend all typed commands to file <scriptout>"
+msgstr "-w <scriptout>\tAggiungi tutti i comandi immessi a file <scriptout>"
+
+msgid "-W <scriptout>\tWrite all typed commands to file <scriptout>"
+msgstr "-W <scriptout>\tScrivi tutti i comandi immessi in file <scriptout>"
+
+msgid "-x\t\t\tEdit encrypted files"
+msgstr "-x\t\t\tApri un file cifrato"
+
+msgid "-display <display>\tConnect vim to this particular X-server"
+msgstr "-display <schermo>\tEsegui vim a questo particolare server X"
+
+msgid "-X\t\t\tDo not connect to X server"
+msgstr "-X\t\t\tNon connetterti a server X"
+
+msgid "--remote <files>\tEdit <files> in a Vim server if possible"
+msgstr "--remote <file>\tApri <file> in un server Vim se possibile"
+
+msgid "--remote-silent <files> Same, don't complain if there is no server"
+msgstr "--remote-silent <file> Stessa cosa, ignora se non esiste un server"
+
+msgid ""
+"--remote-wait <files> As --remote but wait for files to have been edited"
+msgstr ""
+"--remote-wait <file> Come --remote ma aspetta che i file siano elaborati"
+
+msgid ""
+"--remote-wait-silent <files> Same, don't complain if there is no server"
+msgstr ""
+"--remote-wait-silent <file> Stessa cosa, ignora se non esiste un server"
+
+msgid ""
+"--remote-tab[-wait][-silent] <files> As --remote but use tab page per file"
+msgstr ""
+"--remote-tab[-wait][-silent] <file> Come --remote ma apre una linguetta per "
+"file"
+
+msgid "--remote-send <keys>\tSend <keys> to a Vim server and exit"
+msgstr "--remote-send <tasti>\tInvia <tasti> a un server Vim ed esci"
+
+msgid "--remote-expr <expr>\tEvaluate <expr> in a Vim server and print result"
+msgstr ""
+"--remote--expr <expr>\tEsegui <expr> in un server Vim e stampa risultato"
+
+msgid "--serverlist\t\tList available Vim server names and exit"
+msgstr "--serverlist\t\tLista nomi server Vim disponibili ed esci"
+
+msgid "--servername <name>\tSend to/become the Vim server <name>"
+msgstr "--servername <nome>\tInvia a/diventa server Vim di nome <nome>"
+
+msgid "--startuptime <file>\tWrite startup timing messages to <file>"
+msgstr ""
+"--startuptime <file>\tScrivi tutti i messaggi iniziali di timing in <file>"
+
+msgid "-i <viminfo>\t\tUse <viminfo> instead of .viminfo"
+msgstr "-i <viminfo>\t\tUsa <viminfo> invece di .viminfo"
+
+msgid "--clean\t\t'nocompatible', Vim defaults, no plugins, no viminfo"
+msgstr "--clean\t\t'nocompatible', default di Vim, no plugin, no viminfo"
+
+msgid "-h or --help\tPrint Help (this message) and exit"
+msgstr "-h opp. --help\tStampa Aiuto (questo messaggio) ed esci"
+
+msgid "--version\t\tPrint version information and exit"
+msgstr "--version\t\tStampa informazioni sulla versione ed esci"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Motif version):\n"
+msgstr ""
+"\n"
+"Opzioni accettate da gvim (versione Motif):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (neXtaw version):\n"
+msgstr ""
+"\n"
+"Opzioni accettate da gvim (versione neXtaw):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Athena version):\n"
+msgstr ""
+"\n"
+"Opzioni accettate da gvim (versione Athena):\n"
+
+msgid "-display <display>\tRun vim on <display>"
+msgstr "-display <schermo>\tEsegui vim su <schermo>"
+
+msgid "-iconic\t\tStart vim iconified"
+msgstr "-iconic\t\tInizia vim riducendolo ad icona"
+
+msgid "-background <color>\tUse <color> for the background (also: -bg)"
+msgstr "-background <colore>\tUsa <colore> come sfondo (anche: -bg)"
+
+msgid "-foreground <color>\tUse <color> for normal text (also: -fg)"
+msgstr "-foreground <colore>\tUsa <colore> per il testo normale (anche: -fg)"
+
+msgid "-font <font>\t\tUse <font> for normal text (also: -fn)"
+msgstr "-font <font>\t\tUsa <font> for il testo normale (anche: -fn)"
+
+msgid "-boldfont <font>\tUse <font> for bold text"
+msgstr "-boldfont <font>\tUsa <font> per testo in grassetto"
+
+msgid "-italicfont <font>\tUse <font> for italic text"
+msgstr "-italicfont <font>\tUsa <font> per testo in corsivo"
+
+msgid "-geometry <geom>\tUse <geom> for initial geometry (also: -geom)"
+msgstr "-geometry <geom>\tUsa <geom> per la geometria iniziale (anche: -geom)"
+
+msgid "-borderwidth <width>\tUse a border width of <width> (also: -bw)"
+msgstr "-borderwidth <larg>\tUsa larghezza <larg> per bordo (anche: -bw)"
+
+msgid "-scrollbarwidth <width> Use a scrollbar width of <width> (also: -sw)"
+msgstr ""
+"-scrollbarwidth <larg> Usa larghezza <larg> per scrollbar (anche: -sw)"
+
+msgid "-menuheight <height>\tUse a menu bar height of <height> (also: -mh)"
+msgstr "-menuheight <alt>\tUsa altezza <alt> per barra menu (anche: -mh)"
+
+msgid "-reverse\t\tUse reverse video (also: -rv)"
+msgstr "-reverse\t\tUsa colori invertiti (anche: -rv)"
+
+msgid "+reverse\t\tDon't use reverse video (also: +rv)"
+msgstr "+reverse\t\tNon usare colori invertiti (anche: +rv)"
+
+msgid "-xrm <resource>\tSet the specified resource"
+msgstr "-xrm <risorsa>\tImposta la risorsa specificata"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (GTK+ version):\n"
+msgstr ""
+"\n"
+"Argomenti accettati da gvim (versione GTK+):\n"
+
+msgid "-display <display>\tRun vim on <display> (also: --display)"
+msgstr "-display <schermo>\tEsegui vim su <schermo> (anche: --display)"
+
+msgid "--role <role>\tSet a unique role to identify the main window"
+msgstr ""
+"--role <ruolo>\tImposta un ruolo univoco per identificare la finestra "
+"principale"
+
+msgid "--socketid <xid>\tOpen Vim inside another GTK widget"
+msgstr "--socketid <xid>\tApri Vim dentro un altro widget GTK"
+
+msgid "--echo-wid\t\tMake gvim echo the Window ID on stdout"
+msgstr "--echo-wid\t\tStampa il Window ID su stdout"
+
+msgid "-P <parent title>\tOpen Vim inside parent application"
+msgstr "-P <titolo padre>\tApri Vim in un'applicazione padre"
+
+msgid "--windowid <HWND>\tOpen Vim inside another win32 widget"
+msgstr "--windowid <HWND>\tApri Vim dentro un altro widget win32"
+
+msgid "No display"
+msgstr "Manca display"
+
+msgid ": Send failed.\n"
+msgstr ": Invio fallito.\n"
+
+msgid ": Send failed. Trying to execute locally\n"
+msgstr ": Invio fallito. Tento di eseguire localmente\n"
+
+msgid "%d of %d edited"
+msgstr "%d di %d elaborato"
+
+msgid "No display: Send expression failed.\n"
+msgstr "Nessun display: Invio di espressione fallito.\n"
+
+msgid ": Send expression failed.\n"
+msgstr ": Invio di espressione fallito.\n"
+
+msgid "No marks set"
+msgstr "Nessun mark impostato"
+
+msgid "E283: No marks matching \"%s\""
+msgstr "E283: Nessun mark corrispondente a \"%s\""
+
+msgid ""
+"\n"
+"mark line col file/text"
+msgstr ""
+"\n"
+"mark riga col.file/testo"
+
+msgid ""
+"\n"
+" jump line col file/text"
+msgstr ""
+"\n"
+" salt.riga col.file/testo"
+
+msgid ""
+"\n"
+"change line col text"
+msgstr ""
+"\n"
+"modif riga col testo"
+
+msgid ""
+"\n"
+"# File marks:\n"
+msgstr ""
+"\n"
+"# File mark:\n"
+
+msgid ""
+"\n"
+"# Jumplist (newest first):\n"
+msgstr ""
+"\n"
+"# Jumplist (dai più recenti):\n"
+
+msgid ""
+"\n"
+"# History of marks within files (newest to oldest):\n"
+msgstr ""
+"\n"
+"# Storia dei mark all'interno dei file (dai più recenti ai meno recenti):\n"
+
+msgid "Missing '>'"
+msgstr "Manca '>'"
+
+msgid "E543: Not a valid codepage"
+msgstr "E543: Codepage non valido"
+
+msgid "E284: Cannot set IC values"
+msgstr "E284: Non posso assegnare valori IC"
+
+msgid "E285: Failed to create input context"
+msgstr "E285: Creazione di un contesto di input fallita"
+
+msgid "E286: Failed to open input method"
+msgstr "E286: Apertura 'input method' fallita"
+
+msgid "E287: Warning: Could not set destroy callback to IM"
+msgstr "E287: Avviso: Non posso assegnare IM a 'destroy callback'"
+
+msgid "E288: input method doesn't support any style"
+msgstr "E288: 'input method' non sopporta alcuno stile"
+
+msgid "E289: input method doesn't support my preedit type"
+msgstr "E289: 'input method' non supporta il mio tipo di preedit"
+
+msgid "E293: block was not locked"
+msgstr "E293: il blocco non era riservato"
+
+msgid "E294: Seek error in swap file read"
+msgstr "E294: Errore di posizionamento durante lettura swap file"
+
+msgid "E295: Read error in swap file"
+msgstr "E295: Errore leggendo swap file"
+
+msgid "E296: Seek error in swap file write"
+msgstr "E296: Errore di posizionamento scrivendo swap file"
+
+msgid "E297: Write error in swap file"
+msgstr "E297: Errore scrivendo swap file"
+
+msgid "E300: Swap file already exists (symlink attack?)"
+msgstr "E300: Lo swap file esiste già (un link simbolico?)"
+
+msgid "E298: Didn't get block nr 0?"
+msgstr "E298: Non riesco a leggere blocco numero 0?"
+
+msgid "E298: Didn't get block nr 1?"
+msgstr "E298: Non riesco a leggere blocco numero 1?"
+
+msgid "E298: Didn't get block nr 2?"
+msgstr "E298: Non riesco a leggere blocco numero 2?"
+
+msgid "E843: Error while updating swap file crypt"
+msgstr "E843: Errore aggiornando cifratura dello swap file"
+
+msgid "E301: Oops, lost the swap file!!!"
+msgstr "E301: Ahimè, lo swap file è perduto!!!"
+
+msgid "E302: Could not rename swap file"
+msgstr "E302: Non riesco a rinominare lo swap file"
+
+msgid "E303: Unable to open swap file for \"%s\", recovery impossible"
+msgstr ""
+"E303: Non riesco ad aprile lo swap file per \"%s\", recupero impossibile"
+
+msgid "E304: ml_upd_block0(): Didn't get block 0??"
+msgstr "E304: ml_upd_block0(): Non riesco a leggere blocco 0??"
+
+msgid "E305: No swap file found for %s"
+msgstr "E305: Nessun swap file trovato per %s"
+
+msgid "Enter number of swap file to use (0 to quit): "
+msgstr "Dimmi numero di swap file da usare (0 per lasciar perdere): "
+
+msgid "E306: Cannot open %s"
+msgstr "E306: Non riesco ad aprire %s"
+
+msgid "Unable to read block 0 from "
+msgstr "Non riesco a leggere il blocco 0 da "
+
+msgid ""
+"\n"
+"Maybe no changes were made or Vim did not update the swap file."
+msgstr ""
+"\n"
+"Forse non ci sono state modifiche oppure Vim non ha aggiornato lo swap file."
+
+msgid " cannot be used with this version of Vim.\n"
+msgstr " non può essere usato con questa versione di Vim.\n"
+
+msgid "Use Vim version 3.0.\n"
+msgstr "Usa Vim versione 3.0.\n"
+
+msgid "E307: %s does not look like a Vim swap file"
+msgstr "E307: %s non sembra uno swap file Vim"
+
+msgid " cannot be used on this computer.\n"
+msgstr " non può essere usato su questo computer.\n"
+
+msgid "The file was created on "
+msgstr "Il file è stato creato il "
+
+msgid ""
+",\n"
+"or the file has been damaged."
+msgstr ""
+",\n"
+"o il file è stato danneggiato."
+
+msgid ""
+"E833: %s is encrypted and this version of Vim does not support encryption"
+msgstr "E833: %s è cifrato e questa versione di Vim non supporta la cifratura"
+
+msgid " has been damaged (page size is smaller than minimum value).\n"
+msgstr ""
+" è stato danneggiato (la dimensione della pagina è inferiore al minimo).\n"
+
+msgid "Using swap file \"%s\""
+msgstr "Uso swap file \"%s\""
+
+msgid "Original file \"%s\""
+msgstr "File originale \"%s\""
+
+msgid "E308: Warning: Original file may have been changed"
+msgstr ""
+"E308: Avviso: il file originale può essere stato modificato nel frattempo"
+
+msgid "Swap file is encrypted: \"%s\""
+msgstr "Il file swap è cifrato: \"%s\""
+
+msgid ""
+"\n"
+"If you entered a new crypt key but did not write the text file,"
+msgstr ""
+"\n"
+"Se hai immesso una chiave di cifratura senza riscrivere il file di testo,"
+
+msgid ""
+"\n"
+"enter the new crypt key."
+msgstr ""
+"\n"
+"immetti la nuova chiave di cifratura."
+
+msgid ""
+"\n"
+"If you wrote the text file after changing the crypt key press enter"
+msgstr ""
+"\n"
+"Se hai riscritto il file dopo aver cambiato chiave di cifr., premi Invio"
+
+msgid ""
+"\n"
+"to use the same key for text file and swap file"
+msgstr ""
+"\n"
+"per usare la stessa chiave sia per il testo che per il file swap"
+
+msgid "E309: Unable to read block 1 from %s"
+msgstr "E309: Impossibile leggere blocco 1 da %s"
+
+msgid "???MANY LINES MISSING"
+msgstr "???MOLTE RIGHE MANCANTI"
+
+msgid "???LINE COUNT WRONG"
+msgstr "???CONTATORE RIGHE ERRATO"
+
+msgid "???EMPTY BLOCK"
+msgstr "???BLOCCO VUOTO"
+
+msgid "???LINES MISSING"
+msgstr "???RIGHE MANCANTI"
+
+msgid "E310: Block 1 ID wrong (%s not a .swp file?)"
+msgstr "E310: ID del Blocco 1 errato (che %s non sia un .swp file?)"
+
+msgid "???BLOCK MISSING"
+msgstr "???BLOCCO MANCANTE"
+
+msgid "??? from here until ???END lines may be messed up"
+msgstr "??? da qui fino a ???END le righe possono essere fuori ordine"
+
+msgid "??? from here until ???END lines may have been inserted/deleted"
+msgstr ""
+"??? da qui fino a ???END righe possono essere state inserite/cancellate"
+
+msgid "???END"
+msgstr "???END"
+
+msgid "E311: Recovery Interrupted"
+msgstr "E311: Recupero Interrotto"
+
+msgid ""
+"E312: Errors detected while recovering; look for lines starting with ???"
+msgstr "E312: Errori durante recupero; controlla righe che iniziano con ???"
+
+msgid "See \":help E312\" for more information."
+msgstr "Vedere \":help E312\" per ulteriori informazioni."
+
+msgid "Recovery completed. You should check if everything is OK."
+msgstr "Recupero completato. Dovresti controllare se va tutto bene."
+
+msgid ""
+"\n"
+"(You might want to write out this file under another name\n"
+msgstr ""
+"\n"
+"(Potresti salvare questo file con un altro nome ed eseguire\n"
+
+msgid "and run diff with the original file to check for changes)"
+msgstr "'diff' rispetto al file originale per vedere le differenze)"
+
+msgid "Recovery completed. Buffer contents equals file contents."
+msgstr ""
+"Ripristino effettuato. Il contenuto del buffer coincide con quello del file."
+
+msgid ""
+"\n"
+"You may want to delete the .swp file now.\n"
+"\n"
+msgstr ""
+"\n"
+"È consigliato cancellare il file .swp adesso.\n"
+"\n"
+
+msgid "Using crypt key from swap file for the text file.\n"
+msgstr "Uso la chiave di cifratura del file swap per il file di testo.\n"
+
+msgid "Swap files found:"
+msgstr "Swap file trovati:"
+
+msgid " In current directory:\n"
+msgstr " Nella directory in uso:\n"
+
+msgid " Using specified name:\n"
+msgstr " Uso il nome fornito:\n"
+
+msgid " In directory "
+msgstr " Nella directory "
+
+msgid " -- none --\n"
+msgstr " -- nessuno --\n"
+
+msgid " owned by: "
+msgstr " proprietario: "
+
+msgid " dated: "
+msgstr " datato: "
+
+msgid " dated: "
+msgstr " datato: "
+
+msgid " [from Vim version 3.0]"
+msgstr " [da Vim versione 3.0]"
+
+msgid " [does not look like a Vim swap file]"
+msgstr " [non assomiglia ad uno swap file Vim]"
+
+msgid " file name: "
+msgstr " nome file: "
+
+msgid ""
+"\n"
+" modified: "
+msgstr ""
+"\n"
+" modificato: "
+
+msgid "YES"
+msgstr "YES"
+
+msgid "no"
+msgstr "no"
+
+msgid ""
+"\n"
+" user name: "
+msgstr ""
+"\n"
+" nome utente: "
+
+msgid " host name: "
+msgstr " nome computer: "
+
+msgid ""
+"\n"
+" host name: "
+msgstr ""
+"\n"
+" nome computer: "
+
+msgid ""
+"\n"
+" process ID: "
+msgstr ""
+"\n"
+" ID del processo: "
+
+msgid " (still running)"
+msgstr " (ancora attivo)"
+
+msgid ""
+"\n"
+" [not usable with this version of Vim]"
+msgstr ""
+"\n"
+" [non utilizzabile con questa versione di Vim]"
+
+msgid ""
+"\n"
+" [not usable on this computer]"
+msgstr ""
+"\n"
+" [not utilizzabile su questo computer]"
+
+msgid " [cannot be read]"
+msgstr " [non leggibile]"
+
+msgid " [cannot be opened]"
+msgstr " [non riesco ad aprire]"
+
+msgid "E313: Cannot preserve, there is no swap file"
+msgstr "E313: Non posso preservare, manca swap file"
+
+msgid "File preserved"
+msgstr "File preservato"
+
+msgid "E314: Preserve failed"
+msgstr "E314: Preservazione fallita"
+
+msgid "E315: ml_get: invalid lnum: %ld"
+msgstr "E315: ml_get: numero riga non valido: %ld"
+
+msgid "E316: ml_get: cannot find line %ld"
+msgstr "E316: ml_get: non riesco a trovare la riga %ld"
+
+msgid "E317: pointer block id wrong 3"
+msgstr "E317: ID blocco puntatori errato 3"
+
+msgid "stack_idx should be 0"
+msgstr "stack_idx dovrebbe essere 0"
+
+msgid "E318: Updated too many blocks?"
+msgstr "E318: Aggiornati troppi blocchi?"
+
+msgid "E317: pointer block id wrong 4"
+msgstr "E317: ID blocco puntatori errato 4"
+
+msgid "deleted block 1?"
+msgstr "cancellato blocco 1?"
+
+msgid "E320: Cannot find line %ld"
+msgstr "E320: Non riesco a trovare la riga %ld"
+
+msgid "E317: pointer block id wrong"
+msgstr "E317: ID blocco puntatori errato"
+
+msgid "pe_line_count is zero"
+msgstr "pe_line_count a zero"
+
+msgid "E322: line number out of range: %ld past the end"
+msgstr "E322: numero riga non ammissibile: %ld dopo la fine"
+
+msgid "E323: line count wrong in block %ld"
+msgstr "E323: contatore righe errato nel blocco %ld"
+
+msgid "Stack size increases"
+msgstr "Dimensione stack aumentata"
+
+msgid "E317: pointer block id wrong 2"
+msgstr "E317: ID blocco puntatori errato 2"
+
+msgid "E773: Symlink loop for \"%s\""
+msgstr "E773: Collegamento simbolico ricorsivo per \"%s\""
+
+msgid "E325: ATTENTION"
+msgstr "E325: ATTENZIONE"
+
+msgid ""
+"\n"
+"Found a swap file by the name \""
+msgstr ""
+"\n"
+"Trovato uno swap file di nome \""
+
+msgid "While opening file \""
+msgstr "Mentre aprivo file \""
+
+msgid " NEWER than swap file!\n"
+msgstr " più RECENTE dello swap file!\n"
+
+msgid ""
+"\n"
+"(1) Another program may be editing the same file. If this is the case,\n"
+" be careful not to end up with two different instances of the same\n"
+" file when making changes. Quit, or continue with caution.\n"
+msgstr ""
+"\n"
+"(1) Un altro programma può essere in edit sullo stesso file. Se è così,\n"
+" attenzione a non finire con due sessioni differenti che modificano lo\n"
+" stesso file. Uscire da Vim, o continuare con cautela.\n"
+
+msgid "(2) An edit session for this file crashed.\n"
+msgstr "(2) Una sessione di edit per questo file è finita male.\n"
+
+msgid " If this is the case, use \":recover\" or \"vim -r "
+msgstr " Se è così, usa \":recover\" oppure \"vim -r "
+
+msgid ""
+"\"\n"
+" to recover the changes (see \":help recovery\").\n"
+msgstr ""
+"\"\n"
+" per recuperare modifiche fatte (vedi \":help recovery\").\n"
+
+msgid " If you did this already, delete the swap file \""
+msgstr " Se hai già fatto ciò, cancella il file di swap \""
+
+msgid ""
+"\"\n"
+" to avoid this message.\n"
+msgstr ""
+"\"\n"
+" per non ricevere ancora questo messaggio.\n"
+
+msgid "Swap file \""
+msgstr "Swap file \""
+
+msgid "\" already exists!"
+msgstr "\" già esistente!"
+
+msgid "VIM - ATTENTION"
+msgstr "VIM - ATTENZIONE"
+
+msgid "Swap file already exists!"
+msgstr "Lo swap file esiste già!"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"&O Apri sola-lettura\n"
+"&E Apri comunque\n"
+"&Recupera\n"
+"&Q Esci\n"
+"&Annulla"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Delete it\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"&O Apri sola-lettura\n"
+"&E Apri comunque\n"
+"&Recupera\n"
+"&D Cancellalo\n"
+"&Q Esci\n"
+"&Annulla"
+
+msgid "E326: Too many swap files found"
+msgstr "E326: Trovati troppi swap file"
+
+msgid "E327: Part of menu-item path is not sub-menu"
+msgstr ""
+"E327: Parte del percorso di questo elemento di Menu non è un sotto-Menu"
+
+msgid "E328: Menu only exists in another mode"
+msgstr "E328: I Menu esistono solo in un'altra modalità"
+
+msgid "E329: No menu \"%s\""
+msgstr "E329: Nessun Menu \"%s\""
+
+msgid "E792: Empty menu name"
+msgstr "E792: Nome menu non valido"
+
+msgid "E330: Menu path must not lead to a sub-menu"
+msgstr "E330: Il percorso del Menu non deve condurre a un sotto-Menu"
+
+msgid "E331: Must not add menu items directly to menu bar"
+msgstr ""
+"E331: Non devi aggiungere elementi di Menu direttamente alla barra Menu"
+
+msgid "E332: Separator cannot be part of a menu path"
+msgstr "E332: Il separatore non può far parte di un percorso di Menu"
+
+msgid ""
+"\n"
+"--- Menus ---"
+msgstr ""
+"\n"
+"--- Menu ---"
+
+msgid "Tear off this menu"
+msgstr "Togli questo Menu"
+
+msgid "E335: Menu not defined for %s mode"
+msgstr "E335: Menu non definito per la modalità %s"
+
+msgid "E333: Menu path must lead to a menu item"
+msgstr "E333: Il percorso Menu deve condurre ad un elemento Menu"
+
+msgid "E334: Menu not found: %s"
+msgstr "E334: Menu non trovato: %s"
+
+msgid "E336: Menu path must lead to a sub-menu"
+msgstr "E336: Il percorso Menu deve condurre ad un sotto-Menu"
+
+msgid "E337: Menu not found - check menu names"
+msgstr "E337: Menu non trovato - controlla nomi Menu"
+
+msgid "Error detected while processing %s:"
+msgstr "Errore/i eseguendo %s:"
+
+msgid "line %4ld:"
+msgstr "riga %4ld:"
+
+msgid "E354: Invalid register name: '%s'"
+msgstr "E354: Nome registro non valido: '%s'"
+
+msgid "Messages maintainer: Bram Moolenaar <Bram@vim.org>"
+msgstr "Manutentore messaggi: Vlad Sandrini <marco@sandrini.biz>"
+
+msgid "Interrupt: "
+msgstr "Interruzione: "
+
+msgid "Press ENTER or type command to continue"
+msgstr "Premi INVIO o un comando per proseguire"
+
+msgid "%s line %ld"
+msgstr "%s riga %ld"
+
+msgid "-- More --"
+msgstr "-- Ancora --"
+
+msgid " SPACE/d/j: screen/page/line down, b/u/k: up, q: quit "
+msgstr " SPAZIO/d/j: schermo/pagina/riga giù, b/u/k: su, q: abbandona "
+
+msgid "Question"
+msgstr "Domanda"
+
+msgid ""
+"&Yes\n"
+"&No"
+msgstr ""
+"&Y Sì\n"
+"&No"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"Save &All\n"
+"&Discard All\n"
+"&Cancel"
+msgstr ""
+"&Y Sì\n"
+"&No\n"
+"&A Salva tutto\n"
+"&D Scarta Tutto\n"
+"&Cancella"
+
+msgid "Select Directory dialog"
+msgstr "Scelta Directory dialogo"
+
+msgid "Save File dialog"
+msgstr "Salva File dialogo"
+
+msgid "Open File dialog"
+msgstr "Apri File dialogo"
+
+msgid "E338: Sorry, no file browser in console mode"
+msgstr "E338: Spiacente, niente esplorazione file in modalità console"
+
+msgid "E766: Insufficient arguments for printf()"
+msgstr "E766: Argomenti non sufficienti per printf()"
+
+msgid "E807: Expected Float argument for printf()"
+msgstr "E807: Numero-a-virgola-mobile atteso come argomento per printf()"
+
+msgid "E767: Too many arguments to printf()"
+msgstr "E767: Troppi argomenti per printf()"
+
+msgid "W10: Warning: Changing a readonly file"
+msgstr "W10: Avviso: Modifica a un file in sola-lettura"
+
+msgid "Type number and <Enter> or click with mouse (empty cancels): "
+msgstr ""
+"Inserire un numero e <Invio> o fare clic (lasciare vuoto per annullare): "
+
+msgid "Type number and <Enter> (empty cancels): "
+msgstr "Inserire numero e <Invio> (vuoto per annullare): "
+
+msgid "1 more line"
+msgstr "1 riga in più"
+
+msgid "1 line less"
+msgstr "1 riga in meno"
+
+msgid "%ld more lines"
+msgstr "%ld righe in più"
+
+msgid "%ld fewer lines"
+msgstr "%ld righe in meno"
+
+msgid " (Interrupted)"
+msgstr " (Interrotto)"
+
+msgid "Beep!"
+msgstr "Beep!"
+
+msgid "ERROR: "
+msgstr "ERRORE: "
+
+msgid ""
+"\n"
+"[bytes] total alloc-freed %lu-%lu, in use %lu, peak use %lu\n"
+msgstr ""
+"\n"
+"[byte] totali alloc-rilasc %lu-%lu, in uso %lu, max uso %lu\n"
+
+msgid ""
+"[calls] total re/malloc()'s %lu, total free()'s %lu\n"
+"\n"
+msgstr ""
+"[chiamate] totale re/malloc() %lu, totale free() %lu\n"
+"\n"
+
+msgid "E340: Line is becoming too long"
+msgstr "E340: La riga sta diventando troppo lunga"
+
+msgid "E341: Internal error: lalloc(%ld, )"
+msgstr "E341: Errore interno: lalloc(%ld, )"
+
+msgid "E342: Out of memory! (allocating %lu bytes)"
+msgstr "E342: Non c'è più memoria! (stavo allocando %lu byte)"
+
+msgid "Calling shell to execute: \"%s\""
+msgstr "Chiamo lo shell per eseguire: \"%s\""
+
+msgid "E545: Missing colon"
+msgstr "E545: Manca ':'"
+
+msgid "E546: Illegal mode"
+msgstr "E546: Modalità non valida"
+
+msgid "E547: Illegal mouseshape"
+msgstr "E547: Forma del mouse non valida"
+
+msgid "E548: digit expected"
+msgstr "E548: aspettavo un numero"
+
+msgid "E549: Illegal percentage"
+msgstr "E549: Percentuale non valida"
+
+msgid "E854: path too long for completion"
+msgstr "E854: percorso troppo lungo per il completamento"
+
+msgid ""
+"E343: Invalid path: '**[number]' must be at the end of the path or be "
+"followed by '%s'."
+msgstr ""
+"E343: Percorso non valido: '**[numero]' deve essere a fine percorso o essere "
+"seguito da '%s'."
+
+msgid "E344: Can't find directory \"%s\" in cdpath"
+msgstr "E344: Non riesco a trovare la directory \"%s\" nel 'cdpath'"
+
+msgid "E345: Can't find file \"%s\" in path"
+msgstr "E345: Non riesco a trovare il file \"%s\" nel percorso"
+
+msgid "E346: No more directory \"%s\" found in cdpath"
+msgstr "E346: Nessun altra directory \"%s\" trovata nel 'cdpath'"
+
+msgid "E347: No more file \"%s\" found in path"
+msgstr "E347: Nessun altro file \"%s\" trovato nel percorso"
+
+msgid "E668: Wrong access mode for NetBeans connection info file: \"%s\""
+msgstr ""
+"E668: Modalità errata di accesso a file info connessione NetBeans: \"%s\""
+
+msgid "E658: NetBeans connection lost for buffer %ld"
+msgstr "E658: Connessione NetBeans persa per il buffer %ld"
+
+msgid "E838: netbeans is not supported with this GUI"
+msgstr "E838: netbeans non è supportato con questa GUI"
+
+msgid "E511: netbeans already connected"
+msgstr "E511: netbeans già connesso"
+
+msgid "E505: %s is read-only (add ! to override)"
+msgstr "E505: %s è in sola lettura (aggiungi ! per eseguire comunque)"
+
+msgid "E349: No identifier under cursor"
+msgstr "E349: Nessun identificativo sotto il cursore"
+
+msgid "E774: 'operatorfunc' is empty"
+msgstr "E774: opzione 'operatorfunc' non impostata"
+
+msgid "E775: Eval feature not available"
+msgstr "E775: Funzionalità [eval] non disponibile"
+
+msgid "Warning: terminal cannot highlight"
+msgstr "Avviso: il terminale non è in grado di evidenziare"
+
+msgid "E348: No string under cursor"
+msgstr "E348: Nessuna stringa sotto il cursore"
+
+msgid "E352: Cannot erase folds with current 'foldmethod'"
+msgstr "E352: Non posso togliere piegature con il 'foldmethod' in uso"
+
+msgid "E664: changelist is empty"
+msgstr "E664: lista modifiche assente"
+
+msgid "E662: At start of changelist"
+msgstr "E662: All'inizio della lista modifiche"
+
+msgid "E663: At end of changelist"
+msgstr "E663: Alla fine della lista modifiche"
+
+msgid "Type :qa! and press <Enter> to abandon all changes and exit Vim"
+msgstr "Batti :qa! e premi <Invio> per ignorare le modifiche e uscire da Vim"
+
+msgid "1 line %sed 1 time"
+msgstr "1 riga %sa 1 volta"
+
+msgid "1 line %sed %d times"
+msgstr "1 riga %sa %d volte"
+
+msgid "%ld lines %sed 1 time"
+msgstr "%ld righe %se 1 volta"
+
+msgid "%ld lines %sed %d times"
+msgstr "%ld righe %se %d volte"
+
+msgid "%ld lines to indent... "
+msgstr "%ld righe da rientrare... "
+
+msgid "1 line indented "
+msgstr "1 riga rientrata "
+
+msgid "%ld lines indented "
+msgstr "%ld righe rientrate "
+
+msgid "E748: No previously used register"
+msgstr "E748: Nessun registro usato in precedenza"
+
+msgid "cannot yank; delete anyway"
+msgstr "non riesco a salvare in un registro; cancello comunque"
+
+msgid "1 line changed"
+msgstr "1 riga cambiata"
+
+msgid "%ld lines changed"
+msgstr "%ld righe cambiate"
+
+msgid "freeing %ld lines"
+msgstr "libero %ld righe"
+
+msgid " into \"%c"
+msgstr " in \"%c"
+
+msgid "block of 1 line yanked%s"
+msgstr "blocco di 1 riga messo in registro%s"
+
+msgid "1 line yanked%s"
+msgstr "1 riga messa in registro%s"
+
+msgid "block of %ld lines yanked%s"
+msgstr "blocco di %ld righe messo in registro%s"
+
+msgid "%ld lines yanked%s"
+msgstr "%ld righe messe in registro%s"
+
+msgid "E353: Nothing in register %s"
+msgstr "E353: Niente nel registro %s"
+
+msgid ""
+"\n"
+"--- Registers ---"
+msgstr ""
+"\n"
+"--- Registri ---"
+
+msgid "Illegal register name"
+msgstr "Nome registro non ammesso"
+
+msgid ""
+"\n"
+"# Registers:\n"
+msgstr ""
+"\n"
+"# Registri:\n"
+
+msgid "E574: Unknown register type %d"
+msgstr "E574: Tipo di registro sconosciuto: %d"
+
+msgid ""
+"E883: search pattern and expression register may not contain two or more "
+"lines"
+msgstr ""
+"E883: espressione di ricerca e registro dell'espressione non possono "
+"contenere due o più righe"
+
+msgid "%ld Cols; "
+msgstr "%ld Col.; "
+
+msgid "Selected %s%ld of %ld Lines; %lld of %lld Words; %lld of %lld Bytes"
+msgstr ""
+"Selezionate %s%ld di %ld Righe; %lld di %lld Parole; %lld di %lld Caratt."
+
+msgid ""
+"Selected %s%ld of %ld Lines; %lld of %lld Words; %lld of %lld Chars; %lld of "
+"%lld Bytes"
+msgstr ""
+"Selezionate %s%ld di %ld Righe; %lld di %lld Parole; %lld di %lld Caratt.; "
+"%lld di %lld Byte"
+
+msgid "Col %s of %s; Line %ld of %ld; Word %lld of %lld; Byte %lld of %lld"
+msgstr ""
+"Col. %s di %s; Riga %ld di %ld; Parola %lld di %lld; Caratt. %lld di %lld"
+
+msgid ""
+"Col %s of %s; Line %ld of %ld; Word %lld of %lld; Char %lld of %lld; Byte "
+"%lld of %lld"
+msgstr ""
+"Col. %s di %s; Riga %ld di %ld; Parola %lld di %lld; Caratt. %lld di %lld; "
+"Byte %lld di %lld"
+
+msgid "(+%lld for BOM)"
+msgstr "(+%lld per BOM)"
+
+msgid "Thanks for flying Vim"
+msgstr "Grazie per aver volato con Vim"
+
+msgid "E518: Unknown option"
+msgstr "E518: Opzione inesistente"
+
+msgid "E519: Option not supported"
+msgstr "E519: Opzione non supportata"
+
+msgid "E520: Not allowed in a modeline"
+msgstr "E520: Non consentito in una 'modeline'"
+
+msgid "E846: Key code not set"
+msgstr "E846: Key code non impostato"
+
+msgid "E521: Number required after ="
+msgstr "E521: Ci vuole un numero dopo ="
+
+msgid "E522: Not found in termcap"
+msgstr "E522: Non trovato in 'termcap'"
+
+msgid "E539: Illegal character <%s>"
+msgstr "E539: Carattere non ammesso <%s>"
+
+msgid "For option %s"
+msgstr "Per opzione %s"
+
+msgid "E529: Cannot set 'term' to empty string"
+msgstr "E529: Non posso assegnare a 'term' il valore 'stringa nulla'"
+
+msgid "E530: Cannot change term in GUI"
+msgstr "E530: Non posso modificare 'term' mentre sono nella GUI"
+
+msgid "E531: Use \":gui\" to start the GUI"
+msgstr "E531: Usa \":gui\" per far partire la GUI"
+
+msgid "E589: 'backupext' and 'patchmode' are equal"
+msgstr "E589: 'backupext' e 'patchmode' sono uguali"
+
+msgid "E834: Conflicts with value of 'listchars'"
+msgstr "E834: Conflitto con il valore di 'listchars'"
+
+msgid "E835: Conflicts with value of 'fillchars'"
+msgstr "E835: Conflitto con il valore di 'fillchars'"
+
+msgid "E617: Cannot be changed in the GTK+ 2 GUI"
+msgstr "E617: Non può essere cambiato nella GUI GTK+ 2"
+
+msgid "E950: Cannot convert between %s and %s"
+msgstr "E950: Non si può convertire da %s a %s"
+
+msgid "E524: Missing colon"
+msgstr "E524: Manca ':'"
+
+msgid "E525: Zero length string"
+msgstr "E525: Stringa nulla"
+
+msgid "E526: Missing number after <%s>"
+msgstr "E526: Manca numero dopo <%s>"
+
+msgid "E527: Missing comma"
+msgstr "E527: Manca virgola"
+
+msgid "E528: Must specify a ' value"
+msgstr "E528: Devi specificare un valore '"
+
+msgid "E595: contains unprintable or wide character"
+msgstr "E595: contiene carattere 'wide' o non-stampabile"
+
+msgid "E596: Invalid font(s)"
+msgstr "E596: Font non validi"
+
+msgid "E597: can't select fontset"
+msgstr "E597: non posso selezionare fontset"
+
+msgid "E598: Invalid fontset"
+msgstr "E598: Fontset non valido"
+
+msgid "E533: can't select wide font"
+msgstr "E533: non posso selezionare 'wide font'"
+
+msgid "E534: Invalid wide font"
+msgstr "E534: 'Wide font' non valido"
+
+msgid "E535: Illegal character after <%c>"
+msgstr "E535: Carattere non ammesso dopo <%c>"
+
+msgid "E536: comma required"
+msgstr "E536: virgola mancante"
+
+msgid "E537: 'commentstring' must be empty or contain %s"
+msgstr "E537: 'commentstring' deve essere nulla o contenere %s"
+
+msgid "E538: No mouse support"
+msgstr "E538: Manca supporto mouse"
+
+msgid "E540: Unclosed expression sequence"
+msgstr "E540: Espressione non terminata"
+
+msgid "E541: too many items"
+msgstr "E541: troppi elementi"
+
+msgid "E542: unbalanced groups"
+msgstr "E542: gruppi sbilanciati"
+
+msgid "E946: Cannot make a terminal with running job modifiable"
+msgstr ""
+"E946: Non posso aprire un terminale mentre ci sono lavori modificabili in "
+"esecuzione"
+
+msgid "E590: A preview window already exists"
+msgstr "E590: Una finestra di pre-visualizzazione esiste già"
+
+msgid "W17: Arabic requires UTF-8, do ':set encoding=utf-8'"
+msgstr "W17: Arabo richiede UTF-8, esegui ':set encoding=utf-8'"
+
+msgid "E954: 24-bit colors are not supported on this environment"
+msgstr "E954: colori a 24-bit non supportati in questo ambiente"
+
+msgid "E593: Need at least %d lines"
+msgstr "E593: Servono almeno %d righe"
+
+msgid "E594: Need at least %d columns"
+msgstr "E594: Servono almeno %d colonne"
+
+msgid "E355: Unknown option: %s"
+msgstr "E355: Opzione inesistente: %s"
+
+msgid "E521: Number required: &%s = '%s'"
+msgstr "E521: Ci vuole un numero: &%s = '%s'"
+
+msgid ""
+"\n"
+"--- Terminal codes ---"
+msgstr ""
+"\n"
+"--- Codici terminale ---"
+
+msgid ""
+"\n"
+"--- Global option values ---"
+msgstr ""
+"\n"
+"--- Valori opzioni globali ---"
+
+msgid ""
+"\n"
+"--- Local option values ---"
+msgstr ""
+"\n"
+"--- Valore opzioni locali ---"
+
+msgid ""
+"\n"
+"--- Options ---"
+msgstr ""
+"\n"
+"--- Opzioni ---"
+
+msgid "E356: get_varp ERROR"
+msgstr "E356: ERRORE get_varp"
+
+msgid "E357: 'langmap': Matching character missing for %s"
+msgstr "E357: 'langmap': Manca carattere corrispondente per %s"
+
+msgid "E358: 'langmap': Extra characters after semicolon: %s"
+msgstr "E358: 'langmap': Caratteri in più dopo il ';': %s"
+
+msgid "cannot open "
+msgstr "non riesco ad aprire "
+
+msgid "VIM: Can't open window!\n"
+msgstr "VIM: Non riesco ad aprire la finestra!\n"
+
+msgid "Need Amigados version 2.04 or later\n"
+msgstr "Serve Amigados versione 2.04 o successiva\n"
+
+msgid "Need %s version %ld\n"
+msgstr "Serve %s versione %ld\n"
+
+msgid "Cannot open NIL:\n"
+msgstr "Non riesco ad aprire NIL:\n"
+
+msgid "Cannot create "
+msgstr "Non riesco a creare "
+
+msgid "Vim exiting with %d\n"
+msgstr "Vim esce con %d\n"
+
+msgid "cannot change console mode ?!\n"
+msgstr "non posso modificare modalità console ?!\n"
+
+msgid "mch_get_shellsize: not a console??\n"
+msgstr "mch_get_shellsize: non una console??\n"
+
+msgid "E360: Cannot execute shell with -f option"
+msgstr "E360: Non posso eseguire lo shell con l'opzione -f"
+
+msgid "Cannot execute "
+msgstr "Non riesco a eseguire "
+
+msgid "shell "
+msgstr "shell "
+
+msgid " returned\n"
+msgstr " ottenuto\n"
+
+msgid "ANCHOR_BUF_SIZE too small."
+msgstr "ANCHOR_BUF_SIZE troppo piccolo."
+
+msgid "I/O ERROR"
+msgstr "ERRORE I/O"
+
+msgid "Message"
+msgstr "Messaggio"
+
+msgid "E237: Printer selection failed"
+msgstr "E237: Scelta stampante non riuscita"
+
+msgid "to %s on %s"
+msgstr "a %s su %s"
+
+msgid "E613: Unknown printer font: %s"
+msgstr "E613: Font per stampante sconosciuto: %s"
+
+msgid "E238: Print error: %s"
+msgstr "E238: Errore durante stampa: %s"
+
+msgid "Printing '%s'"
+msgstr "Stampato: '%s'"
+
+msgid "E244: Illegal charset name \"%s\" in font name \"%s\""
+msgstr "E244: Nome di charset non ammesso \"%s\" nel fonte di nome \"%s\""
+
+msgid "E244: Illegal quality name \"%s\" in font name \"%s\""
+msgstr "E244: Nome di qualità non ammesso \"%s\" nel font di nome \"%s\""
+
+msgid "E245: Illegal char '%c' in font name \"%s\""
+msgstr "E245: Carattere non ammesso '%c' nel font di nome \"%s\""
+
+msgid "Opening the X display took %ld msec"
+msgstr "Attivazione visualizzazione X ha richiesto %ld msec"
+
+msgid ""
+"\n"
+"Vim: Got X error\n"
+msgstr ""
+"\n"
+"Vim: Preso errore X\n"
+
+msgid "Testing the X display failed"
+msgstr "Prova visualizzazione X fallita"
+
+msgid "Opening the X display timed out"
+msgstr "Apertura visualizzazione X: tempo scaduto"
+
+msgid ""
+"\n"
+"Could not get security context for "
+msgstr ""
+"\n"
+"Non posso ottenere il contesto di sicurezza per "
+
+msgid ""
+"\n"
+"Could not set security context for "
+msgstr ""
+"\n"
+"Non posso impostare il contesto di sicurezza per "
+
+msgid "Could not set security context %s for %s"
+msgstr "Non posso impostare il contesto di sicurezza %s per %s"
+
+msgid "Could not get security context %s for %s. Removing it!"
+msgstr "Non posso ottenere il contesto di sicurezza %s per %s. Lo rimuovo!"
+
+msgid ""
+"\n"
+"Cannot execute shell sh\n"
+msgstr ""
+"\n"
+"Non riesco a eseguire shell sh\n"
+
+msgid ""
+"\n"
+"shell returned "
+msgstr ""
+"\n"
+"shell terminato con return-code "
+
+msgid ""
+"\n"
+"Cannot create pipes\n"
+msgstr ""
+"\n"
+"Non posso creare 'pipe'\n"
+
+msgid ""
+"\n"
+"Cannot fork\n"
+msgstr ""
+"\n"
+"Non riesco ad effettuare 'fork'\n"
+
+msgid ""
+"\n"
+"Cannot execute shell "
+msgstr ""
+"\n"
+"Non riesco a eseguire shell "
+
+msgid ""
+"\n"
+"Command terminated\n"
+msgstr ""
+"\n"
+"Comando terminato\n"
+
+msgid "XSMP lost ICE connection"
+msgstr "XSMP ha perso la connessione ICE"
+
+msgid "dlerror = \"%s\""
+msgstr "dlerror = \"%s\""
+
+msgid "Opening the X display failed"
+msgstr "Apertura visualizzazione X fallita"
+
+msgid "XSMP handling save-yourself request"
+msgstr "XSMP gestione richiesta 'save-yourself'"
+
+msgid "XSMP opening connection"
+msgstr "XSMP apertura connessione"
+
+msgid "XSMP ICE connection watch failed"
+msgstr "XSMP osservazione connessione ICE fallita"
+
+msgid "XSMP SmcOpenConnection failed: %s"
+msgstr "XSMP SmcOpenConnection fallita: %s"
+
+msgid "At line"
+msgstr "Alla riga"
+
+msgid "Could not load vim32.dll!"
+msgstr "Non riesco a caricare vim32.dll!"
+
+msgid "VIM Error"
+msgstr "Errore VIM"
+
+msgid "Could not fix up function pointers to the DLL!"
+msgstr "Non sono riuscito a impostare puntatori di funzione verso la DLL!"
+
+msgid "Vim: Caught %s event\n"
+msgstr "Vim: Intercettato evento %s\n"
+
+msgid "close"
+msgstr "chiusura"
+
+msgid "logoff"
+msgstr "logoff"
+
+msgid "shutdown"
+msgstr "shutdown"
+
+msgid "E371: Command not found"
+msgstr "E371: Comando non trovato"
+
+msgid ""
+"VIMRUN.EXE not found in your $PATH.\n"
+"External commands will not pause after completion.\n"
+"See :help win32-vimrun for more information."
+msgstr ""
+"VIMRUN.EXE non trovato nel tuo $PATH.\n"
+"I comandi esterni non faranno una pausa dopo aver finito l'esecuzione.\n"
+"Vedi :help win32-vimrun per ulteriori informazioni."
+
+msgid "Vim Warning"
+msgstr "Avviso da Vim"
+
+msgid "shell returned %d"
+msgstr "shell terminato con return-code %d"
+
+msgid "E926: Current location list was changed"
+msgstr "E926: La lista delle locazioni corrente è stata cambiata"
+
+msgid "E372: Too many %%%c in format string"
+msgstr "E372: Troppi %%%c nella stringa di 'format'"
+
+msgid "E373: Unexpected %%%c in format string"
+msgstr "E373: %%%c imprevisto nella stringa di 'format'"
+
+msgid "E374: Missing ] in format string"
+msgstr "E374: Manca ] nella stringa di 'format'"
+
+msgid "E375: Unsupported %%%c in format string"
+msgstr "E375: %%%c non supportato nella stringa di 'format'"
+
+msgid "E376: Invalid %%%c in format string prefix"
+msgstr "E376: %%%c non valido nel prefisso della stringa di 'format'"
+
+msgid "E377: Invalid %%%c in format string"
+msgstr "E377: %%%c non valido nella stringa di 'format'"
+
+msgid "E378: 'errorformat' contains no pattern"
+msgstr "E378: 'errorformat' non contiene alcun modello"
+
+msgid "E379: Missing or empty directory name"
+msgstr "E379: Nome directory mancante o nullo"
+
+msgid "E553: No more items"
+msgstr "E553: Non ci sono più elementi"
+
+msgid "E924: Current window was closed"
+msgstr "E924: La finestra corrente è stata chiusa"
+
+msgid "E925: Current quickfix was changed"
+msgstr "E925: Il quickfix corrente è stato cambiato"
+
+msgid "(%d of %d)%s%s: "
+msgstr "(%d di %d)%s%s: "
+
+msgid " (line deleted)"
+msgstr " (riga cancellata)"
+
+msgid "%serror list %d of %d; %d errors "
+msgstr "%slista errori %d di %d; %d errori"
+
+msgid "E380: At bottom of quickfix stack"
+msgstr "E380: Al fondo dello stack di quickfix"
+
+msgid "E381: At top of quickfix stack"
+msgstr "E381: In cima allo stack di quickfix"
+
+msgid "No entries"
+msgstr "Nessun elemento"
+
+msgid "Error file"
+msgstr "File errori"
+
+msgid "E683: File name missing or invalid pattern"
+msgstr "E683: Nome file mancante o espressione non valida"
+
+msgid "Cannot open file \"%s\""
+msgstr "Non riesco ad aprire il file \"%s\""
+
+msgid "E681: Buffer is not loaded"
+msgstr "E681: Buffer non caricato"
+
+msgid "E777: String or List expected"
+msgstr "E777: aspettavo Stringa o Lista"
+
+msgid "E369: invalid item in %s%%[]"
+msgstr "E369: elemento non valido in %s%%[]"
+
+msgid "E769: Missing ] after %s["
+msgstr "E769: Manca ] dopo %s["
+
+msgid "E944: Reverse range in character class"
+msgstr "E944: Intervallo invertito nella classe di caratteri"
+
+msgid "E945: Range too large in character class"
+msgstr "E945: Intervallo troppo ampio nella classe di caratteri"
+
+msgid "E53: Unmatched %s%%("
+msgstr "E53: Senza riscontro: %s%%("
+
+msgid "E54: Unmatched %s("
+msgstr "E54: Senza riscontro: %s("
+
+msgid "E55: Unmatched %s)"
+msgstr "E55: Senza riscontro: %s)"
+
+msgid "E66: \\z( not allowed here"
+msgstr "E66: \\z( non consentito qui"
+
+msgid "E67: \\z1 - \\z9 not allowed here"
+msgstr "E67: \\z1 - \\z9 non consentiti qui"
+
+msgid "E69: Missing ] after %s%%["
+msgstr "E69: Manca ] dopo %s%%["
+
+msgid "E70: Empty %s%%[]"
+msgstr "E70: %s%%[] vuoto"
+
+msgid "E65: Illegal back reference"
+msgstr "E65: Riferimento all'indietro non ammesso"
+
+msgid "E339: Pattern too long"
+msgstr "E339: Espressione troppo lunga"
+
+msgid "E50: Too many \\z("
+msgstr "E50: Troppe \\z("
+
+msgid "E51: Too many %s("
+msgstr "E51: Troppe %s("
+
+msgid "E52: Unmatched \\z("
+msgstr "E52: Senza riscontro: \\z("
+
+msgid "E59: invalid character after %s@"
+msgstr "E59: Carattere non ammesso dopo %s@"
+
+msgid "E60: Too many complex %s{...}s"
+msgstr "E60: Troppi %s{...}s complessi"
+
+msgid "E61: Nested %s*"
+msgstr "E61: %s* nidificato"
+
+msgid "E62: Nested %s%c"
+msgstr "E62: %s%c nidificato"
+
+msgid "E63: invalid use of \\_"
+msgstr "E63: uso non valido di \\_"
+
+msgid "E64: %s%c follows nothing"
+msgstr "E64: %s%c senza nulla prima"
+
+msgid "E68: Invalid character after \\z"
+msgstr "E68: Carattere non ammesso dopo \\z"
+
+msgid "E678: Invalid character after %s%%[dxouU]"
+msgstr "E678: Carattere non valido dopo %s%%[dxouU]"
+
+msgid "E71: Invalid character after %s%%"
+msgstr "E71: Carattere non ammesso dopo %s%%"
+
+msgid "E554: Syntax error in %s{...}"
+msgstr "E554: Errore sintattico in %s{...}"
+
+msgid "External submatches:\n"
+msgstr "Sotto-corrispondenze esterne:\n"
+
+msgid "E888: (NFA regexp) cannot repeat %s"
+msgstr "E888: (NFA regexp) non riesco a ripetere %s"
+
+msgid ""
+"E864: \\%#= can only be followed by 0, 1, or 2. The automatic engine will be "
+"used "
+msgstr ""
+"E864: \\%#= può essere seguito solo da 0, 1 o 2. Sarà usato il motore "
+"automatico "
+
+msgid "Switching to backtracking RE engine for pattern: "
+msgstr "Passo alla ricerca di RE col vecchio metodo: "
+
+msgid "E865: (NFA) Regexp end encountered prematurely"
+msgstr "E865: (NFA) Fine prematura dell'espressione regolare"
+
+msgid "E866: (NFA regexp) Misplaced %c"
+msgstr "E866: (NFA regexp) %c fuori posto"
+
+msgid "E877: (NFA regexp) Invalid character class: %ld"
+msgstr "E877: (NFA regexp) Classe di caratteri non valida: %ld"
+
+msgid "E867: (NFA) Unknown operator '\\z%c'"
+msgstr "E867: (NFA) Operatore sconosciuto '\\z%c'"
+
+msgid "E951: \\% value too large"
+msgstr "E951: \\% valore troppo grande"
+
+msgid "E867: (NFA) Unknown operator '\\%%%c'"
+msgstr "E867: (NFA) Operatore sconosciuto '\\%%%c'"
+
+msgid "E868: Error building NFA with equivalence class!"
+msgstr "E868: Errore nel build di NFA con classe di equivalenza!"
+
+msgid "E869: (NFA) Unknown operator '\\@%c'"
+msgstr "E869: (NFA) Operatore sconosciuto '\\@%c'"
+
+msgid "E870: (NFA regexp) Error reading repetition limits"
+msgstr "E870: (NFA regexp) Errore nella lettura dei limiti di ripetizione"
+
+msgid "E871: (NFA regexp) Can't have a multi follow a multi"
+msgstr "E871: (NFA regexp) Non si può avere multi dopo multi"
+
+msgid "E872: (NFA regexp) Too many '('"
+msgstr "E872: (NFA regexp) Troppi '('"
+
+msgid "E879: (NFA regexp) Too many \\z("
+msgstr "E879: (NFA regexp) Troppi \\z("
+
+msgid "E873: (NFA regexp) proper termination error"
+msgstr "E873: (NFA regexp) errore di terminazione corretta"
+
+msgid "Could not open temporary log file for writing, displaying on stderr... "
+msgstr ""
+"Non posso aprire il file temporaneo di log in scrittura, mostro su stderr... "
+
+msgid "E874: (NFA) Could not pop the stack!"
+msgstr "E874: (NFA) Impossibile riprendere lo stack!"
+
+msgid ""
+"E875: (NFA regexp) (While converting from postfix to NFA), too many states "
+"left on stack"
+msgstr ""
+"E875: (NFA regexp) (Nella conversione da postfix a NFA), troppi stati "
+"lasciati sullo stack"
+
+msgid "E876: (NFA regexp) Not enough space to store the whole NFA "
+msgstr "E876: (NFA regexp) Non c'è spazio per immagazzinare l'intero NFA "
+
+msgid "E878: (NFA) Could not allocate memory for branch traversal!"
+msgstr "E878: (NFA) Non posso allocare memoria per il zigzag di ramo!"
+
+msgid " VREPLACE"
+msgstr " V-SOSTITUISCI"
+
+msgid " REPLACE"
+msgstr " SOSTITUISCI"
+
+msgid " REVERSE"
+msgstr " INVERTITO"
+
+msgid " INSERT"
+msgstr " INSERISCI"
+
+msgid " (insert)"
+msgstr " (inserisci)"
+
+msgid " (replace)"
+msgstr " (sostituisci)"
+
+msgid " (vreplace)"
+msgstr " (v-sostituisci)"
+
+msgid " Hebrew"
+msgstr " Ebraico"
+
+msgid " Arabic"
+msgstr " Arabo"
+
+msgid " (paste)"
+msgstr " (incolla)"
+
+msgid " VISUAL"
+msgstr " VISUALE"
+
+msgid " VISUAL LINE"
+msgstr " VISUALE RIGA"
+
+msgid " VISUAL BLOCK"
+msgstr " VISUALE BLOCCO"
+
+msgid " SELECT"
+msgstr " SELEZIONA"
+
+msgid " SELECT LINE"
+msgstr " SELEZIONA RIGA"
+
+msgid " SELECT BLOCK"
+msgstr " SELEZIONA BLOCCO"
+
+msgid "recording"
+msgstr "registrazione"
+
+msgid "E383: Invalid search string: %s"
+msgstr "E383: Stringa di ricerca non valida: %s"
+
+msgid "E384: search hit TOP without match for: %s"
+msgstr "E384: la ricerca ha raggiunto la CIMA senza successo per: %s"
+
+msgid "E385: search hit BOTTOM without match for: %s"
+msgstr "E385: la ricerca ha raggiunto il FONDO senza successo per: %s"
+
+msgid "E386: Expected '?' or '/' after ';'"
+msgstr "E386: '?' o '/' atteso dopo ';'"
+
+msgid " (includes previously listed match)"
+msgstr " (comprese corrispondenze elencate prima)"
+
+msgid "--- Included files "
+msgstr "--- File inclusi "
+
+msgid "not found "
+msgstr "non trovati "
+
+msgid "in path ---\n"
+msgstr "nel percorso ---\n"
+
+msgid " (Already listed)"
+msgstr " (Già elencati)"
+
+msgid " NOT FOUND"
+msgstr " NON TROVATO"
+
+msgid "Scanning included file: %s"
+msgstr "Scandisco file incluso: %s"
+
+msgid "Searching included file %s"
+msgstr "Cerco nel file incluso: %s"
+
+msgid "E387: Match is on current line"
+msgstr "E387: Corrispondenza nella riga corrente"
+
+msgid "All included files were found"
+msgstr "Tutti i file inclusi sono stati trovati"
+
+msgid "No included files"
+msgstr "Nessun file incluso"
+
+msgid "E388: Couldn't find definition"
+msgstr "E388: Non sono riuscito a trovare la definizione"
+
+msgid "E389: Couldn't find pattern"
+msgstr "E389: Non sono riuscito a trovare il modello"
+
+msgid "Substitute "
+msgstr "Sostituzione "
+
+msgid ""
+"\n"
+"# Last %sSearch Pattern:\n"
+"~"
+msgstr ""
+"\n"
+"# Ult. %sEspressione di Ricerca:\n"
+"~"
+
+msgid "E756: Spell checking is not enabled"
+msgstr "E756: Controllo ortografico non abilitato"
+
+msgid "Warning: Cannot find word list \"%s_%s.spl\" or \"%s_ascii.spl\""
+msgstr "Avviso: Non trovo lista parole \"%s_%s.spl\" o \"%s_ascii.spl\""
+
+msgid "Warning: Cannot find word list \"%s.%s.spl\" or \"%s.ascii.spl\""
+msgstr "Avviso: Non trovo lista parole \"%s.%s.spl\" o \"%s.ascii.spl\""
+
+msgid "E797: SpellFileMissing autocommand deleted buffer"
+msgstr "E797: L'autocomando 'SpellFileMissing' ha cancellato il buffer"
+
+msgid "Warning: region %s not supported"
+msgstr "Avviso: regione %s non supportata"
+
+msgid "Sorry, no suggestions"
+msgstr "Spiacente, nessun suggerimento"
+
+msgid "Sorry, only %ld suggestions"
+msgstr "Spiacente, solo %ld suggerimenti"
+
+msgid "Change \"%.*s\" to:"
+msgstr "Cambiare \"%.*s\" in:"
+
+msgid " < \"%.*s\""
+msgstr " < \"%.*s\""
+
+msgid "E752: No previous spell replacement"
+msgstr "E752: Nessuna sostituzione ortografica precedente"
+
+msgid "E753: Not found: %s"
+msgstr "E753: Non trovato: %s"
+
+msgid "E758: Truncated spell file"
+msgstr "E758: File ortografico troncato"
+
+msgid "Trailing text in %s line %d: %s"
+msgstr "Testo in eccesso in %s riga %d: %s"
+
+msgid "Affix name too long in %s line %d: %s"
+msgstr "Nome affisso troppo lungo in %s riga %d: %s"
+
+msgid "E761: Format error in affix file FOL, LOW or UPP"
+msgstr "E761: Errore di formato nel file affissi FOL, LOW o UPP"
+
+msgid "E762: Character in FOL, LOW or UPP is out of range"
+msgstr "E762: Carattere fuori intervallo in FOL, LOW o UPP"
+
+msgid "Compressing word tree..."
+msgstr "Comprimo albero di parole..."
+
+msgid "Reading spell file \"%s\""
+msgstr "Lettura file ortografico \"%s\""
+
+msgid "E757: This does not look like a spell file"
+msgstr "E757: Questo non sembra un file ortografico"
+
+msgid "E771: Old spell file, needs to be updated"
+msgstr "E771: File ortografico obsoleto, è necessario aggiornarlo"
+
+msgid "E772: Spell file is for newer version of Vim"
+msgstr "E772: Il file ortografico è per versioni di Vim più recenti"
+
+msgid "E770: Unsupported section in spell file"
+msgstr "E770: Sezione non supportata nel file ortografico"
+
+msgid "E778: This does not look like a .sug file: %s"
+msgstr "E778: Questo non sembra un file .sug: %s"
+
+msgid "E779: Old .sug file, needs to be updated: %s"
+msgstr "E779: File .sug obsoleto, è necessario aggiornarlo: %s"
+
+msgid "E780: .sug file is for newer version of Vim: %s"
+msgstr "E780: Il file .sug è per versioni di Vim più recenti: %s"
+
+msgid "E781: .sug file doesn't match .spl file: %s"
+msgstr "E781: Il file .sug non corrisponde al file .spl: %s"
+
+msgid "E782: error while reading .sug file: %s"
+msgstr "E782: Errore leggendo il file .sug: %s"
+
+msgid "Reading affix file %s..."
+msgstr "Lettura file affissi %s..."
+
+msgid "Conversion failure for word in %s line %d: %s"
+msgstr "Conversione fallita per una parola in %s riga %d: %s"
+
+msgid "Conversion in %s not supported: from %s to %s"
+msgstr "Conversione in %s non supportata: da %s a %s"
+
+msgid "Conversion in %s not supported"
+msgstr "Conversione in %s non supportata"
+
+msgid "Invalid value for FLAG in %s line %d: %s"
+msgstr "Valore di FLAG non valido in %s riga %d: %s"
+
+msgid "FLAG after using flags in %s line %d: %s"
+msgstr "FLAG dopo l'uso di flags in %s riga %d: %s"
+
+msgid ""
+"Defining COMPOUNDFORBIDFLAG after PFX item may give wrong results in %s line "
+"%d"
+msgstr ""
+"Definire COMPOUNDFORBIDFLAG dopo l'elemento PFX potrebbe dare risultati "
+"errati in %s riga %d"
+
+msgid ""
+"Defining COMPOUNDPERMITFLAG after PFX item may give wrong results in %s line "
+"%d"
+msgstr ""
+"Definire COMPOUNDPERMITFLAG dopo l'elemento PFX potrebbe dare risultati "
+"errati in %s riga %d"
+
+msgid "Wrong COMPOUNDRULES value in %s line %d: %s"
+msgstr "Valore errato per COMPOUNDRULES in %s riga %d: %s"
+
+msgid "Wrong COMPOUNDWORDMAX value in %s line %d: %s"
+msgstr "Valore errato per COMPOUNDWORDMAX in %s riga %d: %s"
+
+msgid "Wrong COMPOUNDMIN value in %s line %d: %s"
+msgstr "Valore errato per COMPOUNDMIN in %s riga %d: %s"
+
+msgid "Wrong COMPOUNDSYLMAX value in %s line %d: %s"
+msgstr "Valore errato per COMPOUNDSYLMAX in %s riga %d: %s"
+
+msgid "Wrong CHECKCOMPOUNDPATTERN value in %s line %d: %s"
+msgstr "Valore errato per CHECKCOMPOUNDPATTERN in %s riga %d: %s"
+
+msgid "Different combining flag in continued affix block in %s line %d: %s"
+msgstr "Flag combinazione diverso in blocco affissi continuo in %s riga %d: %s"
+
+msgid "Duplicate affix in %s line %d: %s"
+msgstr "Affisso duplicato in %s riga %d: %s"
+
+msgid ""
+"Affix also used for BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST in %s "
+"line %d: %s"
+msgstr ""
+"Affisso usato anche per BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST "
+"in %s riga %d: %s"
+
+msgid "Expected Y or N in %s line %d: %s"
+msgstr "Y o N deve essere presente in %s riga %d: %s"
+
+msgid "Broken condition in %s line %d: %s"
+msgstr "Condizione non rispettata in %s riga %d: %s"
+
+msgid "Expected REP(SAL) count in %s line %d"
+msgstr "Contatore REP(SAL) necessario in %s riga %d"
+
+msgid "Expected MAP count in %s line %d"
+msgstr "Contatore MAP necessario in %s riga %d"
+
+msgid "Duplicate character in MAP in %s line %d"
+msgstr "Carattere duplicato in MAP in %s riga %d"
+
+msgid "Unrecognized or duplicate item in %s line %d: %s"
+msgstr "Elemento non riconosciuto o duplicato in %s riga %d: %s"
+
+msgid "Missing FOL/LOW/UPP line in %s"
+msgstr "Riga FOL/LOW/UPP mancante in %s"
+
+msgid "COMPOUNDSYLMAX used without SYLLABLE"
+msgstr "COMPOUNDSYLMAX usato senza SYLLABLE"
+
+msgid "Too many postponed prefixes"
+msgstr "Troppi suffissi"
+
+msgid "Too many compound flags"
+msgstr "Troppi flag composti"
+
+msgid "Too many postponed prefixes and/or compound flags"
+msgstr "Troppi suffissi e/o flag composti"
+
+msgid "Missing SOFO%s line in %s"
+msgstr "Riga SOFO%s mancante in %s"
+
+msgid "Both SAL and SOFO lines in %s"
+msgstr "Righe sia SAL che SOFO in %s"
+
+msgid "Flag is not a number in %s line %d: %s"
+msgstr "Il flag non è un numero in %s riga %d: %s"
+
+msgid "Illegal flag in %s line %d: %s"
+msgstr "Flag non ammesso in %s riga %d: %s"
+
+msgid "%s value differs from what is used in another .aff file"
+msgstr "Il valore di %s è diverso da quello usato in un altro file .aff"
+
+msgid "Reading dictionary file %s..."
+msgstr "Lettura file dizionario %s..."
+
+msgid "E760: No word count in %s"
+msgstr "E760: Nessun contatore parole in %s"
+
+msgid "line %6d, word %6ld - %s"
+msgstr "riga %6d, parola %6ld - %s"
+
+msgid "Duplicate word in %s line %d: %s"
+msgstr "Parola duplicata in %s riga %d: %s"
+
+msgid "First duplicate word in %s line %d: %s"
+msgstr "Prima parola duplicata in %s riga %d: %s"
+
+msgid "%d duplicate word(s) in %s"
+msgstr "%d parole duplicate in %s"
+
+msgid "Ignored %d word(s) with non-ASCII characters in %s"
+msgstr "%d parole con caratteri non-ASCII ignorate in %s"
+
+msgid "Reading word file %s..."
+msgstr "Lettura file parole %s..."
+
+msgid "Duplicate /encoding= line ignored in %s line %d: %s"
+msgstr "Riga /encoding= duplicata ignorata in %s riga %d: %s"
+
+msgid "/encoding= line after word ignored in %s line %d: %s"
+msgstr "Riga /encoding= dopo parola ignorata in %s riga %d: %s"
+
+msgid "Duplicate /regions= line ignored in %s line %d: %s"
+msgstr "Riga /regions= duplicata ignorata in %s riga %d: %s"
+
+msgid "Too many regions in %s line %d: %s"
+msgstr "Troppe regioni in %s riga %d: %s"
+
+msgid "/ line ignored in %s line %d: %s"
+msgstr "Riga / ignorata in %s riga %d: %s"
+
+msgid "Invalid region nr in %s line %d: %s"
+msgstr "N. regione non valido in %s riga %d: %s"
+
+msgid "Unrecognized flags in %s line %d: %s"
+msgstr "Flag non riconosciuti in %s riga %d: %s"
+
+msgid "Ignored %d words with non-ASCII characters"
+msgstr "%d parole con caratteri non-ASCII ignorate"
+
+msgid "E845: Insufficient memory, word list will be incomplete"
+msgstr "E845: Memoria insufficiente, la lista parole sarà incompleta"
+
+msgid "Compressed %d of %d nodes; %d (%d%%) remaining"
+msgstr "%d di %d nodi compressi; ne restano %d (%d%%)"
+
+msgid "Reading back spell file..."
+msgstr "Rilettura file ortografico..."
+
+msgid "Performing soundfolding..."
+msgstr "Eseguo soundfolding..."
+
+msgid "Number of words after soundfolding: %ld"
+msgstr "Numero di parole dopo soundfolding: %ld"
+
+msgid "Total number of words: %d"
+msgstr "Conteggio totale delle parole: %d"
+
+msgid "Writing suggestion file %s..."
+msgstr "Scrivo file di suggerimenti %s..."
+
+msgid "Estimated runtime memory use: %d bytes"
+msgstr "Uso stimato di memoria durante esecuzione: %d byte"
+
+msgid "E751: Output file name must not have region name"
+msgstr "E751: Il nome del file di output non deve avere il nome di regione"
+
+msgid "E754: Only up to %ld regions supported"
+msgstr "E754: Sono supportate al massimo %ld regioni"
+
+msgid "E755: Invalid region in %s"
+msgstr "E755: Regione non valida in %s"
+
+msgid "Warning: both compounding and NOBREAK specified"
+msgstr "Avviso: specificati sia composizione sia NOBREAK"
+
+msgid "Writing spell file %s..."
+msgstr "Scrivo file ortografico %s..."
+
+msgid "Done!"
+msgstr "Fatto!"
+
+msgid "E765: 'spellfile' does not have %ld entries"
+msgstr "E765: 'spellfile' non ha %ld elementi"
+
+msgid "Word '%.*s' removed from %s"
+msgstr "Parola '%.*s' rimossa da %s"
+
+msgid "Word '%.*s' added to %s"
+msgstr "Parola '%.*s' aggiunta a %s"
+
+msgid "E763: Word characters differ between spell files"
+msgstr "E763: Caratteri di parola differenti nei file ortografici"
+
+msgid "E783: duplicate char in MAP entry"
+msgstr "E783: carattere duplicato nell'elemento MAP"
+
+msgid "No Syntax items defined for this buffer"
+msgstr "Nessun elemento sintattico definito per questo buffer"
+
+msgid "syntax conceal on"
+msgstr "syntax conceal attivo"
+
+msgid "syntax conceal off"
+msgstr "syntax conceal inattivo"
+
+msgid "E390: Illegal argument: %s"
+msgstr "E390: Argomento non ammesso: %s"
+
+msgid "syntax case ignore"
+msgstr "syntax, ignorare maiuscolo/minuscolo"
+
+msgid "syntax case match"
+msgstr "syntax, considerare maiuscolo/minuscolo"
+
+msgid "syntax spell toplevel"
+msgstr "syntax, effettua spell sul testo"
+
+msgid "syntax spell notoplevel"
+msgstr "syntax, non effettuare spell sul testo"
+
+msgid "syntax spell default"
+msgstr "syntax, usare valore di default per lo spell"
+
+msgid "syntax iskeyword "
+msgstr "syntax iskeyword "
+
+msgid "E391: No such syntax cluster: %s"
+msgstr "E391: 'cluster' sintattico inesistente: %s"
+
+msgid "syncing on C-style comments"
+msgstr "sincronizzo i commenti nello stile C"
+
+msgid "no syncing"
+msgstr "nessuna sincronizzazione"
+
+msgid "syncing starts "
+msgstr "la sincronizzazione inizia "
+
+msgid " lines before top line"
+msgstr " righe prima della riga iniziale"
+
+msgid ""
+"\n"
+"--- Syntax sync items ---"
+msgstr ""
+"\n"
+"--- Elementi sincronizzazione sintassi ---"
+
+msgid ""
+"\n"
+"syncing on items"
+msgstr ""
+"\n"
+"sincronizzo elementi"
+
+msgid ""
+"\n"
+"--- Syntax items ---"
+msgstr ""
+"\n"
+"--- Elementi sintattici ---"
+
+msgid "E392: No such syntax cluster: %s"
+msgstr "E392: 'cluster' sintattico inesistente: %s"
+
+msgid "minimal "
+msgstr "minimale "
+
+msgid "maximal "
+msgstr "massimale "
+
+msgid "; match "
+msgstr "; corrisp. "
+
+msgid " line breaks"
+msgstr " interruzioni di riga"
+
+msgid "E395: contains argument not accepted here"
+msgstr "E395: contiene argomenti non accettati qui"
+
+msgid "E844: invalid cchar value"
+msgstr "E844: valore cchar non valido"
+
+msgid "E393: group[t]here not accepted here"
+msgstr "E393: group[t]here non ammesso qui"
+
+msgid "E394: Didn't find region item for %s"
+msgstr "E394: Elemento di 'region' non trovato per %s"
+
+msgid "E397: Filename required"
+msgstr "E397: Nome file necessario"
+
+msgid "E847: Too many syntax includes"
+msgstr "E847: Troppe inclusioni di sintassi"
+
+msgid "E789: Missing ']': %s"
+msgstr "E789: Manca ']': %s"
+
+msgid "E890: trailing char after ']': %s]%s"
+msgstr "E890: Caratteri in più dopo ']': %s]%s"
+
+msgid "E398: Missing '=': %s"
+msgstr "E398: Manca '=': %s"
+
+msgid "E399: Not enough arguments: syntax region %s"
+msgstr "E399: Argomenti non sufficienti per: 'syntax region' %s"
+
+msgid "E848: Too many syntax clusters"
+msgstr "E848: Troppi 'cluster' sintattici"
+
+msgid "E400: No cluster specified"
+msgstr "E400: Nessun 'cluster' specificato"
+
+msgid "E401: Pattern delimiter not found: %s"
+msgstr "E401: Delimitatore di espressione non trovato: %s"
+
+msgid "E402: Garbage after pattern: %s"
+msgstr "E402: Spazzatura dopo espressione: %s"
+
+msgid "E403: syntax sync: line continuations pattern specified twice"
+msgstr ""
+"E403: syntax sync: espressione di continuazione riga specificata due volte"
+
+msgid "E404: Illegal arguments: %s"
+msgstr "E404: Argomenti non validi: %s"
+
+msgid "E405: Missing equal sign: %s"
+msgstr "E405: Manca '=': %s"
+
+msgid "E406: Empty argument: %s"
+msgstr "E406: Argomento nullo: %s"
+
+msgid "E407: %s not allowed here"
+msgstr "E407: %s non consentito qui"
+
+msgid "E408: %s must be first in contains list"
+msgstr "E408: %s deve venire per primo nella lista 'contains'"
+
+msgid "E409: Unknown group name: %s"
+msgstr "E409: Nome gruppo sconosciuto: %s"
+
+msgid "E410: Invalid :syntax subcommand: %s"
+msgstr "E410: Sotto-comando :syntax non valido: %s"
+
+msgid ""
+" TOTAL COUNT MATCH SLOWEST AVERAGE NAME PATTERN"
+msgstr ""
+" TOTALE CONT. CORRIS. PIU LENTO MEDIA NOME MODELLO"
+
+msgid "E679: recursive loop loading syncolor.vim"
+msgstr "E679: ciclo ricorsivo nel caricamento di syncolor.vim"
+
+msgid "E411: highlight group not found: %s"
+msgstr "E411: gruppo evidenziazione non trovato: %s"
+
+msgid "E412: Not enough arguments: \":highlight link %s\""
+msgstr "E412: Argomenti non sufficienti: \":highlight link %s\""
+
+msgid "E413: Too many arguments: \":highlight link %s\""
+msgstr "E413: Troppi argomenti: \":highlight link %s\""
+
+msgid "E414: group has settings, highlight link ignored"
+msgstr "E414: 'group' ha impostazioni, 'highlight link' ignorato"
+
+msgid "E415: unexpected equal sign: %s"
+msgstr "E415: segno '=' inatteso: %s"
+
+msgid "E416: missing equal sign: %s"
+msgstr "E416: manca segno '=': %s"
+
+msgid "E417: missing argument: %s"
+msgstr "E417: manca argomento: %s"
+
+msgid "E418: Illegal value: %s"
+msgstr "E418: Valore non ammesso: %s"
+
+msgid "E419: FG color unknown"
+msgstr "E419: colore di testo sconosciuto"
+
+msgid "E420: BG color unknown"
+msgstr "E420: colore di sfondo sconosciuto"
+
+msgid "E421: Color name or number not recognized: %s"
+msgstr "E421: Numero o nome di colore non riconosciuto: %s"
+
+msgid "E422: terminal code too long: %s"
+msgstr "E422: codice terminale troppo lungo: %s"
+
+msgid "E423: Illegal argument: %s"
+msgstr "E423: Argomento non ammesso: %s"
+
+msgid "E424: Too many different highlighting attributes in use"
+msgstr "E424: Troppi gruppi evidenziazione differenti in uso"
+
+msgid "E669: Unprintable character in group name"
+msgstr "E669: Carattere non stampabile in un nome di gruppo"
+
+msgid "W18: Invalid character in group name"
+msgstr "W18: Carattere non ammesso in un nome di gruppo"
+
+msgid "E849: Too many highlight and syntax groups"
+msgstr "E849: Troppi gruppi di evidenziazione e sintassi"
+
+msgid "E555: at bottom of tag stack"
+msgstr "E555: al fondo dello stack dei tag"
+
+msgid "E556: at top of tag stack"
+msgstr "E556: in cima allo stack dei tag"
+
+msgid "E425: Cannot go before first matching tag"
+msgstr "E425: Non posso andare prima del primo tag corrispondente"
+
+msgid "E426: tag not found: %s"
+msgstr "E426: tag non trovato: %s"
+
+msgid " # pri kind tag"
+msgstr " # pri tipo tag"
+
+msgid "file\n"
+msgstr "file\n"
+
+msgid "E427: There is only one matching tag"
+msgstr "E427: C'è solo un tag corrispondente"
+
+msgid "E428: Cannot go beyond last matching tag"
+msgstr "E428: Non posso andare oltre l'ultimo tag corrispondente"
+
+msgid "File \"%s\" does not exist"
+msgstr "Il file \"%s\" non esiste"
+
+msgid "tag %d of %d%s"
+msgstr "tag %d di %d%s"
+
+msgid " or more"
+msgstr " o più"
+
+msgid " Using tag with different case!"
+msgstr " Uso tag ignorando maiuscole/minuscole!"
+
+msgid "E429: File \"%s\" does not exist"
+msgstr "E429: Il file \"%s\" non esiste"
+
+msgid ""
+"\n"
+" # TO tag FROM line in file/text"
+msgstr ""
+"\n"
+" # A tag DA__ riga in file/testo"
+
+msgid "Searching tags file %s"
+msgstr "Ricerca nel tag file %s"
+
+msgid "E430: Tag file path truncated for %s\n"
+msgstr "E430: Percorso tag file troncato per %s\n"
+
+msgid "Ignoring long line in tags file"
+msgstr "Riga lunga ignorata nel tag file"
+
+msgid "E431: Format error in tags file \"%s\""
+msgstr "E431: Errore di formato nel tag file \"%s\""
+
+msgid "Before byte %ld"
+msgstr "Prima del byte %ld"
+
+msgid "E432: Tags file not sorted: %s"
+msgstr "E432: Tag file non ordinato alfabeticamente: %s"
+
+msgid "E433: No tags file"
+msgstr "E433: Nessun tag file"
+
+msgid "E434: Can't find tag pattern"
+msgstr "E434: Non riesco a trovare modello tag"
+
+msgid "E435: Couldn't find tag, just guessing!"
+msgstr "E435: Non riesco a trovare tag, sto solo tirando a indovinare!"
+
+msgid "Duplicate field name: %s"
+msgstr "Nome di campo duplicato: %s"
+
+msgid "' not known. Available builtin terminals are:"
+msgstr "' non noto. Terminali disponibili predisposti sono:"
+
+msgid "defaulting to '"
+msgstr "predefinito a '"
+
+msgid "E557: Cannot open termcap file"
+msgstr "E557: Non posso aprire file 'termcap'"
+
+msgid "E558: Terminal entry not found in terminfo"
+msgstr "E558: Descrizione terminale non trovata in 'terminfo'"
+
+msgid "E559: Terminal entry not found in termcap"
+msgstr "E559: Descrizione terminale non trovata in 'termcap'"
+
+msgid "E436: No \"%s\" entry in termcap"
+msgstr "E436: Nessuna descrizione per \"%s\" in 'termcap'"
+
+msgid "E437: terminal capability \"cm\" required"
+msgstr "E437: capacità \"cm\" del terminale necessaria"
+
+msgid ""
+"\n"
+"--- Terminal keys ---"
+msgstr ""
+"\n"
+"--- Tasti Terminale ---"
+
+msgid "Cannot open $VIMRUNTIME/rgb.txt"
+msgstr "Non riesco ad aprire $VIMRUNTIME/rgb.txt"
+
+msgid "Kill job in \"%s\"?"
+msgstr "Cancello lavoro \"%s\"?"
+
+msgid "Terminal"
+msgstr "Terminale"
+
+msgid "Terminal-finished"
+msgstr "Terminale-terminato"
+
+msgid "active"
+msgstr "attivo"
+
+msgid "running"
+msgstr "in esecuzione"
+
+msgid "finished"
+msgstr "terminato"
+
+msgid "E953: File exists: %s"
+msgstr "E953: File già esistente: %s"
+
+msgid "E955: Not a terminal buffer"
+msgstr "E955: Il buffer non è un terminale"
+
+msgid "new shell started\n"
+msgstr "fatto eseguire nuovo shell\n"
+
+msgid "Vim: Error reading input, exiting...\n"
+msgstr "Vim: Errore leggendo l'input, esco...\n"
+
+msgid "Used CUT_BUFFER0 instead of empty selection"
+msgstr "Uso CUT_BUFFER0 invece che una scelta nulla"
+
+msgid "E881: Line count changed unexpectedly"
+msgstr "E881: Contatore righe è inaspettatamente cambiato"
+
+msgid "No undo possible; continue anyway"
+msgstr "'undo' non più possibile; continuo comunque"
+
+msgid "E828: Cannot open undo file for writing: %s"
+msgstr "E828: Non posso aprire il file Undo in scrittura: %s"
+
+msgid "E825: Corrupted undo file (%s): %s"
+msgstr "E825: File Undo corrotto (%s): %s"
+
+msgid "Cannot write undo file in any directory in 'undodir'"
+msgstr "Non posso scrivere un file Undo in alcuna directory di 'undodir'"
+
+msgid "Will not overwrite with undo file, cannot read: %s"
+msgstr "File Undo non sovrascritto, non riesco a leggere: %s"
+
+msgid "Will not overwrite, this is not an undo file: %s"
+msgstr "Non sovrascritto, non è un file Undo: %s"
+
+msgid "Skipping undo file write, nothing to undo"
+msgstr "Ometto scrittura del file Undo, non ci sono modifiche"
+
+msgid "Writing undo file: %s"
+msgstr "Scrivo file Undo: %s"
+
+msgid "E829: write error in undo file: %s"
+msgstr "E829: errore scrivendo nel file Undo: %s"
+
+msgid "Not reading undo file, owner differs: %s"
+msgstr "Non leggo file Undo, appartiene a un altro utente: %s"
+
+msgid "Reading undo file: %s"
+msgstr "Lettura file Undo: %s"
+
+msgid "E822: Cannot open undo file for reading: %s"
+msgstr "E822: Non posso aprire il file Undo in lettura: %s"
+
+msgid "E823: Not an undo file: %s"
+msgstr "E823: Non è un file Undo: %s"
+
+msgid "E832: Non-encrypted file has encrypted undo file: %s"
+msgstr "E832: File non cifrato con file Undo cifrato: %s"
+
+msgid "E826: Undo file decryption failed: %s"
+msgstr "E826: Decifratura fallita del file Undo: %s"
+
+msgid "E827: Undo file is encrypted: %s"
+msgstr "E827: File Undo cifrato: %s"
+
+msgid "E824: Incompatible undo file: %s"
+msgstr "E824: File Undo incompatibile: %s"
+
+msgid "File contents changed, cannot use undo info"
+msgstr "File ulteriormente modificato, non posso usare informazioni di Undo"
+
+msgid "Finished reading undo file %s"
+msgstr "Lettura del file Undo %s effettuata"
+
+msgid "Already at oldest change"
+msgstr "Questa è già la prima modifica"
+
+msgid "Already at newest change"
+msgstr "Questa è già l'ultima modifica"
+
+msgid "E830: Undo number %ld not found"
+msgstr "E830: Undo numero %ld non trovato"
+
+msgid "E438: u_undo: line numbers wrong"
+msgstr "E438: u_undo: numeri righe errati"
+
+msgid "more line"
+msgstr "riga in più"
+
+msgid "more lines"
+msgstr "righe in più"
+
+msgid "line less"
+msgstr "riga in meno"
+
+msgid "fewer lines"
+msgstr "righe in meno"
+
+msgid "change"
+msgstr "modifica"
+
+msgid "changes"
+msgstr "modifiche"
+
+msgid "%ld %s; %s #%ld %s"
+msgstr "%ld %s; %s #%ld %s"
+
+msgid "before"
+msgstr "prima"
+
+msgid "after"
+msgstr "dopo"
+
+msgid "Nothing to undo"
+msgstr "Nessuna modifica, Undo impossibile"
+
+msgid "number changes when saved"
+msgstr "numero modif. quando salv."
+
+msgid "%ld seconds ago"
+msgstr "%ld secondi fa"
+
+msgid "E790: undojoin is not allowed after undo"
+msgstr "E790: undojoin non è consentito dopo undo"
+
+msgid "E439: undo list corrupt"
+msgstr "E439: lista 'undo' non valida"
+
+msgid "E440: undo line missing"
+msgstr "E440: riga di 'undo' mancante"
+
+msgid "E122: Function %s already exists, add ! to replace it"
+msgstr "E122: La funzione %s esiste già, aggiungi ! per sostituirla"
+
+msgid "E717: Dictionary entry already exists"
+msgstr "E717: C'è già la voce nel Dizionario"
+
+msgid "E718: Funcref required"
+msgstr "E718: Funcref necessario"
+
+msgid "E130: Unknown function: %s"
+msgstr "E130: Funzione sconosciuta: %s"
+
+msgid "E125: Illegal argument: %s"
+msgstr "E125: Argomento non ammesso: %s"
+
+msgid "E853: Duplicate argument name: %s"
+msgstr "E853: Nome argomento duplicato: %s"
+
+msgid "E740: Too many arguments for function %s"
+msgstr "E740: Troppi argomenti per la funzione: %s"
+
+msgid "E116: Invalid arguments for function %s"
+msgstr "E116: Argomenti non validi per la funzione: %s"
+
+msgid "E132: Function call depth is higher than 'maxfuncdepth'"
+msgstr ""
+"E132: Nidificazione della chiamata di funzione maggiore di 'maxfuncdepth'"
+
+msgid "calling %s"
+msgstr "chiamo %s"
+
+msgid "%s aborted"
+msgstr "%s non completata"
+
+msgid "%s returning #%ld"
+msgstr "%s ritorno #%ld"
+
+msgid "%s returning %s"
+msgstr "%s ritorno %s"
+
+msgid "E699: Too many arguments"
+msgstr "E699: Troppi argomenti"
+
+msgid "E117: Unknown function: %s"
+msgstr "E117: Funzione sconosciuta: %s"
+
+msgid "E933: Function was deleted: %s"
+msgstr "E933: Funzione eliminata: %s"
+
+msgid "E119: Not enough arguments for function: %s"
+msgstr "E119: La funzione: %s richiede più argomenti"
+
+msgid "E120: Using <SID> not in a script context: %s"
+msgstr "E120: Uso di <SID> fuori dal contesto di uno script: %s"
+
+msgid "E725: Calling dict function without Dictionary: %s"
+msgstr "E725: Chiamata di funzione dict in assenza di Dizionario: %s"
+
+msgid "E129: Function name required"
+msgstr "E129: Nome funzione necessario"
+
+msgid "E128: Function name must start with a capital or \"s:\": %s"
+msgstr "E128: Il nome funzione deve iniziare con maiuscola o \"s:\": %s"
+
+msgid "E884: Function name cannot contain a colon: %s"
+msgstr "E884: Il nome della funzione non può contenere un due punti: %s"
+
+msgid "E123: Undefined function: %s"
+msgstr "E123: Funzione non definita: %s"
+
+msgid "E124: Missing '(': %s"
+msgstr "E124: Manca '(': %s"
+
+msgid "E862: Cannot use g: here"
+msgstr "E862: Non si può usare g: qui"
+
+msgid "E932: Closure function should not be at top level: %s"
+msgstr ""
+"E932: La funzione di chiusura non novrebbe essere al livello più alto: %s"
+
+msgid "E126: Missing :endfunction"
+msgstr "E126: Manca :endfunction"
+
+msgid "W22: Text found after :endfunction: %s"
+msgstr "W22: Trovato testo dopo :endfunction: %s"
+
+msgid "E707: Function name conflicts with variable: %s"
+msgstr "E707: Nome funzione in conflitto con la variabile: %s"
+
+msgid "E127: Cannot redefine function %s: It is in use"
+msgstr "E127: Non posso ridefinire la funzione %s: È in uso"
+
+msgid "E746: Function name does not match script file name: %s"
+msgstr "E746: Il nome funzione non corrisponde al nome file dello script: %s"
+
+msgid "E131: Cannot delete function %s: It is in use"
+msgstr "E131: Non posso eliminare la funzione %s: È in uso"
+
+msgid "E133: :return not inside a function"
+msgstr "E133: :return fuori da una funzione"
+
+msgid "E107: Missing parentheses: %s"
+msgstr "E107: Mancano parentesi: %s"
+
+msgid "%s (%s, compiled %s)"
+msgstr "%s (%s, compilato %s)"
+
+msgid ""
+"\n"
+"MS-Windows 64-bit GUI version"
+msgstr ""
+"\n"
+"Versione MS-Windows 64-bit GUI"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit GUI version"
+msgstr ""
+"\n"
+"Versione MS-Windows 32-bit GUI"
+
+msgid " with OLE support"
+msgstr " con supporto OLE"
+
+msgid ""
+"\n"
+"MS-Windows 64-bit console version"
+msgstr ""
+"\n"
+"Versione MS-Windows 64-bit console"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit console version"
+msgstr ""
+"\n"
+"Versione MS-Windows 32-bit console"
+
+msgid ""
+"\n"
+"macOS version"
+msgstr ""
+"\n"
+"Versione macOS"
+
+msgid ""
+"\n"
+"macOS version w/o darwin feat."
+msgstr ""
+"\n"
+"versione macOS senza funzion. darwin"
+
+msgid ""
+"\n"
+"OpenVMS version"
+msgstr ""
+"\n"
+"Versione OpenVMS"
+
+msgid ""
+"\n"
+"Included patches: "
+msgstr ""
+"\n"
+"Patch incluse: "
+
+msgid ""
+"\n"
+"Extra patches: "
+msgstr ""
+"\n"
+"Patch aggiuntive: "
+
+msgid "Modified by "
+msgstr "Modificato da "
+
+msgid ""
+"\n"
+"Compiled "
+msgstr ""
+"\n"
+"Compilato "
+
+msgid "by "
+msgstr "da "
+
+msgid ""
+"\n"
+"Huge version "
+msgstr ""
+"\n"
+"Versione gigante "
+
+msgid ""
+"\n"
+"Big version "
+msgstr ""
+"\n"
+"Versione grande "
+
+msgid ""
+"\n"
+"Normal version "
+msgstr ""
+"\n"
+"Versione normale "
+
+msgid ""
+"\n"
+"Small version "
+msgstr ""
+"\n"
+"Versione piccola "
+
+msgid ""
+"\n"
+"Tiny version "
+msgstr ""
+"\n"
+"Versione minuscola "
+
+msgid "without GUI."
+msgstr "senza GUI."
+
+msgid "with GTK3 GUI."
+msgstr "con GUI GTK3."
+
+msgid "with GTK2-GNOME GUI."
+msgstr "con GUI GTK2-GNOME."
+
+msgid "with GTK2 GUI."
+msgstr "con GUI GTK2."
+
+msgid "with X11-Motif GUI."
+msgstr "con GUI X11-Motif."
+
+msgid "with X11-neXtaw GUI."
+msgstr "con GUI X11-neXtaw."
+
+msgid "with X11-Athena GUI."
+msgstr "con GUI X11-Athena."
+
+msgid "with Photon GUI."
+msgstr "con GUI Photon."
+
+msgid "with GUI."
+msgstr "con GUI."
+
+msgid "with Carbon GUI."
+msgstr "con GUI Carbon."
+
+msgid "with Cocoa GUI."
+msgstr "con GUI Cocoa."
+
+msgid " Features included (+) or not (-):\n"
+msgstr " Funzionalità incluse (+) o escluse (-):\n"
+
+msgid " system vimrc file: \""
+msgstr " file vimrc di sistema: \""
+
+msgid " user vimrc file: \""
+msgstr " file vimrc utente: \""
+
+msgid " 2nd user vimrc file: \""
+msgstr " II file vimrc utente: \""
+
+msgid " 3rd user vimrc file: \""
+msgstr " III file vimrc utente: \""
+
+msgid " user exrc file: \""
+msgstr " file exrc utente: \""
+
+msgid " 2nd user exrc file: \""
+msgstr " II file exrc utente: \""
+
+msgid " system gvimrc file: \""
+msgstr " file gvimrc di sistema: \""
+
+msgid " user gvimrc file: \""
+msgstr " file gvimrc utente: \""
+
+msgid "2nd user gvimrc file: \""
+msgstr " II file gvimrc utente: \""
+
+msgid "3rd user gvimrc file: \""
+msgstr " III file gvimrc utente: \""
+
+msgid " defaults file: \""
+msgstr " file dei default: \""
+
+msgid " system menu file: \""
+msgstr " file menu di sistema: \""
+
+msgid " fall-back for $VIM: \""
+msgstr " $VIM di riserva: \""
+
+msgid " f-b for $VIMRUNTIME: \""
+msgstr " $VIMRUNTIME di riserva: \""
+
+msgid "Compilation: "
+msgstr "Compilazione: "
+
+msgid "Compiler: "
+msgstr "Compilatore: "
+
+msgid "Linking: "
+msgstr "Link: "
+
+msgid " DEBUG BUILD"
+msgstr " VERSIONE DEBUG"
+
+msgid "VIM - Vi IMproved"
+msgstr "VIM - Vi IMproved (VI Migliorato)"
+
+msgid "version "
+msgstr "versione "
+
+msgid "by Bram Moolenaar et al."
+msgstr "di Bram Moolenaar et al."
+
+msgid "Vim is open source and freely distributable"
+msgstr "Vim è 'open source' e può essere distribuito liberamente"
+
+msgid "Help poor children in Uganda!"
+msgstr "Aiuta i bambini poveri dell'Uganda!"
+
+msgid "type :help iccf<Enter> for information "
+msgstr "batti :help iccf<Invio> per informazioni "
+
+msgid "type :q<Enter> to exit "
+msgstr "batti :q<Invio> per uscire "
+
+msgid "type :help<Enter> or <F1> for on-line help"
+msgstr "batti :help<Invio> o <F1> per aiuto online "
+
+msgid "type :help version8<Enter> for version info"
+msgstr "batti :help version8<Invio> per informazioni su versione"
+
+msgid "Running in Vi compatible mode"
+msgstr "Eseguo in modalità compatibile Vi"
+
+msgid "type :set nocp<Enter> for Vim defaults"
+msgstr "batti :set nocp<Invio> per valori predefiniti Vim"
+
+msgid "type :help cp-default<Enter> for info on this"
+msgstr "batti :help cp-default<Enter> per info al riguardo"
+
+msgid "menu Help->Orphans for information "
+msgstr "menu Aiuto->Orfani per informazioni "
+
+msgid "Running modeless, typed text is inserted"
+msgstr "Esecuzione senza modalità: solo inserimento"
+
+msgid "menu Edit->Global Settings->Toggle Insert Mode "
+msgstr "menu Modifica->Impost.Globali->Modal.Inser. Sì/No"
+
+msgid " for two modes "
+msgstr " per modo Inser./Comandi"
+
+msgid "menu Edit->Global Settings->Toggle Vi Compatible"
+msgstr "menu Modifica->Impost.Globali->Compatibile Vi Sì/No"
+
+msgid " for Vim defaults "
+msgstr " modo Vim predefinito "
+
+msgid "Sponsor Vim development!"
+msgstr "Sponsorizza lo sviluppo di Vim!"
+
+msgid "Become a registered Vim user!"
+msgstr "Diventa un utente Vim registrato!"
+
+msgid "type :help sponsor<Enter> for information "
+msgstr "batti :help sponsor<Invio> per informazioni "
+
+msgid "type :help register<Enter> for information "
+msgstr "batti :help register<Invio> per informazioni "
+
+msgid "menu Help->Sponsor/Register for information "
+msgstr "menu Aiuto->Sponsor/Registrazione per informazioni "
+
+msgid "Already only one window"
+msgstr "C'è già una finestra sola"
+
+msgid "E441: There is no preview window"
+msgstr "E441: Non c'è una finestra di pre-visualizzazione"
+
+msgid "E442: Can't split topleft and botright at the same time"
+msgstr "E442: Non riesco a dividere ALTO-SX e BASSO-DX contemporaneamente"
+
+msgid "E443: Cannot rotate when another window is split"
+msgstr "E443: Non posso ruotare quando un'altra finestra è divisa in due"
+
+msgid "E444: Cannot close last window"
+msgstr "E444: Non riesco a chiudere l'ultima finestra"
+
+msgid "E813: Cannot close autocmd window"
+msgstr "E813: Non riesco a chiudere la finestra autocomandi"
+
+msgid "E814: Cannot close window, only autocmd window would remain"
+msgstr ""
+"E814: Non posso chiudere questa finestra, rimarrebbe solo la finestra "
+"autocomandi"
+
+msgid "E445: Other window contains changes"
+msgstr "E445: Altre finestre contengono modifiche"
+
+msgid "E446: No file name under cursor"
+msgstr "E446: Nessun nome file sotto il cursore"
+
+msgid "E447: Can't find file \"%s\" in path"
+msgstr "E447: Non riesco a trovare il file \"%s\" nel percorso"
+
+msgid "E799: Invalid ID: %ld (must be greater than or equal to 1)"
+msgstr "E799: ID non valido: %ld (dev'essere maggiore o uguale a 1)"
+
+msgid "E801: ID already taken: %ld"
+msgstr "E801: ID già utilizzato: %ld"
+
+msgid "List or number required"
+msgstr "È necessaria una Lista o un numero"
+
+msgid "E802: Invalid ID: %ld (must be greater than or equal to 1)"
+msgstr "E802: ID non valido: %ld (dev'essere maggiore o uguale a 1)"
+
+msgid "E803: ID not found: %ld"
+msgstr "E803: ID non trovato: %ld"
+
+msgid "E370: Could not load library %s"
+msgstr "E370: Non riesco a caricare la libreria %s"
+
+msgid "Sorry, this command is disabled: the Perl library could not be loaded."
+msgstr ""
+"Spiacente, comando non disponibile, non riesco a caricare libreria programmi "
+"Perl."
+
+msgid "E299: Perl evaluation forbidden in sandbox without the Safe module"
+msgstr ""
+"E299: Valorizzazione Perl vietata in ambiente protetto senza il modulo Safe"
+
+msgid "Edit with &multiple Vims"
+msgstr "Apri con &molti Vim"
+
+msgid "Edit with single &Vim"
+msgstr "Apri con un solo &Vim"
+
+msgid "Diff with Vim"
+msgstr "Differenza con Vim"
+
+msgid "Edit with &Vim"
+msgstr "Apri con &Vim"
+
+msgid "Edit with existing Vim - "
+msgstr "Apri con Vim esistente - "
+
+msgid "Edits the selected file(s) with Vim"
+msgstr "Apri i(l) file scelto(i) con Vim"
+
+msgid "Error creating process: Check if gvim is in your path!"
+msgstr ""
+"Errore creando il processo: Controllate che gvim sia incluso nel vostro "
+"percorso (PATH)"
+
+msgid "gvimext.dll error"
+msgstr "errore gvimext.dll"
+
+msgid "Path length too long!"
+msgstr "Percorso file troppo lungo!"
+
+msgid "--No lines in buffer--"
+msgstr "--File vuoto--"
+
+msgid "E470: Command aborted"
+msgstr "E470: Comando finito male"
+
+msgid "E471: Argument required"
+msgstr "E471: Argomento necessario"
+
+msgid "E10: \\ should be followed by /, ? or &"
+msgstr "E10: \\ dovrebbe essere seguito da /, ? oppure &"
+
+msgid "E11: Invalid in command-line window; <CR> executes, CTRL-C quits"
+msgstr "E11: Non valido nella finestra comandi; <INVIO> esegue, CTRL-C ignora"
+
+msgid "E12: Command not allowed from exrc/vimrc in current dir or tag search"
+msgstr ""
+"E12: Comando non ammesso da exrc/vimrc nella dir. in uso o nella ricerca tag"
+
+msgid "E171: Missing :endif"
+msgstr "E171: Manca :endif"
+
+msgid "E600: Missing :endtry"
+msgstr "E600: Manca :endtry"
+
+msgid "E170: Missing :endwhile"
+msgstr "E170: Manca :endwhile"
+
+msgid "E170: Missing :endfor"
+msgstr "E170: Manca :endfor"
+
+msgid "E588: :endwhile without :while"
+msgstr "E588: :endwhile senza :while"
+
+msgid "E588: :endfor without :for"
+msgstr "E588: :endfor senza :for"
+
+msgid "E13: File exists (add ! to override)"
+msgstr "E13: File esistente (aggiungi ! per riscriverlo)"
+
+msgid "E472: Command failed"
+msgstr "E472: Comando fallito"
+
+msgid "E234: Unknown fontset: %s"
+msgstr "E234: Fontset sconosciuto: %s"
+
+msgid "E235: Unknown font: %s"
+msgstr "E235: Font sconosciuto: %s"
+
+msgid "E236: Font \"%s\" is not fixed-width"
+msgstr "E236: Font \"%s\" non di larghezza fissa"
+
+msgid "E473: Internal error"
+msgstr "E473: Errore interno"
+
+msgid "E685: Internal error: %s"
+msgstr "E685: Errore interno: %s"
+
+msgid "Interrupted"
+msgstr "Interrotto"
+
+msgid "E14: Invalid address"
+msgstr "E14: Indirizzo non valido"
+
+msgid "E474: Invalid argument"
+msgstr "E474: Argomento non valido"
+
+msgid "E475: Invalid argument: %s"
+msgstr "E475: Argomento non valido: %s"
+
+msgid "E475: Invalid value for argument %s"
+msgstr "E475: Valore non valido per l'argomento %s"
+
+msgid "E475: Invalid value for argument %s: %s"
+msgstr "E475: Valore non valido per l'argomento %s: %s"
+
+msgid "E15: Invalid expression: %s"
+msgstr "E15: Espressione non valida: %s"
+
+msgid "E16: Invalid range"
+msgstr "E16: Intervallo non valido"
+
+msgid "E476: Invalid command"
+msgstr "E476: Comando non valido"
+
+msgid "E17: \"%s\" is a directory"
+msgstr "E17: \"%s\" è una directory"
+
+msgid "E364: Library call failed for \"%s()\""
+msgstr "E364: Chiamata a libreria fallita per \"%s()\""
+
+msgid "E667: Fsync failed"
+msgstr "E667: Fsync fallito"
+
+msgid "E448: Could not load library function %s"
+msgstr "E448: Non posso caricare la funzione di libreria %s"
+
+msgid "E19: Mark has invalid line number"
+msgstr "E19: 'Mark' con numero riga non valido"
+
+msgid "E20: Mark not set"
+msgstr "E20: 'Mark' non impostato"
+
+msgid "E21: Cannot make changes, 'modifiable' is off"
+msgstr "E21: Non posso fare modifiche, 'modifiable' è inibito"
+
+msgid "E22: Scripts nested too deep"
+msgstr "E22: Script troppo nidificati"
+
+msgid "E23: No alternate file"
+msgstr "E23: Nessun file alternato"
+
+msgid "E24: No such abbreviation"
+msgstr "E24: Abbreviazione inesistente"
+
+msgid "E477: No ! allowed"
+msgstr "E477: ! non consentito"
+
+msgid "E25: GUI cannot be used: Not enabled at compile time"
+msgstr "E25: GUI non utilizzabile: Non abilitata in compilazione"
+
+msgid "E26: Hebrew cannot be used: Not enabled at compile time\n"
+msgstr "E26: Ebraico non utilizzabile: Non abilitato in compilazione\n"
+
+msgid "E27: Farsi cannot be used: Not enabled at compile time\n"
+msgstr "E27: Farsi non utilizzabile: Non abilitato in compilazione\n"
+
+msgid "E800: Arabic cannot be used: Not enabled at compile time\n"
+msgstr "E800: Arabo non utilizzabile: Non abilitato in compilazione\n"
+
+msgid "E28: No such highlight group name: %s"
+msgstr "E28: Nome di gruppo di evidenziazione inesistente: %s"
+
+msgid "E29: No inserted text yet"
+msgstr "E29: Ancora nessun testo inserito"
+
+msgid "E30: No previous command line"
+msgstr "E30: Nessuna riga comandi precedente"
+
+msgid "E31: No such mapping"
+msgstr "E31: Mapping inesistente"
+
+msgid "E479: No match"
+msgstr "E479: Nessuna corrispondenza"
+
+msgid "E480: No match: %s"
+msgstr "E480: Nessuna corrispondenza: %s"
+
+msgid "E32: No file name"
+msgstr "E32: Manca nome file"
+
+msgid "E33: No previous substitute regular expression"
+msgstr "E33: Nessuna espressione regolare precedente di 'substitute'"
+
+msgid "E34: No previous command"
+msgstr "E34: Nessun comando precedente"
+
+msgid "E35: No previous regular expression"
+msgstr "E35: Nessuna espressione regolare precedente"
+
+msgid "E481: No range allowed"
+msgstr "E481: Nessun intervallo consentito"
+
+msgid "E36: Not enough room"
+msgstr "E36: Manca spazio"
+
+msgid "E247: no registered server named \"%s\""
+msgstr "E247: non esiste server registrato con nome \"%s\""
+
+msgid "E482: Can't create file %s"
+msgstr "E482: Non riesco a creare il file %s"
+
+msgid "E483: Can't get temp file name"
+msgstr "E483: Non riesco ad ottenere nome file 'temp'"
+
+msgid "E484: Can't open file %s"
+msgstr "E484: Non riesco ad aprire il file %s"
+
+msgid "E485: Can't read file %s"
+msgstr "E485: Non riesco a leggere il file %s"
+
+msgid "E38: Null argument"
+msgstr "E38: Argomento nullo"
+
+msgid "E39: Number expected"
+msgstr "E39: Mi aspettavo un numero"
+
+msgid "E40: Can't open errorfile %s"
+msgstr "E40: Non riesco ad aprire il file errori %s"
+
+msgid "E233: cannot open display"
+msgstr "E233: non riesco ad aprire lo schermo"
+
+msgid "E41: Out of memory!"
+msgstr "E41: Non c'è più memoria!"
+
+msgid "Pattern not found"
+msgstr "Espressione non trovata"
+
+msgid "E486: Pattern not found: %s"
+msgstr "E486: Espressione non trovata: %s"
+
+msgid "E487: Argument must be positive"
+msgstr "E487: L'argomento deve essere positivo"
+
+msgid "E459: Cannot go back to previous directory"
+msgstr "E459: Non posso tornare alla directory precedente"
+
+msgid "E42: No Errors"
+msgstr "E42: Nessun Errore"
+
+msgid "E776: No location list"
+msgstr "E776: Nessuna lista locazioni"
+
+msgid "E43: Damaged match string"
+msgstr "E43: Stringa di confronto danneggiata"
+
+msgid "E44: Corrupted regexp program"
+msgstr "E44: Programma 'regexp' corrotto"
+
+msgid "E45: 'readonly' option is set (add ! to override)"
+msgstr "E45: file in sola lettura (aggiungi ! per eseguire comunque)"
+
+msgid "E46: Cannot change read-only variable \"%s\""
+msgstr "E46: Non posso cambiare la variabile read-only \"%s\""
+
+msgid "E794: Cannot set variable in the sandbox: \"%s\""
+msgstr ""
+"E794: Non posso impostare la variabile read-only in ambiente protetto: \"%s\""
+
+msgid "E713: Cannot use empty key for Dictionary"
+msgstr "E713: Non posso usare una chiave nulla per il Dizionario"
+
+msgid "E715: Dictionary required"
+msgstr "E715: È necessario un Dizionario"
+
+msgid "E684: list index out of range: %ld"
+msgstr "E684: indice lista fuori intervallo: %ld"
+
+msgid "E118: Too many arguments for function: %s"
+msgstr "E118: Troppi argomenti per la funzione: %s"
+
+msgid "E716: Key not present in Dictionary: %s"
+msgstr "E716: Chiave assente dal Dizionario: %s"
+
+msgid "E714: List required"
+msgstr "E714: È necessaria una Lista"
+
+msgid "E712: Argument of %s must be a List or Dictionary"
+msgstr "E712: L'argomento di %s deve essere una Lista o un Dizionario"
+
+msgid "E47: Error while reading errorfile"
+msgstr "E47: Errore leggendo il file errori"
+
+msgid "E48: Not allowed in sandbox"
+msgstr "E48: Non ammesso in ambiente protetto"
+
+msgid "E523: Not allowed here"
+msgstr "E523: Non consentito qui"
+
+msgid "E359: Screen mode setting not supported"
+msgstr "E359: Impostazione modalità schermo non supportata"
+
+msgid "E49: Invalid scroll size"
+msgstr "E49: Quantità di 'scroll' non valida"
+
+msgid "E91: 'shell' option is empty"
+msgstr "E91: opzione 'shell' non impostata"
+
+msgid "E255: Couldn't read in sign data!"
+msgstr "E255: Errore -- non sono riuscito a leggere i dati del 'sign'!"
+
+msgid "E72: Close error on swap file"
+msgstr "E72: Errore durante chiusura swap file"
+
+msgid "E73: tag stack empty"
+msgstr "E73: tag stack ancora vuoto"
+
+msgid "E74: Command too complex"
+msgstr "E74: Comando troppo complesso"
+
+msgid "E75: Name too long"
+msgstr "E75: Nome troppo lungo"
+
+msgid "E76: Too many ["
+msgstr "E76: Troppe ["
+
+msgid "E77: Too many file names"
+msgstr "E77: Troppi nomi file"
+
+msgid "E488: Trailing characters"
+msgstr "E488: Caratteri in più a fine comando"
+
+msgid "E78: Unknown mark"
+msgstr "E78: 'Mark' sconosciuto"
+
+msgid "E79: Cannot expand wildcards"
+msgstr "E79: Non posso espandere 'wildcard'"
+
+msgid "E591: 'winheight' cannot be smaller than 'winminheight'"
+msgstr "E591: 'winheight' non può essere inferiore a 'winminheight'"
+
+msgid "E592: 'winwidth' cannot be smaller than 'winminwidth'"
+msgstr "E592: 'winwidth' non può essere inferiore a 'winminwidth'"
+
+msgid "E80: Error while writing"
+msgstr "E80: Errore in scrittura"
+
+msgid "E939: Positive count required"
+msgstr "E939: Un contatore positivo è necessario"
+
+msgid "E81: Using <SID> not in a script context"
+msgstr "E81: Uso di <SID> fuori dal contesto di uno script"
+
+msgid "E449: Invalid expression received"
+msgstr "E449: Ricevuta un'espressione non valida"
+
+msgid "E463: Region is guarded, cannot modify"
+msgstr "E463: Regione protetta, impossibile modificare"
+
+msgid "E744: NetBeans does not allow changes in read-only files"
+msgstr "E744: NetBeans non permette modifiche a file di sola lettura"
+
+msgid "E363: pattern uses more memory than 'maxmempattern'"
+msgstr "E363: l'espressione usa troppa memoria rispetto a 'maxmempattern'"
+
+msgid "E749: empty buffer"
+msgstr "E749: buffer vuoto"
+
+msgid "E86: Buffer %ld does not exist"
+msgstr "E86: Non esiste il buffer %ld"
+
+msgid "E682: Invalid search pattern or delimiter"
+msgstr "E682: Espressione o delimitatore di ricerca non validi"
+
+msgid "E139: File is loaded in another buffer"
+msgstr "E139: File già caricato in un altro buffer"
+
+msgid "E764: Option '%s' is not set"
+msgstr "E764: opzione '%s' non impostata"
+
+msgid "E850: Invalid register name"
+msgstr "E850: Nome registro non valido"
+
+msgid "E919: Directory not found in '%s': \"%s\""
+msgstr "E919: Directory non trovata in '%s': \"%s\""
+
+msgid "E952: Autocommand caused recursive behavior"
+msgstr "E952: L'autocomando ha generato un comportamento ricorsivo"
+
+msgid "search hit TOP, continuing at BOTTOM"
+msgstr "raggiunta la CIMA nella ricerca, continuo dal FONDO"
+
+msgid "search hit BOTTOM, continuing at TOP"
+msgstr "raggiunto il FONDO nella ricerca, continuo dalla CIMA"
+
+msgid "Need encryption key for \"%s\""
+msgstr "Serve una chiave di cifratura per \"%s\""
+
+msgid "empty keys are not allowed"
+msgstr "chiavi nulle non consentite"
+
+msgid "dictionary is locked"
+msgstr "il dizionario è bloccato"
+
+msgid "list is locked"
+msgstr "la lista è bloccata"
+
+msgid "failed to add key '%s' to dictionary"
+msgstr "non non riusciato ad aggiungere la chiave '%s' al dizionario"
+
+msgid "index must be int or slice, not %s"
+msgstr "l'indice deve'essere un intero o un intervallo, non %s"
+
+msgid "expected str() or unicode() instance, but got %s"
+msgstr "attesa istanza di str() o unicode(), trovato invece %s"
+
+msgid "expected bytes() or str() instance, but got %s"
+msgstr "attesa istanza di bytes() o str(), trovato invece %s"
+
+msgid ""
+"expected int(), long() or something supporting coercing to long(), but got %s"
+msgstr ""
+"atteso int(), long() o qualcosa che supporti forzatura a long(), trovato "
+"invece %s"
+
+msgid "expected int() or something supporting coercing to int(), but got %s"
+msgstr ""
+"atteso int() o qualcosa che supporti forzatura a int(), trovato invece %s"
+
+msgid "value is too large to fit into C int type"
+msgstr "valore troppo grande per il tipo int del C"
+
+msgid "value is too small to fit into C int type"
+msgstr "valore troppo piccolo per il tipo int del C"
+
+msgid "number must be greater than zero"
+msgstr "il numero deve essere maggiore di zero"
+
+msgid "number must be greater or equal to zero"
+msgstr "il numero dev'essere maggiore o uguale a zero"
+
+msgid "can't delete OutputObject attributes"
+msgstr "non riesco a cancellare gli attributi OutputObject"
+
+msgid "invalid attribute: %s"
+msgstr "attributo non valido: %s"
+
+msgid "E264: Python: Error initialising I/O objects"
+msgstr "E264: Python: Errore di inizializzazione oggetti I/O"
+
+msgid "failed to change directory"
+msgstr "cambio directory non riuscito"
+
+msgid "expected 3-tuple as imp.find_module() result, but got %s"
+msgstr "atteso terzetto come risultato di imp.find_module(), trovato invece %s"
+
+msgid "expected 3-tuple as imp.find_module() result, but got tuple of size %d"
+msgstr ""
+"atteso terzetto come risultato di imp.find_module(), trovato invece tuple di "
+"dimens. %d"
+
+msgid "internal error: imp.find_module returned tuple with NULL"
+msgstr "errore interno: imp.find_module restituisce tuple con NULL"
+
+msgid "cannot delete vim.Dictionary attributes"
+msgstr "non riesco a cancellare gli attributi vim.Dictionary"
+
+msgid "cannot modify fixed dictionary"
+msgstr "non posso modificare il dizionario fisso"
+
+msgid "cannot set attribute %s"
+msgstr "non posso impostare attributo %s"
+
+msgid "hashtab changed during iteration"
+msgstr "hashtab cambiato durante l'iterazione"
+
+msgid "expected sequence element of size 2, but got sequence of size %d"
+msgstr ""
+"atteso elemento sequenza di dimensione 2, trovata sequenza di dimensione %d"
+
+msgid "list constructor does not accept keyword arguments"
+msgstr "il costruttore di lista non accetta parole chiave come argomenti"
+
+msgid "list index out of range"
+msgstr "indice di lista non nell'intervallo"
+
+msgid "internal error: failed to get vim list item %d"
+msgstr "errore interno: non ho potuto ottenere l'elemento di vim list %d"
+
+msgid "slice step cannot be zero"
+msgstr "il passo scorrendo un intervallo non può essere zero"
+
+msgid "attempt to assign sequence of size greater than %d to extended slice"
+msgstr ""
+"tentativo di assegnare una sequenza maggiore di %d a un intervallo esteso"
+
+msgid "internal error: no vim list item %d"
+msgstr "errore interno: non c'è un elemento di vim list %d"
+
+msgid "internal error: not enough list items"
+msgstr "errore interno: non ci sono abbastanza elementi per la lista"
+
+msgid "internal error: failed to add item to list"
+msgstr "errore interno: non ho potuto aggiungere un elemento alla lista"
+
+msgid "attempt to assign sequence of size %d to extended slice of size %d"
+msgstr ""
+"tentativo di assegnare sequenza di dimensione %d a un intervallo esteso di "
+"dimensione %d"
+
+msgid "failed to add item to list"
+msgstr "non ho potuto aggiungere un elemento alla lista"
+
+msgid "cannot delete vim.List attributes"
+msgstr "non riesco a cancellare gli attributi vim.List"
+
+msgid "cannot modify fixed list"
+msgstr "non posso modificare la lista fissa"
+
+msgid "unnamed function %s does not exist"
+msgstr "la funzione anonima %s non esiste"
+
+msgid "function %s does not exist"
+msgstr "la funzione %s non esiste"
+
+msgid "failed to run function %s"
+msgstr "esecuzione non riuscita della funzione %s"
+
+msgid "unable to get option value"
+msgstr "impossibile ottenere il valore di opzione"
+
+msgid "internal error: unknown option type"
+msgstr "errore interno: tipo di opzione sconosciuto"
+
+msgid "problem while switching windows"
+msgstr "problema nel cambio finestra"
+
+msgid "unable to unset global option %s"
+msgstr "impossibile deimpostare l'opzione globale %s"
+
+msgid "unable to unset option %s which does not have global value"
+msgstr "impossibile deimpostare l'opzione %s che non ha un valore globale"
+
+msgid "attempt to refer to deleted tab page"
+msgstr "tentativo di riferimento a linguetta cancellata"
+
+msgid "no such tab page"
+msgstr "linguetta inesistente"
+
+msgid "attempt to refer to deleted window"
+msgstr "tentativo di riferimento a una finestra cancellata"
+
+msgid "readonly attribute: buffer"
+msgstr "attributo in sola lettura: buffer"
+
+msgid "cursor position outside buffer"
+msgstr "posizione cursore fuori dal buffer"
+
+msgid "no such window"
+msgstr "finestra inesistente"
+
+msgid "attempt to refer to deleted buffer"
+msgstr "tentativo di riferimento a buffer cancellato"
+
+msgid "failed to rename buffer"
+msgstr "cambio nome buffer non riuscito"
+
+msgid "mark name must be a single character"
+msgstr "il nome mark dev'essere un carattere singolo"
+
+msgid "expected vim.Buffer object, but got %s"
+msgstr "atteso oggetto vim.Buffer, trovato %s"
+
+msgid "failed to switch to buffer %d"
+msgstr "passaggio non riuscito al buffer %d"
+
+msgid "expected vim.Window object, but got %s"
+msgstr "atteso oggetto vim.Window, trovato %s"
+
+msgid "failed to find window in the current tab page"
+msgstr ""
+"non è stato possibile trovare la finestra nella pagina con linguette corrente"
+
+msgid "did not switch to the specified window"
+msgstr "passaggio alla finestra specificata non effettuato"
+
+msgid "expected vim.TabPage object, but got %s"
+msgstr "atteso oggetto vim.TabPage, trovato %s"
+
+msgid "did not switch to the specified tab page"
+msgstr "passaggio alla linguetta specificata non effettuato"
+
+msgid "failed to run the code"
+msgstr "esecuzione del codice non riuscita"
+
+msgid "E858: Eval did not return a valid python object"
+msgstr "E858: Eval non ha restituito un oggetto python valido"
+
+msgid "E859: Failed to convert returned python object to vim value"
+msgstr ""
+"E859: Conversione non riuscita dell'oggetto python risultato a un valore vim"
+
+msgid "unable to convert %s to vim dictionary"
+msgstr "impossibile convertire %s a dizionario vim"
+
+msgid "unable to convert %s to vim list"
+msgstr "impossibile convertire %s a Lista vim"
+
+msgid "unable to convert %s to vim structure"
+msgstr "impossibile convertire %s a struttura vim"
+
+msgid "internal error: NULL reference passed"
+msgstr "errore interno: passato riferimento NULL"
+
+msgid "internal error: invalid value type"
+msgstr "errore interno: tipo di valore non valido"
+
+msgid ""
+"Failed to set path hook: sys.path_hooks is not a list\n"
+"You should now do the following:\n"
+"- append vim.path_hook to sys.path_hooks\n"
+"- append vim.VIM_SPECIAL_PATH to sys.path\n"
+msgstr ""
+"Impostazione dell'ancora di percorso non riuscita: sys.path_hooks non è una "
+"lista\n"
+"Dovresti fare così:\n"
+"- aggiungere vim.path_hook a vim.path_hooks\n"
+"- aggiungere vim.VIM_SPECIAL_PATH a sys.path\n"
+
+msgid ""
+"Failed to set path: sys.path is not a list\n"
+"You should now append vim.VIM_SPECIAL_PATH to sys.path"
+msgstr ""
+"Impostazione di percorso non riuscita: sys.path non è una Lista\n"
+"Dovresti aggiungere vim.VIM_SPECIAL_PATH a sys.path"
+
+msgid ""
+"Vim macro files (*.vim)\t*.vim\n"
+"All Files (*.*)\t*.*\n"
+msgstr ""
+"Vim macro file (*.vim)\t*.vim\n"
+"Tutti i file (*.*)\t*.*\n"
+
+msgid "All Files (*.*)\t*.*\n"
+msgstr "Tutti i file (*.*)\t*.*\n"
+
+msgid ""
+"All Files (*.*)\t*.*\n"
+"C source (*.c, *.h)\t*.c;*.h\n"
+"C++ source (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"VB code (*.bas, *.frm)\t*.bas;*.frm\n"
+"Vim files (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
+msgstr ""
+"Tutti i file (*.*)\t*.*\n"
+"Sorgenti C (*.c, *.h)\t*.c;*.h\n"
+"Sorgenti C++ (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"Codice VB (*.bas, *.frm)\t*.bas;*.frm\n"
+"File di Vim (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
+
+msgid ""
+"Vim macro files (*.vim)\t*.vim\n"
+"All Files (*)\t*\n"
+msgstr ""
+"Vim macro file (*.vim)\t*.vim\n"
+"Tutti i file (*)\t*\n"
+
+msgid "All Files (*)\t*\n"
+msgstr "Tutti i file (*)\t*\n"
+
+msgid ""
+"All Files (*)\t*\n"
+"C source (*.c, *.h)\t*.c;*.h\n"
+"C++ source (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"Vim files (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
+msgstr ""
+"Tutti i file (*)\t*\n"
+"Sorgenti C (*.c, *.h)\t*.c;*.h\n"
+"Sorgenti C++ (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"File di Vim (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
diff --git a/src/po/ja.euc-jp.po b/src/po/ja.euc-jp.po
new file mode 100644
index 0000000..4759103
--- /dev/null
+++ b/src/po/ja.euc-jp.po
@@ -0,0 +1,7068 @@
+# Japanese translation for Vim
+#
+# Do ":help uganda" in Vim to read copying and usage conditions.
+# Do ":help credits" in Vim to see a list of people who contributed.
+#
+# Copyright (C) 2001-2018 MURAOKA Taro <koron.kaoriya@gmail.com>,
+# vim-jp <http://vim-jp.org/>
+#
+# THIS FILE IS DISTRIBUTED UNDER THE VIM LICENSE.
+#
+# Generated from ja.po, DO NOT EDIT.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Vim 8.1\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2018-11-13 19:44+0900\n"
+"PO-Revision-Date: 2018-11-16 09:41+0900\n"
+"Last-Translator: MURAOKA Taro <koron.kaoriya@gmail.com>\n"
+"Language-Team: Japanese <https://github.com/vim-jp/lang-ja>\n"
+"Language: ja\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=euc-jp\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+
+msgid "E831: bf_key_init() called with empty password"
+msgstr "E831: bf_key_init() ¤¬¶õ¥Ñ¥¹¥ï¡¼¥É¤Ç¸Æ¤Ó½Ð¤µ¤ì¤Þ¤·¤¿"
+
+msgid "E820: sizeof(uint32_t) != 4"
+msgstr "E820: sizeof(uint32_t) != 4"
+
+msgid "E817: Blowfish big/little endian use wrong"
+msgstr "E817: Blowfish°Å¹æ¤Î¥Ó¥Ã¥°/¥ê¥È¥ë¥¨¥ó¥Ç¥£¥¢¥ó¤¬´Ö°ã¤Ã¤Æ¤¤¤Þ¤¹"
+
+msgid "E818: sha256 test failed"
+msgstr "E818: sha256¤Î¥Æ¥¹¥È¤Ë¼ºÇÔ¤·¤Þ¤·¤¿"
+
+msgid "E819: Blowfish test failed"
+msgstr "E819: Blowfish°Å¹æ¤Î¥Æ¥¹¥È¤Ë¼ºÇÔ¤·¤Þ¤·¤¿"
+
+msgid "[Location List]"
+msgstr "[¥í¥±¡¼¥·¥ç¥ó¥ê¥¹¥È]"
+
+msgid "[Quickfix List]"
+msgstr "[Quickfix¥ê¥¹¥È]"
+
+msgid "E855: Autocommands caused command to abort"
+msgstr "E855: autocommand¤¬¥³¥Þ¥ó¥É¤ÎÄä»ß¤ò°ú¤­µ¯¤³¤·¤Þ¤·¤¿"
+
+msgid "E82: Cannot allocate any buffer, exiting..."
+msgstr "E82: ¥Ð¥Ã¥Õ¥¡¤ò1¤Ä¤âºîÀ®¤Ç¤­¤Ê¤¤¤Î¤Ç¡¢½ªÎ»¤·¤Þ¤¹..."
+
+msgid "E83: Cannot allocate buffer, using other one..."
+msgstr "E83: ¥Ð¥Ã¥Õ¥¡¤òºîÀ®¤Ç¤­¤Ê¤¤¤Î¤Ç¡¢Â¾¤Î¤ò»ÈÍѤ·¤Þ¤¹..."
+
+msgid "E931: Buffer cannot be registered"
+msgstr "E931: ¥Ð¥Ã¥Õ¥¡¤òÅÐÏ¿¤Ç¤­¤Þ¤»¤ó"
+
+msgid "E937: Attempt to delete a buffer that is in use"
+msgstr "E937: »ÈÍÑÃæ¤Î¥Ð¥Ã¥Õ¥¡¤òºï½ü¤·¤è¤¦¤È»î¤ß¤Þ¤·¤¿"
+
+msgid "E515: No buffers were unloaded"
+msgstr "E515: ²òÊü¤µ¤ì¤¿¥Ð¥Ã¥Õ¥¡¤Ï¤¢¤ê¤Þ¤»¤ó"
+
+msgid "E516: No buffers were deleted"
+msgstr "E516: ºï½ü¤µ¤ì¤¿¥Ð¥Ã¥Õ¥¡¤Ï¤¢¤ê¤Þ¤»¤ó"
+
+msgid "E517: No buffers were wiped out"
+msgstr "E517: ÇË´þ¤µ¤ì¤¿¥Ð¥Ã¥Õ¥¡¤Ï¤¢¤ê¤Þ¤»¤ó"
+
+#, c-format
+msgid "%d buffer unloaded"
+msgid_plural "%d buffers unloaded"
+msgstr[0] "%d ¸Ä¤Î¥Ð¥Ã¥Õ¥¡¤¬²òÊü¤µ¤ì¤Þ¤·¤¿"
+
+#, c-format
+msgid "%d buffer deleted"
+msgid_plural "%d buffers deleted"
+msgstr[0] "%d ¸Ä¤Î¥Ð¥Ã¥Õ¥¡¤¬ºï½ü¤µ¤ì¤Þ¤·¤¿"
+
+#, c-format
+msgid "%d buffer wiped out"
+msgid_plural "%d buffers wiped out"
+msgstr[0] "%d ¸Ä¤Î¥Ð¥Ã¥Õ¥¡¤¬ÇË´þ¤µ¤ì¤Þ¤·¤¿"
+
+msgid "E90: Cannot unload last buffer"
+msgstr "E90: ºÇ¸å¤Î¥Ð¥Ã¥Õ¥¡¤Ï²òÊü¤Ç¤­¤Þ¤»¤ó"
+
+msgid "E84: No modified buffer found"
+msgstr "E84: Êѹ¹¤µ¤ì¤¿¥Ð¥Ã¥Õ¥¡¤Ï¤¢¤ê¤Þ¤»¤ó"
+
+msgid "E85: There is no listed buffer"
+msgstr "E85: ¥ê¥¹¥Èɽ¼¨¤µ¤ì¤ë¥Ð¥Ã¥Õ¥¡¤Ï¤¢¤ê¤Þ¤»¤ó"
+
+msgid "E87: Cannot go beyond last buffer"
+msgstr "E87: ºÇ¸å¤Î¥Ð¥Ã¥Õ¥¡¤ò±Û¤¨¤Æ°ÜÆ°¤Ï¤Ç¤­¤Þ¤»¤ó"
+
+msgid "E88: Cannot go before first buffer"
+msgstr "E88: ºÇ½é¤Î¥Ð¥Ã¥Õ¥¡¤è¤êÁ°¤Ø¤Ï°ÜÆ°¤Ç¤­¤Þ¤»¤ó"
+
+#, c-format
+msgid "E89: No write since last change for buffer %ld (add ! to override)"
+msgstr "E89: ¥Ð¥Ã¥Õ¥¡ %ld ¤ÎÊѹ¹¤ÏÊݸ¤µ¤ì¤Æ¤¤¤Þ¤»¤ó (! ¤ÇÊѹ¹¤òÇË´þ)"
+
+msgid "E948: Job still running (add ! to end the job)"
+msgstr "E948: ¥¸¥ç¥Ö¤Ï¤Þ¤À¼Â¹ÔÃæ¤Ç¤¹ (! ¤òÄɲäǥ¸¥ç¥Ö¤ò½ªÎ»)"
+
+msgid "E37: No write since last change (add ! to override)"
+msgstr "E37: ºÇ¸å¤ÎÊѹ¹¤¬Êݸ¤µ¤ì¤Æ¤¤¤Þ¤»¤ó (! ¤òÄɲäÇÊѹ¹¤òÇË´þ)"
+
+msgid "E948: Job still running"
+msgstr "E948: ¥¸¥ç¥Ö¤Ï¤Þ¤À¼Â¹ÔÃæ¤Ç¤¹"
+
+msgid "E37: No write since last change"
+msgstr "E37: ºÇ¸å¤ÎÊѹ¹¤¬Êݸ¤µ¤ì¤Æ¤¤¤Þ¤»¤ó"
+
+msgid "W14: Warning: List of file names overflow"
+msgstr "W14: ·Ù¹ð: ¥Õ¥¡¥¤¥ë̾¤Î¥ê¥¹¥È¤¬Ä¹²á¤®¤Þ¤¹"
+
+#, c-format
+msgid "E92: Buffer %ld not found"
+msgstr "E92: ¥Ð¥Ã¥Õ¥¡ %ld ¤¬¸«¤Ä¤«¤ê¤Þ¤»¤ó"
+
+#, c-format
+msgid "E93: More than one match for %s"
+msgstr "E93: %s ¤ËÊ£¿ô¤Î³ºÅö¤¬¤¢¤ê¤Þ¤·¤¿"
+
+#, c-format
+msgid "E94: No matching buffer for %s"
+msgstr "E94: %s ¤Ë³ºÅö¤¹¤ë¥Ð¥Ã¥Õ¥¡¤Ï¤¢¤ê¤Þ¤»¤ó¤Ç¤·¤¿"
+
+#, c-format
+msgid "line %ld"
+msgstr "¹Ô %ld"
+
+msgid "E95: Buffer with this name already exists"
+msgstr "E95: ¤³¤Î̾Á°¤Î¥Ð¥Ã¥Õ¥¡¤Ï´û¤Ë¤¢¤ê¤Þ¤¹"
+
+msgid " [Modified]"
+msgstr " [Êѹ¹¤¢¤ê]"
+
+msgid "[Not edited]"
+msgstr "[̤ÊÔ½¸]"
+
+msgid "[New file]"
+msgstr "[¿·¥Õ¥¡¥¤¥ë]"
+
+msgid "[Read errors]"
+msgstr "[Æɹþ¥¨¥é¡¼]"
+
+msgid "[RO]"
+msgstr "[ÆÉÀì]"
+
+msgid "[readonly]"
+msgstr "[ÆɹþÀìÍÑ]"
+
+#, c-format
+msgid "%ld line --%d%%--"
+msgid_plural "%ld lines --%d%%--"
+msgstr[0] "%ld ¹Ô --%d%%--"
+
+#, c-format
+msgid "line %ld of %ld --%d%%-- col "
+msgstr "¹Ô %ld (Á´ÂÎ %ld) --%d%%-- col "
+
+msgid "[No Name]"
+msgstr "[̵̾]"
+
+msgid "help"
+msgstr "¥Ø¥ë¥×"
+
+msgid "[Help]"
+msgstr "[¥Ø¥ë¥×]"
+
+msgid "[Preview]"
+msgstr "[¥×¥ì¥Ó¥å¡¼]"
+
+msgid "All"
+msgstr "Á´¤Æ"
+
+msgid "Bot"
+msgstr "ËöÈø"
+
+msgid "Top"
+msgstr "ÀèƬ"
+
+msgid ""
+"\n"
+"# Buffer list:\n"
+msgstr ""
+"\n"
+"# ¥Ð¥Ã¥Õ¥¡¥ê¥¹¥È:\n"
+
+msgid "E382: Cannot write, 'buftype' option is set"
+msgstr "E382: 'buftype' ¥ª¥×¥·¥ç¥ó¤¬ÀßÄꤵ¤ì¤Æ¤¤¤ë¤Î¤Ç½ñ¹þ¤á¤Þ¤»¤ó"
+
+msgid "[Prompt]"
+msgstr "[¥×¥í¥ó¥×¥È]"
+
+msgid "[Scratch]"
+msgstr "[²¼½ñ¤­]"
+
+msgid ""
+"\n"
+"--- Signs ---"
+msgstr ""
+"\n"
+"--- ¥µ¥¤¥ó ---"
+
+#, c-format
+msgid "Signs for %s:"
+msgstr "%s ¤Î¥µ¥¤¥ó:"
+
+#, c-format
+msgid " line=%ld id=%d name=%s"
+msgstr " ¹Ô=%ld ¼±ÊÌ»Ò=%d ̾Á°=%s"
+
+msgid "E902: Cannot connect to port"
+msgstr "E902: ¥Ý¡¼¥È¤ËÀܳ¤Ç¤­¤Þ¤»¤ó"
+
+msgid "E901: gethostbyname() in channel_open()"
+msgstr "E901: channel_open() Æâ¤Î gethostbyname() ¤¬¼ºÇÔ¤·¤Þ¤·¤¿"
+
+msgid "E898: socket() in channel_open()"
+msgstr "E898: channel_open() Æâ¤Î socket() ¤¬¼ºÇÔ¤·¤Þ¤·¤¿"
+
+msgid "E903: received command with non-string argument"
+msgstr "E903: Èóʸ»úÎó¤Î°ú¿ô¤Î¥³¥Þ¥ó¥É¤ò¼õ¿®¤·¤Þ¤·¤¿"
+
+msgid "E904: last argument for expr/call must be a number"
+msgstr "E904: expr/call ¤ÎºÇ¸å¤Î°ú¿ô¤Ï¿ô»ú¤Ç¤Ê¤±¤ì¤Ð¤Ê¤ê¤Þ¤»¤ó"
+
+msgid "E904: third argument for call must be a list"
+msgstr "E904: call ¤Î3ÈÖÌܤΰú¿ô¤Ï¥ê¥¹¥È·¿¤Ç¤Ê¤±¤ì¤Ð¤Ê¤ê¤Þ¤»¤ó"
+
+#, c-format
+msgid "E905: received unknown command: %s"
+msgstr "E905: ̤ÃΤΥ³¥Þ¥ó¥É¤ò¼õ¿®¤·¤Þ¤·¤¿: %s"
+
+#, c-format
+msgid "E630: %s(): write while not connected"
+msgstr "E630: %s(): ÈóÀܳ¾õÂ֤ǽñ¤­¹þ¤ß¤Þ¤·¤¿"
+
+#, c-format
+msgid "E631: %s(): write failed"
+msgstr "E631: %s(): ½ñ¤­¹þ¤ß¤Ë¼ºÇÔ¤·¤Þ¤·¤¿"
+
+#, c-format
+msgid "E917: Cannot use a callback with %s()"
+msgstr "E917: %s() ¤Ë¥³¡¼¥ë¥Ð¥Ã¥¯¤Ï»È¤¨¤Þ¤»¤ó"
+
+msgid "E912: cannot use ch_evalexpr()/ch_sendexpr() with a raw or nl channel"
+msgstr ""
+"E912: raw ¤ä nl ¥â¡¼¥É¤Î¥Á¥ã¥Í¥ë¤Ë ch_evalexpr()/ch_sendexpr() ¤Ï»È¤¨¤Þ¤»¤ó"
+
+msgid "E906: not an open channel"
+msgstr "E906: ³«¤¤¤Æ¤¤¤Ê¤¤¥Á¥ã¥Í¥ë¤Ç¤¹"
+
+msgid "E920: _io file requires _name to be set"
+msgstr "E920: _io ¥Õ¥¡¥¤¥ë¤Ï _name ¤ÎÀßÄ꤬ɬÍפǤ¹"
+
+msgid "E915: in_io buffer requires in_buf or in_name to be set"
+msgstr "E915: in_io ¥Ð¥Ã¥Õ¥¡¤Ï in_buf ¤« in_name ¤ÎÀßÄ꤬ɬÍפǤ¹"
+
+#, c-format
+msgid "E918: buffer must be loaded: %s"
+msgstr "E918: ¥Ð¥Ã¥Õ¥¡¤¬¥í¡¼¥É¤µ¤ì¤Æ¤Ê¤±¤ì¤Ð¤Ê¤ê¤Þ¤»¤ó: %s"
+
+msgid "E821: File is encrypted with unknown method"
+msgstr "E821: ¥Õ¥¡¥¤¥ë¤¬Ì¤ÃΤÎÊýË¡¤Ç°Å¹æ²½¤µ¤ì¤Æ¤¤¤Þ¤¹"
+
+msgid "Warning: Using a weak encryption method; see :help 'cm'"
+msgstr "·Ù¹ð: ¼å¤¤°Å¹æÊýË¡¤ò»È¤Ã¤Æ¤¤¤Þ¤¹; :help 'cm' ¤ò»²¾È¤·¤Æ¤¯¤À¤µ¤¤"
+
+msgid "Enter encryption key: "
+msgstr "°Å¹æ²½ÍѤΥ­¡¼¤òÆþÎϤ·¤Æ¤¯¤À¤µ¤¤: "
+
+msgid "Enter same key again: "
+msgstr "¤â¤¦°ìÅÙƱ¤¸¥­¡¼¤òÆþÎϤ·¤Æ¤¯¤À¤µ¤¤: "
+
+msgid "Keys don't match!"
+msgstr "¥­¡¼¤¬°ìÃפ·¤Þ¤»¤ó"
+
+msgid "[crypted]"
+msgstr "[°Å¹æ²½]"
+
+#, c-format
+msgid "E720: Missing colon in Dictionary: %s"
+msgstr "E720: ¼­½ñ·¿¤Ë¥³¥í¥ó¤¬¤¢¤ê¤Þ¤»¤ó: %s"
+
+#, c-format
+msgid "E721: Duplicate key in Dictionary: \"%s\""
+msgstr "E721: ¼­½ñ·¿¤Ë½ÅÊ£¥­¡¼¤¬¤¢¤ê¤Þ¤¹: \"%s\""
+
+#, c-format
+msgid "E722: Missing comma in Dictionary: %s"
+msgstr "E722: ¼­½ñ·¿¤Ë¥«¥ó¥Þ¤¬¤¢¤ê¤Þ¤»¤ó: %s"
+
+#, c-format
+msgid "E723: Missing end of Dictionary '}': %s"
+msgstr "E723: ¼­½ñ·¿¤ÎºÇ¸å¤Ë '}' ¤¬¤¢¤ê¤Þ¤»¤ó: %s"
+
+msgid "extend() argument"
+msgstr "extend() ¤Î°ú¿ô"
+
+#, c-format
+msgid "E737: Key already exists: %s"
+msgstr "E737: ¥­¡¼¤Ï´û¤Ë¸ºß¤·¤Þ¤¹: %s"
+
+#, c-format
+msgid "E96: Cannot diff more than %ld buffers"
+msgstr "E96: %ld °Ê¾å¤Î¥Ð¥Ã¥Õ¥¡¤Ïdiff¤Ç¤­¤Þ¤»¤ó"
+
+#, c-format
+msgid "Not enough memory to use internal diff for buffer \"%s\""
+msgstr "¥Ð¥Ã¥Õ¥¡ \"%s\" ÍѤËÆâÉôdiff¤ò»È¤¦¤¿¤á¤Î¥á¥â¥ê¤¬ÉÔ­¤·¤Æ¤¤¤Þ¤¹"
+
+msgid "E810: Cannot read or write temp files"
+msgstr "E810: °ì»þ¥Õ¥¡¥¤¥ë¤ÎÆɹþ¤â¤·¤¯¤Ï½ñ¹þ¤¬¤Ç¤­¤Þ¤»¤ó"
+
+msgid "E97: Cannot create diffs"
+msgstr "E97: º¹Ê¬¤òºîÀ®¤Ç¤­¤Þ¤»¤ó"
+
+msgid "E960: Problem creating the internal diff"
+msgstr "E960: ÆâÉôdiffºîÀ®»þ¤ËÌäÂ꤬ȯÀ¸¤·¤Þ¤·¤¿"
+
+msgid "Patch file"
+msgstr "¥Ñ¥Ã¥Á¥Õ¥¡¥¤¥ë"
+
+msgid "E816: Cannot read patch output"
+msgstr "E816: patch¤Î½ÐÎϤòÆɹþ¤á¤Þ¤»¤ó"
+
+msgid "E98: Cannot read diff output"
+msgstr "E98: diff¤Î½ÐÎϤòÆɹþ¤á¤Þ¤»¤ó"
+
+msgid "E959: Invalid diff format."
+msgstr "E959: ̵¸ú¤Êdiff·Á¼°¤Ç¤¹"
+
+msgid "E99: Current buffer is not in diff mode"
+msgstr "E99: ¸½ºß¤Î¥Ð¥Ã¥Õ¥¡¤Ïº¹Ê¬¥â¡¼¥É¤Ç¤Ï¤¢¤ê¤Þ¤»¤ó"
+
+msgid "E793: No other buffer in diff mode is modifiable"
+msgstr "E793: º¹Ê¬¥â¡¼¥É¤Ç¤¢¤ë¾¤Î¥Ð¥Ã¥Õ¥¡¤ÏÊѹ¹¤Ç¤­¤Þ¤»¤ó"
+
+msgid "E100: No other buffer in diff mode"
+msgstr "E100: º¹Ê¬¥â¡¼¥É¤Ç¤¢¤ë¾¤Î¥Ð¥Ã¥Õ¥¡¤Ï¤¢¤ê¤Þ¤»¤ó"
+
+msgid "E101: More than two buffers in diff mode, don't know which one to use"
+msgstr ""
+"E101: º¹Ê¬¥â¡¼¥É¤Î¥Ð¥Ã¥Õ¥¡¤¬2¸Ä°Ê¾å¤¢¤ë¤Î¤Ç¡¢¤É¤ì¤ò»È¤¦¤«ÆÃÄê¤Ç¤­¤Þ¤»¤ó"
+
+#, c-format
+msgid "E102: Can't find buffer \"%s\""
+msgstr "E102: ¥Ð¥Ã¥Õ¥¡ \"%s\" ¤¬¸«¤Ä¤«¤ê¤Þ¤»¤ó"
+
+#, c-format
+msgid "E103: Buffer \"%s\" is not in diff mode"
+msgstr "E103: ¥Ð¥Ã¥Õ¥¡ \"%s\" ¤Ïº¹Ê¬¥â¡¼¥É¤Ç¤Ï¤¢¤ê¤Þ¤»¤ó"
+
+msgid "E787: Buffer changed unexpectedly"
+msgstr "E787: ͽ´ü¤»¤º¥Ð¥Ã¥Õ¥¡¤¬Êѹ¹Êѹ¹¤µ¤ì¤Þ¤·¤¿"
+
+msgid "E104: Escape not allowed in digraph"
+msgstr "E104: ¹ç»ú¤ËEscape¤Ï»ÈÍѤǤ­¤Þ¤»¤ó"
+
+msgid "E544: Keymap file not found"
+msgstr "E544: ¥­¡¼¥Þ¥Ã¥×¥Õ¥¡¥¤¥ë¤¬¸«¤Ä¤«¤ê¤Þ¤»¤ó"
+
+msgid "E105: Using :loadkeymap not in a sourced file"
+msgstr "E105: :source ¤Ç¼è¹þ¤à¥Õ¥¡¥¤¥ë°Ê³°¤Ç¤Ï :loadkeymap ¤ò»È¤¨¤Þ¤»¤ó"
+
+msgid "E791: Empty keymap entry"
+msgstr "E791: ¶õ¤Î¥­¡¼¥Þ¥Ã¥×¥¨¥ó¥È¥ê"
+
+msgid " Keyword completion (^N^P)"
+msgstr " ¥­¡¼¥ï¡¼¥ÉÊä´° (^N^P)"
+
+msgid " ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+msgstr " ^X ¥â¡¼¥É (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+
+msgid " Whole line completion (^L^N^P)"
+msgstr " ¹Ô(Á´ÂÎ)Êä´° (^L^N^P)"
+
+msgid " File name completion (^F^N^P)"
+msgstr " ¥Õ¥¡¥¤¥ë̾Êä´° (^F^N^P)"
+
+msgid " Tag completion (^]^N^P)"
+msgstr " ¥¿¥°Êä´° (^]^N^P)"
+
+msgid " Path pattern completion (^N^P)"
+msgstr " ¥Ñ¥¹¥Ñ¥¿¡¼¥óÊä´° (^N^P)"
+
+msgid " Definition completion (^D^N^P)"
+msgstr " ÄêµÁÊä´° (^D^N^P)"
+
+msgid " Dictionary completion (^K^N^P)"
+msgstr " ¼­½ñÊä´° (^K^N^P)"
+
+msgid " Thesaurus completion (^T^N^P)"
+msgstr " ¥·¥½¡¼¥é¥¹Êä´° (^T^N^P)"
+
+msgid " Command-line completion (^V^N^P)"
+msgstr " ¥³¥Þ¥ó¥É¥é¥¤¥óÊä´° (^V^N^P)"
+
+msgid " User defined completion (^U^N^P)"
+msgstr " ¥æ¡¼¥¶¡¼ÄêµÁÊä´° (^U^N^P)"
+
+msgid " Omni completion (^O^N^P)"
+msgstr " ¥ª¥à¥ËÊä´° (^O^N^P)"
+
+msgid " Spelling suggestion (s^N^P)"
+msgstr " Ä֤꽤Àµ¸õÊä (s^N^P)"
+
+msgid " Keyword Local completion (^N^P)"
+msgstr " ¶É½ê¥­¡¼¥ï¡¼¥ÉÊä´° (^N^P)"
+
+msgid "Hit end of paragraph"
+msgstr "ÃÊÍî¤ÎºÇ¸å¤Ë¥Ò¥Ã¥È"
+
+msgid "E839: Completion function changed window"
+msgstr "E839: Êä´Ö´Ø¿ô¤¬¥¦¥£¥ó¥É¥¦¤òÊѹ¹¤·¤Þ¤·¤¿"
+
+msgid "E840: Completion function deleted text"
+msgstr "E840: Êä´°´Ø¿ô¤¬¥Æ¥­¥¹¥È¤òºï½ü¤·¤Þ¤·¤¿"
+
+msgid "'dictionary' option is empty"
+msgstr "'dictionary' ¥ª¥×¥·¥ç¥ó¤¬¶õ¤Ç¤¹"
+
+msgid "'thesaurus' option is empty"
+msgstr "'thesaurus' ¥ª¥×¥·¥ç¥ó¤¬¶õ¤Ç¤¹"
+
+#, c-format
+msgid "Scanning dictionary: %s"
+msgstr "¼­½ñ¤ò¥¹¥­¥ã¥óÃæ: %s"
+
+msgid " (insert) Scroll (^E/^Y)"
+msgstr " (ÁÞÆþ) ¥¹¥¯¥í¡¼¥ë(^E/^Y)"
+
+msgid " (replace) Scroll (^E/^Y)"
+msgstr " (ÃÖ´¹) ¥¹¥¯¥í¡¼¥ë (^E/^Y)"
+
+#, c-format
+msgid "Scanning: %s"
+msgstr "¥¹¥­¥ã¥óÃæ: %s"
+
+msgid "Scanning tags."
+msgstr "¥¿¥°¤ò¥¹¥­¥ã¥óÃæ."
+
+msgid "match in file"
+msgstr "¥Õ¥¡¥¤¥ëÆâ¤Î¥Þ¥Ã¥Á"
+
+msgid " Adding"
+msgstr " ÄɲÃÃæ"
+
+msgid "-- Searching..."
+msgstr "-- ¸¡º÷Ãæ..."
+
+msgid "Back at original"
+msgstr "»Ï¤á¤ËÌá¤ë"
+
+msgid "Word from other line"
+msgstr "¾¤Î¹Ô¤Îñ¸ì"
+
+msgid "The only match"
+msgstr "Í£°ì¤Î³ºÅö"
+
+#, c-format
+msgid "match %d of %d"
+msgstr "%d ÈÖÌܤγºÅö (Á´³ºÅö %d ¸ÄÃæ)"
+
+#, c-format
+msgid "match %d"
+msgstr "%d ÈÖÌܤγºÅö"
+
+msgid "E18: Unexpected characters in :let"
+msgstr "E18: ͽ´ü¤»¤Ìʸ»ú¤¬ :let ¤Ë¤¢¤ê¤Þ¤·¤¿"
+
+#, c-format
+msgid "E121: Undefined variable: %s"
+msgstr "E121: ̤ÄêµÁ¤ÎÊÑ¿ô¤Ç¤¹: %s"
+
+msgid "E111: Missing ']'"
+msgstr "E111: ']' ¤¬¸«¤Ä¤«¤ê¤Þ¤»¤ó"
+
+msgid "E719: Cannot use [:] with a Dictionary"
+msgstr "E719: [:] ¤ò¼­½ñ·¿¤ÈÁȤ߹ç¤ï¤»¤Æ¤Ï»È¤¨¤Þ¤»¤ó"
+
+#, c-format
+msgid "E734: Wrong variable type for %s="
+msgstr "E734: °Û¤Ê¤Ã¤¿·¿¤ÎÊÑ¿ô¤Ç¤¹ %s="
+
+#, c-format
+msgid "E461: Illegal variable name: %s"
+msgstr "E461: ÉÔÀµ¤ÊÊÑ¿ô̾¤Ç¤¹: %s"
+
+msgid "E806: using Float as a String"
+msgstr "E806: ÉâÆ°¾®¿ôÅÀ¿ô¤òʸ»úÎó¤È¤·¤Æ°·¤Ã¤Æ¤¤¤Þ¤¹"
+
+msgid "E687: Less targets than List items"
+msgstr "E687: ¥¿¡¼¥²¥Ã¥È¤¬¥ê¥¹¥È·¿Æâ¤ÎÍ×ÁǤè¤ê¤â¾¯¤Ê¤¤¤Ç¤¹"
+
+msgid "E688: More targets than List items"
+msgstr "E688: ¥¿¡¼¥²¥Ã¥È¤¬¥ê¥¹¥È·¿Æâ¤ÎÍ×ÁǤè¤ê¤â¿¤¤¤Ç¤¹"
+
+msgid "Double ; in list of variables"
+msgstr "¥ê¥¹¥È·¿¤ÎÃͤË2¤Ä°Ê¾å¤Î ; ¤¬¸¡½Ð¤µ¤ì¤Þ¤·¤¿"
+
+#, c-format
+msgid "E738: Can't list variables for %s"
+msgstr "E738: %s ¤ÎÃͤò°ìÍ÷ɽ¼¨¤Ç¤­¤Þ¤»¤ó"
+
+msgid "E689: Can only index a List or Dictionary"
+msgstr "E689: ¥ê¥¹¥È·¿¤È¼­½ñ·¿°Ê³°¤Ï¥¤¥ó¥Ç¥Ã¥¯¥¹»ØÄê¤Ç¤­¤Þ¤»¤ó"
+
+msgid "E708: [:] must come last"
+msgstr "E708: [:] ¤ÏºÇ¸å¤Ç¤Ê¤±¤ì¤Ð¤¤¤±¤Þ¤»¤ó"
+
+msgid "E709: [:] requires a List value"
+msgstr "E709: [:] ¤Ë¤Ï¥ê¥¹¥È·¿¤ÎÃͤ¬É¬ÍפǤ¹"
+
+msgid "E710: List value has more items than target"
+msgstr "E710: ¥ê¥¹¥È·¿ÊÑ¿ô¤Ë¥¿¡¼¥²¥Ã¥È¤è¤ê¤â¿¤¤Í×ÁǤ¬¤¢¤ê¤Þ¤¹"
+
+msgid "E711: List value has not enough items"
+msgstr "E711: ¥ê¥¹¥È·¿ÊÑ¿ô¤Ë½½Ê¬¤Ê¿ô¤ÎÍ×ÁǤ¬¤¢¤ê¤Þ¤»¤ó"
+
+msgid "E690: Missing \"in\" after :for"
+msgstr "E690: :for ¤Î¸å¤Ë \"in\" ¤¬¤¢¤ê¤Þ¤»¤ó"
+
+#, c-format
+msgid "E108: No such variable: \"%s\""
+msgstr "E108: ¤½¤ÎÊÑ¿ô¤Ï¤¢¤ê¤Þ¤»¤ó: \"%s\""
+
+#, c-format
+msgid "E940: Cannot lock or unlock variable %s"
+msgstr "E940: ÊÑ¿ô %s ¤Ï¥í¥Ã¥¯¤Þ¤¿¤Ï¥¢¥ó¥í¥Ã¥¯¤Ç¤­¤Þ¤»¤ó"
+
+msgid "E743: variable nested too deep for (un)lock"
+msgstr "E743: (¥¢¥ó)¥í¥Ã¥¯¤¹¤ë¤Ë¤ÏÊÑ¿ô¤ÎÆþ¤ì»Ò¤¬¿¼²á¤®¤Þ¤¹"
+
+msgid "E109: Missing ':' after '?'"
+msgstr "E109: '?' ¤Î¸å¤Ë ':' ¤¬¤¢¤ê¤Þ¤»¤ó"
+
+msgid "E804: Cannot use '%' with Float"
+msgstr "E804: '%' ¤òÉâÆ°¾®¿ôÅÀ¿ô¤ÈÁȤ߹ç¤ï¤»¤Æ¤Ï»È¤¨¤Þ¤»¤ó"
+
+msgid "E110: Missing ')'"
+msgstr "E110: ')' ¤¬¸«¤Ä¤«¤ê¤Þ¤»¤ó"
+
+msgid "E695: Cannot index a Funcref"
+msgstr "E695: ´Ø¿ô»²¾È·¿¤Ï¥¤¥ó¥Ç¥Ã¥¯¥¹¤Ç¤­¤Þ¤»¤ó"
+
+msgid "E909: Cannot index a special variable"
+msgstr "E909: ÆüìÊÑ¿ô¤Ï¥¤¥ó¥Ç¥Ã¥¯¥¹¤Ç¤­¤Þ¤»¤ó"
+
+#, c-format
+msgid "E112: Option name missing: %s"
+msgstr "E112: ¥ª¥×¥·¥ç¥ó̾¤¬¤¢¤ê¤Þ¤»¤ó: %s"
+
+#, c-format
+msgid "E113: Unknown option: %s"
+msgstr "E113: ̤ÃΤΥª¥×¥·¥ç¥ó¤Ç¤¹: %s"
+
+#, c-format
+msgid "E114: Missing quote: %s"
+msgstr "E114: °úÍÑÉä (\") ¤¬¤¢¤ê¤Þ¤»¤ó: %s"
+
+#, c-format
+msgid "E115: Missing quote: %s"
+msgstr "E115: °úÍÑÉä (') ¤¬¤¢¤ê¤Þ¤»¤ó: %s"
+
+msgid "Not enough memory to set references, garbage collection aborted!"
+msgstr ""
+"¥¬¡¼¥Ù¥Ã¥¸¥³¥ì¥¯¥·¥ç¥ó¤òÃæ»ß¤·¤Þ¤·¤¿! »²¾È¤òºîÀ®¤¹¤ë¤Î¤Ë¥á¥â¥ê¤¬ÉÔ­¤·¤Þ¤·¤¿"
+
+msgid "E724: variable nested too deep for displaying"
+msgstr "E724: ɽ¼¨¤¹¤ë¤Ë¤ÏÊÑ¿ô¤ÎÆþ¤ì»Ò¤¬¿¼²á¤®¤Þ¤¹"
+
+msgid "E805: Using a Float as a Number"
+msgstr "E805: ÉâÆ°¾®¿ôÅÀ¿ô¤ò¿ôÃͤȤ·¤Æ°·¤Ã¤Æ¤¤¤Þ¤¹"
+
+msgid "E703: Using a Funcref as a Number"
+msgstr "E703: ´Ø¿ô»²¾È·¿¤ò¿ôÃͤȤ·¤Æ°·¤Ã¤Æ¤¤¤Þ¤¹"
+
+msgid "E745: Using a List as a Number"
+msgstr "E745: ¥ê¥¹¥È·¿¤ò¿ôÃͤȤ·¤Æ°·¤Ã¤Æ¤¤¤Þ¤¹"
+
+msgid "E728: Using a Dictionary as a Number"
+msgstr "E728: ¼­½ñ·¿¤ò¿ôÃͤȤ·¤Æ°·¤Ã¤Æ¤¤¤Þ¤¹"
+
+msgid "E910: Using a Job as a Number"
+msgstr "E910: ¥¸¥ç¥Ö¤ò¿ôÃͤȤ·¤Æ°·¤Ã¤Æ¤¤¤Þ¤¹"
+
+msgid "E913: Using a Channel as a Number"
+msgstr "E913: ¥Á¥ã¥Í¥ë¤ò¿ôÃͤȤ·¤Æ°·¤Ã¤Æ¤¤¤Þ¤¹"
+
+msgid "E891: Using a Funcref as a Float"
+msgstr "E891: ´Ø¿ô»²¾È·¿¤òÉâÆ°¾®¿ôÅÀ¿ô¤È¤·¤Æ°·¤Ã¤Æ¤¤¤Þ¤¹"
+
+msgid "E892: Using a String as a Float"
+msgstr "E892: ʸ»úÎó¤òÉâÆ°¾®¿ôÅÀ¿ô¤È¤·¤Æ°·¤Ã¤Æ¤¤¤Þ¤¹"
+
+msgid "E893: Using a List as a Float"
+msgstr "E893: ¥ê¥¹¥È·¿¤òÉâÆ°¾®¿ôÅÀ¿ô¤È¤·¤Æ°·¤Ã¤Æ¤¤¤Þ¤¹"
+
+msgid "E894: Using a Dictionary as a Float"
+msgstr "E894: ¼­½ñ·¿¤òÉâÆ°¾®¿ôÅÀ¿ô¤È¤·¤Æ°·¤Ã¤Æ¤¤¤Þ¤¹"
+
+msgid "E907: Using a special value as a Float"
+msgstr "E907: ÆüìÃͤòÉâÆ°¾®¿ôÅÀ¿ô¤È¤·¤Æ°·¤Ã¤Æ¤¤¤Þ¤¹"
+
+msgid "E911: Using a Job as a Float"
+msgstr "E911: ¥¸¥ç¥Ö¤òÉâÆ°¾®¿ôÅÀ¿ô¤È¤·¤Æ°·¤Ã¤Æ¤¤¤Þ¤¹"
+
+msgid "E914: Using a Channel as a Float"
+msgstr "E914: ¥Á¥ã¥Í¥ë¤òÉâÆ°¾®¿ôÅÀ¿ô¤È¤·¤Æ°·¤Ã¤Æ¤¤¤Þ¤¹"
+
+msgid "E729: using Funcref as a String"
+msgstr "E729: ´Ø¿ô»²¾È·¿¤òʸ»úÎó¤È¤·¤Æ°·¤Ã¤Æ¤¤¤Þ¤¹"
+
+msgid "E730: using List as a String"
+msgstr "E730: ¥ê¥¹¥È·¿¤òʸ»úÎó¤È¤·¤Æ°·¤Ã¤Æ¤¤¤Þ¤¹"
+
+msgid "E731: using Dictionary as a String"
+msgstr "E731: ¼­½ñ·¿¤òʸ»úÎó¤È¤·¤Æ°·¤Ã¤Æ¤¤¤Þ¤¹"
+
+msgid "E908: using an invalid value as a String"
+msgstr "E908: ̵¸ú¤ÊÃͤòʸ»úÎó¤È¤·¤Æ°·¤Ã¤Æ¤¤¤Þ¤¹"
+
+#, c-format
+msgid "E795: Cannot delete variable %s"
+msgstr "E795: ÊÑ¿ô %s ¤òºï½ü¤Ç¤­¤Þ¤»¤ó"
+
+#, c-format
+msgid "E704: Funcref variable name must start with a capital: %s"
+msgstr "E704: ´Ø¿ô»²¾È·¿ÊÑ¿ô̾¤ÏÂçʸ»ú¤Ç»Ï¤Þ¤é¤Ê¤±¤ì¤Ð¤Ê¤ê¤Þ¤»¤ó: %s"
+
+#, c-format
+msgid "E705: Variable name conflicts with existing function: %s"
+msgstr "E705: ÊÑ¿ô̾¤¬´û¸¤Î´Ø¿ô̾¤È¾×Æͤ·¤Þ¤¹: %s"
+
+#, c-format
+msgid "E741: Value is locked: %s"
+msgstr "E741: Ãͤ¬¥í¥Ã¥¯¤µ¤ì¤Æ¤¤¤Þ¤¹: %s"
+
+msgid "Unknown"
+msgstr "ÉÔÌÀ"
+
+#, c-format
+msgid "E742: Cannot change value of %s"
+msgstr "E742: %s ¤ÎÃͤòÊѹ¹¤Ç¤­¤Þ¤»¤ó"
+
+msgid "E698: variable nested too deep for making a copy"
+msgstr "E698: ¥³¥Ô¡¼¤ò¼è¤ë¤Ë¤ÏÊÑ¿ô¤ÎÆþ¤ì»Ò¤¬¿¼²á¤®¤Þ¤¹"
+
+msgid ""
+"\n"
+"# global variables:\n"
+msgstr ""
+"\n"
+"# ¥°¥í¡¼¥Ð¥ëÊÑ¿ô:\n"
+
+msgid ""
+"\n"
+"\tLast set from "
+msgstr ""
+"\n"
+"\tºÇ¸å¤Ë¥»¥Ã¥È¤·¤¿¥¹¥¯¥ê¥×¥È: "
+
+msgid " line "
+msgstr " ¹Ô "
+
+msgid "E691: Can only compare List with List"
+msgstr "E691: ¥ê¥¹¥È·¿¤Ï¥ê¥¹¥È·¿¤È¤·¤«Èæ³Ó¤Ç¤­¤Þ¤»¤ó"
+
+msgid "E692: Invalid operation for List"
+msgstr "E692: ¥ê¥¹¥È·¿¤Ë¤Ï̵¸ú¤ÊÁàºî¤Ç¤¹"
+
+msgid "E735: Can only compare Dictionary with Dictionary"
+msgstr "E735: ¼­½ñ·¿¤Ï¼­½ñ·¿¤È¤·¤«Èæ³Ó¤Ç¤­¤Þ¤»¤ó"
+
+msgid "E736: Invalid operation for Dictionary"
+msgstr "E736: ¼­½ñ·¿¤Ë¤Ï̵¸ú¤ÊÁàºî¤Ç¤¹"
+
+msgid "E694: Invalid operation for Funcrefs"
+msgstr "E694: ´Ø¿ô»²¾È·¿¤Ë¤Ï̵¸ú¤ÊÁàºî¤Ç¤¹"
+
+msgid "map() argument"
+msgstr "map() ¤Î°ú¿ô"
+
+msgid "filter() argument"
+msgstr "filter() ¤Î°ú¿ô"
+
+#, c-format
+msgid "E686: Argument of %s must be a List"
+msgstr "E686: %s ¤Î°ú¿ô¤Ï¥ê¥¹¥È·¿¤Ç¤Ê¤±¤ì¤Ð¤Ê¤ê¤Þ¤»¤ó"
+
+msgid "E928: String required"
+msgstr "E928: ʸ»úÎó¤¬É¬ÍפǤ¹"
+
+msgid "E808: Number or Float required"
+msgstr "E808: ¿ôÃͤ«ÉâÆ°¾®¿ôÅÀ¿ô¤¬É¬ÍפǤ¹"
+
+msgid "add() argument"
+msgstr "add() ¤Î°ú¿ô"
+
+msgid "E785: complete() can only be used in Insert mode"
+msgstr "E785: complete() ¤ÏÁÞÆþ¥â¡¼¥É¤Ç¤·¤«ÍøÍѤǤ­¤Þ¤»¤ó"
+
+msgid "&Ok"
+msgstr "&Ok"
+
+#, c-format
+msgid "+-%s%3ld line: "
+msgid_plural "+-%s%3ld lines: "
+msgstr[0] "+-%s%3ld ¹Ô: "
+
+#, c-format
+msgid "E700: Unknown function: %s"
+msgstr "E700: ̤ÃΤδؿô¤Ç¤¹: %s"
+
+msgid "E922: expected a dict"
+msgstr "E922: ¼­½ñ¤¬´üÂÔ¤µ¤ì¤Æ¤¤¤Þ¤¹"
+
+msgid "E923: Second argument of function() must be a list or a dict"
+msgstr "E923: function() ¤ÎÂè 2 °ú¿ô¤Ï¥ê¥¹¥È·¿¤Þ¤¿¤Ï¼­½ñ·¿¤Ç¤Ê¤±¤ì¤Ð¤Ê¤ê¤Þ¤»¤ó"
+
+msgid ""
+"&OK\n"
+"&Cancel"
+msgstr ""
+"·èÄê(&O)\n"
+"¥­¥ã¥ó¥»¥ë(&C)"
+
+msgid "called inputrestore() more often than inputsave()"
+msgstr "inputrestore() ¤¬ inputsave() ¤è¤ê¤â¿¤¯¸Æ¤Ð¤ì¤Þ¤·¤¿"
+
+msgid "insert() argument"
+msgstr "insert() ¤Î°ú¿ô"
+
+msgid "E786: Range not allowed"
+msgstr "E786: ÈÏ°Ï»ØÄê¤Ïµö²Ä¤µ¤ì¤Æ¤¤¤Þ¤»¤ó"
+
+msgid "E916: not a valid job"
+msgstr "E916: Í­¸ú¤Ê¥¸¥ç¥Ö¤Ç¤Ï¤¢¤ê¤Þ¤»¤ó"
+
+msgid "E701: Invalid type for len()"
+msgstr "E701: len() ¤Ë¤Ï̵¸ú¤Ê·¿¤Ç¤¹"
+
+msgid "E957: Invalid window number"
+msgstr "E957: ̵¸ú¤Ê¥¦¥£¥ó¥É¥¦ÈÖ¹æ¤Ç¤¹"
+
+#, c-format
+msgid "E798: ID is reserved for \":match\": %ld"
+msgstr "E798: ID ¤Ï \":match\" ¤Î¤¿¤á¤ËͽÌ󤵤ì¤Æ¤¤¤Þ¤¹: %ld"
+
+msgid "E726: Stride is zero"
+msgstr "E726: ¥¹¥È¥é¥¤¥É(Á°¿ÊÎÌ)¤¬ 0 ¤Ç¤¹"
+
+msgid "E727: Start past end"
+msgstr "E727: ³«»Ï°ÌÃÖ¤¬½ªÎ»°ÌÃÖ¤ò±Û¤¨¤Þ¤·¤¿"
+
+msgid "<empty>"
+msgstr "<¶õ>"
+
+msgid "E240: No connection to the X server"
+msgstr "E240: X ¥µ¡¼¥Ð¡¼¤Ø¤ÎÀܳ¤¬¤¢¤ê¤Þ¤»¤ó"
+
+#, c-format
+msgid "E241: Unable to send to %s"
+msgstr "E241: %s ¤ØÁ÷¤ë¤³¤È¤¬¤Ç¤­¤Þ¤»¤ó"
+
+msgid "E277: Unable to read a server reply"
+msgstr "E277: ¥µ¡¼¥Ð¡¼¤Î±þÅú¤¬¤¢¤ê¤Þ¤»¤ó"
+
+msgid "E941: already started a server"
+msgstr "E941: ¥µ¡¼¥Ð¡¼¤Ï¤¹¤Ç¤Ë³«»Ï¤·¤Æ¤¤¤Þ¤¹"
+
+msgid "E942: +clientserver feature not available"
+msgstr "E942: +clientserver µ¡Ç½¤¬Ìµ¸ú¤Ë¤Ê¤Ã¤Æ¤¤¤Þ¤¹"
+
+msgid "remove() argument"
+msgstr "remove() ¤Î°ú¿ô"
+
+# Added at 10-Mar-2004.
+msgid "E655: Too many symbolic links (cycle?)"
+msgstr "E655: ¥·¥ó¥Ü¥ê¥Ã¥¯¥ê¥ó¥¯¤¬Â¿²á¤®¤Þ¤¹ (½Û´Ä¤·¤Æ¤¤¤ë²ÄǽÀ­¤¬¤¢¤ê¤Þ¤¹)"
+
+msgid "reverse() argument"
+msgstr "reverse() ¤Î°ú¿ô"
+
+msgid "E258: Unable to send to client"
+msgstr "E258: ¥¯¥é¥¤¥¢¥ó¥È¤ØÁ÷¤ë¤³¤È¤¬¤Ç¤­¤Þ¤»¤ó"
+
+#, c-format
+msgid "E927: Invalid action: '%s'"
+msgstr "E927: ̵¸ú¤ÊÁàºî¤Ç¤¹: %s"
+
+#, c-format
+msgid "E962: Invalid action: '%s'"
+msgstr "E962: ̵¸ú¤ÊÁàºî¤Ç¤¹: %s"
+
+msgid "sort() argument"
+msgstr "sort() ¤Î°ú¿ô"
+
+msgid "uniq() argument"
+msgstr "uniq() ¤Î°ú¿ô"
+
+msgid "E702: Sort compare function failed"
+msgstr "E702: ¥½¡¼¥È¤ÎÈæ³Ó´Ø¿ô¤¬¼ºÇÔ¤·¤Þ¤·¤¿"
+
+msgid "E882: Uniq compare function failed"
+msgstr "E882: Uniq ¤ÎÈæ³Ó´Ø¿ô¤¬¼ºÇÔ¤·¤Þ¤·¤¿"
+
+msgid "(Invalid)"
+msgstr "(̵¸ú)"
+
+#, c-format
+msgid "E935: invalid submatch number: %d"
+msgstr "E935: ̵¸ú¤Ê¥µ¥Ö¥Þ¥Ã¥ÁÈÖ¹æ: %d"
+
+msgid "E677: Error writing temp file"
+msgstr "E677: °ì»þ¥Õ¥¡¥¤¥ë½ñ¹þÃæ¤Ë¥¨¥é¡¼¤¬È¯À¸¤·¤Þ¤·¤¿"
+
+msgid "E921: Invalid callback argument"
+msgstr "E921: ̵¸ú¤Ê¥³¡¼¥ë¥Ð¥Ã¥¯°ú¿ô¤Ç¤¹"
+
+#, c-format
+msgid "<%s>%s%s %d, Hex %02x, Oct %03o, Digr %s"
+msgstr "<%s>%s%s %d, 16¿Ê¿ô %02x, 8¿Ê¿ô %03o, ¥À¥¤¥°¥é¥Õ %s"
+
+#, c-format
+msgid "<%s>%s%s %d, Hex %02x, Octal %03o"
+msgstr "<%s>%s%s %d, 16¿Ê¿ô %02x, 8¿Ê¿ô %03o"
+
+#, c-format
+msgid "> %d, Hex %04x, Oct %o, Digr %s"
+msgstr "> %d, 16¿Ê¿ô %04x, 8¿Ê¿ô %o, ¥À¥¤¥°¥é¥Õ %s"
+
+#, c-format
+msgid "> %d, Hex %08x, Oct %o, Digr %s"
+msgstr "> %d, 16¿Ê¿ô %08x, 8¿Ê¿ô %o, ¥À¥¤¥°¥é¥Õ %s"
+
+#, c-format
+msgid "> %d, Hex %04x, Octal %o"
+msgstr "> %d, 16¿Ê¿ô %04x, 8¿Ê¿ô %o"
+
+#, c-format
+msgid "> %d, Hex %08x, Octal %o"
+msgstr "> %d, 16¿Ê¿ô %08x, 8¿Ê¿ô %o"
+
+msgid "E134: Cannot move a range of lines into itself"
+msgstr "E134: ¹Ô¤ÎÈϰϤò¤½¤ì¼«¿È¤Ë¤Ï°ÜÆ°¤Ç¤­¤Þ¤»¤ó"
+
+#, c-format
+msgid "%ld line moved"
+msgid_plural "%ld lines moved"
+msgstr[0] "%ld ¹Ô¤¬°ÜÆ°¤µ¤ì¤Þ¤·¤¿"
+
+#, c-format
+msgid "%ld lines filtered"
+msgstr "%ld ¹Ô¤¬¥Õ¥£¥ë¥¿½èÍý¤µ¤ì¤Þ¤·¤¿"
+
+msgid "E135: *Filter* Autocommands must not change current buffer"
+msgstr "E135: *¥Õ¥£¥ë¥¿* autocommand¤Ï¸½ºß¤Î¥Ð¥Ã¥Õ¥¡¤òÊѹ¹¤·¤Æ¤Ï¤¤¤±¤Þ¤»¤ó"
+
+msgid "[No write since last change]\n"
+msgstr "[ºÇ¸å¤ÎÊѹ¹¤¬Êݸ¤µ¤ì¤Æ¤¤¤Þ¤»¤ó]\n"
+
+#, c-format
+msgid "%sviminfo: %s in line: "
+msgstr "%sviminfo: %s ¹ÔÌÜ: "
+
+msgid "E136: viminfo: Too many errors, skipping rest of file"
+msgstr "E136: viminfo: ¥¨¥é¡¼¤¬Â¿²á¤®¤ë¤Î¤Ç¡¢°Ê¹ß¤Ï¥¹¥­¥Ã¥×¤·¤Þ¤¹"
+
+#, c-format
+msgid "Reading viminfo file \"%s\"%s%s%s"
+msgstr "viminfo¥Õ¥¡¥¤¥ë \"%s\"%s%s%s ¤òÆɹþ¤ßÃæ"
+
+msgid " info"
+msgstr " ¾ðÊó"
+
+msgid " marks"
+msgstr " ¥Þ¡¼¥¯"
+
+msgid " oldfiles"
+msgstr " µì¥Õ¥¡¥¤¥ë·²"
+
+msgid " FAILED"
+msgstr " ¼ºÇÔ"
+
+#, c-format
+msgid "E137: Viminfo file is not writable: %s"
+msgstr "E137: viminfo¥Õ¥¡¥¤¥ë¤¬½ñ¹þ¤ß¤Ç¤­¤Þ¤»¤ó: %s"
+
+#, c-format
+msgid "E929: Too many viminfo temp files, like %s!"
+msgstr "E929: °ì»þviminfo¥Õ¥¡¥¤¥ë¤¬Â¿²á¤®¤Þ¤¹! Îã: %s"
+
+#, c-format
+msgid "E138: Can't write viminfo file %s!"
+msgstr "E138: viminfo¥Õ¥¡¥¤¥ë %s ¤òÊݸ¤Ç¤­¤Þ¤»¤ó!"
+
+#, c-format
+msgid "Writing viminfo file \"%s\""
+msgstr "viminfo¥Õ¥¡¥¤¥ë \"%s\" ¤ò½ñ¹þ¤ßÃæ"
+
+#, c-format
+msgid "E886: Can't rename viminfo file to %s!"
+msgstr "E886: viminfo¥Õ¥¡¥¤¥ë¤ò %s ¤Ø̾Á°Êѹ¹¤Ç¤­¤Þ¤»¤ó!"
+
+#, c-format
+msgid "# This viminfo file was generated by Vim %s.\n"
+msgstr "# ¤³¤Î viminfo ¥Õ¥¡¥¤¥ë¤Ï Vim %s ¤Ë¤è¤Ã¤ÆÀ¸À®¤µ¤ì¤Þ¤·¤¿.\n"
+
+msgid ""
+"# You may edit it if you're careful!\n"
+"\n"
+msgstr ""
+"# Êѹ¹¤¹¤ëºÝ¤Ë¤Ï½½Ê¬Ãí°Õ¤·¤Æ¤¯¤À¤µ¤¤!\n"
+"\n"
+
+msgid "# Value of 'encoding' when this file was written\n"
+msgstr "# ¤³¤Î¥Õ¥¡¥¤¥ë¤¬½ñ¤«¤ì¤¿»þ¤Î 'encoding' ¤ÎÃÍ\n"
+
+msgid "Illegal starting char"
+msgstr "ÉÔÀµ¤ÊÀèƬʸ»ú¤Ç¤¹"
+
+msgid ""
+"\n"
+"# Bar lines, copied verbatim:\n"
+msgstr ""
+"\n"
+"# '|' ¤Ç»Ï¤Þ¤ë¹Ô¤Î¡¢Ê¸»úÄ̤ê¤Î¥³¥Ô¡¼:\n"
+
+msgid "Save As"
+msgstr "ÊÌ̾¤ÇÊݸ"
+
+msgid "Write partial file?"
+msgstr "¥Õ¥¡¥¤¥ë¤òÉôʬŪ¤ËÊݸ¤·¤Þ¤¹¤«?"
+
+msgid "E140: Use ! to write partial buffer"
+msgstr "E140: ¥Ð¥Ã¥Õ¥¡¤òÉôʬŪ¤ËÊݸ¤¹¤ë¤Ë¤Ï ! ¤ò»È¤Ã¤Æ¤¯¤À¤µ¤¤"
+
+#, c-format
+msgid "Overwrite existing file \"%s\"?"
+msgstr "´û¸¤Î¥Õ¥¡¥¤¥ë \"%s\" ¤ò¾å½ñ¤­¤·¤Þ¤¹¤«?"
+
+#, c-format
+msgid "Swap file \"%s\" exists, overwrite anyway?"
+msgstr "¥¹¥ï¥Ã¥×¥Õ¥¡¥¤¥ë \"%s\" ¤¬Â¸ºß¤·¤Þ¤¹. ¾å½ñ¤­¤ò¶¯À©¤·¤Þ¤¹¤«?"
+
+#, c-format
+msgid "E768: Swap file exists: %s (:silent! overrides)"
+msgstr "E768: ¥¹¥ï¥Ã¥×¥Õ¥¡¥¤¥ë¤¬Â¸ºß¤·¤Þ¤¹: %s (:silent! ¤òÄɲäǾå½ñ)"
+
+#, c-format
+msgid "E141: No file name for buffer %ld"
+msgstr "E141: ¥Ð¥Ã¥Õ¥¡ %ld ¤Ë¤Ï̾Á°¤¬¤¢¤ê¤Þ¤»¤ó"
+
+msgid "E142: File not written: Writing is disabled by 'write' option"
+msgstr "E142: ¥Õ¥¡¥¤¥ë¤ÏÊݸ¤µ¤ì¤Þ¤»¤ó¤Ç¤·¤¿: 'write' ¥ª¥×¥·¥ç¥ó¤Ë¤è¤ê̵¸ú¤Ç¤¹"
+
+#, c-format
+msgid ""
+"'readonly' option is set for \"%s\".\n"
+"Do you wish to write anyway?"
+msgstr ""
+"\"%s\" ¤Ë¤Ï 'readonly' ¥ª¥×¥·¥ç¥ó¤¬ÀßÄꤵ¤ì¤Æ¤¤¤Þ¤¹.\n"
+"¾å½ñ¤­¶¯À©¤ò¤·¤Þ¤¹¤«?"
+
+#, c-format
+msgid ""
+"File permissions of \"%s\" are read-only.\n"
+"It may still be possible to write it.\n"
+"Do you wish to try?"
+msgstr ""
+"¥Õ¥¡¥¤¥ë \"%s\" ¤Î¥Ñ¡¼¥ß¥Ã¥·¥ç¥ó¤¬ÆɹþÀìÍѤǤ¹.\n"
+"¤½¤ì¤Ç¤â¶²¤é¤¯½ñ¤­¹þ¤à¤³¤È¤Ï²Äǽ¤Ç¤¹.\n"
+"·Ñ³¤·¤Þ¤¹¤«?"
+
+#, c-format
+msgid "E505: \"%s\" is read-only (add ! to override)"
+msgstr "E505: \"%s\" ¤ÏÆɹþÀìÍѤǤ¹ (¶¯À©½ñ¹þ¤Ë¤Ï ! ¤òÄɲÃ)"
+
+msgid "Edit File"
+msgstr "¥Õ¥¡¥¤¥ë¤òÊÔ½¸"
+
+#, c-format
+msgid "E143: Autocommands unexpectedly deleted new buffer %s"
+msgstr "E143: autocommand¤¬Í½´ü¤»¤º¿·¤·¤¤¥Ð¥Ã¥Õ¥¡ %s ¤òºï½ü¤·¤Þ¤·¤¿"
+
+msgid "E144: non-numeric argument to :z"
+msgstr "E144: ¿ô¤Ç¤Ï¤Ê¤¤°ú¿ô¤¬ :z ¤ËÅϤµ¤ì¤Þ¤·¤¿"
+
+msgid "E145: Shell commands not allowed in rvim"
+msgstr "E145: rvim¤Ç¤Ï¥·¥§¥ë¥³¥Þ¥ó¥É¤ò»È¤¨¤Þ¤»¤ó"
+
+msgid "E146: Regular expressions can't be delimited by letters"
+msgstr "E146: Àµµ¬É½¸½¤Ïʸ»ú¤Ç¶èÀڤ뤳¤È¤¬¤Ç¤­¤Þ¤»¤ó"
+
+#, c-format
+msgid "replace with %s (y/n/a/q/l/^E/^Y)?"
+msgstr "%s ¤ËÃÖ´¹¤·¤Þ¤¹¤«? (y/n/a/q/l/^E/^Y)"
+
+msgid "(Interrupted) "
+msgstr "(³ä¹þ¤Þ¤ì¤Þ¤·¤¿) "
+
+#, c-format
+msgid "%ld match on %ld line"
+msgid_plural "%ld matches on %ld line"
+msgstr[0] "%ld ²Õ½ê³ºÅö¤·¤Þ¤·¤¿ (·× %ld ¹ÔÆâ)"
+
+#, c-format
+msgid "%ld substitution on %ld line"
+msgid_plural "%ld substitutions on %ld line"
+msgstr[0] "%ld ²Õ½êÃÖ´¹¤·¤Þ¤·¤¿ (·× %ld ¹ÔÆâ)"
+
+#, c-format
+msgid "%ld match on %ld lines"
+msgid_plural "%ld matches on %ld lines"
+msgstr[0] "%ld ²Õ½ê³ºÅö¤·¤Þ¤·¤¿ (·× %ld ¹ÔÆâ)"
+
+#, c-format
+msgid "%ld substitution on %ld lines"
+msgid_plural "%ld substitutions on %ld lines"
+msgstr[0] "%ld ²Õ½êÃÖ´¹¤·¤Þ¤·¤¿ (·× %ld ¹ÔÆâ)"
+
+msgid "E147: Cannot do :global recursive with a range"
+msgstr "E147: :global ¤òÈÏ°ÏÉÕ¤­¤ÇºÆµ¢Åª¤Ë¤Ï»È¤¨¤Þ¤»¤ó"
+
+msgid "E148: Regular expression missing from global"
+msgstr "E148: global¥³¥Þ¥ó¥É¤ËÀµµ¬É½¸½¤¬»ØÄꤵ¤ì¤Æ¤¤¤Þ¤»¤ó"
+
+#, c-format
+msgid "Pattern found in every line: %s"
+msgstr "¥Ñ¥¿¡¼¥ó¤¬Á´¤Æ¤Î¹Ô¤Ç¸«¤Ä¤«¤ê¤Þ¤·¤¿: %s"
+
+#, c-format
+msgid "Pattern not found: %s"
+msgstr "¥Ñ¥¿¡¼¥ó¤Ï¸«¤Ä¤«¤ê¤Þ¤»¤ó¤Ç¤·¤¿: %s"
+
+msgid ""
+"\n"
+"# Last Substitute String:\n"
+"$"
+msgstr ""
+"\n"
+"# ºÇ¸å¤ËÃÖ´¹¤µ¤ì¤¿Ê¸»úÎó:\n"
+"$"
+
+msgid "E478: Don't panic!"
+msgstr "E478: ¹²¤Æ¤Ê¤¤¤Ç¤¯¤À¤µ¤¤"
+
+#, c-format
+msgid "E661: Sorry, no '%s' help for %s"
+msgstr "E661: »ÄÇ°¤Ç¤¹¤¬ '%s' ¤Î¥Ø¥ë¥×¤¬ %s ¤Ë¤Ï¤¢¤ê¤Þ¤»¤ó"
+
+#, c-format
+msgid "E149: Sorry, no help for %s"
+msgstr "E149: »ÄÇ°¤Ç¤¹¤¬ %s ¤Ë¤Ï¥Ø¥ë¥×¤¬¤¢¤ê¤Þ¤»¤ó"
+
+#, c-format
+msgid "Sorry, help file \"%s\" not found"
+msgstr "»ÄÇ°¤Ç¤¹¤¬¥Ø¥ë¥×¥Õ¥¡¥¤¥ë \"%s\" ¤¬¸«¤Ä¤«¤ê¤Þ¤»¤ó"
+
+#, c-format
+msgid "E151: No match: %s"
+msgstr "E151: ¥Þ¥Ã¥Á¤Ï¤¢¤ê¤Þ¤»¤ó: %s"
+
+#, c-format
+msgid "E152: Cannot open %s for writing"
+msgstr "E152: ½ñ¹þ¤ßÍÑ¤Ë %s ¤ò³«¤±¤Þ¤»¤ó"
+
+#, c-format
+msgid "E153: Unable to open %s for reading"
+msgstr "E153: ÆɹþÍÑ¤Ë %s ¤ò³«¤±¤Þ¤»¤ó"
+
+# Added at 29-Apr-2004.
+#, c-format
+msgid "E670: Mix of help file encodings within a language: %s"
+msgstr "E670: 1¤Ä¤Î¸À¸ì¤Î¥Ø¥ë¥×¥Õ¥¡¥¤¥ë¤ËÊ£¿ô¤Î¥¨¥ó¥³¡¼¥É¤¬º®ºß¤·¤Æ¤¤¤Þ¤¹: %s"
+
+#, c-format
+msgid "E154: Duplicate tag \"%s\" in file %s/%s"
+msgstr "E154: ¥¿¥° \"%s\" ¤¬¥Õ¥¡¥¤¥ë %s/%s ¤Ë½ÅÊ£¤·¤Æ¤¤¤Þ¤¹"
+
+#, c-format
+msgid "E150: Not a directory: %s"
+msgstr "E150: ¥Ç¥£¥ì¥¯¥È¥ê¤Ç¤Ï¤¢¤ê¤Þ¤»¤ó: %s"
+
+#, c-format
+msgid "E160: Unknown sign command: %s"
+msgstr "E160: ̤ÃΤÎsign¥³¥Þ¥ó¥É¤Ç¤¹: %s"
+
+msgid "E156: Missing sign name"
+msgstr "E156: sign̾¤¬¤¢¤ê¤Þ¤»¤ó"
+
+msgid "E612: Too many signs defined"
+msgstr "E612: sign¤ÎÄêµÁ¤¬Â¿¿ô¸«¤Ä¤«¤ê¤Þ¤·¤¿"
+
+#, c-format
+msgid "E239: Invalid sign text: %s"
+msgstr "E239: ̵¸ú¤Êsign¤Î¥Æ¥­¥¹¥È¤Ç¤¹: %s"
+
+#, c-format
+msgid "E155: Unknown sign: %s"
+msgstr "E155: ̤ÃΤÎsign¤Ç¤¹: %s"
+
+msgid "E159: Missing sign number"
+msgstr "E159: sign¤ÎÈֹ椬¤¢¤ê¤Þ¤»¤ó"
+
+#, c-format
+msgid "E158: Invalid buffer name: %s"
+msgstr "E158: ̵¸ú¤Ê¥Ð¥Ã¥Õ¥¡Ì¾¤Ç¤¹: %s"
+
+msgid "E934: Cannot jump to a buffer that does not have a name"
+msgstr "E934: ̾Á°¤Î̵¤¤¥Ð¥Ã¥Õ¥¡¤Ø¤Ï¥¸¥ã¥ó¥×¤Ç¤­¤Þ¤»¤ó"
+
+#, c-format
+msgid "E157: Invalid sign ID: %ld"
+msgstr "E157: ̵¸ú¤Êsign¼±Ê̻ҤǤ¹: %ld"
+
+#, c-format
+msgid "E885: Not possible to change sign %s"
+msgstr "E885: Êѹ¹¤Ç¤­¤Ê¤¤ sign ¤Ç¤¹: %s"
+
+# Added at 27-Jan-2004.
+msgid " (NOT FOUND)"
+msgstr " (¸«¤Ä¤«¤ê¤Þ¤»¤ó)"
+
+msgid " (not supported)"
+msgstr " (È󥵥ݡ¼¥È)"
+
+msgid "[Deleted]"
+msgstr "[ºï½üºÑ]"
+
+msgid "No old files"
+msgstr "¸Å¤¤¥Õ¥¡¥¤¥ë¤Ï¤¢¤ê¤Þ¤»¤ó"
+
+msgid "Entering Debug mode. Type \"cont\" to continue."
+msgstr "¥Ç¥Ð¥Ã¥°¥â¡¼¥É¤ËÆþ¤ê¤Þ¤¹. ³¤±¤ë¤Ë¤Ï \"cont\" ¤ÈÆþÎϤ·¤Æ¤¯¤À¤µ¤¤."
+
+#, c-format
+msgid "Oldval = \"%s\""
+msgstr "¸Å¤¤ÃÍ = \"%s\""
+
+#, c-format
+msgid "Newval = \"%s\""
+msgstr "¿·¤·¤¤ÃÍ = \"%s\""
+
+#, c-format
+msgid "line %ld: %s"
+msgstr "¹Ô %ld: %s"
+
+#, c-format
+msgid "cmd: %s"
+msgstr "¥³¥Þ¥ó¥É: %s"
+
+msgid "frame is zero"
+msgstr "¥Õ¥ì¡¼¥à¤¬ 0 ¤Ç¤¹"
+
+#, c-format
+msgid "frame at highest level: %d"
+msgstr "ºÇ¹â¥ì¥Ù¥ë¤Î¥Õ¥ì¡¼¥à: %d"
+
+#, c-format
+msgid "Breakpoint in \"%s%s\" line %ld"
+msgstr "¥Ö¥ì¡¼¥¯¥Ý¥¤¥ó¥È \"%s%s\" ¹Ô %ld"
+
+#, c-format
+msgid "E161: Breakpoint not found: %s"
+msgstr "E161: ¥Ö¥ì¡¼¥¯¥Ý¥¤¥ó¥È¤¬¸«¤Ä¤«¤ê¤Þ¤»¤ó: %s"
+
+msgid "No breakpoints defined"
+msgstr "¥Ö¥ì¡¼¥¯¥Ý¥¤¥ó¥È¤¬ÄêµÁ¤µ¤ì¤Æ¤¤¤Þ¤»¤ó"
+
+#, c-format
+msgid "%3d %s %s line %ld"
+msgstr "%3d %s %s ¹Ô %ld"
+
+#, c-format
+msgid "%3d expr %s"
+msgstr "%3d expr %s"
+
+msgid "E750: First use \":profile start {fname}\""
+msgstr "E750: ½é¤á¤Ë \":profile start {fname}\" ¤ò¼Â¹Ô¤·¤Æ¤¯¤À¤µ¤¤"
+
+#, c-format
+msgid "Save changes to \"%s\"?"
+msgstr "Êѹ¹¤ò \"%s\" ¤ËÊݸ¤·¤Þ¤¹¤«?"
+
+#, c-format
+msgid "E947: Job still running in buffer \"%s\""
+msgstr "E947: ¥¸¥ç¥Ö¤Ï¥Ð¥Ã¥Õ¥¡ \"%s\" ¤Ç¤Þ¤À¼Â¹ÔÃæ¤Ç¤¹"
+
+#, c-format
+msgid "E162: No write since last change for buffer \"%s\""
+msgstr "E162: ¥Ð¥Ã¥Õ¥¡ \"%s\" ¤ÎÊѹ¹¤ÏÊݸ¤µ¤ì¤Æ¤¤¤Þ¤»¤ó"
+
+msgid "Warning: Entered other buffer unexpectedly (check autocommands)"
+msgstr "·Ù¹ð: ͽ´ü¤»¤ºÂ¾¥Ð¥Ã¥Õ¥¡¤Ø°ÜÆ°¤·¤Þ¤·¤¿ (autocommands ¤òÄ´¤Ù¤Æ¤¯¤À¤µ¤¤)"
+
+msgid "E163: There is only one file to edit"
+msgstr "E163: ÊÔ½¸¤¹¤ë¥Õ¥¡¥¤¥ë¤Ï1¤Ä¤·¤«¤¢¤ê¤Þ¤»¤ó"
+
+msgid "E164: Cannot go before first file"
+msgstr "E164: ºÇ½é¤Î¥Õ¥¡¥¤¥ë¤è¤êÁ°¤Ë¤Ï¹Ô¤±¤Þ¤»¤ó"
+
+msgid "E165: Cannot go beyond last file"
+msgstr "E165: ºÇ¸å¤Î¥Õ¥¡¥¤¥ë¤ò±Û¤¨¤Æ¸å¤Ë¤Ï¹Ô¤±¤Þ¤»¤ó"
+
+#, c-format
+msgid "E666: compiler not supported: %s"
+msgstr "E666: ¤½¤Î¥³¥ó¥Ñ¥¤¥é¤Ë¤ÏÂбþ¤·¤Æ¤¤¤Þ¤»¤ó: %s"
+
+#, c-format
+msgid "Searching for \"%s\" in \"%s\""
+msgstr "\"%s\" ¤ò \"%s\" ¤«¤é¸¡º÷Ãæ"
+
+#, c-format
+msgid "Searching for \"%s\""
+msgstr "\"%s\" ¤ò¸¡º÷Ãæ"
+
+#, c-format
+msgid "not found in '%s': \"%s\""
+msgstr "'%s' ¤ÎÃæ¤Ë¤Ï¤¢¤ê¤Þ¤»¤ó: \"%s\""
+
+#, c-format
+msgid "W20: Required python version 2.x not supported, ignoring file: %s"
+msgstr "W20: Í׵ᤵ¤ì¤¿python 2.x¤ÏÂбþ¤·¤Æ¤¤¤Þ¤»¤ó¡¢¥Õ¥¡¥¤¥ë¤ò̵»ë¤·¤Þ¤¹: %s"
+
+#, c-format
+msgid "W21: Required python version 3.x not supported, ignoring file: %s"
+msgstr "W21: Í׵ᤵ¤ì¤¿python 3.x¤ÏÂбþ¤·¤Æ¤¤¤Þ¤»¤ó¡¢¥Õ¥¡¥¤¥ë¤ò̵»ë¤·¤Þ¤¹: %s"
+
+msgid "Source Vim script"
+msgstr "Vim¥¹¥¯¥ê¥×¥È¤Î¼è¹þ¤ß"
+
+#, c-format
+msgid "Cannot source a directory: \"%s\""
+msgstr "¥Ç¥£¥ì¥¯¥È¥ê¤Ï¼è¹þ¤á¤Þ¤»¤ó: \"%s\""
+
+#, c-format
+msgid "could not source \"%s\""
+msgstr "\"%s\" ¤ò¼è¹þ¤á¤Þ¤»¤ó"
+
+#, c-format
+msgid "line %ld: could not source \"%s\""
+msgstr "¹Ô %ld: \"%s\" ¤ò¼è¹þ¤á¤Þ¤»¤ó"
+
+#, c-format
+msgid "sourcing \"%s\""
+msgstr "\"%s\" ¤ò¼è¹þÃæ"
+
+#, c-format
+msgid "line %ld: sourcing \"%s\""
+msgstr "¹Ô %ld: %s ¤ò¼è¹þÃæ"
+
+#, c-format
+msgid "finished sourcing %s"
+msgstr "%s ¤Î¼è¹þ¤ò´°Î»"
+
+#, c-format
+msgid "continuing in %s"
+msgstr "%s ¤Î¼Â¹Ô¤ò·Ñ³Ãæ¤Ç¤¹"
+
+msgid "modeline"
+msgstr "¥â¡¼¥É¹Ô"
+
+msgid "--cmd argument"
+msgstr "--cmd °ú¿ô"
+
+msgid "-c argument"
+msgstr "-c °ú¿ô"
+
+msgid "environment variable"
+msgstr "´Ä¶­ÊÑ¿ô"
+
+msgid "error handler"
+msgstr "¥¨¥é¡¼¥Ï¥ó¥É¥é"
+
+msgid "W15: Warning: Wrong line separator, ^M may be missing"
+msgstr "W15: ·Ù¹ð: ¹Ô¶èÀÚ¤¬ÉÔÀµ¤Ç¤¹. ^M ¤¬¤Ê¤¤¤Î¤Ç¤·¤ç¤¦"
+
+msgid "E167: :scriptencoding used outside of a sourced file"
+msgstr "E167: :scriptencoding ¤¬¼è¹þ¥¹¥¯¥ê¥×¥È°Ê³°¤Ç»ÈÍѤµ¤ì¤Þ¤·¤¿"
+
+msgid "E168: :finish used outside of a sourced file"
+msgstr "E168: :finish ¤¬¼è¹þ¥¹¥¯¥ê¥×¥È°Ê³°¤Ç»ÈÍѤµ¤ì¤Þ¤·¤¿"
+
+#, c-format
+msgid "Current %slanguage: \"%s\""
+msgstr "¸½ºß¤Î %s¸À¸ì: \"%s\""
+
+#, c-format
+msgid "E197: Cannot set language to \"%s\""
+msgstr "E197: ¸À¸ì¤ò \"%s\" ¤ËÀßÄê¤Ç¤­¤Þ¤»¤ó"
+
+msgid "Entering Ex mode. Type \"visual\" to go to Normal mode."
+msgstr ""
+"Ex¥â¡¼¥É¤ËÆþ¤ê¤Þ¤¹. ¥Î¡¼¥Þ¥ë¥â¡¼¥É¤ËÌá¤ë¤Ë¤Ï\"visual\"¤ÈÆþÎϤ·¤Æ¤¯¤À¤µ¤¤."
+
+msgid "E501: At end-of-file"
+msgstr "E501: ¥Õ¥¡¥¤¥ë¤Î½ªÎ»°ÌÃÖ"
+
+msgid "E169: Command too recursive"
+msgstr "E169: ¥³¥Þ¥ó¥É¤¬ºÆµ¢Åª²á¤®¤Þ¤¹"
+
+#, c-format
+msgid "E605: Exception not caught: %s"
+msgstr "E605: Îã³°¤¬Ê᪤µ¤ì¤Þ¤»¤ó¤Ç¤·¤¿: %s"
+
+msgid "End of sourced file"
+msgstr "¼è¹þ¥Õ¥¡¥¤¥ë¤ÎºÇ¸å¤Ç¤¹"
+
+msgid "End of function"
+msgstr "´Ø¿ô¤ÎºÇ¸å¤Ç¤¹"
+
+msgid "E464: Ambiguous use of user-defined command"
+msgstr "E464: ¥æ¡¼¥¶¡¼ÄêµÁ¥³¥Þ¥ó¥É¤Î¤¢¤¤¤Þ¤¤¤Ê»ÈÍѤǤ¹"
+
+msgid "E492: Not an editor command"
+msgstr "E492: ¥¨¥Ç¥£¥¿¤Î¥³¥Þ¥ó¥É¤Ç¤Ï¤¢¤ê¤Þ¤»¤ó"
+
+msgid "E493: Backwards range given"
+msgstr "E493: µÕ¤µ¤Þ¤ÎÈϰϤ¬»ØÄꤵ¤ì¤Þ¤·¤¿"
+
+msgid "Backwards range given, OK to swap"
+msgstr "µÕ¤µ¤Þ¤ÎÈϰϤ¬»ØÄꤵ¤ì¤Þ¤·¤¿¡¢ÆþÂؤ¨¤Þ¤¹¤«?"
+
+msgid "E494: Use w or w>>"
+msgstr "E494: w ¤â¤·¤¯¤Ï w>> ¤ò»ÈÍѤ·¤Æ¤¯¤À¤µ¤¤"
+
+msgid "E943: Command table needs to be updated, run 'make cmdidxs'"
+msgstr ""
+"E943: ¥³¥Þ¥ó¥É¥Æ¡¼¥Ö¥ë¤ò¹¹¿·¤¹¤ëɬÍפ¬¤¢¤ê¤Þ¤¹¡¢'make cmdidxs' ¤ò¼Â¹Ô¤·¤Æ¤¯¤À"
+"¤µ¤¤"
+
+msgid "E319: Sorry, the command is not available in this version"
+msgstr "E319: ¤³¤Î¥Ð¡¼¥¸¥ç¥ó¤Ç¤Ï¤³¤Î¥³¥Þ¥ó¥É¤ÏÍøÍѤǤ­¤Þ¤»¤ó¡¢¤´¤á¤ó¤Ê¤µ¤¤"
+
+#, c-format
+msgid "%d more file to edit. Quit anyway?"
+msgid_plural "%d more files to edit. Quit anyway?"
+msgstr[0] "ÊÔ½¸¤¹¤Ù¤­¥Õ¥¡¥¤¥ë¤¬¤¢¤È %d ¸Ä¤¢¤ê¤Þ¤¹¤¬¡¢½ªÎ»¤·¤Þ¤¹¤«?"
+
+#, c-format
+msgid "E173: %ld more file to edit"
+msgid_plural "E173: %ld more files to edit"
+msgstr[0] "E173: ÊÔ½¸¤¹¤Ù¤­¥Õ¥¡¥¤¥ë¤¬¤¢¤È %ld ¸Ä¤¢¤ê¤Þ¤¹"
+
+msgid "E174: Command already exists: add ! to replace it"
+msgstr "E174: ¥³¥Þ¥ó¥É¤¬´û¤Ë¤¢¤ê¤Þ¤¹: ºÆÄêµÁ¤¹¤ë¤Ë¤Ï ! ¤òÄɲ䷤Ƥ¯¤À¤µ¤¤"
+
+msgid ""
+"\n"
+" Name Args Address Complete Definition"
+msgstr ""
+"\n"
+" ̾Á° °ú¿ô ¥¢¥É¥ì¥¹ Êä´° ÄêµÁ"
+
+msgid "No user-defined commands found"
+msgstr "¥æ¡¼¥¶¡¼ÄêµÁ¥³¥Þ¥ó¥É¤¬¸«¤Ä¤«¤ê¤Þ¤»¤ó¤Ç¤·¤¿"
+
+msgid "E175: No attribute specified"
+msgstr "E175: °À­¤ÏÄêµÁ¤µ¤ì¤Æ¤¤¤Þ¤»¤ó"
+
+msgid "E176: Invalid number of arguments"
+msgstr "E176: °ú¿ô¤Î¿ô¤¬Ìµ¸ú¤Ç¤¹"
+
+msgid "E177: Count cannot be specified twice"
+msgstr "E177: ¥«¥¦¥ó¥È¤ò2½Å»ØÄꤹ¤ë¤³¤È¤Ï¤Ç¤­¤Þ¤»¤ó"
+
+msgid "E178: Invalid default value for count"
+msgstr "E178: ¥«¥¦¥ó¥È¤Î¾ÊάÃͤ¬Ìµ¸ú¤Ç¤¹"
+
+msgid "E179: argument required for -complete"
+msgstr "E179: -complete ¤Ë¤Ï°ú¿ô¤¬É¬ÍפǤ¹"
+
+msgid "E179: argument required for -addr"
+msgstr "E179: -addr ¤Ë¤Ï°ú¿ô¤¬É¬ÍפǤ¹"
+
+#, c-format
+msgid "E181: Invalid attribute: %s"
+msgstr "E181: ̵¸ú¤Ê°À­¤Ç¤¹: %s"
+
+msgid "E182: Invalid command name"
+msgstr "E182: ̵¸ú¤Ê¥³¥Þ¥ó¥É̾¤Ç¤¹"
+
+msgid "E183: User defined commands must start with an uppercase letter"
+msgstr "E183: ¥æ¡¼¥¶¡¼ÄêµÁ¥³¥Þ¥ó¥É¤Ï±ÑÂçʸ»ú¤Ç»Ï¤Þ¤é¤Ê¤±¤ì¤Ð¤Ê¤ê¤Þ¤»¤ó"
+
+msgid "E841: Reserved name, cannot be used for user defined command"
+msgstr "E841: ͽÌó̾¤Ê¤Î¤Ç¡¢¥æ¡¼¥¶¡¼ÄêµÁ¥³¥Þ¥ó¥É¤ËÍøÍѤǤ­¤Þ¤»¤ó"
+
+#, c-format
+msgid "E184: No such user-defined command: %s"
+msgstr "E184: ¤½¤Î¥æ¡¼¥¶¡¼ÄêµÁ¥³¥Þ¥ó¥É¤Ï¤¢¤ê¤Þ¤»¤ó: %s"
+
+#, c-format
+msgid "E180: Invalid address type value: %s"
+msgstr "E180: ̵¸ú¤Ê¥¢¥É¥ì¥¹¥¿¥¤¥×ÃͤǤ¹: %s"
+
+#, c-format
+msgid "E180: Invalid complete value: %s"
+msgstr "E180: ̵¸ú¤ÊÊä´°»ØÄê¤Ç¤¹: %s"
+
+msgid "E468: Completion argument only allowed for custom completion"
+msgstr "E468: Êä´°°ú¿ô¤Ï¥«¥¹¥¿¥àÊä´°¤Ç¤·¤«»ÈÍѤǤ­¤Þ¤»¤ó"
+
+msgid "E467: Custom completion requires a function argument"
+msgstr "E467: ¥«¥¹¥¿¥àÊä´°¤Ë¤Ï°ú¿ô¤È¤·¤Æ´Ø¿ô¤¬É¬ÍפǤ¹"
+
+msgid "unknown"
+msgstr "ÉÔÌÀ"
+
+#, c-format
+msgid "E185: Cannot find color scheme '%s'"
+msgstr "E185: ¥«¥é¡¼¥¹¥­¡¼¥à '%s' ¤¬¸«¤Ä¤«¤ê¤Þ¤»¤ó"
+
+msgid "Greetings, Vim user!"
+msgstr "Vim »È¤¤¤µ¤ó¡¢¤ä¤¢!"
+
+msgid "E784: Cannot close last tab page"
+msgstr "E784: ºÇ¸å¤Î¥¿¥Ö¥Ú¡¼¥¸¤òÊĤ¸¤ë¤³¤È¤Ï¤Ç¤­¤Þ¤»¤ó"
+
+msgid "Already only one tab page"
+msgstr "´û¤Ë¥¿¥Ö¥Ú¡¼¥¸¤Ï1¤Ä¤·¤«¤¢¤ê¤Þ¤»¤ó"
+
+msgid "Edit File in new tab page"
+msgstr "¿·¤·¤¤¥¿¥Ö¥Ú¡¼¥¸¤Ç¥Õ¥¡¥¤¥ë¤òÊÔ½¸¤·¤Þ¤¹"
+
+msgid "Edit File in new window"
+msgstr "¿·¤·¤¤¥¦¥£¥ó¥É¥¦¤Ç¥Õ¥¡¥¤¥ë¤òÊÔ½¸¤·¤Þ¤¹"
+
+#, c-format
+msgid "Tab page %d"
+msgstr "¥¿¥Ö¥Ú¡¼¥¸ %d"
+
+msgid "No swap file"
+msgstr "¥¹¥ï¥Ã¥×¥Õ¥¡¥¤¥ë¤¬¤¢¤ê¤Þ¤»¤ó"
+
+msgid "Append File"
+msgstr "Äɲåե¡¥¤¥ë"
+
+msgid "E747: Cannot change directory, buffer is modified (add ! to override)"
+msgstr ""
+"E747: ¥Ð¥Ã¥Õ¥¡¤¬½¤Àµ¤µ¤ì¤Æ¤¤¤ë¤Î¤Ç¡¢¥Ç¥£¥ì¥¯¥È¥ê¤òÊѹ¹¤Ç¤­¤Þ¤»¤ó (! ¤òÄɲäÇ"
+"¾å½ñ)"
+
+msgid "E186: No previous directory"
+msgstr "E186: Á°¤Î¥Ç¥£¥ì¥¯¥È¥ê¤Ï¤¢¤ê¤Þ¤»¤ó"
+
+msgid "E187: Unknown"
+msgstr "E187: ̤ÃÎ"
+
+msgid "E465: :winsize requires two number arguments"
+msgstr "E465: :winsize ¤Ë¤Ï2¤Ä¤Î¿ôÃͤΰú¿ô¤¬É¬ÍפǤ¹"
+
+#, c-format
+msgid "Window position: X %d, Y %d"
+msgstr "¥¦¥£¥ó¥É¥¦°ÌÃÖ: X %d, Y %d"
+
+msgid "E188: Obtaining window position not implemented for this platform"
+msgstr ""
+"E188: ¤³¤Î¥×¥é¥Ã¥È¥Û¡¼¥à¤Ë¤Ï¥¦¥£¥ó¥É¥¦°ÌÃ֤μèÆÀµ¡Ç½¤Ï¼ÂÁõ¤µ¤ì¤Æ¤¤¤Þ¤»¤ó"
+
+msgid "E466: :winpos requires two number arguments"
+msgstr "E466: :winpos ¤Ë¤Ï2¤Ä¤Î¿ôÃͤΰú¿ô¤¬É¬ÍפǤ¹"
+
+msgid "E930: Cannot use :redir inside execute()"
+msgstr "E930: execute() ¤ÎÃæ¤Ç¤Ï :redir ¤Ï»È¤¨¤Þ¤»¤ó"
+
+msgid "Save Redirection"
+msgstr "¥ê¥À¥¤¥ì¥¯¥È¤òÊݸ¤·¤Þ¤¹"
+
+msgid "Save View"
+msgstr "¥Ó¥å¡¼¤òÊݸ¤·¤Þ¤¹"
+
+msgid "Save Session"
+msgstr "¥»¥Ã¥·¥ç¥ó¾ðÊó¤òÊݸ¤·¤Þ¤¹"
+
+msgid "Save Setup"
+msgstr "ÀßÄê¤òÊݸ¤·¤Þ¤¹"
+
+#, c-format
+msgid "E739: Cannot create directory: %s"
+msgstr "E739: ¥Ç¥£¥ì¥¯¥È¥ê¤òºîÀ®¤Ç¤­¤Þ¤»¤ó: %s"
+
+#, c-format
+msgid "E189: \"%s\" exists (add ! to override)"
+msgstr "E189: \"%s\" ¤¬Â¸ºß¤·¤Þ¤¹ (¾å½ñ¤¹¤ë¤Ë¤Ï ! ¤òÄɲ䷤Ƥ¯¤À¤µ¤¤)"
+
+#, c-format
+msgid "E190: Cannot open \"%s\" for writing"
+msgstr "E190: \"%s\" ¤ò½ñ¹þ¤ßÍѤȤ·¤Æ³«¤±¤Þ¤»¤ó"
+
+msgid "E191: Argument must be a letter or forward/backward quote"
+msgstr "E191: °ú¿ô¤Ï1ʸ»ú¤Î±Ñ»ú¤«°úÍÑÉä (' ¤« `) ¤Ç¤Ê¤±¤ì¤Ð¤¤¤±¤Þ¤»¤ó"
+
+msgid "E192: Recursive use of :normal too deep"
+msgstr "E192: :normal ¤ÎºÆµ¢ÍøÍѤ¬¿¼¤¯¤Ê¤ê²á¤®¤Þ¤·¤¿"
+
+msgid "E809: #< is not available without the +eval feature"
+msgstr "E809: #< ¤Ï +eval µ¡Ç½¤¬Ìµ¤¤¤ÈÍøÍѤǤ­¤Þ¤»¤ó"
+
+msgid "E194: No alternate file name to substitute for '#'"
+msgstr "E194: '#'¤òÃÖ¤­´¹¤¨¤ëÉû¥Õ¥¡¥¤¥ë¤Î̾Á°¤¬¤¢¤ê¤Þ¤»¤ó"
+
+msgid "E495: no autocommand file name to substitute for \"<afile>\""
+msgstr "E495: \"<afile>\"¤òÃÖ¤­´¹¤¨¤ëautocommand¤Î¥Õ¥¡¥¤¥ë̾¤¬¤¢¤ê¤Þ¤»¤ó"
+
+msgid "E496: no autocommand buffer number to substitute for \"<abuf>\""
+msgstr "E496: \"<abuf>\"¤òÃÖ¤­´¹¤¨¤ëautocommand¥Ð¥Ã¥Õ¥¡Èֹ椬¤¢¤ê¤Þ¤»¤ó"
+
+msgid "E497: no autocommand match name to substitute for \"<amatch>\""
+msgstr "E497: \"<amatch>\"¤òÃÖ¤­´¹¤¨¤ëautocommand¤Î³ºÅö̾¤¬¤¢¤ê¤Þ¤»¤ó"
+
+msgid "E498: no :source file name to substitute for \"<sfile>\""
+msgstr "E498: \"<sfile>\"¤òÃÖ¤­´¹¤¨¤ë :source Âоݥե¡¥¤¥ë̾¤¬¤¢¤ê¤Þ¤»¤ó"
+
+msgid "E842: no line number to use for \"<slnum>\""
+msgstr "E842: \"<slnum>\"¤òÃÖ¤­´¹¤¨¤ë¹ÔÈֹ椬¤¢¤ê¤Þ¤»¤ó"
+
+msgid "E961: no line number to use for \"<sflnum>\""
+msgstr "E961: \"<sflnum>\"¤òÃÖ¤­´¹¤¨¤ë¹ÔÈֹ椬¤¢¤ê¤Þ¤»¤ó"
+
+#, no-c-format
+msgid "E499: Empty file name for '%' or '#', only works with \":p:h\""
+msgstr ""
+"E499: '%' ¤ä '#' ¤¬ÌµÌ¾¥Õ¥¡¥¤¥ë¤Ê¤Î¤Ç \":p:h\" ¤òȼ¤ï¤Ê¤¤»È¤¤Êý¤Ï¤Ç¤­¤Þ¤»¤ó"
+
+msgid "E500: Evaluates to an empty string"
+msgstr "E500: ¶õʸ»úÎó¤È¤·¤Æɾ²Á¤µ¤ì¤Þ¤·¤¿"
+
+msgid "E195: Cannot open viminfo file for reading"
+msgstr "E195: viminfo¥Õ¥¡¥¤¥ë¤òÆɹþÍѤȤ·¤Æ³«¤±¤Þ¤»¤ó"
+
+msgid "Untitled"
+msgstr "̵Âê"
+
+msgid "E196: No digraphs in this version"
+msgstr "E196: ¤³¤Î¥Ð¡¼¥¸¥ç¥ó¤Ë¹ç»ú¤Ï¤¢¤ê¤Þ¤»¤ó"
+
+msgid "E608: Cannot :throw exceptions with 'Vim' prefix"
+msgstr "E608: 'Vim' ¤Ç»Ï¤Þ¤ëÎã³°¤Ï :throw ¤Ç¤­¤Þ¤»¤ó"
+
+#, c-format
+msgid "Exception thrown: %s"
+msgstr "Îã³°¤¬È¯À¸¤·¤Þ¤·¤¿: %s"
+
+#, c-format
+msgid "Exception finished: %s"
+msgstr "Îã³°¤¬¼ý«¤·¤Þ¤·¤¿: %s"
+
+#, c-format
+msgid "Exception discarded: %s"
+msgstr "Îã³°¤¬ÇË´þ¤µ¤ì¤Þ¤·¤¿: %s"
+
+#, c-format
+msgid "%s, line %ld"
+msgstr "%s, ¹Ô %ld"
+
+#, c-format
+msgid "Exception caught: %s"
+msgstr "Îã³°¤¬Ê᪤µ¤ì¤Þ¤·¤¿: %s"
+
+#, c-format
+msgid "%s made pending"
+msgstr "%s ¤Ë¤è¤ê̤·èÄê¾õÂÖ¤¬À¸¤¸¤Þ¤·¤¿"
+
+#, c-format
+msgid "%s resumed"
+msgstr "%s ¤¬ºÆ³«¤·¤Þ¤·¤¿"
+
+#, c-format
+msgid "%s discarded"
+msgstr "%s ¤¬ÇË´þ¤µ¤ì¤Þ¤·¤¿"
+
+msgid "Exception"
+msgstr "Îã³°"
+
+msgid "Error and interrupt"
+msgstr "¥¨¥é¡¼¤È³ä¹þ¤ß"
+
+msgid "Error"
+msgstr "¥¨¥é¡¼"
+
+msgid "Interrupt"
+msgstr "³ä¹þ¤ß"
+
+msgid "E579: :if nesting too deep"
+msgstr "E579: :if ¤ÎÆþ¤ì»Ò¤¬¿¼²á¤®¤Þ¤¹"
+
+msgid "E580: :endif without :if"
+msgstr "E580: :if ¤Î¤Ê¤¤ :endif ¤¬¤¢¤ê¤Þ¤¹"
+
+msgid "E581: :else without :if"
+msgstr "E581: :if ¤Î¤Ê¤¤ :else ¤¬¤¢¤ê¤Þ¤¹"
+
+msgid "E582: :elseif without :if"
+msgstr "E582: :if ¤Î¤Ê¤¤ :elseif ¤¬¤¢¤ê¤Þ¤¹"
+
+msgid "E583: multiple :else"
+msgstr "E583: Ê£¿ô¤Î :else ¤¬¤¢¤ê¤Þ¤¹"
+
+msgid "E584: :elseif after :else"
+msgstr "E584: :else ¤Î¸å¤Ë :elseif ¤¬¤¢¤ê¤Þ¤¹"
+
+msgid "E585: :while/:for nesting too deep"
+msgstr "E585: :while ¤ä :for ¤ÎÆþ¤ì»Ò¤¬¿¼²á¤®¤Þ¤¹"
+
+msgid "E586: :continue without :while or :for"
+msgstr "E586: :while ¤ä :for ¤Î¤Ê¤¤ :continue ¤¬¤¢¤ê¤Þ¤¹"
+
+msgid "E587: :break without :while or :for"
+msgstr "E587: :while ¤ä :for ¤Î¤Ê¤¤ :break ¤¬¤¢¤ê¤Þ¤¹"
+
+msgid "E732: Using :endfor with :while"
+msgstr "E732: :endfor ¤ò :while ¤ÈÁȤ߹ç¤ï¤»¤Æ¤¤¤Þ¤¹"
+
+msgid "E733: Using :endwhile with :for"
+msgstr "E733: :endwhile ¤ò :for ¤ÈÁȤ߹ç¤ï¤»¤Æ¤¤¤Þ¤¹"
+
+msgid "E601: :try nesting too deep"
+msgstr "E601: :try ¤ÎÆþ¤ì»Ò¤¬¿¼²á¤®¤Þ¤¹"
+
+msgid "E603: :catch without :try"
+msgstr "E603: :try ¤Î¤Ê¤¤ :catch ¤¬¤¢¤ê¤Þ¤¹"
+
+msgid "E604: :catch after :finally"
+msgstr "E604: :finally ¤Î¸å¤Ë :catch ¤¬¤¢¤ê¤Þ¤¹"
+
+msgid "E606: :finally without :try"
+msgstr "E606: :try ¤Î¤Ê¤¤ :finally ¤¬¤¢¤ê¤Þ¤¹"
+
+msgid "E607: multiple :finally"
+msgstr "E607: Ê£¿ô¤Î :finally ¤¬¤¢¤ê¤Þ¤¹"
+
+msgid "E602: :endtry without :try"
+msgstr "E602: :try ¤Î¤Ê¤¤ :endtry ¤Ç¤¹"
+
+msgid "E193: :endfunction not inside a function"
+msgstr "E193: ´Ø¿ô¤Î³°¤Ë :endfunction ¤¬¤¢¤ê¤Þ¤·¤¿"
+
+msgid "E788: Not allowed to edit another buffer now"
+msgstr "E788: ¸½ºß¤Ï¾¤Î¥Ð¥Ã¥Õ¥¡¤òÊÔ½¸¤¹¤ë¤³¤È¤Ïµö¤µ¤ì¤Þ¤»¤ó"
+
+msgid "E811: Not allowed to change buffer information now"
+msgstr "E811: ¸½ºß¤Ï¥Ð¥Ã¥Õ¥¡¾ðÊó¤òÊѹ¹¤¹¤ë¤³¤È¤Ïµö¤µ¤ì¤Þ¤»¤ó"
+
+msgid "tagname"
+msgstr "¥¿¥°Ì¾"
+
+msgid " kind file\n"
+msgstr " ¥Õ¥¡¥¤¥ë¼ïÎà\n"
+
+msgid "'history' option is zero"
+msgstr "¥ª¥×¥·¥ç¥ó 'history' ¤¬¥¼¥í¤Ç¤¹"
+
+#, c-format
+msgid ""
+"\n"
+"# %s History (newest to oldest):\n"
+msgstr ""
+"\n"
+"# %s ¹àÌܤÎÍúÎò (¿·¤·¤¤¤â¤Î¤«¤é¸Å¤¤¤â¤Î¤Ø):\n"
+
+msgid "Command Line"
+msgstr "¥³¥Þ¥ó¥É¥é¥¤¥ó"
+
+msgid "Search String"
+msgstr "¸¡º÷ʸ»úÎó"
+
+msgid "Expression"
+msgstr "¼°"
+
+msgid "Input Line"
+msgstr "ÆþÎϹÔ"
+
+msgid "Debug Line"
+msgstr "¥Ç¥Ð¥Ã¥°¹Ô"
+
+msgid "E198: cmd_pchar beyond the command length"
+msgstr "E198: cmd_pchar ¤¬¥³¥Þ¥ó¥ÉŤòĶ¤¨¤Þ¤·¤¿"
+
+msgid "E199: Active window or buffer deleted"
+msgstr "E199: ¥¢¥¯¥Æ¥£¥Ö¤Ê¥¦¥£¥ó¥É¥¦¤«¥Ð¥Ã¥Õ¥¡¤¬ºï½ü¤µ¤ì¤Þ¤·¤¿"
+
+msgid "E812: Autocommands changed buffer or buffer name"
+msgstr "E812: autocommand¤¬¥Ð¥Ã¥Õ¥¡¤«¥Ð¥Ã¥Õ¥¡Ì¾¤òÊѹ¹¤·¤Þ¤·¤¿"
+
+msgid "Illegal file name"
+msgstr "ÉÔÀµ¤Ê¥Õ¥¡¥¤¥ë̾"
+
+msgid "is a directory"
+msgstr "¤Ï¥Ç¥£¥ì¥¯¥È¥ê¤Ç¤¹"
+
+msgid "is not a file"
+msgstr "¤Ï¥Õ¥¡¥¤¥ë¤Ç¤Ï¤¢¤ê¤Þ¤»¤ó"
+
+msgid "is a device (disabled with 'opendevice' option)"
+msgstr "¤Ï¥Ç¥Ð¥¤¥¹¤Ç¤¹ ('opendevice' ¥ª¥×¥·¥ç¥ó¤Ç²óÈò¤Ç¤­¤Þ¤¹)"
+
+msgid "[New File]"
+msgstr "[¿·¥Õ¥¡¥¤¥ë]"
+
+msgid "[New DIRECTORY]"
+msgstr "[¿·µ¬¥Ç¥£¥ì¥¯¥È¥ê]"
+
+msgid "[File too big]"
+msgstr "[¥Õ¥¡¥¤¥ë²áÂç]"
+
+msgid "[Permission Denied]"
+msgstr "[¸¢¸Â¤¬¤¢¤ê¤Þ¤»¤ó]"
+
+msgid "E200: *ReadPre autocommands made the file unreadable"
+msgstr "E200: *ReadPre autocommand ¤¬¥Õ¥¡¥¤¥ë¤òÆɹþÉԲĤˤ·¤Þ¤·¤¿"
+
+msgid "E201: *ReadPre autocommands must not change current buffer"
+msgstr "E201: *ReadPre autocommand ¤Ï¸½ºß¤Î¥Ð¥Ã¥Õ¥¡¤òÊѤ¨¤é¤ì¤Þ¤»¤ó"
+
+msgid "Vim: Reading from stdin...\n"
+msgstr "Vim: ɸ½àÆþÎϤ«¤éÆɹþÃæ...\n"
+
+msgid "Reading from stdin..."
+msgstr "ɸ½àÆþÎϤ«¤éÆɹþ¤ßÃæ..."
+
+msgid "E202: Conversion made file unreadable!"
+msgstr "E202: ÊÑ´¹¤¬¥Õ¥¡¥¤¥ë¤òÆɹþÉԲĤˤ·¤Þ¤·¤¿"
+
+msgid "[fifo]"
+msgstr "[FIFO]"
+
+msgid "[socket]"
+msgstr "[¥½¥±¥Ã¥È]"
+
+msgid "[character special]"
+msgstr "[¥­¥ã¥é¥¯¥¿¡¦¥Ç¥Ð¥¤¥¹]"
+
+msgid "[CR missing]"
+msgstr "[CR̵]"
+
+msgid "[long lines split]"
+msgstr "[Ĺ¹Ôʬ³ä]"
+
+msgid "[NOT converted]"
+msgstr "[̤ÊÑ´¹]"
+
+msgid "[converted]"
+msgstr "[ÊÑ´¹ºÑ]"
+
+#, c-format
+msgid "[CONVERSION ERROR in line %ld]"
+msgstr "[%ld ¹ÔÌܤÇÊÑ´¹¥¨¥é¡¼]"
+
+#, c-format
+msgid "[ILLEGAL BYTE in line %ld]"
+msgstr "[%ld ¹ÔÌܤÎÉÔÀµ¤Ê¥Ð¥¤¥È]"
+
+msgid "[READ ERRORS]"
+msgstr "[Æɹþ¥¨¥é¡¼]"
+
+msgid "Can't find temp file for conversion"
+msgstr "ÊÑ´¹¤ËɬÍפʰì»þ¥Õ¥¡¥¤¥ë¤¬¸«¤Ä¤«¤ê¤Þ¤»¤ó"
+
+msgid "Conversion with 'charconvert' failed"
+msgstr "'charconvert' ¤Ë¤è¤ëÊÑ´¹¤¬¼ºÇÔ¤·¤Þ¤·¤¿"
+
+msgid "can't read output of 'charconvert'"
+msgstr "'charconvert' ¤Î½ÐÎϤòÆɹþ¤á¤Þ¤»¤ó¤Ç¤·¤¿"
+
+msgid "E676: No matching autocommands for acwrite buffer"
+msgstr "E676: acwrite¥Ð¥Ã¥Õ¥¡¤Î³ºÅö¤¹¤ëautocommand¤Ï¸ºß¤·¤Þ¤»¤ó"
+
+msgid "E203: Autocommands deleted or unloaded buffer to be written"
+msgstr "E203: Êݸ¤¹¤ë¥Ð¥Ã¥Õ¥¡¤òautocommand¤¬ºï½ü¤«²òÊü¤·¤Þ¤·¤¿"
+
+msgid "E204: Autocommand changed number of lines in unexpected way"
+msgstr "E204: autocommand¤¬Í½´ü¤»¤ÌÊýË¡¤Ç¹Ô¿ô¤òÊѹ¹¤·¤Þ¤·¤¿"
+
+# Added at 19-Jan-2004.
+msgid "NetBeans disallows writes of unmodified buffers"
+msgstr "NetBeans¤Ï̤Êѹ¹¤Î¥Ð¥Ã¥Õ¥¡¤ò¾å½ñ¤¹¤ë¤³¤È¤Ïµö²Ä¤·¤Æ¤¤¤Þ¤»¤ó"
+
+msgid "Partial writes disallowed for NetBeans buffers"
+msgstr "NetBeans¥Ð¥Ã¥Õ¥¡¤Î°ìÉô¤ò½ñ¤­½Ð¤¹¤³¤È¤Ï¤Ç¤­¤Þ¤»¤ó"
+
+msgid "is not a file or writable device"
+msgstr "¤Ï¥Õ¥¡¥¤¥ë¤Ç¤â½ñ¹þ¤ß²Äǽ¥Ç¥Ð¥¤¥¹¤Ç¤â¤¢¤ê¤Þ¤»¤ó"
+
+msgid "writing to device disabled with 'opendevice' option"
+msgstr "'opendevice' ¥ª¥×¥·¥ç¥ó¤Ë¤è¤ê¥Ç¥Ð¥¤¥¹¤Ø¤Î½ñ¤­¹þ¤ß¤Ï¤Ç¤­¤Þ¤»¤ó"
+
+msgid "is read-only (add ! to override)"
+msgstr "¤ÏÆɹþÀìÍѤǤ¹ (¶¯À©½ñ¹þ¤Ë¤Ï ! ¤òÄɲÃ)"
+
+msgid "E506: Can't write to backup file (add ! to override)"
+msgstr "E506: ¥Ð¥Ã¥¯¥¢¥Ã¥×¥Õ¥¡¥¤¥ë¤òÊݸ¤Ç¤­¤Þ¤»¤ó (! ¤òÄɲäǶ¯À©Êݸ)"
+
+msgid "E507: Close error for backup file (add ! to override)"
+msgstr ""
+"E507: ¥Ð¥Ã¥¯¥¢¥Ã¥×¥Õ¥¡¥¤¥ë¤òÊĤ¸¤ëºÝ¤Ë¥¨¥é¡¼¤¬È¯À¸¤·¤Þ¤·¤¿ (! ¤òÄɲäǶ¯À©)"
+
+msgid "E508: Can't read file for backup (add ! to override)"
+msgstr "E508: ¥Ð¥Ã¥¯¥¢¥Ã¥×ÍÑ¥Õ¥¡¥¤¥ë¤òÆɹþ¤á¤Þ¤»¤ó (! ¤òÄɲäǶ¯À©Æɹþ)"
+
+msgid "E509: Cannot create backup file (add ! to override)"
+msgstr "E509: ¥Ð¥Ã¥¯¥¢¥Ã¥×¥Õ¥¡¥¤¥ë¤òºî¤ì¤Þ¤»¤ó (! ¤òÄɲäǶ¯À©ºîÀ®)"
+
+msgid "E510: Can't make backup file (add ! to override)"
+msgstr "E510: ¥Ð¥Ã¥¯¥¢¥Ã¥×¥Õ¥¡¥¤¥ë¤òºî¤ì¤Þ¤»¤ó (! ¤òÄɲäǶ¯À©ºîÀ®)"
+
+msgid "E214: Can't find temp file for writing"
+msgstr "E214: ÊݸÍÑ°ì»þ¥Õ¥¡¥¤¥ë¤¬¸«¤Ä¤«¤ê¤Þ¤»¤ó"
+
+msgid "E213: Cannot convert (add ! to write without conversion)"
+msgstr "E213: ÊÑ´¹¤Ç¤­¤Þ¤»¤ó (! ¤òÄɲäÇÊÑ´¹¤»¤º¤ËÊݸ)"
+
+msgid "E166: Can't open linked file for writing"
+msgstr "E166: ¥ê¥ó¥¯¤µ¤ì¤¿¥Õ¥¡¥¤¥ë¤Ë½ñ¹þ¤á¤Þ¤»¤ó"
+
+msgid "E212: Can't open file for writing"
+msgstr "E212: ½ñ¹þ¤ßÍѤ˥ե¡¥¤¥ë¤ò³«¤±¤Þ¤»¤ó"
+
+msgid "E949: File changed while writing"
+msgstr "E949: ½ñ¹þ¤ßÃæ¤Ë¥Õ¥¡¥¤¥ë¤¬Êѹ¹¤µ¤ì¤Þ¤·¤¿"
+
+msgid "E512: Close failed"
+msgstr "E512: ÊĤ¸¤ë¤³¤È¤Ë¼ºÇÔ"
+
+msgid "E513: write error, conversion failed (make 'fenc' empty to override)"
+msgstr "E513: ½ñ¹þ¤ß¥¨¥é¡¼¡¢ÊÑ´¹¼ºÇÔ (¾å½ñ¤¹¤ë¤Ë¤Ï 'fenc' ¤ò¶õ¤Ë¤·¤Æ¤¯¤À¤µ¤¤)"
+
+#, c-format
+msgid ""
+"E513: write error, conversion failed in line %ld (make 'fenc' empty to "
+"override)"
+msgstr ""
+"E513: ½ñ¹þ¤ß¥¨¥é¡¼¡¢ÊÑ´¹¼ºÇÔ¡¢¹Ô¿ô %ld (¾å½ñ¤¹¤ë¤Ë¤Ï 'fenc' ¤ò¶õ¤Ë¤·¤Æ¤¯¤À¤µ"
+"¤¤)"
+
+msgid "E514: write error (file system full?)"
+msgstr "E514: ½ñ¹þ¤ß¥¨¥é¡¼ (¥Õ¥¡¥¤¥ë¥·¥¹¥Æ¥à¤¬ËþÇÕ?)"
+
+msgid " CONVERSION ERROR"
+msgstr " ÊÑ´¹¥¨¥é¡¼"
+
+#, c-format
+msgid " in line %ld;"
+msgstr " ¹Ô %ld;"
+
+msgid "[Device]"
+msgstr "[¥Ç¥Ð¥¤¥¹]"
+
+msgid "[New]"
+msgstr "[¿·]"
+
+msgid " [a]"
+msgstr " [a]"
+
+msgid " appended"
+msgstr " ÄɲÃ"
+
+msgid " [w]"
+msgstr " [w]"
+
+msgid " written"
+msgstr " ½ñ¹þ¤ß"
+
+msgid "E205: Patchmode: can't save original file"
+msgstr "E205: patchmode: ¸¶ËÜ¥Õ¥¡¥¤¥ë¤òÊݸ¤Ç¤­¤Þ¤»¤ó"
+
+msgid "E206: patchmode: can't touch empty original file"
+msgstr "E206: patchmode: ¶õ¤Î¸¶ËÜ¥Õ¥¡¥¤¥ë¤òtouch¤Ç¤­¤Þ¤»¤ó"
+
+msgid "E207: Can't delete backup file"
+msgstr "E207: ¥Ð¥Ã¥¯¥¢¥Ã¥×¥Õ¥¡¥¤¥ë¤ò¾Ã¤»¤Þ¤»¤ó"
+
+msgid ""
+"\n"
+"WARNING: Original file may be lost or damaged\n"
+msgstr ""
+"\n"
+"·Ù¹ð: ¸¶ËÜ¥Õ¥¡¥¤¥ë¤¬¼º¤ï¤ì¤¿¤«Êѹ¹¤µ¤ì¤Þ¤·¤¿\n"
+
+msgid "don't quit the editor until the file is successfully written!"
+msgstr "¥Õ¥¡¥¤¥ë¤ÎÊݸ¤ËÀ®¸ù¤¹¤ë¤Þ¤Ç¥¨¥Ç¥£¥¿¤ò½ªÎ»¤·¤Ê¤¤¤Ç¤¯¤À¤µ¤¤!"
+
+msgid "[dos]"
+msgstr "[dos]"
+
+msgid "[dos format]"
+msgstr "[dos¥Õ¥©¡¼¥Þ¥Ã¥È]"
+
+msgid "[mac]"
+msgstr "[mac]"
+
+msgid "[mac format]"
+msgstr "[mac¥Õ¥©¡¼¥Þ¥Ã¥È]"
+
+msgid "[unix]"
+msgstr "[unix]"
+
+msgid "[unix format]"
+msgstr "[unix¥Õ¥©¡¼¥Þ¥Ã¥È]"
+
+#, c-format
+msgid "%ld line, "
+msgid_plural "%ld lines, "
+msgstr[0] "%ld ¹Ô, "
+
+#, c-format
+msgid "%lld character"
+msgid_plural "%lld characters"
+msgstr[0] "%lld ʸ»ú"
+
+msgid "[noeol]"
+msgstr "[noeol]"
+
+msgid "[Incomplete last line]"
+msgstr "[ºÇ½ª¹Ô¤¬ÉÔ´°Á´]"
+
+msgid "WARNING: The file has been changed since reading it!!!"
+msgstr "·Ù¹ð: Æɹþ¤ó¤À¸å¤Ë¥Õ¥¡¥¤¥ë¤ËÊѹ¹¤¬¤¢¤ê¤Þ¤·¤¿!!!"
+
+msgid "Do you really want to write to it"
+msgstr "ËÜÅö¤Ë¾å½ñ¤­¤·¤Þ¤¹¤«"
+
+#, c-format
+msgid "E208: Error writing to \"%s\""
+msgstr "E208: \"%s\" ¤ò½ñ¹þ¤ßÃæ¤Î¥¨¥é¡¼¤Ç¤¹"
+
+#, c-format
+msgid "E209: Error closing \"%s\""
+msgstr "E209: \"%s\" ¤òÊĤ¸¤ë»þ¤Ë¥¨¥é¡¼¤Ç¤¹"
+
+#, c-format
+msgid "E210: Error reading \"%s\""
+msgstr "E210: \"%s\" ¤òÆɹþÃæ¤Î¥¨¥é¡¼¤Ç¤¹"
+
+msgid "E246: FileChangedShell autocommand deleted buffer"
+msgstr "E246: autocommand ¤Î FileChangedShell ¤¬¥Ð¥Ã¥Õ¥¡¤òºï½ü¤·¤Þ¤·¤¿"
+
+#, c-format
+msgid "E211: File \"%s\" no longer available"
+msgstr "E211: ¥Õ¥¡¥¤¥ë \"%s\" ¤Ï´û¤Ë¸ºß¤·¤Þ¤»¤ó"
+
+#, c-format
+msgid ""
+"W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as "
+"well"
+msgstr "W12: ·Ù¹ð: ¥Õ¥¡¥¤¥ë \"%s\" ¤¬Êѹ¹¤µ¤ìVim¤Î¥Ð¥Ã¥Õ¥¡¤âÊѹ¹¤µ¤ì¤Þ¤·¤¿"
+
+msgid "See \":help W12\" for more info."
+msgstr "¾ÜºÙ¤Ï \":help W12\" ¤ò»²¾È¤·¤Æ¤¯¤À¤µ¤¤"
+
+#, c-format
+msgid "W11: Warning: File \"%s\" has changed since editing started"
+msgstr "W11: ·Ù¹ð: ¥Õ¥¡¥¤¥ë \"%s\" ¤ÏÊÔ½¸³«»Ï¸å¤ËÊѹ¹¤µ¤ì¤Þ¤·¤¿"
+
+msgid "See \":help W11\" for more info."
+msgstr "¾ÜºÙ¤Ï \":help W11\" ¤ò»²¾È¤·¤Æ¤¯¤À¤µ¤¤"
+
+#, c-format
+msgid "W16: Warning: Mode of file \"%s\" has changed since editing started"
+msgstr "W16: ·Ù¹ð: ¥Õ¥¡¥¤¥ë \"%s\" ¤Î¥â¡¼¥É¤¬ÊÔ½¸³«»Ï¸å¤ËÊѹ¹¤µ¤ì¤Þ¤·¤¿"
+
+msgid "See \":help W16\" for more info."
+msgstr "¾ÜºÙ¤Ï \":help W16\" ¤ò»²¾È¤·¤Æ¤¯¤À¤µ¤¤"
+
+#, c-format
+msgid "W13: Warning: File \"%s\" has been created after editing started"
+msgstr "W13: ·Ù¹ð: ¥Õ¥¡¥¤¥ë \"%s\" ¤ÏÊÔ½¸³«»Ï¸å¤ËºîÀ®¤µ¤ì¤Þ¤·¤¿"
+
+msgid "Warning"
+msgstr "·Ù¹ð"
+
+msgid ""
+"&OK\n"
+"&Load File"
+msgstr ""
+"&OK\n"
+"¥Õ¥¡¥¤¥ëÆɹþ(&L)"
+
+#, c-format
+msgid "E462: Could not prepare for reloading \"%s\""
+msgstr "E462: \"%s\" ¤ò¥ê¥í¡¼¥É¤¹¤ë½àÈ÷¤¬¤Ç¤­¤Þ¤»¤ó¤Ç¤·¤¿"
+
+#, c-format
+msgid "E321: Could not reload \"%s\""
+msgstr "E321: \"%s\" ¤Ï¥ê¥í¡¼¥É¤Ç¤­¤Þ¤»¤ó¤Ç¤·¤¿"
+
+msgid "--Deleted--"
+msgstr "--ºï½üºÑ--"
+
+#, c-format
+msgid "auto-removing autocommand: %s <buffer=%d>"
+msgstr "autocommand: %s <¥Ð¥Ã¥Õ¥¡=%d> ¤¬¼«Æ°Åª¤Ëºï½ü¤µ¤ì¤Þ¤¹"
+
+#, c-format
+msgid "E367: No such group: \"%s\""
+msgstr "E367: ¤½¤Î¥°¥ë¡¼¥×¤Ï¤¢¤ê¤Þ¤»¤ó: \"%s\""
+
+msgid "E936: Cannot delete the current group"
+msgstr "E936: ¸½ºß¤Î¥°¥ë¡¼¥×¤Ïºï½ü¤Ç¤­¤Þ¤»¤ó"
+
+msgid "W19: Deleting augroup that is still in use"
+msgstr "W19: »ÈÍÑÃæ¤Î augroup ¤ò¾Ã¤½¤¦¤È¤·¤Æ¤¤¤Þ¤¹"
+
+#, c-format
+msgid "E215: Illegal character after *: %s"
+msgstr "E215: * ¤Î¸å¤ËÉÔÀµ¤Êʸ»ú¤¬¤¢¤ê¤Þ¤·¤¿: %s"
+
+#, c-format
+msgid "E216: No such event: %s"
+msgstr "E216: ¤½¤Î¤è¤¦¤Ê¥¤¥Ù¥ó¥È¤Ï¤¢¤ê¤Þ¤»¤ó: %s"
+
+#, c-format
+msgid "E216: No such group or event: %s"
+msgstr "E216: ¤½¤Î¤è¤¦¤Ê¥°¥ë¡¼¥×¤â¤·¤¯¤Ï¥¤¥Ù¥ó¥È¤Ï¤¢¤ê¤Þ¤»¤ó: %s"
+
+msgid ""
+"\n"
+"--- Autocommands ---"
+msgstr ""
+"\n"
+"--- Autocommands ---"
+
+#, c-format
+msgid "E680: <buffer=%d>: invalid buffer number "
+msgstr "E680: <¥Ð¥Ã¥Õ¥¡=%d>: ̵¸ú¤Ê¥Ð¥Ã¥Õ¥¡ÈÖ¹æ¤Ç¤¹ "
+
+msgid "E217: Can't execute autocommands for ALL events"
+msgstr "E217: Á´¤Æ¤Î¥¤¥Ù¥ó¥È¤ËÂФ·¤Æ¤Îautocommand¤Ï¼Â¹Ô¤Ç¤­¤Þ¤»¤ó"
+
+msgid "No matching autocommands"
+msgstr "³ºÅö¤¹¤ëautocommand¤Ï¸ºß¤·¤Þ¤»¤ó"
+
+msgid "E218: autocommand nesting too deep"
+msgstr "E218: autocommand¤ÎÆþ¤ì»Ò¤¬¿¼²á¤®¤Þ¤¹"
+
+#, c-format
+msgid "%s Autocommands for \"%s\""
+msgstr "%s Autocommands for \"%s\""
+
+#, c-format
+msgid "Executing %s"
+msgstr "%s ¤ò¼Â¹Ô¤·¤Æ¤¤¤Þ¤¹"
+
+#, c-format
+msgid "autocommand %s"
+msgstr "autocommand %s"
+
+msgid "E219: Missing {."
+msgstr "E219: { ¤¬¤¢¤ê¤Þ¤»¤ó."
+
+msgid "E220: Missing }."
+msgstr "E220: } ¤¬¤¢¤ê¤Þ¤»¤ó."
+
+msgid "E490: No fold found"
+msgstr "E490: ÀÞ¾ö¤ß¤¬¤¢¤ê¤Þ¤»¤ó"
+
+msgid "E350: Cannot create fold with current 'foldmethod'"
+msgstr "E350: ¸½ºß¤Î 'foldmethod' ¤Ç¤ÏÀÞ¾ö¤ß¤òºîÀ®¤Ç¤­¤Þ¤»¤ó"
+
+msgid "E351: Cannot delete fold with current 'foldmethod'"
+msgstr "E351: ¸½ºß¤Î 'foldmethod' ¤Ç¤ÏÀÞ¾ö¤ß¤òºï½ü¤Ç¤­¤Þ¤»¤ó"
+
+#, c-format
+msgid "+--%3ld line folded "
+msgid_plural "+--%3ld lines folded "
+msgstr[0] "+--%3ld ¹Ô¤¬ÀÞ¾ö¤Þ¤ì¤Þ¤·¤¿"
+
+msgid "E222: Add to read buffer"
+msgstr "E222: Æɹþ¥Ð¥Ã¥Õ¥¡¤ØÄɲÃ"
+
+msgid "E223: recursive mapping"
+msgstr "E223: ºÆµ¢Åª¥Þ¥Ã¥Ô¥ó¥°"
+
+#, c-format
+msgid "E224: global abbreviation already exists for %s"
+msgstr "E224: %s ¤È¤¤¤¦¥°¥í¡¼¥Ð¥ëû½ÌÆþÎϤϴû¤Ë¸ºß¤·¤Þ¤¹"
+
+#, c-format
+msgid "E225: global mapping already exists for %s"
+msgstr "E225: %s ¤È¤¤¤¦¥°¥í¡¼¥Ð¥ë¥Þ¥Ã¥Ô¥ó¥°¤Ï´û¤Ë¸ºß¤·¤Þ¤¹"
+
+#, c-format
+msgid "E226: abbreviation already exists for %s"
+msgstr "E226: %s ¤È¤¤¤¦Ã»½ÌÆþÎϤϴû¤Ë¸ºß¤·¤Þ¤¹"
+
+#, c-format
+msgid "E227: mapping already exists for %s"
+msgstr "E227: %s ¤È¤¤¤¦¥Þ¥Ã¥Ô¥ó¥°¤Ï´û¤Ë¸ºß¤·¤Þ¤¹"
+
+msgid "No abbreviation found"
+msgstr "û½ÌÆþÎϤϸ«¤Ä¤«¤ê¤Þ¤»¤ó¤Ç¤·¤¿"
+
+msgid "No mapping found"
+msgstr "¥Þ¥Ã¥Ô¥ó¥°¤Ï¸«¤Ä¤«¤ê¤Þ¤»¤ó¤Ç¤·¤¿"
+
+msgid "E228: makemap: Illegal mode"
+msgstr "E228: makemap: ÉÔÀµ¤Ê¥â¡¼¥É"
+
+msgid "E851: Failed to create a new process for the GUI"
+msgstr "E851: GUIÍÑ¤Î¥×¥í¥»¥¹¤Îµ¯Æ°¤Ë¼ºÇÔ¤·¤Þ¤·¤¿"
+
+msgid "E852: The child process failed to start the GUI"
+msgstr "E852: »Ò¥×¥í¥»¥¹¤¬GUI¤Îµ¯Æ°¤Ë¼ºÇÔ¤·¤Þ¤·¤¿"
+
+msgid "E229: Cannot start the GUI"
+msgstr "E229: GUI¤ò³«»Ï¤Ç¤­¤Þ¤»¤ó"
+
+#, c-format
+msgid "E230: Cannot read from \"%s\""
+msgstr "E230: \"%s\"¤«¤éÆɹþ¤à¤³¤È¤¬¤Ç¤­¤Þ¤»¤ó"
+
+msgid "E665: Cannot start GUI, no valid font found"
+msgstr "E665: Í­¸ú¤Ê¥Õ¥©¥ó¥È¤¬¸«¤Ä¤«¤é¤Ê¤¤¤Î¤Ç¡¢GUI¤ò³«»Ï¤Ç¤­¤Þ¤»¤ó"
+
+msgid "E231: 'guifontwide' invalid"
+msgstr "E231: 'guifontwide' ¤¬Ìµ¸ú¤Ç¤¹"
+
+msgid "E599: Value of 'imactivatekey' is invalid"
+msgstr "E599: 'imactivatekey' ¤ËÀßÄꤵ¤ì¤¿Ãͤ¬Ìµ¸ú¤Ç¤¹"
+
+#, c-format
+msgid "E254: Cannot allocate color %s"
+msgstr "E254: %s ¤Î¿§¤ò³ä¤êÅö¤Æ¤é¤ì¤Þ¤»¤ó"
+
+msgid "No match at cursor, finding next"
+msgstr "¥«¡¼¥½¥ë¤Î°ÌÃ֤˥ޥåÁ¤Ï¤¢¤ê¤Þ¤»¤ó¡¢¼¡¤ò¸¡º÷¤·¤Æ¤¤¤Þ¤¹"
+
+msgid "<cannot open> "
+msgstr "<³«¤±¤Þ¤»¤ó> "
+
+#, c-format
+msgid "E616: vim_SelFile: can't get font %s"
+msgstr "E616: vim_SelFile: ¥Õ¥©¥ó¥È %s ¤ò¼èÆÀ¤Ç¤­¤Þ¤»¤ó"
+
+msgid "E614: vim_SelFile: can't return to current directory"
+msgstr "E614: vim_SelFile: ¸½ºß¤Î¥Ç¥£¥ì¥¯¥È¥ê¤ËÌá¤ì¤Þ¤»¤ó"
+
+msgid "Pathname:"
+msgstr "¥Ñ¥¹Ì¾:"
+
+msgid "E615: vim_SelFile: can't get current directory"
+msgstr "E615: vim_SelFile: ¸½ºß¤Î¥Ç¥£¥ì¥¯¥È¥ê¤ò¼èÆÀ¤Ç¤­¤Þ¤»¤ó"
+
+msgid "OK"
+msgstr "OK"
+
+msgid "Cancel"
+msgstr "¥­¥ã¥ó¥»¥ë"
+
+msgid "Scrollbar Widget: Could not get geometry of thumb pixmap."
+msgstr "¥¹¥¯¥í¡¼¥ë¥Ð¡¼: ²èÁü¤ò¼èÆÀ¤Ç¤­¤Þ¤»¤ó¤Ç¤·¤¿."
+
+msgid "Vim dialog"
+msgstr "Vim ¥À¥¤¥¢¥í¥°"
+
+msgid "E232: Cannot create BalloonEval with both message and callback"
+msgstr "E232: ¥á¥Ã¥»¡¼¥¸¤È¥³¡¼¥ë¥Ð¥Ã¥¯¤Î¤¢¤ë BalloonEval ¤òºîÀ®¤Ç¤­¤Þ¤»¤ó"
+
+msgid "_Cancel"
+msgstr "¥­¥ã¥ó¥»¥ë(_C)"
+
+msgid "_Save"
+msgstr "Êݸ(_S)"
+
+msgid "_Open"
+msgstr "³«¤¯(_O)"
+
+msgid "_OK"
+msgstr "_OK"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"&Cancel"
+msgstr ""
+"¤Ï¤¤(&Y)\n"
+"¤¤¤¤¤¨(&N)\n"
+"¥­¥ã¥ó¥»¥ë(&C)"
+
+msgid "Yes"
+msgstr "¤Ï¤¤"
+
+msgid "No"
+msgstr "¤¤¤¤¤¨"
+
+msgid "Input _Methods"
+msgstr "¥¤¥ó¥×¥Ã¥È¥á¥½¥Ã¥É"
+
+msgid "VIM - Search and Replace..."
+msgstr "VIM - ¸¡º÷¤ÈÃÖ´¹..."
+
+msgid "VIM - Search..."
+msgstr "VIM - ¸¡º÷..."
+
+msgid "Find what:"
+msgstr "¸¡º÷ʸ»úÎó:"
+
+msgid "Replace with:"
+msgstr "ÃÖ´¹Ê¸»úÎó:"
+
+msgid "Match whole word only"
+msgstr "Àµ³Î¤Ë³ºÅö¤¹¤ë¤â¤Î¤À¤±"
+
+msgid "Match case"
+msgstr "Âçʸ»ú/¾®Ê¸»ú¤ò¶èÊ̤¹¤ë"
+
+msgid "Direction"
+msgstr "Êý¸þ"
+
+msgid "Up"
+msgstr "¾å"
+
+msgid "Down"
+msgstr "²¼"
+
+msgid "Find Next"
+msgstr "¼¡¤ò¸¡º÷"
+
+msgid "Replace"
+msgstr "ÃÖ´¹"
+
+msgid "Replace All"
+msgstr "Á´¤ÆÃÖ´¹"
+
+msgid "_Close"
+msgstr "ÊĤ¸¤ë(_C)"
+
+msgid "Vim: Received \"die\" request from session manager\n"
+msgstr "Vim: ¥»¥Ã¥·¥ç¥ó¥Þ¥Í¡¼¥¸¥ã¤«¤é \"die\" Í×µá¤ò¼õ¤±¼è¤ê¤Þ¤·¤¿\n"
+
+msgid "Close tab"
+msgstr "¥¿¥Ö¥Ú¡¼¥¸¤òÊĤ¸¤ë"
+
+msgid "New tab"
+msgstr "¿·µ¬¥¿¥Ö¥Ú¡¼¥¸"
+
+msgid "Open Tab..."
+msgstr "¥¿¥Ö¥Ú¡¼¥¸¤ò³«¤¯..."
+
+msgid "Vim: Main window unexpectedly destroyed\n"
+msgstr "Vim: ¥á¥¤¥ó¥¦¥£¥ó¥É¥¦¤¬ÉÔ°Õ¤ËÇ˲õ¤µ¤ì¤Þ¤·¤¿\n"
+
+msgid "&Filter"
+msgstr "¥Õ¥£¥ë¥¿(&F)"
+
+msgid "&Cancel"
+msgstr "¥­¥ã¥ó¥»¥ë(&C)"
+
+msgid "Directories"
+msgstr "¥Ç¥£¥ì¥¯¥È¥ê"
+
+msgid "Filter"
+msgstr "¥Õ¥£¥ë¥¿"
+
+msgid "&Help"
+msgstr "¥Ø¥ë¥×(&H)"
+
+msgid "Files"
+msgstr "¥Õ¥¡¥¤¥ë"
+
+msgid "&OK"
+msgstr "&OK"
+
+msgid "Selection"
+msgstr "ÁªÂò"
+
+msgid "Find &Next"
+msgstr "¼¡¤ò¸¡º÷(&N)"
+
+msgid "&Replace"
+msgstr "ÃÖ´¹(&R)"
+
+msgid "Replace &All"
+msgstr "Á´¤ÆÃÖ´¹(&A)"
+
+msgid "&Undo"
+msgstr "¥¢¥ó¥É¥¥(&U)"
+
+msgid "Open tab..."
+msgstr "¥¿¥Ö¥Ú¡¼¥¸¤ò³«¤¯"
+
+msgid "Find string"
+msgstr "¸¡º÷ʸ»úÎó"
+
+msgid "Find & Replace"
+msgstr "¸¡º÷¡¦ÃÖ´¹"
+
+msgid "Not Used"
+msgstr "»È¤ï¤ì¤Þ¤»¤ó"
+
+msgid "Directory\t*.nothing\n"
+msgstr "¥Ç¥£¥ì¥¯¥È¥ê\t*.nothing\n"
+
+#, c-format
+msgid "E671: Cannot find window title \"%s\""
+msgstr "E671: ¥¿¥¤¥È¥ë¤¬ \"%s\" ¤Î¥¦¥£¥ó¥É¥¦¤Ï¸«¤Ä¤«¤ê¤Þ¤»¤ó"
+
+#, c-format
+msgid "E243: Argument not supported: \"-%s\"; Use the OLE version."
+msgstr "E243: °ú¿ô¤Ï¥µ¥Ý¡¼¥È¤µ¤ì¤Þ¤»¤ó: \"-%s\"; OLEÈǤò»ÈÍѤ·¤Æ¤¯¤À¤µ¤¤."
+
+msgid "E672: Unable to open window inside MDI application"
+msgstr "E672: MDI¥¢¥×¥ê¤ÎÃæ¤Ç¤Ï¥¦¥£¥ó¥É¥¦¤ò³«¤±¤Þ¤»¤ó"
+
+msgid "Vim E458: Cannot allocate colormap entry, some colors may be incorrect"
+msgstr "Vim E458: ¿§»ØÄ꤬Àµ¤·¤¯¤Ê¤¤¤Î¤Ç¥¨¥ó¥È¥ê¤ò³ä¤êÅö¤Æ¤é¤ì¤Þ¤»¤ó"
+
+#, c-format
+msgid "E250: Fonts for the following charsets are missing in fontset %s:"
+msgstr "E250: °Ê²¼¤Îʸ»ú¥»¥Ã¥È¤Î¥Õ¥©¥ó¥È¤¬¤¢¤ê¤Þ¤»¤ó %s:"
+
+#, c-format
+msgid "E252: Fontset name: %s"
+msgstr "E252: ¥Õ¥©¥ó¥È¥»¥Ã¥È̾: %s"
+
+#, c-format
+msgid "Font '%s' is not fixed-width"
+msgstr "¥Õ¥©¥ó¥È '%s' ¤Ï¸ÇÄêÉý¤Ç¤Ï¤¢¤ê¤Þ¤»¤ó"
+
+#, c-format
+msgid "E253: Fontset name: %s"
+msgstr "E253: ¥Õ¥©¥ó¥È¥»¥Ã¥È̾: %s"
+
+#, c-format
+msgid "Font0: %s"
+msgstr "¥Õ¥©¥ó¥È0: %s"
+
+#, c-format
+msgid "Font1: %s"
+msgstr "¥Õ¥©¥ó¥È1: %s"
+
+#, c-format
+msgid "Font%ld width is not twice that of font0"
+msgstr "¥Õ¥©¥ó¥È%ld ¤ÎÉý¤¬¥Õ¥©¥ó¥È0¤Î2ÇܤǤϤ¢¤ê¤Þ¤»¤ó"
+
+#, c-format
+msgid "Font0 width: %ld"
+msgstr "¥Õ¥©¥ó¥È0¤ÎÉý: %ld"
+
+#, c-format
+msgid "Font1 width: %ld"
+msgstr "¥Õ¥©¥ó¥È1¤ÎÉý: %ld"
+
+msgid "Invalid font specification"
+msgstr "̵¸ú¤Ê¥Õ¥©¥ó¥È»ØÄê¤Ç¤¹"
+
+msgid "&Dismiss"
+msgstr "µÑ²¼¤¹¤ë(&D)"
+
+msgid "no specific match"
+msgstr "¥Þ¥Ã¥Á¤¹¤ë¤â¤Î¤¬¤¢¤ê¤Þ¤»¤ó"
+
+msgid "Vim - Font Selector"
+msgstr "Vim - ¥Õ¥©¥ó¥ÈÁªÂò"
+
+msgid "Name:"
+msgstr "̾Á°:"
+
+msgid "Show size in Points"
+msgstr "¥µ¥¤¥º¤ò¥Ý¥¤¥ó¥È¤Çɽ¼¨¤¹¤ë"
+
+msgid "Encoding:"
+msgstr "¥¨¥ó¥³¡¼¥É:"
+
+msgid "Font:"
+msgstr "¥Õ¥©¥ó¥È:"
+
+msgid "Style:"
+msgstr "¥¹¥¿¥¤¥ë:"
+
+msgid "Size:"
+msgstr "¥µ¥¤¥º:"
+
+msgid "E256: Hangul automata ERROR"
+msgstr "E256: ¥Ï¥ó¥°¥ë¥ª¡¼¥È¥Þ¥È¥ó¥¨¥é¡¼"
+
+msgid "E550: Missing colon"
+msgstr "E550: ¥³¥í¥ó¤¬¤¢¤ê¤Þ¤»¤ó"
+
+msgid "E551: Illegal component"
+msgstr "E551: ÉÔÀµ¤Ê¹½Ê¸Í×ÁǤǤ¹"
+
+msgid "E552: digit expected"
+msgstr "E552: ¿ôÃͤ¬É¬ÍפǤ¹"
+
+#, c-format
+msgid "Page %d"
+msgstr "%d ¥Ú¡¼¥¸"
+
+msgid "No text to be printed"
+msgstr "°õºþ¤¹¤ë¥Æ¥­¥¹¥È¤¬¤¢¤ê¤Þ¤»¤ó"
+
+#, c-format
+msgid "Printing page %d (%d%%)"
+msgstr "°õºþÃæ: ¥Ú¡¼¥¸ %d (%d%%)"
+
+#, c-format
+msgid " Copy %d of %d"
+msgstr " ¥³¥Ô¡¼ %d (Á´ %d Ãæ)"
+
+#, c-format
+msgid "Printed: %s"
+msgstr "°õºþ¤·¤Þ¤·¤¿: %s"
+
+msgid "Printing aborted"
+msgstr "°õºþ¤¬Ãæ»ß¤µ¤ì¤Þ¤·¤¿"
+
+msgid "E455: Error writing to PostScript output file"
+msgstr "E455: PostScript½ÐÎÏ¥Õ¥¡¥¤¥ë¤Î½ñ¹þ¤ß¥¨¥é¡¼¤Ç¤¹"
+
+#, c-format
+msgid "E624: Can't open file \"%s\""
+msgstr "E624: ¥Õ¥¡¥¤¥ë \"%s\" ¤ò³«¤±¤Þ¤»¤ó"
+
+#, c-format
+msgid "E457: Can't read PostScript resource file \"%s\""
+msgstr "E457: PostScript¤Î¥ê¥½¡¼¥¹¥Õ¥¡¥¤¥ë \"%s\" ¤òÆɹþ¤á¤Þ¤»¤ó"
+
+#, c-format
+msgid "E618: file \"%s\" is not a PostScript resource file"
+msgstr "E618: ¥Õ¥¡¥¤¥ë \"%s\" ¤Ï PostScript ¥ê¥½¡¼¥¹¥Õ¥¡¥¤¥ë¤Ç¤Ï¤¢¤ê¤Þ¤»¤ó"
+
+#, c-format
+msgid "E619: file \"%s\" is not a supported PostScript resource file"
+msgstr "E619: ¥Õ¥¡¥¤¥ë \"%s\" ¤ÏÂбþ¤·¤Æ¤¤¤Ê¤¤ PostScript ¥ê¥½¡¼¥¹¥Õ¥¡¥¤¥ë¤Ç¤¹"
+
+#, c-format
+msgid "E621: \"%s\" resource file has wrong version"
+msgstr "E621: ¥ê¥½¡¼¥¹¥Õ¥¡¥¤¥ë \"%s\" ¤Ï¥Ð¡¼¥¸¥ç¥ó¤¬°Û¤Ê¤ê¤Þ¤¹"
+
+msgid "E673: Incompatible multi-byte encoding and character set."
+msgstr "E673: ¸ß´¹À­¤Î̵¤¤¥Þ¥ë¥Á¥Ð¥¤¥È¥¨¥ó¥³¡¼¥Ç¥£¥ó¥°¤Èʸ»ú¥»¥Ã¥È¤Ç¤¹"
+
+msgid "E674: printmbcharset cannot be empty with multi-byte encoding."
+msgstr "E674: ¥Þ¥ë¥Á¥Ð¥¤¥È¥¨¥ó¥³¡¼¥Ç¥£¥ó¥°¤Ç¤Ï printmbcharset ¤ò¶õ¤Ë¤Ç¤­¤Þ¤»¤ó"
+
+msgid "E675: No default font specified for multi-byte printing."
+msgstr ""
+"E675: ¥Þ¥ë¥Á¥Ð¥¤¥Èʸ»ú¤ò°õºþ¤¹¤ë¤¿¤á¤Î¥Ç¥Õ¥©¥ë¥È¥Õ¥©¥ó¥È¤¬»ØÄꤵ¤ì¤Æ¤¤¤Þ¤»¤ó"
+
+msgid "E324: Can't open PostScript output file"
+msgstr "E324: PostScript½ÐÎÏÍѤΥե¡¥¤¥ë¤ò³«¤±¤Þ¤»¤ó"
+
+#, c-format
+msgid "E456: Can't open file \"%s\""
+msgstr "E456: ¥Õ¥¡¥¤¥ë \"%s\" ¤ò³«¤±¤Þ¤»¤ó"
+
+msgid "E456: Can't find PostScript resource file \"prolog.ps\""
+msgstr "E456: PostScript¤Î¥ê¥½¡¼¥¹¥Õ¥¡¥¤¥ë \"prolog.ps\" ¤¬¸«¤Ä¤«¤ê¤Þ¤»¤ó"
+
+msgid "E456: Can't find PostScript resource file \"cidfont.ps\""
+msgstr "E456: PostScript¤Î¥ê¥½¡¼¥¹¥Õ¥¡¥¤¥ë \"cidfont.ps\" ¤¬¸«¤Ä¤«¤ê¤Þ¤»¤ó"
+
+#, c-format
+msgid "E456: Can't find PostScript resource file \"%s.ps\""
+msgstr "E456: PostScript¤Î¥ê¥½¡¼¥¹¥Õ¥¡¥¤¥ë \"%s.ps\" ¤¬¸«¤Ä¤«¤ê¤Þ¤»¤ó"
+
+#, c-format
+msgid "E620: Unable to convert to print encoding \"%s\""
+msgstr "E620: °õºþ¥¨¥ó¥³¡¼¥É \"%s\" ¤ØÊÑ´¹¤Ç¤­¤Þ¤»¤ó"
+
+msgid "Sending to printer..."
+msgstr "¥×¥ê¥ó¥¿¤ËÁ÷¿®Ãæ..."
+
+msgid "E365: Failed to print PostScript file"
+msgstr "E365: PostScript¥Õ¥¡¥¤¥ë¤Î°õºþ¤Ë¼ºÇÔ¤·¤Þ¤·¤¿"
+
+msgid "Print job sent."
+msgstr "°õºþ¥¸¥ç¥Ö¤òÁ÷¿®¤·¤Þ¤·¤¿."
+
+msgid "Add a new database"
+msgstr "¿·¥Ç¡¼¥¿¥Ù¡¼¥¹¤òÄɲÃ"
+
+msgid "Query for a pattern"
+msgstr "¥Ñ¥¿¡¼¥ó¤Î¥¯¥¨¥ê¡¼¤òÄɲÃ"
+
+msgid "Show this message"
+msgstr "¤³¤Î¥á¥Ã¥»¡¼¥¸¤òɽ¼¨¤¹¤ë"
+
+msgid "Kill a connection"
+msgstr "Àܳ¤ò½ªÎ»¤¹¤ë"
+
+msgid "Reinit all connections"
+msgstr "Á´¤Æ¤ÎÀܳ¤òºÆ½é´ü²½¤¹¤ë"
+
+msgid "Show connections"
+msgstr "Àܳ¤òɽ¼¨¤¹¤ë"
+
+#, c-format
+msgid "E560: Usage: cs[cope] %s"
+msgstr "E560: »ÈÍÑÊýË¡: cs[cope] %s"
+
+msgid "This cscope command does not support splitting the window.\n"
+msgstr "¤³¤Îcscope¥³¥Þ¥ó¥É¤Ïʬ³ä¥¦¥£¥ó¥É¥¦¤Ç¤Ï¥µ¥Ý¡¼¥È¤µ¤ì¤Þ¤»¤ó.\n"
+
+msgid "E562: Usage: cstag <ident>"
+msgstr "E562: »ÈÍÑË¡: cstag <ident>"
+
+msgid "E257: cstag: tag not found"
+msgstr "E257: cstag: ¥¿¥°¤¬¸«¤Ä¤«¤ê¤Þ¤»¤ó"
+
+#, c-format
+msgid "E563: stat(%s) error: %d"
+msgstr "E563: stat(%s) ¥¨¥é¡¼: %d"
+
+msgid "E563: stat error"
+msgstr "E563: stat ¥¨¥é¡¼"
+
+#, c-format
+msgid "E564: %s is not a directory or a valid cscope database"
+msgstr "E564: %s ¤Ï¥Ç¥£¥ì¥¯¥È¥êµÚ¤ÓÍ­¸ú¤Êcscope¤Î¥Ç¡¼¥¿¥Ù¡¼¥¹¤Ç¤Ï¤¢¤ê¤Þ¤»¤ó"
+
+#, c-format
+msgid "Added cscope database %s"
+msgstr "cscope¥Ç¡¼¥¿¥Ù¡¼¥¹ %s ¤òÄɲÃ"
+
+#, c-format
+msgid "E262: error reading cscope connection %ld"
+msgstr "E262: cscope¤ÎÀܳ %ld ¤òÆɹþ¤ßÃæ¤Î¥¨¥é¡¼¤Ç¤¹"
+
+msgid "E561: unknown cscope search type"
+msgstr "E561: ̤ÃΤÎcscope¸¡º÷·¿¤Ç¤¹"
+
+msgid "E566: Could not create cscope pipes"
+msgstr "E566: cscope¥Ñ¥¤¥×¤òºîÀ®¤Ç¤­¤Þ¤»¤ó¤Ç¤·¤¿"
+
+msgid "E622: Could not fork for cscope"
+msgstr "E622: cscope¤Îµ¯Æ°½àÈ÷(fork)¤Ë¼ºÇÔ¤·¤Þ¤·¤¿"
+
+msgid "cs_create_connection setpgid failed"
+msgstr "cs_create_connection ¤Ø¤Î setpgid ¤Ë¼ºÇÔ¤·¤Þ¤·¤¿"
+
+msgid "cs_create_connection exec failed"
+msgstr "cs_create_connection ¤Î¼Â¹Ô¤Ë¼ºÇÔ¤·¤Þ¤·¤¿"
+
+msgid "cs_create_connection: fdopen for to_fp failed"
+msgstr "cs_create_connection: to_fp ¤Î fdopen ¤Ë¼ºÇÔ¤·¤Þ¤·¤¿"
+
+msgid "cs_create_connection: fdopen for fr_fp failed"
+msgstr "cs_create_connection: fr_fp ¤Î fdopen ¤Ë¼ºÇÔ¤·¤Þ¤·¤¿"
+
+msgid "E623: Could not spawn cscope process"
+msgstr "E623: cscope¥×¥í¥»¥¹¤òµ¯Æ°¤Ç¤­¤Þ¤»¤ó¤Ç¤·¤¿"
+
+msgid "E567: no cscope connections"
+msgstr "E567: cscopeÀܳ¤Ë¼ºÇÔ¤·¤Þ¤·¤¿"
+
+#, c-format
+msgid "E469: invalid cscopequickfix flag %c for %c"
+msgstr "E469: ̵¸ú¤Ê cscopequickfix ¥Õ¥é¥° %c ¤Î %c ¤Ç¤¹"
+
+#, c-format
+msgid "E259: no matches found for cscope query %s of %s"
+msgstr "E259: cscope¥¯¥¨¥ê¡¼ %s of %s ¤Ë³ºÅö¤¬¤¢¤ê¤Þ¤»¤ó¤Ç¤·¤¿"
+
+msgid "cscope commands:\n"
+msgstr "cscope¥³¥Þ¥ó¥É:\n"
+
+#, c-format
+msgid "%-5s: %s%*s (Usage: %s)"
+msgstr "%-5s: %s%*s (»ÈÍÑË¡: %s)"
+
+msgid ""
+"\n"
+" a: Find assignments to this symbol\n"
+" c: Find functions calling this function\n"
+" d: Find functions called by this function\n"
+" e: Find this egrep pattern\n"
+" f: Find this file\n"
+" g: Find this definition\n"
+" i: Find files #including this file\n"
+" s: Find this C symbol\n"
+" t: Find this text string\n"
+msgstr ""
+"\n"
+" a: ¤³¤Î¥·¥ó¥Ü¥ë¤ËÂФ¹¤ëÂåÆþ¤òõ¤¹\n"
+" c: ¤³¤Î´Ø¿ô¤ò¸Æ¤ó¤Ç¤¤¤ë´Ø¿ô¤òõ¤¹\n"
+" d: ¤³¤Î´Ø¿ô¤«¤é¸Æ¤ó¤Ç¤¤¤ë´Ø¿ô¤òõ¤¹\n"
+" e: ¤³¤Îegrep¥Ñ¥¿¡¼¥ó¤òõ¤¹\n"
+" f: ¤³¤Î¥Õ¥¡¥¤¥ë¤òõ¤¹\n"
+" g: ¤³¤ÎÄêµÁ¤òõ¤¹\n"
+" i: ¤³¤Î¥Õ¥¡¥¤¥ë¤ò#include¤·¤Æ¤¤¤ë¥Õ¥¡¥¤¥ë¤òõ¤¹\n"
+" s: ¤³¤ÎC¥·¥ó¥Ü¥ë¤òõ¤¹\n"
+" t: ¤³¤Î¥Æ¥­¥¹¥Èʸ»úÎó¤òõ¤¹\n"
+
+#, c-format
+msgid "E625: cannot open cscope database: %s"
+msgstr "E625: cscope¥Ç¡¼¥¿¥Ù¡¼¥¹: %s ¤ò³«¤¯¤³¤È¤¬¤Ç¤­¤Þ¤»¤ó"
+
+msgid "E626: cannot get cscope database information"
+msgstr "E626: cscope¥Ç¡¼¥¿¥Ù¡¼¥¹¤Î¾ðÊó¤ò¼èÆÀ¤Ç¤­¤Þ¤»¤ó"
+
+msgid "E568: duplicate cscope database not added"
+msgstr "E568: ½ÅÊ£¤¹¤ëcscope¥Ç¡¼¥¿¥Ù¡¼¥¹¤ÏÄɲ䵤ì¤Þ¤»¤ó¤Ç¤·¤¿"
+
+#, c-format
+msgid "E261: cscope connection %s not found"
+msgstr "E261: cscopeÀܳ %s ¤¬¸«¤Ä¤«¤ê¤Þ¤»¤ó¤Ç¤·¤¿"
+
+#, c-format
+msgid "cscope connection %s closed"
+msgstr "cscopeÀܳ %s ¤¬ÊĤ¸¤é¤ì¤Þ¤·¤¿"
+
+msgid "E570: fatal error in cs_manage_matches"
+msgstr "E570: cs_manage_matches ¤ÇÃ×̿Ū¤Ê¥¨¥é¡¼¤Ç¤¹"
+
+#, c-format
+msgid "Cscope tag: %s"
+msgstr "Cscope ¥¿¥°: %s"
+
+msgid ""
+"\n"
+" # line"
+msgstr ""
+"\n"
+" # ¹ÔÈÖ¹æ"
+
+msgid "filename / context / line\n"
+msgstr "¥Õ¥¡¥¤¥ë̾ / ʸ̮ / ¹Ô\n"
+
+#, c-format
+msgid "E609: Cscope error: %s"
+msgstr "E609: cscope¥¨¥é¡¼: %s"
+
+msgid "All cscope databases reset"
+msgstr "Á´¤Æ¤Îcscope¥Ç¡¼¥¿¥Ù¡¼¥¹¤ò¥ê¥»¥Ã¥È¤·¤Þ¤¹"
+
+msgid "no cscope connections\n"
+msgstr "cscopeÀܳ¤¬¤¢¤ê¤Þ¤»¤ó\n"
+
+msgid " # pid database name prepend path\n"
+msgstr " # pid ¥Ç¡¼¥¿¥Ù¡¼¥¹Ì¾ prepend ¥Ñ¥¹\n"
+
+msgid "Lua library cannot be loaded."
+msgstr "Lua¥é¥¤¥Ö¥é¥ê¤ò¥í¡¼¥É¤Ç¤­¤Þ¤»¤ó."
+
+msgid "cannot save undo information"
+msgstr "¥¢¥ó¥É¥¥¾ðÊó¤¬Êݸ¤Ç¤­¤Þ¤»¤ó"
+
+msgid ""
+"E815: Sorry, this command is disabled, the MzScheme libraries could not be "
+"loaded."
+msgstr "E815: ¤³¤Î¥³¥Þ¥ó¥É¤Ï̵¸ú¤Ç¤¹. MzScheme ¥é¥¤¥Ö¥é¥ê¤ò¥í¡¼¥É¤Ç¤­¤Þ¤»¤ó."
+
+msgid ""
+"E895: Sorry, this command is disabled, the MzScheme's racket/base module "
+"could not be loaded."
+msgstr ""
+"E895: ¤³¤Î¥³¥Þ¥ó¥É¤Ï̵¸ú¤Ç¤¹¡¢¤´¤á¤ó¤Ê¤µ¤¤. MzScheme ¤Î racket/base ¥â¥¸¥å¡¼"
+"¥ë¤¬¥í¡¼¥É¤Ç¤­¤Þ¤»¤ó¤Ç¤·¤¿."
+
+msgid "invalid expression"
+msgstr "̵¸ú¤Ê¼°¤Ç¤¹"
+
+msgid "expressions disabled at compile time"
+msgstr "¼°¤Ï¥³¥ó¥Ñ¥¤¥ë»þ¤Ë̵¸ú¤Ë¤µ¤ì¤Æ¤¤¤Þ¤¹"
+
+msgid "hidden option"
+msgstr "±£¤·¥ª¥×¥·¥ç¥ó"
+
+msgid "unknown option"
+msgstr "̤ÃΤΥª¥×¥·¥ç¥ó¤Ç¤¹"
+
+msgid "window index is out of range"
+msgstr "Èϰϳ°¤Î¥¦¥£¥ó¥É¥¦ÈÖ¹æ¤Ç¤¹"
+
+msgid "couldn't open buffer"
+msgstr "¥Ð¥Ã¥Õ¥¡¤ò³«¤±¤Þ¤»¤ó"
+
+msgid "cannot delete line"
+msgstr "¹Ô¤ò¾Ã¤»¤Þ¤»¤ó"
+
+msgid "cannot replace line"
+msgstr "¹Ô¤òÃÖ´¹¤Ç¤­¤Þ¤»¤ó"
+
+msgid "cannot insert line"
+msgstr "¹Ô¤òÁÞÆþ¤Ç¤­¤Þ¤»¤ó"
+
+msgid "string cannot contain newlines"
+msgstr "ʸ»úÎó¤Ë¤Ï²þ¹Ôʸ»ú¤ò´Þ¤á¤é¤ì¤Þ¤»¤ó"
+
+msgid "error converting Scheme values to Vim"
+msgstr "SchemeÃͤÎVim¤Ø¤ÎÊÑ´¹¥¨¥é¡¼"
+
+msgid "Vim error: ~a"
+msgstr "Vim ¥¨¥é¡¼: ~a"
+
+msgid "Vim error"
+msgstr "Vim ¥¨¥é¡¼"
+
+msgid "buffer is invalid"
+msgstr "¥Ð¥Ã¥Õ¥¡¤Ï̵¸ú¤Ç¤¹"
+
+msgid "window is invalid"
+msgstr "¥¦¥£¥ó¥É¥¦¤Ï̵¸ú¤Ç¤¹"
+
+msgid "linenr out of range"
+msgstr "Èϰϳ°¤Î¹ÔÈÖ¹æ¤Ç¤¹"
+
+msgid "not allowed in the Vim sandbox"
+msgstr "¥µ¥ó¥É¥Ü¥Ã¥¯¥¹¤Ç¤Ïµö¤µ¤ì¤Þ¤»¤ó"
+
+msgid "E836: This Vim cannot execute :python after using :py3"
+msgstr "E836: ¤³¤ÎVim¤Ç¤Ï :py3 ¤ò»È¤Ã¤¿¸å¤Ë :python ¤ò»È¤¨¤Þ¤»¤ó"
+
+msgid ""
+"E263: Sorry, this command is disabled, the Python library could not be "
+"loaded."
+msgstr ""
+"E263: ¤³¤Î¥³¥Þ¥ó¥É¤Ï̵¸ú¤Ç¤¹¡¢¤´¤á¤ó¤Ê¤µ¤¤: Python¥é¥¤¥Ö¥é¥ê¤ò¥í¡¼¥É¤Ç¤­¤Þ¤»"
+"¤ó¤Ç¤·¤¿."
+
+msgid ""
+"E887: Sorry, this command is disabled, the Python's site module could not be "
+"loaded."
+msgstr ""
+"E887: ¤³¤Î¥³¥Þ¥ó¥É¤Ï̵¸ú¤Ç¤¹¡¢¤´¤á¤ó¤Ê¤µ¤¤. Python ¤Î site ¥â¥¸¥å¡¼¥ë¤ò¥í¡¼¥É"
+"¤Ç¤­¤Þ¤»¤ó¤Ç¤·¤¿."
+
+# Added at 07-Feb-2004.
+msgid "E659: Cannot invoke Python recursively"
+msgstr "E659: Python ¤òºÆµ¢Åª¤Ë¼Â¹Ô¤¹¤ë¤³¤È¤Ï¤Ç¤­¤Þ¤»¤ó"
+
+msgid "E837: This Vim cannot execute :py3 after using :python"
+msgstr "E837: ¤³¤ÎVim¤Ç¤Ï :python ¤ò»È¤Ã¤¿¸å¤Ë :py3 ¤ò»È¤¨¤Þ¤»¤ó"
+
+msgid "E265: $_ must be an instance of String"
+msgstr "E265: $_ ¤Ïʸ»úÎó¤Î¥¤¥ó¥¹¥¿¥ó¥¹¤Ç¤Ê¤±¤ì¤Ð¤Ê¤ê¤Þ¤»¤ó"
+
+msgid ""
+"E266: Sorry, this command is disabled, the Ruby library could not be loaded."
+msgstr ""
+"E266: ¤³¤Î¥³¥Þ¥ó¥É¤Ï̵¸ú¤Ç¤¹¡¢¤´¤á¤ó¤Ê¤µ¤¤: Ruby¥é¥¤¥Ö¥é¥ê¤ò¥í¡¼¥É¤Ç¤­¤Þ¤»¤ó"
+"¤Ç¤·¤¿."
+
+msgid "E267: unexpected return"
+msgstr "E267: ͽ´ü¤»¤Ì return ¤Ç¤¹"
+
+msgid "E268: unexpected next"
+msgstr "E268: ͽ´ü¤»¤Ì next ¤Ç¤¹"
+
+msgid "E269: unexpected break"
+msgstr "E269: ͽ´ü¤»¤Ì break ¤Ç¤¹"
+
+msgid "E270: unexpected redo"
+msgstr "E270: ͽ´ü¤»¤Ì redo ¤Ç¤¹"
+
+msgid "E271: retry outside of rescue clause"
+msgstr "E271: rescue ¤Î³°¤Î retry ¤Ç¤¹"
+
+msgid "E272: unhandled exception"
+msgstr "E272: ¼è¤ê°·¤ï¤ì¤Ê¤«¤Ã¤¿Îã³°¤¬¤¢¤ê¤Þ¤¹"
+
+#, c-format
+msgid "E273: unknown longjmp status %d"
+msgstr "E273: ̤ÃΤÎlongjmp¾õÂÖ: %d"
+
+msgid "invalid buffer number"
+msgstr "̵¸ú¤Ê¥Ð¥Ã¥Õ¥¡ÈÖ¹æ¤Ç¤¹"
+
+msgid "not implemented yet"
+msgstr "¤Þ¤À¼ÂÁõ¤µ¤ì¤Æ¤¤¤Þ¤»¤ó"
+
+msgid "cannot set line(s)"
+msgstr "¹Ô¤òÀßÄê¤Ç¤­¤Þ¤»¤ó"
+
+msgid "invalid mark name"
+msgstr "̵¸ú¤Ê¥Þ¡¼¥¯Ì¾¤Ç¤¹"
+
+msgid "mark not set"
+msgstr "¥Þ¡¼¥¯¤ÏÀßÄꤵ¤ì¤Æ¤¤¤Þ¤»¤ó"
+
+#, c-format
+msgid "row %d column %d"
+msgstr "¹Ô %d Îó %d"
+
+msgid "cannot insert/append line"
+msgstr "¹Ô¤ÎÁÞÆþ/Äɲäò¤Ç¤­¤Þ¤»¤ó"
+
+msgid "line number out of range"
+msgstr "Èϰϳ°¤Î¹ÔÈÖ¹æ¤Ç¤¹"
+
+msgid "unknown flag: "
+msgstr "̤ÃΤΥե饰: "
+
+msgid "unknown vimOption"
+msgstr "̤ÃΤΠvimOption ¤Ç¤¹"
+
+msgid "keyboard interrupt"
+msgstr "¥­¡¼¥Ü¡¼¥É³ä¹þ¤ß"
+
+msgid "vim error"
+msgstr "vim ¥¨¥é¡¼"
+
+msgid "cannot create buffer/window command: object is being deleted"
+msgstr ""
+"¥Ð¥Ã¥Õ¥¡/¥¦¥£¥ó¥É¥¦ºîÀ®¥³¥Þ¥ó¥É¤òºîÀ®¤Ç¤­¤Þ¤»¤ó: ¥ª¥Ö¥¸¥§¥¯¥È¤¬¾Ãµî¤µ¤ì¤Æ¤¤¤Þ"
+"¤·¤¿"
+
+msgid ""
+"cannot register callback command: buffer/window is already being deleted"
+msgstr ""
+"¥³¡¼¥ë¥Ð¥Ã¥¯¥³¥Þ¥ó¥É¤òÅÐÏ¿¤Ç¤­¤Þ¤»¤ó: ¥Ð¥Ã¥Õ¥¡/¥¦¥£¥ó¥É¥¦¤¬´û¤Ë¾Ãµî¤µ¤ì¤Þ¤·¤¿"
+
+msgid ""
+"E280: TCL FATAL ERROR: reflist corrupt!? Please report this to vim-dev@vim."
+"org"
+msgstr ""
+"E280: TCL Ã×̿Ū¥¨¥é¡¼: reflist ±øÀ÷!? vim-dev@vim.org ¤ËÊó¹ð¤·¤Æ¤¯¤À¤µ¤¤"
+
+msgid "cannot register callback command: buffer/window reference not found"
+msgstr ""
+"¥³¡¼¥ë¥Ð¥Ã¥¯¥³¥Þ¥ó¥É¤òÅÐÏ¿¤Ç¤­¤Þ¤»¤ó: ¥Ð¥Ã¥Õ¥¡/¥¦¥£¥ó¥É¥¦¤Î»²¾È¤¬¸«¤Ä¤«¤ê¤Þ¤»"
+"¤ó"
+
+msgid ""
+"E571: Sorry, this command is disabled: the Tcl library could not be loaded."
+msgstr ""
+"E571: ¤³¤Î¥³¥Þ¥ó¥É¤Ï̵¸ú¤Ç¤¹¡¢¤´¤á¤ó¤Ê¤µ¤¤: Tcl¥é¥¤¥Ö¥é¥ê¤ò¥í¡¼¥É¤Ç¤­¤Þ¤»¤ó¤Ç"
+"¤·¤¿."
+
+#, c-format
+msgid "E572: exit code %d"
+msgstr "E572: ½ªÎ»¥³¡¼¥É %d"
+
+msgid "cannot get line"
+msgstr "¹Ô¤ò¼èÆÀ¤Ç¤­¤Þ¤»¤ó"
+
+msgid "Unable to register a command server name"
+msgstr "Ì¿Î᥵¡¼¥Ð¡¼¤Î̾Á°¤òÅÐÏ¿¤Ç¤­¤Þ¤»¤ó"
+
+msgid "E248: Failed to send command to the destination program"
+msgstr "E248: ÌÜŪ¤Î¥×¥í¥°¥é¥à¤Ø¤Î¥³¥Þ¥ó¥ÉÁ÷¿®¤Ë¼ºÇÔ¤·¤Þ¤·¤¿"
+
+#, c-format
+msgid "E573: Invalid server id used: %s"
+msgstr "E573: ̵¸ú¤Ê¥µ¡¼¥Ð¡¼ID¤¬»È¤ï¤ì¤Þ¤·¤¿: %s"
+
+msgid "E251: VIM instance registry property is badly formed. Deleted!"
+msgstr "E251: VIM ¼ÂÂΤÎÅÐÏ¿¥×¥í¥Ñ¥Æ¥£¤¬ÉÔÀµ¤Ç¤¹. ¾Ãµî¤·¤Þ¤·¤¿!"
+
+#, c-format
+msgid "E938: Duplicate key in JSON: \"%s\""
+msgstr "E938: JSON¤Ë½ÅÊ£¥­¡¼¤¬¤¢¤ê¤Þ¤¹: \"%s\""
+
+#, c-format
+msgid "E696: Missing comma in List: %s"
+msgstr "E696: ¥ê¥¹¥È·¿¤Ë¥«¥ó¥Þ¤¬¤¢¤ê¤Þ¤»¤ó: %s"
+
+#, c-format
+msgid "E697: Missing end of List ']': %s"
+msgstr "E697: ¥ê¥¹¥È·¿¤ÎºÇ¸å¤Ë ']' ¤¬¤¢¤ê¤Þ¤»¤ó: %s"
+
+msgid "Unknown option argument"
+msgstr "̤ÃΤΥª¥×¥·¥ç¥ó°ú¿ô¤Ç¤¹"
+
+msgid "Too many edit arguments"
+msgstr "ÊÔ½¸°ú¿ô¤¬Â¿²á¤®¤Þ¤¹"
+
+msgid "Argument missing after"
+msgstr "°ú¿ô¤¬¤¢¤ê¤Þ¤»¤ó"
+
+msgid "Garbage after option argument"
+msgstr "¥ª¥×¥·¥ç¥ó°ú¿ô¤Î¸å¤Ë¥´¥ß¤¬¤¢¤ê¤Þ¤¹"
+
+msgid "Too many \"+command\", \"-c command\" or \"--cmd command\" arguments"
+msgstr "\"+command\", \"-c command\", \"--cmd command\" ¤Î°ú¿ô¤¬Â¿²á¤®¤Þ¤¹"
+
+msgid "Invalid argument for"
+msgstr "̵¸ú¤Ê°ú¿ô¤Ç¤¹: "
+
+#, c-format
+msgid "%d files to edit\n"
+msgstr "%d ¸Ä¤Î¥Õ¥¡¥¤¥ë¤¬ÊÔ½¸¤ò¹µ¤¨¤Æ¤¤¤Þ¤¹\n"
+
+msgid "netbeans is not supported with this GUI\n"
+msgstr "netbeans ¤Ï¤³¤ÎGUI¤Ç¤ÏÍøÍѤǤ­¤Þ¤»¤ó\n"
+
+msgid "'-nb' cannot be used: not enabled at compile time\n"
+msgstr "'-nb' »ÈÍÑÉÔ²Äǽ¤Ç¤¹: ¥³¥ó¥Ñ¥¤¥ë»þ¤Ë̵¸ú¤Ë¤µ¤ì¤Æ¤¤¤Þ¤¹\n"
+
+msgid "This Vim was not compiled with the diff feature."
+msgstr "¤³¤ÎVim¤Ë¤Ïdiffµ¡Ç½¤¬¤¢¤ê¤Þ¤»¤ó(¥³¥ó¥Ñ¥¤¥ë»þÀßÄê)."
+
+msgid "Attempt to open script file again: \""
+msgstr "¥¹¥¯¥ê¥×¥È¥Õ¥¡¥¤¥ë¤òºÆ¤Ó³«¤³¤¦¤È¤·¤Þ¤·¤¿: \""
+
+msgid "Cannot open for reading: \""
+msgstr "ÆɹþÍѤȤ·¤Æ³«¤±¤Þ¤»¤ó"
+
+msgid "Cannot open for script output: \""
+msgstr "¥¹¥¯¥ê¥×¥È½ÐÎÏÍѤò³«¤±¤Þ¤»¤ó"
+
+msgid "Vim: Error: Failure to start gvim from NetBeans\n"
+msgstr "Vim: ¥¨¥é¡¼: NetBeans¤«¤égvim¤ò¥¹¥¿¡¼¥È¤Ç¤­¤Þ¤»¤ó\n"
+
+msgid "Vim: Error: This version of Vim does not run in a Cygwin terminal\n"
+msgstr "Vim: ¥¨¥é¡¼: ¤³¤Î¥Ð¡¼¥¸¥ç¥ó¤ÎVim¤ÏCygwinüËö¤Ç¤ÏÆ°ºî¤·¤Þ¤»¤ó\n"
+
+msgid "Vim: Warning: Output is not to a terminal\n"
+msgstr "Vim: ·Ù¹ð: üËö¤Ø¤Î½ÐÎϤǤϤ¢¤ê¤Þ¤»¤ó\n"
+
+msgid "Vim: Warning: Input is not from a terminal\n"
+msgstr "Vim: ·Ù¹ð: üËö¤«¤é¤ÎÆþÎϤǤϤ¢¤ê¤Þ¤»¤ó\n"
+
+msgid "pre-vimrc command line"
+msgstr "vimrcÁ°¤Î¥³¥Þ¥ó¥É¥é¥¤¥ó"
+
+#, c-format
+msgid "E282: Cannot read from \"%s\""
+msgstr "E282: \"%s\"¤«¤éÆɹþ¤à¤³¤È¤¬¤Ç¤­¤Þ¤»¤ó"
+
+msgid ""
+"\n"
+"More info with: \"vim -h\"\n"
+msgstr ""
+"\n"
+"¤è¤ê¾ÜºÙ¤Ê¾ðÊó¤Ï: \"vim -h\"\n"
+
+msgid "[file ..] edit specified file(s)"
+msgstr "[¥Õ¥¡¥¤¥ë..] ¤¢¤ë¥Õ¥¡¥¤¥ë¤òÊÔ½¸¤¹¤ë"
+
+msgid "- read text from stdin"
+msgstr "- ɸ½àÆþÎϤ«¤é¥Æ¥­¥¹¥È¤òÆɹþ¤à"
+
+msgid "-t tag edit file where tag is defined"
+msgstr "-t ¥¿¥° ¥¿¥°¤¬ÄêµÁ¤µ¤ì¤¿¤È¤³¤í¤«¤éÊÔ½¸¤¹¤ë"
+
+msgid "-q [errorfile] edit file with first error"
+msgstr "-q [errorfile] ºÇ½é¤Î¥¨¥é¡¼¤ÇÊÔ½¸¤¹¤ë"
+
+msgid ""
+"\n"
+"\n"
+"Usage:"
+msgstr ""
+"\n"
+"\n"
+"»ÈÍÑË¡:"
+
+msgid " vim [arguments] "
+msgstr " vim [°ú¿ô] "
+
+msgid ""
+"\n"
+" or:"
+msgstr ""
+"\n"
+" ¤â¤·¤¯¤Ï:"
+
+msgid ""
+"\n"
+"Where case is ignored prepend / to make flag upper case"
+msgstr ""
+"\n"
+"Â羮ʸ»ú¤¬Ìµ»ë¤µ¤ì¤ë¾ì¹ç¤ÏÂçʸ»ú¤Ë¤¹¤ë¤¿¤á¤Ë / ¤òÁ°ÃÖ¤·¤Æ¤¯¤À¤µ¤¤"
+
+msgid ""
+"\n"
+"\n"
+"Arguments:\n"
+msgstr ""
+"\n"
+"\n"
+"°ú¿ô:\n"
+
+msgid "--\t\t\tOnly file names after this"
+msgstr "--\t\t\t¤³¤Î¤¢¤È¤Ë¤Ï¥Õ¥¡¥¤¥ë̾¤À¤±"
+
+msgid "--literal\t\tDon't expand wildcards"
+msgstr "--literal\t\t¥ï¥¤¥ë¥É¥«¡¼¥É¤òŸ³«¤·¤Ê¤¤"
+
+msgid "-register\t\tRegister this gvim for OLE"
+msgstr "-register\t\t¤³¤Îgvim¤òOLE¤È¤·¤ÆÅÐÏ¿¤¹¤ë"
+
+msgid "-unregister\t\tUnregister gvim for OLE"
+msgstr "-unregister\t\tgvim¤ÎOLEÅÐÏ¿¤ò²ò½ü¤¹¤ë"
+
+msgid "-g\t\t\tRun using GUI (like \"gvim\")"
+msgstr "-g\t\t\tGUI¤Çµ¯Æ°¤¹¤ë (\"gvim\" ¤ÈƱ¤¸)"
+
+msgid "-f or --nofork\tForeground: Don't fork when starting GUI"
+msgstr "-f or --nofork\t¥Õ¥©¥¢¥°¥é¥¦¥ó¥É: GUI¤ò»Ï¤á¤ë¤È¤­¤Ëfork¤·¤Ê¤¤"
+
+msgid "-v\t\t\tVi mode (like \"vi\")"
+msgstr "-v\t\t\tVi¥â¡¼¥É (\"vi\" ¤ÈƱ¤¸)"
+
+msgid "-e\t\t\tEx mode (like \"ex\")"
+msgstr "-e\t\t\tEx¥â¡¼¥É (\"ex\" ¤ÈƱ¤¸)"
+
+msgid "-E\t\t\tImproved Ex mode"
+msgstr "-E\t\t\t²þÎÉEx¥â¡¼¥É"
+
+msgid "-s\t\t\tSilent (batch) mode (only for \"ex\")"
+msgstr "-s\t\t\t¥µ¥¤¥ì¥ó¥È(¥Ð¥Ã¥Á)¥â¡¼¥É (\"ex\" ÀìÍÑ)"
+
+msgid "-d\t\t\tDiff mode (like \"vimdiff\")"
+msgstr "-d\t\t\tº¹Ê¬¥â¡¼¥É (\"vidiff\" ¤ÈƱ¤¸)"
+
+msgid "-y\t\t\tEasy mode (like \"evim\", modeless)"
+msgstr "-y\t\t\t¥¤¡¼¥¸¡¼¥â¡¼¥É (\"evim\" ¤ÈƱ¤¸¡¢¥â¡¼¥É̵)"
+
+msgid "-R\t\t\tReadonly mode (like \"view\")"
+msgstr "-R\t\t\tÆɹþÀìÍѥ⡼¥É (\"view\" ¤ÈƱ¤¸)"
+
+msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
+msgstr "-Z\t\t\tÀ©¸Â¥â¡¼¥É (\"rvim\" ¤ÈƱ¤¸)"
+
+msgid "-m\t\t\tModifications (writing files) not allowed"
+msgstr "-m\t\t\tÊѹ¹ (¥Õ¥¡¥¤¥ëÊݸ»þ) ¤ò¤Ç¤­¤Ê¤¤¤è¤¦¤Ë¤¹¤ë"
+
+msgid "-M\t\t\tModifications in text not allowed"
+msgstr "-M\t\t\t¥Æ¥­¥¹¥È¤ÎÊÔ½¸¤ò¹Ô¤Ê¤¨¤Ê¤¤¤è¤¦¤Ë¤¹¤ë"
+
+msgid "-b\t\t\tBinary mode"
+msgstr "-b\t\t\t¥Ð¥¤¥Ê¥ê¥â¡¼¥É"
+
+msgid "-l\t\t\tLisp mode"
+msgstr "-l\t\t\tLisp¥â¡¼¥É"
+
+msgid "-C\t\t\tCompatible with Vi: 'compatible'"
+msgstr "-C\t\t\tVi¸ß´¹¥â¡¼¥É: 'compatible'"
+
+msgid "-N\t\t\tNot fully Vi compatible: 'nocompatible'"
+msgstr "-N\t\t\tViÈó¸ß´¹¥â¡¼¥É: 'nocompatible"
+
+msgid "-V[N][fname]\t\tBe verbose [level N] [log messages to fname]"
+msgstr "-V[N][fname]\t\t¥í¥°½ÐÎÏÀßÄê [¥ì¥Ù¥ë N] [¥í¥°¥Õ¥¡¥¤¥ë̾ fname]"
+
+msgid "-D\t\t\tDebugging mode"
+msgstr "-D\t\t\t¥Ç¥Ð¥Ã¥°¥â¡¼¥É"
+
+msgid "-n\t\t\tNo swap file, use memory only"
+msgstr "-n\t\t\t¥¹¥ï¥Ã¥×¥Õ¥¡¥¤¥ë¤ò»ÈÍѤ»¤º¥á¥â¥ê¤À¤±"
+
+msgid "-r\t\t\tList swap files and exit"
+msgstr "-r\t\t\t¥¹¥ï¥Ã¥×¥Õ¥¡¥¤¥ë¤òÎóµó¤·½ªÎ»"
+
+msgid "-r (with file name)\tRecover crashed session"
+msgstr "-r (¥Õ¥¡¥¤¥ë̾)\t¥¯¥é¥Ã¥·¥å¤·¤¿¥»¥Ã¥·¥ç¥ó¤òÉüµ¢"
+
+msgid "-L\t\t\tSame as -r"
+msgstr "-L\t\t\t-r¤ÈƱ¤¸"
+
+msgid "-f\t\t\tDon't use newcli to open window"
+msgstr "-f\t\t\t¥¦¥£¥ó¥É¥¦¤ò³«¤¯¤Î¤Ë newcli ¤ò»ÈÍѤ·¤Ê¤¤"
+
+msgid "-dev <device>\t\tUse <device> for I/O"
+msgstr "-dev <device>\t\tI/O¤Ë <device> ¤ò»ÈÍѤ¹¤ë"
+
+msgid "-A\t\t\tStart in Arabic mode"
+msgstr "-A\t\t\t¥¢¥é¥Ó¥¢¸ì¥â¡¼¥É¤Çµ¯Æ°¤¹¤ë"
+
+msgid "-H\t\t\tStart in Hebrew mode"
+msgstr "-H\t\t\t¥Ø¥Ö¥é¥¤¸ì¥â¡¼¥É¤Çµ¯Æ°¤¹¤ë"
+
+msgid "-F\t\t\tStart in Farsi mode"
+msgstr "-F\t\t\t¥Ú¥ë¥·¥¢¸ì¥â¡¼¥É¤Çµ¯Æ°¤¹¤ë"
+
+msgid "-T <terminal>\tSet terminal type to <terminal>"
+msgstr "-T <terminal>\tüËö¤ò <terminal> ¤ËÀßÄꤹ¤ë"
+
+msgid "--not-a-term\t\tSkip warning for input/output not being a terminal"
+msgstr "--not-a-term\t\tÆþ½ÐÎϤ¬Ã¼Ëö¤Ç¤Ê¤¤¤È¤Î·Ù¹ð¤ò¥¹¥­¥Ã¥×¤¹¤ë"
+
+msgid "--ttyfail\t\tExit if input or output is not a terminal"
+msgstr "--ttyfail\t\tÆþ½ÐÎϤ¬Ã¼Ëö¤Ç¤Ê¤±¤ì¤Ð½ªÎ»¤¹¤ë"
+
+msgid "-u <vimrc>\t\tUse <vimrc> instead of any .vimrc"
+msgstr "-u <vimrc>\t\t.vimrc¤ÎÂå¤ï¤ê¤Ë <vimrc> ¤ò»È¤¦"
+
+msgid "-U <gvimrc>\t\tUse <gvimrc> instead of any .gvimrc"
+msgstr "-U <gvimrc>\t\t.gvimrc¤ÎÂå¤ï¤ê¤Ë <gvimrc> ¤ò»È¤¦"
+
+msgid "--noplugin\t\tDon't load plugin scripts"
+msgstr "--noplugin\t\t¥×¥é¥°¥¤¥ó¥¹¥¯¥ê¥×¥È¤ò¥í¡¼¥É¤·¤Ê¤¤"
+
+msgid "-p[N]\t\tOpen N tab pages (default: one for each file)"
+msgstr "-p[N]\t\tN ¸Ä¥¿¥Ö¥Ú¡¼¥¸¤ò³«¤¯(¾ÊάÃÍ: ¥Õ¥¡¥¤¥ë¤Ë¤Ä¤­1¸Ä)"
+
+msgid "-o[N]\t\tOpen N windows (default: one for each file)"
+msgstr "-o[N]\t\tN ¸Ä¥¦¥£¥ó¥É¥¦¤ò³«¤¯(¾ÊάÃÍ: ¥Õ¥¡¥¤¥ë¤Ë¤Ä¤­1¸Ä)"
+
+msgid "-O[N]\t\tLike -o but split vertically"
+msgstr "-O[N]\t\t-o¤ÈƱ¤¸¤À¤¬¿âľʬ³ä"
+
+msgid "+\t\t\tStart at end of file"
+msgstr "+\t\t\t¥Õ¥¡¥¤¥ë¤ÎºÇ¸å¤«¤é¤Ï¤¸¤á¤ë"
+
+msgid "+<lnum>\t\tStart at line <lnum>"
+msgstr "+<lnum>\t\t<lnum> ¹Ô¤«¤é¤Ï¤¸¤á¤ë"
+
+msgid "--cmd <command>\tExecute <command> before loading any vimrc file"
+msgstr "--cmd <command>\tvimrc¤ò¥í¡¼¥É¤¹¤ëÁ°¤Ë <command> ¤ò¼Â¹Ô¤¹¤ë"
+
+msgid "-c <command>\t\tExecute <command> after loading the first file"
+msgstr "-c <command>\t\tºÇ½é¤Î¥Õ¥¡¥¤¥ë¤ò¥í¡¼¥É¸å <command> ¤ò¼Â¹Ô¤¹¤ë"
+
+msgid "-S <session>\t\tSource file <session> after loading the first file"
+msgstr "-S <session>\t\tºÇ½é¤Î¥Õ¥¡¥¤¥ë¤ò¥í¡¼¥É¸å¥Õ¥¡¥¤¥ë <session> ¤ò¼è¹þ¤à"
+
+msgid "-s <scriptin>\tRead Normal mode commands from file <scriptin>"
+msgstr "-s <scriptin>\t¥Õ¥¡¥¤¥ë <scriptin> ¤«¤é¥Î¡¼¥Þ¥ë¥³¥Þ¥ó¥É¤òÆɹþ¤à"
+
+msgid "-w <scriptout>\tAppend all typed commands to file <scriptout>"
+msgstr "-w <scriptout>\tÆþÎϤ·¤¿Á´¥³¥Þ¥ó¥É¤ò¥Õ¥¡¥¤¥ë <scriptout> ¤ËÄɲ乤ë"
+
+msgid "-W <scriptout>\tWrite all typed commands to file <scriptout>"
+msgstr "-W <scriptout>\tÆþÎϤ·¤¿Á´¥³¥Þ¥ó¥É¤ò¥Õ¥¡¥¤¥ë <scriptout> ¤ËÊݸ¤¹¤ë"
+
+msgid "-x\t\t\tEdit encrypted files"
+msgstr "-x\t\t\t°Å¹æ²½¤µ¤ì¤¿¥Õ¥¡¥¤¥ë¤òÊÔ½¸¤¹¤ë"
+
+msgid "-display <display>\tConnect vim to this particular X-server"
+msgstr "-display <display>\tvim¤ò»ØÄꤷ¤¿ X ¥µ¡¼¥Ð¡¼¤ËÀܳ¤¹¤ë"
+
+msgid "-X\t\t\tDo not connect to X server"
+msgstr "-X\t\t\tX¥µ¡¼¥Ð¡¼¤ËÀܳ¤·¤Ê¤¤"
+
+msgid "--remote <files>\tEdit <files> in a Vim server if possible"
+msgstr "--remote <files>\t²Äǽ¤Ê¤é¤ÐVim¥µ¡¼¥Ð¡¼¤Ç <files> ¤òÊÔ½¸¤¹¤ë"
+
+msgid "--remote-silent <files> Same, don't complain if there is no server"
+msgstr "--remote-silent <files> Ʊ¾å¡¢¥µ¡¼¥Ð¡¼¤¬Ìµ¤¯¤Æ¤â·Ù¹ðʸ¤ò½ÐÎϤ·¤Ê¤¤"
+
+msgid ""
+"--remote-wait <files> As --remote but wait for files to have been edited"
+msgstr "--remote-wait <files> --remote¸å ¥Õ¥¡¥¤¥ë¤ÎÊÔ½¸¤¬½ª¤ï¤ë¤Î¤òÂÔ¤Ä"
+
+msgid ""
+"--remote-wait-silent <files> Same, don't complain if there is no server"
+msgstr ""
+"--remote-wait-silent <files> Ʊ¾å¡¢¥µ¡¼¥Ð¡¼¤¬Ìµ¤¯¤Æ¤â·Ù¹ðʸ¤ò½ÐÎϤ·¤Ê¤¤"
+
+msgid ""
+"--remote-tab[-wait][-silent] <files> As --remote but use tab page per file"
+msgstr ""
+"--remote-tab[-wait][-silent] <files> --remote¤Ç¥Õ¥¡¥¤¥ë1¤Ä¤Ë¤Ä¤­1¤Ä¤Î¥¿¥Ö"
+"¥Ú¡¼¥¸¤ò³«¤¯"
+
+msgid "--remote-send <keys>\tSend <keys> to a Vim server and exit"
+msgstr "--remote-send <keys>\tVim¥µ¡¼¥Ð¡¼¤Ë <keys> ¤òÁ÷¿®¤·¤Æ½ªÎ»¤¹¤ë"
+
+msgid "--remote-expr <expr>\tEvaluate <expr> in a Vim server and print result"
+msgstr "--remote-expr <expr>\t¥µ¡¼¥Ð¡¼¤Ç <expr> ¤ò¼Â¹Ô¤·¤Æ·ë²Ì¤òɽ¼¨¤¹¤ë"
+
+msgid "--serverlist\t\tList available Vim server names and exit"
+msgstr "--serverlist\t\tVim¥µ¡¼¥Ð¡¼Ì¾¤Î°ìÍ÷¤òɽ¼¨¤·¤Æ½ªÎ»¤¹¤ë"
+
+msgid "--servername <name>\tSend to/become the Vim server <name>"
+msgstr "--servername <name>\tVim¥µ¡¼¥Ð¡¼ <name> ¤ËÁ÷¿®/̾Á°ÀßÄꤹ¤ë"
+
+msgid "--startuptime <file>\tWrite startup timing messages to <file>"
+msgstr "--startuptime <file>\tµ¯Æ°¤Ë¤«¤«¤Ã¤¿»þ´Ö¤Î¾ÜºÙ¤ò <file> ¤Ø½ÐÎϤ¹¤ë"
+
+msgid "-i <viminfo>\t\tUse <viminfo> instead of .viminfo"
+msgstr "-i <viminfo>\t\t.viminfo¤ÎÂå¤ï¤ê¤Ë <viminfo> ¤ò»È¤¦"
+
+msgid "--clean\t\t'nocompatible', Vim defaults, no plugins, no viminfo"
+msgstr "--clean\t\t'nocompatible'¡¢Vim¤Î´ûÄê¡¢¥×¥é¥°¥¤¥ó¤Ê¤·¡¢viminfo¤Ê¤·"
+
+msgid "-h or --help\tPrint Help (this message) and exit"
+msgstr "-h or --help\t¥Ø¥ë¥×(¤³¤Î¥á¥Ã¥»¡¼¥¸)¤òɽ¼¨¤·½ªÎ»¤¹¤ë"
+
+msgid "--version\t\tPrint version information and exit"
+msgstr "--version\t\t¥Ð¡¼¥¸¥ç¥ó¾ðÊó¤òɽ¼¨¤·½ªÎ»¤¹¤ë"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Motif version):\n"
+msgstr ""
+"\n"
+"gvim¤Ë¤è¤Ã¤Æ²ò¼á¤µ¤ì¤ë°ú¿ô(Motif¥Ð¡¼¥¸¥ç¥ó):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (neXtaw version):\n"
+msgstr ""
+"\n"
+"gvim¤Ë¤è¤Ã¤Æ²ò¼á¤µ¤ì¤ë°ú¿ô(neXtaw¥Ð¡¼¥¸¥ç¥ó):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Athena version):\n"
+msgstr ""
+"\n"
+"gvim¤Ë¤è¤Ã¤Æ²ò¼á¤µ¤ì¤ë°ú¿ô(Athena¥Ð¡¼¥¸¥ç¥ó):\n"
+
+msgid "-display <display>\tRun vim on <display>"
+msgstr "-display <display>\t<display> ¤Çvim¤ò¼Â¹Ô¤¹¤ë"
+
+msgid "-iconic\t\tStart vim iconified"
+msgstr "-iconic\t\tºÇ¾®²½¤·¤¿¾õÂÖ¤Çvim¤òµ¯Æ°¤¹¤ë"
+
+msgid "-background <color>\tUse <color> for the background (also: -bg)"
+msgstr "-background <color>\tÇØ·Ê¿§¤Ë <color> ¤ò»È¤¦(ƱµÁ: -bg)"
+
+msgid "-foreground <color>\tUse <color> for normal text (also: -fg)"
+msgstr "-foreground <color>\tÁ°·Ê¿§¤Ë <color> ¤ò»È¤¦(ƱµÁ: -fg)"
+
+msgid "-font <font>\t\tUse <font> for normal text (also: -fn)"
+msgstr "-font <font>\t\t¥Æ¥­¥¹¥Èɽ¼¨¤Ë <font> ¤ò»È¤¦(ƱµÁ: -fn)"
+
+msgid "-boldfont <font>\tUse <font> for bold text"
+msgstr "-boldfont <font>\tÂÀ»ú¤Ë <font> ¤ò»È¤¦"
+
+msgid "-italicfont <font>\tUse <font> for italic text"
+msgstr "-italicfont <for>\t¼ÐÂλú¤Ë <font> ¤ò»È¤¦"
+
+msgid "-geometry <geom>\tUse <geom> for initial geometry (also: -geom)"
+msgstr "-geometry <geom>\t½é´üÇÛÃÖ¤Ë <geom> ¤ò»È¤¦(ƱµÁ: -geom)"
+
+msgid "-borderwidth <width>\tUse a border width of <width> (also: -bw)"
+msgstr "-borderwidth <width>\t¶­³¦¤ÎÉý¤ò <width> ¤Ë¤¹¤ë(ƱµÁ: -bw)"
+
+msgid "-scrollbarwidth <width> Use a scrollbar width of <width> (also: -sw)"
+msgstr ""
+"-scrollbarwidth <width> ¥¹¥¯¥í¡¼¥ë¥Ð¡¼¤ÎÉý¤ò <width> ¤Ë¤¹¤ë(ƱµÁ: -sw)"
+
+msgid "-menuheight <height>\tUse a menu bar height of <height> (also: -mh)"
+msgstr "-menuheight <height>\t¥á¥Ë¥å¡¼¥Ð¡¼¤Î¹â¤µ¤ò <height> ¤Ë¤¹¤ë(ƱµÁ: -mh)"
+
+msgid "-reverse\t\tUse reverse video (also: -rv)"
+msgstr "-reverse\t\tȿž±ÇÁü¤ò»ÈÍѤ¹¤ë(ƱµÁ: -rv)"
+
+msgid "+reverse\t\tDon't use reverse video (also: +rv)"
+msgstr "+reverse\t\tȿž±ÇÁü¤ò»ÈÍѤ·¤Ê¤¤(ƱµÁ: +rv)"
+
+msgid "-xrm <resource>\tSet the specified resource"
+msgstr "-xrm <resource>\tÆÃÄê¤Î¥ê¥½¡¼¥¹¤ò»ÈÍѤ¹¤ë"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (GTK+ version):\n"
+msgstr ""
+"\n"
+"gvim¤Ë¤è¤Ã¤Æ²ò¼á¤µ¤ì¤ë°ú¿ô(GTK+¥Ð¡¼¥¸¥ç¥ó):\n"
+
+msgid "-display <display>\tRun vim on <display> (also: --display)"
+msgstr "-display <display>\t<display> ¤Çvim¤ò¼Â¹Ô¤¹¤ë(ƱµÁ: --display)"
+
+msgid "--role <role>\tSet a unique role to identify the main window"
+msgstr "--role <role>\t¥á¥¤¥ó¥¦¥£¥ó¥É¥¦¤ò¼±Ê̤¹¤ë°ì°Õ¤ÊÌò³ä(role)¤òÀßÄꤹ¤ë"
+
+msgid "--socketid <xid>\tOpen Vim inside another GTK widget"
+msgstr "--socketid <xid>\t°Û¤Ê¤ëGTK widget¤ÎÆâÉô¤ËVim¤ò³«¤¯"
+
+msgid "--echo-wid\t\tMake gvim echo the Window ID on stdout"
+msgstr "--echo-wid\t\t¥¦¥£¥ó¥É¥¦ID¤òɸ½à½ÐÎϤ˽ÐÎϤ¹¤ë"
+
+msgid "-P <parent title>\tOpen Vim inside parent application"
+msgstr "-P <¿Æ¤Î¥¿¥¤¥È¥ë>\tVim¤ò¿Æ¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¤ÎÃæ¤Çµ¯Æ°¤¹¤ë"
+
+msgid "--windowid <HWND>\tOpen Vim inside another win32 widget"
+msgstr "--windowid <HWND>\t°Û¤Ê¤ëWin32 widget¤ÎÆâÉô¤ËVim¤ò³«¤¯"
+
+msgid "No display"
+msgstr "¥Ç¥£¥¹¥×¥ì¥¤¤¬¸«¤Ä¤«¤ê¤Þ¤»¤ó"
+
+msgid ": Send failed.\n"
+msgstr ": Á÷¿®¤Ë¼ºÇÔ¤·¤Þ¤·¤¿.\n"
+
+msgid ": Send failed. Trying to execute locally\n"
+msgstr ": Á÷¿®¤Ë¼ºÇÔ¤·¤Þ¤·¤¿. ¥í¡¼¥«¥ë¤Ç¤Î¼Â¹Ô¤ò»î¤ß¤Æ¤¤¤Þ¤¹\n"
+
+#, c-format
+msgid "%d of %d edited"
+msgstr "%d ¸Ä (%d ¸ÄÃæ) ¤Î¥Õ¥¡¥¤¥ë¤òÊÔ½¸¤·¤Þ¤·¤¿"
+
+msgid "No display: Send expression failed.\n"
+msgstr "¥Ç¥£¥¹¥×¥ì¥¤¤¬¤¢¤ê¤Þ¤»¤ó: ¼°¤ÎÁ÷¿®¤Ë¼ºÇÔ¤·¤Þ¤·¤¿.\n"
+
+msgid ": Send expression failed.\n"
+msgstr ": ¼°¤ÎÁ÷¿®¤Ë¼ºÇÔ¤·¤Þ¤·¤¿.\n"
+
+msgid "No marks set"
+msgstr "¥Þ¡¼¥¯¤¬ÀßÄꤵ¤ì¤Æ¤¤¤Þ¤»¤ó"
+
+#, c-format
+msgid "E283: No marks matching \"%s\""
+msgstr "E283: \"%s\" ¤Ë³ºÅö¤¹¤ë¥Þ¡¼¥¯¤¬¤¢¤ê¤Þ¤»¤ó"
+
+msgid ""
+"\n"
+"mark line col file/text"
+msgstr ""
+"\n"
+"mark ¹Ô Îó ¥Õ¥¡¥¤¥ë/¥Æ¥­¥¹¥È"
+
+msgid ""
+"\n"
+" jump line col file/text"
+msgstr ""
+"\n"
+" jump ¹Ô Îó ¥Õ¥¡¥¤¥ë/¥Æ¥­¥¹¥È"
+
+msgid ""
+"\n"
+"change line col text"
+msgstr ""
+"\n"
+"Êѹ¹ ¹Ô Îó ¥Æ¥­¥¹¥È"
+
+msgid ""
+"\n"
+"# File marks:\n"
+msgstr ""
+"\n"
+"# ¥Õ¥¡¥¤¥ë¥Þ¡¼¥¯:\n"
+
+msgid ""
+"\n"
+"# Jumplist (newest first):\n"
+msgstr ""
+"\n"
+"# ¥¸¥ã¥ó¥×¥ê¥¹¥È (¿·¤·¤¤¤â¤Î¤¬Àè):\n"
+
+msgid ""
+"\n"
+"# History of marks within files (newest to oldest):\n"
+msgstr ""
+"\n"
+"# ¥Õ¥¡¥¤¥ëÆâ¥Þ¡¼¥¯¤ÎÍúÎò (¿·¤·¤¤¤â¤Î¤«¤é¸Å¤¤¤â¤Î):\n"
+
+msgid "Missing '>'"
+msgstr "'>' ¤¬¸«¤Ä¤«¤ê¤Þ¤»¤ó"
+
+msgid "E543: Not a valid codepage"
+msgstr "E543: ̵¸ú¤Ê¥³¡¼¥É¥Ú¡¼¥¸¤Ç¤¹"
+
+msgid "E284: Cannot set IC values"
+msgstr "E284: IC¤ÎÃͤòÀßÄê¤Ç¤­¤Þ¤»¤ó"
+
+msgid "E285: Failed to create input context"
+msgstr "E285: ¥¤¥ó¥×¥Ã¥È¥³¥ó¥Æ¥­¥¹¥È¤ÎºîÀ®¤Ë¼ºÇÔ¤·¤Þ¤·¤¿"
+
+msgid "E286: Failed to open input method"
+msgstr "E286: ¥¤¥ó¥×¥Ã¥È¥á¥½¥Ã¥É¤Î¥ª¡¼¥×¥ó¤Ë¼ºÇÔ¤·¤Þ¤·¤¿"
+
+msgid "E287: Warning: Could not set destroy callback to IM"
+msgstr "E287: ·Ù¹ð: IM¤ÎÇ˲õ¥³¡¼¥ë¥Ð¥Ã¥¯¤òÀßÄê¤Ç¤­¤Þ¤»¤ó¤Ç¤·¤¿"
+
+msgid "E288: input method doesn't support any style"
+msgstr "E288: ¥¤¥ó¥×¥Ã¥È¥á¥½¥Ã¥É¤Ï¤É¤ó¤Ê¥¹¥¿¥¤¥ë¤â¥µ¥Ý¡¼¥È¤·¤Þ¤»¤ó"
+
+msgid "E289: input method doesn't support my preedit type"
+msgstr "E289: ¥¤¥ó¥×¥Ã¥È¥á¥½¥Ã¥É¤Ï my preedit type ¤ò¥µ¥Ý¡¼¥È¤·¤Þ¤»¤ó"
+
+msgid "E293: block was not locked"
+msgstr "E293: ¥Ö¥í¥Ã¥¯¤¬¥í¥Ã¥¯¤µ¤ì¤Æ¤¤¤Þ¤»¤ó"
+
+msgid "E294: Seek error in swap file read"
+msgstr "E294: ¥¹¥ï¥Ã¥×¥Õ¥¡¥¤¥ëÆɹþ»þ¤Ë¥·¡¼¥¯¥¨¥é¡¼¤Ç¤¹"
+
+msgid "E295: Read error in swap file"
+msgstr "E295: ¥¹¥ï¥Ã¥×¥Õ¥¡¥¤¥ë¤ÎÆɹþ¤ß¥¨¥é¡¼¤Ç¤¹"
+
+msgid "E296: Seek error in swap file write"
+msgstr "E296: ¥¹¥ï¥Ã¥×¥Õ¥¡¥¤¥ë½ñ¹þ¤ß»þ¤Ë¥·¡¼¥¯¥¨¥é¡¼¤Ç¤¹"
+
+msgid "E297: Write error in swap file"
+msgstr "E297: ¥¹¥ï¥Ã¥×¥Õ¥¡¥¤¥ë¤Î½ñ¹þ¤ß¥¨¥é¡¼¤Ç¤¹"
+
+msgid "E300: Swap file already exists (symlink attack?)"
+msgstr "E300: ¥¹¥ï¥Ã¥×¥Õ¥¡¥¤¥ë¤¬´û¤Ë¸ºß¤·¤Þ¤¹ (symlink¤Ë¤è¤ë¹¶·â?)"
+
+msgid "E298: Didn't get block nr 0?"
+msgstr "E298: ¥Ö¥í¥Ã¥¯ 0 ¤ò¼èÆÀ¤Ç¤­¤Þ¤»¤ó?"
+
+msgid "E298: Didn't get block nr 1?"
+msgstr "E298: ¥Ö¥í¥Ã¥¯ 1 ¤ò¼èÆÀ¤Ç¤­¤Þ¤»¤ó?"
+
+msgid "E298: Didn't get block nr 2?"
+msgstr "E298: ¥Ö¥í¥Ã¥¯ 2 ¤ò¼èÆÀ¤Ç¤­¤Þ¤»¤ó?"
+
+msgid "E843: Error while updating swap file crypt"
+msgstr "E843: ¥¹¥ï¥Ã¥×¥Õ¥¡¥¤¥ë¤Î°Å¹æ¤ò¹¹¿·Ãæ¤Ë¥¨¥é¡¼¤¬È¯À¸¤·¤Þ¤·¤¿"
+
+msgid "E301: Oops, lost the swap file!!!"
+msgstr "E301: ¤ª¤Ã¤È¡¢¥¹¥ï¥Ã¥×¥Õ¥¡¥¤¥ë¤¬¼º¤ï¤ì¤Þ¤·¤¿!!!"
+
+msgid "E302: Could not rename swap file"
+msgstr "E302: ¥¹¥ï¥Ã¥×¥Õ¥¡¥¤¥ë¤Î̾Á°¤òÊѤ¨¤é¤ì¤Þ¤»¤ó"
+
+#, c-format
+msgid "E303: Unable to open swap file for \"%s\", recovery impossible"
+msgstr "E303: \"%s\" ¤Î¥¹¥ï¥Ã¥×¥Õ¥¡¥¤¥ë¤ò³«¤±¤Ê¤¤¤Î¤Ç¥ê¥«¥Ð¥ê¤ÏÉÔ²Äǽ¤Ç¤¹"
+
+msgid "E304: ml_upd_block0(): Didn't get block 0??"
+msgstr "E304: ml_upd_block0(): ¥Ö¥í¥Ã¥¯ 0 ¤ò¼èÆÀ¤Ç¤­¤Þ¤»¤ó¤Ç¤·¤¿??"
+
+#, c-format
+msgid "E305: No swap file found for %s"
+msgstr "E305: %s ¤Ë¤Ï¥¹¥ï¥Ã¥×¥Õ¥¡¥¤¥ë¤¬¸«¤Ä¤«¤ê¤Þ¤»¤ó"
+
+msgid "Enter number of swap file to use (0 to quit): "
+msgstr "»ÈÍѤ¹¤ë¥¹¥ï¥Ã¥×¥Õ¥¡¥¤¥ë¤ÎÈÖ¹æ¤òÆþÎϤ·¤Æ¤¯¤À¤µ¤¤(0 ¤Ç½ªÎ»): "
+
+#, c-format
+msgid "E306: Cannot open %s"
+msgstr "E306: %s ¤ò³«¤±¤Þ¤»¤ó"
+
+msgid "Unable to read block 0 from "
+msgstr "¥Ö¥í¥Ã¥¯ 0 ¤òÆɹþ¤á¤Þ¤»¤ó "
+
+msgid ""
+"\n"
+"Maybe no changes were made or Vim did not update the swap file."
+msgstr ""
+"\n"
+"¶²¤é¤¯Êѹ¹¤¬¤µ¤ì¤Æ¤¤¤Ê¤¤¤«Vim¤¬¥¹¥ï¥Ã¥×¥Õ¥¡¥¤¥ë¤ò¹¹¿·¤·¤Æ¤¤¤Þ¤»¤ó."
+
+msgid " cannot be used with this version of Vim.\n"
+msgstr " Vim¤Î¤³¤Î¥Ð¡¼¥¸¥ç¥ó¤Ç¤Ï»ÈÍѤǤ­¤Þ¤»¤ó.\n"
+
+msgid "Use Vim version 3.0.\n"
+msgstr "Vim¤Î¥Ð¡¼¥¸¥ç¥ó3.0¤ò»ÈÍѤ·¤Æ¤¯¤À¤µ¤¤.\n"
+
+#, c-format
+msgid "E307: %s does not look like a Vim swap file"
+msgstr "E307: %s ¤ÏVim¤Î¥¹¥ï¥Ã¥×¥Õ¥¡¥¤¥ë¤Ç¤Ï¤Ê¤¤¤è¤¦¤Ç¤¹"
+
+msgid " cannot be used on this computer.\n"
+msgstr " ¤³¤Î¥³¥ó¥Ô¥å¡¼¥¿¤Ç¤Ï»ÈÍѤǤ­¤Þ¤»¤ó.\n"
+
+msgid "The file was created on "
+msgstr "¤³¤Î¥Õ¥¡¥¤¥ë¤Ï¼¡¤Î¾ì½ê¤Çºî¤é¤ì¤Þ¤·¤¿ "
+
+msgid ""
+",\n"
+"or the file has been damaged."
+msgstr ""
+",\n"
+"¤â¤·¤¯¤Ï¥Õ¥¡¥¤¥ë¤¬Â»½ý¤·¤Æ¤¤¤Þ¤¹."
+
+#, c-format
+msgid ""
+"E833: %s is encrypted and this version of Vim does not support encryption"
+msgstr ""
+"E833: %s ¤Ï¤³¤Î¥Ð¡¼¥¸¥ç¥ó¤ÎVim¤Ç¥µ¥Ý¡¼¥È¤·¤Æ¤¤¤Ê¤¤·Á¼°¤Ç°Å¹æ²½¤µ¤ì¤Æ¤¤¤Þ¤¹"
+
+msgid " has been damaged (page size is smaller than minimum value).\n"
+msgstr " ¤Ï»½ý¤·¤Æ¤¤¤Þ¤¹ (¥Ú¡¼¥¸¥µ¥¤¥º¤¬ºÇ¾®Ãͤò²¼²ó¤Ã¤Æ¤¤¤Þ¤¹).\n"
+
+#, c-format
+msgid "Using swap file \"%s\""
+msgstr "¥¹¥ï¥Ã¥×¥Õ¥¡¥¤¥ë \"%s\" ¤ò»ÈÍÑÃæ"
+
+#, c-format
+msgid "Original file \"%s\""
+msgstr "¸¶ËÜ¥Õ¥¡¥¤¥ë \"%s\""
+
+msgid "E308: Warning: Original file may have been changed"
+msgstr "E308: ·Ù¹ð: ¸¶ËÜ¥Õ¥¡¥¤¥ë¤¬Êѹ¹¤µ¤ì¤Æ¤¤¤Þ¤¹"
+
+#, c-format
+msgid "Swap file is encrypted: \"%s\""
+msgstr "¥¹¥ï¥Ã¥×¥Õ¥¡¥¤¥ë¤Ï°Å¹æ²½¤µ¤ì¤Æ¤¤¤Þ¤¹: \"%s\""
+
+msgid ""
+"\n"
+"If you entered a new crypt key but did not write the text file,"
+msgstr ""
+"\n"
+"¿·¤·¤¤°Å¹æ¥­¡¼¤òÆþÎϤ·¤¿¤¢¤È¤Ë¥Æ¥­¥¹¥È¥Õ¥¡¥¤¥ë¤òÊݸ¤·¤Æ¤¤¤Ê¤¤¾ì¹ç¤Ï¡¢"
+
+msgid ""
+"\n"
+"enter the new crypt key."
+msgstr ""
+"\n"
+"¿·¤·¤¤°Å¹æ¥­¡¼¤òÆþÎϤ·¤Æ¤¯¤À¤µ¤¤."
+
+msgid ""
+"\n"
+"If you wrote the text file after changing the crypt key press enter"
+msgstr ""
+"\n"
+"°Å¹æ¥­¡¼¤òÊѤ¨¤¿¤¢¤È¤Ë¥Æ¥­¥¹¥È¥Õ¥¡¥¤¥ë¤òÊݸ¤·¤¿¾ì¹ç¤Ï¡¢¥Æ¥­¥¹¥È¥Õ¥¡¥¤¥ë¤È"
+
+msgid ""
+"\n"
+"to use the same key for text file and swap file"
+msgstr ""
+"\n"
+"¥¹¥ï¥Ã¥×¥Õ¥¡¥¤¥ë¤ËƱ¤¸°Å¹æ¥­¡¼¤ò»È¤¦¤¿¤á¤Ëenter¤À¤±¤ò²¡¤·¤Æ¤¯¤À¤µ¤¤."
+
+#, c-format
+msgid "E309: Unable to read block 1 from %s"
+msgstr "E309: %s ¤«¤é¥Ö¥í¥Ã¥¯ 1 ¤òÆɹþ¤á¤Þ¤»¤ó"
+
+msgid "???MANY LINES MISSING"
+msgstr "???¿¤¯¤Î¹Ô¤¬¼º¤ï¤ì¤Æ¤¤¤Þ¤¹"
+
+msgid "???LINE COUNT WRONG"
+msgstr "???¹Ô¿ô¤¬´Ö°ã¤Ã¤Æ¤¤¤Þ¤¹"
+
+msgid "???EMPTY BLOCK"
+msgstr "???¥Ö¥í¥Ã¥¯¤¬¶õ¤Ç¤¹"
+
+msgid "???LINES MISSING"
+msgstr "???¹Ô¤¬¼º¤ï¤ì¤Æ¤¤¤Þ¤¹"
+
+#, c-format
+msgid "E310: Block 1 ID wrong (%s not a .swp file?)"
+msgstr "E310: ¥Ö¥í¥Ã¥¯ 1 ¤ÎID¤¬´Ö°ã¤Ã¤Æ¤¤¤Þ¤¹(%s ¤¬.swp¥Õ¥¡¥¤¥ë¤Ç¤Ê¤¤?)"
+
+msgid "???BLOCK MISSING"
+msgstr "???¥Ö¥í¥Ã¥¯¤¬¤¢¤ê¤Þ¤»¤ó"
+
+msgid "??? from here until ???END lines may be messed up"
+msgstr "??? ¤³¤³¤«¤é ???END ¤Þ¤Ç¤Î¹Ô¤¬Ç˲õ¤µ¤ì¤Æ¤¤¤ë¤è¤¦¤Ç¤¹"
+
+msgid "??? from here until ???END lines may have been inserted/deleted"
+msgstr "??? ¤³¤³¤«¤é ???END ¤Þ¤Ç¤Î¹Ô¤¬ÁÞÆþ¤«ºï½ü¤µ¤ì¤¿¤è¤¦¤Ç¤¹"
+
+msgid "???END"
+msgstr "???END"
+
+msgid "E311: Recovery Interrupted"
+msgstr "E311: ¥ê¥«¥Ð¥ê¤¬³ä¹þ¤Þ¤ì¤Þ¤·¤¿"
+
+msgid ""
+"E312: Errors detected while recovering; look for lines starting with ???"
+msgstr ""
+"E312: ¥ê¥«¥Ð¥ê¤ÎºÇÃæ¤Ë¥¨¥é¡¼¤¬¸¡½Ð¤µ¤ì¤Þ¤·¤¿; ???¤Ç»Ï¤Þ¤ë¹Ô¤ò»²¾È¤·¤Æ¤¯¤À¤µ¤¤"
+
+msgid "See \":help E312\" for more information."
+msgstr "¾ÜºÙ¤Ï \":help E312\" ¤ò»²¾È¤·¤Æ¤¯¤À¤µ¤¤"
+
+msgid "Recovery completed. You should check if everything is OK."
+msgstr "¥ê¥«¥Ð¥ê¤¬½ªÎ»¤·¤Þ¤·¤¿. Á´¤Æ¤¬Àµ¤·¤¤¤«¥Á¥§¥Ã¥¯¤·¤Æ¤¯¤À¤µ¤¤."
+
+msgid ""
+"\n"
+"(You might want to write out this file under another name\n"
+msgstr ""
+"\n"
+"(Êѹ¹¤ò¥Á¥§¥Ã¥¯¤¹¤ë¤¿¤á¤Ë¡¢¤³¤Î¥Õ¥¡¥¤¥ë¤òÊ̤Î̾Á°¤ÇÊݸ¤·¤¿¾å¤Ç\n"
+
+msgid "and run diff with the original file to check for changes)"
+msgstr "¸¶ËÜ¥Õ¥¡¥¤¥ë¤È¤Î diff ¤ò¼Â¹Ô¤¹¤ë¤ÈÎɤ¤¤Ç¤·¤ç¤¦)"
+
+msgid "Recovery completed. Buffer contents equals file contents."
+msgstr "Éü¸µ´°Î». ¥Ð¥Ã¥Õ¥¡¤ÎÆâÍƤϥե¡¥¤¥ë¤ÈƱ¤¸¤Ë¤Ê¤ê¤Þ¤·¤¿."
+
+msgid ""
+"\n"
+"You may want to delete the .swp file now.\n"
+"\n"
+msgstr ""
+"\n"
+"¸µ¤Î.swp¥Õ¥¡¥¤¥ë¤Ïºï½ü¤·¤Æ¤â¹½¤¤¤Þ¤»¤ó\n"
+"\n"
+
+msgid "Using crypt key from swap file for the text file.\n"
+msgstr "¥¹¥ï¥Ã¥×¥Õ¥¡¥¤¥ë¤«¤é¼èÆÀ¤·¤¿°Å¹æ¥­¡¼¤ò¥Æ¥­¥¹¥È¥Õ¥¡¥¤¥ë¤Ë»È¤¤¤Þ¤¹.\n"
+
+msgid "Swap files found:"
+msgstr "¥¹¥ï¥Ã¥×¥Õ¥¡¥¤¥ë¤¬Ê£¿ô¸«¤Ä¤«¤ê¤Þ¤·¤¿:"
+
+msgid " In current directory:\n"
+msgstr " ¸½ºß¤Î¥Ç¥£¥ì¥¯¥È¥ê:\n"
+
+msgid " Using specified name:\n"
+msgstr " °Ê²¼¤Î̾Á°¤ò»ÈÍÑÃæ:\n"
+
+msgid " In directory "
+msgstr " ¥Ç¥£¥ì¥¯¥È¥ê "
+
+msgid " -- none --\n"
+msgstr " -- ¤Ê¤· --\n"
+
+msgid " owned by: "
+msgstr " ½êÍ­¼Ô: "
+
+msgid " dated: "
+msgstr " ÆüÉÕ: "
+
+msgid " dated: "
+msgstr " ÆüÉÕ: "
+
+msgid " [from Vim version 3.0]"
+msgstr " [from Vim version 3.0]"
+
+msgid " [does not look like a Vim swap file]"
+msgstr " [Vim¤Î¥¹¥ï¥Ã¥×¥Õ¥¡¥¤¥ë¤Ç¤Ï¤Ê¤¤¤è¤¦¤Ç¤¹]"
+
+msgid " file name: "
+msgstr " ¥Õ¥¡¥¤¥ë̾: "
+
+msgid ""
+"\n"
+" modified: "
+msgstr ""
+"\n"
+" Êѹ¹¾õÂÖ: "
+
+msgid "YES"
+msgstr "¤¢¤ê"
+
+msgid "no"
+msgstr "¤Ê¤·"
+
+msgid ""
+"\n"
+" user name: "
+msgstr ""
+"\n"
+" ¥æ¡¼¥¶¡¼Ì¾: "
+
+msgid " host name: "
+msgstr " ¥Û¥¹¥È̾: "
+
+msgid ""
+"\n"
+" host name: "
+msgstr ""
+"\n"
+" ¥Û¥¹¥È̾: "
+
+msgid ""
+"\n"
+" process ID: "
+msgstr ""
+"\n"
+" ¥×¥í¥»¥¹ID: "
+
+msgid " (STILL RUNNING)"
+msgstr " (¤Þ¤À¼Â¹ÔÃæ)"
+
+msgid ""
+"\n"
+" [not usable with this version of Vim]"
+msgstr ""
+"\n"
+" [¤³¤ÎVim¥Ð¡¼¥¸¥ç¥ó¤Ç¤Ï»ÈÍѤǤ­¤Þ¤»¤ó]"
+
+msgid ""
+"\n"
+" [not usable on this computer]"
+msgstr ""
+"\n"
+" [¤³¤Î¥³¥ó¥Ô¥å¡¼¥¿¤Ç¤Ï»ÈÍѤǤ­¤Þ¤»¤ó]"
+
+msgid " [cannot be read]"
+msgstr " [Æɹþ¤á¤Þ¤»¤ó]"
+
+msgid " [cannot be opened]"
+msgstr " [³«¤±¤Þ¤»¤ó]"
+
+msgid "E313: Cannot preserve, there is no swap file"
+msgstr "E313: ¥¹¥ï¥Ã¥×¥Õ¥¡¥¤¥ë¤¬Ìµ¤¤¤Î¤Ç°Ý»ý¤Ç¤­¤Þ¤»¤ó"
+
+msgid "File preserved"
+msgstr "¥Õ¥¡¥¤¥ë¤¬°Ý»ý¤µ¤ì¤Þ¤¹"
+
+msgid "E314: Preserve failed"
+msgstr "E314: °Ý»ý¤Ë¼ºÇÔ¤·¤Þ¤·¤¿"
+
+#, c-format
+msgid "E315: ml_get: invalid lnum: %ld"
+msgstr "E315: ml_get: ̵¸ú¤Êlnum¤Ç¤¹: %ld"
+
+#, c-format
+msgid "E316: ml_get: cannot find line %ld"
+msgstr "E316: ml_get: ¹Ô %ld ¤ò¸«¤Ä¤±¤é¤ì¤Þ¤»¤ó"
+
+msgid "E317: pointer block id wrong 3"
+msgstr "E317: ¥Ý¥¤¥ó¥¿¥Ö¥í¥Ã¥¯¤ÎID¤¬´Ö°ã¤Ã¤Æ¤¤¤Þ¤¹ 3"
+
+msgid "stack_idx should be 0"
+msgstr "stack_idx ¤Ï 0 ¤Ç¤¢¤ë¤Ù¤­¤Ç¤¹"
+
+msgid "E318: Updated too many blocks?"
+msgstr "E318: ¹¹¿·¤µ¤ì¤¿¥Ö¥í¥Ã¥¯¤¬Â¿²á¤®¤ë¤«¤â?"
+
+msgid "E317: pointer block id wrong 4"
+msgstr "E317: ¥Ý¥¤¥ó¥¿¥Ö¥í¥Ã¥¯¤ÎID¤¬´Ö°ã¤Ã¤Æ¤¤¤Þ¤¹ 4"
+
+msgid "deleted block 1?"
+msgstr "¥Ö¥í¥Ã¥¯ 1 ¤Ï¾Ã¤µ¤ì¤¿?"
+
+#, c-format
+msgid "E320: Cannot find line %ld"
+msgstr "E320: ¹Ô %ld ¤¬¸«¤Ä¤«¤ê¤Þ¤»¤ó"
+
+msgid "E317: pointer block id wrong"
+msgstr "E317: ¥Ý¥¤¥ó¥¿¥Ö¥í¥Ã¥¯¤ÎID¤¬´Ö°ã¤Ã¤Æ¤¤¤Þ¤¹"
+
+msgid "pe_line_count is zero"
+msgstr "pe_line_count ¤¬¥¼¥í¤Ç¤¹"
+
+#, c-format
+msgid "E322: line number out of range: %ld past the end"
+msgstr "E322: ¹ÔÈֹ椬Èϰϳ°¤Ç¤¹: %ld Ķ¤¨¤Æ¤¤¤Þ¤¹"
+
+#, c-format
+msgid "E323: line count wrong in block %ld"
+msgstr "E323: ¥Ö¥í¥Ã¥¯ %ld ¤Î¹Ô¥«¥¦¥ó¥È¤¬´Ö°ã¤Ã¤Æ¤¤¤Þ¤¹"
+
+msgid "Stack size increases"
+msgstr "¥¹¥¿¥Ã¥¯¥µ¥¤¥º¤¬Áý¤¨¤Þ¤¹"
+
+msgid "E317: pointer block id wrong 2"
+msgstr "E317: ¥Ý¥¤¥ó¥¿¥Ö¥í¥Ã¥¯¤ÎID¤¬´Ö°ã¤Ã¤Æ¤¤¤Þ¤¹ 2"
+
+#, c-format
+msgid "E773: Symlink loop for \"%s\""
+msgstr "E773: \"%s\" ¤Î¥·¥ó¥Ü¥ê¥Ã¥¯¥ê¥ó¥¯¤¬¥ë¡¼¥×¤Ë¤Ê¤Ã¤Æ¤¤¤Þ¤¹"
+
+msgid "E325: ATTENTION"
+msgstr "E325: Ãí°Õ"
+
+msgid ""
+"\n"
+"Found a swap file by the name \""
+msgstr ""
+"\n"
+"¼¡¤Î̾Á°¤Ç¥¹¥ï¥Ã¥×¥Õ¥¡¥¤¥ë¤ò¸«¤Ä¤±¤Þ¤·¤¿ \""
+
+msgid "While opening file \""
+msgstr "¼¡¤Î¥Õ¥¡¥¤¥ë¤ò³«¤¤¤Æ¤¤¤ëºÇÃæ \""
+
+msgid " CANNOT BE FOUND"
+msgstr " ¸«¤Ä¤«¤ê¤Þ¤»¤ó"
+
+msgid " NEWER than swap file!\n"
+msgstr " ¥¹¥ï¥Ã¥×¥Õ¥¡¥¤¥ë¤è¤ê¤â¿·¤·¤¤¤Ç¤¹!\n"
+
+msgid ""
+"\n"
+"(1) Another program may be editing the same file. If this is the case,\n"
+" be careful not to end up with two different instances of the same\n"
+" file when making changes. Quit, or continue with caution.\n"
+msgstr ""
+"\n"
+"(1) ÊÌ¤Î¥×¥í¥°¥é¥à¤¬Æ±¤¸¥Õ¥¡¥¤¥ë¤òÊÔ½¸¤·¤Æ¤¤¤ë¤«¤â¤·¤ì¤Þ¤»¤ó.\n"
+" ¤³¤Î¾ì¹ç¤Ë¤Ï¡¢Êѹ¹¤ò¤·¤Æ¤·¤Þ¤¦¤È1¤Ä¤Î¥Õ¥¡¥¤¥ë¤ËÂФ·¤Æ°Û¤Ê¤ë2¤Ä¤Î\n"
+" ¥¤¥ó¥¹¥¿¥ó¥¹¤¬¤Ç¤­¤Æ¤·¤Þ¤¦¤Î¤Ç¡¢¤½¤¦¤·¤Ê¤¤¤è¤¦¤Ëµ¤¤ò¤Ä¤±¤Æ¤¯¤À¤µ¤¤.\n"
+" ½ªÎ»¤¹¤ë¤«¡¢Ãí°Õ¤·¤Ê¤¬¤é³¤±¤Æ¤¯¤À¤µ¤¤.\n"
+
+msgid "(2) An edit session for this file crashed.\n"
+msgstr "(2) ¤³¤Î¥Õ¥¡¥¤¥ë¤ÎÊÔ½¸¥»¥Ã¥·¥ç¥ó¤¬¥¯¥é¥Ã¥·¥å¤·¤¿.\n"
+
+msgid " If this is the case, use \":recover\" or \"vim -r "
+msgstr " ¤³¤Î¾ì¹ç¤Ë¤Ï \":recover\" ¤« \"vim -r "
+
+msgid ""
+"\"\n"
+" to recover the changes (see \":help recovery\").\n"
+msgstr ""
+"\"\n"
+" ¤ò»ÈÍѤ·¤ÆÊѹ¹¤ò¥ê¥«¥Ð¡¼¤·¤Þ¤¹(\":help recovery\" ¤ò»²¾È).\n"
+
+msgid " If you did this already, delete the swap file \""
+msgstr " ´û¤Ë¤³¤ì¤ò¹Ô¤Ê¤Ã¤¿¤Î¤Ê¤é¤Ð¡¢¥¹¥ï¥Ã¥×¥Õ¥¡¥¤¥ë \""
+
+msgid ""
+"\"\n"
+" to avoid this message.\n"
+msgstr ""
+"\"\n"
+" ¤ò¾Ã¤»¤Ð¤³¤Î¥á¥Ã¥»¡¼¥¸¤ò²óÈò¤Ç¤­¤Þ¤¹.\n"
+
+msgid "Swap file \""
+msgstr "¥¹¥ï¥Ã¥×¥Õ¥¡¥¤¥ë \""
+
+msgid "\" already exists!"
+msgstr "\" ¤¬´û¤Ë¤¢¤ê¤Þ¤¹!"
+
+msgid "VIM - ATTENTION"
+msgstr "VIM - Ãí°Õ"
+
+msgid "Swap file already exists!"
+msgstr "¥¹¥ï¥Ã¥×¥Õ¥¡¥¤¥ë¤¬´û¤Ë¸ºß¤·¤Þ¤¹!"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"ÆɹþÀìÍѤdz«¤¯(&O)\n"
+"¤È¤Ë¤«¤¯ÊÔ½¸¤¹¤ë(&E)\n"
+"Éü³è¤µ¤»¤ë(&R)\n"
+"½ªÎ»¤¹¤ë(&Q)\n"
+"Ãæ»ß¤¹¤ë(&A)"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Delete it\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"ÆɹþÀìÍѤdz«¤¯(&O)\n"
+"¤È¤Ë¤«¤¯ÊÔ½¸¤¹¤ë(&E)\n"
+"Éü³è¤µ¤»¤ë(&R)\n"
+"ºï½ü¤¹¤ë(&D)\n"
+"½ªÎ»¤¹¤ë(&Q)\n"
+"Ãæ»ß¤¹¤ë(&A)"
+
+msgid "E326: Too many swap files found"
+msgstr "E326: ¥¹¥ï¥Ã¥×¥Õ¥¡¥¤¥ë¤¬Â¿¿ô¸«¤Ä¤«¤ê¤Þ¤·¤¿"
+
+msgid "E327: Part of menu-item path is not sub-menu"
+msgstr "E327: ¥á¥Ë¥å¡¼¥¢¥¤¥Æ¥à¤Î¥Ñ¥¹¤ÎÉôʬ¤¬¥µ¥Ö¥á¥Ë¥å¡¼¤Ç¤Ï¤¢¤ê¤Þ¤»¤ó"
+
+msgid "E328: Menu only exists in another mode"
+msgstr "E328: ¥á¥Ë¥å¡¼¤Ï¾¤Î¥â¡¼¥É¤Ë¤À¤±¤¢¤ê¤Þ¤¹"
+
+#, c-format
+msgid "E329: No menu \"%s\""
+msgstr "E329: \"%s\" ¤È¤¤¤¦¥á¥Ë¥å¡¼¤Ï¤¢¤ê¤Þ¤»¤ó"
+
+msgid "E792: Empty menu name"
+msgstr "E792: ¥á¥Ë¥å¡¼Ì¾¤¬¶õ¤Ç¤¹"
+
+msgid "E330: Menu path must not lead to a sub-menu"
+msgstr "E330: ¥á¥Ë¥å¡¼¥Ñ¥¹¤Ï¥µ¥Ö¥á¥Ë¥å¡¼¤òÀ¸¤¸¤ë¤Ù¤­¤Ç¤Ï¤¢¤ê¤Þ¤»¤ó"
+
+msgid "E331: Must not add menu items directly to menu bar"
+msgstr "E331: ¥á¥Ë¥å¡¼¥Ð¡¼¤Ë¤ÏľÀÜ¥á¥Ë¥å¡¼¥¢¥¤¥Æ¥à¤òÄɲäǤ­¤Þ¤»¤ó"
+
+msgid "E332: Separator cannot be part of a menu path"
+msgstr "E332: ¶èÀÚ¤ê¤Ï¥á¥Ë¥å¡¼¥Ñ¥¹¤Î°ìÉô¤Ç¤Ï¤¢¤ê¤Þ¤»¤ó"
+
+msgid ""
+"\n"
+"--- Menus ---"
+msgstr ""
+"\n"
+"--- ¥á¥Ë¥å¡¼ ---"
+
+msgid "Tear off this menu"
+msgstr "¤³¤Î¥á¥Ë¥å¡¼¤òÀÚ¤ê¼è¤ë"
+
+#, c-format
+msgid "E335: Menu not defined for %s mode"
+msgstr "E335: %s ¤Ë¤Ï¥á¥Ë¥å¡¼¤¬ÄêµÁ¤µ¤ì¤Æ¤¤¤Þ¤»¤ó"
+
+msgid "E333: Menu path must lead to a menu item"
+msgstr "E333: ¥á¥Ë¥å¡¼¥Ñ¥¹¤Ï¥á¥Ë¥å¡¼¥¢¥¤¥Æ¥à¤òÀ¸¤¸¤Ê¤±¤ì¤Ð¤¤¤±¤Þ¤»¤ó"
+
+#, c-format
+msgid "E334: Menu not found: %s"
+msgstr "E334: ¥á¥Ë¥å¡¼¤¬¸«¤Ä¤«¤ê¤Þ¤»¤ó: %s"
+
+msgid "E336: Menu path must lead to a sub-menu"
+msgstr "E336: ¥á¥Ë¥å¡¼¥Ñ¥¹¤Ï¥µ¥Ö¥á¥Ë¥å¡¼¤òÀ¸¤¸¤Ê¤±¤ì¤Ð¤¤¤±¤Þ¤»¤ó"
+
+msgid "E337: Menu not found - check menu names"
+msgstr "E337: ¥á¥Ë¥å¡¼¤¬¸«¤Ä¤«¤ê¤Þ¤»¤ó - ¥á¥Ë¥å¡¼Ì¾¤ò³Îǧ¤·¤Æ¤¯¤À¤µ¤¤"
+
+#, c-format
+msgid "Error detected while processing %s:"
+msgstr "%s ¤Î½èÍýÃæ¤Ë¥¨¥é¡¼¤¬¸¡½Ð¤µ¤ì¤Þ¤·¤¿:"
+
+#, c-format
+msgid "line %4ld:"
+msgstr "¹Ô %4ld:"
+
+#, c-format
+msgid "E354: Invalid register name: '%s'"
+msgstr "E354: ̵¸ú¤Ê¥ì¥¸¥¹¥¿Ì¾: '%s'"
+
+msgid "Messages maintainer: Bram Moolenaar <Bram@vim.org>"
+msgstr "ÆüËܸì¥á¥Ã¥»¡¼¥¸ËÝÌõ/´Æ½¤: ¼²¬ ÂÀϺ <koron.kaoriya@gmail.com>"
+
+msgid "Interrupt: "
+msgstr "³ä¹þ¤ß: "
+
+msgid "Press ENTER or type command to continue"
+msgstr "³¤±¤ë¤Ë¤ÏENTER¤ò²¡¤¹¤«¥³¥Þ¥ó¥É¤òÆþÎϤ·¤Æ¤¯¤À¤µ¤¤"
+
+#, c-format
+msgid "%s line %ld"
+msgstr "%s ¹Ô %ld"
+
+msgid "-- More --"
+msgstr "-- ·Ñ³ --"
+
+msgid " SPACE/d/j: screen/page/line down, b/u/k: up, q: quit "
+msgstr " SPACE/d/j: ²èÌÌ/¥Ú¡¼¥¸/¹Ô ²¼, b/u/k: ¾å, q: ½ªÎ» "
+
+msgid "Question"
+msgstr "¼ÁÌä"
+
+msgid ""
+"&Yes\n"
+"&No"
+msgstr ""
+"¤Ï¤¤(&Y)\n"
+"¤¤¤¤¤¨(&N)"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"Save &All\n"
+"&Discard All\n"
+"&Cancel"
+msgstr ""
+"¤Ï¤¤(&Y)\n"
+"¤¤¤¤¤¨(&N)\n"
+"Á´¤ÆÊݸ(&A)\n"
+"Á´¤ÆÊü´þ(&D)\n"
+"¥­¥ã¥ó¥»¥ë(&C)"
+
+msgid "Select Directory dialog"
+msgstr "¥Ç¥£¥ì¥¯¥È¥êÁªÂò¥À¥¤¥¢¥í¥°"
+
+msgid "Save File dialog"
+msgstr "¥Õ¥¡¥¤¥ëÊݸ¥À¥¤¥¢¥í¥°"
+
+msgid "Open File dialog"
+msgstr "¥Õ¥¡¥¤¥ëÆɹþ¥À¥¤¥¢¥í¥°"
+
+msgid "E338: Sorry, no file browser in console mode"
+msgstr "E338: ¥³¥ó¥½¡¼¥ë¥â¡¼¥É¤Ç¤Ï¥Õ¥¡¥¤¥ë¥Ö¥é¥¦¥¶¤ò»È¤¨¤Þ¤»¤ó¡¢¤´¤á¤ó¤Ê¤µ¤¤"
+
+msgid "E766: Insufficient arguments for printf()"
+msgstr "E766: printf() ¤Î°ú¿ô¤¬ÉÔ½½Ê¬¤Ç¤¹"
+
+msgid "E807: Expected Float argument for printf()"
+msgstr "E807: printf() ¤Î°ú¿ô¤Ë¤ÏÉâÆ°¾®¿ôÅÀ¿ô¤¬´üÂÔ¤µ¤ì¤Æ¤¤¤Þ¤¹"
+
+msgid "E767: Too many arguments to printf()"
+msgstr "E767: printf() ¤Î°ú¿ô¤¬Â¿²á¤®¤Þ¤¹"
+
+msgid "W10: Warning: Changing a readonly file"
+msgstr "W10: ·Ù¹ð: ÆɹþÀìÍÑ¥Õ¥¡¥¤¥ë¤òÊѹ¹¤·¤Þ¤¹"
+
+msgid "Type number and <Enter> or click with mouse (empty cancels): "
+msgstr ""
+"ÈÖ¹æ¤È<Enter>¤òÆþÎϤ¹¤ë¤«¥Þ¥¦¥¹¤Ç¥¯¥ê¥Ã¥¯¤·¤Æ¤¯¤À¤µ¤¤ (¶õ¤Ç¥­¥ã¥ó¥»¥ë): "
+
+msgid "Type number and <Enter> (empty cancels): "
+msgstr "ÈÖ¹æ¤È<Enter>¤òÆþÎϤ·¤Æ¤¯¤À¤µ¤¤ (¶õ¤Ç¥­¥ã¥ó¥»¥ë): "
+
+#, c-format
+msgid "%ld more line"
+msgid_plural "%ld more lines"
+msgstr[0] "%ld ¹Ô Äɲä·¤Þ¤·¤¿"
+
+#, c-format
+msgid "%ld line less"
+msgid_plural "%ld fewer lines"
+msgstr[0] "%ld ¹Ô ºï½ü¤·¤Þ¤·¤¿"
+
+msgid " (Interrupted)"
+msgstr " (³ä¹þ¤Þ¤ì¤Þ¤·¤¿)"
+
+msgid "Beep!"
+msgstr "¥Ó¡¼¥Ã!"
+
+msgid "ERROR: "
+msgstr "¥¨¥é¡¼: "
+
+#, c-format
+msgid ""
+"\n"
+"[bytes] total alloc-freed %lu-%lu, in use %lu, peak use %lu\n"
+msgstr ""
+"\n"
+"[¥á¥â¥ê(¥Ð¥¤¥È)] Áí³äÅö-²òÊüÎÌ %lu-%lu, »ÈÍÑÎÌ %lu, ¥Ô¡¼¥¯»þ %lu\n"
+
+#, c-format
+msgid ""
+"[calls] total re/malloc()'s %lu, total free()'s %lu\n"
+"\n"
+msgstr ""
+"[¸Æ½Ð] Áí re/malloc() ²ó¿ô %lu, Áí free() ²ó¿ô %lu\n"
+"\n"
+
+msgid "E340: Line is becoming too long"
+msgstr "E340: ¹Ô¤¬Ä¹¤¯¤Ê¤ê²á¤®¤Þ¤·¤¿"
+
+#, c-format
+msgid "E341: Internal error: lalloc(%ld, )"
+msgstr "E341: ÆâÉô¥¨¥é¡¼: lalloc(%ld,)"
+
+#, c-format
+msgid "E342: Out of memory! (allocating %lu bytes)"
+msgstr "E342: ¥á¥â¥ê¤¬Â­¤ê¤Þ¤»¤ó! (%lu ¥Ð¥¤¥È¤ò³äÅöÍ×µá)"
+
+#, c-format
+msgid "Calling shell to execute: \"%s\""
+msgstr "¼Â¹Ô¤Î¤¿¤á¤Ë¥·¥§¥ë¤ò¸Æ½Ð¤·Ãæ: \"%s\""
+
+msgid "E545: Missing colon"
+msgstr "E545: ¥³¥í¥ó¤¬¤¢¤ê¤Þ¤»¤ó"
+
+msgid "E546: Illegal mode"
+msgstr "E546: ÉÔÀµ¤Ê¥â¡¼¥É¤Ç¤¹"
+
+msgid "E547: Illegal mouseshape"
+msgstr "E547: ÉÔÀµ¤Ê 'mouseshape' ¤Ç¤¹"
+
+msgid "E548: digit expected"
+msgstr "E548: ¿ôÃͤ¬É¬ÍפǤ¹"
+
+msgid "E549: Illegal percentage"
+msgstr "E549: ÉÔÀµ¤Ê¥Ñ¡¼¥»¥ó¥Æ¡¼¥¸¤Ç¤¹"
+
+msgid "E854: path too long for completion"
+msgstr "E854: ¥Ñ¥¹¤¬Ä¹²á¤®¤ÆÊä´°¤Ç¤­¤Þ¤»¤ó"
+
+#, c-format
+msgid ""
+"E343: Invalid path: '**[number]' must be at the end of the path or be "
+"followed by '%s'."
+msgstr ""
+"E343: ̵¸ú¤Ê¥Ñ¥¹¤Ç¤¹: '**[¿ôÃÍ]' ¤Ïpath¤ÎºÇ¸å¤« '%s' ¤¬Â³¤¤¤Æ¤Ê¤¤¤È¤¤¤±¤Þ¤»"
+"¤ó."
+
+#, c-format
+msgid "E344: Can't find directory \"%s\" in cdpath"
+msgstr "E344: cdpath¤Ë¤Ï \"%s\" ¤È¤¤¤¦¥Ç¥£¥ì¥¯¥È¥ê¤¬¤¢¤ê¤Þ¤»¤ó"
+
+#, c-format
+msgid "E345: Can't find file \"%s\" in path"
+msgstr "E345: path¤Ë¤Ï \"%s\" ¤È¤¤¤¦¥Õ¥¡¥¤¥ë¤¬¤¢¤ê¤Þ¤»¤ó"
+
+#, c-format
+msgid "E346: No more directory \"%s\" found in cdpath"
+msgstr "E346: cdpath¤Ë¤Ï¤³¤ì°Ê¾å \"%s\" ¤È¤¤¤¦¥Ç¥£¥ì¥¯¥È¥ê¤¬¤¢¤ê¤Þ¤»¤ó"
+
+#, c-format
+msgid "E347: No more file \"%s\" found in path"
+msgstr "E347: ¥Ñ¥¹¤Ë¤Ï¤³¤ì°Ê¾å \"%s\" ¤È¤¤¤¦¥Õ¥¡¥¤¥ë¤¬¤¢¤ê¤Þ¤»¤ó"
+
+#, c-format
+msgid "E668: Wrong access mode for NetBeans connection info file: \"%s\""
+msgstr ""
+"E668: NetBeans¤ÎÀܳ¾ðÊó¥Õ¥¡¥¤¥ë¤Î¥¢¥¯¥»¥¹¥â¡¼¥É¤ËÌäÂ꤬¤¢¤ê¤Þ¤¹: \"%s\""
+
+#, c-format
+msgid "E658: NetBeans connection lost for buffer %ld"
+msgstr "E658: ¥Ð¥Ã¥Õ¥¡ %ld ¤Î NetBeans Àܳ¤¬¼º¤ï¤ì¤Þ¤·¤¿"
+
+msgid "E838: netbeans is not supported with this GUI"
+msgstr "E838: NetBeans¤Ï¤³¤ÎGUI¤Ë¤ÏÂбþ¤·¤Æ¤¤¤Þ¤»¤ó"
+
+msgid "E511: netbeans already connected"
+msgstr "E511: NetBeans¤Ï´û¤ËÀܳ¤·¤Æ¤¤¤Þ¤¹"
+
+#, c-format
+msgid "E505: %s is read-only (add ! to override)"
+msgstr "E505: %s ¤ÏÆɹþÀìÍѤǤ¹ (¶¯À©½ñ¹þ¤Ë¤Ï ! ¤òÄɲÃ)"
+
+msgid "E349: No identifier under cursor"
+msgstr "E349: ¥«¡¼¥½¥ë¤Î°ÌÃ֤ˤϼ±Ê̻Ҥ¬¤¢¤ê¤Þ¤»¤ó"
+
+msgid "E774: 'operatorfunc' is empty"
+msgstr "E774: 'operatorfunc' ¥ª¥×¥·¥ç¥ó¤¬¶õ¤Ç¤¹"
+
+msgid "E775: Eval feature not available"
+msgstr "E775: ¼°É¾²Áµ¡Ç½¤¬Ìµ¸ú¤Ë¤Ê¤Ã¤Æ¤¤¤Þ¤¹"
+
+msgid "Warning: terminal cannot highlight"
+msgstr "·Ù¹ð: »ÈÍѤ·¤Æ¤¤¤ëüËö¤Ï¥Ï¥¤¥é¥¤¥È¤Ç¤­¤Þ¤»¤ó"
+
+msgid "E348: No string under cursor"
+msgstr "E348: ¥«¡¼¥½¥ë¤Î°ÌÃ֤ˤÏʸ»úÎ󤬤¢¤ê¤Þ¤»¤ó"
+
+msgid "E352: Cannot erase folds with current 'foldmethod'"
+msgstr "E352: ¸½ºß¤Î 'foldmethod' ¤Ç¤ÏÀÞ¾ö¤ß¤ò¾Ãµî¤Ç¤­¤Þ¤»¤ó"
+
+msgid "E664: changelist is empty"
+msgstr "E664: Êѹ¹¥ê¥¹¥È¤¬¶õ¤Ç¤¹"
+
+msgid "E662: At start of changelist"
+msgstr "E662: Êѹ¹¥ê¥¹¥È¤ÎÀèƬ"
+
+msgid "E663: At end of changelist"
+msgstr "E663: Êѹ¹¥ê¥¹¥È¤ÎËöÈø"
+
+msgid "Type :qa! and press <Enter> to abandon all changes and exit Vim"
+msgstr ""
+"¤¹¤Ù¤Æ¤ÎÊѹ¹¤òÇË´þ¤·¡¢Vim¤ò½ªÎ»¤¹¤ë¤Ë¤Ï :qa! ¤ÈÆþÎϤ· <Enter> ¤ò²¡¤·¤Æ¤¯¤À"
+"¤µ¤¤"
+
+#, c-format
+msgid "%ld line %sed %d time"
+msgid_plural "%ld line %sed %d times"
+msgstr[0] "%ld ¹Ô¤¬ %s ¤Ç %d ²ó½èÍý¤µ¤ì¤Þ¤·¤¿"
+
+#, c-format
+msgid "%ld lines %sed %d time"
+msgid_plural "%ld lines %sed %d times"
+msgstr[0] "%ld ¹Ô¤¬ %s ¤Ç %d ²ó½èÍý¤µ¤ì¤Þ¤·¤¿"
+
+#, c-format
+msgid "%ld lines to indent... "
+msgstr "%ld ¹Ô¤¬¥¤¥ó¥Ç¥ó¥È¤µ¤ì¤Þ¤¹... "
+
+#, c-format
+msgid "%ld line indented "
+msgid_plural "%ld lines indented "
+msgstr[0] "%ld ¹Ô¤ò¥¤¥ó¥Ç¥ó¥È¤·¤Þ¤·¤¿ "
+
+msgid "E748: No previously used register"
+msgstr "E748: ¤Þ¤À¥ì¥¸¥¹¥¿¤ò»ÈÍѤ·¤Æ¤¤¤Þ¤»¤ó"
+
+msgid "cannot yank; delete anyway"
+msgstr "¥ä¥ó¥¯¤Ç¤­¤Þ¤»¤ó; ¤È¤Ë¤«¤¯¾Ãµî"
+
+#, c-format
+msgid "%ld line changed"
+msgid_plural "%ld lines changed"
+msgstr[0] "%ld ¹Ô¤¬Êѹ¹¤µ¤ì¤Þ¤·¤¿"
+
+#, c-format
+msgid "freeing %ld lines"
+msgstr "%ld ¹Ô¤ò²òÊüÃæ"
+
+#, c-format
+msgid " into \"%c"
+msgstr " \"%c ¤Ë"
+
+#, c-format
+msgid "block of %ld line yanked%s"
+msgid_plural "block of %ld lines yanked%s"
+msgstr[0] "%ld ¹Ô¤Î¥Ö¥í¥Ã¥¯¤¬%s¥ä¥ó¥¯¤µ¤ì¤Þ¤·¤¿"
+
+#, c-format
+msgid "%ld line yanked%s"
+msgid_plural "%ld lines yanked%s"
+msgstr[0] "%ld ¹Ô¤¬%s¥ä¥ó¥¯¤µ¤ì¤Þ¤·¤¿"
+
+#, c-format
+msgid "E353: Nothing in register %s"
+msgstr "E353: ¥ì¥¸¥¹¥¿ %s ¤Ë¤Ï²¿¤â¤¢¤ê¤Þ¤»¤ó"
+
+msgid ""
+"\n"
+"--- Registers ---"
+msgstr ""
+"\n"
+"--- ¥ì¥¸¥¹¥¿ ---"
+
+msgid "Illegal register name"
+msgstr "ÉÔÀµ¤Ê¥ì¥¸¥¹¥¿Ì¾"
+
+msgid ""
+"\n"
+"# Registers:\n"
+msgstr ""
+"\n"
+"# ¥ì¥¸¥¹¥¿:\n"
+
+#, c-format
+msgid "E574: Unknown register type %d"
+msgstr "E574: ̤ÃΤΥ쥸¥¹¥¿·¿ %d ¤Ç¤¹"
+
+msgid ""
+"E883: search pattern and expression register may not contain two or more "
+"lines"
+msgstr "E883: ¸¡º÷¥Ñ¥¿¡¼¥ó¤È¼°¥ì¥¸¥¹¥¿¤Ë¤Ï2¹Ô°Ê¾å¤ò´Þ¤á¤é¤ì¤Þ¤»¤ó"
+
+#, c-format
+msgid "%ld Cols; "
+msgstr "%ld Îó; "
+
+#, c-format
+msgid "Selected %s%ld of %ld Lines; %lld of %lld Words; %lld of %lld Bytes"
+msgstr "ÁªÂò %s%ld / %ld ¹Ô; %lld / %lld ñ¸ì; %lld / %lld ¥Ð¥¤¥È"
+
+#, c-format
+msgid ""
+"Selected %s%ld of %ld Lines; %lld of %lld Words; %lld of %lld Chars; %lld of "
+"%lld Bytes"
+msgstr ""
+"ÁªÂò %s%ld / %ld ¹Ô; %lld / %lld ñ¸ì; %lld / %lld ʸ»ú; %lld / %lld ¥Ð¥¤¥È"
+
+#, c-format
+msgid "Col %s of %s; Line %ld of %ld; Word %lld of %lld; Byte %lld of %lld"
+msgstr "Îó %s / %s; ¹Ô %ld of %ld; ñ¸ì %lld / %lld; ¥Ð¥¤¥È %lld / %lld"
+
+#, c-format
+msgid ""
+"Col %s of %s; Line %ld of %ld; Word %lld of %lld; Char %lld of %lld; Byte "
+"%lld of %lld"
+msgstr ""
+"Îó %s / %s; ¹Ô %ld / %ld; ñ¸ì %lld / %lld; ʸ»ú %lld / %lld; ¥Ð¥¤¥È %lld of "
+"%lld"
+
+#, c-format
+msgid "(+%lld for BOM)"
+msgstr "(+%lld for BOM)"
+
+msgid "Thanks for flying Vim"
+msgstr "Vim ¤ò»È¤Ã¤Æ¤¯¤ì¤Æ¤¢¤ê¤¬¤È¤¦"
+
+msgid "E518: Unknown option"
+msgstr "E518: ̤ÃΤΥª¥×¥·¥ç¥ó¤Ç¤¹"
+
+msgid "E519: Option not supported"
+msgstr "E519: ¥ª¥×¥·¥ç¥ó¤Ï¥µ¥Ý¡¼¥È¤µ¤ì¤Æ¤¤¤Þ¤»¤ó"
+
+msgid "E520: Not allowed in a modeline"
+msgstr "E520: modeline ¤Ç¤Ïµö²Ä¤µ¤ì¤Þ¤»¤ó"
+
+msgid "E846: Key code not set"
+msgstr "E846: ¥­¡¼¥³¡¼¥É¤¬ÀßÄꤵ¤ì¤Æ¤¤¤Þ¤»¤ó"
+
+msgid "E521: Number required after ="
+msgstr "E521: = ¤Î¸å¤Ë¤Ï¿ô»ú¤¬É¬ÍפǤ¹"
+
+msgid "E522: Not found in termcap"
+msgstr "E522: termcap Æâ¤Ë¸«¤Ä¤«¤ê¤Þ¤»¤ó"
+
+#, c-format
+msgid "E539: Illegal character <%s>"
+msgstr "E539: ÉÔÀµ¤Êʸ»ú¤Ç¤¹ <%s>"
+
+#, c-format
+msgid "For option %s"
+msgstr "¥ª¥×¥·¥ç¥ó: %s"
+
+msgid "E529: Cannot set 'term' to empty string"
+msgstr "E529: 'term' ¤Ë¤Ï¶õʸ»úÎó¤òÀßÄê¤Ç¤­¤Þ¤»¤ó"
+
+msgid "E530: Cannot change term in GUI"
+msgstr "E530: GUI¤Ç¤Ï 'term' ¤òÊѹ¹¤Ç¤­¤Þ¤»¤ó"
+
+msgid "E531: Use \":gui\" to start the GUI"
+msgstr "E531: GUI¤ò¥¹¥¿¡¼¥È¤¹¤ë¤Ë¤Ï \":gui\" ¤ò»ÈÍѤ·¤Æ¤¯¤À¤µ¤¤"
+
+msgid "E589: 'backupext' and 'patchmode' are equal"
+msgstr "E589: 'backupext' ¤È 'patchmode' ¤¬Æ±¤¸¤Ç¤¹"
+
+msgid "E834: Conflicts with value of 'listchars'"
+msgstr "E834: 'listchars'¤ÎÃͤËÌ·½â¤¬¤¢¤ê¤Þ¤¹"
+
+msgid "E835: Conflicts with value of 'fillchars'"
+msgstr "E835: 'fillchars'¤ÎÃͤËÌ·½â¤¬¤¢¤ê¤Þ¤¹"
+
+msgid "E617: Cannot be changed in the GTK+ 2 GUI"
+msgstr "E617: GTK+2 GUI¤Ç¤ÏÊѹ¹¤Ç¤­¤Þ¤»¤ó"
+
+#, c-format
+msgid "E950: Cannot convert between %s and %s"
+msgstr "E950: %s ¤È %s ¤Î´Ö¤ÇÊÑ´¹¤Ç¤­¤Þ¤»¤ó"
+
+msgid "E524: Missing colon"
+msgstr "E524: ¥³¥í¥ó¤¬¤¢¤ê¤Þ¤»¤ó"
+
+msgid "E525: Zero length string"
+msgstr "E525: ʸ»úÎó¤ÎŤµ¤¬¥¼¥í¤Ç¤¹"
+
+#, c-format
+msgid "E526: Missing number after <%s>"
+msgstr "E526: <%s> ¤Î¸å¤Ë¿ô»ú¤¬¤¢¤ê¤Þ¤»¤ó"
+
+msgid "E527: Missing comma"
+msgstr "E527: ¥«¥ó¥Þ¤¬¤¢¤ê¤Þ¤»¤ó"
+
+msgid "E528: Must specify a ' value"
+msgstr "E528: ' ¤ÎÃͤò»ØÄꤷ¤Ê¤±¤ì¤Ð¤Ê¤ê¤Þ¤»¤ó"
+
+msgid "E595: contains unprintable or wide character"
+msgstr "E595: ɽ¼¨¤Ç¤­¤Ê¤¤Ê¸»ú¤«¥ï¥¤¥Éʸ»ú¤ò´Þ¤ó¤Ç¤¤¤Þ¤¹"
+
+msgid "E596: Invalid font(s)"
+msgstr "E596: ̵¸ú¤Ê¥Õ¥©¥ó¥È¤Ç¤¹"
+
+msgid "E597: can't select fontset"
+msgstr "E597: ¥Õ¥©¥ó¥È¥»¥Ã¥È¤òÁªÂò¤Ç¤­¤Þ¤»¤ó"
+
+msgid "E598: Invalid fontset"
+msgstr "E598: ̵¸ú¤Ê¥Õ¥©¥ó¥È¥»¥Ã¥È¤Ç¤¹"
+
+msgid "E533: can't select wide font"
+msgstr "E533: ¥ï¥¤¥É¥Õ¥©¥ó¥È¤òÁªÂò¤Ç¤­¤Þ¤»¤ó"
+
+msgid "E534: Invalid wide font"
+msgstr "E534: ̵¸ú¤Ê¥ï¥¤¥É¥Õ¥©¥ó¥È¤Ç¤¹"
+
+#, c-format
+msgid "E535: Illegal character after <%c>"
+msgstr "E535: <%c> ¤Î¸å¤ËÉÔÀµ¤Êʸ»ú¤¬¤¢¤ê¤Þ¤¹"
+
+msgid "E536: comma required"
+msgstr "E536: ¥«¥ó¥Þ¤¬É¬ÍפǤ¹"
+
+#, c-format
+msgid "E537: 'commentstring' must be empty or contain %s"
+msgstr "E537: 'commentstring' ¤Ï¶õ¤Ç¤¢¤ë¤« %s ¤ò´Þ¤àɬÍפ¬¤¢¤ê¤Þ¤¹"
+
+msgid "E538: No mouse support"
+msgstr "E538: ¥Þ¥¦¥¹¤Ï¥µ¥Ý¡¼¥È¤µ¤ì¤Þ¤»¤ó"
+
+msgid "E540: Unclosed expression sequence"
+msgstr "E540: ¼°¤¬½ªÎ»¤·¤Æ¤¤¤Þ¤»¤ó"
+
+msgid "E541: too many items"
+msgstr "E541: Í×ÁǤ¬Â¿²á¤®¤Þ¤¹"
+
+msgid "E542: unbalanced groups"
+msgstr "E542: ¥°¥ë¡¼¥×¤¬Äà¹ç¤¤¤Þ¤»¤ó"
+
+msgid "E946: Cannot make a terminal with running job modifiable"
+msgstr "E946: ¼Â¹ÔÃæ¤Î¥¸¥ç¥Ö¤¬¤¢¤ëüËö¤ÏÊѹ¹²Äǽ¤Ë¤Ç¤­¤Þ¤»¤ó"
+
+msgid "E590: A preview window already exists"
+msgstr "E590: ¥×¥ì¥Ó¥å¡¼¥¦¥£¥ó¥É¥¦¤¬´û¤Ë¸ºß¤·¤Þ¤¹"
+
+msgid "W17: Arabic requires UTF-8, do ':set encoding=utf-8'"
+msgstr ""
+"W17: ¥¢¥é¥Ó¥¢Ê¸»ú¤Ë¤ÏUTF-8¤¬É¬ÍפʤΤǡ¢':set encoding=utf-8' ¤·¤Æ¤¯¤À¤µ¤¤"
+
+msgid "E954: 24-bit colors are not supported on this environment"
+msgstr "E954: 24bit¿§¤Ï¤³¤Î´Ä¶­¤Ç¤Ï¥µ¥Ý¡¼¥È¤µ¤ì¤Æ¤¤¤Þ¤»¤ó"
+
+#, c-format
+msgid "E593: Need at least %d lines"
+msgstr "E593: ºÇÄã %d ¤Î¹Ô¿ô¤¬É¬ÍפǤ¹"
+
+#, c-format
+msgid "E594: Need at least %d columns"
+msgstr "E594: ºÇÄã %d ¤Î¥«¥é¥àÉý¤¬É¬ÍפǤ¹"
+
+#, c-format
+msgid "E355: Unknown option: %s"
+msgstr "E355: ̤ÃΤΥª¥×¥·¥ç¥ó¤Ç¤¹: %s"
+
+#, c-format
+msgid "E521: Number required: &%s = '%s'"
+msgstr "E521: ¿ô»ú¤¬É¬ÍפǤ¹: &%s = '%s'"
+
+msgid ""
+"\n"
+"--- Terminal codes ---"
+msgstr ""
+"\n"
+"--- üËö¥³¡¼¥É ---"
+
+msgid ""
+"\n"
+"--- Global option values ---"
+msgstr ""
+"\n"
+"--- ¥°¥í¡¼¥Ð¥ë¥ª¥×¥·¥ç¥óÃÍ ---"
+
+msgid ""
+"\n"
+"--- Local option values ---"
+msgstr ""
+"\n"
+"--- ¥í¡¼¥«¥ë¥ª¥×¥·¥ç¥óÃÍ ---"
+
+msgid ""
+"\n"
+"--- Options ---"
+msgstr ""
+"\n"
+"--- ¥ª¥×¥·¥ç¥ó ---"
+
+msgid "E356: get_varp ERROR"
+msgstr "E356: get_varp ¥¨¥é¡¼"
+
+#, c-format
+msgid "E357: 'langmap': Matching character missing for %s"
+msgstr "E357: 'langmap': %s ¤ËÂбþ¤¹¤ëʸ»ú¤¬¤¢¤ê¤Þ¤»¤ó"
+
+#, c-format
+msgid "E358: 'langmap': Extra characters after semicolon: %s"
+msgstr "E358: 'langmap': ¥»¥ß¥³¥í¥ó¤Î¸å¤Ë;ʬ¤Êʸ»ú¤¬¤¢¤ê¤Þ¤¹: %s"
+
+msgid "cannot open "
+msgstr "³«¤±¤Þ¤»¤ó "
+
+msgid "VIM: Can't open window!\n"
+msgstr "VIM: ¥¦¥£¥ó¥É¥¦¤ò³«¤±¤Þ¤»¤ó!\n"
+
+msgid "Need Amigados version 2.04 or later\n"
+msgstr "Amigados¤Î¥Ð¡¼¥¸¥ç¥ó 2.04¤«¤½¤ì°Ê¹ß¤¬É¬ÍפǤ¹\n"
+
+#, c-format
+msgid "Need %s version %ld\n"
+msgstr "%s ¤Î¥Ð¡¼¥¸¥ç¥ó %ld ¤¬É¬ÍפǤ¹\n"
+
+msgid "Cannot open NIL:\n"
+msgstr "NIL¤ò³«¤±¤Þ¤»¤ó:\n"
+
+msgid "Cannot create "
+msgstr "ºîÀ®¤Ç¤­¤Þ¤»¤ó "
+
+#, c-format
+msgid "Vim exiting with %d\n"
+msgstr "Vim¤Ï %d ¤Ç½ªÎ»¤·¤Þ¤¹\n"
+
+msgid "cannot change console mode ?!\n"
+msgstr "¥³¥ó¥½¡¼¥ë¥â¡¼¥É¤òÊѹ¹¤Ç¤­¤Þ¤»¤ó?!\n"
+
+msgid "mch_get_shellsize: not a console??\n"
+msgstr "mch_get_shellsize: ¥³¥ó¥½¡¼¥ë¤Ç¤Ï¤Ê¤¤??\n"
+
+msgid "E360: Cannot execute shell with -f option"
+msgstr "E360: -f ¥ª¥×¥·¥ç¥ó¤Ç¥·¥§¥ë¤ò¼Â¹Ô¤Ç¤­¤Þ¤»¤ó"
+
+msgid "Cannot execute "
+msgstr "¼Â¹Ô¤Ç¤­¤Þ¤»¤ó "
+
+msgid "shell "
+msgstr "¥·¥§¥ë "
+
+msgid " returned\n"
+msgstr " Ìá¤ê¤Þ¤·¤¿\n"
+
+msgid "ANCHOR_BUF_SIZE too small."
+msgstr "ANCHOR_BUF_SIZE ¤¬¾®¤µ²á¤®¤Þ¤¹."
+
+msgid "I/O ERROR"
+msgstr "Æþ½ÐÎÏ¥¨¥é¡¼"
+
+msgid "Message"
+msgstr "¥á¥Ã¥»¡¼¥¸"
+
+msgid "E237: Printer selection failed"
+msgstr "E237: ¥×¥ê¥ó¥¿¤ÎÁªÂò¤Ë¼ºÇÔ¤·¤Þ¤·¤¿"
+
+#, c-format
+msgid "to %s on %s"
+msgstr "%s ¤Ø (%s ¾å¤Î)"
+
+#, c-format
+msgid "E613: Unknown printer font: %s"
+msgstr "E613: ̤ÃΤΥץê¥ó¥¿¥ª¥×¥·¥ç¥ó¤Ç¤¹: %s"
+
+#, c-format
+msgid "E238: Print error: %s"
+msgstr "E238: °õºþ¥¨¥é¡¼: %s"
+
+#, c-format
+msgid "Printing '%s'"
+msgstr "°õºþ¤·¤Æ¤¤¤Þ¤¹: '%s'"
+
+#, c-format
+msgid "E244: Illegal charset name \"%s\" in font name \"%s\""
+msgstr "E244: ʸ»ú¥»¥Ã¥È̾ \"%s\" ¤ÏÉÔÀµ¤Ç¤¹ (¥Õ¥©¥ó¥È̾ \"%s\")"
+
+#, c-format
+msgid "E244: Illegal quality name \"%s\" in font name \"%s\""
+msgstr "E244: ÉʼÁ̾ \"%s\" ¤ÏÉÔÀµ¤Ç¤¹ (¥Õ¥©¥ó¥È̾ \"%s\")"
+
+#, c-format
+msgid "E245: Illegal char '%c' in font name \"%s\""
+msgstr "E245: '%c' ¤ÏÉÔÀµ¤Êʸ»ú¤Ç¤¹ (¥Õ¥©¥ó¥È̾ \"%s\")"
+
+#, c-format
+msgid "Opening the X display took %ld msec"
+msgstr "X¥µ¡¼¥Ð¡¼¤Ø¤ÎÀܳ¤Ë %ld ¥ß¥êÉ䫤«¤ê¤Þ¤·¤¿"
+
+msgid ""
+"\n"
+"Vim: Got X error\n"
+msgstr ""
+"\n"
+"Vim: X ¤Î¥¨¥é¡¼¤ò¸¡½Ð¤·¤Þ¤·¤¿r\n"
+
+msgid "Testing the X display failed"
+msgstr "X display ¤Î¥Á¥§¥Ã¥¯¤Ë¼ºÇÔ¤·¤Þ¤·¤¿"
+
+msgid "Opening the X display timed out"
+msgstr "X display ¤Î open ¤¬¥¿¥¤¥à¥¢¥¦¥È¤·¤Þ¤·¤¿"
+
+msgid ""
+"\n"
+"Could not get security context for "
+msgstr ""
+"\n"
+"¥»¥­¥å¥ê¥Æ¥£¥³¥ó¥Æ¥­¥¹¥È¤ò¼èÆÀ¤Ç¤­¤Þ¤»¤ó "
+
+msgid ""
+"\n"
+"Could not set security context for "
+msgstr ""
+"\n"
+"¥»¥­¥å¥ê¥Æ¥£¥³¥ó¥Æ¥­¥¹¥È¤òÀßÄê¤Ç¤­¤Þ¤»¤ó "
+
+#, c-format
+msgid "Could not set security context %s for %s"
+msgstr "¥»¥­¥å¥ê¥Æ¥£¥³¥ó¥Æ¥­¥¹¥È %s ¤ò %s ¤ËÀßÄê¤Ç¤­¤Þ¤»¤ó"
+
+#, c-format
+msgid "Could not get security context %s for %s. Removing it!"
+msgstr "¥»¥­¥å¥ê¥Æ¥£¥³¥ó¥Æ¥­¥¹¥È %s ¤ò %s ¤«¤é¼èÆÀ¤Ç¤­¤Þ¤»¤ó. ºï½ü¤·¤Þ¤¹!"
+
+msgid ""
+"\n"
+"Cannot execute shell sh\n"
+msgstr ""
+"\n"
+"sh ¥·¥§¥ë¤ò¼Â¹Ô¤Ç¤­¤Þ¤»¤ó\n"
+
+msgid ""
+"\n"
+"shell returned "
+msgstr ""
+"\n"
+"¥·¥§¥ë¤¬ÃͤòÊÖ¤·¤Þ¤·¤¿ "
+
+msgid ""
+"\n"
+"Cannot create pipes\n"
+msgstr ""
+"\n"
+"¥Ñ¥¤¥×¤òºîÀ®¤Ç¤­¤Þ¤»¤ó\n"
+
+msgid ""
+"\n"
+"Cannot fork\n"
+msgstr ""
+"\n"
+"fork ¤Ç¤­¤Þ¤»¤ó\n"
+
+msgid ""
+"\n"
+"Cannot execute shell "
+msgstr ""
+"\n"
+"¥·¥§¥ë¤ò¼Â¹Ô¤Ç¤­¤Þ¤»¤ó "
+
+msgid ""
+"\n"
+"Command terminated\n"
+msgstr ""
+"\n"
+"¥³¥Þ¥ó¥É¤òÃæÃǤ·¤Þ¤·¤¿\n"
+
+msgid "XSMP lost ICE connection"
+msgstr "XSMP ¤¬ICEÀܳ¤ò¼º¤¤¤Þ¤·¤¿"
+
+#, c-format
+msgid "dlerror = \"%s\""
+msgstr "dlerror = \"%s\""
+
+msgid "Opening the X display failed"
+msgstr "X display ¤Î open ¤Ë¼ºÇÔ¤·¤Þ¤·¤¿"
+
+msgid "XSMP handling save-yourself request"
+msgstr "XSMP ¤¬save-yourselfÍ×µá¤ò½èÍý¤·¤Æ¤¤¤Þ¤¹"
+
+msgid "XSMP opening connection"
+msgstr "XSMP ¤¬Àܳ¤ò³«»Ï¤·¤Æ¤¤¤Þ¤¹"
+
+msgid "XSMP ICE connection watch failed"
+msgstr "XSMP ICEÀܳ¤¬¼ºÇÔ¤·¤¿¤è¤¦¤Ç¤¹"
+
+#, c-format
+msgid "XSMP SmcOpenConnection failed: %s"
+msgstr "XSMP SmcOpenConnection¤¬¼ºÇÔ¤·¤Þ¤·¤¿: %s"
+
+msgid "At line"
+msgstr "¹Ô"
+
+msgid "Could not load vim32.dll!"
+msgstr "vim32.dll ¤ò¥í¡¼¥É¤Ç¤­¤Þ¤»¤ó¤Ç¤·¤¿"
+
+msgid "VIM Error"
+msgstr "VIM¥¨¥é¡¼"
+
+msgid "Could not fix up function pointers to the DLL!"
+msgstr "DLL¤«¤é´Ø¿ô¥Ý¥¤¥ó¥¿¤ò¼èÆÀ¤Ç¤­¤Þ¤»¤ó¤Ç¤·¤¿"
+
+#, c-format
+msgid "Vim: Caught %s event\n"
+msgstr "Vim: ¥¤¥Ù¥ó¥È %s ¤ò¸¡ÃÎ\n"
+
+msgid "close"
+msgstr "ÊĤ¸¤ë"
+
+msgid "logoff"
+msgstr "¥í¥°¥ª¥Õ"
+
+msgid "shutdown"
+msgstr "¥·¥ã¥Ã¥È¥À¥¦¥ó"
+
+msgid "E371: Command not found"
+msgstr "E371: ¥³¥Þ¥ó¥É¤¬¤¢¤ê¤Þ¤»¤ó"
+
+msgid ""
+"VIMRUN.EXE not found in your $PATH.\n"
+"External commands will not pause after completion.\n"
+"See :help win32-vimrun for more information."
+msgstr ""
+"VIMRUN.EXE¤¬ $PATH ¤ÎÃæ¤Ë¸«¤Ä¤«¤ê¤Þ¤»¤ó.\n"
+"³°Éô¥³¥Þ¥ó¥É¤Î½ªÎ»¸å¤Ë°ì»þÄä»ß¤ò¤·¤Þ¤»¤ó.\n"
+"¾ÜºÙ¤Ï :help win32-vimrun ¤ò»²¾È¤·¤Æ¤¯¤À¤µ¤¤."
+
+msgid "Vim Warning"
+msgstr "Vim¤Î·Ù¹ð"
+
+#, c-format
+msgid "shell returned %d"
+msgstr "¥·¥§¥ë¤¬¥³¡¼¥É %d ¤Ç½ªÎ»¤·¤Þ¤·¤¿"
+
+msgid "E926: Current location list was changed"
+msgstr "E926: ¸½ºß¤Î¥í¥±¡¼¥·¥ç¥ó¥ê¥¹¥È¤¬Êѹ¹¤µ¤ì¤Þ¤·¤¿"
+
+#, c-format
+msgid "E372: Too many %%%c in format string"
+msgstr "E372: ¥Õ¥©¡¼¥Þ¥Ã¥Èʸ»úÎó¤Ë %%%c ¤¬Â¿²á¤®¤Þ¤¹"
+
+#, c-format
+msgid "E373: Unexpected %%%c in format string"
+msgstr "E373: ¥Õ¥©¡¼¥Þ¥Ã¥Èʸ»úÎó¤Ëͽ´ü¤»¤Ì %%%c ¤¬¤¢¤ê¤Þ¤·¤¿"
+
+msgid "E374: Missing ] in format string"
+msgstr "E374: ¥Õ¥©¡¼¥Þ¥Ã¥Èʸ»úÎó¤Ë ] ¤¬¤¢¤ê¤Þ¤»¤ó"
+
+#, c-format
+msgid "E375: Unsupported %%%c in format string"
+msgstr "E375: ¥Õ¥©¡¼¥Þ¥Ã¥Èʸ»úÎó¤Ç¤Ï %%%c ¤Ï¥µ¥Ý¡¼¥È¤µ¤ì¤Þ¤»¤ó"
+
+#, c-format
+msgid "E376: Invalid %%%c in format string prefix"
+msgstr "E376: ¥Õ¥©¡¼¥Þ¥Ã¥Èʸ»úÎó¤ÎÁ°ÃÖ¤Ë̵¸ú¤Ê %%%c ¤¬¤¢¤ê¤Þ¤¹"
+
+#, c-format
+msgid "E377: Invalid %%%c in format string"
+msgstr "E377: ¥Õ¥©¡¼¥Þ¥Ã¥Èʸ»úÎó¤Ë̵¸ú¤Ê %%%c ¤¬¤¢¤ê¤Þ¤¹"
+
+msgid "E378: 'errorformat' contains no pattern"
+msgstr "E378: 'errorformat' ¤Ë¥Ñ¥¿¡¼¥ó¤¬»ØÄꤵ¤ì¤Æ¤¤¤Þ¤»¤ó"
+
+msgid "E379: Missing or empty directory name"
+msgstr "E379: ¥Ç¥£¥ì¥¯¥È¥ê̾¤¬Ìµ¤¤¤«¶õ¤Ç¤¹"
+
+msgid "E553: No more items"
+msgstr "E553: Í×ÁǤ¬¤â¤¦¤¢¤ê¤Þ¤»¤ó"
+
+msgid "E924: Current window was closed"
+msgstr "E924: ¸½ºß¤Î¥¦¥£¥ó¥É¥¦¤¬ÊĤ¸¤é¤ì¤Þ¤·¤¿"
+
+msgid "E925: Current quickfix was changed"
+msgstr "E925: ¸½ºß¤Î quickfix ¤¬Êѹ¹¤µ¤ì¤Þ¤·¤¿"
+
+#, c-format
+msgid "(%d of %d)%s%s: "
+msgstr "(%d of %d)%s%s: "
+
+msgid " (line deleted)"
+msgstr " (¹Ô¤¬ºï½ü¤µ¤ì¤Þ¤·¤¿)"
+
+#, c-format
+msgid "%serror list %d of %d; %d errors "
+msgstr "%s ¥¨¥é¡¼°ìÍ÷ %d of %d; %d ¸Ä¥¨¥é¡¼"
+
+msgid "E380: At bottom of quickfix stack"
+msgstr "E380: quickfix ¥¹¥¿¥Ã¥¯¤ÎËöÈø¤Ç¤¹"
+
+msgid "E381: At top of quickfix stack"
+msgstr "E381: quickfix ¥¹¥¿¥Ã¥¯¤ÎÀèƬ¤Ç¤¹"
+
+msgid "No entries"
+msgstr "¥¨¥ó¥È¥ê¤¬¤¢¤ê¤Þ¤»¤ó"
+
+msgid "Error file"
+msgstr "¥¨¥é¡¼¥Õ¥¡¥¤¥ë"
+
+msgid "E683: File name missing or invalid pattern"
+msgstr "E683: ¥Õ¥¡¥¤¥ë̾¤¬Ìµ¤¤¤«Ìµ¸ú¤Ê¥Ñ¥¿¡¼¥ó¤Ç¤¹"
+
+#, c-format
+msgid "Cannot open file \"%s\""
+msgstr "¥Õ¥¡¥¤¥ë \"%s\" ¤ò³«¤±¤Þ¤»¤ó"
+
+msgid "E681: Buffer is not loaded"
+msgstr "E681: ¥Ð¥Ã¥Õ¥¡¤ÏÆɤ߹þ¤Þ¤ì¤Þ¤»¤ó¤Ç¤·¤¿"
+
+msgid "E777: String or List expected"
+msgstr "E777: ʸ»úÎ󤫥ꥹ¥È¤¬É¬ÍפǤ¹"
+
+#, c-format
+msgid "E369: invalid item in %s%%[]"
+msgstr "E369: ̵¸ú¤Ê¹àÌܤǤ¹: %s%%[]"
+
+#, c-format
+msgid "E769: Missing ] after %s["
+msgstr "E769: %s[ ¤Î¸å¤Ë ] ¤¬¤¢¤ê¤Þ¤»¤ó"
+
+msgid "E944: Reverse range in character class"
+msgstr "E944: ʸ»ú¥¯¥é¥¹¤ÎÈϰϤ¬µÕ¤Ç¤¹"
+
+msgid "E945: Range too large in character class"
+msgstr "E945: ʸ»ú¥¯¥é¥¹¤ÎÈϰϤ¬Â礭¤¹¤®¤Þ¤¹"
+
+#, c-format
+msgid "E53: Unmatched %s%%("
+msgstr "E53: %s%%( ¤¬Äà¤ê¹ç¤Ã¤Æ¤¤¤Þ¤»¤ó"
+
+#, c-format
+msgid "E54: Unmatched %s("
+msgstr "E54: %s( ¤¬Äà¤ê¹ç¤Ã¤Æ¤¤¤Þ¤»¤ó"
+
+#, c-format
+msgid "E55: Unmatched %s)"
+msgstr "E55: %s) ¤¬Äà¤ê¹ç¤Ã¤Æ¤¤¤Þ¤»¤ó"
+
+msgid "E66: \\z( not allowed here"
+msgstr "E66: \\z( ¤Ï¥³¥³¤Ç¤Ïµö²Ä¤µ¤ì¤Æ¤¤¤Þ¤»¤ó"
+
+msgid "E67: \\z1 - \\z9 not allowed here"
+msgstr "E67: \\z1 - \\z9 ¤Ï¥³¥³¤Ç¤Ïµö²Ä¤µ¤ì¤Æ¤¤¤Þ¤»¤ó"
+
+#, c-format
+msgid "E69: Missing ] after %s%%["
+msgstr "E69: %s%%[ ¤Î¸å¤Ë ] ¤¬¤¢¤ê¤Þ¤»¤ó"
+
+#, c-format
+msgid "E70: Empty %s%%[]"
+msgstr "E70: %s%%[] ¤¬¶õ¤Ç¤¹"
+
+msgid "E956: Cannot use pattern recursively"
+msgstr "E956: ¥Ñ¥¿¡¼¥ó¤òºÆµ¢Åª¤Ë»È¤¦¤³¤È¤Ï¤Ç¤­¤Þ¤»¤ó"
+
+msgid "E65: Illegal back reference"
+msgstr "E65: ÉÔÀµ¤Ê¸åÊý»²¾È¤Ç¤¹"
+
+msgid "E339: Pattern too long"
+msgstr "E339: ¥Ñ¥¿¡¼¥ó¤¬Ä¹²á¤®¤Þ¤¹"
+
+msgid "E50: Too many \\z("
+msgstr "E50: \\z( ¤¬Â¿²á¤®¤Þ¤¹"
+
+#, c-format
+msgid "E51: Too many %s("
+msgstr "E51: %s( ¤¬Â¿²á¤®¤Þ¤¹"
+
+msgid "E52: Unmatched \\z("
+msgstr "E52: \\z( ¤¬Äà¤ê¹ç¤Ã¤Æ¤¤¤Þ¤»¤ó"
+
+#, c-format
+msgid "E59: invalid character after %s@"
+msgstr "E59: %s@ ¤Î¸å¤ËÉÔÀµ¤Êʸ»ú¤¬¤¢¤ê¤Þ¤·¤¿"
+
+#, c-format
+msgid "E60: Too many complex %s{...}s"
+msgstr "E60: Ê£»¨¤Ê %s{...} ¤¬Â¿²á¤®¤Þ¤¹"
+
+#, c-format
+msgid "E61: Nested %s*"
+msgstr "E61:%s* ¤¬Æþ¤ì»Ò¤Ë¤Ê¤Ã¤Æ¤¤¤Þ¤¹"
+
+#, c-format
+msgid "E62: Nested %s%c"
+msgstr "E62:%s%c ¤¬Æþ¤ì»Ò¤Ë¤Ê¤Ã¤Æ¤¤¤Þ¤¹"
+
+msgid "E63: invalid use of \\_"
+msgstr "E63: \\_ ¤Î̵¸ú¤Ê»ÈÍÑÊýË¡¤Ç¤¹"
+
+#, c-format
+msgid "E64: %s%c follows nothing"
+msgstr "E64:%s%c ¤Î¸å¤Ë¤Ê¤Ë¤â¤¢¤ê¤Þ¤»¤ó"
+
+msgid "E68: Invalid character after \\z"
+msgstr "E68: \\z ¤Î¸å¤ËÉÔÀµ¤Êʸ»ú¤¬¤¢¤ê¤Þ¤·¤¿"
+
+#, c-format
+msgid "E678: Invalid character after %s%%[dxouU]"
+msgstr "E678: %s%%[dxouU] ¤Î¸å¤ËÉÔÀµ¤Êʸ»ú¤¬¤¢¤ê¤Þ¤·¤¿"
+
+#, c-format
+msgid "E71: Invalid character after %s%%"
+msgstr "E71: %s%% ¤Î¸å¤ËÉÔÀµ¤Êʸ»ú¤¬¤¢¤ê¤Þ¤·¤¿"
+
+#, c-format
+msgid "E554: Syntax error in %s{...}"
+msgstr "E554: %s{...} Æâ¤Ëʸˡ¥¨¥é¡¼¤¬¤¢¤ê¤Þ¤¹"
+
+msgid "External submatches:\n"
+msgstr "³°Éô¤ÎÉôʬ³ºÅö:\n"
+
+#, c-format
+msgid "E888: (NFA regexp) cannot repeat %s"
+msgstr "E888: (NFA Àµµ¬É½¸½) ·«¤êÊÖ¤»¤Þ¤»¤ó %s"
+
+msgid ""
+"E864: \\%#= can only be followed by 0, 1, or 2. The automatic engine will be "
+"used "
+msgstr ""
+"E864: \\%#= ¤Ë¤Ï 0, 1 ¤â¤·¤¯¤Ï 2 ¤Î¤ß¤¬Â³¤±¤é¤ì¤Þ¤¹¡£Àµµ¬É½¸½¥¨¥ó¥¸¥ó¤Ï¼«Æ°Áª"
+"Âò¤µ¤ì¤Þ¤¹¡£"
+
+msgid "Switching to backtracking RE engine for pattern: "
+msgstr "¼¡¤Î¥Ñ¥¿¡¼¥ó¤Ë¥Ð¥Ã¥¯¥È¥é¥Ã¥­¥ó¥° RE ¥¨¥ó¥¸¥ó¤òŬÍѤ·¤Þ¤¹: "
+
+msgid "E865: (NFA) Regexp end encountered prematurely"
+msgstr "E865: (NFA) ´üÂÔ¤è¤êÁ᤯Àµµ¬É½¸½¤Î½ªÃ¼¤ËÅþ㤷¤Þ¤·¤¿"
+
+#, c-format
+msgid "E866: (NFA regexp) Misplaced %c"
+msgstr "E866: (NFA Àµµ¬É½¸½) °ÌÃÖ¤¬¸í¤Ã¤Æ¤¤¤Þ¤¹: %c"
+
+#, c-format
+msgid "E877: (NFA regexp) Invalid character class: %ld"
+msgstr "E877: (NFA Àµµ¬É½¸½) ̵¸ú¤Êʸ»ú¥¯¥é¥¹: %ld"
+
+#, c-format
+msgid "E867: (NFA) Unknown operator '\\z%c'"
+msgstr "E867: (NFA) ̤ÃΤΥª¥Ú¥ì¡¼¥¿¤Ç¤¹: '\\z%c'"
+
+msgid "E951: \\% value too large"
+msgstr "E951: \\% Ãͤ¬Ä¹²á¤®¤Þ¤¹"
+
+#, c-format
+msgid "E867: (NFA) Unknown operator '\\%%%c'"
+msgstr "E867: (NFA) ̤ÃΤΥª¥Ú¥ì¡¼¥¿¤Ç¤¹: '\\%%%c'"
+
+msgid "E868: Error building NFA with equivalence class!"
+msgstr "E868: Åù²Á¥¯¥é¥¹¤ò´Þ¤àNFA¹½Ãۤ˼ºÇÔ¤·¤Þ¤·¤¿!"
+
+#, c-format
+msgid "E869: (NFA) Unknown operator '\\@%c'"
+msgstr "E869: (NFA) ̤ÃΤΥª¥Ú¥ì¡¼¥¿¤Ç¤¹: '\\@%c'"
+
+msgid "E870: (NFA regexp) Error reading repetition limits"
+msgstr "E870: (NFA Àµµ¬É½¸½) ·«¤êÊÖ¤·¤ÎÀ©¸Â²ó¿ô¤òÆɹþÃæ¤Ë¥¨¥é¡¼"
+
+msgid "E871: (NFA regexp) Can't have a multi follow a multi"
+msgstr "E871: (NFA Àµµ¬É½¸½) ·«¤êÊÖ¤· ¤Î¸å¤Ë ·«¤êÊÖ¤· ¤Ï¤Ç¤­¤Þ¤»¤ó"
+
+msgid "E872: (NFA regexp) Too many '('"
+msgstr "E872: (NFA Àµµ¬É½¸½) '(' ¤¬Â¿²á¤®¤Þ¤¹"
+
+msgid "E879: (NFA regexp) Too many \\z("
+msgstr "E879: (NFA Àµµ¬É½¸½) \\z( ¤¬Â¿²á¤®¤Þ¤¹"
+
+msgid "E873: (NFA regexp) proper termination error"
+msgstr "E873: (NFA Àµµ¬É½¸½) ½ªÃ¼µ­¹æ¤¬¤¢¤ê¤Þ¤»¤ó"
+
+msgid "Could not open temporary log file for writing, displaying on stderr... "
+msgstr ""
+"NFAÀµµ¬É½¸½¥¨¥ó¥¸¥óÍÑ¤Î¥í¥°¥Õ¥¡¥¤¥ë¤ò½ñ¹þÍѤȤ·¤Æ³«¤±¤Þ¤»¤ó¡£¥í¥°¤Ïɸ½à¥¨¥é¡¼"
+"½ÐÎϤ˽ÐÎϤ·¤Þ¤¹¡£"
+
+msgid "E874: (NFA) Could not pop the stack!"
+msgstr "E874: (NFA) ¥¹¥¿¥Ã¥¯¤ò¥Ý¥Ã¥×¤Ç¤­¤Þ¤»¤ó!"
+
+msgid ""
+"E875: (NFA regexp) (While converting from postfix to NFA), too many states "
+"left on stack"
+msgstr ""
+"E875: (NFA Àµµ¬É½¸½) (¸åÃÖʸ»úÎó¤òNFA¤ËÊÑ´¹Ãæ¤Ë) ¥¹¥¿¥Ã¥¯¤Ë»Ä¤µ¤ì¤¿¥¹¥Æ¡¼¥È¤¬"
+"¿²á¤®¤Þ¤¹"
+
+msgid "E876: (NFA regexp) Not enough space to store the whole NFA "
+msgstr "E876: (NFA Àµµ¬É½¸½) NFAÁ´ÂΤòÊݸ¤¹¤ë¤Ë¤Ï¶õ¤­¥¹¥Ú¡¼¥¹¤¬Â­¤ê¤Þ¤»¤ó"
+
+msgid "E878: (NFA) Could not allocate memory for branch traversal!"
+msgstr "E878: (NFA) ¸½ºß²£ÃÇÃæ¤Î¥Ö¥é¥ó¥Á¤Ë½½Ê¬¤Ê¥á¥â¥ê¤ò³ä¤êÅö¤Æ¤é¤ì¤Þ¤»¤ó!"
+
+msgid " VREPLACE"
+msgstr " ²¾ÁÛÃÖ´¹"
+
+msgid " REPLACE"
+msgstr " ÃÖ´¹"
+
+msgid " REVERSE"
+msgstr " ȿž"
+
+msgid " INSERT"
+msgstr " ÁÞÆþ"
+
+msgid " (insert)"
+msgstr " (ÁÞÆþ)"
+
+msgid " (replace)"
+msgstr " (ÃÖ´¹)"
+
+msgid " (vreplace)"
+msgstr " (²¾ÁÛÃÖ´¹)"
+
+msgid " Hebrew"
+msgstr " ¥Ø¥Ö¥é¥¤"
+
+msgid " Arabic"
+msgstr " ¥¢¥é¥Ó¥¢"
+
+msgid " (paste)"
+msgstr " (Ž¤êÉÕ¤±)"
+
+msgid " VISUAL"
+msgstr " ¥Ó¥¸¥å¥¢¥ë"
+
+msgid " VISUAL LINE"
+msgstr " ¥Ó¥¸¥å¥¢¥ë ¹Ô"
+
+msgid " VISUAL BLOCK"
+msgstr " ¥Ó¥¸¥å¥¢¥ë ¶ë·Á"
+
+msgid " SELECT"
+msgstr " ¥»¥ì¥¯¥È"
+
+msgid " SELECT LINE"
+msgstr " ¹Ô»Ø¸þÁªÂò"
+
+msgid " SELECT BLOCK"
+msgstr " ¶ë·ÁÁªÂò"
+
+msgid "recording"
+msgstr "µ­Ï¿Ãæ"
+
+#, c-format
+msgid "E383: Invalid search string: %s"
+msgstr "E383: ̵¸ú¤Ê¸¡º÷ʸ»úÎó¤Ç¤¹: %s"
+
+#, c-format
+msgid "E384: search hit TOP without match for: %s"
+msgstr "E384: ¾å¤Þ¤Ç¸¡º÷¤·¤Þ¤·¤¿¤¬³ºÅö²Õ½ê¤Ï¤¢¤ê¤Þ¤»¤ó: %s"
+
+#, c-format
+msgid "E385: search hit BOTTOM without match for: %s"
+msgstr "E385: ²¼¤Þ¤Ç¸¡º÷¤·¤Þ¤·¤¿¤¬³ºÅö²Õ½ê¤Ï¤¢¤ê¤Þ¤»¤ó: %s"
+
+msgid "E386: Expected '?' or '/' after ';'"
+msgstr "E386: ';' ¤Î¤¢¤È¤Ë¤Ï '?' ¤« '/' ¤¬´üÂÔ¤µ¤ì¤Æ¤¤¤ë"
+
+msgid " (includes previously listed match)"
+msgstr " (Á°¤ËÎóµó¤·¤¿³ºÅö²Õ½ê¤ò´Þ¤à)"
+
+msgid "--- Included files "
+msgstr "--- ¥¤¥ó¥¯¥ë¡¼¥É¤µ¤ì¤¿¥Õ¥¡¥¤¥ë "
+
+msgid "not found "
+msgstr "¸«¤Ä¤«¤ê¤Þ¤»¤ó "
+
+msgid "in path ---\n"
+msgstr "¥Ñ¥¹¤Ë ----\n"
+
+msgid " (Already listed)"
+msgstr " (´û¤ËÎóµó)"
+
+msgid " NOT FOUND"
+msgstr " ¸«¤Ä¤«¤ê¤Þ¤»¤ó"
+
+#, c-format
+msgid "Scanning included file: %s"
+msgstr "¥¤¥ó¥¯¥ë¡¼¥É¤µ¤ì¤¿¥Õ¥¡¥¤¥ë¤ò¥¹¥­¥ã¥óÃæ: %s"
+
+#, c-format
+msgid "Searching included file %s"
+msgstr "¥¤¥ó¥¯¥ë¡¼¥É¤µ¤ì¤¿¥Õ¥¡¥¤¥ë¤ò¸¡º÷Ãæ %s"
+
+msgid "E387: Match is on current line"
+msgstr "E387: ¸½ºß¹Ô¤Ë³ºÅö¤¬¤¢¤ê¤Þ¤¹"
+
+msgid "All included files were found"
+msgstr "Á´¤Æ¤Î¥¤¥ó¥¯¥ë¡¼¥É¤µ¤ì¤¿¥Õ¥¡¥¤¥ë¤¬¸«¤Ä¤«¤ê¤Þ¤·¤¿"
+
+msgid "No included files"
+msgstr "¥¤¥ó¥¯¥ë¡¼¥É¥Õ¥¡¥¤¥ë¤Ï¤¢¤ê¤Þ¤»¤ó"
+
+msgid "E388: Couldn't find definition"
+msgstr "E388: ÄêµÁ¤ò¸«¤Ä¤±¤é¤ì¤Þ¤»¤ó"
+
+msgid "E389: Couldn't find pattern"
+msgstr "E389: ¥Ñ¥¿¡¼¥ó¤ò¸«¤Ä¤±¤é¤ì¤Þ¤»¤ó"
+
+msgid "Substitute "
+msgstr "Substitute "
+
+#, c-format
+msgid ""
+"\n"
+"# Last %sSearch Pattern:\n"
+"~"
+msgstr ""
+"\n"
+"# ºÇ¸å¤Î %s¸¡º÷¥Ñ¥¿¡¼¥ó:\n"
+"~"
+
+msgid "E756: Spell checking is not enabled"
+msgstr "E756: ¥¹¥Ú¥ë¥Á¥§¥Ã¥¯¤Ï̵¸ú²½¤µ¤ì¤Æ¤¤¤Þ¤¹"
+
+#, c-format
+msgid "Warning: Cannot find word list \"%s_%s.spl\" or \"%s_ascii.spl\""
+msgstr ""
+"·Ù¹ð: ñ¸ì¥ê¥¹¥È \"%s_%s.spl\" ¤ª¤è¤Ó \"%s_ascii.spl\" ¤Ï¸«¤Ä¤«¤ê¤Þ¤»¤ó"
+
+#, c-format
+msgid "Warning: Cannot find word list \"%s.%s.spl\" or \"%s.ascii.spl\""
+msgstr ""
+"·Ù¹ð: ñ¸ì¥ê¥¹¥È \"%s.%s.spl\" ¤ª¤è¤Ó \"%s.ascii.spl\" ¤Ï¸«¤Ä¤«¤ê¤Þ¤»¤ó"
+
+msgid "E797: SpellFileMissing autocommand deleted buffer"
+msgstr "E797: autocommand ¤Î SpellFileMissing ¤¬¥Ð¥Ã¥Õ¥¡¤òºï½ü¤·¤Þ¤·¤¿"
+
+#, c-format
+msgid "Warning: region %s not supported"
+msgstr "·Ù¹ð9: %s ¤È¤¤¤¦ÈϰϤϥµ¥Ý¡¼¥È¤µ¤ì¤Æ¤¤¤Þ¤»¤ó"
+
+msgid "Sorry, no suggestions"
+msgstr "»ÄÇ°¤Ç¤¹¤¬¡¢½¤Àµ¸õÊä¤Ï¤¢¤ê¤Þ¤»¤ó"
+
+#, c-format
+msgid "Sorry, only %ld suggestions"
+msgstr "»ÄÇ°¤Ç¤¹¤¬¡¢½¤Àµ¸õÊä¤Ï %ld ¸Ä¤·¤«¤¢¤ê¤Þ¤»¤ó"
+
+#, c-format
+msgid "Change \"%.*s\" to:"
+msgstr "\"%.*s\" ¤ò¼¡¤ØÊÑ´¹:"
+
+#, c-format
+msgid " < \"%.*s\""
+msgstr " < \"%.*s\""
+
+msgid "E752: No previous spell replacement"
+msgstr "E752: ¥¹¥Ú¥ëÃÖ´¹¤¬¤Þ¤À¼Â¹Ô¤µ¤ì¤Æ¤¤¤Þ¤»¤ó"
+
+#, c-format
+msgid "E753: Not found: %s"
+msgstr "E753: ¸«¤Ä¤«¤ê¤Þ¤»¤ó: %s"
+
+msgid "E758: Truncated spell file"
+msgstr "E758: ¥¹¥Ú¥ë¥Õ¥¡¥¤¥ë¤¬ÀÚ¼è¤é¤ì¤Æ¤¤¤ë¤è¤¦¤Ç¤¹"
+
+#, c-format
+msgid "Trailing text in %s line %d: %s"
+msgstr "%s (%d ¹ÔÌÜ) ¤Ë³¤¯¥Æ¥­¥¹¥È: %s"
+
+#, c-format
+msgid "Affix name too long in %s line %d: %s"
+msgstr "%s (%d ¹ÔÌÜ) ¤Î affix ̾¤¬Ä¹²á¤®¤Þ¤¹: %s"
+
+msgid "E761: Format error in affix file FOL, LOW or UPP"
+msgstr ""
+"E761: affix¥Õ¥¡¥¤¥ë¤Î FOL, LOW ¤â¤·¤¯¤Ï UPP ¤Î¥Õ¥©¡¼¥Þ¥Ã¥È¤Ë¥¨¥é¡¼¤¬¤¢¤ê¤Þ¤¹"
+
+msgid "E762: Character in FOL, LOW or UPP is out of range"
+msgstr "E762: FOL, LOW ¤â¤·¤¯¤Ï UPP ¤Îʸ»ú¤¬Èϰϳ°¤Ç¤¹"
+
+msgid "Compressing word tree..."
+msgstr "ñ¸ì¥Ä¥ê¡¼¤ò°µ½Ì¤·¤Æ¤¤¤Þ¤¹..."
+
+#, c-format
+msgid "Reading spell file \"%s\""
+msgstr "¥¹¥Ú¥ë¥Õ¥¡¥¤¥ë \"%s\" ¤òÆɹþÃæ"
+
+msgid "E757: This does not look like a spell file"
+msgstr "E757: ¥¹¥Ú¥ë¥Õ¥¡¥¤¥ë¤Ç¤Ï¤Ê¤¤¤è¤¦¤Ç¤¹"
+
+msgid "E771: Old spell file, needs to be updated"
+msgstr "E771: ¸Å¤¤¥¹¥Ú¥ë¥Õ¥¡¥¤¥ë¤Ê¤Î¤Ç¡¢¥¢¥Ã¥×¥Ç¡¼¥È¤·¤Æ¤¯¤À¤µ¤¤"
+
+msgid "E772: Spell file is for newer version of Vim"
+msgstr "E772: ¤è¤ê¿·¤·¤¤¥Ð¡¼¥¸¥ç¥ó¤Î Vim ÍѤΥ¹¥Ú¥ë¥Õ¥¡¥¤¥ë¤Ç¤¹"
+
+msgid "E770: Unsupported section in spell file"
+msgstr "E770: ¥¹¥Ú¥ë¥Õ¥¡¥¤¥ë¤Ë¥µ¥Ý¡¼¥È¤·¤Æ¤¤¤Ê¤¤¥»¥¯¥·¥ç¥ó¤¬¤¢¤ê¤Þ¤¹"
+
+#, c-format
+msgid "E778: This does not look like a .sug file: %s"
+msgstr "E778: .sug ¥Õ¥¡¥¤¥ë¤Ç¤Ï¤Ê¤¤¤è¤¦¤Ç¤¹: %s"
+
+#, c-format
+msgid "E779: Old .sug file, needs to be updated: %s"
+msgstr "E779: ¸Å¤¤ .sug ¥Õ¥¡¥¤¥ë¤Ê¤Î¤Ç¡¢¥¢¥Ã¥×¥Ç¡¼¥È¤·¤Æ¤¯¤À¤µ¤¤: %s"
+
+#, c-format
+msgid "E780: .sug file is for newer version of Vim: %s"
+msgstr "E780: ¤è¤ê¿·¤·¤¤¥Ð¡¼¥¸¥ç¥ó¤Î Vim ÍѤΠ.sug ¥Õ¥¡¥¤¥ë¤Ç¤¹: %s"
+
+#, c-format
+msgid "E781: .sug file doesn't match .spl file: %s"
+msgstr "E781: .sug ¥Õ¥¡¥¤¥ë¤¬ .spl ¥Õ¥¡¥¤¥ë¤È°ìÃפ·¤Þ¤»¤ó: %s"
+
+#, c-format
+msgid "E782: error while reading .sug file: %s"
+msgstr "E782: .sug ¥Õ¥¡¥¤¥ë¤ÎÆɹþÃæ¤Ë¥¨¥é¡¼¤¬È¯À¸¤·¤Þ¤·¤¿: %s"
+
+#, c-format
+msgid "Reading affix file %s..."
+msgstr "affix ¥Õ¥¡¥¤¥ë %s ¤òÆɹþÃæ..."
+
+#, c-format
+msgid "Conversion failure for word in %s line %d: %s"
+msgstr "%s (%d ¹ÔÌÜ) ¤Îñ¸ì¤òÊÑ´¹¤Ç¤­¤Þ¤»¤ó¤Ç¤·¤¿: %s"
+
+#, c-format
+msgid "Conversion in %s not supported: from %s to %s"
+msgstr "%s Æâ¤Î¼¡¤ÎÊÑ´¹¤Ï¥µ¥Ý¡¼¥È¤µ¤ì¤Æ¤¤¤Þ¤»¤ó: %s ¤«¤é %s ¤Ø"
+
+#, c-format
+msgid "Conversion in %s not supported"
+msgstr "%s Æâ¤ÎÊÑ´¹¤Ï¥µ¥Ý¡¼¥È¤µ¤ì¤Æ¤¤¤Þ¤»¤ó"
+
+#, c-format
+msgid "Invalid value for FLAG in %s line %d: %s"
+msgstr "%s Æâ¤Î %d ¹ÔÌܤΠFLAG ¤Ë̵¸ú¤ÊÃͤ¬¤¢¤ê¤Þ¤¹: %s"
+
+#, c-format
+msgid "FLAG after using flags in %s line %d: %s"
+msgstr "%s Æâ¤Î %d ¹ÔÌܤ˥ե饰¤ÎÆó½Å»ÈÍѤ¬¤¢¤ê¤Þ¤¹: %s"
+
+#, c-format
+msgid ""
+"Defining COMPOUNDFORBIDFLAG after PFX item may give wrong results in %s line "
+"%d"
+msgstr ""
+"%s ¤Î %d ¹ÔÌܤΠPFX ¹àÌܤθå¤Î COMPOUNDFORBIDFLAG ¤ÎÄêµÁ¤Ï¸í¤Ã¤¿·ë²Ì¤òÀ¸¤¸¤ë"
+"¤³¤È¤¬¤¢¤ê¤Þ¤¹"
+
+#, c-format
+msgid ""
+"Defining COMPOUNDPERMITFLAG after PFX item may give wrong results in %s line "
+"%d"
+msgstr ""
+"%s ¤Î %d ¹ÔÌܤΠPFX ¹àÌܤθå¤Î COMPOUNDPERMITFLAG ¤ÎÄêµÁ¤Ï¸í¤Ã¤¿·ë²Ì¤òÀ¸¤¸¤ë"
+"¤³¤È¤¬¤¢¤ê¤Þ¤¹"
+
+#, c-format
+msgid "Wrong COMPOUNDRULES value in %s line %d: %s"
+msgstr "COMPOUNDRULES ¤ÎÃͤ˸í¤ê¤¬¤¢¤ê¤Þ¤¹. ¥Õ¥¡¥¤¥ë %s ¤Î %d ¹ÔÌÜ: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDWORDMAX value in %s line %d: %s"
+msgstr "%s ¤Î %d ¹ÔÌܤΠCOMPOUNDWORDMAX ¤ÎÃͤ˸í¤ê¤¬¤¢¤ê¤Þ¤¹: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDMIN value in %s line %d: %s"
+msgstr "%s ¤Î %d ¹ÔÌܤΠCOMPOUNDMIN ¤ÎÃͤ˸í¤ê¤¬¤¢¤ê¤Þ¤¹: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDSYLMAX value in %s line %d: %s"
+msgstr "%s ¤Î %d ¹ÔÌܤΠCOMPOUNDSYLMAX ¤ÎÃͤ˸í¤ê¤¬¤¢¤ê¤Þ¤¹: %s"
+
+#, c-format
+msgid "Wrong CHECKCOMPOUNDPATTERN value in %s line %d: %s"
+msgstr "%s ¤Î %d ¹ÔÌܤΠCHECKCOMPOUNDPATTERN ¤ÎÃͤ˸í¤ê¤¬¤¢¤ê¤Þ¤¹: %s"
+
+#, c-format
+msgid "Different combining flag in continued affix block in %s line %d: %s"
+msgstr ""
+"%s ¤Î %d ¹ÔÌܤΠϢ³ affix ¥Ö¥í¥Ã¥¯¤Î¥Õ¥é¥°¤ÎÁȹ礻¤Ë°ã¤¤¤¬¤¢¤ê¤Þ¤¹: %s"
+
+#, c-format
+msgid "Duplicate affix in %s line %d: %s"
+msgstr "%s ¤Î %d ¹ÔÌÜ¤Ë ½ÅÊ£¤·¤¿ affix ¤ò¸¡½Ð¤·¤Þ¤·¤¿: %s"
+
+#, c-format
+msgid ""
+"Affix also used for BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST in %s "
+"line %d: %s"
+msgstr ""
+"%s ¤Î %d ¹ÔÌܤΠaffix ¤Ï BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST "
+"¤Ë»ÈÍѤ·¤Æ¤¯¤À¤µ¤¤: %s"
+
+#, c-format
+msgid "Expected Y or N in %s line %d: %s"
+msgstr "%s ¤Î %d ¹ÔÌÜ¤Ç¤Ï Y ¤« N ¤¬É¬ÍפǤ¹: %s"
+
+#, c-format
+msgid "Broken condition in %s line %d: %s"
+msgstr "%s ¤Î %d ¹ÔÌܤΠ¾ò·ï¤Ï²õ¤ì¤Æ¤¤¤Þ¤¹: %s"
+
+#, c-format
+msgid "Expected REP(SAL) count in %s line %d"
+msgstr "%s ¤Î %d ¹ÔÌÜ¤Ë¤Ï REP(SAL) ¤Î²ó¿ô¤¬É¬ÍפǤ¹"
+
+#, c-format
+msgid "Expected MAP count in %s line %d"
+msgstr "%s ¤Î %d ¹ÔÌÜ¤Ë¤Ï MAP ¤Î²ó¿ô¤¬É¬ÍפǤ¹"
+
+#, c-format
+msgid "Duplicate character in MAP in %s line %d"
+msgstr "%s ¤Î %d ¹ÔÌܤΠMAP ¤Ë½ÅÊ£¤·¤¿Ê¸»ú¤¬¤¢¤ê¤Þ¤¹"
+
+#, c-format
+msgid "Unrecognized or duplicate item in %s line %d: %s"
+msgstr "%s ¤Î %d ¹ÔÌÜ¤Ë Ç§¼±¤Ç¤­¤Ê¤¤¤«½ÅÊ£¤·¤¿¹àÌܤ¬¤¢¤ê¤Þ¤¹: %s"
+
+#, c-format
+msgid "Missing FOL/LOW/UPP line in %s"
+msgstr "%s ¹ÔÌÜ¤Ë FOL/LOW/UPP ¤¬¤¢¤ê¤Þ¤»¤ó"
+
+msgid "COMPOUNDSYLMAX used without SYLLABLE"
+msgstr "SYLLABLE ¤¬»ØÄꤵ¤ì¤Ê¤¤ COMPOUNDSYLMAX"
+
+msgid "Too many postponed prefixes"
+msgstr "ÃÙ±ä¸åÃÖ»Ò¤¬Â¿²á¤®¤Þ¤¹"
+
+msgid "Too many compound flags"
+msgstr "Ê£¹ç¥Õ¥é¥°¤¬Â¿²á¤®¤Þ¤¹"
+
+msgid "Too many postponed prefixes and/or compound flags"
+msgstr "ÃÙ±ä¸åÃÖ»Ò ¤È/¤â¤·¤¯¤Ï Ê£¹ç¥Õ¥é¥°¤¬Â¿²á¤®¤Þ¤¹"
+
+#, c-format
+msgid "Missing SOFO%s line in %s"
+msgstr "SOFO%s ¹Ô¤¬ %s ¤Ë¤¢¤ê¤Þ¤»¤ó"
+
+#, c-format
+msgid "Both SAL and SOFO lines in %s"
+msgstr "SAL¹Ô ¤È SOFO¹Ô ¤¬ %s ¤ÇξÊý»ØÄꤵ¤ì¤Æ¤¤¤Þ¤¹"
+
+#, c-format
+msgid "Flag is not a number in %s line %d: %s"
+msgstr "%s ¤Î %d ¹Ô¤Î ¥Õ¥é¥°¤¬¿ôÃͤǤϤ¢¤ê¤Þ¤»¤ó: %s"
+
+#, c-format
+msgid "Illegal flag in %s line %d: %s"
+msgstr "%s ¤Î %d ¹ÔÌܤΠ¥Õ¥é¥°¤¬ÉÔÀµ¤Ç¤¹: %s"
+
+#, c-format
+msgid "%s value differs from what is used in another .aff file"
+msgstr "ÃÍ %s ¤Ï¾¤Î .aff ¥Õ¥¡¥¤¥ë¤Ç»ÈÍѤµ¤ì¤¿¤Î¤È°Û¤Ê¤ê¤Þ¤¹"
+
+#, c-format
+msgid "Reading dictionary file %s..."
+msgstr "¼­½ñ¥Õ¥¡¥¤¥ë %s ¤òÆɹþ¤ßÃæ..."
+
+#, c-format
+msgid "E760: No word count in %s"
+msgstr "E760: %s ¤Ë¤Ïñ¸ì¿ô¤¬¤¢¤ê¤Þ¤»¤ó"
+
+#, c-format
+msgid "line %6d, word %6ld - %s"
+msgstr "¹Ô %6d, ñ¸ì %6ld - %s"
+
+#, c-format
+msgid "Duplicate word in %s line %d: %s"
+msgstr "%s ¤Î %d ¹ÔÌÜ¤Ç ½Åʣñ¸ì¤¬¸«¤Ä¤«¤ê¤Þ¤·¤¿: %s"
+
+#, c-format
+msgid "First duplicate word in %s line %d: %s"
+msgstr "½ÅÊ£¤Î¤¦¤ÁºÇ½é¤Îñ¸ì¤Ï %s ¤Î %d ¹ÔÌܤǤ¹: %s"
+
+#, c-format
+msgid "%d duplicate word(s) in %s"
+msgstr "%d ¸Ä¤Îñ¸ì¤¬¸«¤Ä¤«¤ê¤Þ¤·¤¿ (%s Æâ)"
+
+#, c-format
+msgid "Ignored %d word(s) with non-ASCII characters in %s"
+msgstr "ÈóASCIIʸ»ú¤ò´Þ¤à %d ¸Ä¤Îñ¸ì¤ò̵»ë¤·¤Þ¤·¤¿ (%s Æâ)"
+
+#, c-format
+msgid "Reading word file %s..."
+msgstr "ñ¸ì¥Õ¥¡¥¤¥ë %s ¤òÆɹþ¤ßÃæ..."
+
+#, c-format
+msgid "Duplicate /encoding= line ignored in %s line %d: %s"
+msgstr "%s ¤Î %d ¹ÔÌܤΠ½ÅÊ£¤·¤¿ /encoding= ¹Ô¤ò̵»ë¤·¤Þ¤·¤¿: %s"
+
+#, c-format
+msgid "/encoding= line after word ignored in %s line %d: %s"
+msgstr "%s ¤Î %d ¹ÔÌܤΠñ¸ì¤Î¸å¤Î /encoding= ¹Ô¤ò̵»ë¤·¤Þ¤·¤¿: %s"
+
+#, c-format
+msgid "Duplicate /regions= line ignored in %s line %d: %s"
+msgstr "%s ¤Î %d ¹ÔÌܤΠ½ÅÊ£¤·¤¿ /regions= ¹Ô¤ò̵»ë¤·¤Þ¤·¤¿: %s"
+
+#, c-format
+msgid "Too many regions in %s line %d: %s"
+msgstr "%s ¤Î %d ¹ÔÌÜ¡¢ÈÏ°Ï»ØÄ꤬¿²á¤®¤Þ¤¹: %s"
+
+#, c-format
+msgid "/ line ignored in %s line %d: %s"
+msgstr "%s ¤Î %d ¹ÔÌܤΠ½ÅÊ£¤·¤¿ / ¹Ô¤ò̵»ë¤·¤Þ¤·¤¿: %s"
+
+#, c-format
+msgid "Invalid region nr in %s line %d: %s"
+msgstr "%s ¤Î %d ¹ÔÌÜ Ìµ¸ú¤Ê nr Îΰè¤Ç¤¹: %s"
+
+#, c-format
+msgid "Unrecognized flags in %s line %d: %s"
+msgstr "%s ¤Î %d ¹ÔÌÜ Ç§¼±ÉÔǽ¤Ê¥Õ¥é¥°¤Ç¤¹: %s"
+
+#, c-format
+msgid "Ignored %d words with non-ASCII characters"
+msgstr "ÈóASCIIʸ»ú¤ò´Þ¤à %d ¸Ä¤Îñ¸ì¤ò̵»ë¤·¤Þ¤·¤¿"
+
+msgid "E845: Insufficient memory, word list will be incomplete"
+msgstr "E845: ¥á¥â¥ê¤¬Â­¤ê¤Ê¤¤¤Î¤Ç¡¢Ã±¸ì¥ê¥¹¥È¤ÏÉÔ´°Á´¤Ç¤¹"
+
+#, c-format
+msgid "Compressed %d of %d nodes; %d (%d%%) remaining"
+msgstr "¥Î¡¼¥É %d ¸Ä(Á´ %d ¸ÄÃæ) ¤ò°µ½Ì¤·¤Þ¤·¤¿; »Ä¤ê %d (%d%%)"
+
+msgid "Reading back spell file..."
+msgstr "¥¹¥Ú¥ë¥Õ¥¡¥¤¥ë¤òµÕÆɹþÃæ"
+
+msgid "Performing soundfolding..."
+msgstr "²»À¼¾ö¹þ¤ß¤ò¼Â¹ÔÃæ..."
+
+#, c-format
+msgid "Number of words after soundfolding: %ld"
+msgstr "²»À¼¾ö¹þ¤ß¸å¤ÎÁíñ¸ì¿ô: %ld"
+
+#, c-format
+msgid "Total number of words: %d"
+msgstr "Áíñ¸ì¿ô: %d"
+
+#, c-format
+msgid "Writing suggestion file %s..."
+msgstr "½¤Àµ¸õÊä¥Õ¥¡¥¤¥ë \"%s\" ¤ò½ñ¹þ¤ßÃæ..."
+
+#, c-format
+msgid "Estimated runtime memory use: %d bytes"
+msgstr "¿äÄê¥á¥â¥ê»ÈÍÑÎÌ: %d ¥Ð¥¤¥È"
+
+msgid "E751: Output file name must not have region name"
+msgstr "E751: ½ÐÎÏ¥Õ¥¡¥¤¥ë̾¤Ë¤ÏÈÏ°Ï̾¤ò´Þ¤á¤é¤ì¤Þ¤»¤ó"
+
+#, c-format
+msgid "E754: Only up to %ld regions supported"
+msgstr "E754: ÈÏ°Ï¤Ï %ld ¸Ä¤Þ¤Ç¤·¤«¥µ¥Ý¡¼¥È¤µ¤ì¤Æ¤¤¤Þ¤»¤ó"
+
+#, c-format
+msgid "E755: Invalid region in %s"
+msgstr "E755: ̵¸ú¤ÊÈϰϤǤ¹: %s"
+
+msgid "Warning: both compounding and NOBREAK specified"
+msgstr "·Ù¹ð: Ê£¹ç¥Õ¥é¥°¤È NOBREAK ¤¬Î¾Êý¤È¤â»ØÄꤵ¤ì¤Þ¤·¤¿"
+
+#, c-format
+msgid "Writing spell file %s..."
+msgstr "¥¹¥Ú¥ë¥Õ¥¡¥¤¥ë %s ¤ò½ñ¹þ¤ßÃæ..."
+
+msgid "Done!"
+msgstr "¼Â¹Ô¤·¤Þ¤·¤¿!"
+
+#, c-format
+msgid "E765: 'spellfile' does not have %ld entries"
+msgstr "E765: 'spellfile' ¤Ë¤Ï %ld ¸Ä¤Î¥¨¥ó¥È¥ê¤Ï¤¢¤ê¤Þ¤»¤ó"
+
+#, c-format
+msgid "Word '%.*s' removed from %s"
+msgstr "ñ¸ì '%.*s' ¤¬ %s ¤«¤éºï½ü¤µ¤ì¤Þ¤·¤¿"
+
+#, c-format
+msgid "Word '%.*s' added to %s"
+msgstr "ñ¸ì '%.*s' ¤¬ %s ¤ØÄɲ䵤ì¤Þ¤·¤¿"
+
+msgid "E763: Word characters differ between spell files"
+msgstr "E763: ñ¸ì¤Îʸ»ú¤¬¥¹¥Ú¥ë¥Õ¥¡¥¤¥ë¤È°Û¤Ê¤ê¤Þ¤¹"
+
+msgid "E783: duplicate char in MAP entry"
+msgstr "E783: MAP ¥¨¥ó¥È¥ê¤Ë½Åʣʸ»ú¤¬Â¸ºß¤·¤Þ¤¹"
+
+msgid "No Syntax items defined for this buffer"
+msgstr "¤³¤Î¥Ð¥Ã¥Õ¥¡¤ËÄêµÁ¤µ¤ì¤¿¹½Ê¸Í×ÁǤϤ¢¤ê¤Þ¤»¤ó"
+
+msgid "'redrawtime' exceeded, syntax highlighting disabled"
+msgstr "'redrawtime' ¤òĶ²á¤·¤¿¤¿¤á¡¢¹½Ê¸¥Ï¥¤¥é¥¤¥È¤Ï̵¸ú²½¤µ¤ì¤Þ¤¹"
+
+msgid "syntax conceal on"
+msgstr "¹½Ê¸¤Î conceal ¤Ï¸½ºß on ¤Ç¤¹"
+
+msgid "syntax conceal off"
+msgstr "¹½Ê¸¤Î conceal ¤Ï¸½ºß off ¤Ç¤¹"
+
+#, c-format
+msgid "E390: Illegal argument: %s"
+msgstr "E390: ÉÔÀµ¤Ê°ú¿ô¤Ç¤¹: %s"
+
+msgid "syntax case ignore"
+msgstr "¹½Ê¸¤ÎÂçʸ»ú¾®Ê¸»ú¤Ï¸½ºß ignore ¤Ç¤¹"
+
+msgid "syntax case match"
+msgstr "¹½Ê¸¤ÎÂçʸ»ú¾®Ê¸»ú¤Ï¸½ºß match ¤Ç¤¹"
+
+msgid "syntax spell toplevel"
+msgstr "¹½Ê¸¤Î spell ¤Ï¸½ºß toplevel ¤Ç¤¹"
+
+msgid "syntax spell notoplevel"
+msgstr "¹½Ê¸¤Î spell ¤Ï¸½ºß notoplevel ¤Ç¤¹"
+
+msgid "syntax spell default"
+msgstr "¹½Ê¸¤Î spell ¤Ï¸½ºß default ¤Ç¤¹"
+
+msgid "syntax iskeyword "
+msgstr "¹½Ê¸ÍÑ iskeyword "
+
+msgid "syntax iskeyword not set"
+msgstr "¹½Ê¸ÍÑ iskeyword ¤Ï¥»¥Ã¥È¤µ¤ì¤Æ¤¤¤Þ¤»¤ó"
+
+#, c-format
+msgid "E391: No such syntax cluster: %s"
+msgstr "E391: ¤½¤Î¤è¤¦¤Ê¹½Ê¸¥¯¥é¥¹¥¿¤Ï¤¢¤ê¤Þ¤»¤ó: %s"
+
+msgid "syncing on C-style comments"
+msgstr "C¸À¸ìÉ÷¥³¥á¥ó¥È¤«¤éƱ´üÃæ"
+
+msgid "no syncing"
+msgstr "ÈóƱ´ü"
+
+msgid "syncing starts "
+msgstr "Ʊ´ü³«»Ï "
+
+msgid " lines before top line"
+msgstr " ¹ÔÁ°(¥È¥Ã¥×¹Ô¤è¤ê¤â)"
+
+msgid ""
+"\n"
+"--- Syntax sync items ---"
+msgstr ""
+"\n"
+"--- ¹½Ê¸Æ±´üÍ×ÁÇ ---"
+
+msgid ""
+"\n"
+"syncing on items"
+msgstr ""
+"\n"
+"Í×ÁǾå¤ÇƱ´üÃæ"
+
+msgid ""
+"\n"
+"--- Syntax items ---"
+msgstr ""
+"\n"
+"--- ¹½Ê¸Í×ÁÇ ---"
+
+#, c-format
+msgid "E392: No such syntax cluster: %s"
+msgstr "E392: ¤½¤Î¤è¤¦¤Ê¹½Ê¸¥¯¥é¥¹¥¿¤Ï¤¢¤ê¤Þ¤»¤ó: %s"
+
+msgid "minimal "
+msgstr "minimal "
+
+msgid "maximal "
+msgstr "maximal "
+
+msgid "; match "
+msgstr "; ³ºÅö "
+
+msgid " line breaks"
+msgstr " ¸Ä¤Î²þ¹Ô"
+
+msgid "E395: contains argument not accepted here"
+msgstr "E395: ¤³¤Î¾ì½ê¤Ç¤Ï°ú¿ôcontains¤Ïµö²Ä¤µ¤ì¤Æ¤¤¤Þ¤»¤ó"
+
+msgid "E844: invalid cchar value"
+msgstr "E844: ̵¸ú¤Êcchar¤ÎÃͤǤ¹"
+
+msgid "E393: group[t]here not accepted here"
+msgstr "E393: ¤³¤³¤Ç¤Ï¥°¥ë¡¼¥×¤Ïµö²Ä¤µ¤ì¤Þ¤»¤ó"
+
+#, c-format
+msgid "E394: Didn't find region item for %s"
+msgstr "E394: %s ¤ÎÈÏ°ÏÍ×ÁǤ¬¸«¤Ä¤«¤ê¤Þ¤»¤ó"
+
+msgid "E397: Filename required"
+msgstr "E397: ¥Õ¥¡¥¤¥ë̾¤¬É¬ÍפǤ¹"
+
+msgid "E847: Too many syntax includes"
+msgstr "E847: ¹½Ê¸¤Î¼è¤ê¹þ¤ß(include)¤¬Â¿²á¤®¤Þ¤¹"
+
+#, c-format
+msgid "E789: Missing ']': %s"
+msgstr "E789: ']' ¤¬¤¢¤ê¤Þ¤»¤ó: %s"
+
+#, c-format
+msgid "E890: trailing char after ']': %s]%s"
+msgstr "E890: ']' ¤Î¸å¤í¤Ë;ʬ¤Êʸ»ú¤¬¤¢¤ê¤Þ¤¹: %s]%s"
+
+#, c-format
+msgid "E398: Missing '=': %s"
+msgstr "E398: '=' ¤¬¤¢¤ê¤Þ¤»¤ó: %s"
+
+#, c-format
+msgid "E399: Not enough arguments: syntax region %s"
+msgstr "E399: °ú¿ô¤¬Â­¤ê¤Þ¤»¤ó: ¹½Ê¸ÈÏ°Ï %s"
+
+msgid "E848: Too many syntax clusters"
+msgstr "E848: ¹½Ê¸¥¯¥é¥¹¥¿¤¬Â¿²á¤®¤Þ¤¹"
+
+msgid "E400: No cluster specified"
+msgstr "E400: ¥¯¥é¥¹¥¿¤¬»ØÄꤵ¤ì¤Æ¤¤¤Þ¤»¤ó"
+
+#, c-format
+msgid "E401: Pattern delimiter not found: %s"
+msgstr "E401: ¥Ñ¥¿¡¼¥ó¶èÀڤ꤬¸«¤Ä¤«¤ê¤Þ¤»¤ó: %s"
+
+#, c-format
+msgid "E402: Garbage after pattern: %s"
+msgstr "E402: ¥Ñ¥¿¡¼¥ó¤Î¤¢¤È¤Ë¥´¥ß¤¬¤¢¤ê¤Þ¤¹: %s"
+
+msgid "E403: syntax sync: line continuations pattern specified twice"
+msgstr "E403: ¹½Ê¸Æ±´ü: Ϣ³¹Ô¥Ñ¥¿¡¼¥ó¤¬2ÅÙ»ØÄꤵ¤ì¤Þ¤·¤¿"
+
+#, c-format
+msgid "E404: Illegal arguments: %s"
+msgstr "E404: ÉÔÀµ¤Ê°ú¿ô¤Ç¤¹: %s"
+
+#, c-format
+msgid "E405: Missing equal sign: %s"
+msgstr "E405: Åù¹æ¤¬¤¢¤ê¤Þ¤»¤ó: %s"
+
+#, c-format
+msgid "E406: Empty argument: %s"
+msgstr "E406: ¶õ¤Î°ú¿ô: %s"
+
+#, c-format
+msgid "E407: %s not allowed here"
+msgstr "E407: %s ¤Ï¥³¥³¤Ç¤Ïµö²Ä¤µ¤ì¤Æ¤¤¤Þ¤»¤ó"
+
+#, c-format
+msgid "E408: %s must be first in contains list"
+msgstr "E408: %s ¤ÏÆâÍƥꥹ¥È¤ÎÀèƬ¤Ç¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤"
+
+#, c-format
+msgid "E409: Unknown group name: %s"
+msgstr "E409: ̤ÃΤΥ°¥ë¡¼¥×̾: %s"
+
+#, c-format
+msgid "E410: Invalid :syntax subcommand: %s"
+msgstr "E410: ̵¸ú¤Ê :syntax ¤Î¥µ¥Ö¥³¥Þ¥ó¥É: %s"
+
+msgid ""
+" TOTAL COUNT MATCH SLOWEST AVERAGE NAME PATTERN"
+msgstr ""
+" TOTAL COUNT MATCH SLOWEST AVERAGE NAME PATTERN"
+
+msgid "E679: recursive loop loading syncolor.vim"
+msgstr "E679: syncolor.vim ¤ÎºÆµ¢¸Æ¤Ó½Ð¤·¤ò¸¡½Ð¤·¤Þ¤·¤¿"
+
+#, c-format
+msgid "E411: highlight group not found: %s"
+msgstr "E411: ¥Ï¥¤¥é¥¤¥È¥°¥ë¡¼¥×¤¬¸«¤Ä¤«¤ê¤Þ¤»¤ó: %s"
+
+#, c-format
+msgid "E412: Not enough arguments: \":highlight link %s\""
+msgstr "E412: °ú¿ô¤¬½¼Ê¬¤Ç¤Ï¤Ê¤¤: \":highlight link %s\""
+
+#, c-format
+msgid "E413: Too many arguments: \":highlight link %s\""
+msgstr "E413: °ú¿ô¤¬Â¿²á¤®¤Þ¤¹: \":highlight link %s\""
+
+msgid "E414: group has settings, highlight link ignored"
+msgstr "E414: ¥°¥ë¡¼¥×¤¬ÀßÄꤵ¤ì¤Æ¤¤¤ë¤Î¤Ç¥Ï¥¤¥é¥¤¥È¥ê¥ó¥¯¤Ï̵»ë¤µ¤ì¤Þ¤¹"
+
+#, c-format
+msgid "E415: unexpected equal sign: %s"
+msgstr "E415: ͽ´ü¤»¤ÌÅù¹æ¤Ç¤¹: %s"
+
+#, c-format
+msgid "E416: missing equal sign: %s"
+msgstr "E416: Åù¹æ¤¬¤¢¤ê¤Þ¤»¤ó: %s"
+
+#, c-format
+msgid "E417: missing argument: %s"
+msgstr "E417: °ú¿ô¤¬¤¢¤ê¤Þ¤»¤ó: %s"
+
+#, c-format
+msgid "E418: Illegal value: %s"
+msgstr "E418: ÉÔÀµ¤ÊÃͤǤ¹: %s"
+
+msgid "E419: FG color unknown"
+msgstr "E419: ̤ÃΤÎÁ°·Ê¿§¤Ç¤¹"
+
+msgid "E420: BG color unknown"
+msgstr "E420: ̤ÃΤÎÇØ·Ê¿§¤Ç¤¹"
+
+#, c-format
+msgid "E421: Color name or number not recognized: %s"
+msgstr "E421: ¥«¥é¡¼Ì¾¤äÈÖ¹æ¤òǧ¼±¤Ç¤­¤Þ¤»¤ó: %s"
+
+#, c-format
+msgid "E422: terminal code too long: %s"
+msgstr "E422: ½ªÃ¼¥³¡¼¥É¤¬Ä¹²á¤®¤Þ¤¹: %s"
+
+#, c-format
+msgid "E423: Illegal argument: %s"
+msgstr "E423: ÉÔÀµ¤Ê°ú¿ô¤Ç¤¹: %s"
+
+msgid "E424: Too many different highlighting attributes in use"
+msgstr "E424: ¿¤¯¤Î°Û¤Ê¤ë¥Ï¥¤¥é¥¤¥È°À­¤¬»È¤ï¤ì²á¤®¤Æ¤¤¤Þ¤¹"
+
+msgid "E669: Unprintable character in group name"
+msgstr "E669: ¥°¥ë¡¼¥×̾¤Ë°õºþÉÔ²Äǽ¤Êʸ»ú¤¬¤¢¤ê¤Þ¤¹"
+
+msgid "W18: Invalid character in group name"
+msgstr "W18: ¥°¥ë¡¼¥×̾¤ËÉÔÀµ¤Êʸ»ú¤¬¤¢¤ê¤Þ¤¹"
+
+msgid "E849: Too many highlight and syntax groups"
+msgstr "E849: ¥Ï¥¤¥é¥¤¥È¤È¹½Ê¸¥°¥ë¡¼¥×¤¬Â¿²á¤®¤Þ¤¹"
+
+msgid "E555: at bottom of tag stack"
+msgstr "E555: ¥¿¥°¥¹¥¿¥Ã¥¯¤ÎËöÈø¤Ç¤¹"
+
+msgid "E556: at top of tag stack"
+msgstr "E556: ¥¿¥°¥¹¥¿¥Ã¥¯¤ÎÀèƬ¤Ç¤¹"
+
+msgid "E425: Cannot go before first matching tag"
+msgstr "E425: ºÇ½é¤Î³ºÅö¥¿¥°¤ò±Û¤¨¤ÆÌá¤ë¤³¤È¤Ï¤Ç¤­¤Þ¤»¤ó"
+
+#, c-format
+msgid "E426: tag not found: %s"
+msgstr "E426: ¥¿¥°¤¬¸«¤Ä¤«¤ê¤Þ¤»¤ó: %s"
+
+msgid " # pri kind tag"
+msgstr " # pri kind tag"
+
+msgid "file\n"
+msgstr "¥Õ¥¡¥¤¥ë\n"
+
+msgid "E427: There is only one matching tag"
+msgstr "E427: ³ºÅö¥¿¥°¤¬1¤Ä¤À¤±¤·¤«¤¢¤ê¤Þ¤»¤ó"
+
+msgid "E428: Cannot go beyond last matching tag"
+msgstr "E428: ºÇ¸å¤Î³ºÅö¥¿¥°¤ò±Û¤¨¤Æ¿Ê¤à¤³¤È¤Ï¤Ç¤­¤Þ¤»¤ó"
+
+#, c-format
+msgid "File \"%s\" does not exist"
+msgstr "¥Õ¥¡¥¤¥ë \"%s\" ¤¬¤¢¤ê¤Þ¤»¤ó"
+
+#, c-format
+msgid "tag %d of %d%s"
+msgstr "¥¿¥° %d (Á´%d%s)"
+
+msgid " or more"
+msgstr " ¤«¤½¤ì°Ê¾å"
+
+msgid " Using tag with different case!"
+msgstr " ¥¿¥°¤ò°Û¤Ê¤ëcase¤Ç»ÈÍѤ·¤Þ¤¹!"
+
+#, c-format
+msgid "E429: File \"%s\" does not exist"
+msgstr "E429: ¥Õ¥¡¥¤¥ë \"%s\" ¤¬¤¢¤ê¤Þ¤»¤ó"
+
+msgid ""
+"\n"
+" # TO tag FROM line in file/text"
+msgstr ""
+"\n"
+" # TO ¥¿¥° FROM ¹Ô in file/text"
+
+#, c-format
+msgid "Searching tags file %s"
+msgstr "¥¿¥°¥Õ¥¡¥¤¥ë %s ¤ò¸¡º÷Ãæ"
+
+#, c-format
+msgid "E430: Tag file path truncated for %s\n"
+msgstr "E430: ¥¿¥°¥Õ¥¡¥¤¥ë¤Î¥Ñ¥¹¤¬ %s ¤ËÀÚ¤ê¼Î¤Æ¤é¤ì¤Þ¤·¤¿\n"
+
+msgid "Ignoring long line in tags file"
+msgstr "¥¿¥°¥Õ¥¡¥¤¥ëÆâ¤ÎŤ¤¹Ô¤ò̵»ë¤·¤Þ¤¹"
+
+#, c-format
+msgid "E431: Format error in tags file \"%s\""
+msgstr "E431: ¥¿¥°¥Õ¥¡¥¤¥ë \"%s\" ¤Î¥Õ¥©¡¼¥Þ¥Ã¥È¤Ë¥¨¥é¡¼¤¬¤¢¤ê¤Þ¤¹"
+
+#, c-format
+msgid "Before byte %ld"
+msgstr "ľÁ°¤Î %ld ¥Ð¥¤¥È"
+
+#, c-format
+msgid "E432: Tags file not sorted: %s"
+msgstr "E432: ¥¿¥°¥Õ¥¡¥¤¥ë¤¬¥½¡¼¥È¤µ¤ì¤Æ¤¤¤Þ¤»¤ó: %s"
+
+msgid "E433: No tags file"
+msgstr "E433: ¥¿¥°¥Õ¥¡¥¤¥ë¤¬¤¢¤ê¤Þ¤»¤ó"
+
+msgid "E434: Can't find tag pattern"
+msgstr "E434: ¥¿¥°¥Ñ¥¿¡¼¥ó¤ò¸«¤Ä¤±¤é¤ì¤Þ¤»¤ó"
+
+msgid "E435: Couldn't find tag, just guessing!"
+msgstr "E435: ¥¿¥°¤ò¸«¤Ä¤±¤é¤ì¤Ê¤¤¤Î¤Çñ¤Ë¿ä¬¤·¤Þ¤¹!"
+
+#, c-format
+msgid "Duplicate field name: %s"
+msgstr "½ÅÊ£¤·¤¿¥Õ¥£¡¼¥ë¥É̾: %s"
+
+msgid "' not known. Available builtin terminals are:"
+msgstr "' ¤Ï̤ÃΤǤ¹. ¸½¹Ô¤ÎÁȤ߹þ¤ßüËö¤Ï¼¡¤Î¤È¤ª¤ê¤Ç¤¹:"
+
+msgid "defaulting to '"
+msgstr "¾ÊάÃͤò¼¡¤Î¤è¤¦¤ËÀßÄꤷ¤Þ¤¹ '"
+
+msgid "E557: Cannot open termcap file"
+msgstr "E557: termcap¥Õ¥¡¥¤¥ë¤ò³«¤±¤Þ¤»¤ó"
+
+msgid "E558: Terminal entry not found in terminfo"
+msgstr "E558: terminfo¤ËüËö¥¨¥ó¥È¥ê¤ò¸«¤Ä¤±¤é¤ì¤Þ¤»¤ó"
+
+msgid "E559: Terminal entry not found in termcap"
+msgstr "E559: termcap¤ËüËö¥¨¥ó¥È¥ê¤ò¸«¤Ä¤±¤é¤ì¤Þ¤»¤ó"
+
+#, c-format
+msgid "E436: No \"%s\" entry in termcap"
+msgstr "E436: termcap¤Ë \"%s\" ¤Î¥¨¥ó¥È¥ê¤¬¤¢¤ê¤Þ¤»¤ó"
+
+msgid "E437: terminal capability \"cm\" required"
+msgstr "E437: üËö¤Ë \"cm\" µ¡Ç½¤¬É¬ÍפǤ¹"
+
+msgid ""
+"\n"
+"--- Terminal keys ---"
+msgstr ""
+"\n"
+"--- üËö¥­¡¼ ---"
+
+msgid "Cannot open $VIMRUNTIME/rgb.txt"
+msgstr "$VIMRUNTIME/rgb.txt¤ò³«¤±¤Þ¤»¤ó"
+
+#, c-format
+msgid "Kill job in \"%s\"?"
+msgstr "\"%s\" Æâ¤Î¥¸¥ç¥Ö¤ò½ªÎ»¤·¤Þ¤¹¤«?"
+
+msgid "Terminal"
+msgstr "üËö"
+
+msgid "Terminal-finished"
+msgstr "üËö (½ªÎ»)"
+
+msgid "active"
+msgstr "¥¢¥¯¥Æ¥£¥Ö"
+
+msgid "running"
+msgstr "¼Â¹ÔÃæ"
+
+msgid "finished"
+msgstr "½ªÎ»"
+
+msgid "E958: Job already finished"
+msgstr "E958: ¥¸¥ç¥Ö¤Ï¤¹¤Ç¤Ë½ªÎ»¤·¤Æ¤¤¤Þ¤¹"
+
+#, c-format
+msgid "E953: File exists: %s"
+msgstr "E953: ¥Õ¥¡¥¤¥ë¤Ï´û¤Ë¸ºß¤·¤Þ¤¹: %s"
+
+msgid "E955: Not a terminal buffer"
+msgstr "E955: üËö¥Ð¥Ã¥Õ¥¡¤Ç¤Ï¤¢¤ê¤Þ¤»¤ó"
+
+msgid "new shell started\n"
+msgstr "¿·¤·¤¤¥·¥§¥ë¤òµ¯Æ°¤·¤Þ¤¹\n"
+
+msgid "Vim: Error reading input, exiting...\n"
+msgstr "Vim: ÆþÎϤòÆɹþ¤ßÃæ¤Î¥¨¥é¡¼¤Ë¤è¤ê½ªÎ»¤·¤Þ¤¹...\n"
+
+msgid "Used CUT_BUFFER0 instead of empty selection"
+msgstr "¶õ¤ÎÁªÂòÎΰè¤Î¤«¤ï¤ê¤ËCUT_BUFFER0¤¬»ÈÍѤµ¤ì¤Þ¤·¤¿"
+
+msgid "E881: Line count changed unexpectedly"
+msgstr "E881: ͽ´ü¤»¤º¹Ô¥«¥¦¥ó¥È¤¬ÊѤï¤ê¤Þ¤·¤¿"
+
+msgid "No undo possible; continue anyway"
+msgstr "²Äǽ¤Ê¥¢¥ó¥É¥¥¤Ï¤¢¤ê¤Þ¤»¤ó: ¤È¤ê¤¢¤¨¤ºÂ³¤±¤Þ¤¹"
+
+#, c-format
+msgid "E828: Cannot open undo file for writing: %s"
+msgstr "E828: ½ñ¹þ¤ßÍѤ˥¢¥ó¥É¥¥¥Õ¥¡¥¤¥ë¤ò³«¤±¤Þ¤»¤ó: %s"
+
+#, c-format
+msgid "E825: Corrupted undo file (%s): %s"
+msgstr "E825: ¥¢¥ó¥É¥¥¥Õ¥¡¥¤¥ë¤¬²õ¤ì¤Æ¤¤¤Þ¤¹ (%s): %s"
+
+msgid "Cannot write undo file in any directory in 'undodir'"
+msgstr "'undodir'¤Î¥Ç¥£¥ì¥¯¥È¥ê¤Ë¥¢¥ó¥É¥¥¥Õ¥¡¥¤¥ë¤ò½ñ¤­¹þ¤á¤Þ¤»¤ó"
+
+#, c-format
+msgid "Will not overwrite with undo file, cannot read: %s"
+msgstr "¥¢¥ó¥É¥¥¥Õ¥¡¥¤¥ë¤È¤·¤ÆÆɤ߹þ¤á¤Ê¤¤¤Î¤Ç¾å½ñ¤­¤·¤Þ¤»¤ó: %s"
+
+#, c-format
+msgid "Will not overwrite, this is not an undo file: %s"
+msgstr "¥¢¥ó¥É¥¥¥Õ¥¡¥¤¥ë¤Ç¤Ï¤Ê¤¤¤Î¤Ç¾å½ñ¤­¤·¤Þ¤»¤ó: %s"
+
+msgid "Skipping undo file write, nothing to undo"
+msgstr "Âоݤ¬¤Ê¤¤¤Î¤Ç¥¢¥ó¥É¥¥¥Õ¥¡¥¤¥ë¤Î½ñ¤­¹þ¤ß¤ò¥¹¥­¥Ã¥×¤·¤Þ¤¹"
+
+#, c-format
+msgid "Writing undo file: %s"
+msgstr "¥¢¥ó¥É¥¥¥Õ¥¡¥¤¥ë½ñ¤­¹þ¤ßÃæ: %s"
+
+#, c-format
+msgid "E829: write error in undo file: %s"
+msgstr "E829: ¥¢¥ó¥É¥¥¥Õ¥¡¥¤¥ë¤Î½ñ¤­¹þ¤ß¥¨¥é¡¼¤Ç¤¹: %s"
+
+#, c-format
+msgid "Not reading undo file, owner differs: %s"
+msgstr "¥ª¡¼¥Ê¡¼¤¬°Û¤Ê¤ë¤Î¤Ç¥¢¥ó¥É¥¥¥Õ¥¡¥¤¥ë¤òÆɤ߹þ¤ß¤Þ¤»¤ó: %s"
+
+#, c-format
+msgid "Reading undo file: %s"
+msgstr "¥¢¥ó¥É¥¥¥Õ¥¡¥¤¥ëÆɹþÃæ: %s"
+
+#, c-format
+msgid "E822: Cannot open undo file for reading: %s"
+msgstr "E822: ¥¢¥ó¥É¥¥¥Õ¥¡¥¤¥ë¤òÆɹþÍѤȤ·¤Æ³«¤±¤Þ¤»¤ó: %s"
+
+#, c-format
+msgid "E823: Not an undo file: %s"
+msgstr "E823: ¥¢¥ó¥É¥¥¥Õ¥¡¥¤¥ë¤Ç¤Ï¤¢¤ê¤Þ¤»¤ó: %s"
+
+#, c-format
+msgid "E832: Non-encrypted file has encrypted undo file: %s"
+msgstr "E832: Èó°Å¹æ²½¥Õ¥¡¥¤¥ë¤¬°Å¹æ²½¤µ¤ì¤¿¥¢¥ó¥É¥¥¥Õ¥¡¥¤¥ë¤ò»È¤Ã¤Æ¤Þ¤¹: %s"
+
+#, c-format
+msgid "E826: Undo file decryption failed: %s"
+msgstr "E826: °Å¹æ²½¤µ¤ì¤¿¥¢¥ó¥É¥¥¥Õ¥¡¥¤¥ë¤Î²òÆɤ˼ºÇÔ¤·¤Þ¤·¤¿: %s"
+
+#, c-format
+msgid "E827: Undo file is encrypted: %s"
+msgstr "E827: ¥¢¥ó¥É¥¥¥Õ¥¡¥¤¥ë¤¬°Å¹æ²½¤µ¤ì¤Æ¤¤¤Þ¤¹: %s"
+
+#, c-format
+msgid "E824: Incompatible undo file: %s"
+msgstr "E824: ¸ß´¹À­¤Î̵¤¤¥¢¥ó¥É¥¥¥Õ¥¡¥¤¥ë¤Ç¤¹: %s"
+
+msgid "File contents changed, cannot use undo info"
+msgstr "¥Õ¥¡¥¤¥ë¤ÎÆâÍƤ¬ÊѤï¤Ã¤Æ¤¤¤ë¤¿¤á¡¢¥¢¥ó¥É¥¥¾ðÊó¤òÍøÍѤǤ­¤Þ¤»¤ó"
+
+#, c-format
+msgid "Finished reading undo file %s"
+msgstr "¥¢¥ó¥É¥¥¥Õ¥¡¥¤¥ë %s ¤Î¼è¹þ¤ò´°Î»"
+
+msgid "Already at oldest change"
+msgstr "´û¤Ë°ìÈָŤ¤Êѹ¹¤Ç¤¹"
+
+msgid "Already at newest change"
+msgstr "´û¤Ë°ìÈÖ¿·¤·¤¤Êѹ¹¤Ç¤¹"
+
+#, c-format
+msgid "E830: Undo number %ld not found"
+msgstr "E830: ¥¢¥ó¥É¥¥ÈÖ¹æ %ld ¤Ï¸«¤Ä¤«¤ê¤Þ¤»¤ó"
+
+msgid "E438: u_undo: line numbers wrong"
+msgstr "E438: u_undo: ¹ÔÈֹ椬´Ö°ã¤Ã¤Æ¤¤¤Þ¤¹"
+
+msgid "more line"
+msgstr "¹Ô Äɲä·¤Þ¤·¤¿"
+
+msgid "more lines"
+msgstr "¹Ô Äɲä·¤Þ¤·¤¿"
+
+msgid "line less"
+msgstr "¹Ô ºï½ü¤·¤Þ¤·¤¿"
+
+msgid "fewer lines"
+msgstr "¹Ô ºï½ü¤·¤Þ¤·¤¿"
+
+msgid "change"
+msgstr "²Õ½êÊѹ¹¤·¤Þ¤·¤¿"
+
+msgid "changes"
+msgstr "²Õ½êÊѹ¹¤·¤Þ¤·¤¿"
+
+#, c-format
+msgid "%ld %s; %s #%ld %s"
+msgstr "%ld %s; %s #%ld %s"
+
+msgid "before"
+msgstr "Á°Êý"
+
+msgid "after"
+msgstr "¸åÊý"
+
+msgid "Nothing to undo"
+msgstr "¥¢¥ó¥É¥¥Âоݤ¬¤¢¤ê¤Þ¤»¤ó"
+
+msgid "number changes when saved"
+msgstr "ÄÌÈÖ Êѹ¹¿ô Êѹ¹»þ´ü ÊݸºÑ"
+
+#, c-format
+msgid "%ld second ago"
+msgid_plural "%ld seconds ago"
+msgstr[0] "%ld É÷вᤷ¤Æ¤¤¤Þ¤¹"
+
+msgid "E790: undojoin is not allowed after undo"
+msgstr "E790: undo ¤Îľ¸å¤Ë undojoin ¤Ï¤Ç¤­¤Þ¤»¤ó"
+
+msgid "E439: undo list corrupt"
+msgstr "E439: ¥¢¥ó¥É¥¥¥ê¥¹¥È¤¬²õ¤ì¤Æ¤¤¤Þ¤¹"
+
+msgid "E440: undo line missing"
+msgstr "E440: ¥¢¥ó¥É¥¥¹Ô¤¬¤¢¤ê¤Þ¤»¤ó"
+
+#, c-format
+msgid "E122: Function %s already exists, add ! to replace it"
+msgstr "E122: ´Ø¿ô %s ¤ÏÄêµÁºÑ¤Ç¤¹¡¢ºÆÄêµÁ¤¹¤ë¤Ë¤Ï ! ¤òÄɲ䷤Ƥ¯¤À¤µ¤¤"
+
+msgid "E717: Dictionary entry already exists"
+msgstr "E717: ¼­½ñ·¿Æâ¤Ë¥¨¥ó¥È¥ê¤¬´û¤Ë¸ºß¤·¤Þ¤¹"
+
+msgid "E718: Funcref required"
+msgstr "E718: ´Ø¿ô»²¾È·¿¤¬Í׵ᤵ¤ì¤Þ¤¹"
+
+#, c-format
+msgid "E130: Unknown function: %s"
+msgstr "E130: ̤ÃΤδؿô¤Ç¤¹: %s"
+
+#, c-format
+msgid "E125: Illegal argument: %s"
+msgstr "E125: ÉÔÀµ¤Ê°ú¿ô¤Ç¤¹: %s"
+
+#, c-format
+msgid "E853: Duplicate argument name: %s"
+msgstr "E853: °ú¿ô̾¤¬½ÅÊ£¤·¤Æ¤¤¤Þ¤¹: %s"
+
+#, c-format
+msgid "E740: Too many arguments for function %s"
+msgstr "E740: ´Ø¿ô¤Î°ú¿ô¤¬Â¿²á¤®¤Þ¤¹: %s"
+
+#, c-format
+msgid "E116: Invalid arguments for function %s"
+msgstr "E116: ´Ø¿ô¤Î̵¸ú¤Ê°ú¿ô¤Ç¤¹: %s"
+
+msgid "E132: Function call depth is higher than 'maxfuncdepth'"
+msgstr "E132: ´Ø¿ô¸Æ½Ð¤ÎÆþ¤ì»Ò¿ô¤¬ 'maxfuncdepth' ¤òĶ¤¨¤Þ¤·¤¿"
+
+#, c-format
+msgid "calling %s"
+msgstr "%s ¤ò¼Â¹ÔÃæ¤Ç¤¹"
+
+#, c-format
+msgid "%s aborted"
+msgstr "%s ¤¬ÃæÃǤµ¤ì¤Þ¤·¤¿"
+
+#, c-format
+msgid "%s returning #%ld"
+msgstr "%s ¤¬ #%ld ¤òÊÖ¤·¤Þ¤·¤¿"
+
+#, c-format
+msgid "%s returning %s"
+msgstr "%s ¤¬ %s ¤òÊÖ¤·¤Þ¤·¤¿"
+
+msgid "E699: Too many arguments"
+msgstr "E699: °ú¿ô¤¬Â¿²á¤®¤Þ¤¹"
+
+#, c-format
+msgid "E117: Unknown function: %s"
+msgstr "E117: ̤ÃΤδؿô¤Ç¤¹: %s"
+
+#, c-format
+msgid "E933: Function was deleted: %s"
+msgstr "E933: ´Ø¿ô¤Ïºï½ü¤µ¤ì¤Þ¤·¤¿: %s"
+
+#, c-format
+msgid "E119: Not enough arguments for function: %s"
+msgstr "E119: ´Ø¿ô¤Î°ú¿ô¤¬Â­¤ê¤Þ¤»¤ó: %s"
+
+#, c-format
+msgid "E120: Using <SID> not in a script context: %s"
+msgstr "E120: ¥¹¥¯¥ê¥×¥È°Ê³°¤Ç<SID>¤¬»È¤ï¤ì¤Þ¤·¤¿: %s"
+
+#, c-format
+msgid "E725: Calling dict function without Dictionary: %s"
+msgstr "E725: ¼­½ñÍÑ´Ø¿ô¤¬¸Æ¤Ð¤ì¤Þ¤·¤¿¤¬¼­½ñ¤¬¤¢¤ê¤Þ¤»¤ó: %s"
+
+msgid "E129: Function name required"
+msgstr "E129: ´Ø¿ô̾¤¬Í׵ᤵ¤ì¤Þ¤¹"
+
+#, c-format
+msgid "E128: Function name must start with a capital or \"s:\": %s"
+msgstr "E128: ´Ø¿ô̾¤ÏÂçʸ»ú¤« \"s:\" ¤Ç»Ï¤Þ¤é¤Ê¤±¤ì¤Ð¤Ê¤ê¤Þ¤»¤ó: %s"
+
+#, c-format
+msgid "E884: Function name cannot contain a colon: %s"
+msgstr "E884: ´Ø¿ô̾¤Ë¤Ï¥³¥í¥ó¤Ï´Þ¤á¤é¤ì¤Þ¤»¤ó: %s"
+
+#, c-format
+msgid "E123: Undefined function: %s"
+msgstr "E123: ̤ÄêµÁ¤Î´Ø¿ô¤Ç¤¹: %s"
+
+#, c-format
+msgid "E124: Missing '(': %s"
+msgstr "E124: '(' ¤¬¤¢¤ê¤Þ¤»¤ó: %s"
+
+msgid "E862: Cannot use g: here"
+msgstr "E862: ¤³¤³¤Ç¤Ï g: ¤Ï»È¤¨¤Þ¤»¤ó"
+
+#, c-format
+msgid "E932: Closure function should not be at top level: %s"
+msgstr "E932: ¥¯¥í¡¼¥¸¥ã¡¼´Ø¿ô¤Ï¥È¥Ã¥×¥ì¥Ù¥ë¤Ëµ­½Ò¤Ç¤­¤Þ¤»¤ó: %s"
+
+msgid "E126: Missing :endfunction"
+msgstr "E126: :endfunction ¤¬¤¢¤ê¤Þ¤»¤ó"
+
+#, c-format
+msgid "W22: Text found after :endfunction: %s"
+msgstr "W22: :endfunction ¤Î¸å¤Ëʸ»ú¤¬¤¢¤ê¤Þ¤¹: %s"
+
+#, c-format
+msgid "E707: Function name conflicts with variable: %s"
+msgstr "E707: ´Ø¿ô̾¤¬ÊÑ¿ô̾¤È¾×Æͤ·¤Þ¤¹: %s"
+
+#, c-format
+msgid "E127: Cannot redefine function %s: It is in use"
+msgstr "E127: ´Ø¿ô %s ¤òºÆÄêµÁ¤Ç¤­¤Þ¤»¤ó: »ÈÍÑÃæ¤Ç¤¹"
+
+#, c-format
+msgid "E746: Function name does not match script file name: %s"
+msgstr "E746: ´Ø¿ô̾¤¬¥¹¥¯¥ê¥×¥È¤Î¥Õ¥¡¥¤¥ë̾¤È°ìÃפ·¤Þ¤»¤ó: %s"
+
+#, c-format
+msgid "E131: Cannot delete function %s: It is in use"
+msgstr "E131: ´Ø¿ô %s ¤òºï½ü¤Ç¤­¤Þ¤»¤ó: »ÈÍÑÃæ¤Ç¤¹"
+
+msgid "E133: :return not inside a function"
+msgstr "E133: ´Ø¿ô³°¤Ë :return ¤¬¤¢¤ê¤Þ¤·¤¿"
+
+#, c-format
+msgid "E107: Missing parentheses: %s"
+msgstr "E107: ¥«¥Ã¥³ '(' ¤¬¤¢¤ê¤Þ¤»¤ó: %s"
+
+#, c-format
+msgid "%s (%s, compiled %s)"
+msgstr "%s (%s, compiled %s)"
+
+msgid ""
+"\n"
+"MS-Windows 64-bit GUI version"
+msgstr ""
+"\n"
+"MS-Windows 64 ¥Ó¥Ã¥È GUI ÈÇ"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit GUI version"
+msgstr ""
+"\n"
+"MS-Windows 32 ¥Ó¥Ã¥È GUI ÈÇ"
+
+msgid " with OLE support"
+msgstr " with OLE ¥µ¥Ý¡¼¥È"
+
+msgid ""
+"\n"
+"MS-Windows 64-bit console version"
+msgstr ""
+"\n"
+"MS-Windows 64 ¥Ó¥Ã¥È ¥³¥ó¥½¡¼¥ë ÈÇ"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit console version"
+msgstr ""
+"\n"
+"MS-Windows 32 ¥Ó¥Ã¥È ¥³¥ó¥½¡¼¥ë ÈÇ"
+
+msgid ""
+"\n"
+"macOS version"
+msgstr ""
+"\n"
+"macOS ÈÇ"
+
+msgid ""
+"\n"
+"macOS version w/o darwin feat."
+msgstr ""
+"\n"
+"macOS ÈÇ (darwin ̵¤·)"
+
+msgid ""
+"\n"
+"OpenVMS version"
+msgstr ""
+"\n"
+"OpenVMS ÈÇ"
+
+msgid ""
+"\n"
+"Included patches: "
+msgstr ""
+"\n"
+"ŬÍѺѥѥåÁ: "
+
+msgid ""
+"\n"
+"Extra patches: "
+msgstr ""
+"\n"
+"ÄɲóÈÄ¥¥Ñ¥Ã¥Á: "
+
+msgid "Modified by "
+msgstr "Modified by "
+
+msgid ""
+"\n"
+"Compiled "
+msgstr ""
+"\n"
+"Compiled "
+
+msgid "by "
+msgstr "by "
+
+msgid ""
+"\n"
+"Huge version "
+msgstr ""
+"\n"
+"Huge ÈÇ "
+
+msgid ""
+"\n"
+"Big version "
+msgstr ""
+"\n"
+"Big ÈÇ "
+
+msgid ""
+"\n"
+"Normal version "
+msgstr ""
+"\n"
+"Ä̾ï ÈÇ "
+
+msgid ""
+"\n"
+"Small version "
+msgstr ""
+"\n"
+"Small ÈÇ "
+
+msgid ""
+"\n"
+"Tiny version "
+msgstr ""
+"\n"
+"Tiny ÈÇ "
+
+msgid "without GUI."
+msgstr "without GUI."
+
+msgid "with GTK3 GUI."
+msgstr "with GTK3 GUI."
+
+msgid "with GTK2-GNOME GUI."
+msgstr "with GTK2-GNOME GUI."
+
+msgid "with GTK2 GUI."
+msgstr "with GTK2 GUI."
+
+msgid "with X11-Motif GUI."
+msgstr "with X11-Motif GUI."
+
+msgid "with X11-neXtaw GUI."
+msgstr "with X11-neXtaw GUI."
+
+msgid "with X11-Athena GUI."
+msgstr "with X11-Athena GUI."
+
+msgid "with Photon GUI."
+msgstr "with Photon GUI."
+
+msgid "with GUI."
+msgstr "with GUI."
+
+msgid "with Carbon GUI."
+msgstr "with Carbon GUI."
+
+msgid "with Cocoa GUI."
+msgstr "with Cocoa GUI."
+
+msgid " Features included (+) or not (-):\n"
+msgstr " µ¡Ç½¤Î°ìÍ÷ Í­¸ú(+)/̵¸ú(-)\n"
+
+msgid " system vimrc file: \""
+msgstr " ¥·¥¹¥Æ¥à vimrc: \""
+
+msgid " user vimrc file: \""
+msgstr " ¥æ¡¼¥¶¡¼ vimrc: \""
+
+msgid " 2nd user vimrc file: \""
+msgstr " Âè2¥æ¡¼¥¶¡¼ vimrc: \""
+
+msgid " 3rd user vimrc file: \""
+msgstr " Âè3¥æ¡¼¥¶¡¼ vimrc: \""
+
+msgid " user exrc file: \""
+msgstr " ¥æ¡¼¥¶¡¼ exrc: \""
+
+msgid " 2nd user exrc file: \""
+msgstr " Âè2¥æ¡¼¥¶¡¼ exrc: \""
+
+msgid " system gvimrc file: \""
+msgstr " ¥·¥¹¥Æ¥à gvimrc: \""
+
+msgid " user gvimrc file: \""
+msgstr " ¥æ¡¼¥¶¡¼ gvimrc: \""
+
+msgid "2nd user gvimrc file: \""
+msgstr " Âè2¥æ¡¼¥¶¡¼ gvimrc: \""
+
+msgid "3rd user gvimrc file: \""
+msgstr " Âè3¥æ¡¼¥¶¡¼ gvimrc: \""
+
+msgid " defaults file: \""
+msgstr " ¥Ç¥Õ¥©¥ë¥È¥Õ¥¡¥¤¥ë: \""
+
+msgid " system menu file: \""
+msgstr " ¥·¥¹¥Æ¥à¥á¥Ë¥å¡¼: \""
+
+msgid " fall-back for $VIM: \""
+msgstr " ¾Êά»þ¤Î $VIM: \""
+
+msgid " f-b for $VIMRUNTIME: \""
+msgstr "¾Êά»þ¤Î $VIMRUNTIME: \""
+
+msgid "Compilation: "
+msgstr "¥³¥ó¥Ñ¥¤¥ë: "
+
+msgid "Compiler: "
+msgstr "¥³¥ó¥Ñ¥¤¥é: "
+
+msgid "Linking: "
+msgstr "¥ê¥ó¥¯: "
+
+msgid " DEBUG BUILD"
+msgstr "¥Ç¥Ð¥Ã¥°¥Ó¥ë¥É"
+
+msgid "VIM - Vi IMproved"
+msgstr "VIM - Vi IMproved"
+
+msgid "version "
+msgstr "version "
+
+msgid "by Bram Moolenaar et al."
+msgstr "by Bram Moolenaar ¾."
+
+msgid "Vim is open source and freely distributable"
+msgstr "Vim ¤Ï¥ª¡¼¥×¥ó¥½¡¼¥¹¤Ç¤¢¤ê¼«Í³¤ËÇÛÉÛ²Äǽ¤Ç¤¹"
+
+msgid "Help poor children in Uganda!"
+msgstr "¥¦¥¬¥ó¥À¤Î·Ã¤Þ¤ì¤Ê¤¤»Ò¶¡¤¿¤Á¤Ë±ç½õ¤ò!"
+
+msgid "type :help iccf<Enter> for information "
+msgstr "¾ÜºÙ¤Ê¾ðÊó¤Ï :help iccf<Enter> "
+
+msgid "type :q<Enter> to exit "
+msgstr "½ªÎ»¤¹¤ë¤Ë¤Ï :q<Enter> "
+
+msgid "type :help<Enter> or <F1> for on-line help"
+msgstr "¥ª¥ó¥é¥¤¥ó¥Ø¥ë¥×¤Ï :help<Enter> ¤« <F1> "
+
+msgid "type :help version8<Enter> for version info"
+msgstr "¥Ð¡¼¥¸¥ç¥ó¾ðÊó¤Ï :help version8<Enter> "
+
+msgid "Running in Vi compatible mode"
+msgstr "Vi¸ß´¹¥â¡¼¥É¤ÇÆ°ºîÃæ"
+
+msgid "type :set nocp<Enter> for Vim defaults"
+msgstr "Vim¿ä¾©Ãͤˤ¹¤ë¤Ë¤Ï :set nocp<Enter> "
+
+msgid "type :help cp-default<Enter> for info on this"
+msgstr "¾ÜºÙ¤Ê¾ðÊó¤Ï :help cp-default<Enter>"
+
+msgid "menu Help->Orphans for information "
+msgstr "¾ÜºÙ¤Ï¥á¥Ë¥å¡¼¤Î ¥Ø¥ë¥×->¸É»ù ¤ò»²¾È¤·¤Æ²¼¤µ¤¤ "
+
+msgid "Running modeless, typed text is inserted"
+msgstr "¥â¡¼¥É̵¤Ç¼Â¹ÔÃæ¡£¥¿¥¤¥×¤·¤¿Ê¸»ú¤¬ÁÞÆþ¤µ¤ì¤Þ¤¹"
+
+msgid "menu Edit->Global Settings->Toggle Insert Mode "
+msgstr "¥á¥Ë¥å¡¼¤Î ÊÔ½¸->Á´ÂÎÀßÄê->ÁÞÆþ(½é¿´¼Ô)¥â¡¼¥ÉÀÚÂØ "
+
+msgid " for two modes "
+msgstr " ¤Ç¥â¡¼¥ÉÍ­¤Ë "
+
+msgid "menu Edit->Global Settings->Toggle Vi Compatible"
+msgstr "¥á¥Ë¥å¡¼¤Î ÊÔ½¸->Á´ÂÎÀßÄê->Vi¸ß´¹¥â¡¼¥ÉÀÚÂØ "
+
+msgid " for Vim defaults "
+msgstr " ¤ÇVim¤È¤·¤ÆÆ°ºî "
+
+msgid "Sponsor Vim development!"
+msgstr "Vim¤Î³«È¯¤ò±þ±ç¤·¤Æ¤¯¤À¤µ¤¤!"
+
+msgid "Become a registered Vim user!"
+msgstr "Vim¤ÎÅÐÏ¿¥æ¡¼¥¶¡¼¤Ë¤Ê¤Ã¤Æ¤¯¤À¤µ¤¤!"
+
+msgid "type :help sponsor<Enter> for information "
+msgstr "¾ÜºÙ¤Ê¾ðÊó¤Ï :help sponsor<Enter> "
+
+msgid "type :help register<Enter> for information "
+msgstr "¾ÜºÙ¤Ê¾ðÊó¤Ï :help register<Enter> "
+
+msgid "menu Help->Sponsor/Register for information "
+msgstr "¾ÜºÙ¤Ï¥á¥Ë¥å¡¼¤Î ¥Ø¥ë¥×->¥¹¥Ý¥ó¥µ¡¼/ÅÐÏ¿ ¤ò»²¾È¤·¤Æ²¼¤µ¤¤"
+
+msgid "Already only one window"
+msgstr "´û¤Ë¥¦¥£¥ó¥É¥¦¤Ï1¤Ä¤·¤«¤¢¤ê¤Þ¤»¤ó"
+
+msgid "E441: There is no preview window"
+msgstr "E441: ¥×¥ì¥Ó¥å¡¼¥¦¥£¥ó¥É¥¦¤¬¤¢¤ê¤Þ¤»¤ó"
+
+msgid "E442: Can't split topleft and botright at the same time"
+msgstr "E442: º¸¾å¤È±¦²¼¤òƱ»þ¤Ëʬ³ä¤¹¤ë¤³¤È¤Ï¤Ç¤­¤Þ¤»¤ó"
+
+msgid "E443: Cannot rotate when another window is split"
+msgstr "E443: ¾¤Î¥¦¥£¥ó¥É¥¦¤¬Ê¬³ä¤µ¤ì¤Æ¤¤¤ë»þ¤Ë¤Ï½ç²ó¤Ç¤­¤Þ¤»¤ó"
+
+msgid "E444: Cannot close last window"
+msgstr "E444: ºÇ¸å¤Î¥¦¥£¥ó¥É¥¦¤òÊĤ¸¤ë¤³¤È¤Ï¤Ç¤­¤Þ¤»¤ó"
+
+msgid "E813: Cannot close autocmd window"
+msgstr "E813: autocmd¥¦¥£¥ó¥É¥¦¤ÏÊĤ¸¤é¤ì¤Þ¤»¤ó"
+
+msgid "E814: Cannot close window, only autocmd window would remain"
+msgstr "E814: autocmd¥¦¥£¥ó¥É¥¦¤·¤«»Ä¤é¤Ê¤¤¤¿¤á¡¢¥¦¥£¥ó¥É¥¦¤ÏÊĤ¸¤é¤ì¤Þ¤»¤ó"
+
+msgid "E445: Other window contains changes"
+msgstr "E445: ¾¤Î¥¦¥£¥ó¥É¥¦¤Ë¤ÏÊѹ¹¤¬¤¢¤ê¤Þ¤¹"
+
+msgid "E446: No file name under cursor"
+msgstr "E446: ¥«¡¼¥½¥ë¤Î²¼¤Ë¥Õ¥¡¥¤¥ë̾¤¬¤¢¤ê¤Þ¤»¤ó"
+
+#, c-format
+msgid "E447: Can't find file \"%s\" in path"
+msgstr "E447: path¤Ë¤Ï \"%s\" ¤È¤¤¤¦¥Õ¥¡¥¤¥ë¤¬¤¢¤ê¤Þ¤»¤ó"
+
+#, c-format
+msgid "E799: Invalid ID: %ld (must be greater than or equal to 1)"
+msgstr "E799: ̵¸ú¤Ê ID: %ld (1 °Ê¾å¤Ç¤Ê¤±¤ì¤Ð¤Ê¤ê¤Þ¤»¤ó)"
+
+#, c-format
+msgid "E801: ID already taken: %ld"
+msgstr "E801: ID ¤Ï¤¹¤Ç¤ËÍøÍÑÃæ¤Ç¤¹: %ld"
+
+msgid "List or number required"
+msgstr "¥ê¥¹¥È¤«¿ôÃͤ¬É¬ÍפǤ¹"
+
+#, c-format
+msgid "E802: Invalid ID: %ld (must be greater than or equal to 1)"
+msgstr "E802: ̵¸ú¤Ê ID: %ld (1 °Ê¾å¤Ç¤Ê¤±¤ì¤Ð¤Ê¤ê¤Þ¤»¤ó)"
+
+#, c-format
+msgid "E803: ID not found: %ld"
+msgstr "E803: ID ¤Ï¤¢¤ê¤Þ¤»¤ó: %ld"
+
+#, c-format
+msgid "E370: Could not load library %s"
+msgstr "E370: ¥é¥¤¥Ö¥é¥ê %s ¤ò¥í¡¼¥É¤Ç¤­¤Þ¤»¤ó¤Ç¤·¤¿"
+
+msgid "Sorry, this command is disabled: the Perl library could not be loaded."
+msgstr ""
+"¤³¤Î¥³¥Þ¥ó¥É¤Ï̵¸ú¤Ç¤¹¡¢¤´¤á¤ó¤Ê¤µ¤¤: Perl¥é¥¤¥Ö¥é¥ê¤ò¥í¡¼¥É¤Ç¤­¤Þ¤»¤ó¤Ç¤·¤¿."
+
+msgid "E299: Perl evaluation forbidden in sandbox without the Safe module"
+msgstr ""
+"E299: ¥µ¥ó¥É¥Ü¥Ã¥¯¥¹¤Ç¤Ï Safe ¥â¥¸¥å¡¼¥ë¤ò»ÈÍѤ·¤Ê¤¤Perl¥¹¥¯¥ê¥×¥È¤Ï¶Ø¤¸¤é¤ì"
+"¤Æ¤¤¤Þ¤¹"
+
+msgid "Edit with &multiple Vims"
+msgstr "Ê£¿ô¤ÎVim¤ÇÊÔ½¸¤¹¤ë (&M)"
+
+msgid "Edit with single &Vim"
+msgstr "1¤Ä¤ÎVim¤ÇÊÔ½¸¤¹¤ë (&V)"
+
+msgid "Diff with Vim"
+msgstr "Vim¤Çº¹Ê¬¤òɽ¼¨¤¹¤ë"
+
+msgid "Edit with &Vim"
+msgstr "Vim¤ÇÊÔ½¸¤¹¤ë (&V)"
+
+msgid "Edit with existing Vim"
+msgstr "µ¯Æ°ºÑ¤ÎVim¤ÇÊÔ½¸¤¹¤ë"
+
+msgid "Edit with existing Vim - "
+msgstr "µ¯Æ°ºÑ¤ÎVim¤ÇÊÔ½¸¤¹¤ë - "
+
+msgid "Edits the selected file(s) with Vim"
+msgstr "ÁªÂò¤·¤¿¥Õ¥¡¥¤¥ë¤òVim¤ÇÊÔ½¸¤¹¤ë"
+
+msgid "Error creating process: Check if gvim is in your path!"
+msgstr "¥×¥í¥»¥¹¤ÎºîÀ®¤Ë¼ºÇÔ: gvim¤¬´Ä¶­ÊÑ¿ôPATH¾å¤Ë¤¢¤ë¤«³Îǧ¤·¤Æ¤¯¤À¤µ¤¤!"
+
+msgid "gvimext.dll error"
+msgstr "gvimext.dll ¥¨¥é¡¼"
+
+msgid "Path length too long!"
+msgstr "¥Ñ¥¹¤¬Ä¹²á¤®¤Þ¤¹!"
+
+msgid "--No lines in buffer--"
+msgstr "--¥Ð¥Ã¥Õ¥¡¤Ë¹Ô¤¬¤¢¤ê¤Þ¤»¤ó--"
+
+msgid "E470: Command aborted"
+msgstr "E470: ¥³¥Þ¥ó¥É¤¬ÃæÃǤµ¤ì¤Þ¤·¤¿"
+
+msgid "E471: Argument required"
+msgstr "E471: °ú¿ô¤¬É¬ÍפǤ¹"
+
+msgid "E10: \\ should be followed by /, ? or &"
+msgstr "E10: \\ ¤Î¸å¤Ï / ¤« ? ¤« & ¤Ç¤Ê¤±¤ì¤Ð¤Ê¤ê¤Þ¤»¤ó"
+
+msgid "E11: Invalid in command-line window; <CR> executes, CTRL-C quits"
+msgstr "E11: ¥³¥Þ¥ó¥É¥é¥¤¥ó¤Ç¤Ï̵¸ú¤Ç¤¹; <CR>¤Ç¼Â¹Ô, CTRL-C¤Ç¤ä¤á¤ë"
+
+msgid "E12: Command not allowed from exrc/vimrc in current dir or tag search"
+msgstr ""
+"E12: ¸½ºß¤Î¥Ç¥£¥ì¥¯¥È¥ê¤ä¥¿¥°¸¡º÷¤Ç¤Ïexrc/vimrc¤Î¥³¥Þ¥ó¥É¤Ïµö²Ä¤µ¤ì¤Þ¤»¤ó"
+
+msgid "E171: Missing :endif"
+msgstr "E171: :endif ¤¬¤¢¤ê¤Þ¤»¤ó"
+
+msgid "E600: Missing :endtry"
+msgstr "E600: :endtry ¤¬¤¢¤ê¤Þ¤»¤ó"
+
+msgid "E170: Missing :endwhile"
+msgstr "E170: :endwhile ¤¬¤¢¤ê¤Þ¤»¤ó"
+
+msgid "E170: Missing :endfor"
+msgstr "E170: :endfor ¤¬¤¢¤ê¤Þ¤»¤ó"
+
+msgid "E588: :endwhile without :while"
+msgstr "E588: :while ¤Î¤Ê¤¤ :endwhile ¤¬¤¢¤ê¤Þ¤¹"
+
+msgid "E588: :endfor without :for"
+msgstr "E588: :endfor ¤Î¤Ê¤¤ :for ¤¬¤¢¤ê¤Þ¤¹"
+
+msgid "E13: File exists (add ! to override)"
+msgstr "E13: ¥Õ¥¡¥¤¥ë¤¬Â¸ºß¤·¤Þ¤¹ (! ¤òÄɲäǾå½ñ)"
+
+msgid "E472: Command failed"
+msgstr "E472: ¥³¥Þ¥ó¥É¤¬¼ºÇÔ¤·¤Þ¤·¤¿"
+
+#, c-format
+msgid "E234: Unknown fontset: %s"
+msgstr "E234: ̤ÃΤΥե©¥ó¥È¥»¥Ã¥È: %s"
+
+#, c-format
+msgid "E235: Unknown font: %s"
+msgstr "E235: ̤ÃΤΥե©¥ó¥È: %s"
+
+#, c-format
+msgid "E236: Font \"%s\" is not fixed-width"
+msgstr "E236: ¥Õ¥©¥ó¥È \"%s\" ¤Ï¸ÇÄêÉý¤Ç¤Ï¤¢¤ê¤Þ¤»¤ó"
+
+msgid "E473: Internal error"
+msgstr "E473: ÆâÉô¥¨¥é¡¼¤Ç¤¹"
+
+#, c-format
+msgid "E685: Internal error: %s"
+msgstr "E685: ÆâÉô¥¨¥é¡¼¤Ç¤¹: %s"
+
+msgid "Interrupted"
+msgstr "³ä¹þ¤Þ¤ì¤Þ¤·¤¿"
+
+msgid "E14: Invalid address"
+msgstr "E14: ̵¸ú¤Ê¥¢¥É¥ì¥¹¤Ç¤¹"
+
+msgid "E474: Invalid argument"
+msgstr "E474: ̵¸ú¤Ê°ú¿ô¤Ç¤¹"
+
+#, c-format
+msgid "E475: Invalid argument: %s"
+msgstr "E475: ̵¸ú¤Ê°ú¿ô¤Ç¤¹: %s"
+
+#, c-format
+msgid "E475: Invalid value for argument %s"
+msgstr "E475: °ú¿ô %s ¤ËÂФ·¤Æ̵¸ú¤ÊÃͤǤ¹"
+
+#, c-format
+msgid "E475: Invalid value for argument %s: %s"
+msgstr "E475: °ú¿ô %s ¤ËÂФ·¤Æ̵¸ú¤ÊÃͤǤ¹: %s"
+
+#, c-format
+msgid "E15: Invalid expression: %s"
+msgstr "E15: ̵¸ú¤Ê¼°¤Ç¤¹: %s"
+
+msgid "E16: Invalid range"
+msgstr "E16: ̵¸ú¤ÊÈϰϤǤ¹"
+
+msgid "E476: Invalid command"
+msgstr "E476: ̵¸ú¤Ê¥³¥Þ¥ó¥É¤Ç¤¹"
+
+#, c-format
+msgid "E17: \"%s\" is a directory"
+msgstr "E17: \"%s\" ¤Ï¥Ç¥£¥ì¥¯¥È¥ê¤Ç¤¹"
+
+#, c-format
+msgid "E364: Library call failed for \"%s()\""
+msgstr "E364: \"%s\"() ¤Î¥é¥¤¥Ö¥é¥ê¸Æ½Ð¤Ë¼ºÇÔ¤·¤Þ¤·¤¿"
+
+msgid "E667: Fsync failed"
+msgstr "E667: fsync ¤Ë¼ºÇÔ¤·¤Þ¤·¤¿"
+
+#, c-format
+msgid "E448: Could not load library function %s"
+msgstr "E448: ¥é¥¤¥Ö¥é¥ê¤Î´Ø¿ô %s ¤ò¥í¡¼¥É¤Ç¤­¤Þ¤»¤ó¤Ç¤·¤¿"
+
+msgid "E19: Mark has invalid line number"
+msgstr "E19: ¥Þ¡¼¥¯¤Ë̵¸ú¤Ê¹ÔÈֹ椬»ØÄꤵ¤ì¤Æ¤¤¤Þ¤·¤¿"
+
+msgid "E20: Mark not set"
+msgstr "E20: ¥Þ¡¼¥¯¤ÏÀßÄꤵ¤ì¤Æ¤¤¤Þ¤»¤ó"
+
+msgid "E21: Cannot make changes, 'modifiable' is off"
+msgstr "E21: 'modifiable' ¤¬¥ª¥Õ¤Ê¤Î¤Ç¡¢Êѹ¹¤Ç¤­¤Þ¤»¤ó"
+
+msgid "E22: Scripts nested too deep"
+msgstr "E22: ¥¹¥¯¥ê¥×¥È¤ÎÆþ¤ì»Ò¤¬¿¼²á¤®¤Þ¤¹"
+
+msgid "E23: No alternate file"
+msgstr "E23: Éû¥Õ¥¡¥¤¥ë¤Ï¤¢¤ê¤Þ¤»¤ó"
+
+msgid "E24: No such abbreviation"
+msgstr "E24: ¤½¤Î¤è¤¦¤Êû½ÌÆþÎϤϤ¢¤ê¤Þ¤»¤ó"
+
+msgid "E477: No ! allowed"
+msgstr "E477: ! ¤Ïµö²Ä¤µ¤ì¤Æ¤¤¤Þ¤»¤ó"
+
+msgid "E25: GUI cannot be used: Not enabled at compile time"
+msgstr "E25: GUI¤Ï»ÈÍÑÉÔ²Äǽ¤Ç¤¹: ¥³¥ó¥Ñ¥¤¥ë»þ¤Ë̵¸ú¤Ë¤µ¤ì¤Æ¤¤¤Þ¤¹"
+
+msgid "E26: Hebrew cannot be used: Not enabled at compile time\n"
+msgstr "E26: ¥Ø¥Ö¥é¥¤¸ì¤Ï»ÈÍÑÉÔ²Äǽ¤Ç¤¹: ¥³¥ó¥Ñ¥¤¥ë»þ¤Ë̵¸ú¤Ë¤µ¤ì¤Æ¤¤¤Þ¤¹\n"
+
+msgid "E27: Farsi cannot be used: Not enabled at compile time\n"
+msgstr "E27: ¥Ú¥ë¥·¥¢¸ì¤Ï»ÈÍÑÉÔ²Äǽ¤Ç¤¹: ¥³¥ó¥Ñ¥¤¥ë»þ¤Ë̵¸ú¤Ë¤µ¤ì¤Æ¤¤¤Þ¤¹\n"
+
+msgid "E800: Arabic cannot be used: Not enabled at compile time\n"
+msgstr "E800: ¥¢¥é¥Ó¥¢¸ì¤Ï»ÈÍÑÉÔ²Äǽ¤Ç¤¹: ¥³¥ó¥Ñ¥¤¥ë»þ¤Ë̵¸ú¤Ë¤µ¤ì¤Æ¤¤¤Þ¤¹\n"
+
+#, c-format
+msgid "E28: No such highlight group name: %s"
+msgstr "E28: ¤½¤Î¤è¤¦¤Ê̾¤Î¥Ï¥¤¥é¥¤¥È¥°¥ë¡¼¥×¤Ï¤¢¤ê¤Þ¤»¤ó: %s"
+
+msgid "E29: No inserted text yet"
+msgstr "E29: ¤Þ¤À¥Æ¥­¥¹¥È¤¬ÁÞÆþ¤µ¤ì¤Æ¤¤¤Þ¤»¤ó"
+
+msgid "E30: No previous command line"
+msgstr "E30: °ÊÁ°¤Ë¥³¥Þ¥ó¥É¹Ô¤¬¤¢¤ê¤Þ¤»¤ó"
+
+msgid "E31: No such mapping"
+msgstr "E31: ¤½¤Î¤è¤¦¤Ê¥Þ¥Ã¥Ô¥ó¥°¤Ï¤¢¤ê¤Þ¤»¤ó"
+
+msgid "E479: No match"
+msgstr "E479: ³ºÅö¤Ï¤¢¤ê¤Þ¤»¤ó"
+
+#, c-format
+msgid "E480: No match: %s"
+msgstr "E480: ³ºÅö¤Ï¤¢¤ê¤Þ¤»¤ó: %s"
+
+msgid "E32: No file name"
+msgstr "E32: ¥Õ¥¡¥¤¥ë̾¤¬¤¢¤ê¤Þ¤»¤ó"
+
+msgid "E33: No previous substitute regular expression"
+msgstr "E33: Àµµ¬É½¸½ÃÖ´¹¤¬¤Þ¤À¼Â¹Ô¤µ¤ì¤Æ¤¤¤Þ¤»¤ó"
+
+msgid "E34: No previous command"
+msgstr "E34: ¥³¥Þ¥ó¥É¤¬¤Þ¤À¼Â¹Ô¤µ¤ì¤Æ¤¤¤Þ¤»¤ó"
+
+msgid "E35: No previous regular expression"
+msgstr "E35: Àµµ¬É½¸½¤¬¤Þ¤À¼Â¹Ô¤µ¤ì¤Æ¤¤¤Þ¤»¤ó"
+
+msgid "E481: No range allowed"
+msgstr "E481: ÈÏ°Ï»ØÄê¤Ïµö²Ä¤µ¤ì¤Æ¤¤¤Þ¤»¤ó"
+
+msgid "E36: Not enough room"
+msgstr "E36: ¥¦¥£¥ó¥É¥¦¤Ë½½Ê¬¤Ê¹â¤µ¤â¤·¤¯¤ÏÉý¤¬¤¢¤ê¤Þ¤»¤ó"
+
+#, c-format
+msgid "E247: no registered server named \"%s\""
+msgstr "E247: %s ¤È¤¤¤¦Ì¾Á°¤ÎÅÐÏ¿¤µ¤ì¤¿¥µ¡¼¥Ð¡¼¤Ï¤¢¤ê¤Þ¤»¤ó"
+
+#, c-format
+msgid "E482: Can't create file %s"
+msgstr "E482: ¥Õ¥¡¥¤¥ë %s ¤òºîÀ®¤Ç¤­¤Þ¤»¤ó"
+
+msgid "E483: Can't get temp file name"
+msgstr "E483: °ì»þ¥Õ¥¡¥¤¥ë¤Î̾Á°¤ò¼èÆÀ¤Ç¤­¤Þ¤»¤ó"
+
+#, c-format
+msgid "E484: Can't open file %s"
+msgstr "E484: ¥Õ¥¡¥¤¥ë \"%s\" ¤ò³«¤±¤Þ¤»¤ó"
+
+#, c-format
+msgid "E485: Can't read file %s"
+msgstr "E485: ¥Õ¥¡¥¤¥ë %s ¤òÆɹþ¤á¤Þ¤»¤ó"
+
+msgid "E38: Null argument"
+msgstr "E38: °ú¿ô¤¬¶õ¤Ç¤¹"
+
+msgid "E39: Number expected"
+msgstr "E39: ¿ôÃͤ¬Í׵ᤵ¤ì¤Æ¤¤¤Þ¤¹"
+
+#, c-format
+msgid "E40: Can't open errorfile %s"
+msgstr "E40: ¥¨¥é¡¼¥Õ¥¡¥¤¥ë %s ¤ò³«¤±¤Þ¤»¤ó"
+
+msgid "E233: cannot open display"
+msgstr "E233: ¥Ç¥£¥¹¥×¥ì¥¤¤ò³«¤±¤Þ¤»¤ó"
+
+msgid "E41: Out of memory!"
+msgstr "E41: ¥á¥â¥ê¤¬¿Ô¤­²Ì¤Æ¤Þ¤·¤¿!"
+
+msgid "Pattern not found"
+msgstr "¥Ñ¥¿¡¼¥ó¤Ï¸«¤Ä¤«¤ê¤Þ¤»¤ó¤Ç¤·¤¿"
+
+#, c-format
+msgid "E486: Pattern not found: %s"
+msgstr "E486: ¥Ñ¥¿¡¼¥ó¤Ï¸«¤Ä¤«¤ê¤Þ¤»¤ó¤Ç¤·¤¿: %s"
+
+msgid "E487: Argument must be positive"
+msgstr "E487: °ú¿ô¤ÏÀµ¤ÎÃͤǤʤ±¤ì¤Ð¤Ê¤ê¤Þ¤»¤ó"
+
+msgid "E459: Cannot go back to previous directory"
+msgstr "E459: Á°¤Î¥Ç¥£¥ì¥¯¥È¥ê¤ËÌá¤ì¤Þ¤»¤ó"
+
+msgid "E42: No Errors"
+msgstr "E42: ¥¨¥é¡¼¤Ï¤¢¤ê¤Þ¤»¤ó"
+
+msgid "E776: No location list"
+msgstr "E776: ¥í¥±¡¼¥·¥ç¥ó¥ê¥¹¥È¤Ï¤¢¤ê¤Þ¤»¤ó"
+
+msgid "E43: Damaged match string"
+msgstr "E43: ³ºÅöʸ»úÎó¤¬ÇË»¤·¤Æ¤¤¤Þ¤¹"
+
+msgid "E44: Corrupted regexp program"
+msgstr "E44: ÉÔÀµ¤ÊÀµµ¬É½¸½¥×¥í¥°¥é¥à¤Ç¤¹"
+
+msgid "E45: 'readonly' option is set (add ! to override)"
+msgstr "E45: 'readonly' ¥ª¥×¥·¥ç¥ó¤¬ÀßÄꤵ¤ì¤Æ¤¤¤Þ¤¹ (! ¤òÄɲäǾå½ñ¤­)"
+
+#, c-format
+msgid "E46: Cannot change read-only variable \"%s\""
+msgstr "E46: ÆɼèÀìÍÑÊÑ¿ô \"%s\" ¤Ë¤ÏÃͤòÀßÄê¤Ç¤­¤Þ¤»¤ó"
+
+#, c-format
+msgid "E794: Cannot set variable in the sandbox: \"%s\""
+msgstr "E794: ¥µ¥ó¥É¥Ü¥Ã¥¯¥¹¤Ç¤ÏÊÑ¿ô \"%s\" ¤ËÃͤòÀßÄê¤Ç¤­¤Þ¤»¤ó"
+
+msgid "E713: Cannot use empty key for Dictionary"
+msgstr "E713: ¼­½ñ·¿¤Ë¶õ¤Î¥­¡¼¤ò»È¤¦¤³¤È¤Ï¤Ç¤­¤Þ¤»¤ó"
+
+msgid "E715: Dictionary required"
+msgstr "E715: ¼­½ñ·¿¤¬É¬ÍפǤ¹"
+
+#, c-format
+msgid "E684: list index out of range: %ld"
+msgstr "E684: ¥ê¥¹¥È¤Î¥¤¥ó¥Ç¥Ã¥¯¥¹¤¬Èϰϳ°¤Ç¤¹: %ld"
+
+#, c-format
+msgid "E118: Too many arguments for function: %s"
+msgstr "E118: ´Ø¿ô¤Î°ú¿ô¤¬Â¿²á¤®¤Þ¤¹: %s"
+
+#, c-format
+msgid "E716: Key not present in Dictionary: %s"
+msgstr "E716: ¼­½ñ·¿¤Ë¥­¡¼¤¬Â¸ºß¤·¤Þ¤»¤ó: %s"
+
+msgid "E714: List required"
+msgstr "E714: ¥ê¥¹¥È·¿¤¬É¬ÍפǤ¹"
+
+#, c-format
+msgid "E712: Argument of %s must be a List or Dictionary"
+msgstr "E712: %s ¤Î°ú¿ô¤Ï¥ê¥¹¥È·¿¤Þ¤¿¤Ï¼­½ñ·¿¤Ç¤Ê¤±¤ì¤Ð¤Ê¤ê¤Þ¤»¤ó"
+
+msgid "E47: Error while reading errorfile"
+msgstr "E47: ¥¨¥é¡¼¥Õ¥¡¥¤¥ë¤ÎÆɹþÃæ¤Ë¥¨¥é¡¼¤¬È¯À¸¤·¤Þ¤·¤¿"
+
+msgid "E48: Not allowed in sandbox"
+msgstr "E48: ¥µ¥ó¥É¥Ü¥Ã¥¯¥¹¤Ç¤Ïµö¤µ¤ì¤Þ¤»¤ó"
+
+msgid "E523: Not allowed here"
+msgstr "E523: ¤³¤³¤Ç¤Ïµö²Ä¤µ¤ì¤Þ¤»¤ó"
+
+msgid "E359: Screen mode setting not supported"
+msgstr "E359: ¥¹¥¯¥ê¡¼¥ó¥â¡¼¥É¤ÎÀßÄê¤Ë¤ÏÂбþ¤·¤Æ¤¤¤Þ¤»¤ó"
+
+msgid "E49: Invalid scroll size"
+msgstr "E49: ̵¸ú¤Ê¥¹¥¯¥í¡¼¥ëÎ̤Ǥ¹"
+
+msgid "E91: 'shell' option is empty"
+msgstr "E91: 'shell' ¥ª¥×¥·¥ç¥ó¤¬¶õ¤Ç¤¹"
+
+msgid "E255: Couldn't read in sign data!"
+msgstr "E255: sign ¤Î¥Ç¡¼¥¿¤òÆɹþ¤á¤Þ¤»¤ó¤Ç¤·¤¿"
+
+msgid "E72: Close error on swap file"
+msgstr "E72: ¥¹¥ï¥Ã¥×¥Õ¥¡¥¤¥ë¤Î¥¯¥í¡¼¥º»þ¥¨¥é¡¼¤Ç¤¹"
+
+msgid "E73: tag stack empty"
+msgstr "E73: ¥¿¥°¥¹¥¿¥Ã¥¯¤¬¶õ¤Ç¤¹"
+
+msgid "E74: Command too complex"
+msgstr "E74: ¥³¥Þ¥ó¥É¤¬Ê£»¨²á¤®¤Þ¤¹"
+
+msgid "E75: Name too long"
+msgstr "E75: ̾Á°¤¬Ä¹²á¤®¤Þ¤¹"
+
+msgid "E76: Too many ["
+msgstr "E76: [ ¤¬Â¿²á¤®¤Þ¤¹"
+
+msgid "E77: Too many file names"
+msgstr "E77: ¥Õ¥¡¥¤¥ë̾¤¬Â¿²á¤®¤Þ¤¹"
+
+msgid "E488: Trailing characters"
+msgstr "E488: ;ʬ¤Êʸ»ú¤¬¸å¤í¤Ë¤¢¤ê¤Þ¤¹"
+
+msgid "E78: Unknown mark"
+msgstr "E78: ̤ÃΤΥޡ¼¥¯"
+
+msgid "E79: Cannot expand wildcards"
+msgstr "E79: ¥ï¥¤¥ë¥É¥«¡¼¥É¤òŸ³«¤Ç¤­¤Þ¤»¤ó"
+
+msgid "E591: 'winheight' cannot be smaller than 'winminheight'"
+msgstr "E591: 'winheight' ¤Ï 'winminheight' ¤è¤ê¾®¤µ¤¯¤Ç¤­¤Þ¤»¤ó"
+
+msgid "E592: 'winwidth' cannot be smaller than 'winminwidth'"
+msgstr "E592: 'winwidth' ¤Ï 'winminwidth' ¤è¤ê¾®¤µ¤¯¤Ç¤­¤Þ¤»¤ó"
+
+msgid "E80: Error while writing"
+msgstr "E80: ½ñ¹þ¤ßÃæ¤Î¥¨¥é¡¼"
+
+msgid "E939: Positive count required"
+msgstr "E939: Àµ¤Î¥«¥¦¥ó¥È¤¬É¬ÍפǤ¹"
+
+msgid "E81: Using <SID> not in a script context"
+msgstr "E81: ¥¹¥¯¥ê¥×¥È°Ê³°¤Ç<SID>¤¬»È¤ï¤ì¤Þ¤·¤¿"
+
+msgid "E449: Invalid expression received"
+msgstr "E449: ̵¸ú¤Ê¼°¤ò¼õ¤±¼è¤ê¤Þ¤·¤¿"
+
+msgid "E463: Region is guarded, cannot modify"
+msgstr "E463: Îΰ褬Êݸ¤ì¤Æ¤¤¤ë¤Î¤Ç¡¢Êѹ¹¤Ç¤­¤Þ¤»¤ó"
+
+msgid "E744: NetBeans does not allow changes in read-only files"
+msgstr "E744: NetBeans ¤ÏÆɹþÀìÍÑ¥Õ¥¡¥¤¥ë¤òÊѹ¹¤¹¤ë¤³¤È¤òµö¤·¤Þ¤»¤ó"
+
+msgid "E363: pattern uses more memory than 'maxmempattern'"
+msgstr "E363: ¥Ñ¥¿¡¼¥ó¤¬ 'maxmempattern' °Ê¾å¤Î¥á¥â¥ê¤ò»ÈÍѤ·¤Þ¤¹"
+
+msgid "E749: empty buffer"
+msgstr "E749: ¥Ð¥Ã¥Õ¥¡¤¬¶õ¤Ç¤¹"
+
+#, c-format
+msgid "E86: Buffer %ld does not exist"
+msgstr "E86: ¥Ð¥Ã¥Õ¥¡ %ld ¤Ï¤¢¤ê¤Þ¤»¤ó"
+
+msgid "E682: Invalid search pattern or delimiter"
+msgstr "E682: ¸¡º÷¥Ñ¥¿¡¼¥ó¤«¶èÀڤ국¹æ¤¬ÉÔÀµ¤Ç¤¹"
+
+msgid "E139: File is loaded in another buffer"
+msgstr "E139: Ʊ¤¸Ì¾Á°¤Î¥Õ¥¡¥¤¥ë¤¬Â¾¤Î¥Ð¥Ã¥Õ¥¡¤ÇÆɹþ¤Þ¤ì¤Æ¤¤¤Þ¤¹"
+
+#, c-format
+msgid "E764: Option '%s' is not set"
+msgstr "E764: ¥ª¥×¥·¥ç¥ó '%s' ¤ÏÀßÄꤵ¤ì¤Æ¤¤¤Þ¤»¤ó"
+
+msgid "E850: Invalid register name"
+msgstr "E850: ̵¸ú¤Ê¥ì¥¸¥¹¥¿Ì¾¤Ç¤¹"
+
+#, c-format
+msgid "E919: Directory not found in '%s': \"%s\""
+msgstr "E919: ¥Ç¥£¥ì¥¯¥È¥ê¤¬ '%s' ¤ÎÃæ¤Ë¤¢¤ê¤Þ¤»¤ó: \"%s\""
+
+msgid "E952: Autocommand caused recursive behavior"
+msgstr "E952: Autocommand¤¬ºÆµ¢¤ò°ú¤­µ¯¤³¤·¤Þ¤·¤¿"
+
+msgid "search hit TOP, continuing at BOTTOM"
+msgstr "¾å¤Þ¤Ç¸¡º÷¤·¤¿¤Î¤Ç²¼¤ËÌá¤ê¤Þ¤¹"
+
+msgid "search hit BOTTOM, continuing at TOP"
+msgstr "²¼¤Þ¤Ç¸¡º÷¤·¤¿¤Î¤Ç¾å¤ËÌá¤ê¤Þ¤¹"
+
+#, c-format
+msgid "Need encryption key for \"%s\""
+msgstr "°Å¹æ¥­¡¼¤¬É¬ÍפǤ¹: \"%s\""
+
+msgid "empty keys are not allowed"
+msgstr "¶õ¤Î¥­¡¼¤Ïµö²Ä¤µ¤ì¤Æ¤¤¤Þ¤»¤ó"
+
+msgid "dictionary is locked"
+msgstr "¼­½ñ¤Ï¥í¥Ã¥¯¤µ¤ì¤Æ¤¤¤Þ¤¹"
+
+msgid "list is locked"
+msgstr "¥ê¥¹¥È¤Ï¥í¥Ã¥¯¤µ¤ì¤Æ¤¤¤Þ¤¹"
+
+#, c-format
+msgid "failed to add key '%s' to dictionary"
+msgstr "¼­½ñ¤Ë¥­¡¼ '%s' ¤òÄɲ乤ë¤Î¤Ë¼ºÇÔ¤·¤Þ¤·¤¿"
+
+#, c-format
+msgid "index must be int or slice, not %s"
+msgstr "¥¤¥ó¥Ç¥Ã¥¯¥¹¤Ï %s ¤Ç¤Ï¤Ê¤¯À°¿ô¤«¥¹¥é¥¤¥¹¤Ë¤·¤Æ¤¯¤À¤µ¤¤"
+
+#, c-format
+msgid "expected str() or unicode() instance, but got %s"
+msgstr "str() ¤â¤·¤¯¤Ï unicode() ¤Î¥¤¥ó¥¹¥¿¥ó¥¹¤¬´üÂÔ¤µ¤ì¤Æ¤¤¤ë¤Î¤Ë %s ¤Ç¤·¤¿"
+
+#, c-format
+msgid "expected bytes() or str() instance, but got %s"
+msgstr "bytes() ¤â¤·¤¯¤Ï str() ¤Î¥¤¥ó¥¹¥¿¥ó¥¹¤¬´üÂÔ¤µ¤ì¤Æ¤¤¤ë¤Î¤Ë %s ¤Ç¤·¤¿"
+
+#, c-format
+msgid ""
+"expected int(), long() or something supporting coercing to long(), but got %s"
+msgstr "long() ¤«¤½¤ì¤ØÊÑ´¹²Äǽ¤Ê¤â¤Î¤¬´üÂÔ¤µ¤ì¤Æ¤¤¤ë¤Î¤Ë %s ¤Ç¤·¤¿"
+
+#, c-format
+msgid "expected int() or something supporting coercing to int(), but got %s"
+msgstr "int() ¤«¤½¤ì¤ØÊÑ´¹²Äǽ¤Ê¤â¤Î¤¬´üÂÔ¤µ¤ì¤Æ¤¤¤ë¤Î¤Ë %s ¤Ç¤·¤¿"
+
+msgid "value is too large to fit into C int type"
+msgstr "C¸À¸ì¤Î int ·¿¤È¤·¤Æ¤ÏÃͤ¬Â礭²á¤®¤Þ¤¹"
+
+msgid "value is too small to fit into C int type"
+msgstr "C¸À¸ì¤Î int ·¿¤È¤·¤Æ¤ÏÃͤ¬¾®¤µ²á¤®¤Þ¤¹"
+
+msgid "number must be greater than zero"
+msgstr "¿ôÃÍ¤Ï 0 ¤è¤êÂ礭¤¯¤Ê¤±¤ì¤Ð¤Ê¤ê¤Þ¤»¤ó"
+
+msgid "number must be greater or equal to zero"
+msgstr "¿ôÃÍ¤Ï 0 ¤«¤½¤ì°Ê¾å¤Ç¤Ê¤±¤ì¤Ð¤Ê¤ê¤Þ¤»¤ó"
+
+msgid "can't delete OutputObject attributes"
+msgstr "OutputObject°À­¤ò¾Ã¤»¤Þ¤»¤ó"
+
+#, c-format
+msgid "invalid attribute: %s"
+msgstr "̵¸ú¤Ê°À­¤Ç¤¹: %s"
+
+msgid "E264: Python: Error initialising I/O objects"
+msgstr "E264: Python: I/O¥ª¥Ö¥¸¥§¥¯¥È¤Î½é´ü²½¥¨¥é¡¼"
+
+msgid "failed to change directory"
+msgstr "¼­½ñ¤ÎÊѹ¹¤Ë¼ºÇÔ¤·¤Þ¤·¤¿"
+
+#, c-format
+msgid "expected 3-tuple as imp.find_module() result, but got %s"
+msgstr "imp.find_module() ¤¬ %s ¤òÊÖ¤·¤Þ¤·¤¿ (´üÂÔÃÍ: 3 Í×ÁǤΥ¿¥×¥ë)"
+
+#, c-format
+msgid "expected 3-tuple as imp.find_module() result, but got tuple of size %d"
+msgstr "imp.find_module() ¤¬ %d Í×ÁǤΥ¿¥×¥ë¤òÊÖ¤·¤Þ¤·¤¿ (´üÂÔÃÍ: 3)"
+
+msgid "internal error: imp.find_module returned tuple with NULL"
+msgstr "ÆâÉô¥¨¥é¡¼: imp.find_module ¤¬ NULL ¤ò´Þ¤à¥¿¥×¥ë¤òÊÖ¤·¤Þ¤·¤¿"
+
+msgid "cannot delete vim.Dictionary attributes"
+msgstr "vim.Dictionary°À­¤Ï¾Ã¤»¤Þ¤»¤ó"
+
+msgid "cannot modify fixed dictionary"
+msgstr "¸ÇÄꤵ¤ì¤¿¼­½ñ¤ÏÊѹ¹¤Ç¤­¤Þ¤»¤ó"
+
+#, c-format
+msgid "cannot set attribute %s"
+msgstr "°À­ %s ¤ÏÀßÄê¤Ç¤­¤Þ¤»¤ó"
+
+msgid "hashtab changed during iteration"
+msgstr "¥¤¥Æ¥ì¡¼¥·¥ç¥óÃæ¤Ë hashtab ¤¬Êѹ¹¤µ¤ì¤Þ¤·¤¿"
+
+#, c-format
+msgid "expected sequence element of size 2, but got sequence of size %d"
+msgstr "¥·¡¼¥±¥ó¥¹¤ÎÍ×ÁÇ¿ô¤Ë¤Ï 2 ¤¬´üÂÔ¤µ¤ì¤Æ¤¤¤Þ¤·¤¿¤¬ %d ¤Ç¤·¤¿"
+
+msgid "list constructor does not accept keyword arguments"
+msgstr "¥ê¥¹¥È¤Î¥³¥ó¥¹¥È¥é¥¯¥¿¤Ï¥­¡¼¥ï¡¼¥É°ú¿ô¤ò¼õ¤±ÉÕ¤±¤Þ¤»¤ó"
+
+msgid "list index out of range"
+msgstr "¥ê¥¹¥ÈÈϰϳ°¤Î¥¤¥ó¥Ç¥Ã¥¯¥¹¤Ç¤¹"
+
+#, c-format
+msgid "internal error: failed to get vim list item %d"
+msgstr "ÆâÉô¥¨¥é¡¼: vim¤Î¥ê¥¹¥ÈÍ×ÁÇ %d ¤Î¼èÆÀ¤Ë¼ºÇÔ¤·¤Þ¤·¤¿"
+
+msgid "slice step cannot be zero"
+msgstr "¥¹¥é¥¤¥¹¤Î¥¹¥Æ¥Ã¥×¤Ë 0 ¤Ï»ØÄê¤Ç¤­¤Þ¤»¤ó"
+
+#, c-format
+msgid "attempt to assign sequence of size greater than %d to extended slice"
+msgstr "Ťµ %d ¤Î³ÈÄ¥¥¹¥é¥¤¥¹¤Ë¡¢¤è¤êŤ¤¥¹¥é¥¤¥¹¤ò³ä¤êÅö¤Æ¤è¤¦¤È¤·¤Þ¤·¤¿"
+
+#, c-format
+msgid "internal error: no vim list item %d"
+msgstr "ÆâÉô¥¨¥é¡¼: vim¤Î¥ê¥¹¥ÈÍ×ÁÇ %d ¤Ï¤¢¤ê¤Þ¤»¤ó"
+
+msgid "internal error: not enough list items"
+msgstr "ÆâÉô¥¨¥é¡¼: ¥ê¥¹¥È¤Ë½½Ê¬¤ÊÍ×ÁǤ¬¤¢¤ê¤Þ¤»¤ó"
+
+msgid "internal error: failed to add item to list"
+msgstr "ÆâÉô¥¨¥é¡¼: ¥ê¥¹¥È¤Ø¤ÎÍ×ÁÇÄɲä˼ºÇÔ¤·¤Þ¤·¤¿"
+
+#, c-format
+msgid "attempt to assign sequence of size %d to extended slice of size %d"
+msgstr "Ťµ %d ¤Î¥¹¥é¥¤¥¹¤ò %d ¤Î³ÈÄ¥¥¹¥é¥¤¥¹¤Ë³ä¤êÅö¤Æ¤è¤¦¤È¤·¤Þ¤·¤¿"
+
+msgid "failed to add item to list"
+msgstr "¥ê¥¹¥È¤Ø¤ÎÍ×ÁÇÄɲä˼ºÇÔ¤·¤Þ¤·¤¿"
+
+msgid "cannot delete vim.List attributes"
+msgstr "vim.List °À­¤Ï¾Ã¤»¤Þ¤»¤ó"
+
+msgid "cannot modify fixed list"
+msgstr "¸ÇÄꤵ¤ì¤¿¥ê¥¹¥È¤ÏÊѹ¹¤Ç¤­¤Þ¤»¤ó"
+
+#, c-format
+msgid "unnamed function %s does not exist"
+msgstr "̵̾´Ø¿ô %s ¤Ï¸ºß¤·¤Þ¤»¤ó"
+
+#, c-format
+msgid "function %s does not exist"
+msgstr "´Ø¿ô %s ¤¬¤¢¤ê¤Þ¤»¤ó"
+
+#, c-format
+msgid "failed to run function %s"
+msgstr "´Ø¿ô %s ¤Î¼Â¹Ô¤Ë¼ºÇÔ¤·¤Þ¤·¤¿"
+
+msgid "unable to get option value"
+msgstr "¥ª¥×¥·¥ç¥ó¤ÎÃͤϼèÆÀ¤Ç¤­¤Þ¤»¤ó"
+
+msgid "internal error: unknown option type"
+msgstr "ÆâÉô¥¨¥é¡¼: ̤ÃΤΥª¥×¥·¥ç¥ó·¿¤Ç¤¹"
+
+msgid "problem while switching windows"
+msgstr "¥¦¥£¥ó¥É¥¦¤òÀÚ´¹Ãæ¤ËÌäÂ꤬ȯÀ¸¤·¤Þ¤·¤¿"
+
+#, c-format
+msgid "unable to unset global option %s"
+msgstr "¥°¥í¡¼¥Ð¥ë¥ª¥×¥·¥ç¥ó %s ¤ÎÀßÄê²ò½ü¤Ï¤Ç¤­¤Þ¤»¤ó"
+
+#, c-format
+msgid "unable to unset option %s which does not have global value"
+msgstr "¥°¥í¡¼¥Ð¥ë¤ÊÃͤÎ̵¤¤¥ª¥×¥·¥ç¥ó %s ¤ÎÀßÄê²ò½ü¤Ï¤Ç¤­¤Þ¤»¤ó"
+
+msgid "attempt to refer to deleted tab page"
+msgstr "ºï½ü¤µ¤ì¤¿¥¿¥Ö¤ò»²¾È¤·¤è¤¦¤È¤·¤Þ¤·¤¿"
+
+msgid "no such tab page"
+msgstr "¤½¤Î¤è¤¦¤Ê¥¿¥Ö¥Ú¡¼¥¸¤Ï¤¢¤ê¤Þ¤»¤ó"
+
+msgid "attempt to refer to deleted window"
+msgstr "ºï½ü¤µ¤ì¤¿¥¦¥£¥ó¥É¥¦¤ò»²¾È¤·¤è¤¦¤È¤·¤Þ¤·¤¿"
+
+msgid "readonly attribute: buffer"
+msgstr "ÆɹþÀìÍÑ°À­: ¥Ð¥Ã¥Õ¥¡¡¼"
+
+msgid "cursor position outside buffer"
+msgstr "¥«¡¼¥½¥ë°ÌÃÖ¤¬¥Ð¥Ã¥Õ¥¡¤Î³°Â¦¤Ç¤¹"
+
+msgid "no such window"
+msgstr "¤½¤Î¤è¤¦¤Ê¥¦¥£¥ó¥É¥¦¤Ï¤¢¤ê¤Þ¤»¤ó"
+
+msgid "attempt to refer to deleted buffer"
+msgstr "ºï½ü¤µ¤ì¤¿¥Ð¥Ã¥Õ¥¡¤ò»²¾È¤·¤è¤¦¤È¤·¤Þ¤·¤¿"
+
+msgid "failed to rename buffer"
+msgstr "¥Ð¥Ã¥Õ¥¡Ì¾¤ÎÊѹ¹¤Ë¼ºÇÔ¤·¤Þ¤·¤¿"
+
+msgid "mark name must be a single character"
+msgstr "¥Þ¡¼¥¯Ì¾¤Ï1ʸ»ú¤Î¥¢¥ë¥Õ¥¡¥Ù¥Ã¥È¤Ç¤Ê¤±¤ì¤Ð¤Ê¤ê¤Þ¤»¤ó"
+
+#, c-format
+msgid "expected vim.Buffer object, but got %s"
+msgstr "vim.Buffer¥ª¥Ö¥¸¥§¥¯¥È¤¬´üÂÔ¤µ¤ì¤Æ¤¤¤ë¤Î¤Ë %s ¤Ç¤·¤¿"
+
+#, c-format
+msgid "failed to switch to buffer %d"
+msgstr "»ØÄꤵ¤ì¤¿¥Ð¥Ã¥Õ¥¡ %d ¤Ø¤ÎÀÚ¤êÂؤ¨¤Ë¼ºÇÔ¤·¤Þ¤·¤¿"
+
+#, c-format
+msgid "expected vim.Window object, but got %s"
+msgstr "vim.Window¥ª¥Ö¥¸¥§¥¯¥È¤¬´üÂÔ¤µ¤ì¤Æ¤¤¤ë¤Î¤Ë %s ¤Ç¤·¤¿"
+
+msgid "failed to find window in the current tab page"
+msgstr "¸½ºß¤Î¥¿¥Ö¤Ë¤Ï»ØÄꤵ¤ì¤¿¥¦¥£¥ó¥É¥¦¤¬¤¢¤ê¤Þ¤»¤ó¤Ç¤·¤¿"
+
+msgid "did not switch to the specified window"
+msgstr "»ØÄꤵ¤ì¤¿¥¦¥£¥ó¥É¥¦¤ËÀÚ¤êÂؤ¨¤Þ¤»¤ó¤Ç¤·¤¿"
+
+#, c-format
+msgid "expected vim.TabPage object, but got %s"
+msgstr "vim.TabPage¥ª¥Ö¥¸¥§¥¯¥È¤¬´üÂÔ¤µ¤ì¤Æ¤¤¤ë¤Î¤Ë %s ¤Ç¤·¤¿"
+
+msgid "did not switch to the specified tab page"
+msgstr "»ØÄꤵ¤ì¤¿¥¿¥Ö¥Ú¡¼¥¸¤ËÀÚ¤êÂؤ¨¤Þ¤»¤ó¤Ç¤·¤¿"
+
+msgid "failed to run the code"
+msgstr "¥³¡¼¥É¤Î¼Â¹Ô¤Ë¼ºÇÔ¤·¤Þ¤·¤¿"
+
+msgid "E858: Eval did not return a valid python object"
+msgstr "E858: ¼°É¾²Á¤ÏÍ­¸ú¤Êpython¥ª¥Ö¥¸¥§¥¯¥È¤òÊÖ¤·¤Þ¤»¤ó¤Ç¤·¤¿"
+
+msgid "E859: Failed to convert returned python object to vim value"
+msgstr "E859: ÊÖ¤µ¤ì¤¿python¥ª¥Ö¥¸¥§¥¯¥È¤òvim¤ÎÃͤËÊÑ´¹¤Ç¤­¤Þ¤»¤ó¤Ç¤·¤¿"
+
+#, c-format
+msgid "unable to convert %s to vim dictionary"
+msgstr "%s vim¤Î¼­½ñ·¿¤ËÊÑ´¹¤Ç¤­¤Þ¤»¤ó"
+
+#, c-format
+msgid "unable to convert %s to vim list"
+msgstr "%s ¤òvim¤Î¥ê¥¹¥È¤ËÊÑ´¹¤Ç¤­¤Þ¤»¤ó"
+
+#, c-format
+msgid "unable to convert %s to vim structure"
+msgstr "%s ¤òvim¤Î¹½Â¤ÂΤËÊÑ´¹¤Ç¤­¤Þ¤»¤ó"
+
+msgid "internal error: NULL reference passed"
+msgstr "ÆâÉô¥¨¥é¡¼: NULL»²¾È¤¬ÅϤµ¤ì¤Þ¤·¤¿"
+
+msgid "internal error: invalid value type"
+msgstr "ÆâÉô¥¨¥é¡¼: ̵¸ú¤ÊÃÍ·¿¤Ç¤¹"
+
+msgid ""
+"Failed to set path hook: sys.path_hooks is not a list\n"
+"You should now do the following:\n"
+"- append vim.path_hook to sys.path_hooks\n"
+"- append vim.VIM_SPECIAL_PATH to sys.path\n"
+msgstr ""
+"¥Ñ¥¹¥Õ¥Ã¥¯¤ÎÀßÄê¤Ë¼ºÇÔ¤·¤Þ¤·¤¿: sys.path_hooks ¤¬¥ê¥¹¥È¤Ç¤Ï¤¢¤ê¤Þ¤»¤ó\n"
+"¤¹¤°¤Ë²¼µ­¤ò¼Â»Ü¤·¤Æ¤¯¤À¤µ¤¤:\n"
+"- vim.path_hooks ¤ò sys.path_hooks ¤ØÄɲÃ\n"
+"- vim.VIM_SPECIAL_PATH ¤ò sys.path ¤ØÄɲÃ\n"
+
+msgid ""
+"Failed to set path: sys.path is not a list\n"
+"You should now append vim.VIM_SPECIAL_PATH to sys.path"
+msgstr ""
+"¥Ñ¥¹¤ÎÀßÄê¤Ë¼ºÇÔ¤·¤Þ¤·¤¿: sys.path ¤¬¥ê¥¹¥È¤Ç¤Ï¤¢¤ê¤Þ¤»¤ó\n"
+"¤¹¤°¤Ë vim.VIM_SPECIAL_PATH ¤ò sys.path ¤ËÄɲ䷤Ƥ¯¤À¤µ¤¤"
+
+msgid ""
+"Vim macro files (*.vim)\t*.vim\n"
+"All Files (*.*)\t*.*\n"
+msgstr ""
+"Vim¥Þ¥¯¥í¥Õ¥¡¥¤¥ë (*.vim)\t*.vim\n"
+"¤¹¤Ù¤Æ¤Î¥Õ¥¡¥¤¥ë (*.*)\t*.*\n"
+
+msgid "All Files (*.*)\t*.*\n"
+msgstr "¤¹¤Ù¤Æ¤Î¥Õ¥¡¥¤¥ë (*.*)\t*.*\n"
+
+msgid ""
+"All Files (*.*)\t*.*\n"
+"C source (*.c, *.h)\t*.c;*.h\n"
+"C++ source (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"VB code (*.bas, *.frm)\t*.bas;*.frm\n"
+"Vim files (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
+msgstr ""
+"¤¹¤Ù¤Æ¤Î¥Õ¥¡¥¤¥ë (*.*)\t*.*\n"
+"C¥½¡¼¥¹ (*.c, *.h)\t*.c;*.h\n"
+"C++¥½¡¼¥¹ (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"VB¥³¡¼¥É (*.bas, *.frm)\t*.bas;*.frm\n"
+"Vim¥Õ¥¡¥¤¥ë (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
+
+msgid ""
+"Vim macro files (*.vim)\t*.vim\n"
+"All Files (*)\t*\n"
+msgstr ""
+"Vim ¥Þ¥¯¥í¥Õ¥¡¥¤¥ë (*.vim)\t*.vim\n"
+"¤¹¤Ù¤Æ¤Î¥Õ¥¡¥¤¥ë (*)\t*\n"
+
+msgid "All Files (*)\t*\n"
+msgstr "¤¹¤Ù¤Æ¤Î¥Õ¥¡¥¤¥ë (*)\t*\n"
+
+msgid ""
+"All Files (*)\t*\n"
+"C source (*.c, *.h)\t*.c;*.h\n"
+"C++ source (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"Vim files (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
+msgstr ""
+"¤¹¤Ù¤Æ¤Î¥Õ¥¡¥¤¥ë (*)\t*\n"
+"C¥½¡¼¥¹ (*.c, *.h)\t*.c;*.h\n"
+"C++¥½¡¼¥¹ (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"Vim¥Õ¥¡¥¤¥ë (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
diff --git a/src/po/ja.po b/src/po/ja.po
new file mode 100644
index 0000000..2e70701
--- /dev/null
+++ b/src/po/ja.po
@@ -0,0 +1,7068 @@
+# Japanese translation for Vim
+#
+# Do ":help uganda" in Vim to read copying and usage conditions.
+# Do ":help credits" in Vim to see a list of people who contributed.
+#
+# Copyright (C) 2001-2018 MURAOKA Taro <koron.kaoriya@gmail.com>,
+# vim-jp <http://vim-jp.org/>
+#
+# THIS FILE IS DISTRIBUTED UNDER THE VIM LICENSE.
+#
+# Original translations.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Vim 8.1\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2018-11-13 19:44+0900\n"
+"PO-Revision-Date: 2018-11-16 09:41+0900\n"
+"Last-Translator: MURAOKA Taro <koron.kaoriya@gmail.com>\n"
+"Language-Team: Japanese <https://github.com/vim-jp/lang-ja>\n"
+"Language: ja\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+
+msgid "E831: bf_key_init() called with empty password"
+msgstr "E831: bf_key_init() ãŒç©ºãƒ‘スワードã§å‘¼ã³å‡ºã•ã‚Œã¾ã—ãŸ"
+
+msgid "E820: sizeof(uint32_t) != 4"
+msgstr "E820: sizeof(uint32_t) != 4"
+
+msgid "E817: Blowfish big/little endian use wrong"
+msgstr "E817: Blowfishæš—å·ã®ãƒ“ッグ/リトルエンディアンãŒé–“é•ã£ã¦ã„ã¾ã™"
+
+msgid "E818: sha256 test failed"
+msgstr "E818: sha256ã®ãƒ†ã‚¹ãƒˆã«å¤±æ•—ã—ã¾ã—ãŸ"
+
+msgid "E819: Blowfish test failed"
+msgstr "E819: Blowfishæš—å·ã®ãƒ†ã‚¹ãƒˆã«å¤±æ•—ã—ã¾ã—ãŸ"
+
+msgid "[Location List]"
+msgstr "[ロケーションリスト]"
+
+msgid "[Quickfix List]"
+msgstr "[Quickfixリスト]"
+
+msgid "E855: Autocommands caused command to abort"
+msgstr "E855: autocommandãŒã‚³ãƒžãƒ³ãƒ‰ã®åœæ­¢ã‚’引ãèµ·ã“ã—ã¾ã—ãŸ"
+
+msgid "E82: Cannot allocate any buffer, exiting..."
+msgstr "E82: ãƒãƒƒãƒ•ã‚¡ã‚’1ã¤ã‚‚作æˆã§ããªã„ã®ã§ã€çµ‚了ã—ã¾ã™..."
+
+msgid "E83: Cannot allocate buffer, using other one..."
+msgstr "E83: ãƒãƒƒãƒ•ã‚¡ã‚’作æˆã§ããªã„ã®ã§ã€ä»–ã®ã‚’使用ã—ã¾ã™..."
+
+msgid "E931: Buffer cannot be registered"
+msgstr "E931: ãƒãƒƒãƒ•ã‚¡ã‚’登録ã§ãã¾ã›ã‚“"
+
+msgid "E937: Attempt to delete a buffer that is in use"
+msgstr "E937: 使用中ã®ãƒãƒƒãƒ•ã‚¡ã‚’削除ã—よã†ã¨è©¦ã¿ã¾ã—ãŸ"
+
+msgid "E515: No buffers were unloaded"
+msgstr "E515: 解放ã•ã‚ŒãŸãƒãƒƒãƒ•ã‚¡ã¯ã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E516: No buffers were deleted"
+msgstr "E516: 削除ã•ã‚ŒãŸãƒãƒƒãƒ•ã‚¡ã¯ã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E517: No buffers were wiped out"
+msgstr "E517: 破棄ã•ã‚ŒãŸãƒãƒƒãƒ•ã‚¡ã¯ã‚ã‚Šã¾ã›ã‚“"
+
+#, c-format
+msgid "%d buffer unloaded"
+msgid_plural "%d buffers unloaded"
+msgstr[0] "%d 個ã®ãƒãƒƒãƒ•ã‚¡ãŒè§£æ”¾ã•ã‚Œã¾ã—ãŸ"
+
+#, c-format
+msgid "%d buffer deleted"
+msgid_plural "%d buffers deleted"
+msgstr[0] "%d 個ã®ãƒãƒƒãƒ•ã‚¡ãŒå‰Šé™¤ã•ã‚Œã¾ã—ãŸ"
+
+#, c-format
+msgid "%d buffer wiped out"
+msgid_plural "%d buffers wiped out"
+msgstr[0] "%d 個ã®ãƒãƒƒãƒ•ã‚¡ãŒç ´æ£„ã•ã‚Œã¾ã—ãŸ"
+
+msgid "E90: Cannot unload last buffer"
+msgstr "E90: 最後ã®ãƒãƒƒãƒ•ã‚¡ã¯è§£æ”¾ã§ãã¾ã›ã‚“"
+
+msgid "E84: No modified buffer found"
+msgstr "E84: 変更ã•ã‚ŒãŸãƒãƒƒãƒ•ã‚¡ã¯ã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E85: There is no listed buffer"
+msgstr "E85: リスト表示ã•ã‚Œã‚‹ãƒãƒƒãƒ•ã‚¡ã¯ã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E87: Cannot go beyond last buffer"
+msgstr "E87: 最後ã®ãƒãƒƒãƒ•ã‚¡ã‚’越ãˆã¦ç§»å‹•ã¯ã§ãã¾ã›ã‚“"
+
+msgid "E88: Cannot go before first buffer"
+msgstr "E88: 最åˆã®ãƒãƒƒãƒ•ã‚¡ã‚ˆã‚Šå‰ã¸ã¯ç§»å‹•ã§ãã¾ã›ã‚“"
+
+#, c-format
+msgid "E89: No write since last change for buffer %ld (add ! to override)"
+msgstr "E89: ãƒãƒƒãƒ•ã‚¡ %ld ã®å¤‰æ›´ã¯ä¿å­˜ã•ã‚Œã¦ã„ã¾ã›ã‚“ (! ã§å¤‰æ›´ã‚’破棄)"
+
+msgid "E948: Job still running (add ! to end the job)"
+msgstr "E948: ジョブã¯ã¾ã å®Ÿè¡Œä¸­ã§ã™ (! を追加ã§ã‚¸ãƒ§ãƒ–を終了)"
+
+msgid "E37: No write since last change (add ! to override)"
+msgstr "E37: 最後ã®å¤‰æ›´ãŒä¿å­˜ã•ã‚Œã¦ã„ã¾ã›ã‚“ (! を追加ã§å¤‰æ›´ã‚’破棄)"
+
+msgid "E948: Job still running"
+msgstr "E948: ジョブã¯ã¾ã å®Ÿè¡Œä¸­ã§ã™"
+
+msgid "E37: No write since last change"
+msgstr "E37: 最後ã®å¤‰æ›´ãŒä¿å­˜ã•ã‚Œã¦ã„ã¾ã›ã‚“"
+
+msgid "W14: Warning: List of file names overflow"
+msgstr "W14: 警告: ファイルåã®ãƒªã‚¹ãƒˆãŒé•·éŽãŽã¾ã™"
+
+#, c-format
+msgid "E92: Buffer %ld not found"
+msgstr "E92: ãƒãƒƒãƒ•ã‚¡ %ld ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“"
+
+#, c-format
+msgid "E93: More than one match for %s"
+msgstr "E93: %s ã«è¤‡æ•°ã®è©²å½“ãŒã‚ã‚Šã¾ã—ãŸ"
+
+#, c-format
+msgid "E94: No matching buffer for %s"
+msgstr "E94: %s ã«è©²å½“ã™ã‚‹ãƒãƒƒãƒ•ã‚¡ã¯ã‚ã‚Šã¾ã›ã‚“ã§ã—ãŸ"
+
+#, c-format
+msgid "line %ld"
+msgstr "行 %ld"
+
+msgid "E95: Buffer with this name already exists"
+msgstr "E95: ã“ã®åå‰ã®ãƒãƒƒãƒ•ã‚¡ã¯æ—¢ã«ã‚ã‚Šã¾ã™"
+
+msgid " [Modified]"
+msgstr " [変更ã‚ã‚Š]"
+
+msgid "[Not edited]"
+msgstr "[未編集]"
+
+msgid "[New file]"
+msgstr "[新ファイル]"
+
+msgid "[Read errors]"
+msgstr "[読込エラー]"
+
+msgid "[RO]"
+msgstr "[読専]"
+
+msgid "[readonly]"
+msgstr "[読込専用]"
+
+#, c-format
+msgid "%ld line --%d%%--"
+msgid_plural "%ld lines --%d%%--"
+msgstr[0] "%ld 行 --%d%%--"
+
+#, c-format
+msgid "line %ld of %ld --%d%%-- col "
+msgstr "行 %ld (全体 %ld) --%d%%-- col "
+
+msgid "[No Name]"
+msgstr "[ç„¡å]"
+
+msgid "help"
+msgstr "ヘルプ"
+
+msgid "[Help]"
+msgstr "[ヘルプ]"
+
+msgid "[Preview]"
+msgstr "[プレビュー]"
+
+msgid "All"
+msgstr "å…¨ã¦"
+
+msgid "Bot"
+msgstr "末尾"
+
+msgid "Top"
+msgstr "先頭"
+
+msgid ""
+"\n"
+"# Buffer list:\n"
+msgstr ""
+"\n"
+"# ãƒãƒƒãƒ•ã‚¡ãƒªã‚¹ãƒˆ:\n"
+
+msgid "E382: Cannot write, 'buftype' option is set"
+msgstr "E382: 'buftype' オプションãŒè¨­å®šã•ã‚Œã¦ã„ã‚‹ã®ã§æ›¸è¾¼ã‚ã¾ã›ã‚“"
+
+msgid "[Prompt]"
+msgstr "[プロンプト]"
+
+msgid "[Scratch]"
+msgstr "[下書ã]"
+
+msgid ""
+"\n"
+"--- Signs ---"
+msgstr ""
+"\n"
+"--- サイン ---"
+
+#, c-format
+msgid "Signs for %s:"
+msgstr "%s ã®ã‚µã‚¤ãƒ³:"
+
+#, c-format
+msgid " line=%ld id=%d name=%s"
+msgstr " è¡Œ=%ld 識別å­=%d åå‰=%s"
+
+msgid "E902: Cannot connect to port"
+msgstr "E902: ãƒãƒ¼ãƒˆã«æŽ¥ç¶šã§ãã¾ã›ã‚“"
+
+msgid "E901: gethostbyname() in channel_open()"
+msgstr "E901: channel_open() 内㮠gethostbyname() ãŒå¤±æ•—ã—ã¾ã—ãŸ"
+
+msgid "E898: socket() in channel_open()"
+msgstr "E898: channel_open() 内㮠socket() ãŒå¤±æ•—ã—ã¾ã—ãŸ"
+
+msgid "E903: received command with non-string argument"
+msgstr "E903: éžæ–‡å­—列ã®å¼•æ•°ã®ã‚³ãƒžãƒ³ãƒ‰ã‚’å—ä¿¡ã—ã¾ã—ãŸ"
+
+msgid "E904: last argument for expr/call must be a number"
+msgstr "E904: expr/call ã®æœ€å¾Œã®å¼•æ•°ã¯æ•°å­—ã§ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“"
+
+msgid "E904: third argument for call must be a list"
+msgstr "E904: call ã®3番目ã®å¼•æ•°ã¯ãƒªã‚¹ãƒˆåž‹ã§ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“"
+
+#, c-format
+msgid "E905: received unknown command: %s"
+msgstr "E905: 未知ã®ã‚³ãƒžãƒ³ãƒ‰ã‚’å—ä¿¡ã—ã¾ã—ãŸ: %s"
+
+#, c-format
+msgid "E630: %s(): write while not connected"
+msgstr "E630: %s(): éžæŽ¥ç¶šçŠ¶æ…‹ã§æ›¸ãè¾¼ã¿ã¾ã—ãŸ"
+
+#, c-format
+msgid "E631: %s(): write failed"
+msgstr "E631: %s(): 書ãè¾¼ã¿ã«å¤±æ•—ã—ã¾ã—ãŸ"
+
+#, c-format
+msgid "E917: Cannot use a callback with %s()"
+msgstr "E917: %s() ã«ã‚³ãƒ¼ãƒ«ãƒãƒƒã‚¯ã¯ä½¿ãˆã¾ã›ã‚“"
+
+msgid "E912: cannot use ch_evalexpr()/ch_sendexpr() with a raw or nl channel"
+msgstr ""
+"E912: raw ã‚„ nl モードã®ãƒãƒ£ãƒãƒ«ã« ch_evalexpr()/ch_sendexpr() ã¯ä½¿ãˆã¾ã›ã‚“"
+
+msgid "E906: not an open channel"
+msgstr "E906: é–‹ã„ã¦ã„ãªã„ãƒãƒ£ãƒãƒ«ã§ã™"
+
+msgid "E920: _io file requires _name to be set"
+msgstr "E920: _io ファイル㯠_name ã®è¨­å®šãŒå¿…è¦ã§ã™"
+
+msgid "E915: in_io buffer requires in_buf or in_name to be set"
+msgstr "E915: in_io ãƒãƒƒãƒ•ã‚¡ã¯ in_buf ã‹ in_name ã®è¨­å®šãŒå¿…è¦ã§ã™"
+
+#, c-format
+msgid "E918: buffer must be loaded: %s"
+msgstr "E918: ãƒãƒƒãƒ•ã‚¡ãŒãƒ­ãƒ¼ãƒ‰ã•ã‚Œã¦ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“: %s"
+
+msgid "E821: File is encrypted with unknown method"
+msgstr "E821: ファイルãŒæœªçŸ¥ã®æ–¹æ³•ã§æš—å·åŒ–ã•ã‚Œã¦ã„ã¾ã™"
+
+msgid "Warning: Using a weak encryption method; see :help 'cm'"
+msgstr "警告: å¼±ã„æš—å·æ–¹æ³•ã‚’使ã£ã¦ã„ã¾ã™; :help 'cm' ã‚’å‚ç…§ã—ã¦ãã ã•ã„"
+
+msgid "Enter encryption key: "
+msgstr "æš—å·åŒ–用ã®ã‚­ãƒ¼ã‚’入力ã—ã¦ãã ã•ã„: "
+
+msgid "Enter same key again: "
+msgstr "ã‚‚ã†ä¸€åº¦åŒã˜ã‚­ãƒ¼ã‚’入力ã—ã¦ãã ã•ã„: "
+
+msgid "Keys don't match!"
+msgstr "キーãŒä¸€è‡´ã—ã¾ã›ã‚“"
+
+msgid "[crypted]"
+msgstr "[æš—å·åŒ–]"
+
+#, c-format
+msgid "E720: Missing colon in Dictionary: %s"
+msgstr "E720: 辞書型ã«ã‚³ãƒ­ãƒ³ãŒã‚ã‚Šã¾ã›ã‚“: %s"
+
+#, c-format
+msgid "E721: Duplicate key in Dictionary: \"%s\""
+msgstr "E721: 辞書型ã«é‡è¤‡ã‚­ãƒ¼ãŒã‚ã‚Šã¾ã™: \"%s\""
+
+#, c-format
+msgid "E722: Missing comma in Dictionary: %s"
+msgstr "E722: 辞書型ã«ã‚«ãƒ³ãƒžãŒã‚ã‚Šã¾ã›ã‚“: %s"
+
+#, c-format
+msgid "E723: Missing end of Dictionary '}': %s"
+msgstr "E723: 辞書型ã®æœ€å¾Œã« '}' ãŒã‚ã‚Šã¾ã›ã‚“: %s"
+
+msgid "extend() argument"
+msgstr "extend() ã®å¼•æ•°"
+
+#, c-format
+msgid "E737: Key already exists: %s"
+msgstr "E737: キーã¯æ—¢ã«å­˜åœ¨ã—ã¾ã™: %s"
+
+#, c-format
+msgid "E96: Cannot diff more than %ld buffers"
+msgstr "E96: %ld 以上ã®ãƒãƒƒãƒ•ã‚¡ã¯diffã§ãã¾ã›ã‚“"
+
+#, c-format
+msgid "Not enough memory to use internal diff for buffer \"%s\""
+msgstr "ãƒãƒƒãƒ•ã‚¡ \"%s\" 用ã«å†…部diffを使ã†ãŸã‚ã®ãƒ¡ãƒ¢ãƒªãŒä¸è¶³ã—ã¦ã„ã¾ã™"
+
+msgid "E810: Cannot read or write temp files"
+msgstr "E810: 一時ファイルã®èª­è¾¼ã‚‚ã—ãã¯æ›¸è¾¼ãŒã§ãã¾ã›ã‚“"
+
+msgid "E97: Cannot create diffs"
+msgstr "E97: 差分を作æˆã§ãã¾ã›ã‚“"
+
+msgid "E960: Problem creating the internal diff"
+msgstr "E960: 内部diff作æˆæ™‚ã«å•é¡ŒãŒç™ºç”Ÿã—ã¾ã—ãŸ"
+
+msgid "Patch file"
+msgstr "パッãƒãƒ•ã‚¡ã‚¤ãƒ«"
+
+msgid "E816: Cannot read patch output"
+msgstr "E816: patchã®å‡ºåŠ›ã‚’読込ã‚ã¾ã›ã‚“"
+
+msgid "E98: Cannot read diff output"
+msgstr "E98: diffã®å‡ºåŠ›ã‚’読込ã‚ã¾ã›ã‚“"
+
+msgid "E959: Invalid diff format."
+msgstr "E959: 無効ãªdiffå½¢å¼ã§ã™"
+
+msgid "E99: Current buffer is not in diff mode"
+msgstr "E99: ç¾åœ¨ã®ãƒãƒƒãƒ•ã‚¡ã¯å·®åˆ†ãƒ¢ãƒ¼ãƒ‰ã§ã¯ã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E793: No other buffer in diff mode is modifiable"
+msgstr "E793: 差分モードã§ã‚ã‚‹ä»–ã®ãƒãƒƒãƒ•ã‚¡ã¯å¤‰æ›´ã§ãã¾ã›ã‚“"
+
+msgid "E100: No other buffer in diff mode"
+msgstr "E100: 差分モードã§ã‚ã‚‹ä»–ã®ãƒãƒƒãƒ•ã‚¡ã¯ã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E101: More than two buffers in diff mode, don't know which one to use"
+msgstr ""
+"E101: 差分モードã®ãƒãƒƒãƒ•ã‚¡ãŒ2個以上ã‚ã‚‹ã®ã§ã€ã©ã‚Œã‚’使ã†ã‹ç‰¹å®šã§ãã¾ã›ã‚“"
+
+#, c-format
+msgid "E102: Can't find buffer \"%s\""
+msgstr "E102: ãƒãƒƒãƒ•ã‚¡ \"%s\" ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“"
+
+#, c-format
+msgid "E103: Buffer \"%s\" is not in diff mode"
+msgstr "E103: ãƒãƒƒãƒ•ã‚¡ \"%s\" ã¯å·®åˆ†ãƒ¢ãƒ¼ãƒ‰ã§ã¯ã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E787: Buffer changed unexpectedly"
+msgstr "E787: 予期ã›ãšãƒãƒƒãƒ•ã‚¡ãŒå¤‰æ›´å¤‰æ›´ã•ã‚Œã¾ã—ãŸ"
+
+msgid "E104: Escape not allowed in digraph"
+msgstr "E104: åˆå­—ã«Escapeã¯ä½¿ç”¨ã§ãã¾ã›ã‚“"
+
+msgid "E544: Keymap file not found"
+msgstr "E544: キーマップファイルãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“"
+
+msgid "E105: Using :loadkeymap not in a sourced file"
+msgstr "E105: :source ã§å–込むファイル以外ã§ã¯ :loadkeymap を使ãˆã¾ã›ã‚“"
+
+msgid "E791: Empty keymap entry"
+msgstr "E791: 空ã®ã‚­ãƒ¼ãƒžãƒƒãƒ—エントリ"
+
+msgid " Keyword completion (^N^P)"
+msgstr " キーワード補完 (^N^P)"
+
+msgid " ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+msgstr " ^X モード (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+
+msgid " Whole line completion (^L^N^P)"
+msgstr " 行(全体)補完 (^L^N^P)"
+
+msgid " File name completion (^F^N^P)"
+msgstr " ファイルå補完 (^F^N^P)"
+
+msgid " Tag completion (^]^N^P)"
+msgstr " タグ補完 (^]^N^P)"
+
+msgid " Path pattern completion (^N^P)"
+msgstr " パスパターン補完 (^N^P)"
+
+msgid " Definition completion (^D^N^P)"
+msgstr " 定義補完 (^D^N^P)"
+
+msgid " Dictionary completion (^K^N^P)"
+msgstr " 辞書補完 (^K^N^P)"
+
+msgid " Thesaurus completion (^T^N^P)"
+msgstr " シソーラス補完 (^T^N^P)"
+
+msgid " Command-line completion (^V^N^P)"
+msgstr " コマンドライン補完 (^V^N^P)"
+
+msgid " User defined completion (^U^N^P)"
+msgstr " ユーザー定義補完 (^U^N^P)"
+
+msgid " Omni completion (^O^N^P)"
+msgstr " オムニ補完 (^O^N^P)"
+
+msgid " Spelling suggestion (s^N^P)"
+msgstr " 綴り修正候補 (s^N^P)"
+
+msgid " Keyword Local completion (^N^P)"
+msgstr " 局所キーワード補完 (^N^P)"
+
+msgid "Hit end of paragraph"
+msgstr "段è½ã®æœ€å¾Œã«ãƒ’ット"
+
+msgid "E839: Completion function changed window"
+msgstr "E839: 補間関数ãŒã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã‚’変更ã—ã¾ã—ãŸ"
+
+msgid "E840: Completion function deleted text"
+msgstr "E840: 補完関数ãŒãƒ†ã‚­ã‚¹ãƒˆã‚’削除ã—ã¾ã—ãŸ"
+
+msgid "'dictionary' option is empty"
+msgstr "'dictionary' オプションãŒç©ºã§ã™"
+
+msgid "'thesaurus' option is empty"
+msgstr "'thesaurus' オプションãŒç©ºã§ã™"
+
+#, c-format
+msgid "Scanning dictionary: %s"
+msgstr "辞書をスキャン中: %s"
+
+msgid " (insert) Scroll (^E/^Y)"
+msgstr " (挿入) スクロール(^E/^Y)"
+
+msgid " (replace) Scroll (^E/^Y)"
+msgstr " (ç½®æ›) スクロール (^E/^Y)"
+
+#, c-format
+msgid "Scanning: %s"
+msgstr "スキャン中: %s"
+
+msgid "Scanning tags."
+msgstr "タグをスキャン中."
+
+msgid "match in file"
+msgstr "ファイル内ã®ãƒžãƒƒãƒ"
+
+msgid " Adding"
+msgstr " 追加中"
+
+msgid "-- Searching..."
+msgstr "-- 検索中..."
+
+msgid "Back at original"
+msgstr "始ã‚ã«æˆ»ã‚‹"
+
+msgid "Word from other line"
+msgstr "ä»–ã®è¡Œã®å˜èªž"
+
+msgid "The only match"
+msgstr "唯一ã®è©²å½“"
+
+#, c-format
+msgid "match %d of %d"
+msgstr "%d 番目ã®è©²å½“ (全該当 %d 個中)"
+
+#, c-format
+msgid "match %d"
+msgstr "%d 番目ã®è©²å½“"
+
+msgid "E18: Unexpected characters in :let"
+msgstr "E18: 予期ã›ã¬æ–‡å­—㌠:let ã«ã‚ã‚Šã¾ã—ãŸ"
+
+#, c-format
+msgid "E121: Undefined variable: %s"
+msgstr "E121: 未定義ã®å¤‰æ•°ã§ã™: %s"
+
+msgid "E111: Missing ']'"
+msgstr "E111: ']' ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“"
+
+msgid "E719: Cannot use [:] with a Dictionary"
+msgstr "E719: [:] を辞書型ã¨çµ„ã¿åˆã‚ã›ã¦ã¯ä½¿ãˆã¾ã›ã‚“"
+
+#, c-format
+msgid "E734: Wrong variable type for %s="
+msgstr "E734: ç•°ãªã£ãŸåž‹ã®å¤‰æ•°ã§ã™ %s="
+
+#, c-format
+msgid "E461: Illegal variable name: %s"
+msgstr "E461: ä¸æ­£ãªå¤‰æ•°åã§ã™: %s"
+
+msgid "E806: using Float as a String"
+msgstr "E806: 浮動å°æ•°ç‚¹æ•°ã‚’文字列ã¨ã—ã¦æ‰±ã£ã¦ã„ã¾ã™"
+
+msgid "E687: Less targets than List items"
+msgstr "E687: ターゲットãŒãƒªã‚¹ãƒˆåž‹å†…ã®è¦ç´ ã‚ˆã‚Šã‚‚å°‘ãªã„ã§ã™"
+
+msgid "E688: More targets than List items"
+msgstr "E688: ターゲットãŒãƒªã‚¹ãƒˆåž‹å†…ã®è¦ç´ ã‚ˆã‚Šã‚‚多ã„ã§ã™"
+
+msgid "Double ; in list of variables"
+msgstr "リスト型ã®å€¤ã«2ã¤ä»¥ä¸Šã® ; ãŒæ¤œå‡ºã•ã‚Œã¾ã—ãŸ"
+
+#, c-format
+msgid "E738: Can't list variables for %s"
+msgstr "E738: %s ã®å€¤ã‚’一覧表示ã§ãã¾ã›ã‚“"
+
+msgid "E689: Can only index a List or Dictionary"
+msgstr "E689: リスト型ã¨è¾žæ›¸åž‹ä»¥å¤–ã¯ã‚¤ãƒ³ãƒ‡ãƒƒã‚¯ã‚¹æŒ‡å®šã§ãã¾ã›ã‚“"
+
+msgid "E708: [:] must come last"
+msgstr "E708: [:] ã¯æœ€å¾Œã§ãªã‘ã‚Œã°ã„ã‘ã¾ã›ã‚“"
+
+msgid "E709: [:] requires a List value"
+msgstr "E709: [:] ã«ã¯ãƒªã‚¹ãƒˆåž‹ã®å€¤ãŒå¿…è¦ã§ã™"
+
+msgid "E710: List value has more items than target"
+msgstr "E710: リスト型変数ã«ã‚¿ãƒ¼ã‚²ãƒƒãƒˆã‚ˆã‚Šã‚‚多ã„è¦ç´ ãŒã‚ã‚Šã¾ã™"
+
+msgid "E711: List value has not enough items"
+msgstr "E711: リスト型変数ã«å分ãªæ•°ã®è¦ç´ ãŒã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E690: Missing \"in\" after :for"
+msgstr "E690: :for ã®å¾Œã« \"in\" ãŒã‚ã‚Šã¾ã›ã‚“"
+
+#, c-format
+msgid "E108: No such variable: \"%s\""
+msgstr "E108: ãã®å¤‰æ•°ã¯ã‚ã‚Šã¾ã›ã‚“: \"%s\""
+
+#, c-format
+msgid "E940: Cannot lock or unlock variable %s"
+msgstr "E940: 変数 %s ã¯ãƒ­ãƒƒã‚¯ã¾ãŸã¯ã‚¢ãƒ³ãƒ­ãƒƒã‚¯ã§ãã¾ã›ã‚“"
+
+msgid "E743: variable nested too deep for (un)lock"
+msgstr "E743: (アン)ロックã™ã‚‹ã«ã¯å¤‰æ•°ã®å…¥ã‚Œå­ãŒæ·±éŽãŽã¾ã™"
+
+msgid "E109: Missing ':' after '?'"
+msgstr "E109: '?' ã®å¾Œã« ':' ãŒã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E804: Cannot use '%' with Float"
+msgstr "E804: '%' を浮動å°æ•°ç‚¹æ•°ã¨çµ„ã¿åˆã‚ã›ã¦ã¯ä½¿ãˆã¾ã›ã‚“"
+
+msgid "E110: Missing ')'"
+msgstr "E110: ')' ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“"
+
+msgid "E695: Cannot index a Funcref"
+msgstr "E695: 関数å‚照型ã¯ã‚¤ãƒ³ãƒ‡ãƒƒã‚¯ã‚¹ã§ãã¾ã›ã‚“"
+
+msgid "E909: Cannot index a special variable"
+msgstr "E909: 特殊変数ã¯ã‚¤ãƒ³ãƒ‡ãƒƒã‚¯ã‚¹ã§ãã¾ã›ã‚“"
+
+#, c-format
+msgid "E112: Option name missing: %s"
+msgstr "E112: オプションåãŒã‚ã‚Šã¾ã›ã‚“: %s"
+
+#, c-format
+msgid "E113: Unknown option: %s"
+msgstr "E113: 未知ã®ã‚ªãƒ—ションã§ã™: %s"
+
+#, c-format
+msgid "E114: Missing quote: %s"
+msgstr "E114: 引用符 (\") ãŒã‚ã‚Šã¾ã›ã‚“: %s"
+
+#, c-format
+msgid "E115: Missing quote: %s"
+msgstr "E115: 引用符 (') ãŒã‚ã‚Šã¾ã›ã‚“: %s"
+
+msgid "Not enough memory to set references, garbage collection aborted!"
+msgstr ""
+"ガーベッジコレクションを中止ã—ã¾ã—ãŸ! å‚照を作æˆã™ã‚‹ã®ã«ãƒ¡ãƒ¢ãƒªãŒä¸è¶³ã—ã¾ã—ãŸ"
+
+msgid "E724: variable nested too deep for displaying"
+msgstr "E724: 表示ã™ã‚‹ã«ã¯å¤‰æ•°ã®å…¥ã‚Œå­ãŒæ·±éŽãŽã¾ã™"
+
+msgid "E805: Using a Float as a Number"
+msgstr "E805: 浮動å°æ•°ç‚¹æ•°ã‚’数値ã¨ã—ã¦æ‰±ã£ã¦ã„ã¾ã™"
+
+msgid "E703: Using a Funcref as a Number"
+msgstr "E703: 関数å‚照型を数値ã¨ã—ã¦æ‰±ã£ã¦ã„ã¾ã™"
+
+msgid "E745: Using a List as a Number"
+msgstr "E745: リスト型を数値ã¨ã—ã¦æ‰±ã£ã¦ã„ã¾ã™"
+
+msgid "E728: Using a Dictionary as a Number"
+msgstr "E728: 辞書型を数値ã¨ã—ã¦æ‰±ã£ã¦ã„ã¾ã™"
+
+msgid "E910: Using a Job as a Number"
+msgstr "E910: ジョブを数値ã¨ã—ã¦æ‰±ã£ã¦ã„ã¾ã™"
+
+msgid "E913: Using a Channel as a Number"
+msgstr "E913: ãƒãƒ£ãƒãƒ«ã‚’数値ã¨ã—ã¦æ‰±ã£ã¦ã„ã¾ã™"
+
+msgid "E891: Using a Funcref as a Float"
+msgstr "E891: 関数å‚照型を浮動å°æ•°ç‚¹æ•°ã¨ã—ã¦æ‰±ã£ã¦ã„ã¾ã™"
+
+msgid "E892: Using a String as a Float"
+msgstr "E892: 文字列を浮動å°æ•°ç‚¹æ•°ã¨ã—ã¦æ‰±ã£ã¦ã„ã¾ã™"
+
+msgid "E893: Using a List as a Float"
+msgstr "E893: リスト型を浮動å°æ•°ç‚¹æ•°ã¨ã—ã¦æ‰±ã£ã¦ã„ã¾ã™"
+
+msgid "E894: Using a Dictionary as a Float"
+msgstr "E894: 辞書型を浮動å°æ•°ç‚¹æ•°ã¨ã—ã¦æ‰±ã£ã¦ã„ã¾ã™"
+
+msgid "E907: Using a special value as a Float"
+msgstr "E907: 特殊値を浮動å°æ•°ç‚¹æ•°ã¨ã—ã¦æ‰±ã£ã¦ã„ã¾ã™"
+
+msgid "E911: Using a Job as a Float"
+msgstr "E911: ジョブを浮動å°æ•°ç‚¹æ•°ã¨ã—ã¦æ‰±ã£ã¦ã„ã¾ã™"
+
+msgid "E914: Using a Channel as a Float"
+msgstr "E914: ãƒãƒ£ãƒãƒ«ã‚’浮動å°æ•°ç‚¹æ•°ã¨ã—ã¦æ‰±ã£ã¦ã„ã¾ã™"
+
+msgid "E729: using Funcref as a String"
+msgstr "E729: 関数å‚照型を文字列ã¨ã—ã¦æ‰±ã£ã¦ã„ã¾ã™"
+
+msgid "E730: using List as a String"
+msgstr "E730: リスト型を文字列ã¨ã—ã¦æ‰±ã£ã¦ã„ã¾ã™"
+
+msgid "E731: using Dictionary as a String"
+msgstr "E731: 辞書型を文字列ã¨ã—ã¦æ‰±ã£ã¦ã„ã¾ã™"
+
+msgid "E908: using an invalid value as a String"
+msgstr "E908: 無効ãªå€¤ã‚’文字列ã¨ã—ã¦æ‰±ã£ã¦ã„ã¾ã™"
+
+#, c-format
+msgid "E795: Cannot delete variable %s"
+msgstr "E795: 変数 %s を削除ã§ãã¾ã›ã‚“"
+
+#, c-format
+msgid "E704: Funcref variable name must start with a capital: %s"
+msgstr "E704: 関数å‚照型変数åã¯å¤§æ–‡å­—ã§å§‹ã¾ã‚‰ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“: %s"
+
+#, c-format
+msgid "E705: Variable name conflicts with existing function: %s"
+msgstr "E705: 変数åãŒæ—¢å­˜ã®é–¢æ•°åã¨è¡çªã—ã¾ã™: %s"
+
+#, c-format
+msgid "E741: Value is locked: %s"
+msgstr "E741: 値ãŒãƒ­ãƒƒã‚¯ã•ã‚Œã¦ã„ã¾ã™: %s"
+
+msgid "Unknown"
+msgstr "ä¸æ˜Ž"
+
+#, c-format
+msgid "E742: Cannot change value of %s"
+msgstr "E742: %s ã®å€¤ã‚’変更ã§ãã¾ã›ã‚“"
+
+msgid "E698: variable nested too deep for making a copy"
+msgstr "E698: コピーをå–ã‚‹ã«ã¯å¤‰æ•°ã®å…¥ã‚Œå­ãŒæ·±éŽãŽã¾ã™"
+
+msgid ""
+"\n"
+"# global variables:\n"
+msgstr ""
+"\n"
+"# グローãƒãƒ«å¤‰æ•°:\n"
+
+msgid ""
+"\n"
+"\tLast set from "
+msgstr ""
+"\n"
+"\t最後ã«ã‚»ãƒƒãƒˆã—ãŸã‚¹ã‚¯ãƒªãƒ—ト: "
+
+msgid " line "
+msgstr " 行 "
+
+msgid "E691: Can only compare List with List"
+msgstr "E691: リスト型ã¯ãƒªã‚¹ãƒˆåž‹ã¨ã—ã‹æ¯”較ã§ãã¾ã›ã‚“"
+
+msgid "E692: Invalid operation for List"
+msgstr "E692: リスト型ã«ã¯ç„¡åŠ¹ãªæ“作ã§ã™"
+
+msgid "E735: Can only compare Dictionary with Dictionary"
+msgstr "E735: 辞書型ã¯è¾žæ›¸åž‹ã¨ã—ã‹æ¯”較ã§ãã¾ã›ã‚“"
+
+msgid "E736: Invalid operation for Dictionary"
+msgstr "E736: 辞書型ã«ã¯ç„¡åŠ¹ãªæ“作ã§ã™"
+
+msgid "E694: Invalid operation for Funcrefs"
+msgstr "E694: 関数å‚照型ã«ã¯ç„¡åŠ¹ãªæ“作ã§ã™"
+
+msgid "map() argument"
+msgstr "map() ã®å¼•æ•°"
+
+msgid "filter() argument"
+msgstr "filter() ã®å¼•æ•°"
+
+#, c-format
+msgid "E686: Argument of %s must be a List"
+msgstr "E686: %s ã®å¼•æ•°ã¯ãƒªã‚¹ãƒˆåž‹ã§ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“"
+
+msgid "E928: String required"
+msgstr "E928: 文字列ãŒå¿…è¦ã§ã™"
+
+msgid "E808: Number or Float required"
+msgstr "E808: 数値ã‹æµ®å‹•å°æ•°ç‚¹æ•°ãŒå¿…è¦ã§ã™"
+
+msgid "add() argument"
+msgstr "add() ã®å¼•æ•°"
+
+msgid "E785: complete() can only be used in Insert mode"
+msgstr "E785: complete() ã¯æŒ¿å…¥ãƒ¢ãƒ¼ãƒ‰ã§ã—ã‹åˆ©ç”¨ã§ãã¾ã›ã‚“"
+
+msgid "&Ok"
+msgstr "&Ok"
+
+#, c-format
+msgid "+-%s%3ld line: "
+msgid_plural "+-%s%3ld lines: "
+msgstr[0] "+-%s%3ld 行: "
+
+#, c-format
+msgid "E700: Unknown function: %s"
+msgstr "E700: 未知ã®é–¢æ•°ã§ã™: %s"
+
+msgid "E922: expected a dict"
+msgstr "E922: 辞書ãŒæœŸå¾…ã•ã‚Œã¦ã„ã¾ã™"
+
+msgid "E923: Second argument of function() must be a list or a dict"
+msgstr "E923: function() ã®ç¬¬ 2 引数ã¯ãƒªã‚¹ãƒˆåž‹ã¾ãŸã¯è¾žæ›¸åž‹ã§ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“"
+
+msgid ""
+"&OK\n"
+"&Cancel"
+msgstr ""
+"決定(&O)\n"
+"キャンセル(&C)"
+
+msgid "called inputrestore() more often than inputsave()"
+msgstr "inputrestore() ㌠inputsave() よりも多ã呼ã°ã‚Œã¾ã—ãŸ"
+
+msgid "insert() argument"
+msgstr "insert() ã®å¼•æ•°"
+
+msgid "E786: Range not allowed"
+msgstr "E786: 範囲指定ã¯è¨±å¯ã•ã‚Œã¦ã„ã¾ã›ã‚“"
+
+msgid "E916: not a valid job"
+msgstr "E916: 有効ãªã‚¸ãƒ§ãƒ–ã§ã¯ã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E701: Invalid type for len()"
+msgstr "E701: len() ã«ã¯ç„¡åŠ¹ãªåž‹ã§ã™"
+
+msgid "E957: Invalid window number"
+msgstr "E957: 無効ãªã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ç•ªå·ã§ã™"
+
+#, c-format
+msgid "E798: ID is reserved for \":match\": %ld"
+msgstr "E798: ID 㯠\":match\" ã®ãŸã‚ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™: %ld"
+
+msgid "E726: Stride is zero"
+msgstr "E726: ストライド(å‰é€²é‡)㌠0 ã§ã™"
+
+msgid "E727: Start past end"
+msgstr "E727: 開始ä½ç½®ãŒçµ‚了ä½ç½®ã‚’越ãˆã¾ã—ãŸ"
+
+msgid "<empty>"
+msgstr "<空>"
+
+msgid "E240: No connection to the X server"
+msgstr "E240: X サーãƒãƒ¼ã¸ã®æŽ¥ç¶šãŒã‚ã‚Šã¾ã›ã‚“"
+
+#, c-format
+msgid "E241: Unable to send to %s"
+msgstr "E241: %s ã¸é€ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“"
+
+msgid "E277: Unable to read a server reply"
+msgstr "E277: サーãƒãƒ¼ã®å¿œç­”ãŒã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E941: already started a server"
+msgstr "E941: サーãƒãƒ¼ã¯ã™ã§ã«é–‹å§‹ã—ã¦ã„ã¾ã™"
+
+msgid "E942: +clientserver feature not available"
+msgstr "E942: +clientserver 機能ãŒç„¡åŠ¹ã«ãªã£ã¦ã„ã¾ã™"
+
+msgid "remove() argument"
+msgstr "remove() ã®å¼•æ•°"
+
+# Added at 10-Mar-2004.
+msgid "E655: Too many symbolic links (cycle?)"
+msgstr "E655: シンボリックリンクãŒå¤šéŽãŽã¾ã™ (循環ã—ã¦ã„ã‚‹å¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™)"
+
+msgid "reverse() argument"
+msgstr "reverse() ã®å¼•æ•°"
+
+msgid "E258: Unable to send to client"
+msgstr "E258: クライアントã¸é€ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“"
+
+#, c-format
+msgid "E927: Invalid action: '%s'"
+msgstr "E927: 無効ãªæ“作ã§ã™: %s"
+
+#, c-format
+msgid "E962: Invalid action: '%s'"
+msgstr "E962: 無効ãªæ“作ã§ã™: %s"
+
+msgid "sort() argument"
+msgstr "sort() ã®å¼•æ•°"
+
+msgid "uniq() argument"
+msgstr "uniq() ã®å¼•æ•°"
+
+msgid "E702: Sort compare function failed"
+msgstr "E702: ソートã®æ¯”較関数ãŒå¤±æ•—ã—ã¾ã—ãŸ"
+
+msgid "E882: Uniq compare function failed"
+msgstr "E882: Uniq ã®æ¯”較関数ãŒå¤±æ•—ã—ã¾ã—ãŸ"
+
+msgid "(Invalid)"
+msgstr "(無効)"
+
+#, c-format
+msgid "E935: invalid submatch number: %d"
+msgstr "E935: 無効ãªã‚µãƒ–マッãƒç•ªå·: %d"
+
+msgid "E677: Error writing temp file"
+msgstr "E677: 一時ファイル書込中ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸ"
+
+msgid "E921: Invalid callback argument"
+msgstr "E921: 無効ãªã‚³ãƒ¼ãƒ«ãƒãƒƒã‚¯å¼•æ•°ã§ã™"
+
+#, c-format
+msgid "<%s>%s%s %d, Hex %02x, Oct %03o, Digr %s"
+msgstr "<%s>%s%s %d, 16進数 %02x, 8進数 %03o, ダイグラフ %s"
+
+#, c-format
+msgid "<%s>%s%s %d, Hex %02x, Octal %03o"
+msgstr "<%s>%s%s %d, 16進数 %02x, 8進数 %03o"
+
+#, c-format
+msgid "> %d, Hex %04x, Oct %o, Digr %s"
+msgstr "> %d, 16進数 %04x, 8進数 %o, ダイグラフ %s"
+
+#, c-format
+msgid "> %d, Hex %08x, Oct %o, Digr %s"
+msgstr "> %d, 16進数 %08x, 8進数 %o, ダイグラフ %s"
+
+#, c-format
+msgid "> %d, Hex %04x, Octal %o"
+msgstr "> %d, 16進数 %04x, 8進数 %o"
+
+#, c-format
+msgid "> %d, Hex %08x, Octal %o"
+msgstr "> %d, 16進数 %08x, 8進数 %o"
+
+msgid "E134: Cannot move a range of lines into itself"
+msgstr "E134: è¡Œã®ç¯„囲をãれ自身ã«ã¯ç§»å‹•ã§ãã¾ã›ã‚“"
+
+#, c-format
+msgid "%ld line moved"
+msgid_plural "%ld lines moved"
+msgstr[0] "%ld è¡ŒãŒç§»å‹•ã•ã‚Œã¾ã—ãŸ"
+
+#, c-format
+msgid "%ld lines filtered"
+msgstr "%ld è¡ŒãŒãƒ•ã‚£ãƒ«ã‚¿å‡¦ç†ã•ã‚Œã¾ã—ãŸ"
+
+msgid "E135: *Filter* Autocommands must not change current buffer"
+msgstr "E135: *フィルタ* autocommandã¯ç¾åœ¨ã®ãƒãƒƒãƒ•ã‚¡ã‚’変更ã—ã¦ã¯ã„ã‘ã¾ã›ã‚“"
+
+msgid "[No write since last change]\n"
+msgstr "[最後ã®å¤‰æ›´ãŒä¿å­˜ã•ã‚Œã¦ã„ã¾ã›ã‚“]\n"
+
+#, c-format
+msgid "%sviminfo: %s in line: "
+msgstr "%sviminfo: %s 行目: "
+
+msgid "E136: viminfo: Too many errors, skipping rest of file"
+msgstr "E136: viminfo: エラーãŒå¤šéŽãŽã‚‹ã®ã§ã€ä»¥é™ã¯ã‚¹ã‚­ãƒƒãƒ—ã—ã¾ã™"
+
+#, c-format
+msgid "Reading viminfo file \"%s\"%s%s%s"
+msgstr "viminfoファイル \"%s\"%s%s%s を読込ã¿ä¸­"
+
+msgid " info"
+msgstr " 情報"
+
+msgid " marks"
+msgstr " マーク"
+
+msgid " oldfiles"
+msgstr " 旧ファイル群"
+
+msgid " FAILED"
+msgstr " 失敗"
+
+#, c-format
+msgid "E137: Viminfo file is not writable: %s"
+msgstr "E137: viminfoファイルãŒæ›¸è¾¼ã¿ã§ãã¾ã›ã‚“: %s"
+
+#, c-format
+msgid "E929: Too many viminfo temp files, like %s!"
+msgstr "E929: 一時viminfoファイルãŒå¤šéŽãŽã¾ã™! 例: %s"
+
+#, c-format
+msgid "E138: Can't write viminfo file %s!"
+msgstr "E138: viminfoファイル %s ã‚’ä¿å­˜ã§ãã¾ã›ã‚“!"
+
+#, c-format
+msgid "Writing viminfo file \"%s\""
+msgstr "viminfoファイル \"%s\" を書込ã¿ä¸­"
+
+#, c-format
+msgid "E886: Can't rename viminfo file to %s!"
+msgstr "E886: viminfoファイルを %s ã¸åå‰å¤‰æ›´ã§ãã¾ã›ã‚“!"
+
+#, c-format
+msgid "# This viminfo file was generated by Vim %s.\n"
+msgstr "# ã“ã® viminfo ファイル㯠Vim %s ã«ã‚ˆã£ã¦ç”Ÿæˆã•ã‚Œã¾ã—ãŸ.\n"
+
+msgid ""
+"# You may edit it if you're careful!\n"
+"\n"
+msgstr ""
+"# 変更ã™ã‚‹éš›ã«ã¯å分注æ„ã—ã¦ãã ã•ã„!\n"
+"\n"
+
+msgid "# Value of 'encoding' when this file was written\n"
+msgstr "# ã“ã®ãƒ•ã‚¡ã‚¤ãƒ«ãŒæ›¸ã‹ã‚ŒãŸæ™‚ã® 'encoding' ã®å€¤\n"
+
+msgid "Illegal starting char"
+msgstr "ä¸æ­£ãªå…ˆé ­æ–‡å­—ã§ã™"
+
+msgid ""
+"\n"
+"# Bar lines, copied verbatim:\n"
+msgstr ""
+"\n"
+"# '|' ã§å§‹ã¾ã‚‹è¡Œã®ã€æ–‡å­—通りã®ã‚³ãƒ”ー:\n"
+
+msgid "Save As"
+msgstr "別åã§ä¿å­˜"
+
+msgid "Write partial file?"
+msgstr "ファイルを部分的ã«ä¿å­˜ã—ã¾ã™ã‹?"
+
+msgid "E140: Use ! to write partial buffer"
+msgstr "E140: ãƒãƒƒãƒ•ã‚¡ã‚’部分的ã«ä¿å­˜ã™ã‚‹ã«ã¯ ! を使ã£ã¦ãã ã•ã„"
+
+#, c-format
+msgid "Overwrite existing file \"%s\"?"
+msgstr "既存ã®ãƒ•ã‚¡ã‚¤ãƒ« \"%s\" を上書ãã—ã¾ã™ã‹?"
+
+#, c-format
+msgid "Swap file \"%s\" exists, overwrite anyway?"
+msgstr "スワップファイル \"%s\" ãŒå­˜åœ¨ã—ã¾ã™. 上書ãを強制ã—ã¾ã™ã‹?"
+
+#, c-format
+msgid "E768: Swap file exists: %s (:silent! overrides)"
+msgstr "E768: スワップファイルãŒå­˜åœ¨ã—ã¾ã™: %s (:silent! を追加ã§ä¸Šæ›¸)"
+
+#, c-format
+msgid "E141: No file name for buffer %ld"
+msgstr "E141: ãƒãƒƒãƒ•ã‚¡ %ld ã«ã¯åå‰ãŒã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E142: File not written: Writing is disabled by 'write' option"
+msgstr "E142: ファイルã¯ä¿å­˜ã•ã‚Œã¾ã›ã‚“ã§ã—ãŸ: 'write' オプションã«ã‚ˆã‚Šç„¡åŠ¹ã§ã™"
+
+#, c-format
+msgid ""
+"'readonly' option is set for \"%s\".\n"
+"Do you wish to write anyway?"
+msgstr ""
+"\"%s\" ã«ã¯ 'readonly' オプションãŒè¨­å®šã•ã‚Œã¦ã„ã¾ã™.\n"
+"上書ã強制をã—ã¾ã™ã‹?"
+
+#, c-format
+msgid ""
+"File permissions of \"%s\" are read-only.\n"
+"It may still be possible to write it.\n"
+"Do you wish to try?"
+msgstr ""
+"ファイル \"%s\" ã®ãƒ‘ーミッションãŒèª­è¾¼å°‚用ã§ã™.\n"
+"ãã‚Œã§ã‚‚æらã書ã込むã“ã¨ã¯å¯èƒ½ã§ã™.\n"
+"継続ã—ã¾ã™ã‹?"
+
+#, c-format
+msgid "E505: \"%s\" is read-only (add ! to override)"
+msgstr "E505: \"%s\" ã¯èª­è¾¼å°‚用ã§ã™ (強制書込ã«ã¯ ! を追加)"
+
+msgid "Edit File"
+msgstr "ファイルを編集"
+
+#, c-format
+msgid "E143: Autocommands unexpectedly deleted new buffer %s"
+msgstr "E143: autocommandãŒäºˆæœŸã›ãšæ–°ã—ã„ãƒãƒƒãƒ•ã‚¡ %s を削除ã—ã¾ã—ãŸ"
+
+msgid "E144: non-numeric argument to :z"
+msgstr "E144: æ•°ã§ã¯ãªã„引数㌠:z ã«æ¸¡ã•ã‚Œã¾ã—ãŸ"
+
+msgid "E145: Shell commands not allowed in rvim"
+msgstr "E145: rvimã§ã¯ã‚·ã‚§ãƒ«ã‚³ãƒžãƒ³ãƒ‰ã‚’使ãˆã¾ã›ã‚“"
+
+msgid "E146: Regular expressions can't be delimited by letters"
+msgstr "E146: æ­£è¦è¡¨ç¾ã¯æ–‡å­—ã§åŒºåˆ‡ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“"
+
+#, c-format
+msgid "replace with %s (y/n/a/q/l/^E/^Y)?"
+msgstr "%s ã«ç½®æ›ã—ã¾ã™ã‹? (y/n/a/q/l/^E/^Y)"
+
+msgid "(Interrupted) "
+msgstr "(割込ã¾ã‚Œã¾ã—ãŸ) "
+
+#, c-format
+msgid "%ld match on %ld line"
+msgid_plural "%ld matches on %ld line"
+msgstr[0] "%ld 箇所該当ã—ã¾ã—㟠(計 %ld 行内)"
+
+#, c-format
+msgid "%ld substitution on %ld line"
+msgid_plural "%ld substitutions on %ld line"
+msgstr[0] "%ld 箇所置æ›ã—ã¾ã—㟠(計 %ld 行内)"
+
+#, c-format
+msgid "%ld match on %ld lines"
+msgid_plural "%ld matches on %ld lines"
+msgstr[0] "%ld 箇所該当ã—ã¾ã—㟠(計 %ld 行内)"
+
+#, c-format
+msgid "%ld substitution on %ld lines"
+msgid_plural "%ld substitutions on %ld lines"
+msgstr[0] "%ld 箇所置æ›ã—ã¾ã—㟠(計 %ld 行内)"
+
+msgid "E147: Cannot do :global recursive with a range"
+msgstr "E147: :global を範囲付ãã§å†å¸°çš„ã«ã¯ä½¿ãˆã¾ã›ã‚“"
+
+msgid "E148: Regular expression missing from global"
+msgstr "E148: globalコマンドã«æ­£è¦è¡¨ç¾ãŒæŒ‡å®šã•ã‚Œã¦ã„ã¾ã›ã‚“"
+
+#, c-format
+msgid "Pattern found in every line: %s"
+msgstr "パターンãŒå…¨ã¦ã®è¡Œã§è¦‹ã¤ã‹ã‚Šã¾ã—ãŸ: %s"
+
+#, c-format
+msgid "Pattern not found: %s"
+msgstr "パターンã¯è¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸ: %s"
+
+msgid ""
+"\n"
+"# Last Substitute String:\n"
+"$"
+msgstr ""
+"\n"
+"# 最後ã«ç½®æ›ã•ã‚ŒãŸæ–‡å­—列:\n"
+"$"
+
+msgid "E478: Don't panic!"
+msgstr "E478: æ…Œã¦ãªã„ã§ãã ã•ã„"
+
+#, c-format
+msgid "E661: Sorry, no '%s' help for %s"
+msgstr "E661: 残念ã§ã™ãŒ '%s' ã®ãƒ˜ãƒ«ãƒ—㌠%s ã«ã¯ã‚ã‚Šã¾ã›ã‚“"
+
+#, c-format
+msgid "E149: Sorry, no help for %s"
+msgstr "E149: 残念ã§ã™ãŒ %s ã«ã¯ãƒ˜ãƒ«ãƒ—ãŒã‚ã‚Šã¾ã›ã‚“"
+
+#, c-format
+msgid "Sorry, help file \"%s\" not found"
+msgstr "残念ã§ã™ãŒãƒ˜ãƒ«ãƒ—ファイル \"%s\" ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“"
+
+#, c-format
+msgid "E151: No match: %s"
+msgstr "E151: マッãƒã¯ã‚ã‚Šã¾ã›ã‚“: %s"
+
+#, c-format
+msgid "E152: Cannot open %s for writing"
+msgstr "E152: 書込ã¿ç”¨ã« %s ã‚’é–‹ã‘ã¾ã›ã‚“"
+
+#, c-format
+msgid "E153: Unable to open %s for reading"
+msgstr "E153: 読込用㫠%s ã‚’é–‹ã‘ã¾ã›ã‚“"
+
+# Added at 29-Apr-2004.
+#, c-format
+msgid "E670: Mix of help file encodings within a language: %s"
+msgstr "E670: 1ã¤ã®è¨€èªžã®ãƒ˜ãƒ«ãƒ—ファイルã«è¤‡æ•°ã®ã‚¨ãƒ³ã‚³ãƒ¼ãƒ‰ãŒæ··åœ¨ã—ã¦ã„ã¾ã™: %s"
+
+#, c-format
+msgid "E154: Duplicate tag \"%s\" in file %s/%s"
+msgstr "E154: ã‚¿ã‚° \"%s\" ãŒãƒ•ã‚¡ã‚¤ãƒ« %s/%s ã«é‡è¤‡ã—ã¦ã„ã¾ã™"
+
+#, c-format
+msgid "E150: Not a directory: %s"
+msgstr "E150: ディレクトリã§ã¯ã‚ã‚Šã¾ã›ã‚“: %s"
+
+#, c-format
+msgid "E160: Unknown sign command: %s"
+msgstr "E160: 未知ã®signコマンドã§ã™: %s"
+
+msgid "E156: Missing sign name"
+msgstr "E156: signåãŒã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E612: Too many signs defined"
+msgstr "E612: signã®å®šç¾©ãŒå¤šæ•°è¦‹ã¤ã‹ã‚Šã¾ã—ãŸ"
+
+#, c-format
+msgid "E239: Invalid sign text: %s"
+msgstr "E239: 無効ãªsignã®ãƒ†ã‚­ã‚¹ãƒˆã§ã™: %s"
+
+#, c-format
+msgid "E155: Unknown sign: %s"
+msgstr "E155: 未知ã®signã§ã™: %s"
+
+msgid "E159: Missing sign number"
+msgstr "E159: signã®ç•ªå·ãŒã‚ã‚Šã¾ã›ã‚“"
+
+#, c-format
+msgid "E158: Invalid buffer name: %s"
+msgstr "E158: 無効ãªãƒãƒƒãƒ•ã‚¡åã§ã™: %s"
+
+msgid "E934: Cannot jump to a buffer that does not have a name"
+msgstr "E934: åå‰ã®ç„¡ã„ãƒãƒƒãƒ•ã‚¡ã¸ã¯ã‚¸ãƒ£ãƒ³ãƒ—ã§ãã¾ã›ã‚“"
+
+#, c-format
+msgid "E157: Invalid sign ID: %ld"
+msgstr "E157: 無効ãªsign識別å­ã§ã™: %ld"
+
+#, c-format
+msgid "E885: Not possible to change sign %s"
+msgstr "E885: 変更ã§ããªã„ sign ã§ã™: %s"
+
+# Added at 27-Jan-2004.
+msgid " (NOT FOUND)"
+msgstr " (見ã¤ã‹ã‚Šã¾ã›ã‚“)"
+
+msgid " (not supported)"
+msgstr " (éžã‚µãƒãƒ¼ãƒˆ)"
+
+msgid "[Deleted]"
+msgstr "[削除済]"
+
+msgid "No old files"
+msgstr "å¤ã„ファイルã¯ã‚ã‚Šã¾ã›ã‚“"
+
+msgid "Entering Debug mode. Type \"cont\" to continue."
+msgstr "デãƒãƒƒã‚°ãƒ¢ãƒ¼ãƒ‰ã«å…¥ã‚Šã¾ã™. 続ã‘ã‚‹ã«ã¯ \"cont\" ã¨å…¥åŠ›ã—ã¦ãã ã•ã„."
+
+#, c-format
+msgid "Oldval = \"%s\""
+msgstr "å¤ã„値 = \"%s\""
+
+#, c-format
+msgid "Newval = \"%s\""
+msgstr "æ–°ã—ã„値 = \"%s\""
+
+#, c-format
+msgid "line %ld: %s"
+msgstr "行 %ld: %s"
+
+#, c-format
+msgid "cmd: %s"
+msgstr "コマンド: %s"
+
+msgid "frame is zero"
+msgstr "フレーム㌠0 ã§ã™"
+
+#, c-format
+msgid "frame at highest level: %d"
+msgstr "最高レベルã®ãƒ•ãƒ¬ãƒ¼ãƒ : %d"
+
+#, c-format
+msgid "Breakpoint in \"%s%s\" line %ld"
+msgstr "ブレークãƒã‚¤ãƒ³ãƒˆ \"%s%s\" è¡Œ %ld"
+
+#, c-format
+msgid "E161: Breakpoint not found: %s"
+msgstr "E161: ブレークãƒã‚¤ãƒ³ãƒˆãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“: %s"
+
+msgid "No breakpoints defined"
+msgstr "ブレークãƒã‚¤ãƒ³ãƒˆãŒå®šç¾©ã•ã‚Œã¦ã„ã¾ã›ã‚“"
+
+#, c-format
+msgid "%3d %s %s line %ld"
+msgstr "%3d %s %s 行 %ld"
+
+#, c-format
+msgid "%3d expr %s"
+msgstr "%3d expr %s"
+
+msgid "E750: First use \":profile start {fname}\""
+msgstr "E750: åˆã‚ã« \":profile start {fname}\" を実行ã—ã¦ãã ã•ã„"
+
+#, c-format
+msgid "Save changes to \"%s\"?"
+msgstr "変更を \"%s\" ã«ä¿å­˜ã—ã¾ã™ã‹?"
+
+#, c-format
+msgid "E947: Job still running in buffer \"%s\""
+msgstr "E947: ジョブã¯ãƒãƒƒãƒ•ã‚¡ \"%s\" ã§ã¾ã å®Ÿè¡Œä¸­ã§ã™"
+
+#, c-format
+msgid "E162: No write since last change for buffer \"%s\""
+msgstr "E162: ãƒãƒƒãƒ•ã‚¡ \"%s\" ã®å¤‰æ›´ã¯ä¿å­˜ã•ã‚Œã¦ã„ã¾ã›ã‚“"
+
+msgid "Warning: Entered other buffer unexpectedly (check autocommands)"
+msgstr "警告: 予期ã›ãšä»–ãƒãƒƒãƒ•ã‚¡ã¸ç§»å‹•ã—ã¾ã—㟠(autocommands を調ã¹ã¦ãã ã•ã„)"
+
+msgid "E163: There is only one file to edit"
+msgstr "E163: 編集ã™ã‚‹ãƒ•ã‚¡ã‚¤ãƒ«ã¯1ã¤ã—ã‹ã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E164: Cannot go before first file"
+msgstr "E164: 最åˆã®ãƒ•ã‚¡ã‚¤ãƒ«ã‚ˆã‚Šå‰ã«ã¯è¡Œã‘ã¾ã›ã‚“"
+
+msgid "E165: Cannot go beyond last file"
+msgstr "E165: 最後ã®ãƒ•ã‚¡ã‚¤ãƒ«ã‚’越ãˆã¦å¾Œã«ã¯è¡Œã‘ã¾ã›ã‚“"
+
+#, c-format
+msgid "E666: compiler not supported: %s"
+msgstr "E666: ãã®ã‚³ãƒ³ãƒ‘イラã«ã¯å¯¾å¿œã—ã¦ã„ã¾ã›ã‚“: %s"
+
+#, c-format
+msgid "Searching for \"%s\" in \"%s\""
+msgstr "\"%s\" ã‚’ \"%s\" ã‹ã‚‰æ¤œç´¢ä¸­"
+
+#, c-format
+msgid "Searching for \"%s\""
+msgstr "\"%s\" を検索中"
+
+#, c-format
+msgid "not found in '%s': \"%s\""
+msgstr "'%s' ã®ä¸­ã«ã¯ã‚ã‚Šã¾ã›ã‚“: \"%s\""
+
+#, c-format
+msgid "W20: Required python version 2.x not supported, ignoring file: %s"
+msgstr "W20: è¦æ±‚ã•ã‚ŒãŸpython 2.xã¯å¯¾å¿œã—ã¦ã„ã¾ã›ã‚“ã€ãƒ•ã‚¡ã‚¤ãƒ«ã‚’無視ã—ã¾ã™: %s"
+
+#, c-format
+msgid "W21: Required python version 3.x not supported, ignoring file: %s"
+msgstr "W21: è¦æ±‚ã•ã‚ŒãŸpython 3.xã¯å¯¾å¿œã—ã¦ã„ã¾ã›ã‚“ã€ãƒ•ã‚¡ã‚¤ãƒ«ã‚’無視ã—ã¾ã™: %s"
+
+msgid "Source Vim script"
+msgstr "Vimスクリプトã®å–è¾¼ã¿"
+
+#, c-format
+msgid "Cannot source a directory: \"%s\""
+msgstr "ディレクトリã¯å–è¾¼ã‚ã¾ã›ã‚“: \"%s\""
+
+#, c-format
+msgid "could not source \"%s\""
+msgstr "\"%s\" ã‚’å–è¾¼ã‚ã¾ã›ã‚“"
+
+#, c-format
+msgid "line %ld: could not source \"%s\""
+msgstr "è¡Œ %ld: \"%s\" ã‚’å–è¾¼ã‚ã¾ã›ã‚“"
+
+#, c-format
+msgid "sourcing \"%s\""
+msgstr "\"%s\" ã‚’å–込中"
+
+#, c-format
+msgid "line %ld: sourcing \"%s\""
+msgstr "è¡Œ %ld: %s ã‚’å–込中"
+
+#, c-format
+msgid "finished sourcing %s"
+msgstr "%s ã®å–込を完了"
+
+#, c-format
+msgid "continuing in %s"
+msgstr "%s ã®å®Ÿè¡Œã‚’継続中ã§ã™"
+
+msgid "modeline"
+msgstr "モード行"
+
+msgid "--cmd argument"
+msgstr "--cmd 引数"
+
+msgid "-c argument"
+msgstr "-c 引数"
+
+msgid "environment variable"
+msgstr "環境変数"
+
+msgid "error handler"
+msgstr "エラーãƒãƒ³ãƒ‰ãƒ©"
+
+msgid "W15: Warning: Wrong line separator, ^M may be missing"
+msgstr "W15: 警告: 行区切ãŒä¸æ­£ã§ã™. ^M ãŒãªã„ã®ã§ã—ょã†"
+
+msgid "E167: :scriptencoding used outside of a sourced file"
+msgstr "E167: :scriptencoding ãŒå–込スクリプト以外ã§ä½¿ç”¨ã•ã‚Œã¾ã—ãŸ"
+
+msgid "E168: :finish used outside of a sourced file"
+msgstr "E168: :finish ãŒå–込スクリプト以外ã§ä½¿ç”¨ã•ã‚Œã¾ã—ãŸ"
+
+#, c-format
+msgid "Current %slanguage: \"%s\""
+msgstr "ç¾åœ¨ã® %s言語: \"%s\""
+
+#, c-format
+msgid "E197: Cannot set language to \"%s\""
+msgstr "E197: 言語を \"%s\" ã«è¨­å®šã§ãã¾ã›ã‚“"
+
+msgid "Entering Ex mode. Type \"visual\" to go to Normal mode."
+msgstr ""
+"Exモードã«å…¥ã‚Šã¾ã™. ノーマルモードã«æˆ»ã‚‹ã«ã¯\"visual\"ã¨å…¥åŠ›ã—ã¦ãã ã•ã„."
+
+msgid "E501: At end-of-file"
+msgstr "E501: ファイルã®çµ‚了ä½ç½®"
+
+msgid "E169: Command too recursive"
+msgstr "E169: コマンドãŒå†å¸°çš„éŽãŽã¾ã™"
+
+#, c-format
+msgid "E605: Exception not caught: %s"
+msgstr "E605: 例外ãŒæ•æ‰ã•ã‚Œã¾ã›ã‚“ã§ã—ãŸ: %s"
+
+msgid "End of sourced file"
+msgstr "å–込ファイルã®æœ€å¾Œã§ã™"
+
+msgid "End of function"
+msgstr "関数ã®æœ€å¾Œã§ã™"
+
+msgid "E464: Ambiguous use of user-defined command"
+msgstr "E464: ユーザー定義コマンドã®ã‚ã„ã¾ã„ãªä½¿ç”¨ã§ã™"
+
+msgid "E492: Not an editor command"
+msgstr "E492: エディタã®ã‚³ãƒžãƒ³ãƒ‰ã§ã¯ã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E493: Backwards range given"
+msgstr "E493: 逆ã•ã¾ã®ç¯„囲ãŒæŒ‡å®šã•ã‚Œã¾ã—ãŸ"
+
+msgid "Backwards range given, OK to swap"
+msgstr "逆ã•ã¾ã®ç¯„囲ãŒæŒ‡å®šã•ã‚Œã¾ã—ãŸã€å…¥æ›¿ãˆã¾ã™ã‹?"
+
+msgid "E494: Use w or w>>"
+msgstr "E494: w ã‚‚ã—ã㯠w>> を使用ã—ã¦ãã ã•ã„"
+
+msgid "E943: Command table needs to be updated, run 'make cmdidxs'"
+msgstr ""
+"E943: コマンドテーブルを更新ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€'make cmdidxs' を実行ã—ã¦ãã "
+"ã•ã„"
+
+msgid "E319: Sorry, the command is not available in this version"
+msgstr "E319: ã“ã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã§ã¯ã“ã®ã‚³ãƒžãƒ³ãƒ‰ã¯åˆ©ç”¨ã§ãã¾ã›ã‚“ã€ã”ã‚ã‚“ãªã•ã„"
+
+#, c-format
+msgid "%d more file to edit. Quit anyway?"
+msgid_plural "%d more files to edit. Quit anyway?"
+msgstr[0] "編集ã™ã¹ãファイルãŒã‚㨠%d 個ã‚ã‚Šã¾ã™ãŒã€çµ‚了ã—ã¾ã™ã‹?"
+
+#, c-format
+msgid "E173: %ld more file to edit"
+msgid_plural "E173: %ld more files to edit"
+msgstr[0] "E173: 編集ã™ã¹ãファイルãŒã‚㨠%ld 個ã‚ã‚Šã¾ã™"
+
+msgid "E174: Command already exists: add ! to replace it"
+msgstr "E174: コマンドãŒæ—¢ã«ã‚ã‚Šã¾ã™: å†å®šç¾©ã™ã‚‹ã«ã¯ ! を追加ã—ã¦ãã ã•ã„"
+
+msgid ""
+"\n"
+" Name Args Address Complete Definition"
+msgstr ""
+"\n"
+" åå‰ å¼•æ•° アドレス 補完 定義"
+
+msgid "No user-defined commands found"
+msgstr "ユーザー定義コマンドãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸ"
+
+msgid "E175: No attribute specified"
+msgstr "E175: 属性ã¯å®šç¾©ã•ã‚Œã¦ã„ã¾ã›ã‚“"
+
+msgid "E176: Invalid number of arguments"
+msgstr "E176: 引数ã®æ•°ãŒç„¡åŠ¹ã§ã™"
+
+msgid "E177: Count cannot be specified twice"
+msgstr "E177: カウントを2é‡æŒ‡å®šã™ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“"
+
+msgid "E178: Invalid default value for count"
+msgstr "E178: カウントã®çœç•¥å€¤ãŒç„¡åŠ¹ã§ã™"
+
+msgid "E179: argument required for -complete"
+msgstr "E179: -complete ã«ã¯å¼•æ•°ãŒå¿…è¦ã§ã™"
+
+msgid "E179: argument required for -addr"
+msgstr "E179: -addr ã«ã¯å¼•æ•°ãŒå¿…è¦ã§ã™"
+
+#, c-format
+msgid "E181: Invalid attribute: %s"
+msgstr "E181: 無効ãªå±žæ€§ã§ã™: %s"
+
+msgid "E182: Invalid command name"
+msgstr "E182: 無効ãªã‚³ãƒžãƒ³ãƒ‰åã§ã™"
+
+msgid "E183: User defined commands must start with an uppercase letter"
+msgstr "E183: ユーザー定義コマンドã¯è‹±å¤§æ–‡å­—ã§å§‹ã¾ã‚‰ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“"
+
+msgid "E841: Reserved name, cannot be used for user defined command"
+msgstr "E841: 予約åãªã®ã§ã€ãƒ¦ãƒ¼ã‚¶ãƒ¼å®šç¾©ã‚³ãƒžãƒ³ãƒ‰ã«åˆ©ç”¨ã§ãã¾ã›ã‚“"
+
+#, c-format
+msgid "E184: No such user-defined command: %s"
+msgstr "E184: ãã®ãƒ¦ãƒ¼ã‚¶ãƒ¼å®šç¾©ã‚³ãƒžãƒ³ãƒ‰ã¯ã‚ã‚Šã¾ã›ã‚“: %s"
+
+#, c-format
+msgid "E180: Invalid address type value: %s"
+msgstr "E180: 無効ãªã‚¢ãƒ‰ãƒ¬ã‚¹ã‚¿ã‚¤ãƒ—値ã§ã™: %s"
+
+#, c-format
+msgid "E180: Invalid complete value: %s"
+msgstr "E180: 無効ãªè£œå®ŒæŒ‡å®šã§ã™: %s"
+
+msgid "E468: Completion argument only allowed for custom completion"
+msgstr "E468: 補完引数ã¯ã‚«ã‚¹ã‚¿ãƒ è£œå®Œã§ã—ã‹ä½¿ç”¨ã§ãã¾ã›ã‚“"
+
+msgid "E467: Custom completion requires a function argument"
+msgstr "E467: カスタム補完ã«ã¯å¼•æ•°ã¨ã—ã¦é–¢æ•°ãŒå¿…è¦ã§ã™"
+
+msgid "unknown"
+msgstr "ä¸æ˜Ž"
+
+#, c-format
+msgid "E185: Cannot find color scheme '%s'"
+msgstr "E185: カラースキーム '%s' ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“"
+
+msgid "Greetings, Vim user!"
+msgstr "Vim 使ã„ã•ã‚“ã€ã‚„ã‚!"
+
+msgid "E784: Cannot close last tab page"
+msgstr "E784: 最後ã®ã‚¿ãƒ–ページを閉ã˜ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“"
+
+msgid "Already only one tab page"
+msgstr "æ—¢ã«ã‚¿ãƒ–ページã¯1ã¤ã—ã‹ã‚ã‚Šã¾ã›ã‚“"
+
+msgid "Edit File in new tab page"
+msgstr "æ–°ã—ã„タブページã§ãƒ•ã‚¡ã‚¤ãƒ«ã‚’編集ã—ã¾ã™"
+
+msgid "Edit File in new window"
+msgstr "æ–°ã—ã„ウィンドウã§ãƒ•ã‚¡ã‚¤ãƒ«ã‚’編集ã—ã¾ã™"
+
+#, c-format
+msgid "Tab page %d"
+msgstr "タブページ %d"
+
+msgid "No swap file"
+msgstr "スワップファイルãŒã‚ã‚Šã¾ã›ã‚“"
+
+msgid "Append File"
+msgstr "追加ファイル"
+
+msgid "E747: Cannot change directory, buffer is modified (add ! to override)"
+msgstr ""
+"E747: ãƒãƒƒãƒ•ã‚¡ãŒä¿®æ­£ã•ã‚Œã¦ã„ã‚‹ã®ã§ã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã‚’変更ã§ãã¾ã›ã‚“ (! を追加ã§"
+"上書)"
+
+msgid "E186: No previous directory"
+msgstr "E186: å‰ã®ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã¯ã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E187: Unknown"
+msgstr "E187: 未知"
+
+msgid "E465: :winsize requires two number arguments"
+msgstr "E465: :winsize ã«ã¯2ã¤ã®æ•°å€¤ã®å¼•æ•°ãŒå¿…è¦ã§ã™"
+
+#, c-format
+msgid "Window position: X %d, Y %d"
+msgstr "ウィンドウä½ç½®: X %d, Y %d"
+
+msgid "E188: Obtaining window position not implemented for this platform"
+msgstr ""
+"E188: ã“ã®ãƒ—ラットホームã«ã¯ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ä½ç½®ã®å–得機能ã¯å®Ÿè£…ã•ã‚Œã¦ã„ã¾ã›ã‚“"
+
+msgid "E466: :winpos requires two number arguments"
+msgstr "E466: :winpos ã«ã¯2ã¤ã®æ•°å€¤ã®å¼•æ•°ãŒå¿…è¦ã§ã™"
+
+msgid "E930: Cannot use :redir inside execute()"
+msgstr "E930: execute() ã®ä¸­ã§ã¯ :redir ã¯ä½¿ãˆã¾ã›ã‚“"
+
+msgid "Save Redirection"
+msgstr "リダイレクトをä¿å­˜ã—ã¾ã™"
+
+msgid "Save View"
+msgstr "ビューをä¿å­˜ã—ã¾ã™"
+
+msgid "Save Session"
+msgstr "セッション情報をä¿å­˜ã—ã¾ã™"
+
+msgid "Save Setup"
+msgstr "設定をä¿å­˜ã—ã¾ã™"
+
+#, c-format
+msgid "E739: Cannot create directory: %s"
+msgstr "E739: ディレクトリを作æˆã§ãã¾ã›ã‚“: %s"
+
+#, c-format
+msgid "E189: \"%s\" exists (add ! to override)"
+msgstr "E189: \"%s\" ãŒå­˜åœ¨ã—ã¾ã™ (上書ã™ã‚‹ã«ã¯ ! を追加ã—ã¦ãã ã•ã„)"
+
+#, c-format
+msgid "E190: Cannot open \"%s\" for writing"
+msgstr "E190: \"%s\" を書込ã¿ç”¨ã¨ã—ã¦é–‹ã‘ã¾ã›ã‚“"
+
+msgid "E191: Argument must be a letter or forward/backward quote"
+msgstr "E191: 引数ã¯1文字ã®è‹±å­—ã‹å¼•ç”¨ç¬¦ (' ã‹ `) ã§ãªã‘ã‚Œã°ã„ã‘ã¾ã›ã‚“"
+
+msgid "E192: Recursive use of :normal too deep"
+msgstr "E192: :normal ã®å†å¸°åˆ©ç”¨ãŒæ·±ããªã‚ŠéŽãŽã¾ã—ãŸ"
+
+msgid "E809: #< is not available without the +eval feature"
+msgstr "E809: #< 㯠+eval 機能ãŒç„¡ã„ã¨åˆ©ç”¨ã§ãã¾ã›ã‚“"
+
+msgid "E194: No alternate file name to substitute for '#'"
+msgstr "E194: '#'ã‚’ç½®ãæ›ãˆã‚‹å‰¯ãƒ•ã‚¡ã‚¤ãƒ«ã®åå‰ãŒã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E495: no autocommand file name to substitute for \"<afile>\""
+msgstr "E495: \"<afile>\"ã‚’ç½®ãæ›ãˆã‚‹autocommandã®ãƒ•ã‚¡ã‚¤ãƒ«åãŒã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E496: no autocommand buffer number to substitute for \"<abuf>\""
+msgstr "E496: \"<abuf>\"ã‚’ç½®ãæ›ãˆã‚‹autocommandãƒãƒƒãƒ•ã‚¡ç•ªå·ãŒã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E497: no autocommand match name to substitute for \"<amatch>\""
+msgstr "E497: \"<amatch>\"ã‚’ç½®ãæ›ãˆã‚‹autocommandã®è©²å½“åãŒã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E498: no :source file name to substitute for \"<sfile>\""
+msgstr "E498: \"<sfile>\"ã‚’ç½®ãæ›ãˆã‚‹ :source 対象ファイルåãŒã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E842: no line number to use for \"<slnum>\""
+msgstr "E842: \"<slnum>\"ã‚’ç½®ãæ›ãˆã‚‹è¡Œç•ªå·ãŒã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E961: no line number to use for \"<sflnum>\""
+msgstr "E961: \"<sflnum>\"ã‚’ç½®ãæ›ãˆã‚‹è¡Œç•ªå·ãŒã‚ã‚Šã¾ã›ã‚“"
+
+#, no-c-format
+msgid "E499: Empty file name for '%' or '#', only works with \":p:h\""
+msgstr ""
+"E499: '%' ã‚„ '#' ãŒç„¡åファイルãªã®ã§ \":p:h\" ã‚’ä¼´ã‚ãªã„使ã„æ–¹ã¯ã§ãã¾ã›ã‚“"
+
+msgid "E500: Evaluates to an empty string"
+msgstr "E500: 空文字列ã¨ã—ã¦è©•ä¾¡ã•ã‚Œã¾ã—ãŸ"
+
+msgid "E195: Cannot open viminfo file for reading"
+msgstr "E195: viminfoファイルを読込用ã¨ã—ã¦é–‹ã‘ã¾ã›ã‚“"
+
+msgid "Untitled"
+msgstr "無題"
+
+msgid "E196: No digraphs in this version"
+msgstr "E196: ã“ã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã«åˆå­—ã¯ã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E608: Cannot :throw exceptions with 'Vim' prefix"
+msgstr "E608: 'Vim' ã§å§‹ã¾ã‚‹ä¾‹å¤–㯠:throw ã§ãã¾ã›ã‚“"
+
+#, c-format
+msgid "Exception thrown: %s"
+msgstr "例外ãŒç™ºç”Ÿã—ã¾ã—ãŸ: %s"
+
+#, c-format
+msgid "Exception finished: %s"
+msgstr "例外ãŒåŽæŸã—ã¾ã—ãŸ: %s"
+
+#, c-format
+msgid "Exception discarded: %s"
+msgstr "例外ãŒç ´æ£„ã•ã‚Œã¾ã—ãŸ: %s"
+
+#, c-format
+msgid "%s, line %ld"
+msgstr "%s, 行 %ld"
+
+#, c-format
+msgid "Exception caught: %s"
+msgstr "例外ãŒæ•æ‰ã•ã‚Œã¾ã—ãŸ: %s"
+
+#, c-format
+msgid "%s made pending"
+msgstr "%s ã«ã‚ˆã‚Šæœªæ±ºå®šçŠ¶æ…‹ãŒç”Ÿã˜ã¾ã—ãŸ"
+
+#, c-format
+msgid "%s resumed"
+msgstr "%s ãŒå†é–‹ã—ã¾ã—ãŸ"
+
+#, c-format
+msgid "%s discarded"
+msgstr "%s ãŒç ´æ£„ã•ã‚Œã¾ã—ãŸ"
+
+msgid "Exception"
+msgstr "例外"
+
+msgid "Error and interrupt"
+msgstr "エラーã¨å‰²è¾¼ã¿"
+
+msgid "Error"
+msgstr "エラー"
+
+msgid "Interrupt"
+msgstr "割込ã¿"
+
+msgid "E579: :if nesting too deep"
+msgstr "E579: :if ã®å…¥ã‚Œå­ãŒæ·±éŽãŽã¾ã™"
+
+msgid "E580: :endif without :if"
+msgstr "E580: :if ã®ãªã„ :endif ãŒã‚ã‚Šã¾ã™"
+
+msgid "E581: :else without :if"
+msgstr "E581: :if ã®ãªã„ :else ãŒã‚ã‚Šã¾ã™"
+
+msgid "E582: :elseif without :if"
+msgstr "E582: :if ã®ãªã„ :elseif ãŒã‚ã‚Šã¾ã™"
+
+msgid "E583: multiple :else"
+msgstr "E583: 複数㮠:else ãŒã‚ã‚Šã¾ã™"
+
+msgid "E584: :elseif after :else"
+msgstr "E584: :else ã®å¾Œã« :elseif ãŒã‚ã‚Šã¾ã™"
+
+msgid "E585: :while/:for nesting too deep"
+msgstr "E585: :while ã‚„ :for ã®å…¥ã‚Œå­ãŒæ·±éŽãŽã¾ã™"
+
+msgid "E586: :continue without :while or :for"
+msgstr "E586: :while ã‚„ :for ã®ãªã„ :continue ãŒã‚ã‚Šã¾ã™"
+
+msgid "E587: :break without :while or :for"
+msgstr "E587: :while ã‚„ :for ã®ãªã„ :break ãŒã‚ã‚Šã¾ã™"
+
+msgid "E732: Using :endfor with :while"
+msgstr "E732: :endfor ã‚’ :while ã¨çµ„ã¿åˆã‚ã›ã¦ã„ã¾ã™"
+
+msgid "E733: Using :endwhile with :for"
+msgstr "E733: :endwhile ã‚’ :for ã¨çµ„ã¿åˆã‚ã›ã¦ã„ã¾ã™"
+
+msgid "E601: :try nesting too deep"
+msgstr "E601: :try ã®å…¥ã‚Œå­ãŒæ·±éŽãŽã¾ã™"
+
+msgid "E603: :catch without :try"
+msgstr "E603: :try ã®ãªã„ :catch ãŒã‚ã‚Šã¾ã™"
+
+msgid "E604: :catch after :finally"
+msgstr "E604: :finally ã®å¾Œã« :catch ãŒã‚ã‚Šã¾ã™"
+
+msgid "E606: :finally without :try"
+msgstr "E606: :try ã®ãªã„ :finally ãŒã‚ã‚Šã¾ã™"
+
+msgid "E607: multiple :finally"
+msgstr "E607: 複数㮠:finally ãŒã‚ã‚Šã¾ã™"
+
+msgid "E602: :endtry without :try"
+msgstr "E602: :try ã®ãªã„ :endtry ã§ã™"
+
+msgid "E193: :endfunction not inside a function"
+msgstr "E193: 関数ã®å¤–ã« :endfunction ãŒã‚ã‚Šã¾ã—ãŸ"
+
+msgid "E788: Not allowed to edit another buffer now"
+msgstr "E788: ç¾åœ¨ã¯ä»–ã®ãƒãƒƒãƒ•ã‚¡ã‚’編集ã™ã‚‹ã“ã¨ã¯è¨±ã•ã‚Œã¾ã›ã‚“"
+
+msgid "E811: Not allowed to change buffer information now"
+msgstr "E811: ç¾åœ¨ã¯ãƒãƒƒãƒ•ã‚¡æƒ…報を変更ã™ã‚‹ã“ã¨ã¯è¨±ã•ã‚Œã¾ã›ã‚“"
+
+msgid "tagname"
+msgstr "ã‚¿ã‚°å"
+
+msgid " kind file\n"
+msgstr " ファイル種類\n"
+
+msgid "'history' option is zero"
+msgstr "オプション 'history' ãŒã‚¼ãƒ­ã§ã™"
+
+#, c-format
+msgid ""
+"\n"
+"# %s History (newest to oldest):\n"
+msgstr ""
+"\n"
+"# %s é …ç›®ã®å±¥æ­´ (æ–°ã—ã„ã‚‚ã®ã‹ã‚‰å¤ã„ã‚‚ã®ã¸):\n"
+
+msgid "Command Line"
+msgstr "コマンドライン"
+
+msgid "Search String"
+msgstr "検索文字列"
+
+msgid "Expression"
+msgstr "å¼"
+
+msgid "Input Line"
+msgstr "入力行"
+
+msgid "Debug Line"
+msgstr "デãƒãƒƒã‚°è¡Œ"
+
+msgid "E198: cmd_pchar beyond the command length"
+msgstr "E198: cmd_pchar ãŒã‚³ãƒžãƒ³ãƒ‰é•·ã‚’超ãˆã¾ã—ãŸ"
+
+msgid "E199: Active window or buffer deleted"
+msgstr "E199: アクティブãªã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã‹ãƒãƒƒãƒ•ã‚¡ãŒå‰Šé™¤ã•ã‚Œã¾ã—ãŸ"
+
+msgid "E812: Autocommands changed buffer or buffer name"
+msgstr "E812: autocommandãŒãƒãƒƒãƒ•ã‚¡ã‹ãƒãƒƒãƒ•ã‚¡åを変更ã—ã¾ã—ãŸ"
+
+msgid "Illegal file name"
+msgstr "ä¸æ­£ãªãƒ•ã‚¡ã‚¤ãƒ«å"
+
+msgid "is a directory"
+msgstr "ã¯ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã§ã™"
+
+msgid "is not a file"
+msgstr "ã¯ãƒ•ã‚¡ã‚¤ãƒ«ã§ã¯ã‚ã‚Šã¾ã›ã‚“"
+
+msgid "is a device (disabled with 'opendevice' option)"
+msgstr "ã¯ãƒ‡ãƒã‚¤ã‚¹ã§ã™ ('opendevice' オプションã§å›žé¿ã§ãã¾ã™)"
+
+msgid "[New File]"
+msgstr "[新ファイル]"
+
+msgid "[New DIRECTORY]"
+msgstr "[æ–°è¦ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒª]"
+
+msgid "[File too big]"
+msgstr "[ファイルéŽå¤§]"
+
+msgid "[Permission Denied]"
+msgstr "[権é™ãŒã‚ã‚Šã¾ã›ã‚“]"
+
+msgid "E200: *ReadPre autocommands made the file unreadable"
+msgstr "E200: *ReadPre autocommand ãŒãƒ•ã‚¡ã‚¤ãƒ«ã‚’読込ä¸å¯ã«ã—ã¾ã—ãŸ"
+
+msgid "E201: *ReadPre autocommands must not change current buffer"
+msgstr "E201: *ReadPre autocommand ã¯ç¾åœ¨ã®ãƒãƒƒãƒ•ã‚¡ã‚’変ãˆã‚‰ã‚Œã¾ã›ã‚“"
+
+msgid "Vim: Reading from stdin...\n"
+msgstr "Vim: 標準入力ã‹ã‚‰èª­è¾¼ä¸­...\n"
+
+msgid "Reading from stdin..."
+msgstr "標準入力ã‹ã‚‰èª­è¾¼ã¿ä¸­..."
+
+msgid "E202: Conversion made file unreadable!"
+msgstr "E202: 変æ›ãŒãƒ•ã‚¡ã‚¤ãƒ«ã‚’読込ä¸å¯ã«ã—ã¾ã—ãŸ"
+
+msgid "[fifo]"
+msgstr "[FIFO]"
+
+msgid "[socket]"
+msgstr "[ソケット]"
+
+msgid "[character special]"
+msgstr "[キャラクタ・デãƒã‚¤ã‚¹]"
+
+msgid "[CR missing]"
+msgstr "[CRç„¡]"
+
+msgid "[long lines split]"
+msgstr "[長行分割]"
+
+msgid "[NOT converted]"
+msgstr "[未変æ›]"
+
+msgid "[converted]"
+msgstr "[変æ›æ¸ˆ]"
+
+#, c-format
+msgid "[CONVERSION ERROR in line %ld]"
+msgstr "[%ld 行目ã§å¤‰æ›ã‚¨ãƒ©ãƒ¼]"
+
+#, c-format
+msgid "[ILLEGAL BYTE in line %ld]"
+msgstr "[%ld 行目ã®ä¸æ­£ãªãƒã‚¤ãƒˆ]"
+
+msgid "[READ ERRORS]"
+msgstr "[読込エラー]"
+
+msgid "Can't find temp file for conversion"
+msgstr "変æ›ã«å¿…è¦ãªä¸€æ™‚ファイルãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“"
+
+msgid "Conversion with 'charconvert' failed"
+msgstr "'charconvert' ã«ã‚ˆã‚‹å¤‰æ›ãŒå¤±æ•—ã—ã¾ã—ãŸ"
+
+msgid "can't read output of 'charconvert'"
+msgstr "'charconvert' ã®å‡ºåŠ›ã‚’読込ã‚ã¾ã›ã‚“ã§ã—ãŸ"
+
+msgid "E676: No matching autocommands for acwrite buffer"
+msgstr "E676: acwriteãƒãƒƒãƒ•ã‚¡ã®è©²å½“ã™ã‚‹autocommandã¯å­˜åœ¨ã—ã¾ã›ã‚“"
+
+msgid "E203: Autocommands deleted or unloaded buffer to be written"
+msgstr "E203: ä¿å­˜ã™ã‚‹ãƒãƒƒãƒ•ã‚¡ã‚’autocommandãŒå‰Šé™¤ã‹è§£æ”¾ã—ã¾ã—ãŸ"
+
+msgid "E204: Autocommand changed number of lines in unexpected way"
+msgstr "E204: autocommandãŒäºˆæœŸã›ã¬æ–¹æ³•ã§è¡Œæ•°ã‚’変更ã—ã¾ã—ãŸ"
+
+# Added at 19-Jan-2004.
+msgid "NetBeans disallows writes of unmodified buffers"
+msgstr "NetBeansã¯æœªå¤‰æ›´ã®ãƒãƒƒãƒ•ã‚¡ã‚’上書ã™ã‚‹ã“ã¨ã¯è¨±å¯ã—ã¦ã„ã¾ã›ã‚“"
+
+msgid "Partial writes disallowed for NetBeans buffers"
+msgstr "NetBeansãƒãƒƒãƒ•ã‚¡ã®ä¸€éƒ¨ã‚’書ã出ã™ã“ã¨ã¯ã§ãã¾ã›ã‚“"
+
+msgid "is not a file or writable device"
+msgstr "ã¯ãƒ•ã‚¡ã‚¤ãƒ«ã§ã‚‚書込ã¿å¯èƒ½ãƒ‡ãƒã‚¤ã‚¹ã§ã‚‚ã‚ã‚Šã¾ã›ã‚“"
+
+msgid "writing to device disabled with 'opendevice' option"
+msgstr "'opendevice' オプションã«ã‚ˆã‚Šãƒ‡ãƒã‚¤ã‚¹ã¸ã®æ›¸ãè¾¼ã¿ã¯ã§ãã¾ã›ã‚“"
+
+msgid "is read-only (add ! to override)"
+msgstr "ã¯èª­è¾¼å°‚用ã§ã™ (強制書込ã«ã¯ ! を追加)"
+
+msgid "E506: Can't write to backup file (add ! to override)"
+msgstr "E506: ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—ファイルをä¿å­˜ã§ãã¾ã›ã‚“ (! を追加ã§å¼·åˆ¶ä¿å­˜)"
+
+msgid "E507: Close error for backup file (add ! to override)"
+msgstr ""
+"E507: ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—ファイルを閉ã˜ã‚‹éš›ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—㟠(! を追加ã§å¼·åˆ¶)"
+
+msgid "E508: Can't read file for backup (add ! to override)"
+msgstr "E508: ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—用ファイルを読込ã‚ã¾ã›ã‚“ (! を追加ã§å¼·åˆ¶èª­è¾¼)"
+
+msgid "E509: Cannot create backup file (add ! to override)"
+msgstr "E509: ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—ファイルを作れã¾ã›ã‚“ (! を追加ã§å¼·åˆ¶ä½œæˆ)"
+
+msgid "E510: Can't make backup file (add ! to override)"
+msgstr "E510: ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—ファイルを作れã¾ã›ã‚“ (! を追加ã§å¼·åˆ¶ä½œæˆ)"
+
+msgid "E214: Can't find temp file for writing"
+msgstr "E214: ä¿å­˜ç”¨ä¸€æ™‚ファイルãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“"
+
+msgid "E213: Cannot convert (add ! to write without conversion)"
+msgstr "E213: 変æ›ã§ãã¾ã›ã‚“ (! を追加ã§å¤‰æ›ã›ãšã«ä¿å­˜)"
+
+msgid "E166: Can't open linked file for writing"
+msgstr "E166: リンクã•ã‚ŒãŸãƒ•ã‚¡ã‚¤ãƒ«ã«æ›¸è¾¼ã‚ã¾ã›ã‚“"
+
+msgid "E212: Can't open file for writing"
+msgstr "E212: 書込ã¿ç”¨ã«ãƒ•ã‚¡ã‚¤ãƒ«ã‚’é–‹ã‘ã¾ã›ã‚“"
+
+msgid "E949: File changed while writing"
+msgstr "E949: 書込ã¿ä¸­ã«ãƒ•ã‚¡ã‚¤ãƒ«ãŒå¤‰æ›´ã•ã‚Œã¾ã—ãŸ"
+
+msgid "E512: Close failed"
+msgstr "E512: é–‰ã˜ã‚‹ã“ã¨ã«å¤±æ•—"
+
+msgid "E513: write error, conversion failed (make 'fenc' empty to override)"
+msgstr "E513: 書込ã¿ã‚¨ãƒ©ãƒ¼ã€å¤‰æ›å¤±æ•— (上書ã™ã‚‹ã«ã¯ 'fenc' を空ã«ã—ã¦ãã ã•ã„)"
+
+#, c-format
+msgid ""
+"E513: write error, conversion failed in line %ld (make 'fenc' empty to "
+"override)"
+msgstr ""
+"E513: 書込ã¿ã‚¨ãƒ©ãƒ¼ã€å¤‰æ›å¤±æ•—ã€è¡Œæ•° %ld (上書ã™ã‚‹ã«ã¯ 'fenc' を空ã«ã—ã¦ãã ã•"
+"ã„)"
+
+msgid "E514: write error (file system full?)"
+msgstr "E514: 書込ã¿ã‚¨ãƒ©ãƒ¼ (ファイルシステムãŒæº€æ¯?)"
+
+msgid " CONVERSION ERROR"
+msgstr " 変æ›ã‚¨ãƒ©ãƒ¼"
+
+#, c-format
+msgid " in line %ld;"
+msgstr " 行 %ld;"
+
+msgid "[Device]"
+msgstr "[デãƒã‚¤ã‚¹]"
+
+msgid "[New]"
+msgstr "[æ–°]"
+
+msgid " [a]"
+msgstr " [a]"
+
+msgid " appended"
+msgstr " 追加"
+
+msgid " [w]"
+msgstr " [w]"
+
+msgid " written"
+msgstr " 書込ã¿"
+
+msgid "E205: Patchmode: can't save original file"
+msgstr "E205: patchmode: 原本ファイルをä¿å­˜ã§ãã¾ã›ã‚“"
+
+msgid "E206: patchmode: can't touch empty original file"
+msgstr "E206: patchmode: 空ã®åŽŸæœ¬ãƒ•ã‚¡ã‚¤ãƒ«ã‚’touchã§ãã¾ã›ã‚“"
+
+msgid "E207: Can't delete backup file"
+msgstr "E207: ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—ファイルを消ã›ã¾ã›ã‚“"
+
+msgid ""
+"\n"
+"WARNING: Original file may be lost or damaged\n"
+msgstr ""
+"\n"
+"警告: 原本ファイルãŒå¤±ã‚ã‚ŒãŸã‹å¤‰æ›´ã•ã‚Œã¾ã—ãŸ\n"
+
+msgid "don't quit the editor until the file is successfully written!"
+msgstr "ファイルã®ä¿å­˜ã«æˆåŠŸã™ã‚‹ã¾ã§ã‚¨ãƒ‡ã‚£ã‚¿ã‚’終了ã—ãªã„ã§ãã ã•ã„!"
+
+msgid "[dos]"
+msgstr "[dos]"
+
+msgid "[dos format]"
+msgstr "[dosフォーマット]"
+
+msgid "[mac]"
+msgstr "[mac]"
+
+msgid "[mac format]"
+msgstr "[macフォーマット]"
+
+msgid "[unix]"
+msgstr "[unix]"
+
+msgid "[unix format]"
+msgstr "[unixフォーマット]"
+
+#, c-format
+msgid "%ld line, "
+msgid_plural "%ld lines, "
+msgstr[0] "%ld 行, "
+
+#, c-format
+msgid "%lld character"
+msgid_plural "%lld characters"
+msgstr[0] "%lld 文字"
+
+msgid "[noeol]"
+msgstr "[noeol]"
+
+msgid "[Incomplete last line]"
+msgstr "[最終行ãŒä¸å®Œå…¨]"
+
+msgid "WARNING: The file has been changed since reading it!!!"
+msgstr "警告: 読込んã å¾Œã«ãƒ•ã‚¡ã‚¤ãƒ«ã«å¤‰æ›´ãŒã‚ã‚Šã¾ã—ãŸ!!!"
+
+msgid "Do you really want to write to it"
+msgstr "本当ã«ä¸Šæ›¸ãã—ã¾ã™ã‹"
+
+#, c-format
+msgid "E208: Error writing to \"%s\""
+msgstr "E208: \"%s\" を書込ã¿ä¸­ã®ã‚¨ãƒ©ãƒ¼ã§ã™"
+
+#, c-format
+msgid "E209: Error closing \"%s\""
+msgstr "E209: \"%s\" ã‚’é–‰ã˜ã‚‹æ™‚ã«ã‚¨ãƒ©ãƒ¼ã§ã™"
+
+#, c-format
+msgid "E210: Error reading \"%s\""
+msgstr "E210: \"%s\" を読込中ã®ã‚¨ãƒ©ãƒ¼ã§ã™"
+
+msgid "E246: FileChangedShell autocommand deleted buffer"
+msgstr "E246: autocommand ã® FileChangedShell ãŒãƒãƒƒãƒ•ã‚¡ã‚’削除ã—ã¾ã—ãŸ"
+
+#, c-format
+msgid "E211: File \"%s\" no longer available"
+msgstr "E211: ファイル \"%s\" ã¯æ—¢ã«å­˜åœ¨ã—ã¾ã›ã‚“"
+
+#, c-format
+msgid ""
+"W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as "
+"well"
+msgstr "W12: 警告: ファイル \"%s\" ãŒå¤‰æ›´ã•ã‚ŒVimã®ãƒãƒƒãƒ•ã‚¡ã‚‚変更ã•ã‚Œã¾ã—ãŸ"
+
+msgid "See \":help W12\" for more info."
+msgstr "詳細㯠\":help W12\" ã‚’å‚ç…§ã—ã¦ãã ã•ã„"
+
+#, c-format
+msgid "W11: Warning: File \"%s\" has changed since editing started"
+msgstr "W11: 警告: ファイル \"%s\" ã¯ç·¨é›†é–‹å§‹å¾Œã«å¤‰æ›´ã•ã‚Œã¾ã—ãŸ"
+
+msgid "See \":help W11\" for more info."
+msgstr "詳細㯠\":help W11\" ã‚’å‚ç…§ã—ã¦ãã ã•ã„"
+
+#, c-format
+msgid "W16: Warning: Mode of file \"%s\" has changed since editing started"
+msgstr "W16: 警告: ファイル \"%s\" ã®ãƒ¢ãƒ¼ãƒ‰ãŒç·¨é›†é–‹å§‹å¾Œã«å¤‰æ›´ã•ã‚Œã¾ã—ãŸ"
+
+msgid "See \":help W16\" for more info."
+msgstr "詳細㯠\":help W16\" ã‚’å‚ç…§ã—ã¦ãã ã•ã„"
+
+#, c-format
+msgid "W13: Warning: File \"%s\" has been created after editing started"
+msgstr "W13: 警告: ファイル \"%s\" ã¯ç·¨é›†é–‹å§‹å¾Œã«ä½œæˆã•ã‚Œã¾ã—ãŸ"
+
+msgid "Warning"
+msgstr "警告"
+
+msgid ""
+"&OK\n"
+"&Load File"
+msgstr ""
+"&OK\n"
+"ファイル読込(&L)"
+
+#, c-format
+msgid "E462: Could not prepare for reloading \"%s\""
+msgstr "E462: \"%s\" をリロードã™ã‚‹æº–å‚™ãŒã§ãã¾ã›ã‚“ã§ã—ãŸ"
+
+#, c-format
+msgid "E321: Could not reload \"%s\""
+msgstr "E321: \"%s\" ã¯ãƒªãƒ­ãƒ¼ãƒ‰ã§ãã¾ã›ã‚“ã§ã—ãŸ"
+
+msgid "--Deleted--"
+msgstr "--削除済--"
+
+#, c-format
+msgid "auto-removing autocommand: %s <buffer=%d>"
+msgstr "autocommand: %s <ãƒãƒƒãƒ•ã‚¡=%d> ãŒè‡ªå‹•çš„ã«å‰Šé™¤ã•ã‚Œã¾ã™"
+
+#, c-format
+msgid "E367: No such group: \"%s\""
+msgstr "E367: ãã®ã‚°ãƒ«ãƒ¼ãƒ—ã¯ã‚ã‚Šã¾ã›ã‚“: \"%s\""
+
+msgid "E936: Cannot delete the current group"
+msgstr "E936: ç¾åœ¨ã®ã‚°ãƒ«ãƒ¼ãƒ—ã¯å‰Šé™¤ã§ãã¾ã›ã‚“"
+
+msgid "W19: Deleting augroup that is still in use"
+msgstr "W19: 使用中㮠augroup を消ãã†ã¨ã—ã¦ã„ã¾ã™"
+
+#, c-format
+msgid "E215: Illegal character after *: %s"
+msgstr "E215: * ã®å¾Œã«ä¸æ­£ãªæ–‡å­—ãŒã‚ã‚Šã¾ã—ãŸ: %s"
+
+#, c-format
+msgid "E216: No such event: %s"
+msgstr "E216: ãã®ã‚ˆã†ãªã‚¤ãƒ™ãƒ³ãƒˆã¯ã‚ã‚Šã¾ã›ã‚“: %s"
+
+#, c-format
+msgid "E216: No such group or event: %s"
+msgstr "E216: ãã®ã‚ˆã†ãªã‚°ãƒ«ãƒ¼ãƒ—ã‚‚ã—ãã¯ã‚¤ãƒ™ãƒ³ãƒˆã¯ã‚ã‚Šã¾ã›ã‚“: %s"
+
+msgid ""
+"\n"
+"--- Autocommands ---"
+msgstr ""
+"\n"
+"--- Autocommands ---"
+
+#, c-format
+msgid "E680: <buffer=%d>: invalid buffer number "
+msgstr "E680: <ãƒãƒƒãƒ•ã‚¡=%d>: 無効ãªãƒãƒƒãƒ•ã‚¡ç•ªå·ã§ã™ "
+
+msgid "E217: Can't execute autocommands for ALL events"
+msgstr "E217: å…¨ã¦ã®ã‚¤ãƒ™ãƒ³ãƒˆã«å¯¾ã—ã¦ã®autocommandã¯å®Ÿè¡Œã§ãã¾ã›ã‚“"
+
+msgid "No matching autocommands"
+msgstr "該当ã™ã‚‹autocommandã¯å­˜åœ¨ã—ã¾ã›ã‚“"
+
+msgid "E218: autocommand nesting too deep"
+msgstr "E218: autocommandã®å…¥ã‚Œå­ãŒæ·±éŽãŽã¾ã™"
+
+#, c-format
+msgid "%s Autocommands for \"%s\""
+msgstr "%s Autocommands for \"%s\""
+
+#, c-format
+msgid "Executing %s"
+msgstr "%s を実行ã—ã¦ã„ã¾ã™"
+
+#, c-format
+msgid "autocommand %s"
+msgstr "autocommand %s"
+
+msgid "E219: Missing {."
+msgstr "E219: { ãŒã‚ã‚Šã¾ã›ã‚“."
+
+msgid "E220: Missing }."
+msgstr "E220: } ãŒã‚ã‚Šã¾ã›ã‚“."
+
+msgid "E490: No fold found"
+msgstr "E490: 折畳ã¿ãŒã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E350: Cannot create fold with current 'foldmethod'"
+msgstr "E350: ç¾åœ¨ã® 'foldmethod' ã§ã¯æŠ˜ç•³ã¿ã‚’作æˆã§ãã¾ã›ã‚“"
+
+msgid "E351: Cannot delete fold with current 'foldmethod'"
+msgstr "E351: ç¾åœ¨ã® 'foldmethod' ã§ã¯æŠ˜ç•³ã¿ã‚’削除ã§ãã¾ã›ã‚“"
+
+#, c-format
+msgid "+--%3ld line folded "
+msgid_plural "+--%3ld lines folded "
+msgstr[0] "+--%3ld è¡ŒãŒæŠ˜ç•³ã¾ã‚Œã¾ã—ãŸ"
+
+msgid "E222: Add to read buffer"
+msgstr "E222: 読込ãƒãƒƒãƒ•ã‚¡ã¸è¿½åŠ "
+
+msgid "E223: recursive mapping"
+msgstr "E223: å†å¸°çš„マッピング"
+
+#, c-format
+msgid "E224: global abbreviation already exists for %s"
+msgstr "E224: %s ã¨ã„ã†ã‚°ãƒ­ãƒ¼ãƒãƒ«çŸ­ç¸®å…¥åŠ›ã¯æ—¢ã«å­˜åœ¨ã—ã¾ã™"
+
+#, c-format
+msgid "E225: global mapping already exists for %s"
+msgstr "E225: %s ã¨ã„ã†ã‚°ãƒ­ãƒ¼ãƒãƒ«ãƒžãƒƒãƒ”ングã¯æ—¢ã«å­˜åœ¨ã—ã¾ã™"
+
+#, c-format
+msgid "E226: abbreviation already exists for %s"
+msgstr "E226: %s ã¨ã„ã†çŸ­ç¸®å…¥åŠ›ã¯æ—¢ã«å­˜åœ¨ã—ã¾ã™"
+
+#, c-format
+msgid "E227: mapping already exists for %s"
+msgstr "E227: %s ã¨ã„ã†ãƒžãƒƒãƒ”ングã¯æ—¢ã«å­˜åœ¨ã—ã¾ã™"
+
+msgid "No abbreviation found"
+msgstr "短縮入力ã¯è¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸ"
+
+msgid "No mapping found"
+msgstr "マッピングã¯è¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸ"
+
+msgid "E228: makemap: Illegal mode"
+msgstr "E228: makemap: ä¸æ­£ãªãƒ¢ãƒ¼ãƒ‰"
+
+msgid "E851: Failed to create a new process for the GUI"
+msgstr "E851: GUI用ã®ãƒ—ロセスã®èµ·å‹•ã«å¤±æ•—ã—ã¾ã—ãŸ"
+
+msgid "E852: The child process failed to start the GUI"
+msgstr "E852: å­ãƒ—ロセスãŒGUIã®èµ·å‹•ã«å¤±æ•—ã—ã¾ã—ãŸ"
+
+msgid "E229: Cannot start the GUI"
+msgstr "E229: GUIを開始ã§ãã¾ã›ã‚“"
+
+#, c-format
+msgid "E230: Cannot read from \"%s\""
+msgstr "E230: \"%s\"ã‹ã‚‰èª­è¾¼ã‚€ã“ã¨ãŒã§ãã¾ã›ã‚“"
+
+msgid "E665: Cannot start GUI, no valid font found"
+msgstr "E665: 有効ãªãƒ•ã‚©ãƒ³ãƒˆãŒè¦‹ã¤ã‹ã‚‰ãªã„ã®ã§ã€GUIを開始ã§ãã¾ã›ã‚“"
+
+msgid "E231: 'guifontwide' invalid"
+msgstr "E231: 'guifontwide' ãŒç„¡åŠ¹ã§ã™"
+
+msgid "E599: Value of 'imactivatekey' is invalid"
+msgstr "E599: 'imactivatekey' ã«è¨­å®šã•ã‚ŒãŸå€¤ãŒç„¡åŠ¹ã§ã™"
+
+#, c-format
+msgid "E254: Cannot allocate color %s"
+msgstr "E254: %s ã®è‰²ã‚’割り当ã¦ã‚‰ã‚Œã¾ã›ã‚“"
+
+msgid "No match at cursor, finding next"
+msgstr "カーソルã®ä½ç½®ã«ãƒžãƒƒãƒã¯ã‚ã‚Šã¾ã›ã‚“ã€æ¬¡ã‚’検索ã—ã¦ã„ã¾ã™"
+
+msgid "<cannot open> "
+msgstr "<é–‹ã‘ã¾ã›ã‚“> "
+
+#, c-format
+msgid "E616: vim_SelFile: can't get font %s"
+msgstr "E616: vim_SelFile: フォント %s ã‚’å–å¾—ã§ãã¾ã›ã‚“"
+
+msgid "E614: vim_SelFile: can't return to current directory"
+msgstr "E614: vim_SelFile: ç¾åœ¨ã®ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã«æˆ»ã‚Œã¾ã›ã‚“"
+
+msgid "Pathname:"
+msgstr "パスå:"
+
+msgid "E615: vim_SelFile: can't get current directory"
+msgstr "E615: vim_SelFile: ç¾åœ¨ã®ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã‚’å–å¾—ã§ãã¾ã›ã‚“"
+
+msgid "OK"
+msgstr "OK"
+
+msgid "Cancel"
+msgstr "キャンセル"
+
+msgid "Scrollbar Widget: Could not get geometry of thumb pixmap."
+msgstr "スクロールãƒãƒ¼: ç”»åƒã‚’å–å¾—ã§ãã¾ã›ã‚“ã§ã—ãŸ."
+
+msgid "Vim dialog"
+msgstr "Vim ダイアログ"
+
+msgid "E232: Cannot create BalloonEval with both message and callback"
+msgstr "E232: メッセージã¨ã‚³ãƒ¼ãƒ«ãƒãƒƒã‚¯ã®ã‚ã‚‹ BalloonEval を作æˆã§ãã¾ã›ã‚“"
+
+msgid "_Cancel"
+msgstr "キャンセル(_C)"
+
+msgid "_Save"
+msgstr "ä¿å­˜(_S)"
+
+msgid "_Open"
+msgstr "é–‹ã(_O)"
+
+msgid "_OK"
+msgstr "_OK"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"&Cancel"
+msgstr ""
+"ã¯ã„(&Y)\n"
+"ã„ã„ãˆ(&N)\n"
+"キャンセル(&C)"
+
+msgid "Yes"
+msgstr "ã¯ã„"
+
+msgid "No"
+msgstr "ã„ã„ãˆ"
+
+msgid "Input _Methods"
+msgstr "インプットメソッド"
+
+msgid "VIM - Search and Replace..."
+msgstr "VIM - 検索ã¨ç½®æ›..."
+
+msgid "VIM - Search..."
+msgstr "VIM - 検索..."
+
+msgid "Find what:"
+msgstr "検索文字列:"
+
+msgid "Replace with:"
+msgstr "ç½®æ›æ–‡å­—列:"
+
+msgid "Match whole word only"
+msgstr "正確ã«è©²å½“ã™ã‚‹ã‚‚ã®ã ã‘"
+
+msgid "Match case"
+msgstr "大文字/å°æ–‡å­—を区別ã™ã‚‹"
+
+msgid "Direction"
+msgstr "æ–¹å‘"
+
+msgid "Up"
+msgstr "上"
+
+msgid "Down"
+msgstr "下"
+
+msgid "Find Next"
+msgstr "次を検索"
+
+msgid "Replace"
+msgstr "ç½®æ›"
+
+msgid "Replace All"
+msgstr "å…¨ã¦ç½®æ›"
+
+msgid "_Close"
+msgstr "é–‰ã˜ã‚‹(_C)"
+
+msgid "Vim: Received \"die\" request from session manager\n"
+msgstr "Vim: セッションマãƒãƒ¼ã‚¸ãƒ£ã‹ã‚‰ \"die\" è¦æ±‚ã‚’å—ã‘å–ã‚Šã¾ã—ãŸ\n"
+
+msgid "Close tab"
+msgstr "タブページを閉ã˜ã‚‹"
+
+msgid "New tab"
+msgstr "æ–°è¦ã‚¿ãƒ–ページ"
+
+msgid "Open Tab..."
+msgstr "タブページを開ã..."
+
+msgid "Vim: Main window unexpectedly destroyed\n"
+msgstr "Vim: メインウィンドウãŒä¸æ„ã«ç ´å£Šã•ã‚Œã¾ã—ãŸ\n"
+
+msgid "&Filter"
+msgstr "フィルタ(&F)"
+
+msgid "&Cancel"
+msgstr "キャンセル(&C)"
+
+msgid "Directories"
+msgstr "ディレクトリ"
+
+msgid "Filter"
+msgstr "フィルタ"
+
+msgid "&Help"
+msgstr "ヘルプ(&H)"
+
+msgid "Files"
+msgstr "ファイル"
+
+msgid "&OK"
+msgstr "&OK"
+
+msgid "Selection"
+msgstr "é¸æŠž"
+
+msgid "Find &Next"
+msgstr "次を検索(&N)"
+
+msgid "&Replace"
+msgstr "ç½®æ›(&R)"
+
+msgid "Replace &All"
+msgstr "å…¨ã¦ç½®æ›(&A)"
+
+msgid "&Undo"
+msgstr "アンドゥ(&U)"
+
+msgid "Open tab..."
+msgstr "タブページを開ã"
+
+msgid "Find string"
+msgstr "検索文字列"
+
+msgid "Find & Replace"
+msgstr "検索・置æ›"
+
+msgid "Not Used"
+msgstr "使ã‚ã‚Œã¾ã›ã‚“"
+
+msgid "Directory\t*.nothing\n"
+msgstr "ディレクトリ\t*.nothing\n"
+
+#, c-format
+msgid "E671: Cannot find window title \"%s\""
+msgstr "E671: タイトル㌠\"%s\" ã®ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã¯è¦‹ã¤ã‹ã‚Šã¾ã›ã‚“"
+
+#, c-format
+msgid "E243: Argument not supported: \"-%s\"; Use the OLE version."
+msgstr "E243: 引数ã¯ã‚µãƒãƒ¼ãƒˆã•ã‚Œã¾ã›ã‚“: \"-%s\"; OLE版を使用ã—ã¦ãã ã•ã„."
+
+msgid "E672: Unable to open window inside MDI application"
+msgstr "E672: MDIアプリã®ä¸­ã§ã¯ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã‚’é–‹ã‘ã¾ã›ã‚“"
+
+msgid "Vim E458: Cannot allocate colormap entry, some colors may be incorrect"
+msgstr "Vim E458: 色指定ãŒæ­£ã—ããªã„ã®ã§ã‚¨ãƒ³ãƒˆãƒªã‚’割り当ã¦ã‚‰ã‚Œã¾ã›ã‚“"
+
+#, c-format
+msgid "E250: Fonts for the following charsets are missing in fontset %s:"
+msgstr "E250: 以下ã®æ–‡å­—セットã®ãƒ•ã‚©ãƒ³ãƒˆãŒã‚ã‚Šã¾ã›ã‚“ %s:"
+
+#, c-format
+msgid "E252: Fontset name: %s"
+msgstr "E252: フォントセットå: %s"
+
+#, c-format
+msgid "Font '%s' is not fixed-width"
+msgstr "フォント '%s' ã¯å›ºå®šå¹…ã§ã¯ã‚ã‚Šã¾ã›ã‚“"
+
+#, c-format
+msgid "E253: Fontset name: %s"
+msgstr "E253: フォントセットå: %s"
+
+#, c-format
+msgid "Font0: %s"
+msgstr "フォント0: %s"
+
+#, c-format
+msgid "Font1: %s"
+msgstr "フォント1: %s"
+
+#, c-format
+msgid "Font%ld width is not twice that of font0"
+msgstr "フォント%ld ã®å¹…ãŒãƒ•ã‚©ãƒ³ãƒˆ0ã®2å€ã§ã¯ã‚ã‚Šã¾ã›ã‚“"
+
+#, c-format
+msgid "Font0 width: %ld"
+msgstr "フォント0ã®å¹…: %ld"
+
+#, c-format
+msgid "Font1 width: %ld"
+msgstr "フォント1ã®å¹…: %ld"
+
+msgid "Invalid font specification"
+msgstr "無効ãªãƒ•ã‚©ãƒ³ãƒˆæŒ‡å®šã§ã™"
+
+msgid "&Dismiss"
+msgstr "å´ä¸‹ã™ã‚‹(&D)"
+
+msgid "no specific match"
+msgstr "マッãƒã™ã‚‹ã‚‚ã®ãŒã‚ã‚Šã¾ã›ã‚“"
+
+msgid "Vim - Font Selector"
+msgstr "Vim - フォントé¸æŠž"
+
+msgid "Name:"
+msgstr "åå‰:"
+
+msgid "Show size in Points"
+msgstr "サイズをãƒã‚¤ãƒ³ãƒˆã§è¡¨ç¤ºã™ã‚‹"
+
+msgid "Encoding:"
+msgstr "エンコード:"
+
+msgid "Font:"
+msgstr "フォント:"
+
+msgid "Style:"
+msgstr "スタイル:"
+
+msgid "Size:"
+msgstr "サイズ:"
+
+msgid "E256: Hangul automata ERROR"
+msgstr "E256: ãƒãƒ³ã‚°ãƒ«ã‚ªãƒ¼ãƒˆãƒžãƒˆãƒ³ã‚¨ãƒ©ãƒ¼"
+
+msgid "E550: Missing colon"
+msgstr "E550: コロンãŒã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E551: Illegal component"
+msgstr "E551: ä¸æ­£ãªæ§‹æ–‡è¦ç´ ã§ã™"
+
+msgid "E552: digit expected"
+msgstr "E552: 数値ãŒå¿…è¦ã§ã™"
+
+#, c-format
+msgid "Page %d"
+msgstr "%d ページ"
+
+msgid "No text to be printed"
+msgstr "å°åˆ·ã™ã‚‹ãƒ†ã‚­ã‚¹ãƒˆãŒã‚ã‚Šã¾ã›ã‚“"
+
+#, c-format
+msgid "Printing page %d (%d%%)"
+msgstr "å°åˆ·ä¸­: ページ %d (%d%%)"
+
+#, c-format
+msgid " Copy %d of %d"
+msgstr " コピー %d (全 %d 中)"
+
+#, c-format
+msgid "Printed: %s"
+msgstr "å°åˆ·ã—ã¾ã—ãŸ: %s"
+
+msgid "Printing aborted"
+msgstr "å°åˆ·ãŒä¸­æ­¢ã•ã‚Œã¾ã—ãŸ"
+
+msgid "E455: Error writing to PostScript output file"
+msgstr "E455: PostScript出力ファイルã®æ›¸è¾¼ã¿ã‚¨ãƒ©ãƒ¼ã§ã™"
+
+#, c-format
+msgid "E624: Can't open file \"%s\""
+msgstr "E624: ファイル \"%s\" ã‚’é–‹ã‘ã¾ã›ã‚“"
+
+#, c-format
+msgid "E457: Can't read PostScript resource file \"%s\""
+msgstr "E457: PostScriptã®ãƒªã‚½ãƒ¼ã‚¹ãƒ•ã‚¡ã‚¤ãƒ« \"%s\" を読込ã‚ã¾ã›ã‚“"
+
+#, c-format
+msgid "E618: file \"%s\" is not a PostScript resource file"
+msgstr "E618: ファイル \"%s\" 㯠PostScript リソースファイルã§ã¯ã‚ã‚Šã¾ã›ã‚“"
+
+#, c-format
+msgid "E619: file \"%s\" is not a supported PostScript resource file"
+msgstr "E619: ファイル \"%s\" ã¯å¯¾å¿œã—ã¦ã„ãªã„ PostScript リソースファイルã§ã™"
+
+#, c-format
+msgid "E621: \"%s\" resource file has wrong version"
+msgstr "E621: リソースファイル \"%s\" ã¯ãƒãƒ¼ã‚¸ãƒ§ãƒ³ãŒç•°ãªã‚Šã¾ã™"
+
+msgid "E673: Incompatible multi-byte encoding and character set."
+msgstr "E673: 互æ›æ€§ã®ç„¡ã„マルãƒãƒã‚¤ãƒˆã‚¨ãƒ³ã‚³ãƒ¼ãƒ‡ã‚£ãƒ³ã‚°ã¨æ–‡å­—セットã§ã™"
+
+msgid "E674: printmbcharset cannot be empty with multi-byte encoding."
+msgstr "E674: マルãƒãƒã‚¤ãƒˆã‚¨ãƒ³ã‚³ãƒ¼ãƒ‡ã‚£ãƒ³ã‚°ã§ã¯ printmbcharset を空ã«ã§ãã¾ã›ã‚“"
+
+msgid "E675: No default font specified for multi-byte printing."
+msgstr ""
+"E675: マルãƒãƒã‚¤ãƒˆæ–‡å­—ã‚’å°åˆ·ã™ã‚‹ãŸã‚ã®ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆãƒ•ã‚©ãƒ³ãƒˆãŒæŒ‡å®šã•ã‚Œã¦ã„ã¾ã›ã‚“"
+
+msgid "E324: Can't open PostScript output file"
+msgstr "E324: PostScript出力用ã®ãƒ•ã‚¡ã‚¤ãƒ«ã‚’é–‹ã‘ã¾ã›ã‚“"
+
+#, c-format
+msgid "E456: Can't open file \"%s\""
+msgstr "E456: ファイル \"%s\" ã‚’é–‹ã‘ã¾ã›ã‚“"
+
+msgid "E456: Can't find PostScript resource file \"prolog.ps\""
+msgstr "E456: PostScriptã®ãƒªã‚½ãƒ¼ã‚¹ãƒ•ã‚¡ã‚¤ãƒ« \"prolog.ps\" ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“"
+
+msgid "E456: Can't find PostScript resource file \"cidfont.ps\""
+msgstr "E456: PostScriptã®ãƒªã‚½ãƒ¼ã‚¹ãƒ•ã‚¡ã‚¤ãƒ« \"cidfont.ps\" ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“"
+
+#, c-format
+msgid "E456: Can't find PostScript resource file \"%s.ps\""
+msgstr "E456: PostScriptã®ãƒªã‚½ãƒ¼ã‚¹ãƒ•ã‚¡ã‚¤ãƒ« \"%s.ps\" ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“"
+
+#, c-format
+msgid "E620: Unable to convert to print encoding \"%s\""
+msgstr "E620: å°åˆ·ã‚¨ãƒ³ã‚³ãƒ¼ãƒ‰ \"%s\" ã¸å¤‰æ›ã§ãã¾ã›ã‚“"
+
+msgid "Sending to printer..."
+msgstr "プリンタã«é€ä¿¡ä¸­..."
+
+msgid "E365: Failed to print PostScript file"
+msgstr "E365: PostScriptファイルã®å°åˆ·ã«å¤±æ•—ã—ã¾ã—ãŸ"
+
+msgid "Print job sent."
+msgstr "å°åˆ·ã‚¸ãƒ§ãƒ–ã‚’é€ä¿¡ã—ã¾ã—ãŸ."
+
+msgid "Add a new database"
+msgstr "新データベースを追加"
+
+msgid "Query for a pattern"
+msgstr "パターンã®ã‚¯ã‚¨ãƒªãƒ¼ã‚’追加"
+
+msgid "Show this message"
+msgstr "ã“ã®ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã‚’表示ã™ã‚‹"
+
+msgid "Kill a connection"
+msgstr "接続を終了ã™ã‚‹"
+
+msgid "Reinit all connections"
+msgstr "å…¨ã¦ã®æŽ¥ç¶šã‚’å†åˆæœŸåŒ–ã™ã‚‹"
+
+msgid "Show connections"
+msgstr "接続を表示ã™ã‚‹"
+
+#, c-format
+msgid "E560: Usage: cs[cope] %s"
+msgstr "E560: 使用方法: cs[cope] %s"
+
+msgid "This cscope command does not support splitting the window.\n"
+msgstr "ã“ã®cscopeコマンドã¯åˆ†å‰²ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã§ã¯ã‚µãƒãƒ¼ãƒˆã•ã‚Œã¾ã›ã‚“.\n"
+
+msgid "E562: Usage: cstag <ident>"
+msgstr "E562: 使用法: cstag <ident>"
+
+msgid "E257: cstag: tag not found"
+msgstr "E257: cstag: ã‚¿ã‚°ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“"
+
+#, c-format
+msgid "E563: stat(%s) error: %d"
+msgstr "E563: stat(%s) エラー: %d"
+
+msgid "E563: stat error"
+msgstr "E563: stat エラー"
+
+#, c-format
+msgid "E564: %s is not a directory or a valid cscope database"
+msgstr "E564: %s ã¯ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªåŠã³æœ‰åŠ¹ãªcscopeã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã§ã¯ã‚ã‚Šã¾ã›ã‚“"
+
+#, c-format
+msgid "Added cscope database %s"
+msgstr "cscopeデータベース %s を追加"
+
+#, c-format
+msgid "E262: error reading cscope connection %ld"
+msgstr "E262: cscopeã®æŽ¥ç¶š %ld を読込ã¿ä¸­ã®ã‚¨ãƒ©ãƒ¼ã§ã™"
+
+msgid "E561: unknown cscope search type"
+msgstr "E561: 未知ã®cscope検索型ã§ã™"
+
+msgid "E566: Could not create cscope pipes"
+msgstr "E566: cscopeパイプを作æˆã§ãã¾ã›ã‚“ã§ã—ãŸ"
+
+msgid "E622: Could not fork for cscope"
+msgstr "E622: cscopeã®èµ·å‹•æº–å‚™(fork)ã«å¤±æ•—ã—ã¾ã—ãŸ"
+
+msgid "cs_create_connection setpgid failed"
+msgstr "cs_create_connection ã¸ã® setpgid ã«å¤±æ•—ã—ã¾ã—ãŸ"
+
+msgid "cs_create_connection exec failed"
+msgstr "cs_create_connection ã®å®Ÿè¡Œã«å¤±æ•—ã—ã¾ã—ãŸ"
+
+msgid "cs_create_connection: fdopen for to_fp failed"
+msgstr "cs_create_connection: to_fp ã® fdopen ã«å¤±æ•—ã—ã¾ã—ãŸ"
+
+msgid "cs_create_connection: fdopen for fr_fp failed"
+msgstr "cs_create_connection: fr_fp ã® fdopen ã«å¤±æ•—ã—ã¾ã—ãŸ"
+
+msgid "E623: Could not spawn cscope process"
+msgstr "E623: cscopeプロセスを起動ã§ãã¾ã›ã‚“ã§ã—ãŸ"
+
+msgid "E567: no cscope connections"
+msgstr "E567: cscope接続ã«å¤±æ•—ã—ã¾ã—ãŸ"
+
+#, c-format
+msgid "E469: invalid cscopequickfix flag %c for %c"
+msgstr "E469: 無効㪠cscopequickfix フラグ %c ã® %c ã§ã™"
+
+#, c-format
+msgid "E259: no matches found for cscope query %s of %s"
+msgstr "E259: cscopeクエリー %s of %s ã«è©²å½“ãŒã‚ã‚Šã¾ã›ã‚“ã§ã—ãŸ"
+
+msgid "cscope commands:\n"
+msgstr "cscopeコマンド:\n"
+
+#, c-format
+msgid "%-5s: %s%*s (Usage: %s)"
+msgstr "%-5s: %s%*s (使用法: %s)"
+
+msgid ""
+"\n"
+" a: Find assignments to this symbol\n"
+" c: Find functions calling this function\n"
+" d: Find functions called by this function\n"
+" e: Find this egrep pattern\n"
+" f: Find this file\n"
+" g: Find this definition\n"
+" i: Find files #including this file\n"
+" s: Find this C symbol\n"
+" t: Find this text string\n"
+msgstr ""
+"\n"
+" a: ã“ã®ã‚·ãƒ³ãƒœãƒ«ã«å¯¾ã™ã‚‹ä»£å…¥ã‚’探ã™\n"
+" c: ã“ã®é–¢æ•°ã‚’呼んã§ã„る関数を探ã™\n"
+" d: ã“ã®é–¢æ•°ã‹ã‚‰å‘¼ã‚“ã§ã„る関数を探ã™\n"
+" e: ã“ã®egrepパターンを探ã™\n"
+" f: ã“ã®ãƒ•ã‚¡ã‚¤ãƒ«ã‚’探ã™\n"
+" g: ã“ã®å®šç¾©ã‚’探ã™\n"
+" i: ã“ã®ãƒ•ã‚¡ã‚¤ãƒ«ã‚’#includeã—ã¦ã„るファイルを探ã™\n"
+" s: ã“ã®Cシンボルを探ã™\n"
+" t: ã“ã®ãƒ†ã‚­ã‚¹ãƒˆæ–‡å­—列を探ã™\n"
+
+#, c-format
+msgid "E625: cannot open cscope database: %s"
+msgstr "E625: cscopeデータベース: %s ã‚’é–‹ãã“ã¨ãŒã§ãã¾ã›ã‚“"
+
+msgid "E626: cannot get cscope database information"
+msgstr "E626: cscopeデータベースã®æƒ…報をå–å¾—ã§ãã¾ã›ã‚“"
+
+msgid "E568: duplicate cscope database not added"
+msgstr "E568: é‡è¤‡ã™ã‚‹cscopeデータベースã¯è¿½åŠ ã•ã‚Œã¾ã›ã‚“ã§ã—ãŸ"
+
+#, c-format
+msgid "E261: cscope connection %s not found"
+msgstr "E261: cscope接続 %s ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸ"
+
+#, c-format
+msgid "cscope connection %s closed"
+msgstr "cscope接続 %s ãŒé–‰ã˜ã‚‰ã‚Œã¾ã—ãŸ"
+
+msgid "E570: fatal error in cs_manage_matches"
+msgstr "E570: cs_manage_matches ã§è‡´å‘½çš„ãªã‚¨ãƒ©ãƒ¼ã§ã™"
+
+#, c-format
+msgid "Cscope tag: %s"
+msgstr "Cscope ã‚¿ã‚°: %s"
+
+msgid ""
+"\n"
+" # line"
+msgstr ""
+"\n"
+" # 行番å·"
+
+msgid "filename / context / line\n"
+msgstr "ファイルå / 文脈 / è¡Œ\n"
+
+#, c-format
+msgid "E609: Cscope error: %s"
+msgstr "E609: cscopeエラー: %s"
+
+msgid "All cscope databases reset"
+msgstr "å…¨ã¦ã®cscopeデータベースをリセットã—ã¾ã™"
+
+msgid "no cscope connections\n"
+msgstr "cscope接続ãŒã‚ã‚Šã¾ã›ã‚“\n"
+
+msgid " # pid database name prepend path\n"
+msgstr " # pid データベースå prepend パス\n"
+
+msgid "Lua library cannot be loaded."
+msgstr "Luaライブラリをロードã§ãã¾ã›ã‚“."
+
+msgid "cannot save undo information"
+msgstr "アンドゥ情報ãŒä¿å­˜ã§ãã¾ã›ã‚“"
+
+msgid ""
+"E815: Sorry, this command is disabled, the MzScheme libraries could not be "
+"loaded."
+msgstr "E815: ã“ã®ã‚³ãƒžãƒ³ãƒ‰ã¯ç„¡åŠ¹ã§ã™. MzScheme ライブラリをロードã§ãã¾ã›ã‚“."
+
+msgid ""
+"E895: Sorry, this command is disabled, the MzScheme's racket/base module "
+"could not be loaded."
+msgstr ""
+"E895: ã“ã®ã‚³ãƒžãƒ³ãƒ‰ã¯ç„¡åŠ¹ã§ã™ã€ã”ã‚ã‚“ãªã•ã„. MzScheme ã® racket/base モジュー"
+"ルãŒãƒ­ãƒ¼ãƒ‰ã§ãã¾ã›ã‚“ã§ã—ãŸ."
+
+msgid "invalid expression"
+msgstr "無効ãªå¼ã§ã™"
+
+msgid "expressions disabled at compile time"
+msgstr "å¼ã¯ã‚³ãƒ³ãƒ‘イル時ã«ç„¡åŠ¹ã«ã•ã‚Œã¦ã„ã¾ã™"
+
+msgid "hidden option"
+msgstr "éš ã—オプション"
+
+msgid "unknown option"
+msgstr "未知ã®ã‚ªãƒ—ションã§ã™"
+
+msgid "window index is out of range"
+msgstr "範囲外ã®ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ç•ªå·ã§ã™"
+
+msgid "couldn't open buffer"
+msgstr "ãƒãƒƒãƒ•ã‚¡ã‚’é–‹ã‘ã¾ã›ã‚“"
+
+msgid "cannot delete line"
+msgstr "行を消ã›ã¾ã›ã‚“"
+
+msgid "cannot replace line"
+msgstr "行を置æ›ã§ãã¾ã›ã‚“"
+
+msgid "cannot insert line"
+msgstr "行を挿入ã§ãã¾ã›ã‚“"
+
+msgid "string cannot contain newlines"
+msgstr "文字列ã«ã¯æ”¹è¡Œæ–‡å­—ã‚’å«ã‚られã¾ã›ã‚“"
+
+msgid "error converting Scheme values to Vim"
+msgstr "Scheme値ã®Vimã¸ã®å¤‰æ›ã‚¨ãƒ©ãƒ¼"
+
+msgid "Vim error: ~a"
+msgstr "Vim エラー: ~a"
+
+msgid "Vim error"
+msgstr "Vim エラー"
+
+msgid "buffer is invalid"
+msgstr "ãƒãƒƒãƒ•ã‚¡ã¯ç„¡åŠ¹ã§ã™"
+
+msgid "window is invalid"
+msgstr "ウィンドウã¯ç„¡åŠ¹ã§ã™"
+
+msgid "linenr out of range"
+msgstr "範囲外ã®è¡Œç•ªå·ã§ã™"
+
+msgid "not allowed in the Vim sandbox"
+msgstr "サンドボックスã§ã¯è¨±ã•ã‚Œã¾ã›ã‚“"
+
+msgid "E836: This Vim cannot execute :python after using :py3"
+msgstr "E836: ã“ã®Vimã§ã¯ :py3 を使ã£ãŸå¾Œã« :python を使ãˆã¾ã›ã‚“"
+
+msgid ""
+"E263: Sorry, this command is disabled, the Python library could not be "
+"loaded."
+msgstr ""
+"E263: ã“ã®ã‚³ãƒžãƒ³ãƒ‰ã¯ç„¡åŠ¹ã§ã™ã€ã”ã‚ã‚“ãªã•ã„: Pythonライブラリをロードã§ãã¾ã›"
+"ã‚“ã§ã—ãŸ."
+
+msgid ""
+"E887: Sorry, this command is disabled, the Python's site module could not be "
+"loaded."
+msgstr ""
+"E887: ã“ã®ã‚³ãƒžãƒ³ãƒ‰ã¯ç„¡åŠ¹ã§ã™ã€ã”ã‚ã‚“ãªã•ã„. Python ã® site モジュールをロード"
+"ã§ãã¾ã›ã‚“ã§ã—ãŸ."
+
+# Added at 07-Feb-2004.
+msgid "E659: Cannot invoke Python recursively"
+msgstr "E659: Python ã‚’å†å¸°çš„ã«å®Ÿè¡Œã™ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“"
+
+msgid "E837: This Vim cannot execute :py3 after using :python"
+msgstr "E837: ã“ã®Vimã§ã¯ :python を使ã£ãŸå¾Œã« :py3 を使ãˆã¾ã›ã‚“"
+
+msgid "E265: $_ must be an instance of String"
+msgstr "E265: $_ ã¯æ–‡å­—列ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ã§ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“"
+
+msgid ""
+"E266: Sorry, this command is disabled, the Ruby library could not be loaded."
+msgstr ""
+"E266: ã“ã®ã‚³ãƒžãƒ³ãƒ‰ã¯ç„¡åŠ¹ã§ã™ã€ã”ã‚ã‚“ãªã•ã„: Rubyライブラリをロードã§ãã¾ã›ã‚“"
+"ã§ã—ãŸ."
+
+msgid "E267: unexpected return"
+msgstr "E267: 予期ã›ã¬ return ã§ã™"
+
+msgid "E268: unexpected next"
+msgstr "E268: 予期ã›ã¬ next ã§ã™"
+
+msgid "E269: unexpected break"
+msgstr "E269: 予期ã›ã¬ break ã§ã™"
+
+msgid "E270: unexpected redo"
+msgstr "E270: 予期ã›ã¬ redo ã§ã™"
+
+msgid "E271: retry outside of rescue clause"
+msgstr "E271: rescue ã®å¤–ã® retry ã§ã™"
+
+msgid "E272: unhandled exception"
+msgstr "E272: å–り扱ã‚ã‚Œãªã‹ã£ãŸä¾‹å¤–ãŒã‚ã‚Šã¾ã™"
+
+#, c-format
+msgid "E273: unknown longjmp status %d"
+msgstr "E273: 未知ã®longjmp状態: %d"
+
+msgid "invalid buffer number"
+msgstr "無効ãªãƒãƒƒãƒ•ã‚¡ç•ªå·ã§ã™"
+
+msgid "not implemented yet"
+msgstr "ã¾ã å®Ÿè£…ã•ã‚Œã¦ã„ã¾ã›ã‚“"
+
+msgid "cannot set line(s)"
+msgstr "行を設定ã§ãã¾ã›ã‚“"
+
+msgid "invalid mark name"
+msgstr "無効ãªãƒžãƒ¼ã‚¯åã§ã™"
+
+msgid "mark not set"
+msgstr "マークã¯è¨­å®šã•ã‚Œã¦ã„ã¾ã›ã‚“"
+
+#, c-format
+msgid "row %d column %d"
+msgstr "行 %d 列 %d"
+
+msgid "cannot insert/append line"
+msgstr "è¡Œã®æŒ¿å…¥/追加をã§ãã¾ã›ã‚“"
+
+msgid "line number out of range"
+msgstr "範囲外ã®è¡Œç•ªå·ã§ã™"
+
+msgid "unknown flag: "
+msgstr "未知ã®ãƒ•ãƒ©ã‚°: "
+
+msgid "unknown vimOption"
+msgstr "未知㮠vimOption ã§ã™"
+
+msgid "keyboard interrupt"
+msgstr "キーボード割込ã¿"
+
+msgid "vim error"
+msgstr "vim エラー"
+
+msgid "cannot create buffer/window command: object is being deleted"
+msgstr ""
+"ãƒãƒƒãƒ•ã‚¡/ウィンドウ作æˆã‚³ãƒžãƒ³ãƒ‰ã‚’作æˆã§ãã¾ã›ã‚“: オブジェクトãŒæ¶ˆåŽ»ã•ã‚Œã¦ã„ã¾"
+"ã—ãŸ"
+
+msgid ""
+"cannot register callback command: buffer/window is already being deleted"
+msgstr ""
+"コールãƒãƒƒã‚¯ã‚³ãƒžãƒ³ãƒ‰ã‚’登録ã§ãã¾ã›ã‚“: ãƒãƒƒãƒ•ã‚¡/ウィンドウãŒæ—¢ã«æ¶ˆåŽ»ã•ã‚Œã¾ã—ãŸ"
+
+msgid ""
+"E280: TCL FATAL ERROR: reflist corrupt!? Please report this to vim-dev@vim."
+"org"
+msgstr ""
+"E280: TCL 致命的エラー: reflist 汚染!? vim-dev@vim.org ã«å ±å‘Šã—ã¦ãã ã•ã„"
+
+msgid "cannot register callback command: buffer/window reference not found"
+msgstr ""
+"コールãƒãƒƒã‚¯ã‚³ãƒžãƒ³ãƒ‰ã‚’登録ã§ãã¾ã›ã‚“: ãƒãƒƒãƒ•ã‚¡/ウィンドウã®å‚ç…§ãŒè¦‹ã¤ã‹ã‚Šã¾ã›"
+"ã‚“"
+
+msgid ""
+"E571: Sorry, this command is disabled: the Tcl library could not be loaded."
+msgstr ""
+"E571: ã“ã®ã‚³ãƒžãƒ³ãƒ‰ã¯ç„¡åŠ¹ã§ã™ã€ã”ã‚ã‚“ãªã•ã„: Tclライブラリをロードã§ãã¾ã›ã‚“ã§"
+"ã—ãŸ."
+
+#, c-format
+msgid "E572: exit code %d"
+msgstr "E572: 終了コード %d"
+
+msgid "cannot get line"
+msgstr "行をå–å¾—ã§ãã¾ã›ã‚“"
+
+msgid "Unable to register a command server name"
+msgstr "命令サーãƒãƒ¼ã®åå‰ã‚’登録ã§ãã¾ã›ã‚“"
+
+msgid "E248: Failed to send command to the destination program"
+msgstr "E248: 目的ã®ãƒ—ログラムã¸ã®ã‚³ãƒžãƒ³ãƒ‰é€ä¿¡ã«å¤±æ•—ã—ã¾ã—ãŸ"
+
+#, c-format
+msgid "E573: Invalid server id used: %s"
+msgstr "E573: 無効ãªã‚µãƒ¼ãƒãƒ¼IDãŒä½¿ã‚ã‚Œã¾ã—ãŸ: %s"
+
+msgid "E251: VIM instance registry property is badly formed. Deleted!"
+msgstr "E251: VIM 実体ã®ç™»éŒ²ãƒ—ロパティãŒä¸æ­£ã§ã™. 消去ã—ã¾ã—ãŸ!"
+
+#, c-format
+msgid "E938: Duplicate key in JSON: \"%s\""
+msgstr "E938: JSONã«é‡è¤‡ã‚­ãƒ¼ãŒã‚ã‚Šã¾ã™: \"%s\""
+
+#, c-format
+msgid "E696: Missing comma in List: %s"
+msgstr "E696: リスト型ã«ã‚«ãƒ³ãƒžãŒã‚ã‚Šã¾ã›ã‚“: %s"
+
+#, c-format
+msgid "E697: Missing end of List ']': %s"
+msgstr "E697: リスト型ã®æœ€å¾Œã« ']' ãŒã‚ã‚Šã¾ã›ã‚“: %s"
+
+msgid "Unknown option argument"
+msgstr "未知ã®ã‚ªãƒ—ション引数ã§ã™"
+
+msgid "Too many edit arguments"
+msgstr "編集引数ãŒå¤šéŽãŽã¾ã™"
+
+msgid "Argument missing after"
+msgstr "引数ãŒã‚ã‚Šã¾ã›ã‚“"
+
+msgid "Garbage after option argument"
+msgstr "オプション引数ã®å¾Œã«ã‚´ãƒŸãŒã‚ã‚Šã¾ã™"
+
+msgid "Too many \"+command\", \"-c command\" or \"--cmd command\" arguments"
+msgstr "\"+command\", \"-c command\", \"--cmd command\" ã®å¼•æ•°ãŒå¤šéŽãŽã¾ã™"
+
+msgid "Invalid argument for"
+msgstr "無効ãªå¼•æ•°ã§ã™: "
+
+#, c-format
+msgid "%d files to edit\n"
+msgstr "%d 個ã®ãƒ•ã‚¡ã‚¤ãƒ«ãŒç·¨é›†ã‚’控ãˆã¦ã„ã¾ã™\n"
+
+msgid "netbeans is not supported with this GUI\n"
+msgstr "netbeans ã¯ã“ã®GUIã§ã¯åˆ©ç”¨ã§ãã¾ã›ã‚“\n"
+
+msgid "'-nb' cannot be used: not enabled at compile time\n"
+msgstr "'-nb' 使用ä¸å¯èƒ½ã§ã™: コンパイル時ã«ç„¡åŠ¹ã«ã•ã‚Œã¦ã„ã¾ã™\n"
+
+msgid "This Vim was not compiled with the diff feature."
+msgstr "ã“ã®Vimã«ã¯diff機能ãŒã‚ã‚Šã¾ã›ã‚“(コンパイル時設定)."
+
+msgid "Attempt to open script file again: \""
+msgstr "スクリプトファイルをå†ã³é–‹ã“ã†ã¨ã—ã¾ã—ãŸ: \""
+
+msgid "Cannot open for reading: \""
+msgstr "読込用ã¨ã—ã¦é–‹ã‘ã¾ã›ã‚“"
+
+msgid "Cannot open for script output: \""
+msgstr "スクリプト出力用を開ã‘ã¾ã›ã‚“"
+
+msgid "Vim: Error: Failure to start gvim from NetBeans\n"
+msgstr "Vim: エラー: NetBeansã‹ã‚‰gvimをスタートã§ãã¾ã›ã‚“\n"
+
+msgid "Vim: Error: This version of Vim does not run in a Cygwin terminal\n"
+msgstr "Vim: エラー: ã“ã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã®Vimã¯Cygwin端末ã§ã¯å‹•ä½œã—ã¾ã›ã‚“\n"
+
+msgid "Vim: Warning: Output is not to a terminal\n"
+msgstr "Vim: 警告: 端末ã¸ã®å‡ºåŠ›ã§ã¯ã‚ã‚Šã¾ã›ã‚“\n"
+
+msgid "Vim: Warning: Input is not from a terminal\n"
+msgstr "Vim: 警告: 端末ã‹ã‚‰ã®å…¥åŠ›ã§ã¯ã‚ã‚Šã¾ã›ã‚“\n"
+
+msgid "pre-vimrc command line"
+msgstr "vimrcå‰ã®ã‚³ãƒžãƒ³ãƒ‰ãƒ©ã‚¤ãƒ³"
+
+#, c-format
+msgid "E282: Cannot read from \"%s\""
+msgstr "E282: \"%s\"ã‹ã‚‰èª­è¾¼ã‚€ã“ã¨ãŒã§ãã¾ã›ã‚“"
+
+msgid ""
+"\n"
+"More info with: \"vim -h\"\n"
+msgstr ""
+"\n"
+"より詳細ãªæƒ…å ±ã¯: \"vim -h\"\n"
+
+msgid "[file ..] edit specified file(s)"
+msgstr "[ファイル..] ã‚るファイルを編集ã™ã‚‹"
+
+msgid "- read text from stdin"
+msgstr "- 標準入力ã‹ã‚‰ãƒ†ã‚­ã‚¹ãƒˆã‚’読込む"
+
+msgid "-t tag edit file where tag is defined"
+msgstr "-t ã‚¿ã‚° ã‚¿ã‚°ãŒå®šç¾©ã•ã‚ŒãŸã¨ã“ã‚ã‹ã‚‰ç·¨é›†ã™ã‚‹"
+
+msgid "-q [errorfile] edit file with first error"
+msgstr "-q [errorfile] 最åˆã®ã‚¨ãƒ©ãƒ¼ã§ç·¨é›†ã™ã‚‹"
+
+msgid ""
+"\n"
+"\n"
+"Usage:"
+msgstr ""
+"\n"
+"\n"
+"使用法:"
+
+msgid " vim [arguments] "
+msgstr " vim [引数] "
+
+msgid ""
+"\n"
+" or:"
+msgstr ""
+"\n"
+" ã‚‚ã—ãã¯:"
+
+msgid ""
+"\n"
+"Where case is ignored prepend / to make flag upper case"
+msgstr ""
+"\n"
+"大å°æ–‡å­—ãŒç„¡è¦–ã•ã‚Œã‚‹å ´åˆã¯å¤§æ–‡å­—ã«ã™ã‚‹ãŸã‚ã« / ã‚’å‰ç½®ã—ã¦ãã ã•ã„"
+
+msgid ""
+"\n"
+"\n"
+"Arguments:\n"
+msgstr ""
+"\n"
+"\n"
+"引数:\n"
+
+msgid "--\t\t\tOnly file names after this"
+msgstr "--\t\t\tã“ã®ã‚ã¨ã«ã¯ãƒ•ã‚¡ã‚¤ãƒ«åã ã‘"
+
+msgid "--literal\t\tDon't expand wildcards"
+msgstr "--literal\t\tワイルドカードを展開ã—ãªã„"
+
+msgid "-register\t\tRegister this gvim for OLE"
+msgstr "-register\t\tã“ã®gvimã‚’OLEã¨ã—ã¦ç™»éŒ²ã™ã‚‹"
+
+msgid "-unregister\t\tUnregister gvim for OLE"
+msgstr "-unregister\t\tgvimã®OLE登録を解除ã™ã‚‹"
+
+msgid "-g\t\t\tRun using GUI (like \"gvim\")"
+msgstr "-g\t\t\tGUIã§èµ·å‹•ã™ã‚‹ (\"gvim\" ã¨åŒã˜)"
+
+msgid "-f or --nofork\tForeground: Don't fork when starting GUI"
+msgstr "-f or --nofork\tフォアグラウンド: GUIを始ã‚ã‚‹ã¨ãã«forkã—ãªã„"
+
+msgid "-v\t\t\tVi mode (like \"vi\")"
+msgstr "-v\t\t\tViモード (\"vi\" ã¨åŒã˜)"
+
+msgid "-e\t\t\tEx mode (like \"ex\")"
+msgstr "-e\t\t\tExモード (\"ex\" ã¨åŒã˜)"
+
+msgid "-E\t\t\tImproved Ex mode"
+msgstr "-E\t\t\t改良Exモード"
+
+msgid "-s\t\t\tSilent (batch) mode (only for \"ex\")"
+msgstr "-s\t\t\tサイレント(ãƒãƒƒãƒ)モード (\"ex\" 専用)"
+
+msgid "-d\t\t\tDiff mode (like \"vimdiff\")"
+msgstr "-d\t\t\t差分モード (\"vidiff\" ã¨åŒã˜)"
+
+msgid "-y\t\t\tEasy mode (like \"evim\", modeless)"
+msgstr "-y\t\t\tイージーモード (\"evim\" ã¨åŒã˜ã€ãƒ¢ãƒ¼ãƒ‰ç„¡)"
+
+msgid "-R\t\t\tReadonly mode (like \"view\")"
+msgstr "-R\t\t\t読込専用モード (\"view\" ã¨åŒã˜)"
+
+msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
+msgstr "-Z\t\t\t制é™ãƒ¢ãƒ¼ãƒ‰ (\"rvim\" ã¨åŒã˜)"
+
+msgid "-m\t\t\tModifications (writing files) not allowed"
+msgstr "-m\t\t\t変更 (ファイルä¿å­˜æ™‚) ã‚’ã§ããªã„よã†ã«ã™ã‚‹"
+
+msgid "-M\t\t\tModifications in text not allowed"
+msgstr "-M\t\t\tテキストã®ç·¨é›†ã‚’è¡Œãªãˆãªã„よã†ã«ã™ã‚‹"
+
+msgid "-b\t\t\tBinary mode"
+msgstr "-b\t\t\tãƒã‚¤ãƒŠãƒªãƒ¢ãƒ¼ãƒ‰"
+
+msgid "-l\t\t\tLisp mode"
+msgstr "-l\t\t\tLispモード"
+
+msgid "-C\t\t\tCompatible with Vi: 'compatible'"
+msgstr "-C\t\t\tVi互æ›ãƒ¢ãƒ¼ãƒ‰: 'compatible'"
+
+msgid "-N\t\t\tNot fully Vi compatible: 'nocompatible'"
+msgstr "-N\t\t\tViéžäº’æ›ãƒ¢ãƒ¼ãƒ‰: 'nocompatible"
+
+msgid "-V[N][fname]\t\tBe verbose [level N] [log messages to fname]"
+msgstr "-V[N][fname]\t\tログ出力設定 [レベル N] [ログファイルå fname]"
+
+msgid "-D\t\t\tDebugging mode"
+msgstr "-D\t\t\tデãƒãƒƒã‚°ãƒ¢ãƒ¼ãƒ‰"
+
+msgid "-n\t\t\tNo swap file, use memory only"
+msgstr "-n\t\t\tスワップファイルを使用ã›ãšãƒ¡ãƒ¢ãƒªã ã‘"
+
+msgid "-r\t\t\tList swap files and exit"
+msgstr "-r\t\t\tスワップファイルを列挙ã—終了"
+
+msgid "-r (with file name)\tRecover crashed session"
+msgstr "-r (ファイルå)\tクラッシュã—ãŸã‚»ãƒƒã‚·ãƒ§ãƒ³ã‚’復帰"
+
+msgid "-L\t\t\tSame as -r"
+msgstr "-L\t\t\t-rã¨åŒã˜"
+
+msgid "-f\t\t\tDon't use newcli to open window"
+msgstr "-f\t\t\tウィンドウを開ãã®ã« newcli を使用ã—ãªã„"
+
+msgid "-dev <device>\t\tUse <device> for I/O"
+msgstr "-dev <device>\t\tI/Oã« <device> を使用ã™ã‚‹"
+
+msgid "-A\t\t\tStart in Arabic mode"
+msgstr "-A\t\t\tアラビア語モードã§èµ·å‹•ã™ã‚‹"
+
+msgid "-H\t\t\tStart in Hebrew mode"
+msgstr "-H\t\t\tヘブライ語モードã§èµ·å‹•ã™ã‚‹"
+
+msgid "-F\t\t\tStart in Farsi mode"
+msgstr "-F\t\t\tペルシア語モードã§èµ·å‹•ã™ã‚‹"
+
+msgid "-T <terminal>\tSet terminal type to <terminal>"
+msgstr "-T <terminal>\t端末を <terminal> ã«è¨­å®šã™ã‚‹"
+
+msgid "--not-a-term\t\tSkip warning for input/output not being a terminal"
+msgstr "--not-a-term\t\t入出力ãŒç«¯æœ«ã§ãªã„ã¨ã®è­¦å‘Šã‚’スキップã™ã‚‹"
+
+msgid "--ttyfail\t\tExit if input or output is not a terminal"
+msgstr "--ttyfail\t\t入出力ãŒç«¯æœ«ã§ãªã‘ã‚Œã°çµ‚了ã™ã‚‹"
+
+msgid "-u <vimrc>\t\tUse <vimrc> instead of any .vimrc"
+msgstr "-u <vimrc>\t\t.vimrcã®ä»£ã‚ã‚Šã« <vimrc> を使ã†"
+
+msgid "-U <gvimrc>\t\tUse <gvimrc> instead of any .gvimrc"
+msgstr "-U <gvimrc>\t\t.gvimrcã®ä»£ã‚ã‚Šã« <gvimrc> を使ã†"
+
+msgid "--noplugin\t\tDon't load plugin scripts"
+msgstr "--noplugin\t\tプラグインスクリプトをロードã—ãªã„"
+
+msgid "-p[N]\t\tOpen N tab pages (default: one for each file)"
+msgstr "-p[N]\t\tN 個タブページを開ã(çœç•¥å€¤: ファイルã«ã¤ã1個)"
+
+msgid "-o[N]\t\tOpen N windows (default: one for each file)"
+msgstr "-o[N]\t\tN 個ウィンドウを開ã(çœç•¥å€¤: ファイルã«ã¤ã1個)"
+
+msgid "-O[N]\t\tLike -o but split vertically"
+msgstr "-O[N]\t\t-oã¨åŒã˜ã ãŒåž‚直分割"
+
+msgid "+\t\t\tStart at end of file"
+msgstr "+\t\t\tファイルã®æœ€å¾Œã‹ã‚‰ã¯ã˜ã‚ã‚‹"
+
+msgid "+<lnum>\t\tStart at line <lnum>"
+msgstr "+<lnum>\t\t<lnum> è¡Œã‹ã‚‰ã¯ã˜ã‚ã‚‹"
+
+msgid "--cmd <command>\tExecute <command> before loading any vimrc file"
+msgstr "--cmd <command>\tvimrcをロードã™ã‚‹å‰ã« <command> を実行ã™ã‚‹"
+
+msgid "-c <command>\t\tExecute <command> after loading the first file"
+msgstr "-c <command>\t\t最åˆã®ãƒ•ã‚¡ã‚¤ãƒ«ã‚’ロード後 <command> を実行ã™ã‚‹"
+
+msgid "-S <session>\t\tSource file <session> after loading the first file"
+msgstr "-S <session>\t\t最åˆã®ãƒ•ã‚¡ã‚¤ãƒ«ã‚’ロード後ファイル <session> ã‚’å–込む"
+
+msgid "-s <scriptin>\tRead Normal mode commands from file <scriptin>"
+msgstr "-s <scriptin>\tファイル <scriptin> ã‹ã‚‰ãƒŽãƒ¼ãƒžãƒ«ã‚³ãƒžãƒ³ãƒ‰ã‚’読込む"
+
+msgid "-w <scriptout>\tAppend all typed commands to file <scriptout>"
+msgstr "-w <scriptout>\t入力ã—ãŸå…¨ã‚³ãƒžãƒ³ãƒ‰ã‚’ファイル <scriptout> ã«è¿½åŠ ã™ã‚‹"
+
+msgid "-W <scriptout>\tWrite all typed commands to file <scriptout>"
+msgstr "-W <scriptout>\t入力ã—ãŸå…¨ã‚³ãƒžãƒ³ãƒ‰ã‚’ファイル <scriptout> ã«ä¿å­˜ã™ã‚‹"
+
+msgid "-x\t\t\tEdit encrypted files"
+msgstr "-x\t\t\tæš—å·åŒ–ã•ã‚ŒãŸãƒ•ã‚¡ã‚¤ãƒ«ã‚’編集ã™ã‚‹"
+
+msgid "-display <display>\tConnect vim to this particular X-server"
+msgstr "-display <display>\tvimを指定ã—㟠X サーãƒãƒ¼ã«æŽ¥ç¶šã™ã‚‹"
+
+msgid "-X\t\t\tDo not connect to X server"
+msgstr "-X\t\t\tXサーãƒãƒ¼ã«æŽ¥ç¶šã—ãªã„"
+
+msgid "--remote <files>\tEdit <files> in a Vim server if possible"
+msgstr "--remote <files>\tå¯èƒ½ãªã‚‰ã°Vimサーãƒãƒ¼ã§ <files> を編集ã™ã‚‹"
+
+msgid "--remote-silent <files> Same, don't complain if there is no server"
+msgstr "--remote-silent <files> åŒä¸Šã€ã‚µãƒ¼ãƒãƒ¼ãŒç„¡ãã¦ã‚‚警告文を出力ã—ãªã„"
+
+msgid ""
+"--remote-wait <files> As --remote but wait for files to have been edited"
+msgstr "--remote-wait <files> --remote後 ファイルã®ç·¨é›†ãŒçµ‚ã‚ã‚‹ã®ã‚’å¾…ã¤"
+
+msgid ""
+"--remote-wait-silent <files> Same, don't complain if there is no server"
+msgstr ""
+"--remote-wait-silent <files> åŒä¸Šã€ã‚µãƒ¼ãƒãƒ¼ãŒç„¡ãã¦ã‚‚警告文を出力ã—ãªã„"
+
+msgid ""
+"--remote-tab[-wait][-silent] <files> As --remote but use tab page per file"
+msgstr ""
+"--remote-tab[-wait][-silent] <files> --remoteã§ãƒ•ã‚¡ã‚¤ãƒ«1ã¤ã«ã¤ã1ã¤ã®ã‚¿ãƒ–"
+"ページを開ã"
+
+msgid "--remote-send <keys>\tSend <keys> to a Vim server and exit"
+msgstr "--remote-send <keys>\tVimサーãƒãƒ¼ã« <keys> ã‚’é€ä¿¡ã—ã¦çµ‚了ã™ã‚‹"
+
+msgid "--remote-expr <expr>\tEvaluate <expr> in a Vim server and print result"
+msgstr "--remote-expr <expr>\tサーãƒãƒ¼ã§ <expr> を実行ã—ã¦çµæžœã‚’表示ã™ã‚‹"
+
+msgid "--serverlist\t\tList available Vim server names and exit"
+msgstr "--serverlist\t\tVimサーãƒãƒ¼åã®ä¸€è¦§ã‚’表示ã—ã¦çµ‚了ã™ã‚‹"
+
+msgid "--servername <name>\tSend to/become the Vim server <name>"
+msgstr "--servername <name>\tVimサーãƒãƒ¼ <name> ã«é€ä¿¡/åå‰è¨­å®šã™ã‚‹"
+
+msgid "--startuptime <file>\tWrite startup timing messages to <file>"
+msgstr "--startuptime <file>\tèµ·å‹•ã«ã‹ã‹ã£ãŸæ™‚é–“ã®è©³ç´°ã‚’ <file> ã¸å‡ºåŠ›ã™ã‚‹"
+
+msgid "-i <viminfo>\t\tUse <viminfo> instead of .viminfo"
+msgstr "-i <viminfo>\t\t.viminfoã®ä»£ã‚ã‚Šã« <viminfo> を使ã†"
+
+msgid "--clean\t\t'nocompatible', Vim defaults, no plugins, no viminfo"
+msgstr "--clean\t\t'nocompatible'ã€Vimã®æ—¢å®šã€ãƒ—ラグインãªã—ã€viminfoãªã—"
+
+msgid "-h or --help\tPrint Help (this message) and exit"
+msgstr "-h or --help\tヘルプ(ã“ã®ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸)を表示ã—終了ã™ã‚‹"
+
+msgid "--version\t\tPrint version information and exit"
+msgstr "--version\t\tãƒãƒ¼ã‚¸ãƒ§ãƒ³æƒ…報を表示ã—終了ã™ã‚‹"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Motif version):\n"
+msgstr ""
+"\n"
+"gvimã«ã‚ˆã£ã¦è§£é‡ˆã•ã‚Œã‚‹å¼•æ•°(Motifãƒãƒ¼ã‚¸ãƒ§ãƒ³):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (neXtaw version):\n"
+msgstr ""
+"\n"
+"gvimã«ã‚ˆã£ã¦è§£é‡ˆã•ã‚Œã‚‹å¼•æ•°(neXtawãƒãƒ¼ã‚¸ãƒ§ãƒ³):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Athena version):\n"
+msgstr ""
+"\n"
+"gvimã«ã‚ˆã£ã¦è§£é‡ˆã•ã‚Œã‚‹å¼•æ•°(Athenaãƒãƒ¼ã‚¸ãƒ§ãƒ³):\n"
+
+msgid "-display <display>\tRun vim on <display>"
+msgstr "-display <display>\t<display> ã§vimを実行ã™ã‚‹"
+
+msgid "-iconic\t\tStart vim iconified"
+msgstr "-iconic\t\t最å°åŒ–ã—ãŸçŠ¶æ…‹ã§vimã‚’èµ·å‹•ã™ã‚‹"
+
+msgid "-background <color>\tUse <color> for the background (also: -bg)"
+msgstr "-background <color>\t背景色㫠<color> を使ã†(åŒç¾©: -bg)"
+
+msgid "-foreground <color>\tUse <color> for normal text (also: -fg)"
+msgstr "-foreground <color>\tå‰æ™¯è‰²ã« <color> を使ã†(åŒç¾©: -fg)"
+
+msgid "-font <font>\t\tUse <font> for normal text (also: -fn)"
+msgstr "-font <font>\t\tテキスト表示㫠<font> を使ã†(åŒç¾©: -fn)"
+
+msgid "-boldfont <font>\tUse <font> for bold text"
+msgstr "-boldfont <font>\t太字㫠<font> を使ã†"
+
+msgid "-italicfont <font>\tUse <font> for italic text"
+msgstr "-italicfont <for>\t斜体字㫠<font> を使ã†"
+
+msgid "-geometry <geom>\tUse <geom> for initial geometry (also: -geom)"
+msgstr "-geometry <geom>\tåˆæœŸé…置㫠<geom> を使ã†(åŒç¾©: -geom)"
+
+msgid "-borderwidth <width>\tUse a border width of <width> (also: -bw)"
+msgstr "-borderwidth <width>\t境界ã®å¹…ã‚’ <width> ã«ã™ã‚‹(åŒç¾©: -bw)"
+
+msgid "-scrollbarwidth <width> Use a scrollbar width of <width> (also: -sw)"
+msgstr ""
+"-scrollbarwidth <width> スクロールãƒãƒ¼ã®å¹…ã‚’ <width> ã«ã™ã‚‹(åŒç¾©: -sw)"
+
+msgid "-menuheight <height>\tUse a menu bar height of <height> (also: -mh)"
+msgstr "-menuheight <height>\tメニューãƒãƒ¼ã®é«˜ã•ã‚’ <height> ã«ã™ã‚‹(åŒç¾©: -mh)"
+
+msgid "-reverse\t\tUse reverse video (also: -rv)"
+msgstr "-reverse\t\tå転映åƒã‚’使用ã™ã‚‹(åŒç¾©: -rv)"
+
+msgid "+reverse\t\tDon't use reverse video (also: +rv)"
+msgstr "+reverse\t\tå転映åƒã‚’使用ã—ãªã„(åŒç¾©: +rv)"
+
+msgid "-xrm <resource>\tSet the specified resource"
+msgstr "-xrm <resource>\t特定ã®ãƒªã‚½ãƒ¼ã‚¹ã‚’使用ã™ã‚‹"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (GTK+ version):\n"
+msgstr ""
+"\n"
+"gvimã«ã‚ˆã£ã¦è§£é‡ˆã•ã‚Œã‚‹å¼•æ•°(GTK+ãƒãƒ¼ã‚¸ãƒ§ãƒ³):\n"
+
+msgid "-display <display>\tRun vim on <display> (also: --display)"
+msgstr "-display <display>\t<display> ã§vimを実行ã™ã‚‹(åŒç¾©: --display)"
+
+msgid "--role <role>\tSet a unique role to identify the main window"
+msgstr "--role <role>\tメインウィンドウを識別ã™ã‚‹ä¸€æ„ãªå½¹å‰²(role)を設定ã™ã‚‹"
+
+msgid "--socketid <xid>\tOpen Vim inside another GTK widget"
+msgstr "--socketid <xid>\tç•°ãªã‚‹GTK widgetã®å†…部ã«Vimã‚’é–‹ã"
+
+msgid "--echo-wid\t\tMake gvim echo the Window ID on stdout"
+msgstr "--echo-wid\t\tウィンドウIDを標準出力ã«å‡ºåŠ›ã™ã‚‹"
+
+msgid "-P <parent title>\tOpen Vim inside parent application"
+msgstr "-P <親ã®ã‚¿ã‚¤ãƒˆãƒ«>\tVimを親アプリケーションã®ä¸­ã§èµ·å‹•ã™ã‚‹"
+
+msgid "--windowid <HWND>\tOpen Vim inside another win32 widget"
+msgstr "--windowid <HWND>\tç•°ãªã‚‹Win32 widgetã®å†…部ã«Vimã‚’é–‹ã"
+
+msgid "No display"
+msgstr "ディスプレイãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“"
+
+msgid ": Send failed.\n"
+msgstr ": é€ä¿¡ã«å¤±æ•—ã—ã¾ã—ãŸ.\n"
+
+msgid ": Send failed. Trying to execute locally\n"
+msgstr ": é€ä¿¡ã«å¤±æ•—ã—ã¾ã—ãŸ. ローカルã§ã®å®Ÿè¡Œã‚’試ã¿ã¦ã„ã¾ã™\n"
+
+#, c-format
+msgid "%d of %d edited"
+msgstr "%d 個 (%d 個中) ã®ãƒ•ã‚¡ã‚¤ãƒ«ã‚’編集ã—ã¾ã—ãŸ"
+
+msgid "No display: Send expression failed.\n"
+msgstr "ディスプレイãŒã‚ã‚Šã¾ã›ã‚“: å¼ã®é€ä¿¡ã«å¤±æ•—ã—ã¾ã—ãŸ.\n"
+
+msgid ": Send expression failed.\n"
+msgstr ": å¼ã®é€ä¿¡ã«å¤±æ•—ã—ã¾ã—ãŸ.\n"
+
+msgid "No marks set"
+msgstr "マークãŒè¨­å®šã•ã‚Œã¦ã„ã¾ã›ã‚“"
+
+#, c-format
+msgid "E283: No marks matching \"%s\""
+msgstr "E283: \"%s\" ã«è©²å½“ã™ã‚‹ãƒžãƒ¼ã‚¯ãŒã‚ã‚Šã¾ã›ã‚“"
+
+msgid ""
+"\n"
+"mark line col file/text"
+msgstr ""
+"\n"
+"mark 行 列 ファイル/テキスト"
+
+msgid ""
+"\n"
+" jump line col file/text"
+msgstr ""
+"\n"
+" jump 行 列 ファイル/テキスト"
+
+msgid ""
+"\n"
+"change line col text"
+msgstr ""
+"\n"
+"変更 行 列 テキスト"
+
+msgid ""
+"\n"
+"# File marks:\n"
+msgstr ""
+"\n"
+"# ファイルマーク:\n"
+
+msgid ""
+"\n"
+"# Jumplist (newest first):\n"
+msgstr ""
+"\n"
+"# ジャンプリスト (æ–°ã—ã„ã‚‚ã®ãŒå…ˆ):\n"
+
+msgid ""
+"\n"
+"# History of marks within files (newest to oldest):\n"
+msgstr ""
+"\n"
+"# ファイル内マークã®å±¥æ­´ (æ–°ã—ã„ã‚‚ã®ã‹ã‚‰å¤ã„ã‚‚ã®):\n"
+
+msgid "Missing '>'"
+msgstr "'>' ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“"
+
+msgid "E543: Not a valid codepage"
+msgstr "E543: 無効ãªã‚³ãƒ¼ãƒ‰ãƒšãƒ¼ã‚¸ã§ã™"
+
+msgid "E284: Cannot set IC values"
+msgstr "E284: ICã®å€¤ã‚’設定ã§ãã¾ã›ã‚“"
+
+msgid "E285: Failed to create input context"
+msgstr "E285: インプットコンテキストã®ä½œæˆã«å¤±æ•—ã—ã¾ã—ãŸ"
+
+msgid "E286: Failed to open input method"
+msgstr "E286: インプットメソッドã®ã‚ªãƒ¼ãƒ—ンã«å¤±æ•—ã—ã¾ã—ãŸ"
+
+msgid "E287: Warning: Could not set destroy callback to IM"
+msgstr "E287: 警告: IMã®ç ´å£Šã‚³ãƒ¼ãƒ«ãƒãƒƒã‚¯ã‚’設定ã§ãã¾ã›ã‚“ã§ã—ãŸ"
+
+msgid "E288: input method doesn't support any style"
+msgstr "E288: インプットメソッドã¯ã©ã‚“ãªã‚¹ã‚¿ã‚¤ãƒ«ã‚‚サãƒãƒ¼ãƒˆã—ã¾ã›ã‚“"
+
+msgid "E289: input method doesn't support my preedit type"
+msgstr "E289: インプットメソッド㯠my preedit type をサãƒãƒ¼ãƒˆã—ã¾ã›ã‚“"
+
+msgid "E293: block was not locked"
+msgstr "E293: ブロックãŒãƒ­ãƒƒã‚¯ã•ã‚Œã¦ã„ã¾ã›ã‚“"
+
+msgid "E294: Seek error in swap file read"
+msgstr "E294: スワップファイル読込時ã«ã‚·ãƒ¼ã‚¯ã‚¨ãƒ©ãƒ¼ã§ã™"
+
+msgid "E295: Read error in swap file"
+msgstr "E295: スワップファイルã®èª­è¾¼ã¿ã‚¨ãƒ©ãƒ¼ã§ã™"
+
+msgid "E296: Seek error in swap file write"
+msgstr "E296: スワップファイル書込ã¿æ™‚ã«ã‚·ãƒ¼ã‚¯ã‚¨ãƒ©ãƒ¼ã§ã™"
+
+msgid "E297: Write error in swap file"
+msgstr "E297: スワップファイルã®æ›¸è¾¼ã¿ã‚¨ãƒ©ãƒ¼ã§ã™"
+
+msgid "E300: Swap file already exists (symlink attack?)"
+msgstr "E300: スワップファイルãŒæ—¢ã«å­˜åœ¨ã—ã¾ã™ (symlinkã«ã‚ˆã‚‹æ”»æ’ƒ?)"
+
+msgid "E298: Didn't get block nr 0?"
+msgstr "E298: ブロック 0 ã‚’å–å¾—ã§ãã¾ã›ã‚“?"
+
+msgid "E298: Didn't get block nr 1?"
+msgstr "E298: ブロック 1 ã‚’å–å¾—ã§ãã¾ã›ã‚“?"
+
+msgid "E298: Didn't get block nr 2?"
+msgstr "E298: ブロック 2 ã‚’å–å¾—ã§ãã¾ã›ã‚“?"
+
+msgid "E843: Error while updating swap file crypt"
+msgstr "E843: スワップファイルã®æš—å·ã‚’更新中ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸ"
+
+msgid "E301: Oops, lost the swap file!!!"
+msgstr "E301: ãŠã£ã¨ã€ã‚¹ãƒ¯ãƒƒãƒ—ファイルãŒå¤±ã‚ã‚Œã¾ã—ãŸ!!!"
+
+msgid "E302: Could not rename swap file"
+msgstr "E302: スワップファイルã®åå‰ã‚’変ãˆã‚‰ã‚Œã¾ã›ã‚“"
+
+#, c-format
+msgid "E303: Unable to open swap file for \"%s\", recovery impossible"
+msgstr "E303: \"%s\" ã®ã‚¹ãƒ¯ãƒƒãƒ—ファイルを開ã‘ãªã„ã®ã§ãƒªã‚«ãƒãƒªã¯ä¸å¯èƒ½ã§ã™"
+
+msgid "E304: ml_upd_block0(): Didn't get block 0??"
+msgstr "E304: ml_upd_block0(): ブロック 0 ã‚’å–å¾—ã§ãã¾ã›ã‚“ã§ã—ãŸ??"
+
+#, c-format
+msgid "E305: No swap file found for %s"
+msgstr "E305: %s ã«ã¯ã‚¹ãƒ¯ãƒƒãƒ—ファイルãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“"
+
+msgid "Enter number of swap file to use (0 to quit): "
+msgstr "使用ã™ã‚‹ã‚¹ãƒ¯ãƒƒãƒ—ファイルã®ç•ªå·ã‚’入力ã—ã¦ãã ã•ã„(0 ã§çµ‚了): "
+
+#, c-format
+msgid "E306: Cannot open %s"
+msgstr "E306: %s ã‚’é–‹ã‘ã¾ã›ã‚“"
+
+msgid "Unable to read block 0 from "
+msgstr "ブロック 0 を読込ã‚ã¾ã›ã‚“ "
+
+msgid ""
+"\n"
+"Maybe no changes were made or Vim did not update the swap file."
+msgstr ""
+"\n"
+"æらã変更ãŒã•ã‚Œã¦ã„ãªã„ã‹VimãŒã‚¹ãƒ¯ãƒƒãƒ—ファイルを更新ã—ã¦ã„ã¾ã›ã‚“."
+
+msgid " cannot be used with this version of Vim.\n"
+msgstr " Vimã®ã“ã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã§ã¯ä½¿ç”¨ã§ãã¾ã›ã‚“.\n"
+
+msgid "Use Vim version 3.0.\n"
+msgstr "Vimã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³3.0を使用ã—ã¦ãã ã•ã„.\n"
+
+#, c-format
+msgid "E307: %s does not look like a Vim swap file"
+msgstr "E307: %s ã¯Vimã®ã‚¹ãƒ¯ãƒƒãƒ—ファイルã§ã¯ãªã„よã†ã§ã™"
+
+msgid " cannot be used on this computer.\n"
+msgstr " ã“ã®ã‚³ãƒ³ãƒ”ュータã§ã¯ä½¿ç”¨ã§ãã¾ã›ã‚“.\n"
+
+msgid "The file was created on "
+msgstr "ã“ã®ãƒ•ã‚¡ã‚¤ãƒ«ã¯æ¬¡ã®å ´æ‰€ã§ä½œã‚‰ã‚Œã¾ã—㟠"
+
+msgid ""
+",\n"
+"or the file has been damaged."
+msgstr ""
+",\n"
+"ã‚‚ã—ãã¯ãƒ•ã‚¡ã‚¤ãƒ«ãŒæå‚·ã—ã¦ã„ã¾ã™."
+
+#, c-format
+msgid ""
+"E833: %s is encrypted and this version of Vim does not support encryption"
+msgstr ""
+"E833: %s ã¯ã“ã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã®Vimã§ã‚µãƒãƒ¼ãƒˆã—ã¦ã„ãªã„å½¢å¼ã§æš—å·åŒ–ã•ã‚Œã¦ã„ã¾ã™"
+
+msgid " has been damaged (page size is smaller than minimum value).\n"
+msgstr " ã¯æå‚·ã—ã¦ã„ã¾ã™ (ページサイズãŒæœ€å°å€¤ã‚’下回ã£ã¦ã„ã¾ã™).\n"
+
+#, c-format
+msgid "Using swap file \"%s\""
+msgstr "スワップファイル \"%s\" を使用中"
+
+#, c-format
+msgid "Original file \"%s\""
+msgstr "原本ファイル \"%s\""
+
+msgid "E308: Warning: Original file may have been changed"
+msgstr "E308: 警告: 原本ファイルãŒå¤‰æ›´ã•ã‚Œã¦ã„ã¾ã™"
+
+#, c-format
+msgid "Swap file is encrypted: \"%s\""
+msgstr "スワップファイルã¯æš—å·åŒ–ã•ã‚Œã¦ã„ã¾ã™: \"%s\""
+
+msgid ""
+"\n"
+"If you entered a new crypt key but did not write the text file,"
+msgstr ""
+"\n"
+"æ–°ã—ã„æš—å·ã‚­ãƒ¼ã‚’入力ã—ãŸã‚ã¨ã«ãƒ†ã‚­ã‚¹ãƒˆãƒ•ã‚¡ã‚¤ãƒ«ã‚’ä¿å­˜ã—ã¦ã„ãªã„å ´åˆã¯ã€"
+
+msgid ""
+"\n"
+"enter the new crypt key."
+msgstr ""
+"\n"
+"æ–°ã—ã„æš—å·ã‚­ãƒ¼ã‚’入力ã—ã¦ãã ã•ã„."
+
+msgid ""
+"\n"
+"If you wrote the text file after changing the crypt key press enter"
+msgstr ""
+"\n"
+"æš—å·ã‚­ãƒ¼ã‚’変ãˆãŸã‚ã¨ã«ãƒ†ã‚­ã‚¹ãƒˆãƒ•ã‚¡ã‚¤ãƒ«ã‚’ä¿å­˜ã—ãŸå ´åˆã¯ã€ãƒ†ã‚­ã‚¹ãƒˆãƒ•ã‚¡ã‚¤ãƒ«ã¨"
+
+msgid ""
+"\n"
+"to use the same key for text file and swap file"
+msgstr ""
+"\n"
+"スワップファイルã«åŒã˜æš—å·ã‚­ãƒ¼ã‚’使ã†ãŸã‚ã«enterã ã‘を押ã—ã¦ãã ã•ã„."
+
+#, c-format
+msgid "E309: Unable to read block 1 from %s"
+msgstr "E309: %s ã‹ã‚‰ãƒ–ロック 1 を読込ã‚ã¾ã›ã‚“"
+
+msgid "???MANY LINES MISSING"
+msgstr "???多ãã®è¡ŒãŒå¤±ã‚ã‚Œã¦ã„ã¾ã™"
+
+msgid "???LINE COUNT WRONG"
+msgstr "???行数ãŒé–“é•ã£ã¦ã„ã¾ã™"
+
+msgid "???EMPTY BLOCK"
+msgstr "???ブロックãŒç©ºã§ã™"
+
+msgid "???LINES MISSING"
+msgstr "???è¡ŒãŒå¤±ã‚ã‚Œã¦ã„ã¾ã™"
+
+#, c-format
+msgid "E310: Block 1 ID wrong (%s not a .swp file?)"
+msgstr "E310: ブロック 1 ã®IDãŒé–“é•ã£ã¦ã„ã¾ã™(%s ãŒ.swpファイルã§ãªã„?)"
+
+msgid "???BLOCK MISSING"
+msgstr "???ブロックãŒã‚ã‚Šã¾ã›ã‚“"
+
+msgid "??? from here until ???END lines may be messed up"
+msgstr "??? ã“ã“ã‹ã‚‰ ???END ã¾ã§ã®è¡ŒãŒç ´å£Šã•ã‚Œã¦ã„るよã†ã§ã™"
+
+msgid "??? from here until ???END lines may have been inserted/deleted"
+msgstr "??? ã“ã“ã‹ã‚‰ ???END ã¾ã§ã®è¡ŒãŒæŒ¿å…¥ã‹å‰Šé™¤ã•ã‚ŒãŸã‚ˆã†ã§ã™"
+
+msgid "???END"
+msgstr "???END"
+
+msgid "E311: Recovery Interrupted"
+msgstr "E311: リカãƒãƒªãŒå‰²è¾¼ã¾ã‚Œã¾ã—ãŸ"
+
+msgid ""
+"E312: Errors detected while recovering; look for lines starting with ???"
+msgstr ""
+"E312: リカãƒãƒªã®æœ€ä¸­ã«ã‚¨ãƒ©ãƒ¼ãŒæ¤œå‡ºã•ã‚Œã¾ã—ãŸ; ???ã§å§‹ã¾ã‚‹è¡Œã‚’å‚ç…§ã—ã¦ãã ã•ã„"
+
+msgid "See \":help E312\" for more information."
+msgstr "詳細㯠\":help E312\" ã‚’å‚ç…§ã—ã¦ãã ã•ã„"
+
+msgid "Recovery completed. You should check if everything is OK."
+msgstr "リカãƒãƒªãŒçµ‚了ã—ã¾ã—ãŸ. å…¨ã¦ãŒæ­£ã—ã„ã‹ãƒã‚§ãƒƒã‚¯ã—ã¦ãã ã•ã„."
+
+msgid ""
+"\n"
+"(You might want to write out this file under another name\n"
+msgstr ""
+"\n"
+"(変更をãƒã‚§ãƒƒã‚¯ã™ã‚‹ãŸã‚ã«ã€ã“ã®ãƒ•ã‚¡ã‚¤ãƒ«ã‚’別ã®åå‰ã§ä¿å­˜ã—ãŸä¸Šã§\n"
+
+msgid "and run diff with the original file to check for changes)"
+msgstr "原本ファイルã¨ã® diff を実行ã™ã‚‹ã¨è‰¯ã„ã§ã—ょã†)"
+
+msgid "Recovery completed. Buffer contents equals file contents."
+msgstr "復元完了. ãƒãƒƒãƒ•ã‚¡ã®å†…容ã¯ãƒ•ã‚¡ã‚¤ãƒ«ã¨åŒã˜ã«ãªã‚Šã¾ã—ãŸ."
+
+msgid ""
+"\n"
+"You may want to delete the .swp file now.\n"
+"\n"
+msgstr ""
+"\n"
+"å…ƒã®.swpファイルã¯å‰Šé™¤ã—ã¦ã‚‚構ã„ã¾ã›ã‚“\n"
+"\n"
+
+msgid "Using crypt key from swap file for the text file.\n"
+msgstr "スワップファイルã‹ã‚‰å–å¾—ã—ãŸæš—å·ã‚­ãƒ¼ã‚’テキストファイルã«ä½¿ã„ã¾ã™.\n"
+
+msgid "Swap files found:"
+msgstr "スワップファイルãŒè¤‡æ•°è¦‹ã¤ã‹ã‚Šã¾ã—ãŸ:"
+
+msgid " In current directory:\n"
+msgstr " ç¾åœ¨ã®ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒª:\n"
+
+msgid " Using specified name:\n"
+msgstr " 以下ã®åå‰ã‚’使用中:\n"
+
+msgid " In directory "
+msgstr " ディレクトリ "
+
+msgid " -- none --\n"
+msgstr " -- ãªã— --\n"
+
+msgid " owned by: "
+msgstr " 所有者: "
+
+msgid " dated: "
+msgstr " 日付: "
+
+msgid " dated: "
+msgstr " 日付: "
+
+msgid " [from Vim version 3.0]"
+msgstr " [from Vim version 3.0]"
+
+msgid " [does not look like a Vim swap file]"
+msgstr " [Vimã®ã‚¹ãƒ¯ãƒƒãƒ—ファイルã§ã¯ãªã„よã†ã§ã™]"
+
+msgid " file name: "
+msgstr " ファイルå: "
+
+msgid ""
+"\n"
+" modified: "
+msgstr ""
+"\n"
+" 変更状態: "
+
+msgid "YES"
+msgstr "ã‚ã‚Š"
+
+msgid "no"
+msgstr "ãªã—"
+
+msgid ""
+"\n"
+" user name: "
+msgstr ""
+"\n"
+" ユーザーå: "
+
+msgid " host name: "
+msgstr " ホストå: "
+
+msgid ""
+"\n"
+" host name: "
+msgstr ""
+"\n"
+" ホストå: "
+
+msgid ""
+"\n"
+" process ID: "
+msgstr ""
+"\n"
+" プロセスID: "
+
+msgid " (STILL RUNNING)"
+msgstr " (ã¾ã å®Ÿè¡Œä¸­)"
+
+msgid ""
+"\n"
+" [not usable with this version of Vim]"
+msgstr ""
+"\n"
+" [ã“ã®Vimãƒãƒ¼ã‚¸ãƒ§ãƒ³ã§ã¯ä½¿ç”¨ã§ãã¾ã›ã‚“]"
+
+msgid ""
+"\n"
+" [not usable on this computer]"
+msgstr ""
+"\n"
+" [ã“ã®ã‚³ãƒ³ãƒ”ュータã§ã¯ä½¿ç”¨ã§ãã¾ã›ã‚“]"
+
+msgid " [cannot be read]"
+msgstr " [読込ã‚ã¾ã›ã‚“]"
+
+msgid " [cannot be opened]"
+msgstr " [é–‹ã‘ã¾ã›ã‚“]"
+
+msgid "E313: Cannot preserve, there is no swap file"
+msgstr "E313: スワップファイルãŒç„¡ã„ã®ã§ç¶­æŒã§ãã¾ã›ã‚“"
+
+msgid "File preserved"
+msgstr "ファイルãŒç¶­æŒã•ã‚Œã¾ã™"
+
+msgid "E314: Preserve failed"
+msgstr "E314: 維æŒã«å¤±æ•—ã—ã¾ã—ãŸ"
+
+#, c-format
+msgid "E315: ml_get: invalid lnum: %ld"
+msgstr "E315: ml_get: 無効ãªlnumã§ã™: %ld"
+
+#, c-format
+msgid "E316: ml_get: cannot find line %ld"
+msgstr "E316: ml_get: è¡Œ %ld を見ã¤ã‘られã¾ã›ã‚“"
+
+msgid "E317: pointer block id wrong 3"
+msgstr "E317: ãƒã‚¤ãƒ³ã‚¿ãƒ–ロックã®IDãŒé–“é•ã£ã¦ã„ã¾ã™ 3"
+
+msgid "stack_idx should be 0"
+msgstr "stack_idx 㯠0 ã§ã‚ã‚‹ã¹ãã§ã™"
+
+msgid "E318: Updated too many blocks?"
+msgstr "E318: æ›´æ–°ã•ã‚ŒãŸãƒ–ロックãŒå¤šéŽãŽã‚‹ã‹ã‚‚?"
+
+msgid "E317: pointer block id wrong 4"
+msgstr "E317: ãƒã‚¤ãƒ³ã‚¿ãƒ–ロックã®IDãŒé–“é•ã£ã¦ã„ã¾ã™ 4"
+
+msgid "deleted block 1?"
+msgstr "ブロック 1 ã¯æ¶ˆã•ã‚ŒãŸ?"
+
+#, c-format
+msgid "E320: Cannot find line %ld"
+msgstr "E320: è¡Œ %ld ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“"
+
+msgid "E317: pointer block id wrong"
+msgstr "E317: ãƒã‚¤ãƒ³ã‚¿ãƒ–ロックã®IDãŒé–“é•ã£ã¦ã„ã¾ã™"
+
+msgid "pe_line_count is zero"
+msgstr "pe_line_count ãŒã‚¼ãƒ­ã§ã™"
+
+#, c-format
+msgid "E322: line number out of range: %ld past the end"
+msgstr "E322: 行番å·ãŒç¯„囲外ã§ã™: %ld 超ãˆã¦ã„ã¾ã™"
+
+#, c-format
+msgid "E323: line count wrong in block %ld"
+msgstr "E323: ブロック %ld ã®è¡Œã‚«ã‚¦ãƒ³ãƒˆãŒé–“é•ã£ã¦ã„ã¾ã™"
+
+msgid "Stack size increases"
+msgstr "スタックサイズãŒå¢—ãˆã¾ã™"
+
+msgid "E317: pointer block id wrong 2"
+msgstr "E317: ãƒã‚¤ãƒ³ã‚¿ãƒ–ロックã®IDãŒé–“é•ã£ã¦ã„ã¾ã™ 2"
+
+#, c-format
+msgid "E773: Symlink loop for \"%s\""
+msgstr "E773: \"%s\" ã®ã‚·ãƒ³ãƒœãƒªãƒƒã‚¯ãƒªãƒ³ã‚¯ãŒãƒ«ãƒ¼ãƒ—ã«ãªã£ã¦ã„ã¾ã™"
+
+msgid "E325: ATTENTION"
+msgstr "E325: 注æ„"
+
+msgid ""
+"\n"
+"Found a swap file by the name \""
+msgstr ""
+"\n"
+"次ã®åå‰ã§ã‚¹ãƒ¯ãƒƒãƒ—ファイルを見ã¤ã‘ã¾ã—㟠\""
+
+msgid "While opening file \""
+msgstr "次ã®ãƒ•ã‚¡ã‚¤ãƒ«ã‚’é–‹ã„ã¦ã„る最中 \""
+
+msgid " CANNOT BE FOUND"
+msgstr " 見ã¤ã‹ã‚Šã¾ã›ã‚“"
+
+msgid " NEWER than swap file!\n"
+msgstr " スワップファイルよりも新ã—ã„ã§ã™!\n"
+
+msgid ""
+"\n"
+"(1) Another program may be editing the same file. If this is the case,\n"
+" be careful not to end up with two different instances of the same\n"
+" file when making changes. Quit, or continue with caution.\n"
+msgstr ""
+"\n"
+"(1) 別ã®ãƒ—ログラムãŒåŒã˜ãƒ•ã‚¡ã‚¤ãƒ«ã‚’編集ã—ã¦ã„ã‚‹ã‹ã‚‚ã—ã‚Œã¾ã›ã‚“.\n"
+" ã“ã®å ´åˆã«ã¯ã€å¤‰æ›´ã‚’ã—ã¦ã—ã¾ã†ã¨1ã¤ã®ãƒ•ã‚¡ã‚¤ãƒ«ã«å¯¾ã—ã¦ç•°ãªã‚‹2ã¤ã®\n"
+" インスタンスãŒã§ãã¦ã—ã¾ã†ã®ã§ã€ãã†ã—ãªã„よã†ã«æ°—ã‚’ã¤ã‘ã¦ãã ã•ã„.\n"
+" 終了ã™ã‚‹ã‹ã€æ³¨æ„ã—ãªãŒã‚‰ç¶šã‘ã¦ãã ã•ã„.\n"
+
+msgid "(2) An edit session for this file crashed.\n"
+msgstr "(2) ã“ã®ãƒ•ã‚¡ã‚¤ãƒ«ã®ç·¨é›†ã‚»ãƒƒã‚·ãƒ§ãƒ³ãŒã‚¯ãƒ©ãƒƒã‚·ãƒ¥ã—ãŸ.\n"
+
+msgid " If this is the case, use \":recover\" or \"vim -r "
+msgstr " ã“ã®å ´åˆã«ã¯ \":recover\" ã‹ \"vim -r "
+
+msgid ""
+"\"\n"
+" to recover the changes (see \":help recovery\").\n"
+msgstr ""
+"\"\n"
+" を使用ã—ã¦å¤‰æ›´ã‚’リカãƒãƒ¼ã—ã¾ã™(\":help recovery\" ã‚’å‚ç…§).\n"
+
+msgid " If you did this already, delete the swap file \""
+msgstr " æ—¢ã«ã“れを行ãªã£ãŸã®ãªã‚‰ã°ã€ã‚¹ãƒ¯ãƒƒãƒ—ファイル \""
+
+msgid ""
+"\"\n"
+" to avoid this message.\n"
+msgstr ""
+"\"\n"
+" を消ã›ã°ã“ã®ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã‚’回é¿ã§ãã¾ã™.\n"
+
+msgid "Swap file \""
+msgstr "スワップファイル \""
+
+msgid "\" already exists!"
+msgstr "\" ãŒæ—¢ã«ã‚ã‚Šã¾ã™!"
+
+msgid "VIM - ATTENTION"
+msgstr "VIM - 注æ„"
+
+msgid "Swap file already exists!"
+msgstr "スワップファイルãŒæ—¢ã«å­˜åœ¨ã—ã¾ã™!"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"読込専用ã§é–‹ã(&O)\n"
+"ã¨ã«ã‹ã編集ã™ã‚‹(&E)\n"
+"復活ã•ã›ã‚‹(&R)\n"
+"終了ã™ã‚‹(&Q)\n"
+"中止ã™ã‚‹(&A)"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Delete it\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"読込専用ã§é–‹ã(&O)\n"
+"ã¨ã«ã‹ã編集ã™ã‚‹(&E)\n"
+"復活ã•ã›ã‚‹(&R)\n"
+"削除ã™ã‚‹(&D)\n"
+"終了ã™ã‚‹(&Q)\n"
+"中止ã™ã‚‹(&A)"
+
+msgid "E326: Too many swap files found"
+msgstr "E326: スワップファイルãŒå¤šæ•°è¦‹ã¤ã‹ã‚Šã¾ã—ãŸ"
+
+msgid "E327: Part of menu-item path is not sub-menu"
+msgstr "E327: メニューアイテムã®ãƒ‘スã®éƒ¨åˆ†ãŒã‚µãƒ–メニューã§ã¯ã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E328: Menu only exists in another mode"
+msgstr "E328: メニューã¯ä»–ã®ãƒ¢ãƒ¼ãƒ‰ã«ã ã‘ã‚ã‚Šã¾ã™"
+
+#, c-format
+msgid "E329: No menu \"%s\""
+msgstr "E329: \"%s\" ã¨ã„ã†ãƒ¡ãƒ‹ãƒ¥ãƒ¼ã¯ã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E792: Empty menu name"
+msgstr "E792: メニューåãŒç©ºã§ã™"
+
+msgid "E330: Menu path must not lead to a sub-menu"
+msgstr "E330: メニューパスã¯ã‚µãƒ–メニューを生ã˜ã‚‹ã¹ãã§ã¯ã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E331: Must not add menu items directly to menu bar"
+msgstr "E331: メニューãƒãƒ¼ã«ã¯ç›´æŽ¥ãƒ¡ãƒ‹ãƒ¥ãƒ¼ã‚¢ã‚¤ãƒ†ãƒ ã‚’追加ã§ãã¾ã›ã‚“"
+
+msgid "E332: Separator cannot be part of a menu path"
+msgstr "E332: 区切りã¯ãƒ¡ãƒ‹ãƒ¥ãƒ¼ãƒ‘スã®ä¸€éƒ¨ã§ã¯ã‚ã‚Šã¾ã›ã‚“"
+
+msgid ""
+"\n"
+"--- Menus ---"
+msgstr ""
+"\n"
+"--- メニュー ---"
+
+msgid "Tear off this menu"
+msgstr "ã“ã®ãƒ¡ãƒ‹ãƒ¥ãƒ¼ã‚’切りå–ã‚‹"
+
+#, c-format
+msgid "E335: Menu not defined for %s mode"
+msgstr "E335: %s ã«ã¯ãƒ¡ãƒ‹ãƒ¥ãƒ¼ãŒå®šç¾©ã•ã‚Œã¦ã„ã¾ã›ã‚“"
+
+msgid "E333: Menu path must lead to a menu item"
+msgstr "E333: メニューパスã¯ãƒ¡ãƒ‹ãƒ¥ãƒ¼ã‚¢ã‚¤ãƒ†ãƒ ã‚’生ã˜ãªã‘ã‚Œã°ã„ã‘ã¾ã›ã‚“"
+
+#, c-format
+msgid "E334: Menu not found: %s"
+msgstr "E334: メニューãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“: %s"
+
+msgid "E336: Menu path must lead to a sub-menu"
+msgstr "E336: メニューパスã¯ã‚µãƒ–メニューを生ã˜ãªã‘ã‚Œã°ã„ã‘ã¾ã›ã‚“"
+
+msgid "E337: Menu not found - check menu names"
+msgstr "E337: メニューãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ - メニューåを確èªã—ã¦ãã ã•ã„"
+
+#, c-format
+msgid "Error detected while processing %s:"
+msgstr "%s ã®å‡¦ç†ä¸­ã«ã‚¨ãƒ©ãƒ¼ãŒæ¤œå‡ºã•ã‚Œã¾ã—ãŸ:"
+
+#, c-format
+msgid "line %4ld:"
+msgstr "行 %4ld:"
+
+#, c-format
+msgid "E354: Invalid register name: '%s'"
+msgstr "E354: 無効ãªãƒ¬ã‚¸ã‚¹ã‚¿å: '%s'"
+
+msgid "Messages maintainer: Bram Moolenaar <Bram@vim.org>"
+msgstr "日本語メッセージ翻訳/監修: æ‘岡 太郎 <koron.kaoriya@gmail.com>"
+
+msgid "Interrupt: "
+msgstr "割込ã¿: "
+
+msgid "Press ENTER or type command to continue"
+msgstr "続ã‘ã‚‹ã«ã¯ENTERを押ã™ã‹ã‚³ãƒžãƒ³ãƒ‰ã‚’入力ã—ã¦ãã ã•ã„"
+
+#, c-format
+msgid "%s line %ld"
+msgstr "%s 行 %ld"
+
+msgid "-- More --"
+msgstr "-- 継続 --"
+
+msgid " SPACE/d/j: screen/page/line down, b/u/k: up, q: quit "
+msgstr " SPACE/d/j: ç”»é¢/ページ/è¡Œ 下, b/u/k: 上, q: 終了 "
+
+msgid "Question"
+msgstr "質å•"
+
+msgid ""
+"&Yes\n"
+"&No"
+msgstr ""
+"ã¯ã„(&Y)\n"
+"ã„ã„ãˆ(&N)"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"Save &All\n"
+"&Discard All\n"
+"&Cancel"
+msgstr ""
+"ã¯ã„(&Y)\n"
+"ã„ã„ãˆ(&N)\n"
+"å…¨ã¦ä¿å­˜(&A)\n"
+"å…¨ã¦æ”¾æ£„(&D)\n"
+"キャンセル(&C)"
+
+msgid "Select Directory dialog"
+msgstr "ディレクトリé¸æŠžãƒ€ã‚¤ã‚¢ãƒ­ã‚°"
+
+msgid "Save File dialog"
+msgstr "ファイルä¿å­˜ãƒ€ã‚¤ã‚¢ãƒ­ã‚°"
+
+msgid "Open File dialog"
+msgstr "ファイル読込ダイアログ"
+
+msgid "E338: Sorry, no file browser in console mode"
+msgstr "E338: コンソールモードã§ã¯ãƒ•ã‚¡ã‚¤ãƒ«ãƒ–ラウザを使ãˆã¾ã›ã‚“ã€ã”ã‚ã‚“ãªã•ã„"
+
+msgid "E766: Insufficient arguments for printf()"
+msgstr "E766: printf() ã®å¼•æ•°ãŒä¸å分ã§ã™"
+
+msgid "E807: Expected Float argument for printf()"
+msgstr "E807: printf() ã®å¼•æ•°ã«ã¯æµ®å‹•å°æ•°ç‚¹æ•°ãŒæœŸå¾…ã•ã‚Œã¦ã„ã¾ã™"
+
+msgid "E767: Too many arguments to printf()"
+msgstr "E767: printf() ã®å¼•æ•°ãŒå¤šéŽãŽã¾ã™"
+
+msgid "W10: Warning: Changing a readonly file"
+msgstr "W10: 警告: 読込専用ファイルを変更ã—ã¾ã™"
+
+msgid "Type number and <Enter> or click with mouse (empty cancels): "
+msgstr ""
+"番å·ã¨<Enter>を入力ã™ã‚‹ã‹ãƒžã‚¦ã‚¹ã§ã‚¯ãƒªãƒƒã‚¯ã—ã¦ãã ã•ã„ (空ã§ã‚­ãƒ£ãƒ³ã‚»ãƒ«): "
+
+msgid "Type number and <Enter> (empty cancels): "
+msgstr "番å·ã¨<Enter>を入力ã—ã¦ãã ã•ã„ (空ã§ã‚­ãƒ£ãƒ³ã‚»ãƒ«): "
+
+#, c-format
+msgid "%ld more line"
+msgid_plural "%ld more lines"
+msgstr[0] "%ld è¡Œ 追加ã—ã¾ã—ãŸ"
+
+#, c-format
+msgid "%ld line less"
+msgid_plural "%ld fewer lines"
+msgstr[0] "%ld è¡Œ 削除ã—ã¾ã—ãŸ"
+
+msgid " (Interrupted)"
+msgstr " (割込ã¾ã‚Œã¾ã—ãŸ)"
+
+msgid "Beep!"
+msgstr "ビーッ!"
+
+msgid "ERROR: "
+msgstr "エラー: "
+
+#, c-format
+msgid ""
+"\n"
+"[bytes] total alloc-freed %lu-%lu, in use %lu, peak use %lu\n"
+msgstr ""
+"\n"
+"[メモリ(ãƒã‚¤ãƒˆ)] ç·å‰²å½“-è§£æ”¾é‡ %lu-%lu, ä½¿ç”¨é‡ %lu, ピーク時 %lu\n"
+
+#, c-format
+msgid ""
+"[calls] total re/malloc()'s %lu, total free()'s %lu\n"
+"\n"
+msgstr ""
+"[呼出] ç· re/malloc() 回数 %lu, ç· free() 回数 %lu\n"
+"\n"
+
+msgid "E340: Line is becoming too long"
+msgstr "E340: è¡ŒãŒé•·ããªã‚ŠéŽãŽã¾ã—ãŸ"
+
+#, c-format
+msgid "E341: Internal error: lalloc(%ld, )"
+msgstr "E341: 内部エラー: lalloc(%ld,)"
+
+#, c-format
+msgid "E342: Out of memory! (allocating %lu bytes)"
+msgstr "E342: メモリãŒè¶³ã‚Šã¾ã›ã‚“! (%lu ãƒã‚¤ãƒˆã‚’割当è¦æ±‚)"
+
+#, c-format
+msgid "Calling shell to execute: \"%s\""
+msgstr "実行ã®ãŸã‚ã«ã‚·ã‚§ãƒ«ã‚’呼出ã—中: \"%s\""
+
+msgid "E545: Missing colon"
+msgstr "E545: コロンãŒã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E546: Illegal mode"
+msgstr "E546: ä¸æ­£ãªãƒ¢ãƒ¼ãƒ‰ã§ã™"
+
+msgid "E547: Illegal mouseshape"
+msgstr "E547: ä¸æ­£ãª 'mouseshape' ã§ã™"
+
+msgid "E548: digit expected"
+msgstr "E548: 数値ãŒå¿…è¦ã§ã™"
+
+msgid "E549: Illegal percentage"
+msgstr "E549: ä¸æ­£ãªãƒ‘ーセンテージã§ã™"
+
+msgid "E854: path too long for completion"
+msgstr "E854: パスãŒé•·éŽãŽã¦è£œå®Œã§ãã¾ã›ã‚“"
+
+#, c-format
+msgid ""
+"E343: Invalid path: '**[number]' must be at the end of the path or be "
+"followed by '%s'."
+msgstr ""
+"E343: 無効ãªãƒ‘スã§ã™: '**[数値]' ã¯pathã®æœ€å¾Œã‹ '%s' ãŒç¶šã„ã¦ãªã„ã¨ã„ã‘ã¾ã›"
+"ã‚“."
+
+#, c-format
+msgid "E344: Can't find directory \"%s\" in cdpath"
+msgstr "E344: cdpathã«ã¯ \"%s\" ã¨ã„ã†ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªãŒã‚ã‚Šã¾ã›ã‚“"
+
+#, c-format
+msgid "E345: Can't find file \"%s\" in path"
+msgstr "E345: pathã«ã¯ \"%s\" ã¨ã„ã†ãƒ•ã‚¡ã‚¤ãƒ«ãŒã‚ã‚Šã¾ã›ã‚“"
+
+#, c-format
+msgid "E346: No more directory \"%s\" found in cdpath"
+msgstr "E346: cdpathã«ã¯ã“れ以上 \"%s\" ã¨ã„ã†ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªãŒã‚ã‚Šã¾ã›ã‚“"
+
+#, c-format
+msgid "E347: No more file \"%s\" found in path"
+msgstr "E347: パスã«ã¯ã“れ以上 \"%s\" ã¨ã„ã†ãƒ•ã‚¡ã‚¤ãƒ«ãŒã‚ã‚Šã¾ã›ã‚“"
+
+#, c-format
+msgid "E668: Wrong access mode for NetBeans connection info file: \"%s\""
+msgstr ""
+"E668: NetBeansã®æŽ¥ç¶šæƒ…報ファイルã®ã‚¢ã‚¯ã‚»ã‚¹ãƒ¢ãƒ¼ãƒ‰ã«å•é¡ŒãŒã‚ã‚Šã¾ã™: \"%s\""
+
+#, c-format
+msgid "E658: NetBeans connection lost for buffer %ld"
+msgstr "E658: ãƒãƒƒãƒ•ã‚¡ %ld ã® NetBeans 接続ãŒå¤±ã‚ã‚Œã¾ã—ãŸ"
+
+msgid "E838: netbeans is not supported with this GUI"
+msgstr "E838: NetBeansã¯ã“ã®GUIã«ã¯å¯¾å¿œã—ã¦ã„ã¾ã›ã‚“"
+
+msgid "E511: netbeans already connected"
+msgstr "E511: NetBeansã¯æ—¢ã«æŽ¥ç¶šã—ã¦ã„ã¾ã™"
+
+#, c-format
+msgid "E505: %s is read-only (add ! to override)"
+msgstr "E505: %s ã¯èª­è¾¼å°‚用ã§ã™ (強制書込ã«ã¯ ! を追加)"
+
+msgid "E349: No identifier under cursor"
+msgstr "E349: カーソルã®ä½ç½®ã«ã¯è­˜åˆ¥å­ãŒã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E774: 'operatorfunc' is empty"
+msgstr "E774: 'operatorfunc' オプションãŒç©ºã§ã™"
+
+msgid "E775: Eval feature not available"
+msgstr "E775: å¼è©•ä¾¡æ©Ÿèƒ½ãŒç„¡åŠ¹ã«ãªã£ã¦ã„ã¾ã™"
+
+msgid "Warning: terminal cannot highlight"
+msgstr "警告: 使用ã—ã¦ã„る端末ã¯ãƒã‚¤ãƒ©ã‚¤ãƒˆã§ãã¾ã›ã‚“"
+
+msgid "E348: No string under cursor"
+msgstr "E348: カーソルã®ä½ç½®ã«ã¯æ–‡å­—列ãŒã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E352: Cannot erase folds with current 'foldmethod'"
+msgstr "E352: ç¾åœ¨ã® 'foldmethod' ã§ã¯æŠ˜ç•³ã¿ã‚’消去ã§ãã¾ã›ã‚“"
+
+msgid "E664: changelist is empty"
+msgstr "E664: 変更リストãŒç©ºã§ã™"
+
+msgid "E662: At start of changelist"
+msgstr "E662: 変更リストã®å…ˆé ­"
+
+msgid "E663: At end of changelist"
+msgstr "E663: 変更リストã®æœ«å°¾"
+
+msgid "Type :qa! and press <Enter> to abandon all changes and exit Vim"
+msgstr ""
+"ã™ã¹ã¦ã®å¤‰æ›´ã‚’破棄ã—ã€Vimを終了ã™ã‚‹ã«ã¯ :qa! ã¨å…¥åŠ›ã— <Enter> を押ã—ã¦ãã "
+"ã•ã„"
+
+#, c-format
+msgid "%ld line %sed %d time"
+msgid_plural "%ld line %sed %d times"
+msgstr[0] "%ld 行㌠%s 㧠%d 回処ç†ã•ã‚Œã¾ã—ãŸ"
+
+#, c-format
+msgid "%ld lines %sed %d time"
+msgid_plural "%ld lines %sed %d times"
+msgstr[0] "%ld 行㌠%s 㧠%d 回処ç†ã•ã‚Œã¾ã—ãŸ"
+
+#, c-format
+msgid "%ld lines to indent... "
+msgstr "%ld è¡ŒãŒã‚¤ãƒ³ãƒ‡ãƒ³ãƒˆã•ã‚Œã¾ã™... "
+
+#, c-format
+msgid "%ld line indented "
+msgid_plural "%ld lines indented "
+msgstr[0] "%ld 行をインデントã—ã¾ã—㟠"
+
+msgid "E748: No previously used register"
+msgstr "E748: ã¾ã ãƒ¬ã‚¸ã‚¹ã‚¿ã‚’使用ã—ã¦ã„ã¾ã›ã‚“"
+
+msgid "cannot yank; delete anyway"
+msgstr "ヤンクã§ãã¾ã›ã‚“; ã¨ã«ã‹ã消去"
+
+#, c-format
+msgid "%ld line changed"
+msgid_plural "%ld lines changed"
+msgstr[0] "%ld è¡ŒãŒå¤‰æ›´ã•ã‚Œã¾ã—ãŸ"
+
+#, c-format
+msgid "freeing %ld lines"
+msgstr "%ld 行を解放中"
+
+#, c-format
+msgid " into \"%c"
+msgstr " \"%c ã«"
+
+#, c-format
+msgid "block of %ld line yanked%s"
+msgid_plural "block of %ld lines yanked%s"
+msgstr[0] "%ld è¡Œã®ãƒ–ロックãŒ%sヤンクã•ã‚Œã¾ã—ãŸ"
+
+#, c-format
+msgid "%ld line yanked%s"
+msgid_plural "%ld lines yanked%s"
+msgstr[0] "%ld è¡ŒãŒ%sヤンクã•ã‚Œã¾ã—ãŸ"
+
+#, c-format
+msgid "E353: Nothing in register %s"
+msgstr "E353: レジスタ %s ã«ã¯ä½•ã‚‚ã‚ã‚Šã¾ã›ã‚“"
+
+msgid ""
+"\n"
+"--- Registers ---"
+msgstr ""
+"\n"
+"--- レジスタ ---"
+
+msgid "Illegal register name"
+msgstr "ä¸æ­£ãªãƒ¬ã‚¸ã‚¹ã‚¿å"
+
+msgid ""
+"\n"
+"# Registers:\n"
+msgstr ""
+"\n"
+"# レジスタ:\n"
+
+#, c-format
+msgid "E574: Unknown register type %d"
+msgstr "E574: 未知ã®ãƒ¬ã‚¸ã‚¹ã‚¿åž‹ %d ã§ã™"
+
+msgid ""
+"E883: search pattern and expression register may not contain two or more "
+"lines"
+msgstr "E883: 検索パターンã¨å¼ãƒ¬ã‚¸ã‚¹ã‚¿ã«ã¯2行以上をå«ã‚られã¾ã›ã‚“"
+
+#, c-format
+msgid "%ld Cols; "
+msgstr "%ld 列; "
+
+#, c-format
+msgid "Selected %s%ld of %ld Lines; %lld of %lld Words; %lld of %lld Bytes"
+msgstr "é¸æŠž %s%ld / %ld è¡Œ; %lld / %lld å˜èªž; %lld / %lld ãƒã‚¤ãƒˆ"
+
+#, c-format
+msgid ""
+"Selected %s%ld of %ld Lines; %lld of %lld Words; %lld of %lld Chars; %lld of "
+"%lld Bytes"
+msgstr ""
+"é¸æŠž %s%ld / %ld è¡Œ; %lld / %lld å˜èªž; %lld / %lld 文字; %lld / %lld ãƒã‚¤ãƒˆ"
+
+#, c-format
+msgid "Col %s of %s; Line %ld of %ld; Word %lld of %lld; Byte %lld of %lld"
+msgstr "列 %s / %s; è¡Œ %ld of %ld; å˜èªž %lld / %lld; ãƒã‚¤ãƒˆ %lld / %lld"
+
+#, c-format
+msgid ""
+"Col %s of %s; Line %ld of %ld; Word %lld of %lld; Char %lld of %lld; Byte "
+"%lld of %lld"
+msgstr ""
+"列 %s / %s; è¡Œ %ld / %ld; å˜èªž %lld / %lld; 文字 %lld / %lld; ãƒã‚¤ãƒˆ %lld of "
+"%lld"
+
+#, c-format
+msgid "(+%lld for BOM)"
+msgstr "(+%lld for BOM)"
+
+msgid "Thanks for flying Vim"
+msgstr "Vim を使ã£ã¦ãã‚Œã¦ã‚ã‚ŠãŒã¨ã†"
+
+msgid "E518: Unknown option"
+msgstr "E518: 未知ã®ã‚ªãƒ—ションã§ã™"
+
+msgid "E519: Option not supported"
+msgstr "E519: オプションã¯ã‚µãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ã¾ã›ã‚“"
+
+msgid "E520: Not allowed in a modeline"
+msgstr "E520: modeline ã§ã¯è¨±å¯ã•ã‚Œã¾ã›ã‚“"
+
+msgid "E846: Key code not set"
+msgstr "E846: キーコードãŒè¨­å®šã•ã‚Œã¦ã„ã¾ã›ã‚“"
+
+msgid "E521: Number required after ="
+msgstr "E521: = ã®å¾Œã«ã¯æ•°å­—ãŒå¿…è¦ã§ã™"
+
+msgid "E522: Not found in termcap"
+msgstr "E522: termcap 内ã«è¦‹ã¤ã‹ã‚Šã¾ã›ã‚“"
+
+#, c-format
+msgid "E539: Illegal character <%s>"
+msgstr "E539: ä¸æ­£ãªæ–‡å­—ã§ã™ <%s>"
+
+#, c-format
+msgid "For option %s"
+msgstr "オプション: %s"
+
+msgid "E529: Cannot set 'term' to empty string"
+msgstr "E529: 'term' ã«ã¯ç©ºæ–‡å­—列を設定ã§ãã¾ã›ã‚“"
+
+msgid "E530: Cannot change term in GUI"
+msgstr "E530: GUIã§ã¯ 'term' を変更ã§ãã¾ã›ã‚“"
+
+msgid "E531: Use \":gui\" to start the GUI"
+msgstr "E531: GUIをスタートã™ã‚‹ã«ã¯ \":gui\" を使用ã—ã¦ãã ã•ã„"
+
+msgid "E589: 'backupext' and 'patchmode' are equal"
+msgstr "E589: 'backupext' 㨠'patchmode' ãŒåŒã˜ã§ã™"
+
+msgid "E834: Conflicts with value of 'listchars'"
+msgstr "E834: 'listchars'ã®å€¤ã«çŸ›ç›¾ãŒã‚ã‚Šã¾ã™"
+
+msgid "E835: Conflicts with value of 'fillchars'"
+msgstr "E835: 'fillchars'ã®å€¤ã«çŸ›ç›¾ãŒã‚ã‚Šã¾ã™"
+
+msgid "E617: Cannot be changed in the GTK+ 2 GUI"
+msgstr "E617: GTK+2 GUIã§ã¯å¤‰æ›´ã§ãã¾ã›ã‚“"
+
+#, c-format
+msgid "E950: Cannot convert between %s and %s"
+msgstr "E950: %s 㨠%s ã®é–“ã§å¤‰æ›ã§ãã¾ã›ã‚“"
+
+msgid "E524: Missing colon"
+msgstr "E524: コロンãŒã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E525: Zero length string"
+msgstr "E525: 文字列ã®é•·ã•ãŒã‚¼ãƒ­ã§ã™"
+
+#, c-format
+msgid "E526: Missing number after <%s>"
+msgstr "E526: <%s> ã®å¾Œã«æ•°å­—ãŒã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E527: Missing comma"
+msgstr "E527: カンマãŒã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E528: Must specify a ' value"
+msgstr "E528: ' ã®å€¤ã‚’指定ã—ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“"
+
+msgid "E595: contains unprintable or wide character"
+msgstr "E595: 表示ã§ããªã„文字ã‹ãƒ¯ã‚¤ãƒ‰æ–‡å­—ã‚’å«ã‚“ã§ã„ã¾ã™"
+
+msgid "E596: Invalid font(s)"
+msgstr "E596: 無効ãªãƒ•ã‚©ãƒ³ãƒˆã§ã™"
+
+msgid "E597: can't select fontset"
+msgstr "E597: フォントセットをé¸æŠžã§ãã¾ã›ã‚“"
+
+msgid "E598: Invalid fontset"
+msgstr "E598: 無効ãªãƒ•ã‚©ãƒ³ãƒˆã‚»ãƒƒãƒˆã§ã™"
+
+msgid "E533: can't select wide font"
+msgstr "E533: ワイドフォントをé¸æŠžã§ãã¾ã›ã‚“"
+
+msgid "E534: Invalid wide font"
+msgstr "E534: 無効ãªãƒ¯ã‚¤ãƒ‰ãƒ•ã‚©ãƒ³ãƒˆã§ã™"
+
+#, c-format
+msgid "E535: Illegal character after <%c>"
+msgstr "E535: <%c> ã®å¾Œã«ä¸æ­£ãªæ–‡å­—ãŒã‚ã‚Šã¾ã™"
+
+msgid "E536: comma required"
+msgstr "E536: カンマãŒå¿…è¦ã§ã™"
+
+#, c-format
+msgid "E537: 'commentstring' must be empty or contain %s"
+msgstr "E537: 'commentstring' ã¯ç©ºã§ã‚ã‚‹ã‹ %s ã‚’å«ã‚€å¿…è¦ãŒã‚ã‚Šã¾ã™"
+
+msgid "E538: No mouse support"
+msgstr "E538: マウスã¯ã‚µãƒãƒ¼ãƒˆã•ã‚Œã¾ã›ã‚“"
+
+msgid "E540: Unclosed expression sequence"
+msgstr "E540: å¼ãŒçµ‚了ã—ã¦ã„ã¾ã›ã‚“"
+
+msgid "E541: too many items"
+msgstr "E541: è¦ç´ ãŒå¤šéŽãŽã¾ã™"
+
+msgid "E542: unbalanced groups"
+msgstr "E542: グループãŒé‡£åˆã„ã¾ã›ã‚“"
+
+msgid "E946: Cannot make a terminal with running job modifiable"
+msgstr "E946: 実行中ã®ã‚¸ãƒ§ãƒ–ãŒã‚る端末ã¯å¤‰æ›´å¯èƒ½ã«ã§ãã¾ã›ã‚“"
+
+msgid "E590: A preview window already exists"
+msgstr "E590: プレビューウィンドウãŒæ—¢ã«å­˜åœ¨ã—ã¾ã™"
+
+msgid "W17: Arabic requires UTF-8, do ':set encoding=utf-8'"
+msgstr ""
+"W17: アラビア文字ã«ã¯UTF-8ãŒå¿…è¦ãªã®ã§ã€':set encoding=utf-8' ã—ã¦ãã ã•ã„"
+
+msgid "E954: 24-bit colors are not supported on this environment"
+msgstr "E954: 24bit色ã¯ã“ã®ç’°å¢ƒã§ã¯ã‚µãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ã¾ã›ã‚“"
+
+#, c-format
+msgid "E593: Need at least %d lines"
+msgstr "E593: 最低 %d ã®è¡Œæ•°ãŒå¿…è¦ã§ã™"
+
+#, c-format
+msgid "E594: Need at least %d columns"
+msgstr "E594: 最低 %d ã®ã‚«ãƒ©ãƒ å¹…ãŒå¿…è¦ã§ã™"
+
+#, c-format
+msgid "E355: Unknown option: %s"
+msgstr "E355: 未知ã®ã‚ªãƒ—ションã§ã™: %s"
+
+#, c-format
+msgid "E521: Number required: &%s = '%s'"
+msgstr "E521: æ•°å­—ãŒå¿…è¦ã§ã™: &%s = '%s'"
+
+msgid ""
+"\n"
+"--- Terminal codes ---"
+msgstr ""
+"\n"
+"--- 端末コード ---"
+
+msgid ""
+"\n"
+"--- Global option values ---"
+msgstr ""
+"\n"
+"--- グローãƒãƒ«ã‚ªãƒ—ション値 ---"
+
+msgid ""
+"\n"
+"--- Local option values ---"
+msgstr ""
+"\n"
+"--- ローカルオプション値 ---"
+
+msgid ""
+"\n"
+"--- Options ---"
+msgstr ""
+"\n"
+"--- オプション ---"
+
+msgid "E356: get_varp ERROR"
+msgstr "E356: get_varp エラー"
+
+#, c-format
+msgid "E357: 'langmap': Matching character missing for %s"
+msgstr "E357: 'langmap': %s ã«å¯¾å¿œã™ã‚‹æ–‡å­—ãŒã‚ã‚Šã¾ã›ã‚“"
+
+#, c-format
+msgid "E358: 'langmap': Extra characters after semicolon: %s"
+msgstr "E358: 'langmap': セミコロンã®å¾Œã«ä½™åˆ†ãªæ–‡å­—ãŒã‚ã‚Šã¾ã™: %s"
+
+msgid "cannot open "
+msgstr "é–‹ã‘ã¾ã›ã‚“ "
+
+msgid "VIM: Can't open window!\n"
+msgstr "VIM: ウィンドウを開ã‘ã¾ã›ã‚“!\n"
+
+msgid "Need Amigados version 2.04 or later\n"
+msgstr "Amigadosã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ 2.04ã‹ãれ以é™ãŒå¿…è¦ã§ã™\n"
+
+#, c-format
+msgid "Need %s version %ld\n"
+msgstr "%s ã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ %ld ãŒå¿…è¦ã§ã™\n"
+
+msgid "Cannot open NIL:\n"
+msgstr "NILã‚’é–‹ã‘ã¾ã›ã‚“:\n"
+
+msgid "Cannot create "
+msgstr "作æˆã§ãã¾ã›ã‚“ "
+
+#, c-format
+msgid "Vim exiting with %d\n"
+msgstr "Vim㯠%d ã§çµ‚了ã—ã¾ã™\n"
+
+msgid "cannot change console mode ?!\n"
+msgstr "コンソールモードを変更ã§ãã¾ã›ã‚“?!\n"
+
+msgid "mch_get_shellsize: not a console??\n"
+msgstr "mch_get_shellsize: コンソールã§ã¯ãªã„??\n"
+
+msgid "E360: Cannot execute shell with -f option"
+msgstr "E360: -f オプションã§ã‚·ã‚§ãƒ«ã‚’実行ã§ãã¾ã›ã‚“"
+
+msgid "Cannot execute "
+msgstr "実行ã§ãã¾ã›ã‚“ "
+
+msgid "shell "
+msgstr "シェル "
+
+msgid " returned\n"
+msgstr " 戻りã¾ã—ãŸ\n"
+
+msgid "ANCHOR_BUF_SIZE too small."
+msgstr "ANCHOR_BUF_SIZE ãŒå°ã•éŽãŽã¾ã™."
+
+msgid "I/O ERROR"
+msgstr "入出力エラー"
+
+msgid "Message"
+msgstr "メッセージ"
+
+msgid "E237: Printer selection failed"
+msgstr "E237: プリンタã®é¸æŠžã«å¤±æ•—ã—ã¾ã—ãŸ"
+
+#, c-format
+msgid "to %s on %s"
+msgstr "%s 㸠(%s 上ã®)"
+
+#, c-format
+msgid "E613: Unknown printer font: %s"
+msgstr "E613: 未知ã®ãƒ—リンタオプションã§ã™: %s"
+
+#, c-format
+msgid "E238: Print error: %s"
+msgstr "E238: å°åˆ·ã‚¨ãƒ©ãƒ¼: %s"
+
+#, c-format
+msgid "Printing '%s'"
+msgstr "å°åˆ·ã—ã¦ã„ã¾ã™: '%s'"
+
+#, c-format
+msgid "E244: Illegal charset name \"%s\" in font name \"%s\""
+msgstr "E244: 文字セットå \"%s\" ã¯ä¸æ­£ã§ã™ (フォントå \"%s\")"
+
+#, c-format
+msgid "E244: Illegal quality name \"%s\" in font name \"%s\""
+msgstr "E244: å“質å \"%s\" ã¯ä¸æ­£ã§ã™ (フォントå \"%s\")"
+
+#, c-format
+msgid "E245: Illegal char '%c' in font name \"%s\""
+msgstr "E245: '%c' ã¯ä¸æ­£ãªæ–‡å­—ã§ã™ (フォントå \"%s\")"
+
+#, c-format
+msgid "Opening the X display took %ld msec"
+msgstr "Xサーãƒãƒ¼ã¸ã®æŽ¥ç¶šã« %ld ミリ秒ã‹ã‹ã‚Šã¾ã—ãŸ"
+
+msgid ""
+"\n"
+"Vim: Got X error\n"
+msgstr ""
+"\n"
+"Vim: X ã®ã‚¨ãƒ©ãƒ¼ã‚’検出ã—ã¾ã—ãŸr\n"
+
+msgid "Testing the X display failed"
+msgstr "X display ã®ãƒã‚§ãƒƒã‚¯ã«å¤±æ•—ã—ã¾ã—ãŸ"
+
+msgid "Opening the X display timed out"
+msgstr "X display ã® open ãŒã‚¿ã‚¤ãƒ ã‚¢ã‚¦ãƒˆã—ã¾ã—ãŸ"
+
+msgid ""
+"\n"
+"Could not get security context for "
+msgstr ""
+"\n"
+"セキュリティコンテキストをå–å¾—ã§ãã¾ã›ã‚“ "
+
+msgid ""
+"\n"
+"Could not set security context for "
+msgstr ""
+"\n"
+"セキュリティコンテキストを設定ã§ãã¾ã›ã‚“ "
+
+#, c-format
+msgid "Could not set security context %s for %s"
+msgstr "セキュリティコンテキスト %s ã‚’ %s ã«è¨­å®šã§ãã¾ã›ã‚“"
+
+#, c-format
+msgid "Could not get security context %s for %s. Removing it!"
+msgstr "セキュリティコンテキスト %s ã‚’ %s ã‹ã‚‰å–å¾—ã§ãã¾ã›ã‚“. 削除ã—ã¾ã™!"
+
+msgid ""
+"\n"
+"Cannot execute shell sh\n"
+msgstr ""
+"\n"
+"sh シェルを実行ã§ãã¾ã›ã‚“\n"
+
+msgid ""
+"\n"
+"shell returned "
+msgstr ""
+"\n"
+"シェルãŒå€¤ã‚’è¿”ã—ã¾ã—㟠"
+
+msgid ""
+"\n"
+"Cannot create pipes\n"
+msgstr ""
+"\n"
+"パイプを作æˆã§ãã¾ã›ã‚“\n"
+
+msgid ""
+"\n"
+"Cannot fork\n"
+msgstr ""
+"\n"
+"fork ã§ãã¾ã›ã‚“\n"
+
+msgid ""
+"\n"
+"Cannot execute shell "
+msgstr ""
+"\n"
+"シェルを実行ã§ãã¾ã›ã‚“ "
+
+msgid ""
+"\n"
+"Command terminated\n"
+msgstr ""
+"\n"
+"コマンドを中断ã—ã¾ã—ãŸ\n"
+
+msgid "XSMP lost ICE connection"
+msgstr "XSMP ãŒICE接続を失ã„ã¾ã—ãŸ"
+
+#, c-format
+msgid "dlerror = \"%s\""
+msgstr "dlerror = \"%s\""
+
+msgid "Opening the X display failed"
+msgstr "X display ã® open ã«å¤±æ•—ã—ã¾ã—ãŸ"
+
+msgid "XSMP handling save-yourself request"
+msgstr "XSMP ãŒsave-yourselfè¦æ±‚を処ç†ã—ã¦ã„ã¾ã™"
+
+msgid "XSMP opening connection"
+msgstr "XSMP ãŒæŽ¥ç¶šã‚’開始ã—ã¦ã„ã¾ã™"
+
+msgid "XSMP ICE connection watch failed"
+msgstr "XSMP ICE接続ãŒå¤±æ•—ã—ãŸã‚ˆã†ã§ã™"
+
+#, c-format
+msgid "XSMP SmcOpenConnection failed: %s"
+msgstr "XSMP SmcOpenConnectionãŒå¤±æ•—ã—ã¾ã—ãŸ: %s"
+
+msgid "At line"
+msgstr "行"
+
+msgid "Could not load vim32.dll!"
+msgstr "vim32.dll をロードã§ãã¾ã›ã‚“ã§ã—ãŸ"
+
+msgid "VIM Error"
+msgstr "VIMエラー"
+
+msgid "Could not fix up function pointers to the DLL!"
+msgstr "DLLã‹ã‚‰é–¢æ•°ãƒã‚¤ãƒ³ã‚¿ã‚’å–å¾—ã§ãã¾ã›ã‚“ã§ã—ãŸ"
+
+#, c-format
+msgid "Vim: Caught %s event\n"
+msgstr "Vim: イベント %s を検知\n"
+
+msgid "close"
+msgstr "é–‰ã˜ã‚‹"
+
+msgid "logoff"
+msgstr "ログオフ"
+
+msgid "shutdown"
+msgstr "シャットダウン"
+
+msgid "E371: Command not found"
+msgstr "E371: コマンドãŒã‚ã‚Šã¾ã›ã‚“"
+
+msgid ""
+"VIMRUN.EXE not found in your $PATH.\n"
+"External commands will not pause after completion.\n"
+"See :help win32-vimrun for more information."
+msgstr ""
+"VIMRUN.EXE㌠$PATH ã®ä¸­ã«è¦‹ã¤ã‹ã‚Šã¾ã›ã‚“.\n"
+"外部コマンドã®çµ‚了後ã«ä¸€æ™‚åœæ­¢ã‚’ã—ã¾ã›ã‚“.\n"
+"詳細㯠:help win32-vimrun ã‚’å‚ç…§ã—ã¦ãã ã•ã„."
+
+msgid "Vim Warning"
+msgstr "Vimã®è­¦å‘Š"
+
+#, c-format
+msgid "shell returned %d"
+msgstr "シェルãŒã‚³ãƒ¼ãƒ‰ %d ã§çµ‚了ã—ã¾ã—ãŸ"
+
+msgid "E926: Current location list was changed"
+msgstr "E926: ç¾åœ¨ã®ãƒ­ã‚±ãƒ¼ã‚·ãƒ§ãƒ³ãƒªã‚¹ãƒˆãŒå¤‰æ›´ã•ã‚Œã¾ã—ãŸ"
+
+#, c-format
+msgid "E372: Too many %%%c in format string"
+msgstr "E372: フォーマット文字列㫠%%%c ãŒå¤šéŽãŽã¾ã™"
+
+#, c-format
+msgid "E373: Unexpected %%%c in format string"
+msgstr "E373: フォーマット文字列ã«äºˆæœŸã›ã¬ %%%c ãŒã‚ã‚Šã¾ã—ãŸ"
+
+msgid "E374: Missing ] in format string"
+msgstr "E374: フォーマット文字列㫠] ãŒã‚ã‚Šã¾ã›ã‚“"
+
+#, c-format
+msgid "E375: Unsupported %%%c in format string"
+msgstr "E375: フォーマット文字列ã§ã¯ %%%c ã¯ã‚µãƒãƒ¼ãƒˆã•ã‚Œã¾ã›ã‚“"
+
+#, c-format
+msgid "E376: Invalid %%%c in format string prefix"
+msgstr "E376: フォーマット文字列ã®å‰ç½®ã«ç„¡åŠ¹ãª %%%c ãŒã‚ã‚Šã¾ã™"
+
+#, c-format
+msgid "E377: Invalid %%%c in format string"
+msgstr "E377: フォーマット文字列ã«ç„¡åŠ¹ãª %%%c ãŒã‚ã‚Šã¾ã™"
+
+msgid "E378: 'errorformat' contains no pattern"
+msgstr "E378: 'errorformat' ã«ãƒ‘ターンãŒæŒ‡å®šã•ã‚Œã¦ã„ã¾ã›ã‚“"
+
+msgid "E379: Missing or empty directory name"
+msgstr "E379: ディレクトリåãŒç„¡ã„ã‹ç©ºã§ã™"
+
+msgid "E553: No more items"
+msgstr "E553: è¦ç´ ãŒã‚‚ã†ã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E924: Current window was closed"
+msgstr "E924: ç¾åœ¨ã®ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ãŒé–‰ã˜ã‚‰ã‚Œã¾ã—ãŸ"
+
+msgid "E925: Current quickfix was changed"
+msgstr "E925: ç¾åœ¨ã® quickfix ãŒå¤‰æ›´ã•ã‚Œã¾ã—ãŸ"
+
+#, c-format
+msgid "(%d of %d)%s%s: "
+msgstr "(%d of %d)%s%s: "
+
+msgid " (line deleted)"
+msgstr " (è¡ŒãŒå‰Šé™¤ã•ã‚Œã¾ã—ãŸ)"
+
+#, c-format
+msgid "%serror list %d of %d; %d errors "
+msgstr "%s エラー一覧 %d of %d; %d 個エラー"
+
+msgid "E380: At bottom of quickfix stack"
+msgstr "E380: quickfix スタックã®æœ«å°¾ã§ã™"
+
+msgid "E381: At top of quickfix stack"
+msgstr "E381: quickfix スタックã®å…ˆé ­ã§ã™"
+
+msgid "No entries"
+msgstr "エントリãŒã‚ã‚Šã¾ã›ã‚“"
+
+msgid "Error file"
+msgstr "エラーファイル"
+
+msgid "E683: File name missing or invalid pattern"
+msgstr "E683: ファイルåãŒç„¡ã„ã‹ç„¡åŠ¹ãªãƒ‘ターンã§ã™"
+
+#, c-format
+msgid "Cannot open file \"%s\""
+msgstr "ファイル \"%s\" ã‚’é–‹ã‘ã¾ã›ã‚“"
+
+msgid "E681: Buffer is not loaded"
+msgstr "E681: ãƒãƒƒãƒ•ã‚¡ã¯èª­ã¿è¾¼ã¾ã‚Œã¾ã›ã‚“ã§ã—ãŸ"
+
+msgid "E777: String or List expected"
+msgstr "E777: 文字列ã‹ãƒªã‚¹ãƒˆãŒå¿…è¦ã§ã™"
+
+#, c-format
+msgid "E369: invalid item in %s%%[]"
+msgstr "E369: 無効ãªé …ç›®ã§ã™: %s%%[]"
+
+#, c-format
+msgid "E769: Missing ] after %s["
+msgstr "E769: %s[ ã®å¾Œã« ] ãŒã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E944: Reverse range in character class"
+msgstr "E944: 文字クラスã®ç¯„囲ãŒé€†ã§ã™"
+
+msgid "E945: Range too large in character class"
+msgstr "E945: 文字クラスã®ç¯„囲ãŒå¤§ãã™ãŽã¾ã™"
+
+#, c-format
+msgid "E53: Unmatched %s%%("
+msgstr "E53: %s%%( ãŒé‡£ã‚Šåˆã£ã¦ã„ã¾ã›ã‚“"
+
+#, c-format
+msgid "E54: Unmatched %s("
+msgstr "E54: %s( ãŒé‡£ã‚Šåˆã£ã¦ã„ã¾ã›ã‚“"
+
+#, c-format
+msgid "E55: Unmatched %s)"
+msgstr "E55: %s) ãŒé‡£ã‚Šåˆã£ã¦ã„ã¾ã›ã‚“"
+
+msgid "E66: \\z( not allowed here"
+msgstr "E66: \\z( ã¯ã‚³ã‚³ã§ã¯è¨±å¯ã•ã‚Œã¦ã„ã¾ã›ã‚“"
+
+msgid "E67: \\z1 - \\z9 not allowed here"
+msgstr "E67: \\z1 - \\z9 ã¯ã‚³ã‚³ã§ã¯è¨±å¯ã•ã‚Œã¦ã„ã¾ã›ã‚“"
+
+#, c-format
+msgid "E69: Missing ] after %s%%["
+msgstr "E69: %s%%[ ã®å¾Œã« ] ãŒã‚ã‚Šã¾ã›ã‚“"
+
+#, c-format
+msgid "E70: Empty %s%%[]"
+msgstr "E70: %s%%[] ãŒç©ºã§ã™"
+
+msgid "E956: Cannot use pattern recursively"
+msgstr "E956: パターンをå†å¸°çš„ã«ä½¿ã†ã“ã¨ã¯ã§ãã¾ã›ã‚“"
+
+msgid "E65: Illegal back reference"
+msgstr "E65: ä¸æ­£ãªå¾Œæ–¹å‚ç…§ã§ã™"
+
+msgid "E339: Pattern too long"
+msgstr "E339: パターンãŒé•·éŽãŽã¾ã™"
+
+msgid "E50: Too many \\z("
+msgstr "E50: \\z( ãŒå¤šéŽãŽã¾ã™"
+
+#, c-format
+msgid "E51: Too many %s("
+msgstr "E51: %s( ãŒå¤šéŽãŽã¾ã™"
+
+msgid "E52: Unmatched \\z("
+msgstr "E52: \\z( ãŒé‡£ã‚Šåˆã£ã¦ã„ã¾ã›ã‚“"
+
+#, c-format
+msgid "E59: invalid character after %s@"
+msgstr "E59: %s@ ã®å¾Œã«ä¸æ­£ãªæ–‡å­—ãŒã‚ã‚Šã¾ã—ãŸ"
+
+#, c-format
+msgid "E60: Too many complex %s{...}s"
+msgstr "E60: 複雑㪠%s{...} ãŒå¤šéŽãŽã¾ã™"
+
+#, c-format
+msgid "E61: Nested %s*"
+msgstr "E61:%s* ãŒå…¥ã‚Œå­ã«ãªã£ã¦ã„ã¾ã™"
+
+#, c-format
+msgid "E62: Nested %s%c"
+msgstr "E62:%s%c ãŒå…¥ã‚Œå­ã«ãªã£ã¦ã„ã¾ã™"
+
+msgid "E63: invalid use of \\_"
+msgstr "E63: \\_ ã®ç„¡åŠ¹ãªä½¿ç”¨æ–¹æ³•ã§ã™"
+
+#, c-format
+msgid "E64: %s%c follows nothing"
+msgstr "E64:%s%c ã®å¾Œã«ãªã«ã‚‚ã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E68: Invalid character after \\z"
+msgstr "E68: \\z ã®å¾Œã«ä¸æ­£ãªæ–‡å­—ãŒã‚ã‚Šã¾ã—ãŸ"
+
+#, c-format
+msgid "E678: Invalid character after %s%%[dxouU]"
+msgstr "E678: %s%%[dxouU] ã®å¾Œã«ä¸æ­£ãªæ–‡å­—ãŒã‚ã‚Šã¾ã—ãŸ"
+
+#, c-format
+msgid "E71: Invalid character after %s%%"
+msgstr "E71: %s%% ã®å¾Œã«ä¸æ­£ãªæ–‡å­—ãŒã‚ã‚Šã¾ã—ãŸ"
+
+#, c-format
+msgid "E554: Syntax error in %s{...}"
+msgstr "E554: %s{...} 内ã«æ–‡æ³•ã‚¨ãƒ©ãƒ¼ãŒã‚ã‚Šã¾ã™"
+
+msgid "External submatches:\n"
+msgstr "外部ã®éƒ¨åˆ†è©²å½“:\n"
+
+#, c-format
+msgid "E888: (NFA regexp) cannot repeat %s"
+msgstr "E888: (NFA æ­£è¦è¡¨ç¾) ç¹°ã‚Šè¿”ã›ã¾ã›ã‚“ %s"
+
+msgid ""
+"E864: \\%#= can only be followed by 0, 1, or 2. The automatic engine will be "
+"used "
+msgstr ""
+"E864: \\%#= ã«ã¯ 0, 1 ã‚‚ã—ã㯠2 ã®ã¿ãŒç¶šã‘られã¾ã™ã€‚æ­£è¦è¡¨ç¾ã‚¨ãƒ³ã‚¸ãƒ³ã¯è‡ªå‹•é¸"
+"択ã•ã‚Œã¾ã™ã€‚"
+
+msgid "Switching to backtracking RE engine for pattern: "
+msgstr "次ã®ãƒ‘ターンã«ãƒãƒƒã‚¯ãƒˆãƒ©ãƒƒã‚­ãƒ³ã‚° RE エンジンをé©ç”¨ã—ã¾ã™: "
+
+msgid "E865: (NFA) Regexp end encountered prematurely"
+msgstr "E865: (NFA) 期待より早ãæ­£è¦è¡¨ç¾ã®çµ‚端ã«åˆ°é”ã—ã¾ã—ãŸ"
+
+#, c-format
+msgid "E866: (NFA regexp) Misplaced %c"
+msgstr "E866: (NFA æ­£è¦è¡¨ç¾) ä½ç½®ãŒèª¤ã£ã¦ã„ã¾ã™: %c"
+
+#, c-format
+msgid "E877: (NFA regexp) Invalid character class: %ld"
+msgstr "E877: (NFA æ­£è¦è¡¨ç¾) 無効ãªæ–‡å­—クラス: %ld"
+
+#, c-format
+msgid "E867: (NFA) Unknown operator '\\z%c'"
+msgstr "E867: (NFA) 未知ã®ã‚ªãƒšãƒ¬ãƒ¼ã‚¿ã§ã™: '\\z%c'"
+
+msgid "E951: \\% value too large"
+msgstr "E951: \\% 値ãŒé•·éŽãŽã¾ã™"
+
+#, c-format
+msgid "E867: (NFA) Unknown operator '\\%%%c'"
+msgstr "E867: (NFA) 未知ã®ã‚ªãƒšãƒ¬ãƒ¼ã‚¿ã§ã™: '\\%%%c'"
+
+msgid "E868: Error building NFA with equivalence class!"
+msgstr "E868: 等価クラスをå«ã‚€NFA構築ã«å¤±æ•—ã—ã¾ã—ãŸ!"
+
+#, c-format
+msgid "E869: (NFA) Unknown operator '\\@%c'"
+msgstr "E869: (NFA) 未知ã®ã‚ªãƒšãƒ¬ãƒ¼ã‚¿ã§ã™: '\\@%c'"
+
+msgid "E870: (NFA regexp) Error reading repetition limits"
+msgstr "E870: (NFA æ­£è¦è¡¨ç¾) ç¹°ã‚Šè¿”ã—ã®åˆ¶é™å›žæ•°ã‚’読込中ã«ã‚¨ãƒ©ãƒ¼"
+
+msgid "E871: (NFA regexp) Can't have a multi follow a multi"
+msgstr "E871: (NFA æ­£è¦è¡¨ç¾) 繰り返㗠ã®å¾Œã« 繰り返㗠ã¯ã§ãã¾ã›ã‚“"
+
+msgid "E872: (NFA regexp) Too many '('"
+msgstr "E872: (NFA æ­£è¦è¡¨ç¾) '(' ãŒå¤šéŽãŽã¾ã™"
+
+msgid "E879: (NFA regexp) Too many \\z("
+msgstr "E879: (NFA æ­£è¦è¡¨ç¾) \\z( ãŒå¤šéŽãŽã¾ã™"
+
+msgid "E873: (NFA regexp) proper termination error"
+msgstr "E873: (NFA æ­£è¦è¡¨ç¾) 終端記å·ãŒã‚ã‚Šã¾ã›ã‚“"
+
+msgid "Could not open temporary log file for writing, displaying on stderr... "
+msgstr ""
+"NFAæ­£è¦è¡¨ç¾ã‚¨ãƒ³ã‚¸ãƒ³ç”¨ã®ãƒ­ã‚°ãƒ•ã‚¡ã‚¤ãƒ«ã‚’書込用ã¨ã—ã¦é–‹ã‘ã¾ã›ã‚“。ログã¯æ¨™æº–エラー"
+"出力ã«å‡ºåŠ›ã—ã¾ã™ã€‚"
+
+msgid "E874: (NFA) Could not pop the stack!"
+msgstr "E874: (NFA) スタックをãƒãƒƒãƒ—ã§ãã¾ã›ã‚“!"
+
+msgid ""
+"E875: (NFA regexp) (While converting from postfix to NFA), too many states "
+"left on stack"
+msgstr ""
+"E875: (NFA æ­£è¦è¡¨ç¾) (後置文字列をNFAã«å¤‰æ›ä¸­ã«) スタックã«æ®‹ã•ã‚ŒãŸã‚¹ãƒ†ãƒ¼ãƒˆãŒ"
+"多éŽãŽã¾ã™"
+
+msgid "E876: (NFA regexp) Not enough space to store the whole NFA "
+msgstr "E876: (NFA æ­£è¦è¡¨ç¾) NFA全体をä¿å­˜ã™ã‚‹ã«ã¯ç©ºãスペースãŒè¶³ã‚Šã¾ã›ã‚“"
+
+msgid "E878: (NFA) Could not allocate memory for branch traversal!"
+msgstr "E878: (NFA) ç¾åœ¨æ¨ªæ–­ä¸­ã®ãƒ–ランãƒã«å分ãªãƒ¡ãƒ¢ãƒªã‚’割り当ã¦ã‚‰ã‚Œã¾ã›ã‚“!"
+
+msgid " VREPLACE"
+msgstr " 仮想置æ›"
+
+msgid " REPLACE"
+msgstr " ç½®æ›"
+
+msgid " REVERSE"
+msgstr " å転"
+
+msgid " INSERT"
+msgstr " 挿入"
+
+msgid " (insert)"
+msgstr " (挿入)"
+
+msgid " (replace)"
+msgstr " (ç½®æ›)"
+
+msgid " (vreplace)"
+msgstr " (仮想置æ›)"
+
+msgid " Hebrew"
+msgstr " ヘブライ"
+
+msgid " Arabic"
+msgstr " アラビア"
+
+msgid " (paste)"
+msgstr " (貼り付ã‘)"
+
+msgid " VISUAL"
+msgstr " ビジュアル"
+
+msgid " VISUAL LINE"
+msgstr " ビジュアル 行"
+
+msgid " VISUAL BLOCK"
+msgstr " ビジュアル 矩形"
+
+msgid " SELECT"
+msgstr " セレクト"
+
+msgid " SELECT LINE"
+msgstr " 行指å‘é¸æŠž"
+
+msgid " SELECT BLOCK"
+msgstr " 矩形é¸æŠž"
+
+msgid "recording"
+msgstr "記録中"
+
+#, c-format
+msgid "E383: Invalid search string: %s"
+msgstr "E383: 無効ãªæ¤œç´¢æ–‡å­—列ã§ã™: %s"
+
+#, c-format
+msgid "E384: search hit TOP without match for: %s"
+msgstr "E384: 上ã¾ã§æ¤œç´¢ã—ã¾ã—ãŸãŒè©²å½“箇所ã¯ã‚ã‚Šã¾ã›ã‚“: %s"
+
+#, c-format
+msgid "E385: search hit BOTTOM without match for: %s"
+msgstr "E385: 下ã¾ã§æ¤œç´¢ã—ã¾ã—ãŸãŒè©²å½“箇所ã¯ã‚ã‚Šã¾ã›ã‚“: %s"
+
+msgid "E386: Expected '?' or '/' after ';'"
+msgstr "E386: ';' ã®ã‚ã¨ã«ã¯ '?' ã‹ '/' ãŒæœŸå¾…ã•ã‚Œã¦ã„ã‚‹"
+
+msgid " (includes previously listed match)"
+msgstr " (å‰ã«åˆ—挙ã—ãŸè©²å½“箇所をå«ã‚€)"
+
+msgid "--- Included files "
+msgstr "--- インクルードã•ã‚ŒãŸãƒ•ã‚¡ã‚¤ãƒ« "
+
+msgid "not found "
+msgstr "見ã¤ã‹ã‚Šã¾ã›ã‚“ "
+
+msgid "in path ---\n"
+msgstr "パス㫠----\n"
+
+msgid " (Already listed)"
+msgstr " (æ—¢ã«åˆ—挙)"
+
+msgid " NOT FOUND"
+msgstr " 見ã¤ã‹ã‚Šã¾ã›ã‚“"
+
+#, c-format
+msgid "Scanning included file: %s"
+msgstr "インクルードã•ã‚ŒãŸãƒ•ã‚¡ã‚¤ãƒ«ã‚’スキャン中: %s"
+
+#, c-format
+msgid "Searching included file %s"
+msgstr "インクルードã•ã‚ŒãŸãƒ•ã‚¡ã‚¤ãƒ«ã‚’検索中 %s"
+
+msgid "E387: Match is on current line"
+msgstr "E387: ç¾åœ¨è¡Œã«è©²å½“ãŒã‚ã‚Šã¾ã™"
+
+msgid "All included files were found"
+msgstr "å…¨ã¦ã®ã‚¤ãƒ³ã‚¯ãƒ«ãƒ¼ãƒ‰ã•ã‚ŒãŸãƒ•ã‚¡ã‚¤ãƒ«ãŒè¦‹ã¤ã‹ã‚Šã¾ã—ãŸ"
+
+msgid "No included files"
+msgstr "インクルードファイルã¯ã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E388: Couldn't find definition"
+msgstr "E388: 定義を見ã¤ã‘られã¾ã›ã‚“"
+
+msgid "E389: Couldn't find pattern"
+msgstr "E389: パターンを見ã¤ã‘られã¾ã›ã‚“"
+
+msgid "Substitute "
+msgstr "Substitute "
+
+#, c-format
+msgid ""
+"\n"
+"# Last %sSearch Pattern:\n"
+"~"
+msgstr ""
+"\n"
+"# 最後㮠%s検索パターン:\n"
+"~"
+
+msgid "E756: Spell checking is not enabled"
+msgstr "E756: スペルãƒã‚§ãƒƒã‚¯ã¯ç„¡åŠ¹åŒ–ã•ã‚Œã¦ã„ã¾ã™"
+
+#, c-format
+msgid "Warning: Cannot find word list \"%s_%s.spl\" or \"%s_ascii.spl\""
+msgstr ""
+"警告: å˜èªžãƒªã‚¹ãƒˆ \"%s_%s.spl\" ãŠã‚ˆã³ \"%s_ascii.spl\" ã¯è¦‹ã¤ã‹ã‚Šã¾ã›ã‚“"
+
+#, c-format
+msgid "Warning: Cannot find word list \"%s.%s.spl\" or \"%s.ascii.spl\""
+msgstr ""
+"警告: å˜èªžãƒªã‚¹ãƒˆ \"%s.%s.spl\" ãŠã‚ˆã³ \"%s.ascii.spl\" ã¯è¦‹ã¤ã‹ã‚Šã¾ã›ã‚“"
+
+msgid "E797: SpellFileMissing autocommand deleted buffer"
+msgstr "E797: autocommand ã® SpellFileMissing ãŒãƒãƒƒãƒ•ã‚¡ã‚’削除ã—ã¾ã—ãŸ"
+
+#, c-format
+msgid "Warning: region %s not supported"
+msgstr "警告9: %s ã¨ã„ã†ç¯„囲ã¯ã‚µãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ã¾ã›ã‚“"
+
+msgid "Sorry, no suggestions"
+msgstr "残念ã§ã™ãŒã€ä¿®æ­£å€™è£œã¯ã‚ã‚Šã¾ã›ã‚“"
+
+#, c-format
+msgid "Sorry, only %ld suggestions"
+msgstr "残念ã§ã™ãŒã€ä¿®æ­£å€™è£œã¯ %ld 個ã—ã‹ã‚ã‚Šã¾ã›ã‚“"
+
+#, c-format
+msgid "Change \"%.*s\" to:"
+msgstr "\"%.*s\" を次ã¸å¤‰æ›:"
+
+#, c-format
+msgid " < \"%.*s\""
+msgstr " < \"%.*s\""
+
+msgid "E752: No previous spell replacement"
+msgstr "E752: スペル置æ›ãŒã¾ã å®Ÿè¡Œã•ã‚Œã¦ã„ã¾ã›ã‚“"
+
+#, c-format
+msgid "E753: Not found: %s"
+msgstr "E753: 見ã¤ã‹ã‚Šã¾ã›ã‚“: %s"
+
+msgid "E758: Truncated spell file"
+msgstr "E758: スペルファイルãŒåˆ‡å–られã¦ã„るよã†ã§ã™"
+
+#, c-format
+msgid "Trailing text in %s line %d: %s"
+msgstr "%s (%d 行目) ã«ç¶šãテキスト: %s"
+
+#, c-format
+msgid "Affix name too long in %s line %d: %s"
+msgstr "%s (%d 行目) ã® affix åãŒé•·éŽãŽã¾ã™: %s"
+
+msgid "E761: Format error in affix file FOL, LOW or UPP"
+msgstr ""
+"E761: affixファイル㮠FOL, LOW ã‚‚ã—ã㯠UPP ã®ãƒ•ã‚©ãƒ¼ãƒžãƒƒãƒˆã«ã‚¨ãƒ©ãƒ¼ãŒã‚ã‚Šã¾ã™"
+
+msgid "E762: Character in FOL, LOW or UPP is out of range"
+msgstr "E762: FOL, LOW ã‚‚ã—ã㯠UPP ã®æ–‡å­—ãŒç¯„囲外ã§ã™"
+
+msgid "Compressing word tree..."
+msgstr "å˜èªžãƒ„リーを圧縮ã—ã¦ã„ã¾ã™..."
+
+#, c-format
+msgid "Reading spell file \"%s\""
+msgstr "スペルファイル \"%s\" を読込中"
+
+msgid "E757: This does not look like a spell file"
+msgstr "E757: スペルファイルã§ã¯ãªã„よã†ã§ã™"
+
+msgid "E771: Old spell file, needs to be updated"
+msgstr "E771: å¤ã„スペルファイルãªã®ã§ã€ã‚¢ãƒƒãƒ—デートã—ã¦ãã ã•ã„"
+
+msgid "E772: Spell file is for newer version of Vim"
+msgstr "E772: より新ã—ã„ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã® Vim 用ã®ã‚¹ãƒšãƒ«ãƒ•ã‚¡ã‚¤ãƒ«ã§ã™"
+
+msgid "E770: Unsupported section in spell file"
+msgstr "E770: スペルファイルã«ã‚µãƒãƒ¼ãƒˆã—ã¦ã„ãªã„セクションãŒã‚ã‚Šã¾ã™"
+
+#, c-format
+msgid "E778: This does not look like a .sug file: %s"
+msgstr "E778: .sug ファイルã§ã¯ãªã„よã†ã§ã™: %s"
+
+#, c-format
+msgid "E779: Old .sug file, needs to be updated: %s"
+msgstr "E779: å¤ã„ .sug ファイルãªã®ã§ã€ã‚¢ãƒƒãƒ—デートã—ã¦ãã ã•ã„: %s"
+
+#, c-format
+msgid "E780: .sug file is for newer version of Vim: %s"
+msgstr "E780: より新ã—ã„ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã® Vim 用㮠.sug ファイルã§ã™: %s"
+
+#, c-format
+msgid "E781: .sug file doesn't match .spl file: %s"
+msgstr "E781: .sug ファイル㌠.spl ファイルã¨ä¸€è‡´ã—ã¾ã›ã‚“: %s"
+
+#, c-format
+msgid "E782: error while reading .sug file: %s"
+msgstr "E782: .sug ファイルã®èª­è¾¼ä¸­ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸ: %s"
+
+#, c-format
+msgid "Reading affix file %s..."
+msgstr "affix ファイル %s を読込中..."
+
+#, c-format
+msgid "Conversion failure for word in %s line %d: %s"
+msgstr "%s (%d 行目) ã®å˜èªžã‚’変æ›ã§ãã¾ã›ã‚“ã§ã—ãŸ: %s"
+
+#, c-format
+msgid "Conversion in %s not supported: from %s to %s"
+msgstr "%s 内ã®æ¬¡ã®å¤‰æ›ã¯ã‚µãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ã¾ã›ã‚“: %s ã‹ã‚‰ %s ã¸"
+
+#, c-format
+msgid "Conversion in %s not supported"
+msgstr "%s 内ã®å¤‰æ›ã¯ã‚µãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ã¾ã›ã‚“"
+
+#, c-format
+msgid "Invalid value for FLAG in %s line %d: %s"
+msgstr "%s 内㮠%d 行目㮠FLAG ã«ç„¡åŠ¹ãªå€¤ãŒã‚ã‚Šã¾ã™: %s"
+
+#, c-format
+msgid "FLAG after using flags in %s line %d: %s"
+msgstr "%s 内㮠%d 行目ã«ãƒ•ãƒ©ã‚°ã®äºŒé‡ä½¿ç”¨ãŒã‚ã‚Šã¾ã™: %s"
+
+#, c-format
+msgid ""
+"Defining COMPOUNDFORBIDFLAG after PFX item may give wrong results in %s line "
+"%d"
+msgstr ""
+"%s ã® %d 行目㮠PFX é …ç›®ã®å¾Œã® COMPOUNDFORBIDFLAG ã®å®šç¾©ã¯èª¤ã£ãŸçµæžœã‚’生ã˜ã‚‹"
+"ã“ã¨ãŒã‚ã‚Šã¾ã™"
+
+#, c-format
+msgid ""
+"Defining COMPOUNDPERMITFLAG after PFX item may give wrong results in %s line "
+"%d"
+msgstr ""
+"%s ã® %d 行目㮠PFX é …ç›®ã®å¾Œã® COMPOUNDPERMITFLAG ã®å®šç¾©ã¯èª¤ã£ãŸçµæžœã‚’生ã˜ã‚‹"
+"ã“ã¨ãŒã‚ã‚Šã¾ã™"
+
+#, c-format
+msgid "Wrong COMPOUNDRULES value in %s line %d: %s"
+msgstr "COMPOUNDRULES ã®å€¤ã«èª¤ã‚ŠãŒã‚ã‚Šã¾ã™. ファイル %s ã® %d 行目: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDWORDMAX value in %s line %d: %s"
+msgstr "%s ã® %d 行目㮠COMPOUNDWORDMAX ã®å€¤ã«èª¤ã‚ŠãŒã‚ã‚Šã¾ã™: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDMIN value in %s line %d: %s"
+msgstr "%s ã® %d 行目㮠COMPOUNDMIN ã®å€¤ã«èª¤ã‚ŠãŒã‚ã‚Šã¾ã™: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDSYLMAX value in %s line %d: %s"
+msgstr "%s ã® %d 行目㮠COMPOUNDSYLMAX ã®å€¤ã«èª¤ã‚ŠãŒã‚ã‚Šã¾ã™: %s"
+
+#, c-format
+msgid "Wrong CHECKCOMPOUNDPATTERN value in %s line %d: %s"
+msgstr "%s ã® %d 行目㮠CHECKCOMPOUNDPATTERN ã®å€¤ã«èª¤ã‚ŠãŒã‚ã‚Šã¾ã™: %s"
+
+#, c-format
+msgid "Different combining flag in continued affix block in %s line %d: %s"
+msgstr ""
+"%s ã® %d 行目㮠連続 affix ブロックã®ãƒ•ãƒ©ã‚°ã®çµ„åˆã›ã«é•ã„ãŒã‚ã‚Šã¾ã™: %s"
+
+#, c-format
+msgid "Duplicate affix in %s line %d: %s"
+msgstr "%s ã® %d 行目㫠é‡è¤‡ã—㟠affix を検出ã—ã¾ã—ãŸ: %s"
+
+#, c-format
+msgid ""
+"Affix also used for BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST in %s "
+"line %d: %s"
+msgstr ""
+"%s 㮠%d 行目㮠affix 㯠BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST "
+"ã«ä½¿ç”¨ã—ã¦ãã ã•ã„: %s"
+
+#, c-format
+msgid "Expected Y or N in %s line %d: %s"
+msgstr "%s ã® %d 行目ã§ã¯ Y ã‹ N ãŒå¿…è¦ã§ã™: %s"
+
+#, c-format
+msgid "Broken condition in %s line %d: %s"
+msgstr "%s ã® %d 行目㮠æ¡ä»¶ã¯å£Šã‚Œã¦ã„ã¾ã™: %s"
+
+#, c-format
+msgid "Expected REP(SAL) count in %s line %d"
+msgstr "%s ã® %d 行目ã«ã¯ REP(SAL) ã®å›žæ•°ãŒå¿…è¦ã§ã™"
+
+#, c-format
+msgid "Expected MAP count in %s line %d"
+msgstr "%s ã® %d 行目ã«ã¯ MAP ã®å›žæ•°ãŒå¿…è¦ã§ã™"
+
+#, c-format
+msgid "Duplicate character in MAP in %s line %d"
+msgstr "%s ã® %d 行目㮠MAP ã«é‡è¤‡ã—ãŸæ–‡å­—ãŒã‚ã‚Šã¾ã™"
+
+#, c-format
+msgid "Unrecognized or duplicate item in %s line %d: %s"
+msgstr "%s ã® %d 行目㫠èªè­˜ã§ããªã„ã‹é‡è¤‡ã—ãŸé …ç›®ãŒã‚ã‚Šã¾ã™: %s"
+
+#, c-format
+msgid "Missing FOL/LOW/UPP line in %s"
+msgstr "%s 行目㫠FOL/LOW/UPP ãŒã‚ã‚Šã¾ã›ã‚“"
+
+msgid "COMPOUNDSYLMAX used without SYLLABLE"
+msgstr "SYLLABLE ãŒæŒ‡å®šã•ã‚Œãªã„ COMPOUNDSYLMAX"
+
+msgid "Too many postponed prefixes"
+msgstr "é…延後置å­ãŒå¤šéŽãŽã¾ã™"
+
+msgid "Too many compound flags"
+msgstr "複åˆãƒ•ãƒ©ã‚°ãŒå¤šéŽãŽã¾ã™"
+
+msgid "Too many postponed prefixes and/or compound flags"
+msgstr "é…å»¶å¾Œç½®å­ ã¨/ã‚‚ã—ã㯠複åˆãƒ•ãƒ©ã‚°ãŒå¤šéŽãŽã¾ã™"
+
+#, c-format
+msgid "Missing SOFO%s line in %s"
+msgstr "SOFO%s 行㌠%s ã«ã‚ã‚Šã¾ã›ã‚“"
+
+#, c-format
+msgid "Both SAL and SOFO lines in %s"
+msgstr "SALè¡Œ 㨠SOFOè¡Œ ㌠%s ã§ä¸¡æ–¹æŒ‡å®šã•ã‚Œã¦ã„ã¾ã™"
+
+#, c-format
+msgid "Flag is not a number in %s line %d: %s"
+msgstr "%s ã® %d 行㮠フラグãŒæ•°å€¤ã§ã¯ã‚ã‚Šã¾ã›ã‚“: %s"
+
+#, c-format
+msgid "Illegal flag in %s line %d: %s"
+msgstr "%s ã® %d 行目㮠フラグãŒä¸æ­£ã§ã™: %s"
+
+#, c-format
+msgid "%s value differs from what is used in another .aff file"
+msgstr "値 %s ã¯ä»–ã® .aff ファイルã§ä½¿ç”¨ã•ã‚ŒãŸã®ã¨ç•°ãªã‚Šã¾ã™"
+
+#, c-format
+msgid "Reading dictionary file %s..."
+msgstr "辞書ファイル %s を読込ã¿ä¸­..."
+
+#, c-format
+msgid "E760: No word count in %s"
+msgstr "E760: %s ã«ã¯å˜èªžæ•°ãŒã‚ã‚Šã¾ã›ã‚“"
+
+#, c-format
+msgid "line %6d, word %6ld - %s"
+msgstr "è¡Œ %6d, å˜èªž %6ld - %s"
+
+#, c-format
+msgid "Duplicate word in %s line %d: %s"
+msgstr "%s ã® %d 行目㧠é‡è¤‡å˜èªžãŒè¦‹ã¤ã‹ã‚Šã¾ã—ãŸ: %s"
+
+#, c-format
+msgid "First duplicate word in %s line %d: %s"
+msgstr "é‡è¤‡ã®ã†ã¡æœ€åˆã®å˜èªžã¯ %s ã® %d 行目ã§ã™: %s"
+
+#, c-format
+msgid "%d duplicate word(s) in %s"
+msgstr "%d 個ã®å˜èªžãŒè¦‹ã¤ã‹ã‚Šã¾ã—㟠(%s 内)"
+
+#, c-format
+msgid "Ignored %d word(s) with non-ASCII characters in %s"
+msgstr "éžASCII文字をå«ã‚€ %d 個ã®å˜èªžã‚’無視ã—ã¾ã—㟠(%s 内)"
+
+#, c-format
+msgid "Reading word file %s..."
+msgstr "å˜èªžãƒ•ã‚¡ã‚¤ãƒ« %s を読込ã¿ä¸­..."
+
+#, c-format
+msgid "Duplicate /encoding= line ignored in %s line %d: %s"
+msgstr "%s ã® %d 行目㮠é‡è¤‡ã—㟠/encoding= 行を無視ã—ã¾ã—ãŸ: %s"
+
+#, c-format
+msgid "/encoding= line after word ignored in %s line %d: %s"
+msgstr "%s ã® %d 行目㮠å˜èªžã®å¾Œã® /encoding= 行を無視ã—ã¾ã—ãŸ: %s"
+
+#, c-format
+msgid "Duplicate /regions= line ignored in %s line %d: %s"
+msgstr "%s ã® %d 行目㮠é‡è¤‡ã—㟠/regions= 行を無視ã—ã¾ã—ãŸ: %s"
+
+#, c-format
+msgid "Too many regions in %s line %d: %s"
+msgstr "%s ã® %d 行目ã€ç¯„囲指定ãŒå¤šéŽãŽã¾ã™: %s"
+
+#, c-format
+msgid "/ line ignored in %s line %d: %s"
+msgstr "%s ã® %d 行目㮠é‡è¤‡ã—㟠/ 行を無視ã—ã¾ã—ãŸ: %s"
+
+#, c-format
+msgid "Invalid region nr in %s line %d: %s"
+msgstr "%s ã® %d 行目 無効㪠nr 領域ã§ã™: %s"
+
+#, c-format
+msgid "Unrecognized flags in %s line %d: %s"
+msgstr "%s ã® %d 行目 èªè­˜ä¸èƒ½ãªãƒ•ãƒ©ã‚°ã§ã™: %s"
+
+#, c-format
+msgid "Ignored %d words with non-ASCII characters"
+msgstr "éžASCII文字をå«ã‚€ %d 個ã®å˜èªžã‚’無視ã—ã¾ã—ãŸ"
+
+msgid "E845: Insufficient memory, word list will be incomplete"
+msgstr "E845: メモリãŒè¶³ã‚Šãªã„ã®ã§ã€å˜èªžãƒªã‚¹ãƒˆã¯ä¸å®Œå…¨ã§ã™"
+
+#, c-format
+msgid "Compressed %d of %d nodes; %d (%d%%) remaining"
+msgstr "ノード %d 個(å…¨ %d 個中) を圧縮ã—ã¾ã—ãŸ; 残り %d (%d%%)"
+
+msgid "Reading back spell file..."
+msgstr "スペルファイルを逆読込中"
+
+msgid "Performing soundfolding..."
+msgstr "音声畳込ã¿ã‚’実行中..."
+
+#, c-format
+msgid "Number of words after soundfolding: %ld"
+msgstr "音声畳込ã¿å¾Œã®ç·å˜èªžæ•°: %ld"
+
+#, c-format
+msgid "Total number of words: %d"
+msgstr "ç·å˜èªžæ•°: %d"
+
+#, c-format
+msgid "Writing suggestion file %s..."
+msgstr "修正候補ファイル \"%s\" を書込ã¿ä¸­..."
+
+#, c-format
+msgid "Estimated runtime memory use: %d bytes"
+msgstr "推定メモリ使用é‡: %d ãƒã‚¤ãƒˆ"
+
+msgid "E751: Output file name must not have region name"
+msgstr "E751: 出力ファイルåã«ã¯ç¯„囲åã‚’å«ã‚られã¾ã›ã‚“"
+
+#, c-format
+msgid "E754: Only up to %ld regions supported"
+msgstr "E754: 範囲㯠%ld 個ã¾ã§ã—ã‹ã‚µãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ã¾ã›ã‚“"
+
+#, c-format
+msgid "E755: Invalid region in %s"
+msgstr "E755: 無効ãªç¯„囲ã§ã™: %s"
+
+msgid "Warning: both compounding and NOBREAK specified"
+msgstr "警告: 複åˆãƒ•ãƒ©ã‚°ã¨ NOBREAK ãŒä¸¡æ–¹ã¨ã‚‚指定ã•ã‚Œã¾ã—ãŸ"
+
+#, c-format
+msgid "Writing spell file %s..."
+msgstr "スペルファイル %s を書込ã¿ä¸­..."
+
+msgid "Done!"
+msgstr "実行ã—ã¾ã—ãŸ!"
+
+#, c-format
+msgid "E765: 'spellfile' does not have %ld entries"
+msgstr "E765: 'spellfile' ã«ã¯ %ld 個ã®ã‚¨ãƒ³ãƒˆãƒªã¯ã‚ã‚Šã¾ã›ã‚“"
+
+#, c-format
+msgid "Word '%.*s' removed from %s"
+msgstr "å˜èªž '%.*s' ㌠%s ã‹ã‚‰å‰Šé™¤ã•ã‚Œã¾ã—ãŸ"
+
+#, c-format
+msgid "Word '%.*s' added to %s"
+msgstr "å˜èªž '%.*s' ㌠%s ã¸è¿½åŠ ã•ã‚Œã¾ã—ãŸ"
+
+msgid "E763: Word characters differ between spell files"
+msgstr "E763: å˜èªžã®æ–‡å­—ãŒã‚¹ãƒšãƒ«ãƒ•ã‚¡ã‚¤ãƒ«ã¨ç•°ãªã‚Šã¾ã™"
+
+msgid "E783: duplicate char in MAP entry"
+msgstr "E783: MAP エントリã«é‡è¤‡æ–‡å­—ãŒå­˜åœ¨ã—ã¾ã™"
+
+msgid "No Syntax items defined for this buffer"
+msgstr "ã“ã®ãƒãƒƒãƒ•ã‚¡ã«å®šç¾©ã•ã‚ŒãŸæ§‹æ–‡è¦ç´ ã¯ã‚ã‚Šã¾ã›ã‚“"
+
+msgid "'redrawtime' exceeded, syntax highlighting disabled"
+msgstr "'redrawtime' を超éŽã—ãŸãŸã‚ã€æ§‹æ–‡ãƒã‚¤ãƒ©ã‚¤ãƒˆã¯ç„¡åŠ¹åŒ–ã•ã‚Œã¾ã™"
+
+msgid "syntax conceal on"
+msgstr "構文㮠conceal ã¯ç¾åœ¨ on ã§ã™"
+
+msgid "syntax conceal off"
+msgstr "構文㮠conceal ã¯ç¾åœ¨ off ã§ã™"
+
+#, c-format
+msgid "E390: Illegal argument: %s"
+msgstr "E390: ä¸æ­£ãªå¼•æ•°ã§ã™: %s"
+
+msgid "syntax case ignore"
+msgstr "構文ã®å¤§æ–‡å­—å°æ–‡å­—ã¯ç¾åœ¨ ignore ã§ã™"
+
+msgid "syntax case match"
+msgstr "構文ã®å¤§æ–‡å­—å°æ–‡å­—ã¯ç¾åœ¨ match ã§ã™"
+
+msgid "syntax spell toplevel"
+msgstr "構文㮠spell ã¯ç¾åœ¨ toplevel ã§ã™"
+
+msgid "syntax spell notoplevel"
+msgstr "構文㮠spell ã¯ç¾åœ¨ notoplevel ã§ã™"
+
+msgid "syntax spell default"
+msgstr "構文㮠spell ã¯ç¾åœ¨ default ã§ã™"
+
+msgid "syntax iskeyword "
+msgstr "構文用 iskeyword "
+
+msgid "syntax iskeyword not set"
+msgstr "構文用 iskeyword ã¯ã‚»ãƒƒãƒˆã•ã‚Œã¦ã„ã¾ã›ã‚“"
+
+#, c-format
+msgid "E391: No such syntax cluster: %s"
+msgstr "E391: ãã®ã‚ˆã†ãªæ§‹æ–‡ã‚¯ãƒ©ã‚¹ã‚¿ã¯ã‚ã‚Šã¾ã›ã‚“: %s"
+
+msgid "syncing on C-style comments"
+msgstr "C言語風コメントã‹ã‚‰åŒæœŸä¸­"
+
+msgid "no syncing"
+msgstr "éžåŒæœŸ"
+
+msgid "syncing starts "
+msgstr "åŒæœŸé–‹å§‹ "
+
+msgid " lines before top line"
+msgstr " è¡Œå‰(トップ行よりも)"
+
+msgid ""
+"\n"
+"--- Syntax sync items ---"
+msgstr ""
+"\n"
+"--- 構文åŒæœŸè¦ç´  ---"
+
+msgid ""
+"\n"
+"syncing on items"
+msgstr ""
+"\n"
+"è¦ç´ ä¸Šã§åŒæœŸä¸­"
+
+msgid ""
+"\n"
+"--- Syntax items ---"
+msgstr ""
+"\n"
+"--- 構文è¦ç´  ---"
+
+#, c-format
+msgid "E392: No such syntax cluster: %s"
+msgstr "E392: ãã®ã‚ˆã†ãªæ§‹æ–‡ã‚¯ãƒ©ã‚¹ã‚¿ã¯ã‚ã‚Šã¾ã›ã‚“: %s"
+
+msgid "minimal "
+msgstr "minimal "
+
+msgid "maximal "
+msgstr "maximal "
+
+msgid "; match "
+msgstr "; 該当 "
+
+msgid " line breaks"
+msgstr " 個ã®æ”¹è¡Œ"
+
+msgid "E395: contains argument not accepted here"
+msgstr "E395: ã“ã®å ´æ‰€ã§ã¯å¼•æ•°containsã¯è¨±å¯ã•ã‚Œã¦ã„ã¾ã›ã‚“"
+
+msgid "E844: invalid cchar value"
+msgstr "E844: 無効ãªccharã®å€¤ã§ã™"
+
+msgid "E393: group[t]here not accepted here"
+msgstr "E393: ã“ã“ã§ã¯ã‚°ãƒ«ãƒ¼ãƒ—ã¯è¨±å¯ã•ã‚Œã¾ã›ã‚“"
+
+#, c-format
+msgid "E394: Didn't find region item for %s"
+msgstr "E394: %s ã®ç¯„囲è¦ç´ ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“"
+
+msgid "E397: Filename required"
+msgstr "E397: ファイルåãŒå¿…è¦ã§ã™"
+
+msgid "E847: Too many syntax includes"
+msgstr "E847: 構文ã®å–ã‚Šè¾¼ã¿(include)ãŒå¤šéŽãŽã¾ã™"
+
+#, c-format
+msgid "E789: Missing ']': %s"
+msgstr "E789: ']' ãŒã‚ã‚Šã¾ã›ã‚“: %s"
+
+#, c-format
+msgid "E890: trailing char after ']': %s]%s"
+msgstr "E890: ']' ã®å¾Œã‚ã«ä½™åˆ†ãªæ–‡å­—ãŒã‚ã‚Šã¾ã™: %s]%s"
+
+#, c-format
+msgid "E398: Missing '=': %s"
+msgstr "E398: '=' ãŒã‚ã‚Šã¾ã›ã‚“: %s"
+
+#, c-format
+msgid "E399: Not enough arguments: syntax region %s"
+msgstr "E399: 引数ãŒè¶³ã‚Šã¾ã›ã‚“: 構文範囲 %s"
+
+msgid "E848: Too many syntax clusters"
+msgstr "E848: 構文クラスタãŒå¤šéŽãŽã¾ã™"
+
+msgid "E400: No cluster specified"
+msgstr "E400: クラスタãŒæŒ‡å®šã•ã‚Œã¦ã„ã¾ã›ã‚“"
+
+#, c-format
+msgid "E401: Pattern delimiter not found: %s"
+msgstr "E401: パターン区切りãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“: %s"
+
+#, c-format
+msgid "E402: Garbage after pattern: %s"
+msgstr "E402: パターンã®ã‚ã¨ã«ã‚´ãƒŸãŒã‚ã‚Šã¾ã™: %s"
+
+msgid "E403: syntax sync: line continuations pattern specified twice"
+msgstr "E403: 構文åŒæœŸ: 連続行パターンãŒ2度指定ã•ã‚Œã¾ã—ãŸ"
+
+#, c-format
+msgid "E404: Illegal arguments: %s"
+msgstr "E404: ä¸æ­£ãªå¼•æ•°ã§ã™: %s"
+
+#, c-format
+msgid "E405: Missing equal sign: %s"
+msgstr "E405: ç­‰å·ãŒã‚ã‚Šã¾ã›ã‚“: %s"
+
+#, c-format
+msgid "E406: Empty argument: %s"
+msgstr "E406: 空ã®å¼•æ•°: %s"
+
+#, c-format
+msgid "E407: %s not allowed here"
+msgstr "E407: %s ã¯ã‚³ã‚³ã§ã¯è¨±å¯ã•ã‚Œã¦ã„ã¾ã›ã‚“"
+
+#, c-format
+msgid "E408: %s must be first in contains list"
+msgstr "E408: %s ã¯å†…容リストã®å…ˆé ­ã§ãªã‘ã‚Œã°ãªã‚‰ãªã„"
+
+#, c-format
+msgid "E409: Unknown group name: %s"
+msgstr "E409: 未知ã®ã‚°ãƒ«ãƒ¼ãƒ—å: %s"
+
+#, c-format
+msgid "E410: Invalid :syntax subcommand: %s"
+msgstr "E410: 無効㪠:syntax ã®ã‚µãƒ–コマンド: %s"
+
+msgid ""
+" TOTAL COUNT MATCH SLOWEST AVERAGE NAME PATTERN"
+msgstr ""
+" TOTAL COUNT MATCH SLOWEST AVERAGE NAME PATTERN"
+
+msgid "E679: recursive loop loading syncolor.vim"
+msgstr "E679: syncolor.vim ã®å†å¸°å‘¼ã³å‡ºã—を検出ã—ã¾ã—ãŸ"
+
+#, c-format
+msgid "E411: highlight group not found: %s"
+msgstr "E411: ãƒã‚¤ãƒ©ã‚¤ãƒˆã‚°ãƒ«ãƒ¼ãƒ—ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“: %s"
+
+#, c-format
+msgid "E412: Not enough arguments: \":highlight link %s\""
+msgstr "E412: 引数ãŒå……分ã§ã¯ãªã„: \":highlight link %s\""
+
+#, c-format
+msgid "E413: Too many arguments: \":highlight link %s\""
+msgstr "E413: 引数ãŒå¤šéŽãŽã¾ã™: \":highlight link %s\""
+
+msgid "E414: group has settings, highlight link ignored"
+msgstr "E414: グループãŒè¨­å®šã•ã‚Œã¦ã„ã‚‹ã®ã§ãƒã‚¤ãƒ©ã‚¤ãƒˆãƒªãƒ³ã‚¯ã¯ç„¡è¦–ã•ã‚Œã¾ã™"
+
+#, c-format
+msgid "E415: unexpected equal sign: %s"
+msgstr "E415: 予期ã›ã¬ç­‰å·ã§ã™: %s"
+
+#, c-format
+msgid "E416: missing equal sign: %s"
+msgstr "E416: ç­‰å·ãŒã‚ã‚Šã¾ã›ã‚“: %s"
+
+#, c-format
+msgid "E417: missing argument: %s"
+msgstr "E417: 引数ãŒã‚ã‚Šã¾ã›ã‚“: %s"
+
+#, c-format
+msgid "E418: Illegal value: %s"
+msgstr "E418: ä¸æ­£ãªå€¤ã§ã™: %s"
+
+msgid "E419: FG color unknown"
+msgstr "E419: 未知ã®å‰æ™¯è‰²ã§ã™"
+
+msgid "E420: BG color unknown"
+msgstr "E420: 未知ã®èƒŒæ™¯è‰²ã§ã™"
+
+#, c-format
+msgid "E421: Color name or number not recognized: %s"
+msgstr "E421: カラーåや番å·ã‚’èªè­˜ã§ãã¾ã›ã‚“: %s"
+
+#, c-format
+msgid "E422: terminal code too long: %s"
+msgstr "E422: 終端コードãŒé•·éŽãŽã¾ã™: %s"
+
+#, c-format
+msgid "E423: Illegal argument: %s"
+msgstr "E423: ä¸æ­£ãªå¼•æ•°ã§ã™: %s"
+
+msgid "E424: Too many different highlighting attributes in use"
+msgstr "E424: 多ãã®ç•°ãªã‚‹ãƒã‚¤ãƒ©ã‚¤ãƒˆå±žæ€§ãŒä½¿ã‚ã‚ŒéŽãŽã¦ã„ã¾ã™"
+
+msgid "E669: Unprintable character in group name"
+msgstr "E669: グループåã«å°åˆ·ä¸å¯èƒ½ãªæ–‡å­—ãŒã‚ã‚Šã¾ã™"
+
+msgid "W18: Invalid character in group name"
+msgstr "W18: グループåã«ä¸æ­£ãªæ–‡å­—ãŒã‚ã‚Šã¾ã™"
+
+msgid "E849: Too many highlight and syntax groups"
+msgstr "E849: ãƒã‚¤ãƒ©ã‚¤ãƒˆã¨æ§‹æ–‡ã‚°ãƒ«ãƒ¼ãƒ—ãŒå¤šéŽãŽã¾ã™"
+
+msgid "E555: at bottom of tag stack"
+msgstr "E555: タグスタックã®æœ«å°¾ã§ã™"
+
+msgid "E556: at top of tag stack"
+msgstr "E556: タグスタックã®å…ˆé ­ã§ã™"
+
+msgid "E425: Cannot go before first matching tag"
+msgstr "E425: 最åˆã®è©²å½“タグを越ãˆã¦æˆ»ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“"
+
+#, c-format
+msgid "E426: tag not found: %s"
+msgstr "E426: ã‚¿ã‚°ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“: %s"
+
+msgid " # pri kind tag"
+msgstr " # pri kind tag"
+
+msgid "file\n"
+msgstr "ファイル\n"
+
+msgid "E427: There is only one matching tag"
+msgstr "E427: 該当タグãŒ1ã¤ã ã‘ã—ã‹ã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E428: Cannot go beyond last matching tag"
+msgstr "E428: 最後ã®è©²å½“タグを越ãˆã¦é€²ã‚€ã“ã¨ã¯ã§ãã¾ã›ã‚“"
+
+#, c-format
+msgid "File \"%s\" does not exist"
+msgstr "ファイル \"%s\" ãŒã‚ã‚Šã¾ã›ã‚“"
+
+#, c-format
+msgid "tag %d of %d%s"
+msgstr "ã‚¿ã‚° %d (å…¨%d%s)"
+
+msgid " or more"
+msgstr " ã‹ãれ以上"
+
+msgid " Using tag with different case!"
+msgstr " ã‚¿ã‚°ã‚’ç•°ãªã‚‹caseã§ä½¿ç”¨ã—ã¾ã™!"
+
+#, c-format
+msgid "E429: File \"%s\" does not exist"
+msgstr "E429: ファイル \"%s\" ãŒã‚ã‚Šã¾ã›ã‚“"
+
+msgid ""
+"\n"
+" # TO tag FROM line in file/text"
+msgstr ""
+"\n"
+" # TO タグ FROM 行 in file/text"
+
+#, c-format
+msgid "Searching tags file %s"
+msgstr "タグファイル %s を検索中"
+
+#, c-format
+msgid "E430: Tag file path truncated for %s\n"
+msgstr "E430: タグファイルã®ãƒ‘ス㌠%s ã«åˆ‡ã‚Šæ¨ã¦ã‚‰ã‚Œã¾ã—ãŸ\n"
+
+msgid "Ignoring long line in tags file"
+msgstr "タグファイル内ã®é•·ã„行を無視ã—ã¾ã™"
+
+#, c-format
+msgid "E431: Format error in tags file \"%s\""
+msgstr "E431: タグファイル \"%s\" ã®ãƒ•ã‚©ãƒ¼ãƒžãƒƒãƒˆã«ã‚¨ãƒ©ãƒ¼ãŒã‚ã‚Šã¾ã™"
+
+#, c-format
+msgid "Before byte %ld"
+msgstr "ç›´å‰ã® %ld ãƒã‚¤ãƒˆ"
+
+#, c-format
+msgid "E432: Tags file not sorted: %s"
+msgstr "E432: タグファイルãŒã‚½ãƒ¼ãƒˆã•ã‚Œã¦ã„ã¾ã›ã‚“: %s"
+
+msgid "E433: No tags file"
+msgstr "E433: タグファイルãŒã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E434: Can't find tag pattern"
+msgstr "E434: タグパターンを見ã¤ã‘られã¾ã›ã‚“"
+
+msgid "E435: Couldn't find tag, just guessing!"
+msgstr "E435: タグを見ã¤ã‘られãªã„ã®ã§å˜ã«æŽ¨æ¸¬ã—ã¾ã™!"
+
+#, c-format
+msgid "Duplicate field name: %s"
+msgstr "é‡è¤‡ã—ãŸãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰å: %s"
+
+msgid "' not known. Available builtin terminals are:"
+msgstr "' ã¯æœªçŸ¥ã§ã™. ç¾è¡Œã®çµ„ã¿è¾¼ã¿ç«¯æœ«ã¯æ¬¡ã®ã¨ãŠã‚Šã§ã™:"
+
+msgid "defaulting to '"
+msgstr "çœç•¥å€¤ã‚’次ã®ã‚ˆã†ã«è¨­å®šã—ã¾ã™ '"
+
+msgid "E557: Cannot open termcap file"
+msgstr "E557: termcapファイルを開ã‘ã¾ã›ã‚“"
+
+msgid "E558: Terminal entry not found in terminfo"
+msgstr "E558: terminfoã«ç«¯æœ«ã‚¨ãƒ³ãƒˆãƒªã‚’見ã¤ã‘られã¾ã›ã‚“"
+
+msgid "E559: Terminal entry not found in termcap"
+msgstr "E559: termcapã«ç«¯æœ«ã‚¨ãƒ³ãƒˆãƒªã‚’見ã¤ã‘られã¾ã›ã‚“"
+
+#, c-format
+msgid "E436: No \"%s\" entry in termcap"
+msgstr "E436: termcapã« \"%s\" ã®ã‚¨ãƒ³ãƒˆãƒªãŒã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E437: terminal capability \"cm\" required"
+msgstr "E437: 端末㫠\"cm\" 機能ãŒå¿…è¦ã§ã™"
+
+msgid ""
+"\n"
+"--- Terminal keys ---"
+msgstr ""
+"\n"
+"--- 端末キー ---"
+
+msgid "Cannot open $VIMRUNTIME/rgb.txt"
+msgstr "$VIMRUNTIME/rgb.txtã‚’é–‹ã‘ã¾ã›ã‚“"
+
+#, c-format
+msgid "Kill job in \"%s\"?"
+msgstr "\"%s\" 内ã®ã‚¸ãƒ§ãƒ–を終了ã—ã¾ã™ã‹?"
+
+msgid "Terminal"
+msgstr "端末"
+
+msgid "Terminal-finished"
+msgstr "端末 (終了)"
+
+msgid "active"
+msgstr "アクティブ"
+
+msgid "running"
+msgstr "実行中"
+
+msgid "finished"
+msgstr "終了"
+
+msgid "E958: Job already finished"
+msgstr "E958: ジョブã¯ã™ã§ã«çµ‚了ã—ã¦ã„ã¾ã™"
+
+#, c-format
+msgid "E953: File exists: %s"
+msgstr "E953: ファイルã¯æ—¢ã«å­˜åœ¨ã—ã¾ã™: %s"
+
+msgid "E955: Not a terminal buffer"
+msgstr "E955: 端末ãƒãƒƒãƒ•ã‚¡ã§ã¯ã‚ã‚Šã¾ã›ã‚“"
+
+msgid "new shell started\n"
+msgstr "æ–°ã—ã„シェルを起動ã—ã¾ã™\n"
+
+msgid "Vim: Error reading input, exiting...\n"
+msgstr "Vim: 入力を読込ã¿ä¸­ã®ã‚¨ãƒ©ãƒ¼ã«ã‚ˆã‚Šçµ‚了ã—ã¾ã™...\n"
+
+msgid "Used CUT_BUFFER0 instead of empty selection"
+msgstr "空ã®é¸æŠžé ˜åŸŸã®ã‹ã‚ã‚Šã«CUT_BUFFER0ãŒä½¿ç”¨ã•ã‚Œã¾ã—ãŸ"
+
+msgid "E881: Line count changed unexpectedly"
+msgstr "E881: 予期ã›ãšè¡Œã‚«ã‚¦ãƒ³ãƒˆãŒå¤‰ã‚ã‚Šã¾ã—ãŸ"
+
+msgid "No undo possible; continue anyway"
+msgstr "å¯èƒ½ãªã‚¢ãƒ³ãƒ‰ã‚¥ã¯ã‚ã‚Šã¾ã›ã‚“: ã¨ã‚Šã‚ãˆãšç¶šã‘ã¾ã™"
+
+#, c-format
+msgid "E828: Cannot open undo file for writing: %s"
+msgstr "E828: 書込ã¿ç”¨ã«ã‚¢ãƒ³ãƒ‰ã‚¥ãƒ•ã‚¡ã‚¤ãƒ«ã‚’é–‹ã‘ã¾ã›ã‚“: %s"
+
+#, c-format
+msgid "E825: Corrupted undo file (%s): %s"
+msgstr "E825: アンドゥファイルãŒå£Šã‚Œã¦ã„ã¾ã™ (%s): %s"
+
+msgid "Cannot write undo file in any directory in 'undodir'"
+msgstr "'undodir'ã®ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã«ã‚¢ãƒ³ãƒ‰ã‚¥ãƒ•ã‚¡ã‚¤ãƒ«ã‚’書ãè¾¼ã‚ã¾ã›ã‚“"
+
+#, c-format
+msgid "Will not overwrite with undo file, cannot read: %s"
+msgstr "アンドゥファイルã¨ã—ã¦èª­ã¿è¾¼ã‚ãªã„ã®ã§ä¸Šæ›¸ãã—ã¾ã›ã‚“: %s"
+
+#, c-format
+msgid "Will not overwrite, this is not an undo file: %s"
+msgstr "アンドゥファイルã§ã¯ãªã„ã®ã§ä¸Šæ›¸ãã—ã¾ã›ã‚“: %s"
+
+msgid "Skipping undo file write, nothing to undo"
+msgstr "対象ãŒãªã„ã®ã§ã‚¢ãƒ³ãƒ‰ã‚¥ãƒ•ã‚¡ã‚¤ãƒ«ã®æ›¸ãè¾¼ã¿ã‚’スキップã—ã¾ã™"
+
+#, c-format
+msgid "Writing undo file: %s"
+msgstr "アンドゥファイル書ãè¾¼ã¿ä¸­: %s"
+
+#, c-format
+msgid "E829: write error in undo file: %s"
+msgstr "E829: アンドゥファイルã®æ›¸ãè¾¼ã¿ã‚¨ãƒ©ãƒ¼ã§ã™: %s"
+
+#, c-format
+msgid "Not reading undo file, owner differs: %s"
+msgstr "オーナーãŒç•°ãªã‚‹ã®ã§ã‚¢ãƒ³ãƒ‰ã‚¥ãƒ•ã‚¡ã‚¤ãƒ«ã‚’読ã¿è¾¼ã¿ã¾ã›ã‚“: %s"
+
+#, c-format
+msgid "Reading undo file: %s"
+msgstr "アンドゥファイル読込中: %s"
+
+#, c-format
+msgid "E822: Cannot open undo file for reading: %s"
+msgstr "E822: アンドゥファイルを読込用ã¨ã—ã¦é–‹ã‘ã¾ã›ã‚“: %s"
+
+#, c-format
+msgid "E823: Not an undo file: %s"
+msgstr "E823: アンドゥファイルã§ã¯ã‚ã‚Šã¾ã›ã‚“: %s"
+
+#, c-format
+msgid "E832: Non-encrypted file has encrypted undo file: %s"
+msgstr "E832: éžæš—å·åŒ–ファイルãŒæš—å·åŒ–ã•ã‚ŒãŸã‚¢ãƒ³ãƒ‰ã‚¥ãƒ•ã‚¡ã‚¤ãƒ«ã‚’使ã£ã¦ã¾ã™: %s"
+
+#, c-format
+msgid "E826: Undo file decryption failed: %s"
+msgstr "E826: æš—å·åŒ–ã•ã‚ŒãŸã‚¢ãƒ³ãƒ‰ã‚¥ãƒ•ã‚¡ã‚¤ãƒ«ã®è§£èª­ã«å¤±æ•—ã—ã¾ã—ãŸ: %s"
+
+#, c-format
+msgid "E827: Undo file is encrypted: %s"
+msgstr "E827: アンドゥファイルãŒæš—å·åŒ–ã•ã‚Œã¦ã„ã¾ã™: %s"
+
+#, c-format
+msgid "E824: Incompatible undo file: %s"
+msgstr "E824: 互æ›æ€§ã®ç„¡ã„アンドゥファイルã§ã™: %s"
+
+msgid "File contents changed, cannot use undo info"
+msgstr "ファイルã®å†…容ãŒå¤‰ã‚ã£ã¦ã„ã‚‹ãŸã‚ã€ã‚¢ãƒ³ãƒ‰ã‚¥æƒ…報を利用ã§ãã¾ã›ã‚“"
+
+#, c-format
+msgid "Finished reading undo file %s"
+msgstr "アンドゥファイル %s ã®å–込を完了"
+
+msgid "Already at oldest change"
+msgstr "æ—¢ã«ä¸€ç•ªå¤ã„変更ã§ã™"
+
+msgid "Already at newest change"
+msgstr "æ—¢ã«ä¸€ç•ªæ–°ã—ã„変更ã§ã™"
+
+#, c-format
+msgid "E830: Undo number %ld not found"
+msgstr "E830: ã‚¢ãƒ³ãƒ‰ã‚¥ç•ªå· %ld ã¯è¦‹ã¤ã‹ã‚Šã¾ã›ã‚“"
+
+msgid "E438: u_undo: line numbers wrong"
+msgstr "E438: u_undo: 行番å·ãŒé–“é•ã£ã¦ã„ã¾ã™"
+
+msgid "more line"
+msgstr "è¡Œ 追加ã—ã¾ã—ãŸ"
+
+msgid "more lines"
+msgstr "è¡Œ 追加ã—ã¾ã—ãŸ"
+
+msgid "line less"
+msgstr "è¡Œ 削除ã—ã¾ã—ãŸ"
+
+msgid "fewer lines"
+msgstr "è¡Œ 削除ã—ã¾ã—ãŸ"
+
+msgid "change"
+msgstr "箇所変更ã—ã¾ã—ãŸ"
+
+msgid "changes"
+msgstr "箇所変更ã—ã¾ã—ãŸ"
+
+#, c-format
+msgid "%ld %s; %s #%ld %s"
+msgstr "%ld %s; %s #%ld %s"
+
+msgid "before"
+msgstr "å‰æ–¹"
+
+msgid "after"
+msgstr "後方"
+
+msgid "Nothing to undo"
+msgstr "アンドゥ対象ãŒã‚ã‚Šã¾ã›ã‚“"
+
+msgid "number changes when saved"
+msgstr "通番 変更数 変更時期 ä¿å­˜æ¸ˆ"
+
+#, c-format
+msgid "%ld second ago"
+msgid_plural "%ld seconds ago"
+msgstr[0] "%ld 秒経éŽã—ã¦ã„ã¾ã™"
+
+msgid "E790: undojoin is not allowed after undo"
+msgstr "E790: undo ã®ç›´å¾Œã« undojoin ã¯ã§ãã¾ã›ã‚“"
+
+msgid "E439: undo list corrupt"
+msgstr "E439: アンドゥリストãŒå£Šã‚Œã¦ã„ã¾ã™"
+
+msgid "E440: undo line missing"
+msgstr "E440: アンドゥ行ãŒã‚ã‚Šã¾ã›ã‚“"
+
+#, c-format
+msgid "E122: Function %s already exists, add ! to replace it"
+msgstr "E122: 関数 %s ã¯å®šç¾©æ¸ˆã§ã™ã€å†å®šç¾©ã™ã‚‹ã«ã¯ ! を追加ã—ã¦ãã ã•ã„"
+
+msgid "E717: Dictionary entry already exists"
+msgstr "E717: 辞書型内ã«ã‚¨ãƒ³ãƒˆãƒªãŒæ—¢ã«å­˜åœ¨ã—ã¾ã™"
+
+msgid "E718: Funcref required"
+msgstr "E718: 関数å‚照型ãŒè¦æ±‚ã•ã‚Œã¾ã™"
+
+#, c-format
+msgid "E130: Unknown function: %s"
+msgstr "E130: 未知ã®é–¢æ•°ã§ã™: %s"
+
+#, c-format
+msgid "E125: Illegal argument: %s"
+msgstr "E125: ä¸æ­£ãªå¼•æ•°ã§ã™: %s"
+
+#, c-format
+msgid "E853: Duplicate argument name: %s"
+msgstr "E853: 引数åãŒé‡è¤‡ã—ã¦ã„ã¾ã™: %s"
+
+#, c-format
+msgid "E740: Too many arguments for function %s"
+msgstr "E740: 関数ã®å¼•æ•°ãŒå¤šéŽãŽã¾ã™: %s"
+
+#, c-format
+msgid "E116: Invalid arguments for function %s"
+msgstr "E116: 関数ã®ç„¡åŠ¹ãªå¼•æ•°ã§ã™: %s"
+
+msgid "E132: Function call depth is higher than 'maxfuncdepth'"
+msgstr "E132: 関数呼出ã®å…¥ã‚Œå­æ•°ãŒ 'maxfuncdepth' を超ãˆã¾ã—ãŸ"
+
+#, c-format
+msgid "calling %s"
+msgstr "%s を実行中ã§ã™"
+
+#, c-format
+msgid "%s aborted"
+msgstr "%s ãŒä¸­æ–­ã•ã‚Œã¾ã—ãŸ"
+
+#, c-format
+msgid "%s returning #%ld"
+msgstr "%s ㌠#%ld ã‚’è¿”ã—ã¾ã—ãŸ"
+
+#, c-format
+msgid "%s returning %s"
+msgstr "%s ㌠%s ã‚’è¿”ã—ã¾ã—ãŸ"
+
+msgid "E699: Too many arguments"
+msgstr "E699: 引数ãŒå¤šéŽãŽã¾ã™"
+
+#, c-format
+msgid "E117: Unknown function: %s"
+msgstr "E117: 未知ã®é–¢æ•°ã§ã™: %s"
+
+#, c-format
+msgid "E933: Function was deleted: %s"
+msgstr "E933: 関数ã¯å‰Šé™¤ã•ã‚Œã¾ã—ãŸ: %s"
+
+#, c-format
+msgid "E119: Not enough arguments for function: %s"
+msgstr "E119: 関数ã®å¼•æ•°ãŒè¶³ã‚Šã¾ã›ã‚“: %s"
+
+#, c-format
+msgid "E120: Using <SID> not in a script context: %s"
+msgstr "E120: スクリプト以外ã§<SID>ãŒä½¿ã‚ã‚Œã¾ã—ãŸ: %s"
+
+#, c-format
+msgid "E725: Calling dict function without Dictionary: %s"
+msgstr "E725: 辞書用関数ãŒå‘¼ã°ã‚Œã¾ã—ãŸãŒè¾žæ›¸ãŒã‚ã‚Šã¾ã›ã‚“: %s"
+
+msgid "E129: Function name required"
+msgstr "E129: 関数åãŒè¦æ±‚ã•ã‚Œã¾ã™"
+
+#, c-format
+msgid "E128: Function name must start with a capital or \"s:\": %s"
+msgstr "E128: 関数åã¯å¤§æ–‡å­—ã‹ \"s:\" ã§å§‹ã¾ã‚‰ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“: %s"
+
+#, c-format
+msgid "E884: Function name cannot contain a colon: %s"
+msgstr "E884: 関数åã«ã¯ã‚³ãƒ­ãƒ³ã¯å«ã‚られã¾ã›ã‚“: %s"
+
+#, c-format
+msgid "E123: Undefined function: %s"
+msgstr "E123: 未定義ã®é–¢æ•°ã§ã™: %s"
+
+#, c-format
+msgid "E124: Missing '(': %s"
+msgstr "E124: '(' ãŒã‚ã‚Šã¾ã›ã‚“: %s"
+
+msgid "E862: Cannot use g: here"
+msgstr "E862: ã“ã“ã§ã¯ g: ã¯ä½¿ãˆã¾ã›ã‚“"
+
+#, c-format
+msgid "E932: Closure function should not be at top level: %s"
+msgstr "E932: クロージャー関数ã¯ãƒˆãƒƒãƒ—レベルã«è¨˜è¿°ã§ãã¾ã›ã‚“: %s"
+
+msgid "E126: Missing :endfunction"
+msgstr "E126: :endfunction ãŒã‚ã‚Šã¾ã›ã‚“"
+
+#, c-format
+msgid "W22: Text found after :endfunction: %s"
+msgstr "W22: :endfunction ã®å¾Œã«æ–‡å­—ãŒã‚ã‚Šã¾ã™: %s"
+
+#, c-format
+msgid "E707: Function name conflicts with variable: %s"
+msgstr "E707: 関数åãŒå¤‰æ•°åã¨è¡çªã—ã¾ã™: %s"
+
+#, c-format
+msgid "E127: Cannot redefine function %s: It is in use"
+msgstr "E127: 関数 %s ã‚’å†å®šç¾©ã§ãã¾ã›ã‚“: 使用中ã§ã™"
+
+#, c-format
+msgid "E746: Function name does not match script file name: %s"
+msgstr "E746: 関数åãŒã‚¹ã‚¯ãƒªãƒ—トã®ãƒ•ã‚¡ã‚¤ãƒ«åã¨ä¸€è‡´ã—ã¾ã›ã‚“: %s"
+
+#, c-format
+msgid "E131: Cannot delete function %s: It is in use"
+msgstr "E131: 関数 %s を削除ã§ãã¾ã›ã‚“: 使用中ã§ã™"
+
+msgid "E133: :return not inside a function"
+msgstr "E133: 関数外㫠:return ãŒã‚ã‚Šã¾ã—ãŸ"
+
+#, c-format
+msgid "E107: Missing parentheses: %s"
+msgstr "E107: カッコ '(' ãŒã‚ã‚Šã¾ã›ã‚“: %s"
+
+#, c-format
+msgid "%s (%s, compiled %s)"
+msgstr "%s (%s, compiled %s)"
+
+msgid ""
+"\n"
+"MS-Windows 64-bit GUI version"
+msgstr ""
+"\n"
+"MS-Windows 64 ビット GUI 版"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit GUI version"
+msgstr ""
+"\n"
+"MS-Windows 32 ビット GUI 版"
+
+msgid " with OLE support"
+msgstr " with OLE サãƒãƒ¼ãƒˆ"
+
+msgid ""
+"\n"
+"MS-Windows 64-bit console version"
+msgstr ""
+"\n"
+"MS-Windows 64 ビット コンソール 版"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit console version"
+msgstr ""
+"\n"
+"MS-Windows 32 ビット コンソール 版"
+
+msgid ""
+"\n"
+"macOS version"
+msgstr ""
+"\n"
+"macOS 版"
+
+msgid ""
+"\n"
+"macOS version w/o darwin feat."
+msgstr ""
+"\n"
+"macOS 版 (darwin ç„¡ã—)"
+
+msgid ""
+"\n"
+"OpenVMS version"
+msgstr ""
+"\n"
+"OpenVMS 版"
+
+msgid ""
+"\n"
+"Included patches: "
+msgstr ""
+"\n"
+"é©ç”¨æ¸ˆãƒ‘ッãƒ: "
+
+msgid ""
+"\n"
+"Extra patches: "
+msgstr ""
+"\n"
+"追加拡張パッãƒ: "
+
+msgid "Modified by "
+msgstr "Modified by "
+
+msgid ""
+"\n"
+"Compiled "
+msgstr ""
+"\n"
+"Compiled "
+
+msgid "by "
+msgstr "by "
+
+msgid ""
+"\n"
+"Huge version "
+msgstr ""
+"\n"
+"Huge 版 "
+
+msgid ""
+"\n"
+"Big version "
+msgstr ""
+"\n"
+"Big 版 "
+
+msgid ""
+"\n"
+"Normal version "
+msgstr ""
+"\n"
+"通常 版 "
+
+msgid ""
+"\n"
+"Small version "
+msgstr ""
+"\n"
+"Small 版 "
+
+msgid ""
+"\n"
+"Tiny version "
+msgstr ""
+"\n"
+"Tiny 版 "
+
+msgid "without GUI."
+msgstr "without GUI."
+
+msgid "with GTK3 GUI."
+msgstr "with GTK3 GUI."
+
+msgid "with GTK2-GNOME GUI."
+msgstr "with GTK2-GNOME GUI."
+
+msgid "with GTK2 GUI."
+msgstr "with GTK2 GUI."
+
+msgid "with X11-Motif GUI."
+msgstr "with X11-Motif GUI."
+
+msgid "with X11-neXtaw GUI."
+msgstr "with X11-neXtaw GUI."
+
+msgid "with X11-Athena GUI."
+msgstr "with X11-Athena GUI."
+
+msgid "with Photon GUI."
+msgstr "with Photon GUI."
+
+msgid "with GUI."
+msgstr "with GUI."
+
+msgid "with Carbon GUI."
+msgstr "with Carbon GUI."
+
+msgid "with Cocoa GUI."
+msgstr "with Cocoa GUI."
+
+msgid " Features included (+) or not (-):\n"
+msgstr " 機能ã®ä¸€è¦§ 有効(+)/無効(-)\n"
+
+msgid " system vimrc file: \""
+msgstr " システム vimrc: \""
+
+msgid " user vimrc file: \""
+msgstr " ユーザー vimrc: \""
+
+msgid " 2nd user vimrc file: \""
+msgstr " 第2ユーザー vimrc: \""
+
+msgid " 3rd user vimrc file: \""
+msgstr " 第3ユーザー vimrc: \""
+
+msgid " user exrc file: \""
+msgstr " ユーザー exrc: \""
+
+msgid " 2nd user exrc file: \""
+msgstr " 第2ユーザー exrc: \""
+
+msgid " system gvimrc file: \""
+msgstr " システム gvimrc: \""
+
+msgid " user gvimrc file: \""
+msgstr " ユーザー gvimrc: \""
+
+msgid "2nd user gvimrc file: \""
+msgstr " 第2ユーザー gvimrc: \""
+
+msgid "3rd user gvimrc file: \""
+msgstr " 第3ユーザー gvimrc: \""
+
+msgid " defaults file: \""
+msgstr " デフォルトファイル: \""
+
+msgid " system menu file: \""
+msgstr " システムメニュー: \""
+
+msgid " fall-back for $VIM: \""
+msgstr " çœç•¥æ™‚ã® $VIM: \""
+
+msgid " f-b for $VIMRUNTIME: \""
+msgstr "çœç•¥æ™‚ã® $VIMRUNTIME: \""
+
+msgid "Compilation: "
+msgstr "コンパイル: "
+
+msgid "Compiler: "
+msgstr "コンパイラ: "
+
+msgid "Linking: "
+msgstr "リンク: "
+
+msgid " DEBUG BUILD"
+msgstr "デãƒãƒƒã‚°ãƒ“ルド"
+
+msgid "VIM - Vi IMproved"
+msgstr "VIM - Vi IMproved"
+
+msgid "version "
+msgstr "version "
+
+msgid "by Bram Moolenaar et al."
+msgstr "by Bram Moolenaar ä»–."
+
+msgid "Vim is open source and freely distributable"
+msgstr "Vim ã¯ã‚ªãƒ¼ãƒ—ンソースã§ã‚り自由ã«é…布å¯èƒ½ã§ã™"
+
+msgid "Help poor children in Uganda!"
+msgstr "ウガンダã®æµã¾ã‚Œãªã„å­ä¾›ãŸã¡ã«æ´åŠ©ã‚’!"
+
+msgid "type :help iccf<Enter> for information "
+msgstr "詳細ãªæƒ…報㯠:help iccf<Enter> "
+
+msgid "type :q<Enter> to exit "
+msgstr "終了ã™ã‚‹ã«ã¯ :q<Enter> "
+
+msgid "type :help<Enter> or <F1> for on-line help"
+msgstr "オンラインヘルプ㯠:help<Enter> ㋠<F1> "
+
+msgid "type :help version8<Enter> for version info"
+msgstr "ãƒãƒ¼ã‚¸ãƒ§ãƒ³æƒ…報㯠:help version8<Enter> "
+
+msgid "Running in Vi compatible mode"
+msgstr "Vi互æ›ãƒ¢ãƒ¼ãƒ‰ã§å‹•ä½œä¸­"
+
+msgid "type :set nocp<Enter> for Vim defaults"
+msgstr "Vim推奨値ã«ã™ã‚‹ã«ã¯ :set nocp<Enter> "
+
+msgid "type :help cp-default<Enter> for info on this"
+msgstr "詳細ãªæƒ…報㯠:help cp-default<Enter>"
+
+msgid "menu Help->Orphans for information "
+msgstr "詳細ã¯ãƒ¡ãƒ‹ãƒ¥ãƒ¼ã® ヘルプ->å­¤å… ã‚’å‚ç…§ã—ã¦ä¸‹ã•ã„ "
+
+msgid "Running modeless, typed text is inserted"
+msgstr "モード無ã§å®Ÿè¡Œä¸­ã€‚タイプã—ãŸæ–‡å­—ãŒæŒ¿å…¥ã•ã‚Œã¾ã™"
+
+msgid "menu Edit->Global Settings->Toggle Insert Mode "
+msgstr "メニュー㮠編集->全体設定->挿入(åˆå¿ƒè€…)モード切替 "
+
+msgid " for two modes "
+msgstr " ã§ãƒ¢ãƒ¼ãƒ‰æœ‰ã« "
+
+msgid "menu Edit->Global Settings->Toggle Vi Compatible"
+msgstr "メニュー㮠編集->全体設定->Vi互æ›ãƒ¢ãƒ¼ãƒ‰åˆ‡æ›¿ "
+
+msgid " for Vim defaults "
+msgstr " ã§Vimã¨ã—ã¦å‹•ä½œ "
+
+msgid "Sponsor Vim development!"
+msgstr "Vimã®é–‹ç™ºã‚’å¿œæ´ã—ã¦ãã ã•ã„!"
+
+msgid "Become a registered Vim user!"
+msgstr "Vimã®ç™»éŒ²ãƒ¦ãƒ¼ã‚¶ãƒ¼ã«ãªã£ã¦ãã ã•ã„!"
+
+msgid "type :help sponsor<Enter> for information "
+msgstr "詳細ãªæƒ…報㯠:help sponsor<Enter> "
+
+msgid "type :help register<Enter> for information "
+msgstr "詳細ãªæƒ…報㯠:help register<Enter> "
+
+msgid "menu Help->Sponsor/Register for information "
+msgstr "詳細ã¯ãƒ¡ãƒ‹ãƒ¥ãƒ¼ã® ヘルプ->スãƒãƒ³ã‚µãƒ¼/登録 ã‚’å‚ç…§ã—ã¦ä¸‹ã•ã„"
+
+msgid "Already only one window"
+msgstr "æ—¢ã«ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã¯1ã¤ã—ã‹ã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E441: There is no preview window"
+msgstr "E441: プレビューウィンドウãŒã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E442: Can't split topleft and botright at the same time"
+msgstr "E442: 左上ã¨å³ä¸‹ã‚’åŒæ™‚ã«åˆ†å‰²ã™ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“"
+
+msgid "E443: Cannot rotate when another window is split"
+msgstr "E443: ä»–ã®ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ãŒåˆ†å‰²ã•ã‚Œã¦ã„る時ã«ã¯é †å›žã§ãã¾ã›ã‚“"
+
+msgid "E444: Cannot close last window"
+msgstr "E444: 最後ã®ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã‚’é–‰ã˜ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“"
+
+msgid "E813: Cannot close autocmd window"
+msgstr "E813: autocmdウィンドウã¯é–‰ã˜ã‚‰ã‚Œã¾ã›ã‚“"
+
+msgid "E814: Cannot close window, only autocmd window would remain"
+msgstr "E814: autocmdウィンドウã—ã‹æ®‹ã‚‰ãªã„ãŸã‚ã€ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã¯é–‰ã˜ã‚‰ã‚Œã¾ã›ã‚“"
+
+msgid "E445: Other window contains changes"
+msgstr "E445: ä»–ã®ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã«ã¯å¤‰æ›´ãŒã‚ã‚Šã¾ã™"
+
+msgid "E446: No file name under cursor"
+msgstr "E446: カーソルã®ä¸‹ã«ãƒ•ã‚¡ã‚¤ãƒ«åãŒã‚ã‚Šã¾ã›ã‚“"
+
+#, c-format
+msgid "E447: Can't find file \"%s\" in path"
+msgstr "E447: pathã«ã¯ \"%s\" ã¨ã„ã†ãƒ•ã‚¡ã‚¤ãƒ«ãŒã‚ã‚Šã¾ã›ã‚“"
+
+#, c-format
+msgid "E799: Invalid ID: %ld (must be greater than or equal to 1)"
+msgstr "E799: 無効㪠ID: %ld (1 以上ã§ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“)"
+
+#, c-format
+msgid "E801: ID already taken: %ld"
+msgstr "E801: ID ã¯ã™ã§ã«åˆ©ç”¨ä¸­ã§ã™: %ld"
+
+msgid "List or number required"
+msgstr "リストã‹æ•°å€¤ãŒå¿…è¦ã§ã™"
+
+#, c-format
+msgid "E802: Invalid ID: %ld (must be greater than or equal to 1)"
+msgstr "E802: 無効㪠ID: %ld (1 以上ã§ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“)"
+
+#, c-format
+msgid "E803: ID not found: %ld"
+msgstr "E803: ID ã¯ã‚ã‚Šã¾ã›ã‚“: %ld"
+
+#, c-format
+msgid "E370: Could not load library %s"
+msgstr "E370: ライブラリ %s をロードã§ãã¾ã›ã‚“ã§ã—ãŸ"
+
+msgid "Sorry, this command is disabled: the Perl library could not be loaded."
+msgstr ""
+"ã“ã®ã‚³ãƒžãƒ³ãƒ‰ã¯ç„¡åŠ¹ã§ã™ã€ã”ã‚ã‚“ãªã•ã„: Perlライブラリをロードã§ãã¾ã›ã‚“ã§ã—ãŸ."
+
+msgid "E299: Perl evaluation forbidden in sandbox without the Safe module"
+msgstr ""
+"E299: サンドボックスã§ã¯ Safe モジュールを使用ã—ãªã„Perlスクリプトã¯ç¦ã˜ã‚‰ã‚Œ"
+"ã¦ã„ã¾ã™"
+
+msgid "Edit with &multiple Vims"
+msgstr "複数ã®Vimã§ç·¨é›†ã™ã‚‹ (&M)"
+
+msgid "Edit with single &Vim"
+msgstr "1ã¤ã®Vimã§ç·¨é›†ã™ã‚‹ (&V)"
+
+msgid "Diff with Vim"
+msgstr "Vimã§å·®åˆ†ã‚’表示ã™ã‚‹"
+
+msgid "Edit with &Vim"
+msgstr "Vimã§ç·¨é›†ã™ã‚‹ (&V)"
+
+msgid "Edit with existing Vim"
+msgstr "起動済ã®Vimã§ç·¨é›†ã™ã‚‹"
+
+msgid "Edit with existing Vim - "
+msgstr "起動済ã®Vimã§ç·¨é›†ã™ã‚‹ - "
+
+msgid "Edits the selected file(s) with Vim"
+msgstr "é¸æŠžã—ãŸãƒ•ã‚¡ã‚¤ãƒ«ã‚’Vimã§ç·¨é›†ã™ã‚‹"
+
+msgid "Error creating process: Check if gvim is in your path!"
+msgstr "プロセスã®ä½œæˆã«å¤±æ•—: gvimãŒç’°å¢ƒå¤‰æ•°PATH上ã«ã‚ã‚‹ã‹ç¢ºèªã—ã¦ãã ã•ã„!"
+
+msgid "gvimext.dll error"
+msgstr "gvimext.dll エラー"
+
+msgid "Path length too long!"
+msgstr "パスãŒé•·éŽãŽã¾ã™!"
+
+msgid "--No lines in buffer--"
+msgstr "--ãƒãƒƒãƒ•ã‚¡ã«è¡ŒãŒã‚ã‚Šã¾ã›ã‚“--"
+
+msgid "E470: Command aborted"
+msgstr "E470: コマンドãŒä¸­æ–­ã•ã‚Œã¾ã—ãŸ"
+
+msgid "E471: Argument required"
+msgstr "E471: 引数ãŒå¿…è¦ã§ã™"
+
+msgid "E10: \\ should be followed by /, ? or &"
+msgstr "E10: \\ ã®å¾Œã¯ / ã‹ ? ã‹ & ã§ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“"
+
+msgid "E11: Invalid in command-line window; <CR> executes, CTRL-C quits"
+msgstr "E11: コマンドラインã§ã¯ç„¡åŠ¹ã§ã™; <CR>ã§å®Ÿè¡Œ, CTRL-Cã§ã‚„ã‚ã‚‹"
+
+msgid "E12: Command not allowed from exrc/vimrc in current dir or tag search"
+msgstr ""
+"E12: ç¾åœ¨ã®ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã‚„タグ検索ã§ã¯exrc/vimrcã®ã‚³ãƒžãƒ³ãƒ‰ã¯è¨±å¯ã•ã‚Œã¾ã›ã‚“"
+
+msgid "E171: Missing :endif"
+msgstr "E171: :endif ãŒã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E600: Missing :endtry"
+msgstr "E600: :endtry ãŒã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E170: Missing :endwhile"
+msgstr "E170: :endwhile ãŒã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E170: Missing :endfor"
+msgstr "E170: :endfor ãŒã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E588: :endwhile without :while"
+msgstr "E588: :while ã®ãªã„ :endwhile ãŒã‚ã‚Šã¾ã™"
+
+msgid "E588: :endfor without :for"
+msgstr "E588: :endfor ã®ãªã„ :for ãŒã‚ã‚Šã¾ã™"
+
+msgid "E13: File exists (add ! to override)"
+msgstr "E13: ファイルãŒå­˜åœ¨ã—ã¾ã™ (! を追加ã§ä¸Šæ›¸)"
+
+msgid "E472: Command failed"
+msgstr "E472: コマンドãŒå¤±æ•—ã—ã¾ã—ãŸ"
+
+#, c-format
+msgid "E234: Unknown fontset: %s"
+msgstr "E234: 未知ã®ãƒ•ã‚©ãƒ³ãƒˆã‚»ãƒƒãƒˆ: %s"
+
+#, c-format
+msgid "E235: Unknown font: %s"
+msgstr "E235: 未知ã®ãƒ•ã‚©ãƒ³ãƒˆ: %s"
+
+#, c-format
+msgid "E236: Font \"%s\" is not fixed-width"
+msgstr "E236: フォント \"%s\" ã¯å›ºå®šå¹…ã§ã¯ã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E473: Internal error"
+msgstr "E473: 内部エラーã§ã™"
+
+#, c-format
+msgid "E685: Internal error: %s"
+msgstr "E685: 内部エラーã§ã™: %s"
+
+msgid "Interrupted"
+msgstr "割込ã¾ã‚Œã¾ã—ãŸ"
+
+msgid "E14: Invalid address"
+msgstr "E14: 無効ãªã‚¢ãƒ‰ãƒ¬ã‚¹ã§ã™"
+
+msgid "E474: Invalid argument"
+msgstr "E474: 無効ãªå¼•æ•°ã§ã™"
+
+#, c-format
+msgid "E475: Invalid argument: %s"
+msgstr "E475: 無効ãªå¼•æ•°ã§ã™: %s"
+
+#, c-format
+msgid "E475: Invalid value for argument %s"
+msgstr "E475: 引数 %s ã«å¯¾ã—ã¦ç„¡åŠ¹ãªå€¤ã§ã™"
+
+#, c-format
+msgid "E475: Invalid value for argument %s: %s"
+msgstr "E475: 引数 %s ã«å¯¾ã—ã¦ç„¡åŠ¹ãªå€¤ã§ã™: %s"
+
+#, c-format
+msgid "E15: Invalid expression: %s"
+msgstr "E15: 無効ãªå¼ã§ã™: %s"
+
+msgid "E16: Invalid range"
+msgstr "E16: 無効ãªç¯„囲ã§ã™"
+
+msgid "E476: Invalid command"
+msgstr "E476: 無効ãªã‚³ãƒžãƒ³ãƒ‰ã§ã™"
+
+#, c-format
+msgid "E17: \"%s\" is a directory"
+msgstr "E17: \"%s\" ã¯ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã§ã™"
+
+#, c-format
+msgid "E364: Library call failed for \"%s()\""
+msgstr "E364: \"%s\"() ã®ãƒ©ã‚¤ãƒ–ラリ呼出ã«å¤±æ•—ã—ã¾ã—ãŸ"
+
+msgid "E667: Fsync failed"
+msgstr "E667: fsync ã«å¤±æ•—ã—ã¾ã—ãŸ"
+
+#, c-format
+msgid "E448: Could not load library function %s"
+msgstr "E448: ライブラリã®é–¢æ•° %s をロードã§ãã¾ã›ã‚“ã§ã—ãŸ"
+
+msgid "E19: Mark has invalid line number"
+msgstr "E19: マークã«ç„¡åŠ¹ãªè¡Œç•ªå·ãŒæŒ‡å®šã•ã‚Œã¦ã„ã¾ã—ãŸ"
+
+msgid "E20: Mark not set"
+msgstr "E20: マークã¯è¨­å®šã•ã‚Œã¦ã„ã¾ã›ã‚“"
+
+msgid "E21: Cannot make changes, 'modifiable' is off"
+msgstr "E21: 'modifiable' ãŒã‚ªãƒ•ãªã®ã§ã€å¤‰æ›´ã§ãã¾ã›ã‚“"
+
+msgid "E22: Scripts nested too deep"
+msgstr "E22: スクリプトã®å…¥ã‚Œå­ãŒæ·±éŽãŽã¾ã™"
+
+msgid "E23: No alternate file"
+msgstr "E23: 副ファイルã¯ã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E24: No such abbreviation"
+msgstr "E24: ãã®ã‚ˆã†ãªçŸ­ç¸®å…¥åŠ›ã¯ã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E477: No ! allowed"
+msgstr "E477: ! ã¯è¨±å¯ã•ã‚Œã¦ã„ã¾ã›ã‚“"
+
+msgid "E25: GUI cannot be used: Not enabled at compile time"
+msgstr "E25: GUIã¯ä½¿ç”¨ä¸å¯èƒ½ã§ã™: コンパイル時ã«ç„¡åŠ¹ã«ã•ã‚Œã¦ã„ã¾ã™"
+
+msgid "E26: Hebrew cannot be used: Not enabled at compile time\n"
+msgstr "E26: ヘブライ語ã¯ä½¿ç”¨ä¸å¯èƒ½ã§ã™: コンパイル時ã«ç„¡åŠ¹ã«ã•ã‚Œã¦ã„ã¾ã™\n"
+
+msgid "E27: Farsi cannot be used: Not enabled at compile time\n"
+msgstr "E27: ペルシア語ã¯ä½¿ç”¨ä¸å¯èƒ½ã§ã™: コンパイル時ã«ç„¡åŠ¹ã«ã•ã‚Œã¦ã„ã¾ã™\n"
+
+msgid "E800: Arabic cannot be used: Not enabled at compile time\n"
+msgstr "E800: アラビア語ã¯ä½¿ç”¨ä¸å¯èƒ½ã§ã™: コンパイル時ã«ç„¡åŠ¹ã«ã•ã‚Œã¦ã„ã¾ã™\n"
+
+#, c-format
+msgid "E28: No such highlight group name: %s"
+msgstr "E28: ãã®ã‚ˆã†ãªåã®ãƒã‚¤ãƒ©ã‚¤ãƒˆã‚°ãƒ«ãƒ¼ãƒ—ã¯ã‚ã‚Šã¾ã›ã‚“: %s"
+
+msgid "E29: No inserted text yet"
+msgstr "E29: ã¾ã ãƒ†ã‚­ã‚¹ãƒˆãŒæŒ¿å…¥ã•ã‚Œã¦ã„ã¾ã›ã‚“"
+
+msgid "E30: No previous command line"
+msgstr "E30: 以å‰ã«ã‚³ãƒžãƒ³ãƒ‰è¡ŒãŒã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E31: No such mapping"
+msgstr "E31: ãã®ã‚ˆã†ãªãƒžãƒƒãƒ”ングã¯ã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E479: No match"
+msgstr "E479: 該当ã¯ã‚ã‚Šã¾ã›ã‚“"
+
+#, c-format
+msgid "E480: No match: %s"
+msgstr "E480: 該当ã¯ã‚ã‚Šã¾ã›ã‚“: %s"
+
+msgid "E32: No file name"
+msgstr "E32: ファイルåãŒã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E33: No previous substitute regular expression"
+msgstr "E33: æ­£è¦è¡¨ç¾ç½®æ›ãŒã¾ã å®Ÿè¡Œã•ã‚Œã¦ã„ã¾ã›ã‚“"
+
+msgid "E34: No previous command"
+msgstr "E34: コマンドãŒã¾ã å®Ÿè¡Œã•ã‚Œã¦ã„ã¾ã›ã‚“"
+
+msgid "E35: No previous regular expression"
+msgstr "E35: æ­£è¦è¡¨ç¾ãŒã¾ã å®Ÿè¡Œã•ã‚Œã¦ã„ã¾ã›ã‚“"
+
+msgid "E481: No range allowed"
+msgstr "E481: 範囲指定ã¯è¨±å¯ã•ã‚Œã¦ã„ã¾ã›ã‚“"
+
+msgid "E36: Not enough room"
+msgstr "E36: ウィンドウã«å分ãªé«˜ã•ã‚‚ã—ãã¯å¹…ãŒã‚ã‚Šã¾ã›ã‚“"
+
+#, c-format
+msgid "E247: no registered server named \"%s\""
+msgstr "E247: %s ã¨ã„ã†åå‰ã®ç™»éŒ²ã•ã‚ŒãŸã‚µãƒ¼ãƒãƒ¼ã¯ã‚ã‚Šã¾ã›ã‚“"
+
+#, c-format
+msgid "E482: Can't create file %s"
+msgstr "E482: ファイル %s を作æˆã§ãã¾ã›ã‚“"
+
+msgid "E483: Can't get temp file name"
+msgstr "E483: 一時ファイルã®åå‰ã‚’å–å¾—ã§ãã¾ã›ã‚“"
+
+#, c-format
+msgid "E484: Can't open file %s"
+msgstr "E484: ファイル \"%s\" ã‚’é–‹ã‘ã¾ã›ã‚“"
+
+#, c-format
+msgid "E485: Can't read file %s"
+msgstr "E485: ファイル %s を読込ã‚ã¾ã›ã‚“"
+
+msgid "E38: Null argument"
+msgstr "E38: 引数ãŒç©ºã§ã™"
+
+msgid "E39: Number expected"
+msgstr "E39: 数値ãŒè¦æ±‚ã•ã‚Œã¦ã„ã¾ã™"
+
+#, c-format
+msgid "E40: Can't open errorfile %s"
+msgstr "E40: エラーファイル %s ã‚’é–‹ã‘ã¾ã›ã‚“"
+
+msgid "E233: cannot open display"
+msgstr "E233: ディスプレイを開ã‘ã¾ã›ã‚“"
+
+msgid "E41: Out of memory!"
+msgstr "E41: メモリãŒå°½ãæžœã¦ã¾ã—ãŸ!"
+
+msgid "Pattern not found"
+msgstr "パターンã¯è¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸ"
+
+#, c-format
+msgid "E486: Pattern not found: %s"
+msgstr "E486: パターンã¯è¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸ: %s"
+
+msgid "E487: Argument must be positive"
+msgstr "E487: 引数ã¯æ­£ã®å€¤ã§ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“"
+
+msgid "E459: Cannot go back to previous directory"
+msgstr "E459: å‰ã®ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã«æˆ»ã‚Œã¾ã›ã‚“"
+
+msgid "E42: No Errors"
+msgstr "E42: エラーã¯ã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E776: No location list"
+msgstr "E776: ロケーションリストã¯ã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E43: Damaged match string"
+msgstr "E43: 該当文字列ãŒç ´æã—ã¦ã„ã¾ã™"
+
+msgid "E44: Corrupted regexp program"
+msgstr "E44: ä¸æ­£ãªæ­£è¦è¡¨ç¾ãƒ—ログラムã§ã™"
+
+msgid "E45: 'readonly' option is set (add ! to override)"
+msgstr "E45: 'readonly' オプションãŒè¨­å®šã•ã‚Œã¦ã„ã¾ã™ (! を追加ã§ä¸Šæ›¸ã)"
+
+#, c-format
+msgid "E46: Cannot change read-only variable \"%s\""
+msgstr "E46: 読å–専用変数 \"%s\" ã«ã¯å€¤ã‚’設定ã§ãã¾ã›ã‚“"
+
+#, c-format
+msgid "E794: Cannot set variable in the sandbox: \"%s\""
+msgstr "E794: サンドボックスã§ã¯å¤‰æ•° \"%s\" ã«å€¤ã‚’設定ã§ãã¾ã›ã‚“"
+
+msgid "E713: Cannot use empty key for Dictionary"
+msgstr "E713: 辞書型ã«ç©ºã®ã‚­ãƒ¼ã‚’使ã†ã“ã¨ã¯ã§ãã¾ã›ã‚“"
+
+msgid "E715: Dictionary required"
+msgstr "E715: 辞書型ãŒå¿…è¦ã§ã™"
+
+#, c-format
+msgid "E684: list index out of range: %ld"
+msgstr "E684: リストã®ã‚¤ãƒ³ãƒ‡ãƒƒã‚¯ã‚¹ãŒç¯„囲外ã§ã™: %ld"
+
+#, c-format
+msgid "E118: Too many arguments for function: %s"
+msgstr "E118: 関数ã®å¼•æ•°ãŒå¤šéŽãŽã¾ã™: %s"
+
+#, c-format
+msgid "E716: Key not present in Dictionary: %s"
+msgstr "E716: 辞書型ã«ã‚­ãƒ¼ãŒå­˜åœ¨ã—ã¾ã›ã‚“: %s"
+
+msgid "E714: List required"
+msgstr "E714: リスト型ãŒå¿…è¦ã§ã™"
+
+#, c-format
+msgid "E712: Argument of %s must be a List or Dictionary"
+msgstr "E712: %s ã®å¼•æ•°ã¯ãƒªã‚¹ãƒˆåž‹ã¾ãŸã¯è¾žæ›¸åž‹ã§ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“"
+
+msgid "E47: Error while reading errorfile"
+msgstr "E47: エラーファイルã®èª­è¾¼ä¸­ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸ"
+
+msgid "E48: Not allowed in sandbox"
+msgstr "E48: サンドボックスã§ã¯è¨±ã•ã‚Œã¾ã›ã‚“"
+
+msgid "E523: Not allowed here"
+msgstr "E523: ã“ã“ã§ã¯è¨±å¯ã•ã‚Œã¾ã›ã‚“"
+
+msgid "E359: Screen mode setting not supported"
+msgstr "E359: スクリーンモードã®è¨­å®šã«ã¯å¯¾å¿œã—ã¦ã„ã¾ã›ã‚“"
+
+msgid "E49: Invalid scroll size"
+msgstr "E49: 無効ãªã‚¹ã‚¯ãƒ­ãƒ¼ãƒ«é‡ã§ã™"
+
+msgid "E91: 'shell' option is empty"
+msgstr "E91: 'shell' オプションãŒç©ºã§ã™"
+
+msgid "E255: Couldn't read in sign data!"
+msgstr "E255: sign ã®ãƒ‡ãƒ¼ã‚¿ã‚’読込ã‚ã¾ã›ã‚“ã§ã—ãŸ"
+
+msgid "E72: Close error on swap file"
+msgstr "E72: スワップファイルã®ã‚¯ãƒ­ãƒ¼ã‚ºæ™‚エラーã§ã™"
+
+msgid "E73: tag stack empty"
+msgstr "E73: タグスタックãŒç©ºã§ã™"
+
+msgid "E74: Command too complex"
+msgstr "E74: コマンドãŒè¤‡é›‘éŽãŽã¾ã™"
+
+msgid "E75: Name too long"
+msgstr "E75: åå‰ãŒé•·éŽãŽã¾ã™"
+
+msgid "E76: Too many ["
+msgstr "E76: [ ãŒå¤šéŽãŽã¾ã™"
+
+msgid "E77: Too many file names"
+msgstr "E77: ファイルåãŒå¤šéŽãŽã¾ã™"
+
+msgid "E488: Trailing characters"
+msgstr "E488: 余分ãªæ–‡å­—ãŒå¾Œã‚ã«ã‚ã‚Šã¾ã™"
+
+msgid "E78: Unknown mark"
+msgstr "E78: 未知ã®ãƒžãƒ¼ã‚¯"
+
+msgid "E79: Cannot expand wildcards"
+msgstr "E79: ワイルドカードを展開ã§ãã¾ã›ã‚“"
+
+msgid "E591: 'winheight' cannot be smaller than 'winminheight'"
+msgstr "E591: 'winheight' 㯠'winminheight' よりå°ã•ãã§ãã¾ã›ã‚“"
+
+msgid "E592: 'winwidth' cannot be smaller than 'winminwidth'"
+msgstr "E592: 'winwidth' 㯠'winminwidth' よりå°ã•ãã§ãã¾ã›ã‚“"
+
+msgid "E80: Error while writing"
+msgstr "E80: 書込ã¿ä¸­ã®ã‚¨ãƒ©ãƒ¼"
+
+msgid "E939: Positive count required"
+msgstr "E939: æ­£ã®ã‚«ã‚¦ãƒ³ãƒˆãŒå¿…è¦ã§ã™"
+
+msgid "E81: Using <SID> not in a script context"
+msgstr "E81: スクリプト以外ã§<SID>ãŒä½¿ã‚ã‚Œã¾ã—ãŸ"
+
+msgid "E449: Invalid expression received"
+msgstr "E449: 無効ãªå¼ã‚’å—ã‘å–ã‚Šã¾ã—ãŸ"
+
+msgid "E463: Region is guarded, cannot modify"
+msgstr "E463: 領域ãŒä¿è­·ã•ã‚Œã¦ã„ã‚‹ã®ã§ã€å¤‰æ›´ã§ãã¾ã›ã‚“"
+
+msgid "E744: NetBeans does not allow changes in read-only files"
+msgstr "E744: NetBeans ã¯èª­è¾¼å°‚用ファイルを変更ã™ã‚‹ã“ã¨ã‚’許ã—ã¾ã›ã‚“"
+
+msgid "E363: pattern uses more memory than 'maxmempattern'"
+msgstr "E363: パターン㌠'maxmempattern' 以上ã®ãƒ¡ãƒ¢ãƒªã‚’使用ã—ã¾ã™"
+
+msgid "E749: empty buffer"
+msgstr "E749: ãƒãƒƒãƒ•ã‚¡ãŒç©ºã§ã™"
+
+#, c-format
+msgid "E86: Buffer %ld does not exist"
+msgstr "E86: ãƒãƒƒãƒ•ã‚¡ %ld ã¯ã‚ã‚Šã¾ã›ã‚“"
+
+msgid "E682: Invalid search pattern or delimiter"
+msgstr "E682: 検索パターンã‹åŒºåˆ‡ã‚Šè¨˜å·ãŒä¸æ­£ã§ã™"
+
+msgid "E139: File is loaded in another buffer"
+msgstr "E139: åŒã˜åå‰ã®ãƒ•ã‚¡ã‚¤ãƒ«ãŒä»–ã®ãƒãƒƒãƒ•ã‚¡ã§èª­è¾¼ã¾ã‚Œã¦ã„ã¾ã™"
+
+#, c-format
+msgid "E764: Option '%s' is not set"
+msgstr "E764: オプション '%s' ã¯è¨­å®šã•ã‚Œã¦ã„ã¾ã›ã‚“"
+
+msgid "E850: Invalid register name"
+msgstr "E850: 無効ãªãƒ¬ã‚¸ã‚¹ã‚¿åã§ã™"
+
+#, c-format
+msgid "E919: Directory not found in '%s': \"%s\""
+msgstr "E919: ディレクトリ㌠'%s' ã®ä¸­ã«ã‚ã‚Šã¾ã›ã‚“: \"%s\""
+
+msgid "E952: Autocommand caused recursive behavior"
+msgstr "E952: AutocommandãŒå†å¸°ã‚’引ãèµ·ã“ã—ã¾ã—ãŸ"
+
+msgid "search hit TOP, continuing at BOTTOM"
+msgstr "上ã¾ã§æ¤œç´¢ã—ãŸã®ã§ä¸‹ã«æˆ»ã‚Šã¾ã™"
+
+msgid "search hit BOTTOM, continuing at TOP"
+msgstr "下ã¾ã§æ¤œç´¢ã—ãŸã®ã§ä¸Šã«æˆ»ã‚Šã¾ã™"
+
+#, c-format
+msgid "Need encryption key for \"%s\""
+msgstr "æš—å·ã‚­ãƒ¼ãŒå¿…è¦ã§ã™: \"%s\""
+
+msgid "empty keys are not allowed"
+msgstr "空ã®ã‚­ãƒ¼ã¯è¨±å¯ã•ã‚Œã¦ã„ã¾ã›ã‚“"
+
+msgid "dictionary is locked"
+msgstr "辞書ã¯ãƒ­ãƒƒã‚¯ã•ã‚Œã¦ã„ã¾ã™"
+
+msgid "list is locked"
+msgstr "リストã¯ãƒ­ãƒƒã‚¯ã•ã‚Œã¦ã„ã¾ã™"
+
+#, c-format
+msgid "failed to add key '%s' to dictionary"
+msgstr "辞書ã«ã‚­ãƒ¼ '%s' を追加ã™ã‚‹ã®ã«å¤±æ•—ã—ã¾ã—ãŸ"
+
+#, c-format
+msgid "index must be int or slice, not %s"
+msgstr "インデックス㯠%s ã§ã¯ãªãæ•´æ•°ã‹ã‚¹ãƒ©ã‚¤ã‚¹ã«ã—ã¦ãã ã•ã„"
+
+#, c-format
+msgid "expected str() or unicode() instance, but got %s"
+msgstr "str() ã‚‚ã—ã㯠unicode() ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ãŒæœŸå¾…ã•ã‚Œã¦ã„ã‚‹ã®ã« %s ã§ã—ãŸ"
+
+#, c-format
+msgid "expected bytes() or str() instance, but got %s"
+msgstr "bytes() ã‚‚ã—ã㯠str() ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ãŒæœŸå¾…ã•ã‚Œã¦ã„ã‚‹ã®ã« %s ã§ã—ãŸ"
+
+#, c-format
+msgid ""
+"expected int(), long() or something supporting coercing to long(), but got %s"
+msgstr "long() ã‹ãã‚Œã¸å¤‰æ›å¯èƒ½ãªã‚‚ã®ãŒæœŸå¾…ã•ã‚Œã¦ã„ã‚‹ã®ã« %s ã§ã—ãŸ"
+
+#, c-format
+msgid "expected int() or something supporting coercing to int(), but got %s"
+msgstr "int() ã‹ãã‚Œã¸å¤‰æ›å¯èƒ½ãªã‚‚ã®ãŒæœŸå¾…ã•ã‚Œã¦ã„ã‚‹ã®ã« %s ã§ã—ãŸ"
+
+msgid "value is too large to fit into C int type"
+msgstr "C言語㮠int åž‹ã¨ã—ã¦ã¯å€¤ãŒå¤§ãéŽãŽã¾ã™"
+
+msgid "value is too small to fit into C int type"
+msgstr "C言語㮠int åž‹ã¨ã—ã¦ã¯å€¤ãŒå°ã•éŽãŽã¾ã™"
+
+msgid "number must be greater than zero"
+msgstr "数値㯠0 より大ãããªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“"
+
+msgid "number must be greater or equal to zero"
+msgstr "数値㯠0 ã‹ãれ以上ã§ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“"
+
+msgid "can't delete OutputObject attributes"
+msgstr "OutputObject属性を消ã›ã¾ã›ã‚“"
+
+#, c-format
+msgid "invalid attribute: %s"
+msgstr "無効ãªå±žæ€§ã§ã™: %s"
+
+msgid "E264: Python: Error initialising I/O objects"
+msgstr "E264: Python: I/Oオブジェクトã®åˆæœŸåŒ–エラー"
+
+msgid "failed to change directory"
+msgstr "辞書ã®å¤‰æ›´ã«å¤±æ•—ã—ã¾ã—ãŸ"
+
+#, c-format
+msgid "expected 3-tuple as imp.find_module() result, but got %s"
+msgstr "imp.find_module() ㌠%s ã‚’è¿”ã—ã¾ã—㟠(期待値: 3 è¦ç´ ã®ã‚¿ãƒ—ル)"
+
+#, c-format
+msgid "expected 3-tuple as imp.find_module() result, but got tuple of size %d"
+msgstr "imp.find_module() ㌠%d è¦ç´ ã®ã‚¿ãƒ—ルを返ã—ã¾ã—㟠(期待値: 3)"
+
+msgid "internal error: imp.find_module returned tuple with NULL"
+msgstr "内部エラー: imp.find_module ㌠NULL ã‚’å«ã‚€ã‚¿ãƒ—ルを返ã—ã¾ã—ãŸ"
+
+msgid "cannot delete vim.Dictionary attributes"
+msgstr "vim.Dictionary属性ã¯æ¶ˆã›ã¾ã›ã‚“"
+
+msgid "cannot modify fixed dictionary"
+msgstr "固定ã•ã‚ŒãŸè¾žæ›¸ã¯å¤‰æ›´ã§ãã¾ã›ã‚“"
+
+#, c-format
+msgid "cannot set attribute %s"
+msgstr "属性 %s ã¯è¨­å®šã§ãã¾ã›ã‚“"
+
+msgid "hashtab changed during iteration"
+msgstr "イテレーション中㫠hashtab ãŒå¤‰æ›´ã•ã‚Œã¾ã—ãŸ"
+
+#, c-format
+msgid "expected sequence element of size 2, but got sequence of size %d"
+msgstr "シーケンスã®è¦ç´ æ•°ã«ã¯ 2 ãŒæœŸå¾…ã•ã‚Œã¦ã„ã¾ã—ãŸãŒ %d ã§ã—ãŸ"
+
+msgid "list constructor does not accept keyword arguments"
+msgstr "リストã®ã‚³ãƒ³ã‚¹ãƒˆãƒ©ã‚¯ã‚¿ã¯ã‚­ãƒ¼ãƒ¯ãƒ¼ãƒ‰å¼•æ•°ã‚’å—ã‘付ã‘ã¾ã›ã‚“"
+
+msgid "list index out of range"
+msgstr "リスト範囲外ã®ã‚¤ãƒ³ãƒ‡ãƒƒã‚¯ã‚¹ã§ã™"
+
+#, c-format
+msgid "internal error: failed to get vim list item %d"
+msgstr "内部エラー: vimã®ãƒªã‚¹ãƒˆè¦ç´  %d ã®å–å¾—ã«å¤±æ•—ã—ã¾ã—ãŸ"
+
+msgid "slice step cannot be zero"
+msgstr "スライスã®ã‚¹ãƒ†ãƒƒãƒ—ã« 0 ã¯æŒ‡å®šã§ãã¾ã›ã‚“"
+
+#, c-format
+msgid "attempt to assign sequence of size greater than %d to extended slice"
+msgstr "é•·ã• %d ã®æ‹¡å¼µã‚¹ãƒ©ã‚¤ã‚¹ã«ã€ã‚ˆã‚Šé•·ã„スライスを割り当ã¦ã‚ˆã†ã¨ã—ã¾ã—ãŸ"
+
+#, c-format
+msgid "internal error: no vim list item %d"
+msgstr "内部エラー: vimã®ãƒªã‚¹ãƒˆè¦ç´  %d ã¯ã‚ã‚Šã¾ã›ã‚“"
+
+msgid "internal error: not enough list items"
+msgstr "内部エラー: リストã«å分ãªè¦ç´ ãŒã‚ã‚Šã¾ã›ã‚“"
+
+msgid "internal error: failed to add item to list"
+msgstr "内部エラー: リストã¸ã®è¦ç´ è¿½åŠ ã«å¤±æ•—ã—ã¾ã—ãŸ"
+
+#, c-format
+msgid "attempt to assign sequence of size %d to extended slice of size %d"
+msgstr "é•·ã• %d ã®ã‚¹ãƒ©ã‚¤ã‚¹ã‚’ %d ã®æ‹¡å¼µã‚¹ãƒ©ã‚¤ã‚¹ã«å‰²ã‚Šå½“ã¦ã‚ˆã†ã¨ã—ã¾ã—ãŸ"
+
+msgid "failed to add item to list"
+msgstr "リストã¸ã®è¦ç´ è¿½åŠ ã«å¤±æ•—ã—ã¾ã—ãŸ"
+
+msgid "cannot delete vim.List attributes"
+msgstr "vim.List 属性ã¯æ¶ˆã›ã¾ã›ã‚“"
+
+msgid "cannot modify fixed list"
+msgstr "固定ã•ã‚ŒãŸãƒªã‚¹ãƒˆã¯å¤‰æ›´ã§ãã¾ã›ã‚“"
+
+#, c-format
+msgid "unnamed function %s does not exist"
+msgstr "ç„¡å関数 %s ã¯å­˜åœ¨ã—ã¾ã›ã‚“"
+
+#, c-format
+msgid "function %s does not exist"
+msgstr "関数 %s ãŒã‚ã‚Šã¾ã›ã‚“"
+
+#, c-format
+msgid "failed to run function %s"
+msgstr "関数 %s ã®å®Ÿè¡Œã«å¤±æ•—ã—ã¾ã—ãŸ"
+
+msgid "unable to get option value"
+msgstr "オプションã®å€¤ã¯å–å¾—ã§ãã¾ã›ã‚“"
+
+msgid "internal error: unknown option type"
+msgstr "内部エラー: 未知ã®ã‚ªãƒ—ション型ã§ã™"
+
+msgid "problem while switching windows"
+msgstr "ウィンドウを切æ›ä¸­ã«å•é¡ŒãŒç™ºç”Ÿã—ã¾ã—ãŸ"
+
+#, c-format
+msgid "unable to unset global option %s"
+msgstr "グローãƒãƒ«ã‚ªãƒ—ション %s ã®è¨­å®šè§£é™¤ã¯ã§ãã¾ã›ã‚“"
+
+#, c-format
+msgid "unable to unset option %s which does not have global value"
+msgstr "グローãƒãƒ«ãªå€¤ã®ç„¡ã„オプション %s ã®è¨­å®šè§£é™¤ã¯ã§ãã¾ã›ã‚“"
+
+msgid "attempt to refer to deleted tab page"
+msgstr "削除ã•ã‚ŒãŸã‚¿ãƒ–ã‚’å‚ç…§ã—よã†ã¨ã—ã¾ã—ãŸ"
+
+msgid "no such tab page"
+msgstr "ãã®ã‚ˆã†ãªã‚¿ãƒ–ページã¯ã‚ã‚Šã¾ã›ã‚“"
+
+msgid "attempt to refer to deleted window"
+msgstr "削除ã•ã‚ŒãŸã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã‚’å‚ç…§ã—よã†ã¨ã—ã¾ã—ãŸ"
+
+msgid "readonly attribute: buffer"
+msgstr "読込専用属性: ãƒãƒƒãƒ•ã‚¡ãƒ¼"
+
+msgid "cursor position outside buffer"
+msgstr "カーソルä½ç½®ãŒãƒãƒƒãƒ•ã‚¡ã®å¤–å´ã§ã™"
+
+msgid "no such window"
+msgstr "ãã®ã‚ˆã†ãªã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã¯ã‚ã‚Šã¾ã›ã‚“"
+
+msgid "attempt to refer to deleted buffer"
+msgstr "削除ã•ã‚ŒãŸãƒãƒƒãƒ•ã‚¡ã‚’å‚ç…§ã—よã†ã¨ã—ã¾ã—ãŸ"
+
+msgid "failed to rename buffer"
+msgstr "ãƒãƒƒãƒ•ã‚¡åã®å¤‰æ›´ã«å¤±æ•—ã—ã¾ã—ãŸ"
+
+msgid "mark name must be a single character"
+msgstr "マークåã¯1文字ã®ã‚¢ãƒ«ãƒ•ã‚¡ãƒ™ãƒƒãƒˆã§ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“"
+
+#, c-format
+msgid "expected vim.Buffer object, but got %s"
+msgstr "vim.BufferオブジェクトãŒæœŸå¾…ã•ã‚Œã¦ã„ã‚‹ã®ã« %s ã§ã—ãŸ"
+
+#, c-format
+msgid "failed to switch to buffer %d"
+msgstr "指定ã•ã‚ŒãŸãƒãƒƒãƒ•ã‚¡ %d ã¸ã®åˆ‡ã‚Šæ›¿ãˆã«å¤±æ•—ã—ã¾ã—ãŸ"
+
+#, c-format
+msgid "expected vim.Window object, but got %s"
+msgstr "vim.WindowオブジェクトãŒæœŸå¾…ã•ã‚Œã¦ã„ã‚‹ã®ã« %s ã§ã—ãŸ"
+
+msgid "failed to find window in the current tab page"
+msgstr "ç¾åœ¨ã®ã‚¿ãƒ–ã«ã¯æŒ‡å®šã•ã‚ŒãŸã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ãŒã‚ã‚Šã¾ã›ã‚“ã§ã—ãŸ"
+
+msgid "did not switch to the specified window"
+msgstr "指定ã•ã‚ŒãŸã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã«åˆ‡ã‚Šæ›¿ãˆã¾ã›ã‚“ã§ã—ãŸ"
+
+#, c-format
+msgid "expected vim.TabPage object, but got %s"
+msgstr "vim.TabPageオブジェクトãŒæœŸå¾…ã•ã‚Œã¦ã„ã‚‹ã®ã« %s ã§ã—ãŸ"
+
+msgid "did not switch to the specified tab page"
+msgstr "指定ã•ã‚ŒãŸã‚¿ãƒ–ページã«åˆ‡ã‚Šæ›¿ãˆã¾ã›ã‚“ã§ã—ãŸ"
+
+msgid "failed to run the code"
+msgstr "コードã®å®Ÿè¡Œã«å¤±æ•—ã—ã¾ã—ãŸ"
+
+msgid "E858: Eval did not return a valid python object"
+msgstr "E858: å¼è©•ä¾¡ã¯æœ‰åŠ¹ãªpythonオブジェクトを返ã—ã¾ã›ã‚“ã§ã—ãŸ"
+
+msgid "E859: Failed to convert returned python object to vim value"
+msgstr "E859: è¿”ã•ã‚ŒãŸpythonオブジェクトをvimã®å€¤ã«å¤‰æ›ã§ãã¾ã›ã‚“ã§ã—ãŸ"
+
+#, c-format
+msgid "unable to convert %s to vim dictionary"
+msgstr "%s vimã®è¾žæ›¸åž‹ã«å¤‰æ›ã§ãã¾ã›ã‚“"
+
+#, c-format
+msgid "unable to convert %s to vim list"
+msgstr "%s ã‚’vimã®ãƒªã‚¹ãƒˆã«å¤‰æ›ã§ãã¾ã›ã‚“"
+
+#, c-format
+msgid "unable to convert %s to vim structure"
+msgstr "%s ã‚’vimã®æ§‹é€ ä½“ã«å¤‰æ›ã§ãã¾ã›ã‚“"
+
+msgid "internal error: NULL reference passed"
+msgstr "内部エラー: NULLå‚ç…§ãŒæ¸¡ã•ã‚Œã¾ã—ãŸ"
+
+msgid "internal error: invalid value type"
+msgstr "内部エラー: 無効ãªå€¤åž‹ã§ã™"
+
+msgid ""
+"Failed to set path hook: sys.path_hooks is not a list\n"
+"You should now do the following:\n"
+"- append vim.path_hook to sys.path_hooks\n"
+"- append vim.VIM_SPECIAL_PATH to sys.path\n"
+msgstr ""
+"パスフックã®è¨­å®šã«å¤±æ•—ã—ã¾ã—ãŸ: sys.path_hooks ãŒãƒªã‚¹ãƒˆã§ã¯ã‚ã‚Šã¾ã›ã‚“\n"
+"ã™ãã«ä¸‹è¨˜ã‚’実施ã—ã¦ãã ã•ã„:\n"
+"- vim.path_hooks ã‚’ sys.path_hooks ã¸è¿½åŠ \n"
+"- vim.VIM_SPECIAL_PATH ã‚’ sys.path ã¸è¿½åŠ \n"
+
+msgid ""
+"Failed to set path: sys.path is not a list\n"
+"You should now append vim.VIM_SPECIAL_PATH to sys.path"
+msgstr ""
+"パスã®è¨­å®šã«å¤±æ•—ã—ã¾ã—ãŸ: sys.path ãŒãƒªã‚¹ãƒˆã§ã¯ã‚ã‚Šã¾ã›ã‚“\n"
+"ã™ãã« vim.VIM_SPECIAL_PATH ã‚’ sys.path ã«è¿½åŠ ã—ã¦ãã ã•ã„"
+
+msgid ""
+"Vim macro files (*.vim)\t*.vim\n"
+"All Files (*.*)\t*.*\n"
+msgstr ""
+"Vimマクロファイル (*.vim)\t*.vim\n"
+"ã™ã¹ã¦ã®ãƒ•ã‚¡ã‚¤ãƒ« (*.*)\t*.*\n"
+
+msgid "All Files (*.*)\t*.*\n"
+msgstr "ã™ã¹ã¦ã®ãƒ•ã‚¡ã‚¤ãƒ« (*.*)\t*.*\n"
+
+msgid ""
+"All Files (*.*)\t*.*\n"
+"C source (*.c, *.h)\t*.c;*.h\n"
+"C++ source (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"VB code (*.bas, *.frm)\t*.bas;*.frm\n"
+"Vim files (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
+msgstr ""
+"ã™ã¹ã¦ã®ãƒ•ã‚¡ã‚¤ãƒ« (*.*)\t*.*\n"
+"Cソース (*.c, *.h)\t*.c;*.h\n"
+"C++ソース (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"VBコード (*.bas, *.frm)\t*.bas;*.frm\n"
+"Vimファイル (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
+
+msgid ""
+"Vim macro files (*.vim)\t*.vim\n"
+"All Files (*)\t*\n"
+msgstr ""
+"Vim マクロファイル (*.vim)\t*.vim\n"
+"ã™ã¹ã¦ã®ãƒ•ã‚¡ã‚¤ãƒ« (*)\t*\n"
+
+msgid "All Files (*)\t*\n"
+msgstr "ã™ã¹ã¦ã®ãƒ•ã‚¡ã‚¤ãƒ« (*)\t*\n"
+
+msgid ""
+"All Files (*)\t*\n"
+"C source (*.c, *.h)\t*.c;*.h\n"
+"C++ source (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"Vim files (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
+msgstr ""
+"ã™ã¹ã¦ã®ãƒ•ã‚¡ã‚¤ãƒ« (*)\t*\n"
+"Cソース (*.c, *.h)\t*.c;*.h\n"
+"C++ソース (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"Vimファイル (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
diff --git a/src/po/ja.sjis.po b/src/po/ja.sjis.po
new file mode 100644
index 0000000..9e70745
--- /dev/null
+++ b/src/po/ja.sjis.po
@@ -0,0 +1,7068 @@
+# Japanese translation for Vim
+#
+# Do ":help uganda" in Vim to read copying and usage conditions.
+# Do ":help credits" in Vim to see a list of people who contributed.
+#
+# Copyright (C) 2001-2018 MURAOKA Taro <koron.kaoriya@gmail.com>,
+# vim-jp <http://vim-jp.org/>
+#
+# THIS FILE IS DISTRIBUTED UNDER THE VIM LICENSE.
+#
+# generated from ja.po, DO NOT EDIT
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Vim 8.1\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2018-11-13 19:44+0900\n"
+"PO-Revision-Date: 2018-11-16 09:41+0900\n"
+"Last-Translator: MURAOKA Taro <koron.kaoriya@gmail.com>\n"
+"Language-Team: Japanese <https://github.com/vim-jp/lang-ja>\n"
+"Language: ja\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=cp932\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+
+msgid "E831: bf_key_init() called with empty password"
+msgstr "E831: bf_key_init() ‚ª‹óƒpƒXƒ[ƒh‚ŌĂÑo‚³‚ê‚Ü‚µ‚½"
+
+msgid "E820: sizeof(uint32_t) != 4"
+msgstr "E820: sizeof(uint32_t) != 4"
+
+msgid "E817: Blowfish big/little endian use wrong"
+msgstr "E817: BlowfishˆÃ†‚̃rƒbƒO/ƒŠƒgƒ‹ƒGƒ“ƒfƒBƒAƒ“‚ªŠÔˆá‚Á‚Ä‚¢‚Ü‚·"
+
+msgid "E818: sha256 test failed"
+msgstr "E818: sha256‚̃eƒXƒg‚ÉŽ¸”s‚µ‚Ü‚µ‚½"
+
+msgid "E819: Blowfish test failed"
+msgstr "E819: BlowfishˆÃ†‚̃eƒXƒg‚ÉŽ¸”s‚µ‚Ü‚µ‚½"
+
+msgid "[Location List]"
+msgstr "[ƒƒP[ƒVƒ‡ƒ“ƒŠƒXƒg]"
+
+msgid "[Quickfix List]"
+msgstr "[QuickfixƒŠƒXƒg]"
+
+msgid "E855: Autocommands caused command to abort"
+msgstr "E855: autocommand‚ªƒRƒ}ƒ“ƒh‚Ì’âŽ~‚ðˆø‚«‹N‚±‚µ‚Ü‚µ‚½"
+
+msgid "E82: Cannot allocate any buffer, exiting..."
+msgstr "E82: ƒoƒbƒtƒ@‚ð1‚‚à쬂ł«‚È‚¢‚Ì‚ÅAI—¹‚µ‚Ü‚·..."
+
+msgid "E83: Cannot allocate buffer, using other one..."
+msgstr "E83: ƒoƒbƒtƒ@‚ð쬂ł«‚È‚¢‚Ì‚ÅA‘¼‚Ì‚ðŽg—p‚µ‚Ü‚·..."
+
+msgid "E931: Buffer cannot be registered"
+msgstr "E931: ƒoƒbƒtƒ@‚ð“o˜^‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "E937: Attempt to delete a buffer that is in use"
+msgstr "E937: Žg—p’†‚̃oƒbƒtƒ@‚ð휂µ‚悤‚ÆŽŽ‚Ý‚Ü‚µ‚½"
+
+msgid "E515: No buffers were unloaded"
+msgstr "E515: ‰ð•ú‚³‚ꂽƒoƒbƒtƒ@‚Í‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "E516: No buffers were deleted"
+msgstr "E516: 휂³‚ꂽƒoƒbƒtƒ@‚Í‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "E517: No buffers were wiped out"
+msgstr "E517: ”jŠü‚³‚ꂽƒoƒbƒtƒ@‚Í‚ ‚è‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "%d buffer unloaded"
+msgid_plural "%d buffers unloaded"
+msgstr[0] "%d ŒÂ‚̃oƒbƒtƒ@‚ª‰ð•ú‚³‚ê‚Ü‚µ‚½"
+
+#, c-format
+msgid "%d buffer deleted"
+msgid_plural "%d buffers deleted"
+msgstr[0] "%d ŒÂ‚̃oƒbƒtƒ@‚ªíœ‚³‚ê‚Ü‚µ‚½"
+
+#, c-format
+msgid "%d buffer wiped out"
+msgid_plural "%d buffers wiped out"
+msgstr[0] "%d ŒÂ‚̃oƒbƒtƒ@‚ª”jŠü‚³‚ê‚Ü‚µ‚½"
+
+msgid "E90: Cannot unload last buffer"
+msgstr "E90: ÅŒã‚̃oƒbƒtƒ@‚͉ð•ú‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "E84: No modified buffer found"
+msgstr "E84: •ÏX‚³‚ꂽƒoƒbƒtƒ@‚Í‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "E85: There is no listed buffer"
+msgstr "E85: ƒŠƒXƒg•\\Ž¦‚³‚ê‚éƒoƒbƒtƒ@‚Í‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "E87: Cannot go beyond last buffer"
+msgstr "E87: ÅŒã‚̃oƒbƒtƒ@‚ð‰z‚¦‚Ĉړ®‚Í‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "E88: Cannot go before first buffer"
+msgstr "E88: ʼn‚̃oƒbƒtƒ@‚æ‚è‘O‚ւ͈ړ®‚Å‚«‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E89: No write since last change for buffer %ld (add ! to override)"
+msgstr "E89: ƒoƒbƒtƒ@ %ld ‚Ì•ÏX‚Í•Û‘¶‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ (! ‚Å•ÏX‚ð”jŠü)"
+
+msgid "E948: Job still running (add ! to end the job)"
+msgstr "E948: ƒWƒ‡ƒu‚Í‚Ü‚¾ŽÀs’†‚Å‚· (! ‚ð’ljÁ‚ŃWƒ‡ƒu‚ðI—¹)"
+
+msgid "E37: No write since last change (add ! to override)"
+msgstr "E37: ÅŒã‚Ì•ÏX‚ª•Û‘¶‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ (! ‚ð’ljÁ‚Å•ÏX‚ð”jŠü)"
+
+msgid "E948: Job still running"
+msgstr "E948: ƒWƒ‡ƒu‚Í‚Ü‚¾ŽÀs’†‚Å‚·"
+
+msgid "E37: No write since last change"
+msgstr "E37: ÅŒã‚Ì•ÏX‚ª•Û‘¶‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ"
+
+msgid "W14: Warning: List of file names overflow"
+msgstr "W14: Œx: ƒtƒ@ƒCƒ‹–¼‚̃ŠƒXƒg‚ª’·‰ß‚¬‚Ü‚·"
+
+#, c-format
+msgid "E92: Buffer %ld not found"
+msgstr "E92: ƒoƒbƒtƒ@ %ld ‚ªŒ©‚‚©‚è‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E93: More than one match for %s"
+msgstr "E93: %s ‚É•¡”‚ÌŠY“–‚ª‚ ‚è‚Ü‚µ‚½"
+
+#, c-format
+msgid "E94: No matching buffer for %s"
+msgstr "E94: %s ‚ÉŠY“–‚·‚éƒoƒbƒtƒ@‚Í‚ ‚è‚Ü‚¹‚ñ‚Å‚µ‚½"
+
+#, c-format
+msgid "line %ld"
+msgstr "s %ld"
+
+msgid "E95: Buffer with this name already exists"
+msgstr "E95: ‚±‚Ì–¼‘O‚̃oƒbƒtƒ@‚ÍŠù‚É‚ ‚è‚Ü‚·"
+
+msgid " [Modified]"
+msgstr " [•ÏX‚ ‚è]"
+
+msgid "[Not edited]"
+msgstr "[–¢•ÒW]"
+
+msgid "[New file]"
+msgstr "[Vƒtƒ@ƒCƒ‹]"
+
+msgid "[Read errors]"
+msgstr "[“ÇžƒGƒ‰[]"
+
+msgid "[RO]"
+msgstr "[“Çê]"
+
+msgid "[readonly]"
+msgstr "[“Çžê—p]"
+
+#, c-format
+msgid "%ld line --%d%%--"
+msgid_plural "%ld lines --%d%%--"
+msgstr[0] "%ld s --%d%%--"
+
+#, c-format
+msgid "line %ld of %ld --%d%%-- col "
+msgstr "s %ld (‘S‘Ì %ld) --%d%%-- col "
+
+msgid "[No Name]"
+msgstr "[–³–¼]"
+
+msgid "help"
+msgstr "ƒwƒ‹ƒv"
+
+msgid "[Help]"
+msgstr "[ƒwƒ‹ƒv]"
+
+msgid "[Preview]"
+msgstr "[ƒvƒŒƒrƒ…[]"
+
+msgid "All"
+msgstr "‘S‚Ä"
+
+msgid "Bot"
+msgstr "––”ö"
+
+msgid "Top"
+msgstr "擪"
+
+msgid ""
+"\n"
+"# Buffer list:\n"
+msgstr ""
+"\n"
+"# ƒoƒbƒtƒ@ƒŠƒXƒg:\n"
+
+msgid "E382: Cannot write, 'buftype' option is set"
+msgstr "E382: 'buftype' ƒIƒvƒVƒ‡ƒ“‚ªÝ’肳‚ê‚Ä‚¢‚é‚Ì‚Å‘ž‚ß‚Ü‚¹‚ñ"
+
+msgid "[Prompt]"
+msgstr "[ƒvƒƒ“ƒvƒg]"
+
+msgid "[Scratch]"
+msgstr "[‰º‘‚«]"
+
+msgid ""
+"\n"
+"--- Signs ---"
+msgstr ""
+"\n"
+"--- ƒTƒCƒ“ ---"
+
+#, c-format
+msgid "Signs for %s:"
+msgstr "%s ‚̃TƒCƒ“:"
+
+#, c-format
+msgid " line=%ld id=%d name=%s"
+msgstr " s=%ld Ž¯•ÊŽq=%d –¼‘O=%s"
+
+msgid "E902: Cannot connect to port"
+msgstr "E902: ƒ|[ƒg‚ÉÚ‘±‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "E901: gethostbyname() in channel_open()"
+msgstr "E901: channel_open() “à‚Ì gethostbyname() ‚ªŽ¸”s‚µ‚Ü‚µ‚½"
+
+msgid "E898: socket() in channel_open()"
+msgstr "E898: channel_open() “à‚Ì socket() ‚ªŽ¸”s‚µ‚Ü‚µ‚½"
+
+msgid "E903: received command with non-string argument"
+msgstr "E903: ”ñ•¶Žš—ñ‚̈ø”‚̃Rƒ}ƒ“ƒh‚ðŽóM‚µ‚Ü‚µ‚½"
+
+msgid "E904: last argument for expr/call must be a number"
+msgstr "E904: expr/call ‚ÌÅŒã‚̈ø”‚Í”Žš‚Å‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñ"
+
+msgid "E904: third argument for call must be a list"
+msgstr "E904: call ‚Ì3”Ԗڂ̈ø”‚̓ŠƒXƒgŒ^‚Å‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E905: received unknown command: %s"
+msgstr "E905: –¢’m‚̃Rƒ}ƒ“ƒh‚ðŽóM‚µ‚Ü‚µ‚½: %s"
+
+#, c-format
+msgid "E630: %s(): write while not connected"
+msgstr "E630: %s(): ”ñÚ‘±ó‘Ô‚Å‘‚«ž‚Ý‚Ü‚µ‚½"
+
+#, c-format
+msgid "E631: %s(): write failed"
+msgstr "E631: %s(): ‘‚«ž‚Ý‚ÉŽ¸”s‚µ‚Ü‚µ‚½"
+
+#, c-format
+msgid "E917: Cannot use a callback with %s()"
+msgstr "E917: %s() ‚ɃR[ƒ‹ƒoƒbƒN‚ÍŽg‚¦‚Ü‚¹‚ñ"
+
+msgid "E912: cannot use ch_evalexpr()/ch_sendexpr() with a raw or nl channel"
+msgstr ""
+"E912: raw ‚â nl ƒ‚[ƒh‚̃`ƒƒƒlƒ‹‚É ch_evalexpr()/ch_sendexpr() ‚ÍŽg‚¦‚Ü‚¹‚ñ"
+
+msgid "E906: not an open channel"
+msgstr "E906: ŠJ‚¢‚Ä‚¢‚È‚¢ƒ`ƒƒƒlƒ‹‚Å‚·"
+
+msgid "E920: _io file requires _name to be set"
+msgstr "E920: _io ƒtƒ@ƒCƒ‹‚Í _name ‚Ìݒ肪•K—v‚Å‚·"
+
+msgid "E915: in_io buffer requires in_buf or in_name to be set"
+msgstr "E915: in_io ƒoƒbƒtƒ@‚Í in_buf ‚© in_name ‚Ìݒ肪•K—v‚Å‚·"
+
+#, c-format
+msgid "E918: buffer must be loaded: %s"
+msgstr "E918: ƒoƒbƒtƒ@‚ªƒ[ƒh‚³‚ê‚Ä‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñ: %s"
+
+msgid "E821: File is encrypted with unknown method"
+msgstr "E821: ƒtƒ@ƒCƒ‹‚ª–¢’m‚Ì•û–@‚ňƉ»‚³‚ê‚Ä‚¢‚Ü‚·"
+
+msgid "Warning: Using a weak encryption method; see :help 'cm'"
+msgstr "Œx: Žã‚¢ˆÃ†•û–@‚ðŽg‚Á‚Ä‚¢‚Ü‚·; :help 'cm' ‚ðŽQÆ‚µ‚Ä‚­‚¾‚³‚¢"
+
+msgid "Enter encryption key: "
+msgstr "ˆÃ†‰»—p‚̃L[‚ð“ü—Í‚µ‚Ä‚­‚¾‚³‚¢: "
+
+msgid "Enter same key again: "
+msgstr "‚à‚¤ˆê“x“¯‚¶ƒL[‚ð“ü—Í‚µ‚Ä‚­‚¾‚³‚¢: "
+
+msgid "Keys don't match!"
+msgstr "ƒL[‚ªˆê’v‚µ‚Ü‚¹‚ñ"
+
+msgid "[crypted]"
+msgstr "[ˆÃ†‰»]"
+
+#, c-format
+msgid "E720: Missing colon in Dictionary: %s"
+msgstr "E720: Ž«‘Œ^‚ɃRƒƒ“‚ª‚ ‚è‚Ü‚¹‚ñ: %s"
+
+#, c-format
+msgid "E721: Duplicate key in Dictionary: \"%s\""
+msgstr "E721: Ž«‘Œ^‚Éd•¡ƒL[‚ª‚ ‚è‚Ü‚·: \"%s\""
+
+#, c-format
+msgid "E722: Missing comma in Dictionary: %s"
+msgstr "E722: Ž«‘Œ^‚ɃJƒ“ƒ}‚ª‚ ‚è‚Ü‚¹‚ñ: %s"
+
+#, c-format
+msgid "E723: Missing end of Dictionary '}': %s"
+msgstr "E723: Ž«‘Œ^‚ÌÅŒã‚É '}' ‚ª‚ ‚è‚Ü‚¹‚ñ: %s"
+
+msgid "extend() argument"
+msgstr "extend() ‚̈ø”"
+
+#, c-format
+msgid "E737: Key already exists: %s"
+msgstr "E737: ƒL[‚ÍŠù‚É‘¶Ý‚µ‚Ü‚·: %s"
+
+#, c-format
+msgid "E96: Cannot diff more than %ld buffers"
+msgstr "E96: %ld ˆÈã‚̃oƒbƒtƒ@‚Ídiff‚Å‚«‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "Not enough memory to use internal diff for buffer \"%s\""
+msgstr "ƒoƒbƒtƒ@ \"%s\" —p‚É“à•”diff‚ðŽg‚¤‚½‚߂̃ƒ‚ƒŠ‚ª•s‘«‚µ‚Ä‚¢‚Ü‚·"
+
+msgid "E810: Cannot read or write temp files"
+msgstr "E810: ˆêŽžƒtƒ@ƒCƒ‹‚Ì“Çž‚à‚µ‚­‚Í‘ž‚ª‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "E97: Cannot create diffs"
+msgstr "E97: ·•ª‚ð쬂ł«‚Ü‚¹‚ñ"
+
+msgid "E960: Problem creating the internal diff"
+msgstr "E960: “à•”diff쬎ž‚É–â‘肪”­¶‚µ‚Ü‚µ‚½"
+
+msgid "Patch file"
+msgstr "ƒpƒbƒ`ƒtƒ@ƒCƒ‹"
+
+msgid "E816: Cannot read patch output"
+msgstr "E816: patch‚Ìo—Í‚ð“Çž‚ß‚Ü‚¹‚ñ"
+
+msgid "E98: Cannot read diff output"
+msgstr "E98: diff‚Ìo—Í‚ð“Çž‚ß‚Ü‚¹‚ñ"
+
+msgid "E959: Invalid diff format."
+msgstr "E959: –³Œø‚ÈdiffŒ`Ž®‚Å‚·"
+
+msgid "E99: Current buffer is not in diff mode"
+msgstr "E99: Œ»Ý‚̃oƒbƒtƒ@‚Í·•ªƒ‚[ƒh‚Å‚Í‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "E793: No other buffer in diff mode is modifiable"
+msgstr "E793: ·•ªƒ‚[ƒh‚Å‚ ‚鑼‚̃oƒbƒtƒ@‚Í•ÏX‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "E100: No other buffer in diff mode"
+msgstr "E100: ·•ªƒ‚[ƒh‚Å‚ ‚鑼‚̃oƒbƒtƒ@‚Í‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "E101: More than two buffers in diff mode, don't know which one to use"
+msgstr ""
+"E101: ·•ªƒ‚[ƒh‚̃oƒbƒtƒ@‚ª2ŒÂˆÈã‚ ‚é‚Ì‚ÅA‚Ç‚ê‚ðŽg‚¤‚©“Á’è‚Å‚«‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E102: Can't find buffer \"%s\""
+msgstr "E102: ƒoƒbƒtƒ@ \"%s\" ‚ªŒ©‚‚©‚è‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E103: Buffer \"%s\" is not in diff mode"
+msgstr "E103: ƒoƒbƒtƒ@ \"%s\" ‚Í·•ªƒ‚[ƒh‚Å‚Í‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "E787: Buffer changed unexpectedly"
+msgstr "E787: —\\Šú‚¹‚¸ƒoƒbƒtƒ@‚ª•ÏX•ÏX‚³‚ê‚Ü‚µ‚½"
+
+msgid "E104: Escape not allowed in digraph"
+msgstr "E104: ‡Žš‚ÉEscape‚ÍŽg—p‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "E544: Keymap file not found"
+msgstr "E544: ƒL[ƒ}ƒbƒvƒtƒ@ƒCƒ‹‚ªŒ©‚‚©‚è‚Ü‚¹‚ñ"
+
+msgid "E105: Using :loadkeymap not in a sourced file"
+msgstr "E105: :source ‚ÅŽæž‚Þƒtƒ@ƒCƒ‹ˆÈŠO‚Å‚Í :loadkeymap ‚ðŽg‚¦‚Ü‚¹‚ñ"
+
+msgid "E791: Empty keymap entry"
+msgstr "E791: ‹ó‚̃L[ƒ}ƒbƒvƒGƒ“ƒgƒŠ"
+
+msgid " Keyword completion (^N^P)"
+msgstr " ƒL[ƒ[ƒh•âŠ® (^N^P)"
+
+msgid " ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+msgstr " ^X ƒ‚[ƒh (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+
+msgid " Whole line completion (^L^N^P)"
+msgstr " s(‘S‘Ì)•âŠ® (^L^N^P)"
+
+msgid " File name completion (^F^N^P)"
+msgstr " ƒtƒ@ƒCƒ‹–¼•âŠ® (^F^N^P)"
+
+msgid " Tag completion (^]^N^P)"
+msgstr " ƒ^ƒO•âŠ® (^]^N^P)"
+
+msgid " Path pattern completion (^N^P)"
+msgstr " ƒpƒXƒpƒ^[ƒ“•âŠ® (^N^P)"
+
+msgid " Definition completion (^D^N^P)"
+msgstr " ’è‹`•âŠ® (^D^N^P)"
+
+msgid " Dictionary completion (^K^N^P)"
+msgstr " Ž«‘•âŠ® (^K^N^P)"
+
+msgid " Thesaurus completion (^T^N^P)"
+msgstr " ƒVƒ\\[ƒ‰ƒX•âŠ® (^T^N^P)"
+
+msgid " Command-line completion (^V^N^P)"
+msgstr " ƒRƒ}ƒ“ƒhƒ‰ƒCƒ“•âŠ® (^V^N^P)"
+
+msgid " User defined completion (^U^N^P)"
+msgstr " ƒ†[ƒU[’è‹`•âŠ® (^U^N^P)"
+
+msgid " Omni completion (^O^N^P)"
+msgstr " ƒIƒ€ƒj•âŠ® (^O^N^P)"
+
+msgid " Spelling suggestion (s^N^P)"
+msgstr " ’Ô‚èC³Œó•â (s^N^P)"
+
+msgid " Keyword Local completion (^N^P)"
+msgstr " ‹ÇŠƒL[ƒ[ƒh•âŠ® (^N^P)"
+
+msgid "Hit end of paragraph"
+msgstr "’i—Ž‚ÌÅŒã‚Ƀqƒbƒg"
+
+msgid "E839: Completion function changed window"
+msgstr "E839: •âŠÔŠÖ”‚ªƒEƒBƒ“ƒhƒE‚ð•ÏX‚µ‚Ü‚µ‚½"
+
+msgid "E840: Completion function deleted text"
+msgstr "E840: •âŠ®ŠÖ”‚ªƒeƒLƒXƒg‚ð휂µ‚Ü‚µ‚½"
+
+msgid "'dictionary' option is empty"
+msgstr "'dictionary' ƒIƒvƒVƒ‡ƒ“‚ª‹ó‚Å‚·"
+
+msgid "'thesaurus' option is empty"
+msgstr "'thesaurus' ƒIƒvƒVƒ‡ƒ“‚ª‹ó‚Å‚·"
+
+#, c-format
+msgid "Scanning dictionary: %s"
+msgstr "Ž«‘‚ðƒXƒLƒƒƒ“’†: %s"
+
+msgid " (insert) Scroll (^E/^Y)"
+msgstr " (‘}“ü) ƒXƒNƒ[ƒ‹(^E/^Y)"
+
+msgid " (replace) Scroll (^E/^Y)"
+msgstr " (’uŠ·) ƒXƒNƒ[ƒ‹ (^E/^Y)"
+
+#, c-format
+msgid "Scanning: %s"
+msgstr "ƒXƒLƒƒƒ“’†: %s"
+
+msgid "Scanning tags."
+msgstr "ƒ^ƒO‚ðƒXƒLƒƒƒ“’†."
+
+msgid "match in file"
+msgstr "ƒtƒ@ƒCƒ‹“à‚̃}ƒbƒ`"
+
+msgid " Adding"
+msgstr " ’ljÁ’†"
+
+msgid "-- Searching..."
+msgstr "-- ŒŸõ’†..."
+
+msgid "Back at original"
+msgstr "Žn‚ß‚É–ß‚é"
+
+msgid "Word from other line"
+msgstr "‘¼‚Ìs‚Ì’PŒê"
+
+msgid "The only match"
+msgstr "—Bˆê‚ÌŠY“–"
+
+#, c-format
+msgid "match %d of %d"
+msgstr "%d ”Ô–Ú‚ÌŠY“– (‘SŠY“– %d ŒÂ’†)"
+
+#, c-format
+msgid "match %d"
+msgstr "%d ”Ô–Ú‚ÌŠY“–"
+
+msgid "E18: Unexpected characters in :let"
+msgstr "E18: —\\Šú‚¹‚Ê•¶Žš‚ª :let ‚É‚ ‚è‚Ü‚µ‚½"
+
+#, c-format
+msgid "E121: Undefined variable: %s"
+msgstr "E121: –¢’è‹`‚Ì•Ï”‚Å‚·: %s"
+
+msgid "E111: Missing ']'"
+msgstr "E111: ']' ‚ªŒ©‚‚©‚è‚Ü‚¹‚ñ"
+
+msgid "E719: Cannot use [:] with a Dictionary"
+msgstr "E719: [:] ‚ðŽ«‘Œ^‚Æ‘g‚݇‚킹‚Ä‚ÍŽg‚¦‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E734: Wrong variable type for %s="
+msgstr "E734: ˆÙ‚È‚Á‚½Œ^‚Ì•Ï”‚Å‚· %s="
+
+#, c-format
+msgid "E461: Illegal variable name: %s"
+msgstr "E461: •s³‚È•Ï”–¼‚Å‚·: %s"
+
+msgid "E806: using Float as a String"
+msgstr "E806: •‚“®¬”“_”‚𕶎š—ñ‚Æ‚µ‚Ĉµ‚Á‚Ä‚¢‚Ü‚·"
+
+msgid "E687: Less targets than List items"
+msgstr "E687: ƒ^[ƒQƒbƒg‚ªƒŠƒXƒgŒ^“à‚Ì—v‘f‚æ‚è‚à­‚È‚¢‚Å‚·"
+
+msgid "E688: More targets than List items"
+msgstr "E688: ƒ^[ƒQƒbƒg‚ªƒŠƒXƒgŒ^“à‚Ì—v‘f‚æ‚è‚à‘½‚¢‚Å‚·"
+
+msgid "Double ; in list of variables"
+msgstr "ƒŠƒXƒgŒ^‚Ì’l‚É2‚ˆÈã‚Ì ; ‚ªŒŸo‚³‚ê‚Ü‚µ‚½"
+
+#, c-format
+msgid "E738: Can't list variables for %s"
+msgstr "E738: %s ‚Ì’l‚ðˆê——•\\Ž¦‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "E689: Can only index a List or Dictionary"
+msgstr "E689: ƒŠƒXƒgŒ^‚ÆŽ«‘Œ^ˆÈŠO‚̓Cƒ“ƒfƒbƒNƒXŽw’è‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "E708: [:] must come last"
+msgstr "E708: [:] ‚ÍÅŒã‚Å‚È‚¯‚ê‚΂¢‚¯‚Ü‚¹‚ñ"
+
+msgid "E709: [:] requires a List value"
+msgstr "E709: [:] ‚ɂ̓ŠƒXƒgŒ^‚Ì’l‚ª•K—v‚Å‚·"
+
+msgid "E710: List value has more items than target"
+msgstr "E710: ƒŠƒXƒgŒ^•Ï”‚Ƀ^[ƒQƒbƒg‚æ‚è‚à‘½‚¢—v‘f‚ª‚ ‚è‚Ü‚·"
+
+msgid "E711: List value has not enough items"
+msgstr "E711: ƒŠƒXƒgŒ^•Ï”‚É\\•ª‚È”‚Ì—v‘f‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "E690: Missing \"in\" after :for"
+msgstr "E690: :for ‚ÌŒã‚É \"in\" ‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E108: No such variable: \"%s\""
+msgstr "E108: ‚»‚Ì•Ï”‚Í‚ ‚è‚Ü‚¹‚ñ: \"%s\""
+
+#, c-format
+msgid "E940: Cannot lock or unlock variable %s"
+msgstr "E940: •Ï” %s ‚̓ƒbƒN‚Ü‚½‚̓Aƒ“ƒƒbƒN‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "E743: variable nested too deep for (un)lock"
+msgstr "E743: (ƒAƒ“)ƒƒbƒN‚·‚é‚É‚Í•Ï”‚Ì“ü‚êŽq‚ª[‰ß‚¬‚Ü‚·"
+
+msgid "E109: Missing ':' after '?'"
+msgstr "E109: '?' ‚ÌŒã‚É ':' ‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "E804: Cannot use '%' with Float"
+msgstr "E804: '%' ‚ð•‚“®¬”“_”‚Æ‘g‚݇‚킹‚Ä‚ÍŽg‚¦‚Ü‚¹‚ñ"
+
+msgid "E110: Missing ')'"
+msgstr "E110: ')' ‚ªŒ©‚‚©‚è‚Ü‚¹‚ñ"
+
+msgid "E695: Cannot index a Funcref"
+msgstr "E695: ŠÖ”ŽQÆŒ^‚̓Cƒ“ƒfƒbƒNƒX‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "E909: Cannot index a special variable"
+msgstr "E909: “ÁŽê•Ï”‚̓Cƒ“ƒfƒbƒNƒX‚Å‚«‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E112: Option name missing: %s"
+msgstr "E112: ƒIƒvƒVƒ‡ƒ“–¼‚ª‚ ‚è‚Ü‚¹‚ñ: %s"
+
+#, c-format
+msgid "E113: Unknown option: %s"
+msgstr "E113: –¢’m‚̃IƒvƒVƒ‡ƒ“‚Å‚·: %s"
+
+#, c-format
+msgid "E114: Missing quote: %s"
+msgstr "E114: ˆø—p•„ (\") ‚ª‚ ‚è‚Ü‚¹‚ñ: %s"
+
+#, c-format
+msgid "E115: Missing quote: %s"
+msgstr "E115: ˆø—p•„ (') ‚ª‚ ‚è‚Ü‚¹‚ñ: %s"
+
+msgid "Not enough memory to set references, garbage collection aborted!"
+msgstr ""
+"ƒK[ƒxƒbƒWƒRƒŒƒNƒVƒ‡ƒ“‚𒆎~‚µ‚Ü‚µ‚½! ŽQÆ‚ð쬂·‚é‚̂Ƀƒ‚ƒŠ‚ª•s‘«‚µ‚Ü‚µ‚½"
+
+msgid "E724: variable nested too deep for displaying"
+msgstr "E724: •\\Ž¦‚·‚é‚É‚Í•Ï”‚Ì“ü‚êŽq‚ª[‰ß‚¬‚Ü‚·"
+
+msgid "E805: Using a Float as a Number"
+msgstr "E805: •‚“®¬”“_”‚ð”’l‚Æ‚µ‚Ĉµ‚Á‚Ä‚¢‚Ü‚·"
+
+msgid "E703: Using a Funcref as a Number"
+msgstr "E703: ŠÖ”ŽQÆŒ^‚ð”’l‚Æ‚µ‚Ĉµ‚Á‚Ä‚¢‚Ü‚·"
+
+msgid "E745: Using a List as a Number"
+msgstr "E745: ƒŠƒXƒgŒ^‚ð”’l‚Æ‚µ‚Ĉµ‚Á‚Ä‚¢‚Ü‚·"
+
+msgid "E728: Using a Dictionary as a Number"
+msgstr "E728: Ž«‘Œ^‚ð”’l‚Æ‚µ‚Ĉµ‚Á‚Ä‚¢‚Ü‚·"
+
+msgid "E910: Using a Job as a Number"
+msgstr "E910: ƒWƒ‡ƒu‚ð”’l‚Æ‚µ‚Ĉµ‚Á‚Ä‚¢‚Ü‚·"
+
+msgid "E913: Using a Channel as a Number"
+msgstr "E913: ƒ`ƒƒƒlƒ‹‚ð”’l‚Æ‚µ‚Ĉµ‚Á‚Ä‚¢‚Ü‚·"
+
+msgid "E891: Using a Funcref as a Float"
+msgstr "E891: ŠÖ”ŽQÆŒ^‚ð•‚“®¬”“_”‚Æ‚µ‚Ĉµ‚Á‚Ä‚¢‚Ü‚·"
+
+msgid "E892: Using a String as a Float"
+msgstr "E892: •¶Žš—ñ‚ð•‚“®¬”“_”‚Æ‚µ‚Ĉµ‚Á‚Ä‚¢‚Ü‚·"
+
+msgid "E893: Using a List as a Float"
+msgstr "E893: ƒŠƒXƒgŒ^‚ð•‚“®¬”“_”‚Æ‚µ‚Ĉµ‚Á‚Ä‚¢‚Ü‚·"
+
+msgid "E894: Using a Dictionary as a Float"
+msgstr "E894: Ž«‘Œ^‚ð•‚“®¬”“_”‚Æ‚µ‚Ĉµ‚Á‚Ä‚¢‚Ü‚·"
+
+msgid "E907: Using a special value as a Float"
+msgstr "E907: “ÁŽê’l‚ð•‚“®¬”“_”‚Æ‚µ‚Ĉµ‚Á‚Ä‚¢‚Ü‚·"
+
+msgid "E911: Using a Job as a Float"
+msgstr "E911: ƒWƒ‡ƒu‚ð•‚“®¬”“_”‚Æ‚µ‚Ĉµ‚Á‚Ä‚¢‚Ü‚·"
+
+msgid "E914: Using a Channel as a Float"
+msgstr "E914: ƒ`ƒƒƒlƒ‹‚ð•‚“®¬”“_”‚Æ‚µ‚Ĉµ‚Á‚Ä‚¢‚Ü‚·"
+
+msgid "E729: using Funcref as a String"
+msgstr "E729: ŠÖ”ŽQÆŒ^‚𕶎š—ñ‚Æ‚µ‚Ĉµ‚Á‚Ä‚¢‚Ü‚·"
+
+msgid "E730: using List as a String"
+msgstr "E730: ƒŠƒXƒgŒ^‚𕶎š—ñ‚Æ‚µ‚Ĉµ‚Á‚Ä‚¢‚Ü‚·"
+
+msgid "E731: using Dictionary as a String"
+msgstr "E731: Ž«‘Œ^‚𕶎š—ñ‚Æ‚µ‚Ĉµ‚Á‚Ä‚¢‚Ü‚·"
+
+msgid "E908: using an invalid value as a String"
+msgstr "E908: –³Œø‚È’l‚𕶎š—ñ‚Æ‚µ‚Ĉµ‚Á‚Ä‚¢‚Ü‚·"
+
+#, c-format
+msgid "E795: Cannot delete variable %s"
+msgstr "E795: •Ï” %s ‚ð휂ł«‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E704: Funcref variable name must start with a capital: %s"
+msgstr "E704: ŠÖ”ŽQÆŒ^•Ï”–¼‚͑啶Žš‚ÅŽn‚Ü‚ç‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñ: %s"
+
+#, c-format
+msgid "E705: Variable name conflicts with existing function: %s"
+msgstr "E705: •Ï”–¼‚ªŠù‘¶‚ÌŠÖ”–¼‚ÆÕ“Ë‚µ‚Ü‚·: %s"
+
+#, c-format
+msgid "E741: Value is locked: %s"
+msgstr "E741: ’l‚ªƒƒbƒN‚³‚ê‚Ä‚¢‚Ü‚·: %s"
+
+msgid "Unknown"
+msgstr "•s–¾"
+
+#, c-format
+msgid "E742: Cannot change value of %s"
+msgstr "E742: %s ‚Ì’l‚ð•ÏX‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "E698: variable nested too deep for making a copy"
+msgstr "E698: ƒRƒs[‚ðŽæ‚é‚É‚Í•Ï”‚Ì“ü‚êŽq‚ª[‰ß‚¬‚Ü‚·"
+
+msgid ""
+"\n"
+"# global variables:\n"
+msgstr ""
+"\n"
+"# ƒOƒ[ƒoƒ‹•Ï”:\n"
+
+msgid ""
+"\n"
+"\tLast set from "
+msgstr ""
+"\n"
+"\tÅŒã‚ɃZƒbƒg‚µ‚½ƒXƒNƒŠƒvƒg: "
+
+msgid " line "
+msgstr " s "
+
+msgid "E691: Can only compare List with List"
+msgstr "E691: ƒŠƒXƒgŒ^‚̓ŠƒXƒgŒ^‚Æ‚µ‚©”äŠr‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "E692: Invalid operation for List"
+msgstr "E692: ƒŠƒXƒgŒ^‚É‚Í–³Œø‚È‘€ì‚Å‚·"
+
+msgid "E735: Can only compare Dictionary with Dictionary"
+msgstr "E735: Ž«‘Œ^‚ÍŽ«‘Œ^‚Æ‚µ‚©”äŠr‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "E736: Invalid operation for Dictionary"
+msgstr "E736: Ž«‘Œ^‚É‚Í–³Œø‚È‘€ì‚Å‚·"
+
+msgid "E694: Invalid operation for Funcrefs"
+msgstr "E694: ŠÖ”ŽQÆŒ^‚É‚Í–³Œø‚È‘€ì‚Å‚·"
+
+msgid "map() argument"
+msgstr "map() ‚̈ø”"
+
+msgid "filter() argument"
+msgstr "filter() ‚̈ø”"
+
+#, c-format
+msgid "E686: Argument of %s must be a List"
+msgstr "E686: %s ‚̈ø”‚̓ŠƒXƒgŒ^‚Å‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñ"
+
+msgid "E928: String required"
+msgstr "E928: •¶Žš—ñ‚ª•K—v‚Å‚·"
+
+msgid "E808: Number or Float required"
+msgstr "E808: ”’l‚©•‚“®¬”“_”‚ª•K—v‚Å‚·"
+
+msgid "add() argument"
+msgstr "add() ‚̈ø”"
+
+msgid "E785: complete() can only be used in Insert mode"
+msgstr "E785: complete() ‚Í‘}“üƒ‚[ƒh‚Å‚µ‚©—˜—p‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "&Ok"
+msgstr "&Ok"
+
+#, c-format
+msgid "+-%s%3ld line: "
+msgid_plural "+-%s%3ld lines: "
+msgstr[0] "+-%s%3ld s: "
+
+#, c-format
+msgid "E700: Unknown function: %s"
+msgstr "E700: –¢’m‚ÌŠÖ”‚Å‚·: %s"
+
+msgid "E922: expected a dict"
+msgstr "E922: Ž«‘‚ªŠú‘Ò‚³‚ê‚Ä‚¢‚Ü‚·"
+
+msgid "E923: Second argument of function() must be a list or a dict"
+msgstr "E923: function() ‚Ì‘æ 2 ˆø”‚̓ŠƒXƒgŒ^‚Ü‚½‚ÍŽ«‘Œ^‚Å‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñ"
+
+msgid ""
+"&OK\n"
+"&Cancel"
+msgstr ""
+"Œˆ’è(&O)\n"
+"ƒLƒƒƒ“ƒZƒ‹(&C)"
+
+msgid "called inputrestore() more often than inputsave()"
+msgstr "inputrestore() ‚ª inputsave() ‚æ‚è‚à‘½‚­ŒÄ‚΂ê‚Ü‚µ‚½"
+
+msgid "insert() argument"
+msgstr "insert() ‚̈ø”"
+
+msgid "E786: Range not allowed"
+msgstr "E786: ”͈͎w’è‚Í‹–‰Â‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ"
+
+msgid "E916: not a valid job"
+msgstr "E916: —LŒø‚ȃWƒ‡ƒu‚Å‚Í‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "E701: Invalid type for len()"
+msgstr "E701: len() ‚É‚Í–³Œø‚ÈŒ^‚Å‚·"
+
+msgid "E957: Invalid window number"
+msgstr "E957: –³Œø‚ȃEƒBƒ“ƒhƒE”Ô†‚Å‚·"
+
+#, c-format
+msgid "E798: ID is reserved for \":match\": %ld"
+msgstr "E798: ID ‚Í \":match\" ‚Ì‚½‚ß‚É—\\–ñ‚³‚ê‚Ä‚¢‚Ü‚·: %ld"
+
+msgid "E726: Stride is zero"
+msgstr "E726: ƒXƒgƒ‰ƒCƒh(‘Oi—Ê)‚ª 0 ‚Å‚·"
+
+msgid "E727: Start past end"
+msgstr "E727: ŠJŽnˆÊ’u‚ªI—¹ˆÊ’u‚ð‰z‚¦‚Ü‚µ‚½"
+
+msgid "<empty>"
+msgstr "<‹ó>"
+
+msgid "E240: No connection to the X server"
+msgstr "E240: X ƒT[ƒo[‚Ö‚ÌÚ‘±‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E241: Unable to send to %s"
+msgstr "E241: %s ‚Ö‘—‚邱‚Æ‚ª‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "E277: Unable to read a server reply"
+msgstr "E277: ƒT[ƒo[‚̉ž“š‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "E941: already started a server"
+msgstr "E941: ƒT[ƒo[‚Í‚·‚Å‚ÉŠJŽn‚µ‚Ä‚¢‚Ü‚·"
+
+msgid "E942: +clientserver feature not available"
+msgstr "E942: +clientserver ‹@”\\‚ª–³Œø‚É‚È‚Á‚Ä‚¢‚Ü‚·"
+
+msgid "remove() argument"
+msgstr "remove() ‚̈ø”"
+
+# Added at 10-Mar-2004.
+msgid "E655: Too many symbolic links (cycle?)"
+msgstr "E655: ƒVƒ“ƒ{ƒŠƒbƒNƒŠƒ“ƒN‚ª‘½‰ß‚¬‚Ü‚· (zŠÂ‚µ‚Ä‚¢‚é‰Â”\\«‚ª‚ ‚è‚Ü‚·)"
+
+msgid "reverse() argument"
+msgstr "reverse() ‚̈ø”"
+
+msgid "E258: Unable to send to client"
+msgstr "E258: ƒNƒ‰ƒCƒAƒ“ƒg‚Ö‘—‚邱‚Æ‚ª‚Å‚«‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E927: Invalid action: '%s'"
+msgstr "E927: –³Œø‚È‘€ì‚Å‚·: %s"
+
+#, c-format
+msgid "E962: Invalid action: '%s'"
+msgstr "E962: –³Œø‚È‘€ì‚Å‚·: %s"
+
+msgid "sort() argument"
+msgstr "sort() ‚̈ø”"
+
+msgid "uniq() argument"
+msgstr "uniq() ‚̈ø”"
+
+msgid "E702: Sort compare function failed"
+msgstr "E702: ƒ\\[ƒg‚Ì”äŠrŠÖ”‚ªŽ¸”s‚µ‚Ü‚µ‚½"
+
+msgid "E882: Uniq compare function failed"
+msgstr "E882: Uniq ‚Ì”äŠrŠÖ”‚ªŽ¸”s‚µ‚Ü‚µ‚½"
+
+msgid "(Invalid)"
+msgstr "(–³Œø)"
+
+#, c-format
+msgid "E935: invalid submatch number: %d"
+msgstr "E935: –³Œø‚ȃTƒuƒ}ƒbƒ`”Ô†: %d"
+
+msgid "E677: Error writing temp file"
+msgstr "E677: ˆêŽžƒtƒ@ƒCƒ‹‘ž’†‚ɃGƒ‰[‚ª”­¶‚µ‚Ü‚µ‚½"
+
+msgid "E921: Invalid callback argument"
+msgstr "E921: –³Œø‚ȃR[ƒ‹ƒoƒbƒNˆø”‚Å‚·"
+
+#, c-format
+msgid "<%s>%s%s %d, Hex %02x, Oct %03o, Digr %s"
+msgstr "<%s>%s%s %d, 16i” %02x, 8i” %03o, ƒ_ƒCƒOƒ‰ƒt %s"
+
+#, c-format
+msgid "<%s>%s%s %d, Hex %02x, Octal %03o"
+msgstr "<%s>%s%s %d, 16i” %02x, 8i” %03o"
+
+#, c-format
+msgid "> %d, Hex %04x, Oct %o, Digr %s"
+msgstr "> %d, 16i” %04x, 8i” %o, ƒ_ƒCƒOƒ‰ƒt %s"
+
+#, c-format
+msgid "> %d, Hex %08x, Oct %o, Digr %s"
+msgstr "> %d, 16i” %08x, 8i” %o, ƒ_ƒCƒOƒ‰ƒt %s"
+
+#, c-format
+msgid "> %d, Hex %04x, Octal %o"
+msgstr "> %d, 16i” %04x, 8i” %o"
+
+#, c-format
+msgid "> %d, Hex %08x, Octal %o"
+msgstr "> %d, 16i” %08x, 8i” %o"
+
+msgid "E134: Cannot move a range of lines into itself"
+msgstr "E134: s‚Ì”ÍˆÍ‚ð‚»‚êŽ©g‚ɂ͈ړ®‚Å‚«‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "%ld line moved"
+msgid_plural "%ld lines moved"
+msgstr[0] "%ld s‚ªˆÚ“®‚³‚ê‚Ü‚µ‚½"
+
+#, c-format
+msgid "%ld lines filtered"
+msgstr "%ld s‚ªƒtƒBƒ‹ƒ^ˆ—‚³‚ê‚Ü‚µ‚½"
+
+msgid "E135: *Filter* Autocommands must not change current buffer"
+msgstr "E135: *ƒtƒBƒ‹ƒ^* autocommand‚ÍŒ»Ý‚̃oƒbƒtƒ@‚ð•ÏX‚µ‚Ä‚Í‚¢‚¯‚Ü‚¹‚ñ"
+
+msgid "[No write since last change]\n"
+msgstr "[ÅŒã‚Ì•ÏX‚ª•Û‘¶‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ]\n"
+
+#, c-format
+msgid "%sviminfo: %s in line: "
+msgstr "%sviminfo: %s s–Ú: "
+
+msgid "E136: viminfo: Too many errors, skipping rest of file"
+msgstr "E136: viminfo: ƒGƒ‰[‚ª‘½‰ß‚¬‚é‚Ì‚ÅAˆÈ~‚̓XƒLƒbƒv‚µ‚Ü‚·"
+
+#, c-format
+msgid "Reading viminfo file \"%s\"%s%s%s"
+msgstr "viminfoƒtƒ@ƒCƒ‹ \"%s\"%s%s%s ‚ð“Çž‚Ý’†"
+
+msgid " info"
+msgstr " î•ñ"
+
+msgid " marks"
+msgstr " ƒ}[ƒN"
+
+msgid " oldfiles"
+msgstr " ‹Œƒtƒ@ƒCƒ‹ŒQ"
+
+msgid " FAILED"
+msgstr " Ž¸”s"
+
+#, c-format
+msgid "E137: Viminfo file is not writable: %s"
+msgstr "E137: viminfoƒtƒ@ƒCƒ‹‚ª‘ž‚Ý‚Å‚«‚Ü‚¹‚ñ: %s"
+
+#, c-format
+msgid "E929: Too many viminfo temp files, like %s!"
+msgstr "E929: ˆêŽžviminfoƒtƒ@ƒCƒ‹‚ª‘½‰ß‚¬‚Ü‚·! —á: %s"
+
+#, c-format
+msgid "E138: Can't write viminfo file %s!"
+msgstr "E138: viminfoƒtƒ@ƒCƒ‹ %s ‚ð•Û‘¶‚Å‚«‚Ü‚¹‚ñ!"
+
+#, c-format
+msgid "Writing viminfo file \"%s\""
+msgstr "viminfoƒtƒ@ƒCƒ‹ \"%s\" ‚ð‘ž‚Ý’†"
+
+#, c-format
+msgid "E886: Can't rename viminfo file to %s!"
+msgstr "E886: viminfoƒtƒ@ƒCƒ‹‚ð %s ‚Ö–¼‘O•ÏX‚Å‚«‚Ü‚¹‚ñ!"
+
+#, c-format
+msgid "# This viminfo file was generated by Vim %s.\n"
+msgstr "# ‚±‚Ì viminfo ƒtƒ@ƒCƒ‹‚Í Vim %s ‚É‚æ‚Á‚Ķ¬‚³‚ê‚Ü‚µ‚½.\n"
+
+msgid ""
+"# You may edit it if you're careful!\n"
+"\n"
+msgstr ""
+"# •ÏX‚·‚éÛ‚É‚Í\\•ª’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢!\n"
+"\n"
+
+msgid "# Value of 'encoding' when this file was written\n"
+msgstr "# ‚±‚̃tƒ@ƒCƒ‹‚ª‘‚©‚ꂽŽž‚Ì 'encoding' ‚Ì’l\n"
+
+msgid "Illegal starting char"
+msgstr "•s³‚È擪•¶Žš‚Å‚·"
+
+msgid ""
+"\n"
+"# Bar lines, copied verbatim:\n"
+msgstr ""
+"\n"
+"# '|' ‚ÅŽn‚Ü‚és‚ÌA•¶Žš’Ê‚è‚̃Rƒs[:\n"
+
+msgid "Save As"
+msgstr "•Ê–¼‚Å•Û‘¶"
+
+msgid "Write partial file?"
+msgstr "ƒtƒ@ƒCƒ‹‚ð•”•ª“I‚É•Û‘¶‚µ‚Ü‚·‚©?"
+
+msgid "E140: Use ! to write partial buffer"
+msgstr "E140: ƒoƒbƒtƒ@‚ð•”•ª“I‚É•Û‘¶‚·‚é‚É‚Í ! ‚ðŽg‚Á‚Ä‚­‚¾‚³‚¢"
+
+#, c-format
+msgid "Overwrite existing file \"%s\"?"
+msgstr "Šù‘¶‚̃tƒ@ƒCƒ‹ \"%s\" ‚ðã‘‚«‚µ‚Ü‚·‚©?"
+
+#, c-format
+msgid "Swap file \"%s\" exists, overwrite anyway?"
+msgstr "ƒXƒƒbƒvƒtƒ@ƒCƒ‹ \"%s\" ‚ª‘¶Ý‚µ‚Ü‚·. ã‘‚«‚ð‹­§‚µ‚Ü‚·‚©?"
+
+#, c-format
+msgid "E768: Swap file exists: %s (:silent! overrides)"
+msgstr "E768: ƒXƒƒbƒvƒtƒ@ƒCƒ‹‚ª‘¶Ý‚µ‚Ü‚·: %s (:silent! ‚ð’ljÁ‚Åã‘)"
+
+#, c-format
+msgid "E141: No file name for buffer %ld"
+msgstr "E141: ƒoƒbƒtƒ@ %ld ‚É‚Í–¼‘O‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "E142: File not written: Writing is disabled by 'write' option"
+msgstr "E142: ƒtƒ@ƒCƒ‹‚Í•Û‘¶‚³‚ê‚Ü‚¹‚ñ‚Å‚µ‚½: 'write' ƒIƒvƒVƒ‡ƒ“‚É‚æ‚è–³Œø‚Å‚·"
+
+#, c-format
+msgid ""
+"'readonly' option is set for \"%s\".\n"
+"Do you wish to write anyway?"
+msgstr ""
+"\"%s\" ‚É‚Í 'readonly' ƒIƒvƒVƒ‡ƒ“‚ªÝ’肳‚ê‚Ä‚¢‚Ü‚·.\n"
+"ã‘‚«‹­§‚ð‚µ‚Ü‚·‚©?"
+
+#, c-format
+msgid ""
+"File permissions of \"%s\" are read-only.\n"
+"It may still be possible to write it.\n"
+"Do you wish to try?"
+msgstr ""
+"ƒtƒ@ƒCƒ‹ \"%s\" ‚̃p[ƒ~ƒbƒVƒ‡ƒ“‚ª“Çžê—p‚Å‚·.\n"
+"‚»‚ê‚Å‚à‹°‚ç‚­‘‚«ž‚Þ‚±‚Ƃ͉”\\‚Å‚·.\n"
+"Œp‘±‚µ‚Ü‚·‚©?"
+
+#, c-format
+msgid "E505: \"%s\" is read-only (add ! to override)"
+msgstr "E505: \"%s\" ‚Í“Çžê—p‚Å‚· (‹­§‘ž‚É‚Í ! ‚ð’ljÁ)"
+
+msgid "Edit File"
+msgstr "ƒtƒ@ƒCƒ‹‚ð•ÒW"
+
+#, c-format
+msgid "E143: Autocommands unexpectedly deleted new buffer %s"
+msgstr "E143: autocommand‚ª—\\Šú‚¹‚¸V‚µ‚¢ƒoƒbƒtƒ@ %s ‚ð휂µ‚Ü‚µ‚½"
+
+msgid "E144: non-numeric argument to :z"
+msgstr "E144: ”‚Å‚Í‚È‚¢ˆø”‚ª :z ‚É“n‚³‚ê‚Ü‚µ‚½"
+
+msgid "E145: Shell commands not allowed in rvim"
+msgstr "E145: rvim‚ł̓VƒFƒ‹ƒRƒ}ƒ“ƒh‚ðŽg‚¦‚Ü‚¹‚ñ"
+
+msgid "E146: Regular expressions can't be delimited by letters"
+msgstr "E146: ³‹K•\\Œ»‚Í•¶Žš‚Å‹æ؂邱‚Æ‚ª‚Å‚«‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "replace with %s (y/n/a/q/l/^E/^Y)?"
+msgstr "%s ‚É’uŠ·‚µ‚Ü‚·‚©? (y/n/a/q/l/^E/^Y)"
+
+msgid "(Interrupted) "
+msgstr "(Š„ž‚Ü‚ê‚Ü‚µ‚½) "
+
+#, c-format
+msgid "%ld match on %ld line"
+msgid_plural "%ld matches on %ld line"
+msgstr[0] "%ld ‰ÓŠŠY“–‚µ‚Ü‚µ‚½ (Œv %ld s“à)"
+
+#, c-format
+msgid "%ld substitution on %ld line"
+msgid_plural "%ld substitutions on %ld line"
+msgstr[0] "%ld ‰ÓŠ’uŠ·‚µ‚Ü‚µ‚½ (Œv %ld s“à)"
+
+#, c-format
+msgid "%ld match on %ld lines"
+msgid_plural "%ld matches on %ld lines"
+msgstr[0] "%ld ‰ÓŠŠY“–‚µ‚Ü‚µ‚½ (Œv %ld s“à)"
+
+#, c-format
+msgid "%ld substitution on %ld lines"
+msgid_plural "%ld substitutions on %ld lines"
+msgstr[0] "%ld ‰ÓŠ’uŠ·‚µ‚Ü‚µ‚½ (Œv %ld s“à)"
+
+msgid "E147: Cannot do :global recursive with a range"
+msgstr "E147: :global ‚ð”͈͕t‚«‚ÅÄ‹A“I‚É‚ÍŽg‚¦‚Ü‚¹‚ñ"
+
+msgid "E148: Regular expression missing from global"
+msgstr "E148: globalƒRƒ}ƒ“ƒh‚ɳ‹K•\\Œ»‚ªŽw’肳‚ê‚Ä‚¢‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "Pattern found in every line: %s"
+msgstr "ƒpƒ^[ƒ“‚ª‘S‚Ä‚Ìs‚ÅŒ©‚‚©‚è‚Ü‚µ‚½: %s"
+
+#, c-format
+msgid "Pattern not found: %s"
+msgstr "ƒpƒ^[ƒ“‚ÍŒ©‚‚©‚è‚Ü‚¹‚ñ‚Å‚µ‚½: %s"
+
+msgid ""
+"\n"
+"# Last Substitute String:\n"
+"$"
+msgstr ""
+"\n"
+"# ÅŒã‚É’uŠ·‚³‚ꂽ•¶Žš—ñ:\n"
+"$"
+
+msgid "E478: Don't panic!"
+msgstr "E478: Q‚Ä‚È‚¢‚Å‚­‚¾‚³‚¢"
+
+#, c-format
+msgid "E661: Sorry, no '%s' help for %s"
+msgstr "E661: Žc”O‚Å‚·‚ª '%s' ‚̃wƒ‹ƒv‚ª %s ‚É‚Í‚ ‚è‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E149: Sorry, no help for %s"
+msgstr "E149: Žc”O‚Å‚·‚ª %s ‚ɂ̓wƒ‹ƒv‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "Sorry, help file \"%s\" not found"
+msgstr "Žc”O‚Å‚·‚ªƒwƒ‹ƒvƒtƒ@ƒCƒ‹ \"%s\" ‚ªŒ©‚‚©‚è‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E151: No match: %s"
+msgstr "E151: ƒ}ƒbƒ`‚Í‚ ‚è‚Ü‚¹‚ñ: %s"
+
+#, c-format
+msgid "E152: Cannot open %s for writing"
+msgstr "E152: ‘ž‚Ý—p‚É %s ‚ðŠJ‚¯‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E153: Unable to open %s for reading"
+msgstr "E153: “Çž—p‚É %s ‚ðŠJ‚¯‚Ü‚¹‚ñ"
+
+# Added at 29-Apr-2004.
+#, c-format
+msgid "E670: Mix of help file encodings within a language: %s"
+msgstr "E670: 1‚‚̌¾Œê‚̃wƒ‹ƒvƒtƒ@ƒCƒ‹‚É•¡”‚̃Gƒ“ƒR[ƒh‚ª¬Ý‚µ‚Ä‚¢‚Ü‚·: %s"
+
+#, c-format
+msgid "E154: Duplicate tag \"%s\" in file %s/%s"
+msgstr "E154: ƒ^ƒO \"%s\" ‚ªƒtƒ@ƒCƒ‹ %s/%s ‚Éd•¡‚µ‚Ä‚¢‚Ü‚·"
+
+#, c-format
+msgid "E150: Not a directory: %s"
+msgstr "E150: ƒfƒBƒŒƒNƒgƒŠ‚Å‚Í‚ ‚è‚Ü‚¹‚ñ: %s"
+
+#, c-format
+msgid "E160: Unknown sign command: %s"
+msgstr "E160: –¢’m‚ÌsignƒRƒ}ƒ“ƒh‚Å‚·: %s"
+
+msgid "E156: Missing sign name"
+msgstr "E156: sign–¼‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "E612: Too many signs defined"
+msgstr "E612: sign‚Ì’è‹`‚ª‘½”Œ©‚‚©‚è‚Ü‚µ‚½"
+
+#, c-format
+msgid "E239: Invalid sign text: %s"
+msgstr "E239: –³Œø‚Èsign‚̃eƒLƒXƒg‚Å‚·: %s"
+
+#, c-format
+msgid "E155: Unknown sign: %s"
+msgstr "E155: –¢’m‚Ìsign‚Å‚·: %s"
+
+msgid "E159: Missing sign number"
+msgstr "E159: sign‚̔Ԇ‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E158: Invalid buffer name: %s"
+msgstr "E158: –³Œø‚ȃoƒbƒtƒ@–¼‚Å‚·: %s"
+
+msgid "E934: Cannot jump to a buffer that does not have a name"
+msgstr "E934: –¼‘O‚Ì–³‚¢ƒoƒbƒtƒ@‚ւ̓Wƒƒƒ“ƒv‚Å‚«‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E157: Invalid sign ID: %ld"
+msgstr "E157: –³Œø‚ÈsignŽ¯•ÊŽq‚Å‚·: %ld"
+
+#, c-format
+msgid "E885: Not possible to change sign %s"
+msgstr "E885: •ÏX‚Å‚«‚È‚¢ sign ‚Å‚·: %s"
+
+# Added at 27-Jan-2004.
+msgid " (NOT FOUND)"
+msgstr " (Œ©‚‚©‚è‚Ü‚¹‚ñ)"
+
+msgid " (not supported)"
+msgstr " (”ñƒTƒ|[ƒg)"
+
+msgid "[Deleted]"
+msgstr "[íœÏ]"
+
+msgid "No old files"
+msgstr "ŒÃ‚¢ƒtƒ@ƒCƒ‹‚Í‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "Entering Debug mode. Type \"cont\" to continue."
+msgstr "ƒfƒoƒbƒOƒ‚[ƒh‚É“ü‚è‚Ü‚·. ‘±‚¯‚é‚É‚Í \"cont\" ‚Æ“ü—Í‚µ‚Ä‚­‚¾‚³‚¢."
+
+#, c-format
+msgid "Oldval = \"%s\""
+msgstr "ŒÃ‚¢’l = \"%s\""
+
+#, c-format
+msgid "Newval = \"%s\""
+msgstr "V‚µ‚¢’l = \"%s\""
+
+#, c-format
+msgid "line %ld: %s"
+msgstr "s %ld: %s"
+
+#, c-format
+msgid "cmd: %s"
+msgstr "ƒRƒ}ƒ“ƒh: %s"
+
+msgid "frame is zero"
+msgstr "ƒtƒŒ[ƒ€‚ª 0 ‚Å‚·"
+
+#, c-format
+msgid "frame at highest level: %d"
+msgstr "Å‚ƒŒƒxƒ‹‚̃tƒŒ[ƒ€: %d"
+
+#, c-format
+msgid "Breakpoint in \"%s%s\" line %ld"
+msgstr "ƒuƒŒ[ƒNƒ|ƒCƒ“ƒg \"%s%s\" s %ld"
+
+#, c-format
+msgid "E161: Breakpoint not found: %s"
+msgstr "E161: ƒuƒŒ[ƒNƒ|ƒCƒ“ƒg‚ªŒ©‚‚©‚è‚Ü‚¹‚ñ: %s"
+
+msgid "No breakpoints defined"
+msgstr "ƒuƒŒ[ƒNƒ|ƒCƒ“ƒg‚ª’è‹`‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "%3d %s %s line %ld"
+msgstr "%3d %s %s s %ld"
+
+#, c-format
+msgid "%3d expr %s"
+msgstr "%3d expr %s"
+
+msgid "E750: First use \":profile start {fname}\""
+msgstr "E750: ‰‚ß‚É \":profile start {fname}\" ‚ðŽÀs‚µ‚Ä‚­‚¾‚³‚¢"
+
+#, c-format
+msgid "Save changes to \"%s\"?"
+msgstr "•ÏX‚ð \"%s\" ‚É•Û‘¶‚µ‚Ü‚·‚©?"
+
+#, c-format
+msgid "E947: Job still running in buffer \"%s\""
+msgstr "E947: ƒWƒ‡ƒu‚̓oƒbƒtƒ@ \"%s\" ‚Å‚Ü‚¾ŽÀs’†‚Å‚·"
+
+#, c-format
+msgid "E162: No write since last change for buffer \"%s\""
+msgstr "E162: ƒoƒbƒtƒ@ \"%s\" ‚Ì•ÏX‚Í•Û‘¶‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ"
+
+msgid "Warning: Entered other buffer unexpectedly (check autocommands)"
+msgstr "Œx: —\\Šú‚¹‚¸‘¼ƒoƒbƒtƒ@‚ÖˆÚ“®‚µ‚Ü‚µ‚½ (autocommands ‚𒲂ׂĂ­‚¾‚³‚¢)"
+
+msgid "E163: There is only one file to edit"
+msgstr "E163: •ÒW‚·‚éƒtƒ@ƒCƒ‹‚Í1‚‚µ‚©‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "E164: Cannot go before first file"
+msgstr "E164: ʼn‚̃tƒ@ƒCƒ‹‚æ‚è‘O‚É‚Ís‚¯‚Ü‚¹‚ñ"
+
+msgid "E165: Cannot go beyond last file"
+msgstr "E165: ÅŒã‚̃tƒ@ƒCƒ‹‚ð‰z‚¦‚ÄŒã‚É‚Ís‚¯‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E666: compiler not supported: %s"
+msgstr "E666: ‚»‚̃Rƒ“ƒpƒCƒ‰‚ɂ͑Ήž‚µ‚Ä‚¢‚Ü‚¹‚ñ: %s"
+
+#, c-format
+msgid "Searching for \"%s\" in \"%s\""
+msgstr "\"%s\" ‚ð \"%s\" ‚©‚猟õ’†"
+
+#, c-format
+msgid "Searching for \"%s\""
+msgstr "\"%s\" ‚ðŒŸõ’†"
+
+#, c-format
+msgid "not found in '%s': \"%s\""
+msgstr "'%s' ‚Ì’†‚É‚Í‚ ‚è‚Ü‚¹‚ñ: \"%s\""
+
+#, c-format
+msgid "W20: Required python version 2.x not supported, ignoring file: %s"
+msgstr "W20: —v‹‚³‚ꂽpython 2.x‚͑Ήž‚µ‚Ä‚¢‚Ü‚¹‚ñAƒtƒ@ƒCƒ‹‚𖳎‹‚µ‚Ü‚·: %s"
+
+#, c-format
+msgid "W21: Required python version 3.x not supported, ignoring file: %s"
+msgstr "W21: —v‹‚³‚ꂽpython 3.x‚͑Ήž‚µ‚Ä‚¢‚Ü‚¹‚ñAƒtƒ@ƒCƒ‹‚𖳎‹‚µ‚Ü‚·: %s"
+
+msgid "Source Vim script"
+msgstr "VimƒXƒNƒŠƒvƒg‚ÌŽæž‚Ý"
+
+#, c-format
+msgid "Cannot source a directory: \"%s\""
+msgstr "ƒfƒBƒŒƒNƒgƒŠ‚ÍŽæž‚ß‚Ü‚¹‚ñ: \"%s\""
+
+#, c-format
+msgid "could not source \"%s\""
+msgstr "\"%s\" ‚ðŽæž‚ß‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "line %ld: could not source \"%s\""
+msgstr "s %ld: \"%s\" ‚ðŽæž‚ß‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "sourcing \"%s\""
+msgstr "\"%s\" ‚ðŽæž’†"
+
+#, c-format
+msgid "line %ld: sourcing \"%s\""
+msgstr "s %ld: %s ‚ðŽæž’†"
+
+#, c-format
+msgid "finished sourcing %s"
+msgstr "%s ‚ÌŽæž‚ðŠ®—¹"
+
+#, c-format
+msgid "continuing in %s"
+msgstr "%s ‚ÌŽÀs‚ðŒp‘±’†‚Å‚·"
+
+msgid "modeline"
+msgstr "ƒ‚[ƒhs"
+
+msgid "--cmd argument"
+msgstr "--cmd ˆø”"
+
+msgid "-c argument"
+msgstr "-c ˆø”"
+
+msgid "environment variable"
+msgstr "ŠÂ‹«•Ï”"
+
+msgid "error handler"
+msgstr "ƒGƒ‰[ƒnƒ“ƒhƒ‰"
+
+msgid "W15: Warning: Wrong line separator, ^M may be missing"
+msgstr "W15: Œx: s‹æØ‚ª•s³‚Å‚·. ^M ‚ª‚È‚¢‚Ì‚Å‚µ‚傤"
+
+msgid "E167: :scriptencoding used outside of a sourced file"
+msgstr "E167: :scriptencoding ‚ªŽæžƒXƒNƒŠƒvƒgˆÈŠO‚ÅŽg—p‚³‚ê‚Ü‚µ‚½"
+
+msgid "E168: :finish used outside of a sourced file"
+msgstr "E168: :finish ‚ªŽæžƒXƒNƒŠƒvƒgˆÈŠO‚ÅŽg—p‚³‚ê‚Ü‚µ‚½"
+
+#, c-format
+msgid "Current %slanguage: \"%s\""
+msgstr "Œ»Ý‚Ì %sŒ¾Œê: \"%s\""
+
+#, c-format
+msgid "E197: Cannot set language to \"%s\""
+msgstr "E197: Œ¾Œê‚ð \"%s\" ‚ÉÝ’è‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "Entering Ex mode. Type \"visual\" to go to Normal mode."
+msgstr ""
+"Exƒ‚[ƒh‚É“ü‚è‚Ü‚·. ƒm[ƒ}ƒ‹ƒ‚[ƒh‚É–ß‚é‚É‚Í\"visual\"‚Æ“ü—Í‚µ‚Ä‚­‚¾‚³‚¢."
+
+msgid "E501: At end-of-file"
+msgstr "E501: ƒtƒ@ƒCƒ‹‚ÌI—¹ˆÊ’u"
+
+msgid "E169: Command too recursive"
+msgstr "E169: ƒRƒ}ƒ“ƒh‚ªÄ‹A“I‰ß‚¬‚Ü‚·"
+
+#, c-format
+msgid "E605: Exception not caught: %s"
+msgstr "E605: —áŠO‚ª•ß‘¨‚³‚ê‚Ü‚¹‚ñ‚Å‚µ‚½: %s"
+
+msgid "End of sourced file"
+msgstr "Žæžƒtƒ@ƒCƒ‹‚ÌÅŒã‚Å‚·"
+
+msgid "End of function"
+msgstr "ŠÖ”‚ÌÅŒã‚Å‚·"
+
+msgid "E464: Ambiguous use of user-defined command"
+msgstr "E464: ƒ†[ƒU[’è‹`ƒRƒ}ƒ“ƒh‚Ì‚ ‚¢‚Ü‚¢‚ÈŽg—p‚Å‚·"
+
+msgid "E492: Not an editor command"
+msgstr "E492: ƒGƒfƒBƒ^‚̃Rƒ}ƒ“ƒh‚Å‚Í‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "E493: Backwards range given"
+msgstr "E493: ‹t‚³‚܂͈̔͂ªŽw’肳‚ê‚Ü‚µ‚½"
+
+msgid "Backwards range given, OK to swap"
+msgstr "‹t‚³‚܂͈̔͂ªŽw’肳‚ê‚Ü‚µ‚½A“ü‘Ö‚¦‚Ü‚·‚©?"
+
+msgid "E494: Use w or w>>"
+msgstr "E494: w ‚à‚µ‚­‚Í w>> ‚ðŽg—p‚µ‚Ä‚­‚¾‚³‚¢"
+
+msgid "E943: Command table needs to be updated, run 'make cmdidxs'"
+msgstr ""
+"E943: ƒRƒ}ƒ“ƒhƒe[ƒuƒ‹‚ðXV‚·‚é•K—v‚ª‚ ‚è‚Ü‚·A'make cmdidxs' ‚ðŽÀs‚µ‚Ä‚­‚¾"
+"‚³‚¢"
+
+msgid "E319: Sorry, the command is not available in this version"
+msgstr "E319: ‚±‚̃o[ƒWƒ‡ƒ“‚Å‚Í‚±‚̃Rƒ}ƒ“ƒh‚Í—˜—p‚Å‚«‚Ü‚¹‚ñA‚²‚ß‚ñ‚È‚³‚¢"
+
+#, c-format
+msgid "%d more file to edit. Quit anyway?"
+msgid_plural "%d more files to edit. Quit anyway?"
+msgstr[0] "•ÒW‚·‚ׂ«ƒtƒ@ƒCƒ‹‚ª‚ ‚Æ %d ŒÂ‚ ‚è‚Ü‚·‚ªAI—¹‚µ‚Ü‚·‚©?"
+
+#, c-format
+msgid "E173: %ld more file to edit"
+msgid_plural "E173: %ld more files to edit"
+msgstr[0] "E173: •ÒW‚·‚ׂ«ƒtƒ@ƒCƒ‹‚ª‚ ‚Æ %ld ŒÂ‚ ‚è‚Ü‚·"
+
+msgid "E174: Command already exists: add ! to replace it"
+msgstr "E174: ƒRƒ}ƒ“ƒh‚ªŠù‚É‚ ‚è‚Ü‚·: Ä’è‹`‚·‚é‚É‚Í ! ‚ð’ljÁ‚µ‚Ä‚­‚¾‚³‚¢"
+
+msgid ""
+"\n"
+" Name Args Address Complete Definition"
+msgstr ""
+"\n"
+" –¼‘O ˆø” ƒAƒhƒŒƒX •âŠ® ’è‹`"
+
+msgid "No user-defined commands found"
+msgstr "ƒ†[ƒU[’è‹`ƒRƒ}ƒ“ƒh‚ªŒ©‚‚©‚è‚Ü‚¹‚ñ‚Å‚µ‚½"
+
+msgid "E175: No attribute specified"
+msgstr "E175: ‘®«‚Í’è‹`‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ"
+
+msgid "E176: Invalid number of arguments"
+msgstr "E176: ˆø”‚Ì”‚ª–³Œø‚Å‚·"
+
+msgid "E177: Count cannot be specified twice"
+msgstr "E177: ƒJƒEƒ“ƒg‚ð2dŽw’è‚·‚邱‚Æ‚Í‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "E178: Invalid default value for count"
+msgstr "E178: ƒJƒEƒ“ƒg‚ÌÈ—ª’l‚ª–³Œø‚Å‚·"
+
+msgid "E179: argument required for -complete"
+msgstr "E179: -complete ‚ɂ͈ø”‚ª•K—v‚Å‚·"
+
+msgid "E179: argument required for -addr"
+msgstr "E179: -addr ‚ɂ͈ø”‚ª•K—v‚Å‚·"
+
+#, c-format
+msgid "E181: Invalid attribute: %s"
+msgstr "E181: –³Œø‚È‘®«‚Å‚·: %s"
+
+msgid "E182: Invalid command name"
+msgstr "E182: –³Œø‚ȃRƒ}ƒ“ƒh–¼‚Å‚·"
+
+msgid "E183: User defined commands must start with an uppercase letter"
+msgstr "E183: ƒ†[ƒU[’è‹`ƒRƒ}ƒ“ƒh‚͉p‘啶Žš‚ÅŽn‚Ü‚ç‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñ"
+
+msgid "E841: Reserved name, cannot be used for user defined command"
+msgstr "E841: —\\–ñ–¼‚È‚Ì‚ÅAƒ†[ƒU[’è‹`ƒRƒ}ƒ“ƒh‚É—˜—p‚Å‚«‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E184: No such user-defined command: %s"
+msgstr "E184: ‚»‚̃†[ƒU[’è‹`ƒRƒ}ƒ“ƒh‚Í‚ ‚è‚Ü‚¹‚ñ: %s"
+
+#, c-format
+msgid "E180: Invalid address type value: %s"
+msgstr "E180: –³Œø‚ȃAƒhƒŒƒXƒ^ƒCƒv’l‚Å‚·: %s"
+
+#, c-format
+msgid "E180: Invalid complete value: %s"
+msgstr "E180: –³Œø‚ȕ⊮Žw’è‚Å‚·: %s"
+
+msgid "E468: Completion argument only allowed for custom completion"
+msgstr "E468: •âŠ®ˆø”‚̓JƒXƒ^ƒ€•âŠ®‚Å‚µ‚©Žg—p‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "E467: Custom completion requires a function argument"
+msgstr "E467: ƒJƒXƒ^ƒ€•âŠ®‚ɂ͈ø”‚Æ‚µ‚ÄŠÖ”‚ª•K—v‚Å‚·"
+
+msgid "unknown"
+msgstr "•s–¾"
+
+#, c-format
+msgid "E185: Cannot find color scheme '%s'"
+msgstr "E185: ƒJƒ‰[ƒXƒL[ƒ€ '%s' ‚ªŒ©‚‚©‚è‚Ü‚¹‚ñ"
+
+msgid "Greetings, Vim user!"
+msgstr "Vim Žg‚¢‚³‚ñA‚â‚ !"
+
+msgid "E784: Cannot close last tab page"
+msgstr "E784: ÅŒã‚̃^ƒuƒy[ƒW‚ð•Â‚¶‚邱‚Æ‚Í‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "Already only one tab page"
+msgstr "Šù‚Ƀ^ƒuƒy[ƒW‚Í1‚‚µ‚©‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "Edit File in new tab page"
+msgstr "V‚µ‚¢ƒ^ƒuƒy[ƒW‚Ńtƒ@ƒCƒ‹‚ð•ÒW‚µ‚Ü‚·"
+
+msgid "Edit File in new window"
+msgstr "V‚µ‚¢ƒEƒBƒ“ƒhƒE‚Ńtƒ@ƒCƒ‹‚ð•ÒW‚µ‚Ü‚·"
+
+#, c-format
+msgid "Tab page %d"
+msgstr "ƒ^ƒuƒy[ƒW %d"
+
+msgid "No swap file"
+msgstr "ƒXƒƒbƒvƒtƒ@ƒCƒ‹‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "Append File"
+msgstr "’ljÁƒtƒ@ƒCƒ‹"
+
+msgid "E747: Cannot change directory, buffer is modified (add ! to override)"
+msgstr ""
+"E747: ƒoƒbƒtƒ@‚ªC³‚³‚ê‚Ä‚¢‚é‚Ì‚ÅAƒfƒBƒŒƒNƒgƒŠ‚ð•ÏX‚Å‚«‚Ü‚¹‚ñ (! ‚ð’ljÁ‚Å"
+"ã‘)"
+
+msgid "E186: No previous directory"
+msgstr "E186: ‘O‚̃fƒBƒŒƒNƒgƒŠ‚Í‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "E187: Unknown"
+msgstr "E187: –¢’m"
+
+msgid "E465: :winsize requires two number arguments"
+msgstr "E465: :winsize ‚É‚Í2‚‚̔’l‚̈ø”‚ª•K—v‚Å‚·"
+
+#, c-format
+msgid "Window position: X %d, Y %d"
+msgstr "ƒEƒBƒ“ƒhƒEˆÊ’u: X %d, Y %d"
+
+msgid "E188: Obtaining window position not implemented for this platform"
+msgstr ""
+"E188: ‚±‚̃vƒ‰ƒbƒgƒz[ƒ€‚ɂ̓EƒBƒ“ƒhƒEˆÊ’u‚̎擾‹@”\\‚ÍŽÀ‘•‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ"
+
+msgid "E466: :winpos requires two number arguments"
+msgstr "E466: :winpos ‚É‚Í2‚‚̔’l‚̈ø”‚ª•K—v‚Å‚·"
+
+msgid "E930: Cannot use :redir inside execute()"
+msgstr "E930: execute() ‚Ì’†‚Å‚Í :redir ‚ÍŽg‚¦‚Ü‚¹‚ñ"
+
+msgid "Save Redirection"
+msgstr "ƒŠƒ_ƒCƒŒƒNƒg‚ð•Û‘¶‚µ‚Ü‚·"
+
+msgid "Save View"
+msgstr "ƒrƒ…[‚ð•Û‘¶‚µ‚Ü‚·"
+
+msgid "Save Session"
+msgstr "ƒZƒbƒVƒ‡ƒ“î•ñ‚ð•Û‘¶‚µ‚Ü‚·"
+
+msgid "Save Setup"
+msgstr "Ý’è‚ð•Û‘¶‚µ‚Ü‚·"
+
+#, c-format
+msgid "E739: Cannot create directory: %s"
+msgstr "E739: ƒfƒBƒŒƒNƒgƒŠ‚ð쬂ł«‚Ü‚¹‚ñ: %s"
+
+#, c-format
+msgid "E189: \"%s\" exists (add ! to override)"
+msgstr "E189: \"%s\" ‚ª‘¶Ý‚µ‚Ü‚· (ã‘‚·‚é‚É‚Í ! ‚ð’ljÁ‚µ‚Ä‚­‚¾‚³‚¢)"
+
+#, c-format
+msgid "E190: Cannot open \"%s\" for writing"
+msgstr "E190: \"%s\" ‚ð‘ž‚Ý—p‚Æ‚µ‚ÄŠJ‚¯‚Ü‚¹‚ñ"
+
+msgid "E191: Argument must be a letter or forward/backward quote"
+msgstr "E191: ˆø”‚Í1•¶Žš‚̉pŽš‚©ˆø—p•„ (' ‚© `) ‚Å‚È‚¯‚ê‚΂¢‚¯‚Ü‚¹‚ñ"
+
+msgid "E192: Recursive use of :normal too deep"
+msgstr "E192: :normal ‚ÌÄ‹A—˜—p‚ª[‚­‚È‚è‰ß‚¬‚Ü‚µ‚½"
+
+msgid "E809: #< is not available without the +eval feature"
+msgstr "E809: #< ‚Í +eval ‹@”\\‚ª–³‚¢‚Æ—˜—p‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "E194: No alternate file name to substitute for '#'"
+msgstr "E194: '#'‚ð’u‚«Š·‚¦‚é•›ƒtƒ@ƒCƒ‹‚Ì–¼‘O‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "E495: no autocommand file name to substitute for \"<afile>\""
+msgstr "E495: \"<afile>\"‚ð’u‚«Š·‚¦‚éautocommand‚̃tƒ@ƒCƒ‹–¼‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "E496: no autocommand buffer number to substitute for \"<abuf>\""
+msgstr "E496: \"<abuf>\"‚ð’u‚«Š·‚¦‚éautocommandƒoƒbƒtƒ@”Ô†‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "E497: no autocommand match name to substitute for \"<amatch>\""
+msgstr "E497: \"<amatch>\"‚ð’u‚«Š·‚¦‚éautocommand‚ÌŠY“––¼‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "E498: no :source file name to substitute for \"<sfile>\""
+msgstr "E498: \"<sfile>\"‚ð’u‚«Š·‚¦‚é :source ‘ÎÛƒtƒ@ƒCƒ‹–¼‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "E842: no line number to use for \"<slnum>\""
+msgstr "E842: \"<slnum>\"‚ð’u‚«Š·‚¦‚és”Ô†‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "E961: no line number to use for \"<sflnum>\""
+msgstr "E961: \"<sflnum>\"‚ð’u‚«Š·‚¦‚és”Ô†‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+#, no-c-format
+msgid "E499: Empty file name for '%' or '#', only works with \":p:h\""
+msgstr ""
+"E499: '%' ‚â '#' ‚ª–³–¼ƒtƒ@ƒCƒ‹‚È‚Ì‚Å \":p:h\" ‚𔺂í‚È‚¢Žg‚¢•û‚Í‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "E500: Evaluates to an empty string"
+msgstr "E500: ‹ó•¶Žš—ñ‚Æ‚µ‚Ä•]‰¿‚³‚ê‚Ü‚µ‚½"
+
+msgid "E195: Cannot open viminfo file for reading"
+msgstr "E195: viminfoƒtƒ@ƒCƒ‹‚ð“Çž—p‚Æ‚µ‚ÄŠJ‚¯‚Ü‚¹‚ñ"
+
+msgid "Untitled"
+msgstr "–³‘è"
+
+msgid "E196: No digraphs in this version"
+msgstr "E196: ‚±‚̃o[ƒWƒ‡ƒ“‚ɇŽš‚Í‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "E608: Cannot :throw exceptions with 'Vim' prefix"
+msgstr "E608: 'Vim' ‚ÅŽn‚Ü‚é—áŠO‚Í :throw ‚Å‚«‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "Exception thrown: %s"
+msgstr "—áŠO‚ª”­¶‚µ‚Ü‚µ‚½: %s"
+
+#, c-format
+msgid "Exception finished: %s"
+msgstr "—áŠO‚ªŽû‘©‚µ‚Ü‚µ‚½: %s"
+
+#, c-format
+msgid "Exception discarded: %s"
+msgstr "—áŠO‚ª”jŠü‚³‚ê‚Ü‚µ‚½: %s"
+
+#, c-format
+msgid "%s, line %ld"
+msgstr "%s, s %ld"
+
+#, c-format
+msgid "Exception caught: %s"
+msgstr "—áŠO‚ª•ß‘¨‚³‚ê‚Ü‚µ‚½: %s"
+
+#, c-format
+msgid "%s made pending"
+msgstr "%s ‚É‚æ‚è–¢Œˆ’èó‘Ô‚ª¶‚¶‚Ü‚µ‚½"
+
+#, c-format
+msgid "%s resumed"
+msgstr "%s ‚ªÄŠJ‚µ‚Ü‚µ‚½"
+
+#, c-format
+msgid "%s discarded"
+msgstr "%s ‚ª”jŠü‚³‚ê‚Ü‚µ‚½"
+
+msgid "Exception"
+msgstr "—áŠO"
+
+msgid "Error and interrupt"
+msgstr "ƒGƒ‰[‚ÆŠ„ž‚Ý"
+
+msgid "Error"
+msgstr "ƒGƒ‰["
+
+msgid "Interrupt"
+msgstr "Š„ž‚Ý"
+
+msgid "E579: :if nesting too deep"
+msgstr "E579: :if ‚Ì“ü‚êŽq‚ª[‰ß‚¬‚Ü‚·"
+
+msgid "E580: :endif without :if"
+msgstr "E580: :if ‚Ì‚È‚¢ :endif ‚ª‚ ‚è‚Ü‚·"
+
+msgid "E581: :else without :if"
+msgstr "E581: :if ‚Ì‚È‚¢ :else ‚ª‚ ‚è‚Ü‚·"
+
+msgid "E582: :elseif without :if"
+msgstr "E582: :if ‚Ì‚È‚¢ :elseif ‚ª‚ ‚è‚Ü‚·"
+
+msgid "E583: multiple :else"
+msgstr "E583: •¡”‚Ì :else ‚ª‚ ‚è‚Ü‚·"
+
+msgid "E584: :elseif after :else"
+msgstr "E584: :else ‚ÌŒã‚É :elseif ‚ª‚ ‚è‚Ü‚·"
+
+msgid "E585: :while/:for nesting too deep"
+msgstr "E585: :while ‚â :for ‚Ì“ü‚êŽq‚ª[‰ß‚¬‚Ü‚·"
+
+msgid "E586: :continue without :while or :for"
+msgstr "E586: :while ‚â :for ‚Ì‚È‚¢ :continue ‚ª‚ ‚è‚Ü‚·"
+
+msgid "E587: :break without :while or :for"
+msgstr "E587: :while ‚â :for ‚Ì‚È‚¢ :break ‚ª‚ ‚è‚Ü‚·"
+
+msgid "E732: Using :endfor with :while"
+msgstr "E732: :endfor ‚ð :while ‚Æ‘g‚݇‚킹‚Ä‚¢‚Ü‚·"
+
+msgid "E733: Using :endwhile with :for"
+msgstr "E733: :endwhile ‚ð :for ‚Æ‘g‚݇‚킹‚Ä‚¢‚Ü‚·"
+
+msgid "E601: :try nesting too deep"
+msgstr "E601: :try ‚Ì“ü‚êŽq‚ª[‰ß‚¬‚Ü‚·"
+
+msgid "E603: :catch without :try"
+msgstr "E603: :try ‚Ì‚È‚¢ :catch ‚ª‚ ‚è‚Ü‚·"
+
+msgid "E604: :catch after :finally"
+msgstr "E604: :finally ‚ÌŒã‚É :catch ‚ª‚ ‚è‚Ü‚·"
+
+msgid "E606: :finally without :try"
+msgstr "E606: :try ‚Ì‚È‚¢ :finally ‚ª‚ ‚è‚Ü‚·"
+
+msgid "E607: multiple :finally"
+msgstr "E607: •¡”‚Ì :finally ‚ª‚ ‚è‚Ü‚·"
+
+msgid "E602: :endtry without :try"
+msgstr "E602: :try ‚Ì‚È‚¢ :endtry ‚Å‚·"
+
+msgid "E193: :endfunction not inside a function"
+msgstr "E193: ŠÖ”‚ÌŠO‚É :endfunction ‚ª‚ ‚è‚Ü‚µ‚½"
+
+msgid "E788: Not allowed to edit another buffer now"
+msgstr "E788: Œ»Ý‚Í‘¼‚̃oƒbƒtƒ@‚ð•ÒW‚·‚邱‚Æ‚Í‹–‚³‚ê‚Ü‚¹‚ñ"
+
+msgid "E811: Not allowed to change buffer information now"
+msgstr "E811: Œ»Ý‚̓oƒbƒtƒ@î•ñ‚ð•ÏX‚·‚邱‚Æ‚Í‹–‚³‚ê‚Ü‚¹‚ñ"
+
+msgid "tagname"
+msgstr "ƒ^ƒO–¼"
+
+msgid " kind file\n"
+msgstr " ƒtƒ@ƒCƒ‹Ží—Þ\n"
+
+msgid "'history' option is zero"
+msgstr "ƒIƒvƒVƒ‡ƒ“ 'history' ‚ªƒ[ƒ‚Å‚·"
+
+#, c-format
+msgid ""
+"\n"
+"# %s History (newest to oldest):\n"
+msgstr ""
+"\n"
+"# %s €–Ú‚Ì—š—ð (V‚µ‚¢‚à‚Ì‚©‚çŒÃ‚¢‚à‚Ì‚Ö):\n"
+
+msgid "Command Line"
+msgstr "ƒRƒ}ƒ“ƒhƒ‰ƒCƒ“"
+
+msgid "Search String"
+msgstr "ŒŸõ•¶Žš—ñ"
+
+msgid "Expression"
+msgstr "Ž®"
+
+msgid "Input Line"
+msgstr "“ü—Ís"
+
+msgid "Debug Line"
+msgstr "ƒfƒoƒbƒOs"
+
+msgid "E198: cmd_pchar beyond the command length"
+msgstr "E198: cmd_pchar ‚ªƒRƒ}ƒ“ƒh’·‚ð’´‚¦‚Ü‚µ‚½"
+
+msgid "E199: Active window or buffer deleted"
+msgstr "E199: ƒAƒNƒeƒBƒu‚ȃEƒBƒ“ƒhƒE‚©ƒoƒbƒtƒ@‚ªíœ‚³‚ê‚Ü‚µ‚½"
+
+msgid "E812: Autocommands changed buffer or buffer name"
+msgstr "E812: autocommand‚ªƒoƒbƒtƒ@‚©ƒoƒbƒtƒ@–¼‚ð•ÏX‚µ‚Ü‚µ‚½"
+
+msgid "Illegal file name"
+msgstr "•s³‚ȃtƒ@ƒCƒ‹–¼"
+
+msgid "is a directory"
+msgstr "‚̓fƒBƒŒƒNƒgƒŠ‚Å‚·"
+
+msgid "is not a file"
+msgstr "‚̓tƒ@ƒCƒ‹‚Å‚Í‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "is a device (disabled with 'opendevice' option)"
+msgstr "‚̓fƒoƒCƒX‚Å‚· ('opendevice' ƒIƒvƒVƒ‡ƒ“‚ʼnñ”ð‚Å‚«‚Ü‚·)"
+
+msgid "[New File]"
+msgstr "[Vƒtƒ@ƒCƒ‹]"
+
+msgid "[New DIRECTORY]"
+msgstr "[V‹KƒfƒBƒŒƒNƒgƒŠ]"
+
+msgid "[File too big]"
+msgstr "[ƒtƒ@ƒCƒ‹‰ß‘å]"
+
+msgid "[Permission Denied]"
+msgstr "[Œ ŒÀ‚ª‚ ‚è‚Ü‚¹‚ñ]"
+
+msgid "E200: *ReadPre autocommands made the file unreadable"
+msgstr "E200: *ReadPre autocommand ‚ªƒtƒ@ƒCƒ‹‚ð“Çž•s‰Â‚É‚µ‚Ü‚µ‚½"
+
+msgid "E201: *ReadPre autocommands must not change current buffer"
+msgstr "E201: *ReadPre autocommand ‚ÍŒ»Ý‚̃oƒbƒtƒ@‚ð•Ï‚¦‚ç‚ê‚Ü‚¹‚ñ"
+
+msgid "Vim: Reading from stdin...\n"
+msgstr "Vim: •W€“ü—Í‚©‚ç“Çž’†...\n"
+
+msgid "Reading from stdin..."
+msgstr "•W€“ü—Í‚©‚ç“Çž‚Ý’†..."
+
+msgid "E202: Conversion made file unreadable!"
+msgstr "E202: •ÏŠ·‚ªƒtƒ@ƒCƒ‹‚ð“Çž•s‰Â‚É‚µ‚Ü‚µ‚½"
+
+msgid "[fifo]"
+msgstr "[FIFO]"
+
+msgid "[socket]"
+msgstr "[ƒ\\ƒPƒbƒg]"
+
+msgid "[character special]"
+msgstr "[ƒLƒƒƒ‰ƒNƒ^EƒfƒoƒCƒX]"
+
+msgid "[CR missing]"
+msgstr "[CR–³]"
+
+msgid "[long lines split]"
+msgstr "[’·s•ªŠ„]"
+
+msgid "[NOT converted]"
+msgstr "[–¢•ÏŠ·]"
+
+msgid "[converted]"
+msgstr "[•ÏŠ·Ï]"
+
+#, c-format
+msgid "[CONVERSION ERROR in line %ld]"
+msgstr "[%ld s–Ú‚Å•ÏŠ·ƒGƒ‰[]"
+
+#, c-format
+msgid "[ILLEGAL BYTE in line %ld]"
+msgstr "[%ld s–Ú‚Ì•s³‚ȃoƒCƒg]"
+
+msgid "[READ ERRORS]"
+msgstr "[“ÇžƒGƒ‰[]"
+
+msgid "Can't find temp file for conversion"
+msgstr "•ÏŠ·‚É•K—v‚Ȉꎞƒtƒ@ƒCƒ‹‚ªŒ©‚‚©‚è‚Ü‚¹‚ñ"
+
+msgid "Conversion with 'charconvert' failed"
+msgstr "'charconvert' ‚É‚æ‚é•ÏŠ·‚ªŽ¸”s‚µ‚Ü‚µ‚½"
+
+msgid "can't read output of 'charconvert'"
+msgstr "'charconvert' ‚Ìo—Í‚ð“Çž‚ß‚Ü‚¹‚ñ‚Å‚µ‚½"
+
+msgid "E676: No matching autocommands for acwrite buffer"
+msgstr "E676: acwriteƒoƒbƒtƒ@‚ÌŠY“–‚·‚éautocommand‚Í‘¶Ý‚µ‚Ü‚¹‚ñ"
+
+msgid "E203: Autocommands deleted or unloaded buffer to be written"
+msgstr "E203: •Û‘¶‚·‚éƒoƒbƒtƒ@‚ðautocommand‚ªíœ‚©‰ð•ú‚µ‚Ü‚µ‚½"
+
+msgid "E204: Autocommand changed number of lines in unexpected way"
+msgstr "E204: autocommand‚ª—\\Šú‚¹‚Ê•û–@‚Ås”‚ð•ÏX‚µ‚Ü‚µ‚½"
+
+# Added at 19-Jan-2004.
+msgid "NetBeans disallows writes of unmodified buffers"
+msgstr "NetBeans‚Í–¢•ÏX‚̃oƒbƒtƒ@‚ðã‘‚·‚邱‚Æ‚Í‹–‰Â‚µ‚Ä‚¢‚Ü‚¹‚ñ"
+
+msgid "Partial writes disallowed for NetBeans buffers"
+msgstr "NetBeansƒoƒbƒtƒ@‚̈ꕔ‚ð‘‚«o‚·‚±‚Æ‚Í‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "is not a file or writable device"
+msgstr "‚̓tƒ@ƒCƒ‹‚Å‚à‘ž‚݉”\\ƒfƒoƒCƒX‚Å‚à‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "writing to device disabled with 'opendevice' option"
+msgstr "'opendevice' ƒIƒvƒVƒ‡ƒ“‚É‚æ‚èƒfƒoƒCƒX‚Ö‚Ì‘‚«ž‚Ý‚Í‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "is read-only (add ! to override)"
+msgstr "‚Í“Çžê—p‚Å‚· (‹­§‘ž‚É‚Í ! ‚ð’ljÁ)"
+
+msgid "E506: Can't write to backup file (add ! to override)"
+msgstr "E506: ƒoƒbƒNƒAƒbƒvƒtƒ@ƒCƒ‹‚ð•Û‘¶‚Å‚«‚Ü‚¹‚ñ (! ‚ð’ljÁ‚Å‹­§•Û‘¶)"
+
+msgid "E507: Close error for backup file (add ! to override)"
+msgstr ""
+"E507: ƒoƒbƒNƒAƒbƒvƒtƒ@ƒCƒ‹‚ð•Â‚¶‚éۂɃGƒ‰[‚ª”­¶‚µ‚Ü‚µ‚½ (! ‚ð’ljÁ‚Å‹­§)"
+
+msgid "E508: Can't read file for backup (add ! to override)"
+msgstr "E508: ƒoƒbƒNƒAƒbƒv—pƒtƒ@ƒCƒ‹‚ð“Çž‚ß‚Ü‚¹‚ñ (! ‚ð’ljÁ‚Å‹­§“Çž)"
+
+msgid "E509: Cannot create backup file (add ! to override)"
+msgstr "E509: ƒoƒbƒNƒAƒbƒvƒtƒ@ƒCƒ‹‚ðì‚ê‚Ü‚¹‚ñ (! ‚ð’ljÁ‚Å‹­§ì¬)"
+
+msgid "E510: Can't make backup file (add ! to override)"
+msgstr "E510: ƒoƒbƒNƒAƒbƒvƒtƒ@ƒCƒ‹‚ðì‚ê‚Ü‚¹‚ñ (! ‚ð’ljÁ‚Å‹­§ì¬)"
+
+msgid "E214: Can't find temp file for writing"
+msgstr "E214: •Û‘¶—pˆêŽžƒtƒ@ƒCƒ‹‚ªŒ©‚‚©‚è‚Ü‚¹‚ñ"
+
+msgid "E213: Cannot convert (add ! to write without conversion)"
+msgstr "E213: •ÏŠ·‚Å‚«‚Ü‚¹‚ñ (! ‚ð’ljÁ‚Å•ÏŠ·‚¹‚¸‚É•Û‘¶)"
+
+msgid "E166: Can't open linked file for writing"
+msgstr "E166: ƒŠƒ“ƒN‚³‚ꂽƒtƒ@ƒCƒ‹‚É‘ž‚ß‚Ü‚¹‚ñ"
+
+msgid "E212: Can't open file for writing"
+msgstr "E212: ‘ž‚Ý—p‚Ƀtƒ@ƒCƒ‹‚ðŠJ‚¯‚Ü‚¹‚ñ"
+
+msgid "E949: File changed while writing"
+msgstr "E949: ‘ž‚Ý’†‚Ƀtƒ@ƒCƒ‹‚ª•ÏX‚³‚ê‚Ü‚µ‚½"
+
+msgid "E512: Close failed"
+msgstr "E512: •Â‚¶‚邱‚Æ‚ÉŽ¸”s"
+
+msgid "E513: write error, conversion failed (make 'fenc' empty to override)"
+msgstr "E513: ‘ž‚݃Gƒ‰[A•ÏŠ·Ž¸”s (ã‘‚·‚é‚É‚Í 'fenc' ‚ð‹ó‚É‚µ‚Ä‚­‚¾‚³‚¢)"
+
+#, c-format
+msgid ""
+"E513: write error, conversion failed in line %ld (make 'fenc' empty to "
+"override)"
+msgstr ""
+"E513: ‘ž‚݃Gƒ‰[A•ÏŠ·Ž¸”sAs” %ld (ã‘‚·‚é‚É‚Í 'fenc' ‚ð‹ó‚É‚µ‚Ä‚­‚¾‚³"
+"‚¢)"
+
+msgid "E514: write error (file system full?)"
+msgstr "E514: ‘ž‚݃Gƒ‰[ (ƒtƒ@ƒCƒ‹ƒVƒXƒeƒ€‚ª–ž”t?)"
+
+msgid " CONVERSION ERROR"
+msgstr " •ÏŠ·ƒGƒ‰["
+
+#, c-format
+msgid " in line %ld;"
+msgstr " s %ld;"
+
+msgid "[Device]"
+msgstr "[ƒfƒoƒCƒX]"
+
+msgid "[New]"
+msgstr "[V]"
+
+msgid " [a]"
+msgstr " [a]"
+
+msgid " appended"
+msgstr " ’ljÁ"
+
+msgid " [w]"
+msgstr " [w]"
+
+msgid " written"
+msgstr " ‘ž‚Ý"
+
+msgid "E205: Patchmode: can't save original file"
+msgstr "E205: patchmode: Œ´–{ƒtƒ@ƒCƒ‹‚ð•Û‘¶‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "E206: patchmode: can't touch empty original file"
+msgstr "E206: patchmode: ‹ó‚ÌŒ´–{ƒtƒ@ƒCƒ‹‚ðtouch‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "E207: Can't delete backup file"
+msgstr "E207: ƒoƒbƒNƒAƒbƒvƒtƒ@ƒCƒ‹‚ðÁ‚¹‚Ü‚¹‚ñ"
+
+msgid ""
+"\n"
+"WARNING: Original file may be lost or damaged\n"
+msgstr ""
+"\n"
+"Œx: Œ´–{ƒtƒ@ƒCƒ‹‚ªŽ¸‚í‚ꂽ‚©•ÏX‚³‚ê‚Ü‚µ‚½\n"
+
+msgid "don't quit the editor until the file is successfully written!"
+msgstr "ƒtƒ@ƒCƒ‹‚Ì•Û‘¶‚ɬŒ÷‚·‚é‚܂ŃGƒfƒBƒ^‚ðI—¹‚µ‚È‚¢‚Å‚­‚¾‚³‚¢!"
+
+msgid "[dos]"
+msgstr "[dos]"
+
+msgid "[dos format]"
+msgstr "[dosƒtƒH[ƒ}ƒbƒg]"
+
+msgid "[mac]"
+msgstr "[mac]"
+
+msgid "[mac format]"
+msgstr "[macƒtƒH[ƒ}ƒbƒg]"
+
+msgid "[unix]"
+msgstr "[unix]"
+
+msgid "[unix format]"
+msgstr "[unixƒtƒH[ƒ}ƒbƒg]"
+
+#, c-format
+msgid "%ld line, "
+msgid_plural "%ld lines, "
+msgstr[0] "%ld s, "
+
+#, c-format
+msgid "%lld character"
+msgid_plural "%lld characters"
+msgstr[0] "%lld •¶Žš"
+
+msgid "[noeol]"
+msgstr "[noeol]"
+
+msgid "[Incomplete last line]"
+msgstr "[ÅIs‚ª•sŠ®‘S]"
+
+msgid "WARNING: The file has been changed since reading it!!!"
+msgstr "Œx: “Çž‚ñ‚¾Œã‚Ƀtƒ@ƒCƒ‹‚É•ÏX‚ª‚ ‚è‚Ü‚µ‚½!!!"
+
+msgid "Do you really want to write to it"
+msgstr "–{“–‚Éã‘‚«‚µ‚Ü‚·‚©"
+
+#, c-format
+msgid "E208: Error writing to \"%s\""
+msgstr "E208: \"%s\" ‚ð‘ž‚Ý’†‚̃Gƒ‰[‚Å‚·"
+
+#, c-format
+msgid "E209: Error closing \"%s\""
+msgstr "E209: \"%s\" ‚ð•Â‚¶‚鎞‚ɃGƒ‰[‚Å‚·"
+
+#, c-format
+msgid "E210: Error reading \"%s\""
+msgstr "E210: \"%s\" ‚ð“Çž’†‚̃Gƒ‰[‚Å‚·"
+
+msgid "E246: FileChangedShell autocommand deleted buffer"
+msgstr "E246: autocommand ‚Ì FileChangedShell ‚ªƒoƒbƒtƒ@‚ð휂µ‚Ü‚µ‚½"
+
+#, c-format
+msgid "E211: File \"%s\" no longer available"
+msgstr "E211: ƒtƒ@ƒCƒ‹ \"%s\" ‚ÍŠù‚É‘¶Ý‚µ‚Ü‚¹‚ñ"
+
+#, c-format
+msgid ""
+"W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as "
+"well"
+msgstr "W12: Œx: ƒtƒ@ƒCƒ‹ \"%s\" ‚ª•ÏX‚³‚êVim‚̃oƒbƒtƒ@‚à•ÏX‚³‚ê‚Ü‚µ‚½"
+
+msgid "See \":help W12\" for more info."
+msgstr "Ú×‚Í \":help W12\" ‚ðŽQÆ‚µ‚Ä‚­‚¾‚³‚¢"
+
+#, c-format
+msgid "W11: Warning: File \"%s\" has changed since editing started"
+msgstr "W11: Œx: ƒtƒ@ƒCƒ‹ \"%s\" ‚Í•ÒWŠJŽnŒã‚É•ÏX‚³‚ê‚Ü‚µ‚½"
+
+msgid "See \":help W11\" for more info."
+msgstr "Ú×‚Í \":help W11\" ‚ðŽQÆ‚µ‚Ä‚­‚¾‚³‚¢"
+
+#, c-format
+msgid "W16: Warning: Mode of file \"%s\" has changed since editing started"
+msgstr "W16: Œx: ƒtƒ@ƒCƒ‹ \"%s\" ‚̃‚[ƒh‚ª•ÒWŠJŽnŒã‚É•ÏX‚³‚ê‚Ü‚µ‚½"
+
+msgid "See \":help W16\" for more info."
+msgstr "Ú×‚Í \":help W16\" ‚ðŽQÆ‚µ‚Ä‚­‚¾‚³‚¢"
+
+#, c-format
+msgid "W13: Warning: File \"%s\" has been created after editing started"
+msgstr "W13: Œx: ƒtƒ@ƒCƒ‹ \"%s\" ‚Í•ÒWŠJŽnŒã‚É쬂³‚ê‚Ü‚µ‚½"
+
+msgid "Warning"
+msgstr "Œx"
+
+msgid ""
+"&OK\n"
+"&Load File"
+msgstr ""
+"&OK\n"
+"ƒtƒ@ƒCƒ‹“Çž(&L)"
+
+#, c-format
+msgid "E462: Could not prepare for reloading \"%s\""
+msgstr "E462: \"%s\" ‚ðƒŠƒ[ƒh‚·‚途õ‚ª‚Å‚«‚Ü‚¹‚ñ‚Å‚µ‚½"
+
+#, c-format
+msgid "E321: Could not reload \"%s\""
+msgstr "E321: \"%s\" ‚̓Šƒ[ƒh‚Å‚«‚Ü‚¹‚ñ‚Å‚µ‚½"
+
+msgid "--Deleted--"
+msgstr "--íœÏ--"
+
+#, c-format
+msgid "auto-removing autocommand: %s <buffer=%d>"
+msgstr "autocommand: %s <ƒoƒbƒtƒ@=%d> ‚ªŽ©“®“I‚É휂³‚ê‚Ü‚·"
+
+#, c-format
+msgid "E367: No such group: \"%s\""
+msgstr "E367: ‚»‚̃Oƒ‹[ƒv‚Í‚ ‚è‚Ü‚¹‚ñ: \"%s\""
+
+msgid "E936: Cannot delete the current group"
+msgstr "E936: Œ»Ý‚̃Oƒ‹[ƒv‚Í휂ł«‚Ü‚¹‚ñ"
+
+msgid "W19: Deleting augroup that is still in use"
+msgstr "W19: Žg—p’†‚Ì augroup ‚ðÁ‚»‚¤‚Æ‚µ‚Ä‚¢‚Ü‚·"
+
+#, c-format
+msgid "E215: Illegal character after *: %s"
+msgstr "E215: * ‚ÌŒã‚É•s³‚È•¶Žš‚ª‚ ‚è‚Ü‚µ‚½: %s"
+
+#, c-format
+msgid "E216: No such event: %s"
+msgstr "E216: ‚»‚̂悤‚ȃCƒxƒ“ƒg‚Í‚ ‚è‚Ü‚¹‚ñ: %s"
+
+#, c-format
+msgid "E216: No such group or event: %s"
+msgstr "E216: ‚»‚̂悤‚ȃOƒ‹[ƒv‚à‚µ‚­‚̓Cƒxƒ“ƒg‚Í‚ ‚è‚Ü‚¹‚ñ: %s"
+
+msgid ""
+"\n"
+"--- Autocommands ---"
+msgstr ""
+"\n"
+"--- Autocommands ---"
+
+#, c-format
+msgid "E680: <buffer=%d>: invalid buffer number "
+msgstr "E680: <ƒoƒbƒtƒ@=%d>: –³Œø‚ȃoƒbƒtƒ@”Ô†‚Å‚· "
+
+msgid "E217: Can't execute autocommands for ALL events"
+msgstr "E217: ‘S‚ẴCƒxƒ“ƒg‚ɑ΂µ‚Ä‚Ìautocommand‚ÍŽÀs‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "No matching autocommands"
+msgstr "ŠY“–‚·‚éautocommand‚Í‘¶Ý‚µ‚Ü‚¹‚ñ"
+
+msgid "E218: autocommand nesting too deep"
+msgstr "E218: autocommand‚Ì“ü‚êŽq‚ª[‰ß‚¬‚Ü‚·"
+
+#, c-format
+msgid "%s Autocommands for \"%s\""
+msgstr "%s Autocommands for \"%s\""
+
+#, c-format
+msgid "Executing %s"
+msgstr "%s ‚ðŽÀs‚µ‚Ä‚¢‚Ü‚·"
+
+#, c-format
+msgid "autocommand %s"
+msgstr "autocommand %s"
+
+msgid "E219: Missing {."
+msgstr "E219: { ‚ª‚ ‚è‚Ü‚¹‚ñ."
+
+msgid "E220: Missing }."
+msgstr "E220: } ‚ª‚ ‚è‚Ü‚¹‚ñ."
+
+msgid "E490: No fold found"
+msgstr "E490: Üô‚Ý‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "E350: Cannot create fold with current 'foldmethod'"
+msgstr "E350: Œ»Ý‚Ì 'foldmethod' ‚Å‚ÍÜô‚Ý‚ð쬂ł«‚Ü‚¹‚ñ"
+
+msgid "E351: Cannot delete fold with current 'foldmethod'"
+msgstr "E351: Œ»Ý‚Ì 'foldmethod' ‚Å‚ÍÜô‚Ý‚ð휂ł«‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "+--%3ld line folded "
+msgid_plural "+--%3ld lines folded "
+msgstr[0] "+--%3ld s‚ªÜô‚Ü‚ê‚Ü‚µ‚½"
+
+msgid "E222: Add to read buffer"
+msgstr "E222: “Çžƒoƒbƒtƒ@‚֒ljÁ"
+
+msgid "E223: recursive mapping"
+msgstr "E223: Ä‹A“Iƒ}ƒbƒsƒ“ƒO"
+
+#, c-format
+msgid "E224: global abbreviation already exists for %s"
+msgstr "E224: %s ‚Æ‚¢‚¤ƒOƒ[ƒoƒ‹’Zk“ü—Í‚ÍŠù‚É‘¶Ý‚µ‚Ü‚·"
+
+#, c-format
+msgid "E225: global mapping already exists for %s"
+msgstr "E225: %s ‚Æ‚¢‚¤ƒOƒ[ƒoƒ‹ƒ}ƒbƒsƒ“ƒO‚ÍŠù‚É‘¶Ý‚µ‚Ü‚·"
+
+#, c-format
+msgid "E226: abbreviation already exists for %s"
+msgstr "E226: %s ‚Æ‚¢‚¤’Zk“ü—Í‚ÍŠù‚É‘¶Ý‚µ‚Ü‚·"
+
+#, c-format
+msgid "E227: mapping already exists for %s"
+msgstr "E227: %s ‚Æ‚¢‚¤ƒ}ƒbƒsƒ“ƒO‚ÍŠù‚É‘¶Ý‚µ‚Ü‚·"
+
+msgid "No abbreviation found"
+msgstr "’Zk“ü—Í‚ÍŒ©‚‚©‚è‚Ü‚¹‚ñ‚Å‚µ‚½"
+
+msgid "No mapping found"
+msgstr "ƒ}ƒbƒsƒ“ƒO‚ÍŒ©‚‚©‚è‚Ü‚¹‚ñ‚Å‚µ‚½"
+
+msgid "E228: makemap: Illegal mode"
+msgstr "E228: makemap: •s³‚ȃ‚[ƒh"
+
+msgid "E851: Failed to create a new process for the GUI"
+msgstr "E851: GUI—p‚̃vƒƒZƒX‚Ì‹N“®‚ÉŽ¸”s‚µ‚Ü‚µ‚½"
+
+msgid "E852: The child process failed to start the GUI"
+msgstr "E852: ŽqƒvƒƒZƒX‚ªGUI‚Ì‹N“®‚ÉŽ¸”s‚µ‚Ü‚µ‚½"
+
+msgid "E229: Cannot start the GUI"
+msgstr "E229: GUI‚ðŠJŽn‚Å‚«‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E230: Cannot read from \"%s\""
+msgstr "E230: \"%s\"‚©‚ç“Çž‚Þ‚±‚Æ‚ª‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "E665: Cannot start GUI, no valid font found"
+msgstr "E665: —LŒø‚ȃtƒHƒ“ƒg‚ªŒ©‚‚©‚ç‚È‚¢‚Ì‚ÅAGUI‚ðŠJŽn‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "E231: 'guifontwide' invalid"
+msgstr "E231: 'guifontwide' ‚ª–³Œø‚Å‚·"
+
+msgid "E599: Value of 'imactivatekey' is invalid"
+msgstr "E599: 'imactivatekey' ‚Éݒ肳‚ꂽ’l‚ª–³Œø‚Å‚·"
+
+#, c-format
+msgid "E254: Cannot allocate color %s"
+msgstr "E254: %s ‚ÌF‚ðŠ„‚è“–‚Ä‚ç‚ê‚Ü‚¹‚ñ"
+
+msgid "No match at cursor, finding next"
+msgstr "ƒJ[ƒ\\ƒ‹‚̈ʒu‚Ƀ}ƒbƒ`‚Í‚ ‚è‚Ü‚¹‚ñAŽŸ‚ðŒŸõ‚µ‚Ä‚¢‚Ü‚·"
+
+msgid "<cannot open> "
+msgstr "<ŠJ‚¯‚Ü‚¹‚ñ> "
+
+#, c-format
+msgid "E616: vim_SelFile: can't get font %s"
+msgstr "E616: vim_SelFile: ƒtƒHƒ“ƒg %s ‚ðŽæ“¾‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "E614: vim_SelFile: can't return to current directory"
+msgstr "E614: vim_SelFile: Œ»Ý‚̃fƒBƒŒƒNƒgƒŠ‚É–ß‚ê‚Ü‚¹‚ñ"
+
+msgid "Pathname:"
+msgstr "ƒpƒX–¼:"
+
+msgid "E615: vim_SelFile: can't get current directory"
+msgstr "E615: vim_SelFile: Œ»Ý‚̃fƒBƒŒƒNƒgƒŠ‚ðŽæ“¾‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "OK"
+msgstr "OK"
+
+msgid "Cancel"
+msgstr "ƒLƒƒƒ“ƒZƒ‹"
+
+msgid "Scrollbar Widget: Could not get geometry of thumb pixmap."
+msgstr "ƒXƒNƒ[ƒ‹ƒo[: ‰æ‘œ‚ðŽæ“¾‚Å‚«‚Ü‚¹‚ñ‚Å‚µ‚½."
+
+msgid "Vim dialog"
+msgstr "Vim ƒ_ƒCƒAƒƒO"
+
+msgid "E232: Cannot create BalloonEval with both message and callback"
+msgstr "E232: ƒƒbƒZ[ƒW‚ƃR[ƒ‹ƒoƒbƒN‚Ì‚ ‚é BalloonEval ‚ð쬂ł«‚Ü‚¹‚ñ"
+
+msgid "_Cancel"
+msgstr "ƒLƒƒƒ“ƒZƒ‹(_C)"
+
+msgid "_Save"
+msgstr "•Û‘¶(_S)"
+
+msgid "_Open"
+msgstr "ŠJ‚­(_O)"
+
+msgid "_OK"
+msgstr "_OK"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"&Cancel"
+msgstr ""
+"‚Í‚¢(&Y)\n"
+"‚¢‚¢‚¦(&N)\n"
+"ƒLƒƒƒ“ƒZƒ‹(&C)"
+
+msgid "Yes"
+msgstr "‚Í‚¢"
+
+msgid "No"
+msgstr "‚¢‚¢‚¦"
+
+msgid "Input _Methods"
+msgstr "ƒCƒ“ƒvƒbƒgƒƒ\\ƒbƒh"
+
+msgid "VIM - Search and Replace..."
+msgstr "VIM - ŒŸõ‚Æ’uŠ·..."
+
+msgid "VIM - Search..."
+msgstr "VIM - ŒŸõ..."
+
+msgid "Find what:"
+msgstr "ŒŸõ•¶Žš—ñ:"
+
+msgid "Replace with:"
+msgstr "’uŠ·•¶Žš—ñ:"
+
+msgid "Match whole word only"
+msgstr "³Šm‚ÉŠY“–‚·‚é‚à‚Ì‚¾‚¯"
+
+msgid "Match case"
+msgstr "‘啶Žš/¬•¶Žš‚ð‹æ•Ê‚·‚é"
+
+msgid "Direction"
+msgstr "•ûŒü"
+
+msgid "Up"
+msgstr "ã"
+
+msgid "Down"
+msgstr "‰º"
+
+msgid "Find Next"
+msgstr "ŽŸ‚ðŒŸõ"
+
+msgid "Replace"
+msgstr "’uŠ·"
+
+msgid "Replace All"
+msgstr "‘S‚Ä’uŠ·"
+
+msgid "_Close"
+msgstr "•Â‚¶‚é(_C)"
+
+msgid "Vim: Received \"die\" request from session manager\n"
+msgstr "Vim: ƒZƒbƒVƒ‡ƒ“ƒ}ƒl[ƒWƒƒ‚©‚ç \"die\" —v‹‚ðŽó‚¯Žæ‚è‚Ü‚µ‚½\n"
+
+msgid "Close tab"
+msgstr "ƒ^ƒuƒy[ƒW‚ð•Â‚¶‚é"
+
+msgid "New tab"
+msgstr "V‹Kƒ^ƒuƒy[ƒW"
+
+msgid "Open Tab..."
+msgstr "ƒ^ƒuƒy[ƒW‚ðŠJ‚­..."
+
+msgid "Vim: Main window unexpectedly destroyed\n"
+msgstr "Vim: ƒƒCƒ“ƒEƒBƒ“ƒhƒE‚ª•sˆÓ‚É”j‰ó‚³‚ê‚Ü‚µ‚½\n"
+
+msgid "&Filter"
+msgstr "ƒtƒBƒ‹ƒ^(&F)"
+
+msgid "&Cancel"
+msgstr "ƒLƒƒƒ“ƒZƒ‹(&C)"
+
+msgid "Directories"
+msgstr "ƒfƒBƒŒƒNƒgƒŠ"
+
+msgid "Filter"
+msgstr "ƒtƒBƒ‹ƒ^"
+
+msgid "&Help"
+msgstr "ƒwƒ‹ƒv(&H)"
+
+msgid "Files"
+msgstr "ƒtƒ@ƒCƒ‹"
+
+msgid "&OK"
+msgstr "&OK"
+
+msgid "Selection"
+msgstr "‘I‘ð"
+
+msgid "Find &Next"
+msgstr "ŽŸ‚ðŒŸõ(&N)"
+
+msgid "&Replace"
+msgstr "’uŠ·(&R)"
+
+msgid "Replace &All"
+msgstr "‘S‚Ä’uŠ·(&A)"
+
+msgid "&Undo"
+msgstr "ƒAƒ“ƒhƒD(&U)"
+
+msgid "Open tab..."
+msgstr "ƒ^ƒuƒy[ƒW‚ðŠJ‚­"
+
+msgid "Find string"
+msgstr "ŒŸõ•¶Žš—ñ"
+
+msgid "Find & Replace"
+msgstr "ŒŸõE’uŠ·"
+
+msgid "Not Used"
+msgstr "Žg‚í‚ê‚Ü‚¹‚ñ"
+
+msgid "Directory\t*.nothing\n"
+msgstr "ƒfƒBƒŒƒNƒgƒŠ\t*.nothing\n"
+
+#, c-format
+msgid "E671: Cannot find window title \"%s\""
+msgstr "E671: ƒ^ƒCƒgƒ‹‚ª \"%s\" ‚̃EƒBƒ“ƒhƒE‚ÍŒ©‚‚©‚è‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E243: Argument not supported: \"-%s\"; Use the OLE version."
+msgstr "E243: ˆø”‚̓Tƒ|[ƒg‚³‚ê‚Ü‚¹‚ñ: \"-%s\"; OLE”Å‚ðŽg—p‚µ‚Ä‚­‚¾‚³‚¢."
+
+msgid "E672: Unable to open window inside MDI application"
+msgstr "E672: MDIƒAƒvƒŠ‚Ì’†‚ł̓EƒBƒ“ƒhƒE‚ðŠJ‚¯‚Ü‚¹‚ñ"
+
+msgid "Vim E458: Cannot allocate colormap entry, some colors may be incorrect"
+msgstr "Vim E458: FŽw’肪³‚µ‚­‚È‚¢‚̂ŃGƒ“ƒgƒŠ‚ðŠ„‚è“–‚Ä‚ç‚ê‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E250: Fonts for the following charsets are missing in fontset %s:"
+msgstr "E250: ˆÈ‰º‚Ì•¶ŽšƒZƒbƒg‚̃tƒHƒ“ƒg‚ª‚ ‚è‚Ü‚¹‚ñ %s:"
+
+#, c-format
+msgid "E252: Fontset name: %s"
+msgstr "E252: ƒtƒHƒ“ƒgƒZƒbƒg–¼: %s"
+
+#, c-format
+msgid "Font '%s' is not fixed-width"
+msgstr "ƒtƒHƒ“ƒg '%s' ‚͌Œ蕂ł͂ ‚è‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E253: Fontset name: %s"
+msgstr "E253: ƒtƒHƒ“ƒgƒZƒbƒg–¼: %s"
+
+#, c-format
+msgid "Font0: %s"
+msgstr "ƒtƒHƒ“ƒg0: %s"
+
+#, c-format
+msgid "Font1: %s"
+msgstr "ƒtƒHƒ“ƒg1: %s"
+
+#, c-format
+msgid "Font%ld width is not twice that of font0"
+msgstr "ƒtƒHƒ“ƒg%ld ‚Ì•‚ªƒtƒHƒ“ƒg0‚Ì2”{‚Å‚Í‚ ‚è‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "Font0 width: %ld"
+msgstr "ƒtƒHƒ“ƒg0‚Ì•: %ld"
+
+#, c-format
+msgid "Font1 width: %ld"
+msgstr "ƒtƒHƒ“ƒg1‚Ì•: %ld"
+
+msgid "Invalid font specification"
+msgstr "–³Œø‚ȃtƒHƒ“ƒgŽw’è‚Å‚·"
+
+msgid "&Dismiss"
+msgstr "‹p‰º‚·‚é(&D)"
+
+msgid "no specific match"
+msgstr "ƒ}ƒbƒ`‚·‚é‚à‚Ì‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "Vim - Font Selector"
+msgstr "Vim - ƒtƒHƒ“ƒg‘I‘ð"
+
+msgid "Name:"
+msgstr "–¼‘O:"
+
+msgid "Show size in Points"
+msgstr "ƒTƒCƒY‚ðƒ|ƒCƒ“ƒg‚Å•\\Ž¦‚·‚é"
+
+msgid "Encoding:"
+msgstr "ƒGƒ“ƒR[ƒh:"
+
+msgid "Font:"
+msgstr "ƒtƒHƒ“ƒg:"
+
+msgid "Style:"
+msgstr "ƒXƒ^ƒCƒ‹:"
+
+msgid "Size:"
+msgstr "ƒTƒCƒY:"
+
+msgid "E256: Hangul automata ERROR"
+msgstr "E256: ƒnƒ“ƒOƒ‹ƒI[ƒgƒ}ƒgƒ“ƒGƒ‰["
+
+msgid "E550: Missing colon"
+msgstr "E550: ƒRƒƒ“‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "E551: Illegal component"
+msgstr "E551: •s³‚È\\•¶—v‘f‚Å‚·"
+
+msgid "E552: digit expected"
+msgstr "E552: ”’l‚ª•K—v‚Å‚·"
+
+#, c-format
+msgid "Page %d"
+msgstr "%d ƒy[ƒW"
+
+msgid "No text to be printed"
+msgstr "ˆóü‚·‚éƒeƒLƒXƒg‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "Printing page %d (%d%%)"
+msgstr "ˆóü’†: ƒy[ƒW %d (%d%%)"
+
+#, c-format
+msgid " Copy %d of %d"
+msgstr " ƒRƒs[ %d (‘S %d ’†)"
+
+#, c-format
+msgid "Printed: %s"
+msgstr "ˆóü‚µ‚Ü‚µ‚½: %s"
+
+msgid "Printing aborted"
+msgstr "ˆóü‚ª’†Ž~‚³‚ê‚Ü‚µ‚½"
+
+msgid "E455: Error writing to PostScript output file"
+msgstr "E455: PostScripto—̓tƒ@ƒCƒ‹‚Ì‘ž‚݃Gƒ‰[‚Å‚·"
+
+#, c-format
+msgid "E624: Can't open file \"%s\""
+msgstr "E624: ƒtƒ@ƒCƒ‹ \"%s\" ‚ðŠJ‚¯‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E457: Can't read PostScript resource file \"%s\""
+msgstr "E457: PostScript‚̃Šƒ\\[ƒXƒtƒ@ƒCƒ‹ \"%s\" ‚ð“Çž‚ß‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E618: file \"%s\" is not a PostScript resource file"
+msgstr "E618: ƒtƒ@ƒCƒ‹ \"%s\" ‚Í PostScript ƒŠƒ\\[ƒXƒtƒ@ƒCƒ‹‚Å‚Í‚ ‚è‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E619: file \"%s\" is not a supported PostScript resource file"
+msgstr "E619: ƒtƒ@ƒCƒ‹ \"%s\" ‚͑Ήž‚µ‚Ä‚¢‚È‚¢ PostScript ƒŠƒ\\[ƒXƒtƒ@ƒCƒ‹‚Å‚·"
+
+#, c-format
+msgid "E621: \"%s\" resource file has wrong version"
+msgstr "E621: ƒŠƒ\\[ƒXƒtƒ@ƒCƒ‹ \"%s\" ‚̓o[ƒWƒ‡ƒ“‚ªˆÙ‚È‚è‚Ü‚·"
+
+msgid "E673: Incompatible multi-byte encoding and character set."
+msgstr "E673: ŒÝŠ·«‚Ì–³‚¢ƒ}ƒ‹ƒ`ƒoƒCƒgƒGƒ“ƒR[ƒfƒBƒ“ƒO‚Æ•¶ŽšƒZƒbƒg‚Å‚·"
+
+msgid "E674: printmbcharset cannot be empty with multi-byte encoding."
+msgstr "E674: ƒ}ƒ‹ƒ`ƒoƒCƒgƒGƒ“ƒR[ƒfƒBƒ“ƒO‚Å‚Í printmbcharset ‚ð‹ó‚É‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "E675: No default font specified for multi-byte printing."
+msgstr ""
+"E675: ƒ}ƒ‹ƒ`ƒoƒCƒg•¶Žš‚ðˆóü‚·‚邽‚߂̃fƒtƒHƒ‹ƒgƒtƒHƒ“ƒg‚ªŽw’肳‚ê‚Ä‚¢‚Ü‚¹‚ñ"
+
+msgid "E324: Can't open PostScript output file"
+msgstr "E324: PostScripto—Í—p‚̃tƒ@ƒCƒ‹‚ðŠJ‚¯‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E456: Can't open file \"%s\""
+msgstr "E456: ƒtƒ@ƒCƒ‹ \"%s\" ‚ðŠJ‚¯‚Ü‚¹‚ñ"
+
+msgid "E456: Can't find PostScript resource file \"prolog.ps\""
+msgstr "E456: PostScript‚̃Šƒ\\[ƒXƒtƒ@ƒCƒ‹ \"prolog.ps\" ‚ªŒ©‚‚©‚è‚Ü‚¹‚ñ"
+
+msgid "E456: Can't find PostScript resource file \"cidfont.ps\""
+msgstr "E456: PostScript‚̃Šƒ\\[ƒXƒtƒ@ƒCƒ‹ \"cidfont.ps\" ‚ªŒ©‚‚©‚è‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E456: Can't find PostScript resource file \"%s.ps\""
+msgstr "E456: PostScript‚̃Šƒ\\[ƒXƒtƒ@ƒCƒ‹ \"%s.ps\" ‚ªŒ©‚‚©‚è‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E620: Unable to convert to print encoding \"%s\""
+msgstr "E620: ˆóüƒGƒ“ƒR[ƒh \"%s\" ‚Ö•ÏŠ·‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "Sending to printer..."
+msgstr "ƒvƒŠƒ“ƒ^‚É‘—M’†..."
+
+msgid "E365: Failed to print PostScript file"
+msgstr "E365: PostScriptƒtƒ@ƒCƒ‹‚̈óü‚ÉŽ¸”s‚µ‚Ü‚µ‚½"
+
+msgid "Print job sent."
+msgstr "ˆóüƒWƒ‡ƒu‚ð‘—M‚µ‚Ü‚µ‚½."
+
+msgid "Add a new database"
+msgstr "Vƒf[ƒ^ƒx[ƒX‚ð’ljÁ"
+
+msgid "Query for a pattern"
+msgstr "ƒpƒ^[ƒ“‚̃NƒGƒŠ[‚ð’ljÁ"
+
+msgid "Show this message"
+msgstr "‚±‚̃ƒbƒZ[ƒW‚ð•\\Ž¦‚·‚é"
+
+msgid "Kill a connection"
+msgstr "Ú‘±‚ðI—¹‚·‚é"
+
+msgid "Reinit all connections"
+msgstr "‘S‚Ä‚ÌÚ‘±‚ðĉŠú‰»‚·‚é"
+
+msgid "Show connections"
+msgstr "Ú‘±‚ð•\\Ž¦‚·‚é"
+
+#, c-format
+msgid "E560: Usage: cs[cope] %s"
+msgstr "E560: Žg—p•û–@: cs[cope] %s"
+
+msgid "This cscope command does not support splitting the window.\n"
+msgstr "‚±‚ÌcscopeƒRƒ}ƒ“ƒh‚Í•ªŠ„ƒEƒBƒ“ƒhƒE‚ł̓Tƒ|[ƒg‚³‚ê‚Ü‚¹‚ñ.\n"
+
+msgid "E562: Usage: cstag <ident>"
+msgstr "E562: Žg—p–@: cstag <ident>"
+
+msgid "E257: cstag: tag not found"
+msgstr "E257: cstag: ƒ^ƒO‚ªŒ©‚‚©‚è‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E563: stat(%s) error: %d"
+msgstr "E563: stat(%s) ƒGƒ‰[: %d"
+
+msgid "E563: stat error"
+msgstr "E563: stat ƒGƒ‰["
+
+#, c-format
+msgid "E564: %s is not a directory or a valid cscope database"
+msgstr "E564: %s ‚̓fƒBƒŒƒNƒgƒŠ‹y‚Ñ—LŒø‚Ècscope‚̃f[ƒ^ƒx[ƒX‚Å‚Í‚ ‚è‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "Added cscope database %s"
+msgstr "cscopeƒf[ƒ^ƒx[ƒX %s ‚ð’ljÁ"
+
+#, c-format
+msgid "E262: error reading cscope connection %ld"
+msgstr "E262: cscope‚ÌÚ‘± %ld ‚ð“Çž‚Ý’†‚̃Gƒ‰[‚Å‚·"
+
+msgid "E561: unknown cscope search type"
+msgstr "E561: –¢’m‚ÌcscopeŒŸõŒ^‚Å‚·"
+
+msgid "E566: Could not create cscope pipes"
+msgstr "E566: cscopeƒpƒCƒv‚ð쬂ł«‚Ü‚¹‚ñ‚Å‚µ‚½"
+
+msgid "E622: Could not fork for cscope"
+msgstr "E622: cscope‚Ì‹N“®€”õ(fork)‚ÉŽ¸”s‚µ‚Ü‚µ‚½"
+
+msgid "cs_create_connection setpgid failed"
+msgstr "cs_create_connection ‚Ö‚Ì setpgid ‚ÉŽ¸”s‚µ‚Ü‚µ‚½"
+
+msgid "cs_create_connection exec failed"
+msgstr "cs_create_connection ‚ÌŽÀs‚ÉŽ¸”s‚µ‚Ü‚µ‚½"
+
+msgid "cs_create_connection: fdopen for to_fp failed"
+msgstr "cs_create_connection: to_fp ‚Ì fdopen ‚ÉŽ¸”s‚µ‚Ü‚µ‚½"
+
+msgid "cs_create_connection: fdopen for fr_fp failed"
+msgstr "cs_create_connection: fr_fp ‚Ì fdopen ‚ÉŽ¸”s‚µ‚Ü‚µ‚½"
+
+msgid "E623: Could not spawn cscope process"
+msgstr "E623: cscopeƒvƒƒZƒX‚ð‹N“®‚Å‚«‚Ü‚¹‚ñ‚Å‚µ‚½"
+
+msgid "E567: no cscope connections"
+msgstr "E567: cscopeÚ‘±‚ÉŽ¸”s‚µ‚Ü‚µ‚½"
+
+#, c-format
+msgid "E469: invalid cscopequickfix flag %c for %c"
+msgstr "E469: –³Œø‚È cscopequickfix ƒtƒ‰ƒO %c ‚Ì %c ‚Å‚·"
+
+#, c-format
+msgid "E259: no matches found for cscope query %s of %s"
+msgstr "E259: cscopeƒNƒGƒŠ[ %s of %s ‚ÉŠY“–‚ª‚ ‚è‚Ü‚¹‚ñ‚Å‚µ‚½"
+
+msgid "cscope commands:\n"
+msgstr "cscopeƒRƒ}ƒ“ƒh:\n"
+
+#, c-format
+msgid "%-5s: %s%*s (Usage: %s)"
+msgstr "%-5s: %s%*s (Žg—p–@: %s)"
+
+msgid ""
+"\n"
+" a: Find assignments to this symbol\n"
+" c: Find functions calling this function\n"
+" d: Find functions called by this function\n"
+" e: Find this egrep pattern\n"
+" f: Find this file\n"
+" g: Find this definition\n"
+" i: Find files #including this file\n"
+" s: Find this C symbol\n"
+" t: Find this text string\n"
+msgstr ""
+"\n"
+" a: ‚±‚̃Vƒ“ƒ{ƒ‹‚ɑ΂·‚é‘ã“ü‚ð’T‚·\n"
+" c: ‚±‚ÌŠÖ”‚ðŒÄ‚ñ‚Å‚¢‚éŠÖ”‚ð’T‚·\n"
+" d: ‚±‚ÌŠÖ”‚©‚çŒÄ‚ñ‚Å‚¢‚éŠÖ”‚ð’T‚·\n"
+" e: ‚±‚Ìegrepƒpƒ^[ƒ“‚ð’T‚·\n"
+" f: ‚±‚̃tƒ@ƒCƒ‹‚ð’T‚·\n"
+" g: ‚±‚Ì’è‹`‚ð’T‚·\n"
+" i: ‚±‚̃tƒ@ƒCƒ‹‚ð#include‚µ‚Ä‚¢‚éƒtƒ@ƒCƒ‹‚ð’T‚·\n"
+" s: ‚±‚ÌCƒVƒ“ƒ{ƒ‹‚ð’T‚·\n"
+" t: ‚±‚̃eƒLƒXƒg•¶Žš—ñ‚ð’T‚·\n"
+
+#, c-format
+msgid "E625: cannot open cscope database: %s"
+msgstr "E625: cscopeƒf[ƒ^ƒx[ƒX: %s ‚ðŠJ‚­‚±‚Æ‚ª‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "E626: cannot get cscope database information"
+msgstr "E626: cscopeƒf[ƒ^ƒx[ƒX‚Ìî•ñ‚ðŽæ“¾‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "E568: duplicate cscope database not added"
+msgstr "E568: d•¡‚·‚écscopeƒf[ƒ^ƒx[ƒX‚͒ljÁ‚³‚ê‚Ü‚¹‚ñ‚Å‚µ‚½"
+
+#, c-format
+msgid "E261: cscope connection %s not found"
+msgstr "E261: cscopeÚ‘± %s ‚ªŒ©‚‚©‚è‚Ü‚¹‚ñ‚Å‚µ‚½"
+
+#, c-format
+msgid "cscope connection %s closed"
+msgstr "cscopeÚ‘± %s ‚ª•Â‚¶‚ç‚ê‚Ü‚µ‚½"
+
+msgid "E570: fatal error in cs_manage_matches"
+msgstr "E570: cs_manage_matches ‚Å’v–½“I‚ȃGƒ‰[‚Å‚·"
+
+#, c-format
+msgid "Cscope tag: %s"
+msgstr "Cscope ƒ^ƒO: %s"
+
+msgid ""
+"\n"
+" # line"
+msgstr ""
+"\n"
+" # s”Ô†"
+
+msgid "filename / context / line\n"
+msgstr "ƒtƒ@ƒCƒ‹–¼ / •¶–¬ / s\n"
+
+#, c-format
+msgid "E609: Cscope error: %s"
+msgstr "E609: cscopeƒGƒ‰[: %s"
+
+msgid "All cscope databases reset"
+msgstr "‘S‚Ä‚Ìcscopeƒf[ƒ^ƒx[ƒX‚ðƒŠƒZƒbƒg‚µ‚Ü‚·"
+
+msgid "no cscope connections\n"
+msgstr "cscopeÚ‘±‚ª‚ ‚è‚Ü‚¹‚ñ\n"
+
+msgid " # pid database name prepend path\n"
+msgstr " # pid ƒf[ƒ^ƒx[ƒX–¼ prepend ƒpƒX\n"
+
+msgid "Lua library cannot be loaded."
+msgstr "Luaƒ‰ƒCƒuƒ‰ƒŠ‚ðƒ[ƒh‚Å‚«‚Ü‚¹‚ñ."
+
+msgid "cannot save undo information"
+msgstr "ƒAƒ“ƒhƒDî•ñ‚ª•Û‘¶‚Å‚«‚Ü‚¹‚ñ"
+
+msgid ""
+"E815: Sorry, this command is disabled, the MzScheme libraries could not be "
+"loaded."
+msgstr "E815: ‚±‚̃Rƒ}ƒ“ƒh‚Í–³Œø‚Å‚·. MzScheme ƒ‰ƒCƒuƒ‰ƒŠ‚ðƒ[ƒh‚Å‚«‚Ü‚¹‚ñ."
+
+msgid ""
+"E895: Sorry, this command is disabled, the MzScheme's racket/base module "
+"could not be loaded."
+msgstr ""
+"E895: ‚±‚̃Rƒ}ƒ“ƒh‚Í–³Œø‚Å‚·A‚²‚ß‚ñ‚È‚³‚¢. MzScheme ‚Ì racket/base ƒ‚ƒWƒ…["
+"ƒ‹‚ªƒ[ƒh‚Å‚«‚Ü‚¹‚ñ‚Å‚µ‚½."
+
+msgid "invalid expression"
+msgstr "–³Œø‚ÈŽ®‚Å‚·"
+
+msgid "expressions disabled at compile time"
+msgstr "Ž®‚̓Rƒ“ƒpƒCƒ‹Žž‚É–³Œø‚É‚³‚ê‚Ä‚¢‚Ü‚·"
+
+msgid "hidden option"
+msgstr "‰B‚µƒIƒvƒVƒ‡ƒ“"
+
+msgid "unknown option"
+msgstr "–¢’m‚̃IƒvƒVƒ‡ƒ“‚Å‚·"
+
+msgid "window index is out of range"
+msgstr "”͈͊O‚̃EƒBƒ“ƒhƒE”Ô†‚Å‚·"
+
+msgid "couldn't open buffer"
+msgstr "ƒoƒbƒtƒ@‚ðŠJ‚¯‚Ü‚¹‚ñ"
+
+msgid "cannot delete line"
+msgstr "s‚ðÁ‚¹‚Ü‚¹‚ñ"
+
+msgid "cannot replace line"
+msgstr "s‚ð’uŠ·‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "cannot insert line"
+msgstr "s‚ð‘}“ü‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "string cannot contain newlines"
+msgstr "•¶Žš—ñ‚ɂ͉üs•¶Žš‚ðŠÜ‚ß‚ç‚ê‚Ü‚¹‚ñ"
+
+msgid "error converting Scheme values to Vim"
+msgstr "Scheme’l‚ÌVim‚Ö‚Ì•ÏŠ·ƒGƒ‰["
+
+msgid "Vim error: ~a"
+msgstr "Vim ƒGƒ‰[: ~a"
+
+msgid "Vim error"
+msgstr "Vim ƒGƒ‰["
+
+msgid "buffer is invalid"
+msgstr "ƒoƒbƒtƒ@‚Í–³Œø‚Å‚·"
+
+msgid "window is invalid"
+msgstr "ƒEƒBƒ“ƒhƒE‚Í–³Œø‚Å‚·"
+
+msgid "linenr out of range"
+msgstr "”͈͊O‚Ìs”Ô†‚Å‚·"
+
+msgid "not allowed in the Vim sandbox"
+msgstr "ƒTƒ“ƒhƒ{ƒbƒNƒX‚Å‚Í‹–‚³‚ê‚Ü‚¹‚ñ"
+
+msgid "E836: This Vim cannot execute :python after using :py3"
+msgstr "E836: ‚±‚ÌVim‚Å‚Í :py3 ‚ðŽg‚Á‚½Œã‚É :python ‚ðŽg‚¦‚Ü‚¹‚ñ"
+
+msgid ""
+"E263: Sorry, this command is disabled, the Python library could not be "
+"loaded."
+msgstr ""
+"E263: ‚±‚̃Rƒ}ƒ“ƒh‚Í–³Œø‚Å‚·A‚²‚ß‚ñ‚È‚³‚¢: Pythonƒ‰ƒCƒuƒ‰ƒŠ‚ðƒ[ƒh‚Å‚«‚Ü‚¹"
+"‚ñ‚Å‚µ‚½."
+
+msgid ""
+"E887: Sorry, this command is disabled, the Python's site module could not be "
+"loaded."
+msgstr ""
+"E887: ‚±‚̃Rƒ}ƒ“ƒh‚Í–³Œø‚Å‚·A‚²‚ß‚ñ‚È‚³‚¢. Python ‚Ì site ƒ‚ƒWƒ…[ƒ‹‚ðƒ[ƒh"
+"‚Å‚«‚Ü‚¹‚ñ‚Å‚µ‚½."
+
+# Added at 07-Feb-2004.
+msgid "E659: Cannot invoke Python recursively"
+msgstr "E659: Python ‚ðÄ‹A“I‚ÉŽÀs‚·‚邱‚Æ‚Í‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "E837: This Vim cannot execute :py3 after using :python"
+msgstr "E837: ‚±‚ÌVim‚Å‚Í :python ‚ðŽg‚Á‚½Œã‚É :py3 ‚ðŽg‚¦‚Ü‚¹‚ñ"
+
+msgid "E265: $_ must be an instance of String"
+msgstr "E265: $_ ‚Í•¶Žš—ñ‚̃Cƒ“ƒXƒ^ƒ“ƒX‚Å‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñ"
+
+msgid ""
+"E266: Sorry, this command is disabled, the Ruby library could not be loaded."
+msgstr ""
+"E266: ‚±‚̃Rƒ}ƒ“ƒh‚Í–³Œø‚Å‚·A‚²‚ß‚ñ‚È‚³‚¢: Rubyƒ‰ƒCƒuƒ‰ƒŠ‚ðƒ[ƒh‚Å‚«‚Ü‚¹‚ñ"
+"‚Å‚µ‚½."
+
+msgid "E267: unexpected return"
+msgstr "E267: —\\Šú‚¹‚Ê return ‚Å‚·"
+
+msgid "E268: unexpected next"
+msgstr "E268: —\\Šú‚¹‚Ê next ‚Å‚·"
+
+msgid "E269: unexpected break"
+msgstr "E269: —\\Šú‚¹‚Ê break ‚Å‚·"
+
+msgid "E270: unexpected redo"
+msgstr "E270: —\\Šú‚¹‚Ê redo ‚Å‚·"
+
+msgid "E271: retry outside of rescue clause"
+msgstr "E271: rescue ‚ÌŠO‚Ì retry ‚Å‚·"
+
+msgid "E272: unhandled exception"
+msgstr "E272: Žæ‚舵‚í‚ê‚È‚©‚Á‚½—áŠO‚ª‚ ‚è‚Ü‚·"
+
+#, c-format
+msgid "E273: unknown longjmp status %d"
+msgstr "E273: –¢’m‚Ìlongjmpó‘Ô: %d"
+
+msgid "invalid buffer number"
+msgstr "–³Œø‚ȃoƒbƒtƒ@”Ô†‚Å‚·"
+
+msgid "not implemented yet"
+msgstr "‚Ü‚¾ŽÀ‘•‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ"
+
+msgid "cannot set line(s)"
+msgstr "s‚ðÝ’è‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "invalid mark name"
+msgstr "–³Œø‚ȃ}[ƒN–¼‚Å‚·"
+
+msgid "mark not set"
+msgstr "ƒ}[ƒN‚Íݒ肳‚ê‚Ä‚¢‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "row %d column %d"
+msgstr "s %d —ñ %d"
+
+msgid "cannot insert/append line"
+msgstr "s‚Ì‘}“ü/’ljÁ‚ð‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "line number out of range"
+msgstr "”͈͊O‚Ìs”Ô†‚Å‚·"
+
+msgid "unknown flag: "
+msgstr "–¢’m‚̃tƒ‰ƒO: "
+
+msgid "unknown vimOption"
+msgstr "–¢’m‚Ì vimOption ‚Å‚·"
+
+msgid "keyboard interrupt"
+msgstr "ƒL[ƒ{[ƒhŠ„ž‚Ý"
+
+msgid "vim error"
+msgstr "vim ƒGƒ‰["
+
+msgid "cannot create buffer/window command: object is being deleted"
+msgstr ""
+"ƒoƒbƒtƒ@/ƒEƒBƒ“ƒhƒE쬃Rƒ}ƒ“ƒh‚ð쬂ł«‚Ü‚¹‚ñ: ƒIƒuƒWƒFƒNƒg‚ªÁ‹Ž‚³‚ê‚Ä‚¢‚Ü"
+"‚µ‚½"
+
+msgid ""
+"cannot register callback command: buffer/window is already being deleted"
+msgstr ""
+"ƒR[ƒ‹ƒoƒbƒNƒRƒ}ƒ“ƒh‚ð“o˜^‚Å‚«‚Ü‚¹‚ñ: ƒoƒbƒtƒ@/ƒEƒBƒ“ƒhƒE‚ªŠù‚ÉÁ‹Ž‚³‚ê‚Ü‚µ‚½"
+
+msgid ""
+"E280: TCL FATAL ERROR: reflist corrupt!? Please report this to vim-dev@vim."
+"org"
+msgstr ""
+"E280: TCL ’v–½“IƒGƒ‰[: reflist ‰˜õ!? vim-dev@vim.org ‚É•ñ‚µ‚Ä‚­‚¾‚³‚¢"
+
+msgid "cannot register callback command: buffer/window reference not found"
+msgstr ""
+"ƒR[ƒ‹ƒoƒbƒNƒRƒ}ƒ“ƒh‚ð“o˜^‚Å‚«‚Ü‚¹‚ñ: ƒoƒbƒtƒ@/ƒEƒBƒ“ƒhƒE‚ÌŽQÆ‚ªŒ©‚‚©‚è‚Ü‚¹"
+"‚ñ"
+
+msgid ""
+"E571: Sorry, this command is disabled: the Tcl library could not be loaded."
+msgstr ""
+"E571: ‚±‚̃Rƒ}ƒ“ƒh‚Í–³Œø‚Å‚·A‚²‚ß‚ñ‚È‚³‚¢: Tclƒ‰ƒCƒuƒ‰ƒŠ‚ðƒ[ƒh‚Å‚«‚Ü‚¹‚ñ‚Å"
+"‚µ‚½."
+
+#, c-format
+msgid "E572: exit code %d"
+msgstr "E572: I—¹ƒR[ƒh %d"
+
+msgid "cannot get line"
+msgstr "s‚ðŽæ“¾‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "Unable to register a command server name"
+msgstr "–½—߃T[ƒo[‚Ì–¼‘O‚ð“o˜^‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "E248: Failed to send command to the destination program"
+msgstr "E248: –Ú“I‚̃vƒƒOƒ‰ƒ€‚ւ̃Rƒ}ƒ“ƒh‘—M‚ÉŽ¸”s‚µ‚Ü‚µ‚½"
+
+#, c-format
+msgid "E573: Invalid server id used: %s"
+msgstr "E573: –³Œø‚ȃT[ƒo[ID‚ªŽg‚í‚ê‚Ü‚µ‚½: %s"
+
+msgid "E251: VIM instance registry property is badly formed. Deleted!"
+msgstr "E251: VIM ŽÀ‘Ì‚Ì“o˜^ƒvƒƒpƒeƒB‚ª•s³‚Å‚·. Á‹Ž‚µ‚Ü‚µ‚½!"
+
+#, c-format
+msgid "E938: Duplicate key in JSON: \"%s\""
+msgstr "E938: JSON‚Éd•¡ƒL[‚ª‚ ‚è‚Ü‚·: \"%s\""
+
+#, c-format
+msgid "E696: Missing comma in List: %s"
+msgstr "E696: ƒŠƒXƒgŒ^‚ɃJƒ“ƒ}‚ª‚ ‚è‚Ü‚¹‚ñ: %s"
+
+#, c-format
+msgid "E697: Missing end of List ']': %s"
+msgstr "E697: ƒŠƒXƒgŒ^‚ÌÅŒã‚É ']' ‚ª‚ ‚è‚Ü‚¹‚ñ: %s"
+
+msgid "Unknown option argument"
+msgstr "–¢’m‚̃IƒvƒVƒ‡ƒ“ˆø”‚Å‚·"
+
+msgid "Too many edit arguments"
+msgstr "•ÒWˆø”‚ª‘½‰ß‚¬‚Ü‚·"
+
+msgid "Argument missing after"
+msgstr "ˆø”‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "Garbage after option argument"
+msgstr "ƒIƒvƒVƒ‡ƒ“ˆø”‚ÌŒã‚ɃSƒ~‚ª‚ ‚è‚Ü‚·"
+
+msgid "Too many \"+command\", \"-c command\" or \"--cmd command\" arguments"
+msgstr "\"+command\", \"-c command\", \"--cmd command\" ‚̈ø”‚ª‘½‰ß‚¬‚Ü‚·"
+
+msgid "Invalid argument for"
+msgstr "–³Œø‚Ȉø”‚Å‚·: "
+
+#, c-format
+msgid "%d files to edit\n"
+msgstr "%d ŒÂ‚̃tƒ@ƒCƒ‹‚ª•ÒW‚ðT‚¦‚Ä‚¢‚Ü‚·\n"
+
+msgid "netbeans is not supported with this GUI\n"
+msgstr "netbeans ‚Í‚±‚ÌGUI‚Å‚Í—˜—p‚Å‚«‚Ü‚¹‚ñ\n"
+
+msgid "'-nb' cannot be used: not enabled at compile time\n"
+msgstr "'-nb' Žg—p•s‰Â”\\‚Å‚·: ƒRƒ“ƒpƒCƒ‹Žž‚É–³Œø‚É‚³‚ê‚Ä‚¢‚Ü‚·\n"
+
+msgid "This Vim was not compiled with the diff feature."
+msgstr "‚±‚ÌVim‚É‚Ídiff‹@”\\‚ª‚ ‚è‚Ü‚¹‚ñ(ƒRƒ“ƒpƒCƒ‹ŽžÝ’è)."
+
+msgid "Attempt to open script file again: \""
+msgstr "ƒXƒNƒŠƒvƒgƒtƒ@ƒCƒ‹‚ðÄ‚ÑŠJ‚±‚¤‚Æ‚µ‚Ü‚µ‚½: \""
+
+msgid "Cannot open for reading: \""
+msgstr "“Çž—p‚Æ‚µ‚ÄŠJ‚¯‚Ü‚¹‚ñ"
+
+msgid "Cannot open for script output: \""
+msgstr "ƒXƒNƒŠƒvƒgo—Í—p‚ðŠJ‚¯‚Ü‚¹‚ñ"
+
+msgid "Vim: Error: Failure to start gvim from NetBeans\n"
+msgstr "Vim: ƒGƒ‰[: NetBeans‚©‚çgvim‚ðƒXƒ^[ƒg‚Å‚«‚Ü‚¹‚ñ\n"
+
+msgid "Vim: Error: This version of Vim does not run in a Cygwin terminal\n"
+msgstr "Vim: ƒGƒ‰[: ‚±‚̃o[ƒWƒ‡ƒ“‚ÌVim‚ÍCygwin’[––‚Å‚Í“®ì‚µ‚Ü‚¹‚ñ\n"
+
+msgid "Vim: Warning: Output is not to a terminal\n"
+msgstr "Vim: Œx: ’[––‚Ö‚Ìo—Í‚Å‚Í‚ ‚è‚Ü‚¹‚ñ\n"
+
+msgid "Vim: Warning: Input is not from a terminal\n"
+msgstr "Vim: Œx: ’[––‚©‚ç‚Ì“ü—Í‚Å‚Í‚ ‚è‚Ü‚¹‚ñ\n"
+
+msgid "pre-vimrc command line"
+msgstr "vimrc‘O‚̃Rƒ}ƒ“ƒhƒ‰ƒCƒ“"
+
+#, c-format
+msgid "E282: Cannot read from \"%s\""
+msgstr "E282: \"%s\"‚©‚ç“Çž‚Þ‚±‚Æ‚ª‚Å‚«‚Ü‚¹‚ñ"
+
+msgid ""
+"\n"
+"More info with: \"vim -h\"\n"
+msgstr ""
+"\n"
+"‚æ‚èÚׂÈî•ñ‚Í: \"vim -h\"\n"
+
+msgid "[file ..] edit specified file(s)"
+msgstr "[ƒtƒ@ƒCƒ‹..] ‚ ‚éƒtƒ@ƒCƒ‹‚ð•ÒW‚·‚é"
+
+msgid "- read text from stdin"
+msgstr "- •W€“ü—Í‚©‚çƒeƒLƒXƒg‚ð“Çž‚Þ"
+
+msgid "-t tag edit file where tag is defined"
+msgstr "-t ƒ^ƒO ƒ^ƒO‚ª’è‹`‚³‚ꂽ‚Æ‚±‚ë‚©‚ç•ÒW‚·‚é"
+
+msgid "-q [errorfile] edit file with first error"
+msgstr "-q [errorfile] ʼn‚̃Gƒ‰[‚Å•ÒW‚·‚é"
+
+msgid ""
+"\n"
+"\n"
+"Usage:"
+msgstr ""
+"\n"
+"\n"
+"Žg—p–@:"
+
+msgid " vim [arguments] "
+msgstr " vim [ˆø”] "
+
+msgid ""
+"\n"
+" or:"
+msgstr ""
+"\n"
+" ‚à‚µ‚­‚Í:"
+
+msgid ""
+"\n"
+"Where case is ignored prepend / to make flag upper case"
+msgstr ""
+"\n"
+"‘嬕¶Žš‚ª–³Ž‹‚³‚ê‚éꇂ͑啶Žš‚É‚·‚邽‚ß‚É / ‚ð‘O’u‚µ‚Ä‚­‚¾‚³‚¢"
+
+msgid ""
+"\n"
+"\n"
+"Arguments:\n"
+msgstr ""
+"\n"
+"\n"
+"ˆø”:\n"
+
+msgid "--\t\t\tOnly file names after this"
+msgstr "--\t\t\t‚±‚Ì‚ ‚Ƃɂ̓tƒ@ƒCƒ‹–¼‚¾‚¯"
+
+msgid "--literal\t\tDon't expand wildcards"
+msgstr "--literal\t\tƒƒCƒ‹ƒhƒJ[ƒh‚ð“WŠJ‚µ‚È‚¢"
+
+msgid "-register\t\tRegister this gvim for OLE"
+msgstr "-register\t\t‚±‚Ìgvim‚ðOLE‚Æ‚µ‚Ä“o˜^‚·‚é"
+
+msgid "-unregister\t\tUnregister gvim for OLE"
+msgstr "-unregister\t\tgvim‚ÌOLE“o˜^‚ð‰ðœ‚·‚é"
+
+msgid "-g\t\t\tRun using GUI (like \"gvim\")"
+msgstr "-g\t\t\tGUI‚Å‹N“®‚·‚é (\"gvim\" ‚Æ“¯‚¶)"
+
+msgid "-f or --nofork\tForeground: Don't fork when starting GUI"
+msgstr "-f or --nofork\tƒtƒHƒAƒOƒ‰ƒEƒ“ƒh: GUI‚ðŽn‚ß‚é‚Æ‚«‚Éfork‚µ‚È‚¢"
+
+msgid "-v\t\t\tVi mode (like \"vi\")"
+msgstr "-v\t\t\tViƒ‚[ƒh (\"vi\" ‚Æ“¯‚¶)"
+
+msgid "-e\t\t\tEx mode (like \"ex\")"
+msgstr "-e\t\t\tExƒ‚[ƒh (\"ex\" ‚Æ“¯‚¶)"
+
+msgid "-E\t\t\tImproved Ex mode"
+msgstr "-E\t\t\t‰ü—ÇExƒ‚[ƒh"
+
+msgid "-s\t\t\tSilent (batch) mode (only for \"ex\")"
+msgstr "-s\t\t\tƒTƒCƒŒƒ“ƒg(ƒoƒbƒ`)ƒ‚[ƒh (\"ex\" ê—p)"
+
+msgid "-d\t\t\tDiff mode (like \"vimdiff\")"
+msgstr "-d\t\t\t·•ªƒ‚[ƒh (\"vidiff\" ‚Æ“¯‚¶)"
+
+msgid "-y\t\t\tEasy mode (like \"evim\", modeless)"
+msgstr "-y\t\t\tƒC[ƒW[ƒ‚[ƒh (\"evim\" ‚Æ“¯‚¶Aƒ‚[ƒh–³)"
+
+msgid "-R\t\t\tReadonly mode (like \"view\")"
+msgstr "-R\t\t\t“Çžê—pƒ‚[ƒh (\"view\" ‚Æ“¯‚¶)"
+
+msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
+msgstr "-Z\t\t\t§ŒÀƒ‚[ƒh (\"rvim\" ‚Æ“¯‚¶)"
+
+msgid "-m\t\t\tModifications (writing files) not allowed"
+msgstr "-m\t\t\t•ÏX (ƒtƒ@ƒCƒ‹•Û‘¶Žž) ‚ð‚Å‚«‚È‚¢‚悤‚É‚·‚é"
+
+msgid "-M\t\t\tModifications in text not allowed"
+msgstr "-M\t\t\tƒeƒLƒXƒg‚Ì•ÒW‚ðs‚È‚¦‚È‚¢‚悤‚É‚·‚é"
+
+msgid "-b\t\t\tBinary mode"
+msgstr "-b\t\t\tƒoƒCƒiƒŠƒ‚[ƒh"
+
+msgid "-l\t\t\tLisp mode"
+msgstr "-l\t\t\tLispƒ‚[ƒh"
+
+msgid "-C\t\t\tCompatible with Vi: 'compatible'"
+msgstr "-C\t\t\tViŒÝŠ·ƒ‚[ƒh: 'compatible'"
+
+msgid "-N\t\t\tNot fully Vi compatible: 'nocompatible'"
+msgstr "-N\t\t\tVi”ñŒÝŠ·ƒ‚[ƒh: 'nocompatible"
+
+msgid "-V[N][fname]\t\tBe verbose [level N] [log messages to fname]"
+msgstr "-V[N][fname]\t\tƒƒOo—ÍÝ’è [ƒŒƒxƒ‹ N] [ƒƒOƒtƒ@ƒCƒ‹–¼ fname]"
+
+msgid "-D\t\t\tDebugging mode"
+msgstr "-D\t\t\tƒfƒoƒbƒOƒ‚[ƒh"
+
+msgid "-n\t\t\tNo swap file, use memory only"
+msgstr "-n\t\t\tƒXƒƒbƒvƒtƒ@ƒCƒ‹‚ðŽg—p‚¹‚¸ƒƒ‚ƒŠ‚¾‚¯"
+
+msgid "-r\t\t\tList swap files and exit"
+msgstr "-r\t\t\tƒXƒƒbƒvƒtƒ@ƒCƒ‹‚ð—ñ‹“‚µI—¹"
+
+msgid "-r (with file name)\tRecover crashed session"
+msgstr "-r (ƒtƒ@ƒCƒ‹–¼)\tƒNƒ‰ƒbƒVƒ…‚µ‚½ƒZƒbƒVƒ‡ƒ“‚𕜋A"
+
+msgid "-L\t\t\tSame as -r"
+msgstr "-L\t\t\t-r‚Æ“¯‚¶"
+
+msgid "-f\t\t\tDon't use newcli to open window"
+msgstr "-f\t\t\tƒEƒBƒ“ƒhƒE‚ðŠJ‚­‚Ì‚É newcli ‚ðŽg—p‚µ‚È‚¢"
+
+msgid "-dev <device>\t\tUse <device> for I/O"
+msgstr "-dev <device>\t\tI/O‚É <device> ‚ðŽg—p‚·‚é"
+
+msgid "-A\t\t\tStart in Arabic mode"
+msgstr "-A\t\t\tƒAƒ‰ƒrƒAŒêƒ‚[ƒh‚Å‹N“®‚·‚é"
+
+msgid "-H\t\t\tStart in Hebrew mode"
+msgstr "-H\t\t\tƒwƒuƒ‰ƒCŒêƒ‚[ƒh‚Å‹N“®‚·‚é"
+
+msgid "-F\t\t\tStart in Farsi mode"
+msgstr "-F\t\t\tƒyƒ‹ƒVƒAŒêƒ‚[ƒh‚Å‹N“®‚·‚é"
+
+msgid "-T <terminal>\tSet terminal type to <terminal>"
+msgstr "-T <terminal>\t’[––‚ð <terminal> ‚ÉÝ’è‚·‚é"
+
+msgid "--not-a-term\t\tSkip warning for input/output not being a terminal"
+msgstr "--not-a-term\t\t“üo—Í‚ª’[––‚Å‚È‚¢‚Æ‚ÌŒx‚ðƒXƒLƒbƒv‚·‚é"
+
+msgid "--ttyfail\t\tExit if input or output is not a terminal"
+msgstr "--ttyfail\t\t“üo—Í‚ª’[––‚Å‚È‚¯‚ê‚ÎI—¹‚·‚é"
+
+msgid "-u <vimrc>\t\tUse <vimrc> instead of any .vimrc"
+msgstr "-u <vimrc>\t\t.vimrc‚Ì‘ã‚í‚è‚É <vimrc> ‚ðŽg‚¤"
+
+msgid "-U <gvimrc>\t\tUse <gvimrc> instead of any .gvimrc"
+msgstr "-U <gvimrc>\t\t.gvimrc‚Ì‘ã‚í‚è‚É <gvimrc> ‚ðŽg‚¤"
+
+msgid "--noplugin\t\tDon't load plugin scripts"
+msgstr "--noplugin\t\tƒvƒ‰ƒOƒCƒ“ƒXƒNƒŠƒvƒg‚ðƒ[ƒh‚µ‚È‚¢"
+
+msgid "-p[N]\t\tOpen N tab pages (default: one for each file)"
+msgstr "-p[N]\t\tN ŒÂƒ^ƒuƒy[ƒW‚ðŠJ‚­(È—ª’l: ƒtƒ@ƒCƒ‹‚ɂ‚«1ŒÂ)"
+
+msgid "-o[N]\t\tOpen N windows (default: one for each file)"
+msgstr "-o[N]\t\tN ŒÂƒEƒBƒ“ƒhƒE‚ðŠJ‚­(È—ª’l: ƒtƒ@ƒCƒ‹‚ɂ‚«1ŒÂ)"
+
+msgid "-O[N]\t\tLike -o but split vertically"
+msgstr "-O[N]\t\t-o‚Æ“¯‚¶‚¾‚ª‚’¼•ªŠ„"
+
+msgid "+\t\t\tStart at end of file"
+msgstr "+\t\t\tƒtƒ@ƒCƒ‹‚ÌŌォ‚ç‚Í‚¶‚ß‚é"
+
+msgid "+<lnum>\t\tStart at line <lnum>"
+msgstr "+<lnum>\t\t<lnum> s‚©‚ç‚Í‚¶‚ß‚é"
+
+msgid "--cmd <command>\tExecute <command> before loading any vimrc file"
+msgstr "--cmd <command>\tvimrc‚ðƒ[ƒh‚·‚é‘O‚É <command> ‚ðŽÀs‚·‚é"
+
+msgid "-c <command>\t\tExecute <command> after loading the first file"
+msgstr "-c <command>\t\tʼn‚̃tƒ@ƒCƒ‹‚ðƒ[ƒhŒã <command> ‚ðŽÀs‚·‚é"
+
+msgid "-S <session>\t\tSource file <session> after loading the first file"
+msgstr "-S <session>\t\tʼn‚̃tƒ@ƒCƒ‹‚ðƒ[ƒhŒãƒtƒ@ƒCƒ‹ <session> ‚ðŽæž‚Þ"
+
+msgid "-s <scriptin>\tRead Normal mode commands from file <scriptin>"
+msgstr "-s <scriptin>\tƒtƒ@ƒCƒ‹ <scriptin> ‚©‚çƒm[ƒ}ƒ‹ƒRƒ}ƒ“ƒh‚ð“Çž‚Þ"
+
+msgid "-w <scriptout>\tAppend all typed commands to file <scriptout>"
+msgstr "-w <scriptout>\t“ü—Í‚µ‚½‘SƒRƒ}ƒ“ƒh‚ðƒtƒ@ƒCƒ‹ <scriptout> ‚ɒljÁ‚·‚é"
+
+msgid "-W <scriptout>\tWrite all typed commands to file <scriptout>"
+msgstr "-W <scriptout>\t“ü—Í‚µ‚½‘SƒRƒ}ƒ“ƒh‚ðƒtƒ@ƒCƒ‹ <scriptout> ‚É•Û‘¶‚·‚é"
+
+msgid "-x\t\t\tEdit encrypted files"
+msgstr "-x\t\t\tˆÃ†‰»‚³‚ꂽƒtƒ@ƒCƒ‹‚ð•ÒW‚·‚é"
+
+msgid "-display <display>\tConnect vim to this particular X-server"
+msgstr "-display <display>\tvim‚ðŽw’肵‚½ X ƒT[ƒo[‚ÉÚ‘±‚·‚é"
+
+msgid "-X\t\t\tDo not connect to X server"
+msgstr "-X\t\t\tXƒT[ƒo[‚ÉÚ‘±‚µ‚È‚¢"
+
+msgid "--remote <files>\tEdit <files> in a Vim server if possible"
+msgstr "--remote <files>\t‰Â”\\‚È‚ç‚ÎVimƒT[ƒo[‚Å <files> ‚ð•ÒW‚·‚é"
+
+msgid "--remote-silent <files> Same, don't complain if there is no server"
+msgstr "--remote-silent <files> “¯ãAƒT[ƒo[‚ª–³‚­‚Ä‚àŒx•¶‚ðo—Í‚µ‚È‚¢"
+
+msgid ""
+"--remote-wait <files> As --remote but wait for files to have been edited"
+msgstr "--remote-wait <files> --remoteŒã ƒtƒ@ƒCƒ‹‚Ì•ÒW‚ªI‚í‚é‚Ì‚ð‘Ò‚Â"
+
+msgid ""
+"--remote-wait-silent <files> Same, don't complain if there is no server"
+msgstr ""
+"--remote-wait-silent <files> “¯ãAƒT[ƒo[‚ª–³‚­‚Ä‚àŒx•¶‚ðo—Í‚µ‚È‚¢"
+
+msgid ""
+"--remote-tab[-wait][-silent] <files> As --remote but use tab page per file"
+msgstr ""
+"--remote-tab[-wait][-silent] <files> --remote‚Ńtƒ@ƒCƒ‹1‚‚ɂ‚«1‚‚̃^ƒu"
+"ƒy[ƒW‚ðŠJ‚­"
+
+msgid "--remote-send <keys>\tSend <keys> to a Vim server and exit"
+msgstr "--remote-send <keys>\tVimƒT[ƒo[‚É <keys> ‚ð‘—M‚µ‚ÄI—¹‚·‚é"
+
+msgid "--remote-expr <expr>\tEvaluate <expr> in a Vim server and print result"
+msgstr "--remote-expr <expr>\tƒT[ƒo[‚Å <expr> ‚ðŽÀs‚µ‚ÄŒ‹‰Ê‚ð•\\Ž¦‚·‚é"
+
+msgid "--serverlist\t\tList available Vim server names and exit"
+msgstr "--serverlist\t\tVimƒT[ƒo[–¼‚̈ꗗ‚ð•\\Ž¦‚µ‚ÄI—¹‚·‚é"
+
+msgid "--servername <name>\tSend to/become the Vim server <name>"
+msgstr "--servername <name>\tVimƒT[ƒo[ <name> ‚É‘—M/–¼‘OÝ’è‚·‚é"
+
+msgid "--startuptime <file>\tWrite startup timing messages to <file>"
+msgstr "--startuptime <file>\t‹N“®‚É‚©‚©‚Á‚½ŽžŠÔ‚ÌÚׂð <file> ‚Öo—Í‚·‚é"
+
+msgid "-i <viminfo>\t\tUse <viminfo> instead of .viminfo"
+msgstr "-i <viminfo>\t\t.viminfo‚Ì‘ã‚í‚è‚É <viminfo> ‚ðŽg‚¤"
+
+msgid "--clean\t\t'nocompatible', Vim defaults, no plugins, no viminfo"
+msgstr "--clean\t\t'nocompatible'AVim‚ÌŠù’èAƒvƒ‰ƒOƒCƒ“‚È‚µAviminfo‚È‚µ"
+
+msgid "-h or --help\tPrint Help (this message) and exit"
+msgstr "-h or --help\tƒwƒ‹ƒv(‚±‚̃ƒbƒZ[ƒW)‚ð•\\Ž¦‚µI—¹‚·‚é"
+
+msgid "--version\t\tPrint version information and exit"
+msgstr "--version\t\tƒo[ƒWƒ‡ƒ“î•ñ‚ð•\\Ž¦‚µI—¹‚·‚é"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Motif version):\n"
+msgstr ""
+"\n"
+"gvim‚É‚æ‚Á‚ĉðŽß‚³‚ê‚éˆø”(Motifƒo[ƒWƒ‡ƒ“):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (neXtaw version):\n"
+msgstr ""
+"\n"
+"gvim‚É‚æ‚Á‚ĉðŽß‚³‚ê‚éˆø”(neXtawƒo[ƒWƒ‡ƒ“):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Athena version):\n"
+msgstr ""
+"\n"
+"gvim‚É‚æ‚Á‚ĉðŽß‚³‚ê‚éˆø”(Athenaƒo[ƒWƒ‡ƒ“):\n"
+
+msgid "-display <display>\tRun vim on <display>"
+msgstr "-display <display>\t<display> ‚Åvim‚ðŽÀs‚·‚é"
+
+msgid "-iconic\t\tStart vim iconified"
+msgstr "-iconic\t\tŬ‰»‚µ‚½ó‘Ô‚Åvim‚ð‹N“®‚·‚é"
+
+msgid "-background <color>\tUse <color> for the background (also: -bg)"
+msgstr "-background <color>\t”wŒiF‚É <color> ‚ðŽg‚¤(“¯‹`: -bg)"
+
+msgid "-foreground <color>\tUse <color> for normal text (also: -fg)"
+msgstr "-foreground <color>\t‘OŒiF‚É <color> ‚ðŽg‚¤(“¯‹`: -fg)"
+
+msgid "-font <font>\t\tUse <font> for normal text (also: -fn)"
+msgstr "-font <font>\t\tƒeƒLƒXƒg•\\Ž¦‚É <font> ‚ðŽg‚¤(“¯‹`: -fn)"
+
+msgid "-boldfont <font>\tUse <font> for bold text"
+msgstr "-boldfont <font>\t‘¾Žš‚É <font> ‚ðŽg‚¤"
+
+msgid "-italicfont <font>\tUse <font> for italic text"
+msgstr "-italicfont <for>\tŽÎ‘ÌŽš‚É <font> ‚ðŽg‚¤"
+
+msgid "-geometry <geom>\tUse <geom> for initial geometry (also: -geom)"
+msgstr "-geometry <geom>\t‰Šú”z’u‚É <geom> ‚ðŽg‚¤(“¯‹`: -geom)"
+
+msgid "-borderwidth <width>\tUse a border width of <width> (also: -bw)"
+msgstr "-borderwidth <width>\t‹«ŠE‚Ì•‚ð <width> ‚É‚·‚é(“¯‹`: -bw)"
+
+msgid "-scrollbarwidth <width> Use a scrollbar width of <width> (also: -sw)"
+msgstr ""
+"-scrollbarwidth <width> ƒXƒNƒ[ƒ‹ƒo[‚Ì•‚ð <width> ‚É‚·‚é(“¯‹`: -sw)"
+
+msgid "-menuheight <height>\tUse a menu bar height of <height> (also: -mh)"
+msgstr "-menuheight <height>\tƒƒjƒ…[ƒo[‚Ì‚‚³‚ð <height> ‚É‚·‚é(“¯‹`: -mh)"
+
+msgid "-reverse\t\tUse reverse video (also: -rv)"
+msgstr "-reverse\t\t”½“]‰f‘œ‚ðŽg—p‚·‚é(“¯‹`: -rv)"
+
+msgid "+reverse\t\tDon't use reverse video (also: +rv)"
+msgstr "+reverse\t\t”½“]‰f‘œ‚ðŽg—p‚µ‚È‚¢(“¯‹`: +rv)"
+
+msgid "-xrm <resource>\tSet the specified resource"
+msgstr "-xrm <resource>\t“Á’è‚̃Šƒ\\[ƒX‚ðŽg—p‚·‚é"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (GTK+ version):\n"
+msgstr ""
+"\n"
+"gvim‚É‚æ‚Á‚ĉðŽß‚³‚ê‚éˆø”(GTK+ƒo[ƒWƒ‡ƒ“):\n"
+
+msgid "-display <display>\tRun vim on <display> (also: --display)"
+msgstr "-display <display>\t<display> ‚Åvim‚ðŽÀs‚·‚é(“¯‹`: --display)"
+
+msgid "--role <role>\tSet a unique role to identify the main window"
+msgstr "--role <role>\tƒƒCƒ“ƒEƒBƒ“ƒhƒE‚ðŽ¯•Ê‚·‚éˆêˆÓ‚È–ðŠ„(role)‚ðÝ’è‚·‚é"
+
+msgid "--socketid <xid>\tOpen Vim inside another GTK widget"
+msgstr "--socketid <xid>\tˆÙ‚È‚éGTK widget‚Ì“à•”‚ÉVim‚ðŠJ‚­"
+
+msgid "--echo-wid\t\tMake gvim echo the Window ID on stdout"
+msgstr "--echo-wid\t\tƒEƒBƒ“ƒhƒEID‚ð•W€o—Í‚Éo—Í‚·‚é"
+
+msgid "-P <parent title>\tOpen Vim inside parent application"
+msgstr "-P <e‚̃^ƒCƒgƒ‹>\tVim‚ðeƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚Ì’†‚Å‹N“®‚·‚é"
+
+msgid "--windowid <HWND>\tOpen Vim inside another win32 widget"
+msgstr "--windowid <HWND>\tˆÙ‚È‚éWin32 widget‚Ì“à•”‚ÉVim‚ðŠJ‚­"
+
+msgid "No display"
+msgstr "ƒfƒBƒXƒvƒŒƒC‚ªŒ©‚‚©‚è‚Ü‚¹‚ñ"
+
+msgid ": Send failed.\n"
+msgstr ": ‘—M‚ÉŽ¸”s‚µ‚Ü‚µ‚½.\n"
+
+msgid ": Send failed. Trying to execute locally\n"
+msgstr ": ‘—M‚ÉŽ¸”s‚µ‚Ü‚µ‚½. ƒ[ƒJƒ‹‚Å‚ÌŽÀs‚ðŽŽ‚Ý‚Ä‚¢‚Ü‚·\n"
+
+#, c-format
+msgid "%d of %d edited"
+msgstr "%d ŒÂ (%d ŒÂ’†) ‚̃tƒ@ƒCƒ‹‚ð•ÒW‚µ‚Ü‚µ‚½"
+
+msgid "No display: Send expression failed.\n"
+msgstr "ƒfƒBƒXƒvƒŒƒC‚ª‚ ‚è‚Ü‚¹‚ñ: Ž®‚Ì‘—M‚ÉŽ¸”s‚µ‚Ü‚µ‚½.\n"
+
+msgid ": Send expression failed.\n"
+msgstr ": Ž®‚Ì‘—M‚ÉŽ¸”s‚µ‚Ü‚µ‚½.\n"
+
+msgid "No marks set"
+msgstr "ƒ}[ƒN‚ªÝ’肳‚ê‚Ä‚¢‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E283: No marks matching \"%s\""
+msgstr "E283: \"%s\" ‚ÉŠY“–‚·‚éƒ}[ƒN‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+msgid ""
+"\n"
+"mark line col file/text"
+msgstr ""
+"\n"
+"mark s —ñ ƒtƒ@ƒCƒ‹/ƒeƒLƒXƒg"
+
+msgid ""
+"\n"
+" jump line col file/text"
+msgstr ""
+"\n"
+" jump s —ñ ƒtƒ@ƒCƒ‹/ƒeƒLƒXƒg"
+
+msgid ""
+"\n"
+"change line col text"
+msgstr ""
+"\n"
+"•ÏX s —ñ ƒeƒLƒXƒg"
+
+msgid ""
+"\n"
+"# File marks:\n"
+msgstr ""
+"\n"
+"# ƒtƒ@ƒCƒ‹ƒ}[ƒN:\n"
+
+msgid ""
+"\n"
+"# Jumplist (newest first):\n"
+msgstr ""
+"\n"
+"# ƒWƒƒƒ“ƒvƒŠƒXƒg (V‚µ‚¢‚à‚Ì‚ªæ):\n"
+
+msgid ""
+"\n"
+"# History of marks within files (newest to oldest):\n"
+msgstr ""
+"\n"
+"# ƒtƒ@ƒCƒ‹“àƒ}[ƒN‚Ì—š—ð (V‚µ‚¢‚à‚Ì‚©‚çŒÃ‚¢‚à‚Ì):\n"
+
+msgid "Missing '>'"
+msgstr "'>' ‚ªŒ©‚‚©‚è‚Ü‚¹‚ñ"
+
+msgid "E543: Not a valid codepage"
+msgstr "E543: –³Œø‚ȃR[ƒhƒy[ƒW‚Å‚·"
+
+msgid "E284: Cannot set IC values"
+msgstr "E284: IC‚Ì’l‚ðÝ’è‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "E285: Failed to create input context"
+msgstr "E285: ƒCƒ“ƒvƒbƒgƒRƒ“ƒeƒLƒXƒg‚Ì쬂Ɏ¸”s‚µ‚Ü‚µ‚½"
+
+msgid "E286: Failed to open input method"
+msgstr "E286: ƒCƒ“ƒvƒbƒgƒƒ\\ƒbƒh‚̃I[ƒvƒ“‚ÉŽ¸”s‚µ‚Ü‚µ‚½"
+
+msgid "E287: Warning: Could not set destroy callback to IM"
+msgstr "E287: Œx: IM‚Ì”j‰óƒR[ƒ‹ƒoƒbƒN‚ðÝ’è‚Å‚«‚Ü‚¹‚ñ‚Å‚µ‚½"
+
+msgid "E288: input method doesn't support any style"
+msgstr "E288: ƒCƒ“ƒvƒbƒgƒƒ\\ƒbƒh‚Í‚Ç‚ñ‚ȃXƒ^ƒCƒ‹‚àƒTƒ|[ƒg‚µ‚Ü‚¹‚ñ"
+
+msgid "E289: input method doesn't support my preedit type"
+msgstr "E289: ƒCƒ“ƒvƒbƒgƒƒ\\ƒbƒh‚Í my preedit type ‚ðƒTƒ|[ƒg‚µ‚Ü‚¹‚ñ"
+
+msgid "E293: block was not locked"
+msgstr "E293: ƒuƒƒbƒN‚ªƒƒbƒN‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ"
+
+msgid "E294: Seek error in swap file read"
+msgstr "E294: ƒXƒƒbƒvƒtƒ@ƒCƒ‹“ÇžŽž‚ɃV[ƒNƒGƒ‰[‚Å‚·"
+
+msgid "E295: Read error in swap file"
+msgstr "E295: ƒXƒƒbƒvƒtƒ@ƒCƒ‹‚Ì“Çž‚݃Gƒ‰[‚Å‚·"
+
+msgid "E296: Seek error in swap file write"
+msgstr "E296: ƒXƒƒbƒvƒtƒ@ƒCƒ‹‘ž‚ÝŽž‚ɃV[ƒNƒGƒ‰[‚Å‚·"
+
+msgid "E297: Write error in swap file"
+msgstr "E297: ƒXƒƒbƒvƒtƒ@ƒCƒ‹‚Ì‘ž‚݃Gƒ‰[‚Å‚·"
+
+msgid "E300: Swap file already exists (symlink attack?)"
+msgstr "E300: ƒXƒƒbƒvƒtƒ@ƒCƒ‹‚ªŠù‚É‘¶Ý‚µ‚Ü‚· (symlink‚É‚æ‚éUŒ‚?)"
+
+msgid "E298: Didn't get block nr 0?"
+msgstr "E298: ƒuƒƒbƒN 0 ‚ðŽæ“¾‚Å‚«‚Ü‚¹‚ñ?"
+
+msgid "E298: Didn't get block nr 1?"
+msgstr "E298: ƒuƒƒbƒN 1 ‚ðŽæ“¾‚Å‚«‚Ü‚¹‚ñ?"
+
+msgid "E298: Didn't get block nr 2?"
+msgstr "E298: ƒuƒƒbƒN 2 ‚ðŽæ“¾‚Å‚«‚Ü‚¹‚ñ?"
+
+msgid "E843: Error while updating swap file crypt"
+msgstr "E843: ƒXƒƒbƒvƒtƒ@ƒCƒ‹‚̈Æ‚ðXV’†‚ɃGƒ‰[‚ª”­¶‚µ‚Ü‚µ‚½"
+
+msgid "E301: Oops, lost the swap file!!!"
+msgstr "E301: ‚¨‚Á‚ÆAƒXƒƒbƒvƒtƒ@ƒCƒ‹‚ªŽ¸‚í‚ê‚Ü‚µ‚½!!!"
+
+msgid "E302: Could not rename swap file"
+msgstr "E302: ƒXƒƒbƒvƒtƒ@ƒCƒ‹‚Ì–¼‘O‚ð•Ï‚¦‚ç‚ê‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E303: Unable to open swap file for \"%s\", recovery impossible"
+msgstr "E303: \"%s\" ‚̃Xƒƒbƒvƒtƒ@ƒCƒ‹‚ðŠJ‚¯‚È‚¢‚̂ŃŠƒJƒoƒŠ‚Í•s‰Â”\\‚Å‚·"
+
+msgid "E304: ml_upd_block0(): Didn't get block 0??"
+msgstr "E304: ml_upd_block0(): ƒuƒƒbƒN 0 ‚ðŽæ“¾‚Å‚«‚Ü‚¹‚ñ‚Å‚µ‚½??"
+
+#, c-format
+msgid "E305: No swap file found for %s"
+msgstr "E305: %s ‚ɂ̓Xƒƒbƒvƒtƒ@ƒCƒ‹‚ªŒ©‚‚©‚è‚Ü‚¹‚ñ"
+
+msgid "Enter number of swap file to use (0 to quit): "
+msgstr "Žg—p‚·‚éƒXƒƒbƒvƒtƒ@ƒCƒ‹‚̔Ԇ‚ð“ü—Í‚µ‚Ä‚­‚¾‚³‚¢(0 ‚ÅI—¹): "
+
+#, c-format
+msgid "E306: Cannot open %s"
+msgstr "E306: %s ‚ðŠJ‚¯‚Ü‚¹‚ñ"
+
+msgid "Unable to read block 0 from "
+msgstr "ƒuƒƒbƒN 0 ‚ð“Çž‚ß‚Ü‚¹‚ñ "
+
+msgid ""
+"\n"
+"Maybe no changes were made or Vim did not update the swap file."
+msgstr ""
+"\n"
+"‹°‚ç‚­•ÏX‚ª‚³‚ê‚Ä‚¢‚È‚¢‚©Vim‚ªƒXƒƒbƒvƒtƒ@ƒCƒ‹‚ðXV‚µ‚Ä‚¢‚Ü‚¹‚ñ."
+
+msgid " cannot be used with this version of Vim.\n"
+msgstr " Vim‚Ì‚±‚̃o[ƒWƒ‡ƒ“‚Å‚ÍŽg—p‚Å‚«‚Ü‚¹‚ñ.\n"
+
+msgid "Use Vim version 3.0.\n"
+msgstr "Vim‚̃o[ƒWƒ‡ƒ“3.0‚ðŽg—p‚µ‚Ä‚­‚¾‚³‚¢.\n"
+
+#, c-format
+msgid "E307: %s does not look like a Vim swap file"
+msgstr "E307: %s ‚ÍVim‚̃Xƒƒbƒvƒtƒ@ƒCƒ‹‚Å‚Í‚È‚¢‚悤‚Å‚·"
+
+msgid " cannot be used on this computer.\n"
+msgstr " ‚±‚̃Rƒ“ƒsƒ…[ƒ^‚Å‚ÍŽg—p‚Å‚«‚Ü‚¹‚ñ.\n"
+
+msgid "The file was created on "
+msgstr "‚±‚̃tƒ@ƒCƒ‹‚ÍŽŸ‚ÌꊂÅì‚ç‚ê‚Ü‚µ‚½ "
+
+msgid ""
+",\n"
+"or the file has been damaged."
+msgstr ""
+",\n"
+"‚à‚µ‚­‚̓tƒ@ƒCƒ‹‚ª‘¹‚µ‚Ä‚¢‚Ü‚·."
+
+#, c-format
+msgid ""
+"E833: %s is encrypted and this version of Vim does not support encryption"
+msgstr ""
+"E833: %s ‚Í‚±‚̃o[ƒWƒ‡ƒ“‚ÌVim‚ŃTƒ|[ƒg‚µ‚Ä‚¢‚È‚¢Œ`Ž®‚ňƉ»‚³‚ê‚Ä‚¢‚Ü‚·"
+
+msgid " has been damaged (page size is smaller than minimum value).\n"
+msgstr " ‚Í‘¹‚µ‚Ä‚¢‚Ü‚· (ƒy[ƒWƒTƒCƒY‚ªÅ¬’l‚ð‰º‰ñ‚Á‚Ä‚¢‚Ü‚·).\n"
+
+#, c-format
+msgid "Using swap file \"%s\""
+msgstr "ƒXƒƒbƒvƒtƒ@ƒCƒ‹ \"%s\" ‚ðŽg—p’†"
+
+#, c-format
+msgid "Original file \"%s\""
+msgstr "Œ´–{ƒtƒ@ƒCƒ‹ \"%s\""
+
+msgid "E308: Warning: Original file may have been changed"
+msgstr "E308: Œx: Œ´–{ƒtƒ@ƒCƒ‹‚ª•ÏX‚³‚ê‚Ä‚¢‚Ü‚·"
+
+#, c-format
+msgid "Swap file is encrypted: \"%s\""
+msgstr "ƒXƒƒbƒvƒtƒ@ƒCƒ‹‚͈Ɖ»‚³‚ê‚Ä‚¢‚Ü‚·: \"%s\""
+
+msgid ""
+"\n"
+"If you entered a new crypt key but did not write the text file,"
+msgstr ""
+"\n"
+"V‚µ‚¢ˆÃ†ƒL[‚ð“ü—Í‚µ‚½‚ ‚ƂɃeƒLƒXƒgƒtƒ@ƒCƒ‹‚ð•Û‘¶‚µ‚Ä‚¢‚È‚¢ê‡‚ÍA"
+
+msgid ""
+"\n"
+"enter the new crypt key."
+msgstr ""
+"\n"
+"V‚µ‚¢ˆÃ†ƒL[‚ð“ü—Í‚µ‚Ä‚­‚¾‚³‚¢."
+
+msgid ""
+"\n"
+"If you wrote the text file after changing the crypt key press enter"
+msgstr ""
+"\n"
+"ˆÃ†ƒL[‚ð•Ï‚¦‚½‚ ‚ƂɃeƒLƒXƒgƒtƒ@ƒCƒ‹‚ð•Û‘¶‚µ‚½ê‡‚ÍAƒeƒLƒXƒgƒtƒ@ƒCƒ‹‚Æ"
+
+msgid ""
+"\n"
+"to use the same key for text file and swap file"
+msgstr ""
+"\n"
+"ƒXƒƒbƒvƒtƒ@ƒCƒ‹‚É“¯‚¶ˆÃ†ƒL[‚ðŽg‚¤‚½‚ß‚Éenter‚¾‚¯‚ð‰Ÿ‚µ‚Ä‚­‚¾‚³‚¢."
+
+#, c-format
+msgid "E309: Unable to read block 1 from %s"
+msgstr "E309: %s ‚©‚çƒuƒƒbƒN 1 ‚ð“Çž‚ß‚Ü‚¹‚ñ"
+
+msgid "???MANY LINES MISSING"
+msgstr "???‘½‚­‚Ìs‚ªŽ¸‚í‚ê‚Ä‚¢‚Ü‚·"
+
+msgid "???LINE COUNT WRONG"
+msgstr "???s”‚ªŠÔˆá‚Á‚Ä‚¢‚Ü‚·"
+
+msgid "???EMPTY BLOCK"
+msgstr "???ƒuƒƒbƒN‚ª‹ó‚Å‚·"
+
+msgid "???LINES MISSING"
+msgstr "???s‚ªŽ¸‚í‚ê‚Ä‚¢‚Ü‚·"
+
+#, c-format
+msgid "E310: Block 1 ID wrong (%s not a .swp file?)"
+msgstr "E310: ƒuƒƒbƒN 1 ‚ÌID‚ªŠÔˆá‚Á‚Ä‚¢‚Ü‚·(%s ‚ª.swpƒtƒ@ƒCƒ‹‚Å‚È‚¢?)"
+
+msgid "???BLOCK MISSING"
+msgstr "???ƒuƒƒbƒN‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "??? from here until ???END lines may be messed up"
+msgstr "??? ‚±‚±‚©‚ç ???END ‚Ü‚Å‚Ìs‚ª”j‰ó‚³‚ê‚Ä‚¢‚é‚悤‚Å‚·"
+
+msgid "??? from here until ???END lines may have been inserted/deleted"
+msgstr "??? ‚±‚±‚©‚ç ???END ‚Ü‚Å‚Ìs‚ª‘}“ü‚©íœ‚³‚ꂽ‚悤‚Å‚·"
+
+msgid "???END"
+msgstr "???END"
+
+msgid "E311: Recovery Interrupted"
+msgstr "E311: ƒŠƒJƒoƒŠ‚ªŠ„ž‚Ü‚ê‚Ü‚µ‚½"
+
+msgid ""
+"E312: Errors detected while recovering; look for lines starting with ???"
+msgstr ""
+"E312: ƒŠƒJƒoƒŠ‚ÌÅ’†‚ɃGƒ‰[‚ªŒŸo‚³‚ê‚Ü‚µ‚½; ???‚ÅŽn‚Ü‚és‚ðŽQÆ‚µ‚Ä‚­‚¾‚³‚¢"
+
+msgid "See \":help E312\" for more information."
+msgstr "Ú×‚Í \":help E312\" ‚ðŽQÆ‚µ‚Ä‚­‚¾‚³‚¢"
+
+msgid "Recovery completed. You should check if everything is OK."
+msgstr "ƒŠƒJƒoƒŠ‚ªI—¹‚µ‚Ü‚µ‚½. ‘S‚Ä‚ª³‚µ‚¢‚©ƒ`ƒFƒbƒN‚µ‚Ä‚­‚¾‚³‚¢."
+
+msgid ""
+"\n"
+"(You might want to write out this file under another name\n"
+msgstr ""
+"\n"
+"(•ÏX‚ðƒ`ƒFƒbƒN‚·‚邽‚ß‚ÉA‚±‚̃tƒ@ƒCƒ‹‚ð•Ê‚Ì–¼‘O‚Å•Û‘¶‚µ‚½ã‚Å\n"
+
+msgid "and run diff with the original file to check for changes)"
+msgstr "Œ´–{ƒtƒ@ƒCƒ‹‚Æ‚Ì diff ‚ðŽÀs‚·‚é‚Æ—Ç‚¢‚Å‚µ‚傤)"
+
+msgid "Recovery completed. Buffer contents equals file contents."
+msgstr "•œŒ³Š®—¹. ƒoƒbƒtƒ@‚Ì“à—e‚̓tƒ@ƒCƒ‹‚Æ“¯‚¶‚É‚È‚è‚Ü‚µ‚½."
+
+msgid ""
+"\n"
+"You may want to delete the .swp file now.\n"
+"\n"
+msgstr ""
+"\n"
+"Œ³‚Ì.swpƒtƒ@ƒCƒ‹‚Í휂µ‚Ä‚à\\‚¢‚Ü‚¹‚ñ\n"
+"\n"
+
+msgid "Using crypt key from swap file for the text file.\n"
+msgstr "ƒXƒƒbƒvƒtƒ@ƒCƒ‹‚©‚çŽæ“¾‚µ‚½ˆÃ†ƒL[‚ðƒeƒLƒXƒgƒtƒ@ƒCƒ‹‚ÉŽg‚¢‚Ü‚·.\n"
+
+msgid "Swap files found:"
+msgstr "ƒXƒƒbƒvƒtƒ@ƒCƒ‹‚ª•¡”Œ©‚‚©‚è‚Ü‚µ‚½:"
+
+msgid " In current directory:\n"
+msgstr " Œ»Ý‚̃fƒBƒŒƒNƒgƒŠ:\n"
+
+msgid " Using specified name:\n"
+msgstr " ˆÈ‰º‚Ì–¼‘O‚ðŽg—p’†:\n"
+
+msgid " In directory "
+msgstr " ƒfƒBƒŒƒNƒgƒŠ "
+
+msgid " -- none --\n"
+msgstr " -- ‚È‚µ --\n"
+
+msgid " owned by: "
+msgstr " Š—LŽÒ: "
+
+msgid " dated: "
+msgstr " “ú•t: "
+
+msgid " dated: "
+msgstr " “ú•t: "
+
+msgid " [from Vim version 3.0]"
+msgstr " [from Vim version 3.0]"
+
+msgid " [does not look like a Vim swap file]"
+msgstr " [Vim‚̃Xƒƒbƒvƒtƒ@ƒCƒ‹‚Å‚Í‚È‚¢‚悤‚Å‚·]"
+
+msgid " file name: "
+msgstr " ƒtƒ@ƒCƒ‹–¼: "
+
+msgid ""
+"\n"
+" modified: "
+msgstr ""
+"\n"
+" •ÏXó‘Ô: "
+
+msgid "YES"
+msgstr "‚ ‚è"
+
+msgid "no"
+msgstr "‚È‚µ"
+
+msgid ""
+"\n"
+" user name: "
+msgstr ""
+"\n"
+" ƒ†[ƒU[–¼: "
+
+msgid " host name: "
+msgstr " ƒzƒXƒg–¼: "
+
+msgid ""
+"\n"
+" host name: "
+msgstr ""
+"\n"
+" ƒzƒXƒg–¼: "
+
+msgid ""
+"\n"
+" process ID: "
+msgstr ""
+"\n"
+" ƒvƒƒZƒXID: "
+
+msgid " (STILL RUNNING)"
+msgstr " (‚Ü‚¾ŽÀs’†)"
+
+msgid ""
+"\n"
+" [not usable with this version of Vim]"
+msgstr ""
+"\n"
+" [‚±‚ÌVimƒo[ƒWƒ‡ƒ“‚Å‚ÍŽg—p‚Å‚«‚Ü‚¹‚ñ]"
+
+msgid ""
+"\n"
+" [not usable on this computer]"
+msgstr ""
+"\n"
+" [‚±‚̃Rƒ“ƒsƒ…[ƒ^‚Å‚ÍŽg—p‚Å‚«‚Ü‚¹‚ñ]"
+
+msgid " [cannot be read]"
+msgstr " [“Çž‚ß‚Ü‚¹‚ñ]"
+
+msgid " [cannot be opened]"
+msgstr " [ŠJ‚¯‚Ü‚¹‚ñ]"
+
+msgid "E313: Cannot preserve, there is no swap file"
+msgstr "E313: ƒXƒƒbƒvƒtƒ@ƒCƒ‹‚ª–³‚¢‚̂ňێ‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "File preserved"
+msgstr "ƒtƒ@ƒCƒ‹‚ªˆÛŽ‚³‚ê‚Ü‚·"
+
+msgid "E314: Preserve failed"
+msgstr "E314: ˆÛŽ‚ÉŽ¸”s‚µ‚Ü‚µ‚½"
+
+#, c-format
+msgid "E315: ml_get: invalid lnum: %ld"
+msgstr "E315: ml_get: –³Œø‚Èlnum‚Å‚·: %ld"
+
+#, c-format
+msgid "E316: ml_get: cannot find line %ld"
+msgstr "E316: ml_get: s %ld ‚ðŒ©‚Â‚¯‚ç‚ê‚Ü‚¹‚ñ"
+
+msgid "E317: pointer block id wrong 3"
+msgstr "E317: ƒ|ƒCƒ“ƒ^ƒuƒƒbƒN‚ÌID‚ªŠÔˆá‚Á‚Ä‚¢‚Ü‚· 3"
+
+msgid "stack_idx should be 0"
+msgstr "stack_idx ‚Í 0 ‚Å‚ ‚é‚ׂ«‚Å‚·"
+
+msgid "E318: Updated too many blocks?"
+msgstr "E318: XV‚³‚ꂽƒuƒƒbƒN‚ª‘½‰ß‚¬‚é‚©‚à?"
+
+msgid "E317: pointer block id wrong 4"
+msgstr "E317: ƒ|ƒCƒ“ƒ^ƒuƒƒbƒN‚ÌID‚ªŠÔˆá‚Á‚Ä‚¢‚Ü‚· 4"
+
+msgid "deleted block 1?"
+msgstr "ƒuƒƒbƒN 1 ‚ÍÁ‚³‚ꂽ?"
+
+#, c-format
+msgid "E320: Cannot find line %ld"
+msgstr "E320: s %ld ‚ªŒ©‚‚©‚è‚Ü‚¹‚ñ"
+
+msgid "E317: pointer block id wrong"
+msgstr "E317: ƒ|ƒCƒ“ƒ^ƒuƒƒbƒN‚ÌID‚ªŠÔˆá‚Á‚Ä‚¢‚Ü‚·"
+
+msgid "pe_line_count is zero"
+msgstr "pe_line_count ‚ªƒ[ƒ‚Å‚·"
+
+#, c-format
+msgid "E322: line number out of range: %ld past the end"
+msgstr "E322: s”Ô†‚ª”͈͊O‚Å‚·: %ld ’´‚¦‚Ä‚¢‚Ü‚·"
+
+#, c-format
+msgid "E323: line count wrong in block %ld"
+msgstr "E323: ƒuƒƒbƒN %ld ‚ÌsƒJƒEƒ“ƒg‚ªŠÔˆá‚Á‚Ä‚¢‚Ü‚·"
+
+msgid "Stack size increases"
+msgstr "ƒXƒ^ƒbƒNƒTƒCƒY‚ª‘‚¦‚Ü‚·"
+
+msgid "E317: pointer block id wrong 2"
+msgstr "E317: ƒ|ƒCƒ“ƒ^ƒuƒƒbƒN‚ÌID‚ªŠÔˆá‚Á‚Ä‚¢‚Ü‚· 2"
+
+#, c-format
+msgid "E773: Symlink loop for \"%s\""
+msgstr "E773: \"%s\" ‚̃Vƒ“ƒ{ƒŠƒbƒNƒŠƒ“ƒN‚ªƒ‹[ƒv‚É‚È‚Á‚Ä‚¢‚Ü‚·"
+
+msgid "E325: ATTENTION"
+msgstr "E325: ’ˆÓ"
+
+msgid ""
+"\n"
+"Found a swap file by the name \""
+msgstr ""
+"\n"
+"ŽŸ‚Ì–¼‘O‚ŃXƒƒbƒvƒtƒ@ƒCƒ‹‚ðŒ©‚Â‚¯‚Ü‚µ‚½ \""
+
+msgid "While opening file \""
+msgstr "ŽŸ‚̃tƒ@ƒCƒ‹‚ðŠJ‚¢‚Ä‚¢‚éÅ’† \""
+
+msgid " CANNOT BE FOUND"
+msgstr " Œ©‚‚©‚è‚Ü‚¹‚ñ"
+
+msgid " NEWER than swap file!\n"
+msgstr " ƒXƒƒbƒvƒtƒ@ƒCƒ‹‚æ‚è‚àV‚µ‚¢‚Å‚·!\n"
+
+msgid ""
+"\n"
+"(1) Another program may be editing the same file. If this is the case,\n"
+" be careful not to end up with two different instances of the same\n"
+" file when making changes. Quit, or continue with caution.\n"
+msgstr ""
+"\n"
+"(1) •Ê‚̃vƒƒOƒ‰ƒ€‚ª“¯‚¶ƒtƒ@ƒCƒ‹‚ð•ÒW‚µ‚Ä‚¢‚é‚©‚à‚µ‚ê‚Ü‚¹‚ñ.\n"
+" ‚±‚ÌꇂɂÍA•ÏX‚ð‚µ‚Ä‚µ‚Ü‚¤‚Æ1‚‚̃tƒ@ƒCƒ‹‚ɑ΂µ‚ĈقȂé2‚‚Ì\n"
+" ƒCƒ“ƒXƒ^ƒ“ƒX‚ª‚Å‚«‚Ä‚µ‚Ü‚¤‚Ì‚ÅA‚»‚¤‚µ‚È‚¢‚悤‚É‹C‚ð‚‚¯‚Ä‚­‚¾‚³‚¢.\n"
+" I—¹‚·‚é‚©A’ˆÓ‚µ‚È‚ª‚瑱‚¯‚Ä‚­‚¾‚³‚¢.\n"
+
+msgid "(2) An edit session for this file crashed.\n"
+msgstr "(2) ‚±‚̃tƒ@ƒCƒ‹‚Ì•ÒWƒZƒbƒVƒ‡ƒ“‚ªƒNƒ‰ƒbƒVƒ…‚µ‚½.\n"
+
+msgid " If this is the case, use \":recover\" or \"vim -r "
+msgstr " ‚±‚Ìê‡‚É‚Í \":recover\" ‚© \"vim -r "
+
+msgid ""
+"\"\n"
+" to recover the changes (see \":help recovery\").\n"
+msgstr ""
+"\"\n"
+" ‚ðŽg—p‚µ‚Ä•ÏX‚ðƒŠƒJƒo[‚µ‚Ü‚·(\":help recovery\" ‚ðŽQÆ).\n"
+
+msgid " If you did this already, delete the swap file \""
+msgstr " Šù‚É‚±‚ê‚ðs‚È‚Á‚½‚Ì‚È‚ç‚ÎAƒXƒƒbƒvƒtƒ@ƒCƒ‹ \""
+
+msgid ""
+"\"\n"
+" to avoid this message.\n"
+msgstr ""
+"\"\n"
+" ‚ðÁ‚¹‚΂±‚̃ƒbƒZ[ƒW‚ð‰ñ”ð‚Å‚«‚Ü‚·.\n"
+
+msgid "Swap file \""
+msgstr "ƒXƒƒbƒvƒtƒ@ƒCƒ‹ \""
+
+msgid "\" already exists!"
+msgstr "\" ‚ªŠù‚É‚ ‚è‚Ü‚·!"
+
+msgid "VIM - ATTENTION"
+msgstr "VIM - ’ˆÓ"
+
+msgid "Swap file already exists!"
+msgstr "ƒXƒƒbƒvƒtƒ@ƒCƒ‹‚ªŠù‚É‘¶Ý‚µ‚Ü‚·!"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"“Çžê—p‚ÅŠJ‚­(&O)\n"
+"‚Æ‚É‚©‚­•ÒW‚·‚é(&E)\n"
+"•œŠˆ‚³‚¹‚é(&R)\n"
+"I—¹‚·‚é(&Q)\n"
+"’†Ž~‚·‚é(&A)"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Delete it\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"“Çžê—p‚ÅŠJ‚­(&O)\n"
+"‚Æ‚É‚©‚­•ÒW‚·‚é(&E)\n"
+"•œŠˆ‚³‚¹‚é(&R)\n"
+"휂·‚é(&D)\n"
+"I—¹‚·‚é(&Q)\n"
+"’†Ž~‚·‚é(&A)"
+
+msgid "E326: Too many swap files found"
+msgstr "E326: ƒXƒƒbƒvƒtƒ@ƒCƒ‹‚ª‘½”Œ©‚‚©‚è‚Ü‚µ‚½"
+
+msgid "E327: Part of menu-item path is not sub-menu"
+msgstr "E327: ƒƒjƒ…[ƒAƒCƒeƒ€‚̃pƒX‚Ì•”•ª‚ªƒTƒuƒƒjƒ…[‚Å‚Í‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "E328: Menu only exists in another mode"
+msgstr "E328: ƒƒjƒ…[‚Í‘¼‚̃‚[ƒh‚É‚¾‚¯‚ ‚è‚Ü‚·"
+
+#, c-format
+msgid "E329: No menu \"%s\""
+msgstr "E329: \"%s\" ‚Æ‚¢‚¤ƒƒjƒ…[‚Í‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "E792: Empty menu name"
+msgstr "E792: ƒƒjƒ…[–¼‚ª‹ó‚Å‚·"
+
+msgid "E330: Menu path must not lead to a sub-menu"
+msgstr "E330: ƒƒjƒ…[ƒpƒX‚̓Tƒuƒƒjƒ…[‚𶂶‚é‚ׂ«‚Å‚Í‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "E331: Must not add menu items directly to menu bar"
+msgstr "E331: ƒƒjƒ…[ƒo[‚É‚Í’¼Úƒƒjƒ…[ƒAƒCƒeƒ€‚ð’ljÁ‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "E332: Separator cannot be part of a menu path"
+msgstr "E332: ‹æØ‚è‚̓ƒjƒ…[ƒpƒX‚̈ꕔ‚Å‚Í‚ ‚è‚Ü‚¹‚ñ"
+
+msgid ""
+"\n"
+"--- Menus ---"
+msgstr ""
+"\n"
+"--- ƒƒjƒ…[ ---"
+
+msgid "Tear off this menu"
+msgstr "‚±‚̃ƒjƒ…[‚ðØ‚èŽæ‚é"
+
+#, c-format
+msgid "E335: Menu not defined for %s mode"
+msgstr "E335: %s ‚ɂ̓ƒjƒ…[‚ª’è‹`‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ"
+
+msgid "E333: Menu path must lead to a menu item"
+msgstr "E333: ƒƒjƒ…[ƒpƒX‚̓ƒjƒ…[ƒAƒCƒeƒ€‚𶂶‚È‚¯‚ê‚΂¢‚¯‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E334: Menu not found: %s"
+msgstr "E334: ƒƒjƒ…[‚ªŒ©‚‚©‚è‚Ü‚¹‚ñ: %s"
+
+msgid "E336: Menu path must lead to a sub-menu"
+msgstr "E336: ƒƒjƒ…[ƒpƒX‚̓Tƒuƒƒjƒ…[‚𶂶‚È‚¯‚ê‚΂¢‚¯‚Ü‚¹‚ñ"
+
+msgid "E337: Menu not found - check menu names"
+msgstr "E337: ƒƒjƒ…[‚ªŒ©‚‚©‚è‚Ü‚¹‚ñ - ƒƒjƒ…[–¼‚ðŠm”F‚µ‚Ä‚­‚¾‚³‚¢"
+
+#, c-format
+msgid "Error detected while processing %s:"
+msgstr "%s ‚̈—’†‚ɃGƒ‰[‚ªŒŸo‚³‚ê‚Ü‚µ‚½:"
+
+#, c-format
+msgid "line %4ld:"
+msgstr "s %4ld:"
+
+#, c-format
+msgid "E354: Invalid register name: '%s'"
+msgstr "E354: –³Œø‚ȃŒƒWƒXƒ^–¼: '%s'"
+
+msgid "Messages maintainer: Bram Moolenaar <Bram@vim.org>"
+msgstr "“ú–{ŒêƒƒbƒZ[ƒW–|–ó/ŠÄC: ‘º‰ª ‘¾˜Y <koron.kaoriya@gmail.com>"
+
+msgid "Interrupt: "
+msgstr "Š„ž‚Ý: "
+
+msgid "Press ENTER or type command to continue"
+msgstr "‘±‚¯‚é‚É‚ÍENTER‚ð‰Ÿ‚·‚©ƒRƒ}ƒ“ƒh‚ð“ü—Í‚µ‚Ä‚­‚¾‚³‚¢"
+
+#, c-format
+msgid "%s line %ld"
+msgstr "%s s %ld"
+
+msgid "-- More --"
+msgstr "-- Œp‘± --"
+
+msgid " SPACE/d/j: screen/page/line down, b/u/k: up, q: quit "
+msgstr " SPACE/d/j: ‰æ–Ê/ƒy[ƒW/s ‰º, b/u/k: ã, q: I—¹ "
+
+msgid "Question"
+msgstr "Ž¿–â"
+
+msgid ""
+"&Yes\n"
+"&No"
+msgstr ""
+"‚Í‚¢(&Y)\n"
+"‚¢‚¢‚¦(&N)"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"Save &All\n"
+"&Discard All\n"
+"&Cancel"
+msgstr ""
+"‚Í‚¢(&Y)\n"
+"‚¢‚¢‚¦(&N)\n"
+"‘S‚Ä•Û‘¶(&A)\n"
+"‘S‚Ä•úŠü(&D)\n"
+"ƒLƒƒƒ“ƒZƒ‹(&C)"
+
+msgid "Select Directory dialog"
+msgstr "ƒfƒBƒŒƒNƒgƒŠ‘I‘ðƒ_ƒCƒAƒƒO"
+
+msgid "Save File dialog"
+msgstr "ƒtƒ@ƒCƒ‹•Û‘¶ƒ_ƒCƒAƒƒO"
+
+msgid "Open File dialog"
+msgstr "ƒtƒ@ƒCƒ‹“Çžƒ_ƒCƒAƒƒO"
+
+msgid "E338: Sorry, no file browser in console mode"
+msgstr "E338: ƒRƒ“ƒ\\[ƒ‹ƒ‚[ƒh‚ł̓tƒ@ƒCƒ‹ƒuƒ‰ƒEƒU‚ðŽg‚¦‚Ü‚¹‚ñA‚²‚ß‚ñ‚È‚³‚¢"
+
+msgid "E766: Insufficient arguments for printf()"
+msgstr "E766: printf() ‚̈ø”‚ª•s\\•ª‚Å‚·"
+
+msgid "E807: Expected Float argument for printf()"
+msgstr "E807: printf() ‚̈ø”‚É‚Í•‚“®¬”“_”‚ªŠú‘Ò‚³‚ê‚Ä‚¢‚Ü‚·"
+
+msgid "E767: Too many arguments to printf()"
+msgstr "E767: printf() ‚̈ø”‚ª‘½‰ß‚¬‚Ü‚·"
+
+msgid "W10: Warning: Changing a readonly file"
+msgstr "W10: Œx: “Çžê—pƒtƒ@ƒCƒ‹‚ð•ÏX‚µ‚Ü‚·"
+
+msgid "Type number and <Enter> or click with mouse (empty cancels): "
+msgstr ""
+"”Ô†‚Æ<Enter>‚ð“ü—Í‚·‚é‚©ƒ}ƒEƒX‚ŃNƒŠƒbƒN‚µ‚Ä‚­‚¾‚³‚¢ (‹ó‚ŃLƒƒƒ“ƒZƒ‹): "
+
+msgid "Type number and <Enter> (empty cancels): "
+msgstr "”Ô†‚Æ<Enter>‚ð“ü—Í‚µ‚Ä‚­‚¾‚³‚¢ (‹ó‚ŃLƒƒƒ“ƒZƒ‹): "
+
+#, c-format
+msgid "%ld more line"
+msgid_plural "%ld more lines"
+msgstr[0] "%ld s ’ljÁ‚µ‚Ü‚µ‚½"
+
+#, c-format
+msgid "%ld line less"
+msgid_plural "%ld fewer lines"
+msgstr[0] "%ld s 휂µ‚Ü‚µ‚½"
+
+msgid " (Interrupted)"
+msgstr " (Š„ž‚Ü‚ê‚Ü‚µ‚½)"
+
+msgid "Beep!"
+msgstr "ƒr[ƒb!"
+
+msgid "ERROR: "
+msgstr "ƒGƒ‰[: "
+
+#, c-format
+msgid ""
+"\n"
+"[bytes] total alloc-freed %lu-%lu, in use %lu, peak use %lu\n"
+msgstr ""
+"\n"
+"[ƒƒ‚ƒŠ(ƒoƒCƒg)] ‘Š„“–-‰ð•ú—Ê %lu-%lu, Žg—p—Ê %lu, ƒs[ƒNŽž %lu\n"
+
+#, c-format
+msgid ""
+"[calls] total re/malloc()'s %lu, total free()'s %lu\n"
+"\n"
+msgstr ""
+"[ŒÄo] ‘ re/malloc() ‰ñ” %lu, ‘ free() ‰ñ” %lu\n"
+"\n"
+
+msgid "E340: Line is becoming too long"
+msgstr "E340: s‚ª’·‚­‚È‚è‰ß‚¬‚Ü‚µ‚½"
+
+#, c-format
+msgid "E341: Internal error: lalloc(%ld, )"
+msgstr "E341: “à•”ƒGƒ‰[: lalloc(%ld,)"
+
+#, c-format
+msgid "E342: Out of memory! (allocating %lu bytes)"
+msgstr "E342: ƒƒ‚ƒŠ‚ª‘«‚è‚Ü‚¹‚ñ! (%lu ƒoƒCƒg‚ðŠ„“–—v‹)"
+
+#, c-format
+msgid "Calling shell to execute: \"%s\""
+msgstr "ŽÀs‚Ì‚½‚߂ɃVƒFƒ‹‚ðŒÄo‚µ’†: \"%s\""
+
+msgid "E545: Missing colon"
+msgstr "E545: ƒRƒƒ“‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "E546: Illegal mode"
+msgstr "E546: •s³‚ȃ‚[ƒh‚Å‚·"
+
+msgid "E547: Illegal mouseshape"
+msgstr "E547: •s³‚È 'mouseshape' ‚Å‚·"
+
+msgid "E548: digit expected"
+msgstr "E548: ”’l‚ª•K—v‚Å‚·"
+
+msgid "E549: Illegal percentage"
+msgstr "E549: •s³‚ȃp[ƒZƒ“ƒe[ƒW‚Å‚·"
+
+msgid "E854: path too long for completion"
+msgstr "E854: ƒpƒX‚ª’·‰ß‚¬‚ĕ⊮‚Å‚«‚Ü‚¹‚ñ"
+
+#, c-format
+msgid ""
+"E343: Invalid path: '**[number]' must be at the end of the path or be "
+"followed by '%s'."
+msgstr ""
+"E343: –³Œø‚ȃpƒX‚Å‚·: '**[”’l]' ‚Ípath‚ÌŌォ '%s' ‚ª‘±‚¢‚Ä‚È‚¢‚Æ‚¢‚¯‚Ü‚¹"
+"‚ñ."
+
+#, c-format
+msgid "E344: Can't find directory \"%s\" in cdpath"
+msgstr "E344: cdpath‚É‚Í \"%s\" ‚Æ‚¢‚¤ƒfƒBƒŒƒNƒgƒŠ‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E345: Can't find file \"%s\" in path"
+msgstr "E345: path‚É‚Í \"%s\" ‚Æ‚¢‚¤ƒtƒ@ƒCƒ‹‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E346: No more directory \"%s\" found in cdpath"
+msgstr "E346: cdpath‚É‚Í‚±‚êˆÈã \"%s\" ‚Æ‚¢‚¤ƒfƒBƒŒƒNƒgƒŠ‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E347: No more file \"%s\" found in path"
+msgstr "E347: ƒpƒX‚É‚Í‚±‚êˆÈã \"%s\" ‚Æ‚¢‚¤ƒtƒ@ƒCƒ‹‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E668: Wrong access mode for NetBeans connection info file: \"%s\""
+msgstr ""
+"E668: NetBeans‚ÌÚ‘±î•ñƒtƒ@ƒCƒ‹‚̃AƒNƒZƒXƒ‚[ƒh‚É–â‘肪‚ ‚è‚Ü‚·: \"%s\""
+
+#, c-format
+msgid "E658: NetBeans connection lost for buffer %ld"
+msgstr "E658: ƒoƒbƒtƒ@ %ld ‚Ì NetBeans Ú‘±‚ªŽ¸‚í‚ê‚Ü‚µ‚½"
+
+msgid "E838: netbeans is not supported with this GUI"
+msgstr "E838: NetBeans‚Í‚±‚ÌGUI‚ɂ͑Ήž‚µ‚Ä‚¢‚Ü‚¹‚ñ"
+
+msgid "E511: netbeans already connected"
+msgstr "E511: NetBeans‚ÍŠù‚ÉÚ‘±‚µ‚Ä‚¢‚Ü‚·"
+
+#, c-format
+msgid "E505: %s is read-only (add ! to override)"
+msgstr "E505: %s ‚Í“Çžê—p‚Å‚· (‹­§‘ž‚É‚Í ! ‚ð’ljÁ)"
+
+msgid "E349: No identifier under cursor"
+msgstr "E349: ƒJ[ƒ\\ƒ‹‚̈ʒu‚É‚ÍŽ¯•ÊŽq‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "E774: 'operatorfunc' is empty"
+msgstr "E774: 'operatorfunc' ƒIƒvƒVƒ‡ƒ“‚ª‹ó‚Å‚·"
+
+msgid "E775: Eval feature not available"
+msgstr "E775: Ž®•]‰¿‹@”\\‚ª–³Œø‚É‚È‚Á‚Ä‚¢‚Ü‚·"
+
+msgid "Warning: terminal cannot highlight"
+msgstr "Œx: Žg—p‚µ‚Ä‚¢‚é’[––‚̓nƒCƒ‰ƒCƒg‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "E348: No string under cursor"
+msgstr "E348: ƒJ[ƒ\\ƒ‹‚̈ʒu‚É‚Í•¶Žš—ñ‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "E352: Cannot erase folds with current 'foldmethod'"
+msgstr "E352: Œ»Ý‚Ì 'foldmethod' ‚Å‚ÍÜô‚Ý‚ðÁ‹Ž‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "E664: changelist is empty"
+msgstr "E664: •ÏXƒŠƒXƒg‚ª‹ó‚Å‚·"
+
+msgid "E662: At start of changelist"
+msgstr "E662: •ÏXƒŠƒXƒg‚Ì擪"
+
+msgid "E663: At end of changelist"
+msgstr "E663: •ÏXƒŠƒXƒg‚Ì––”ö"
+
+msgid "Type :qa! and press <Enter> to abandon all changes and exit Vim"
+msgstr ""
+"‚·‚ׂĂ̕ÏX‚ð”jŠü‚µAVim‚ðI—¹‚·‚é‚É‚Í :qa! ‚Æ“ü—Í‚µ <Enter> ‚ð‰Ÿ‚µ‚Ä‚­‚¾"
+"‚³‚¢"
+
+#, c-format
+msgid "%ld line %sed %d time"
+msgid_plural "%ld line %sed %d times"
+msgstr[0] "%ld s‚ª %s ‚Å %d ‰ñˆ—‚³‚ê‚Ü‚µ‚½"
+
+#, c-format
+msgid "%ld lines %sed %d time"
+msgid_plural "%ld lines %sed %d times"
+msgstr[0] "%ld s‚ª %s ‚Å %d ‰ñˆ—‚³‚ê‚Ü‚µ‚½"
+
+#, c-format
+msgid "%ld lines to indent... "
+msgstr "%ld s‚ªƒCƒ“ƒfƒ“ƒg‚³‚ê‚Ü‚·... "
+
+#, c-format
+msgid "%ld line indented "
+msgid_plural "%ld lines indented "
+msgstr[0] "%ld s‚ðƒCƒ“ƒfƒ“ƒg‚µ‚Ü‚µ‚½ "
+
+msgid "E748: No previously used register"
+msgstr "E748: ‚Ü‚¾ƒŒƒWƒXƒ^‚ðŽg—p‚µ‚Ä‚¢‚Ü‚¹‚ñ"
+
+msgid "cannot yank; delete anyway"
+msgstr "ƒ„ƒ“ƒN‚Å‚«‚Ü‚¹‚ñ; ‚Æ‚É‚©‚­Á‹Ž"
+
+#, c-format
+msgid "%ld line changed"
+msgid_plural "%ld lines changed"
+msgstr[0] "%ld s‚ª•ÏX‚³‚ê‚Ü‚µ‚½"
+
+#, c-format
+msgid "freeing %ld lines"
+msgstr "%ld s‚ð‰ð•ú’†"
+
+#, c-format
+msgid " into \"%c"
+msgstr " \"%c ‚É"
+
+#, c-format
+msgid "block of %ld line yanked%s"
+msgid_plural "block of %ld lines yanked%s"
+msgstr[0] "%ld s‚̃uƒƒbƒN‚ª%sƒ„ƒ“ƒN‚³‚ê‚Ü‚µ‚½"
+
+#, c-format
+msgid "%ld line yanked%s"
+msgid_plural "%ld lines yanked%s"
+msgstr[0] "%ld s‚ª%sƒ„ƒ“ƒN‚³‚ê‚Ü‚µ‚½"
+
+#, c-format
+msgid "E353: Nothing in register %s"
+msgstr "E353: ƒŒƒWƒXƒ^ %s ‚ɂ͉½‚à‚ ‚è‚Ü‚¹‚ñ"
+
+msgid ""
+"\n"
+"--- Registers ---"
+msgstr ""
+"\n"
+"--- ƒŒƒWƒXƒ^ ---"
+
+msgid "Illegal register name"
+msgstr "•s³‚ȃŒƒWƒXƒ^–¼"
+
+msgid ""
+"\n"
+"# Registers:\n"
+msgstr ""
+"\n"
+"# ƒŒƒWƒXƒ^:\n"
+
+#, c-format
+msgid "E574: Unknown register type %d"
+msgstr "E574: –¢’m‚̃ŒƒWƒXƒ^Œ^ %d ‚Å‚·"
+
+msgid ""
+"E883: search pattern and expression register may not contain two or more "
+"lines"
+msgstr "E883: ŒŸõƒpƒ^[ƒ“‚ÆŽ®ƒŒƒWƒXƒ^‚É‚Í2sˆÈã‚ðŠÜ‚ß‚ç‚ê‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "%ld Cols; "
+msgstr "%ld —ñ; "
+
+#, c-format
+msgid "Selected %s%ld of %ld Lines; %lld of %lld Words; %lld of %lld Bytes"
+msgstr "‘I‘ð %s%ld / %ld s; %lld / %lld ’PŒê; %lld / %lld ƒoƒCƒg"
+
+#, c-format
+msgid ""
+"Selected %s%ld of %ld Lines; %lld of %lld Words; %lld of %lld Chars; %lld of "
+"%lld Bytes"
+msgstr ""
+"‘I‘ð %s%ld / %ld s; %lld / %lld ’PŒê; %lld / %lld •¶Žš; %lld / %lld ƒoƒCƒg"
+
+#, c-format
+msgid "Col %s of %s; Line %ld of %ld; Word %lld of %lld; Byte %lld of %lld"
+msgstr "—ñ %s / %s; s %ld of %ld; ’PŒê %lld / %lld; ƒoƒCƒg %lld / %lld"
+
+#, c-format
+msgid ""
+"Col %s of %s; Line %ld of %ld; Word %lld of %lld; Char %lld of %lld; Byte "
+"%lld of %lld"
+msgstr ""
+"—ñ %s / %s; s %ld / %ld; ’PŒê %lld / %lld; •¶Žš %lld / %lld; ƒoƒCƒg %lld of "
+"%lld"
+
+#, c-format
+msgid "(+%lld for BOM)"
+msgstr "(+%lld for BOM)"
+
+msgid "Thanks for flying Vim"
+msgstr "Vim ‚ðŽg‚Á‚Ä‚­‚ê‚Ä‚ ‚肪‚Æ‚¤"
+
+msgid "E518: Unknown option"
+msgstr "E518: –¢’m‚̃IƒvƒVƒ‡ƒ“‚Å‚·"
+
+msgid "E519: Option not supported"
+msgstr "E519: ƒIƒvƒVƒ‡ƒ“‚̓Tƒ|[ƒg‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ"
+
+msgid "E520: Not allowed in a modeline"
+msgstr "E520: modeline ‚Å‚Í‹–‰Â‚³‚ê‚Ü‚¹‚ñ"
+
+msgid "E846: Key code not set"
+msgstr "E846: ƒL[ƒR[ƒh‚ªÝ’肳‚ê‚Ä‚¢‚Ü‚¹‚ñ"
+
+msgid "E521: Number required after ="
+msgstr "E521: = ‚ÌŒã‚É‚Í”Žš‚ª•K—v‚Å‚·"
+
+msgid "E522: Not found in termcap"
+msgstr "E522: termcap “à‚ÉŒ©‚‚©‚è‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E539: Illegal character <%s>"
+msgstr "E539: •s³‚È•¶Žš‚Å‚· <%s>"
+
+#, c-format
+msgid "For option %s"
+msgstr "ƒIƒvƒVƒ‡ƒ“: %s"
+
+msgid "E529: Cannot set 'term' to empty string"
+msgstr "E529: 'term' ‚ɂ͋󕶎š—ñ‚ðÝ’è‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "E530: Cannot change term in GUI"
+msgstr "E530: GUI‚Å‚Í 'term' ‚ð•ÏX‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "E531: Use \":gui\" to start the GUI"
+msgstr "E531: GUI‚ðƒXƒ^[ƒg‚·‚é‚É‚Í \":gui\" ‚ðŽg—p‚µ‚Ä‚­‚¾‚³‚¢"
+
+msgid "E589: 'backupext' and 'patchmode' are equal"
+msgstr "E589: 'backupext' ‚Æ 'patchmode' ‚ª“¯‚¶‚Å‚·"
+
+msgid "E834: Conflicts with value of 'listchars'"
+msgstr "E834: 'listchars'‚Ì’l‚É–µ‚‚ª‚ ‚è‚Ü‚·"
+
+msgid "E835: Conflicts with value of 'fillchars'"
+msgstr "E835: 'fillchars'‚Ì’l‚É–µ‚‚ª‚ ‚è‚Ü‚·"
+
+msgid "E617: Cannot be changed in the GTK+ 2 GUI"
+msgstr "E617: GTK+2 GUI‚Å‚Í•ÏX‚Å‚«‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E950: Cannot convert between %s and %s"
+msgstr "E950: %s ‚Æ %s ‚ÌŠÔ‚Å•ÏŠ·‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "E524: Missing colon"
+msgstr "E524: ƒRƒƒ“‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "E525: Zero length string"
+msgstr "E525: •¶Žš—ñ‚Ì’·‚³‚ªƒ[ƒ‚Å‚·"
+
+#, c-format
+msgid "E526: Missing number after <%s>"
+msgstr "E526: <%s> ‚ÌŒã‚É”Žš‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "E527: Missing comma"
+msgstr "E527: ƒJƒ“ƒ}‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "E528: Must specify a ' value"
+msgstr "E528: ' ‚Ì’l‚ðŽw’肵‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñ"
+
+msgid "E595: contains unprintable or wide character"
+msgstr "E595: •\\Ž¦‚Å‚«‚È‚¢•¶Žš‚©ƒƒCƒh•¶Žš‚ðŠÜ‚ñ‚Å‚¢‚Ü‚·"
+
+msgid "E596: Invalid font(s)"
+msgstr "E596: –³Œø‚ȃtƒHƒ“ƒg‚Å‚·"
+
+msgid "E597: can't select fontset"
+msgstr "E597: ƒtƒHƒ“ƒgƒZƒbƒg‚ð‘I‘ð‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "E598: Invalid fontset"
+msgstr "E598: –³Œø‚ȃtƒHƒ“ƒgƒZƒbƒg‚Å‚·"
+
+msgid "E533: can't select wide font"
+msgstr "E533: ƒƒCƒhƒtƒHƒ“ƒg‚ð‘I‘ð‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "E534: Invalid wide font"
+msgstr "E534: –³Œø‚ȃƒCƒhƒtƒHƒ“ƒg‚Å‚·"
+
+#, c-format
+msgid "E535: Illegal character after <%c>"
+msgstr "E535: <%c> ‚ÌŒã‚É•s³‚È•¶Žš‚ª‚ ‚è‚Ü‚·"
+
+msgid "E536: comma required"
+msgstr "E536: ƒJƒ“ƒ}‚ª•K—v‚Å‚·"
+
+#, c-format
+msgid "E537: 'commentstring' must be empty or contain %s"
+msgstr "E537: 'commentstring' ‚Í‹ó‚Å‚ ‚é‚© %s ‚ðŠÜ‚Þ•K—v‚ª‚ ‚è‚Ü‚·"
+
+msgid "E538: No mouse support"
+msgstr "E538: ƒ}ƒEƒX‚̓Tƒ|[ƒg‚³‚ê‚Ü‚¹‚ñ"
+
+msgid "E540: Unclosed expression sequence"
+msgstr "E540: Ž®‚ªI—¹‚µ‚Ä‚¢‚Ü‚¹‚ñ"
+
+msgid "E541: too many items"
+msgstr "E541: —v‘f‚ª‘½‰ß‚¬‚Ü‚·"
+
+msgid "E542: unbalanced groups"
+msgstr "E542: ƒOƒ‹[ƒv‚ª’Þ‡‚¢‚Ü‚¹‚ñ"
+
+msgid "E946: Cannot make a terminal with running job modifiable"
+msgstr "E946: ŽÀs’†‚̃Wƒ‡ƒu‚ª‚ ‚é’[––‚Í•ÏX‰Â”\\‚É‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "E590: A preview window already exists"
+msgstr "E590: ƒvƒŒƒrƒ…[ƒEƒBƒ“ƒhƒE‚ªŠù‚É‘¶Ý‚µ‚Ü‚·"
+
+msgid "W17: Arabic requires UTF-8, do ':set encoding=utf-8'"
+msgstr ""
+"W17: ƒAƒ‰ƒrƒA•¶Žš‚É‚ÍUTF-8‚ª•K—v‚È‚Ì‚ÅA':set encoding=utf-8' ‚µ‚Ä‚­‚¾‚³‚¢"
+
+msgid "E954: 24-bit colors are not supported on this environment"
+msgstr "E954: 24bitF‚Í‚±‚̊‹«‚ł̓Tƒ|[ƒg‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E593: Need at least %d lines"
+msgstr "E593: Å’á %d ‚Ìs”‚ª•K—v‚Å‚·"
+
+#, c-format
+msgid "E594: Need at least %d columns"
+msgstr "E594: Å’á %d ‚̃Jƒ‰ƒ€•‚ª•K—v‚Å‚·"
+
+#, c-format
+msgid "E355: Unknown option: %s"
+msgstr "E355: –¢’m‚̃IƒvƒVƒ‡ƒ“‚Å‚·: %s"
+
+#, c-format
+msgid "E521: Number required: &%s = '%s'"
+msgstr "E521: ”Žš‚ª•K—v‚Å‚·: &%s = '%s'"
+
+msgid ""
+"\n"
+"--- Terminal codes ---"
+msgstr ""
+"\n"
+"--- ’[––ƒR[ƒh ---"
+
+msgid ""
+"\n"
+"--- Global option values ---"
+msgstr ""
+"\n"
+"--- ƒOƒ[ƒoƒ‹ƒIƒvƒVƒ‡ƒ“’l ---"
+
+msgid ""
+"\n"
+"--- Local option values ---"
+msgstr ""
+"\n"
+"--- ƒ[ƒJƒ‹ƒIƒvƒVƒ‡ƒ“’l ---"
+
+msgid ""
+"\n"
+"--- Options ---"
+msgstr ""
+"\n"
+"--- ƒIƒvƒVƒ‡ƒ“ ---"
+
+msgid "E356: get_varp ERROR"
+msgstr "E356: get_varp ƒGƒ‰["
+
+#, c-format
+msgid "E357: 'langmap': Matching character missing for %s"
+msgstr "E357: 'langmap': %s ‚ɑΉž‚·‚镶Žš‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E358: 'langmap': Extra characters after semicolon: %s"
+msgstr "E358: 'langmap': ƒZƒ~ƒRƒƒ“‚ÌŒã‚É—]•ª‚È•¶Žš‚ª‚ ‚è‚Ü‚·: %s"
+
+msgid "cannot open "
+msgstr "ŠJ‚¯‚Ü‚¹‚ñ "
+
+msgid "VIM: Can't open window!\n"
+msgstr "VIM: ƒEƒBƒ“ƒhƒE‚ðŠJ‚¯‚Ü‚¹‚ñ!\n"
+
+msgid "Need Amigados version 2.04 or later\n"
+msgstr "Amigados‚̃o[ƒWƒ‡ƒ“ 2.04‚©‚»‚êˆÈ~‚ª•K—v‚Å‚·\n"
+
+#, c-format
+msgid "Need %s version %ld\n"
+msgstr "%s ‚̃o[ƒWƒ‡ƒ“ %ld ‚ª•K—v‚Å‚·\n"
+
+msgid "Cannot open NIL:\n"
+msgstr "NIL‚ðŠJ‚¯‚Ü‚¹‚ñ:\n"
+
+msgid "Cannot create "
+msgstr "쬂ł«‚Ü‚¹‚ñ "
+
+#, c-format
+msgid "Vim exiting with %d\n"
+msgstr "Vim‚Í %d ‚ÅI—¹‚µ‚Ü‚·\n"
+
+msgid "cannot change console mode ?!\n"
+msgstr "ƒRƒ“ƒ\\[ƒ‹ƒ‚[ƒh‚ð•ÏX‚Å‚«‚Ü‚¹‚ñ?!\n"
+
+msgid "mch_get_shellsize: not a console??\n"
+msgstr "mch_get_shellsize: ƒRƒ“ƒ\\[ƒ‹‚Å‚Í‚È‚¢??\n"
+
+msgid "E360: Cannot execute shell with -f option"
+msgstr "E360: -f ƒIƒvƒVƒ‡ƒ“‚ŃVƒFƒ‹‚ðŽÀs‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "Cannot execute "
+msgstr "ŽÀs‚Å‚«‚Ü‚¹‚ñ "
+
+msgid "shell "
+msgstr "ƒVƒFƒ‹ "
+
+msgid " returned\n"
+msgstr " –ß‚è‚Ü‚µ‚½\n"
+
+msgid "ANCHOR_BUF_SIZE too small."
+msgstr "ANCHOR_BUF_SIZE ‚ª¬‚³‰ß‚¬‚Ü‚·."
+
+msgid "I/O ERROR"
+msgstr "“üo—̓Gƒ‰["
+
+msgid "Message"
+msgstr "ƒƒbƒZ[ƒW"
+
+msgid "E237: Printer selection failed"
+msgstr "E237: ƒvƒŠƒ“ƒ^‚Ì‘I‘ð‚ÉŽ¸”s‚µ‚Ü‚µ‚½"
+
+#, c-format
+msgid "to %s on %s"
+msgstr "%s ‚Ö (%s ã‚Ì)"
+
+#, c-format
+msgid "E613: Unknown printer font: %s"
+msgstr "E613: –¢’m‚̃vƒŠƒ“ƒ^ƒIƒvƒVƒ‡ƒ“‚Å‚·: %s"
+
+#, c-format
+msgid "E238: Print error: %s"
+msgstr "E238: ˆóüƒGƒ‰[: %s"
+
+#, c-format
+msgid "Printing '%s'"
+msgstr "ˆóü‚µ‚Ä‚¢‚Ü‚·: '%s'"
+
+#, c-format
+msgid "E244: Illegal charset name \"%s\" in font name \"%s\""
+msgstr "E244: •¶ŽšƒZƒbƒg–¼ \"%s\" ‚Í•s³‚Å‚· (ƒtƒHƒ“ƒg–¼ \"%s\")"
+
+#, c-format
+msgid "E244: Illegal quality name \"%s\" in font name \"%s\""
+msgstr "E244: •iŽ¿–¼ \"%s\" ‚Í•s³‚Å‚· (ƒtƒHƒ“ƒg–¼ \"%s\")"
+
+#, c-format
+msgid "E245: Illegal char '%c' in font name \"%s\""
+msgstr "E245: '%c' ‚Í•s³‚È•¶Žš‚Å‚· (ƒtƒHƒ“ƒg–¼ \"%s\")"
+
+#, c-format
+msgid "Opening the X display took %ld msec"
+msgstr "XƒT[ƒo[‚Ö‚ÌÚ‘±‚É %ld ƒ~ƒŠ•b‚©‚©‚è‚Ü‚µ‚½"
+
+msgid ""
+"\n"
+"Vim: Got X error\n"
+msgstr ""
+"\n"
+"Vim: X ‚̃Gƒ‰[‚ðŒŸo‚µ‚Ü‚µ‚½r\n"
+
+msgid "Testing the X display failed"
+msgstr "X display ‚̃`ƒFƒbƒN‚ÉŽ¸”s‚µ‚Ü‚µ‚½"
+
+msgid "Opening the X display timed out"
+msgstr "X display ‚Ì open ‚ªƒ^ƒCƒ€ƒAƒEƒg‚µ‚Ü‚µ‚½"
+
+msgid ""
+"\n"
+"Could not get security context for "
+msgstr ""
+"\n"
+"ƒZƒLƒ…ƒŠƒeƒBƒRƒ“ƒeƒLƒXƒg‚ðŽæ“¾‚Å‚«‚Ü‚¹‚ñ "
+
+msgid ""
+"\n"
+"Could not set security context for "
+msgstr ""
+"\n"
+"ƒZƒLƒ…ƒŠƒeƒBƒRƒ“ƒeƒLƒXƒg‚ðÝ’è‚Å‚«‚Ü‚¹‚ñ "
+
+#, c-format
+msgid "Could not set security context %s for %s"
+msgstr "ƒZƒLƒ…ƒŠƒeƒBƒRƒ“ƒeƒLƒXƒg %s ‚ð %s ‚ÉÝ’è‚Å‚«‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "Could not get security context %s for %s. Removing it!"
+msgstr "ƒZƒLƒ…ƒŠƒeƒBƒRƒ“ƒeƒLƒXƒg %s ‚ð %s ‚©‚çŽæ“¾‚Å‚«‚Ü‚¹‚ñ. 휂µ‚Ü‚·!"
+
+msgid ""
+"\n"
+"Cannot execute shell sh\n"
+msgstr ""
+"\n"
+"sh ƒVƒFƒ‹‚ðŽÀs‚Å‚«‚Ü‚¹‚ñ\n"
+
+msgid ""
+"\n"
+"shell returned "
+msgstr ""
+"\n"
+"ƒVƒFƒ‹‚ª’l‚ð•Ô‚µ‚Ü‚µ‚½ "
+
+msgid ""
+"\n"
+"Cannot create pipes\n"
+msgstr ""
+"\n"
+"ƒpƒCƒv‚ð쬂ł«‚Ü‚¹‚ñ\n"
+
+msgid ""
+"\n"
+"Cannot fork\n"
+msgstr ""
+"\n"
+"fork ‚Å‚«‚Ü‚¹‚ñ\n"
+
+msgid ""
+"\n"
+"Cannot execute shell "
+msgstr ""
+"\n"
+"ƒVƒFƒ‹‚ðŽÀs‚Å‚«‚Ü‚¹‚ñ "
+
+msgid ""
+"\n"
+"Command terminated\n"
+msgstr ""
+"\n"
+"ƒRƒ}ƒ“ƒh‚ð’†’f‚µ‚Ü‚µ‚½\n"
+
+msgid "XSMP lost ICE connection"
+msgstr "XSMP ‚ªICEÚ‘±‚ðŽ¸‚¢‚Ü‚µ‚½"
+
+#, c-format
+msgid "dlerror = \"%s\""
+msgstr "dlerror = \"%s\""
+
+msgid "Opening the X display failed"
+msgstr "X display ‚Ì open ‚ÉŽ¸”s‚µ‚Ü‚µ‚½"
+
+msgid "XSMP handling save-yourself request"
+msgstr "XSMP ‚ªsave-yourself—v‹‚ðˆ—‚µ‚Ä‚¢‚Ü‚·"
+
+msgid "XSMP opening connection"
+msgstr "XSMP ‚ªÚ‘±‚ðŠJŽn‚µ‚Ä‚¢‚Ü‚·"
+
+msgid "XSMP ICE connection watch failed"
+msgstr "XSMP ICEÚ‘±‚ªŽ¸”s‚µ‚½‚悤‚Å‚·"
+
+#, c-format
+msgid "XSMP SmcOpenConnection failed: %s"
+msgstr "XSMP SmcOpenConnection‚ªŽ¸”s‚µ‚Ü‚µ‚½: %s"
+
+msgid "At line"
+msgstr "s"
+
+msgid "Could not load vim32.dll!"
+msgstr "vim32.dll ‚ðƒ[ƒh‚Å‚«‚Ü‚¹‚ñ‚Å‚µ‚½"
+
+msgid "VIM Error"
+msgstr "VIMƒGƒ‰["
+
+msgid "Could not fix up function pointers to the DLL!"
+msgstr "DLL‚©‚çŠÖ”ƒ|ƒCƒ“ƒ^‚ðŽæ“¾‚Å‚«‚Ü‚¹‚ñ‚Å‚µ‚½"
+
+#, c-format
+msgid "Vim: Caught %s event\n"
+msgstr "Vim: ƒCƒxƒ“ƒg %s ‚ðŒŸ’m\n"
+
+msgid "close"
+msgstr "•Â‚¶‚é"
+
+msgid "logoff"
+msgstr "ƒƒOƒIƒt"
+
+msgid "shutdown"
+msgstr "ƒVƒƒƒbƒgƒ_ƒEƒ“"
+
+msgid "E371: Command not found"
+msgstr "E371: ƒRƒ}ƒ“ƒh‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+msgid ""
+"VIMRUN.EXE not found in your $PATH.\n"
+"External commands will not pause after completion.\n"
+"See :help win32-vimrun for more information."
+msgstr ""
+"VIMRUN.EXE‚ª $PATH ‚Ì’†‚ÉŒ©‚‚©‚è‚Ü‚¹‚ñ.\n"
+"ŠO•”ƒRƒ}ƒ“ƒh‚ÌI—¹Œã‚Ɉꎞ’âŽ~‚ð‚µ‚Ü‚¹‚ñ.\n"
+"Ú×‚Í :help win32-vimrun ‚ðŽQÆ‚µ‚Ä‚­‚¾‚³‚¢."
+
+msgid "Vim Warning"
+msgstr "Vim‚ÌŒx"
+
+#, c-format
+msgid "shell returned %d"
+msgstr "ƒVƒFƒ‹‚ªƒR[ƒh %d ‚ÅI—¹‚µ‚Ü‚µ‚½"
+
+msgid "E926: Current location list was changed"
+msgstr "E926: Œ»Ý‚̃ƒP[ƒVƒ‡ƒ“ƒŠƒXƒg‚ª•ÏX‚³‚ê‚Ü‚µ‚½"
+
+#, c-format
+msgid "E372: Too many %%%c in format string"
+msgstr "E372: ƒtƒH[ƒ}ƒbƒg•¶Žš—ñ‚É %%%c ‚ª‘½‰ß‚¬‚Ü‚·"
+
+#, c-format
+msgid "E373: Unexpected %%%c in format string"
+msgstr "E373: ƒtƒH[ƒ}ƒbƒg•¶Žš—ñ‚É—\\Šú‚¹‚Ê %%%c ‚ª‚ ‚è‚Ü‚µ‚½"
+
+msgid "E374: Missing ] in format string"
+msgstr "E374: ƒtƒH[ƒ}ƒbƒg•¶Žš—ñ‚É ] ‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E375: Unsupported %%%c in format string"
+msgstr "E375: ƒtƒH[ƒ}ƒbƒg•¶Žš—ñ‚Å‚Í %%%c ‚̓Tƒ|[ƒg‚³‚ê‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E376: Invalid %%%c in format string prefix"
+msgstr "E376: ƒtƒH[ƒ}ƒbƒg•¶Žš—ñ‚Ì‘O’u‚É–³Œø‚È %%%c ‚ª‚ ‚è‚Ü‚·"
+
+#, c-format
+msgid "E377: Invalid %%%c in format string"
+msgstr "E377: ƒtƒH[ƒ}ƒbƒg•¶Žš—ñ‚É–³Œø‚È %%%c ‚ª‚ ‚è‚Ü‚·"
+
+msgid "E378: 'errorformat' contains no pattern"
+msgstr "E378: 'errorformat' ‚Ƀpƒ^[ƒ“‚ªŽw’肳‚ê‚Ä‚¢‚Ü‚¹‚ñ"
+
+msgid "E379: Missing or empty directory name"
+msgstr "E379: ƒfƒBƒŒƒNƒgƒŠ–¼‚ª–³‚¢‚©‹ó‚Å‚·"
+
+msgid "E553: No more items"
+msgstr "E553: —v‘f‚ª‚à‚¤‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "E924: Current window was closed"
+msgstr "E924: Œ»Ý‚̃EƒBƒ“ƒhƒE‚ª•Â‚¶‚ç‚ê‚Ü‚µ‚½"
+
+msgid "E925: Current quickfix was changed"
+msgstr "E925: Œ»Ý‚Ì quickfix ‚ª•ÏX‚³‚ê‚Ü‚µ‚½"
+
+#, c-format
+msgid "(%d of %d)%s%s: "
+msgstr "(%d of %d)%s%s: "
+
+msgid " (line deleted)"
+msgstr " (s‚ªíœ‚³‚ê‚Ü‚µ‚½)"
+
+#, c-format
+msgid "%serror list %d of %d; %d errors "
+msgstr "%s ƒGƒ‰[ˆê—— %d of %d; %d ŒÂƒGƒ‰["
+
+msgid "E380: At bottom of quickfix stack"
+msgstr "E380: quickfix ƒXƒ^ƒbƒN‚Ì––”ö‚Å‚·"
+
+msgid "E381: At top of quickfix stack"
+msgstr "E381: quickfix ƒXƒ^ƒbƒN‚Ì擪‚Å‚·"
+
+msgid "No entries"
+msgstr "ƒGƒ“ƒgƒŠ‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "Error file"
+msgstr "ƒGƒ‰[ƒtƒ@ƒCƒ‹"
+
+msgid "E683: File name missing or invalid pattern"
+msgstr "E683: ƒtƒ@ƒCƒ‹–¼‚ª–³‚¢‚©–³Œø‚ȃpƒ^[ƒ“‚Å‚·"
+
+#, c-format
+msgid "Cannot open file \"%s\""
+msgstr "ƒtƒ@ƒCƒ‹ \"%s\" ‚ðŠJ‚¯‚Ü‚¹‚ñ"
+
+msgid "E681: Buffer is not loaded"
+msgstr "E681: ƒoƒbƒtƒ@‚Í“Ç‚Ýž‚Ü‚ê‚Ü‚¹‚ñ‚Å‚µ‚½"
+
+msgid "E777: String or List expected"
+msgstr "E777: •¶Žš—ñ‚©ƒŠƒXƒg‚ª•K—v‚Å‚·"
+
+#, c-format
+msgid "E369: invalid item in %s%%[]"
+msgstr "E369: –³Œø‚È€–Ú‚Å‚·: %s%%[]"
+
+#, c-format
+msgid "E769: Missing ] after %s["
+msgstr "E769: %s[ ‚ÌŒã‚É ] ‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "E944: Reverse range in character class"
+msgstr "E944: •¶ŽšƒNƒ‰ƒX‚͈̔͂ª‹t‚Å‚·"
+
+msgid "E945: Range too large in character class"
+msgstr "E945: •¶ŽšƒNƒ‰ƒX‚͈̔͂ª‘å‚«‚·‚¬‚Ü‚·"
+
+#, c-format
+msgid "E53: Unmatched %s%%("
+msgstr "E53: %s%%( ‚ª’ނ臂Á‚Ä‚¢‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E54: Unmatched %s("
+msgstr "E54: %s( ‚ª’ނ臂Á‚Ä‚¢‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E55: Unmatched %s)"
+msgstr "E55: %s) ‚ª’ނ臂Á‚Ä‚¢‚Ü‚¹‚ñ"
+
+msgid "E66: \\z( not allowed here"
+msgstr "E66: \\z( ‚̓RƒR‚Å‚Í‹–‰Â‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ"
+
+msgid "E67: \\z1 - \\z9 not allowed here"
+msgstr "E67: \\z1 - \\z9 ‚̓RƒR‚Å‚Í‹–‰Â‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E69: Missing ] after %s%%["
+msgstr "E69: %s%%[ ‚ÌŒã‚É ] ‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E70: Empty %s%%[]"
+msgstr "E70: %s%%[] ‚ª‹ó‚Å‚·"
+
+msgid "E956: Cannot use pattern recursively"
+msgstr "E956: ƒpƒ^[ƒ“‚ðÄ‹A“I‚ÉŽg‚¤‚±‚Æ‚Í‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "E65: Illegal back reference"
+msgstr "E65: •s³‚ÈŒã•ûŽQÆ‚Å‚·"
+
+msgid "E339: Pattern too long"
+msgstr "E339: ƒpƒ^[ƒ“‚ª’·‰ß‚¬‚Ü‚·"
+
+msgid "E50: Too many \\z("
+msgstr "E50: \\z( ‚ª‘½‰ß‚¬‚Ü‚·"
+
+#, c-format
+msgid "E51: Too many %s("
+msgstr "E51: %s( ‚ª‘½‰ß‚¬‚Ü‚·"
+
+msgid "E52: Unmatched \\z("
+msgstr "E52: \\z( ‚ª’ނ臂Á‚Ä‚¢‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E59: invalid character after %s@"
+msgstr "E59: %s@ ‚ÌŒã‚É•s³‚È•¶Žš‚ª‚ ‚è‚Ü‚µ‚½"
+
+#, c-format
+msgid "E60: Too many complex %s{...}s"
+msgstr "E60: •¡ŽG‚È %s{...} ‚ª‘½‰ß‚¬‚Ü‚·"
+
+#, c-format
+msgid "E61: Nested %s*"
+msgstr "E61:%s* ‚ª“ü‚êŽq‚É‚È‚Á‚Ä‚¢‚Ü‚·"
+
+#, c-format
+msgid "E62: Nested %s%c"
+msgstr "E62:%s%c ‚ª“ü‚êŽq‚É‚È‚Á‚Ä‚¢‚Ü‚·"
+
+msgid "E63: invalid use of \\_"
+msgstr "E63: \\_ ‚Ì–³Œø‚ÈŽg—p•û–@‚Å‚·"
+
+#, c-format
+msgid "E64: %s%c follows nothing"
+msgstr "E64:%s%c ‚ÌŒã‚É‚È‚É‚à‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "E68: Invalid character after \\z"
+msgstr "E68: \\z ‚ÌŒã‚É•s³‚È•¶Žš‚ª‚ ‚è‚Ü‚µ‚½"
+
+#, c-format
+msgid "E678: Invalid character after %s%%[dxouU]"
+msgstr "E678: %s%%[dxouU] ‚ÌŒã‚É•s³‚È•¶Žš‚ª‚ ‚è‚Ü‚µ‚½"
+
+#, c-format
+msgid "E71: Invalid character after %s%%"
+msgstr "E71: %s%% ‚ÌŒã‚É•s³‚È•¶Žš‚ª‚ ‚è‚Ü‚µ‚½"
+
+#, c-format
+msgid "E554: Syntax error in %s{...}"
+msgstr "E554: %s{...} “à‚É•¶–@ƒGƒ‰[‚ª‚ ‚è‚Ü‚·"
+
+msgid "External submatches:\n"
+msgstr "ŠO•”‚Ì•”•ªŠY“–:\n"
+
+#, c-format
+msgid "E888: (NFA regexp) cannot repeat %s"
+msgstr "E888: (NFA ³‹K•\\Œ») ŒJ‚è•Ô‚¹‚Ü‚¹‚ñ %s"
+
+msgid ""
+"E864: \\%#= can only be followed by 0, 1, or 2. The automatic engine will be "
+"used "
+msgstr ""
+"E864: \\%#= ‚É‚Í 0, 1 ‚à‚µ‚­‚Í 2 ‚Ì‚Ý‚ª‘±‚¯‚ç‚ê‚Ü‚·B³‹K•\\Œ»ƒGƒ“ƒWƒ“‚ÍŽ©“®‘I"
+"‘ð‚³‚ê‚Ü‚·B"
+
+msgid "Switching to backtracking RE engine for pattern: "
+msgstr "ŽŸ‚̃pƒ^[ƒ“‚ɃoƒbƒNƒgƒ‰ƒbƒLƒ“ƒO RE ƒGƒ“ƒWƒ“‚ð“K—p‚µ‚Ü‚·: "
+
+msgid "E865: (NFA) Regexp end encountered prematurely"
+msgstr "E865: (NFA) Šú‘Ò‚æ‚è‘‚­³‹K•\\Œ»‚ÌI’[‚É“ž’B‚µ‚Ü‚µ‚½"
+
+#, c-format
+msgid "E866: (NFA regexp) Misplaced %c"
+msgstr "E866: (NFA ³‹K•\\Œ») ˆÊ’u‚ªŒë‚Á‚Ä‚¢‚Ü‚·: %c"
+
+#, c-format
+msgid "E877: (NFA regexp) Invalid character class: %ld"
+msgstr "E877: (NFA ³‹K•\\Œ») –³Œø‚È•¶ŽšƒNƒ‰ƒX: %ld"
+
+#, c-format
+msgid "E867: (NFA) Unknown operator '\\z%c'"
+msgstr "E867: (NFA) –¢’m‚̃IƒyƒŒ[ƒ^‚Å‚·: '\\z%c'"
+
+msgid "E951: \\% value too large"
+msgstr "E951: \\% ’l‚ª’·‰ß‚¬‚Ü‚·"
+
+#, c-format
+msgid "E867: (NFA) Unknown operator '\\%%%c'"
+msgstr "E867: (NFA) –¢’m‚̃IƒyƒŒ[ƒ^‚Å‚·: '\\%%%c'"
+
+msgid "E868: Error building NFA with equivalence class!"
+msgstr "E868: “™‰¿ƒNƒ‰ƒX‚ðŠÜ‚ÞNFA\\’z‚ÉŽ¸”s‚µ‚Ü‚µ‚½!"
+
+#, c-format
+msgid "E869: (NFA) Unknown operator '\\@%c'"
+msgstr "E869: (NFA) –¢’m‚̃IƒyƒŒ[ƒ^‚Å‚·: '\\@%c'"
+
+msgid "E870: (NFA regexp) Error reading repetition limits"
+msgstr "E870: (NFA ³‹K•\\Œ») ŒJ‚è•Ô‚µ‚̧ŒÀ‰ñ”‚ð“Çž’†‚ɃGƒ‰["
+
+msgid "E871: (NFA regexp) Can't have a multi follow a multi"
+msgstr "E871: (NFA ³‹K•\\Œ») ŒJ‚è•Ô‚µ ‚ÌŒã‚É ŒJ‚è•Ô‚µ ‚Í‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "E872: (NFA regexp) Too many '('"
+msgstr "E872: (NFA ³‹K•\\Œ») '(' ‚ª‘½‰ß‚¬‚Ü‚·"
+
+msgid "E879: (NFA regexp) Too many \\z("
+msgstr "E879: (NFA ³‹K•\\Œ») \\z( ‚ª‘½‰ß‚¬‚Ü‚·"
+
+msgid "E873: (NFA regexp) proper termination error"
+msgstr "E873: (NFA ³‹K•\\Œ») I’[‹L†‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "Could not open temporary log file for writing, displaying on stderr... "
+msgstr ""
+"NFA³‹K•\\Œ»ƒGƒ“ƒWƒ“—p‚̃ƒOƒtƒ@ƒCƒ‹‚ð‘ž—p‚Æ‚µ‚ÄŠJ‚¯‚Ü‚¹‚ñBƒƒO‚Í•W€ƒGƒ‰["
+"o—Í‚Éo—Í‚µ‚Ü‚·B"
+
+msgid "E874: (NFA) Could not pop the stack!"
+msgstr "E874: (NFA) ƒXƒ^ƒbƒN‚ðƒ|ƒbƒv‚Å‚«‚Ü‚¹‚ñ!"
+
+msgid ""
+"E875: (NFA regexp) (While converting from postfix to NFA), too many states "
+"left on stack"
+msgstr ""
+"E875: (NFA ³‹K•\\Œ») (Œã’u•¶Žš—ñ‚ðNFA‚É•ÏŠ·’†‚É) ƒXƒ^ƒbƒN‚ÉŽc‚³‚ꂽƒXƒe[ƒg‚ª"
+"‘½‰ß‚¬‚Ü‚·"
+
+msgid "E876: (NFA regexp) Not enough space to store the whole NFA "
+msgstr "E876: (NFA ³‹K•\\Œ») NFA‘S‘Ì‚ð•Û‘¶‚·‚é‚ɂ͋󂫃Xƒy[ƒX‚ª‘«‚è‚Ü‚¹‚ñ"
+
+msgid "E878: (NFA) Could not allocate memory for branch traversal!"
+msgstr "E878: (NFA) Œ»Ý‰¡’f’†‚̃uƒ‰ƒ“ƒ`‚É\\•ª‚ȃƒ‚ƒŠ‚ðŠ„‚è“–‚Ä‚ç‚ê‚Ü‚¹‚ñ!"
+
+msgid " VREPLACE"
+msgstr " ‰¼‘z’uŠ·"
+
+msgid " REPLACE"
+msgstr " ’uŠ·"
+
+msgid " REVERSE"
+msgstr " ”½“]"
+
+msgid " INSERT"
+msgstr " ‘}“ü"
+
+msgid " (insert)"
+msgstr " (‘}“ü)"
+
+msgid " (replace)"
+msgstr " (’uŠ·)"
+
+msgid " (vreplace)"
+msgstr " (‰¼‘z’uŠ·)"
+
+msgid " Hebrew"
+msgstr " ƒwƒuƒ‰ƒC"
+
+msgid " Arabic"
+msgstr " ƒAƒ‰ƒrƒA"
+
+msgid " (paste)"
+msgstr " (“\\‚è•t‚¯)"
+
+msgid " VISUAL"
+msgstr " ƒrƒWƒ…ƒAƒ‹"
+
+msgid " VISUAL LINE"
+msgstr " ƒrƒWƒ…ƒAƒ‹ s"
+
+msgid " VISUAL BLOCK"
+msgstr " ƒrƒWƒ…ƒAƒ‹ ‹éŒ`"
+
+msgid " SELECT"
+msgstr " ƒZƒŒƒNƒg"
+
+msgid " SELECT LINE"
+msgstr " sŽwŒü‘I‘ð"
+
+msgid " SELECT BLOCK"
+msgstr " ‹éŒ`‘I‘ð"
+
+msgid "recording"
+msgstr "‹L˜^’†"
+
+#, c-format
+msgid "E383: Invalid search string: %s"
+msgstr "E383: –³Œø‚ÈŒŸõ•¶Žš—ñ‚Å‚·: %s"
+
+#, c-format
+msgid "E384: search hit TOP without match for: %s"
+msgstr "E384: ã‚Ü‚ÅŒŸõ‚µ‚Ü‚µ‚½‚ªŠY“–‰ÓŠ‚Í‚ ‚è‚Ü‚¹‚ñ: %s"
+
+#, c-format
+msgid "E385: search hit BOTTOM without match for: %s"
+msgstr "E385: ‰º‚Ü‚ÅŒŸõ‚µ‚Ü‚µ‚½‚ªŠY“–‰ÓŠ‚Í‚ ‚è‚Ü‚¹‚ñ: %s"
+
+msgid "E386: Expected '?' or '/' after ';'"
+msgstr "E386: ';' ‚Ì‚ ‚Æ‚É‚Í '?' ‚© '/' ‚ªŠú‘Ò‚³‚ê‚Ä‚¢‚é"
+
+msgid " (includes previously listed match)"
+msgstr " (‘O‚É—ñ‹“‚µ‚½ŠY“–‰ÓŠ‚ðŠÜ‚Þ)"
+
+msgid "--- Included files "
+msgstr "--- ƒCƒ“ƒNƒ‹[ƒh‚³‚ꂽƒtƒ@ƒCƒ‹ "
+
+msgid "not found "
+msgstr "Œ©‚‚©‚è‚Ü‚¹‚ñ "
+
+msgid "in path ---\n"
+msgstr "ƒpƒX‚É ----\n"
+
+msgid " (Already listed)"
+msgstr " (Šù‚É—ñ‹“)"
+
+msgid " NOT FOUND"
+msgstr " Œ©‚‚©‚è‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "Scanning included file: %s"
+msgstr "ƒCƒ“ƒNƒ‹[ƒh‚³‚ꂽƒtƒ@ƒCƒ‹‚ðƒXƒLƒƒƒ“’†: %s"
+
+#, c-format
+msgid "Searching included file %s"
+msgstr "ƒCƒ“ƒNƒ‹[ƒh‚³‚ꂽƒtƒ@ƒCƒ‹‚ðŒŸõ’† %s"
+
+msgid "E387: Match is on current line"
+msgstr "E387: Œ»Ýs‚ÉŠY“–‚ª‚ ‚è‚Ü‚·"
+
+msgid "All included files were found"
+msgstr "‘S‚ẴCƒ“ƒNƒ‹[ƒh‚³‚ꂽƒtƒ@ƒCƒ‹‚ªŒ©‚‚©‚è‚Ü‚µ‚½"
+
+msgid "No included files"
+msgstr "ƒCƒ“ƒNƒ‹[ƒhƒtƒ@ƒCƒ‹‚Í‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "E388: Couldn't find definition"
+msgstr "E388: ’è‹`‚ðŒ©‚Â‚¯‚ç‚ê‚Ü‚¹‚ñ"
+
+msgid "E389: Couldn't find pattern"
+msgstr "E389: ƒpƒ^[ƒ“‚ðŒ©‚Â‚¯‚ç‚ê‚Ü‚¹‚ñ"
+
+msgid "Substitute "
+msgstr "Substitute "
+
+#, c-format
+msgid ""
+"\n"
+"# Last %sSearch Pattern:\n"
+"~"
+msgstr ""
+"\n"
+"# ÅŒã‚Ì %sŒŸõƒpƒ^[ƒ“:\n"
+"~"
+
+msgid "E756: Spell checking is not enabled"
+msgstr "E756: ƒXƒyƒ‹ƒ`ƒFƒbƒN‚Í–³Œø‰»‚³‚ê‚Ä‚¢‚Ü‚·"
+
+#, c-format
+msgid "Warning: Cannot find word list \"%s_%s.spl\" or \"%s_ascii.spl\""
+msgstr ""
+"Œx: ’PŒêƒŠƒXƒg \"%s_%s.spl\" ‚¨‚æ‚Ñ \"%s_ascii.spl\" ‚ÍŒ©‚‚©‚è‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "Warning: Cannot find word list \"%s.%s.spl\" or \"%s.ascii.spl\""
+msgstr ""
+"Œx: ’PŒêƒŠƒXƒg \"%s.%s.spl\" ‚¨‚æ‚Ñ \"%s.ascii.spl\" ‚ÍŒ©‚‚©‚è‚Ü‚¹‚ñ"
+
+msgid "E797: SpellFileMissing autocommand deleted buffer"
+msgstr "E797: autocommand ‚Ì SpellFileMissing ‚ªƒoƒbƒtƒ@‚ð휂µ‚Ü‚µ‚½"
+
+#, c-format
+msgid "Warning: region %s not supported"
+msgstr "Œx9: %s ‚Æ‚¢‚¤”͈͂̓Tƒ|[ƒg‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ"
+
+msgid "Sorry, no suggestions"
+msgstr "Žc”O‚Å‚·‚ªAC³Œó•â‚Í‚ ‚è‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "Sorry, only %ld suggestions"
+msgstr "Žc”O‚Å‚·‚ªAC³Œó•â‚Í %ld ŒÂ‚µ‚©‚ ‚è‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "Change \"%.*s\" to:"
+msgstr "\"%.*s\" ‚ðŽŸ‚Ö•ÏŠ·:"
+
+#, c-format
+msgid " < \"%.*s\""
+msgstr " < \"%.*s\""
+
+msgid "E752: No previous spell replacement"
+msgstr "E752: ƒXƒyƒ‹’uŠ·‚ª‚Ü‚¾ŽÀs‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E753: Not found: %s"
+msgstr "E753: Œ©‚‚©‚è‚Ü‚¹‚ñ: %s"
+
+msgid "E758: Truncated spell file"
+msgstr "E758: ƒXƒyƒ‹ƒtƒ@ƒCƒ‹‚ªØŽæ‚ç‚ê‚Ä‚¢‚é‚悤‚Å‚·"
+
+#, c-format
+msgid "Trailing text in %s line %d: %s"
+msgstr "%s (%d s–Ú) ‚É‘±‚­ƒeƒLƒXƒg: %s"
+
+#, c-format
+msgid "Affix name too long in %s line %d: %s"
+msgstr "%s (%d s–Ú) ‚Ì affix –¼‚ª’·‰ß‚¬‚Ü‚·: %s"
+
+msgid "E761: Format error in affix file FOL, LOW or UPP"
+msgstr ""
+"E761: affixƒtƒ@ƒCƒ‹‚Ì FOL, LOW ‚à‚µ‚­‚Í UPP ‚̃tƒH[ƒ}ƒbƒg‚ɃGƒ‰[‚ª‚ ‚è‚Ü‚·"
+
+msgid "E762: Character in FOL, LOW or UPP is out of range"
+msgstr "E762: FOL, LOW ‚à‚µ‚­‚Í UPP ‚Ì•¶Žš‚ª”͈͊O‚Å‚·"
+
+msgid "Compressing word tree..."
+msgstr "’PŒêƒcƒŠ[‚ðˆ³k‚µ‚Ä‚¢‚Ü‚·..."
+
+#, c-format
+msgid "Reading spell file \"%s\""
+msgstr "ƒXƒyƒ‹ƒtƒ@ƒCƒ‹ \"%s\" ‚ð“Çž’†"
+
+msgid "E757: This does not look like a spell file"
+msgstr "E757: ƒXƒyƒ‹ƒtƒ@ƒCƒ‹‚Å‚Í‚È‚¢‚悤‚Å‚·"
+
+msgid "E771: Old spell file, needs to be updated"
+msgstr "E771: ŒÃ‚¢ƒXƒyƒ‹ƒtƒ@ƒCƒ‹‚È‚Ì‚ÅAƒAƒbƒvƒf[ƒg‚µ‚Ä‚­‚¾‚³‚¢"
+
+msgid "E772: Spell file is for newer version of Vim"
+msgstr "E772: ‚æ‚èV‚µ‚¢ƒo[ƒWƒ‡ƒ“‚Ì Vim —p‚̃Xƒyƒ‹ƒtƒ@ƒCƒ‹‚Å‚·"
+
+msgid "E770: Unsupported section in spell file"
+msgstr "E770: ƒXƒyƒ‹ƒtƒ@ƒCƒ‹‚ɃTƒ|[ƒg‚µ‚Ä‚¢‚È‚¢ƒZƒNƒVƒ‡ƒ“‚ª‚ ‚è‚Ü‚·"
+
+#, c-format
+msgid "E778: This does not look like a .sug file: %s"
+msgstr "E778: .sug ƒtƒ@ƒCƒ‹‚Å‚Í‚È‚¢‚悤‚Å‚·: %s"
+
+#, c-format
+msgid "E779: Old .sug file, needs to be updated: %s"
+msgstr "E779: ŒÃ‚¢ .sug ƒtƒ@ƒCƒ‹‚È‚Ì‚ÅAƒAƒbƒvƒf[ƒg‚µ‚Ä‚­‚¾‚³‚¢: %s"
+
+#, c-format
+msgid "E780: .sug file is for newer version of Vim: %s"
+msgstr "E780: ‚æ‚èV‚µ‚¢ƒo[ƒWƒ‡ƒ“‚Ì Vim —p‚Ì .sug ƒtƒ@ƒCƒ‹‚Å‚·: %s"
+
+#, c-format
+msgid "E781: .sug file doesn't match .spl file: %s"
+msgstr "E781: .sug ƒtƒ@ƒCƒ‹‚ª .spl ƒtƒ@ƒCƒ‹‚ƈê’v‚µ‚Ü‚¹‚ñ: %s"
+
+#, c-format
+msgid "E782: error while reading .sug file: %s"
+msgstr "E782: .sug ƒtƒ@ƒCƒ‹‚Ì“Çž’†‚ɃGƒ‰[‚ª”­¶‚µ‚Ü‚µ‚½: %s"
+
+#, c-format
+msgid "Reading affix file %s..."
+msgstr "affix ƒtƒ@ƒCƒ‹ %s ‚ð“Çž’†..."
+
+#, c-format
+msgid "Conversion failure for word in %s line %d: %s"
+msgstr "%s (%d s–Ú) ‚Ì’PŒê‚ð•ÏŠ·‚Å‚«‚Ü‚¹‚ñ‚Å‚µ‚½: %s"
+
+#, c-format
+msgid "Conversion in %s not supported: from %s to %s"
+msgstr "%s “à‚ÌŽŸ‚Ì•ÏŠ·‚̓Tƒ|[ƒg‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ: %s ‚©‚ç %s ‚Ö"
+
+#, c-format
+msgid "Conversion in %s not supported"
+msgstr "%s “à‚Ì•ÏŠ·‚̓Tƒ|[ƒg‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "Invalid value for FLAG in %s line %d: %s"
+msgstr "%s “à‚Ì %d s–Ú‚Ì FLAG ‚É–³Œø‚È’l‚ª‚ ‚è‚Ü‚·: %s"
+
+#, c-format
+msgid "FLAG after using flags in %s line %d: %s"
+msgstr "%s “à‚Ì %d s–ڂɃtƒ‰ƒO‚Ì“ñdŽg—p‚ª‚ ‚è‚Ü‚·: %s"
+
+#, c-format
+msgid ""
+"Defining COMPOUNDFORBIDFLAG after PFX item may give wrong results in %s line "
+"%d"
+msgstr ""
+"%s ‚Ì %d s–Ú‚Ì PFX €–Ú‚ÌŒã‚Ì COMPOUNDFORBIDFLAG ‚Ì’è‹`‚ÍŒë‚Á‚½Œ‹‰Ê‚𶂶‚é"
+"‚±‚Æ‚ª‚ ‚è‚Ü‚·"
+
+#, c-format
+msgid ""
+"Defining COMPOUNDPERMITFLAG after PFX item may give wrong results in %s line "
+"%d"
+msgstr ""
+"%s ‚Ì %d s–Ú‚Ì PFX €–Ú‚ÌŒã‚Ì COMPOUNDPERMITFLAG ‚Ì’è‹`‚ÍŒë‚Á‚½Œ‹‰Ê‚𶂶‚é"
+"‚±‚Æ‚ª‚ ‚è‚Ü‚·"
+
+#, c-format
+msgid "Wrong COMPOUNDRULES value in %s line %d: %s"
+msgstr "COMPOUNDRULES ‚Ì’l‚ÉŒë‚肪‚ ‚è‚Ü‚·. ƒtƒ@ƒCƒ‹ %s ‚Ì %d s–Ú: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDWORDMAX value in %s line %d: %s"
+msgstr "%s ‚Ì %d s–Ú‚Ì COMPOUNDWORDMAX ‚Ì’l‚ÉŒë‚肪‚ ‚è‚Ü‚·: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDMIN value in %s line %d: %s"
+msgstr "%s ‚Ì %d s–Ú‚Ì COMPOUNDMIN ‚Ì’l‚ÉŒë‚肪‚ ‚è‚Ü‚·: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDSYLMAX value in %s line %d: %s"
+msgstr "%s ‚Ì %d s–Ú‚Ì COMPOUNDSYLMAX ‚Ì’l‚ÉŒë‚肪‚ ‚è‚Ü‚·: %s"
+
+#, c-format
+msgid "Wrong CHECKCOMPOUNDPATTERN value in %s line %d: %s"
+msgstr "%s ‚Ì %d s–Ú‚Ì CHECKCOMPOUNDPATTERN ‚Ì’l‚ÉŒë‚肪‚ ‚è‚Ü‚·: %s"
+
+#, c-format
+msgid "Different combining flag in continued affix block in %s line %d: %s"
+msgstr ""
+"%s ‚Ì %d s–Ú‚Ì ˜A‘± affix ƒuƒƒbƒN‚̃tƒ‰ƒO‚Ì‘g‡‚¹‚ɈႢ‚ª‚ ‚è‚Ü‚·: %s"
+
+#, c-format
+msgid "Duplicate affix in %s line %d: %s"
+msgstr "%s ‚Ì %d s–Ú‚É d•¡‚µ‚½ affix ‚ðŒŸo‚µ‚Ü‚µ‚½: %s"
+
+#, c-format
+msgid ""
+"Affix also used for BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST in %s "
+"line %d: %s"
+msgstr ""
+"%s ‚Ì %d s–Ú‚Ì affix ‚Í BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST "
+"‚ÉŽg—p‚µ‚Ä‚­‚¾‚³‚¢: %s"
+
+#, c-format
+msgid "Expected Y or N in %s line %d: %s"
+msgstr "%s ‚Ì %d s–Ú‚Å‚Í Y ‚© N ‚ª•K—v‚Å‚·: %s"
+
+#, c-format
+msgid "Broken condition in %s line %d: %s"
+msgstr "%s ‚Ì %d s–Ú‚Ì ðŒ‚͉ó‚ê‚Ä‚¢‚Ü‚·: %s"
+
+#, c-format
+msgid "Expected REP(SAL) count in %s line %d"
+msgstr "%s ‚Ì %d s–Ú‚É‚Í REP(SAL) ‚̉ñ”‚ª•K—v‚Å‚·"
+
+#, c-format
+msgid "Expected MAP count in %s line %d"
+msgstr "%s ‚Ì %d s–Ú‚É‚Í MAP ‚̉ñ”‚ª•K—v‚Å‚·"
+
+#, c-format
+msgid "Duplicate character in MAP in %s line %d"
+msgstr "%s ‚Ì %d s–Ú‚Ì MAP ‚Éd•¡‚µ‚½•¶Žš‚ª‚ ‚è‚Ü‚·"
+
+#, c-format
+msgid "Unrecognized or duplicate item in %s line %d: %s"
+msgstr "%s ‚Ì %d s–Ú‚É ”FŽ¯‚Å‚«‚È‚¢‚©d•¡‚µ‚½€–Ú‚ª‚ ‚è‚Ü‚·: %s"
+
+#, c-format
+msgid "Missing FOL/LOW/UPP line in %s"
+msgstr "%s s–Ú‚É FOL/LOW/UPP ‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "COMPOUNDSYLMAX used without SYLLABLE"
+msgstr "SYLLABLE ‚ªŽw’肳‚ê‚È‚¢ COMPOUNDSYLMAX"
+
+msgid "Too many postponed prefixes"
+msgstr "’x‰„Œã’uŽq‚ª‘½‰ß‚¬‚Ü‚·"
+
+msgid "Too many compound flags"
+msgstr "•¡‡ƒtƒ‰ƒO‚ª‘½‰ß‚¬‚Ü‚·"
+
+msgid "Too many postponed prefixes and/or compound flags"
+msgstr "’x‰„Œã’uŽq ‚Æ/‚à‚µ‚­‚Í •¡‡ƒtƒ‰ƒO‚ª‘½‰ß‚¬‚Ü‚·"
+
+#, c-format
+msgid "Missing SOFO%s line in %s"
+msgstr "SOFO%s s‚ª %s ‚É‚ ‚è‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "Both SAL and SOFO lines in %s"
+msgstr "SALs ‚Æ SOFOs ‚ª %s ‚Å—¼•ûŽw’肳‚ê‚Ä‚¢‚Ü‚·"
+
+#, c-format
+msgid "Flag is not a number in %s line %d: %s"
+msgstr "%s ‚Ì %d s‚Ì ƒtƒ‰ƒO‚ª”’l‚Å‚Í‚ ‚è‚Ü‚¹‚ñ: %s"
+
+#, c-format
+msgid "Illegal flag in %s line %d: %s"
+msgstr "%s ‚Ì %d s–Ú‚Ì ƒtƒ‰ƒO‚ª•s³‚Å‚·: %s"
+
+#, c-format
+msgid "%s value differs from what is used in another .aff file"
+msgstr "’l %s ‚Í‘¼‚Ì .aff ƒtƒ@ƒCƒ‹‚ÅŽg—p‚³‚ꂽ‚̂ƈقȂè‚Ü‚·"
+
+#, c-format
+msgid "Reading dictionary file %s..."
+msgstr "Ž«‘ƒtƒ@ƒCƒ‹ %s ‚ð“Çž‚Ý’†..."
+
+#, c-format
+msgid "E760: No word count in %s"
+msgstr "E760: %s ‚É‚Í’PŒê”‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "line %6d, word %6ld - %s"
+msgstr "s %6d, ’PŒê %6ld - %s"
+
+#, c-format
+msgid "Duplicate word in %s line %d: %s"
+msgstr "%s ‚Ì %d s–Ú‚Å d•¡’PŒê‚ªŒ©‚‚©‚è‚Ü‚µ‚½: %s"
+
+#, c-format
+msgid "First duplicate word in %s line %d: %s"
+msgstr "d•¡‚Ì‚¤‚¿Å‰‚Ì’PŒê‚Í %s ‚Ì %d s–Ú‚Å‚·: %s"
+
+#, c-format
+msgid "%d duplicate word(s) in %s"
+msgstr "%d ŒÂ‚Ì’PŒê‚ªŒ©‚‚©‚è‚Ü‚µ‚½ (%s “à)"
+
+#, c-format
+msgid "Ignored %d word(s) with non-ASCII characters in %s"
+msgstr "”ñASCII•¶Žš‚ðŠÜ‚Þ %d ŒÂ‚Ì’PŒê‚𖳎‹‚µ‚Ü‚µ‚½ (%s “à)"
+
+#, c-format
+msgid "Reading word file %s..."
+msgstr "’PŒêƒtƒ@ƒCƒ‹ %s ‚ð“Çž‚Ý’†..."
+
+#, c-format
+msgid "Duplicate /encoding= line ignored in %s line %d: %s"
+msgstr "%s ‚Ì %d s–Ú‚Ì d•¡‚µ‚½ /encoding= s‚𖳎‹‚µ‚Ü‚µ‚½: %s"
+
+#, c-format
+msgid "/encoding= line after word ignored in %s line %d: %s"
+msgstr "%s ‚Ì %d s–Ú‚Ì ’PŒê‚ÌŒã‚Ì /encoding= s‚𖳎‹‚µ‚Ü‚µ‚½: %s"
+
+#, c-format
+msgid "Duplicate /regions= line ignored in %s line %d: %s"
+msgstr "%s ‚Ì %d s–Ú‚Ì d•¡‚µ‚½ /regions= s‚𖳎‹‚µ‚Ü‚µ‚½: %s"
+
+#, c-format
+msgid "Too many regions in %s line %d: %s"
+msgstr "%s ‚Ì %d s–ÚA”͈͎w’肪‘½‰ß‚¬‚Ü‚·: %s"
+
+#, c-format
+msgid "/ line ignored in %s line %d: %s"
+msgstr "%s ‚Ì %d s–Ú‚Ì d•¡‚µ‚½ / s‚𖳎‹‚µ‚Ü‚µ‚½: %s"
+
+#, c-format
+msgid "Invalid region nr in %s line %d: %s"
+msgstr "%s ‚Ì %d s–Ú –³Œø‚È nr —̈æ‚Å‚·: %s"
+
+#, c-format
+msgid "Unrecognized flags in %s line %d: %s"
+msgstr "%s ‚Ì %d s–Ú ”FŽ¯•s”\\‚ȃtƒ‰ƒO‚Å‚·: %s"
+
+#, c-format
+msgid "Ignored %d words with non-ASCII characters"
+msgstr "”ñASCII•¶Žš‚ðŠÜ‚Þ %d ŒÂ‚Ì’PŒê‚𖳎‹‚µ‚Ü‚µ‚½"
+
+msgid "E845: Insufficient memory, word list will be incomplete"
+msgstr "E845: ƒƒ‚ƒŠ‚ª‘«‚è‚È‚¢‚Ì‚ÅA’PŒêƒŠƒXƒg‚Í•sŠ®‘S‚Å‚·"
+
+#, c-format
+msgid "Compressed %d of %d nodes; %d (%d%%) remaining"
+msgstr "ƒm[ƒh %d ŒÂ(‘S %d ŒÂ’†) ‚ðˆ³k‚µ‚Ü‚µ‚½; Žc‚è %d (%d%%)"
+
+msgid "Reading back spell file..."
+msgstr "ƒXƒyƒ‹ƒtƒ@ƒCƒ‹‚ð‹t“Çž’†"
+
+msgid "Performing soundfolding..."
+msgstr "‰¹ºôž‚Ý‚ðŽÀs’†..."
+
+#, c-format
+msgid "Number of words after soundfolding: %ld"
+msgstr "‰¹ºôž‚ÝŒã‚Ì‘’PŒê”: %ld"
+
+#, c-format
+msgid "Total number of words: %d"
+msgstr "‘’PŒê”: %d"
+
+#, c-format
+msgid "Writing suggestion file %s..."
+msgstr "C³Œó•âƒtƒ@ƒCƒ‹ \"%s\" ‚ð‘ž‚Ý’†..."
+
+#, c-format
+msgid "Estimated runtime memory use: %d bytes"
+msgstr "„’胃‚ƒŠŽg—p—Ê: %d ƒoƒCƒg"
+
+msgid "E751: Output file name must not have region name"
+msgstr "E751: o—̓tƒ@ƒCƒ‹–¼‚ɂ͔͈͖¼‚ðŠÜ‚ß‚ç‚ê‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E754: Only up to %ld regions supported"
+msgstr "E754: ”ÍˆÍ‚Í %ld ŒÂ‚Ü‚Å‚µ‚©ƒTƒ|[ƒg‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E755: Invalid region in %s"
+msgstr "E755: –³Œø‚Ȕ͈͂ł·: %s"
+
+msgid "Warning: both compounding and NOBREAK specified"
+msgstr "Œx: •¡‡ƒtƒ‰ƒO‚Æ NOBREAK ‚ª—¼•û‚Æ‚àŽw’肳‚ê‚Ü‚µ‚½"
+
+#, c-format
+msgid "Writing spell file %s..."
+msgstr "ƒXƒyƒ‹ƒtƒ@ƒCƒ‹ %s ‚ð‘ž‚Ý’†..."
+
+msgid "Done!"
+msgstr "ŽÀs‚µ‚Ü‚µ‚½!"
+
+#, c-format
+msgid "E765: 'spellfile' does not have %ld entries"
+msgstr "E765: 'spellfile' ‚É‚Í %ld ŒÂ‚̃Gƒ“ƒgƒŠ‚Í‚ ‚è‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "Word '%.*s' removed from %s"
+msgstr "’PŒê '%.*s' ‚ª %s ‚©‚ç휂³‚ê‚Ü‚µ‚½"
+
+#, c-format
+msgid "Word '%.*s' added to %s"
+msgstr "’PŒê '%.*s' ‚ª %s ‚֒ljÁ‚³‚ê‚Ü‚µ‚½"
+
+msgid "E763: Word characters differ between spell files"
+msgstr "E763: ’PŒê‚Ì•¶Žš‚ªƒXƒyƒ‹ƒtƒ@ƒCƒ‹‚ƈقȂè‚Ü‚·"
+
+msgid "E783: duplicate char in MAP entry"
+msgstr "E783: MAP ƒGƒ“ƒgƒŠ‚Éd•¡•¶Žš‚ª‘¶Ý‚µ‚Ü‚·"
+
+msgid "No Syntax items defined for this buffer"
+msgstr "‚±‚̃oƒbƒtƒ@‚É’è‹`‚³‚ꂽ\\•¶—v‘f‚Í‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "'redrawtime' exceeded, syntax highlighting disabled"
+msgstr "'redrawtime' ‚𒴉߂µ‚½‚½‚ßA\\•¶ƒnƒCƒ‰ƒCƒg‚Í–³Œø‰»‚³‚ê‚Ü‚·"
+
+msgid "syntax conceal on"
+msgstr "\\•¶‚Ì conceal ‚ÍŒ»Ý on ‚Å‚·"
+
+msgid "syntax conceal off"
+msgstr "\\•¶‚Ì conceal ‚ÍŒ»Ý off ‚Å‚·"
+
+#, c-format
+msgid "E390: Illegal argument: %s"
+msgstr "E390: •s³‚Ȉø”‚Å‚·: %s"
+
+msgid "syntax case ignore"
+msgstr "\\•¶‚̑啶Žš¬•¶Žš‚ÍŒ»Ý ignore ‚Å‚·"
+
+msgid "syntax case match"
+msgstr "\\•¶‚̑啶Žš¬•¶Žš‚ÍŒ»Ý match ‚Å‚·"
+
+msgid "syntax spell toplevel"
+msgstr "\\•¶‚Ì spell ‚ÍŒ»Ý toplevel ‚Å‚·"
+
+msgid "syntax spell notoplevel"
+msgstr "\\•¶‚Ì spell ‚ÍŒ»Ý notoplevel ‚Å‚·"
+
+msgid "syntax spell default"
+msgstr "\\•¶‚Ì spell ‚ÍŒ»Ý default ‚Å‚·"
+
+msgid "syntax iskeyword "
+msgstr "\\•¶—p iskeyword "
+
+msgid "syntax iskeyword not set"
+msgstr "\\•¶—p iskeyword ‚̓Zƒbƒg‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E391: No such syntax cluster: %s"
+msgstr "E391: ‚»‚̂悤‚È\\•¶ƒNƒ‰ƒXƒ^‚Í‚ ‚è‚Ü‚¹‚ñ: %s"
+
+msgid "syncing on C-style comments"
+msgstr "CŒ¾Œê•—ƒRƒƒ“ƒg‚©‚瓯Šú’†"
+
+msgid "no syncing"
+msgstr "”ñ“¯Šú"
+
+msgid "syncing starts "
+msgstr "“¯ŠúŠJŽn "
+
+msgid " lines before top line"
+msgstr " s‘O(ƒgƒbƒvs‚æ‚è‚à)"
+
+msgid ""
+"\n"
+"--- Syntax sync items ---"
+msgstr ""
+"\n"
+"--- \\•¶“¯Šú—v‘f ---"
+
+msgid ""
+"\n"
+"syncing on items"
+msgstr ""
+"\n"
+"—v‘fã‚Å“¯Šú’†"
+
+msgid ""
+"\n"
+"--- Syntax items ---"
+msgstr ""
+"\n"
+"--- \\•¶—v‘f ---"
+
+#, c-format
+msgid "E392: No such syntax cluster: %s"
+msgstr "E392: ‚»‚̂悤‚È\\•¶ƒNƒ‰ƒXƒ^‚Í‚ ‚è‚Ü‚¹‚ñ: %s"
+
+msgid "minimal "
+msgstr "minimal "
+
+msgid "maximal "
+msgstr "maximal "
+
+msgid "; match "
+msgstr "; ŠY“– "
+
+msgid " line breaks"
+msgstr " ŒÂ‚̉üs"
+
+msgid "E395: contains argument not accepted here"
+msgstr "E395: ‚±‚Ìꊂł͈ø”contains‚Í‹–‰Â‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ"
+
+msgid "E844: invalid cchar value"
+msgstr "E844: –³Œø‚Ècchar‚Ì’l‚Å‚·"
+
+msgid "E393: group[t]here not accepted here"
+msgstr "E393: ‚±‚±‚ł̓Oƒ‹[ƒv‚Í‹–‰Â‚³‚ê‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E394: Didn't find region item for %s"
+msgstr "E394: %s ‚͈̔͗v‘f‚ªŒ©‚‚©‚è‚Ü‚¹‚ñ"
+
+msgid "E397: Filename required"
+msgstr "E397: ƒtƒ@ƒCƒ‹–¼‚ª•K—v‚Å‚·"
+
+msgid "E847: Too many syntax includes"
+msgstr "E847: \\•¶‚ÌŽæ‚èž‚Ý(include)‚ª‘½‰ß‚¬‚Ü‚·"
+
+#, c-format
+msgid "E789: Missing ']': %s"
+msgstr "E789: ']' ‚ª‚ ‚è‚Ü‚¹‚ñ: %s"
+
+#, c-format
+msgid "E890: trailing char after ']': %s]%s"
+msgstr "E890: ']' ‚ÌŒã‚ë‚É—]•ª‚È•¶Žš‚ª‚ ‚è‚Ü‚·: %s]%s"
+
+#, c-format
+msgid "E398: Missing '=': %s"
+msgstr "E398: '=' ‚ª‚ ‚è‚Ü‚¹‚ñ: %s"
+
+#, c-format
+msgid "E399: Not enough arguments: syntax region %s"
+msgstr "E399: ˆø”‚ª‘«‚è‚Ü‚¹‚ñ: \\•¶”ÍˆÍ %s"
+
+msgid "E848: Too many syntax clusters"
+msgstr "E848: \\•¶ƒNƒ‰ƒXƒ^‚ª‘½‰ß‚¬‚Ü‚·"
+
+msgid "E400: No cluster specified"
+msgstr "E400: ƒNƒ‰ƒXƒ^‚ªŽw’肳‚ê‚Ä‚¢‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E401: Pattern delimiter not found: %s"
+msgstr "E401: ƒpƒ^[ƒ“‹æ؂肪Œ©‚‚©‚è‚Ü‚¹‚ñ: %s"
+
+#, c-format
+msgid "E402: Garbage after pattern: %s"
+msgstr "E402: ƒpƒ^[ƒ“‚Ì‚ ‚ƂɃSƒ~‚ª‚ ‚è‚Ü‚·: %s"
+
+msgid "E403: syntax sync: line continuations pattern specified twice"
+msgstr "E403: \\•¶“¯Šú: ˜A‘±sƒpƒ^[ƒ“‚ª2“xŽw’肳‚ê‚Ü‚µ‚½"
+
+#, c-format
+msgid "E404: Illegal arguments: %s"
+msgstr "E404: •s³‚Ȉø”‚Å‚·: %s"
+
+#, c-format
+msgid "E405: Missing equal sign: %s"
+msgstr "E405: “™†‚ª‚ ‚è‚Ü‚¹‚ñ: %s"
+
+#, c-format
+msgid "E406: Empty argument: %s"
+msgstr "E406: ‹ó‚̈ø”: %s"
+
+#, c-format
+msgid "E407: %s not allowed here"
+msgstr "E407: %s ‚̓RƒR‚Å‚Í‹–‰Â‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E408: %s must be first in contains list"
+msgstr "E408: %s ‚Í“à—eƒŠƒXƒg‚Ì擪‚Å‚È‚¯‚ê‚΂Ȃç‚È‚¢"
+
+#, c-format
+msgid "E409: Unknown group name: %s"
+msgstr "E409: –¢’m‚̃Oƒ‹[ƒv–¼: %s"
+
+#, c-format
+msgid "E410: Invalid :syntax subcommand: %s"
+msgstr "E410: –³Œø‚È :syntax ‚̃TƒuƒRƒ}ƒ“ƒh: %s"
+
+msgid ""
+" TOTAL COUNT MATCH SLOWEST AVERAGE NAME PATTERN"
+msgstr ""
+" TOTAL COUNT MATCH SLOWEST AVERAGE NAME PATTERN"
+
+msgid "E679: recursive loop loading syncolor.vim"
+msgstr "E679: syncolor.vim ‚ÌÄ‹AŒÄ‚Ño‚µ‚ðŒŸo‚µ‚Ü‚µ‚½"
+
+#, c-format
+msgid "E411: highlight group not found: %s"
+msgstr "E411: ƒnƒCƒ‰ƒCƒgƒOƒ‹[ƒv‚ªŒ©‚‚©‚è‚Ü‚¹‚ñ: %s"
+
+#, c-format
+msgid "E412: Not enough arguments: \":highlight link %s\""
+msgstr "E412: ˆø”‚ª[•ª‚Å‚Í‚È‚¢: \":highlight link %s\""
+
+#, c-format
+msgid "E413: Too many arguments: \":highlight link %s\""
+msgstr "E413: ˆø”‚ª‘½‰ß‚¬‚Ü‚·: \":highlight link %s\""
+
+msgid "E414: group has settings, highlight link ignored"
+msgstr "E414: ƒOƒ‹[ƒv‚ªÝ’肳‚ê‚Ä‚¢‚é‚̂ŃnƒCƒ‰ƒCƒgƒŠƒ“ƒN‚Í–³Ž‹‚³‚ê‚Ü‚·"
+
+#, c-format
+msgid "E415: unexpected equal sign: %s"
+msgstr "E415: —\\Šú‚¹‚Ê“™†‚Å‚·: %s"
+
+#, c-format
+msgid "E416: missing equal sign: %s"
+msgstr "E416: “™†‚ª‚ ‚è‚Ü‚¹‚ñ: %s"
+
+#, c-format
+msgid "E417: missing argument: %s"
+msgstr "E417: ˆø”‚ª‚ ‚è‚Ü‚¹‚ñ: %s"
+
+#, c-format
+msgid "E418: Illegal value: %s"
+msgstr "E418: •s³‚È’l‚Å‚·: %s"
+
+msgid "E419: FG color unknown"
+msgstr "E419: –¢’m‚Ì‘OŒiF‚Å‚·"
+
+msgid "E420: BG color unknown"
+msgstr "E420: –¢’m‚Ì”wŒiF‚Å‚·"
+
+#, c-format
+msgid "E421: Color name or number not recognized: %s"
+msgstr "E421: ƒJƒ‰[–¼‚â”Ô†‚ð”FŽ¯‚Å‚«‚Ü‚¹‚ñ: %s"
+
+#, c-format
+msgid "E422: terminal code too long: %s"
+msgstr "E422: I’[ƒR[ƒh‚ª’·‰ß‚¬‚Ü‚·: %s"
+
+#, c-format
+msgid "E423: Illegal argument: %s"
+msgstr "E423: •s³‚Ȉø”‚Å‚·: %s"
+
+msgid "E424: Too many different highlighting attributes in use"
+msgstr "E424: ‘½‚­‚̈قȂéƒnƒCƒ‰ƒCƒg‘®«‚ªŽg‚í‚ê‰ß‚¬‚Ä‚¢‚Ü‚·"
+
+msgid "E669: Unprintable character in group name"
+msgstr "E669: ƒOƒ‹[ƒv–¼‚Ɉóü•s‰Â”\\‚È•¶Žš‚ª‚ ‚è‚Ü‚·"
+
+msgid "W18: Invalid character in group name"
+msgstr "W18: ƒOƒ‹[ƒv–¼‚É•s³‚È•¶Žš‚ª‚ ‚è‚Ü‚·"
+
+msgid "E849: Too many highlight and syntax groups"
+msgstr "E849: ƒnƒCƒ‰ƒCƒg‚Æ\\•¶ƒOƒ‹[ƒv‚ª‘½‰ß‚¬‚Ü‚·"
+
+msgid "E555: at bottom of tag stack"
+msgstr "E555: ƒ^ƒOƒXƒ^ƒbƒN‚Ì––”ö‚Å‚·"
+
+msgid "E556: at top of tag stack"
+msgstr "E556: ƒ^ƒOƒXƒ^ƒbƒN‚Ì擪‚Å‚·"
+
+msgid "E425: Cannot go before first matching tag"
+msgstr "E425: ʼn‚ÌŠY“–ƒ^ƒO‚ð‰z‚¦‚Ė߂邱‚Æ‚Í‚Å‚«‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E426: tag not found: %s"
+msgstr "E426: ƒ^ƒO‚ªŒ©‚‚©‚è‚Ü‚¹‚ñ: %s"
+
+msgid " # pri kind tag"
+msgstr " # pri kind tag"
+
+msgid "file\n"
+msgstr "ƒtƒ@ƒCƒ‹\n"
+
+msgid "E427: There is only one matching tag"
+msgstr "E427: ŠY“–ƒ^ƒO‚ª1‚‚¾‚¯‚µ‚©‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "E428: Cannot go beyond last matching tag"
+msgstr "E428: ÅŒã‚ÌŠY“–ƒ^ƒO‚ð‰z‚¦‚Äi‚Þ‚±‚Æ‚Í‚Å‚«‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "File \"%s\" does not exist"
+msgstr "ƒtƒ@ƒCƒ‹ \"%s\" ‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "tag %d of %d%s"
+msgstr "ƒ^ƒO %d (‘S%d%s)"
+
+msgid " or more"
+msgstr " ‚©‚»‚êˆÈã"
+
+msgid " Using tag with different case!"
+msgstr " ƒ^ƒO‚ðˆÙ‚È‚écase‚ÅŽg—p‚µ‚Ü‚·!"
+
+#, c-format
+msgid "E429: File \"%s\" does not exist"
+msgstr "E429: ƒtƒ@ƒCƒ‹ \"%s\" ‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+msgid ""
+"\n"
+" # TO tag FROM line in file/text"
+msgstr ""
+"\n"
+" # TO ƒ^ƒO FROM s in file/text"
+
+#, c-format
+msgid "Searching tags file %s"
+msgstr "ƒ^ƒOƒtƒ@ƒCƒ‹ %s ‚ðŒŸõ’†"
+
+#, c-format
+msgid "E430: Tag file path truncated for %s\n"
+msgstr "E430: ƒ^ƒOƒtƒ@ƒCƒ‹‚̃pƒX‚ª %s ‚ÉØ‚èŽÌ‚Ä‚ç‚ê‚Ü‚µ‚½\n"
+
+msgid "Ignoring long line in tags file"
+msgstr "ƒ^ƒOƒtƒ@ƒCƒ‹“à‚Ì’·‚¢s‚𖳎‹‚µ‚Ü‚·"
+
+#, c-format
+msgid "E431: Format error in tags file \"%s\""
+msgstr "E431: ƒ^ƒOƒtƒ@ƒCƒ‹ \"%s\" ‚̃tƒH[ƒ}ƒbƒg‚ɃGƒ‰[‚ª‚ ‚è‚Ü‚·"
+
+#, c-format
+msgid "Before byte %ld"
+msgstr "’¼‘O‚Ì %ld ƒoƒCƒg"
+
+#, c-format
+msgid "E432: Tags file not sorted: %s"
+msgstr "E432: ƒ^ƒOƒtƒ@ƒCƒ‹‚ªƒ\\[ƒg‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ: %s"
+
+msgid "E433: No tags file"
+msgstr "E433: ƒ^ƒOƒtƒ@ƒCƒ‹‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "E434: Can't find tag pattern"
+msgstr "E434: ƒ^ƒOƒpƒ^[ƒ“‚ðŒ©‚Â‚¯‚ç‚ê‚Ü‚¹‚ñ"
+
+msgid "E435: Couldn't find tag, just guessing!"
+msgstr "E435: ƒ^ƒO‚ðŒ©‚Â‚¯‚ç‚ê‚È‚¢‚Ì‚Å’P‚É„‘ª‚µ‚Ü‚·!"
+
+#, c-format
+msgid "Duplicate field name: %s"
+msgstr "d•¡‚µ‚½ƒtƒB[ƒ‹ƒh–¼: %s"
+
+msgid "' not known. Available builtin terminals are:"
+msgstr "' ‚Í–¢’m‚Å‚·. Œ»s‚Ì‘g‚Ýž‚Ý’[––‚ÍŽŸ‚Ì‚Æ‚¨‚è‚Å‚·:"
+
+msgid "defaulting to '"
+msgstr "È—ª’l‚ðŽŸ‚Ì‚æ‚¤‚Éݒ肵‚Ü‚· '"
+
+msgid "E557: Cannot open termcap file"
+msgstr "E557: termcapƒtƒ@ƒCƒ‹‚ðŠJ‚¯‚Ü‚¹‚ñ"
+
+msgid "E558: Terminal entry not found in terminfo"
+msgstr "E558: terminfo‚É’[––ƒGƒ“ƒgƒŠ‚ðŒ©‚Â‚¯‚ç‚ê‚Ü‚¹‚ñ"
+
+msgid "E559: Terminal entry not found in termcap"
+msgstr "E559: termcap‚É’[––ƒGƒ“ƒgƒŠ‚ðŒ©‚Â‚¯‚ç‚ê‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E436: No \"%s\" entry in termcap"
+msgstr "E436: termcap‚É \"%s\" ‚̃Gƒ“ƒgƒŠ‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "E437: terminal capability \"cm\" required"
+msgstr "E437: ’[––‚É \"cm\" ‹@”\\‚ª•K—v‚Å‚·"
+
+msgid ""
+"\n"
+"--- Terminal keys ---"
+msgstr ""
+"\n"
+"--- ’[––ƒL[ ---"
+
+msgid "Cannot open $VIMRUNTIME/rgb.txt"
+msgstr "$VIMRUNTIME/rgb.txt‚ðŠJ‚¯‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "Kill job in \"%s\"?"
+msgstr "\"%s\" “à‚̃Wƒ‡ƒu‚ðI—¹‚µ‚Ü‚·‚©?"
+
+msgid "Terminal"
+msgstr "’[––"
+
+msgid "Terminal-finished"
+msgstr "’[–– (I—¹)"
+
+msgid "active"
+msgstr "ƒAƒNƒeƒBƒu"
+
+msgid "running"
+msgstr "ŽÀs’†"
+
+msgid "finished"
+msgstr "I—¹"
+
+msgid "E958: Job already finished"
+msgstr "E958: ƒWƒ‡ƒu‚Í‚·‚Å‚ÉI—¹‚µ‚Ä‚¢‚Ü‚·"
+
+#, c-format
+msgid "E953: File exists: %s"
+msgstr "E953: ƒtƒ@ƒCƒ‹‚ÍŠù‚É‘¶Ý‚µ‚Ü‚·: %s"
+
+msgid "E955: Not a terminal buffer"
+msgstr "E955: ’[––ƒoƒbƒtƒ@‚Å‚Í‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "new shell started\n"
+msgstr "V‚µ‚¢ƒVƒFƒ‹‚ð‹N“®‚µ‚Ü‚·\n"
+
+msgid "Vim: Error reading input, exiting...\n"
+msgstr "Vim: “ü—Í‚ð“Çž‚Ý’†‚̃Gƒ‰[‚É‚æ‚èI—¹‚µ‚Ü‚·...\n"
+
+msgid "Used CUT_BUFFER0 instead of empty selection"
+msgstr "‹ó‚Ì‘I‘ð—̈æ‚Ì‚©‚í‚è‚ÉCUT_BUFFER0‚ªŽg—p‚³‚ê‚Ü‚µ‚½"
+
+msgid "E881: Line count changed unexpectedly"
+msgstr "E881: —\\Šú‚¹‚¸sƒJƒEƒ“ƒg‚ª•Ï‚í‚è‚Ü‚µ‚½"
+
+msgid "No undo possible; continue anyway"
+msgstr "‰Â”\\‚ȃAƒ“ƒhƒD‚Í‚ ‚è‚Ü‚¹‚ñ: ‚Æ‚è‚ ‚¦‚¸‘±‚¯‚Ü‚·"
+
+#, c-format
+msgid "E828: Cannot open undo file for writing: %s"
+msgstr "E828: ‘ž‚Ý—p‚ɃAƒ“ƒhƒDƒtƒ@ƒCƒ‹‚ðŠJ‚¯‚Ü‚¹‚ñ: %s"
+
+#, c-format
+msgid "E825: Corrupted undo file (%s): %s"
+msgstr "E825: ƒAƒ“ƒhƒDƒtƒ@ƒCƒ‹‚ª‰ó‚ê‚Ä‚¢‚Ü‚· (%s): %s"
+
+msgid "Cannot write undo file in any directory in 'undodir'"
+msgstr "'undodir'‚̃fƒBƒŒƒNƒgƒŠ‚ɃAƒ“ƒhƒDƒtƒ@ƒCƒ‹‚ð‘‚«ž‚ß‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "Will not overwrite with undo file, cannot read: %s"
+msgstr "ƒAƒ“ƒhƒDƒtƒ@ƒCƒ‹‚Æ‚µ‚Ä“Ç‚Ýž‚ß‚È‚¢‚Ì‚Åã‘‚«‚µ‚Ü‚¹‚ñ: %s"
+
+#, c-format
+msgid "Will not overwrite, this is not an undo file: %s"
+msgstr "ƒAƒ“ƒhƒDƒtƒ@ƒCƒ‹‚Å‚Í‚È‚¢‚Ì‚Åã‘‚«‚µ‚Ü‚¹‚ñ: %s"
+
+msgid "Skipping undo file write, nothing to undo"
+msgstr "‘ÎÛ‚ª‚È‚¢‚̂ŃAƒ“ƒhƒDƒtƒ@ƒCƒ‹‚Ì‘‚«ž‚Ý‚ðƒXƒLƒbƒv‚µ‚Ü‚·"
+
+#, c-format
+msgid "Writing undo file: %s"
+msgstr "ƒAƒ“ƒhƒDƒtƒ@ƒCƒ‹‘‚«ž‚Ý’†: %s"
+
+#, c-format
+msgid "E829: write error in undo file: %s"
+msgstr "E829: ƒAƒ“ƒhƒDƒtƒ@ƒCƒ‹‚Ì‘‚«ž‚݃Gƒ‰[‚Å‚·: %s"
+
+#, c-format
+msgid "Not reading undo file, owner differs: %s"
+msgstr "ƒI[ƒi[‚ªˆÙ‚È‚é‚̂ŃAƒ“ƒhƒDƒtƒ@ƒCƒ‹‚ð“Ç‚Ýž‚Ý‚Ü‚¹‚ñ: %s"
+
+#, c-format
+msgid "Reading undo file: %s"
+msgstr "ƒAƒ“ƒhƒDƒtƒ@ƒCƒ‹“Çž’†: %s"
+
+#, c-format
+msgid "E822: Cannot open undo file for reading: %s"
+msgstr "E822: ƒAƒ“ƒhƒDƒtƒ@ƒCƒ‹‚ð“Çž—p‚Æ‚µ‚ÄŠJ‚¯‚Ü‚¹‚ñ: %s"
+
+#, c-format
+msgid "E823: Not an undo file: %s"
+msgstr "E823: ƒAƒ“ƒhƒDƒtƒ@ƒCƒ‹‚Å‚Í‚ ‚è‚Ü‚¹‚ñ: %s"
+
+#, c-format
+msgid "E832: Non-encrypted file has encrypted undo file: %s"
+msgstr "E832: ”ñˆÃ†‰»ƒtƒ@ƒCƒ‹‚ªˆÃ†‰»‚³‚ꂽƒAƒ“ƒhƒDƒtƒ@ƒCƒ‹‚ðŽg‚Á‚Ä‚Ü‚·: %s"
+
+#, c-format
+msgid "E826: Undo file decryption failed: %s"
+msgstr "E826: ˆÃ†‰»‚³‚ꂽƒAƒ“ƒhƒDƒtƒ@ƒCƒ‹‚̉ð“Ç‚ÉŽ¸”s‚µ‚Ü‚µ‚½: %s"
+
+#, c-format
+msgid "E827: Undo file is encrypted: %s"
+msgstr "E827: ƒAƒ“ƒhƒDƒtƒ@ƒCƒ‹‚ªˆÃ†‰»‚³‚ê‚Ä‚¢‚Ü‚·: %s"
+
+#, c-format
+msgid "E824: Incompatible undo file: %s"
+msgstr "E824: ŒÝŠ·«‚Ì–³‚¢ƒAƒ“ƒhƒDƒtƒ@ƒCƒ‹‚Å‚·: %s"
+
+msgid "File contents changed, cannot use undo info"
+msgstr "ƒtƒ@ƒCƒ‹‚Ì“à—e‚ª•Ï‚í‚Á‚Ä‚¢‚邽‚ßAƒAƒ“ƒhƒDî•ñ‚ð—˜—p‚Å‚«‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "Finished reading undo file %s"
+msgstr "ƒAƒ“ƒhƒDƒtƒ@ƒCƒ‹ %s ‚ÌŽæž‚ðŠ®—¹"
+
+msgid "Already at oldest change"
+msgstr "Šù‚Ɉê”Ԍ¢•ÏX‚Å‚·"
+
+msgid "Already at newest change"
+msgstr "Šù‚Ɉê”ÔV‚µ‚¢•ÏX‚Å‚·"
+
+#, c-format
+msgid "E830: Undo number %ld not found"
+msgstr "E830: ƒAƒ“ƒhƒD”Ô† %ld ‚ÍŒ©‚‚©‚è‚Ü‚¹‚ñ"
+
+msgid "E438: u_undo: line numbers wrong"
+msgstr "E438: u_undo: s”Ô†‚ªŠÔˆá‚Á‚Ä‚¢‚Ü‚·"
+
+msgid "more line"
+msgstr "s ’ljÁ‚µ‚Ü‚µ‚½"
+
+msgid "more lines"
+msgstr "s ’ljÁ‚µ‚Ü‚µ‚½"
+
+msgid "line less"
+msgstr "s 휂µ‚Ü‚µ‚½"
+
+msgid "fewer lines"
+msgstr "s 휂µ‚Ü‚µ‚½"
+
+msgid "change"
+msgstr "‰ÓŠ•ÏX‚µ‚Ü‚µ‚½"
+
+msgid "changes"
+msgstr "‰ÓŠ•ÏX‚µ‚Ü‚µ‚½"
+
+#, c-format
+msgid "%ld %s; %s #%ld %s"
+msgstr "%ld %s; %s #%ld %s"
+
+msgid "before"
+msgstr "‘O•û"
+
+msgid "after"
+msgstr "Œã•û"
+
+msgid "Nothing to undo"
+msgstr "ƒAƒ“ƒhƒD‘ÎÛ‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "number changes when saved"
+msgstr "’Ê”Ô •ÏX” •ÏXŽžŠú •Û‘¶Ï"
+
+#, c-format
+msgid "%ld second ago"
+msgid_plural "%ld seconds ago"
+msgstr[0] "%ld •bŒo‰ß‚µ‚Ä‚¢‚Ü‚·"
+
+msgid "E790: undojoin is not allowed after undo"
+msgstr "E790: undo ‚Ì’¼Œã‚É undojoin ‚Í‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "E439: undo list corrupt"
+msgstr "E439: ƒAƒ“ƒhƒDƒŠƒXƒg‚ª‰ó‚ê‚Ä‚¢‚Ü‚·"
+
+msgid "E440: undo line missing"
+msgstr "E440: ƒAƒ“ƒhƒDs‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E122: Function %s already exists, add ! to replace it"
+msgstr "E122: ŠÖ” %s ‚Í’è‹`Ï‚Å‚·AÄ’è‹`‚·‚é‚É‚Í ! ‚ð’ljÁ‚µ‚Ä‚­‚¾‚³‚¢"
+
+msgid "E717: Dictionary entry already exists"
+msgstr "E717: Ž«‘Œ^“à‚ɃGƒ“ƒgƒŠ‚ªŠù‚É‘¶Ý‚µ‚Ü‚·"
+
+msgid "E718: Funcref required"
+msgstr "E718: ŠÖ”ŽQÆŒ^‚ª—v‹‚³‚ê‚Ü‚·"
+
+#, c-format
+msgid "E130: Unknown function: %s"
+msgstr "E130: –¢’m‚ÌŠÖ”‚Å‚·: %s"
+
+#, c-format
+msgid "E125: Illegal argument: %s"
+msgstr "E125: •s³‚Ȉø”‚Å‚·: %s"
+
+#, c-format
+msgid "E853: Duplicate argument name: %s"
+msgstr "E853: ˆø”–¼‚ªd•¡‚µ‚Ä‚¢‚Ü‚·: %s"
+
+#, c-format
+msgid "E740: Too many arguments for function %s"
+msgstr "E740: ŠÖ”‚̈ø”‚ª‘½‰ß‚¬‚Ü‚·: %s"
+
+#, c-format
+msgid "E116: Invalid arguments for function %s"
+msgstr "E116: ŠÖ”‚Ì–³Œø‚Ȉø”‚Å‚·: %s"
+
+msgid "E132: Function call depth is higher than 'maxfuncdepth'"
+msgstr "E132: ŠÖ”ŒÄo‚Ì“ü‚êŽq”‚ª 'maxfuncdepth' ‚ð’´‚¦‚Ü‚µ‚½"
+
+#, c-format
+msgid "calling %s"
+msgstr "%s ‚ðŽÀs’†‚Å‚·"
+
+#, c-format
+msgid "%s aborted"
+msgstr "%s ‚ª’†’f‚³‚ê‚Ü‚µ‚½"
+
+#, c-format
+msgid "%s returning #%ld"
+msgstr "%s ‚ª #%ld ‚ð•Ô‚µ‚Ü‚µ‚½"
+
+#, c-format
+msgid "%s returning %s"
+msgstr "%s ‚ª %s ‚ð•Ô‚µ‚Ü‚µ‚½"
+
+msgid "E699: Too many arguments"
+msgstr "E699: ˆø”‚ª‘½‰ß‚¬‚Ü‚·"
+
+#, c-format
+msgid "E117: Unknown function: %s"
+msgstr "E117: –¢’m‚ÌŠÖ”‚Å‚·: %s"
+
+#, c-format
+msgid "E933: Function was deleted: %s"
+msgstr "E933: ŠÖ”‚Í휂³‚ê‚Ü‚µ‚½: %s"
+
+#, c-format
+msgid "E119: Not enough arguments for function: %s"
+msgstr "E119: ŠÖ”‚̈ø”‚ª‘«‚è‚Ü‚¹‚ñ: %s"
+
+#, c-format
+msgid "E120: Using <SID> not in a script context: %s"
+msgstr "E120: ƒXƒNƒŠƒvƒgˆÈŠO‚Å<SID>‚ªŽg‚í‚ê‚Ü‚µ‚½: %s"
+
+#, c-format
+msgid "E725: Calling dict function without Dictionary: %s"
+msgstr "E725: Ž«‘—pŠÖ”‚ªŒÄ‚΂ê‚Ü‚µ‚½‚ªŽ«‘‚ª‚ ‚è‚Ü‚¹‚ñ: %s"
+
+msgid "E129: Function name required"
+msgstr "E129: ŠÖ”–¼‚ª—v‹‚³‚ê‚Ü‚·"
+
+#, c-format
+msgid "E128: Function name must start with a capital or \"s:\": %s"
+msgstr "E128: ŠÖ”–¼‚͑啶Žš‚© \"s:\" ‚ÅŽn‚Ü‚ç‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñ: %s"
+
+#, c-format
+msgid "E884: Function name cannot contain a colon: %s"
+msgstr "E884: ŠÖ”–¼‚ɂ̓Rƒƒ“‚ÍŠÜ‚ß‚ç‚ê‚Ü‚¹‚ñ: %s"
+
+#, c-format
+msgid "E123: Undefined function: %s"
+msgstr "E123: –¢’è‹`‚ÌŠÖ”‚Å‚·: %s"
+
+#, c-format
+msgid "E124: Missing '(': %s"
+msgstr "E124: '(' ‚ª‚ ‚è‚Ü‚¹‚ñ: %s"
+
+msgid "E862: Cannot use g: here"
+msgstr "E862: ‚±‚±‚Å‚Í g: ‚ÍŽg‚¦‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E932: Closure function should not be at top level: %s"
+msgstr "E932: ƒNƒ[ƒWƒƒ[ŠÖ”‚̓gƒbƒvƒŒƒxƒ‹‚É‹Lq‚Å‚«‚Ü‚¹‚ñ: %s"
+
+msgid "E126: Missing :endfunction"
+msgstr "E126: :endfunction ‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "W22: Text found after :endfunction: %s"
+msgstr "W22: :endfunction ‚ÌŒã‚É•¶Žš‚ª‚ ‚è‚Ü‚·: %s"
+
+#, c-format
+msgid "E707: Function name conflicts with variable: %s"
+msgstr "E707: ŠÖ”–¼‚ª•Ï”–¼‚ÆÕ“Ë‚µ‚Ü‚·: %s"
+
+#, c-format
+msgid "E127: Cannot redefine function %s: It is in use"
+msgstr "E127: ŠÖ” %s ‚ðÄ’è‹`‚Å‚«‚Ü‚¹‚ñ: Žg—p’†‚Å‚·"
+
+#, c-format
+msgid "E746: Function name does not match script file name: %s"
+msgstr "E746: ŠÖ”–¼‚ªƒXƒNƒŠƒvƒg‚̃tƒ@ƒCƒ‹–¼‚ƈê’v‚µ‚Ü‚¹‚ñ: %s"
+
+#, c-format
+msgid "E131: Cannot delete function %s: It is in use"
+msgstr "E131: ŠÖ” %s ‚ð휂ł«‚Ü‚¹‚ñ: Žg—p’†‚Å‚·"
+
+msgid "E133: :return not inside a function"
+msgstr "E133: ŠÖ”ŠO‚É :return ‚ª‚ ‚è‚Ü‚µ‚½"
+
+#, c-format
+msgid "E107: Missing parentheses: %s"
+msgstr "E107: ƒJƒbƒR '(' ‚ª‚ ‚è‚Ü‚¹‚ñ: %s"
+
+#, c-format
+msgid "%s (%s, compiled %s)"
+msgstr "%s (%s, compiled %s)"
+
+msgid ""
+"\n"
+"MS-Windows 64-bit GUI version"
+msgstr ""
+"\n"
+"MS-Windows 64 ƒrƒbƒg GUI ”Å"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit GUI version"
+msgstr ""
+"\n"
+"MS-Windows 32 ƒrƒbƒg GUI ”Å"
+
+msgid " with OLE support"
+msgstr " with OLE ƒTƒ|[ƒg"
+
+msgid ""
+"\n"
+"MS-Windows 64-bit console version"
+msgstr ""
+"\n"
+"MS-Windows 64 ƒrƒbƒg ƒRƒ“ƒ\\[ƒ‹ ”Å"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit console version"
+msgstr ""
+"\n"
+"MS-Windows 32 ƒrƒbƒg ƒRƒ“ƒ\\[ƒ‹ ”Å"
+
+msgid ""
+"\n"
+"macOS version"
+msgstr ""
+"\n"
+"macOS Ӂ"
+
+msgid ""
+"\n"
+"macOS version w/o darwin feat."
+msgstr ""
+"\n"
+"macOS ”Å (darwin –³‚µ)"
+
+msgid ""
+"\n"
+"OpenVMS version"
+msgstr ""
+"\n"
+"OpenVMS Ӂ"
+
+msgid ""
+"\n"
+"Included patches: "
+msgstr ""
+"\n"
+"“K—pσpƒbƒ`: "
+
+msgid ""
+"\n"
+"Extra patches: "
+msgstr ""
+"\n"
+"’ljÁŠg’£ƒpƒbƒ`: "
+
+msgid "Modified by "
+msgstr "Modified by "
+
+msgid ""
+"\n"
+"Compiled "
+msgstr ""
+"\n"
+"Compiled "
+
+msgid "by "
+msgstr "by "
+
+msgid ""
+"\n"
+"Huge version "
+msgstr ""
+"\n"
+"Huge Ӂ "
+
+msgid ""
+"\n"
+"Big version "
+msgstr ""
+"\n"
+"Big Ӂ "
+
+msgid ""
+"\n"
+"Normal version "
+msgstr ""
+"\n"
+"’Êí ”Å "
+
+msgid ""
+"\n"
+"Small version "
+msgstr ""
+"\n"
+"Small Ӂ "
+
+msgid ""
+"\n"
+"Tiny version "
+msgstr ""
+"\n"
+"Tiny Ӂ "
+
+msgid "without GUI."
+msgstr "without GUI."
+
+msgid "with GTK3 GUI."
+msgstr "with GTK3 GUI."
+
+msgid "with GTK2-GNOME GUI."
+msgstr "with GTK2-GNOME GUI."
+
+msgid "with GTK2 GUI."
+msgstr "with GTK2 GUI."
+
+msgid "with X11-Motif GUI."
+msgstr "with X11-Motif GUI."
+
+msgid "with X11-neXtaw GUI."
+msgstr "with X11-neXtaw GUI."
+
+msgid "with X11-Athena GUI."
+msgstr "with X11-Athena GUI."
+
+msgid "with Photon GUI."
+msgstr "with Photon GUI."
+
+msgid "with GUI."
+msgstr "with GUI."
+
+msgid "with Carbon GUI."
+msgstr "with Carbon GUI."
+
+msgid "with Cocoa GUI."
+msgstr "with Cocoa GUI."
+
+msgid " Features included (+) or not (-):\n"
+msgstr " ‹@”\\‚̈ꗗ —LŒø(+)/–³Œø(-)\n"
+
+msgid " system vimrc file: \""
+msgstr " ƒVƒXƒeƒ€ vimrc: \""
+
+msgid " user vimrc file: \""
+msgstr " ƒ†[ƒU[ vimrc: \""
+
+msgid " 2nd user vimrc file: \""
+msgstr " ‘æ2ƒ†[ƒU[ vimrc: \""
+
+msgid " 3rd user vimrc file: \""
+msgstr " ‘æ3ƒ†[ƒU[ vimrc: \""
+
+msgid " user exrc file: \""
+msgstr " ƒ†[ƒU[ exrc: \""
+
+msgid " 2nd user exrc file: \""
+msgstr " ‘æ2ƒ†[ƒU[ exrc: \""
+
+msgid " system gvimrc file: \""
+msgstr " ƒVƒXƒeƒ€ gvimrc: \""
+
+msgid " user gvimrc file: \""
+msgstr " ƒ†[ƒU[ gvimrc: \""
+
+msgid "2nd user gvimrc file: \""
+msgstr " ‘æ2ƒ†[ƒU[ gvimrc: \""
+
+msgid "3rd user gvimrc file: \""
+msgstr " ‘æ3ƒ†[ƒU[ gvimrc: \""
+
+msgid " defaults file: \""
+msgstr " ƒfƒtƒHƒ‹ƒgƒtƒ@ƒCƒ‹: \""
+
+msgid " system menu file: \""
+msgstr " ƒVƒXƒeƒ€ƒƒjƒ…[: \""
+
+msgid " fall-back for $VIM: \""
+msgstr " È—ªŽž‚Ì $VIM: \""
+
+msgid " f-b for $VIMRUNTIME: \""
+msgstr "È—ªŽž‚Ì $VIMRUNTIME: \""
+
+msgid "Compilation: "
+msgstr "ƒRƒ“ƒpƒCƒ‹: "
+
+msgid "Compiler: "
+msgstr "ƒRƒ“ƒpƒCƒ‰: "
+
+msgid "Linking: "
+msgstr "ƒŠƒ“ƒN: "
+
+msgid " DEBUG BUILD"
+msgstr "ƒfƒoƒbƒOƒrƒ‹ƒh"
+
+msgid "VIM - Vi IMproved"
+msgstr "VIM - Vi IMproved"
+
+msgid "version "
+msgstr "version "
+
+msgid "by Bram Moolenaar et al."
+msgstr "by Bram Moolenaar ‘¼."
+
+msgid "Vim is open source and freely distributable"
+msgstr "Vim ‚̓I[ƒvƒ“ƒ\\[ƒX‚Å‚ ‚莩—R‚É”z•z‰Â”\\‚Å‚·"
+
+msgid "Help poor children in Uganda!"
+msgstr "ƒEƒKƒ“ƒ_‚ÌŒb‚Ü‚ê‚È‚¢Žq‹Ÿ‚½‚¿‚ɉ‡•‚ð!"
+
+msgid "type :help iccf<Enter> for information "
+msgstr "ÚׂÈî•ñ‚Í :help iccf<Enter> "
+
+msgid "type :q<Enter> to exit "
+msgstr "I—¹‚·‚é‚É‚Í :q<Enter> "
+
+msgid "type :help<Enter> or <F1> for on-line help"
+msgstr "ƒIƒ“ƒ‰ƒCƒ“ƒwƒ‹ƒv‚Í :help<Enter> ‚© <F1> "
+
+msgid "type :help version8<Enter> for version info"
+msgstr "ƒo[ƒWƒ‡ƒ“î•ñ‚Í :help version8<Enter> "
+
+msgid "Running in Vi compatible mode"
+msgstr "ViŒÝŠ·ƒ‚[ƒh‚Å“®ì’†"
+
+msgid "type :set nocp<Enter> for Vim defaults"
+msgstr "Vim„§’l‚É‚·‚é‚É‚Í :set nocp<Enter> "
+
+msgid "type :help cp-default<Enter> for info on this"
+msgstr "ÚׂÈî•ñ‚Í :help cp-default<Enter>"
+
+msgid "menu Help->Orphans for information "
+msgstr "Úׂ̓ƒjƒ…[‚Ì ƒwƒ‹ƒv->ŒÇŽ™ ‚ðŽQÆ‚µ‚ĉº‚³‚¢ "
+
+msgid "Running modeless, typed text is inserted"
+msgstr "ƒ‚[ƒh–³‚ÅŽÀs’†Bƒ^ƒCƒv‚µ‚½•¶Žš‚ª‘}“ü‚³‚ê‚Ü‚·"
+
+msgid "menu Edit->Global Settings->Toggle Insert Mode "
+msgstr "ƒƒjƒ…[‚Ì •ÒW->‘S‘ÌÝ’è->‘}“ü(‰SŽÒ)ƒ‚[ƒhØ‘Ö "
+
+msgid " for two modes "
+msgstr " ‚Ń‚[ƒh—L‚É "
+
+msgid "menu Edit->Global Settings->Toggle Vi Compatible"
+msgstr "ƒƒjƒ…[‚Ì •ÒW->‘S‘ÌÝ’è->ViŒÝŠ·ƒ‚[ƒhØ‘Ö "
+
+msgid " for Vim defaults "
+msgstr " ‚ÅVim‚Æ‚µ‚Ä“®ì "
+
+msgid "Sponsor Vim development!"
+msgstr "Vim‚ÌŠJ”­‚ð‰ž‰‡‚µ‚Ä‚­‚¾‚³‚¢!"
+
+msgid "Become a registered Vim user!"
+msgstr "Vim‚Ì“o˜^ƒ†[ƒU[‚É‚È‚Á‚Ä‚­‚¾‚³‚¢!"
+
+msgid "type :help sponsor<Enter> for information "
+msgstr "ÚׂÈî•ñ‚Í :help sponsor<Enter> "
+
+msgid "type :help register<Enter> for information "
+msgstr "ÚׂÈî•ñ‚Í :help register<Enter> "
+
+msgid "menu Help->Sponsor/Register for information "
+msgstr "Úׂ̓ƒjƒ…[‚Ì ƒwƒ‹ƒv->ƒXƒ|ƒ“ƒT[/“o˜^ ‚ðŽQÆ‚µ‚ĉº‚³‚¢"
+
+msgid "Already only one window"
+msgstr "Šù‚ɃEƒBƒ“ƒhƒE‚Í1‚‚µ‚©‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "E441: There is no preview window"
+msgstr "E441: ƒvƒŒƒrƒ…[ƒEƒBƒ“ƒhƒE‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "E442: Can't split topleft and botright at the same time"
+msgstr "E442: ¶ã‚ƉE‰º‚𓯎ž‚É•ªŠ„‚·‚邱‚Æ‚Í‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "E443: Cannot rotate when another window is split"
+msgstr "E443: ‘¼‚̃EƒBƒ“ƒhƒE‚ª•ªŠ„‚³‚ê‚Ä‚¢‚鎞‚ɂ͇‰ñ‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "E444: Cannot close last window"
+msgstr "E444: ÅŒã‚̃EƒBƒ“ƒhƒE‚ð•Â‚¶‚邱‚Æ‚Í‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "E813: Cannot close autocmd window"
+msgstr "E813: autocmdƒEƒBƒ“ƒhƒE‚͕‚¶‚ç‚ê‚Ü‚¹‚ñ"
+
+msgid "E814: Cannot close window, only autocmd window would remain"
+msgstr "E814: autocmdƒEƒBƒ“ƒhƒE‚µ‚©Žc‚ç‚È‚¢‚½‚ßAƒEƒBƒ“ƒhƒE‚͕‚¶‚ç‚ê‚Ü‚¹‚ñ"
+
+msgid "E445: Other window contains changes"
+msgstr "E445: ‘¼‚̃EƒBƒ“ƒhƒE‚É‚Í•ÏX‚ª‚ ‚è‚Ü‚·"
+
+msgid "E446: No file name under cursor"
+msgstr "E446: ƒJ[ƒ\\ƒ‹‚̉º‚Ƀtƒ@ƒCƒ‹–¼‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E447: Can't find file \"%s\" in path"
+msgstr "E447: path‚É‚Í \"%s\" ‚Æ‚¢‚¤ƒtƒ@ƒCƒ‹‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E799: Invalid ID: %ld (must be greater than or equal to 1)"
+msgstr "E799: –³Œø‚È ID: %ld (1 ˆÈã‚Å‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñ)"
+
+#, c-format
+msgid "E801: ID already taken: %ld"
+msgstr "E801: ID ‚Í‚·‚Å‚É—˜—p’†‚Å‚·: %ld"
+
+msgid "List or number required"
+msgstr "ƒŠƒXƒg‚©”’l‚ª•K—v‚Å‚·"
+
+#, c-format
+msgid "E802: Invalid ID: %ld (must be greater than or equal to 1)"
+msgstr "E802: –³Œø‚È ID: %ld (1 ˆÈã‚Å‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñ)"
+
+#, c-format
+msgid "E803: ID not found: %ld"
+msgstr "E803: ID ‚Í‚ ‚è‚Ü‚¹‚ñ: %ld"
+
+#, c-format
+msgid "E370: Could not load library %s"
+msgstr "E370: ƒ‰ƒCƒuƒ‰ƒŠ %s ‚ðƒ[ƒh‚Å‚«‚Ü‚¹‚ñ‚Å‚µ‚½"
+
+msgid "Sorry, this command is disabled: the Perl library could not be loaded."
+msgstr ""
+"‚±‚̃Rƒ}ƒ“ƒh‚Í–³Œø‚Å‚·A‚²‚ß‚ñ‚È‚³‚¢: Perlƒ‰ƒCƒuƒ‰ƒŠ‚ðƒ[ƒh‚Å‚«‚Ü‚¹‚ñ‚Å‚µ‚½."
+
+msgid "E299: Perl evaluation forbidden in sandbox without the Safe module"
+msgstr ""
+"E299: ƒTƒ“ƒhƒ{ƒbƒNƒX‚Å‚Í Safe ƒ‚ƒWƒ…[ƒ‹‚ðŽg—p‚µ‚È‚¢PerlƒXƒNƒŠƒvƒg‚Í‹Ö‚¶‚ç‚ê"
+"‚Ä‚¢‚Ü‚·"
+
+msgid "Edit with &multiple Vims"
+msgstr "•¡”‚ÌVim‚Å•ÒW‚·‚é (&M)"
+
+msgid "Edit with single &Vim"
+msgstr "1‚‚ÌVim‚Å•ÒW‚·‚é (&V)"
+
+msgid "Diff with Vim"
+msgstr "Vim‚Å·•ª‚ð•\\Ž¦‚·‚é"
+
+msgid "Edit with &Vim"
+msgstr "Vim‚Å•ÒW‚·‚é (&V)"
+
+msgid "Edit with existing Vim"
+msgstr "‹N“®Ï‚ÌVim‚Å•ÒW‚·‚é"
+
+msgid "Edit with existing Vim - "
+msgstr "‹N“®Ï‚ÌVim‚Å•ÒW‚·‚é - "
+
+msgid "Edits the selected file(s) with Vim"
+msgstr "‘I‘ð‚µ‚½ƒtƒ@ƒCƒ‹‚ðVim‚Å•ÒW‚·‚é"
+
+msgid "Error creating process: Check if gvim is in your path!"
+msgstr "ƒvƒƒZƒX‚Ì쬂Ɏ¸”s: gvim‚ªŠÂ‹«•Ï”PATHã‚É‚ ‚é‚©Šm”F‚µ‚Ä‚­‚¾‚³‚¢!"
+
+msgid "gvimext.dll error"
+msgstr "gvimext.dll ƒGƒ‰["
+
+msgid "Path length too long!"
+msgstr "ƒpƒX‚ª’·‰ß‚¬‚Ü‚·!"
+
+msgid "--No lines in buffer--"
+msgstr "--ƒoƒbƒtƒ@‚És‚ª‚ ‚è‚Ü‚¹‚ñ--"
+
+msgid "E470: Command aborted"
+msgstr "E470: ƒRƒ}ƒ“ƒh‚ª’†’f‚³‚ê‚Ü‚µ‚½"
+
+msgid "E471: Argument required"
+msgstr "E471: ˆø”‚ª•K—v‚Å‚·"
+
+msgid "E10: \\ should be followed by /, ? or &"
+msgstr "E10: \\ ‚ÌŒã‚Í / ‚© ? ‚© & ‚Å‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñ"
+
+msgid "E11: Invalid in command-line window; <CR> executes, CTRL-C quits"
+msgstr "E11: ƒRƒ}ƒ“ƒhƒ‰ƒCƒ“‚Å‚Í–³Œø‚Å‚·; <CR>‚ÅŽÀs, CTRL-C‚Å‚â‚ß‚é"
+
+msgid "E12: Command not allowed from exrc/vimrc in current dir or tag search"
+msgstr ""
+"E12: Œ»Ý‚̃fƒBƒŒƒNƒgƒŠ‚âƒ^ƒOŒŸõ‚Å‚Íexrc/vimrc‚̃Rƒ}ƒ“ƒh‚Í‹–‰Â‚³‚ê‚Ü‚¹‚ñ"
+
+msgid "E171: Missing :endif"
+msgstr "E171: :endif ‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "E600: Missing :endtry"
+msgstr "E600: :endtry ‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "E170: Missing :endwhile"
+msgstr "E170: :endwhile ‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "E170: Missing :endfor"
+msgstr "E170: :endfor ‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "E588: :endwhile without :while"
+msgstr "E588: :while ‚Ì‚È‚¢ :endwhile ‚ª‚ ‚è‚Ü‚·"
+
+msgid "E588: :endfor without :for"
+msgstr "E588: :endfor ‚Ì‚È‚¢ :for ‚ª‚ ‚è‚Ü‚·"
+
+msgid "E13: File exists (add ! to override)"
+msgstr "E13: ƒtƒ@ƒCƒ‹‚ª‘¶Ý‚µ‚Ü‚· (! ‚ð’ljÁ‚Åã‘)"
+
+msgid "E472: Command failed"
+msgstr "E472: ƒRƒ}ƒ“ƒh‚ªŽ¸”s‚µ‚Ü‚µ‚½"
+
+#, c-format
+msgid "E234: Unknown fontset: %s"
+msgstr "E234: –¢’m‚̃tƒHƒ“ƒgƒZƒbƒg: %s"
+
+#, c-format
+msgid "E235: Unknown font: %s"
+msgstr "E235: –¢’m‚̃tƒHƒ“ƒg: %s"
+
+#, c-format
+msgid "E236: Font \"%s\" is not fixed-width"
+msgstr "E236: ƒtƒHƒ“ƒg \"%s\" ‚͌Œ蕂ł͂ ‚è‚Ü‚¹‚ñ"
+
+msgid "E473: Internal error"
+msgstr "E473: “à•”ƒGƒ‰[‚Å‚·"
+
+#, c-format
+msgid "E685: Internal error: %s"
+msgstr "E685: “à•”ƒGƒ‰[‚Å‚·: %s"
+
+msgid "Interrupted"
+msgstr "Š„ž‚Ü‚ê‚Ü‚µ‚½"
+
+msgid "E14: Invalid address"
+msgstr "E14: –³Œø‚ȃAƒhƒŒƒX‚Å‚·"
+
+msgid "E474: Invalid argument"
+msgstr "E474: –³Œø‚Ȉø”‚Å‚·"
+
+#, c-format
+msgid "E475: Invalid argument: %s"
+msgstr "E475: –³Œø‚Ȉø”‚Å‚·: %s"
+
+#, c-format
+msgid "E475: Invalid value for argument %s"
+msgstr "E475: ˆø” %s ‚ɑ΂µ‚Ä–³Œø‚È’l‚Å‚·"
+
+#, c-format
+msgid "E475: Invalid value for argument %s: %s"
+msgstr "E475: ˆø” %s ‚ɑ΂µ‚Ä–³Œø‚È’l‚Å‚·: %s"
+
+#, c-format
+msgid "E15: Invalid expression: %s"
+msgstr "E15: –³Œø‚ÈŽ®‚Å‚·: %s"
+
+msgid "E16: Invalid range"
+msgstr "E16: –³Œø‚Ȕ͈͂ł·"
+
+msgid "E476: Invalid command"
+msgstr "E476: –³Œø‚ȃRƒ}ƒ“ƒh‚Å‚·"
+
+#, c-format
+msgid "E17: \"%s\" is a directory"
+msgstr "E17: \"%s\" ‚̓fƒBƒŒƒNƒgƒŠ‚Å‚·"
+
+#, c-format
+msgid "E364: Library call failed for \"%s()\""
+msgstr "E364: \"%s\"() ‚̃‰ƒCƒuƒ‰ƒŠŒÄo‚ÉŽ¸”s‚µ‚Ü‚µ‚½"
+
+msgid "E667: Fsync failed"
+msgstr "E667: fsync ‚ÉŽ¸”s‚µ‚Ü‚µ‚½"
+
+#, c-format
+msgid "E448: Could not load library function %s"
+msgstr "E448: ƒ‰ƒCƒuƒ‰ƒŠ‚ÌŠÖ” %s ‚ðƒ[ƒh‚Å‚«‚Ü‚¹‚ñ‚Å‚µ‚½"
+
+msgid "E19: Mark has invalid line number"
+msgstr "E19: ƒ}[ƒN‚É–³Œø‚Ès”Ô†‚ªŽw’肳‚ê‚Ä‚¢‚Ü‚µ‚½"
+
+msgid "E20: Mark not set"
+msgstr "E20: ƒ}[ƒN‚Íݒ肳‚ê‚Ä‚¢‚Ü‚¹‚ñ"
+
+msgid "E21: Cannot make changes, 'modifiable' is off"
+msgstr "E21: 'modifiable' ‚ªƒIƒt‚È‚Ì‚ÅA•ÏX‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "E22: Scripts nested too deep"
+msgstr "E22: ƒXƒNƒŠƒvƒg‚Ì“ü‚êŽq‚ª[‰ß‚¬‚Ü‚·"
+
+msgid "E23: No alternate file"
+msgstr "E23: •›ƒtƒ@ƒCƒ‹‚Í‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "E24: No such abbreviation"
+msgstr "E24: ‚»‚̂悤‚È’Zk“ü—Í‚Í‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "E477: No ! allowed"
+msgstr "E477: ! ‚Í‹–‰Â‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ"
+
+msgid "E25: GUI cannot be used: Not enabled at compile time"
+msgstr "E25: GUI‚ÍŽg—p•s‰Â”\\‚Å‚·: ƒRƒ“ƒpƒCƒ‹Žž‚É–³Œø‚É‚³‚ê‚Ä‚¢‚Ü‚·"
+
+msgid "E26: Hebrew cannot be used: Not enabled at compile time\n"
+msgstr "E26: ƒwƒuƒ‰ƒCŒê‚ÍŽg—p•s‰Â”\\‚Å‚·: ƒRƒ“ƒpƒCƒ‹Žž‚É–³Œø‚É‚³‚ê‚Ä‚¢‚Ü‚·\n"
+
+msgid "E27: Farsi cannot be used: Not enabled at compile time\n"
+msgstr "E27: ƒyƒ‹ƒVƒAŒê‚ÍŽg—p•s‰Â”\\‚Å‚·: ƒRƒ“ƒpƒCƒ‹Žž‚É–³Œø‚É‚³‚ê‚Ä‚¢‚Ü‚·\n"
+
+msgid "E800: Arabic cannot be used: Not enabled at compile time\n"
+msgstr "E800: ƒAƒ‰ƒrƒAŒê‚ÍŽg—p•s‰Â”\\‚Å‚·: ƒRƒ“ƒpƒCƒ‹Žž‚É–³Œø‚É‚³‚ê‚Ä‚¢‚Ü‚·\n"
+
+#, c-format
+msgid "E28: No such highlight group name: %s"
+msgstr "E28: ‚»‚̂悤‚È–¼‚̃nƒCƒ‰ƒCƒgƒOƒ‹[ƒv‚Í‚ ‚è‚Ü‚¹‚ñ: %s"
+
+msgid "E29: No inserted text yet"
+msgstr "E29: ‚Ü‚¾ƒeƒLƒXƒg‚ª‘}“ü‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ"
+
+msgid "E30: No previous command line"
+msgstr "E30: ˆÈ‘O‚ɃRƒ}ƒ“ƒhs‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "E31: No such mapping"
+msgstr "E31: ‚»‚̂悤‚ȃ}ƒbƒsƒ“ƒO‚Í‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "E479: No match"
+msgstr "E479: ŠY“–‚Í‚ ‚è‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E480: No match: %s"
+msgstr "E480: ŠY“–‚Í‚ ‚è‚Ü‚¹‚ñ: %s"
+
+msgid "E32: No file name"
+msgstr "E32: ƒtƒ@ƒCƒ‹–¼‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "E33: No previous substitute regular expression"
+msgstr "E33: ³‹K•\\Œ»’uŠ·‚ª‚Ü‚¾ŽÀs‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ"
+
+msgid "E34: No previous command"
+msgstr "E34: ƒRƒ}ƒ“ƒh‚ª‚Ü‚¾ŽÀs‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ"
+
+msgid "E35: No previous regular expression"
+msgstr "E35: ³‹K•\\Œ»‚ª‚Ü‚¾ŽÀs‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ"
+
+msgid "E481: No range allowed"
+msgstr "E481: ”͈͎w’è‚Í‹–‰Â‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ"
+
+msgid "E36: Not enough room"
+msgstr "E36: ƒEƒBƒ“ƒhƒE‚É\\•ª‚È‚‚³‚à‚µ‚­‚Í•‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E247: no registered server named \"%s\""
+msgstr "E247: %s ‚Æ‚¢‚¤–¼‘O‚Ì“o˜^‚³‚ꂽƒT[ƒo[‚Í‚ ‚è‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E482: Can't create file %s"
+msgstr "E482: ƒtƒ@ƒCƒ‹ %s ‚ð쬂ł«‚Ü‚¹‚ñ"
+
+msgid "E483: Can't get temp file name"
+msgstr "E483: ˆêŽžƒtƒ@ƒCƒ‹‚Ì–¼‘O‚ðŽæ“¾‚Å‚«‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E484: Can't open file %s"
+msgstr "E484: ƒtƒ@ƒCƒ‹ \"%s\" ‚ðŠJ‚¯‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E485: Can't read file %s"
+msgstr "E485: ƒtƒ@ƒCƒ‹ %s ‚ð“Çž‚ß‚Ü‚¹‚ñ"
+
+msgid "E38: Null argument"
+msgstr "E38: ˆø”‚ª‹ó‚Å‚·"
+
+msgid "E39: Number expected"
+msgstr "E39: ”’l‚ª—v‹‚³‚ê‚Ä‚¢‚Ü‚·"
+
+#, c-format
+msgid "E40: Can't open errorfile %s"
+msgstr "E40: ƒGƒ‰[ƒtƒ@ƒCƒ‹ %s ‚ðŠJ‚¯‚Ü‚¹‚ñ"
+
+msgid "E233: cannot open display"
+msgstr "E233: ƒfƒBƒXƒvƒŒƒC‚ðŠJ‚¯‚Ü‚¹‚ñ"
+
+msgid "E41: Out of memory!"
+msgstr "E41: ƒƒ‚ƒŠ‚ªs‚«‰Ê‚Ä‚Ü‚µ‚½!"
+
+msgid "Pattern not found"
+msgstr "ƒpƒ^[ƒ“‚ÍŒ©‚‚©‚è‚Ü‚¹‚ñ‚Å‚µ‚½"
+
+#, c-format
+msgid "E486: Pattern not found: %s"
+msgstr "E486: ƒpƒ^[ƒ“‚ÍŒ©‚‚©‚è‚Ü‚¹‚ñ‚Å‚µ‚½: %s"
+
+msgid "E487: Argument must be positive"
+msgstr "E487: ˆø”‚ͳ‚Ì’l‚Å‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñ"
+
+msgid "E459: Cannot go back to previous directory"
+msgstr "E459: ‘O‚̃fƒBƒŒƒNƒgƒŠ‚É–ß‚ê‚Ü‚¹‚ñ"
+
+msgid "E42: No Errors"
+msgstr "E42: ƒGƒ‰[‚Í‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "E776: No location list"
+msgstr "E776: ƒƒP[ƒVƒ‡ƒ“ƒŠƒXƒg‚Í‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "E43: Damaged match string"
+msgstr "E43: ŠY“–•¶Žš—ñ‚ª”j‘¹‚µ‚Ä‚¢‚Ü‚·"
+
+msgid "E44: Corrupted regexp program"
+msgstr "E44: •s³‚ȳ‹K•\\Œ»ƒvƒƒOƒ‰ƒ€‚Å‚·"
+
+msgid "E45: 'readonly' option is set (add ! to override)"
+msgstr "E45: 'readonly' ƒIƒvƒVƒ‡ƒ“‚ªÝ’肳‚ê‚Ä‚¢‚Ü‚· (! ‚ð’ljÁ‚Åã‘‚«)"
+
+#, c-format
+msgid "E46: Cannot change read-only variable \"%s\""
+msgstr "E46: “ÇŽæê—p•Ï” \"%s\" ‚É‚Í’l‚ðÝ’è‚Å‚«‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "E794: Cannot set variable in the sandbox: \"%s\""
+msgstr "E794: ƒTƒ“ƒhƒ{ƒbƒNƒX‚Å‚Í•Ï” \"%s\" ‚É’l‚ðÝ’è‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "E713: Cannot use empty key for Dictionary"
+msgstr "E713: Ž«‘Œ^‚É‹ó‚̃L[‚ðŽg‚¤‚±‚Æ‚Í‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "E715: Dictionary required"
+msgstr "E715: Ž«‘Œ^‚ª•K—v‚Å‚·"
+
+#, c-format
+msgid "E684: list index out of range: %ld"
+msgstr "E684: ƒŠƒXƒg‚̃Cƒ“ƒfƒbƒNƒX‚ª”͈͊O‚Å‚·: %ld"
+
+#, c-format
+msgid "E118: Too many arguments for function: %s"
+msgstr "E118: ŠÖ”‚̈ø”‚ª‘½‰ß‚¬‚Ü‚·: %s"
+
+#, c-format
+msgid "E716: Key not present in Dictionary: %s"
+msgstr "E716: Ž«‘Œ^‚ɃL[‚ª‘¶Ý‚µ‚Ü‚¹‚ñ: %s"
+
+msgid "E714: List required"
+msgstr "E714: ƒŠƒXƒgŒ^‚ª•K—v‚Å‚·"
+
+#, c-format
+msgid "E712: Argument of %s must be a List or Dictionary"
+msgstr "E712: %s ‚̈ø”‚̓ŠƒXƒgŒ^‚Ü‚½‚ÍŽ«‘Œ^‚Å‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñ"
+
+msgid "E47: Error while reading errorfile"
+msgstr "E47: ƒGƒ‰[ƒtƒ@ƒCƒ‹‚Ì“Çž’†‚ɃGƒ‰[‚ª”­¶‚µ‚Ü‚µ‚½"
+
+msgid "E48: Not allowed in sandbox"
+msgstr "E48: ƒTƒ“ƒhƒ{ƒbƒNƒX‚Å‚Í‹–‚³‚ê‚Ü‚¹‚ñ"
+
+msgid "E523: Not allowed here"
+msgstr "E523: ‚±‚±‚Å‚Í‹–‰Â‚³‚ê‚Ü‚¹‚ñ"
+
+msgid "E359: Screen mode setting not supported"
+msgstr "E359: ƒXƒNƒŠ[ƒ“ƒ‚[ƒh‚ÌÝ’è‚ɂ͑Ήž‚µ‚Ä‚¢‚Ü‚¹‚ñ"
+
+msgid "E49: Invalid scroll size"
+msgstr "E49: –³Œø‚ȃXƒNƒ[ƒ‹—Ê‚Å‚·"
+
+msgid "E91: 'shell' option is empty"
+msgstr "E91: 'shell' ƒIƒvƒVƒ‡ƒ“‚ª‹ó‚Å‚·"
+
+msgid "E255: Couldn't read in sign data!"
+msgstr "E255: sign ‚̃f[ƒ^‚ð“Çž‚ß‚Ü‚¹‚ñ‚Å‚µ‚½"
+
+msgid "E72: Close error on swap file"
+msgstr "E72: ƒXƒƒbƒvƒtƒ@ƒCƒ‹‚̃Nƒ[ƒYŽžƒGƒ‰[‚Å‚·"
+
+msgid "E73: tag stack empty"
+msgstr "E73: ƒ^ƒOƒXƒ^ƒbƒN‚ª‹ó‚Å‚·"
+
+msgid "E74: Command too complex"
+msgstr "E74: ƒRƒ}ƒ“ƒh‚ª•¡ŽG‰ß‚¬‚Ü‚·"
+
+msgid "E75: Name too long"
+msgstr "E75: –¼‘O‚ª’·‰ß‚¬‚Ü‚·"
+
+msgid "E76: Too many ["
+msgstr "E76: [ ‚ª‘½‰ß‚¬‚Ü‚·"
+
+msgid "E77: Too many file names"
+msgstr "E77: ƒtƒ@ƒCƒ‹–¼‚ª‘½‰ß‚¬‚Ü‚·"
+
+msgid "E488: Trailing characters"
+msgstr "E488: —]•ª‚È•¶Žš‚ªŒã‚ë‚É‚ ‚è‚Ü‚·"
+
+msgid "E78: Unknown mark"
+msgstr "E78: –¢’m‚̃}[ƒN"
+
+msgid "E79: Cannot expand wildcards"
+msgstr "E79: ƒƒCƒ‹ƒhƒJ[ƒh‚ð“WŠJ‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "E591: 'winheight' cannot be smaller than 'winminheight'"
+msgstr "E591: 'winheight' ‚Í 'winminheight' ‚æ‚謂³‚­‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "E592: 'winwidth' cannot be smaller than 'winminwidth'"
+msgstr "E592: 'winwidth' ‚Í 'winminwidth' ‚æ‚謂³‚­‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "E80: Error while writing"
+msgstr "E80: ‘ž‚Ý’†‚̃Gƒ‰["
+
+msgid "E939: Positive count required"
+msgstr "E939: ³‚̃JƒEƒ“ƒg‚ª•K—v‚Å‚·"
+
+msgid "E81: Using <SID> not in a script context"
+msgstr "E81: ƒXƒNƒŠƒvƒgˆÈŠO‚Å<SID>‚ªŽg‚í‚ê‚Ü‚µ‚½"
+
+msgid "E449: Invalid expression received"
+msgstr "E449: –³Œø‚ÈŽ®‚ðŽó‚¯Žæ‚è‚Ü‚µ‚½"
+
+msgid "E463: Region is guarded, cannot modify"
+msgstr "E463: —̈悪•ÛŒì‚³‚ê‚Ä‚¢‚é‚Ì‚ÅA•ÏX‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "E744: NetBeans does not allow changes in read-only files"
+msgstr "E744: NetBeans ‚Í“Çžê—pƒtƒ@ƒCƒ‹‚ð•ÏX‚·‚邱‚Æ‚ð‹–‚µ‚Ü‚¹‚ñ"
+
+msgid "E363: pattern uses more memory than 'maxmempattern'"
+msgstr "E363: ƒpƒ^[ƒ“‚ª 'maxmempattern' ˆÈã‚̃ƒ‚ƒŠ‚ðŽg—p‚µ‚Ü‚·"
+
+msgid "E749: empty buffer"
+msgstr "E749: ƒoƒbƒtƒ@‚ª‹ó‚Å‚·"
+
+#, c-format
+msgid "E86: Buffer %ld does not exist"
+msgstr "E86: ƒoƒbƒtƒ@ %ld ‚Í‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "E682: Invalid search pattern or delimiter"
+msgstr "E682: ŒŸõƒpƒ^[ƒ“‚©‹æØ‚è‹L†‚ª•s³‚Å‚·"
+
+msgid "E139: File is loaded in another buffer"
+msgstr "E139: “¯‚¶–¼‘O‚̃tƒ@ƒCƒ‹‚ª‘¼‚̃oƒbƒtƒ@‚Å“Çž‚Ü‚ê‚Ä‚¢‚Ü‚·"
+
+#, c-format
+msgid "E764: Option '%s' is not set"
+msgstr "E764: ƒIƒvƒVƒ‡ƒ“ '%s' ‚Íݒ肳‚ê‚Ä‚¢‚Ü‚¹‚ñ"
+
+msgid "E850: Invalid register name"
+msgstr "E850: –³Œø‚ȃŒƒWƒXƒ^–¼‚Å‚·"
+
+#, c-format
+msgid "E919: Directory not found in '%s': \"%s\""
+msgstr "E919: ƒfƒBƒŒƒNƒgƒŠ‚ª '%s' ‚Ì’†‚É‚ ‚è‚Ü‚¹‚ñ: \"%s\""
+
+msgid "E952: Autocommand caused recursive behavior"
+msgstr "E952: Autocommand‚ªÄ‹A‚ðˆø‚«‹N‚±‚µ‚Ü‚µ‚½"
+
+msgid "search hit TOP, continuing at BOTTOM"
+msgstr "ã‚Ü‚ÅŒŸõ‚µ‚½‚̂ʼnº‚É–ß‚è‚Ü‚·"
+
+msgid "search hit BOTTOM, continuing at TOP"
+msgstr "‰º‚Ü‚ÅŒŸõ‚µ‚½‚Ì‚Åã‚É–ß‚è‚Ü‚·"
+
+#, c-format
+msgid "Need encryption key for \"%s\""
+msgstr "ˆÃ†ƒL[‚ª•K—v‚Å‚·: \"%s\""
+
+msgid "empty keys are not allowed"
+msgstr "‹ó‚̃L[‚Í‹–‰Â‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ"
+
+msgid "dictionary is locked"
+msgstr "Ž«‘‚̓ƒbƒN‚³‚ê‚Ä‚¢‚Ü‚·"
+
+msgid "list is locked"
+msgstr "ƒŠƒXƒg‚̓ƒbƒN‚³‚ê‚Ä‚¢‚Ü‚·"
+
+#, c-format
+msgid "failed to add key '%s' to dictionary"
+msgstr "Ž«‘‚ɃL[ '%s' ‚ð’ljÁ‚·‚é‚Ì‚ÉŽ¸”s‚µ‚Ü‚µ‚½"
+
+#, c-format
+msgid "index must be int or slice, not %s"
+msgstr "ƒCƒ“ƒfƒbƒNƒX‚Í %s ‚Å‚Í‚È‚­®”‚©ƒXƒ‰ƒCƒX‚É‚µ‚Ä‚­‚¾‚³‚¢"
+
+#, c-format
+msgid "expected str() or unicode() instance, but got %s"
+msgstr "str() ‚à‚µ‚­‚Í unicode() ‚̃Cƒ“ƒXƒ^ƒ“ƒX‚ªŠú‘Ò‚³‚ê‚Ä‚¢‚é‚Ì‚É %s ‚Å‚µ‚½"
+
+#, c-format
+msgid "expected bytes() or str() instance, but got %s"
+msgstr "bytes() ‚à‚µ‚­‚Í str() ‚̃Cƒ“ƒXƒ^ƒ“ƒX‚ªŠú‘Ò‚³‚ê‚Ä‚¢‚é‚Ì‚É %s ‚Å‚µ‚½"
+
+#, c-format
+msgid ""
+"expected int(), long() or something supporting coercing to long(), but got %s"
+msgstr "long() ‚©‚»‚ê‚Ö•ÏŠ·‰Â”\\‚È‚à‚Ì‚ªŠú‘Ò‚³‚ê‚Ä‚¢‚é‚Ì‚É %s ‚Å‚µ‚½"
+
+#, c-format
+msgid "expected int() or something supporting coercing to int(), but got %s"
+msgstr "int() ‚©‚»‚ê‚Ö•ÏŠ·‰Â”\\‚È‚à‚Ì‚ªŠú‘Ò‚³‚ê‚Ä‚¢‚é‚Ì‚É %s ‚Å‚µ‚½"
+
+msgid "value is too large to fit into C int type"
+msgstr "CŒ¾Œê‚Ì int Œ^‚Æ‚µ‚Ä‚Í’l‚ª‘å‚«‰ß‚¬‚Ü‚·"
+
+msgid "value is too small to fit into C int type"
+msgstr "CŒ¾Œê‚Ì int Œ^‚Æ‚µ‚Ä‚Í’l‚ª¬‚³‰ß‚¬‚Ü‚·"
+
+msgid "number must be greater than zero"
+msgstr "”’l‚Í 0 ‚æ‚è‘å‚«‚­‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñ"
+
+msgid "number must be greater or equal to zero"
+msgstr "”’l‚Í 0 ‚©‚»‚êˆÈã‚Å‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñ"
+
+msgid "can't delete OutputObject attributes"
+msgstr "OutputObject‘®«‚ðÁ‚¹‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "invalid attribute: %s"
+msgstr "–³Œø‚È‘®«‚Å‚·: %s"
+
+msgid "E264: Python: Error initialising I/O objects"
+msgstr "E264: Python: I/OƒIƒuƒWƒFƒNƒg‚̉Šú‰»ƒGƒ‰["
+
+msgid "failed to change directory"
+msgstr "Ž«‘‚Ì•ÏX‚ÉŽ¸”s‚µ‚Ü‚µ‚½"
+
+#, c-format
+msgid "expected 3-tuple as imp.find_module() result, but got %s"
+msgstr "imp.find_module() ‚ª %s ‚ð•Ô‚µ‚Ü‚µ‚½ (Šú‘Ò’l: 3 —v‘f‚̃^ƒvƒ‹)"
+
+#, c-format
+msgid "expected 3-tuple as imp.find_module() result, but got tuple of size %d"
+msgstr "imp.find_module() ‚ª %d —v‘f‚̃^ƒvƒ‹‚ð•Ô‚µ‚Ü‚µ‚½ (Šú‘Ò’l: 3)"
+
+msgid "internal error: imp.find_module returned tuple with NULL"
+msgstr "“à•”ƒGƒ‰[: imp.find_module ‚ª NULL ‚ðŠÜ‚Þƒ^ƒvƒ‹‚ð•Ô‚µ‚Ü‚µ‚½"
+
+msgid "cannot delete vim.Dictionary attributes"
+msgstr "vim.Dictionary‘®«‚ÍÁ‚¹‚Ü‚¹‚ñ"
+
+msgid "cannot modify fixed dictionary"
+msgstr "ŒÅ’肳‚ꂽŽ«‘‚Í•ÏX‚Å‚«‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "cannot set attribute %s"
+msgstr "‘®« %s ‚ÍÝ’è‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "hashtab changed during iteration"
+msgstr "ƒCƒeƒŒ[ƒVƒ‡ƒ“’†‚É hashtab ‚ª•ÏX‚³‚ê‚Ü‚µ‚½"
+
+#, c-format
+msgid "expected sequence element of size 2, but got sequence of size %d"
+msgstr "ƒV[ƒPƒ“ƒX‚Ì—v‘f”‚É‚Í 2 ‚ªŠú‘Ò‚³‚ê‚Ä‚¢‚Ü‚µ‚½‚ª %d ‚Å‚µ‚½"
+
+msgid "list constructor does not accept keyword arguments"
+msgstr "ƒŠƒXƒg‚̃Rƒ“ƒXƒgƒ‰ƒNƒ^‚̓L[ƒ[ƒhˆø”‚ðŽó‚¯•t‚¯‚Ü‚¹‚ñ"
+
+msgid "list index out of range"
+msgstr "ƒŠƒXƒg”͈͊O‚̃Cƒ“ƒfƒbƒNƒX‚Å‚·"
+
+#, c-format
+msgid "internal error: failed to get vim list item %d"
+msgstr "“à•”ƒGƒ‰[: vim‚̃ŠƒXƒg—v‘f %d ‚̎擾‚ÉŽ¸”s‚µ‚Ü‚µ‚½"
+
+msgid "slice step cannot be zero"
+msgstr "ƒXƒ‰ƒCƒX‚̃Xƒeƒbƒv‚É 0 ‚ÍŽw’è‚Å‚«‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "attempt to assign sequence of size greater than %d to extended slice"
+msgstr "’·‚³ %d ‚ÌŠg’£ƒXƒ‰ƒCƒX‚ÉA‚æ‚è’·‚¢ƒXƒ‰ƒCƒX‚ðŠ„‚è“–‚Ă悤‚Æ‚µ‚Ü‚µ‚½"
+
+#, c-format
+msgid "internal error: no vim list item %d"
+msgstr "“à•”ƒGƒ‰[: vim‚̃ŠƒXƒg—v‘f %d ‚Í‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "internal error: not enough list items"
+msgstr "“à•”ƒGƒ‰[: ƒŠƒXƒg‚É\\•ª‚È—v‘f‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "internal error: failed to add item to list"
+msgstr "“à•”ƒGƒ‰[: ƒŠƒXƒg‚Ö‚Ì—v‘f’ljÁ‚ÉŽ¸”s‚µ‚Ü‚µ‚½"
+
+#, c-format
+msgid "attempt to assign sequence of size %d to extended slice of size %d"
+msgstr "’·‚³ %d ‚̃Xƒ‰ƒCƒX‚ð %d ‚ÌŠg’£ƒXƒ‰ƒCƒX‚ÉŠ„‚è“–‚Ă悤‚Æ‚µ‚Ü‚µ‚½"
+
+msgid "failed to add item to list"
+msgstr "ƒŠƒXƒg‚Ö‚Ì—v‘f’ljÁ‚ÉŽ¸”s‚µ‚Ü‚µ‚½"
+
+msgid "cannot delete vim.List attributes"
+msgstr "vim.List ‘®«‚ÍÁ‚¹‚Ü‚¹‚ñ"
+
+msgid "cannot modify fixed list"
+msgstr "ŒÅ’肳‚ꂽƒŠƒXƒg‚Í•ÏX‚Å‚«‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "unnamed function %s does not exist"
+msgstr "–³–¼ŠÖ” %s ‚Í‘¶Ý‚µ‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "function %s does not exist"
+msgstr "ŠÖ” %s ‚ª‚ ‚è‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "failed to run function %s"
+msgstr "ŠÖ” %s ‚ÌŽÀs‚ÉŽ¸”s‚µ‚Ü‚µ‚½"
+
+msgid "unable to get option value"
+msgstr "ƒIƒvƒVƒ‡ƒ“‚Ì’l‚͎擾‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "internal error: unknown option type"
+msgstr "“à•”ƒGƒ‰[: –¢’m‚̃IƒvƒVƒ‡ƒ“Œ^‚Å‚·"
+
+msgid "problem while switching windows"
+msgstr "ƒEƒBƒ“ƒhƒE‚ðØŠ·’†‚É–â‘肪”­¶‚µ‚Ü‚µ‚½"
+
+#, c-format
+msgid "unable to unset global option %s"
+msgstr "ƒOƒ[ƒoƒ‹ƒIƒvƒVƒ‡ƒ“ %s ‚ÌÝ’è‰ðœ‚Í‚Å‚«‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "unable to unset option %s which does not have global value"
+msgstr "ƒOƒ[ƒoƒ‹‚È’l‚Ì–³‚¢ƒIƒvƒVƒ‡ƒ“ %s ‚ÌÝ’è‰ðœ‚Í‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "attempt to refer to deleted tab page"
+msgstr "휂³‚ꂽƒ^ƒu‚ðŽQÆ‚µ‚悤‚Æ‚µ‚Ü‚µ‚½"
+
+msgid "no such tab page"
+msgstr "‚»‚̂悤‚ȃ^ƒuƒy[ƒW‚Í‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "attempt to refer to deleted window"
+msgstr "휂³‚ꂽƒEƒBƒ“ƒhƒE‚ðŽQÆ‚µ‚悤‚Æ‚µ‚Ü‚µ‚½"
+
+msgid "readonly attribute: buffer"
+msgstr "“Çžê—p‘®«: ƒoƒbƒtƒ@["
+
+msgid "cursor position outside buffer"
+msgstr "ƒJ[ƒ\\ƒ‹ˆÊ’u‚ªƒoƒbƒtƒ@‚ÌŠO‘¤‚Å‚·"
+
+msgid "no such window"
+msgstr "‚»‚̂悤‚ȃEƒBƒ“ƒhƒE‚Í‚ ‚è‚Ü‚¹‚ñ"
+
+msgid "attempt to refer to deleted buffer"
+msgstr "휂³‚ꂽƒoƒbƒtƒ@‚ðŽQÆ‚µ‚悤‚Æ‚µ‚Ü‚µ‚½"
+
+msgid "failed to rename buffer"
+msgstr "ƒoƒbƒtƒ@–¼‚Ì•ÏX‚ÉŽ¸”s‚µ‚Ü‚µ‚½"
+
+msgid "mark name must be a single character"
+msgstr "ƒ}[ƒN–¼‚Í1•¶Žš‚̃Aƒ‹ƒtƒ@ƒxƒbƒg‚Å‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "expected vim.Buffer object, but got %s"
+msgstr "vim.BufferƒIƒuƒWƒFƒNƒg‚ªŠú‘Ò‚³‚ê‚Ä‚¢‚é‚Ì‚É %s ‚Å‚µ‚½"
+
+#, c-format
+msgid "failed to switch to buffer %d"
+msgstr "Žw’肳‚ꂽƒoƒbƒtƒ@ %d ‚Ö‚ÌØ‚è‘Ö‚¦‚ÉŽ¸”s‚µ‚Ü‚µ‚½"
+
+#, c-format
+msgid "expected vim.Window object, but got %s"
+msgstr "vim.WindowƒIƒuƒWƒFƒNƒg‚ªŠú‘Ò‚³‚ê‚Ä‚¢‚é‚Ì‚É %s ‚Å‚µ‚½"
+
+msgid "failed to find window in the current tab page"
+msgstr "Œ»Ý‚̃^ƒu‚É‚ÍŽw’肳‚ꂽƒEƒBƒ“ƒhƒE‚ª‚ ‚è‚Ü‚¹‚ñ‚Å‚µ‚½"
+
+msgid "did not switch to the specified window"
+msgstr "Žw’肳‚ꂽƒEƒBƒ“ƒhƒE‚ÉØ‚è‘Ö‚¦‚Ü‚¹‚ñ‚Å‚µ‚½"
+
+#, c-format
+msgid "expected vim.TabPage object, but got %s"
+msgstr "vim.TabPageƒIƒuƒWƒFƒNƒg‚ªŠú‘Ò‚³‚ê‚Ä‚¢‚é‚Ì‚É %s ‚Å‚µ‚½"
+
+msgid "did not switch to the specified tab page"
+msgstr "Žw’肳‚ꂽƒ^ƒuƒy[ƒW‚ÉØ‚è‘Ö‚¦‚Ü‚¹‚ñ‚Å‚µ‚½"
+
+msgid "failed to run the code"
+msgstr "ƒR[ƒh‚ÌŽÀs‚ÉŽ¸”s‚µ‚Ü‚µ‚½"
+
+msgid "E858: Eval did not return a valid python object"
+msgstr "E858: Ž®•]‰¿‚Í—LŒø‚ÈpythonƒIƒuƒWƒFƒNƒg‚ð•Ô‚µ‚Ü‚¹‚ñ‚Å‚µ‚½"
+
+msgid "E859: Failed to convert returned python object to vim value"
+msgstr "E859: •Ô‚³‚ꂽpythonƒIƒuƒWƒFƒNƒg‚ðvim‚Ì’l‚É•ÏŠ·‚Å‚«‚Ü‚¹‚ñ‚Å‚µ‚½"
+
+#, c-format
+msgid "unable to convert %s to vim dictionary"
+msgstr "%s vim‚ÌŽ«‘Œ^‚É•ÏŠ·‚Å‚«‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "unable to convert %s to vim list"
+msgstr "%s ‚ðvim‚̃ŠƒXƒg‚É•ÏŠ·‚Å‚«‚Ü‚¹‚ñ"
+
+#, c-format
+msgid "unable to convert %s to vim structure"
+msgstr "%s ‚ðvim‚Ì\\‘¢‘Ì‚É•ÏŠ·‚Å‚«‚Ü‚¹‚ñ"
+
+msgid "internal error: NULL reference passed"
+msgstr "“à•”ƒGƒ‰[: NULLŽQÆ‚ª“n‚³‚ê‚Ü‚µ‚½"
+
+msgid "internal error: invalid value type"
+msgstr "“à•”ƒGƒ‰[: –³Œø‚È’lŒ^‚Å‚·"
+
+msgid ""
+"Failed to set path hook: sys.path_hooks is not a list\n"
+"You should now do the following:\n"
+"- append vim.path_hook to sys.path_hooks\n"
+"- append vim.VIM_SPECIAL_PATH to sys.path\n"
+msgstr ""
+"ƒpƒXƒtƒbƒN‚ÌÝ’è‚ÉŽ¸”s‚µ‚Ü‚µ‚½: sys.path_hooks ‚ªƒŠƒXƒg‚Å‚Í‚ ‚è‚Ü‚¹‚ñ\n"
+"‚·‚®‚ɉº‹L‚ðŽÀŽ{‚µ‚Ä‚­‚¾‚³‚¢:\n"
+"- vim.path_hooks ‚ð sys.path_hooks ‚֒ljÁ\n"
+"- vim.VIM_SPECIAL_PATH ‚ð sys.path ‚֒ljÁ\n"
+
+msgid ""
+"Failed to set path: sys.path is not a list\n"
+"You should now append vim.VIM_SPECIAL_PATH to sys.path"
+msgstr ""
+"ƒpƒX‚ÌÝ’è‚ÉŽ¸”s‚µ‚Ü‚µ‚½: sys.path ‚ªƒŠƒXƒg‚Å‚Í‚ ‚è‚Ü‚¹‚ñ\n"
+"‚·‚®‚É vim.VIM_SPECIAL_PATH ‚ð sys.path ‚ɒljÁ‚µ‚Ä‚­‚¾‚³‚¢"
+
+msgid ""
+"Vim macro files (*.vim)\t*.vim\n"
+"All Files (*.*)\t*.*\n"
+msgstr ""
+"Vimƒ}ƒNƒƒtƒ@ƒCƒ‹ (*.vim)\t*.vim\n"
+"‚·‚ׂẴtƒ@ƒCƒ‹ (*.*)\t*.*\n"
+
+msgid "All Files (*.*)\t*.*\n"
+msgstr "‚·‚ׂẴtƒ@ƒCƒ‹ (*.*)\t*.*\n"
+
+msgid ""
+"All Files (*.*)\t*.*\n"
+"C source (*.c, *.h)\t*.c;*.h\n"
+"C++ source (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"VB code (*.bas, *.frm)\t*.bas;*.frm\n"
+"Vim files (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
+msgstr ""
+"‚·‚ׂẴtƒ@ƒCƒ‹ (*.*)\t*.*\n"
+"Cƒ\\[ƒX (*.c, *.h)\t*.c;*.h\n"
+"C++ƒ\\[ƒX (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"VBƒR[ƒh (*.bas, *.frm)\t*.bas;*.frm\n"
+"Vimƒtƒ@ƒCƒ‹ (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
+
+msgid ""
+"Vim macro files (*.vim)\t*.vim\n"
+"All Files (*)\t*\n"
+msgstr ""
+"Vim ƒ}ƒNƒƒtƒ@ƒCƒ‹ (*.vim)\t*.vim\n"
+"‚·‚ׂẴtƒ@ƒCƒ‹ (*)\t*\n"
+
+msgid "All Files (*)\t*\n"
+msgstr "‚·‚ׂẴtƒ@ƒCƒ‹ (*)\t*\n"
+
+msgid ""
+"All Files (*)\t*\n"
+"C source (*.c, *.h)\t*.c;*.h\n"
+"C++ source (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"Vim files (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
+msgstr ""
+"‚·‚ׂẴtƒ@ƒCƒ‹ (*)\t*\n"
+"Cƒ\\[ƒX (*.c, *.h)\t*.c;*.h\n"
+"C++ƒ\\[ƒX (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"Vimƒtƒ@ƒCƒ‹ (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
diff --git a/src/po/ko.UTF-8.po b/src/po/ko.UTF-8.po
new file mode 100644
index 0000000..b01fb8e
--- /dev/null
+++ b/src/po/ko.UTF-8.po
@@ -0,0 +1,7009 @@
+# Korean translation for Vim
+#
+# FIRST AUTHOR SungHyun Nam <goweol@gmail.com>, 2000-2018
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: vim 8.1\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2018-06-29 08:21+0900\n"
+"PO-Revision-Date: 2018-06-29 09:32+0900\n"
+"Last-Translator: SungHyun Nam <goweol@gmail.com>\n"
+"Language-Team: Korean\n"
+"Language: ko\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+
+msgid "E831: bf_key_init() called with empty password"
+msgstr "E831: 빈 비밀번호로 bf_key_init() 함수가 불려졌습니다"
+
+msgid "E820: sizeof(uint32_t) != 4"
+msgstr "E820: sizeof(uint32_t) != 4"
+
+msgid "E817: Blowfish big/little endian use wrong"
+msgstr "E817: Blowfish big/little endian use wrong"
+
+msgid "E818: sha256 test failed"
+msgstr "E818: sha256 ì‹œí—˜ì´ ì‹¤íŒ¨í–ˆìŠµë‹ˆë‹¤."
+
+msgid "E819: Blowfish test failed"
+msgstr "E819: Blowfish ì‹œí—˜ì´ ì‹¤íŒ¨í–ˆìŠµë‹ˆë‹¤."
+
+msgid "[Location List]"
+msgstr "[위치 목ë¡]"
+
+msgid "[Quickfix List]"
+msgstr "[Quickfix 목ë¡]"
+
+msgid "E855: Autocommands caused command to abort"
+msgstr "E855: Autocommandë¡œ ëª…ë ¹ì´ ì¤‘ë‹¨ë˜ì—ˆìŠµë‹ˆë‹¤"
+
+msgid "E82: Cannot allocate any buffer, exiting..."
+msgstr "E82: 버í¼ë¥¼ 할당할 수 없어서 ë냅니다..."
+
+msgid "E83: Cannot allocate buffer, using other one..."
+msgstr "E83: 버í¼ë¥¼ 할당할 수 없어서 다른 걸 사용합니다..."
+
+msgid "E931: Buffer cannot be registered"
+msgstr "E931: 버í¼ë¥¼ 등ë¡í•˜ì§€ 못했습니다"
+
+msgid "E937: Attempt to delete a buffer that is in use"
+msgstr "E937: ì‚¬ìš©ì¤‘ì¸ ë²„í¼ë¥¼ 삭제하려고 했습니다"
+
+msgid "E515: No buffers were unloaded"
+msgstr "E515: 내려진 버í¼ê°€ 없습니다"
+
+msgid "E516: No buffers were deleted"
+msgstr "E516: 지워진 버í¼ê°€ 없습니다"
+
+msgid "E517: No buffers were wiped out"
+msgstr "E517: 완전히 지워진 버í¼ê°€ 없습니다"
+
+msgid "1 buffer unloaded"
+msgstr "ë²„í¼ í•œ 개가 내려졌습니다"
+
+#, c-format
+msgid "%d buffers unloaded"
+msgstr "ë²„í¼ %d 개가 내려졌습니다"
+
+msgid "1 buffer deleted"
+msgstr "ë²„í¼ í•œ 개가 지워졌습니다"
+
+#, c-format
+msgid "%d buffers deleted"
+msgstr "ë²„í¼ %d 개가 지워졌습니다"
+
+msgid "1 buffer wiped out"
+msgstr "ë²„í¼ í•œ 개가 완전히 지워졌습니다"
+
+#, c-format
+msgid "%d buffers wiped out"
+msgstr "ë²„í¼ %d개가 완전히 지워졌습니다"
+
+msgid "E90: Cannot unload last buffer"
+msgstr "E90: 마지막 버í¼ë¥¼ 내릴 수 없습니다"
+
+msgid "E84: No modified buffer found"
+msgstr "E84: ë°”ë€ ë²„í¼ë¥¼ ì°¾ì„ ìˆ˜ 없습니다"
+
+msgid "E85: There is no listed buffer"
+msgstr "E85: ë‚˜ì—´ëœ ë²„í¼ê°€ 없습니다"
+
+msgid "E87: Cannot go beyond last buffer"
+msgstr "E87: 마지막 버í¼ìž…니다"
+
+msgid "E88: Cannot go before first buffer"
+msgstr "E88: 첫 번째 버í¼ìž…니다"
+
+#, c-format
+msgid "E89: No write since last change for buffer %ld (add ! to override)"
+msgstr ""
+"E89: ë²„í¼ %ldì„(를) 마지막으로 고친 ë’¤ 저장하지 않았습니다 (ë®ì–´ì“°ë ¤ë©´ ! ë”하"
+"기)"
+
+msgid "E948: Job still running (add ! to end the job)"
+msgstr "E948: Jobì´ ì•„ì§ ì‹¤í–‰ì¤‘ìž…ë‹ˆë‹¤ (ë내려면 ë§ˆì§€ë§‰ì— !ì„ ì¶”ê°€)"
+
+msgid "E37: No write since last change (add ! to override)"
+msgstr "E37: 마지막으로 고친 ë’¤ 저장ë˜ì§€ 않았습니다 (무시하려면 ! ë”하기)"
+
+msgid "E948: Job still running"
+msgstr "E948: Jobì´ ì•„ì§ ì‹¤í–‰ì¤‘ìž…ë‹ˆë‹¤"
+
+msgid "E37: No write since last change"
+msgstr "E37: 마지막으로 고친 뒤 저장하지 않았습니다"
+
+msgid "W14: Warning: List of file names overflow"
+msgstr "W14: 경고: íŒŒì¼ ì´ë¦„ 목ë¡ì´ 넘쳤습니다"
+
+#, c-format
+msgid "E92: Buffer %ld not found"
+msgstr "E92: ë²„í¼ %ldì„(를) ì°¾ì„ ìˆ˜ 없습니다"
+
+#, c-format
+msgid "E93: More than one match for %s"
+msgstr "E93: %sì„(를) 하나 ì´ìƒ 찾았습니다"
+
+#, c-format
+msgid "E94: No matching buffer for %s"
+msgstr "E94: %s와 맞는 버í¼ê°€ 없습니다"
+
+#, c-format
+msgid "line %ld"
+msgstr "%ld 줄"
+
+msgid "E95: Buffer with this name already exists"
+msgstr "E95: ì´ ì´ë¦„ì„ ê°€ì§„ 버í¼ê°€ ì´ë¯¸ 있습니다"
+
+msgid " [Modified]"
+msgstr " [바뀜]"
+
+msgid "[Not edited]"
+msgstr "[고치지 않았ìŒ]"
+
+msgid "[New file]"
+msgstr "[새 파ì¼]"
+
+msgid "[Read errors]"
+msgstr "[ì½ê¸° ì—러]"
+
+msgid "[RO]"
+msgstr "[ì½ê¸° ì „ìš©]"
+
+msgid "[readonly]"
+msgstr "[ì½ê¸° ì „ìš©]"
+
+#, c-format
+msgid "1 line --%d%%--"
+msgstr "1 줄 --%d%%--"
+
+#, c-format
+msgid "%ld lines --%d%%--"
+msgstr "%ld 줄 --%d%%--"
+
+#, c-format
+msgid "line %ld of %ld --%d%%-- col "
+msgstr "%ld / %ld 줄 --%d%%-- 칸 "
+
+msgid "[No Name]"
+msgstr "[ì´ë¦„ ì—†ìŒ]"
+
+msgid "help"
+msgstr "ë„움ë§"
+
+msgid "[Help]"
+msgstr "[ë„움ë§]"
+
+msgid "[Preview]"
+msgstr "[미리 보기]"
+
+msgid "All"
+msgstr "모ë‘"
+
+msgid "Bot"
+msgstr "바닥"
+
+msgid "Top"
+msgstr "꼭대기"
+
+msgid ""
+"\n"
+"# Buffer list:\n"
+msgstr ""
+"\n"
+"# ë²„í¼ ëª©ë¡:\n"
+
+msgid "E382: Cannot write, 'buftype' option is set"
+msgstr "E382: 쓸 수 ì—†ìŒ, 'buftype' ì˜µì…˜ì´ ì„¤ì •ë˜ì–´ 있습니다"
+
+msgid "[Prompt]"
+msgstr "[Prompt]"
+
+msgid "[Scratch]"
+msgstr "[Scratch]"
+
+msgid ""
+"\n"
+"--- Signs ---"
+msgstr ""
+"\n"
+"--- 기호 ---"
+
+#, c-format
+msgid "Signs for %s:"
+msgstr "%sì— ëŒ€í•œ 기호:"
+
+#, c-format
+msgid " line=%ld id=%d name=%s"
+msgstr " 줄=%ld id=%d ì´ë¦„=%s"
+
+msgid "E902: Cannot connect to port"
+msgstr "E902: í¬íŠ¸ë¡œ ì—°ê²°í•  수 없습니다"
+
+msgid "E901: gethostbyname() in channel_open()"
+msgstr "E901: channel_open()ì—ì„œ gethostbyname()"
+
+msgid "E898: socket() in channel_open()"
+msgstr "E898: channel_open()ì—ì„œ socket()"
+
+msgid "E903: received command with non-string argument"
+msgstr "E903: 문ìžì—´ì´ ì•„ë‹Œ ì¸ìžë¥¼ 명령으로 수신했습니다"
+
+msgid "E904: last argument for expr/call must be a number"
+msgstr "E904: expr/callì˜ ë§ˆì§€ë§‰ ì¸ìžëŠ” 숫ìžì—¬ì•¼ 합니다"
+
+msgid "E904: third argument for call must be a list"
+msgstr "E904: 3번째 ì¸ìžëŠ” list여야 합니다"
+
+#, c-format
+msgid "E905: received unknown command: %s"
+msgstr "E905: 모르는 명령 수신: %s"
+
+#, c-format
+msgid "E630: %s(): write while not connected"
+msgstr "E630: %s(): ì—°ê²°ë˜ì§€ 않았는 ë° ì“°ê¸°"
+
+#, c-format
+msgid "E631: %s(): write failed"
+msgstr "E631: %s(): 쓰기가 실패했습니다"
+
+#, c-format
+msgid "E917: Cannot use a callback with %s()"
+msgstr "E917: %s()ì—는 callbackì„ ì‚¬ìš©í•  수 없습니다"
+
+msgid "E912: cannot use ch_evalexpr()/ch_sendexpr() with a raw or nl channel"
+msgstr ""
+"E912: raw í˜¹ì€ nl 채ë„ì—ì„œ ch_evalexpr()/ch_sendexpr()ì„ ì‚¬ìš©í•  수 없습니다"
+
+msgid "E906: not an open channel"
+msgstr "E906: 열린 채ë„ì´ ì•„ë‹™ë‹ˆë‹¤"
+
+msgid "E920: _io file requires _name to be set"
+msgstr "E920: _io 파ì¼ì€ 설정하려면 _nameì´ í•„ìš”í•©ë‹ˆë‹¤"
+
+msgid "E915: in_io buffer requires in_buf or in_name to be set"
+msgstr "E915: in_io 버í¼ëŠ” 설정하려면 in_buf나 in_nameì´ í•„ìš”í•©ë‹ˆë‹¤"
+
+#, c-format
+msgid "E918: buffer must be loaded: %s"
+msgstr "E918: 버í¼ê°€ 로딩ë˜ì–´ì•¼ 합니다: %s"
+
+msgid "E821: File is encrypted with unknown method"
+msgstr "E821: 파ì¼ì´ 모르는 방법으로 암호화ë˜ì–´ 있습니다"
+
+msgid "Warning: Using a weak encryption method; see :help 'cm'"
+msgstr "경고: 약한 암호 ë°©ì‹ì„ 사용중; :help 'cm'ì„ í™•ì¸í•˜ì„¸ìš”"
+
+msgid "Enter encryption key: "
+msgstr "암호 키 입력: "
+
+msgid "Enter same key again: "
+msgstr "ê°™ì€ í‚¤ë¥¼ 다시 ìž…ë ¥: "
+
+msgid "Keys don't match!"
+msgstr "키가 맞지 않습니다!"
+
+msgid "[crypted]"
+msgstr "[암호화 ë˜ì—ˆìŠµë‹ˆë‹¤]"
+
+#, c-format
+msgid "E720: Missing colon in Dictionary: %s"
+msgstr "E720: Dictionaryì— ì½œë¡  누ë½: %s"
+
+#, c-format
+msgid "E721: Duplicate key in Dictionary: \"%s\""
+msgstr "E721: Dictionaryì— ì¤‘ë³µëœ í‚¤: \"%s\""
+
+#, c-format
+msgid "E722: Missing comma in Dictionary: %s"
+msgstr "E722: Dictionaryì— ì½¤ë§ˆ 누ë½: %s"
+
+#, c-format
+msgid "E723: Missing end of Dictionary '}': %s"
+msgstr "E723: Dictionary ëì— '}' 누ë½: %s"
+
+msgid "extend() argument"
+msgstr "extend() ì¸ìž"
+
+#, c-format
+msgid "E737: Key already exists: %s"
+msgstr "E737: 키가 ì´ë¯¸ 존재함: %s"
+
+#, c-format
+msgid "E96: Cannot diff more than %ld buffers"
+msgstr "E96: 버í¼ë¥¼ %ldê°œ ì´ìƒì€ 비êµí•  수 없습니다"
+
+msgid "E810: Cannot read or write temp files"
+msgstr "E810: ìž„ì‹œ 파ì¼ì„ ì½ê±°ë‚˜ 쓸 수 없습니다"
+
+msgid "E97: Cannot create diffs"
+msgstr "E97: diff를 만들 수 없습니다"
+
+msgid "Patch file"
+msgstr "패키 파ì¼"
+
+msgid "E816: Cannot read patch output"
+msgstr "E816: patch 결과를 ì½ì„ 수 없습니다"
+
+msgid "E98: Cannot read diff output"
+msgstr "E98: diff ì¶œë ¥ì„ ì½ì„ 수 없습니다"
+
+msgid "E99: Current buffer is not in diff mode"
+msgstr "E99: 현재 버í¼ëŠ” diff ìƒíƒœê°€ 아닙니다"
+
+msgid "E793: No other buffer in diff mode is modifiable"
+msgstr "E793: 수정 가능한 diff ìƒíƒœ 버í¼ëŠ” 없습니다"
+
+msgid "E100: No other buffer in diff mode"
+msgstr "E100: 다른 버í¼ì¤‘ì— diff ìƒíƒœì¸ 게 없습니다"
+
+msgid "E101: More than two buffers in diff mode, don't know which one to use"
+msgstr ""
+"E101: ë‘ê°œ ì´ìƒì˜ 버í¼ê°€ diff ìƒíƒœì—¬ì„œ ì–´ë–¤ ê²ƒì„ ì¨ì•¼í•  지 ì•Œ 수 없습니다"
+
+#, c-format
+msgid "E102: Can't find buffer \"%s\""
+msgstr "E102: \"%s\" 버í¼ë¥¼ ì°¾ì„ ìˆ˜ 없습니다"
+
+#, c-format
+msgid "E103: Buffer \"%s\" is not in diff mode"
+msgstr "E103: \"%s\" 버í¼ëŠ” diff ìƒíƒœê°€ 아닙니다"
+
+msgid "E787: Buffer changed unexpectedly"
+msgstr "E787: 버í¼ê°€ 모르는 사ì´ì— 바뀌었습니다"
+
+msgid "E104: Escape not allowed in digraph"
+msgstr "E104: digraphì—는 Escapeì„ ì“¸ 수 없습니다"
+
+msgid "E544: Keymap file not found"
+msgstr "E544: 키맵 파ì¼ì„ ì°¾ì„ ìˆ˜ 없습니다"
+
+msgid "E105: Using :loadkeymap not in a sourced file"
+msgstr "E105: ë¶ˆëŸ¬ë“¤ì¸ íŒŒì¼ì—ì„œ :loadkeymapì„ ì‚¬ìš©í•˜ì§€ 않았습니다"
+
+msgid "E791: Empty keymap entry"
+msgstr "E791: 키맵 엔트리가 비어있ìŒ"
+
+msgid " Keyword completion (^N^P)"
+msgstr " ë‚±ë§ ì™„ì„± (^N^P)"
+
+msgid " ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+msgstr " ^X 모드 (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+
+msgid " Whole line completion (^L^N^P)"
+msgstr " 전체 줄 완성 (^L^N^P)"
+
+msgid " File name completion (^F^N^P)"
+msgstr " íŒŒì¼ ì´ë¦„ 완성 (^F^N^P)"
+
+msgid " Tag completion (^]^N^P)"
+msgstr " 태그 완성 (^]^N^P)"
+
+msgid " Path pattern completion (^N^P)"
+msgstr " 경로 패턴 완성 (^N^P)"
+
+msgid " Definition completion (^D^N^P)"
+msgstr " ì •ì˜ ì™„ì„± (^D^N^P)"
+
+msgid " Dictionary completion (^K^N^P)"
+msgstr " Dictionary 완성 (^K^N^P)"
+
+msgid " Thesaurus completion (^T^N^P)"
+msgstr " 백과사전 완성 (^T^N^P)"
+
+msgid " Command-line completion (^V^N^P)"
+msgstr " 명령행 완성 (^V^N^P)"
+
+msgid " User defined completion (^U^N^P)"
+msgstr " ì‚¬ìš©ìž ì •ì˜ ì™„ì„± (^U^N^P)"
+
+msgid " Omni completion (^O^N^P)"
+msgstr " Omni 완성 (^O^N^P)"
+
+msgid " Spelling suggestion (s^N^P)"
+msgstr " 단어 제안 (s^N^P)"
+
+msgid " Keyword Local completion (^N^P)"
+msgstr " ë‚±ë§ ë¡œì»¬ 완성 (^N^P)"
+
+msgid "Hit end of paragraph"
+msgstr "단ë½ì˜ 마지막 만남"
+
+msgid "E839: Completion function changed window"
+msgstr "E839: Completion ê¸°ëŠ¥ì´ ì°½ì„ ë°”ê¾¸ì—ˆìŠµë‹ˆë‹¤"
+
+msgid "E840: Completion function deleted text"
+msgstr "E840: Completion ê¸°ëŠ¥ì´ ë¬¸ìžì—´ì„ 지웠습니다"
+
+msgid "'dictionary' option is empty"
+msgstr "'dictionary' ì˜µì…˜ì´ ë¹„ì—ˆìŠµë‹ˆë‹¤"
+
+msgid "'thesaurus' option is empty"
+msgstr "'thesaurus' ì˜µì…˜ì´ ë¹„ì—ˆìŠµë‹ˆë‹¤"
+
+#, c-format
+msgid "Scanning dictionary: %s"
+msgstr "사전 찾는 중: %s"
+
+msgid " (insert) Scroll (^E/^Y)"
+msgstr " (ë¼ì›Œë„£ê¸°) 스í¬ë¡¤ (^E/^Y)"
+
+msgid " (replace) Scroll (^E/^Y)"
+msgstr " (바꿈) 스í¬ë¡¤ (^E/^Y)"
+
+#, c-format
+msgid "Scanning: %s"
+msgstr "찾는 중: %s"
+
+msgid "Scanning tags."
+msgstr "태그 찾는 중."
+
+msgid "match in file"
+msgstr "match in file"
+
+msgid " Adding"
+msgstr " ë”하기"
+
+msgid "-- Searching..."
+msgstr "-- 찾는 중..."
+
+msgid "Back at original"
+msgstr "ì›ëž˜ëŒ€ë¡œ 복구"
+
+msgid "Word from other line"
+msgstr "다른 ì¤„ì— ë‚±ë§"
+
+msgid "The only match"
+msgstr "The only match"
+
+#, c-format
+msgid "match %d of %d"
+msgstr "match %d of %d"
+
+#, c-format
+msgid "match %d"
+msgstr "match %d"
+
+msgid "E18: Unexpected characters in :let"
+msgstr "E18: ':let'ì— ëª¨ë¥´ëŠ” 글ìž"
+
+#, c-format
+msgid "E121: Undefined variable: %s"
+msgstr "E121: ì •ì˜ ì•ˆ ëœ ë³€ìˆ˜: %s"
+
+msgid "E111: Missing ']'"
+msgstr "E111: ']'ì´ ì—†ìŠµë‹ˆë‹¤"
+
+msgid "E719: Cannot use [:] with a Dictionary"
+msgstr "E719: Dictionaryì— [:]ì„ ì‚¬ìš©í•  수 없습니다"
+
+#, c-format
+msgid "E734: Wrong variable type for %s="
+msgstr "E734: %s=ì— ëŒ€í•œ ìž˜ëª»ëœ ë³€ìˆ˜í˜•"
+
+#, c-format
+msgid "E461: Illegal variable name: %s"
+msgstr "E461: 비정ìƒì ì¸ 변수 명: %s"
+
+msgid "E806: using Float as a String"
+msgstr "E806: Float를 String으로 사용"
+
+msgid "E687: Less targets than List items"
+msgstr "E687: List 항목보다 ì ì€ 대ìƒ"
+
+msgid "E688: More targets than List items"
+msgstr "E688: List 항목보다 ë§Žì€ ëŒ€ìƒ"
+
+msgid "Double ; in list of variables"
+msgstr "변수 목ë¡ì— ì¤‘ë³µëœ ;"
+
+#, c-format
+msgid "E738: Can't list variables for %s"
+msgstr "E738: %s 변수 목ë¡ì„ 나열할 수 없습니다"
+
+msgid "E689: Can only index a List or Dictionary"
+msgstr "E689: List나 Dictionary만 색ì¸í•  수 있습니다"
+
+msgid "E708: [:] must come last"
+msgstr "E708: [:]ì€ ë§ˆì§€ë§‰ì— ìœ„ì¹˜í•´ì•¼ 합니다"
+
+msgid "E709: [:] requires a List value"
+msgstr "E709: [:]ì€ List ê°’ì´ í•„ìš”í•©ë‹ˆë‹¤"
+
+msgid "E710: List value has more items than target"
+msgstr "E710: List ê°’ì´ ëŒ€ìƒë³´ë‹¤ ë§Žì€ í•­ëª©ì„ ê°€ì§€ê³  있습니다"
+
+msgid "E711: List value has not enough items"
+msgstr "E711: List ê°’ì´ ì¶©ë¶„í•œ í•­ëª©ì„ ê°€ì§€ê³  있지 않습니다"
+
+msgid "E690: Missing \"in\" after :for"
+msgstr "E690: :for ë’¤ì— \"in\"ê°€ 없습니다"
+
+#, c-format
+msgid "E108: No such variable: \"%s\""
+msgstr "E108: ì´ëŸ° 변수 ì—†ìŒ: \"%s\""
+
+#, c-format
+msgid "E940: Cannot lock or unlock variable %s"
+msgstr "E940: 변수 %sì„(를) 잠금 í˜¹ì€ í•´ì œí•  수 없습니다"
+
+msgid "E743: variable nested too deep for (un)lock"
+msgstr "E743: 잠금(í•´ì œ)í•˜ê¸°ì— ë³€ìˆ˜ê°€ 너무 ê¹Šì´ ì¤‘ì²©ë˜ì—ˆìŠµë‹ˆë‹¤"
+
+msgid "E109: Missing ':' after '?'"
+msgstr "E109: '?' ë’¤ì— ':'ì´ ì—†ìŠµë‹ˆë‹¤"
+
+msgid "E804: Cannot use '%' with Float"
+msgstr "E804: Floatì— '%'는 사용할 수 없습니다"
+
+msgid "E110: Missing ')'"
+msgstr "E110: ')'가 없습니다"
+
+msgid "E695: Cannot index a Funcref"
+msgstr "E695: Funcref를 색ì¸í•  수 없습니다"
+
+msgid "E909: Cannot index a special variable"
+msgstr "E909: 특수한 변수는 색ì¸í•  수 없습니다"
+
+#, c-format
+msgid "E112: Option name missing: %s"
+msgstr "E112: 옵션 ì´ë¦„ ì—†ìŒ: %s"
+
+#, c-format
+msgid "E113: Unknown option: %s"
+msgstr "E113: 모르는 옵션: %s"
+
+#, c-format
+msgid "E114: Missing quote: %s"
+msgstr "E114: 따옴표 ì—†ìŒ: %s"
+
+#, c-format
+msgid "E115: Missing quote: %s"
+msgstr "E115: 따옴표 ì—†ìŒ: %s"
+
+msgid "Not enough memory to set references, garbage collection aborted!"
+msgstr "메모리가 부족하여 가비지 ì½œë ‰ì…˜ì´ ì¤‘ë‹¨ë˜ì—ˆìŠµë‹ˆë‹¤!"
+
+msgid "E724: variable nested too deep for displaying"
+msgstr "E724: 변수가 í‘œì‹œí•˜ê¸°ì— ë„ˆë¬´ ê¹Šì´ ì¤‘ì²©ë˜ì—ˆìŠµë‹ˆë‹¤"
+
+msgid "E805: Using a Float as a Number"
+msgstr "E805: Float를 Number로 사용"
+
+msgid "E703: Using a Funcref as a Number"
+msgstr "E703: Funcref를 Number로 사용"
+
+msgid "E745: Using a List as a Number"
+msgstr "E745: List를 Number로 사용"
+
+msgid "E728: Using a Dictionary as a Number"
+msgstr "E728: Dictionary를 Number로 사용"
+
+msgid "E910: Using a Job as a Number"
+msgstr "E910: Jobì„ Numberë¡œ 사용하고 있습니다"
+
+msgid "E913: Using a Channel as a Number"
+msgstr "E913: Channelì„ Numberë¡œ 사용하고 있습니다"
+
+msgid "E891: Using a Funcref as a Float"
+msgstr "E891: Funcref를 Float로 사용하고 있습니다"
+
+msgid "E892: Using a String as a Float"
+msgstr "E892: Stringì„ Floatë¡œ 사용하고 있습니다"
+
+msgid "E893: Using a List as a Float"
+msgstr "E893: List를 Float로 사용하고 있습니다"
+
+msgid "E894: Using a Dictionary as a Float"
+msgstr "E894: Dictionary를 Float로 사용하고 있습니다"
+
+msgid "E907: Using a special value as a Float"
+msgstr "E907: 특수한 ê°’ì„ Floatë¡œ 사용하고 있습니다"
+
+msgid "E911: Using a Job as a Float"
+msgstr "E911: Jobì„ Floatë¡œ 사용하고 있습니다"
+
+msgid "E914: Using a Channel as a Float"
+msgstr "E914: Channelì„ Floatë¡œ 사용하고 있습니다"
+
+msgid "E729: using Funcref as a String"
+msgstr "E729: Funcref를 String으로 사용"
+
+msgid "E730: using List as a String"
+msgstr "E730: List를 String으로 사용"
+
+msgid "E731: using Dictionary as a String"
+msgstr "E731: Dictionary를 String으로 사용"
+
+msgid "E908: using an invalid value as a String"
+msgstr "E908: ìž˜ëª»ëœ ê°’ì„ String으로 사용하고 있습니다"
+
+#, c-format
+msgid "E795: Cannot delete variable %s"
+msgstr "E795: 변수 %s를 삭제할 수 없습니다"
+
+#, c-format
+msgid "E704: Funcref variable name must start with a capital: %s"
+msgstr "E704: Funcref ë³€ìˆ˜ëª…ì€ ëŒ€ë¬¸ìžë¡œ 시작해야 함: %s"
+
+#, c-format
+msgid "E705: Variable name conflicts with existing function: %s"
+msgstr "E705: ë³€ìˆ˜ëª…ì´ ì´ë¯¸ 있는 함수명과 충ëŒ: %s"
+
+#, c-format
+msgid "E741: Value is locked: %s"
+msgstr "E741: ê°’ì´ ìž ê²¨ìžˆìŒ: %s"
+
+msgid "Unknown"
+msgstr "모름"
+
+#, c-format
+msgid "E742: Cannot change value of %s"
+msgstr "E742: %s ê°’ì„ ë°”ê¿€ 수 없습니다"
+
+msgid "E698: variable nested too deep for making a copy"
+msgstr "E698: ë³µì‚¬í•˜ê¸°ì— ë³€ìˆ˜ê°€ 너무 깊게 중첩ë˜ì—ˆìŠµë‹ˆë‹¤"
+
+msgid ""
+"\n"
+"# global variables:\n"
+msgstr ""
+"\n"
+"# 전역 변수:\n"
+
+msgid ""
+"\n"
+"\tLast set from "
+msgstr ""
+"\n"
+"\tLast set from "
+
+msgid "E691: Can only compare List with List"
+msgstr "E691: List는 List와만 비êµí•  수 있습니다"
+
+msgid "E692: Invalid operation for List"
+msgstr "E692: Listì— ëŒ€í•œ ìž˜ëª»ëœ ë™ìž‘"
+
+msgid "E735: Can only compare Dictionary with Dictionary"
+msgstr "E735: Dictionary는 Dictionary와만 비êµí•  수 있습니다"
+
+msgid "E736: Invalid operation for Dictionary"
+msgstr "E736: Dictionaryì— ëŒ€í•œ ìž˜ëª»ëœ ë™ìž‘"
+
+msgid "E694: Invalid operation for Funcrefs"
+msgstr "E694: Funcrefsì— ëŒ€í•œ ìž˜ëª»ëœ ë™ìž‘"
+
+msgid "map() argument"
+msgstr "map() ì¸ìž"
+
+msgid "filter() argument"
+msgstr "filter() ì¸ìž"
+
+#, c-format
+msgid "E686: Argument of %s must be a List"
+msgstr "E686: %s ì¸ìžëŠ” Listì´ì–´ì•¼ 합니다"
+
+msgid "E928: String required"
+msgstr "E928: Stringì´ í•„ìš”í•©ë‹ˆë‹¤"
+
+msgid "E808: Number or Float required"
+msgstr "E808: Number í˜¹ì€ Floatê°€ 필요합니다"
+
+msgid "add() argument"
+msgstr "add() ì¸ìž"
+
+msgid "E785: complete() can only be used in Insert mode"
+msgstr "E785: complete()ì€ ìž…ë ¥ 모드ì—서만 ì‚¬ìš©ë  ìˆ˜ 있습니다"
+
+msgid "&Ok"
+msgstr "확ì¸(&O)"
+
+#, c-format
+#msgid "+-%s%3ld line: "
+#msgid_plural "+-%s%3ld lines: "
+#msgstr[0] ""
+#msgstr[1] ""
+
+#, c-format
+msgid "E700: Unknown function: %s"
+msgstr "E700: 모르는 함수: %s"
+
+msgid "E922: expected a dict"
+msgstr "E922: dictê°€ 요구ë©ë‹ˆë‹¤"
+
+msgid "E923: Second argument of function() must be a list or a dict"
+msgstr "E923: function()ì˜ ë‘번째 ì¸ìžëŠ” list나 dictì´ì–´ì•¼ 합니다"
+
+msgid ""
+"&OK\n"
+"&Cancel"
+msgstr ""
+"확ì¸(&O)\n"
+"취소(&C)"
+
+msgid "called inputrestore() more often than inputsave()"
+msgstr "inputrestore()ê°€ inputsave()보다 ë§Žì´ ë¶ˆë ¤ì¡ŒìŠµë‹ˆë‹¤"
+
+msgid "insert() argument"
+msgstr "insert() ì¸ìž"
+
+msgid "E786: Range not allowed"
+msgstr "E786: 범위가 허용ë˜ì§€ 않습니다"
+
+msgid "E916: not a valid job"
+msgstr "E916: ì •ìƒì ì¸ jobì´ ì•„ë‹™ë‹ˆë‹¤"
+
+msgid "E701: Invalid type for len()"
+msgstr "E701: len()ì— ìž˜ëª»ëœ í˜•"
+
+#, c-format
+msgid "E798: ID is reserved for \":match\": %ld"
+msgstr "E798: IDê°€ \":match\"ë•Œë¬¸ì— ì˜ˆì•½ë¨: %ld"
+
+msgid "E726: Stride is zero"
+msgstr "E726: Strideê°€ 0"
+
+msgid "E727: Start past end"
+msgstr "E727: 시작위치가 ëì„ ì§€ë‚˜ì¹¨"
+
+msgid "<empty>"
+msgstr "<비어있ìŒ>"
+
+msgid "E240: No connection to the X server"
+msgstr "E240: X ì„œë²„ì— ì—°ê²°ë˜ì–´ 있지 않습니다"
+
+#, c-format
+msgid "E241: Unable to send to %s"
+msgstr "E241: %s(으)로 보낼 수 없습니다"
+
+msgid "E277: Unable to read a server reply"
+msgstr "E277: ì„œë²„ì˜ ì‘ë‹µì„ ì½ì„ 수 없습니다"
+
+msgid "E941: already started a server"
+msgstr "E941: 서버가 ì´ë¯¸ 시작ë˜ì—ˆìŠµë‹ˆë‹¤"
+
+msgid "E942: +clientserver feature not available"
+msgstr "E942: +clientserver ê¸°ëŠ¥ì´ í¬í•¨ë˜ì§€ 않았습니다"
+
+msgid "remove() argument"
+msgstr "remove() ì¸ìž"
+
+msgid "E655: Too many symbolic links (cycle?)"
+msgstr "E655: 너무 ë§Žì€ ì‹¬ë³¼ë¦­ ë§í¬ (반복순환?)"
+
+msgid "reverse() argument"
+msgstr "reverse() ì¸ìž"
+
+msgid "E258: Unable to send to client"
+msgstr "E258: í´ë¼ì´ì–¸íŠ¸ë¡œ 보낼 수 없습니다"
+
+#, c-format
+msgid "E927: Invalid action: '%s'"
+msgstr "E927: 비정ìƒì ì¸ ë™ìž‘: '%s'"
+
+msgid "sort() argument"
+msgstr "sort() ì¸ìž"
+
+msgid "uniq() argument"
+msgstr "uniq() ì¸ìž"
+
+msgid "E702: Sort compare function failed"
+msgstr "E702: ì •ë ¬ ë¹„êµ ê¸°ëŠ¥ì´ ì‹¤íŒ¨í–ˆìŠµë‹ˆë‹¤"
+
+msgid "E882: Uniq compare function failed"
+msgstr "E882: Uniq ë¹„êµ í•¨ìˆ˜ê°€ 실패하였습니다"
+
+msgid "(Invalid)"
+msgstr "(비정ìƒ)"
+
+#, c-format
+msgid "E935: invalid submatch number: %d"
+msgstr "E935: 비정ìƒì ì¸ submatch number: %d"
+
+msgid "E677: Error writing temp file"
+msgstr "E677: ìž„ì‹œ íŒŒì¼ ì“°ê¸° ì—러"
+
+msgid "E921: Invalid callback argument"
+msgstr "E921: 비정ìƒì ì¸ 콜백 ì¸ìž"
+
+msgid "Entering Debug mode. Type \"cont\" to continue."
+msgstr "디버그 ìƒíƒœë¡œ 들어ê°. 계ì†í•˜ë ¤ë©´ \"cont\"를 입력하십시오."
+
+#, c-format
+msgid "Oldval = \"%s\""
+msgstr "ì´ì „ ê°’ = \"%s\""
+
+#, c-format
+msgid "Newval = \"%s\""
+msgstr "새로운 값 = \"%s\""
+
+#, c-format
+msgid "line %ld: %s"
+msgstr "%ld 줄: %s"
+
+#, c-format
+msgid "cmd: %s"
+msgstr "명령: %s"
+
+msgid "frame is zero"
+msgstr "í”„ë ˆìž„ì´ 0"
+
+#, c-format
+msgid "frame at highest level: %d"
+msgstr "í”„ë ˆìž„ì´ ê°€ìž¥ ë†’ì€ ë‹¨ê³„ìž„: %d"
+
+#, c-format
+msgid "Breakpoint in \"%s%s\" line %ld"
+msgstr "중지ì : \"%s%s\" %ld 줄"
+
+#, c-format
+msgid "E161: Breakpoint not found: %s"
+msgstr "E161: 중지ì ì„ ì°¾ì„ ìˆ˜ 없습니다: %s"
+
+msgid "No breakpoints defined"
+msgstr "중지ì ì´ ì •ì˜ë˜ì–´ 있지 않습니다"
+
+#, c-format
+msgid "%3d %s %s line %ld"
+msgstr "%3d %s %s %ld 줄"
+
+#, c-format
+msgid "%3d expr %s"
+msgstr "%3d expr %s"
+
+msgid "E750: First use \":profile start {fname}\""
+msgstr "E750: 먼저 \":profile start {fname}\"ì„ ì‚¬ìš©í•˜ì„¸ìš”"
+
+msgid "Save As"
+msgstr "다른 ì´ë¦„으로 저장"
+
+#, c-format
+msgid "Save changes to \"%s\"?"
+msgstr "\"%s\"ì— ë°”ë€ ë‚´ìš©ì„ ì €ìž¥í• ê¹Œìš”?"
+
+#, c-format
+msgid "E947: Job still running in buffer \"%s\""
+msgstr "E947: Jobì´ ì—¬ì „ížˆ \"%s\" 버í¼ì—ì„œ 실행 중입니다"
+
+#, c-format
+msgid "E162: No write since last change for buffer \"%s\""
+msgstr "E162: ë²„í¼ \"%s\"ì— ë‚˜ì¤‘ì— ë°”ë€ ë‚´ìš©ì´ ì¨ì§€ì§€ 않았습니다"
+
+msgid "Warning: Entered other buffer unexpectedly (check autocommands)"
+msgstr "경고: 뜻 ë°–ì— ë‹¤ë¥¸ 버í¼ë¡œ 들어갔습니다 (autocommand를 확ì¸í•˜ì‹­ì‹œì˜¤)"
+
+msgid "E163: There is only one file to edit"
+msgstr "E163: ê³ ì¹  파ì¼ì´ 하나 ë°–ì— ì—†ìŠµë‹ˆë‹¤"
+
+msgid "E164: Cannot go before first file"
+msgstr "E164: 첫 번째 íŒŒì¼ ì´ì „으로는 ê°ˆ 수 없습니다"
+
+msgid "E165: Cannot go beyond last file"
+msgstr "E165: 마지막 íŒŒì¼ ë’¤ë¡œëŠ” ê°ˆ 수 없습니다"
+
+#, c-format
+msgid "E666: compiler not supported: %s"
+msgstr "E666: 컴파ì¼ëŸ¬ê°€ 지ì›ë˜ì§€ ì•ŠìŒ: %s"
+
+#, c-format
+msgid "Searching for \"%s\" in \"%s\""
+msgstr "\"%s\"ì„(를) \"%s\"ì—ì„œ 찾는 중"
+
+#, c-format
+msgid "Searching for \"%s\""
+msgstr "\"%s\"ì„(를) 찾는 중"
+
+#, c-format
+msgid "not found in '%s': \"%s\""
+msgstr "'%s'ì—ì„œ ì°¾ì„ ìˆ˜ ì—†ìŒ: \"%s\""
+
+#, c-format
+msgid "W20: Required python version 2.x not supported, ignoring file: %s"
+msgstr "W20: 요구ë˜ëŠ” 파ì´ì„  버젼 2.x는 지ì›ë˜ì§€ ì•ŠìŒ, 파ì¼ì„ 무시: %s"
+
+#, c-format
+msgid "W21: Required python version 3.x not supported, ignoring file: %s"
+msgstr "W21: 요구ë˜ëŠ” 파ì´ì„  버젼 3.x는 지ì›ë˜ì§€ ì•ŠìŒ, 파ì¼ì„ 무시: %s"
+
+msgid "Source Vim script"
+msgstr "ë¹” 스í¬ë¦½íŠ¸ 로드"
+
+#, c-format
+msgid "Cannot source a directory: \"%s\""
+msgstr "디렉토리는 sourceí•  수 ì—†ìŒ: \"%s\""
+
+#, c-format
+msgid "could not source \"%s\""
+msgstr "\"%s\"ì„(를) 불러 ë“¤ì¼ ìˆ˜ 없습니다"
+
+#, c-format
+msgid "line %ld: could not source \"%s\""
+msgstr "%ld 줄: \"%s\"ì„(를) 불러 ë“¤ì¼ ìˆ˜ 없습니다"
+
+#, c-format
+msgid "sourcing \"%s\""
+msgstr "\"%s\"ì„(를) 불러들ì´ëŠ” 중"
+
+#, c-format
+msgid "line %ld: sourcing \"%s\""
+msgstr "%ld 줄: \"%s\" 불러들ì´ëŠ” 중"
+
+#, c-format
+msgid "finished sourcing %s"
+msgstr "%s 불러들ì´ê¸° ë"
+
+#, c-format
+msgid "continuing in %s"
+msgstr "%sì—ì„œ 계ì†"
+
+msgid "modeline"
+msgstr "modeline"
+
+msgid "--cmd argument"
+msgstr "--cmd ì¸ìž"
+
+msgid "-c argument"
+msgstr "-c ì¸ìž"
+
+msgid "environment variable"
+msgstr "환경 변수"
+
+msgid "error handler"
+msgstr "ì—러 핸들러"
+
+msgid "W15: Warning: Wrong line separator, ^M may be missing"
+msgstr "W15: 경고: ìž˜ëª»ëœ ì¤„ 구분ìž. ^Mì´ ì—†ëŠ” 것 같습니다"
+
+msgid "E167: :scriptencoding used outside of a sourced file"
+msgstr "E167: :scriptencodingì´ ë¶ˆëŸ¬ë“¤ì¸ íŒŒì¼ ë°–ì—ì„œ 사용ë˜ì—ˆìŠµë‹ˆë‹¤"
+
+msgid "E168: :finish used outside of a sourced file"
+msgstr "E168: :finishê°€ ë¶ˆëŸ¬ë“¤ì¸ íŒŒì¼ ë°–ì—ì„œ 사용ë˜ì—ˆìŠµë‹ˆë‹¤"
+
+#, c-format
+msgid "Current %slanguage: \"%s\""
+msgstr "현재 %s언어: \"%s\""
+
+#, c-format
+msgid "E197: Cannot set language to \"%s\""
+msgstr "E197: 언어를 \"%s\"(으)로 설정할 수 없습니다"
+
+#, c-format
+msgid "<%s>%s%s %d, Hex %02x, Oct %03o, Digr %s"
+msgstr "<%s>%s%s %d, 십육진 %02x, 팔진 %03o, ì´ì¤‘ê¸€ìž %s"
+
+#, c-format
+msgid "<%s>%s%s %d, Hex %02x, Octal %03o"
+msgstr "<%s>%s%s %d, 십육진 %02x, 팔진수 %03o"
+
+#, c-format
+msgid "> %d, Hex %04x, Oct %o, Digr %s"
+msgstr "> %d, 십육진 %04x, 팔진 %o, ì´ì¤‘ê¸€ìž %s"
+
+#, c-format
+msgid "> %d, Hex %08x, Oct %o, Digr %s"
+msgstr "> %d, 십육진 %08x, 팔진 %o, ì´ì¤‘ê¸€ìž %s"
+
+#, c-format
+msgid "> %d, Hex %04x, Octal %o"
+msgstr "> %d, 십육진 %04x, 팔진수 %o"
+
+#, c-format
+msgid "> %d, Hex %08x, Octal %o"
+msgstr "> %d, 십육진 %08x, 팔진수 %o"
+
+msgid "E134: Move lines into themselves"
+msgstr "E134: ì¤„ì„ ê·¸ ìžì‹ ìœ¼ë¡œ ì´ë™í•˜ë ¤ê³  했습니다"
+
+msgid "1 line moved"
+msgstr "1 줄 옮겨졌습니다"
+
+#, c-format
+msgid "%ld lines moved"
+msgstr "%ld 줄 옮겨졌습니다"
+
+#, c-format
+msgid "%ld lines filtered"
+msgstr "%ld ì¤„ì„ ê±¸ë €ìŠµë‹ˆë‹¤"
+
+msgid "E135: *Filter* Autocommands must not change current buffer"
+msgstr "E135: *Filter* ìžë™ëª…ë ¹ì€ í˜„ìž¬ 버í¼ë¥¼ 바꾸어서는 안 ë©ë‹ˆë‹¤"
+
+msgid "[No write since last change]\n"
+msgstr "[마지막으로 고친 뒤 저장 안 함]\n"
+
+#, c-format
+msgid "%sviminfo: %s in line: "
+msgstr "%sviminfo: ì¤„ì— %s: "
+
+msgid "E136: viminfo: Too many errors, skipping rest of file"
+msgstr "E136: viminfo: 너무 ë§Žì€ ì—러, 나머지 건너뜀"
+
+#, c-format
+msgid "Reading viminfo file \"%s\"%s%s%s"
+msgstr "viminfo íŒŒì¼ \"%s\"%s%s%sì„(를) ì½ëŠ” 중"
+
+msgid " info"
+msgstr " ì¸í¬"
+
+msgid " marks"
+msgstr " 마í¬"
+
+msgid " oldfiles"
+msgstr " oldfiles"
+
+msgid " FAILED"
+msgstr " 실패"
+
+#, c-format
+msgid "E137: Viminfo file is not writable: %s"
+msgstr "E137: Viminfo 파ì¼ì˜ 쓰기 ê¶Œí•œì´ ì—†ìŠµë‹ˆë‹¤: %s"
+
+#, c-format
+msgid "E929: Too many viminfo temp files, like %s!"
+msgstr "E929: 너무 ë§Žì€ viminfo ìž„ì‹œ 파ì¼ë“¤, 가령 %s!"
+
+#, c-format
+msgid "E138: Can't write viminfo file %s!"
+msgstr "E138: Viminfo íŒŒì¼ %sì„(를) 쓸 수 없습니다!"
+
+#, c-format
+msgid "Writing viminfo file \"%s\""
+msgstr "Viminfo íŒŒì¼ \"%s\"ì„(를) 쓰는 중"
+
+#, c-format
+msgid "E886: Can't rename viminfo file to %s!"
+msgstr "E886: viminfo 파ì¼ëª…ì„ %s(으)ë¡œ 변경할 수 없습니다!"
+
+#, c-format
+msgid "# This viminfo file was generated by Vim %s.\n"
+msgstr "# ì´ viminfo 파ì¼ì€ ë¹”ì´ ë§Œë“  것입니다 Vim %s.\n"
+
+msgid ""
+"# You may edit it if you're careful!\n"
+"\n"
+msgstr ""
+"# 조심만 한다면 ê³ ì¹  ìˆ˜ë„ ìžˆìŠµë‹ˆë‹¤!\n"
+"\n"
+
+msgid "# Value of 'encoding' when this file was written\n"
+msgstr "# ì´ íŒŒì¼ì´ 저장ë˜ì—ˆì„ ë•Œì˜ 'encoding'ì˜ ê°’\n"
+
+msgid "Illegal starting char"
+msgstr "ì´ìƒí•œ 시작 글ìž"
+
+#~ msgid ""
+#~ "\n"
+#~ "# Bar lines, copied verbatim:\n"
+#~ msgstr ""
+
+msgid "Write partial file?"
+msgstr "íŒŒì¼ ì¼ë¶€ë§Œ 저장할까요?"
+
+msgid "E140: Use ! to write partial buffer"
+msgstr "E140: ë²„í¼ ì¼ë¶€ë§Œ 쓰려면 !ì„ ì‚¬ìš©í•˜ì‹­ì‹œì˜¤"
+
+#, c-format
+msgid "Overwrite existing file \"%s\"?"
+msgstr "ì´ë¯¸ 있는 \"%s\" 파ì¼ì„ ë®ì–´ì“¸ê¹Œìš”?"
+
+#, c-format
+msgid "Swap file \"%s\" exists, overwrite anyway?"
+msgstr "스왑 íŒŒì¼ \"%s\"ê°€ 있습니다, ë®ì–´ì“¸ê¹Œìš”?"
+
+#, c-format
+msgid "E768: Swap file exists: %s (:silent! overrides)"
+msgstr "E768: 스왑 íŒŒì¼ ìžˆìŒ: %s (ë®ì–´ì“°ë ¤ë©´ :silent! 사용)"
+
+#, c-format
+msgid "E141: No file name for buffer %ld"
+msgstr "E141: ë²„í¼ %ldì˜ íŒŒì¼ ì´ë¦„ì´ ì—†ìŠµë‹ˆë‹¤"
+
+msgid "E142: File not written: Writing is disabled by 'write' option"
+msgstr "E142: 파ì¼ì´ ì¨ì§€ì§€ ì•ŠìŒ: 'write' ì˜µì…˜ì— ì˜í•´ 쓸 수가 없습니다"
+
+#, c-format
+msgid ""
+"'readonly' option is set for \"%s\".\n"
+"Do you wish to write anyway?"
+msgstr ""
+"'readonly' ì˜µì…˜ì´ \"%s\"ì— ëŒ€í•´ 설정ë˜ì–´ 있습니다.\n"
+"ê·¸ëž˜ë„ ì“°ê¸°ë¥¼ ì›í•˜ì‹­ë‹ˆê¹Œ?"
+
+#, c-format
+msgid ""
+"File permissions of \"%s\" are read-only.\n"
+"It may still be possible to write it.\n"
+"Do you wish to try?"
+msgstr ""
+"íŒŒì¼ \"%s\"ê°€ ì½ê¸°ì „용입니다.\n"
+"ê·¸ëž˜ë„ ì“°ê¸°ê°€ 가능할 ì§€ë„ ëª¨ë¦…ë‹ˆë‹¤.\n"
+"í•œ 번 ì¨ ë³¼ê¹Œìš”?"
+
+#, c-format
+msgid "E505: \"%s\" is read-only (add ! to override)"
+msgstr "E505: \"%s\"는 ì½ê¸° 전용입니다 (ë®ì–´ì“°ë ¤ë©´ ! ë”하기)"
+
+msgid "Edit File"
+msgstr "íŒŒì¼ ê³ ì¹˜ê¸°"
+
+#, c-format
+msgid "E143: Autocommands unexpectedly deleted new buffer %s"
+msgstr "E143: Autocommandê°€ 뜻 ë°–ì— ìƒˆ ë²„í¼ %sì„(를) 지웠습니다"
+
+msgid "E144: non-numeric argument to :z"
+msgstr "E144: 숫ìžê°€ ì•„ë‹Œ ì¸ìžê°€ :zì— ì£¼ì–´ì¡ŒìŠµë‹ˆë‹¤"
+
+msgid "E145: Shell commands not allowed in rvim"
+msgstr "E145: rvimì—서는 쉘 ëª…ë ¹ì„ ì‚¬ìš©í•  수 없습니다"
+
+msgid "E146: Regular expressions can't be delimited by letters"
+msgstr "E146: 정규표현ì‹ì€ 글ìžë¡œ êµ¬ë¶„ë  ìˆ˜ 없습니다"
+
+#, c-format
+msgid "replace with %s (y/n/a/q/l/^E/^Y)?"
+msgstr "%s(으)로 바꿈 (y/n/a/q/l/^E/^Y)?"
+
+msgid "(Interrupted) "
+msgstr "(중단ë˜ì—ˆìŠµë‹ˆë‹¤) "
+
+msgid "1 match"
+msgstr "1ê°œ 찾아ì§"
+
+msgid "1 substitution"
+msgstr "1ê°œ 바꿨ìŒ"
+
+#, c-format
+msgid "%ld matches"
+msgstr "%ldê°œ 찾아ì§"
+
+#, c-format
+msgid "%ld substitutions"
+msgstr "%ldê°œ 바꿨ìŒ"
+
+msgid " on 1 line"
+msgstr " í•œ 줄ì—ì„œ"
+
+#, c-format
+msgid " on %ld lines"
+msgstr " %ld 줄ì—ì„œ"
+
+msgid "E147: Cannot do :global recursive with a range"
+msgstr "E147: :globalì€ ë²”ìœ„ë¡œ 재귀 호출 ë  ìˆ˜ 없습니다"
+
+msgid "E148: Regular expression missing from global"
+msgstr "E148: globalì—ì„œ 정규표현ì‹ì´ 빠졌습니다"
+
+#, c-format
+msgid "Pattern found in every line: %s"
+msgstr "여러 줄ì—ì„œ íŒ¨í„´ì„ ì°¾ì•˜ìŠµë‹ˆë‹¤: %s"
+
+#, c-format
+msgid "Pattern not found: %s"
+msgstr "íŒ¨í„´ì„ ì°¾ì„ ìˆ˜ ì—†ìŒ: %s"
+
+msgid ""
+"\n"
+"# Last Substitute String:\n"
+"$"
+msgstr ""
+"\n"
+"# 마지막으로 바꾼 문ìžì—´:\n"
+"$"
+
+msgid "E478: Don't panic!"
+msgstr "E478: 당황하지 마십시오!"
+
+#, c-format
+msgid "E661: Sorry, no '%s' help for %s"
+msgstr "E661: 미안합니다, ë„ì›€ë§ '%s'ì´(ê°€) %sì— ëŒ€í•´ 없습니다"
+
+#, c-format
+msgid "E149: Sorry, no help for %s"
+msgstr "E149: 미안합니다, %sì— ëŒ€í•œ ë„움ë§ì´ 없습니다"
+
+#, c-format
+msgid "Sorry, help file \"%s\" not found"
+msgstr "미안합니다, ë„ì›€ë§ íŒŒì¼ \"%s\"ì„(를) ì°¾ì„ ìˆ˜ 없습니다"
+
+#, c-format
+msgid "E151: No match: %s"
+msgstr "E151: 맞지 ì•ŠìŒ: %s"
+
+#, c-format
+msgid "E152: Cannot open %s for writing"
+msgstr "E152: 쓰기 위한 %sì„(를) ì—´ 수 없습니다"
+
+#, c-format
+msgid "E153: Unable to open %s for reading"
+msgstr "E153: ì½ê¸° 위한 %sì„(를) ì—´ 수 없습니다"
+
+#, c-format
+msgid "E670: Mix of help file encodings within a language: %s"
+msgstr "E670: í•œ 언어내ì—ì„œ 여러 ì¸ì½”딩 사용: %s"
+
+#, c-format
+msgid "E154: Duplicate tag \"%s\" in file %s/%s"
+msgstr "E154: \"%s\" 태그가 %s/%s 파ì¼ì—ì„œ 중복ë˜ì—ˆìŠµë‹ˆë‹¤"
+
+#, c-format
+msgid "E150: Not a directory: %s"
+msgstr "E150: 디렉토리가 아님: %s"
+
+#, c-format
+msgid "E160: Unknown sign command: %s"
+msgstr "E160: 모르는 sign 명령: %s"
+
+msgid "E156: Missing sign name"
+msgstr "E156: sign ì´ë¦„ì´ ì—†ìŠµë‹ˆë‹¤"
+
+msgid "E612: Too many signs defined"
+msgstr "E612: 너무 ë§Žì€ signì´ ì •ì˜ë˜ì–´ 있습니다"
+
+#, c-format
+msgid "E239: Invalid sign text: %s"
+msgstr "E239: ìž˜ëª»ëœ sign í…스트: %s"
+
+#, c-format
+msgid "E155: Unknown sign: %s"
+msgstr "E155: 모르는 sign: %s"
+
+msgid "E159: Missing sign number"
+msgstr "E159: sign 번호가 없습니다"
+
+#, c-format
+msgid "E158: Invalid buffer name: %s"
+msgstr "E158: ìž˜ëª»ëœ ë²„í¼ ì´ë¦„: %s"
+
+msgid "E934: Cannot jump to a buffer that does not have a name"
+msgstr "E934: ì´ë¦„없는 버í¼ë¡œëŠ” ì í”„í•  수 없습니다"
+
+#, c-format
+msgid "E157: Invalid sign ID: %ld"
+msgstr "E157: ìž˜ëª»ëœ sign ID: %ld"
+
+#, c-format
+msgid "E885: Not possible to change sign %s"
+msgstr "E885: sign %sì„(를) 바꿀 수 없습니다"
+
+msgid " (NOT FOUND)"
+msgstr " (못 찾았ìŒ)"
+
+msgid " (not supported)"
+msgstr " (지ì›ë˜ì§€ ì•ŠìŒ)"
+
+msgid "[Deleted]"
+msgstr "[지워졌습니다]"
+
+msgid "No old files"
+msgstr "old 파ì¼ì´ 없습니다"
+
+msgid "Entering Ex mode. Type \"visual\" to go to Normal mode."
+msgstr "Ex ìƒíƒœë¡œ 전환. Normal ìƒíƒœë¡œ 가려면 \"visual\"ì„ ìž…ë ¥í•˜ì‹­ì‹œì˜¤."
+
+msgid "E501: At end-of-file"
+msgstr "E501: 파ì¼ì˜ 마지막입니다"
+
+msgid "E169: Command too recursive"
+msgstr "E169: ëª…ë ¹ì´ ë„ˆë¬´ ë§Žì´ ë‹¤ì‹œ 반복ë˜ì—ˆìŠµë‹ˆë‹¤"
+
+#, c-format
+msgid "E605: Exception not caught: %s"
+msgstr "E605: 예외가 ë°œìƒí•˜ì§€ 않았습니다: %s"
+
+msgid "End of sourced file"
+msgstr "ë¶ˆëŸ¬ë“¤ì¸ íŒŒì¼ì˜ 마지막"
+
+msgid "End of function"
+msgstr "í•¨ìˆ˜ì˜ ë§ˆì§€ë§‰"
+
+msgid "E464: Ambiguous use of user-defined command"
+msgstr "E464: ì‚¬ìš©ìž ì •ì˜ ëª…ë ¹ì„ ëª¨í˜¸í•˜ê²Œ 사용하고 있습니다"
+
+msgid "E492: Not an editor command"
+msgstr "E492: 편집기 ëª…ë ¹ì´ ì•„ë‹™ë‹ˆë‹¤"
+
+msgid "E493: Backwards range given"
+msgstr "E493: 반대 ì˜ì—­ì´ 주어졌습니다"
+
+msgid "Backwards range given, OK to swap"
+msgstr "반대 ì˜ì—­ì´ 주어졌습니다, 뒤집ì„까요"
+
+msgid "E494: Use w or w>>"
+msgstr "E494: w나 w>>를 사용하십시오"
+
+msgid "E943: Command table needs to be updated, run 'make cmdidxs'"
+msgstr "E943: 명령 í…Œì´ë¸” ê°±ì‹ ì´ í•„ìš”, 'make cmdidxs'를 실행하세요"
+
+msgid "E319: Sorry, the command is not available in this version"
+msgstr "E319: 미안합니다, ê·¸ ëª…ë ¹ì€ í˜„ìž¬ íŒì—ì„œ 사용할 수 없습니다"
+
+msgid "1 more file to edit. Quit anyway?"
+msgstr "ê³ ì¹  파ì¼ì´ í•œ ê°œ ë” ìžˆìŠµë‹ˆë‹¤. ê·¸ëž˜ë„ ë낼까요?"
+
+#, c-format
+msgid "%d more files to edit. Quit anyway?"
+msgstr "ê³ ì¹  파ì¼ì´ %d ê°œ ë” ìžˆìŠµë‹ˆë‹¤. ê·¸ëž˜ë„ ë낼까요?"
+
+msgid "E173: 1 more file to edit"
+msgstr "E173: ê³ ì¹  파ì¼ì´ í•œ ê°œ ë” ìžˆìŠµë‹ˆë‹¤"
+
+#, c-format
+msgid "E173: %ld more files to edit"
+msgstr "E173: ê³ ì¹  파ì¼ì´ %ld ê°œ ë” ìžˆìŠµë‹ˆë‹¤"
+
+msgid "E174: Command already exists: add ! to replace it"
+msgstr "E174: ëª…ë ¹ì´ ì´ë¯¸ 존재합니다: 바꾸려면 !ì„ ë”하세요"
+
+msgid ""
+"\n"
+" Name Args Address Complete Definition"
+msgstr ""
+"\n"
+" ì´ë¦„ ì¸ìž 주소 완성 ì •ì˜"
+
+msgid "No user-defined commands found"
+msgstr "ì‚¬ìš©ìž ì •ì˜ ëª…ë ¹ì„ ì°¾ì„ ìˆ˜ 없습니다"
+
+msgid "E175: No attribute specified"
+msgstr "E175: ëª…ì‹œëœ ì†ì„±ì´ 없습니다"
+
+msgid "E176: Invalid number of arguments"
+msgstr "E176: ìž˜ëª»ëœ ì¸ìž 갯수"
+
+msgid "E177: Count cannot be specified twice"
+msgstr "E177: 카운트는 ë‘ ë²ˆ ì´ìƒ ëª…ì‹œë  ìˆ˜ 없습니다"
+
+msgid "E178: Invalid default value for count"
+msgstr "E178: ìž˜ëª»ëœ ê¸°ë³¸ 카운트 ê°’"
+
+msgid "E179: argument required for -complete"
+msgstr "E179: -completeì— ì¸ìžê°€ 필요합니다"
+
+msgid "E179: argument required for -addr"
+msgstr "E179: -addrì— ì¸ìžê°€ 필요합니다"
+
+#, c-format
+msgid "E181: Invalid attribute: %s"
+msgstr "E181: ìž˜ëª»ëœ ì†ì„±: %s"
+
+msgid "E182: Invalid command name"
+msgstr "E182: ìž˜ëª»ëœ ëª…ë ¹ ì´ë¦„"
+
+msgid "E183: User defined commands must start with an uppercase letter"
+msgstr "E183: ì‚¬ìš©ìž ì •ì˜ ëª…ë ¹ì€ ëŒ€ë¬¸ìžë¡œ 시작해야 합니다"
+
+msgid "E841: Reserved name, cannot be used for user defined command"
+msgstr "E841: ì˜ˆì•½ëœ ì´ë¦„, ì‚¬ìš©ìž ì •ì˜ ëª…ë ¹ìœ¼ë¡œ ì‚¬ìš©ë  ìˆ˜ 없습니다"
+
+#, c-format
+msgid "E184: No such user-defined command: %s"
+msgstr "E184: 그런 ì‚¬ìš©ìž ì •ì˜ ëª…ë ¹ ì—†ìŒ: %s"
+
+#, c-format
+msgid "E180: Invalid address type value: %s"
+msgstr "E180: ìž˜ëª»ëœ ì£¼ì†Œ í˜•ì‹ ê°’: %s"
+
+#, c-format
+msgid "E180: Invalid complete value: %s"
+msgstr "E180: ìž˜ëª»ëœ ë내기 ê°’: %s"
+
+msgid "E468: Completion argument only allowed for custom completion"
+msgstr "E468: 완성 ì¸ìžëŠ” ì‚¬ìš©ìž ì™„ì„±ì—서만 허용ë©ë‹ˆë‹¤"
+
+msgid "E467: Custom completion requires a function argument"
+msgstr "E467: ì‚¬ìš©ìž ì™„ì„±ì€ í•¨ìˆ˜ ì¸ìžê°€ 필요합니다"
+
+msgid "unknown"
+msgstr "모름"
+
+#, c-format
+msgid "E185: Cannot find color scheme '%s'"
+msgstr "E185: 색 스킴 %sì„(를) ì°¾ì„ ìˆ˜ 없습니다"
+
+msgid "Greetings, Vim user!"
+msgstr "ë¹” 사용ìžë‹˜, 환ì˜í•©ë‹ˆë‹¤!"
+
+msgid "E784: Cannot close last tab page"
+msgstr "E784: 마지막 íƒ­ì„ ë‹«ì„ ìˆ˜ 없습니다"
+
+msgid "Already only one tab page"
+msgstr "ì´ë¯¸ í•˜ë‚˜ì˜ íƒ­ë§Œ 있습니다"
+
+msgid "Edit File in new tab page"
+msgstr "새 탭ì—ì„œ íŒŒì¼ ê³ ì¹˜ê¸°"
+
+msgid "Edit File in new window"
+msgstr "새 ì°½ì—ì„œ íŒŒì¼ ê³ ì¹˜ê¸°"
+
+#, c-format
+msgid "Tab page %d"
+msgstr "탭 페ì´ì§€ %d"
+
+msgid "No swap file"
+msgstr "스왑 파ì¼ì´ 없습니다"
+
+msgid "Append File"
+msgstr "íŒŒì¼ ì¶”ê°€"
+
+msgid "E747: Cannot change directory, buffer is modified (add ! to override)"
+msgstr "E747: 디렉토리를 바꿀 수 없는 ë°, 버í¼ëŠ” ìˆ˜ì •ë¨ (ë®ì–´ì“°ë ¤ë©´ ! ë”하기)"
+
+msgid "E186: No previous directory"
+msgstr "E186: ì´ì „ 디렉토리가 없습니다"
+
+msgid "E187: Unknown"
+msgstr "E187: 모름"
+
+msgid "E465: :winsize requires two number arguments"
+msgstr "E465: :winsize는 ë‘ê°œì˜ ì¸ìžê°€ 필요합니다"
+
+#, c-format
+msgid "Window position: X %d, Y %d"
+msgstr "창 위치: X %d, Y %d"
+
+msgid "E188: Obtaining window position not implemented for this platform"
+msgstr "E188: ì´ í”Œëž«í¼ì— 대한 ì°½ 위치 얻는 ê¸°ëŠ¥ì„ êµ¬í˜„ë˜ì§€ 않았습니다"
+
+msgid "E466: :winpos requires two number arguments"
+msgstr "E466: :winposì—는 ë‘ê°œì˜ ì¸ìžê°€ 필요합니다"
+
+msgid "E930: Cannot use :redir inside execute()"
+msgstr "E930: execute() ë‚´ì—ì„œ :redirì„ ì‚¬ìš©í•  수 없습니다"
+
+msgid "Save Redirection"
+msgstr "리디렉션 저장"
+
+msgid "Save View"
+msgstr "보기 저장"
+
+msgid "Save Session"
+msgstr "세션 저장"
+
+msgid "Save Setup"
+msgstr "설정 저장"
+
+#, c-format
+msgid "E739: Cannot create directory: %s"
+msgstr "E739: 디렉토리 ìƒì„± 실패: %s"
+
+#, c-format
+msgid "E189: \"%s\" exists (add ! to override)"
+msgstr "E189: \"%s\"ì´(ê°€) 존재합니다 (ë®ì–´ì“°ë ¤ë©´ ! ë”하기)"
+
+#, c-format
+msgid "E190: Cannot open \"%s\" for writing"
+msgstr "E190: 쓰기 위한 \"%s\"ì„(를) ì—´ 수 없습니다"
+
+msgid "E191: Argument must be a letter or forward/backward quote"
+msgstr "E191: ì¸ìžëŠ” 글ìžë‚˜ ì•ž/ë’¤ ì¸ìš© 부호여야 합니다"
+
+msgid "E192: Recursive use of :normal too deep"
+msgstr "E192: :normalì˜ ìž¬ê·€ í˜¸ì¶œì´ ë„ˆë¬´ ë§Žì´ ìƒê²¼ìŠµë‹ˆë‹¤"
+
+msgid "E809: #< is not available without the +eval feature"
+msgstr "E809: #<는 +eval ê¸°ëŠ¥ì´ í¬í•¨ë˜ì–´ì•¼ 사용할 수 있습니다"
+
+msgid "E194: No alternate file name to substitute for '#'"
+msgstr "E194: '#'ì— ëŒ€í•´ 치환할 êµì²´ íŒŒì¼ ì´ë¦„ì´ ì—†ìŠµë‹ˆë‹¤"
+
+msgid "E495: no autocommand file name to substitute for \"<afile>\""
+msgstr "E495: \"<afile>\"ì— ëŒ€í•´ 치환할 ìžë™ëª…ë ¹ íŒŒì¼ ì´ë¦„ì´ ì—†ìŠµë‹ˆë‹¤"
+
+msgid "E496: no autocommand buffer number to substitute for \"<abuf>\""
+msgstr "E496: \"<abuf>\"ì— ëŒ€í•´ 치환할 ìžë™ëª…ë ¹ ë²„í¼ ë²ˆí˜¸ê°€ 없습니다"
+
+msgid "E497: no autocommand match name to substitute for \"<amatch>\""
+msgstr "E497: \"<amatch>\"ì— ëŒ€í•´ 치환할 ìžë™ëª…ë ¹ 매치 ì´ë¦„ì´ ì—†ìŠµë‹ˆë‹¤"
+
+msgid "E498: no :source file name to substitute for \"<sfile>\""
+msgstr "E498: \"<sfile>\"ì— ëŒ€í•´ 치환할 :source íŒŒì¼ ì´ë¦„ì´ ì—†ìŠµë‹ˆë‹¤"
+
+msgid "E842: no line number to use for \"<slnum>\""
+msgstr "E842: \"<slnum>\"ì— ì‚¬ìš©ë  ì¤„ 번호가 없습니다"
+
+#, no-c-format
+msgid "E499: Empty file name for '%' or '#', only works with \":p:h\""
+msgstr "E499: '%'나 '#'ì— ëŒ€í•œ 빈 íŒŒì¼ ì´ë¦„, 오로지 \":p:h\"와만 ë™ìž‘합니다"
+
+msgid "E500: Evaluates to an empty string"
+msgstr "E500: 빈 문ìžì—´ì—ì„œ ê°’ì„ êµ¬í•˜ë ¤ê³  합니다"
+
+msgid "E195: Cannot open viminfo file for reading"
+msgstr "E195: ì½ì„ viminfo 파ì¼ì„ ì—´ 수 없습니다"
+
+msgid "Untitled"
+msgstr "제목 ì—†ìŒ"
+
+msgid "E196: No digraphs in this version"
+msgstr "E196: ì´ íŒì—는 digraphê°€ 없습니다"
+
+msgid "E608: Cannot :throw exceptions with 'Vim' prefix"
+msgstr "E608: 'Vim' ì ‘ë‘사로 예외를 :throwí•  수 없습니다"
+
+#, c-format
+msgid "Exception thrown: %s"
+msgstr "예외 thrown: %s"
+
+#, c-format
+msgid "Exception finished: %s"
+msgstr "예외 종료ë¨: %s"
+
+#, c-format
+msgid "Exception discarded: %s"
+msgstr "예외 버려ì§: %s"
+
+#, c-format
+msgid "%s, line %ld"
+msgstr "%s, %ld 줄"
+
+#, c-format
+msgid "Exception caught: %s"
+msgstr "예외 ë°œìƒ: %s"
+
+#, c-format
+msgid "%s made pending"
+msgstr "%sì´(ê°€) pending ë˜ì—ˆìŠµë‹ˆë‹¤"
+
+#, c-format
+msgid "%s resumed"
+msgstr "%sì´(ê°€) 재개 ë˜ì—ˆìŠµë‹ˆë‹¤"
+
+#, c-format
+msgid "%s discarded"
+msgstr "%sì´(ê°€) 버려졌습니다"
+
+msgid "Exception"
+msgstr "예외"
+
+msgid "Error and interrupt"
+msgstr "ì—러와 ì¸í„°ëŸ½íŠ¸"
+
+msgid "Error"
+msgstr "ì—러"
+
+msgid "Interrupt"
+msgstr "ì¸í„°ëŸ½íŠ¸"
+
+msgid "E579: :if nesting too deep"
+msgstr "E579: :ifê°€ 너무 깊게 중첩ë˜ì—ˆìŠµë‹ˆë‹¤"
+
+msgid "E580: :endif without :if"
+msgstr "E580: :ifì—†ì´ :endifê°€ 있습니다"
+
+msgid "E581: :else without :if"
+msgstr "E581: :ifì—†ì´ :elseê°€ 있습니다"
+
+msgid "E582: :elseif without :if"
+msgstr "E582: :ifì—†ì´ :elseifê°€ 있습니다"
+
+msgid "E583: multiple :else"
+msgstr "E583: ì—¬ëŸ¬ê°œì˜ :elseê°€ 있습니다"
+
+msgid "E584: :elseif after :else"
+msgstr "E584: :else ë’¤ì— :elseifê°€ 있습니다"
+
+msgid "E585: :while/:for nesting too deep"
+msgstr "E585: :while/:forê°€ 너무 깊게 중첩ë˜ì—ˆìŠµë‹ˆë‹¤"
+
+msgid "E586: :continue without :while or :for"
+msgstr "E586: :while í˜¹ì€ :forì—†ì´ :continueê°€ 있습니다"
+
+msgid "E587: :break without :while or :for"
+msgstr "E587: :while í˜¹ì€ :forì—†ì´ :breakê°€ 있습니다"
+
+msgid "E732: Using :endfor with :while"
+msgstr "E732: :whileì— :endforê°€ 사용ë˜ì—ˆìŠµë‹ˆë‹¤"
+
+msgid "E733: Using :endwhile with :for"
+msgstr "E733: :forì— :endwhileì´ ì‚¬ìš©ë˜ì—ˆìŠµë‹ˆë‹¤"
+
+msgid "E601: :try nesting too deep"
+msgstr "E601: :tryê°€ 너무 깊게 중첩ë˜ì—ˆìŠµë‹ˆë‹¤"
+
+msgid "E603: :catch without :try"
+msgstr "E603: :tryì—†ì´ :catchê°€ 있습니다"
+
+msgid "E604: :catch after :finally"
+msgstr "E604: :finally ë’¤ì— :catchê°€ 있습니다"
+
+msgid "E606: :finally without :try"
+msgstr "E606: :tryì—†ì´ :finallyê°€ 있습니다"
+
+msgid "E607: multiple :finally"
+msgstr "E607: ì—¬ëŸ¬ê°œì˜ :finallyê°€ 있습니다"
+
+msgid "E602: :endtry without :try"
+msgstr "E602: :tryì—†ì´ :endtryê°€ 있습니다"
+
+msgid "E193: :endfunction not inside a function"
+msgstr "E193: :endfunctionì´ function ë‚´ì— ì—†ìŠµë‹ˆë‹¤"
+
+msgid "E788: Not allowed to edit another buffer now"
+msgstr "E788: ì§€ê¸ˆì€ ë‹¤ë¥¸ 버í¼ë¥¼ 편집할 수 없습니다"
+
+msgid "E811: Not allowed to change buffer information now"
+msgstr "E811: ì§€ê¸ˆì€ ë²„í¼ ì •ë³´ë¥¼ 바꿀 수 없습니다"
+
+msgid "tagname"
+msgstr "태그ì´ë¦„"
+
+msgid " kind file\n"
+msgstr " kind file\n"
+
+msgid "'history' option is zero"
+msgstr "'history' ì˜µì…˜ì´ 0입니다"
+
+#, c-format
+msgid ""
+"\n"
+"# %s History (newest to oldest):\n"
+msgstr ""
+"\n"
+"# %s 히스토리 (새것부터 ì˜¤ëž˜ëœ ê²ƒ 순):\n"
+
+msgid "Command Line"
+msgstr "명령 행"
+
+msgid "Search String"
+msgstr "ì°¾ì„ ë¬¸ìžì—´"
+
+msgid "Expression"
+msgstr "표현"
+
+msgid "Input Line"
+msgstr "ìž…ë ¥ í–‰"
+
+msgid "Debug Line"
+msgstr "디버그 행"
+
+msgid "E198: cmd_pchar beyond the command length"
+msgstr "E198: cmd_pcharê°€ 명령 길ì´ë¥¼ 벗어났습니다"
+
+msgid "E199: Active window or buffer deleted"
+msgstr "E199: í™œì„±ëœ ì°½ì´ë‚˜ 버í¼ê°€ 지워졌습니다"
+
+msgid "E812: Autocommands changed buffer or buffer name"
+msgstr "E812: Autocommandê°€ 버í¼ë‚˜ 버í¼ì´ë¦„ì„ ë°”ê¾¸ì—ˆìŠµë‹ˆë‹¤"
+
+msgid "Illegal file name"
+msgstr "ìž˜ëª»ëœ íŒŒì¼ ì´ë¦„"
+
+msgid "is a directory"
+msgstr "ì€(는) 디렉토리입니다"
+
+msgid "is not a file"
+msgstr "ì€(는) 파ì¼ì´ 아닙니다"
+
+msgid "is a device (disabled with 'opendevice' option)"
+msgstr "ì€(는) 장치가 아닙니다 ('opendevice' 옵션으로 막힘)"
+
+msgid "[New File]"
+msgstr "[새 파ì¼]"
+
+msgid "[New DIRECTORY]"
+msgstr "[새 디렉토리]"
+
+msgid "[File too big]"
+msgstr "[파ì¼ì´ 너무 í¼]"
+
+msgid "[Permission Denied]"
+msgstr "[허용 안 ë©ë‹ˆë‹¤]"
+
+msgid "E200: *ReadPre autocommands made the file unreadable"
+msgstr "E200: *ReadPre ìžë™ëª…ë ¹ì´ íŒŒì¼ì„ ì½ì§€ 못하게 만들었습니다"
+
+msgid "E201: *ReadPre autocommands must not change current buffer"
+msgstr "E201: *ReadPre ìžë™ëª…ë ¹ì€ í˜„ìž¬ 버í¼ë¥¼ 바꾸면 안 ë©ë‹ˆë‹¤"
+
+msgid "Vim: Reading from stdin...\n"
+msgstr "ë¹”: 표준입력ì—ì„œ ì½ëŠ” 중...\n"
+
+msgid "Reading from stdin..."
+msgstr "표준입력ì—ì„œ ì½ëŠ” 중..."
+
+msgid "E202: Conversion made file unreadable!"
+msgstr "E202: ë³€í™˜ëœ íŒŒì¼ì„ ì½ì„ 수가 없습니다!"
+
+msgid "[fifo/socket]"
+msgstr "[피í¬/소켓]"
+
+msgid "[fifo]"
+msgstr "[피í¬]"
+
+msgid "[socket]"
+msgstr "[소켓]"
+
+#~ msgid "[character special]"
+#~ msgstr ""
+
+msgid "[CR missing]"
+msgstr "[CR ì—†ìŒ]"
+
+msgid "[long lines split]"
+msgstr "[긴 줄 잘림]"
+
+msgid "[NOT converted]"
+msgstr "[변환 안 ë©ë‹ˆë‹¤]"
+
+msgid "[converted]"
+msgstr "[변환 ë˜ì—ˆìŠµë‹ˆë‹¤]"
+
+#, c-format
+msgid "[CONVERSION ERROR in line %ld]"
+msgstr "[%ld 줄ì—ì„œ 변환 ì—러]"
+
+#, c-format
+msgid "[ILLEGAL BYTE in line %ld]"
+msgstr "[%ld ì¤„ì— ìž˜ëª»ëœ ë°”ì´íŠ¸]"
+
+msgid "[READ ERRORS]"
+msgstr "[ì½ê¸° ì—러]"
+
+msgid "Can't find temp file for conversion"
+msgstr "변환하기 위한 ìž„ì‹œ 파ì¼ì„ ì°¾ì„ ìˆ˜ 없습니다"
+
+msgid "Conversion with 'charconvert' failed"
+msgstr "'charconvert'를 사용한 ë³€í™˜ì´ ì‹¤íŒ¨í–ˆìŠµë‹ˆë‹¤"
+
+msgid "can't read output of 'charconvert'"
+msgstr "'charconvert'ì˜ ì¶œë ¥ê²°ê³¼ë¥¼ ì½ì„ 수 없습니다"
+
+msgid "E676: No matching autocommands for acwrite buffer"
+msgstr "E676: acwrite 버í¼ì— 대한 autocommand를 ì°¾ì„ ìˆ˜ 없습니다"
+
+msgid "E203: Autocommands deleted or unloaded buffer to be written"
+msgstr "E203: 쓸 버í¼ë¥¼ ìžë™ëª…ë ¹ì´ ì§€ìš°ê±°ë‚˜ 닫았습니다"
+
+msgid "E204: Autocommand changed number of lines in unexpected way"
+msgstr "E204: Autocommandê°€ ìž˜ëª»ëœ ë°©ë²•ìœ¼ë¡œ ì¤„ì„ ë°”ê¾¸ì—ˆìŠµë‹ˆë‹¤"
+
+msgid "NetBeans disallows writes of unmodified buffers"
+msgstr "NetBeansì—서는 바뀌지 ì•Šì€ ë²„í¼ë¥¼ 쓸 수 없습니다"
+
+msgid "Partial writes disallowed for NetBeans buffers"
+msgstr "NetBeans 버í¼ì— 대해서는 부분 ì €ìž¥ì„ í•  수 없습니다"
+
+msgid "is not a file or writable device"
+msgstr "íŒŒì¼ í˜¹ì€ ì“¸ 수 있는 장치가 아닙니다"
+
+msgid "writing to device disabled with 'opendevice' option"
+msgstr "장치 쓰기가 'opendevice' 옵션으로 막힘"
+
+msgid "is read-only (add ! to override)"
+msgstr "ì½ê¸° 전용입니다 (ë®ì–´ì“°ë ¤ë©´ ! ë”하기)"
+
+msgid "E506: Can't write to backup file (add ! to override)"
+msgstr "E506: 백업파ì¼ì„ 쓸 수 없습니다 (ë®ì–´ì“°ë ¤ë©´ ! ë”하기)"
+
+msgid "E507: Close error for backup file (add ! to override)"
+msgstr "E507: ë°±ì—…íŒŒì¼ ë‹«ê¸° ì—러 (ë®ì–´ì“°ë ¤ë©´ ! ë”하기)"
+
+msgid "E508: Can't read file for backup (add ! to override)"
+msgstr "E508: 백업할 파ì¼ì„ ì½ì„ 수 없습니다 (ë®ì–´ì“°ë ¤ë©´ ! ë”하기)"
+
+msgid "E509: Cannot create backup file (add ! to override)"
+msgstr "E509: 백업파ì¼ì„ 만들 수 없습니다 (ë®ì–´ì“°ë ¤ë©´ ! ë”하기)"
+
+msgid "E510: Can't make backup file (add ! to override)"
+msgstr "E510: 백업파ì¼ì„ 만들 수 없습니다 (ë®ì–´ì“°ë ¤ë©´ ! ë”하기)"
+
+msgid "E214: Can't find temp file for writing"
+msgstr "E214: 쓸 ìž„ì‹œ 파ì¼ì„ ì°¾ì„ ìˆ˜ 없습니다"
+
+msgid "E213: Cannot convert (add ! to write without conversion)"
+msgstr "E213: 변환할 수 없습니다 (변환 ì—†ì´ ì €ìž¥í•˜ë ¤ë©´ ! ë”하기)"
+
+msgid "E166: Can't open linked file for writing"
+msgstr "E166: 쓸 ì—°ê²°ëœ íŒŒì¼ì„ ì—´ 수 없습니다"
+
+msgid "E212: Can't open file for writing"
+msgstr "E212: 쓸 파ì¼ì„ ì—´ 수 없습니다"
+
+msgid "E949: File changed while writing"
+msgstr "E949: 쓰는 ì¤‘ì— íŒŒì¼ì´ 변경ë˜ì—ˆìŠµë‹ˆë‹¤"
+
+msgid "E512: Close failed"
+msgstr "E512: 닫기가 실패했습니다"
+
+msgid "E513: write error, conversion failed (make 'fenc' empty to override)"
+msgstr "E513: 쓰기 ì—러, 변환 실패 (무시하려면 'fenc'를 비우면 ë¨)"
+
+#, c-format
+msgid ""
+"E513: write error, conversion failed in line %ld (make 'fenc' empty to "
+"override)"
+msgstr "E513: 쓰기 ì—러, %ld 줄ì—ì„œ 변환 실패 (무시하려면 'fenc'를 비우면 ë¨)"
+
+msgid "E514: write error (file system full?)"
+msgstr "E514: 쓰기 ì—러 (íŒŒì¼ ì‹œìŠ¤í…œì´ ê½‰ì°¼ë‚˜ìš”?)"
+
+msgid " CONVERSION ERROR"
+msgstr " 변환 ì—러"
+
+#, c-format
+msgid " in line %ld;"
+msgstr "%ld 줄ì—ì„œ;"
+
+msgid "[Device]"
+msgstr "[장치]"
+
+msgid "[New]"
+msgstr "[새로운]"
+
+msgid " [a]"
+msgstr " [a]"
+
+msgid " appended"
+msgstr " ë”했습니다"
+
+msgid " [w]"
+msgstr " [w]"
+
+msgid " written"
+msgstr " 저장 했습니다"
+
+msgid "E205: Patchmode: can't save original file"
+msgstr "E205: 패치 ìƒíƒœ: ì›ëž˜ 파ì¼ì„ 저장할 수 없습니다"
+
+msgid "E206: patchmode: can't touch empty original file"
+msgstr "E206: 패치 ìƒíƒœ: 빈 ì›ëž˜ 파ì¼ì„ 만들 수 없습니다"
+
+msgid "E207: Can't delete backup file"
+msgstr "E207: 백업 파ì¼ì„ 지울 수 없습니다"
+
+msgid ""
+"\n"
+"WARNING: Original file may be lost or damaged\n"
+msgstr ""
+"\n"
+"경고: ì›ëž˜ 파ì¼ì´ 없어졌거나 ê¹¨ì¡Œì„ ìˆ˜ 있습니다\n"
+
+msgid "don't quit the editor until the file is successfully written!"
+msgstr "파ì¼ì´ 성공ì ìœ¼ë¡œ ì €ìž¥ë  ë•Œê¹Œì§€ 편집기를 ë내지 마십시오!"
+
+msgid "[dos]"
+msgstr "[ë„스]"
+
+msgid "[dos format]"
+msgstr "[ë„스 형ì‹]"
+
+msgid "[mac]"
+msgstr "[맥]"
+
+msgid "[mac format]"
+msgstr "[맥 형ì‹]"
+
+msgid "[unix]"
+msgstr "[유닉스]"
+
+msgid "[unix format]"
+msgstr "[유닉스 형ì‹]"
+
+msgid "1 line, "
+msgstr "1 줄, "
+
+#, c-format
+msgid "%ld lines, "
+msgstr "%ld 줄, "
+
+msgid "1 character"
+msgstr "1 글ìž"
+
+#, c-format
+msgid "%lld characters"
+msgstr "%lld 글ìž"
+
+msgid "[noeol]"
+msgstr "[noeol]"
+
+msgid "[Incomplete last line]"
+msgstr "[불완전한 마지막 줄]"
+
+msgid "WARNING: The file has been changed since reading it!!!"
+msgstr "경고: 파ì¼ì´ ì½ì€ ë’¤ì— ë°”ë€Œì—ˆìŠµë‹ˆë‹¤!!!"
+
+msgid "Do you really want to write to it"
+msgstr "ì •ë§ë¡œ 쓰기를 ì›í•˜ì‹­ë‹ˆê¹Œ"
+
+#, c-format
+msgid "E208: Error writing to \"%s\""
+msgstr "E208: \"%s\"ì— ì“°ê¸° ì—러"
+
+#, c-format
+msgid "E209: Error closing \"%s\""
+msgstr "E209: \"%s\" 닫기 ì—러"
+
+#, c-format
+msgid "E210: Error reading \"%s\""
+msgstr "E210: \"%s\" ì½ê¸° ì—러"
+
+msgid "E246: FileChangedShell autocommand deleted buffer"
+msgstr "E246: FileChangedShell ìžë™ëª…ë ¹ì´ ë²„í¼ë¥¼ 지웠습니다"
+
+#, c-format
+msgid "E211: File \"%s\" no longer available"
+msgstr "E211: íŒŒì¼ \"%s\"ì„(를) ë” ì´ìƒ 사용할 수 없습니다"
+
+#, c-format
+msgid ""
+"W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as "
+"well"
+msgstr ""
+"W12: 경고: íŒŒì¼ \"%s\"ì´(ê°€) 바뀌었고 마찬가지로 ë¹”ì˜ ë²„í¼ë„ 바뀌었습니다"
+
+msgid "See \":help W12\" for more info."
+msgstr "ë” ë§Žì€ ì •ë³´ë¥¼ 보려면 \":help W12\"ì„ ìž…ë ¥í•˜ì„¸ìš”."
+
+#, c-format
+msgid "W11: Warning: File \"%s\" has changed since editing started"
+msgstr "W11: 경고: íŒŒì¼ \"%s\"ì´(ê°€) 고치기 시작한 ë’¤ì— ë°”ë€Œì—ˆìŠµë‹ˆë‹¤"
+
+msgid "See \":help W11\" for more info."
+msgstr "ë” ë§Žì€ ì •ë³´ë¥¼ 보려면 \":help W11\"ì„ ìž…ë ¥í•˜ì„¸ìš”."
+
+#, c-format
+msgid "W16: Warning: Mode of file \"%s\" has changed since editing started"
+msgstr "W16: 경고: íŒŒì¼ \"%s\"ì˜ ìƒíƒœê°€ 고치기 시작한 ë’¤ì— ë°”ë€Œì—ˆìŠµë‹ˆë‹¤"
+
+msgid "See \":help W16\" for more info."
+msgstr "ë” ë§Žì€ ì •ë³´ë¥¼ 보려면 \":help W16\"ì„ ìž…ë ¥í•˜ì„¸ìš”."
+
+#, c-format
+msgid "W13: Warning: File \"%s\" has been created after editing started"
+msgstr "W13: 경고: íŒŒì¼ \"%s\"ì´(ê°€) 고치기 시작한 ë’¤ì— ë§Œë“¤ì—ˆìŠµë‹ˆë‹¤"
+
+msgid "Warning"
+msgstr "경고"
+
+msgid ""
+"&OK\n"
+"&Load File"
+msgstr ""
+"확ì¸(&O)\n"
+"íŒŒì¼ ë¶ˆëŸ¬ì˜¤ê¸°(&L)"
+
+#, c-format
+msgid "E462: Could not prepare for reloading \"%s\""
+msgstr "E462: \"%s\"ì˜ ìž¬ë¡œë“œë¥¼ 준비할 수 없습니다"
+
+#, c-format
+msgid "E321: Could not reload \"%s\""
+msgstr "E321: \"%s\"ì„(를) 다시 로드할 수 없습니다"
+
+msgid "--Deleted--"
+msgstr "--지워ì§--"
+
+#, c-format
+msgid "auto-removing autocommand: %s <buffer=%d>"
+msgstr "autocommand ìžë™ì‚­ì œ: %s <buffer=%d>"
+
+#, c-format
+msgid "E367: No such group: \"%s\""
+msgstr "E367: ì´ëŸ° 그룹 ì—†ìŒ: \"%s\""
+
+msgid "E936: Cannot delete the current group"
+msgstr "E936: 현재 ê·¸ë£¹ì„ ì‚­ì œí•  수 없습니다"
+
+msgid "W19: Deleting augroup that is still in use"
+msgstr "W19: ì‚¬ìš©ì¤‘ì¸ augroupì„ ì‚­ì œí•˜ë ¤ê³  합니다"
+
+#, c-format
+msgid "E215: Illegal character after *: %s"
+msgstr "E215: * ë’¤ì— ì´ìƒí•œ 글ìž: %s"
+
+#, c-format
+msgid "E216: No such event: %s"
+msgstr "E216: 그런 ì´ë²¤íŠ¸ ì—†ìŒ: %s"
+
+#, c-format
+msgid "E216: No such group or event: %s"
+msgstr "E216: 그런 그룹ì´ë‚˜ ì´ë²¤íŠ¸ ì—†ìŒ: %s"
+
+msgid ""
+"\n"
+"--- Autocommands ---"
+msgstr ""
+"\n"
+"--- ìžë™-명령 ---"
+
+#, c-format
+msgid "E680: <buffer=%d>: invalid buffer number "
+msgstr "E680: <buffer=%d>: ìž˜ëª»ëœ ë²„í¼ ë²ˆí˜¸"
+
+msgid "E217: Can't execute autocommands for ALL events"
+msgstr "E217: ALL ì´ë²¤íŠ¸ì— 대해 ìžë™ëª…ë ¹ì„ ì‹¤í–‰í•  수 없습니다"
+
+msgid "No matching autocommands"
+msgstr "맞는 ìžë™ëª…ë ¹ì´ ì—†ìŠµë‹ˆë‹¤"
+
+msgid "E218: autocommand nesting too deep"
+msgstr "E218: ìžë™ëª…ë ¹ì´ ë„ˆë¬´ 깊게 중첩ë˜ì—ˆìŠµë‹ˆë‹¤"
+
+#, c-format
+#~ msgid "%s Autocommands for \"%s\""
+#~ msgstr ""
+
+#, c-format
+msgid "Executing %s"
+msgstr "%s 실행중"
+
+#, c-format
+msgid "autocommand %s"
+msgstr "ìžë™ëª…ë ¹ %s"
+
+msgid "E219: Missing {."
+msgstr "E219: {가 없습니다."
+
+msgid "E220: Missing }."
+msgstr "E220: }가 없습니다."
+
+msgid "E490: No fold found"
+msgstr "E490: fold가 없습니다"
+
+msgid "E350: Cannot create fold with current 'foldmethod'"
+msgstr "E350: í˜„ìž¬ì˜ 'foldmethod'으로 접기를 만들 수 없습니다"
+
+msgid "E351: Cannot delete fold with current 'foldmethod'"
+msgstr "E351: í˜„ìž¬ì˜ 'foldmethod'으로 접기를 지울 수 없습니다"
+
+#, c-format
+msgid "+--%3ld line folded "
+msgid_plural "+--%3ld lines folded "
+msgstr[0] "+-%3ld ì¤„ì´ ì ‘í˜”ìŠµë‹ˆë‹¤"
+msgstr[1] "+-%3ld ì¤„ë“¤ì´ ì ‘í˜”ìŠµë‹ˆë‹¤"
+
+msgid "E222: Add to read buffer"
+msgstr "E222: ì½í˜€ì§„ 버í¼ì— ë”하기"
+
+msgid "E223: recursive mapping"
+msgstr "E223: 재귀 맵핑"
+
+#, c-format
+msgid "E224: global abbreviation already exists for %s"
+msgstr "E224: %s ì „ì—­ 약어가 ì´ë¯¸ 존재합니다"
+
+#, c-format
+msgid "E225: global mapping already exists for %s"
+msgstr "E225: %s ì „ì—­ ë§¤í•‘ì´ ì´ë¯¸ 존재합니다"
+
+#, c-format
+msgid "E226: abbreviation already exists for %s"
+msgstr "E226: %s 약어가 ì´ë¯¸ 존재합니다"
+
+#, c-format
+msgid "E227: mapping already exists for %s"
+msgstr "E227: %s ë§¤í•‘ì´ ì´ë¯¸ 존재합니다"
+
+msgid "No abbreviation found"
+msgstr "약어를 ì°¾ì„ ìˆ˜ 없습니다"
+
+msgid "No mapping found"
+msgstr "ë§µí•‘ì„ ì°¾ì„ ìˆ˜ 없습니다"
+
+msgid "E228: makemap: Illegal mode"
+msgstr "E228: makemap: ì´ìƒí•œ ìƒíƒœ"
+
+msgid "<cannot open> "
+msgstr "<ì—´ 수 ì—†ìŒ> "
+
+#, c-format
+msgid "E616: vim_SelFile: can't get font %s"
+msgstr "E616: vim_SelFile: 글꼴 %sì„(를) ì–»ì„ ìˆ˜ 없습니다"
+
+msgid "E614: vim_SelFile: can't return to current directory"
+msgstr "E614: vim_SelFile: 현재 디렉토리로 ëŒì•„ê°ˆ 수 없습니다"
+
+msgid "Pathname:"
+msgstr "경로 ì´ë¦„:"
+
+msgid "E615: vim_SelFile: can't get current directory"
+msgstr "E615: vim_SelFile: 현재 디렉토리를 ì–»ì„ ìˆ˜ 없습니다"
+
+msgid "OK"
+msgstr "확ì¸"
+
+msgid "Cancel"
+msgstr "취소"
+
+msgid "Vim dialog"
+msgstr "ë¹” 대화ìƒìž"
+
+msgid "Scrollbar Widget: Could not get geometry of thumb pixmap."
+msgstr "스í¬ë¡¤ë°” 위젯: ì¸ í”½ìŠ¤ë§µì˜ ì§€ì˜¤ë¯¸íŠ¸ë¦¬ë¥¼ ì–»ì„ ìˆ˜ 없습니다."
+
+msgid "E232: Cannot create BalloonEval with both message and callback"
+msgstr "E232: 메시지와 콜백 모ë‘를 사용해서는 BalloonEvalì„ ë§Œë“¤ 수 없습니다"
+
+msgid "E851: Failed to create a new process for the GUI"
+msgstr "E851: 새로운 GUI 프로세스를 ìƒì„±í•  수 없습니다"
+
+msgid "E852: The child process failed to start the GUI"
+msgstr "E852: ìžì‹ 프로세스가 GUI를 시작하지 못했습니다"
+
+msgid "E229: Cannot start the GUI"
+msgstr "E229: GUI를 시작할 수 없습니다"
+
+#, c-format
+msgid "E230: Cannot read from \"%s\""
+msgstr "E230: \"%s\"ì—ì„œ ì½ì„ 수 없습니다"
+
+msgid "E665: Cannot start GUI, no valid font found"
+msgstr "E665: 쓸만한 ê¸€ê¼´ì„ ì°¾ì„ ìˆ˜ 없어서 GUI를 실행할 수 없습니다"
+
+msgid "E231: 'guifontwide' invalid"
+msgstr "E231: 'guifontwide'ê°€ ì´ìƒí•©ë‹ˆë‹¤"
+
+msgid "E599: Value of 'imactivatekey' is invalid"
+msgstr "E599: 'imactivatekey' ê°’ì´ ì´ìƒí•©ë‹ˆë‹¤"
+
+#, c-format
+msgid "E254: Cannot allocate color %s"
+msgstr "E254: 색 %sì„(를) 할당할 수 없습니다"
+
+#~ msgid "No match at cursor, finding next"
+#~ msgstr ""
+
+msgid "_Cancel"
+msgstr "취소(_C)"
+
+msgid "_Save"
+msgstr "저장(_S)"
+
+msgid "_Open"
+msgstr "열기(_O)"
+
+msgid "_OK"
+msgstr "확ì¸(_O)"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"&Cancel"
+msgstr ""
+"예(&Y)\n"
+"아니오(&N)\n"
+"취소(&C)"
+
+msgid "Yes"
+msgstr "예"
+
+msgid "No"
+msgstr "아니오"
+
+msgid "Input _Methods"
+msgstr "입력 방법(_M)"
+
+msgid "VIM - Search and Replace..."
+msgstr "빔 - 찾아서 바꾸기..."
+
+msgid "VIM - Search..."
+msgstr "빔 - 찾기..."
+
+msgid "Find what:"
+msgstr "무얼 ì°¾ì„까요:"
+
+msgid "Replace with:"
+msgstr "바꿀 문ìžì—´:"
+
+msgid "Match whole word only"
+msgstr "ë˜‘ê°™ì€ ë‚±ë§ë§Œ"
+
+#~ msgid "Match case"
+#~ msgstr ""
+
+msgid "Direction"
+msgstr "ë°©í–¥"
+
+msgid "Up"
+msgstr "위로"
+
+msgid "Down"
+msgstr "아래로"
+
+msgid "Find Next"
+msgstr "ë‹¤ìŒ ì°¾ê¸°"
+
+msgid "Replace"
+msgstr "바꾸기"
+
+msgid "Replace All"
+msgstr "ëª¨ë‘ ë°”ê¾¸ê¸°"
+
+msgid "_Close"
+msgstr "닫기(_C)"
+
+msgid "Vim: Received \"die\" request from session manager\n"
+msgstr "ë¹”: 세션 관리ìžë¡œë¶€í„° \"die\" ìš”ì²­ì„ ë°›ì•˜ìŠµë‹ˆë‹¤\n"
+
+msgid "Close tab"
+msgstr "탭 닫기"
+
+msgid "New tab"
+msgstr "새 탭"
+
+msgid "Open Tab..."
+msgstr "탭 열기..."
+
+msgid "Vim: Main window unexpectedly destroyed\n"
+msgstr "ë¹”: ë©”ì¸ ì°½ì´ ì£½ê²Œ ë  ê²ƒìž…ë‹ˆë‹¤\n"
+
+msgid "&Filter"
+msgstr "거르개(&F)"
+
+msgid "&Cancel"
+msgstr "취소(&C)"
+
+msgid "Directories"
+msgstr "디렉토리"
+
+msgid "Filter"
+msgstr "거르개"
+
+msgid "&Help"
+msgstr "ë„움ë§(&H)"
+
+msgid "Files"
+msgstr "파ì¼"
+
+msgid "&OK"
+msgstr "확ì¸(&O)"
+
+msgid "Selection"
+msgstr "고르기"
+
+msgid "Find &Next"
+msgstr "ë‹¤ìŒ ì°¾ê¸°(&N)"
+
+msgid "&Replace"
+msgstr "바꾸기(&R)"
+
+msgid "Replace &All"
+msgstr "ëª¨ë‘ ë°”ê¾¸ê¸°(&A)"
+
+msgid "&Undo"
+msgstr "취소(&U)"
+
+msgid "Open tab..."
+msgstr "탭 열기..."
+
+msgid "Find string (use '\\\\' to find a '\\')"
+msgstr "문ìžì—´ 찾기 ('\\'를 찾으려면 '\\\\' 사용)"
+
+msgid "Find & Replace (use '\\\\' to find a '\\')"
+msgstr "문ìžì—´ 찾아서 바꾸기 ('\\'를 찾으려면 '\\\\' 사용)"
+
+msgid "Not Used"
+msgstr "사용 ì•Šë¨"
+
+msgid "Directory\t*.nothing\n"
+msgstr "디렉토리\t*.nothing\n"
+
+#, c-format
+msgid "E671: Cannot find window title \"%s\""
+msgstr "E671: ì°½ 제목 \"%s\"ì„(를) ì°¾ì„ ìˆ˜ 없습니다"
+
+#, c-format
+msgid "E243: Argument not supported: \"-%s\"; Use the OLE version."
+msgstr "E243: 지ì›ë˜ì§€ 않는 ì¸ìž: \"-%s\": OLE íŒì„ 사용하십시오."
+
+msgid "E672: Unable to open window inside MDI application"
+msgstr "E672: MDI ì‘용프로그램 안ì—ì„œ ì°½ì„ ì—´ 수 없습니다"
+
+msgid "Vim E458: Cannot allocate colormap entry, some colors may be incorrect"
+msgstr ""
+"ë¹” E458: 색ìƒë§µ 엔트리를 할당할 수 없습니다, 몇몇 ìƒ‰ì´ ìž˜ëª»ë  ìˆ˜ 있습니다"
+
+#, c-format
+msgid "E250: Fonts for the following charsets are missing in fontset %s:"
+msgstr "E250: ë‹¤ìŒ ê¸€ìžì…‹ì˜ ê¸€ê¼´ì´ ê¸€ê¼´ì…‹ %sì— ì—†ìŠµë‹ˆë‹¤:"
+
+#, c-format
+msgid "E252: Fontset name: %s"
+msgstr "E252: 글꼴셋 ì´ë¦„: %s"
+
+#, c-format
+msgid "Font '%s' is not fixed-width"
+msgstr "글꼴 '%s'ì€(는) ê³ ì •ë„“ì´ê°€ 아닙니다"
+
+#, c-format
+msgid "E253: Fontset name: %s"
+msgstr "E253: 글꼴셋 ì´ë¦„: %s"
+
+#, c-format
+msgid "Font0: %s"
+msgstr "글꼴0: %s"
+
+#, c-format
+msgid "Font1: %s"
+msgstr "글꼴1: %s"
+
+#, c-format
+msgid "Font%ld width is not twice that of font0"
+msgstr "글꼴%ld 너비가 글꼴0ì˜ ë‘ë°°ê°€ 아닙니다"
+
+#, c-format
+msgid "Font0 width: %ld"
+msgstr "글꼴0 너비: %ld"
+
+#, c-format
+msgid "Font1 width: %ld"
+msgstr "글꼴1 너비: %ld"
+
+msgid "Invalid font specification"
+msgstr "글꼴 ê·œê²©ì´ ì´ìƒí•©ë‹ˆë‹¤"
+
+msgid "&Dismiss"
+msgstr "취소(&D)"
+
+#~ msgid "no specific match"
+#~ msgstr ""
+
+msgid "Vim - Font Selector"
+msgstr "Vim - 글꼴 ì„ íƒê¸°"
+
+msgid "Name:"
+msgstr "ì´ë¦„:"
+
+#~ msgid "Show size in Points"
+#~ msgstr ""
+
+msgid "Encoding:"
+msgstr "ì¸ì½”딩:"
+
+msgid "Font:"
+msgstr "글꼴:"
+
+msgid "Style:"
+msgstr "스타ì¼:"
+
+msgid "Size:"
+msgstr "í¬ê¸°:"
+
+msgid "E256: Hangul automata ERROR"
+msgstr "E256: 한글 오토마타 ì—러"
+
+msgid "E550: Missing colon"
+msgstr "E550: ì½œë¡ ì´ ì—†ìŠµë‹ˆë‹¤"
+
+msgid "E551: Illegal component"
+msgstr "E551: ì´ìƒí•œ ì»´í¬ë„ŒíŠ¸"
+
+msgid "E552: digit expected"
+msgstr "E552: 숫ìžê°€ 필요합니다"
+
+#, c-format
+msgid "Page %d"
+msgstr "페ì´ì§€ %d"
+
+msgid "No text to be printed"
+msgstr "ì¸ì‡„ë  í…스트가 없습니다"
+
+#, c-format
+msgid "Printing page %d (%d%%)"
+msgstr "페ì´ì§€ %d ì¸ì‡„중 (%d%%)"
+
+#, c-format
+msgid " Copy %d of %d"
+msgstr " 복사 %d / %d"
+
+#, c-format
+msgid "Printed: %s"
+msgstr "ì¸ì‡„ë¨: %s"
+
+msgid "Printing aborted"
+msgstr "ì¸ì‡„ê°€ 취소ë˜ì—ˆìŠµë‹ˆë‹¤."
+
+msgid "E455: Error writing to PostScript output file"
+msgstr "E455: í¬ìŠ¤íŠ¸ìŠ¤í¬ë¦½íŠ¸ 출력파ì¼ì— 쓸 수 없습니다."
+
+#, c-format
+msgid "E624: Can't open file \"%s\""
+msgstr "E624: \"%s\" 파ì¼ì„ ì—´ 수 없습니다"
+
+#, c-format
+msgid "E457: Can't read PostScript resource file \"%s\""
+msgstr "E457: í¬ìŠ¤íŠ¸ìŠ¤í¬ë¦½íŠ¸ 리소스 íŒŒì¼ \"%s\"ì„(를) ì½ì„ 수 없습니다"
+
+#, c-format
+msgid "E618: file \"%s\" is not a PostScript resource file"
+msgstr "E618: íŒŒì¼ \"%s\"ì€(는) í¬ìŠ¤íŠ¸ìŠ¤í¬ë¦½íŠ¸ 리소스 파ì¼ì´ 아닙니다"
+
+#, c-format
+msgid "E619: file \"%s\" is not a supported PostScript resource file"
+msgstr "E619: íŒŒì¼ \"%s\"ì€(는) 지ì›ë˜ëŠ” í¬ìŠ¤íŠ¸ìŠ¤í¬ë¦½íŠ¸ 리소스 파ì¼ì´ 아닙니다"
+
+#, c-format
+msgid "E621: \"%s\" resource file has wrong version"
+msgstr "E621: \"%s\" 리소스 파ì¼ì€ ë²„ì „ì´ ìž˜ëª»ë˜ì—ˆìŠµë‹ˆë‹¤"
+
+msgid "E673: Incompatible multi-byte encoding and character set."
+msgstr "E673: 호환ë˜ì§€ 않는 ë‹¤ì¤‘ë¬¸ìž ì¸ì½”딩과 문ìžì…‹."
+
+msgid "E674: printmbcharset cannot be empty with multi-byte encoding."
+msgstr "E674: printmbcharset는 ë‹¤ì¤‘ë¬¸ìž ì¸ì½”딩ì—ì„œ 반드시 설정ë˜ì–´ì•¼ 합니다."
+
+msgid "E675: No default font specified for multi-byte printing."
+msgstr "E675: ë‹¤ì¤‘ë¬¸ìž ì¸ì‡„를 위한 ê¸€ê¼´ì´ ì„¤ì •ë˜ì–´ 있지 않습니다"
+
+msgid "E324: Can't open PostScript output file"
+msgstr "E324: í¬ìŠ¤íŠ¸ìŠ¤í¬ë¦½íŠ¸ 출력파ì¼ì„ ì—´ 수 없습니다"
+
+#, c-format
+msgid "E456: Can't open file \"%s\""
+msgstr "E456: \"%s\" 파ì¼ì„ ì—´ 수 없습니다"
+
+msgid "E456: Can't find PostScript resource file \"prolog.ps\""
+msgstr "E456: í¬ìŠ¤íŠ¸ìŠ¤í¬ë¦½íŠ¸ 리소스 íŒŒì¼ \"prolog.ps\"를 ì°¾ì„ ìˆ˜ 없습니다"
+
+msgid "E456: Can't find PostScript resource file \"cidfont.ps\""
+msgstr "E456: í¬ìŠ¤íŠ¸ìŠ¤í¬ë¦½íŠ¸ 리소스 íŒŒì¼ \"cidfont.ps\"를 ì°¾ì„ ìˆ˜ 없습니다"
+
+#, c-format
+msgid "E456: Can't find PostScript resource file \"%s.ps\""
+msgstr "E456: í¬ìŠ¤íŠ¸ìŠ¤í¬ë¦½íŠ¸ 리소스 íŒŒì¼ \"%s.ps\"를 ì°¾ì„ ìˆ˜ 없습니다"
+
+#, c-format
+msgid "E620: Unable to convert to print encoding \"%s\""
+msgstr "E620: \"%s\" ì¸ì‡„ ì¸ì½”딩으로 변환할 수 없습니다"
+
+msgid "Sending to printer..."
+msgstr "프린터로 보내는 중..."
+
+msgid "E365: Failed to print PostScript file"
+msgstr "E365: í¬ìŠ¤íŠ¸ìŠ¤í¬ë¦½íŠ¸ 파ì¼ì„ ì¸ì‡„í•  수 없습니다"
+
+msgid "Print job sent."
+msgstr "ì¸ì‡„ìž‘ì—…ì´ ë났습니다."
+
+msgid "Add a new database"
+msgstr "새 ë°ì´í„°ë² ì´ìŠ¤ ë”하기"
+
+#~ msgid "Query for a pattern"
+#~ msgstr ""
+
+msgid "Show this message"
+msgstr "ì´ ë©”ì‹œì§€ ë³´ì´ê¸°"
+
+msgid "Kill a connection"
+msgstr "ì—°ê²° ëŠê¸°"
+
+msgid "Reinit all connections"
+msgstr "모든 연결 다시 초기화"
+
+msgid "Show connections"
+msgstr "연결 보여주기"
+
+#, c-format
+msgid "E560: Usage: cs[cope] %s"
+msgstr "E560: 사용법: cs[cope] %s"
+
+msgid "This cscope command does not support splitting the window.\n"
+msgstr "ì´ cscope ëª…ë ¹ì€ ì°½ 나누기를 지ì›í•˜ì§€ 않습니다.\n"
+
+msgid "E562: Usage: cstag <ident>"
+msgstr "E562: 사용법: cstag <ident>"
+
+msgid "E257: cstag: tag not found"
+msgstr "E257: cstag: 태그를 ì°¾ì„ ìˆ˜ 없습니다"
+
+#, c-format
+msgid "E563: stat(%s) error: %d"
+msgstr "E563: stat(%s) ì—러: %d"
+
+msgid "E563: stat error"
+msgstr "E563: stat ì—러"
+
+#, c-format
+msgid "E564: %s is not a directory or a valid cscope database"
+msgstr "E564: %sì€(는) ë””ë ‰í† ë¦¬ë„ í˜¹ì€ cscope ë°ì´í„°ë² ì´ìŠ¤ê°€ 아닙니다"
+
+#, c-format
+msgid "Added cscope database %s"
+msgstr "cscope ë°ì´í„°ë² ì´ìŠ¤ %sì— ë”했습니다."
+
+#, c-format
+msgid "E262: error reading cscope connection %ld"
+msgstr "E262: cscope ì—°ê²° %ld ì½ê¸° ì—러"
+
+msgid "E561: unknown cscope search type"
+msgstr "E561: 모르는 cscope 찾기 형ì‹"
+
+msgid "E566: Could not create cscope pipes"
+msgstr "E566: cscope 파ì´í”„를 만들 수 없습니다"
+
+msgid "E622: Could not fork for cscope"
+msgstr "E622: cscope를 fork할 수 없습니다"
+
+msgid "cs_create_connection setpgid failed"
+msgstr "cs_create_connection setpgid가 실패했습니다"
+
+msgid "cs_create_connection exec failed"
+msgstr "cs_create_connection ì‹¤í–‰ì´ ì‹¤íŒ¨í–ˆìŠµë‹ˆë‹¤"
+
+msgid "cs_create_connection: fdopen for to_fp failed"
+msgstr "cs_create_connection: to_fpì— ëŒ€í•œ fdopen 실패"
+
+msgid "cs_create_connection: fdopen for fr_fp failed"
+msgstr "cs_create_connection: fr_fpì— ëŒ€í•œ fdopen 실패"
+
+msgid "E623: Could not spawn cscope process"
+msgstr "E623: cscope 프로세스를 spawn할 수 없습니다"
+
+msgid "E567: no cscope connections"
+msgstr "E567: cscope ì—°ê²°ì´ ì—†ìŠµë‹ˆë‹¤"
+
+#, c-format
+#~ msgid "E469: invalid cscopequickfix flag %c for %c"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E259: no matches found for cscope query %s of %s"
+#~ msgstr ""
+
+msgid "cscope commands:\n"
+msgstr "cscope 명령:\n"
+
+#, c-format
+msgid "%-5s: %s%*s (Usage: %s)"
+msgstr "%-5s: %s%*s (사용법: %s)"
+
+msgid ""
+"\n"
+" a: Find assignments to this symbol\n"
+" c: Find functions calling this function\n"
+" d: Find functions called by this function\n"
+" e: Find this egrep pattern\n"
+" f: Find this file\n"
+" g: Find this definition\n"
+" i: Find files #including this file\n"
+" s: Find this C symbol\n"
+" t: Find this text string\n"
+msgstr ""
+"\n"
+" a: ì´ ê¸°í˜¸ì— ëŒ€í•œ 할당 찾기\n"
+" c: ì´ í•¨ìˆ˜ë¥¼ 부르는 함수들 찾기\n"
+" d: ì´ í•¨ìˆ˜ì— ì˜í•´ 불려지는 함수들 찾기\n"
+" e: ì´ egrep 패턴 찾기\n"
+" f: ì´ íŒŒì¼ ì°¾ê¸°\n"
+" g: ì´ ì •ì˜ ì°¾ê¸°\n"
+" i: ì´ íŒŒì¼ì„ #include하는 파ì¼ë“¤ 찾기\n"
+" s: ì´ C 기호 찾기\n"
+" t: ì´ ë¬¸ìžì—´ 찾기\n"
+
+#, c-format
+msgid "E625: cannot open cscope database: %s"
+msgstr "E625: cscope ë°ì´í„°ë² ì´ìŠ¤ë¥¼ ì—´ 수 ì—†ìŒ: %s"
+
+msgid "E626: cannot get cscope database information"
+msgstr "E626: cscope ë°ì´í„°ë² ì´ìŠ¤ 정보를 ì–»ì„ ìˆ˜ 없습니다"
+
+msgid "E568: duplicate cscope database not added"
+msgstr "E568: ì¤‘ë³µëœ cscope ë°ì´í„°ë² ì´ìŠ¤ëŠ” ë”해지지 않았습니다"
+
+#, c-format
+msgid "E261: cscope connection %s not found"
+msgstr "E261: cscope ì—°ê²° %sì„(를) ì°¾ì„ ìˆ˜ 없습니다"
+
+#, c-format
+msgid "cscope connection %s closed"
+msgstr "cscope ì—°ê²° %sì´(ê°€) 닫혔습니다"
+
+msgid "E570: fatal error in cs_manage_matches"
+msgstr "E570: cs_manage_matchesì— ì‹¬ê°í•œ ì—러"
+
+#, c-format
+msgid "Cscope tag: %s"
+msgstr "Cscope 태그: %s"
+
+msgid ""
+"\n"
+" # line"
+msgstr ""
+"\n"
+" # 줄"
+
+msgid "filename / context / line\n"
+msgstr "íŒŒì¼ ì´ë¦„ / 콘í…스트 / 줄\n"
+
+#, c-format
+msgid "E609: Cscope error: %s"
+msgstr "E609: Cscope ì—러: %s"
+
+msgid "All cscope databases reset"
+msgstr "모든 cscope ë°ì´í„°ë² ì´ìŠ¤ 리셋"
+
+msgid "no cscope connections\n"
+msgstr "cscope ì—°ê²°ì´ ì—†ìŠµë‹ˆë‹¤\n"
+
+msgid " # pid database name prepend path\n"
+msgstr " # pid ë°ì´í„°ë² ì´ìŠ¤ ì´ë¦„ prepend path\n"
+
+msgid "Lua library cannot be loaded."
+msgstr "Lua ë¼ì´ë¸ŒëŸ¬ë¦¬ë¥¼ 로딩할 수 없습니다."
+
+msgid "cannot save undo information"
+msgstr "undo 정보를 저장할 수 없습니다"
+
+msgid ""
+"E815: Sorry, this command is disabled, the MzScheme libraries could not be "
+"loaded."
+msgstr ""
+"E815: 미안합니다, ì´ ëª…ë ¹ì€ ì‚¬ìš©í•  수 없습니다, MzScheme ë¼ì´ë¸ŒëŸ¬ë¦¬ë¥¼ 로딩할 "
+"수 없습니다."
+
+msgid ""
+"E895: Sorry, this command is disabled, the MzScheme's racket/base module "
+"could not be loaded."
+msgstr ""
+"E895: 미안합니다, ì´ ëª…ë ¹ì€ ì‚¬ìš©í•  수 없습니다, MzSchemeì˜ racket/base 모듈"
+"ì„ ë¡œë”©í•  수 없습니다."
+
+msgid "invalid expression"
+msgstr "ìž˜ëª»ëœ í‘œí˜„ì‹"
+
+msgid "expressions disabled at compile time"
+msgstr "표현ì‹ì„ 지ì›í•˜ì§€ ì•Šë„ë¡ ì»´íŒŒì¼ ë˜ì—ˆìŠµë‹ˆë‹¤"
+
+msgid "hidden option"
+msgstr "숨김 옵션"
+
+msgid "unknown option"
+msgstr "모르는 옵션"
+
+msgid "window index is out of range"
+msgstr "창 번호가 범위를 벗어났습니다"
+
+msgid "couldn't open buffer"
+msgstr "버í¼ë¥¼ ì—´ 수 없었습니다"
+
+msgid "cannot delete line"
+msgstr "ì¤„ì„ ì§€ìš¸ 수 없습니다"
+
+msgid "cannot replace line"
+msgstr "ì¤„ì„ ë°”ê¿€ 수 없습니다"
+
+msgid "cannot insert line"
+msgstr "ì¤„ì„ ë¼ì›Œë„£ì„ 수 없습니다"
+
+msgid "string cannot contain newlines"
+msgstr "문ìžì—´ì€ newlineì„ í¬í•¨í•  수 없습니다"
+
+#~ msgid "error converting Scheme values to Vim"
+#~ msgstr ""
+
+msgid "Vim error: ~a"
+msgstr "Vim ì—러: ~a"
+
+msgid "Vim error"
+msgstr "Vim ì—러"
+
+msgid "buffer is invalid"
+msgstr "버í¼ê°€ ì´ìƒí•©ë‹ˆë‹¤"
+
+msgid "window is invalid"
+msgstr "ì°½ì´ ì´ìƒí•©ë‹ˆë‹¤"
+
+msgid "linenr out of range"
+msgstr "줄 번호가 범위를 벗어났습니다"
+
+msgid "not allowed in the Vim sandbox"
+msgstr "Vim sandboxì—서는 허용ë˜ì§€ 않습니다"
+
+msgid "E837: This Vim cannot execute :py3 after using :python"
+msgstr "E837: ì´ Vimì€ :pythonì„ ì‚¬ìš©í•œ í›„ì— :py3ì„ ì‚¬ìš©í•  수 없습니다"
+
+msgid ""
+"E263: Sorry, this command is disabled, the Python library could not be "
+"loaded."
+msgstr ""
+"E263: 미안합니다, ì´ ëª…ë ¹ì€ ì‚¬ìš©í•  수 없습니다, 파ì´ì¬ ë¼ì´ë¸ŒëŸ¬ë¦¬ë¥¼ 로딩할 "
+"수 없습니다."
+
+msgid "E836: This Vim cannot execute :python after using :py3"
+msgstr "E836: ì´ Vimì€ :py3ì„ ì‚¬ìš©í•œ í›„ì— :pythonì„ ì‚¬ìš©í•  수 없습니다"
+
+msgid ""
+"E887: Sorry, this command is disabled, the Python's site module could not be "
+"loaded."
+msgstr ""
+"E887: 미안합니다, ì´ ëª…ë ¹ì€ ì‚¬ìš©í•  수 없습니다, 파ì´ì¬ì˜ 사ì´íŠ¸ ëª¨ë“ˆì„ ë¡œë”©"
+"할 수 없습니다."
+
+msgid "E659: Cannot invoke Python recursively"
+msgstr "E659: Pythonì„ ìž¬ê·€í˜¸ì¶œí•  수 없습니다"
+
+msgid "E265: $_ must be an instance of String"
+msgstr "E265: $_는 String ì¸ìŠ¤í„´ìŠ¤ì´ì–´ì•¼ 합니다"
+
+msgid ""
+"E266: Sorry, this command is disabled, the Ruby library could not be loaded."
+msgstr ""
+"E266: 미안합니다, ì´ ëª…ë ¹ì€ ì‚¬ìš©í•  수 없습니다, 루비 ë¼ì´ë¸ŒëŸ¬ë¦¬ë¥¼ 로딩할 수 "
+"없습니다."
+
+msgid "E267: unexpected return"
+msgstr "E267: ëœ»ë°–ì˜ return"
+
+msgid "E268: unexpected next"
+msgstr "E268: ëœ»ë°–ì˜ next"
+
+msgid "E269: unexpected break"
+msgstr "E269: ëœ»ë°–ì˜ break"
+
+msgid "E270: unexpected redo"
+msgstr "E270: ëœ»ë°–ì˜ redo"
+
+#~ msgid "E271: retry outside of rescue clause"
+#~ msgstr ""
+
+msgid "E272: unhandled exception"
+msgstr "E272: ì²˜ë¦¬ì•Šëœ ì˜ˆì™¸"
+
+#, c-format
+msgid "E273: unknown longjmp status %d"
+msgstr "E273: 모르는 longjmp ìƒíƒœ %d"
+
+msgid "invalid buffer number"
+msgstr "ìž˜ëª»ëœ ë²„í¼ ë²ˆí˜¸"
+
+msgid "not implemented yet"
+msgstr "ì•„ì§ êµ¬í˜„ë˜ì§€ 않았습니다"
+
+msgid "cannot set line(s)"
+msgstr "ì¤„ì„ ì„¤ì •í•  수 없습니다"
+
+msgid "invalid mark name"
+msgstr "ìž˜ëª»ëœ ë§ˆí¬ ì´ë¦„"
+
+msgid "mark not set"
+msgstr "마í¬ê°€ 설정ë˜ì§€ 않았습니다"
+
+#, c-format
+msgid "row %d column %d"
+msgstr "í–‰ %d ì—´ %d"
+
+msgid "cannot insert/append line"
+msgstr "ì¤„ì„ ë¼ì›Œë„£ê±°ë‚˜ ë”í•  수 없습니다"
+
+msgid "line number out of range"
+msgstr "줄 번호가 범위를 벗어났습니다"
+
+msgid "unknown flag: "
+msgstr "모르는 플래그: "
+
+msgid "unknown vimOption"
+msgstr "모르는 빔 옵션"
+
+msgid "keyboard interrupt"
+msgstr "키보드 ì¸í„°ëŸ½íŠ¸"
+
+msgid "vim error"
+msgstr "ë¹” ì—러"
+
+msgid "cannot create buffer/window command: object is being deleted"
+msgstr "버í¼/ì°½ ëª…ë ¹ì„ ë§Œë“¤ 수 없습니다: ê°ì²´ê°€ 지워집니다"
+
+msgid ""
+"cannot register callback command: buffer/window is already being deleted"
+msgstr "콜백 ëª…ë ¹ì„ ë“±ë¡í•  수 없습니다: 버í¼/ì°½ì´ ì´ë¯¸ 지워졌습니다"
+
+msgid ""
+"E280: TCL FATAL ERROR: reflist corrupt!? Please report this to vim-dev@vim."
+"org"
+msgstr ""
+"E280: TCL 심ê°í•œ ì—러: reflistê°€ 깨졌나!? ì´ ë¬¸ì œë¥¼ vim-dev@vim.orgë¡œ 알려주"
+"십시오"
+
+msgid "cannot register callback command: buffer/window reference not found"
+msgstr "콜백 ëª…ë ¹ì„ ë“±ë¡í•  수 없습니다: 버í¼/ì°½ 참조를 ì°¾ì„ ìˆ˜ 없습니다"
+
+msgid ""
+"E571: Sorry, this command is disabled: the Tcl library could not be loaded."
+msgstr ""
+"E571: 미안합니다, ì´ ëª…ë ¹ì€ ì‚¬ìš©í•  수 없습니다, Tcl ë¼ì´ë¸ŒëŸ¬ë¦¬ë¥¼ 로딩할 수 ì—†"
+"습니다."
+
+#, c-format
+msgid "E572: exit code %d"
+msgstr "E572: 종료 코드 %d"
+
+msgid "cannot get line"
+msgstr "ì¤„ì„ ì–»ì„ ìˆ˜ 없습니다"
+
+msgid "Unable to register a command server name"
+msgstr "명령 서버 ì´ë¦„ì„ ë“±ë¡í•  수 없습니다"
+
+msgid "E248: Failed to send command to the destination program"
+msgstr "E248: 대ìƒí”„로그램으로 명령 보내기가 실패했습니다"
+
+#, c-format
+msgid "E573: Invalid server id used: %s"
+msgstr "E573: ìž˜ëª»ëœ ì„œë²„ id 사용ë¨: %s"
+
+msgid "E251: VIM instance registry property is badly formed. Deleted!"
+msgstr "E251: ë¹” ì¸ìŠ¤í„´ìŠ¤ 레지스트리 ì†ì„±ì´ 잘못ë˜ì–´ 있습니다. 지웠습니다!"
+
+#, c-format
+msgid "E938: Duplicate key in JSON: \"%s\""
+msgstr "E938: JSONì— ì¤‘ë³µëœ í‚¤: \"%s\""
+
+#, c-format
+msgid "E696: Missing comma in List: %s"
+msgstr "E696: Listì— ì½¤ë§ˆ 누ë½: %s"
+
+#, c-format
+msgid "E697: Missing end of List ']': %s"
+msgstr "E697: List ëì— ']' 누ë½: %s"
+
+msgid "Unknown option argument"
+msgstr "모르는 옵션 ì¸ìž"
+
+msgid "Too many edit arguments"
+msgstr "너무 ë§Žì€ íŽ¸ì§‘ ì¸ìž"
+
+msgid "Argument missing after"
+msgstr "ë’¤ì— ì¸ìžê°€ ì—†ìŒ"
+
+msgid "Garbage after option argument"
+msgstr "옵션 ì¸ìž ë’¤ì— ì“°ë ˆê¸° ê°’"
+
+msgid "Too many \"+command\", \"-c command\" or \"--cmd command\" arguments"
+msgstr "너무 ë§Žì€ \"+command\" \"-c command\" í˜¹ì€ \"--cmd command\" ì¸ìž"
+
+msgid "Invalid argument for"
+msgstr "Invalid argument for"
+
+#, c-format
+msgid "%d files to edit\n"
+msgstr "%d 파ì¼ì„ 고치기\n"
+
+msgid "netbeans is not supported with this GUI\n"
+msgstr "ì´ GUI는 netbeans를 지ì›í•˜ì§€ 않습니다\n"
+
+msgid "'-nb' cannot be used: not enabled at compile time\n"
+msgstr "'-nb'는 사용할 수 ì—†ìŒ: 컴파ì¼í•  ë•Œ í¬í•¨ë˜ì§€ ì•ŠìŒ\n"
+
+msgid "This Vim was not compiled with the diff feature."
+msgstr "ì´ ë¹”ì€ diff 기능 ì—†ì´ ì»´íŒŒì¼ ë˜ì—ˆìŠµë‹ˆë‹¤."
+
+msgid "Attempt to open script file again: \""
+msgstr "스í¬ë¦½íŠ¸ 파ì¼ì„ 다시 열려고 ì‹œë„: \""
+
+msgid "Cannot open for reading: \""
+msgstr "ì½ê¸° 위해 ì—´ 수 ì—†ìŒ: \""
+
+msgid "Cannot open for script output: \""
+msgstr "스í¬ë¦½íŠ¸ ì¶œë ¥ì„ ì—´ 수 ì—†ìŒ: \""
+
+msgid "Vim: Error: Failure to start gvim from NetBeans\n"
+msgstr "Vim: ì—러: NetBeansì—ì„œ gvim 시작 실패\n"
+
+msgid "Vim: Error: This version of Vim does not run in a Cygwin terminal\n"
+msgstr "Vim: ì—러: ì´ ë²„ì ¼ì˜ ë¹”ì€ Cygwin 터미ë„ì—ì„œ 실행할 수 없습니다\n"
+
+msgid "Vim: Warning: Output is not to a terminal\n"
+msgstr "ë¹”: 경고: 터미ë„ë¡œ 출력할 수 없습니다\n"
+
+msgid "Vim: Warning: Input is not from a terminal\n"
+msgstr "ë¹”: 경고: 터미ë„ë¡œ 부터 ìž…ë ¥ë°›ì„ ìˆ˜ 없습니다\n"
+
+msgid "pre-vimrc command line"
+msgstr "pre-vimrc 명령 행"
+
+#, c-format
+msgid "E282: Cannot read from \"%s\""
+msgstr "E282: \"%s\"ì—ì„œ ì½ì„ 수 없습니다"
+
+msgid ""
+"\n"
+"More info with: \"vim -h\"\n"
+msgstr ""
+"\n"
+"ë” ë§Žì€ ì •ë³´ë¥¼ ì›í•˜ì‹œë©´: \"vim -h\"\n"
+
+msgid "[file ..] edit specified file(s)"
+msgstr "[íŒŒì¼ ..] 주어진 íŒŒì¼ ê³ ì¹˜ê¸°"
+
+msgid "- read text from stdin"
+msgstr "- 표준입력ì—ì„œ í…스트 ì½ê¸°"
+
+msgid "-t tag edit file where tag is defined"
+msgstr "-t tag 태그가 ì •ì˜ëœ 위치ì—ì„œ íŒŒì¼ ê³ ì¹˜ê¸°"
+
+msgid "-q [errorfile] edit file with first error"
+msgstr "-q [ì—러파ì¼] 첫 번째 ì—러가 ë‚œ íŒŒì¼ ê³ ì¹˜ê¸°"
+
+msgid ""
+"\n"
+"\n"
+"Usage:"
+msgstr ""
+"\n"
+"\n"
+"사용법:"
+
+msgid " vim [arguments] "
+msgstr " vim [ì¸ìž] "
+
+msgid ""
+"\n"
+" or:"
+msgstr ""
+"\n"
+" 혹ì€:"
+
+#~ msgid ""
+#~ "\n"
+#~ "Where case is ignored prepend / to make flag upper case"
+#~ msgstr ""
+
+msgid ""
+"\n"
+"\n"
+"Arguments:\n"
+msgstr ""
+"\n"
+"\n"
+"ì¸ìž:\n"
+
+msgid "--\t\t\tOnly file names after this"
+msgstr "--\t\t\tì´ ë’¤ì—는 íŒŒì¼ ì´ë¦„만"
+
+msgid "--literal\t\tDon't expand wildcards"
+msgstr "--literal\t\t와ì¼ë“œì¹´ë“œë¥¼ 확장하지 ì•ŠìŒ"
+
+msgid "-register\t\tRegister this gvim for OLE"
+msgstr "-register\t\tì´ gvim OLEì— ë“±ë¡"
+
+msgid "-unregister\t\tUnregister gvim for OLE"
+msgstr "-unregister\t\tgvimì„ OLEì—ì„œ 등ë¡ì·¨ì†Œ"
+
+msgid "-g\t\t\tRun using GUI (like \"gvim\")"
+msgstr "-g\t\t\tGUIë¡œ 실행 (\"gvim\"ê³¼ ê°™ìŒ)"
+
+msgid "-f or --nofork\tForeground: Don't fork when starting GUI"
+msgstr "-f í˜¹ì€ --nofork\tí¬ê·¸ë¼ìš´ë“œ: GUIë¡œ 시작할 ë•Œ fork하지 ë§ ê²ƒ"
+
+msgid "-v\t\t\tVi mode (like \"vi\")"
+msgstr "-v\t\t\tVi 모드 (\"vi\"와 ê°™ìŒ)"
+
+msgid "-e\t\t\tEx mode (like \"ex\")"
+msgstr "-e\t\t\tEx 모드 (\"ex\"와 ê°™ìŒ)"
+
+msgid "-E\t\t\tImproved Ex mode"
+msgstr "-E\t\t\tí–¥ìƒëœ Ex 모드"
+
+msgid "-s\t\t\tSilent (batch) mode (only for \"ex\")"
+msgstr "-s\t\t\t조용한 (배치) 모드 (\"ex\"만)"
+
+msgid "-d\t\t\tDiff mode (like \"vimdiff\")"
+msgstr "-d\t\t\tDiff 모드 (\"vimdiff\"와 ê°™ìŒ)"
+
+msgid "-y\t\t\tEasy mode (like \"evim\", modeless)"
+msgstr "-y\t\t\t쉬운 모드 (\"evim\"ê³¼ ê°™ìŒ, modeless)"
+
+msgid "-R\t\t\tReadonly mode (like \"view\")"
+msgstr "-R\t\t\tì½ê¸° ì „ìš© 모드 (\"view\"와 ê°™ìŒ)"
+
+msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
+msgstr "-Z\t\t\tì œí•œëœ ëª¨ë“œ (\"rvim\"ê³¼ ê°™ìŒ)"
+
+msgid "-m\t\t\tModifications (writing files) not allowed"
+msgstr "-m\t\t\t수정(íŒŒì¼ ì“°ê¸°)ì´ í—ˆìš©ë˜ì§€ ì•ŠìŒ"
+
+msgid "-M\t\t\tModifications in text not allowed"
+msgstr "-M\t\t\tí…스트 ìˆ˜ì •ì´ í—ˆìš©ë˜ì§€ ì•ŠìŒ"
+
+msgid "-b\t\t\tBinary mode"
+msgstr "-b\t\t\tì´ì§„ ìƒíƒœ"
+
+msgid "-l\t\t\tLisp mode"
+msgstr "-l\t\t\t리스프 ìƒíƒœ"
+
+msgid "-C\t\t\tCompatible with Vi: 'compatible'"
+msgstr "-C\t\t\tVi 호환: 'compatible'"
+
+msgid "-N\t\t\tNot fully Vi compatible: 'nocompatible'"
+msgstr "-N\t\t\tVi와 호환ë˜ì§€ ì•ŠìŒ: 'nocompatible'"
+
+msgid "-V[N][fname]\t\tBe verbose [level N] [log messages to fname]"
+msgstr "-V[N][fname]\t\tBe verbose [level N] [fnameì— ë©”ì‹œì§€ 저장]"
+
+msgid "-D\t\t\tDebugging mode"
+msgstr "-D\t\t\t디버깅 모드"
+
+msgid "-n\t\t\tNo swap file, use memory only"
+msgstr "-n\t\t\t스왑 íŒŒì¼ ì—†ì´ ë©”ëª¨ë¦¬ë§Œ 사용"
+
+msgid "-r\t\t\tList swap files and exit"
+msgstr "-r\t\t\t스왑 íŒŒì¼ ëª©ë¡ì„ 표시한 ë’¤ ë내기"
+
+msgid "-r (with file name)\tRecover crashed session"
+msgstr "-r (íŒŒì¼ ì´ë¦„ê³¼ 함께)\t파ì†ë˜ì—ˆë˜ 세션 복구"
+
+msgid "-L\t\t\tSame as -r"
+msgstr "-L\t\t\t-rê³¼ ê°™ìŒ"
+
+msgid "-f\t\t\tDon't use newcli to open window"
+msgstr "-f\t\t\tì°½ì„ ì—´ ë•Œ newcli 사용하지 ì•ŠìŒ"
+
+msgid "-dev <device>\t\tUse <device> for I/O"
+msgstr "-dev <장치>\t\tI/Oì— <장치> 사용"
+
+msgid "-A\t\t\tStart in Arabic mode"
+msgstr "-A\t\t\tArabic 모드로 시작"
+
+msgid "-H\t\t\tStart in Hebrew mode"
+msgstr "-H\t\t\tHebrew 모드로 시작"
+
+msgid "-F\t\t\tStart in Farsi mode"
+msgstr "-F\t\t\tFarsi 모드로 시작"
+
+msgid "-T <terminal>\tSet terminal type to <terminal>"
+msgstr "-T <terminal>\tí„°ë¯¸ë„ ì¢…ë¥˜ë¥¼ <terminal>ë¡œ 설정"
+
+msgid "--not-a-term\t\tSkip warning for input/output not being a terminal"
+msgstr "--not-a-term\t\t터미ë„ì— ìž…ì¶œë ¥í•  수 없다는 경고하지 ì•ŠìŒ"
+
+msgid "--ttyfail\t\tExit if input or output is not a terminal"
+msgstr "--ttyfail\t\t터미ë„ì— ìž…ì¶œë ¥í•  수 없는 경우 종료"
+
+msgid "-u <vimrc>\t\tUse <vimrc> instead of any .vimrc"
+msgstr "-u <vimrc>\t\t.vimrc 대신 <vimrc>를 사용"
+
+msgid "-U <gvimrc>\t\tUse <gvimrc> instead of any .gvimrc"
+msgstr "-U <gvimrc>\t\t.gvimrc 대신 <gvimrc>를 사용"
+
+msgid "--noplugin\t\tDon't load plugin scripts"
+msgstr "--noplugin\t\tí”ŒëŸ¬ê·¸ì¸ ìŠ¤í¬ë¦½íŠ¸ë¥¼ 불러들ì´ì§€ ì•ŠìŒ"
+
+msgid "-p[N]\t\tOpen N tab pages (default: one for each file)"
+msgstr "-p[N]\t\tNê°œì˜ íƒ­ 열기 (기본: 파ì¼ë³„ë¡œ 하나)"
+
+msgid "-o[N]\t\tOpen N windows (default: one for each file)"
+msgstr "-o[N]\t\tNê°œì˜ ì°½ 열기 (기본: 파ì¼ë³„ë¡œ 하나)"
+
+msgid "-O[N]\t\tLike -o but split vertically"
+msgstr "-O[N]\t\t-o와 같지만 ì°½ì„ ìˆ˜ì§ìœ¼ë¡œ 나누기"
+
+msgid "+\t\t\tStart at end of file"
+msgstr "+\t\t\tíŒŒì¼ ë§ˆì§€ë§‰ì—ì„œ 시작"
+
+msgid "+<lnum>\t\tStart at line <lnum>"
+msgstr "+<lnum>\t\t<lnum> 줄ì—ì„œ 시작"
+
+msgid "--cmd <command>\tExecute <command> before loading any vimrc file"
+msgstr "--cmd <명령>\tvimrc 파ì¼ì„ ì½ê¸° ì „ì— <명령>ì„ ì‹¤í–‰"
+
+msgid "-c <command>\t\tExecute <command> after loading the first file"
+msgstr "-c <명령>\t\t첫째 파ì¼ì„ ì½ì€ ë’¤ <명령>ì„ ì‹¤í–‰"
+
+msgid "-S <session>\t\tSource file <session> after loading the first file"
+msgstr "-S <세션>\t\t첫째 파ì¼ì„ ì½ì€ ë’¤ <세션> íŒŒì¼ ë¶ˆëŸ¬ 들ì´ê¸°"
+
+msgid "-s <scriptin>\tRead Normal mode commands from file <scriptin>"
+msgstr "-s <scriptin>\t<scriptin> 파ì¼ì—ì„œ Normal ìƒíƒœ 명령 ì½ê¸°"
+
+msgid "-w <scriptout>\tAppend all typed commands to file <scriptout>"
+msgstr "-w <scriptout>\t모든 ìž…ë ¥ëœ ëª…ë ¹ì„ <scriptout> 파ì¼ì— 추가"
+
+msgid "-W <scriptout>\tWrite all typed commands to file <scriptout>"
+msgstr "-W <scriptout>\t모든 ìž…ë ¥ëœ ëª…ë ¹ì„ <scriptout> 파ì¼ì— 저장"
+
+msgid "-x\t\t\tEdit encrypted files"
+msgstr "-x\t\t\tì•”í˜¸í™”ëœ íŒŒì¼ ê³ ì¹˜ê¸°"
+
+msgid "-display <display>\tConnect vim to this particular X-server"
+msgstr "-display <display>\të¹”ì„ íŠ¹ì • X-서버와 ì—°ê²°"
+
+msgid "-X\t\t\tDo not connect to X server"
+msgstr "-X\t\t\tX ì„œë²„ì— ì—°ê²°í•˜ì§€ ì•ŠìŒ"
+
+msgid "--remote <files>\tEdit <files> in a Vim server if possible"
+msgstr "--remote <files>\t가능하면 ë¹” 서버ì—ì„œ <files> 편집"
+
+msgid "--remote-silent <files> Same, don't complain if there is no server"
+msgstr "--remote-silent <files> ê°™ìŒ, 서버가 없다고 불í‰í•˜ì§€ ì•ŠìŒ"
+
+msgid ""
+"--remote-wait <files> As --remote but wait for files to have been edited"
+msgstr "--remote-wait <files> --remote와 같지만 다 고칠 때까지 기다립니다"
+
+msgid ""
+"--remote-wait-silent <files> Same, don't complain if there is no server"
+msgstr "--remote-wait-silent <files> ê°™ìŒ, 서버가 없다고 불í‰í•˜ì§€ ì•ŠìŒ"
+
+msgid ""
+"--remote-tab[-wait][-silent] <files> As --remote but use tab page per file"
+msgstr ""
+"--remote-tab[-wait][-silent] <files> --remote와 같지만 파ì¼ë³„ë¡œ 탭 페ì´ì§€ 사"
+"ìš©"
+
+msgid "--remote-send <keys>\tSend <keys> to a Vim server and exit"
+msgstr "--remote-send <keys>\të¹” 서버로 <keys>를 ë³´ë‚´ê³  ë내기"
+
+msgid "--remote-expr <expr>\tEvaluate <expr> in a Vim server and print result"
+msgstr "--remote-expr <expr>\të¹” 서버ì—ì„œ <expr> 실행하고 ê²°ê³¼ 출력"
+
+msgid "--serverlist\t\tList available Vim server names and exit"
+msgstr "--serverlist\t\t사용 가능한 ë¹” 서버 ì´ë¦„ì„ í‘œì‹œí•˜ê³  ë내기"
+
+msgid "--servername <name>\tSend to/become the Vim server <name>"
+msgstr "--servername <name>\të¹” 서버 <name>ì´ ë˜ê±°ë‚˜ 서버로 보내기"
+
+msgid "--startuptime <file>\tWrite startup timing messages to <file>"
+msgstr "--startuptime <file>\tstartup timing 메시지를 <file>ì— ì €ìž¥"
+
+msgid "-i <viminfo>\t\tUse <viminfo> instead of .viminfo"
+msgstr "-i <viminfo>\t\t.viminfo 대신 <viminfo>를 사용"
+
+#~ msgid "--clean\t\t'nocompatible', Vim defaults, no plugins, no viminfo"
+#~ msgstr ""
+
+msgid "-h or --help\tPrint Help (this message) and exit"
+msgstr "-h í˜¹ì€ --help\të„움ë§(ì´ ë©”ì‹œì§€)ì„ ì¶œë ¥í•œ ë’¤ ë내기"
+
+msgid "--version\t\tPrint version information and exit"
+msgstr "--version\t\tíŒ ì •ë³´ë¥¼ 출력한 ë’¤ ë내기"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Motif version):\n"
+msgstr ""
+"\n"
+"gvimì´ ì•Œê³  있는 ì¸ìž (모티프 íŒ):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (neXtaw version):\n"
+msgstr ""
+"\n"
+"gvimì´ ì•Œê³  있는 ì¸ìž (neXtaw íŒ):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Athena version):\n"
+msgstr ""
+"\n"
+"gvimì´ ì•Œê³  있는 ì¸ìž (아테나 íŒ):\n"
+
+msgid "-display <display>\tRun vim on <display>"
+msgstr "-display <display>\të¹”ì„ <display>ì—ì„œ 실행"
+
+msgid "-iconic\t\tStart vim iconified"
+msgstr "-iconic\t\tì•„ì´ì½˜ ìƒíƒœë¡œ ë¹” 시작"
+
+msgid "-background <color>\tUse <color> for the background (also: -bg)"
+msgstr "-background <color>\t바탕 색으로 <color> 사용 (also: -bg)"
+
+msgid "-foreground <color>\tUse <color> for normal text (also: -fg)"
+msgstr "-foreground <color>\tì¼ë°˜ ìƒ‰ì— <color> 사용 (also: -fg)"
+
+msgid "-font <font>\t\tUse <font> for normal text (also: -fn)"
+msgstr "-font <font>\t\tì¼ë°˜ í…ìŠ¤íŠ¸ì— <font> 사용 (also: -fn)"
+
+msgid "-boldfont <font>\tUse <font> for bold text"
+msgstr "-boldfont <font>\têµµì€ í…ìŠ¤íŠ¸ì— <font> 사용"
+
+msgid "-italicfont <font>\tUse <font> for italic text"
+msgstr "-italicfont <font>\t기울임 í…ìŠ¤íŠ¸ì— <font> 사용"
+
+msgid "-geometry <geom>\tUse <geom> for initial geometry (also: -geom)"
+msgstr "-geometry <geom>\t초기 ì§€ì˜¤ë¯¸íŠ¸ë¦¬ì— <geom> 사용 (also: -geom)"
+
+msgid "-borderwidth <width>\tUse a border width of <width> (also: -bw)"
+msgstr "-borderwidth <width>\t가장ìžë¦¬ ë„“ì´ì— <width> 사용 (also: -bw)"
+
+msgid "-scrollbarwidth <width> Use a scrollbar width of <width> (also: -sw)"
+msgstr "-scrollbarwidth <width> 스í¬ë¡¤ë°” ë„“ì´ì— <width> 사용 (also: -sw)"
+
+msgid "-menuheight <height>\tUse a menu bar height of <height> (also: -mh)"
+msgstr "-menuheight <height>\t메뉴바 높ì´ì— <height> 사용 (also: -mh)"
+
+msgid "-reverse\t\tUse reverse video (also: -rv)"
+msgstr "-reverse\t\t반전 비디오 사용 (also: -rv)"
+
+msgid "+reverse\t\tDon't use reverse video (also: +rv)"
+msgstr "+reverse\t\t반전 비디오 사용 안 함 (also: +rv)"
+
+msgid "-xrm <resource>\tSet the specified resource"
+msgstr "-xrm <resource>\tëª…ì‹œëœ ë¦¬ì†ŒìŠ¤ 설정"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (GTK+ version):\n"
+msgstr ""
+"\n"
+"gvimì´ ì•Œê³ ìžˆëŠ” ì¸ìž (GTK+ íŒ):\n"
+
+msgid "-display <display>\tRun vim on <display> (also: --display)"
+msgstr "-display <display>\të¹”ì„ <display>ì—ì„œ 실행 (also: --display)"
+
+msgid "--role <role>\tSet a unique role to identify the main window"
+msgstr "--role <role>\të©”ì¸ ì°½ êµ¬ë¶„ì„ ìœ„í•´ 유ì¼í•œ ì—­í•  설정"
+
+msgid "--socketid <xid>\tOpen Vim inside another GTK widget"
+msgstr "--socketid <xid>\të¹”ì„ ë‹¤ë¥¸ GTK 위젯 안ì—ì„œ ì—´ìŒ"
+
+msgid "--echo-wid\t\tMake gvim echo the Window ID on stdout"
+msgstr "--echo-wid\t\tí‘œì¤€ì¶œë ¥ì— gvimì˜ Window ID를 표시"
+
+msgid "-P <parent title>\tOpen Vim inside parent application"
+msgstr "-P <parent title>\tVimì„ ë¶€ëª¨ ì‘ìš© 프로그램 ë‚´ì—ì„œ 열기"
+
+msgid "--windowid <HWND>\tOpen Vim inside another win32 widget"
+msgstr "--windowid <HWND>\t다른 win32 위젯 안ì—ì„œ Vim 열기"
+
+msgid "No display"
+msgstr "디스플레ì´ê°€ 없습니다"
+
+msgid ": Send failed.\n"
+msgstr ": 보내기가 실패하였습니다.\n"
+
+msgid ": Send failed. Trying to execute locally\n"
+msgstr ": 보내기 실패. 로컬ì—ì„œ 실행ë©ë‹ˆë‹¤\n"
+
+#, c-format
+#~ msgid "%d of %d edited"
+#~ msgstr ""
+
+msgid "No display: Send expression failed.\n"
+msgstr "ë””ìŠ¤í”Œë ˆì´ ì—†ìŒ: í‘œí˜„ì‹ ë³´ë‚´ê¸°ê°€ 실패했습니다.\n"
+
+msgid ": Send expression failed.\n"
+msgstr ": í‘œí˜„ì‹ ë³´ë‚´ê¸°ê°€ 실패했습니다.\n"
+
+msgid "No marks set"
+msgstr "ì„¤ì •ëœ ë§ˆí¬ê°€ 없습니다"
+
+#, c-format
+msgid "E283: No marks matching \"%s\""
+msgstr "E283: \"%s\"ì— ë§žëŠ” 마í¬ê°€ 없습니다"
+
+msgid ""
+"\n"
+"mark line col file/text"
+msgstr ""
+"\n"
+"ë§ˆí¬ ë¼ì¸ col 파ì¼/í…스트"
+
+msgid ""
+"\n"
+" jump line col file/text"
+msgstr ""
+"\n"
+" ì í”„ ë¼ì¸ col 파ì¼/í…스트"
+
+#~ msgid ""
+#~ "\n"
+#~ "change line col text"
+#~ msgstr ""
+
+msgid ""
+"\n"
+"# File marks:\n"
+msgstr ""
+"\n"
+"# íŒŒì¼ ë§ˆí¬:\n"
+
+msgid ""
+"\n"
+"# Jumplist (newest first):\n"
+msgstr ""
+"\n"
+"# ì í”„ëª©ë¡ (ìƒˆê²ƒì´ ë¨¼ì €):\n"
+
+msgid ""
+"\n"
+"# History of marks within files (newest to oldest):\n"
+msgstr ""
+"\n"
+"# 파ì¼ë‚´ì˜ ë§ˆí¬ ížˆìŠ¤í† ë¦¬ (새것부터 ì˜¤ëž˜ëœ ìˆœ):\n"
+
+msgid "Missing '>'"
+msgstr "'>'ì´ ì—†ìŠµë‹ˆë‹¤"
+
+msgid "E543: Not a valid codepage"
+msgstr "E543: ì •ìƒì ì¸ 코드페ì´ì§€ê°€ 아닙니다"
+
+msgid "E284: Cannot set IC values"
+msgstr "E284: IC ê°’ì„ ì„¤ì •í•  수 없습니다"
+
+msgid "E285: Failed to create input context"
+msgstr "E285: ìž…ë ¥ 콘í…스트를 만들 수 없습니다"
+
+msgid "E286: Failed to open input method"
+msgstr "E286: ìž…ë ¥ ë°©ì‹ì„ 열다가 실패했습니다"
+
+msgid "E287: Warning: Could not set destroy callback to IM"
+msgstr "E287: 경고: IMì— íŒŒê´´ ì½œë°±ì„ ì„¤ì •í•  수 없습니다"
+
+msgid "E288: input method doesn't support any style"
+msgstr "E288: ìž…ë ¥ ë°©ì‹ì´ ì–´ë–¤ 형ì‹ë„ 지ì›í•˜ì§€ 않습니다"
+
+msgid "E289: input method doesn't support my preedit type"
+msgstr "E289: ìž…ë ¥ ë°©ì‹ì´ ë‚´ preedit 형ì‹ì„ 지ì›í•˜ì§€ 않습니다"
+
+msgid "E293: block was not locked"
+msgstr "E293: êµ¬ì—­ì´ ìž ê¶ˆì§€ì§€ 않았습니다"
+
+msgid "E294: Seek error in swap file read"
+msgstr "E294: 스왑 파ì¼ì„ ì½ê¸° 위해 특정 위치로 ê°ˆ 수 없습니다"
+
+msgid "E295: Read error in swap file"
+msgstr "E295: 스왑 파ì¼ì„ ì½ì„ 수 없습니다"
+
+msgid "E296: Seek error in swap file write"
+msgstr "E296: 스왑 파ì¼ì„ 쓰기 위해 특정 위치로 ê°ˆ 수 없습니다"
+
+msgid "E297: Write error in swap file"
+msgstr "E297: 스왑 파ì¼ì„ 쓸 수 없습니다"
+
+msgid "E300: Swap file already exists (symlink attack?)"
+msgstr "E300: 스왑 파ì¼ì´ ì´ë¯¸ 존재합니다 (symlink 공격?)"
+
+msgid "E298: Didn't get block nr 0?"
+msgstr "E298: 구역 번호 0ì„ ì–»ì§€ 못했나요?"
+
+msgid "E298: Didn't get block nr 1?"
+msgstr "E298: 구역 번호 1ì„ ì–»ì§€ 못했나요?"
+
+msgid "E298: Didn't get block nr 2?"
+msgstr "E298: 구역 번호 2를 얻지 못했나요?"
+
+msgid "E843: Error while updating swap file crypt"
+msgstr "E843: 스왑 파ì¼ì„ 암호화할 수 없습니다"
+
+msgid "E301: Oops, lost the swap file!!!"
+msgstr "E301: 으윽, 스왑 파ì¼ì„ 잃어버렸습니다!!!"
+
+msgid "E302: Could not rename swap file"
+msgstr "E302: 스왑 íŒŒì¼ ì´ë¦„ì„ ë°”ê¿€ 수 없습니다"
+
+#, c-format
+msgid "E303: Unable to open swap file for \"%s\", recovery impossible"
+msgstr "E303: \"%s\"ì˜ ìŠ¤ì™‘ 파ì¼ì„ ì—´ 수 없어서 복구는 불가능합니다"
+
+msgid "E304: ml_upd_block0(): Didn't get block 0??"
+msgstr "E304: ml_upd_block0(): 구역 0ì„ ì–»ì§€ 못했나요??"
+
+#, c-format
+msgid "E305: No swap file found for %s"
+msgstr "E305: %sì˜ ìŠ¤ì™‘ 파ì¼ì„ ì°¾ì„ ìˆ˜ 없습니다"
+
+msgid "Enter number of swap file to use (0 to quit): "
+msgstr "사용할 스왑 íŒŒì¼ ë²ˆí˜¸ë¥¼ 입력하십시오 (0ì€ ë내기): "
+
+#, c-format
+msgid "E306: Cannot open %s"
+msgstr "E306: %sì„(를) ì—´ 수 없습니다"
+
+msgid "Unable to read block 0 from "
+msgstr "Unable to read block 0 from "
+
+msgid ""
+"\n"
+"Maybe no changes were made or Vim did not update the swap file."
+msgstr ""
+"\n"
+"ì–´ë–¤ ìˆ˜ì •ë„ ì—†ì—ˆê±°ë‚˜ ë¹”ì´ ìŠ¤ì™‘ 파ì¼ì„ 갱신하지 ì•Šì€ ê²ƒ 같습니다."
+
+msgid " cannot be used with this version of Vim.\n"
+msgstr " cannot be used with this version of Vim.\n"
+
+msgid "Use Vim version 3.0.\n"
+msgstr "ë¹” 3.0 íŒì„ 사용하십시오.\n"
+
+#, c-format
+msgid "E307: %s does not look like a Vim swap file"
+msgstr "E307: %sì€(는) ë¹” 스왑 파ì¼ì´ ì•„ë‹Œ 것 같습니다"
+
+msgid " cannot be used on this computer.\n"
+msgstr " ì´ ì»´í“¨í„°ì—서는 ì‚¬ìš©ë  ìˆ˜ 없습니다.\n"
+
+msgid "The file was created on "
+msgstr "The file was created on "
+
+msgid ""
+",\n"
+"or the file has been damaged."
+msgstr ""
+",\n"
+"or the file has been damaged."
+
+#, c-format
+msgid ""
+"E833: %s is encrypted and this version of Vim does not support encryption"
+msgstr "E833: %sì´(ê°€) 암호화ë˜ì–´ 있는 ë°, ì´ Vimì€ ì•”í˜¸í™”ë¥¼ 지ì›í•˜ì§€ 않습니다"
+
+msgid " has been damaged (page size is smaller than minimum value).\n"
+msgstr " has been damaged (page size is smaller than minimum value).\n"
+
+#, c-format
+msgid "Using swap file \"%s\""
+msgstr "스왑 íŒŒì¼ \"%s\"ì„(를) 사용합니다"
+
+#, c-format
+msgid "Original file \"%s\""
+msgstr "ì›ëž˜ íŒŒì¼ \"%s\""
+
+msgid "E308: Warning: Original file may have been changed"
+msgstr "E308: 경고: ì›ëž˜ 파ì¼ì´ 바뀌었습니다"
+
+#, c-format
+msgid "Swap file is encrypted: \"%s\""
+msgstr "스왑 파ì¼ì´ 암호화ë¨: \"%s\""
+
+msgid ""
+"\n"
+"If you entered a new crypt key but did not write the text file,"
+msgstr ""
+"\n"
+"새로운 암호 키를 입력했는 ë°, 파ì¼ì„ 저장하지 않았었다면,"
+
+msgid ""
+"\n"
+"enter the new crypt key."
+msgstr ""
+"\n"
+"새로운 암호 키를 입력하세요."
+
+msgid ""
+"\n"
+"If you wrote the text file after changing the crypt key press enter"
+msgstr ""
+"\n"
+"암호 키를 바꾼 í›„ì— íŒŒì¼ì„ 저장했었다면 ê°™ì€ í‚¤ë¡œ í…스트 파ì¼ê³¼"
+
+msgid ""
+"\n"
+"to use the same key for text file and swap file"
+msgstr ""
+"\n"
+"스왑파ì¼ì„ 저장하려면 엔터를 누르세요"
+
+#, c-format
+msgid "E309: Unable to read block 1 from %s"
+msgstr "E309: %sì˜ êµ¬ì—­ 1ì„ ì½ì„ 수 없습니다"
+
+msgid "???MANY LINES MISSING"
+msgstr "???ë§Žì€ ì¤„ì„ ìžƒì–´ë²„ë¦¼"
+
+msgid "???LINE COUNT WRONG"
+msgstr "???줄 번호가 잘못ë˜ì—ˆìŠµë‹ˆë‹¤"
+
+msgid "???EMPTY BLOCK"
+msgstr "???빈 구역"
+
+msgid "???LINES MISSING"
+msgstr "???ì¤„ì„ ìžƒì–´ë²„ë¦¼"
+
+#, c-format
+msgid "E310: Block 1 ID wrong (%s not a .swp file?)"
+msgstr "E310: 구역 1ì˜ IDê°€ 잘못ë˜ì—ˆìŠµë‹ˆë‹¤ (%sì´(ê°€) .swp 파ì¼ì´ 아닌가?)"
+
+msgid "???BLOCK MISSING"
+msgstr "???구역 잃어버림"
+
+msgid "??? from here until ???END lines may be messed up"
+msgstr "??? 여기부터 ???ëê¹Œì§€ì˜ ì¤„ì´ ì„žì˜€ìŠµë‹ˆë‹¤"
+
+msgid "??? from here until ???END lines may have been inserted/deleted"
+msgstr "??? 여기부터 ???ëê¹Œì§€ì˜ ì¤„ì´ ë¼ì›Œì§€ê±°ë‚˜ 지워져 버린 것 같습니다"
+
+msgid "???END"
+msgstr "???ë"
+
+msgid "E311: Recovery Interrupted"
+msgstr "E311: 복구 중단ë˜ì—ˆìŠµë‹ˆë‹¤"
+
+msgid ""
+"E312: Errors detected while recovering; look for lines starting with ???"
+msgstr "E312: 복구 ë„중 ì—러 ìƒê²¼ìŠµë‹ˆë‹¤; ???ë¡œ 시작하는 ì¤„ì„ ì°¾ì•„ë³´ì‹­ì‹œì˜¤"
+
+msgid "See \":help E312\" for more information."
+msgstr "ë” ë§Žì€ ì •ë³´ë¥¼ 보려면 \":help E312\"를 입력하세요."
+
+msgid "Recovery completed. You should check if everything is OK."
+msgstr "복구가 ë났습니다. 모든 게 ì •ìƒì¸ 지 확ì¸í•´ 보셔야만 합니다."
+
+msgid ""
+"\n"
+"(You might want to write out this file under another name\n"
+msgstr ""
+"\n"
+"(어쩌면 다른 ì´ë¦„으로 저장하고 싶으실 ì§€ë„ ëª¨ë¥´ê² ìŠµë‹ˆë‹¤\n"
+
+msgid "and run diff with the original file to check for changes)"
+msgstr "그리고 ë°”ë€ ë‚´ìš©ì„ í™•ì¸í•˜ë ¤ë©´ ì›ëž˜ 파ì¼ì— 대해 diff를 실행하세요)"
+
+msgid "Recovery completed. Buffer contents equals file contents."
+msgstr "복구가 ë났습니다. 버í¼ì˜ ë‚´ìš©ì´ íŒŒì¼ ë‚´ìš©ê³¼ 같습니다."
+
+msgid ""
+"\n"
+"You may want to delete the .swp file now.\n"
+"\n"
+msgstr ""
+"\n"
+"ì´ì œ .swp 파ì¼ì„ ì§€ìš°ì…”ë„ ë©ë‹ˆë‹¤.\n"
+"\n"
+
+msgid "Using crypt key from swap file for the text file.\n"
+msgstr "í…스트 파ì¼ì— 스왑파ì¼ì—ì„œ 가져온 암호 키를 사용합니다.\n"
+
+msgid "Swap files found:"
+msgstr "스왑 파ì¼ì„ 찾았ìŒ:"
+
+msgid " In current directory:\n"
+msgstr " 현재 디렉토리ì—:\n"
+
+msgid " Using specified name:\n"
+msgstr " ëª…ì‹œëœ ì´ë¦„ì„ ì‚¬ìš©:\n"
+
+msgid " In directory "
+msgstr " In directory "
+
+msgid " -- none --\n"
+msgstr " -- ì—†ìŒ --\n"
+
+msgid " owned by: "
+msgstr " 소유ìž: "
+
+msgid " dated: "
+msgstr " 날짜: "
+
+msgid " dated: "
+msgstr " 날짜: "
+
+msgid " [from Vim version 3.0]"
+msgstr " [ë¹” 3.0 íŒì˜ 것]"
+
+msgid " [does not look like a Vim swap file]"
+msgstr " [ë¹” 스왑 파ì¼ë¡œ ë³´ì´ì§€ 않습니다]"
+
+msgid " file name: "
+msgstr " íŒŒì¼ ì´ë¦„: "
+
+msgid ""
+"\n"
+" modified: "
+msgstr ""
+"\n"
+" 수정: "
+
+msgid "YES"
+msgstr "예"
+
+msgid "no"
+msgstr "아니오"
+
+msgid ""
+"\n"
+" user name: "
+msgstr ""
+"\n"
+" ì‚¬ìš©ìž ì´ë¦„: "
+
+msgid " host name: "
+msgstr " 호스트 ì´ë¦„: "
+
+msgid ""
+"\n"
+" host name: "
+msgstr ""
+"\n"
+" 호스트 ì´ë¦„: "
+
+msgid ""
+"\n"
+" process ID: "
+msgstr ""
+"\n"
+" 프로세스 ID: "
+
+msgid " (still running)"
+msgstr " (ì•„ì§ ì‹¤í–‰ì¤‘)"
+
+msgid ""
+"\n"
+" [not usable with this version of Vim]"
+msgstr ""
+"\n"
+" [ë¹” ì´ë²ˆ íŒì—서는 사용할 수 ì—†ìŒ]"
+
+msgid ""
+"\n"
+" [not usable on this computer]"
+msgstr ""
+"\n"
+" [ì´ ì»´í“¨í„°ì—서는 사용할 수 ì—†ìŒ]"
+
+msgid " [cannot be read]"
+msgstr " [ì½ì„ 수 ì—†ìŒ]"
+
+msgid " [cannot be opened]"
+msgstr " [ì—´ 수 ì—†ìŒ]"
+
+msgid "E313: Cannot preserve, there is no swap file"
+msgstr "E313: ë³´ì¡´í•  수 없습니다, 스왑 파ì¼ì´ 없습니다"
+
+msgid "File preserved"
+msgstr "파ì¼ì´ ë³´ì¡´ë˜ì—ˆìŠµë‹ˆë‹¤"
+
+msgid "E314: Preserve failed"
+msgstr "E314: íŒŒì¼ ë³´ì¡´ì„ ì‹¤íŒ¨í–ˆìŠµë‹ˆë‹¤"
+
+#, c-format
+msgid "E315: ml_get: invalid lnum: %ld"
+msgstr "E315: ml_get: ìž˜ëª»ëœ lnum: %ld"
+
+#, c-format
+msgid "E316: ml_get: cannot find line %ld"
+msgstr "E316: ml_get: %ld ì¤„ì„ ì°¾ì„ ìˆ˜ 없습니다"
+
+msgid "E317: pointer block id wrong 3"
+msgstr "E317: ìž˜ëª»ëœ í¬ì¸í„° 구역 id 3"
+
+msgid "stack_idx should be 0"
+msgstr "stack_idx는 0여야만 합니다"
+
+msgid "E318: Updated too many blocks?"
+msgstr "E318: 너무 ë§Žì€ êµ¬ì—­ì´ ê°±ì‹ ë˜ì—ˆë‚˜ìš”?"
+
+msgid "E317: pointer block id wrong 4"
+msgstr "E317: ìž˜ëª»ëœ í¬ì¸í„° 구역 id 4"
+
+msgid "deleted block 1?"
+msgstr "구역 1ì´ ì§€ì›Œì¡Œë‚˜ìš”?"
+
+#, c-format
+msgid "E320: Cannot find line %ld"
+msgstr "E320: %ld ì¤„ì„ ì°¾ì„ ìˆ˜ 없습니다"
+
+msgid "E317: pointer block id wrong"
+msgstr "E317: ìž˜ëª»ëœ í¬ì¸í„° 구역 id"
+
+msgid "pe_line_count is zero"
+msgstr "pe_line_count가 0입니다"
+
+#, c-format
+msgid "E322: line number out of range: %ld past the end"
+msgstr "E322: 줄 번호가 범위를 벗어났습니다: 마지막ì—ì„œ %ld 만í¼"
+
+#, c-format
+msgid "E323: line count wrong in block %ld"
+msgstr "E323: 구역 %ldì˜ ì¤„ 갯수가 틀렸습니다"
+
+msgid "Stack size increases"
+msgstr "ìŠ¤íƒ í¬ê¸° ì¦ê°€"
+
+msgid "E317: pointer block id wrong 2"
+msgstr "E317: ìž˜ëª»ëœ í¬ì¸í„° 구역 id 2"
+
+#, c-format
+#~ msgid "E773: Symlink loop for \"%s\""
+#~ msgstr ""
+
+msgid "E325: ATTENTION"
+msgstr "E325: 주목"
+
+msgid ""
+"\n"
+"Found a swap file by the name \""
+msgstr ""
+"\n"
+"Found a swap file by the name \""
+
+msgid "While opening file \""
+msgstr "While opening file \""
+
+msgid " NEWER than swap file!\n"
+msgstr " NEWER than swap file!\n"
+
+msgid ""
+"\n"
+"(1) Another program may be editing the same file. If this is the case,\n"
+" be careful not to end up with two different instances of the same\n"
+" file when making changes. Quit, or continue with caution.\n"
+msgstr ""
+"\n"
+"(1) 다른 í”„ë¡œê·¸ëž¨ì´ ê°™ì€ íŒŒì¼ì„ 고치고 ìžˆëŠ”ì¤‘ì¼ ìˆ˜ 있습니다.\n"
+" 만약 그렇다면 ê°™ì€ íŒŒì¼ì„ ë‘ ê°œì˜ í”„ë¡œê·¸ëž¨ì—ì„œ 고치지 ì•Šë„ë¡\n"
+" 조심하시기 ë°”ëžë‹ˆë‹¤. 종료하세요. 계ì†í•˜ì‹œë ¤ë©´ 주ì˜í•˜ì„¸ìš”.\n"
+
+msgid "(2) An edit session for this file crashed.\n"
+msgstr "(2) ì´ íŒŒì¼ì„ 고치다가 죽었었습니다.\n"
+
+msgid " If this is the case, use \":recover\" or \"vim -r "
+msgstr " 만약 그렇다면 \":recover\" í˜¹ì€ \"vim -r "
+
+msgid ""
+"\"\n"
+" to recover the changes (see \":help recovery\").\n"
+msgstr ""
+"\"\n"
+" ì„ ì‚¬ìš©í•˜ì—¬ 복구하십시오 (\":help recovery\" 참고).\n"
+
+msgid " If you did this already, delete the swap file \""
+msgstr " ì´ë¯¸ 복구하셨었다면 ìŠ¤ì™‘íŒŒì¼ \""
+
+msgid ""
+"\"\n"
+" to avoid this message.\n"
+msgstr ""
+"\"\n"
+" ì„(를) 지우셔야 ì´ ë©”ì‹œì§€ê°€ 사ë¼ì§‘니다.\n"
+
+msgid "Swap file \""
+msgstr "스왑 íŒŒì¼ \""
+
+msgid "\" already exists!"
+msgstr "\"ì´ ì´ë¯¸ 존재합니다!"
+
+msgid "VIM - ATTENTION"
+msgstr "빔 - 주목"
+
+msgid "Swap file already exists!"
+msgstr "스왑 파ì¼ì´ ì´ë¯¸ 존재합니다!"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"ì½ê¸° 전용으로 열기(&O)\n"
+"그냥 고치기(&E)\n"
+"복구(&R)\n"
+"ë내기(&Q)\n"
+"버리기(&A)"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Delete it\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"ì½ê¸° 전용으로 열기(&O)\n"
+"무조건 편집(&E)\n"
+"복구(&R)\n"
+"삭제(&D)\n"
+"ë내기(&Q)\n"
+"버리기(&A)"
+
+msgid "E326: Too many swap files found"
+msgstr "E326: 너무 ë§Žì€ ìŠ¤ì™‘ 파ì¼ì´ 발견ë˜ì—ˆìŠµë‹ˆë‹¤"
+
+msgid "E327: Part of menu-item path is not sub-menu"
+msgstr "E327: 메뉴 항목 ê²½ë¡œì˜ ë¶€ë¶„ì´ í•˜ìœ„ 메뉴가 아닙니다"
+
+msgid "E328: Menu only exists in another mode"
+msgstr "E328: 메뉴가 다른 모드ì—서만 존재합니다"
+
+#, c-format
+msgid "E329: No menu \"%s\""
+msgstr "E329: \"%s\" 메뉴 ì—†ìŒ"
+
+msgid "E792: Empty menu name"
+msgstr "E792: 메뉴 ì´ë¦„ ì—†ìŒ"
+
+msgid "E330: Menu path must not lead to a sub-menu"
+msgstr "E330: 하위 메뉴 ì•žì—는 메뉴 경로가 ë¶™ì„ ìˆ˜ 없습니다"
+
+msgid "E331: Must not add menu items directly to menu bar"
+msgstr "E331: ë©”ë‰´ë°”ì— ê³§ë°”ë¡œ 메뉴 í•­ëª©ì„ ë”í•  수는 없습니다"
+
+msgid "E332: Separator cannot be part of a menu path"
+msgstr "E332: 구분ìžëŠ” 메뉴 ê²½ë¡œì˜ ë¶€ë¶„ì´ ë  ìˆ˜ 없습니다"
+
+msgid ""
+"\n"
+"--- Menus ---"
+msgstr ""
+"\n"
+"--- 메뉴 ---"
+
+msgid "Tear off this menu"
+msgstr "ì´ ë©”ë‰´ë¥¼ 떼어냄"
+
+#, c-format
+msgid "E335: Menu not defined for %s mode"
+msgstr "E335: %s ëª¨ë“œì— ëŒ€í•œ 메뉴가 ì •ì˜ë˜ì–´ 있지 않습니다"
+
+msgid "E333: Menu path must lead to a menu item"
+msgstr "E333: 메뉴 항목 ì•žì—는 메뉴 경로가 있어야 합니다"
+
+#, c-format
+msgid "E334: Menu not found: %s"
+msgstr "E334: 메뉴를 ì°¾ì„ ìˆ˜ 없습니다: %s"
+
+msgid "E336: Menu path must lead to a sub-menu"
+msgstr "E336: 하위 메뉴 ì•žì— ë©”ë‰´ 경로가 있어야 합니다"
+
+msgid "E337: Menu not found - check menu names"
+msgstr "E337: 메뉴를 ì°¾ì„ ìˆ˜ ì—†ìŒ - 메뉴 ì´ë¦„ì„ í™•ì¸í•˜ì‹­ì‹œì˜¤"
+
+#, c-format
+msgid "Error detected while processing %s:"
+msgstr "%s 수행중 ì—러 발견:"
+
+#, c-format
+msgid "line %4ld:"
+msgstr "%4ld 줄:"
+
+#, c-format
+msgid "E354: Invalid register name: '%s'"
+msgstr "E354: ìž˜ëª»ëœ ë ˆì§€ìŠ¤í„° ì´ë¦„: '%s'"
+
+msgid "Messages maintainer: Bram Moolenaar <Bram@vim.org>"
+msgstr "메시지 관리ìž: SungHyun Nam <goweol@gmail.com>"
+
+msgid "Interrupt: "
+msgstr "중단: "
+
+msgid "Press ENTER or type command to continue"
+msgstr "계ì†í•˜ë ¤ë©´ 엔터 í˜¹ì€ ëª…ë ¹ì„ ìž…ë ¥í•˜ì‹­ì‹œì˜¤"
+
+#, c-format
+msgid "%s line %ld"
+msgstr "%s 줄 %ld"
+
+msgid "-- More --"
+msgstr "-- ë” --"
+
+msgid " SPACE/d/j: screen/page/line down, b/u/k: up, q: quit "
+msgstr " SPACE/d/j: 화면/페ì´ì§€/ë¼ì¸ 아래로, b/u/k: 위로, q: 종료 "
+
+msgid "Question"
+msgstr "질문"
+
+msgid ""
+"&Yes\n"
+"&No"
+msgstr ""
+"예(&Y)\n"
+"아니오(&N)"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"Save &All\n"
+"&Discard All\n"
+"&Cancel"
+msgstr ""
+"예(&Y)\n"
+"아니오(&N)\n"
+"ëª¨ë‘ ì €ìž¥(&A)\n"
+"ëª¨ë‘ ë²„ë¦¼(&D)\n"
+"취소(&C)"
+
+msgid "Select Directory dialog"
+msgstr "디렉토리 ì„ íƒ ëŒ€í™”ìƒìž"
+
+msgid "Save File dialog"
+msgstr "íŒŒì¼ ì €ìž¥ 대화ìƒìž"
+
+msgid "Open File dialog"
+msgstr "íŒŒì¼ ì—´ê¸° 대화ìƒìž"
+
+msgid "E338: Sorry, no file browser in console mode"
+msgstr "E338: 미안합니다, 콘솔 ìƒíƒœì—는 íŒŒì¼ ë¸Œë¼ìš°ì €ê°€ 없습니다"
+
+msgid "E766: Insufficient arguments for printf()"
+msgstr "E766: printf()ì— ë„˜ì–´ì˜¨ ì¸ìž 갯수가 부족"
+
+msgid "E807: Expected Float argument for printf()"
+msgstr "E807: printf()ì— ì˜ˆìƒëª»í•œ Float ì¸ìž"
+
+msgid "E767: Too many arguments to printf()"
+msgstr "E767: printf()ì— ë„ˆë¬´ ë§Žì€ ì¸ìž 넘어옴"
+
+msgid "W10: Warning: Changing a readonly file"
+msgstr "W10: 경고: ì½ê¸° ì „ìš© 파ì¼ì„ 고치고 있습니다"
+
+msgid "Type number and <Enter> or click with mouse (empty cancels): "
+msgstr "ìˆ«ìž ìž…ë ¥í›„ <엔터>나 마우스 í´ë¦­ (숫ìžì—†ìœ¼ë©´ 취소): "
+
+msgid "Type number and <Enter> (empty cancels): "
+msgstr "ìˆ«ìž ìž…ë ¥í›„ <엔터> (숫ìžì—†ìœ¼ë©´ 취소): "
+
+msgid "1 more line"
+msgstr "í•œ 줄 ì´ìƒ"
+
+msgid "1 line less"
+msgstr "í•œ 줄 ì´í•˜"
+
+#, c-format
+msgid "%ld more lines"
+msgstr "%ld 보다 ë§Žì€ ì¤„"
+
+#, c-format
+msgid "%ld fewer lines"
+msgstr "%ld 보다 ì ì€ 줄"
+
+msgid " (Interrupted)"
+msgstr " (중단ë˜ì—ˆìŠµë‹ˆë‹¤)"
+
+msgid "Beep!"
+msgstr "ì‚‘!"
+
+msgid "ERROR: "
+msgstr "ì—러: "
+
+#, c-format
+#~ msgid ""
+#~ "\n"
+#~ "[bytes] total alloc-freed %lu-%lu, in use %lu, peak use %lu\n"
+#~ msgstr ""
+
+#, c-format
+#~ msgid ""
+#~ "[calls] total re/malloc()'s %lu, total free()'s %lu\n"
+#~ "\n"
+#~ msgstr ""
+
+msgid "E340: Line is becoming too long"
+msgstr "E340: ì¤„ì´ ë„ˆë¬´ 길어졌습니다"
+
+#, c-format
+msgid "E341: Internal error: lalloc(%ld, )"
+msgstr "E341: 내부 ì—러: lalloc(%ld, )"
+
+#, c-format
+msgid "E342: Out of memory! (allocating %lu bytes)"
+msgstr "E342: 메모리 부족! (%lu ë°”ì´íŠ¸ë¥¼ 할당)"
+
+#, c-format
+msgid "Calling shell to execute: \"%s\""
+msgstr "실행하려고 쉘 부름: \"%s\""
+
+msgid "E545: Missing colon"
+msgstr "E545: ì½œë¡ ì´ ì—†ìŠµë‹ˆë‹¤"
+
+msgid "E546: Illegal mode"
+msgstr "E546: ì´ìƒí•œ 모드"
+
+msgid "E547: Illegal mouseshape"
+msgstr "E547: ì´ìƒí•œ 마우스모양"
+
+msgid "E548: digit expected"
+msgstr "E548: 숫ìžê°€ 필요합니다"
+
+msgid "E549: Illegal percentage"
+msgstr "E549: ì´ìƒí•œ 백분율"
+
+#~ msgid "E854: path too long for completion"
+#~ msgstr ""
+
+#, c-format
+msgid ""
+"E343: Invalid path: '**[number]' must be at the end of the path or be "
+"followed by '%s'."
+msgstr ""
+"E343: ìž˜ëª»ëœ ê²½ë¡œ: '**[번호]'는 ê²½ë¡œì˜ ë§ˆì§€ë§‰ì— ìœ„ì¹˜í•˜ê±°ë‚˜ '%s' ë’¤ì— ìžˆì–´ì•¼ "
+"합니다."
+
+#, c-format
+msgid "E344: Can't find directory \"%s\" in cdpath"
+msgstr "E344: cdpathì—ì„œ \"%s\" 디렉토리를 ì°¾ì„ ìˆ˜ 없습니다"
+
+#, c-format
+msgid "E345: Can't find file \"%s\" in path"
+msgstr "E345: pathì—ì„œ \"%s\" 파ì¼ì„ ì°¾ì„ ìˆ˜ 없습니다"
+
+#, c-format
+msgid "E346: No more directory \"%s\" found in cdpath"
+msgstr "E346: cdpathì—ì„œ ë” ì´ìƒì˜ \"%s\" 디렉토리를 ì°¾ì„ ìˆ˜ 없습니다"
+
+#, c-format
+msgid "E347: No more file \"%s\" found in path"
+msgstr "E347: pathì—ì„œ ë” ì´ìƒì˜ \"%s\" 파ì¼ì„ ì°¾ì„ ìˆ˜ 없습니다"
+
+#, c-format
+msgid "E668: Wrong access mode for NetBeans connection info file: \"%s\""
+msgstr "E668: NetBeans ì—°ê²° ì •ë³´ 파ì¼ì´ ì ‘ê·¼ 모드가 잘못ë¨: \"%s\""
+
+#, c-format
+msgid "E658: NetBeans connection lost for buffer %ld"
+msgstr "E658: ë²„í¼ %ldì— ëŒ€í•œ NetBeans ì—°ê²°ì„ ìžƒì–´ë²„ë ¸ìŠµë‹ˆë‹¤"
+
+msgid "E838: netbeans is not supported with this GUI"
+msgstr "E838: ì´ GUI는 netbeans를 지ì›í•˜ì§€ 않습니다"
+
+msgid "E511: netbeans already connected"
+msgstr "E511: netbeansê°€ ì´ë¯¸ ì—°ê²°ë˜ì–´ 있습니다"
+
+#, c-format
+msgid "E505: %s is read-only (add ! to override)"
+msgstr "E505: %sì€(는) ì½ê¸° 전용입니다 (ë®ì–´ì“°ë ¤ë©´ ! ë”하기)"
+
+msgid "E349: No identifier under cursor"
+msgstr "E349: 커서 ë°‘ì— ì‹ë³„ìžê°€ 없습니다"
+
+msgid "E774: 'operatorfunc' is empty"
+msgstr "E774: 'operatorfunc'가 비어있습니다"
+
+msgid "E775: Eval feature not available"
+msgstr "E775: Eval ê¸°ëŠ¥ì´ ë¹ ì ¸ìžˆìŠµë‹ˆë‹¤"
+
+msgid "Warning: terminal cannot highlight"
+msgstr "경고: 터미ë„ì´ ë¹„ì¥¬ì–¼ ìƒíƒœë¥¼ 표시할 수 없습니다"
+
+msgid "E348: No string under cursor"
+msgstr "E348: 커서 ë°‘ì— ë¬¸ìžì—´ì´ 없습니다"
+
+msgid "E352: Cannot erase folds with current 'foldmethod'"
+msgstr "E352: í˜„ìž¬ì˜ 'foldmethod'으로 접기를 지울 수 없습니다"
+
+msgid "E664: changelist is empty"
+msgstr "E664: changelist가 비었습니다"
+
+#~ msgid "E662: At start of changelist"
+#~ msgstr ""
+
+#~ msgid "E663: At end of changelist"
+#~ msgstr ""
+
+msgid "Type :qa! and press <Enter> to abandon all changes and exit Vim"
+msgstr ":qa! ìž…ë ¥ í›„ì— <엔터> 키를 누르시면 ìˆ˜ì •ì„ ì·¨ì†Œí•˜ê³  ë¹”ì„ ì¢…ë£Œí•©ë‹ˆë‹¤"
+
+#, c-format
+msgid "1 line %sed 1 time"
+msgstr "1 line %sed 1 time"
+
+#, c-format
+msgid "1 line %sed %d times"
+msgstr "1 line %sed %d times"
+
+#, c-format
+msgid "%ld lines %sed 1 time"
+msgstr "%ld lines %sed 1 time"
+
+#, c-format
+msgid "%ld lines %sed %d times"
+msgstr "%ld lines %sed %d times"
+
+#, c-format
+msgid "%ld lines to indent... "
+msgstr "%ld lines to indent... "
+
+msgid "1 line indented "
+msgstr "1 line indented "
+
+#, c-format
+msgid "%ld lines indented "
+msgstr "%ld lines indented "
+
+#~ msgid "E748: No previously used register"
+#~ msgstr ""
+
+msgid "cannot yank; delete anyway"
+msgstr "cannot yank; delete anyway"
+
+msgid "1 line changed"
+msgstr "1 line changed"
+
+#, c-format
+msgid "%ld lines changed"
+msgstr "%ld lines changed"
+
+#, c-format
+msgid "freeing %ld lines"
+msgstr "freeing %ld lines"
+
+#, c-format
+msgid " into \"%c"
+msgstr " into \"%c"
+
+#, c-format
+msgid "block of 1 line yanked%s"
+msgstr "block of 1 line yanked%s"
+
+#, c-format
+msgid "1 line yanked%s"
+msgstr "1 line yanked%s"
+
+#, c-format
+msgid "block of %ld lines yanked%s"
+msgstr "block of %ld lines yanked%s"
+
+#, c-format
+msgid "%ld lines yanked%s"
+msgstr "%ld lines yanked%s"
+
+#, c-format
+msgid "E353: Nothing in register %s"
+msgstr "E353: %s ë ˆì§€ìŠ¤í„°ì— ì•„ë¬´ ê²ƒë„ ì—†ìŠµë‹ˆë‹¤"
+
+msgid ""
+"\n"
+"--- Registers ---"
+msgstr ""
+"\n"
+"--- 레지스터 ---"
+
+msgid "Illegal register name"
+msgstr "ì´ìƒí•œ 레지스터 ì´ë¦„"
+
+msgid ""
+"\n"
+"# Registers:\n"
+msgstr ""
+"\n"
+"# 레지스터:\n"
+
+#, c-format
+msgid "E574: Unknown register type %d"
+msgstr "E574: 모르는 레지스터 í˜•ì‹ %d"
+
+#~ msgid ""
+#~ "E883: search pattern and expression register may not contain two or more "
+#~ "lines"
+#~ msgstr ""
+
+#, c-format
+msgid "%ld Cols; "
+msgstr "%ld ì—´; "
+
+#, c-format
+msgid "Selected %s%ld of %ld Lines; %lld of %lld Words; %lld of %lld Bytes"
+msgstr "Selected %s%ld of %ld Lines; %lld of %lld Words; %lld of %lld Bytes"
+
+#, c-format
+msgid ""
+"Selected %s%ld of %ld Lines; %lld of %lld Words; %lld of %lld Chars; %lld of "
+"%lld Bytes"
+msgstr ""
+"Selected %s%ld of %ld Lines; %lld of %lld Words; %lld of %lld Chars; %lld of "
+"%lld Bytes"
+
+#, c-format
+msgid "Col %s of %s; Line %ld of %ld; Word %lld of %lld; Byte %lld of %lld"
+msgstr "Col %s of %s; Line %ld of %ld; Word %lld of %lld; Byte %lld of %lld"
+
+#, c-format
+msgid ""
+"Col %s of %s; Line %ld of %ld; Word %lld of %lld; Char %lld of %lld; Byte "
+"%lld of %lld"
+msgstr ""
+"Col %s of %s; Line %ld of %ld; Word %lld of %lld; Char %lld of %lld; Byte "
+"%lld of %lld"
+
+#, c-format
+#~ msgid "(+%lld for BOM)"
+#~ msgstr ""
+
+msgid "Thanks for flying Vim"
+msgstr "ë¹”ì„ ë‚ ê²Œ í•´ 주셔서 고맙습니다"
+
+msgid "E518: Unknown option"
+msgstr "E518: 모르는 옵션"
+
+msgid "E519: Option not supported"
+msgstr "E519: 지ì›ë˜ì§€ 않는 옵션입니다"
+
+msgid "E520: Not allowed in a modeline"
+msgstr "E520: 모드ë¼ì¸ì—ì„œ ì‚¬ìš©ë  ìˆ˜ 없습니다"
+
+msgid "E846: Key code not set"
+msgstr "E846: 키 코드가 설정ë˜ì§€ 않았습니다"
+
+msgid "E521: Number required after ="
+msgstr "E521: = ë’¤ì— ìˆ«ìžê°€ 필요합니다"
+
+msgid "E522: Not found in termcap"
+msgstr "E522: termcapì—ì„œ ì°¾ì„ ìˆ˜ 없습니다"
+
+#, c-format
+msgid "E539: Illegal character <%s>"
+msgstr "E539: ì´ìƒí•œ ê¸€ìž <%s>"
+
+#, c-format
+#~ msgid "For option %s"
+#~ msgstr ""
+
+msgid "E529: Cannot set 'term' to empty string"
+msgstr "E529: 'term'ì„ ë¹ˆ 문ìžì—´ë¡œ 설정할 수 없습니다"
+
+msgid "E530: Cannot change term in GUI"
+msgstr "E530: GUIì—서는 termì„ ë°”ê¿€ 수 없습니다"
+
+msgid "E531: Use \":gui\" to start the GUI"
+msgstr "E531: GUI를 시작하려면 \":gui\"를 사용하십시오"
+
+msgid "E589: 'backupext' and 'patchmode' are equal"
+msgstr "E589: 'backupext'와 'patchmode'ê°€ ë™ì¼í•©ë‹ˆë‹¤"
+
+msgid "E834: Conflicts with value of 'listchars'"
+msgstr "E834: 'listchars' ê°’ê³¼ 충ëŒì´ ë°œìƒí•©ë‹ˆë‹¤"
+
+msgid "E835: Conflicts with value of 'fillchars'"
+msgstr "E835: 'fillchars' ê°’ê³¼ 충ëŒì´ ë°œìƒí•©ë‹ˆë‹¤"
+
+msgid "E617: Cannot be changed in the GTK+ 2 GUI"
+msgstr "E617: GTK+ 2 GUIì—서는 바뀔 수 없습니다"
+
+#, c-format
+#~ msgid "E950: Cannot convert between %s and %s"
+#~ msgstr ""
+
+msgid "E524: Missing colon"
+msgstr "E524: ì½œë¡ ì´ ì—†ìŠµë‹ˆë‹¤"
+
+msgid "E525: Zero length string"
+msgstr "E525: 빈 문ìžì—´ìž…니다"
+
+#, c-format
+msgid "E526: Missing number after <%s>"
+msgstr "E526: <%s> ë’¤ì— ìˆ«ìžê°€ 없습니다"
+
+msgid "E527: Missing comma"
+msgstr "E527: 콤마가 없습니다"
+
+msgid "E528: Must specify a ' value"
+msgstr "E528: ' ê°’ì„ ëª…ì‹œí•´ 주셔야 합니다"
+
+msgid "E595: contains unprintable or wide character"
+msgstr "E595: 출력할 수 없는, í˜¹ì€ ì™€ì´ë“œ 문ìžë¥¼ í¬í•¨í•˜ê³  있습니다"
+
+msgid "E596: Invalid font(s)"
+msgstr "E596: ìž˜ëª»ëœ ê¸€ê¼´(들)"
+
+msgid "E597: can't select fontset"
+msgstr "E597: ê¸€ê¼´ì…‹ì„ ê³ ë¥¼ 수 없습니다"
+
+msgid "E598: Invalid fontset"
+msgstr "E598: ìž˜ëª»ëœ ê¸€ê¼´ì…‹"
+
+msgid "E533: can't select wide font"
+msgstr "E533: 와ì´ë“œ ê¸€ê¼´ì„ ê³ ë¥¼ 수 없습니다"
+
+msgid "E534: Invalid wide font"
+msgstr "E534: ìž˜ëª»ëœ ì™€ì´ë“œ 글꼴"
+
+#, c-format
+msgid "E535: Illegal character after <%c>"
+msgstr "E535: <%c> ë’¤ì— ì´ìƒí•œ 글ìž"
+
+msgid "E536: comma required"
+msgstr "E536: 콤마가 필요합니다"
+
+#, c-format
+msgid "E537: 'commentstring' must be empty or contain %s"
+msgstr "E537: 'commentstring'ì€ ë¹„ê±°ë‚˜ %sì„(를) í¬í•¨í•´ì•¼ 합니다"
+
+msgid "E538: No mouse support"
+msgstr "E538: 마우스를 지ì›í•˜ì§€ 않습니다"
+
+msgid "E540: Unclosed expression sequence"
+msgstr "E540: 닫히지 ì•Šì€ í‘œí˜„ì‹ ë°°ì—´"
+
+msgid "E541: too many items"
+msgstr "E541: 너무 ë§Žì€ í•­ëª©"
+
+msgid "E542: unbalanced groups"
+msgstr "E542: ê· í˜•ì´ ì•ˆ 잡힌 그룹"
+
+#~ msgid "E946: Cannot make a terminal with running job modifiable"
+#~ msgstr ""
+
+msgid "E590: A preview window already exists"
+msgstr "E590: 미리 보기 ì°½ì´ ì´ë¯¸ 존재합니다"
+
+msgid "W17: Arabic requires UTF-8, do ':set encoding=utf-8'"
+msgstr "W17: Arabicì€ UTF-8 ì¸ì½”딩 í•„ìš”, ':set encoding=utf-8' 하세요"
+
+msgid "E954: 24-bit colors are not supported on this environment"
+msgstr "E954: ì´ í™˜ê²½ì—서는 24비트 색ìƒì´ 지ì›ë˜ì§€ 않습니다"
+
+#, c-format
+msgid "E593: Need at least %d lines"
+msgstr "E593: ì ì–´ë„ %d ì¤„ì´ í•„ìš”í•©ë‹ˆë‹¤"
+
+#, c-format
+msgid "E594: Need at least %d columns"
+msgstr "E594: ì ì–´ë„ %d ì¹¸ì´ í•„ìš”í•©ë‹ˆë‹¤"
+
+#, c-format
+msgid "E355: Unknown option: %s"
+msgstr "E355: 모르는 옵션: %s"
+
+#, c-format
+msgid "E521: Number required: &%s = '%s'"
+msgstr "E521: 숫ìžê°€ í•„ìš”: &%s = '%s'"
+
+msgid ""
+"\n"
+"--- Terminal codes ---"
+msgstr ""
+"\n"
+"--- í„°ë¯¸ë„ ì½”ë“œ ---"
+
+msgid ""
+"\n"
+"--- Global option values ---"
+msgstr ""
+"\n"
+"--- 전역 옵션 값 ---"
+
+msgid ""
+"\n"
+"--- Local option values ---"
+msgstr ""
+"\n"
+"--- 지역 옵션 값 ---"
+
+msgid ""
+"\n"
+"--- Options ---"
+msgstr ""
+"\n"
+"--- 옵션 ---"
+
+msgid "E356: get_varp ERROR"
+msgstr "E356: get_varp ì—러"
+
+#, c-format
+msgid "E357: 'langmap': Matching character missing for %s"
+msgstr "E357: 'langmap': %sì— ëŒ€í•œ 맞는 글ìžê°€ 없습니다"
+
+#, c-format
+msgid "E358: 'langmap': Extra characters after semicolon: %s"
+msgstr "E358: 'langmap': 세미콜론 ë’¤ì— ê¸€ìžê°€ ë” ìžˆìŒ: %s"
+
+msgid "cannot open "
+msgstr "cannot open "
+
+msgid "VIM: Can't open window!\n"
+msgstr "ë¹”: ì°½ì„ ì—´ 수 없습니다!\n"
+
+msgid "Need Amigados version 2.04 or later\n"
+msgstr "아미가ë„스 2.04나 ë” ë†’ì€ íŒì´ 필요합니다\n"
+
+#, c-format
+msgid "Need %s version %ld\n"
+msgstr "Need %s version %ld\n"
+
+msgid "Cannot open NIL:\n"
+msgstr "NILì„ ì—´ 수 ì—†ìŒ:\n"
+
+msgid "Cannot create "
+msgstr "Cannot create "
+
+#, c-format
+msgid "Vim exiting with %d\n"
+msgstr "ë¹”ì´ %d 값으로 ë냅니다\n"
+
+msgid "cannot change console mode ?!\n"
+msgstr "콘솔 ìƒíƒœë¥¼ 바꿀 수 없습니다 ?!\n"
+
+msgid "mch_get_shellsize: not a console??\n"
+msgstr "mch_get_shellsize: ì½˜ì†”ì´ ì•„ë‹Œê°€??\n"
+
+msgid "E360: Cannot execute shell with -f option"
+msgstr "E360: -f ì˜µì…˜ì´ ì‚¬ìš©ëœ ê²½ìš° ì‰˜ì„ ì‹¤í–‰í•  수 없습니다"
+
+msgid "Cannot execute "
+msgstr "Cannot execute "
+
+msgid "shell "
+msgstr "shell "
+
+msgid " returned\n"
+msgstr " returned\n"
+
+msgid "ANCHOR_BUF_SIZE too small."
+msgstr "ANCHOR_BUF_SIZE가 너무 작습니다."
+
+msgid "I/O ERROR"
+msgstr "I/O ì—러"
+
+msgid "Message"
+msgstr "메시지"
+
+msgid "E237: Printer selection failed"
+msgstr "E237: 프린터를 고르지 못했습니다"
+
+#, c-format
+msgid "to %s on %s"
+msgstr "to %s on %s"
+
+#, c-format
+msgid "E613: Unknown printer font: %s"
+msgstr "E613: 모르는 프린터 글꼴: %s"
+
+#, c-format
+msgid "E238: Print error: %s"
+msgstr "E238: ì¸ì‡„ ì—러: %s"
+
+#, c-format
+msgid "Printing '%s'"
+msgstr "'%s' ì¸ì‡„중"
+
+#, c-format
+msgid "E244: Illegal charset name \"%s\" in font name \"%s\""
+msgstr "E244: ìž˜ëª»ëœ ê¸€ìžì…‹ ì´ë¦„ \"%s\"ì´(ê°€) 글꼴 ì´ë¦„ \"%s\"ì— ìžˆìŠµë‹ˆë‹¤"
+
+#, c-format
+msgid "E244: Illegal quality name \"%s\" in font name \"%s\""
+msgstr "E244: ìž˜ëª»ëœ í€„ëŸ¬í‹° ì´ë¦„ \"%s\"ì´(ê°€) 글꼴 ì´ë¦„ \"%s\"ì— ìžˆìŠµë‹ˆë‹¤"
+
+#, c-format
+msgid "E245: Illegal char '%c' in font name \"%s\""
+msgstr "E245: ìž˜ëª»ëœ ê¸€ìž '%c'ì´(ê°€) 글꼴 ì´ë¦„ \"%s\"ì— ìžˆìŠµë‹ˆë‹¤"
+
+#, c-format
+msgid "Opening the X display took %ld msec"
+msgstr "X 디스플레ì´ë¥¼ 여는 ë° %ld msecì´ ê±¸ë ¸ìŠµë‹ˆë‹¤"
+
+msgid ""
+"\n"
+"Vim: Got X error\n"
+msgstr ""
+"\n"
+"ë¹”: X ì—러가 ìƒê²¼ìŠµë‹ˆë‹¤\n"
+
+msgid "Testing the X display failed"
+msgstr "X ë””ìŠ¤í”Œë ˆì´ ì‹œí—˜ì´ ì‹¤íŒ¨í–ˆìŠµë‹ˆë‹¤"
+
+msgid "Opening the X display timed out"
+msgstr "X 디스플레ì´ë¥¼ 열다가 ì‹œê°„ì´ ì´ˆê³¼ë˜ì—ˆìŠµë‹ˆë‹¤"
+
+msgid ""
+"\n"
+"Could not get security context for "
+msgstr ""
+"\n"
+"Could not get security context for "
+
+msgid ""
+"\n"
+"Could not set security context for "
+msgstr ""
+"\n"
+"Could not set security context for "
+
+#, c-format
+#~ msgid "Could not set security context %s for %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Could not get security context %s for %s. Removing it!"
+#~ msgstr ""
+
+msgid ""
+"\n"
+"Cannot execute shell sh\n"
+msgstr ""
+"\n"
+"쉘 sh를 실행할 수 없습니다\n"
+
+msgid ""
+"\n"
+"shell returned "
+msgstr ""
+"\n"
+"shell returned "
+
+msgid ""
+"\n"
+"Cannot create pipes\n"
+msgstr ""
+"\n"
+"파ì´í”„를 만들 수 없습니다\n"
+
+msgid ""
+"\n"
+"Cannot fork\n"
+msgstr ""
+"\n"
+"ìžì‹ 프로세스를 만들 수 없습니다\n"
+
+msgid ""
+"\n"
+"Cannot execute shell "
+msgstr ""
+"\n"
+"Cannot execute shell "
+
+msgid ""
+"\n"
+"Command terminated\n"
+msgstr ""
+"\n"
+"ëª…ë ¹ì´ ë마ì³ì¡ŒìŠµë‹ˆë‹¤\n"
+
+msgid "XSMP lost ICE connection"
+msgstr "XSMPê°€ ICE ì—°ê²°ì„ ìžƒì–´ë²„ë ¸ìŠµë‹ˆë‹¤"
+
+#, c-format
+msgid "dlerror = \"%s\""
+msgstr "dlerror = \"%s\""
+
+msgid "Opening the X display failed"
+msgstr "X ë””ìŠ¤í”Œë ˆì´ ì—´ê¸°ê°€ 실패했습니다"
+
+msgid "XSMP handling save-yourself request"
+msgstr "XSMPê°€ save-yourself ìš”ì²­ì„ ì‹¤í–‰í•˜ê³  있습니다"
+
+msgid "XSMP opening connection"
+msgstr "XSMPê°€ ì—°ê²°ì„ ì—¬ëŠ” 중입니다"
+
+msgid "XSMP ICE connection watch failed"
+msgstr "XSMPê°€ ICE ì—°ê²° ê°ì‹œë¥¼ 실패했습니다"
+
+#, c-format
+msgid "XSMP SmcOpenConnection failed: %s"
+msgstr "XSMP SmcOpenConnection 실패: %s"
+
+msgid "At line"
+msgstr "At line"
+
+msgid "Could not load vim32.dll!"
+msgstr "vim32.dllì„ ë¶ˆëŸ¬ ë“¤ì¼ ìˆ˜ 없습니다!"
+
+msgid "VIM Error"
+msgstr "ë¹” ì—러"
+
+msgid "Could not fix up function pointers to the DLL!"
+msgstr "함수 í¬ì¸í„°ë¥¼ DLLë¡œ 바꿀 수 없습니다!"
+
+#, c-format
+msgid "Vim: Caught %s event\n"
+msgstr "ë¹”: %s ì´ë²¤íŠ¸ë¥¼ 잡았습니다\n"
+
+msgid "close"
+msgstr "닫기"
+
+msgid "logoff"
+msgstr "로그아웃"
+
+msgid "shutdown"
+msgstr "셧다운"
+
+msgid "E371: Command not found"
+msgstr "E371: ëª…ë ¹ì„ ì°¾ì„ ìˆ˜ 없습니다"
+
+msgid ""
+"VIMRUN.EXE not found in your $PATH.\n"
+"External commands will not pause after completion.\n"
+"See :help win32-vimrun for more information."
+msgstr ""
+"VIMRUN.EXE를 $PATHì—ì„œ ì°¾ì„ ìˆ˜ 없습니다.\n"
+"외부 ëª…ë ¹ì´ ëë‚œ ë’¤ 멈출 수 없습니다.\n"
+"다 ë§Žì€ ì •ë³´ë¥¼ 보시려면 :help win32-vimrunì„ ë³´ì‹­ì‹œì˜¤."
+
+msgid "Vim Warning"
+msgstr "빔 경고"
+
+#, c-format
+msgid "shell returned %d"
+msgstr "ì‰˜ì´ %dì„(를) ëŒë ¤ì£¼ì—ˆìŠµë‹ˆë‹¤"
+
+msgid "E926: Current location list was changed"
+msgstr "E926: í˜„ìž¬ì˜ location listê°€ 바뀌었습니다"
+
+#, c-format
+msgid "E372: Too many %%%c in format string"
+msgstr "E372: í˜•ì‹ ë¬¸ìžì—´ì— %%%cì´(ê°€) 너무 많습니다"
+
+#, c-format
+msgid "E373: Unexpected %%%c in format string"
+msgstr "E373: í˜•ì‹ ë¬¸ìžì—´ì— %%%cì´(ê°€) 잘못ë˜ì—ˆìŠµë‹ˆë‹¤"
+
+msgid "E374: Missing ] in format string"
+msgstr "E374: í˜•ì‹ ë¬¸ìžì—´ì— ]ê°€ 없습니다"
+
+#, c-format
+msgid "E375: Unsupported %%%c in format string"
+msgstr "E375: í˜•ì‹ ë¬¸ìžì—´ì— 지ì›ë˜ì§€ 않는 %%%cì´(ê°€) 있습니다"
+
+#, c-format
+msgid "E376: Invalid %%%c in format string prefix"
+msgstr "E376: í˜•ì‹ ë¬¸ìžì—´ ì„œë‘ì— ìž˜ëª»ëœ %%%cì´(ê°€) 있습니다"
+
+#, c-format
+msgid "E377: Invalid %%%c in format string"
+msgstr "E377: í˜•ì‹ ë¬¸ìžì—´ì— ìž˜ëª»ëœ %%%cì´(ê°€) 있습니다"
+
+msgid "E378: 'errorformat' contains no pattern"
+msgstr "E378: 'errorformat'ì´ ì–´ë–¤ íŒ¨í„´ë„ í¬í•¨í•˜ê³  있지 않습니다"
+
+msgid "E379: Missing or empty directory name"
+msgstr "E379: 빠졌거나 빈 디렉토리 ì´ë¦„"
+
+msgid "E553: No more items"
+msgstr "E553: ë” ì´ìƒì˜ í•­ëª©ì´ ì—†ìŠµë‹ˆë‹¤"
+
+msgid "E924: Current window was closed"
+msgstr "E924: 현재 ì°½ì´ ë‹«í˜”ìŠµë‹ˆë‹¤"
+
+msgid "E925: Current quickfix was changed"
+msgstr "E925: í˜„ìž¬ì˜ quickfixê°€ 바뀌었습니다"
+
+#, c-format
+msgid "(%d of %d)%s%s: "
+msgstr "(%d of %d)%s%s: "
+
+msgid " (line deleted)"
+msgstr " (ì¤„ì„ ì§€ì› ìŒ)"
+
+#, c-format
+msgid "%serror list %d of %d; %d errors "
+msgstr "%serror list %d of %d; %d errors "
+
+msgid "E380: At bottom of quickfix stack"
+msgstr "E380: 퀵픽스 스íƒì˜ 바닥입니다"
+
+msgid "E381: At top of quickfix stack"
+msgstr "E381: 퀵픽스 스íƒì˜ 꼭대기입니다"
+
+#~ msgid "No entries"
+#~ msgstr ""
+
+msgid "Error file"
+msgstr "ì—러 파ì¼"
+
+msgid "E683: File name missing or invalid pattern"
+msgstr "E683: 파ì¼ëª… ëˆ„ë½ í˜¹ì€ ìž˜ëª»ëœ íŒ¨í„´"
+
+#, c-format
+msgid "Cannot open file \"%s\""
+msgstr "\"%s\" 파ì¼ì„ ì—´ 수 없습니다"
+
+msgid "E681: Buffer is not loaded"
+msgstr "E681: 버í¼ê°€ 로드ë˜ì§€ 않았습니다"
+
+msgid "E777: String or List expected"
+msgstr "E777: Stringì´ë‚˜ Listê°€ 있어야 함"
+
+#, c-format
+msgid "E369: invalid item in %s%%[]"
+msgstr "E369: %s%%[]ì— ìž˜ëª»ëœ í•­ëª©"
+
+#, c-format
+msgid "E769: Missing ] after %s["
+msgstr "E769: %s[ ë’¤ì— ]ê°€ 없습니다"
+
+#~ msgid "E944: Reverse range in character class"
+#~ msgstr ""
+
+#~ msgid "E945: Range too large in character class"
+#~ msgstr ""
+
+#, c-format
+msgid "E53: Unmatched %s%%("
+msgstr "E53: 맞지 않는 %s%%("
+
+#, c-format
+msgid "E54: Unmatched %s("
+msgstr "E54: 맞지 않는 %s("
+
+#, c-format
+msgid "E55: Unmatched %s)"
+msgstr "E55: 맞지 않는 %s)"
+
+msgid "E66: \\z( not allowed here"
+msgstr "E66: \\z(는 여기ì—ì„œ 허용ë˜ì§€ 않습니다"
+
+msgid "E67: \\z1 - \\z9 not allowed here"
+msgstr "E67: \\z1 ë“±ì€ ì—¬ê¸°ì—ì„œ 허용ë˜ì§€ 않습니다"
+
+#, c-format
+msgid "E69: Missing ] after %s%%["
+msgstr "E69: %s%%[ ë’¤ì— ]ê°€ 없습니다"
+
+#, c-format
+msgid "E70: Empty %s%%[]"
+msgstr "E70: 빈 %s%%[]"
+
+msgid "E65: Illegal back reference"
+msgstr "E65: ì´ìƒí•œ 후위 참조"
+
+msgid "E339: Pattern too long"
+msgstr "E339: íŒ¨í„´ì´ ë„ˆë¬´ ê¹ë‹ˆë‹¤"
+
+msgid "E50: Too many \\z("
+msgstr "E50: \\z(가 너무 많습니다"
+
+#, c-format
+msgid "E51: Too many %s("
+msgstr "E51: %s(가 너무 많습니다"
+
+msgid "E52: Unmatched \\z("
+msgstr "E52: 맞지 않는 \\z("
+
+#, c-format
+msgid "E59: invalid character after %s@"
+msgstr "E59: %s@ ë’¤ì— ìž˜ëª»ëœ ë¬¸ìž"
+
+#, c-format
+msgid "E60: Too many complex %s{...}s"
+msgstr "E60: %s{...}sê°€ 너무 많ìŒ"
+
+#, c-format
+msgid "E61: Nested %s*"
+msgstr "E61: Nested %s*"
+
+#, c-format
+msgid "E62: Nested %s%c"
+msgstr "E62: Nested %s%c"
+
+msgid "E63: invalid use of \\_"
+msgstr "E63: \\_를 잘 못 사용"
+
+#, c-format
+msgid "E64: %s%c follows nothing"
+msgstr "E64: %s%c ë’¤ì— ì•„ë¬´ê²ƒë„ ì—†ìŠµë‹ˆë‹¤"
+
+msgid "E68: Invalid character after \\z"
+msgstr "E68: \\z ë’¤ì— ì´ìƒí•œ 문ìž"
+
+#, c-format
+msgid "E678: Invalid character after %s%%[dxouU]"
+msgstr "E678: %s%%[dxouU] ë’¤ì— ì´ìƒí•œ 문ìž"
+
+#, c-format
+msgid "E71: Invalid character after %s%%"
+msgstr "E71: %s%% ë’¤ì— ì´ìƒí•œ 문ìž"
+
+#, c-format
+msgid "E554: Syntax error in %s{...}"
+msgstr "E554: %s{...}ì— êµ¬ë¬¸ ì—러"
+
+msgid "External submatches:\n"
+msgstr "외부 submatches:\n"
+
+#, c-format
+msgid "E888: (NFA regexp) cannot repeat %s"
+msgstr "E888: (NFA 정규표현ì‹) %sì„(를) 반복할 수 없습니다"
+
+#~ msgid ""
+#~ "E864: \\%#= can only be followed by 0, 1, or 2. The automatic engine will be "
+#~ "used "
+#~ msgstr ""
+
+#~ msgid "Switching to backtracking RE engine for pattern: "
+#~ msgstr ""
+
+#~ msgid "E865: (NFA) Regexp end encountered prematurely"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E866: (NFA regexp) Misplaced %c"
+#~ msgstr ""
+
+#, c-format
+msgid "E877: (NFA regexp) Invalid character class: %ld"
+msgstr "E877: (NFA 정규표현ì‹) 비정ìƒì ì¸ ë¬¸ìž í´ëž˜ìŠ¤: %ld"
+
+#, c-format
+msgid "E867: (NFA) Unknown operator '\\z%c'"
+msgstr "E867: (NFA) 모르는 오í¼ë ˆì´í„° '\\z%c'"
+
+msgid "E951: \\% value too large"
+msgstr "E951: \\% ê°’ì´ ë„ˆë¬´ ê¹ë‹ˆë‹¤"
+
+#, c-format
+msgid "E867: (NFA) Unknown operator '\\%%%c'"
+msgstr "E867: (NFA) 모르는 오í¼ë ˆì´í„° '\\%%%c'"
+
+msgid "E868: Error building NFA with equivalence class!"
+msgstr "E868: Error building NFA with equivalence class!"
+
+#, c-format
+msgid "E869: (NFA) Unknown operator '\\@%c'"
+msgstr "E869: (NFA) 모르는 오í¼ë ˆì´í„° '\\@%c'"
+
+#~ msgid "E870: (NFA regexp) Error reading repetition limits"
+#~ msgstr ""
+
+#~ msgid "E871: (NFA regexp) Can't have a multi follow a multi"
+#~ msgstr ""
+
+msgid "E872: (NFA regexp) Too many '('"
+msgstr "E872: (NFA 정규표현ì‹) '('ê°€ 너무 많습니다"
+
+msgid "E879: (NFA regexp) Too many \\z("
+msgstr "E879: (NFA 정규표현ì‹) \\z(ê°€ 너무 많습니다"
+
+#~ msgid "E873: (NFA regexp) proper termination error"
+#~ msgstr ""
+
+msgid "Could not open temporary log file for writing, displaying on stderr... "
+msgstr "쓰기위한 ìž„ì‹œ 로그 파ì¼ì„ ì—´ 수 없습니다, 표준ì—러(stderr)ì— í‘œì‹œí•©ë‹ˆë‹¤..."
+
+msgid "E874: (NFA) Could not pop the stack!"
+msgstr "E874: (NFA) 스íƒì—ì„œ 꺼낼 수 없습니다!"
+
+#~ msgid ""
+#~ "E875: (NFA regexp) (While converting from postfix to NFA), too many states "
+#~ "left on stack"
+#~ msgstr ""
+
+#~ msgid "E876: (NFA regexp) Not enough space to store the whole NFA "
+#~ msgstr ""
+
+#~ msgid "E878: (NFA) Could not allocate memory for branch traversal!"
+#~ msgstr ""
+
+msgid " VREPLACE"
+msgstr " ì„ íƒì¹˜í™˜"
+
+msgid " REPLACE"
+msgstr " 바꾸기"
+
+msgid " REVERSE"
+msgstr " 반대"
+
+msgid " INSERT"
+msgstr " ë¼ì›Œë„£ê¸°"
+
+msgid " (insert)"
+msgstr " (ë¼ì›Œë„£ê¸°)"
+
+msgid " (replace)"
+msgstr " (바꾸기)"
+
+msgid " (vreplace)"
+msgstr " (ì„ íƒì¹˜í™˜)"
+
+msgid " Hebrew"
+msgstr " 헤브루"
+
+msgid " Arabic"
+msgstr " ì•„ë¼ë¹„ì•„"
+
+msgid " (paste)"
+msgstr " (붙ì´ê¸°)"
+
+msgid " VISUAL"
+msgstr " 비주얼"
+
+msgid " VISUAL LINE"
+msgstr " 비주얼 ë¼ì¸"
+
+msgid " VISUAL BLOCK"
+msgstr " 비주얼 블ë¡"
+
+msgid " SELECT"
+msgstr " 고르기"
+
+msgid " SELECT LINE"
+msgstr " ë¼ì¸ 고르기"
+
+msgid " SELECT BLOCK"
+msgstr " ë¸”ë¡ ê³ ë¥´ê¸°"
+
+msgid "recording"
+msgstr "기ë¡ì¤‘"
+
+#, c-format
+msgid "E383: Invalid search string: %s"
+msgstr "E383: ìž˜ëª»ëœ ì°¾ê¸° 문ìžì—´: %s"
+
+#, c-format
+msgid "E384: search hit TOP without match for: %s"
+msgstr "E384: 처ìŒê¹Œì§€ 맞는 문ìžì—´ì´ 없습니다: %s"
+
+#, c-format
+msgid "E385: search hit BOTTOM without match for: %s"
+msgstr "E385: ë까지 맞는 문ìžì—´ì´ 없습니다: %s"
+
+msgid "E386: Expected '?' or '/' after ';'"
+msgstr "E386: ';' ë’¤ì—는 '?'나 '/'ê°€ 와야 합니다"
+
+msgid " (includes previously listed match)"
+msgstr " (ì´ì „ì— ë§žì•˜ë˜ ëª©ë¡ í¬í•¨)"
+
+msgid "--- Included files "
+msgstr "--- Included files "
+
+msgid "not found "
+msgstr "not found "
+
+msgid "in path ---\n"
+msgstr "in path ---\n"
+
+msgid " (Already listed)"
+msgstr " (Already listed)"
+
+msgid " NOT FOUND"
+msgstr " 못 찾았ìŒ"
+
+#, c-format
+msgid "Scanning included file: %s"
+msgstr "í¬í•¨ëœ íŒŒì¼ ì°¾ëŠ” 중: %s"
+
+#, c-format
+msgid "Searching included file %s"
+msgstr "í¬í•¨ëœ íŒŒì¼ %s 찾는 중"
+
+msgid "E387: Match is on current line"
+msgstr "E387: 맞는 게 현재 ì¤„ì— ìžˆìŠµë‹ˆë‹¤"
+
+msgid "All included files were found"
+msgstr "모든 í¬í•¨ëœ 파ì¼ì„ 찾았습니다"
+
+msgid "No included files"
+msgstr "í¬í•¨ëœ 파ì¼ì´ 없습니다"
+
+msgid "E388: Couldn't find definition"
+msgstr "E388: ì •ì˜ë¥¼ ì°¾ì„ ìˆ˜ 없습니다"
+
+msgid "E389: Couldn't find pattern"
+msgstr "E389: íŒ¨í„´ì„ ì°¾ì„ ìˆ˜ 없습니다"
+
+msgid "Substitute "
+msgstr "Substitute "
+
+#, c-format
+msgid ""
+"\n"
+"# Last %sSearch Pattern:\n"
+"~"
+msgstr ""
+"\n"
+"# Last %sSearch Pattern:\n"
+"~"
+
+msgid "E756: Spell checking is not enabled"
+msgstr "E756: 맞춤법 검사가 활성화ë˜ì–´ 있지 않습니다"
+
+#, c-format
+msgid "Warning: Cannot find word list \"%s_%s.spl\" or \"%s_ascii.spl\""
+msgstr "경고: 단어 ëª©ë¡ \"%s_%s.spl\" í˜¹ì€ \"%s_ascii.spl\"ì„ ì°¾ì„ ìˆ˜ 없습니다"
+
+#, c-format
+msgid "Warning: Cannot find word list \"%s.%s.spl\" or \"%s.ascii.spl\""
+msgstr "경고: 단어 ëª©ë¡ \"%s.%s.spl\" í˜¹ì€ \"%s.ascii.spl\"ì„ ì°¾ì„ ìˆ˜ 없습니다"
+
+msgid "E797: SpellFileMissing autocommand deleted buffer"
+msgstr "E797: SpellFileMissing autocommandê°€ 버í¼ë¥¼ 삭제했습니다"
+
+#, c-format
+msgid "Warning: region %s not supported"
+msgstr "경고: %s ì˜ì—­ì€ 지ì›ë˜ì§€ 않습니다"
+
+msgid "Sorry, no suggestions"
+msgstr "죄송, 제안할 게 없습니다"
+
+#, c-format
+msgid "Sorry, only %ld suggestions"
+msgstr "죄송, %ld개만 제안"
+
+#, c-format
+msgid "Change \"%.*s\" to:"
+msgstr "Change \"%.*s\" to:"
+
+#, c-format
+msgid " < \"%.*s\""
+msgstr " < \"%.*s\""
+
+msgid "E752: No previous spell replacement"
+msgstr "E752: ì² ìžê°€ ë°”ë€ì ì´ 없습니다"
+
+#, c-format
+msgid "E753: Not found: %s"
+msgstr "E753: ì°¾ì„ ìˆ˜ ì—†ìŒ: %s"
+
+msgid "E758: Truncated spell file"
+msgstr "E758: 잘린 spell 파ì¼"
+
+#, c-format
+msgid "Trailing text in %s line %d: %s"
+msgstr "Trailing text in %s line %d: %s"
+
+#, c-format
+msgid "Affix name too long in %s line %d: %s"
+msgstr "Affix name too long in %s line %d: %s"
+
+msgid "E761: Format error in affix file FOL, LOW or UPP"
+msgstr "E761: affix íŒŒì¼ FOL, LOW í˜¹ì€ UPPì— í˜•ì‹ ì—러"
+
+msgid "E762: Character in FOL, LOW or UPP is out of range"
+msgstr "E762: FOL, LOW í˜¹ì€ UPPì˜ ë¬¸ìžê°€ 범위를 벗어남"
+
+msgid "Compressing word tree..."
+msgstr "단어 트리 압축중..."
+
+#, c-format
+msgid "Reading spell file \"%s\""
+msgstr "spell íŒŒì¼ \"%s\"ì„(를) ì½ê³  있습니다"
+
+msgid "E757: This does not look like a spell file"
+msgstr "E757: spell 파ì¼ì´ ì•„ë‹Œ 것 같습니다"
+
+msgid "E771: Old spell file, needs to be updated"
+msgstr "E771: ì˜¤ëž˜ëœ spell 파ì¼, ê°±ì‹ ì´ í•„ìš”í•©ë‹ˆë‹¤"
+
+msgid "E772: Spell file is for newer version of Vim"
+msgstr "E772: Spell 파ì¼ì´ 새 ë²„ì ¼ì˜ Vim용입니다"
+
+msgid "E770: Unsupported section in spell file"
+msgstr "E770: spell 파ì¼ì— 지ì›ë˜ì§€ 않는 섹션"
+
+#, c-format
+msgid "E778: This does not look like a .sug file: %s"
+msgstr "E778: .sug 파ì¼ì´ ì•„ë‹Œ 것 ê°™ìŒ: %s"
+
+#, c-format
+msgid "E779: Old .sug file, needs to be updated: %s"
+msgstr "E779: ì˜¤ëž˜ëœ .sug 파ì¼, 갱신 í•„ìš”: %s"
+
+#, c-format
+msgid "E780: .sug file is for newer version of Vim: %s"
+msgstr "E780: .sug 파ì¼ì´ 새 ë²„ì ¼ì˜ Vimìš©ìž„: %s"
+
+#, c-format
+msgid "E781: .sug file doesn't match .spl file: %s"
+msgstr "E781: .sug 파ì¼ì´ .spl 파ì¼ê³¼ 맞지 ì•ŠìŒ: %s"
+
+#, c-format
+msgid "E782: error while reading .sug file: %s"
+msgstr "E782: .sug íŒŒì¼ ì½ê¸° ì—러: %s"
+
+#, c-format
+msgid "Reading affix file %s..."
+msgstr "affix íŒŒì¼ %s ì½ëŠ” 중"
+
+#, c-format
+msgid "Conversion failure for word in %s line %d: %s"
+msgstr "%s ë¼ì¸ %dì— ìžˆëŠ” 단어 변환 실패: %s"
+
+#, c-format
+msgid "Conversion in %s not supported: from %s to %s"
+msgstr "%sì˜ ë³€í™˜ì´ ì§€ì›ë˜ì§€ 않습니다: %sì—ì„œ %së¡œ"
+
+#, c-format
+msgid "Conversion in %s not supported"
+msgstr "%sì˜ ë³€í™˜ì´ ì§€ì›ë˜ì§€ 않습니다"
+
+#, c-format
+msgid "Invalid value for FLAG in %s line %d: %s"
+msgstr "%s ë¼ì¸ %dì— FLAGì— ëŒ€í•œ ìž˜ëª»ëœ ê°’: %s"
+
+#, c-format
+msgid "FLAG after using flags in %s line %d: %s"
+msgstr "%s ë¼ì¸ %dì— í”Œëž˜ê·¸ê°€ ì‚¬ìš©ëœ í›„ FLAG: %s"
+
+#, c-format
+msgid ""
+"Defining COMPOUNDFORBIDFLAG after PFX item may give wrong results in %s line "
+"%d"
+msgstr ""
+"%s ë¼ì¸ %dì— PFX ë’¤ì— COMPOUNDFORBIDFLAGì„ ì •ì˜í•œ ê²ƒì€ ìž˜ëª»ëœ ê²°ê³¼ë¥¼ 초래할 "
+"수 있습니다"
+
+#, c-format
+msgid ""
+"Defining COMPOUNDPERMITFLAG after PFX item may give wrong results in %s line "
+"%d"
+msgstr ""
+"%s ë¼ì¸ %dì— PFX ë’¤ì— COMPOUNDPERMITFLAGì„ ì •ì˜í•œ ê²ƒì€ ìž˜ëª»ëœ ê²°ê³¼ë¥¼ 초래할 "
+"수 있습니다"
+
+#, c-format
+msgid "Wrong COMPOUNDRULES value in %s line %d: %s"
+msgstr "%s ë¼ì¸ %dì— ìž˜ëª»ëœ COMPOUNDRULES ê°’: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDWORDMAX value in %s line %d: %s"
+msgstr "%s ë¼ì¸ %dì— ìž˜ëª»ëœ COMPOUNDWORDMAX ê°’: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDMIN value in %s line %d: %s"
+msgstr "%s ë¼ì¸ %dì— ìž˜ëª»ëœ COMPOUNDMIN ê°’: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDSYLMAX value in %s line %d: %s"
+msgstr "%s ë¼ì¸ %dì— ìž˜ëª»ëœ COMPOUNDSYLMAX ê°’: %s"
+
+#, c-format
+msgid "Wrong CHECKCOMPOUNDPATTERN value in %s line %d: %s"
+msgstr "%s ë¼ì¸ %dì— ìž˜ëª»ëœ CHECKCOMPOUNDPATTERN ê°’: %s"
+
+#, c-format
+msgid "Different combining flag in continued affix block in %s line %d: %s"
+msgstr "%s ë¼ì¸ %dì— ì—°ì†ëœ affix 블ë¡ì— 다른 ê²°í•© 플래그: %s"
+
+#, c-format
+msgid "Duplicate affix in %s line %d: %s"
+msgstr "%s ë¼ì¸ %dì— ì¤‘ë³µëœ affix: %s"
+
+#, c-format
+msgid ""
+"Affix also used for BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST in %s "
+"line %d: %s"
+msgstr ""
+"%s ë¼ì¸ %dì— BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGESTì— ëŒ€í•´ì„œë„ "
+"affixê°€ 사용ë¨: %s"
+
+#, c-format
+msgid "Expected Y or N in %s line %d: %s"
+msgstr "%s ë¼ì¸ %dì— Y나 Nì´ ê¸°ëŒ€ë¨: %s"
+
+#, c-format
+msgid "Broken condition in %s line %d: %s"
+msgstr "%s ë¼ì¸ %dê°€ ë§ê°€ì§„ ìƒíƒœ: %s"
+
+#, c-format
+msgid "Expected REP(SAL) count in %s line %d"
+msgstr "%s ë¼ì¸ %dì— REP(SAL) 카운트가 기대ë¨"
+
+#, c-format
+msgid "Expected MAP count in %s line %d"
+msgstr "%s ë¼ì¸ %dì— MAP 카운트가 기대ë¨"
+
+#, c-format
+msgid "Duplicate character in MAP in %s line %d"
+msgstr "%s ë¼ì¸ %dì˜ MAPì— ì¤‘ë³µëœ ë¬¸ìž"
+
+#, c-format
+msgid "Unrecognized or duplicate item in %s line %d: %s"
+msgstr "%s ë¼ì¸ %dì— ëª¨ë¥´ëŠ” í˜¹ì€ ì¤‘ë³µëœ í•­ëª©: %s"
+
+#, c-format
+msgid "Missing FOL/LOW/UPP line in %s"
+msgstr "%sì— FOL/LOW/UPPì´ ëˆ„ë½ëœ ë¼ì¸"
+
+msgid "COMPOUNDSYLMAX used without SYLLABLE"
+msgstr "COMPOUNDSYLMAXì´ SYLLABLEì—†ì´ ì‚¬ìš©ë¨"
+
+msgid "Too many postponed prefixes"
+msgstr "postponed ì ‘ë‘사가 너무 많습니다"
+
+msgid "Too many compound flags"
+msgstr "compound 플래그가 너무 많습니다"
+
+msgid "Too many postponed prefixes and/or compound flags"
+msgstr "postponed ì ‘ë‘사와(나) compound 플래그가 너무 많습니다"
+
+#, c-format
+msgid "Missing SOFO%s line in %s"
+msgstr "SOFO%sê°€ 누ë½ëœ ë¼ì¸ì´ %sì— ìžˆìŠµë‹ˆë‹¤"
+
+#, c-format
+msgid "Both SAL and SOFO lines in %s"
+msgstr "%sì— SALê³¼ SOFO ë¼ì¸ì´ 둘 다 있습니다"
+
+#, c-format
+msgid "Flag is not a number in %s line %d: %s"
+msgstr "%s ë¼ì¸ %dì— ìˆ«ìžê°€ ì•„ë‹Œ 플래그: %s"
+
+#, c-format
+msgid "Illegal flag in %s line %d: %s"
+msgstr "%s ë¼ì¸ %dì— ìž˜ëª»ëœ í”Œëž˜ê·¸: %s"
+
+#, c-format
+msgid "%s value differs from what is used in another .aff file"
+msgstr "%s ê°’ì´ ë‹¤ë¥¸ .aff 파ì¼ì—ì„œ ì‚¬ìš©ëœ ê²ƒê³¼ 다릅니다"
+
+#, c-format
+msgid "Reading dictionary file %s..."
+msgstr "사전 íŒŒì¼ %s ì½ëŠ” 중 ..."
+
+#, c-format
+msgid "E760: No word count in %s"
+msgstr "E760: %sì— ë‹¨ì–´ 카운트가 없습니다"
+
+#, c-format
+msgid "line %6d, word %6ld - %s"
+msgstr "ë¼ì¸ %6d, 단어 %6ld - %s"
+
+#, c-format
+msgid "Duplicate word in %s line %d: %s"
+msgstr "%s ë¼ì¸ %dì— ì¤‘ë³µëœ ë‹¨ì–´: %s"
+
+#, c-format
+msgid "First duplicate word in %s line %d: %s"
+msgstr "%s ë¼ì¸ %dì— ì²˜ìŒ ì¤‘ë³µëœ ë‹¨ì–´: %s"
+
+#, c-format
+msgid "%d duplicate word(s) in %s"
+msgstr "%dê°œì˜ ì¤‘ë³µëœ ë‹¨ì–´ê°€ %sì— ìžˆìŠµë‹ˆë‹¤"
+
+#, c-format
+msgid "Ignored %d word(s) with non-ASCII characters in %s"
+msgstr "ë¬´ì‹œëœ %dê°œì˜ ì•„ìŠ¤í‚¤ë¬¸ìžì—´ì´ ì•„ë‹Œ 단어가 %sì— ìžˆìŠµë‹ˆë‹¤"
+
+#, c-format
+msgid "Reading word file %s..."
+msgstr "단어 íŒŒì¼ %s ì½ëŠ” 중 ..."
+
+#, c-format
+msgid "Duplicate /encoding= line ignored in %s line %d: %s"
+msgstr "%s ë¼ì¸ %dì˜ ì¤‘ë³µëœ /encoding= ë¼ì¸ 무시ë¨: %s"
+
+#, c-format
+msgid "/encoding= line after word ignored in %s line %d: %s"
+msgstr "%s ë¼ì¸ %dì˜ ë‹¨ì–´ ë’¤ì˜ /encoding= ë¼ì¸ 무시ë¨: %s"
+
+#, c-format
+msgid "Duplicate /regions= line ignored in %s line %d: %s"
+msgstr "%s ë¼ì¸ %dì˜ ì¤‘ë³µëœ /regions= ë¼ì¸ 무시ë¨: %s"
+
+#, c-format
+msgid "Too many regions in %s line %d: %s"
+msgstr "%s ë¼ì¸ %dì— ë„ˆë¬´ ë§Žì€ ì˜ì—­: %s"
+
+#, c-format
+msgid "/ line ignored in %s line %d: %s"
+msgstr "%s ë¼ì¸ %dì˜ / ë¼ì¸ 무시ë¨: %s"
+
+#, c-format
+msgid "Invalid region nr in %s line %d: %s"
+msgstr "%s ë¼ì¸ %dì— ìž˜ëª»ëœ ì˜ì—­ 번호: %s"
+
+#, c-format
+msgid "Unrecognized flags in %s line %d: %s"
+msgstr "%s ë¼ì¸ %dì— ëª¨ë¥´ëŠ” 플래그: %s"
+
+#, c-format
+msgid "Ignored %d words with non-ASCII characters"
+msgstr "아스키 문ìžì—´ì´ ì•„ë‹Œ %dê°œì˜ ë‹¨ì–´ê°€ 무시ë˜ì—ˆìŠµë‹ˆë‹¤"
+
+msgid "E845: Insufficient memory, word list will be incomplete"
+msgstr "E845: 메모리 부족, 단어 목ë¡ì´ 불완전할 것입니다"
+
+#, c-format
+msgid "Compressed %d of %d nodes; %d (%d%%) remaining"
+msgstr "%d/%d 노드가 압축ë¨; %d (%d%%)ê°€ 남ìŒ"
+
+msgid "Reading back spell file..."
+msgstr "맞춤법 파ì¼ì„ ì½ëŠ” 중..."
+
+msgid "Performing soundfolding..."
+msgstr "soundfold 수행중..."
+
+#, c-format
+msgid "Number of words after soundfolding: %ld"
+msgstr "soundfold 수행 í›„ì˜ ë‹¨ì–´ 수: %ld"
+
+#, c-format
+msgid "Total number of words: %d"
+msgstr "ì´ ë‹¨ì–´ 수: %d"
+
+#, c-format
+msgid "Writing suggestion file %s..."
+msgstr "%s 제안 파ì¼ì„ 쓰는 중 ..."
+
+#, c-format
+msgid "Estimated runtime memory use: %d bytes"
+msgstr "ì¶”ì •ëœ ëŸ°íƒ€ìž„ 메모리 사용량: %d ë°”ì´íŠ¸"
+
+msgid "E751: Output file name must not have region name"
+msgstr "E751: ìƒì„± 파ì¼ëª…ì€ ì˜ì—­ ì´ë¦„ê³¼ 달ë¼ì•¼ 합니다"
+
+#, c-format
+msgid "E754: Only up to %ld regions supported"
+msgstr "E754: 최대 %ldê°œì˜ ì˜ì—­ì´ 지ì›ë©ë‹ˆë‹¤"
+
+#, c-format
+msgid "E755: Invalid region in %s"
+msgstr "E755: %sì— ìž˜ëª»ëœ ì˜ì—­"
+
+msgid "Warning: both compounding and NOBREAK specified"
+msgstr "경고: compound와 NOBREAK 둘 다 명시ë¨"
+
+#, c-format
+msgid "Writing spell file %s..."
+msgstr "spell íŒŒì¼ %s 쓰는 중 ..."
+
+msgid "Done!"
+msgstr "ë!"
+
+#, c-format
+msgid "E765: 'spellfile' does not have %ld entries"
+msgstr "E765: 'spellfile'ì— %ld í•­ëª©ì´ ì—†ìŠµë‹ˆë‹¤"
+
+#, c-format
+msgid "Word '%.*s' removed from %s"
+msgstr "단어 '%.*s'ì´(ê°€) %sì—ì„œ 제거ë¨"
+
+#, c-format
+msgid "Word '%.*s' added to %s"
+msgstr "단어 '%.*s'ì´(ê°€) %sì— ì¶”ê°€ë¨"
+
+msgid "E763: Word characters differ between spell files"
+msgstr "E763: 단어가 spell íŒŒì¼ ê°„ì— ë‹¤ë¦…ë‹ˆë‹¤"
+
+msgid "E783: duplicate char in MAP entry"
+msgstr "E783: MAP í•­ëª©ì— ì¤‘ë³µëœ ë¬¸ìž"
+
+msgid "No Syntax items defined for this buffer"
+msgstr "ì´ ë²„í¼ì— 대해 ì •ì˜ëœ 구문 í•­ëª©ì´ ì—†ìŠµë‹ˆë‹¤"
+
+msgid "syntax conceal on"
+msgstr "구문 ê°ì¶”기 활성"
+
+msgid "syntax conceal off"
+msgstr "구문 ê°ì¶”기 비활성"
+
+#, c-format
+msgid "E390: Illegal argument: %s"
+msgstr "E390: ìž˜ëª»ëœ ì¸ìž: %s"
+
+msgid "syntax case ignore"
+msgstr "구문 ëŒ€ì†Œë¬¸ìž êµ¬ë³„ì•Ší•¨"
+
+msgid "syntax case match"
+msgstr "구문 ëŒ€ì†Œë¬¸ìž êµ¬ë³„"
+
+#~ msgid "syntax spell toplevel"
+#~ msgstr ""
+
+#~ msgid "syntax spell notoplevel"
+#~ msgstr ""
+
+#~ msgid "syntax spell default"
+#~ msgstr ""
+
+msgid "syntax iskeyword "
+msgstr "syntax iskeyword "
+
+#, c-format
+msgid "E391: No such syntax cluster: %s"
+msgstr "E391: ì´ëŸ° 구문 í´ëŸ¬ìŠ¤í„°ëŠ” 없습니다: %s"
+
+msgid "syncing on C-style comments"
+msgstr "C-í˜•ì‹ ì£¼ì„ë¬¸ì— ë™ê¸°ë§žì¶¤"
+
+msgid "no syncing"
+msgstr "ë™ê¸°ë§žì¶¤ ì—†ìŒ"
+
+msgid "syncing starts "
+msgstr "syncing starts "
+
+msgid " lines before top line"
+msgstr " lines before top line"
+
+msgid ""
+"\n"
+"--- Syntax sync items ---"
+msgstr ""
+"\n"
+"--- Syntax sync 항목들 ---"
+
+msgid ""
+"\n"
+"syncing on items"
+msgstr ""
+"\n"
+"syncing on items"
+
+msgid ""
+"\n"
+"--- Syntax items ---"
+msgstr ""
+"\n"
+"--- Syntax 항목 ---"
+
+#, c-format
+msgid "E392: No such syntax cluster: %s"
+msgstr "E392: ì´ëŸ° 구문 í´ëŸ¬ìŠ¤í„°ëŠ” 없습니다: %s"
+
+msgid "minimal "
+msgstr "minimal "
+
+msgid "maximal "
+msgstr "maximal "
+
+msgid "; match "
+msgstr "; match "
+
+msgid " line breaks"
+msgstr " line breaks"
+
+msgid "E395: contains argument not accepted here"
+msgstr "E395: contains ì¸ìžëŠ” ì—¬ê¸°ì— ì“¸ 수 없습니다"
+
+msgid "E844: invalid cchar value"
+msgstr "E844: ìž˜ëª»ëœ cchar ê°’"
+
+msgid "E393: group[t]here not accepted here"
+msgstr "E393: group[t]here는 여기ì—ì„œ ì‚¬ìš©ë  ìˆ˜ 없습니다"
+
+#, c-format
+msgid "E394: Didn't find region item for %s"
+msgstr "E394: %sì— ëŒ€í•œ region í•­ëª©ì„ ì°¾ì§€ 못했습니다"
+
+msgid "E397: Filename required"
+msgstr "E397: 파ì¼ì´ë¦„ì´ í•„ìš”í•©ë‹ˆë‹¤"
+
+msgid "E847: Too many syntax includes"
+msgstr "E847: 구문 í¬í•¨(include)ì´ ë„ˆë¬´ 많습니다"
+
+#, c-format
+msgid "E789: Missing ']': %s"
+msgstr "E789: ']' 누ë½: %s"
+
+#, c-format
+msgid "E890: trailing char after ']': %s]%s"
+msgstr "E890: ']' ë’¤ì— ë¬¸ìžê°€ ë” ìžˆìŒ: %s]%s"
+
+#, c-format
+msgid "E398: Missing '=': %s"
+msgstr "E398: '=' 누ë½: %s"
+
+#, c-format
+msgid "E399: Not enough arguments: syntax region %s"
+msgstr "E399: 충분치 ì•Šì€ ì¸ìž: 구문 ì˜ì—­ %s"
+
+msgid "E848: Too many syntax clusters"
+msgstr "E848: 구문 í´ëŸ¬ìŠ¤í„°ê°€ 너무 많습니다"
+
+msgid "E400: No cluster specified"
+msgstr "E400: í´ëŸ¬ìŠ¤í„°ê°€ 명시ë˜ì§€ 않았습니다"
+
+#, c-format
+msgid "E401: Pattern delimiter not found: %s"
+msgstr "E401: 패턴 구분ìžë¥¼ ì°¾ì„ ìˆ˜ 없습니다: %s"
+
+#, c-format
+msgid "E402: Garbage after pattern: %s"
+msgstr "E402: 패턴 ë’¤ì— ì“°ë ˆê¸°: %s"
+
+msgid "E403: syntax sync: line continuations pattern specified twice"
+msgstr "E403: syntax sync: 줄 ì—°ì† íŒ¨í„´ì´ ë‘ ë²ˆ 사용ë˜ì—ˆìŠµë‹ˆë‹¤"
+
+#, c-format
+msgid "E404: Illegal arguments: %s"
+msgstr "E404: 비정ìƒì ì¸ ì¸ìž: %s"
+
+#, c-format
+msgid "E405: Missing equal sign: %s"
+msgstr "E405: ì´í€„ 기호가 ë¹ ì¡ŒìŒ: %s"
+
+#, c-format
+msgid "E406: Empty argument: %s"
+msgstr "E406: 빈 ì¸ìž: %s"
+
+#, c-format
+msgid "E407: %s not allowed here"
+msgstr "E407: %sì€(는) 여기ì—ì„œ 허용ë˜ì§€ 않습니다"
+
+#, c-format
+msgid "E408: %s must be first in contains list"
+msgstr "E408: %sì€(는) contains 목ë¡ì˜ 첫 번째여야 합니다"
+
+#, c-format
+msgid "E409: Unknown group name: %s"
+msgstr "E409: 모르는 그룹 ì´ë¦„: %s"
+
+#, c-format
+msgid "E410: Invalid :syntax subcommand: %s"
+msgstr "E410: ìž˜ëª»ëœ :syntax 하위 명령: %s"
+
+#~ msgid ""
+#~ " TOTAL COUNT MATCH SLOWEST AVERAGE NAME PATTERN"
+#~ msgstr ""
+
+msgid "E679: recursive loop loading syncolor.vim"
+msgstr "E679: syncolor.vim 반복 로딩"
+
+#, c-format
+msgid "E411: highlight group not found: %s"
+msgstr "E411: 하ì´ë¼ì´íŠ¸ ê·¸ë£¹ì„ ì°¾ì„ ìˆ˜ 없습니다: %s"
+
+#, c-format
+msgid "E412: Not enough arguments: \":highlight link %s\""
+msgstr "E412: 충분치 ì•Šì€ ì¸ìž: \":highlight link %s\""
+
+#, c-format
+msgid "E413: Too many arguments: \":highlight link %s\""
+msgstr "E413: 너무 ë§Žì€ ì¸ìž: \":highlight link %s\""
+
+msgid "E414: group has settings, highlight link ignored"
+msgstr "E414: groupì´ ì„¤ì •ê°’ì´ ìžˆìŠµë‹ˆë‹¤, highlight link 무시ë¨"
+
+#, c-format
+msgid "E415: unexpected equal sign: %s"
+msgstr "E415: ëœ»ë°–ì˜ ì´í€„ 기호: %s"
+
+#, c-format
+msgid "E416: missing equal sign: %s"
+msgstr "E416: ì´í€„ 기호가 ë¹ ì¡ŒìŒ: %s"
+
+#, c-format
+msgid "E417: missing argument: %s"
+msgstr "E417: ì¸ìžê°€ ë¹ ì¡ŒìŒ: %s"
+
+#, c-format
+msgid "E418: Illegal value: %s"
+msgstr "E418: 비정ìƒì ì¸ ê°’: %s"
+
+msgid "E419: FG color unknown"
+msgstr "E419: 모르는 FG 색ìƒ"
+
+msgid "E420: BG color unknown"
+msgstr "E420: 모르는 BG 색ìƒ"
+
+#, c-format
+msgid "E421: Color name or number not recognized: %s"
+msgstr "E421: 색 ì´ë¦„ì´ë‚˜ 숫ìžë¥¼ ì¸ì‹í•  수 ì—†ìŒ: %s"
+
+#, c-format
+msgid "E422: terminal code too long: %s"
+msgstr "E422: í„°ë¯¸ë„ ì½”ë“œê°€ 너무 ê¹€: %s"
+
+#, c-format
+msgid "E423: Illegal argument: %s"
+msgstr "E423: ìž˜ëª»ëœ ì¸ìž: %s"
+
+msgid "E424: Too many different highlighting attributes in use"
+msgstr "E424: 너무 ë§Žì€ ë‹¤ë¥¸ 하ì´ë¼ì´íŠ¸ ì†ì„±ì´ 사용ë˜ê³  있습니다"
+
+msgid "E669: Unprintable character in group name"
+msgstr "E669: 그룹 ì´ë¦„ì— ì¶œë ¥í•  수 없는 문ìžê°€ 있습니다"
+
+msgid "W18: Invalid character in group name"
+msgstr "W18: 그룹 ì´ë¦„ì— ì´ìƒí•œ 문ìž"
+
+msgid "E849: Too many highlight and syntax groups"
+msgstr "E849: highlight와 syntax groupì´ ë„ˆë¬´ 많습니다"
+
+msgid "E555: at bottom of tag stack"
+msgstr "E555: 태그 스íƒì˜ ë입니다"
+
+msgid "E556: at top of tag stack"
+msgstr "E556: 태그 스íƒì˜ 처ìŒìž…니다"
+
+msgid "E425: Cannot go before first matching tag"
+msgstr "E425: 첫 번째 맞는 태그 ì´ì „으로는 ê°ˆ 수 없습니다"
+
+#, c-format
+msgid "E426: tag not found: %s"
+msgstr "E426: 태그를 ì°¾ì„ ìˆ˜ ì—†ìŒ: %s"
+
+msgid " # pri kind tag"
+msgstr " # pri kind tag"
+
+msgid "file\n"
+msgstr "파ì¼\n"
+
+msgid "E427: There is only one matching tag"
+msgstr "E427: 맞는 태그가 하나 ë°–ì— ì—†ìŠµë‹ˆë‹¤"
+
+msgid "E428: Cannot go beyond last matching tag"
+msgstr "E428: 마지막 맞는 태그 뒤로는 갈 수 없습니다"
+
+#, c-format
+msgid "File \"%s\" does not exist"
+msgstr "íŒŒì¼ \"%s\"ì´(ê°€) 존재하지 않습니다"
+
+#, c-format
+msgid "tag %d of %d%s"
+msgstr "tag %d of %d%s"
+
+msgid " or more"
+msgstr " or more"
+
+msgid " Using tag with different case!"
+msgstr " Using tag with different case!"
+
+#, c-format
+msgid "E429: File \"%s\" does not exist"
+msgstr "E429: íŒŒì¼ \"%s\"ì´(ê°€) 존재하지 않습니다"
+
+msgid ""
+"\n"
+" # TO tag FROM line in file/text"
+msgstr ""
+"\n"
+" # TO tag FROM line in file/text"
+
+#, c-format
+msgid "Searching tags file %s"
+msgstr "태그 íŒŒì¼ %s 찾는 중"
+
+#, c-format
+msgid "E430: Tag file path truncated for %s\n"
+msgstr "E430: %sì— ëŒ€í•œ 태그 íŒŒì¼ ê²½ë¡œê°€ 잘렸습니다\n"
+
+msgid "Ignoring long line in tags file"
+msgstr "태그 파ì¼ì˜ 너무 긴 ë¼ì¸ì„ 무시합니다"
+
+#, c-format
+msgid "E431: Format error in tags file \"%s\""
+msgstr "E431: 태그 íŒŒì¼ \"%s\"ì— í˜•ì‹ ì—러가 있습니다"
+
+#, c-format
+msgid "Before byte %ld"
+msgstr "Before byte %ld"
+
+#, c-format
+msgid "E432: Tags file not sorted: %s"
+msgstr "E432: 태그 파ì¼ì´ ì •ë ¬ë˜ì–´ 있지 ì•ŠìŒ: %s"
+
+msgid "E433: No tags file"
+msgstr "E433: 태그 파ì¼ì´ 없습니다"
+
+msgid "E434: Can't find tag pattern"
+msgstr "E434: 태그 íŒ¨í„´ì„ ì°¾ì„ ìˆ˜ 없습니다"
+
+msgid "E435: Couldn't find tag, just guessing!"
+msgstr "E435: 태그를 ì°¾ì„ ìˆ˜ 없지만 ì´ê±° 같습니다!"
+
+#, c-format
+msgid "Duplicate field name: %s"
+msgstr "ì¤‘ë³µëœ í•„ë“œ 명: %s"
+
+msgid "' not known. Available builtin terminals are:"
+msgstr "' not known. Available builtin terminals are:"
+
+msgid "defaulting to '"
+msgstr "defaulting to '"
+
+msgid "E557: Cannot open termcap file"
+msgstr "E557: termcap 파ì¼ì„ ì—´ 수 없습니다"
+
+msgid "E558: Terminal entry not found in terminfo"
+msgstr "E558: í„°ë¯¸ë„ í•­ëª©ì„ terminfoì—ì„œ ì°¾ì„ ìˆ˜ 없습니다"
+
+msgid "E559: Terminal entry not found in termcap"
+msgstr "E559: í„°ë¯¸ë„ í•­ëª©ì„ termcapì—ì„œ ì°¾ì„ ìˆ˜ 없습니다"
+
+#, c-format
+msgid "E436: No \"%s\" entry in termcap"
+msgstr "E436: termcapì— \"%s\" í•­ëª©ì´ ì—†ìŠµë‹ˆë‹¤"
+
+msgid "E437: terminal capability \"cm\" required"
+msgstr "E437: 터미ë„ì´ \"cm\" ê¸°ëŠ¥ì„ ì§€ì›í•´ì•¼ 합니다"
+
+msgid ""
+"\n"
+"--- Terminal keys ---"
+msgstr ""
+"\n"
+"--- í„°ë¯¸ë„ í‚¤ ---"
+
+msgid "Cannot open $VIMRUNTIME/rgb.txt"
+msgstr "$VIMRUNTIME/rgb.txtì„ ì—´ 수 없습니다"
+
+#, c-format
+msgid "Kill job in \"%s\"?"
+msgstr "\"%s\"ì˜ jobì„ ì£½ì¼ê¹Œìš”?"
+
+msgid "Terminal"
+msgstr "Terminal"
+
+msgid "Terminal-finished"
+msgstr "Terminal-finished"
+
+msgid "active"
+msgstr "active"
+
+msgid "running"
+msgstr "running"
+
+msgid "finished"
+msgstr "finished"
+
+#, c-format
+msgid "E953: File exists: %s"
+msgstr "E953: 파ì¼ì´ 존재함: %s"
+
+msgid "E955: Not a terminal buffer"
+msgstr "E955: í„°ë¯¸ë„ ë²„í¼ê°€ 아닙니다"
+
+msgid "new shell started\n"
+msgstr "새 ì‰˜ì´ ì‹œìž‘ë˜ì—ˆìŠµë‹ˆë‹¤\n"
+
+msgid "Vim: Error reading input, exiting...\n"
+msgstr "ë¹”: ìž…ë ¥ ì½ëŠ” 중 ì—러, ë내는중...\n"
+
+msgid "Used CUT_BUFFER0 instead of empty selection"
+msgstr "빈 고르기 대신 CUT_BUFFER0ì„ ì‚¬ìš©í–ˆìŠµë‹ˆë‹¤"
+
+msgid "E881: Line count changed unexpectedly"
+msgstr "E881: í–‰ 갯수가 ê°‘ìžê¸° 바뀌었습니다"
+
+msgid "No undo possible; continue anyway"
+msgstr "취소 불가능; 어쨌든 계ì†í•©ë‹ˆë‹¤"
+
+#, c-format
+msgid "E828: Cannot open undo file for writing: %s"
+msgstr "E828: 쓰기 위해 undoì„ ì—´ 수 없습니다: %s"
+
+#, c-format
+msgid "E825: Corrupted undo file (%s): %s"
+msgstr "E825: 깨진 undo íŒŒì¼ (%s): %s"
+
+msgid "Cannot write undo file in any directory in 'undodir'"
+msgstr "'undodir'ì— ìžˆëŠ” ì–´ë–¤ 디렉토리ì—ë„ undo 파ì¼ì„ 쓸 수 없습니다"
+
+#, c-format
+msgid "Will not overwrite with undo file, cannot read: %s"
+msgstr "ì½ì„ 수가 없어서 undo 파ì¼ì— ë®ì–´ì“¸ 수 없습니다: %s"
+
+#, c-format
+msgid "Will not overwrite, this is not an undo file: %s"
+msgstr "undo 파ì¼ì´ 아니어서 ë®ì–´ì“¸ 수 없습니다: %s"
+
+msgid "Skipping undo file write, nothing to undo"
+msgstr "undoí•  ë‚´ìš©ì´ ì—†ì–´ì„œ undo íŒŒì¼ ì €ìž¥ì„ ê±´ë„ˆëœë‹ˆë‹¤"
+
+#, c-format
+msgid "Writing undo file: %s"
+msgstr "undo íŒŒì¼ ì“°ëŠ” 중: %s"
+
+#, c-format
+msgid "E829: write error in undo file: %s"
+msgstr "E829: undo íŒŒì¼ ì“°ê¸° ì—러: %s"
+
+#, c-format
+msgid "Not reading undo file, owner differs: %s"
+msgstr "소유ìžê°€ 달ë¼ì„œ undo 파ì¼ì„ ì½ì§€ 않습니다: %s"
+
+#, c-format
+msgid "Reading undo file: %s"
+msgstr "undo íŒŒì¼ ì½ëŠ” 중: %s"
+
+#, c-format
+msgid "E822: Cannot open undo file for reading: %s"
+msgstr "E822: ì½ê¸° 위해 undo 파ì¼ì„ ì—´ 수 없습니다: %s"
+
+#, c-format
+msgid "E823: Not an undo file: %s"
+msgstr "E823: undo 파ì¼ì´ 아닙니다: %s"
+
+#, c-format
+msgid "E832: Non-encrypted file has encrypted undo file: %s"
+msgstr "E832: 암호화ë˜ì§€ ì•Šì€ íŒŒì¼ì´ ì•”í˜¸í™”ëœ undo 파ì¼ì„ 가지고 있습니다: %s"
+
+#, c-format
+msgid "E826: Undo file decryption failed: %s"
+msgstr "E826: Undo 파ì¼ì„ í•´ë…í•  수 없습니다: %s"
+
+#, c-format
+msgid "E827: Undo file is encrypted: %s"
+msgstr "E827: Undo 파ì¼ì´ 암호화ë˜ì—ˆìŠµë‹ˆë‹¤: %s"
+
+#, c-format
+msgid "E824: Incompatible undo file: %s"
+msgstr "E824: 호환ë˜ì§€ 않는 undo 파ì¼: %s"
+
+msgid "File contents changed, cannot use undo info"
+msgstr "íŒŒì¼ ë‚´ìš©ì´ ë°”ë€Œì–´ì„œ, undo 정보를 사용할 수 없습니다"
+
+#, c-format
+msgid "Finished reading undo file %s"
+msgstr "undo íŒŒì¼ %sì„(를) ì½ì–´ë“¤ì˜€ìŠµë‹ˆë‹¤"
+
+msgid "Already at oldest change"
+msgstr "ë” ì´ìƒì˜ ìˆ˜ì •ì´ ì—†ì—ˆìŠµë‹ˆë‹¤"
+
+msgid "Already at newest change"
+msgstr "ë” ì´ìƒì˜ ìˆ˜ì •ì€ ì—†ì—ˆìŠµë‹ˆë‹¤"
+
+#, c-format
+msgid "E830: Undo number %ld not found"
+msgstr "E830: Undo 번호 %ld를 ì°¾ì„ ìˆ˜ 없습니다"
+
+msgid "E438: u_undo: line numbers wrong"
+msgstr "E438: u_undo: ìž˜ëª»ëœ ì¤„ 번호"
+
+msgid "more line"
+msgstr "more line"
+
+msgid "more lines"
+msgstr "more lines"
+
+msgid "line less"
+msgstr "line less"
+
+msgid "fewer lines"
+msgstr "fewer lines"
+
+msgid "change"
+msgstr "change"
+
+msgid "changes"
+msgstr "changes"
+
+#, c-format
+msgid "%ld %s; %s #%ld %s"
+msgstr "%ld %s; %s #%ld %s"
+
+msgid "before"
+msgstr "before"
+
+msgid "after"
+msgstr "after"
+
+msgid "Nothing to undo"
+msgstr "취소할 게 없습니다"
+
+#~ msgid "number changes when saved"
+#~ msgstr ""
+
+#, c-format
+msgid "%ld seconds ago"
+msgstr "%ld seconds ago"
+
+msgid "E790: undojoin is not allowed after undo"
+msgstr "E790: undo ë’¤ì— undojoinì€ í•  수 없습니다"
+
+msgid "E439: undo list corrupt"
+msgstr "E439: undo 목ë¡ì´ 깨졌습니다"
+
+msgid "E440: undo line missing"
+msgstr "E440: undo ì¤„ì´ ì—†ìŠµë‹ˆë‹¤"
+
+#, c-format
+msgid "E122: Function %s already exists, add ! to replace it"
+msgstr "E122: 함수 %sì´(ê°€) ì´ë¯¸ 있습니다, 바꾸려면 !ì„ ë”하세요"
+
+msgid "E717: Dictionary entry already exists"
+msgstr "E717: ì´ë¯¸ Dictionary í•­ëª©ì´ ìžˆìŠµë‹ˆë‹¤"
+
+msgid "E718: Funcref required"
+msgstr "E718: Funcref가 필요합니다"
+
+#, c-format
+msgid "E130: Unknown function: %s"
+msgstr "E130: 모르는 함수: %s"
+
+#, c-format
+msgid "E125: Illegal argument: %s"
+msgstr "E125: ìž˜ëª»ëœ ì¸ìž: %s"
+
+#, c-format
+msgid "E853: Duplicate argument name: %s"
+msgstr "E853: ì¤‘ë³µëœ ì¸ìž ì´ë¦„: %s"
+
+#, c-format
+msgid "E740: Too many arguments for function %s"
+msgstr "E740: 함수 %sì— ë„ˆë¬´ ë§Žì€ ì¸ìžê°€ 전달ë˜ì—ˆìŠµë‹ˆë‹¤"
+
+#, c-format
+msgid "E116: Invalid arguments for function %s"
+msgstr "E116: 함수 %s(으)ë¡œ ìž˜ëª»ëœ ì¸ìžê°€ 넘겨졌습니다"
+
+msgid "E132: Function call depth is higher than 'maxfuncdepth'"
+msgstr "E132: 함수를 부른 깊ì´ê°€ 'maxfuncdepth'보다 í½ë‹ˆë‹¤"
+
+#, c-format
+msgid "calling %s"
+msgstr "%s 부르는 중"
+
+#, c-format
+msgid "%s aborted"
+msgstr "%sì´(ê°€) 중지ë˜ì—ˆìŠµë‹ˆë‹¤"
+
+#, c-format
+msgid "%s returning #%ld"
+msgstr "%sì´(ê°€) #%ldì„(를) ëŒë ¤ì£¼ì—ˆìŠµë‹ˆë‹¤"
+
+#, c-format
+msgid "%s returning %s"
+msgstr "%sì´(ê°€) %sì„(를) ëŒë ¤ì£¼ì—ˆìŠµë‹ˆë‹¤"
+
+msgid "E699: Too many arguments"
+msgstr "E699: 너무 ë§Žì€ ì¸ìž"
+
+#, c-format
+msgid "E117: Unknown function: %s"
+msgstr "E117: 모르는 함수: %s"
+
+#, c-format
+msgid "E933: Function was deleted: %s"
+msgstr "E933: 함수가 ì‚­ì œë¨: %s"
+
+#, c-format
+msgid "E119: Not enough arguments for function: %s"
+msgstr "E119: í•¨ìˆ˜ì— ì ì€ ì¸ìž 넘김: %s"
+
+#, c-format
+msgid "E120: Using <SID> not in a script context: %s"
+msgstr "E120: 스í¬ë¦½íŠ¸ 콘í…스트 ë°–ì—ì„œ <SID> 사용: %s"
+
+#, c-format
+msgid "E725: Calling dict function without Dictionary: %s"
+msgstr "E725: Dictionaryì—†ì´ ì‚¬ì „í•¨ìˆ˜ê°€ 불려ì§: %s"
+
+msgid "E129: Function name required"
+msgstr "E129: 함수 ì´ë¦„ì´ í•„ìš”í•©ë‹ˆë‹¤"
+
+#, c-format
+msgid "E128: Function name must start with a capital or \"s:\": %s"
+msgstr "E128: 함수 ì´ë¦„ì€ ëŒ€ë¬¸ìž í˜¹ì€ \"s:\"ë¡œ 시작해야 함: %s"
+
+#, c-format
+msgid "E884: Function name cannot contain a colon: %s"
+msgstr "E884: 함수 ì´ë¦„ì€ ì½œë¡ ì„ í¬í•¨í•  수 ì—†ìŒ: %s"
+
+#, c-format
+msgid "E123: Undefined function: %s"
+msgstr "E123: ì •ì˜ ì•ˆ ëœ í•¨ìˆ˜: %s"
+
+#, c-format
+msgid "E124: Missing '(': %s"
+msgstr "E124: '('ê°€ ì—†ìŒ: %s"
+
+msgid "E862: Cannot use g: here"
+msgstr "E862: 여기ì—ì„œ g:ì„ ì‚¬ìš©í•  수 없습니다"
+
+#, c-format
+msgid "E932: Closure function should not be at top level: %s"
+msgstr "E932: Closure 함수는 최ìƒìœ„ ë ˆë²¨ì¼ ìˆ˜ 없습니다: %s"
+
+msgid "E126: Missing :endfunction"
+msgstr "E126: :endfunctionì´ ì—†ìŠµë‹ˆë‹¤"
+
+#, c-format
+msgid "W22: Text found after :endfunction: %s"
+msgstr "W22: :endfunction ë’¤ì— ë¬¸ìžì—´ì´ 있ìŒ: %s"
+
+#, c-format
+msgid "E707: Function name conflicts with variable: %s"
+msgstr "E707: í•¨ìˆ˜ëª…ì´ ë³€ìˆ˜ëª…ê³¼ 충ëŒ: %s"
+
+#, c-format
+msgid "E127: Cannot redefine function %s: It is in use"
+msgstr "E127: 함수 %sì„(를) 다시 ì •ì˜í•  수 없습니다: 사용중입니다"
+
+#, c-format
+msgid "E746: Function name does not match script file name: %s"
+msgstr "E746: í•¨ìˆ˜ëª…ì´ ìŠ¤í¬ë¦½íŠ¸ 파ì¼ëª…ê³¼ 다름: %s"
+
+#, c-format
+msgid "E131: Cannot delete function %s: It is in use"
+msgstr "E131: 함수 %sì„(를) 지울 수 없습니다: 사용중입니다"
+
+msgid "E133: :return not inside a function"
+msgstr "E133: :returnì´ í•¨ìˆ˜ ì•ˆì— ìžˆì§€ 않습니다"
+
+#, c-format
+msgid "E107: Missing parentheses: %s"
+msgstr "E107: 괄호 ì—†ìŒ: %s"
+
+#, c-format
+msgid "%s (%s, compiled %s)"
+msgstr "%s (%s, 빌드한 날짜 %s)"
+
+msgid ""
+"\n"
+"MS-Windows 64-bit GUI version"
+msgstr ""
+"\n"
+"MS-Windows 64비트 GUI 버젼"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit GUI version"
+msgstr ""
+"\n"
+"MS-Windows 32비트 GUI 버젼"
+
+msgid " with OLE support"
+msgstr " OLE 지ì›"
+
+msgid ""
+"\n"
+"MS-Windows 64-bit console version"
+msgstr ""
+"\n"
+"MS-Windows 64비트 콘솔 버젼"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit console version"
+msgstr ""
+"\n"
+"MS-Windows 32비트 콘솔 버젼"
+
+msgid ""
+"\n"
+"macOS version"
+msgstr ""
+"\n"
+"macOS 버젼"
+
+#~ msgid ""
+#~ "\n"
+#~ "macOS version w/o darwin feat."
+#~ msgstr ""
+
+msgid ""
+"\n"
+"OpenVMS version"
+msgstr ""
+"\n"
+"OpenVMS 버젼"
+
+msgid ""
+"\n"
+"Included patches: "
+msgstr ""
+"\n"
+"í¬í•¨ëœ 패치: "
+
+msgid ""
+"\n"
+"Extra patches: "
+msgstr ""
+"\n"
+"별ë„ì˜ íŒ¨ì¹˜: "
+
+msgid "Modified by "
+msgstr "Modified by "
+
+msgid ""
+"\n"
+"Compiled "
+msgstr ""
+"\n"
+"Compiled "
+
+msgid "by "
+msgstr "by "
+
+msgid ""
+"\n"
+"Huge version "
+msgstr ""
+"\n"
+"Huge 버젼 "
+
+msgid ""
+"\n"
+"Big version "
+msgstr ""
+"\n"
+"Big 버젼 "
+
+msgid ""
+"\n"
+"Normal version "
+msgstr ""
+"\n"
+"Normal 버젼 "
+
+msgid ""
+"\n"
+"Small version "
+msgstr ""
+"\n"
+"Small 버젼 "
+
+msgid ""
+"\n"
+"Tiny version "
+msgstr ""
+"\n"
+"Tiny 버젼 "
+
+msgid "without GUI."
+msgstr "GUI ì—†ìŒ."
+
+msgid "with GTK3 GUI."
+msgstr "GTK3 GUI."
+
+msgid "with GTK2-GNOME GUI."
+msgstr "GTK2-GNOME GUI."
+
+msgid "with GTK2 GUI."
+msgstr "GTK2 GUI."
+
+msgid "with X11-Motif GUI."
+msgstr "X11-Motif GUI."
+
+msgid "with X11-neXtaw GUI."
+msgstr "X11-neXtaw GUI."
+
+msgid "with X11-Athena GUI."
+msgstr "X11-Athena GUI."
+
+msgid "with Photon GUI."
+msgstr "Photon GUI."
+
+msgid "with GUI."
+msgstr "GUI."
+
+msgid "with Carbon GUI."
+msgstr "Carbon GUI."
+
+msgid "with Cocoa GUI."
+msgstr "Cocoa GUI."
+
+msgid " Features included (+) or not (-):\n"
+msgstr " 기능 (+: í¬í•¨ë¨, -: í¬í•¨ 안 ë¨):\n"
+
+msgid " system vimrc file: \""
+msgstr " 시스템 vimrc 파ì¼: \""
+
+msgid " user vimrc file: \""
+msgstr " ì‚¬ìš©ìž vimrc 파ì¼: \""
+
+msgid " 2nd user vimrc file: \""
+msgstr " ì‚¬ìš©ìž ë‘ ë²ˆì§¸ vimrc 파ì¼: \""
+
+msgid " 3rd user vimrc file: \""
+msgstr " ì‚¬ìš©ìž ì„¸ 번째 vimrc 파ì¼: \""
+
+msgid " user exrc file: \""
+msgstr " ì‚¬ìš©ìž exrc 파ì¼: \""
+
+msgid " 2nd user exrc file: \""
+msgstr " ì‚¬ìš©ìž ë‘ ë²ˆì§¸ exrc 파ì¼: \""
+
+msgid " system gvimrc file: \""
+msgstr " 시스템 gvimrc 파ì¼: \""
+
+msgid " user gvimrc file: \""
+msgstr " ì‚¬ìš©ìž gvimrc 파ì¼: \""
+
+msgid "2nd user gvimrc file: \""
+msgstr "ì‚¬ìš©ìž ë‘ ë²ˆì§¸ gvimrc 파ì¼: \""
+
+msgid "3rd user gvimrc file: \""
+msgstr "ì‚¬ìš©ìž ì„¸ 번째 gvimrc 파ì¼: \""
+
+msgid " defaults file: \""
+msgstr " defaults 파ì¼: \""
+
+msgid " system menu file: \""
+msgstr " 시스템 메뉴 파ì¼: \""
+
+msgid " fall-back for $VIM: \""
+msgstr " fall-back for $VIM: \""
+
+msgid " f-b for $VIMRUNTIME: \""
+msgstr " f-b for $VIMRUNTIME: \""
+
+msgid "Compilation: "
+msgstr "컴파ì¼: "
+
+msgid "Compiler: "
+msgstr "컴파ì¼ëŸ¬: "
+
+msgid "Linking: "
+msgstr "ë§í¬: "
+
+msgid " DEBUG BUILD"
+msgstr " 디버그 빌드"
+
+msgid "VIM - Vi IMproved"
+msgstr "ë¹” - í–¥ìƒëœ Vi"
+
+msgid "version "
+msgstr "íŒ "
+
+msgid "by Bram Moolenaar et al."
+msgstr "by Bram Moolenaar et al."
+
+msgid "Vim is open source and freely distributable"
+msgstr "ë¹”ì€ ëˆ„êµ¬ë‚˜ 소스를 ë³¼ 수 있고 공짜로 ë°°í¬ë©ë‹ˆë‹¤"
+
+msgid "Help poor children in Uganda!"
+msgstr "ìš°ê°„ë‹¤ì— ì‚¬ëŠ” 가난한 ì•„ì´ë¥¼ ë„와주세요!"
+
+msgid "type :help iccf<Enter> for information "
+msgstr "ì´ì— 대한 정보를 보려면 :help iccf<엔터> ìž…ë ¥"
+
+msgid "type :q<Enter> to exit "
+msgstr "ë내려면 :q<엔터> ìž…ë ¥"
+
+msgid "type :help<Enter> or <F1> for on-line help"
+msgstr "온ë¼ì¸ ë„움ë§ì„ 보려면 :help<엔터> ë˜ëŠ” <F1> ìž…ë ¥"
+
+msgid "type :help version8<Enter> for version info"
+msgstr "íŒ ì •ë³´ë¥¼ 보려면 :help version8<엔터> ìž…ë ¥"
+
+msgid "Running in Vi compatible mode"
+msgstr "Vi 호환 ìƒíƒœë¡œ 실행중입니다"
+
+msgid "type :set nocp<Enter> for Vim defaults"
+msgstr "ë¹” ê¸°ë³¸ê°’ì„ ì‚¬ìš©í•˜ë ¤ë©´ :set nocp<엔터> ìž…ë ¥"
+
+msgid "type :help cp-default<Enter> for info on this"
+msgstr "ì´ì— 대한 정보를 보려면 :help cp-default<엔터> ìž…ë ¥"
+
+msgid "menu Help->Orphans for information "
+msgstr "ì´ì— 대한 정보를 보려면 메뉴ì—ì„œ ë„움ë§->ê³ ì•„ ì„ íƒ"
+
+msgid "Running modeless, typed text is inserted"
+msgstr "ëª¨ë“œì—†ì´ ìˆ˜í–‰ì¤‘ì´ë©°, ìž…ë ¥ëœ ë¬¸ìžëŠ” 삽입ë©ë‹ˆë‹¤"
+
+msgid "menu Edit->Global Settings->Toggle Insert Mode "
+msgstr "메뉴ì—ì„œ 편집->ì „ì—­ 설정->삽입 모드 í† ê¸€ì„ ì„ íƒí•˜ì‹œë©´ "
+
+msgid " for two modes "
+msgstr " ë‘ ëª¨ë“œë¥¼ 사용할 수 있습니다 "
+
+msgid "menu Edit->Global Settings->Toggle Vi Compatible"
+msgstr "메뉴ì—ì„œ 편집->ì „ì—­ 설정->Vi 호환 í† ê¸€ì„ ì„ íƒí•˜ì‹œë©´ "
+
+msgid " for Vim defaults "
+msgstr " Vimì´ ê¸°ë³¸ê°’ìœ¼ë¡œ ë™ìž‘합니다 "
+
+msgid "Sponsor Vim development!"
+msgstr "ë¹” ê°œë°œì„ í›„ì›í•´ 주세요!"
+
+msgid "Become a registered Vim user!"
+msgstr "ë¹” 사용ìžë¡œ 등ë¡í•˜ì„¸ìš”!"
+
+msgid "type :help sponsor<Enter> for information "
+msgstr "ì´ì— 대한 정보를 보려면 :help sponsor<엔터> ìž…ë ¥"
+
+msgid "type :help register<Enter> for information "
+msgstr "ì´ì— 대한 정보를 보려면 :help register<엔터> ìž…ë ¥"
+
+msgid "menu Help->Sponsor/Register for information "
+msgstr "ì´ì— 대한 정보를 보려면 메뉴 ë„움ë§->Sponsor/Register"
+
+msgid "Already only one window"
+msgstr "ì´ë¯¸ í•˜ë‚˜ì˜ ì°½ë§Œ 있습니다"
+
+msgid "E441: There is no preview window"
+msgstr "E441: 미리 보기 ì°½ì´ ì—†ìŠµë‹ˆë‹¤"
+
+msgid "E442: Can't split topleft and botright at the same time"
+msgstr "E442: 위 왼쪽과 아래 ì˜¤ë¥¸ìª½ì„ ë™ì‹œì— 나눌 수 없습니다"
+
+msgid "E443: Cannot rotate when another window is split"
+msgstr "E443: 다른 ì°½ì´ ë‚˜ëˆ ì¡Œì„ ë•Œì—는 회전할 수 없습니다"
+
+msgid "E444: Cannot close last window"
+msgstr "E444: 마지막 ì°½ì„ ë‹«ì„ ìˆ˜ 없습니다"
+
+msgid "E813: Cannot close autocmd window"
+msgstr "E813: autocmd ì°½ì„ ë‹«ì„ ìˆ˜ 없습니다"
+
+msgid "E814: Cannot close window, only autocmd window would remain"
+msgstr "E814: ì°½ì„ ë‹«ì„ ìˆ˜ ì—†ìŒ, autocmd 창만 남ìŒ"
+
+msgid "E445: Other window contains changes"
+msgstr "E445: 다른 ì°½ì´ ë°”ë€Œì—ˆìŠµë‹ˆë‹¤"
+
+msgid "E446: No file name under cursor"
+msgstr "E446: 커서 ë°‘ì— íŒŒì¼ ì´ë¦„ì´ ì—†ìŠµë‹ˆë‹¤"
+
+#, c-format
+msgid "E447: Can't find file \"%s\" in path"
+msgstr "E447: pathì—ì„œ \"%s\" 파ì¼ì„ ì°¾ì„ ìˆ˜ 없습니다"
+
+#, c-format
+msgid "E799: Invalid ID: %ld (must be greater than or equal to 1)"
+msgstr "E799: 비정ìƒì ì¸ ID: %ld (1보다 í¬ê±°ë‚˜ 같아야 합니다)"
+
+#, c-format
+#~ msgid "E801: ID already taken: %ld"
+#~ msgstr ""
+
+msgid "List or number required"
+msgstr "List나 number가 필요합니다"
+
+#, c-format
+msgid "E802: Invalid ID: %ld (must be greater than or equal to 1)"
+msgstr "E802: 비정ìƒì ì¸ ID: %ld (1보다 í¬ê±°ë‚˜ 같아야 합니다)"
+
+#, c-format
+msgid "E803: ID not found: %ld"
+msgstr "E803: ID를 ì°¾ì„ ìˆ˜ ì—†ìŒ: %ld"
+
+#, c-format
+msgid "E370: Could not load library %s"
+msgstr "E370: %s ë¼ì´ë¸ŒëŸ¬ë¦¬ë¥¼ 로드할 수 없습니다"
+
+msgid "Sorry, this command is disabled: the Perl library could not be loaded."
+msgstr ""
+"미안합니다, ì´ ëª…ë ¹ì€ ì‚¬ìš©í•  수 없습니다, Perl ë¼ì´ë¸ŒëŸ¬ë¦¬ë¥¼ 로딩할 수 없습니"
+"다."
+
+msgid "E299: Perl evaluation forbidden in sandbox without the Safe module"
+msgstr "E299: Safe 모듈없ì´ëŠ” sandboxì—ì„œ Perl evaluationì´ ì œí•œë©ë‹ˆë‹¤"
+
+msgid "Edit with &multiple Vims"
+msgstr "여러 빔으로 편집(&M)"
+
+msgid "Edit with single &Vim"
+msgstr "í•˜ë‚˜ì˜ ë¹”ìœ¼ë¡œë§Œ 편집(&V)"
+
+msgid "Diff with Vim"
+msgstr "빔으로 Diff"
+
+msgid "Edit with &Vim"
+msgstr "빔으로 편집(&V)"
+
+msgid "Edit with existing Vim - "
+msgstr "í•˜ë‚˜ì˜ ë¹”ìœ¼ë¡œë§Œ 편집 - "
+
+msgid "Edits the selected file(s) with Vim"
+msgstr "ì„ íƒëœ 파ì¼(들)ì„ ë¹”ìœ¼ë¡œ 편집"
+
+msgid "Error creating process: Check if gvim is in your path!"
+msgstr "프로세스 ìƒì„± ì—러: gvimì´ pathì— ìžˆëŠ” 지 확ì¸í•˜ì„¸ìš”!"
+
+msgid "gvimext.dll error"
+msgstr "gvimext.dll ì—러"
+
+msgid "Path length too long!"
+msgstr "경로가 너무 ê¹ë‹ˆë‹¤"
+
+msgid "--No lines in buffer--"
+msgstr "--버í¼ì— 줄 ì—†ìŒ--"
+
+msgid "E470: Command aborted"
+msgstr "E470: ëª…ë ¹ì´ ì¤‘ì§€ë˜ì—ˆìŠµë‹ˆë‹¤"
+
+msgid "E471: Argument required"
+msgstr "E471: ì¸ìžê°€ 필요합니다"
+
+msgid "E10: \\ should be followed by /, ? or &"
+msgstr "E10: /, ? í˜¹ì€ &는 \\ ë’¤ì— ì™€ì•¼ 합니다"
+
+msgid "E11: Invalid in command-line window; <CR> executes, CTRL-C quits"
+msgstr "E11: 명령줄 ì°½ì— ìž˜ëª»ë¨; <CR> 실행, CTRL-C ë내기"
+
+msgid "E12: Command not allowed from exrc/vimrc in current dir or tag search"
+msgstr ""
+"E12: 현재 디렉토리 ë˜ëŠ” 태그 찾기ì—ì„œ exrc/vimrcì—ì„œì˜ ëª…ë ¹ì€ í—ˆìš© 안 ë©ë‹ˆë‹¤"
+
+msgid "E171: Missing :endif"
+msgstr "E171: :endif가 없습니다"
+
+msgid "E600: Missing :endtry"
+msgstr "E600: :endtry가 없습니다"
+
+msgid "E170: Missing :endwhile"
+msgstr "E170: :endwhileì´ ì—†ìŠµë‹ˆë‹¤"
+
+msgid "E170: Missing :endfor"
+msgstr "E170: :endfor 누ë½"
+
+msgid "E588: :endwhile without :while"
+msgstr "E588: :whileì—†ì´ :endwhileì´ ìžˆìŠµë‹ˆë‹¤"
+
+msgid "E588: :endfor without :for"
+msgstr "E588: :for 없는 :endfor"
+
+msgid "E13: File exists (add ! to override)"
+msgstr "E13: 파ì¼ì´ 있습니다 (ë®ì–´ì“°ë ¤ë©´ ! 사용)"
+
+msgid "E472: Command failed"
+msgstr "E472: ëª…ë ¹ì´ ì‹¤íŒ¨í–ˆìŠµë‹ˆë‹¤"
+
+#, c-format
+msgid "E234: Unknown fontset: %s"
+msgstr "E234: 모르는 글꼴셋: %s"
+
+#, c-format
+msgid "E235: Unknown font: %s"
+msgstr "E235: 모르는 글꼴: %s"
+
+#, c-format
+msgid "E236: Font \"%s\" is not fixed-width"
+msgstr "E236: 글꼴 \"%s\"ì€(는) ê³ ì •ë„“ì´ê°€ 아닙니다"
+
+msgid "E473: Internal error"
+msgstr "E473: 내부 ì—러"
+
+#, c-format
+msgid "E685: Internal error: %s"
+msgstr "E685: 내부 ì—러: %s"
+
+msgid "Interrupted"
+msgstr "중단ë˜ì—ˆìŠµë‹ˆë‹¤"
+
+msgid "E14: Invalid address"
+msgstr "E14: ìž˜ëª»ëœ ì£¼ì†Œ"
+
+msgid "E474: Invalid argument"
+msgstr "E474: ìž˜ëª»ëœ ì¸ìž"
+
+#, c-format
+msgid "E475: Invalid argument: %s"
+msgstr "E475: ìž˜ëª»ëœ ì¸ìž: %s"
+
+#, c-format
+msgid "E475: Invalid value for argument %s"
+msgstr "E475: ì¸ìž %sì— ìž˜ëª»ëœ ê°’"
+
+#, c-format
+msgid "E475: Invalid value for argument %s: %s"
+msgstr "E475: ì¸ìž %sì— ìž˜ëª»ëœ ê°’: %s"
+
+#, c-format
+msgid "E15: Invalid expression: %s"
+msgstr "E15: ìž˜ëª»ëœ í‘œí˜„ì‹: %s"
+
+msgid "E16: Invalid range"
+msgstr "E16: ìž˜ëª»ëœ ë²”ìœ„"
+
+msgid "E476: Invalid command"
+msgstr "E476: ìž˜ëª»ëœ ëª…ë ¹"
+
+#, c-format
+msgid "E17: \"%s\" is a directory"
+msgstr "E17: \"%s\"ì€(는) 디렉토리입니다"
+
+#, c-format
+msgid "E364: Library call failed for \"%s()\""
+msgstr "E364: ë¼ì´ë¸ŒëŸ¬ë¦¬ \"%s()\" 부르기 실패"
+
+msgid "E667: Fsync failed"
+msgstr "E667: Fsync가 실패했습니다"
+
+#, c-format
+msgid "E448: Could not load library function %s"
+msgstr "E448: %s ë¼ì´ë¸ŒëŸ¬ë¦¬ 함수를 로드할 수 없습니다"
+
+msgid "E19: Mark has invalid line number"
+msgstr "E19: 마í¬ê°€ ìž˜ëª»ëœ ì¤„ 번호를 가지고 있습니다"
+
+msgid "E20: Mark not set"
+msgstr "E20: 마í¬ê°€ 설정ë˜ì–´ 있지 않습니다"
+
+msgid "E21: Cannot make changes, 'modifiable' is off"
+msgstr "E21: 바꿀 수 ì—†ìŒ, 'modifiable'ì´ êº¼ì ¸ìžˆìŠµë‹ˆë‹¤"
+
+msgid "E22: Scripts nested too deep"
+msgstr "E22: 스í¬ë¦½íŠ¸ê°€ 너무 깊게 중첩ë˜ì—ˆìŠµë‹ˆë‹¤"
+
+msgid "E23: No alternate file"
+msgstr "E23: 다른 파ì¼ì´ 없습니다"
+
+msgid "E24: No such abbreviation"
+msgstr "E24: 그런 약어는 없습니다"
+
+msgid "E477: No ! allowed"
+msgstr "E477: !ì€ í—ˆìš©ë˜ì§€ 않습니다"
+
+msgid "E25: GUI cannot be used: Not enabled at compile time"
+msgstr "E25: GUI는 사용할 수 없습니다: ì»´íŒŒì¼ ë•Œ í¬í•¨ë˜ì§€ 않았습니다"
+
+msgid "E26: Hebrew cannot be used: Not enabled at compile time\n"
+msgstr "E26: Hebrew는 사용할 수 없습니다: ì»´íŒŒì¼ ë•Œ í¬í•¨ë˜ì§€ 않았습니다\n"
+
+msgid "E27: Farsi cannot be used: Not enabled at compile time\n"
+msgstr "E27: Farsi는 사용할 수 없습니다: ì»´íŒŒì¼ ë•Œ í¬í•¨ë˜ì§€ 않았습니다\n"
+
+msgid "E800: Arabic cannot be used: Not enabled at compile time\n"
+msgstr "E800: Arabicì€ ì‚¬ìš©í•  수 없습니다: ì»´íŒŒì¼ ë•Œ í¬í•¨ë˜ì§€ 않았습니다\n"
+
+#, c-format
+msgid "E28: No such highlight group name: %s"
+msgstr "E28: ì´ëŸ° 하ì´ë¼ì´íŠ¸ 그룹 ì´ë¦„ì€ ì—†ìŠµë‹ˆë‹¤: %s"
+
+msgid "E29: No inserted text yet"
+msgstr "E29: ìž…ë ¥ëœ í…스트가 ì•„ì§ ì—†ìŠµë‹ˆë‹¤"
+
+msgid "E30: No previous command line"
+msgstr "E30: ì´ì „ 명령 ì¤„ì´ ì—†ìŠµë‹ˆë‹¤"
+
+msgid "E31: No such mapping"
+msgstr "E31: 그런 ë§µí•‘ì´ ì—†ìŠµë‹ˆë‹¤"
+
+msgid "E479: No match"
+msgstr "E479: 맞지 않습니다"
+
+#, c-format
+msgid "E480: No match: %s"
+msgstr "E480: 맞지 ì•ŠìŒ: %s"
+
+msgid "E32: No file name"
+msgstr "E32: íŒŒì¼ ì´ë¦„ì´ ì—†ìŠµë‹ˆë‹¤"
+
+msgid "E33: No previous substitute regular expression"
+msgstr "E33: ì´ì „ 바꾸기 ì •ê·œ 표현ì‹ì´ 없습니다"
+
+msgid "E34: No previous command"
+msgstr "E34: ì´ì „ ëª…ë ¹ì´ ì—†ìŠµë‹ˆë‹¤"
+
+msgid "E35: No previous regular expression"
+msgstr "E35: ì´ì „ 정규표현ì‹ì´ 없습니다"
+
+msgid "E481: No range allowed"
+msgstr "E481: 범위는 허용ë˜ì§€ 않습니다"
+
+msgid "E36: Not enough room"
+msgstr "E36: 빈 ê³µê°„ì´ ì¶©ë¶„í•˜ì§€ 않습니다"
+
+#, c-format
+msgid "E247: no registered server named \"%s\""
+msgstr "E247: \"%s\"ì€(는) 등ë¡ëœ ì„œë²„ëª…ì´ ì•„ë‹™ë‹ˆë‹¤"
+
+#, c-format
+msgid "E482: Can't create file %s"
+msgstr "E482: %s 파ì¼ì„ 만들 수 없습니다"
+
+msgid "E483: Can't get temp file name"
+msgstr "E483: ìž„ì‹œ íŒŒì¼ ì´ë¦„ì„ ì–»ì„ ìˆ˜ 없습니다"
+
+#, c-format
+msgid "E484: Can't open file %s"
+msgstr "E484: %s 파ì¼ì„ ì—´ 수 없습니다"
+
+#, c-format
+msgid "E485: Can't read file %s"
+msgstr "E485: %s 파ì¼ì„ ì½ì„ 수 없습니다"
+
+msgid "E38: Null argument"
+msgstr "E38: ë„ ì¸ìž"
+
+msgid "E39: Number expected"
+msgstr "E39: 숫ìžê°€ 필요합니다"
+
+#, c-format
+msgid "E40: Can't open errorfile %s"
+msgstr "E40: ì—ëŸ¬íŒŒì¼ %sì„(를) ì—´ 수 없습니다"
+
+msgid "E233: cannot open display"
+msgstr "E233: 디스플레ì´ë¥¼ ì—´ 수 없습니다"
+
+msgid "E41: Out of memory!"
+msgstr "E41: 메모리가 바닥났습니다!"
+
+msgid "Pattern not found"
+msgstr "íŒ¨í„´ì„ ì°¾ì„ ìˆ˜ 없습니다"
+
+#, c-format
+msgid "E486: Pattern not found: %s"
+msgstr "E486: íŒ¨í„´ì„ ì°¾ì„ ìˆ˜ 없습니다: %s"
+
+msgid "E487: Argument must be positive"
+msgstr "E487: ì¸ìžëŠ” 양수ì´ì–´ì•¼ 합니다"
+
+msgid "E459: Cannot go back to previous directory"
+msgstr "E459: ì´ì „ 디렉토리로 ê°ˆ 수 없습니다"
+
+msgid "E42: No Errors"
+msgstr "E42: ì—러 ì—†ìŒ"
+
+msgid "E776: No location list"
+msgstr "E776: 위치 ëª©ë¡ ì—†ìŒ"
+
+msgid "E43: Damaged match string"
+msgstr "E43: 깨진 맞는 문ìžì—´"
+
+msgid "E44: Corrupted regexp program"
+msgstr "E44: 깨진 ì •ê·œí‘œí˜„ì‹ í”„ë¡œê·¸ëž¨"
+
+msgid "E45: 'readonly' option is set (add ! to override)"
+msgstr "E45: 'readonly' ì˜µì…˜ì´ ì„¤ì •ë˜ì–´ 있습니다 (ë®ì–´ì“°ë ¤ë©´ ! ë”하기)"
+
+#, c-format
+msgid "E46: Cannot change read-only variable \"%s\""
+msgstr "E46: ì½ê¸° ì „ìš© 변수 \"%s\"ì„(를) 바꿀 수 없습니다"
+
+#, c-format
+msgid "E794: Cannot set variable in the sandbox: \"%s\""
+msgstr "E794: sandbox 안ì—서는 변수를 설정할 수 ì—†ìŒ: \"%s\""
+
+msgid "E713: Cannot use empty key for Dictionary"
+msgstr "E713: Dictionaryì— ë¹ˆ 키를 쓸 수 없습니다"
+
+msgid "E715: Dictionary required"
+msgstr "E715: Dictionary가 필요합니다"
+
+#, c-format
+msgid "E684: list index out of range: %ld"
+msgstr "E684: ëª©ë¡ ë²ˆí˜¸ê°€ 범위를 벗어남: %ld"
+
+#, c-format
+msgid "E118: Too many arguments for function: %s"
+msgstr "E118: í•¨ìˆ˜ì— ë„ˆë¬´ ë§Žì€ ì¸ìž 넘김: %s"
+
+#, c-format
+msgid "E716: Key not present in Dictionary: %s"
+msgstr "E716: Dictionaryì— í‚¤ê°€ ì—†ìŒ: %s"
+
+msgid "E714: List required"
+msgstr "E714: List가 필요합니다"
+
+#, c-format
+msgid "E712: Argument of %s must be a List or Dictionary"
+msgstr "E712: %s ì¸ìžëŠ” List í˜¹ì€ Dictionary여야 합니다"
+
+msgid "E47: Error while reading errorfile"
+msgstr "E47: ì—ëŸ¬íŒŒì¼ ì½ëŠ” ë„ì¤‘ì— ì—러"
+
+msgid "E48: Not allowed in sandbox"
+msgstr "E48: sandboxì—서는 허용ë˜ì§€ 않습니다"
+
+msgid "E523: Not allowed here"
+msgstr "E523: 여기ì—ì„œ 허용ë˜ì§€ 않습니다"
+
+msgid "E359: Screen mode setting not supported"
+msgstr "E359: 스í¬ë¦° ìƒíƒœ ì„¤ì •ì€ ì§€ì›ë˜ì§€ 않습니다"
+
+msgid "E49: Invalid scroll size"
+msgstr "E49: 스í¬ë¡¤ í¬ê¸°ê°€ 잘못ë˜ì—ˆìŠµë‹ˆë‹¤"
+
+msgid "E91: 'shell' option is empty"
+msgstr "E91: 'shell' ì˜µì…˜ì´ ë¹„ì—ˆìŠµë‹ˆë‹¤"
+
+msgid "E255: Couldn't read in sign data!"
+msgstr "E255: sign ìžë£Œë¥¼ ì½ì„ 수 없습니다"
+
+msgid "E72: Close error on swap file"
+msgstr "E72: 스왑 파ì¼ì„ ë‹«ì„ ìˆ˜ 없습니다"
+
+msgid "E73: tag stack empty"
+msgstr "E73: 태그 스íƒì´ 비었습니다"
+
+msgid "E74: Command too complex"
+msgstr "E74: ëª…ë ¹ì´ ë„ˆë¬´ 복잡합니다"
+
+msgid "E75: Name too long"
+msgstr "E75: ì´ë¦„ì´ ë„ˆë¬´ ê¹ë‹ˆë‹¤"
+
+msgid "E76: Too many ["
+msgstr "E76: [가 너무 많습니다"
+
+msgid "E77: Too many file names"
+msgstr "E77: íŒŒì¼ ì´ë¦„ì´ ë„ˆë¬´ 많습니다"
+
+msgid "E488: Trailing characters"
+msgstr "E488: ëì— ë¬¸ìžê°€ ë” ìžˆìŠµë‹ˆë‹¤"
+
+msgid "E78: Unknown mark"
+msgstr "E78: 모르는 마í¬"
+
+msgid "E79: Cannot expand wildcards"
+msgstr "E79: 만능 글ìžë¥¼ 확장할 수 없습니다"
+
+msgid "E591: 'winheight' cannot be smaller than 'winminheight'"
+msgstr "E591: 'winheight'는 'winminheight'보다 커야 합니다"
+
+msgid "E592: 'winwidth' cannot be smaller than 'winminwidth'"
+msgstr "E592: 'winwidth'는 'winminwidth'보다 커야 합니다"
+
+msgid "E80: Error while writing"
+msgstr "E80: 쓰는 ì¤‘ì— ì—러"
+
+#~ msgid "E939: Positive count required"
+#~ msgstr ""
+
+msgid "E81: Using <SID> not in a script context"
+msgstr "E81: 스í¬ë¦½íŠ¸ 콘í…스트 ë°–ì—ì„œ <SID> 사용"
+
+msgid "E449: Invalid expression received"
+msgstr "E449: ìž˜ëª»ëœ í‘œí˜„ì‹ì´ 받아졌습니다"
+
+msgid "E463: Region is guarded, cannot modify"
+msgstr "E463: ì˜ì—­ì´ 보호ë˜ê³  있어서 수정할 수 없습니다"
+
+msgid "E744: NetBeans does not allow changes in read-only files"
+msgstr "E744: NetBeans는 ì½ê¸° ì „ìš© 파ì¼ì„ 바꿀 수 없습니다"
+
+msgid "E363: pattern uses more memory than 'maxmempattern'"
+msgstr "E363: íŒ¨í„´ì´ 'maxmempattern'보다 ë§Žì€ ë©”ëª¨ë¦¬ë¥¼ 사용합니다"
+
+msgid "E749: empty buffer"
+msgstr "E749: 빈 버í¼"
+
+#, c-format
+msgid "E86: Buffer %ld does not exist"
+msgstr "E86: ë²„í¼ %ldì´(ê°€) 존재하지 않습니다"
+
+msgid "E682: Invalid search pattern or delimiter"
+msgstr "E682: ìž˜ëª»ëœ ì°¾ê¸° 패턴 í˜¹ì€ êµ¬ë¶„ìž"
+
+msgid "E139: File is loaded in another buffer"
+msgstr "E139: 파ì¼ì´ 다른 버í¼ì— 로딩ë˜ì–´ 있습니다"
+
+#, c-format
+msgid "E764: Option '%s' is not set"
+msgstr "E764: 옵션 '%s'ì´(ê°€) 설정ë˜ì–´ 있지 않습니다"
+
+msgid "E850: Invalid register name"
+msgstr "E850: ìž˜ëª»ëœ ë ˆì§€ìŠ¤í„° ì´ë¦„"
+
+#, c-format
+msgid "E919: Directory not found in '%s': \"%s\""
+msgstr "E919: '%s'ì—ì„œ 디렉토리를 못찾ìŒ: \"%s\""
+
+msgid "E952: Autocommand caused recursive behavior"
+msgstr "E952: Autocommandê°€ 재귀 호출ë˜ì—ˆìŠµë‹ˆë‹¤"
+
+msgid "search hit TOP, continuing at BOTTOM"
+msgstr "처ìŒê¹Œì§€ 찾았ìŒ, ëì—ì„œ 계ì†"
+
+msgid "search hit BOTTOM, continuing at TOP"
+msgstr "ë까지 찾았ìŒ, 처ìŒë¶€í„° 계ì†"
+
+#, c-format
+msgid "Need encryption key for \"%s\""
+msgstr "\"%s\"ì— ëŒ€í•œ 암호 키가 필요합니다"
+
+msgid "empty keys are not allowed"
+msgstr "빈 키 ê°’ì€ í—ˆìš©ë˜ì§€ 않습니다"
+
+msgid "dictionary is locked"
+msgstr "dictionary가 잠겨있습니다"
+
+msgid "list is locked"
+msgstr "list가 잠겨있습니다"
+
+#, c-format
+msgid "failed to add key '%s' to dictionary"
+msgstr "dictionaryì— '%s' 키를 추가할 수 없습니다"
+
+#, c-format
+#~ msgid "index must be int or slice, not %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "expected str() or unicode() instance, but got %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "expected bytes() or str() instance, but got %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid ""
+#~ "expected int(), long() or something supporting coercing to long(), but got %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "expected int() or something supporting coercing to int(), but got %s"
+#~ msgstr ""
+
+msgid "value is too large to fit into C int type"
+msgstr "ê°’ì´ C 정수 í˜•ì‹ ëŒ€ë¹„í•˜ì—¬ 너무 í½ë‹ˆë‹¤"
+
+msgid "value is too small to fit into C int type"
+msgstr "ê°’ì´ C 정수 í˜•ì‹ ëŒ€ë¹„í•˜ì—¬ 너무 작습니다"
+
+msgid "number must be greater than zero"
+msgstr "ê°’ì´ 0보다 커야 합니다"
+
+msgid "number must be greater or equal to zero"
+msgstr "ê°’ì´ 0보다 í¬ê±°ë‚˜ 같아야 합니다"
+
+msgid "can't delete OutputObject attributes"
+msgstr "OutputObject ì†ì„±ì„ 지울 수 없습니다"
+
+#, c-format
+msgid "invalid attribute: %s"
+msgstr "ìž˜ëª»ëœ ì†ì„±: %s"
+
+msgid "E264: Python: Error initialising I/O objects"
+msgstr "E264: 파ì´ì¬: I/O ê°ì²´ 초기화중 ì—러가 ìƒê²¼ìŠµë‹ˆë‹¤"
+
+msgid "failed to change directory"
+msgstr "디렉토리를 바꿀 수 없습니다"
+
+#, c-format
+#~ msgid "expected 3-tuple as imp.find_module() result, but got %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "expected 3-tuple as imp.find_module() result, but got tuple of size %d"
+#~ msgstr ""
+
+#~ msgid "internal error: imp.find_module returned tuple with NULL"
+#~ msgstr ""
+
+msgid "cannot delete vim.Dictionary attributes"
+msgstr "vim.Dictionary ì†ì„±ì„ 삭제할 수 없습니다"
+
+msgid "cannot modify fixed dictionary"
+msgstr "fixed dictionary를 수정할 수 없습니다"
+
+#, c-format
+msgid "cannot set attribute %s"
+msgstr "ì†ì„± %sì„(를) 설정할 수 없습니다"
+
+#~ msgid "hashtab changed during iteration"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "expected sequence element of size 2, but got sequence of size %d"
+#~ msgstr ""
+
+#~ msgid "list constructor does not accept keyword arguments"
+#~ msgstr ""
+
+msgid "list index out of range"
+msgstr "list 색ì¸ì´ 범위를 벗어났습니다"
+
+#, c-format
+#~ msgid "internal error: failed to get vim list item %d"
+#~ msgstr ""
+
+#~ msgid "slice step cannot be zero"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "attempt to assign sequence of size greater than %d to extended slice"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "internal error: no vim list item %d"
+#~ msgstr ""
+
+#~ msgid "internal error: not enough list items"
+#~ msgstr ""
+
+#~ msgid "internal error: failed to add item to list"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "attempt to assign sequence of size %d to extended slice of size %d"
+#~ msgstr ""
+
+#~ msgid "failed to add item to list"
+#~ msgstr ""
+
+msgid "cannot delete vim.List attributes"
+msgstr "vim.List ì†ì„±ì„ 삭제할 수 없습니다"
+
+#~ msgid "cannot modify fixed list"
+#~ msgstr ""
+
+#, c-format
+msgid "unnamed function %s does not exist"
+msgstr "ì´ë¦„없는 함수 %sì´(ê°€) 존재하지 않습니다"
+
+#, c-format
+msgid "function %s does not exist"
+msgstr "함수 %sì´(ê°€) 존재하지 않습니다"
+
+#, c-format
+msgid "failed to run function %s"
+msgstr "함수 %sì„(를) 실행할 수 없습니다"
+
+msgid "unable to get option value"
+msgstr "옵션 ê°’ì„ ì–»ì„ ìˆ˜ 없습니다"
+
+#~ msgid "internal error: unknown option type"
+#~ msgstr ""
+
+#~ msgid "problem while switching windows"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "unable to unset global option %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "unable to unset option %s which does not have global value"
+#~ msgstr ""
+
+msgid "attempt to refer to deleted tab page"
+msgstr "지워진 탭 페ì´ì§€ë¥¼ 참조하려고 하였습니다"
+
+msgid "no such tab page"
+msgstr "그런 탭 페ì´ì§€ê°€ 없습니다"
+
+msgid "attempt to refer to deleted window"
+msgstr "지워진 ì°½ì„ ì°¸ì¡°í•˜ë ¤ê³  하였습니다"
+
+msgid "readonly attribute: buffer"
+msgstr "ì½ê¸° ì „ìš© ì†ì„±: 버í¼"
+
+msgid "cursor position outside buffer"
+msgstr "í¼ì„œ 위치가 ë²„í¼ ë°–ì— ìžˆìŠµë‹ˆë‹¤"
+
+msgid "no such window"
+msgstr "그런 ì°½ì€ ì—†ìŠµë‹ˆë‹¤"
+
+msgid "attempt to refer to deleted buffer"
+msgstr "지워진 버í¼ë¥¼ 참조하려고 하였습니다"
+
+msgid "failed to rename buffer"
+msgstr "ë²„í¼ ì´ë¦„ì„ ë³€ê²½í•  수 없습니다"
+
+#~ msgid "mark name must be a single character"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "expected vim.Buffer object, but got %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "failed to switch to buffer %d"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "expected vim.Window object, but got %s"
+#~ msgstr ""
+
+#~ msgid "failed to find window in the current tab page"
+#~ msgstr ""
+
+#~ msgid "did not switch to the specified window"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "expected vim.TabPage object, but got %s"
+#~ msgstr ""
+
+#~ msgid "did not switch to the specified tab page"
+#~ msgstr ""
+
+#~ msgid "failed to run the code"
+#~ msgstr ""
+
+#~ msgid "E858: Eval did not return a valid python object"
+#~ msgstr ""
+
+#~ msgid "E859: Failed to convert returned python object to vim value"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "unable to convert %s to vim dictionary"
+#~ msgstr ""
+
+#, c-format
+msgid "unable to convert %s to vim list"
+msgstr "%sì„(를) vim listë¡œ 변경할 수 없습니다"
+
+#, c-format
+#~ msgid "unable to convert %s to vim structure"
+#~ msgstr ""
+
+#~ msgid "internal error: NULL reference passed"
+#~ msgstr ""
+
+#~ msgid "internal error: invalid value type"
+#~ msgstr ""
+
+#~ msgid ""
+#~ "Failed to set path hook: sys.path_hooks is not a list\n"
+#~ "You should now do the following:\n"
+#~ "- append vim.path_hook to sys.path_hooks\n"
+#~ "- append vim.VIM_SPECIAL_PATH to sys.path\n"
+#~ msgstr ""
+
+#~ msgid ""
+#~ "Failed to set path: sys.path is not a list\n"
+#~ "You should now append vim.VIM_SPECIAL_PATH to sys.path"
+#~ msgstr ""
+
+msgid ""
+"Vim macro files (*.vim)\t*.vim\n"
+"All Files (*.*)\t*.*\n"
+msgstr ""
+"Vim 매í¬ë¡œ íŒŒì¼ (*.vim)\t*.vim\n"
+"모든 íŒŒì¼ (*.*)\t*.*\n"
+
+msgid "All Files (*.*)\t*.*\n"
+msgstr "모든 íŒŒì¼ (*.*)\t*.*\n"
+
+msgid ""
+"All Files (*.*)\t*.*\n"
+"C source (*.c, *.h)\t*.c;*.h\n"
+"C++ source (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"VB code (*.bas, *.frm)\t*.bas;*.frm\n"
+"Vim files (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
+msgstr ""
+"모든 íŒŒì¼ (*.*)\t*.*\n"
+"C 소스 (*.c, *.h)\t*.c;*.h\n"
+"C++ 소스 (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"VB 코드 (*.bas, *.frm)\t*.bas;*.frm\n"
+"Vim íŒŒì¼ (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
+
+msgid ""
+"Vim macro files (*.vim)\t*.vim\n"
+"All Files (*)\t*\n"
+msgstr ""
+"Vim 매í¬ë¡œ íŒŒì¼ (*.vim)\t*.vim\n"
+"모든 íŒŒì¼ (*)\t*\n"
+
+msgid "All Files (*)\t*\n"
+msgstr "모든 íŒŒì¼ (*)\t*\n"
+
+msgid ""
+"All Files (*)\t*\n"
+"C source (*.c, *.h)\t*.c;*.h\n"
+"C++ source (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"Vim files (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
+msgstr ""
+"모든 íŒŒì¼ (*)\t*\n"
+"C 소스 (*.c, *.h)\t*.c;*.h\n"
+"C++ 소스 (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"Vim íŒŒì¼ (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
diff --git a/src/po/ko.po b/src/po/ko.po
new file mode 100644
index 0000000..c7c67a2
--- /dev/null
+++ b/src/po/ko.po
@@ -0,0 +1,7009 @@
+# Generated from ko.UTF-8.po, DO NOT EDIT
+#
+# FIRST AUTHOR SungHyun Nam <goweol@gmail.com>, 2000-2018
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: vim 8.1\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2018-06-29 08:21+0900\n"
+"PO-Revision-Date: 2018-06-29 09:32+0900\n"
+"Last-Translator: SungHyun Nam <goweol@gmail.com>\n"
+"Language-Team: Korean\n"
+"Language: ko\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=euc-kr\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+
+msgid "E831: bf_key_init() called with empty password"
+msgstr "E831: ºó ºñ¹Ð¹øÈ£·Î bf_key_init() ÇÔ¼ö°¡ ºÒ·ÁÁ³½À´Ï´Ù"
+
+msgid "E820: sizeof(uint32_t) != 4"
+msgstr "E820: sizeof(uint32_t) != 4"
+
+msgid "E817: Blowfish big/little endian use wrong"
+msgstr "E817: Blowfish big/little endian use wrong"
+
+msgid "E818: sha256 test failed"
+msgstr "E818: sha256 ½ÃÇèÀÌ ½ÇÆÐÇß½À´Ï´Ù."
+
+msgid "E819: Blowfish test failed"
+msgstr "E819: Blowfish ½ÃÇèÀÌ ½ÇÆÐÇß½À´Ï´Ù."
+
+msgid "[Location List]"
+msgstr "[À§Ä¡ ¸ñ·Ï]"
+
+msgid "[Quickfix List]"
+msgstr "[Quickfix ¸ñ·Ï]"
+
+msgid "E855: Autocommands caused command to abort"
+msgstr "E855: Autocommand·Î ¸í·ÉÀÌ ÁߴܵǾú½À´Ï´Ù"
+
+msgid "E82: Cannot allocate any buffer, exiting..."
+msgstr "E82: ¹öÆÛ¸¦ ÇÒ´çÇÒ ¼ö ¾ø¾î¼­ ³¡³À´Ï´Ù..."
+
+msgid "E83: Cannot allocate buffer, using other one..."
+msgstr "E83: ¹öÆÛ¸¦ ÇÒ´çÇÒ ¼ö ¾ø¾î¼­ ´Ù¸¥ °É »ç¿ëÇÕ´Ï´Ù..."
+
+msgid "E931: Buffer cannot be registered"
+msgstr "E931: ¹öÆÛ¸¦ µî·ÏÇÏÁö ¸øÇß½À´Ï´Ù"
+
+msgid "E937: Attempt to delete a buffer that is in use"
+msgstr "E937: »ç¿ëÁßÀÎ ¹öÆÛ¸¦ »èÁ¦ÇÏ·Á°í Çß½À´Ï´Ù"
+
+msgid "E515: No buffers were unloaded"
+msgstr "E515: ³»·ÁÁø ¹öÆÛ°¡ ¾ø½À´Ï´Ù"
+
+msgid "E516: No buffers were deleted"
+msgstr "E516: Áö¿öÁø ¹öÆÛ°¡ ¾ø½À´Ï´Ù"
+
+msgid "E517: No buffers were wiped out"
+msgstr "E517: ¿ÏÀüÈ÷ Áö¿öÁø ¹öÆÛ°¡ ¾ø½À´Ï´Ù"
+
+msgid "1 buffer unloaded"
+msgstr "¹öÆÛ ÇÑ °³°¡ ³»·ÁÁ³½À´Ï´Ù"
+
+#, c-format
+msgid "%d buffers unloaded"
+msgstr "¹öÆÛ %d °³°¡ ³»·ÁÁ³½À´Ï´Ù"
+
+msgid "1 buffer deleted"
+msgstr "¹öÆÛ ÇÑ °³°¡ Áö¿öÁ³½À´Ï´Ù"
+
+#, c-format
+msgid "%d buffers deleted"
+msgstr "¹öÆÛ %d °³°¡ Áö¿öÁ³½À´Ï´Ù"
+
+msgid "1 buffer wiped out"
+msgstr "¹öÆÛ ÇÑ °³°¡ ¿ÏÀüÈ÷ Áö¿öÁ³½À´Ï´Ù"
+
+#, c-format
+msgid "%d buffers wiped out"
+msgstr "¹öÆÛ %d°³°¡ ¿ÏÀüÈ÷ Áö¿öÁ³½À´Ï´Ù"
+
+msgid "E90: Cannot unload last buffer"
+msgstr "E90: ¸¶Áö¸· ¹öÆÛ¸¦ ³»¸± ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E84: No modified buffer found"
+msgstr "E84: ¹Ù²ï ¹öÆÛ¸¦ ãÀ» ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E85: There is no listed buffer"
+msgstr "E85: ³ª¿­µÈ ¹öÆÛ°¡ ¾ø½À´Ï´Ù"
+
+msgid "E87: Cannot go beyond last buffer"
+msgstr "E87: ¸¶Áö¸· ¹öÆÛÀÔ´Ï´Ù"
+
+msgid "E88: Cannot go before first buffer"
+msgstr "E88: ù ¹ø° ¹öÆÛÀÔ´Ï´Ù"
+
+#, c-format
+msgid "E89: No write since last change for buffer %ld (add ! to override)"
+msgstr ""
+"E89: ¹öÆÛ %ldÀ»(¸¦) ¸¶Áö¸·À¸·Î °íÄ£ µÚ ÀúÀåÇÏÁö ¾Ê¾Ò½À´Ï´Ù (µ¤¾î¾²·Á¸é ! ´õÇÏ"
+"±â)"
+
+msgid "E948: Job still running (add ! to end the job)"
+msgstr "E948: JobÀÌ ¾ÆÁ÷ ½ÇÇàÁßÀÔ´Ï´Ù (³¡³»·Á¸é ¸¶Áö¸·¿¡ !À» Ãß°¡)"
+
+msgid "E37: No write since last change (add ! to override)"
+msgstr "E37: ¸¶Áö¸·À¸·Î °íÄ£ µÚ ÀúÀåµÇÁö ¾Ê¾Ò½À´Ï´Ù (¹«½ÃÇÏ·Á¸é ! ´õÇϱâ)"
+
+msgid "E948: Job still running"
+msgstr "E948: JobÀÌ ¾ÆÁ÷ ½ÇÇàÁßÀÔ´Ï´Ù"
+
+msgid "E37: No write since last change"
+msgstr "E37: ¸¶Áö¸·À¸·Î °íÄ£ µÚ ÀúÀåÇÏÁö ¾Ê¾Ò½À´Ï´Ù"
+
+msgid "W14: Warning: List of file names overflow"
+msgstr "W14: °æ°í: ÆÄÀÏ À̸§ ¸ñ·ÏÀÌ ³ÑÃƽÀ´Ï´Ù"
+
+#, c-format
+msgid "E92: Buffer %ld not found"
+msgstr "E92: ¹öÆÛ %ldÀ»(¸¦) ãÀ» ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "E93: More than one match for %s"
+msgstr "E93: %sÀ»(¸¦) Çϳª ÀÌ»ó ã¾Ò½À´Ï´Ù"
+
+#, c-format
+msgid "E94: No matching buffer for %s"
+msgstr "E94: %s¿Í ¸Â´Â ¹öÆÛ°¡ ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "line %ld"
+msgstr "%ld ÁÙ"
+
+msgid "E95: Buffer with this name already exists"
+msgstr "E95: ÀÌ À̸§À» °¡Áø ¹öÆÛ°¡ ÀÌ¹Ì ÀÖ½À´Ï´Ù"
+
+msgid " [Modified]"
+msgstr " [¹Ù²ñ]"
+
+msgid "[Not edited]"
+msgstr "[°íÄ¡Áö ¾Ê¾ÒÀ½]"
+
+msgid "[New file]"
+msgstr "[»õ ÆÄÀÏ]"
+
+msgid "[Read errors]"
+msgstr "[Àб⠿¡·¯]"
+
+msgid "[RO]"
+msgstr "[Àбâ Àü¿ë]"
+
+msgid "[readonly]"
+msgstr "[Àбâ Àü¿ë]"
+
+#, c-format
+msgid "1 line --%d%%--"
+msgstr "1 ÁÙ --%d%%--"
+
+#, c-format
+msgid "%ld lines --%d%%--"
+msgstr "%ld ÁÙ --%d%%--"
+
+#, c-format
+msgid "line %ld of %ld --%d%%-- col "
+msgstr "%ld / %ld ÁÙ --%d%%-- Ä­ "
+
+msgid "[No Name]"
+msgstr "[À̸§ ¾øÀ½]"
+
+msgid "help"
+msgstr "µµ¿ò¸»"
+
+msgid "[Help]"
+msgstr "[µµ¿ò¸»]"
+
+msgid "[Preview]"
+msgstr "[¹Ì¸® º¸±â]"
+
+msgid "All"
+msgstr "¸ðµÎ"
+
+msgid "Bot"
+msgstr "¹Ù´Ú"
+
+msgid "Top"
+msgstr "²À´ë±â"
+
+msgid ""
+"\n"
+"# Buffer list:\n"
+msgstr ""
+"\n"
+"# ¹öÆÛ ¸ñ·Ï:\n"
+
+msgid "E382: Cannot write, 'buftype' option is set"
+msgstr "E382: ¾µ ¼ö ¾øÀ½, 'buftype' ¿É¼ÇÀÌ ¼³Á¤µÇ¾î ÀÖ½À´Ï´Ù"
+
+msgid "[Prompt]"
+msgstr "[Prompt]"
+
+msgid "[Scratch]"
+msgstr "[Scratch]"
+
+msgid ""
+"\n"
+"--- Signs ---"
+msgstr ""
+"\n"
+"--- ±âÈ£ ---"
+
+#, c-format
+msgid "Signs for %s:"
+msgstr "%s¿¡ ´ëÇÑ ±âÈ£:"
+
+#, c-format
+msgid " line=%ld id=%d name=%s"
+msgstr " ÁÙ=%ld id=%d À̸§=%s"
+
+msgid "E902: Cannot connect to port"
+msgstr "E902: Æ÷Æ®·Î ¿¬°áÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E901: gethostbyname() in channel_open()"
+msgstr "E901: channel_open()¿¡¼­ gethostbyname()"
+
+msgid "E898: socket() in channel_open()"
+msgstr "E898: channel_open()¿¡¼­ socket()"
+
+msgid "E903: received command with non-string argument"
+msgstr "E903: ¹®ÀÚ¿­ÀÌ ¾Æ´Ñ ÀÎÀÚ¸¦ ¸í·ÉÀ¸·Î ¼ö½ÅÇß½À´Ï´Ù"
+
+msgid "E904: last argument for expr/call must be a number"
+msgstr "E904: expr/callÀÇ ¸¶Áö¸· ÀÎÀÚ´Â ¼ýÀÚ¿©¾ß ÇÕ´Ï´Ù"
+
+msgid "E904: third argument for call must be a list"
+msgstr "E904: 3¹ø° ÀÎÀÚ´Â list¿©¾ß ÇÕ´Ï´Ù"
+
+#, c-format
+msgid "E905: received unknown command: %s"
+msgstr "E905: ¸ð¸£´Â ¸í·É ¼ö½Å: %s"
+
+#, c-format
+msgid "E630: %s(): write while not connected"
+msgstr "E630: %s(): ¿¬°áµÇÁö ¾Ê¾Ò´Â µ¥ ¾²±â"
+
+#, c-format
+msgid "E631: %s(): write failed"
+msgstr "E631: %s(): ¾²±â°¡ ½ÇÆÐÇß½À´Ï´Ù"
+
+#, c-format
+msgid "E917: Cannot use a callback with %s()"
+msgstr "E917: %s()¿¡´Â callbackÀ» »ç¿ëÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E912: cannot use ch_evalexpr()/ch_sendexpr() with a raw or nl channel"
+msgstr ""
+"E912: raw ȤÀº nl ä³Î¿¡¼­ ch_evalexpr()/ch_sendexpr()À» »ç¿ëÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E906: not an open channel"
+msgstr "E906: ¿­¸° ä³ÎÀÌ ¾Æ´Õ´Ï´Ù"
+
+msgid "E920: _io file requires _name to be set"
+msgstr "E920: _io ÆÄÀÏÀº ¼³Á¤ÇÏ·Á¸é _nameÀÌ ÇÊ¿äÇÕ´Ï´Ù"
+
+msgid "E915: in_io buffer requires in_buf or in_name to be set"
+msgstr "E915: in_io ¹öÆÛ´Â ¼³Á¤ÇÏ·Á¸é in_buf³ª in_nameÀÌ ÇÊ¿äÇÕ´Ï´Ù"
+
+#, c-format
+msgid "E918: buffer must be loaded: %s"
+msgstr "E918: ¹öÆÛ°¡ ·ÎµùµÇ¾î¾ß ÇÕ´Ï´Ù: %s"
+
+msgid "E821: File is encrypted with unknown method"
+msgstr "E821: ÆÄÀÏÀÌ ¸ð¸£´Â ¹æ¹ýÀ¸·Î ¾ÏȣȭµÇ¾î ÀÖ½À´Ï´Ù"
+
+msgid "Warning: Using a weak encryption method; see :help 'cm'"
+msgstr "°æ°í: ¾àÇÑ ¾ÏÈ£ ¹æ½ÄÀ» »ç¿ëÁß; :help 'cm'À» È®ÀÎÇϼ¼¿ä"
+
+msgid "Enter encryption key: "
+msgstr "¾ÏÈ£ Å° ÀÔ·Â: "
+
+msgid "Enter same key again: "
+msgstr "°°Àº Å°¸¦ ´Ù½Ã ÀÔ·Â: "
+
+msgid "Keys don't match!"
+msgstr "Å°°¡ ¸ÂÁö ¾Ê½À´Ï´Ù!"
+
+msgid "[crypted]"
+msgstr "[¾Ïȣȭ µÇ¾ú½À´Ï´Ù]"
+
+#, c-format
+msgid "E720: Missing colon in Dictionary: %s"
+msgstr "E720: Dictionary¿¡ ÄÝ·Ð ´©¶ô: %s"
+
+#, c-format
+msgid "E721: Duplicate key in Dictionary: \"%s\""
+msgstr "E721: Dictionary¿¡ Áߺ¹µÈ Å°: \"%s\""
+
+#, c-format
+msgid "E722: Missing comma in Dictionary: %s"
+msgstr "E722: Dictionary¿¡ ÄÞ¸¶ ´©¶ô: %s"
+
+#, c-format
+msgid "E723: Missing end of Dictionary '}': %s"
+msgstr "E723: Dictionary ³¡¿¡ '}' ´©¶ô: %s"
+
+msgid "extend() argument"
+msgstr "extend() ÀÎÀÚ"
+
+#, c-format
+msgid "E737: Key already exists: %s"
+msgstr "E737: Å°°¡ ÀÌ¹Ì Á¸ÀçÇÔ: %s"
+
+#, c-format
+msgid "E96: Cannot diff more than %ld buffers"
+msgstr "E96: ¹öÆÛ¸¦ %ld°³ ÀÌ»óÀº ºñ±³ÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E810: Cannot read or write temp files"
+msgstr "E810: Àӽà ÆÄÀÏÀ» Àаųª ¾µ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E97: Cannot create diffs"
+msgstr "E97: diff¸¦ ¸¸µé ¼ö ¾ø½À´Ï´Ù"
+
+msgid "Patch file"
+msgstr "ÆÐÅ° ÆÄÀÏ"
+
+msgid "E816: Cannot read patch output"
+msgstr "E816: patch °á°ú¸¦ ÀÐÀ» ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E98: Cannot read diff output"
+msgstr "E98: diff Ãâ·ÂÀ» ÀÐÀ» ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E99: Current buffer is not in diff mode"
+msgstr "E99: ÇöÀç ¹öÆÛ´Â diff »óÅ°¡ ¾Æ´Õ´Ï´Ù"
+
+msgid "E793: No other buffer in diff mode is modifiable"
+msgstr "E793: ¼öÁ¤ °¡´ÉÇÑ diff »óÅ ¹öÆÛ´Â ¾ø½À´Ï´Ù"
+
+msgid "E100: No other buffer in diff mode"
+msgstr "E100: ´Ù¸¥ ¹öÆÛÁß¿¡ diff »óÅÂÀÎ °Ô ¾ø½À´Ï´Ù"
+
+msgid "E101: More than two buffers in diff mode, don't know which one to use"
+msgstr ""
+"E101: µÎ°³ ÀÌ»óÀÇ ¹öÆÛ°¡ diff »óÅ¿©¼­ ¾î¶² °ÍÀ» ½á¾ßÇÒ Áö ¾Ë ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "E102: Can't find buffer \"%s\""
+msgstr "E102: \"%s\" ¹öÆÛ¸¦ ãÀ» ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "E103: Buffer \"%s\" is not in diff mode"
+msgstr "E103: \"%s\" ¹öÆÛ´Â diff »óÅ°¡ ¾Æ´Õ´Ï´Ù"
+
+msgid "E787: Buffer changed unexpectedly"
+msgstr "E787: ¹öÆÛ°¡ ¸ð¸£´Â »çÀÌ¿¡ ¹Ù²î¾ú½À´Ï´Ù"
+
+msgid "E104: Escape not allowed in digraph"
+msgstr "E104: digraph¿¡´Â EscapeÀ» ¾µ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E544: Keymap file not found"
+msgstr "E544: Å°¸Ê ÆÄÀÏÀ» ãÀ» ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E105: Using :loadkeymap not in a sourced file"
+msgstr "E105: ºÒ·¯µéÀÎ ÆÄÀÏ¿¡¼­ :loadkeymapÀ» »ç¿ëÇÏÁö ¾Ê¾Ò½À´Ï´Ù"
+
+msgid "E791: Empty keymap entry"
+msgstr "E791: Å°¸Ê ¿£Æ®¸®°¡ ºñ¾îÀÖÀ½"
+
+msgid " Keyword completion (^N^P)"
+msgstr " ³¹¸» ¿Ï¼º (^N^P)"
+
+msgid " ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+msgstr " ^X ¸ðµå (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+
+msgid " Whole line completion (^L^N^P)"
+msgstr " Àüü ÁÙ ¿Ï¼º (^L^N^P)"
+
+msgid " File name completion (^F^N^P)"
+msgstr " ÆÄÀÏ À̸§ ¿Ï¼º (^F^N^P)"
+
+msgid " Tag completion (^]^N^P)"
+msgstr " ÅÂ±× ¿Ï¼º (^]^N^P)"
+
+msgid " Path pattern completion (^N^P)"
+msgstr " °æ·Î ÆÐÅÏ ¿Ï¼º (^N^P)"
+
+msgid " Definition completion (^D^N^P)"
+msgstr " Á¤ÀÇ ¿Ï¼º (^D^N^P)"
+
+msgid " Dictionary completion (^K^N^P)"
+msgstr " Dictionary ¿Ï¼º (^K^N^P)"
+
+msgid " Thesaurus completion (^T^N^P)"
+msgstr " ¹é°ú»çÀü ¿Ï¼º (^T^N^P)"
+
+msgid " Command-line completion (^V^N^P)"
+msgstr " ¸í·ÉÇà ¿Ï¼º (^V^N^P)"
+
+msgid " User defined completion (^U^N^P)"
+msgstr " »ç¿ëÀÚ Á¤ÀÇ ¿Ï¼º (^U^N^P)"
+
+msgid " Omni completion (^O^N^P)"
+msgstr " Omni ¿Ï¼º (^O^N^P)"
+
+msgid " Spelling suggestion (s^N^P)"
+msgstr " ´Ü¾î Á¦¾È (s^N^P)"
+
+msgid " Keyword Local completion (^N^P)"
+msgstr " ³¹¸» ·ÎÄà ¿Ï¼º (^N^P)"
+
+msgid "Hit end of paragraph"
+msgstr "´Ü¶ôÀÇ ¸¶Áö¸· ¸¸³²"
+
+msgid "E839: Completion function changed window"
+msgstr "E839: Completion ±â´ÉÀÌ Ã¢À» ¹Ù²Ù¾ú½À´Ï´Ù"
+
+msgid "E840: Completion function deleted text"
+msgstr "E840: Completion ±â´ÉÀÌ ¹®ÀÚ¿­À» Áö¿ü½À´Ï´Ù"
+
+msgid "'dictionary' option is empty"
+msgstr "'dictionary' ¿É¼ÇÀÌ ºñ¾ú½À´Ï´Ù"
+
+msgid "'thesaurus' option is empty"
+msgstr "'thesaurus' ¿É¼ÇÀÌ ºñ¾ú½À´Ï´Ù"
+
+#, c-format
+msgid "Scanning dictionary: %s"
+msgstr "»çÀü ã´Â Áß: %s"
+
+msgid " (insert) Scroll (^E/^Y)"
+msgstr " (³¢¿ö³Ö±â) ½ºÅ©·Ñ (^E/^Y)"
+
+msgid " (replace) Scroll (^E/^Y)"
+msgstr " (¹Ù²Þ) ½ºÅ©·Ñ (^E/^Y)"
+
+#, c-format
+msgid "Scanning: %s"
+msgstr "ã´Â Áß: %s"
+
+msgid "Scanning tags."
+msgstr "ÅÂ±× Ã£´Â Áß."
+
+msgid "match in file"
+msgstr "match in file"
+
+msgid " Adding"
+msgstr " ´õÇϱâ"
+
+msgid "-- Searching..."
+msgstr "-- ã´Â Áß..."
+
+msgid "Back at original"
+msgstr "¿ø·¡´ë·Î º¹±¸"
+
+msgid "Word from other line"
+msgstr "´Ù¸¥ ÁÙ¿¡ ³¹¸»"
+
+msgid "The only match"
+msgstr "The only match"
+
+#, c-format
+msgid "match %d of %d"
+msgstr "match %d of %d"
+
+#, c-format
+msgid "match %d"
+msgstr "match %d"
+
+msgid "E18: Unexpected characters in :let"
+msgstr "E18: ':let'¿¡ ¸ð¸£´Â ±ÛÀÚ"
+
+#, c-format
+msgid "E121: Undefined variable: %s"
+msgstr "E121: Á¤ÀÇ ¾È µÈ º¯¼ö: %s"
+
+msgid "E111: Missing ']'"
+msgstr "E111: ']'ÀÌ ¾ø½À´Ï´Ù"
+
+msgid "E719: Cannot use [:] with a Dictionary"
+msgstr "E719: Dictionary¿¡ [:]À» »ç¿ëÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "E734: Wrong variable type for %s="
+msgstr "E734: %s=¿¡ ´ëÇÑ À߸øµÈ º¯¼öÇü"
+
+#, c-format
+msgid "E461: Illegal variable name: %s"
+msgstr "E461: ºñÁ¤»óÀûÀÎ º¯¼ö ¸í: %s"
+
+msgid "E806: using Float as a String"
+msgstr "E806: Float¸¦ StringÀ¸·Î »ç¿ë"
+
+msgid "E687: Less targets than List items"
+msgstr "E687: List Ç׸ñº¸´Ù ÀûÀº ´ë»ó"
+
+msgid "E688: More targets than List items"
+msgstr "E688: List Ç׸ñº¸´Ù ¸¹Àº ´ë»ó"
+
+msgid "Double ; in list of variables"
+msgstr "º¯¼ö ¸ñ·Ï¿¡ Áߺ¹µÈ ;"
+
+#, c-format
+msgid "E738: Can't list variables for %s"
+msgstr "E738: %s º¯¼ö ¸ñ·ÏÀ» ³ª¿­ÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E689: Can only index a List or Dictionary"
+msgstr "E689: List³ª Dictionary¸¸ »öÀÎÇÒ ¼ö ÀÖ½À´Ï´Ù"
+
+msgid "E708: [:] must come last"
+msgstr "E708: [:]Àº ¸¶Áö¸·¿¡ À§Ä¡ÇØ¾ß ÇÕ´Ï´Ù"
+
+msgid "E709: [:] requires a List value"
+msgstr "E709: [:]Àº List °ªÀÌ ÇÊ¿äÇÕ´Ï´Ù"
+
+msgid "E710: List value has more items than target"
+msgstr "E710: List °ªÀÌ ´ë»óº¸´Ù ¸¹Àº Ç׸ñÀ» °¡Áö°í ÀÖ½À´Ï´Ù"
+
+msgid "E711: List value has not enough items"
+msgstr "E711: List °ªÀÌ ÃæºÐÇÑ Ç׸ñÀ» °¡Áö°í ÀÖÁö ¾Ê½À´Ï´Ù"
+
+msgid "E690: Missing \"in\" after :for"
+msgstr "E690: :for µÚ¿¡ \"in\"°¡ ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "E108: No such variable: \"%s\""
+msgstr "E108: ÀÌ·± º¯¼ö ¾øÀ½: \"%s\""
+
+#, c-format
+msgid "E940: Cannot lock or unlock variable %s"
+msgstr "E940: º¯¼ö %sÀ»(¸¦) Àá±Ý ȤÀº ÇØÁ¦ÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E743: variable nested too deep for (un)lock"
+msgstr "E743: Àá±Ý(ÇØÁ¦)Çϱ⿡ º¯¼ö°¡ ³Ê¹« ±íÀÌ ÁßøµÇ¾ú½À´Ï´Ù"
+
+msgid "E109: Missing ':' after '?'"
+msgstr "E109: '?' µÚ¿¡ ':'ÀÌ ¾ø½À´Ï´Ù"
+
+msgid "E804: Cannot use '%' with Float"
+msgstr "E804: Float¿¡ '%'´Â »ç¿ëÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E110: Missing ')'"
+msgstr "E110: ')'°¡ ¾ø½À´Ï´Ù"
+
+msgid "E695: Cannot index a Funcref"
+msgstr "E695: Funcref¸¦ »öÀÎÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E909: Cannot index a special variable"
+msgstr "E909: Ư¼öÇÑ º¯¼ö´Â »öÀÎÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "E112: Option name missing: %s"
+msgstr "E112: ¿É¼Ç À̸§ ¾øÀ½: %s"
+
+#, c-format
+msgid "E113: Unknown option: %s"
+msgstr "E113: ¸ð¸£´Â ¿É¼Ç: %s"
+
+#, c-format
+msgid "E114: Missing quote: %s"
+msgstr "E114: µû¿ÈÇ¥ ¾øÀ½: %s"
+
+#, c-format
+msgid "E115: Missing quote: %s"
+msgstr "E115: µû¿ÈÇ¥ ¾øÀ½: %s"
+
+msgid "Not enough memory to set references, garbage collection aborted!"
+msgstr "¸Þ¸ð¸®°¡ ºÎÁ·ÇÏ¿© °¡ºñÁö ÄÝ·º¼ÇÀÌ ÁߴܵǾú½À´Ï´Ù!"
+
+msgid "E724: variable nested too deep for displaying"
+msgstr "E724: º¯¼ö°¡ Ç¥½ÃÇϱ⿡ ³Ê¹« ±íÀÌ ÁßøµÇ¾ú½À´Ï´Ù"
+
+msgid "E805: Using a Float as a Number"
+msgstr "E805: Float¸¦ Number·Î »ç¿ë"
+
+msgid "E703: Using a Funcref as a Number"
+msgstr "E703: Funcref¸¦ Number·Î »ç¿ë"
+
+msgid "E745: Using a List as a Number"
+msgstr "E745: List¸¦ Number·Î »ç¿ë"
+
+msgid "E728: Using a Dictionary as a Number"
+msgstr "E728: Dictionary¸¦ Number·Î »ç¿ë"
+
+msgid "E910: Using a Job as a Number"
+msgstr "E910: JobÀ» Number·Î »ç¿ëÇÏ°í ÀÖ½À´Ï´Ù"
+
+msgid "E913: Using a Channel as a Number"
+msgstr "E913: ChannelÀ» Number·Î »ç¿ëÇÏ°í ÀÖ½À´Ï´Ù"
+
+msgid "E891: Using a Funcref as a Float"
+msgstr "E891: Funcref¸¦ Float·Î »ç¿ëÇÏ°í ÀÖ½À´Ï´Ù"
+
+msgid "E892: Using a String as a Float"
+msgstr "E892: StringÀ» Float·Î »ç¿ëÇÏ°í ÀÖ½À´Ï´Ù"
+
+msgid "E893: Using a List as a Float"
+msgstr "E893: List¸¦ Float·Î »ç¿ëÇÏ°í ÀÖ½À´Ï´Ù"
+
+msgid "E894: Using a Dictionary as a Float"
+msgstr "E894: Dictionary¸¦ Float·Î »ç¿ëÇÏ°í ÀÖ½À´Ï´Ù"
+
+msgid "E907: Using a special value as a Float"
+msgstr "E907: Ư¼öÇÑ °ªÀ» Float·Î »ç¿ëÇÏ°í ÀÖ½À´Ï´Ù"
+
+msgid "E911: Using a Job as a Float"
+msgstr "E911: JobÀ» Float·Î »ç¿ëÇÏ°í ÀÖ½À´Ï´Ù"
+
+msgid "E914: Using a Channel as a Float"
+msgstr "E914: ChannelÀ» Float·Î »ç¿ëÇÏ°í ÀÖ½À´Ï´Ù"
+
+msgid "E729: using Funcref as a String"
+msgstr "E729: Funcref¸¦ StringÀ¸·Î »ç¿ë"
+
+msgid "E730: using List as a String"
+msgstr "E730: List¸¦ StringÀ¸·Î »ç¿ë"
+
+msgid "E731: using Dictionary as a String"
+msgstr "E731: Dictionary¸¦ StringÀ¸·Î »ç¿ë"
+
+msgid "E908: using an invalid value as a String"
+msgstr "E908: À߸øµÈ °ªÀ» StringÀ¸·Î »ç¿ëÇÏ°í ÀÖ½À´Ï´Ù"
+
+#, c-format
+msgid "E795: Cannot delete variable %s"
+msgstr "E795: º¯¼ö %s¸¦ »èÁ¦ÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "E704: Funcref variable name must start with a capital: %s"
+msgstr "E704: Funcref º¯¼ö¸íÀº ´ë¹®ÀÚ·Î ½ÃÀÛÇØ¾ß ÇÔ: %s"
+
+#, c-format
+msgid "E705: Variable name conflicts with existing function: %s"
+msgstr "E705: º¯¼ö¸íÀÌ ÀÌ¹Ì ÀÖ´Â ÇÔ¼ö¸í°ú Ãæµ¹: %s"
+
+#, c-format
+msgid "E741: Value is locked: %s"
+msgstr "E741: °ªÀÌ Àá°ÜÀÖÀ½: %s"
+
+msgid "Unknown"
+msgstr "¸ð¸§"
+
+#, c-format
+msgid "E742: Cannot change value of %s"
+msgstr "E742: %s °ªÀ» ¹Ù²Ü ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E698: variable nested too deep for making a copy"
+msgstr "E698: º¹»çÇϱ⿡ º¯¼ö°¡ ³Ê¹« ±í°Ô ÁßøµÇ¾ú½À´Ï´Ù"
+
+msgid ""
+"\n"
+"# global variables:\n"
+msgstr ""
+"\n"
+"# Àü¿ª º¯¼ö:\n"
+
+msgid ""
+"\n"
+"\tLast set from "
+msgstr ""
+"\n"
+"\tLast set from "
+
+msgid "E691: Can only compare List with List"
+msgstr "E691: List´Â List¿Í¸¸ ºñ±³ÇÒ ¼ö ÀÖ½À´Ï´Ù"
+
+msgid "E692: Invalid operation for List"
+msgstr "E692: List¿¡ ´ëÇÑ À߸øµÈ µ¿ÀÛ"
+
+msgid "E735: Can only compare Dictionary with Dictionary"
+msgstr "E735: Dictionary´Â Dictionary¿Í¸¸ ºñ±³ÇÒ ¼ö ÀÖ½À´Ï´Ù"
+
+msgid "E736: Invalid operation for Dictionary"
+msgstr "E736: Dictionary¿¡ ´ëÇÑ À߸øµÈ µ¿ÀÛ"
+
+msgid "E694: Invalid operation for Funcrefs"
+msgstr "E694: Funcrefs¿¡ ´ëÇÑ À߸øµÈ µ¿ÀÛ"
+
+msgid "map() argument"
+msgstr "map() ÀÎÀÚ"
+
+msgid "filter() argument"
+msgstr "filter() ÀÎÀÚ"
+
+#, c-format
+msgid "E686: Argument of %s must be a List"
+msgstr "E686: %s ÀÎÀÚ´Â ListÀ̾î¾ß ÇÕ´Ï´Ù"
+
+msgid "E928: String required"
+msgstr "E928: StringÀÌ ÇÊ¿äÇÕ´Ï´Ù"
+
+msgid "E808: Number or Float required"
+msgstr "E808: Number ȤÀº Float°¡ ÇÊ¿äÇÕ´Ï´Ù"
+
+msgid "add() argument"
+msgstr "add() ÀÎÀÚ"
+
+msgid "E785: complete() can only be used in Insert mode"
+msgstr "E785: complete()Àº ÀÔ·Â ¸ðµå¿¡¼­¸¸ »ç¿ëµÉ ¼ö ÀÖ½À´Ï´Ù"
+
+msgid "&Ok"
+msgstr "È®ÀÎ(&O)"
+
+#, c-format
+#msgid "+-%s%3ld line: "
+#msgid_plural "+-%s%3ld lines: "
+#msgstr[0] ""
+#msgstr[1] ""
+
+#, c-format
+msgid "E700: Unknown function: %s"
+msgstr "E700: ¸ð¸£´Â ÇÔ¼ö: %s"
+
+msgid "E922: expected a dict"
+msgstr "E922: dict°¡ ¿ä±¸µË´Ï´Ù"
+
+msgid "E923: Second argument of function() must be a list or a dict"
+msgstr "E923: function()ÀÇ µÎ¹ø° ÀÎÀÚ´Â list³ª dictÀ̾î¾ß ÇÕ´Ï´Ù"
+
+msgid ""
+"&OK\n"
+"&Cancel"
+msgstr ""
+"È®ÀÎ(&O)\n"
+"Ãë¼Ò(&C)"
+
+msgid "called inputrestore() more often than inputsave()"
+msgstr "inputrestore()°¡ inputsave()º¸´Ù ¸¹ÀÌ ºÒ·ÁÁ³½À´Ï´Ù"
+
+msgid "insert() argument"
+msgstr "insert() ÀÎÀÚ"
+
+msgid "E786: Range not allowed"
+msgstr "E786: ¹üÀ§°¡ Çã¿ëµÇÁö ¾Ê½À´Ï´Ù"
+
+msgid "E916: not a valid job"
+msgstr "E916: Á¤»óÀûÀÎ jobÀÌ ¾Æ´Õ´Ï´Ù"
+
+msgid "E701: Invalid type for len()"
+msgstr "E701: len()¿¡ À߸øµÈ Çü"
+
+#, c-format
+msgid "E798: ID is reserved for \":match\": %ld"
+msgstr "E798: ID°¡ \":match\"¶§¹®¿¡ ¿¹¾àµÊ: %ld"
+
+msgid "E726: Stride is zero"
+msgstr "E726: Stride°¡ 0"
+
+msgid "E727: Start past end"
+msgstr "E727: ½ÃÀÛÀ§Ä¡°¡ ³¡À» Áö³ªÄ§"
+
+msgid "<empty>"
+msgstr "<ºñ¾îÀÖÀ½>"
+
+msgid "E240: No connection to the X server"
+msgstr "E240: X ¼­¹ö¿¡ ¿¬°áµÇ¾î ÀÖÁö ¾Ê½À´Ï´Ù"
+
+#, c-format
+msgid "E241: Unable to send to %s"
+msgstr "E241: %s(À¸)·Î º¸³¾ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E277: Unable to read a server reply"
+msgstr "E277: ¼­¹öÀÇ ÀÀ´äÀ» ÀÐÀ» ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E941: already started a server"
+msgstr "E941: ¼­¹ö°¡ ÀÌ¹Ì ½ÃÀ۵Ǿú½À´Ï´Ù"
+
+msgid "E942: +clientserver feature not available"
+msgstr "E942: +clientserver ±â´ÉÀÌ Æ÷ÇÔµÇÁö ¾Ê¾Ò½À´Ï´Ù"
+
+msgid "remove() argument"
+msgstr "remove() ÀÎÀÚ"
+
+msgid "E655: Too many symbolic links (cycle?)"
+msgstr "E655: ³Ê¹« ¸¹Àº ½Éº¼¸¯ ¸µÅ© (¹Ýº¹¼øȯ?)"
+
+msgid "reverse() argument"
+msgstr "reverse() ÀÎÀÚ"
+
+msgid "E258: Unable to send to client"
+msgstr "E258: Ŭ¶óÀ̾ðÆ®·Î º¸³¾ ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "E927: Invalid action: '%s'"
+msgstr "E927: ºñÁ¤»óÀûÀÎ µ¿ÀÛ: '%s'"
+
+msgid "sort() argument"
+msgstr "sort() ÀÎÀÚ"
+
+msgid "uniq() argument"
+msgstr "uniq() ÀÎÀÚ"
+
+msgid "E702: Sort compare function failed"
+msgstr "E702: Á¤·Ä ºñ±³ ±â´ÉÀÌ ½ÇÆÐÇß½À´Ï´Ù"
+
+msgid "E882: Uniq compare function failed"
+msgstr "E882: Uniq ºñ±³ ÇÔ¼ö°¡ ½ÇÆÐÇÏ¿´½À´Ï´Ù"
+
+msgid "(Invalid)"
+msgstr "(ºñÁ¤»ó)"
+
+#, c-format
+msgid "E935: invalid submatch number: %d"
+msgstr "E935: ºñÁ¤»óÀûÀÎ submatch number: %d"
+
+msgid "E677: Error writing temp file"
+msgstr "E677: Àӽà ÆÄÀÏ ¾²±â ¿¡·¯"
+
+msgid "E921: Invalid callback argument"
+msgstr "E921: ºñÁ¤»óÀûÀÎ Äݹé ÀÎÀÚ"
+
+msgid "Entering Debug mode. Type \"cont\" to continue."
+msgstr "µð¹ö±× »óÅ·Πµé¾î°¨. °è¼ÓÇÏ·Á¸é \"cont\"¸¦ ÀÔ·ÂÇϽʽÿÀ."
+
+#, c-format
+msgid "Oldval = \"%s\""
+msgstr "ÀÌÀü °ª = \"%s\""
+
+#, c-format
+msgid "Newval = \"%s\""
+msgstr "»õ·Î¿î °ª = \"%s\""
+
+#, c-format
+msgid "line %ld: %s"
+msgstr "%ld ÁÙ: %s"
+
+#, c-format
+msgid "cmd: %s"
+msgstr "¸í·É: %s"
+
+msgid "frame is zero"
+msgstr "ÇÁ·¹ÀÓÀÌ 0"
+
+#, c-format
+msgid "frame at highest level: %d"
+msgstr "ÇÁ·¹ÀÓÀÌ °¡Àå ³ôÀº ´Ü°èÀÓ: %d"
+
+#, c-format
+msgid "Breakpoint in \"%s%s\" line %ld"
+msgstr "ÁßÁöÁ¡: \"%s%s\" %ld ÁÙ"
+
+#, c-format
+msgid "E161: Breakpoint not found: %s"
+msgstr "E161: ÁßÁöÁ¡À» ãÀ» ¼ö ¾ø½À´Ï´Ù: %s"
+
+msgid "No breakpoints defined"
+msgstr "ÁßÁöÁ¡ÀÌ Á¤ÀǵǾî ÀÖÁö ¾Ê½À´Ï´Ù"
+
+#, c-format
+msgid "%3d %s %s line %ld"
+msgstr "%3d %s %s %ld ÁÙ"
+
+#, c-format
+msgid "%3d expr %s"
+msgstr "%3d expr %s"
+
+msgid "E750: First use \":profile start {fname}\""
+msgstr "E750: ¸ÕÀú \":profile start {fname}\"À» »ç¿ëÇϼ¼¿ä"
+
+msgid "Save As"
+msgstr "´Ù¸¥ À̸§À¸·Î ÀúÀå"
+
+#, c-format
+msgid "Save changes to \"%s\"?"
+msgstr "\"%s\"¿¡ ¹Ù²ï ³»¿ëÀ» ÀúÀåÇÒ±î¿ä?"
+
+#, c-format
+msgid "E947: Job still running in buffer \"%s\""
+msgstr "E947: JobÀÌ ¿©ÀüÈ÷ \"%s\" ¹öÆÛ¿¡¼­ ½ÇÇà ÁßÀÔ´Ï´Ù"
+
+#, c-format
+msgid "E162: No write since last change for buffer \"%s\""
+msgstr "E162: ¹öÆÛ \"%s\"¿¡ ³ªÁß¿¡ ¹Ù²ï ³»¿ëÀÌ ½áÁöÁö ¾Ê¾Ò½À´Ï´Ù"
+
+msgid "Warning: Entered other buffer unexpectedly (check autocommands)"
+msgstr "°æ°í: ¶æ ¹Û¿¡ ´Ù¸¥ ¹öÆÛ·Î µé¾î°¬½À´Ï´Ù (autocommand¸¦ È®ÀÎÇϽʽÿÀ)"
+
+msgid "E163: There is only one file to edit"
+msgstr "E163: °íÄ¥ ÆÄÀÏÀÌ Çϳª ¹Û¿¡ ¾ø½À´Ï´Ù"
+
+msgid "E164: Cannot go before first file"
+msgstr "E164: ù ¹ø° ÆÄÀÏ ÀÌÀüÀ¸·Î´Â °¥ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E165: Cannot go beyond last file"
+msgstr "E165: ¸¶Áö¸· ÆÄÀÏ µÚ·Î´Â °¥ ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "E666: compiler not supported: %s"
+msgstr "E666: ÄÄÆÄÀÏ·¯°¡ Áö¿øµÇÁö ¾ÊÀ½: %s"
+
+#, c-format
+msgid "Searching for \"%s\" in \"%s\""
+msgstr "\"%s\"À»(¸¦) \"%s\"¿¡¼­ ã´Â Áß"
+
+#, c-format
+msgid "Searching for \"%s\""
+msgstr "\"%s\"À»(¸¦) ã´Â Áß"
+
+#, c-format
+msgid "not found in '%s': \"%s\""
+msgstr "'%s'¿¡¼­ ãÀ» ¼ö ¾øÀ½: \"%s\""
+
+#, c-format
+msgid "W20: Required python version 2.x not supported, ignoring file: %s"
+msgstr "W20: ¿ä±¸µÇ´Â ÆÄÀ̼± ¹öÁ¯ 2.x´Â Áö¿øµÇÁö ¾ÊÀ½, ÆÄÀÏÀ» ¹«½Ã: %s"
+
+#, c-format
+msgid "W21: Required python version 3.x not supported, ignoring file: %s"
+msgstr "W21: ¿ä±¸µÇ´Â ÆÄÀ̼± ¹öÁ¯ 3.x´Â Áö¿øµÇÁö ¾ÊÀ½, ÆÄÀÏÀ» ¹«½Ã: %s"
+
+msgid "Source Vim script"
+msgstr "ºö ½ºÅ©¸³Æ® ·Îµå"
+
+#, c-format
+msgid "Cannot source a directory: \"%s\""
+msgstr "µð·ºÅ丮´Â sourceÇÒ ¼ö ¾øÀ½: \"%s\""
+
+#, c-format
+msgid "could not source \"%s\""
+msgstr "\"%s\"À»(¸¦) ºÒ·¯ µéÀÏ ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "line %ld: could not source \"%s\""
+msgstr "%ld ÁÙ: \"%s\"À»(¸¦) ºÒ·¯ µéÀÏ ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "sourcing \"%s\""
+msgstr "\"%s\"À»(¸¦) ºÒ·¯µéÀÌ´Â Áß"
+
+#, c-format
+msgid "line %ld: sourcing \"%s\""
+msgstr "%ld ÁÙ: \"%s\" ºÒ·¯µéÀÌ´Â Áß"
+
+#, c-format
+msgid "finished sourcing %s"
+msgstr "%s ºÒ·¯µéÀ̱⠳¡"
+
+#, c-format
+msgid "continuing in %s"
+msgstr "%s¿¡¼­ °è¼Ó"
+
+msgid "modeline"
+msgstr "modeline"
+
+msgid "--cmd argument"
+msgstr "--cmd ÀÎÀÚ"
+
+msgid "-c argument"
+msgstr "-c ÀÎÀÚ"
+
+msgid "environment variable"
+msgstr "ȯ°æ º¯¼ö"
+
+msgid "error handler"
+msgstr "¿¡·¯ Çڵ鷯"
+
+msgid "W15: Warning: Wrong line separator, ^M may be missing"
+msgstr "W15: °æ°í: À߸øµÈ ÁÙ ±¸ºÐÀÚ. ^MÀÌ ¾ø´Â °Í °°½À´Ï´Ù"
+
+msgid "E167: :scriptencoding used outside of a sourced file"
+msgstr "E167: :scriptencodingÀÌ ºÒ·¯µéÀÎ ÆÄÀÏ ¹Û¿¡¼­ »ç¿ëµÇ¾ú½À´Ï´Ù"
+
+msgid "E168: :finish used outside of a sourced file"
+msgstr "E168: :finish°¡ ºÒ·¯µéÀÎ ÆÄÀÏ ¹Û¿¡¼­ »ç¿ëµÇ¾ú½À´Ï´Ù"
+
+#, c-format
+msgid "Current %slanguage: \"%s\""
+msgstr "ÇöÀç %s¾ð¾î: \"%s\""
+
+#, c-format
+msgid "E197: Cannot set language to \"%s\""
+msgstr "E197: ¾ð¾î¸¦ \"%s\"(À¸)·Î ¼³Á¤ÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "<%s>%s%s %d, Hex %02x, Oct %03o, Digr %s"
+msgstr "<%s>%s%s %d, ½ÊÀ°Áø %02x, ÆÈÁø %03o, ÀÌÁß±ÛÀÚ %s"
+
+#, c-format
+msgid "<%s>%s%s %d, Hex %02x, Octal %03o"
+msgstr "<%s>%s%s %d, ½ÊÀ°Áø %02x, ÆÈÁø¼ö %03o"
+
+#, c-format
+msgid "> %d, Hex %04x, Oct %o, Digr %s"
+msgstr "> %d, ½ÊÀ°Áø %04x, ÆÈÁø %o, ÀÌÁß±ÛÀÚ %s"
+
+#, c-format
+msgid "> %d, Hex %08x, Oct %o, Digr %s"
+msgstr "> %d, ½ÊÀ°Áø %08x, ÆÈÁø %o, ÀÌÁß±ÛÀÚ %s"
+
+#, c-format
+msgid "> %d, Hex %04x, Octal %o"
+msgstr "> %d, ½ÊÀ°Áø %04x, ÆÈÁø¼ö %o"
+
+#, c-format
+msgid "> %d, Hex %08x, Octal %o"
+msgstr "> %d, ½ÊÀ°Áø %08x, ÆÈÁø¼ö %o"
+
+msgid "E134: Move lines into themselves"
+msgstr "E134: ÁÙÀ» ±× ÀÚ½ÅÀ¸·Î À̵¿ÇÏ·Á°í Çß½À´Ï´Ù"
+
+msgid "1 line moved"
+msgstr "1 ÁÙ ¿Å°ÜÁ³½À´Ï´Ù"
+
+#, c-format
+msgid "%ld lines moved"
+msgstr "%ld ÁÙ ¿Å°ÜÁ³½À´Ï´Ù"
+
+#, c-format
+msgid "%ld lines filtered"
+msgstr "%ld ÁÙÀ» °É·¶½À´Ï´Ù"
+
+msgid "E135: *Filter* Autocommands must not change current buffer"
+msgstr "E135: *Filter* ÀÚµ¿¸í·ÉÀº ÇöÀç ¹öÆÛ¸¦ ¹Ù²Ù¾î¼­´Â ¾È µË´Ï´Ù"
+
+msgid "[No write since last change]\n"
+msgstr "[¸¶Áö¸·À¸·Î °íÄ£ µÚ ÀúÀå ¾È ÇÔ]\n"
+
+#, c-format
+msgid "%sviminfo: %s in line: "
+msgstr "%sviminfo: ÁÙ¿¡ %s: "
+
+msgid "E136: viminfo: Too many errors, skipping rest of file"
+msgstr "E136: viminfo: ³Ê¹« ¸¹Àº ¿¡·¯, ³ª¸ÓÁö °Ç³Ê¶Ü"
+
+#, c-format
+msgid "Reading viminfo file \"%s\"%s%s%s"
+msgstr "viminfo ÆÄÀÏ \"%s\"%s%s%sÀ»(¸¦) Àд Áß"
+
+msgid " info"
+msgstr " ÀÎÆ÷"
+
+msgid " marks"
+msgstr " ¸¶Å©"
+
+msgid " oldfiles"
+msgstr " oldfiles"
+
+msgid " FAILED"
+msgstr " ½ÇÆÐ"
+
+#, c-format
+msgid "E137: Viminfo file is not writable: %s"
+msgstr "E137: Viminfo ÆÄÀÏÀÇ ¾²±â ±ÇÇÑÀÌ ¾ø½À´Ï´Ù: %s"
+
+#, c-format
+msgid "E929: Too many viminfo temp files, like %s!"
+msgstr "E929: ³Ê¹« ¸¹Àº viminfo Àӽà ÆÄÀϵé, °¡·É %s!"
+
+#, c-format
+msgid "E138: Can't write viminfo file %s!"
+msgstr "E138: Viminfo ÆÄÀÏ %sÀ»(¸¦) ¾µ ¼ö ¾ø½À´Ï´Ù!"
+
+#, c-format
+msgid "Writing viminfo file \"%s\""
+msgstr "Viminfo ÆÄÀÏ \"%s\"À»(¸¦) ¾²´Â Áß"
+
+#, c-format
+msgid "E886: Can't rename viminfo file to %s!"
+msgstr "E886: viminfo ÆÄÀϸíÀ» %s(À¸)·Î º¯°æÇÒ ¼ö ¾ø½À´Ï´Ù!"
+
+#, c-format
+msgid "# This viminfo file was generated by Vim %s.\n"
+msgstr "# ÀÌ viminfo ÆÄÀÏÀº ºöÀÌ ¸¸µç °ÍÀÔ´Ï´Ù Vim %s.\n"
+
+msgid ""
+"# You may edit it if you're careful!\n"
+"\n"
+msgstr ""
+"# Á¶½É¸¸ ÇÑ´Ù¸é °íÄ¥ ¼öµµ ÀÖ½À´Ï´Ù!\n"
+"\n"
+
+msgid "# Value of 'encoding' when this file was written\n"
+msgstr "# ÀÌ ÆÄÀÏÀÌ ÀúÀåµÇ¾úÀ» ¶§ÀÇ 'encoding'ÀÇ °ª\n"
+
+msgid "Illegal starting char"
+msgstr "ÀÌ»óÇÑ ½ÃÀÛ ±ÛÀÚ"
+
+#~ msgid ""
+#~ "\n"
+#~ "# Bar lines, copied verbatim:\n"
+#~ msgstr ""
+
+msgid "Write partial file?"
+msgstr "ÆÄÀÏ ÀϺθ¸ ÀúÀåÇÒ±î¿ä?"
+
+msgid "E140: Use ! to write partial buffer"
+msgstr "E140: ¹öÆÛ ÀϺθ¸ ¾²·Á¸é !À» »ç¿ëÇϽʽÿÀ"
+
+#, c-format
+msgid "Overwrite existing file \"%s\"?"
+msgstr "ÀÌ¹Ì ÀÖ´Â \"%s\" ÆÄÀÏÀ» µ¤¾î¾µ±î¿ä?"
+
+#, c-format
+msgid "Swap file \"%s\" exists, overwrite anyway?"
+msgstr "½º¿Ò ÆÄÀÏ \"%s\"°¡ ÀÖ½À´Ï´Ù, µ¤¾î¾µ±î¿ä?"
+
+#, c-format
+msgid "E768: Swap file exists: %s (:silent! overrides)"
+msgstr "E768: ½º¿Ò ÆÄÀÏ ÀÖÀ½: %s (µ¤¾î¾²·Á¸é :silent! »ç¿ë)"
+
+#, c-format
+msgid "E141: No file name for buffer %ld"
+msgstr "E141: ¹öÆÛ %ldÀÇ ÆÄÀÏ À̸§ÀÌ ¾ø½À´Ï´Ù"
+
+msgid "E142: File not written: Writing is disabled by 'write' option"
+msgstr "E142: ÆÄÀÏÀÌ ½áÁöÁö ¾ÊÀ½: 'write' ¿É¼Ç¿¡ ÀÇÇØ ¾µ ¼ö°¡ ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid ""
+"'readonly' option is set for \"%s\".\n"
+"Do you wish to write anyway?"
+msgstr ""
+"'readonly' ¿É¼ÇÀÌ \"%s\"¿¡ ´ëÇØ ¼³Á¤µÇ¾î ÀÖ½À´Ï´Ù.\n"
+"±×·¡µµ ¾²±â¸¦ ¿øÇϽʴϱî?"
+
+#, c-format
+msgid ""
+"File permissions of \"%s\" are read-only.\n"
+"It may still be possible to write it.\n"
+"Do you wish to try?"
+msgstr ""
+"ÆÄÀÏ \"%s\"°¡ ÀбâÀü¿ëÀÔ´Ï´Ù.\n"
+"±×·¡µµ ¾²±â°¡ °¡´ÉÇÒ Áöµµ ¸ð¸¨´Ï´Ù.\n"
+"ÇÑ ¹ø ½á º¼±î¿ä?"
+
+#, c-format
+msgid "E505: \"%s\" is read-only (add ! to override)"
+msgstr "E505: \"%s\"´Â Àбâ Àü¿ëÀÔ´Ï´Ù (µ¤¾î¾²·Á¸é ! ´õÇϱâ)"
+
+msgid "Edit File"
+msgstr "ÆÄÀÏ °íÄ¡±â"
+
+#, c-format
+msgid "E143: Autocommands unexpectedly deleted new buffer %s"
+msgstr "E143: Autocommand°¡ ¶æ ¹Û¿¡ »õ ¹öÆÛ %sÀ»(¸¦) Áö¿ü½À´Ï´Ù"
+
+msgid "E144: non-numeric argument to :z"
+msgstr "E144: ¼ýÀÚ°¡ ¾Æ´Ñ ÀÎÀÚ°¡ :z¿¡ ÁÖ¾îÁ³½À´Ï´Ù"
+
+msgid "E145: Shell commands not allowed in rvim"
+msgstr "E145: rvim¿¡¼­´Â ½© ¸í·ÉÀ» »ç¿ëÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E146: Regular expressions can't be delimited by letters"
+msgstr "E146: Á¤±ÔÇ¥Çö½ÄÀº ±ÛÀÚ·Î ±¸ºÐµÉ ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "replace with %s (y/n/a/q/l/^E/^Y)?"
+msgstr "%s(À¸)·Î ¹Ù²Þ (y/n/a/q/l/^E/^Y)?"
+
+msgid "(Interrupted) "
+msgstr "(ÁߴܵǾú½À´Ï´Ù) "
+
+msgid "1 match"
+msgstr "1°³ ã¾ÆÁü"
+
+msgid "1 substitution"
+msgstr "1°³ ¹Ù²åÀ½"
+
+#, c-format
+msgid "%ld matches"
+msgstr "%ld°³ ã¾ÆÁü"
+
+#, c-format
+msgid "%ld substitutions"
+msgstr "%ld°³ ¹Ù²åÀ½"
+
+msgid " on 1 line"
+msgstr " ÇÑ ÁÙ¿¡¼­"
+
+#, c-format
+msgid " on %ld lines"
+msgstr " %ld ÁÙ¿¡¼­"
+
+msgid "E147: Cannot do :global recursive with a range"
+msgstr "E147: :globalÀº ¹üÀ§·Î Àç±Í È£Ãâ µÉ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E148: Regular expression missing from global"
+msgstr "E148: global¿¡¼­ Á¤±ÔÇ¥Çö½ÄÀÌ ºüÁ³½À´Ï´Ù"
+
+#, c-format
+msgid "Pattern found in every line: %s"
+msgstr "¿©·¯ ÁÙ¿¡¼­ ÆÐÅÏÀ» ã¾Ò½À´Ï´Ù: %s"
+
+#, c-format
+msgid "Pattern not found: %s"
+msgstr "ÆÐÅÏÀ» ãÀ» ¼ö ¾øÀ½: %s"
+
+msgid ""
+"\n"
+"# Last Substitute String:\n"
+"$"
+msgstr ""
+"\n"
+"# ¸¶Áö¸·À¸·Î ¹Ù²Û ¹®ÀÚ¿­:\n"
+"$"
+
+msgid "E478: Don't panic!"
+msgstr "E478: ´çȲÇÏÁö ¸¶½Ê½Ã¿À!"
+
+#, c-format
+msgid "E661: Sorry, no '%s' help for %s"
+msgstr "E661: ¹Ì¾ÈÇÕ´Ï´Ù, µµ¿ò¸» '%s'ÀÌ(°¡) %s¿¡ ´ëÇØ ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "E149: Sorry, no help for %s"
+msgstr "E149: ¹Ì¾ÈÇÕ´Ï´Ù, %s¿¡ ´ëÇÑ µµ¿ò¸»ÀÌ ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "Sorry, help file \"%s\" not found"
+msgstr "¹Ì¾ÈÇÕ´Ï´Ù, µµ¿ò¸» ÆÄÀÏ \"%s\"À»(¸¦) ãÀ» ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "E151: No match: %s"
+msgstr "E151: ¸ÂÁö ¾ÊÀ½: %s"
+
+#, c-format
+msgid "E152: Cannot open %s for writing"
+msgstr "E152: ¾²±â À§ÇÑ %sÀ»(¸¦) ¿­ ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "E153: Unable to open %s for reading"
+msgstr "E153: Àбâ À§ÇÑ %sÀ»(¸¦) ¿­ ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "E670: Mix of help file encodings within a language: %s"
+msgstr "E670: ÇÑ ¾ð¾î³»¿¡¼­ ¿©·¯ ÀÎÄÚµù »ç¿ë: %s"
+
+#, c-format
+msgid "E154: Duplicate tag \"%s\" in file %s/%s"
+msgstr "E154: \"%s\" űװ¡ %s/%s ÆÄÀÏ¿¡¼­ Áߺ¹µÇ¾ú½À´Ï´Ù"
+
+#, c-format
+msgid "E150: Not a directory: %s"
+msgstr "E150: µð·ºÅ丮°¡ ¾Æ´Ô: %s"
+
+#, c-format
+msgid "E160: Unknown sign command: %s"
+msgstr "E160: ¸ð¸£´Â sign ¸í·É: %s"
+
+msgid "E156: Missing sign name"
+msgstr "E156: sign À̸§ÀÌ ¾ø½À´Ï´Ù"
+
+msgid "E612: Too many signs defined"
+msgstr "E612: ³Ê¹« ¸¹Àº signÀÌ Á¤ÀǵǾî ÀÖ½À´Ï´Ù"
+
+#, c-format
+msgid "E239: Invalid sign text: %s"
+msgstr "E239: À߸øµÈ sign ÅؽºÆ®: %s"
+
+#, c-format
+msgid "E155: Unknown sign: %s"
+msgstr "E155: ¸ð¸£´Â sign: %s"
+
+msgid "E159: Missing sign number"
+msgstr "E159: sign ¹øÈ£°¡ ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "E158: Invalid buffer name: %s"
+msgstr "E158: À߸øµÈ ¹öÆÛ À̸§: %s"
+
+msgid "E934: Cannot jump to a buffer that does not have a name"
+msgstr "E934: À̸§¾ø´Â ¹öÆ۷δ Á¡ÇÁÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "E157: Invalid sign ID: %ld"
+msgstr "E157: À߸øµÈ sign ID: %ld"
+
+#, c-format
+msgid "E885: Not possible to change sign %s"
+msgstr "E885: sign %sÀ»(¸¦) ¹Ù²Ü ¼ö ¾ø½À´Ï´Ù"
+
+msgid " (NOT FOUND)"
+msgstr " (¸ø ã¾ÒÀ½)"
+
+msgid " (not supported)"
+msgstr " (Áö¿øµÇÁö ¾ÊÀ½)"
+
+msgid "[Deleted]"
+msgstr "[Áö¿öÁ³½À´Ï´Ù]"
+
+msgid "No old files"
+msgstr "old ÆÄÀÏÀÌ ¾ø½À´Ï´Ù"
+
+msgid "Entering Ex mode. Type \"visual\" to go to Normal mode."
+msgstr "Ex »óÅ·ΠÀüȯ. Normal »óÅ·Π°¡·Á¸é \"visual\"À» ÀÔ·ÂÇϽʽÿÀ."
+
+msgid "E501: At end-of-file"
+msgstr "E501: ÆÄÀÏÀÇ ¸¶Áö¸·ÀÔ´Ï´Ù"
+
+msgid "E169: Command too recursive"
+msgstr "E169: ¸í·ÉÀÌ ³Ê¹« ¸¹ÀÌ ´Ù½Ã ¹Ýº¹µÇ¾ú½À´Ï´Ù"
+
+#, c-format
+msgid "E605: Exception not caught: %s"
+msgstr "E605: ¿¹¿Ü°¡ ¹ß»ýÇÏÁö ¾Ê¾Ò½À´Ï´Ù: %s"
+
+msgid "End of sourced file"
+msgstr "ºÒ·¯µéÀÎ ÆÄÀÏÀÇ ¸¶Áö¸·"
+
+msgid "End of function"
+msgstr "ÇÔ¼öÀÇ ¸¶Áö¸·"
+
+msgid "E464: Ambiguous use of user-defined command"
+msgstr "E464: »ç¿ëÀÚ Á¤ÀÇ ¸í·ÉÀ» ¸ðÈ£ÇÏ°Ô »ç¿ëÇÏ°í ÀÖ½À´Ï´Ù"
+
+msgid "E492: Not an editor command"
+msgstr "E492: ÆíÁý±â ¸í·ÉÀÌ ¾Æ´Õ´Ï´Ù"
+
+msgid "E493: Backwards range given"
+msgstr "E493: ¹Ý´ë ¿µ¿ªÀÌ ÁÖ¾îÁ³½À´Ï´Ù"
+
+msgid "Backwards range given, OK to swap"
+msgstr "¹Ý´ë ¿µ¿ªÀÌ ÁÖ¾îÁ³½À´Ï´Ù, µÚÁýÀ»±î¿ä"
+
+msgid "E494: Use w or w>>"
+msgstr "E494: w³ª w>>¸¦ »ç¿ëÇϽʽÿÀ"
+
+msgid "E943: Command table needs to be updated, run 'make cmdidxs'"
+msgstr "E943: ¸í·É Å×ÀÌºí °»½ÅÀÌ ÇÊ¿ä, 'make cmdidxs'¸¦ ½ÇÇàÇϼ¼¿ä"
+
+msgid "E319: Sorry, the command is not available in this version"
+msgstr "E319: ¹Ì¾ÈÇÕ´Ï´Ù, ±× ¸í·ÉÀº ÇöÀç ÆÇ¿¡¼­ »ç¿ëÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "1 more file to edit. Quit anyway?"
+msgstr "°íÄ¥ ÆÄÀÏÀÌ ÇÑ °³ ´õ ÀÖ½À´Ï´Ù. ±×·¡µµ ³¡³¾±î¿ä?"
+
+#, c-format
+msgid "%d more files to edit. Quit anyway?"
+msgstr "°íÄ¥ ÆÄÀÏÀÌ %d °³ ´õ ÀÖ½À´Ï´Ù. ±×·¡µµ ³¡³¾±î¿ä?"
+
+msgid "E173: 1 more file to edit"
+msgstr "E173: °íÄ¥ ÆÄÀÏÀÌ ÇÑ °³ ´õ ÀÖ½À´Ï´Ù"
+
+#, c-format
+msgid "E173: %ld more files to edit"
+msgstr "E173: °íÄ¥ ÆÄÀÏÀÌ %ld °³ ´õ ÀÖ½À´Ï´Ù"
+
+msgid "E174: Command already exists: add ! to replace it"
+msgstr "E174: ¸í·ÉÀÌ ÀÌ¹Ì Á¸ÀçÇÕ´Ï´Ù: ¹Ù²Ù·Á¸é !À» ´õÇϼ¼¿ä"
+
+msgid ""
+"\n"
+" Name Args Address Complete Definition"
+msgstr ""
+"\n"
+" À̸§ ÀÎÀÚ ÁÖ¼Ò ¿Ï¼º Á¤ÀÇ"
+
+msgid "No user-defined commands found"
+msgstr "»ç¿ëÀÚ Á¤ÀÇ ¸í·ÉÀ» ãÀ» ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E175: No attribute specified"
+msgstr "E175: ¸í½ÃµÈ ¼Ó¼ºÀÌ ¾ø½À´Ï´Ù"
+
+msgid "E176: Invalid number of arguments"
+msgstr "E176: À߸øµÈ ÀÎÀÚ °¹¼ö"
+
+msgid "E177: Count cannot be specified twice"
+msgstr "E177: Ä«¿îÆ®´Â µÎ ¹ø ÀÌ»ó ¸í½ÃµÉ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E178: Invalid default value for count"
+msgstr "E178: À߸øµÈ ±âº» Ä«¿îÆ® °ª"
+
+msgid "E179: argument required for -complete"
+msgstr "E179: -complete¿¡ ÀÎÀÚ°¡ ÇÊ¿äÇÕ´Ï´Ù"
+
+msgid "E179: argument required for -addr"
+msgstr "E179: -addr¿¡ ÀÎÀÚ°¡ ÇÊ¿äÇÕ´Ï´Ù"
+
+#, c-format
+msgid "E181: Invalid attribute: %s"
+msgstr "E181: À߸øµÈ ¼Ó¼º: %s"
+
+msgid "E182: Invalid command name"
+msgstr "E182: À߸øµÈ ¸í·É À̸§"
+
+msgid "E183: User defined commands must start with an uppercase letter"
+msgstr "E183: »ç¿ëÀÚ Á¤ÀÇ ¸í·ÉÀº ´ë¹®ÀÚ·Î ½ÃÀÛÇØ¾ß ÇÕ´Ï´Ù"
+
+msgid "E841: Reserved name, cannot be used for user defined command"
+msgstr "E841: ¿¹¾àµÈ À̸§, »ç¿ëÀÚ Á¤ÀÇ ¸í·ÉÀ¸·Î »ç¿ëµÉ ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "E184: No such user-defined command: %s"
+msgstr "E184: ±×·± »ç¿ëÀÚ Á¤ÀÇ ¸í·É ¾øÀ½: %s"
+
+#, c-format
+msgid "E180: Invalid address type value: %s"
+msgstr "E180: À߸øµÈ ÁÖ¼Ò Çü½Ä °ª: %s"
+
+#, c-format
+msgid "E180: Invalid complete value: %s"
+msgstr "E180: À߸øµÈ ³¡³»±â °ª: %s"
+
+msgid "E468: Completion argument only allowed for custom completion"
+msgstr "E468: ¿Ï¼º ÀÎÀÚ´Â »ç¿ëÀÚ ¿Ï¼º¿¡¼­¸¸ Çã¿ëµË´Ï´Ù"
+
+msgid "E467: Custom completion requires a function argument"
+msgstr "E467: »ç¿ëÀÚ ¿Ï¼ºÀº ÇÔ¼ö ÀÎÀÚ°¡ ÇÊ¿äÇÕ´Ï´Ù"
+
+msgid "unknown"
+msgstr "¸ð¸§"
+
+#, c-format
+msgid "E185: Cannot find color scheme '%s'"
+msgstr "E185: »ö ½ºÅ´ %sÀ»(¸¦) ãÀ» ¼ö ¾ø½À´Ï´Ù"
+
+msgid "Greetings, Vim user!"
+msgstr "ºö »ç¿ëÀÚ´Ô, ȯ¿µÇÕ´Ï´Ù!"
+
+msgid "E784: Cannot close last tab page"
+msgstr "E784: ¸¶Áö¸· ÅÇÀ» ´ÝÀ» ¼ö ¾ø½À´Ï´Ù"
+
+msgid "Already only one tab page"
+msgstr "ÀÌ¹Ì ÇϳªÀÇ ÅǸ¸ ÀÖ½À´Ï´Ù"
+
+msgid "Edit File in new tab page"
+msgstr "»õ ÅÇ¿¡¼­ ÆÄÀÏ °íÄ¡±â"
+
+msgid "Edit File in new window"
+msgstr "»õ â¿¡¼­ ÆÄÀÏ °íÄ¡±â"
+
+#, c-format
+msgid "Tab page %d"
+msgstr "ÅÇ ÆäÀÌÁö %d"
+
+msgid "No swap file"
+msgstr "½º¿Ò ÆÄÀÏÀÌ ¾ø½À´Ï´Ù"
+
+msgid "Append File"
+msgstr "ÆÄÀÏ Ãß°¡"
+
+msgid "E747: Cannot change directory, buffer is modified (add ! to override)"
+msgstr "E747: µð·ºÅ丮¸¦ ¹Ù²Ü ¼ö ¾ø´Â µ¥, ¹öÆÛ´Â ¼öÁ¤µÊ (µ¤¾î¾²·Á¸é ! ´õÇϱâ)"
+
+msgid "E186: No previous directory"
+msgstr "E186: ÀÌÀü µð·ºÅ丮°¡ ¾ø½À´Ï´Ù"
+
+msgid "E187: Unknown"
+msgstr "E187: ¸ð¸§"
+
+msgid "E465: :winsize requires two number arguments"
+msgstr "E465: :winsize´Â µÎ°³ÀÇ ÀÎÀÚ°¡ ÇÊ¿äÇÕ´Ï´Ù"
+
+#, c-format
+msgid "Window position: X %d, Y %d"
+msgstr "â À§Ä¡: X %d, Y %d"
+
+msgid "E188: Obtaining window position not implemented for this platform"
+msgstr "E188: ÀÌ Ç÷§Æû¿¡ ´ëÇÑ Ã¢ À§Ä¡ ¾ò´Â ±â´ÉÀ» ±¸ÇöµÇÁö ¾Ê¾Ò½À´Ï´Ù"
+
+msgid "E466: :winpos requires two number arguments"
+msgstr "E466: :winpos¿¡´Â µÎ°³ÀÇ ÀÎÀÚ°¡ ÇÊ¿äÇÕ´Ï´Ù"
+
+msgid "E930: Cannot use :redir inside execute()"
+msgstr "E930: execute() ³»¿¡¼­ :redirÀ» »ç¿ëÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "Save Redirection"
+msgstr "¸®µð·º¼Ç ÀúÀå"
+
+msgid "Save View"
+msgstr "º¸±â ÀúÀå"
+
+msgid "Save Session"
+msgstr "¼¼¼Ç ÀúÀå"
+
+msgid "Save Setup"
+msgstr "¼³Á¤ ÀúÀå"
+
+#, c-format
+msgid "E739: Cannot create directory: %s"
+msgstr "E739: µð·ºÅ丮 »ý¼º ½ÇÆÐ: %s"
+
+#, c-format
+msgid "E189: \"%s\" exists (add ! to override)"
+msgstr "E189: \"%s\"ÀÌ(°¡) Á¸ÀçÇÕ´Ï´Ù (µ¤¾î¾²·Á¸é ! ´õÇϱâ)"
+
+#, c-format
+msgid "E190: Cannot open \"%s\" for writing"
+msgstr "E190: ¾²±â À§ÇÑ \"%s\"À»(¸¦) ¿­ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E191: Argument must be a letter or forward/backward quote"
+msgstr "E191: ÀÎÀÚ´Â ±ÛÀÚ³ª ¾Õ/µÚ ÀÎ¿ë ºÎÈ£¿©¾ß ÇÕ´Ï´Ù"
+
+msgid "E192: Recursive use of :normal too deep"
+msgstr "E192: :normalÀÇ Àç±Í È£ÃâÀÌ ³Ê¹« ¸¹ÀÌ »ý°å½À´Ï´Ù"
+
+msgid "E809: #< is not available without the +eval feature"
+msgstr "E809: #<´Â +eval ±â´ÉÀÌ Æ÷ÇԵǾî¾ß »ç¿ëÇÒ ¼ö ÀÖ½À´Ï´Ù"
+
+msgid "E194: No alternate file name to substitute for '#'"
+msgstr "E194: '#'¿¡ ´ëÇØ Ä¡È¯ÇÒ ±³Ã¼ ÆÄÀÏ À̸§ÀÌ ¾ø½À´Ï´Ù"
+
+msgid "E495: no autocommand file name to substitute for \"<afile>\""
+msgstr "E495: \"<afile>\"¿¡ ´ëÇØ Ä¡È¯ÇÒ ÀÚµ¿¸í·É ÆÄÀÏ À̸§ÀÌ ¾ø½À´Ï´Ù"
+
+msgid "E496: no autocommand buffer number to substitute for \"<abuf>\""
+msgstr "E496: \"<abuf>\"¿¡ ´ëÇØ Ä¡È¯ÇÒ ÀÚµ¿¸í·É ¹öÆÛ ¹øÈ£°¡ ¾ø½À´Ï´Ù"
+
+msgid "E497: no autocommand match name to substitute for \"<amatch>\""
+msgstr "E497: \"<amatch>\"¿¡ ´ëÇØ Ä¡È¯ÇÒ ÀÚµ¿¸í·É ¸ÅÄ¡ À̸§ÀÌ ¾ø½À´Ï´Ù"
+
+msgid "E498: no :source file name to substitute for \"<sfile>\""
+msgstr "E498: \"<sfile>\"¿¡ ´ëÇØ Ä¡È¯ÇÒ :source ÆÄÀÏ À̸§ÀÌ ¾ø½À´Ï´Ù"
+
+msgid "E842: no line number to use for \"<slnum>\""
+msgstr "E842: \"<slnum>\"¿¡ »ç¿ëµÉ ÁÙ ¹øÈ£°¡ ¾ø½À´Ï´Ù"
+
+#, no-c-format
+msgid "E499: Empty file name for '%' or '#', only works with \":p:h\""
+msgstr "E499: '%'³ª '#'¿¡ ´ëÇÑ ºó ÆÄÀÏ À̸§, ¿À·ÎÁö \":p:h\"¿Í¸¸ µ¿ÀÛÇÕ´Ï´Ù"
+
+msgid "E500: Evaluates to an empty string"
+msgstr "E500: ºó ¹®ÀÚ¿­¿¡¼­ °ªÀ» ±¸ÇÏ·Á°í ÇÕ´Ï´Ù"
+
+msgid "E195: Cannot open viminfo file for reading"
+msgstr "E195: ÀÐÀ» viminfo ÆÄÀÏÀ» ¿­ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "Untitled"
+msgstr "Á¦¸ñ ¾øÀ½"
+
+msgid "E196: No digraphs in this version"
+msgstr "E196: ÀÌ ÆÇ¿¡´Â digraph°¡ ¾ø½À´Ï´Ù"
+
+msgid "E608: Cannot :throw exceptions with 'Vim' prefix"
+msgstr "E608: 'Vim' Á¢µÎ»ç·Î ¿¹¿Ü¸¦ :throwÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "Exception thrown: %s"
+msgstr "¿¹¿Ü thrown: %s"
+
+#, c-format
+msgid "Exception finished: %s"
+msgstr "¿¹¿Ü Á¾·áµÊ: %s"
+
+#, c-format
+msgid "Exception discarded: %s"
+msgstr "¿¹¿Ü ¹ö·ÁÁü: %s"
+
+#, c-format
+msgid "%s, line %ld"
+msgstr "%s, %ld ÁÙ"
+
+#, c-format
+msgid "Exception caught: %s"
+msgstr "¿¹¿Ü ¹ß»ý: %s"
+
+#, c-format
+msgid "%s made pending"
+msgstr "%sÀÌ(°¡) pending µÇ¾ú½À´Ï´Ù"
+
+#, c-format
+msgid "%s resumed"
+msgstr "%sÀÌ(°¡) Àç°³ µÇ¾ú½À´Ï´Ù"
+
+#, c-format
+msgid "%s discarded"
+msgstr "%sÀÌ(°¡) ¹ö·ÁÁ³½À´Ï´Ù"
+
+msgid "Exception"
+msgstr "¿¹¿Ü"
+
+msgid "Error and interrupt"
+msgstr "¿¡·¯¿Í ÀÎÅÍ·´Æ®"
+
+msgid "Error"
+msgstr "¿¡·¯"
+
+msgid "Interrupt"
+msgstr "ÀÎÅÍ·´Æ®"
+
+msgid "E579: :if nesting too deep"
+msgstr "E579: :if°¡ ³Ê¹« ±í°Ô ÁßøµÇ¾ú½À´Ï´Ù"
+
+msgid "E580: :endif without :if"
+msgstr "E580: :if¾øÀÌ :endif°¡ ÀÖ½À´Ï´Ù"
+
+msgid "E581: :else without :if"
+msgstr "E581: :if¾øÀÌ :else°¡ ÀÖ½À´Ï´Ù"
+
+msgid "E582: :elseif without :if"
+msgstr "E582: :if¾øÀÌ :elseif°¡ ÀÖ½À´Ï´Ù"
+
+msgid "E583: multiple :else"
+msgstr "E583: ¿©·¯°³ÀÇ :else°¡ ÀÖ½À´Ï´Ù"
+
+msgid "E584: :elseif after :else"
+msgstr "E584: :else µÚ¿¡ :elseif°¡ ÀÖ½À´Ï´Ù"
+
+msgid "E585: :while/:for nesting too deep"
+msgstr "E585: :while/:for°¡ ³Ê¹« ±í°Ô ÁßøµÇ¾ú½À´Ï´Ù"
+
+msgid "E586: :continue without :while or :for"
+msgstr "E586: :while ȤÀº :for¾øÀÌ :continue°¡ ÀÖ½À´Ï´Ù"
+
+msgid "E587: :break without :while or :for"
+msgstr "E587: :while ȤÀº :for¾øÀÌ :break°¡ ÀÖ½À´Ï´Ù"
+
+msgid "E732: Using :endfor with :while"
+msgstr "E732: :while¿¡ :endfor°¡ »ç¿ëµÇ¾ú½À´Ï´Ù"
+
+msgid "E733: Using :endwhile with :for"
+msgstr "E733: :for¿¡ :endwhileÀÌ »ç¿ëµÇ¾ú½À´Ï´Ù"
+
+msgid "E601: :try nesting too deep"
+msgstr "E601: :try°¡ ³Ê¹« ±í°Ô ÁßøµÇ¾ú½À´Ï´Ù"
+
+msgid "E603: :catch without :try"
+msgstr "E603: :try¾øÀÌ :catch°¡ ÀÖ½À´Ï´Ù"
+
+msgid "E604: :catch after :finally"
+msgstr "E604: :finally µÚ¿¡ :catch°¡ ÀÖ½À´Ï´Ù"
+
+msgid "E606: :finally without :try"
+msgstr "E606: :try¾øÀÌ :finally°¡ ÀÖ½À´Ï´Ù"
+
+msgid "E607: multiple :finally"
+msgstr "E607: ¿©·¯°³ÀÇ :finally°¡ ÀÖ½À´Ï´Ù"
+
+msgid "E602: :endtry without :try"
+msgstr "E602: :try¾øÀÌ :endtry°¡ ÀÖ½À´Ï´Ù"
+
+msgid "E193: :endfunction not inside a function"
+msgstr "E193: :endfunctionÀÌ function ³»¿¡ ¾ø½À´Ï´Ù"
+
+msgid "E788: Not allowed to edit another buffer now"
+msgstr "E788: Áö±ÝÀº ´Ù¸¥ ¹öÆÛ¸¦ ÆíÁýÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E811: Not allowed to change buffer information now"
+msgstr "E811: Áö±ÝÀº ¹öÆÛ Á¤º¸¸¦ ¹Ù²Ü ¼ö ¾ø½À´Ï´Ù"
+
+msgid "tagname"
+msgstr "ű×À̸§"
+
+msgid " kind file\n"
+msgstr " kind file\n"
+
+msgid "'history' option is zero"
+msgstr "'history' ¿É¼ÇÀÌ 0ÀÔ´Ï´Ù"
+
+#, c-format
+msgid ""
+"\n"
+"# %s History (newest to oldest):\n"
+msgstr ""
+"\n"
+"# %s È÷½ºÅ丮 (»õ°ÍºÎÅÍ ¿À·¡µÈ °Í ¼ø):\n"
+
+msgid "Command Line"
+msgstr "¸í·É Çà"
+
+msgid "Search String"
+msgstr "ãÀ» ¹®ÀÚ¿­"
+
+msgid "Expression"
+msgstr "Ç¥Çö"
+
+msgid "Input Line"
+msgstr "ÀÔ·Â Çà"
+
+msgid "Debug Line"
+msgstr "µð¹ö±× Çà"
+
+msgid "E198: cmd_pchar beyond the command length"
+msgstr "E198: cmd_pchar°¡ ¸í·É ±æÀ̸¦ ¹þ¾î³µ½À´Ï´Ù"
+
+msgid "E199: Active window or buffer deleted"
+msgstr "E199: È°¼ºµÈ âÀ̳ª ¹öÆÛ°¡ Áö¿öÁ³½À´Ï´Ù"
+
+msgid "E812: Autocommands changed buffer or buffer name"
+msgstr "E812: Autocommand°¡ ¹öÆÛ³ª ¹öÆÛÀ̸§À» ¹Ù²Ù¾ú½À´Ï´Ù"
+
+msgid "Illegal file name"
+msgstr "À߸øµÈ ÆÄÀÏ À̸§"
+
+msgid "is a directory"
+msgstr "Àº(´Â) µð·ºÅ丮ÀÔ´Ï´Ù"
+
+msgid "is not a file"
+msgstr "Àº(´Â) ÆÄÀÏÀÌ ¾Æ´Õ´Ï´Ù"
+
+msgid "is a device (disabled with 'opendevice' option)"
+msgstr "Àº(´Â) ÀåÄ¡°¡ ¾Æ´Õ´Ï´Ù ('opendevice' ¿É¼ÇÀ¸·Î ¸·Èû)"
+
+msgid "[New File]"
+msgstr "[»õ ÆÄÀÏ]"
+
+msgid "[New DIRECTORY]"
+msgstr "[»õ µð·ºÅ丮]"
+
+msgid "[File too big]"
+msgstr "[ÆÄÀÏÀÌ ³Ê¹« Å­]"
+
+msgid "[Permission Denied]"
+msgstr "[Çã¿ë ¾È µË´Ï´Ù]"
+
+msgid "E200: *ReadPre autocommands made the file unreadable"
+msgstr "E200: *ReadPre ÀÚµ¿¸í·ÉÀÌ ÆÄÀÏÀ» ÀÐÁö ¸øÇÏ°Ô ¸¸µé¾ú½À´Ï´Ù"
+
+msgid "E201: *ReadPre autocommands must not change current buffer"
+msgstr "E201: *ReadPre ÀÚµ¿¸í·ÉÀº ÇöÀç ¹öÆÛ¸¦ ¹Ù²Ù¸é ¾È µË´Ï´Ù"
+
+msgid "Vim: Reading from stdin...\n"
+msgstr "ºö: Ç¥ÁØÀԷ¿¡¼­ Àд Áß...\n"
+
+msgid "Reading from stdin..."
+msgstr "Ç¥ÁØÀԷ¿¡¼­ Àд Áß..."
+
+msgid "E202: Conversion made file unreadable!"
+msgstr "E202: º¯È¯µÈ ÆÄÀÏÀ» ÀÐÀ» ¼ö°¡ ¾ø½À´Ï´Ù!"
+
+msgid "[fifo/socket]"
+msgstr "[ÇÇÆ÷/¼ÒÄÏ]"
+
+msgid "[fifo]"
+msgstr "[ÇÇÆ÷]"
+
+msgid "[socket]"
+msgstr "[¼ÒÄÏ]"
+
+#~ msgid "[character special]"
+#~ msgstr ""
+
+msgid "[CR missing]"
+msgstr "[CR ¾øÀ½]"
+
+msgid "[long lines split]"
+msgstr "[±ä ÁÙ À߸²]"
+
+msgid "[NOT converted]"
+msgstr "[º¯È¯ ¾È µË´Ï´Ù]"
+
+msgid "[converted]"
+msgstr "[º¯È¯ µÇ¾ú½À´Ï´Ù]"
+
+#, c-format
+msgid "[CONVERSION ERROR in line %ld]"
+msgstr "[%ld ÁÙ¿¡¼­ º¯È¯ ¿¡·¯]"
+
+#, c-format
+msgid "[ILLEGAL BYTE in line %ld]"
+msgstr "[%ld ÁÙ¿¡ À߸øµÈ ¹ÙÀÌÆ®]"
+
+msgid "[READ ERRORS]"
+msgstr "[Àб⠿¡·¯]"
+
+msgid "Can't find temp file for conversion"
+msgstr "º¯È¯Çϱâ À§ÇÑ Àӽà ÆÄÀÏÀ» ãÀ» ¼ö ¾ø½À´Ï´Ù"
+
+msgid "Conversion with 'charconvert' failed"
+msgstr "'charconvert'¸¦ »ç¿ëÇÑ º¯È¯ÀÌ ½ÇÆÐÇß½À´Ï´Ù"
+
+msgid "can't read output of 'charconvert'"
+msgstr "'charconvert'ÀÇ Ãâ·Â°á°ú¸¦ ÀÐÀ» ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E676: No matching autocommands for acwrite buffer"
+msgstr "E676: acwrite ¹öÆÛ¿¡ ´ëÇÑ autocommand¸¦ ãÀ» ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E203: Autocommands deleted or unloaded buffer to be written"
+msgstr "E203: ¾µ ¹öÆÛ¸¦ ÀÚµ¿¸í·ÉÀÌ Áö¿ì°Å³ª ´Ý¾Ò½À´Ï´Ù"
+
+msgid "E204: Autocommand changed number of lines in unexpected way"
+msgstr "E204: Autocommand°¡ À߸øµÈ ¹æ¹ýÀ¸·Î ÁÙÀ» ¹Ù²Ù¾ú½À´Ï´Ù"
+
+msgid "NetBeans disallows writes of unmodified buffers"
+msgstr "NetBeans¿¡¼­´Â ¹Ù²îÁö ¾ÊÀº ¹öÆÛ¸¦ ¾µ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "Partial writes disallowed for NetBeans buffers"
+msgstr "NetBeans ¹öÆÛ¿¡ ´ëÇؼ­´Â ºÎºÐ ÀúÀåÀ» ÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "is not a file or writable device"
+msgstr "ÆÄÀÏ È¤Àº ¾µ ¼ö ÀÖ´Â ÀåÄ¡°¡ ¾Æ´Õ´Ï´Ù"
+
+msgid "writing to device disabled with 'opendevice' option"
+msgstr "ÀåÄ¡ ¾²±â°¡ 'opendevice' ¿É¼ÇÀ¸·Î ¸·Èû"
+
+msgid "is read-only (add ! to override)"
+msgstr "Àбâ Àü¿ëÀÔ´Ï´Ù (µ¤¾î¾²·Á¸é ! ´õÇϱâ)"
+
+msgid "E506: Can't write to backup file (add ! to override)"
+msgstr "E506: ¹é¾÷ÆÄÀÏÀ» ¾µ ¼ö ¾ø½À´Ï´Ù (µ¤¾î¾²·Á¸é ! ´õÇϱâ)"
+
+msgid "E507: Close error for backup file (add ! to override)"
+msgstr "E507: ¹é¾÷ÆÄÀÏ ´Ý±â ¿¡·¯ (µ¤¾î¾²·Á¸é ! ´õÇϱâ)"
+
+msgid "E508: Can't read file for backup (add ! to override)"
+msgstr "E508: ¹é¾÷ÇÒ ÆÄÀÏÀ» ÀÐÀ» ¼ö ¾ø½À´Ï´Ù (µ¤¾î¾²·Á¸é ! ´õÇϱâ)"
+
+msgid "E509: Cannot create backup file (add ! to override)"
+msgstr "E509: ¹é¾÷ÆÄÀÏÀ» ¸¸µé ¼ö ¾ø½À´Ï´Ù (µ¤¾î¾²·Á¸é ! ´õÇϱâ)"
+
+msgid "E510: Can't make backup file (add ! to override)"
+msgstr "E510: ¹é¾÷ÆÄÀÏÀ» ¸¸µé ¼ö ¾ø½À´Ï´Ù (µ¤¾î¾²·Á¸é ! ´õÇϱâ)"
+
+msgid "E214: Can't find temp file for writing"
+msgstr "E214: ¾µ Àӽà ÆÄÀÏÀ» ãÀ» ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E213: Cannot convert (add ! to write without conversion)"
+msgstr "E213: º¯È¯ÇÒ ¼ö ¾ø½À´Ï´Ù (º¯È¯ ¾øÀÌ ÀúÀåÇÏ·Á¸é ! ´õÇϱâ)"
+
+msgid "E166: Can't open linked file for writing"
+msgstr "E166: ¾µ ¿¬°áµÈ ÆÄÀÏÀ» ¿­ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E212: Can't open file for writing"
+msgstr "E212: ¾µ ÆÄÀÏÀ» ¿­ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E949: File changed while writing"
+msgstr "E949: ¾²´Â Áß¿¡ ÆÄÀÏÀÌ º¯°æµÇ¾ú½À´Ï´Ù"
+
+msgid "E512: Close failed"
+msgstr "E512: ´Ý±â°¡ ½ÇÆÐÇß½À´Ï´Ù"
+
+msgid "E513: write error, conversion failed (make 'fenc' empty to override)"
+msgstr "E513: ¾²±â ¿¡·¯, º¯È¯ ½ÇÆÐ (¹«½ÃÇÏ·Á¸é 'fenc'¸¦ ºñ¿ì¸é µÊ)"
+
+#, c-format
+msgid ""
+"E513: write error, conversion failed in line %ld (make 'fenc' empty to "
+"override)"
+msgstr "E513: ¾²±â ¿¡·¯, %ld ÁÙ¿¡¼­ º¯È¯ ½ÇÆÐ (¹«½ÃÇÏ·Á¸é 'fenc'¸¦ ºñ¿ì¸é µÊ)"
+
+msgid "E514: write error (file system full?)"
+msgstr "E514: ¾²±â ¿¡·¯ (ÆÄÀÏ ½Ã½ºÅÛÀÌ ²Ëᳪ¿ä?)"
+
+msgid " CONVERSION ERROR"
+msgstr " º¯È¯ ¿¡·¯"
+
+#, c-format
+msgid " in line %ld;"
+msgstr "%ld ÁÙ¿¡¼­;"
+
+msgid "[Device]"
+msgstr "[ÀåÄ¡]"
+
+msgid "[New]"
+msgstr "[»õ·Î¿î]"
+
+msgid " [a]"
+msgstr " [a]"
+
+msgid " appended"
+msgstr " ´õÇß½À´Ï´Ù"
+
+msgid " [w]"
+msgstr " [w]"
+
+msgid " written"
+msgstr " ÀúÀå Çß½À´Ï´Ù"
+
+msgid "E205: Patchmode: can't save original file"
+msgstr "E205: ÆÐÄ¡ »óÅÂ: ¿ø·¡ ÆÄÀÏÀ» ÀúÀåÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E206: patchmode: can't touch empty original file"
+msgstr "E206: ÆÐÄ¡ »óÅÂ: ºó ¿ø·¡ ÆÄÀÏÀ» ¸¸µé ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E207: Can't delete backup file"
+msgstr "E207: ¹é¾÷ ÆÄÀÏÀ» Áö¿ï ¼ö ¾ø½À´Ï´Ù"
+
+msgid ""
+"\n"
+"WARNING: Original file may be lost or damaged\n"
+msgstr ""
+"\n"
+"°æ°í: ¿ø·¡ ÆÄÀÏÀÌ ¾ø¾îÁ³°Å³ª ±úÁ³À» ¼ö ÀÖ½À´Ï´Ù\n"
+
+msgid "don't quit the editor until the file is successfully written!"
+msgstr "ÆÄÀÏÀÌ ¼º°øÀûÀ¸·Î ÀúÀåµÉ ¶§±îÁö ÆíÁý±â¸¦ ³¡³»Áö ¸¶½Ê½Ã¿À!"
+
+msgid "[dos]"
+msgstr "[µµ½º]"
+
+msgid "[dos format]"
+msgstr "[µµ½º Çü½Ä]"
+
+msgid "[mac]"
+msgstr "[¸Æ]"
+
+msgid "[mac format]"
+msgstr "[¸Æ Çü½Ä]"
+
+msgid "[unix]"
+msgstr "[À¯´Ð½º]"
+
+msgid "[unix format]"
+msgstr "[À¯´Ð½º Çü½Ä]"
+
+msgid "1 line, "
+msgstr "1 ÁÙ, "
+
+#, c-format
+msgid "%ld lines, "
+msgstr "%ld ÁÙ, "
+
+msgid "1 character"
+msgstr "1 ±ÛÀÚ"
+
+#, c-format
+msgid "%lld characters"
+msgstr "%lld ±ÛÀÚ"
+
+msgid "[noeol]"
+msgstr "[noeol]"
+
+msgid "[Incomplete last line]"
+msgstr "[ºÒ¿ÏÀüÇÑ ¸¶Áö¸· ÁÙ]"
+
+msgid "WARNING: The file has been changed since reading it!!!"
+msgstr "°æ°í: ÆÄÀÏÀÌ ÀÐÀº µÚ¿¡ ¹Ù²î¾ú½À´Ï´Ù!!!"
+
+msgid "Do you really want to write to it"
+msgstr "Á¤¸»·Î ¾²±â¸¦ ¿øÇϽʴϱî"
+
+#, c-format
+msgid "E208: Error writing to \"%s\""
+msgstr "E208: \"%s\"¿¡ ¾²±â ¿¡·¯"
+
+#, c-format
+msgid "E209: Error closing \"%s\""
+msgstr "E209: \"%s\" ´Ý±â ¿¡·¯"
+
+#, c-format
+msgid "E210: Error reading \"%s\""
+msgstr "E210: \"%s\" Àб⠿¡·¯"
+
+msgid "E246: FileChangedShell autocommand deleted buffer"
+msgstr "E246: FileChangedShell ÀÚµ¿¸í·ÉÀÌ ¹öÆÛ¸¦ Áö¿ü½À´Ï´Ù"
+
+#, c-format
+msgid "E211: File \"%s\" no longer available"
+msgstr "E211: ÆÄÀÏ \"%s\"À»(¸¦) ´õ ÀÌ»ó »ç¿ëÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid ""
+"W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as "
+"well"
+msgstr ""
+"W12: °æ°í: ÆÄÀÏ \"%s\"ÀÌ(°¡) ¹Ù²î¾ú°í ¸¶Âù°¡Áö·Î ºöÀÇ ¹öÆÛµµ ¹Ù²î¾ú½À´Ï´Ù"
+
+msgid "See \":help W12\" for more info."
+msgstr "´õ ¸¹Àº Á¤º¸¸¦ º¸·Á¸é \":help W12\"À» ÀÔ·ÂÇϼ¼¿ä."
+
+#, c-format
+msgid "W11: Warning: File \"%s\" has changed since editing started"
+msgstr "W11: °æ°í: ÆÄÀÏ \"%s\"ÀÌ(°¡) °íÄ¡±â ½ÃÀÛÇÑ µÚ¿¡ ¹Ù²î¾ú½À´Ï´Ù"
+
+msgid "See \":help W11\" for more info."
+msgstr "´õ ¸¹Àº Á¤º¸¸¦ º¸·Á¸é \":help W11\"À» ÀÔ·ÂÇϼ¼¿ä."
+
+#, c-format
+msgid "W16: Warning: Mode of file \"%s\" has changed since editing started"
+msgstr "W16: °æ°í: ÆÄÀÏ \"%s\"ÀÇ »óÅ°¡ °íÄ¡±â ½ÃÀÛÇÑ µÚ¿¡ ¹Ù²î¾ú½À´Ï´Ù"
+
+msgid "See \":help W16\" for more info."
+msgstr "´õ ¸¹Àº Á¤º¸¸¦ º¸·Á¸é \":help W16\"À» ÀÔ·ÂÇϼ¼¿ä."
+
+#, c-format
+msgid "W13: Warning: File \"%s\" has been created after editing started"
+msgstr "W13: °æ°í: ÆÄÀÏ \"%s\"ÀÌ(°¡) °íÄ¡±â ½ÃÀÛÇÑ µÚ¿¡ ¸¸µé¾ú½À´Ï´Ù"
+
+msgid "Warning"
+msgstr "°æ°í"
+
+msgid ""
+"&OK\n"
+"&Load File"
+msgstr ""
+"È®ÀÎ(&O)\n"
+"ÆÄÀÏ ºÒ·¯¿À±â(&L)"
+
+#, c-format
+msgid "E462: Could not prepare for reloading \"%s\""
+msgstr "E462: \"%s\"ÀÇ Àç·Îµå¸¦ ÁغñÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "E321: Could not reload \"%s\""
+msgstr "E321: \"%s\"À»(¸¦) ´Ù½Ã ·ÎµåÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "--Deleted--"
+msgstr "--Áö¿öÁü--"
+
+#, c-format
+msgid "auto-removing autocommand: %s <buffer=%d>"
+msgstr "autocommand ÀÚµ¿»èÁ¦: %s <buffer=%d>"
+
+#, c-format
+msgid "E367: No such group: \"%s\""
+msgstr "E367: ÀÌ·± ±×·ì ¾øÀ½: \"%s\""
+
+msgid "E936: Cannot delete the current group"
+msgstr "E936: ÇöÀç ±×·ìÀ» »èÁ¦ÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "W19: Deleting augroup that is still in use"
+msgstr "W19: »ç¿ëÁßÀÎ augroupÀ» »èÁ¦ÇÏ·Á°í ÇÕ´Ï´Ù"
+
+#, c-format
+msgid "E215: Illegal character after *: %s"
+msgstr "E215: * µÚ¿¡ ÀÌ»óÇÑ ±ÛÀÚ: %s"
+
+#, c-format
+msgid "E216: No such event: %s"
+msgstr "E216: ±×·± À̺¥Æ® ¾øÀ½: %s"
+
+#, c-format
+msgid "E216: No such group or event: %s"
+msgstr "E216: ±×·± ±×·ìÀ̳ª À̺¥Æ® ¾øÀ½: %s"
+
+msgid ""
+"\n"
+"--- Autocommands ---"
+msgstr ""
+"\n"
+"--- ÀÚµ¿-¸í·É ---"
+
+#, c-format
+msgid "E680: <buffer=%d>: invalid buffer number "
+msgstr "E680: <buffer=%d>: À߸øµÈ ¹öÆÛ ¹øÈ£"
+
+msgid "E217: Can't execute autocommands for ALL events"
+msgstr "E217: ALL À̺¥Æ®¿¡ ´ëÇØ ÀÚµ¿¸í·ÉÀ» ½ÇÇàÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "No matching autocommands"
+msgstr "¸Â´Â ÀÚµ¿¸í·ÉÀÌ ¾ø½À´Ï´Ù"
+
+msgid "E218: autocommand nesting too deep"
+msgstr "E218: ÀÚµ¿¸í·ÉÀÌ ³Ê¹« ±í°Ô ÁßøµÇ¾ú½À´Ï´Ù"
+
+#, c-format
+#~ msgid "%s Autocommands for \"%s\""
+#~ msgstr ""
+
+#, c-format
+msgid "Executing %s"
+msgstr "%s ½ÇÇàÁß"
+
+#, c-format
+msgid "autocommand %s"
+msgstr "ÀÚµ¿¸í·É %s"
+
+msgid "E219: Missing {."
+msgstr "E219: {°¡ ¾ø½À´Ï´Ù."
+
+msgid "E220: Missing }."
+msgstr "E220: }°¡ ¾ø½À´Ï´Ù."
+
+msgid "E490: No fold found"
+msgstr "E490: fold°¡ ¾ø½À´Ï´Ù"
+
+msgid "E350: Cannot create fold with current 'foldmethod'"
+msgstr "E350: ÇöÀçÀÇ 'foldmethod'À¸·Î Á¢±â¸¦ ¸¸µé ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E351: Cannot delete fold with current 'foldmethod'"
+msgstr "E351: ÇöÀçÀÇ 'foldmethod'À¸·Î Á¢±â¸¦ Áö¿ï ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "+--%3ld line folded "
+msgid_plural "+--%3ld lines folded "
+msgstr[0] "+-%3ld ÁÙÀÌ Á¢Çû½À´Ï´Ù"
+msgstr[1] "+-%3ld ÁÙµéÀÌ Á¢Çû½À´Ï´Ù"
+
+msgid "E222: Add to read buffer"
+msgstr "E222: ÀÐÇôÁø ¹öÆÛ¿¡ ´õÇϱâ"
+
+msgid "E223: recursive mapping"
+msgstr "E223: Àç±Í ¸ÊÇÎ"
+
+#, c-format
+msgid "E224: global abbreviation already exists for %s"
+msgstr "E224: %s Àü¿ª ¾à¾î°¡ ÀÌ¹Ì Á¸ÀçÇÕ´Ï´Ù"
+
+#, c-format
+msgid "E225: global mapping already exists for %s"
+msgstr "E225: %s Àü¿ª ¸ÅÇÎÀÌ ÀÌ¹Ì Á¸ÀçÇÕ´Ï´Ù"
+
+#, c-format
+msgid "E226: abbreviation already exists for %s"
+msgstr "E226: %s ¾à¾î°¡ ÀÌ¹Ì Á¸ÀçÇÕ´Ï´Ù"
+
+#, c-format
+msgid "E227: mapping already exists for %s"
+msgstr "E227: %s ¸ÅÇÎÀÌ ÀÌ¹Ì Á¸ÀçÇÕ´Ï´Ù"
+
+msgid "No abbreviation found"
+msgstr "¾à¾î¸¦ ãÀ» ¼ö ¾ø½À´Ï´Ù"
+
+msgid "No mapping found"
+msgstr "¸ÊÇÎÀ» ãÀ» ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E228: makemap: Illegal mode"
+msgstr "E228: makemap: ÀÌ»óÇÑ »óÅÂ"
+
+msgid "<cannot open> "
+msgstr "<¿­ ¼ö ¾øÀ½> "
+
+#, c-format
+msgid "E616: vim_SelFile: can't get font %s"
+msgstr "E616: vim_SelFile: ±Û²Ã %sÀ»(¸¦) ¾òÀ» ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E614: vim_SelFile: can't return to current directory"
+msgstr "E614: vim_SelFile: ÇöÀç µð·ºÅ丮·Î µ¹¾Æ°¥ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "Pathname:"
+msgstr "°æ·Î À̸§:"
+
+msgid "E615: vim_SelFile: can't get current directory"
+msgstr "E615: vim_SelFile: ÇöÀç µð·ºÅ丮¸¦ ¾òÀ» ¼ö ¾ø½À´Ï´Ù"
+
+msgid "OK"
+msgstr "È®ÀÎ"
+
+msgid "Cancel"
+msgstr "Ãë¼Ò"
+
+msgid "Vim dialog"
+msgstr "ºö ´ëÈ­»óÀÚ"
+
+msgid "Scrollbar Widget: Could not get geometry of thumb pixmap."
+msgstr "½ºÅ©·Ñ¹Ù À§Á¬: ½æ ÇȽº¸ÊÀÇ Áö¿À¹ÌÆ®¸®¸¦ ¾òÀ» ¼ö ¾ø½À´Ï´Ù."
+
+msgid "E232: Cannot create BalloonEval with both message and callback"
+msgstr "E232: ¸Þ½ÃÁö¿Í ÄÝ¹é ¸ðµÎ¸¦ »ç¿ëÇؼ­´Â BalloonEvalÀ» ¸¸µé ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E851: Failed to create a new process for the GUI"
+msgstr "E851: »õ·Î¿î GUI ÇÁ·Î¼¼½º¸¦ »ý¼ºÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E852: The child process failed to start the GUI"
+msgstr "E852: ÀÚ½Ä ÇÁ·Î¼¼½º°¡ GUI¸¦ ½ÃÀÛÇÏÁö ¸øÇß½À´Ï´Ù"
+
+msgid "E229: Cannot start the GUI"
+msgstr "E229: GUI¸¦ ½ÃÀÛÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "E230: Cannot read from \"%s\""
+msgstr "E230: \"%s\"¿¡¼­ ÀÐÀ» ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E665: Cannot start GUI, no valid font found"
+msgstr "E665: ¾µ¸¸ÇÑ ±Û²ÃÀ» ãÀ» ¼ö ¾ø¾î¼­ GUI¸¦ ½ÇÇàÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E231: 'guifontwide' invalid"
+msgstr "E231: 'guifontwide'°¡ ÀÌ»óÇÕ´Ï´Ù"
+
+msgid "E599: Value of 'imactivatekey' is invalid"
+msgstr "E599: 'imactivatekey' °ªÀÌ ÀÌ»óÇÕ´Ï´Ù"
+
+#, c-format
+msgid "E254: Cannot allocate color %s"
+msgstr "E254: »ö %sÀ»(¸¦) ÇÒ´çÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+#~ msgid "No match at cursor, finding next"
+#~ msgstr ""
+
+msgid "_Cancel"
+msgstr "Ãë¼Ò(_C)"
+
+msgid "_Save"
+msgstr "ÀúÀå(_S)"
+
+msgid "_Open"
+msgstr "¿­±â(_O)"
+
+msgid "_OK"
+msgstr "È®ÀÎ(_O)"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"&Cancel"
+msgstr ""
+"¿¹(&Y)\n"
+"¾Æ´Ï¿À(&N)\n"
+"Ãë¼Ò(&C)"
+
+msgid "Yes"
+msgstr "¿¹"
+
+msgid "No"
+msgstr "¾Æ´Ï¿À"
+
+msgid "Input _Methods"
+msgstr "ÀÔ·Â ¹æ¹ý(_M)"
+
+msgid "VIM - Search and Replace..."
+msgstr "ºö - ã¾Æ¼­ ¹Ù²Ù±â..."
+
+msgid "VIM - Search..."
+msgstr "ºö - ã±â..."
+
+msgid "Find what:"
+msgstr "¹«¾ó ãÀ»±î¿ä:"
+
+msgid "Replace with:"
+msgstr "¹Ù²Ü ¹®ÀÚ¿­:"
+
+msgid "Match whole word only"
+msgstr "¶È°°Àº ³¹¸»¸¸"
+
+#~ msgid "Match case"
+#~ msgstr ""
+
+msgid "Direction"
+msgstr "¹æÇâ"
+
+msgid "Up"
+msgstr "À§·Î"
+
+msgid "Down"
+msgstr "¾Æ·¡·Î"
+
+msgid "Find Next"
+msgstr "´ÙÀ½ ã±â"
+
+msgid "Replace"
+msgstr "¹Ù²Ù±â"
+
+msgid "Replace All"
+msgstr "¸ðµÎ ¹Ù²Ù±â"
+
+msgid "_Close"
+msgstr "´Ý±â(_C)"
+
+msgid "Vim: Received \"die\" request from session manager\n"
+msgstr "ºö: ¼¼¼Ç °ü¸®ÀڷκÎÅÍ \"die\" ¿äûÀ» ¹Þ¾Ò½À´Ï´Ù\n"
+
+msgid "Close tab"
+msgstr "ÅÇ ´Ý±â"
+
+msgid "New tab"
+msgstr "»õ ÅÇ"
+
+msgid "Open Tab..."
+msgstr "ÅÇ ¿­±â..."
+
+msgid "Vim: Main window unexpectedly destroyed\n"
+msgstr "ºö: ¸ÞÀΠâÀÌ Á×°Ô µÉ °ÍÀÔ´Ï´Ù\n"
+
+msgid "&Filter"
+msgstr "°Å¸£°³(&F)"
+
+msgid "&Cancel"
+msgstr "Ãë¼Ò(&C)"
+
+msgid "Directories"
+msgstr "µð·ºÅ丮"
+
+msgid "Filter"
+msgstr "°Å¸£°³"
+
+msgid "&Help"
+msgstr "µµ¿ò¸»(&H)"
+
+msgid "Files"
+msgstr "ÆÄÀÏ"
+
+msgid "&OK"
+msgstr "È®ÀÎ(&O)"
+
+msgid "Selection"
+msgstr "°í¸£±â"
+
+msgid "Find &Next"
+msgstr "´ÙÀ½ ã±â(&N)"
+
+msgid "&Replace"
+msgstr "¹Ù²Ù±â(&R)"
+
+msgid "Replace &All"
+msgstr "¸ðµÎ ¹Ù²Ù±â(&A)"
+
+msgid "&Undo"
+msgstr "Ãë¼Ò(&U)"
+
+msgid "Open tab..."
+msgstr "ÅÇ ¿­±â..."
+
+msgid "Find string (use '\\\\' to find a '\\')"
+msgstr "¹®ÀÚ¿­ ã±â ('\\'¸¦ ãÀ¸·Á¸é '\\\\' »ç¿ë)"
+
+msgid "Find & Replace (use '\\\\' to find a '\\')"
+msgstr "¹®ÀÚ¿­ ã¾Æ¼­ ¹Ù²Ù±â ('\\'¸¦ ãÀ¸·Á¸é '\\\\' »ç¿ë)"
+
+msgid "Not Used"
+msgstr "»ç¿ë ¾ÊµÊ"
+
+msgid "Directory\t*.nothing\n"
+msgstr "µð·ºÅ丮\t*.nothing\n"
+
+#, c-format
+msgid "E671: Cannot find window title \"%s\""
+msgstr "E671: â Á¦¸ñ \"%s\"À»(¸¦) ãÀ» ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "E243: Argument not supported: \"-%s\"; Use the OLE version."
+msgstr "E243: Áö¿øµÇÁö ¾Ê´Â ÀÎÀÚ: \"-%s\": OLE ÆÇÀ» »ç¿ëÇϽʽÿÀ."
+
+msgid "E672: Unable to open window inside MDI application"
+msgstr "E672: MDI ÀÀ¿ëÇÁ·Î±×·¥ ¾È¿¡¼­ âÀ» ¿­ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "Vim E458: Cannot allocate colormap entry, some colors may be incorrect"
+msgstr ""
+"ºö E458: »ö»ó¸Ê ¿£Æ®¸®¸¦ ÇÒ´çÇÒ ¼ö ¾ø½À´Ï´Ù, ¸î¸î »öÀÌ À߸øµÉ ¼ö ÀÖ½À´Ï´Ù"
+
+#, c-format
+msgid "E250: Fonts for the following charsets are missing in fontset %s:"
+msgstr "E250: ´ÙÀ½ ±ÛÀÚ¼ÂÀÇ ±Û²ÃÀÌ ±Û²Ã¼Â %s¿¡ ¾ø½À´Ï´Ù:"
+
+#, c-format
+msgid "E252: Fontset name: %s"
+msgstr "E252: ±Û²Ã¼Â À̸§: %s"
+
+#, c-format
+msgid "Font '%s' is not fixed-width"
+msgstr "±Û²Ã '%s'Àº(´Â) °íÁ¤³ÐÀÌ°¡ ¾Æ´Õ´Ï´Ù"
+
+#, c-format
+msgid "E253: Fontset name: %s"
+msgstr "E253: ±Û²Ã¼Â À̸§: %s"
+
+#, c-format
+msgid "Font0: %s"
+msgstr "±Û²Ã0: %s"
+
+#, c-format
+msgid "Font1: %s"
+msgstr "±Û²Ã1: %s"
+
+#, c-format
+msgid "Font%ld width is not twice that of font0"
+msgstr "±Û²Ã%ld ³Êºñ°¡ ±Û²Ã0ÀÇ µÎ¹è°¡ ¾Æ´Õ´Ï´Ù"
+
+#, c-format
+msgid "Font0 width: %ld"
+msgstr "±Û²Ã0 ³Êºñ: %ld"
+
+#, c-format
+msgid "Font1 width: %ld"
+msgstr "±Û²Ã1 ³Êºñ: %ld"
+
+msgid "Invalid font specification"
+msgstr "±Û²Ã ±Ô°ÝÀÌ ÀÌ»óÇÕ´Ï´Ù"
+
+msgid "&Dismiss"
+msgstr "Ãë¼Ò(&D)"
+
+#~ msgid "no specific match"
+#~ msgstr ""
+
+msgid "Vim - Font Selector"
+msgstr "Vim - ±Û²Ã ¼±Åñâ"
+
+msgid "Name:"
+msgstr "À̸§:"
+
+#~ msgid "Show size in Points"
+#~ msgstr ""
+
+msgid "Encoding:"
+msgstr "ÀÎÄÚµù:"
+
+msgid "Font:"
+msgstr "±Û²Ã:"
+
+msgid "Style:"
+msgstr "½ºÅ¸ÀÏ:"
+
+msgid "Size:"
+msgstr "Å©±â:"
+
+msgid "E256: Hangul automata ERROR"
+msgstr "E256: ÇÑ±Û ¿ÀÅ丶Ÿ ¿¡·¯"
+
+msgid "E550: Missing colon"
+msgstr "E550: ÄÝ·ÐÀÌ ¾ø½À´Ï´Ù"
+
+msgid "E551: Illegal component"
+msgstr "E551: ÀÌ»óÇÑ ÄÄÆ÷³ÍÆ®"
+
+msgid "E552: digit expected"
+msgstr "E552: ¼ýÀÚ°¡ ÇÊ¿äÇÕ´Ï´Ù"
+
+#, c-format
+msgid "Page %d"
+msgstr "ÆäÀÌÁö %d"
+
+msgid "No text to be printed"
+msgstr "ÀμâµÉ ÅؽºÆ®°¡ ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "Printing page %d (%d%%)"
+msgstr "ÆäÀÌÁö %d ÀμâÁß (%d%%)"
+
+#, c-format
+msgid " Copy %d of %d"
+msgstr " º¹»ç %d / %d"
+
+#, c-format
+msgid "Printed: %s"
+msgstr "ÀμâµÊ: %s"
+
+msgid "Printing aborted"
+msgstr "ÀμⰡ Ãë¼ÒµÇ¾ú½À´Ï´Ù."
+
+msgid "E455: Error writing to PostScript output file"
+msgstr "E455: Æ÷½ºÆ®½ºÅ©¸³Æ® Ãâ·ÂÆÄÀÏ¿¡ ¾µ ¼ö ¾ø½À´Ï´Ù."
+
+#, c-format
+msgid "E624: Can't open file \"%s\""
+msgstr "E624: \"%s\" ÆÄÀÏÀ» ¿­ ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "E457: Can't read PostScript resource file \"%s\""
+msgstr "E457: Æ÷½ºÆ®½ºÅ©¸³Æ® ¸®¼Ò½º ÆÄÀÏ \"%s\"À»(¸¦) ÀÐÀ» ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "E618: file \"%s\" is not a PostScript resource file"
+msgstr "E618: ÆÄÀÏ \"%s\"Àº(´Â) Æ÷½ºÆ®½ºÅ©¸³Æ® ¸®¼Ò½º ÆÄÀÏÀÌ ¾Æ´Õ´Ï´Ù"
+
+#, c-format
+msgid "E619: file \"%s\" is not a supported PostScript resource file"
+msgstr "E619: ÆÄÀÏ \"%s\"Àº(´Â) Áö¿øµÇ´Â Æ÷½ºÆ®½ºÅ©¸³Æ® ¸®¼Ò½º ÆÄÀÏÀÌ ¾Æ´Õ´Ï´Ù"
+
+#, c-format
+msgid "E621: \"%s\" resource file has wrong version"
+msgstr "E621: \"%s\" ¸®¼Ò½º ÆÄÀÏÀº ¹öÀüÀÌ À߸øµÇ¾ú½À´Ï´Ù"
+
+msgid "E673: Incompatible multi-byte encoding and character set."
+msgstr "E673: ȣȯµÇÁö ¾Ê´Â ´ÙÁß¹®ÀÚ ÀÎÄÚµù°ú ¹®ÀÚ¼Â."
+
+msgid "E674: printmbcharset cannot be empty with multi-byte encoding."
+msgstr "E674: printmbcharset´Â ´ÙÁß¹®ÀÚ ÀÎÄÚµù¿¡¼­ ¹Ýµå½Ã ¼³Á¤µÇ¾î¾ß ÇÕ´Ï´Ù."
+
+msgid "E675: No default font specified for multi-byte printing."
+msgstr "E675: ´ÙÁß¹®ÀÚ Àμ⸦ À§ÇÑ ±Û²ÃÀÌ ¼³Á¤µÇ¾î ÀÖÁö ¾Ê½À´Ï´Ù"
+
+msgid "E324: Can't open PostScript output file"
+msgstr "E324: Æ÷½ºÆ®½ºÅ©¸³Æ® Ãâ·ÂÆÄÀÏÀ» ¿­ ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "E456: Can't open file \"%s\""
+msgstr "E456: \"%s\" ÆÄÀÏÀ» ¿­ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E456: Can't find PostScript resource file \"prolog.ps\""
+msgstr "E456: Æ÷½ºÆ®½ºÅ©¸³Æ® ¸®¼Ò½º ÆÄÀÏ \"prolog.ps\"¸¦ ãÀ» ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E456: Can't find PostScript resource file \"cidfont.ps\""
+msgstr "E456: Æ÷½ºÆ®½ºÅ©¸³Æ® ¸®¼Ò½º ÆÄÀÏ \"cidfont.ps\"¸¦ ãÀ» ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "E456: Can't find PostScript resource file \"%s.ps\""
+msgstr "E456: Æ÷½ºÆ®½ºÅ©¸³Æ® ¸®¼Ò½º ÆÄÀÏ \"%s.ps\"¸¦ ãÀ» ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "E620: Unable to convert to print encoding \"%s\""
+msgstr "E620: \"%s\" Àμâ ÀÎÄÚµùÀ¸·Î º¯È¯ÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "Sending to printer..."
+msgstr "ÇÁ¸°ÅÍ·Î º¸³»´Â Áß..."
+
+msgid "E365: Failed to print PostScript file"
+msgstr "E365: Æ÷½ºÆ®½ºÅ©¸³Æ® ÆÄÀÏÀ» ÀμâÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "Print job sent."
+msgstr "ÀμâÀÛ¾÷ÀÌ ³¡³µ½À´Ï´Ù."
+
+msgid "Add a new database"
+msgstr "»õ µ¥ÀÌÅͺ£À̽º ´õÇϱâ"
+
+#~ msgid "Query for a pattern"
+#~ msgstr ""
+
+msgid "Show this message"
+msgstr "ÀÌ ¸Þ½ÃÁö º¸À̱â"
+
+msgid "Kill a connection"
+msgstr "¿¬°á ²÷±â"
+
+msgid "Reinit all connections"
+msgstr "¸ðµç ¿¬°á ´Ù½Ã ÃʱâÈ­"
+
+msgid "Show connections"
+msgstr "¿¬°á º¸¿©ÁÖ±â"
+
+#, c-format
+msgid "E560: Usage: cs[cope] %s"
+msgstr "E560: »ç¿ë¹ý: cs[cope] %s"
+
+msgid "This cscope command does not support splitting the window.\n"
+msgstr "ÀÌ cscope ¸í·ÉÀº â ³ª´©±â¸¦ Áö¿øÇÏÁö ¾Ê½À´Ï´Ù.\n"
+
+msgid "E562: Usage: cstag <ident>"
+msgstr "E562: »ç¿ë¹ý: cstag <ident>"
+
+msgid "E257: cstag: tag not found"
+msgstr "E257: cstag: ű׸¦ ãÀ» ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "E563: stat(%s) error: %d"
+msgstr "E563: stat(%s) ¿¡·¯: %d"
+
+msgid "E563: stat error"
+msgstr "E563: stat ¿¡·¯"
+
+#, c-format
+msgid "E564: %s is not a directory or a valid cscope database"
+msgstr "E564: %sÀº(´Â) µð·ºÅ丮µµ ȤÀº cscope µ¥ÀÌÅͺ£À̽º°¡ ¾Æ´Õ´Ï´Ù"
+
+#, c-format
+msgid "Added cscope database %s"
+msgstr "cscope µ¥ÀÌÅͺ£À̽º %s¿¡ ´õÇß½À´Ï´Ù."
+
+#, c-format
+msgid "E262: error reading cscope connection %ld"
+msgstr "E262: cscope ¿¬°á %ld Àб⠿¡·¯"
+
+msgid "E561: unknown cscope search type"
+msgstr "E561: ¸ð¸£´Â cscope ã±â Çü½Ä"
+
+msgid "E566: Could not create cscope pipes"
+msgstr "E566: cscope ÆÄÀÌÇÁ¸¦ ¸¸µé ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E622: Could not fork for cscope"
+msgstr "E622: cscope¸¦ forkÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "cs_create_connection setpgid failed"
+msgstr "cs_create_connection setpgid°¡ ½ÇÆÐÇß½À´Ï´Ù"
+
+msgid "cs_create_connection exec failed"
+msgstr "cs_create_connection ½ÇÇàÀÌ ½ÇÆÐÇß½À´Ï´Ù"
+
+msgid "cs_create_connection: fdopen for to_fp failed"
+msgstr "cs_create_connection: to_fp¿¡ ´ëÇÑ fdopen ½ÇÆÐ"
+
+msgid "cs_create_connection: fdopen for fr_fp failed"
+msgstr "cs_create_connection: fr_fp¿¡ ´ëÇÑ fdopen ½ÇÆÐ"
+
+msgid "E623: Could not spawn cscope process"
+msgstr "E623: cscope ÇÁ·Î¼¼½º¸¦ spawnÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E567: no cscope connections"
+msgstr "E567: cscope ¿¬°áÀÌ ¾ø½À´Ï´Ù"
+
+#, c-format
+#~ msgid "E469: invalid cscopequickfix flag %c for %c"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E259: no matches found for cscope query %s of %s"
+#~ msgstr ""
+
+msgid "cscope commands:\n"
+msgstr "cscope ¸í·É:\n"
+
+#, c-format
+msgid "%-5s: %s%*s (Usage: %s)"
+msgstr "%-5s: %s%*s (»ç¿ë¹ý: %s)"
+
+msgid ""
+"\n"
+" a: Find assignments to this symbol\n"
+" c: Find functions calling this function\n"
+" d: Find functions called by this function\n"
+" e: Find this egrep pattern\n"
+" f: Find this file\n"
+" g: Find this definition\n"
+" i: Find files #including this file\n"
+" s: Find this C symbol\n"
+" t: Find this text string\n"
+msgstr ""
+"\n"
+" a: ÀÌ ±âÈ£¿¡ ´ëÇÑ ÇÒ´ç ã±â\n"
+" c: ÀÌ ÇÔ¼ö¸¦ ºÎ¸£´Â ÇÔ¼öµé ã±â\n"
+" d: ÀÌ ÇÔ¼ö¿¡ ÀÇÇØ ºÒ·ÁÁö´Â ÇÔ¼öµé ã±â\n"
+" e: ÀÌ egrep ÆÐÅÏ Ã£±â\n"
+" f: ÀÌ ÆÄÀÏ Ã£±â\n"
+" g: ÀÌ Á¤ÀÇ Ã£±â\n"
+" i: ÀÌ ÆÄÀÏÀ» #includeÇÏ´Â ÆÄÀϵé ã±â\n"
+" s: ÀÌ C ±âÈ£ ã±â\n"
+" t: ÀÌ ¹®ÀÚ¿­ ã±â\n"
+
+#, c-format
+msgid "E625: cannot open cscope database: %s"
+msgstr "E625: cscope µ¥ÀÌÅͺ£À̽º¸¦ ¿­ ¼ö ¾øÀ½: %s"
+
+msgid "E626: cannot get cscope database information"
+msgstr "E626: cscope µ¥ÀÌÅͺ£À̽º Á¤º¸¸¦ ¾òÀ» ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E568: duplicate cscope database not added"
+msgstr "E568: Áߺ¹µÈ cscope µ¥ÀÌÅͺ£À̽º´Â ´õÇØÁöÁö ¾Ê¾Ò½À´Ï´Ù"
+
+#, c-format
+msgid "E261: cscope connection %s not found"
+msgstr "E261: cscope ¿¬°á %sÀ»(¸¦) ãÀ» ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "cscope connection %s closed"
+msgstr "cscope ¿¬°á %sÀÌ(°¡) ´ÝÇû½À´Ï´Ù"
+
+msgid "E570: fatal error in cs_manage_matches"
+msgstr "E570: cs_manage_matches¿¡ ½É°¢ÇÑ ¿¡·¯"
+
+#, c-format
+msgid "Cscope tag: %s"
+msgstr "Cscope ű×: %s"
+
+msgid ""
+"\n"
+" # line"
+msgstr ""
+"\n"
+" # ÁÙ"
+
+msgid "filename / context / line\n"
+msgstr "ÆÄÀÏ À̸§ / ÄÜÅؽºÆ® / ÁÙ\n"
+
+#, c-format
+msgid "E609: Cscope error: %s"
+msgstr "E609: Cscope ¿¡·¯: %s"
+
+msgid "All cscope databases reset"
+msgstr "¸ðµç cscope µ¥ÀÌÅͺ£À̽º ¸®¼Â"
+
+msgid "no cscope connections\n"
+msgstr "cscope ¿¬°áÀÌ ¾ø½À´Ï´Ù\n"
+
+msgid " # pid database name prepend path\n"
+msgstr " # pid µ¥ÀÌÅͺ£À̽º À̸§ prepend path\n"
+
+msgid "Lua library cannot be loaded."
+msgstr "Lua ¶óÀ̺귯¸®¸¦ ·ÎµùÇÒ ¼ö ¾ø½À´Ï´Ù."
+
+msgid "cannot save undo information"
+msgstr "undo Á¤º¸¸¦ ÀúÀåÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+msgid ""
+"E815: Sorry, this command is disabled, the MzScheme libraries could not be "
+"loaded."
+msgstr ""
+"E815: ¹Ì¾ÈÇÕ´Ï´Ù, ÀÌ ¸í·ÉÀº »ç¿ëÇÒ ¼ö ¾ø½À´Ï´Ù, MzScheme ¶óÀ̺귯¸®¸¦ ·ÎµùÇÒ "
+"¼ö ¾ø½À´Ï´Ù."
+
+msgid ""
+"E895: Sorry, this command is disabled, the MzScheme's racket/base module "
+"could not be loaded."
+msgstr ""
+"E895: ¹Ì¾ÈÇÕ´Ï´Ù, ÀÌ ¸í·ÉÀº »ç¿ëÇÒ ¼ö ¾ø½À´Ï´Ù, MzSchemeÀÇ racket/base ¸ðµâ"
+"À» ·ÎµùÇÒ ¼ö ¾ø½À´Ï´Ù."
+
+msgid "invalid expression"
+msgstr "À߸øµÈ Ç¥Çö½Ä"
+
+msgid "expressions disabled at compile time"
+msgstr "Ç¥Çö½ÄÀ» Áö¿øÇÏÁö ¾Êµµ·Ï ÄÄÆÄÀÏ µÇ¾ú½À´Ï´Ù"
+
+msgid "hidden option"
+msgstr "¼û±è ¿É¼Ç"
+
+msgid "unknown option"
+msgstr "¸ð¸£´Â ¿É¼Ç"
+
+msgid "window index is out of range"
+msgstr "â ¹øÈ£°¡ ¹üÀ§¸¦ ¹þ¾î³µ½À´Ï´Ù"
+
+msgid "couldn't open buffer"
+msgstr "¹öÆÛ¸¦ ¿­ ¼ö ¾ø¾ú½À´Ï´Ù"
+
+msgid "cannot delete line"
+msgstr "ÁÙÀ» Áö¿ï ¼ö ¾ø½À´Ï´Ù"
+
+msgid "cannot replace line"
+msgstr "ÁÙÀ» ¹Ù²Ü ¼ö ¾ø½À´Ï´Ù"
+
+msgid "cannot insert line"
+msgstr "ÁÙÀ» ³¢¿ö³ÖÀ» ¼ö ¾ø½À´Ï´Ù"
+
+msgid "string cannot contain newlines"
+msgstr "¹®ÀÚ¿­Àº newlineÀ» Æ÷ÇÔÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+#~ msgid "error converting Scheme values to Vim"
+#~ msgstr ""
+
+msgid "Vim error: ~a"
+msgstr "Vim ¿¡·¯: ~a"
+
+msgid "Vim error"
+msgstr "Vim ¿¡·¯"
+
+msgid "buffer is invalid"
+msgstr "¹öÆÛ°¡ ÀÌ»óÇÕ´Ï´Ù"
+
+msgid "window is invalid"
+msgstr "âÀÌ ÀÌ»óÇÕ´Ï´Ù"
+
+msgid "linenr out of range"
+msgstr "ÁÙ ¹øÈ£°¡ ¹üÀ§¸¦ ¹þ¾î³µ½À´Ï´Ù"
+
+msgid "not allowed in the Vim sandbox"
+msgstr "Vim sandbox¿¡¼­´Â Çã¿ëµÇÁö ¾Ê½À´Ï´Ù"
+
+msgid "E837: This Vim cannot execute :py3 after using :python"
+msgstr "E837: ÀÌ VimÀº :pythonÀ» »ç¿ëÇÑ ÈÄ¿¡ :py3À» »ç¿ëÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+msgid ""
+"E263: Sorry, this command is disabled, the Python library could not be "
+"loaded."
+msgstr ""
+"E263: ¹Ì¾ÈÇÕ´Ï´Ù, ÀÌ ¸í·ÉÀº »ç¿ëÇÒ ¼ö ¾ø½À´Ï´Ù, ÆÄÀ̽㠶óÀ̺귯¸®¸¦ ·ÎµùÇÒ "
+"¼ö ¾ø½À´Ï´Ù."
+
+msgid "E836: This Vim cannot execute :python after using :py3"
+msgstr "E836: ÀÌ VimÀº :py3À» »ç¿ëÇÑ ÈÄ¿¡ :pythonÀ» »ç¿ëÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+msgid ""
+"E887: Sorry, this command is disabled, the Python's site module could not be "
+"loaded."
+msgstr ""
+"E887: ¹Ì¾ÈÇÕ´Ï´Ù, ÀÌ ¸í·ÉÀº »ç¿ëÇÒ ¼ö ¾ø½À´Ï´Ù, ÆÄÀ̽ãÀÇ »çÀÌÆ® ¸ðµâÀ» ·Îµù"
+"ÇÒ ¼ö ¾ø½À´Ï´Ù."
+
+msgid "E659: Cannot invoke Python recursively"
+msgstr "E659: PythonÀ» Àç±ÍÈ£ÃâÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E265: $_ must be an instance of String"
+msgstr "E265: $_´Â String ÀνºÅϽºÀ̾î¾ß ÇÕ´Ï´Ù"
+
+msgid ""
+"E266: Sorry, this command is disabled, the Ruby library could not be loaded."
+msgstr ""
+"E266: ¹Ì¾ÈÇÕ´Ï´Ù, ÀÌ ¸í·ÉÀº »ç¿ëÇÒ ¼ö ¾ø½À´Ï´Ù, ·çºñ ¶óÀ̺귯¸®¸¦ ·ÎµùÇÒ ¼ö "
+"¾ø½À´Ï´Ù."
+
+msgid "E267: unexpected return"
+msgstr "E267: ¶æ¹ÛÀÇ return"
+
+msgid "E268: unexpected next"
+msgstr "E268: ¶æ¹ÛÀÇ next"
+
+msgid "E269: unexpected break"
+msgstr "E269: ¶æ¹ÛÀÇ break"
+
+msgid "E270: unexpected redo"
+msgstr "E270: ¶æ¹ÛÀÇ redo"
+
+#~ msgid "E271: retry outside of rescue clause"
+#~ msgstr ""
+
+msgid "E272: unhandled exception"
+msgstr "E272: ó¸®¾ÊµÈ ¿¹¿Ü"
+
+#, c-format
+msgid "E273: unknown longjmp status %d"
+msgstr "E273: ¸ð¸£´Â longjmp »óÅ %d"
+
+msgid "invalid buffer number"
+msgstr "À߸øµÈ ¹öÆÛ ¹øÈ£"
+
+msgid "not implemented yet"
+msgstr "¾ÆÁ÷ ±¸ÇöµÇÁö ¾Ê¾Ò½À´Ï´Ù"
+
+msgid "cannot set line(s)"
+msgstr "ÁÙÀ» ¼³Á¤ÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "invalid mark name"
+msgstr "À߸øµÈ ¸¶Å© À̸§"
+
+msgid "mark not set"
+msgstr "¸¶Å©°¡ ¼³Á¤µÇÁö ¾Ê¾Ò½À´Ï´Ù"
+
+#, c-format
+msgid "row %d column %d"
+msgstr "Çà %d ¿­ %d"
+
+msgid "cannot insert/append line"
+msgstr "ÁÙÀ» ³¢¿ö³Ö°Å³ª ´õÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "line number out of range"
+msgstr "ÁÙ ¹øÈ£°¡ ¹üÀ§¸¦ ¹þ¾î³µ½À´Ï´Ù"
+
+msgid "unknown flag: "
+msgstr "¸ð¸£´Â Ç÷¡±×: "
+
+msgid "unknown vimOption"
+msgstr "¸ð¸£´Â ºö ¿É¼Ç"
+
+msgid "keyboard interrupt"
+msgstr "Å°º¸µå ÀÎÅÍ·´Æ®"
+
+msgid "vim error"
+msgstr "ºö ¿¡·¯"
+
+msgid "cannot create buffer/window command: object is being deleted"
+msgstr "¹öÆÛ/â ¸í·ÉÀ» ¸¸µé ¼ö ¾ø½À´Ï´Ù: °´Ã¼°¡ Áö¿öÁý´Ï´Ù"
+
+msgid ""
+"cannot register callback command: buffer/window is already being deleted"
+msgstr "ÄÝ¹é ¸í·ÉÀ» µî·ÏÇÒ ¼ö ¾ø½À´Ï´Ù: ¹öÆÛ/âÀÌ ÀÌ¹Ì Áö¿öÁ³½À´Ï´Ù"
+
+msgid ""
+"E280: TCL FATAL ERROR: reflist corrupt!? Please report this to vim-dev@vim."
+"org"
+msgstr ""
+"E280: TCL ½É°¢ÇÑ ¿¡·¯: reflist°¡ ±úÁ³³ª!? ÀÌ ¹®Á¦¸¦ vim-dev@vim.org·Î ¾Ë·ÁÁÖ"
+"½Ê½Ã¿À"
+
+msgid "cannot register callback command: buffer/window reference not found"
+msgstr "ÄÝ¹é ¸í·ÉÀ» µî·ÏÇÒ ¼ö ¾ø½À´Ï´Ù: ¹öÆÛ/â ÂüÁ¶¸¦ ãÀ» ¼ö ¾ø½À´Ï´Ù"
+
+msgid ""
+"E571: Sorry, this command is disabled: the Tcl library could not be loaded."
+msgstr ""
+"E571: ¹Ì¾ÈÇÕ´Ï´Ù, ÀÌ ¸í·ÉÀº »ç¿ëÇÒ ¼ö ¾ø½À´Ï´Ù, Tcl ¶óÀ̺귯¸®¸¦ ·ÎµùÇÒ ¼ö ¾ø"
+"½À´Ï´Ù."
+
+#, c-format
+msgid "E572: exit code %d"
+msgstr "E572: Á¾·á ÄÚµå %d"
+
+msgid "cannot get line"
+msgstr "ÁÙÀ» ¾òÀ» ¼ö ¾ø½À´Ï´Ù"
+
+msgid "Unable to register a command server name"
+msgstr "¸í·É ¼­¹ö À̸§À» µî·ÏÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E248: Failed to send command to the destination program"
+msgstr "E248: ´ë»óÇÁ·Î±×·¥À¸·Î ¸í·É º¸³»±â°¡ ½ÇÆÐÇß½À´Ï´Ù"
+
+#, c-format
+msgid "E573: Invalid server id used: %s"
+msgstr "E573: À߸øµÈ ¼­¹ö id »ç¿ëµÊ: %s"
+
+msgid "E251: VIM instance registry property is badly formed. Deleted!"
+msgstr "E251: ºö ÀνºÅϽº ·¹Áö½ºÆ®¸® ¼Ó¼ºÀÌ À߸øµÇ¾î ÀÖ½À´Ï´Ù. Áö¿ü½À´Ï´Ù!"
+
+#, c-format
+msgid "E938: Duplicate key in JSON: \"%s\""
+msgstr "E938: JSON¿¡ Áߺ¹µÈ Å°: \"%s\""
+
+#, c-format
+msgid "E696: Missing comma in List: %s"
+msgstr "E696: List¿¡ ÄÞ¸¶ ´©¶ô: %s"
+
+#, c-format
+msgid "E697: Missing end of List ']': %s"
+msgstr "E697: List ³¡¿¡ ']' ´©¶ô: %s"
+
+msgid "Unknown option argument"
+msgstr "¸ð¸£´Â ¿É¼Ç ÀÎÀÚ"
+
+msgid "Too many edit arguments"
+msgstr "³Ê¹« ¸¹Àº ÆíÁý ÀÎÀÚ"
+
+msgid "Argument missing after"
+msgstr "µÚ¿¡ ÀÎÀÚ°¡ ¾øÀ½"
+
+msgid "Garbage after option argument"
+msgstr "¿É¼Ç ÀÎÀÚ µÚ¿¡ ¾²·¹±â °ª"
+
+msgid "Too many \"+command\", \"-c command\" or \"--cmd command\" arguments"
+msgstr "³Ê¹« ¸¹Àº \"+command\" \"-c command\" ȤÀº \"--cmd command\" ÀÎÀÚ"
+
+msgid "Invalid argument for"
+msgstr "Invalid argument for"
+
+#, c-format
+msgid "%d files to edit\n"
+msgstr "%d ÆÄÀÏÀ» °íÄ¡±â\n"
+
+msgid "netbeans is not supported with this GUI\n"
+msgstr "ÀÌ GUI´Â netbeans¸¦ Áö¿øÇÏÁö ¾Ê½À´Ï´Ù\n"
+
+msgid "'-nb' cannot be used: not enabled at compile time\n"
+msgstr "'-nb'´Â »ç¿ëÇÒ ¼ö ¾øÀ½: ÄÄÆÄÀÏÇÒ ¶§ Æ÷ÇÔµÇÁö ¾ÊÀ½\n"
+
+msgid "This Vim was not compiled with the diff feature."
+msgstr "ÀÌ ºöÀº diff ±â´É ¾øÀÌ ÄÄÆÄÀÏ µÇ¾ú½À´Ï´Ù."
+
+msgid "Attempt to open script file again: \""
+msgstr "½ºÅ©¸³Æ® ÆÄÀÏÀ» ´Ù½Ã ¿­·Á°í ½Ãµµ: \""
+
+msgid "Cannot open for reading: \""
+msgstr "Àбâ À§ÇØ ¿­ ¼ö ¾øÀ½: \""
+
+msgid "Cannot open for script output: \""
+msgstr "½ºÅ©¸³Æ® Ãâ·ÂÀ» ¿­ ¼ö ¾øÀ½: \""
+
+msgid "Vim: Error: Failure to start gvim from NetBeans\n"
+msgstr "Vim: ¿¡·¯: NetBeans¿¡¼­ gvim ½ÃÀÛ ½ÇÆÐ\n"
+
+msgid "Vim: Error: This version of Vim does not run in a Cygwin terminal\n"
+msgstr "Vim: ¿¡·¯: ÀÌ ¹öÁ¯ÀÇ ºöÀº Cygwin Å͹̳ο¡¼­ ½ÇÇàÇÒ ¼ö ¾ø½À´Ï´Ù\n"
+
+msgid "Vim: Warning: Output is not to a terminal\n"
+msgstr "ºö: °æ°í: Å͹̳ηΠÃâ·ÂÇÒ ¼ö ¾ø½À´Ï´Ù\n"
+
+msgid "Vim: Warning: Input is not from a terminal\n"
+msgstr "ºö: °æ°í: Å͹̳ηΠºÎÅÍ ÀԷ¹ÞÀ» ¼ö ¾ø½À´Ï´Ù\n"
+
+msgid "pre-vimrc command line"
+msgstr "pre-vimrc ¸í·É Çà"
+
+#, c-format
+msgid "E282: Cannot read from \"%s\""
+msgstr "E282: \"%s\"¿¡¼­ ÀÐÀ» ¼ö ¾ø½À´Ï´Ù"
+
+msgid ""
+"\n"
+"More info with: \"vim -h\"\n"
+msgstr ""
+"\n"
+"´õ ¸¹Àº Á¤º¸¸¦ ¿øÇϽøé: \"vim -h\"\n"
+
+msgid "[file ..] edit specified file(s)"
+msgstr "[ÆÄÀÏ ..] ÁÖ¾îÁø ÆÄÀÏ °íÄ¡±â"
+
+msgid "- read text from stdin"
+msgstr "- Ç¥ÁØÀԷ¿¡¼­ ÅؽºÆ® Àбâ"
+
+msgid "-t tag edit file where tag is defined"
+msgstr "-t tag űװ¡ Á¤ÀÇµÈ À§Ä¡¿¡¼­ ÆÄÀÏ °íÄ¡±â"
+
+msgid "-q [errorfile] edit file with first error"
+msgstr "-q [¿¡·¯ÆÄÀÏ] ù ¹ø° ¿¡·¯°¡ ³­ ÆÄÀÏ °íÄ¡±â"
+
+msgid ""
+"\n"
+"\n"
+"Usage:"
+msgstr ""
+"\n"
+"\n"
+"»ç¿ë¹ý:"
+
+msgid " vim [arguments] "
+msgstr " vim [ÀÎÀÚ] "
+
+msgid ""
+"\n"
+" or:"
+msgstr ""
+"\n"
+" ȤÀº:"
+
+#~ msgid ""
+#~ "\n"
+#~ "Where case is ignored prepend / to make flag upper case"
+#~ msgstr ""
+
+msgid ""
+"\n"
+"\n"
+"Arguments:\n"
+msgstr ""
+"\n"
+"\n"
+"ÀÎÀÚ:\n"
+
+msgid "--\t\t\tOnly file names after this"
+msgstr "--\t\t\tÀÌ µÚ¿¡´Â ÆÄÀÏ À̸§¸¸"
+
+msgid "--literal\t\tDon't expand wildcards"
+msgstr "--literal\t\t¿ÍÀϵåÄ«µå¸¦ È®ÀåÇÏÁö ¾ÊÀ½"
+
+msgid "-register\t\tRegister this gvim for OLE"
+msgstr "-register\t\tÀÌ gvim OLE¿¡ µî·Ï"
+
+msgid "-unregister\t\tUnregister gvim for OLE"
+msgstr "-unregister\t\tgvimÀ» OLE¿¡¼­ µî·ÏÃë¼Ò"
+
+msgid "-g\t\t\tRun using GUI (like \"gvim\")"
+msgstr "-g\t\t\tGUI·Î ½ÇÇà (\"gvim\"°ú °°À½)"
+
+msgid "-f or --nofork\tForeground: Don't fork when starting GUI"
+msgstr "-f ȤÀº --nofork\tÆ÷±×¶ó¿îµå: GUI·Î ½ÃÀÛÇÒ ¶§ forkÇÏÁö ¸» °Í"
+
+msgid "-v\t\t\tVi mode (like \"vi\")"
+msgstr "-v\t\t\tVi ¸ðµå (\"vi\"¿Í °°À½)"
+
+msgid "-e\t\t\tEx mode (like \"ex\")"
+msgstr "-e\t\t\tEx ¸ðµå (\"ex\"¿Í °°À½)"
+
+msgid "-E\t\t\tImproved Ex mode"
+msgstr "-E\t\t\tÇâ»óµÈ Ex ¸ðµå"
+
+msgid "-s\t\t\tSilent (batch) mode (only for \"ex\")"
+msgstr "-s\t\t\tÁ¶¿ëÇÑ (¹èÄ¡) ¸ðµå (\"ex\"¸¸)"
+
+msgid "-d\t\t\tDiff mode (like \"vimdiff\")"
+msgstr "-d\t\t\tDiff ¸ðµå (\"vimdiff\"¿Í °°À½)"
+
+msgid "-y\t\t\tEasy mode (like \"evim\", modeless)"
+msgstr "-y\t\t\t½¬¿î ¸ðµå (\"evim\"°ú °°À½, modeless)"
+
+msgid "-R\t\t\tReadonly mode (like \"view\")"
+msgstr "-R\t\t\tÀбâ Àü¿ë ¸ðµå (\"view\"¿Í °°À½)"
+
+msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
+msgstr "-Z\t\t\tÁ¦ÇÑµÈ ¸ðµå (\"rvim\"°ú °°À½)"
+
+msgid "-m\t\t\tModifications (writing files) not allowed"
+msgstr "-m\t\t\t¼öÁ¤(ÆÄÀÏ ¾²±â)ÀÌ Çã¿ëµÇÁö ¾ÊÀ½"
+
+msgid "-M\t\t\tModifications in text not allowed"
+msgstr "-M\t\t\tÅؽºÆ® ¼öÁ¤ÀÌ Çã¿ëµÇÁö ¾ÊÀ½"
+
+msgid "-b\t\t\tBinary mode"
+msgstr "-b\t\t\tÀÌÁø »óÅÂ"
+
+msgid "-l\t\t\tLisp mode"
+msgstr "-l\t\t\t¸®½ºÇÁ »óÅÂ"
+
+msgid "-C\t\t\tCompatible with Vi: 'compatible'"
+msgstr "-C\t\t\tVi ȣȯ: 'compatible'"
+
+msgid "-N\t\t\tNot fully Vi compatible: 'nocompatible'"
+msgstr "-N\t\t\tVi¿Í ȣȯµÇÁö ¾ÊÀ½: 'nocompatible'"
+
+msgid "-V[N][fname]\t\tBe verbose [level N] [log messages to fname]"
+msgstr "-V[N][fname]\t\tBe verbose [level N] [fname¿¡ ¸Þ½ÃÁö ÀúÀå]"
+
+msgid "-D\t\t\tDebugging mode"
+msgstr "-D\t\t\tµð¹ö±ë ¸ðµå"
+
+msgid "-n\t\t\tNo swap file, use memory only"
+msgstr "-n\t\t\t½º¿Ò ÆÄÀÏ ¾øÀÌ ¸Þ¸ð¸®¸¸ »ç¿ë"
+
+msgid "-r\t\t\tList swap files and exit"
+msgstr "-r\t\t\t½º¿Ò ÆÄÀÏ ¸ñ·ÏÀ» Ç¥½ÃÇÑ µÚ ³¡³»±â"
+
+msgid "-r (with file name)\tRecover crashed session"
+msgstr "-r (ÆÄÀÏ À̸§°ú ÇÔ²²)\tÆļյǾú´ø ¼¼¼Ç º¹±¸"
+
+msgid "-L\t\t\tSame as -r"
+msgstr "-L\t\t\t-r°ú °°À½"
+
+msgid "-f\t\t\tDon't use newcli to open window"
+msgstr "-f\t\t\tâÀ» ¿­ ¶§ newcli »ç¿ëÇÏÁö ¾ÊÀ½"
+
+msgid "-dev <device>\t\tUse <device> for I/O"
+msgstr "-dev <ÀåÄ¡>\t\tI/O¿¡ <ÀåÄ¡> »ç¿ë"
+
+msgid "-A\t\t\tStart in Arabic mode"
+msgstr "-A\t\t\tArabic ¸ðµå·Î ½ÃÀÛ"
+
+msgid "-H\t\t\tStart in Hebrew mode"
+msgstr "-H\t\t\tHebrew ¸ðµå·Î ½ÃÀÛ"
+
+msgid "-F\t\t\tStart in Farsi mode"
+msgstr "-F\t\t\tFarsi ¸ðµå·Î ½ÃÀÛ"
+
+msgid "-T <terminal>\tSet terminal type to <terminal>"
+msgstr "-T <terminal>\tÅ͹̳ΠÁ¾·ù¸¦ <terminal>·Î ¼³Á¤"
+
+msgid "--not-a-term\t\tSkip warning for input/output not being a terminal"
+msgstr "--not-a-term\t\tÅ͹̳ο¡ ÀÔÃâ·ÂÇÒ ¼ö ¾ø´Ù´Â °æ°íÇÏÁö ¾ÊÀ½"
+
+msgid "--ttyfail\t\tExit if input or output is not a terminal"
+msgstr "--ttyfail\t\tÅ͹̳ο¡ ÀÔÃâ·ÂÇÒ ¼ö ¾ø´Â °æ¿ì Á¾·á"
+
+msgid "-u <vimrc>\t\tUse <vimrc> instead of any .vimrc"
+msgstr "-u <vimrc>\t\t.vimrc ´ë½Å <vimrc>¸¦ »ç¿ë"
+
+msgid "-U <gvimrc>\t\tUse <gvimrc> instead of any .gvimrc"
+msgstr "-U <gvimrc>\t\t.gvimrc ´ë½Å <gvimrc>¸¦ »ç¿ë"
+
+msgid "--noplugin\t\tDon't load plugin scripts"
+msgstr "--noplugin\t\tÇ÷¯±×ÀÎ ½ºÅ©¸³Æ®¸¦ ºÒ·¯µéÀÌÁö ¾ÊÀ½"
+
+msgid "-p[N]\t\tOpen N tab pages (default: one for each file)"
+msgstr "-p[N]\t\tN°³ÀÇ ÅÇ ¿­±â (±âº»: ÆÄÀϺ°·Î Çϳª)"
+
+msgid "-o[N]\t\tOpen N windows (default: one for each file)"
+msgstr "-o[N]\t\tN°³ÀÇ Ã¢ ¿­±â (±âº»: ÆÄÀϺ°·Î Çϳª)"
+
+msgid "-O[N]\t\tLike -o but split vertically"
+msgstr "-O[N]\t\t-o¿Í °°Áö¸¸ âÀ» ¼öÁ÷À¸·Î ³ª´©±â"
+
+msgid "+\t\t\tStart at end of file"
+msgstr "+\t\t\tÆÄÀÏ ¸¶Áö¸·¿¡¼­ ½ÃÀÛ"
+
+msgid "+<lnum>\t\tStart at line <lnum>"
+msgstr "+<lnum>\t\t<lnum> ÁÙ¿¡¼­ ½ÃÀÛ"
+
+msgid "--cmd <command>\tExecute <command> before loading any vimrc file"
+msgstr "--cmd <¸í·É>\tvimrc ÆÄÀÏÀ» Àбâ Àü¿¡ <¸í·É>À» ½ÇÇà"
+
+msgid "-c <command>\t\tExecute <command> after loading the first file"
+msgstr "-c <¸í·É>\t\tù° ÆÄÀÏÀ» ÀÐÀº µÚ <¸í·É>À» ½ÇÇà"
+
+msgid "-S <session>\t\tSource file <session> after loading the first file"
+msgstr "-S <¼¼¼Ç>\t\tù° ÆÄÀÏÀ» ÀÐÀº µÚ <¼¼¼Ç> ÆÄÀÏ ºÒ·¯ µéÀ̱â"
+
+msgid "-s <scriptin>\tRead Normal mode commands from file <scriptin>"
+msgstr "-s <scriptin>\t<scriptin> ÆÄÀÏ¿¡¼­ Normal »óÅ ¸í·É Àбâ"
+
+msgid "-w <scriptout>\tAppend all typed commands to file <scriptout>"
+msgstr "-w <scriptout>\t¸ðµç ÀÔ·ÂµÈ ¸í·ÉÀ» <scriptout> ÆÄÀÏ¿¡ Ãß°¡"
+
+msgid "-W <scriptout>\tWrite all typed commands to file <scriptout>"
+msgstr "-W <scriptout>\t¸ðµç ÀÔ·ÂµÈ ¸í·ÉÀ» <scriptout> ÆÄÀÏ¿¡ ÀúÀå"
+
+msgid "-x\t\t\tEdit encrypted files"
+msgstr "-x\t\t\t¾ÏȣȭµÈ ÆÄÀÏ °íÄ¡±â"
+
+msgid "-display <display>\tConnect vim to this particular X-server"
+msgstr "-display <display>\tºöÀ» ƯÁ¤ X-¼­¹ö¿Í ¿¬°á"
+
+msgid "-X\t\t\tDo not connect to X server"
+msgstr "-X\t\t\tX ¼­¹ö¿¡ ¿¬°áÇÏÁö ¾ÊÀ½"
+
+msgid "--remote <files>\tEdit <files> in a Vim server if possible"
+msgstr "--remote <files>\t°¡´ÉÇÏ¸é ºö ¼­¹ö¿¡¼­ <files> ÆíÁý"
+
+msgid "--remote-silent <files> Same, don't complain if there is no server"
+msgstr "--remote-silent <files> °°À½, ¼­¹ö°¡ ¾ø´Ù°í ºÒÆòÇÏÁö ¾ÊÀ½"
+
+msgid ""
+"--remote-wait <files> As --remote but wait for files to have been edited"
+msgstr "--remote-wait <files> --remote¿Í °°Áö¸¸ ´Ù °íÄ¥ ¶§±îÁö ±â´Ù¸³´Ï´Ù"
+
+msgid ""
+"--remote-wait-silent <files> Same, don't complain if there is no server"
+msgstr "--remote-wait-silent <files> °°À½, ¼­¹ö°¡ ¾ø´Ù°í ºÒÆòÇÏÁö ¾ÊÀ½"
+
+msgid ""
+"--remote-tab[-wait][-silent] <files> As --remote but use tab page per file"
+msgstr ""
+"--remote-tab[-wait][-silent] <files> --remote¿Í °°Áö¸¸ ÆÄÀϺ°·Î ÅÇ ÆäÀÌÁö »ç"
+"¿ë"
+
+msgid "--remote-send <keys>\tSend <keys> to a Vim server and exit"
+msgstr "--remote-send <keys>\tºö ¼­¹ö·Î <keys>¸¦ º¸³»°í ³¡³»±â"
+
+msgid "--remote-expr <expr>\tEvaluate <expr> in a Vim server and print result"
+msgstr "--remote-expr <expr>\tºö ¼­¹ö¿¡¼­ <expr> ½ÇÇàÇÏ°í °á°ú Ãâ·Â"
+
+msgid "--serverlist\t\tList available Vim server names and exit"
+msgstr "--serverlist\t\t»ç¿ë °¡´ÉÇÑ ºö ¼­¹ö À̸§À» Ç¥½ÃÇÏ°í ³¡³»±â"
+
+msgid "--servername <name>\tSend to/become the Vim server <name>"
+msgstr "--servername <name>\tºö ¼­¹ö <name>ÀÌ µÇ°Å³ª ¼­¹ö·Î º¸³»±â"
+
+msgid "--startuptime <file>\tWrite startup timing messages to <file>"
+msgstr "--startuptime <file>\tstartup timing ¸Þ½ÃÁö¸¦ <file>¿¡ ÀúÀå"
+
+msgid "-i <viminfo>\t\tUse <viminfo> instead of .viminfo"
+msgstr "-i <viminfo>\t\t.viminfo ´ë½Å <viminfo>¸¦ »ç¿ë"
+
+#~ msgid "--clean\t\t'nocompatible', Vim defaults, no plugins, no viminfo"
+#~ msgstr ""
+
+msgid "-h or --help\tPrint Help (this message) and exit"
+msgstr "-h ȤÀº --help\tµµ¿ò¸»(ÀÌ ¸Þ½ÃÁö)À» Ãâ·ÂÇÑ µÚ ³¡³»±â"
+
+msgid "--version\t\tPrint version information and exit"
+msgstr "--version\t\tÆÇ Á¤º¸¸¦ Ãâ·ÂÇÑ µÚ ³¡³»±â"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Motif version):\n"
+msgstr ""
+"\n"
+"gvimÀÌ ¾Ë°í ÀÖ´Â ÀÎÀÚ (¸ðƼÇÁ ÆÇ):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (neXtaw version):\n"
+msgstr ""
+"\n"
+"gvimÀÌ ¾Ë°í ÀÖ´Â ÀÎÀÚ (neXtaw ÆÇ):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Athena version):\n"
+msgstr ""
+"\n"
+"gvimÀÌ ¾Ë°í ÀÖ´Â ÀÎÀÚ (¾ÆÅ׳ª ÆÇ):\n"
+
+msgid "-display <display>\tRun vim on <display>"
+msgstr "-display <display>\tºöÀ» <display>¿¡¼­ ½ÇÇà"
+
+msgid "-iconic\t\tStart vim iconified"
+msgstr "-iconic\t\t¾ÆÀÌÄÜ »óÅ·Πºö ½ÃÀÛ"
+
+msgid "-background <color>\tUse <color> for the background (also: -bg)"
+msgstr "-background <color>\t¹ÙÅÁ »öÀ¸·Î <color> »ç¿ë (also: -bg)"
+
+msgid "-foreground <color>\tUse <color> for normal text (also: -fg)"
+msgstr "-foreground <color>\tÀÏ¹Ý »ö¿¡ <color> »ç¿ë (also: -fg)"
+
+msgid "-font <font>\t\tUse <font> for normal text (also: -fn)"
+msgstr "-font <font>\t\tÀÏ¹Ý ÅؽºÆ®¿¡ <font> »ç¿ë (also: -fn)"
+
+msgid "-boldfont <font>\tUse <font> for bold text"
+msgstr "-boldfont <font>\t±½Àº ÅؽºÆ®¿¡ <font> »ç¿ë"
+
+msgid "-italicfont <font>\tUse <font> for italic text"
+msgstr "-italicfont <font>\t±â¿ïÀÓ ÅؽºÆ®¿¡ <font> »ç¿ë"
+
+msgid "-geometry <geom>\tUse <geom> for initial geometry (also: -geom)"
+msgstr "-geometry <geom>\tÃʱâ Áö¿À¹ÌÆ®¸®¿¡ <geom> »ç¿ë (also: -geom)"
+
+msgid "-borderwidth <width>\tUse a border width of <width> (also: -bw)"
+msgstr "-borderwidth <width>\t°¡ÀåÀÚ¸® ³ÐÀÌ¿¡ <width> »ç¿ë (also: -bw)"
+
+msgid "-scrollbarwidth <width> Use a scrollbar width of <width> (also: -sw)"
+msgstr "-scrollbarwidth <width> ½ºÅ©·Ñ¹Ù ³ÐÀÌ¿¡ <width> »ç¿ë (also: -sw)"
+
+msgid "-menuheight <height>\tUse a menu bar height of <height> (also: -mh)"
+msgstr "-menuheight <height>\t¸Þ´º¹Ù ³ôÀÌ¿¡ <height> »ç¿ë (also: -mh)"
+
+msgid "-reverse\t\tUse reverse video (also: -rv)"
+msgstr "-reverse\t\t¹ÝÀü ºñµð¿À »ç¿ë (also: -rv)"
+
+msgid "+reverse\t\tDon't use reverse video (also: +rv)"
+msgstr "+reverse\t\t¹ÝÀü ºñµð¿À »ç¿ë ¾È ÇÔ (also: +rv)"
+
+msgid "-xrm <resource>\tSet the specified resource"
+msgstr "-xrm <resource>\t¸í½ÃµÈ ¸®¼Ò½º ¼³Á¤"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (GTK+ version):\n"
+msgstr ""
+"\n"
+"gvimÀÌ ¾Ë°íÀÖ´Â ÀÎÀÚ (GTK+ ÆÇ):\n"
+
+msgid "-display <display>\tRun vim on <display> (also: --display)"
+msgstr "-display <display>\tºöÀ» <display>¿¡¼­ ½ÇÇà (also: --display)"
+
+msgid "--role <role>\tSet a unique role to identify the main window"
+msgstr "--role <role>\t¸ÞÀΠâ ±¸ºÐÀ» À§ÇØ À¯ÀÏÇÑ ¿ªÇÒ ¼³Á¤"
+
+msgid "--socketid <xid>\tOpen Vim inside another GTK widget"
+msgstr "--socketid <xid>\tºöÀ» ´Ù¸¥ GTK À§Á¬ ¾È¿¡¼­ ¿­À½"
+
+msgid "--echo-wid\t\tMake gvim echo the Window ID on stdout"
+msgstr "--echo-wid\t\tÇ¥ÁØÃâ·Â¿¡ gvimÀÇ Window ID¸¦ Ç¥½Ã"
+
+msgid "-P <parent title>\tOpen Vim inside parent application"
+msgstr "-P <parent title>\tVimÀ» ºÎ¸ð ÀÀ¿ë ÇÁ·Î±×·¥ ³»¿¡¼­ ¿­±â"
+
+msgid "--windowid <HWND>\tOpen Vim inside another win32 widget"
+msgstr "--windowid <HWND>\t´Ù¸¥ win32 À§Á¬ ¾È¿¡¼­ Vim ¿­±â"
+
+msgid "No display"
+msgstr "µð½ºÇ÷¹ÀÌ°¡ ¾ø½À´Ï´Ù"
+
+msgid ": Send failed.\n"
+msgstr ": º¸³»±â°¡ ½ÇÆÐÇÏ¿´½À´Ï´Ù.\n"
+
+msgid ": Send failed. Trying to execute locally\n"
+msgstr ": º¸³»±â ½ÇÆÐ. ·ÎÄÿ¡¼­ ½ÇÇàµË´Ï´Ù\n"
+
+#, c-format
+#~ msgid "%d of %d edited"
+#~ msgstr ""
+
+msgid "No display: Send expression failed.\n"
+msgstr "µð½ºÇ÷¹ÀÌ ¾øÀ½: Ç¥Çö½Ä º¸³»±â°¡ ½ÇÆÐÇß½À´Ï´Ù.\n"
+
+msgid ": Send expression failed.\n"
+msgstr ": Ç¥Çö½Ä º¸³»±â°¡ ½ÇÆÐÇß½À´Ï´Ù.\n"
+
+msgid "No marks set"
+msgstr "¼³Á¤µÈ ¸¶Å©°¡ ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "E283: No marks matching \"%s\""
+msgstr "E283: \"%s\"¿¡ ¸Â´Â ¸¶Å©°¡ ¾ø½À´Ï´Ù"
+
+msgid ""
+"\n"
+"mark line col file/text"
+msgstr ""
+"\n"
+"¸¶Å© ¶óÀÎ col ÆÄÀÏ/ÅؽºÆ®"
+
+msgid ""
+"\n"
+" jump line col file/text"
+msgstr ""
+"\n"
+" Á¡ÇÁ ¶óÀÎ col ÆÄÀÏ/ÅؽºÆ®"
+
+#~ msgid ""
+#~ "\n"
+#~ "change line col text"
+#~ msgstr ""
+
+msgid ""
+"\n"
+"# File marks:\n"
+msgstr ""
+"\n"
+"# ÆÄÀÏ ¸¶Å©:\n"
+
+msgid ""
+"\n"
+"# Jumplist (newest first):\n"
+msgstr ""
+"\n"
+"# Á¡ÇÁ¸ñ·Ï (»õ°ÍÀÌ ¸ÕÀú):\n"
+
+msgid ""
+"\n"
+"# History of marks within files (newest to oldest):\n"
+msgstr ""
+"\n"
+"# ÆÄÀϳ»ÀÇ ¸¶Å© È÷½ºÅ丮 (»õ°ÍºÎÅÍ ¿À·¡µÈ ¼ø):\n"
+
+msgid "Missing '>'"
+msgstr "'>'ÀÌ ¾ø½À´Ï´Ù"
+
+msgid "E543: Not a valid codepage"
+msgstr "E543: Á¤»óÀûÀÎ ÄÚµåÆäÀÌÁö°¡ ¾Æ´Õ´Ï´Ù"
+
+msgid "E284: Cannot set IC values"
+msgstr "E284: IC °ªÀ» ¼³Á¤ÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E285: Failed to create input context"
+msgstr "E285: ÀÔ·Â ÄÜÅؽºÆ®¸¦ ¸¸µé ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E286: Failed to open input method"
+msgstr "E286: ÀÔ·Â ¹æ½ÄÀ» ¿­´Ù°¡ ½ÇÆÐÇß½À´Ï´Ù"
+
+msgid "E287: Warning: Could not set destroy callback to IM"
+msgstr "E287: °æ°í: IM¿¡ Æı« ÄݹéÀ» ¼³Á¤ÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E288: input method doesn't support any style"
+msgstr "E288: ÀÔ·Â ¹æ½ÄÀÌ ¾î¶² Çü½Äµµ Áö¿øÇÏÁö ¾Ê½À´Ï´Ù"
+
+msgid "E289: input method doesn't support my preedit type"
+msgstr "E289: ÀÔ·Â ¹æ½ÄÀÌ ³» preedit Çü½ÄÀ» Áö¿øÇÏÁö ¾Ê½À´Ï´Ù"
+
+msgid "E293: block was not locked"
+msgstr "E293: ±¸¿ªÀÌ Àá±ÅÁöÁö ¾Ê¾Ò½À´Ï´Ù"
+
+msgid "E294: Seek error in swap file read"
+msgstr "E294: ½º¿Ò ÆÄÀÏÀ» Àбâ À§ÇØ Æ¯Á¤ À§Ä¡·Î °¥ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E295: Read error in swap file"
+msgstr "E295: ½º¿Ò ÆÄÀÏÀ» ÀÐÀ» ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E296: Seek error in swap file write"
+msgstr "E296: ½º¿Ò ÆÄÀÏÀ» ¾²±â À§ÇØ Æ¯Á¤ À§Ä¡·Î °¥ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E297: Write error in swap file"
+msgstr "E297: ½º¿Ò ÆÄÀÏÀ» ¾µ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E300: Swap file already exists (symlink attack?)"
+msgstr "E300: ½º¿Ò ÆÄÀÏÀÌ ÀÌ¹Ì Á¸ÀçÇÕ´Ï´Ù (symlink °ø°Ý?)"
+
+msgid "E298: Didn't get block nr 0?"
+msgstr "E298: ±¸¿ª ¹øÈ£ 0À» ¾òÁö ¸øÇß³ª¿ä?"
+
+msgid "E298: Didn't get block nr 1?"
+msgstr "E298: ±¸¿ª ¹øÈ£ 1À» ¾òÁö ¸øÇß³ª¿ä?"
+
+msgid "E298: Didn't get block nr 2?"
+msgstr "E298: ±¸¿ª ¹øÈ£ 2¸¦ ¾òÁö ¸øÇß³ª¿ä?"
+
+msgid "E843: Error while updating swap file crypt"
+msgstr "E843: ½º¿Ò ÆÄÀÏÀ» ¾ÏȣȭÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E301: Oops, lost the swap file!!!"
+msgstr "E301: À¸À¹, ½º¿Ò ÆÄÀÏÀ» ÀÒ¾î¹ö·È½À´Ï´Ù!!!"
+
+msgid "E302: Could not rename swap file"
+msgstr "E302: ½º¿Ò ÆÄÀÏ À̸§À» ¹Ù²Ü ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "E303: Unable to open swap file for \"%s\", recovery impossible"
+msgstr "E303: \"%s\"ÀÇ ½º¿Ò ÆÄÀÏÀ» ¿­ ¼ö ¾ø¾î¼­ º¹±¸´Â ºÒ°¡´ÉÇÕ´Ï´Ù"
+
+msgid "E304: ml_upd_block0(): Didn't get block 0??"
+msgstr "E304: ml_upd_block0(): ±¸¿ª 0À» ¾òÁö ¸øÇß³ª¿ä??"
+
+#, c-format
+msgid "E305: No swap file found for %s"
+msgstr "E305: %sÀÇ ½º¿Ò ÆÄÀÏÀ» ãÀ» ¼ö ¾ø½À´Ï´Ù"
+
+msgid "Enter number of swap file to use (0 to quit): "
+msgstr "»ç¿ëÇÒ ½º¿Ò ÆÄÀÏ ¹øÈ£¸¦ ÀÔ·ÂÇϽʽÿÀ (0Àº ³¡³»±â): "
+
+#, c-format
+msgid "E306: Cannot open %s"
+msgstr "E306: %sÀ»(¸¦) ¿­ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "Unable to read block 0 from "
+msgstr "Unable to read block 0 from "
+
+msgid ""
+"\n"
+"Maybe no changes were made or Vim did not update the swap file."
+msgstr ""
+"\n"
+"¾î¶² ¼öÁ¤µµ ¾ø¾ú°Å³ª ºöÀÌ ½º¿Ò ÆÄÀÏÀ» °»½ÅÇÏÁö ¾ÊÀº °Í °°½À´Ï´Ù."
+
+msgid " cannot be used with this version of Vim.\n"
+msgstr " cannot be used with this version of Vim.\n"
+
+msgid "Use Vim version 3.0.\n"
+msgstr "ºö 3.0 ÆÇÀ» »ç¿ëÇϽʽÿÀ.\n"
+
+#, c-format
+msgid "E307: %s does not look like a Vim swap file"
+msgstr "E307: %sÀº(´Â) ºö ½º¿Ò ÆÄÀÏÀÌ ¾Æ´Ñ °Í °°½À´Ï´Ù"
+
+msgid " cannot be used on this computer.\n"
+msgstr " ÀÌ ÄÄÇ»ÅÍ¿¡¼­´Â »ç¿ëµÉ ¼ö ¾ø½À´Ï´Ù.\n"
+
+msgid "The file was created on "
+msgstr "The file was created on "
+
+msgid ""
+",\n"
+"or the file has been damaged."
+msgstr ""
+",\n"
+"or the file has been damaged."
+
+#, c-format
+msgid ""
+"E833: %s is encrypted and this version of Vim does not support encryption"
+msgstr "E833: %sÀÌ(°¡) ¾ÏȣȭµÇ¾î ÀÖ´Â µ¥, ÀÌ VimÀº ¾Ïȣȭ¸¦ Áö¿øÇÏÁö ¾Ê½À´Ï´Ù"
+
+msgid " has been damaged (page size is smaller than minimum value).\n"
+msgstr " has been damaged (page size is smaller than minimum value).\n"
+
+#, c-format
+msgid "Using swap file \"%s\""
+msgstr "½º¿Ò ÆÄÀÏ \"%s\"À»(¸¦) »ç¿ëÇÕ´Ï´Ù"
+
+#, c-format
+msgid "Original file \"%s\""
+msgstr "¿ø·¡ ÆÄÀÏ \"%s\""
+
+msgid "E308: Warning: Original file may have been changed"
+msgstr "E308: °æ°í: ¿ø·¡ ÆÄÀÏÀÌ ¹Ù²î¾ú½À´Ï´Ù"
+
+#, c-format
+msgid "Swap file is encrypted: \"%s\""
+msgstr "½º¿Ò ÆÄÀÏÀÌ ¾ÏȣȭµÊ: \"%s\""
+
+msgid ""
+"\n"
+"If you entered a new crypt key but did not write the text file,"
+msgstr ""
+"\n"
+"»õ·Î¿î ¾ÏÈ£ Å°¸¦ ÀÔ·ÂÇß´Â µ¥, ÆÄÀÏÀ» ÀúÀåÇÏÁö ¾Ê¾Ò¾ú´Ù¸é,"
+
+msgid ""
+"\n"
+"enter the new crypt key."
+msgstr ""
+"\n"
+"»õ·Î¿î ¾ÏÈ£ Å°¸¦ ÀÔ·ÂÇϼ¼¿ä."
+
+msgid ""
+"\n"
+"If you wrote the text file after changing the crypt key press enter"
+msgstr ""
+"\n"
+"¾ÏÈ£ Å°¸¦ ¹Ù²Û ÈÄ¿¡ ÆÄÀÏÀ» ÀúÀåÇß¾ú´Ù¸é °°Àº Å°·Î ÅؽºÆ® ÆÄÀÏ°ú"
+
+msgid ""
+"\n"
+"to use the same key for text file and swap file"
+msgstr ""
+"\n"
+"½º¿ÒÆÄÀÏÀ» ÀúÀåÇÏ·Á¸é ¿£Å͸¦ ´©¸£¼¼¿ä"
+
+#, c-format
+msgid "E309: Unable to read block 1 from %s"
+msgstr "E309: %sÀÇ ±¸¿ª 1À» ÀÐÀ» ¼ö ¾ø½À´Ï´Ù"
+
+msgid "???MANY LINES MISSING"
+msgstr "???¸¹Àº ÁÙÀ» ÀÒ¾î¹ö¸²"
+
+msgid "???LINE COUNT WRONG"
+msgstr "???ÁÙ ¹øÈ£°¡ À߸øµÇ¾ú½À´Ï´Ù"
+
+msgid "???EMPTY BLOCK"
+msgstr "???ºó ±¸¿ª"
+
+msgid "???LINES MISSING"
+msgstr "???ÁÙÀ» ÀÒ¾î¹ö¸²"
+
+#, c-format
+msgid "E310: Block 1 ID wrong (%s not a .swp file?)"
+msgstr "E310: ±¸¿ª 1ÀÇ ID°¡ À߸øµÇ¾ú½À´Ï´Ù (%sÀÌ(°¡) .swp ÆÄÀÏÀÌ ¾Æ´Ñ°¡?)"
+
+msgid "???BLOCK MISSING"
+msgstr "???±¸¿ª ÀÒ¾î¹ö¸²"
+
+msgid "??? from here until ???END lines may be messed up"
+msgstr "??? ¿©±âºÎÅÍ ???³¡±îÁöÀÇ ÁÙÀÌ ¼¯¿´½À´Ï´Ù"
+
+msgid "??? from here until ???END lines may have been inserted/deleted"
+msgstr "??? ¿©±âºÎÅÍ ???³¡±îÁöÀÇ ÁÙÀÌ ³¢¿öÁö°Å³ª Áö¿öÁ® ¹ö¸° °Í °°½À´Ï´Ù"
+
+msgid "???END"
+msgstr "???³¡"
+
+msgid "E311: Recovery Interrupted"
+msgstr "E311: º¹±¸ ÁߴܵǾú½À´Ï´Ù"
+
+msgid ""
+"E312: Errors detected while recovering; look for lines starting with ???"
+msgstr "E312: º¹±¸ µµÁß ¿¡·¯ »ý°å½À´Ï´Ù; ???·Î ½ÃÀÛÇÏ´Â ÁÙÀ» ã¾Æº¸½Ê½Ã¿À"
+
+msgid "See \":help E312\" for more information."
+msgstr "´õ ¸¹Àº Á¤º¸¸¦ º¸·Á¸é \":help E312\"¸¦ ÀÔ·ÂÇϼ¼¿ä."
+
+msgid "Recovery completed. You should check if everything is OK."
+msgstr "º¹±¸°¡ ³¡³µ½À´Ï´Ù. ¸ðµç °Ô Á¤»óÀÎ Áö È®ÀÎÇØ º¸¼Å¾ß¸¸ ÇÕ´Ï´Ù."
+
+msgid ""
+"\n"
+"(You might want to write out this file under another name\n"
+msgstr ""
+"\n"
+"(¾î¼¸é ´Ù¸¥ À̸§À¸·Î ÀúÀåÇÏ°í ½ÍÀ¸½Ç Áöµµ ¸ð¸£°Ú½À´Ï´Ù\n"
+
+msgid "and run diff with the original file to check for changes)"
+msgstr "±×¸®°í ¹Ù²ï ³»¿ëÀ» È®ÀÎÇÏ·Á¸é ¿ø·¡ ÆÄÀÏ¿¡ ´ëÇØ diff¸¦ ½ÇÇàÇϼ¼¿ä)"
+
+msgid "Recovery completed. Buffer contents equals file contents."
+msgstr "º¹±¸°¡ ³¡³µ½À´Ï´Ù. ¹öÆÛÀÇ ³»¿ëÀÌ ÆÄÀÏ ³»¿ë°ú °°½À´Ï´Ù."
+
+msgid ""
+"\n"
+"You may want to delete the .swp file now.\n"
+"\n"
+msgstr ""
+"\n"
+"ÀÌÁ¦ .swp ÆÄÀÏÀ» Áö¿ì¼Åµµ µË´Ï´Ù.\n"
+"\n"
+
+msgid "Using crypt key from swap file for the text file.\n"
+msgstr "ÅؽºÆ® ÆÄÀÏ¿¡ ½º¿ÒÆÄÀÏ¿¡¼­ °¡Á®¿Â ¾ÏÈ£ Å°¸¦ »ç¿ëÇÕ´Ï´Ù.\n"
+
+msgid "Swap files found:"
+msgstr "½º¿Ò ÆÄÀÏÀ» ã¾ÒÀ½:"
+
+msgid " In current directory:\n"
+msgstr " ÇöÀç µð·ºÅ丮¿¡:\n"
+
+msgid " Using specified name:\n"
+msgstr " ¸í½ÃµÈ À̸§À» »ç¿ë:\n"
+
+msgid " In directory "
+msgstr " In directory "
+
+msgid " -- none --\n"
+msgstr " -- ¾øÀ½ --\n"
+
+msgid " owned by: "
+msgstr " ¼ÒÀ¯ÀÚ: "
+
+msgid " dated: "
+msgstr " ³¯Â¥: "
+
+msgid " dated: "
+msgstr " ³¯Â¥: "
+
+msgid " [from Vim version 3.0]"
+msgstr " [ºö 3.0 ÆÇÀÇ °Í]"
+
+msgid " [does not look like a Vim swap file]"
+msgstr " [ºö ½º¿Ò ÆÄÀÏ·Î º¸ÀÌÁö ¾Ê½À´Ï´Ù]"
+
+msgid " file name: "
+msgstr " ÆÄÀÏ À̸§: "
+
+msgid ""
+"\n"
+" modified: "
+msgstr ""
+"\n"
+" ¼öÁ¤: "
+
+msgid "YES"
+msgstr "¿¹"
+
+msgid "no"
+msgstr "¾Æ´Ï¿À"
+
+msgid ""
+"\n"
+" user name: "
+msgstr ""
+"\n"
+" »ç¿ëÀÚ À̸§: "
+
+msgid " host name: "
+msgstr " È£½ºÆ® À̸§: "
+
+msgid ""
+"\n"
+" host name: "
+msgstr ""
+"\n"
+" È£½ºÆ® À̸§: "
+
+msgid ""
+"\n"
+" process ID: "
+msgstr ""
+"\n"
+" ÇÁ·Î¼¼½º ID: "
+
+msgid " (still running)"
+msgstr " (¾ÆÁ÷ ½ÇÇàÁß)"
+
+msgid ""
+"\n"
+" [not usable with this version of Vim]"
+msgstr ""
+"\n"
+" [ºö À̹ø ÆÇ¿¡¼­´Â »ç¿ëÇÒ ¼ö ¾øÀ½]"
+
+msgid ""
+"\n"
+" [not usable on this computer]"
+msgstr ""
+"\n"
+" [ÀÌ ÄÄÇ»ÅÍ¿¡¼­´Â »ç¿ëÇÒ ¼ö ¾øÀ½]"
+
+msgid " [cannot be read]"
+msgstr " [ÀÐÀ» ¼ö ¾øÀ½]"
+
+msgid " [cannot be opened]"
+msgstr " [¿­ ¼ö ¾øÀ½]"
+
+msgid "E313: Cannot preserve, there is no swap file"
+msgstr "E313: º¸Á¸ÇÒ ¼ö ¾ø½À´Ï´Ù, ½º¿Ò ÆÄÀÏÀÌ ¾ø½À´Ï´Ù"
+
+msgid "File preserved"
+msgstr "ÆÄÀÏÀÌ º¸Á¸µÇ¾ú½À´Ï´Ù"
+
+msgid "E314: Preserve failed"
+msgstr "E314: ÆÄÀÏ º¸Á¸À» ½ÇÆÐÇß½À´Ï´Ù"
+
+#, c-format
+msgid "E315: ml_get: invalid lnum: %ld"
+msgstr "E315: ml_get: À߸øµÈ lnum: %ld"
+
+#, c-format
+msgid "E316: ml_get: cannot find line %ld"
+msgstr "E316: ml_get: %ld ÁÙÀ» ãÀ» ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E317: pointer block id wrong 3"
+msgstr "E317: À߸øµÈ Æ÷ÀÎÅÍ ±¸¿ª id 3"
+
+msgid "stack_idx should be 0"
+msgstr "stack_idx´Â 0¿©¾ß¸¸ ÇÕ´Ï´Ù"
+
+msgid "E318: Updated too many blocks?"
+msgstr "E318: ³Ê¹« ¸¹Àº ±¸¿ªÀÌ °»½ÅµÇ¾ú³ª¿ä?"
+
+msgid "E317: pointer block id wrong 4"
+msgstr "E317: À߸øµÈ Æ÷ÀÎÅÍ ±¸¿ª id 4"
+
+msgid "deleted block 1?"
+msgstr "±¸¿ª 1ÀÌ Áö¿öÁ³³ª¿ä?"
+
+#, c-format
+msgid "E320: Cannot find line %ld"
+msgstr "E320: %ld ÁÙÀ» ãÀ» ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E317: pointer block id wrong"
+msgstr "E317: À߸øµÈ Æ÷ÀÎÅÍ ±¸¿ª id"
+
+msgid "pe_line_count is zero"
+msgstr "pe_line_count°¡ 0ÀÔ´Ï´Ù"
+
+#, c-format
+msgid "E322: line number out of range: %ld past the end"
+msgstr "E322: ÁÙ ¹øÈ£°¡ ¹üÀ§¸¦ ¹þ¾î³µ½À´Ï´Ù: ¸¶Áö¸·¿¡¼­ %ld ¸¸Å­"
+
+#, c-format
+msgid "E323: line count wrong in block %ld"
+msgstr "E323: ±¸¿ª %ldÀÇ ÁÙ °¹¼ö°¡ Ʋ·È½À´Ï´Ù"
+
+msgid "Stack size increases"
+msgstr "½ºÅà ũ±â Áõ°¡"
+
+msgid "E317: pointer block id wrong 2"
+msgstr "E317: À߸øµÈ Æ÷ÀÎÅÍ ±¸¿ª id 2"
+
+#, c-format
+#~ msgid "E773: Symlink loop for \"%s\""
+#~ msgstr ""
+
+msgid "E325: ATTENTION"
+msgstr "E325: ÁÖ¸ñ"
+
+msgid ""
+"\n"
+"Found a swap file by the name \""
+msgstr ""
+"\n"
+"Found a swap file by the name \""
+
+msgid "While opening file \""
+msgstr "While opening file \""
+
+msgid " NEWER than swap file!\n"
+msgstr " NEWER than swap file!\n"
+
+msgid ""
+"\n"
+"(1) Another program may be editing the same file. If this is the case,\n"
+" be careful not to end up with two different instances of the same\n"
+" file when making changes. Quit, or continue with caution.\n"
+msgstr ""
+"\n"
+"(1) ´Ù¸¥ ÇÁ·Î±×·¥ÀÌ °°Àº ÆÄÀÏÀ» °íÄ¡°í ÀÖ´ÂÁßÀÏ ¼ö ÀÖ½À´Ï´Ù.\n"
+" ¸¸¾à ±×·¸´Ù¸é °°Àº ÆÄÀÏÀ» µÎ °³ÀÇ ÇÁ·Î±×·¥¿¡¼­ °íÄ¡Áö ¾Êµµ·Ï\n"
+" Á¶½ÉÇϽñ⠹ٶø´Ï´Ù. Á¾·áÇϼ¼¿ä. °è¼ÓÇϽ÷Á¸é ÁÖÀÇÇϼ¼¿ä.\n"
+
+msgid "(2) An edit session for this file crashed.\n"
+msgstr "(2) ÀÌ ÆÄÀÏÀ» °íÄ¡´Ù°¡ Á×¾ú¾ú½À´Ï´Ù.\n"
+
+msgid " If this is the case, use \":recover\" or \"vim -r "
+msgstr " ¸¸¾à ±×·¸´Ù¸é \":recover\" ȤÀº \"vim -r "
+
+msgid ""
+"\"\n"
+" to recover the changes (see \":help recovery\").\n"
+msgstr ""
+"\"\n"
+" À» »ç¿ëÇÏ¿© º¹±¸ÇϽʽÿÀ (\":help recovery\" Âü°í).\n"
+
+msgid " If you did this already, delete the swap file \""
+msgstr " ÀÌ¹Ì º¹±¸Çϼ̾ú´Ù¸é ½º¿ÒÆÄÀÏ \""
+
+msgid ""
+"\"\n"
+" to avoid this message.\n"
+msgstr ""
+"\"\n"
+" À»(¸¦) Áö¿ì¼Å¾ß ÀÌ ¸Þ½ÃÁö°¡ »ç¶óÁý´Ï´Ù.\n"
+
+msgid "Swap file \""
+msgstr "½º¿Ò ÆÄÀÏ \""
+
+msgid "\" already exists!"
+msgstr "\"ÀÌ ÀÌ¹Ì Á¸ÀçÇÕ´Ï´Ù!"
+
+msgid "VIM - ATTENTION"
+msgstr "ºö - ÁÖ¸ñ"
+
+msgid "Swap file already exists!"
+msgstr "½º¿Ò ÆÄÀÏÀÌ ÀÌ¹Ì Á¸ÀçÇÕ´Ï´Ù!"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"Àбâ Àü¿ëÀ¸·Î ¿­±â(&O)\n"
+"±×³É °íÄ¡±â(&E)\n"
+"º¹±¸(&R)\n"
+"³¡³»±â(&Q)\n"
+"¹ö¸®±â(&A)"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Delete it\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"Àбâ Àü¿ëÀ¸·Î ¿­±â(&O)\n"
+"¹«Á¶°Ç ÆíÁý(&E)\n"
+"º¹±¸(&R)\n"
+"»èÁ¦(&D)\n"
+"³¡³»±â(&Q)\n"
+"¹ö¸®±â(&A)"
+
+msgid "E326: Too many swap files found"
+msgstr "E326: ³Ê¹« ¸¹Àº ½º¿Ò ÆÄÀÏÀÌ ¹ß°ßµÇ¾ú½À´Ï´Ù"
+
+msgid "E327: Part of menu-item path is not sub-menu"
+msgstr "E327: ¸Þ´º Ç׸ñ °æ·ÎÀÇ ºÎºÐÀÌ ÇÏÀ§ ¸Þ´º°¡ ¾Æ´Õ´Ï´Ù"
+
+msgid "E328: Menu only exists in another mode"
+msgstr "E328: ¸Þ´º°¡ ´Ù¸¥ ¸ðµå¿¡¼­¸¸ Á¸ÀçÇÕ´Ï´Ù"
+
+#, c-format
+msgid "E329: No menu \"%s\""
+msgstr "E329: \"%s\" ¸Þ´º ¾øÀ½"
+
+msgid "E792: Empty menu name"
+msgstr "E792: ¸Þ´º À̸§ ¾øÀ½"
+
+msgid "E330: Menu path must not lead to a sub-menu"
+msgstr "E330: ÇÏÀ§ ¸Þ´º ¾Õ¿¡´Â ¸Þ´º °æ·Î°¡ ºÙÀ» ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E331: Must not add menu items directly to menu bar"
+msgstr "E331: ¸Þ´º¹Ù¿¡ °ð¹Ù·Î ¸Þ´º Ç׸ñÀ» ´õÇÒ ¼ö´Â ¾ø½À´Ï´Ù"
+
+msgid "E332: Separator cannot be part of a menu path"
+msgstr "E332: ±¸ºÐÀÚ´Â ¸Þ´º °æ·ÎÀÇ ºÎºÐÀÌ µÉ ¼ö ¾ø½À´Ï´Ù"
+
+msgid ""
+"\n"
+"--- Menus ---"
+msgstr ""
+"\n"
+"--- ¸Þ´º ---"
+
+msgid "Tear off this menu"
+msgstr "ÀÌ ¸Þ´º¸¦ ¶¼¾î³¿"
+
+#, c-format
+msgid "E335: Menu not defined for %s mode"
+msgstr "E335: %s ¸ðµå¿¡ ´ëÇÑ ¸Þ´º°¡ Á¤ÀǵǾî ÀÖÁö ¾Ê½À´Ï´Ù"
+
+msgid "E333: Menu path must lead to a menu item"
+msgstr "E333: ¸Þ´º Ç׸ñ ¾Õ¿¡´Â ¸Þ´º °æ·Î°¡ ÀÖ¾î¾ß ÇÕ´Ï´Ù"
+
+#, c-format
+msgid "E334: Menu not found: %s"
+msgstr "E334: ¸Þ´º¸¦ ãÀ» ¼ö ¾ø½À´Ï´Ù: %s"
+
+msgid "E336: Menu path must lead to a sub-menu"
+msgstr "E336: ÇÏÀ§ ¸Þ´º ¾Õ¿¡ ¸Þ´º °æ·Î°¡ ÀÖ¾î¾ß ÇÕ´Ï´Ù"
+
+msgid "E337: Menu not found - check menu names"
+msgstr "E337: ¸Þ´º¸¦ ãÀ» ¼ö ¾øÀ½ - ¸Þ´º À̸§À» È®ÀÎÇϽʽÿÀ"
+
+#, c-format
+msgid "Error detected while processing %s:"
+msgstr "%s ¼öÇàÁß ¿¡·¯ ¹ß°ß:"
+
+#, c-format
+msgid "line %4ld:"
+msgstr "%4ld ÁÙ:"
+
+#, c-format
+msgid "E354: Invalid register name: '%s'"
+msgstr "E354: À߸øµÈ ·¹Áö½ºÅÍ À̸§: '%s'"
+
+msgid "Messages maintainer: Bram Moolenaar <Bram@vim.org>"
+msgstr "¸Þ½ÃÁö °ü¸®ÀÚ: SungHyun Nam <goweol@gmail.com>"
+
+msgid "Interrupt: "
+msgstr "Áß´Ü: "
+
+msgid "Press ENTER or type command to continue"
+msgstr "°è¼ÓÇÏ·Á¸é ¿£ÅÍ È¤Àº ¸í·ÉÀ» ÀÔ·ÂÇϽʽÿÀ"
+
+#, c-format
+msgid "%s line %ld"
+msgstr "%s ÁÙ %ld"
+
+msgid "-- More --"
+msgstr "-- ´õ --"
+
+msgid " SPACE/d/j: screen/page/line down, b/u/k: up, q: quit "
+msgstr " SPACE/d/j: È­¸é/ÆäÀÌÁö/¶óÀÎ ¾Æ·¡·Î, b/u/k: À§·Î, q: Á¾·á "
+
+msgid "Question"
+msgstr "Áú¹®"
+
+msgid ""
+"&Yes\n"
+"&No"
+msgstr ""
+"¿¹(&Y)\n"
+"¾Æ´Ï¿À(&N)"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"Save &All\n"
+"&Discard All\n"
+"&Cancel"
+msgstr ""
+"¿¹(&Y)\n"
+"¾Æ´Ï¿À(&N)\n"
+"¸ðµÎ ÀúÀå(&A)\n"
+"¸ðµÎ ¹ö¸²(&D)\n"
+"Ãë¼Ò(&C)"
+
+msgid "Select Directory dialog"
+msgstr "µð·ºÅ丮 ¼±Åà ´ëÈ­»óÀÚ"
+
+msgid "Save File dialog"
+msgstr "ÆÄÀÏ ÀúÀå ´ëÈ­»óÀÚ"
+
+msgid "Open File dialog"
+msgstr "ÆÄÀÏ ¿­±â ´ëÈ­»óÀÚ"
+
+msgid "E338: Sorry, no file browser in console mode"
+msgstr "E338: ¹Ì¾ÈÇÕ´Ï´Ù, ÄÜ¼Ö »óÅ¿¡´Â ÆÄÀÏ ºê¶ó¿ìÀú°¡ ¾ø½À´Ï´Ù"
+
+msgid "E766: Insufficient arguments for printf()"
+msgstr "E766: printf()¿¡ ³Ñ¾î¿Â ÀÎÀÚ °¹¼ö°¡ ºÎÁ·"
+
+msgid "E807: Expected Float argument for printf()"
+msgstr "E807: printf()¿¡ ¿¹»ó¸øÇÑ Float ÀÎÀÚ"
+
+msgid "E767: Too many arguments to printf()"
+msgstr "E767: printf()¿¡ ³Ê¹« ¸¹Àº ÀÎÀÚ ³Ñ¾î¿È"
+
+msgid "W10: Warning: Changing a readonly file"
+msgstr "W10: °æ°í: Àбâ Àü¿ë ÆÄÀÏÀ» °íÄ¡°í ÀÖ½À´Ï´Ù"
+
+msgid "Type number and <Enter> or click with mouse (empty cancels): "
+msgstr "¼ýÀÚ ÀÔ·ÂÈÄ <¿£ÅÍ>³ª ¸¶¿ì½º Ŭ¸¯ (¼ýÀÚ¾øÀ¸¸é Ãë¼Ò): "
+
+msgid "Type number and <Enter> (empty cancels): "
+msgstr "¼ýÀÚ ÀÔ·ÂÈÄ <¿£ÅÍ> (¼ýÀÚ¾øÀ¸¸é Ãë¼Ò): "
+
+msgid "1 more line"
+msgstr "ÇÑ ÁÙ ÀÌ»ó"
+
+msgid "1 line less"
+msgstr "ÇÑ ÁÙ ÀÌÇÏ"
+
+#, c-format
+msgid "%ld more lines"
+msgstr "%ld º¸´Ù ¸¹Àº ÁÙ"
+
+#, c-format
+msgid "%ld fewer lines"
+msgstr "%ld º¸´Ù ÀûÀº ÁÙ"
+
+msgid " (Interrupted)"
+msgstr " (ÁߴܵǾú½À´Ï´Ù)"
+
+msgid "Beep!"
+msgstr "Ȉ!"
+
+msgid "ERROR: "
+msgstr "¿¡·¯: "
+
+#, c-format
+#~ msgid ""
+#~ "\n"
+#~ "[bytes] total alloc-freed %lu-%lu, in use %lu, peak use %lu\n"
+#~ msgstr ""
+
+#, c-format
+#~ msgid ""
+#~ "[calls] total re/malloc()'s %lu, total free()'s %lu\n"
+#~ "\n"
+#~ msgstr ""
+
+msgid "E340: Line is becoming too long"
+msgstr "E340: ÁÙÀÌ ³Ê¹« ±æ¾îÁ³½À´Ï´Ù"
+
+#, c-format
+msgid "E341: Internal error: lalloc(%ld, )"
+msgstr "E341: ³»ºÎ ¿¡·¯: lalloc(%ld, )"
+
+#, c-format
+msgid "E342: Out of memory! (allocating %lu bytes)"
+msgstr "E342: ¸Þ¸ð¸® ºÎÁ·! (%lu ¹ÙÀÌÆ®¸¦ ÇÒ´ç)"
+
+#, c-format
+msgid "Calling shell to execute: \"%s\""
+msgstr "½ÇÇàÇÏ·Á°í ½© ºÎ¸§: \"%s\""
+
+msgid "E545: Missing colon"
+msgstr "E545: ÄÝ·ÐÀÌ ¾ø½À´Ï´Ù"
+
+msgid "E546: Illegal mode"
+msgstr "E546: ÀÌ»óÇÑ ¸ðµå"
+
+msgid "E547: Illegal mouseshape"
+msgstr "E547: ÀÌ»óÇÑ ¸¶¿ì½º¸ð¾ç"
+
+msgid "E548: digit expected"
+msgstr "E548: ¼ýÀÚ°¡ ÇÊ¿äÇÕ´Ï´Ù"
+
+msgid "E549: Illegal percentage"
+msgstr "E549: ÀÌ»óÇÑ ¹éºÐÀ²"
+
+#~ msgid "E854: path too long for completion"
+#~ msgstr ""
+
+#, c-format
+msgid ""
+"E343: Invalid path: '**[number]' must be at the end of the path or be "
+"followed by '%s'."
+msgstr ""
+"E343: À߸øµÈ °æ·Î: '**[¹øÈ£]'´Â °æ·ÎÀÇ ¸¶Áö¸·¿¡ À§Ä¡Çϰųª '%s' µÚ¿¡ ÀÖ¾î¾ß "
+"ÇÕ´Ï´Ù."
+
+#, c-format
+msgid "E344: Can't find directory \"%s\" in cdpath"
+msgstr "E344: cdpath¿¡¼­ \"%s\" µð·ºÅ丮¸¦ ãÀ» ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "E345: Can't find file \"%s\" in path"
+msgstr "E345: path¿¡¼­ \"%s\" ÆÄÀÏÀ» ãÀ» ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "E346: No more directory \"%s\" found in cdpath"
+msgstr "E346: cdpath¿¡¼­ ´õ ÀÌ»óÀÇ \"%s\" µð·ºÅ丮¸¦ ãÀ» ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "E347: No more file \"%s\" found in path"
+msgstr "E347: path¿¡¼­ ´õ ÀÌ»óÀÇ \"%s\" ÆÄÀÏÀ» ãÀ» ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "E668: Wrong access mode for NetBeans connection info file: \"%s\""
+msgstr "E668: NetBeans ¿¬°á Á¤º¸ ÆÄÀÏÀÌ Á¢±Ù ¸ðµå°¡ À߸øµÊ: \"%s\""
+
+#, c-format
+msgid "E658: NetBeans connection lost for buffer %ld"
+msgstr "E658: ¹öÆÛ %ld¿¡ ´ëÇÑ NetBeans ¿¬°áÀ» ÀÒ¾î¹ö·È½À´Ï´Ù"
+
+msgid "E838: netbeans is not supported with this GUI"
+msgstr "E838: ÀÌ GUI´Â netbeans¸¦ Áö¿øÇÏÁö ¾Ê½À´Ï´Ù"
+
+msgid "E511: netbeans already connected"
+msgstr "E511: netbeans°¡ ÀÌ¹Ì ¿¬°áµÇ¾î ÀÖ½À´Ï´Ù"
+
+#, c-format
+msgid "E505: %s is read-only (add ! to override)"
+msgstr "E505: %sÀº(´Â) Àбâ Àü¿ëÀÔ´Ï´Ù (µ¤¾î¾²·Á¸é ! ´õÇϱâ)"
+
+msgid "E349: No identifier under cursor"
+msgstr "E349: Ä¿¼­ ¹Ø¿¡ ½Äº°ÀÚ°¡ ¾ø½À´Ï´Ù"
+
+msgid "E774: 'operatorfunc' is empty"
+msgstr "E774: 'operatorfunc'°¡ ºñ¾îÀÖ½À´Ï´Ù"
+
+msgid "E775: Eval feature not available"
+msgstr "E775: Eval ±â´ÉÀÌ ºüÁ®ÀÖ½À´Ï´Ù"
+
+msgid "Warning: terminal cannot highlight"
+msgstr "°æ°í: Å͹̳ÎÀÌ ºñÁê¾ó »óŸ¦ Ç¥½ÃÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E348: No string under cursor"
+msgstr "E348: Ä¿¼­ ¹Ø¿¡ ¹®ÀÚ¿­ÀÌ ¾ø½À´Ï´Ù"
+
+msgid "E352: Cannot erase folds with current 'foldmethod'"
+msgstr "E352: ÇöÀçÀÇ 'foldmethod'À¸·Î Á¢±â¸¦ Áö¿ï ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E664: changelist is empty"
+msgstr "E664: changelist°¡ ºñ¾ú½À´Ï´Ù"
+
+#~ msgid "E662: At start of changelist"
+#~ msgstr ""
+
+#~ msgid "E663: At end of changelist"
+#~ msgstr ""
+
+msgid "Type :qa! and press <Enter> to abandon all changes and exit Vim"
+msgstr ":qa! ÀÔ·Â ÈÄ¿¡ <¿£ÅÍ> Å°¸¦ ´©¸£½Ã¸é ¼öÁ¤À» Ãë¼ÒÇÏ°í ºöÀ» Á¾·áÇÕ´Ï´Ù"
+
+#, c-format
+msgid "1 line %sed 1 time"
+msgstr "1 line %sed 1 time"
+
+#, c-format
+msgid "1 line %sed %d times"
+msgstr "1 line %sed %d times"
+
+#, c-format
+msgid "%ld lines %sed 1 time"
+msgstr "%ld lines %sed 1 time"
+
+#, c-format
+msgid "%ld lines %sed %d times"
+msgstr "%ld lines %sed %d times"
+
+#, c-format
+msgid "%ld lines to indent... "
+msgstr "%ld lines to indent... "
+
+msgid "1 line indented "
+msgstr "1 line indented "
+
+#, c-format
+msgid "%ld lines indented "
+msgstr "%ld lines indented "
+
+#~ msgid "E748: No previously used register"
+#~ msgstr ""
+
+msgid "cannot yank; delete anyway"
+msgstr "cannot yank; delete anyway"
+
+msgid "1 line changed"
+msgstr "1 line changed"
+
+#, c-format
+msgid "%ld lines changed"
+msgstr "%ld lines changed"
+
+#, c-format
+msgid "freeing %ld lines"
+msgstr "freeing %ld lines"
+
+#, c-format
+msgid " into \"%c"
+msgstr " into \"%c"
+
+#, c-format
+msgid "block of 1 line yanked%s"
+msgstr "block of 1 line yanked%s"
+
+#, c-format
+msgid "1 line yanked%s"
+msgstr "1 line yanked%s"
+
+#, c-format
+msgid "block of %ld lines yanked%s"
+msgstr "block of %ld lines yanked%s"
+
+#, c-format
+msgid "%ld lines yanked%s"
+msgstr "%ld lines yanked%s"
+
+#, c-format
+msgid "E353: Nothing in register %s"
+msgstr "E353: %s ·¹Áö½ºÅÍ¿¡ ¾Æ¹« °Íµµ ¾ø½À´Ï´Ù"
+
+msgid ""
+"\n"
+"--- Registers ---"
+msgstr ""
+"\n"
+"--- ·¹Áö½ºÅÍ ---"
+
+msgid "Illegal register name"
+msgstr "ÀÌ»óÇÑ ·¹Áö½ºÅÍ À̸§"
+
+msgid ""
+"\n"
+"# Registers:\n"
+msgstr ""
+"\n"
+"# ·¹Áö½ºÅÍ:\n"
+
+#, c-format
+msgid "E574: Unknown register type %d"
+msgstr "E574: ¸ð¸£´Â ·¹Áö½ºÅÍ Çü½Ä %d"
+
+#~ msgid ""
+#~ "E883: search pattern and expression register may not contain two or more "
+#~ "lines"
+#~ msgstr ""
+
+#, c-format
+msgid "%ld Cols; "
+msgstr "%ld ¿­; "
+
+#, c-format
+msgid "Selected %s%ld of %ld Lines; %lld of %lld Words; %lld of %lld Bytes"
+msgstr "Selected %s%ld of %ld Lines; %lld of %lld Words; %lld of %lld Bytes"
+
+#, c-format
+msgid ""
+"Selected %s%ld of %ld Lines; %lld of %lld Words; %lld of %lld Chars; %lld of "
+"%lld Bytes"
+msgstr ""
+"Selected %s%ld of %ld Lines; %lld of %lld Words; %lld of %lld Chars; %lld of "
+"%lld Bytes"
+
+#, c-format
+msgid "Col %s of %s; Line %ld of %ld; Word %lld of %lld; Byte %lld of %lld"
+msgstr "Col %s of %s; Line %ld of %ld; Word %lld of %lld; Byte %lld of %lld"
+
+#, c-format
+msgid ""
+"Col %s of %s; Line %ld of %ld; Word %lld of %lld; Char %lld of %lld; Byte "
+"%lld of %lld"
+msgstr ""
+"Col %s of %s; Line %ld of %ld; Word %lld of %lld; Char %lld of %lld; Byte "
+"%lld of %lld"
+
+#, c-format
+#~ msgid "(+%lld for BOM)"
+#~ msgstr ""
+
+msgid "Thanks for flying Vim"
+msgstr "ºöÀ» ³¯°Ô ÇØ Áּż­ °í¸¿½À´Ï´Ù"
+
+msgid "E518: Unknown option"
+msgstr "E518: ¸ð¸£´Â ¿É¼Ç"
+
+msgid "E519: Option not supported"
+msgstr "E519: Áö¿øµÇÁö ¾Ê´Â ¿É¼ÇÀÔ´Ï´Ù"
+
+msgid "E520: Not allowed in a modeline"
+msgstr "E520: ¸ðµå¶óÀο¡¼­ »ç¿ëµÉ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E846: Key code not set"
+msgstr "E846: Å° Äڵ尡 ¼³Á¤µÇÁö ¾Ê¾Ò½À´Ï´Ù"
+
+msgid "E521: Number required after ="
+msgstr "E521: = µÚ¿¡ ¼ýÀÚ°¡ ÇÊ¿äÇÕ´Ï´Ù"
+
+msgid "E522: Not found in termcap"
+msgstr "E522: termcap¿¡¼­ ãÀ» ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "E539: Illegal character <%s>"
+msgstr "E539: ÀÌ»óÇÑ ±ÛÀÚ <%s>"
+
+#, c-format
+#~ msgid "For option %s"
+#~ msgstr ""
+
+msgid "E529: Cannot set 'term' to empty string"
+msgstr "E529: 'term'À» ºó ¹®ÀÚ¿­·Î ¼³Á¤ÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E530: Cannot change term in GUI"
+msgstr "E530: GUI¿¡¼­´Â termÀ» ¹Ù²Ü ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E531: Use \":gui\" to start the GUI"
+msgstr "E531: GUI¸¦ ½ÃÀÛÇÏ·Á¸é \":gui\"¸¦ »ç¿ëÇϽʽÿÀ"
+
+msgid "E589: 'backupext' and 'patchmode' are equal"
+msgstr "E589: 'backupext'¿Í 'patchmode'°¡ µ¿ÀÏÇÕ´Ï´Ù"
+
+msgid "E834: Conflicts with value of 'listchars'"
+msgstr "E834: 'listchars' °ª°ú Ãæµ¹ÀÌ ¹ß»ýÇÕ´Ï´Ù"
+
+msgid "E835: Conflicts with value of 'fillchars'"
+msgstr "E835: 'fillchars' °ª°ú Ãæµ¹ÀÌ ¹ß»ýÇÕ´Ï´Ù"
+
+msgid "E617: Cannot be changed in the GTK+ 2 GUI"
+msgstr "E617: GTK+ 2 GUI¿¡¼­´Â ¹Ù²ð ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+#~ msgid "E950: Cannot convert between %s and %s"
+#~ msgstr ""
+
+msgid "E524: Missing colon"
+msgstr "E524: ÄÝ·ÐÀÌ ¾ø½À´Ï´Ù"
+
+msgid "E525: Zero length string"
+msgstr "E525: ºó ¹®ÀÚ¿­ÀÔ´Ï´Ù"
+
+#, c-format
+msgid "E526: Missing number after <%s>"
+msgstr "E526: <%s> µÚ¿¡ ¼ýÀÚ°¡ ¾ø½À´Ï´Ù"
+
+msgid "E527: Missing comma"
+msgstr "E527: ÄÞ¸¶°¡ ¾ø½À´Ï´Ù"
+
+msgid "E528: Must specify a ' value"
+msgstr "E528: ' °ªÀ» ¸í½ÃÇØ ÁÖ¼Å¾ß ÇÕ´Ï´Ù"
+
+msgid "E595: contains unprintable or wide character"
+msgstr "E595: Ãâ·ÂÇÒ ¼ö ¾ø´Â, ȤÀº ¿ÍÀÌµå ¹®ÀÚ¸¦ Æ÷ÇÔÇÏ°í ÀÖ½À´Ï´Ù"
+
+msgid "E596: Invalid font(s)"
+msgstr "E596: À߸øµÈ ±Û²Ã(µé)"
+
+msgid "E597: can't select fontset"
+msgstr "E597: ±Û²Ã¼ÂÀ» °í¸¦ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E598: Invalid fontset"
+msgstr "E598: À߸øµÈ ±Û²Ã¼Â"
+
+msgid "E533: can't select wide font"
+msgstr "E533: ¿ÍÀÌµå ±Û²ÃÀ» °í¸¦ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E534: Invalid wide font"
+msgstr "E534: À߸øµÈ ¿ÍÀÌµå ±Û²Ã"
+
+#, c-format
+msgid "E535: Illegal character after <%c>"
+msgstr "E535: <%c> µÚ¿¡ ÀÌ»óÇÑ ±ÛÀÚ"
+
+msgid "E536: comma required"
+msgstr "E536: ÄÞ¸¶°¡ ÇÊ¿äÇÕ´Ï´Ù"
+
+#, c-format
+msgid "E537: 'commentstring' must be empty or contain %s"
+msgstr "E537: 'commentstring'Àº ºñ°Å³ª %sÀ»(¸¦) Æ÷ÇÔÇØ¾ß ÇÕ´Ï´Ù"
+
+msgid "E538: No mouse support"
+msgstr "E538: ¸¶¿ì½º¸¦ Áö¿øÇÏÁö ¾Ê½À´Ï´Ù"
+
+msgid "E540: Unclosed expression sequence"
+msgstr "E540: ´ÝÈ÷Áö ¾ÊÀº Ç¥Çö½Ä ¹è¿­"
+
+msgid "E541: too many items"
+msgstr "E541: ³Ê¹« ¸¹Àº Ç׸ñ"
+
+msgid "E542: unbalanced groups"
+msgstr "E542: ±ÕÇüÀÌ ¾È ÀâÈù ±×·ì"
+
+#~ msgid "E946: Cannot make a terminal with running job modifiable"
+#~ msgstr ""
+
+msgid "E590: A preview window already exists"
+msgstr "E590: ¹Ì¸® º¸±â âÀÌ ÀÌ¹Ì Á¸ÀçÇÕ´Ï´Ù"
+
+msgid "W17: Arabic requires UTF-8, do ':set encoding=utf-8'"
+msgstr "W17: ArabicÀº UTF-8 ÀÎÄÚµù ÇÊ¿ä, ':set encoding=utf-8' Çϼ¼¿ä"
+
+msgid "E954: 24-bit colors are not supported on this environment"
+msgstr "E954: ÀÌ È¯°æ¿¡¼­´Â 24ºñÆ® »ö»óÀÌ Áö¿øµÇÁö ¾Ê½À´Ï´Ù"
+
+#, c-format
+msgid "E593: Need at least %d lines"
+msgstr "E593: Àû¾îµµ %d ÁÙÀÌ ÇÊ¿äÇÕ´Ï´Ù"
+
+#, c-format
+msgid "E594: Need at least %d columns"
+msgstr "E594: Àû¾îµµ %d Ä­ÀÌ ÇÊ¿äÇÕ´Ï´Ù"
+
+#, c-format
+msgid "E355: Unknown option: %s"
+msgstr "E355: ¸ð¸£´Â ¿É¼Ç: %s"
+
+#, c-format
+msgid "E521: Number required: &%s = '%s'"
+msgstr "E521: ¼ýÀÚ°¡ ÇÊ¿ä: &%s = '%s'"
+
+msgid ""
+"\n"
+"--- Terminal codes ---"
+msgstr ""
+"\n"
+"--- Å͹̳ΠÄÚµå ---"
+
+msgid ""
+"\n"
+"--- Global option values ---"
+msgstr ""
+"\n"
+"--- Àü¿ª ¿É¼Ç °ª ---"
+
+msgid ""
+"\n"
+"--- Local option values ---"
+msgstr ""
+"\n"
+"--- Áö¿ª ¿É¼Ç °ª ---"
+
+msgid ""
+"\n"
+"--- Options ---"
+msgstr ""
+"\n"
+"--- ¿É¼Ç ---"
+
+msgid "E356: get_varp ERROR"
+msgstr "E356: get_varp ¿¡·¯"
+
+#, c-format
+msgid "E357: 'langmap': Matching character missing for %s"
+msgstr "E357: 'langmap': %s¿¡ ´ëÇÑ ¸Â´Â ±ÛÀÚ°¡ ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "E358: 'langmap': Extra characters after semicolon: %s"
+msgstr "E358: 'langmap': ¼¼¹ÌÄÝ·Ð µÚ¿¡ ±ÛÀÚ°¡ ´õ ÀÖÀ½: %s"
+
+msgid "cannot open "
+msgstr "cannot open "
+
+msgid "VIM: Can't open window!\n"
+msgstr "ºö: âÀ» ¿­ ¼ö ¾ø½À´Ï´Ù!\n"
+
+msgid "Need Amigados version 2.04 or later\n"
+msgstr "¾Æ¹Ì°¡µµ½º 2.04³ª ´õ ³ôÀº ÆÇÀÌ ÇÊ¿äÇÕ´Ï´Ù\n"
+
+#, c-format
+msgid "Need %s version %ld\n"
+msgstr "Need %s version %ld\n"
+
+msgid "Cannot open NIL:\n"
+msgstr "NILÀ» ¿­ ¼ö ¾øÀ½:\n"
+
+msgid "Cannot create "
+msgstr "Cannot create "
+
+#, c-format
+msgid "Vim exiting with %d\n"
+msgstr "ºöÀÌ %d °ªÀ¸·Î ³¡³À´Ï´Ù\n"
+
+msgid "cannot change console mode ?!\n"
+msgstr "ÄÜ¼Ö »óŸ¦ ¹Ù²Ü ¼ö ¾ø½À´Ï´Ù ?!\n"
+
+msgid "mch_get_shellsize: not a console??\n"
+msgstr "mch_get_shellsize: ÄܼÖÀÌ ¾Æ´Ñ°¡??\n"
+
+msgid "E360: Cannot execute shell with -f option"
+msgstr "E360: -f ¿É¼ÇÀÌ »ç¿ëµÈ °æ¿ì ½©À» ½ÇÇàÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "Cannot execute "
+msgstr "Cannot execute "
+
+msgid "shell "
+msgstr "shell "
+
+msgid " returned\n"
+msgstr " returned\n"
+
+msgid "ANCHOR_BUF_SIZE too small."
+msgstr "ANCHOR_BUF_SIZE°¡ ³Ê¹« ÀÛ½À´Ï´Ù."
+
+msgid "I/O ERROR"
+msgstr "I/O ¿¡·¯"
+
+msgid "Message"
+msgstr "¸Þ½ÃÁö"
+
+msgid "E237: Printer selection failed"
+msgstr "E237: ÇÁ¸°Å͸¦ °í¸£Áö ¸øÇß½À´Ï´Ù"
+
+#, c-format
+msgid "to %s on %s"
+msgstr "to %s on %s"
+
+#, c-format
+msgid "E613: Unknown printer font: %s"
+msgstr "E613: ¸ð¸£´Â ÇÁ¸°ÅÍ ±Û²Ã: %s"
+
+#, c-format
+msgid "E238: Print error: %s"
+msgstr "E238: Àμ⠿¡·¯: %s"
+
+#, c-format
+msgid "Printing '%s'"
+msgstr "'%s' ÀμâÁß"
+
+#, c-format
+msgid "E244: Illegal charset name \"%s\" in font name \"%s\""
+msgstr "E244: À߸øµÈ ±ÛÀڼ À̸§ \"%s\"ÀÌ(°¡) ±Û²Ã À̸§ \"%s\"¿¡ ÀÖ½À´Ï´Ù"
+
+#, c-format
+msgid "E244: Illegal quality name \"%s\" in font name \"%s\""
+msgstr "E244: À߸øµÈ Ä÷·¯Æ¼ À̸§ \"%s\"ÀÌ(°¡) ±Û²Ã À̸§ \"%s\"¿¡ ÀÖ½À´Ï´Ù"
+
+#, c-format
+msgid "E245: Illegal char '%c' in font name \"%s\""
+msgstr "E245: À߸øµÈ ±ÛÀÚ '%c'ÀÌ(°¡) ±Û²Ã À̸§ \"%s\"¿¡ ÀÖ½À´Ï´Ù"
+
+#, c-format
+msgid "Opening the X display took %ld msec"
+msgstr "X µð½ºÇ÷¹À̸¦ ¿©´Â µ¥ %ld msecÀÌ °É·È½À´Ï´Ù"
+
+msgid ""
+"\n"
+"Vim: Got X error\n"
+msgstr ""
+"\n"
+"ºö: X ¿¡·¯°¡ »ý°å½À´Ï´Ù\n"
+
+msgid "Testing the X display failed"
+msgstr "X µð½ºÇ÷¹ÀÌ ½ÃÇèÀÌ ½ÇÆÐÇß½À´Ï´Ù"
+
+msgid "Opening the X display timed out"
+msgstr "X µð½ºÇ÷¹À̸¦ ¿­´Ù°¡ ½Ã°£ÀÌ ÃÊ°úµÇ¾ú½À´Ï´Ù"
+
+msgid ""
+"\n"
+"Could not get security context for "
+msgstr ""
+"\n"
+"Could not get security context for "
+
+msgid ""
+"\n"
+"Could not set security context for "
+msgstr ""
+"\n"
+"Could not set security context for "
+
+#, c-format
+#~ msgid "Could not set security context %s for %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Could not get security context %s for %s. Removing it!"
+#~ msgstr ""
+
+msgid ""
+"\n"
+"Cannot execute shell sh\n"
+msgstr ""
+"\n"
+"½© sh¸¦ ½ÇÇàÇÒ ¼ö ¾ø½À´Ï´Ù\n"
+
+msgid ""
+"\n"
+"shell returned "
+msgstr ""
+"\n"
+"shell returned "
+
+msgid ""
+"\n"
+"Cannot create pipes\n"
+msgstr ""
+"\n"
+"ÆÄÀÌÇÁ¸¦ ¸¸µé ¼ö ¾ø½À´Ï´Ù\n"
+
+msgid ""
+"\n"
+"Cannot fork\n"
+msgstr ""
+"\n"
+"ÀÚ½Ä ÇÁ·Î¼¼½º¸¦ ¸¸µé ¼ö ¾ø½À´Ï´Ù\n"
+
+msgid ""
+"\n"
+"Cannot execute shell "
+msgstr ""
+"\n"
+"Cannot execute shell "
+
+msgid ""
+"\n"
+"Command terminated\n"
+msgstr ""
+"\n"
+"¸í·ÉÀÌ ³¡¸¶ÃÄÁ³½À´Ï´Ù\n"
+
+msgid "XSMP lost ICE connection"
+msgstr "XSMP°¡ ICE ¿¬°áÀ» ÀÒ¾î¹ö·È½À´Ï´Ù"
+
+#, c-format
+msgid "dlerror = \"%s\""
+msgstr "dlerror = \"%s\""
+
+msgid "Opening the X display failed"
+msgstr "X µð½ºÇ÷¹ÀÌ ¿­±â°¡ ½ÇÆÐÇß½À´Ï´Ù"
+
+msgid "XSMP handling save-yourself request"
+msgstr "XSMP°¡ save-yourself ¿äûÀ» ½ÇÇàÇÏ°í ÀÖ½À´Ï´Ù"
+
+msgid "XSMP opening connection"
+msgstr "XSMP°¡ ¿¬°áÀ» ¿©´Â ÁßÀÔ´Ï´Ù"
+
+msgid "XSMP ICE connection watch failed"
+msgstr "XSMP°¡ ICE ¿¬°á °¨½Ã¸¦ ½ÇÆÐÇß½À´Ï´Ù"
+
+#, c-format
+msgid "XSMP SmcOpenConnection failed: %s"
+msgstr "XSMP SmcOpenConnection ½ÇÆÐ: %s"
+
+msgid "At line"
+msgstr "At line"
+
+msgid "Could not load vim32.dll!"
+msgstr "vim32.dllÀ» ºÒ·¯ µéÀÏ ¼ö ¾ø½À´Ï´Ù!"
+
+msgid "VIM Error"
+msgstr "ºö ¿¡·¯"
+
+msgid "Could not fix up function pointers to the DLL!"
+msgstr "ÇÔ¼ö Æ÷ÀÎÅ͸¦ DLL·Î ¹Ù²Ü ¼ö ¾ø½À´Ï´Ù!"
+
+#, c-format
+msgid "Vim: Caught %s event\n"
+msgstr "ºö: %s À̺¥Æ®¸¦ Àâ¾Ò½À´Ï´Ù\n"
+
+msgid "close"
+msgstr "´Ý±â"
+
+msgid "logoff"
+msgstr "·Î±×¾Æ¿ô"
+
+msgid "shutdown"
+msgstr "¼Ë´Ù¿î"
+
+msgid "E371: Command not found"
+msgstr "E371: ¸í·ÉÀ» ãÀ» ¼ö ¾ø½À´Ï´Ù"
+
+msgid ""
+"VIMRUN.EXE not found in your $PATH.\n"
+"External commands will not pause after completion.\n"
+"See :help win32-vimrun for more information."
+msgstr ""
+"VIMRUN.EXE¸¦ $PATH¿¡¼­ ãÀ» ¼ö ¾ø½À´Ï´Ù.\n"
+"¿ÜºÎ ¸í·ÉÀÌ ³¡³­ µÚ ¸ØÃâ ¼ö ¾ø½À´Ï´Ù.\n"
+"´Ù ¸¹Àº Á¤º¸¸¦ º¸½Ã·Á¸é :help win32-vimrunÀ» º¸½Ê½Ã¿À."
+
+msgid "Vim Warning"
+msgstr "ºö °æ°í"
+
+#, c-format
+msgid "shell returned %d"
+msgstr "½©ÀÌ %dÀ»(¸¦) µ¹·ÁÁÖ¾ú½À´Ï´Ù"
+
+msgid "E926: Current location list was changed"
+msgstr "E926: ÇöÀçÀÇ location list°¡ ¹Ù²î¾ú½À´Ï´Ù"
+
+#, c-format
+msgid "E372: Too many %%%c in format string"
+msgstr "E372: Çü½Ä ¹®ÀÚ¿­¿¡ %%%cÀÌ(°¡) ³Ê¹« ¸¹½À´Ï´Ù"
+
+#, c-format
+msgid "E373: Unexpected %%%c in format string"
+msgstr "E373: Çü½Ä ¹®ÀÚ¿­¿¡ %%%cÀÌ(°¡) À߸øµÇ¾ú½À´Ï´Ù"
+
+msgid "E374: Missing ] in format string"
+msgstr "E374: Çü½Ä ¹®ÀÚ¿­¿¡ ]°¡ ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "E375: Unsupported %%%c in format string"
+msgstr "E375: Çü½Ä ¹®ÀÚ¿­¿¡ Áö¿øµÇÁö ¾Ê´Â %%%cÀÌ(°¡) ÀÖ½À´Ï´Ù"
+
+#, c-format
+msgid "E376: Invalid %%%c in format string prefix"
+msgstr "E376: Çü½Ä ¹®ÀÚ¿­ ¼­µÎ¿¡ À߸øµÈ %%%cÀÌ(°¡) ÀÖ½À´Ï´Ù"
+
+#, c-format
+msgid "E377: Invalid %%%c in format string"
+msgstr "E377: Çü½Ä ¹®ÀÚ¿­¿¡ À߸øµÈ %%%cÀÌ(°¡) ÀÖ½À´Ï´Ù"
+
+msgid "E378: 'errorformat' contains no pattern"
+msgstr "E378: 'errorformat'ÀÌ ¾î¶² ÆÐÅϵµ Æ÷ÇÔÇÏ°í ÀÖÁö ¾Ê½À´Ï´Ù"
+
+msgid "E379: Missing or empty directory name"
+msgstr "E379: ºüÁ³°Å³ª ºó µð·ºÅ丮 À̸§"
+
+msgid "E553: No more items"
+msgstr "E553: ´õ ÀÌ»óÀÇ Ç׸ñÀÌ ¾ø½À´Ï´Ù"
+
+msgid "E924: Current window was closed"
+msgstr "E924: ÇöÀç âÀÌ ´ÝÇû½À´Ï´Ù"
+
+msgid "E925: Current quickfix was changed"
+msgstr "E925: ÇöÀçÀÇ quickfix°¡ ¹Ù²î¾ú½À´Ï´Ù"
+
+#, c-format
+msgid "(%d of %d)%s%s: "
+msgstr "(%d of %d)%s%s: "
+
+msgid " (line deleted)"
+msgstr " (ÁÙÀ» Áö¿üÀ½)"
+
+#, c-format
+msgid "%serror list %d of %d; %d errors "
+msgstr "%serror list %d of %d; %d errors "
+
+msgid "E380: At bottom of quickfix stack"
+msgstr "E380: ÄüÇȽº ½ºÅÃÀÇ ¹Ù´ÚÀÔ´Ï´Ù"
+
+msgid "E381: At top of quickfix stack"
+msgstr "E381: ÄüÇȽº ½ºÅÃÀÇ ²À´ë±âÀÔ´Ï´Ù"
+
+#~ msgid "No entries"
+#~ msgstr ""
+
+msgid "Error file"
+msgstr "¿¡·¯ ÆÄÀÏ"
+
+msgid "E683: File name missing or invalid pattern"
+msgstr "E683: ÆÄÀÏ¸í ´©¶ô ȤÀº À߸øµÈ ÆÐÅÏ"
+
+#, c-format
+msgid "Cannot open file \"%s\""
+msgstr "\"%s\" ÆÄÀÏÀ» ¿­ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E681: Buffer is not loaded"
+msgstr "E681: ¹öÆÛ°¡ ·ÎµåµÇÁö ¾Ê¾Ò½À´Ï´Ù"
+
+msgid "E777: String or List expected"
+msgstr "E777: StringÀ̳ª List°¡ ÀÖ¾î¾ß ÇÔ"
+
+#, c-format
+msgid "E369: invalid item in %s%%[]"
+msgstr "E369: %s%%[]¿¡ À߸øµÈ Ç׸ñ"
+
+#, c-format
+msgid "E769: Missing ] after %s["
+msgstr "E769: %s[ µÚ¿¡ ]°¡ ¾ø½À´Ï´Ù"
+
+#~ msgid "E944: Reverse range in character class"
+#~ msgstr ""
+
+#~ msgid "E945: Range too large in character class"
+#~ msgstr ""
+
+#, c-format
+msgid "E53: Unmatched %s%%("
+msgstr "E53: ¸ÂÁö ¾Ê´Â %s%%("
+
+#, c-format
+msgid "E54: Unmatched %s("
+msgstr "E54: ¸ÂÁö ¾Ê´Â %s("
+
+#, c-format
+msgid "E55: Unmatched %s)"
+msgstr "E55: ¸ÂÁö ¾Ê´Â %s)"
+
+msgid "E66: \\z( not allowed here"
+msgstr "E66: \\z(´Â ¿©±â¿¡¼­ Çã¿ëµÇÁö ¾Ê½À´Ï´Ù"
+
+msgid "E67: \\z1 - \\z9 not allowed here"
+msgstr "E67: \\z1 µîÀº ¿©±â¿¡¼­ Çã¿ëµÇÁö ¾Ê½À´Ï´Ù"
+
+#, c-format
+msgid "E69: Missing ] after %s%%["
+msgstr "E69: %s%%[ µÚ¿¡ ]°¡ ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "E70: Empty %s%%[]"
+msgstr "E70: ºó %s%%[]"
+
+msgid "E65: Illegal back reference"
+msgstr "E65: ÀÌ»óÇÑ ÈÄÀ§ ÂüÁ¶"
+
+msgid "E339: Pattern too long"
+msgstr "E339: ÆÐÅÏÀÌ ³Ê¹« ±é´Ï´Ù"
+
+msgid "E50: Too many \\z("
+msgstr "E50: \\z(°¡ ³Ê¹« ¸¹½À´Ï´Ù"
+
+#, c-format
+msgid "E51: Too many %s("
+msgstr "E51: %s(°¡ ³Ê¹« ¸¹½À´Ï´Ù"
+
+msgid "E52: Unmatched \\z("
+msgstr "E52: ¸ÂÁö ¾Ê´Â \\z("
+
+#, c-format
+msgid "E59: invalid character after %s@"
+msgstr "E59: %s@ µÚ¿¡ À߸øµÈ ¹®ÀÚ"
+
+#, c-format
+msgid "E60: Too many complex %s{...}s"
+msgstr "E60: %s{...}s°¡ ³Ê¹« ¸¹À½"
+
+#, c-format
+msgid "E61: Nested %s*"
+msgstr "E61: Nested %s*"
+
+#, c-format
+msgid "E62: Nested %s%c"
+msgstr "E62: Nested %s%c"
+
+msgid "E63: invalid use of \\_"
+msgstr "E63: \\_¸¦ Àß ¸ø »ç¿ë"
+
+#, c-format
+msgid "E64: %s%c follows nothing"
+msgstr "E64: %s%c µÚ¿¡ ¾Æ¹«°Íµµ ¾ø½À´Ï´Ù"
+
+msgid "E68: Invalid character after \\z"
+msgstr "E68: \\z µÚ¿¡ ÀÌ»óÇÑ ¹®ÀÚ"
+
+#, c-format
+msgid "E678: Invalid character after %s%%[dxouU]"
+msgstr "E678: %s%%[dxouU] µÚ¿¡ ÀÌ»óÇÑ ¹®ÀÚ"
+
+#, c-format
+msgid "E71: Invalid character after %s%%"
+msgstr "E71: %s%% µÚ¿¡ ÀÌ»óÇÑ ¹®ÀÚ"
+
+#, c-format
+msgid "E554: Syntax error in %s{...}"
+msgstr "E554: %s{...}¿¡ ±¸¹® ¿¡·¯"
+
+msgid "External submatches:\n"
+msgstr "¿ÜºÎ submatches:\n"
+
+#, c-format
+msgid "E888: (NFA regexp) cannot repeat %s"
+msgstr "E888: (NFA Á¤±ÔÇ¥Çö½Ä) %sÀ»(¸¦) ¹Ýº¹ÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+#~ msgid ""
+#~ "E864: \\%#= can only be followed by 0, 1, or 2. The automatic engine will be "
+#~ "used "
+#~ msgstr ""
+
+#~ msgid "Switching to backtracking RE engine for pattern: "
+#~ msgstr ""
+
+#~ msgid "E865: (NFA) Regexp end encountered prematurely"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E866: (NFA regexp) Misplaced %c"
+#~ msgstr ""
+
+#, c-format
+msgid "E877: (NFA regexp) Invalid character class: %ld"
+msgstr "E877: (NFA Á¤±ÔÇ¥Çö½Ä) ºñÁ¤»óÀûÀÎ ¹®ÀÚ Å¬·¡½º: %ld"
+
+#, c-format
+msgid "E867: (NFA) Unknown operator '\\z%c'"
+msgstr "E867: (NFA) ¸ð¸£´Â ¿ÀÆÛ·¹ÀÌÅÍ '\\z%c'"
+
+msgid "E951: \\% value too large"
+msgstr "E951: \\% °ªÀÌ ³Ê¹« ±é´Ï´Ù"
+
+#, c-format
+msgid "E867: (NFA) Unknown operator '\\%%%c'"
+msgstr "E867: (NFA) ¸ð¸£´Â ¿ÀÆÛ·¹ÀÌÅÍ '\\%%%c'"
+
+msgid "E868: Error building NFA with equivalence class!"
+msgstr "E868: Error building NFA with equivalence class!"
+
+#, c-format
+msgid "E869: (NFA) Unknown operator '\\@%c'"
+msgstr "E869: (NFA) ¸ð¸£´Â ¿ÀÆÛ·¹ÀÌÅÍ '\\@%c'"
+
+#~ msgid "E870: (NFA regexp) Error reading repetition limits"
+#~ msgstr ""
+
+#~ msgid "E871: (NFA regexp) Can't have a multi follow a multi"
+#~ msgstr ""
+
+msgid "E872: (NFA regexp) Too many '('"
+msgstr "E872: (NFA Á¤±ÔÇ¥Çö½Ä) '('°¡ ³Ê¹« ¸¹½À´Ï´Ù"
+
+msgid "E879: (NFA regexp) Too many \\z("
+msgstr "E879: (NFA Á¤±ÔÇ¥Çö½Ä) \\z(°¡ ³Ê¹« ¸¹½À´Ï´Ù"
+
+#~ msgid "E873: (NFA regexp) proper termination error"
+#~ msgstr ""
+
+msgid "Could not open temporary log file for writing, displaying on stderr... "
+msgstr "¾²±âÀ§ÇÑ Àӽà ·Î±× ÆÄÀÏÀ» ¿­ ¼ö ¾ø½À´Ï´Ù, Ç¥ÁØ¿¡·¯(stderr)¿¡ Ç¥½ÃÇÕ´Ï´Ù..."
+
+msgid "E874: (NFA) Could not pop the stack!"
+msgstr "E874: (NFA) ½ºÅÿ¡¼­ ²¨³¾ ¼ö ¾ø½À´Ï´Ù!"
+
+#~ msgid ""
+#~ "E875: (NFA regexp) (While converting from postfix to NFA), too many states "
+#~ "left on stack"
+#~ msgstr ""
+
+#~ msgid "E876: (NFA regexp) Not enough space to store the whole NFA "
+#~ msgstr ""
+
+#~ msgid "E878: (NFA) Could not allocate memory for branch traversal!"
+#~ msgstr ""
+
+msgid " VREPLACE"
+msgstr " ¼±ÅÃġȯ"
+
+msgid " REPLACE"
+msgstr " ¹Ù²Ù±â"
+
+msgid " REVERSE"
+msgstr " ¹Ý´ë"
+
+msgid " INSERT"
+msgstr " ³¢¿ö³Ö±â"
+
+msgid " (insert)"
+msgstr " (³¢¿ö³Ö±â)"
+
+msgid " (replace)"
+msgstr " (¹Ù²Ù±â)"
+
+msgid " (vreplace)"
+msgstr " (¼±ÅÃġȯ)"
+
+msgid " Hebrew"
+msgstr " Çìºê·ç"
+
+msgid " Arabic"
+msgstr " ¾Æ¶óºñ¾Æ"
+
+msgid " (paste)"
+msgstr " (ºÙÀ̱â)"
+
+msgid " VISUAL"
+msgstr " ºñÁÖ¾ó"
+
+msgid " VISUAL LINE"
+msgstr " ºñÁÖ¾ó ¶óÀÎ"
+
+msgid " VISUAL BLOCK"
+msgstr " ºñÁÖ¾ó ºí·Ï"
+
+msgid " SELECT"
+msgstr " °í¸£±â"
+
+msgid " SELECT LINE"
+msgstr " ¶óÀÎ °í¸£±â"
+
+msgid " SELECT BLOCK"
+msgstr " ºí·Ï °í¸£±â"
+
+msgid "recording"
+msgstr "±â·ÏÁß"
+
+#, c-format
+msgid "E383: Invalid search string: %s"
+msgstr "E383: À߸øµÈ ã±â ¹®ÀÚ¿­: %s"
+
+#, c-format
+msgid "E384: search hit TOP without match for: %s"
+msgstr "E384: óÀ½±îÁö ¸Â´Â ¹®ÀÚ¿­ÀÌ ¾ø½À´Ï´Ù: %s"
+
+#, c-format
+msgid "E385: search hit BOTTOM without match for: %s"
+msgstr "E385: ³¡±îÁö ¸Â´Â ¹®ÀÚ¿­ÀÌ ¾ø½À´Ï´Ù: %s"
+
+msgid "E386: Expected '?' or '/' after ';'"
+msgstr "E386: ';' µÚ¿¡´Â '?'³ª '/'°¡ ¿Í¾ß ÇÕ´Ï´Ù"
+
+msgid " (includes previously listed match)"
+msgstr " (ÀÌÀü¿¡ ¸Â¾Ò´ø ¸ñ·Ï Æ÷ÇÔ)"
+
+msgid "--- Included files "
+msgstr "--- Included files "
+
+msgid "not found "
+msgstr "not found "
+
+msgid "in path ---\n"
+msgstr "in path ---\n"
+
+msgid " (Already listed)"
+msgstr " (Already listed)"
+
+msgid " NOT FOUND"
+msgstr " ¸ø ã¾ÒÀ½"
+
+#, c-format
+msgid "Scanning included file: %s"
+msgstr "Æ÷ÇÔµÈ ÆÄÀÏ Ã£´Â Áß: %s"
+
+#, c-format
+msgid "Searching included file %s"
+msgstr "Æ÷ÇÔµÈ ÆÄÀÏ %s ã´Â Áß"
+
+msgid "E387: Match is on current line"
+msgstr "E387: ¸Â´Â °Ô ÇöÀç ÁÙ¿¡ ÀÖ½À´Ï´Ù"
+
+msgid "All included files were found"
+msgstr "¸ðµç Æ÷ÇÔµÈ ÆÄÀÏÀ» ã¾Ò½À´Ï´Ù"
+
+msgid "No included files"
+msgstr "Æ÷ÇÔµÈ ÆÄÀÏÀÌ ¾ø½À´Ï´Ù"
+
+msgid "E388: Couldn't find definition"
+msgstr "E388: Á¤ÀǸ¦ ãÀ» ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E389: Couldn't find pattern"
+msgstr "E389: ÆÐÅÏÀ» ãÀ» ¼ö ¾ø½À´Ï´Ù"
+
+msgid "Substitute "
+msgstr "Substitute "
+
+#, c-format
+msgid ""
+"\n"
+"# Last %sSearch Pattern:\n"
+"~"
+msgstr ""
+"\n"
+"# Last %sSearch Pattern:\n"
+"~"
+
+msgid "E756: Spell checking is not enabled"
+msgstr "E756: ¸ÂÃã¹ý °Ë»ç°¡ È°¼ºÈ­µÇ¾î ÀÖÁö ¾Ê½À´Ï´Ù"
+
+#, c-format
+msgid "Warning: Cannot find word list \"%s_%s.spl\" or \"%s_ascii.spl\""
+msgstr "°æ°í: ´Ü¾î ¸ñ·Ï \"%s_%s.spl\" ȤÀº \"%s_ascii.spl\"À» ãÀ» ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "Warning: Cannot find word list \"%s.%s.spl\" or \"%s.ascii.spl\""
+msgstr "°æ°í: ´Ü¾î ¸ñ·Ï \"%s.%s.spl\" ȤÀº \"%s.ascii.spl\"À» ãÀ» ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E797: SpellFileMissing autocommand deleted buffer"
+msgstr "E797: SpellFileMissing autocommand°¡ ¹öÆÛ¸¦ »èÁ¦Çß½À´Ï´Ù"
+
+#, c-format
+msgid "Warning: region %s not supported"
+msgstr "°æ°í: %s ¿µ¿ªÀº Áö¿øµÇÁö ¾Ê½À´Ï´Ù"
+
+msgid "Sorry, no suggestions"
+msgstr "Á˼Û, Á¦¾ÈÇÒ °Ô ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "Sorry, only %ld suggestions"
+msgstr "Á˼Û, %ld°³¸¸ Á¦¾È"
+
+#, c-format
+msgid "Change \"%.*s\" to:"
+msgstr "Change \"%.*s\" to:"
+
+#, c-format
+msgid " < \"%.*s\""
+msgstr " < \"%.*s\""
+
+msgid "E752: No previous spell replacement"
+msgstr "E752: öÀÚ°¡ ¹Ù²ïÀûÀÌ ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "E753: Not found: %s"
+msgstr "E753: ãÀ» ¼ö ¾øÀ½: %s"
+
+msgid "E758: Truncated spell file"
+msgstr "E758: À߸° spell ÆÄÀÏ"
+
+#, c-format
+msgid "Trailing text in %s line %d: %s"
+msgstr "Trailing text in %s line %d: %s"
+
+#, c-format
+msgid "Affix name too long in %s line %d: %s"
+msgstr "Affix name too long in %s line %d: %s"
+
+msgid "E761: Format error in affix file FOL, LOW or UPP"
+msgstr "E761: affix ÆÄÀÏ FOL, LOW ȤÀº UPP¿¡ Çü½Ä ¿¡·¯"
+
+msgid "E762: Character in FOL, LOW or UPP is out of range"
+msgstr "E762: FOL, LOW ȤÀº UPPÀÇ ¹®ÀÚ°¡ ¹üÀ§¸¦ ¹þ¾î³²"
+
+msgid "Compressing word tree..."
+msgstr "´Ü¾î Æ®¸® ¾ÐÃàÁß..."
+
+#, c-format
+msgid "Reading spell file \"%s\""
+msgstr "spell ÆÄÀÏ \"%s\"À»(¸¦) Àаí ÀÖ½À´Ï´Ù"
+
+msgid "E757: This does not look like a spell file"
+msgstr "E757: spell ÆÄÀÏÀÌ ¾Æ´Ñ °Í °°½À´Ï´Ù"
+
+msgid "E771: Old spell file, needs to be updated"
+msgstr "E771: ¿À·¡µÈ spell ÆÄÀÏ, °»½ÅÀÌ ÇÊ¿äÇÕ´Ï´Ù"
+
+msgid "E772: Spell file is for newer version of Vim"
+msgstr "E772: Spell ÆÄÀÏÀÌ »õ ¹öÁ¯ÀÇ Vim¿ëÀÔ´Ï´Ù"
+
+msgid "E770: Unsupported section in spell file"
+msgstr "E770: spell ÆÄÀÏ¿¡ Áö¿øµÇÁö ¾Ê´Â ¼½¼Ç"
+
+#, c-format
+msgid "E778: This does not look like a .sug file: %s"
+msgstr "E778: .sug ÆÄÀÏÀÌ ¾Æ´Ñ °Í °°À½: %s"
+
+#, c-format
+msgid "E779: Old .sug file, needs to be updated: %s"
+msgstr "E779: ¿À·¡µÈ .sug ÆÄÀÏ, °»½Å ÇÊ¿ä: %s"
+
+#, c-format
+msgid "E780: .sug file is for newer version of Vim: %s"
+msgstr "E780: .sug ÆÄÀÏÀÌ »õ ¹öÁ¯ÀÇ Vim¿ëÀÓ: %s"
+
+#, c-format
+msgid "E781: .sug file doesn't match .spl file: %s"
+msgstr "E781: .sug ÆÄÀÏÀÌ .spl ÆÄÀÏ°ú ¸ÂÁö ¾ÊÀ½: %s"
+
+#, c-format
+msgid "E782: error while reading .sug file: %s"
+msgstr "E782: .sug ÆÄÀÏ Àб⠿¡·¯: %s"
+
+#, c-format
+msgid "Reading affix file %s..."
+msgstr "affix ÆÄÀÏ %s Àд Áß"
+
+#, c-format
+msgid "Conversion failure for word in %s line %d: %s"
+msgstr "%s ¶óÀÎ %d¿¡ ÀÖ´Â ´Ü¾î º¯È¯ ½ÇÆÐ: %s"
+
+#, c-format
+msgid "Conversion in %s not supported: from %s to %s"
+msgstr "%sÀÇ º¯È¯ÀÌ Áö¿øµÇÁö ¾Ê½À´Ï´Ù: %s¿¡¼­ %s·Î"
+
+#, c-format
+msgid "Conversion in %s not supported"
+msgstr "%sÀÇ º¯È¯ÀÌ Áö¿øµÇÁö ¾Ê½À´Ï´Ù"
+
+#, c-format
+msgid "Invalid value for FLAG in %s line %d: %s"
+msgstr "%s ¶óÀÎ %d¿¡ FLAG¿¡ ´ëÇÑ À߸øµÈ °ª: %s"
+
+#, c-format
+msgid "FLAG after using flags in %s line %d: %s"
+msgstr "%s ¶óÀÎ %d¿¡ Ç÷¡±×°¡ »ç¿ëµÈ ÈÄ FLAG: %s"
+
+#, c-format
+msgid ""
+"Defining COMPOUNDFORBIDFLAG after PFX item may give wrong results in %s line "
+"%d"
+msgstr ""
+"%s ¶óÀÎ %d¿¡ PFX µÚ¿¡ COMPOUNDFORBIDFLAGÀ» Á¤ÀÇÇÑ °ÍÀº À߸øµÈ °á°ú¸¦ ÃÊ·¡ÇÒ "
+"¼ö ÀÖ½À´Ï´Ù"
+
+#, c-format
+msgid ""
+"Defining COMPOUNDPERMITFLAG after PFX item may give wrong results in %s line "
+"%d"
+msgstr ""
+"%s ¶óÀÎ %d¿¡ PFX µÚ¿¡ COMPOUNDPERMITFLAGÀ» Á¤ÀÇÇÑ °ÍÀº À߸øµÈ °á°ú¸¦ ÃÊ·¡ÇÒ "
+"¼ö ÀÖ½À´Ï´Ù"
+
+#, c-format
+msgid "Wrong COMPOUNDRULES value in %s line %d: %s"
+msgstr "%s ¶óÀÎ %d¿¡ À߸øµÈ COMPOUNDRULES °ª: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDWORDMAX value in %s line %d: %s"
+msgstr "%s ¶óÀÎ %d¿¡ À߸øµÈ COMPOUNDWORDMAX °ª: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDMIN value in %s line %d: %s"
+msgstr "%s ¶óÀÎ %d¿¡ À߸øµÈ COMPOUNDMIN °ª: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDSYLMAX value in %s line %d: %s"
+msgstr "%s ¶óÀÎ %d¿¡ À߸øµÈ COMPOUNDSYLMAX °ª: %s"
+
+#, c-format
+msgid "Wrong CHECKCOMPOUNDPATTERN value in %s line %d: %s"
+msgstr "%s ¶óÀÎ %d¿¡ À߸øµÈ CHECKCOMPOUNDPATTERN °ª: %s"
+
+#, c-format
+msgid "Different combining flag in continued affix block in %s line %d: %s"
+msgstr "%s ¶óÀÎ %d¿¡ ¿¬¼ÓµÈ affix ºí·Ï¿¡ ´Ù¸¥ °áÇÕ Ç÷¡±×: %s"
+
+#, c-format
+msgid "Duplicate affix in %s line %d: %s"
+msgstr "%s ¶óÀÎ %d¿¡ Áߺ¹µÈ affix: %s"
+
+#, c-format
+msgid ""
+"Affix also used for BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST in %s "
+"line %d: %s"
+msgstr ""
+"%s ¶óÀÎ %d¿¡ BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST¿¡ ´ëÇؼ­µµ "
+"affix°¡ »ç¿ëµÊ: %s"
+
+#, c-format
+msgid "Expected Y or N in %s line %d: %s"
+msgstr "%s ¶óÀÎ %d¿¡ Y³ª NÀÌ ±â´ëµÊ: %s"
+
+#, c-format
+msgid "Broken condition in %s line %d: %s"
+msgstr "%s ¶óÀÎ %d°¡ ¸Á°¡Áø »óÅÂ: %s"
+
+#, c-format
+msgid "Expected REP(SAL) count in %s line %d"
+msgstr "%s ¶óÀÎ %d¿¡ REP(SAL) Ä«¿îÆ®°¡ ±â´ëµÊ"
+
+#, c-format
+msgid "Expected MAP count in %s line %d"
+msgstr "%s ¶óÀÎ %d¿¡ MAP Ä«¿îÆ®°¡ ±â´ëµÊ"
+
+#, c-format
+msgid "Duplicate character in MAP in %s line %d"
+msgstr "%s ¶óÀÎ %dÀÇ MAP¿¡ Áߺ¹µÈ ¹®ÀÚ"
+
+#, c-format
+msgid "Unrecognized or duplicate item in %s line %d: %s"
+msgstr "%s ¶óÀÎ %d¿¡ ¸ð¸£´Â ȤÀº Áߺ¹µÈ Ç׸ñ: %s"
+
+#, c-format
+msgid "Missing FOL/LOW/UPP line in %s"
+msgstr "%s¿¡ FOL/LOW/UPPÀÌ ´©¶ôµÈ ¶óÀÎ"
+
+msgid "COMPOUNDSYLMAX used without SYLLABLE"
+msgstr "COMPOUNDSYLMAXÀÌ SYLLABLE¾øÀÌ »ç¿ëµÊ"
+
+msgid "Too many postponed prefixes"
+msgstr "postponed Á¢µÎ»ç°¡ ³Ê¹« ¸¹½À´Ï´Ù"
+
+msgid "Too many compound flags"
+msgstr "compound Ç÷¡±×°¡ ³Ê¹« ¸¹½À´Ï´Ù"
+
+msgid "Too many postponed prefixes and/or compound flags"
+msgstr "postponed Á¢µÎ»ç¿Í(³ª) compound Ç÷¡±×°¡ ³Ê¹« ¸¹½À´Ï´Ù"
+
+#, c-format
+msgid "Missing SOFO%s line in %s"
+msgstr "SOFO%s°¡ ´©¶ôµÈ ¶óÀÎÀÌ %s¿¡ ÀÖ½À´Ï´Ù"
+
+#, c-format
+msgid "Both SAL and SOFO lines in %s"
+msgstr "%s¿¡ SAL°ú SOFO ¶óÀÎÀÌ µÑ ´Ù ÀÖ½À´Ï´Ù"
+
+#, c-format
+msgid "Flag is not a number in %s line %d: %s"
+msgstr "%s ¶óÀÎ %d¿¡ ¼ýÀÚ°¡ ¾Æ´Ñ Ç÷¡±×: %s"
+
+#, c-format
+msgid "Illegal flag in %s line %d: %s"
+msgstr "%s ¶óÀÎ %d¿¡ À߸øµÈ Ç÷¡±×: %s"
+
+#, c-format
+msgid "%s value differs from what is used in another .aff file"
+msgstr "%s °ªÀÌ ´Ù¸¥ .aff ÆÄÀÏ¿¡¼­ »ç¿ëµÈ °Í°ú ´Ù¸¨´Ï´Ù"
+
+#, c-format
+msgid "Reading dictionary file %s..."
+msgstr "»çÀü ÆÄÀÏ %s Àд Áß ..."
+
+#, c-format
+msgid "E760: No word count in %s"
+msgstr "E760: %s¿¡ ´Ü¾î Ä«¿îÆ®°¡ ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "line %6d, word %6ld - %s"
+msgstr "¶óÀÎ %6d, ´Ü¾î %6ld - %s"
+
+#, c-format
+msgid "Duplicate word in %s line %d: %s"
+msgstr "%s ¶óÀÎ %d¿¡ Áߺ¹µÈ ´Ü¾î: %s"
+
+#, c-format
+msgid "First duplicate word in %s line %d: %s"
+msgstr "%s ¶óÀÎ %d¿¡ óÀ½ Áߺ¹µÈ ´Ü¾î: %s"
+
+#, c-format
+msgid "%d duplicate word(s) in %s"
+msgstr "%d°³ÀÇ Áߺ¹µÈ ´Ü¾î°¡ %s¿¡ ÀÖ½À´Ï´Ù"
+
+#, c-format
+msgid "Ignored %d word(s) with non-ASCII characters in %s"
+msgstr "¹«½ÃµÈ %d°³ÀÇ ¾Æ½ºÅ°¹®ÀÚ¿­ÀÌ ¾Æ´Ñ ´Ü¾î°¡ %s¿¡ ÀÖ½À´Ï´Ù"
+
+#, c-format
+msgid "Reading word file %s..."
+msgstr "´Ü¾î ÆÄÀÏ %s Àд Áß ..."
+
+#, c-format
+msgid "Duplicate /encoding= line ignored in %s line %d: %s"
+msgstr "%s ¶óÀÎ %dÀÇ Áߺ¹µÈ /encoding= ¶óÀÎ ¹«½ÃµÊ: %s"
+
+#, c-format
+msgid "/encoding= line after word ignored in %s line %d: %s"
+msgstr "%s ¶óÀÎ %dÀÇ ´Ü¾î µÚÀÇ /encoding= ¶óÀÎ ¹«½ÃµÊ: %s"
+
+#, c-format
+msgid "Duplicate /regions= line ignored in %s line %d: %s"
+msgstr "%s ¶óÀÎ %dÀÇ Áߺ¹µÈ /regions= ¶óÀÎ ¹«½ÃµÊ: %s"
+
+#, c-format
+msgid "Too many regions in %s line %d: %s"
+msgstr "%s ¶óÀÎ %d¿¡ ³Ê¹« ¸¹Àº ¿µ¿ª: %s"
+
+#, c-format
+msgid "/ line ignored in %s line %d: %s"
+msgstr "%s ¶óÀÎ %dÀÇ / ¶óÀÎ ¹«½ÃµÊ: %s"
+
+#, c-format
+msgid "Invalid region nr in %s line %d: %s"
+msgstr "%s ¶óÀÎ %d¿¡ À߸øµÈ ¿µ¿ª ¹øÈ£: %s"
+
+#, c-format
+msgid "Unrecognized flags in %s line %d: %s"
+msgstr "%s ¶óÀÎ %d¿¡ ¸ð¸£´Â Ç÷¡±×: %s"
+
+#, c-format
+msgid "Ignored %d words with non-ASCII characters"
+msgstr "¾Æ½ºÅ° ¹®ÀÚ¿­ÀÌ ¾Æ´Ñ %d°³ÀÇ ´Ü¾î°¡ ¹«½ÃµÇ¾ú½À´Ï´Ù"
+
+msgid "E845: Insufficient memory, word list will be incomplete"
+msgstr "E845: ¸Þ¸ð¸® ºÎÁ·, ´Ü¾î ¸ñ·ÏÀÌ ºÒ¿ÏÀüÇÒ °ÍÀÔ´Ï´Ù"
+
+#, c-format
+msgid "Compressed %d of %d nodes; %d (%d%%) remaining"
+msgstr "%d/%d ³ëµå°¡ ¾ÐÃàµÊ; %d (%d%%)°¡ ³²À½"
+
+msgid "Reading back spell file..."
+msgstr "¸ÂÃã¹ý ÆÄÀÏÀ» Àд Áß..."
+
+msgid "Performing soundfolding..."
+msgstr "soundfold ¼öÇàÁß..."
+
+#, c-format
+msgid "Number of words after soundfolding: %ld"
+msgstr "soundfold ¼öÇà ÈÄÀÇ ´Ü¾î ¼ö: %ld"
+
+#, c-format
+msgid "Total number of words: %d"
+msgstr "ÃÑ ´Ü¾î ¼ö: %d"
+
+#, c-format
+msgid "Writing suggestion file %s..."
+msgstr "%s Á¦¾È ÆÄÀÏÀ» ¾²´Â Áß ..."
+
+#, c-format
+msgid "Estimated runtime memory use: %d bytes"
+msgstr "ÃßÁ¤µÈ ·±Å¸ÀÓ ¸Þ¸ð¸® »ç¿ë·®: %d ¹ÙÀÌÆ®"
+
+msgid "E751: Output file name must not have region name"
+msgstr "E751: »ý¼º ÆÄÀϸíÀº ¿µ¿ª À̸§°ú ´Þ¶ó¾ß ÇÕ´Ï´Ù"
+
+#, c-format
+msgid "E754: Only up to %ld regions supported"
+msgstr "E754: ÃÖ´ë %ld°³ÀÇ ¿µ¿ªÀÌ Áö¿øµË´Ï´Ù"
+
+#, c-format
+msgid "E755: Invalid region in %s"
+msgstr "E755: %s¿¡ À߸øµÈ ¿µ¿ª"
+
+msgid "Warning: both compounding and NOBREAK specified"
+msgstr "°æ°í: compound¿Í NOBREAK µÑ ´Ù ¸í½ÃµÊ"
+
+#, c-format
+msgid "Writing spell file %s..."
+msgstr "spell ÆÄÀÏ %s ¾²´Â Áß ..."
+
+msgid "Done!"
+msgstr "³¡!"
+
+#, c-format
+msgid "E765: 'spellfile' does not have %ld entries"
+msgstr "E765: 'spellfile'¿¡ %ld Ç׸ñÀÌ ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "Word '%.*s' removed from %s"
+msgstr "´Ü¾î '%.*s'ÀÌ(°¡) %s¿¡¼­ Á¦°ÅµÊ"
+
+#, c-format
+msgid "Word '%.*s' added to %s"
+msgstr "´Ü¾î '%.*s'ÀÌ(°¡) %s¿¡ Ãß°¡µÊ"
+
+msgid "E763: Word characters differ between spell files"
+msgstr "E763: ´Ü¾î°¡ spell ÆÄÀÏ °£¿¡ ´Ù¸¨´Ï´Ù"
+
+msgid "E783: duplicate char in MAP entry"
+msgstr "E783: MAP Ç׸ñ¿¡ Áߺ¹µÈ ¹®ÀÚ"
+
+msgid "No Syntax items defined for this buffer"
+msgstr "ÀÌ ¹öÆÛ¿¡ ´ëÇØ Á¤ÀÇµÈ ±¸¹® Ç׸ñÀÌ ¾ø½À´Ï´Ù"
+
+msgid "syntax conceal on"
+msgstr "±¸¹® °¨Ãß±â È°¼º"
+
+msgid "syntax conceal off"
+msgstr "±¸¹® °¨Ã߱⠺ñÈ°¼º"
+
+#, c-format
+msgid "E390: Illegal argument: %s"
+msgstr "E390: À߸øµÈ ÀÎÀÚ: %s"
+
+msgid "syntax case ignore"
+msgstr "±¸¹® ´ë¼Ò¹®ÀÚ ±¸º°¾ÊÇÔ"
+
+msgid "syntax case match"
+msgstr "±¸¹® ´ë¼Ò¹®ÀÚ ±¸º°"
+
+#~ msgid "syntax spell toplevel"
+#~ msgstr ""
+
+#~ msgid "syntax spell notoplevel"
+#~ msgstr ""
+
+#~ msgid "syntax spell default"
+#~ msgstr ""
+
+msgid "syntax iskeyword "
+msgstr "syntax iskeyword "
+
+#, c-format
+msgid "E391: No such syntax cluster: %s"
+msgstr "E391: ÀÌ·± ±¸¹® Ŭ·¯½ºÅÍ´Â ¾ø½À´Ï´Ù: %s"
+
+msgid "syncing on C-style comments"
+msgstr "C-Çü½Ä ÁÖ¼®¹®¿¡ µ¿±â¸ÂÃã"
+
+msgid "no syncing"
+msgstr "µ¿±â¸ÂÃã ¾øÀ½"
+
+msgid "syncing starts "
+msgstr "syncing starts "
+
+msgid " lines before top line"
+msgstr " lines before top line"
+
+msgid ""
+"\n"
+"--- Syntax sync items ---"
+msgstr ""
+"\n"
+"--- Syntax sync Ç׸ñµé ---"
+
+msgid ""
+"\n"
+"syncing on items"
+msgstr ""
+"\n"
+"syncing on items"
+
+msgid ""
+"\n"
+"--- Syntax items ---"
+msgstr ""
+"\n"
+"--- Syntax Ç׸ñ ---"
+
+#, c-format
+msgid "E392: No such syntax cluster: %s"
+msgstr "E392: ÀÌ·± ±¸¹® Ŭ·¯½ºÅÍ´Â ¾ø½À´Ï´Ù: %s"
+
+msgid "minimal "
+msgstr "minimal "
+
+msgid "maximal "
+msgstr "maximal "
+
+msgid "; match "
+msgstr "; match "
+
+msgid " line breaks"
+msgstr " line breaks"
+
+msgid "E395: contains argument not accepted here"
+msgstr "E395: contains ÀÎÀÚ´Â ¿©±â¿¡ ¾µ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E844: invalid cchar value"
+msgstr "E844: À߸øµÈ cchar °ª"
+
+msgid "E393: group[t]here not accepted here"
+msgstr "E393: group[t]here´Â ¿©±â¿¡¼­ »ç¿ëµÉ ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "E394: Didn't find region item for %s"
+msgstr "E394: %s¿¡ ´ëÇÑ region Ç׸ñÀ» ãÁö ¸øÇß½À´Ï´Ù"
+
+msgid "E397: Filename required"
+msgstr "E397: ÆÄÀÏÀ̸§ÀÌ ÇÊ¿äÇÕ´Ï´Ù"
+
+msgid "E847: Too many syntax includes"
+msgstr "E847: ±¸¹® Æ÷ÇÔ(include)ÀÌ ³Ê¹« ¸¹½À´Ï´Ù"
+
+#, c-format
+msgid "E789: Missing ']': %s"
+msgstr "E789: ']' ´©¶ô: %s"
+
+#, c-format
+msgid "E890: trailing char after ']': %s]%s"
+msgstr "E890: ']' µÚ¿¡ ¹®ÀÚ°¡ ´õ ÀÖÀ½: %s]%s"
+
+#, c-format
+msgid "E398: Missing '=': %s"
+msgstr "E398: '=' ´©¶ô: %s"
+
+#, c-format
+msgid "E399: Not enough arguments: syntax region %s"
+msgstr "E399: ÃæºÐÄ¡ ¾ÊÀº ÀÎÀÚ: ±¸¹® ¿µ¿ª %s"
+
+msgid "E848: Too many syntax clusters"
+msgstr "E848: ±¸¹® Ŭ·¯½ºÅÍ°¡ ³Ê¹« ¸¹½À´Ï´Ù"
+
+msgid "E400: No cluster specified"
+msgstr "E400: Ŭ·¯½ºÅÍ°¡ ¸í½ÃµÇÁö ¾Ê¾Ò½À´Ï´Ù"
+
+#, c-format
+msgid "E401: Pattern delimiter not found: %s"
+msgstr "E401: ÆÐÅÏ ±¸ºÐÀÚ¸¦ ãÀ» ¼ö ¾ø½À´Ï´Ù: %s"
+
+#, c-format
+msgid "E402: Garbage after pattern: %s"
+msgstr "E402: ÆÐÅÏ µÚ¿¡ ¾²·¹±â: %s"
+
+msgid "E403: syntax sync: line continuations pattern specified twice"
+msgstr "E403: syntax sync: ÁÙ ¿¬¼Ó ÆÐÅÏÀÌ µÎ ¹ø »ç¿ëµÇ¾ú½À´Ï´Ù"
+
+#, c-format
+msgid "E404: Illegal arguments: %s"
+msgstr "E404: ºñÁ¤»óÀûÀÎ ÀÎÀÚ: %s"
+
+#, c-format
+msgid "E405: Missing equal sign: %s"
+msgstr "E405: ÀÌÄ÷ ±âÈ£°¡ ºüÁ³À½: %s"
+
+#, c-format
+msgid "E406: Empty argument: %s"
+msgstr "E406: ºó ÀÎÀÚ: %s"
+
+#, c-format
+msgid "E407: %s not allowed here"
+msgstr "E407: %sÀº(´Â) ¿©±â¿¡¼­ Çã¿ëµÇÁö ¾Ê½À´Ï´Ù"
+
+#, c-format
+msgid "E408: %s must be first in contains list"
+msgstr "E408: %sÀº(´Â) contains ¸ñ·ÏÀÇ Ã¹ ¹ø°¿©¾ß ÇÕ´Ï´Ù"
+
+#, c-format
+msgid "E409: Unknown group name: %s"
+msgstr "E409: ¸ð¸£´Â ±×·ì À̸§: %s"
+
+#, c-format
+msgid "E410: Invalid :syntax subcommand: %s"
+msgstr "E410: À߸øµÈ :syntax ÇÏÀ§ ¸í·É: %s"
+
+#~ msgid ""
+#~ " TOTAL COUNT MATCH SLOWEST AVERAGE NAME PATTERN"
+#~ msgstr ""
+
+msgid "E679: recursive loop loading syncolor.vim"
+msgstr "E679: syncolor.vim ¹Ýº¹ ·Îµù"
+
+#, c-format
+msgid "E411: highlight group not found: %s"
+msgstr "E411: ÇÏÀ̶óÀÌÆ® ±×·ìÀ» ãÀ» ¼ö ¾ø½À´Ï´Ù: %s"
+
+#, c-format
+msgid "E412: Not enough arguments: \":highlight link %s\""
+msgstr "E412: ÃæºÐÄ¡ ¾ÊÀº ÀÎÀÚ: \":highlight link %s\""
+
+#, c-format
+msgid "E413: Too many arguments: \":highlight link %s\""
+msgstr "E413: ³Ê¹« ¸¹Àº ÀÎÀÚ: \":highlight link %s\""
+
+msgid "E414: group has settings, highlight link ignored"
+msgstr "E414: groupÀÌ ¼³Á¤°ªÀÌ ÀÖ½À´Ï´Ù, highlight link ¹«½ÃµÊ"
+
+#, c-format
+msgid "E415: unexpected equal sign: %s"
+msgstr "E415: ¶æ¹ÛÀÇ ÀÌÄ÷ ±âÈ£: %s"
+
+#, c-format
+msgid "E416: missing equal sign: %s"
+msgstr "E416: ÀÌÄ÷ ±âÈ£°¡ ºüÁ³À½: %s"
+
+#, c-format
+msgid "E417: missing argument: %s"
+msgstr "E417: ÀÎÀÚ°¡ ºüÁ³À½: %s"
+
+#, c-format
+msgid "E418: Illegal value: %s"
+msgstr "E418: ºñÁ¤»óÀûÀÎ °ª: %s"
+
+msgid "E419: FG color unknown"
+msgstr "E419: ¸ð¸£´Â FG »ö»ó"
+
+msgid "E420: BG color unknown"
+msgstr "E420: ¸ð¸£´Â BG »ö»ó"
+
+#, c-format
+msgid "E421: Color name or number not recognized: %s"
+msgstr "E421: »ö À̸§À̳ª ¼ýÀÚ¸¦ ÀνÄÇÒ ¼ö ¾øÀ½: %s"
+
+#, c-format
+msgid "E422: terminal code too long: %s"
+msgstr "E422: Å͹̳ΠÄڵ尡 ³Ê¹« ±è: %s"
+
+#, c-format
+msgid "E423: Illegal argument: %s"
+msgstr "E423: À߸øµÈ ÀÎÀÚ: %s"
+
+msgid "E424: Too many different highlighting attributes in use"
+msgstr "E424: ³Ê¹« ¸¹Àº ´Ù¸¥ ÇÏÀ̶óÀÌÆ® ¼Ó¼ºÀÌ »ç¿ëµÇ°í ÀÖ½À´Ï´Ù"
+
+msgid "E669: Unprintable character in group name"
+msgstr "E669: ±×·ì À̸§¿¡ Ãâ·ÂÇÒ ¼ö ¾ø´Â ¹®ÀÚ°¡ ÀÖ½À´Ï´Ù"
+
+msgid "W18: Invalid character in group name"
+msgstr "W18: ±×·ì À̸§¿¡ ÀÌ»óÇÑ ¹®ÀÚ"
+
+msgid "E849: Too many highlight and syntax groups"
+msgstr "E849: highlight¿Í syntax groupÀÌ ³Ê¹« ¸¹½À´Ï´Ù"
+
+msgid "E555: at bottom of tag stack"
+msgstr "E555: ÅÂ±× ½ºÅÃÀÇ ³¡ÀÔ´Ï´Ù"
+
+msgid "E556: at top of tag stack"
+msgstr "E556: ÅÂ±× ½ºÅÃÀÇ Ã³À½ÀÔ´Ï´Ù"
+
+msgid "E425: Cannot go before first matching tag"
+msgstr "E425: ù ¹ø° ¸Â´Â ÅÂ±× ÀÌÀüÀ¸·Î´Â °¥ ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "E426: tag not found: %s"
+msgstr "E426: ű׸¦ ãÀ» ¼ö ¾øÀ½: %s"
+
+msgid " # pri kind tag"
+msgstr " # pri kind tag"
+
+msgid "file\n"
+msgstr "ÆÄÀÏ\n"
+
+msgid "E427: There is only one matching tag"
+msgstr "E427: ¸Â´Â űװ¡ Çϳª ¹Û¿¡ ¾ø½À´Ï´Ù"
+
+msgid "E428: Cannot go beyond last matching tag"
+msgstr "E428: ¸¶Áö¸· ¸Â´Â ÅÂ±× µÚ·Î´Â °¥ ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "File \"%s\" does not exist"
+msgstr "ÆÄÀÏ \"%s\"ÀÌ(°¡) Á¸ÀçÇÏÁö ¾Ê½À´Ï´Ù"
+
+#, c-format
+msgid "tag %d of %d%s"
+msgstr "tag %d of %d%s"
+
+msgid " or more"
+msgstr " or more"
+
+msgid " Using tag with different case!"
+msgstr " Using tag with different case!"
+
+#, c-format
+msgid "E429: File \"%s\" does not exist"
+msgstr "E429: ÆÄÀÏ \"%s\"ÀÌ(°¡) Á¸ÀçÇÏÁö ¾Ê½À´Ï´Ù"
+
+msgid ""
+"\n"
+" # TO tag FROM line in file/text"
+msgstr ""
+"\n"
+" # TO tag FROM line in file/text"
+
+#, c-format
+msgid "Searching tags file %s"
+msgstr "ÅÂ±× ÆÄÀÏ %s ã´Â Áß"
+
+#, c-format
+msgid "E430: Tag file path truncated for %s\n"
+msgstr "E430: %s¿¡ ´ëÇÑ ÅÂ±× ÆÄÀÏ °æ·Î°¡ À߷ȽÀ´Ï´Ù\n"
+
+msgid "Ignoring long line in tags file"
+msgstr "ÅÂ±× ÆÄÀÏÀÇ ³Ê¹« ±ä ¶óÀÎÀ» ¹«½ÃÇÕ´Ï´Ù"
+
+#, c-format
+msgid "E431: Format error in tags file \"%s\""
+msgstr "E431: ÅÂ±× ÆÄÀÏ \"%s\"¿¡ Çü½Ä ¿¡·¯°¡ ÀÖ½À´Ï´Ù"
+
+#, c-format
+msgid "Before byte %ld"
+msgstr "Before byte %ld"
+
+#, c-format
+msgid "E432: Tags file not sorted: %s"
+msgstr "E432: ÅÂ±× ÆÄÀÏÀÌ Á¤·ÄµÇ¾î ÀÖÁö ¾ÊÀ½: %s"
+
+msgid "E433: No tags file"
+msgstr "E433: ÅÂ±× ÆÄÀÏÀÌ ¾ø½À´Ï´Ù"
+
+msgid "E434: Can't find tag pattern"
+msgstr "E434: ÅÂ±× ÆÐÅÏÀ» ãÀ» ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E435: Couldn't find tag, just guessing!"
+msgstr "E435: ű׸¦ ãÀ» ¼ö ¾øÁö¸¸ ÀÌ°Å °°½À´Ï´Ù!"
+
+#, c-format
+msgid "Duplicate field name: %s"
+msgstr "Áߺ¹µÈ ÇÊµå ¸í: %s"
+
+msgid "' not known. Available builtin terminals are:"
+msgstr "' not known. Available builtin terminals are:"
+
+msgid "defaulting to '"
+msgstr "defaulting to '"
+
+msgid "E557: Cannot open termcap file"
+msgstr "E557: termcap ÆÄÀÏÀ» ¿­ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E558: Terminal entry not found in terminfo"
+msgstr "E558: Å͹̳ΠÇ׸ñÀ» terminfo¿¡¼­ ãÀ» ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E559: Terminal entry not found in termcap"
+msgstr "E559: Å͹̳ΠÇ׸ñÀ» termcap¿¡¼­ ãÀ» ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "E436: No \"%s\" entry in termcap"
+msgstr "E436: termcap¿¡ \"%s\" Ç׸ñÀÌ ¾ø½À´Ï´Ù"
+
+msgid "E437: terminal capability \"cm\" required"
+msgstr "E437: Å͹̳ÎÀÌ \"cm\" ±â´ÉÀ» Áö¿øÇØ¾ß ÇÕ´Ï´Ù"
+
+msgid ""
+"\n"
+"--- Terminal keys ---"
+msgstr ""
+"\n"
+"--- Å͹̳ΠŰ ---"
+
+msgid "Cannot open $VIMRUNTIME/rgb.txt"
+msgstr "$VIMRUNTIME/rgb.txtÀ» ¿­ ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "Kill job in \"%s\"?"
+msgstr "\"%s\"ÀÇ jobÀ» Á×Àϱî¿ä?"
+
+msgid "Terminal"
+msgstr "Terminal"
+
+msgid "Terminal-finished"
+msgstr "Terminal-finished"
+
+msgid "active"
+msgstr "active"
+
+msgid "running"
+msgstr "running"
+
+msgid "finished"
+msgstr "finished"
+
+#, c-format
+msgid "E953: File exists: %s"
+msgstr "E953: ÆÄÀÏÀÌ Á¸ÀçÇÔ: %s"
+
+msgid "E955: Not a terminal buffer"
+msgstr "E955: Å͹̳Π¹öÆÛ°¡ ¾Æ´Õ´Ï´Ù"
+
+msgid "new shell started\n"
+msgstr "»õ ½©ÀÌ ½ÃÀ۵Ǿú½À´Ï´Ù\n"
+
+msgid "Vim: Error reading input, exiting...\n"
+msgstr "ºö: ÀÔ·Â Àд Áß ¿¡·¯, ³¡³»´ÂÁß...\n"
+
+msgid "Used CUT_BUFFER0 instead of empty selection"
+msgstr "ºó °í¸£±â ´ë½Å CUT_BUFFER0À» »ç¿ëÇß½À´Ï´Ù"
+
+msgid "E881: Line count changed unexpectedly"
+msgstr "E881: Çà °¹¼ö°¡ °©Àڱ⠹ٲî¾ú½À´Ï´Ù"
+
+msgid "No undo possible; continue anyway"
+msgstr "Ãë¼Ò ºÒ°¡´É; ¾î·µç °è¼ÓÇÕ´Ï´Ù"
+
+#, c-format
+msgid "E828: Cannot open undo file for writing: %s"
+msgstr "E828: ¾²±â À§ÇØ undoÀ» ¿­ ¼ö ¾ø½À´Ï´Ù: %s"
+
+#, c-format
+msgid "E825: Corrupted undo file (%s): %s"
+msgstr "E825: ±úÁø undo ÆÄÀÏ (%s): %s"
+
+msgid "Cannot write undo file in any directory in 'undodir'"
+msgstr "'undodir'¿¡ ÀÖ´Â ¾î¶² µð·ºÅ丮¿¡µµ undo ÆÄÀÏÀ» ¾µ ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "Will not overwrite with undo file, cannot read: %s"
+msgstr "ÀÐÀ» ¼ö°¡ ¾ø¾î¼­ undo ÆÄÀÏ¿¡ µ¤¾î¾µ ¼ö ¾ø½À´Ï´Ù: %s"
+
+#, c-format
+msgid "Will not overwrite, this is not an undo file: %s"
+msgstr "undo ÆÄÀÏÀÌ ¾Æ´Ï¾î¼­ µ¤¾î¾µ ¼ö ¾ø½À´Ï´Ù: %s"
+
+msgid "Skipping undo file write, nothing to undo"
+msgstr "undoÇÒ ³»¿ëÀÌ ¾ø¾î¼­ undo ÆÄÀÏ ÀúÀåÀ» °Ç³Ê¶Ý´Ï´Ù"
+
+#, c-format
+msgid "Writing undo file: %s"
+msgstr "undo ÆÄÀÏ ¾²´Â Áß: %s"
+
+#, c-format
+msgid "E829: write error in undo file: %s"
+msgstr "E829: undo ÆÄÀÏ ¾²±â ¿¡·¯: %s"
+
+#, c-format
+msgid "Not reading undo file, owner differs: %s"
+msgstr "¼ÒÀ¯ÀÚ°¡ ´Þ¶ó¼­ undo ÆÄÀÏÀ» ÀÐÁö ¾Ê½À´Ï´Ù: %s"
+
+#, c-format
+msgid "Reading undo file: %s"
+msgstr "undo ÆÄÀÏ Àд Áß: %s"
+
+#, c-format
+msgid "E822: Cannot open undo file for reading: %s"
+msgstr "E822: Àбâ À§ÇØ undo ÆÄÀÏÀ» ¿­ ¼ö ¾ø½À´Ï´Ù: %s"
+
+#, c-format
+msgid "E823: Not an undo file: %s"
+msgstr "E823: undo ÆÄÀÏÀÌ ¾Æ´Õ´Ï´Ù: %s"
+
+#, c-format
+msgid "E832: Non-encrypted file has encrypted undo file: %s"
+msgstr "E832: ¾ÏȣȭµÇÁö ¾ÊÀº ÆÄÀÏÀÌ ¾ÏȣȭµÈ undo ÆÄÀÏÀ» °¡Áö°í ÀÖ½À´Ï´Ù: %s"
+
+#, c-format
+msgid "E826: Undo file decryption failed: %s"
+msgstr "E826: Undo ÆÄÀÏÀ» Çص¶ÇÒ ¼ö ¾ø½À´Ï´Ù: %s"
+
+#, c-format
+msgid "E827: Undo file is encrypted: %s"
+msgstr "E827: Undo ÆÄÀÏÀÌ ¾ÏȣȭµÇ¾ú½À´Ï´Ù: %s"
+
+#, c-format
+msgid "E824: Incompatible undo file: %s"
+msgstr "E824: ȣȯµÇÁö ¾Ê´Â undo ÆÄÀÏ: %s"
+
+msgid "File contents changed, cannot use undo info"
+msgstr "ÆÄÀÏ ³»¿ëÀÌ ¹Ù²î¾î¼­, undo Á¤º¸¸¦ »ç¿ëÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "Finished reading undo file %s"
+msgstr "undo ÆÄÀÏ %sÀ»(¸¦) Àоîµé¿´½À´Ï´Ù"
+
+msgid "Already at oldest change"
+msgstr "´õ ÀÌ»óÀÇ ¼öÁ¤ÀÌ ¾ø¾ú½À´Ï´Ù"
+
+msgid "Already at newest change"
+msgstr "´õ ÀÌ»óÀÇ ¼öÁ¤Àº ¾ø¾ú½À´Ï´Ù"
+
+#, c-format
+msgid "E830: Undo number %ld not found"
+msgstr "E830: Undo ¹øÈ£ %ld¸¦ ãÀ» ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E438: u_undo: line numbers wrong"
+msgstr "E438: u_undo: À߸øµÈ ÁÙ ¹øÈ£"
+
+msgid "more line"
+msgstr "more line"
+
+msgid "more lines"
+msgstr "more lines"
+
+msgid "line less"
+msgstr "line less"
+
+msgid "fewer lines"
+msgstr "fewer lines"
+
+msgid "change"
+msgstr "change"
+
+msgid "changes"
+msgstr "changes"
+
+#, c-format
+msgid "%ld %s; %s #%ld %s"
+msgstr "%ld %s; %s #%ld %s"
+
+msgid "before"
+msgstr "before"
+
+msgid "after"
+msgstr "after"
+
+msgid "Nothing to undo"
+msgstr "Ãë¼ÒÇÒ °Ô ¾ø½À´Ï´Ù"
+
+#~ msgid "number changes when saved"
+#~ msgstr ""
+
+#, c-format
+msgid "%ld seconds ago"
+msgstr "%ld seconds ago"
+
+msgid "E790: undojoin is not allowed after undo"
+msgstr "E790: undo µÚ¿¡ undojoinÀº ÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E439: undo list corrupt"
+msgstr "E439: undo ¸ñ·ÏÀÌ ±úÁ³½À´Ï´Ù"
+
+msgid "E440: undo line missing"
+msgstr "E440: undo ÁÙÀÌ ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "E122: Function %s already exists, add ! to replace it"
+msgstr "E122: ÇÔ¼ö %sÀÌ(°¡) ÀÌ¹Ì ÀÖ½À´Ï´Ù, ¹Ù²Ù·Á¸é !À» ´õÇϼ¼¿ä"
+
+msgid "E717: Dictionary entry already exists"
+msgstr "E717: ÀÌ¹Ì Dictionary Ç׸ñÀÌ ÀÖ½À´Ï´Ù"
+
+msgid "E718: Funcref required"
+msgstr "E718: Funcref°¡ ÇÊ¿äÇÕ´Ï´Ù"
+
+#, c-format
+msgid "E130: Unknown function: %s"
+msgstr "E130: ¸ð¸£´Â ÇÔ¼ö: %s"
+
+#, c-format
+msgid "E125: Illegal argument: %s"
+msgstr "E125: À߸øµÈ ÀÎÀÚ: %s"
+
+#, c-format
+msgid "E853: Duplicate argument name: %s"
+msgstr "E853: Áߺ¹µÈ ÀÎÀÚ À̸§: %s"
+
+#, c-format
+msgid "E740: Too many arguments for function %s"
+msgstr "E740: ÇÔ¼ö %s¿¡ ³Ê¹« ¸¹Àº ÀÎÀÚ°¡ Àü´ÞµÇ¾ú½À´Ï´Ù"
+
+#, c-format
+msgid "E116: Invalid arguments for function %s"
+msgstr "E116: ÇÔ¼ö %s(À¸)·Î À߸øµÈ ÀÎÀÚ°¡ ³Ñ°ÜÁ³½À´Ï´Ù"
+
+msgid "E132: Function call depth is higher than 'maxfuncdepth'"
+msgstr "E132: ÇÔ¼ö¸¦ ºÎ¸¥ ±íÀÌ°¡ 'maxfuncdepth'º¸´Ù Å®´Ï´Ù"
+
+#, c-format
+msgid "calling %s"
+msgstr "%s ºÎ¸£´Â Áß"
+
+#, c-format
+msgid "%s aborted"
+msgstr "%sÀÌ(°¡) ÁßÁöµÇ¾ú½À´Ï´Ù"
+
+#, c-format
+msgid "%s returning #%ld"
+msgstr "%sÀÌ(°¡) #%ldÀ»(¸¦) µ¹·ÁÁÖ¾ú½À´Ï´Ù"
+
+#, c-format
+msgid "%s returning %s"
+msgstr "%sÀÌ(°¡) %sÀ»(¸¦) µ¹·ÁÁÖ¾ú½À´Ï´Ù"
+
+msgid "E699: Too many arguments"
+msgstr "E699: ³Ê¹« ¸¹Àº ÀÎÀÚ"
+
+#, c-format
+msgid "E117: Unknown function: %s"
+msgstr "E117: ¸ð¸£´Â ÇÔ¼ö: %s"
+
+#, c-format
+msgid "E933: Function was deleted: %s"
+msgstr "E933: ÇÔ¼ö°¡ »èÁ¦µÊ: %s"
+
+#, c-format
+msgid "E119: Not enough arguments for function: %s"
+msgstr "E119: ÇÔ¼ö¿¡ ÀûÀº ÀÎÀÚ ³Ñ±è: %s"
+
+#, c-format
+msgid "E120: Using <SID> not in a script context: %s"
+msgstr "E120: ½ºÅ©¸³Æ® ÄÜÅؽºÆ® ¹Û¿¡¼­ <SID> »ç¿ë: %s"
+
+#, c-format
+msgid "E725: Calling dict function without Dictionary: %s"
+msgstr "E725: Dictionary¾øÀÌ »çÀüÇÔ¼ö°¡ ºÒ·ÁÁü: %s"
+
+msgid "E129: Function name required"
+msgstr "E129: ÇÔ¼ö À̸§ÀÌ ÇÊ¿äÇÕ´Ï´Ù"
+
+#, c-format
+msgid "E128: Function name must start with a capital or \"s:\": %s"
+msgstr "E128: ÇÔ¼ö À̸§Àº ´ë¹®ÀÚ È¤Àº \"s:\"·Î ½ÃÀÛÇØ¾ß ÇÔ: %s"
+
+#, c-format
+msgid "E884: Function name cannot contain a colon: %s"
+msgstr "E884: ÇÔ¼ö À̸§Àº ÄÝ·ÐÀ» Æ÷ÇÔÇÒ ¼ö ¾øÀ½: %s"
+
+#, c-format
+msgid "E123: Undefined function: %s"
+msgstr "E123: Á¤ÀÇ ¾È µÈ ÇÔ¼ö: %s"
+
+#, c-format
+msgid "E124: Missing '(': %s"
+msgstr "E124: '('°¡ ¾øÀ½: %s"
+
+msgid "E862: Cannot use g: here"
+msgstr "E862: ¿©±â¿¡¼­ g:À» »ç¿ëÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "E932: Closure function should not be at top level: %s"
+msgstr "E932: Closure ÇÔ¼ö´Â ÃÖ»óÀ§ ·¹º§ÀÏ ¼ö ¾ø½À´Ï´Ù: %s"
+
+msgid "E126: Missing :endfunction"
+msgstr "E126: :endfunctionÀÌ ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "W22: Text found after :endfunction: %s"
+msgstr "W22: :endfunction µÚ¿¡ ¹®ÀÚ¿­ÀÌ ÀÖÀ½: %s"
+
+#, c-format
+msgid "E707: Function name conflicts with variable: %s"
+msgstr "E707: ÇÔ¼ö¸íÀÌ º¯¼ö¸í°ú Ãæµ¹: %s"
+
+#, c-format
+msgid "E127: Cannot redefine function %s: It is in use"
+msgstr "E127: ÇÔ¼ö %sÀ»(¸¦) ´Ù½Ã Á¤ÀÇÇÒ ¼ö ¾ø½À´Ï´Ù: »ç¿ëÁßÀÔ´Ï´Ù"
+
+#, c-format
+msgid "E746: Function name does not match script file name: %s"
+msgstr "E746: ÇÔ¼ö¸íÀÌ ½ºÅ©¸³Æ® ÆÄÀϸí°ú ´Ù¸§: %s"
+
+#, c-format
+msgid "E131: Cannot delete function %s: It is in use"
+msgstr "E131: ÇÔ¼ö %sÀ»(¸¦) Áö¿ï ¼ö ¾ø½À´Ï´Ù: »ç¿ëÁßÀÔ´Ï´Ù"
+
+msgid "E133: :return not inside a function"
+msgstr "E133: :returnÀÌ ÇÔ¼ö ¾È¿¡ ÀÖÁö ¾Ê½À´Ï´Ù"
+
+#, c-format
+msgid "E107: Missing parentheses: %s"
+msgstr "E107: °ýÈ£ ¾øÀ½: %s"
+
+#, c-format
+msgid "%s (%s, compiled %s)"
+msgstr "%s (%s, ºôµåÇÑ ³¯Â¥ %s)"
+
+msgid ""
+"\n"
+"MS-Windows 64-bit GUI version"
+msgstr ""
+"\n"
+"MS-Windows 64ºñÆ® GUI ¹öÁ¯"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit GUI version"
+msgstr ""
+"\n"
+"MS-Windows 32ºñÆ® GUI ¹öÁ¯"
+
+msgid " with OLE support"
+msgstr " OLE Áö¿ø"
+
+msgid ""
+"\n"
+"MS-Windows 64-bit console version"
+msgstr ""
+"\n"
+"MS-Windows 64ºñÆ® ÄÜ¼Ö ¹öÁ¯"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit console version"
+msgstr ""
+"\n"
+"MS-Windows 32ºñÆ® ÄÜ¼Ö ¹öÁ¯"
+
+msgid ""
+"\n"
+"macOS version"
+msgstr ""
+"\n"
+"macOS ¹öÁ¯"
+
+#~ msgid ""
+#~ "\n"
+#~ "macOS version w/o darwin feat."
+#~ msgstr ""
+
+msgid ""
+"\n"
+"OpenVMS version"
+msgstr ""
+"\n"
+"OpenVMS ¹öÁ¯"
+
+msgid ""
+"\n"
+"Included patches: "
+msgstr ""
+"\n"
+"Æ÷ÇÔµÈ ÆÐÄ¡: "
+
+msgid ""
+"\n"
+"Extra patches: "
+msgstr ""
+"\n"
+"º°µµÀÇ ÆÐÄ¡: "
+
+msgid "Modified by "
+msgstr "Modified by "
+
+msgid ""
+"\n"
+"Compiled "
+msgstr ""
+"\n"
+"Compiled "
+
+msgid "by "
+msgstr "by "
+
+msgid ""
+"\n"
+"Huge version "
+msgstr ""
+"\n"
+"Huge ¹öÁ¯ "
+
+msgid ""
+"\n"
+"Big version "
+msgstr ""
+"\n"
+"Big ¹öÁ¯ "
+
+msgid ""
+"\n"
+"Normal version "
+msgstr ""
+"\n"
+"Normal ¹öÁ¯ "
+
+msgid ""
+"\n"
+"Small version "
+msgstr ""
+"\n"
+"Small ¹öÁ¯ "
+
+msgid ""
+"\n"
+"Tiny version "
+msgstr ""
+"\n"
+"Tiny ¹öÁ¯ "
+
+msgid "without GUI."
+msgstr "GUI ¾øÀ½."
+
+msgid "with GTK3 GUI."
+msgstr "GTK3 GUI."
+
+msgid "with GTK2-GNOME GUI."
+msgstr "GTK2-GNOME GUI."
+
+msgid "with GTK2 GUI."
+msgstr "GTK2 GUI."
+
+msgid "with X11-Motif GUI."
+msgstr "X11-Motif GUI."
+
+msgid "with X11-neXtaw GUI."
+msgstr "X11-neXtaw GUI."
+
+msgid "with X11-Athena GUI."
+msgstr "X11-Athena GUI."
+
+msgid "with Photon GUI."
+msgstr "Photon GUI."
+
+msgid "with GUI."
+msgstr "GUI."
+
+msgid "with Carbon GUI."
+msgstr "Carbon GUI."
+
+msgid "with Cocoa GUI."
+msgstr "Cocoa GUI."
+
+msgid " Features included (+) or not (-):\n"
+msgstr " ±â´É (+: Æ÷ÇÔµÊ, -: Æ÷ÇÔ ¾È µÊ):\n"
+
+msgid " system vimrc file: \""
+msgstr " ½Ã½ºÅÛ vimrc ÆÄÀÏ: \""
+
+msgid " user vimrc file: \""
+msgstr " »ç¿ëÀÚ vimrc ÆÄÀÏ: \""
+
+msgid " 2nd user vimrc file: \""
+msgstr " »ç¿ëÀÚ µÎ ¹ø° vimrc ÆÄÀÏ: \""
+
+msgid " 3rd user vimrc file: \""
+msgstr " »ç¿ëÀÚ ¼¼ ¹ø° vimrc ÆÄÀÏ: \""
+
+msgid " user exrc file: \""
+msgstr " »ç¿ëÀÚ exrc ÆÄÀÏ: \""
+
+msgid " 2nd user exrc file: \""
+msgstr " »ç¿ëÀÚ µÎ ¹ø° exrc ÆÄÀÏ: \""
+
+msgid " system gvimrc file: \""
+msgstr " ½Ã½ºÅÛ gvimrc ÆÄÀÏ: \""
+
+msgid " user gvimrc file: \""
+msgstr " »ç¿ëÀÚ gvimrc ÆÄÀÏ: \""
+
+msgid "2nd user gvimrc file: \""
+msgstr "»ç¿ëÀÚ µÎ ¹ø° gvimrc ÆÄÀÏ: \""
+
+msgid "3rd user gvimrc file: \""
+msgstr "»ç¿ëÀÚ ¼¼ ¹ø° gvimrc ÆÄÀÏ: \""
+
+msgid " defaults file: \""
+msgstr " defaults ÆÄÀÏ: \""
+
+msgid " system menu file: \""
+msgstr " ½Ã½ºÅÛ ¸Þ´º ÆÄÀÏ: \""
+
+msgid " fall-back for $VIM: \""
+msgstr " fall-back for $VIM: \""
+
+msgid " f-b for $VIMRUNTIME: \""
+msgstr " f-b for $VIMRUNTIME: \""
+
+msgid "Compilation: "
+msgstr "ÄÄÆÄÀÏ: "
+
+msgid "Compiler: "
+msgstr "ÄÄÆÄÀÏ·¯: "
+
+msgid "Linking: "
+msgstr "¸µÅ©: "
+
+msgid " DEBUG BUILD"
+msgstr " µð¹ö±× ºôµå"
+
+msgid "VIM - Vi IMproved"
+msgstr "ºö - Çâ»óµÈ Vi"
+
+msgid "version "
+msgstr "ÆÇ "
+
+msgid "by Bram Moolenaar et al."
+msgstr "by Bram Moolenaar et al."
+
+msgid "Vim is open source and freely distributable"
+msgstr "ºöÀº ´©±¸³ª ¼Ò½º¸¦ º¼ ¼ö ÀÖ°í °øÂ¥·Î ¹èÆ÷µË´Ï´Ù"
+
+msgid "Help poor children in Uganda!"
+msgstr "¿ì°£´Ù¿¡ »ç´Â °¡³­ÇÑ ¾ÆÀ̸¦ µµ¿ÍÁÖ¼¼¿ä!"
+
+msgid "type :help iccf<Enter> for information "
+msgstr "ÀÌ¿¡ ´ëÇÑ Á¤º¸¸¦ º¸·Á¸é :help iccf<¿£ÅÍ> ÀÔ·Â"
+
+msgid "type :q<Enter> to exit "
+msgstr "³¡³»·Á¸é :q<¿£ÅÍ> ÀÔ·Â"
+
+msgid "type :help<Enter> or <F1> for on-line help"
+msgstr "¿Â¶óÀÎ µµ¿ò¸»À» º¸·Á¸é :help<¿£ÅÍ> ¶Ç´Â <F1> ÀÔ·Â"
+
+msgid "type :help version8<Enter> for version info"
+msgstr "ÆÇ Á¤º¸¸¦ º¸·Á¸é :help version8<¿£ÅÍ> ÀÔ·Â"
+
+msgid "Running in Vi compatible mode"
+msgstr "Vi ȣȯ »óÅ·Π½ÇÇàÁßÀÔ´Ï´Ù"
+
+msgid "type :set nocp<Enter> for Vim defaults"
+msgstr "ºö ±âº»°ªÀ» »ç¿ëÇÏ·Á¸é :set nocp<¿£ÅÍ> ÀÔ·Â"
+
+msgid "type :help cp-default<Enter> for info on this"
+msgstr "ÀÌ¿¡ ´ëÇÑ Á¤º¸¸¦ º¸·Á¸é :help cp-default<¿£ÅÍ> ÀÔ·Â"
+
+msgid "menu Help->Orphans for information "
+msgstr "ÀÌ¿¡ ´ëÇÑ Á¤º¸¸¦ º¸·Á¸é ¸Þ´º¿¡¼­ µµ¿ò¸»->°í¾Æ ¼±ÅÃ"
+
+msgid "Running modeless, typed text is inserted"
+msgstr "¸ðµå¾øÀÌ ¼öÇàÁßÀ̸ç, ÀÔ·ÂµÈ ¹®ÀÚ´Â »ðÀԵ˴ϴÙ"
+
+msgid "menu Edit->Global Settings->Toggle Insert Mode "
+msgstr "¸Þ´º¿¡¼­ ÆíÁý->Àü¿ª ¼³Á¤->»ðÀÔ ¸ðµå Åä±ÛÀ» ¼±ÅÃÇϽøé "
+
+msgid " for two modes "
+msgstr " µÎ ¸ðµå¸¦ »ç¿ëÇÒ ¼ö ÀÖ½À´Ï´Ù "
+
+msgid "menu Edit->Global Settings->Toggle Vi Compatible"
+msgstr "¸Þ´º¿¡¼­ ÆíÁý->Àü¿ª ¼³Á¤->Vi ȣȯ Åä±ÛÀ» ¼±ÅÃÇϽøé "
+
+msgid " for Vim defaults "
+msgstr " VimÀÌ ±âº»°ªÀ¸·Î µ¿ÀÛÇÕ´Ï´Ù "
+
+msgid "Sponsor Vim development!"
+msgstr "ºö °³¹ßÀ» ÈÄ¿øÇØ ÁÖ¼¼¿ä!"
+
+msgid "Become a registered Vim user!"
+msgstr "ºö »ç¿ëÀÚ·Î µî·ÏÇϼ¼¿ä!"
+
+msgid "type :help sponsor<Enter> for information "
+msgstr "ÀÌ¿¡ ´ëÇÑ Á¤º¸¸¦ º¸·Á¸é :help sponsor<¿£ÅÍ> ÀÔ·Â"
+
+msgid "type :help register<Enter> for information "
+msgstr "ÀÌ¿¡ ´ëÇÑ Á¤º¸¸¦ º¸·Á¸é :help register<¿£ÅÍ> ÀÔ·Â"
+
+msgid "menu Help->Sponsor/Register for information "
+msgstr "ÀÌ¿¡ ´ëÇÑ Á¤º¸¸¦ º¸·Á¸é ¸Þ´º µµ¿ò¸»->Sponsor/Register"
+
+msgid "Already only one window"
+msgstr "ÀÌ¹Ì ÇϳªÀÇ Ã¢¸¸ ÀÖ½À´Ï´Ù"
+
+msgid "E441: There is no preview window"
+msgstr "E441: ¹Ì¸® º¸±â âÀÌ ¾ø½À´Ï´Ù"
+
+msgid "E442: Can't split topleft and botright at the same time"
+msgstr "E442: À§ ¿ÞÂÊ°ú ¾Æ·¡ ¿À¸¥ÂÊÀ» µ¿½Ã¿¡ ³ª´­ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E443: Cannot rotate when another window is split"
+msgstr "E443: ´Ù¸¥ âÀÌ ³ª´²Á³À» ¶§¿¡´Â ȸÀüÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E444: Cannot close last window"
+msgstr "E444: ¸¶Áö¸· âÀ» ´ÝÀ» ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E813: Cannot close autocmd window"
+msgstr "E813: autocmd âÀ» ´ÝÀ» ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E814: Cannot close window, only autocmd window would remain"
+msgstr "E814: âÀ» ´ÝÀ» ¼ö ¾øÀ½, autocmd ⸸ ³²À½"
+
+msgid "E445: Other window contains changes"
+msgstr "E445: ´Ù¸¥ âÀÌ ¹Ù²î¾ú½À´Ï´Ù"
+
+msgid "E446: No file name under cursor"
+msgstr "E446: Ä¿¼­ ¹Ø¿¡ ÆÄÀÏ À̸§ÀÌ ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "E447: Can't find file \"%s\" in path"
+msgstr "E447: path¿¡¼­ \"%s\" ÆÄÀÏÀ» ãÀ» ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "E799: Invalid ID: %ld (must be greater than or equal to 1)"
+msgstr "E799: ºñÁ¤»óÀûÀÎ ID: %ld (1º¸´Ù Å©°Å³ª °°¾Æ¾ß ÇÕ´Ï´Ù)"
+
+#, c-format
+#~ msgid "E801: ID already taken: %ld"
+#~ msgstr ""
+
+msgid "List or number required"
+msgstr "List³ª number°¡ ÇÊ¿äÇÕ´Ï´Ù"
+
+#, c-format
+msgid "E802: Invalid ID: %ld (must be greater than or equal to 1)"
+msgstr "E802: ºñÁ¤»óÀûÀÎ ID: %ld (1º¸´Ù Å©°Å³ª °°¾Æ¾ß ÇÕ´Ï´Ù)"
+
+#, c-format
+msgid "E803: ID not found: %ld"
+msgstr "E803: ID¸¦ ãÀ» ¼ö ¾øÀ½: %ld"
+
+#, c-format
+msgid "E370: Could not load library %s"
+msgstr "E370: %s ¶óÀ̺귯¸®¸¦ ·ÎµåÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "Sorry, this command is disabled: the Perl library could not be loaded."
+msgstr ""
+"¹Ì¾ÈÇÕ´Ï´Ù, ÀÌ ¸í·ÉÀº »ç¿ëÇÒ ¼ö ¾ø½À´Ï´Ù, Perl ¶óÀ̺귯¸®¸¦ ·ÎµùÇÒ ¼ö ¾ø½À´Ï"
+"´Ù."
+
+msgid "E299: Perl evaluation forbidden in sandbox without the Safe module"
+msgstr "E299: Safe ¸ðµâ¾øÀÌ´Â sandbox¿¡¼­ Perl evaluationÀÌ Á¦Çѵ˴ϴÙ"
+
+msgid "Edit with &multiple Vims"
+msgstr "¿©·¯ ºöÀ¸·Î ÆíÁý(&M)"
+
+msgid "Edit with single &Vim"
+msgstr "ÇϳªÀÇ ºöÀ¸·Î¸¸ ÆíÁý(&V)"
+
+msgid "Diff with Vim"
+msgstr "ºöÀ¸·Î Diff"
+
+msgid "Edit with &Vim"
+msgstr "ºöÀ¸·Î ÆíÁý(&V)"
+
+msgid "Edit with existing Vim - "
+msgstr "ÇϳªÀÇ ºöÀ¸·Î¸¸ ÆíÁý - "
+
+msgid "Edits the selected file(s) with Vim"
+msgstr "¼±ÅÃµÈ ÆÄÀÏ(µé)À» ºöÀ¸·Î ÆíÁý"
+
+msgid "Error creating process: Check if gvim is in your path!"
+msgstr "ÇÁ·Î¼¼½º »ý¼º ¿¡·¯: gvimÀÌ path¿¡ ÀÖ´Â Áö È®ÀÎÇϼ¼¿ä!"
+
+msgid "gvimext.dll error"
+msgstr "gvimext.dll ¿¡·¯"
+
+msgid "Path length too long!"
+msgstr "°æ·Î°¡ ³Ê¹« ±é´Ï´Ù"
+
+msgid "--No lines in buffer--"
+msgstr "--¹öÆÛ¿¡ ÁÙ ¾øÀ½--"
+
+msgid "E470: Command aborted"
+msgstr "E470: ¸í·ÉÀÌ ÁßÁöµÇ¾ú½À´Ï´Ù"
+
+msgid "E471: Argument required"
+msgstr "E471: ÀÎÀÚ°¡ ÇÊ¿äÇÕ´Ï´Ù"
+
+msgid "E10: \\ should be followed by /, ? or &"
+msgstr "E10: /, ? ȤÀº &´Â \\ µÚ¿¡ ¿Í¾ß ÇÕ´Ï´Ù"
+
+msgid "E11: Invalid in command-line window; <CR> executes, CTRL-C quits"
+msgstr "E11: ¸í·ÉÁ٠â¿¡ À߸øµÊ; <CR> ½ÇÇà, CTRL-C ³¡³»±â"
+
+msgid "E12: Command not allowed from exrc/vimrc in current dir or tag search"
+msgstr ""
+"E12: ÇöÀç µð·ºÅ丮 ¶Ç´Â ÅÂ±× Ã£±â¿¡¼­ exrc/vimrc¿¡¼­ÀÇ ¸í·ÉÀº Çã¿ë ¾È µË´Ï´Ù"
+
+msgid "E171: Missing :endif"
+msgstr "E171: :endif°¡ ¾ø½À´Ï´Ù"
+
+msgid "E600: Missing :endtry"
+msgstr "E600: :endtry°¡ ¾ø½À´Ï´Ù"
+
+msgid "E170: Missing :endwhile"
+msgstr "E170: :endwhileÀÌ ¾ø½À´Ï´Ù"
+
+msgid "E170: Missing :endfor"
+msgstr "E170: :endfor ´©¶ô"
+
+msgid "E588: :endwhile without :while"
+msgstr "E588: :while¾øÀÌ :endwhileÀÌ ÀÖ½À´Ï´Ù"
+
+msgid "E588: :endfor without :for"
+msgstr "E588: :for ¾ø´Â :endfor"
+
+msgid "E13: File exists (add ! to override)"
+msgstr "E13: ÆÄÀÏÀÌ ÀÖ½À´Ï´Ù (µ¤¾î¾²·Á¸é ! »ç¿ë)"
+
+msgid "E472: Command failed"
+msgstr "E472: ¸í·ÉÀÌ ½ÇÆÐÇß½À´Ï´Ù"
+
+#, c-format
+msgid "E234: Unknown fontset: %s"
+msgstr "E234: ¸ð¸£´Â ±Û²Ã¼Â: %s"
+
+#, c-format
+msgid "E235: Unknown font: %s"
+msgstr "E235: ¸ð¸£´Â ±Û²Ã: %s"
+
+#, c-format
+msgid "E236: Font \"%s\" is not fixed-width"
+msgstr "E236: ±Û²Ã \"%s\"Àº(´Â) °íÁ¤³ÐÀÌ°¡ ¾Æ´Õ´Ï´Ù"
+
+msgid "E473: Internal error"
+msgstr "E473: ³»ºÎ ¿¡·¯"
+
+#, c-format
+msgid "E685: Internal error: %s"
+msgstr "E685: ³»ºÎ ¿¡·¯: %s"
+
+msgid "Interrupted"
+msgstr "ÁߴܵǾú½À´Ï´Ù"
+
+msgid "E14: Invalid address"
+msgstr "E14: À߸øµÈ ÁÖ¼Ò"
+
+msgid "E474: Invalid argument"
+msgstr "E474: À߸øµÈ ÀÎÀÚ"
+
+#, c-format
+msgid "E475: Invalid argument: %s"
+msgstr "E475: À߸øµÈ ÀÎÀÚ: %s"
+
+#, c-format
+msgid "E475: Invalid value for argument %s"
+msgstr "E475: ÀÎÀÚ %s¿¡ À߸øµÈ °ª"
+
+#, c-format
+msgid "E475: Invalid value for argument %s: %s"
+msgstr "E475: ÀÎÀÚ %s¿¡ À߸øµÈ °ª: %s"
+
+#, c-format
+msgid "E15: Invalid expression: %s"
+msgstr "E15: À߸øµÈ Ç¥Çö½Ä: %s"
+
+msgid "E16: Invalid range"
+msgstr "E16: À߸øµÈ ¹üÀ§"
+
+msgid "E476: Invalid command"
+msgstr "E476: À߸øµÈ ¸í·É"
+
+#, c-format
+msgid "E17: \"%s\" is a directory"
+msgstr "E17: \"%s\"Àº(´Â) µð·ºÅ丮ÀÔ´Ï´Ù"
+
+#, c-format
+msgid "E364: Library call failed for \"%s()\""
+msgstr "E364: ¶óÀ̺귯¸® \"%s()\" ºÎ¸£±â ½ÇÆÐ"
+
+msgid "E667: Fsync failed"
+msgstr "E667: Fsync°¡ ½ÇÆÐÇß½À´Ï´Ù"
+
+#, c-format
+msgid "E448: Could not load library function %s"
+msgstr "E448: %s ¶óÀ̺귯¸® ÇÔ¼ö¸¦ ·ÎµåÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E19: Mark has invalid line number"
+msgstr "E19: ¸¶Å©°¡ À߸øµÈ ÁÙ ¹øÈ£¸¦ °¡Áö°í ÀÖ½À´Ï´Ù"
+
+msgid "E20: Mark not set"
+msgstr "E20: ¸¶Å©°¡ ¼³Á¤µÇ¾î ÀÖÁö ¾Ê½À´Ï´Ù"
+
+msgid "E21: Cannot make changes, 'modifiable' is off"
+msgstr "E21: ¹Ù²Ü ¼ö ¾øÀ½, 'modifiable'ÀÌ ²¨Á®ÀÖ½À´Ï´Ù"
+
+msgid "E22: Scripts nested too deep"
+msgstr "E22: ½ºÅ©¸³Æ®°¡ ³Ê¹« ±í°Ô ÁßøµÇ¾ú½À´Ï´Ù"
+
+msgid "E23: No alternate file"
+msgstr "E23: ´Ù¸¥ ÆÄÀÏÀÌ ¾ø½À´Ï´Ù"
+
+msgid "E24: No such abbreviation"
+msgstr "E24: ±×·± ¾à¾î´Â ¾ø½À´Ï´Ù"
+
+msgid "E477: No ! allowed"
+msgstr "E477: !Àº Çã¿ëµÇÁö ¾Ê½À´Ï´Ù"
+
+msgid "E25: GUI cannot be used: Not enabled at compile time"
+msgstr "E25: GUI´Â »ç¿ëÇÒ ¼ö ¾ø½À´Ï´Ù: ÄÄÆÄÀÏ ¶§ Æ÷ÇÔµÇÁö ¾Ê¾Ò½À´Ï´Ù"
+
+msgid "E26: Hebrew cannot be used: Not enabled at compile time\n"
+msgstr "E26: Hebrew´Â »ç¿ëÇÒ ¼ö ¾ø½À´Ï´Ù: ÄÄÆÄÀÏ ¶§ Æ÷ÇÔµÇÁö ¾Ê¾Ò½À´Ï´Ù\n"
+
+msgid "E27: Farsi cannot be used: Not enabled at compile time\n"
+msgstr "E27: Farsi´Â »ç¿ëÇÒ ¼ö ¾ø½À´Ï´Ù: ÄÄÆÄÀÏ ¶§ Æ÷ÇÔµÇÁö ¾Ê¾Ò½À´Ï´Ù\n"
+
+msgid "E800: Arabic cannot be used: Not enabled at compile time\n"
+msgstr "E800: ArabicÀº »ç¿ëÇÒ ¼ö ¾ø½À´Ï´Ù: ÄÄÆÄÀÏ ¶§ Æ÷ÇÔµÇÁö ¾Ê¾Ò½À´Ï´Ù\n"
+
+#, c-format
+msgid "E28: No such highlight group name: %s"
+msgstr "E28: ÀÌ·± ÇÏÀ̶óÀÌÆ® ±×·ì À̸§Àº ¾ø½À´Ï´Ù: %s"
+
+msgid "E29: No inserted text yet"
+msgstr "E29: ÀÔ·ÂµÈ ÅؽºÆ®°¡ ¾ÆÁ÷ ¾ø½À´Ï´Ù"
+
+msgid "E30: No previous command line"
+msgstr "E30: ÀÌÀü ¸í·É ÁÙÀÌ ¾ø½À´Ï´Ù"
+
+msgid "E31: No such mapping"
+msgstr "E31: ±×·± ¸ÊÇÎÀÌ ¾ø½À´Ï´Ù"
+
+msgid "E479: No match"
+msgstr "E479: ¸ÂÁö ¾Ê½À´Ï´Ù"
+
+#, c-format
+msgid "E480: No match: %s"
+msgstr "E480: ¸ÂÁö ¾ÊÀ½: %s"
+
+msgid "E32: No file name"
+msgstr "E32: ÆÄÀÏ À̸§ÀÌ ¾ø½À´Ï´Ù"
+
+msgid "E33: No previous substitute regular expression"
+msgstr "E33: ÀÌÀü ¹Ù²Ù±â Á¤±Ô Ç¥Çö½ÄÀÌ ¾ø½À´Ï´Ù"
+
+msgid "E34: No previous command"
+msgstr "E34: ÀÌÀü ¸í·ÉÀÌ ¾ø½À´Ï´Ù"
+
+msgid "E35: No previous regular expression"
+msgstr "E35: ÀÌÀü Á¤±ÔÇ¥Çö½ÄÀÌ ¾ø½À´Ï´Ù"
+
+msgid "E481: No range allowed"
+msgstr "E481: ¹üÀ§´Â Çã¿ëµÇÁö ¾Ê½À´Ï´Ù"
+
+msgid "E36: Not enough room"
+msgstr "E36: ºó °ø°£ÀÌ ÃæºÐÇÏÁö ¾Ê½À´Ï´Ù"
+
+#, c-format
+msgid "E247: no registered server named \"%s\""
+msgstr "E247: \"%s\"Àº(´Â) µî·ÏµÈ ¼­¹ö¸íÀÌ ¾Æ´Õ´Ï´Ù"
+
+#, c-format
+msgid "E482: Can't create file %s"
+msgstr "E482: %s ÆÄÀÏÀ» ¸¸µé ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E483: Can't get temp file name"
+msgstr "E483: Àӽà ÆÄÀÏ À̸§À» ¾òÀ» ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "E484: Can't open file %s"
+msgstr "E484: %s ÆÄÀÏÀ» ¿­ ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "E485: Can't read file %s"
+msgstr "E485: %s ÆÄÀÏÀ» ÀÐÀ» ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E38: Null argument"
+msgstr "E38: ³Î ÀÎÀÚ"
+
+msgid "E39: Number expected"
+msgstr "E39: ¼ýÀÚ°¡ ÇÊ¿äÇÕ´Ï´Ù"
+
+#, c-format
+msgid "E40: Can't open errorfile %s"
+msgstr "E40: ¿¡·¯ÆÄÀÏ %sÀ»(¸¦) ¿­ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E233: cannot open display"
+msgstr "E233: µð½ºÇ÷¹À̸¦ ¿­ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E41: Out of memory!"
+msgstr "E41: ¸Þ¸ð¸®°¡ ¹Ù´Ú³µ½À´Ï´Ù!"
+
+msgid "Pattern not found"
+msgstr "ÆÐÅÏÀ» ãÀ» ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "E486: Pattern not found: %s"
+msgstr "E486: ÆÐÅÏÀ» ãÀ» ¼ö ¾ø½À´Ï´Ù: %s"
+
+msgid "E487: Argument must be positive"
+msgstr "E487: ÀÎÀÚ´Â ¾ç¼öÀ̾î¾ß ÇÕ´Ï´Ù"
+
+msgid "E459: Cannot go back to previous directory"
+msgstr "E459: ÀÌÀü µð·ºÅ丮·Î °¥ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E42: No Errors"
+msgstr "E42: ¿¡·¯ ¾øÀ½"
+
+msgid "E776: No location list"
+msgstr "E776: À§Ä¡ ¸ñ·Ï ¾øÀ½"
+
+msgid "E43: Damaged match string"
+msgstr "E43: ±úÁø ¸Â´Â ¹®ÀÚ¿­"
+
+msgid "E44: Corrupted regexp program"
+msgstr "E44: ±úÁø Á¤±ÔÇ¥Çö½Ä ÇÁ·Î±×·¥"
+
+msgid "E45: 'readonly' option is set (add ! to override)"
+msgstr "E45: 'readonly' ¿É¼ÇÀÌ ¼³Á¤µÇ¾î ÀÖ½À´Ï´Ù (µ¤¾î¾²·Á¸é ! ´õÇϱâ)"
+
+#, c-format
+msgid "E46: Cannot change read-only variable \"%s\""
+msgstr "E46: Àбâ Àü¿ë º¯¼ö \"%s\"À»(¸¦) ¹Ù²Ü ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "E794: Cannot set variable in the sandbox: \"%s\""
+msgstr "E794: sandbox ¾È¿¡¼­´Â º¯¼ö¸¦ ¼³Á¤ÇÒ ¼ö ¾øÀ½: \"%s\""
+
+msgid "E713: Cannot use empty key for Dictionary"
+msgstr "E713: Dictionary¿¡ ºó Å°¸¦ ¾µ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E715: Dictionary required"
+msgstr "E715: Dictionary°¡ ÇÊ¿äÇÕ´Ï´Ù"
+
+#, c-format
+msgid "E684: list index out of range: %ld"
+msgstr "E684: ¸ñ·Ï ¹øÈ£°¡ ¹üÀ§¸¦ ¹þ¾î³²: %ld"
+
+#, c-format
+msgid "E118: Too many arguments for function: %s"
+msgstr "E118: ÇÔ¼ö¿¡ ³Ê¹« ¸¹Àº ÀÎÀÚ ³Ñ±è: %s"
+
+#, c-format
+msgid "E716: Key not present in Dictionary: %s"
+msgstr "E716: Dictionary¿¡ Å°°¡ ¾øÀ½: %s"
+
+msgid "E714: List required"
+msgstr "E714: List°¡ ÇÊ¿äÇÕ´Ï´Ù"
+
+#, c-format
+msgid "E712: Argument of %s must be a List or Dictionary"
+msgstr "E712: %s ÀÎÀÚ´Â List ȤÀº Dictionary¿©¾ß ÇÕ´Ï´Ù"
+
+msgid "E47: Error while reading errorfile"
+msgstr "E47: ¿¡·¯ÆÄÀÏ Àд µµÁß¿¡ ¿¡·¯"
+
+msgid "E48: Not allowed in sandbox"
+msgstr "E48: sandbox¿¡¼­´Â Çã¿ëµÇÁö ¾Ê½À´Ï´Ù"
+
+msgid "E523: Not allowed here"
+msgstr "E523: ¿©±â¿¡¼­ Çã¿ëµÇÁö ¾Ê½À´Ï´Ù"
+
+msgid "E359: Screen mode setting not supported"
+msgstr "E359: ½ºÅ©¸° »óÅ ¼³Á¤Àº Áö¿øµÇÁö ¾Ê½À´Ï´Ù"
+
+msgid "E49: Invalid scroll size"
+msgstr "E49: ½ºÅ©·Ñ Å©±â°¡ À߸øµÇ¾ú½À´Ï´Ù"
+
+msgid "E91: 'shell' option is empty"
+msgstr "E91: 'shell' ¿É¼ÇÀÌ ºñ¾ú½À´Ï´Ù"
+
+msgid "E255: Couldn't read in sign data!"
+msgstr "E255: sign ÀڷḦ ÀÐÀ» ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E72: Close error on swap file"
+msgstr "E72: ½º¿Ò ÆÄÀÏÀ» ´ÝÀ» ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E73: tag stack empty"
+msgstr "E73: ÅÂ±× ½ºÅÃÀÌ ºñ¾ú½À´Ï´Ù"
+
+msgid "E74: Command too complex"
+msgstr "E74: ¸í·ÉÀÌ ³Ê¹« º¹ÀâÇÕ´Ï´Ù"
+
+msgid "E75: Name too long"
+msgstr "E75: À̸§ÀÌ ³Ê¹« ±é´Ï´Ù"
+
+msgid "E76: Too many ["
+msgstr "E76: [°¡ ³Ê¹« ¸¹½À´Ï´Ù"
+
+msgid "E77: Too many file names"
+msgstr "E77: ÆÄÀÏ À̸§ÀÌ ³Ê¹« ¸¹½À´Ï´Ù"
+
+msgid "E488: Trailing characters"
+msgstr "E488: ³¡¿¡ ¹®ÀÚ°¡ ´õ ÀÖ½À´Ï´Ù"
+
+msgid "E78: Unknown mark"
+msgstr "E78: ¸ð¸£´Â ¸¶Å©"
+
+msgid "E79: Cannot expand wildcards"
+msgstr "E79: ¸¸´É ±ÛÀÚ¸¦ È®ÀåÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E591: 'winheight' cannot be smaller than 'winminheight'"
+msgstr "E591: 'winheight'´Â 'winminheight'º¸´Ù Ä¿¾ß ÇÕ´Ï´Ù"
+
+msgid "E592: 'winwidth' cannot be smaller than 'winminwidth'"
+msgstr "E592: 'winwidth'´Â 'winminwidth'º¸´Ù Ä¿¾ß ÇÕ´Ï´Ù"
+
+msgid "E80: Error while writing"
+msgstr "E80: ¾²´Â Áß¿¡ ¿¡·¯"
+
+#~ msgid "E939: Positive count required"
+#~ msgstr ""
+
+msgid "E81: Using <SID> not in a script context"
+msgstr "E81: ½ºÅ©¸³Æ® ÄÜÅؽºÆ® ¹Û¿¡¼­ <SID> »ç¿ë"
+
+msgid "E449: Invalid expression received"
+msgstr "E449: À߸øµÈ Ç¥Çö½ÄÀÌ ¹Þ¾ÆÁ³½À´Ï´Ù"
+
+msgid "E463: Region is guarded, cannot modify"
+msgstr "E463: ¿µ¿ªÀÌ º¸È£µÇ°í À־ ¼öÁ¤ÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E744: NetBeans does not allow changes in read-only files"
+msgstr "E744: NetBeans´Â Àбâ Àü¿ë ÆÄÀÏÀ» ¹Ù²Ü ¼ö ¾ø½À´Ï´Ù"
+
+msgid "E363: pattern uses more memory than 'maxmempattern'"
+msgstr "E363: ÆÐÅÏÀÌ 'maxmempattern'º¸´Ù ¸¹Àº ¸Þ¸ð¸®¸¦ »ç¿ëÇÕ´Ï´Ù"
+
+msgid "E749: empty buffer"
+msgstr "E749: ºó ¹öÆÛ"
+
+#, c-format
+msgid "E86: Buffer %ld does not exist"
+msgstr "E86: ¹öÆÛ %ldÀÌ(°¡) Á¸ÀçÇÏÁö ¾Ê½À´Ï´Ù"
+
+msgid "E682: Invalid search pattern or delimiter"
+msgstr "E682: À߸øµÈ ã±â ÆÐÅÏ È¤Àº ±¸ºÐÀÚ"
+
+msgid "E139: File is loaded in another buffer"
+msgstr "E139: ÆÄÀÏÀÌ ´Ù¸¥ ¹öÆÛ¿¡ ·ÎµùµÇ¾î ÀÖ½À´Ï´Ù"
+
+#, c-format
+msgid "E764: Option '%s' is not set"
+msgstr "E764: ¿É¼Ç '%s'ÀÌ(°¡) ¼³Á¤µÇ¾î ÀÖÁö ¾Ê½À´Ï´Ù"
+
+msgid "E850: Invalid register name"
+msgstr "E850: À߸øµÈ ·¹Áö½ºÅÍ À̸§"
+
+#, c-format
+msgid "E919: Directory not found in '%s': \"%s\""
+msgstr "E919: '%s'¿¡¼­ µð·ºÅ丮¸¦ ¸øãÀ½: \"%s\""
+
+msgid "E952: Autocommand caused recursive behavior"
+msgstr "E952: Autocommand°¡ Àç±Í È£ÃâµÇ¾ú½À´Ï´Ù"
+
+msgid "search hit TOP, continuing at BOTTOM"
+msgstr "óÀ½±îÁö ã¾ÒÀ½, ³¡¿¡¼­ °è¼Ó"
+
+msgid "search hit BOTTOM, continuing at TOP"
+msgstr "³¡±îÁö ã¾ÒÀ½, óÀ½ºÎÅÍ °è¼Ó"
+
+#, c-format
+msgid "Need encryption key for \"%s\""
+msgstr "\"%s\"¿¡ ´ëÇÑ ¾ÏÈ£ Å°°¡ ÇÊ¿äÇÕ´Ï´Ù"
+
+msgid "empty keys are not allowed"
+msgstr "ºó Å° °ªÀº Çã¿ëµÇÁö ¾Ê½À´Ï´Ù"
+
+msgid "dictionary is locked"
+msgstr "dictionary°¡ Àá°ÜÀÖ½À´Ï´Ù"
+
+msgid "list is locked"
+msgstr "list°¡ Àá°ÜÀÖ½À´Ï´Ù"
+
+#, c-format
+msgid "failed to add key '%s' to dictionary"
+msgstr "dictionary¿¡ '%s' Å°¸¦ Ãß°¡ÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+#~ msgid "index must be int or slice, not %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "expected str() or unicode() instance, but got %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "expected bytes() or str() instance, but got %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid ""
+#~ "expected int(), long() or something supporting coercing to long(), but got %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "expected int() or something supporting coercing to int(), but got %s"
+#~ msgstr ""
+
+msgid "value is too large to fit into C int type"
+msgstr "°ªÀÌ C Á¤¼ö Çü½Ä ´ëºñÇÏ¿© ³Ê¹« Å®´Ï´Ù"
+
+msgid "value is too small to fit into C int type"
+msgstr "°ªÀÌ C Á¤¼ö Çü½Ä ´ëºñÇÏ¿© ³Ê¹« ÀÛ½À´Ï´Ù"
+
+msgid "number must be greater than zero"
+msgstr "°ªÀÌ 0º¸´Ù Ä¿¾ß ÇÕ´Ï´Ù"
+
+msgid "number must be greater or equal to zero"
+msgstr "°ªÀÌ 0º¸´Ù Å©°Å³ª °°¾Æ¾ß ÇÕ´Ï´Ù"
+
+msgid "can't delete OutputObject attributes"
+msgstr "OutputObject ¼Ó¼ºÀ» Áö¿ï ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "invalid attribute: %s"
+msgstr "À߸øµÈ ¼Ó¼º: %s"
+
+msgid "E264: Python: Error initialising I/O objects"
+msgstr "E264: ÆÄÀ̽ã: I/O °´Ã¼ ÃʱâÈ­Áß ¿¡·¯°¡ »ý°å½À´Ï´Ù"
+
+msgid "failed to change directory"
+msgstr "µð·ºÅ丮¸¦ ¹Ù²Ü ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+#~ msgid "expected 3-tuple as imp.find_module() result, but got %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "expected 3-tuple as imp.find_module() result, but got tuple of size %d"
+#~ msgstr ""
+
+#~ msgid "internal error: imp.find_module returned tuple with NULL"
+#~ msgstr ""
+
+msgid "cannot delete vim.Dictionary attributes"
+msgstr "vim.Dictionary ¼Ó¼ºÀ» »èÁ¦ÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "cannot modify fixed dictionary"
+msgstr "fixed dictionary¸¦ ¼öÁ¤ÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+msgid "cannot set attribute %s"
+msgstr "¼Ó¼º %sÀ»(¸¦) ¼³Á¤ÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+#~ msgid "hashtab changed during iteration"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "expected sequence element of size 2, but got sequence of size %d"
+#~ msgstr ""
+
+#~ msgid "list constructor does not accept keyword arguments"
+#~ msgstr ""
+
+msgid "list index out of range"
+msgstr "list »öÀÎÀÌ ¹üÀ§¸¦ ¹þ¾î³µ½À´Ï´Ù"
+
+#, c-format
+#~ msgid "internal error: failed to get vim list item %d"
+#~ msgstr ""
+
+#~ msgid "slice step cannot be zero"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "attempt to assign sequence of size greater than %d to extended slice"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "internal error: no vim list item %d"
+#~ msgstr ""
+
+#~ msgid "internal error: not enough list items"
+#~ msgstr ""
+
+#~ msgid "internal error: failed to add item to list"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "attempt to assign sequence of size %d to extended slice of size %d"
+#~ msgstr ""
+
+#~ msgid "failed to add item to list"
+#~ msgstr ""
+
+msgid "cannot delete vim.List attributes"
+msgstr "vim.List ¼Ó¼ºÀ» »èÁ¦ÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+#~ msgid "cannot modify fixed list"
+#~ msgstr ""
+
+#, c-format
+msgid "unnamed function %s does not exist"
+msgstr "À̸§¾ø´Â ÇÔ¼ö %sÀÌ(°¡) Á¸ÀçÇÏÁö ¾Ê½À´Ï´Ù"
+
+#, c-format
+msgid "function %s does not exist"
+msgstr "ÇÔ¼ö %sÀÌ(°¡) Á¸ÀçÇÏÁö ¾Ê½À´Ï´Ù"
+
+#, c-format
+msgid "failed to run function %s"
+msgstr "ÇÔ¼ö %sÀ»(¸¦) ½ÇÇàÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+msgid "unable to get option value"
+msgstr "¿É¼Ç °ªÀ» ¾òÀ» ¼ö ¾ø½À´Ï´Ù"
+
+#~ msgid "internal error: unknown option type"
+#~ msgstr ""
+
+#~ msgid "problem while switching windows"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "unable to unset global option %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "unable to unset option %s which does not have global value"
+#~ msgstr ""
+
+msgid "attempt to refer to deleted tab page"
+msgstr "Áö¿öÁø ÅÇ ÆäÀÌÁö¸¦ ÂüÁ¶ÇÏ·Á°í ÇÏ¿´½À´Ï´Ù"
+
+msgid "no such tab page"
+msgstr "±×·± ÅÇ ÆäÀÌÁö°¡ ¾ø½À´Ï´Ù"
+
+msgid "attempt to refer to deleted window"
+msgstr "Áö¿öÁø âÀ» ÂüÁ¶ÇÏ·Á°í ÇÏ¿´½À´Ï´Ù"
+
+msgid "readonly attribute: buffer"
+msgstr "Àбâ Àü¿ë ¼Ó¼º: ¹öÆÛ"
+
+msgid "cursor position outside buffer"
+msgstr "ÆÛ¼­ À§Ä¡°¡ ¹öÆÛ ¹Û¿¡ ÀÖ½À´Ï´Ù"
+
+msgid "no such window"
+msgstr "±×·± âÀº ¾ø½À´Ï´Ù"
+
+msgid "attempt to refer to deleted buffer"
+msgstr "Áö¿öÁø ¹öÆÛ¸¦ ÂüÁ¶ÇÏ·Á°í ÇÏ¿´½À´Ï´Ù"
+
+msgid "failed to rename buffer"
+msgstr "¹öÆÛ À̸§À» º¯°æÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+#~ msgid "mark name must be a single character"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "expected vim.Buffer object, but got %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "failed to switch to buffer %d"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "expected vim.Window object, but got %s"
+#~ msgstr ""
+
+#~ msgid "failed to find window in the current tab page"
+#~ msgstr ""
+
+#~ msgid "did not switch to the specified window"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "expected vim.TabPage object, but got %s"
+#~ msgstr ""
+
+#~ msgid "did not switch to the specified tab page"
+#~ msgstr ""
+
+#~ msgid "failed to run the code"
+#~ msgstr ""
+
+#~ msgid "E858: Eval did not return a valid python object"
+#~ msgstr ""
+
+#~ msgid "E859: Failed to convert returned python object to vim value"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "unable to convert %s to vim dictionary"
+#~ msgstr ""
+
+#, c-format
+msgid "unable to convert %s to vim list"
+msgstr "%sÀ»(¸¦) vim list·Î º¯°æÇÒ ¼ö ¾ø½À´Ï´Ù"
+
+#, c-format
+#~ msgid "unable to convert %s to vim structure"
+#~ msgstr ""
+
+#~ msgid "internal error: NULL reference passed"
+#~ msgstr ""
+
+#~ msgid "internal error: invalid value type"
+#~ msgstr ""
+
+#~ msgid ""
+#~ "Failed to set path hook: sys.path_hooks is not a list\n"
+#~ "You should now do the following:\n"
+#~ "- append vim.path_hook to sys.path_hooks\n"
+#~ "- append vim.VIM_SPECIAL_PATH to sys.path\n"
+#~ msgstr ""
+
+#~ msgid ""
+#~ "Failed to set path: sys.path is not a list\n"
+#~ "You should now append vim.VIM_SPECIAL_PATH to sys.path"
+#~ msgstr ""
+
+msgid ""
+"Vim macro files (*.vim)\t*.vim\n"
+"All Files (*.*)\t*.*\n"
+msgstr ""
+"Vim ¸ÅÅ©·Î ÆÄÀÏ (*.vim)\t*.vim\n"
+"¸ðµç ÆÄÀÏ (*.*)\t*.*\n"
+
+msgid "All Files (*.*)\t*.*\n"
+msgstr "¸ðµç ÆÄÀÏ (*.*)\t*.*\n"
+
+msgid ""
+"All Files (*.*)\t*.*\n"
+"C source (*.c, *.h)\t*.c;*.h\n"
+"C++ source (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"VB code (*.bas, *.frm)\t*.bas;*.frm\n"
+"Vim files (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
+msgstr ""
+"¸ðµç ÆÄÀÏ (*.*)\t*.*\n"
+"C ¼Ò½º (*.c, *.h)\t*.c;*.h\n"
+"C++ ¼Ò½º (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"VB ÄÚµå (*.bas, *.frm)\t*.bas;*.frm\n"
+"Vim ÆÄÀÏ (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
+
+msgid ""
+"Vim macro files (*.vim)\t*.vim\n"
+"All Files (*)\t*\n"
+msgstr ""
+"Vim ¸ÅÅ©·Î ÆÄÀÏ (*.vim)\t*.vim\n"
+"¸ðµç ÆÄÀÏ (*)\t*\n"
+
+msgid "All Files (*)\t*\n"
+msgstr "¸ðµç ÆÄÀÏ (*)\t*\n"
+
+msgid ""
+"All Files (*)\t*\n"
+"C source (*.c, *.h)\t*.c;*.h\n"
+"C++ source (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"Vim files (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
+msgstr ""
+"¸ðµç ÆÄÀÏ (*)\t*\n"
+"C ¼Ò½º (*.c, *.h)\t*.c;*.h\n"
+"C++ ¼Ò½º (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"Vim ÆÄÀÏ (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
diff --git a/src/po/lv.po b/src/po/lv.po
new file mode 100644
index 0000000..12a91ea
--- /dev/null
+++ b/src/po/lv.po
@@ -0,0 +1,282 @@
+# Latvian Translation for Vim vim:set foldmethod=marker:
+#
+# Do ":help uganda" in Vim to read copying and usage conditions.
+# Do ":help credits" in Vim to see a list of people who contributed.
+#
+# FIRST AUTHOR Valdis Vitolins <valdis.vitolins@odo.lv>, 2017.
+#
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Vim (Latvian)\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2017-05-03 18:03+0100\n"
+"PO-Revision-Date: 2017-05-03 18:08+0300\n"
+"Last-Translator: Valdis Vītoliņš <valdis.vitolins@odo.lv>\n"
+"Language-Team: Bram Moolenaar <Bram@vim.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: lv\n"
+"X-Generator: Poedit 1.8.7.1\n"
+
+#, c-format
+msgid "E96: Can not diff more than %ld buffers"
+msgstr "E96: Nevar salÄ«dzinÄt vairÄk kÄ %ld buferus"
+
+msgid "E101: More than two buffers in diff mode, don't know which one to use"
+msgstr "E101: VairÄk par vienu buferi diff režīmÄ, nav skaidrs, kuru izmantot"
+
+#, c-format
+msgid "E102: Can't find buffer \"%s\""
+msgstr "E102: Nevar atrast buferi \"%s\""
+
+#, c-format
+msgid "E738: Can't list variables for %s"
+msgstr "E738: Nevar parÄdÄ«t %s mainÄ«gos"
+
+#, c-format
+msgid "E138: Can't write viminfo file %s!"
+msgstr "E138: Nevar ierakstīt viminfo failu %s!"
+
+msgid ""
+"# You may edit it if you're careful!\n"
+"\n"
+msgstr ""
+"# Ja rediģējat, esiet uzmanīgs!\n"
+"\n"
+
+msgid "E146: Regular expressions can't be delimited by letters"
+msgstr "E146: RegulÄrÄs izteiksmes nedrÄ«kst atdalÄ«t ar burtiem"
+
+msgid "E493: Backwards range given"
+msgstr "E493: Uzdots pretējs diapazons"
+
+msgid "Backwards range given, OK to swap"
+msgstr "Diapazons pretÄ“jÄ secÄ«bÄ, OK lai apvÄ“rstu"
+
+#, c-format
+msgid "E185: Cannot find color scheme %s"
+msgstr "E185: Nevar atrast krÄsu shÄ“mu %s"
+
+msgid "Can't find temp file for conversion"
+msgstr "Nevar atrast konvertējamo īslaicīgo failu"
+
+msgid "can't read output of 'charconvert'"
+msgstr "nevar nolasīt 'charconvert' izeju"
+
+msgid "E506: Can't write to backup file (add ! to override)"
+msgstr "E506: Nevar ierakstÄ«t rezerves failu (pievienojiet ! lai pÄrlabotu)"
+
+msgid "E508: Can't read file for backup (add ! to override)"
+msgstr "E508: Nevar nolasÄ«t rezerves failu (pievienojiet ! lai pÄrlabotu)"
+
+msgid "E510: Can't make backup file (add ! to override)"
+msgstr "E510: Nevar izveidot rezerves failu (pievienojiet ! lai pÄrlabotu)"
+
+msgid "E214: Can't find temp file for writing"
+msgstr "E214: Nevar atvērt īslaicīgo failu rakstīšanai"
+
+msgid "E166: Can't open linked file for writing"
+msgstr "E166: Nevar atvērt rakstīšanai saistīto failu"
+
+msgid "E212: Can't open file for writing"
+msgstr "E212: Nevar atvērt failu rakstīšanai"
+
+msgid "E205: Patchmode: can't save original file"
+msgstr "E205: Patchmode: nevar saglabÄt oriÄ£inÄlo failu"
+
+msgid "E206: patchmode: can't touch empty original file"
+msgstr "E206: patchmode: nevar izveidot jaunu oriÄ£inÄlo failu"
+
+msgid "E207: Can't delete backup file"
+msgstr "E207: nevar izdzēst kopijas failu"
+
+msgid "don't quit the editor until the file is successfully written!"
+msgstr "neizejiet no redaktora pirms fails nav veiksmÄ«gi saglabÄts!"
+
+msgid "E217: Can't execute autocommands for ALL events"
+msgstr "E217: Nevar izpildīt autokomandu VISIEM notikumiem"
+
+#, c-format
+msgid "E482: Can't create file %s"
+msgstr "E482: Nevar izveidot failu %s"
+
+msgid "E483: Can't get temp file name"
+msgstr "E483: Nevar iegÅ«t Ä«slaicÄ«gÄ faila nosaukumu"
+
+#, c-format
+msgid "E484: Can't open file %s"
+msgstr "E484: Nevar atvērt failu %s"
+
+#, c-format
+msgid "E485: Can't read file %s"
+msgstr "E485: Nevar nolasīt failu %s"
+
+#, c-format
+msgid "E40: Can't open errorfile %s"
+msgstr "E40: Nevar atvērt kļūdu failu %s"
+
+msgid "E255: Couldn't read in sign data!"
+msgstr "E255: Nevar nolasīt zīmes datus!"
+
+#, c-format
+msgid "E254: Cannot allocate color %s"
+msgstr "E254: Nevar izdalÄ«t krÄsu %s"
+
+#, c-format
+msgid "E616: vim_SelFile: can't get font %s"
+msgstr "E616: vim_SelFile: nevar iegūt fontu %s"
+
+msgid "E614: vim_SelFile: can't return to current directory"
+msgstr "E614: vim_SelFile: nevar atgriezties uz tekošo mapi"
+
+msgid "E615: vim_SelFile: can't get current directory"
+msgstr "E615: vim_SelFile: nevar iegūt tekošo mapi"
+
+msgid "Vim E458: Cannot allocate colormap entry, some colors may be incorrect"
+msgstr "Vim E458: Nevar izveidot krÄsu karti, iespÄ“jams, ir kÄda nepareiza krÄsa"
+
+#, c-format
+msgid "E624: Can't open file \"%s\""
+msgstr "E624: Nevar atvērt failu \"%s\""
+
+#, c-format
+msgid "E457: Can't read PostScript resource file \"%s\""
+msgstr "E457: Nevar nolasīt PostScript resursu failu \"%s\""
+
+msgid "E324: Can't open PostScript output file"
+msgstr "E324: Nevar atvērt PostScript izejas failu"
+
+#, c-format
+msgid "E456: Can't open file \"%s\""
+msgstr "E456: Nevar atrast failu \"%s\""
+
+msgid "E456: Can't find PostScript resource file \"prolog.ps\""
+msgstr "E456: Nevar atrast PostScript resursu failu \"prolog.ps\""
+
+msgid "E456: Can't find PostScript resource file \"cidfont.ps\""
+msgstr "E456: Nevar atrast PostScript resursu failu \"cidfont.ps\""
+
+#, c-format
+msgid "E456: Can't find PostScript resource file \"%s.ps\""
+msgstr "E456: Nevar atrast PostScript resursu failu \"%s.ps\""
+
+msgid "couldn't open buffer"
+msgstr "nevar atvērt buferi"
+
+msgid "can't delete OutputObject attributes"
+msgstr "nevar izdzēst OutputObject vērtības"
+
+msgid "--literal\t\tDon't expand wildcards"
+msgstr "--literal\t\tNeizvÄ“rst aizstÄjÄ“jzÄ«mes"
+
+msgid "-f or --nofork\tForeground: Don't fork when starting GUI"
+msgstr "-f jeb --nofork\tPriekÅ¡plÄnÄ: startÄ“jot GUI, neveidot jaunu pavedienu"
+
+msgid "-f\t\t\tDon't use newcli to open window"
+msgstr "-f\t\t\tAtverot logu, neveidot jaunu klientu"
+
+msgid "--noplugin\t\tDon't load plugin scripts"
+msgstr "--noplugin\t\tNeielÄdÄ“t spraudņu skriptus"
+
+msgid "--remote-silent <files> Same, don't complain if there is no server"
+msgstr "--remote-silent <files> LÄ«dzÄ«gi, nebrÄ«dinÄt, ja nav servera"
+
+msgid "--remote-wait-silent <files> Same, don't complain if there is no server"
+msgstr "--remote-wait-silent <files> LÄ«dzÄ«gi, nebrÄ«dinÄt, ja nav servera"
+
+msgid "-background <color>\tUse <color> for the background (also: -bg)"
+msgstr "-background <krÄsa>\tLietot <krÄsa> kÄ fonu (arÄ«: -bg)"
+
+msgid "-foreground <color>\tUse <color> for normal text (also: -fg)"
+msgstr "-foreground <krÄsa>\tLietot <krÄsa> normÄlam tekstam (arÄ«: -fg)"
+
+msgid "+reverse\t\tDon't use reverse video (also: +rv)"
+msgstr "+reverse\t\tNelietot reversu video (arī: +rv)"
+
+msgid "E288: input method doesn't support any style"
+msgstr "E288: ievades veids neatbalsta nevienu stilu"
+
+msgid "E289: input method doesn't support my preedit type"
+msgstr "E289: ievades veids neatbalsta Å¡Ädu preedit veidu"
+
+msgid "E298: Didn't get block nr 0?"
+msgstr "E298: NeizdevÄs iegÅ«t bloku nr 0?"
+
+msgid "E298: Didn't get block nr 1?"
+msgstr "E298: NeizdevÄs iegÅ«t blok nr 1?"
+
+msgid "E298: Didn't get block nr 2?"
+msgstr "E298: NeizdevÄs iegÅ«t bloku nr 2?"
+
+msgid "E304: ml_upd_block0(): Didn't get block 0??"
+msgstr "E304: ml_upd_block0(): NeizdevÄs iegÅ«t bloku 0??"
+
+msgid "Messages maintainer: Bram Moolenaar <Bram@vim.org>"
+msgstr "Messages maintainer: Valdis Vitolins <valdis.vitolins@odo.lv>"
+
+msgid "Keys don't match!"
+msgstr "Atslēgas neatbilst!"
+
+#, c-format
+msgid "E344: Can't find directory \"%s\" in cdpath"
+msgstr "E344: cdpath nevar atrast mapi \"%s\""
+
+#, c-format
+msgid "E345: Can't find file \"%s\" in path"
+msgstr "E345: ceÄ¼Ä nevar atrast failu \"%s\""
+
+msgid "E597: can't select fontset"
+msgstr "E597: nevar izvēlēties fontu kopu"
+
+msgid "E533: can't select wide font"
+msgstr "E533: nevar izvēlēties plato fontu"
+
+msgid "VIM: Can't open window!\n"
+msgstr "VIM: Nevar atvērt logu!\n"
+
+msgid "E388: Couldn't find definition"
+msgstr "E388: neatradu definīciju"
+
+msgid "E389: Couldn't find pattern"
+msgstr "E389: neatradu Å¡ablonu"
+
+#, c-format
+msgid "Unrecognized or duplicate item in %s line %d: %s"
+msgstr "NeatpazÄ«ts vai dublÄ“ts vienums %s rindÄ %d: %s"
+
+#, c-format
+msgid "Unrecognized flags in %s line %d: %s"
+msgstr "NeatpazÄ«ti karodziņi %s rindÄ %d: %s"
+
+#, c-format
+msgid "E781: .sug file doesn't match .spl file: %s"
+msgstr "E781: .sug fails neatbilst .spl failam: %s"
+
+#, c-format
+msgid "E394: Didn't find region item for %s"
+msgstr "E394: Neatradu vienuma %s reģionu"
+
+msgid "E419: FG color unknown"
+msgstr "E419: NezinÄma priekÅ¡plÄna krÄsa"
+
+msgid "E420: BG color unknown"
+msgstr "E420: NezinÄma fona krÄsa"
+
+#, c-format
+msgid "E421: Color name or number not recognized: %s"
+msgstr "E421: NezinÄms krÄsas %s nosaukums vai numurs"
+
+msgid "E434: Can't find tag pattern"
+msgstr "E434: Neatradu tagu paraugu"
+
+msgid "E435: Couldn't find tag, just guessing!"
+msgstr "E435: Neatradu tagu, mēģinu uzminēt!"
+
+msgid "E442: Can't split topleft and botright at the same time"
+msgstr "E442: Nevar sadalīt kreiso augšu un labo apakšu vienlaicīgi"
+
+#, c-format
+msgid "E447: Can't find file \"%s\" in path"
+msgstr "E447: Failu \"%s\" ceÄ¼Ä nevar atrast"
diff --git a/src/po/nb.po b/src/po/nb.po
new file mode 100644
index 0000000..98033a1
--- /dev/null
+++ b/src/po/nb.po
@@ -0,0 +1,6166 @@
+# Norwegian (Bokmål) translation of Vim.
+# Copyright (C) 2003-2007 Free Software Foundation, Inc.
+# FIRST AUTHOR Øyvind A. Holm <sunny@sunbase.org>, 2003-2007.
+# Id: no.po 435 2007-03-21 10:52:22Z sunny256
+#
+# Comments and error reports appreciated.
+#
+# Information about the "Vim in Norwegian" project:
+#
+# http://www.sunbase.org/src/vim/norwegian/
+#
+# New versions of the translation files can be downloaded in .tar.gz
+# format from
+#
+# http://svn.sunbase.org/repos/norwegian_vim/download/
+#
+# The files are stored in the Subversion version control system and
+# users of this software can check out the latest version with
+#
+# svn checkout http://svn.sunbase.org/repos/norwegian_vim/trunk/msgs norwegian_vim-msgs
+#
+# This will place the message files into the "norwegian_vim-msgs"
+# directory.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Vim 6.x\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2007-03-19 02:09+0100\n"
+"PO-Revision-Date: 2007-03-21 11:51+0100\n"
+"Last-Translator: Øyvind A. Holm <sunny@sunbase.org>\n"
+"Language-Team: Norwegian <vim.in.norwegian@sunbase.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-1\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "E82: Cannot allocate any buffer, exiting..."
+msgstr "E82: Kan ikke reservere plass til noen buffere, avslutter ..."
+
+msgid "E83: Cannot allocate buffer, using other one..."
+msgstr "E83: Kan ikke reservere plass til buffer, bruker en annen ..."
+
+msgid "E515: No buffers were unloaded"
+msgstr "E515: Ingen buffere ble lastet ut"
+
+msgid "E516: No buffers were deleted"
+msgstr "E516: Ingen buffere ble slettet"
+
+msgid "E517: No buffers were wiped out"
+msgstr "E517: Ingen buffere ble visket ut"
+
+msgid "1 buffer unloaded"
+msgstr "1 buffer ble lastet ut"
+
+#, c-format
+msgid "%d buffers unloaded"
+msgstr "%d buffere ble lastet ut"
+
+msgid "1 buffer deleted"
+msgstr "1 buffer ble slettet"
+
+#, c-format
+msgid "%d buffers deleted"
+msgstr "%d buffere ble slettet"
+
+msgid "1 buffer wiped out"
+msgstr "1 buffer ble visket ut"
+
+#, c-format
+msgid "%d buffers wiped out"
+msgstr "%d buffere ble visket ut"
+
+msgid "E84: No modified buffer found"
+msgstr "E84: Fant ingen modifisert buffer"
+
+#. back where we started, didn't find anything.
+msgid "E85: There is no listed buffer"
+msgstr "E85: Det finnes ingen listede buffere"
+
+#, c-format
+msgid "E86: Buffer %ld does not exist"
+msgstr "E86: Bufferen %ld finnes ikke"
+
+msgid "E87: Cannot go beyond last buffer"
+msgstr "E87: Kan ikke gå forbi siste buffer"
+
+msgid "E88: Cannot go before first buffer"
+msgstr "E88: Kan ikke gå forbi første buffer"
+
+#, c-format
+msgid "E89: No write since last change for buffer %ld (add ! to override)"
+msgstr ""
+"E89: Ikke lagret siden forrige forandring av bufferen %ld (legg til ! for å "
+"overstyre)"
+
+msgid "E90: Cannot unload last buffer"
+msgstr "E90: Kan ikke laste ut siste buffer"
+
+msgid "W14: Warning: List of file names overflow"
+msgstr "W14: Advarsel: Listen med filnavn er overfylt"
+
+#, c-format
+msgid "E92: Buffer %ld not found"
+msgstr "E92: Fant ikke bufferen %ld"
+
+#, c-format
+msgid "E93: More than one match for %s"
+msgstr "E93: Mer enn ett treff for %s"
+
+#, c-format
+msgid "E94: No matching buffer for %s"
+msgstr "E94: Ingen samsvarende buffer for %s"
+
+#, c-format
+msgid "line %ld"
+msgstr "linje %ld"
+
+msgid "E95: Buffer with this name already exists"
+msgstr "E95: En buffer med dette navnet finnes allerede"
+
+msgid " [Modified]"
+msgstr " [Modifisert]"
+
+msgid "[Not edited]"
+msgstr "[Uredigert]"
+
+msgid "[New file]"
+msgstr "[Ny fil]"
+
+msgid "[Read errors]"
+msgstr "[Lesefeil]"
+
+msgid "[readonly]"
+msgstr "[skrivebeskyttet]"
+
+#, c-format
+msgid "1 line --%d%%--"
+msgstr "1 linje --%d%%--"
+
+#, c-format
+msgid "%ld lines --%d%%--"
+msgstr "%ld linjer --%d%%--"
+
+#, c-format
+msgid "line %ld of %ld --%d%%-- col "
+msgstr "linje %ld av %ld --%d%%-- kol "
+
+msgid "[No Name]"
+msgstr "[Uten navn]"
+
+#. must be a help buffer
+msgid "help"
+msgstr "hjelp"
+
+msgid "[Help]"
+msgstr "[Hjelp]"
+
+msgid "[Preview]"
+msgstr "[Forhåndsvisning]"
+
+msgid "All"
+msgstr "Alt"
+
+msgid "Bot"
+msgstr "Bunn"
+
+msgid "Top"
+msgstr "Topp"
+
+#, c-format
+msgid ""
+"\n"
+"# Buffer list:\n"
+msgstr ""
+"\n"
+"# Bufferliste:\n"
+
+msgid "[Location List]"
+msgstr "[Plassliste]"
+
+#~ msgid "[Quickfix List]"
+#~ msgstr ""
+
+msgid ""
+"\n"
+"--- Signs ---"
+msgstr ""
+"\n"
+"--- Skilt ---"
+
+#, c-format
+msgid "Signs for %s:"
+msgstr "Skilt for %s:"
+
+#, c-format
+msgid " line=%ld id=%d name=%s"
+msgstr " linje=%ld id=%d navn=%s"
+
+#, c-format
+msgid "E96: Can not diff more than %ld buffers"
+msgstr "E96: Kan ikke sammenligne flere enn %ld buffere"
+
+msgid "E97: Cannot create diffs"
+msgstr "E97: Kan ikke lage differansefiler"
+
+msgid "Patch file"
+msgstr "Patch fil"
+
+msgid "E98: Cannot read diff output"
+msgstr "E98: Kan ikke lese differanse-utdata"
+
+msgid "E99: Current buffer is not in diff mode"
+msgstr "E99: Nåværende buffer er ikke i differansemodus"
+
+msgid "E793: No other buffer in diff mode is modifiable"
+msgstr "E793: Ingen annen buffer i differansemodus er redigerbar"
+
+msgid "E100: No other buffer in diff mode"
+msgstr "E100: Ingen annen buffer i differansemodus"
+
+msgid "E101: More than two buffers in diff mode, don't know which one to use"
+msgstr ""
+"E101: Mer enn to buffere i differansemodus, vet ikke hvilken som skal brukes"
+
+#, c-format
+msgid "E102: Can't find buffer \"%s\""
+msgstr "E102: Kan ikke finne buffer \"%s\""
+
+#, c-format
+msgid "E103: Buffer \"%s\" is not in diff mode"
+msgstr "E103: Bufferen \"%s\" er ikke i differansemodus"
+
+msgid "E787: Buffer changed unexpectedly"
+msgstr "E787: Uventet forandring i buffer"
+
+msgid "E104: Escape not allowed in digraph"
+msgstr "E104: Escape er ikke lovlig i spesialtegn"
+
+msgid "E544: Keymap file not found"
+msgstr "E544: Fant ikke keymap-fil"
+
+msgid "E105: Using :loadkeymap not in a sourced file"
+msgstr "E105: Bruk av :loadkeymap utenfor en kjørt fil"
+
+msgid "E791: Empty keymap entry"
+msgstr "E791: Tom tastaturoppsett-oppføring"
+
+msgid " Keyword completion (^N^P)"
+msgstr " Nøkkelordfullføring (^N^P)"
+
+#. ctrl_x_mode == 0, ^P/^N compl.
+#, fuzzy
+#~ msgid " ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+#~ msgstr " ^X-modus (^]^D^E^F^I^K^L^N^O^P^S^U^V^Y)"
+
+msgid " Whole line completion (^L^N^P)"
+msgstr " Fullføring av hel linje (^L^N^P)"
+
+msgid " File name completion (^F^N^P)"
+msgstr " Fullføring av filnavn (^F^N^P)"
+
+msgid " Tag completion (^]^N^P)"
+msgstr " Fullføring av tag (^]^N^P)"
+
+msgid " Path pattern completion (^N^P)"
+msgstr " Stimønster-fullføring (^N^P)"
+
+msgid " Definition completion (^D^N^P)"
+msgstr " Fullføring av defineringer (^D^N^P)"
+
+msgid " Dictionary completion (^K^N^P)"
+msgstr " Fullføring fra ordliste (^K^N^P)"
+
+msgid " Thesaurus completion (^T^N^P)"
+msgstr " Thesaurus-fullføring (^T^N^P)"
+
+msgid " Command-line completion (^V^N^P)"
+msgstr " Kommandolinje-fullføring (^V^N^P)"
+
+msgid " User defined completion (^U^N^P)"
+msgstr " Brukerdefinert fullføring (^U^N^P)"
+
+msgid " Omni completion (^O^N^P)"
+msgstr " Omni-fullføring (^O^N^P)"
+
+#, fuzzy
+#~ msgid " Spelling suggestion (s^N^P)"
+#~ msgstr " Staveforslag (^S^N^P)"
+
+msgid " Keyword Local completion (^N^P)"
+msgstr " Lokal nøkkelordfullføring (^N^P)"
+
+msgid "Hit end of paragraph"
+msgstr "Kom til slutten av avsnittet"
+
+msgid "'dictionary' option is empty"
+msgstr "'dictionary'-valget er tomt"
+
+msgid "'thesaurus' option is empty"
+msgstr "'thesaurus'-valget er tomt"
+
+#, c-format
+msgid "Scanning dictionary: %s"
+msgstr "Leter gjennom ordliste: %s"
+
+msgid " (insert) Scroll (^E/^Y)"
+msgstr " (sett inn) Rulling (^E/^Y)"
+
+msgid " (replace) Scroll (^E/^Y)"
+msgstr " (erstatt) Rulling (^E/^Y)"
+
+#, c-format
+msgid "Scanning: %s"
+msgstr "Leter: %s"
+
+#, c-format
+msgid "Scanning tags."
+msgstr "Leter gjennom tagger."
+
+msgid " Adding"
+msgstr " Legger til"
+
+#. showmode might reset the internal line pointers, so it must
+#. * be called before line = ml_get(), or when this address is no
+#. * longer needed. -- Acevedo.
+#.
+msgid "-- Searching..."
+msgstr "-- Søker ..."
+
+msgid "Back at original"
+msgstr "Tilbake i originalen"
+
+msgid "Word from other line"
+msgstr "Ord fra annen linje"
+
+msgid "The only match"
+msgstr "Det eneste treffet"
+
+#, c-format
+msgid "match %d of %d"
+msgstr "treff %d av %d"
+
+#, c-format
+msgid "match %d"
+msgstr "treff %d"
+
+msgid "E18: Unexpected characters in :let"
+msgstr "E18: Uventede tegn i :let"
+
+#, c-format
+msgid "E684: list index out of range: %ld"
+msgstr "E684: Listeindeks utenfor område: %ld"
+
+#, c-format
+msgid "E121: Undefined variable: %s"
+msgstr "E121: Udefinert variabel: %s"
+
+msgid "E111: Missing ']'"
+msgstr "E111: Mangler ']'"
+
+#, c-format
+msgid "E686: Argument of %s must be a List"
+msgstr "E686: Parameter til %s må være en liste"
+
+#, c-format
+msgid "E712: Argument of %s must be a List or Dictionary"
+msgstr "E712: Parameter til %s må være en liste eller ordliste"
+
+msgid "E713: Cannot use empty key for Dictionary"
+msgstr "E713: Kan ikke bruke tom nøkkel med ordliste"
+
+msgid "E714: List required"
+msgstr "E714: Liste påkrevet"
+
+msgid "E715: Dictionary required"
+msgstr "E715: Ordliste påkrevet"
+
+#, c-format
+msgid "E118: Too many arguments for function: %s"
+msgstr "E118: For mange parametere til funksjonen: %s"
+
+#, c-format
+msgid "E716: Key not present in Dictionary: %s"
+msgstr "E716: Nøkkelen finnes ikke i ordliste: %s"
+
+#, c-format
+msgid "E122: Function %s already exists, add ! to replace it"
+msgstr "E122: Funksjonen %s eksisterer allerede, legg til ! for å erstatte den"
+
+msgid "E717: Dictionary entry already exists"
+msgstr "E717: Ordlisteoppføring finnes allerede"
+
+msgid "E718: Funcref required"
+msgstr "E718: Funksjonsreferanse nødvendig"
+
+msgid "E719: Cannot use [:] with a Dictionary"
+msgstr "E719: Kan ikke bruke [:] sammen med en ordliste"
+
+#, c-format
+msgid "E734: Wrong variable type for %s="
+msgstr "E734: Feil variabeltype for %s="
+
+#, c-format
+msgid "E130: Unknown function: %s"
+msgstr "E130: Ukjent funksjon: %s"
+
+#, c-format
+msgid "E461: Illegal variable name: %s"
+msgstr "E461: Ugyldig variabelnavn: %s"
+
+msgid "E687: Less targets than List items"
+msgstr "E687: Færre mål enn listeelementer"
+
+msgid "E688: More targets than List items"
+msgstr "E688: Flere mål enn listeelementer"
+
+msgid "Double ; in list of variables"
+msgstr "Dobbel ; i variabelliste"
+
+#, c-format
+msgid "E738: Can't list variables for %s"
+msgstr "E738: Kan ikke liste variabler for %s"
+
+msgid "E689: Can only index a List or Dictionary"
+msgstr "E689: Kan bare indeksere en liste eller ordliste"
+
+msgid "E708: [:] must come last"
+msgstr "E708: [:] må komme sist"
+
+msgid "E709: [:] requires a List value"
+msgstr "E709: [:] krever en listeverdi"
+
+msgid "E710: List value has more items than target"
+msgstr "E710: Listeverdien har flere elementer enn mål"
+
+msgid "E711: List value has not enough items"
+msgstr "E711: Listeverdien har ikke nok elementer"
+
+msgid "E690: Missing \"in\" after :for"
+msgstr "E690: Mangler \"in\" etter :for"
+
+#, c-format
+msgid "E107: Missing parentheses: %s"
+msgstr "E107: Mangler parenteser: %s"
+
+#, c-format
+msgid "E108: No such variable: \"%s\""
+msgstr "E108: Variabelen finnes ikke: \"%s\""
+
+msgid "E743: variable nested too deep for (un)lock"
+msgstr "E743: Variabel nøstet for dypt for (un)lock"
+
+msgid "E109: Missing ':' after '?'"
+msgstr "E109: Mangler ':' etter '?'"
+
+msgid "E691: Can only compare List with List"
+msgstr "E691: Kan bare sammenligne liste med liste"
+
+msgid "E692: Invalid operation for List"
+msgstr "E692: Ugyldig operasjon for liste"
+
+msgid "E735: Can only compare Dictionary with Dictionary"
+msgstr "E735: Kan bare sammenligne ordliste med ordliste"
+
+msgid "E736: Invalid operation for Dictionary"
+msgstr "E736: Ugyldig operasjon for ordliste"
+
+msgid "E693: Can only compare Funcref with Funcref"
+msgstr "E693: Kan bare sammenligne funksjonsreferanse med funksjonsreferanse"
+
+msgid "E694: Invalid operation for Funcrefs"
+msgstr "E694: Ugyldig operasjon for funksjonsreferanser"
+
+msgid "E110: Missing ')'"
+msgstr "E110: Mangler ')'"
+
+msgid "E695: Cannot index a Funcref"
+msgstr "E695: Kan ikke indeksere en funksjonsreferanse"
+
+#, c-format
+msgid "E112: Option name missing: %s"
+msgstr "E112: Navn på valg mangler: %s"
+
+#, c-format
+msgid "E113: Unknown option: %s"
+msgstr "E113: Ukjent valg: %s"
+
+#, c-format
+msgid "E114: Missing quote: %s"
+msgstr "E114: Mangler anførselstegn (\"): %s"
+
+#, c-format
+msgid "E115: Missing quote: %s"
+msgstr "E115: Mangler apostrof ('): %s"
+
+#, c-format
+msgid "E696: Missing comma in List: %s"
+msgstr "E696: Mangler komma i liste: %s"
+
+#, c-format
+msgid "E697: Missing end of List ']': %s"
+msgstr "E697: Mangler slutt på liste ']': %s"
+
+#, c-format
+msgid "E720: Missing colon in Dictionary: %s"
+msgstr "E720: Mangler kolon i ordliste: %s"
+
+#, c-format
+msgid "E721: Duplicate key in Dictionary: \"%s\""
+msgstr "E721: Duplisert nøkkel i ordliste: \"%s\""
+
+#, c-format
+msgid "E722: Missing comma in Dictionary: %s"
+msgstr "E722: Mangler komma i ordliste: %s"
+
+#, c-format
+msgid "E723: Missing end of Dictionary '}': %s"
+msgstr "E723: Mangler slutt på ordliste '}': %s"
+
+msgid "E724: variable nested too deep for displaying"
+msgstr "E724: Variabel nøstet for dypt for visning"
+
+#, c-format
+msgid "E117: Unknown function: %s"
+msgstr "E117: Ukjent funksjon: %s"
+
+#, c-format
+msgid "E119: Not enough arguments for function: %s"
+msgstr "E119: Ikke nok parametere til funksjonen: %s"
+
+#, c-format
+msgid "E120: Using <SID> not in a script context: %s"
+msgstr "E120: Bruk av \"<SID>\" utenfor skript-sammenheng: %s"
+
+#, c-format
+msgid "E725: Calling dict function without Dictionary: %s"
+msgstr "E725: Kaller ordlistefunksjon uten ordliste: %s"
+
+msgid "E699: Too many arguments"
+msgstr "E699: For mange parametere"
+
+msgid "E785: complete() can only be used in Insert mode"
+msgstr "E785: complete() kan bare brukes i innsettingsmodus"
+
+#.
+#. * Yes this is ugly, I don't particularly like it either. But doing it
+#. * this way has the compelling advantage that translations need not to
+#. * be touched at all. See below what 'ok' and 'ync' are used for.
+#.
+msgid "&Ok"
+msgstr "&Ok"
+
+#, c-format
+msgid "E737: Key already exists: %s"
+msgstr "E737: Nøkkelen finnes allerede: %s"
+
+#, c-format
+msgid "+-%s%3ld lines: "
+msgstr "+-%s%3ld linjer: "
+
+#, c-format
+msgid "E700: Unknown function: %s"
+msgstr "E700: Ukjent funksjon: %s"
+
+msgid ""
+"&OK\n"
+"&Cancel"
+msgstr ""
+"&OK\n"
+"&Avbryt"
+
+msgid "called inputrestore() more often than inputsave()"
+msgstr "kalte inputrestore() oftere enn inputsave()"
+
+msgid "E786: Range not allowed"
+msgstr "E786: Område ikke tillatt"
+
+msgid "E701: Invalid type for len()"
+msgstr "E701: Ugyldig type for len()"
+
+msgid "E726: Stride is zero"
+msgstr "E726: Økning er null"
+
+msgid "E727: Start past end"
+msgstr "E727: Starten er bak slutten"
+
+msgid "<empty>"
+msgstr "<tom>"
+
+msgid "E240: No connection to Vim server"
+msgstr "E240: Ingen forbindelse med Vim-tjeneren"
+
+#, c-format
+msgid "E241: Unable to send to %s"
+msgstr "E241: Klarer ikke sende til %s"
+
+msgid "E277: Unable to read a server reply"
+msgstr "E277: Klarer ikke lese svar fra tjeneren"
+
+msgid "E655: Too many symbolic links (cycle?)"
+msgstr "E655: For mange symbolske linker (runddans?)"
+
+msgid "E258: Unable to send to client"
+msgstr "E258: Klarer ikke sende til klienten"
+
+msgid "E702: Sort compare function failed"
+msgstr "E702: Funksjon for sorteringssammenligning feilet"
+
+msgid "(Invalid)"
+msgstr "(Ugyldig)"
+
+msgid "E677: Error writing temp file"
+msgstr "E677: Feil under skriving til midlertidig fil"
+
+msgid "E703: Using a Funcref as a Number"
+msgstr "E703: Bruker en funksjonsreferanse som et nummer"
+
+msgid "E745: Using a List as a Number"
+msgstr "E745: Bruker en liste som et nummer"
+
+msgid "E728: Using a Dictionary as a Number"
+msgstr "E728: Bruker en ordliste som et nummer"
+
+msgid "E729: using Funcref as a String"
+msgstr "E729: Bruker en funksjonsreferanse som en streng"
+
+msgid "E730: using List as a String"
+msgstr "E730: Bruker en liste som en streng"
+
+msgid "E731: using Dictionary as a String"
+msgstr "E731: Bruker en ordliste som en streng"
+
+#, c-format
+msgid "E704: Funcref variable name must start with a capital: %s"
+msgstr "E704: Variabelnavn for funksjonsreferanse må ha stor forbokstav: %s"
+
+#, c-format
+msgid "E705: Variable name conflicts with existing function: %s"
+msgstr "E705: Variabelnavn er i konflikt med en eksisterende funksjon: %s"
+
+#, c-format
+msgid "E706: Variable type mismatch for: %s"
+msgstr "E706: Variabeltype samsvarer ikke med: %s"
+
+#, c-format
+msgid "E795: Cannot delete variable %s"
+msgstr "E795: Kan ikke slette variabel %s"
+
+#, c-format
+msgid "E741: Value is locked: %s"
+msgstr "E741: Verdi er låst: %s"
+
+msgid "Unknown"
+msgstr "Ukjent"
+
+#, c-format
+msgid "E742: Cannot change value of %s"
+msgstr "E742: Kan ikke forandre verdi for %s"
+
+msgid "E698: variable nested too deep for making a copy"
+msgstr "E698: Variabel nøstet for dypt til å lage en kopi"
+
+#, c-format
+msgid "E124: Missing '(': %s"
+msgstr "E124: Mangler '(': %s"
+
+#, c-format
+msgid "E125: Illegal argument: %s"
+msgstr "E125: Ugyldig parameter: %s"
+
+msgid "E126: Missing :endfunction"
+msgstr "E126: Mangler :endfunction"
+
+#, c-format
+msgid "E746: Function name does not match script file name: %s"
+msgstr "E746: Funksjonsnavn samsvarer ikke med skriptfilnavn: %s"
+
+msgid "E129: Function name required"
+msgstr "E129: Funksjonsnavn nødvendig"
+
+#, c-format
+msgid "E128: Function name must start with a capital or contain a colon: %s"
+msgstr "E128: Funksjonsnavn må ha stor forbokstav eller inneholde et kolon: %s"
+
+#, c-format
+msgid "E131: Cannot delete function %s: It is in use"
+msgstr "E131: Kan ikke slette funksjonen %s: Den er i bruk"
+
+msgid "E132: Function call depth is higher than 'maxfuncdepth'"
+msgstr "E132: Funksjonskalldybden er større enn 'maxfuncdepth'"
+
+#, c-format
+msgid "calling %s"
+msgstr "kaller %s"
+
+#, c-format
+msgid "%s aborted"
+msgstr "%s avbrutt"
+
+#, c-format
+msgid "%s returning #%ld"
+msgstr "%s returnerer #%ld"
+
+#, c-format
+msgid "%s returning %s"
+msgstr "%s returnerer %s"
+
+#, c-format
+msgid "continuing in %s"
+msgstr "fortsetter i %s"
+
+msgid "E133: :return not inside a function"
+msgstr "E133: :return er ikke innenfor en funksjon"
+
+#, c-format
+msgid ""
+"\n"
+"# global variables:\n"
+msgstr ""
+"\n"
+"# globale variabler:\n"
+
+msgid ""
+"\n"
+"\tLast set from "
+msgstr ""
+"\n"
+"\tSist satt fra "
+
+#, c-format
+msgid "<%s>%s%s %d, Hex %02x, Octal %03o"
+msgstr "<%s>%s%s %d, Hex %02x, Oktal %03o"
+
+#, c-format
+msgid "> %d, Hex %04x, Octal %o"
+msgstr "> %d, Hex %04x, Oktal %o"
+
+#, c-format
+msgid "> %d, Hex %08x, Octal %o"
+msgstr "> %d, Hex %08x, Oktal %o"
+
+msgid "E134: Move lines into themselves"
+msgstr "E134: Flytting av linjer inn i seg selv"
+
+msgid "1 line moved"
+msgstr "1 linje flyttet"
+
+#, c-format
+msgid "%ld lines moved"
+msgstr "%ld linjer flyttet"
+
+#, c-format
+msgid "%ld lines filtered"
+msgstr "%ld linjer filtrert"
+
+msgid "E135: *Filter* Autocommands must not change current buffer"
+msgstr "E135: *Filter* Autokommandoer må ikke forandre nåværende buffer"
+
+msgid "[No write since last change]\n"
+msgstr "[Ikke lagret siden forrige forandring]\n"
+
+#, c-format
+msgid "%sviminfo: %s in line: "
+msgstr "%sviminfo: %s i linje: "
+
+msgid "E136: viminfo: Too many errors, skipping rest of file"
+msgstr "E136: viminfo: For mange feil, hopper over resten av filen"
+
+#, c-format
+msgid "Reading viminfo file \"%s\"%s%s%s"
+msgstr "Leser viminfo-fil \"%s\"%s%s%s"
+
+msgid " info"
+msgstr " info"
+
+msgid " marks"
+msgstr " merker"
+
+msgid " FAILED"
+msgstr " FEILET"
+
+#. avoid a wait_return for this message, it's annoying
+#, c-format
+msgid "E137: Viminfo file is not writable: %s"
+msgstr "E137: Viminfo-fil er ikke skrivbar: %s"
+
+#, c-format
+msgid "E138: Can't write viminfo file %s!"
+msgstr "E138: Kan ikke lagre viminfo-fil %s!"
+
+#, c-format
+msgid "Writing viminfo file \"%s\""
+msgstr "Lagrer viminfo-fil \"%s\""
+
+#. Write the info:
+#, c-format
+msgid "# This viminfo file was generated by Vim %s.\n"
+msgstr "# Denne viminfo-filen ble generert av Vim %s.\n"
+
+#, c-format
+msgid ""
+"# You may edit it if you're careful!\n"
+"\n"
+msgstr ""
+"# Du kan redigere den hvis du er forsiktig!\n"
+"\n"
+
+#, c-format
+msgid "# Value of 'encoding' when this file was written\n"
+msgstr "# Verdien av 'encoding' når denne filen ble skrevet\n"
+
+msgid "Illegal starting char"
+msgstr "Ulovlig starttegn"
+
+msgid "Save As"
+msgstr "Lagre som"
+
+msgid "Write partial file?"
+msgstr "Skrive delvis fil?"
+
+msgid "E140: Use ! to write partial buffer"
+msgstr "E140: Bruk ! for å skrive delvis buffer"
+
+#, c-format
+msgid "Overwrite existing file \"%s\"?"
+msgstr "Overskrive eksisterende fil \"%s\"?"
+
+#, c-format
+msgid "Swap file \"%s\" exists, overwrite anyway?"
+msgstr "Swapfilen \"%s\" finnes, overskriv likevel?"
+
+#, c-format
+msgid "E768: Swap file exists: %s (:silent! overrides)"
+msgstr "E768: Swapfilen finnes: %s (:silent! overstyrer)"
+
+#, c-format
+msgid "E141: No file name for buffer %ld"
+msgstr "E141: Mangler filnavn for buffer %ld"
+
+msgid "E142: File not written: Writing is disabled by 'write' option"
+msgstr "E142: Filen ble ikke lagret: Lagring er deaktivert med 'write'-valget"
+
+#, c-format
+msgid ""
+"'readonly' option is set for \"%s\".\n"
+"Do you wish to write anyway?"
+msgstr ""
+"'readonly'-valget er satt for \"%s\".\n"
+"Vil du lagre likevel?"
+
+msgid "Edit File"
+msgstr "Rediger fil"
+
+#, c-format
+msgid "E143: Autocommands unexpectedly deleted new buffer %s"
+msgstr "E143: Autokommandoer slettet uventet den nye bufferen %s"
+
+msgid "E144: non-numeric argument to :z"
+msgstr "E144: Ikke-numerisk parameter til :z"
+
+msgid "E145: Shell commands not allowed in rvim"
+msgstr "E145: Skallkommandoer er ikke tillatt i rvim"
+
+msgid "E146: Regular expressions can't be delimited by letters"
+msgstr "E146: Regulære uttrykk kan ikke bli adskilt av bokstaver"
+
+#, c-format
+msgid "replace with %s (y/n/a/q/l/^E/^Y)?"
+msgstr "Erstatt med %s (y/n/a/q/l/^E/^Y)?"
+
+msgid "(Interrupted) "
+msgstr "(Avbrutt) "
+
+msgid "1 match"
+msgstr "1 treff"
+
+msgid "1 substitution"
+msgstr "1 erstatning"
+
+#, c-format
+msgid "%ld matches"
+msgstr "%ld treff"
+
+#, c-format
+msgid "%ld substitutions"
+msgstr "%ld erstatninger"
+
+msgid " on 1 line"
+msgstr " i 1 linje"
+
+#, c-format
+msgid " on %ld lines"
+msgstr " i %ld linjer"
+
+msgid "E147: Cannot do :global recursive"
+msgstr "E147: Kan ikke gjøre :global rekursiv"
+
+msgid "E148: Regular expression missing from global"
+msgstr "E148: Regulært uttrykk mangler i global kommando"
+
+#, c-format
+msgid "Pattern found in every line: %s"
+msgstr "Søkestreng funnet i alle linjene: %s"
+
+#, c-format
+msgid ""
+"\n"
+"# Last Substitute String:\n"
+"$"
+msgstr ""
+"\n"
+"# Siste erstatningstekst:\n"
+"$"
+
+msgid "E478: Don't panic!"
+msgstr "E478: Ingen panikk!"
+
+#, c-format
+msgid "E661: Sorry, no '%s' help for %s"
+msgstr "E661: Dessverre ingen '%s' hjelp for %s"
+
+#, c-format
+msgid "E149: Sorry, no help for %s"
+msgstr "E149: Dessverre ingen hjelp for %s"
+
+#, c-format
+msgid "Sorry, help file \"%s\" not found"
+msgstr "Fant ikke hjelpefilen \"%s\""
+
+#, c-format
+msgid "E150: Not a directory: %s"
+msgstr "E150: Er ikke en katalog: %s"
+
+#, c-format
+msgid "E152: Cannot open %s for writing"
+msgstr "E152: Kan ikke åpne %s for skriving"
+
+#, c-format
+msgid "E153: Unable to open %s for reading"
+msgstr "E153: Kan ikke åpne %s for lesing"
+
+#, c-format
+msgid "E670: Mix of help file encodings within a language: %s"
+msgstr "E670: Tegnsettblanding i hjelpefilen innenfor samme språk: %s"
+
+#, c-format
+msgid "E154: Duplicate tag \"%s\" in file %s/%s"
+msgstr "E154: Duplikat-tag \"%s\" i filen %s/%s"
+
+#, c-format
+msgid "E160: Unknown sign command: %s"
+msgstr "E160: Ukjent skiltkommando: %s"
+
+msgid "E156: Missing sign name"
+msgstr "E156: Mangler skiltnavn"
+
+msgid "E612: Too many signs defined"
+msgstr "E612: For mange skilt definert"
+
+#, c-format
+msgid "E239: Invalid sign text: %s"
+msgstr "E239: Ugyldig skilttekst: %s"
+
+#, c-format
+msgid "E155: Unknown sign: %s"
+msgstr "E155: Ukjent skilt: %s"
+
+msgid "E159: Missing sign number"
+msgstr "E159: Mangler skiltnummer"
+
+#, c-format
+msgid "E158: Invalid buffer name: %s"
+msgstr "E158: Ugyldig buffernavn: %s"
+
+#, c-format
+msgid "E157: Invalid sign ID: %ld"
+msgstr "E157: Ulovlig skilt-ID: %ld"
+
+msgid " (NOT FOUND)"
+msgstr " (IKKE FUNNET)"
+
+msgid " (not supported)"
+msgstr " (ikke støttet)"
+
+msgid "[Deleted]"
+msgstr "[Slettet]"
+
+msgid "Entering Debug mode. Type \"cont\" to continue."
+msgstr "Går inn i debuggingsmodus. Skriv \"cont\" for å fortsette."
+
+#, c-format
+msgid "line %ld: %s"
+msgstr "linje %ld: %s"
+
+#, c-format
+msgid "cmd: %s"
+msgstr "kommando: %s"
+
+#, c-format
+msgid "Breakpoint in \"%s%s\" line %ld"
+msgstr "Stoppunkt i \"%s%s\" linje %ld"
+
+#, c-format
+msgid "E161: Breakpoint not found: %s"
+msgstr "E161: Fant ikke stoppunkt: %s"
+
+msgid "No breakpoints defined"
+msgstr "Ingen stoppunkt definert"
+
+#, c-format
+msgid "%3d %s %s line %ld"
+msgstr "%3d %s %s linje %ld"
+
+msgid "E750: First use :profile start <fname>"
+msgstr "E750: Bruk først :profile start <filnavn>"
+
+#, c-format
+msgid "Save changes to \"%s\"?"
+msgstr "Lagre forandringer til \"%s\"?"
+
+msgid "Untitled"
+msgstr "Uten navn"
+
+#, c-format
+msgid "E162: No write since last change for buffer \"%s\""
+msgstr "E162: Ikke lagret siden siste forandringer i bufferen \"%s\""
+
+msgid "Warning: Entered other buffer unexpectedly (check autocommands)"
+msgstr "Advarsel: Gikk uventet inn i en annen buffer (sjekk autokommandoer)"
+
+msgid "E163: There is only one file to edit"
+msgstr "E163: Det er bare en fil å redigere"
+
+msgid "E164: Cannot go before first file"
+msgstr "E164: Kan ikke gå forbi første fil"
+
+msgid "E165: Cannot go beyond last file"
+msgstr "E165: Kan ikke gå forbi siste fil"
+
+#, c-format
+msgid "E666: compiler not supported: %s"
+msgstr "E666: Kompilatoren er ikke støttet: %s"
+
+#, c-format
+msgid "Searching for \"%s\" in \"%s\""
+msgstr "Søker etter \"%s\" i \"%s\""
+
+#, c-format
+msgid "Searching for \"%s\""
+msgstr "Søker etter \"%s\""
+
+#, c-format
+msgid "not found in 'runtimepath': \"%s\""
+msgstr "ikke funnet i 'runtimepath': \"%s\""
+
+msgid "Source Vim script"
+msgstr "Kjør Vim-skript"
+
+#, c-format
+msgid "Cannot source a directory: \"%s\""
+msgstr "Kan ikke kjøre en katalog: \"%s\""
+
+#, c-format
+msgid "could not source \"%s\""
+msgstr "kunne ikke kjøre \"%s\""
+
+#, c-format
+msgid "line %ld: could not source \"%s\""
+msgstr "linje %ld: Kunne ikke kjøre \"%s\""
+
+#, c-format
+msgid "sourcing \"%s\""
+msgstr "kjører \"%s\""
+
+#, c-format
+msgid "line %ld: sourcing \"%s\""
+msgstr "linje %ld: kjører \"%s\""
+
+#, c-format
+msgid "finished sourcing %s"
+msgstr "ferdig med kjøring av %s"
+
+#, fuzzy
+#~ msgid "modeline"
+#~ msgstr "1 linje lagt til"
+
+#, fuzzy
+#~ msgid "--cmd argument"
+#~ msgstr " vim [parametere] "
+
+#, fuzzy
+#~ msgid "-c argument"
+#~ msgstr " vim [parametere] "
+
+msgid "environment variable"
+msgstr "miljøvariabel"
+
+msgid "error handler"
+msgstr "feilbehandler"
+
+msgid "W15: Warning: Wrong line separator, ^M may be missing"
+msgstr "W15: Advarsel: Feil linjeseparator, det er mulig ^M mangler"
+
+msgid "E167: :scriptencoding used outside of a sourced file"
+msgstr "E167: :scriptencoding brukt utenfor en kjørt fil"
+
+msgid "E168: :finish used outside of a sourced file"
+msgstr "E168: :finish brukt utenfor en kjørt fil"
+
+#, c-format
+msgid "Current %slanguage: \"%s\""
+msgstr "Nåværende %sspråk: \"%s\""
+
+#, c-format
+msgid "E197: Cannot set language to \"%s\""
+msgstr "E197: Kan ikke sette språk til \"%s\""
+
+msgid "Entering Ex mode. Type \"visual\" to go to Normal mode."
+msgstr "Går inn i Ex-modus. Skriv \"visual\" for å gå til normalmodus."
+
+msgid "E501: At end-of-file"
+msgstr "E501: Ved slutten av filen"
+
+msgid "E169: Command too recursive"
+msgstr "E169: Kommando altfor rekursiv"
+
+#, c-format
+msgid "E605: Exception not caught: %s"
+msgstr "E605: Unntak ikke fanget opp: %s"
+
+msgid "End of sourced file"
+msgstr "Slutt på kjørt fil"
+
+msgid "End of function"
+msgstr "Slutt på funksjon"
+
+msgid "E464: Ambiguous use of user-defined command"
+msgstr "E464: Flertydig bruk av brukerdefinert kommando"
+
+msgid "E492: Not an editor command"
+msgstr "E492: Er ikke en editorkommando"
+
+msgid "E493: Backwards range given"
+msgstr "E493: Område bakover er angitt"
+
+msgid "Backwards range given, OK to swap"
+msgstr "Område bakover er angitt, OK å swappe"
+
+msgid "E494: Use w or w>>"
+msgstr "E494: Bruk w eller w>>"
+
+msgid "E319: Sorry, the command is not available in this version"
+msgstr "E319: Kommandoen er ikke tilgjengelig i denne versjonen"
+
+msgid "E172: Only one file name allowed"
+msgstr "E172: Bare ett filnavn tillatt"
+
+msgid "1 more file to edit. Quit anyway?"
+msgstr "1 annen fil å redigere. Avslutt likevel?"
+
+#, c-format
+msgid "%d more files to edit. Quit anyway?"
+msgstr "%d andre filer å redigere. Avslutt likevel?"
+
+msgid "E173: 1 more file to edit"
+msgstr "E173: 1 annen fil å redigere"
+
+#, c-format
+msgid "E173: %ld more files to edit"
+msgstr "E173: %ld andre filer å redigere"
+
+msgid "E174: Command already exists: add ! to replace it"
+msgstr "E174: Kommandoen finnes allerede: Legg til ! for å erstatte den"
+
+msgid ""
+"\n"
+" Name Args Range Complete Definition"
+msgstr ""
+"\n"
+" Navn Prm. Områd Fullfør Definering"
+
+msgid "No user-defined commands found"
+msgstr "Ingen brukerdefinerte kommandoer funnet"
+
+msgid "E175: No attribute specified"
+msgstr "E175: Ingen attributt spesifisert"
+
+msgid "E176: Invalid number of arguments"
+msgstr "E176: Ugyldig antall parametere"
+
+msgid "E177: Count cannot be specified twice"
+msgstr "E177: Antall repeteringer kan ikke bli spesifisert to ganger"
+
+msgid "E178: Invalid default value for count"
+msgstr "E178: Ugyldig standardverdi for antall repeteringer"
+
+msgid "E179: argument required for -complete"
+msgstr "E179: Trenger parameter til -complete"
+
+#, c-format
+msgid "E181: Invalid attribute: %s"
+msgstr "E181: Ugyldig attributt: %s"
+
+msgid "E182: Invalid command name"
+msgstr "E182: Ugyldig kommandonavn"
+
+msgid "E183: User defined commands must start with an uppercase letter"
+msgstr "E183: Brukerdefinerte kommandoer må ha stor forbokstav"
+
+#, c-format
+msgid "E184: No such user-defined command: %s"
+msgstr "E184: Brukerdefinert kommando finnes ikke: %s"
+
+#, c-format
+msgid "E180: Invalid complete value: %s"
+msgstr "E180: Ugyldig \"complete\"-verdi: %s"
+
+msgid "E468: Completion argument only allowed for custom completion"
+msgstr "E468: Fullføringsparameter er bare tillatt for tilpasset fullføring"
+
+msgid "E467: Custom completion requires a function argument"
+msgstr "E467: Tilpassede fullføringer trenger et funksjonsparameter"
+
+#, c-format
+msgid "E185: Cannot find color scheme %s"
+msgstr "E185: Kan ikke finne fargeoppsettet %s"
+
+msgid "Greetings, Vim user!"
+msgstr "Vær hilset, Vim-bruker!"
+
+#, fuzzy
+#~ msgid "E784: Cannot close last tab page"
+#~ msgstr "E444: Kan ikke lukke det siste vinduet"
+
+#, fuzzy
+#~ msgid "Already only one tab page"
+#~ msgstr "Allerede bare ett vindu"
+
+msgid "Edit File in new window"
+msgstr "Rediger fil i nytt vindu"
+
+#, fuzzy, c-format
+#~ msgid "Tab page %d"
+#~ msgstr "Side %d"
+
+msgid "No swap file"
+msgstr "Ingen swapfil"
+
+msgid "Append File"
+msgstr "Legg til fil"
+
+msgid "E747: Cannot change directory, buffer is modified (add ! to override)"
+msgstr ""
+"E747: Kan ikke skifte katalog, bufferen er forandret (legg til ! for å "
+"overstyre)"
+
+msgid "E186: No previous directory"
+msgstr "E186: Ingen tidligere katalog"
+
+msgid "E187: Unknown"
+msgstr "E187: Ukjent"
+
+msgid "E465: :winsize requires two number arguments"
+msgstr "E465: :winsize trenger to numeriske parametere"
+
+#, c-format
+msgid "Window position: X %d, Y %d"
+msgstr "Vindusposisjon: X %d, Y %d"
+
+msgid "E188: Obtaining window position not implemented for this platform"
+msgstr ""
+"E188: Lesing av vindusposisjon er ikke implementert på denne plattformen"
+
+msgid "E466: :winpos requires two number arguments"
+msgstr "E466: :winpos trenger to numeriske parametere"
+
+msgid "Save Redirection"
+msgstr "Lagre omdirigering"
+
+msgid "Save View"
+msgstr "Lagre utseende"
+
+msgid "Save Session"
+msgstr "Lagre økt"
+
+msgid "Save Setup"
+msgstr "Lagre oppsett"
+
+#, c-format
+msgid "E739: Cannot create directory: %s"
+msgstr "E739: Kan ikke lage katalog: %s"
+
+#, c-format
+msgid "E189: \"%s\" exists (add ! to override)"
+msgstr "E189: \"%s\" finnes (legg til ! for å overstyre)"
+
+#, c-format
+msgid "E190: Cannot open \"%s\" for writing"
+msgstr "E190: Kan ikke åpne \"%s\" for skriving"
+
+#. set mark
+msgid "E191: Argument must be a letter or forward/backward quote"
+msgstr "E191: Parameter må være en bokstav eller vanlig/baklengs apostrof"
+
+msgid "E192: Recursive use of :normal too deep"
+msgstr "E192: Rekursiv bruk av :normal er for dyp"
+
+msgid "E194: No alternate file name to substitute for '#'"
+msgstr "E194: Ingen alternative filnavn tilgjengelig som erstatning for '#'"
+
+msgid "E495: no autocommand file name to substitute for \"<afile>\""
+msgstr ""
+"E495: Ingen autokommandofilnavn tilgjengelig som erstatning for \"<afile>\""
+
+msgid "E496: no autocommand buffer number to substitute for \"<abuf>\""
+msgstr ""
+"E496: Ingen buffernummer tilgjengelig som erstatning for \"<abuf>\" i "
+"autokommando"
+
+msgid "E497: no autocommand match name to substitute for \"<amatch>\""
+msgstr ""
+"E497: Ingen autokommandonavn tilgjengelig som erstatning for \"<amatch>\""
+
+msgid "E498: no :source file name to substitute for \"<sfile>\""
+msgstr ""
+"E498: Ingen ':source'-filnavn tilgjengelig som erstatning for \"<sfile>\""
+
+#, no-c-format
+msgid "E499: Empty file name for '%' or '#', only works with \":p:h\""
+msgstr "E499: Tomt filnavn for '%' eller '#', virker bare med \":p:h\""
+
+msgid "E500: Evaluates to an empty string"
+msgstr "E500: Resulterer i en tom streng"
+
+msgid "E195: Cannot open viminfo file for reading"
+msgstr "E195: Kan ikke åpne viminfo-fil for lesing"
+
+msgid "E196: No digraphs in this version"
+msgstr "E196: Ingen spesialtegn i denne versjonen"
+
+msgid "E608: Cannot :throw exceptions with 'Vim' prefix"
+msgstr "E608: Kan ikke :throw unntak med 'Vim'-forstavelse"
+
+#. always scroll up, don't overwrite
+#, c-format
+#~ msgid "Exception thrown: %s"
+#~ msgstr ""
+
+#, c-format
+msgid "Exception finished: %s"
+msgstr "Unntak fullført: %s"
+
+#, c-format
+msgid "Exception discarded: %s"
+msgstr "Unntak forkastet: %s"
+
+#, c-format
+msgid "%s, line %ld"
+msgstr "%s, linje %ld"
+
+#. always scroll up, don't overwrite
+#, c-format
+msgid "Exception caught: %s"
+msgstr "Unntak fanget opp: %s"
+
+#, c-format
+msgid "%s made pending"
+msgstr "%s satt på venting"
+
+#, c-format
+msgid "%s resumed"
+msgstr "%s gjenopptatt"
+
+#, c-format
+msgid "%s discarded"
+msgstr "%s forkastet"
+
+msgid "Exception"
+msgstr "Unntak"
+
+msgid "Error and interrupt"
+msgstr "Feil og avbrudd"
+
+msgid "Error"
+msgstr "Feil"
+
+#. if (pending & CSTP_INTERRUPT)
+msgid "Interrupt"
+msgstr "Avbrudd"
+
+msgid "E579: :if nesting too deep"
+msgstr "E579: Nøsting av :if for dyp"
+
+msgid "E580: :endif without :if"
+msgstr "E580: :endif uten :if"
+
+msgid "E581: :else without :if"
+msgstr "E581: :else uten :if"
+
+msgid "E582: :elseif without :if"
+msgstr "E582: :elseif uten :if"
+
+msgid "E583: multiple :else"
+msgstr "E583: Flere forekomster av :else"
+
+msgid "E584: :elseif after :else"
+msgstr "E584: :elseif etter :else"
+
+msgid "E585: :while/:for nesting too deep"
+msgstr "E585: Nøsting av :while/:for er for dyp"
+
+msgid "E586: :continue without :while or :for"
+msgstr "E586: :continue uten :while eller :for"
+
+msgid "E587: :break without :while or :for"
+msgstr "E587: :break uten :while eller :for"
+
+msgid "E732: Using :endfor with :while"
+msgstr "E732: Bruker :endfor sammen med :while"
+
+msgid "E733: Using :endwhile with :for"
+msgstr "E733: Bruker :endwhile sammen med :for"
+
+msgid "E601: :try nesting too deep"
+msgstr "E601: Nøsting av :try for dyp"
+
+msgid "E603: :catch without :try"
+msgstr "E603: :catch uten :try"
+
+#. Give up for a ":catch" after ":finally" and ignore it.
+#. * Just parse.
+msgid "E604: :catch after :finally"
+msgstr "E604: :catch etter :finally"
+
+msgid "E606: :finally without :try"
+msgstr "E606: :finally uten :try"
+
+#. Give up for a multiple ":finally" and ignore it.
+msgid "E607: multiple :finally"
+msgstr "E607: Flere forekomster av :finally"
+
+msgid "E602: :endtry without :try"
+msgstr "E602: :endtry uten :try"
+
+msgid "E193: :endfunction not inside a function"
+msgstr "E193: :endfunction er ikke innenfor en funksjon"
+
+msgid "E788: Not allowed to edit another buffer now"
+msgstr "E788: Ikke tillatt å redigere en annen buffer nå"
+
+msgid "tagname"
+msgstr "navn på tag"
+
+#~ msgid " kind file\n"
+#~ msgstr ""
+
+msgid "'history' option is zero"
+msgstr "'history'-valget er null"
+
+#, c-format
+msgid ""
+"\n"
+"# %s History (newest to oldest):\n"
+msgstr ""
+"\n"
+"# %s-historie (nyeste til eldste):\n"
+
+msgid "Command Line"
+msgstr "Kommandolinje"
+
+msgid "Search String"
+msgstr "Søkestreng"
+
+msgid "Expression"
+msgstr "Uttrykk"
+
+msgid "Input Line"
+msgstr "Inndatalinje"
+
+msgid "E198: cmd_pchar beyond the command length"
+msgstr "E198: cmd_pchar utenfor kommandolengden"
+
+msgid "E199: Active window or buffer deleted"
+msgstr "E199: Aktivt vindu eller buffer slettet"
+
+msgid "Illegal file name"
+msgstr "Ulovlig filnavn"
+
+msgid "is a directory"
+msgstr "er en katalog"
+
+msgid "is not a file"
+msgstr "er ikke en fil"
+
+msgid "is a device (disabled with 'opendevice' option)"
+msgstr "er en enhet (frakoblet med 'opendevice'-valg)"
+
+msgid "[New File]"
+msgstr "[Ny fil]"
+
+msgid "[New DIRECTORY]"
+msgstr "[Ny KATALOG]"
+
+msgid "[File too big]"
+msgstr "[Filen er for stor]"
+
+msgid "[Permission Denied]"
+msgstr "[Tilgang nektet]"
+
+msgid "E200: *ReadPre autocommands made the file unreadable"
+msgstr "E200: \"*ReadPre\"-autokommandoer gjorde filen uleselig"
+
+msgid "E201: *ReadPre autocommands must not change current buffer"
+msgstr "E201: \"*ReadPre\"-autokommandoer må ikke forandre nåværende buffer"
+
+msgid "Vim: Reading from stdin...\n"
+msgstr "Vim: Leser fra stdin ...\n"
+
+msgid "Reading from stdin..."
+msgstr "Leser fra stdin ..."
+
+#. Re-opening the original file failed!
+msgid "E202: Conversion made file unreadable!"
+msgstr "E202: Konverteringen gjorde filen uleselig!"
+
+msgid "[fifo/socket]"
+msgstr "[fifo/socket]"
+
+msgid "[fifo]"
+msgstr "[fifo]"
+
+msgid "[socket]"
+msgstr "[socket]"
+
+msgid "[RO]"
+msgstr "[SB]"
+
+msgid "[CR missing]"
+msgstr "[CR mangler]"
+
+msgid "[NL found]"
+msgstr "[NL funnet]"
+
+msgid "[long lines split]"
+msgstr "[lange linjer splittes]"
+
+msgid "[NOT converted]"
+msgstr "[IKKE konvertert]"
+
+msgid "[converted]"
+msgstr "[konvertert]"
+
+msgid "[crypted]"
+msgstr "[kryptert]"
+
+#, c-format
+msgid "[CONVERSION ERROR in line %ld]"
+msgstr "[KONVERTERINGSFEIL i linje %ld]"
+
+#, c-format
+msgid "[ILLEGAL BYTE in line %ld]"
+msgstr "[ULOVLIG BYTE i linje %ld]"
+
+msgid "[READ ERRORS]"
+msgstr "[LESEFEIL]"
+
+msgid "Can't find temp file for conversion"
+msgstr "Kan ikke finne midlertidig fil for konvertering"
+
+msgid "Conversion with 'charconvert' failed"
+msgstr "Konvertering med 'charconvert' feilet"
+
+msgid "can't read output of 'charconvert'"
+msgstr "Kan ikke lese utdata fra 'charconvert'"
+
+msgid "E676: No matching autocommands for acwrite buffer"
+msgstr "E676: Ingen samsvarende autokommandoer for 'acwrite'-buffer"
+
+msgid "E203: Autocommands deleted or unloaded buffer to be written"
+msgstr "E203: Autokommandoer slettet eller lastet ut buffer som skulle lagres"
+
+msgid "E204: Autocommand changed number of lines in unexpected way"
+msgstr "E204: Autokommando forandret linjeantall på en uventet måte"
+
+msgid "NetBeans disallows writes of unmodified buffers"
+msgstr "NetBeans forbyr lagring av buffere som ikke er forandret"
+
+msgid "Partial writes disallowed for NetBeans buffers"
+msgstr "Delvis lagring ikke tillatt for NetBeans-buffere"
+
+msgid "is not a file or writable device"
+msgstr "er ikke en fil eller skrivbar enhet"
+
+msgid "writing to device disabled with 'opendevice' option"
+msgstr "skriving til enhet er slått av med 'opendevice'-valg"
+
+msgid "is read-only (add ! to override)"
+msgstr "er skrivebeskyttet (legg til ! for å overstyre)"
+
+msgid "E506: Can't write to backup file (add ! to override)"
+msgstr "E506: Kan ikke skrive til backupfil (legg til ! for å overstyre)"
+
+msgid "E507: Close error for backup file (add ! to override)"
+msgstr "E507: Feil under lukking av backupfil (legg til ! for å overstyre)"
+
+msgid "E508: Can't read file for backup (add ! to override)"
+msgstr "E508: Kan ikke lese fil for backup (legg til ! for å overstyre)"
+
+msgid "E509: Cannot create backup file (add ! to override)"
+msgstr "E509: Kan ikke lese backupfil (legg til ! for å overstyre)"
+
+msgid "E510: Can't make backup file (add ! to override)"
+msgstr "E510: Kan ikke lage backupfil (legg til ! for å overstyre)"
+
+msgid "E460: The resource fork would be lost (add ! to override)"
+msgstr "E460: Ressursforgreningen ville gått tapt (legg til ! for å overstyre)"
+
+msgid "E214: Can't find temp file for writing"
+msgstr "E214: Kan ikke finne midlertidig fil for skriving"
+
+msgid "E213: Cannot convert (add ! to write without conversion)"
+msgstr "E213: Kan ikke konvertere (legg til ! for å lagre uten konvertering)"
+
+msgid "E166: Can't open linked file for writing"
+msgstr "E166: Kan ikke åpne lenket fil for skriving"
+
+msgid "E212: Can't open file for writing"
+msgstr "E212: Kan ikke åpne fil for skriving"
+
+msgid "E667: Fsync failed"
+msgstr "E667: Fsync feilet"
+
+msgid "E512: Close failed"
+msgstr "E512: Lukking feilet"
+
+msgid "E513: write error, conversion failed (make 'fenc' empty to override)"
+msgstr ""
+"E513: Feil under skriving, konvertering feilet (gjør 'fenc' tom for å "
+"overstyre)"
+
+msgid "E514: write error (file system full?)"
+msgstr "E514: Feil under lagring (full disk?)"
+
+msgid " CONVERSION ERROR"
+msgstr " KONVERTERINGSFEIL"
+
+msgid "[Device]"
+msgstr "[Enhet]"
+
+msgid "[New]"
+msgstr "[Ny]"
+
+msgid " [a]"
+msgstr " [l]"
+
+msgid " appended"
+msgstr " lagt til"
+
+msgid " [w]"
+msgstr " [s]"
+
+msgid " written"
+msgstr " skrevet"
+
+msgid "E205: Patchmode: can't save original file"
+msgstr "E205: Patchmode: Kan ikke lagre originalfil"
+
+msgid "E206: patchmode: can't touch empty original file"
+msgstr "E206: patchmode: Kan ikke oppdatere tom originalfil"
+
+msgid "E207: Can't delete backup file"
+msgstr "E207: Kan ikke slette backupfil"
+
+msgid ""
+"\n"
+"WARNING: Original file may be lost or damaged\n"
+msgstr ""
+"\n"
+"ADVARSEL: Originalfilen kan bli tapt eller ødelagt\n"
+
+msgid "don't quit the editor until the file is successfully written!"
+msgstr "ikke avslutt editoren før filen er skikkelig lagret!"
+
+msgid "[dos]"
+msgstr "[dos]"
+
+msgid "[dos format]"
+msgstr "[dos-format]"
+
+msgid "[mac]"
+msgstr "[mac]"
+
+msgid "[mac format]"
+msgstr "[mac-format]"
+
+msgid "[unix]"
+msgstr "[unix]"
+
+msgid "[unix format]"
+msgstr "[unix-format]"
+
+msgid "1 line, "
+msgstr "1 linje, "
+
+#, c-format
+msgid "%ld lines, "
+msgstr "%ld linjer, "
+
+msgid "1 character"
+msgstr "1 tegn"
+
+#, c-format
+msgid "%ld characters"
+msgstr "%ld tegn"
+
+msgid "[noeol]"
+msgstr "[ingenlinjeslutt]"
+
+msgid "[Incomplete last line]"
+msgstr "[Ufullstendig sistelinje]"
+
+#. don't overwrite messages here
+#. must give this prompt
+#. don't use emsg() here, don't want to flush the buffers
+msgid "WARNING: The file has been changed since reading it!!!"
+msgstr "ADVARSEL: Filen er blitt forandret siden den ble lest!!!"
+
+msgid "Do you really want to write to it"
+msgstr "Vil du virkelig skrive til den"
+
+#, c-format
+msgid "E208: Error writing to \"%s\""
+msgstr "E208: Feil under skriving til \"%s\""
+
+#, c-format
+msgid "E209: Error closing \"%s\""
+msgstr "E209: Feil under lukking av \"%s\""
+
+#, c-format
+msgid "E210: Error reading \"%s\""
+msgstr "E210: Feil under lesing av \"%s\""
+
+msgid "E246: FileChangedShell autocommand deleted buffer"
+msgstr "E246: Autokommandoen \"FileChangedShell\" slettet buffer"
+
+#, c-format
+msgid "E211: File \"%s\" no longer available"
+msgstr "E211: Filen \"%s\" er ikke lenger tilgjengelig"
+
+#, c-format
+msgid ""
+"W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as "
+"well"
+msgstr ""
+"W12: Advarsel: Filen \"%s\" er forandret og bufferen var også forandret i Vim"
+
+msgid "See \":help W12\" for more info."
+msgstr "Se \":help W12\" for mer informasjon."
+
+#, c-format
+msgid "W11: Warning: File \"%s\" has changed since editing started"
+msgstr "W11: Advarsel: Filen \"%s\" er forandret siden redigeringen startet"
+
+msgid "See \":help W11\" for more info."
+msgstr "Se \":help W11\" for mer informasjon."
+
+#, c-format
+msgid "W16: Warning: Mode of file \"%s\" has changed since editing started"
+msgstr ""
+"W16: Advarsel: Rettighetene til filen \"%s\" er forandret siden redigeringen "
+"startet"
+
+msgid "See \":help W16\" for more info."
+msgstr "Se \":help W16\" for mer informasjon."
+
+#, c-format
+msgid "W13: Warning: File \"%s\" has been created after editing started"
+msgstr ""
+"W13: Advarsel: Filen \"%s\" er blitt opprettet etter at redigeringen startet"
+
+msgid "Warning"
+msgstr "Advarsel"
+
+msgid ""
+"&OK\n"
+"&Load File"
+msgstr ""
+"&OK\n"
+"&Åpne fil"
+
+#, c-format
+msgid "E462: Could not prepare for reloading \"%s\""
+msgstr "E462: Kunne ikke forberede for relasting \"%s\""
+
+#, c-format
+msgid "E321: Could not reload \"%s\""
+msgstr "E321: Kunne ikke laste \"%s\" på nytt"
+
+msgid "--Deleted--"
+msgstr "--Slettet--"
+
+#, c-format
+msgid "auto-removing autocommand: %s <buffer=%d>"
+msgstr "fjerner autokommando automatisk: %s <buffer=%d>"
+
+#. the group doesn't exist
+#, c-format
+msgid "E367: No such group: \"%s\""
+msgstr "E367: Gruppen finnes ikke: \"%s\""
+
+#, c-format
+msgid "E215: Illegal character after *: %s"
+msgstr "E215: Ulovlig tegn etter *: %s"
+
+#, c-format
+msgid "E216: No such event: %s"
+msgstr "E216: Handlingen finnes ikke: %s"
+
+#, c-format
+msgid "E216: No such group or event: %s"
+msgstr "E216: Gruppen eller handlingen finnes ikke: %s"
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Autocommands ---"
+msgstr ""
+"\n"
+"--- Autokommandoer ---"
+
+#, c-format
+msgid "E680: <buffer=%d>: invalid buffer number "
+msgstr "E680: <buffer=%d>: Ugyldig buffernummer"
+
+msgid "E217: Can't execute autocommands for ALL events"
+msgstr "E217: Kan ikke utføre autokommandoer for ALLE hendelser"
+
+msgid "No matching autocommands"
+msgstr "Ingen samsvarende autokommandoer"
+
+msgid "E218: autocommand nesting too deep"
+msgstr "E218: Nøsting av autokommandoer for dyp"
+
+#, c-format
+msgid "%s Autocommands for \"%s\""
+msgstr "%s Autokommandoer for \"%s\""
+
+#, c-format
+msgid "Executing %s"
+msgstr "Utfører %s"
+
+#, c-format
+msgid "autocommand %s"
+msgstr "autokommando %s"
+
+msgid "E219: Missing {."
+msgstr "E219: Mangler {."
+
+msgid "E220: Missing }."
+msgstr "E220: Mangler }."
+
+msgid "E490: No fold found"
+msgstr "E490: Ingen fold funnet"
+
+msgid "E350: Cannot create fold with current 'foldmethod'"
+msgstr "E350: Kan ikke lage fold med nåværende 'foldmethod'"
+
+msgid "E351: Cannot delete fold with current 'foldmethod'"
+msgstr "E351: Kan ikke slette fold med nåværende 'foldmethod'"
+
+#, c-format
+msgid "+--%3ld lines folded "
+msgstr "+--%3ld linjer foldet "
+
+msgid "E222: Add to read buffer"
+msgstr "E222: Legger til allerede lest buffer"
+
+msgid "E223: recursive mapping"
+msgstr "E223: Rekursiv mapping"
+
+#, c-format
+msgid "E224: global abbreviation already exists for %s"
+msgstr "E224: Global forkortelse finnes allerede for %s"
+
+#, c-format
+msgid "E225: global mapping already exists for %s"
+msgstr "E225: Global mapping finnes allerede for %s"
+
+#, c-format
+msgid "E226: abbreviation already exists for %s"
+msgstr "E226: Forkortelse finnes allerede for %s"
+
+#, c-format
+msgid "E227: mapping already exists for %s"
+msgstr "E227: Mappingen finnes allerede for %s"
+
+msgid "No abbreviation found"
+msgstr "Ingen forkortelse funnet"
+
+msgid "No mapping found"
+msgstr "Ingen mapping funnet"
+
+msgid "E228: makemap: Illegal mode"
+msgstr "E228: makemap: Ulovlig modus"
+
+msgid "E229: Cannot start the GUI"
+msgstr "E229: Kan ikke starte grafisk brukergrensesnitt (GUI)"
+
+#, c-format
+msgid "E230: Cannot read from \"%s\""
+msgstr "E230: Kan ikke lese fra \"%s\""
+
+msgid "E665: Cannot start GUI, no valid font found"
+msgstr ""
+"E665: Kan ikke starte grafisk brukergrensesnitt, fant ingen gyldig font"
+
+msgid "E231: 'guifontwide' invalid"
+msgstr "E231: 'guifontwide' ugyldig"
+
+msgid "E599: Value of 'imactivatekey' is invalid"
+msgstr "E599: Verdien for 'imactivatekey' er ugyldig"
+
+#, c-format
+msgid "E254: Cannot allocate color %s"
+msgstr "E254: Kan ikke reservere farge %s"
+
+msgid "No match at cursor, finding next"
+msgstr "Ingen treff ved markøren, finner neste"
+
+msgid "<cannot open> "
+msgstr "<kan ikke åpne> "
+
+#, c-format
+msgid "E616: vim_SelFile: can't get font %s"
+msgstr "E616: vim_SelFile: Kan ikke bruke skrifttypen %s"
+
+msgid "E614: vim_SelFile: can't return to current directory"
+msgstr "E614: vim_SelFile: Kan ikke returnere til nåværende katalog"
+
+msgid "Pathname:"
+msgstr "Sti:"
+
+msgid "E615: vim_SelFile: can't get current directory"
+msgstr "E615: vim_SelFile: Kan ikke finne nåværende katalog"
+
+msgid "OK"
+msgstr "OK"
+
+msgid "Cancel"
+msgstr "Avbryt"
+
+msgid "Scrollbar Widget: Could not get geometry of thumb pixmap."
+msgstr "Rullefeltelement: Klarte ikke hente dimensjoner på \"thumb pixmap\"."
+
+msgid "Vim dialog"
+msgstr "Dialogvindu for Vim"
+
+msgid "E232: Cannot create BalloonEval with both message and callback"
+msgstr "E232: Kan ikke lage BalloonEval med både melding og tilbakekall"
+
+msgid "Vim dialog..."
+msgstr "Vim dialogvindu ..."
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"&Cancel"
+msgstr ""
+"&Ja\n"
+"&Nei\n"
+"&Avbryt"
+
+msgid "Input _Methods"
+msgstr "Inndata-_metoder"
+
+msgid "VIM - Search and Replace..."
+msgstr "VIM - Søk og erstatt ..."
+
+msgid "VIM - Search..."
+msgstr "VIM - Søk ..."
+
+msgid "Find what:"
+msgstr "Finn hva:"
+
+msgid "Replace with:"
+msgstr "Erstatt med:"
+
+#. whole word only button
+msgid "Match whole word only"
+msgstr "Finn kun hele ord"
+
+#. match case button
+msgid "Match case"
+msgstr "Forskjell på store/små bokstaver"
+
+msgid "Direction"
+msgstr "Retning"
+
+#. 'Up' and 'Down' buttons
+msgid "Up"
+msgstr "Opp"
+
+msgid "Down"
+msgstr "Ned"
+
+msgid "Find Next"
+msgstr "Finn neste"
+
+msgid "Replace"
+msgstr "Erstatt"
+
+msgid "Replace All"
+msgstr "Erstatt alle"
+
+msgid "Vim: Received \"die\" request from session manager\n"
+msgstr "Vim: Mottok \"dø\"-forespørsel fra øktbehandleren\n"
+
+msgid "Close"
+msgstr "Lukk"
+
+#~ msgid "New tab"
+#~ msgstr ""
+
+#~ msgid "Open Tab..."
+#~ msgstr ""
+
+msgid "Vim: Main window unexpectedly destroyed\n"
+msgstr "Vim: Uventet ødeleggelse av hovedvinduet\n"
+
+msgid "Font Selection"
+msgstr "Velge skrifttype"
+
+msgid "Used CUT_BUFFER0 instead of empty selection"
+msgstr "Brukte CUT_BUFFER0 istedenfor tomt valg"
+
+msgid "&Filter"
+msgstr "&Filter"
+
+msgid "&Cancel"
+msgstr "&Avbryt"
+
+msgid "Directories"
+msgstr "Kataloger"
+
+msgid "Filter"
+msgstr "Filter"
+
+msgid "&Help"
+msgstr "&Hjelp"
+
+msgid "Files"
+msgstr "Filer"
+
+msgid "&OK"
+msgstr "&OK"
+
+msgid "Selection"
+msgstr "Valg"
+
+msgid "Find &Next"
+msgstr "Finn &neste"
+
+msgid "&Replace"
+msgstr "E&rstatt"
+
+msgid "Replace &All"
+msgstr "Erstatt &alle"
+
+msgid "&Undo"
+msgstr "&Angre"
+
+#, c-format
+msgid "E671: Cannot find window title \"%s\""
+msgstr "E671: Fant ikke vindutittel \"%s\""
+
+#, c-format
+msgid "E243: Argument not supported: \"-%s\"; Use the OLE version."
+msgstr "E243: Parameter ikke støttet: \"-%s\"; Bruk OLE-versjonen."
+
+msgid "E672: Unable to open window inside MDI application"
+msgstr "E672: Klarer ikke åpne vindu inne i MDI-applikasjon"
+
+#~ msgid "Close tab"
+#~ msgstr ""
+
+#~ msgid "Open tab..."
+#~ msgstr ""
+
+msgid "Find string (use '\\\\' to find a '\\')"
+msgstr "Finn streng (bruk '\\\\' for å finne en '\\')"
+
+msgid "Find & Replace (use '\\\\' to find a '\\')"
+msgstr "Søk og erstatt (bruk '\\\\' for å finne en '\\')"
+
+#. We fake this: Use a filter that doesn't select anything and a default
+#. * file name that won't be used.
+msgid "Not Used"
+msgstr "Ikke brukt"
+
+msgid "Directory\t*.nothing\n"
+msgstr "Katalog\t*.ingenting\n"
+
+msgid "Vim E458: Cannot allocate colormap entry, some colors may be incorrect"
+msgstr "Vim E458: Kan ikke reservere fargekart, noen farger kan være feil"
+
+#, c-format
+msgid "E250: Fonts for the following charsets are missing in fontset %s:"
+msgstr "E250: Skrifttyper for de følgende tegnsett mangler i fontsett %s:"
+
+#, c-format
+msgid "E252: Fontset name: %s"
+msgstr "E252: Navn på skrifttypesett: %s"
+
+#, c-format
+msgid "Font '%s' is not fixed-width"
+msgstr "Skrifttypen '%s' har ikke konstant bredde"
+
+#, c-format
+msgid "E253: Fontset name: %s\n"
+msgstr "E253: Navn på skrifttypesett: %s\n"
+
+#, c-format
+msgid "Font0: %s\n"
+msgstr "Font0: %s\n"
+
+#, c-format
+msgid "Font1: %s\n"
+msgstr "Font1: %s\n"
+
+#, c-format
+msgid "Font%ld width is not twice that of font0\n"
+msgstr "Font%ld-bredde er ikke to ganger bredden av font0\n"
+
+#, c-format
+msgid "Font0 width: %ld\n"
+msgstr "Font0-bredde: %ld\n"
+
+#, c-format
+msgid ""
+"Font1 width: %ld\n"
+"\n"
+msgstr ""
+"Font1-bredde: %ld\n"
+"\n"
+
+msgid "Invalid font specification"
+msgstr "Ugyldig skrifttypespesifisering"
+
+msgid "&Dismiss"
+msgstr "&Forkast"
+
+msgid "no specific match"
+msgstr "ingen spesifikke treff"
+
+msgid "Vim - Font Selector"
+msgstr "Vim - Skrifttypevelger"
+
+msgid "Name:"
+msgstr "Navn:"
+
+#. create toggle button
+msgid "Show size in Points"
+msgstr "Vis størrelse i punkter"
+
+msgid "Encoding:"
+msgstr "Koding:"
+
+msgid "Font:"
+msgstr "Skrifttype:"
+
+msgid "Style:"
+msgstr "Stil:"
+
+msgid "Size:"
+msgstr "Størrelse:"
+
+#~ msgid "E256: Hangul automata ERROR"
+#~ msgstr ""
+
+msgid "E550: Missing colon"
+msgstr "E550: Mangler kolon"
+
+msgid "E551: Illegal component"
+msgstr "E551: Ulovlig komponent"
+
+msgid "E552: digit expected"
+msgstr "E552: Siffer forventet"
+
+#, c-format
+msgid "Page %d"
+msgstr "Side %d"
+
+msgid "No text to be printed"
+msgstr "Ingen tekst for utskrift"
+
+#, c-format
+msgid "Printing page %d (%d%%)"
+msgstr "Skriver ut side %d (%d%%)"
+
+#, c-format
+msgid " Copy %d of %d"
+msgstr " Kopi %d av %d"
+
+#, c-format
+msgid "Printed: %s"
+msgstr "Skrevet ut: %s"
+
+msgid "Printing aborted"
+msgstr "Utskrift avbrutt"
+
+msgid "E455: Error writing to PostScript output file"
+msgstr "E455: Feil under skriving til Postscript-fil"
+
+#, c-format
+msgid "E624: Can't open file \"%s\""
+msgstr "E624: Kan ikke åpne filen \"%s\""
+
+#, c-format
+msgid "E457: Can't read PostScript resource file \"%s\""
+msgstr "E457: Kan ikke lese Postscript-ressursfil \"%s\""
+
+#, c-format
+msgid "E618: file \"%s\" is not a PostScript resource file"
+msgstr "E618: Filen \"%s\" er ikke en Postscript-ressursfil"
+
+#, c-format
+msgid "E619: file \"%s\" is not a supported PostScript resource file"
+msgstr "E619: Det er ikke støtte for Postscript-ressursfilen \"%s\""
+
+#, c-format
+msgid "E621: \"%s\" resource file has wrong version"
+msgstr "E621: Ressursfilen \"%s\" er feil versjon"
+
+msgid "E673: Incompatible multi-byte encoding and character set."
+msgstr "E673: Inkompatibel multibytekoding og tegnsett"
+
+msgid "E674: printmbcharset cannot be empty with multi-byte encoding."
+msgstr "E674: printmbcharset kan ikke være tom med multibytekoding"
+
+msgid "E675: No default font specified for multi-byte printing."
+msgstr "E675: Ingen standardfont spesifisert for multibyteutskrift"
+
+msgid "E324: Can't open PostScript output file"
+msgstr "E324: Kan ikke åpne Postscript-fil for skriving"
+
+#, c-format
+msgid "E456: Can't open file \"%s\""
+msgstr "E456: Kan ikke åpne filen \"%s\""
+
+msgid "E456: Can't find PostScript resource file \"prolog.ps\""
+msgstr "E456: Fant ikke Postscript-ressursfilen \"prolog.ps\""
+
+msgid "E456: Can't find PostScript resource file \"cidfont.ps\""
+msgstr "E456: Fant ikke Postscript-ressursfilen \"cidfont.ps\""
+
+#, c-format
+msgid "E456: Can't find PostScript resource file \"%s.ps\""
+msgstr "E456: Fant ikke Postscript-ressursfilen \"%s.ps\""
+
+#, c-format
+msgid "E620: Unable to convert to print encoding \"%s\""
+msgstr "E620: Klarte ikke å konvertere til utskriftskoding \"%s\""
+
+msgid "Sending to printer..."
+msgstr "Sender til skriver ..."
+
+msgid "E365: Failed to print PostScript file"
+msgstr "E365: Feil under utskrift av Postscript-fil"
+
+msgid "Print job sent."
+msgstr "Skriverjobb sendt."
+
+msgid "Add a new database"
+msgstr "Legg til en ny database"
+
+msgid "Query for a pattern"
+msgstr "Forespørsel etter søkestreng"
+
+msgid "Show this message"
+msgstr "Vis denne meldingen"
+
+msgid "Kill a connection"
+msgstr "Drep en forbindelse"
+
+msgid "Reinit all connections"
+msgstr "Reinitialiser alle forbindelser"
+
+msgid "Show connections"
+msgstr "Vis forbindelser"
+
+#, c-format
+msgid "E560: Usage: cs[cope] %s"
+msgstr "E560: Bruk: cs[cope] %s"
+
+msgid "This cscope command does not support splitting the window.\n"
+msgstr "Denne cscope-kommandoen støtter ikke splitting av vinduet.\n"
+
+msgid "E562: Usage: cstag <ident>"
+msgstr "E562: Bruk: cstag <identifikator>"
+
+msgid "E257: cstag: tag not found"
+msgstr "E257: cstag: Tag ikke funnet"
+
+#, c-format
+msgid "E563: stat(%s) error: %d"
+msgstr "E563: stat(%s) feil: %d"
+
+msgid "E563: stat error"
+msgstr "E563: \"stat\"-feil"
+
+#, c-format
+msgid "E564: %s is not a directory or a valid cscope database"
+msgstr "E564: %s er ikke en katalog eller gyldig cscope-database"
+
+#, c-format
+msgid "Added cscope database %s"
+msgstr "La til cscope-database %s"
+
+#, c-format
+msgid "E262: error reading cscope connection %ld"
+msgstr "E262: Feil under lesing av cscope-forbindelse %ld"
+
+msgid "E561: unknown cscope search type"
+msgstr "E561: Ukjent cscope-søketype"
+
+msgid "E566: Could not create cscope pipes"
+msgstr "E566: Kunne ikke lage cscope-rør (\"pipe\")"
+
+msgid "E622: Could not fork for cscope"
+msgstr "E622: Klarte ikke lage tvillingprosess for cscope"
+
+msgid "cs_create_connection exec failed"
+msgstr "Utføring av cs_create_connection feilet"
+
+msgid "E623: Could not spawn cscope process"
+msgstr "E623: Klarte ikke starte cscope-prosess"
+
+msgid "cs_create_connection: fdopen for to_fp failed"
+msgstr "cs_create_connection: fdopen for to_fp feilet"
+
+msgid "cs_create_connection: fdopen for fr_fp failed"
+msgstr "cs_create_connection: fdopen for fr_fp feilet"
+
+msgid "E567: no cscope connections"
+msgstr "E567: Ingen cscope-forbindelse"
+
+#, c-format
+msgid "E259: no matches found for cscope query %s of %s"
+msgstr "E259: Ingen treff funnet for cscope-forespørsel %s av %s"
+
+#, c-format
+msgid "E469: invalid cscopequickfix flag %c for %c"
+msgstr "E469: Ugyldig \"cscopequickfix\"-flagg %c for %c"
+
+msgid "cscope commands:\n"
+msgstr "cscope-kommandoer:\n"
+
+#, c-format
+msgid "%-5s: %-30s (Usage: %s)"
+msgstr "%-5s: %-30s (Bruk: %s)"
+
+#, c-format
+msgid "E625: cannot open cscope database: %s"
+msgstr "E625: Kan ikke åpne cscope-database: %s"
+
+msgid "E626: cannot get cscope database information"
+msgstr "E626: Kan ikke hente informasjon om cscope-database"
+
+msgid "E568: duplicate cscope database not added"
+msgstr "E568: Duplisert cscope-database ikke lagt til"
+
+msgid "E569: maximum number of cscope connections reached"
+msgstr "E569: Maksimum antall cscope-forbindelser nådd"
+
+#, c-format
+msgid "E261: cscope connection %s not found"
+msgstr "E261: cscope-forbindelse %s ikke funnet"
+
+#, c-format
+msgid "cscope connection %s closed"
+msgstr "cscope-forbindelsen %s stengt"
+
+#. should not reach here
+msgid "E570: fatal error in cs_manage_matches"
+msgstr "E570: Kritisk feil i cs_manage_matches"
+
+#, c-format
+msgid "Cscope tag: %s"
+msgstr "Cscope-tag: %s"
+
+msgid ""
+"\n"
+" # line"
+msgstr ""
+"\n"
+" # linje"
+
+msgid "filename / context / line\n"
+msgstr "filnavn / kontekst / linje\n"
+
+#, c-format
+msgid "E609: Cscope error: %s"
+msgstr "E609: Cscope-feil: %s"
+
+msgid "All cscope databases reset"
+msgstr "Alle cscope-databaser resatt"
+
+msgid "no cscope connections\n"
+msgstr "ingen cscope-forbindelser\n"
+
+msgid " # pid database name prepend path\n"
+msgstr " # pid databasenavn legg til sti\n"
+
+msgid ""
+"???: Sorry, this command is disabled, the MzScheme library could not be "
+"loaded."
+msgstr ""
+"???: Denne kommandoen er deaktivert, MzScheme-biblioteket kunne ikke lastes."
+
+msgid "invalid expression"
+msgstr "ugyldig uttrykk"
+
+msgid "expressions disabled at compile time"
+msgstr "uttrykk deaktivert på kompileringsstadiet"
+
+msgid "hidden option"
+msgstr "skjult valg"
+
+msgid "unknown option"
+msgstr "ukjent valg"
+
+msgid "window index is out of range"
+msgstr "indeks for vindu er utenfor område"
+
+msgid "couldn't open buffer"
+msgstr "klarte ikke å åpne buffer"
+
+msgid "cannot save undo information"
+msgstr "kan ikke lagre angre-informasjon"
+
+msgid "cannot delete line"
+msgstr "kan ikke slette linje"
+
+msgid "cannot replace line"
+msgstr "kan ikke erstatte linje"
+
+msgid "cannot insert line"
+msgstr "kan ikke sette inn linje"
+
+msgid "string cannot contain newlines"
+msgstr "streng kan ikke inneholde linjeskift"
+
+msgid "Vim error: ~a"
+msgstr "Vim-feil: ~a"
+
+msgid "Vim error"
+msgstr "Vim-feil"
+
+msgid "buffer is invalid"
+msgstr "buffer er ugyldig"
+
+msgid "window is invalid"
+msgstr "vindu er ugyldig"
+
+msgid "linenr out of range"
+msgstr "linjenummer utenfor område"
+
+msgid "not allowed in the Vim sandbox"
+msgstr "ikke tillatt i Vim-sandkassen"
+
+msgid ""
+"E263: Sorry, this command is disabled, the Python library could not be "
+"loaded."
+msgstr ""
+"E263: Denne kommandoen er deaktivert, Python-biblioteket kunne ikke lastes."
+
+msgid "E659: Cannot invoke Python recursively"
+msgstr "E659: Kan ikke starte Python rekursivt"
+
+msgid "can't delete OutputObject attributes"
+msgstr "Kan ikke slette \"OutputObject\"-attributter"
+
+msgid "softspace must be an integer"
+msgstr "\"softspace\" må være et heltall"
+
+msgid "invalid attribute"
+msgstr "ugyldig attributt"
+
+msgid "writelines() requires list of strings"
+msgstr "writelines() krever en liste av strenger"
+
+msgid "E264: Python: Error initialising I/O objects"
+msgstr "E264: Python: Feil under initialisering av I/U-objekter"
+
+msgid "attempt to refer to deleted buffer"
+msgstr "forsøk på å referere til slettet buffer"
+
+msgid "line number out of range"
+msgstr "linjenummer utenfor område"
+
+#, c-format
+msgid "<buffer object (deleted) at %8lX>"
+msgstr "<bufferobjekt (slettet) ved %8lX>"
+
+msgid "invalid mark name"
+msgstr "ugyldig merkenavn"
+
+msgid "no such buffer"
+msgstr "bufferen finnes ikke"
+
+msgid "attempt to refer to deleted window"
+msgstr "forsøk på å referere til slettet vindu"
+
+msgid "readonly attribute"
+msgstr "skrivebeskyttet attributt"
+
+msgid "cursor position outside buffer"
+msgstr "markørposisjon utenfor buffer"
+
+#, c-format
+msgid "<window object (deleted) at %.8lX>"
+msgstr "<vindusobjekt (slettet) ved %.8lX>"
+
+#, c-format
+msgid "<window object (unknown) at %.8lX>"
+msgstr "<vindusobjekt (ukjent) ved %.8lX>"
+
+#, c-format
+msgid "<window %d>"
+msgstr "<vindu %d>"
+
+msgid "no such window"
+msgstr "vinduet finnes ikke"
+
+#~ msgid "E265: $_ must be an instance of String"
+#~ msgstr ""
+
+msgid ""
+"E266: Sorry, this command is disabled, the Ruby library could not be loaded."
+msgstr ""
+"E266: Denne kommandoen er deaktivert, Ruby-biblioteket kunne ikke lastes."
+
+msgid "E267: unexpected return"
+msgstr "E267: Uventet return"
+
+msgid "E268: unexpected next"
+msgstr "E268: Uvented next"
+
+msgid "E269: unexpected break"
+msgstr "E269: Uventet break"
+
+msgid "E270: unexpected redo"
+msgstr "E270: Uventet redo"
+
+#~ msgid "E271: retry outside of rescue clause"
+#~ msgstr ""
+
+msgid "E272: unhandled exception"
+msgstr "E272: Ubehandlet unntak"
+
+#, c-format
+msgid "E273: unknown longjmp status %d"
+msgstr "E273: Ukjent longjmp-status %d"
+
+msgid "Toggle implementation/definition"
+msgstr "Bytt mellom implementasjon/definisjon"
+
+msgid "Show base class of"
+msgstr "Vis basisklasse av"
+
+msgid "Show overridden member function"
+msgstr "Vis overstyrt medlemsfunksjon"
+
+msgid "Retrieve from file"
+msgstr "Hent fra fil"
+
+msgid "Retrieve from project"
+msgstr "Hent fra prosjekt"
+
+msgid "Retrieve from all projects"
+msgstr "Hent fra alle prosjekter"
+
+msgid "Retrieve"
+msgstr "Hent"
+
+msgid "Show source of"
+msgstr "Vis kilde til"
+
+msgid "Find symbol"
+msgstr "Finn symbol"
+
+msgid "Browse class"
+msgstr "Bla gjennom klasse"
+
+msgid "Show class in hierarchy"
+msgstr "Vis klasse i hierarki"
+
+msgid "Show class in restricted hierarchy"
+msgstr "Vis klasse i begrenset hierarki"
+
+msgid "Xref refers to"
+msgstr "Xref refererer til"
+
+msgid "Xref referred by"
+msgstr "Xref referert av"
+
+msgid "Xref has a"
+msgstr "Xref har en"
+
+msgid "Xref used by"
+msgstr "Xref brukt av"
+
+msgid "Show docu of"
+msgstr "Vis docu av"
+
+msgid "Generate docu for"
+msgstr "Generer docu for"
+
+msgid ""
+"Cannot connect to SNiFF+. Check environment (sniffemacs must be found in "
+"$PATH).\n"
+msgstr ""
+"Kan ikke koble til SNiFF+. Sjekk miljøet (\"environment\") (sniffemacs må "
+"bli funnet i $PATH).\n"
+
+msgid "E274: Sniff: Error during read. Disconnected"
+msgstr "E274: Sniff: Feil under lesing. Frakoblet"
+
+msgid "SNiFF+ is currently "
+msgstr "SNiFF+ er for øyeblikket "
+
+msgid "not "
+msgstr "ikke "
+
+msgid "connected"
+msgstr "oppkoblet"
+
+#, c-format
+msgid "E275: Unknown SNiFF+ request: %s"
+msgstr "E275: Ukjent SNiFF+-forespørsel: %s"
+
+msgid "E276: Error connecting to SNiFF+"
+msgstr "E276: Feil ved oppkobling til SNiFF+"
+
+msgid "E278: SNiFF+ not connected"
+msgstr "E278: SNiFF+ ikke tilkoblet"
+
+msgid "E279: Not a SNiFF+ buffer"
+msgstr "E279: Ikke en SNiFF+-buffer"
+
+msgid "Sniff: Error during write. Disconnected"
+msgstr "Sniff: Feil under skriving. Frakoblet"
+
+msgid "invalid buffer number"
+msgstr "ugyldig buffernummer"
+
+msgid "not implemented yet"
+msgstr "ikke implementert enda"
+
+#. ???
+msgid "cannot set line(s)"
+msgstr "kan ikke sette linje(r)"
+
+msgid "mark not set"
+msgstr "merke ikke satt"
+
+#, c-format
+msgid "row %d column %d"
+msgstr "rad %d kolonne %d"
+
+msgid "cannot insert/append line"
+msgstr "kan ikke sette inn/legge til linje"
+
+msgid "unknown flag: "
+msgstr "ukjent flagg: "
+
+msgid "unknown vimOption"
+msgstr "ukjent vimOption"
+
+msgid "keyboard interrupt"
+msgstr "tastaturavbrudd"
+
+msgid "vim error"
+msgstr "vim-feil"
+
+msgid "cannot create buffer/window command: object is being deleted"
+msgstr "kan ikke opprette buffer/vindukommando: Objektet slettes"
+
+msgid ""
+"cannot register callback command: buffer/window is already being deleted"
+msgstr ""
+"kan ikke registrere callback-kommando: Buffer/vindu er allerede slettet"
+
+#. This should never happen. Famous last word?
+msgid ""
+"E280: TCL FATAL ERROR: reflist corrupt!? Please report this to vim-dev@vim."
+"org"
+msgstr ""
+"E280: TCL KRITISK FEIL: reflist skadet!? Vennligst rapporter dette til vim-"
+"dev@vim.org"
+
+msgid "cannot register callback command: buffer/window reference not found"
+msgstr ""
+"kan ikke registrere callback-kommando: Buffer/vindureferanse ikke funnet"
+
+msgid ""
+"E571: Sorry, this command is disabled: the Tcl library could not be loaded."
+msgstr ""
+"E571: Denne kommandoen er deaktivert, Tcl-biblioteket kunne ikke lastes."
+
+msgid ""
+"E281: TCL ERROR: exit code is not int!? Please report this to vim-dev@vim.org"
+msgstr ""
+"E281: TCL-FEIL: Avslutningskode er ikke int!? Vennligst rapporter dette til "
+"vim-dev@vim.org"
+
+#, c-format
+msgid "E572: exit code %d"
+msgstr "E572: Avslutningskode %d"
+
+msgid "cannot get line"
+msgstr "kan ikke hente linje"
+
+msgid "Unable to register a command server name"
+msgstr "Klarer ikke registrere kommandotjenernavn"
+
+msgid "E248: Failed to send command to the destination program"
+msgstr "E248: Klarte ikke sende kommando til destinasjonsprogrammet"
+
+#, c-format
+msgid "E573: Invalid server id used: %s"
+msgstr "E573: Ugyldig tjener-id brukt: %s"
+
+msgid "E251: VIM instance registry property is badly formed. Deleted!"
+msgstr ""
+"E251: Registry-egenskapen for VIM-oppføringen er ikke korrekt. Slettet!"
+
+msgid "Unknown option argument"
+msgstr "Ukjent parameter til valg"
+
+msgid "Too many edit arguments"
+msgstr "For mange redigeringsparametere"
+
+msgid "Argument missing after"
+msgstr "Parameter mangler etter"
+
+msgid "Garbage after option argument"
+msgstr "Søppel etter valgparameter"
+
+msgid "Too many \"+command\", \"-c command\" or \"--cmd command\" arguments"
+msgstr ""
+"For mange \"+command\"-, \"-c command\"- eller \"--cmd kommando\"-parametere"
+
+msgid "Invalid argument for"
+msgstr "Ugyldig parameter for"
+
+#, c-format
+msgid "%d files to edit\n"
+msgstr "%d filer å redigere\n"
+
+msgid "This Vim was not compiled with the diff feature."
+msgstr "Denne Vim-versjonen er kompilert uten differansefunksjonen."
+
+msgid "Attempt to open script file again: \""
+msgstr "Forsøk på å åpne skriptfilen igjen: \""
+
+msgid "Cannot open for reading: \""
+msgstr "Kan ikke åpne for lesing: \""
+
+msgid "Cannot open for script output: \""
+msgstr "Kan ikke åpne for skript-utdata: \""
+
+msgid "Vim: Error: Failure to start gvim from NetBeans\n"
+msgstr "Vim: Feil: Feil under start av gvim fra NetBeans\n"
+
+msgid "Vim: Warning: Output is not to a terminal\n"
+msgstr "Vim: Advarsel: Utdata går ikke til en terminal\n"
+
+msgid "Vim: Warning: Input is not from a terminal\n"
+msgstr "Vim: Advarsel: Inndata kommer ikke fra en terminal\n"
+
+#. just in case..
+msgid "pre-vimrc command line"
+msgstr "pre-vimrc kommandolinje"
+
+#, c-format
+msgid "E282: Cannot read from \"%s\""
+msgstr "E282: Kan ikke lese fra \"%s\""
+
+msgid ""
+"\n"
+"More info with: \"vim -h\"\n"
+msgstr ""
+"\n"
+"Mer info med: \"vim -h\"\n"
+
+msgid "[file ..] edit specified file(s)"
+msgstr "[file ..] rediger spesifisert(e) fil(er)"
+
+msgid "- read text from stdin"
+msgstr "- les tekst fra stdin"
+
+msgid "-t tag edit file where tag is defined"
+msgstr "-t tag rediger fil hvor en tag er definert"
+
+msgid "-q [errorfile] edit file with first error"
+msgstr "-q [feilfil] rediger fil med første feil"
+
+msgid ""
+"\n"
+"\n"
+"Usage:"
+msgstr ""
+"\n"
+"\n"
+"bruk:"
+
+msgid " vim [arguments] "
+msgstr " vim [parametere] "
+
+msgid ""
+"\n"
+" or:"
+msgstr ""
+"\n"
+" eller:"
+
+msgid "where case is ignored prepend / to make flag upper case"
+msgstr ""
+"der bokstavstørrelse ignoreres, legg til / i begynnelsen for "
+"å gjøre flagget om til stor bokstav"
+
+msgid ""
+"\n"
+"\n"
+"Arguments:\n"
+msgstr ""
+"\n"
+"\n"
+"Parametere:\n"
+
+msgid "--\t\t\tOnly file names after this"
+msgstr "--\t\t\tBare filnavn etter dette"
+
+msgid "--literal\t\tDon't expand wildcards"
+msgstr "--literal\t\tIkke utvid jokertegn"
+
+msgid "-register\t\tRegister this gvim for OLE"
+msgstr "-register\t\tRegistrer gvim for OLE"
+
+msgid "-unregister\t\tUnregister gvim for OLE"
+msgstr "-unregister\t\tFjern OLE-registrering for gvim"
+
+msgid "-g\t\t\tRun using GUI (like \"gvim\")"
+msgstr "-g\t\t\tKjør med GUI (som \"gvim\")"
+
+msgid "-f or --nofork\tForeground: Don't fork when starting GUI"
+msgstr "-f eller --nofork\tForgrunn: Ikke fork når GUI-et startes"
+
+msgid "-v\t\t\tVi mode (like \"vi\")"
+msgstr "-v\t\t\tVi-modus (som \"vi\")"
+
+msgid "-e\t\t\tEx mode (like \"ex\")"
+msgstr "-e\t\t\tEx-modus (som \"ex\")"
+
+msgid "-s\t\t\tSilent (batch) mode (only for \"ex\")"
+msgstr "-s\t\t\tStille (batch) modus (bare for \"ex\")"
+
+msgid "-d\t\t\tDiff mode (like \"vimdiff\")"
+msgstr "-d\t\t\tDifferanse-modus (som \"vimdiff\")"
+
+msgid "-y\t\t\tEasy mode (like \"evim\", modeless)"
+msgstr "-y\t\t\tLett modus (som \"evim\", uten modus)"
+
+msgid "-R\t\t\tReadonly mode (like \"view\")"
+msgstr "-R\t\t\tSkrivebeskyttet modus (som \"view\")"
+
+msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
+msgstr "-Z\t\t\tBegrenset modus (som \"rvim\")"
+
+msgid "-m\t\t\tModifications (writing files) not allowed"
+msgstr "-m\t\t\tModifisering (lagring av filer) ikke tillatt"
+
+msgid "-M\t\t\tModifications in text not allowed"
+msgstr "-M\t\t\tModifiseringer i teksten ikke tillatt"
+
+msgid "-b\t\t\tBinary mode"
+msgstr "-b\t\t\tBinærmodus"
+
+msgid "-l\t\t\tLisp mode"
+msgstr "-l\t\t\tLisp-modus"
+
+msgid "-C\t\t\tCompatible with Vi: 'compatible'"
+msgstr "-C\t\t\tKompatibel med Vi: 'compatible'"
+
+msgid "-N\t\t\tNot fully Vi compatible: 'nocompatible'"
+msgstr "-N\t\t\tIkke helt Vi-kompatibel: 'nocompatible'"
+
+msgid "-V[N]\t\tVerbose level"
+msgstr "-V[N]\t\tInformasjonsnivå (\"Verbose\")"
+
+msgid "-D\t\t\tDebugging mode"
+msgstr "-D\t\t\tDebuggingsmodus"
+
+msgid "-n\t\t\tNo swap file, use memory only"
+msgstr "-n\t\t\tIngen swapfil, bruk bare hukommelsen"
+
+msgid "-r\t\t\tList swap files and exit"
+msgstr "-r\t\t\tList swapfiler og avslutt"
+
+msgid "-r (with file name)\tRecover crashed session"
+msgstr "-r (med filnavn)\tGjenopprett kræsjet økt"
+
+msgid "-L\t\t\tSame as -r"
+msgstr "-L\t\t\tSamme som -r"
+
+msgid "-f\t\t\tDon't use newcli to open window"
+msgstr "-f\t\t\tIkke bruk newcli for å åpne vindu"
+
+msgid "-dev <device>\t\tUse <device> for I/O"
+msgstr "-dev <enhet>\t\tBruk <enhet> for I/U"
+
+msgid "-A\t\t\tStart in Arabic mode"
+msgstr "-A\t\t\tStart i arabisk modus"
+
+msgid "-H\t\t\tStart in Hebrew mode"
+msgstr "-H\t\t\tStart i hebraisk modus"
+
+msgid "-F\t\t\tStart in Farsi mode"
+msgstr "-F\t\t\tStart i persisk (Farsi) modus"
+
+msgid "-T <terminal>\tSet terminal type to <terminal>"
+msgstr "-T <terminal>\tSett terminaltypen til <terminal>"
+
+msgid "-u <vimrc>\t\tUse <vimrc> instead of any .vimrc"
+msgstr "-u <vimrc>\t\tBruk <vimrc> istedenfor eventuell .vimrc"
+
+msgid "-U <gvimrc>\t\tUse <gvimrc> instead of any .gvimrc"
+msgstr "-U <gvimrc>\t\tBruk <gvimrc> istedenfor eventuell .gvimrc"
+
+msgid "--noplugin\t\tDon't load plugin scripts"
+msgstr "--noplugin\t\tIkke last plugin-skripts"
+
+#, fuzzy
+#~ msgid "-p[N]\t\tOpen N tab pages (default: one for each file)"
+#~ msgstr "-o[N]\t\tÅpne N vinduer (standard: Ett for hver fil)"
+
+msgid "-o[N]\t\tOpen N windows (default: one for each file)"
+msgstr "-o[N]\t\tÅpne N vinduer (standard: Ett for hver fil)"
+
+msgid "-O[N]\t\tLike -o but split vertically"
+msgstr "-O[N]\t\tSom -o men splitt loddrett"
+
+msgid "+\t\t\tStart at end of file"
+msgstr "+\t\t\tStart på slutten av filen"
+
+msgid "+<lnum>\t\tStart at line <lnum>"
+msgstr "+<lnr>\t\tStart på linje <lnr>"
+
+msgid "--cmd <command>\tExecute <command> before loading any vimrc file"
+msgstr "--cmd <kommando>\tKjør <kommando> før lasting av vimrc-filer"
+
+msgid "-c <command>\t\tExecute <command> after loading the first file"
+msgstr "-c <kommando>\tKjør <kommando> etter lasting av første fil"
+
+msgid "-S <session>\t\tSource file <session> after loading the first file"
+msgstr "-S <økt>\t\tKjør filen <økt> etter lasting av første fil"
+
+msgid "-s <scriptin>\tRead Normal mode commands from file <scriptin>"
+msgstr "-s <innskript>\tLes normalmodus-kommandoer fra filen <innskript>"
+
+msgid "-w <scriptout>\tAppend all typed commands to file <scriptout>"
+msgstr "-w <utskript>\tLegg alle skrevne kommandoer til filen <utskript>"
+
+msgid "-W <scriptout>\tWrite all typed commands to file <scriptout>"
+msgstr "-W <utskript>\tSkriv alle skrevne kommandoer til filen <utskript>"
+
+msgid "-x\t\t\tEdit encrypted files"
+msgstr "-x\t\t\tRediger krypterte filer"
+
+msgid "-display <display>\tConnect vim to this particular X-server"
+msgstr "-display <display>\tKoble vim til denne spesielle X-tjeneren"
+
+msgid "-X\t\t\tDo not connect to X server"
+msgstr "-X\t\t\tUnngå oppkobling til X-tjener"
+
+msgid "--remote <files>\tEdit <files> in a Vim server if possible"
+msgstr "--remote <filer>\tRediger <filer> på en Vim-tjener hvis mulig"
+
+msgid "--remote-silent <files> Same, don't complain if there is no server"
+msgstr "--remote-silent <filer> Samme, ikke klag hvis tjeneren mangler"
+
+msgid ""
+"--remote-wait <files> As --remote but wait for files to have been edited"
+msgstr ""
+"--remote-wait <filer> Som --remote men vent på filer som blir redigert"
+
+msgid ""
+"--remote-wait-silent <files> Same, don't complain if there is no server"
+msgstr "--remote-wait-silent <files> Samme, ikke klag hvis tjeneren mangler"
+
+#, fuzzy
+#~ msgid "--remote-tab <files> As --remote but open tab page for each file"
+#~ msgstr ""
+#~ "--remote-wait <filer> Som --remote men vent på filer som blir redigert"
+
+msgid "--remote-send <keys>\tSend <keys> to a Vim server and exit"
+msgstr "--remote-send <nøkler>\tSend <nøkler> til en Vim-tjener og avslutt"
+
+msgid "--remote-expr <expr>\tEvaluate <expr> in a Vim server and print result"
+msgstr ""
+"--remote-expr <uttrykk>\tEvaluer <uttrykk> på en Vim-tjener og skriv "
+"resultatet"
+
+msgid "--serverlist\t\tList available Vim server names and exit"
+msgstr "--serverlist\t\tList navn på tilgjengelige Vim-tjenere og avslutt"
+
+msgid "--servername <name>\tSend to/become the Vim server <name>"
+msgstr "--servername <navn>\tSend til/bli Vim-tjeneren <navn>"
+
+msgid "-i <viminfo>\t\tUse <viminfo> instead of .viminfo"
+msgstr "-i <viminfo>\t\tBruk <viminfo> istedenfor .viminfo"
+
+msgid "-h or --help\tPrint Help (this message) and exit"
+msgstr "-h eller --help\tSkriv hjelpen (denne teksten) og avslutt"
+
+msgid "--version\t\tPrint version information and exit"
+msgstr "--version\t\tSkriv versjonsinformasjon og avslutt"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Motif version):\n"
+msgstr ""
+"\n"
+"Parametere gjenkjent av gvim (Motif-versjon):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (neXtaw version):\n"
+msgstr ""
+"\n"
+"Parametere gjenkjent av gvim (neXtaw-versjon):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Athena version):\n"
+msgstr ""
+"\n"
+"Parametere gjenkjent av gvim (Athena-versjon):\n"
+
+msgid "-display <display>\tRun vim on <display>"
+msgstr "-display <display>\tKjør vim på <display>"
+
+msgid "-iconic\t\tStart vim iconified"
+msgstr "-iconic\t\tStart vim som ikon"
+
+msgid "-name <name>\t\tUse resource as if vim was <name>"
+msgstr "-name <navn>\t\tBruk ressurs som om Vim var <navn>"
+
+msgid "\t\t\t (Unimplemented)\n"
+msgstr "\t\t\t (Ikke implementert)\n"
+
+msgid "-background <color>\tUse <color> for the background (also: -bg)"
+msgstr "-background <farge>\tBruk <farge> på bakgrunnen (også: -bg)"
+
+msgid "-foreground <color>\tUse <color> for normal text (also: -fg)"
+msgstr "-foreground <farge>\tBruk <farge> på normal tekst (også: -fg)"
+
+msgid "-font <font>\t\tUse <font> for normal text (also: -fn)"
+msgstr "-font <skrifttype>\t\tBruk <skrifttype> på normal tekst (også: -fn)"
+
+msgid "-boldfont <font>\tUse <font> for bold text"
+msgstr "-boldfont <skrifttype>\tBruk <skrifttype> på fet skrift"
+
+msgid "-italicfont <font>\tUse <font> for italic text"
+msgstr "-italicfont <skrifttype>\tBruk <skrifttype> på skrå tekst"
+
+msgid "-geometry <geom>\tUse <geom> for initial geometry (also: -geom)"
+msgstr ""
+"-geometry <geom>\tBruk <geom> for innledende vindusplassering (også: -geom)"
+
+msgid "-borderwidth <width>\tUse a border width of <width> (also: -bw)"
+msgstr ""
+"-borderwidth <bredde>\tBruk en rammebredde tilsvarende <bredde> (også: -bw)"
+
+msgid "-scrollbarwidth <width> Use a scrollbar width of <width> (also: -sw)"
+msgstr ""
+"-scrollbarwidth <bredde> Bruk en rullefeltbredde tilsvarende <bredde> "
+"(også: -sw)"
+
+msgid "-menuheight <height>\tUse a menu bar height of <height> (also: -mh)"
+msgstr ""
+"-menuheight <høyde>\tBruk en menyblokkhøyde tilsvarende <høyde> (også: -mh)"
+
+msgid "-reverse\t\tUse reverse video (also: -rv)"
+msgstr "-reverse\t\tBruk invers video (også: -rv)"
+
+msgid "+reverse\t\tDon't use reverse video (also: +rv)"
+msgstr "+reverse\t\tIkke bruk invers video (også: +rv)"
+
+msgid "-xrm <resource>\tSet the specified resource"
+msgstr "-xrm <ressurs>\tSett den spesifiserte ressursen"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (RISC OS version):\n"
+msgstr ""
+"\n"
+"Parametere gjenkjent av gvim (RISC OS-versjon):\n"
+
+msgid "--columns <number>\tInitial width of window in columns"
+msgstr "--columns <antall>\tInnledende bredde på vindu i kolonner"
+
+msgid "--rows <number>\tInitial height of window in rows"
+msgstr "--rows <antall>\tInnledende høyde på vindu i rader"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (GTK+ version):\n"
+msgstr ""
+"\n"
+"Parametere gjenkjent av gvim (GTK+-versjon):\n"
+
+msgid "-display <display>\tRun vim on <display> (also: --display)"
+msgstr "-display <display>\tKjør vim på <display> (også: --display)"
+
+msgid "--role <role>\tSet a unique role to identify the main window"
+msgstr "--role <role>\tSett en unik \"role\" for å identifisere hovedvinduet"
+
+msgid "--socketid <xid>\tOpen Vim inside another GTK widget"
+msgstr "--socketid <xid>\tÅpne Vim innenfor et annet GTK-skjermelement"
+
+msgid "-P <parent title>\tOpen Vim inside parent application"
+msgstr "-P <foreldretittel>\tStart Vim innenfor et foreldreprogram"
+
+msgid "No display"
+msgstr "Ingen display"
+
+#. Failed to send, abort.
+msgid ": Send failed.\n"
+msgstr ": Send feilet.\n"
+
+#. Let vim start normally.
+msgid ": Send failed. Trying to execute locally\n"
+msgstr ": Send feilet. Prøver å utføre lokalt\n"
+
+#, c-format
+msgid "%d of %d edited"
+msgstr "%d av %d redigert"
+
+msgid "No display: Send expression failed.\n"
+msgstr "Ingen display: Sending av uttrykk feilet.\n"
+
+msgid ": Send expression failed.\n"
+msgstr ": Sending av uttrykk feilet.\n"
+
+msgid "No marks set"
+msgstr "Ingen merker satt"
+
+#, c-format
+msgid "E283: No marks matching \"%s\""
+msgstr "E283: Ingen merker samsvarer med \"%s\""
+
+#. Highlight title
+msgid ""
+"\n"
+"mark line col file/text"
+msgstr ""
+"\n"
+"merk linje kol fil/tekst"
+
+#. Highlight title
+msgid ""
+"\n"
+" jump line col file/text"
+msgstr ""
+"\n"
+" hopp linje kol fil/tekst"
+
+#. Highlight title
+msgid ""
+"\n"
+"change line col text"
+msgstr ""
+"\n"
+"forand linje kol tekst"
+
+#, c-format
+msgid ""
+"\n"
+"# File marks:\n"
+msgstr ""
+"\n"
+"# Filmerker:\n"
+
+#. Write the jumplist with -'
+#, c-format
+msgid ""
+"\n"
+"# Jumplist (newest first):\n"
+msgstr ""
+"\n"
+"# Hoppliste (nyeste først):\n"
+
+#, c-format
+msgid ""
+"\n"
+"# History of marks within files (newest to oldest):\n"
+msgstr ""
+"\n"
+"# Historie for merker inne i filer (yngst til eldst):\n"
+
+msgid "Missing '>'"
+msgstr "Mangler '>'"
+
+msgid "E543: Not a valid codepage"
+msgstr "E543: Er ikke en gyldig codepage"
+
+msgid "E284: Cannot set IC values"
+msgstr "E284: Kan ikke sette IC-verdier (\"Input Context\")"
+
+msgid "E285: Failed to create input context"
+msgstr "E285: Klarte ikke opprette inndatakontekst"
+
+msgid "E286: Failed to open input method"
+msgstr "E286: Klarte ikke åpne inndatametode"
+
+msgid "E287: Warning: Could not set destroy callback to IM"
+msgstr ""
+"E287: Advarsel: Klarte ikke sette \"destroy callback\" til inndatametode"
+
+msgid "E288: input method doesn't support any style"
+msgstr "E288: Inndatametode støtter ikke enhver stil"
+
+msgid "E289: input method doesn't support my preedit type"
+msgstr "E289: Inndatametode støtter ikke min \"preedit\" type"
+
+msgid "E290: over-the-spot style requires fontset"
+msgstr "E290: \"over-the-spot\"-stil trenger et skrifttypesett"
+
+msgid "E291: Your GTK+ is older than 1.2.3. Status area disabled"
+msgstr "E291: Din GTK+ er eldre enn 1.2.3. Statusområde deaktivert"
+
+msgid "E292: Input Method Server is not running"
+msgstr "E292: Inndatametodetjener kjører ikke"
+
+msgid "E293: block was not locked"
+msgstr "E293: Blokken var ikke låst"
+
+msgid "E294: Seek error in swap file read"
+msgstr "E294: Søkefeil i lesing av swapfil"
+
+msgid "E295: Read error in swap file"
+msgstr "E295: Lesefeil i swapfil"
+
+msgid "E296: Seek error in swap file write"
+msgstr "E296: Søkefeil i skriving til swapfil"
+
+msgid "E297: Write error in swap file"
+msgstr "E297: Skrivefeil i swapfil"
+
+msgid "E300: Swap file already exists (symlink attack?)"
+msgstr "E300: Swapfilen finnes allerede (symlenke-angrep?)"
+
+msgid "E298: Didn't get block nr 0?"
+msgstr "E298: Hentet ikke blokk nummer 0?"
+
+msgid "E298: Didn't get block nr 1?"
+msgstr "E298: Hentet ikke blokk nummer 1?"
+
+msgid "E298: Didn't get block nr 2?"
+msgstr "E298: Hentet ikke blokk nummer 2?"
+
+#. could not (re)open the swap file, what can we do????
+msgid "E301: Oops, lost the swap file!!!"
+msgstr "E301: Opps, mistet swapfilen!!!"
+
+msgid "E302: Could not rename swap file"
+msgstr "E302: Klarte ikke skifte navn på swapfil"
+
+#, c-format
+msgid "E303: Unable to open swap file for \"%s\", recovery impossible"
+msgstr "E303: Klarte ikke åpne swapfil for \"%s\", gjenoppretting umulig"
+
+msgid "E304: ml_upd_block0(): Didn't get block 0??"
+msgstr "E304: ml_upd_block0(): Hentet ikke blokk 0??"
+
+#, c-format
+msgid "E305: No swap file found for %s"
+msgstr "E305: Ingen swapfil funnet for %s"
+
+msgid "Enter number of swap file to use (0 to quit): "
+msgstr "Skriv nummeret på swapfil som skal brukes (0 for å avslutte): "
+
+#, c-format
+msgid "E306: Cannot open %s"
+msgstr "E306: Kan ikke åpne %s"
+
+msgid "Unable to read block 0 from "
+msgstr "Klarte ikke lese blokk 0 fra "
+
+msgid ""
+"\n"
+"Maybe no changes were made or Vim did not update the swap file."
+msgstr ""
+"\n"
+"Det er mulig ingen forandringer ble gjort, eller Vim oppdaterte ikke "
+"swapfilen."
+
+msgid " cannot be used with this version of Vim.\n"
+msgstr " kan ikke brukes med denne Vim-versjonen.\n"
+
+msgid "Use Vim version 3.0.\n"
+msgstr "Bruk Vim versjon 3.0.\n"
+
+#, c-format
+msgid "E307: %s does not look like a Vim swap file"
+msgstr "E307: %s ser ikke ut som en Vim-swapfil"
+
+msgid " cannot be used on this computer.\n"
+msgstr " kan ikke brukes på denne maskinen.\n"
+
+msgid "The file was created on "
+msgstr "Filen ble laget på "
+
+msgid ""
+",\n"
+"or the file has been damaged."
+msgstr ""
+",\n"
+"eller filen er blitt ødelagt."
+
+#, c-format
+msgid "Using swap file \"%s\""
+msgstr "Bruker swapfilen \"%s\""
+
+#, c-format
+msgid "Original file \"%s\""
+msgstr "Originalfil \"%s\""
+
+msgid "E308: Warning: Original file may have been changed"
+msgstr "E308: Advarsel: Originalfilen kan ha blitt forandret"
+
+#, c-format
+msgid "E309: Unable to read block 1 from %s"
+msgstr "E309: Klarte ikke lese blokk 1 fra %s"
+
+msgid "???MANY LINES MISSING"
+msgstr "???MANGE LINJER MANGLER"
+
+msgid "???LINE COUNT WRONG"
+msgstr "???FEIL LINJEANTALL"
+
+msgid "???EMPTY BLOCK"
+msgstr "???TOM BLOKK"
+
+msgid "???LINES MISSING"
+msgstr "???LINJER MANGLER"
+
+#, c-format
+msgid "E310: Block 1 ID wrong (%s not a .swp file?)"
+msgstr "E310: ID til blokk 1 er feil (%s ikke en \".swp\"-fil?)"
+
+msgid "???BLOCK MISSING"
+msgstr "???BLOKK MANGLER"
+
+msgid "??? from here until ???END lines may be messed up"
+msgstr "??? Herfra til ???SLUTT kan linjer være rotet til"
+
+msgid "??? from here until ???END lines may have been inserted/deleted"
+msgstr "??? Herfra til ???SLUTT kan linjer ha blitt lagt til eller slettet"
+
+msgid "???END"
+msgstr "???SLUTT"
+
+msgid "E311: Recovery Interrupted"
+msgstr "E311: Gjenoppretting avbrutt"
+
+msgid ""
+"E312: Errors detected while recovering; look for lines starting with ???"
+msgstr ""
+"E312: Feil oppdaget under gjenoppretting; se etter linjer som starter med ???"
+
+msgid "See \":help E312\" for more information."
+msgstr "Se \":help E312\" for mer informasjon."
+
+msgid "Recovery completed. You should check if everything is OK."
+msgstr "Gjenoppretting komplett. Du bør sjekke at alt er i orden."
+
+msgid ""
+"\n"
+"(You might want to write out this file under another name\n"
+msgstr ""
+"\n"
+"(Du vil kanskje lagre denne filen under et annet navn\n"
+
+msgid "and run diff with the original file to check for changes)\n"
+msgstr "og sammenligne den mot den originale filen for å finne forandringer)\n"
+
+msgid ""
+"Delete the .swp file afterwards.\n"
+"\n"
+msgstr ""
+"Slett \".swp\"-filen etterpå.\n"
+"\n"
+
+#. use msg() to start the scrolling properly
+msgid "Swap files found:"
+msgstr "Swapfiler funnet:"
+
+msgid " In current directory:\n"
+msgstr " I nåværende katalog:\n"
+
+msgid " Using specified name:\n"
+msgstr " Bruker spesifisert navn:\n"
+
+msgid " In directory "
+msgstr " I katalog "
+
+msgid " -- none --\n"
+msgstr " -- ingen --\n"
+
+msgid " owned by: "
+msgstr " eies av: "
+
+msgid " dated: "
+msgstr " datert: "
+
+msgid " dated: "
+msgstr " datert: "
+
+msgid " [from Vim version 3.0]"
+msgstr " [fra Vim versjon 3.0]"
+
+msgid " [does not look like a Vim swap file]"
+msgstr " [ser ikke ut som en Vim-swapfil]"
+
+msgid " file name: "
+msgstr " filnavn: "
+
+msgid ""
+"\n"
+" modified: "
+msgstr ""
+"\n"
+" modifisert: "
+
+msgid "YES"
+msgstr "JA"
+
+msgid "no"
+msgstr "nei"
+
+msgid ""
+"\n"
+" user name: "
+msgstr ""
+"\n"
+" brukernavn: "
+
+msgid " host name: "
+msgstr " vertsnavn: "
+
+msgid ""
+"\n"
+" host name: "
+msgstr ""
+"\n"
+" vertsnavn: "
+
+msgid ""
+"\n"
+" process ID: "
+msgstr ""
+"\n"
+" prosess-ID: "
+
+msgid " (still running)"
+msgstr " (kjører fortsatt)"
+
+msgid ""
+"\n"
+" [not usable with this version of Vim]"
+msgstr ""
+"\n"
+" [ikke brukbar med denne Vim-versjonen]"
+
+msgid ""
+"\n"
+" [not usable on this computer]"
+msgstr ""
+"\n"
+" [ikke brukbar på denne maskinen]"
+
+msgid " [cannot be read]"
+msgstr " [kan ikke leses]"
+
+msgid " [cannot be opened]"
+msgstr " [kan ikke åpnes]"
+
+msgid "E313: Cannot preserve, there is no swap file"
+msgstr "E313: Kan ikke bevare, swapfil mangler"
+
+msgid "File preserved"
+msgstr "Fil bevart"
+
+msgid "E314: Preserve failed"
+msgstr "E314: Bevaring feilet"
+
+#, c-format
+msgid "E315: ml_get: invalid lnum: %ld"
+msgstr "E315: ml_get: Ugyldig lnum: %ld"
+
+#, c-format
+msgid "E316: ml_get: cannot find line %ld"
+msgstr "E316: ml_get: Kan ikke finne linje %ld"
+
+msgid "E317: pointer block id wrong 3"
+msgstr "E317: Pekerblokk-id feil 3"
+
+msgid "stack_idx should be 0"
+msgstr "stack_idx skulle være 0"
+
+msgid "E318: Updated too many blocks?"
+msgstr "E318: Oppdaterte for mange blokker?"
+
+msgid "E317: pointer block id wrong 4"
+msgstr "E317: Pekerblokk-id feil 4"
+
+msgid "deleted block 1?"
+msgstr "slettet blokk 1?"
+
+#, c-format
+msgid "E320: Cannot find line %ld"
+msgstr "E320: Kan ikke finne linje %ld"
+
+msgid "E317: pointer block id wrong"
+msgstr "E317: Pekerblokk-id feil"
+
+msgid "pe_line_count is zero"
+msgstr "pe_line_count er null"
+
+#, c-format
+msgid "E322: line number out of range: %ld past the end"
+msgstr "E322: Linjenummer utenfor område: %ld forbi slutten"
+
+#, c-format
+msgid "E323: line count wrong in block %ld"
+msgstr "E323: Linjeantall feil i blokk %ld"
+
+msgid "Stack size increases"
+msgstr "Stackstørrelse øker"
+
+msgid "E317: pointer block id wrong 2"
+msgstr "E317: Pekerblokk-id feil 2"
+
+#, c-format
+msgid "E773: Symlink loop for \"%s\""
+msgstr "E773: Symlenkesløyfe for \"%s\""
+
+msgid "E325: ATTENTION"
+msgstr "E325: VIKTIG"
+
+msgid ""
+"\n"
+"Found a swap file by the name \""
+msgstr ""
+"\n"
+"Fant en swapfil ved navn \""
+
+msgid "While opening file \""
+msgstr "Under åpning av filen \""
+
+msgid " NEWER than swap file!\n"
+msgstr " NYERE enn swapfil!\n"
+
+#. Some of these messages are long to allow translation to
+#. * other languages.
+msgid ""
+"\n"
+"(1) Another program may be editing the same file.\n"
+" If this is the case, be careful not to end up with two\n"
+" different instances of the same file when making changes.\n"
+msgstr ""
+"\n"
+"(1) Det er mulig et annet program redigerer den samme filen.\n"
+" Hvis det er tilfelle, vær forsiktig så du ikke ender opp med to\n"
+" forskjellige utgaver av den samme filen når du gjør forandringer.\n"
+
+msgid " Quit, or continue with caution.\n"
+msgstr " Avslutt, eller fortsett med varsomhet.\n"
+
+msgid ""
+"\n"
+"(2) An edit session for this file crashed.\n"
+msgstr ""
+"\n"
+"(2) En økt for denne filen kræsjet.\n"
+
+msgid " If this is the case, use \":recover\" or \"vim -r "
+msgstr " Hvis det er tilfelle, bruk \":recover\" eller \"vim -r "
+
+msgid ""
+"\"\n"
+" to recover the changes (see \":help recovery\").\n"
+msgstr ""
+"\"\n"
+" for å gjenopprette forandringene (se \":help recovery\").\n"
+
+msgid " If you did this already, delete the swap file \""
+msgstr " Hvis du har gjort dette allerede, slett swapfilen \""
+
+msgid ""
+"\"\n"
+" to avoid this message.\n"
+msgstr ""
+"\"\n"
+" for å unngå denne meldingen.\n"
+
+msgid "Swap file \""
+msgstr "Swapfilen \""
+
+msgid "\" already exists!"
+msgstr "\" finnes allerede!"
+
+msgid "VIM - ATTENTION"
+msgstr "VIM - VIKTIG"
+
+msgid "Swap file already exists!"
+msgstr "Swapfilen eksisterer allerede!"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"&Åpne skrivebeskyttet\n"
+"&Rediger likevel\n"
+"&Gjenopprett\n"
+"&Avslutt\n"
+"Av&bryt"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Delete it\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"&Åpne skrivebeskyttet\n"
+"&Rediger likevel\n"
+"&Gjenopprett\n"
+"&Slett den\n"
+"&Avslutt\n"
+"Av&bryt"
+
+msgid "E326: Too many swap files found"
+msgstr "E326: For mange swapfiler funnet"
+
+msgid "E327: Part of menu-item path is not sub-menu"
+msgstr "E327: Del av menyelement er ikke undermeny"
+
+msgid "E328: Menu only exists in another mode"
+msgstr "E328: Menyen eksisterer bare i en annen modus"
+
+#, c-format
+msgid "E329: No menu \"%s\""
+msgstr "E329: Ingen \"%s\"-meny"
+
+#. Only a mnemonic or accelerator is not valid.
+msgid "E792: Empty menu name"
+msgstr "E792: Tomt menynavn"
+
+msgid "E330: Menu path must not lead to a sub-menu"
+msgstr "E330: Menysti kan ikke lede til en undermeny"
+
+msgid "E331: Must not add menu items directly to menu bar"
+msgstr "E331: Kan ikke legge til menyelementer direkte på menylinjen"
+
+msgid "E332: Separator cannot be part of a menu path"
+msgstr "E332: Skilletegn kan ikke være del av en menysti"
+
+#. Now we have found the matching menu, and we list the mappings
+#. Highlight title
+msgid ""
+"\n"
+"--- Menus ---"
+msgstr ""
+"\n"
+"--- Menyer ---"
+
+msgid "Tear off this menu"
+msgstr "Riv av denne menyen"
+
+msgid "E333: Menu path must lead to a menu item"
+msgstr "E333: Menystien må lede til et menyvalg"
+
+#, c-format
+msgid "E334: Menu not found: %s"
+msgstr "E334: Fant ikke menyen: %s"
+
+#, c-format
+msgid "E335: Menu not defined for %s mode"
+msgstr "E335: Menyen er ikke definert for %s-modus"
+
+msgid "E336: Menu path must lead to a sub-menu"
+msgstr "E336: Menystien må lede til en undermeny"
+
+msgid "E337: Menu not found - check menu names"
+msgstr "E337: Fant ikke menyen - sjekk menynavnet"
+
+#, c-format
+msgid "Error detected while processing %s:"
+msgstr "Feil oppdaget under prosessering av %s:"
+
+#, c-format
+msgid "line %4ld:"
+msgstr "linje %4ld:"
+
+#, c-format
+msgid "E354: Invalid register name: '%s'"
+msgstr "E354: Ugyldig registernavn: '%s'"
+
+msgid "Messages maintainer: Bram Moolenaar <Bram@vim.org>"
+msgstr ""
+"Vedlikeholder for norsk oversettelse: Øyvind A. Holm <sunny@sunbase.org>"
+
+msgid "Interrupt: "
+msgstr "Avbryt: "
+
+msgid "Press ENTER or type command to continue"
+msgstr "Trykk ENTER eller skriv kommando for å fortsette"
+
+#, c-format
+msgid "%s line %ld"
+msgstr "%s linje %ld"
+
+msgid "-- More --"
+msgstr "-- Mer --"
+
+msgid " SPACE/d/j: screen/page/line down, b/u/k: up, q: quit "
+msgstr " MELLOMROM/d/j: Skjerm/side/linje ned, b/u/k: Opp, q: Avslutt "
+
+msgid "Question"
+msgstr "Spørsmål"
+
+msgid ""
+"&Yes\n"
+"&No"
+msgstr ""
+"&Ja\n"
+"&Nei"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"Save &All\n"
+"&Discard All\n"
+"&Cancel"
+msgstr ""
+"&Ja\n"
+"&Nei\n"
+"&Lagre alle\n"
+"&Forkast alle\n"
+"&Avbryt"
+
+msgid "Select Directory dialog"
+msgstr "\"Velge katalog\"-dialogvindu"
+
+msgid "Save File dialog"
+msgstr "\"Lagre fil\"-dialogvindu"
+
+msgid "Open File dialog"
+msgstr "\"Åpne fil\"-dialogvindu"
+
+#. TODO: non-GUI file selector here
+msgid "E338: Sorry, no file browser in console mode"
+msgstr "E338: Dessverre ingen filbehandler i konsollmodus"
+
+msgid "E766: Insufficient arguments for printf()"
+msgstr "E766: Ikke nok parametre for printf()"
+
+msgid "E767: Too many arguments to printf()"
+msgstr "E767: For mange parametere for printf()"
+
+msgid "W10: Warning: Changing a readonly file"
+msgstr "W10: Advarsel: Forandrer en skrivebeskyttet fil"
+
+msgid "Type number or click with mouse (<Enter> cancels): "
+msgstr "Skriv nummer eller velg med musen (<Enter> avbryter)"
+
+msgid "Choice number (<Enter> cancels): "
+msgstr "Valgnummer (<Enter> avbryter)"
+
+msgid "1 more line"
+msgstr "1 linje lagt til"
+
+msgid "1 line less"
+msgstr "1 linje fjernet"
+
+#, c-format
+msgid "%ld more lines"
+msgstr "%ld linjer lagt til"
+
+#, c-format
+msgid "%ld fewer lines"
+msgstr "%ld linjer fjernet"
+
+msgid " (Interrupted)"
+msgstr " (Avbrutt)"
+
+msgid "Beep!"
+msgstr "Pip!"
+
+msgid "Vim: preserving files...\n"
+msgstr "Vim: Bevarer filer ...\n"
+
+#. close all memfiles, without deleting
+msgid "Vim: Finished.\n"
+msgstr "Vim: Ferdig.\n"
+
+#, c-format
+msgid "ERROR: "
+msgstr "FEIL: "
+
+#, c-format
+msgid ""
+"\n"
+"[bytes] total alloc-freed %lu-%lu, in use %lu, peak use %lu\n"
+msgstr ""
+"\n"
+"[bytes] totalt alloc-frigjort %lu-%lu, i bruk %lu, topp-bruk %lu\n"
+
+#, c-format
+msgid ""
+"[calls] total re/malloc()'s %lu, total free()'s %lu\n"
+"\n"
+msgstr ""
+"[kall] totale \"re/malloc()\"-er %lu, totale \"free()\"-er %lu\n"
+"\n"
+
+msgid "E340: Line is becoming too long"
+msgstr "E340: Linjen blir for lang"
+
+#, c-format
+msgid "E341: Internal error: lalloc(%ld, )"
+msgstr "E341: Intern feil: lalloc(%ld, )"
+
+#, c-format
+msgid "E342: Out of memory! (allocating %lu bytes)"
+msgstr "E342: Ikke mer ledig hukommelse! (Reserverer %lu bytes)"
+
+#, c-format
+msgid "Calling shell to execute: \"%s\""
+msgstr "Kaller skall for å utføre \"%s\""
+
+msgid "E545: Missing colon"
+msgstr "E545: Mangler kolon"
+
+msgid "E546: Illegal mode"
+msgstr "E546: Ulovlig modus"
+
+msgid "E547: Illegal mouseshape"
+msgstr "E547: Ulovlig utseende på musepekeren"
+
+msgid "E548: digit expected"
+msgstr "E548: Siffer forventet"
+
+msgid "E549: Illegal percentage"
+msgstr "E549: Ulovlig prosent"
+
+msgid "Enter encryption key: "
+msgstr "Skriv krypteringsnøkkel: "
+
+msgid "Enter same key again: "
+msgstr "Gjenta krypteringsnøkkelen: "
+
+msgid "Keys don't match!"
+msgstr "Krypteringsnøklene stemmer ikke overens!"
+
+#, c-format
+msgid ""
+"E343: Invalid path: '**[number]' must be at the end of the path or be "
+"followed by '%s'."
+msgstr ""
+"E343: Ugyldig sti: '**[nummer]' må være på slutten av stien eller bli "
+"etterfulgt av '%s'."
+
+#, c-format
+msgid "E344: Can't find directory \"%s\" in cdpath"
+msgstr "E344: Kan ikke finne katalogen \"%s\" i \"cdpath\""
+
+#, c-format
+msgid "E345: Can't find file \"%s\" in path"
+msgstr "E345: Kan ikke finne filen \"%s\" i stien"
+
+#, c-format
+msgid "E346: No more directory \"%s\" found in cdpath"
+msgstr "E346: Ingen flere katalog-\"%s\" funnet i \"cdpath\""
+
+#, c-format
+msgid "E347: No more file \"%s\" found in path"
+msgstr "E347: Ingen flere fil-\"%s\" funnet i stien"
+
+#. Get here when the server can't be found.
+msgid "Cannot connect to Netbeans #2"
+msgstr "Kan ikke koble til Netbeans #2"
+
+msgid "Cannot connect to Netbeans"
+msgstr "Kan ikke koble til Netbeans"
+
+#, c-format
+msgid "E668: Wrong access mode for NetBeans connection info file: \"%s\""
+msgstr ""
+"E668: Feil tilgangsmodus for infofilen til NetBeans-forbindelse: \"%s\""
+
+msgid "read from Netbeans socket"
+msgstr "les fra Netbeans-socket"
+
+#, c-format
+msgid "E658: NetBeans connection lost for buffer %ld"
+msgstr "E658: Mistet NetBeans-forbindelse for buffer %ld"
+
+msgid "E505: "
+msgstr "E505: "
+
+msgid "E774: 'operatorfunc' is empty"
+msgstr "E774: 'operatorfunc' er tomt"
+
+msgid "E775: Eval feature not available"
+msgstr "E775: Eval-funksjonaliteten er ikke tilgjengelig"
+
+msgid "Warning: terminal cannot highlight"
+msgstr "Advarsel: Terminalen kan ikke utheve"
+
+msgid "E348: No string under cursor"
+msgstr "E348: Ingen streng under markør"
+
+msgid "E349: No identifier under cursor"
+msgstr "E349: Ingen identifikator under markør"
+
+msgid "E352: Cannot erase folds with current 'foldmethod'"
+msgstr "E352: Kan ikke slette folder med nåværende 'foldmethod'"
+
+msgid "E664: changelist is empty"
+msgstr "E664: Forandringslisten er tom"
+
+msgid "E662: At start of changelist"
+msgstr "E662: Ved starten av forandringsliste"
+
+msgid "E663: At end of changelist"
+msgstr "E663: Ved slutten av forandringsliste"
+
+msgid "Type :quit<Enter> to exit Vim"
+msgstr "Skriv :quit<Enter> for å avslutte Vim"
+
+#, c-format
+msgid "1 line %sed 1 time"
+msgstr "1 linje \"%s\"-et 1 gang"
+
+#, c-format
+msgid "1 line %sed %d times"
+msgstr "1 linje \"%s\"-et %d ganger"
+
+#, c-format
+msgid "%ld lines %sed 1 time"
+msgstr "%ld linjer \"%s\"-et 1 gang"
+
+#, c-format
+msgid "%ld lines %sed %d times"
+msgstr "%ld linjer \"%s\"-et %d ganger"
+
+#, c-format
+msgid "%ld lines to indent... "
+msgstr "%ld linjer å rykke inn ... "
+
+msgid "1 line indented "
+msgstr "1 linje rykket inn "
+
+#, c-format
+msgid "%ld lines indented "
+msgstr "%ld linjer rykket inn "
+
+msgid "E748: No previously used register"
+msgstr "E748: Register ikke tidligere brukt"
+
+#. must display the prompt
+msgid "cannot yank; delete anyway"
+msgstr "kan ikke kopiere til utklippstavle; slett likevel"
+
+msgid "1 line changed"
+msgstr "1 linje forandret"
+
+#, c-format
+msgid "%ld lines changed"
+msgstr "%ld linjer forandret"
+
+#, c-format
+msgid "freeing %ld lines"
+msgstr "frigjør %ld linjer"
+
+msgid "block of 1 line yanked"
+msgstr "blokk med 1 linje kopiert til utklippstavlen"
+
+msgid "1 line yanked"
+msgstr "1 linje kopiert til utklippstavlen"
+
+#, c-format
+msgid "block of %ld lines yanked"
+msgstr "blokk med %ld linjer kopiert til utklippstavlen"
+
+#, c-format
+msgid "%ld lines yanked"
+msgstr "%ld linjer kopiert til utklippstavlen"
+
+#, c-format
+msgid "E353: Nothing in register %s"
+msgstr "E353: Ingenting i register %s"
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Registers ---"
+msgstr ""
+"\n"
+"--- Registere ---"
+
+msgid "Illegal register name"
+msgstr "Ulovlig registernavn"
+
+#, c-format
+msgid ""
+"\n"
+"# Registers:\n"
+msgstr ""
+"\n"
+"# Registere:\n"
+
+#, c-format
+msgid "E574: Unknown register type %d"
+msgstr "E574: Ukjent registertype %d"
+
+#, c-format
+msgid "%ld Cols; "
+msgstr "%ld Kol; "
+
+#, c-format
+msgid "Selected %s%ld of %ld Lines; %ld of %ld Words; %ld of %ld Bytes"
+msgstr "Valgte %s%ld av %ld linjer; %ld av %ld ord; %ld av %ld bytes"
+
+#, c-format
+msgid ""
+"Selected %s%ld of %ld Lines; %ld of %ld Words; %ld of %ld Chars; %ld of %ld "
+"Bytes"
+msgstr ""
+"Valgte %s%ld av %ld linjer; %ld av %ld ord; %ld av %ld tegn; %ld av %ld bytes"
+
+#, c-format
+msgid "Col %s of %s; Line %ld of %ld; Word %ld of %ld; Byte %ld of %ld"
+msgstr "Kol %s av %s; Linje %ld av %ld; Ord %ld av %ld; Byte %ld av %ld"
+
+#, c-format
+msgid ""
+"Col %s of %s; Line %ld of %ld; Word %ld of %ld; Char %ld of %ld; Byte %ld of "
+"%ld"
+msgstr ""
+"Kol %s av %s; linje %ld av %ld; ord %ld av %ld; tegn %ld av %ld; byte %ld av "
+"%ld"
+
+#, c-format
+msgid "(+%ld for BOM)"
+msgstr "(+%ld for BOM)"
+
+msgid "%<%f%h%m%=Page %N"
+msgstr "%<%f%h%m%=Side %N"
+
+msgid "Thanks for flying Vim"
+msgstr "Takk for at du fløy Vim"
+
+msgid "E518: Unknown option"
+msgstr "E518: Ukjent valg"
+
+msgid "E519: Option not supported"
+msgstr "E519: Valget er ikke støttet"
+
+msgid "E520: Not allowed in a modeline"
+msgstr "E520: Ikke tillatt i moduslinje"
+
+msgid "E521: Number required after ="
+msgstr "E521: Nummer nødvendig etter ="
+
+msgid "E522: Not found in termcap"
+msgstr "E522: Ikke funnet i termcap"
+
+#, c-format
+msgid "E539: Illegal character <%s>"
+msgstr "E539: Ulovlig tegn <%s>"
+
+msgid "E529: Cannot set 'term' to empty string"
+msgstr "E529: Kan ikke sette 'term' til tom streng"
+
+msgid "E530: Cannot change term in GUI"
+msgstr "E530: Kan ikke forandre \"term\" i grafisk brukergrensesnitt"
+
+msgid "E531: Use \":gui\" to start the GUI"
+msgstr "E531: Bruk \":gui\" for å starte med grafisk brukergrensesnitt"
+
+msgid "E589: 'backupext' and 'patchmode' are equal"
+msgstr "E589: 'backupext' og 'patchmode' er like"
+
+msgid "E617: Cannot be changed in the GTK+ 2 GUI"
+msgstr "E617: Kan ikke forandres i GTK+ 2 GUI"
+
+msgid "E524: Missing colon"
+msgstr "E524: Mangler kolon"
+
+msgid "E525: Zero length string"
+msgstr "E525: Tom streng"
+
+#, c-format
+msgid "E526: Missing number after <%s>"
+msgstr "E526: Mangler nummer etter <%s>"
+
+msgid "E527: Missing comma"
+msgstr "E527: Mangler komma"
+
+msgid "E528: Must specify a ' value"
+msgstr "E528: Må spesifisere en \"'\"-verdi"
+
+msgid "E595: contains unprintable or wide character"
+msgstr "E595: Inneholder uskrivelige eller brede tegn"
+
+msgid "E596: Invalid font(s)"
+msgstr "E596: Ugyldig(e) skrifttype(r)"
+
+msgid "E597: can't select fontset"
+msgstr "E597: Kan ikke velge skrifttypesett"
+
+msgid "E598: Invalid fontset"
+msgstr "E598: Ugyldig skrifttypesett"
+
+msgid "E533: can't select wide font"
+msgstr "E533: Kan ikke velge bred skrifttype"
+
+msgid "E534: Invalid wide font"
+msgstr "E534: Ugyldig bred skrifttype"
+
+#, c-format
+msgid "E535: Illegal character after <%c>"
+msgstr "E535: Ulovlig tegn etter <%c>"
+
+msgid "E536: comma required"
+msgstr "E536: Komma nødvendig"
+
+#, c-format
+msgid "E537: 'commentstring' must be empty or contain %s"
+msgstr "E537: 'commentstring' må være tom eller inneholde %s"
+
+msgid "E538: No mouse support"
+msgstr "E538: Ingen støtte for mus"
+
+msgid "E540: Unclosed expression sequence"
+msgstr "E540: Uttrykkssekvens som ikke er lukket"
+
+msgid "E541: too many items"
+msgstr "E541: For mange elementer"
+
+msgid "E542: unbalanced groups"
+msgstr "E542: Ubalanserte grupper"
+
+msgid "E590: A preview window already exists"
+msgstr "E590: Det finnes allerede et forhåndsvisningsvindu"
+
+msgid "W17: Arabic requires UTF-8, do ':set encoding=utf-8'"
+msgstr "W17: Arabisk trenger UTF-8, utfør ':set encoding=utf-8'"
+
+#, c-format
+msgid "E593: Need at least %d lines"
+msgstr "E593: Trenger minst %d linjer"
+
+#, c-format
+msgid "E594: Need at least %d columns"
+msgstr "E594: Trenger minst %d kolonner"
+
+#, c-format
+msgid "E355: Unknown option: %s"
+msgstr "E355: Ukjent valg: %s"
+
+msgid ""
+"\n"
+"--- Terminal codes ---"
+msgstr ""
+"\n"
+"--- Terminalkoder ---"
+
+msgid ""
+"\n"
+"--- Global option values ---"
+msgstr ""
+"\n"
+"--- Globale valgverdier ---"
+
+msgid ""
+"\n"
+"--- Local option values ---"
+msgstr ""
+"\n"
+"--- Lokale valgverdier ---"
+
+msgid ""
+"\n"
+"--- Options ---"
+msgstr ""
+"\n"
+"--- Valg ---"
+
+msgid "E356: get_varp ERROR"
+msgstr "E356: \"get_varp\"-FEIL"
+
+#, c-format
+msgid "E357: 'langmap': Matching character missing for %s"
+msgstr "E357: 'langmap': Samsvarende tegn mangler for %s"
+
+#, c-format
+msgid "E358: 'langmap': Extra characters after semicolon: %s"
+msgstr "E358: 'langmap': Ekstra tegn etter semikolon: %s"
+
+msgid "cannot open "
+msgstr "kan ikke åpne "
+
+msgid "VIM: Can't open window!\n"
+msgstr "VIM: Kan ikke åpne vindu!\n"
+
+msgid "Need Amigados version 2.04 or later\n"
+msgstr "Trenger Amigados versjon 2.04 eller nyere\n"
+
+#, c-format
+msgid "Need %s version %ld\n"
+msgstr "Trenger %s versjon %ld\n"
+
+msgid "Cannot open NIL:\n"
+msgstr "Kan ikke åpne NIL:\n"
+
+msgid "Cannot create "
+msgstr "Kan ikke opprette "
+
+#, c-format
+msgid "Vim exiting with %d\n"
+msgstr "Vim avslutter med %d\n"
+
+msgid "cannot change console mode ?!\n"
+msgstr "kan ikke forandre konsollmodus ?!\n"
+
+msgid "mch_get_shellsize: not a console??\n"
+msgstr "mch_get_shellsize: Ikke et konsoll??\n"
+
+#. if Vim opened a window: Executing a shell may cause crashes
+msgid "E360: Cannot execute shell with -f option"
+msgstr "E360: Kan ikke kjøre skall med \"-f\"-valg"
+
+msgid "Cannot execute "
+msgstr "Kan ikke utføre "
+
+msgid "shell "
+msgstr "skall "
+
+msgid " returned\n"
+msgstr " returnerte\n"
+
+msgid "ANCHOR_BUF_SIZE too small."
+msgstr "ANCHOR_BUF_SIZE for liten."
+
+msgid "I/O ERROR"
+msgstr "I/U-FEIL"
+
+msgid "Message"
+msgstr "Melding"
+
+msgid "'columns' is not 80, cannot execute external commands"
+msgstr "'columns' er ikke 80, kan ikke utføre eksterne kommandoer"
+
+msgid "E237: Printer selection failed"
+msgstr "E237: Valg av skriver feilet"
+
+#, c-format
+msgid "to %s on %s"
+msgstr "til %s på %s"
+
+#, c-format
+msgid "E613: Unknown printer font: %s"
+msgstr "E613: Ukjent skrifttype for skriver: %s"
+
+#, c-format
+msgid "E238: Print error: %s"
+msgstr "E238: Feil under utskrift: %s"
+
+#, c-format
+msgid "Printing '%s'"
+msgstr "Skriver ut '%s'"
+
+#, c-format
+msgid "E244: Illegal charset name \"%s\" in font name \"%s\""
+msgstr "E244: Ulovlig navn på tegnsett \"%s\" i skrifttypenavn \"%s\""
+
+#, c-format
+msgid "E245: Illegal char '%c' in font name \"%s\""
+msgstr "E245: Ulovlig tegn '%c' i skrifttypenavn \"%s\""
+
+msgid "Vim: Double signal, exiting\n"
+msgstr "Vim: Dobbelt signal, avslutter\n"
+
+#, c-format
+msgid "Vim: Caught deadly signal %s\n"
+msgstr "Vim: Mottok dødelig signal %s\n"
+
+#, c-format
+msgid "Vim: Caught deadly signal\n"
+msgstr "Vim: Mottok dødelig signal\n"
+
+#, c-format
+msgid "Opening the X display took %ld msec"
+msgstr "Åpning av X-display tok %ld millisekunder"
+
+msgid ""
+"\n"
+"Vim: Got X error\n"
+msgstr ""
+"\n"
+"Vim: Mottok X-feil\n"
+
+msgid "Testing the X display failed"
+msgstr "Test av X-display feilet"
+
+msgid "Opening the X display timed out"
+msgstr "Tidsavbrudd for åpning av X-display"
+
+msgid ""
+"\n"
+"Cannot execute shell "
+msgstr ""
+"\n"
+"Kan ikke kjøre skall "
+
+msgid ""
+"\n"
+"Cannot execute shell sh\n"
+msgstr ""
+"\n"
+"Kan ikke kjøre skallet sh\n"
+
+msgid ""
+"\n"
+"shell returned "
+msgstr ""
+"\n"
+"skallet returnerte "
+
+msgid ""
+"\n"
+"Cannot create pipes\n"
+msgstr ""
+"\n"
+"Kan ikke opprette rør (\"pipe\")\n"
+
+msgid ""
+"\n"
+"Cannot fork\n"
+msgstr ""
+"\n"
+"Kan ikke opprette tvillingprosess (\"fork\")\n"
+
+msgid ""
+"\n"
+"Command terminated\n"
+msgstr ""
+"\n"
+"Kommando avsluttet\n"
+
+msgid "XSMP lost ICE connection"
+msgstr "XSMP mistet ICE-forbindelsen"
+
+#, c-format
+msgid "dlerror = \"%s\""
+msgstr "dlerror = \"%s\""
+
+msgid "Opening the X display failed"
+msgstr "Åpning av X-display feilet"
+
+msgid "XSMP handling save-yourself request"
+msgstr "XSMP håndterer \"redd-deg-selv\"-forespørsel"
+
+msgid "XSMP opening connection"
+msgstr "XSMP åpner forbindelse"
+
+msgid "XSMP ICE connection watch failed"
+msgstr "Overvåkning av XSMP ICE-forbindelse feilet"
+
+#, c-format
+msgid "XSMP SmcOpenConnection failed: %s"
+msgstr "XSMP SmcOpenConnection feilet: %s"
+
+msgid "At line"
+msgstr "På linje"
+
+msgid "Could not load vim32.dll!"
+msgstr "Klarte ikke laste vim32.dll!"
+
+msgid "VIM Error"
+msgstr "VIM-feil"
+
+msgid "Could not fix up function pointers to the DLL!"
+msgstr "Klarte ikke ordne opp i funksjonspekere til DLL-en!"
+
+#, c-format
+msgid "shell returned %d"
+msgstr "skallet returnerte %d"
+
+#, c-format
+msgid "Vim: Caught %s event\n"
+msgstr "Vim: Mottok \"%s\"-hendelse\n"
+
+msgid "close"
+msgstr "lukk"
+
+msgid "logoff"
+msgstr "logg av"
+
+msgid "shutdown"
+msgstr "kjør ned"
+
+msgid "E371: Command not found"
+msgstr "E371: Kommando ikke funnet"
+
+msgid ""
+"VIMRUN.EXE not found in your $PATH.\n"
+"External commands will not pause after completion.\n"
+"See :help win32-vimrun for more information."
+msgstr ""
+"VIMRUN.EXE ikke funnet i $PATH.\n"
+"Eksterne kommandoer kommer ikke til å vente etter fullføring.\n"
+"Se \":help win32-vimrun\" for mer informasjon."
+
+msgid "Vim Warning"
+msgstr "Vim-advarsel"
+
+#, c-format
+msgid "E372: Too many %%%c in format string"
+msgstr "E372: For mange %%%c i formatstreng"
+
+#, c-format
+msgid "E373: Unexpected %%%c in format string"
+msgstr "E373: Uventet %%%c i formatstreng"
+
+msgid "E374: Missing ] in format string"
+msgstr "E374: Mangler ] i formatstreng"
+
+#, c-format
+msgid "E375: Unsupported %%%c in format string"
+msgstr "E375: %%%c ikke støttet i formatstreng"
+
+#, c-format
+msgid "E376: Invalid %%%c in format string prefix"
+msgstr "E376: Ugyldig %%%c i formatstreng-prefiks"
+
+#, c-format
+msgid "E377: Invalid %%%c in format string"
+msgstr "E377: Ugyldig %%%c i formatstreng"
+
+msgid "E378: 'errorformat' contains no pattern"
+msgstr "E378: 'errorformat' inneholder ikke søkestreng"
+
+msgid "E379: Missing or empty directory name"
+msgstr "E379: Manglende eller tomt katalognavn"
+
+msgid "E553: No more items"
+msgstr "E553: Ingen flere elementer"
+
+#, c-format
+msgid "(%d of %d)%s%s: "
+msgstr "(%d av %d)%s%s: "
+
+msgid " (line deleted)"
+msgstr " (linjen slettet)"
+
+msgid "E380: At bottom of quickfix stack"
+msgstr "E380: På bunnen av quickfix-stack"
+
+msgid "E381: At top of quickfix stack"
+msgstr "E381: På toppen av quickfix-stack"
+
+#, c-format
+msgid "error list %d of %d; %d errors"
+msgstr "feilliste %d av %d; %d feil"
+
+msgid "E382: Cannot write, 'buftype' option is set"
+msgstr "E382: Kan ikke lagre, 'buftype'-valget er satt"
+
+msgid "E683: File name missing or invalid pattern"
+msgstr "E683: Filnavn mangler eller ugyldig søkestreng"
+
+#, c-format
+msgid "Cannot open file \"%s\""
+msgstr "Kan ikke åpne filen \"%s\""
+
+msgid "E681: Buffer is not loaded"
+msgstr "E681: Bufferen er ikke lastet"
+
+msgid "E777: String or List expected"
+msgstr "E777: Streng eller liste forventet"
+
+#, c-format
+msgid "E369: invalid item in %s%%[]"
+msgstr "E369: Ugyldig element i %s%%[]"
+
+msgid "E339: Pattern too long"
+msgstr "E339: Søkestrengen er for lang"
+
+msgid "E50: Too many \\z("
+msgstr "E50: For mange \\z("
+
+#, c-format
+msgid "E51: Too many %s("
+msgstr "E51: For mange %s("
+
+msgid "E52: Unmatched \\z("
+msgstr "E52: Usamsvarende \\z("
+
+#, c-format
+msgid "E53: Unmatched %s%%("
+msgstr "E53: Usamsvarende %s%%("
+
+#, c-format
+msgid "E54: Unmatched %s("
+msgstr "E54: Usamsvarende %s("
+
+#, c-format
+msgid "E55: Unmatched %s)"
+msgstr "E55: Usamsvarende %s)"
+
+#, c-format
+msgid "E59: invalid character after %s@"
+msgstr "E59: Ugyldig tegn etter %s@"
+
+#, c-format
+msgid "E60: Too many complex %s{...}s"
+msgstr "E60: For mange komplekse %s{...}s"
+
+#, c-format
+msgid "E61: Nested %s*"
+msgstr "E61: Nøstede %s*"
+
+#, c-format
+msgid "E62: Nested %s%c"
+msgstr "E62: Nøstede %s%c"
+
+msgid "E63: invalid use of \\_"
+msgstr "E63: Ugyldig bruk av \\_"
+
+#, c-format
+msgid "E64: %s%c follows nothing"
+msgstr "E64: %s%c etterfølger ingenting"
+
+msgid "E65: Illegal back reference"
+msgstr "E65: Ulovlig tilbakereferanse"
+
+msgid "E66: \\z( not allowed here"
+msgstr "E66: \\z( ikke tillatt her"
+
+msgid "E67: \\z1 - \\z9 not allowed here"
+msgstr "E67: \\z1 med venner er ikke tillatt her"
+
+msgid "E68: Invalid character after \\z"
+msgstr "E68: Ugyldig tegn etter \\z"
+
+#, c-format
+msgid "E69: Missing ] after %s%%["
+msgstr "E69: Mangler ] etter %s%%["
+
+#, c-format
+msgid "E70: Empty %s%%[]"
+msgstr "E70: Tom %s%%[]"
+
+#, c-format
+msgid "E678: Invalid character after %s%%[dxouU]"
+msgstr "E678: Ugyldig tegn etter %s%%[dxouU]"
+
+#, c-format
+msgid "E71: Invalid character after %s%%"
+msgstr "E71: Ugyldig tegn etter %s%%"
+
+#, c-format
+msgid "E769: Missing ] after %s["
+msgstr "E769: Mangler ] etter %s["
+
+#, c-format
+msgid "E554: Syntax error in %s{...}"
+msgstr "E554: Syntaksfeil i %s{...}"
+
+msgid "External submatches:\n"
+msgstr "Eksterne deltreff:\n"
+
+msgid " VREPLACE"
+msgstr " V-ERSTATT"
+
+msgid " REPLACE"
+msgstr " ERSTATT"
+
+msgid " REVERSE"
+msgstr " OMVENDT"
+
+msgid " INSERT"
+msgstr " SETT INN"
+
+msgid " (insert)"
+msgstr " (sett inn)"
+
+msgid " (replace)"
+msgstr " (erstatt)"
+
+msgid " (vreplace)"
+msgstr " (v-erstatt)"
+
+msgid " Hebrew"
+msgstr " hebraisk"
+
+msgid " Arabic"
+msgstr " arabisk"
+
+msgid " (lang)"
+msgstr " (lang)"
+
+msgid " (paste)"
+msgstr " (lim inn)"
+
+msgid " VISUAL"
+msgstr " VISUELL"
+
+msgid " VISUAL LINE"
+msgstr " VISUELL LINJE"
+
+msgid " VISUAL BLOCK"
+msgstr " VISUELL BLOKK"
+
+msgid " SELECT"
+msgstr " VELG"
+
+msgid " SELECT LINE"
+msgstr " VELG LINJE"
+
+msgid " SELECT BLOCK"
+msgstr " VELG BLOKK"
+
+msgid "recording"
+msgstr "spiller inn"
+
+#, c-format
+msgid "E383: Invalid search string: %s"
+msgstr "E383: Ugyldig søkestreng: %s"
+
+#, c-format
+msgid "E384: search hit TOP without match for: %s"
+msgstr "E384: Søket kom til TOPPEN uten treff på: %s"
+
+#, c-format
+msgid "E385: search hit BOTTOM without match for: %s"
+msgstr "E385: Søket kom til BUNNEN uten treff på: %s"
+
+msgid "E386: Expected '?' or '/' after ';'"
+msgstr "E386: Forventet '?' eller '/' etter ';'"
+
+msgid " (includes previously listed match)"
+msgstr " (inkluderer tidligere utlistede treff)"
+
+#. cursor at status line
+msgid "--- Included files "
+msgstr "--- Inkluderte filer "
+
+msgid "not found "
+msgstr "ikke funnet "
+
+msgid "in path ---\n"
+msgstr "i sti ---\n"
+
+msgid " (Already listed)"
+msgstr " (Allerede listet)"
+
+msgid " NOT FOUND"
+msgstr " IKKE FUNNET"
+
+#, c-format
+msgid "Scanning included file: %s"
+msgstr "Leter gjennom inkludert fil: %s"
+
+#, c-format
+msgid "Searching included file %s"
+msgstr "Leter gjennom inkludert fil %s"
+
+msgid "E387: Match is on current line"
+msgstr "E387: Treffet er på nåværende linje"
+
+msgid "All included files were found"
+msgstr "Alle inkluderte filer ble funnet"
+
+msgid "No included files"
+msgstr "Ingen inkluderte filer"
+
+msgid "E388: Couldn't find definition"
+msgstr "E388: Fant ikke definisjonen"
+
+msgid "E389: Couldn't find pattern"
+msgstr "E389: Fant ikke søketeksten"
+
+#, c-format
+#~ msgid ""
+#~ "\n"
+#~ "# Last %sSearch Pattern:\n"
+#~ "~"
+#~ msgstr ""
+
+msgid "E759: Format error in spell file"
+msgstr "E759: Formateringsfeil i stavefil"
+
+msgid "E758: Truncated spell file"
+msgstr "E758: Valg av skriver feilet"
+
+#, c-format
+msgid "Trailing text in %s line %d: %s"
+msgstr "Etterfølgende tekst i %s linje %d: %s"
+
+#, c-format
+msgid "Affix name too long in %s line %d: %s"
+msgstr "Affiksnavn for langt i %s linje %d: %s"
+
+msgid "E761: Format error in affix file FOL, LOW or UPP"
+msgstr "E761: Formatfeil i affiksfil FOL, LOW eller UPP"
+
+msgid "E762: Character in FOL, LOW or UPP is out of range"
+msgstr "E762: Tegn i FOL, LOW eller UPP er utenfor område"
+
+msgid "Compressing word tree..."
+msgstr "Pakker ordtre ..."
+
+msgid "E756: Spell checking is not enabled"
+msgstr "E756: Stavekontroll er ikke aktivisert"
+
+#, c-format
+msgid "Warning: Cannot find word list \"%s.%s.spl\" or \"%s.ascii.spl\""
+msgstr "Advarsel: Kan ikke finne ordliste \"%s.%s.spl\" eller \"%s.ascii.spl\""
+
+#, c-format
+msgid "Reading spell file \"%s\""
+msgstr "Leser stavefil \"%s\""
+
+msgid "E757: This does not look like a spell file"
+msgstr "E757: Dette ser ikke ut som en stavefil"
+
+msgid "E771: Old spell file, needs to be updated"
+msgstr "E771: Gammel stavefil, trenger oppdatering"
+
+msgid "E772: Spell file is for newer version of Vim"
+msgstr "E772: Stavefilen er for en nyere versjon av Vim"
+
+msgid "E770: Unsupported section in spell file"
+msgstr "E770: Ustøttet seksjon i stavefil"
+
+#, c-format
+msgid "Warning: region %s not supported"
+msgstr "Advarsel: Region %s ikke støttet"
+
+#, c-format
+msgid "Reading affix file %s..."
+msgstr "Leser affiksfil %s..."
+
+#, c-format
+msgid "Conversion failure for word in %s line %d: %s"
+msgstr "Konverteringsfeil for ord i %s linje %d: %s"
+
+#, c-format
+msgid "Conversion in %s not supported: from %s to %s"
+msgstr "Konvertering i %s ikke støttet: Fra %s til %s"
+
+#, c-format
+msgid "Conversion in %s not supported"
+msgstr "Konvertering i %s ikke støttet"
+
+#, c-format
+msgid "Invalid value for FLAG in %s line %d: %s"
+msgstr "Ugyldig verdi for FLAG i %s linje %d: %s"
+
+#, c-format
+msgid "FLAG after using flags in %s line %d: %s"
+msgstr "FLAG etter bruk av flagg i %s linje %d: %s"
+
+#, c-format
+#~ msgid ""
+#~ "Defining COMPOUNDFORBIDFLAG after PFX item may give wrong results in %s line "
+#~ "%d"
+#~ msgstr ""
+
+#, c-format
+#~ msgid ""
+#~ "Defining COMPOUNDPERMITFLAG after PFX item may give wrong results in %s line "
+#~ "%d"
+#~ msgstr ""
+
+#, c-format
+msgid "Wrong COMPOUNDWORDMAX value in %s line %d: %s"
+msgstr "Feil COMPOUNDWORDMAX-verdi i %s linje %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDMIN value in %s line %d: %s"
+msgstr "Feil COMPOUNDMIN-verdi i %s linje %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDSYLMAX value in %s line %d: %s"
+msgstr "Feil COMPOUNDSYLMAX-verdi i %s linje %d: %s"
+
+#, c-format
+msgid "Wrong CHECKCOMPOUNDPATTERN value in %s line %d: %s"
+msgstr "Feil CHECKCOMPOUNDPATTERN-verdi i %s linje %d: %s"
+
+#, c-format
+msgid "Different combining flag in continued affix block in %s line %d: %s"
+msgstr ""
+"Forskjellig kombinasjonsflagg i affiksblokk som fortsetter i %s linje %d: %s"
+
+#, c-format
+msgid "Duplicate affix in %s line %d: %s"
+msgstr "Duplisert affiks i %s linje %d: %s"
+
+#, c-format
+msgid ""
+"Affix also used for BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST in %s "
+"line %d: %s"
+msgstr ""
+"Affiks også brukt for BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST i %"
+"s linje %d: %s"
+
+#, c-format
+msgid "Expected Y or N in %s line %d: %s"
+msgstr "Forventet Y eller N i %s linje %d: %s"
+
+#, c-format
+msgid "Broken condition in %s line %d: %s"
+msgstr "Brutt betingelse i %s linje %d: %s"
+
+#, c-format
+msgid "Expected REP(SAL) count in %s line %d"
+msgstr "Forventet REP(SAL)-antall i %s linje %d"
+
+#, c-format
+msgid "Expected MAP count in %s line %d"
+msgstr "Forventet MAP-antall i %s linje %d"
+
+#, c-format
+msgid "Duplicate character in MAP in %s line %d"
+msgstr "Duplisert tegn i MAP i %s linje %d"
+
+#, c-format
+msgid "Unrecognized or duplicate item in %s line %d: %s"
+msgstr "Ukjent eller duplisert element i %s linje %d: %s"
+
+#, c-format
+msgid "Missing FOL/LOW/UPP line in %s"
+msgstr "Mangler FOL/LOW/UPP-linje i %s"
+
+msgid "COMPOUNDSYLMAX used without SYLLABLE"
+msgstr "COMPOUNDSYLMAX brukt uten SYLLABLE"
+
+msgid "Too many postponed prefixes"
+msgstr "For mange utsatte forstavelser"
+
+msgid "Too many compound flags"
+msgstr "For mange sammensatte flagg"
+
+msgid "Too many postponed prefixes and/or compound flags"
+msgstr "For mange utsatte forstavelser og/eller sammensatte flagg"
+
+#, c-format
+msgid "Missing SOFO%s line in %s"
+msgstr "Mangler SOFO%s-linje i %s"
+
+#, c-format
+msgid "Both SAL and SOFO lines in %s"
+msgstr "Både SAL- og SOFO-linjer i %s"
+
+#, c-format
+msgid "Flag is not a number in %s line %d: %s"
+msgstr "Flagg er ikke et tall i %s linje %d: %s"
+
+#, c-format
+msgid "Illegal flag in %s line %d: %s"
+msgstr "Ulovlig flagg i %s linje %d: %s"
+
+#, c-format
+msgid "%s value differs from what is used in another .aff file"
+msgstr "%s-verdi er forskjellig fra det som er bruk i en annen .aff-fil"
+
+#, c-format
+msgid "Reading dictionary file %s..."
+msgstr "Leser ordlistefil %s..."
+
+#, c-format
+msgid "E760: No word count in %s"
+msgstr "E760: Ingen ord-antall i %s"
+
+#, c-format
+msgid "line %6d, word %6d - %s"
+msgstr "linje %6d, ord %6d - %s"
+
+#, c-format
+msgid "Duplicate word in %s line %d: %s"
+msgstr "Duplisert ord i %s linje %d: %s"
+
+#, c-format
+msgid "First duplicate word in %s line %d: %s"
+msgstr "Første dupliserte ord i %s linje %d: %s"
+
+#, c-format
+msgid "%d duplicate word(s) in %s"
+msgstr "%d duplisert(e) ord i %s"
+
+#, c-format
+msgid "Ignored %d word(s) with non-ASCII characters in %s"
+msgstr "Ignorerte %d ord med ikke-ASCII-tegn i %s"
+
+#, c-format
+msgid "Reading word file %s..."
+msgstr "Leser ordfil %s..."
+
+#, c-format
+msgid "Duplicate /encoding= line ignored in %s line %d: %s"
+msgstr "Duplisert '/encoding='-linje ignorert i %s linje %d: %s"
+
+#, c-format
+msgid "/encoding= line after word ignored in %s line %d: %s"
+msgstr "'/encoding='-linje etter ord ignorert i %s linje %d: %s"
+
+#, c-format
+msgid "Duplicate /regions= line ignored in %s line %d: %s"
+msgstr "Duplisert '/regions='-linje ignorert i %s linje %d: %s"
+
+#, c-format
+msgid "Too many regions in %s line %d: %s"
+msgstr "For mange regioner i %s linje %d: %s"
+
+#, c-format
+msgid "/ line ignored in %s line %d: %s"
+msgstr "'/'-linje ignorert i %s linje %d: %s"
+
+#, c-format
+msgid "Invalid region nr in %s line %d: %s"
+msgstr "Ugyldig regionnummer i %s linje %d: %s"
+
+#, c-format
+msgid "Unrecognized flags in %s line %d: %s"
+msgstr "Ukjent flagg i %s linje %d: %s"
+
+#, c-format
+msgid "Ignored %d words with non-ASCII characters"
+msgstr "Ignorerte %d ord med ikke-ASCII-tegn"
+
+#, c-format
+msgid "Compressed %d of %d nodes; %d (%d%%) remaining"
+msgstr "Pakket %d av %d noder; %d (%d%%) igjen"
+
+#, fuzzy
+#~ msgid "Reading back spell file..."
+#~ msgstr "Leser stavefil \"%s\""
+
+#.
+#. * Go through the trie of good words, soundfold each word and add it to
+#. * the soundfold trie.
+#.
+#~ msgid "Performing soundfolding..."
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Number of words after soundfolding: %ld"
+#~ msgstr ""
+
+#, c-format
+msgid "Total number of words: %d"
+msgstr "Totalt antall ord: %d"
+
+#, c-format
+msgid "Writing suggestion file %s..."
+msgstr "Skriver forslagsfil %s..."
+
+#, c-format
+msgid "Estimated runtime memory use: %d bytes"
+msgstr "Anslått hukommelsesbruk under kjøring: %d bytes"
+
+msgid "E751: Output file name must not have region name"
+msgstr "E751: Utdatafilnavn må ikke ha regionnavn"
+
+msgid "E754: Only up to 8 regions supported"
+msgstr "E754: Kun opp til 8 regioner er støttet"
+
+#, c-format
+msgid "E755: Invalid region in %s"
+msgstr "E755: Ugyldig region i %s"
+
+#~ msgid "Warning: both compounding and NOBREAK specified"
+#~ msgstr ""
+
+#, c-format
+msgid "Writing spell file %s..."
+msgstr "Lagrer stavefil %s..."
+
+msgid "Done!"
+msgstr "Ferdig!"
+
+#, c-format
+msgid "E765: 'spellfile' does not have %ld entries"
+msgstr "E765: 'spellfile' har ikke %ld poster"
+
+#, c-format
+msgid "Word removed from %s"
+msgstr "Ord fjernet fra %s"
+
+#, c-format
+msgid "Word added to %s"
+msgstr "Ord lagt til %s"
+
+msgid "E763: Word characters differ between spell files"
+msgstr "E763: Tegn i ord varierer mellom stavefiler"
+
+msgid "Sorry, no suggestions"
+msgstr "Dessverre, ingen forslag"
+
+#, c-format
+msgid "Sorry, only %ld suggestions"
+msgstr "Dessverre bare %ld forslag"
+
+#. for when 'cmdheight' > 1
+#. avoid more prompt
+#, c-format
+msgid "Change \"%.*s\" to:"
+msgstr "Forandre \"%.*s\" til:"
+
+#, c-format
+msgid " < \"%.*s\""
+msgstr " < \"%.*s\""
+
+msgid "E752: No previous spell replacement"
+msgstr "E752: Ingen tidligere staveerstatninger"
+
+#, c-format
+msgid "E753: Not found: %s"
+msgstr "E753: Ikke funnet: %s"
+
+#, c-format
+msgid "E778: This does not look like a .sug file: %s"
+msgstr "E778: Dette ser ikke ut som en .sug-fil: %s"
+
+#, c-format
+msgid "E779: Old .sug file, needs to be updated: %s"
+msgstr "E779: Gammel .sug-fil, trenger oppdatering: %s"
+
+#, c-format
+msgid "E780: .sug file is for newer version of Vim: %s"
+msgstr "E780: .sug-fila er for en nyere versjon av Vim: %s"
+
+#, c-format
+msgid "E781: .sug file doesn't match .spl file: %s"
+msgstr "E781: .sug-fil samsvarer ikke med .spl-fil: %s"
+
+#, c-format
+msgid "E782: error while reading .sug file: %s"
+msgstr "E782: Feil under lesing av .sug-fil: %s"
+
+#. This should have been checked when generating the .spl
+#. * file.
+msgid "E783: duplicate char in MAP entry"
+msgstr "E783: Duplisert tegn i MAP-oppføring"
+
+#, c-format
+msgid "E390: Illegal argument: %s"
+msgstr "E390: Ulovlig parameter: %s"
+
+#, c-format
+msgid "E391: No such syntax cluster: %s"
+msgstr "E391: Syntaksklyngen finnes ikke: %s"
+
+msgid "No Syntax items defined for this buffer"
+msgstr "Ingen syntakselementer er definert for denne bufferen"
+
+msgid "syncing on C-style comments"
+msgstr "synkroniserer C-lignende kommentarer"
+
+msgid "no syncing"
+msgstr "ingen synkronisering"
+
+msgid "syncing starts "
+msgstr "synkronisering starter "
+
+msgid " lines before top line"
+msgstr " linjer før topplinje"
+
+msgid ""
+"\n"
+"--- Syntax sync items ---"
+msgstr ""
+"\n"
+"--- \"Syntax sync\"-elementer ---"
+
+msgid ""
+"\n"
+"syncing on items"
+msgstr ""
+"\n"
+"synkroniserer på elementer"
+
+msgid ""
+"\n"
+"--- Syntax items ---"
+msgstr ""
+"\n"
+"--- Syntakselementer ---"
+
+#, c-format
+msgid "E392: No such syntax cluster: %s"
+msgstr "E392: Syntaksklyngen finnes ikke: %s"
+
+msgid "minimal "
+msgstr "minimal "
+
+msgid "maximal "
+msgstr "maksimal "
+
+msgid "; match "
+msgstr "; samsvarer med "
+
+msgid " line breaks"
+msgstr " linjeskift"
+
+msgid "E395: contains argument not accepted here"
+msgstr "E395: \"contains\"-parameter aksepteres ikke her"
+
+msgid "E396: containedin argument not accepted here"
+msgstr "E396: \"containedin\"-parameter aksepteres ikke her"
+
+msgid "E393: group[t]here not accepted here"
+msgstr "E393: \"group[t]here\" aksepteres ikke her"
+
+#, c-format
+msgid "E394: Didn't find region item for %s"
+msgstr "E394: Fant ikke regionelement for %s"
+
+msgid "E397: Filename required"
+msgstr "E397: Trenger filnavn"
+
+#, c-format
+msgid "E789: Missing ']': %s"
+msgstr "E789: Mangler ']': %s"
+
+#, c-format
+msgid "E398: Missing '=': %s"
+msgstr "E398: Mangler '=': %s"
+
+#, c-format
+msgid "E399: Not enough arguments: syntax region %s"
+msgstr "E399: Ikke nok parametere: syntax region %s"
+
+msgid "E400: No cluster specified"
+msgstr "E400: Ingen klynge er spesifisert"
+
+#, c-format
+msgid "E401: Pattern delimiter not found: %s"
+msgstr "E401: Skilletegn for søketekst ble ikke funnet: %s"
+
+#, c-format
+msgid "E402: Garbage after pattern: %s"
+msgstr "E402: Søppel etter søketekst: %s"
+
+msgid "E403: syntax sync: line continuations pattern specified twice"
+msgstr ""
+"E403: syntax sync: Søkestreng for linjefortsettelser er spesifisert to ganger"
+
+#, c-format
+msgid "E404: Illegal arguments: %s"
+msgstr "E404: Ulovlige parametere: %s"
+
+#, c-format
+msgid "E405: Missing equal sign: %s"
+msgstr "E405: Mangler \"er lik\"-tegn: %s"
+
+#, c-format
+msgid "E406: Empty argument: %s"
+msgstr "E406: Tomt parameter: %s"
+
+#, c-format
+msgid "E407: %s not allowed here"
+msgstr "E407: %s er ikke tillatt her"
+
+#, c-format
+msgid "E408: %s must be first in contains list"
+msgstr "E408: %s må være først i \"contains\"-liste"
+
+#, c-format
+msgid "E409: Unknown group name: %s"
+msgstr "E409: Ukjent gruppenavn: %s"
+
+#, c-format
+msgid "E410: Invalid :syntax subcommand: %s"
+msgstr "E410: Ugyldig \":syntax\"-delkommando: %s"
+
+msgid "E679: recursive loop loading syncolor.vim"
+msgstr "E679: Rekursiv løkke laster syncolor.vim"
+
+#, c-format
+msgid "E411: highlight group not found: %s"
+msgstr "E411: Fant ikke uthevingsgruppe: %s"
+
+#, c-format
+msgid "E412: Not enough arguments: \":highlight link %s\""
+msgstr "E412: Ikke nok parametere: \":highlight link %s\""
+
+#, c-format
+msgid "E413: Too many arguments: \":highlight link %s\""
+msgstr "E413: For mange parametere: \":highlight link %s\""
+
+msgid "E414: group has settings, highlight link ignored"
+msgstr "E414: Syntaxgruppen har oppsett, uthevingslenke ignoreres"
+
+#, c-format
+msgid "E415: unexpected equal sign: %s"
+msgstr "E415: Uventet \"er lik\"-tegn: %s"
+
+#, c-format
+msgid "E416: missing equal sign: %s"
+msgstr "E416: Mangler \"er lik\"-tegn: %s"
+
+#, c-format
+msgid "E417: missing argument: %s"
+msgstr "E417: Mangler parameter: %s"
+
+#, c-format
+msgid "E418: Illegal value: %s"
+msgstr "E418: Ulovlig verdi: %s"
+
+msgid "E419: FG color unknown"
+msgstr "E419: Ukjent forgrunnsfarge"
+
+msgid "E420: BG color unknown"
+msgstr "E420: Ukjent bakgrunnsfarge"
+
+#, c-format
+msgid "E421: Color name or number not recognized: %s"
+msgstr "E421: Kjenner ikke til fargenavnet eller -nummeret: %s"
+
+#, c-format
+msgid "E422: terminal code too long: %s"
+msgstr "E422: Terminalkoden er for lang: %s"
+
+#, c-format
+msgid "E423: Illegal argument: %s"
+msgstr "E423: Ulovlig parameter: %s"
+
+msgid "E424: Too many different highlighting attributes in use"
+msgstr "E424: For mange forskjellige uthevingsattributter i bruk"
+
+msgid "E669: Unprintable character in group name"
+msgstr "E669: Ikke-skrivbart tegn i gruppenavn"
+
+msgid "W18: Invalid character in group name"
+msgstr "W18: Ugyldig tegn i gruppenavn"
+
+msgid "E555: at bottom of tag stack"
+msgstr "E555: På bunnen av tag-stack"
+
+msgid "E556: at top of tag stack"
+msgstr "E556: På toppen av tag-stack"
+
+msgid "E425: Cannot go before first matching tag"
+msgstr "E425: Kan ikke gå før første samsvarende tag"
+
+#, c-format
+msgid "E426: tag not found: %s"
+msgstr "E426: Fant ikke tag: %s"
+
+#~ msgid " # pri kind tag"
+#~ msgstr ""
+
+msgid "file\n"
+msgstr "fil\n"
+
+msgid "E427: There is only one matching tag"
+msgstr "E427: Det finnes bare en samsvarende tag"
+
+msgid "E428: Cannot go beyond last matching tag"
+msgstr "E428: Kan ikke gå forbi siste samsvarende tag"
+
+#, c-format
+msgid "File \"%s\" does not exist"
+msgstr "Filen \"%s\" finnes ikke"
+
+#. Give an indication of the number of matching tags
+#, c-format
+msgid "tag %d of %d%s"
+msgstr "tag %d av %d%s"
+
+msgid " or more"
+msgstr " eller mer"
+
+msgid " Using tag with different case!"
+msgstr " Bruker tag med forskjellig bokstavstørrelse!"
+
+#, c-format
+msgid "E429: File \"%s\" does not exist"
+msgstr "E429: Filen \"%s\" finnes ikke"
+
+#. Highlight title
+msgid ""
+"\n"
+" # TO tag FROM line in file/text"
+msgstr ""
+"\n"
+" # TIL tag FRA linje i fil/tekst"
+
+#, c-format
+msgid "Searching tags file %s"
+msgstr "Leter i tagfil %s"
+
+#, c-format
+msgid "E430: Tag file path truncated for %s\n"
+msgstr "E430: Sti til tagfil kuttet for %s\n"
+
+#, c-format
+msgid "E431: Format error in tags file \"%s\""
+msgstr "E431: Formatfeil i tagfil \"%s\""
+
+#, c-format
+msgid "Before byte %ld"
+msgstr "Før byte %ld"
+
+#, c-format
+msgid "E432: Tags file not sorted: %s"
+msgstr "E432: Tagfil ikke sortert: %s"
+
+#. never opened any tags file
+msgid "E433: No tags file"
+msgstr "E433: Ingen tagfil"
+
+msgid "E434: Can't find tag pattern"
+msgstr "E434: Kan ikke finne tagsøkestreng"
+
+msgid "E435: Couldn't find tag, just guessing!"
+msgstr "E435: Kunne ikke finne tag, bare gjetter!"
+
+msgid "' not known. Available builtin terminals are:"
+msgstr "' ikke kjent. Tilgjengelige innebygde terminaler er:"
+
+msgid "defaulting to '"
+msgstr "faller tilbake på '"
+
+msgid "E557: Cannot open termcap file"
+msgstr "E557: Kan ikke åpne termcap-fil"
+
+msgid "E558: Terminal entry not found in terminfo"
+msgstr "E558: Fant ikke terminaloppføring i terminfo"
+
+msgid "E559: Terminal entry not found in termcap"
+msgstr "E559: Fant ikke terminaloppføring i termcap"
+
+#, c-format
+msgid "E436: No \"%s\" entry in termcap"
+msgstr "E436: Ingen \"%s\"-oppføring i termcap"
+
+msgid "E437: terminal capability \"cm\" required"
+msgstr "E437: Terminalfunksjonen \"cm\" nødvendig"
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Terminal keys ---"
+msgstr ""
+"\n"
+"--- Terminaltaster ---"
+
+msgid "new shell started\n"
+msgstr "nytt skall startet\n"
+
+msgid "Vim: Error reading input, exiting...\n"
+msgstr "Vim: Feil under lesing av inndata, avslutter ...\n"
+
+#. must display the prompt
+msgid "No undo possible; continue anyway"
+msgstr "Ingen angremuligheter; fortsett likevel"
+
+msgid "Already at oldest change"
+msgstr "Allerede ved eldste forandring"
+
+msgid "Already at newest change"
+msgstr "Allerede ved nyeste forandring"
+
+#, c-format
+msgid "Undo number %ld not found"
+msgstr "Angrenummer %ld ikke funnet"
+
+msgid "E438: u_undo: line numbers wrong"
+msgstr "E438: u_undo: Gale linjenummer"
+
+msgid "more line"
+msgstr "linje lagt til"
+
+msgid "more lines"
+msgstr "linjer lagt til"
+
+msgid "line less"
+msgstr "linje fjernet"
+
+msgid "fewer lines"
+msgstr "linjer fjernet"
+
+msgid "change"
+msgstr "forandring"
+
+msgid "changes"
+msgstr "forandringer"
+
+#, c-format
+msgid "%ld %s; %s #%ld %s"
+msgstr "%ld %s; %s #%ld %s"
+
+msgid "before"
+msgstr "før"
+
+msgid "after"
+msgstr "etter"
+
+msgid "Nothing to undo"
+msgstr "Ingenting å angre"
+
+msgid "number changes time"
+msgstr "nummer forandringer tidspunkt"
+
+#, c-format
+msgid "%ld seconds ago"
+msgstr "%ld sekunder siden"
+
+msgid "E790: undojoin is not allowed after undo"
+msgstr "E790: undojoin er ikke tillatt etter undo"
+
+msgid "E439: undo list corrupt"
+msgstr "E439: Angrelisten er skadet"
+
+msgid "E440: undo line missing"
+msgstr "E440: Angrelisten mangler"
+
+#. Only MS VC 4.1 and earlier can do Win32s
+msgid ""
+"\n"
+"MS-Windows 16/32-bit GUI version"
+msgstr ""
+"\n"
+"MS Windows 16/32-bits grafisk versjon"
+
+msgid ""
+"\n"
+"MS-Windows 64-bit GUI version"
+msgstr ""
+"\n"
+"MS Windows 64-bits grafisk versjon"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit GUI version"
+msgstr ""
+"\n"
+"MS-Windows 32-bits GUI-versjon"
+
+msgid " in Win32s mode"
+msgstr " i Win32s-modus"
+
+msgid " with OLE support"
+msgstr " med OLE-støtte"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit console version"
+msgstr ""
+"\n"
+"MS-Windows 32-bits konsollversjon"
+
+msgid ""
+"\n"
+"MS-Windows 16-bit version"
+msgstr ""
+"\n"
+"MS-Windows 16-bits versjon"
+
+msgid ""
+"\n"
+"32-bit MS-DOS version"
+msgstr ""
+"\n"
+"32-bits MS-DOS-versjon"
+
+msgid ""
+"\n"
+"16-bit MS-DOS version"
+msgstr ""
+"\n"
+"16-bits MS-DOS-versjon"
+
+msgid ""
+"\n"
+"MacOS X (unix) version"
+msgstr ""
+"\n"
+"MacOS X (unix)-versjon"
+
+msgid ""
+"\n"
+"MacOS X version"
+msgstr ""
+"\n"
+"MacOS X-versjon"
+
+msgid ""
+"\n"
+"MacOS version"
+msgstr ""
+"\n"
+"MacOS-versjon"
+
+msgid ""
+"\n"
+"RISC OS version"
+msgstr ""
+"\n"
+"RISC OS-versjon"
+
+msgid ""
+"\n"
+"Included patches: "
+msgstr ""
+"\n"
+"Inkluderte patcher: "
+
+msgid "Modified by "
+msgstr "Modifisert av "
+
+msgid ""
+"\n"
+"Compiled "
+msgstr ""
+"\n"
+"Kompilert "
+
+msgid "by "
+msgstr "av "
+
+msgid ""
+"\n"
+"Huge version "
+msgstr ""
+"\n"
+"Diger (\"huge\") versjon "
+
+msgid ""
+"\n"
+"Big version "
+msgstr ""
+"\n"
+"Stor (\"big\") versjon "
+
+msgid ""
+"\n"
+"Normal version "
+msgstr ""
+"\n"
+"Normal versjon "
+
+msgid ""
+"\n"
+"Small version "
+msgstr ""
+"\n"
+"Liten (\"small\") versjon "
+
+msgid ""
+"\n"
+"Tiny version "
+msgstr ""
+"\n"
+"Spinkel (\"tiny\") versjon "
+
+msgid "without GUI."
+msgstr "uten GUI."
+
+msgid "with GTK2-GNOME GUI."
+msgstr "med GTK2-GNOME GUI."
+
+msgid "with GTK-GNOME GUI."
+msgstr "med GTK-GNOME GUI."
+
+msgid "with GTK2 GUI."
+msgstr "med GTK2 GUI."
+
+msgid "with GTK GUI."
+msgstr "med GTK GUI."
+
+msgid "with X11-Motif GUI."
+msgstr "med X11-Motif GUI."
+
+msgid "with X11-neXtaw GUI."
+msgstr "med X11-neXtaw GUI."
+
+msgid "with X11-Athena GUI."
+msgstr "med X11-Athena GUI."
+
+msgid "with Photon GUI."
+msgstr "med Photon GUI."
+
+msgid "with GUI."
+msgstr "med GUI."
+
+msgid "with Carbon GUI."
+msgstr "med Carbon GUI."
+
+msgid "with Cocoa GUI."
+msgstr "med Cocoa GUI."
+
+msgid "with (classic) GUI."
+msgstr "med (klassisk) GUI."
+
+msgid " Features included (+) or not (-):\n"
+msgstr " Funksjoner inkludert (+) eller ikke (-):\n"
+
+msgid " system vimrc file: \""
+msgstr " vimrc-fil på systemet: \""
+
+msgid " user vimrc file: \""
+msgstr " vimrc-fil for brukere: \""
+
+msgid " 2nd user vimrc file: \""
+msgstr " vimrc-fil nr. 2 for brukere: \""
+
+msgid " 3rd user vimrc file: \""
+msgstr " vimrc-fil nr. 3 for brukere: \""
+
+msgid " user exrc file: \""
+msgstr " exrc-fil for brukere: \""
+
+msgid " 2nd user exrc file: \""
+msgstr " exrc-fil nr. 2 for brukere: \""
+
+msgid " system gvimrc file: \""
+msgstr " gvimrc-fil på systemet: \""
+
+msgid " user gvimrc file: \""
+msgstr " gvimrc-fil for brukere: \""
+
+msgid "2nd user gvimrc file: \""
+msgstr " gvimrc-fil nr. 2 for brukere: \""
+
+msgid "3rd user gvimrc file: \""
+msgstr " gvimrc-fil nr. 3 for brukere: \""
+
+msgid " system menu file: \""
+msgstr " menyfil på systemet: \""
+
+msgid " fall-back for $VIM: \""
+msgstr " $VIM faller tilbake på: \""
+
+msgid " f-b for $VIMRUNTIME: \""
+msgstr "$VIMRUNTIME faller tilbake på: \""
+
+msgid "Compilation: "
+msgstr "Kompilering: "
+
+msgid "Compiler: "
+msgstr "Kompilator: "
+
+msgid "Linking: "
+msgstr "Linking: "
+
+msgid " DEBUG BUILD"
+msgstr " DEBUGGINGSVERSJON"
+
+msgid "VIM - Vi IMproved"
+msgstr "VIM - Vi IMproved - Forbedret Vi"
+
+msgid "version "
+msgstr "versjon "
+
+msgid "by Bram Moolenaar et al."
+msgstr "av Bram Moolenaar med flere"
+
+msgid "Vim is open source and freely distributable"
+msgstr "Vim er åpen kildekode og kan fritt distribueres"
+
+msgid "Help poor children in Uganda!"
+msgstr "Hjelp fattige barn i Uganda!"
+
+msgid "type :help iccf<Enter> for information "
+msgstr "skriv :help iccf<Enter> for informasjon "
+
+msgid "type :q<Enter> to exit "
+msgstr "skriv :q<Enter> for å avslutte "
+
+msgid "type :help<Enter> or <F1> for on-line help"
+msgstr "skriv :help<Enter> eller <F1> for on-line hjelp"
+
+msgid "type :help version8<Enter> for version info"
+msgstr "skriv :help version8<Enter> for versjonsinfo "
+
+msgid "Running in Vi compatible mode"
+msgstr "Kjører i Vi-kompatibel modus"
+
+msgid "type :set nocp<Enter> for Vim defaults"
+msgstr "skriv :set nocp<Enter> for standard Vim "
+
+msgid "type :help cp-default<Enter> for info on this"
+msgstr "skriv :help cp-default<Enter> for informasjon "
+
+msgid "menu Help->Orphans for information "
+msgstr "meny: Hjelp->Foreldreløse for informasjon "
+
+msgid "Running modeless, typed text is inserted"
+msgstr "Kjører uten modus, tastetrykk blir lagt inn i teksten"
+
+msgid "menu Edit->Global Settings->Toggle Insert Mode "
+msgstr "meny: Rediger->Globale innstillinger->Innsettingsmodus av/på"
+
+msgid " for two modes "
+msgstr " for to moduser "
+
+msgid "menu Edit->Global Settings->Toggle Vi Compatible"
+msgstr "meny: Rediger->Globale innstillinger->Vi-kompatibilitet av/på"
+
+msgid " for Vim defaults "
+msgstr " for standard Vim "
+
+msgid "Sponsor Vim development!"
+msgstr "Støtt utviklingen av Vim!"
+
+msgid "Become a registered Vim user!"
+msgstr "Bli registrert bruker av Vim!"
+
+msgid "type :help sponsor<Enter> for information "
+msgstr "skriv :help sponsor<Enter> for informasjon "
+
+msgid "type :help register<Enter> for information "
+msgstr "skriv :help register<Enter> for informasjon "
+
+msgid "menu Help->Sponsor/Register for information "
+msgstr "meny: Hjelp->Støtte/Registrering for informasjon "
+
+msgid "WARNING: Windows 95/98/ME detected"
+msgstr "ADVARSEL: Windows 95/98/ME oppdaget"
+
+msgid "type :help windows95<Enter> for info on this"
+msgstr "skriv :help windows95<Enter> for informasjon "
+
+msgid "Already only one window"
+msgstr "Allerede bare ett vindu"
+
+msgid "E441: There is no preview window"
+msgstr "E441: Vindu for forhåndsvisning finnes ikke"
+
+msgid "E442: Can't split topleft and botright at the same time"
+msgstr "E442: Kan ikke splitte \"topleft\" og \"botright\" på en gang"
+
+msgid "E443: Cannot rotate when another window is split"
+msgstr "E443: Kan ikke rotere når et annet vindu er splittet"
+
+msgid "E444: Cannot close last window"
+msgstr "E444: Kan ikke lukke det siste vinduet"
+
+msgid "E445: Other window contains changes"
+msgstr "E445: Annet vindu inneholder forandringer"
+
+msgid "E446: No file name under cursor"
+msgstr "E446: Ingen filnavn under markøren"
+
+#, c-format
+msgid "E447: Can't find file \"%s\" in path"
+msgstr "E447: Kan ikke finne filen \"%s\" i stien"
+
+#, c-format
+msgid "E370: Could not load library %s"
+msgstr "E370: Klarte ikke laste bibliotek %s"
+
+msgid "Sorry, this command is disabled: the Perl library could not be loaded."
+msgstr "Denne kommandoen er deaktivert, Perl-biblioteket kunne ikke lastes."
+
+msgid "E299: Perl evaluation forbidden in sandbox without the Safe module"
+msgstr ""
+"E299: Evaluering av Perl er ikke tillatt i sandkassen uten \"Safe\"-modulen"
+
+msgid "Edit with &multiple Vims"
+msgstr "Rediger med &flere Vim-er"
+
+msgid "Edit with single &Vim"
+msgstr "Rediger med enkel &Vim"
+
+msgid "Diff with Vim"
+msgstr "Differanse med Vim"
+
+msgid "Edit with &Vim"
+msgstr "Rediger med &Vim"
+
+#. Now concatenate
+msgid "Edit with existing Vim - "
+msgstr "Rediger med eksisterende Vim - "
+
+msgid "Edits the selected file(s) with Vim"
+msgstr "Redigerer de(n) valgte filen(e) med Vim"
+
+msgid "Error creating process: Check if gvim is in your path!"
+msgstr "Klarte ikke lage prosess: Sjekk at gvim er i stien!"
+
+msgid "gvimext.dll error"
+msgstr "Feil i gvimext.dll"
+
+msgid "Path length too long!"
+msgstr "Lengden på stien er for lang!"
+
+msgid "--No lines in buffer--"
+msgstr "--Ingen linjer i bufferen--"
+
+#.
+#. * The error messages that can be shared are included here.
+#. * Excluded are errors that are only used once and debugging messages.
+#.
+msgid "E470: Command aborted"
+msgstr "E470: Kommandoen avbrutt"
+
+msgid "E471: Argument required"
+msgstr "E471: Parameter nødvendig"
+
+msgid "E10: \\ should be followed by /, ? or &"
+msgstr "E10: \\ skulle ha vært fulgt av /, ? eller &"
+
+msgid "E11: Invalid in command-line window; <CR> executes, CTRL-C quits"
+msgstr "E11: Ugyldig i kommandolinjevindu; <ENTER> utfører, CTRL-C avslutter"
+
+msgid "E12: Command not allowed from exrc/vimrc in current dir or tag search"
+msgstr ""
+"E12: Kommandoen er ikke tillatt fra exrc/vimrc i nåværende katalog eller "
+"tagsøk"
+
+msgid "E171: Missing :endif"
+msgstr "E171: Mangler :endif"
+
+msgid "E600: Missing :endtry"
+msgstr "E600: Mangler :endtry"
+
+msgid "E170: Missing :endwhile"
+msgstr "E170: Mangler :endwhile"
+
+msgid "E170: Missing :endfor"
+msgstr "E170: Mangler :endfor"
+
+msgid "E588: :endwhile without :while"
+msgstr "E588: :endwhile uten :while"
+
+msgid "E588: :endfor without :for"
+msgstr "E588: :endfor uten :for"
+
+msgid "E13: File exists (add ! to override)"
+msgstr "E13: Filen finnes (legg til ! for å overstyre)"
+
+msgid "E472: Command failed"
+msgstr "E472: Kommandoen feilet"
+
+#, c-format
+msgid "E234: Unknown fontset: %s"
+msgstr "E234: Ukjent skrifttypesett: %s"
+
+#, c-format
+msgid "E235: Unknown font: %s"
+msgstr "E235: Ukjent skrifttype: %s"
+
+#, c-format
+msgid "E236: Font \"%s\" is not fixed-width"
+msgstr "E236: Skrifttypen \"%s\" har ikke fast bredde"
+
+msgid "E473: Internal error"
+msgstr "E473: Intern feil"
+
+msgid "Interrupted"
+msgstr "Avbrutt"
+
+msgid "E14: Invalid address"
+msgstr "E14: Ugyldig adresse"
+
+msgid "E474: Invalid argument"
+msgstr "E474: Ugyldig parameter"
+
+#, c-format
+msgid "E475: Invalid argument: %s"
+msgstr "E475: Ugyldig paramter: %s"
+
+#, c-format
+msgid "E15: Invalid expression: %s"
+msgstr "E15: Ugyldig uttrykk: %s"
+
+msgid "E16: Invalid range"
+msgstr "E16: Ugyldig område"
+
+msgid "E476: Invalid command"
+msgstr "E476: Ugyldig kommando"
+
+#, c-format
+msgid "E17: \"%s\" is a directory"
+msgstr "E17: \"%s\" er en katalog"
+
+#, c-format
+msgid "E364: Library call failed for \"%s()\""
+msgstr "E364: Bibliotek-kall feilet for \"%s()\""
+
+#, c-format
+msgid "E448: Could not load library function %s"
+msgstr "E448: Klarte ikke laste biblioteksfunksjon %s"
+
+msgid "E19: Mark has invalid line number"
+msgstr "E19: Merket har et ugyldig linjenummer"
+
+msgid "E20: Mark not set"
+msgstr "E20: Merket ble ikke satt"
+
+msgid "E21: Cannot make changes, 'modifiable' is off"
+msgstr "E21: Kan ikke gjøre forandringer, 'modifiable' er av"
+
+msgid "E22: Scripts nested too deep"
+msgstr "E22: Skripts nøstet for dypt"
+
+msgid "E23: No alternate file"
+msgstr "E23: Ingen alternativ fil"
+
+msgid "E24: No such abbreviation"
+msgstr "E24: Forkortelsen finnes ikke"
+
+msgid "E477: No ! allowed"
+msgstr "E477: Ingen ! tillatt"
+
+msgid "E25: GUI cannot be used: Not enabled at compile time"
+msgstr "E25: GUI kan ikke brukes: Ikke slått på under kompilering"
+
+msgid "E26: Hebrew cannot be used: Not enabled at compile time\n"
+msgstr "E26: Hebraisk kan ikke brukes: Ikke slått på under kompilering\n"
+
+msgid "E27: Farsi cannot be used: Not enabled at compile time\n"
+msgstr ""
+"E27: Persisk (Farsi) kan ikke brukes: Ikke slått på under kompilering\n"
+
+msgid "E800: Arabic cannot be used: Not enabled at compile time\n"
+msgstr "E800: Arabisk kan ikke brukes: Ikke slått på under kompilering\n"
+
+#, c-format
+msgid "E28: No such highlight group name: %s"
+msgstr "E28: Uthevingsgruppe finnes ikke: %s"
+
+msgid "E29: No inserted text yet"
+msgstr "E29: Ingen innlagt tekst enda"
+
+msgid "E30: No previous command line"
+msgstr "E30: Ingen tidligere kommandolinje"
+
+msgid "E31: No such mapping"
+msgstr "E31: Mappingen finnes ikke"
+
+msgid "E479: No match"
+msgstr "E479: Ingen treff"
+
+#, c-format
+msgid "E480: No match: %s"
+msgstr "E480: Ingen treff: %s"
+
+msgid "E32: No file name"
+msgstr "E32: Mangler filnavn"
+
+msgid "E33: No previous substitute regular expression"
+msgstr "E33: Ingen tidligere erstatninger med regulære uttrykk"
+
+msgid "E34: No previous command"
+msgstr "E34: Ingen tidligere kommando"
+
+msgid "E35: No previous regular expression"
+msgstr "E35: Ingen tidligere regulære uttrykk"
+
+msgid "E481: No range allowed"
+msgstr "E481: Område er ikke tillatt"
+
+msgid "E36: Not enough room"
+msgstr "E36: Ikke nok plass"
+
+#, c-format
+msgid "E247: no registered server named \"%s\""
+msgstr "E247: Ingen registrert tjener kalt \"%s\""
+
+#, c-format
+msgid "E482: Can't create file %s"
+msgstr "E482: Kan ikke opprette filen %s"
+
+msgid "E483: Can't get temp file name"
+msgstr "E483: Kan ikke hente navn på midlertidig fil"
+
+#, c-format
+msgid "E484: Can't open file %s"
+msgstr "E484: Kan ikke åpne filen %s"
+
+#, c-format
+msgid "E485: Can't read file %s"
+msgstr "E485: Kan ikke lese filen %s"
+
+msgid "E37: No write since last change (add ! to override)"
+msgstr "E37: Ikke lagret siden forrige forandring (legg til ! for å overstyre)"
+
+msgid "E38: Null argument"
+msgstr "E38: Nullparameter"
+
+msgid "E39: Number expected"
+msgstr "E39: Nummer forventet"
+
+#, c-format
+msgid "E40: Can't open errorfile %s"
+msgstr "E40: Kan ikke åpne feilfilen %s"
+
+msgid "E233: cannot open display"
+msgstr "E233: Kan ikke åpne display"
+
+msgid "E41: Out of memory!"
+msgstr "E41: Ikke mer ledig hukommelse!"
+
+msgid "Pattern not found"
+msgstr "Fant ikke søketeksten"
+
+#, c-format
+msgid "E486: Pattern not found: %s"
+msgstr "E486: Fant ikke søketeksten: %s"
+
+msgid "E487: Argument must be positive"
+msgstr "E487: Parameteret må være positivt"
+
+msgid "E459: Cannot go back to previous directory"
+msgstr "E459: Kan ikke gå tilbake til tidligere katalog"
+
+msgid "E42: No Errors"
+msgstr "E42: Ingen feil"
+
+msgid "E776: No location list"
+msgstr "E776: Ingen plassliste"
+
+msgid "E43: Damaged match string"
+msgstr "E43: Ødelagt søkestreng"
+
+msgid "E44: Corrupted regexp program"
+msgstr "E44: Skadet program med regulært uttrykk"
+
+msgid "E45: 'readonly' option is set (add ! to override)"
+msgstr "E45: 'readonly'-valget er satt (legg til ! for å overstyre)"
+
+#, c-format
+msgid "E46: Cannot change read-only variable \"%s\""
+msgstr "E46: Kan ikke forandre skrivebeskyttet variabel \"%s\""
+
+#, c-format
+msgid "E794: Cannot set variable in the sandbox: \"%s\""
+msgstr "E794: Kan ikke sette variabel i sandkassen: \"%s\""
+
+msgid "E47: Error while reading errorfile"
+msgstr "E47: Feil under lesing av feilfilen"
+
+msgid "E48: Not allowed in sandbox"
+msgstr "E48: Ikke tillatt i sandkassen"
+
+msgid "E523: Not allowed here"
+msgstr "E523: Ikke tillatt her"
+
+msgid "E359: Screen mode setting not supported"
+msgstr "E359: Forandring av skjermmodus er ikke støttet"
+
+msgid "E49: Invalid scroll size"
+msgstr "E49: Ugyldig \"scroll\"-verdi"
+
+msgid "E91: 'shell' option is empty"
+msgstr "E91: 'shell'-valget er tomt"
+
+msgid "E255: Couldn't read in sign data!"
+msgstr "E255: Kunne ikke lese inn skiltdata!"
+
+msgid "E72: Close error on swap file"
+msgstr "E72: Feil under lukking av swapfil"
+
+msgid "E73: tag stack empty"
+msgstr "E73: Tag-stack tom"
+
+msgid "E74: Command too complex"
+msgstr "E74: Kommandoen er for kompleks"
+
+msgid "E75: Name too long"
+msgstr "E75: Navnet er for langt"
+
+msgid "E76: Too many ["
+msgstr "E76: For mange ["
+
+msgid "E77: Too many file names"
+msgstr "E77: For mange filnavn"
+
+msgid "E488: Trailing characters"
+msgstr "E488: Etterfølgende tegn"
+
+msgid "E78: Unknown mark"
+msgstr "E78: Ukjent merke"
+
+msgid "E79: Cannot expand wildcards"
+msgstr "E79: Klarte ikke utvide jokertegn"
+
+msgid "E591: 'winheight' cannot be smaller than 'winminheight'"
+msgstr "E591: 'winheight' kan ikke være mindre enn 'winminheight'"
+
+msgid "E592: 'winwidth' cannot be smaller than 'winminwidth'"
+msgstr "E592: 'winwidth' kan ikke være mindre enn 'winminwidth'"
+
+msgid "E80: Error while writing"
+msgstr "E80: Feil under skriving"
+
+msgid "Zero count"
+msgstr "Antall repeteringer er null"
+
+msgid "E81: Using <SID> not in a script context"
+msgstr "E81: Bruker <SID> utenom skript-kontekst"
+
+msgid "E449: Invalid expression received"
+msgstr "E449: Ugyldig uttrykk mottatt"
+
+msgid "E463: Region is guarded, cannot modify"
+msgstr "E463: Regionen er beskyttet og kan ikke modifiseres"
+
+msgid "E744: NetBeans does not allow changes in read-only files"
+msgstr "E744: NetBeans tillater ikke forandringer i skrivebeskyttede filer"
+
+#, c-format
+msgid "E685: Internal error: %s"
+msgstr "E685: Intern feil: %s"
+
+msgid "E363: pattern uses more memory than 'maxmempattern'"
+msgstr "E363: Søkestrengen bruker mer hukommelse enn 'maxmempattern'"
+
+msgid "E749: empty buffer"
+msgstr "E749: Tom buffer"
+
+msgid "E682: Invalid search pattern or delimiter"
+msgstr "E682: Ugyldig søkestreng eller skilletegn"
+
+msgid "E139: File is loaded in another buffer"
+msgstr "E139: Filen er lastet i en annen buffer"
+
+#, c-format
+msgid "E764: Option '%s' is not set"
+msgstr "E764: Valget '%s' er ikke satt"
+
+msgid "search hit TOP, continuing at BOTTOM"
+msgstr "Søket traff TOPPEN, fortsetter fra BUNNEN"
+
+msgid "search hit BOTTOM, continuing at TOP"
+msgstr "Søket traff BUNNEN, fortsetter fra TOPPEN"
diff --git a/src/po/nl.po b/src/po/nl.po
new file mode 100644
index 0000000..38d01db
--- /dev/null
+++ b/src/po/nl.po
@@ -0,0 +1,5852 @@
+# Dutch Translation for Vim vim:set foldmethod=marker:
+# Do ":help uganda" in Vim to read copying and usage conditions.
+# Do ":help credits" in Vim to see a list of people who contributed.
+# Previous-Translator(s):
+# highlight: oplichten
+# Erwin Poeze <erwin.poeze@gmail.com>, 2011, 2012.
+msgid ""
+msgstr ""
+"Project-Id-Version: vim 7.3\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2011-05-29 07:43+0200\n"
+"PO-Revision-Date: 2012-03-28 08:07+0200\n"
+"Last-Translator: YOUR NAME <E-MAIL@ADDRESS>\n"
+"Language-Team: Dutch <vertaling@vrijschrift.nl>\n"
+"Language: nl\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+msgid "E831: bf_key_init() called with empty password"
+msgstr "E831: bf_key_init() uitgevoerd met leeg wachtwoord"
+
+msgid "E820: sizeof(uint32_t) != 4"
+msgstr "E820: sizeof(uint32_t) != 4"
+
+msgid "E817: Blowfish big/little endian use wrong"
+msgstr "E817: gebruik Blowfish big/little endian is onjuist"
+
+msgid "E818: sha256 test failed"
+msgstr "E818: sha256 test mislukt"
+
+msgid "E819: Blowfish test failed"
+msgstr "E819: Blowfish test mislukt"
+
+msgid "E82: Cannot allocate any buffer, exiting..."
+msgstr "E82: kan geen buffer aanmaken, beëindigen..."
+
+msgid "E83: Cannot allocate buffer, using other one..."
+msgstr "E83: kan geen buffer aanmaken, een andere wordt gebruikt..."
+
+msgid "E515: No buffers were unloaded"
+msgstr "E515: geen van de buffers is gelost"
+
+msgid "E516: No buffers were deleted"
+msgstr "E516: geen van de buffers is verwijderd"
+
+msgid "E517: No buffers were wiped out"
+msgstr "E517: geen van de buffers is gewist"
+
+msgid "1 buffer unloaded"
+msgstr "1 buffer gelost"
+
+#, c-format
+msgid "%d buffers unloaded"
+msgstr "%d buffers gelost"
+
+msgid "1 buffer deleted"
+msgstr "1 buffer verwijderd"
+
+#, c-format
+msgid "%d buffers deleted"
+msgstr "%d buffers verwijderd"
+
+msgid "1 buffer wiped out"
+msgstr "1 buffer gewist"
+
+#, c-format
+msgid "%d buffers wiped out"
+msgstr "%d buffers gewist"
+
+msgid "E84: No modified buffer found"
+msgstr "E84: geen aangepast buffer gevonden"
+
+#. back where we started, didn't find anything.
+msgid "E85: There is no listed buffer"
+msgstr "E85: er is geen vermelde buffer"
+
+#, c-format
+msgid "E86: Buffer %ld does not exist"
+msgstr "E86: Buffer %ld bestaat niet"
+
+msgid "E87: Cannot go beyond last buffer"
+msgstr "E87: kan niet voorbij het laatste buffer komen"
+
+msgid "E88: Cannot go before first buffer"
+msgstr "E88: kan niet vóór het eerste buffer komen"
+
+#, c-format
+msgid "E89: No write since last change for buffer %ld (add ! to override)"
+msgstr "E89: niets opgeslagen sinds laatste wijziging van buffer %ld (voeg ! toe om te forceren)"
+
+msgid "E90: Cannot unload last buffer"
+msgstr "E90: kan laatste buffer niet legen"
+
+msgid "W14: Warning: List of file names overflow"
+msgstr "W14: waarschuwing: lijst met bestandsnamen is vol"
+
+#, c-format
+msgid "E92: Buffer %ld not found"
+msgstr "E92: buffer %ld niet gevonden"
+
+#, c-format
+msgid "E93: More than one match for %s"
+msgstr "E93: %s meermaals gevonden"
+
+#, c-format
+msgid "E94: No matching buffer for %s"
+msgstr "E94: geen overeenkomstig buffer voor %s"
+
+#, c-format
+msgid "line %ld"
+msgstr "regel %ld"
+
+msgid "E95: Buffer with this name already exists"
+msgstr "E95: buffer met deze naam bestaat al"
+
+msgid " [Modified]"
+msgstr " [Gewijzigd]"
+
+msgid "[Not edited]"
+msgstr "[Niet bewerkt]"
+
+msgid "[New file]"
+msgstr "[Nieuw bestand]"
+
+msgid "[Read errors]"
+msgstr "[Leesfouten]"
+
+msgid "[readonly]"
+msgstr "[alleen-lezen]"
+
+#, c-format
+msgid "1 line --%d%%--"
+msgstr "1 regel --%d%%--"
+
+#, c-format
+msgid "%ld lines --%d%%--"
+msgstr "%ld regels --%d%%--"
+
+#, c-format
+msgid "line %ld of %ld --%d%%-- col "
+msgstr "regel %ld van %ld --%d%%-- kol "
+
+msgid "[No Name]"
+msgstr "[Geen naam]"
+
+#. must be a help buffer
+msgid "help"
+msgstr "hulp"
+
+msgid "[Help]"
+msgstr "[Hulp]"
+
+msgid "[Preview]"
+msgstr "[Voorvertoning]"
+
+msgid "All"
+msgstr "Alles"
+
+msgid "Bot"
+msgstr "Bodem"
+
+msgid "Top"
+msgstr "Top"
+
+#, c-format
+msgid ""
+"\n"
+"# Buffer list:\n"
+msgstr ""
+"\n"
+"# Bufferlijst:\n"
+
+msgid "[Location List]"
+msgstr "[Locatielijst]"
+
+msgid "[Quickfix list]"
+msgstr "[Quickfix-lijst]"
+
+msgid "[Scratch]"
+msgstr "[Klad]"
+
+msgid ""
+"\n"
+"--- Signs ---"
+msgstr ""
+"\n"
+"--- Tekens ---"
+
+#, c-format
+msgid "Signs for %s:"
+msgstr "Tekens voor %s:"
+
+#, c-format
+msgid " line=%ld id=%d name=%s"
+msgstr " regel=%ld id=%d naam=%s"
+
+#, c-format
+msgid "E96: Can not diff more than %ld buffers"
+msgstr "E96: kan niet meer dan %ld buffers vergelijken"
+
+msgid "E810: Cannot read or write temp files"
+msgstr "E810: kan tijdelijke bestand niet lezen of opslaan"
+
+msgid "E97: Cannot create diffs"
+msgstr "E97: kan geen verschillen genereren"
+
+msgid "Patch file"
+msgstr "Patch-bestand"
+
+msgid "E816: Cannot read patch output"
+msgstr "E816: kan patch-uitvoer niet lezen"
+
+msgid "E98: Cannot read diff output"
+msgstr "E98: kan diff-uitvoer niet lezen"
+
+msgid "E99: Current buffer is not in diff mode"
+msgstr "E99: huidige buffer is niet in diff-modus"
+
+msgid "E793: No other buffer in diff mode is modifiable"
+msgstr "E793: geen ander buffer in diff-modus is bewerkbaar"
+
+msgid "E100: No other buffer in diff mode"
+msgstr "E100: geen ander buffer in diff-modus"
+
+msgid "E101: More than two buffers in diff mode, don't know which one to use"
+msgstr "E101: meer dan twee buffers in diff-modus, weet niet welke gebruikt moet worden"
+
+#, c-format
+msgid "E102: Can't find buffer \"%s\""
+msgstr "E102: kan buffer \"%s\" niet vinden"
+
+#, c-format
+msgid "E103: Buffer \"%s\" is not in diff mode"
+msgstr "E103: buffer \"%s\" is niet in diff-modus"
+
+msgid "E787: Buffer changed unexpectedly"
+msgstr "E787: buffer is onverwacht gewijzigd"
+
+msgid "E104: Escape not allowed in digraph"
+msgstr "E104: Escape in digraph niet toegestaan"
+
+msgid "E544: Keymap file not found"
+msgstr "E544: bestand met toetsbindingen niet gevonden"
+
+msgid "E105: Using :loadkeymap not in a sourced file"
+msgstr "E105: Gebruik van :loadkeymap niet in een 'sourced' bestand"
+
+msgid "E791: Empty keymap entry"
+msgstr "E791: toetsbinding leeg"
+
+msgid " Keyword completion (^N^P)"
+msgstr " trefwoordvoltooiing (^N^P)"
+
+#. ctrl_x_mode == 0, ^P/^N compl.
+msgid " ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+msgstr " ^X-modus (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+
+msgid " Whole line completion (^L^N^P)"
+msgstr " gehele-regelvoltooiing (^L^N^P)"
+
+msgid " File name completion (^F^N^P)"
+msgstr " bestandsnaamvoltooiing (^F^N^P)"
+
+msgid " Tag completion (^]^N^P)"
+msgstr " tag-voltooiing (^]^N^P)"
+
+msgid " Path pattern completion (^N^P)"
+msgstr " Padpatroonvoltooiing (^N^P)"
+
+msgid " Definition completion (^D^N^P)"
+msgstr " definitievoltooiiing (^D^N^P)"
+
+msgid " Dictionary completion (^K^N^P)"
+msgstr " Dictionaryvoltooiing (^K^N^P)"
+
+msgid " Thesaurus completion (^T^N^P)"
+msgstr " Thesaurusvoltooiing (^T^N^P)"
+
+msgid " Command-line completion (^V^N^P)"
+msgstr " opdrachtregelvoltooiing (^V^N^P)"
+
+msgid " User defined completion (^U^N^P)"
+msgstr " gebruikergedefinieerde voltooiing (^U^N^P)"
+
+msgid " Omni completion (^O^N^P)"
+msgstr " omni-voltooiing (^O^N^P)"
+
+msgid " Spelling suggestion (s^N^P)"
+msgstr " spellingsuggestie (s^N^P)"
+
+msgid " Keyword Local completion (^N^P)"
+msgstr " lokaal-trefwoordvoltooiing (^N^P)"
+
+msgid "Hit end of paragraph"
+msgstr "Einde van paragraaf"
+
+msgid "'dictionary' option is empty"
+msgstr "'Dictionary'-optie is leeg"
+
+msgid "'thesaurus' option is empty"
+msgstr "'thesaurus'-optie is leeg"
+
+#, c-format
+msgid "Scanning dictionary: %s"
+msgstr "Doorzoeken Dictionary: %s"
+
+msgid " (insert) Scroll (^E/^Y)"
+msgstr " (invoegen) scroll (^E/^Y)"
+
+msgid " (replace) Scroll (^E/^Y)"
+msgstr " (vervangen) scroll (^E/^Y)"
+
+#, c-format
+msgid "Scanning: %s"
+msgstr "doorzoeken: %s"
+
+msgid "Scanning tags."
+msgstr "Doorzoeken tags."
+
+msgid " Adding"
+msgstr " toevoegen"
+
+#. showmode might reset the internal line pointers, so it must
+#. * be called before line = ml_get(), or when this address is no
+#. * longer needed. -- Acevedo.
+#.
+msgid "-- Searching..."
+msgstr "-- doorzoeken..."
+
+msgid "Back at original"
+msgstr "Terug naar origineel"
+
+msgid "Word from other line"
+msgstr "Woord uit andere regel"
+
+msgid "The only match"
+msgstr "Het enige resultaat"
+
+#, c-format
+msgid "match %d of %d"
+msgstr "resultaat %d van %d"
+
+#, c-format
+msgid "match %d"
+msgstr "resultaat %d"
+
+msgid "E18: Unexpected characters in :let"
+msgstr "E18: onverwachte tekens in :let"
+
+#, c-format
+msgid "E684: list index out of range: %ld"
+msgstr "E684: lijstindex buiten bereik: %ld"
+
+#, c-format
+msgid "E121: Undefined variable: %s"
+msgstr "E121: ongedefinieerde variabele: %s"
+
+msgid "E111: Missing ']'"
+msgstr "E111: ontbrekende ']'"
+
+#, c-format
+msgid "E686: Argument of %s must be a List"
+msgstr "E686: argument van %s moet een List zijn"
+
+#, c-format
+msgid "E712: Argument of %s must be a List or Dictionary"
+msgstr "E712: argument van %s moet een List of Dictionary zijn"
+
+msgid "E713: Cannot use empty key for Dictionary"
+msgstr "E713: kan geen leeg trefwoord als Dictionary gebruiken"
+
+msgid "E714: List required"
+msgstr "E714: List is vereist"
+
+msgid "E715: Dictionary required"
+msgstr "E715: Dictionary is vereist"
+
+#, c-format
+msgid "E118: Too many arguments for function: %s"
+msgstr "E118: te veel argumenten voor functie: %s"
+
+#, c-format
+msgid "E716: Key not present in Dictionary: %s"
+msgstr "E716: trefwoord niet aangetroffen in Dictionary: %s"
+
+#, c-format
+msgid "E122: Function %s already exists, add ! to replace it"
+msgstr "E122: function %s bestaat reeds, voeg ! toe om te vervangen"
+
+msgid "E717: Dictionary entry already exists"
+msgstr "E717: woord bestaat al in Dictionary"
+
+msgid "E718: Funcref required"
+msgstr "E718: Funcref is vereist"
+
+msgid "E719: Cannot use [:] with a Dictionary"
+msgstr "E719: kan [:] niet met een Dictionary gebruiken"
+
+#, c-format
+msgid "E734: Wrong variable type for %s="
+msgstr "E734: onjuist type variabele voor %s="
+
+#, c-format
+msgid "E130: Unknown function: %s"
+msgstr "E130: onbekende functie: %s"
+
+#, c-format
+msgid "E461: Illegal variable name: %s"
+msgstr "E461: ongeldige variabelenaam: %s"
+
+msgid "E687: Less targets than List items"
+msgstr "E687: minder doelen dan Listitems"
+
+msgid "E688: More targets than List items"
+msgstr "E688: meer doelen dan Listitems"
+
+msgid "Double ; in list of variables"
+msgstr "Dubbele ; in variabelenlijst"
+
+#, c-format
+msgid "E738: Can't list variables for %s"
+msgstr "E738: kan variabelen voor %s niet tonen"
+
+msgid "E689: Can only index a List or Dictionary"
+msgstr "E689: alleen een List of Dictionary kan geïndexeerd worden"
+
+msgid "E708: [:] must come last"
+msgstr "E708: [:] moet als laatste staan"
+
+msgid "E709: [:] requires a List value"
+msgstr "E709: [:] vereist een Listwaarde"
+
+msgid "E710: List value has more items than target"
+msgstr "E710: Listwaarde heeft meer value has more items than target"
+
+msgid "E711: List value has not enough items"
+msgstr "E711: Listwaarde heeft onvoldoende items"
+
+msgid "E690: Missing \"in\" after :for"
+msgstr "E690: \"in\" ontbreekt na :for"
+
+#, c-format
+msgid "E107: Missing parentheses: %s"
+msgstr "E107: ontbrekende haakjes: %s"
+
+#, c-format
+msgid "E108: No such variable: \"%s\""
+msgstr "E108: onbekende variabele: \"%s\""
+
+msgid "E743: variable nested too deep for (un)lock"
+msgstr "E743: variabele is te diep genest om te beveiligen"
+
+msgid "E109: Missing ':' after '?'"
+msgstr "E109: ':' ontbreekt na '?'"
+
+msgid "E691: Can only compare List with List"
+msgstr "E691: List kan alleen met een Lijst worden vergeleken"
+
+msgid "E692: Invalid operation for List"
+msgstr "E692: ongeldige bewerking voor List"
+
+msgid "E735: Can only compare Dictionary with Dictionary"
+msgstr "E735: Dictionary kan alleen met Woordenboek worden vergeleken"
+
+msgid "E736: Invalid operation for Dictionary"
+msgstr "E736: ongeldige bewerking voor Dictionary"
+
+msgid "E693: Can only compare Funcref with Funcref"
+msgstr "E693: Funcref kan alleen met Funcref worden vergeleken"
+
+msgid "E694: Invalid operation for Funcrefs"
+msgstr "E694: ongeldige bewerking voor Funcrefs"
+
+msgid "E804: Cannot use '%' with Float"
+msgstr "E804: '%' kan niet met Float worden gebruikt"
+
+msgid "E110: Missing ')'"
+msgstr "E110: ')' ontbreekt"
+
+msgid "E695: Cannot index a Funcref"
+msgstr "E695: een Funcref kan niet geïndexeerd worden"
+
+#, c-format
+msgid "E112: Option name missing: %s"
+msgstr "E112: optienaam ontbreekt: %s"
+
+#, c-format
+msgid "E113: Unknown option: %s"
+msgstr "E113: onbekende optie: %s"
+
+#, c-format
+msgid "E114: Missing quote: %s"
+msgstr "E114: ontbrekend aanhaalteken: %s"
+
+#, c-format
+msgid "E115: Missing quote: %s"
+msgstr "E115: ontbrekend aanhaalteken: %s"
+
+#, c-format
+msgid "E696: Missing comma in List: %s"
+msgstr "E696: komma ontbreekt in List: %s"
+
+#, c-format
+msgid "E697: Missing end of List ']': %s"
+msgstr "E697: einde van List ']' ontbreekt: %s"
+
+#, c-format
+msgid "E720: Missing colon in Dictionary: %s"
+msgstr "E720: dubbelepunt in Dictionary ontbreekt: %s"
+
+#, c-format
+msgid "E721: Duplicate key in Dictionary: \"%s\""
+msgstr "E721: dubbele sleutel in Dictionary: \"%s\""
+
+#, c-format
+msgid "E722: Missing comma in Dictionary: %s"
+msgstr "E722: komma ontbreekt in Dictionary: %s"
+
+#, c-format
+msgid "E723: Missing end of Dictionary '}': %s"
+msgstr "E723: einde van Dictionary '}' ontbreekt: %s"
+
+msgid "E724: variable nested too deep for displaying"
+msgstr "E724: variabele is te diep genest om te tonen"
+
+#, c-format
+msgid "E740: Too many arguments for function %s"
+msgstr "E740: teveel argumenten voor functie %s"
+
+#, c-format
+msgid "E116: Invalid arguments for function %s"
+msgstr "E116: ongeldige argumenten voor functie %s"
+
+#, c-format
+msgid "E117: Unknown function: %s"
+msgstr "E117: onbekende functie: %s"
+
+#, c-format
+msgid "E119: Not enough arguments for function: %s"
+msgstr "E119: onvoldoende argumenten voor functie: %s"
+
+#, c-format
+msgid "E120: Using <SID> not in a script context: %s"
+msgstr "E120: gebruik van <SID> buiten een scriptcontext: %s"
+
+#, c-format
+msgid "E725: Calling dict function without Dictionary: %s"
+msgstr "E725: dict-functie aanroep zonder Dictionary: %s"
+
+msgid "E808: Number or Float required"
+msgstr "E808: Number of Float vereist"
+
+msgid "E699: Too many arguments"
+msgstr "E699:teveel argumenten"
+
+msgid "E785: complete() can only be used in Insert mode"
+msgstr "E785: complete() kan alleen in Invoegmodus worden gebruikt"
+
+#.
+#. * Yes this is ugly, I don't particularly like it either. But doing it
+#. * this way has the compelling advantage that translations need not to
+#. * be touched at all. See below what 'ok' and 'ync' are used for.
+#.
+msgid "&Ok"
+msgstr "&Ok"
+
+#, c-format
+msgid "E737: Key already exists: %s"
+msgstr "E737: sleutel bestaat al: %s"
+
+#, c-format
+msgid "+-%s%3ld lines: "
+msgstr "+-%s%3ld regels: "
+
+#, c-format
+msgid "E700: Unknown function: %s"
+msgstr "E700: onbekende functie: %s"
+
+msgid ""
+"&OK\n"
+"&Cancel"
+msgstr ""
+"&OK\n"
+"&Annuleren"
+
+msgid "called inputrestore() more often than inputsave()"
+msgstr "inputrestore() vaker aangeroepen dan inputsave()"
+
+msgid "E786: Range not allowed"
+msgstr "E786: bereik niet toegestaan"
+
+msgid "E701: Invalid type for len()"
+msgstr "E701: ongeldig type voor len()"
+
+msgid "E726: Stride is zero"
+msgstr "E726: stap is nul"
+
+msgid "E727: Start past end"
+msgstr "E727: start na einde"
+
+msgid "<empty>"
+msgstr "<leeg>"
+
+msgid "E240: No connection to Vim server"
+msgstr "E240: geen verbinding met Vim-server"
+
+#, c-format
+msgid "E241: Unable to send to %s"
+msgstr "E241: verzenden naar %s onmogelijk"
+
+msgid "E277: Unable to read a server reply"
+msgstr "E277: lezen van serverantwoord onmogelijk"
+
+msgid "E655: Too many symbolic links (cycle?)"
+msgstr "E655: teveel symbolische koppelingen (oneindige lus?)"
+
+msgid "E258: Unable to send to client"
+msgstr "E258: verzenden nar client onmogelijk"
+
+msgid "E702: Sort compare function failed"
+msgstr "E702: sorteer-vergelijkfunctie mislukt"
+
+msgid "(Invalid)"
+msgstr "(ongeldig)"
+
+msgid "E677: Error writing temp file"
+msgstr "E677: opslaan van temp-bestand is mislukt"
+
+msgid "E805: Using a Float as a Number"
+msgstr "E805: een Float wordt als Number gebruikt"
+
+msgid "E703: Using a Funcref as a Number"
+msgstr "E703: een Funcref wordt als Number gebruikt"
+
+msgid "E745: Using a List as a Number"
+msgstr "E745: List wordt als een Number gebruikt"
+
+msgid "E728: Using a Dictionary as a Number"
+msgstr "E728: Dictionary gebruiken als een Number"
+
+msgid "E729: using Funcref as a String"
+msgstr "E729: Funcref gebruiken als een String"
+
+msgid "E730: using List as a String"
+msgstr "E730: List gebruiken als een String"
+
+msgid "E731: using Dictionary as a String"
+msgstr "E731: Dictionary gebruiken als een String"
+
+msgid "E806: using Float as a String"
+msgstr "E806: Float gebruiken als een String"
+
+#, c-format
+msgid "E704: Funcref variable name must start with a capital: %s"
+msgstr "E704: variabelenaam van Funcref moet beginnen met een hoofdletter: %s"
+
+#, c-format
+msgid "E705: Variable name conflicts with existing function: %s"
+msgstr "E705: variablenaam botst met bestaande functie: %s"
+
+#, c-format
+msgid "E706: Variable type mismatch for: %s"
+msgstr "E706: variabelesoort past niet bij: %s"
+
+#, c-format
+msgid "E795: Cannot delete variable %s"
+msgstr "E795: kan variabele %s niet verwijderen"
+
+#, c-format
+msgid "E741: Value is locked: %s"
+msgstr "E741: waarde is geblokkeerd: %s"
+
+msgid "Unknown"
+msgstr "Onbekend"
+
+#, c-format
+msgid "E742: Cannot change value of %s"
+msgstr "E742: kan waarde van %s niet veranderen"
+
+msgid "E698: variable nested too deep for making a copy"
+msgstr "E698: variabele te diep genest om een kopie te maken"
+
+#, c-format
+msgid "E123: Undefined function: %s"
+msgstr "E123: ongedefinieerde functie: %s"
+
+#, c-format
+msgid "E124: Missing '(': %s"
+msgstr "E124: ontbrekende '(': %s"
+
+#, c-format
+msgid "E125: Illegal argument: %s"
+msgstr "E125: ongeldig argument: %s"
+
+msgid "E126: Missing :endfunction"
+msgstr "E126: ontbrekende :endfunction"
+
+#, c-format
+msgid "E707: Function name conflicts with variable: %s"
+msgstr "E707: functienaam botst met variabele: %s"
+
+#, c-format
+msgid "E127: Cannot redefine function %s: It is in use"
+msgstr "E127: kan functie %s niet opnieuw definiëren, het is in gebruik"
+
+#, c-format
+msgid "E746: Function name does not match script file name: %s"
+msgstr "E746: functienaam komt niet overeen met bestandsnaam van het script: %s"
+
+msgid "E129: Function name required"
+msgstr "E129: functienaam is vereist"
+
+#, c-format
+msgid "E128: Function name must start with a capital or contain a colon: %s"
+msgstr "E128: functionnaam moet met een hoofdletter beginnen of een dubbelepunt bevatten: %s"
+
+#, c-format
+msgid "E131: Cannot delete function %s: It is in use"
+msgstr "E131: functie %s wordt gebruikt en kan niet worden verwijderd"
+
+msgid "E132: Function call depth is higher than 'maxfuncdepth'"
+msgstr "E132: diepte functieaanroep overstijgt 'maxfuncdepth'"
+
+#, c-format
+msgid "calling %s"
+msgstr "%s aanroepen"
+
+#, c-format
+msgid "%s aborted"
+msgstr "%s afgebroken"
+
+#, c-format
+msgid "%s returning #%ld"
+msgstr "%s komt terug met de waarde #%ld"
+
+#, c-format
+msgid "%s returning %s"
+msgstr "%s komt terug met de waarde %s"
+
+#, c-format
+msgid "continuing in %s"
+msgstr "voortzetten in %s"
+
+msgid "E133: :return not inside a function"
+msgstr "E133: :return niet binnen een functie"
+
+msgid ""
+"\n"
+"# global variables:\n"
+msgstr ""
+"\n"
+"# globale variabelen:\n"
+
+msgid ""
+"\n"
+"\tLast set from "
+msgstr ""
+"\n"
+"\tLaatst ingesteld door "
+
+msgid "No old files"
+msgstr "Geen oudere bestanden"
+
+#, c-format
+msgid "<%s>%s%s %d, Hex %02x, Octal %03o"
+msgstr "<%s>%s%s %d, Hex %02x, Octal %03o"
+
+#, c-format
+msgid "> %d, Hex %04x, Octal %o"
+msgstr "> %d, Hex %04x, Octal %o"
+
+#, c-format
+msgid "> %d, Hex %08x, Octal %o"
+msgstr "> %d, Hex %08x, Octal %o"
+
+msgid "E134: Move lines into themselves"
+msgstr "E134: verplaats regels in zichzelf"
+
+msgid "1 line moved"
+msgstr "1 regel verplaatst"
+
+#, c-format
+msgid "%ld lines moved"
+msgstr "%ld regels verplaatst"
+
+#, c-format
+msgid "%ld lines filtered"
+msgstr "%ld regels gefilterd"
+
+msgid "E135: *Filter* Autocommands must not change current buffer"
+msgstr "E135: *Filter* Autocommands mogen huidige buffer niet wijzigen"
+
+msgid "[No write since last change]\n"
+msgstr "[Niets opgeslagen sinds laatste wijziging]\n"
+
+#, c-format
+msgid "%sviminfo: %s in line: "
+msgstr "%sviminfo: %s in regel: "
+
+msgid "E136: viminfo: Too many errors, skipping rest of file"
+msgstr "E136: viminfo: teveel fouten, restand van bestand overgeslagen"
+
+#, c-format
+msgid "Reading viminfo file \"%s\"%s%s%s"
+msgstr "Inlezen viminfo-bestand \"%s\"%s%s%s"
+
+msgid " info"
+msgstr " info"
+
+msgid " marks"
+msgstr " markering"
+
+msgid " oldfiles"
+msgstr " oud-bestanden"
+
+msgid " FAILED"
+msgstr " MISLUKT"
+
+#. avoid a wait_return for this message, it's annoying
+#, c-format
+msgid "E137: Viminfo file is not writable: %s"
+msgstr "E137: viminfo-bestand is niet schrijfbaar: %s"
+
+#, c-format
+msgid "E138: Can't write viminfo file %s!"
+msgstr "E138: kan niet naar viminfo-bestand %s schrijven!"
+
+#, c-format
+msgid "Writing viminfo file \"%s\""
+msgstr "viminfo-bestand \"%s\" opslaan"
+
+#. Write the info:
+#, c-format
+msgid "# This viminfo file was generated by Vim %s.\n"
+msgstr "# Dit viminfo-bestand is aangemaakt door Vim %s.\n"
+
+#, c-format
+msgid ""
+"# You may edit it if you're careful!\n"
+"\n"
+msgstr ""
+"# Bewerken is toegestaan, maar doe het met aandacht!\n"
+"\n"
+
+#, c-format
+msgid "# Value of 'encoding' when this file was written\n"
+msgstr "# Waarde van 'encoding' bij het opslaan van dit bestand\n"
+
+msgid "Illegal starting char"
+msgstr "Ongeldig startteken"
+
+msgid "Save As"
+msgstr "Opslaan als"
+
+msgid "Write partial file?"
+msgstr "Gedeeltelijk bestand opslaan?"
+
+msgid "E140: Use ! to write partial buffer"
+msgstr "E140: gebruik ! om gedeeltelijk buffer op te slaan"
+
+#, c-format
+msgid "Overwrite existing file \"%s\"?"
+msgstr "Bestaand bestand \"%s\" overschrijven?"
+
+#, c-format
+msgid "Swap file \"%s\" exists, overwrite anyway?"
+msgstr "Wisselbestand \"%s\" bestaat, toch overschrijven?"
+
+#, c-format
+msgid "E768: Swap file exists: %s (:silent! overrides)"
+msgstr "E768: wisselbestand bestaat: %s (:silent! overschrijft)"
+
+#, c-format
+msgid "E141: No file name for buffer %ld"
+msgstr "E141: buffer %ld heeft geen bestandsnaam"
+
+msgid "E142: File not written: Writing is disabled by 'write' option"
+msgstr "E142: bestand is niet opgeslagen: opslaan is uitgeschakeld door 'write'-optie"
+
+#, c-format
+msgid ""
+"'readonly' option is set for \"%s\".\n"
+"Do you wish to write anyway?"
+msgstr ""
+"'alleen-lezen'-optie is inschakeld voor \"%s\".\n"
+"Toch opslaan?"
+
+#, c-format
+msgid ""
+"File permissions of \"%s\" are read-only.\n"
+"It may still be possible to write it.\n"
+"Do you wish to try?"
+msgstr ""
+"Bestandsrechten van \"%s\" zijn alleen-lezen.\n"
+"Mogelijk kan er toch naar weggeschreven worden.\n"
+"Proberen op te slaan?"
+
+#, c-format
+msgid "E505: \"%s\" is read-only (add ! to override)"
+msgstr "E505: \"%s\" is alleen-lezen (voeg ! toe om te overschrijven)"
+
+msgid "Edit File"
+msgstr "Bestand bewerken"
+
+#, c-format
+msgid "E143: Autocommands unexpectedly deleted new buffer %s"
+msgstr "E143: 'Autocommands' hebben het nieuwe buffer %s onverwacht verwijderd"
+
+msgid "E144: non-numeric argument to :z"
+msgstr "E144: niet-numeriek argument voor :z"
+
+msgid "E145: Shell commands not allowed in rvim"
+msgstr "E145: in rvim zijn shell-opdrachten zijn niet toegestaan"
+
+msgid "E146: Regular expressions can't be delimited by letters"
+msgstr "E146: reguliere expressies kunnen niet begrensd worden door letters"
+
+#, c-format
+msgid "replace with %s (y/n/a/q/l/^E/^Y)?"
+msgstr "vervang door %s (y/n/a/q/l/^E/^Y)?"
+
+msgid "(Interrupted) "
+msgstr "(Onderbroken) "
+
+msgid "1 match"
+msgstr "1 overeenkomst"
+
+msgid "1 substitution"
+msgstr "1 vervanging"
+
+#, c-format
+msgid "%ld matches"
+msgstr "%ld overeenkomsten"
+
+#, c-format
+msgid "%ld substitutions"
+msgstr "%ld vervangingen"
+
+msgid " on 1 line"
+msgstr " op 1 regel"
+
+#, c-format
+msgid " on %ld lines"
+msgstr " op %ld regels"
+
+msgid "E147: Cannot do :global recursive"
+msgstr "E147: kan :global niet recursief uitvoeren"
+
+msgid "E148: Regular expression missing from global"
+msgstr "E148: reguliere expressies ontbreken bij global"
+
+#, c-format
+msgid "Pattern found in every line: %s"
+msgstr "Patroon aangetroffen in iedere regel: %s"
+
+#, c-format
+msgid ""
+"\n"
+"# Last Substitute String:\n"
+"$"
+msgstr ""
+"\n"
+"# Laatst vervangingsstring:\n"
+"$"
+
+msgid "E478: Don't panic!"
+msgstr "E478: geen paniek!"
+
+#, c-format
+msgid "E661: Sorry, no '%s' help for %s"
+msgstr "E661: helaas, geen '%s'-hulp voor %s"
+
+#, c-format
+msgid "E149: Sorry, no help for %s"
+msgstr "E149: helaas, geen hulp voor %s"
+
+#, c-format
+msgid "Sorry, help file \"%s\" not found"
+msgstr "helaas, hulpbestand \"%s\" is niet gevonden"
+
+#, c-format
+msgid "E150: Not a directory: %s"
+msgstr "E150: geen map: %s"
+
+#, c-format
+msgid "E152: Cannot open %s for writing"
+msgstr "E152: kan %s niet openen om naar te schrijven"
+
+#, c-format
+msgid "E153: Unable to open %s for reading"
+msgstr "E153: kan %s niet openen om uit te lezen"
+
+#, c-format
+msgid "E670: Mix of help file encodings within a language: %s"
+msgstr "E670: mengelmoes van hulpbestandcoderingen binnen een taal: %s"
+
+#, c-format
+msgid "E154: Duplicate tag \"%s\" in file %s/%s"
+msgstr "E154: dubbele tag \"%s\" in bestand %s/%s"
+
+#, c-format
+msgid "E160: Unknown sign command: %s"
+msgstr "E160: onbekende opdracht voor margetekens: %s"
+
+msgid "E156: Missing sign name"
+msgstr "E156: ontbrekende naam margeteken"
+
+msgid "E612: Too many signs defined"
+msgstr "E612: teveel margetekens gedefinieerd"
+
+#, c-format
+msgid "E239: Invalid sign text: %s"
+msgstr "E239: ongeldige tekst margeteken: %s"
+
+#, c-format
+msgid "E155: Unknown sign: %s"
+msgstr "E155: onbekend margeteken: %s"
+
+msgid "E159: Missing sign number"
+msgstr "E159: ontbrekend nummer margeteken"
+
+#, c-format
+msgid "E158: Invalid buffer name: %s"
+msgstr "E158: ongeldige buffernaam: %s"
+
+#, c-format
+msgid "E157: Invalid sign ID: %ld"
+msgstr "E157: ongeldige id margeteken: %ld"
+
+msgid " (NOT FOUND)"
+msgstr " (NIET GEVONDEN)"
+
+msgid " (not supported)"
+msgstr "(niet ondersteund)"
+
+msgid "[Deleted]"
+msgstr "[Verwijderd]"
+
+msgid "Entering Debug mode. Type \"cont\" to continue."
+msgstr "Debug-modus gestart. Typ \"cont\" om verder te gaan."
+
+#, c-format
+msgid "line %ld: %s"
+msgstr "regel %ld: %s"
+
+#, c-format
+msgid "cmd: %s"
+msgstr "cmd: %s"
+
+#, c-format
+msgid "Breakpoint in \"%s%s\" line %ld"
+msgstr "'Breakpoint' in \"%s%s\" regel %ld"
+
+#, c-format
+msgid "E161: Breakpoint not found: %s"
+msgstr "E161: 'Breakpoint' niet gevonden: %s"
+
+msgid "No breakpoints defined"
+msgstr "Geen 'breakpoints' opgegeven"
+
+#, c-format
+msgid "%3d %s %s line %ld"
+msgstr "%3d %s %s regel %ld"
+
+msgid "E750: First use \":profile start {fname}\""
+msgstr "E750: gebruik eerst \":profile start {fname}\""
+
+#, c-format
+msgid "Save changes to \"%s\"?"
+msgstr "veranderingen opslaan in \"%s\"?"
+
+msgid "Untitled"
+msgstr "naamloos"
+
+#, c-format
+msgid "E162: No write since last change for buffer \"%s\""
+msgstr "E162: niets opgeslagen sinds laatste wijziging van buffer \"%s\""
+
+msgid "Warning: Entered other buffer unexpectedly (check autocommands)"
+msgstr "Waarschuwing: onverwacht ander buffer binnengegaan (controleer 'autocommands')"
+
+msgid "E163: There is only one file to edit"
+msgstr "E163: slechts een bestand beschikbaar voor bewerking"
+
+msgid "E164: Cannot go before first file"
+msgstr "E164: kan niet verder terug dan eerste bestand"
+
+msgid "E165: Cannot go beyond last file"
+msgstr "E165: kan niet verder dan laatste bestand"
+
+#, c-format
+msgid "E666: compiler not supported: %s"
+msgstr "E666: compiler niet ondersteund: %s"
+
+#, c-format
+msgid "Searching for \"%s\" in \"%s\""
+msgstr "Naar \"%s\" in \"%s\" zoeken"
+
+#, c-format
+msgid "Searching for \"%s\""
+msgstr "Naar \"%s\" zoeken"
+
+#, c-format
+msgid "not found in 'runtimepath': \"%s\""
+msgstr "niet gevonden in 'runtimepath': \"%s\""
+
+msgid "Source Vim script"
+msgstr "Vim-script laden"
+
+#, c-format
+msgid "Cannot source a directory: \"%s\""
+msgstr "kan geen map laden: \"%s\""
+
+#, c-format
+msgid "could not source \"%s\""
+msgstr "kan \"%s\" niet laden"
+
+#, c-format
+msgid "line %ld: could not source \"%s\""
+msgstr "regel %ld: kan \"%s\" niet laden"
+
+#, c-format
+msgid "sourcing \"%s\""
+msgstr "\"%s\" laden"
+
+#, c-format
+msgid "line %ld: sourcing \"%s\""
+msgstr "regel %ld: \"%s\" laden"
+
+#, c-format
+msgid "finished sourcing %s"
+msgstr "laden van %s afgerond"
+
+msgid "modeline"
+msgstr "modusregel"
+
+msgid "--cmd argument"
+msgstr "argument van --cmd"
+
+msgid "-c argument"
+msgstr "argument van -c"
+
+msgid "environment variable"
+msgstr "omgevingsvariabele"
+
+msgid "error handler"
+msgstr "foutafhandeling"
+
+msgid "W15: Warning: Wrong line separator, ^M may be missing"
+msgstr "W15: waarschuwing: ongeldige regelscheiding, ^M kan ontbreken"
+
+msgid "E167: :scriptencoding used outside of a sourced file"
+msgstr "E167: :scriptencoding buiten een geladen bestand gebruikt"
+
+msgid "E168: :finish used outside of a sourced file"
+msgstr "E168: :finish buiten een geladen bestand gebruikt"
+
+#, c-format
+msgid "Current %slanguage: \"%s\""
+msgstr "Huidige %s-taal: \"%s\""
+
+#, c-format
+msgid "E197: Cannot set language to \"%s\""
+msgstr "E197: taal kan niet ingesteld worden op \"%s\""
+
+msgid "Entering Ex mode. Type \"visual\" to go to Normal mode."
+msgstr "Ex-modus betreden. Typ \"visual\" om naar de Normaal-modus te gaan."
+
+msgid "E501: At end-of-file"
+msgstr "E501: bij bestandseinde"
+
+msgid "E169: Command too recursive"
+msgstr "E169: opdracht te recursief"
+
+#, c-format
+msgid "E605: Exception not caught: %s"
+msgstr "E605: uitzondering niet afgevangen: %s"
+
+msgid "End of sourced file"
+msgstr "Einde van geladen bestand"
+
+msgid "End of function"
+msgstr "Einde van functie"
+
+msgid "E464: Ambiguous use of user-defined command"
+msgstr "E464: dubbelzinnig gebruik van gebruikergedefinieerde opdracht"
+
+msgid "E492: Not an editor command"
+msgstr "E492: geen editor-opdracht"
+
+msgid "E493: Backwards range given"
+msgstr "E493: Teruggaand bereik opgegeven"
+
+msgid "Backwards range given, OK to swap"
+msgstr "Teruggaand bereik opgegeven, wisselen is toegestaan"
+
+msgid "E494: Use w or w>>"
+msgstr "E494: w of w>> gebruiken"
+
+msgid "E319: Sorry, the command is not available in this version"
+msgstr "E319: Helaas, in deze versie is de opdracht niet beschikbaar"
+
+msgid "E172: Only one file name allowed"
+msgstr "E172: slechts een bestandsnaam toegestaan"
+
+msgid "1 more file to edit. Quit anyway?"
+msgstr "1 bestand wacht nog op bewerking. Toch stoppen?"
+
+#, c-format
+msgid "%d more files to edit. Quit anyway?"
+msgstr "%d bestanden wachten nog op bewerking. Toch stoppen?"
+
+msgid "E173: 1 more file to edit"
+msgstr "E173: 1 bestand wacht op bewerking"
+
+#, c-format
+msgid "E173: %ld more files to edit"
+msgstr "E173: %ld bestanden wachten op bewerking"
+
+msgid "E174: Command already exists: add ! to replace it"
+msgstr "E174: opdracht bestaat al: voeg ! toe om het te vervangen"
+
+msgid ""
+"\n"
+" Name Args Range Complete Definition"
+msgstr ""
+"\n"
+" Naam Args Berk. Compleet Definitie"
+
+msgid "No user-defined commands found"
+msgstr "Geen gebruikergedefinieerde opdrachten gevonden"
+
+msgid "E175: No attribute specified"
+msgstr "E175: geen attribute opgegeven"
+
+msgid "E176: Invalid number of arguments"
+msgstr "E176: ongeldig aantal argumenten"
+
+msgid "E177: Count cannot be specified twice"
+msgstr "E177: aantal kan niet tweemaal worden opgegeven"
+
+msgid "E178: Invalid default value for count"
+msgstr "E178: ongeldige standaardwaarde voor aantal"
+
+msgid "E179: argument required for -complete"
+msgstr "E179: argument vereist voor -complete"
+
+#, c-format
+msgid "E181: Invalid attribute: %s"
+msgstr "E181: ongeldig attribute: %s"
+
+msgid "E182: Invalid command name"
+msgstr "E182: ongeldige opdrachtnaam"
+
+msgid "E183: User defined commands must start with an uppercase letter"
+msgstr "E183: door gebruiker gedefinieerde opdrachten moet een een hoofdletter beginnen"
+
+#, c-format
+msgid "E184: No such user-defined command: %s"
+msgstr "E184: deze door gebruiker gedefinieerde opdracht bestaat niet: %s"
+
+#, c-format
+msgid "E180: Invalid complete value: %s"
+msgstr "E180: ongeldige voltooiingswaarde: %s"
+
+msgid "E468: Completion argument only allowed for custom completion"
+msgstr "E468: argument voor voltooiing alleen toegestaan bij aangepaste voltooiing"
+
+msgid "E467: Custom completion requires a function argument"
+msgstr "E467: aangepaste voltooiing vereist een functieargument"
+
+msgid "unknown"
+msgstr "onbekend"
+
+#, c-format
+msgid "E185: Cannot find color scheme %s"
+msgstr "E185: kan kleurenschema %s niet vinden"
+
+msgid "Greetings, Vim user!"
+msgstr "Gegroet, Vim-gebruiker!"
+
+msgid "E784: Cannot close last tab page"
+msgstr "E784: laatste tabpagina kan niet afgesloten worden"
+
+msgid "Already only one tab page"
+msgstr "Reeds beperkt tot één tabpagina"
+
+msgid "Edit File in new window"
+msgstr "Bestand in nieuw venster bewerken"
+
+#, c-format
+msgid "Tab page %d"
+msgstr "Tabpagina %d"
+
+msgid "No swap file"
+msgstr "Geen wisselbestand"
+
+msgid "Append File"
+msgstr "Bestand toevoegen"
+
+msgid "E747: Cannot change directory, buffer is modified (add ! to override)"
+msgstr "E747: kan niet van map veranderen, buffer is gewijzigd (voeg ! toe om te forceren)"
+
+msgid "E186: No previous directory"
+msgstr "E186: geen voorgaande map"
+
+msgid "E187: Unknown"
+msgstr "E187: onbekend"
+
+msgid "E465: :winsize requires two number arguments"
+msgstr "E465: :winsize vereist twee getallen als argument"
+
+#, c-format
+msgid "Window position: X %d, Y %d"
+msgstr "Vensterpositie: X %d, Y %d"
+
+msgid "E188: Obtaining window position not implemented for this platform"
+msgstr "E188: verkrijgen van vensterpositie is voor dit platform niet geïmplementeerd"
+
+msgid "E466: :winpos requires two number arguments"
+msgstr "E466: :winpos vereist twee getallen als argument"
+
+msgid "Save Redirection"
+msgstr "'Redirection' opslaan"
+
+msgid "Save View"
+msgstr "Beeld opslaan"
+
+msgid "Save Session"
+msgstr "Sessie opslaan"
+
+msgid "Save Setup"
+msgstr "Instellingen opslaan"
+
+#, c-format
+msgid "E739: Cannot create directory: %s"
+msgstr "E739: kan map %s niet aanmaken"
+
+#, c-format
+msgid "E189: \"%s\" exists (add ! to override)"
+msgstr "E189: \"%s\" bestaat al (voeg ! toe om te forceren)"
+
+#, c-format
+msgid "E190: Cannot open \"%s\" for writing"
+msgstr "E190: \"%s\" kan niet worden beschreven"
+
+#. set mark
+msgid "E191: Argument must be a letter or forward/backward quote"
+msgstr "E191: argument moet een letter zijn of een aanhaalteken, voor of achterwaarts"
+
+msgid "E192: Recursive use of :normal too deep"
+msgstr "E192: recursief gebruik van :normal gaat te diep"
+
+msgid "E809: #< is not available without the +eval feature"
+msgstr "E809: #< is zonder de +eval-functionaliteit niet beschikbaar"
+
+msgid "E194: No alternate file name to substitute for '#'"
+msgstr "E194: er is geen wisselende bestandsnaam beschikbaar om '#' te vervangen"
+
+msgid "E495: no autocommand file name to substitute for \"<afile>\""
+msgstr "E495: er is geen 'autocommand'-bestandsnaam om \"<afile>\" te vervangen"
+
+msgid "E496: no autocommand buffer number to substitute for \"<abuf>\""
+msgstr "E496: er is geen 'autocommand'-buffernummer om \"<abuf>\" te vervangen"
+
+msgid "E497: no autocommand match name to substitute for \"<amatch>\""
+msgstr "E497: er is geen 'autocommand'-naamovereenkomst om \"<amatch>\" te vervangen"
+
+msgid "E498: no :source file name to substitute for \"<sfile>\""
+msgstr "E498: er is geen :source-bestandsnaam om \"<sfile>\" te vervangen"
+
+#, no-c-format
+msgid "E499: Empty file name for '%' or '#', only works with \":p:h\""
+msgstr "E499: lege bestandsnaam voor '%' of '#', werkt alleen samen met \":p:h\""
+
+msgid "E500: Evaluates to an empty string"
+msgstr "E500: resulteert in een lege string"
+
+msgid "E195: Cannot open viminfo file for reading"
+msgstr "E195: het 'viminfo'-bestand kan niet worden gelezen"
+
+msgid "E196: No digraphs in this version"
+msgstr "E196: deze versie bevat geen 'digraphs'"
+
+msgid "E608: Cannot :throw exceptions with 'Vim' prefix"
+msgstr "E608: :throw exceptions met 'Vim' als voorvoegsel zijn niet mogelijk"
+
+#. always scroll up, don't overwrite
+#, c-format
+msgid "Exception thrown: %s"
+msgstr "Geworpen uitzondering: %s"
+
+#, c-format
+msgid "Exception finished: %s"
+msgstr "Afgeronde uitzondering: %s"
+
+#, c-format
+msgid "Exception discarded: %s"
+msgstr "Afgedankte uitzondering: %s"
+
+#, c-format
+msgid "%s, line %ld"
+msgstr "%s, regel %ld"
+
+#. always scroll up, don't overwrite
+#, c-format
+msgid "Exception caught: %s"
+msgstr "Gevangen uitzondering: %s"
+
+#, c-format
+msgid "%s made pending"
+msgstr "%s aanhanging gemaakt"
+
+#, c-format
+msgid "%s resumed"
+msgstr "%s voortgezet"
+
+#, c-format
+msgid "%s discarded"
+msgstr "%s afgedankt"
+
+msgid "Exception"
+msgstr "Uitzondering"
+
+msgid "Error and interrupt"
+msgstr "Fout en onderbreken"
+
+msgid "Error"
+msgstr "Fout"
+
+#. if (pending & CSTP_INTERRUPT)
+msgid "Interrupt"
+msgstr "Onderbreken"
+
+msgid "E579: :if nesting too deep"
+msgstr "E579: te diepe :if-nesting"
+
+msgid "E580: :endif without :if"
+msgstr "E580: :endif zonder :if"
+
+msgid "E581: :else without :if"
+msgstr "E581: :else zonder :if"
+
+msgid "E582: :elseif without :if"
+msgstr "E582: :elseif zonder :if"
+
+msgid "E583: multiple :else"
+msgstr "E583: meerdere :else"
+
+msgid "E584: :elseif after :else"
+msgstr "E584: :elseif na :else"
+
+msgid "E585: :while/:for nesting too deep"
+msgstr "E585: te diepe :while/:for-nesting"
+
+msgid "E586: :continue without :while or :for"
+msgstr "E586: :continue zonder :while of :for"
+
+msgid "E587: :break without :while or :for"
+msgstr "E587: :break zonder :while of :for"
+
+msgid "E732: Using :endfor with :while"
+msgstr "E732: gebruik van :endfor met :while"
+
+msgid "E733: Using :endwhile with :for"
+msgstr "E733: gebruik van :endwhile met :for"
+
+msgid "E601: :try nesting too deep"
+msgstr "E601: te diepe :try-nesting"
+
+msgid "E603: :catch without :try"
+msgstr "E603: :catch zonder :try"
+
+#. Give up for a ":catch" after ":finally" and ignore it.
+#. * Just parse.
+msgid "E604: :catch after :finally"
+msgstr "E604: :catch na :finally"
+
+msgid "E606: :finally without :try"
+msgstr "E606: :finally zonder :try"
+
+#. Give up for a multiple ":finally" and ignore it.
+msgid "E607: multiple :finally"
+msgstr "E607: meerdere :finally"
+
+msgid "E602: :endtry without :try"
+msgstr "E602: :endtry zonder :try"
+
+msgid "E193: :endfunction not inside a function"
+msgstr "E193: :endfunction niet binnen een functie"
+
+msgid "E788: Not allowed to edit another buffer now"
+msgstr "E788: nu een andere buffer bewerken is niet toegestaan"
+
+msgid "E811: Not allowed to change buffer information now"
+msgstr "E811: nu bufferinformatie wijzigen is niet toegestaan"
+
+msgid "tagname"
+msgstr "tagnaam"
+
+msgid " kind file\n"
+msgstr "soor bestand\n"
+
+msgid "'history' option is zero"
+msgstr "'history'-optie is nul"
+
+#, c-format
+msgid ""
+"\n"
+"# %s History (newest to oldest):\n"
+msgstr ""
+"\n"
+"# %s Historie (jongste naar oudste):\n"
+
+msgid "Command Line"
+msgstr "Opdrachtregel"
+
+msgid "Search String"
+msgstr "Zoekstring"
+
+msgid "Expression"
+msgstr "Expressie"
+
+msgid "Input Line"
+msgstr "Invoerregel"
+
+msgid "E198: cmd_pchar beyond the command length"
+msgstr "E198: cmd_pchar is langer dan toegestaan voor een opdracht"
+
+msgid "E199: Active window or buffer deleted"
+msgstr "E199: actieve venster of buffer verwijderd"
+
+msgid "E812: Autocommands changed buffer or buffer name"
+msgstr "E812: buffer of buffernaam gewijzigd door autocommands"
+
+msgid "Illegal file name"
+msgstr "Ongeldige bestandsnaam"
+
+msgid "is a directory"
+msgstr "is een map"
+
+msgid "is not a file"
+msgstr "is geen bestand"
+
+msgid "is a device (disabled with 'opendevice' option)"
+msgstr "is een apparaat (uitgeschakeld door optie 'opendevice'"
+
+msgid "[New File]"
+msgstr "[Nieuw bestand]"
+
+msgid "[New DIRECTORY]"
+msgstr "[Nieuwe MAP]"
+
+msgid "[File too big]"
+msgstr "Bestand te groot"
+
+msgid "[Permission Denied]"
+msgstr "[Geen rechten]"
+
+msgid "E200: *ReadPre autocommands made the file unreadable"
+msgstr "E200: *ReadPre autocommands hebben het bestand niet-leesbaar gemaakt"
+
+msgid "E201: *ReadPre autocommands must not change current buffer"
+msgstr "E201: *ReadPre autocommands mogen huidige buffer niet wijzigen"
+
+msgid "Vim: Reading from stdin...\n"
+msgstr "Vim: lezen van standaardinvoer...\n"
+
+msgid "Reading from stdin..."
+msgstr "Lezen van standaardinvoer..."
+
+#. Re-opening the original file failed!
+msgid "E202: Conversion made file unreadable!"
+msgstr "E202: bestand niet-leesbaar gemaakt door conversatie"
+
+msgid "[fifo/socket]"
+msgstr "[fifo/socket]"
+
+msgid "[fifo]"
+msgstr "[fifo]"
+
+msgid "[socket]"
+msgstr "[socket]"
+
+msgid "[character special]"
+msgstr "[karakter speciaal]"
+
+msgid "[RO]"
+msgstr "[RO]"
+
+msgid "[CR missing]"
+msgstr "[CR ontbreekt]"
+
+msgid "[long lines split]"
+msgstr "[lange regels gesplitst]"
+
+msgid "[NOT converted]"
+msgstr "[NIET omgezet]"
+
+msgid "[converted]"
+msgstr "[omgezet]"
+
+msgid "[crypted]"
+msgstr "[versleuteld]"
+
+#, c-format
+msgid "[CONVERSION ERROR in line %ld]"
+msgstr "[OMZETFOUT in regel %ld]"
+
+#, c-format
+msgid "[ILLEGAL BYTE in line %ld]"
+msgstr "[ONGELDIGE BYTE in regel %ld]"
+
+msgid "[READ ERRORS]"
+msgstr "[LEESFOUTEN]"
+
+msgid "Can't find temp file for conversion"
+msgstr "Tijdelijk bestand voor conversie ontbreekt"
+
+msgid "Conversion with 'charconvert' failed"
+msgstr "Conversatie met 'charconvert' is mislukt"
+
+msgid "can't read output of 'charconvert'"
+msgstr "uitvoer van 'charconvert' kan niet worden gelezen"
+
+msgid "E821: File is encrypted with unknown method"
+msgstr "E821: bestand is met onbekende methode versleuteld"
+
+msgid "E676: No matching autocommands for acwrite buffer"
+msgstr "E676: geen overeenkomende autocommands voor 'acwrite'-buffer"
+
+msgid "E203: Autocommands deleted or unloaded buffer to be written"
+msgstr "E203: autocommands hebben buffer verwijderd of gelost die moest worden opgeslagen"
+
+msgid "E204: Autocommand changed number of lines in unexpected way"
+msgstr "E204: autocommand heeft op onverwachte wijze het aantal regels gewijzigd"
+
+msgid "NetBeans disallows writes of unmodified buffers"
+msgstr "Netbeans staat het opslaan van onveranderde buffers niet toe"
+
+msgid "Partial writes disallowed for NetBeans buffers"
+msgstr "Deelopslag voor buffers van Netbeans niet toegestaan"
+
+msgid "is not a file or writable device"
+msgstr "is geen bestand of schrijfbaar apparaat"
+
+msgid "writing to device disabled with 'opendevice' option"
+msgstr "het schrijven naar apparaat is uitgeschakeld met optie 'opendevice'"
+
+msgid "is read-only (add ! to override)"
+msgstr "is alleen-lezen (voeg ! toe om te schrijven)"
+
+msgid "E506: Can't write to backup file (add ! to override)"
+msgstr "E506: kan niet naar back-upbestand schrijven (voeg hiervoor ! toe)"
+
+msgid "E507: Close error for backup file (add ! to override)"
+msgstr "E507: fout tijdens afsluiten van back-upbestand (voeg ! om toch af te sluiten)"
+
+msgid "E508: Can't read file for backup (add ! to override)"
+msgstr "E508: kan bestand voor back-up niet lezen (voeg ! toe om toch te lezen)"
+
+msgid "E509: Cannot create backup file (add ! to override)"
+msgstr "E509: kan back-upbestand niet aanmaken (voeg ! toe om dit toch aan te maken)"
+
+msgid "E510: Can't make backup file (add ! to override)"
+msgstr "E510: kan back-upbestand niet maken (voeg ! toe om dit toch te maken)"
+
+msgid "E460: The resource fork would be lost (add ! to override)"
+msgstr "E460: de afsplitsing van middelen zou verloren gaan (voeg ! toe om dit toch te doen)"
+
+msgid "E214: Can't find temp file for writing"
+msgstr "E214: kan tijdelijk bestand voor wegschrijven niet vinden"
+
+msgid "E213: Cannot convert (add ! to write without conversion)"
+msgstr "E213: kan niet omzetten (voeg ! toe om zonder omzetting op te slaan)"
+
+msgid "E166: Can't open linked file for writing"
+msgstr "E166: kan niet schrijven naar gekoppeld bestand"
+
+msgid "E212: Can't open file for writing"
+msgstr "E212: kan niet schrijven naar bestand"
+
+msgid "E667: Fsync failed"
+msgstr "E667: fsync is mislukt"
+
+msgid "E512: Close failed"
+msgstr "E512: Afsluiten is mislukt"
+
+msgid "E513: write error, conversion failed (make 'fenc' empty to override)"
+msgstr "E513: schrijffout waarbij omzetting is mislukt (leeg 'fenc' om te overschrijven)"
+
+#, c-format
+msgid "E513: write error, conversion failed in line %ld (make 'fenc' empty to override)"
+msgstr "E513: schrijffout waarbij omzetting in regel %ld is mislukt (leeg 'fenc' om te overschrijven)"
+
+msgid "E514: write error (file system full?)"
+msgstr "E514: schrijffout (is bestandssysteem vol?)"
+
+msgid " CONVERSION ERROR"
+msgstr " OMZETTINGFOUT"
+
+#, c-format
+msgid " in line %ld;"
+msgstr " in regel %ld;"
+
+msgid "[Device]"
+msgstr "[Apparaat]"
+
+msgid "[New]"
+msgstr "[Nieuw]"
+
+msgid " [a]"
+msgstr " [a]"
+
+msgid " appended"
+msgstr " toegevoegd"
+
+msgid " [w]"
+msgstr " [w]"
+
+msgid " written"
+msgstr " opgeslagen"
+
+msgid "E205: Patchmode: can't save original file"
+msgstr "E205: patch-modus: kan oorspronkelijke bestand niet opslaan"
+
+msgid "E206: patchmode: can't touch empty original file"
+msgstr "E206: patch-modus: kan oorspronkelijk leeg bestand niet aanraken"
+
+msgid "E207: Can't delete backup file"
+msgstr "E207: back-upbestand kan niet worden verwijderd"
+
+msgid ""
+"\n"
+"WARNING: Original file may be lost or damaged\n"
+msgstr ""
+"\n"
+"WAARSCHUWING: oorspronkelijk bestand kan verloren gaan of beschadigen\n"
+
+msgid "don't quit the editor until the file is successfully written!"
+msgstr "verlaat vim niet voordat het bestand volledig opgeslagen is!"
+
+msgid "[dos]"
+msgstr "[dos]"
+
+msgid "[dos format]"
+msgstr "[dos-format]"
+
+msgid "[mac]"
+msgstr "[mac]"
+
+msgid "[mac format]"
+msgstr "[mac-format]"
+
+msgid "[unix]"
+msgstr "[unix]"
+
+msgid "[unix format]"
+msgstr "[unix-format]"
+
+msgid "1 line, "
+msgstr "1 regel, "
+
+#, c-format
+msgid "%ld lines, "
+msgstr "%ld regels, "
+
+msgid "1 character"
+msgstr "1 teken"
+
+#, c-format
+msgid "%lld characters"
+msgstr "%lld tekens"
+
+#, c-format
+msgid "%ld characters"
+msgstr "%ld tekens"
+
+msgid "[noeol]"
+msgstr "[noeol]"
+
+msgid "[Incomplete last line]"
+msgstr "[Laatste regel onvolledig]"
+
+#. don't overwrite messages here
+#. must give this prompt
+#. don't use emsg() here, don't want to flush the buffers
+msgid "WARNING: The file has been changed since reading it!!!"
+msgstr "WAARSCHUWING: het bestand is na het laden gewijzigd!!!"
+
+msgid "Do you really want to write to it"
+msgstr "Wilt u er zeker naar schrijven"
+
+#, c-format
+msgid "E208: Error writing to \"%s\""
+msgstr "E208: schrijven naar \"%s\" is mislukt"
+
+#, c-format
+msgid "E209: Error closing \"%s\""
+msgstr "E209: afsluiten van \"%s\" is mislukt"
+
+#, c-format
+msgid "E210: Error reading \"%s\""
+msgstr "E210: lezen van \"%s\" is mislukt"
+
+msgid "E246: FileChangedShell autocommand deleted buffer"
+msgstr "E246: buffer verwijderd door 'autocommand' FileChangedShell"
+
+#, c-format
+msgid "E211: File \"%s\" no longer available"
+msgstr "E211: bestand \"%s\" is niet meer beschikbaar"
+
+#, c-format
+msgid "W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as well"
+msgstr "W12: waarschuwing: bestand \"%s\" en de buffer zijn gewijzigd in Vim "
+
+msgid "See \":help W12\" for more info."
+msgstr "Lees \":help W12\" voor meer informatie."
+
+#, c-format
+msgid "W11: Warning: File \"%s\" has changed since editing started"
+msgstr "W11: waarschuwing: bestand \"%s\" is gewijzigd sinds het begin van het bewerken"
+
+msgid "See \":help W11\" for more info."
+msgstr "Lees \":help W11\" voor meer informatie."
+
+#, c-format
+msgid "W16: Warning: Mode of file \"%s\" has changed since editing started"
+msgstr "W16: waarschuwing: rechten van bestand \"%s\" zijn gewijzigd sinds het begin van het bewerken"
+
+msgid "See \":help W16\" for more info."
+msgstr "Lees \":help W16\" voor meer informatie"
+
+#, c-format
+msgid "W13: Warning: File \"%s\" has been created after editing started"
+msgstr "W13: waarschuwing: na het begin van het bewerken van bestand \"%s\" is deze ook elders aangemaakt"
+
+msgid "Warning"
+msgstr "Waarschuwing"
+
+msgid ""
+"&OK\n"
+"&Load File"
+msgstr ""
+"&OK\n"
+"Bestand &Laden"
+
+#, c-format
+msgid "E462: Could not prepare for reloading \"%s\""
+msgstr "E462: het voorbereiden van \"%s\" voor het opnieuw laden is mislukt"
+
+#, c-format
+msgid "E321: Could not reload \"%s\""
+msgstr "E321: kan \"%s\" niet opnieuw laden"
+
+msgid "--Deleted--"
+msgstr "--Verwijderd--"
+
+#, c-format
+msgid "auto-removing autocommand: %s <buffer=%d>"
+msgstr "automatisch verwijderen 'autocommand': %s <buffer=%d>"
+
+#. the group doesn't exist
+#, c-format
+msgid "E367: No such group: \"%s\""
+msgstr "E367: groep \"%s\" bestaat niet"
+
+#, c-format
+msgid "E215: Illegal character after *: %s"
+msgstr "E215: ongeldig teken na *: %s"
+
+#, c-format
+msgid "E216: No such event: %s"
+msgstr "E216: onbekend 'event': %s"
+
+#, c-format
+msgid "E216: No such group or event: %s"
+msgstr "E216: onbekende groep of 'event': %s"
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Autocommands ---"
+msgstr ""
+"\n"
+"--- Autocommands ---"
+
+#, c-format
+msgid "E680: <buffer=%d>: invalid buffer number "
+msgstr "E680: <buffer=%d>: ongeldig buffernummer "
+
+msgid "E217: Can't execute autocommands for ALL events"
+msgstr "E217: autocommands kunnen niet voor alle 'events' worden uitgevoerd"
+
+msgid "No matching autocommands"
+msgstr "Geen overeenkomstige autocommands"
+
+msgid "E218: autocommand nesting too deep"
+msgstr "E218: hierarchie van aanroepen autocommands te diep"
+
+#, c-format
+msgid "%s Autocommands for \"%s\""
+msgstr "%s 'Autocommands' voor \"%s\""
+
+#, c-format
+msgid "Executing %s"
+msgstr "%s uitvoeren"
+
+#, c-format
+msgid "autocommand %s"
+msgstr "autocommand %s"
+
+msgid "E219: Missing {."
+msgstr "E219: ontbrekende {."
+
+msgid "E220: Missing }."
+msgstr "E220: ontbrekende }."
+
+msgid "E490: No fold found"
+msgstr "E490: geen vouw gevonden"
+
+msgid "E350: Cannot create fold with current 'foldmethod'"
+msgstr "E350: kan geen vouw aanmaken met huidige 'vouwmethode'"
+
+msgid "E351: Cannot delete fold with current 'foldmethod'"
+msgstr "E351: kan geen vouw verwijderen met huidige 'vouwmethode'"
+
+#, c-format
+msgid "+--%3ld lines folded "
+msgstr "+--%3ld regels gevouwen "
+
+msgid "E222: Add to read buffer"
+msgstr "E222: aan leesbuffer toevoegen"
+
+msgid "E223: recursive mapping"
+msgstr "E223: recursieve toewijzing"
+
+#, c-format
+msgid "E224: global abbreviation already exists for %s"
+msgstr "E224: algemene afkorting bestaat al voor %s"
+
+#, c-format
+msgid "E225: global mapping already exists for %s"
+msgstr "E225: er bestaat al een algemene toewijzing voor %s"
+
+#, c-format
+msgid "E226: abbreviation already exists for %s"
+msgstr "E226: er bestaat al een afkorting voor %s"
+
+#, c-format
+msgid "E227: mapping already exists for %s"
+msgstr "E227: toewijzing bestaat al voor %s"
+
+msgid "No abbreviation found"
+msgstr "Geen afkorting gevonden"
+
+msgid "No mapping found"
+msgstr "Geen toewijzing gevonden"
+
+msgid "E228: makemap: Illegal mode"
+msgstr "E228: makemap: ongeldige modus"
+
+msgid "E229: Cannot start the GUI"
+msgstr "E229: de GUI kan niet worden gestart"
+
+#, c-format
+msgid "E230: Cannot read from \"%s\""
+msgstr "E230: kan niet gelezen worden uit \"%s\""
+
+msgid "E665: Cannot start GUI, no valid font found"
+msgstr "E665: de GUI kan niet gestart worden, er is geen geldig lettertype gevonden"
+
+msgid "E231: 'guifontwide' invalid"
+msgstr "E231: 'guifontwide' ongeldig"
+
+msgid "E599: Value of 'imactivatekey' is invalid"
+msgstr "E599: waarde van 'imactivatekey' is ongeldig"
+
+#, c-format
+msgid "E254: Cannot allocate color %s"
+msgstr "E254: kan de kleur %s niet reserveren"
+
+msgid "No match at cursor, finding next"
+msgstr "Op cursorpositie is geen overeenkomst: de volgende zoeken"
+
+msgid "<cannot open> "
+msgstr "<kan niet openen> "
+
+#, c-format
+msgid "E616: vim_SelFile: can't get font %s"
+msgstr "E616: vim_SelFile: lettertype %s niet gevonden"
+
+msgid "E614: vim_SelFile: can't return to current directory"
+msgstr "E614: vim_SelFile: teruggaan naar huidige map is niet mogelijk"
+
+msgid "Pathname:"
+msgstr "Padnaam:"
+
+msgid "E615: vim_SelFile: can't get current directory"
+msgstr "E615: vim_SelFile: vaststellen huidige map is niet mogelijk"
+
+msgid "OK"
+msgstr "Ok"
+
+msgid "Cancel"
+msgstr "Annuleren"
+
+msgid "Scrollbar Widget: Could not get geometry of thumb pixmap."
+msgstr "Scrollbar-widget: vaststellen afmetingen van miniaturenkaart niet mogelijk."
+
+msgid "Vim dialog"
+msgstr "Vim-dialoog"
+
+msgid "E232: Cannot create BalloonEval with both message and callback"
+msgstr "E232: aanmaken 'BalloonEval' met zowel een bericht als een 'callback' is niet mogelijk"
+
+msgid "Vim dialog..."
+msgstr "Vim-dialoog..."
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"&Cancel"
+msgstr ""
+"&Ja\n"
+"&Nee\n"
+"&Annuleren"
+
+msgid "Input _Methods"
+msgstr "Invoer_wijzen"
+
+msgid "VIM - Search and Replace..."
+msgstr "VIM - zoeken en vervangen..."
+
+msgid "VIM - Search..."
+msgstr "VIM - zoeken..."
+
+msgid "Find what:"
+msgstr "Zoek naar:"
+
+msgid "Replace with:"
+msgstr "Vervang door:"
+
+#. whole word only button
+msgid "Match whole word only"
+msgstr "Alleen volledig woord"
+
+#. match case button
+msgid "Match case"
+msgstr "Hoofdlettergevoelig"
+
+msgid "Direction"
+msgstr "Richting"
+
+#. 'Up' and 'Down' buttons
+msgid "Up"
+msgstr "Opwaarts"
+
+msgid "Down"
+msgstr "Neerwaarts"
+
+msgid "Find Next"
+msgstr "Volgende zoeken"
+
+msgid "Replace"
+msgstr "Vervangen"
+
+msgid "Replace All"
+msgstr "Alles vervangen"
+
+msgid "Vim: Received \"die\" request from session manager\n"
+msgstr "Vim: \"die\"-verzoek van sessiebeheerder ontvangen\n"
+
+msgid "Close"
+msgstr "Sluiten"
+
+msgid "New tab"
+msgstr "Nieuw tabblad"
+
+msgid "Open Tab..."
+msgstr "Tabblad openen..."
+
+msgid "Vim: Main window unexpectedly destroyed\n"
+msgstr "Vim: hoofdvenster onverwacht gesloten\n"
+
+msgid "Font Selection"
+msgstr "Lettertypeselectie"
+
+msgid "&Filter"
+msgstr "&Filter"
+
+msgid "&Cancel"
+msgstr "&Annuleren"
+
+msgid "Directories"
+msgstr "Mappen"
+
+msgid "Filter"
+msgstr "Filter"
+
+msgid "&Help"
+msgstr "&Hulp"
+
+msgid "Files"
+msgstr "Bestanden"
+
+msgid "&OK"
+msgstr "&Ok"
+
+msgid "Selection"
+msgstr "Selectie"
+
+msgid "Find &Next"
+msgstr "&Volgende zoeken"
+
+msgid "&Replace"
+msgstr "Ve&rvangen"
+
+msgid "Replace &All"
+msgstr "&Alles vervangen"
+
+msgid "&Undo"
+msgstr "&Herstellen"
+
+#, c-format
+msgid "E610: Can't load Zap font '%s'"
+msgstr "E610: Zap-lettertype '%s' kan niet worden geladen"
+
+#, c-format
+msgid "E611: Can't use font %s"
+msgstr "E611: lettertype %s kan niet worden gebruikt"
+
+msgid ""
+"\n"
+"Sending message to terminate child process.\n"
+msgstr ""
+"\n"
+"Bericht versturen om kindproces te beëindigen.\n"
+
+#, c-format
+msgid "E671: Cannot find window title \"%s\""
+msgstr "E671: kan venstertitel \"%s\" niet vinden"
+
+#, c-format
+msgid "E243: Argument not supported: \"-%s\"; Use the OLE version."
+msgstr "E243: argument niet ondersteund: \"-%s\"; gebruik de OLE-versie."
+
+msgid "E672: Unable to open window inside MDI application"
+msgstr "E672: kan geen venster binnen MDI-applicatie openen"
+
+msgid "Close tab"
+msgstr "Tabblad sluiten"
+
+msgid "Open tab..."
+msgstr "Tabblad openen..."
+
+msgid "Find string (use '\\\\' to find a '\\')"
+msgstr "Tekenreeks zoeken (gebruik '\\\\' om een '\\' te vinden)"
+
+msgid "Find & Replace (use '\\\\' to find a '\\')"
+msgstr "Zoeken & vervangen (gebruik '\\\\' om een '\\' te vinden')"
+
+#. We fake this: Use a filter that doesn't select anything and a default
+#. * file name that won't be used.
+msgid "Not Used"
+msgstr "Niet gebruikt"
+
+msgid "Directory\t*.nothing\n"
+msgstr "Map\t*.niets\n"
+
+msgid "Vim E458: Cannot allocate colormap entry, some colors may be incorrect"
+msgstr "E458: kan geen kleur toewijzen, sommige kleuren kunnen onjuist zijn"
+
+#, c-format
+msgid "E250: Fonts for the following charsets are missing in fontset %s:"
+msgstr "E250: lettertypen voor de volgende tekenverzamelingen ontbreken in verzameling %s:"
+
+#, c-format
+msgid "E252: Fontset name: %s"
+msgstr "E252: naam lettertypeverzameling: %s"
+
+#, c-format
+msgid "Font '%s' is not fixed-width"
+msgstr "Lettertype '%s' heeft geen vaste breedte"
+
+#, c-format
+msgid "E253: Fontset name: %s\n"
+msgstr "E253: naam lettertypeverzameling: %s\n"
+
+#, c-format
+msgid "Font0: %s\n"
+msgstr "Font0: %s\n"
+
+#, c-format
+msgid "Font1: %s\n"
+msgstr "Font1: %s\n"
+
+#, c-format
+msgid "Font%ld width is not twice that of font0\n"
+msgstr "Breedte font%ld is niet het dubbele van font0\n"
+
+#, c-format
+msgid "Font0 width: %ld\n"
+msgstr "Font0-breedte: %ld\n"
+
+#, c-format
+msgid ""
+"Font1 width: %ld\n"
+"\n"
+msgstr ""
+"Font1-breedte: %ld\n"
+"\n"
+
+msgid "Invalid font specification"
+msgstr "Onjuiste specificatie van lettertype"
+
+msgid "&Dismiss"
+msgstr "&Afwijzen"
+
+msgid "no specific match"
+msgstr "geen specifieke overeenkomst"
+
+msgid "Vim - Font Selector"
+msgstr "Vim - Lettertypekiezer"
+
+msgid "Name:"
+msgstr "Naam:"
+
+#. create toggle button
+msgid "Show size in Points"
+msgstr "Grootte in punten tonen"
+
+msgid "Encoding:"
+msgstr "Codering:"
+
+msgid "Font:"
+msgstr "Lettertype:"
+
+msgid "Style:"
+msgstr "Stijl:"
+
+msgid "Size:"
+msgstr "Grootte:"
+
+msgid "E256: Hangul automata ERROR"
+msgstr "E256: 'Hangul automata'-fout"
+
+msgid "E550: Missing colon"
+msgstr "E550: dubbelepunt ontbreekt"
+
+msgid "E551: Illegal component"
+msgstr "E551: ongeldige component"
+
+msgid "E552: digit expected"
+msgstr "E552: cijfer verwacht"
+
+#, c-format
+msgid "Page %d"
+msgstr "Pagina %d"
+
+msgid "No text to be printed"
+msgstr "Geen tekst om af te drukken"
+
+#, c-format
+msgid "Printing page %d (%d%%)"
+msgstr "Afdrukken van pagina %d (%d%%)"
+
+#, c-format
+msgid " Copy %d of %d"
+msgstr "Kopie %d van %d"
+
+#, c-format
+msgid "Printed: %s"
+msgstr "Afgedrukt: %s"
+
+msgid "Printing aborted"
+msgstr "Afdrukken afgebroken"
+
+msgid "E455: Error writing to PostScript output file"
+msgstr "E455: wegschrijven Postscript-uitvoerbestand is mislukt"
+
+#, c-format
+msgid "E624: Can't open file \"%s\""
+msgstr "E624: openen bestand \"%s\" is mislukt"
+
+#, c-format
+msgid "E457: Can't read PostScript resource file \"%s\""
+msgstr "E457: kan 'Postscript resource'-bestand \"%s\" niet lezen"
+
+#, c-format
+msgid "E618: file \"%s\" is not a PostScript resource file"
+msgstr "E618: bestand \"%s\" is geen 'Postscript resource'-bestand"
+
+#, c-format
+msgid "E619: file \"%s\" is not a supported PostScript resource file"
+msgstr "E619: bestand \"%s\" is geen ondersteund 'Postscript resource'-bestand"
+
+#, c-format
+msgid "E621: \"%s\" resource file has wrong version"
+msgstr "E621: 'resource'-bestand \"%s\" heeft verkeerde versie"
+
+msgid "E673: Incompatible multi-byte encoding and character set."
+msgstr "E673: Multi-byte-codering en de tekenverzameling zijn onverenigbaar."
+
+msgid "E674: printmbcharset cannot be empty with multi-byte encoding."
+msgstr "E674: printmbcharset mag bij multi-byte-codering niet leeg zijn."
+
+msgid "E675: No default font specified for multi-byte printing."
+msgstr "E675: geen standaard lettertype opgegeven voor multi-byte-afdrukken."
+
+msgid "E324: Can't open PostScript output file"
+msgstr "E324: openen van PostScript-uitoverbestand is mislukt"
+
+#, c-format
+msgid "E456: Can't open file \"%s\""
+msgstr "E456: Bestand \"%s\" kan niet worden geopend"
+
+msgid "E456: Can't find PostScript resource file \"prolog.ps\""
+msgstr "E456: 'PostScript resource'-bestand \"prolog.ps\" is niet gevonden"
+
+msgid "E456: Can't find PostScript resource file \"cidfont.ps\""
+msgstr "E456: 'PostScript resource'-bestand \"cidfont.ps\" is niet gevonden"
+
+#, c-format
+msgid "E456: Can't find PostScript resource file \"%s.ps\""
+msgstr "E456: 'PostScript resource'-bestand \"%s.ps\" is niet gevonden"
+
+#, c-format
+msgid "E620: Unable to convert to print encoding \"%s\""
+msgstr "E620: omzetten naar afdrukcodering \"%s\" is mislukt"
+
+msgid "Sending to printer..."
+msgstr "Naar printer versturen..."
+
+msgid "E365: Failed to print PostScript file"
+msgstr "E365: Afdrukken van PostScript-bestand is mislukt"
+
+msgid "Print job sent."
+msgstr "Afdrukopdracht verzonden"
+
+msgid "Add a new database"
+msgstr "Nieuwe databank toevoegen"
+
+msgid "Query for a pattern"
+msgstr "Naar een patroon zoeken"
+
+msgid "Show this message"
+msgstr "Dit bericht tonen"
+
+msgid "Kill a connection"
+msgstr "Een verbinding verbreken"
+
+msgid "Reinit all connections"
+msgstr "Alle verbindingen opnieuw initialiseren"
+
+msgid "Show connections"
+msgstr "Verbindingen tonen"
+
+#, c-format
+msgid "E560: Usage: cs[cope] %s"
+msgstr "E560: Gebruik: cs[cope] %s"
+
+msgid "This cscope command does not support splitting the window.\n"
+msgstr "Deze cscope-opdracht ondersteunt niet het splitsen van het venster.\n"
+
+msgid "E562: Usage: cstag <ident>"
+msgstr "E562: Gebruik: cstag <ident>"
+
+msgid "E257: cstag: tag not found"
+msgstr "E257: cstag: tag is gevonden"
+
+#, c-format
+msgid "E563: stat(%s) error: %d"
+msgstr "E563: bevraag((%s) fout: %d"
+
+msgid "E563: stat error"
+msgstr "E563: bevragingsfout"
+
+#, c-format
+msgid "E564: %s is not a directory or a valid cscope database"
+msgstr "E564: %s is geen map of een geldige cscope-databank"
+
+#, c-format
+msgid "Added cscope database %s"
+msgstr "cscope-databank %s toegevoegd"
+
+#, c-format
+msgid "E262: error reading cscope connection %ld"
+msgstr "E262: lezen van cscope-verbinding %ld is mislukt"
+
+msgid "E561: unknown cscope search type"
+msgstr "E561: soort cscope-zoekopdracht is onbekend"
+
+msgid "E566: Could not create cscope pipes"
+msgstr "E566: aanmaken cscopei-pijp is mislukt"
+
+msgid "E622: Could not fork for cscope"
+msgstr "E622: nieuw cscope-proces beginnen is mislukt"
+
+msgid "cs_create_connection exec failed"
+msgstr "uitvoering cs_create_connection is mislukt"
+
+msgid "cs_create_connection: fdopen for to_fp failed"
+msgstr "cs_create_connection: fdopen voor to_fp is mislukt"
+
+msgid "cs_create_connection: fdopen for fr_fp failed"
+msgstr "cs_create_connection: fdopen voor fr_fp is mislukt"
+
+msgid "E623: Could not spawn cscope process"
+msgstr "E623: voortbrengen cscope-proces is mislukt"
+
+msgid "E567: no cscope connections"
+msgstr "E567: geen cscope-verbindingen"
+
+#, c-format
+msgid "E469: invalid cscopequickfix flag %c for %c"
+msgstr "E469: cscopequickfix-vlag %c voor %c is ongeldig"
+
+#, c-format
+msgid "E259: no matches found for cscope query %s of %s"
+msgstr "E259: cscope-zoekopdracht %s van %s leverde geen resultaten"
+
+msgid "cscope commands:\n"
+msgstr "cscope-opdrachten:\n"
+
+#, c-format
+msgid "%-5s: %s%*s (Usage: %s)"
+msgstr "%-5s: %s%*s (Gebruik: %s)"
+
+msgid ""
+"\n"
+" c: Find functions calling this function\n"
+" d: Find functions called by this function\n"
+" e: Find this egrep pattern\n"
+" f: Find this file\n"
+" g: Find this definition\n"
+" i: Find files #including this file\n"
+" s: Find this C symbol\n"
+" t: Find assignments to\n"
+msgstr ""
+"\n"
+" c: zoek functies die deze functie aanroepen\n"
+" d: zoek functies die door deze functie worden aangeroepen\n"
+" e: zoek op dit egrep-patroon\n"
+" f: zoek dit bestand\n"
+" g: zoek deze definitie\n"
+" i: zoek bestanden #inclusief dit bestand\n"
+" s: zoek dit C-symbool\n"
+" t: zoek toekenningen aan\n"
+
+#, c-format
+msgid "E625: cannot open cscope database: %s"
+msgstr "E625: openen is mislukt van cscope-databank: %s"
+
+msgid "E626: cannot get cscope database information"
+msgstr "E626: opvragen cscope-databankinformatie is mislukt"
+
+msgid "E568: duplicate cscope database not added"
+msgstr "E568: dubbele cscope-databank is niet toegevoegd"
+
+#, c-format
+msgid "E261: cscope connection %s not found"
+msgstr "E261: cscope-verbinding %s is niet gevonden"
+
+#, c-format
+msgid "cscope connection %s closed"
+msgstr "cscope-verbinding %s is verbroken"
+
+#. should not reach here
+msgid "E570: fatal error in cs_manage_matches"
+msgstr "E570: fatale fout in cs_manage_matches"
+
+#, c-format
+msgid "Cscope tag: %s"
+msgstr "Cscope-tag: %s"
+
+msgid ""
+"\n"
+" # line"
+msgstr ""
+"\n"
+" # regel"
+
+msgid "filename / context / line\n"
+msgstr "bestandsnaam / context / regel\n"
+
+#, c-format
+msgid "E609: Cscope error: %s"
+msgstr "E609: Cscope-fout: %s"
+
+msgid "All cscope databases reset"
+msgstr "Alle cscope-databanken opnieuw ingesteld"
+
+msgid "no cscope connections\n"
+msgstr "geen cscope-verbindingen\n"
+
+msgid " # pid database name prepend path\n"
+msgstr " # pid databanknaam padvoorvoegsel\n"
+
+msgid "E815: Sorry, this command is disabled, the MzScheme libraries could not be loaded."
+msgstr "E815: helaas, deze opdracht is uitgeschakeld. De MzScheme-bibliotheken kunnen niet geladen worden."
+
+msgid "invalid expression"
+msgstr "ongeldige uitdrukking"
+
+msgid "expressions disabled at compile time"
+msgstr "tijdens compileren zijn de expressies uitgeschakeld"
+
+msgid "hidden option"
+msgstr "verborgen optie"
+
+msgid "unknown option"
+msgstr "onbekende optie"
+
+msgid "window index is out of range"
+msgstr "vensterindex valt buiten het bereik"
+
+msgid "couldn't open buffer"
+msgstr "buffer openen is mislukt"
+
+msgid "cannot save undo information"
+msgstr "herstelinformatie kan niet worden opgeslagen"
+
+msgid "cannot delete line"
+msgstr "regel kan niet worden verwijderd"
+
+msgid "cannot replace line"
+msgstr "regel kan niet worden vervangen"
+
+msgid "cannot insert line"
+msgstr "regel kan niet worden ingevoegd"
+
+msgid "string cannot contain newlines"
+msgstr "tekenreeks kan geen regeleinden bevatten"
+
+msgid "Vim error: ~a"
+msgstr "Vim-fout: ~a"
+
+msgid "Vim error"
+msgstr "Vim-fout"
+
+msgid "buffer is invalid"
+msgstr "buffer is ongeldig"
+
+msgid "window is invalid"
+msgstr "venster is ongeldig"
+
+msgid "linenr out of range"
+msgstr "regelnummer buiten het bereik"
+
+msgid "not allowed in the Vim sandbox"
+msgstr "niet toegestaan in de Vim-zandbak"
+
+msgid "E263: Sorry, this command is disabled, the Python library could not be loaded."
+msgstr "E263: helaas, deze opdracht is uitgeschakeld. De Python-bibliotheek kan niet worden geladen."
+
+msgid "E659: Cannot invoke Python recursively"
+msgstr "E659: Python kan niet recursief worden aangeroepen"
+
+msgid "can't delete OutputObject attributes"
+msgstr "attributen van OutputObject kunnen niet worden verwijderd"
+
+msgid "softspace must be an integer"
+msgstr "zachte spatie moet een geheel getal zijn"
+
+msgid "invalid attribute"
+msgstr "ongeldig attribuut"
+
+msgid "writelines() requires list of strings"
+msgstr "writelines() vereist een lijst met tekenreeksen"
+
+msgid "E264: Python: Error initialising I/O objects"
+msgstr "E264: Python: initialiseren I/O-objecten is mislukt"
+
+msgid "attempt to refer to deleted buffer"
+msgstr "poging om naar een verwijderd buffer te verwijzen"
+
+msgid "line number out of range"
+msgstr "regelnummer valt buiten het bereik"
+
+#, c-format
+msgid "<buffer object (deleted) at %p>"
+msgstr "<buffer-object (verwijderd) bij %p>"
+
+msgid "invalid mark name"
+msgstr "naam markering ongeldig"
+
+msgid "no such buffer"
+msgstr "onbekende buffer"
+
+msgid "attempt to refer to deleted window"
+msgstr "poging om naar een verwijderd venster te verwijzen"
+
+msgid "readonly attribute"
+msgstr "alleen-lezen attribuut"
+
+msgid "cursor position outside buffer"
+msgstr "cursorpositie valt buiten buffer"
+
+#, c-format
+msgid "<window object (deleted) at %p>"
+msgstr "<venster-object (verwijderd) bij %p>"
+
+#, c-format
+msgid "<window object (unknown) at %p>"
+msgstr "<venster-object (onbekend) bij %p>"
+
+#, c-format
+msgid "<window %d>"
+msgstr "<venster %d>"
+
+msgid "no such window"
+msgstr "onbekend venster"
+
+msgid "E265: $_ must be an instance of String"
+msgstr "E265: $_ moet een instantie van String zijn"
+
+msgid "E266: Sorry, this command is disabled, the Ruby library could not be loaded."
+msgstr "E266: helaas, deze opdracht is uitgeschakeld. De Ruby-bibliotheek kan niet worden geladen."
+
+msgid "E267: unexpected return"
+msgstr "E267: onverwacht resultaat"
+
+msgid "E268: unexpected next"
+msgstr "E268: onverwachte volgende"
+
+msgid "E269: unexpected break"
+msgstr "E269: onverwachte onderbreking"
+
+msgid "E270: unexpected redo"
+msgstr "E270: onverwachte herstelopdracht"
+
+msgid "E271: retry outside of rescue clause"
+msgstr "E271: hernieuwde poging buiten de reddingsclausule"
+
+msgid "E272: unhandled exception"
+msgstr "E272: niet-afgehandelde uitzondering"
+
+#, c-format
+msgid "E273: unknown longjmp status %d"
+msgstr "E273: onbekende longjmp-status %d"
+
+msgid "Toggle implementation/definition"
+msgstr "Implementatie/definitie wisselen"
+
+msgid "Show base class of"
+msgstr "Toon basisklasse van"
+
+msgid "Show overridden member function"
+msgstr "Toon overschreven member-functie"
+
+msgid "Retrieve from file"
+msgstr "Uit bestand halen"
+
+msgid "Retrieve from project"
+msgstr "Uit project halen"
+
+msgid "Retrieve from all projects"
+msgstr "Uit alle projecten halen"
+
+msgid "Retrieve"
+msgstr "Ophalen"
+
+msgid "Show source of"
+msgstr "Toon broncode van"
+
+msgid "Find symbol"
+msgstr "Zoek symbool"
+
+msgid "Browse class"
+msgstr "Bekijk klasse"
+
+msgid "Show class in hierarchy"
+msgstr "Toon klasse in hierarchie"
+
+msgid "Show class in restricted hierarchy"
+msgstr "Toon klasse in beperkte hierarchie"
+
+msgid "Xref refers to"
+msgstr "Xref verwijst naar"
+
+msgid "Xref referred by"
+msgstr "Xref wordt naar verwezen door"
+
+msgid "Xref has a"
+msgstr "Xref heeft een"
+
+msgid "Xref used by"
+msgstr "Xref gebruikt door"
+
+msgid "Show docu of"
+msgstr "Toon documentatie van"
+
+msgid "Generate docu for"
+msgstr "Genereer documentatie voor"
+
+msgid "Cannot connect to SNiFF+. Check environment (sniffemacs must be found in $PATH).\n"
+msgstr "Verbinden met SNiFF+ is mislukt. Controleer omgevingsvariabelen (sniffemacs moet in $PATH staan).\n"
+
+msgid "E274: Sniff: Error during read. Disconnected"
+msgstr "E274: Sniff: leesfout. Verbroken"
+
+msgid "SNiFF+ is currently "
+msgstr "SNiFF+ is momenteel "
+
+msgid "not "
+msgstr "niet "
+
+msgid "connected"
+msgstr "verbonden"
+
+#, c-format
+msgid "E275: Unknown SNiFF+ request: %s"
+msgstr "E275: onbekend SNiFF+-verzoek: %s"
+
+msgid "E276: Error connecting to SNiFF+"
+msgstr "E276: verbinden met SNiFF+ is mislukt"
+
+msgid "E278: SNiFF+ not connected"
+msgstr "E278: SNiFF+ niet verbonden"
+
+msgid "E279: Not a SNiFF+ buffer"
+msgstr "E279: geen SNiFF+-buffer"
+
+msgid "Sniff: Error during write. Disconnected"
+msgstr "Sniff: schrijven is mislukt. Verbroken"
+
+msgid "invalid buffer number"
+msgstr "buffernummer is ongeldig"
+
+msgid "not implemented yet"
+msgstr "nog niet geïmplementeerd"
+
+#. ???
+msgid "cannot set line(s)"
+msgstr "kan regel(s) niet instellen"
+
+msgid "mark not set"
+msgstr "markering niet ingesteld"
+
+#, c-format
+msgid "row %d column %d"
+msgstr "rij %d kolom %d"
+
+msgid "cannot insert/append line"
+msgstr "invoegen/toevoegen regel is mislukt"
+
+msgid "unknown flag: "
+msgstr "unbekende instelling: "
+
+msgid "unknown vimOption"
+msgstr "onbekende vim-optie"
+
+msgid "keyboard interrupt"
+msgstr "toetsenbord-interrupt"
+
+msgid "vim error"
+msgstr "vim-fout"
+
+msgid "cannot create buffer/window command: object is being deleted"
+msgstr "aanmaken buffer-/vensteropdracht is mislukt: object wordt verwijderd"
+
+msgid "cannot register callback command: buffer/window is already being deleted"
+msgstr " kan 'callback'-opdracht niet registreren: buffer/venster is reeds verwijderd"
+
+#. This should never happen. Famous last word?
+msgid "E280: TCL FATAL ERROR: reflist corrupt!? Please report this to vim-dev@vim.org"
+msgstr "E280: TCL FATALE FOUT: reflist misschien corrupt!? Meld dit a.u.b. aan vim-dev@vim.org"
+
+msgid "cannot register callback command: buffer/window reference not found"
+msgstr "'callback'-opdracht kan niet worden geregistreerd: buffer-/vensterreferentie ontbreekt"
+
+msgid "E571: Sorry, this command is disabled: the Tcl library could not be loaded."
+msgstr "E571: Helaas, deze opdracht is uitgeschakeld: het laden van de Tcl-bibliotheek is mislukt."
+
+msgid "E281: TCL ERROR: exit code is not int!? Please report this to vim-dev@vim.org"
+msgstr "E281: Tcl-fout: afsluitcode is geen geheel getal!? Meld dit a.u.b. aan vim-dev@vim.org"
+
+#, c-format
+msgid "E572: exit code %d"
+msgstr "E572: afsluitcode %d"
+
+msgid "cannot get line"
+msgstr "kan regel niet verkrijgen"
+
+msgid "Unable to register a command server name"
+msgstr "Het registreren van een opdrachtservernaam is mislukt"
+
+msgid "E248: Failed to send command to the destination program"
+msgstr "E248: versturen van opdracht naar het doelprogramma is mislukt"
+
+#, c-format
+msgid "E573: Invalid server id used: %s"
+msgstr "E573: ongeldige server-id gebruikt: %s"
+
+msgid "E251: VIM instance registry property is badly formed. Deleted!"
+msgstr "E251: registereigenschap van VIM-instantie is misvormd. Verwijderd!"
+
+msgid "Unknown option argument"
+msgstr "Onbekend optieargument"
+
+msgid "Too many edit arguments"
+msgstr "Teveel bewerkargumenten"
+
+msgid "Argument missing after"
+msgstr "Argument ontbreekt na"
+
+msgid "Garbage after option argument"
+msgstr "Rommel na optieargument"
+
+msgid "Too many \"+command\", \"-c command\" or \"--cmd command\" arguments"
+msgstr "Teveel \"+opdracht\", \"-c opdracht\" of \"--cmd opdracht\"-argumenten"
+
+msgid "Invalid argument for"
+msgstr "Ongeldig argument voor"
+
+#, c-format
+msgid "%d files to edit\n"
+msgstr "%d bestanden om te bewerken\n"
+
+msgid "netbeans is not supported with this GUI\n"
+msgstr "Netbeans wordt door deze GUI niet ondersteund\n"
+
+msgid "This Vim was not compiled with the diff feature."
+msgstr "Deze Vim is niet met de diff-functionaliteit gecompileerd"
+
+msgid "'-nb' cannot be used: not enabled at compile time\n"
+msgstr "'-nb' kan niet worden gebruikt: was tijdens compilatie niet ingeschakeld\n"
+
+msgid "Attempt to open script file again: \""
+msgstr "Poging scriptbestand wederom te openen: \""
+
+msgid "Cannot open for reading: \""
+msgstr "Openen om te lezen is mislukt: \""
+
+msgid "Cannot open for script output: \""
+msgstr "Openen voor script-uitvoer is mislukt: \""
+
+msgid "Vim: Error: Failure to start gvim from NetBeans\n"
+msgstr "Vim: Fout: gvim starten vanuit Netbeans is mislukt\n"
+
+msgid "Vim: Warning: Output is not to a terminal\n"
+msgstr "Vim: Waarschuwing: Uitvoer gaan niet naar een terminal\n"
+
+msgid "Vim: Warning: Input is not from a terminal\n"
+msgstr "Vim: Waarschuwing: Invoer komt niet van een terminal\n"
+
+#. just in case..
+msgid "pre-vimrc command line"
+msgstr "pre-vimrc-opdracjtregel"
+
+#, c-format
+msgid "E282: Cannot read from \"%s\""
+msgstr "E282: Kan niet lezen vanuit \"%s\""
+
+msgid ""
+"\n"
+"More info with: \"vim -h\"\n"
+msgstr ""
+"\n"
+"Meer informatie via: \"vim -h\"\n"
+
+msgid "[file ..] edit specified file(s)"
+msgstr "[bestand ..] bewerk opgegeven bestand(en)"
+
+msgid "- read text from stdin"
+msgstr "- lees tekst vanuit stdin"
+
+msgid "-t tag edit file where tag is defined"
+msgstr "-t tag bewerk bestand waar tag is gedefinieerd"
+
+msgid "-q [errorfile] edit file with first error"
+msgstr "-q [foutbestand] bewerk bestand dat eerste fout bevat"
+
+msgid ""
+"\n"
+"\n"
+"Usage:"
+msgstr ""
+"\n"
+"\n"
+"Gebruik:"
+
+msgid " vim [arguments] "
+msgstr " vim [argumenten] "
+
+msgid ""
+"\n"
+" or:"
+msgstr ""
+"\n"
+" of:"
+
+msgid ""
+"\n"
+"Where case is ignored prepend / to make flag upper case"
+msgstr ""
+"\n"
+"Daar waar hoofdletters genegeerd worden kan met / vlag in hoofdletters gezet worden"
+
+msgid ""
+"\n"
+"\n"
+"Arguments:\n"
+msgstr ""
+"\n"
+"\n"
+"Argumenten:\n"
+
+msgid "--\t\t\tOnly file names after this"
+msgstr "--\t\t\tHierna alleen bestandsnamen"
+
+msgid "--literal\t\tDon't expand wildcards"
+msgstr "--literal\t\tJokertekens niet vervangen"
+
+msgid "-register\t\tRegister this gvim for OLE"
+msgstr "-register\t\tDeze gvim voor OLE registreren"
+
+msgid "-unregister\t\tUnregister gvim for OLE"
+msgstr "-unregister\t\tgvim afmelden voor OLE"
+
+msgid "-g\t\t\tRun using GUI (like \"gvim\")"
+msgstr "-g\t\t\tMet GUI opstarten (zoals \"gvim\")"
+
+msgid "-f or --nofork\tForeground: Don't fork when starting GUI"
+msgstr "-f of --nofork\tVoorgrond: niet afsplitsen tijdens opstarten GUI"
+
+msgid "-v\t\t\tVi mode (like \"vi\")"
+msgstr "-v\t\t\tVi-modus (zoals \"vi\")"
+
+msgid "-e\t\t\tEx mode (like \"ex\")"
+msgstr "-e\t\t\tEx-modus (zoals \"ex\")"
+
+msgid "-s\t\t\tSilent (batch) mode (only for \"ex\")"
+msgstr "-s\t\t\tStille (bulk)modus (alleen bij \"ex\")"
+
+msgid "-d\t\t\tDiff mode (like \"vimdiff\")"
+msgstr "-d\t\t\tDiff-modus (zoals \"vimdiff\")"
+
+msgid "-y\t\t\tEasy mode (like \"evim\", modeless)"
+msgstr "-y\t\t\tEenvoudige modus (zoals \"evim\", zonder modus)"
+
+msgid "-R\t\t\tReadonly mode (like \"view\")"
+msgstr "-R\t\t\tAlleen-lezen modus (zoals \"view\")"
+
+msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
+msgstr "-Z\t\t\tBeperkte modus (zoals \"rvim\")"
+
+msgid "-m\t\t\tModifications (writing files) not allowed"
+msgstr "-m\t\t\tAanpassingen (bestanden opslaan) niet toegestaan"
+
+msgid "-M\t\t\tModifications in text not allowed"
+msgstr "-M\t\t\tTekstuele aanpassingen niet toegestaan"
+
+msgid "-b\t\t\tBinary mode"
+msgstr "-b\t\t\tBinaire modus"
+
+msgid "-l\t\t\tLisp mode"
+msgstr "-l\t\t\tLisp-modus"
+
+msgid "-C\t\t\tCompatible with Vi: 'compatible'"
+msgstr "-C\t\t\tUitwisselbaar met Vi: 'compatible'"
+
+msgid "-N\t\t\tNot fully Vi compatible: 'nocompatible'"
+msgstr "-N\t\t\tNiet volledig met Vi uitwisselbaar: 'nocompatible'"
+
+msgid "-V[N][fname]\t\tBe verbose [level N] [log messages to fname]"
+msgstr "-V[N][fname]\t\tWees uitbundig [niveau N] [schrijf berichten naar fname]"
+
+msgid "-D\t\t\tDebugging mode"
+msgstr "-D\t\t\tFoutopspoormodus"
+
+msgid "-n\t\t\tNo swap file, use memory only"
+msgstr "-n\t\t\tGeen wisselbestand, alleen geheugen gebruiken"
+
+msgid "-r\t\t\tList swap files and exit"
+msgstr "-r\t\t\tWisselbestanden tonen en stoppen"
+
+msgid "-r (with file name)\tRecover crashed session"
+msgstr "-r (bestandsnaam)\tHerstel ontspoorde sessie"
+
+msgid "-L\t\t\tSame as -r"
+msgstr "-L\t\t\tGelijk aan -r"
+
+msgid "-f\t\t\tDon't use newcli to open window"
+msgstr "-f\t\t\tGebruik geen newcli om venster te openen"
+
+msgid "-dev <device>\t\tUse <device> for I/O"
+msgstr "-dev <device>\t\tGebruik <device> voor in- en uitvoer"
+
+msgid "-A\t\t\tStart in Arabic mode"
+msgstr "-A\t\t\tIn Arabische modus starten"
+
+msgid "-H\t\t\tStart in Hebrew mode"
+msgstr "-H\t\t\tIn Hebrewsche modus starten"
+
+msgid "-F\t\t\tStart in Farsi mode"
+msgstr "-F\t\t\tIn Perzische modus starten"
+
+msgid "-T <terminal>\tSet terminal type to <terminal>"
+msgstr "-T <terminal>\tTerminalsoort op <terminal> instellen"
+
+msgid "-u <vimrc>\t\tUse <vimrc> instead of any .vimrc"
+msgstr "-u <vimrc>\t\tGebruik <vimrc> in plaats van enige .vimrc"
+
+msgid "-U <gvimrc>\t\tUse <gvimrc> instead of any .gvimrc"
+msgstr "-U <gvimrc>\t\tGebruik <gvimrc> in plaats van enige .gvimrc"
+
+msgid "--noplugin\t\tDon't load plugin scripts"
+msgstr "--noplugin\t\tGeen plugin-scripts laden"
+
+msgid "-p[N]\t\tOpen N tab pages (default: one for each file)"
+msgstr "-p[N]\t\tN tabpagina's openen (standaard: 1 per bestand)"
+
+msgid "-o[N]\t\tOpen N windows (default: one for each file)"
+msgstr "-o[N]\t\tN vensters openen (standaard: 1 per bestand)"
+
+msgid "-O[N]\t\tLike -o but split vertically"
+msgstr "-O[N]\t\tGelijk aan -o maar vertikaal gesplitst"
+
+msgid "+\t\t\tStart at end of file"
+msgstr "+\t\t\tAan einde van bestand beginnen"
+
+msgid "+<lnum>\t\tStart at line <lnum>"
+msgstr "+<lnum>\t\tOp regel <lnum> beginnen"
+
+msgid "--cmd <command>\tExecute <command> before loading any vimrc file"
+msgstr "--cmd <opdracht>\tOpdracht <opdracht> uitvoeren voor enige vimrc-bestand"
+
+msgid "-c <command>\t\tExecute <command> after loading the first file"
+msgstr "-c <opdracht>\t\tOpdracht <opdracht> uitvoeren na eerste bestand"
+
+msgid "-h or --help\tPrint Help (this message) and exit"
+msgstr "-h of --help\tDit bericht tonen en stoppen"
+
+msgid "--version\t\tPrint version information and exit"
+msgstr "--version\t\tVersieinformatie tonen en stoppen"
+
+msgid "E298: Didn't get block nr 0?"
+msgstr "E298: Ophalen blok nummer 0 mislukt?"
+
+msgid "E298: Didn't get block nr 1?"
+msgstr "E298: Ophalen blok nummer 1 mislukt?"
+
+msgid "E298: Didn't get block nr 2?"
+msgstr "E298: Ophalen blok nummer 2 mislukt?"
+
+#. could not (re)open the swap file, what can we do????
+msgid "E301: Oops, lost the swap file!!!"
+msgstr "E301: Helaas, wisselbestand is verdwenen!!!"
+
+msgid "Enter number of swap file to use (0 to quit): "
+msgstr "Typ het nummer van het wisselbestand om te gebruiken (0 om te stoppen): "
+
+#, c-format
+msgid "Using swap file \"%s\""
+msgstr "Toepassen van wisselbestand \"%s\""
+
+#, c-format
+msgid "Original file \"%s\""
+msgstr "Oorspronkelijke bestand \"%s\""
+
+msgid "Recovery completed. You should check if everything is OK."
+msgstr "Herstel is afgerond. Controleer of het resultaat juist is."
+
+msgid ""
+"\n"
+"(You might want to write out this file under another name\n"
+msgstr ""
+"\n"
+"(Een advies is dit bestand onder een andere naam op te slaan\n"
+
+msgid "and run diff with the original file to check for changes)"
+msgstr "en met 'diff' te controleren op wijzigingen)"
+
+msgid "Recovery completed. Buffer contents equals file contents."
+msgstr "Herstel is afgerond. Inhoud van het buffer komt overeen met de bestandsinhoud."
+
+msgid ""
+"\n"
+"You may want to delete the .swp file now.\n"
+"\n"
+msgstr ""
+"\n"
+"Het .swp-bestand kan nu verwijderd worden.\n"
+"\n"
+
+#. use msg() to start the scrolling properly
+msgid "Swap files found:"
+msgstr "Gevonden wisselbestanden:"
+
+msgid " In current directory:\n"
+msgstr " In huidige map:\n"
+
+msgid " Using specified name:\n"
+msgstr " Gebruikt opgegeven naam:\n"
+
+msgid " In directory "
+msgstr " In map "
+
+msgid " -- none --\n"
+msgstr " -- geen --\n"
+
+msgid " owned by: "
+msgstr " eigenaar: "
+
+msgid " dated: "
+msgstr " datum: "
+
+msgid " dated: "
+msgstr " datum: "
+
+msgid " [from Vim version 3.0]"
+msgstr " [van Vim-versie 3.0]"
+
+msgid " [does not look like a Vim swap file]"
+msgstr " [lijkt geen Vvim-wisselbestand te zijn]"
+
+msgid " file name: "
+msgstr " bestandsnaam: "
+
+msgid ""
+"\n"
+" modified: "
+msgstr ""
+"\n"
+" bewerkt: "
+
+msgid "YES"
+msgstr "JA"
+
+msgid "no"
+msgstr "nee"
+
+msgid ""
+"\n"
+" user name: "
+msgstr ""
+"\n"
+" gebruikersnaam: "
+
+msgid " host name: "
+msgstr " host-naam:"
+
+msgid ""
+"\n"
+" host name: "
+msgstr ""
+"\n"
+" host-naam: "
+
+msgid ""
+"\n"
+" process ID: "
+msgstr ""
+"\n"
+" proces-id: "
+
+msgid " (still running)"
+msgstr " (nog actief)"
+
+msgid ""
+"\n"
+" [not usable with this version of Vim]"
+msgstr ""
+"\n"
+" [onbruikbaar met deze versie van Vim]"
+
+msgid ""
+"\n"
+" [not usable on this computer]"
+msgstr ""
+"\n"
+" [onbruikbaar op deze computer]"
+
+msgid " [cannot be read]"
+msgstr " [lezen is onmogelijk]"
+
+msgid " [cannot be opened]"
+msgstr " [openen is onmogelijk]"
+
+msgid "E313: Cannot preserve, there is no swap file"
+msgstr "E313: kan niet worden behouden, want er is geen wisselbestand"
+
+msgid "File preserved"
+msgstr "Bestand behouden"
+
+msgid "E314: Preserve failed"
+msgstr "E314: behouden is mislukt"
+
+#, c-format
+msgid "E773: Symlink loop for \"%s\""
+msgstr "E773: Symbolische koppelingslus voor \"%s\""
+
+msgid "E325: ATTENTION"
+msgstr "E325: OPGELET"
+
+msgid ""
+"\n"
+"Found a swap file by the name \""
+msgstr ""
+"\n"
+"Er is een wisselbestand aangetroffen met de naam \""
+
+msgid "While opening file \""
+msgstr "bij het openen van bestand \""
+
+msgid " NEWER than swap file!\n"
+msgstr " NIEUWER dan het wisselbestand!\n"
+
+#. Some of these messages are long to allow translation to
+#. * other languages.
+msgid ""
+"\n"
+"(1) Another program may be editing the same file.\n"
+" If this is the case, be careful not to end up with two\n"
+" different instances of the same file when making changes.\n"
+msgstr ""
+"\n"
+"(1) Mogelijk wordt dit bestand met een ander programma bewerkt.\n"
+" Als dit het geval is, pas dan op niet met twee verschillende\n"
+" versies van hetzelfde bestand te eindigen bij het bewerken.\n"
+
+msgid " Quit, or continue with caution.\n"
+msgstr " Stop of ga aandachtig verder.\n"
+
+msgid ""
+"\n"
+"(2) An edit session for this file crashed.\n"
+msgstr ""
+"\n"
+"(2) Een sessie waarin dit bestand werd bewerkt is onverhoeds gestopt.\n"
+
+msgid " If this is the case, use \":recover\" or \"vim -r "
+msgstr " Als dit het geval is, gebruikt dan \":recover\" of \"vim -r "
+
+msgid ""
+"\"\n"
+" to recover the changes (see \":help recovery\").\n"
+msgstr ""
+"\"\n"
+" om de aanpassingen te herstellen (zie \":help recovery\").\n"
+
+msgid " If you did this already, delete the swap file \""
+msgstr " Als dit al gedaan is, verwijder dan het wisselbestand \""
+
+msgid ""
+"\"\n"
+" to avoid this message.\n"
+msgstr ""
+"\"\n"
+" om dit bericht te voorkomen.\n"
+
+msgid "Swap file \""
+msgstr "Wisselbestand \""
+
+msgid "\" already exists!"
+msgstr "\" bestaat al!"
+
+msgid "VIM - ATTENTION"
+msgstr "VIM - OPGELET"
+
+msgid "Swap file already exists!"
+msgstr "Wisselbestand bestaat reeds."
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"Alleen-lezen &openen\n"
+"Toch b&ewerken\n"
+"He&rstellen\n"
+"&Stoppen\n"
+"&Afbreken"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Delete it\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"Alleen-lezen &openen\n"
+"Toch b&ewerken\n"
+"He&rstellen\n"
+"Verwij&deren\n"
+"&Stoppen\n"
+"&Afbreken"
+
+msgid "E326: Too many swap files found"
+msgstr "E326: teveel wisselbestanden aangetroffen"
+
+msgid "E327: Part of menu-item path is not sub-menu"
+msgstr "E327: deel van menu-itempad is geen submenu"
+
+msgid "E328: Menu only exists in another mode"
+msgstr "E328: menu bestaat alleen in andere modus"
+
+#, c-format
+msgid "E329: No menu \"%s\""
+msgstr "E329: geen menu \"%s\""
+
+#. Only a mnemonic or accelerator is not valid.
+msgid "E792: Empty menu name"
+msgstr "E792: menunaam is leeg"
+
+#, c-format
+#~ msgid "E335: Menu not defined for %s mode"
+#~ msgstr ""
+
+#~ msgid "E336: Menu path must lead to a sub-menu"
+#~ msgstr ""
+
+#~ msgid "E337: Menu not found - check menu names"
+#~ msgstr ""
+
+#, c-format
+msgid "Error detected while processing %s:"
+msgstr "Fout opgetreden tijdens verwerken van %s:"
+
+#, c-format
+msgid "line %4ld:"
+msgstr "regel %4ld:"
+
+#, c-format
+#~ msgid "E354: Invalid register name: '%s'"
+#~ msgstr ""
+
+msgid "Messages maintainer: Bram Moolenaar <Bram@vim.org>"
+msgstr "Vertaald door: Erwin Poeze <erwin.poeze@gmail.com>"
+
+#~ msgid "Interrupt: "
+#~ msgstr ""
+
+msgid "Press ENTER or type command to continue"
+msgstr "Toets ENTER of typ een opdracht om verder te gaan"
+
+#, c-format
+msgid "%s line %ld"
+msgstr "%s regel %ld"
+
+msgid "-- More --"
+msgstr "-- meer --"
+
+#~ msgid " SPACE/d/j: screen/page/line down, b/u/k: up, q: quit "
+#~ msgstr ""
+
+msgid "Question"
+msgstr "Vraag"
+
+#~ msgid ""
+#~ "&Yes\n"
+#~ "&No"
+#~ msgstr ""
+
+#~ msgid ""
+#~ "&Yes\n"
+#~ "&No\n"
+#~ "Save &All\n"
+#~ "&Discard All\n"
+#~ "&Cancel"
+#~ msgstr ""
+
+#~ msgid "Select Directory dialog"
+#~ msgstr ""
+
+#~ msgid "Save File dialog"
+#~ msgstr ""
+
+#~ msgid "Open File dialog"
+#~ msgstr ""
+
+#. TODO: non-GUI file selector here
+#~ msgid "E338: Sorry, no file browser in console mode"
+#~ msgstr ""
+
+#~ msgid "E766: Insufficient arguments for printf()"
+#~ msgstr ""
+
+#~ msgid "E807: Expected Float argument for printf()"
+#~ msgstr ""
+
+#~ msgid "E767: Too many arguments to printf()"
+#~ msgstr ""
+
+#~ msgid "W10: Warning: Changing a readonly file"
+#~ msgstr ""
+
+#~ msgid "Type number and <Enter> or click with mouse (empty cancels): "
+#~ msgstr ""
+
+#~ msgid "Type number and <Enter> (empty cancels): "
+#~ msgstr ""
+
+msgid "1 more line"
+msgstr "1 regel meer"
+
+msgid "1 line less"
+msgstr "1 regel minder"
+
+#, c-format
+msgid "%ld more lines"
+msgstr "%ld regels meer"
+
+#, c-format
+msgid "%ld fewer lines"
+msgstr "%ld regels minder"
+
+msgid " (Interrupted)"
+msgstr " (onderbroken)"
+
+msgid "Beep!"
+msgstr "biep!"
+
+#~ msgid "Vim: preserving files...\n"
+#~ msgstr ""
+
+#. close all memfiles, without deleting
+#~ msgid "Vim: Finished.\n"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "ERROR: "
+#~ msgstr ""
+
+#, c-format
+#~ msgid ""
+#~ "\n"
+#~ "[bytes] total alloc-freed %lu-%lu, in use %lu, peak use %lu\n"
+#~ msgstr ""
+
+#, c-format
+#~ msgid ""
+#~ "[calls] total re/malloc()'s %lu, total free()'s %lu\n"
+#~ "\n"
+#~ msgstr ""
+
+#~ msgid "E340: Line is becoming too long"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E341: Internal error: lalloc(%ld, )"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E342: Out of memory! (allocating %lu bytes)"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Calling shell to execute: \"%s\""
+#~ msgstr ""
+
+#~ msgid "E545: Missing colon"
+#~ msgstr ""
+
+#~ msgid "E546: Illegal mode"
+#~ msgstr ""
+
+#~ msgid "E547: Illegal mouseshape"
+#~ msgstr ""
+
+#~ msgid "E548: digit expected"
+#~ msgstr ""
+
+#~ msgid "E549: Illegal percentage"
+#~ msgstr ""
+
+#~ msgid "Enter encryption key: "
+#~ msgstr ""
+
+#~ msgid "Enter same key again: "
+#~ msgstr ""
+
+#~ msgid "Keys don't match!"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E343: Invalid path: '**[number]' must be at the end of the path or be followed by '%s'."
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E344: Can't find directory \"%s\" in cdpath"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E345: Can't find file \"%s\" in path"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E346: No more directory \"%s\" found in cdpath"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E347: No more file \"%s\" found in path"
+#~ msgstr ""
+
+#~ msgid "Cannot connect to Netbeans #2"
+#~ msgstr ""
+
+#~ msgid "Cannot connect to Netbeans"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E668: Wrong access mode for NetBeans connection info file: \"%s\""
+#~ msgstr ""
+
+#~ msgid "read from Netbeans socket"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E658: NetBeans connection lost for buffer %ld"
+#~ msgstr ""
+
+#~ msgid "E511: netbeans already connected"
+#~ msgstr ""
+
+#~ msgid "E505: "
+#~ msgstr ""
+
+#~ msgid "E349: No identifier under cursor"
+#~ msgstr ""
+
+#~ msgid "E774: 'operatorfunc' is empty"
+#~ msgstr ""
+
+#~ msgid "E775: Eval feature not available"
+#~ msgstr ""
+
+msgid "Warning: terminal cannot highlight"
+msgstr "waarschuwing: terminal kan niet oplichten"
+
+#~ msgid "E348: No string under cursor"
+#~ msgstr ""
+
+#~ msgid "E352: Cannot erase folds with current 'foldmethod'"
+#~ msgstr ""
+
+msgid "E664: changelist is empty"
+msgstr "E664: wijzigingslijst is leeg"
+
+msgid "E662: At start of changelist"
+msgstr "E662: begin van wijzigingslijst"
+
+msgid "E663: At end of changelist"
+msgstr "E663: einde van wijzigingslijst"
+
+msgid "Type :quit<Enter> to exit Vim"
+msgstr "Typ :quit<Enter> om Vim te verlaten"
+
+#, c-format
+msgid "1 line %sed 1 time"
+msgstr "1 regel %sed 1 maal"
+
+#, c-format
+msgid "1 line %sed %d times"
+msgstr "1 regel %sed %d maal"
+
+#, c-format
+msgid "%ld lines %sed 1 time"
+msgstr "%ld regels %sed 1 maal"
+
+#, c-format
+msgid "%ld lines %sed %d times"
+msgstr "%ld regels %sed %d maal"
+
+#, c-format
+msgid "%ld lines to indent... "
+msgstr "%ld in te springen regels... "
+
+msgid "1 line indented "
+msgstr "1 regel ingesprongen "
+
+#, c-format
+msgid "%ld lines indented "
+msgstr "%ld regels ingesprongen "
+
+#~ msgid "E748: No previously used register"
+#~ msgstr ""
+
+#. must display the prompt
+msgid "cannot yank; delete anyway"
+msgstr "kopiëren niet mogelijk; toch verwijderd"
+
+msgid "1 line changed"
+msgstr "1 regel gewijzigd"
+
+#, c-format
+msgid "%ld lines changed"
+msgstr "%ld regels gewijzigd"
+
+#, c-format
+#~ msgid "freeing %ld lines"
+#~ msgstr ""
+
+msgid "block of 1 line yanked"
+msgstr "blok van 1 regel gekopieerd"
+
+msgid "1 line yanked"
+msgstr "1 regel gekopieerd"
+
+#, c-format
+msgid "block of %ld lines yanked"
+msgstr "blok van %ld regels gekopieerd"
+
+#, c-format
+msgid "%ld lines yanked"
+msgstr "%ld regels gekopieerd"
+
+#, c-format
+msgid "E353: Nothing in register %s"
+msgstr "E353: niets in register %s"
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Registers ---"
+msgstr ""
+"\n"
+"--- Registers ---"
+
+msgid "Illegal register name"
+msgstr "ongeldige registernaam"
+
+#, c-format
+msgid ""
+"\n"
+"# Registers:\n"
+msgstr ""
+"\n"
+"# Registers:\n"
+
+#, c-format
+#~ msgid "E574: Unknown register type %d"
+#~ msgstr ""
+
+#, c-format
+msgid "%ld Cols; "
+msgstr "%ld koln; "
+
+#, c-format
+msgid "Selected %s%ld of %ld Lines; %ld of %ld Words; %ld of %ld Bytes"
+msgstr "geselecteerd %s%ld van %ld regels; %ld van %ld woorden; %ld van %ld bytes"
+
+#, c-format
+msgid "Selected %s%ld of %ld Lines; %ld of %ld Words; %ld of %ld Chars; %ld of %ld Bytes"
+msgstr "geselecteerd %s%ld van %ld regels; %ld van %ld woorden; %ld van %ld rekens; %ld van %ld bytes"
+
+#, c-format
+msgid "Col %s of %s; Line %ld of %ld; Word %ld of %ld; Byte %ld of %ld"
+msgstr "kol %s van %s; regel %ld van %ld; woord %ld van %ld; byte %ld van %ld"
+
+#, c-format
+msgid "Col %s of %s; Line %ld of %ld; Word %ld of %ld; Char %ld of %ld; Byte %ld of %ld"
+msgstr "kol %s van %s; regel %ld van %ld; woord %ld van %ld; teken %ld van %ld; byte %ld van %ld"
+
+#, c-format
+msgid "(+%ld for BOM)"
+msgstr "(+%ld voor BOD)"
+
+msgid "%<%f%h%m%=Page %N"
+msgstr "%<%f%h%m%=pagina %N"
+
+msgid "Thanks for flying Vim"
+msgstr "Dank voor het gebruik van Vim"
+
+msgid "E518: Unknown option"
+msgstr "E518: onbekende optie"
+
+msgid "E519: Option not supported"
+msgstr "E519: optie niet ondersteund"
+
+#~ msgid "E520: Not allowed in a modeline"
+#~ msgstr ""
+
+#~ msgid "E521: Number required after ="
+#~ msgstr ""
+
+#~ msgid "E522: Not found in termcap"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E539: Illegal character <%s>"
+#~ msgstr ""
+
+#~ msgid "E529: Cannot set 'term' to empty string"
+#~ msgstr ""
+
+#~ msgid "E530: Cannot change term in GUI"
+#~ msgstr ""
+
+#~ msgid "E531: Use \":gui\" to start the GUI"
+#~ msgstr ""
+
+#~ msgid "E589: 'backupext' and 'patchmode' are equal"
+#~ msgstr ""
+
+#~ msgid "E617: Cannot be changed in the GTK+ 2 GUI"
+#~ msgstr ""
+
+#~ msgid "E524: Missing colon"
+#~ msgstr ""
+
+#~ msgid "E525: Zero length string"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E526: Missing number after <%s>"
+#~ msgstr ""
+
+#~ msgid "E527: Missing comma"
+#~ msgstr ""
+
+#~ msgid "E528: Must specify a ' value"
+#~ msgstr ""
+
+#~ msgid "E595: contains unprintable or wide character"
+#~ msgstr ""
+
+#~ msgid "E596: Invalid font(s)"
+#~ msgstr ""
+
+#~ msgid "E597: can't select fontset"
+#~ msgstr ""
+
+#~ msgid "E598: Invalid fontset"
+#~ msgstr ""
+
+#~ msgid "E533: can't select wide font"
+#~ msgstr ""
+
+#~ msgid "E534: Invalid wide font"
+#~ msgstr ""
+
+#, c-format
+msgid "E535: Illegal character after <%c>"
+msgstr "E535: ongeldig teken na <%c>"
+
+msgid "E536: comma required"
+msgstr "E536: komma is vereist"
+
+#, c-format
+msgid "E537: 'commentstring' must be empty or contain %s"
+msgstr "E537: 'commentstring' moet leeg zijn of het volgende bevatten: %s"
+
+msgid "E538: No mouse support"
+msgstr "E538: geen muisondersteuning"
+
+msgid "E540: Unclosed expression sequence"
+msgstr "E540: ongepaarde expressie-volgorde"
+
+msgid "E541: too many items"
+msgstr "E541: teveel items"
+
+msgid "E542: unbalanced groups"
+msgstr "E542: ongepaarde groepen"
+
+msgid "E590: A preview window already exists"
+msgstr "E590: een voorvertoningsvenster bestaat al"
+
+msgid "W17: Arabic requires UTF-8, do ':set encoding=utf-8'"
+msgstr "W17: Arabisch vereist UTF-8, typ ':set encoding=utf-8'"
+
+#, c-format
+msgid "E593: Need at least %d lines"
+msgstr "E593: vereist minstens %d regels"
+
+#, c-format
+msgid "E594: Need at least %d columns"
+msgstr "E594: vereist minstens %d kolommen"
+
+#, c-format
+msgid "E355: Unknown option: %s"
+msgstr "E355: onbekende optie: %s"
+
+#. There's another character after zeros or the string
+#. * is empty. In both cases, we are trying to set a
+#. * num option using a string.
+#, c-format
+msgid "E521: Number required: &%s = '%s'"
+msgstr "E521: 'Number' vereist: &%s = '%s'"
+
+msgid ""
+"\n"
+"--- Terminal codes ---"
+msgstr ""
+"\n"
+"--- Terminal-codes ---"
+
+msgid ""
+"\n"
+"--- Global option values ---"
+msgstr ""
+"\n"
+"--- Globale optiewaarden ---"
+
+msgid ""
+"\n"
+"--- Local option values ---"
+msgstr ""
+"\n"
+"--- Lokale optiewaarden ---"
+
+msgid ""
+"\n"
+"--- Options ---"
+msgstr ""
+"\n"
+"--- Opties ---"
+
+#~ msgid "E356: get_varp ERROR"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E357: 'langmap': Matching character missing for %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E358: 'langmap': Extra characters after semicolon: %s"
+#~ msgstr ""
+
+msgid "cannot open "
+msgstr "gefaald tijden openen van "
+
+msgid "VIM: Can't open window!\n"
+msgstr "VIM: kan venster niet openen!\n"
+
+msgid "Need Amigados version 2.04 or later\n"
+msgstr "Vereist Amigados versie 2.04 of nieuwer\n"
+
+#, c-format
+msgid "Need %s version %ld\n"
+msgstr "Vereist %s versie %ld\n"
+
+#~ msgid "Cannot open NIL:\n"
+#~ msgstr ""
+
+msgid "Cannot create "
+msgstr "Gefaald tijdens aanmaken van "
+
+#, c-format
+msgid "Vim exiting with %d\n"
+msgstr "Vim stoppen met %d\n"
+
+#~ msgid "cannot change console mode ?!\n"
+#~ msgstr ""
+
+#~ msgid "mch_get_shellsize: not a console??\n"
+#~ msgstr ""
+
+#. if Vim opened a window: Executing a shell may cause crashes
+#~ msgid "E360: Cannot execute shell with -f option"
+#~ msgstr ""
+
+#~ msgid "Cannot execute "
+#~ msgstr ""
+
+#~ msgid "shell "
+#~ msgstr ""
+
+#~ msgid " returned\n"
+#~ msgstr ""
+
+#~ msgid "ANCHOR_BUF_SIZE too small."
+#~ msgstr ""
+
+#~ msgid "I/O ERROR"
+#~ msgstr ""
+
+#~ msgid "Message"
+#~ msgstr ""
+
+#~ msgid "'columns' is not 80, cannot execute external commands"
+#~ msgstr ""
+
+#~ msgid "E237: Printer selection failed"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "to %s on %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E613: Unknown printer font: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E238: Print error: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Printing '%s'"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E244: Illegal charset name \"%s\" in font name \"%s\""
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E245: Illegal char '%c' in font name \"%s\""
+#~ msgstr ""
+
+#~ msgid "E366: Invalid 'osfiletype' option - using Text"
+#~ msgstr ""
+
+msgid "Vim: Double signal, exiting\n"
+msgstr "Vim: dubbel signaal, stoppen\n"
+
+#, c-format
+msgid "Vim: Caught deadly signal %s\n"
+msgstr "Vim: fataal signaal gevangen %s\n"
+
+#, c-format
+msgid "Vim: Caught deadly signal\n"
+msgstr "Vim: fataal signaal gevangen\n"
+
+#, c-format
+msgid "Opening the X display took %ld msec"
+msgstr "Openen van X-display vereiste %ld ms"
+
+#~ msgid ""
+#~ "\n"
+#~ "Vim: Got X error\n"
+#~ msgstr ""
+
+#~ msgid "Testing the X display failed"
+#~ msgstr ""
+
+#~ msgid "Opening the X display timed out"
+#~ msgstr ""
+
+#~ msgid ""
+#~ "\n"
+#~ "Could not get security context for "
+#~ msgstr ""
+
+#~ msgid ""
+#~ "\n"
+#~ "Could not set security context for "
+#~ msgstr ""
+
+#~ msgid ""
+#~ "\n"
+#~ "Cannot execute shell "
+#~ msgstr ""
+
+#~ msgid ""
+#~ "\n"
+#~ "Cannot execute shell sh\n"
+#~ msgstr ""
+
+#~ msgid ""
+#~ "\n"
+#~ "shell returned "
+#~ msgstr ""
+
+#~ msgid ""
+#~ "\n"
+#~ "Cannot create pipes\n"
+#~ msgstr ""
+
+#~ msgid ""
+#~ "\n"
+#~ "Cannot fork\n"
+#~ msgstr ""
+
+#~ msgid ""
+#~ "\n"
+#~ "Command terminated\n"
+#~ msgstr ""
+
+#~ msgid "XSMP lost ICE connection"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "dlerror = \"%s\""
+#~ msgstr ""
+
+#~ msgid "Opening the X display failed"
+#~ msgstr ""
+
+#~ msgid "XSMP handling save-yourself request"
+#~ msgstr ""
+
+#~ msgid "XSMP opening connection"
+#~ msgstr ""
+
+#~ msgid "XSMP ICE connection watch failed"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "XSMP SmcOpenConnection failed: %s"
+#~ msgstr ""
+
+msgid "At line"
+msgstr "Bij regel"
+
+#~ msgid "Could not load vim32.dll!"
+#~ msgstr ""
+
+msgid "VIM Error"
+msgstr "Vim-fout"
+
+#~ msgid "Could not fix up function pointers to the DLL!"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "shell returned %d"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Vim: Caught %s event\n"
+#~ msgstr ""
+
+msgid "close"
+msgstr "sluiten"
+
+msgid "logoff"
+msgstr "uitloggen"
+
+msgid "shutdown"
+msgstr "afsluiten"
+
+msgid "E371: Command not found"
+msgstr "E371: opdracht niet gevonden"
+
+#~ msgid ""
+#~ "VIMRUN.EXE not found in your $PATH.\n"
+#~ "External commands will not pause after completion.\n"
+#~ "See :help win32-vimrun for more information."
+#~ msgstr ""
+
+msgid "Vim Warning"
+msgstr "Vim-waarschuwing"
+
+#, c-format
+#~ msgid "E372: Too many %%%c in format string"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E373: Unexpected %%%c in format string"
+#~ msgstr ""
+
+#~ msgid "E374: Missing ] in format string"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E375: Unsupported %%%c in format string"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E376: Invalid %%%c in format string prefix"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E377: Invalid %%%c in format string"
+#~ msgstr ""
+
+#~ msgid "E378: 'errorformat' contains no pattern"
+#~ msgstr ""
+
+#~ msgid "E379: Missing or empty directory name"
+#~ msgstr ""
+
+#~ msgid "E553: No more items"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "(%d of %d)%s%s: "
+#~ msgstr ""
+
+#~ msgid " (line deleted)"
+#~ msgstr ""
+
+#~ msgid "E380: At bottom of quickfix stack"
+#~ msgstr ""
+
+#~ msgid "E381: At top of quickfix stack"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "error list %d of %d; %d errors"
+#~ msgstr ""
+
+#~ msgid "E382: Cannot write, 'buftype' option is set"
+#~ msgstr ""
+
+#~ msgid "E683: File name missing or invalid pattern"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Cannot open file \"%s\""
+#~ msgstr ""
+
+msgid "E681: Buffer is not loaded"
+msgstr "E681: buffer is niet geladen"
+
+#~ msgid "E777: String or List expected"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E369: invalid item in %s%%[]"
+#~ msgstr ""
+
+#~ msgid "E339: Pattern too long"
+#~ msgstr ""
+
+#~ msgid "E50: Too many \\z("
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E51: Too many %s("
+#~ msgstr ""
+
+msgid "E52: Unmatched \\z("
+msgstr "E52: \\z( is niet gepaard"
+
+#, c-format
+msgid "E53: Unmatched %s%%("
+msgstr "E53: %s%%( is niet gepaard"
+
+#, c-format
+msgid "E54: Unmatched %s("
+msgstr "E54: %s( is niet gepaard"
+
+#, c-format
+msgid "E55: Unmatched %s)"
+msgstr "E55: %s) is ongepaard"
+
+#, c-format
+#~ msgid "E59: invalid character after %s@"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E60: Too many complex %s{...}s"
+#~ msgstr ""
+
+#, c-format
+msgid "E61: Nested %s*"
+msgstr "E61: geneste %s*"
+
+#, c-format
+msgid "E62: Nested %s%c"
+msgstr "E62: geneste %s%c"
+
+msgid "E63: invalid use of \\_"
+msgstr "E63: onjuist gebruikt van \\_"
+
+#, c-format
+msgid "E64: %s%c follows nothing"
+msgstr "E64: %s%c volgt op niets"
+
+msgid "E65: Illegal back reference"
+msgstr "E65: ongeldige terugverwijzing"
+
+msgid "E66: \\z( not allowed here"
+msgstr "E66: \\z( hier niet toegestaan"
+
+msgid "E67: \\z1 - \\z9 not allowed here"
+msgstr "E67: \\z1 en andere hier niet toegestaan"
+
+msgid "E68: Invalid character after \\z"
+msgstr "E68: ongeldig teken na \\z"
+
+#, c-format
+msgid "E69: Missing ] after %s%%["
+msgstr "E69: ontbrekende ] na %s%%["
+
+#, c-format
+msgid "E70: Empty %s%%[]"
+msgstr "E70: leeg %s%%[]"
+
+#, c-format
+msgid "E678: Invalid character after %s%%[dxouU]"
+msgstr "E678: onjuist teken na %s%%[dxouU]"
+
+#, c-format
+msgid "E71: Invalid character after %s%%"
+msgstr "E71: onjuist teken na %s%%"
+
+#, c-format
+msgid "E769: Missing ] after %s["
+msgstr "E769: ontbrekende ] na %s["
+
+#, c-format
+msgid "E554: Syntax error in %s{...}"
+msgstr "E554: Syntaxfout in %s{...}"
+
+#~ msgid "External submatches:\n"
+#~ msgstr ""
+
+#~ msgid " VREPLACE"
+#~ msgstr ""
+
+msgid " REPLACE"
+msgstr " VERVANGEN"
+
+#~ msgid " REVERSE"
+#~ msgstr ""
+
+msgid " INSERT"
+msgstr " INVOEGEN"
+
+msgid " (insert)"
+msgstr " (invoegen)"
+
+msgid " (replace)"
+msgstr " (vervangen)"
+
+#~ msgid " (vreplace)"
+#~ msgstr ""
+
+#~ msgid " Hebrew"
+#~ msgstr ""
+
+#~ msgid " Arabic"
+#~ msgstr ""
+
+#~ msgid " (lang)"
+#~ msgstr ""
+
+#~ msgid " (paste)"
+#~ msgstr ""
+
+msgid " VISUAL"
+msgstr " VISUEEL"
+
+msgid " VISUAL LINE"
+msgstr " VISUELE REGEL"
+
+msgid " VISUAL BLOCK"
+msgstr " VISUEEL BLOK"
+
+msgid " SELECT"
+msgstr " SELECTEREN"
+
+msgid " SELECT LINE"
+msgstr " REGELSELECTIE"
+
+msgid " SELECT BLOCK"
+msgstr " BLOKSELECTIE"
+
+msgid "recording"
+msgstr "opnemen"
+
+#, c-format
+msgid "E383: Invalid search string: %s"
+msgstr "E383: ongeldige zoekstring: %s"
+
+#, c-format
+msgid "E384: search hit TOP without match for: %s"
+msgstr "E384: TOP bereikt zonder overeenkomst voor: %s"
+
+#, c-format
+msgid "E385: search hit BOTTOM without match for: %s"
+msgstr "E385: BODEM bereikt zonder overeenkomst voor: %s"
+
+msgid "E386: Expected '?' or '/' after ';'"
+msgstr "E386: verwachte '?' of '/' na ';'"
+
+msgid " (includes previously listed match)"
+msgstr " (bevat eerder getoonde overeenkomst)"
+
+#. cursor at status line
+msgid "--- Included files "
+msgstr "--- bevatte bestanden "
+
+msgid "not found "
+msgstr "niet gevonden "
+
+msgid "in path ---\n"
+msgstr "in pad ---\n"
+
+msgid " (Already listed)"
+msgstr " (Reeds getoond)"
+
+msgid " NOT FOUND"
+msgstr " NIET GEVONDEN"
+
+#, c-format
+#~ msgid "Scanning included file: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Searching included file %s"
+#~ msgstr ""
+
+#~ msgid "E387: Match is on current line"
+#~ msgstr ""
+
+#~ msgid "All included files were found"
+#~ msgstr ""
+
+#~ msgid "No included files"
+#~ msgstr ""
+
+#~ msgid "E388: Couldn't find definition"
+#~ msgstr ""
+
+msgid "E389: Couldn't find pattern"
+msgstr "E389: kan zoekpatroon niet vinden"
+
+msgid "Substitute "
+msgstr "Vervangen "
+
+#, c-format
+msgid ""
+"\n"
+"# Last %sSearch Pattern:\n"
+"~"
+msgstr ""
+"\n"
+"# Laatste %szoekpatroon:\n"
+"~"
+
+#~ msgid "E759: Format error in spell file"
+#~ msgstr ""
+
+#~ msgid "E758: Truncated spell file"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Trailing text in %s line %d: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Affix name too long in %s line %d: %s"
+#~ msgstr ""
+
+#~ msgid "E761: Format error in affix file FOL, LOW or UPP"
+#~ msgstr ""
+
+#~ msgid "E762: Character in FOL, LOW or UPP is out of range"
+#~ msgstr ""
+
+#~ msgid "Compressing word tree..."
+#~ msgstr ""
+
+#~ msgid "E756: Spell checking is not enabled"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Warning: Cannot find word list \"%s.%s.spl\" or \"%s.ascii.spl\""
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Reading spell file \"%s\""
+#~ msgstr ""
+
+#~ msgid "E757: This does not look like a spell file"
+#~ msgstr ""
+
+#~ msgid "E771: Old spell file, needs to be updated"
+#~ msgstr ""
+
+#~ msgid "E772: Spell file is for newer version of Vim"
+#~ msgstr ""
+
+#~ msgid "E770: Unsupported section in spell file"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Warning: region %s not supported"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Reading affix file %s..."
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Conversion failure for word in %s line %d: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Conversion in %s not supported: from %s to %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Conversion in %s not supported"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Invalid value for FLAG in %s line %d: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "FLAG after using flags in %s line %d: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Defining COMPOUNDFORBIDFLAG after PFX item may give wrong results in %s line %d"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Defining COMPOUNDPERMITFLAG after PFX item may give wrong results in %s line %d"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Wrong COMPOUNDRULES value in %s line %d: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Wrong COMPOUNDWORDMAX value in %s line %d: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Wrong COMPOUNDMIN value in %s line %d: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Wrong COMPOUNDSYLMAX value in %s line %d: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Wrong CHECKCOMPOUNDPATTERN value in %s line %d: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Different combining flag in continued affix block in %s line %d: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Duplicate affix in %s line %d: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Affix also used for BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST in %s line %d: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Expected Y or N in %s line %d: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Broken condition in %s line %d: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Expected REP(SAL) count in %s line %d"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Expected MAP count in %s line %d"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Duplicate character in MAP in %s line %d"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Unrecognized or duplicate item in %s line %d: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Missing FOL/LOW/UPP line in %s"
+#~ msgstr ""
+
+#~ msgid "COMPOUNDSYLMAX used without SYLLABLE"
+#~ msgstr ""
+
+#~ msgid "Too many postponed prefixes"
+#~ msgstr ""
+
+#~ msgid "Too many compound flags"
+#~ msgstr ""
+
+#~ msgid "Too many postponed prefixes and/or compound flags"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Missing SOFO%s line in %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Both SAL and SOFO lines in %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Flag is not a number in %s line %d: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Illegal flag in %s line %d: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "%s value differs from what is used in another .aff file"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Reading dictionary file %s..."
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E760: No word count in %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "line %6d, word %6d - %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Duplicate word in %s line %d: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "First duplicate word in %s line %d: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "%d duplicate word(s) in %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Ignored %d word(s) with non-ASCII characters in %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Reading word file %s..."
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Duplicate /encoding= line ignored in %s line %d: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "/encoding= line after word ignored in %s line %d: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Duplicate /regions= line ignored in %s line %d: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Too many regions in %s line %d: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "/ line ignored in %s line %d: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Invalid region nr in %s line %d: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Unrecognized flags in %s line %d: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Ignored %d words with non-ASCII characters"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Compressed %d of %d nodes; %d (%d%%) remaining"
+#~ msgstr ""
+
+#~ msgid "Reading back spell file..."
+#~ msgstr ""
+
+#.
+#. * Go through the trie of good words, soundfold each word and add it to
+#. * the soundfold trie.
+#.
+#~ msgid "Performing soundfolding..."
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Number of words after soundfolding: %ld"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Total number of words: %d"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Writing suggestion file %s..."
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Estimated runtime memory use: %d bytes"
+#~ msgstr ""
+
+#~ msgid "E751: Output file name must not have region name"
+#~ msgstr ""
+
+#~ msgid "E754: Only up to 8 regions supported"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E755: Invalid region in %s"
+#~ msgstr ""
+
+#~ msgid "Warning: both compounding and NOBREAK specified"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Writing spell file %s..."
+#~ msgstr ""
+
+#~ msgid "Done!"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E765: 'spellfile' does not have %ld entries"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Word removed from %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Word added to %s"
+#~ msgstr ""
+
+#~ msgid "E763: Word characters differ between spell files"
+#~ msgstr ""
+
+#~ msgid "Sorry, no suggestions"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Sorry, only %ld suggestions"
+#~ msgstr ""
+
+#. for when 'cmdheight' > 1
+#. avoid more prompt
+#, c-format
+#~ msgid "Change \"%.*s\" to:"
+#~ msgstr ""
+
+#, c-format
+#~ msgid " < \"%.*s\""
+#~ msgstr ""
+
+#~ msgid "E752: No previous spell replacement"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E753: Not found: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E778: This does not look like a .sug file: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E779: Old .sug file, needs to be updated: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E780: .sug file is for newer version of Vim: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E781: .sug file doesn't match .spl file: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E782: error while reading .sug file: %s"
+#~ msgstr ""
+
+#. This should have been checked when generating the .spl
+#. * file.
+#~ msgid "E783: duplicate char in MAP entry"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E390: Illegal argument: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E391: No such syntax cluster: %s"
+#~ msgstr ""
+
+#~ msgid "No Syntax items defined for this buffer"
+#~ msgstr ""
+
+#~ msgid "syncing on C-style comments"
+#~ msgstr ""
+
+#~ msgid "no syncing"
+#~ msgstr ""
+
+#~ msgid "syncing starts "
+#~ msgstr ""
+
+#~ msgid " lines before top line"
+#~ msgstr ""
+
+#~ msgid ""
+#~ "\n"
+#~ "--- Syntax sync items ---"
+#~ msgstr ""
+
+#~ msgid ""
+#~ "\n"
+#~ "syncing on items"
+#~ msgstr ""
+
+#~ msgid ""
+#~ "\n"
+#~ "--- Syntax items ---"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E392: No such syntax cluster: %s"
+#~ msgstr ""
+
+#~ msgid "minimal "
+#~ msgstr ""
+
+#~ msgid "maximal "
+#~ msgstr ""
+
+#~ msgid "; match "
+#~ msgstr ""
+
+#~ msgid " line breaks"
+#~ msgstr ""
+
+#~ msgid "E395: contains argument not accepted here"
+#~ msgstr ""
+
+#~ msgid "E396: containedin argument not accepted here"
+#~ msgstr ""
+
+#~ msgid "E393: group[t]here not accepted here"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E394: Didn't find region item for %s"
+#~ msgstr ""
+
+#~ msgid "E397: Filename required"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E789: Missing ']': %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E398: Missing '=': %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E399: Not enough arguments: syntax region %s"
+#~ msgstr ""
+
+#~ msgid "E400: No cluster specified"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E401: Pattern delimiter not found: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E402: Garbage after pattern: %s"
+#~ msgstr ""
+
+#~ msgid "E403: syntax sync: line continuations pattern specified twice"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E404: Illegal arguments: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E405: Missing equal sign: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E406: Empty argument: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E407: %s not allowed here"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E408: %s must be first in contains list"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E409: Unknown group name: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E410: Invalid :syntax subcommand: %s"
+#~ msgstr ""
+
+#~ msgid "E679: recursive loop loading syncolor.vim"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E411: highlight group not found: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E412: Not enough arguments: \":highlight link %s\""
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E413: Too many arguments: \":highlight link %s\""
+#~ msgstr ""
+
+#~ msgid "E414: group has settings, highlight link ignored"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E415: unexpected equal sign: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E416: missing equal sign: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E417: missing argument: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E418: Illegal value: %s"
+#~ msgstr ""
+
+#~ msgid "E419: FG color unknown"
+#~ msgstr ""
+
+#~ msgid "E420: BG color unknown"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E421: Color name or number not recognized: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E422: terminal code too long: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E423: Illegal argument: %s"
+#~ msgstr ""
+
+#~ msgid "E424: Too many different highlighting attributes in use"
+#~ msgstr ""
+
+#~ msgid "E669: Unprintable character in group name"
+#~ msgstr ""
+
+#~ msgid "W18: Invalid character in group name"
+#~ msgstr ""
+
+#~ msgid "E555: at bottom of tag stack"
+#~ msgstr ""
+
+#~ msgid "E556: at top of tag stack"
+#~ msgstr ""
+
+#~ msgid "E425: Cannot go before first matching tag"
+#~ msgstr ""
+
+#, c-format
+msgid "E426: tag not found: %s"
+msgstr "E426: tag niet gevonden: %s"
+
+#~ msgid " # pri kind tag"
+#~ msgstr ""
+
+#~ msgid "file\n"
+#~ msgstr ""
+
+#~ msgid "E427: There is only one matching tag"
+#~ msgstr ""
+
+#~ msgid "E428: Cannot go beyond last matching tag"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "File \"%s\" does not exist"
+#~ msgstr ""
+
+#. Give an indication of the number of matching tags
+#, c-format
+#~ msgid "tag %d of %d%s"
+#~ msgstr ""
+
+#~ msgid " or more"
+#~ msgstr ""
+
+#~ msgid " Using tag with different case!"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E429: File \"%s\" does not exist"
+#~ msgstr ""
+
+#. Highlight title
+#~ msgid ""
+#~ "\n"
+#~ " # TO tag FROM line in file/text"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Searching tags file %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E430: Tag file path truncated for %s\n"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E431: Format error in tags file \"%s\""
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Before byte %ld"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E432: Tags file not sorted: %s"
+#~ msgstr ""
+
+#. never opened any tags file
+msgid "E433: No tags file"
+msgstr "E433: geen tags-bestand"
+
+#~ msgid "Ignoring long line in tags file"
+#~ msgstr ""
+
+#~ msgid "E434: Can't find tag pattern"
+#~ msgstr ""
+
+#~ msgid "E435: Couldn't find tag, just guessing!"
+#~ msgstr ""
+
+#~ msgid "' not known. Available builtin terminals are:"
+#~ msgstr ""
+
+#~ msgid "defaulting to '"
+#~ msgstr ""
+
+#~ msgid "E557: Cannot open termcap file"
+#~ msgstr ""
+
+#~ msgid "E558: Terminal entry not found in terminfo"
+#~ msgstr ""
+
+#~ msgid "E559: Terminal entry not found in termcap"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E436: No \"%s\" entry in termcap"
+#~ msgstr ""
+
+#~ msgid "E437: terminal capability \"cm\" required"
+#~ msgstr ""
+
+#. Highlight title
+#~ msgid ""
+#~ "\n"
+#~ "--- Terminal keys ---"
+#~ msgstr ""
+
+#~ msgid "new shell started\n"
+#~ msgstr ""
+
+msgid "Vim: Error reading input, exiting...\n"
+msgstr "Vim: lezen van de invoer is mislukt. Stoppen...\n"
+
+#~ msgid "Used CUT_BUFFER0 instead of empty selection"
+#~ msgstr ""
+
+#. must display the prompt
+#~ msgid "No undo possible; continue anyway"
+#~ msgstr ""
+
+#. magic at start of header
+#. magic after last header
+#. magic at start of entry
+#. magic after last entry
+#. 2-byte undofile version number
+#. idem, encrypted
+#, c-format
+#~ msgid "E828: Cannot open undo file for writing: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E825: Corrupted undo file (%s): %s"
+#~ msgstr ""
+
+#~ msgid "Cannot write undo file in any directory in 'undodir'"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Will not overwrite with undo file, cannot read: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Will not overwrite, this is not an undo file: %s"
+#~ msgstr ""
+
+#~ msgid "Skipping undo file write, noting to undo"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Writing undo file: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E829: write error in undo file: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Not reading undo file, owner differs: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Reading undo file: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E822: Cannot open undo file for reading: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E823: Not an undo file: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E832: Non-encrypted file has encrypted undo file: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E826: Undo file decryption failed: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E827: Undo file is encrypted: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E824: Incompatible undo file: %s"
+#~ msgstr ""
+
+#~ msgid "File contents changed, cannot use undo info"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Finished reading undo file %s"
+#~ msgstr ""
+
+msgid "Already at oldest change"
+msgstr "Reeds de laatste wijziging"
+
+msgid "Already at newest change"
+msgstr "Reeds de nieuwste wijziging"
+
+#, c-format
+msgid "E830: Undo number %ld not found"
+msgstr "E830: Ongedaan-nummer %ld niet gevonden"
+
+msgid "E438: u_undo: line numbers wrong"
+msgstr "E438: u_undo: regelnummers onjuist"
+
+msgid "more line"
+msgstr "extra regel"
+
+msgid "more lines"
+msgstr "extra regel"
+
+msgid "line less"
+msgstr "regel minder"
+
+msgid "fewer lines"
+msgstr "regels minder"
+
+msgid "change"
+msgstr "wijziging"
+
+msgid "changes"
+msgstr "wijzigingen"
+
+#, c-format
+msgid "%ld %s; %s #%ld %s"
+msgstr "%ld %s; %s #%ld %s"
+
+msgid "before"
+msgstr "voor"
+
+msgid "after"
+msgstr "na"
+
+msgid "Nothing to undo"
+msgstr "Niets om ongedaan te maken"
+
+msgid "number changes time"
+msgstr "aantal wijzign tijd"
+
+#, c-format
+msgid "%ld seconds ago"
+msgstr "%ld seconden geleden"
+
+#~ msgid "E790: undojoin is not allowed after undo"
+#~ msgstr ""
+
+#~ msgid "E439: undo list corrupt"
+#~ msgstr ""
+
+#~ msgid "E440: undo line missing"
+#~ msgstr ""
+
+#. Only MS VC 4.1 and earlier can do Win32s
+msgid ""
+"\n"
+"MS-Windows 16/32-bit GUI version"
+msgstr ""
+"\n"
+"MS-Windows 16/32-bit GUI-versie"
+
+msgid ""
+"\n"
+"MS-Windows 64-bit GUI version"
+msgstr ""
+"\n"
+"MS-Windows 64-bit GUI-versie"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit GUI version"
+msgstr ""
+"\n"
+"MS-Windows 32-bit GUIversie"
+
+msgid " in Win32s mode"
+msgstr " in Win32s-modus"
+
+msgid " with OLE support"
+msgstr "met OLE-ondersteuning"
+
+msgid ""
+"\n"
+"MS-Windows 64-bit console version"
+msgstr ""
+"\n"
+"MS-Windows 64-bit console-versie"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit console version"
+msgstr ""
+"\n"
+"MS-Windows 32-bit console-versie"
+
+msgid ""
+"\n"
+"MS-Windows 16-bit version"
+msgstr ""
+"\n"
+"MS-Windows 16-bit-versie"
+
+msgid ""
+"\n"
+"32-bit MS-DOS version"
+msgstr ""
+"\n"
+"32-bit MS-DOS-versie"
+
+msgid ""
+"\n"
+"16-bit MS-DOS version"
+msgstr ""
+"\n"
+"16-bit MS-DOS-versie"
+
+msgid ""
+"\n"
+"MacOS X (unix) version"
+msgstr ""
+"\n"
+"MacOS X (unix)-versie"
+
+msgid ""
+"\n"
+"MacOS X-versie"
+msgstr ""
+"\n"
+"MacOS X version"
+
+msgid ""
+"\n"
+"MacOS version"
+msgstr ""
+"\n"
+"MacOS-versie"
+
+msgid ""
+"\n"
+"RISC OS version"
+msgstr ""
+"\n"
+"RISC OS-versie"
+
+msgid ""
+"\n"
+"OpenVMS version"
+msgstr ""
+"\n"
+"OpenVMS-versie"
+
+msgid ""
+"\n"
+"Included patches: "
+msgstr ""
+"\n"
+"Inclusief 'patches': "
+
+msgid ""
+"\n"
+"Extra patches: "
+msgstr ""
+"\n"
+"Extra 'patches': "
+
+msgid "Modified by "
+msgstr "Aangepast door "
+
+msgid ""
+"\n"
+"Compiled "
+msgstr ""
+"\n"
+"Gecompileerd "
+
+msgid "by "
+msgstr "door "
+
+msgid ""
+"\n"
+"Huge version "
+msgstr ""
+"\n"
+"Enorme versie "
+
+msgid ""
+"\n"
+"Big version "
+msgstr ""
+"\n"
+"Grote versie "
+
+msgid ""
+"\n"
+"Normal version "
+msgstr ""
+"\n"
+"Normale versie "
+
+msgid ""
+"\n"
+"Small version "
+msgstr ""
+"\n"
+"Kleine versie "
+
+msgid ""
+"\n"
+"Tiny version "
+msgstr ""
+"\n"
+"Mini versie "
+
+#~ msgid "without GUI."
+#~ msgstr ""
+
+#~ msgid "with GTK2-GNOME GUI."
+#~ msgstr ""
+
+#~ msgid "with GTK-GNOME GUI."
+#~ msgstr ""
+
+#~ msgid "with GTK2 GUI."
+#~ msgstr ""
+
+#~ msgid "with GTK GUI."
+#~ msgstr ""
+
+#~ msgid "with X11-Motif GUI."
+#~ msgstr ""
+
+#~ msgid "with X11-neXtaw GUI."
+#~ msgstr ""
+
+#~ msgid "with X11-Athena GUI."
+#~ msgstr ""
+
+#~ msgid "with Photon GUI."
+#~ msgstr ""
+
+#~ msgid "with GUI."
+#~ msgstr ""
+
+#~ msgid "with Carbon GUI."
+#~ msgstr ""
+
+#~ msgid "with Cocoa GUI."
+#~ msgstr ""
+
+#~ msgid "with (classic) GUI."
+#~ msgstr ""
+
+#~ msgid " Features included (+) or not (-):\n"
+#~ msgstr ""
+
+#~ msgid " system vimrc file: \""
+#~ msgstr ""
+
+#~ msgid " user vimrc file: \""
+#~ msgstr ""
+
+#~ msgid " 2nd user vimrc file: \""
+#~ msgstr ""
+
+#~ msgid " 3rd user vimrc file: \""
+#~ msgstr ""
+
+#~ msgid " user exrc file: \""
+#~ msgstr ""
+
+#~ msgid " 2nd user exrc file: \""
+#~ msgstr ""
+
+#~ msgid " system gvimrc file: \""
+#~ msgstr ""
+
+#~ msgid " user gvimrc file: \""
+#~ msgstr ""
+
+#~ msgid "2nd user gvimrc file: \""
+#~ msgstr ""
+
+#~ msgid "3rd user gvimrc file: \""
+#~ msgstr ""
+
+#~ msgid " system menu file: \""
+#~ msgstr ""
+
+#~ msgid " fall-back for $VIM: \""
+#~ msgstr ""
+
+#~ msgid " f-b for $VIMRUNTIME: \""
+#~ msgstr ""
+
+msgid "Compilation: "
+msgstr "Compilatie: "
+
+msgid "Compiler: "
+msgstr "Compiler: "
+
+msgid "Linking: "
+msgstr "Linking: "
+
+msgid " DEBUG BUILD"
+msgstr " DEBUG BUILD"
+
+msgid "VIM - Vi IMproved"
+msgstr "VIM - Vi IMproved"
+
+msgid "version "
+msgstr "versie "
+
+msgid "by Bram Moolenaar et al."
+msgstr "door Bram Moolenaar en anderen"
+
+msgid "Vim is open source and freely distributable"
+msgstr "Vim is open-source en vrij verspreidbaar"
+
+msgid "Help poor children in Uganda!"
+msgstr "Help arme kinderen in Uganda!"
+
+msgid "type :help iccf<Enter> for information "
+msgstr "typ :help iccf<Enter> voor informatie"
+
+msgid "type :q<Enter> to exit"
+msgstr "typ :q<Enter> om te stoppen"
+
+msgid "type :help<Enter> or <F1> for on-line help"
+msgstr "typ :help<Enter> of <F1> voor on-line hulp"
+
+msgid "type :help version8<Enter> for version info"
+msgstr "typ :help version8<Enter> voor versieinformatie"
+
+msgid "Running in Vi compatible mode"
+msgstr "wordt uitgevoerd in Vi compatible-modus"
+
+msgid "type :set nocp<Enter> for Vim defaults"
+msgstr "typ :set nocp<Enter> voor standaardinstellingen van Vim"
+
+msgid "type :help cp-default<Enter> for info on this"
+msgstr "typ :help cp-default<Enter> voor informatie hierover"
+
+msgid "menu Help->Orphans for information "
+msgstr "menu Help->Orphans voor informatie"
+
+#~ msgid "Running modeless, typed text is inserted"
+#~ msgstr ""
+
+#~ msgid "menu Edit->Global Settings->Toggle Insert Mode "
+#~ msgstr ""
+
+#~ msgid " for two modes "
+#~ msgstr ""
+
+#~ msgid "menu Edit->Global Settings->Toggle Vi Compatible"
+#~ msgstr ""
+
+#~ msgid " for Vim defaults "
+#~ msgstr ""
+
+msgid "Sponsor Vim development!"
+msgstr "Ondersteun de ontwikkeling van Vim!"
+
+msgid "Become a registered Vim user!"
+msgstr "Word een geregistreerde Vim-gebruiker!"
+
+msgid "type :help sponsor<Enter> for information "
+msgstr "typ :help sponsor<Enter> voor informatie "
+
+msgid "type :help register<Enter> for information "
+msgstr "typ :help register<Enter> voor informatie "
+
+msgid "menu Help->Sponsor/Register for information "
+msgstr "menu Help->Sponsor/Register voor informatie "
+
+msgid "WARNING: Windows 95/98/ME detected"
+msgstr "Waarschuwing: Windows 95/98/ME gedetecteerd"
+
+msgid "type :help windows95<Enter> for info on this"
+msgstr "typ :help windows95<Enter> voor informatie hierover"
+
+msgid "Already only one window"
+msgstr "Reeds beperkt tot een venster"
+
+msgid "E441: There is no preview window"
+msgstr "E441: er is geen voorvertoningsvenster"
+
+msgid "E442: Can't split topleft and botright at the same time"
+msgstr "E442: kan linkerbovenzijde en rechteronderzijde niet gelijktijdig splitsen"
+
+#~ msgid "E443: Cannot rotate when another window is split"
+#~ msgstr ""
+
+msgid "E444: Cannot close last window"
+msgstr "E444: sluiten laatste venster is mislukt"
+
+msgid "E813: Cannot close autocmd window"
+msgstr "E813: sluiten autocmd-venster is mislukt"
+
+msgid "E814: Cannot close window, only autocmd window would remain"
+msgstr "E814: venster kan niet sluiten want autocmd-venster blijft als enige achter"
+
+msgid "E445: Other window contains changes"
+msgstr "E445: ander venster blijft achter"
+
+msgid "E446: No file name under cursor"
+msgstr "E446: cursor staat niet op een bestandsnaam"
+
+#, c-format
+msgid "E447: Can't find file \"%s\" in path"
+msgstr "E447: bestand \"%s\" niet in pad gevonden"
+
+#, c-format
+msgid "E370: Could not load library %s"
+msgstr "E370: laden van bibliotheek %s is mislukt"
+
+#~ msgid "Sorry, this command is disabled: the Perl library could not be loaded."
+#~ msgstr ""
+
+#~ msgid "E299: Perl evaluation forbidden in sandbox without the Safe module"
+#~ msgstr ""
+
+#~ msgid "Edit with &multiple Vims"
+#~ msgstr ""
+
+#~ msgid "Edit with single &Vim"
+#~ msgstr ""
+
+#~ msgid "Diff with Vim"
+#~ msgstr ""
+
+#~ msgid "Edit with &Vim"
+#~ msgstr ""
+
+#. Now concatenate
+#~ msgid "Edit with existing Vim - "
+#~ msgstr ""
+
+#~ msgid "Edits the selected file(s) with Vim"
+#~ msgstr ""
+
+#~ msgid "Error creating process: Check if gvim is in your path!"
+#~ msgstr ""
+
+#~ msgid "gvimext.dll error"
+#~ msgstr ""
+
+#~ msgid "Path length too long!"
+#~ msgstr ""
+
+msgid "--No lines in buffer--"
+msgstr "-- geen regels in buffer --"
+
+#.
+#. * The error messages that can be shared are included here.
+#. * Excluded are errors that are only used once and debugging messages.
+#.
+msgid "E470: Command aborted"
+msgstr "E470: opdracht afgebroken"
+
+msgid "E471: Argument required"
+msgstr "E471: Argument vereist"
+
+msgid "E10: \\ should be followed by /, ? or &"
+msgstr "E10: \\ moet worden gevolgd door /, ? of &"
+
+msgid "E11: Invalid in command-line window; <CR> executes, CTRL-C quits"
+msgstr "E11: ongeldig in opdrachtregelvenster; <CR> voert uit, CTRL-C stopt"
+
+#~ msgid "E12: Command not allowed from exrc/vimrc in current dir or tag search"
+#~ msgstr ""
+
+#~ msgid "E171: Missing :endif"
+#~ msgstr ""
+
+#~ msgid "E600: Missing :endtry"
+#~ msgstr ""
+
+#~ msgid "E170: Missing :endwhile"
+#~ msgstr ""
+
+#~ msgid "E170: Missing :endfor"
+#~ msgstr ""
+
+#~ msgid "E588: :endwhile without :while"
+#~ msgstr ""
+
+#~ msgid "E588: :endfor without :for"
+#~ msgstr ""
+
+#~ msgid "E13: File exists (add ! to override)"
+#~ msgstr ""
+
+#~ msgid "E472: Command failed"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E234: Unknown fontset: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E235: Unknown font: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E236: Font \"%s\" is not fixed-width"
+#~ msgstr ""
+
+msgid "E473: Internal error"
+msgstr "E473: interne fout"
+
+msgid "Interrupted"
+msgstr "onderbroken"
+
+msgid "E14: Invalid address"
+msgstr "E14: ongeldig adres"
+
+msgid "E474: Invalid argument"
+msgstr "E474: ongeldig argument"
+
+#, c-format
+msgid "E475: Invalid argument: %s"
+msgstr "E475: ongeldig argument: %s"
+
+#, c-format
+msgid "E15: Invalid expression: %s"
+msgstr "E15: ongeldige expressie: %s"
+
+msgid "E16: Invalid range"
+msgstr "E16: ongeldig bereik"
+
+msgid "E476: Invalid command"
+msgstr "E476: ongeldige opdracht"
+
+#, c-format
+#~ msgid "E17: \"%s\" is a directory"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E364: Library call failed for \"%s()\""
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E448: Could not load library function %s"
+#~ msgstr ""
+
+msgid "E19: Mark has invalid line number"
+msgstr "E19: markering heeft een ongeldig regelnummer"
+
+msgid "E20: Mark not set"
+msgstr "E20: Markering is niet ingesteld"
+
+msgid "E21: Cannot make changes, 'modifiable' is off"
+msgstr "E21: kan geen veranderingen maken, 'modifiable' is uitgeschakeld"
+
+msgid "E22: Scripts nested too deep"
+msgstr "E22: scripts "
+
+#~ msgid "E23: No alternate file"
+#~ msgstr ""
+
+#~ msgid "E24: No such abbreviation"
+#~ msgstr ""
+
+#~ msgid "E477: No ! allowed"
+#~ msgstr ""
+
+#~ msgid "E25: GUI cannot be used: Not enabled at compile time"
+#~ msgstr ""
+
+#~ msgid "E26: Hebrew cannot be used: Not enabled at compile time\n"
+#~ msgstr ""
+
+#~ msgid "E27: Farsi cannot be used: Not enabled at compile time\n"
+#~ msgstr ""
+
+#~ msgid "E800: Arabic cannot be used: Not enabled at compile time\n"
+#~ msgstr ""
+
+#, c-format
+msgid "E28: No such highlight group name: %s"
+msgstr "E28: naam van deze oplichtgroep is onbekend: %s"
+
+#~ msgid "E29: No inserted text yet"
+#~ msgstr ""
+
+#~ msgid "E30: No previous command line"
+#~ msgstr ""
+
+#~ msgid "E31: No such mapping"
+#~ msgstr ""
+
+msgid "E479: No match"
+msgstr "E479: geen overeenkomst"
+
+#, c-format
+msgid "E480: No match: %s"
+msgstr "E480: geen overeenkomst: %s"
+
+msgid "E32: No file name"
+msgstr "E32: geen bestandsnaam"
+
+msgid "E33: No previous substitute regular expression"
+msgstr "E33: geen eerdere reguliere expressie substitutie"
+
+msgid "E34: No previous command"
+msgstr "E34: geen eerdere opdracht"
+
+msgid "E35: No previous regular expression"
+msgstr "E35: geen eerdere reguliere expressie"
+
+msgid "E481: No range allowed"
+msgstr "E481: een bereik is niet toegestaan"
+
+msgid "E36: Not enough room"
+msgstr "E36: onvoldoende ruimte"
+
+#, c-format
+msgid "E247: no registered server named \"%s\""
+msgstr "E247: \"%s\" niet gevonden als geregistreerde server"
+
+#, c-format
+msgid "E482: Can't create file %s"
+msgstr "E482: aanmaken bestand %s is mislukt"
+
+msgid "E483: Can't get temp file name"
+msgstr "E483: bepalen naam tijdelijk bestand is mislukt"
+
+#, c-format
+msgid "E484: Can't open file %s"
+msgstr "E484: openen bestand %s is mislukt"
+
+#, c-format
+msgid "E485: Can't read file %s"
+msgstr "E485: lezen bestand %s is mislukt"
+
+msgid "E37: No write since last change (add ! to override)"
+msgstr "E37: niets opgeslagen sinds laatste wijziging (voeg ! toe om te forceren)"
+
+msgid "E38: Null argument"
+msgstr "E38: leeg argument (null)"
+
+msgid "E39: Number expected"
+msgstr "E39: getal verwacht"
+
+#, c-format
+msgid "E40: Can't open errorfile %s"
+msgstr "E40: openen foutenbestand %s is mislukt"
+
+msgid "E233: cannot open display"
+msgstr "E233: openen scherm is mislukt"
+
+msgid "E41: Out of memory!"
+msgstr "E41: te weinig geheugen!"
+
+msgid "Pattern not found"
+msgstr "patroon niet gevonden"
+
+#, c-format
+msgid "E486: Pattern not found: %s"
+msgstr "E486: patroon niet gevonden: %s"
+
+msgid "E487: Argument must be positive"
+msgstr "E487: argument moet positief zijn"
+
+msgid "E459: Cannot go back to previous directory"
+msgstr "E459: kan niet terug naar vorig Dictionary"
+
+msgid "E42: No Errors"
+msgstr "E42: geen fouten"
+
+#~ msgid "E776: No location list"
+#~ msgstr ""
+
+msgid "E43: Damaged match string"
+msgstr "E43: beschadigde zoekstring"
+
+msgid "E44: Corrupted regexp program"
+msgstr "E44: regexp-programma is misvormd"
+
+msgid "E45: 'readonly' option is set (add ! to override)"
+msgstr "E45: 'alleen-lezen'-optie is ingeschakeld (voeg ! toe om te overschrijven)"
+
+#, c-format
+msgid "E46: Cannot change read-only variable \"%s\""
+msgstr "E46: kan alleen-lezenvariabele \"%s\" niet veranderen"
+
+#, c-format
+msgid "E794: Cannot set variable in the sandbox: \"%s\""
+msgstr "E794: kan variabele niet instellen in de zandbak: \"%s\""
+
+msgid "E47: Error while reading errorfile"
+msgstr "E47: fout tijdens lezen foutenbestand"
+
+msgid "E48: Not allowed in sandbox"
+msgstr "E48: niet toegestaan in zandbak"
+
+msgid "E523: Not allowed here"
+msgstr "E523: hier niet toegestaan"
+
+msgid "E359: Screen mode setting not supported"
+msgstr "E359: instelling schermmodus niet ondersteund"
+
+msgid "E49: Invalid scroll size"
+msgstr "E49: ongeldige scroll-grootte"
+
+msgid "E91: 'shell' option is empty"
+msgstr "E91: 'shell'-optie is leeg"
+
+#~ msgid "E255: Couldn't read in sign data!"
+#~ msgstr ""
+
+#~ msgid "E72: Close error on swap file"
+#~ msgstr ""
+
+#~ msgid "E73: tag stack empty"
+#~ msgstr ""
+
+msgid "E74: Command too complex"
+msgstr "E74: opdracht te ingewikkeld"
+
+msgid "E75: Name too long"
+msgstr "E75: te lange naam"
+
+msgid "E76: Too many ["
+msgstr "E76: teveel ["
+
+msgid "E77: Too many file names"
+msgstr "E77: teveel bestandsnamen"
+
+msgid "E488: Trailing characters"
+msgstr "E488: nakomende tekens"
+
+msgid "E78: Unknown mark"
+msgstr "E78: onbekende markering"
+
+msgid "E79: Cannot expand wildcards"
+msgstr "E79: vervangen jokertekens is mislukt"
+
+msgid "E591: 'winheight' cannot be smaller than 'winminheight'"
+msgstr "E591: 'winheight' kan niet kleiner zijn dan 'winminheight'"
+
+msgid "E592: 'winwidth' cannot be smaller than 'winminwidth'"
+msgstr "E592: 'winwidth' kan niet kleiner zijn dan 'winminwidth'"
+
+msgid "E80: Error while writing"
+msgstr "E80: opslaan is mislukt"
+
+msgid "Zero count"
+msgstr "Aantal is nul"
+
+msgid "E81: Using <SID> not in a script context"
+msgstr "E81: <SID> wordt buiten de scriptcontext gebruikt"
+
+msgid "E449: Invalid expression received"
+msgstr "E449: ontvangen expressie is ongeldig"
+
+msgid "E463: Region is guarded, cannot modify"
+msgstr "E463: Regio is bescherm en kan niet worden veranderd"
+
+msgid "E744: NetBeans does not allow changes in read-only files"
+msgstr "E744: NetBeans staat geen veranderingen in alleen-lezenbestanden toe"
+
+#, c-format
+msgid "E685: Internal error: %s"
+msgstr "E685: interne fout: %s"
+
+msgid "E363: pattern uses more memory than 'maxmempattern'"
+msgstr "E363: patroon gebruikt meer geheugen dan 'maxmempattern'"
+
+msgid "E749: empty buffer"
+msgstr "E749: leeg buffer"
+
+msgid "E682: Invalid search pattern or delimiter"
+msgstr "E682: zoekpatroon of scheidingsteken is ongeldig"
+
+msgid "E139: File is loaded in another buffer"
+msgstr "E139: bestand is in een ander buffer geladen"
+
+#, c-format
+msgid "E764: Option '%s' is not set"
+msgstr "E764: Optie '%s' is niet ingesteld"
+
+msgid "search hit TOP, continuing at BOTTOM"
+msgstr "zoeken bereikte TOP, verder vanaf BODEM"
+
+msgid "search hit BOTTOM, continuing at TOP"
+msgstr "zoeken bereikte BODEM, verder vanaf TOP"
+
diff --git a/src/po/no.po b/src/po/no.po
new file mode 100644
index 0000000..98033a1
--- /dev/null
+++ b/src/po/no.po
@@ -0,0 +1,6166 @@
+# Norwegian (Bokmål) translation of Vim.
+# Copyright (C) 2003-2007 Free Software Foundation, Inc.
+# FIRST AUTHOR Øyvind A. Holm <sunny@sunbase.org>, 2003-2007.
+# Id: no.po 435 2007-03-21 10:52:22Z sunny256
+#
+# Comments and error reports appreciated.
+#
+# Information about the "Vim in Norwegian" project:
+#
+# http://www.sunbase.org/src/vim/norwegian/
+#
+# New versions of the translation files can be downloaded in .tar.gz
+# format from
+#
+# http://svn.sunbase.org/repos/norwegian_vim/download/
+#
+# The files are stored in the Subversion version control system and
+# users of this software can check out the latest version with
+#
+# svn checkout http://svn.sunbase.org/repos/norwegian_vim/trunk/msgs norwegian_vim-msgs
+#
+# This will place the message files into the "norwegian_vim-msgs"
+# directory.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Vim 6.x\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2007-03-19 02:09+0100\n"
+"PO-Revision-Date: 2007-03-21 11:51+0100\n"
+"Last-Translator: Øyvind A. Holm <sunny@sunbase.org>\n"
+"Language-Team: Norwegian <vim.in.norwegian@sunbase.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-1\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "E82: Cannot allocate any buffer, exiting..."
+msgstr "E82: Kan ikke reservere plass til noen buffere, avslutter ..."
+
+msgid "E83: Cannot allocate buffer, using other one..."
+msgstr "E83: Kan ikke reservere plass til buffer, bruker en annen ..."
+
+msgid "E515: No buffers were unloaded"
+msgstr "E515: Ingen buffere ble lastet ut"
+
+msgid "E516: No buffers were deleted"
+msgstr "E516: Ingen buffere ble slettet"
+
+msgid "E517: No buffers were wiped out"
+msgstr "E517: Ingen buffere ble visket ut"
+
+msgid "1 buffer unloaded"
+msgstr "1 buffer ble lastet ut"
+
+#, c-format
+msgid "%d buffers unloaded"
+msgstr "%d buffere ble lastet ut"
+
+msgid "1 buffer deleted"
+msgstr "1 buffer ble slettet"
+
+#, c-format
+msgid "%d buffers deleted"
+msgstr "%d buffere ble slettet"
+
+msgid "1 buffer wiped out"
+msgstr "1 buffer ble visket ut"
+
+#, c-format
+msgid "%d buffers wiped out"
+msgstr "%d buffere ble visket ut"
+
+msgid "E84: No modified buffer found"
+msgstr "E84: Fant ingen modifisert buffer"
+
+#. back where we started, didn't find anything.
+msgid "E85: There is no listed buffer"
+msgstr "E85: Det finnes ingen listede buffere"
+
+#, c-format
+msgid "E86: Buffer %ld does not exist"
+msgstr "E86: Bufferen %ld finnes ikke"
+
+msgid "E87: Cannot go beyond last buffer"
+msgstr "E87: Kan ikke gå forbi siste buffer"
+
+msgid "E88: Cannot go before first buffer"
+msgstr "E88: Kan ikke gå forbi første buffer"
+
+#, c-format
+msgid "E89: No write since last change for buffer %ld (add ! to override)"
+msgstr ""
+"E89: Ikke lagret siden forrige forandring av bufferen %ld (legg til ! for å "
+"overstyre)"
+
+msgid "E90: Cannot unload last buffer"
+msgstr "E90: Kan ikke laste ut siste buffer"
+
+msgid "W14: Warning: List of file names overflow"
+msgstr "W14: Advarsel: Listen med filnavn er overfylt"
+
+#, c-format
+msgid "E92: Buffer %ld not found"
+msgstr "E92: Fant ikke bufferen %ld"
+
+#, c-format
+msgid "E93: More than one match for %s"
+msgstr "E93: Mer enn ett treff for %s"
+
+#, c-format
+msgid "E94: No matching buffer for %s"
+msgstr "E94: Ingen samsvarende buffer for %s"
+
+#, c-format
+msgid "line %ld"
+msgstr "linje %ld"
+
+msgid "E95: Buffer with this name already exists"
+msgstr "E95: En buffer med dette navnet finnes allerede"
+
+msgid " [Modified]"
+msgstr " [Modifisert]"
+
+msgid "[Not edited]"
+msgstr "[Uredigert]"
+
+msgid "[New file]"
+msgstr "[Ny fil]"
+
+msgid "[Read errors]"
+msgstr "[Lesefeil]"
+
+msgid "[readonly]"
+msgstr "[skrivebeskyttet]"
+
+#, c-format
+msgid "1 line --%d%%--"
+msgstr "1 linje --%d%%--"
+
+#, c-format
+msgid "%ld lines --%d%%--"
+msgstr "%ld linjer --%d%%--"
+
+#, c-format
+msgid "line %ld of %ld --%d%%-- col "
+msgstr "linje %ld av %ld --%d%%-- kol "
+
+msgid "[No Name]"
+msgstr "[Uten navn]"
+
+#. must be a help buffer
+msgid "help"
+msgstr "hjelp"
+
+msgid "[Help]"
+msgstr "[Hjelp]"
+
+msgid "[Preview]"
+msgstr "[Forhåndsvisning]"
+
+msgid "All"
+msgstr "Alt"
+
+msgid "Bot"
+msgstr "Bunn"
+
+msgid "Top"
+msgstr "Topp"
+
+#, c-format
+msgid ""
+"\n"
+"# Buffer list:\n"
+msgstr ""
+"\n"
+"# Bufferliste:\n"
+
+msgid "[Location List]"
+msgstr "[Plassliste]"
+
+#~ msgid "[Quickfix List]"
+#~ msgstr ""
+
+msgid ""
+"\n"
+"--- Signs ---"
+msgstr ""
+"\n"
+"--- Skilt ---"
+
+#, c-format
+msgid "Signs for %s:"
+msgstr "Skilt for %s:"
+
+#, c-format
+msgid " line=%ld id=%d name=%s"
+msgstr " linje=%ld id=%d navn=%s"
+
+#, c-format
+msgid "E96: Can not diff more than %ld buffers"
+msgstr "E96: Kan ikke sammenligne flere enn %ld buffere"
+
+msgid "E97: Cannot create diffs"
+msgstr "E97: Kan ikke lage differansefiler"
+
+msgid "Patch file"
+msgstr "Patch fil"
+
+msgid "E98: Cannot read diff output"
+msgstr "E98: Kan ikke lese differanse-utdata"
+
+msgid "E99: Current buffer is not in diff mode"
+msgstr "E99: Nåværende buffer er ikke i differansemodus"
+
+msgid "E793: No other buffer in diff mode is modifiable"
+msgstr "E793: Ingen annen buffer i differansemodus er redigerbar"
+
+msgid "E100: No other buffer in diff mode"
+msgstr "E100: Ingen annen buffer i differansemodus"
+
+msgid "E101: More than two buffers in diff mode, don't know which one to use"
+msgstr ""
+"E101: Mer enn to buffere i differansemodus, vet ikke hvilken som skal brukes"
+
+#, c-format
+msgid "E102: Can't find buffer \"%s\""
+msgstr "E102: Kan ikke finne buffer \"%s\""
+
+#, c-format
+msgid "E103: Buffer \"%s\" is not in diff mode"
+msgstr "E103: Bufferen \"%s\" er ikke i differansemodus"
+
+msgid "E787: Buffer changed unexpectedly"
+msgstr "E787: Uventet forandring i buffer"
+
+msgid "E104: Escape not allowed in digraph"
+msgstr "E104: Escape er ikke lovlig i spesialtegn"
+
+msgid "E544: Keymap file not found"
+msgstr "E544: Fant ikke keymap-fil"
+
+msgid "E105: Using :loadkeymap not in a sourced file"
+msgstr "E105: Bruk av :loadkeymap utenfor en kjørt fil"
+
+msgid "E791: Empty keymap entry"
+msgstr "E791: Tom tastaturoppsett-oppføring"
+
+msgid " Keyword completion (^N^P)"
+msgstr " Nøkkelordfullføring (^N^P)"
+
+#. ctrl_x_mode == 0, ^P/^N compl.
+#, fuzzy
+#~ msgid " ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+#~ msgstr " ^X-modus (^]^D^E^F^I^K^L^N^O^P^S^U^V^Y)"
+
+msgid " Whole line completion (^L^N^P)"
+msgstr " Fullføring av hel linje (^L^N^P)"
+
+msgid " File name completion (^F^N^P)"
+msgstr " Fullføring av filnavn (^F^N^P)"
+
+msgid " Tag completion (^]^N^P)"
+msgstr " Fullføring av tag (^]^N^P)"
+
+msgid " Path pattern completion (^N^P)"
+msgstr " Stimønster-fullføring (^N^P)"
+
+msgid " Definition completion (^D^N^P)"
+msgstr " Fullføring av defineringer (^D^N^P)"
+
+msgid " Dictionary completion (^K^N^P)"
+msgstr " Fullføring fra ordliste (^K^N^P)"
+
+msgid " Thesaurus completion (^T^N^P)"
+msgstr " Thesaurus-fullføring (^T^N^P)"
+
+msgid " Command-line completion (^V^N^P)"
+msgstr " Kommandolinje-fullføring (^V^N^P)"
+
+msgid " User defined completion (^U^N^P)"
+msgstr " Brukerdefinert fullføring (^U^N^P)"
+
+msgid " Omni completion (^O^N^P)"
+msgstr " Omni-fullføring (^O^N^P)"
+
+#, fuzzy
+#~ msgid " Spelling suggestion (s^N^P)"
+#~ msgstr " Staveforslag (^S^N^P)"
+
+msgid " Keyword Local completion (^N^P)"
+msgstr " Lokal nøkkelordfullføring (^N^P)"
+
+msgid "Hit end of paragraph"
+msgstr "Kom til slutten av avsnittet"
+
+msgid "'dictionary' option is empty"
+msgstr "'dictionary'-valget er tomt"
+
+msgid "'thesaurus' option is empty"
+msgstr "'thesaurus'-valget er tomt"
+
+#, c-format
+msgid "Scanning dictionary: %s"
+msgstr "Leter gjennom ordliste: %s"
+
+msgid " (insert) Scroll (^E/^Y)"
+msgstr " (sett inn) Rulling (^E/^Y)"
+
+msgid " (replace) Scroll (^E/^Y)"
+msgstr " (erstatt) Rulling (^E/^Y)"
+
+#, c-format
+msgid "Scanning: %s"
+msgstr "Leter: %s"
+
+#, c-format
+msgid "Scanning tags."
+msgstr "Leter gjennom tagger."
+
+msgid " Adding"
+msgstr " Legger til"
+
+#. showmode might reset the internal line pointers, so it must
+#. * be called before line = ml_get(), or when this address is no
+#. * longer needed. -- Acevedo.
+#.
+msgid "-- Searching..."
+msgstr "-- Søker ..."
+
+msgid "Back at original"
+msgstr "Tilbake i originalen"
+
+msgid "Word from other line"
+msgstr "Ord fra annen linje"
+
+msgid "The only match"
+msgstr "Det eneste treffet"
+
+#, c-format
+msgid "match %d of %d"
+msgstr "treff %d av %d"
+
+#, c-format
+msgid "match %d"
+msgstr "treff %d"
+
+msgid "E18: Unexpected characters in :let"
+msgstr "E18: Uventede tegn i :let"
+
+#, c-format
+msgid "E684: list index out of range: %ld"
+msgstr "E684: Listeindeks utenfor område: %ld"
+
+#, c-format
+msgid "E121: Undefined variable: %s"
+msgstr "E121: Udefinert variabel: %s"
+
+msgid "E111: Missing ']'"
+msgstr "E111: Mangler ']'"
+
+#, c-format
+msgid "E686: Argument of %s must be a List"
+msgstr "E686: Parameter til %s må være en liste"
+
+#, c-format
+msgid "E712: Argument of %s must be a List or Dictionary"
+msgstr "E712: Parameter til %s må være en liste eller ordliste"
+
+msgid "E713: Cannot use empty key for Dictionary"
+msgstr "E713: Kan ikke bruke tom nøkkel med ordliste"
+
+msgid "E714: List required"
+msgstr "E714: Liste påkrevet"
+
+msgid "E715: Dictionary required"
+msgstr "E715: Ordliste påkrevet"
+
+#, c-format
+msgid "E118: Too many arguments for function: %s"
+msgstr "E118: For mange parametere til funksjonen: %s"
+
+#, c-format
+msgid "E716: Key not present in Dictionary: %s"
+msgstr "E716: Nøkkelen finnes ikke i ordliste: %s"
+
+#, c-format
+msgid "E122: Function %s already exists, add ! to replace it"
+msgstr "E122: Funksjonen %s eksisterer allerede, legg til ! for å erstatte den"
+
+msgid "E717: Dictionary entry already exists"
+msgstr "E717: Ordlisteoppføring finnes allerede"
+
+msgid "E718: Funcref required"
+msgstr "E718: Funksjonsreferanse nødvendig"
+
+msgid "E719: Cannot use [:] with a Dictionary"
+msgstr "E719: Kan ikke bruke [:] sammen med en ordliste"
+
+#, c-format
+msgid "E734: Wrong variable type for %s="
+msgstr "E734: Feil variabeltype for %s="
+
+#, c-format
+msgid "E130: Unknown function: %s"
+msgstr "E130: Ukjent funksjon: %s"
+
+#, c-format
+msgid "E461: Illegal variable name: %s"
+msgstr "E461: Ugyldig variabelnavn: %s"
+
+msgid "E687: Less targets than List items"
+msgstr "E687: Færre mål enn listeelementer"
+
+msgid "E688: More targets than List items"
+msgstr "E688: Flere mål enn listeelementer"
+
+msgid "Double ; in list of variables"
+msgstr "Dobbel ; i variabelliste"
+
+#, c-format
+msgid "E738: Can't list variables for %s"
+msgstr "E738: Kan ikke liste variabler for %s"
+
+msgid "E689: Can only index a List or Dictionary"
+msgstr "E689: Kan bare indeksere en liste eller ordliste"
+
+msgid "E708: [:] must come last"
+msgstr "E708: [:] må komme sist"
+
+msgid "E709: [:] requires a List value"
+msgstr "E709: [:] krever en listeverdi"
+
+msgid "E710: List value has more items than target"
+msgstr "E710: Listeverdien har flere elementer enn mål"
+
+msgid "E711: List value has not enough items"
+msgstr "E711: Listeverdien har ikke nok elementer"
+
+msgid "E690: Missing \"in\" after :for"
+msgstr "E690: Mangler \"in\" etter :for"
+
+#, c-format
+msgid "E107: Missing parentheses: %s"
+msgstr "E107: Mangler parenteser: %s"
+
+#, c-format
+msgid "E108: No such variable: \"%s\""
+msgstr "E108: Variabelen finnes ikke: \"%s\""
+
+msgid "E743: variable nested too deep for (un)lock"
+msgstr "E743: Variabel nøstet for dypt for (un)lock"
+
+msgid "E109: Missing ':' after '?'"
+msgstr "E109: Mangler ':' etter '?'"
+
+msgid "E691: Can only compare List with List"
+msgstr "E691: Kan bare sammenligne liste med liste"
+
+msgid "E692: Invalid operation for List"
+msgstr "E692: Ugyldig operasjon for liste"
+
+msgid "E735: Can only compare Dictionary with Dictionary"
+msgstr "E735: Kan bare sammenligne ordliste med ordliste"
+
+msgid "E736: Invalid operation for Dictionary"
+msgstr "E736: Ugyldig operasjon for ordliste"
+
+msgid "E693: Can only compare Funcref with Funcref"
+msgstr "E693: Kan bare sammenligne funksjonsreferanse med funksjonsreferanse"
+
+msgid "E694: Invalid operation for Funcrefs"
+msgstr "E694: Ugyldig operasjon for funksjonsreferanser"
+
+msgid "E110: Missing ')'"
+msgstr "E110: Mangler ')'"
+
+msgid "E695: Cannot index a Funcref"
+msgstr "E695: Kan ikke indeksere en funksjonsreferanse"
+
+#, c-format
+msgid "E112: Option name missing: %s"
+msgstr "E112: Navn på valg mangler: %s"
+
+#, c-format
+msgid "E113: Unknown option: %s"
+msgstr "E113: Ukjent valg: %s"
+
+#, c-format
+msgid "E114: Missing quote: %s"
+msgstr "E114: Mangler anførselstegn (\"): %s"
+
+#, c-format
+msgid "E115: Missing quote: %s"
+msgstr "E115: Mangler apostrof ('): %s"
+
+#, c-format
+msgid "E696: Missing comma in List: %s"
+msgstr "E696: Mangler komma i liste: %s"
+
+#, c-format
+msgid "E697: Missing end of List ']': %s"
+msgstr "E697: Mangler slutt på liste ']': %s"
+
+#, c-format
+msgid "E720: Missing colon in Dictionary: %s"
+msgstr "E720: Mangler kolon i ordliste: %s"
+
+#, c-format
+msgid "E721: Duplicate key in Dictionary: \"%s\""
+msgstr "E721: Duplisert nøkkel i ordliste: \"%s\""
+
+#, c-format
+msgid "E722: Missing comma in Dictionary: %s"
+msgstr "E722: Mangler komma i ordliste: %s"
+
+#, c-format
+msgid "E723: Missing end of Dictionary '}': %s"
+msgstr "E723: Mangler slutt på ordliste '}': %s"
+
+msgid "E724: variable nested too deep for displaying"
+msgstr "E724: Variabel nøstet for dypt for visning"
+
+#, c-format
+msgid "E117: Unknown function: %s"
+msgstr "E117: Ukjent funksjon: %s"
+
+#, c-format
+msgid "E119: Not enough arguments for function: %s"
+msgstr "E119: Ikke nok parametere til funksjonen: %s"
+
+#, c-format
+msgid "E120: Using <SID> not in a script context: %s"
+msgstr "E120: Bruk av \"<SID>\" utenfor skript-sammenheng: %s"
+
+#, c-format
+msgid "E725: Calling dict function without Dictionary: %s"
+msgstr "E725: Kaller ordlistefunksjon uten ordliste: %s"
+
+msgid "E699: Too many arguments"
+msgstr "E699: For mange parametere"
+
+msgid "E785: complete() can only be used in Insert mode"
+msgstr "E785: complete() kan bare brukes i innsettingsmodus"
+
+#.
+#. * Yes this is ugly, I don't particularly like it either. But doing it
+#. * this way has the compelling advantage that translations need not to
+#. * be touched at all. See below what 'ok' and 'ync' are used for.
+#.
+msgid "&Ok"
+msgstr "&Ok"
+
+#, c-format
+msgid "E737: Key already exists: %s"
+msgstr "E737: Nøkkelen finnes allerede: %s"
+
+#, c-format
+msgid "+-%s%3ld lines: "
+msgstr "+-%s%3ld linjer: "
+
+#, c-format
+msgid "E700: Unknown function: %s"
+msgstr "E700: Ukjent funksjon: %s"
+
+msgid ""
+"&OK\n"
+"&Cancel"
+msgstr ""
+"&OK\n"
+"&Avbryt"
+
+msgid "called inputrestore() more often than inputsave()"
+msgstr "kalte inputrestore() oftere enn inputsave()"
+
+msgid "E786: Range not allowed"
+msgstr "E786: Område ikke tillatt"
+
+msgid "E701: Invalid type for len()"
+msgstr "E701: Ugyldig type for len()"
+
+msgid "E726: Stride is zero"
+msgstr "E726: Økning er null"
+
+msgid "E727: Start past end"
+msgstr "E727: Starten er bak slutten"
+
+msgid "<empty>"
+msgstr "<tom>"
+
+msgid "E240: No connection to Vim server"
+msgstr "E240: Ingen forbindelse med Vim-tjeneren"
+
+#, c-format
+msgid "E241: Unable to send to %s"
+msgstr "E241: Klarer ikke sende til %s"
+
+msgid "E277: Unable to read a server reply"
+msgstr "E277: Klarer ikke lese svar fra tjeneren"
+
+msgid "E655: Too many symbolic links (cycle?)"
+msgstr "E655: For mange symbolske linker (runddans?)"
+
+msgid "E258: Unable to send to client"
+msgstr "E258: Klarer ikke sende til klienten"
+
+msgid "E702: Sort compare function failed"
+msgstr "E702: Funksjon for sorteringssammenligning feilet"
+
+msgid "(Invalid)"
+msgstr "(Ugyldig)"
+
+msgid "E677: Error writing temp file"
+msgstr "E677: Feil under skriving til midlertidig fil"
+
+msgid "E703: Using a Funcref as a Number"
+msgstr "E703: Bruker en funksjonsreferanse som et nummer"
+
+msgid "E745: Using a List as a Number"
+msgstr "E745: Bruker en liste som et nummer"
+
+msgid "E728: Using a Dictionary as a Number"
+msgstr "E728: Bruker en ordliste som et nummer"
+
+msgid "E729: using Funcref as a String"
+msgstr "E729: Bruker en funksjonsreferanse som en streng"
+
+msgid "E730: using List as a String"
+msgstr "E730: Bruker en liste som en streng"
+
+msgid "E731: using Dictionary as a String"
+msgstr "E731: Bruker en ordliste som en streng"
+
+#, c-format
+msgid "E704: Funcref variable name must start with a capital: %s"
+msgstr "E704: Variabelnavn for funksjonsreferanse må ha stor forbokstav: %s"
+
+#, c-format
+msgid "E705: Variable name conflicts with existing function: %s"
+msgstr "E705: Variabelnavn er i konflikt med en eksisterende funksjon: %s"
+
+#, c-format
+msgid "E706: Variable type mismatch for: %s"
+msgstr "E706: Variabeltype samsvarer ikke med: %s"
+
+#, c-format
+msgid "E795: Cannot delete variable %s"
+msgstr "E795: Kan ikke slette variabel %s"
+
+#, c-format
+msgid "E741: Value is locked: %s"
+msgstr "E741: Verdi er låst: %s"
+
+msgid "Unknown"
+msgstr "Ukjent"
+
+#, c-format
+msgid "E742: Cannot change value of %s"
+msgstr "E742: Kan ikke forandre verdi for %s"
+
+msgid "E698: variable nested too deep for making a copy"
+msgstr "E698: Variabel nøstet for dypt til å lage en kopi"
+
+#, c-format
+msgid "E124: Missing '(': %s"
+msgstr "E124: Mangler '(': %s"
+
+#, c-format
+msgid "E125: Illegal argument: %s"
+msgstr "E125: Ugyldig parameter: %s"
+
+msgid "E126: Missing :endfunction"
+msgstr "E126: Mangler :endfunction"
+
+#, c-format
+msgid "E746: Function name does not match script file name: %s"
+msgstr "E746: Funksjonsnavn samsvarer ikke med skriptfilnavn: %s"
+
+msgid "E129: Function name required"
+msgstr "E129: Funksjonsnavn nødvendig"
+
+#, c-format
+msgid "E128: Function name must start with a capital or contain a colon: %s"
+msgstr "E128: Funksjonsnavn må ha stor forbokstav eller inneholde et kolon: %s"
+
+#, c-format
+msgid "E131: Cannot delete function %s: It is in use"
+msgstr "E131: Kan ikke slette funksjonen %s: Den er i bruk"
+
+msgid "E132: Function call depth is higher than 'maxfuncdepth'"
+msgstr "E132: Funksjonskalldybden er større enn 'maxfuncdepth'"
+
+#, c-format
+msgid "calling %s"
+msgstr "kaller %s"
+
+#, c-format
+msgid "%s aborted"
+msgstr "%s avbrutt"
+
+#, c-format
+msgid "%s returning #%ld"
+msgstr "%s returnerer #%ld"
+
+#, c-format
+msgid "%s returning %s"
+msgstr "%s returnerer %s"
+
+#, c-format
+msgid "continuing in %s"
+msgstr "fortsetter i %s"
+
+msgid "E133: :return not inside a function"
+msgstr "E133: :return er ikke innenfor en funksjon"
+
+#, c-format
+msgid ""
+"\n"
+"# global variables:\n"
+msgstr ""
+"\n"
+"# globale variabler:\n"
+
+msgid ""
+"\n"
+"\tLast set from "
+msgstr ""
+"\n"
+"\tSist satt fra "
+
+#, c-format
+msgid "<%s>%s%s %d, Hex %02x, Octal %03o"
+msgstr "<%s>%s%s %d, Hex %02x, Oktal %03o"
+
+#, c-format
+msgid "> %d, Hex %04x, Octal %o"
+msgstr "> %d, Hex %04x, Oktal %o"
+
+#, c-format
+msgid "> %d, Hex %08x, Octal %o"
+msgstr "> %d, Hex %08x, Oktal %o"
+
+msgid "E134: Move lines into themselves"
+msgstr "E134: Flytting av linjer inn i seg selv"
+
+msgid "1 line moved"
+msgstr "1 linje flyttet"
+
+#, c-format
+msgid "%ld lines moved"
+msgstr "%ld linjer flyttet"
+
+#, c-format
+msgid "%ld lines filtered"
+msgstr "%ld linjer filtrert"
+
+msgid "E135: *Filter* Autocommands must not change current buffer"
+msgstr "E135: *Filter* Autokommandoer må ikke forandre nåværende buffer"
+
+msgid "[No write since last change]\n"
+msgstr "[Ikke lagret siden forrige forandring]\n"
+
+#, c-format
+msgid "%sviminfo: %s in line: "
+msgstr "%sviminfo: %s i linje: "
+
+msgid "E136: viminfo: Too many errors, skipping rest of file"
+msgstr "E136: viminfo: For mange feil, hopper over resten av filen"
+
+#, c-format
+msgid "Reading viminfo file \"%s\"%s%s%s"
+msgstr "Leser viminfo-fil \"%s\"%s%s%s"
+
+msgid " info"
+msgstr " info"
+
+msgid " marks"
+msgstr " merker"
+
+msgid " FAILED"
+msgstr " FEILET"
+
+#. avoid a wait_return for this message, it's annoying
+#, c-format
+msgid "E137: Viminfo file is not writable: %s"
+msgstr "E137: Viminfo-fil er ikke skrivbar: %s"
+
+#, c-format
+msgid "E138: Can't write viminfo file %s!"
+msgstr "E138: Kan ikke lagre viminfo-fil %s!"
+
+#, c-format
+msgid "Writing viminfo file \"%s\""
+msgstr "Lagrer viminfo-fil \"%s\""
+
+#. Write the info:
+#, c-format
+msgid "# This viminfo file was generated by Vim %s.\n"
+msgstr "# Denne viminfo-filen ble generert av Vim %s.\n"
+
+#, c-format
+msgid ""
+"# You may edit it if you're careful!\n"
+"\n"
+msgstr ""
+"# Du kan redigere den hvis du er forsiktig!\n"
+"\n"
+
+#, c-format
+msgid "# Value of 'encoding' when this file was written\n"
+msgstr "# Verdien av 'encoding' når denne filen ble skrevet\n"
+
+msgid "Illegal starting char"
+msgstr "Ulovlig starttegn"
+
+msgid "Save As"
+msgstr "Lagre som"
+
+msgid "Write partial file?"
+msgstr "Skrive delvis fil?"
+
+msgid "E140: Use ! to write partial buffer"
+msgstr "E140: Bruk ! for å skrive delvis buffer"
+
+#, c-format
+msgid "Overwrite existing file \"%s\"?"
+msgstr "Overskrive eksisterende fil \"%s\"?"
+
+#, c-format
+msgid "Swap file \"%s\" exists, overwrite anyway?"
+msgstr "Swapfilen \"%s\" finnes, overskriv likevel?"
+
+#, c-format
+msgid "E768: Swap file exists: %s (:silent! overrides)"
+msgstr "E768: Swapfilen finnes: %s (:silent! overstyrer)"
+
+#, c-format
+msgid "E141: No file name for buffer %ld"
+msgstr "E141: Mangler filnavn for buffer %ld"
+
+msgid "E142: File not written: Writing is disabled by 'write' option"
+msgstr "E142: Filen ble ikke lagret: Lagring er deaktivert med 'write'-valget"
+
+#, c-format
+msgid ""
+"'readonly' option is set for \"%s\".\n"
+"Do you wish to write anyway?"
+msgstr ""
+"'readonly'-valget er satt for \"%s\".\n"
+"Vil du lagre likevel?"
+
+msgid "Edit File"
+msgstr "Rediger fil"
+
+#, c-format
+msgid "E143: Autocommands unexpectedly deleted new buffer %s"
+msgstr "E143: Autokommandoer slettet uventet den nye bufferen %s"
+
+msgid "E144: non-numeric argument to :z"
+msgstr "E144: Ikke-numerisk parameter til :z"
+
+msgid "E145: Shell commands not allowed in rvim"
+msgstr "E145: Skallkommandoer er ikke tillatt i rvim"
+
+msgid "E146: Regular expressions can't be delimited by letters"
+msgstr "E146: Regulære uttrykk kan ikke bli adskilt av bokstaver"
+
+#, c-format
+msgid "replace with %s (y/n/a/q/l/^E/^Y)?"
+msgstr "Erstatt med %s (y/n/a/q/l/^E/^Y)?"
+
+msgid "(Interrupted) "
+msgstr "(Avbrutt) "
+
+msgid "1 match"
+msgstr "1 treff"
+
+msgid "1 substitution"
+msgstr "1 erstatning"
+
+#, c-format
+msgid "%ld matches"
+msgstr "%ld treff"
+
+#, c-format
+msgid "%ld substitutions"
+msgstr "%ld erstatninger"
+
+msgid " on 1 line"
+msgstr " i 1 linje"
+
+#, c-format
+msgid " on %ld lines"
+msgstr " i %ld linjer"
+
+msgid "E147: Cannot do :global recursive"
+msgstr "E147: Kan ikke gjøre :global rekursiv"
+
+msgid "E148: Regular expression missing from global"
+msgstr "E148: Regulært uttrykk mangler i global kommando"
+
+#, c-format
+msgid "Pattern found in every line: %s"
+msgstr "Søkestreng funnet i alle linjene: %s"
+
+#, c-format
+msgid ""
+"\n"
+"# Last Substitute String:\n"
+"$"
+msgstr ""
+"\n"
+"# Siste erstatningstekst:\n"
+"$"
+
+msgid "E478: Don't panic!"
+msgstr "E478: Ingen panikk!"
+
+#, c-format
+msgid "E661: Sorry, no '%s' help for %s"
+msgstr "E661: Dessverre ingen '%s' hjelp for %s"
+
+#, c-format
+msgid "E149: Sorry, no help for %s"
+msgstr "E149: Dessverre ingen hjelp for %s"
+
+#, c-format
+msgid "Sorry, help file \"%s\" not found"
+msgstr "Fant ikke hjelpefilen \"%s\""
+
+#, c-format
+msgid "E150: Not a directory: %s"
+msgstr "E150: Er ikke en katalog: %s"
+
+#, c-format
+msgid "E152: Cannot open %s for writing"
+msgstr "E152: Kan ikke åpne %s for skriving"
+
+#, c-format
+msgid "E153: Unable to open %s for reading"
+msgstr "E153: Kan ikke åpne %s for lesing"
+
+#, c-format
+msgid "E670: Mix of help file encodings within a language: %s"
+msgstr "E670: Tegnsettblanding i hjelpefilen innenfor samme språk: %s"
+
+#, c-format
+msgid "E154: Duplicate tag \"%s\" in file %s/%s"
+msgstr "E154: Duplikat-tag \"%s\" i filen %s/%s"
+
+#, c-format
+msgid "E160: Unknown sign command: %s"
+msgstr "E160: Ukjent skiltkommando: %s"
+
+msgid "E156: Missing sign name"
+msgstr "E156: Mangler skiltnavn"
+
+msgid "E612: Too many signs defined"
+msgstr "E612: For mange skilt definert"
+
+#, c-format
+msgid "E239: Invalid sign text: %s"
+msgstr "E239: Ugyldig skilttekst: %s"
+
+#, c-format
+msgid "E155: Unknown sign: %s"
+msgstr "E155: Ukjent skilt: %s"
+
+msgid "E159: Missing sign number"
+msgstr "E159: Mangler skiltnummer"
+
+#, c-format
+msgid "E158: Invalid buffer name: %s"
+msgstr "E158: Ugyldig buffernavn: %s"
+
+#, c-format
+msgid "E157: Invalid sign ID: %ld"
+msgstr "E157: Ulovlig skilt-ID: %ld"
+
+msgid " (NOT FOUND)"
+msgstr " (IKKE FUNNET)"
+
+msgid " (not supported)"
+msgstr " (ikke støttet)"
+
+msgid "[Deleted]"
+msgstr "[Slettet]"
+
+msgid "Entering Debug mode. Type \"cont\" to continue."
+msgstr "Går inn i debuggingsmodus. Skriv \"cont\" for å fortsette."
+
+#, c-format
+msgid "line %ld: %s"
+msgstr "linje %ld: %s"
+
+#, c-format
+msgid "cmd: %s"
+msgstr "kommando: %s"
+
+#, c-format
+msgid "Breakpoint in \"%s%s\" line %ld"
+msgstr "Stoppunkt i \"%s%s\" linje %ld"
+
+#, c-format
+msgid "E161: Breakpoint not found: %s"
+msgstr "E161: Fant ikke stoppunkt: %s"
+
+msgid "No breakpoints defined"
+msgstr "Ingen stoppunkt definert"
+
+#, c-format
+msgid "%3d %s %s line %ld"
+msgstr "%3d %s %s linje %ld"
+
+msgid "E750: First use :profile start <fname>"
+msgstr "E750: Bruk først :profile start <filnavn>"
+
+#, c-format
+msgid "Save changes to \"%s\"?"
+msgstr "Lagre forandringer til \"%s\"?"
+
+msgid "Untitled"
+msgstr "Uten navn"
+
+#, c-format
+msgid "E162: No write since last change for buffer \"%s\""
+msgstr "E162: Ikke lagret siden siste forandringer i bufferen \"%s\""
+
+msgid "Warning: Entered other buffer unexpectedly (check autocommands)"
+msgstr "Advarsel: Gikk uventet inn i en annen buffer (sjekk autokommandoer)"
+
+msgid "E163: There is only one file to edit"
+msgstr "E163: Det er bare en fil å redigere"
+
+msgid "E164: Cannot go before first file"
+msgstr "E164: Kan ikke gå forbi første fil"
+
+msgid "E165: Cannot go beyond last file"
+msgstr "E165: Kan ikke gå forbi siste fil"
+
+#, c-format
+msgid "E666: compiler not supported: %s"
+msgstr "E666: Kompilatoren er ikke støttet: %s"
+
+#, c-format
+msgid "Searching for \"%s\" in \"%s\""
+msgstr "Søker etter \"%s\" i \"%s\""
+
+#, c-format
+msgid "Searching for \"%s\""
+msgstr "Søker etter \"%s\""
+
+#, c-format
+msgid "not found in 'runtimepath': \"%s\""
+msgstr "ikke funnet i 'runtimepath': \"%s\""
+
+msgid "Source Vim script"
+msgstr "Kjør Vim-skript"
+
+#, c-format
+msgid "Cannot source a directory: \"%s\""
+msgstr "Kan ikke kjøre en katalog: \"%s\""
+
+#, c-format
+msgid "could not source \"%s\""
+msgstr "kunne ikke kjøre \"%s\""
+
+#, c-format
+msgid "line %ld: could not source \"%s\""
+msgstr "linje %ld: Kunne ikke kjøre \"%s\""
+
+#, c-format
+msgid "sourcing \"%s\""
+msgstr "kjører \"%s\""
+
+#, c-format
+msgid "line %ld: sourcing \"%s\""
+msgstr "linje %ld: kjører \"%s\""
+
+#, c-format
+msgid "finished sourcing %s"
+msgstr "ferdig med kjøring av %s"
+
+#, fuzzy
+#~ msgid "modeline"
+#~ msgstr "1 linje lagt til"
+
+#, fuzzy
+#~ msgid "--cmd argument"
+#~ msgstr " vim [parametere] "
+
+#, fuzzy
+#~ msgid "-c argument"
+#~ msgstr " vim [parametere] "
+
+msgid "environment variable"
+msgstr "miljøvariabel"
+
+msgid "error handler"
+msgstr "feilbehandler"
+
+msgid "W15: Warning: Wrong line separator, ^M may be missing"
+msgstr "W15: Advarsel: Feil linjeseparator, det er mulig ^M mangler"
+
+msgid "E167: :scriptencoding used outside of a sourced file"
+msgstr "E167: :scriptencoding brukt utenfor en kjørt fil"
+
+msgid "E168: :finish used outside of a sourced file"
+msgstr "E168: :finish brukt utenfor en kjørt fil"
+
+#, c-format
+msgid "Current %slanguage: \"%s\""
+msgstr "Nåværende %sspråk: \"%s\""
+
+#, c-format
+msgid "E197: Cannot set language to \"%s\""
+msgstr "E197: Kan ikke sette språk til \"%s\""
+
+msgid "Entering Ex mode. Type \"visual\" to go to Normal mode."
+msgstr "Går inn i Ex-modus. Skriv \"visual\" for å gå til normalmodus."
+
+msgid "E501: At end-of-file"
+msgstr "E501: Ved slutten av filen"
+
+msgid "E169: Command too recursive"
+msgstr "E169: Kommando altfor rekursiv"
+
+#, c-format
+msgid "E605: Exception not caught: %s"
+msgstr "E605: Unntak ikke fanget opp: %s"
+
+msgid "End of sourced file"
+msgstr "Slutt på kjørt fil"
+
+msgid "End of function"
+msgstr "Slutt på funksjon"
+
+msgid "E464: Ambiguous use of user-defined command"
+msgstr "E464: Flertydig bruk av brukerdefinert kommando"
+
+msgid "E492: Not an editor command"
+msgstr "E492: Er ikke en editorkommando"
+
+msgid "E493: Backwards range given"
+msgstr "E493: Område bakover er angitt"
+
+msgid "Backwards range given, OK to swap"
+msgstr "Område bakover er angitt, OK å swappe"
+
+msgid "E494: Use w or w>>"
+msgstr "E494: Bruk w eller w>>"
+
+msgid "E319: Sorry, the command is not available in this version"
+msgstr "E319: Kommandoen er ikke tilgjengelig i denne versjonen"
+
+msgid "E172: Only one file name allowed"
+msgstr "E172: Bare ett filnavn tillatt"
+
+msgid "1 more file to edit. Quit anyway?"
+msgstr "1 annen fil å redigere. Avslutt likevel?"
+
+#, c-format
+msgid "%d more files to edit. Quit anyway?"
+msgstr "%d andre filer å redigere. Avslutt likevel?"
+
+msgid "E173: 1 more file to edit"
+msgstr "E173: 1 annen fil å redigere"
+
+#, c-format
+msgid "E173: %ld more files to edit"
+msgstr "E173: %ld andre filer å redigere"
+
+msgid "E174: Command already exists: add ! to replace it"
+msgstr "E174: Kommandoen finnes allerede: Legg til ! for å erstatte den"
+
+msgid ""
+"\n"
+" Name Args Range Complete Definition"
+msgstr ""
+"\n"
+" Navn Prm. Områd Fullfør Definering"
+
+msgid "No user-defined commands found"
+msgstr "Ingen brukerdefinerte kommandoer funnet"
+
+msgid "E175: No attribute specified"
+msgstr "E175: Ingen attributt spesifisert"
+
+msgid "E176: Invalid number of arguments"
+msgstr "E176: Ugyldig antall parametere"
+
+msgid "E177: Count cannot be specified twice"
+msgstr "E177: Antall repeteringer kan ikke bli spesifisert to ganger"
+
+msgid "E178: Invalid default value for count"
+msgstr "E178: Ugyldig standardverdi for antall repeteringer"
+
+msgid "E179: argument required for -complete"
+msgstr "E179: Trenger parameter til -complete"
+
+#, c-format
+msgid "E181: Invalid attribute: %s"
+msgstr "E181: Ugyldig attributt: %s"
+
+msgid "E182: Invalid command name"
+msgstr "E182: Ugyldig kommandonavn"
+
+msgid "E183: User defined commands must start with an uppercase letter"
+msgstr "E183: Brukerdefinerte kommandoer må ha stor forbokstav"
+
+#, c-format
+msgid "E184: No such user-defined command: %s"
+msgstr "E184: Brukerdefinert kommando finnes ikke: %s"
+
+#, c-format
+msgid "E180: Invalid complete value: %s"
+msgstr "E180: Ugyldig \"complete\"-verdi: %s"
+
+msgid "E468: Completion argument only allowed for custom completion"
+msgstr "E468: Fullføringsparameter er bare tillatt for tilpasset fullføring"
+
+msgid "E467: Custom completion requires a function argument"
+msgstr "E467: Tilpassede fullføringer trenger et funksjonsparameter"
+
+#, c-format
+msgid "E185: Cannot find color scheme %s"
+msgstr "E185: Kan ikke finne fargeoppsettet %s"
+
+msgid "Greetings, Vim user!"
+msgstr "Vær hilset, Vim-bruker!"
+
+#, fuzzy
+#~ msgid "E784: Cannot close last tab page"
+#~ msgstr "E444: Kan ikke lukke det siste vinduet"
+
+#, fuzzy
+#~ msgid "Already only one tab page"
+#~ msgstr "Allerede bare ett vindu"
+
+msgid "Edit File in new window"
+msgstr "Rediger fil i nytt vindu"
+
+#, fuzzy, c-format
+#~ msgid "Tab page %d"
+#~ msgstr "Side %d"
+
+msgid "No swap file"
+msgstr "Ingen swapfil"
+
+msgid "Append File"
+msgstr "Legg til fil"
+
+msgid "E747: Cannot change directory, buffer is modified (add ! to override)"
+msgstr ""
+"E747: Kan ikke skifte katalog, bufferen er forandret (legg til ! for å "
+"overstyre)"
+
+msgid "E186: No previous directory"
+msgstr "E186: Ingen tidligere katalog"
+
+msgid "E187: Unknown"
+msgstr "E187: Ukjent"
+
+msgid "E465: :winsize requires two number arguments"
+msgstr "E465: :winsize trenger to numeriske parametere"
+
+#, c-format
+msgid "Window position: X %d, Y %d"
+msgstr "Vindusposisjon: X %d, Y %d"
+
+msgid "E188: Obtaining window position not implemented for this platform"
+msgstr ""
+"E188: Lesing av vindusposisjon er ikke implementert på denne plattformen"
+
+msgid "E466: :winpos requires two number arguments"
+msgstr "E466: :winpos trenger to numeriske parametere"
+
+msgid "Save Redirection"
+msgstr "Lagre omdirigering"
+
+msgid "Save View"
+msgstr "Lagre utseende"
+
+msgid "Save Session"
+msgstr "Lagre økt"
+
+msgid "Save Setup"
+msgstr "Lagre oppsett"
+
+#, c-format
+msgid "E739: Cannot create directory: %s"
+msgstr "E739: Kan ikke lage katalog: %s"
+
+#, c-format
+msgid "E189: \"%s\" exists (add ! to override)"
+msgstr "E189: \"%s\" finnes (legg til ! for å overstyre)"
+
+#, c-format
+msgid "E190: Cannot open \"%s\" for writing"
+msgstr "E190: Kan ikke åpne \"%s\" for skriving"
+
+#. set mark
+msgid "E191: Argument must be a letter or forward/backward quote"
+msgstr "E191: Parameter må være en bokstav eller vanlig/baklengs apostrof"
+
+msgid "E192: Recursive use of :normal too deep"
+msgstr "E192: Rekursiv bruk av :normal er for dyp"
+
+msgid "E194: No alternate file name to substitute for '#'"
+msgstr "E194: Ingen alternative filnavn tilgjengelig som erstatning for '#'"
+
+msgid "E495: no autocommand file name to substitute for \"<afile>\""
+msgstr ""
+"E495: Ingen autokommandofilnavn tilgjengelig som erstatning for \"<afile>\""
+
+msgid "E496: no autocommand buffer number to substitute for \"<abuf>\""
+msgstr ""
+"E496: Ingen buffernummer tilgjengelig som erstatning for \"<abuf>\" i "
+"autokommando"
+
+msgid "E497: no autocommand match name to substitute for \"<amatch>\""
+msgstr ""
+"E497: Ingen autokommandonavn tilgjengelig som erstatning for \"<amatch>\""
+
+msgid "E498: no :source file name to substitute for \"<sfile>\""
+msgstr ""
+"E498: Ingen ':source'-filnavn tilgjengelig som erstatning for \"<sfile>\""
+
+#, no-c-format
+msgid "E499: Empty file name for '%' or '#', only works with \":p:h\""
+msgstr "E499: Tomt filnavn for '%' eller '#', virker bare med \":p:h\""
+
+msgid "E500: Evaluates to an empty string"
+msgstr "E500: Resulterer i en tom streng"
+
+msgid "E195: Cannot open viminfo file for reading"
+msgstr "E195: Kan ikke åpne viminfo-fil for lesing"
+
+msgid "E196: No digraphs in this version"
+msgstr "E196: Ingen spesialtegn i denne versjonen"
+
+msgid "E608: Cannot :throw exceptions with 'Vim' prefix"
+msgstr "E608: Kan ikke :throw unntak med 'Vim'-forstavelse"
+
+#. always scroll up, don't overwrite
+#, c-format
+#~ msgid "Exception thrown: %s"
+#~ msgstr ""
+
+#, c-format
+msgid "Exception finished: %s"
+msgstr "Unntak fullført: %s"
+
+#, c-format
+msgid "Exception discarded: %s"
+msgstr "Unntak forkastet: %s"
+
+#, c-format
+msgid "%s, line %ld"
+msgstr "%s, linje %ld"
+
+#. always scroll up, don't overwrite
+#, c-format
+msgid "Exception caught: %s"
+msgstr "Unntak fanget opp: %s"
+
+#, c-format
+msgid "%s made pending"
+msgstr "%s satt på venting"
+
+#, c-format
+msgid "%s resumed"
+msgstr "%s gjenopptatt"
+
+#, c-format
+msgid "%s discarded"
+msgstr "%s forkastet"
+
+msgid "Exception"
+msgstr "Unntak"
+
+msgid "Error and interrupt"
+msgstr "Feil og avbrudd"
+
+msgid "Error"
+msgstr "Feil"
+
+#. if (pending & CSTP_INTERRUPT)
+msgid "Interrupt"
+msgstr "Avbrudd"
+
+msgid "E579: :if nesting too deep"
+msgstr "E579: Nøsting av :if for dyp"
+
+msgid "E580: :endif without :if"
+msgstr "E580: :endif uten :if"
+
+msgid "E581: :else without :if"
+msgstr "E581: :else uten :if"
+
+msgid "E582: :elseif without :if"
+msgstr "E582: :elseif uten :if"
+
+msgid "E583: multiple :else"
+msgstr "E583: Flere forekomster av :else"
+
+msgid "E584: :elseif after :else"
+msgstr "E584: :elseif etter :else"
+
+msgid "E585: :while/:for nesting too deep"
+msgstr "E585: Nøsting av :while/:for er for dyp"
+
+msgid "E586: :continue without :while or :for"
+msgstr "E586: :continue uten :while eller :for"
+
+msgid "E587: :break without :while or :for"
+msgstr "E587: :break uten :while eller :for"
+
+msgid "E732: Using :endfor with :while"
+msgstr "E732: Bruker :endfor sammen med :while"
+
+msgid "E733: Using :endwhile with :for"
+msgstr "E733: Bruker :endwhile sammen med :for"
+
+msgid "E601: :try nesting too deep"
+msgstr "E601: Nøsting av :try for dyp"
+
+msgid "E603: :catch without :try"
+msgstr "E603: :catch uten :try"
+
+#. Give up for a ":catch" after ":finally" and ignore it.
+#. * Just parse.
+msgid "E604: :catch after :finally"
+msgstr "E604: :catch etter :finally"
+
+msgid "E606: :finally without :try"
+msgstr "E606: :finally uten :try"
+
+#. Give up for a multiple ":finally" and ignore it.
+msgid "E607: multiple :finally"
+msgstr "E607: Flere forekomster av :finally"
+
+msgid "E602: :endtry without :try"
+msgstr "E602: :endtry uten :try"
+
+msgid "E193: :endfunction not inside a function"
+msgstr "E193: :endfunction er ikke innenfor en funksjon"
+
+msgid "E788: Not allowed to edit another buffer now"
+msgstr "E788: Ikke tillatt å redigere en annen buffer nå"
+
+msgid "tagname"
+msgstr "navn på tag"
+
+#~ msgid " kind file\n"
+#~ msgstr ""
+
+msgid "'history' option is zero"
+msgstr "'history'-valget er null"
+
+#, c-format
+msgid ""
+"\n"
+"# %s History (newest to oldest):\n"
+msgstr ""
+"\n"
+"# %s-historie (nyeste til eldste):\n"
+
+msgid "Command Line"
+msgstr "Kommandolinje"
+
+msgid "Search String"
+msgstr "Søkestreng"
+
+msgid "Expression"
+msgstr "Uttrykk"
+
+msgid "Input Line"
+msgstr "Inndatalinje"
+
+msgid "E198: cmd_pchar beyond the command length"
+msgstr "E198: cmd_pchar utenfor kommandolengden"
+
+msgid "E199: Active window or buffer deleted"
+msgstr "E199: Aktivt vindu eller buffer slettet"
+
+msgid "Illegal file name"
+msgstr "Ulovlig filnavn"
+
+msgid "is a directory"
+msgstr "er en katalog"
+
+msgid "is not a file"
+msgstr "er ikke en fil"
+
+msgid "is a device (disabled with 'opendevice' option)"
+msgstr "er en enhet (frakoblet med 'opendevice'-valg)"
+
+msgid "[New File]"
+msgstr "[Ny fil]"
+
+msgid "[New DIRECTORY]"
+msgstr "[Ny KATALOG]"
+
+msgid "[File too big]"
+msgstr "[Filen er for stor]"
+
+msgid "[Permission Denied]"
+msgstr "[Tilgang nektet]"
+
+msgid "E200: *ReadPre autocommands made the file unreadable"
+msgstr "E200: \"*ReadPre\"-autokommandoer gjorde filen uleselig"
+
+msgid "E201: *ReadPre autocommands must not change current buffer"
+msgstr "E201: \"*ReadPre\"-autokommandoer må ikke forandre nåværende buffer"
+
+msgid "Vim: Reading from stdin...\n"
+msgstr "Vim: Leser fra stdin ...\n"
+
+msgid "Reading from stdin..."
+msgstr "Leser fra stdin ..."
+
+#. Re-opening the original file failed!
+msgid "E202: Conversion made file unreadable!"
+msgstr "E202: Konverteringen gjorde filen uleselig!"
+
+msgid "[fifo/socket]"
+msgstr "[fifo/socket]"
+
+msgid "[fifo]"
+msgstr "[fifo]"
+
+msgid "[socket]"
+msgstr "[socket]"
+
+msgid "[RO]"
+msgstr "[SB]"
+
+msgid "[CR missing]"
+msgstr "[CR mangler]"
+
+msgid "[NL found]"
+msgstr "[NL funnet]"
+
+msgid "[long lines split]"
+msgstr "[lange linjer splittes]"
+
+msgid "[NOT converted]"
+msgstr "[IKKE konvertert]"
+
+msgid "[converted]"
+msgstr "[konvertert]"
+
+msgid "[crypted]"
+msgstr "[kryptert]"
+
+#, c-format
+msgid "[CONVERSION ERROR in line %ld]"
+msgstr "[KONVERTERINGSFEIL i linje %ld]"
+
+#, c-format
+msgid "[ILLEGAL BYTE in line %ld]"
+msgstr "[ULOVLIG BYTE i linje %ld]"
+
+msgid "[READ ERRORS]"
+msgstr "[LESEFEIL]"
+
+msgid "Can't find temp file for conversion"
+msgstr "Kan ikke finne midlertidig fil for konvertering"
+
+msgid "Conversion with 'charconvert' failed"
+msgstr "Konvertering med 'charconvert' feilet"
+
+msgid "can't read output of 'charconvert'"
+msgstr "Kan ikke lese utdata fra 'charconvert'"
+
+msgid "E676: No matching autocommands for acwrite buffer"
+msgstr "E676: Ingen samsvarende autokommandoer for 'acwrite'-buffer"
+
+msgid "E203: Autocommands deleted or unloaded buffer to be written"
+msgstr "E203: Autokommandoer slettet eller lastet ut buffer som skulle lagres"
+
+msgid "E204: Autocommand changed number of lines in unexpected way"
+msgstr "E204: Autokommando forandret linjeantall på en uventet måte"
+
+msgid "NetBeans disallows writes of unmodified buffers"
+msgstr "NetBeans forbyr lagring av buffere som ikke er forandret"
+
+msgid "Partial writes disallowed for NetBeans buffers"
+msgstr "Delvis lagring ikke tillatt for NetBeans-buffere"
+
+msgid "is not a file or writable device"
+msgstr "er ikke en fil eller skrivbar enhet"
+
+msgid "writing to device disabled with 'opendevice' option"
+msgstr "skriving til enhet er slått av med 'opendevice'-valg"
+
+msgid "is read-only (add ! to override)"
+msgstr "er skrivebeskyttet (legg til ! for å overstyre)"
+
+msgid "E506: Can't write to backup file (add ! to override)"
+msgstr "E506: Kan ikke skrive til backupfil (legg til ! for å overstyre)"
+
+msgid "E507: Close error for backup file (add ! to override)"
+msgstr "E507: Feil under lukking av backupfil (legg til ! for å overstyre)"
+
+msgid "E508: Can't read file for backup (add ! to override)"
+msgstr "E508: Kan ikke lese fil for backup (legg til ! for å overstyre)"
+
+msgid "E509: Cannot create backup file (add ! to override)"
+msgstr "E509: Kan ikke lese backupfil (legg til ! for å overstyre)"
+
+msgid "E510: Can't make backup file (add ! to override)"
+msgstr "E510: Kan ikke lage backupfil (legg til ! for å overstyre)"
+
+msgid "E460: The resource fork would be lost (add ! to override)"
+msgstr "E460: Ressursforgreningen ville gått tapt (legg til ! for å overstyre)"
+
+msgid "E214: Can't find temp file for writing"
+msgstr "E214: Kan ikke finne midlertidig fil for skriving"
+
+msgid "E213: Cannot convert (add ! to write without conversion)"
+msgstr "E213: Kan ikke konvertere (legg til ! for å lagre uten konvertering)"
+
+msgid "E166: Can't open linked file for writing"
+msgstr "E166: Kan ikke åpne lenket fil for skriving"
+
+msgid "E212: Can't open file for writing"
+msgstr "E212: Kan ikke åpne fil for skriving"
+
+msgid "E667: Fsync failed"
+msgstr "E667: Fsync feilet"
+
+msgid "E512: Close failed"
+msgstr "E512: Lukking feilet"
+
+msgid "E513: write error, conversion failed (make 'fenc' empty to override)"
+msgstr ""
+"E513: Feil under skriving, konvertering feilet (gjør 'fenc' tom for å "
+"overstyre)"
+
+msgid "E514: write error (file system full?)"
+msgstr "E514: Feil under lagring (full disk?)"
+
+msgid " CONVERSION ERROR"
+msgstr " KONVERTERINGSFEIL"
+
+msgid "[Device]"
+msgstr "[Enhet]"
+
+msgid "[New]"
+msgstr "[Ny]"
+
+msgid " [a]"
+msgstr " [l]"
+
+msgid " appended"
+msgstr " lagt til"
+
+msgid " [w]"
+msgstr " [s]"
+
+msgid " written"
+msgstr " skrevet"
+
+msgid "E205: Patchmode: can't save original file"
+msgstr "E205: Patchmode: Kan ikke lagre originalfil"
+
+msgid "E206: patchmode: can't touch empty original file"
+msgstr "E206: patchmode: Kan ikke oppdatere tom originalfil"
+
+msgid "E207: Can't delete backup file"
+msgstr "E207: Kan ikke slette backupfil"
+
+msgid ""
+"\n"
+"WARNING: Original file may be lost or damaged\n"
+msgstr ""
+"\n"
+"ADVARSEL: Originalfilen kan bli tapt eller ødelagt\n"
+
+msgid "don't quit the editor until the file is successfully written!"
+msgstr "ikke avslutt editoren før filen er skikkelig lagret!"
+
+msgid "[dos]"
+msgstr "[dos]"
+
+msgid "[dos format]"
+msgstr "[dos-format]"
+
+msgid "[mac]"
+msgstr "[mac]"
+
+msgid "[mac format]"
+msgstr "[mac-format]"
+
+msgid "[unix]"
+msgstr "[unix]"
+
+msgid "[unix format]"
+msgstr "[unix-format]"
+
+msgid "1 line, "
+msgstr "1 linje, "
+
+#, c-format
+msgid "%ld lines, "
+msgstr "%ld linjer, "
+
+msgid "1 character"
+msgstr "1 tegn"
+
+#, c-format
+msgid "%ld characters"
+msgstr "%ld tegn"
+
+msgid "[noeol]"
+msgstr "[ingenlinjeslutt]"
+
+msgid "[Incomplete last line]"
+msgstr "[Ufullstendig sistelinje]"
+
+#. don't overwrite messages here
+#. must give this prompt
+#. don't use emsg() here, don't want to flush the buffers
+msgid "WARNING: The file has been changed since reading it!!!"
+msgstr "ADVARSEL: Filen er blitt forandret siden den ble lest!!!"
+
+msgid "Do you really want to write to it"
+msgstr "Vil du virkelig skrive til den"
+
+#, c-format
+msgid "E208: Error writing to \"%s\""
+msgstr "E208: Feil under skriving til \"%s\""
+
+#, c-format
+msgid "E209: Error closing \"%s\""
+msgstr "E209: Feil under lukking av \"%s\""
+
+#, c-format
+msgid "E210: Error reading \"%s\""
+msgstr "E210: Feil under lesing av \"%s\""
+
+msgid "E246: FileChangedShell autocommand deleted buffer"
+msgstr "E246: Autokommandoen \"FileChangedShell\" slettet buffer"
+
+#, c-format
+msgid "E211: File \"%s\" no longer available"
+msgstr "E211: Filen \"%s\" er ikke lenger tilgjengelig"
+
+#, c-format
+msgid ""
+"W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as "
+"well"
+msgstr ""
+"W12: Advarsel: Filen \"%s\" er forandret og bufferen var også forandret i Vim"
+
+msgid "See \":help W12\" for more info."
+msgstr "Se \":help W12\" for mer informasjon."
+
+#, c-format
+msgid "W11: Warning: File \"%s\" has changed since editing started"
+msgstr "W11: Advarsel: Filen \"%s\" er forandret siden redigeringen startet"
+
+msgid "See \":help W11\" for more info."
+msgstr "Se \":help W11\" for mer informasjon."
+
+#, c-format
+msgid "W16: Warning: Mode of file \"%s\" has changed since editing started"
+msgstr ""
+"W16: Advarsel: Rettighetene til filen \"%s\" er forandret siden redigeringen "
+"startet"
+
+msgid "See \":help W16\" for more info."
+msgstr "Se \":help W16\" for mer informasjon."
+
+#, c-format
+msgid "W13: Warning: File \"%s\" has been created after editing started"
+msgstr ""
+"W13: Advarsel: Filen \"%s\" er blitt opprettet etter at redigeringen startet"
+
+msgid "Warning"
+msgstr "Advarsel"
+
+msgid ""
+"&OK\n"
+"&Load File"
+msgstr ""
+"&OK\n"
+"&Åpne fil"
+
+#, c-format
+msgid "E462: Could not prepare for reloading \"%s\""
+msgstr "E462: Kunne ikke forberede for relasting \"%s\""
+
+#, c-format
+msgid "E321: Could not reload \"%s\""
+msgstr "E321: Kunne ikke laste \"%s\" på nytt"
+
+msgid "--Deleted--"
+msgstr "--Slettet--"
+
+#, c-format
+msgid "auto-removing autocommand: %s <buffer=%d>"
+msgstr "fjerner autokommando automatisk: %s <buffer=%d>"
+
+#. the group doesn't exist
+#, c-format
+msgid "E367: No such group: \"%s\""
+msgstr "E367: Gruppen finnes ikke: \"%s\""
+
+#, c-format
+msgid "E215: Illegal character after *: %s"
+msgstr "E215: Ulovlig tegn etter *: %s"
+
+#, c-format
+msgid "E216: No such event: %s"
+msgstr "E216: Handlingen finnes ikke: %s"
+
+#, c-format
+msgid "E216: No such group or event: %s"
+msgstr "E216: Gruppen eller handlingen finnes ikke: %s"
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Autocommands ---"
+msgstr ""
+"\n"
+"--- Autokommandoer ---"
+
+#, c-format
+msgid "E680: <buffer=%d>: invalid buffer number "
+msgstr "E680: <buffer=%d>: Ugyldig buffernummer"
+
+msgid "E217: Can't execute autocommands for ALL events"
+msgstr "E217: Kan ikke utføre autokommandoer for ALLE hendelser"
+
+msgid "No matching autocommands"
+msgstr "Ingen samsvarende autokommandoer"
+
+msgid "E218: autocommand nesting too deep"
+msgstr "E218: Nøsting av autokommandoer for dyp"
+
+#, c-format
+msgid "%s Autocommands for \"%s\""
+msgstr "%s Autokommandoer for \"%s\""
+
+#, c-format
+msgid "Executing %s"
+msgstr "Utfører %s"
+
+#, c-format
+msgid "autocommand %s"
+msgstr "autokommando %s"
+
+msgid "E219: Missing {."
+msgstr "E219: Mangler {."
+
+msgid "E220: Missing }."
+msgstr "E220: Mangler }."
+
+msgid "E490: No fold found"
+msgstr "E490: Ingen fold funnet"
+
+msgid "E350: Cannot create fold with current 'foldmethod'"
+msgstr "E350: Kan ikke lage fold med nåværende 'foldmethod'"
+
+msgid "E351: Cannot delete fold with current 'foldmethod'"
+msgstr "E351: Kan ikke slette fold med nåværende 'foldmethod'"
+
+#, c-format
+msgid "+--%3ld lines folded "
+msgstr "+--%3ld linjer foldet "
+
+msgid "E222: Add to read buffer"
+msgstr "E222: Legger til allerede lest buffer"
+
+msgid "E223: recursive mapping"
+msgstr "E223: Rekursiv mapping"
+
+#, c-format
+msgid "E224: global abbreviation already exists for %s"
+msgstr "E224: Global forkortelse finnes allerede for %s"
+
+#, c-format
+msgid "E225: global mapping already exists for %s"
+msgstr "E225: Global mapping finnes allerede for %s"
+
+#, c-format
+msgid "E226: abbreviation already exists for %s"
+msgstr "E226: Forkortelse finnes allerede for %s"
+
+#, c-format
+msgid "E227: mapping already exists for %s"
+msgstr "E227: Mappingen finnes allerede for %s"
+
+msgid "No abbreviation found"
+msgstr "Ingen forkortelse funnet"
+
+msgid "No mapping found"
+msgstr "Ingen mapping funnet"
+
+msgid "E228: makemap: Illegal mode"
+msgstr "E228: makemap: Ulovlig modus"
+
+msgid "E229: Cannot start the GUI"
+msgstr "E229: Kan ikke starte grafisk brukergrensesnitt (GUI)"
+
+#, c-format
+msgid "E230: Cannot read from \"%s\""
+msgstr "E230: Kan ikke lese fra \"%s\""
+
+msgid "E665: Cannot start GUI, no valid font found"
+msgstr ""
+"E665: Kan ikke starte grafisk brukergrensesnitt, fant ingen gyldig font"
+
+msgid "E231: 'guifontwide' invalid"
+msgstr "E231: 'guifontwide' ugyldig"
+
+msgid "E599: Value of 'imactivatekey' is invalid"
+msgstr "E599: Verdien for 'imactivatekey' er ugyldig"
+
+#, c-format
+msgid "E254: Cannot allocate color %s"
+msgstr "E254: Kan ikke reservere farge %s"
+
+msgid "No match at cursor, finding next"
+msgstr "Ingen treff ved markøren, finner neste"
+
+msgid "<cannot open> "
+msgstr "<kan ikke åpne> "
+
+#, c-format
+msgid "E616: vim_SelFile: can't get font %s"
+msgstr "E616: vim_SelFile: Kan ikke bruke skrifttypen %s"
+
+msgid "E614: vim_SelFile: can't return to current directory"
+msgstr "E614: vim_SelFile: Kan ikke returnere til nåværende katalog"
+
+msgid "Pathname:"
+msgstr "Sti:"
+
+msgid "E615: vim_SelFile: can't get current directory"
+msgstr "E615: vim_SelFile: Kan ikke finne nåværende katalog"
+
+msgid "OK"
+msgstr "OK"
+
+msgid "Cancel"
+msgstr "Avbryt"
+
+msgid "Scrollbar Widget: Could not get geometry of thumb pixmap."
+msgstr "Rullefeltelement: Klarte ikke hente dimensjoner på \"thumb pixmap\"."
+
+msgid "Vim dialog"
+msgstr "Dialogvindu for Vim"
+
+msgid "E232: Cannot create BalloonEval with both message and callback"
+msgstr "E232: Kan ikke lage BalloonEval med både melding og tilbakekall"
+
+msgid "Vim dialog..."
+msgstr "Vim dialogvindu ..."
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"&Cancel"
+msgstr ""
+"&Ja\n"
+"&Nei\n"
+"&Avbryt"
+
+msgid "Input _Methods"
+msgstr "Inndata-_metoder"
+
+msgid "VIM - Search and Replace..."
+msgstr "VIM - Søk og erstatt ..."
+
+msgid "VIM - Search..."
+msgstr "VIM - Søk ..."
+
+msgid "Find what:"
+msgstr "Finn hva:"
+
+msgid "Replace with:"
+msgstr "Erstatt med:"
+
+#. whole word only button
+msgid "Match whole word only"
+msgstr "Finn kun hele ord"
+
+#. match case button
+msgid "Match case"
+msgstr "Forskjell på store/små bokstaver"
+
+msgid "Direction"
+msgstr "Retning"
+
+#. 'Up' and 'Down' buttons
+msgid "Up"
+msgstr "Opp"
+
+msgid "Down"
+msgstr "Ned"
+
+msgid "Find Next"
+msgstr "Finn neste"
+
+msgid "Replace"
+msgstr "Erstatt"
+
+msgid "Replace All"
+msgstr "Erstatt alle"
+
+msgid "Vim: Received \"die\" request from session manager\n"
+msgstr "Vim: Mottok \"dø\"-forespørsel fra øktbehandleren\n"
+
+msgid "Close"
+msgstr "Lukk"
+
+#~ msgid "New tab"
+#~ msgstr ""
+
+#~ msgid "Open Tab..."
+#~ msgstr ""
+
+msgid "Vim: Main window unexpectedly destroyed\n"
+msgstr "Vim: Uventet ødeleggelse av hovedvinduet\n"
+
+msgid "Font Selection"
+msgstr "Velge skrifttype"
+
+msgid "Used CUT_BUFFER0 instead of empty selection"
+msgstr "Brukte CUT_BUFFER0 istedenfor tomt valg"
+
+msgid "&Filter"
+msgstr "&Filter"
+
+msgid "&Cancel"
+msgstr "&Avbryt"
+
+msgid "Directories"
+msgstr "Kataloger"
+
+msgid "Filter"
+msgstr "Filter"
+
+msgid "&Help"
+msgstr "&Hjelp"
+
+msgid "Files"
+msgstr "Filer"
+
+msgid "&OK"
+msgstr "&OK"
+
+msgid "Selection"
+msgstr "Valg"
+
+msgid "Find &Next"
+msgstr "Finn &neste"
+
+msgid "&Replace"
+msgstr "E&rstatt"
+
+msgid "Replace &All"
+msgstr "Erstatt &alle"
+
+msgid "&Undo"
+msgstr "&Angre"
+
+#, c-format
+msgid "E671: Cannot find window title \"%s\""
+msgstr "E671: Fant ikke vindutittel \"%s\""
+
+#, c-format
+msgid "E243: Argument not supported: \"-%s\"; Use the OLE version."
+msgstr "E243: Parameter ikke støttet: \"-%s\"; Bruk OLE-versjonen."
+
+msgid "E672: Unable to open window inside MDI application"
+msgstr "E672: Klarer ikke åpne vindu inne i MDI-applikasjon"
+
+#~ msgid "Close tab"
+#~ msgstr ""
+
+#~ msgid "Open tab..."
+#~ msgstr ""
+
+msgid "Find string (use '\\\\' to find a '\\')"
+msgstr "Finn streng (bruk '\\\\' for å finne en '\\')"
+
+msgid "Find & Replace (use '\\\\' to find a '\\')"
+msgstr "Søk og erstatt (bruk '\\\\' for å finne en '\\')"
+
+#. We fake this: Use a filter that doesn't select anything and a default
+#. * file name that won't be used.
+msgid "Not Used"
+msgstr "Ikke brukt"
+
+msgid "Directory\t*.nothing\n"
+msgstr "Katalog\t*.ingenting\n"
+
+msgid "Vim E458: Cannot allocate colormap entry, some colors may be incorrect"
+msgstr "Vim E458: Kan ikke reservere fargekart, noen farger kan være feil"
+
+#, c-format
+msgid "E250: Fonts for the following charsets are missing in fontset %s:"
+msgstr "E250: Skrifttyper for de følgende tegnsett mangler i fontsett %s:"
+
+#, c-format
+msgid "E252: Fontset name: %s"
+msgstr "E252: Navn på skrifttypesett: %s"
+
+#, c-format
+msgid "Font '%s' is not fixed-width"
+msgstr "Skrifttypen '%s' har ikke konstant bredde"
+
+#, c-format
+msgid "E253: Fontset name: %s\n"
+msgstr "E253: Navn på skrifttypesett: %s\n"
+
+#, c-format
+msgid "Font0: %s\n"
+msgstr "Font0: %s\n"
+
+#, c-format
+msgid "Font1: %s\n"
+msgstr "Font1: %s\n"
+
+#, c-format
+msgid "Font%ld width is not twice that of font0\n"
+msgstr "Font%ld-bredde er ikke to ganger bredden av font0\n"
+
+#, c-format
+msgid "Font0 width: %ld\n"
+msgstr "Font0-bredde: %ld\n"
+
+#, c-format
+msgid ""
+"Font1 width: %ld\n"
+"\n"
+msgstr ""
+"Font1-bredde: %ld\n"
+"\n"
+
+msgid "Invalid font specification"
+msgstr "Ugyldig skrifttypespesifisering"
+
+msgid "&Dismiss"
+msgstr "&Forkast"
+
+msgid "no specific match"
+msgstr "ingen spesifikke treff"
+
+msgid "Vim - Font Selector"
+msgstr "Vim - Skrifttypevelger"
+
+msgid "Name:"
+msgstr "Navn:"
+
+#. create toggle button
+msgid "Show size in Points"
+msgstr "Vis størrelse i punkter"
+
+msgid "Encoding:"
+msgstr "Koding:"
+
+msgid "Font:"
+msgstr "Skrifttype:"
+
+msgid "Style:"
+msgstr "Stil:"
+
+msgid "Size:"
+msgstr "Størrelse:"
+
+#~ msgid "E256: Hangul automata ERROR"
+#~ msgstr ""
+
+msgid "E550: Missing colon"
+msgstr "E550: Mangler kolon"
+
+msgid "E551: Illegal component"
+msgstr "E551: Ulovlig komponent"
+
+msgid "E552: digit expected"
+msgstr "E552: Siffer forventet"
+
+#, c-format
+msgid "Page %d"
+msgstr "Side %d"
+
+msgid "No text to be printed"
+msgstr "Ingen tekst for utskrift"
+
+#, c-format
+msgid "Printing page %d (%d%%)"
+msgstr "Skriver ut side %d (%d%%)"
+
+#, c-format
+msgid " Copy %d of %d"
+msgstr " Kopi %d av %d"
+
+#, c-format
+msgid "Printed: %s"
+msgstr "Skrevet ut: %s"
+
+msgid "Printing aborted"
+msgstr "Utskrift avbrutt"
+
+msgid "E455: Error writing to PostScript output file"
+msgstr "E455: Feil under skriving til Postscript-fil"
+
+#, c-format
+msgid "E624: Can't open file \"%s\""
+msgstr "E624: Kan ikke åpne filen \"%s\""
+
+#, c-format
+msgid "E457: Can't read PostScript resource file \"%s\""
+msgstr "E457: Kan ikke lese Postscript-ressursfil \"%s\""
+
+#, c-format
+msgid "E618: file \"%s\" is not a PostScript resource file"
+msgstr "E618: Filen \"%s\" er ikke en Postscript-ressursfil"
+
+#, c-format
+msgid "E619: file \"%s\" is not a supported PostScript resource file"
+msgstr "E619: Det er ikke støtte for Postscript-ressursfilen \"%s\""
+
+#, c-format
+msgid "E621: \"%s\" resource file has wrong version"
+msgstr "E621: Ressursfilen \"%s\" er feil versjon"
+
+msgid "E673: Incompatible multi-byte encoding and character set."
+msgstr "E673: Inkompatibel multibytekoding og tegnsett"
+
+msgid "E674: printmbcharset cannot be empty with multi-byte encoding."
+msgstr "E674: printmbcharset kan ikke være tom med multibytekoding"
+
+msgid "E675: No default font specified for multi-byte printing."
+msgstr "E675: Ingen standardfont spesifisert for multibyteutskrift"
+
+msgid "E324: Can't open PostScript output file"
+msgstr "E324: Kan ikke åpne Postscript-fil for skriving"
+
+#, c-format
+msgid "E456: Can't open file \"%s\""
+msgstr "E456: Kan ikke åpne filen \"%s\""
+
+msgid "E456: Can't find PostScript resource file \"prolog.ps\""
+msgstr "E456: Fant ikke Postscript-ressursfilen \"prolog.ps\""
+
+msgid "E456: Can't find PostScript resource file \"cidfont.ps\""
+msgstr "E456: Fant ikke Postscript-ressursfilen \"cidfont.ps\""
+
+#, c-format
+msgid "E456: Can't find PostScript resource file \"%s.ps\""
+msgstr "E456: Fant ikke Postscript-ressursfilen \"%s.ps\""
+
+#, c-format
+msgid "E620: Unable to convert to print encoding \"%s\""
+msgstr "E620: Klarte ikke å konvertere til utskriftskoding \"%s\""
+
+msgid "Sending to printer..."
+msgstr "Sender til skriver ..."
+
+msgid "E365: Failed to print PostScript file"
+msgstr "E365: Feil under utskrift av Postscript-fil"
+
+msgid "Print job sent."
+msgstr "Skriverjobb sendt."
+
+msgid "Add a new database"
+msgstr "Legg til en ny database"
+
+msgid "Query for a pattern"
+msgstr "Forespørsel etter søkestreng"
+
+msgid "Show this message"
+msgstr "Vis denne meldingen"
+
+msgid "Kill a connection"
+msgstr "Drep en forbindelse"
+
+msgid "Reinit all connections"
+msgstr "Reinitialiser alle forbindelser"
+
+msgid "Show connections"
+msgstr "Vis forbindelser"
+
+#, c-format
+msgid "E560: Usage: cs[cope] %s"
+msgstr "E560: Bruk: cs[cope] %s"
+
+msgid "This cscope command does not support splitting the window.\n"
+msgstr "Denne cscope-kommandoen støtter ikke splitting av vinduet.\n"
+
+msgid "E562: Usage: cstag <ident>"
+msgstr "E562: Bruk: cstag <identifikator>"
+
+msgid "E257: cstag: tag not found"
+msgstr "E257: cstag: Tag ikke funnet"
+
+#, c-format
+msgid "E563: stat(%s) error: %d"
+msgstr "E563: stat(%s) feil: %d"
+
+msgid "E563: stat error"
+msgstr "E563: \"stat\"-feil"
+
+#, c-format
+msgid "E564: %s is not a directory or a valid cscope database"
+msgstr "E564: %s er ikke en katalog eller gyldig cscope-database"
+
+#, c-format
+msgid "Added cscope database %s"
+msgstr "La til cscope-database %s"
+
+#, c-format
+msgid "E262: error reading cscope connection %ld"
+msgstr "E262: Feil under lesing av cscope-forbindelse %ld"
+
+msgid "E561: unknown cscope search type"
+msgstr "E561: Ukjent cscope-søketype"
+
+msgid "E566: Could not create cscope pipes"
+msgstr "E566: Kunne ikke lage cscope-rør (\"pipe\")"
+
+msgid "E622: Could not fork for cscope"
+msgstr "E622: Klarte ikke lage tvillingprosess for cscope"
+
+msgid "cs_create_connection exec failed"
+msgstr "Utføring av cs_create_connection feilet"
+
+msgid "E623: Could not spawn cscope process"
+msgstr "E623: Klarte ikke starte cscope-prosess"
+
+msgid "cs_create_connection: fdopen for to_fp failed"
+msgstr "cs_create_connection: fdopen for to_fp feilet"
+
+msgid "cs_create_connection: fdopen for fr_fp failed"
+msgstr "cs_create_connection: fdopen for fr_fp feilet"
+
+msgid "E567: no cscope connections"
+msgstr "E567: Ingen cscope-forbindelse"
+
+#, c-format
+msgid "E259: no matches found for cscope query %s of %s"
+msgstr "E259: Ingen treff funnet for cscope-forespørsel %s av %s"
+
+#, c-format
+msgid "E469: invalid cscopequickfix flag %c for %c"
+msgstr "E469: Ugyldig \"cscopequickfix\"-flagg %c for %c"
+
+msgid "cscope commands:\n"
+msgstr "cscope-kommandoer:\n"
+
+#, c-format
+msgid "%-5s: %-30s (Usage: %s)"
+msgstr "%-5s: %-30s (Bruk: %s)"
+
+#, c-format
+msgid "E625: cannot open cscope database: %s"
+msgstr "E625: Kan ikke åpne cscope-database: %s"
+
+msgid "E626: cannot get cscope database information"
+msgstr "E626: Kan ikke hente informasjon om cscope-database"
+
+msgid "E568: duplicate cscope database not added"
+msgstr "E568: Duplisert cscope-database ikke lagt til"
+
+msgid "E569: maximum number of cscope connections reached"
+msgstr "E569: Maksimum antall cscope-forbindelser nådd"
+
+#, c-format
+msgid "E261: cscope connection %s not found"
+msgstr "E261: cscope-forbindelse %s ikke funnet"
+
+#, c-format
+msgid "cscope connection %s closed"
+msgstr "cscope-forbindelsen %s stengt"
+
+#. should not reach here
+msgid "E570: fatal error in cs_manage_matches"
+msgstr "E570: Kritisk feil i cs_manage_matches"
+
+#, c-format
+msgid "Cscope tag: %s"
+msgstr "Cscope-tag: %s"
+
+msgid ""
+"\n"
+" # line"
+msgstr ""
+"\n"
+" # linje"
+
+msgid "filename / context / line\n"
+msgstr "filnavn / kontekst / linje\n"
+
+#, c-format
+msgid "E609: Cscope error: %s"
+msgstr "E609: Cscope-feil: %s"
+
+msgid "All cscope databases reset"
+msgstr "Alle cscope-databaser resatt"
+
+msgid "no cscope connections\n"
+msgstr "ingen cscope-forbindelser\n"
+
+msgid " # pid database name prepend path\n"
+msgstr " # pid databasenavn legg til sti\n"
+
+msgid ""
+"???: Sorry, this command is disabled, the MzScheme library could not be "
+"loaded."
+msgstr ""
+"???: Denne kommandoen er deaktivert, MzScheme-biblioteket kunne ikke lastes."
+
+msgid "invalid expression"
+msgstr "ugyldig uttrykk"
+
+msgid "expressions disabled at compile time"
+msgstr "uttrykk deaktivert på kompileringsstadiet"
+
+msgid "hidden option"
+msgstr "skjult valg"
+
+msgid "unknown option"
+msgstr "ukjent valg"
+
+msgid "window index is out of range"
+msgstr "indeks for vindu er utenfor område"
+
+msgid "couldn't open buffer"
+msgstr "klarte ikke å åpne buffer"
+
+msgid "cannot save undo information"
+msgstr "kan ikke lagre angre-informasjon"
+
+msgid "cannot delete line"
+msgstr "kan ikke slette linje"
+
+msgid "cannot replace line"
+msgstr "kan ikke erstatte linje"
+
+msgid "cannot insert line"
+msgstr "kan ikke sette inn linje"
+
+msgid "string cannot contain newlines"
+msgstr "streng kan ikke inneholde linjeskift"
+
+msgid "Vim error: ~a"
+msgstr "Vim-feil: ~a"
+
+msgid "Vim error"
+msgstr "Vim-feil"
+
+msgid "buffer is invalid"
+msgstr "buffer er ugyldig"
+
+msgid "window is invalid"
+msgstr "vindu er ugyldig"
+
+msgid "linenr out of range"
+msgstr "linjenummer utenfor område"
+
+msgid "not allowed in the Vim sandbox"
+msgstr "ikke tillatt i Vim-sandkassen"
+
+msgid ""
+"E263: Sorry, this command is disabled, the Python library could not be "
+"loaded."
+msgstr ""
+"E263: Denne kommandoen er deaktivert, Python-biblioteket kunne ikke lastes."
+
+msgid "E659: Cannot invoke Python recursively"
+msgstr "E659: Kan ikke starte Python rekursivt"
+
+msgid "can't delete OutputObject attributes"
+msgstr "Kan ikke slette \"OutputObject\"-attributter"
+
+msgid "softspace must be an integer"
+msgstr "\"softspace\" må være et heltall"
+
+msgid "invalid attribute"
+msgstr "ugyldig attributt"
+
+msgid "writelines() requires list of strings"
+msgstr "writelines() krever en liste av strenger"
+
+msgid "E264: Python: Error initialising I/O objects"
+msgstr "E264: Python: Feil under initialisering av I/U-objekter"
+
+msgid "attempt to refer to deleted buffer"
+msgstr "forsøk på å referere til slettet buffer"
+
+msgid "line number out of range"
+msgstr "linjenummer utenfor område"
+
+#, c-format
+msgid "<buffer object (deleted) at %8lX>"
+msgstr "<bufferobjekt (slettet) ved %8lX>"
+
+msgid "invalid mark name"
+msgstr "ugyldig merkenavn"
+
+msgid "no such buffer"
+msgstr "bufferen finnes ikke"
+
+msgid "attempt to refer to deleted window"
+msgstr "forsøk på å referere til slettet vindu"
+
+msgid "readonly attribute"
+msgstr "skrivebeskyttet attributt"
+
+msgid "cursor position outside buffer"
+msgstr "markørposisjon utenfor buffer"
+
+#, c-format
+msgid "<window object (deleted) at %.8lX>"
+msgstr "<vindusobjekt (slettet) ved %.8lX>"
+
+#, c-format
+msgid "<window object (unknown) at %.8lX>"
+msgstr "<vindusobjekt (ukjent) ved %.8lX>"
+
+#, c-format
+msgid "<window %d>"
+msgstr "<vindu %d>"
+
+msgid "no such window"
+msgstr "vinduet finnes ikke"
+
+#~ msgid "E265: $_ must be an instance of String"
+#~ msgstr ""
+
+msgid ""
+"E266: Sorry, this command is disabled, the Ruby library could not be loaded."
+msgstr ""
+"E266: Denne kommandoen er deaktivert, Ruby-biblioteket kunne ikke lastes."
+
+msgid "E267: unexpected return"
+msgstr "E267: Uventet return"
+
+msgid "E268: unexpected next"
+msgstr "E268: Uvented next"
+
+msgid "E269: unexpected break"
+msgstr "E269: Uventet break"
+
+msgid "E270: unexpected redo"
+msgstr "E270: Uventet redo"
+
+#~ msgid "E271: retry outside of rescue clause"
+#~ msgstr ""
+
+msgid "E272: unhandled exception"
+msgstr "E272: Ubehandlet unntak"
+
+#, c-format
+msgid "E273: unknown longjmp status %d"
+msgstr "E273: Ukjent longjmp-status %d"
+
+msgid "Toggle implementation/definition"
+msgstr "Bytt mellom implementasjon/definisjon"
+
+msgid "Show base class of"
+msgstr "Vis basisklasse av"
+
+msgid "Show overridden member function"
+msgstr "Vis overstyrt medlemsfunksjon"
+
+msgid "Retrieve from file"
+msgstr "Hent fra fil"
+
+msgid "Retrieve from project"
+msgstr "Hent fra prosjekt"
+
+msgid "Retrieve from all projects"
+msgstr "Hent fra alle prosjekter"
+
+msgid "Retrieve"
+msgstr "Hent"
+
+msgid "Show source of"
+msgstr "Vis kilde til"
+
+msgid "Find symbol"
+msgstr "Finn symbol"
+
+msgid "Browse class"
+msgstr "Bla gjennom klasse"
+
+msgid "Show class in hierarchy"
+msgstr "Vis klasse i hierarki"
+
+msgid "Show class in restricted hierarchy"
+msgstr "Vis klasse i begrenset hierarki"
+
+msgid "Xref refers to"
+msgstr "Xref refererer til"
+
+msgid "Xref referred by"
+msgstr "Xref referert av"
+
+msgid "Xref has a"
+msgstr "Xref har en"
+
+msgid "Xref used by"
+msgstr "Xref brukt av"
+
+msgid "Show docu of"
+msgstr "Vis docu av"
+
+msgid "Generate docu for"
+msgstr "Generer docu for"
+
+msgid ""
+"Cannot connect to SNiFF+. Check environment (sniffemacs must be found in "
+"$PATH).\n"
+msgstr ""
+"Kan ikke koble til SNiFF+. Sjekk miljøet (\"environment\") (sniffemacs må "
+"bli funnet i $PATH).\n"
+
+msgid "E274: Sniff: Error during read. Disconnected"
+msgstr "E274: Sniff: Feil under lesing. Frakoblet"
+
+msgid "SNiFF+ is currently "
+msgstr "SNiFF+ er for øyeblikket "
+
+msgid "not "
+msgstr "ikke "
+
+msgid "connected"
+msgstr "oppkoblet"
+
+#, c-format
+msgid "E275: Unknown SNiFF+ request: %s"
+msgstr "E275: Ukjent SNiFF+-forespørsel: %s"
+
+msgid "E276: Error connecting to SNiFF+"
+msgstr "E276: Feil ved oppkobling til SNiFF+"
+
+msgid "E278: SNiFF+ not connected"
+msgstr "E278: SNiFF+ ikke tilkoblet"
+
+msgid "E279: Not a SNiFF+ buffer"
+msgstr "E279: Ikke en SNiFF+-buffer"
+
+msgid "Sniff: Error during write. Disconnected"
+msgstr "Sniff: Feil under skriving. Frakoblet"
+
+msgid "invalid buffer number"
+msgstr "ugyldig buffernummer"
+
+msgid "not implemented yet"
+msgstr "ikke implementert enda"
+
+#. ???
+msgid "cannot set line(s)"
+msgstr "kan ikke sette linje(r)"
+
+msgid "mark not set"
+msgstr "merke ikke satt"
+
+#, c-format
+msgid "row %d column %d"
+msgstr "rad %d kolonne %d"
+
+msgid "cannot insert/append line"
+msgstr "kan ikke sette inn/legge til linje"
+
+msgid "unknown flag: "
+msgstr "ukjent flagg: "
+
+msgid "unknown vimOption"
+msgstr "ukjent vimOption"
+
+msgid "keyboard interrupt"
+msgstr "tastaturavbrudd"
+
+msgid "vim error"
+msgstr "vim-feil"
+
+msgid "cannot create buffer/window command: object is being deleted"
+msgstr "kan ikke opprette buffer/vindukommando: Objektet slettes"
+
+msgid ""
+"cannot register callback command: buffer/window is already being deleted"
+msgstr ""
+"kan ikke registrere callback-kommando: Buffer/vindu er allerede slettet"
+
+#. This should never happen. Famous last word?
+msgid ""
+"E280: TCL FATAL ERROR: reflist corrupt!? Please report this to vim-dev@vim."
+"org"
+msgstr ""
+"E280: TCL KRITISK FEIL: reflist skadet!? Vennligst rapporter dette til vim-"
+"dev@vim.org"
+
+msgid "cannot register callback command: buffer/window reference not found"
+msgstr ""
+"kan ikke registrere callback-kommando: Buffer/vindureferanse ikke funnet"
+
+msgid ""
+"E571: Sorry, this command is disabled: the Tcl library could not be loaded."
+msgstr ""
+"E571: Denne kommandoen er deaktivert, Tcl-biblioteket kunne ikke lastes."
+
+msgid ""
+"E281: TCL ERROR: exit code is not int!? Please report this to vim-dev@vim.org"
+msgstr ""
+"E281: TCL-FEIL: Avslutningskode er ikke int!? Vennligst rapporter dette til "
+"vim-dev@vim.org"
+
+#, c-format
+msgid "E572: exit code %d"
+msgstr "E572: Avslutningskode %d"
+
+msgid "cannot get line"
+msgstr "kan ikke hente linje"
+
+msgid "Unable to register a command server name"
+msgstr "Klarer ikke registrere kommandotjenernavn"
+
+msgid "E248: Failed to send command to the destination program"
+msgstr "E248: Klarte ikke sende kommando til destinasjonsprogrammet"
+
+#, c-format
+msgid "E573: Invalid server id used: %s"
+msgstr "E573: Ugyldig tjener-id brukt: %s"
+
+msgid "E251: VIM instance registry property is badly formed. Deleted!"
+msgstr ""
+"E251: Registry-egenskapen for VIM-oppføringen er ikke korrekt. Slettet!"
+
+msgid "Unknown option argument"
+msgstr "Ukjent parameter til valg"
+
+msgid "Too many edit arguments"
+msgstr "For mange redigeringsparametere"
+
+msgid "Argument missing after"
+msgstr "Parameter mangler etter"
+
+msgid "Garbage after option argument"
+msgstr "Søppel etter valgparameter"
+
+msgid "Too many \"+command\", \"-c command\" or \"--cmd command\" arguments"
+msgstr ""
+"For mange \"+command\"-, \"-c command\"- eller \"--cmd kommando\"-parametere"
+
+msgid "Invalid argument for"
+msgstr "Ugyldig parameter for"
+
+#, c-format
+msgid "%d files to edit\n"
+msgstr "%d filer å redigere\n"
+
+msgid "This Vim was not compiled with the diff feature."
+msgstr "Denne Vim-versjonen er kompilert uten differansefunksjonen."
+
+msgid "Attempt to open script file again: \""
+msgstr "Forsøk på å åpne skriptfilen igjen: \""
+
+msgid "Cannot open for reading: \""
+msgstr "Kan ikke åpne for lesing: \""
+
+msgid "Cannot open for script output: \""
+msgstr "Kan ikke åpne for skript-utdata: \""
+
+msgid "Vim: Error: Failure to start gvim from NetBeans\n"
+msgstr "Vim: Feil: Feil under start av gvim fra NetBeans\n"
+
+msgid "Vim: Warning: Output is not to a terminal\n"
+msgstr "Vim: Advarsel: Utdata går ikke til en terminal\n"
+
+msgid "Vim: Warning: Input is not from a terminal\n"
+msgstr "Vim: Advarsel: Inndata kommer ikke fra en terminal\n"
+
+#. just in case..
+msgid "pre-vimrc command line"
+msgstr "pre-vimrc kommandolinje"
+
+#, c-format
+msgid "E282: Cannot read from \"%s\""
+msgstr "E282: Kan ikke lese fra \"%s\""
+
+msgid ""
+"\n"
+"More info with: \"vim -h\"\n"
+msgstr ""
+"\n"
+"Mer info med: \"vim -h\"\n"
+
+msgid "[file ..] edit specified file(s)"
+msgstr "[file ..] rediger spesifisert(e) fil(er)"
+
+msgid "- read text from stdin"
+msgstr "- les tekst fra stdin"
+
+msgid "-t tag edit file where tag is defined"
+msgstr "-t tag rediger fil hvor en tag er definert"
+
+msgid "-q [errorfile] edit file with first error"
+msgstr "-q [feilfil] rediger fil med første feil"
+
+msgid ""
+"\n"
+"\n"
+"Usage:"
+msgstr ""
+"\n"
+"\n"
+"bruk:"
+
+msgid " vim [arguments] "
+msgstr " vim [parametere] "
+
+msgid ""
+"\n"
+" or:"
+msgstr ""
+"\n"
+" eller:"
+
+msgid "where case is ignored prepend / to make flag upper case"
+msgstr ""
+"der bokstavstørrelse ignoreres, legg til / i begynnelsen for "
+"å gjøre flagget om til stor bokstav"
+
+msgid ""
+"\n"
+"\n"
+"Arguments:\n"
+msgstr ""
+"\n"
+"\n"
+"Parametere:\n"
+
+msgid "--\t\t\tOnly file names after this"
+msgstr "--\t\t\tBare filnavn etter dette"
+
+msgid "--literal\t\tDon't expand wildcards"
+msgstr "--literal\t\tIkke utvid jokertegn"
+
+msgid "-register\t\tRegister this gvim for OLE"
+msgstr "-register\t\tRegistrer gvim for OLE"
+
+msgid "-unregister\t\tUnregister gvim for OLE"
+msgstr "-unregister\t\tFjern OLE-registrering for gvim"
+
+msgid "-g\t\t\tRun using GUI (like \"gvim\")"
+msgstr "-g\t\t\tKjør med GUI (som \"gvim\")"
+
+msgid "-f or --nofork\tForeground: Don't fork when starting GUI"
+msgstr "-f eller --nofork\tForgrunn: Ikke fork når GUI-et startes"
+
+msgid "-v\t\t\tVi mode (like \"vi\")"
+msgstr "-v\t\t\tVi-modus (som \"vi\")"
+
+msgid "-e\t\t\tEx mode (like \"ex\")"
+msgstr "-e\t\t\tEx-modus (som \"ex\")"
+
+msgid "-s\t\t\tSilent (batch) mode (only for \"ex\")"
+msgstr "-s\t\t\tStille (batch) modus (bare for \"ex\")"
+
+msgid "-d\t\t\tDiff mode (like \"vimdiff\")"
+msgstr "-d\t\t\tDifferanse-modus (som \"vimdiff\")"
+
+msgid "-y\t\t\tEasy mode (like \"evim\", modeless)"
+msgstr "-y\t\t\tLett modus (som \"evim\", uten modus)"
+
+msgid "-R\t\t\tReadonly mode (like \"view\")"
+msgstr "-R\t\t\tSkrivebeskyttet modus (som \"view\")"
+
+msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
+msgstr "-Z\t\t\tBegrenset modus (som \"rvim\")"
+
+msgid "-m\t\t\tModifications (writing files) not allowed"
+msgstr "-m\t\t\tModifisering (lagring av filer) ikke tillatt"
+
+msgid "-M\t\t\tModifications in text not allowed"
+msgstr "-M\t\t\tModifiseringer i teksten ikke tillatt"
+
+msgid "-b\t\t\tBinary mode"
+msgstr "-b\t\t\tBinærmodus"
+
+msgid "-l\t\t\tLisp mode"
+msgstr "-l\t\t\tLisp-modus"
+
+msgid "-C\t\t\tCompatible with Vi: 'compatible'"
+msgstr "-C\t\t\tKompatibel med Vi: 'compatible'"
+
+msgid "-N\t\t\tNot fully Vi compatible: 'nocompatible'"
+msgstr "-N\t\t\tIkke helt Vi-kompatibel: 'nocompatible'"
+
+msgid "-V[N]\t\tVerbose level"
+msgstr "-V[N]\t\tInformasjonsnivå (\"Verbose\")"
+
+msgid "-D\t\t\tDebugging mode"
+msgstr "-D\t\t\tDebuggingsmodus"
+
+msgid "-n\t\t\tNo swap file, use memory only"
+msgstr "-n\t\t\tIngen swapfil, bruk bare hukommelsen"
+
+msgid "-r\t\t\tList swap files and exit"
+msgstr "-r\t\t\tList swapfiler og avslutt"
+
+msgid "-r (with file name)\tRecover crashed session"
+msgstr "-r (med filnavn)\tGjenopprett kræsjet økt"
+
+msgid "-L\t\t\tSame as -r"
+msgstr "-L\t\t\tSamme som -r"
+
+msgid "-f\t\t\tDon't use newcli to open window"
+msgstr "-f\t\t\tIkke bruk newcli for å åpne vindu"
+
+msgid "-dev <device>\t\tUse <device> for I/O"
+msgstr "-dev <enhet>\t\tBruk <enhet> for I/U"
+
+msgid "-A\t\t\tStart in Arabic mode"
+msgstr "-A\t\t\tStart i arabisk modus"
+
+msgid "-H\t\t\tStart in Hebrew mode"
+msgstr "-H\t\t\tStart i hebraisk modus"
+
+msgid "-F\t\t\tStart in Farsi mode"
+msgstr "-F\t\t\tStart i persisk (Farsi) modus"
+
+msgid "-T <terminal>\tSet terminal type to <terminal>"
+msgstr "-T <terminal>\tSett terminaltypen til <terminal>"
+
+msgid "-u <vimrc>\t\tUse <vimrc> instead of any .vimrc"
+msgstr "-u <vimrc>\t\tBruk <vimrc> istedenfor eventuell .vimrc"
+
+msgid "-U <gvimrc>\t\tUse <gvimrc> instead of any .gvimrc"
+msgstr "-U <gvimrc>\t\tBruk <gvimrc> istedenfor eventuell .gvimrc"
+
+msgid "--noplugin\t\tDon't load plugin scripts"
+msgstr "--noplugin\t\tIkke last plugin-skripts"
+
+#, fuzzy
+#~ msgid "-p[N]\t\tOpen N tab pages (default: one for each file)"
+#~ msgstr "-o[N]\t\tÅpne N vinduer (standard: Ett for hver fil)"
+
+msgid "-o[N]\t\tOpen N windows (default: one for each file)"
+msgstr "-o[N]\t\tÅpne N vinduer (standard: Ett for hver fil)"
+
+msgid "-O[N]\t\tLike -o but split vertically"
+msgstr "-O[N]\t\tSom -o men splitt loddrett"
+
+msgid "+\t\t\tStart at end of file"
+msgstr "+\t\t\tStart på slutten av filen"
+
+msgid "+<lnum>\t\tStart at line <lnum>"
+msgstr "+<lnr>\t\tStart på linje <lnr>"
+
+msgid "--cmd <command>\tExecute <command> before loading any vimrc file"
+msgstr "--cmd <kommando>\tKjør <kommando> før lasting av vimrc-filer"
+
+msgid "-c <command>\t\tExecute <command> after loading the first file"
+msgstr "-c <kommando>\tKjør <kommando> etter lasting av første fil"
+
+msgid "-S <session>\t\tSource file <session> after loading the first file"
+msgstr "-S <økt>\t\tKjør filen <økt> etter lasting av første fil"
+
+msgid "-s <scriptin>\tRead Normal mode commands from file <scriptin>"
+msgstr "-s <innskript>\tLes normalmodus-kommandoer fra filen <innskript>"
+
+msgid "-w <scriptout>\tAppend all typed commands to file <scriptout>"
+msgstr "-w <utskript>\tLegg alle skrevne kommandoer til filen <utskript>"
+
+msgid "-W <scriptout>\tWrite all typed commands to file <scriptout>"
+msgstr "-W <utskript>\tSkriv alle skrevne kommandoer til filen <utskript>"
+
+msgid "-x\t\t\tEdit encrypted files"
+msgstr "-x\t\t\tRediger krypterte filer"
+
+msgid "-display <display>\tConnect vim to this particular X-server"
+msgstr "-display <display>\tKoble vim til denne spesielle X-tjeneren"
+
+msgid "-X\t\t\tDo not connect to X server"
+msgstr "-X\t\t\tUnngå oppkobling til X-tjener"
+
+msgid "--remote <files>\tEdit <files> in a Vim server if possible"
+msgstr "--remote <filer>\tRediger <filer> på en Vim-tjener hvis mulig"
+
+msgid "--remote-silent <files> Same, don't complain if there is no server"
+msgstr "--remote-silent <filer> Samme, ikke klag hvis tjeneren mangler"
+
+msgid ""
+"--remote-wait <files> As --remote but wait for files to have been edited"
+msgstr ""
+"--remote-wait <filer> Som --remote men vent på filer som blir redigert"
+
+msgid ""
+"--remote-wait-silent <files> Same, don't complain if there is no server"
+msgstr "--remote-wait-silent <files> Samme, ikke klag hvis tjeneren mangler"
+
+#, fuzzy
+#~ msgid "--remote-tab <files> As --remote but open tab page for each file"
+#~ msgstr ""
+#~ "--remote-wait <filer> Som --remote men vent på filer som blir redigert"
+
+msgid "--remote-send <keys>\tSend <keys> to a Vim server and exit"
+msgstr "--remote-send <nøkler>\tSend <nøkler> til en Vim-tjener og avslutt"
+
+msgid "--remote-expr <expr>\tEvaluate <expr> in a Vim server and print result"
+msgstr ""
+"--remote-expr <uttrykk>\tEvaluer <uttrykk> på en Vim-tjener og skriv "
+"resultatet"
+
+msgid "--serverlist\t\tList available Vim server names and exit"
+msgstr "--serverlist\t\tList navn på tilgjengelige Vim-tjenere og avslutt"
+
+msgid "--servername <name>\tSend to/become the Vim server <name>"
+msgstr "--servername <navn>\tSend til/bli Vim-tjeneren <navn>"
+
+msgid "-i <viminfo>\t\tUse <viminfo> instead of .viminfo"
+msgstr "-i <viminfo>\t\tBruk <viminfo> istedenfor .viminfo"
+
+msgid "-h or --help\tPrint Help (this message) and exit"
+msgstr "-h eller --help\tSkriv hjelpen (denne teksten) og avslutt"
+
+msgid "--version\t\tPrint version information and exit"
+msgstr "--version\t\tSkriv versjonsinformasjon og avslutt"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Motif version):\n"
+msgstr ""
+"\n"
+"Parametere gjenkjent av gvim (Motif-versjon):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (neXtaw version):\n"
+msgstr ""
+"\n"
+"Parametere gjenkjent av gvim (neXtaw-versjon):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Athena version):\n"
+msgstr ""
+"\n"
+"Parametere gjenkjent av gvim (Athena-versjon):\n"
+
+msgid "-display <display>\tRun vim on <display>"
+msgstr "-display <display>\tKjør vim på <display>"
+
+msgid "-iconic\t\tStart vim iconified"
+msgstr "-iconic\t\tStart vim som ikon"
+
+msgid "-name <name>\t\tUse resource as if vim was <name>"
+msgstr "-name <navn>\t\tBruk ressurs som om Vim var <navn>"
+
+msgid "\t\t\t (Unimplemented)\n"
+msgstr "\t\t\t (Ikke implementert)\n"
+
+msgid "-background <color>\tUse <color> for the background (also: -bg)"
+msgstr "-background <farge>\tBruk <farge> på bakgrunnen (også: -bg)"
+
+msgid "-foreground <color>\tUse <color> for normal text (also: -fg)"
+msgstr "-foreground <farge>\tBruk <farge> på normal tekst (også: -fg)"
+
+msgid "-font <font>\t\tUse <font> for normal text (also: -fn)"
+msgstr "-font <skrifttype>\t\tBruk <skrifttype> på normal tekst (også: -fn)"
+
+msgid "-boldfont <font>\tUse <font> for bold text"
+msgstr "-boldfont <skrifttype>\tBruk <skrifttype> på fet skrift"
+
+msgid "-italicfont <font>\tUse <font> for italic text"
+msgstr "-italicfont <skrifttype>\tBruk <skrifttype> på skrå tekst"
+
+msgid "-geometry <geom>\tUse <geom> for initial geometry (also: -geom)"
+msgstr ""
+"-geometry <geom>\tBruk <geom> for innledende vindusplassering (også: -geom)"
+
+msgid "-borderwidth <width>\tUse a border width of <width> (also: -bw)"
+msgstr ""
+"-borderwidth <bredde>\tBruk en rammebredde tilsvarende <bredde> (også: -bw)"
+
+msgid "-scrollbarwidth <width> Use a scrollbar width of <width> (also: -sw)"
+msgstr ""
+"-scrollbarwidth <bredde> Bruk en rullefeltbredde tilsvarende <bredde> "
+"(også: -sw)"
+
+msgid "-menuheight <height>\tUse a menu bar height of <height> (also: -mh)"
+msgstr ""
+"-menuheight <høyde>\tBruk en menyblokkhøyde tilsvarende <høyde> (også: -mh)"
+
+msgid "-reverse\t\tUse reverse video (also: -rv)"
+msgstr "-reverse\t\tBruk invers video (også: -rv)"
+
+msgid "+reverse\t\tDon't use reverse video (also: +rv)"
+msgstr "+reverse\t\tIkke bruk invers video (også: +rv)"
+
+msgid "-xrm <resource>\tSet the specified resource"
+msgstr "-xrm <ressurs>\tSett den spesifiserte ressursen"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (RISC OS version):\n"
+msgstr ""
+"\n"
+"Parametere gjenkjent av gvim (RISC OS-versjon):\n"
+
+msgid "--columns <number>\tInitial width of window in columns"
+msgstr "--columns <antall>\tInnledende bredde på vindu i kolonner"
+
+msgid "--rows <number>\tInitial height of window in rows"
+msgstr "--rows <antall>\tInnledende høyde på vindu i rader"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (GTK+ version):\n"
+msgstr ""
+"\n"
+"Parametere gjenkjent av gvim (GTK+-versjon):\n"
+
+msgid "-display <display>\tRun vim on <display> (also: --display)"
+msgstr "-display <display>\tKjør vim på <display> (også: --display)"
+
+msgid "--role <role>\tSet a unique role to identify the main window"
+msgstr "--role <role>\tSett en unik \"role\" for å identifisere hovedvinduet"
+
+msgid "--socketid <xid>\tOpen Vim inside another GTK widget"
+msgstr "--socketid <xid>\tÅpne Vim innenfor et annet GTK-skjermelement"
+
+msgid "-P <parent title>\tOpen Vim inside parent application"
+msgstr "-P <foreldretittel>\tStart Vim innenfor et foreldreprogram"
+
+msgid "No display"
+msgstr "Ingen display"
+
+#. Failed to send, abort.
+msgid ": Send failed.\n"
+msgstr ": Send feilet.\n"
+
+#. Let vim start normally.
+msgid ": Send failed. Trying to execute locally\n"
+msgstr ": Send feilet. Prøver å utføre lokalt\n"
+
+#, c-format
+msgid "%d of %d edited"
+msgstr "%d av %d redigert"
+
+msgid "No display: Send expression failed.\n"
+msgstr "Ingen display: Sending av uttrykk feilet.\n"
+
+msgid ": Send expression failed.\n"
+msgstr ": Sending av uttrykk feilet.\n"
+
+msgid "No marks set"
+msgstr "Ingen merker satt"
+
+#, c-format
+msgid "E283: No marks matching \"%s\""
+msgstr "E283: Ingen merker samsvarer med \"%s\""
+
+#. Highlight title
+msgid ""
+"\n"
+"mark line col file/text"
+msgstr ""
+"\n"
+"merk linje kol fil/tekst"
+
+#. Highlight title
+msgid ""
+"\n"
+" jump line col file/text"
+msgstr ""
+"\n"
+" hopp linje kol fil/tekst"
+
+#. Highlight title
+msgid ""
+"\n"
+"change line col text"
+msgstr ""
+"\n"
+"forand linje kol tekst"
+
+#, c-format
+msgid ""
+"\n"
+"# File marks:\n"
+msgstr ""
+"\n"
+"# Filmerker:\n"
+
+#. Write the jumplist with -'
+#, c-format
+msgid ""
+"\n"
+"# Jumplist (newest first):\n"
+msgstr ""
+"\n"
+"# Hoppliste (nyeste først):\n"
+
+#, c-format
+msgid ""
+"\n"
+"# History of marks within files (newest to oldest):\n"
+msgstr ""
+"\n"
+"# Historie for merker inne i filer (yngst til eldst):\n"
+
+msgid "Missing '>'"
+msgstr "Mangler '>'"
+
+msgid "E543: Not a valid codepage"
+msgstr "E543: Er ikke en gyldig codepage"
+
+msgid "E284: Cannot set IC values"
+msgstr "E284: Kan ikke sette IC-verdier (\"Input Context\")"
+
+msgid "E285: Failed to create input context"
+msgstr "E285: Klarte ikke opprette inndatakontekst"
+
+msgid "E286: Failed to open input method"
+msgstr "E286: Klarte ikke åpne inndatametode"
+
+msgid "E287: Warning: Could not set destroy callback to IM"
+msgstr ""
+"E287: Advarsel: Klarte ikke sette \"destroy callback\" til inndatametode"
+
+msgid "E288: input method doesn't support any style"
+msgstr "E288: Inndatametode støtter ikke enhver stil"
+
+msgid "E289: input method doesn't support my preedit type"
+msgstr "E289: Inndatametode støtter ikke min \"preedit\" type"
+
+msgid "E290: over-the-spot style requires fontset"
+msgstr "E290: \"over-the-spot\"-stil trenger et skrifttypesett"
+
+msgid "E291: Your GTK+ is older than 1.2.3. Status area disabled"
+msgstr "E291: Din GTK+ er eldre enn 1.2.3. Statusområde deaktivert"
+
+msgid "E292: Input Method Server is not running"
+msgstr "E292: Inndatametodetjener kjører ikke"
+
+msgid "E293: block was not locked"
+msgstr "E293: Blokken var ikke låst"
+
+msgid "E294: Seek error in swap file read"
+msgstr "E294: Søkefeil i lesing av swapfil"
+
+msgid "E295: Read error in swap file"
+msgstr "E295: Lesefeil i swapfil"
+
+msgid "E296: Seek error in swap file write"
+msgstr "E296: Søkefeil i skriving til swapfil"
+
+msgid "E297: Write error in swap file"
+msgstr "E297: Skrivefeil i swapfil"
+
+msgid "E300: Swap file already exists (symlink attack?)"
+msgstr "E300: Swapfilen finnes allerede (symlenke-angrep?)"
+
+msgid "E298: Didn't get block nr 0?"
+msgstr "E298: Hentet ikke blokk nummer 0?"
+
+msgid "E298: Didn't get block nr 1?"
+msgstr "E298: Hentet ikke blokk nummer 1?"
+
+msgid "E298: Didn't get block nr 2?"
+msgstr "E298: Hentet ikke blokk nummer 2?"
+
+#. could not (re)open the swap file, what can we do????
+msgid "E301: Oops, lost the swap file!!!"
+msgstr "E301: Opps, mistet swapfilen!!!"
+
+msgid "E302: Could not rename swap file"
+msgstr "E302: Klarte ikke skifte navn på swapfil"
+
+#, c-format
+msgid "E303: Unable to open swap file for \"%s\", recovery impossible"
+msgstr "E303: Klarte ikke åpne swapfil for \"%s\", gjenoppretting umulig"
+
+msgid "E304: ml_upd_block0(): Didn't get block 0??"
+msgstr "E304: ml_upd_block0(): Hentet ikke blokk 0??"
+
+#, c-format
+msgid "E305: No swap file found for %s"
+msgstr "E305: Ingen swapfil funnet for %s"
+
+msgid "Enter number of swap file to use (0 to quit): "
+msgstr "Skriv nummeret på swapfil som skal brukes (0 for å avslutte): "
+
+#, c-format
+msgid "E306: Cannot open %s"
+msgstr "E306: Kan ikke åpne %s"
+
+msgid "Unable to read block 0 from "
+msgstr "Klarte ikke lese blokk 0 fra "
+
+msgid ""
+"\n"
+"Maybe no changes were made or Vim did not update the swap file."
+msgstr ""
+"\n"
+"Det er mulig ingen forandringer ble gjort, eller Vim oppdaterte ikke "
+"swapfilen."
+
+msgid " cannot be used with this version of Vim.\n"
+msgstr " kan ikke brukes med denne Vim-versjonen.\n"
+
+msgid "Use Vim version 3.0.\n"
+msgstr "Bruk Vim versjon 3.0.\n"
+
+#, c-format
+msgid "E307: %s does not look like a Vim swap file"
+msgstr "E307: %s ser ikke ut som en Vim-swapfil"
+
+msgid " cannot be used on this computer.\n"
+msgstr " kan ikke brukes på denne maskinen.\n"
+
+msgid "The file was created on "
+msgstr "Filen ble laget på "
+
+msgid ""
+",\n"
+"or the file has been damaged."
+msgstr ""
+",\n"
+"eller filen er blitt ødelagt."
+
+#, c-format
+msgid "Using swap file \"%s\""
+msgstr "Bruker swapfilen \"%s\""
+
+#, c-format
+msgid "Original file \"%s\""
+msgstr "Originalfil \"%s\""
+
+msgid "E308: Warning: Original file may have been changed"
+msgstr "E308: Advarsel: Originalfilen kan ha blitt forandret"
+
+#, c-format
+msgid "E309: Unable to read block 1 from %s"
+msgstr "E309: Klarte ikke lese blokk 1 fra %s"
+
+msgid "???MANY LINES MISSING"
+msgstr "???MANGE LINJER MANGLER"
+
+msgid "???LINE COUNT WRONG"
+msgstr "???FEIL LINJEANTALL"
+
+msgid "???EMPTY BLOCK"
+msgstr "???TOM BLOKK"
+
+msgid "???LINES MISSING"
+msgstr "???LINJER MANGLER"
+
+#, c-format
+msgid "E310: Block 1 ID wrong (%s not a .swp file?)"
+msgstr "E310: ID til blokk 1 er feil (%s ikke en \".swp\"-fil?)"
+
+msgid "???BLOCK MISSING"
+msgstr "???BLOKK MANGLER"
+
+msgid "??? from here until ???END lines may be messed up"
+msgstr "??? Herfra til ???SLUTT kan linjer være rotet til"
+
+msgid "??? from here until ???END lines may have been inserted/deleted"
+msgstr "??? Herfra til ???SLUTT kan linjer ha blitt lagt til eller slettet"
+
+msgid "???END"
+msgstr "???SLUTT"
+
+msgid "E311: Recovery Interrupted"
+msgstr "E311: Gjenoppretting avbrutt"
+
+msgid ""
+"E312: Errors detected while recovering; look for lines starting with ???"
+msgstr ""
+"E312: Feil oppdaget under gjenoppretting; se etter linjer som starter med ???"
+
+msgid "See \":help E312\" for more information."
+msgstr "Se \":help E312\" for mer informasjon."
+
+msgid "Recovery completed. You should check if everything is OK."
+msgstr "Gjenoppretting komplett. Du bør sjekke at alt er i orden."
+
+msgid ""
+"\n"
+"(You might want to write out this file under another name\n"
+msgstr ""
+"\n"
+"(Du vil kanskje lagre denne filen under et annet navn\n"
+
+msgid "and run diff with the original file to check for changes)\n"
+msgstr "og sammenligne den mot den originale filen for å finne forandringer)\n"
+
+msgid ""
+"Delete the .swp file afterwards.\n"
+"\n"
+msgstr ""
+"Slett \".swp\"-filen etterpå.\n"
+"\n"
+
+#. use msg() to start the scrolling properly
+msgid "Swap files found:"
+msgstr "Swapfiler funnet:"
+
+msgid " In current directory:\n"
+msgstr " I nåværende katalog:\n"
+
+msgid " Using specified name:\n"
+msgstr " Bruker spesifisert navn:\n"
+
+msgid " In directory "
+msgstr " I katalog "
+
+msgid " -- none --\n"
+msgstr " -- ingen --\n"
+
+msgid " owned by: "
+msgstr " eies av: "
+
+msgid " dated: "
+msgstr " datert: "
+
+msgid " dated: "
+msgstr " datert: "
+
+msgid " [from Vim version 3.0]"
+msgstr " [fra Vim versjon 3.0]"
+
+msgid " [does not look like a Vim swap file]"
+msgstr " [ser ikke ut som en Vim-swapfil]"
+
+msgid " file name: "
+msgstr " filnavn: "
+
+msgid ""
+"\n"
+" modified: "
+msgstr ""
+"\n"
+" modifisert: "
+
+msgid "YES"
+msgstr "JA"
+
+msgid "no"
+msgstr "nei"
+
+msgid ""
+"\n"
+" user name: "
+msgstr ""
+"\n"
+" brukernavn: "
+
+msgid " host name: "
+msgstr " vertsnavn: "
+
+msgid ""
+"\n"
+" host name: "
+msgstr ""
+"\n"
+" vertsnavn: "
+
+msgid ""
+"\n"
+" process ID: "
+msgstr ""
+"\n"
+" prosess-ID: "
+
+msgid " (still running)"
+msgstr " (kjører fortsatt)"
+
+msgid ""
+"\n"
+" [not usable with this version of Vim]"
+msgstr ""
+"\n"
+" [ikke brukbar med denne Vim-versjonen]"
+
+msgid ""
+"\n"
+" [not usable on this computer]"
+msgstr ""
+"\n"
+" [ikke brukbar på denne maskinen]"
+
+msgid " [cannot be read]"
+msgstr " [kan ikke leses]"
+
+msgid " [cannot be opened]"
+msgstr " [kan ikke åpnes]"
+
+msgid "E313: Cannot preserve, there is no swap file"
+msgstr "E313: Kan ikke bevare, swapfil mangler"
+
+msgid "File preserved"
+msgstr "Fil bevart"
+
+msgid "E314: Preserve failed"
+msgstr "E314: Bevaring feilet"
+
+#, c-format
+msgid "E315: ml_get: invalid lnum: %ld"
+msgstr "E315: ml_get: Ugyldig lnum: %ld"
+
+#, c-format
+msgid "E316: ml_get: cannot find line %ld"
+msgstr "E316: ml_get: Kan ikke finne linje %ld"
+
+msgid "E317: pointer block id wrong 3"
+msgstr "E317: Pekerblokk-id feil 3"
+
+msgid "stack_idx should be 0"
+msgstr "stack_idx skulle være 0"
+
+msgid "E318: Updated too many blocks?"
+msgstr "E318: Oppdaterte for mange blokker?"
+
+msgid "E317: pointer block id wrong 4"
+msgstr "E317: Pekerblokk-id feil 4"
+
+msgid "deleted block 1?"
+msgstr "slettet blokk 1?"
+
+#, c-format
+msgid "E320: Cannot find line %ld"
+msgstr "E320: Kan ikke finne linje %ld"
+
+msgid "E317: pointer block id wrong"
+msgstr "E317: Pekerblokk-id feil"
+
+msgid "pe_line_count is zero"
+msgstr "pe_line_count er null"
+
+#, c-format
+msgid "E322: line number out of range: %ld past the end"
+msgstr "E322: Linjenummer utenfor område: %ld forbi slutten"
+
+#, c-format
+msgid "E323: line count wrong in block %ld"
+msgstr "E323: Linjeantall feil i blokk %ld"
+
+msgid "Stack size increases"
+msgstr "Stackstørrelse øker"
+
+msgid "E317: pointer block id wrong 2"
+msgstr "E317: Pekerblokk-id feil 2"
+
+#, c-format
+msgid "E773: Symlink loop for \"%s\""
+msgstr "E773: Symlenkesløyfe for \"%s\""
+
+msgid "E325: ATTENTION"
+msgstr "E325: VIKTIG"
+
+msgid ""
+"\n"
+"Found a swap file by the name \""
+msgstr ""
+"\n"
+"Fant en swapfil ved navn \""
+
+msgid "While opening file \""
+msgstr "Under åpning av filen \""
+
+msgid " NEWER than swap file!\n"
+msgstr " NYERE enn swapfil!\n"
+
+#. Some of these messages are long to allow translation to
+#. * other languages.
+msgid ""
+"\n"
+"(1) Another program may be editing the same file.\n"
+" If this is the case, be careful not to end up with two\n"
+" different instances of the same file when making changes.\n"
+msgstr ""
+"\n"
+"(1) Det er mulig et annet program redigerer den samme filen.\n"
+" Hvis det er tilfelle, vær forsiktig så du ikke ender opp med to\n"
+" forskjellige utgaver av den samme filen når du gjør forandringer.\n"
+
+msgid " Quit, or continue with caution.\n"
+msgstr " Avslutt, eller fortsett med varsomhet.\n"
+
+msgid ""
+"\n"
+"(2) An edit session for this file crashed.\n"
+msgstr ""
+"\n"
+"(2) En økt for denne filen kræsjet.\n"
+
+msgid " If this is the case, use \":recover\" or \"vim -r "
+msgstr " Hvis det er tilfelle, bruk \":recover\" eller \"vim -r "
+
+msgid ""
+"\"\n"
+" to recover the changes (see \":help recovery\").\n"
+msgstr ""
+"\"\n"
+" for å gjenopprette forandringene (se \":help recovery\").\n"
+
+msgid " If you did this already, delete the swap file \""
+msgstr " Hvis du har gjort dette allerede, slett swapfilen \""
+
+msgid ""
+"\"\n"
+" to avoid this message.\n"
+msgstr ""
+"\"\n"
+" for å unngå denne meldingen.\n"
+
+msgid "Swap file \""
+msgstr "Swapfilen \""
+
+msgid "\" already exists!"
+msgstr "\" finnes allerede!"
+
+msgid "VIM - ATTENTION"
+msgstr "VIM - VIKTIG"
+
+msgid "Swap file already exists!"
+msgstr "Swapfilen eksisterer allerede!"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"&Åpne skrivebeskyttet\n"
+"&Rediger likevel\n"
+"&Gjenopprett\n"
+"&Avslutt\n"
+"Av&bryt"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Delete it\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"&Åpne skrivebeskyttet\n"
+"&Rediger likevel\n"
+"&Gjenopprett\n"
+"&Slett den\n"
+"&Avslutt\n"
+"Av&bryt"
+
+msgid "E326: Too many swap files found"
+msgstr "E326: For mange swapfiler funnet"
+
+msgid "E327: Part of menu-item path is not sub-menu"
+msgstr "E327: Del av menyelement er ikke undermeny"
+
+msgid "E328: Menu only exists in another mode"
+msgstr "E328: Menyen eksisterer bare i en annen modus"
+
+#, c-format
+msgid "E329: No menu \"%s\""
+msgstr "E329: Ingen \"%s\"-meny"
+
+#. Only a mnemonic or accelerator is not valid.
+msgid "E792: Empty menu name"
+msgstr "E792: Tomt menynavn"
+
+msgid "E330: Menu path must not lead to a sub-menu"
+msgstr "E330: Menysti kan ikke lede til en undermeny"
+
+msgid "E331: Must not add menu items directly to menu bar"
+msgstr "E331: Kan ikke legge til menyelementer direkte på menylinjen"
+
+msgid "E332: Separator cannot be part of a menu path"
+msgstr "E332: Skilletegn kan ikke være del av en menysti"
+
+#. Now we have found the matching menu, and we list the mappings
+#. Highlight title
+msgid ""
+"\n"
+"--- Menus ---"
+msgstr ""
+"\n"
+"--- Menyer ---"
+
+msgid "Tear off this menu"
+msgstr "Riv av denne menyen"
+
+msgid "E333: Menu path must lead to a menu item"
+msgstr "E333: Menystien må lede til et menyvalg"
+
+#, c-format
+msgid "E334: Menu not found: %s"
+msgstr "E334: Fant ikke menyen: %s"
+
+#, c-format
+msgid "E335: Menu not defined for %s mode"
+msgstr "E335: Menyen er ikke definert for %s-modus"
+
+msgid "E336: Menu path must lead to a sub-menu"
+msgstr "E336: Menystien må lede til en undermeny"
+
+msgid "E337: Menu not found - check menu names"
+msgstr "E337: Fant ikke menyen - sjekk menynavnet"
+
+#, c-format
+msgid "Error detected while processing %s:"
+msgstr "Feil oppdaget under prosessering av %s:"
+
+#, c-format
+msgid "line %4ld:"
+msgstr "linje %4ld:"
+
+#, c-format
+msgid "E354: Invalid register name: '%s'"
+msgstr "E354: Ugyldig registernavn: '%s'"
+
+msgid "Messages maintainer: Bram Moolenaar <Bram@vim.org>"
+msgstr ""
+"Vedlikeholder for norsk oversettelse: Øyvind A. Holm <sunny@sunbase.org>"
+
+msgid "Interrupt: "
+msgstr "Avbryt: "
+
+msgid "Press ENTER or type command to continue"
+msgstr "Trykk ENTER eller skriv kommando for å fortsette"
+
+#, c-format
+msgid "%s line %ld"
+msgstr "%s linje %ld"
+
+msgid "-- More --"
+msgstr "-- Mer --"
+
+msgid " SPACE/d/j: screen/page/line down, b/u/k: up, q: quit "
+msgstr " MELLOMROM/d/j: Skjerm/side/linje ned, b/u/k: Opp, q: Avslutt "
+
+msgid "Question"
+msgstr "Spørsmål"
+
+msgid ""
+"&Yes\n"
+"&No"
+msgstr ""
+"&Ja\n"
+"&Nei"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"Save &All\n"
+"&Discard All\n"
+"&Cancel"
+msgstr ""
+"&Ja\n"
+"&Nei\n"
+"&Lagre alle\n"
+"&Forkast alle\n"
+"&Avbryt"
+
+msgid "Select Directory dialog"
+msgstr "\"Velge katalog\"-dialogvindu"
+
+msgid "Save File dialog"
+msgstr "\"Lagre fil\"-dialogvindu"
+
+msgid "Open File dialog"
+msgstr "\"Åpne fil\"-dialogvindu"
+
+#. TODO: non-GUI file selector here
+msgid "E338: Sorry, no file browser in console mode"
+msgstr "E338: Dessverre ingen filbehandler i konsollmodus"
+
+msgid "E766: Insufficient arguments for printf()"
+msgstr "E766: Ikke nok parametre for printf()"
+
+msgid "E767: Too many arguments to printf()"
+msgstr "E767: For mange parametere for printf()"
+
+msgid "W10: Warning: Changing a readonly file"
+msgstr "W10: Advarsel: Forandrer en skrivebeskyttet fil"
+
+msgid "Type number or click with mouse (<Enter> cancels): "
+msgstr "Skriv nummer eller velg med musen (<Enter> avbryter)"
+
+msgid "Choice number (<Enter> cancels): "
+msgstr "Valgnummer (<Enter> avbryter)"
+
+msgid "1 more line"
+msgstr "1 linje lagt til"
+
+msgid "1 line less"
+msgstr "1 linje fjernet"
+
+#, c-format
+msgid "%ld more lines"
+msgstr "%ld linjer lagt til"
+
+#, c-format
+msgid "%ld fewer lines"
+msgstr "%ld linjer fjernet"
+
+msgid " (Interrupted)"
+msgstr " (Avbrutt)"
+
+msgid "Beep!"
+msgstr "Pip!"
+
+msgid "Vim: preserving files...\n"
+msgstr "Vim: Bevarer filer ...\n"
+
+#. close all memfiles, without deleting
+msgid "Vim: Finished.\n"
+msgstr "Vim: Ferdig.\n"
+
+#, c-format
+msgid "ERROR: "
+msgstr "FEIL: "
+
+#, c-format
+msgid ""
+"\n"
+"[bytes] total alloc-freed %lu-%lu, in use %lu, peak use %lu\n"
+msgstr ""
+"\n"
+"[bytes] totalt alloc-frigjort %lu-%lu, i bruk %lu, topp-bruk %lu\n"
+
+#, c-format
+msgid ""
+"[calls] total re/malloc()'s %lu, total free()'s %lu\n"
+"\n"
+msgstr ""
+"[kall] totale \"re/malloc()\"-er %lu, totale \"free()\"-er %lu\n"
+"\n"
+
+msgid "E340: Line is becoming too long"
+msgstr "E340: Linjen blir for lang"
+
+#, c-format
+msgid "E341: Internal error: lalloc(%ld, )"
+msgstr "E341: Intern feil: lalloc(%ld, )"
+
+#, c-format
+msgid "E342: Out of memory! (allocating %lu bytes)"
+msgstr "E342: Ikke mer ledig hukommelse! (Reserverer %lu bytes)"
+
+#, c-format
+msgid "Calling shell to execute: \"%s\""
+msgstr "Kaller skall for å utføre \"%s\""
+
+msgid "E545: Missing colon"
+msgstr "E545: Mangler kolon"
+
+msgid "E546: Illegal mode"
+msgstr "E546: Ulovlig modus"
+
+msgid "E547: Illegal mouseshape"
+msgstr "E547: Ulovlig utseende på musepekeren"
+
+msgid "E548: digit expected"
+msgstr "E548: Siffer forventet"
+
+msgid "E549: Illegal percentage"
+msgstr "E549: Ulovlig prosent"
+
+msgid "Enter encryption key: "
+msgstr "Skriv krypteringsnøkkel: "
+
+msgid "Enter same key again: "
+msgstr "Gjenta krypteringsnøkkelen: "
+
+msgid "Keys don't match!"
+msgstr "Krypteringsnøklene stemmer ikke overens!"
+
+#, c-format
+msgid ""
+"E343: Invalid path: '**[number]' must be at the end of the path or be "
+"followed by '%s'."
+msgstr ""
+"E343: Ugyldig sti: '**[nummer]' må være på slutten av stien eller bli "
+"etterfulgt av '%s'."
+
+#, c-format
+msgid "E344: Can't find directory \"%s\" in cdpath"
+msgstr "E344: Kan ikke finne katalogen \"%s\" i \"cdpath\""
+
+#, c-format
+msgid "E345: Can't find file \"%s\" in path"
+msgstr "E345: Kan ikke finne filen \"%s\" i stien"
+
+#, c-format
+msgid "E346: No more directory \"%s\" found in cdpath"
+msgstr "E346: Ingen flere katalog-\"%s\" funnet i \"cdpath\""
+
+#, c-format
+msgid "E347: No more file \"%s\" found in path"
+msgstr "E347: Ingen flere fil-\"%s\" funnet i stien"
+
+#. Get here when the server can't be found.
+msgid "Cannot connect to Netbeans #2"
+msgstr "Kan ikke koble til Netbeans #2"
+
+msgid "Cannot connect to Netbeans"
+msgstr "Kan ikke koble til Netbeans"
+
+#, c-format
+msgid "E668: Wrong access mode for NetBeans connection info file: \"%s\""
+msgstr ""
+"E668: Feil tilgangsmodus for infofilen til NetBeans-forbindelse: \"%s\""
+
+msgid "read from Netbeans socket"
+msgstr "les fra Netbeans-socket"
+
+#, c-format
+msgid "E658: NetBeans connection lost for buffer %ld"
+msgstr "E658: Mistet NetBeans-forbindelse for buffer %ld"
+
+msgid "E505: "
+msgstr "E505: "
+
+msgid "E774: 'operatorfunc' is empty"
+msgstr "E774: 'operatorfunc' er tomt"
+
+msgid "E775: Eval feature not available"
+msgstr "E775: Eval-funksjonaliteten er ikke tilgjengelig"
+
+msgid "Warning: terminal cannot highlight"
+msgstr "Advarsel: Terminalen kan ikke utheve"
+
+msgid "E348: No string under cursor"
+msgstr "E348: Ingen streng under markør"
+
+msgid "E349: No identifier under cursor"
+msgstr "E349: Ingen identifikator under markør"
+
+msgid "E352: Cannot erase folds with current 'foldmethod'"
+msgstr "E352: Kan ikke slette folder med nåværende 'foldmethod'"
+
+msgid "E664: changelist is empty"
+msgstr "E664: Forandringslisten er tom"
+
+msgid "E662: At start of changelist"
+msgstr "E662: Ved starten av forandringsliste"
+
+msgid "E663: At end of changelist"
+msgstr "E663: Ved slutten av forandringsliste"
+
+msgid "Type :quit<Enter> to exit Vim"
+msgstr "Skriv :quit<Enter> for å avslutte Vim"
+
+#, c-format
+msgid "1 line %sed 1 time"
+msgstr "1 linje \"%s\"-et 1 gang"
+
+#, c-format
+msgid "1 line %sed %d times"
+msgstr "1 linje \"%s\"-et %d ganger"
+
+#, c-format
+msgid "%ld lines %sed 1 time"
+msgstr "%ld linjer \"%s\"-et 1 gang"
+
+#, c-format
+msgid "%ld lines %sed %d times"
+msgstr "%ld linjer \"%s\"-et %d ganger"
+
+#, c-format
+msgid "%ld lines to indent... "
+msgstr "%ld linjer å rykke inn ... "
+
+msgid "1 line indented "
+msgstr "1 linje rykket inn "
+
+#, c-format
+msgid "%ld lines indented "
+msgstr "%ld linjer rykket inn "
+
+msgid "E748: No previously used register"
+msgstr "E748: Register ikke tidligere brukt"
+
+#. must display the prompt
+msgid "cannot yank; delete anyway"
+msgstr "kan ikke kopiere til utklippstavle; slett likevel"
+
+msgid "1 line changed"
+msgstr "1 linje forandret"
+
+#, c-format
+msgid "%ld lines changed"
+msgstr "%ld linjer forandret"
+
+#, c-format
+msgid "freeing %ld lines"
+msgstr "frigjør %ld linjer"
+
+msgid "block of 1 line yanked"
+msgstr "blokk med 1 linje kopiert til utklippstavlen"
+
+msgid "1 line yanked"
+msgstr "1 linje kopiert til utklippstavlen"
+
+#, c-format
+msgid "block of %ld lines yanked"
+msgstr "blokk med %ld linjer kopiert til utklippstavlen"
+
+#, c-format
+msgid "%ld lines yanked"
+msgstr "%ld linjer kopiert til utklippstavlen"
+
+#, c-format
+msgid "E353: Nothing in register %s"
+msgstr "E353: Ingenting i register %s"
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Registers ---"
+msgstr ""
+"\n"
+"--- Registere ---"
+
+msgid "Illegal register name"
+msgstr "Ulovlig registernavn"
+
+#, c-format
+msgid ""
+"\n"
+"# Registers:\n"
+msgstr ""
+"\n"
+"# Registere:\n"
+
+#, c-format
+msgid "E574: Unknown register type %d"
+msgstr "E574: Ukjent registertype %d"
+
+#, c-format
+msgid "%ld Cols; "
+msgstr "%ld Kol; "
+
+#, c-format
+msgid "Selected %s%ld of %ld Lines; %ld of %ld Words; %ld of %ld Bytes"
+msgstr "Valgte %s%ld av %ld linjer; %ld av %ld ord; %ld av %ld bytes"
+
+#, c-format
+msgid ""
+"Selected %s%ld of %ld Lines; %ld of %ld Words; %ld of %ld Chars; %ld of %ld "
+"Bytes"
+msgstr ""
+"Valgte %s%ld av %ld linjer; %ld av %ld ord; %ld av %ld tegn; %ld av %ld bytes"
+
+#, c-format
+msgid "Col %s of %s; Line %ld of %ld; Word %ld of %ld; Byte %ld of %ld"
+msgstr "Kol %s av %s; Linje %ld av %ld; Ord %ld av %ld; Byte %ld av %ld"
+
+#, c-format
+msgid ""
+"Col %s of %s; Line %ld of %ld; Word %ld of %ld; Char %ld of %ld; Byte %ld of "
+"%ld"
+msgstr ""
+"Kol %s av %s; linje %ld av %ld; ord %ld av %ld; tegn %ld av %ld; byte %ld av "
+"%ld"
+
+#, c-format
+msgid "(+%ld for BOM)"
+msgstr "(+%ld for BOM)"
+
+msgid "%<%f%h%m%=Page %N"
+msgstr "%<%f%h%m%=Side %N"
+
+msgid "Thanks for flying Vim"
+msgstr "Takk for at du fløy Vim"
+
+msgid "E518: Unknown option"
+msgstr "E518: Ukjent valg"
+
+msgid "E519: Option not supported"
+msgstr "E519: Valget er ikke støttet"
+
+msgid "E520: Not allowed in a modeline"
+msgstr "E520: Ikke tillatt i moduslinje"
+
+msgid "E521: Number required after ="
+msgstr "E521: Nummer nødvendig etter ="
+
+msgid "E522: Not found in termcap"
+msgstr "E522: Ikke funnet i termcap"
+
+#, c-format
+msgid "E539: Illegal character <%s>"
+msgstr "E539: Ulovlig tegn <%s>"
+
+msgid "E529: Cannot set 'term' to empty string"
+msgstr "E529: Kan ikke sette 'term' til tom streng"
+
+msgid "E530: Cannot change term in GUI"
+msgstr "E530: Kan ikke forandre \"term\" i grafisk brukergrensesnitt"
+
+msgid "E531: Use \":gui\" to start the GUI"
+msgstr "E531: Bruk \":gui\" for å starte med grafisk brukergrensesnitt"
+
+msgid "E589: 'backupext' and 'patchmode' are equal"
+msgstr "E589: 'backupext' og 'patchmode' er like"
+
+msgid "E617: Cannot be changed in the GTK+ 2 GUI"
+msgstr "E617: Kan ikke forandres i GTK+ 2 GUI"
+
+msgid "E524: Missing colon"
+msgstr "E524: Mangler kolon"
+
+msgid "E525: Zero length string"
+msgstr "E525: Tom streng"
+
+#, c-format
+msgid "E526: Missing number after <%s>"
+msgstr "E526: Mangler nummer etter <%s>"
+
+msgid "E527: Missing comma"
+msgstr "E527: Mangler komma"
+
+msgid "E528: Must specify a ' value"
+msgstr "E528: Må spesifisere en \"'\"-verdi"
+
+msgid "E595: contains unprintable or wide character"
+msgstr "E595: Inneholder uskrivelige eller brede tegn"
+
+msgid "E596: Invalid font(s)"
+msgstr "E596: Ugyldig(e) skrifttype(r)"
+
+msgid "E597: can't select fontset"
+msgstr "E597: Kan ikke velge skrifttypesett"
+
+msgid "E598: Invalid fontset"
+msgstr "E598: Ugyldig skrifttypesett"
+
+msgid "E533: can't select wide font"
+msgstr "E533: Kan ikke velge bred skrifttype"
+
+msgid "E534: Invalid wide font"
+msgstr "E534: Ugyldig bred skrifttype"
+
+#, c-format
+msgid "E535: Illegal character after <%c>"
+msgstr "E535: Ulovlig tegn etter <%c>"
+
+msgid "E536: comma required"
+msgstr "E536: Komma nødvendig"
+
+#, c-format
+msgid "E537: 'commentstring' must be empty or contain %s"
+msgstr "E537: 'commentstring' må være tom eller inneholde %s"
+
+msgid "E538: No mouse support"
+msgstr "E538: Ingen støtte for mus"
+
+msgid "E540: Unclosed expression sequence"
+msgstr "E540: Uttrykkssekvens som ikke er lukket"
+
+msgid "E541: too many items"
+msgstr "E541: For mange elementer"
+
+msgid "E542: unbalanced groups"
+msgstr "E542: Ubalanserte grupper"
+
+msgid "E590: A preview window already exists"
+msgstr "E590: Det finnes allerede et forhåndsvisningsvindu"
+
+msgid "W17: Arabic requires UTF-8, do ':set encoding=utf-8'"
+msgstr "W17: Arabisk trenger UTF-8, utfør ':set encoding=utf-8'"
+
+#, c-format
+msgid "E593: Need at least %d lines"
+msgstr "E593: Trenger minst %d linjer"
+
+#, c-format
+msgid "E594: Need at least %d columns"
+msgstr "E594: Trenger minst %d kolonner"
+
+#, c-format
+msgid "E355: Unknown option: %s"
+msgstr "E355: Ukjent valg: %s"
+
+msgid ""
+"\n"
+"--- Terminal codes ---"
+msgstr ""
+"\n"
+"--- Terminalkoder ---"
+
+msgid ""
+"\n"
+"--- Global option values ---"
+msgstr ""
+"\n"
+"--- Globale valgverdier ---"
+
+msgid ""
+"\n"
+"--- Local option values ---"
+msgstr ""
+"\n"
+"--- Lokale valgverdier ---"
+
+msgid ""
+"\n"
+"--- Options ---"
+msgstr ""
+"\n"
+"--- Valg ---"
+
+msgid "E356: get_varp ERROR"
+msgstr "E356: \"get_varp\"-FEIL"
+
+#, c-format
+msgid "E357: 'langmap': Matching character missing for %s"
+msgstr "E357: 'langmap': Samsvarende tegn mangler for %s"
+
+#, c-format
+msgid "E358: 'langmap': Extra characters after semicolon: %s"
+msgstr "E358: 'langmap': Ekstra tegn etter semikolon: %s"
+
+msgid "cannot open "
+msgstr "kan ikke åpne "
+
+msgid "VIM: Can't open window!\n"
+msgstr "VIM: Kan ikke åpne vindu!\n"
+
+msgid "Need Amigados version 2.04 or later\n"
+msgstr "Trenger Amigados versjon 2.04 eller nyere\n"
+
+#, c-format
+msgid "Need %s version %ld\n"
+msgstr "Trenger %s versjon %ld\n"
+
+msgid "Cannot open NIL:\n"
+msgstr "Kan ikke åpne NIL:\n"
+
+msgid "Cannot create "
+msgstr "Kan ikke opprette "
+
+#, c-format
+msgid "Vim exiting with %d\n"
+msgstr "Vim avslutter med %d\n"
+
+msgid "cannot change console mode ?!\n"
+msgstr "kan ikke forandre konsollmodus ?!\n"
+
+msgid "mch_get_shellsize: not a console??\n"
+msgstr "mch_get_shellsize: Ikke et konsoll??\n"
+
+#. if Vim opened a window: Executing a shell may cause crashes
+msgid "E360: Cannot execute shell with -f option"
+msgstr "E360: Kan ikke kjøre skall med \"-f\"-valg"
+
+msgid "Cannot execute "
+msgstr "Kan ikke utføre "
+
+msgid "shell "
+msgstr "skall "
+
+msgid " returned\n"
+msgstr " returnerte\n"
+
+msgid "ANCHOR_BUF_SIZE too small."
+msgstr "ANCHOR_BUF_SIZE for liten."
+
+msgid "I/O ERROR"
+msgstr "I/U-FEIL"
+
+msgid "Message"
+msgstr "Melding"
+
+msgid "'columns' is not 80, cannot execute external commands"
+msgstr "'columns' er ikke 80, kan ikke utføre eksterne kommandoer"
+
+msgid "E237: Printer selection failed"
+msgstr "E237: Valg av skriver feilet"
+
+#, c-format
+msgid "to %s on %s"
+msgstr "til %s på %s"
+
+#, c-format
+msgid "E613: Unknown printer font: %s"
+msgstr "E613: Ukjent skrifttype for skriver: %s"
+
+#, c-format
+msgid "E238: Print error: %s"
+msgstr "E238: Feil under utskrift: %s"
+
+#, c-format
+msgid "Printing '%s'"
+msgstr "Skriver ut '%s'"
+
+#, c-format
+msgid "E244: Illegal charset name \"%s\" in font name \"%s\""
+msgstr "E244: Ulovlig navn på tegnsett \"%s\" i skrifttypenavn \"%s\""
+
+#, c-format
+msgid "E245: Illegal char '%c' in font name \"%s\""
+msgstr "E245: Ulovlig tegn '%c' i skrifttypenavn \"%s\""
+
+msgid "Vim: Double signal, exiting\n"
+msgstr "Vim: Dobbelt signal, avslutter\n"
+
+#, c-format
+msgid "Vim: Caught deadly signal %s\n"
+msgstr "Vim: Mottok dødelig signal %s\n"
+
+#, c-format
+msgid "Vim: Caught deadly signal\n"
+msgstr "Vim: Mottok dødelig signal\n"
+
+#, c-format
+msgid "Opening the X display took %ld msec"
+msgstr "Åpning av X-display tok %ld millisekunder"
+
+msgid ""
+"\n"
+"Vim: Got X error\n"
+msgstr ""
+"\n"
+"Vim: Mottok X-feil\n"
+
+msgid "Testing the X display failed"
+msgstr "Test av X-display feilet"
+
+msgid "Opening the X display timed out"
+msgstr "Tidsavbrudd for åpning av X-display"
+
+msgid ""
+"\n"
+"Cannot execute shell "
+msgstr ""
+"\n"
+"Kan ikke kjøre skall "
+
+msgid ""
+"\n"
+"Cannot execute shell sh\n"
+msgstr ""
+"\n"
+"Kan ikke kjøre skallet sh\n"
+
+msgid ""
+"\n"
+"shell returned "
+msgstr ""
+"\n"
+"skallet returnerte "
+
+msgid ""
+"\n"
+"Cannot create pipes\n"
+msgstr ""
+"\n"
+"Kan ikke opprette rør (\"pipe\")\n"
+
+msgid ""
+"\n"
+"Cannot fork\n"
+msgstr ""
+"\n"
+"Kan ikke opprette tvillingprosess (\"fork\")\n"
+
+msgid ""
+"\n"
+"Command terminated\n"
+msgstr ""
+"\n"
+"Kommando avsluttet\n"
+
+msgid "XSMP lost ICE connection"
+msgstr "XSMP mistet ICE-forbindelsen"
+
+#, c-format
+msgid "dlerror = \"%s\""
+msgstr "dlerror = \"%s\""
+
+msgid "Opening the X display failed"
+msgstr "Åpning av X-display feilet"
+
+msgid "XSMP handling save-yourself request"
+msgstr "XSMP håndterer \"redd-deg-selv\"-forespørsel"
+
+msgid "XSMP opening connection"
+msgstr "XSMP åpner forbindelse"
+
+msgid "XSMP ICE connection watch failed"
+msgstr "Overvåkning av XSMP ICE-forbindelse feilet"
+
+#, c-format
+msgid "XSMP SmcOpenConnection failed: %s"
+msgstr "XSMP SmcOpenConnection feilet: %s"
+
+msgid "At line"
+msgstr "På linje"
+
+msgid "Could not load vim32.dll!"
+msgstr "Klarte ikke laste vim32.dll!"
+
+msgid "VIM Error"
+msgstr "VIM-feil"
+
+msgid "Could not fix up function pointers to the DLL!"
+msgstr "Klarte ikke ordne opp i funksjonspekere til DLL-en!"
+
+#, c-format
+msgid "shell returned %d"
+msgstr "skallet returnerte %d"
+
+#, c-format
+msgid "Vim: Caught %s event\n"
+msgstr "Vim: Mottok \"%s\"-hendelse\n"
+
+msgid "close"
+msgstr "lukk"
+
+msgid "logoff"
+msgstr "logg av"
+
+msgid "shutdown"
+msgstr "kjør ned"
+
+msgid "E371: Command not found"
+msgstr "E371: Kommando ikke funnet"
+
+msgid ""
+"VIMRUN.EXE not found in your $PATH.\n"
+"External commands will not pause after completion.\n"
+"See :help win32-vimrun for more information."
+msgstr ""
+"VIMRUN.EXE ikke funnet i $PATH.\n"
+"Eksterne kommandoer kommer ikke til å vente etter fullføring.\n"
+"Se \":help win32-vimrun\" for mer informasjon."
+
+msgid "Vim Warning"
+msgstr "Vim-advarsel"
+
+#, c-format
+msgid "E372: Too many %%%c in format string"
+msgstr "E372: For mange %%%c i formatstreng"
+
+#, c-format
+msgid "E373: Unexpected %%%c in format string"
+msgstr "E373: Uventet %%%c i formatstreng"
+
+msgid "E374: Missing ] in format string"
+msgstr "E374: Mangler ] i formatstreng"
+
+#, c-format
+msgid "E375: Unsupported %%%c in format string"
+msgstr "E375: %%%c ikke støttet i formatstreng"
+
+#, c-format
+msgid "E376: Invalid %%%c in format string prefix"
+msgstr "E376: Ugyldig %%%c i formatstreng-prefiks"
+
+#, c-format
+msgid "E377: Invalid %%%c in format string"
+msgstr "E377: Ugyldig %%%c i formatstreng"
+
+msgid "E378: 'errorformat' contains no pattern"
+msgstr "E378: 'errorformat' inneholder ikke søkestreng"
+
+msgid "E379: Missing or empty directory name"
+msgstr "E379: Manglende eller tomt katalognavn"
+
+msgid "E553: No more items"
+msgstr "E553: Ingen flere elementer"
+
+#, c-format
+msgid "(%d of %d)%s%s: "
+msgstr "(%d av %d)%s%s: "
+
+msgid " (line deleted)"
+msgstr " (linjen slettet)"
+
+msgid "E380: At bottom of quickfix stack"
+msgstr "E380: På bunnen av quickfix-stack"
+
+msgid "E381: At top of quickfix stack"
+msgstr "E381: På toppen av quickfix-stack"
+
+#, c-format
+msgid "error list %d of %d; %d errors"
+msgstr "feilliste %d av %d; %d feil"
+
+msgid "E382: Cannot write, 'buftype' option is set"
+msgstr "E382: Kan ikke lagre, 'buftype'-valget er satt"
+
+msgid "E683: File name missing or invalid pattern"
+msgstr "E683: Filnavn mangler eller ugyldig søkestreng"
+
+#, c-format
+msgid "Cannot open file \"%s\""
+msgstr "Kan ikke åpne filen \"%s\""
+
+msgid "E681: Buffer is not loaded"
+msgstr "E681: Bufferen er ikke lastet"
+
+msgid "E777: String or List expected"
+msgstr "E777: Streng eller liste forventet"
+
+#, c-format
+msgid "E369: invalid item in %s%%[]"
+msgstr "E369: Ugyldig element i %s%%[]"
+
+msgid "E339: Pattern too long"
+msgstr "E339: Søkestrengen er for lang"
+
+msgid "E50: Too many \\z("
+msgstr "E50: For mange \\z("
+
+#, c-format
+msgid "E51: Too many %s("
+msgstr "E51: For mange %s("
+
+msgid "E52: Unmatched \\z("
+msgstr "E52: Usamsvarende \\z("
+
+#, c-format
+msgid "E53: Unmatched %s%%("
+msgstr "E53: Usamsvarende %s%%("
+
+#, c-format
+msgid "E54: Unmatched %s("
+msgstr "E54: Usamsvarende %s("
+
+#, c-format
+msgid "E55: Unmatched %s)"
+msgstr "E55: Usamsvarende %s)"
+
+#, c-format
+msgid "E59: invalid character after %s@"
+msgstr "E59: Ugyldig tegn etter %s@"
+
+#, c-format
+msgid "E60: Too many complex %s{...}s"
+msgstr "E60: For mange komplekse %s{...}s"
+
+#, c-format
+msgid "E61: Nested %s*"
+msgstr "E61: Nøstede %s*"
+
+#, c-format
+msgid "E62: Nested %s%c"
+msgstr "E62: Nøstede %s%c"
+
+msgid "E63: invalid use of \\_"
+msgstr "E63: Ugyldig bruk av \\_"
+
+#, c-format
+msgid "E64: %s%c follows nothing"
+msgstr "E64: %s%c etterfølger ingenting"
+
+msgid "E65: Illegal back reference"
+msgstr "E65: Ulovlig tilbakereferanse"
+
+msgid "E66: \\z( not allowed here"
+msgstr "E66: \\z( ikke tillatt her"
+
+msgid "E67: \\z1 - \\z9 not allowed here"
+msgstr "E67: \\z1 med venner er ikke tillatt her"
+
+msgid "E68: Invalid character after \\z"
+msgstr "E68: Ugyldig tegn etter \\z"
+
+#, c-format
+msgid "E69: Missing ] after %s%%["
+msgstr "E69: Mangler ] etter %s%%["
+
+#, c-format
+msgid "E70: Empty %s%%[]"
+msgstr "E70: Tom %s%%[]"
+
+#, c-format
+msgid "E678: Invalid character after %s%%[dxouU]"
+msgstr "E678: Ugyldig tegn etter %s%%[dxouU]"
+
+#, c-format
+msgid "E71: Invalid character after %s%%"
+msgstr "E71: Ugyldig tegn etter %s%%"
+
+#, c-format
+msgid "E769: Missing ] after %s["
+msgstr "E769: Mangler ] etter %s["
+
+#, c-format
+msgid "E554: Syntax error in %s{...}"
+msgstr "E554: Syntaksfeil i %s{...}"
+
+msgid "External submatches:\n"
+msgstr "Eksterne deltreff:\n"
+
+msgid " VREPLACE"
+msgstr " V-ERSTATT"
+
+msgid " REPLACE"
+msgstr " ERSTATT"
+
+msgid " REVERSE"
+msgstr " OMVENDT"
+
+msgid " INSERT"
+msgstr " SETT INN"
+
+msgid " (insert)"
+msgstr " (sett inn)"
+
+msgid " (replace)"
+msgstr " (erstatt)"
+
+msgid " (vreplace)"
+msgstr " (v-erstatt)"
+
+msgid " Hebrew"
+msgstr " hebraisk"
+
+msgid " Arabic"
+msgstr " arabisk"
+
+msgid " (lang)"
+msgstr " (lang)"
+
+msgid " (paste)"
+msgstr " (lim inn)"
+
+msgid " VISUAL"
+msgstr " VISUELL"
+
+msgid " VISUAL LINE"
+msgstr " VISUELL LINJE"
+
+msgid " VISUAL BLOCK"
+msgstr " VISUELL BLOKK"
+
+msgid " SELECT"
+msgstr " VELG"
+
+msgid " SELECT LINE"
+msgstr " VELG LINJE"
+
+msgid " SELECT BLOCK"
+msgstr " VELG BLOKK"
+
+msgid "recording"
+msgstr "spiller inn"
+
+#, c-format
+msgid "E383: Invalid search string: %s"
+msgstr "E383: Ugyldig søkestreng: %s"
+
+#, c-format
+msgid "E384: search hit TOP without match for: %s"
+msgstr "E384: Søket kom til TOPPEN uten treff på: %s"
+
+#, c-format
+msgid "E385: search hit BOTTOM without match for: %s"
+msgstr "E385: Søket kom til BUNNEN uten treff på: %s"
+
+msgid "E386: Expected '?' or '/' after ';'"
+msgstr "E386: Forventet '?' eller '/' etter ';'"
+
+msgid " (includes previously listed match)"
+msgstr " (inkluderer tidligere utlistede treff)"
+
+#. cursor at status line
+msgid "--- Included files "
+msgstr "--- Inkluderte filer "
+
+msgid "not found "
+msgstr "ikke funnet "
+
+msgid "in path ---\n"
+msgstr "i sti ---\n"
+
+msgid " (Already listed)"
+msgstr " (Allerede listet)"
+
+msgid " NOT FOUND"
+msgstr " IKKE FUNNET"
+
+#, c-format
+msgid "Scanning included file: %s"
+msgstr "Leter gjennom inkludert fil: %s"
+
+#, c-format
+msgid "Searching included file %s"
+msgstr "Leter gjennom inkludert fil %s"
+
+msgid "E387: Match is on current line"
+msgstr "E387: Treffet er på nåværende linje"
+
+msgid "All included files were found"
+msgstr "Alle inkluderte filer ble funnet"
+
+msgid "No included files"
+msgstr "Ingen inkluderte filer"
+
+msgid "E388: Couldn't find definition"
+msgstr "E388: Fant ikke definisjonen"
+
+msgid "E389: Couldn't find pattern"
+msgstr "E389: Fant ikke søketeksten"
+
+#, c-format
+#~ msgid ""
+#~ "\n"
+#~ "# Last %sSearch Pattern:\n"
+#~ "~"
+#~ msgstr ""
+
+msgid "E759: Format error in spell file"
+msgstr "E759: Formateringsfeil i stavefil"
+
+msgid "E758: Truncated spell file"
+msgstr "E758: Valg av skriver feilet"
+
+#, c-format
+msgid "Trailing text in %s line %d: %s"
+msgstr "Etterfølgende tekst i %s linje %d: %s"
+
+#, c-format
+msgid "Affix name too long in %s line %d: %s"
+msgstr "Affiksnavn for langt i %s linje %d: %s"
+
+msgid "E761: Format error in affix file FOL, LOW or UPP"
+msgstr "E761: Formatfeil i affiksfil FOL, LOW eller UPP"
+
+msgid "E762: Character in FOL, LOW or UPP is out of range"
+msgstr "E762: Tegn i FOL, LOW eller UPP er utenfor område"
+
+msgid "Compressing word tree..."
+msgstr "Pakker ordtre ..."
+
+msgid "E756: Spell checking is not enabled"
+msgstr "E756: Stavekontroll er ikke aktivisert"
+
+#, c-format
+msgid "Warning: Cannot find word list \"%s.%s.spl\" or \"%s.ascii.spl\""
+msgstr "Advarsel: Kan ikke finne ordliste \"%s.%s.spl\" eller \"%s.ascii.spl\""
+
+#, c-format
+msgid "Reading spell file \"%s\""
+msgstr "Leser stavefil \"%s\""
+
+msgid "E757: This does not look like a spell file"
+msgstr "E757: Dette ser ikke ut som en stavefil"
+
+msgid "E771: Old spell file, needs to be updated"
+msgstr "E771: Gammel stavefil, trenger oppdatering"
+
+msgid "E772: Spell file is for newer version of Vim"
+msgstr "E772: Stavefilen er for en nyere versjon av Vim"
+
+msgid "E770: Unsupported section in spell file"
+msgstr "E770: Ustøttet seksjon i stavefil"
+
+#, c-format
+msgid "Warning: region %s not supported"
+msgstr "Advarsel: Region %s ikke støttet"
+
+#, c-format
+msgid "Reading affix file %s..."
+msgstr "Leser affiksfil %s..."
+
+#, c-format
+msgid "Conversion failure for word in %s line %d: %s"
+msgstr "Konverteringsfeil for ord i %s linje %d: %s"
+
+#, c-format
+msgid "Conversion in %s not supported: from %s to %s"
+msgstr "Konvertering i %s ikke støttet: Fra %s til %s"
+
+#, c-format
+msgid "Conversion in %s not supported"
+msgstr "Konvertering i %s ikke støttet"
+
+#, c-format
+msgid "Invalid value for FLAG in %s line %d: %s"
+msgstr "Ugyldig verdi for FLAG i %s linje %d: %s"
+
+#, c-format
+msgid "FLAG after using flags in %s line %d: %s"
+msgstr "FLAG etter bruk av flagg i %s linje %d: %s"
+
+#, c-format
+#~ msgid ""
+#~ "Defining COMPOUNDFORBIDFLAG after PFX item may give wrong results in %s line "
+#~ "%d"
+#~ msgstr ""
+
+#, c-format
+#~ msgid ""
+#~ "Defining COMPOUNDPERMITFLAG after PFX item may give wrong results in %s line "
+#~ "%d"
+#~ msgstr ""
+
+#, c-format
+msgid "Wrong COMPOUNDWORDMAX value in %s line %d: %s"
+msgstr "Feil COMPOUNDWORDMAX-verdi i %s linje %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDMIN value in %s line %d: %s"
+msgstr "Feil COMPOUNDMIN-verdi i %s linje %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDSYLMAX value in %s line %d: %s"
+msgstr "Feil COMPOUNDSYLMAX-verdi i %s linje %d: %s"
+
+#, c-format
+msgid "Wrong CHECKCOMPOUNDPATTERN value in %s line %d: %s"
+msgstr "Feil CHECKCOMPOUNDPATTERN-verdi i %s linje %d: %s"
+
+#, c-format
+msgid "Different combining flag in continued affix block in %s line %d: %s"
+msgstr ""
+"Forskjellig kombinasjonsflagg i affiksblokk som fortsetter i %s linje %d: %s"
+
+#, c-format
+msgid "Duplicate affix in %s line %d: %s"
+msgstr "Duplisert affiks i %s linje %d: %s"
+
+#, c-format
+msgid ""
+"Affix also used for BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST in %s "
+"line %d: %s"
+msgstr ""
+"Affiks også brukt for BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST i %"
+"s linje %d: %s"
+
+#, c-format
+msgid "Expected Y or N in %s line %d: %s"
+msgstr "Forventet Y eller N i %s linje %d: %s"
+
+#, c-format
+msgid "Broken condition in %s line %d: %s"
+msgstr "Brutt betingelse i %s linje %d: %s"
+
+#, c-format
+msgid "Expected REP(SAL) count in %s line %d"
+msgstr "Forventet REP(SAL)-antall i %s linje %d"
+
+#, c-format
+msgid "Expected MAP count in %s line %d"
+msgstr "Forventet MAP-antall i %s linje %d"
+
+#, c-format
+msgid "Duplicate character in MAP in %s line %d"
+msgstr "Duplisert tegn i MAP i %s linje %d"
+
+#, c-format
+msgid "Unrecognized or duplicate item in %s line %d: %s"
+msgstr "Ukjent eller duplisert element i %s linje %d: %s"
+
+#, c-format
+msgid "Missing FOL/LOW/UPP line in %s"
+msgstr "Mangler FOL/LOW/UPP-linje i %s"
+
+msgid "COMPOUNDSYLMAX used without SYLLABLE"
+msgstr "COMPOUNDSYLMAX brukt uten SYLLABLE"
+
+msgid "Too many postponed prefixes"
+msgstr "For mange utsatte forstavelser"
+
+msgid "Too many compound flags"
+msgstr "For mange sammensatte flagg"
+
+msgid "Too many postponed prefixes and/or compound flags"
+msgstr "For mange utsatte forstavelser og/eller sammensatte flagg"
+
+#, c-format
+msgid "Missing SOFO%s line in %s"
+msgstr "Mangler SOFO%s-linje i %s"
+
+#, c-format
+msgid "Both SAL and SOFO lines in %s"
+msgstr "Både SAL- og SOFO-linjer i %s"
+
+#, c-format
+msgid "Flag is not a number in %s line %d: %s"
+msgstr "Flagg er ikke et tall i %s linje %d: %s"
+
+#, c-format
+msgid "Illegal flag in %s line %d: %s"
+msgstr "Ulovlig flagg i %s linje %d: %s"
+
+#, c-format
+msgid "%s value differs from what is used in another .aff file"
+msgstr "%s-verdi er forskjellig fra det som er bruk i en annen .aff-fil"
+
+#, c-format
+msgid "Reading dictionary file %s..."
+msgstr "Leser ordlistefil %s..."
+
+#, c-format
+msgid "E760: No word count in %s"
+msgstr "E760: Ingen ord-antall i %s"
+
+#, c-format
+msgid "line %6d, word %6d - %s"
+msgstr "linje %6d, ord %6d - %s"
+
+#, c-format
+msgid "Duplicate word in %s line %d: %s"
+msgstr "Duplisert ord i %s linje %d: %s"
+
+#, c-format
+msgid "First duplicate word in %s line %d: %s"
+msgstr "Første dupliserte ord i %s linje %d: %s"
+
+#, c-format
+msgid "%d duplicate word(s) in %s"
+msgstr "%d duplisert(e) ord i %s"
+
+#, c-format
+msgid "Ignored %d word(s) with non-ASCII characters in %s"
+msgstr "Ignorerte %d ord med ikke-ASCII-tegn i %s"
+
+#, c-format
+msgid "Reading word file %s..."
+msgstr "Leser ordfil %s..."
+
+#, c-format
+msgid "Duplicate /encoding= line ignored in %s line %d: %s"
+msgstr "Duplisert '/encoding='-linje ignorert i %s linje %d: %s"
+
+#, c-format
+msgid "/encoding= line after word ignored in %s line %d: %s"
+msgstr "'/encoding='-linje etter ord ignorert i %s linje %d: %s"
+
+#, c-format
+msgid "Duplicate /regions= line ignored in %s line %d: %s"
+msgstr "Duplisert '/regions='-linje ignorert i %s linje %d: %s"
+
+#, c-format
+msgid "Too many regions in %s line %d: %s"
+msgstr "For mange regioner i %s linje %d: %s"
+
+#, c-format
+msgid "/ line ignored in %s line %d: %s"
+msgstr "'/'-linje ignorert i %s linje %d: %s"
+
+#, c-format
+msgid "Invalid region nr in %s line %d: %s"
+msgstr "Ugyldig regionnummer i %s linje %d: %s"
+
+#, c-format
+msgid "Unrecognized flags in %s line %d: %s"
+msgstr "Ukjent flagg i %s linje %d: %s"
+
+#, c-format
+msgid "Ignored %d words with non-ASCII characters"
+msgstr "Ignorerte %d ord med ikke-ASCII-tegn"
+
+#, c-format
+msgid "Compressed %d of %d nodes; %d (%d%%) remaining"
+msgstr "Pakket %d av %d noder; %d (%d%%) igjen"
+
+#, fuzzy
+#~ msgid "Reading back spell file..."
+#~ msgstr "Leser stavefil \"%s\""
+
+#.
+#. * Go through the trie of good words, soundfold each word and add it to
+#. * the soundfold trie.
+#.
+#~ msgid "Performing soundfolding..."
+#~ msgstr ""
+
+#, c-format
+#~ msgid "Number of words after soundfolding: %ld"
+#~ msgstr ""
+
+#, c-format
+msgid "Total number of words: %d"
+msgstr "Totalt antall ord: %d"
+
+#, c-format
+msgid "Writing suggestion file %s..."
+msgstr "Skriver forslagsfil %s..."
+
+#, c-format
+msgid "Estimated runtime memory use: %d bytes"
+msgstr "Anslått hukommelsesbruk under kjøring: %d bytes"
+
+msgid "E751: Output file name must not have region name"
+msgstr "E751: Utdatafilnavn må ikke ha regionnavn"
+
+msgid "E754: Only up to 8 regions supported"
+msgstr "E754: Kun opp til 8 regioner er støttet"
+
+#, c-format
+msgid "E755: Invalid region in %s"
+msgstr "E755: Ugyldig region i %s"
+
+#~ msgid "Warning: both compounding and NOBREAK specified"
+#~ msgstr ""
+
+#, c-format
+msgid "Writing spell file %s..."
+msgstr "Lagrer stavefil %s..."
+
+msgid "Done!"
+msgstr "Ferdig!"
+
+#, c-format
+msgid "E765: 'spellfile' does not have %ld entries"
+msgstr "E765: 'spellfile' har ikke %ld poster"
+
+#, c-format
+msgid "Word removed from %s"
+msgstr "Ord fjernet fra %s"
+
+#, c-format
+msgid "Word added to %s"
+msgstr "Ord lagt til %s"
+
+msgid "E763: Word characters differ between spell files"
+msgstr "E763: Tegn i ord varierer mellom stavefiler"
+
+msgid "Sorry, no suggestions"
+msgstr "Dessverre, ingen forslag"
+
+#, c-format
+msgid "Sorry, only %ld suggestions"
+msgstr "Dessverre bare %ld forslag"
+
+#. for when 'cmdheight' > 1
+#. avoid more prompt
+#, c-format
+msgid "Change \"%.*s\" to:"
+msgstr "Forandre \"%.*s\" til:"
+
+#, c-format
+msgid " < \"%.*s\""
+msgstr " < \"%.*s\""
+
+msgid "E752: No previous spell replacement"
+msgstr "E752: Ingen tidligere staveerstatninger"
+
+#, c-format
+msgid "E753: Not found: %s"
+msgstr "E753: Ikke funnet: %s"
+
+#, c-format
+msgid "E778: This does not look like a .sug file: %s"
+msgstr "E778: Dette ser ikke ut som en .sug-fil: %s"
+
+#, c-format
+msgid "E779: Old .sug file, needs to be updated: %s"
+msgstr "E779: Gammel .sug-fil, trenger oppdatering: %s"
+
+#, c-format
+msgid "E780: .sug file is for newer version of Vim: %s"
+msgstr "E780: .sug-fila er for en nyere versjon av Vim: %s"
+
+#, c-format
+msgid "E781: .sug file doesn't match .spl file: %s"
+msgstr "E781: .sug-fil samsvarer ikke med .spl-fil: %s"
+
+#, c-format
+msgid "E782: error while reading .sug file: %s"
+msgstr "E782: Feil under lesing av .sug-fil: %s"
+
+#. This should have been checked when generating the .spl
+#. * file.
+msgid "E783: duplicate char in MAP entry"
+msgstr "E783: Duplisert tegn i MAP-oppføring"
+
+#, c-format
+msgid "E390: Illegal argument: %s"
+msgstr "E390: Ulovlig parameter: %s"
+
+#, c-format
+msgid "E391: No such syntax cluster: %s"
+msgstr "E391: Syntaksklyngen finnes ikke: %s"
+
+msgid "No Syntax items defined for this buffer"
+msgstr "Ingen syntakselementer er definert for denne bufferen"
+
+msgid "syncing on C-style comments"
+msgstr "synkroniserer C-lignende kommentarer"
+
+msgid "no syncing"
+msgstr "ingen synkronisering"
+
+msgid "syncing starts "
+msgstr "synkronisering starter "
+
+msgid " lines before top line"
+msgstr " linjer før topplinje"
+
+msgid ""
+"\n"
+"--- Syntax sync items ---"
+msgstr ""
+"\n"
+"--- \"Syntax sync\"-elementer ---"
+
+msgid ""
+"\n"
+"syncing on items"
+msgstr ""
+"\n"
+"synkroniserer på elementer"
+
+msgid ""
+"\n"
+"--- Syntax items ---"
+msgstr ""
+"\n"
+"--- Syntakselementer ---"
+
+#, c-format
+msgid "E392: No such syntax cluster: %s"
+msgstr "E392: Syntaksklyngen finnes ikke: %s"
+
+msgid "minimal "
+msgstr "minimal "
+
+msgid "maximal "
+msgstr "maksimal "
+
+msgid "; match "
+msgstr "; samsvarer med "
+
+msgid " line breaks"
+msgstr " linjeskift"
+
+msgid "E395: contains argument not accepted here"
+msgstr "E395: \"contains\"-parameter aksepteres ikke her"
+
+msgid "E396: containedin argument not accepted here"
+msgstr "E396: \"containedin\"-parameter aksepteres ikke her"
+
+msgid "E393: group[t]here not accepted here"
+msgstr "E393: \"group[t]here\" aksepteres ikke her"
+
+#, c-format
+msgid "E394: Didn't find region item for %s"
+msgstr "E394: Fant ikke regionelement for %s"
+
+msgid "E397: Filename required"
+msgstr "E397: Trenger filnavn"
+
+#, c-format
+msgid "E789: Missing ']': %s"
+msgstr "E789: Mangler ']': %s"
+
+#, c-format
+msgid "E398: Missing '=': %s"
+msgstr "E398: Mangler '=': %s"
+
+#, c-format
+msgid "E399: Not enough arguments: syntax region %s"
+msgstr "E399: Ikke nok parametere: syntax region %s"
+
+msgid "E400: No cluster specified"
+msgstr "E400: Ingen klynge er spesifisert"
+
+#, c-format
+msgid "E401: Pattern delimiter not found: %s"
+msgstr "E401: Skilletegn for søketekst ble ikke funnet: %s"
+
+#, c-format
+msgid "E402: Garbage after pattern: %s"
+msgstr "E402: Søppel etter søketekst: %s"
+
+msgid "E403: syntax sync: line continuations pattern specified twice"
+msgstr ""
+"E403: syntax sync: Søkestreng for linjefortsettelser er spesifisert to ganger"
+
+#, c-format
+msgid "E404: Illegal arguments: %s"
+msgstr "E404: Ulovlige parametere: %s"
+
+#, c-format
+msgid "E405: Missing equal sign: %s"
+msgstr "E405: Mangler \"er lik\"-tegn: %s"
+
+#, c-format
+msgid "E406: Empty argument: %s"
+msgstr "E406: Tomt parameter: %s"
+
+#, c-format
+msgid "E407: %s not allowed here"
+msgstr "E407: %s er ikke tillatt her"
+
+#, c-format
+msgid "E408: %s must be first in contains list"
+msgstr "E408: %s må være først i \"contains\"-liste"
+
+#, c-format
+msgid "E409: Unknown group name: %s"
+msgstr "E409: Ukjent gruppenavn: %s"
+
+#, c-format
+msgid "E410: Invalid :syntax subcommand: %s"
+msgstr "E410: Ugyldig \":syntax\"-delkommando: %s"
+
+msgid "E679: recursive loop loading syncolor.vim"
+msgstr "E679: Rekursiv løkke laster syncolor.vim"
+
+#, c-format
+msgid "E411: highlight group not found: %s"
+msgstr "E411: Fant ikke uthevingsgruppe: %s"
+
+#, c-format
+msgid "E412: Not enough arguments: \":highlight link %s\""
+msgstr "E412: Ikke nok parametere: \":highlight link %s\""
+
+#, c-format
+msgid "E413: Too many arguments: \":highlight link %s\""
+msgstr "E413: For mange parametere: \":highlight link %s\""
+
+msgid "E414: group has settings, highlight link ignored"
+msgstr "E414: Syntaxgruppen har oppsett, uthevingslenke ignoreres"
+
+#, c-format
+msgid "E415: unexpected equal sign: %s"
+msgstr "E415: Uventet \"er lik\"-tegn: %s"
+
+#, c-format
+msgid "E416: missing equal sign: %s"
+msgstr "E416: Mangler \"er lik\"-tegn: %s"
+
+#, c-format
+msgid "E417: missing argument: %s"
+msgstr "E417: Mangler parameter: %s"
+
+#, c-format
+msgid "E418: Illegal value: %s"
+msgstr "E418: Ulovlig verdi: %s"
+
+msgid "E419: FG color unknown"
+msgstr "E419: Ukjent forgrunnsfarge"
+
+msgid "E420: BG color unknown"
+msgstr "E420: Ukjent bakgrunnsfarge"
+
+#, c-format
+msgid "E421: Color name or number not recognized: %s"
+msgstr "E421: Kjenner ikke til fargenavnet eller -nummeret: %s"
+
+#, c-format
+msgid "E422: terminal code too long: %s"
+msgstr "E422: Terminalkoden er for lang: %s"
+
+#, c-format
+msgid "E423: Illegal argument: %s"
+msgstr "E423: Ulovlig parameter: %s"
+
+msgid "E424: Too many different highlighting attributes in use"
+msgstr "E424: For mange forskjellige uthevingsattributter i bruk"
+
+msgid "E669: Unprintable character in group name"
+msgstr "E669: Ikke-skrivbart tegn i gruppenavn"
+
+msgid "W18: Invalid character in group name"
+msgstr "W18: Ugyldig tegn i gruppenavn"
+
+msgid "E555: at bottom of tag stack"
+msgstr "E555: På bunnen av tag-stack"
+
+msgid "E556: at top of tag stack"
+msgstr "E556: På toppen av tag-stack"
+
+msgid "E425: Cannot go before first matching tag"
+msgstr "E425: Kan ikke gå før første samsvarende tag"
+
+#, c-format
+msgid "E426: tag not found: %s"
+msgstr "E426: Fant ikke tag: %s"
+
+#~ msgid " # pri kind tag"
+#~ msgstr ""
+
+msgid "file\n"
+msgstr "fil\n"
+
+msgid "E427: There is only one matching tag"
+msgstr "E427: Det finnes bare en samsvarende tag"
+
+msgid "E428: Cannot go beyond last matching tag"
+msgstr "E428: Kan ikke gå forbi siste samsvarende tag"
+
+#, c-format
+msgid "File \"%s\" does not exist"
+msgstr "Filen \"%s\" finnes ikke"
+
+#. Give an indication of the number of matching tags
+#, c-format
+msgid "tag %d of %d%s"
+msgstr "tag %d av %d%s"
+
+msgid " or more"
+msgstr " eller mer"
+
+msgid " Using tag with different case!"
+msgstr " Bruker tag med forskjellig bokstavstørrelse!"
+
+#, c-format
+msgid "E429: File \"%s\" does not exist"
+msgstr "E429: Filen \"%s\" finnes ikke"
+
+#. Highlight title
+msgid ""
+"\n"
+" # TO tag FROM line in file/text"
+msgstr ""
+"\n"
+" # TIL tag FRA linje i fil/tekst"
+
+#, c-format
+msgid "Searching tags file %s"
+msgstr "Leter i tagfil %s"
+
+#, c-format
+msgid "E430: Tag file path truncated for %s\n"
+msgstr "E430: Sti til tagfil kuttet for %s\n"
+
+#, c-format
+msgid "E431: Format error in tags file \"%s\""
+msgstr "E431: Formatfeil i tagfil \"%s\""
+
+#, c-format
+msgid "Before byte %ld"
+msgstr "Før byte %ld"
+
+#, c-format
+msgid "E432: Tags file not sorted: %s"
+msgstr "E432: Tagfil ikke sortert: %s"
+
+#. never opened any tags file
+msgid "E433: No tags file"
+msgstr "E433: Ingen tagfil"
+
+msgid "E434: Can't find tag pattern"
+msgstr "E434: Kan ikke finne tagsøkestreng"
+
+msgid "E435: Couldn't find tag, just guessing!"
+msgstr "E435: Kunne ikke finne tag, bare gjetter!"
+
+msgid "' not known. Available builtin terminals are:"
+msgstr "' ikke kjent. Tilgjengelige innebygde terminaler er:"
+
+msgid "defaulting to '"
+msgstr "faller tilbake på '"
+
+msgid "E557: Cannot open termcap file"
+msgstr "E557: Kan ikke åpne termcap-fil"
+
+msgid "E558: Terminal entry not found in terminfo"
+msgstr "E558: Fant ikke terminaloppføring i terminfo"
+
+msgid "E559: Terminal entry not found in termcap"
+msgstr "E559: Fant ikke terminaloppføring i termcap"
+
+#, c-format
+msgid "E436: No \"%s\" entry in termcap"
+msgstr "E436: Ingen \"%s\"-oppføring i termcap"
+
+msgid "E437: terminal capability \"cm\" required"
+msgstr "E437: Terminalfunksjonen \"cm\" nødvendig"
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Terminal keys ---"
+msgstr ""
+"\n"
+"--- Terminaltaster ---"
+
+msgid "new shell started\n"
+msgstr "nytt skall startet\n"
+
+msgid "Vim: Error reading input, exiting...\n"
+msgstr "Vim: Feil under lesing av inndata, avslutter ...\n"
+
+#. must display the prompt
+msgid "No undo possible; continue anyway"
+msgstr "Ingen angremuligheter; fortsett likevel"
+
+msgid "Already at oldest change"
+msgstr "Allerede ved eldste forandring"
+
+msgid "Already at newest change"
+msgstr "Allerede ved nyeste forandring"
+
+#, c-format
+msgid "Undo number %ld not found"
+msgstr "Angrenummer %ld ikke funnet"
+
+msgid "E438: u_undo: line numbers wrong"
+msgstr "E438: u_undo: Gale linjenummer"
+
+msgid "more line"
+msgstr "linje lagt til"
+
+msgid "more lines"
+msgstr "linjer lagt til"
+
+msgid "line less"
+msgstr "linje fjernet"
+
+msgid "fewer lines"
+msgstr "linjer fjernet"
+
+msgid "change"
+msgstr "forandring"
+
+msgid "changes"
+msgstr "forandringer"
+
+#, c-format
+msgid "%ld %s; %s #%ld %s"
+msgstr "%ld %s; %s #%ld %s"
+
+msgid "before"
+msgstr "før"
+
+msgid "after"
+msgstr "etter"
+
+msgid "Nothing to undo"
+msgstr "Ingenting å angre"
+
+msgid "number changes time"
+msgstr "nummer forandringer tidspunkt"
+
+#, c-format
+msgid "%ld seconds ago"
+msgstr "%ld sekunder siden"
+
+msgid "E790: undojoin is not allowed after undo"
+msgstr "E790: undojoin er ikke tillatt etter undo"
+
+msgid "E439: undo list corrupt"
+msgstr "E439: Angrelisten er skadet"
+
+msgid "E440: undo line missing"
+msgstr "E440: Angrelisten mangler"
+
+#. Only MS VC 4.1 and earlier can do Win32s
+msgid ""
+"\n"
+"MS-Windows 16/32-bit GUI version"
+msgstr ""
+"\n"
+"MS Windows 16/32-bits grafisk versjon"
+
+msgid ""
+"\n"
+"MS-Windows 64-bit GUI version"
+msgstr ""
+"\n"
+"MS Windows 64-bits grafisk versjon"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit GUI version"
+msgstr ""
+"\n"
+"MS-Windows 32-bits GUI-versjon"
+
+msgid " in Win32s mode"
+msgstr " i Win32s-modus"
+
+msgid " with OLE support"
+msgstr " med OLE-støtte"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit console version"
+msgstr ""
+"\n"
+"MS-Windows 32-bits konsollversjon"
+
+msgid ""
+"\n"
+"MS-Windows 16-bit version"
+msgstr ""
+"\n"
+"MS-Windows 16-bits versjon"
+
+msgid ""
+"\n"
+"32-bit MS-DOS version"
+msgstr ""
+"\n"
+"32-bits MS-DOS-versjon"
+
+msgid ""
+"\n"
+"16-bit MS-DOS version"
+msgstr ""
+"\n"
+"16-bits MS-DOS-versjon"
+
+msgid ""
+"\n"
+"MacOS X (unix) version"
+msgstr ""
+"\n"
+"MacOS X (unix)-versjon"
+
+msgid ""
+"\n"
+"MacOS X version"
+msgstr ""
+"\n"
+"MacOS X-versjon"
+
+msgid ""
+"\n"
+"MacOS version"
+msgstr ""
+"\n"
+"MacOS-versjon"
+
+msgid ""
+"\n"
+"RISC OS version"
+msgstr ""
+"\n"
+"RISC OS-versjon"
+
+msgid ""
+"\n"
+"Included patches: "
+msgstr ""
+"\n"
+"Inkluderte patcher: "
+
+msgid "Modified by "
+msgstr "Modifisert av "
+
+msgid ""
+"\n"
+"Compiled "
+msgstr ""
+"\n"
+"Kompilert "
+
+msgid "by "
+msgstr "av "
+
+msgid ""
+"\n"
+"Huge version "
+msgstr ""
+"\n"
+"Diger (\"huge\") versjon "
+
+msgid ""
+"\n"
+"Big version "
+msgstr ""
+"\n"
+"Stor (\"big\") versjon "
+
+msgid ""
+"\n"
+"Normal version "
+msgstr ""
+"\n"
+"Normal versjon "
+
+msgid ""
+"\n"
+"Small version "
+msgstr ""
+"\n"
+"Liten (\"small\") versjon "
+
+msgid ""
+"\n"
+"Tiny version "
+msgstr ""
+"\n"
+"Spinkel (\"tiny\") versjon "
+
+msgid "without GUI."
+msgstr "uten GUI."
+
+msgid "with GTK2-GNOME GUI."
+msgstr "med GTK2-GNOME GUI."
+
+msgid "with GTK-GNOME GUI."
+msgstr "med GTK-GNOME GUI."
+
+msgid "with GTK2 GUI."
+msgstr "med GTK2 GUI."
+
+msgid "with GTK GUI."
+msgstr "med GTK GUI."
+
+msgid "with X11-Motif GUI."
+msgstr "med X11-Motif GUI."
+
+msgid "with X11-neXtaw GUI."
+msgstr "med X11-neXtaw GUI."
+
+msgid "with X11-Athena GUI."
+msgstr "med X11-Athena GUI."
+
+msgid "with Photon GUI."
+msgstr "med Photon GUI."
+
+msgid "with GUI."
+msgstr "med GUI."
+
+msgid "with Carbon GUI."
+msgstr "med Carbon GUI."
+
+msgid "with Cocoa GUI."
+msgstr "med Cocoa GUI."
+
+msgid "with (classic) GUI."
+msgstr "med (klassisk) GUI."
+
+msgid " Features included (+) or not (-):\n"
+msgstr " Funksjoner inkludert (+) eller ikke (-):\n"
+
+msgid " system vimrc file: \""
+msgstr " vimrc-fil på systemet: \""
+
+msgid " user vimrc file: \""
+msgstr " vimrc-fil for brukere: \""
+
+msgid " 2nd user vimrc file: \""
+msgstr " vimrc-fil nr. 2 for brukere: \""
+
+msgid " 3rd user vimrc file: \""
+msgstr " vimrc-fil nr. 3 for brukere: \""
+
+msgid " user exrc file: \""
+msgstr " exrc-fil for brukere: \""
+
+msgid " 2nd user exrc file: \""
+msgstr " exrc-fil nr. 2 for brukere: \""
+
+msgid " system gvimrc file: \""
+msgstr " gvimrc-fil på systemet: \""
+
+msgid " user gvimrc file: \""
+msgstr " gvimrc-fil for brukere: \""
+
+msgid "2nd user gvimrc file: \""
+msgstr " gvimrc-fil nr. 2 for brukere: \""
+
+msgid "3rd user gvimrc file: \""
+msgstr " gvimrc-fil nr. 3 for brukere: \""
+
+msgid " system menu file: \""
+msgstr " menyfil på systemet: \""
+
+msgid " fall-back for $VIM: \""
+msgstr " $VIM faller tilbake på: \""
+
+msgid " f-b for $VIMRUNTIME: \""
+msgstr "$VIMRUNTIME faller tilbake på: \""
+
+msgid "Compilation: "
+msgstr "Kompilering: "
+
+msgid "Compiler: "
+msgstr "Kompilator: "
+
+msgid "Linking: "
+msgstr "Linking: "
+
+msgid " DEBUG BUILD"
+msgstr " DEBUGGINGSVERSJON"
+
+msgid "VIM - Vi IMproved"
+msgstr "VIM - Vi IMproved - Forbedret Vi"
+
+msgid "version "
+msgstr "versjon "
+
+msgid "by Bram Moolenaar et al."
+msgstr "av Bram Moolenaar med flere"
+
+msgid "Vim is open source and freely distributable"
+msgstr "Vim er åpen kildekode og kan fritt distribueres"
+
+msgid "Help poor children in Uganda!"
+msgstr "Hjelp fattige barn i Uganda!"
+
+msgid "type :help iccf<Enter> for information "
+msgstr "skriv :help iccf<Enter> for informasjon "
+
+msgid "type :q<Enter> to exit "
+msgstr "skriv :q<Enter> for å avslutte "
+
+msgid "type :help<Enter> or <F1> for on-line help"
+msgstr "skriv :help<Enter> eller <F1> for on-line hjelp"
+
+msgid "type :help version8<Enter> for version info"
+msgstr "skriv :help version8<Enter> for versjonsinfo "
+
+msgid "Running in Vi compatible mode"
+msgstr "Kjører i Vi-kompatibel modus"
+
+msgid "type :set nocp<Enter> for Vim defaults"
+msgstr "skriv :set nocp<Enter> for standard Vim "
+
+msgid "type :help cp-default<Enter> for info on this"
+msgstr "skriv :help cp-default<Enter> for informasjon "
+
+msgid "menu Help->Orphans for information "
+msgstr "meny: Hjelp->Foreldreløse for informasjon "
+
+msgid "Running modeless, typed text is inserted"
+msgstr "Kjører uten modus, tastetrykk blir lagt inn i teksten"
+
+msgid "menu Edit->Global Settings->Toggle Insert Mode "
+msgstr "meny: Rediger->Globale innstillinger->Innsettingsmodus av/på"
+
+msgid " for two modes "
+msgstr " for to moduser "
+
+msgid "menu Edit->Global Settings->Toggle Vi Compatible"
+msgstr "meny: Rediger->Globale innstillinger->Vi-kompatibilitet av/på"
+
+msgid " for Vim defaults "
+msgstr " for standard Vim "
+
+msgid "Sponsor Vim development!"
+msgstr "Støtt utviklingen av Vim!"
+
+msgid "Become a registered Vim user!"
+msgstr "Bli registrert bruker av Vim!"
+
+msgid "type :help sponsor<Enter> for information "
+msgstr "skriv :help sponsor<Enter> for informasjon "
+
+msgid "type :help register<Enter> for information "
+msgstr "skriv :help register<Enter> for informasjon "
+
+msgid "menu Help->Sponsor/Register for information "
+msgstr "meny: Hjelp->Støtte/Registrering for informasjon "
+
+msgid "WARNING: Windows 95/98/ME detected"
+msgstr "ADVARSEL: Windows 95/98/ME oppdaget"
+
+msgid "type :help windows95<Enter> for info on this"
+msgstr "skriv :help windows95<Enter> for informasjon "
+
+msgid "Already only one window"
+msgstr "Allerede bare ett vindu"
+
+msgid "E441: There is no preview window"
+msgstr "E441: Vindu for forhåndsvisning finnes ikke"
+
+msgid "E442: Can't split topleft and botright at the same time"
+msgstr "E442: Kan ikke splitte \"topleft\" og \"botright\" på en gang"
+
+msgid "E443: Cannot rotate when another window is split"
+msgstr "E443: Kan ikke rotere når et annet vindu er splittet"
+
+msgid "E444: Cannot close last window"
+msgstr "E444: Kan ikke lukke det siste vinduet"
+
+msgid "E445: Other window contains changes"
+msgstr "E445: Annet vindu inneholder forandringer"
+
+msgid "E446: No file name under cursor"
+msgstr "E446: Ingen filnavn under markøren"
+
+#, c-format
+msgid "E447: Can't find file \"%s\" in path"
+msgstr "E447: Kan ikke finne filen \"%s\" i stien"
+
+#, c-format
+msgid "E370: Could not load library %s"
+msgstr "E370: Klarte ikke laste bibliotek %s"
+
+msgid "Sorry, this command is disabled: the Perl library could not be loaded."
+msgstr "Denne kommandoen er deaktivert, Perl-biblioteket kunne ikke lastes."
+
+msgid "E299: Perl evaluation forbidden in sandbox without the Safe module"
+msgstr ""
+"E299: Evaluering av Perl er ikke tillatt i sandkassen uten \"Safe\"-modulen"
+
+msgid "Edit with &multiple Vims"
+msgstr "Rediger med &flere Vim-er"
+
+msgid "Edit with single &Vim"
+msgstr "Rediger med enkel &Vim"
+
+msgid "Diff with Vim"
+msgstr "Differanse med Vim"
+
+msgid "Edit with &Vim"
+msgstr "Rediger med &Vim"
+
+#. Now concatenate
+msgid "Edit with existing Vim - "
+msgstr "Rediger med eksisterende Vim - "
+
+msgid "Edits the selected file(s) with Vim"
+msgstr "Redigerer de(n) valgte filen(e) med Vim"
+
+msgid "Error creating process: Check if gvim is in your path!"
+msgstr "Klarte ikke lage prosess: Sjekk at gvim er i stien!"
+
+msgid "gvimext.dll error"
+msgstr "Feil i gvimext.dll"
+
+msgid "Path length too long!"
+msgstr "Lengden på stien er for lang!"
+
+msgid "--No lines in buffer--"
+msgstr "--Ingen linjer i bufferen--"
+
+#.
+#. * The error messages that can be shared are included here.
+#. * Excluded are errors that are only used once and debugging messages.
+#.
+msgid "E470: Command aborted"
+msgstr "E470: Kommandoen avbrutt"
+
+msgid "E471: Argument required"
+msgstr "E471: Parameter nødvendig"
+
+msgid "E10: \\ should be followed by /, ? or &"
+msgstr "E10: \\ skulle ha vært fulgt av /, ? eller &"
+
+msgid "E11: Invalid in command-line window; <CR> executes, CTRL-C quits"
+msgstr "E11: Ugyldig i kommandolinjevindu; <ENTER> utfører, CTRL-C avslutter"
+
+msgid "E12: Command not allowed from exrc/vimrc in current dir or tag search"
+msgstr ""
+"E12: Kommandoen er ikke tillatt fra exrc/vimrc i nåværende katalog eller "
+"tagsøk"
+
+msgid "E171: Missing :endif"
+msgstr "E171: Mangler :endif"
+
+msgid "E600: Missing :endtry"
+msgstr "E600: Mangler :endtry"
+
+msgid "E170: Missing :endwhile"
+msgstr "E170: Mangler :endwhile"
+
+msgid "E170: Missing :endfor"
+msgstr "E170: Mangler :endfor"
+
+msgid "E588: :endwhile without :while"
+msgstr "E588: :endwhile uten :while"
+
+msgid "E588: :endfor without :for"
+msgstr "E588: :endfor uten :for"
+
+msgid "E13: File exists (add ! to override)"
+msgstr "E13: Filen finnes (legg til ! for å overstyre)"
+
+msgid "E472: Command failed"
+msgstr "E472: Kommandoen feilet"
+
+#, c-format
+msgid "E234: Unknown fontset: %s"
+msgstr "E234: Ukjent skrifttypesett: %s"
+
+#, c-format
+msgid "E235: Unknown font: %s"
+msgstr "E235: Ukjent skrifttype: %s"
+
+#, c-format
+msgid "E236: Font \"%s\" is not fixed-width"
+msgstr "E236: Skrifttypen \"%s\" har ikke fast bredde"
+
+msgid "E473: Internal error"
+msgstr "E473: Intern feil"
+
+msgid "Interrupted"
+msgstr "Avbrutt"
+
+msgid "E14: Invalid address"
+msgstr "E14: Ugyldig adresse"
+
+msgid "E474: Invalid argument"
+msgstr "E474: Ugyldig parameter"
+
+#, c-format
+msgid "E475: Invalid argument: %s"
+msgstr "E475: Ugyldig paramter: %s"
+
+#, c-format
+msgid "E15: Invalid expression: %s"
+msgstr "E15: Ugyldig uttrykk: %s"
+
+msgid "E16: Invalid range"
+msgstr "E16: Ugyldig område"
+
+msgid "E476: Invalid command"
+msgstr "E476: Ugyldig kommando"
+
+#, c-format
+msgid "E17: \"%s\" is a directory"
+msgstr "E17: \"%s\" er en katalog"
+
+#, c-format
+msgid "E364: Library call failed for \"%s()\""
+msgstr "E364: Bibliotek-kall feilet for \"%s()\""
+
+#, c-format
+msgid "E448: Could not load library function %s"
+msgstr "E448: Klarte ikke laste biblioteksfunksjon %s"
+
+msgid "E19: Mark has invalid line number"
+msgstr "E19: Merket har et ugyldig linjenummer"
+
+msgid "E20: Mark not set"
+msgstr "E20: Merket ble ikke satt"
+
+msgid "E21: Cannot make changes, 'modifiable' is off"
+msgstr "E21: Kan ikke gjøre forandringer, 'modifiable' er av"
+
+msgid "E22: Scripts nested too deep"
+msgstr "E22: Skripts nøstet for dypt"
+
+msgid "E23: No alternate file"
+msgstr "E23: Ingen alternativ fil"
+
+msgid "E24: No such abbreviation"
+msgstr "E24: Forkortelsen finnes ikke"
+
+msgid "E477: No ! allowed"
+msgstr "E477: Ingen ! tillatt"
+
+msgid "E25: GUI cannot be used: Not enabled at compile time"
+msgstr "E25: GUI kan ikke brukes: Ikke slått på under kompilering"
+
+msgid "E26: Hebrew cannot be used: Not enabled at compile time\n"
+msgstr "E26: Hebraisk kan ikke brukes: Ikke slått på under kompilering\n"
+
+msgid "E27: Farsi cannot be used: Not enabled at compile time\n"
+msgstr ""
+"E27: Persisk (Farsi) kan ikke brukes: Ikke slått på under kompilering\n"
+
+msgid "E800: Arabic cannot be used: Not enabled at compile time\n"
+msgstr "E800: Arabisk kan ikke brukes: Ikke slått på under kompilering\n"
+
+#, c-format
+msgid "E28: No such highlight group name: %s"
+msgstr "E28: Uthevingsgruppe finnes ikke: %s"
+
+msgid "E29: No inserted text yet"
+msgstr "E29: Ingen innlagt tekst enda"
+
+msgid "E30: No previous command line"
+msgstr "E30: Ingen tidligere kommandolinje"
+
+msgid "E31: No such mapping"
+msgstr "E31: Mappingen finnes ikke"
+
+msgid "E479: No match"
+msgstr "E479: Ingen treff"
+
+#, c-format
+msgid "E480: No match: %s"
+msgstr "E480: Ingen treff: %s"
+
+msgid "E32: No file name"
+msgstr "E32: Mangler filnavn"
+
+msgid "E33: No previous substitute regular expression"
+msgstr "E33: Ingen tidligere erstatninger med regulære uttrykk"
+
+msgid "E34: No previous command"
+msgstr "E34: Ingen tidligere kommando"
+
+msgid "E35: No previous regular expression"
+msgstr "E35: Ingen tidligere regulære uttrykk"
+
+msgid "E481: No range allowed"
+msgstr "E481: Område er ikke tillatt"
+
+msgid "E36: Not enough room"
+msgstr "E36: Ikke nok plass"
+
+#, c-format
+msgid "E247: no registered server named \"%s\""
+msgstr "E247: Ingen registrert tjener kalt \"%s\""
+
+#, c-format
+msgid "E482: Can't create file %s"
+msgstr "E482: Kan ikke opprette filen %s"
+
+msgid "E483: Can't get temp file name"
+msgstr "E483: Kan ikke hente navn på midlertidig fil"
+
+#, c-format
+msgid "E484: Can't open file %s"
+msgstr "E484: Kan ikke åpne filen %s"
+
+#, c-format
+msgid "E485: Can't read file %s"
+msgstr "E485: Kan ikke lese filen %s"
+
+msgid "E37: No write since last change (add ! to override)"
+msgstr "E37: Ikke lagret siden forrige forandring (legg til ! for å overstyre)"
+
+msgid "E38: Null argument"
+msgstr "E38: Nullparameter"
+
+msgid "E39: Number expected"
+msgstr "E39: Nummer forventet"
+
+#, c-format
+msgid "E40: Can't open errorfile %s"
+msgstr "E40: Kan ikke åpne feilfilen %s"
+
+msgid "E233: cannot open display"
+msgstr "E233: Kan ikke åpne display"
+
+msgid "E41: Out of memory!"
+msgstr "E41: Ikke mer ledig hukommelse!"
+
+msgid "Pattern not found"
+msgstr "Fant ikke søketeksten"
+
+#, c-format
+msgid "E486: Pattern not found: %s"
+msgstr "E486: Fant ikke søketeksten: %s"
+
+msgid "E487: Argument must be positive"
+msgstr "E487: Parameteret må være positivt"
+
+msgid "E459: Cannot go back to previous directory"
+msgstr "E459: Kan ikke gå tilbake til tidligere katalog"
+
+msgid "E42: No Errors"
+msgstr "E42: Ingen feil"
+
+msgid "E776: No location list"
+msgstr "E776: Ingen plassliste"
+
+msgid "E43: Damaged match string"
+msgstr "E43: Ødelagt søkestreng"
+
+msgid "E44: Corrupted regexp program"
+msgstr "E44: Skadet program med regulært uttrykk"
+
+msgid "E45: 'readonly' option is set (add ! to override)"
+msgstr "E45: 'readonly'-valget er satt (legg til ! for å overstyre)"
+
+#, c-format
+msgid "E46: Cannot change read-only variable \"%s\""
+msgstr "E46: Kan ikke forandre skrivebeskyttet variabel \"%s\""
+
+#, c-format
+msgid "E794: Cannot set variable in the sandbox: \"%s\""
+msgstr "E794: Kan ikke sette variabel i sandkassen: \"%s\""
+
+msgid "E47: Error while reading errorfile"
+msgstr "E47: Feil under lesing av feilfilen"
+
+msgid "E48: Not allowed in sandbox"
+msgstr "E48: Ikke tillatt i sandkassen"
+
+msgid "E523: Not allowed here"
+msgstr "E523: Ikke tillatt her"
+
+msgid "E359: Screen mode setting not supported"
+msgstr "E359: Forandring av skjermmodus er ikke støttet"
+
+msgid "E49: Invalid scroll size"
+msgstr "E49: Ugyldig \"scroll\"-verdi"
+
+msgid "E91: 'shell' option is empty"
+msgstr "E91: 'shell'-valget er tomt"
+
+msgid "E255: Couldn't read in sign data!"
+msgstr "E255: Kunne ikke lese inn skiltdata!"
+
+msgid "E72: Close error on swap file"
+msgstr "E72: Feil under lukking av swapfil"
+
+msgid "E73: tag stack empty"
+msgstr "E73: Tag-stack tom"
+
+msgid "E74: Command too complex"
+msgstr "E74: Kommandoen er for kompleks"
+
+msgid "E75: Name too long"
+msgstr "E75: Navnet er for langt"
+
+msgid "E76: Too many ["
+msgstr "E76: For mange ["
+
+msgid "E77: Too many file names"
+msgstr "E77: For mange filnavn"
+
+msgid "E488: Trailing characters"
+msgstr "E488: Etterfølgende tegn"
+
+msgid "E78: Unknown mark"
+msgstr "E78: Ukjent merke"
+
+msgid "E79: Cannot expand wildcards"
+msgstr "E79: Klarte ikke utvide jokertegn"
+
+msgid "E591: 'winheight' cannot be smaller than 'winminheight'"
+msgstr "E591: 'winheight' kan ikke være mindre enn 'winminheight'"
+
+msgid "E592: 'winwidth' cannot be smaller than 'winminwidth'"
+msgstr "E592: 'winwidth' kan ikke være mindre enn 'winminwidth'"
+
+msgid "E80: Error while writing"
+msgstr "E80: Feil under skriving"
+
+msgid "Zero count"
+msgstr "Antall repeteringer er null"
+
+msgid "E81: Using <SID> not in a script context"
+msgstr "E81: Bruker <SID> utenom skript-kontekst"
+
+msgid "E449: Invalid expression received"
+msgstr "E449: Ugyldig uttrykk mottatt"
+
+msgid "E463: Region is guarded, cannot modify"
+msgstr "E463: Regionen er beskyttet og kan ikke modifiseres"
+
+msgid "E744: NetBeans does not allow changes in read-only files"
+msgstr "E744: NetBeans tillater ikke forandringer i skrivebeskyttede filer"
+
+#, c-format
+msgid "E685: Internal error: %s"
+msgstr "E685: Intern feil: %s"
+
+msgid "E363: pattern uses more memory than 'maxmempattern'"
+msgstr "E363: Søkestrengen bruker mer hukommelse enn 'maxmempattern'"
+
+msgid "E749: empty buffer"
+msgstr "E749: Tom buffer"
+
+msgid "E682: Invalid search pattern or delimiter"
+msgstr "E682: Ugyldig søkestreng eller skilletegn"
+
+msgid "E139: File is loaded in another buffer"
+msgstr "E139: Filen er lastet i en annen buffer"
+
+#, c-format
+msgid "E764: Option '%s' is not set"
+msgstr "E764: Valget '%s' er ikke satt"
+
+msgid "search hit TOP, continuing at BOTTOM"
+msgstr "Søket traff TOPPEN, fortsetter fra BUNNEN"
+
+msgid "search hit BOTTOM, continuing at TOP"
+msgstr "Søket traff BUNNEN, fortsetter fra TOPPEN"
diff --git a/src/po/pl.UTF-8.po b/src/po/pl.UTF-8.po
new file mode 100644
index 0000000..e28c888
--- /dev/null
+++ b/src/po/pl.UTF-8.po
@@ -0,0 +1,6904 @@
+# Polish translation for Vim
+#
+# updated 2013 for vim-7.4
+#
+# FIRST AUTHOR Marcin Dalecki <martin@dalecki.de>, 2000.
+# Mikolaj Machowski <mikmach@wp.pl>, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2013.
+msgid ""
+msgstr ""
+"Project-Id-Version: pl\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2013-07-06 19:33+0200\n"
+"PO-Revision-Date: 2010-08-10 18:15+0200\n"
+"Last-Translator: Mikolaj Machowski <mikmach@wp.pl>\n"
+"Language-Team: Polish\n"
+"Language: pl\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Lokalize 1.0\n"
+"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
+"|| n%100>=20) ? 1 : 2);\n"
+
+msgid "E831: bf_key_init() called with empty password"
+msgstr "E831: bf_key_init() wywołany z pustym hasłem"
+
+msgid "E820: sizeof(uint32_t) != 4"
+msgstr "E820: sizeof(uint32_t) != 4"
+
+msgid "E817: Blowfish big/little endian use wrong"
+msgstr "E817: Blowfish używa błędnej kolejności bajtów"
+
+msgid "E818: sha256 test failed"
+msgstr "E818: test sha256 nie powiódł się"
+
+msgid "E819: Blowfish test failed"
+msgstr "E819: test Blowfisha nie powiódł się"
+
+msgid "[Location List]"
+msgstr "[Lista lokacji]"
+
+msgid "[Quickfix List]"
+msgstr "[Lista quickfix]"
+
+msgid "E855: Autocommands caused command to abort"
+msgstr "E855: Autokomendy spowodowały porzucenie komendy"
+
+msgid "E82: Cannot allocate any buffer, exiting..."
+msgstr "E82: Nie mogę zarezerwować bufora; zakończenie..."
+
+msgid "E83: Cannot allocate buffer, using other one..."
+msgstr "E83: Nie mogę zarezerwować bufora; używam innego..."
+
+msgid "E515: No buffers were unloaded"
+msgstr "E515: Nie wyładowano żadnego bufora"
+
+msgid "E516: No buffers were deleted"
+msgstr "E516: Nie skasowano żadnego bufora"
+
+msgid "E517: No buffers were wiped out"
+msgstr "E517: Nie wyrzucono żadnego bufora"
+
+msgid "1 buffer unloaded"
+msgstr "1 bufor wyładowany"
+
+#, c-format
+msgid "%d buffers unloaded"
+msgstr "wyładowano %d buforów"
+
+msgid "1 buffer deleted"
+msgstr "1 bufor skasowany"
+
+#, c-format
+msgid "%d buffers deleted"
+msgstr "%d buforów skasowano"
+
+msgid "1 buffer wiped out"
+msgstr "wyrzucono 1 bufor "
+
+#, c-format
+msgid "%d buffers wiped out"
+msgstr "wyrzucono %d buforów"
+
+msgid "E84: No modified buffer found"
+msgstr "E84: Nie znaleziono zmienionych buforów"
+
+#. back where we started, didn't find anything.
+msgid "E85: There is no listed buffer"
+msgstr "E85: Nie ma wylistowanych buforów"
+
+#, c-format
+msgid "E86: Buffer %ld does not exist"
+msgstr "E86: Bufor \"%ld\" nie istnieje"
+
+msgid "E87: Cannot go beyond last buffer"
+msgstr "E87: Nie mogę przejść poza ostatni bufor"
+
+msgid "E88: Cannot go before first buffer"
+msgstr "E88: Nie mogę przejść przed pierwszy bufor"
+
+#, c-format
+msgid "E89: No write since last change for buffer %ld (add ! to override)"
+msgstr "E89: Nie zapisano zmian w buforze %ld (wymuÅ› przez !)"
+
+msgid "E90: Cannot unload last buffer"
+msgstr "E90: Nie mogę wyładować ostatniego bufora"
+
+msgid "W14: Warning: List of file names overflow"
+msgstr "W14: OSTRZEŻENIE: Przepełnienie listy nazw plików"
+
+#, c-format
+msgid "E92: Buffer %ld not found"
+msgstr "E92: Nie znaleziono bufora %ld"
+
+#, c-format
+msgid "E93: More than one match for %s"
+msgstr "E93: Wielokrotne dopasowania dla %s"
+
+#, c-format
+msgid "E94: No matching buffer for %s"
+msgstr "E94: Żaden bufor nie pasuje do %s"
+
+#, c-format
+msgid "line %ld"
+msgstr "wiersz %ld"
+
+msgid "E95: Buffer with this name already exists"
+msgstr "E95: Bufor o tej nazwie już istnieje"
+
+msgid " [Modified]"
+msgstr " [Zmieniony]"
+
+msgid "[Not edited]"
+msgstr "[Nie edytowany]"
+
+msgid "[New file]"
+msgstr "[Nowy Plik]"
+
+msgid "[Read errors]"
+msgstr "[BÅ‚Ä…d odczytu]"
+
+msgid "[RO]"
+msgstr "[RO]"
+
+msgid "[readonly]"
+msgstr "[tylko odczyt]"
+
+#, c-format
+msgid "1 line --%d%%--"
+msgstr "1 wiersz --%d%%--"
+
+#, c-format
+msgid "%ld lines --%d%%--"
+msgstr "%ld wiersze --%d%%--"
+
+#, c-format
+msgid "line %ld of %ld --%d%%-- col "
+msgstr "wiersz %ld z %ld --%d%%-- kol "
+
+msgid "[No Name]"
+msgstr "[Bez nazwy]"
+
+#. must be a help buffer
+msgid "help"
+msgstr "pomoc"
+
+msgid "[Help]"
+msgstr "[Pomoc]"
+
+msgid "[Preview]"
+msgstr "[PodglÄ…d]"
+
+msgid "All"
+msgstr "Wszystko"
+
+msgid "Bot"
+msgstr "Dół"
+
+msgid "Top"
+msgstr "Góra"
+
+msgid ""
+"\n"
+"# Buffer list:\n"
+msgstr ""
+"\n"
+"# Lista buforów:\n"
+
+msgid "[Scratch]"
+msgstr "[Notka]"
+
+msgid ""
+"\n"
+"--- Signs ---"
+msgstr ""
+"\n"
+"--- Znaki ---"
+
+#, c-format
+msgid "Signs for %s:"
+msgstr "Znaki dla %s:"
+
+#, c-format
+msgid " line=%ld id=%d name=%s"
+msgstr " wiersz=%ld id=%d nazwa=%s"
+
+#, c-format
+msgid "E96: Can not diff more than %ld buffers"
+msgstr "E96: Nie mogę zróżnicować więcej niż %ld buforów"
+
+msgid "E810: Cannot read or write temp files"
+msgstr "E810: Nie mogę otworzyć lub zapisać plików tymczasowych"
+
+msgid "E97: Cannot create diffs"
+msgstr "E97: Nie mogę stworzyć różnic"
+
+msgid "Patch file"
+msgstr "Plik Å‚ata"
+
+msgid "E816: Cannot read patch output"
+msgstr "E816: Nie mogę odczytać wyjścia pliku łaty"
+
+msgid "E98: Cannot read diff output"
+msgstr "E98: Nie mogę wczytać wyjścia różnicy"
+
+msgid "E99: Current buffer is not in diff mode"
+msgstr "E99: Bieżący bufor nie jest w trybie różnic"
+
+msgid "E793: No other buffer in diff mode is modifiable"
+msgstr "E793: Żaden inny bufor w trybie diff nie jest modyfikowalny"
+
+msgid "E100: No other buffer in diff mode"
+msgstr "E100: Brak innego bufora w trybie różnic"
+
+msgid "E101: More than two buffers in diff mode, don't know which one to use"
+msgstr ""
+"E101: Więcej niż jeden bufor w trybie różnicowania, nie wiem którego użyć"
+
+#, c-format
+msgid "E102: Can't find buffer \"%s\""
+msgstr "E102: Nie mogę znaleźć bufora \"%s\""
+
+#, c-format
+msgid "E103: Buffer \"%s\" is not in diff mode"
+msgstr "E103: Bufor \"%s\" nie jest w trybie różnicowania"
+
+msgid "E787: Buffer changed unexpectedly"
+msgstr "E787: Nieoczekiwana zmiana bufora"
+
+msgid "E104: Escape not allowed in digraph"
+msgstr "E104: Escape jest niedozwolone w dwugrafie"
+
+msgid "E544: Keymap file not found"
+msgstr "E544: Nie znaleziono pliku rozkładu klawiszy"
+
+msgid "E105: Using :loadkeymap not in a sourced file"
+msgstr "E105: Zastosowano :loadkeymap w niewczytanym pliku"
+
+msgid "E791: Empty keymap entry"
+msgstr "E791: Pusty wpis keymap"
+
+msgid " Keyword completion (^N^P)"
+msgstr " Dopełnianie słów kluczowych (^N^P)"
+
+#. ctrl_x_mode == 0, ^P/^N compl.
+msgid " ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+msgstr " ^X tryb (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+
+msgid " Whole line completion (^L^N^P)"
+msgstr " Dopełnianie pełnych wierszy (^L^N^P)"
+
+msgid " File name completion (^F^N^P)"
+msgstr " Dopełnianie nazw plików (^F^N^P)"
+
+msgid " Tag completion (^]^N^P)"
+msgstr " Dopełnianie znaczników (^]^N^P)"
+
+msgid " Path pattern completion (^N^P)"
+msgstr " Dopełnianie wzorców tropów (^N^P)"
+
+msgid " Definition completion (^D^N^P)"
+msgstr " Dopełnianie definicji (^D^N^P)"
+
+msgid " Dictionary completion (^K^N^P)"
+msgstr " Dopełnianie ze słowników (^K^N^P)"
+
+msgid " Thesaurus completion (^T^N^P)"
+msgstr " Dopełnianie z tezaurusa (^T^N^P)"
+
+msgid " Command-line completion (^V^N^P)"
+msgstr " Dopełnianie wiersza poleceń (^V^N^P)"
+
+msgid " User defined completion (^U^N^P)"
+msgstr "Dopełnianie zdefiniowane przez użytkownika (^U^N^P)"
+
+msgid " Omni completion (^O^N^P)"
+msgstr " Omni uzupełnianie (^O^N^P)"
+
+msgid " Spelling suggestion (s^N^P)"
+msgstr "Propozycja pisowni (^L^N^P)"
+
+msgid " Keyword Local completion (^N^P)"
+msgstr " Lokalne dopełnianie słów kluczowych (^N^P)"
+
+msgid "Hit end of paragraph"
+msgstr "Dobiłem do końca akapitu"
+
+msgid "E839: Completion function changed window"
+msgstr "E839: Funkcja uzupełniania zmieniła okno"
+
+msgid "E840: Completion function deleted text"
+msgstr "E840: Funkcja uzupełnania usunęła tekst"
+
+msgid "'dictionary' option is empty"
+msgstr "opcja 'dictionary' jest pusta"
+
+msgid "'thesaurus' option is empty"
+msgstr "opcja 'thesaurus' jest pusta"
+
+#, c-format
+msgid "Scanning dictionary: %s"
+msgstr "Przeglądam słownik: %s"
+
+msgid " (insert) Scroll (^E/^Y)"
+msgstr " (wprowadzanie) Przewijanie (^E/^Y)"
+
+msgid " (replace) Scroll (^E/^Y)"
+msgstr " (zamiana) Przewijanie (^E/^Y)"
+
+#, c-format
+msgid "Scanning: %s"
+msgstr "PrzeglÄ…dam: %s"
+
+msgid "Scanning tags."
+msgstr "PrzeglÄ…dam znaczniki."
+
+msgid " Adding"
+msgstr " DodajÄ™"
+
+#. showmode might reset the internal line pointers, so it must
+#. * be called before line = ml_get(), or when this address is no
+#. * longer needed. -- Acevedo.
+#.
+msgid "-- Searching..."
+msgstr "-- Szukam..."
+
+msgid "Back at original"
+msgstr "Z powrotem na pierwotnym"
+
+msgid "Word from other line"
+msgstr "Wyraz z innego wiersza"
+
+msgid "The only match"
+msgstr "Jedyne dopasowanie"
+
+#, c-format
+msgid "match %d of %d"
+msgstr "pasuje %d z %d"
+
+#, c-format
+msgid "match %d"
+msgstr "pasuje %d"
+
+msgid "E18: Unexpected characters in :let"
+msgstr "E18: Nieoczekiwane znaki w :let"
+
+#, c-format
+msgid "E684: list index out of range: %ld"
+msgstr "E684: Indeks listy poza zakresem: %ld"
+
+#, c-format
+msgid "E121: Undefined variable: %s"
+msgstr "E121: Nieokreślona zmienna: %s"
+
+msgid "E111: Missing ']'"
+msgstr "E111: Brak ']'"
+
+#, c-format
+msgid "E686: Argument of %s must be a List"
+msgstr "E686: Argument %s musi być Listą"
+
+#, c-format
+msgid "E712: Argument of %s must be a List or Dictionary"
+msgstr "E712: Argument %s musi być Listą lub Słownikiem"
+
+msgid "E713: Cannot use empty key for Dictionary"
+msgstr "E713: Nie można użyć pustego klucza dla Słownika"
+
+msgid "E714: List required"
+msgstr "E714: wymagana Lista"
+
+msgid "E715: Dictionary required"
+msgstr "E715: wymagany SÅ‚ownik"
+
+#, c-format
+msgid "E118: Too many arguments for function: %s"
+msgstr "E118: Zbyt wiele argumentów dla funkcji: %s"
+
+#, c-format
+msgid "E716: Key not present in Dictionary: %s"
+msgstr "E716: Klucz nie istnieje w SÅ‚owniku: %s"
+
+#, c-format
+msgid "E122: Function %s already exists, add ! to replace it"
+msgstr "E122: Funkcja %s już istnieje; aby ją zamienić użyj !"
+
+msgid "E717: Dictionary entry already exists"
+msgstr "E717: istnieje już taki element Słownika"
+
+msgid "E718: Funcref required"
+msgstr "E718: wymagana Funcref"
+
+msgid "E719: Cannot use [:] with a Dictionary"
+msgstr "E719: Nie można użyć [:] przy Słowniku"
+
+#, c-format
+msgid "E734: Wrong variable type for %s="
+msgstr "E734: ZÅ‚y typ zmiennej dla %s="
+
+#, c-format
+msgid "E130: Unknown function: %s"
+msgstr "E130: Nieznana funkcja: %s"
+
+#, c-format
+msgid "E461: Illegal variable name: %s"
+msgstr "E461: Niedozwolona nazwa zmiennej: %s"
+
+msgid "E806: using Float as a String"
+msgstr "E806: Użycie Zmiennoprzecinkowej jako ÅaÅ„cucha"
+
+msgid "E687: Less targets than List items"
+msgstr "E687: Mniej celów niż elementów Listy"
+
+msgid "E688: More targets than List items"
+msgstr "E688: Więcej celów niż elementów Listy"
+
+msgid "Double ; in list of variables"
+msgstr "Podwójny ; w liście zmiennych"
+
+#, c-format
+msgid "E738: Can't list variables for %s"
+msgstr "E738: Nie mogę wypisać zmiennych dla %s"
+
+msgid "E689: Can only index a List or Dictionary"
+msgstr "E689: Indeks może istnieć tylko dla Listy lub Słownika"
+
+msgid "E708: [:] must come last"
+msgstr "E708: [:] musi być ostatnie"
+
+msgid "E709: [:] requires a List value"
+msgstr "E709: [:] wymaga wartości listy"
+
+msgid "E710: List value has more items than target"
+msgstr "E710: Lista ma więcej elementów niż cel"
+
+msgid "E711: List value has not enough items"
+msgstr "E711: Lista nie ma wystarczającej ilości elementów"
+
+msgid "E690: Missing \"in\" after :for"
+msgstr "E690: Brak \"in\" po :for"
+
+#, c-format
+msgid "E107: Missing parentheses: %s"
+msgstr "E107: Brak nawiasów: %s"
+
+#, c-format
+msgid "E108: No such variable: \"%s\""
+msgstr "E108: Nie istnieje zmienna: \"%s\""
+
+msgid "E743: variable nested too deep for (un)lock"
+msgstr "E743: zmienna zagnieżdżona zbyt głęboko dla (un)lock"
+
+msgid "E109: Missing ':' after '?'"
+msgstr "E109: Brak ':' po '?'"
+
+msgid "E691: Can only compare List with List"
+msgstr "E691: Listę mogę porównać tylko z Listą"
+
+msgid "E692: Invalid operation for List"
+msgstr "E692: Nieprawidłowa operacja dla Listy"
+
+msgid "E735: Can only compare Dictionary with Dictionary"
+msgstr "E735: Słownik mogę porównać tylko ze Słownikiem"
+
+msgid "E736: Invalid operation for Dictionary"
+msgstr "E736: Nieprawidłowa operacja dla Słownika"
+
+msgid "E693: Can only compare Funcref with Funcref"
+msgstr "E693: Funcref mogę porównać tylko z Funcref"
+
+msgid "E694: Invalid operation for Funcrefs"
+msgstr "E694: Nieprawidłowa operacja dla Funcref"
+
+msgid "E804: Cannot use '%' with Float"
+msgstr "E804: Nie mogę użyć '%' w Zmiennoprzecinkowej"
+
+msgid "E110: Missing ')'"
+msgstr "E110: Brak ')'"
+
+msgid "E695: Cannot index a Funcref"
+msgstr "E695: Nie można zindeksować Funcref"
+
+#, c-format
+msgid "E112: Option name missing: %s"
+msgstr "E112: Brak nazwy opcji: %s"
+
+#, c-format
+msgid "E113: Unknown option: %s"
+msgstr "E113: Nieznana opcja: %s"
+
+#, c-format
+msgid "E114: Missing quote: %s"
+msgstr "E114: Brak cudzysłowu: %s"
+
+#, c-format
+msgid "E115: Missing quote: %s"
+msgstr "E115: Brak cudzysłowu: %s"
+
+#, c-format
+msgid "E696: Missing comma in List: %s"
+msgstr "E696: Brakujący przecinek w Liście: '%s"
+
+#, c-format
+msgid "E697: Missing end of List ']': %s"
+msgstr "E697: Brak zakończenia Listy ']': %s"
+
+#, c-format
+msgid "E720: Missing colon in Dictionary: %s"
+msgstr "E720: Brak dwukropka w SÅ‚owniku: %s"
+
+#, c-format
+msgid "E721: Duplicate key in Dictionary: \"%s\""
+msgstr "E721: Powtórzony klucz w Słowniku: \"%s\""
+
+#, c-format
+msgid "E722: Missing comma in Dictionary: %s"
+msgstr "E722: BrakujÄ…cy przecinek w SÅ‚owniku: %s"
+
+#, c-format
+msgid "E723: Missing end of Dictionary '}': %s"
+msgstr "E723: Brak końca w Słowniku '}': %s"
+
+msgid "E724: variable nested too deep for displaying"
+msgstr "E724: Zmienna zagnieżdżona zbyt głęboko by pokazać"
+
+#, c-format
+msgid "E740: Too many arguments for function %s"
+msgstr "E740: Zbyt wiele argumentów dla funkcji %s"
+
+#, c-format
+msgid "E116: Invalid arguments for function %s"
+msgstr "E116: Zbyt wiele argumentów dla funkcji %s"
+
+#, c-format
+msgid "E117: Unknown function: %s"
+msgstr "E117: Nieznana funkcja: %s"
+
+#, c-format
+msgid "E119: Not enough arguments for function: %s"
+msgstr "E119: Za mało argumentów dla funkcji: %s"
+
+#, c-format
+msgid "E120: Using <SID> not in a script context: %s"
+msgstr "E120: Użycie <SID> poza kontekstem skryptu: %s"
+
+#, c-format
+msgid "E725: Calling dict function without Dictionary: %s"
+msgstr "E725: Wywołanie funkcji \"dict\" bez Słownika: %s"
+
+msgid "E808: Number or Float required"
+msgstr "E808: Wymagana Liczba lub Zmiennoprzecinkowa"
+
+msgid "add() argument"
+msgstr "argument add()"
+
+msgid "E699: Too many arguments"
+msgstr "E699: Za dużo argumentów"
+
+msgid "E785: complete() can only be used in Insert mode"
+msgstr "E785: complete() może być użyte tylko w trybie Wprowadzania"
+
+#.
+#. * Yes this is ugly, I don't particularly like it either. But doing it
+#. * this way has the compelling advantage that translations need not to
+#. * be touched at all. See below what 'ok' and 'ync' are used for.
+#.
+msgid "&Ok"
+msgstr "&Ok"
+
+#, c-format
+msgid "E737: Key already exists: %s"
+msgstr "E737: Klucz już istnieje: %s"
+
+msgid "extend() argument"
+msgstr "argument extend()"
+
+msgid "map() argument"
+msgstr "argument map()"
+
+msgid "filter() argument"
+msgstr "argument filter()"
+
+#, c-format
+msgid "+-%s%3ld lines: "
+msgstr "+-%s%3ld wierszy: "
+
+#, c-format
+msgid "E700: Unknown function: %s"
+msgstr "E700: Nieznana funkcja: %s"
+
+msgid ""
+"&OK\n"
+"&Cancel"
+msgstr ""
+"&OK\n"
+"&Zakończ"
+
+msgid "called inputrestore() more often than inputsave()"
+msgstr "wywołano inputrestore() więcej razy niż inputsave()"
+
+msgid "insert() argument"
+msgstr "argument insert()"
+
+msgid "E786: Range not allowed"
+msgstr "E786: Zakres niedozwolony"
+
+msgid "E701: Invalid type for len()"
+msgstr "E701: Nieprawidłowy typ dla len()"
+
+msgid "E726: Stride is zero"
+msgstr "E726: Skok to zero"
+
+msgid "E727: Start past end"
+msgstr "E727: Początek po końcu"
+
+msgid "<empty>"
+msgstr "<pusty>"
+
+msgid "E240: No connection to Vim server"
+msgstr "E240: Brak połączenia z serwerem Vim"
+
+#, c-format
+msgid "E241: Unable to send to %s"
+msgstr "E241: Nie mogę wysłać do %s"
+
+msgid "E277: Unable to read a server reply"
+msgstr "E277: Nie mogę czytać odpowiedzi serwera"
+
+msgid "remove() argument"
+msgstr "argument remove()"
+
+msgid "E655: Too many symbolic links (cycle?)"
+msgstr "E655: Za dużo dowiązań symbolicznych (pętla?)"
+
+msgid "reverse() argument"
+msgstr "argument reverse()"
+
+msgid "E258: Unable to send to client"
+msgstr "E258: Nie mogę wysłać do klienta"
+
+msgid "sort() argument"
+msgstr "argument sort()"
+
+msgid "E702: Sort compare function failed"
+msgstr "E702: Funkcja porównywania w sort nie powiodła się"
+
+msgid "(Invalid)"
+msgstr "(Niewłaściwe)"
+
+msgid "E677: Error writing temp file"
+msgstr "E677: BÅ‚Ä…d zapisywania pliku tymczasowego"
+
+msgid "E805: Using a Float as a Number"
+msgstr "E805: Użycie Zmiennoprzecinkowej jako Liczby"
+
+msgid "E703: Using a Funcref as a Number"
+msgstr "E703: Użycie Funcref jako Liczby"
+
+msgid "E745: Using a List as a Number"
+msgstr "E745: Użycie Listy jako Liczby"
+
+msgid "E728: Using a Dictionary as a Number"
+msgstr "E728: Użycie Słownika jako Liczby"
+
+msgid "E729: using Funcref as a String"
+msgstr "E729: Użycie Funcref jako ÅaÅ„cucha"
+
+msgid "E730: using List as a String"
+msgstr "E730: Użycie Listy jako ÅaÅ„cucha"
+
+msgid "E731: using Dictionary as a String"
+msgstr "E731: Użycie SÅ‚ownika jako ÅaÅ„cucha"
+
+#, c-format
+msgid "E706: Variable type mismatch for: %s"
+msgstr "E706: Nieprawidłowy typ zmiennej dla: %s"
+
+#, c-format
+msgid "E795: Cannot delete variable %s"
+msgstr "E795: Nie mogę usunąć zmiennej %s"
+
+#, c-format
+msgid "E704: Funcref variable name must start with a capital: %s"
+msgstr "E704: Nazwa Funcref musi się zaczynać wielką literą: %s"
+
+#, c-format
+msgid "E705: Variable name conflicts with existing function: %s"
+msgstr "E705: Nazwa zmiennej jest w konflikcie z istniejÄ…cÄ… funkcjÄ…: %s"
+
+#, c-format
+msgid "E741: Value is locked: %s"
+msgstr "E741: Wartość jest zablokowana: %s"
+
+msgid "Unknown"
+msgstr "Nieznane"
+
+#, c-format
+msgid "E742: Cannot change value of %s"
+msgstr "E742: Nie mogę zmienić wartości %s"
+
+msgid "E698: variable nested too deep for making a copy"
+msgstr "E698: Zmienna zagnieżdżona zbyt głęboko by zrobić kopię"
+
+#, c-format
+msgid "E123: Undefined function: %s"
+msgstr "E123: Nieznana funkcja: %s"
+
+#, c-format
+msgid "E124: Missing '(': %s"
+msgstr "E124: Brak '(': %s"
+
+msgid "E862: Cannot use g: here"
+msgstr "E862: Nie można tutaj użyć g:"
+
+#, c-format
+msgid "E125: Illegal argument: %s"
+msgstr "E125: Niedozwolony argument: %s"
+
+#, c-format
+msgid "E853: Duplicate argument name: %s"
+msgstr "E853: Powtórzona nazwa argumentu: %s"
+
+msgid "E126: Missing :endfunction"
+msgstr "E126: Brak :endfunction"
+
+#, c-format
+msgid "E707: Function name conflicts with variable: %s"
+msgstr "E707: Nazwa funkcji jest w konflikcie ze zmiennÄ…: %s"
+
+#, c-format
+msgid "E127: Cannot redefine function %s: It is in use"
+msgstr "E127: Nie mogę redefiniować funkcji %s: jest w użyciu"
+
+#, c-format
+msgid "E746: Function name does not match script file name: %s"
+msgstr "E746: Nazwa funkcji nie pasuje do nazwy skryptu: %s"
+
+msgid "E129: Function name required"
+msgstr "E129: Wymagana jest nazwa funkcji"
+
+#, c-format
+msgid "E128: Function name must start with a capital or contain a colon: %s"
+msgstr ""
+"E128: Nazwa funkcji musi rozpoczynać się wielką literą lub zawierać "
+"dwukropek: %s"
+
+#, c-format
+msgid "E131: Cannot delete function %s: It is in use"
+msgstr "E131: Nie mogę skasować funkcji %s: jest w użyciu"
+
+msgid "E132: Function call depth is higher than 'maxfuncdepth'"
+msgstr "E132: Zagnieżdżenie wywołań funkcji ponad 'maxfuncdepth'"
+
+#, c-format
+msgid "calling %s"
+msgstr "wywołuję %s"
+
+#, c-format
+msgid "%s aborted"
+msgstr "porzucono %s"
+
+#, c-format
+msgid "%s returning #%ld"
+msgstr "%s zwraca #%ld"
+
+#, c-format
+msgid "%s returning %s"
+msgstr "%s zwraca %s"
+
+#, c-format
+msgid "continuing in %s"
+msgstr "kontynuacja w %s"
+
+msgid "E133: :return not inside a function"
+msgstr "E133: :return poza funkcjÄ…"
+
+msgid ""
+"\n"
+"# global variables:\n"
+msgstr ""
+"\n"
+"# zmienne globalne:\n"
+
+msgid ""
+"\n"
+"\tLast set from "
+msgstr ""
+"\n"
+"\tOstatnie ustawienie przez "
+
+msgid "No old files"
+msgstr "Brak starych plików"
+
+msgid "Entering Debug mode. Type \"cont\" to continue."
+msgstr "Wchodzę w tryb odpluskwiania. Wprowadź \"cont\" aby kontynuować."
+
+#, c-format
+msgid "line %ld: %s"
+msgstr "wiersz %ld: %s"
+
+#, c-format
+msgid "cmd: %s"
+msgstr "cmd: %s"
+
+#, c-format
+msgid "Breakpoint in \"%s%s\" line %ld"
+msgstr "Punkt kontrolny w \"%s%s\" wiersz %ld"
+
+#, c-format
+msgid "E161: Breakpoint not found: %s"
+msgstr "E161: Nie znaleziono punktu kontrolnego: %s"
+
+msgid "No breakpoints defined"
+msgstr "Nie określono żadnych punktów kontrolnych"
+
+#, c-format
+msgid "%3d %s %s line %ld"
+msgstr "%3d %s %s wiersz %ld"
+
+msgid "E750: First use \":profile start {fname}\""
+msgstr "E750: Pierwsze użycie \":profile start {fname}\""
+
+msgid "Save As"
+msgstr "Zapisz jako"
+
+#, c-format
+msgid "Save changes to \"%s\"?"
+msgstr "Zachować zmiany w \"%s\"?"
+
+msgid "Untitled"
+msgstr "Bez Tytułu"
+
+#, c-format
+msgid "E162: No write since last change for buffer \"%s\""
+msgstr "E162: Nie zapisano zmian w buforze \"%s\""
+
+msgid "Warning: Entered other buffer unexpectedly (check autocommands)"
+msgstr "OSTRZEŻENIE: Nieoczekiwane wejście w inny bufor (sprawdź autokomendy)"
+
+msgid "E163: There is only one file to edit"
+msgstr "E163: Tylko jeden plik w edycji"
+
+msgid "E164: Cannot go before first file"
+msgstr "E164: Nie można przejść przed pierwszy plik"
+
+msgid "E165: Cannot go beyond last file"
+msgstr "E165: Nie można przejść za ostatni plik"
+
+#, c-format
+msgid "E666: compiler not supported: %s"
+msgstr "E666: nie wspierany kompilator: %s"
+
+#, c-format
+msgid "Searching for \"%s\" in \"%s\""
+msgstr "Szukanie \"%s\" w \"%s\""
+
+#, c-format
+msgid "Searching for \"%s\""
+msgstr "Szukanie \"%s\""
+
+#, c-format
+msgid "not found in 'runtimepath': \"%s\""
+msgstr "nie znaleziono w 'runtimepath': \"%s\""
+
+msgid "Source Vim script"
+msgstr "Wczytaj skrypt Vima"
+
+#, c-format
+msgid "Cannot source a directory: \"%s\""
+msgstr "Nie można wczytać katalogu: \"%s\""
+
+#, c-format
+msgid "could not source \"%s\""
+msgstr "nie mogłem wczytać \"%s\""
+
+#, c-format
+msgid "line %ld: could not source \"%s\""
+msgstr "wiersz: %ld nie mogłem wczytać \"%s\""
+
+#, c-format
+msgid "sourcing \"%s\""
+msgstr "wczytywanie \"%s\""
+
+#, c-format
+msgid "line %ld: sourcing \"%s\""
+msgstr "wiersz %ld: wczytywanie \"%s\""
+
+#, c-format
+msgid "finished sourcing %s"
+msgstr "skończono wczytywanie %s"
+
+msgid "modeline"
+msgstr "modeline"
+
+msgid "--cmd argument"
+msgstr "--cmd argument"
+
+msgid "-c argument"
+msgstr "-c argument"
+
+msgid "environment variable"
+msgstr "zmienna środowiskowa"
+
+msgid "error handler"
+msgstr "obsługa błędu"
+
+msgid "W15: Warning: Wrong line separator, ^M may be missing"
+msgstr "W15: OSTRZEŻENIE: Niewłaściwy separator wierszy, pewnie brak ^M"
+
+msgid "E167: :scriptencoding used outside of a sourced file"
+msgstr "E167: użyto :scriptencoding poza wczytywanym plikiem"
+
+msgid "E168: :finish used outside of a sourced file"
+msgstr "E168: użyto :finish poza wczytywanym plikiem"
+
+#, c-format
+msgid "Current %slanguage: \"%s\""
+msgstr "Bieżący %sjęzyk: \"%s\""
+
+#, c-format
+msgid "E197: Cannot set language to \"%s\""
+msgstr "E197: Nie mogę ustawić języka na \"%s\""
+
+#, c-format
+msgid "<%s>%s%s %d, Hex %02x, Octal %03o"
+msgstr "<%s>%s%s %d, Hex %02x, Oktal %03o"
+
+#, c-format
+msgid "> %d, Hex %04x, Octal %o"
+msgstr "> %d, Hex %04x, Oktal %o"
+
+#, c-format
+msgid "> %d, Hex %08x, Octal %o"
+msgstr "> %d, Hex %08x, Oktal %o"
+
+msgid "E134: Move lines into themselves"
+msgstr "E134: Przeniesienie wierszy na siebie samych"
+
+msgid "1 line moved"
+msgstr "1 wiersz przeniesiony"
+
+#, c-format
+msgid "%ld lines moved"
+msgstr "%ld wiersze przeniesione"
+
+#, c-format
+msgid "%ld lines filtered"
+msgstr "%ld wierszy przefiltrowanych"
+
+msgid "E135: *Filter* Autocommands must not change current buffer"
+msgstr "E135: Autokomendy *Filter* nie mogą zmieniać bieżącego bufora"
+
+msgid "[No write since last change]\n"
+msgstr "[Brak zapisu od czasu ostatniej zmiany]\n"
+
+#, c-format
+msgid "%sviminfo: %s in line: "
+msgstr "%sviminfo: %s w wierszu: "
+
+msgid "E136: viminfo: Too many errors, skipping rest of file"
+msgstr "E136: viminfo: Zbyt wiele błędów; pomijam resztę pliku"
+
+#, c-format
+msgid "Reading viminfo file \"%s\"%s%s%s"
+msgstr "WczytujÄ™ plik viminfo \"%s\"%s%s%s"
+
+msgid " info"
+msgstr " informacja"
+
+msgid " marks"
+msgstr " zakładki"
+
+msgid " oldfiles"
+msgstr " stare pliki"
+
+msgid " FAILED"
+msgstr " NIE POWIODÅO SIĘ"
+
+#. avoid a wait_return for this message, it's annoying
+#, c-format
+msgid "E137: Viminfo file is not writable: %s"
+msgstr "E137: Plik viminfo jest niezapisywalny: %s"
+
+#, c-format
+msgid "E138: Can't write viminfo file %s!"
+msgstr "E138: Nie mogę zapisać pliku viminfo %s!"
+
+#, c-format
+msgid "Writing viminfo file \"%s\""
+msgstr "ZapisujÄ™ plik viminfo \"%s\""
+
+#. Write the info:
+#, c-format
+msgid "# This viminfo file was generated by Vim %s.\n"
+msgstr "# Ten plik viminfo został wygenerowany przez Vima %s.\n"
+
+msgid ""
+"# You may edit it if you're careful!\n"
+"\n"
+msgstr ""
+"# Możesz go ostrożnie edytować!\n"
+"\n"
+
+msgid "# Value of 'encoding' when this file was written\n"
+msgstr "# Wartość 'encoding' w czasie zapisu tego pliku\n"
+
+msgid "Illegal starting char"
+msgstr "Niedopuszczalny poczÄ…tkowy znak"
+
+msgid "Write partial file?"
+msgstr "Zapisać częściowo plik?"
+
+msgid "E140: Use ! to write partial buffer"
+msgstr "E140: Stosuj ! do zapisania częściowo bufora"
+
+#, c-format
+msgid "Overwrite existing file \"%s\"?"
+msgstr "Nadpisać istniejący plik \"%s\"?"
+
+#, c-format
+msgid "Swap file \"%s\" exists, overwrite anyway?"
+msgstr "Plik wymiany \"%s\" istnieje, czy go nadpisać?"
+
+#, c-format
+msgid "E768: Swap file exists: %s (:silent! overrides)"
+msgstr "E768: Plik wymiany istnieje: %s (wymuÅ› poprzez :silent!)"
+
+#, c-format
+msgid "E141: No file name for buffer %ld"
+msgstr "E141: Brak nazwy pliku dla bufora %ld"
+
+msgid "E142: File not written: Writing is disabled by 'write' option"
+msgstr "E142: Plik niezapisany: Zapis jest wyłączony opcją 'write'"
+
+#, c-format
+msgid ""
+"'readonly' option is set for \"%s\".\n"
+"Do you wish to write anyway?"
+msgstr ""
+"opcja 'readonly' nastawiona dla \"%s\".\n"
+"Czy chcesz go pomimo tego zapisać?"
+
+#, c-format
+msgid ""
+"File permissions of \"%s\" are read-only.\n"
+"It may still be possible to write it.\n"
+"Do you wish to try?"
+msgstr ""
+"Prawa pliku \"%s\" sÄ… tylko do odczytu.\n"
+"Mimo to być może uda się zmienić ten plik.\n"
+"Chcesz spróbować?"
+
+#, c-format
+msgid "E505: \"%s\" is read-only (add ! to override)"
+msgstr "E505: \"%s\" jest tylko do odczytu (dodaj ! aby wymusić)"
+
+msgid "Edit File"
+msgstr "Edytuj Plik"
+
+#, c-format
+msgid "E143: Autocommands unexpectedly deleted new buffer %s"
+msgstr "E143: Autokomendy nieoczekiwanie skasowały nowy bufor %s"
+
+msgid "E144: non-numeric argument to :z"
+msgstr "E144: nienumeryczny argument dla :z"
+
+msgid "E145: Shell commands not allowed in rvim"
+msgstr "E145: Komendy powłoki są niedozwolone w rvim"
+
+msgid "E146: Regular expressions can't be delimited by letters"
+msgstr "E146: Wzorce regularne nie mogą być rozgraniczane literami"
+
+#, c-format
+msgid "replace with %s (y/n/a/q/l/^E/^Y)?"
+msgstr "zamień na %s (y/n/a/q/l/^E/^Y)?"
+
+msgid "(Interrupted) "
+msgstr "(Przerwane) "
+
+msgid "1 match"
+msgstr "1 pasuje"
+
+msgid "1 substitution"
+msgstr "1 podstawienie "
+
+#, c-format
+msgid "%ld matches"
+msgstr "%ld dopasowań"
+
+#, c-format
+msgid "%ld substitutions"
+msgstr "%ld podstawień"
+
+msgid " on 1 line"
+msgstr " w 1 wierszu"
+
+#, c-format
+msgid " on %ld lines"
+msgstr " w %ld wierszach"
+
+msgid "E147: Cannot do :global recursive"
+msgstr "E147: Nie mogę wykonać :global rekursywnie"
+
+msgid "E148: Regular expression missing from global"
+msgstr "E148: Brak wzorca regularnego w :global"
+
+# c-format
+#, c-format
+msgid "Pattern found in every line: %s"
+msgstr "Wzorzec znaleziono w każdym wierszu: %s"
+
+#, c-format
+msgid "Pattern not found: %s"
+msgstr "Nie znaleziono wzorca: %s"
+
+msgid ""
+"\n"
+"# Last Substitute String:\n"
+"$"
+msgstr ""
+"\n"
+"# Ostatni podstawiany ciÄ…g:\n"
+"$"
+
+msgid "E478: Don't panic!"
+msgstr "E478: Nie panikuj!"
+
+#, c-format
+msgid "E661: Sorry, no '%s' help for %s"
+msgstr "E661: Przykro mi, brak '%s' pomocy dla %s"
+
+#, c-format
+msgid "E149: Sorry, no help for %s"
+msgstr "E149: Przykro mi, ale brak pomocy o %s"
+
+#, c-format
+msgid "Sorry, help file \"%s\" not found"
+msgstr "Przykro mi, nie ma pliku pomocy \"%s\""
+
+#, c-format
+msgid "E150: Not a directory: %s"
+msgstr "E150: Nie jest katalogiem: %s"
+
+#, c-format
+msgid "E152: Cannot open %s for writing"
+msgstr "E152: Nie mogę otworzyć %s do zapisu"
+
+#, c-format
+msgid "E153: Unable to open %s for reading"
+msgstr "E153: Nie mogę otworzyć %s do odczytu"
+
+#, c-format
+msgid "E670: Mix of help file encodings within a language: %s"
+msgstr "E670: Mieszanka kodowań w pliku pomocy w ramach języka: %s"
+
+#, c-format
+msgid "E154: Duplicate tag \"%s\" in file %s/%s"
+msgstr "E154: Powtórzony znacznik \"%s\" w pliku %s/%s"
+
+#, c-format
+msgid "E160: Unknown sign command: %s"
+msgstr "E160: Nieznana komenda znaku: %s"
+
+msgid "E156: Missing sign name"
+msgstr "E156: Brak nazwy znaku"
+
+msgid "E612: Too many signs defined"
+msgstr "E612: Zbyt wiele nazw znaków"
+
+#, c-format
+msgid "E239: Invalid sign text: %s"
+msgstr "E239: Niewłaściwy tekst znaku: %s"
+
+#, c-format
+msgid "E155: Unknown sign: %s"
+msgstr "E155: Nieznany znak: %s"
+
+msgid "E159: Missing sign number"
+msgstr "E159: Brak numeru znaku"
+
+#, c-format
+msgid "E158: Invalid buffer name: %s"
+msgstr "E158: Niewłaściwa nazwa bufora: %s"
+
+#, c-format
+msgid "E157: Invalid sign ID: %ld"
+msgstr "E157: Niewłaściwe ID znaku: %ld"
+
+msgid " (NOT FOUND)"
+msgstr " (NIE ZNALEZIONO)"
+
+msgid " (not supported)"
+msgstr "(nie wspomagane)"
+
+msgid "[Deleted]"
+msgstr "[Skasowano]"
+
+msgid "Entering Ex mode. Type \"visual\" to go to Normal mode."
+msgstr "Wchodzę w tryb Ex. Wprowadź \"visual\" aby przejść do trybu Normal."
+
+msgid "E501: At end-of-file"
+msgstr "E501: Na końcu pliku"
+
+msgid "E169: Command too recursive"
+msgstr "E169: Komenda zbyt rekursywna"
+
+#, c-format
+msgid "E605: Exception not caught: %s"
+msgstr "E605: Nie znaleziono wyjÄ…tku: %s"
+
+msgid "End of sourced file"
+msgstr "Koniec wczytywanego pliku"
+
+msgid "End of function"
+msgstr "Koniec funkcji"
+
+msgid "E464: Ambiguous use of user-defined command"
+msgstr ""
+"E464: Niejednoznaczne zastosowanie komendy zdefiniowanej przez użytkownika"
+
+msgid "E492: Not an editor command"
+msgstr "E492: Nie jest komendÄ… edytora"
+
+msgid "E493: Backwards range given"
+msgstr "E493: Dano wsteczny zakres"
+
+msgid "Backwards range given, OK to swap"
+msgstr "Dano wsteczny zakres; zamiana jest możliwa"
+
+msgid "E494: Use w or w>>"
+msgstr "E494: Stosuj w lub w>>"
+
+msgid "E319: Sorry, the command is not available in this version"
+msgstr "E319: Przykro mi, ale ta komenda nie jest dostępna w tej wersji"
+
+msgid "E172: Only one file name allowed"
+msgstr "E172: Tylko pojedyncza nazwa pliku dozwolona"
+
+msgid "1 more file to edit. Quit anyway?"
+msgstr "1 więcej plik do edycji. Mimo to wyjść?"
+
+#, c-format
+msgid "%d more files to edit. Quit anyway?"
+msgstr "jeszcze %d plików do edycji. Mimo to wyjść?"
+
+msgid "E173: 1 more file to edit"
+msgstr "E173: 1 więcej plik do edycji"
+
+#, c-format
+msgid "E173: %ld more files to edit"
+msgstr "E173: jeszcze %ld plików do edycji"
+
+msgid "E174: Command already exists: add ! to replace it"
+msgstr "E174: Komenda już istnieje; aby ją przedefiniować stosuj !"
+
+msgid ""
+"\n"
+" Name Args Range Complete Definition"
+msgstr ""
+"\n"
+" Nazwa Arg. Zak. Gotowość Definicja"
+
+msgid "No user-defined commands found"
+msgstr "Nie znaleziono komend zdefiniowanych przez użytkownika"
+
+msgid "E175: No attribute specified"
+msgstr "E175: Nie określono atrybutu"
+
+msgid "E176: Invalid number of arguments"
+msgstr "E176: Niewłaściwa ilość argumentów"
+
+msgid "E177: Count cannot be specified twice"
+msgstr "E177: Mnożnik nie może być podany dwukrotnie"
+
+msgid "E178: Invalid default value for count"
+msgstr "E178: Niewłaściwa domyślna wartość mnożnika"
+
+msgid "E179: argument required for -complete"
+msgstr "E179: -complete wymaga argumentu"
+
+#, c-format
+msgid "E181: Invalid attribute: %s"
+msgstr "E181: Niewłaściwy atrybut: %s"
+
+msgid "E182: Invalid command name"
+msgstr "E182: Niewłaściwa nazwa komendy"
+
+msgid "E183: User defined commands must start with an uppercase letter"
+msgstr ""
+"E183: Komendy zdefiniowane przez użytkownika muszą rozpoczynać się dużą "
+"literÄ…"
+
+msgid "E841: Reserved name, cannot be used for user defined command"
+msgstr ""
+"E841: Nazwa zastrzeżona, nie można jej użyć w komendzie użytkownika"
+
+#, c-format
+msgid "E184: No such user-defined command: %s"
+msgstr "E184: Nie ma takiej komendy użytkownika: %s"
+
+#, c-format
+msgid "E180: Invalid complete value: %s"
+msgstr "E180: Niewłaściwa wartość dopełniania: %s"
+
+msgid "E468: Completion argument only allowed for custom completion"
+msgstr ""
+"E468: Argument depełniania dozwolony wyłącznie dla dopełniania użytkownika"
+
+msgid "E467: Custom completion requires a function argument"
+msgstr "E467: Dopełnianie użytkownika wymaga funkcji jako argumentu"
+
+msgid "unknown"
+msgstr "nieznany"
+
+#, c-format
+msgid "E185: Cannot find color scheme '%s'"
+msgstr "E185: Nie mogę znaleźć zestawu kolorów '%s'"
+
+msgid "Greetings, Vim user!"
+msgstr "Witaj użytkowniku Vima!"
+
+msgid "E784: Cannot close last tab page"
+msgstr "E784: Nie mogę zamknąć ostatniej karty"
+
+msgid "Already only one tab page"
+msgstr "Jest już tylko jedna karta"
+
+msgid "Edit File in new window"
+msgstr "Edytuj plik w nowym oknie"
+
+#, c-format
+msgid "Tab page %d"
+msgstr "Karta %d"
+
+msgid "No swap file"
+msgstr "Brak pliku wymiany"
+
+msgid "Append File"
+msgstr "Dołącz plik"
+
+msgid "E747: Cannot change directory, buffer is modified (add ! to override)"
+msgstr ""
+"E747: Nie mogę zmienić katalogu, bufor został zmodyfikowany (dodaj ! aby "
+"wymusić)"
+
+msgid "E186: No previous directory"
+msgstr "E186: Nie ma poprzedniego katalogu"
+
+msgid "E187: Unknown"
+msgstr "E187: Nieznany"
+
+msgid "E465: :winsize requires two number arguments"
+msgstr "E465: :winsize wymaga dwóch argumentów numerycznych"
+
+#, c-format
+msgid "Window position: X %d, Y %d"
+msgstr "Pozycja okna: X %d, Y %d"
+
+msgid "E188: Obtaining window position not implemented for this platform"
+msgstr ""
+"E188: Pozyskiwanie pozycji okna nie jest zaimplementowane dla tego systemu"
+
+msgid "E466: :winpos requires two number arguments"
+msgstr "E466: :winpos wymaga dwóch argumentów numerycznych"
+
+msgid "Save Redirection"
+msgstr "Zapisz przekierowanie"
+
+msgid "Save View"
+msgstr "Zapisz widok"
+
+msgid "Save Session"
+msgstr "Zapisz sesjÄ™"
+
+msgid "Save Setup"
+msgstr "Zapisz ustawienia"
+
+#, c-format
+msgid "E739: Cannot create directory: %s"
+msgstr "E739: Nie mogę utworzyć katalogu: %s"
+
+#, c-format
+msgid "E189: \"%s\" exists (add ! to override)"
+msgstr "E189: \"%s\" istnieje (wymuÅ› poprzez !)"
+
+#, c-format
+msgid "E190: Cannot open \"%s\" for writing"
+msgstr "E190: Nie mogę otworzyć \"%s\" do zapisu"
+
+#. set mark
+msgid "E191: Argument must be a letter or forward/backward quote"
+msgstr "E191: Argument musi być literą albo cudzysłowem w przód/tył"
+
+msgid "E192: Recursive use of :normal too deep"
+msgstr "E192: Rekursywne zastosowanie :normal za głębokie"
+
+msgid "E809: #< is not available without the +eval feature"
+msgstr "E809: #< nie jest dostępne bez właściwości +eval"
+
+msgid "E194: No alternate file name to substitute for '#'"
+msgstr "E194: Brak nazwy zamiennego pliku do podstawienia pod '#'"
+
+msgid "E495: no autocommand file name to substitute for \"<afile>\""
+msgstr "E495: brak nazwy pliku autokomend do podstawienia pod \"<afile>\""
+
+msgid "E496: no autocommand buffer number to substitute for \"<abuf>\""
+msgstr "E496: brak numeru bufora autokomend do podstawienia pod \"<abuf>\""
+
+msgid "E497: no autocommand match name to substitute for \"<amatch>\""
+msgstr "E497: brak nazwy dopasowania autokomend pod \"<amatch>\""
+
+msgid "E498: no :source file name to substitute for \"<sfile>\""
+msgstr "E498: brak nazwy pliku :source do postawienia pod \"<sfile>\""
+
+msgid "E842: no line number to use for \"<slnum>\""
+msgstr "E842: brak numeru linii by użyć z \"<slnum>\""
+
+#, no-c-format
+msgid "E499: Empty file name for '%' or '#', only works with \":p:h\""
+msgstr "E499: Pusta nazwa pliku dla '%' lub '#', działa tylko z \":p:h\""
+
+msgid "E500: Evaluates to an empty string"
+msgstr "E500: Wynikiem jest pusty ciÄ…g"
+
+msgid "E195: Cannot open viminfo file for reading"
+msgstr "E195: Nie mogę otworzyć pliku viminfo do odczytu"
+
+msgid "E196: No digraphs in this version"
+msgstr "E196: Brak dwugrafów w tej wersji"
+
+msgid "E608: Cannot :throw exceptions with 'Vim' prefix"
+msgstr "E608: Nie można ':throw' wyjątków z prefiksem 'Vim'"
+
+#. always scroll up, don't overwrite
+#, c-format
+msgid "Exception thrown: %s"
+msgstr "WyjÄ…tek: %s"
+
+#, c-format
+msgid "Exception finished: %s"
+msgstr "Wyjątek zakończony: %s"
+
+#, c-format
+msgid "Exception discarded: %s"
+msgstr "WyjÄ…tek odrzucony: %s"
+
+#, c-format
+msgid "%s, line %ld"
+msgstr "%s, wiersz %ld"
+
+#. always scroll up, don't overwrite
+#, c-format
+msgid "Exception caught: %s"
+msgstr "WyjÄ…tek przechwycony: %s"
+
+#, c-format
+msgid "%s made pending"
+msgstr "%s został zawieszony"
+
+#, c-format
+msgid "%s resumed"
+msgstr "%s przywrócony"
+
+#, c-format
+msgid "%s discarded"
+msgstr "%s odrzucony"
+
+msgid "Exception"
+msgstr "WyjÄ…tek"
+
+msgid "Error and interrupt"
+msgstr "BÅ‚Ä…d i przerwanie"
+
+msgid "Error"
+msgstr "BÅ‚Ä…d"
+
+#. if (pending & CSTP_INTERRUPT)
+msgid "Interrupt"
+msgstr "Przerwanie"
+
+msgid "E579: :if nesting too deep"
+msgstr "E579: zbyt głębokie zagnieżdżenie :if"
+
+msgid "E580: :endif without :if"
+msgstr "E580: :endif bez :if"
+
+msgid "E581: :else without :if"
+msgstr "E581: :else bez :if"
+
+msgid "E582: :elseif without :if"
+msgstr "E582: :elseif bez :if"
+
+msgid "E583: multiple :else"
+msgstr "E583: wielokrotne :else"
+
+msgid "E584: :elseif after :else"
+msgstr "E584: :elseif po :else"
+
+msgid "E585: :while/:for nesting too deep"
+msgstr "E585: zbyt głębokie zagnieżdżenie :while/:for"
+
+msgid "E586: :continue without :while or :for"
+msgstr "E586: :continue bez :while lub :for"
+
+msgid "E587: :break without :while or :for"
+msgstr "E587: :break bez :while lub :for"
+
+msgid "E732: Using :endfor with :while"
+msgstr "E732: Użycie :endfor z :while"
+
+msgid "E733: Using :endwhile with :for"
+msgstr "E733: Użycie :endwhile z :for"
+
+msgid "E601: :try nesting too deep"
+msgstr "E601: zbyt głębokie zagnieżdżenie :try"
+
+msgid "E603: :catch without :try"
+msgstr "E603: :catch bez :try"
+
+#. Give up for a ":catch" after ":finally" and ignore it.
+#. * Just parse.
+msgid "E604: :catch after :finally"
+msgstr "E604: :catch za :finally"
+
+msgid "E606: :finally without :try"
+msgstr "E606: :finally bez :try"
+
+#. Give up for a multiple ":finally" and ignore it.
+msgid "E607: multiple :finally"
+msgstr "E607: wielokrotne :finally"
+
+msgid "E602: :endtry without :try"
+msgstr "E602: :endtry bez :try"
+
+msgid "E193: :endfunction not inside a function"
+msgstr "E193: :endfunction poza funkcjÄ…"
+
+msgid "E788: Not allowed to edit another buffer now"
+msgstr "E788: Nie można teraz edytować innego bufora"
+
+msgid "E811: Not allowed to change buffer information now"
+msgstr "E811: Nie można teraz zmieniać informacji o buforze"
+
+msgid "tagname"
+msgstr "nazwa znacznika"
+
+msgid " kind file\n"
+msgstr " pokrewny plik\n"
+
+msgid "'history' option is zero"
+msgstr "opcja 'history' jest zerowa"
+
+#, c-format
+msgid ""
+"\n"
+"# %s History (newest to oldest):\n"
+msgstr ""
+"\n"
+"# %s Historia (od najnowszych po najstarsze):\n"
+
+msgid "Command Line"
+msgstr "Wiersz poleceń"
+
+msgid "Search String"
+msgstr "Szukany ciÄ…g"
+
+msgid "Expression"
+msgstr "Wyrażenie"
+
+msgid "Input Line"
+msgstr "Wiersz wprowadzeń"
+
+msgid "E198: cmd_pchar beyond the command length"
+msgstr "E198: cmd_pchar przekracza długość polecenia"
+
+msgid "E199: Active window or buffer deleted"
+msgstr "E199: Aktywny widok lub bufor skasowany"
+
+msgid "E812: Autocommands changed buffer or buffer name"
+msgstr "E812: Autokomendy zmieniły bufor lub jego nazwę"
+
+msgid "Illegal file name"
+msgstr "Niedopuszczalna nazwa pliku"
+
+msgid "is a directory"
+msgstr "jest katalogiem"
+
+msgid "is not a file"
+msgstr "nie jest plikiem"
+
+msgid "is a device (disabled with 'opendevice' option)"
+msgstr "jest urządzeniem (wyłączonym w opcji 'opendevice')"
+
+msgid "[New File]"
+msgstr "[Nowy Plik]"
+
+msgid "[New DIRECTORY]"
+msgstr "[Nowy KATALOG]"
+
+msgid "[File too big]"
+msgstr "[Za duży plik]"
+
+msgid "[Permission Denied]"
+msgstr "[Nie dozwolono]"
+
+msgid "E200: *ReadPre autocommands made the file unreadable"
+msgstr "E200: Autokomendy *ReadPre zrobiły plik nieodczytywalnym"
+
+msgid "E201: *ReadPre autocommands must not change current buffer"
+msgstr "E201: Autokomendy *ReadPre nie mogą zmieniać bieżącego bufora"
+
+msgid "Vim: Reading from stdin...\n"
+msgstr "Vim: Wczytywanie ze stdin...\n"
+
+msgid "Reading from stdin..."
+msgstr "Wczytywanie ze stdin..."
+
+#. Re-opening the original file failed!
+msgid "E202: Conversion made file unreadable!"
+msgstr "E202: Nie można otworzyć pliku utworzonego przez przemianę!"
+
+msgid "[fifo/socket]"
+msgstr "[fifo/socket]"
+
+msgid "[fifo]"
+msgstr "[fifo]"
+
+msgid "[socket]"
+msgstr "[socket]"
+
+msgid "[character special]"
+msgstr "[specjalny znak]"
+
+msgid "[CR missing]"
+msgstr "[brak CR]'"
+
+msgid "[long lines split]"
+msgstr "[długie wiersze rozdzielane]"
+
+msgid "[NOT converted]"
+msgstr "[NIE przemienione]"
+
+msgid "[converted]"
+msgstr "[przemienione]"
+
+msgid "[blowfish]"
+msgstr "[blowfish]"
+
+msgid "[crypted]"
+msgstr "[zakodowane]"
+
+#, c-format
+msgid "[CONVERSION ERROR in line %ld]"
+msgstr "[BÅÄ„D W PRZEMIANIE w linii %ld]"
+
+#, c-format
+msgid "[ILLEGAL BYTE in line %ld]"
+msgstr "[NIEDOZWOLONY BAJT w wierszu %ld]"
+
+msgid "[READ ERRORS]"
+msgstr "[BÅĘDY W ODCZYCIE]"
+
+msgid "Can't find temp file for conversion"
+msgstr "Nie mogę znaleźć pliku tymczasowego w celu przemiany"
+
+msgid "Conversion with 'charconvert' failed"
+msgstr "Nieudana przemiana z 'charconvert'"
+
+msgid "can't read output of 'charconvert'"
+msgstr "nie mogę odczytać wyjścia z 'charconvert'"
+
+msgid "E821: File is encrypted with unknown method"
+msgstr "E821: Plik zaszyfrowano w nieznany sposób"
+
+msgid "E676: No matching autocommands for acwrite buffer"
+msgstr "E676: Brak pasujÄ…cych autokomend dla bufora acwrite"
+
+msgid "E203: Autocommands deleted or unloaded buffer to be written"
+msgstr ""
+"E203: Autokomendy skasowały lub wyładowały bufor przeznaczony do zapisu"
+
+msgid "E204: Autocommand changed number of lines in unexpected way"
+msgstr "E204: Autokomenda zmieniła liczbę wierszy w nieoczekiwany sposób"
+
+msgid "NetBeans disallows writes of unmodified buffers"
+msgstr "NetBeans nie pozwala na zapis niezmodyfikowanych buforów"
+
+msgid "Partial writes disallowed for NetBeans buffers"
+msgstr "Częściowy zapis niemożliwy dla buforów NetBeans"
+
+msgid "is not a file or writable device"
+msgstr "nie jest plikiem lub zapisywalnym przyrzÄ…dem"
+
+msgid "writing to device disabled with 'opendevice' option"
+msgstr "zapisywanie do urządzenia wyłączone w opcji 'opendevice'"
+
+msgid "is read-only (add ! to override)"
+msgstr "jest tylko do odczytu (wymuÅ› poprzez !)"
+
+msgid "E506: Can't write to backup file (add ! to override)"
+msgstr "E506: Nie mogę zapisać do pliku zabezpieczenia (wymuś przez !)"
+
+msgid "E507: Close error for backup file (add ! to override)"
+msgstr "E507: BÅ‚Ä…d podczas zamykania pliku zabezpieczenia (wymuÅ› przez !)"
+
+msgid "E508: Can't read file for backup (add ! to override)"
+msgstr "E508: Nie mogę odczytać pliku w celu zabezpieczenia (wymuś przez !)"
+
+msgid "E509: Cannot create backup file (add ! to override)"
+msgstr "E509: Nie mogę stworzyć pliku zabezpieczenia (wymuś przez !)"
+
+msgid "E510: Can't make backup file (add ! to override)"
+msgstr "E510: Nie mogę zrobić pliku zabezpieczenia (wymuś przez !)"
+
+msgid "E460: The resource fork would be lost (add ! to override)"
+msgstr "E460: Rozdział zasobów zostanie utracony (wymuś przez !)"
+
+msgid "E214: Can't find temp file for writing"
+msgstr "E214: Nie mogę znaleźć pliku tymczasowego do zapisania"
+
+msgid "E213: Cannot convert (add ! to write without conversion)"
+msgstr "E213: Nie mogę przemienić (użyj ! by zapisać bez przemiany)"
+
+msgid "E166: Can't open linked file for writing"
+msgstr "E166: Nie mogę otworzyć podłączonego pliku do zapisu"
+
+msgid "E212: Can't open file for writing"
+msgstr "E212: Nie mogę otworzyć pliku do zapisu"
+
+msgid "E667: Fsync failed"
+msgstr "E667: Fsync nie powiódł się"
+
+msgid "E512: Close failed"
+msgstr "E512: Zamknięcie się nie powiodło"
+
+msgid "E513: write error, conversion failed (make 'fenc' empty to override)"
+msgstr ""
+"E513: Błąd zapisu, przemiana się nie powiodła (opróżnij 'fenc' aby wymusić)"
+
+#, c-format
+msgid ""
+"E513: write error, conversion failed in line %ld (make 'fenc' empty to "
+"override)"
+msgstr ""
+"E513: Błąd zapisu, przemiana się nie powiodła w wierszu %ld (opróżnij 'fenc' "
+"by wymusić)"
+
+msgid "E514: write error (file system full?)"
+msgstr "E514: błąd w zapisie (może system plików jest przepełniony?)"
+
+msgid " CONVERSION ERROR"
+msgstr " BÅÄ„D W PRZEMIANIE"
+
+#, c-format
+msgid " in line %ld;"
+msgstr " w wierszu %ld;"
+
+msgid "[Device]"
+msgstr "[UrzÄ…dzenie]"
+
+msgid "[New]"
+msgstr "[Nowy]"
+
+msgid " [a]"
+msgstr " [a]"
+
+msgid " appended"
+msgstr " dołączono"
+
+msgid " [w]"
+msgstr " [w]"
+
+msgid " written"
+msgstr " zapisano"
+
+msgid "E205: Patchmode: can't save original file"
+msgstr "E205: Patchmode: nie mogę zapisać oryginalnego pliku"
+
+msgid "E206: patchmode: can't touch empty original file"
+msgstr "E206: patchmode: nie mogę stworzyć pustego oryginalnego pliku"
+
+msgid "E207: Can't delete backup file"
+msgstr "E207: Nie mogę skasować pliku zabezpieczenia"
+
+msgid ""
+"\n"
+"WARNING: Original file may be lost or damaged\n"
+msgstr ""
+"\n"
+"OSTRZEŻENIE: Oryginalny plik może zostać utracony lub uszkodzony\n"
+
+msgid "don't quit the editor until the file is successfully written!"
+msgstr "nie wychodź edytora, dopóki plik nie został poprawnie zapisany!"
+
+msgid "[dos]"
+msgstr "[dos]"
+
+msgid "[dos format]"
+msgstr "[format dos-a]"
+
+msgid "[mac]"
+msgstr "[mac]"
+
+msgid "[mac format]"
+msgstr "[format maca]"
+
+msgid "[unix]"
+msgstr "[unix]"
+
+msgid "[unix format]"
+msgstr "[format unixa]"
+
+msgid "1 line, "
+msgstr "1 wiersz, "
+
+#, c-format
+msgid "%ld lines, "
+msgstr "%ld wierszy, "
+
+msgid "1 character"
+msgstr "1 znak"
+
+#, c-format
+msgid "%lld characters"
+msgstr "%lld znaków"
+
+#. Explicit typecast avoids warning on Mac OS X 10.6
+#, c-format
+msgid "%ld characters"
+msgstr "%ld znaków"
+
+msgid "[noeol]"
+msgstr "[noeol]"
+
+msgid "[Incomplete last line]"
+msgstr "[Niekompletny ostatni wiersz]"
+
+#. don't overwrite messages here
+#. must give this prompt
+#. don't use emsg() here, don't want to flush the buffers
+msgid "WARNING: The file has been changed since reading it!!!"
+msgstr "OSTRZEŻENIE: Plik zmienił się od czasu ostatniego odczytu!!!"
+
+msgid "Do you really want to write to it"
+msgstr "Czy naprawdę chcesz go zapisać"
+
+#, c-format
+msgid "E208: Error writing to \"%s\""
+msgstr "E208: BÅ‚Ä…d zapisywania do \"%s\""
+
+#, c-format
+msgid "E209: Error closing \"%s\""
+msgstr "E209: BÅ‚Ä…d w trakcie zamykania \"%s\""
+
+#, c-format
+msgid "E210: Error reading \"%s\""
+msgstr "E210: BÅ‚Ä…d odczytu \"%s\""
+
+msgid "E246: FileChangedShell autocommand deleted buffer"
+msgstr "E246: Autokomenda FileChangedShell skasowała bufor"
+
+#, c-format
+msgid "E211: File \"%s\" no longer available"
+msgstr "E211: Plik \"%s\" nie jest dłużej dostępny"
+
+#, c-format
+msgid ""
+"W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as "
+"well"
+msgstr ""
+"W12: OSTRZEŻENIE: Plik \"%s\" zmienił się od czasu rozpoczęcia edycji, bufor "
+"w Vimie również został zmieniony"
+
+msgid "See \":help W12\" for more info."
+msgstr "Zobacz \":help W12\" dla dalszych informacji."
+
+#, c-format
+msgid "W11: Warning: File \"%s\" has changed since editing started"
+msgstr "W11: OSTRZEŻENIE: Plik \"%s\" zmienił się od czasu rozpoczęcia edycji"
+
+msgid "See \":help W11\" for more info."
+msgstr "Zobacz \":help W11\" dla dalszych informacji."
+
+#, c-format
+msgid "W16: Warning: Mode of file \"%s\" has changed since editing started"
+msgstr ""
+"W16: OSTRZEŻENIE: Tryb pliku \"%s\" zmienił się od czasu rozpoczęcia edycji"
+
+msgid "See \":help W16\" for more info."
+msgstr "Zobacz \":help W16\" dla dalszych informacji."
+
+#, c-format
+msgid "W13: Warning: File \"%s\" has been created after editing started"
+msgstr "W13: OSTRZEŻENIE: Plik \"%s\" został stworzony po rozpoczęciu edycji"
+
+msgid "Warning"
+msgstr "OSTRZEŻENIE"
+
+msgid ""
+"&OK\n"
+"&Load File"
+msgstr ""
+"&OK\n"
+"&Załaduj Plik"
+
+#, c-format
+msgid "E462: Could not prepare for reloading \"%s\""
+msgstr "E462: Nie można przygotować przeładowania \"%s\""
+
+#, c-format
+msgid "E321: Could not reload \"%s\""
+msgstr "E321: Nie można przeładować \"%s\""
+
+msgid "--Deleted--"
+msgstr "--Skasowano--"
+
+#, c-format
+msgid "auto-removing autocommand: %s <buffer=%d>"
+msgstr "auto-usuwanie autokomendy: %s <buffer=%d>"
+
+#. the group doesn't exist
+#, c-format
+msgid "E367: No such group: \"%s\""
+msgstr "E367: Nie ma takiej grupy: \"%s\""
+
+#, c-format
+msgid "E215: Illegal character after *: %s"
+msgstr "E215: Niedopuszczalny znak po *: %s"
+
+#, c-format
+msgid "E216: No such event: %s"
+msgstr "E216: Nie ma takiego wydarzenia: %s"
+
+#, c-format
+msgid "E216: No such group or event: %s"
+msgstr "E216: Nie ma takiej grupy lub wydarzenia: %s"
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Autocommands ---"
+msgstr ""
+"\n"
+"--- Autokomendy ---"
+
+#, c-format
+msgid "E680: <buffer=%d>: invalid buffer number "
+msgstr "E680: <buffer=%d>: niewłaściwy numer bufora"
+
+msgid "E217: Can't execute autocommands for ALL events"
+msgstr "E217: Nie można wykonywać autokomend dla wydarzeń ALL"
+
+msgid "No matching autocommands"
+msgstr "Brak pasujÄ…cych autokomend"
+
+msgid "E218: autocommand nesting too deep"
+msgstr "E218: zbyt głębokie zagnieżdżenie autokomend"
+
+#, c-format
+msgid "%s Autocommands for \"%s\""
+msgstr "%s Autokomend dla \"%s\""
+
+#, c-format
+msgid "Executing %s"
+msgstr "WykonujÄ™ %s"
+
+#, c-format
+msgid "autocommand %s"
+msgstr "autokomenda %s"
+
+msgid "E219: Missing {."
+msgstr "E219: Brak {."
+
+msgid "E220: Missing }."
+msgstr "E220: Brak }."
+
+msgid "E490: No fold found"
+msgstr "E490: Nie znaleziono zwinięcia"
+
+msgid "E350: Cannot create fold with current 'foldmethod'"
+msgstr "E350: Nie można utworzyć zwinięcia przy bieżącej 'foldmethod'"
+
+msgid "E351: Cannot delete fold with current 'foldmethod'"
+msgstr "E351: Nie można skasować zwinięcia przy bieżącej 'foldmethod'"
+
+#, c-format
+msgid "+--%3ld lines folded "
+msgstr "+--%3ld wierszy zwinięto "
+
+msgid "E222: Add to read buffer"
+msgstr "E222: Dodaj do bufora odczytu"
+
+msgid "E223: recursive mapping"
+msgstr "E223: rekursywne przyporzÄ…dkowanie"
+
+#, c-format
+msgid "E224: global abbreviation already exists for %s"
+msgstr "E224: istnieje już globalny skrót dla %s"
+
+#, c-format
+msgid "E225: global mapping already exists for %s"
+msgstr "E225: istnieje już globalne przyporządkowanie dla %s"
+
+#, c-format
+msgid "E226: abbreviation already exists for %s"
+msgstr "E226: istnieje już skrót dla %s"
+
+#, c-format
+msgid "E227: mapping already exists for %s"
+msgstr "E227: istnieje już przyporządkowanie dla %s"
+
+msgid "No abbreviation found"
+msgstr "Nie znaleziono skrótu"
+
+msgid "No mapping found"
+msgstr "Nie znaleziono przyporzÄ…dkowania"
+
+msgid "E228: makemap: Illegal mode"
+msgstr "E228: makemap: Niedopuszczalny tryb"
+
+msgid "<cannot open> "
+msgstr "<nie mogę otworzyć> "
+
+#, c-format
+msgid "E616: vim_SelFile: can't get font %s"
+msgstr "E616: vim_SelFile: nie mogę otrzymać czcionki %s"
+
+msgid "E614: vim_SelFile: can't return to current directory"
+msgstr "E614: vim_SelFile: nie mogę powrócić do bieżącego katalogu"
+
+msgid "Pathname:"
+msgstr "Trop:"
+
+msgid "E615: vim_SelFile: can't get current directory"
+msgstr "E615: vim_SelFile: nie mogę otrzymać bieżącego katalogu"
+
+msgid "OK"
+msgstr "OK"
+
+msgid "Cancel"
+msgstr "Zakończ"
+
+msgid "Vim dialog"
+msgstr "VIM - Dialog"
+
+msgid "Scrollbar Widget: Could not get geometry of thumb pixmap."
+msgstr "Scrollbar Widget: Nie mogłem otrzymać rozmiarów rysunku na przycisku."
+
+msgid "E232: Cannot create BalloonEval with both message and callback"
+msgstr "E232: Nie mogę stworzyć BalloonEval z powiadomieniem i wywołaniem"
+
+msgid "E851: Failed to create a new process for the GUI"
+msgstr "E851: Nie mogłem stworzyć nowego procesu dla GUI"
+
+msgid "E852: The child process failed to start the GUI"
+msgstr "E852: Proces potomny nie mógł uruchomić GUI"
+
+msgid "E229: Cannot start the GUI"
+msgstr "E229: Nie mogę odpalić GUI"
+
+#, c-format
+msgid "E230: Cannot read from \"%s\""
+msgstr "E230: Nie mogę czytać z \"%s\""
+
+msgid "E665: Cannot start GUI, no valid font found"
+msgstr "E665: Nie można uruchomić GUI, brak prawidłowej czcionki"
+
+msgid "E231: 'guifontwide' invalid"
+msgstr "E231: Niewłaściwe 'guifontwide'"
+
+msgid "E599: Value of 'imactivatekey' is invalid"
+msgstr "E599: Nieprawidłowa wartość 'imactivatekey'"
+
+#, c-format
+msgid "E254: Cannot allocate color %s"
+msgstr "E254: Nie mogę zarezerwować koloru %s"
+
+msgid "No match at cursor, finding next"
+msgstr "Brak dopasowania przy kursorze, szukam dalej"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"&Cancel"
+msgstr ""
+"&Tak\n"
+"&Nie\n"
+"&Zakończ"
+
+msgid "Input _Methods"
+msgstr "Input _Methods"
+
+msgid "VIM - Search and Replace..."
+msgstr "VIM - Szukaj i Zamień..."
+
+msgid "VIM - Search..."
+msgstr "VIM - Szukaj..."
+
+msgid "Find what:"
+msgstr "Znajdź:"
+
+msgid "Replace with:"
+msgstr "Zamień na:"
+
+#. whole word only button
+msgid "Match whole word only"
+msgstr "Dopasuj tylko całe wyrazy"
+
+#. match case button
+msgid "Match case"
+msgstr "Dopasuj wielkość liter"
+
+msgid "Direction"
+msgstr "Kierunek"
+
+#. 'Up' and 'Down' buttons
+msgid "Up"
+msgstr "W górę"
+
+msgid "Down"
+msgstr "W dół"
+
+#. 'Find Next' button
+msgid "Find Next"
+msgstr "Znajdź następne"
+
+#. 'Replace' button
+msgid "Replace"
+msgstr "Zamień"
+
+#. 'Replace All' button
+msgid "Replace All"
+msgstr "Zamień wszystkie"
+
+msgid "Vim: Received \"die\" request from session manager\n"
+msgstr "Vim: otrzymano żądanie \"die\" od menedżera sesji\n"
+
+msgid "Close"
+msgstr "Zamknij"
+
+msgid "New tab"
+msgstr "Nowa karta"
+
+msgid "Open Tab..."
+msgstr "Otwórz kartę..."
+
+msgid "Vim: Main window unexpectedly destroyed\n"
+msgstr "Vim: Główne okno nieoczekiwanie zniszczone\n"
+
+msgid "&Filter"
+msgstr "&Filtr"
+
+msgid "&Cancel"
+msgstr "&Anuluj"
+
+msgid "Directories"
+msgstr "Katalogi"
+
+msgid "Filter"
+msgstr "Filtr"
+
+msgid "&Help"
+msgstr "&Pomoc"
+
+msgid "Files"
+msgstr "Pliki"
+
+msgid "&OK"
+msgstr "&OK"
+
+msgid "Selection"
+msgstr "Wybór"
+
+msgid "Find &Next"
+msgstr "Znajdź &następne"
+
+msgid "&Replace"
+msgstr "&Zamień"
+
+msgid "Replace &All"
+msgstr "Zamień &wszystko"
+
+msgid "&Undo"
+msgstr "&Cofnij"
+
+#, c-format
+msgid "E671: Cannot find window title \"%s\""
+msgstr "E671: Nie mogę znaleźć tytułu okna \"%s\""
+
+#, c-format
+msgid "E243: Argument not supported: \"-%s\"; Use the OLE version."
+msgstr "E243: Argument nie jest wspomagany: \"-%s\"; Używaj wersji OLE."
+
+msgid "E672: Unable to open window inside MDI application"
+msgstr "E672: Nie można otworzyć okna wewnątrz aplikacji MDI"
+
+msgid "Close tab"
+msgstr "Zamknij kartÄ™"
+
+msgid "Open tab..."
+msgstr "Otwórz kartę..."
+
+msgid "Find string (use '\\\\' to find a '\\')"
+msgstr "Znajdź ciąg (użyj '\\\\' do szukania '\\')"
+
+msgid "Find & Replace (use '\\\\' to find a '\\')"
+msgstr "Szukanie i Zamiana (użyj '\\\\' do szukania '\\')"
+
+#. We fake this: Use a filter that doesn't select anything and a default
+#. * file name that won't be used.
+msgid "Not Used"
+msgstr "Nie używany"
+
+msgid "Directory\t*.nothing\n"
+msgstr "Katalog\t*.nic\n"
+
+msgid "Vim E458: Cannot allocate colormap entry, some colors may be incorrect"
+msgstr ""
+"Vim E458: Nie mogę zarezerwować mapy kolorów, pewne kolory mogą być "
+"nieprawidłowe"
+
+#, c-format
+msgid "E250: Fonts for the following charsets are missing in fontset %s:"
+msgstr ""
+"E250: Brak czcionek dla następujących zestawów znaków w zestawie czcionek %s:"
+
+#, c-format
+msgid "E252: Fontset name: %s"
+msgstr "E252: Nazwa zestawu czcionek: %s"
+
+#, c-format
+msgid "Font '%s' is not fixed-width"
+msgstr "Czcionka '%s' nie posiada znaków jednolitej szerokości"
+
+#, c-format
+msgid "E253: Fontset name: %s"
+msgstr "E253: Nazwa zestawu czcionek: %s"
+
+#, c-format
+msgid "Font0: %s"
+msgstr "Font0: %s"
+
+#, c-format
+msgid "Font1: %s"
+msgstr "Font1: %s"
+
+#, c-format
+msgid "Font%ld width is not twice that of font0"
+msgstr "Szerokość font%ld nie jest podwójną szerokością font0"
+
+#, c-format
+msgid "Font0 width: %ld"
+msgstr "Szerokość font0: %ld"
+
+#, c-format
+msgid "Font1 width: %ld"
+msgstr "Szerokość font1: %ld"
+
+msgid "Invalid font specification"
+msgstr "Nieprawidłowy opis czcionki"
+
+msgid "&Dismiss"
+msgstr "&Anuluj"
+
+msgid "no specific match"
+msgstr "brak określonego dopasowania"
+
+msgid "Vim - Font Selector"
+msgstr "Vim - wybór czcionki"
+
+msgid "Name:"
+msgstr "Nazwa:"
+
+#. create toggle button
+msgid "Show size in Points"
+msgstr "Pokaż wielkość w punktach"
+
+msgid "Encoding:"
+msgstr "Kodowanie:"
+
+msgid "Font:"
+msgstr "Czcionka:"
+
+msgid "Style:"
+msgstr "Styl:"
+
+msgid "Size:"
+msgstr "Wielkość:"
+
+msgid "E256: Hangul automata ERROR"
+msgstr "E256: BÅÄ„D w automacie Hangul"
+
+msgid "E550: Missing colon"
+msgstr "E550: Brak dwukropka"
+
+msgid "E551: Illegal component"
+msgstr "E551: Niedozwolona część"
+
+msgid "E552: digit expected"
+msgstr "E552: oczekiwałem na cyfrę"
+
+#, c-format
+msgid "Page %d"
+msgstr "Strona %d"
+
+msgid "No text to be printed"
+msgstr "Brak tekstu do drukowania"
+
+#, c-format
+msgid "Printing page %d (%d%%)"
+msgstr "DrukujÄ™ stronÄ™ %d (%d%%)"
+
+#, c-format
+msgid " Copy %d of %d"
+msgstr " Kopia %d z %d"
+
+#, c-format
+msgid "Printed: %s"
+msgstr "Wydrukowano: %s"
+
+msgid "Printing aborted"
+msgstr "Drukowanie odwołane"
+
+msgid "E455: Error writing to PostScript output file"
+msgstr "E455: Nie można zapisać do wyjściowego pliku PostScriptu"
+
+#, c-format
+msgid "E624: Can't open file \"%s\""
+msgstr "E624: Nie mogę otworzyć pliku \"%s\""
+
+#, c-format
+msgid "E457: Can't read PostScript resource file \"%s\""
+msgstr "E457: Nie można odczytać pliku zasobów PostScriptu \"%s\""
+
+#, c-format
+msgid "E618: file \"%s\" is not a PostScript resource file"
+msgstr "E618: plik \"%s\" nie jest plikiem zasobów PostScriptu"
+
+#, c-format
+msgid "E619: file \"%s\" is not a supported PostScript resource file"
+msgstr "E619: plik \"%s\" nie jest wspieranym plikiem zasobów PostScriptu"
+
+#, c-format
+msgid "E621: \"%s\" resource file has wrong version"
+msgstr "E621: \"%s\" nieprawidłowa wersja pliku zasobów"
+
+msgid "E673: Incompatible multi-byte encoding and character set."
+msgstr "E673: Niekompatybilne kodowanie wielobajtowe i zestaw znaków."
+
+msgid "E674: printmbcharset cannot be empty with multi-byte encoding."
+msgstr "E674: printmbcharset nie może być pusty przy kodowaniu wielobajtowym."
+
+msgid "E675: No default font specified for multi-byte printing."
+msgstr "E675: Nie określono domyślnej czcionki dla drukowania wielobajtowego."
+
+msgid "E324: Can't open PostScript output file"
+msgstr "E324: Nie można otworzyć pliku PostScript do wyjścia"
+
+#, c-format
+msgid "E456: Can't open file \"%s\""
+msgstr "E456: Nie mogę otworzyć pliku \"%s\""
+
+msgid "E456: Can't find PostScript resource file \"prolog.ps\""
+msgstr "E456: Nie można znaleźć pliku zasobów PostScriptu \"prolog.ps\""
+
+msgid "E456: Can't find PostScript resource file \"cidfont.ps\""
+msgstr "E456: Nie można znaleźć pliku zasobów PostScriptu \"cidfont.ps\""
+
+#, c-format
+msgid "E456: Can't find PostScript resource file \"%s.ps\""
+msgstr "E456: Nie można znaleźć pliku zasobów PostScriptu \"%s.ps\""
+
+#, c-format
+msgid "E620: Unable to convert to print encoding \"%s\""
+msgstr "E620: Nie można przekonwertować by drukować kodowanie \"%s\""
+
+msgid "Sending to printer..."
+msgstr "Przesyłam do drukarki..."
+
+msgid "E365: Failed to print PostScript file"
+msgstr "E365: Drukowanie pliku PostScript nie powiodło się"
+
+msgid "Print job sent."
+msgstr "Zadanie drukowanie przesłane."
+
+msgid "Add a new database"
+msgstr "Dodaj nowÄ… bazÄ™ danych"
+
+msgid "Query for a pattern"
+msgstr "Zapytane o wzorzec"
+
+msgid "Show this message"
+msgstr "Pokaż ten komunikat"
+
+msgid "Kill a connection"
+msgstr "Zabij połączenie"
+
+msgid "Reinit all connections"
+msgstr "Ponów wszelkie połączenia"
+
+msgid "Show connections"
+msgstr "Pokaż połączenia"
+
+#, c-format
+msgid "E560: Usage: cs[cope] %s"
+msgstr "E560: Zastosowanie: cs[cope] %s"
+
+msgid "This cscope command does not support splitting the window.\n"
+msgstr "Ta komenda cscope nie wspomaga podzielenia okna.\n"
+
+msgid "E562: Usage: cstag <ident>"
+msgstr "E562: Zastosowanie: cstag <ident>"
+
+msgid "E257: cstag: tag not found"
+msgstr "E257: cstag: nie znaleziono znacznika"
+
+#, c-format
+msgid "E563: stat(%s) error: %d"
+msgstr "E563: stat(%s) błąd: %d"
+
+msgid "E563: stat error"
+msgstr "E563: błąd stat"
+
+#, c-format
+msgid "E564: %s is not a directory or a valid cscope database"
+msgstr "E564: %s nie jest katalogiem lub poprawnÄ… bazÄ… danych cscope"
+
+#, c-format
+msgid "Added cscope database %s"
+msgstr "Dodano bazÄ™ danych cscope %s"
+
+#, c-format
+msgid "E262: error reading cscope connection %ld"
+msgstr "E262: błąd odczytu połączenia z cscope %ld"
+
+msgid "E561: unknown cscope search type"
+msgstr "E561: nieznany typ szukania cscope"
+
+msgid "E566: Could not create cscope pipes"
+msgstr "E566: Nie mogłem stworzyć potoku do cscope"
+
+msgid "E622: Could not fork for cscope"
+msgstr "E622: Nie mogłem utworzyć rozwidlenia dla cscope"
+
+msgid "cs_create_connection setpgid failed"
+msgstr "nie powiodło się setpgid cs_create_connection"
+
+msgid "cs_create_connection exec failed"
+msgstr "wykonanie cs_create_connection nie powiodło się"
+
+msgid "cs_create_connection: fdopen for to_fp failed"
+msgstr "cs_create_connection: fdopen dla to_fp nie powiodło się"
+
+msgid "cs_create_connection: fdopen for fr_fp failed"
+msgstr "cs_create_connection: fdopen dla fr_fp nie powiodło się"
+
+msgid "E623: Could not spawn cscope process"
+msgstr "E623: Nie mogłem stworzyć procesu cscope"
+
+msgid "E567: no cscope connections"
+msgstr "E567: brak połączenia z cscope"
+
+#, c-format
+msgid "E469: invalid cscopequickfix flag %c for %c"
+msgstr "E469: nieprawidłowa flaga cscopequickfix %c dla %c"
+
+#, c-format
+msgid "E259: no matches found for cscope query %s of %s"
+msgstr "E259: brak dopasowań dla zapytania cscope %s o %s"
+
+msgid "cscope commands:\n"
+msgstr "komendy cscope:\n"
+
+#, c-format
+msgid "%-5s: %s%*s (Usage: %s)"
+msgstr "%-5s: %s%*s (Użycie: %s)"
+
+msgid ""
+"\n"
+" c: Find functions calling this function\n"
+" d: Find functions called by this function\n"
+" e: Find this egrep pattern\n"
+" f: Find this file\n"
+" g: Find this definition\n"
+" i: Find files #including this file\n"
+" s: Find this C symbol\n"
+" t: Find this text string\n"
+msgstr ""
+"\n"
+" c: znajdź funkcje wywołujące tę funkcję\n"
+" d: znajdź funkcje wywoływane przez tę funkcję\n"
+" e: znajdź ten wzorzec egrep\n"
+" f: znajdź ten plik\n"
+" g: znajdź tę definicję\n"
+" i: znajdź pliki włączające (#include) ten plik\n"
+" s: znajdź ten symbol C\n"
+" t: znajdź ten łańcuch znaków\n"
+
+#, c-format
+msgid "E625: cannot open cscope database: %s"
+msgstr "E625: nie mogę otworzyć bazy danych cscope: %s"
+
+msgid "E626: cannot get cscope database information"
+msgstr "E626: nie mogę uzyskać informacji z bazy danych cscope"
+
+msgid "E568: duplicate cscope database not added"
+msgstr "E568: nie dodano duplikatu bazy danych cscope"
+
+#, c-format
+msgid "E261: cscope connection %s not found"
+msgstr "E261: nie ma połączenia %s z cscope"
+
+#, c-format
+msgid "cscope connection %s closed"
+msgstr "połączenie %s z cscope zostało zamknięte"
+
+#. should not reach here
+msgid "E570: fatal error in cs_manage_matches"
+msgstr "E570: błąd krytyczny w cs_manage_matches"
+
+#, c-format
+msgid "Cscope tag: %s"
+msgstr "Znacznik cscope: %s"
+
+msgid ""
+"\n"
+" # line"
+msgstr ""
+"\n"
+" # wiersz"
+
+msgid "filename / context / line\n"
+msgstr "nazwa pliku / kontekst / wiersz\n"
+
+#, c-format
+msgid "E609: Cscope error: %s"
+msgstr "E609: BÅ‚Ä…d cscope: %s"
+
+msgid "All cscope databases reset"
+msgstr "Wszystkie bazy danych cscope przeładowano"
+
+msgid "no cscope connections\n"
+msgstr "brak połączeń z cscope\n"
+
+msgid " # pid database name prepend path\n"
+msgstr " # pid nazwa bazy danych przedsionek tropu\n"
+
+msgid "Lua library cannot be loaded."
+msgstr "Nie można wczytać biblioteki Lua."
+
+msgid "cannot save undo information"
+msgstr "nie mogę zachować informacji cofania"
+
+msgid ""
+"E815: Sorry, this command is disabled, the MzScheme libraries could not be "
+"loaded."
+msgstr ""
+"E815: Przykro mi, ta komenda jest wyłączona, biblioteka MzScheme nie może "
+"być załadowana."
+
+msgid "invalid expression"
+msgstr "niepoprawne wyrażenie"
+
+msgid "expressions disabled at compile time"
+msgstr "wyrażenia wyłączone podczas kompilacji"
+
+msgid "hidden option"
+msgstr "ukryta opcja"
+
+msgid "unknown option"
+msgstr "nieznana opcja"
+
+msgid "window index is out of range"
+msgstr "indeks okna poza zakresem"
+
+msgid "couldn't open buffer"
+msgstr "nie mogę otworzyć bufora"
+
+msgid "cannot delete line"
+msgstr "nie mogę skasować wiersza"
+
+msgid "cannot replace line"
+msgstr "nie mogę zamienić wiersza"
+
+msgid "cannot insert line"
+msgstr "nie mogę wprowadzić wiersza"
+
+msgid "string cannot contain newlines"
+msgstr "ciąg nie może zawierać znaków nowego wiersza"
+
+msgid "error converting Scheme values to Vim"
+msgstr "błąd przy konwersji wartości Scheme do Vima"
+
+msgid "Vim error: ~a"
+msgstr "BÅ‚Ä…d vima: ~a"
+
+msgid "Vim error"
+msgstr "BÅ‚Ä…d Vima"
+
+msgid "buffer is invalid"
+msgstr "bufor jest nieważny"
+
+msgid "window is invalid"
+msgstr "okno jest nieważne"
+
+msgid "linenr out of range"
+msgstr "numer wiersza poza zakresem"
+
+msgid "not allowed in the Vim sandbox"
+msgstr "Niedozwolone w piaskownicy Vima"
+
+msgid "E837: This Vim cannot execute :py3 after using :python"
+msgstr "E837: Python: nie można używać :py i :py3 w czasie jednej sesji"
+
+msgid ""
+"E263: Sorry, this command is disabled, the Python library could not be "
+"loaded."
+msgstr ""
+"E263: Przykro mi, ta komenda jest wyłączona, bo nie można załadować "
+"biblioteki Pythona"
+
+msgid "E836: This Vim cannot execute :python after using :py3"
+msgstr "E836: Python: nie można używać :py i :py3 w czasie jednej sesji"
+
+msgid "E659: Cannot invoke Python recursively"
+msgstr "E659: Nie można wywołać Pythona rekursywnie"
+
+msgid "E265: $_ must be an instance of String"
+msgstr "E265: $_ musi być reprezentacjÄ… ÅaÅ„cucha"
+
+msgid ""
+"E266: Sorry, this command is disabled, the Ruby library could not be loaded."
+msgstr ""
+"E266: Przykro mi, ta komenda jest wyłączona, bo nie można załadować "
+"biblioteki Ruby."
+
+msgid "E267: unexpected return"
+msgstr "E267: nieoczekiwany return"
+
+msgid "E268: unexpected next"
+msgstr "E268: nieoczekiwany next"
+
+msgid "E269: unexpected break"
+msgstr "E269: nieoczekiwany break"
+
+msgid "E270: unexpected redo"
+msgstr "E270: nieoczekiwane redo"
+
+msgid "E271: retry outside of rescue clause"
+msgstr "E271: ponowna próba poza klauzulą ratunku"
+
+msgid "E272: unhandled exception"
+msgstr "E272: nieobsługiwany wyjątek"
+
+#, c-format
+msgid "E273: unknown longjmp status %d"
+msgstr "E273: Nieznany status longjmp %d"
+
+msgid "Toggle implementation/definition"
+msgstr "Przełącz między implementacją/określeniem"
+
+msgid "Show base class of"
+msgstr "Pokaż bazę klasy"
+
+msgid "Show overridden member function"
+msgstr "Pokaż przepisaną funkcję członową"
+
+msgid "Retrieve from file"
+msgstr "Pobieraj z pliku"
+
+msgid "Retrieve from project"
+msgstr "Pobieraj z projektu"
+
+msgid "Retrieve from all projects"
+msgstr "Pobieraj z wszystkich projektów"
+
+msgid "Retrieve"
+msgstr "Pobierz"
+
+msgid "Show source of"
+msgstr "Pokaż źródło dla"
+
+msgid "Find symbol"
+msgstr "Znajdź symbol"
+
+msgid "Browse class"
+msgstr "Przejrzyj klasÄ™"
+
+msgid "Show class in hierarchy"
+msgstr "Pokaż klasę w hierarchii"
+
+msgid "Show class in restricted hierarchy"
+msgstr "Pokaż klasę w ograniczonej hierarchii"
+
+msgid "Xref refers to"
+msgstr "Xref odnosi siÄ™ do"
+
+msgid "Xref referred by"
+msgstr "Xref ma odniesienia od"
+
+msgid "Xref has a"
+msgstr "Xref ma"
+
+msgid "Xref used by"
+msgstr "Xref użyte przez"
+
+msgid "Show docu of"
+msgstr "Pokaż dokumentację dla"
+
+msgid "Generate docu for"
+msgstr "Utwórz dokumentację dla"
+
+msgid ""
+"Cannot connect to SNiFF+. Check environment (sniffemacs must be found in "
+"$PATH).\n"
+msgstr ""
+"Nie mogę podłączyć do SNiFF+. Sprawdź środowisko (sniffemacs musi być "
+"odnaleziony w $PATH).\n"
+
+msgid "E274: Sniff: Error during read. Disconnected"
+msgstr "E274: Sniff: Błąd podczas czytania. Rozłączenie"
+
+msgid "SNiFF+ is currently "
+msgstr "SNiFF+ jest obecnie "
+
+msgid "not "
+msgstr "nie "
+
+msgid "connected"
+msgstr "podłączony"
+
+#, c-format
+msgid "E275: Unknown SNiFF+ request: %s"
+msgstr "E275: Nieznane zapytanie SNiFF+: %s"
+
+msgid "E276: Error connecting to SNiFF+"
+msgstr "E276: Błąd w trakcie podłączania do SNiFF+"
+
+msgid "E278: SNiFF+ not connected"
+msgstr "E278: SNiFF+ niepodłączony"
+
+msgid "E279: Not a SNiFF+ buffer"
+msgstr "E279: Nie jest buforem SNiFF+"
+
+msgid "Sniff: Error during write. Disconnected"
+msgstr "Sniff: Błąd w trakcie zapisu. Rozłączony"
+
+msgid "invalid buffer number"
+msgstr "niewłaściwy numer bufora"
+
+msgid "not implemented yet"
+msgstr "obecnie nie zaimplementowano"
+
+#. ???
+msgid "cannot set line(s)"
+msgstr "nie mogę ustawić wiersza(y)"
+
+msgid "invalid mark name"
+msgstr "niepoprawna nazwa zakładki"
+
+msgid "mark not set"
+msgstr "zakładka nie ustawiona"
+
+#, c-format
+msgid "row %d column %d"
+msgstr "wiersz %d kolumna %d"
+
+msgid "cannot insert/append line"
+msgstr "nie mogę wprowadzić/dołączyć wiersza"
+
+msgid "line number out of range"
+msgstr "numer wiersza poza zakresem"
+
+msgid "unknown flag: "
+msgstr "nieznana flaga: "
+
+msgid "unknown vimOption"
+msgstr "nieznane vimOption"
+
+msgid "keyboard interrupt"
+msgstr "przerwanie klawiatury"
+
+msgid "vim error"
+msgstr "błąd vima"
+
+msgid "cannot create buffer/window command: object is being deleted"
+msgstr "nie mogę stworzyć bufora/okna komendy: obiekt jest kasowany"
+
+msgid ""
+"cannot register callback command: buffer/window is already being deleted"
+msgstr ""
+"nie mogę zarejestrować wstecznego wywołania komendy: bufor/okno już została "
+"skasowana"
+
+#. This should never happen. Famous last word?
+msgid ""
+"E280: TCL FATAL ERROR: reflist corrupt!? Please report this to vim-dev@vim."
+"org"
+msgstr ""
+"E280: TCL FATALNY BÅÄ„D: reflist zepsuta!? ProszÄ™ zÅ‚ożyć raport o tym na vim-"
+"dev@vim.org"
+
+msgid "cannot register callback command: buffer/window reference not found"
+msgstr ""
+"nie mogę zarejestrować wstecznego wywołania komendy: brak odniesienia do "
+"bufora/okna"
+
+msgid ""
+"E571: Sorry, this command is disabled: the Tcl library could not be loaded."
+msgstr ""
+"E571: Przykro mi, ta komenda jest wyłączona, bo nie można załadować "
+"biblioteki Tcl."
+
+#, c-format
+msgid "E572: exit code %d"
+msgstr "E572: kod wyjścia %d"
+
+msgid "cannot get line"
+msgstr "nie mogę dostać wiersza"
+
+msgid "Unable to register a command server name"
+msgstr "Nie mogę zarejestrować nazwy serwera komend"
+
+msgid "E248: Failed to send command to the destination program"
+msgstr "E248: Wysłanie komendy do programu docelowego nie powiodło się"
+
+#, c-format
+msgid "E573: Invalid server id used: %s"
+msgstr "E573: Użyto niewłaściwego id serwera: %s"
+
+msgid "E251: VIM instance registry property is badly formed. Deleted!"
+msgstr ""
+"E251: wcielenia instancji rejestru Vima jest źle sformowane. Skasowano!"
+
+msgid "Unknown option argument"
+msgstr "Nieznany argument opcji"
+
+msgid "Too many edit arguments"
+msgstr "Zbyt wiele argumentów"
+
+msgid "Argument missing after"
+msgstr "Brak argumentu po"
+
+msgid "Garbage after option argument"
+msgstr "Åšmiecie po argumencie opcji"
+
+msgid "Too many \"+command\", \"-c command\" or \"--cmd command\" arguments"
+msgstr ""
+"Zbyt wiele argumentów \"+komenda\", \"-c komenda\" lub \"--cmd komenda\""
+
+msgid "Invalid argument for"
+msgstr "Niewłaściwy argument dla"
+
+#, c-format
+msgid "%d files to edit\n"
+msgstr "%d plików do edycji\n"
+
+msgid "netbeans is not supported with this GUI\n"
+msgstr "netbeans nie są obsługiwane przez to GUI\n"
+
+msgid "This Vim was not compiled with the diff feature."
+msgstr "Ta wersja Vima nie była skompilowanego z opcją różnic (diff)."
+
+msgid "'-nb' cannot be used: not enabled at compile time\n"
+msgstr "'-nb' - nie może być użyte: nie włączone przy kompilacji\n"
+
+msgid "Attempt to open script file again: \""
+msgstr "Próba ponownego otworzenia pliku skryptu: \""
+
+msgid "Cannot open for reading: \""
+msgstr "Nie mogę otworzyć do odczytu: \""
+
+msgid "Cannot open for script output: \""
+msgstr "Nie mogę otworzyć dla wyjścia skryptu: \""
+
+msgid "Vim: Error: Failure to start gvim from NetBeans\n"
+msgstr "Vim: Błąd: Nie można uruchomić gvim z NetBeans\n"
+
+msgid "Vim: Warning: Output is not to a terminal\n"
+msgstr "Vim: OSTRZEŻENIE: Wyjście nie jest terminalem\n"
+
+msgid "Vim: Warning: Input is not from a terminal\n"
+msgstr "Vim: OSTRZEŻENIE: Wejście nie pochodzi z terminala\n"
+
+#. just in case..
+msgid "pre-vimrc command line"
+msgstr "linia poleceń pre-vimrc"
+
+#, c-format
+msgid "E282: Cannot read from \"%s\""
+msgstr "E282: Nie mogę czytać z \"%s\""
+
+msgid ""
+"\n"
+"More info with: \"vim -h\"\n"
+msgstr ""
+"\n"
+"Dalsze informacje poprzez: \"vim -h\"\n"
+
+msgid "[file ..] edit specified file(s)"
+msgstr "[plik ..] edytuj zadane pliki"
+
+msgid "- read text from stdin"
+msgstr "- czytaj tekst ze stdin"
+
+msgid "-t tag edit file where tag is defined"
+msgstr "-t znacznik edytuj plik, w którym dany znacznik jest zdefiniowany"
+
+msgid "-q [errorfile] edit file with first error"
+msgstr "-q [errorfile] edytuj plik, zawierający pierwszy błąd"
+
+msgid ""
+"\n"
+"\n"
+"Usage:"
+msgstr ""
+"\n"
+"\n"
+"użycie:"
+
+msgid " vim [arguments] "
+msgstr " vim [argumenty]"
+
+msgid ""
+"\n"
+" or:"
+msgstr ""
+"\n"
+" lub:"
+
+msgid ""
+"\n"
+"Where case is ignored prepend / to make flag upper case"
+msgstr ""
+"\n"
+"gdzie wielkość znaków jest ignorowana dodaj na początku / by flaga była "
+"wielkÄ… literÄ…"
+
+msgid ""
+"\n"
+"\n"
+"Arguments:\n"
+msgstr ""
+"\n"
+"\n"
+"Argumenty:\n"
+
+msgid "--\t\t\tOnly file names after this"
+msgstr "--\t\t\tTylko nazwy plików po tym"
+
+msgid "--literal\t\tDon't expand wildcards"
+msgstr "--literal\t\tNie rozwijaj znaków specjalnych"
+
+msgid "-register\t\tRegister this gvim for OLE"
+msgstr "-register\t\tZarejestruj tego gvima w OLE"
+
+msgid "-unregister\t\tUnregister gvim for OLE"
+msgstr "-unregister\t\tWyrejestruj gvima z OLE"
+
+msgid "-g\t\t\tRun using GUI (like \"gvim\")"
+msgstr "-g\t\t\tStartuj w GUI (tak jak \"gvim\")"
+
+msgid "-f or --nofork\tForeground: Don't fork when starting GUI"
+msgstr "-f lub --nofork\tPierwszy plan: Nie wydzielaj przy odpalaniu GUI"
+
+msgid "-v\t\t\tVi mode (like \"vi\")"
+msgstr "-v\t\t\tTryb vi (jak \"vi\")"
+
+msgid "-e\t\t\tEx mode (like \"ex\")"
+msgstr "-e\t\t\tTryb ex (jak \"ex\")"
+
+msgid "-E\t\t\tImproved Ex mode"
+msgstr "-E\t\t\tUsprawniony tryb Ex"
+
+msgid "-s\t\t\tSilent (batch) mode (only for \"ex\")"
+msgstr "-s\t\t\tCichy tryb (tła) (tylko dla \"ex\")"
+
+msgid "-d\t\t\tDiff mode (like \"vimdiff\")"
+msgstr "-d\t\t\tTryb różnic (jak \"vimdiff\")"
+
+msgid "-y\t\t\tEasy mode (like \"evim\", modeless)"
+msgstr "-y\t\t\tTryb łatwy (jak \"evim\", bez trybów)"
+
+msgid "-R\t\t\tReadonly mode (like \"view\")"
+msgstr "-R\t\t\tTryb wyłącznie do odczytu (jak \"view\")"
+
+msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
+msgstr "-Z\t\t\tTryb ograniczenia (jak \"rvim\")"
+
+msgid "-m\t\t\tModifications (writing files) not allowed"
+msgstr "-m\t\t\tModyfikacje (zapisywanie plików) niedozwolone"
+
+msgid "-M\t\t\tModifications in text not allowed"
+msgstr "-M\t\t\tZakaz modyfikacji tekstu"
+
+msgid "-b\t\t\tBinary mode"
+msgstr "-b\t\t\tTryb binarny"
+
+msgid "-l\t\t\tLisp mode"
+msgstr "-l\t\t\tTryb lisp"
+
+msgid "-C\t\t\tCompatible with Vi: 'compatible'"
+msgstr "-C\t\t\tBądź zgodny z Vi: 'compatible'"
+
+msgid "-N\t\t\tNot fully Vi compatible: 'nocompatible'"
+msgstr "-N\t\t\tBądź niezupełnie zgodny z Vi: 'nocompatible'"
+
+msgid "-V[N][fname]\t\tBe verbose [level N] [log messages to fname]"
+msgstr "-V[N][nazwap]\t\tGadatliwy [poziom N] [zapisuj wiadomości do nazwap]"
+
+msgid "-D\t\t\tDebugging mode"
+msgstr "-D\t\t\tTryb odpluskwiania"
+
+msgid "-n\t\t\tNo swap file, use memory only"
+msgstr "-n\t\t\tZamiast pliku wymiany, używaj tylko pamięci"
+
+msgid "-r\t\t\tList swap files and exit"
+msgstr "-r\t\t\tWylicz pliki wymiany i zakończ"
+
+msgid "-r (with file name)\tRecover crashed session"
+msgstr "-r (z nazwą pliku)\tOdtwórz załamaną sesję"
+
+msgid "-L\t\t\tSame as -r"
+msgstr "-L\t\t\tTożsame z -r"
+
+msgid "-f\t\t\tDon't use newcli to open window"
+msgstr "-f\t\t\tNie stosuj newcli do otwierania okien"
+
+msgid "-dev <device>\t\tUse <device> for I/O"
+msgstr "-dev <device>\t\tUżywaj <device> do I/O"
+
+msgid "-A\t\t\tStart in Arabic mode"
+msgstr "-A\t\t\trozpocznij w trybie arabskim"
+
+msgid "-H\t\t\tStart in Hebrew mode"
+msgstr "-H\t\t\trozpocznij w trybie hebrajskim"
+
+msgid "-F\t\t\tStart in Farsi mode"
+msgstr "-F\t\t\trozpocznij w trybie farsi"
+
+msgid "-T <terminal>\tSet terminal type to <terminal>"
+msgstr "-T <terminal>\tUstaw typ terminala na <terminal>"
+
+msgid "-u <vimrc>\t\tUse <vimrc> instead of any .vimrc"
+msgstr "-u <vimrc>\t\tUżyj <vimrc> zamiast jakiegokolwiek .vimrc"
+
+msgid "-U <gvimrc>\t\tUse <gvimrc> instead of any .gvimrc"
+msgstr "-U <gvimrc>\t\tUżyj <gvimrc> zamiast jakiegokolwiek .gvimrc"
+
+msgid "--noplugin\t\tDon't load plugin scripts"
+msgstr "--noplugin\t\tNie ładuj skryptów wtyczek"
+
+msgid "-p[N]\t\tOpen N tab pages (default: one for each file)"
+msgstr "-p[N]\t\tOtwórz N kart (domyślnie: po jednej dla każdego pliku)"
+
+msgid "-o[N]\t\tOpen N windows (default: one for each file)"
+msgstr "-o[N]\t\tOtwórz N okien (domyślnie: po jednym dla każdego pliku)"
+
+msgid "-O[N]\t\tLike -o but split vertically"
+msgstr "-O[N]\t\ttak samo jak -o tylko dziel okno pionowo"
+
+msgid "+\t\t\tStart at end of file"
+msgstr "+\t\t\tZacznij na końcu pliku"
+
+msgid "+<lnum>\t\tStart at line <lnum>"
+msgstr "+<lnum>\t\tZacznij w wierszu <lnum>"
+
+msgid "--cmd <command>\tExecute <command> before loading any vimrc file"
+msgstr ""
+"-cmd <command>\t\tWykonaj komendę <command> przed załadowaniem "
+"jakiegokolwiek pliku vimrc"
+
+msgid "-c <command>\t\tExecute <command> after loading the first file"
+msgstr ""
+"-c <command>\t\tWykonaj komendę <command> po załadowaniu pierwszego pliku"
+
+msgid "-S <session>\t\tSource file <session> after loading the first file"
+msgstr "-S <sesja>\t\tWczytaj plik <sesja> po załadowaniu pierwszego pliku"
+
+msgid "-s <scriptin>\tRead Normal mode commands from file <scriptin>"
+msgstr "-s <scriptin>\tWczytuj komendy trybu normalnego z pliku <scriptin>"
+
+msgid "-w <scriptout>\tAppend all typed commands to file <scriptout>"
+msgstr ""
+"-w <scriptout>\tDołącz wszystkie wprowadzane komendy do pliku <scriptout>"
+
+msgid "-W <scriptout>\tWrite all typed commands to file <scriptout>"
+msgstr ""
+"-W <scriptout>\tZapisuj wszystkie wprowadzane komendy do pliku <scriptout>"
+
+msgid "-x\t\t\tEdit encrypted files"
+msgstr "-x\t\t\tEdytuj zakodowane pliki"
+
+msgid "-display <display>\tConnect vim to this particular X-server"
+msgstr "-display <display>\tPodłącz vima to danego X-serwera"
+
+msgid "-X\t\t\tDo not connect to X server"
+msgstr "-X\t\t\tNie Å‚Ä…cz z serwerem X"
+
+msgid "--remote <files>\tEdit <files> in a Vim server if possible"
+msgstr "--remote <pliki>\tEdytuj pliki w serwerze Vima jeśli możliwe"
+
+msgid "--remote-silent <files> Same, don't complain if there is no server"
+msgstr "--remote-silent <pliki> To samo, nie narzekaj jeśli nie ma serwera"
+
+msgid ""
+"--remote-wait <files> As --remote but wait for files to have been edited"
+msgstr ""
+"--remote-wait <pliki>\tTak jak --remote, lecz czekaj na pliki przed edycjÄ…"
+
+msgid ""
+"--remote-wait-silent <files> Same, don't complain if there is no server"
+msgstr ""
+"--remote-wait-silent <pliki> To samo, nie narzekaj jeśli nie ma serwera"
+
+msgid ""
+"--remote-tab[-wait][-silent] <files> As --remote but use tab page per file"
+msgstr ""
+"--remote-tab[-wait][-silent] <pliki> tak jak --remote ale używa jednej "
+"karty na plik"
+
+msgid "--remote-send <keys>\tSend <keys> to a Vim server and exit"
+msgstr "--remote-send <klawisze>\tWyślij <klawisze> do serwera Vima i zakończ"
+
+msgid "--remote-expr <expr>\tEvaluate <expr> in a Vim server and print result"
+msgstr "--remote-expr <wyr>\tWykonaj <wyrażenie> w serwerze i wypisz wynik"
+
+msgid "--serverlist\t\tList available Vim server names and exit"
+msgstr "--serverlist\t\tWymień nazwy dostępnych serwerów Vima i zakończ"
+
+msgid "--servername <name>\tSend to/become the Vim server <name>"
+msgstr "--servername <nazwa>\t\tOdsyłaj do/stań się serwerem Vim <nazwa>"
+
+msgid "--startuptime <file>\tWrite startup timing messages to <file>"
+msgstr ""
+"--startuptime <plik> "
+"Zapisz wiadomości o długości startu do <plik>"
+
+msgid "-i <viminfo>\t\tUse <viminfo> instead of .viminfo"
+msgstr "-i <viminfo>\t\tUżywaj <viminfo> zamiast .viminfo"
+
+msgid "-h or --help\tPrint Help (this message) and exit"
+msgstr "-h lub --help\twyświetl Pomoc (czyli tę wiadomość) i zakończ"
+
+msgid "--version\t\tPrint version information and exit"
+msgstr "--version\t\twyświetl informację o wersji i zakończ"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Motif version):\n"
+msgstr ""
+"\n"
+"Argumenty rozpoznawane przez gvim (wersja Motif):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (neXtaw version):\n"
+msgstr ""
+"\n"
+"Argumenty rozpoznawane przez gvim (wersja neXtaw):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Athena version):\n"
+msgstr ""
+"\n"
+"Argumenty rozpoznawane przez gvim (wersja Athena):\n"
+
+msgid "-display <display>\tRun vim on <display>"
+msgstr "-display <display>\tZaładuj vim na <display>"
+
+msgid "-iconic\t\tStart vim iconified"
+msgstr "-iconic\t\tZacznij Vim jako ikonÄ™"
+
+msgid "-background <color>\tUse <color> for the background (also: -bg)"
+msgstr "-background <kolor>\tUżywaj <kolor> dla tła (również: -bg)"
+
+msgid "-foreground <color>\tUse <color> for normal text (also: -fg)"
+msgstr ""
+"-foreground <kolor>\tUżywaj <kolor> dla normalnego tekstu (również: -fg)"
+
+msgid "-font <font>\t\tUse <font> for normal text (also: -fn)"
+msgstr "-font <font>\t\tUżywaj <font> dla normalnego tekstu (również: -fn)"
+
+msgid "-boldfont <font>\tUse <font> for bold text"
+msgstr "-boldfont <font>\tUżywaj <font> dla wytłuszczonego tekstu"
+
+msgid "-italicfont <font>\tUse <font> for italic text"
+msgstr "-italicfont <font>\tUżywaj <font> dla pochyłego"
+
+msgid "-geometry <geom>\tUse <geom> for initial geometry (also: -geom)"
+msgstr ""
+"-geometry <geom>\tUżywaj <geom> dla początkowych rozmiarów (również: -geom)"
+
+msgid "-borderwidth <width>\tUse a border width of <width> (also: -bw)"
+msgstr "-borderwidth <szer>\tUżyj ramki o grubości <szer> (również: -bw)"
+
+msgid "-scrollbarwidth <width> Use a scrollbar width of <width> (also: -sw)"
+msgstr ""
+"-scrollbarwidth <szer> Używaj przewijacza o szerokości <szer> (również: -sw)"
+
+msgid "-menuheight <height>\tUse a menu bar height of <height> (also: -mh)"
+msgstr ""
+"-menuheight <height>\tStosuj belkę menu o wysokości <height> (również: -mh)"
+
+msgid "-reverse\t\tUse reverse video (also: -rv)"
+msgstr "-reverse\t\tStosuj negatyw kolorów (również: -rv)"
+
+msgid "+reverse\t\tDon't use reverse video (also: +rv)"
+msgstr "+reverse\t\tNie stosuj negatywu kolorów (również: +rv)"
+
+msgid "-xrm <resource>\tSet the specified resource"
+msgstr "-xrm <resource>\tUstaw określony zasób"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (GTK+ version):\n"
+msgstr ""
+"\n"
+"Argumenty rozpoznawane przez gvim (wersja GTK+):\n"
+
+msgid "-display <display>\tRun vim on <display> (also: --display)"
+msgstr "-display <display>\tZastartuj vim na <display> (również: --display)"
+
+msgid "--role <role>\tSet a unique role to identify the main window"
+msgstr "--role <role>\tUstaw unikatową rolę do identyfikacji głównego okna"
+
+msgid "--socketid <xid>\tOpen Vim inside another GTK widget"
+msgstr "--socketid <xid>\tOtwórz Vim wewnątrz innego widgetu GTK"
+
+msgid "--echo-wid\t\tMake gvim echo the Window ID on stdout"
+msgstr "-echo-wid\t\tGvim wypisze Window ID na wyjście standardowe"
+
+msgid "-P <parent title>\tOpen Vim inside parent application"
+msgstr "-P <tytuł rodzica>\tOtwórz Vima wewnątrz rodzicielskiej aplikacji"
+
+msgid "--windowid <HWND>\tOpen Vim inside another win32 widget"
+msgstr "--windowid <HWND>\tOtwórz Vima wewnątrz innego elementu win32"
+
+msgid "No display"
+msgstr "Brak display"
+
+#. Failed to send, abort.
+msgid ": Send failed.\n"
+msgstr ": Wysłanie nie powiodło się.\n"
+
+#. Let vim start normally.
+msgid ": Send failed. Trying to execute locally\n"
+msgstr ": Wysłanie nie powiodło się. Próbuję wykonać na miejscu\n"
+
+#, c-format
+msgid "%d of %d edited"
+msgstr "otworzono %d z %d"
+
+msgid "No display: Send expression failed.\n"
+msgstr "Brak terminala: Wysłanie wyrażenia nie powiodło się.\n"
+
+msgid ": Send expression failed.\n"
+msgstr ": Wysłanie wyrażenia nie powiodło się.\n"
+
+msgid "No marks set"
+msgstr "Brak zakładek"
+
+#, c-format
+msgid "E283: No marks matching \"%s\""
+msgstr "E283: Żadna zakładka nie pasuje do \"%s\""
+
+#. Highlight title
+msgid ""
+"\n"
+"mark line col file/text"
+msgstr ""
+"\n"
+"zakł. wiersz kol plik/tekst"
+
+#. Highlight title
+msgid ""
+"\n"
+" jump line col file/text"
+msgstr ""
+"\n"
+" skok wiersz kol plik/tekst"
+
+#. Highlight title
+msgid ""
+"\n"
+"change line col text"
+msgstr ""
+"\n"
+"zmień wrsz. kol tekst"
+
+msgid ""
+"\n"
+"# File marks:\n"
+msgstr ""
+"\n"
+"# Zakładki w plikach:\n"
+
+#. Write the jumplist with -'
+msgid ""
+"\n"
+"# Jumplist (newest first):\n"
+msgstr ""
+"\n"
+"# Lista odniesień (począwszy od najnowszych):\n"
+
+msgid ""
+"\n"
+"# History of marks within files (newest to oldest):\n"
+msgstr ""
+"\n"
+"# Historia zakładek w plikach (od najnowszych po najstarsze):\n"
+
+msgid "Missing '>'"
+msgstr "Brak '>'"
+
+msgid "E543: Not a valid codepage"
+msgstr "E543: To nie jest ważna strona kodowa"
+
+msgid "E284: Cannot set IC values"
+msgstr "E284: Nie mogę nastawić wartości IC"
+
+msgid "E285: Failed to create input context"
+msgstr "E285: Nie mogłem stworzyć kontekstu wprowadzeń"
+
+msgid "E286: Failed to open input method"
+msgstr "E286: Nie mogłem otworzyć sposobu wprowadzeń"
+
+msgid "E287: Warning: Could not set destroy callback to IM"
+msgstr "E287: OSTRZEŻENIE: Nie mogłem zlikwidować wywołania dla IM"
+
+msgid "E288: input method doesn't support any style"
+msgstr "E288: metoda wprowadzeń nie wspomaga żadnego stylu"
+
+msgid "E289: input method doesn't support my preedit type"
+msgstr "E289: metoda wprowadzeń nie wspomaga mojego typu preedit"
+
+msgid "E293: block was not locked"
+msgstr "E293: blok nie był zablokowany"
+
+msgid "E294: Seek error in swap file read"
+msgstr "E294: BÅ‚Ä…d w trakcie czytania pliku wymiany"
+
+msgid "E295: Read error in swap file"
+msgstr "E295: BÅ‚Ä…d odczytu pliku wymiany"
+
+msgid "E296: Seek error in swap file write"
+msgstr "E296: BÅ‚Ä…d szukania w pliku wymiany"
+
+msgid "E297: Write error in swap file"
+msgstr "E297: BÅ‚Ä…d zapisu w pliku wymiany"
+
+msgid "E300: Swap file already exists (symlink attack?)"
+msgstr "E300: Plik wymiany już istnieje (atak symlink?)"
+
+msgid "E298: Didn't get block nr 0?"
+msgstr "E298: Nie otrzymałem bloku nr 0?"
+
+msgid "E298: Didn't get block nr 1?"
+msgstr "E298: Nie otrzymałem bloku nr 1?"
+
+msgid "E298: Didn't get block nr 2?"
+msgstr "E298: Nie otrzymałem bloku nr 2?"
+
+msgid "E843: Error while updating swap file crypt"
+msgstr "E843: BÅ‚Ä…d w czasie uaktualniania szyfrowania pliku wymiany"
+
+#. could not (re)open the swap file, what can we do????
+msgid "E301: Oops, lost the swap file!!!"
+msgstr "E301: Ojej, zgubiłem plik wymiany!!!"
+
+msgid "E302: Could not rename swap file"
+msgstr "E302: Nie mogłem zmienić nazwy pliku wymiany"
+
+#, c-format
+msgid "E303: Unable to open swap file for \"%s\", recovery impossible"
+msgstr ""
+"E303: Nie mogę otworzyć pliku wymiany dla \"%s\"; odtworzenie niemożliwe"
+
+msgid "E304: ml_upd_block0(): Didn't get block 0??"
+msgstr "E304: ml_upd_block(): Nie otrzymałem bloku 0??"
+
+#, c-format
+msgid "E305: No swap file found for %s"
+msgstr "E305: Nie znaleziono pliku wymiany dla %s"
+
+msgid "Enter number of swap file to use (0 to quit): "
+msgstr "Wprowadź numer pliku wymiany, którego użyć (0 by wyjść): "
+
+#, c-format
+msgid "E306: Cannot open %s"
+msgstr "E306: Nie mogę otworzyć %s"
+
+msgid "Unable to read block 0 from "
+msgstr "Nie mogę odczytać bloku 0 z "
+
+msgid ""
+"\n"
+"Maybe no changes were made or Vim did not update the swap file."
+msgstr ""
+"\n"
+"Może nie wykonano zmian albo Vim nie zaktualizował pliku wymiany."
+
+msgid " cannot be used with this version of Vim.\n"
+msgstr " nie może być stosowany z tą wersją Vima.\n"
+
+msgid "Use Vim version 3.0.\n"
+msgstr "Użyj Vima w wersji 3.0.\n"
+
+#, c-format
+msgid "E307: %s does not look like a Vim swap file"
+msgstr "E307: %s nie wyglÄ…da na plik wymiany Vima"
+
+msgid " cannot be used on this computer.\n"
+msgstr " nie może być stosowany na tym komputerze.\n"
+
+msgid "The file was created on "
+msgstr "Ten plik został stworzony na "
+
+msgid ""
+",\n"
+"or the file has been damaged."
+msgstr ""
+",\n"
+"lub plik został uszkodzony."
+
+#, c-format
+msgid ""
+"E833: %s is encrypted and this version of Vim does not support encryption"
+msgstr "E833: %s jest zaszyfrowany a ta wersja Vima nie wspiera szyfrowania"
+
+msgid " has been damaged (page size is smaller than minimum value).\n"
+msgstr ""
+" został uszkodzony (wielkość strony jest mniejsza niż najmniejsza wartość).\n"
+
+#, c-format
+msgid "Using swap file \"%s\""
+msgstr "Używam pliku wymiany \"%s\""
+
+#, c-format
+msgid "Original file \"%s\""
+msgstr "Oryginalny plik \"%s\""
+
+msgid "E308: Warning: Original file may have been changed"
+msgstr "E308: OSTRZEŻENIE: Oryginalny plik mógł być zmieniony"
+
+#, c-format
+msgid "Swap file is encrypted: \"%s\""
+msgstr "Zaszyfrowany plik wymiany: \"%s\""
+
+msgid ""
+"\n"
+"If you entered a new crypt key but did not write the text file,"
+msgstr ""
+"\n"
+"Jeśli podano nowy klucz szyfrujący, ale nie zapisano pliku tekstowego,"
+
+msgid ""
+"\n"
+"enter the new crypt key."
+msgstr ""
+"\n"
+"wprowadź nowy klucz szyfrujący."
+
+msgid ""
+"\n"
+"If you wrote the text file after changing the crypt key press enter"
+msgstr ""
+"\n"
+"Jeśli zapisano plik tekstowy po zmianie klucza szyfrującego wciśnij Enter"
+
+msgid ""
+"\n"
+"to use the same key for text file and swap file"
+msgstr ""
+"\n"
+"aby użyć tego samego klucza dla pliku tekstowego i wymiany"
+
+#, c-format
+msgid "E309: Unable to read block 1 from %s"
+msgstr "E309: Nie mogę odczytać bloku 1 z %s"
+
+msgid "???MANY LINES MISSING"
+msgstr "???BRAKUJE WIELU WIERSZY"
+
+msgid "???LINE COUNT WRONG"
+msgstr "???LICZNIK WIERSZY NIEZGODNY"
+
+msgid "???EMPTY BLOCK"
+msgstr "???PUSTY BLOK"
+
+msgid "???LINES MISSING"
+msgstr "???BRAKUJE WIERSZY"
+
+#, c-format
+msgid "E310: Block 1 ID wrong (%s not a .swp file?)"
+msgstr "E310: Niewłaściwe ID bloku 1 (może %s nie jest plikiem .swp?)"
+
+msgid "???BLOCK MISSING"
+msgstr "???BRAK BLOKU"
+
+msgid "??? from here until ???END lines may be messed up"
+msgstr "??? od tego miejsca po ???KONIEC wiersze mogą być pomieszane"
+
+msgid "??? from here until ???END lines may have been inserted/deleted"
+msgstr "??? od tego miejsca po ???KONIEC wiersze mogą być włożone/skasowane"
+
+msgid "???END"
+msgstr "???KONIEC"
+
+msgid "E311: Recovery Interrupted"
+msgstr "E311: Przerwanie odtwarzania"
+
+msgid ""
+"E312: Errors detected while recovering; look for lines starting with ???"
+msgstr "E312: Wykryto błędy podczas odtwarzania; od których wierszy zacząć ???"
+
+msgid "See \":help E312\" for more information."
+msgstr "Zobacz \":help E312\" dla dalszych informacji."
+
+msgid "Recovery completed. You should check if everything is OK."
+msgstr ""
+"Odtwarzanie zakończono. Powinieneś sprawdzić czy wszystko jest w porządku."
+
+msgid ""
+"\n"
+"(You might want to write out this file under another name\n"
+msgstr ""
+"\n"
+"(Możesz chcieć zapisać ten plik pod inną nazwą\n"
+
+msgid "and run diff with the original file to check for changes)"
+msgstr "i wykonać diff z oryginalnym plikiem aby sprawdzić zmiany)"
+
+msgid "Recovery completed. Buffer contents equals file contents."
+msgstr "Odzyskiwanie zakończone. Zawartość bufora jest równa zawartości pliku."
+
+msgid ""
+"\n"
+"You may want to delete the .swp file now.\n"
+"\n"
+msgstr ""
+"\n"
+"Możesz teraz chcieć usunąć plik .swp.\n"
+"\n"
+
+msgid "Using crypt key from swap file for the text file.\n"
+msgstr "Używam klucza szyfrującego z pliku wymiany do pliku tekstowego.\n"
+
+#. use msg() to start the scrolling properly
+msgid "Swap files found:"
+msgstr "Znalezione pliki wymiany:"
+
+msgid " In current directory:\n"
+msgstr " W bieżącym katalogu:\n"
+
+msgid " Using specified name:\n"
+msgstr " Używam podanej nazwy:\n"
+
+msgid " In directory "
+msgstr " W katalogu "
+
+msgid " -- none --\n"
+msgstr " -- żaden --\n"
+
+msgid " owned by: "
+msgstr " posiadany przez: "
+
+msgid " dated: "
+msgstr " data: "
+
+msgid " dated: "
+msgstr " data: "
+
+msgid " [from Vim version 3.0]"
+msgstr " [po Vimie wersja 3.0]"
+
+msgid " [does not look like a Vim swap file]"
+msgstr " [nie wyglÄ…da na plik wymiany Vima]"
+
+msgid " file name: "
+msgstr " nazwa pliku: "
+
+msgid ""
+"\n"
+" modified: "
+msgstr ""
+"\n"
+" zmieniono: "
+
+msgid "YES"
+msgstr "TAK"
+
+msgid "no"
+msgstr "nie"
+
+msgid ""
+"\n"
+" user name: "
+msgstr ""
+"\n"
+" użytkownik: "
+
+msgid " host name: "
+msgstr " nazwa hosta: "
+
+msgid ""
+"\n"
+" host name: "
+msgstr ""
+"\n"
+" nazwa hosta: "
+
+msgid ""
+"\n"
+" process ID: "
+msgstr ""
+"\n"
+" ID procesu: "
+
+msgid " (still running)"
+msgstr " (dalej działa)"
+
+msgid ""
+"\n"
+" [not usable with this version of Vim]"
+msgstr ""
+"\n"
+" [nie nadaje siÄ™ dla tej wersji Vima]"
+
+msgid ""
+"\n"
+" [not usable on this computer]"
+msgstr ""
+"\n"
+" [nie do użytku na tym komputerze]"
+
+msgid " [cannot be read]"
+msgstr " [nieodczytywalny]"
+
+msgid " [cannot be opened]"
+msgstr " [nieotwieralny]"
+
+msgid "E313: Cannot preserve, there is no swap file"
+msgstr "E313: Nie mogę zabezpieczyć, bo brak pliku wymiany"
+
+msgid "File preserved"
+msgstr "Plik zabezpieczono"
+
+msgid "E314: Preserve failed"
+msgstr "E314: Nieudane zabezpieczenie"
+
+#, c-format
+msgid "E315: ml_get: invalid lnum: %ld"
+msgstr "E315: ml_get: niewłaściwy lnum: %ld"
+
+#, c-format
+msgid "E316: ml_get: cannot find line %ld"
+msgstr "E316: ml_get: nie znaleziono wiersza %ld"
+
+msgid "E317: pointer block id wrong 3"
+msgstr "E317: niepoprawne id wskaźnika bloku 3"
+
+msgid "stack_idx should be 0"
+msgstr "stack_idx powinien być 0"
+
+msgid "E318: Updated too many blocks?"
+msgstr "E318: Zaktualizowano zbyt wiele bloków?"
+
+msgid "E317: pointer block id wrong 4"
+msgstr "E317: niepoprawne id wskaźnika bloku 4"
+
+msgid "deleted block 1?"
+msgstr "blok nr 1 skasowany?"
+
+#, c-format
+msgid "E320: Cannot find line %ld"
+msgstr "E320: Nie mogę znaleźć wiersza %ld"
+
+msgid "E317: pointer block id wrong"
+msgstr "E317: niepoprawne id bloku odniesienia"
+
+msgid "pe_line_count is zero"
+msgstr "pe_line_count wynosi zero"
+
+#, c-format
+msgid "E322: line number out of range: %ld past the end"
+msgstr "E322: numer wiersza poza zakresem: %ld jest poza końcem"
+
+#, c-format
+msgid "E323: line count wrong in block %ld"
+msgstr "E323: liczba wierszy niepoprawna w bloku %ld"
+
+msgid "Stack size increases"
+msgstr "Wielkość stosu wzrasta"
+
+msgid "E317: pointer block id wrong 2"
+msgstr "E317: niepoprawne id bloku odniesienia 2"
+
+#, c-format
+msgid "E773: Symlink loop for \"%s\""
+msgstr "E773: Pętla dowiązań dla \"%s\""
+
+msgid "E325: ATTENTION"
+msgstr "E325: UWAGA"
+
+msgid ""
+"\n"
+"Found a swap file by the name \""
+msgstr ""
+"\n"
+"Znalazłem plik wymiany o nazwie \""
+
+msgid "While opening file \""
+msgstr "Podczas otwierania pliku \""
+
+msgid " NEWER than swap file!\n"
+msgstr " NOWSZE od pliku wymiany!\n"
+
+#. Some of these messages are long to allow translation to
+#. * other languages.
+msgid ""
+"\n"
+"(1) Another program may be editing the same file. If this is the case,\n"
+" be careful not to end up with two different instances of the same\n"
+" file when making changes.\n"
+msgstr ""
+"\n"
+"(1) Pewnie inny program obrabia ten sam plik.\n"
+" Jeśli tak, bądź ostrożny, aby nie skończyć z dwoma\n"
+" różnymi wersjami tego samego pliku po zmianach.\n"
+
+msgid " Quit, or continue with caution.\n"
+msgstr " Zakończ lub ostrożnie kontynuuj.\n"
+
+msgid "(2) An edit session for this file crashed.\n"
+msgstr "(2) Sesja edycji dla pliku załamała się.\n"
+
+msgid " If this is the case, use \":recover\" or \"vim -r "
+msgstr " Jeśli tak, to użyj \":recover\" lub \"vim -r "
+
+msgid ""
+"\"\n"
+" to recover the changes (see \":help recovery\").\n"
+msgstr ""
+"\"\n"
+" aby odzyskać zmiany (zobacz \":help recovery)\").\n"
+
+msgid " If you did this already, delete the swap file \""
+msgstr " Jeśli już to zrobiłeś, usuń plik wymiany \""
+
+msgid ""
+"\"\n"
+" to avoid this message.\n"
+msgstr ""
+"\"\n"
+" aby uniknąć tej wiadomości.\n"
+
+msgid "Swap file \""
+msgstr "Plik wymiany \""
+
+msgid "\" already exists!"
+msgstr "\" już istnieje!"
+
+msgid "VIM - ATTENTION"
+msgstr "VIM - UWAGA"
+
+msgid "Swap file already exists!"
+msgstr "Plik wymiany już istnieje!"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"&Otwórz Read-Only\n"
+"&Edytuj pomimo\n"
+"O&dtwórz\n"
+"&Zakończ\n"
+"&Porzuć"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Delete it\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"&Otwórz Read-Only\n"
+"&Edytuj pomimo\n"
+"O&dtwórz\n"
+"&Usuń\n"
+"&Zakończ\n"
+"&Porzuć"
+
+msgid "E326: Too many swap files found"
+msgstr "E326: Znaleziono zbyt wiele plików wymiany"
+
+msgid "E327: Part of menu-item path is not sub-menu"
+msgstr "E327: Część tropu punktu menu nie określa podmenu"
+
+msgid "E328: Menu only exists in another mode"
+msgstr "E328: Menu istnieje tylko w innym trybie"
+
+#, c-format
+msgid "E329: No menu \"%s\""
+msgstr "E329: Nie ma menu \"%s\""
+
+#. Only a mnemonic or accelerator is not valid.
+msgid "E792: Empty menu name"
+msgstr "E792: Pusta nazwa menu"
+
+msgid "E330: Menu path must not lead to a sub-menu"
+msgstr "E330: Trop menu nie może prowadzić do podmenu"
+
+msgid "E331: Must not add menu items directly to menu bar"
+msgstr "E331: Nie wolno dodawać punktów menu wprost do paska menu"
+
+msgid "E332: Separator cannot be part of a menu path"
+msgstr "E332: Separator nie może być częścią tropu menu"
+
+#. Now we have found the matching menu, and we list the mappings
+#. Highlight title
+msgid ""
+"\n"
+"--- Menus ---"
+msgstr ""
+"\n"
+"--- Menu ---"
+
+msgid "Tear off this menu"
+msgstr "Oderwij to menu"
+
+msgid "E333: Menu path must lead to a menu item"
+msgstr "E333: Trop menu musi prowadzić do punktu menu"
+
+#, c-format
+msgid "E334: Menu not found: %s"
+msgstr "E334: Nie znaleziono menu: %s"
+
+#, c-format
+msgid "E335: Menu not defined for %s mode"
+msgstr "E335: Menu nie jest zdefiniowane dla trybu %s"
+
+msgid "E336: Menu path must lead to a sub-menu"
+msgstr "E336: Trop menu musi prowadzić do podmenu"
+
+msgid "E337: Menu not found - check menu names"
+msgstr "E337: Nie znaleziono menu - sprawdź nazwy menu"
+
+#, c-format
+msgid "Error detected while processing %s:"
+msgstr "Wykryto błąd podczas przetwarzania %s:"
+
+#, c-format
+msgid "line %4ld:"
+msgstr "wiersz %4ld:"
+
+#, c-format
+msgid "E354: Invalid register name: '%s'"
+msgstr "E354: Niewłaściwa nazwa rejestru: '%s'"
+
+msgid "Messages maintainer: Bram Moolenaar <Bram@vim.org>"
+msgstr "Opiekun komunikatów: Mikołaj Machowski <mikmach@wp.pl>"
+
+msgid "Interrupt: "
+msgstr "Przerwanie: "
+
+msgid "Press ENTER or type command to continue"
+msgstr "Naciśnij ENTER lub wprowadź komendę aby kontynuować"
+
+#, c-format
+msgid "%s line %ld"
+msgstr "%s wiersz %ld"
+
+msgid "-- More --"
+msgstr "-- Więcej --"
+
+msgid " SPACE/d/j: screen/page/line down, b/u/k: up, q: quit "
+msgstr " SPACE/d/j: ekran/strona/wiersz w dół, b/u/k: do góry, q: zakończ"
+
+msgid "Question"
+msgstr "Pytanie"
+
+msgid ""
+"&Yes\n"
+"&No"
+msgstr ""
+"&Tak\n"
+"&Nie"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"Save &All\n"
+"&Discard All\n"
+"&Cancel"
+msgstr ""
+"&Tak\n"
+"&Nie\n"
+"Zapisz &wszystkie\n"
+"&Odrzuć wszystkie\n"
+"&Zakończ"
+
+msgid "Select Directory dialog"
+msgstr "Dialog wyboru katalogu"
+
+msgid "Save File dialog"
+msgstr "Dialog zapisywania pliku"
+
+msgid "Open File dialog"
+msgstr "Dialog otwierania pliku"
+
+#. TODO: non-GUI file selector here
+msgid "E338: Sorry, no file browser in console mode"
+msgstr "E338: Przykro mi, nie ma przeglądarki plików w trybie konsoli"
+
+msgid "E766: Insufficient arguments for printf()"
+msgstr "E766: Za mało argumentów dla printf()"
+
+msgid "E807: Expected Float argument for printf()"
+msgstr "E807: Spodziewany argument Zmiennoprzecinkowy w printf()"
+
+msgid "E767: Too many arguments to printf()"
+msgstr "E767: Za dużo argumentów dla printf()"
+
+msgid "W10: Warning: Changing a readonly file"
+msgstr "W10: OSTRZEŻENIE: Zmiany w pliku tylko do odczytu"
+
+msgid "Type number and <Enter> or click with mouse (empty cancels): "
+msgstr "Wpisz numer i <Enter> lub wybierz myszą (pusta wartość anuluje): "
+
+msgid "Type number and <Enter> (empty cancels): "
+msgstr "Wpisz numer i <Enter> (puste anuluje): "
+
+msgid "1 more line"
+msgstr "1 wiersz więcej"
+
+msgid "1 line less"
+msgstr "1 wiersz mniej"
+
+#, c-format
+msgid "%ld more lines"
+msgstr "dodano %ld wierszy"
+
+#, c-format
+msgid "%ld fewer lines"
+msgstr "usunięto %ld wierszy"
+
+msgid " (Interrupted)"
+msgstr " (Przerwane)"
+
+msgid "Beep!"
+msgstr "Biiip!"
+
+msgid "Vim: preserving files...\n"
+msgstr "Vim: zachowujÄ™ plik...\n"
+
+#. close all memfiles, without deleting
+msgid "Vim: Finished.\n"
+msgstr "Vim: Zakończono.\n"
+
+msgid "ERROR: "
+msgstr "BÅÄ„D: "
+
+#, c-format
+msgid ""
+"\n"
+"[bytes] total alloc-freed %lu-%lu, in use %lu, peak use %lu\n"
+msgstr ""
+"\n"
+"[bajtów] totalne alokacje-zwolnienia %lu-%lu, w użytku %lu, maksymalne "
+"użycie %lu\n"
+
+#, c-format
+msgid ""
+"[calls] total re/malloc()'s %lu, total free()'s %lu\n"
+"\n"
+msgstr ""
+"[wywołania] wszystkich re/malloc()-ów %lu, wszystkich free()-ów %lu\n"
+"\n"
+
+msgid "E340: Line is becoming too long"
+msgstr "E340: Wiersz staje się zbyt długi"
+
+#, c-format
+msgid "E341: Internal error: lalloc(%ld, )"
+msgstr "E341: Wewnętrzny błąd: lalloc(%ld, )"
+
+#, c-format
+msgid "E342: Out of memory! (allocating %lu bytes)"
+msgstr "E342: Brak pamięci! (rezerwacja %lu bajtów)"
+
+#, c-format
+msgid "Calling shell to execute: \"%s\""
+msgstr "Wywołuję powłokę do wykonania: \"%s\""
+
+msgid "E545: Missing colon"
+msgstr "E545: Brak dwukropka"
+
+msgid "E546: Illegal mode"
+msgstr "E546: Niedozwolony tryb"
+
+msgid "E547: Illegal mouseshape"
+msgstr "E547: Niedozwolony obrys myszki"
+
+msgid "E548: digit expected"
+msgstr "E548: oczekiwałem na cyfrę"
+
+msgid "E549: Illegal percentage"
+msgstr "E549: Niedozwolony procent"
+
+msgid "Enter encryption key: "
+msgstr "Wprowadź klucz do odkodowania: "
+
+msgid "Enter same key again: "
+msgstr "Wprowadź ponownie ten sam klucz: "
+
+msgid "Keys don't match!"
+msgstr "Klucze nie pasujÄ… do siebie!"
+
+msgid "E854: path too long for completion"
+msgstr "E854: ścieżka za długa by uzupełnić"
+
+#, c-format
+msgid ""
+"E343: Invalid path: '**[number]' must be at the end of the path or be "
+"followed by '%s'."
+msgstr ""
+"E343: Niewłaściwy trop: '**[numer]' musi być na końcu tropu lub po nim musi "
+"być '%s'."
+
+#, c-format
+msgid "E344: Can't find directory \"%s\" in cdpath"
+msgstr "E344: Nie mogę znaleźć katalogu \"%s\" w cdpath"
+
+#, c-format
+msgid "E345: Can't find file \"%s\" in path"
+msgstr "E345: Nie mogę znaleźć pliku \"%s\" w tropie"
+
+#, c-format
+msgid "E346: No more directory \"%s\" found in cdpath"
+msgstr "E346: Katalogu \"%s\" nie ma więcej w cdpath"
+
+#, c-format
+msgid "E347: No more file \"%s\" found in path"
+msgstr "E347: Pliku \"%s\" nie ma więcej w tropie"
+
+msgid "Cannot connect to Netbeans #2"
+msgstr "Nie można połączyć z Netbeans #2"
+
+msgid "Cannot connect to Netbeans"
+msgstr "Nie można połączyć z Netbeans"
+
+#, c-format
+msgid "E668: Wrong access mode for NetBeans connection info file: \"%s\""
+msgstr "E668: Błędny tryb dostępu pliku info połączenia NetBeans: \"%s\""
+
+msgid "read from Netbeans socket"
+msgstr "odczyt z gniazda Netbeans"
+
+#, c-format
+msgid "E658: NetBeans connection lost for buffer %ld"
+msgstr "E658: Bufor %ld utracił połączenie z NetBeans"
+
+msgid "E838: netbeans is not supported with this GUI"
+msgstr "E838: netbeans nie są obsługiwane przez to GUI"
+
+msgid "E511: netbeans already connected"
+msgstr "E511: netbeans już podłączone"
+
+#, c-format
+msgid "E505: %s is read-only (add ! to override)"
+msgstr "E505: %s jest tylko do odczytu (dodaj ! aby wymusić)"
+
+msgid "E349: No identifier under cursor"
+msgstr "E349: Brak identyfikatora pod kursorem"
+
+msgid "E774: 'operatorfunc' is empty"
+msgstr "E774: 'operatorfunc' jest pusta"
+
+msgid "E775: Eval feature not available"
+msgstr "E775: Funkcjonalność eval nie jest dostępna"
+
+msgid "Warning: terminal cannot highlight"
+msgstr "OSTRZEŻENIE: terminal nie wykonuje podświetlania"
+
+msgid "E348: No string under cursor"
+msgstr "E348: Brak ciÄ…gu pod kursorem"
+
+msgid "E352: Cannot erase folds with current 'foldmethod'"
+msgstr "E352: Nie mogę skasować zwinięcia z bieżącą 'foldmethod'"
+
+msgid "E664: changelist is empty"
+msgstr "E664: lista zmian (changelist) jest pusta"
+
+msgid "E662: At start of changelist"
+msgstr "E662: Na poczÄ…tku listy zmian"
+
+msgid "E663: At end of changelist"
+msgstr "E663: Na końcu listy zmian"
+
+msgid "Type :quit<Enter> to exit Vim"
+msgstr "wprowadź :quit<Enter> zakończenie programu"
+
+#, c-format
+msgid "1 line %sed 1 time"
+msgstr "1 wiersz %sed 1 raz"
+
+#, c-format
+msgid "1 line %sed %d times"
+msgstr "1 wiersz %sed %d razy"
+
+#, c-format
+msgid "%ld lines %sed 1 time"
+msgstr "%ld wierszy %sed 1 raz"
+
+#, c-format
+msgid "%ld lines %sed %d times"
+msgstr "%ld wierszy %sed %d razy"
+
+#, c-format
+msgid "%ld lines to indent... "
+msgstr "%ld wierszy do wcięcia... "
+
+msgid "1 line indented "
+msgstr "1 wiersz wcięty "
+
+#, c-format
+msgid "%ld lines indented "
+msgstr "%ld wierszy wciętych "
+
+msgid "E748: No previously used register"
+msgstr "E748: Brak poprzednio użytego rejestru"
+
+#. must display the prompt
+msgid "cannot yank; delete anyway"
+msgstr "nie mogę skopiować, mimo to kasuję"
+
+msgid "1 line changed"
+msgstr "1 wiersz zmieniono"
+
+#, c-format
+msgid "%ld lines changed"
+msgstr "%ld wierszy zmieniono"
+
+#, c-format
+msgid "freeing %ld lines"
+msgstr "zwalniam %ld wierszy"
+
+msgid "block of 1 line yanked"
+msgstr "skopiowano blok 1 wiersza"
+
+msgid "1 line yanked"
+msgstr "1 wiersz skopiowano"
+
+#, c-format
+msgid "block of %ld lines yanked"
+msgstr "%ld wierszy skopiowanych"
+
+#, c-format
+msgid "%ld lines yanked"
+msgstr "%ld wierszy skopiowanych"
+
+#, c-format
+msgid "E353: Nothing in register %s"
+msgstr "E353: Pusty rejestr %s"
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Registers ---"
+msgstr ""
+"\n"
+"--- Rejestry ---"
+
+msgid "Illegal register name"
+msgstr "Niedozwolona nazwa rejestru"
+
+msgid ""
+"\n"
+"# Registers:\n"
+msgstr ""
+"\n"
+"# Rejestry:\n"
+
+#, c-format
+msgid "E574: Unknown register type %d"
+msgstr "E574: Nieznany typ rejestru %d"
+
+#, c-format
+msgid "%ld Cols; "
+msgstr "%ld Kolumn; "
+
+#, c-format
+msgid "Selected %s%ld of %ld Lines; %ld of %ld Words; %ld of %ld Bytes"
+msgstr "Wybrano %s%ld z %ld Wierszy; %ld z %ld Słów; %ld z %ld Bajtów"
+
+#, c-format
+msgid ""
+"Selected %s%ld of %ld Lines; %ld of %ld Words; %ld of %ld Chars; %ld of %ld "
+"Bytes"
+msgstr ""
+"Wybrano %s%ld z %ld Wierszy; %ld z %ld Słów; %ld z %ld Znaków; %ld z %ld "
+"Bajtów"
+
+#, c-format
+msgid "Col %s of %s; Line %ld of %ld; Word %ld of %ld; Byte %ld of %ld"
+msgstr "Kol %s z %s; Wiersz %ld z %ld; SÅ‚owo %ld z %ld; Bajt %ld z %ld"
+
+#, c-format
+msgid ""
+"Col %s of %s; Line %ld of %ld; Word %ld of %ld; Char %ld of %ld; Byte %ld of "
+"%ld"
+msgstr ""
+"Kol %s z %s; Wiersz %ld z %ld; SÅ‚owo %ld z %ld; Znak %ld z %ld; Bajt %ld z "
+"%ld"
+
+#, c-format
+msgid "(+%ld for BOM)"
+msgstr "(+%ld dla BOM)"
+
+msgid "%<%f%h%m%=Page %N"
+msgstr "%<%f%h%m%=Strona %N"
+
+msgid "Thanks for flying Vim"
+msgstr "Dzięki za lot Vimem"
+
+msgid "E518: Unknown option"
+msgstr "E518: Nieznana opcja"
+
+msgid "E519: Option not supported"
+msgstr "E519: Opcja nie jest wspomagana"
+
+msgid "E520: Not allowed in a modeline"
+msgstr "E520: Niedozwolone w modeline"
+
+msgid "E846: Key code not set"
+msgstr "E846: Kod klucza nie jest ustawiony"
+
+msgid "E521: Number required after ="
+msgstr "E521: Po = wymagany jest numer"
+
+msgid "E522: Not found in termcap"
+msgstr "E522: Nie znaleziono w termcap"
+
+#, c-format
+msgid "E539: Illegal character <%s>"
+msgstr "E539: Niedozwolony znak <%s>"
+
+msgid "E529: Cannot set 'term' to empty string"
+msgstr "E529: Nie mogę ustawić 'term' na pusty ciąg"
+
+msgid "E530: Cannot change term in GUI"
+msgstr "E530: Nie mogę zmienić term w GUI"
+
+msgid "E531: Use \":gui\" to start the GUI"
+msgstr "E531: Użyj \":gui\" do odpalenia GUI"
+
+msgid "E589: 'backupext' and 'patchmode' are equal"
+msgstr "E589: 'backupext' i 'patchmode' są tożsame"
+
+msgid "E834: Conflicts with value of 'listchars'"
+msgstr "E834: Konflikty wartości 'listchars'"
+
+msgid "E835: Conflicts with value of 'fillchars'"
+msgstr "E835: Konflikty wartości 'fillchars'"
+
+msgid "E617: Cannot be changed in the GTK+ 2 GUI"
+msgstr "E617: Nie mogę zmienić w GTK+2 GUI"
+
+msgid "E524: Missing colon"
+msgstr "E524: Brak dwukropka"
+
+msgid "E525: Zero length string"
+msgstr "E525: Ciąg o zerowej długości"
+
+#, c-format
+msgid "E526: Missing number after <%s>"
+msgstr "E526: Brak numeru po <%s>"
+
+msgid "E527: Missing comma"
+msgstr "E527: Brak przecinka"
+
+msgid "E528: Must specify a ' value"
+msgstr "E528: Musi określać wartość '"
+
+msgid "E595: contains unprintable or wide character"
+msgstr "E595: zawiera niewyświetlalny lub szeroki znak"
+
+msgid "E596: Invalid font(s)"
+msgstr "E596: Niedozwolona czcionka/ki"
+
+msgid "E597: can't select fontset"
+msgstr "E597: nie mogę wybrać zestawu czcionek"
+
+msgid "E598: Invalid fontset"
+msgstr "E598: Niedozwolony zestaw czcionek"
+
+msgid "E533: can't select wide font"
+msgstr "E533: nie mogę wybrać szerokiej czcionki"
+
+msgid "E534: Invalid wide font"
+msgstr "E534: Niedozwolona szeroka czcionka"
+
+#, c-format
+msgid "E535: Illegal character after <%c>"
+msgstr "E535: Niedozwolony znak po <%c>"
+
+msgid "E536: comma required"
+msgstr "E536: wymagany przecinek"
+
+#, c-format
+msgid "E537: 'commentstring' must be empty or contain %s"
+msgstr "E537: 'commentstring' musi być pusty lub zawierać %s"
+
+msgid "E538: No mouse support"
+msgstr "E538: Brak wspomagania myszki"
+
+msgid "E540: Unclosed expression sequence"
+msgstr "E540: Niedomknięty ciąg wyrażeń"
+
+msgid "E541: too many items"
+msgstr "E541: zbyt wiele elementów"
+
+msgid "E542: unbalanced groups"
+msgstr "E542: niezbalansowane grupy"
+
+msgid "E590: A preview window already exists"
+msgstr "E590: okno podglądu już istnieje"
+
+msgid "W17: Arabic requires UTF-8, do ':set encoding=utf-8'"
+msgstr "W17: Arabski wymaga UTF-8, zrób ':set encoding=utf-8'"
+
+#, c-format
+msgid "E593: Need at least %d lines"
+msgstr "E593: PotrzebujÄ™ przynajmniej %d wierszy"
+
+#, c-format
+msgid "E594: Need at least %d columns"
+msgstr "E594: PotrzebujÄ™ przynajmniej %d kolumn"
+
+#, c-format
+msgid "E355: Unknown option: %s"
+msgstr "E355: Nieznana opcja: %s"
+
+#. There's another character after zeros or the string
+#. * is empty. In both cases, we are trying to set a
+#. * num option using a string.
+#, c-format
+msgid "E521: Number required: &%s = '%s'"
+msgstr "E521: Wymagana Liczba: &%s = '%s'"
+
+msgid ""
+"\n"
+"--- Terminal codes ---"
+msgstr ""
+"\n"
+"--- Kody terminala ---"
+
+msgid ""
+"\n"
+"--- Global option values ---"
+msgstr ""
+"\n"
+"--- Globalne wartości opcji ---"
+
+msgid ""
+"\n"
+"--- Local option values ---"
+msgstr ""
+"\n"
+"--- Lokalne wartości opcji ---"
+
+msgid ""
+"\n"
+"--- Options ---"
+msgstr ""
+"\n"
+"--- Opcje ---"
+
+msgid "E356: get_varp ERROR"
+msgstr "E356: BÅÄ„D get_varp"
+
+#, c-format
+msgid "E357: 'langmap': Matching character missing for %s"
+msgstr "E357: 'langmap': Brak pasujÄ…cego znaku dla %s"
+
+#, c-format
+msgid "E358: 'langmap': Extra characters after semicolon: %s"
+msgstr "E358: 'langmap': Dodatkowe znaki po średniku: %s"
+
+msgid "cannot open "
+msgstr "nie mogę otworzyć "
+
+msgid "VIM: Can't open window!\n"
+msgstr "VIM: Nie mogę otworzyć okna!\n"
+
+msgid "Need Amigados version 2.04 or later\n"
+msgstr "Potrzebuję Amigados w wersji 2.04 lub późniejszą\n"
+
+#, c-format
+msgid "Need %s version %ld\n"
+msgstr "PotrzebujÄ™ %s w wersji %ld\n"
+
+msgid "Cannot open NIL:\n"
+msgstr "Nie mogę otworzyć NIL:\n"
+
+msgid "Cannot create "
+msgstr "Nie mogę stworzyć "
+
+#, c-format
+msgid "Vim exiting with %d\n"
+msgstr "Vim kończy pracę z %d\n"
+
+msgid "cannot change console mode ?!\n"
+msgstr "nie mogę zmienić trybu konsoli ?!\n"
+
+msgid "mch_get_shellsize: not a console??\n"
+msgstr "mch_get_shellsize: nie jest konsolÄ…??\n"
+
+#. if Vim opened a window: Executing a shell may cause crashes
+msgid "E360: Cannot execute shell with -f option"
+msgstr "E360: Nie mogę wykonać powłoki z opcją -f"
+
+msgid "Cannot execute "
+msgstr "Nie mogę wykonać "
+
+msgid "shell "
+msgstr "powłoka "
+
+msgid " returned\n"
+msgstr " zwrócił\n"
+
+msgid "ANCHOR_BUF_SIZE too small."
+msgstr "ANCHOR_BUF_SIZE zbyt niskie."
+
+msgid "I/O ERROR"
+msgstr "BÅÄ„D I/O"
+
+msgid "Message"
+msgstr "Wiadomość"
+
+msgid "'columns' is not 80, cannot execute external commands"
+msgstr "'columns' nie wynosi 80, nie mogę wykonać zewnętrznych komend"
+
+msgid "E237: Printer selection failed"
+msgstr "E237: Wybór drukarki nie powiódł się"
+
+#, c-format
+msgid "to %s on %s"
+msgstr "do %s z %s"
+
+#, c-format
+msgid "E613: Unknown printer font: %s"
+msgstr "E613: Nieznana czcionka drukarki: %s"
+
+#, c-format
+msgid "E238: Print error: %s"
+msgstr "E238: BÅ‚Ä…d drukarki: %s"
+
+#, c-format
+msgid "Printing '%s'"
+msgstr "Wydrukowano '%s'"
+
+#, c-format
+msgid "E244: Illegal charset name \"%s\" in font name \"%s\""
+msgstr ""
+"E244: Niedozwolona nazwa zestawu znaków \"%s\" w nazwie czcionki \"%s\""
+
+#, c-format
+msgid "E245: Illegal char '%c' in font name \"%s\""
+msgstr "E245: Niedozwolony znak '%c' w nazwie czcionki \"%s\""
+
+msgid "Vim: Double signal, exiting\n"
+msgstr "Vim: Podwójny sygnał, wychodzę\n"
+
+#, c-format
+msgid "Vim: Caught deadly signal %s\n"
+msgstr "Vim: Załapał śmiertelny sygnał %s\n"
+
+#, c-format
+msgid "Vim: Caught deadly signal\n"
+msgstr "Vim: Załapał śmiertelny sygnał\n"
+
+#, c-format
+msgid "Opening the X display took %ld msec"
+msgstr "Otwieranie ekranu X trwało %ld msec"
+
+msgid ""
+"\n"
+"Vim: Got X error\n"
+msgstr ""
+"\n"
+"Vim: Dostał błąd X\n"
+
+msgid "Testing the X display failed"
+msgstr "Test ekranu X nie powiódł się"
+
+msgid "Opening the X display timed out"
+msgstr "Próba otwarcia ekranu X trwała zbyt długo"
+
+msgid ""
+"\n"
+"Could not get security context for "
+msgstr ""
+"\n"
+"Nie mogę uzyskać kontekstu bezpieczeństwa dla"
+
+msgid ""
+"\n"
+"Could not set security context for "
+msgstr ""
+"\n"
+"Nie można uzyskać kontekstu bezpieczeństwa dla"
+
+msgid ""
+"\n"
+"Cannot execute shell "
+msgstr ""
+"\n"
+"Nie mogę wykonać powłoki "
+
+msgid ""
+"\n"
+"Cannot execute shell sh\n"
+msgstr ""
+"\n"
+"Nie mogę wykonać powłoki sh\n"
+
+msgid ""
+"\n"
+"shell returned "
+msgstr ""
+"\n"
+"powłoka zwróciła "
+
+msgid ""
+"\n"
+"Cannot create pipes\n"
+msgstr ""
+"\n"
+"Nie mogę stworzyć potoków\n"
+
+msgid ""
+"\n"
+"Cannot fork\n"
+msgstr ""
+"\n"
+"Nie mogę rozdzielić się\n"
+
+msgid ""
+"\n"
+"Command terminated\n"
+msgstr ""
+"\n"
+"Komenda zakończona\n"
+
+msgid "XSMP lost ICE connection"
+msgstr "XSMP stracił połączenie ICE"
+
+#, c-format
+msgid "dlerror = \"%s\""
+msgstr "dlerror = \"%s\""
+
+msgid "Opening the X display failed"
+msgstr "Otwarcie ekranu X nie powiodło się"
+
+msgid "XSMP handling save-yourself request"
+msgstr "XSMP obsługuje żądanie samozapisu"
+
+msgid "XSMP opening connection"
+msgstr "XSMP otwiera połączenie"
+
+msgid "XSMP ICE connection watch failed"
+msgstr "Obserwacja połączenia XSMP ICE nie powiodła się"
+
+#, c-format
+msgid "XSMP SmcOpenConnection failed: %s"
+msgstr "XSMP SmcOpenConnection nie powiodło się: %s"
+
+msgid "At line"
+msgstr "W wierszu"
+
+msgid "Could not load vim32.dll!"
+msgstr "Nie mogę załadować vim32.dll!"
+
+msgid "VIM Error"
+msgstr "BÅ‚Ä…d VIM"
+
+msgid "Could not fix up function pointers to the DLL!"
+msgstr "Nie zdołałem poprawić wskaźników funkcji w DLL!"
+
+#, c-format
+msgid "shell returned %d"
+msgstr "powłoka zwróciła %d"
+
+#, c-format
+msgid "Vim: Caught %s event\n"
+msgstr "Vim: Załapał wydarzenie %s\n"
+
+msgid "close"
+msgstr "zamknij"
+
+msgid "logoff"
+msgstr "wyloguj"
+
+msgid "shutdown"
+msgstr "zakończ"
+
+msgid "E371: Command not found"
+msgstr "E371: Nie znaleziono komendy"
+
+msgid ""
+"VIMRUN.EXE not found in your $PATH.\n"
+"External commands will not pause after completion.\n"
+"See :help win32-vimrun for more information."
+msgstr ""
+"VIMRUN.EXE nie znaleziono w twoim $PATH.\n"
+"Zewnętrzne komendy nie będą wstrzymane po wykonaniu.\n"
+"Zobacz :help wim32-vimrun aby otrzymać więcej informacji."
+
+msgid "Vim Warning"
+msgstr "Vim Ostrzeżenie"
+
+#, c-format
+msgid "E372: Too many %%%c in format string"
+msgstr "E372: Zbyt wiele %%%c w ciÄ…gu formatujÄ…cym"
+
+#, c-format
+msgid "E373: Unexpected %%%c in format string"
+msgstr "E373: Nieoczekiwane %%%c w ciÄ…gu formatujÄ…cym"
+
+msgid "E374: Missing ] in format string"
+msgstr "E374: Brak ] w ciÄ…gu formatujÄ…cym"
+
+#, c-format
+msgid "E375: Unsupported %%%c in format string"
+msgstr "E375: Niewspomagane %%%c w ciÄ…gu formatujÄ…cym"
+
+#, c-format
+msgid "E376: Invalid %%%c in format string prefix"
+msgstr "E376: Niepoprawne %%%c w prefiksie ciÄ…gu formatujÄ…cego"
+
+#, c-format
+msgid "E377: Invalid %%%c in format string"
+msgstr "E377: Niepoprawne %%%c w ciÄ…gu formatujÄ…cym"
+
+msgid "E378: 'errorformat' contains no pattern"
+msgstr "E378: 'errorformat' nie zawiera wzorca"
+
+msgid "E379: Missing or empty directory name"
+msgstr "E379: Pusta nazwa katalogu lub jej brak"
+
+msgid "E553: No more items"
+msgstr "E553: Nie ma więcej elementów"
+
+#, c-format
+msgid "(%d of %d)%s%s: "
+msgstr "(%d z %d)%s%s: "
+
+msgid " (line deleted)"
+msgstr " (wiersz skasowany)"
+
+msgid "E380: At bottom of quickfix stack"
+msgstr "E380: Na dole stosu quickfix"
+
+msgid "E381: At top of quickfix stack"
+msgstr "E381: Na górze stosu quickfix"
+
+#, c-format
+msgid "error list %d of %d; %d errors"
+msgstr "lista błędów %d z %d; %d błędów"
+
+msgid "E382: Cannot write, 'buftype' option is set"
+msgstr "E382: Nie mogę zapisać, opcja 'buftype' jest ustawiona"
+
+msgid "Error file"
+msgstr "Plik błędu"
+
+msgid "E683: File name missing or invalid pattern"
+msgstr "E683: Brak nazwy pliku lub niewłaściwa ścieżka"
+
+#, c-format
+msgid "Cannot open file \"%s\""
+msgstr "Nie mogę otworzyć pliku \"%s\""
+
+msgid "E681: Buffer is not loaded"
+msgstr "E681: Bufor nie jest załadowany"
+
+msgid "E777: String or List expected"
+msgstr "E777: Oczekiwałem na łańcuch lub listę"
+
+#, c-format
+msgid "E369: invalid item in %s%%[]"
+msgstr "E369: Niewłaściwy element w %s%%[]"
+
+#, c-format
+msgid "E769: Missing ] after %s["
+msgstr "E769: Brak ] po %s["
+
+#, c-format
+msgid "E53: Unmatched %s%%("
+msgstr "E53: Niesparowany %s%%("
+
+#, c-format
+msgid "E54: Unmatched %s("
+msgstr "E54: Niesparowany %s("
+
+#, c-format
+msgid "E55: Unmatched %s)"
+msgstr "E55: Niesparowany %s)"
+
+msgid "E66: \\z( not allowed here"
+msgstr "E66: \\z( jest niedozwolone w tym miejscu"
+
+msgid "E67: \\z1 - \\z9 not allowed here"
+msgstr "E67: \\z1 i podobne sÄ… niedozwolone w tym miejscu"
+
+#, c-format
+msgid "E69: Missing ] after %s%%["
+msgstr "E69: Brak ] po %s%%["
+
+#, c-format
+msgid "E70: Empty %s%%[]"
+msgstr "E70: Pusty %s%%[]"
+
+msgid "E339: Pattern too long"
+msgstr "E339: Zbyt długi wzorzec"
+
+msgid "E50: Too many \\z("
+msgstr "E50: Zbyt wiele \\z("
+
+#, c-format
+msgid "E51: Too many %s("
+msgstr "E51: Zbyt wiele %s("
+
+msgid "E52: Unmatched \\z("
+msgstr "E52: Niesparowany \\z("
+
+#, c-format
+msgid "E59: invalid character after %s@"
+msgstr "E59: niedozwolony znak po %s@"
+
+#, c-format
+msgid "E60: Too many complex %s{...}s"
+msgstr "E60: Zbyt wiele złożonych %s{...}"
+
+#, c-format
+msgid "E61: Nested %s*"
+msgstr "E61: Zagnieżdżone %s*"
+
+#, c-format
+msgid "E62: Nested %s%c"
+msgstr "E62: Zagnieżdżone %s%c"
+
+msgid "E63: invalid use of \\_"
+msgstr "E63: Niedozwolone użycie \\_"
+
+#, c-format
+msgid "E64: %s%c follows nothing"
+msgstr "E64: %s%c po niczym"
+
+msgid "E65: Illegal back reference"
+msgstr "E65: Niewłaściwe odwołanie wsteczne"
+
+msgid "E68: Invalid character after \\z"
+msgstr "E68: niedopuszczalny znak po \\z"
+
+#, c-format
+msgid "E678: Invalid character after %s%%[dxouU]"
+msgstr "E678: Niedozwolony znak po %s%%[dxouU]"
+
+#, c-format
+msgid "E71: Invalid character after %s%%"
+msgstr "E71: Niedozwolony znak po %s%%"
+
+#, c-format
+msgid "E554: Syntax error in %s{...}"
+msgstr "E554: Błąd składni w %s{...}"
+
+msgid "External submatches:\n"
+msgstr "Zewnętrzne poddopasowania:\n"
+
+msgid ""
+"E864: \\%#= can only be followed by 0, 1, or 2. The automatic engine will be "
+"used "
+msgstr "E:864: \\%#= może być tylko przed 0, 1 lub 2. Zostanie użyty silnik automatyczny"
+
+#, c-format
+msgid "E866: (NFA regexp) Misplaced %c"
+msgstr "E866: (wyrażenie regularne NFA) Niepoprawnie umieszczone %c"
+
+msgid "E865: (NFA) Regexp end encountered prematurely"
+msgstr "E865: (NFA) przedwczesny koniec wyrażenia regularnego"
+
+#, c-format
+msgid "E867: (NFA) Unknown operator '\\z%c'"
+msgstr "E867: (NFA) Nieznany operator '\\z%c'"
+
+#, c-format
+msgid "E867: (NFA) Unknown operator '\\%%%c'"
+msgstr "E867: (NFA) Nieznany operator '\\%%%c'"
+
+#. should never happen
+msgid "E868: Error building NFA with equivalence class!"
+msgstr "E868: BÅ‚Ä…d przy budowwaniu NFA z klasÄ… ekwiwalencji"
+
+#, c-format
+msgid "E869: (NFA) Unknown operator '\\@%c'"
+msgstr "E869: (NFA) Nieznany operator '\\@%c'"
+
+msgid "E870: (NFA regexp) Error reading repetition limits"
+msgstr "E870: (wyrażenie regularne NFA) Błąd przy odczytywaniu limitów powtórzeń"
+
+#. Can't have a multi follow a multi.
+msgid "E871: (NFA regexp) Can't have a multi follow a multi"
+msgstr "E871: (wyrażenie regularne NFA) wielokrotne nie może być po wielokrotnym"
+
+#. Too many `('
+msgid "E872: (NFA regexp) Too many '('"
+msgstr "E872: (wyrażenie regularne NFA) Zbyt dużo '('"
+
+msgid "E879: (NFA regexp) Too many \\z("
+msgstr "E879: (wyrażenie regularne NFA) Za dużo \\z("
+
+msgid "E873: (NFA regexp) proper termination error"
+msgstr "E873: (wyrażenie regularne NFA) błąd poprawnego zakończenia"
+
+msgid "E874: (NFA) Could not pop the stack!"
+msgstr "E874: (NFA) Nie można zdjąć elementu ze stosu!"
+
+msgid ""
+"E875: (NFA regexp) (While converting from postfix to NFA), too many states "
+"left on stack"
+msgstr "E875: (wyrażenie regularne NFA) (w trakcie konwersji postfix do NFA), za wiele stanów na stosie"
+
+msgid "E876: (NFA regexp) Not enough space to store the whole NFA "
+msgstr "E876: (wyrażenie regularne NFA) Nie ma miejsca na całe NFA "
+
+msgid "E878: (NFA) Could not allocate memory for branch traversal!"
+msgstr "E878: (NFA) Nie można przydzielić pamięci do przejścia przez gałęzie!"
+
+msgid ""
+"Could not open temporary log file for writing, displaying on stderr... "
+msgstr "Nie można otworzyć do zapisu tymczasowego pliku, pokazuję na stderr... "
+
+#, c-format
+msgid "(NFA) COULD NOT OPEN %s !"
+msgstr "(NFA) NIE MOŻNA OTWORZYĆ %s !"
+
+msgid "Could not open temporary log file for writing "
+msgstr "Nie można otworzyć do zapisu tymczasowego pliku logowania"
+
+msgid " VREPLACE"
+msgstr " V-ZAMIANA"
+
+msgid " REPLACE"
+msgstr " ZAMIANA"
+
+msgid " REVERSE"
+msgstr " NEGATYW"
+
+msgid " INSERT"
+msgstr " WPROWADZANIE"
+
+msgid " (insert)"
+msgstr " (wprowadzanie)"
+
+msgid " (replace)"
+msgstr " (zamiana)"
+
+msgid " (vreplace)"
+msgstr " (v-zamiana)"
+
+msgid " Hebrew"
+msgstr " Hebrajski"
+
+msgid " Arabic"
+msgstr " Arabski"
+
+msgid " (lang)"
+msgstr " (język)"
+
+msgid " (paste)"
+msgstr " (wklejanie)"
+
+msgid " VISUAL"
+msgstr " WIZUALNY"
+
+msgid " VISUAL LINE"
+msgstr " WIZUALNY LINIOWY"
+
+msgid " VISUAL BLOCK"
+msgstr " WIZUALNY BLOKOWY"
+
+msgid " SELECT"
+msgstr " ZAZNACZANIE"
+
+msgid " SELECT LINE"
+msgstr " ZAZNACZANIE LINIOWE"
+
+msgid " SELECT BLOCK"
+msgstr " ZAZNACZANIE BLOKOWE"
+
+msgid "recording"
+msgstr "zapis"
+
+#, c-format
+msgid "E383: Invalid search string: %s"
+msgstr "E383: Niewłaściwy ciąg do szukania: %s"
+
+#, c-format
+msgid "E384: search hit TOP without match for: %s"
+msgstr "E384: szukanie dobiło GÓRY bez znalezienia: %s"
+
+#, c-format
+msgid "E385: search hit BOTTOM without match for: %s"
+msgstr "E385: szukanie dobiło KOŃCA bez znalezienia : %s"
+
+msgid "E386: Expected '?' or '/' after ';'"
+msgstr "E386: OczekujÄ™ '?' lub '/' po ';'"
+
+msgid " (includes previously listed match)"
+msgstr " (zawiera poprzednio wymienione dopasowanie)"
+
+#. cursor at status line
+msgid "--- Included files "
+msgstr "--- Zawarte pliki "
+
+msgid "not found "
+msgstr "nie znaleziono"
+
+msgid "in path ---\n"
+msgstr "w tropie ---\n"
+
+msgid " (Already listed)"
+msgstr " (Już wymienione)"
+
+msgid " NOT FOUND"
+msgstr " NIE ZNALEZIONO"
+
+#, c-format
+msgid "Scanning included file: %s"
+msgstr "Przegląd włączonego pliku: %s"
+
+#, c-format
+msgid "Searching included file %s"
+msgstr "Przeszukiwanie włączonego pliku %s"
+
+msgid "E387: Match is on current line"
+msgstr "E387: Wzorzec pasuje w bieżącym wierszu"
+
+msgid "All included files were found"
+msgstr "Wszelkie włączane pliki odnaleziono"
+
+msgid "No included files"
+msgstr "Brak włączanych plików"
+
+msgid "E388: Couldn't find definition"
+msgstr "E388: Nie znalazłem definicji"
+
+msgid "E389: Couldn't find pattern"
+msgstr "E389: Nie znalazłem wzorca"
+
+msgid "Substitute "
+msgstr "Podstawienie "
+
+#, c-format
+msgid ""
+"\n"
+"# Last %sSearch Pattern:\n"
+"~"
+msgstr ""
+"\n"
+"# Ostatni %sWyszukiwany wzorzec:\n"
+"~"
+
+msgid "E759: Format error in spell file"
+msgstr "E759: Nieprawidłowy format pliku sprawdzania pisowni"
+
+msgid "E758: Truncated spell file"
+msgstr "E758: Obcięty plik sprawdzania pisowni"
+
+#, c-format
+msgid "Trailing text in %s line %d: %s"
+msgstr "Zbędny tekst w %s wiersz %d: %s"
+
+#, c-format
+msgid "Affix name too long in %s line %d: %s"
+msgstr "Za długa nazwa afiksu w %s wiersz %d: %s"
+
+msgid "E761: Format error in affix file FOL, LOW or UPP"
+msgstr "E761: Błąd formatu w pliku afiksów FOL, LOW lub UPP"
+
+msgid "E762: Character in FOL, LOW or UPP is out of range"
+msgstr "E762: Znak w FOL, LOW lub UPP jest poza zasięgiem"
+
+msgid "Compressing word tree..."
+msgstr "Kompresja drzewa słów..."
+
+msgid "E756: Spell checking is not enabled"
+msgstr "E756: Sprawdzanie pisowni nie jest włączone"
+
+#, c-format
+msgid "Warning: Cannot find word list \"%s_%s.spl\" or \"%s_ascii.spl\""
+msgstr ""
+"Ostrzeżenie: Nie mogę znaleźć listy słów \"%s_%s.spl\" lub \"%s_ascii.spl\""
+
+#, c-format
+msgid "Warning: Cannot find word list \"%s.%s.spl\" or \"%s.ascii.spl\""
+msgstr ""
+"Ostrzeżenie: Nie mogę znaleźć listy słów \"%s.%s.spl\" lub \"%s.ascii.spl\""
+
+#, c-format
+msgid "Reading spell file \"%s\""
+msgstr "OdczytujÄ™ plik sprawdzania pisowni \"%s\""
+
+msgid "E757: This does not look like a spell file"
+msgstr "E757: To nie wyglÄ…da na plik sprawdzania pisowni"
+
+msgid "E771: Old spell file, needs to be updated"
+msgstr "E771: Stary plik sprawdzania pisowni, wymagane uaktualnienie"
+
+msgid "E772: Spell file is for newer version of Vim"
+msgstr "E772: Plik sprawdzania pisowni dla nowszej wersji Vima"
+
+msgid "E770: Unsupported section in spell file"
+msgstr "E770: Niewspierana sekcja w pliku sprawdzania pisowni"
+
+#, c-format
+msgid "Warning: region %s not supported"
+msgstr "Ostrzeżenie: region %s nie jest wspierany"
+
+#, c-format
+msgid "Reading affix file %s..."
+msgstr "Czytam plik afiksów %s..."
+
+#, c-format
+msgid "Conversion failure for word in %s line %d: %s"
+msgstr "Konwersja nie powiodła się dla wyrazu w %s wierszu %d: %s"
+
+#, c-format
+msgid "Conversion in %s not supported: from %s to %s"
+msgstr "Konwersja w %s nie jest wspierana: od %s do %s"
+
+#, c-format
+msgid "Conversion in %s not supported"
+msgstr "Konwersja w %s nie jest wspierana"
+
+#, c-format
+msgid "Invalid value for FLAG in %s line %d: %s"
+msgstr "Nieprawidłowa wartość FLAG w %s wierz %d: %s"
+
+#, c-format
+msgid "FLAG after using flags in %s line %d: %s"
+msgstr "FLAG po użyciu flag w %s wiersz %d: %s"
+
+#, c-format
+msgid ""
+"Defining COMPOUNDFORBIDFLAG after PFX item may give wrong results in %s line "
+"%d"
+msgstr ""
+"Definiowanie COMPOUNDFORBIDFLAG po PFX może skutkować złym wynikiem w %s "
+"wiersz %d"
+
+#, c-format
+msgid ""
+"Defining COMPOUNDPERMITFLAG after PFX item may give wrong results in %s line "
+"%d"
+msgstr ""
+"Definiowanie COMPOUNDPERMITFLAG po PFX może skutkować złym wynikiem w %s "
+"wiersz %d"
+
+#, c-format
+msgid "Wrong COMPOUNDRULES value in %s line %d: %s"
+msgstr "Zła wartość COMPOUNDRULES w %s wiersz %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDWORDMAX value in %s line %d: %s"
+msgstr "Zła wartość COMPOUNDWORDMAX w %s wiersz %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDMIN value in %s line %d: %s"
+msgstr "Zła wartość COMPOUNDMIM w %s wiersz %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDSYLMAX value in %s line %d: %s"
+msgstr "Zła wartość COMPOUNDSYLMAX w %s wiersz %d: %s"
+
+#, c-format
+msgid "Wrong CHECKCOMPOUNDPATTERN value in %s line %d: %s"
+msgstr "Zła wartość CHECKCOMPOUNDPATTERN w %s wiersz %d: %s"
+
+#, c-format
+msgid "Different combining flag in continued affix block in %s line %d: %s"
+msgstr "Różne flagi złożeń w kontynuowanym bloku afiksu w %s wiersz %d: %s"
+
+#, c-format
+msgid "Duplicate affix in %s line %d: %s"
+msgstr "Powtórzony afiks w %s wiersz %d: %s"
+
+#, c-format
+msgid ""
+"Affix also used for BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST in %s "
+"line %d: %s"
+msgstr ""
+"Afiks użyty także dla BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST w "
+"%s wiersz %d: %s"
+
+#, c-format
+msgid "Expected Y or N in %s line %d: %s"
+msgstr "Oczekiwano Y lub N w %s wierszu %d: %s"
+
+#, c-format
+msgid "Broken condition in %s line %d: %s"
+msgstr "Błędny warunek w %s wiersz %d: %s"
+
+#, c-format
+msgid "Expected REP(SAL) count in %s line %d"
+msgstr "Oczekiwano ilości REP(SAL) w %s wierszu %d"
+
+#, c-format
+msgid "Expected MAP count in %s line %d"
+msgstr "Oczekiwano ilości MAP w %s wierszu %d"
+
+#, c-format
+msgid "Duplicate character in MAP in %s line %d"
+msgstr "Powtórzony znak w MAP w %s wierszu %d"
+
+#, c-format
+msgid "Unrecognized or duplicate item in %s line %d: %s"
+msgstr "Nieznany lub powtórzony element w %s wierszu %d: %s"
+
+#, c-format
+msgid "Missing FOL/LOW/UPP line in %s"
+msgstr "Brak wiersza FOL/LOW/UPP w %s"
+
+msgid "COMPOUNDSYLMAX used without SYLLABLE"
+msgstr "COMPOUNDSYLMAX użyty bez SYLLABLE"
+
+msgid "Too many postponed prefixes"
+msgstr "Zbyt wiele opóźnionych prefiksów"
+
+msgid "Too many compound flags"
+msgstr "Zbyt wiele flag złożeń"
+
+msgid "Too many postponed prefixes and/or compound flags"
+msgstr "Zbyt wiele opóźnionych prefiksów i/lub flag złożeń"
+
+#, c-format
+msgid "Missing SOFO%s line in %s"
+msgstr "Brak wiersza SOFO%s wiersz w %s"
+
+#, c-format
+msgid "Both SAL and SOFO lines in %s"
+msgstr "Wiersze SAL i SOFO w %s"
+
+#, c-format
+msgid "Flag is not a number in %s line %d: %s"
+msgstr "Flaga nie jest liczbÄ… w %s wiersz %d: %s"
+
+#, c-format
+msgid "Illegal flag in %s line %d: %s"
+msgstr "Nieprawidłowa flaga w %s wiersz %d: %s"
+
+#, c-format
+msgid "%s value differs from what is used in another .aff file"
+msgstr "Wartość %s różni się od tej użytej w innym pliku .aff"
+
+#, c-format
+msgid "Reading dictionary file %s..."
+msgstr "Czytam plik słownika %s..."
+
+#, c-format
+msgid "E760: No word count in %s"
+msgstr "E760: Brak ilości słów w %s"
+
+#, c-format
+msgid "line %6d, word %6d - %s"
+msgstr "wiersz %6d, słowo %6d - %s"
+
+# c-format
+#, c-format
+msgid "Duplicate word in %s line %d: %s"
+msgstr "Powtórzony wyraz w %s wierszu %d: %s"
+
+# c-format
+#, c-format
+msgid "First duplicate word in %s line %d: %s"
+msgstr "Pierwszy powtórzony wyraz w %s wiersz %d: %s"
+
+# c-format
+#, c-format
+msgid "%d duplicate word(s) in %s"
+msgstr "%d powtórzony(ch) wyraz(ów) w %s"
+
+#, c-format
+msgid "Ignored %d word(s) with non-ASCII characters in %s"
+msgstr "Zignorowałem %d słów ze znakami nie ASCII w %s"
+
+#, c-format
+msgid "Reading word file %s..."
+msgstr "Odczytuję plik wyrazów %s..."
+
+#, c-format
+msgid "Duplicate /encoding= line ignored in %s line %d: %s"
+msgstr "Zignorowano powtórzony wiersz /encoding= w %s wierszu %d: %s"
+
+#, c-format
+msgid "/encoding= line after word ignored in %s line %d: %s"
+msgstr "Zignorowano wiersz /encoding= po wyrazie w %s wierszu %d: %s"
+
+#, c-format
+msgid "Duplicate /regions= line ignored in %s line %d: %s"
+msgstr "Powtórzony wiersz /regions= zignorowano w %s wierszu %d: %s"
+
+#, c-format
+msgid "Too many regions in %s line %d: %s"
+msgstr "Za dużo regionów w %s wiersz %d: %s"
+
+#, c-format
+msgid "/ line ignored in %s line %d: %s"
+msgstr "wiersz / zignorowano w %s wierszu %d: %s"
+
+#, c-format
+msgid "Invalid region nr in %s line %d: %s"
+msgstr "Nieprawidłowy numer regionu w %s wierszu %d: %s"
+
+#, c-format
+msgid "Unrecognized flags in %s line %d: %s"
+msgstr "Nieznane flagi w %s wiersz %d: %s"
+
+#, c-format
+msgid "Ignored %d words with non-ASCII characters"
+msgstr "Zignorowałem %d słów ze znakami nie ASCII"
+
+msgid "E845: Insufficient memory, word list will be incomplete"
+msgstr "E845: Nie wystarczająca ilość pamięci, lista słów będzie niekompletna"
+
+#, c-format
+msgid "Compressed %d of %d nodes; %d (%d%%) remaining"
+msgstr "Skompresowano %d z %d węzłów; pozostaje %d (%d%%)"
+
+msgid "Reading back spell file..."
+msgstr "OdczytujÄ™ plik sprawdzania pisowni..."
+
+#.
+#. * Go through the trie of good words, soundfold each word and add it to
+#. * the soundfold trie.
+#.
+msgid "Performing soundfolding..."
+msgstr "Wykonuję kompresję dźwiękową..."
+
+#, c-format
+msgid "Number of words after soundfolding: %ld"
+msgstr "Liczba słów po kompresji dźwiękowej: %ld"
+
+#, c-format
+msgid "Total number of words: %d"
+msgstr "Całkowita liczba słów: %d"
+
+#, c-format
+msgid "Writing suggestion file %s..."
+msgstr "ZapisujÄ™ plik sugestii %s..."
+
+#, c-format
+msgid "Estimated runtime memory use: %d bytes"
+msgstr "Oczekiwane zużycie pamięci: %d bajtów"
+
+msgid "E751: Output file name must not have region name"
+msgstr "E751: Nazwa pliku wynikowego nie może być nazwą regionu"
+
+msgid "E754: Only up to 8 regions supported"
+msgstr "E754: Wspieram tylko 8 regionów"
+
+#, c-format
+msgid "E755: Invalid region in %s"
+msgstr "E755: Nieprawidłowy region w %s"
+
+msgid "Warning: both compounding and NOBREAK specified"
+msgstr "Ostrzeżenie: określono zarówno złożenia jak i NOBREAK"
+
+#, c-format
+msgid "Writing spell file %s..."
+msgstr "ZapisujÄ™ plik sprawdzania pisowni %s..."
+
+msgid "Done!"
+msgstr "Zrobione!"
+
+#, c-format
+msgid "E765: 'spellfile' does not have %ld entries"
+msgstr "E765: 'spellfile' nie posiada wpisów %ld"
+
+#, c-format
+msgid "Word removed from %s"
+msgstr "Usunięto słowo z %s"
+
+#, c-format
+msgid "Word added to %s"
+msgstr "Dodano słowo do %s"
+
+msgid "E763: Word characters differ between spell files"
+msgstr "E763: Znaki wyrazów różnią się między plikami sprawdzania pisowni"
+
+msgid "Sorry, no suggestions"
+msgstr "Przykro mi, brak podpowiedzi"
+
+#, c-format
+msgid "Sorry, only %ld suggestions"
+msgstr "Przykro mi, tylko %ld podpowiedzi"
+
+#. for when 'cmdheight' > 1
+#. avoid more prompt
+#, c-format
+msgid "Change \"%.*s\" to:"
+msgstr "Zmień \"%.*s\" na:"
+
+#, c-format
+msgid " < \"%.*s\""
+msgstr " < \"%.*s\""
+
+msgid "E752: No previous spell replacement"
+msgstr "E752: Brak poprzednich podmian sprawdzania pisowni"
+
+#, c-format
+msgid "E753: Not found: %s"
+msgstr "E753: Nie znaleziono: %s"
+
+#, c-format
+msgid "E778: This does not look like a .sug file: %s"
+msgstr "E778: Ten plik nie wyglÄ…da na plik .sug: %s"
+
+#, c-format
+msgid "E779: Old .sug file, needs to be updated: %s"
+msgstr "E779: Stary plik .sug, konieczne jest uaktualnienie: %s"
+
+#, c-format
+msgid "E780: .sug file is for newer version of Vim: %s"
+msgstr "E780: Plik .sug dla nowszej wersji Vima: %s"
+
+#, c-format
+msgid "E781: .sug file doesn't match .spl file: %s"
+msgstr "E781: Plik .sug nie pasuje do pliku .spl: %s"
+
+#, c-format
+msgid "E782: error while reading .sug file: %s"
+msgstr "E782: BÅ‚Ä…d w czasie odczytu pliku .sug: %s"
+
+#. This should have been checked when generating the .spl
+#. * file.
+msgid "E783: duplicate char in MAP entry"
+msgstr "E783: Podwojony znak we wpisie MAP"
+
+msgid "No Syntax items defined for this buffer"
+msgstr "Brak elementów składni określonych dla tego bufora"
+
+#, c-format
+msgid "E390: Illegal argument: %s"
+msgstr "E390: Niedozwolony argument: %s"
+
+#, c-format
+msgid "E391: No such syntax cluster: %s"
+msgstr "E391: Nie ma takiego klastra składni: %s"
+
+msgid "syncing on C-style comments"
+msgstr "synchronizacja komentarzy w stylu C"
+
+msgid "no syncing"
+msgstr "brak synchronizacji"
+
+msgid "syncing starts "
+msgstr "poczÄ…tek synchronizacji"
+
+msgid " lines before top line"
+msgstr " wierszy przed górną linią"
+
+msgid ""
+"\n"
+"--- Syntax sync items ---"
+msgstr ""
+"\n"
+"--- Elementy synchronizacji składni ---"
+
+msgid ""
+"\n"
+"syncing on items"
+msgstr ""
+"\n"
+"synchronizujÄ™ na elementach"
+
+msgid ""
+"\n"
+"--- Syntax items ---"
+msgstr ""
+"\n"
+"--- Elementy składni ---"
+
+#, c-format
+msgid "E392: No such syntax cluster: %s"
+msgstr "E392: Nie ma takiego klastra składni: %s"
+
+msgid "minimal "
+msgstr "minimalnie "
+
+msgid "maximal "
+msgstr "maksymalnie "
+
+msgid "; match "
+msgstr "; pasuje "
+
+msgid " line breaks"
+msgstr "znaków nowego wiersza"
+
+msgid "E395: contains argument not accepted here"
+msgstr "E395: argument contains niedozwolony w tym miejscu"
+
+msgid "E844: invalid cchar value"
+msgstr "E844: Niewłaściwa wartość cchar"
+
+msgid "E393: group[t]here not accepted here"
+msgstr "E393: group[t]here niedozwolone w tym miejscu"
+
+#, c-format
+msgid "E394: Didn't find region item for %s"
+msgstr "E394: Nie znalazłem elementów regionu dla %s"
+
+msgid "E397: Filename required"
+msgstr "E397: Wymagana nazwa pliku"
+
+msgid "E847: Too many syntax includes"
+msgstr "E847: Za dużo włączonych składni"
+
+#, c-format
+msgid "E789: Missing ']': %s"
+msgstr "E789: Brak ']': %s"
+
+#, c-format
+msgid "E398: Missing '=': %s"
+msgstr "E398: Brak '=': %s"
+
+#, c-format
+msgid "E399: Not enough arguments: syntax region %s"
+msgstr "E399: Za mało argumentów: syntax region %s"
+
+msgid "E848: Too many syntax clusters"
+msgstr "E848: Za dużo klastrów składni"
+
+msgid "E400: No cluster specified"
+msgstr "E400: Brak specyfikacji klastra"
+
+#, c-format
+msgid "E401: Pattern delimiter not found: %s"
+msgstr "E401: Brak ogranicznika wzorca: %s"
+
+#, c-format
+msgid "E402: Garbage after pattern: %s"
+msgstr "E402: Åšmieci po wzorcu: %s"
+
+msgid "E403: syntax sync: line continuations pattern specified twice"
+msgstr "E403: syntax sync: wielokrotnie podane wzorce kontynuacji wiersza"
+
+#, c-format
+msgid "E404: Illegal arguments: %s"
+msgstr "E404: Niedozwolone argumenty: %s"
+
+#, c-format
+msgid "E405: Missing equal sign: %s"
+msgstr "E405: Brak znaku równości: %s"
+
+#, c-format
+msgid "E406: Empty argument: %s"
+msgstr "E406: Pusty argument: %s"
+
+#, c-format
+msgid "E407: %s not allowed here"
+msgstr "E407: %s jest niedozwolone w tym miejscu"
+
+#, c-format
+msgid "E408: %s must be first in contains list"
+msgstr "E408: %s musi być pierwsze w liście contains"
+
+#, c-format
+msgid "E409: Unknown group name: %s"
+msgstr "E409: Nieznana nazwa grupy: %s"
+
+#, c-format
+msgid "E410: Invalid :syntax subcommand: %s"
+msgstr "E410: Niewłaściwa podkomenda :syntax : %s"
+
+msgid ""
+" TOTAL COUNT MATCH SLOWEST AVERAGE NAME PATTERN"
+msgstr ""
+" WSZYTKO ILOŚĆ PASUJE NAJWOLN. ŚREDNIO NAZWA WZORZEC"
+
+msgid "E679: recursive loop loading syncolor.vim"
+msgstr "E679: rekursywna pętla wczytująca syncolor.vim"
+
+#, c-format
+msgid "E411: highlight group not found: %s"
+msgstr "E411: nie znaleziono grupy podświetlania: %s"
+
+#, c-format
+msgid "E412: Not enough arguments: \":highlight link %s\""
+msgstr "E412: Zbyt mało argumentów: \":highlight link %s\""
+
+#, c-format
+msgid "E413: Too many arguments: \":highlight link %s\""
+msgstr "E413: Zbyt wiele argumentów: \":highlight link %s\""
+
+msgid "E414: group has settings, highlight link ignored"
+msgstr "E414: grupa ma ustawienia; zignorowane podłączenie podświetlania"
+
+#, c-format
+msgid "E415: unexpected equal sign: %s"
+msgstr "E415: nieoczekiwany znak równości: %s"
+
+#, c-format
+msgid "E416: missing equal sign: %s"
+msgstr "E416: brak znaku równości: %s"
+
+#, c-format
+msgid "E417: missing argument: %s"
+msgstr "E417: brak argumentu: %s"
+
+#, c-format
+msgid "E418: Illegal value: %s"
+msgstr "E418: Niedozwolona wartość: %s"
+
+msgid "E419: FG color unknown"
+msgstr "E419: Kolor FG nieznany"
+
+msgid "E420: BG color unknown"
+msgstr "E420: Kolor BG nieznany"
+
+#, c-format
+msgid "E421: Color name or number not recognized: %s"
+msgstr "E421: Nazwa lub liczba koloru nierozpoznana: %s"
+
+#, c-format
+msgid "E422: terminal code too long: %s"
+msgstr "E422: za długi kod terminala: %s"
+
+#, c-format
+msgid "E423: Illegal argument: %s"
+msgstr "E423: Niedozwolony argument: %s"
+
+msgid "E424: Too many different highlighting attributes in use"
+msgstr "E424: Zbyt wiele różnych atrybutów podkreślania w użyciu"
+
+msgid "E669: Unprintable character in group name"
+msgstr "E669: Niedrukowalny znak w nazwie grupy"
+
+msgid "W18: Invalid character in group name"
+msgstr "W18: nieprawidłowy znak w nazwie grupy"
+
+msgid "E849: Too many highlight and syntax groups"
+msgstr "E849: Za dużo grup podświetlania i składni"
+
+msgid "E555: at bottom of tag stack"
+msgstr "E555: na dole stosu znaczników"
+
+msgid "E556: at top of tag stack"
+msgstr "E556: na górze stosu znaczników"
+
+msgid "E425: Cannot go before first matching tag"
+msgstr "E425: Nie można przejść przed pierwszy pasujący znacznik"
+
+#, c-format
+msgid "E426: tag not found: %s"
+msgstr "E426: nie znaleziono znacznika: %s"
+
+msgid " # pri kind tag"
+msgstr " # pri rodzaj znacznik"
+
+msgid "file\n"
+msgstr "plik\n"
+
+msgid "E427: There is only one matching tag"
+msgstr "E427: Pasuje tylko jeden znacznik"
+
+msgid "E428: Cannot go beyond last matching tag"
+msgstr "E428: Nie można przejść za ostatni pasujący znacznik"
+
+#, c-format
+msgid "File \"%s\" does not exist"
+msgstr "Plik \"%s\" nie istnieje"
+
+#. Give an indication of the number of matching tags
+#, c-format
+msgid "tag %d of %d%s"
+msgstr "znacznik %d z %d%s"
+
+msgid " or more"
+msgstr " lub więcej"
+
+msgid " Using tag with different case!"
+msgstr " Używam znacznika o odmiennej wielkości liter!"
+
+#, c-format
+msgid "E429: File \"%s\" does not exist"
+msgstr "E429: Plik \"%s\" nie istnieje"
+
+#. Highlight title
+msgid ""
+"\n"
+" # TO tag FROM line in file/text"
+msgstr ""
+"\n"
+" # DO znacznik OD wiersza w pliku/tekście"
+
+#, c-format
+msgid "Searching tags file %s"
+msgstr "Szukam w pliku znaczników %s"
+
+#, c-format
+msgid "E430: Tag file path truncated for %s\n"
+msgstr "E430: Trop szukania pliku znaczników obcięty dla %s\n"
+
+msgid "Ignoring long line in tags file"
+msgstr "Ignoruję długie wiersze w pliku znaczników"
+
+#, c-format
+msgid "E431: Format error in tags file \"%s\""
+msgstr "E431: Błąd formatu w pliku znaczników \"%s\""
+
+#, c-format
+msgid "Before byte %ld"
+msgstr "Przed bajtem %ld"
+
+#, c-format
+msgid "E432: Tags file not sorted: %s"
+msgstr "E432: Plik znaczników nieuporządkowany: %s"
+
+#. never opened any tags file
+msgid "E433: No tags file"
+msgstr "E433: Brak pliku znaczników"
+
+msgid "E434: Can't find tag pattern"
+msgstr "E434: Nie mogę znaleźć wzorca znacznika"
+
+msgid "E435: Couldn't find tag, just guessing!"
+msgstr "E435: Nie znalazłem znacznika - tylko zgaduję!"
+
+#, c-format
+msgid "Duplicate field name: %s"
+msgstr "Powtórzona nazwa pola: %s"
+
+msgid "' not known. Available builtin terminals are:"
+msgstr "' nieznany. Możliwe typy wbudowanych terminali:"
+
+msgid "defaulting to '"
+msgstr "domyślnie jest '"
+
+msgid "E557: Cannot open termcap file"
+msgstr "E557: Nie mogę otworzyć pliku termcap"
+
+msgid "E558: Terminal entry not found in terminfo"
+msgstr "E558: Nie ma opisu takiego terminala w terminfo"
+
+msgid "E559: Terminal entry not found in termcap"
+msgstr "E559: Nie ma opisu takiego terminala w termcap"
+
+#, c-format
+msgid "E436: No \"%s\" entry in termcap"
+msgstr "E436: Brak opisu \"%s\" w termcap"
+
+msgid "E437: terminal capability \"cm\" required"
+msgstr "E437: wymagana zdolność \"cm\" terminala"
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Terminal keys ---"
+msgstr ""
+"\n"
+"--- Klawisze terminala ---"
+
+msgid "new shell started\n"
+msgstr "uruchomiono nową powłokę\n"
+
+msgid "Vim: Error reading input, exiting...\n"
+msgstr "Vim: Błąd podczas wczytywania wejścia, kończę...\n"
+
+msgid "Used CUT_BUFFER0 instead of empty selection"
+msgstr "Używam CUT_BUFFER0 zamiast pustego wyboru"
+
+#. This happens when the FileChangedRO autocommand changes the
+#. * file in a way it becomes shorter.
+msgid "E834: Line count changed unexpectedly"
+msgstr "E834: Niespodziewana zmiana ilości linii"
+
+#. must display the prompt
+msgid "No undo possible; continue anyway"
+msgstr "Cofnięcie niemożliwe; mimo to kontynuuję"
+
+#, c-format
+msgid "E828: Cannot open undo file for writing: %s"
+msgstr "E828: Nie mogę otworzyć do zapisu pliku undo: %s"
+
+#, c-format
+msgid "E825: Corrupted undo file (%s): %s"
+msgstr "E825: Uszkodzony plik undo (%s): %s"
+
+msgid "Cannot write undo file in any directory in 'undodir'"
+msgstr "Nie można zapisać pliku undo w żadnym katalogu z 'undodir'"
+
+#, c-format
+msgid "Will not overwrite with undo file, cannot read: %s"
+msgstr "Nie nadpiszę plikiem undo, nie mogę odczytać: %s"
+
+#, c-format
+msgid "Will not overwrite, this is not an undo file: %s"
+msgstr "Nie nadpiszÄ™, to nie jest plik undo: %s"
+
+msgid "Skipping undo file write, nothing to undo"
+msgstr "Pomijam zapis pliku undo, nic do cofnięcia"
+
+#, c-format
+msgid "Writing undo file: %s"
+msgstr "ZapisujÄ™ plik undo: %s"
+
+#, c-format
+msgid "E829: write error in undo file: %s"
+msgstr "E829: BÅ‚Ä…d zapisu w pliku undo: %s"
+
+#, c-format
+msgid "Not reading undo file, owner differs: %s"
+msgstr "Nie wczytuję pliku undo, inny właściciel: %s"
+
+#, c-format
+msgid "Reading undo file: %s"
+msgstr "WczytujÄ™ plik undo: %s"
+
+#, c-format
+msgid "E822: Cannot open undo file for reading: %s"
+msgstr "E822: Nie mogę otworzyć pliku undo do odczytu: %s"
+
+#, c-format
+msgid "E823: Not an undo file: %s"
+msgstr "E823: To nie jest plik undo: %s"
+
+#, c-format
+msgid "E832: Non-encrypted file has encrypted undo file: %s"
+msgstr "E832: Nie zaszyfrowany plik ma zaszyfrowany plik undo: %s"
+
+#, c-format
+msgid "E826: Undo file decryption failed: %s"
+msgstr "E826: Nie powiodło się odszyfrowywanie pliku undo: %s"
+
+#, c-format
+msgid "E827: Undo file is encrypted: %s"
+msgstr "E827: Plik undo jest zaszyfrowany: %s"
+
+#, c-format
+msgid "E824: Incompatible undo file: %s"
+msgstr "E824: Niekompatybilny plik undo: %s"
+
+msgid "File contents changed, cannot use undo info"
+msgstr "Zawartość pliku się zmieniła, nie mogę użyć pliku undo"
+
+#, c-format
+msgid "Finished reading undo file %s"
+msgstr "Skończono wczytywanie pliku undo %s"
+
+msgid "Already at oldest change"
+msgstr "Już w miejscu ostatniej zmiany"
+
+msgid "Already at newest change"
+msgstr "Już w miejscu najnowszej zmiany"
+
+#, c-format
+msgid "E830: Undo number %ld not found"
+msgstr "E830: Nie znaleziono numeru cofnięcia %ld"
+
+msgid "E438: u_undo: line numbers wrong"
+msgstr "E438: u_undo: niewłaściwe numery wierszy"
+
+msgid "more line"
+msgstr "1 wiersz więcej"
+
+msgid "more lines"
+msgstr "więcej wierszy"
+
+msgid "line less"
+msgstr "1 wiersz mniej"
+
+msgid "fewer lines"
+msgstr "mniej wierszy"
+
+msgid "change"
+msgstr "1 zmiana"
+
+msgid "changes"
+msgstr "zmiany"
+
+#, c-format
+msgid "%ld %s; %s #%ld %s"
+msgstr "%ld %s; %s #%ld %s"
+
+msgid "before"
+msgstr "przed"
+
+msgid "after"
+msgstr "za"
+
+msgid "Nothing to undo"
+msgstr "Nie ma zmian do cofnięcia"
+
+msgid "number changes when saved"
+msgstr "liczba zmiany kiedy zapisano"
+
+#, c-format
+msgid "%ld seconds ago"
+msgstr "%ld sekund temu"
+
+msgid "E790: undojoin is not allowed after undo"
+msgstr "E790: undojoin nie jest dozwolone po undo"
+
+msgid "E439: undo list corrupt"
+msgstr "E439: uszkodzona lista cofania"
+
+msgid "E440: undo line missing"
+msgstr "E440: brak wiersza cofania"
+
+#. Only MS VC 4.1 and earlier can do Win32s
+msgid ""
+"\n"
+"MS-Windows 16/32-bit GUI version"
+msgstr ""
+"\n"
+"16/32-bit wersja GUI dla MS-Windows"
+
+msgid ""
+"\n"
+"MS-Windows 64-bit GUI version"
+msgstr ""
+"\n"
+"64 bitowa wersja GUI dla MS-Windows"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit GUI version"
+msgstr ""
+"\n"
+"32 bitowa wersja GUI dla MS-Windows"
+
+msgid " in Win32s mode"
+msgstr " w trybie Win32s"
+
+msgid " with OLE support"
+msgstr " ze wspomaganiem OLE"
+
+msgid ""
+"\n"
+"MS-Windows 64-bit console version"
+msgstr ""
+"\n"
+"32 bitowa wersja na konsolÄ™ dla MS-Windows"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit console version"
+msgstr ""
+"\n"
+"32 bitowa wersja na konsolÄ™ dla MS-Windows"
+
+msgid ""
+"\n"
+"MS-Windows 16-bit version"
+msgstr ""
+"\n"
+"16 bitowa wersja dla MS-Windows"
+
+msgid ""
+"\n"
+"32-bit MS-DOS version"
+msgstr ""
+"\n"
+"32 bitowa wersja dla MS-DOS"
+
+msgid ""
+"\n"
+"16-bit MS-DOS version"
+msgstr ""
+"\n"
+"16 bitowa wersja dla MS-DOS"
+
+msgid ""
+"\n"
+"MacOS X (unix) version"
+msgstr ""
+"\n"
+"wersja dla MacOS X (unix)"
+
+msgid ""
+"\n"
+"MacOS X version"
+msgstr ""
+"\n"
+"wersja dla MacOS X"
+
+msgid ""
+"\n"
+"MacOS version"
+msgstr ""
+"\n"
+"wersja dla MacOS"
+
+msgid ""
+"\n"
+"OpenVMS version"
+msgstr ""
+"\n"
+"wersja dla OpenVMS"
+
+msgid ""
+"\n"
+"Included patches: "
+msgstr ""
+"\n"
+"Zadane Å‚aty: "
+
+msgid ""
+"\n"
+"Extra patches: "
+msgstr ""
+"\n"
+"Ekstra Å‚aty: "
+
+msgid "Modified by "
+msgstr "Zmieniony przez "
+
+msgid ""
+"\n"
+"Compiled "
+msgstr ""
+"\n"
+"Skompilowany "
+
+msgid "by "
+msgstr "przez "
+
+msgid ""
+"\n"
+"Huge version "
+msgstr ""
+"\n"
+"Olbrzymia wersja "
+
+msgid ""
+"\n"
+"Big version "
+msgstr ""
+"\n"
+"Duża wersja "
+
+msgid ""
+"\n"
+"Normal version "
+msgstr ""
+"\n"
+"Normalna wersja "
+
+msgid ""
+"\n"
+"Small version "
+msgstr ""
+"\n"
+"Mała wersja "
+
+msgid ""
+"\n"
+"Tiny version "
+msgstr ""
+"\n"
+"Malutka wersja "
+
+msgid "without GUI."
+msgstr "bez GUI."
+
+msgid "with GTK2-GNOME GUI."
+msgstr "z GTK2-GNOME GUI."
+
+msgid "with GTK2 GUI."
+msgstr "z GTK2 GUI."
+
+msgid "with X11-Motif GUI."
+msgstr "z X11-Motif GUI."
+
+msgid "with X11-neXtaw GUI."
+msgstr "z X11-neXtaw GUI."
+
+msgid "with X11-Athena GUI."
+msgstr "z X11-Athena GUI."
+
+msgid "with Photon GUI."
+msgstr "z Photon GUI."
+
+msgid "with GUI."
+msgstr "z GUI."
+
+msgid "with Carbon GUI."
+msgstr "z Carbon GUI."
+
+msgid "with Cocoa GUI."
+msgstr "z Cocoa GUI."
+
+msgid "with (classic) GUI."
+msgstr "z (klasycznym) GUI."
+
+msgid " Features included (+) or not (-):\n"
+msgstr " Opcje włączone (+) lub nie (-):\n"
+
+msgid " system vimrc file: \""
+msgstr " vimrc systemu: \""
+
+msgid " user vimrc file: \""
+msgstr " vimrc użytkownika: \""
+
+msgid " 2nd user vimrc file: \""
+msgstr " 2-gi plik vimrc użytkownika: \""
+
+msgid " 3rd user vimrc file: \""
+msgstr " 3-ci plik vimrc użytkownika: \""
+
+msgid " user exrc file: \""
+msgstr " exrc użytkownika: \""
+
+msgid " 2nd user exrc file: \""
+msgstr " 2-gi plik exrc użytkownika: \""
+
+msgid " system gvimrc file: \""
+msgstr " gvimrc systemu: \""
+
+msgid " user gvimrc file: \""
+msgstr " gvimrc użytkownika: \""
+
+msgid "2nd user gvimrc file: \""
+msgstr "2-gi plik gvimrc użytkownika: \""
+
+msgid "3rd user gvimrc file: \""
+msgstr "3-ci plik gvimrc użytkownika: \""
+
+msgid " system menu file: \""
+msgstr " systemowy plik menu: \""
+
+msgid " fall-back for $VIM: \""
+msgstr " odwet dla $VIM-a: \""
+
+msgid " f-b for $VIMRUNTIME: \""
+msgstr "f-b dla $VIMRUNTIME: \""
+
+msgid "Compilation: "
+msgstr "Kompilacja: "
+
+msgid "Compiler: "
+msgstr "Kompilator: "
+
+msgid "Linking: "
+msgstr "Konsolidacja: "
+
+msgid " DEBUG BUILD"
+msgstr " KOMPILACJA DEBUG"
+
+msgid "VIM - Vi IMproved"
+msgstr "VIM - Vi rozbudowany"
+
+msgid "version "
+msgstr "wersja "
+
+msgid "by Bram Moolenaar et al."
+msgstr "Autor: Bram Moolenaar i Inni."
+
+msgid "Vim is open source and freely distributable"
+msgstr "Vim jest open source i rozprowadzany darmowo"
+
+msgid "Help poor children in Uganda!"
+msgstr "Pomóż biednym dzieciom w Ugandzie!"
+
+msgid "type :help iccf<Enter> for information "
+msgstr "wprowadź :help iccf<Enter> dla informacji o tym "
+
+msgid "type :q<Enter> to exit "
+msgstr "wprowadź :q<Enter> zakończenie programu "
+
+msgid "type :help<Enter> or <F1> for on-line help"
+msgstr "wprowadź :help<Enter> lub <F1> pomoc na bieżąco "
+
+msgid "type :help version8<Enter> for version info"
+msgstr "wprowadź :help version8<Enter> dla informacji o wersji"
+
+msgid "Running in Vi compatible mode"
+msgstr "Działam w trybie zgodności z Vi"
+
+msgid "type :set nocp<Enter> for Vim defaults"
+msgstr "wprowadź :set nocp<Enter> wartości domyślne Vim-a"
+
+msgid "type :help cp-default<Enter> for info on this"
+msgstr "wprowadź :help cp-default<Enter> dla informacji to tym "
+
+msgid "menu Help->Orphans for information "
+msgstr "menu Pomoc->Sieroty dla informacji to tym "
+
+msgid "Running modeless, typed text is inserted"
+msgstr "Uruchomiony bez trybów, wpisany tekst jest wprowadzany"
+
+msgid "menu Edit->Global Settings->Toggle Insert Mode "
+msgstr "menu Edytuj->Ustawienia globalne->Tryb wstawiania"
+
+msgid " for two modes "
+msgstr " dla dwóch trybów "
+
+msgid "menu Edit->Global Settings->Toggle Vi Compatible"
+msgstr "menu Edytuj->Ustawienia globalne->Kompatybilność z Vi"
+
+msgid " for Vim defaults "
+msgstr " dla domyślnych ustawień Vima "
+
+msgid "Sponsor Vim development!"
+msgstr "Sponsoruj rozwój Vima!"
+
+msgid "Become a registered Vim user!"
+msgstr "Zostań zarejestrowanym użytkownikiem Vima!"
+
+msgid "type :help sponsor<Enter> for information "
+msgstr "wprowadź :help sponsor<Enter> dla informacji"
+
+msgid "type :help register<Enter> for information "
+msgstr "wprowadź :help register<Enter> dla informacji"
+
+msgid "menu Help->Sponsor/Register for information "
+msgstr "menu Pomoc->Sponsoruj/Zarejestruj siÄ™ dla informacji"
+
+msgid "WARNING: Windows 95/98/ME detected"
+msgstr "OSTRZEŻENIE: wykryto Windows 95/98/ME"
+
+msgid "type :help windows95<Enter> for info on this"
+msgstr "wprowadź :help windows95<Enter> dla informacji to tym "
+
+msgid "Already only one window"
+msgstr "Już jest tylko jeden widok"
+
+msgid "E441: There is no preview window"
+msgstr "E441: Nie ma okna podglÄ…du"
+
+msgid "E442: Can't split topleft and botright at the same time"
+msgstr "E442: Nie mogę rozdzielić lewo-górnego i prawo-dolnego jednocześnie"
+
+msgid "E443: Cannot rotate when another window is split"
+msgstr "E443: Nie mogę przekręcić, gdy inne okno jest rozdzielone"
+
+msgid "E444: Cannot close last window"
+msgstr "E444: Nie mogę zamknąć ostatniego okna"
+
+msgid "E813: Cannot close autocmd window"
+msgstr "E813: Nie można zamknąć okna autocmd"
+
+msgid "E814: Cannot close window, only autocmd window would remain"
+msgstr "E814: Nie można zamknąć okna, zostałoby tylko okno autocmd"
+
+msgid "E445: Other window contains changes"
+msgstr "E445: Inne okno zawiera zmiany"
+
+msgid "E446: No file name under cursor"
+msgstr "E446: Brak nazwy pliku pod kursorem"
+
+#, c-format
+msgid "E447: Can't find file \"%s\" in path"
+msgstr "E447: Nie mogę znaleźć pliku \"%s\" w tropie"
+
+#, c-format
+msgid "E370: Could not load library %s"
+msgstr "E370: Nie mogłem załadować biblioteki %s"
+
+msgid "Sorry, this command is disabled: the Perl library could not be loaded."
+msgstr ""
+"Przykro mi, ta komenda jest wyłączona: nie mogłem załadować biblioteki Perla."
+
+msgid "E299: Perl evaluation forbidden in sandbox without the Safe module"
+msgstr "E299: wyliczenie Perla zabronione w piaskownicy bez modułu Safe"
+
+msgid "Edit with &multiple Vims"
+msgstr "Edytuj w &wielu Vimach"
+
+msgid "Edit with single &Vim"
+msgstr "Edytuj w pojedynczym &Vimie"
+
+msgid "Diff with Vim"
+msgstr "Diff z Vimem"
+
+msgid "Edit with &Vim"
+msgstr "Edytuj w &Vimie"
+
+#. Now concatenate
+msgid "Edit with existing Vim - "
+msgstr "Edytuj z istniejÄ…cym Vimem - "
+
+msgid "Edits the selected file(s) with Vim"
+msgstr "Edytuj wybrane pliki w Vimie"
+
+msgid "Error creating process: Check if gvim is in your path!"
+msgstr "Błąd tworzenia procesu: Sprawdź czy gvim jest w twojej ścieżce!"
+
+msgid "gvimext.dll error"
+msgstr "błąd gvimext.dll"
+
+msgid "Path length too long!"
+msgstr "Za długa ścieżka!"
+
+msgid "--No lines in buffer--"
+msgstr "--Brak wierszy w buforze--"
+
+#.
+#. * The error messages that can be shared are included here.
+#. * Excluded are errors that are only used once and debugging messages.
+#.
+msgid "E470: Command aborted"
+msgstr "E470: Przerwanie komendy"
+
+msgid "E471: Argument required"
+msgstr "E471: wymagany argument"
+
+msgid "E10: \\ should be followed by /, ? or &"
+msgstr "E10: po \\ powinno być /, ? lub &"
+
+msgid "E11: Invalid in command-line window; <CR> executes, CTRL-C quits"
+msgstr ""
+"E11: Niedozwolone w oknie wiersza poleceń; <CR> wykonuje, CTRL-C opuszcza"
+
+msgid "E12: Command not allowed from exrc/vimrc in current dir or tag search"
+msgstr ""
+"E12: Komenda niedozwolona z exrc/vimrc w bieżącym szukaniu katalogu lub "
+"znacznika"
+
+msgid "E171: Missing :endif"
+msgstr "E171: Brak :endif"
+
+msgid "E600: Missing :endtry"
+msgstr "E600: Brak :endtry"
+
+msgid "E170: Missing :endwhile"
+msgstr "E170: Brak :endwhile"
+
+msgid "E170: Missing :endfor"
+msgstr "E170: Brak :endfor"
+
+msgid "E588: :endwhile without :while"
+msgstr "E588: :endwhile bez :while"
+
+msgid "E588: :endfor without :for"
+msgstr "E588: :endfor bez :for"
+
+msgid "E13: File exists (add ! to override)"
+msgstr "E13: Plik istnieje (wymuÅ› poprzez !)"
+
+msgid "E472: Command failed"
+msgstr "E472: Komenda nie powiodła się"
+
+#, c-format
+msgid "E234: Unknown fontset: %s"
+msgstr "E234: Nieznany zestaw czcionek: %s"
+
+#, c-format
+msgid "E235: Unknown font: %s"
+msgstr "E235: Nieznana czcionka: %s"
+
+#, c-format
+msgid "E236: Font \"%s\" is not fixed-width"
+msgstr "E236: Czcionka \"%s\" nie ma stałej szerokości znaków"
+
+msgid "E473: Internal error"
+msgstr "E473: Błąd wewnętrzny"
+
+msgid "Interrupted"
+msgstr "Przerwane"
+
+msgid "E14: Invalid address"
+msgstr "E14: Niewłaściwy adres"
+
+msgid "E474: Invalid argument"
+msgstr "E474: Niewłaściwy argument"
+
+#, c-format
+msgid "E475: Invalid argument: %s"
+msgstr "E475: Niewłaściwy argument: %s"
+
+#, c-format
+msgid "E15: Invalid expression: %s"
+msgstr "E15: Niewłaściwe wyrażenie: %s"
+
+msgid "E16: Invalid range"
+msgstr "E16: Niewłaściwy zakres"
+
+msgid "E476: Invalid command"
+msgstr "E476: Niewłaściwa komenda"
+
+#, c-format
+msgid "E17: \"%s\" is a directory"
+msgstr "E17: \"%s\" jest katalogiem"
+
+#, c-format
+msgid "E364: Library call failed for \"%s()\""
+msgstr "E364: Wywołanie z biblioteki nie powiodło się dla \"%s()\""
+
+#, c-format
+msgid "E448: Could not load library function %s"
+msgstr "E448: Nie można załadować funkcji biblioteki %s"
+
+msgid "E19: Mark has invalid line number"
+msgstr "E19: Zakładka ma niewłaściwy numer wiersza"
+
+msgid "E20: Mark not set"
+msgstr "E20: Zakładka nienastawiona"
+
+msgid "E21: Cannot make changes, 'modifiable' is off"
+msgstr "E21: Nie mogę wykonać zmian, 'modifiable' jest wyłączone"
+
+msgid "E22: Scripts nested too deep"
+msgstr "E22: Zbyt głębokie zagnieżdżenie skryptów"
+
+msgid "E23: No alternate file"
+msgstr "E23: Brak pliku zamiany"
+
+msgid "E24: No such abbreviation"
+msgstr "E24: Nie ma takiego skrótu"
+
+msgid "E477: No ! allowed"
+msgstr "E477: Niedozwolone !"
+
+msgid "E25: GUI cannot be used: Not enabled at compile time"
+msgstr "E25: GUI nie może być użyte: Nie włączono podczas kompilacji"
+
+msgid "E26: Hebrew cannot be used: Not enabled at compile time\n"
+msgstr "E26: Hebrajski nie może być użyty: Nie włączono podczas kompilacji\n"
+
+msgid "E27: Farsi cannot be used: Not enabled at compile time\n"
+msgstr "E27: Farsi nie może być użyty: Nie włączono podczas kompilacji\n"
+
+msgid "E800: Arabic cannot be used: Not enabled at compile time\n"
+msgstr "E800: Arabski nie może być użyty: Nie włączono podczas kompilacji\n"
+
+#, c-format
+msgid "E28: No such highlight group name: %s"
+msgstr "E28: Brak takiej nazwy grupy podświetlania: %s"
+
+msgid "E29: No inserted text yet"
+msgstr "E29: Nie wprowadzono jeszcze żadnego tekstu"
+
+msgid "E30: No previous command line"
+msgstr "E30: Nie ma poprzedniego wiersza poleceń"
+
+msgid "E31: No such mapping"
+msgstr "E31: Nie ma takiego przyporzÄ…dkowania"
+
+msgid "E479: No match"
+msgstr "E479: Brak dopasowań"
+
+#, c-format
+msgid "E480: No match: %s"
+msgstr "E480: Brak dopasowań: %s"
+
+msgid "E32: No file name"
+msgstr "E32: Brak nazwy pliku"
+
+msgid "E33: No previous substitute regular expression"
+msgstr "E33: Brak poprzedniego podstawieniowego wyrażenia regularnego"
+
+msgid "E34: No previous command"
+msgstr "E34: Brak poprzedniej komendy"
+
+msgid "E35: No previous regular expression"
+msgstr "E35: Brak poprzedniego wyrażenia regularnego"
+
+msgid "E481: No range allowed"
+msgstr "E481: Zakres niedozwolony"
+
+msgid "E36: Not enough room"
+msgstr "E36: Brak miejsca"
+
+#, c-format
+msgid "E247: no registered server named \"%s\""
+msgstr "E247: brak zarejestrowanego serwera o nazwie \"%s\""
+
+#, c-format
+msgid "E482: Can't create file %s"
+msgstr "E482: Nie mogę stworzyć pliku %s"
+
+msgid "E483: Can't get temp file name"
+msgstr "E483: Nie mogę pobrać nazwy pliku tymczasowego"
+
+#, c-format
+msgid "E484: Can't open file %s"
+msgstr "E484: Nie mogę otworzyć pliku %s"
+
+#, c-format
+msgid "E485: Can't read file %s"
+msgstr "E485: Nie mogę odczytać pliku %s"
+
+msgid "E37: No write since last change (add ! to override)"
+msgstr "E37: Nie zapisano od ostatniej zmiany (wymuÅ› przez !)"
+
+msgid "E38: Null argument"
+msgstr "E38: Zerowy argument"
+
+msgid "E39: Number expected"
+msgstr "E39: OczekujÄ™ liczby"
+
+#, c-format
+msgid "E40: Can't open errorfile %s"
+msgstr "E40: Nie mogę otworzyć pliku błędów %s"
+
+msgid "E233: cannot open display"
+msgstr "E233: nie mogę otworzyć ekranu"
+
+msgid "E41: Out of memory!"
+msgstr "E41: Pamięć wyczerpana!"
+
+msgid "Pattern not found"
+msgstr "Nie znaleziono wzorca"
+
+#, c-format
+msgid "E486: Pattern not found: %s"
+msgstr "E486: Nie znaleziono wzorca: %s"
+
+msgid "E487: Argument must be positive"
+msgstr "E487: Argument musi być dodatni"
+
+msgid "E459: Cannot go back to previous directory"
+msgstr "E459: Nie można przejść do poprzedniego katalogu"
+
+msgid "E42: No Errors"
+msgstr "E42: Brak Błędów"
+
+msgid "E776: No location list"
+msgstr "E776: Brak listy lokacji"
+
+msgid "E43: Damaged match string"
+msgstr "E43: Popsuty ciÄ…g wzorca"
+
+msgid "E44: Corrupted regexp program"
+msgstr "E44: Zepsuty program wyrażeń regularnych"
+
+msgid "E45: 'readonly' option is set (add ! to override)"
+msgstr "E45: opcja 'readonly' jest ustawiona (wymuÅ› poprzez !)"
+
+#, c-format
+msgid "E46: Cannot change read-only variable \"%s\""
+msgstr "E46: Nie mogę zmienić zmiennej tylko do odczytu \"%s\""
+
+#, c-format
+msgid "E794: Cannot set variable in the sandbox: \"%s\""
+msgstr "E794: Nie mogę ustawić zmiennej w piaskownicy: \"%s\""
+
+msgid "E47: Error while reading errorfile"
+msgstr "E47: Błąd w trakcie czytania pliku błędów"
+
+msgid "E48: Not allowed in sandbox"
+msgstr "E48: Niedozwolone w piaskownicy"
+
+msgid "E523: Not allowed here"
+msgstr "E523: Niedozwolone w tym miejscu"
+
+msgid "E359: Screen mode setting not supported"
+msgstr "E359: Ustawianie trybu ekranu niewspomagane"
+
+msgid "E49: Invalid scroll size"
+msgstr "E49: Niewłaściwa wielkość przewinięcia"
+
+msgid "E91: 'shell' option is empty"
+msgstr "E91: opcja 'shell' jest pusta"
+
+msgid "E255: Couldn't read in sign data!"
+msgstr "E255: Nie mogłem wczytać danych znaku!"
+
+msgid "E72: Close error on swap file"
+msgstr "E72: BÅ‚Ä…d podczas zamykania pliku wymiany"
+
+msgid "E73: tag stack empty"
+msgstr "E73: stos znaczników jest pusty"
+
+msgid "E74: Command too complex"
+msgstr "E74: Komenda jest zbyt skomplikowana"
+
+msgid "E75: Name too long"
+msgstr "E75: Zbyt długa nazwa"
+
+msgid "E76: Too many ["
+msgstr "E76: Zbyt wiele ["
+
+msgid "E77: Too many file names"
+msgstr "E77: Zbyt wiele nazw plików"
+
+msgid "E488: Trailing characters"
+msgstr "E488: Nadstępne znaczki"
+
+msgid "E78: Unknown mark"
+msgstr "E78: Nieznana zakładka"
+
+msgid "E79: Cannot expand wildcards"
+msgstr "E79: Nie mogą rozwinąć znaków wieloznacznych"
+
+msgid "E591: 'winheight' cannot be smaller than 'winminheight'"
+msgstr "E591: 'winheight' nie może być mniejsze niż 'winminheight'"
+
+msgid "E592: 'winwidth' cannot be smaller than 'winminwidth'"
+msgstr "E592: 'winwidth' nie może być mniejsze niż 'winminwidth'"
+
+msgid "E80: Error while writing"
+msgstr "E80: BÅ‚Ä…d w trakcie zapisu"
+
+msgid "Zero count"
+msgstr "Zerowy licznik"
+
+msgid "E81: Using <SID> not in a script context"
+msgstr "E81: Użycie <SID> poza kontekstem skryptu"
+
+msgid "E449: Invalid expression received"
+msgstr "E449: Odebrałem niewłaściwe wyrażenie"
+
+msgid "E463: Region is guarded, cannot modify"
+msgstr "E463: Region jest chroniony, nie mogę zmienić"
+
+msgid "E744: NetBeans does not allow changes in read-only files"
+msgstr "E744: NetBeans nie zezwala na zmiany w plikach tylko do odczytu"
+
+#, c-format
+msgid "E685: Internal error: %s"
+msgstr "E685: Błąd wewnętrzny: %s"
+
+msgid "E363: pattern uses more memory than 'maxmempattern'"
+msgstr "E363: Wzorzec używa więcej pamięci niż 'maxmempattern'"
+
+msgid "E749: empty buffer"
+msgstr "E749: pusty bufor"
+
+msgid "E682: Invalid search pattern or delimiter"
+msgstr "E682: Niewłaściwy wzorzec wyszukiwania lub delimiter"
+
+msgid "E139: File is loaded in another buffer"
+msgstr "E139: Plik jest załadowany w innym buforze"
+
+#, c-format
+msgid "E764: Option '%s' is not set"
+msgstr "E764: Nie ustawiono opcji '%s'"
+
+msgid "E850: Invalid register name"
+msgstr "E850: Niewłaściwa nazwa rejestru"
+
+msgid "search hit TOP, continuing at BOTTOM"
+msgstr "szukanie dobiło GÓRY; kontynuacja od KOŃCA"
+
+msgid "search hit BOTTOM, continuing at TOP"
+msgstr "szukanie dobiło KOŃCA; kontynuacja od GÓRY"
+
+#, c-format
+msgid "Need encryption key for \"%s\""
+msgstr "PotrzebujÄ™ klucza szyfrowania dla \"%s\""
+
+msgid "empty keys are not allowed"
+msgstr "puste klucze nie sÄ… dozwolone"
+
+msgid "dictionary is locked"
+msgstr "słownik jest zablokowany"
+
+msgid "list is locked"
+msgstr "lista jest zablokowana"
+
+#, c-format
+msgid "failed to add key '%s' to dictionary"
+msgstr "nie powiodło się dodanie klucza '%s' do słownika"
+
+#, c-format
+msgid "index must be int or slice, not %s"
+msgstr "indeks musi być liczbą lub wycinkiem, nie %s"
+
+#, c-format
+msgid "expected str() or unicode() instance, but got %s"
+msgstr "czekałem na str() lub unicode(), a dostałem %s"
+
+#, c-format
+msgid "expected bytes() or str() instance, but got %s"
+msgstr "czekałem na bytes() lub str(), a dostałem %s"
+
+#, c-format
+msgid ""
+"expected int(), long() or something supporting coercing to long(), but got %s"
+msgstr ""
+"czekałem na int(), long() lub coś co można zmienić na long(), ale dostałem %s"
+
+#, c-format
+msgid "expected int() or something supporting coercing to int(), but got %s"
+msgstr "czekałem na int() lub coś co można zmienić na int(), ale dostałem %s"
+
+msgid "value is too large to fit into C int type"
+msgstr "wartość zbyt duża by zmieściła się w typie int C"
+
+msgid "value is too small to fit into C int type"
+msgstr "wartość jest zbyt mała by zmieściła się w typie int C"
+
+msgid "number must be greater then zero"
+msgstr "liczba musi być większa niż zero"
+
+msgid "number must be greater or equal to zero"
+msgstr "liczba musi być większa lub mniejsza niż zero"
+
+msgid "can't delete OutputObject attributes"
+msgstr "nie mogę skasować atrybutów OutputObject"
+
+#, c-format
+msgid "invalid attribute: %s"
+msgstr "niepoprawny atrybut: %s"
+
+msgid "E264: Python: Error initialising I/O objects"
+msgstr "E264: Python: Błąd w uruchomieniu obiektów I/O"
+
+msgid "failed to change directory"
+msgstr "nie powiodła się zmiana katalogu"
+
+#, c-format
+msgid "expected 3-tuple as imp.find_module() result, but got %s"
+msgstr "czekałem na 3-krotkę jako wynik imp.find_module(), a dostałem %s"
+
+#, c-format
+msgid "expected 3-tuple as imp.find_module() result, but got tuple of size %d"
+msgstr "czekałem na 3-krotkę jako wynik imp.find_module(), a dostałem krotkę o wielkości %d"
+
+msgid "internal error: imp.find_module returned tuple with NULL"
+msgstr "wewnętrzny błąd: imp.find_module zwrócił krotkę z NULL"
+
+msgid "cannot delete vim.Dictionary attributes"
+msgstr "nie mogę usunąć atrybutów vim.Dictionary"
+
+msgid "cannot modify fixed dictionary"
+msgstr "nie mogę zmienić zablokowanego słownika"
+
+#, c-format
+msgid "cannot set attribute %s"
+msgstr "nie mogę ustawić atrybutu %s"
+
+msgid "hashtab changed during iteration"
+msgstr "hashtab zmienił się w czasie iteracji"
+
+#, c-format
+msgid "expected sequence element of size 2, but got sequence of size %d"
+msgstr "czekałem na element sekwencyjny od długości 2, a dostałem sekwencję o długości %d"
+
+msgid "list constructor does not accept keyword arguments"
+msgstr "konstruktor listy nie akceptuje słów kluczowych jako argumentów"
+
+msgid "list index out of range"
+msgstr "indeks listy poza zakresem"
+
+#. No more suitable format specifications in python-2.3
+#, c-format
+msgid "internal error: failed to get vim list item %d"
+msgstr "błąd wewnętrzny: nie powiodło się pobranie z listy Vima elementu %d"
+
+msgid "failed to add item to list"
+msgstr "nie powiodło się dodanie elementu do listy"
+
+#, c-format
+msgid "internal error: no vim list item %d"
+msgstr "błąd wewnętrzny: w liście Vima brak elementu %d"
+
+msgid "internal error: failed to add item to list"
+msgstr "błąd wewnętrzny: nie powiodło się dodanie elementu do listy"
+
+msgid "cannot delete vim.List attributes"
+msgstr "nie mogę usunąć atrybutów vim.List"
+
+msgid "cannot modify fixed list"
+msgstr "nie mogę zmienić zablokowanej listy"
+
+#, c-format
+msgid "unnamed function %s does not exist"
+msgstr "nie nazwana funkcja %s nie istnieje"
+
+#, c-format
+msgid "function %s does not exist"
+msgstr "funkcja %s nie istnieje"
+
+msgid "function constructor does not accept keyword arguments"
+msgstr "konstruktor funkcji nie akceptuje słów kluczowych jako argumentów"
+
+#, c-format
+msgid "failed to run function %s"
+msgstr "nie mogę uruchomić funkcji %s"
+
+msgid "unable to get option value"
+msgstr "nie mogę pobrać wartości opcji"
+
+msgid "internal error: unknown option type"
+msgstr "błąd wewnętrzny: nieznany typ opcji"
+
+msgid "problem while switching windows"
+msgstr "wystąpił problem w czasie zmiany okien"
+
+#, c-format
+msgid "unable to unset global option %s"
+msgstr "nie mogę wyzerować opcji globalnej %s"
+
+#, c-format
+msgid "unable to unset option %s which does not have global value"
+msgstr "nie mogę wyzerować opcji %s, która nie ma wartości globalnej"
+
+msgid "attempt to refer to deleted tab page"
+msgstr "próba odniesienia do skasowanej karty"
+
+msgid "no such tab page"
+msgstr "nie ma takiej karty"
+
+msgid "attempt to refer to deleted window"
+msgstr "próba odniesienia do skasowanego okna"
+
+msgid "readonly attribute: buffer"
+msgstr "atrybut tylko do odczytu: bufor"
+
+msgid "cursor position outside buffer"
+msgstr "pozycja kursora poza buforem"
+
+msgid "no such window"
+msgstr "nie ma takiego okna"
+
+msgid "attempt to refer to deleted buffer"
+msgstr "próba odniesienia do skasowanego bufora"
+
+msgid "failed to rename buffer"
+msgstr "nie powiodła się zmiana nazwy bufora"
+
+msgid "mark name must be a single character"
+msgstr "nazwa zakładki musi być pojedynczym znakiem"
+
+#, c-format
+msgid "expected vim.Buffer object, but got %s"
+msgstr "oczekiwałem na obiekt vim.Buffer, a dostałem %s"
+
+#, c-format
+msgid "failed to switch to buffer %d"
+msgstr "nie przeszedłem do bufora %d"
+
+#, c-format
+msgid "expected vim.Window object, but got %s"
+msgstr "oczekiwałem na obiekt vim.Window, a dostałem %s"
+
+msgid "failed to find window in the current tab page"
+msgstr "nie znaleziono okna na bieżącej karcie"
+
+msgid "did not switch to the specified window"
+msgstr "nie przeszedłem do określonego okna"
+
+#, c-format
+msgid "expected vim.TabPage object, but got %s"
+msgstr "oczekiwałem na obiekt vim.TabPage, a dostałem %s"
+
+msgid "did not switch to the specified tab page"
+msgstr "nie przeszedłem do określonej karty"
+
+msgid "failed to run the code"
+msgstr "uruchomienie kodu się nie powiodło"
+
+msgid "E858: Eval did not return a valid python object"
+msgstr "E858: eval nie zwróciło odpowiedniego obiektu pythona"
+
+msgid "E859: Failed to convert returned python object to vim value"
+msgstr "E859: Nie powiodła się konwersja obiektu pythona do wartości Vima"
+
+#, c-format
+msgid "unable to convert %s to vim dictionary"
+msgstr "nie można konwertować %s do słownika Vima"
+
+#, c-format
+msgid "unable to convert %s to vim structure"
+msgstr "nie można konwertować %s do struktury Vima"
+
+msgid "internal error: NULL reference passed"
+msgstr "błąd wewnętrzny: przekazano referencję NULL"
+
+msgid "internal error: invalid value type"
+msgstr "błąd wewnętrzny: błędny typ wartości"
+
+msgid ""
+"Failed to set path hook: sys.path_hooks is not a list\n"
+"You should now do the following:\n"
+"- append vim.path_hook to sys.path_hooks\n"
+"- append vim.VIM_SPECIAL_PATH to sys.path\n"
+msgstr ""
+"Nie mogę ustawić haka ścieżki: sys.path_hooks nie jest listą\n"
+"Powinieneś teraz wykonać następujące czynności:\n"
+"- dodać vim.path_hook do sys.path_hooks\n"
+"- dodać vim.VIM_SPECIAL_PATH do sys.path\n"
+
+msgid ""
+"Failed to set path: sys.path is not a list\n"
+"You should now append vim.VIM_SPECIAL_PATH to sys.path"
+msgstr ""
+"Nie mogę ustawić ścieżki: sys.path nie jest listą\n"
+"Powinno się teraz dodać vim.VIM_SPECIAL_PATH do sys.path"
+
+#~ msgid "softspace must be an integer"
+#~ msgstr "softspace musi być liczbą całkowitą"
+
+#~ msgid "<buffer object (deleted) at %p>"
+#~ msgstr "<obiekt bufora (skasowany) w %p>"
+
+#~ msgid ""
+#~ "E281: TCL ERROR: exit code is not int!? Please report this to vim-dev@vim."
+#~ "org"
+#~ msgstr ""
+#~ "E281: BÅÄ„D TCL: kod zakoÅ„czeniowy nie jest caÅ‚kowity!? ProszÄ™ zÅ‚ożyć "
+#~ "raport o tym na vim-dev@vim.org"
+
+#~ msgid ""
+#~ "\n"
+#~ "Arguments recognised by gvim (RISC OS version):\n"
+#~ msgstr ""
+#~ "\n"
+#~ "Argumenty rozpoznawane przez gvim (wersja RISC OS):\n"
+
+#~ msgid "--columns <number>\tInitial width of window in columns"
+#~ msgstr "--columns <number>\tPoczątkowa szerokość okna w kolumnach"
+
+#~ msgid "--rows <number>\tInitial height of window in rows"
+#~ msgstr "--rows <number>\tPoczątkowa wysokość okna w wierszach"
+
+#~ msgid "E505: "
+#~ msgstr "E505: "
+
+#~ msgid ""
+#~ "\n"
+#~ "RISC OS version"
+#~ msgstr ""
+#~ "\n"
+#~ "wersja dla RISC OS"
+
+#~ msgid "writelines() requires list of strings"
+#~ msgstr "writelines() wymaga listy ciągów"
+
+#~ msgid "<window object (deleted) at %p>"
+#~ msgstr "<obiekt okna (skasowany) w %p>"
+
+#~ msgid "<window object (unknown) at %p>"
+#~ msgstr "<obiekt okna (nieznany) w %p>"
+
+#~ msgid "<window %d>"
+#~ msgstr "<okno %d>"
+
+#~ msgid "-name <name>\t\tUse resource as if vim was <name>"
+#~ msgstr "-name <nazwa>\t\tUżywaj zasobów tak jak by Vim był <nazwa>"
+
+#~ msgid "\t\t\t (Unimplemented)\n"
+#~ msgstr "\t\t\t (Niezaimplementowane)\n"
+
+#~ msgid "E396: containedin argument not accepted here"
+#~ msgstr "E396: argument containedin niedozwolony w tym miejscu"
+
+#~ msgid "Vim dialog..."
+#~ msgstr "Dialog Vima..."
+
+#~ msgid "Font Selection"
+#~ msgstr "Wybór czcionki"
+
+#~ msgid "E290: over-the-spot style requires fontset"
+#~ msgstr "E290: styl nadpunktowy wymaga +fontset"
+
+#~ msgid "E291: Your GTK+ is older than 1.2.3. Status area disabled"
+#~ msgstr "E291: Twój GTK+ jest starszy niż 1.2.3. Pole statusu wyłączono"
+
+#~ msgid "E292: Input Method Server is not running"
+#~ msgstr "E292: Serwer metod wprowadzeń nie jest uruchomiony"
+
+#~ msgid "with GTK-GNOME GUI."
+#~ msgstr "z GTK-GNOME GUI."
+
+#~ msgid "with GTK GUI."
+#~ msgstr "z GTK GUI."
+
+#~ msgid "[NL found]"
+#~ msgstr "[znaleziono NL]"
+
+#~ msgid "E569: maximum number of cscope connections reached"
+#~ msgstr "E569: wyczerpano maksymalną liczbę połączeń cscope"
diff --git a/src/po/pl.cp1250.po b/src/po/pl.cp1250.po
new file mode 100644
index 0000000..382a52b
--- /dev/null
+++ b/src/po/pl.cp1250.po
@@ -0,0 +1,6904 @@
+# Polish translation for Vim
+#
+# updated 2013 for vim-7.4
+#
+# FIRST AUTHOR Marcin Dalecki <martin@dalecki.de>, 2000.
+# Mikolaj Machowski <mikmach@wp.pl>, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2013.
+msgid ""
+msgstr ""
+"Project-Id-Version: pl\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2013-07-06 19:33+0200\n"
+"PO-Revision-Date: 2010-08-10 18:15+0200\n"
+"Last-Translator: Mikolaj Machowski <mikmach@wp.pl>\n"
+"Language-Team: Polish\n"
+"Language: pl\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=cp1250\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Lokalize 1.0\n"
+"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
+"|| n%100>=20) ? 1 : 2);\n"
+
+msgid "E831: bf_key_init() called with empty password"
+msgstr "E831: bf_key_init() wywo³any z pustym has³em"
+
+msgid "E820: sizeof(uint32_t) != 4"
+msgstr "E820: sizeof(uint32_t) != 4"
+
+msgid "E817: Blowfish big/little endian use wrong"
+msgstr "E817: Blowfish u¿ywa b³êdnej kolejnoœci bajtów"
+
+msgid "E818: sha256 test failed"
+msgstr "E818: test sha256 nie powiód³ siê"
+
+msgid "E819: Blowfish test failed"
+msgstr "E819: test Blowfisha nie powiód³ siê"
+
+msgid "[Location List]"
+msgstr "[Lista lokacji]"
+
+msgid "[Quickfix List]"
+msgstr "[Lista quickfix]"
+
+msgid "E855: Autocommands caused command to abort"
+msgstr "E855: Autokomendy spowodowa³y porzucenie komendy"
+
+msgid "E82: Cannot allocate any buffer, exiting..."
+msgstr "E82: Nie mogê zarezerwowaæ bufora; zakoñczenie..."
+
+msgid "E83: Cannot allocate buffer, using other one..."
+msgstr "E83: Nie mogê zarezerwowaæ bufora; u¿ywam innego..."
+
+msgid "E515: No buffers were unloaded"
+msgstr "E515: Nie wy³adowano ¿adnego bufora"
+
+msgid "E516: No buffers were deleted"
+msgstr "E516: Nie skasowano ¿adnego bufora"
+
+msgid "E517: No buffers were wiped out"
+msgstr "E517: Nie wyrzucono ¿adnego bufora"
+
+msgid "1 buffer unloaded"
+msgstr "1 bufor wy³adowany"
+
+#, c-format
+msgid "%d buffers unloaded"
+msgstr "wy³adowano %d buforów"
+
+msgid "1 buffer deleted"
+msgstr "1 bufor skasowany"
+
+#, c-format
+msgid "%d buffers deleted"
+msgstr "%d buforów skasowano"
+
+msgid "1 buffer wiped out"
+msgstr "wyrzucono 1 bufor "
+
+#, c-format
+msgid "%d buffers wiped out"
+msgstr "wyrzucono %d buforów"
+
+msgid "E84: No modified buffer found"
+msgstr "E84: Nie znaleziono zmienionych buforów"
+
+#. back where we started, didn't find anything.
+msgid "E85: There is no listed buffer"
+msgstr "E85: Nie ma wylistowanych buforów"
+
+#, c-format
+msgid "E86: Buffer %ld does not exist"
+msgstr "E86: Bufor \"%ld\" nie istnieje"
+
+msgid "E87: Cannot go beyond last buffer"
+msgstr "E87: Nie mogê przejœæ poza ostatni bufor"
+
+msgid "E88: Cannot go before first buffer"
+msgstr "E88: Nie mogê przejœæ przed pierwszy bufor"
+
+#, c-format
+msgid "E89: No write since last change for buffer %ld (add ! to override)"
+msgstr "E89: Nie zapisano zmian w buforze %ld (wymuœ przez !)"
+
+msgid "E90: Cannot unload last buffer"
+msgstr "E90: Nie mogê wy³adowaæ ostatniego bufora"
+
+msgid "W14: Warning: List of file names overflow"
+msgstr "W14: OSTRZE¯ENIE: Przepe³nienie listy nazw plików"
+
+#, c-format
+msgid "E92: Buffer %ld not found"
+msgstr "E92: Nie znaleziono bufora %ld"
+
+#, c-format
+msgid "E93: More than one match for %s"
+msgstr "E93: Wielokrotne dopasowania dla %s"
+
+#, c-format
+msgid "E94: No matching buffer for %s"
+msgstr "E94: ¯aden bufor nie pasuje do %s"
+
+#, c-format
+msgid "line %ld"
+msgstr "wiersz %ld"
+
+msgid "E95: Buffer with this name already exists"
+msgstr "E95: Bufor o tej nazwie ju¿ istnieje"
+
+msgid " [Modified]"
+msgstr " [Zmieniony]"
+
+msgid "[Not edited]"
+msgstr "[Nie edytowany]"
+
+msgid "[New file]"
+msgstr "[Nowy Plik]"
+
+msgid "[Read errors]"
+msgstr "[B³¹d odczytu]"
+
+msgid "[RO]"
+msgstr "[RO]"
+
+msgid "[readonly]"
+msgstr "[tylko odczyt]"
+
+#, c-format
+msgid "1 line --%d%%--"
+msgstr "1 wiersz --%d%%--"
+
+#, c-format
+msgid "%ld lines --%d%%--"
+msgstr "%ld wiersze --%d%%--"
+
+#, c-format
+msgid "line %ld of %ld --%d%%-- col "
+msgstr "wiersz %ld z %ld --%d%%-- kol "
+
+msgid "[No Name]"
+msgstr "[Bez nazwy]"
+
+#. must be a help buffer
+msgid "help"
+msgstr "pomoc"
+
+msgid "[Help]"
+msgstr "[Pomoc]"
+
+msgid "[Preview]"
+msgstr "[Podgl¹d]"
+
+msgid "All"
+msgstr "Wszystko"
+
+msgid "Bot"
+msgstr "Dó³"
+
+msgid "Top"
+msgstr "Góra"
+
+msgid ""
+"\n"
+"# Buffer list:\n"
+msgstr ""
+"\n"
+"# Lista buforów:\n"
+
+msgid "[Scratch]"
+msgstr "[Notka]"
+
+msgid ""
+"\n"
+"--- Signs ---"
+msgstr ""
+"\n"
+"--- Znaki ---"
+
+#, c-format
+msgid "Signs for %s:"
+msgstr "Znaki dla %s:"
+
+#, c-format
+msgid " line=%ld id=%d name=%s"
+msgstr " wiersz=%ld id=%d nazwa=%s"
+
+#, c-format
+msgid "E96: Can not diff more than %ld buffers"
+msgstr "E96: Nie mogê zró¿nicowaæ wiêcej ni¿ %ld buforów"
+
+msgid "E810: Cannot read or write temp files"
+msgstr "E810: Nie mogê otworzyæ lub zapisaæ plików tymczasowych"
+
+msgid "E97: Cannot create diffs"
+msgstr "E97: Nie mogê stworzyæ ró¿nic"
+
+msgid "Patch file"
+msgstr "Plik ³ata"
+
+msgid "E816: Cannot read patch output"
+msgstr "E816: Nie mogê odczytaæ wyjœcia pliku ³aty"
+
+msgid "E98: Cannot read diff output"
+msgstr "E98: Nie mogê wczytaæ wyjœcia ró¿nicy"
+
+msgid "E99: Current buffer is not in diff mode"
+msgstr "E99: Bie¿¹cy bufor nie jest w trybie ró¿nic"
+
+msgid "E793: No other buffer in diff mode is modifiable"
+msgstr "E793: ¯aden inny bufor w trybie diff nie jest modyfikowalny"
+
+msgid "E100: No other buffer in diff mode"
+msgstr "E100: Brak innego bufora w trybie ró¿nic"
+
+msgid "E101: More than two buffers in diff mode, don't know which one to use"
+msgstr ""
+"E101: Wiêcej ni¿ jeden bufor w trybie ró¿nicowania, nie wiem którego u¿yæ"
+
+#, c-format
+msgid "E102: Can't find buffer \"%s\""
+msgstr "E102: Nie mogê znaleŸæ bufora \"%s\""
+
+#, c-format
+msgid "E103: Buffer \"%s\" is not in diff mode"
+msgstr "E103: Bufor \"%s\" nie jest w trybie ró¿nicowania"
+
+msgid "E787: Buffer changed unexpectedly"
+msgstr "E787: Nieoczekiwana zmiana bufora"
+
+msgid "E104: Escape not allowed in digraph"
+msgstr "E104: Escape jest niedozwolone w dwugrafie"
+
+msgid "E544: Keymap file not found"
+msgstr "E544: Nie znaleziono pliku rozk³adu klawiszy"
+
+msgid "E105: Using :loadkeymap not in a sourced file"
+msgstr "E105: Zastosowano :loadkeymap w niewczytanym pliku"
+
+msgid "E791: Empty keymap entry"
+msgstr "E791: Pusty wpis keymap"
+
+msgid " Keyword completion (^N^P)"
+msgstr " Dope³nianie s³ów kluczowych (^N^P)"
+
+#. ctrl_x_mode == 0, ^P/^N compl.
+msgid " ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+msgstr " ^X tryb (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+
+msgid " Whole line completion (^L^N^P)"
+msgstr " Dope³nianie pe³nych wierszy (^L^N^P)"
+
+msgid " File name completion (^F^N^P)"
+msgstr " Dope³nianie nazw plików (^F^N^P)"
+
+msgid " Tag completion (^]^N^P)"
+msgstr " Dope³nianie znaczników (^]^N^P)"
+
+msgid " Path pattern completion (^N^P)"
+msgstr " Dope³nianie wzorców tropów (^N^P)"
+
+msgid " Definition completion (^D^N^P)"
+msgstr " Dope³nianie definicji (^D^N^P)"
+
+msgid " Dictionary completion (^K^N^P)"
+msgstr " Dope³nianie ze s³owników (^K^N^P)"
+
+msgid " Thesaurus completion (^T^N^P)"
+msgstr " Dope³nianie z tezaurusa (^T^N^P)"
+
+msgid " Command-line completion (^V^N^P)"
+msgstr " Dope³nianie wiersza poleceñ (^V^N^P)"
+
+msgid " User defined completion (^U^N^P)"
+msgstr "Dope³nianie zdefiniowane przez u¿ytkownika (^U^N^P)"
+
+msgid " Omni completion (^O^N^P)"
+msgstr " Omni uzupe³nianie (^O^N^P)"
+
+msgid " Spelling suggestion (s^N^P)"
+msgstr "Propozycja pisowni (^L^N^P)"
+
+msgid " Keyword Local completion (^N^P)"
+msgstr " Lokalne dope³nianie s³ów kluczowych (^N^P)"
+
+msgid "Hit end of paragraph"
+msgstr "Dobi³em do koñca akapitu"
+
+msgid "E839: Completion function changed window"
+msgstr "E839: Funkcja uzupe³niania zmieni³a okno"
+
+msgid "E840: Completion function deleted text"
+msgstr "E840: Funkcja uzupe³nania usunê³a tekst"
+
+msgid "'dictionary' option is empty"
+msgstr "opcja 'dictionary' jest pusta"
+
+msgid "'thesaurus' option is empty"
+msgstr "opcja 'thesaurus' jest pusta"
+
+#, c-format
+msgid "Scanning dictionary: %s"
+msgstr "Przegl¹dam s³ownik: %s"
+
+msgid " (insert) Scroll (^E/^Y)"
+msgstr " (wprowadzanie) Przewijanie (^E/^Y)"
+
+msgid " (replace) Scroll (^E/^Y)"
+msgstr " (zamiana) Przewijanie (^E/^Y)"
+
+#, c-format
+msgid "Scanning: %s"
+msgstr "Przegl¹dam: %s"
+
+msgid "Scanning tags."
+msgstr "Przegl¹dam znaczniki."
+
+msgid " Adding"
+msgstr " Dodajê"
+
+#. showmode might reset the internal line pointers, so it must
+#. * be called before line = ml_get(), or when this address is no
+#. * longer needed. -- Acevedo.
+#.
+msgid "-- Searching..."
+msgstr "-- Szukam..."
+
+msgid "Back at original"
+msgstr "Z powrotem na pierwotnym"
+
+msgid "Word from other line"
+msgstr "Wyraz z innego wiersza"
+
+msgid "The only match"
+msgstr "Jedyne dopasowanie"
+
+#, c-format
+msgid "match %d of %d"
+msgstr "pasuje %d z %d"
+
+#, c-format
+msgid "match %d"
+msgstr "pasuje %d"
+
+msgid "E18: Unexpected characters in :let"
+msgstr "E18: Nieoczekiwane znaki w :let"
+
+#, c-format
+msgid "E684: list index out of range: %ld"
+msgstr "E684: Indeks listy poza zakresem: %ld"
+
+#, c-format
+msgid "E121: Undefined variable: %s"
+msgstr "E121: Nieokreœlona zmienna: %s"
+
+msgid "E111: Missing ']'"
+msgstr "E111: Brak ']'"
+
+#, c-format
+msgid "E686: Argument of %s must be a List"
+msgstr "E686: Argument %s musi byæ List¹"
+
+#, c-format
+msgid "E712: Argument of %s must be a List or Dictionary"
+msgstr "E712: Argument %s musi byæ List¹ lub S³ownikiem"
+
+msgid "E713: Cannot use empty key for Dictionary"
+msgstr "E713: Nie mo¿na u¿yæ pustego klucza dla S³ownika"
+
+msgid "E714: List required"
+msgstr "E714: wymagana Lista"
+
+msgid "E715: Dictionary required"
+msgstr "E715: wymagany S³ownik"
+
+#, c-format
+msgid "E118: Too many arguments for function: %s"
+msgstr "E118: Zbyt wiele argumentów dla funkcji: %s"
+
+#, c-format
+msgid "E716: Key not present in Dictionary: %s"
+msgstr "E716: Klucz nie istnieje w S³owniku: %s"
+
+#, c-format
+msgid "E122: Function %s already exists, add ! to replace it"
+msgstr "E122: Funkcja %s ju¿ istnieje; aby j¹ zamieniæ u¿yj !"
+
+msgid "E717: Dictionary entry already exists"
+msgstr "E717: istnieje ju¿ taki element S³ownika"
+
+msgid "E718: Funcref required"
+msgstr "E718: wymagana Funcref"
+
+msgid "E719: Cannot use [:] with a Dictionary"
+msgstr "E719: Nie mo¿na u¿yæ [:] przy S³owniku"
+
+#, c-format
+msgid "E734: Wrong variable type for %s="
+msgstr "E734: Z³y typ zmiennej dla %s="
+
+#, c-format
+msgid "E130: Unknown function: %s"
+msgstr "E130: Nieznana funkcja: %s"
+
+#, c-format
+msgid "E461: Illegal variable name: %s"
+msgstr "E461: Niedozwolona nazwa zmiennej: %s"
+
+msgid "E806: using Float as a String"
+msgstr "E806: U¿ycie Zmiennoprzecinkowej jako £añcucha"
+
+msgid "E687: Less targets than List items"
+msgstr "E687: Mniej celów ni¿ elementów Listy"
+
+msgid "E688: More targets than List items"
+msgstr "E688: Wiêcej celów ni¿ elementów Listy"
+
+msgid "Double ; in list of variables"
+msgstr "Podwójny ; w liœcie zmiennych"
+
+#, c-format
+msgid "E738: Can't list variables for %s"
+msgstr "E738: Nie mogê wypisaæ zmiennych dla %s"
+
+msgid "E689: Can only index a List or Dictionary"
+msgstr "E689: Indeks mo¿e istnieæ tylko dla Listy lub S³ownika"
+
+msgid "E708: [:] must come last"
+msgstr "E708: [:] musi byæ ostatnie"
+
+msgid "E709: [:] requires a List value"
+msgstr "E709: [:] wymaga wartoœci listy"
+
+msgid "E710: List value has more items than target"
+msgstr "E710: Lista ma wiêcej elementów ni¿ cel"
+
+msgid "E711: List value has not enough items"
+msgstr "E711: Lista nie ma wystarczaj¹cej iloœci elementów"
+
+msgid "E690: Missing \"in\" after :for"
+msgstr "E690: Brak \"in\" po :for"
+
+#, c-format
+msgid "E107: Missing parentheses: %s"
+msgstr "E107: Brak nawiasów: %s"
+
+#, c-format
+msgid "E108: No such variable: \"%s\""
+msgstr "E108: Nie istnieje zmienna: \"%s\""
+
+msgid "E743: variable nested too deep for (un)lock"
+msgstr "E743: zmienna zagnie¿d¿ona zbyt g³êboko dla (un)lock"
+
+msgid "E109: Missing ':' after '?'"
+msgstr "E109: Brak ':' po '?'"
+
+msgid "E691: Can only compare List with List"
+msgstr "E691: Listê mogê porównaæ tylko z List¹"
+
+msgid "E692: Invalid operation for List"
+msgstr "E692: Nieprawid³owa operacja dla Listy"
+
+msgid "E735: Can only compare Dictionary with Dictionary"
+msgstr "E735: S³ownik mogê porównaæ tylko ze S³ownikiem"
+
+msgid "E736: Invalid operation for Dictionary"
+msgstr "E736: Nieprawid³owa operacja dla S³ownika"
+
+msgid "E693: Can only compare Funcref with Funcref"
+msgstr "E693: Funcref mogê porównaæ tylko z Funcref"
+
+msgid "E694: Invalid operation for Funcrefs"
+msgstr "E694: Nieprawid³owa operacja dla Funcref"
+
+msgid "E804: Cannot use '%' with Float"
+msgstr "E804: Nie mogê u¿yæ '%' w Zmiennoprzecinkowej"
+
+msgid "E110: Missing ')'"
+msgstr "E110: Brak ')'"
+
+msgid "E695: Cannot index a Funcref"
+msgstr "E695: Nie mo¿na zindeksowaæ Funcref"
+
+#, c-format
+msgid "E112: Option name missing: %s"
+msgstr "E112: Brak nazwy opcji: %s"
+
+#, c-format
+msgid "E113: Unknown option: %s"
+msgstr "E113: Nieznana opcja: %s"
+
+#, c-format
+msgid "E114: Missing quote: %s"
+msgstr "E114: Brak cudzys³owu: %s"
+
+#, c-format
+msgid "E115: Missing quote: %s"
+msgstr "E115: Brak cudzys³owu: %s"
+
+#, c-format
+msgid "E696: Missing comma in List: %s"
+msgstr "E696: Brakuj¹cy przecinek w Liœcie: '%s"
+
+#, c-format
+msgid "E697: Missing end of List ']': %s"
+msgstr "E697: Brak zakoñczenia Listy ']': %s"
+
+#, c-format
+msgid "E720: Missing colon in Dictionary: %s"
+msgstr "E720: Brak dwukropka w S³owniku: %s"
+
+#, c-format
+msgid "E721: Duplicate key in Dictionary: \"%s\""
+msgstr "E721: Powtórzony klucz w S³owniku: \"%s\""
+
+#, c-format
+msgid "E722: Missing comma in Dictionary: %s"
+msgstr "E722: Brakuj¹cy przecinek w S³owniku: %s"
+
+#, c-format
+msgid "E723: Missing end of Dictionary '}': %s"
+msgstr "E723: Brak koñca w S³owniku '}': %s"
+
+msgid "E724: variable nested too deep for displaying"
+msgstr "E724: Zmienna zagnie¿d¿ona zbyt g³êboko by pokazaæ"
+
+#, c-format
+msgid "E740: Too many arguments for function %s"
+msgstr "E740: Zbyt wiele argumentów dla funkcji %s"
+
+#, c-format
+msgid "E116: Invalid arguments for function %s"
+msgstr "E116: Zbyt wiele argumentów dla funkcji %s"
+
+#, c-format
+msgid "E117: Unknown function: %s"
+msgstr "E117: Nieznana funkcja: %s"
+
+#, c-format
+msgid "E119: Not enough arguments for function: %s"
+msgstr "E119: Za ma³o argumentów dla funkcji: %s"
+
+#, c-format
+msgid "E120: Using <SID> not in a script context: %s"
+msgstr "E120: U¿ycie <SID> poza kontekstem skryptu: %s"
+
+#, c-format
+msgid "E725: Calling dict function without Dictionary: %s"
+msgstr "E725: Wywo³anie funkcji \"dict\" bez S³ownika: %s"
+
+msgid "E808: Number or Float required"
+msgstr "E808: Wymagana Liczba lub Zmiennoprzecinkowa"
+
+msgid "add() argument"
+msgstr "argument add()"
+
+msgid "E699: Too many arguments"
+msgstr "E699: Za du¿o argumentów"
+
+msgid "E785: complete() can only be used in Insert mode"
+msgstr "E785: complete() mo¿e byæ u¿yte tylko w trybie Wprowadzania"
+
+#.
+#. * Yes this is ugly, I don't particularly like it either. But doing it
+#. * this way has the compelling advantage that translations need not to
+#. * be touched at all. See below what 'ok' and 'ync' are used for.
+#.
+msgid "&Ok"
+msgstr "&Ok"
+
+#, c-format
+msgid "E737: Key already exists: %s"
+msgstr "E737: Klucz ju¿ istnieje: %s"
+
+msgid "extend() argument"
+msgstr "argument extend()"
+
+msgid "map() argument"
+msgstr "argument map()"
+
+msgid "filter() argument"
+msgstr "argument filter()"
+
+#, c-format
+msgid "+-%s%3ld lines: "
+msgstr "+-%s%3ld wierszy: "
+
+#, c-format
+msgid "E700: Unknown function: %s"
+msgstr "E700: Nieznana funkcja: %s"
+
+msgid ""
+"&OK\n"
+"&Cancel"
+msgstr ""
+"&OK\n"
+"&Zakoñcz"
+
+msgid "called inputrestore() more often than inputsave()"
+msgstr "wywo³ano inputrestore() wiêcej razy ni¿ inputsave()"
+
+msgid "insert() argument"
+msgstr "argument insert()"
+
+msgid "E786: Range not allowed"
+msgstr "E786: Zakres niedozwolony"
+
+msgid "E701: Invalid type for len()"
+msgstr "E701: Nieprawid³owy typ dla len()"
+
+msgid "E726: Stride is zero"
+msgstr "E726: Skok to zero"
+
+msgid "E727: Start past end"
+msgstr "E727: Pocz¹tek po koñcu"
+
+msgid "<empty>"
+msgstr "<pusty>"
+
+msgid "E240: No connection to Vim server"
+msgstr "E240: Brak po³¹czenia z serwerem Vim"
+
+#, c-format
+msgid "E241: Unable to send to %s"
+msgstr "E241: Nie mogê wys³aæ do %s"
+
+msgid "E277: Unable to read a server reply"
+msgstr "E277: Nie mogê czytaæ odpowiedzi serwera"
+
+msgid "remove() argument"
+msgstr "argument remove()"
+
+msgid "E655: Too many symbolic links (cycle?)"
+msgstr "E655: Za du¿o dowi¹zañ symbolicznych (pêtla?)"
+
+msgid "reverse() argument"
+msgstr "argument reverse()"
+
+msgid "E258: Unable to send to client"
+msgstr "E258: Nie mogê wys³aæ do klienta"
+
+msgid "sort() argument"
+msgstr "argument sort()"
+
+msgid "E702: Sort compare function failed"
+msgstr "E702: Funkcja porównywania w sort nie powiod³a siê"
+
+msgid "(Invalid)"
+msgstr "(Niew³aœciwe)"
+
+msgid "E677: Error writing temp file"
+msgstr "E677: B³¹d zapisywania pliku tymczasowego"
+
+msgid "E805: Using a Float as a Number"
+msgstr "E805: U¿ycie Zmiennoprzecinkowej jako Liczby"
+
+msgid "E703: Using a Funcref as a Number"
+msgstr "E703: U¿ycie Funcref jako Liczby"
+
+msgid "E745: Using a List as a Number"
+msgstr "E745: U¿ycie Listy jako Liczby"
+
+msgid "E728: Using a Dictionary as a Number"
+msgstr "E728: U¿ycie S³ownika jako Liczby"
+
+msgid "E729: using Funcref as a String"
+msgstr "E729: U¿ycie Funcref jako £añcucha"
+
+msgid "E730: using List as a String"
+msgstr "E730: U¿ycie Listy jako £añcucha"
+
+msgid "E731: using Dictionary as a String"
+msgstr "E731: U¿ycie S³ownika jako £añcucha"
+
+#, c-format
+msgid "E706: Variable type mismatch for: %s"
+msgstr "E706: Nieprawid³owy typ zmiennej dla: %s"
+
+#, c-format
+msgid "E795: Cannot delete variable %s"
+msgstr "E795: Nie mogê usun¹æ zmiennej %s"
+
+#, c-format
+msgid "E704: Funcref variable name must start with a capital: %s"
+msgstr "E704: Nazwa Funcref musi siê zaczynaæ wielk¹ liter¹: %s"
+
+#, c-format
+msgid "E705: Variable name conflicts with existing function: %s"
+msgstr "E705: Nazwa zmiennej jest w konflikcie z istniej¹c¹ funkcj¹: %s"
+
+#, c-format
+msgid "E741: Value is locked: %s"
+msgstr "E741: WartoϾ jest zablokowana: %s"
+
+msgid "Unknown"
+msgstr "Nieznane"
+
+#, c-format
+msgid "E742: Cannot change value of %s"
+msgstr "E742: Nie mogê zmieniæ wartoœci %s"
+
+msgid "E698: variable nested too deep for making a copy"
+msgstr "E698: Zmienna zagnie¿d¿ona zbyt g³êboko by zrobiæ kopiê"
+
+#, c-format
+msgid "E123: Undefined function: %s"
+msgstr "E123: Nieznana funkcja: %s"
+
+#, c-format
+msgid "E124: Missing '(': %s"
+msgstr "E124: Brak '(': %s"
+
+msgid "E862: Cannot use g: here"
+msgstr "E862: Nie mo¿na tutaj u¿yæ g:"
+
+#, c-format
+msgid "E125: Illegal argument: %s"
+msgstr "E125: Niedozwolony argument: %s"
+
+#, c-format
+msgid "E853: Duplicate argument name: %s"
+msgstr "E853: Powtórzona nazwa argumentu: %s"
+
+msgid "E126: Missing :endfunction"
+msgstr "E126: Brak :endfunction"
+
+#, c-format
+msgid "E707: Function name conflicts with variable: %s"
+msgstr "E707: Nazwa funkcji jest w konflikcie ze zmienn¹: %s"
+
+#, c-format
+msgid "E127: Cannot redefine function %s: It is in use"
+msgstr "E127: Nie mogê redefiniowaæ funkcji %s: jest w u¿yciu"
+
+#, c-format
+msgid "E746: Function name does not match script file name: %s"
+msgstr "E746: Nazwa funkcji nie pasuje do nazwy skryptu: %s"
+
+msgid "E129: Function name required"
+msgstr "E129: Wymagana jest nazwa funkcji"
+
+#, c-format
+msgid "E128: Function name must start with a capital or contain a colon: %s"
+msgstr ""
+"E128: Nazwa funkcji musi rozpoczynaæ siê wielk¹ liter¹ lub zawieraæ "
+"dwukropek: %s"
+
+#, c-format
+msgid "E131: Cannot delete function %s: It is in use"
+msgstr "E131: Nie mogê skasowaæ funkcji %s: jest w u¿yciu"
+
+msgid "E132: Function call depth is higher than 'maxfuncdepth'"
+msgstr "E132: Zagnie¿d¿enie wywo³añ funkcji ponad 'maxfuncdepth'"
+
+#, c-format
+msgid "calling %s"
+msgstr "wywo³ujê %s"
+
+#, c-format
+msgid "%s aborted"
+msgstr "porzucono %s"
+
+#, c-format
+msgid "%s returning #%ld"
+msgstr "%s zwraca #%ld"
+
+#, c-format
+msgid "%s returning %s"
+msgstr "%s zwraca %s"
+
+#, c-format
+msgid "continuing in %s"
+msgstr "kontynuacja w %s"
+
+msgid "E133: :return not inside a function"
+msgstr "E133: :return poza funkcj¹"
+
+msgid ""
+"\n"
+"# global variables:\n"
+msgstr ""
+"\n"
+"# zmienne globalne:\n"
+
+msgid ""
+"\n"
+"\tLast set from "
+msgstr ""
+"\n"
+"\tOstatnie ustawienie przez "
+
+msgid "No old files"
+msgstr "Brak starych plików"
+
+msgid "Entering Debug mode. Type \"cont\" to continue."
+msgstr "Wchodzê w tryb odpluskwiania. WprowadŸ \"cont\" aby kontynuowaæ."
+
+#, c-format
+msgid "line %ld: %s"
+msgstr "wiersz %ld: %s"
+
+#, c-format
+msgid "cmd: %s"
+msgstr "cmd: %s"
+
+#, c-format
+msgid "Breakpoint in \"%s%s\" line %ld"
+msgstr "Punkt kontrolny w \"%s%s\" wiersz %ld"
+
+#, c-format
+msgid "E161: Breakpoint not found: %s"
+msgstr "E161: Nie znaleziono punktu kontrolnego: %s"
+
+msgid "No breakpoints defined"
+msgstr "Nie okreœlono ¿adnych punktów kontrolnych"
+
+#, c-format
+msgid "%3d %s %s line %ld"
+msgstr "%3d %s %s wiersz %ld"
+
+msgid "E750: First use \":profile start {fname}\""
+msgstr "E750: Pierwsze u¿ycie \":profile start {fname}\""
+
+msgid "Save As"
+msgstr "Zapisz jako"
+
+#, c-format
+msgid "Save changes to \"%s\"?"
+msgstr "Zachowaæ zmiany w \"%s\"?"
+
+msgid "Untitled"
+msgstr "Bez Tytu³u"
+
+#, c-format
+msgid "E162: No write since last change for buffer \"%s\""
+msgstr "E162: Nie zapisano zmian w buforze \"%s\""
+
+msgid "Warning: Entered other buffer unexpectedly (check autocommands)"
+msgstr "OSTRZE¯ENIE: Nieoczekiwane wejœcie w inny bufor (sprawdŸ autokomendy)"
+
+msgid "E163: There is only one file to edit"
+msgstr "E163: Tylko jeden plik w edycji"
+
+msgid "E164: Cannot go before first file"
+msgstr "E164: Nie mo¿na przejœæ przed pierwszy plik"
+
+msgid "E165: Cannot go beyond last file"
+msgstr "E165: Nie mo¿na przejœæ za ostatni plik"
+
+#, c-format
+msgid "E666: compiler not supported: %s"
+msgstr "E666: nie wspierany kompilator: %s"
+
+#, c-format
+msgid "Searching for \"%s\" in \"%s\""
+msgstr "Szukanie \"%s\" w \"%s\""
+
+#, c-format
+msgid "Searching for \"%s\""
+msgstr "Szukanie \"%s\""
+
+#, c-format
+msgid "not found in 'runtimepath': \"%s\""
+msgstr "nie znaleziono w 'runtimepath': \"%s\""
+
+msgid "Source Vim script"
+msgstr "Wczytaj skrypt Vima"
+
+#, c-format
+msgid "Cannot source a directory: \"%s\""
+msgstr "Nie mo¿na wczytaæ katalogu: \"%s\""
+
+#, c-format
+msgid "could not source \"%s\""
+msgstr "nie mog³em wczytaæ \"%s\""
+
+#, c-format
+msgid "line %ld: could not source \"%s\""
+msgstr "wiersz: %ld nie mog³em wczytaæ \"%s\""
+
+#, c-format
+msgid "sourcing \"%s\""
+msgstr "wczytywanie \"%s\""
+
+#, c-format
+msgid "line %ld: sourcing \"%s\""
+msgstr "wiersz %ld: wczytywanie \"%s\""
+
+#, c-format
+msgid "finished sourcing %s"
+msgstr "skoñczono wczytywanie %s"
+
+msgid "modeline"
+msgstr "modeline"
+
+msgid "--cmd argument"
+msgstr "--cmd argument"
+
+msgid "-c argument"
+msgstr "-c argument"
+
+msgid "environment variable"
+msgstr "zmienna œrodowiskowa"
+
+msgid "error handler"
+msgstr "obs³uga b³êdu"
+
+msgid "W15: Warning: Wrong line separator, ^M may be missing"
+msgstr "W15: OSTRZE¯ENIE: Niew³aœciwy separator wierszy, pewnie brak ^M"
+
+msgid "E167: :scriptencoding used outside of a sourced file"
+msgstr "E167: u¿yto :scriptencoding poza wczytywanym plikiem"
+
+msgid "E168: :finish used outside of a sourced file"
+msgstr "E168: u¿yto :finish poza wczytywanym plikiem"
+
+#, c-format
+msgid "Current %slanguage: \"%s\""
+msgstr "Bie¿¹cy %sjêzyk: \"%s\""
+
+#, c-format
+msgid "E197: Cannot set language to \"%s\""
+msgstr "E197: Nie mogê ustawiæ jêzyka na \"%s\""
+
+#, c-format
+msgid "<%s>%s%s %d, Hex %02x, Octal %03o"
+msgstr "<%s>%s%s %d, Hex %02x, Oktal %03o"
+
+#, c-format
+msgid "> %d, Hex %04x, Octal %o"
+msgstr "> %d, Hex %04x, Oktal %o"
+
+#, c-format
+msgid "> %d, Hex %08x, Octal %o"
+msgstr "> %d, Hex %08x, Oktal %o"
+
+msgid "E134: Move lines into themselves"
+msgstr "E134: Przeniesienie wierszy na siebie samych"
+
+msgid "1 line moved"
+msgstr "1 wiersz przeniesiony"
+
+#, c-format
+msgid "%ld lines moved"
+msgstr "%ld wiersze przeniesione"
+
+#, c-format
+msgid "%ld lines filtered"
+msgstr "%ld wierszy przefiltrowanych"
+
+msgid "E135: *Filter* Autocommands must not change current buffer"
+msgstr "E135: Autokomendy *Filter* nie mog¹ zmieniaæ bie¿¹cego bufora"
+
+msgid "[No write since last change]\n"
+msgstr "[Brak zapisu od czasu ostatniej zmiany]\n"
+
+#, c-format
+msgid "%sviminfo: %s in line: "
+msgstr "%sviminfo: %s w wierszu: "
+
+msgid "E136: viminfo: Too many errors, skipping rest of file"
+msgstr "E136: viminfo: Zbyt wiele b³êdów; pomijam resztê pliku"
+
+#, c-format
+msgid "Reading viminfo file \"%s\"%s%s%s"
+msgstr "Wczytujê plik viminfo \"%s\"%s%s%s"
+
+msgid " info"
+msgstr " informacja"
+
+msgid " marks"
+msgstr " zak³adki"
+
+msgid " oldfiles"
+msgstr " stare pliki"
+
+msgid " FAILED"
+msgstr " NIE POWIOD£O SIÊ"
+
+#. avoid a wait_return for this message, it's annoying
+#, c-format
+msgid "E137: Viminfo file is not writable: %s"
+msgstr "E137: Plik viminfo jest niezapisywalny: %s"
+
+#, c-format
+msgid "E138: Can't write viminfo file %s!"
+msgstr "E138: Nie mogê zapisaæ pliku viminfo %s!"
+
+#, c-format
+msgid "Writing viminfo file \"%s\""
+msgstr "Zapisujê plik viminfo \"%s\""
+
+#. Write the info:
+#, c-format
+msgid "# This viminfo file was generated by Vim %s.\n"
+msgstr "# Ten plik viminfo zosta³ wygenerowany przez Vima %s.\n"
+
+msgid ""
+"# You may edit it if you're careful!\n"
+"\n"
+msgstr ""
+"# Mo¿esz go ostro¿nie edytowaæ!\n"
+"\n"
+
+msgid "# Value of 'encoding' when this file was written\n"
+msgstr "# WartoϾ 'encoding' w czasie zapisu tego pliku\n"
+
+msgid "Illegal starting char"
+msgstr "Niedopuszczalny pocz¹tkowy znak"
+
+msgid "Write partial file?"
+msgstr "Zapisaæ czêœciowo plik?"
+
+msgid "E140: Use ! to write partial buffer"
+msgstr "E140: Stosuj ! do zapisania czêœciowo bufora"
+
+#, c-format
+msgid "Overwrite existing file \"%s\"?"
+msgstr "Nadpisaæ istniej¹cy plik \"%s\"?"
+
+#, c-format
+msgid "Swap file \"%s\" exists, overwrite anyway?"
+msgstr "Plik wymiany \"%s\" istnieje, czy go nadpisaæ?"
+
+#, c-format
+msgid "E768: Swap file exists: %s (:silent! overrides)"
+msgstr "E768: Plik wymiany istnieje: %s (wymuœ poprzez :silent!)"
+
+#, c-format
+msgid "E141: No file name for buffer %ld"
+msgstr "E141: Brak nazwy pliku dla bufora %ld"
+
+msgid "E142: File not written: Writing is disabled by 'write' option"
+msgstr "E142: Plik niezapisany: Zapis jest wy³¹czony opcj¹ 'write'"
+
+#, c-format
+msgid ""
+"'readonly' option is set for \"%s\".\n"
+"Do you wish to write anyway?"
+msgstr ""
+"opcja 'readonly' nastawiona dla \"%s\".\n"
+"Czy chcesz go pomimo tego zapisaæ?"
+
+#, c-format
+msgid ""
+"File permissions of \"%s\" are read-only.\n"
+"It may still be possible to write it.\n"
+"Do you wish to try?"
+msgstr ""
+"Prawa pliku \"%s\" s¹ tylko do odczytu.\n"
+"Mimo to byæ mo¿e uda siê zmieniæ ten plik.\n"
+"Chcesz spróbowaæ?"
+
+#, c-format
+msgid "E505: \"%s\" is read-only (add ! to override)"
+msgstr "E505: \"%s\" jest tylko do odczytu (dodaj ! aby wymusiæ)"
+
+msgid "Edit File"
+msgstr "Edytuj Plik"
+
+#, c-format
+msgid "E143: Autocommands unexpectedly deleted new buffer %s"
+msgstr "E143: Autokomendy nieoczekiwanie skasowa³y nowy bufor %s"
+
+msgid "E144: non-numeric argument to :z"
+msgstr "E144: nienumeryczny argument dla :z"
+
+msgid "E145: Shell commands not allowed in rvim"
+msgstr "E145: Komendy pow³oki s¹ niedozwolone w rvim"
+
+msgid "E146: Regular expressions can't be delimited by letters"
+msgstr "E146: Wzorce regularne nie mog¹ byæ rozgraniczane literami"
+
+#, c-format
+msgid "replace with %s (y/n/a/q/l/^E/^Y)?"
+msgstr "zamieñ na %s (y/n/a/q/l/^E/^Y)?"
+
+msgid "(Interrupted) "
+msgstr "(Przerwane) "
+
+msgid "1 match"
+msgstr "1 pasuje"
+
+msgid "1 substitution"
+msgstr "1 podstawienie "
+
+#, c-format
+msgid "%ld matches"
+msgstr "%ld dopasowañ"
+
+#, c-format
+msgid "%ld substitutions"
+msgstr "%ld podstawieñ"
+
+msgid " on 1 line"
+msgstr " w 1 wierszu"
+
+#, c-format
+msgid " on %ld lines"
+msgstr " w %ld wierszach"
+
+msgid "E147: Cannot do :global recursive"
+msgstr "E147: Nie mogê wykonaæ :global rekursywnie"
+
+msgid "E148: Regular expression missing from global"
+msgstr "E148: Brak wzorca regularnego w :global"
+
+# c-format
+#, c-format
+msgid "Pattern found in every line: %s"
+msgstr "Wzorzec znaleziono w ka¿dym wierszu: %s"
+
+#, c-format
+msgid "Pattern not found: %s"
+msgstr "Nie znaleziono wzorca: %s"
+
+msgid ""
+"\n"
+"# Last Substitute String:\n"
+"$"
+msgstr ""
+"\n"
+"# Ostatni podstawiany ci¹g:\n"
+"$"
+
+msgid "E478: Don't panic!"
+msgstr "E478: Nie panikuj!"
+
+#, c-format
+msgid "E661: Sorry, no '%s' help for %s"
+msgstr "E661: Przykro mi, brak '%s' pomocy dla %s"
+
+#, c-format
+msgid "E149: Sorry, no help for %s"
+msgstr "E149: Przykro mi, ale brak pomocy o %s"
+
+#, c-format
+msgid "Sorry, help file \"%s\" not found"
+msgstr "Przykro mi, nie ma pliku pomocy \"%s\""
+
+#, c-format
+msgid "E150: Not a directory: %s"
+msgstr "E150: Nie jest katalogiem: %s"
+
+#, c-format
+msgid "E152: Cannot open %s for writing"
+msgstr "E152: Nie mogê otworzyæ %s do zapisu"
+
+#, c-format
+msgid "E153: Unable to open %s for reading"
+msgstr "E153: Nie mogê otworzyæ %s do odczytu"
+
+#, c-format
+msgid "E670: Mix of help file encodings within a language: %s"
+msgstr "E670: Mieszanka kodowañ w pliku pomocy w ramach jêzyka: %s"
+
+#, c-format
+msgid "E154: Duplicate tag \"%s\" in file %s/%s"
+msgstr "E154: Powtórzony znacznik \"%s\" w pliku %s/%s"
+
+#, c-format
+msgid "E160: Unknown sign command: %s"
+msgstr "E160: Nieznana komenda znaku: %s"
+
+msgid "E156: Missing sign name"
+msgstr "E156: Brak nazwy znaku"
+
+msgid "E612: Too many signs defined"
+msgstr "E612: Zbyt wiele nazw znaków"
+
+#, c-format
+msgid "E239: Invalid sign text: %s"
+msgstr "E239: Niew³aœciwy tekst znaku: %s"
+
+#, c-format
+msgid "E155: Unknown sign: %s"
+msgstr "E155: Nieznany znak: %s"
+
+msgid "E159: Missing sign number"
+msgstr "E159: Brak numeru znaku"
+
+#, c-format
+msgid "E158: Invalid buffer name: %s"
+msgstr "E158: Niew³aœciwa nazwa bufora: %s"
+
+#, c-format
+msgid "E157: Invalid sign ID: %ld"
+msgstr "E157: Niew³aœciwe ID znaku: %ld"
+
+msgid " (NOT FOUND)"
+msgstr " (NIE ZNALEZIONO)"
+
+msgid " (not supported)"
+msgstr "(nie wspomagane)"
+
+msgid "[Deleted]"
+msgstr "[Skasowano]"
+
+msgid "Entering Ex mode. Type \"visual\" to go to Normal mode."
+msgstr "Wchodzê w tryb Ex. WprowadŸ \"visual\" aby przejœæ do trybu Normal."
+
+msgid "E501: At end-of-file"
+msgstr "E501: Na koñcu pliku"
+
+msgid "E169: Command too recursive"
+msgstr "E169: Komenda zbyt rekursywna"
+
+#, c-format
+msgid "E605: Exception not caught: %s"
+msgstr "E605: Nie znaleziono wyj¹tku: %s"
+
+msgid "End of sourced file"
+msgstr "Koniec wczytywanego pliku"
+
+msgid "End of function"
+msgstr "Koniec funkcji"
+
+msgid "E464: Ambiguous use of user-defined command"
+msgstr ""
+"E464: Niejednoznaczne zastosowanie komendy zdefiniowanej przez u¿ytkownika"
+
+msgid "E492: Not an editor command"
+msgstr "E492: Nie jest komend¹ edytora"
+
+msgid "E493: Backwards range given"
+msgstr "E493: Dano wsteczny zakres"
+
+msgid "Backwards range given, OK to swap"
+msgstr "Dano wsteczny zakres; zamiana jest mo¿liwa"
+
+msgid "E494: Use w or w>>"
+msgstr "E494: Stosuj w lub w>>"
+
+msgid "E319: Sorry, the command is not available in this version"
+msgstr "E319: Przykro mi, ale ta komenda nie jest dostêpna w tej wersji"
+
+msgid "E172: Only one file name allowed"
+msgstr "E172: Tylko pojedyncza nazwa pliku dozwolona"
+
+msgid "1 more file to edit. Quit anyway?"
+msgstr "1 wiêcej plik do edycji. Mimo to wyjœæ?"
+
+#, c-format
+msgid "%d more files to edit. Quit anyway?"
+msgstr "jeszcze %d plików do edycji. Mimo to wyjœæ?"
+
+msgid "E173: 1 more file to edit"
+msgstr "E173: 1 wiêcej plik do edycji"
+
+#, c-format
+msgid "E173: %ld more files to edit"
+msgstr "E173: jeszcze %ld plików do edycji"
+
+msgid "E174: Command already exists: add ! to replace it"
+msgstr "E174: Komenda ju¿ istnieje; aby j¹ przedefiniowaæ stosuj !"
+
+msgid ""
+"\n"
+" Name Args Range Complete Definition"
+msgstr ""
+"\n"
+" Nazwa Arg. Zak. GotowoϾ Definicja"
+
+msgid "No user-defined commands found"
+msgstr "Nie znaleziono komend zdefiniowanych przez u¿ytkownika"
+
+msgid "E175: No attribute specified"
+msgstr "E175: Nie okreœlono atrybutu"
+
+msgid "E176: Invalid number of arguments"
+msgstr "E176: Niew³aœciwa iloœæ argumentów"
+
+msgid "E177: Count cannot be specified twice"
+msgstr "E177: Mno¿nik nie mo¿e byæ podany dwukrotnie"
+
+msgid "E178: Invalid default value for count"
+msgstr "E178: Niew³aœciwa domyœlna wartoœæ mno¿nika"
+
+msgid "E179: argument required for -complete"
+msgstr "E179: -complete wymaga argumentu"
+
+#, c-format
+msgid "E181: Invalid attribute: %s"
+msgstr "E181: Niew³aœciwy atrybut: %s"
+
+msgid "E182: Invalid command name"
+msgstr "E182: Niew³aœciwa nazwa komendy"
+
+msgid "E183: User defined commands must start with an uppercase letter"
+msgstr ""
+"E183: Komendy zdefiniowane przez u¿ytkownika musz¹ rozpoczynaæ siê du¿¹ "
+"liter¹"
+
+msgid "E841: Reserved name, cannot be used for user defined command"
+msgstr ""
+"E841: Nazwa zastrze¿ona, nie mo¿na jej u¿yæ w komendzie u¿ytkownika"
+
+#, c-format
+msgid "E184: No such user-defined command: %s"
+msgstr "E184: Nie ma takiej komendy u¿ytkownika: %s"
+
+#, c-format
+msgid "E180: Invalid complete value: %s"
+msgstr "E180: Niew³aœciwa wartoœæ dope³niania: %s"
+
+msgid "E468: Completion argument only allowed for custom completion"
+msgstr ""
+"E468: Argument depe³niania dozwolony wy³¹cznie dla dope³niania u¿ytkownika"
+
+msgid "E467: Custom completion requires a function argument"
+msgstr "E467: Dope³nianie u¿ytkownika wymaga funkcji jako argumentu"
+
+msgid "unknown"
+msgstr "nieznany"
+
+#, c-format
+msgid "E185: Cannot find color scheme '%s'"
+msgstr "E185: Nie mogê znaleŸæ zestawu kolorów '%s'"
+
+msgid "Greetings, Vim user!"
+msgstr "Witaj u¿ytkowniku Vima!"
+
+msgid "E784: Cannot close last tab page"
+msgstr "E784: Nie mogê zamkn¹æ ostatniej karty"
+
+msgid "Already only one tab page"
+msgstr "Jest ju¿ tylko jedna karta"
+
+msgid "Edit File in new window"
+msgstr "Edytuj plik w nowym oknie"
+
+#, c-format
+msgid "Tab page %d"
+msgstr "Karta %d"
+
+msgid "No swap file"
+msgstr "Brak pliku wymiany"
+
+msgid "Append File"
+msgstr "Do³¹cz plik"
+
+msgid "E747: Cannot change directory, buffer is modified (add ! to override)"
+msgstr ""
+"E747: Nie mogê zmieniæ katalogu, bufor zosta³ zmodyfikowany (dodaj ! aby "
+"wymusiæ)"
+
+msgid "E186: No previous directory"
+msgstr "E186: Nie ma poprzedniego katalogu"
+
+msgid "E187: Unknown"
+msgstr "E187: Nieznany"
+
+msgid "E465: :winsize requires two number arguments"
+msgstr "E465: :winsize wymaga dwóch argumentów numerycznych"
+
+#, c-format
+msgid "Window position: X %d, Y %d"
+msgstr "Pozycja okna: X %d, Y %d"
+
+msgid "E188: Obtaining window position not implemented for this platform"
+msgstr ""
+"E188: Pozyskiwanie pozycji okna nie jest zaimplementowane dla tego systemu"
+
+msgid "E466: :winpos requires two number arguments"
+msgstr "E466: :winpos wymaga dwóch argumentów numerycznych"
+
+msgid "Save Redirection"
+msgstr "Zapisz przekierowanie"
+
+msgid "Save View"
+msgstr "Zapisz widok"
+
+msgid "Save Session"
+msgstr "Zapisz sesjê"
+
+msgid "Save Setup"
+msgstr "Zapisz ustawienia"
+
+#, c-format
+msgid "E739: Cannot create directory: %s"
+msgstr "E739: Nie mogê utworzyæ katalogu: %s"
+
+#, c-format
+msgid "E189: \"%s\" exists (add ! to override)"
+msgstr "E189: \"%s\" istnieje (wymuœ poprzez !)"
+
+#, c-format
+msgid "E190: Cannot open \"%s\" for writing"
+msgstr "E190: Nie mogê otworzyæ \"%s\" do zapisu"
+
+#. set mark
+msgid "E191: Argument must be a letter or forward/backward quote"
+msgstr "E191: Argument musi byæ liter¹ albo cudzys³owem w przód/ty³"
+
+msgid "E192: Recursive use of :normal too deep"
+msgstr "E192: Rekursywne zastosowanie :normal za g³êbokie"
+
+msgid "E809: #< is not available without the +eval feature"
+msgstr "E809: #< nie jest dostêpne bez w³aœciwoœci +eval"
+
+msgid "E194: No alternate file name to substitute for '#'"
+msgstr "E194: Brak nazwy zamiennego pliku do podstawienia pod '#'"
+
+msgid "E495: no autocommand file name to substitute for \"<afile>\""
+msgstr "E495: brak nazwy pliku autokomend do podstawienia pod \"<afile>\""
+
+msgid "E496: no autocommand buffer number to substitute for \"<abuf>\""
+msgstr "E496: brak numeru bufora autokomend do podstawienia pod \"<abuf>\""
+
+msgid "E497: no autocommand match name to substitute for \"<amatch>\""
+msgstr "E497: brak nazwy dopasowania autokomend pod \"<amatch>\""
+
+msgid "E498: no :source file name to substitute for \"<sfile>\""
+msgstr "E498: brak nazwy pliku :source do postawienia pod \"<sfile>\""
+
+msgid "E842: no line number to use for \"<slnum>\""
+msgstr "E842: brak numeru linii by u¿yæ z \"<slnum>\""
+
+#, no-c-format
+msgid "E499: Empty file name for '%' or '#', only works with \":p:h\""
+msgstr "E499: Pusta nazwa pliku dla '%' lub '#', dzia³a tylko z \":p:h\""
+
+msgid "E500: Evaluates to an empty string"
+msgstr "E500: Wynikiem jest pusty ci¹g"
+
+msgid "E195: Cannot open viminfo file for reading"
+msgstr "E195: Nie mogê otworzyæ pliku viminfo do odczytu"
+
+msgid "E196: No digraphs in this version"
+msgstr "E196: Brak dwugrafów w tej wersji"
+
+msgid "E608: Cannot :throw exceptions with 'Vim' prefix"
+msgstr "E608: Nie mo¿na ':throw' wyj¹tków z prefiksem 'Vim'"
+
+#. always scroll up, don't overwrite
+#, c-format
+msgid "Exception thrown: %s"
+msgstr "Wyj¹tek: %s"
+
+#, c-format
+msgid "Exception finished: %s"
+msgstr "Wyj¹tek zakoñczony: %s"
+
+#, c-format
+msgid "Exception discarded: %s"
+msgstr "Wyj¹tek odrzucony: %s"
+
+#, c-format
+msgid "%s, line %ld"
+msgstr "%s, wiersz %ld"
+
+#. always scroll up, don't overwrite
+#, c-format
+msgid "Exception caught: %s"
+msgstr "Wyj¹tek przechwycony: %s"
+
+#, c-format
+msgid "%s made pending"
+msgstr "%s zosta³ zawieszony"
+
+#, c-format
+msgid "%s resumed"
+msgstr "%s przywrócony"
+
+#, c-format
+msgid "%s discarded"
+msgstr "%s odrzucony"
+
+msgid "Exception"
+msgstr "Wyj¹tek"
+
+msgid "Error and interrupt"
+msgstr "B³¹d i przerwanie"
+
+msgid "Error"
+msgstr "B³¹d"
+
+#. if (pending & CSTP_INTERRUPT)
+msgid "Interrupt"
+msgstr "Przerwanie"
+
+msgid "E579: :if nesting too deep"
+msgstr "E579: zbyt g³êbokie zagnie¿d¿enie :if"
+
+msgid "E580: :endif without :if"
+msgstr "E580: :endif bez :if"
+
+msgid "E581: :else without :if"
+msgstr "E581: :else bez :if"
+
+msgid "E582: :elseif without :if"
+msgstr "E582: :elseif bez :if"
+
+msgid "E583: multiple :else"
+msgstr "E583: wielokrotne :else"
+
+msgid "E584: :elseif after :else"
+msgstr "E584: :elseif po :else"
+
+msgid "E585: :while/:for nesting too deep"
+msgstr "E585: zbyt g³êbokie zagnie¿d¿enie :while/:for"
+
+msgid "E586: :continue without :while or :for"
+msgstr "E586: :continue bez :while lub :for"
+
+msgid "E587: :break without :while or :for"
+msgstr "E587: :break bez :while lub :for"
+
+msgid "E732: Using :endfor with :while"
+msgstr "E732: U¿ycie :endfor z :while"
+
+msgid "E733: Using :endwhile with :for"
+msgstr "E733: U¿ycie :endwhile z :for"
+
+msgid "E601: :try nesting too deep"
+msgstr "E601: zbyt g³êbokie zagnie¿d¿enie :try"
+
+msgid "E603: :catch without :try"
+msgstr "E603: :catch bez :try"
+
+#. Give up for a ":catch" after ":finally" and ignore it.
+#. * Just parse.
+msgid "E604: :catch after :finally"
+msgstr "E604: :catch za :finally"
+
+msgid "E606: :finally without :try"
+msgstr "E606: :finally bez :try"
+
+#. Give up for a multiple ":finally" and ignore it.
+msgid "E607: multiple :finally"
+msgstr "E607: wielokrotne :finally"
+
+msgid "E602: :endtry without :try"
+msgstr "E602: :endtry bez :try"
+
+msgid "E193: :endfunction not inside a function"
+msgstr "E193: :endfunction poza funkcj¹"
+
+msgid "E788: Not allowed to edit another buffer now"
+msgstr "E788: Nie mo¿na teraz edytowaæ innego bufora"
+
+msgid "E811: Not allowed to change buffer information now"
+msgstr "E811: Nie mo¿na teraz zmieniaæ informacji o buforze"
+
+msgid "tagname"
+msgstr "nazwa znacznika"
+
+msgid " kind file\n"
+msgstr " pokrewny plik\n"
+
+msgid "'history' option is zero"
+msgstr "opcja 'history' jest zerowa"
+
+#, c-format
+msgid ""
+"\n"
+"# %s History (newest to oldest):\n"
+msgstr ""
+"\n"
+"# %s Historia (od najnowszych po najstarsze):\n"
+
+msgid "Command Line"
+msgstr "Wiersz poleceñ"
+
+msgid "Search String"
+msgstr "Szukany ci¹g"
+
+msgid "Expression"
+msgstr "Wyra¿enie"
+
+msgid "Input Line"
+msgstr "Wiersz wprowadzeñ"
+
+msgid "E198: cmd_pchar beyond the command length"
+msgstr "E198: cmd_pchar przekracza d³ugoœæ polecenia"
+
+msgid "E199: Active window or buffer deleted"
+msgstr "E199: Aktywny widok lub bufor skasowany"
+
+msgid "E812: Autocommands changed buffer or buffer name"
+msgstr "E812: Autokomendy zmieni³y bufor lub jego nazwê"
+
+msgid "Illegal file name"
+msgstr "Niedopuszczalna nazwa pliku"
+
+msgid "is a directory"
+msgstr "jest katalogiem"
+
+msgid "is not a file"
+msgstr "nie jest plikiem"
+
+msgid "is a device (disabled with 'opendevice' option)"
+msgstr "jest urz¹dzeniem (wy³¹czonym w opcji 'opendevice')"
+
+msgid "[New File]"
+msgstr "[Nowy Plik]"
+
+msgid "[New DIRECTORY]"
+msgstr "[Nowy KATALOG]"
+
+msgid "[File too big]"
+msgstr "[Za du¿y plik]"
+
+msgid "[Permission Denied]"
+msgstr "[Nie dozwolono]"
+
+msgid "E200: *ReadPre autocommands made the file unreadable"
+msgstr "E200: Autokomendy *ReadPre zrobi³y plik nieodczytywalnym"
+
+msgid "E201: *ReadPre autocommands must not change current buffer"
+msgstr "E201: Autokomendy *ReadPre nie mog¹ zmieniaæ bie¿¹cego bufora"
+
+msgid "Vim: Reading from stdin...\n"
+msgstr "Vim: Wczytywanie ze stdin...\n"
+
+msgid "Reading from stdin..."
+msgstr "Wczytywanie ze stdin..."
+
+#. Re-opening the original file failed!
+msgid "E202: Conversion made file unreadable!"
+msgstr "E202: Nie mo¿na otworzyæ pliku utworzonego przez przemianê!"
+
+msgid "[fifo/socket]"
+msgstr "[fifo/socket]"
+
+msgid "[fifo]"
+msgstr "[fifo]"
+
+msgid "[socket]"
+msgstr "[socket]"
+
+msgid "[character special]"
+msgstr "[specjalny znak]"
+
+msgid "[CR missing]"
+msgstr "[brak CR]'"
+
+msgid "[long lines split]"
+msgstr "[d³ugie wiersze rozdzielane]"
+
+msgid "[NOT converted]"
+msgstr "[NIE przemienione]"
+
+msgid "[converted]"
+msgstr "[przemienione]"
+
+msgid "[blowfish]"
+msgstr "[blowfish]"
+
+msgid "[crypted]"
+msgstr "[zakodowane]"
+
+#, c-format
+msgid "[CONVERSION ERROR in line %ld]"
+msgstr "[B£¥D W PRZEMIANIE w linii %ld]"
+
+#, c-format
+msgid "[ILLEGAL BYTE in line %ld]"
+msgstr "[NIEDOZWOLONY BAJT w wierszu %ld]"
+
+msgid "[READ ERRORS]"
+msgstr "[B£ÊDY W ODCZYCIE]"
+
+msgid "Can't find temp file for conversion"
+msgstr "Nie mogê znaleŸæ pliku tymczasowego w celu przemiany"
+
+msgid "Conversion with 'charconvert' failed"
+msgstr "Nieudana przemiana z 'charconvert'"
+
+msgid "can't read output of 'charconvert'"
+msgstr "nie mogê odczytaæ wyjœcia z 'charconvert'"
+
+msgid "E821: File is encrypted with unknown method"
+msgstr "E821: Plik zaszyfrowano w nieznany sposób"
+
+msgid "E676: No matching autocommands for acwrite buffer"
+msgstr "E676: Brak pasuj¹cych autokomend dla bufora acwrite"
+
+msgid "E203: Autocommands deleted or unloaded buffer to be written"
+msgstr ""
+"E203: Autokomendy skasowa³y lub wy³adowa³y bufor przeznaczony do zapisu"
+
+msgid "E204: Autocommand changed number of lines in unexpected way"
+msgstr "E204: Autokomenda zmieni³a liczbê wierszy w nieoczekiwany sposób"
+
+msgid "NetBeans disallows writes of unmodified buffers"
+msgstr "NetBeans nie pozwala na zapis niezmodyfikowanych buforów"
+
+msgid "Partial writes disallowed for NetBeans buffers"
+msgstr "Czêœciowy zapis niemo¿liwy dla buforów NetBeans"
+
+msgid "is not a file or writable device"
+msgstr "nie jest plikiem lub zapisywalnym przyrz¹dem"
+
+msgid "writing to device disabled with 'opendevice' option"
+msgstr "zapisywanie do urz¹dzenia wy³¹czone w opcji 'opendevice'"
+
+msgid "is read-only (add ! to override)"
+msgstr "jest tylko do odczytu (wymuœ poprzez !)"
+
+msgid "E506: Can't write to backup file (add ! to override)"
+msgstr "E506: Nie mogê zapisaæ do pliku zabezpieczenia (wymuœ przez !)"
+
+msgid "E507: Close error for backup file (add ! to override)"
+msgstr "E507: B³¹d podczas zamykania pliku zabezpieczenia (wymuœ przez !)"
+
+msgid "E508: Can't read file for backup (add ! to override)"
+msgstr "E508: Nie mogê odczytaæ pliku w celu zabezpieczenia (wymuœ przez !)"
+
+msgid "E509: Cannot create backup file (add ! to override)"
+msgstr "E509: Nie mogê stworzyæ pliku zabezpieczenia (wymuœ przez !)"
+
+msgid "E510: Can't make backup file (add ! to override)"
+msgstr "E510: Nie mogê zrobiæ pliku zabezpieczenia (wymuœ przez !)"
+
+msgid "E460: The resource fork would be lost (add ! to override)"
+msgstr "E460: Rozdzia³ zasobów zostanie utracony (wymuœ przez !)"
+
+msgid "E214: Can't find temp file for writing"
+msgstr "E214: Nie mogê znaleŸæ pliku tymczasowego do zapisania"
+
+msgid "E213: Cannot convert (add ! to write without conversion)"
+msgstr "E213: Nie mogê przemieniæ (u¿yj ! by zapisaæ bez przemiany)"
+
+msgid "E166: Can't open linked file for writing"
+msgstr "E166: Nie mogê otworzyæ pod³¹czonego pliku do zapisu"
+
+msgid "E212: Can't open file for writing"
+msgstr "E212: Nie mogê otworzyæ pliku do zapisu"
+
+msgid "E667: Fsync failed"
+msgstr "E667: Fsync nie powiód³ siê"
+
+msgid "E512: Close failed"
+msgstr "E512: Zamkniêcie siê nie powiod³o"
+
+msgid "E513: write error, conversion failed (make 'fenc' empty to override)"
+msgstr ""
+"E513: B³¹d zapisu, przemiana siê nie powiod³a (opró¿nij 'fenc' aby wymusiæ)"
+
+#, c-format
+msgid ""
+"E513: write error, conversion failed in line %ld (make 'fenc' empty to "
+"override)"
+msgstr ""
+"E513: B³¹d zapisu, przemiana siê nie powiod³a w wierszu %ld (opró¿nij 'fenc' "
+"by wymusiæ)"
+
+msgid "E514: write error (file system full?)"
+msgstr "E514: b³¹d w zapisie (mo¿e system plików jest przepe³niony?)"
+
+msgid " CONVERSION ERROR"
+msgstr " B£¥D W PRZEMIANIE"
+
+#, c-format
+msgid " in line %ld;"
+msgstr " w wierszu %ld;"
+
+msgid "[Device]"
+msgstr "[Urz¹dzenie]"
+
+msgid "[New]"
+msgstr "[Nowy]"
+
+msgid " [a]"
+msgstr " [a]"
+
+msgid " appended"
+msgstr " do³¹czono"
+
+msgid " [w]"
+msgstr " [w]"
+
+msgid " written"
+msgstr " zapisano"
+
+msgid "E205: Patchmode: can't save original file"
+msgstr "E205: Patchmode: nie mogê zapisaæ oryginalnego pliku"
+
+msgid "E206: patchmode: can't touch empty original file"
+msgstr "E206: patchmode: nie mogê stworzyæ pustego oryginalnego pliku"
+
+msgid "E207: Can't delete backup file"
+msgstr "E207: Nie mogê skasowaæ pliku zabezpieczenia"
+
+msgid ""
+"\n"
+"WARNING: Original file may be lost or damaged\n"
+msgstr ""
+"\n"
+"OSTRZE¯ENIE: Oryginalny plik mo¿e zostaæ utracony lub uszkodzony\n"
+
+msgid "don't quit the editor until the file is successfully written!"
+msgstr "nie wychodŸ edytora, dopóki plik nie zosta³ poprawnie zapisany!"
+
+msgid "[dos]"
+msgstr "[dos]"
+
+msgid "[dos format]"
+msgstr "[format dos-a]"
+
+msgid "[mac]"
+msgstr "[mac]"
+
+msgid "[mac format]"
+msgstr "[format maca]"
+
+msgid "[unix]"
+msgstr "[unix]"
+
+msgid "[unix format]"
+msgstr "[format unixa]"
+
+msgid "1 line, "
+msgstr "1 wiersz, "
+
+#, c-format
+msgid "%ld lines, "
+msgstr "%ld wierszy, "
+
+msgid "1 character"
+msgstr "1 znak"
+
+#, c-format
+msgid "%lld characters"
+msgstr "%lld znaków"
+
+#. Explicit typecast avoids warning on Mac OS X 10.6
+#, c-format
+msgid "%ld characters"
+msgstr "%ld znaków"
+
+msgid "[noeol]"
+msgstr "[noeol]"
+
+msgid "[Incomplete last line]"
+msgstr "[Niekompletny ostatni wiersz]"
+
+#. don't overwrite messages here
+#. must give this prompt
+#. don't use emsg() here, don't want to flush the buffers
+msgid "WARNING: The file has been changed since reading it!!!"
+msgstr "OSTRZE¯ENIE: Plik zmieni³ siê od czasu ostatniego odczytu!!!"
+
+msgid "Do you really want to write to it"
+msgstr "Czy naprawdê chcesz go zapisaæ"
+
+#, c-format
+msgid "E208: Error writing to \"%s\""
+msgstr "E208: B³¹d zapisywania do \"%s\""
+
+#, c-format
+msgid "E209: Error closing \"%s\""
+msgstr "E209: B³¹d w trakcie zamykania \"%s\""
+
+#, c-format
+msgid "E210: Error reading \"%s\""
+msgstr "E210: B³¹d odczytu \"%s\""
+
+msgid "E246: FileChangedShell autocommand deleted buffer"
+msgstr "E246: Autokomenda FileChangedShell skasowa³a bufor"
+
+#, c-format
+msgid "E211: File \"%s\" no longer available"
+msgstr "E211: Plik \"%s\" nie jest d³u¿ej dostêpny"
+
+#, c-format
+msgid ""
+"W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as "
+"well"
+msgstr ""
+"W12: OSTRZE¯ENIE: Plik \"%s\" zmieni³ siê od czasu rozpoczêcia edycji, bufor "
+"w Vimie równie¿ zosta³ zmieniony"
+
+msgid "See \":help W12\" for more info."
+msgstr "Zobacz \":help W12\" dla dalszych informacji."
+
+#, c-format
+msgid "W11: Warning: File \"%s\" has changed since editing started"
+msgstr "W11: OSTRZE¯ENIE: Plik \"%s\" zmieni³ siê od czasu rozpoczêcia edycji"
+
+msgid "See \":help W11\" for more info."
+msgstr "Zobacz \":help W11\" dla dalszych informacji."
+
+#, c-format
+msgid "W16: Warning: Mode of file \"%s\" has changed since editing started"
+msgstr ""
+"W16: OSTRZE¯ENIE: Tryb pliku \"%s\" zmieni³ siê od czasu rozpoczêcia edycji"
+
+msgid "See \":help W16\" for more info."
+msgstr "Zobacz \":help W16\" dla dalszych informacji."
+
+#, c-format
+msgid "W13: Warning: File \"%s\" has been created after editing started"
+msgstr "W13: OSTRZE¯ENIE: Plik \"%s\" zosta³ stworzony po rozpoczêciu edycji"
+
+msgid "Warning"
+msgstr "OSTRZE¯ENIE"
+
+msgid ""
+"&OK\n"
+"&Load File"
+msgstr ""
+"&OK\n"
+"&Za³aduj Plik"
+
+#, c-format
+msgid "E462: Could not prepare for reloading \"%s\""
+msgstr "E462: Nie mo¿na przygotowaæ prze³adowania \"%s\""
+
+#, c-format
+msgid "E321: Could not reload \"%s\""
+msgstr "E321: Nie mo¿na prze³adowaæ \"%s\""
+
+msgid "--Deleted--"
+msgstr "--Skasowano--"
+
+#, c-format
+msgid "auto-removing autocommand: %s <buffer=%d>"
+msgstr "auto-usuwanie autokomendy: %s <buffer=%d>"
+
+#. the group doesn't exist
+#, c-format
+msgid "E367: No such group: \"%s\""
+msgstr "E367: Nie ma takiej grupy: \"%s\""
+
+#, c-format
+msgid "E215: Illegal character after *: %s"
+msgstr "E215: Niedopuszczalny znak po *: %s"
+
+#, c-format
+msgid "E216: No such event: %s"
+msgstr "E216: Nie ma takiego wydarzenia: %s"
+
+#, c-format
+msgid "E216: No such group or event: %s"
+msgstr "E216: Nie ma takiej grupy lub wydarzenia: %s"
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Autocommands ---"
+msgstr ""
+"\n"
+"--- Autokomendy ---"
+
+#, c-format
+msgid "E680: <buffer=%d>: invalid buffer number "
+msgstr "E680: <buffer=%d>: niew³aœciwy numer bufora"
+
+msgid "E217: Can't execute autocommands for ALL events"
+msgstr "E217: Nie mo¿na wykonywaæ autokomend dla wydarzeñ ALL"
+
+msgid "No matching autocommands"
+msgstr "Brak pasuj¹cych autokomend"
+
+msgid "E218: autocommand nesting too deep"
+msgstr "E218: zbyt g³êbokie zagnie¿d¿enie autokomend"
+
+#, c-format
+msgid "%s Autocommands for \"%s\""
+msgstr "%s Autokomend dla \"%s\""
+
+#, c-format
+msgid "Executing %s"
+msgstr "Wykonujê %s"
+
+#, c-format
+msgid "autocommand %s"
+msgstr "autokomenda %s"
+
+msgid "E219: Missing {."
+msgstr "E219: Brak {."
+
+msgid "E220: Missing }."
+msgstr "E220: Brak }."
+
+msgid "E490: No fold found"
+msgstr "E490: Nie znaleziono zwiniêcia"
+
+msgid "E350: Cannot create fold with current 'foldmethod'"
+msgstr "E350: Nie mo¿na utworzyæ zwiniêcia przy bie¿¹cej 'foldmethod'"
+
+msgid "E351: Cannot delete fold with current 'foldmethod'"
+msgstr "E351: Nie mo¿na skasowaæ zwiniêcia przy bie¿¹cej 'foldmethod'"
+
+#, c-format
+msgid "+--%3ld lines folded "
+msgstr "+--%3ld wierszy zwiniêto "
+
+msgid "E222: Add to read buffer"
+msgstr "E222: Dodaj do bufora odczytu"
+
+msgid "E223: recursive mapping"
+msgstr "E223: rekursywne przyporz¹dkowanie"
+
+#, c-format
+msgid "E224: global abbreviation already exists for %s"
+msgstr "E224: istnieje ju¿ globalny skrót dla %s"
+
+#, c-format
+msgid "E225: global mapping already exists for %s"
+msgstr "E225: istnieje ju¿ globalne przyporz¹dkowanie dla %s"
+
+#, c-format
+msgid "E226: abbreviation already exists for %s"
+msgstr "E226: istnieje ju¿ skrót dla %s"
+
+#, c-format
+msgid "E227: mapping already exists for %s"
+msgstr "E227: istnieje ju¿ przyporz¹dkowanie dla %s"
+
+msgid "No abbreviation found"
+msgstr "Nie znaleziono skrótu"
+
+msgid "No mapping found"
+msgstr "Nie znaleziono przyporz¹dkowania"
+
+msgid "E228: makemap: Illegal mode"
+msgstr "E228: makemap: Niedopuszczalny tryb"
+
+msgid "<cannot open> "
+msgstr "<nie mogê otworzyæ> "
+
+#, c-format
+msgid "E616: vim_SelFile: can't get font %s"
+msgstr "E616: vim_SelFile: nie mogê otrzymaæ czcionki %s"
+
+msgid "E614: vim_SelFile: can't return to current directory"
+msgstr "E614: vim_SelFile: nie mogê powróciæ do bie¿¹cego katalogu"
+
+msgid "Pathname:"
+msgstr "Trop:"
+
+msgid "E615: vim_SelFile: can't get current directory"
+msgstr "E615: vim_SelFile: nie mogê otrzymaæ bie¿¹cego katalogu"
+
+msgid "OK"
+msgstr "OK"
+
+msgid "Cancel"
+msgstr "Zakoñcz"
+
+msgid "Vim dialog"
+msgstr "VIM - Dialog"
+
+msgid "Scrollbar Widget: Could not get geometry of thumb pixmap."
+msgstr "Scrollbar Widget: Nie mog³em otrzymaæ rozmiarów rysunku na przycisku."
+
+msgid "E232: Cannot create BalloonEval with both message and callback"
+msgstr "E232: Nie mogê stworzyæ BalloonEval z powiadomieniem i wywo³aniem"
+
+msgid "E851: Failed to create a new process for the GUI"
+msgstr "E851: Nie mog³em stworzyæ nowego procesu dla GUI"
+
+msgid "E852: The child process failed to start the GUI"
+msgstr "E852: Proces potomny nie móg³ uruchomiæ GUI"
+
+msgid "E229: Cannot start the GUI"
+msgstr "E229: Nie mogê odpaliæ GUI"
+
+#, c-format
+msgid "E230: Cannot read from \"%s\""
+msgstr "E230: Nie mogê czytaæ z \"%s\""
+
+msgid "E665: Cannot start GUI, no valid font found"
+msgstr "E665: Nie mo¿na uruchomiæ GUI, brak prawid³owej czcionki"
+
+msgid "E231: 'guifontwide' invalid"
+msgstr "E231: Niew³aœciwe 'guifontwide'"
+
+msgid "E599: Value of 'imactivatekey' is invalid"
+msgstr "E599: Nieprawid³owa wartoœæ 'imactivatekey'"
+
+#, c-format
+msgid "E254: Cannot allocate color %s"
+msgstr "E254: Nie mogê zarezerwowaæ koloru %s"
+
+msgid "No match at cursor, finding next"
+msgstr "Brak dopasowania przy kursorze, szukam dalej"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"&Cancel"
+msgstr ""
+"&Tak\n"
+"&Nie\n"
+"&Zakoñcz"
+
+msgid "Input _Methods"
+msgstr "Input _Methods"
+
+msgid "VIM - Search and Replace..."
+msgstr "VIM - Szukaj i Zamieñ..."
+
+msgid "VIM - Search..."
+msgstr "VIM - Szukaj..."
+
+msgid "Find what:"
+msgstr "ZnajdŸ:"
+
+msgid "Replace with:"
+msgstr "Zamieñ na:"
+
+#. whole word only button
+msgid "Match whole word only"
+msgstr "Dopasuj tylko ca³e wyrazy"
+
+#. match case button
+msgid "Match case"
+msgstr "Dopasuj wielkoϾ liter"
+
+msgid "Direction"
+msgstr "Kierunek"
+
+#. 'Up' and 'Down' buttons
+msgid "Up"
+msgstr "W górê"
+
+msgid "Down"
+msgstr "W dó³"
+
+#. 'Find Next' button
+msgid "Find Next"
+msgstr "ZnajdŸ nastêpne"
+
+#. 'Replace' button
+msgid "Replace"
+msgstr "Zamieñ"
+
+#. 'Replace All' button
+msgid "Replace All"
+msgstr "Zamieñ wszystkie"
+
+msgid "Vim: Received \"die\" request from session manager\n"
+msgstr "Vim: otrzymano ¿¹danie \"die\" od mened¿era sesji\n"
+
+msgid "Close"
+msgstr "Zamknij"
+
+msgid "New tab"
+msgstr "Nowa karta"
+
+msgid "Open Tab..."
+msgstr "Otwórz kartê..."
+
+msgid "Vim: Main window unexpectedly destroyed\n"
+msgstr "Vim: G³ówne okno nieoczekiwanie zniszczone\n"
+
+msgid "&Filter"
+msgstr "&Filtr"
+
+msgid "&Cancel"
+msgstr "&Anuluj"
+
+msgid "Directories"
+msgstr "Katalogi"
+
+msgid "Filter"
+msgstr "Filtr"
+
+msgid "&Help"
+msgstr "&Pomoc"
+
+msgid "Files"
+msgstr "Pliki"
+
+msgid "&OK"
+msgstr "&OK"
+
+msgid "Selection"
+msgstr "Wybór"
+
+msgid "Find &Next"
+msgstr "ZnajdŸ &nastêpne"
+
+msgid "&Replace"
+msgstr "&Zamieñ"
+
+msgid "Replace &All"
+msgstr "Zamieñ &wszystko"
+
+msgid "&Undo"
+msgstr "&Cofnij"
+
+#, c-format
+msgid "E671: Cannot find window title \"%s\""
+msgstr "E671: Nie mogê znaleŸæ tytu³u okna \"%s\""
+
+#, c-format
+msgid "E243: Argument not supported: \"-%s\"; Use the OLE version."
+msgstr "E243: Argument nie jest wspomagany: \"-%s\"; U¿ywaj wersji OLE."
+
+msgid "E672: Unable to open window inside MDI application"
+msgstr "E672: Nie mo¿na otworzyæ okna wewn¹trz aplikacji MDI"
+
+msgid "Close tab"
+msgstr "Zamknij kartê"
+
+msgid "Open tab..."
+msgstr "Otwórz kartê..."
+
+msgid "Find string (use '\\\\' to find a '\\')"
+msgstr "ZnajdŸ ci¹g (u¿yj '\\\\' do szukania '\\')"
+
+msgid "Find & Replace (use '\\\\' to find a '\\')"
+msgstr "Szukanie i Zamiana (u¿yj '\\\\' do szukania '\\')"
+
+#. We fake this: Use a filter that doesn't select anything and a default
+#. * file name that won't be used.
+msgid "Not Used"
+msgstr "Nie u¿ywany"
+
+msgid "Directory\t*.nothing\n"
+msgstr "Katalog\t*.nic\n"
+
+msgid "Vim E458: Cannot allocate colormap entry, some colors may be incorrect"
+msgstr ""
+"Vim E458: Nie mogê zarezerwowaæ mapy kolorów, pewne kolory mog¹ byæ "
+"nieprawid³owe"
+
+#, c-format
+msgid "E250: Fonts for the following charsets are missing in fontset %s:"
+msgstr ""
+"E250: Brak czcionek dla nastêpuj¹cych zestawów znaków w zestawie czcionek %s:"
+
+#, c-format
+msgid "E252: Fontset name: %s"
+msgstr "E252: Nazwa zestawu czcionek: %s"
+
+#, c-format
+msgid "Font '%s' is not fixed-width"
+msgstr "Czcionka '%s' nie posiada znaków jednolitej szerokoœci"
+
+#, c-format
+msgid "E253: Fontset name: %s"
+msgstr "E253: Nazwa zestawu czcionek: %s"
+
+#, c-format
+msgid "Font0: %s"
+msgstr "Font0: %s"
+
+#, c-format
+msgid "Font1: %s"
+msgstr "Font1: %s"
+
+#, c-format
+msgid "Font%ld width is not twice that of font0"
+msgstr "Szerokoœæ font%ld nie jest podwójn¹ szerokoœci¹ font0"
+
+#, c-format
+msgid "Font0 width: %ld"
+msgstr "SzerokoϾ font0: %ld"
+
+#, c-format
+msgid "Font1 width: %ld"
+msgstr "SzerokoϾ font1: %ld"
+
+msgid "Invalid font specification"
+msgstr "Nieprawid³owy opis czcionki"
+
+msgid "&Dismiss"
+msgstr "&Anuluj"
+
+msgid "no specific match"
+msgstr "brak okreœlonego dopasowania"
+
+msgid "Vim - Font Selector"
+msgstr "Vim - wybór czcionki"
+
+msgid "Name:"
+msgstr "Nazwa:"
+
+#. create toggle button
+msgid "Show size in Points"
+msgstr "Poka¿ wielkoœæ w punktach"
+
+msgid "Encoding:"
+msgstr "Kodowanie:"
+
+msgid "Font:"
+msgstr "Czcionka:"
+
+msgid "Style:"
+msgstr "Styl:"
+
+msgid "Size:"
+msgstr "WielkoϾ:"
+
+msgid "E256: Hangul automata ERROR"
+msgstr "E256: B£¥D w automacie Hangul"
+
+msgid "E550: Missing colon"
+msgstr "E550: Brak dwukropka"
+
+msgid "E551: Illegal component"
+msgstr "E551: Niedozwolona czêœæ"
+
+msgid "E552: digit expected"
+msgstr "E552: oczekiwa³em na cyfrê"
+
+#, c-format
+msgid "Page %d"
+msgstr "Strona %d"
+
+msgid "No text to be printed"
+msgstr "Brak tekstu do drukowania"
+
+#, c-format
+msgid "Printing page %d (%d%%)"
+msgstr "Drukujê stronê %d (%d%%)"
+
+#, c-format
+msgid " Copy %d of %d"
+msgstr " Kopia %d z %d"
+
+#, c-format
+msgid "Printed: %s"
+msgstr "Wydrukowano: %s"
+
+msgid "Printing aborted"
+msgstr "Drukowanie odwo³ane"
+
+msgid "E455: Error writing to PostScript output file"
+msgstr "E455: Nie mo¿na zapisaæ do wyjœciowego pliku PostScriptu"
+
+#, c-format
+msgid "E624: Can't open file \"%s\""
+msgstr "E624: Nie mogê otworzyæ pliku \"%s\""
+
+#, c-format
+msgid "E457: Can't read PostScript resource file \"%s\""
+msgstr "E457: Nie mo¿na odczytaæ pliku zasobów PostScriptu \"%s\""
+
+#, c-format
+msgid "E618: file \"%s\" is not a PostScript resource file"
+msgstr "E618: plik \"%s\" nie jest plikiem zasobów PostScriptu"
+
+#, c-format
+msgid "E619: file \"%s\" is not a supported PostScript resource file"
+msgstr "E619: plik \"%s\" nie jest wspieranym plikiem zasobów PostScriptu"
+
+#, c-format
+msgid "E621: \"%s\" resource file has wrong version"
+msgstr "E621: \"%s\" nieprawid³owa wersja pliku zasobów"
+
+msgid "E673: Incompatible multi-byte encoding and character set."
+msgstr "E673: Niekompatybilne kodowanie wielobajtowe i zestaw znaków."
+
+msgid "E674: printmbcharset cannot be empty with multi-byte encoding."
+msgstr "E674: printmbcharset nie mo¿e byæ pusty przy kodowaniu wielobajtowym."
+
+msgid "E675: No default font specified for multi-byte printing."
+msgstr "E675: Nie okreœlono domyœlnej czcionki dla drukowania wielobajtowego."
+
+msgid "E324: Can't open PostScript output file"
+msgstr "E324: Nie mo¿na otworzyæ pliku PostScript do wyjœcia"
+
+#, c-format
+msgid "E456: Can't open file \"%s\""
+msgstr "E456: Nie mogê otworzyæ pliku \"%s\""
+
+msgid "E456: Can't find PostScript resource file \"prolog.ps\""
+msgstr "E456: Nie mo¿na znaleŸæ pliku zasobów PostScriptu \"prolog.ps\""
+
+msgid "E456: Can't find PostScript resource file \"cidfont.ps\""
+msgstr "E456: Nie mo¿na znaleŸæ pliku zasobów PostScriptu \"cidfont.ps\""
+
+#, c-format
+msgid "E456: Can't find PostScript resource file \"%s.ps\""
+msgstr "E456: Nie mo¿na znaleŸæ pliku zasobów PostScriptu \"%s.ps\""
+
+#, c-format
+msgid "E620: Unable to convert to print encoding \"%s\""
+msgstr "E620: Nie mo¿na przekonwertowaæ by drukowaæ kodowanie \"%s\""
+
+msgid "Sending to printer..."
+msgstr "Przesy³am do drukarki..."
+
+msgid "E365: Failed to print PostScript file"
+msgstr "E365: Drukowanie pliku PostScript nie powiod³o siê"
+
+msgid "Print job sent."
+msgstr "Zadanie drukowanie przes³ane."
+
+msgid "Add a new database"
+msgstr "Dodaj now¹ bazê danych"
+
+msgid "Query for a pattern"
+msgstr "Zapytane o wzorzec"
+
+msgid "Show this message"
+msgstr "Poka¿ ten komunikat"
+
+msgid "Kill a connection"
+msgstr "Zabij po³¹czenie"
+
+msgid "Reinit all connections"
+msgstr "Ponów wszelkie po³¹czenia"
+
+msgid "Show connections"
+msgstr "Poka¿ po³¹czenia"
+
+#, c-format
+msgid "E560: Usage: cs[cope] %s"
+msgstr "E560: Zastosowanie: cs[cope] %s"
+
+msgid "This cscope command does not support splitting the window.\n"
+msgstr "Ta komenda cscope nie wspomaga podzielenia okna.\n"
+
+msgid "E562: Usage: cstag <ident>"
+msgstr "E562: Zastosowanie: cstag <ident>"
+
+msgid "E257: cstag: tag not found"
+msgstr "E257: cstag: nie znaleziono znacznika"
+
+#, c-format
+msgid "E563: stat(%s) error: %d"
+msgstr "E563: stat(%s) b³¹d: %d"
+
+msgid "E563: stat error"
+msgstr "E563: b³¹d stat"
+
+#, c-format
+msgid "E564: %s is not a directory or a valid cscope database"
+msgstr "E564: %s nie jest katalogiem lub poprawn¹ baz¹ danych cscope"
+
+#, c-format
+msgid "Added cscope database %s"
+msgstr "Dodano bazê danych cscope %s"
+
+#, c-format
+msgid "E262: error reading cscope connection %ld"
+msgstr "E262: b³¹d odczytu po³¹czenia z cscope %ld"
+
+msgid "E561: unknown cscope search type"
+msgstr "E561: nieznany typ szukania cscope"
+
+msgid "E566: Could not create cscope pipes"
+msgstr "E566: Nie mog³em stworzyæ potoku do cscope"
+
+msgid "E622: Could not fork for cscope"
+msgstr "E622: Nie mog³em utworzyæ rozwidlenia dla cscope"
+
+msgid "cs_create_connection setpgid failed"
+msgstr "nie powiod³o siê setpgid cs_create_connection"
+
+msgid "cs_create_connection exec failed"
+msgstr "wykonanie cs_create_connection nie powiod³o siê"
+
+msgid "cs_create_connection: fdopen for to_fp failed"
+msgstr "cs_create_connection: fdopen dla to_fp nie powiod³o siê"
+
+msgid "cs_create_connection: fdopen for fr_fp failed"
+msgstr "cs_create_connection: fdopen dla fr_fp nie powiod³o siê"
+
+msgid "E623: Could not spawn cscope process"
+msgstr "E623: Nie mog³em stworzyæ procesu cscope"
+
+msgid "E567: no cscope connections"
+msgstr "E567: brak po³¹czenia z cscope"
+
+#, c-format
+msgid "E469: invalid cscopequickfix flag %c for %c"
+msgstr "E469: nieprawid³owa flaga cscopequickfix %c dla %c"
+
+#, c-format
+msgid "E259: no matches found for cscope query %s of %s"
+msgstr "E259: brak dopasowañ dla zapytania cscope %s o %s"
+
+msgid "cscope commands:\n"
+msgstr "komendy cscope:\n"
+
+#, c-format
+msgid "%-5s: %s%*s (Usage: %s)"
+msgstr "%-5s: %s%*s (U¿ycie: %s)"
+
+msgid ""
+"\n"
+" c: Find functions calling this function\n"
+" d: Find functions called by this function\n"
+" e: Find this egrep pattern\n"
+" f: Find this file\n"
+" g: Find this definition\n"
+" i: Find files #including this file\n"
+" s: Find this C symbol\n"
+" t: Find this text string\n"
+msgstr ""
+"\n"
+" c: znajdŸ funkcje wywo³uj¹ce tê funkcjê\n"
+" d: znajdŸ funkcje wywo³ywane przez tê funkcjê\n"
+" e: znajdŸ ten wzorzec egrep\n"
+" f: znajdŸ ten plik\n"
+" g: znajdŸ tê definicjê\n"
+" i: znajdŸ pliki w³¹czaj¹ce (#include) ten plik\n"
+" s: znajdŸ ten symbol C\n"
+" t: znajdŸ ten ³añcuch znaków\n"
+
+#, c-format
+msgid "E625: cannot open cscope database: %s"
+msgstr "E625: nie mogê otworzyæ bazy danych cscope: %s"
+
+msgid "E626: cannot get cscope database information"
+msgstr "E626: nie mogê uzyskaæ informacji z bazy danych cscope"
+
+msgid "E568: duplicate cscope database not added"
+msgstr "E568: nie dodano duplikatu bazy danych cscope"
+
+#, c-format
+msgid "E261: cscope connection %s not found"
+msgstr "E261: nie ma po³¹czenia %s z cscope"
+
+#, c-format
+msgid "cscope connection %s closed"
+msgstr "po³¹czenie %s z cscope zosta³o zamkniête"
+
+#. should not reach here
+msgid "E570: fatal error in cs_manage_matches"
+msgstr "E570: b³¹d krytyczny w cs_manage_matches"
+
+#, c-format
+msgid "Cscope tag: %s"
+msgstr "Znacznik cscope: %s"
+
+msgid ""
+"\n"
+" # line"
+msgstr ""
+"\n"
+" # wiersz"
+
+msgid "filename / context / line\n"
+msgstr "nazwa pliku / kontekst / wiersz\n"
+
+#, c-format
+msgid "E609: Cscope error: %s"
+msgstr "E609: B³¹d cscope: %s"
+
+msgid "All cscope databases reset"
+msgstr "Wszystkie bazy danych cscope prze³adowano"
+
+msgid "no cscope connections\n"
+msgstr "brak po³¹czeñ z cscope\n"
+
+msgid " # pid database name prepend path\n"
+msgstr " # pid nazwa bazy danych przedsionek tropu\n"
+
+msgid "Lua library cannot be loaded."
+msgstr "Nie mo¿na wczytaæ biblioteki Lua."
+
+msgid "cannot save undo information"
+msgstr "nie mogê zachowaæ informacji cofania"
+
+msgid ""
+"E815: Sorry, this command is disabled, the MzScheme libraries could not be "
+"loaded."
+msgstr ""
+"E815: Przykro mi, ta komenda jest wy³¹czona, biblioteka MzScheme nie mo¿e "
+"byæ za³adowana."
+
+msgid "invalid expression"
+msgstr "niepoprawne wyra¿enie"
+
+msgid "expressions disabled at compile time"
+msgstr "wyra¿enia wy³¹czone podczas kompilacji"
+
+msgid "hidden option"
+msgstr "ukryta opcja"
+
+msgid "unknown option"
+msgstr "nieznana opcja"
+
+msgid "window index is out of range"
+msgstr "indeks okna poza zakresem"
+
+msgid "couldn't open buffer"
+msgstr "nie mogê otworzyæ bufora"
+
+msgid "cannot delete line"
+msgstr "nie mogê skasowaæ wiersza"
+
+msgid "cannot replace line"
+msgstr "nie mogê zamieniæ wiersza"
+
+msgid "cannot insert line"
+msgstr "nie mogê wprowadziæ wiersza"
+
+msgid "string cannot contain newlines"
+msgstr "ci¹g nie mo¿e zawieraæ znaków nowego wiersza"
+
+msgid "error converting Scheme values to Vim"
+msgstr "b³¹d przy konwersji wartoœci Scheme do Vima"
+
+msgid "Vim error: ~a"
+msgstr "B³¹d vima: ~a"
+
+msgid "Vim error"
+msgstr "B³¹d Vima"
+
+msgid "buffer is invalid"
+msgstr "bufor jest niewa¿ny"
+
+msgid "window is invalid"
+msgstr "okno jest niewa¿ne"
+
+msgid "linenr out of range"
+msgstr "numer wiersza poza zakresem"
+
+msgid "not allowed in the Vim sandbox"
+msgstr "Niedozwolone w piaskownicy Vima"
+
+msgid "E837: This Vim cannot execute :py3 after using :python"
+msgstr "E837: Python: nie mo¿na u¿ywaæ :py i :py3 w czasie jednej sesji"
+
+msgid ""
+"E263: Sorry, this command is disabled, the Python library could not be "
+"loaded."
+msgstr ""
+"E263: Przykro mi, ta komenda jest wy³¹czona, bo nie mo¿na za³adowaæ "
+"biblioteki Pythona"
+
+msgid "E836: This Vim cannot execute :python after using :py3"
+msgstr "E836: Python: nie mo¿na u¿ywaæ :py i :py3 w czasie jednej sesji"
+
+msgid "E659: Cannot invoke Python recursively"
+msgstr "E659: Nie mo¿na wywo³aæ Pythona rekursywnie"
+
+msgid "E265: $_ must be an instance of String"
+msgstr "E265: $_ musi byæ reprezentacj¹ £añcucha"
+
+msgid ""
+"E266: Sorry, this command is disabled, the Ruby library could not be loaded."
+msgstr ""
+"E266: Przykro mi, ta komenda jest wy³¹czona, bo nie mo¿na za³adowaæ "
+"biblioteki Ruby."
+
+msgid "E267: unexpected return"
+msgstr "E267: nieoczekiwany return"
+
+msgid "E268: unexpected next"
+msgstr "E268: nieoczekiwany next"
+
+msgid "E269: unexpected break"
+msgstr "E269: nieoczekiwany break"
+
+msgid "E270: unexpected redo"
+msgstr "E270: nieoczekiwane redo"
+
+msgid "E271: retry outside of rescue clause"
+msgstr "E271: ponowna próba poza klauzul¹ ratunku"
+
+msgid "E272: unhandled exception"
+msgstr "E272: nieobs³ugiwany wyj¹tek"
+
+#, c-format
+msgid "E273: unknown longjmp status %d"
+msgstr "E273: Nieznany status longjmp %d"
+
+msgid "Toggle implementation/definition"
+msgstr "Prze³¹cz miêdzy implementacj¹/okreœleniem"
+
+msgid "Show base class of"
+msgstr "Poka¿ bazê klasy"
+
+msgid "Show overridden member function"
+msgstr "Poka¿ przepisan¹ funkcjê cz³onow¹"
+
+msgid "Retrieve from file"
+msgstr "Pobieraj z pliku"
+
+msgid "Retrieve from project"
+msgstr "Pobieraj z projektu"
+
+msgid "Retrieve from all projects"
+msgstr "Pobieraj z wszystkich projektów"
+
+msgid "Retrieve"
+msgstr "Pobierz"
+
+msgid "Show source of"
+msgstr "Poka¿ Ÿród³o dla"
+
+msgid "Find symbol"
+msgstr "ZnajdŸ symbol"
+
+msgid "Browse class"
+msgstr "Przejrzyj klasê"
+
+msgid "Show class in hierarchy"
+msgstr "Poka¿ klasê w hierarchii"
+
+msgid "Show class in restricted hierarchy"
+msgstr "Poka¿ klasê w ograniczonej hierarchii"
+
+msgid "Xref refers to"
+msgstr "Xref odnosi siê do"
+
+msgid "Xref referred by"
+msgstr "Xref ma odniesienia od"
+
+msgid "Xref has a"
+msgstr "Xref ma"
+
+msgid "Xref used by"
+msgstr "Xref u¿yte przez"
+
+msgid "Show docu of"
+msgstr "Poka¿ dokumentacjê dla"
+
+msgid "Generate docu for"
+msgstr "Utwórz dokumentacjê dla"
+
+msgid ""
+"Cannot connect to SNiFF+. Check environment (sniffemacs must be found in "
+"$PATH).\n"
+msgstr ""
+"Nie mogê pod³¹czyæ do SNiFF+. SprawdŸ œrodowisko (sniffemacs musi byæ "
+"odnaleziony w $PATH).\n"
+
+msgid "E274: Sniff: Error during read. Disconnected"
+msgstr "E274: Sniff: B³¹d podczas czytania. Roz³¹czenie"
+
+msgid "SNiFF+ is currently "
+msgstr "SNiFF+ jest obecnie "
+
+msgid "not "
+msgstr "nie "
+
+msgid "connected"
+msgstr "pod³¹czony"
+
+#, c-format
+msgid "E275: Unknown SNiFF+ request: %s"
+msgstr "E275: Nieznane zapytanie SNiFF+: %s"
+
+msgid "E276: Error connecting to SNiFF+"
+msgstr "E276: B³¹d w trakcie pod³¹czania do SNiFF+"
+
+msgid "E278: SNiFF+ not connected"
+msgstr "E278: SNiFF+ niepod³¹czony"
+
+msgid "E279: Not a SNiFF+ buffer"
+msgstr "E279: Nie jest buforem SNiFF+"
+
+msgid "Sniff: Error during write. Disconnected"
+msgstr "Sniff: B³¹d w trakcie zapisu. Roz³¹czony"
+
+msgid "invalid buffer number"
+msgstr "niew³aœciwy numer bufora"
+
+msgid "not implemented yet"
+msgstr "obecnie nie zaimplementowano"
+
+#. ???
+msgid "cannot set line(s)"
+msgstr "nie mogê ustawiæ wiersza(y)"
+
+msgid "invalid mark name"
+msgstr "niepoprawna nazwa zak³adki"
+
+msgid "mark not set"
+msgstr "zak³adka nie ustawiona"
+
+#, c-format
+msgid "row %d column %d"
+msgstr "wiersz %d kolumna %d"
+
+msgid "cannot insert/append line"
+msgstr "nie mogê wprowadziæ/do³¹czyæ wiersza"
+
+msgid "line number out of range"
+msgstr "numer wiersza poza zakresem"
+
+msgid "unknown flag: "
+msgstr "nieznana flaga: "
+
+msgid "unknown vimOption"
+msgstr "nieznane vimOption"
+
+msgid "keyboard interrupt"
+msgstr "przerwanie klawiatury"
+
+msgid "vim error"
+msgstr "b³¹d vima"
+
+msgid "cannot create buffer/window command: object is being deleted"
+msgstr "nie mogê stworzyæ bufora/okna komendy: obiekt jest kasowany"
+
+msgid ""
+"cannot register callback command: buffer/window is already being deleted"
+msgstr ""
+"nie mogê zarejestrowaæ wstecznego wywo³ania komendy: bufor/okno ju¿ zosta³a "
+"skasowana"
+
+#. This should never happen. Famous last word?
+msgid ""
+"E280: TCL FATAL ERROR: reflist corrupt!? Please report this to vim-dev@vim."
+"org"
+msgstr ""
+"E280: TCL FATALNY B£¥D: reflist zepsuta!? Proszê z³o¿yæ raport o tym na vim-"
+"dev@vim.org"
+
+msgid "cannot register callback command: buffer/window reference not found"
+msgstr ""
+"nie mogê zarejestrowaæ wstecznego wywo³ania komendy: brak odniesienia do "
+"bufora/okna"
+
+msgid ""
+"E571: Sorry, this command is disabled: the Tcl library could not be loaded."
+msgstr ""
+"E571: Przykro mi, ta komenda jest wy³¹czona, bo nie mo¿na za³adowaæ "
+"biblioteki Tcl."
+
+#, c-format
+msgid "E572: exit code %d"
+msgstr "E572: kod wyjœcia %d"
+
+msgid "cannot get line"
+msgstr "nie mogê dostaæ wiersza"
+
+msgid "Unable to register a command server name"
+msgstr "Nie mogê zarejestrowaæ nazwy serwera komend"
+
+msgid "E248: Failed to send command to the destination program"
+msgstr "E248: Wys³anie komendy do programu docelowego nie powiod³o siê"
+
+#, c-format
+msgid "E573: Invalid server id used: %s"
+msgstr "E573: U¿yto niew³aœciwego id serwera: %s"
+
+msgid "E251: VIM instance registry property is badly formed. Deleted!"
+msgstr ""
+"E251: wcielenia instancji rejestru Vima jest Ÿle sformowane. Skasowano!"
+
+msgid "Unknown option argument"
+msgstr "Nieznany argument opcji"
+
+msgid "Too many edit arguments"
+msgstr "Zbyt wiele argumentów"
+
+msgid "Argument missing after"
+msgstr "Brak argumentu po"
+
+msgid "Garbage after option argument"
+msgstr "Œmiecie po argumencie opcji"
+
+msgid "Too many \"+command\", \"-c command\" or \"--cmd command\" arguments"
+msgstr ""
+"Zbyt wiele argumentów \"+komenda\", \"-c komenda\" lub \"--cmd komenda\""
+
+msgid "Invalid argument for"
+msgstr "Niew³aœciwy argument dla"
+
+#, c-format
+msgid "%d files to edit\n"
+msgstr "%d plików do edycji\n"
+
+msgid "netbeans is not supported with this GUI\n"
+msgstr "netbeans nie s¹ obs³ugiwane przez to GUI\n"
+
+msgid "This Vim was not compiled with the diff feature."
+msgstr "Ta wersja Vima nie by³a skompilowanego z opcj¹ ró¿nic (diff)."
+
+msgid "'-nb' cannot be used: not enabled at compile time\n"
+msgstr "'-nb' - nie mo¿e byæ u¿yte: nie w³¹czone przy kompilacji\n"
+
+msgid "Attempt to open script file again: \""
+msgstr "Próba ponownego otworzenia pliku skryptu: \""
+
+msgid "Cannot open for reading: \""
+msgstr "Nie mogê otworzyæ do odczytu: \""
+
+msgid "Cannot open for script output: \""
+msgstr "Nie mogê otworzyæ dla wyjœcia skryptu: \""
+
+msgid "Vim: Error: Failure to start gvim from NetBeans\n"
+msgstr "Vim: B³¹d: Nie mo¿na uruchomiæ gvim z NetBeans\n"
+
+msgid "Vim: Warning: Output is not to a terminal\n"
+msgstr "Vim: OSTRZE¯ENIE: Wyjœcie nie jest terminalem\n"
+
+msgid "Vim: Warning: Input is not from a terminal\n"
+msgstr "Vim: OSTRZE¯ENIE: Wejœcie nie pochodzi z terminala\n"
+
+#. just in case..
+msgid "pre-vimrc command line"
+msgstr "linia poleceñ pre-vimrc"
+
+#, c-format
+msgid "E282: Cannot read from \"%s\""
+msgstr "E282: Nie mogê czytaæ z \"%s\""
+
+msgid ""
+"\n"
+"More info with: \"vim -h\"\n"
+msgstr ""
+"\n"
+"Dalsze informacje poprzez: \"vim -h\"\n"
+
+msgid "[file ..] edit specified file(s)"
+msgstr "[plik ..] edytuj zadane pliki"
+
+msgid "- read text from stdin"
+msgstr "- czytaj tekst ze stdin"
+
+msgid "-t tag edit file where tag is defined"
+msgstr "-t znacznik edytuj plik, w którym dany znacznik jest zdefiniowany"
+
+msgid "-q [errorfile] edit file with first error"
+msgstr "-q [errorfile] edytuj plik, zawieraj¹cy pierwszy b³¹d"
+
+msgid ""
+"\n"
+"\n"
+"Usage:"
+msgstr ""
+"\n"
+"\n"
+"u¿ycie:"
+
+msgid " vim [arguments] "
+msgstr " vim [argumenty]"
+
+msgid ""
+"\n"
+" or:"
+msgstr ""
+"\n"
+" lub:"
+
+msgid ""
+"\n"
+"Where case is ignored prepend / to make flag upper case"
+msgstr ""
+"\n"
+"gdzie wielkoœæ znaków jest ignorowana dodaj na pocz¹tku / by flaga by³a "
+"wielk¹ liter¹"
+
+msgid ""
+"\n"
+"\n"
+"Arguments:\n"
+msgstr ""
+"\n"
+"\n"
+"Argumenty:\n"
+
+msgid "--\t\t\tOnly file names after this"
+msgstr "--\t\t\tTylko nazwy plików po tym"
+
+msgid "--literal\t\tDon't expand wildcards"
+msgstr "--literal\t\tNie rozwijaj znaków specjalnych"
+
+msgid "-register\t\tRegister this gvim for OLE"
+msgstr "-register\t\tZarejestruj tego gvima w OLE"
+
+msgid "-unregister\t\tUnregister gvim for OLE"
+msgstr "-unregister\t\tWyrejestruj gvima z OLE"
+
+msgid "-g\t\t\tRun using GUI (like \"gvim\")"
+msgstr "-g\t\t\tStartuj w GUI (tak jak \"gvim\")"
+
+msgid "-f or --nofork\tForeground: Don't fork when starting GUI"
+msgstr "-f lub --nofork\tPierwszy plan: Nie wydzielaj przy odpalaniu GUI"
+
+msgid "-v\t\t\tVi mode (like \"vi\")"
+msgstr "-v\t\t\tTryb vi (jak \"vi\")"
+
+msgid "-e\t\t\tEx mode (like \"ex\")"
+msgstr "-e\t\t\tTryb ex (jak \"ex\")"
+
+msgid "-E\t\t\tImproved Ex mode"
+msgstr "-E\t\t\tUsprawniony tryb Ex"
+
+msgid "-s\t\t\tSilent (batch) mode (only for \"ex\")"
+msgstr "-s\t\t\tCichy tryb (t³a) (tylko dla \"ex\")"
+
+msgid "-d\t\t\tDiff mode (like \"vimdiff\")"
+msgstr "-d\t\t\tTryb ró¿nic (jak \"vimdiff\")"
+
+msgid "-y\t\t\tEasy mode (like \"evim\", modeless)"
+msgstr "-y\t\t\tTryb ³atwy (jak \"evim\", bez trybów)"
+
+msgid "-R\t\t\tReadonly mode (like \"view\")"
+msgstr "-R\t\t\tTryb wy³¹cznie do odczytu (jak \"view\")"
+
+msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
+msgstr "-Z\t\t\tTryb ograniczenia (jak \"rvim\")"
+
+msgid "-m\t\t\tModifications (writing files) not allowed"
+msgstr "-m\t\t\tModyfikacje (zapisywanie plików) niedozwolone"
+
+msgid "-M\t\t\tModifications in text not allowed"
+msgstr "-M\t\t\tZakaz modyfikacji tekstu"
+
+msgid "-b\t\t\tBinary mode"
+msgstr "-b\t\t\tTryb binarny"
+
+msgid "-l\t\t\tLisp mode"
+msgstr "-l\t\t\tTryb lisp"
+
+msgid "-C\t\t\tCompatible with Vi: 'compatible'"
+msgstr "-C\t\t\tB¹dŸ zgodny z Vi: 'compatible'"
+
+msgid "-N\t\t\tNot fully Vi compatible: 'nocompatible'"
+msgstr "-N\t\t\tB¹dŸ niezupe³nie zgodny z Vi: 'nocompatible'"
+
+msgid "-V[N][fname]\t\tBe verbose [level N] [log messages to fname]"
+msgstr "-V[N][nazwap]\t\tGadatliwy [poziom N] [zapisuj wiadomoœci do nazwap]"
+
+msgid "-D\t\t\tDebugging mode"
+msgstr "-D\t\t\tTryb odpluskwiania"
+
+msgid "-n\t\t\tNo swap file, use memory only"
+msgstr "-n\t\t\tZamiast pliku wymiany, u¿ywaj tylko pamiêci"
+
+msgid "-r\t\t\tList swap files and exit"
+msgstr "-r\t\t\tWylicz pliki wymiany i zakoñcz"
+
+msgid "-r (with file name)\tRecover crashed session"
+msgstr "-r (z nazw¹ pliku)\tOdtwórz za³aman¹ sesjê"
+
+msgid "-L\t\t\tSame as -r"
+msgstr "-L\t\t\tTo¿same z -r"
+
+msgid "-f\t\t\tDon't use newcli to open window"
+msgstr "-f\t\t\tNie stosuj newcli do otwierania okien"
+
+msgid "-dev <device>\t\tUse <device> for I/O"
+msgstr "-dev <device>\t\tU¿ywaj <device> do I/O"
+
+msgid "-A\t\t\tStart in Arabic mode"
+msgstr "-A\t\t\trozpocznij w trybie arabskim"
+
+msgid "-H\t\t\tStart in Hebrew mode"
+msgstr "-H\t\t\trozpocznij w trybie hebrajskim"
+
+msgid "-F\t\t\tStart in Farsi mode"
+msgstr "-F\t\t\trozpocznij w trybie farsi"
+
+msgid "-T <terminal>\tSet terminal type to <terminal>"
+msgstr "-T <terminal>\tUstaw typ terminala na <terminal>"
+
+msgid "-u <vimrc>\t\tUse <vimrc> instead of any .vimrc"
+msgstr "-u <vimrc>\t\tU¿yj <vimrc> zamiast jakiegokolwiek .vimrc"
+
+msgid "-U <gvimrc>\t\tUse <gvimrc> instead of any .gvimrc"
+msgstr "-U <gvimrc>\t\tU¿yj <gvimrc> zamiast jakiegokolwiek .gvimrc"
+
+msgid "--noplugin\t\tDon't load plugin scripts"
+msgstr "--noplugin\t\tNie ³aduj skryptów wtyczek"
+
+msgid "-p[N]\t\tOpen N tab pages (default: one for each file)"
+msgstr "-p[N]\t\tOtwórz N kart (domyœlnie: po jednej dla ka¿dego pliku)"
+
+msgid "-o[N]\t\tOpen N windows (default: one for each file)"
+msgstr "-o[N]\t\tOtwórz N okien (domyœlnie: po jednym dla ka¿dego pliku)"
+
+msgid "-O[N]\t\tLike -o but split vertically"
+msgstr "-O[N]\t\ttak samo jak -o tylko dziel okno pionowo"
+
+msgid "+\t\t\tStart at end of file"
+msgstr "+\t\t\tZacznij na koñcu pliku"
+
+msgid "+<lnum>\t\tStart at line <lnum>"
+msgstr "+<lnum>\t\tZacznij w wierszu <lnum>"
+
+msgid "--cmd <command>\tExecute <command> before loading any vimrc file"
+msgstr ""
+"-cmd <command>\t\tWykonaj komendê <command> przed za³adowaniem "
+"jakiegokolwiek pliku vimrc"
+
+msgid "-c <command>\t\tExecute <command> after loading the first file"
+msgstr ""
+"-c <command>\t\tWykonaj komendê <command> po za³adowaniu pierwszego pliku"
+
+msgid "-S <session>\t\tSource file <session> after loading the first file"
+msgstr "-S <sesja>\t\tWczytaj plik <sesja> po za³adowaniu pierwszego pliku"
+
+msgid "-s <scriptin>\tRead Normal mode commands from file <scriptin>"
+msgstr "-s <scriptin>\tWczytuj komendy trybu normalnego z pliku <scriptin>"
+
+msgid "-w <scriptout>\tAppend all typed commands to file <scriptout>"
+msgstr ""
+"-w <scriptout>\tDo³¹cz wszystkie wprowadzane komendy do pliku <scriptout>"
+
+msgid "-W <scriptout>\tWrite all typed commands to file <scriptout>"
+msgstr ""
+"-W <scriptout>\tZapisuj wszystkie wprowadzane komendy do pliku <scriptout>"
+
+msgid "-x\t\t\tEdit encrypted files"
+msgstr "-x\t\t\tEdytuj zakodowane pliki"
+
+msgid "-display <display>\tConnect vim to this particular X-server"
+msgstr "-display <display>\tPod³¹cz vima to danego X-serwera"
+
+msgid "-X\t\t\tDo not connect to X server"
+msgstr "-X\t\t\tNie ³¹cz z serwerem X"
+
+msgid "--remote <files>\tEdit <files> in a Vim server if possible"
+msgstr "--remote <pliki>\tEdytuj pliki w serwerze Vima jeœli mo¿liwe"
+
+msgid "--remote-silent <files> Same, don't complain if there is no server"
+msgstr "--remote-silent <pliki> To samo, nie narzekaj jeœli nie ma serwera"
+
+msgid ""
+"--remote-wait <files> As --remote but wait for files to have been edited"
+msgstr ""
+"--remote-wait <pliki>\tTak jak --remote, lecz czekaj na pliki przed edycj¹"
+
+msgid ""
+"--remote-wait-silent <files> Same, don't complain if there is no server"
+msgstr ""
+"--remote-wait-silent <pliki> To samo, nie narzekaj jeœli nie ma serwera"
+
+msgid ""
+"--remote-tab[-wait][-silent] <files> As --remote but use tab page per file"
+msgstr ""
+"--remote-tab[-wait][-silent] <pliki> tak jak --remote ale u¿ywa jednej "
+"karty na plik"
+
+msgid "--remote-send <keys>\tSend <keys> to a Vim server and exit"
+msgstr "--remote-send <klawisze>\tWyœlij <klawisze> do serwera Vima i zakoñcz"
+
+msgid "--remote-expr <expr>\tEvaluate <expr> in a Vim server and print result"
+msgstr "--remote-expr <wyr>\tWykonaj <wyra¿enie> w serwerze i wypisz wynik"
+
+msgid "--serverlist\t\tList available Vim server names and exit"
+msgstr "--serverlist\t\tWymieñ nazwy dostêpnych serwerów Vima i zakoñcz"
+
+msgid "--servername <name>\tSend to/become the Vim server <name>"
+msgstr "--servername <nazwa>\t\tOdsy³aj do/stañ siê serwerem Vim <nazwa>"
+
+msgid "--startuptime <file>\tWrite startup timing messages to <file>"
+msgstr ""
+"--startuptime <plik> "
+"Zapisz wiadomoœci o d³ugoœci startu do <plik>"
+
+msgid "-i <viminfo>\t\tUse <viminfo> instead of .viminfo"
+msgstr "-i <viminfo>\t\tU¿ywaj <viminfo> zamiast .viminfo"
+
+msgid "-h or --help\tPrint Help (this message) and exit"
+msgstr "-h lub --help\twyœwietl Pomoc (czyli tê wiadomoœæ) i zakoñcz"
+
+msgid "--version\t\tPrint version information and exit"
+msgstr "--version\t\twyœwietl informacjê o wersji i zakoñcz"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Motif version):\n"
+msgstr ""
+"\n"
+"Argumenty rozpoznawane przez gvim (wersja Motif):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (neXtaw version):\n"
+msgstr ""
+"\n"
+"Argumenty rozpoznawane przez gvim (wersja neXtaw):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Athena version):\n"
+msgstr ""
+"\n"
+"Argumenty rozpoznawane przez gvim (wersja Athena):\n"
+
+msgid "-display <display>\tRun vim on <display>"
+msgstr "-display <display>\tZa³aduj vim na <display>"
+
+msgid "-iconic\t\tStart vim iconified"
+msgstr "-iconic\t\tZacznij Vim jako ikonê"
+
+msgid "-background <color>\tUse <color> for the background (also: -bg)"
+msgstr "-background <kolor>\tU¿ywaj <kolor> dla t³a (równie¿: -bg)"
+
+msgid "-foreground <color>\tUse <color> for normal text (also: -fg)"
+msgstr ""
+"-foreground <kolor>\tU¿ywaj <kolor> dla normalnego tekstu (równie¿: -fg)"
+
+msgid "-font <font>\t\tUse <font> for normal text (also: -fn)"
+msgstr "-font <font>\t\tU¿ywaj <font> dla normalnego tekstu (równie¿: -fn)"
+
+msgid "-boldfont <font>\tUse <font> for bold text"
+msgstr "-boldfont <font>\tU¿ywaj <font> dla wyt³uszczonego tekstu"
+
+msgid "-italicfont <font>\tUse <font> for italic text"
+msgstr "-italicfont <font>\tU¿ywaj <font> dla pochy³ego"
+
+msgid "-geometry <geom>\tUse <geom> for initial geometry (also: -geom)"
+msgstr ""
+"-geometry <geom>\tU¿ywaj <geom> dla pocz¹tkowych rozmiarów (równie¿: -geom)"
+
+msgid "-borderwidth <width>\tUse a border width of <width> (also: -bw)"
+msgstr "-borderwidth <szer>\tU¿yj ramki o gruboœci <szer> (równie¿: -bw)"
+
+msgid "-scrollbarwidth <width> Use a scrollbar width of <width> (also: -sw)"
+msgstr ""
+"-scrollbarwidth <szer> U¿ywaj przewijacza o szerokoœci <szer> (równie¿: -sw)"
+
+msgid "-menuheight <height>\tUse a menu bar height of <height> (also: -mh)"
+msgstr ""
+"-menuheight <height>\tStosuj belkê menu o wysokoœci <height> (równie¿: -mh)"
+
+msgid "-reverse\t\tUse reverse video (also: -rv)"
+msgstr "-reverse\t\tStosuj negatyw kolorów (równie¿: -rv)"
+
+msgid "+reverse\t\tDon't use reverse video (also: +rv)"
+msgstr "+reverse\t\tNie stosuj negatywu kolorów (równie¿: +rv)"
+
+msgid "-xrm <resource>\tSet the specified resource"
+msgstr "-xrm <resource>\tUstaw okreœlony zasób"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (GTK+ version):\n"
+msgstr ""
+"\n"
+"Argumenty rozpoznawane przez gvim (wersja GTK+):\n"
+
+msgid "-display <display>\tRun vim on <display> (also: --display)"
+msgstr "-display <display>\tZastartuj vim na <display> (równie¿: --display)"
+
+msgid "--role <role>\tSet a unique role to identify the main window"
+msgstr "--role <role>\tUstaw unikatow¹ rolê do identyfikacji g³ównego okna"
+
+msgid "--socketid <xid>\tOpen Vim inside another GTK widget"
+msgstr "--socketid <xid>\tOtwórz Vim wewn¹trz innego widgetu GTK"
+
+msgid "--echo-wid\t\tMake gvim echo the Window ID on stdout"
+msgstr "-echo-wid\t\tGvim wypisze Window ID na wyjœcie standardowe"
+
+msgid "-P <parent title>\tOpen Vim inside parent application"
+msgstr "-P <tytu³ rodzica>\tOtwórz Vima wewn¹trz rodzicielskiej aplikacji"
+
+msgid "--windowid <HWND>\tOpen Vim inside another win32 widget"
+msgstr "--windowid <HWND>\tOtwórz Vima wewn¹trz innego elementu win32"
+
+msgid "No display"
+msgstr "Brak display"
+
+#. Failed to send, abort.
+msgid ": Send failed.\n"
+msgstr ": Wys³anie nie powiod³o siê.\n"
+
+#. Let vim start normally.
+msgid ": Send failed. Trying to execute locally\n"
+msgstr ": Wys³anie nie powiod³o siê. Próbujê wykonaæ na miejscu\n"
+
+#, c-format
+msgid "%d of %d edited"
+msgstr "otworzono %d z %d"
+
+msgid "No display: Send expression failed.\n"
+msgstr "Brak terminala: Wys³anie wyra¿enia nie powiod³o siê.\n"
+
+msgid ": Send expression failed.\n"
+msgstr ": Wys³anie wyra¿enia nie powiod³o siê.\n"
+
+msgid "No marks set"
+msgstr "Brak zak³adek"
+
+#, c-format
+msgid "E283: No marks matching \"%s\""
+msgstr "E283: ¯adna zak³adka nie pasuje do \"%s\""
+
+#. Highlight title
+msgid ""
+"\n"
+"mark line col file/text"
+msgstr ""
+"\n"
+"zak³. wiersz kol plik/tekst"
+
+#. Highlight title
+msgid ""
+"\n"
+" jump line col file/text"
+msgstr ""
+"\n"
+" skok wiersz kol plik/tekst"
+
+#. Highlight title
+msgid ""
+"\n"
+"change line col text"
+msgstr ""
+"\n"
+"zmieñ wrsz. kol tekst"
+
+msgid ""
+"\n"
+"# File marks:\n"
+msgstr ""
+"\n"
+"# Zak³adki w plikach:\n"
+
+#. Write the jumplist with -'
+msgid ""
+"\n"
+"# Jumplist (newest first):\n"
+msgstr ""
+"\n"
+"# Lista odniesieñ (pocz¹wszy od najnowszych):\n"
+
+msgid ""
+"\n"
+"# History of marks within files (newest to oldest):\n"
+msgstr ""
+"\n"
+"# Historia zak³adek w plikach (od najnowszych po najstarsze):\n"
+
+msgid "Missing '>'"
+msgstr "Brak '>'"
+
+msgid "E543: Not a valid codepage"
+msgstr "E543: To nie jest wa¿na strona kodowa"
+
+msgid "E284: Cannot set IC values"
+msgstr "E284: Nie mogê nastawiæ wartoœci IC"
+
+msgid "E285: Failed to create input context"
+msgstr "E285: Nie mog³em stworzyæ kontekstu wprowadzeñ"
+
+msgid "E286: Failed to open input method"
+msgstr "E286: Nie mog³em otworzyæ sposobu wprowadzeñ"
+
+msgid "E287: Warning: Could not set destroy callback to IM"
+msgstr "E287: OSTRZE¯ENIE: Nie mog³em zlikwidowaæ wywo³ania dla IM"
+
+msgid "E288: input method doesn't support any style"
+msgstr "E288: metoda wprowadzeñ nie wspomaga ¿adnego stylu"
+
+msgid "E289: input method doesn't support my preedit type"
+msgstr "E289: metoda wprowadzeñ nie wspomaga mojego typu preedit"
+
+msgid "E293: block was not locked"
+msgstr "E293: blok nie by³ zablokowany"
+
+msgid "E294: Seek error in swap file read"
+msgstr "E294: B³¹d w trakcie czytania pliku wymiany"
+
+msgid "E295: Read error in swap file"
+msgstr "E295: B³¹d odczytu pliku wymiany"
+
+msgid "E296: Seek error in swap file write"
+msgstr "E296: B³¹d szukania w pliku wymiany"
+
+msgid "E297: Write error in swap file"
+msgstr "E297: B³¹d zapisu w pliku wymiany"
+
+msgid "E300: Swap file already exists (symlink attack?)"
+msgstr "E300: Plik wymiany ju¿ istnieje (atak symlink?)"
+
+msgid "E298: Didn't get block nr 0?"
+msgstr "E298: Nie otrzyma³em bloku nr 0?"
+
+msgid "E298: Didn't get block nr 1?"
+msgstr "E298: Nie otrzyma³em bloku nr 1?"
+
+msgid "E298: Didn't get block nr 2?"
+msgstr "E298: Nie otrzyma³em bloku nr 2?"
+
+msgid "E843: Error while updating swap file crypt"
+msgstr "E843: B³¹d w czasie uaktualniania szyfrowania pliku wymiany"
+
+#. could not (re)open the swap file, what can we do????
+msgid "E301: Oops, lost the swap file!!!"
+msgstr "E301: Ojej, zgubi³em plik wymiany!!!"
+
+msgid "E302: Could not rename swap file"
+msgstr "E302: Nie mog³em zmieniæ nazwy pliku wymiany"
+
+#, c-format
+msgid "E303: Unable to open swap file for \"%s\", recovery impossible"
+msgstr ""
+"E303: Nie mogê otworzyæ pliku wymiany dla \"%s\"; odtworzenie niemo¿liwe"
+
+msgid "E304: ml_upd_block0(): Didn't get block 0??"
+msgstr "E304: ml_upd_block(): Nie otrzyma³em bloku 0??"
+
+#, c-format
+msgid "E305: No swap file found for %s"
+msgstr "E305: Nie znaleziono pliku wymiany dla %s"
+
+msgid "Enter number of swap file to use (0 to quit): "
+msgstr "WprowadŸ numer pliku wymiany, którego u¿yæ (0 by wyjœæ): "
+
+#, c-format
+msgid "E306: Cannot open %s"
+msgstr "E306: Nie mogê otworzyæ %s"
+
+msgid "Unable to read block 0 from "
+msgstr "Nie mogê odczytaæ bloku 0 z "
+
+msgid ""
+"\n"
+"Maybe no changes were made or Vim did not update the swap file."
+msgstr ""
+"\n"
+"Mo¿e nie wykonano zmian albo Vim nie zaktualizowa³ pliku wymiany."
+
+msgid " cannot be used with this version of Vim.\n"
+msgstr " nie mo¿e byæ stosowany z t¹ wersj¹ Vima.\n"
+
+msgid "Use Vim version 3.0.\n"
+msgstr "U¿yj Vima w wersji 3.0.\n"
+
+#, c-format
+msgid "E307: %s does not look like a Vim swap file"
+msgstr "E307: %s nie wygl¹da na plik wymiany Vima"
+
+msgid " cannot be used on this computer.\n"
+msgstr " nie mo¿e byæ stosowany na tym komputerze.\n"
+
+msgid "The file was created on "
+msgstr "Ten plik zosta³ stworzony na "
+
+msgid ""
+",\n"
+"or the file has been damaged."
+msgstr ""
+",\n"
+"lub plik zosta³ uszkodzony."
+
+#, c-format
+msgid ""
+"E833: %s is encrypted and this version of Vim does not support encryption"
+msgstr "E833: %s jest zaszyfrowany a ta wersja Vima nie wspiera szyfrowania"
+
+msgid " has been damaged (page size is smaller than minimum value).\n"
+msgstr ""
+" zosta³ uszkodzony (wielkoœæ strony jest mniejsza ni¿ najmniejsza wartoœæ).\n"
+
+#, c-format
+msgid "Using swap file \"%s\""
+msgstr "U¿ywam pliku wymiany \"%s\""
+
+#, c-format
+msgid "Original file \"%s\""
+msgstr "Oryginalny plik \"%s\""
+
+msgid "E308: Warning: Original file may have been changed"
+msgstr "E308: OSTRZE¯ENIE: Oryginalny plik móg³ byæ zmieniony"
+
+#, c-format
+msgid "Swap file is encrypted: \"%s\""
+msgstr "Zaszyfrowany plik wymiany: \"%s\""
+
+msgid ""
+"\n"
+"If you entered a new crypt key but did not write the text file,"
+msgstr ""
+"\n"
+"Jeœli podano nowy klucz szyfruj¹cy, ale nie zapisano pliku tekstowego,"
+
+msgid ""
+"\n"
+"enter the new crypt key."
+msgstr ""
+"\n"
+"wprowadŸ nowy klucz szyfruj¹cy."
+
+msgid ""
+"\n"
+"If you wrote the text file after changing the crypt key press enter"
+msgstr ""
+"\n"
+"Jeœli zapisano plik tekstowy po zmianie klucza szyfruj¹cego wciœnij Enter"
+
+msgid ""
+"\n"
+"to use the same key for text file and swap file"
+msgstr ""
+"\n"
+"aby u¿yæ tego samego klucza dla pliku tekstowego i wymiany"
+
+#, c-format
+msgid "E309: Unable to read block 1 from %s"
+msgstr "E309: Nie mogê odczytaæ bloku 1 z %s"
+
+msgid "???MANY LINES MISSING"
+msgstr "???BRAKUJE WIELU WIERSZY"
+
+msgid "???LINE COUNT WRONG"
+msgstr "???LICZNIK WIERSZY NIEZGODNY"
+
+msgid "???EMPTY BLOCK"
+msgstr "???PUSTY BLOK"
+
+msgid "???LINES MISSING"
+msgstr "???BRAKUJE WIERSZY"
+
+#, c-format
+msgid "E310: Block 1 ID wrong (%s not a .swp file?)"
+msgstr "E310: Niew³aœciwe ID bloku 1 (mo¿e %s nie jest plikiem .swp?)"
+
+msgid "???BLOCK MISSING"
+msgstr "???BRAK BLOKU"
+
+msgid "??? from here until ???END lines may be messed up"
+msgstr "??? od tego miejsca po ???KONIEC wiersze mog¹ byæ pomieszane"
+
+msgid "??? from here until ???END lines may have been inserted/deleted"
+msgstr "??? od tego miejsca po ???KONIEC wiersze mog¹ byæ w³o¿one/skasowane"
+
+msgid "???END"
+msgstr "???KONIEC"
+
+msgid "E311: Recovery Interrupted"
+msgstr "E311: Przerwanie odtwarzania"
+
+msgid ""
+"E312: Errors detected while recovering; look for lines starting with ???"
+msgstr "E312: Wykryto b³êdy podczas odtwarzania; od których wierszy zacz¹æ ???"
+
+msgid "See \":help E312\" for more information."
+msgstr "Zobacz \":help E312\" dla dalszych informacji."
+
+msgid "Recovery completed. You should check if everything is OK."
+msgstr ""
+"Odtwarzanie zakoñczono. Powinieneœ sprawdziæ czy wszystko jest w porz¹dku."
+
+msgid ""
+"\n"
+"(You might want to write out this file under another name\n"
+msgstr ""
+"\n"
+"(Mo¿esz chcieæ zapisaæ ten plik pod inn¹ nazw¹\n"
+
+msgid "and run diff with the original file to check for changes)"
+msgstr "i wykonaæ diff z oryginalnym plikiem aby sprawdziæ zmiany)"
+
+msgid "Recovery completed. Buffer contents equals file contents."
+msgstr "Odzyskiwanie zakoñczone. Zawartoœæ bufora jest równa zawartoœci pliku."
+
+msgid ""
+"\n"
+"You may want to delete the .swp file now.\n"
+"\n"
+msgstr ""
+"\n"
+"Mo¿esz teraz chcieæ usun¹æ plik .swp.\n"
+"\n"
+
+msgid "Using crypt key from swap file for the text file.\n"
+msgstr "U¿ywam klucza szyfruj¹cego z pliku wymiany do pliku tekstowego.\n"
+
+#. use msg() to start the scrolling properly
+msgid "Swap files found:"
+msgstr "Znalezione pliki wymiany:"
+
+msgid " In current directory:\n"
+msgstr " W bie¿¹cym katalogu:\n"
+
+msgid " Using specified name:\n"
+msgstr " U¿ywam podanej nazwy:\n"
+
+msgid " In directory "
+msgstr " W katalogu "
+
+msgid " -- none --\n"
+msgstr " -- ¿aden --\n"
+
+msgid " owned by: "
+msgstr " posiadany przez: "
+
+msgid " dated: "
+msgstr " data: "
+
+msgid " dated: "
+msgstr " data: "
+
+msgid " [from Vim version 3.0]"
+msgstr " [po Vimie wersja 3.0]"
+
+msgid " [does not look like a Vim swap file]"
+msgstr " [nie wygl¹da na plik wymiany Vima]"
+
+msgid " file name: "
+msgstr " nazwa pliku: "
+
+msgid ""
+"\n"
+" modified: "
+msgstr ""
+"\n"
+" zmieniono: "
+
+msgid "YES"
+msgstr "TAK"
+
+msgid "no"
+msgstr "nie"
+
+msgid ""
+"\n"
+" user name: "
+msgstr ""
+"\n"
+" u¿ytkownik: "
+
+msgid " host name: "
+msgstr " nazwa hosta: "
+
+msgid ""
+"\n"
+" host name: "
+msgstr ""
+"\n"
+" nazwa hosta: "
+
+msgid ""
+"\n"
+" process ID: "
+msgstr ""
+"\n"
+" ID procesu: "
+
+msgid " (still running)"
+msgstr " (dalej dzia³a)"
+
+msgid ""
+"\n"
+" [not usable with this version of Vim]"
+msgstr ""
+"\n"
+" [nie nadaje siê dla tej wersji Vima]"
+
+msgid ""
+"\n"
+" [not usable on this computer]"
+msgstr ""
+"\n"
+" [nie do u¿ytku na tym komputerze]"
+
+msgid " [cannot be read]"
+msgstr " [nieodczytywalny]"
+
+msgid " [cannot be opened]"
+msgstr " [nieotwieralny]"
+
+msgid "E313: Cannot preserve, there is no swap file"
+msgstr "E313: Nie mogê zabezpieczyæ, bo brak pliku wymiany"
+
+msgid "File preserved"
+msgstr "Plik zabezpieczono"
+
+msgid "E314: Preserve failed"
+msgstr "E314: Nieudane zabezpieczenie"
+
+#, c-format
+msgid "E315: ml_get: invalid lnum: %ld"
+msgstr "E315: ml_get: niew³aœciwy lnum: %ld"
+
+#, c-format
+msgid "E316: ml_get: cannot find line %ld"
+msgstr "E316: ml_get: nie znaleziono wiersza %ld"
+
+msgid "E317: pointer block id wrong 3"
+msgstr "E317: niepoprawne id wskaŸnika bloku 3"
+
+msgid "stack_idx should be 0"
+msgstr "stack_idx powinien byæ 0"
+
+msgid "E318: Updated too many blocks?"
+msgstr "E318: Zaktualizowano zbyt wiele bloków?"
+
+msgid "E317: pointer block id wrong 4"
+msgstr "E317: niepoprawne id wskaŸnika bloku 4"
+
+msgid "deleted block 1?"
+msgstr "blok nr 1 skasowany?"
+
+#, c-format
+msgid "E320: Cannot find line %ld"
+msgstr "E320: Nie mogê znaleŸæ wiersza %ld"
+
+msgid "E317: pointer block id wrong"
+msgstr "E317: niepoprawne id bloku odniesienia"
+
+msgid "pe_line_count is zero"
+msgstr "pe_line_count wynosi zero"
+
+#, c-format
+msgid "E322: line number out of range: %ld past the end"
+msgstr "E322: numer wiersza poza zakresem: %ld jest poza koñcem"
+
+#, c-format
+msgid "E323: line count wrong in block %ld"
+msgstr "E323: liczba wierszy niepoprawna w bloku %ld"
+
+msgid "Stack size increases"
+msgstr "WielkoϾ stosu wzrasta"
+
+msgid "E317: pointer block id wrong 2"
+msgstr "E317: niepoprawne id bloku odniesienia 2"
+
+#, c-format
+msgid "E773: Symlink loop for \"%s\""
+msgstr "E773: Pêtla dowi¹zañ dla \"%s\""
+
+msgid "E325: ATTENTION"
+msgstr "E325: UWAGA"
+
+msgid ""
+"\n"
+"Found a swap file by the name \""
+msgstr ""
+"\n"
+"Znalaz³em plik wymiany o nazwie \""
+
+msgid "While opening file \""
+msgstr "Podczas otwierania pliku \""
+
+msgid " NEWER than swap file!\n"
+msgstr " NOWSZE od pliku wymiany!\n"
+
+#. Some of these messages are long to allow translation to
+#. * other languages.
+msgid ""
+"\n"
+"(1) Another program may be editing the same file. If this is the case,\n"
+" be careful not to end up with two different instances of the same\n"
+" file when making changes.\n"
+msgstr ""
+"\n"
+"(1) Pewnie inny program obrabia ten sam plik.\n"
+" Jeœli tak, b¹dŸ ostro¿ny, aby nie skoñczyæ z dwoma\n"
+" ró¿nymi wersjami tego samego pliku po zmianach.\n"
+
+msgid " Quit, or continue with caution.\n"
+msgstr " Zakoñcz lub ostro¿nie kontynuuj.\n"
+
+msgid "(2) An edit session for this file crashed.\n"
+msgstr "(2) Sesja edycji dla pliku za³ama³a siê.\n"
+
+msgid " If this is the case, use \":recover\" or \"vim -r "
+msgstr " Jeœli tak, to u¿yj \":recover\" lub \"vim -r "
+
+msgid ""
+"\"\n"
+" to recover the changes (see \":help recovery\").\n"
+msgstr ""
+"\"\n"
+" aby odzyskaæ zmiany (zobacz \":help recovery)\").\n"
+
+msgid " If you did this already, delete the swap file \""
+msgstr " Jeœli ju¿ to zrobi³eœ, usuñ plik wymiany \""
+
+msgid ""
+"\"\n"
+" to avoid this message.\n"
+msgstr ""
+"\"\n"
+" aby unikn¹æ tej wiadomoœci.\n"
+
+msgid "Swap file \""
+msgstr "Plik wymiany \""
+
+msgid "\" already exists!"
+msgstr "\" ju¿ istnieje!"
+
+msgid "VIM - ATTENTION"
+msgstr "VIM - UWAGA"
+
+msgid "Swap file already exists!"
+msgstr "Plik wymiany ju¿ istnieje!"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"&Otwórz Read-Only\n"
+"&Edytuj pomimo\n"
+"O&dtwórz\n"
+"&Zakoñcz\n"
+"&Porzuæ"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Delete it\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"&Otwórz Read-Only\n"
+"&Edytuj pomimo\n"
+"O&dtwórz\n"
+"&Usuñ\n"
+"&Zakoñcz\n"
+"&Porzuæ"
+
+msgid "E326: Too many swap files found"
+msgstr "E326: Znaleziono zbyt wiele plików wymiany"
+
+msgid "E327: Part of menu-item path is not sub-menu"
+msgstr "E327: Czêœæ tropu punktu menu nie okreœla podmenu"
+
+msgid "E328: Menu only exists in another mode"
+msgstr "E328: Menu istnieje tylko w innym trybie"
+
+#, c-format
+msgid "E329: No menu \"%s\""
+msgstr "E329: Nie ma menu \"%s\""
+
+#. Only a mnemonic or accelerator is not valid.
+msgid "E792: Empty menu name"
+msgstr "E792: Pusta nazwa menu"
+
+msgid "E330: Menu path must not lead to a sub-menu"
+msgstr "E330: Trop menu nie mo¿e prowadziæ do podmenu"
+
+msgid "E331: Must not add menu items directly to menu bar"
+msgstr "E331: Nie wolno dodawaæ punktów menu wprost do paska menu"
+
+msgid "E332: Separator cannot be part of a menu path"
+msgstr "E332: Separator nie mo¿e byæ czêœci¹ tropu menu"
+
+#. Now we have found the matching menu, and we list the mappings
+#. Highlight title
+msgid ""
+"\n"
+"--- Menus ---"
+msgstr ""
+"\n"
+"--- Menu ---"
+
+msgid "Tear off this menu"
+msgstr "Oderwij to menu"
+
+msgid "E333: Menu path must lead to a menu item"
+msgstr "E333: Trop menu musi prowadziæ do punktu menu"
+
+#, c-format
+msgid "E334: Menu not found: %s"
+msgstr "E334: Nie znaleziono menu: %s"
+
+#, c-format
+msgid "E335: Menu not defined for %s mode"
+msgstr "E335: Menu nie jest zdefiniowane dla trybu %s"
+
+msgid "E336: Menu path must lead to a sub-menu"
+msgstr "E336: Trop menu musi prowadziæ do podmenu"
+
+msgid "E337: Menu not found - check menu names"
+msgstr "E337: Nie znaleziono menu - sprawdŸ nazwy menu"
+
+#, c-format
+msgid "Error detected while processing %s:"
+msgstr "Wykryto b³¹d podczas przetwarzania %s:"
+
+#, c-format
+msgid "line %4ld:"
+msgstr "wiersz %4ld:"
+
+#, c-format
+msgid "E354: Invalid register name: '%s'"
+msgstr "E354: Niew³aœciwa nazwa rejestru: '%s'"
+
+msgid "Messages maintainer: Bram Moolenaar <Bram@vim.org>"
+msgstr "Opiekun komunikatów: Miko³aj Machowski <mikmach@wp.pl>"
+
+msgid "Interrupt: "
+msgstr "Przerwanie: "
+
+msgid "Press ENTER or type command to continue"
+msgstr "Naciœnij ENTER lub wprowadŸ komendê aby kontynuowaæ"
+
+#, c-format
+msgid "%s line %ld"
+msgstr "%s wiersz %ld"
+
+msgid "-- More --"
+msgstr "-- Wiêcej --"
+
+msgid " SPACE/d/j: screen/page/line down, b/u/k: up, q: quit "
+msgstr " SPACE/d/j: ekran/strona/wiersz w dó³, b/u/k: do góry, q: zakoñcz"
+
+msgid "Question"
+msgstr "Pytanie"
+
+msgid ""
+"&Yes\n"
+"&No"
+msgstr ""
+"&Tak\n"
+"&Nie"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"Save &All\n"
+"&Discard All\n"
+"&Cancel"
+msgstr ""
+"&Tak\n"
+"&Nie\n"
+"Zapisz &wszystkie\n"
+"&Odrzuæ wszystkie\n"
+"&Zakoñcz"
+
+msgid "Select Directory dialog"
+msgstr "Dialog wyboru katalogu"
+
+msgid "Save File dialog"
+msgstr "Dialog zapisywania pliku"
+
+msgid "Open File dialog"
+msgstr "Dialog otwierania pliku"
+
+#. TODO: non-GUI file selector here
+msgid "E338: Sorry, no file browser in console mode"
+msgstr "E338: Przykro mi, nie ma przegl¹darki plików w trybie konsoli"
+
+msgid "E766: Insufficient arguments for printf()"
+msgstr "E766: Za ma³o argumentów dla printf()"
+
+msgid "E807: Expected Float argument for printf()"
+msgstr "E807: Spodziewany argument Zmiennoprzecinkowy w printf()"
+
+msgid "E767: Too many arguments to printf()"
+msgstr "E767: Za du¿o argumentów dla printf()"
+
+msgid "W10: Warning: Changing a readonly file"
+msgstr "W10: OSTRZE¯ENIE: Zmiany w pliku tylko do odczytu"
+
+msgid "Type number and <Enter> or click with mouse (empty cancels): "
+msgstr "Wpisz numer i <Enter> lub wybierz mysz¹ (pusta wartoœæ anuluje): "
+
+msgid "Type number and <Enter> (empty cancels): "
+msgstr "Wpisz numer i <Enter> (puste anuluje): "
+
+msgid "1 more line"
+msgstr "1 wiersz wiêcej"
+
+msgid "1 line less"
+msgstr "1 wiersz mniej"
+
+#, c-format
+msgid "%ld more lines"
+msgstr "dodano %ld wierszy"
+
+#, c-format
+msgid "%ld fewer lines"
+msgstr "usuniêto %ld wierszy"
+
+msgid " (Interrupted)"
+msgstr " (Przerwane)"
+
+msgid "Beep!"
+msgstr "Biiip!"
+
+msgid "Vim: preserving files...\n"
+msgstr "Vim: zachowujê plik...\n"
+
+#. close all memfiles, without deleting
+msgid "Vim: Finished.\n"
+msgstr "Vim: Zakoñczono.\n"
+
+msgid "ERROR: "
+msgstr "B£¥D: "
+
+#, c-format
+msgid ""
+"\n"
+"[bytes] total alloc-freed %lu-%lu, in use %lu, peak use %lu\n"
+msgstr ""
+"\n"
+"[bajtów] totalne alokacje-zwolnienia %lu-%lu, w u¿ytku %lu, maksymalne "
+"u¿ycie %lu\n"
+
+#, c-format
+msgid ""
+"[calls] total re/malloc()'s %lu, total free()'s %lu\n"
+"\n"
+msgstr ""
+"[wywo³ania] wszystkich re/malloc()-ów %lu, wszystkich free()-ów %lu\n"
+"\n"
+
+msgid "E340: Line is becoming too long"
+msgstr "E340: Wiersz staje siê zbyt d³ugi"
+
+#, c-format
+msgid "E341: Internal error: lalloc(%ld, )"
+msgstr "E341: Wewnêtrzny b³¹d: lalloc(%ld, )"
+
+#, c-format
+msgid "E342: Out of memory! (allocating %lu bytes)"
+msgstr "E342: Brak pamiêci! (rezerwacja %lu bajtów)"
+
+#, c-format
+msgid "Calling shell to execute: \"%s\""
+msgstr "Wywo³ujê pow³okê do wykonania: \"%s\""
+
+msgid "E545: Missing colon"
+msgstr "E545: Brak dwukropka"
+
+msgid "E546: Illegal mode"
+msgstr "E546: Niedozwolony tryb"
+
+msgid "E547: Illegal mouseshape"
+msgstr "E547: Niedozwolony obrys myszki"
+
+msgid "E548: digit expected"
+msgstr "E548: oczekiwa³em na cyfrê"
+
+msgid "E549: Illegal percentage"
+msgstr "E549: Niedozwolony procent"
+
+msgid "Enter encryption key: "
+msgstr "WprowadŸ klucz do odkodowania: "
+
+msgid "Enter same key again: "
+msgstr "WprowadŸ ponownie ten sam klucz: "
+
+msgid "Keys don't match!"
+msgstr "Klucze nie pasuj¹ do siebie!"
+
+msgid "E854: path too long for completion"
+msgstr "E854: œcie¿ka za d³uga by uzupe³niæ"
+
+#, c-format
+msgid ""
+"E343: Invalid path: '**[number]' must be at the end of the path or be "
+"followed by '%s'."
+msgstr ""
+"E343: Niew³aœciwy trop: '**[numer]' musi byæ na koñcu tropu lub po nim musi "
+"byæ '%s'."
+
+#, c-format
+msgid "E344: Can't find directory \"%s\" in cdpath"
+msgstr "E344: Nie mogê znaleŸæ katalogu \"%s\" w cdpath"
+
+#, c-format
+msgid "E345: Can't find file \"%s\" in path"
+msgstr "E345: Nie mogê znaleŸæ pliku \"%s\" w tropie"
+
+#, c-format
+msgid "E346: No more directory \"%s\" found in cdpath"
+msgstr "E346: Katalogu \"%s\" nie ma wiêcej w cdpath"
+
+#, c-format
+msgid "E347: No more file \"%s\" found in path"
+msgstr "E347: Pliku \"%s\" nie ma wiêcej w tropie"
+
+msgid "Cannot connect to Netbeans #2"
+msgstr "Nie mo¿na po³¹czyæ z Netbeans #2"
+
+msgid "Cannot connect to Netbeans"
+msgstr "Nie mo¿na po³¹czyæ z Netbeans"
+
+#, c-format
+msgid "E668: Wrong access mode for NetBeans connection info file: \"%s\""
+msgstr "E668: B³êdny tryb dostêpu pliku info po³¹czenia NetBeans: \"%s\""
+
+msgid "read from Netbeans socket"
+msgstr "odczyt z gniazda Netbeans"
+
+#, c-format
+msgid "E658: NetBeans connection lost for buffer %ld"
+msgstr "E658: Bufor %ld utraci³ po³¹czenie z NetBeans"
+
+msgid "E838: netbeans is not supported with this GUI"
+msgstr "E838: netbeans nie s¹ obs³ugiwane przez to GUI"
+
+msgid "E511: netbeans already connected"
+msgstr "E511: netbeans ju¿ pod³¹czone"
+
+#, c-format
+msgid "E505: %s is read-only (add ! to override)"
+msgstr "E505: %s jest tylko do odczytu (dodaj ! aby wymusiæ)"
+
+msgid "E349: No identifier under cursor"
+msgstr "E349: Brak identyfikatora pod kursorem"
+
+msgid "E774: 'operatorfunc' is empty"
+msgstr "E774: 'operatorfunc' jest pusta"
+
+msgid "E775: Eval feature not available"
+msgstr "E775: Funkcjonalnoœæ eval nie jest dostêpna"
+
+msgid "Warning: terminal cannot highlight"
+msgstr "OSTRZE¯ENIE: terminal nie wykonuje podœwietlania"
+
+msgid "E348: No string under cursor"
+msgstr "E348: Brak ci¹gu pod kursorem"
+
+msgid "E352: Cannot erase folds with current 'foldmethod'"
+msgstr "E352: Nie mogê skasowaæ zwiniêcia z bie¿¹c¹ 'foldmethod'"
+
+msgid "E664: changelist is empty"
+msgstr "E664: lista zmian (changelist) jest pusta"
+
+msgid "E662: At start of changelist"
+msgstr "E662: Na pocz¹tku listy zmian"
+
+msgid "E663: At end of changelist"
+msgstr "E663: Na koñcu listy zmian"
+
+msgid "Type :quit<Enter> to exit Vim"
+msgstr "wprowadŸ :quit<Enter> zakoñczenie programu"
+
+#, c-format
+msgid "1 line %sed 1 time"
+msgstr "1 wiersz %sed 1 raz"
+
+#, c-format
+msgid "1 line %sed %d times"
+msgstr "1 wiersz %sed %d razy"
+
+#, c-format
+msgid "%ld lines %sed 1 time"
+msgstr "%ld wierszy %sed 1 raz"
+
+#, c-format
+msgid "%ld lines %sed %d times"
+msgstr "%ld wierszy %sed %d razy"
+
+#, c-format
+msgid "%ld lines to indent... "
+msgstr "%ld wierszy do wciêcia... "
+
+msgid "1 line indented "
+msgstr "1 wiersz wciêty "
+
+#, c-format
+msgid "%ld lines indented "
+msgstr "%ld wierszy wciêtych "
+
+msgid "E748: No previously used register"
+msgstr "E748: Brak poprzednio u¿ytego rejestru"
+
+#. must display the prompt
+msgid "cannot yank; delete anyway"
+msgstr "nie mogê skopiowaæ, mimo to kasujê"
+
+msgid "1 line changed"
+msgstr "1 wiersz zmieniono"
+
+#, c-format
+msgid "%ld lines changed"
+msgstr "%ld wierszy zmieniono"
+
+#, c-format
+msgid "freeing %ld lines"
+msgstr "zwalniam %ld wierszy"
+
+msgid "block of 1 line yanked"
+msgstr "skopiowano blok 1 wiersza"
+
+msgid "1 line yanked"
+msgstr "1 wiersz skopiowano"
+
+#, c-format
+msgid "block of %ld lines yanked"
+msgstr "%ld wierszy skopiowanych"
+
+#, c-format
+msgid "%ld lines yanked"
+msgstr "%ld wierszy skopiowanych"
+
+#, c-format
+msgid "E353: Nothing in register %s"
+msgstr "E353: Pusty rejestr %s"
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Registers ---"
+msgstr ""
+"\n"
+"--- Rejestry ---"
+
+msgid "Illegal register name"
+msgstr "Niedozwolona nazwa rejestru"
+
+msgid ""
+"\n"
+"# Registers:\n"
+msgstr ""
+"\n"
+"# Rejestry:\n"
+
+#, c-format
+msgid "E574: Unknown register type %d"
+msgstr "E574: Nieznany typ rejestru %d"
+
+#, c-format
+msgid "%ld Cols; "
+msgstr "%ld Kolumn; "
+
+#, c-format
+msgid "Selected %s%ld of %ld Lines; %ld of %ld Words; %ld of %ld Bytes"
+msgstr "Wybrano %s%ld z %ld Wierszy; %ld z %ld S³ów; %ld z %ld Bajtów"
+
+#, c-format
+msgid ""
+"Selected %s%ld of %ld Lines; %ld of %ld Words; %ld of %ld Chars; %ld of %ld "
+"Bytes"
+msgstr ""
+"Wybrano %s%ld z %ld Wierszy; %ld z %ld S³ów; %ld z %ld Znaków; %ld z %ld "
+"Bajtów"
+
+#, c-format
+msgid "Col %s of %s; Line %ld of %ld; Word %ld of %ld; Byte %ld of %ld"
+msgstr "Kol %s z %s; Wiersz %ld z %ld; S³owo %ld z %ld; Bajt %ld z %ld"
+
+#, c-format
+msgid ""
+"Col %s of %s; Line %ld of %ld; Word %ld of %ld; Char %ld of %ld; Byte %ld of "
+"%ld"
+msgstr ""
+"Kol %s z %s; Wiersz %ld z %ld; S³owo %ld z %ld; Znak %ld z %ld; Bajt %ld z "
+"%ld"
+
+#, c-format
+msgid "(+%ld for BOM)"
+msgstr "(+%ld dla BOM)"
+
+msgid "%<%f%h%m%=Page %N"
+msgstr "%<%f%h%m%=Strona %N"
+
+msgid "Thanks for flying Vim"
+msgstr "Dziêki za lot Vimem"
+
+msgid "E518: Unknown option"
+msgstr "E518: Nieznana opcja"
+
+msgid "E519: Option not supported"
+msgstr "E519: Opcja nie jest wspomagana"
+
+msgid "E520: Not allowed in a modeline"
+msgstr "E520: Niedozwolone w modeline"
+
+msgid "E846: Key code not set"
+msgstr "E846: Kod klucza nie jest ustawiony"
+
+msgid "E521: Number required after ="
+msgstr "E521: Po = wymagany jest numer"
+
+msgid "E522: Not found in termcap"
+msgstr "E522: Nie znaleziono w termcap"
+
+#, c-format
+msgid "E539: Illegal character <%s>"
+msgstr "E539: Niedozwolony znak <%s>"
+
+msgid "E529: Cannot set 'term' to empty string"
+msgstr "E529: Nie mogê ustawiæ 'term' na pusty ci¹g"
+
+msgid "E530: Cannot change term in GUI"
+msgstr "E530: Nie mogê zmieniæ term w GUI"
+
+msgid "E531: Use \":gui\" to start the GUI"
+msgstr "E531: U¿yj \":gui\" do odpalenia GUI"
+
+msgid "E589: 'backupext' and 'patchmode' are equal"
+msgstr "E589: 'backupext' i 'patchmode' s¹ to¿same"
+
+msgid "E834: Conflicts with value of 'listchars'"
+msgstr "E834: Konflikty wartoœci 'listchars'"
+
+msgid "E835: Conflicts with value of 'fillchars'"
+msgstr "E835: Konflikty wartoœci 'fillchars'"
+
+msgid "E617: Cannot be changed in the GTK+ 2 GUI"
+msgstr "E617: Nie mogê zmieniæ w GTK+2 GUI"
+
+msgid "E524: Missing colon"
+msgstr "E524: Brak dwukropka"
+
+msgid "E525: Zero length string"
+msgstr "E525: Ci¹g o zerowej d³ugoœci"
+
+#, c-format
+msgid "E526: Missing number after <%s>"
+msgstr "E526: Brak numeru po <%s>"
+
+msgid "E527: Missing comma"
+msgstr "E527: Brak przecinka"
+
+msgid "E528: Must specify a ' value"
+msgstr "E528: Musi okreœlaæ wartoœæ '"
+
+msgid "E595: contains unprintable or wide character"
+msgstr "E595: zawiera niewyœwietlalny lub szeroki znak"
+
+msgid "E596: Invalid font(s)"
+msgstr "E596: Niedozwolona czcionka/ki"
+
+msgid "E597: can't select fontset"
+msgstr "E597: nie mogê wybraæ zestawu czcionek"
+
+msgid "E598: Invalid fontset"
+msgstr "E598: Niedozwolony zestaw czcionek"
+
+msgid "E533: can't select wide font"
+msgstr "E533: nie mogê wybraæ szerokiej czcionki"
+
+msgid "E534: Invalid wide font"
+msgstr "E534: Niedozwolona szeroka czcionka"
+
+#, c-format
+msgid "E535: Illegal character after <%c>"
+msgstr "E535: Niedozwolony znak po <%c>"
+
+msgid "E536: comma required"
+msgstr "E536: wymagany przecinek"
+
+#, c-format
+msgid "E537: 'commentstring' must be empty or contain %s"
+msgstr "E537: 'commentstring' musi byæ pusty lub zawieraæ %s"
+
+msgid "E538: No mouse support"
+msgstr "E538: Brak wspomagania myszki"
+
+msgid "E540: Unclosed expression sequence"
+msgstr "E540: Niedomkniêty ci¹g wyra¿eñ"
+
+msgid "E541: too many items"
+msgstr "E541: zbyt wiele elementów"
+
+msgid "E542: unbalanced groups"
+msgstr "E542: niezbalansowane grupy"
+
+msgid "E590: A preview window already exists"
+msgstr "E590: okno podgl¹du ju¿ istnieje"
+
+msgid "W17: Arabic requires UTF-8, do ':set encoding=utf-8'"
+msgstr "W17: Arabski wymaga UTF-8, zrób ':set encoding=utf-8'"
+
+#, c-format
+msgid "E593: Need at least %d lines"
+msgstr "E593: Potrzebujê przynajmniej %d wierszy"
+
+#, c-format
+msgid "E594: Need at least %d columns"
+msgstr "E594: Potrzebujê przynajmniej %d kolumn"
+
+#, c-format
+msgid "E355: Unknown option: %s"
+msgstr "E355: Nieznana opcja: %s"
+
+#. There's another character after zeros or the string
+#. * is empty. In both cases, we are trying to set a
+#. * num option using a string.
+#, c-format
+msgid "E521: Number required: &%s = '%s'"
+msgstr "E521: Wymagana Liczba: &%s = '%s'"
+
+msgid ""
+"\n"
+"--- Terminal codes ---"
+msgstr ""
+"\n"
+"--- Kody terminala ---"
+
+msgid ""
+"\n"
+"--- Global option values ---"
+msgstr ""
+"\n"
+"--- Globalne wartoœci opcji ---"
+
+msgid ""
+"\n"
+"--- Local option values ---"
+msgstr ""
+"\n"
+"--- Lokalne wartoœci opcji ---"
+
+msgid ""
+"\n"
+"--- Options ---"
+msgstr ""
+"\n"
+"--- Opcje ---"
+
+msgid "E356: get_varp ERROR"
+msgstr "E356: B£¥D get_varp"
+
+#, c-format
+msgid "E357: 'langmap': Matching character missing for %s"
+msgstr "E357: 'langmap': Brak pasuj¹cego znaku dla %s"
+
+#, c-format
+msgid "E358: 'langmap': Extra characters after semicolon: %s"
+msgstr "E358: 'langmap': Dodatkowe znaki po œredniku: %s"
+
+msgid "cannot open "
+msgstr "nie mogê otworzyæ "
+
+msgid "VIM: Can't open window!\n"
+msgstr "VIM: Nie mogê otworzyæ okna!\n"
+
+msgid "Need Amigados version 2.04 or later\n"
+msgstr "Potrzebujê Amigados w wersji 2.04 lub póŸniejsz¹\n"
+
+#, c-format
+msgid "Need %s version %ld\n"
+msgstr "Potrzebujê %s w wersji %ld\n"
+
+msgid "Cannot open NIL:\n"
+msgstr "Nie mogê otworzyæ NIL:\n"
+
+msgid "Cannot create "
+msgstr "Nie mogê stworzyæ "
+
+#, c-format
+msgid "Vim exiting with %d\n"
+msgstr "Vim koñczy pracê z %d\n"
+
+msgid "cannot change console mode ?!\n"
+msgstr "nie mogê zmieniæ trybu konsoli ?!\n"
+
+msgid "mch_get_shellsize: not a console??\n"
+msgstr "mch_get_shellsize: nie jest konsol¹??\n"
+
+#. if Vim opened a window: Executing a shell may cause crashes
+msgid "E360: Cannot execute shell with -f option"
+msgstr "E360: Nie mogê wykonaæ pow³oki z opcj¹ -f"
+
+msgid "Cannot execute "
+msgstr "Nie mogê wykonaæ "
+
+msgid "shell "
+msgstr "pow³oka "
+
+msgid " returned\n"
+msgstr " zwróci³\n"
+
+msgid "ANCHOR_BUF_SIZE too small."
+msgstr "ANCHOR_BUF_SIZE zbyt niskie."
+
+msgid "I/O ERROR"
+msgstr "B£¥D I/O"
+
+msgid "Message"
+msgstr "WiadomoϾ"
+
+msgid "'columns' is not 80, cannot execute external commands"
+msgstr "'columns' nie wynosi 80, nie mogê wykonaæ zewnêtrznych komend"
+
+msgid "E237: Printer selection failed"
+msgstr "E237: Wybór drukarki nie powiód³ siê"
+
+#, c-format
+msgid "to %s on %s"
+msgstr "do %s z %s"
+
+#, c-format
+msgid "E613: Unknown printer font: %s"
+msgstr "E613: Nieznana czcionka drukarki: %s"
+
+#, c-format
+msgid "E238: Print error: %s"
+msgstr "E238: B³¹d drukarki: %s"
+
+#, c-format
+msgid "Printing '%s'"
+msgstr "Wydrukowano '%s'"
+
+#, c-format
+msgid "E244: Illegal charset name \"%s\" in font name \"%s\""
+msgstr ""
+"E244: Niedozwolona nazwa zestawu znaków \"%s\" w nazwie czcionki \"%s\""
+
+#, c-format
+msgid "E245: Illegal char '%c' in font name \"%s\""
+msgstr "E245: Niedozwolony znak '%c' w nazwie czcionki \"%s\""
+
+msgid "Vim: Double signal, exiting\n"
+msgstr "Vim: Podwójny sygna³, wychodzê\n"
+
+#, c-format
+msgid "Vim: Caught deadly signal %s\n"
+msgstr "Vim: Za³apa³ œmiertelny sygna³ %s\n"
+
+#, c-format
+msgid "Vim: Caught deadly signal\n"
+msgstr "Vim: Za³apa³ œmiertelny sygna³\n"
+
+#, c-format
+msgid "Opening the X display took %ld msec"
+msgstr "Otwieranie ekranu X trwa³o %ld msec"
+
+msgid ""
+"\n"
+"Vim: Got X error\n"
+msgstr ""
+"\n"
+"Vim: Dosta³ b³¹d X\n"
+
+msgid "Testing the X display failed"
+msgstr "Test ekranu X nie powiód³ siê"
+
+msgid "Opening the X display timed out"
+msgstr "Próba otwarcia ekranu X trwa³a zbyt d³ugo"
+
+msgid ""
+"\n"
+"Could not get security context for "
+msgstr ""
+"\n"
+"Nie mogê uzyskaæ kontekstu bezpieczeñstwa dla"
+
+msgid ""
+"\n"
+"Could not set security context for "
+msgstr ""
+"\n"
+"Nie mo¿na uzyskaæ kontekstu bezpieczeñstwa dla"
+
+msgid ""
+"\n"
+"Cannot execute shell "
+msgstr ""
+"\n"
+"Nie mogê wykonaæ pow³oki "
+
+msgid ""
+"\n"
+"Cannot execute shell sh\n"
+msgstr ""
+"\n"
+"Nie mogê wykonaæ pow³oki sh\n"
+
+msgid ""
+"\n"
+"shell returned "
+msgstr ""
+"\n"
+"pow³oka zwróci³a "
+
+msgid ""
+"\n"
+"Cannot create pipes\n"
+msgstr ""
+"\n"
+"Nie mogê stworzyæ potoków\n"
+
+msgid ""
+"\n"
+"Cannot fork\n"
+msgstr ""
+"\n"
+"Nie mogê rozdzieliæ siê\n"
+
+msgid ""
+"\n"
+"Command terminated\n"
+msgstr ""
+"\n"
+"Komenda zakoñczona\n"
+
+msgid "XSMP lost ICE connection"
+msgstr "XSMP straci³ po³¹czenie ICE"
+
+#, c-format
+msgid "dlerror = \"%s\""
+msgstr "dlerror = \"%s\""
+
+msgid "Opening the X display failed"
+msgstr "Otwarcie ekranu X nie powiod³o siê"
+
+msgid "XSMP handling save-yourself request"
+msgstr "XSMP obs³uguje ¿¹danie samozapisu"
+
+msgid "XSMP opening connection"
+msgstr "XSMP otwiera po³¹czenie"
+
+msgid "XSMP ICE connection watch failed"
+msgstr "Obserwacja po³¹czenia XSMP ICE nie powiod³a siê"
+
+#, c-format
+msgid "XSMP SmcOpenConnection failed: %s"
+msgstr "XSMP SmcOpenConnection nie powiod³o siê: %s"
+
+msgid "At line"
+msgstr "W wierszu"
+
+msgid "Could not load vim32.dll!"
+msgstr "Nie mogê za³adowaæ vim32.dll!"
+
+msgid "VIM Error"
+msgstr "B³¹d VIM"
+
+msgid "Could not fix up function pointers to the DLL!"
+msgstr "Nie zdo³a³em poprawiæ wskaŸników funkcji w DLL!"
+
+#, c-format
+msgid "shell returned %d"
+msgstr "pow³oka zwróci³a %d"
+
+#, c-format
+msgid "Vim: Caught %s event\n"
+msgstr "Vim: Za³apa³ wydarzenie %s\n"
+
+msgid "close"
+msgstr "zamknij"
+
+msgid "logoff"
+msgstr "wyloguj"
+
+msgid "shutdown"
+msgstr "zakoñcz"
+
+msgid "E371: Command not found"
+msgstr "E371: Nie znaleziono komendy"
+
+msgid ""
+"VIMRUN.EXE not found in your $PATH.\n"
+"External commands will not pause after completion.\n"
+"See :help win32-vimrun for more information."
+msgstr ""
+"VIMRUN.EXE nie znaleziono w twoim $PATH.\n"
+"Zewnêtrzne komendy nie bêd¹ wstrzymane po wykonaniu.\n"
+"Zobacz :help wim32-vimrun aby otrzymaæ wiêcej informacji."
+
+msgid "Vim Warning"
+msgstr "Vim Ostrze¿enie"
+
+#, c-format
+msgid "E372: Too many %%%c in format string"
+msgstr "E372: Zbyt wiele %%%c w ci¹gu formatuj¹cym"
+
+#, c-format
+msgid "E373: Unexpected %%%c in format string"
+msgstr "E373: Nieoczekiwane %%%c w ci¹gu formatuj¹cym"
+
+msgid "E374: Missing ] in format string"
+msgstr "E374: Brak ] w ci¹gu formatuj¹cym"
+
+#, c-format
+msgid "E375: Unsupported %%%c in format string"
+msgstr "E375: Niewspomagane %%%c w ci¹gu formatuj¹cym"
+
+#, c-format
+msgid "E376: Invalid %%%c in format string prefix"
+msgstr "E376: Niepoprawne %%%c w prefiksie ci¹gu formatuj¹cego"
+
+#, c-format
+msgid "E377: Invalid %%%c in format string"
+msgstr "E377: Niepoprawne %%%c w ci¹gu formatuj¹cym"
+
+msgid "E378: 'errorformat' contains no pattern"
+msgstr "E378: 'errorformat' nie zawiera wzorca"
+
+msgid "E379: Missing or empty directory name"
+msgstr "E379: Pusta nazwa katalogu lub jej brak"
+
+msgid "E553: No more items"
+msgstr "E553: Nie ma wiêcej elementów"
+
+#, c-format
+msgid "(%d of %d)%s%s: "
+msgstr "(%d z %d)%s%s: "
+
+msgid " (line deleted)"
+msgstr " (wiersz skasowany)"
+
+msgid "E380: At bottom of quickfix stack"
+msgstr "E380: Na dole stosu quickfix"
+
+msgid "E381: At top of quickfix stack"
+msgstr "E381: Na górze stosu quickfix"
+
+#, c-format
+msgid "error list %d of %d; %d errors"
+msgstr "lista b³êdów %d z %d; %d b³êdów"
+
+msgid "E382: Cannot write, 'buftype' option is set"
+msgstr "E382: Nie mogê zapisaæ, opcja 'buftype' jest ustawiona"
+
+msgid "Error file"
+msgstr "Plik b³êdu"
+
+msgid "E683: File name missing or invalid pattern"
+msgstr "E683: Brak nazwy pliku lub niew³aœciwa œcie¿ka"
+
+#, c-format
+msgid "Cannot open file \"%s\""
+msgstr "Nie mogê otworzyæ pliku \"%s\""
+
+msgid "E681: Buffer is not loaded"
+msgstr "E681: Bufor nie jest za³adowany"
+
+msgid "E777: String or List expected"
+msgstr "E777: Oczekiwa³em na ³añcuch lub listê"
+
+#, c-format
+msgid "E369: invalid item in %s%%[]"
+msgstr "E369: Niew³aœciwy element w %s%%[]"
+
+#, c-format
+msgid "E769: Missing ] after %s["
+msgstr "E769: Brak ] po %s["
+
+#, c-format
+msgid "E53: Unmatched %s%%("
+msgstr "E53: Niesparowany %s%%("
+
+#, c-format
+msgid "E54: Unmatched %s("
+msgstr "E54: Niesparowany %s("
+
+#, c-format
+msgid "E55: Unmatched %s)"
+msgstr "E55: Niesparowany %s)"
+
+msgid "E66: \\z( not allowed here"
+msgstr "E66: \\z( jest niedozwolone w tym miejscu"
+
+msgid "E67: \\z1 - \\z9 not allowed here"
+msgstr "E67: \\z1 i podobne s¹ niedozwolone w tym miejscu"
+
+#, c-format
+msgid "E69: Missing ] after %s%%["
+msgstr "E69: Brak ] po %s%%["
+
+#, c-format
+msgid "E70: Empty %s%%[]"
+msgstr "E70: Pusty %s%%[]"
+
+msgid "E339: Pattern too long"
+msgstr "E339: Zbyt d³ugi wzorzec"
+
+msgid "E50: Too many \\z("
+msgstr "E50: Zbyt wiele \\z("
+
+#, c-format
+msgid "E51: Too many %s("
+msgstr "E51: Zbyt wiele %s("
+
+msgid "E52: Unmatched \\z("
+msgstr "E52: Niesparowany \\z("
+
+#, c-format
+msgid "E59: invalid character after %s@"
+msgstr "E59: niedozwolony znak po %s@"
+
+#, c-format
+msgid "E60: Too many complex %s{...}s"
+msgstr "E60: Zbyt wiele z³o¿onych %s{...}"
+
+#, c-format
+msgid "E61: Nested %s*"
+msgstr "E61: Zagnie¿d¿one %s*"
+
+#, c-format
+msgid "E62: Nested %s%c"
+msgstr "E62: Zagnie¿d¿one %s%c"
+
+msgid "E63: invalid use of \\_"
+msgstr "E63: Niedozwolone u¿ycie \\_"
+
+#, c-format
+msgid "E64: %s%c follows nothing"
+msgstr "E64: %s%c po niczym"
+
+msgid "E65: Illegal back reference"
+msgstr "E65: Niew³aœciwe odwo³anie wsteczne"
+
+msgid "E68: Invalid character after \\z"
+msgstr "E68: niedopuszczalny znak po \\z"
+
+#, c-format
+msgid "E678: Invalid character after %s%%[dxouU]"
+msgstr "E678: Niedozwolony znak po %s%%[dxouU]"
+
+#, c-format
+msgid "E71: Invalid character after %s%%"
+msgstr "E71: Niedozwolony znak po %s%%"
+
+#, c-format
+msgid "E554: Syntax error in %s{...}"
+msgstr "E554: B³¹d sk³adni w %s{...}"
+
+msgid "External submatches:\n"
+msgstr "Zewnêtrzne poddopasowania:\n"
+
+msgid ""
+"E864: \\%#= can only be followed by 0, 1, or 2. The automatic engine will be "
+"used "
+msgstr "E:864: \\%#= mo¿e byæ tylko przed 0, 1 lub 2. Zostanie u¿yty silnik automatyczny"
+
+#, c-format
+msgid "E866: (NFA regexp) Misplaced %c"
+msgstr "E866: (wyra¿enie regularne NFA) Niepoprawnie umieszczone %c"
+
+msgid "E865: (NFA) Regexp end encountered prematurely"
+msgstr "E865: (NFA) przedwczesny koniec wyra¿enia regularnego"
+
+#, c-format
+msgid "E867: (NFA) Unknown operator '\\z%c'"
+msgstr "E867: (NFA) Nieznany operator '\\z%c'"
+
+#, c-format
+msgid "E867: (NFA) Unknown operator '\\%%%c'"
+msgstr "E867: (NFA) Nieznany operator '\\%%%c'"
+
+#. should never happen
+msgid "E868: Error building NFA with equivalence class!"
+msgstr "E868: B³¹d przy budowwaniu NFA z klas¹ ekwiwalencji"
+
+#, c-format
+msgid "E869: (NFA) Unknown operator '\\@%c'"
+msgstr "E869: (NFA) Nieznany operator '\\@%c'"
+
+msgid "E870: (NFA regexp) Error reading repetition limits"
+msgstr "E870: (wyra¿enie regularne NFA) B³¹d przy odczytywaniu limitów powtórzeñ"
+
+#. Can't have a multi follow a multi.
+msgid "E871: (NFA regexp) Can't have a multi follow a multi"
+msgstr "E871: (wyra¿enie regularne NFA) wielokrotne nie mo¿e byæ po wielokrotnym"
+
+#. Too many `('
+msgid "E872: (NFA regexp) Too many '('"
+msgstr "E872: (wyra¿enie regularne NFA) Zbyt du¿o '('"
+
+msgid "E879: (NFA regexp) Too many \\z("
+msgstr "E879: (wyra¿enie regularne NFA) Za du¿o \\z("
+
+msgid "E873: (NFA regexp) proper termination error"
+msgstr "E873: (wyra¿enie regularne NFA) b³¹d poprawnego zakoñczenia"
+
+msgid "E874: (NFA) Could not pop the stack!"
+msgstr "E874: (NFA) Nie mo¿na zdj¹æ elementu ze stosu!"
+
+msgid ""
+"E875: (NFA regexp) (While converting from postfix to NFA), too many states "
+"left on stack"
+msgstr "E875: (wyra¿enie regularne NFA) (w trakcie konwersji postfix do NFA), za wiele stanów na stosie"
+
+msgid "E876: (NFA regexp) Not enough space to store the whole NFA "
+msgstr "E876: (wyra¿enie regularne NFA) Nie ma miejsca na ca³e NFA "
+
+msgid "E878: (NFA) Could not allocate memory for branch traversal!"
+msgstr "E878: (NFA) Nie mo¿na przydzieliæ pamiêci do przejœcia przez ga³êzie!"
+
+msgid ""
+"Could not open temporary log file for writing, displaying on stderr... "
+msgstr "Nie mo¿na otworzyæ do zapisu tymczasowego pliku, pokazujê na stderr... "
+
+#, c-format
+msgid "(NFA) COULD NOT OPEN %s !"
+msgstr "(NFA) NIE MO¯NA OTWORZYÆ %s !"
+
+msgid "Could not open temporary log file for writing "
+msgstr "Nie mo¿na otworzyæ do zapisu tymczasowego pliku logowania"
+
+msgid " VREPLACE"
+msgstr " V-ZAMIANA"
+
+msgid " REPLACE"
+msgstr " ZAMIANA"
+
+msgid " REVERSE"
+msgstr " NEGATYW"
+
+msgid " INSERT"
+msgstr " WPROWADZANIE"
+
+msgid " (insert)"
+msgstr " (wprowadzanie)"
+
+msgid " (replace)"
+msgstr " (zamiana)"
+
+msgid " (vreplace)"
+msgstr " (v-zamiana)"
+
+msgid " Hebrew"
+msgstr " Hebrajski"
+
+msgid " Arabic"
+msgstr " Arabski"
+
+msgid " (lang)"
+msgstr " (jêzyk)"
+
+msgid " (paste)"
+msgstr " (wklejanie)"
+
+msgid " VISUAL"
+msgstr " WIZUALNY"
+
+msgid " VISUAL LINE"
+msgstr " WIZUALNY LINIOWY"
+
+msgid " VISUAL BLOCK"
+msgstr " WIZUALNY BLOKOWY"
+
+msgid " SELECT"
+msgstr " ZAZNACZANIE"
+
+msgid " SELECT LINE"
+msgstr " ZAZNACZANIE LINIOWE"
+
+msgid " SELECT BLOCK"
+msgstr " ZAZNACZANIE BLOKOWE"
+
+msgid "recording"
+msgstr "zapis"
+
+#, c-format
+msgid "E383: Invalid search string: %s"
+msgstr "E383: Niew³aœciwy ci¹g do szukania: %s"
+
+#, c-format
+msgid "E384: search hit TOP without match for: %s"
+msgstr "E384: szukanie dobi³o GÓRY bez znalezienia: %s"
+
+#, c-format
+msgid "E385: search hit BOTTOM without match for: %s"
+msgstr "E385: szukanie dobi³o KOÑCA bez znalezienia : %s"
+
+msgid "E386: Expected '?' or '/' after ';'"
+msgstr "E386: Oczekujê '?' lub '/' po ';'"
+
+msgid " (includes previously listed match)"
+msgstr " (zawiera poprzednio wymienione dopasowanie)"
+
+#. cursor at status line
+msgid "--- Included files "
+msgstr "--- Zawarte pliki "
+
+msgid "not found "
+msgstr "nie znaleziono"
+
+msgid "in path ---\n"
+msgstr "w tropie ---\n"
+
+msgid " (Already listed)"
+msgstr " (Ju¿ wymienione)"
+
+msgid " NOT FOUND"
+msgstr " NIE ZNALEZIONO"
+
+#, c-format
+msgid "Scanning included file: %s"
+msgstr "Przegl¹d w³¹czonego pliku: %s"
+
+#, c-format
+msgid "Searching included file %s"
+msgstr "Przeszukiwanie w³¹czonego pliku %s"
+
+msgid "E387: Match is on current line"
+msgstr "E387: Wzorzec pasuje w bie¿¹cym wierszu"
+
+msgid "All included files were found"
+msgstr "Wszelkie w³¹czane pliki odnaleziono"
+
+msgid "No included files"
+msgstr "Brak w³¹czanych plików"
+
+msgid "E388: Couldn't find definition"
+msgstr "E388: Nie znalaz³em definicji"
+
+msgid "E389: Couldn't find pattern"
+msgstr "E389: Nie znalaz³em wzorca"
+
+msgid "Substitute "
+msgstr "Podstawienie "
+
+#, c-format
+msgid ""
+"\n"
+"# Last %sSearch Pattern:\n"
+"~"
+msgstr ""
+"\n"
+"# Ostatni %sWyszukiwany wzorzec:\n"
+"~"
+
+msgid "E759: Format error in spell file"
+msgstr "E759: Nieprawid³owy format pliku sprawdzania pisowni"
+
+msgid "E758: Truncated spell file"
+msgstr "E758: Obciêty plik sprawdzania pisowni"
+
+#, c-format
+msgid "Trailing text in %s line %d: %s"
+msgstr "Zbêdny tekst w %s wiersz %d: %s"
+
+#, c-format
+msgid "Affix name too long in %s line %d: %s"
+msgstr "Za d³uga nazwa afiksu w %s wiersz %d: %s"
+
+msgid "E761: Format error in affix file FOL, LOW or UPP"
+msgstr "E761: B³¹d formatu w pliku afiksów FOL, LOW lub UPP"
+
+msgid "E762: Character in FOL, LOW or UPP is out of range"
+msgstr "E762: Znak w FOL, LOW lub UPP jest poza zasiêgiem"
+
+msgid "Compressing word tree..."
+msgstr "Kompresja drzewa s³ów..."
+
+msgid "E756: Spell checking is not enabled"
+msgstr "E756: Sprawdzanie pisowni nie jest w³¹czone"
+
+#, c-format
+msgid "Warning: Cannot find word list \"%s_%s.spl\" or \"%s_ascii.spl\""
+msgstr ""
+"Ostrze¿enie: Nie mogê znaleŸæ listy s³ów \"%s_%s.spl\" lub \"%s_ascii.spl\""
+
+#, c-format
+msgid "Warning: Cannot find word list \"%s.%s.spl\" or \"%s.ascii.spl\""
+msgstr ""
+"Ostrze¿enie: Nie mogê znaleŸæ listy s³ów \"%s.%s.spl\" lub \"%s.ascii.spl\""
+
+#, c-format
+msgid "Reading spell file \"%s\""
+msgstr "Odczytujê plik sprawdzania pisowni \"%s\""
+
+msgid "E757: This does not look like a spell file"
+msgstr "E757: To nie wygl¹da na plik sprawdzania pisowni"
+
+msgid "E771: Old spell file, needs to be updated"
+msgstr "E771: Stary plik sprawdzania pisowni, wymagane uaktualnienie"
+
+msgid "E772: Spell file is for newer version of Vim"
+msgstr "E772: Plik sprawdzania pisowni dla nowszej wersji Vima"
+
+msgid "E770: Unsupported section in spell file"
+msgstr "E770: Niewspierana sekcja w pliku sprawdzania pisowni"
+
+#, c-format
+msgid "Warning: region %s not supported"
+msgstr "Ostrze¿enie: region %s nie jest wspierany"
+
+#, c-format
+msgid "Reading affix file %s..."
+msgstr "Czytam plik afiksów %s..."
+
+#, c-format
+msgid "Conversion failure for word in %s line %d: %s"
+msgstr "Konwersja nie powiod³a siê dla wyrazu w %s wierszu %d: %s"
+
+#, c-format
+msgid "Conversion in %s not supported: from %s to %s"
+msgstr "Konwersja w %s nie jest wspierana: od %s do %s"
+
+#, c-format
+msgid "Conversion in %s not supported"
+msgstr "Konwersja w %s nie jest wspierana"
+
+#, c-format
+msgid "Invalid value for FLAG in %s line %d: %s"
+msgstr "Nieprawid³owa wartoœæ FLAG w %s wierz %d: %s"
+
+#, c-format
+msgid "FLAG after using flags in %s line %d: %s"
+msgstr "FLAG po u¿yciu flag w %s wiersz %d: %s"
+
+#, c-format
+msgid ""
+"Defining COMPOUNDFORBIDFLAG after PFX item may give wrong results in %s line "
+"%d"
+msgstr ""
+"Definiowanie COMPOUNDFORBIDFLAG po PFX mo¿e skutkowaæ z³ym wynikiem w %s "
+"wiersz %d"
+
+#, c-format
+msgid ""
+"Defining COMPOUNDPERMITFLAG after PFX item may give wrong results in %s line "
+"%d"
+msgstr ""
+"Definiowanie COMPOUNDPERMITFLAG po PFX mo¿e skutkowaæ z³ym wynikiem w %s "
+"wiersz %d"
+
+#, c-format
+msgid "Wrong COMPOUNDRULES value in %s line %d: %s"
+msgstr "Z³a wartoœæ COMPOUNDRULES w %s wiersz %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDWORDMAX value in %s line %d: %s"
+msgstr "Z³a wartoœæ COMPOUNDWORDMAX w %s wiersz %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDMIN value in %s line %d: %s"
+msgstr "Z³a wartoœæ COMPOUNDMIM w %s wiersz %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDSYLMAX value in %s line %d: %s"
+msgstr "Z³a wartoœæ COMPOUNDSYLMAX w %s wiersz %d: %s"
+
+#, c-format
+msgid "Wrong CHECKCOMPOUNDPATTERN value in %s line %d: %s"
+msgstr "Z³a wartoœæ CHECKCOMPOUNDPATTERN w %s wiersz %d: %s"
+
+#, c-format
+msgid "Different combining flag in continued affix block in %s line %d: %s"
+msgstr "Ró¿ne flagi z³o¿eñ w kontynuowanym bloku afiksu w %s wiersz %d: %s"
+
+#, c-format
+msgid "Duplicate affix in %s line %d: %s"
+msgstr "Powtórzony afiks w %s wiersz %d: %s"
+
+#, c-format
+msgid ""
+"Affix also used for BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST in %s "
+"line %d: %s"
+msgstr ""
+"Afiks u¿yty tak¿e dla BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST w "
+"%s wiersz %d: %s"
+
+#, c-format
+msgid "Expected Y or N in %s line %d: %s"
+msgstr "Oczekiwano Y lub N w %s wierszu %d: %s"
+
+#, c-format
+msgid "Broken condition in %s line %d: %s"
+msgstr "B³êdny warunek w %s wiersz %d: %s"
+
+#, c-format
+msgid "Expected REP(SAL) count in %s line %d"
+msgstr "Oczekiwano iloœci REP(SAL) w %s wierszu %d"
+
+#, c-format
+msgid "Expected MAP count in %s line %d"
+msgstr "Oczekiwano iloœci MAP w %s wierszu %d"
+
+#, c-format
+msgid "Duplicate character in MAP in %s line %d"
+msgstr "Powtórzony znak w MAP w %s wierszu %d"
+
+#, c-format
+msgid "Unrecognized or duplicate item in %s line %d: %s"
+msgstr "Nieznany lub powtórzony element w %s wierszu %d: %s"
+
+#, c-format
+msgid "Missing FOL/LOW/UPP line in %s"
+msgstr "Brak wiersza FOL/LOW/UPP w %s"
+
+msgid "COMPOUNDSYLMAX used without SYLLABLE"
+msgstr "COMPOUNDSYLMAX u¿yty bez SYLLABLE"
+
+msgid "Too many postponed prefixes"
+msgstr "Zbyt wiele opóŸnionych prefiksów"
+
+msgid "Too many compound flags"
+msgstr "Zbyt wiele flag z³o¿eñ"
+
+msgid "Too many postponed prefixes and/or compound flags"
+msgstr "Zbyt wiele opóŸnionych prefiksów i/lub flag z³o¿eñ"
+
+#, c-format
+msgid "Missing SOFO%s line in %s"
+msgstr "Brak wiersza SOFO%s wiersz w %s"
+
+#, c-format
+msgid "Both SAL and SOFO lines in %s"
+msgstr "Wiersze SAL i SOFO w %s"
+
+#, c-format
+msgid "Flag is not a number in %s line %d: %s"
+msgstr "Flaga nie jest liczb¹ w %s wiersz %d: %s"
+
+#, c-format
+msgid "Illegal flag in %s line %d: %s"
+msgstr "Nieprawid³owa flaga w %s wiersz %d: %s"
+
+#, c-format
+msgid "%s value differs from what is used in another .aff file"
+msgstr "Wartoœæ %s ró¿ni siê od tej u¿ytej w innym pliku .aff"
+
+#, c-format
+msgid "Reading dictionary file %s..."
+msgstr "Czytam plik s³ownika %s..."
+
+#, c-format
+msgid "E760: No word count in %s"
+msgstr "E760: Brak iloœci s³ów w %s"
+
+#, c-format
+msgid "line %6d, word %6d - %s"
+msgstr "wiersz %6d, s³owo %6d - %s"
+
+# c-format
+#, c-format
+msgid "Duplicate word in %s line %d: %s"
+msgstr "Powtórzony wyraz w %s wierszu %d: %s"
+
+# c-format
+#, c-format
+msgid "First duplicate word in %s line %d: %s"
+msgstr "Pierwszy powtórzony wyraz w %s wiersz %d: %s"
+
+# c-format
+#, c-format
+msgid "%d duplicate word(s) in %s"
+msgstr "%d powtórzony(ch) wyraz(ów) w %s"
+
+#, c-format
+msgid "Ignored %d word(s) with non-ASCII characters in %s"
+msgstr "Zignorowa³em %d s³ów ze znakami nie ASCII w %s"
+
+#, c-format
+msgid "Reading word file %s..."
+msgstr "Odczytujê plik wyrazów %s..."
+
+#, c-format
+msgid "Duplicate /encoding= line ignored in %s line %d: %s"
+msgstr "Zignorowano powtórzony wiersz /encoding= w %s wierszu %d: %s"
+
+#, c-format
+msgid "/encoding= line after word ignored in %s line %d: %s"
+msgstr "Zignorowano wiersz /encoding= po wyrazie w %s wierszu %d: %s"
+
+#, c-format
+msgid "Duplicate /regions= line ignored in %s line %d: %s"
+msgstr "Powtórzony wiersz /regions= zignorowano w %s wierszu %d: %s"
+
+#, c-format
+msgid "Too many regions in %s line %d: %s"
+msgstr "Za du¿o regionów w %s wiersz %d: %s"
+
+#, c-format
+msgid "/ line ignored in %s line %d: %s"
+msgstr "wiersz / zignorowano w %s wierszu %d: %s"
+
+#, c-format
+msgid "Invalid region nr in %s line %d: %s"
+msgstr "Nieprawid³owy numer regionu w %s wierszu %d: %s"
+
+#, c-format
+msgid "Unrecognized flags in %s line %d: %s"
+msgstr "Nieznane flagi w %s wiersz %d: %s"
+
+#, c-format
+msgid "Ignored %d words with non-ASCII characters"
+msgstr "Zignorowa³em %d s³ów ze znakami nie ASCII"
+
+msgid "E845: Insufficient memory, word list will be incomplete"
+msgstr "E845: Nie wystarczaj¹ca iloœæ pamiêci, lista s³ów bêdzie niekompletna"
+
+#, c-format
+msgid "Compressed %d of %d nodes; %d (%d%%) remaining"
+msgstr "Skompresowano %d z %d wêz³ów; pozostaje %d (%d%%)"
+
+msgid "Reading back spell file..."
+msgstr "Odczytujê plik sprawdzania pisowni..."
+
+#.
+#. * Go through the trie of good words, soundfold each word and add it to
+#. * the soundfold trie.
+#.
+msgid "Performing soundfolding..."
+msgstr "Wykonujê kompresjê dŸwiêkow¹..."
+
+#, c-format
+msgid "Number of words after soundfolding: %ld"
+msgstr "Liczba s³ów po kompresji dŸwiêkowej: %ld"
+
+#, c-format
+msgid "Total number of words: %d"
+msgstr "Ca³kowita liczba s³ów: %d"
+
+#, c-format
+msgid "Writing suggestion file %s..."
+msgstr "Zapisujê plik sugestii %s..."
+
+#, c-format
+msgid "Estimated runtime memory use: %d bytes"
+msgstr "Oczekiwane zu¿ycie pamiêci: %d bajtów"
+
+msgid "E751: Output file name must not have region name"
+msgstr "E751: Nazwa pliku wynikowego nie mo¿e byæ nazw¹ regionu"
+
+msgid "E754: Only up to 8 regions supported"
+msgstr "E754: Wspieram tylko 8 regionów"
+
+#, c-format
+msgid "E755: Invalid region in %s"
+msgstr "E755: Nieprawid³owy region w %s"
+
+msgid "Warning: both compounding and NOBREAK specified"
+msgstr "Ostrze¿enie: okreœlono zarówno z³o¿enia jak i NOBREAK"
+
+#, c-format
+msgid "Writing spell file %s..."
+msgstr "Zapisujê plik sprawdzania pisowni %s..."
+
+msgid "Done!"
+msgstr "Zrobione!"
+
+#, c-format
+msgid "E765: 'spellfile' does not have %ld entries"
+msgstr "E765: 'spellfile' nie posiada wpisów %ld"
+
+#, c-format
+msgid "Word removed from %s"
+msgstr "Usuniêto s³owo z %s"
+
+#, c-format
+msgid "Word added to %s"
+msgstr "Dodano s³owo do %s"
+
+msgid "E763: Word characters differ between spell files"
+msgstr "E763: Znaki wyrazów ró¿ni¹ siê miêdzy plikami sprawdzania pisowni"
+
+msgid "Sorry, no suggestions"
+msgstr "Przykro mi, brak podpowiedzi"
+
+#, c-format
+msgid "Sorry, only %ld suggestions"
+msgstr "Przykro mi, tylko %ld podpowiedzi"
+
+#. for when 'cmdheight' > 1
+#. avoid more prompt
+#, c-format
+msgid "Change \"%.*s\" to:"
+msgstr "Zmieñ \"%.*s\" na:"
+
+#, c-format
+msgid " < \"%.*s\""
+msgstr " < \"%.*s\""
+
+msgid "E752: No previous spell replacement"
+msgstr "E752: Brak poprzednich podmian sprawdzania pisowni"
+
+#, c-format
+msgid "E753: Not found: %s"
+msgstr "E753: Nie znaleziono: %s"
+
+#, c-format
+msgid "E778: This does not look like a .sug file: %s"
+msgstr "E778: Ten plik nie wygl¹da na plik .sug: %s"
+
+#, c-format
+msgid "E779: Old .sug file, needs to be updated: %s"
+msgstr "E779: Stary plik .sug, konieczne jest uaktualnienie: %s"
+
+#, c-format
+msgid "E780: .sug file is for newer version of Vim: %s"
+msgstr "E780: Plik .sug dla nowszej wersji Vima: %s"
+
+#, c-format
+msgid "E781: .sug file doesn't match .spl file: %s"
+msgstr "E781: Plik .sug nie pasuje do pliku .spl: %s"
+
+#, c-format
+msgid "E782: error while reading .sug file: %s"
+msgstr "E782: B³¹d w czasie odczytu pliku .sug: %s"
+
+#. This should have been checked when generating the .spl
+#. * file.
+msgid "E783: duplicate char in MAP entry"
+msgstr "E783: Podwojony znak we wpisie MAP"
+
+msgid "No Syntax items defined for this buffer"
+msgstr "Brak elementów sk³adni okreœlonych dla tego bufora"
+
+#, c-format
+msgid "E390: Illegal argument: %s"
+msgstr "E390: Niedozwolony argument: %s"
+
+#, c-format
+msgid "E391: No such syntax cluster: %s"
+msgstr "E391: Nie ma takiego klastra sk³adni: %s"
+
+msgid "syncing on C-style comments"
+msgstr "synchronizacja komentarzy w stylu C"
+
+msgid "no syncing"
+msgstr "brak synchronizacji"
+
+msgid "syncing starts "
+msgstr "pocz¹tek synchronizacji"
+
+msgid " lines before top line"
+msgstr " wierszy przed górn¹ lini¹"
+
+msgid ""
+"\n"
+"--- Syntax sync items ---"
+msgstr ""
+"\n"
+"--- Elementy synchronizacji sk³adni ---"
+
+msgid ""
+"\n"
+"syncing on items"
+msgstr ""
+"\n"
+"synchronizujê na elementach"
+
+msgid ""
+"\n"
+"--- Syntax items ---"
+msgstr ""
+"\n"
+"--- Elementy sk³adni ---"
+
+#, c-format
+msgid "E392: No such syntax cluster: %s"
+msgstr "E392: Nie ma takiego klastra sk³adni: %s"
+
+msgid "minimal "
+msgstr "minimalnie "
+
+msgid "maximal "
+msgstr "maksymalnie "
+
+msgid "; match "
+msgstr "; pasuje "
+
+msgid " line breaks"
+msgstr "znaków nowego wiersza"
+
+msgid "E395: contains argument not accepted here"
+msgstr "E395: argument contains niedozwolony w tym miejscu"
+
+msgid "E844: invalid cchar value"
+msgstr "E844: Niew³aœciwa wartoœæ cchar"
+
+msgid "E393: group[t]here not accepted here"
+msgstr "E393: group[t]here niedozwolone w tym miejscu"
+
+#, c-format
+msgid "E394: Didn't find region item for %s"
+msgstr "E394: Nie znalaz³em elementów regionu dla %s"
+
+msgid "E397: Filename required"
+msgstr "E397: Wymagana nazwa pliku"
+
+msgid "E847: Too many syntax includes"
+msgstr "E847: Za du¿o w³¹czonych sk³adni"
+
+#, c-format
+msgid "E789: Missing ']': %s"
+msgstr "E789: Brak ']': %s"
+
+#, c-format
+msgid "E398: Missing '=': %s"
+msgstr "E398: Brak '=': %s"
+
+#, c-format
+msgid "E399: Not enough arguments: syntax region %s"
+msgstr "E399: Za ma³o argumentów: syntax region %s"
+
+msgid "E848: Too many syntax clusters"
+msgstr "E848: Za du¿o klastrów sk³adni"
+
+msgid "E400: No cluster specified"
+msgstr "E400: Brak specyfikacji klastra"
+
+#, c-format
+msgid "E401: Pattern delimiter not found: %s"
+msgstr "E401: Brak ogranicznika wzorca: %s"
+
+#, c-format
+msgid "E402: Garbage after pattern: %s"
+msgstr "E402: Œmieci po wzorcu: %s"
+
+msgid "E403: syntax sync: line continuations pattern specified twice"
+msgstr "E403: syntax sync: wielokrotnie podane wzorce kontynuacji wiersza"
+
+#, c-format
+msgid "E404: Illegal arguments: %s"
+msgstr "E404: Niedozwolone argumenty: %s"
+
+#, c-format
+msgid "E405: Missing equal sign: %s"
+msgstr "E405: Brak znaku równoœci: %s"
+
+#, c-format
+msgid "E406: Empty argument: %s"
+msgstr "E406: Pusty argument: %s"
+
+#, c-format
+msgid "E407: %s not allowed here"
+msgstr "E407: %s jest niedozwolone w tym miejscu"
+
+#, c-format
+msgid "E408: %s must be first in contains list"
+msgstr "E408: %s musi byæ pierwsze w liœcie contains"
+
+#, c-format
+msgid "E409: Unknown group name: %s"
+msgstr "E409: Nieznana nazwa grupy: %s"
+
+#, c-format
+msgid "E410: Invalid :syntax subcommand: %s"
+msgstr "E410: Niew³aœciwa podkomenda :syntax : %s"
+
+msgid ""
+" TOTAL COUNT MATCH SLOWEST AVERAGE NAME PATTERN"
+msgstr ""
+" WSZYTKO ILOŒÆ PASUJE NAJWOLN. ŒREDNIO NAZWA WZORZEC"
+
+msgid "E679: recursive loop loading syncolor.vim"
+msgstr "E679: rekursywna pêtla wczytuj¹ca syncolor.vim"
+
+#, c-format
+msgid "E411: highlight group not found: %s"
+msgstr "E411: nie znaleziono grupy podœwietlania: %s"
+
+#, c-format
+msgid "E412: Not enough arguments: \":highlight link %s\""
+msgstr "E412: Zbyt ma³o argumentów: \":highlight link %s\""
+
+#, c-format
+msgid "E413: Too many arguments: \":highlight link %s\""
+msgstr "E413: Zbyt wiele argumentów: \":highlight link %s\""
+
+msgid "E414: group has settings, highlight link ignored"
+msgstr "E414: grupa ma ustawienia; zignorowane pod³¹czenie podœwietlania"
+
+#, c-format
+msgid "E415: unexpected equal sign: %s"
+msgstr "E415: nieoczekiwany znak równoœci: %s"
+
+#, c-format
+msgid "E416: missing equal sign: %s"
+msgstr "E416: brak znaku równoœci: %s"
+
+#, c-format
+msgid "E417: missing argument: %s"
+msgstr "E417: brak argumentu: %s"
+
+#, c-format
+msgid "E418: Illegal value: %s"
+msgstr "E418: Niedozwolona wartoϾ: %s"
+
+msgid "E419: FG color unknown"
+msgstr "E419: Kolor FG nieznany"
+
+msgid "E420: BG color unknown"
+msgstr "E420: Kolor BG nieznany"
+
+#, c-format
+msgid "E421: Color name or number not recognized: %s"
+msgstr "E421: Nazwa lub liczba koloru nierozpoznana: %s"
+
+#, c-format
+msgid "E422: terminal code too long: %s"
+msgstr "E422: za d³ugi kod terminala: %s"
+
+#, c-format
+msgid "E423: Illegal argument: %s"
+msgstr "E423: Niedozwolony argument: %s"
+
+msgid "E424: Too many different highlighting attributes in use"
+msgstr "E424: Zbyt wiele ró¿nych atrybutów podkreœlania w u¿yciu"
+
+msgid "E669: Unprintable character in group name"
+msgstr "E669: Niedrukowalny znak w nazwie grupy"
+
+msgid "W18: Invalid character in group name"
+msgstr "W18: nieprawid³owy znak w nazwie grupy"
+
+msgid "E849: Too many highlight and syntax groups"
+msgstr "E849: Za du¿o grup podœwietlania i sk³adni"
+
+msgid "E555: at bottom of tag stack"
+msgstr "E555: na dole stosu znaczników"
+
+msgid "E556: at top of tag stack"
+msgstr "E556: na górze stosu znaczników"
+
+msgid "E425: Cannot go before first matching tag"
+msgstr "E425: Nie mo¿na przejœæ przed pierwszy pasuj¹cy znacznik"
+
+#, c-format
+msgid "E426: tag not found: %s"
+msgstr "E426: nie znaleziono znacznika: %s"
+
+msgid " # pri kind tag"
+msgstr " # pri rodzaj znacznik"
+
+msgid "file\n"
+msgstr "plik\n"
+
+msgid "E427: There is only one matching tag"
+msgstr "E427: Pasuje tylko jeden znacznik"
+
+msgid "E428: Cannot go beyond last matching tag"
+msgstr "E428: Nie mo¿na przejœæ za ostatni pasuj¹cy znacznik"
+
+#, c-format
+msgid "File \"%s\" does not exist"
+msgstr "Plik \"%s\" nie istnieje"
+
+#. Give an indication of the number of matching tags
+#, c-format
+msgid "tag %d of %d%s"
+msgstr "znacznik %d z %d%s"
+
+msgid " or more"
+msgstr " lub wiêcej"
+
+msgid " Using tag with different case!"
+msgstr " U¿ywam znacznika o odmiennej wielkoœci liter!"
+
+#, c-format
+msgid "E429: File \"%s\" does not exist"
+msgstr "E429: Plik \"%s\" nie istnieje"
+
+#. Highlight title
+msgid ""
+"\n"
+" # TO tag FROM line in file/text"
+msgstr ""
+"\n"
+" # DO znacznik OD wiersza w pliku/tekœcie"
+
+#, c-format
+msgid "Searching tags file %s"
+msgstr "Szukam w pliku znaczników %s"
+
+#, c-format
+msgid "E430: Tag file path truncated for %s\n"
+msgstr "E430: Trop szukania pliku znaczników obciêty dla %s\n"
+
+msgid "Ignoring long line in tags file"
+msgstr "Ignorujê d³ugie wiersze w pliku znaczników"
+
+#, c-format
+msgid "E431: Format error in tags file \"%s\""
+msgstr "E431: B³¹d formatu w pliku znaczników \"%s\""
+
+#, c-format
+msgid "Before byte %ld"
+msgstr "Przed bajtem %ld"
+
+#, c-format
+msgid "E432: Tags file not sorted: %s"
+msgstr "E432: Plik znaczników nieuporz¹dkowany: %s"
+
+#. never opened any tags file
+msgid "E433: No tags file"
+msgstr "E433: Brak pliku znaczników"
+
+msgid "E434: Can't find tag pattern"
+msgstr "E434: Nie mogê znaleŸæ wzorca znacznika"
+
+msgid "E435: Couldn't find tag, just guessing!"
+msgstr "E435: Nie znalaz³em znacznika - tylko zgadujê!"
+
+#, c-format
+msgid "Duplicate field name: %s"
+msgstr "Powtórzona nazwa pola: %s"
+
+msgid "' not known. Available builtin terminals are:"
+msgstr "' nieznany. Mo¿liwe typy wbudowanych terminali:"
+
+msgid "defaulting to '"
+msgstr "domyœlnie jest '"
+
+msgid "E557: Cannot open termcap file"
+msgstr "E557: Nie mogê otworzyæ pliku termcap"
+
+msgid "E558: Terminal entry not found in terminfo"
+msgstr "E558: Nie ma opisu takiego terminala w terminfo"
+
+msgid "E559: Terminal entry not found in termcap"
+msgstr "E559: Nie ma opisu takiego terminala w termcap"
+
+#, c-format
+msgid "E436: No \"%s\" entry in termcap"
+msgstr "E436: Brak opisu \"%s\" w termcap"
+
+msgid "E437: terminal capability \"cm\" required"
+msgstr "E437: wymagana zdolnoϾ \"cm\" terminala"
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Terminal keys ---"
+msgstr ""
+"\n"
+"--- Klawisze terminala ---"
+
+msgid "new shell started\n"
+msgstr "uruchomiono now¹ pow³okê\n"
+
+msgid "Vim: Error reading input, exiting...\n"
+msgstr "Vim: B³¹d podczas wczytywania wejœcia, koñczê...\n"
+
+msgid "Used CUT_BUFFER0 instead of empty selection"
+msgstr "U¿ywam CUT_BUFFER0 zamiast pustego wyboru"
+
+#. This happens when the FileChangedRO autocommand changes the
+#. * file in a way it becomes shorter.
+msgid "E834: Line count changed unexpectedly"
+msgstr "E834: Niespodziewana zmiana iloœci linii"
+
+#. must display the prompt
+msgid "No undo possible; continue anyway"
+msgstr "Cofniêcie niemo¿liwe; mimo to kontynuujê"
+
+#, c-format
+msgid "E828: Cannot open undo file for writing: %s"
+msgstr "E828: Nie mogê otworzyæ do zapisu pliku undo: %s"
+
+#, c-format
+msgid "E825: Corrupted undo file (%s): %s"
+msgstr "E825: Uszkodzony plik undo (%s): %s"
+
+msgid "Cannot write undo file in any directory in 'undodir'"
+msgstr "Nie mo¿na zapisaæ pliku undo w ¿adnym katalogu z 'undodir'"
+
+#, c-format
+msgid "Will not overwrite with undo file, cannot read: %s"
+msgstr "Nie nadpiszê plikiem undo, nie mogê odczytaæ: %s"
+
+#, c-format
+msgid "Will not overwrite, this is not an undo file: %s"
+msgstr "Nie nadpiszê, to nie jest plik undo: %s"
+
+msgid "Skipping undo file write, nothing to undo"
+msgstr "Pomijam zapis pliku undo, nic do cofniêcia"
+
+#, c-format
+msgid "Writing undo file: %s"
+msgstr "Zapisujê plik undo: %s"
+
+#, c-format
+msgid "E829: write error in undo file: %s"
+msgstr "E829: B³¹d zapisu w pliku undo: %s"
+
+#, c-format
+msgid "Not reading undo file, owner differs: %s"
+msgstr "Nie wczytujê pliku undo, inny w³aœciciel: %s"
+
+#, c-format
+msgid "Reading undo file: %s"
+msgstr "Wczytujê plik undo: %s"
+
+#, c-format
+msgid "E822: Cannot open undo file for reading: %s"
+msgstr "E822: Nie mogê otworzyæ pliku undo do odczytu: %s"
+
+#, c-format
+msgid "E823: Not an undo file: %s"
+msgstr "E823: To nie jest plik undo: %s"
+
+#, c-format
+msgid "E832: Non-encrypted file has encrypted undo file: %s"
+msgstr "E832: Nie zaszyfrowany plik ma zaszyfrowany plik undo: %s"
+
+#, c-format
+msgid "E826: Undo file decryption failed: %s"
+msgstr "E826: Nie powiod³o siê odszyfrowywanie pliku undo: %s"
+
+#, c-format
+msgid "E827: Undo file is encrypted: %s"
+msgstr "E827: Plik undo jest zaszyfrowany: %s"
+
+#, c-format
+msgid "E824: Incompatible undo file: %s"
+msgstr "E824: Niekompatybilny plik undo: %s"
+
+msgid "File contents changed, cannot use undo info"
+msgstr "Zawartoœæ pliku siê zmieni³a, nie mogê u¿yæ pliku undo"
+
+#, c-format
+msgid "Finished reading undo file %s"
+msgstr "Skoñczono wczytywanie pliku undo %s"
+
+msgid "Already at oldest change"
+msgstr "Ju¿ w miejscu ostatniej zmiany"
+
+msgid "Already at newest change"
+msgstr "Ju¿ w miejscu najnowszej zmiany"
+
+#, c-format
+msgid "E830: Undo number %ld not found"
+msgstr "E830: Nie znaleziono numeru cofniêcia %ld"
+
+msgid "E438: u_undo: line numbers wrong"
+msgstr "E438: u_undo: niew³aœciwe numery wierszy"
+
+msgid "more line"
+msgstr "1 wiersz wiêcej"
+
+msgid "more lines"
+msgstr "wiêcej wierszy"
+
+msgid "line less"
+msgstr "1 wiersz mniej"
+
+msgid "fewer lines"
+msgstr "mniej wierszy"
+
+msgid "change"
+msgstr "1 zmiana"
+
+msgid "changes"
+msgstr "zmiany"
+
+#, c-format
+msgid "%ld %s; %s #%ld %s"
+msgstr "%ld %s; %s #%ld %s"
+
+msgid "before"
+msgstr "przed"
+
+msgid "after"
+msgstr "za"
+
+msgid "Nothing to undo"
+msgstr "Nie ma zmian do cofniêcia"
+
+msgid "number changes when saved"
+msgstr "liczba zmiany kiedy zapisano"
+
+#, c-format
+msgid "%ld seconds ago"
+msgstr "%ld sekund temu"
+
+msgid "E790: undojoin is not allowed after undo"
+msgstr "E790: undojoin nie jest dozwolone po undo"
+
+msgid "E439: undo list corrupt"
+msgstr "E439: uszkodzona lista cofania"
+
+msgid "E440: undo line missing"
+msgstr "E440: brak wiersza cofania"
+
+#. Only MS VC 4.1 and earlier can do Win32s
+msgid ""
+"\n"
+"MS-Windows 16/32-bit GUI version"
+msgstr ""
+"\n"
+"16/32-bit wersja GUI dla MS-Windows"
+
+msgid ""
+"\n"
+"MS-Windows 64-bit GUI version"
+msgstr ""
+"\n"
+"64 bitowa wersja GUI dla MS-Windows"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit GUI version"
+msgstr ""
+"\n"
+"32 bitowa wersja GUI dla MS-Windows"
+
+msgid " in Win32s mode"
+msgstr " w trybie Win32s"
+
+msgid " with OLE support"
+msgstr " ze wspomaganiem OLE"
+
+msgid ""
+"\n"
+"MS-Windows 64-bit console version"
+msgstr ""
+"\n"
+"32 bitowa wersja na konsolê dla MS-Windows"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit console version"
+msgstr ""
+"\n"
+"32 bitowa wersja na konsolê dla MS-Windows"
+
+msgid ""
+"\n"
+"MS-Windows 16-bit version"
+msgstr ""
+"\n"
+"16 bitowa wersja dla MS-Windows"
+
+msgid ""
+"\n"
+"32-bit MS-DOS version"
+msgstr ""
+"\n"
+"32 bitowa wersja dla MS-DOS"
+
+msgid ""
+"\n"
+"16-bit MS-DOS version"
+msgstr ""
+"\n"
+"16 bitowa wersja dla MS-DOS"
+
+msgid ""
+"\n"
+"MacOS X (unix) version"
+msgstr ""
+"\n"
+"wersja dla MacOS X (unix)"
+
+msgid ""
+"\n"
+"MacOS X version"
+msgstr ""
+"\n"
+"wersja dla MacOS X"
+
+msgid ""
+"\n"
+"MacOS version"
+msgstr ""
+"\n"
+"wersja dla MacOS"
+
+msgid ""
+"\n"
+"OpenVMS version"
+msgstr ""
+"\n"
+"wersja dla OpenVMS"
+
+msgid ""
+"\n"
+"Included patches: "
+msgstr ""
+"\n"
+"Zadane ³aty: "
+
+msgid ""
+"\n"
+"Extra patches: "
+msgstr ""
+"\n"
+"Ekstra ³aty: "
+
+msgid "Modified by "
+msgstr "Zmieniony przez "
+
+msgid ""
+"\n"
+"Compiled "
+msgstr ""
+"\n"
+"Skompilowany "
+
+msgid "by "
+msgstr "przez "
+
+msgid ""
+"\n"
+"Huge version "
+msgstr ""
+"\n"
+"Olbrzymia wersja "
+
+msgid ""
+"\n"
+"Big version "
+msgstr ""
+"\n"
+"Du¿a wersja "
+
+msgid ""
+"\n"
+"Normal version "
+msgstr ""
+"\n"
+"Normalna wersja "
+
+msgid ""
+"\n"
+"Small version "
+msgstr ""
+"\n"
+"Ma³a wersja "
+
+msgid ""
+"\n"
+"Tiny version "
+msgstr ""
+"\n"
+"Malutka wersja "
+
+msgid "without GUI."
+msgstr "bez GUI."
+
+msgid "with GTK2-GNOME GUI."
+msgstr "z GTK2-GNOME GUI."
+
+msgid "with GTK2 GUI."
+msgstr "z GTK2 GUI."
+
+msgid "with X11-Motif GUI."
+msgstr "z X11-Motif GUI."
+
+msgid "with X11-neXtaw GUI."
+msgstr "z X11-neXtaw GUI."
+
+msgid "with X11-Athena GUI."
+msgstr "z X11-Athena GUI."
+
+msgid "with Photon GUI."
+msgstr "z Photon GUI."
+
+msgid "with GUI."
+msgstr "z GUI."
+
+msgid "with Carbon GUI."
+msgstr "z Carbon GUI."
+
+msgid "with Cocoa GUI."
+msgstr "z Cocoa GUI."
+
+msgid "with (classic) GUI."
+msgstr "z (klasycznym) GUI."
+
+msgid " Features included (+) or not (-):\n"
+msgstr " Opcje w³¹czone (+) lub nie (-):\n"
+
+msgid " system vimrc file: \""
+msgstr " vimrc systemu: \""
+
+msgid " user vimrc file: \""
+msgstr " vimrc u¿ytkownika: \""
+
+msgid " 2nd user vimrc file: \""
+msgstr " 2-gi plik vimrc u¿ytkownika: \""
+
+msgid " 3rd user vimrc file: \""
+msgstr " 3-ci plik vimrc u¿ytkownika: \""
+
+msgid " user exrc file: \""
+msgstr " exrc u¿ytkownika: \""
+
+msgid " 2nd user exrc file: \""
+msgstr " 2-gi plik exrc u¿ytkownika: \""
+
+msgid " system gvimrc file: \""
+msgstr " gvimrc systemu: \""
+
+msgid " user gvimrc file: \""
+msgstr " gvimrc u¿ytkownika: \""
+
+msgid "2nd user gvimrc file: \""
+msgstr "2-gi plik gvimrc u¿ytkownika: \""
+
+msgid "3rd user gvimrc file: \""
+msgstr "3-ci plik gvimrc u¿ytkownika: \""
+
+msgid " system menu file: \""
+msgstr " systemowy plik menu: \""
+
+msgid " fall-back for $VIM: \""
+msgstr " odwet dla $VIM-a: \""
+
+msgid " f-b for $VIMRUNTIME: \""
+msgstr "f-b dla $VIMRUNTIME: \""
+
+msgid "Compilation: "
+msgstr "Kompilacja: "
+
+msgid "Compiler: "
+msgstr "Kompilator: "
+
+msgid "Linking: "
+msgstr "Konsolidacja: "
+
+msgid " DEBUG BUILD"
+msgstr " KOMPILACJA DEBUG"
+
+msgid "VIM - Vi IMproved"
+msgstr "VIM - Vi rozbudowany"
+
+msgid "version "
+msgstr "wersja "
+
+msgid "by Bram Moolenaar et al."
+msgstr "Autor: Bram Moolenaar i Inni."
+
+msgid "Vim is open source and freely distributable"
+msgstr "Vim jest open source i rozprowadzany darmowo"
+
+msgid "Help poor children in Uganda!"
+msgstr "Pomó¿ biednym dzieciom w Ugandzie!"
+
+msgid "type :help iccf<Enter> for information "
+msgstr "wprowadŸ :help iccf<Enter> dla informacji o tym "
+
+msgid "type :q<Enter> to exit "
+msgstr "wprowadŸ :q<Enter> zakoñczenie programu "
+
+msgid "type :help<Enter> or <F1> for on-line help"
+msgstr "wprowadŸ :help<Enter> lub <F1> pomoc na bie¿¹co "
+
+msgid "type :help version8<Enter> for version info"
+msgstr "wprowadŸ :help version8<Enter> dla informacji o wersji"
+
+msgid "Running in Vi compatible mode"
+msgstr "Dzia³am w trybie zgodnoœci z Vi"
+
+msgid "type :set nocp<Enter> for Vim defaults"
+msgstr "wprowadŸ :set nocp<Enter> wartoœci domyœlne Vim-a"
+
+msgid "type :help cp-default<Enter> for info on this"
+msgstr "wprowadŸ :help cp-default<Enter> dla informacji to tym "
+
+msgid "menu Help->Orphans for information "
+msgstr "menu Pomoc->Sieroty dla informacji to tym "
+
+msgid "Running modeless, typed text is inserted"
+msgstr "Uruchomiony bez trybów, wpisany tekst jest wprowadzany"
+
+msgid "menu Edit->Global Settings->Toggle Insert Mode "
+msgstr "menu Edytuj->Ustawienia globalne->Tryb wstawiania"
+
+msgid " for two modes "
+msgstr " dla dwóch trybów "
+
+msgid "menu Edit->Global Settings->Toggle Vi Compatible"
+msgstr "menu Edytuj->Ustawienia globalne->KompatybilnoϾ z Vi"
+
+msgid " for Vim defaults "
+msgstr " dla domyœlnych ustawieñ Vima "
+
+msgid "Sponsor Vim development!"
+msgstr "Sponsoruj rozwój Vima!"
+
+msgid "Become a registered Vim user!"
+msgstr "Zostañ zarejestrowanym u¿ytkownikiem Vima!"
+
+msgid "type :help sponsor<Enter> for information "
+msgstr "wprowadŸ :help sponsor<Enter> dla informacji"
+
+msgid "type :help register<Enter> for information "
+msgstr "wprowadŸ :help register<Enter> dla informacji"
+
+msgid "menu Help->Sponsor/Register for information "
+msgstr "menu Pomoc->Sponsoruj/Zarejestruj siê dla informacji"
+
+msgid "WARNING: Windows 95/98/ME detected"
+msgstr "OSTRZE¯ENIE: wykryto Windows 95/98/ME"
+
+msgid "type :help windows95<Enter> for info on this"
+msgstr "wprowadŸ :help windows95<Enter> dla informacji to tym "
+
+msgid "Already only one window"
+msgstr "Ju¿ jest tylko jeden widok"
+
+msgid "E441: There is no preview window"
+msgstr "E441: Nie ma okna podgl¹du"
+
+msgid "E442: Can't split topleft and botright at the same time"
+msgstr "E442: Nie mogê rozdzieliæ lewo-górnego i prawo-dolnego jednoczeœnie"
+
+msgid "E443: Cannot rotate when another window is split"
+msgstr "E443: Nie mogê przekrêciæ, gdy inne okno jest rozdzielone"
+
+msgid "E444: Cannot close last window"
+msgstr "E444: Nie mogê zamkn¹æ ostatniego okna"
+
+msgid "E813: Cannot close autocmd window"
+msgstr "E813: Nie mo¿na zamkn¹æ okna autocmd"
+
+msgid "E814: Cannot close window, only autocmd window would remain"
+msgstr "E814: Nie mo¿na zamkn¹æ okna, zosta³oby tylko okno autocmd"
+
+msgid "E445: Other window contains changes"
+msgstr "E445: Inne okno zawiera zmiany"
+
+msgid "E446: No file name under cursor"
+msgstr "E446: Brak nazwy pliku pod kursorem"
+
+#, c-format
+msgid "E447: Can't find file \"%s\" in path"
+msgstr "E447: Nie mogê znaleŸæ pliku \"%s\" w tropie"
+
+#, c-format
+msgid "E370: Could not load library %s"
+msgstr "E370: Nie mog³em za³adowaæ biblioteki %s"
+
+msgid "Sorry, this command is disabled: the Perl library could not be loaded."
+msgstr ""
+"Przykro mi, ta komenda jest wy³¹czona: nie mog³em za³adowaæ biblioteki Perla."
+
+msgid "E299: Perl evaluation forbidden in sandbox without the Safe module"
+msgstr "E299: wyliczenie Perla zabronione w piaskownicy bez modu³u Safe"
+
+msgid "Edit with &multiple Vims"
+msgstr "Edytuj w &wielu Vimach"
+
+msgid "Edit with single &Vim"
+msgstr "Edytuj w pojedynczym &Vimie"
+
+msgid "Diff with Vim"
+msgstr "Diff z Vimem"
+
+msgid "Edit with &Vim"
+msgstr "Edytuj w &Vimie"
+
+#. Now concatenate
+msgid "Edit with existing Vim - "
+msgstr "Edytuj z istniej¹cym Vimem - "
+
+msgid "Edits the selected file(s) with Vim"
+msgstr "Edytuj wybrane pliki w Vimie"
+
+msgid "Error creating process: Check if gvim is in your path!"
+msgstr "B³¹d tworzenia procesu: SprawdŸ czy gvim jest w twojej œcie¿ce!"
+
+msgid "gvimext.dll error"
+msgstr "b³¹d gvimext.dll"
+
+msgid "Path length too long!"
+msgstr "Za d³uga œcie¿ka!"
+
+msgid "--No lines in buffer--"
+msgstr "--Brak wierszy w buforze--"
+
+#.
+#. * The error messages that can be shared are included here.
+#. * Excluded are errors that are only used once and debugging messages.
+#.
+msgid "E470: Command aborted"
+msgstr "E470: Przerwanie komendy"
+
+msgid "E471: Argument required"
+msgstr "E471: wymagany argument"
+
+msgid "E10: \\ should be followed by /, ? or &"
+msgstr "E10: po \\ powinno byæ /, ? lub &"
+
+msgid "E11: Invalid in command-line window; <CR> executes, CTRL-C quits"
+msgstr ""
+"E11: Niedozwolone w oknie wiersza poleceñ; <CR> wykonuje, CTRL-C opuszcza"
+
+msgid "E12: Command not allowed from exrc/vimrc in current dir or tag search"
+msgstr ""
+"E12: Komenda niedozwolona z exrc/vimrc w bie¿¹cym szukaniu katalogu lub "
+"znacznika"
+
+msgid "E171: Missing :endif"
+msgstr "E171: Brak :endif"
+
+msgid "E600: Missing :endtry"
+msgstr "E600: Brak :endtry"
+
+msgid "E170: Missing :endwhile"
+msgstr "E170: Brak :endwhile"
+
+msgid "E170: Missing :endfor"
+msgstr "E170: Brak :endfor"
+
+msgid "E588: :endwhile without :while"
+msgstr "E588: :endwhile bez :while"
+
+msgid "E588: :endfor without :for"
+msgstr "E588: :endfor bez :for"
+
+msgid "E13: File exists (add ! to override)"
+msgstr "E13: Plik istnieje (wymuœ poprzez !)"
+
+msgid "E472: Command failed"
+msgstr "E472: Komenda nie powiod³a siê"
+
+#, c-format
+msgid "E234: Unknown fontset: %s"
+msgstr "E234: Nieznany zestaw czcionek: %s"
+
+#, c-format
+msgid "E235: Unknown font: %s"
+msgstr "E235: Nieznana czcionka: %s"
+
+#, c-format
+msgid "E236: Font \"%s\" is not fixed-width"
+msgstr "E236: Czcionka \"%s\" nie ma sta³ej szerokoœci znaków"
+
+msgid "E473: Internal error"
+msgstr "E473: B³¹d wewnêtrzny"
+
+msgid "Interrupted"
+msgstr "Przerwane"
+
+msgid "E14: Invalid address"
+msgstr "E14: Niew³aœciwy adres"
+
+msgid "E474: Invalid argument"
+msgstr "E474: Niew³aœciwy argument"
+
+#, c-format
+msgid "E475: Invalid argument: %s"
+msgstr "E475: Niew³aœciwy argument: %s"
+
+#, c-format
+msgid "E15: Invalid expression: %s"
+msgstr "E15: Niew³aœciwe wyra¿enie: %s"
+
+msgid "E16: Invalid range"
+msgstr "E16: Niew³aœciwy zakres"
+
+msgid "E476: Invalid command"
+msgstr "E476: Niew³aœciwa komenda"
+
+#, c-format
+msgid "E17: \"%s\" is a directory"
+msgstr "E17: \"%s\" jest katalogiem"
+
+#, c-format
+msgid "E364: Library call failed for \"%s()\""
+msgstr "E364: Wywo³anie z biblioteki nie powiod³o siê dla \"%s()\""
+
+#, c-format
+msgid "E448: Could not load library function %s"
+msgstr "E448: Nie mo¿na za³adowaæ funkcji biblioteki %s"
+
+msgid "E19: Mark has invalid line number"
+msgstr "E19: Zak³adka ma niew³aœciwy numer wiersza"
+
+msgid "E20: Mark not set"
+msgstr "E20: Zak³adka nienastawiona"
+
+msgid "E21: Cannot make changes, 'modifiable' is off"
+msgstr "E21: Nie mogê wykonaæ zmian, 'modifiable' jest wy³¹czone"
+
+msgid "E22: Scripts nested too deep"
+msgstr "E22: Zbyt g³êbokie zagnie¿d¿enie skryptów"
+
+msgid "E23: No alternate file"
+msgstr "E23: Brak pliku zamiany"
+
+msgid "E24: No such abbreviation"
+msgstr "E24: Nie ma takiego skrótu"
+
+msgid "E477: No ! allowed"
+msgstr "E477: Niedozwolone !"
+
+msgid "E25: GUI cannot be used: Not enabled at compile time"
+msgstr "E25: GUI nie mo¿e byæ u¿yte: Nie w³¹czono podczas kompilacji"
+
+msgid "E26: Hebrew cannot be used: Not enabled at compile time\n"
+msgstr "E26: Hebrajski nie mo¿e byæ u¿yty: Nie w³¹czono podczas kompilacji\n"
+
+msgid "E27: Farsi cannot be used: Not enabled at compile time\n"
+msgstr "E27: Farsi nie mo¿e byæ u¿yty: Nie w³¹czono podczas kompilacji\n"
+
+msgid "E800: Arabic cannot be used: Not enabled at compile time\n"
+msgstr "E800: Arabski nie mo¿e byæ u¿yty: Nie w³¹czono podczas kompilacji\n"
+
+#, c-format
+msgid "E28: No such highlight group name: %s"
+msgstr "E28: Brak takiej nazwy grupy podœwietlania: %s"
+
+msgid "E29: No inserted text yet"
+msgstr "E29: Nie wprowadzono jeszcze ¿adnego tekstu"
+
+msgid "E30: No previous command line"
+msgstr "E30: Nie ma poprzedniego wiersza poleceñ"
+
+msgid "E31: No such mapping"
+msgstr "E31: Nie ma takiego przyporz¹dkowania"
+
+msgid "E479: No match"
+msgstr "E479: Brak dopasowañ"
+
+#, c-format
+msgid "E480: No match: %s"
+msgstr "E480: Brak dopasowañ: %s"
+
+msgid "E32: No file name"
+msgstr "E32: Brak nazwy pliku"
+
+msgid "E33: No previous substitute regular expression"
+msgstr "E33: Brak poprzedniego podstawieniowego wyra¿enia regularnego"
+
+msgid "E34: No previous command"
+msgstr "E34: Brak poprzedniej komendy"
+
+msgid "E35: No previous regular expression"
+msgstr "E35: Brak poprzedniego wyra¿enia regularnego"
+
+msgid "E481: No range allowed"
+msgstr "E481: Zakres niedozwolony"
+
+msgid "E36: Not enough room"
+msgstr "E36: Brak miejsca"
+
+#, c-format
+msgid "E247: no registered server named \"%s\""
+msgstr "E247: brak zarejestrowanego serwera o nazwie \"%s\""
+
+#, c-format
+msgid "E482: Can't create file %s"
+msgstr "E482: Nie mogê stworzyæ pliku %s"
+
+msgid "E483: Can't get temp file name"
+msgstr "E483: Nie mogê pobraæ nazwy pliku tymczasowego"
+
+#, c-format
+msgid "E484: Can't open file %s"
+msgstr "E484: Nie mogê otworzyæ pliku %s"
+
+#, c-format
+msgid "E485: Can't read file %s"
+msgstr "E485: Nie mogê odczytaæ pliku %s"
+
+msgid "E37: No write since last change (add ! to override)"
+msgstr "E37: Nie zapisano od ostatniej zmiany (wymuœ przez !)"
+
+msgid "E38: Null argument"
+msgstr "E38: Zerowy argument"
+
+msgid "E39: Number expected"
+msgstr "E39: Oczekujê liczby"
+
+#, c-format
+msgid "E40: Can't open errorfile %s"
+msgstr "E40: Nie mogê otworzyæ pliku b³êdów %s"
+
+msgid "E233: cannot open display"
+msgstr "E233: nie mogê otworzyæ ekranu"
+
+msgid "E41: Out of memory!"
+msgstr "E41: Pamiêæ wyczerpana!"
+
+msgid "Pattern not found"
+msgstr "Nie znaleziono wzorca"
+
+#, c-format
+msgid "E486: Pattern not found: %s"
+msgstr "E486: Nie znaleziono wzorca: %s"
+
+msgid "E487: Argument must be positive"
+msgstr "E487: Argument musi byæ dodatni"
+
+msgid "E459: Cannot go back to previous directory"
+msgstr "E459: Nie mo¿na przejœæ do poprzedniego katalogu"
+
+msgid "E42: No Errors"
+msgstr "E42: Brak B³êdów"
+
+msgid "E776: No location list"
+msgstr "E776: Brak listy lokacji"
+
+msgid "E43: Damaged match string"
+msgstr "E43: Popsuty ci¹g wzorca"
+
+msgid "E44: Corrupted regexp program"
+msgstr "E44: Zepsuty program wyra¿eñ regularnych"
+
+msgid "E45: 'readonly' option is set (add ! to override)"
+msgstr "E45: opcja 'readonly' jest ustawiona (wymuœ poprzez !)"
+
+#, c-format
+msgid "E46: Cannot change read-only variable \"%s\""
+msgstr "E46: Nie mogê zmieniæ zmiennej tylko do odczytu \"%s\""
+
+#, c-format
+msgid "E794: Cannot set variable in the sandbox: \"%s\""
+msgstr "E794: Nie mogê ustawiæ zmiennej w piaskownicy: \"%s\""
+
+msgid "E47: Error while reading errorfile"
+msgstr "E47: B³¹d w trakcie czytania pliku b³êdów"
+
+msgid "E48: Not allowed in sandbox"
+msgstr "E48: Niedozwolone w piaskownicy"
+
+msgid "E523: Not allowed here"
+msgstr "E523: Niedozwolone w tym miejscu"
+
+msgid "E359: Screen mode setting not supported"
+msgstr "E359: Ustawianie trybu ekranu niewspomagane"
+
+msgid "E49: Invalid scroll size"
+msgstr "E49: Niew³aœciwa wielkoœæ przewiniêcia"
+
+msgid "E91: 'shell' option is empty"
+msgstr "E91: opcja 'shell' jest pusta"
+
+msgid "E255: Couldn't read in sign data!"
+msgstr "E255: Nie mog³em wczytaæ danych znaku!"
+
+msgid "E72: Close error on swap file"
+msgstr "E72: B³¹d podczas zamykania pliku wymiany"
+
+msgid "E73: tag stack empty"
+msgstr "E73: stos znaczników jest pusty"
+
+msgid "E74: Command too complex"
+msgstr "E74: Komenda jest zbyt skomplikowana"
+
+msgid "E75: Name too long"
+msgstr "E75: Zbyt d³uga nazwa"
+
+msgid "E76: Too many ["
+msgstr "E76: Zbyt wiele ["
+
+msgid "E77: Too many file names"
+msgstr "E77: Zbyt wiele nazw plików"
+
+msgid "E488: Trailing characters"
+msgstr "E488: Nadstêpne znaczki"
+
+msgid "E78: Unknown mark"
+msgstr "E78: Nieznana zak³adka"
+
+msgid "E79: Cannot expand wildcards"
+msgstr "E79: Nie mog¹ rozwin¹æ znaków wieloznacznych"
+
+msgid "E591: 'winheight' cannot be smaller than 'winminheight'"
+msgstr "E591: 'winheight' nie mo¿e byæ mniejsze ni¿ 'winminheight'"
+
+msgid "E592: 'winwidth' cannot be smaller than 'winminwidth'"
+msgstr "E592: 'winwidth' nie mo¿e byæ mniejsze ni¿ 'winminwidth'"
+
+msgid "E80: Error while writing"
+msgstr "E80: B³¹d w trakcie zapisu"
+
+msgid "Zero count"
+msgstr "Zerowy licznik"
+
+msgid "E81: Using <SID> not in a script context"
+msgstr "E81: U¿ycie <SID> poza kontekstem skryptu"
+
+msgid "E449: Invalid expression received"
+msgstr "E449: Odebra³em niew³aœciwe wyra¿enie"
+
+msgid "E463: Region is guarded, cannot modify"
+msgstr "E463: Region jest chroniony, nie mogê zmieniæ"
+
+msgid "E744: NetBeans does not allow changes in read-only files"
+msgstr "E744: NetBeans nie zezwala na zmiany w plikach tylko do odczytu"
+
+#, c-format
+msgid "E685: Internal error: %s"
+msgstr "E685: B³¹d wewnêtrzny: %s"
+
+msgid "E363: pattern uses more memory than 'maxmempattern'"
+msgstr "E363: Wzorzec u¿ywa wiêcej pamiêci ni¿ 'maxmempattern'"
+
+msgid "E749: empty buffer"
+msgstr "E749: pusty bufor"
+
+msgid "E682: Invalid search pattern or delimiter"
+msgstr "E682: Niew³aœciwy wzorzec wyszukiwania lub delimiter"
+
+msgid "E139: File is loaded in another buffer"
+msgstr "E139: Plik jest za³adowany w innym buforze"
+
+#, c-format
+msgid "E764: Option '%s' is not set"
+msgstr "E764: Nie ustawiono opcji '%s'"
+
+msgid "E850: Invalid register name"
+msgstr "E850: Niew³aœciwa nazwa rejestru"
+
+msgid "search hit TOP, continuing at BOTTOM"
+msgstr "szukanie dobi³o GÓRY; kontynuacja od KOÑCA"
+
+msgid "search hit BOTTOM, continuing at TOP"
+msgstr "szukanie dobi³o KOÑCA; kontynuacja od GÓRY"
+
+#, c-format
+msgid "Need encryption key for \"%s\""
+msgstr "Potrzebujê klucza szyfrowania dla \"%s\""
+
+msgid "empty keys are not allowed"
+msgstr "puste klucze nie s¹ dozwolone"
+
+msgid "dictionary is locked"
+msgstr "s³ownik jest zablokowany"
+
+msgid "list is locked"
+msgstr "lista jest zablokowana"
+
+#, c-format
+msgid "failed to add key '%s' to dictionary"
+msgstr "nie powiod³o siê dodanie klucza '%s' do s³ownika"
+
+#, c-format
+msgid "index must be int or slice, not %s"
+msgstr "indeks musi byæ liczb¹ lub wycinkiem, nie %s"
+
+#, c-format
+msgid "expected str() or unicode() instance, but got %s"
+msgstr "czeka³em na str() lub unicode(), a dosta³em %s"
+
+#, c-format
+msgid "expected bytes() or str() instance, but got %s"
+msgstr "czeka³em na bytes() lub str(), a dosta³em %s"
+
+#, c-format
+msgid ""
+"expected int(), long() or something supporting coercing to long(), but got %s"
+msgstr ""
+"czeka³em na int(), long() lub coœ co mo¿na zmieniæ na long(), ale dosta³em %s"
+
+#, c-format
+msgid "expected int() or something supporting coercing to int(), but got %s"
+msgstr "czeka³em na int() lub coœ co mo¿na zmieniæ na int(), ale dosta³em %s"
+
+msgid "value is too large to fit into C int type"
+msgstr "wartoœæ zbyt du¿a by zmieœci³a siê w typie int C"
+
+msgid "value is too small to fit into C int type"
+msgstr "wartoœæ jest zbyt ma³a by zmieœci³a siê w typie int C"
+
+msgid "number must be greater then zero"
+msgstr "liczba musi byæ wiêksza ni¿ zero"
+
+msgid "number must be greater or equal to zero"
+msgstr "liczba musi byæ wiêksza lub mniejsza ni¿ zero"
+
+msgid "can't delete OutputObject attributes"
+msgstr "nie mogê skasowaæ atrybutów OutputObject"
+
+#, c-format
+msgid "invalid attribute: %s"
+msgstr "niepoprawny atrybut: %s"
+
+msgid "E264: Python: Error initialising I/O objects"
+msgstr "E264: Python: B³¹d w uruchomieniu obiektów I/O"
+
+msgid "failed to change directory"
+msgstr "nie powiod³a siê zmiana katalogu"
+
+#, c-format
+msgid "expected 3-tuple as imp.find_module() result, but got %s"
+msgstr "czeka³em na 3-krotkê jako wynik imp.find_module(), a dosta³em %s"
+
+#, c-format
+msgid "expected 3-tuple as imp.find_module() result, but got tuple of size %d"
+msgstr "czeka³em na 3-krotkê jako wynik imp.find_module(), a dosta³em krotkê o wielkoœci %d"
+
+msgid "internal error: imp.find_module returned tuple with NULL"
+msgstr "wewnêtrzny b³¹d: imp.find_module zwróci³ krotkê z NULL"
+
+msgid "cannot delete vim.Dictionary attributes"
+msgstr "nie mogê usun¹æ atrybutów vim.Dictionary"
+
+msgid "cannot modify fixed dictionary"
+msgstr "nie mogê zmieniæ zablokowanego s³ownika"
+
+#, c-format
+msgid "cannot set attribute %s"
+msgstr "nie mogê ustawiæ atrybutu %s"
+
+msgid "hashtab changed during iteration"
+msgstr "hashtab zmieni³ siê w czasie iteracji"
+
+#, c-format
+msgid "expected sequence element of size 2, but got sequence of size %d"
+msgstr "czeka³em na element sekwencyjny od d³ugoœci 2, a dosta³em sekwencjê o d³ugoœci %d"
+
+msgid "list constructor does not accept keyword arguments"
+msgstr "konstruktor listy nie akceptuje s³ów kluczowych jako argumentów"
+
+msgid "list index out of range"
+msgstr "indeks listy poza zakresem"
+
+#. No more suitable format specifications in python-2.3
+#, c-format
+msgid "internal error: failed to get vim list item %d"
+msgstr "b³¹d wewnêtrzny: nie powiod³o siê pobranie z listy Vima elementu %d"
+
+msgid "failed to add item to list"
+msgstr "nie powiod³o siê dodanie elementu do listy"
+
+#, c-format
+msgid "internal error: no vim list item %d"
+msgstr "b³¹d wewnêtrzny: w liœcie Vima brak elementu %d"
+
+msgid "internal error: failed to add item to list"
+msgstr "b³¹d wewnêtrzny: nie powiod³o siê dodanie elementu do listy"
+
+msgid "cannot delete vim.List attributes"
+msgstr "nie mogê usun¹æ atrybutów vim.List"
+
+msgid "cannot modify fixed list"
+msgstr "nie mogê zmieniæ zablokowanej listy"
+
+#, c-format
+msgid "unnamed function %s does not exist"
+msgstr "nie nazwana funkcja %s nie istnieje"
+
+#, c-format
+msgid "function %s does not exist"
+msgstr "funkcja %s nie istnieje"
+
+msgid "function constructor does not accept keyword arguments"
+msgstr "konstruktor funkcji nie akceptuje s³ów kluczowych jako argumentów"
+
+#, c-format
+msgid "failed to run function %s"
+msgstr "nie mogê uruchomiæ funkcji %s"
+
+msgid "unable to get option value"
+msgstr "nie mogê pobraæ wartoœci opcji"
+
+msgid "internal error: unknown option type"
+msgstr "b³¹d wewnêtrzny: nieznany typ opcji"
+
+msgid "problem while switching windows"
+msgstr "wyst¹pi³ problem w czasie zmiany okien"
+
+#, c-format
+msgid "unable to unset global option %s"
+msgstr "nie mogê wyzerowaæ opcji globalnej %s"
+
+#, c-format
+msgid "unable to unset option %s which does not have global value"
+msgstr "nie mogê wyzerowaæ opcji %s, która nie ma wartoœci globalnej"
+
+msgid "attempt to refer to deleted tab page"
+msgstr "próba odniesienia do skasowanej karty"
+
+msgid "no such tab page"
+msgstr "nie ma takiej karty"
+
+msgid "attempt to refer to deleted window"
+msgstr "próba odniesienia do skasowanego okna"
+
+msgid "readonly attribute: buffer"
+msgstr "atrybut tylko do odczytu: bufor"
+
+msgid "cursor position outside buffer"
+msgstr "pozycja kursora poza buforem"
+
+msgid "no such window"
+msgstr "nie ma takiego okna"
+
+msgid "attempt to refer to deleted buffer"
+msgstr "próba odniesienia do skasowanego bufora"
+
+msgid "failed to rename buffer"
+msgstr "nie powiod³a siê zmiana nazwy bufora"
+
+msgid "mark name must be a single character"
+msgstr "nazwa zak³adki musi byæ pojedynczym znakiem"
+
+#, c-format
+msgid "expected vim.Buffer object, but got %s"
+msgstr "oczekiwa³em na obiekt vim.Buffer, a dosta³em %s"
+
+#, c-format
+msgid "failed to switch to buffer %d"
+msgstr "nie przeszed³em do bufora %d"
+
+#, c-format
+msgid "expected vim.Window object, but got %s"
+msgstr "oczekiwa³em na obiekt vim.Window, a dosta³em %s"
+
+msgid "failed to find window in the current tab page"
+msgstr "nie znaleziono okna na bie¿¹cej karcie"
+
+msgid "did not switch to the specified window"
+msgstr "nie przeszed³em do okreœlonego okna"
+
+#, c-format
+msgid "expected vim.TabPage object, but got %s"
+msgstr "oczekiwa³em na obiekt vim.TabPage, a dosta³em %s"
+
+msgid "did not switch to the specified tab page"
+msgstr "nie przeszed³em do okreœlonej karty"
+
+msgid "failed to run the code"
+msgstr "uruchomienie kodu siê nie powiod³o"
+
+msgid "E858: Eval did not return a valid python object"
+msgstr "E858: eval nie zwróci³o odpowiedniego obiektu pythona"
+
+msgid "E859: Failed to convert returned python object to vim value"
+msgstr "E859: Nie powiod³a siê konwersja obiektu pythona do wartoœci Vima"
+
+#, c-format
+msgid "unable to convert %s to vim dictionary"
+msgstr "nie mo¿na konwertowaæ %s do s³ownika Vima"
+
+#, c-format
+msgid "unable to convert %s to vim structure"
+msgstr "nie mo¿na konwertowaæ %s do struktury Vima"
+
+msgid "internal error: NULL reference passed"
+msgstr "b³¹d wewnêtrzny: przekazano referencjê NULL"
+
+msgid "internal error: invalid value type"
+msgstr "b³¹d wewnêtrzny: b³êdny typ wartoœci"
+
+msgid ""
+"Failed to set path hook: sys.path_hooks is not a list\n"
+"You should now do the following:\n"
+"- append vim.path_hook to sys.path_hooks\n"
+"- append vim.VIM_SPECIAL_PATH to sys.path\n"
+msgstr ""
+"Nie mogê ustawiæ haka œcie¿ki: sys.path_hooks nie jest list¹\n"
+"Powinieneœ teraz wykonaæ nastêpuj¹ce czynnoœci:\n"
+"- dodaæ vim.path_hook do sys.path_hooks\n"
+"- dodaæ vim.VIM_SPECIAL_PATH do sys.path\n"
+
+msgid ""
+"Failed to set path: sys.path is not a list\n"
+"You should now append vim.VIM_SPECIAL_PATH to sys.path"
+msgstr ""
+"Nie mogê ustawiæ œcie¿ki: sys.path nie jest list¹\n"
+"Powinno siê teraz dodaæ vim.VIM_SPECIAL_PATH do sys.path"
+
+#~ msgid "softspace must be an integer"
+#~ msgstr "softspace musi byæ liczb¹ ca³kowit¹"
+
+#~ msgid "<buffer object (deleted) at %p>"
+#~ msgstr "<obiekt bufora (skasowany) w %p>"
+
+#~ msgid ""
+#~ "E281: TCL ERROR: exit code is not int!? Please report this to vim-dev@vim."
+#~ "org"
+#~ msgstr ""
+#~ "E281: B£¥D TCL: kod zakoñczeniowy nie jest ca³kowity!? Proszê z³o¿yæ "
+#~ "raport o tym na vim-dev@vim.org"
+
+#~ msgid ""
+#~ "\n"
+#~ "Arguments recognised by gvim (RISC OS version):\n"
+#~ msgstr ""
+#~ "\n"
+#~ "Argumenty rozpoznawane przez gvim (wersja RISC OS):\n"
+
+#~ msgid "--columns <number>\tInitial width of window in columns"
+#~ msgstr "--columns <number>\tPocz¹tkowa szerokoœæ okna w kolumnach"
+
+#~ msgid "--rows <number>\tInitial height of window in rows"
+#~ msgstr "--rows <number>\tPocz¹tkowa wysokoœæ okna w wierszach"
+
+#~ msgid "E505: "
+#~ msgstr "E505: "
+
+#~ msgid ""
+#~ "\n"
+#~ "RISC OS version"
+#~ msgstr ""
+#~ "\n"
+#~ "wersja dla RISC OS"
+
+#~ msgid "writelines() requires list of strings"
+#~ msgstr "writelines() wymaga listy ci¹gów"
+
+#~ msgid "<window object (deleted) at %p>"
+#~ msgstr "<obiekt okna (skasowany) w %p>"
+
+#~ msgid "<window object (unknown) at %p>"
+#~ msgstr "<obiekt okna (nieznany) w %p>"
+
+#~ msgid "<window %d>"
+#~ msgstr "<okno %d>"
+
+#~ msgid "-name <name>\t\tUse resource as if vim was <name>"
+#~ msgstr "-name <nazwa>\t\tU¿ywaj zasobów tak jak by Vim by³ <nazwa>"
+
+#~ msgid "\t\t\t (Unimplemented)\n"
+#~ msgstr "\t\t\t (Niezaimplementowane)\n"
+
+#~ msgid "E396: containedin argument not accepted here"
+#~ msgstr "E396: argument containedin niedozwolony w tym miejscu"
+
+#~ msgid "Vim dialog..."
+#~ msgstr "Dialog Vima..."
+
+#~ msgid "Font Selection"
+#~ msgstr "Wybór czcionki"
+
+#~ msgid "E290: over-the-spot style requires fontset"
+#~ msgstr "E290: styl nadpunktowy wymaga +fontset"
+
+#~ msgid "E291: Your GTK+ is older than 1.2.3. Status area disabled"
+#~ msgstr "E291: Twój GTK+ jest starszy ni¿ 1.2.3. Pole statusu wy³¹czono"
+
+#~ msgid "E292: Input Method Server is not running"
+#~ msgstr "E292: Serwer metod wprowadzeñ nie jest uruchomiony"
+
+#~ msgid "with GTK-GNOME GUI."
+#~ msgstr "z GTK-GNOME GUI."
+
+#~ msgid "with GTK GUI."
+#~ msgstr "z GTK GUI."
+
+#~ msgid "[NL found]"
+#~ msgstr "[znaleziono NL]"
+
+#~ msgid "E569: maximum number of cscope connections reached"
+#~ msgstr "E569: wyczerpano maksymaln¹ liczbê po³¹czeñ cscope"
diff --git a/src/po/pl.po b/src/po/pl.po
new file mode 100644
index 0000000..288a5e6
--- /dev/null
+++ b/src/po/pl.po
@@ -0,0 +1,6904 @@
+# Polish translation for Vim
+#
+# updated 2013 for vim-7.4
+#
+# FIRST AUTHOR Marcin Dalecki <martin@dalecki.de>, 2000.
+# Mikolaj Machowski <mikmach@wp.pl>, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2013.
+msgid ""
+msgstr ""
+"Project-Id-Version: pl\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2013-07-06 19:33+0200\n"
+"PO-Revision-Date: 2010-08-10 18:15+0200\n"
+"Last-Translator: Mikolaj Machowski <mikmach@wp.pl>\n"
+"Language-Team: Polish\n"
+"Language: pl\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-2\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Lokalize 1.0\n"
+"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
+"|| n%100>=20) ? 1 : 2);\n"
+
+msgid "E831: bf_key_init() called with empty password"
+msgstr "E831: bf_key_init() wywo³any z pustym has³em"
+
+msgid "E820: sizeof(uint32_t) != 4"
+msgstr "E820: sizeof(uint32_t) != 4"
+
+msgid "E817: Blowfish big/little endian use wrong"
+msgstr "E817: Blowfish u¿ywa b³êdnej kolejno¶ci bajtów"
+
+msgid "E818: sha256 test failed"
+msgstr "E818: test sha256 nie powiód³ siê"
+
+msgid "E819: Blowfish test failed"
+msgstr "E819: test Blowfisha nie powiód³ siê"
+
+msgid "[Location List]"
+msgstr "[Lista lokacji]"
+
+msgid "[Quickfix List]"
+msgstr "[Lista quickfix]"
+
+msgid "E855: Autocommands caused command to abort"
+msgstr "E855: Autokomendy spowodowa³y porzucenie komendy"
+
+msgid "E82: Cannot allocate any buffer, exiting..."
+msgstr "E82: Nie mogê zarezerwowaæ bufora; zakoñczenie..."
+
+msgid "E83: Cannot allocate buffer, using other one..."
+msgstr "E83: Nie mogê zarezerwowaæ bufora; u¿ywam innego..."
+
+msgid "E515: No buffers were unloaded"
+msgstr "E515: Nie wy³adowano ¿adnego bufora"
+
+msgid "E516: No buffers were deleted"
+msgstr "E516: Nie skasowano ¿adnego bufora"
+
+msgid "E517: No buffers were wiped out"
+msgstr "E517: Nie wyrzucono ¿adnego bufora"
+
+msgid "1 buffer unloaded"
+msgstr "1 bufor wy³adowany"
+
+#, c-format
+msgid "%d buffers unloaded"
+msgstr "wy³adowano %d buforów"
+
+msgid "1 buffer deleted"
+msgstr "1 bufor skasowany"
+
+#, c-format
+msgid "%d buffers deleted"
+msgstr "%d buforów skasowano"
+
+msgid "1 buffer wiped out"
+msgstr "wyrzucono 1 bufor "
+
+#, c-format
+msgid "%d buffers wiped out"
+msgstr "wyrzucono %d buforów"
+
+msgid "E84: No modified buffer found"
+msgstr "E84: Nie znaleziono zmienionych buforów"
+
+#. back where we started, didn't find anything.
+msgid "E85: There is no listed buffer"
+msgstr "E85: Nie ma wylistowanych buforów"
+
+#, c-format
+msgid "E86: Buffer %ld does not exist"
+msgstr "E86: Bufor \"%ld\" nie istnieje"
+
+msgid "E87: Cannot go beyond last buffer"
+msgstr "E87: Nie mogê przej¶æ poza ostatni bufor"
+
+msgid "E88: Cannot go before first buffer"
+msgstr "E88: Nie mogê przej¶æ przed pierwszy bufor"
+
+#, c-format
+msgid "E89: No write since last change for buffer %ld (add ! to override)"
+msgstr "E89: Nie zapisano zmian w buforze %ld (wymu¶ przez !)"
+
+msgid "E90: Cannot unload last buffer"
+msgstr "E90: Nie mogê wy³adowaæ ostatniego bufora"
+
+msgid "W14: Warning: List of file names overflow"
+msgstr "W14: OSTRZE¯ENIE: Przepe³nienie listy nazw plików"
+
+#, c-format
+msgid "E92: Buffer %ld not found"
+msgstr "E92: Nie znaleziono bufora %ld"
+
+#, c-format
+msgid "E93: More than one match for %s"
+msgstr "E93: Wielokrotne dopasowania dla %s"
+
+#, c-format
+msgid "E94: No matching buffer for %s"
+msgstr "E94: ¯aden bufor nie pasuje do %s"
+
+#, c-format
+msgid "line %ld"
+msgstr "wiersz %ld"
+
+msgid "E95: Buffer with this name already exists"
+msgstr "E95: Bufor o tej nazwie ju¿ istnieje"
+
+msgid " [Modified]"
+msgstr " [Zmieniony]"
+
+msgid "[Not edited]"
+msgstr "[Nie edytowany]"
+
+msgid "[New file]"
+msgstr "[Nowy Plik]"
+
+msgid "[Read errors]"
+msgstr "[B³±d odczytu]"
+
+msgid "[RO]"
+msgstr "[RO]"
+
+msgid "[readonly]"
+msgstr "[tylko odczyt]"
+
+#, c-format
+msgid "1 line --%d%%--"
+msgstr "1 wiersz --%d%%--"
+
+#, c-format
+msgid "%ld lines --%d%%--"
+msgstr "%ld wiersze --%d%%--"
+
+#, c-format
+msgid "line %ld of %ld --%d%%-- col "
+msgstr "wiersz %ld z %ld --%d%%-- kol "
+
+msgid "[No Name]"
+msgstr "[Bez nazwy]"
+
+#. must be a help buffer
+msgid "help"
+msgstr "pomoc"
+
+msgid "[Help]"
+msgstr "[Pomoc]"
+
+msgid "[Preview]"
+msgstr "[Podgl±d]"
+
+msgid "All"
+msgstr "Wszystko"
+
+msgid "Bot"
+msgstr "Dó³"
+
+msgid "Top"
+msgstr "Góra"
+
+msgid ""
+"\n"
+"# Buffer list:\n"
+msgstr ""
+"\n"
+"# Lista buforów:\n"
+
+msgid "[Scratch]"
+msgstr "[Notka]"
+
+msgid ""
+"\n"
+"--- Signs ---"
+msgstr ""
+"\n"
+"--- Znaki ---"
+
+#, c-format
+msgid "Signs for %s:"
+msgstr "Znaki dla %s:"
+
+#, c-format
+msgid " line=%ld id=%d name=%s"
+msgstr " wiersz=%ld id=%d nazwa=%s"
+
+#, c-format
+msgid "E96: Can not diff more than %ld buffers"
+msgstr "E96: Nie mogê zró¿nicowaæ wiêcej ni¿ %ld buforów"
+
+msgid "E810: Cannot read or write temp files"
+msgstr "E810: Nie mogê otworzyæ lub zapisaæ plików tymczasowych"
+
+msgid "E97: Cannot create diffs"
+msgstr "E97: Nie mogê stworzyæ ró¿nic"
+
+msgid "Patch file"
+msgstr "Plik ³ata"
+
+msgid "E816: Cannot read patch output"
+msgstr "E816: Nie mogê odczytaæ wyj¶cia pliku ³aty"
+
+msgid "E98: Cannot read diff output"
+msgstr "E98: Nie mogê wczytaæ wyj¶cia ró¿nicy"
+
+msgid "E99: Current buffer is not in diff mode"
+msgstr "E99: Bie¿±cy bufor nie jest w trybie ró¿nic"
+
+msgid "E793: No other buffer in diff mode is modifiable"
+msgstr "E793: ¯aden inny bufor w trybie diff nie jest modyfikowalny"
+
+msgid "E100: No other buffer in diff mode"
+msgstr "E100: Brak innego bufora w trybie ró¿nic"
+
+msgid "E101: More than two buffers in diff mode, don't know which one to use"
+msgstr ""
+"E101: Wiêcej ni¿ jeden bufor w trybie ró¿nicowania, nie wiem którego u¿yæ"
+
+#, c-format
+msgid "E102: Can't find buffer \"%s\""
+msgstr "E102: Nie mogê znale¼æ bufora \"%s\""
+
+#, c-format
+msgid "E103: Buffer \"%s\" is not in diff mode"
+msgstr "E103: Bufor \"%s\" nie jest w trybie ró¿nicowania"
+
+msgid "E787: Buffer changed unexpectedly"
+msgstr "E787: Nieoczekiwana zmiana bufora"
+
+msgid "E104: Escape not allowed in digraph"
+msgstr "E104: Escape jest niedozwolone w dwugrafie"
+
+msgid "E544: Keymap file not found"
+msgstr "E544: Nie znaleziono pliku rozk³adu klawiszy"
+
+msgid "E105: Using :loadkeymap not in a sourced file"
+msgstr "E105: Zastosowano :loadkeymap w niewczytanym pliku"
+
+msgid "E791: Empty keymap entry"
+msgstr "E791: Pusty wpis keymap"
+
+msgid " Keyword completion (^N^P)"
+msgstr " Dope³nianie s³ów kluczowych (^N^P)"
+
+#. ctrl_x_mode == 0, ^P/^N compl.
+msgid " ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+msgstr " ^X tryb (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+
+msgid " Whole line completion (^L^N^P)"
+msgstr " Dope³nianie pe³nych wierszy (^L^N^P)"
+
+msgid " File name completion (^F^N^P)"
+msgstr " Dope³nianie nazw plików (^F^N^P)"
+
+msgid " Tag completion (^]^N^P)"
+msgstr " Dope³nianie znaczników (^]^N^P)"
+
+msgid " Path pattern completion (^N^P)"
+msgstr " Dope³nianie wzorców tropów (^N^P)"
+
+msgid " Definition completion (^D^N^P)"
+msgstr " Dope³nianie definicji (^D^N^P)"
+
+msgid " Dictionary completion (^K^N^P)"
+msgstr " Dope³nianie ze s³owników (^K^N^P)"
+
+msgid " Thesaurus completion (^T^N^P)"
+msgstr " Dope³nianie z tezaurusa (^T^N^P)"
+
+msgid " Command-line completion (^V^N^P)"
+msgstr " Dope³nianie wiersza poleceñ (^V^N^P)"
+
+msgid " User defined completion (^U^N^P)"
+msgstr "Dope³nianie zdefiniowane przez u¿ytkownika (^U^N^P)"
+
+msgid " Omni completion (^O^N^P)"
+msgstr " Omni uzupe³nianie (^O^N^P)"
+
+msgid " Spelling suggestion (s^N^P)"
+msgstr "Propozycja pisowni (^L^N^P)"
+
+msgid " Keyword Local completion (^N^P)"
+msgstr " Lokalne dope³nianie s³ów kluczowych (^N^P)"
+
+msgid "Hit end of paragraph"
+msgstr "Dobi³em do koñca akapitu"
+
+msgid "E839: Completion function changed window"
+msgstr "E839: Funkcja uzupe³niania zmieni³a okno"
+
+msgid "E840: Completion function deleted text"
+msgstr "E840: Funkcja uzupe³nania usunê³a tekst"
+
+msgid "'dictionary' option is empty"
+msgstr "opcja 'dictionary' jest pusta"
+
+msgid "'thesaurus' option is empty"
+msgstr "opcja 'thesaurus' jest pusta"
+
+#, c-format
+msgid "Scanning dictionary: %s"
+msgstr "Przegl±dam s³ownik: %s"
+
+msgid " (insert) Scroll (^E/^Y)"
+msgstr " (wprowadzanie) Przewijanie (^E/^Y)"
+
+msgid " (replace) Scroll (^E/^Y)"
+msgstr " (zamiana) Przewijanie (^E/^Y)"
+
+#, c-format
+msgid "Scanning: %s"
+msgstr "Przegl±dam: %s"
+
+msgid "Scanning tags."
+msgstr "Przegl±dam znaczniki."
+
+msgid " Adding"
+msgstr " Dodajê"
+
+#. showmode might reset the internal line pointers, so it must
+#. * be called before line = ml_get(), or when this address is no
+#. * longer needed. -- Acevedo.
+#.
+msgid "-- Searching..."
+msgstr "-- Szukam..."
+
+msgid "Back at original"
+msgstr "Z powrotem na pierwotnym"
+
+msgid "Word from other line"
+msgstr "Wyraz z innego wiersza"
+
+msgid "The only match"
+msgstr "Jedyne dopasowanie"
+
+#, c-format
+msgid "match %d of %d"
+msgstr "pasuje %d z %d"
+
+#, c-format
+msgid "match %d"
+msgstr "pasuje %d"
+
+msgid "E18: Unexpected characters in :let"
+msgstr "E18: Nieoczekiwane znaki w :let"
+
+#, c-format
+msgid "E684: list index out of range: %ld"
+msgstr "E684: Indeks listy poza zakresem: %ld"
+
+#, c-format
+msgid "E121: Undefined variable: %s"
+msgstr "E121: Nieokre¶lona zmienna: %s"
+
+msgid "E111: Missing ']'"
+msgstr "E111: Brak ']'"
+
+#, c-format
+msgid "E686: Argument of %s must be a List"
+msgstr "E686: Argument %s musi byæ List±"
+
+#, c-format
+msgid "E712: Argument of %s must be a List or Dictionary"
+msgstr "E712: Argument %s musi byæ List± lub S³ownikiem"
+
+msgid "E713: Cannot use empty key for Dictionary"
+msgstr "E713: Nie mo¿na u¿yæ pustego klucza dla S³ownika"
+
+msgid "E714: List required"
+msgstr "E714: wymagana Lista"
+
+msgid "E715: Dictionary required"
+msgstr "E715: wymagany S³ownik"
+
+#, c-format
+msgid "E118: Too many arguments for function: %s"
+msgstr "E118: Zbyt wiele argumentów dla funkcji: %s"
+
+#, c-format
+msgid "E716: Key not present in Dictionary: %s"
+msgstr "E716: Klucz nie istnieje w S³owniku: %s"
+
+#, c-format
+msgid "E122: Function %s already exists, add ! to replace it"
+msgstr "E122: Funkcja %s ju¿ istnieje; aby j± zamieniæ u¿yj !"
+
+msgid "E717: Dictionary entry already exists"
+msgstr "E717: istnieje ju¿ taki element S³ownika"
+
+msgid "E718: Funcref required"
+msgstr "E718: wymagana Funcref"
+
+msgid "E719: Cannot use [:] with a Dictionary"
+msgstr "E719: Nie mo¿na u¿yæ [:] przy S³owniku"
+
+#, c-format
+msgid "E734: Wrong variable type for %s="
+msgstr "E734: Z³y typ zmiennej dla %s="
+
+#, c-format
+msgid "E130: Unknown function: %s"
+msgstr "E130: Nieznana funkcja: %s"
+
+#, c-format
+msgid "E461: Illegal variable name: %s"
+msgstr "E461: Niedozwolona nazwa zmiennej: %s"
+
+msgid "E806: using Float as a String"
+msgstr "E806: U¿ycie Zmiennoprzecinkowej jako £añcucha"
+
+msgid "E687: Less targets than List items"
+msgstr "E687: Mniej celów ni¿ elementów Listy"
+
+msgid "E688: More targets than List items"
+msgstr "E688: Wiêcej celów ni¿ elementów Listy"
+
+msgid "Double ; in list of variables"
+msgstr "Podwójny ; w li¶cie zmiennych"
+
+#, c-format
+msgid "E738: Can't list variables for %s"
+msgstr "E738: Nie mogê wypisaæ zmiennych dla %s"
+
+msgid "E689: Can only index a List or Dictionary"
+msgstr "E689: Indeks mo¿e istnieæ tylko dla Listy lub S³ownika"
+
+msgid "E708: [:] must come last"
+msgstr "E708: [:] musi byæ ostatnie"
+
+msgid "E709: [:] requires a List value"
+msgstr "E709: [:] wymaga warto¶ci listy"
+
+msgid "E710: List value has more items than target"
+msgstr "E710: Lista ma wiêcej elementów ni¿ cel"
+
+msgid "E711: List value has not enough items"
+msgstr "E711: Lista nie ma wystarczaj±cej ilo¶ci elementów"
+
+msgid "E690: Missing \"in\" after :for"
+msgstr "E690: Brak \"in\" po :for"
+
+#, c-format
+msgid "E107: Missing parentheses: %s"
+msgstr "E107: Brak nawiasów: %s"
+
+#, c-format
+msgid "E108: No such variable: \"%s\""
+msgstr "E108: Nie istnieje zmienna: \"%s\""
+
+msgid "E743: variable nested too deep for (un)lock"
+msgstr "E743: zmienna zagnie¿d¿ona zbyt g³êboko dla (un)lock"
+
+msgid "E109: Missing ':' after '?'"
+msgstr "E109: Brak ':' po '?'"
+
+msgid "E691: Can only compare List with List"
+msgstr "E691: Listê mogê porównaæ tylko z List±"
+
+msgid "E692: Invalid operation for List"
+msgstr "E692: Nieprawid³owa operacja dla Listy"
+
+msgid "E735: Can only compare Dictionary with Dictionary"
+msgstr "E735: S³ownik mogê porównaæ tylko ze S³ownikiem"
+
+msgid "E736: Invalid operation for Dictionary"
+msgstr "E736: Nieprawid³owa operacja dla S³ownika"
+
+msgid "E693: Can only compare Funcref with Funcref"
+msgstr "E693: Funcref mogê porównaæ tylko z Funcref"
+
+msgid "E694: Invalid operation for Funcrefs"
+msgstr "E694: Nieprawid³owa operacja dla Funcref"
+
+msgid "E804: Cannot use '%' with Float"
+msgstr "E804: Nie mogê u¿yæ '%' w Zmiennoprzecinkowej"
+
+msgid "E110: Missing ')'"
+msgstr "E110: Brak ')'"
+
+msgid "E695: Cannot index a Funcref"
+msgstr "E695: Nie mo¿na zindeksowaæ Funcref"
+
+#, c-format
+msgid "E112: Option name missing: %s"
+msgstr "E112: Brak nazwy opcji: %s"
+
+#, c-format
+msgid "E113: Unknown option: %s"
+msgstr "E113: Nieznana opcja: %s"
+
+#, c-format
+msgid "E114: Missing quote: %s"
+msgstr "E114: Brak cudzys³owu: %s"
+
+#, c-format
+msgid "E115: Missing quote: %s"
+msgstr "E115: Brak cudzys³owu: %s"
+
+#, c-format
+msgid "E696: Missing comma in List: %s"
+msgstr "E696: Brakuj±cy przecinek w Li¶cie: '%s"
+
+#, c-format
+msgid "E697: Missing end of List ']': %s"
+msgstr "E697: Brak zakoñczenia Listy ']': %s"
+
+#, c-format
+msgid "E720: Missing colon in Dictionary: %s"
+msgstr "E720: Brak dwukropka w S³owniku: %s"
+
+#, c-format
+msgid "E721: Duplicate key in Dictionary: \"%s\""
+msgstr "E721: Powtórzony klucz w S³owniku: \"%s\""
+
+#, c-format
+msgid "E722: Missing comma in Dictionary: %s"
+msgstr "E722: Brakuj±cy przecinek w S³owniku: %s"
+
+#, c-format
+msgid "E723: Missing end of Dictionary '}': %s"
+msgstr "E723: Brak koñca w S³owniku '}': %s"
+
+msgid "E724: variable nested too deep for displaying"
+msgstr "E724: Zmienna zagnie¿d¿ona zbyt g³êboko by pokazaæ"
+
+#, c-format
+msgid "E740: Too many arguments for function %s"
+msgstr "E740: Zbyt wiele argumentów dla funkcji %s"
+
+#, c-format
+msgid "E116: Invalid arguments for function %s"
+msgstr "E116: Zbyt wiele argumentów dla funkcji %s"
+
+#, c-format
+msgid "E117: Unknown function: %s"
+msgstr "E117: Nieznana funkcja: %s"
+
+#, c-format
+msgid "E119: Not enough arguments for function: %s"
+msgstr "E119: Za ma³o argumentów dla funkcji: %s"
+
+#, c-format
+msgid "E120: Using <SID> not in a script context: %s"
+msgstr "E120: U¿ycie <SID> poza kontekstem skryptu: %s"
+
+#, c-format
+msgid "E725: Calling dict function without Dictionary: %s"
+msgstr "E725: Wywo³anie funkcji \"dict\" bez S³ownika: %s"
+
+msgid "E808: Number or Float required"
+msgstr "E808: Wymagana Liczba lub Zmiennoprzecinkowa"
+
+msgid "add() argument"
+msgstr "argument add()"
+
+msgid "E699: Too many arguments"
+msgstr "E699: Za du¿o argumentów"
+
+msgid "E785: complete() can only be used in Insert mode"
+msgstr "E785: complete() mo¿e byæ u¿yte tylko w trybie Wprowadzania"
+
+#.
+#. * Yes this is ugly, I don't particularly like it either. But doing it
+#. * this way has the compelling advantage that translations need not to
+#. * be touched at all. See below what 'ok' and 'ync' are used for.
+#.
+msgid "&Ok"
+msgstr "&Ok"
+
+#, c-format
+msgid "E737: Key already exists: %s"
+msgstr "E737: Klucz ju¿ istnieje: %s"
+
+msgid "extend() argument"
+msgstr "argument extend()"
+
+msgid "map() argument"
+msgstr "argument map()"
+
+msgid "filter() argument"
+msgstr "argument filter()"
+
+#, c-format
+msgid "+-%s%3ld lines: "
+msgstr "+-%s%3ld wierszy: "
+
+#, c-format
+msgid "E700: Unknown function: %s"
+msgstr "E700: Nieznana funkcja: %s"
+
+msgid ""
+"&OK\n"
+"&Cancel"
+msgstr ""
+"&OK\n"
+"&Zakoñcz"
+
+msgid "called inputrestore() more often than inputsave()"
+msgstr "wywo³ano inputrestore() wiêcej razy ni¿ inputsave()"
+
+msgid "insert() argument"
+msgstr "argument insert()"
+
+msgid "E786: Range not allowed"
+msgstr "E786: Zakres niedozwolony"
+
+msgid "E701: Invalid type for len()"
+msgstr "E701: Nieprawid³owy typ dla len()"
+
+msgid "E726: Stride is zero"
+msgstr "E726: Skok to zero"
+
+msgid "E727: Start past end"
+msgstr "E727: Pocz±tek po koñcu"
+
+msgid "<empty>"
+msgstr "<pusty>"
+
+msgid "E240: No connection to Vim server"
+msgstr "E240: Brak po³±czenia z serwerem Vim"
+
+#, c-format
+msgid "E241: Unable to send to %s"
+msgstr "E241: Nie mogê wys³aæ do %s"
+
+msgid "E277: Unable to read a server reply"
+msgstr "E277: Nie mogê czytaæ odpowiedzi serwera"
+
+msgid "remove() argument"
+msgstr "argument remove()"
+
+msgid "E655: Too many symbolic links (cycle?)"
+msgstr "E655: Za du¿o dowi±zañ symbolicznych (pêtla?)"
+
+msgid "reverse() argument"
+msgstr "argument reverse()"
+
+msgid "E258: Unable to send to client"
+msgstr "E258: Nie mogê wys³aæ do klienta"
+
+msgid "sort() argument"
+msgstr "argument sort()"
+
+msgid "E702: Sort compare function failed"
+msgstr "E702: Funkcja porównywania w sort nie powiod³a siê"
+
+msgid "(Invalid)"
+msgstr "(Niew³a¶ciwe)"
+
+msgid "E677: Error writing temp file"
+msgstr "E677: B³±d zapisywania pliku tymczasowego"
+
+msgid "E805: Using a Float as a Number"
+msgstr "E805: U¿ycie Zmiennoprzecinkowej jako Liczby"
+
+msgid "E703: Using a Funcref as a Number"
+msgstr "E703: U¿ycie Funcref jako Liczby"
+
+msgid "E745: Using a List as a Number"
+msgstr "E745: U¿ycie Listy jako Liczby"
+
+msgid "E728: Using a Dictionary as a Number"
+msgstr "E728: U¿ycie S³ownika jako Liczby"
+
+msgid "E729: using Funcref as a String"
+msgstr "E729: U¿ycie Funcref jako £añcucha"
+
+msgid "E730: using List as a String"
+msgstr "E730: U¿ycie Listy jako £añcucha"
+
+msgid "E731: using Dictionary as a String"
+msgstr "E731: U¿ycie S³ownika jako £añcucha"
+
+#, c-format
+msgid "E706: Variable type mismatch for: %s"
+msgstr "E706: Nieprawid³owy typ zmiennej dla: %s"
+
+#, c-format
+msgid "E795: Cannot delete variable %s"
+msgstr "E795: Nie mogê usun±æ zmiennej %s"
+
+#, c-format
+msgid "E704: Funcref variable name must start with a capital: %s"
+msgstr "E704: Nazwa Funcref musi siê zaczynaæ wielk± liter±: %s"
+
+#, c-format
+msgid "E705: Variable name conflicts with existing function: %s"
+msgstr "E705: Nazwa zmiennej jest w konflikcie z istniej±c± funkcj±: %s"
+
+#, c-format
+msgid "E741: Value is locked: %s"
+msgstr "E741: Warto¶æ jest zablokowana: %s"
+
+msgid "Unknown"
+msgstr "Nieznane"
+
+#, c-format
+msgid "E742: Cannot change value of %s"
+msgstr "E742: Nie mogê zmieniæ warto¶ci %s"
+
+msgid "E698: variable nested too deep for making a copy"
+msgstr "E698: Zmienna zagnie¿d¿ona zbyt g³êboko by zrobiæ kopiê"
+
+#, c-format
+msgid "E123: Undefined function: %s"
+msgstr "E123: Nieznana funkcja: %s"
+
+#, c-format
+msgid "E124: Missing '(': %s"
+msgstr "E124: Brak '(': %s"
+
+msgid "E862: Cannot use g: here"
+msgstr "E862: Nie mo¿na tutaj u¿yæ g:"
+
+#, c-format
+msgid "E125: Illegal argument: %s"
+msgstr "E125: Niedozwolony argument: %s"
+
+#, c-format
+msgid "E853: Duplicate argument name: %s"
+msgstr "E853: Powtórzona nazwa argumentu: %s"
+
+msgid "E126: Missing :endfunction"
+msgstr "E126: Brak :endfunction"
+
+#, c-format
+msgid "E707: Function name conflicts with variable: %s"
+msgstr "E707: Nazwa funkcji jest w konflikcie ze zmienn±: %s"
+
+#, c-format
+msgid "E127: Cannot redefine function %s: It is in use"
+msgstr "E127: Nie mogê redefiniowaæ funkcji %s: jest w u¿yciu"
+
+#, c-format
+msgid "E746: Function name does not match script file name: %s"
+msgstr "E746: Nazwa funkcji nie pasuje do nazwy skryptu: %s"
+
+msgid "E129: Function name required"
+msgstr "E129: Wymagana jest nazwa funkcji"
+
+#, c-format
+msgid "E128: Function name must start with a capital or contain a colon: %s"
+msgstr ""
+"E128: Nazwa funkcji musi rozpoczynaæ siê wielk± liter± lub zawieraæ "
+"dwukropek: %s"
+
+#, c-format
+msgid "E131: Cannot delete function %s: It is in use"
+msgstr "E131: Nie mogê skasowaæ funkcji %s: jest w u¿yciu"
+
+msgid "E132: Function call depth is higher than 'maxfuncdepth'"
+msgstr "E132: Zagnie¿d¿enie wywo³añ funkcji ponad 'maxfuncdepth'"
+
+#, c-format
+msgid "calling %s"
+msgstr "wywo³ujê %s"
+
+#, c-format
+msgid "%s aborted"
+msgstr "porzucono %s"
+
+#, c-format
+msgid "%s returning #%ld"
+msgstr "%s zwraca #%ld"
+
+#, c-format
+msgid "%s returning %s"
+msgstr "%s zwraca %s"
+
+#, c-format
+msgid "continuing in %s"
+msgstr "kontynuacja w %s"
+
+msgid "E133: :return not inside a function"
+msgstr "E133: :return poza funkcj±"
+
+msgid ""
+"\n"
+"# global variables:\n"
+msgstr ""
+"\n"
+"# zmienne globalne:\n"
+
+msgid ""
+"\n"
+"\tLast set from "
+msgstr ""
+"\n"
+"\tOstatnie ustawienie przez "
+
+msgid "No old files"
+msgstr "Brak starych plików"
+
+msgid "Entering Debug mode. Type \"cont\" to continue."
+msgstr "Wchodzê w tryb odpluskwiania. Wprowad¼ \"cont\" aby kontynuowaæ."
+
+#, c-format
+msgid "line %ld: %s"
+msgstr "wiersz %ld: %s"
+
+#, c-format
+msgid "cmd: %s"
+msgstr "cmd: %s"
+
+#, c-format
+msgid "Breakpoint in \"%s%s\" line %ld"
+msgstr "Punkt kontrolny w \"%s%s\" wiersz %ld"
+
+#, c-format
+msgid "E161: Breakpoint not found: %s"
+msgstr "E161: Nie znaleziono punktu kontrolnego: %s"
+
+msgid "No breakpoints defined"
+msgstr "Nie okre¶lono ¿adnych punktów kontrolnych"
+
+#, c-format
+msgid "%3d %s %s line %ld"
+msgstr "%3d %s %s wiersz %ld"
+
+msgid "E750: First use \":profile start {fname}\""
+msgstr "E750: Pierwsze u¿ycie \":profile start {fname}\""
+
+msgid "Save As"
+msgstr "Zapisz jako"
+
+#, c-format
+msgid "Save changes to \"%s\"?"
+msgstr "Zachowaæ zmiany w \"%s\"?"
+
+msgid "Untitled"
+msgstr "Bez Tytu³u"
+
+#, c-format
+msgid "E162: No write since last change for buffer \"%s\""
+msgstr "E162: Nie zapisano zmian w buforze \"%s\""
+
+msgid "Warning: Entered other buffer unexpectedly (check autocommands)"
+msgstr "OSTRZE¯ENIE: Nieoczekiwane wej¶cie w inny bufor (sprawd¼ autokomendy)"
+
+msgid "E163: There is only one file to edit"
+msgstr "E163: Tylko jeden plik w edycji"
+
+msgid "E164: Cannot go before first file"
+msgstr "E164: Nie mo¿na przej¶æ przed pierwszy plik"
+
+msgid "E165: Cannot go beyond last file"
+msgstr "E165: Nie mo¿na przej¶æ za ostatni plik"
+
+#, c-format
+msgid "E666: compiler not supported: %s"
+msgstr "E666: nie wspierany kompilator: %s"
+
+#, c-format
+msgid "Searching for \"%s\" in \"%s\""
+msgstr "Szukanie \"%s\" w \"%s\""
+
+#, c-format
+msgid "Searching for \"%s\""
+msgstr "Szukanie \"%s\""
+
+#, c-format
+msgid "not found in 'runtimepath': \"%s\""
+msgstr "nie znaleziono w 'runtimepath': \"%s\""
+
+msgid "Source Vim script"
+msgstr "Wczytaj skrypt Vima"
+
+#, c-format
+msgid "Cannot source a directory: \"%s\""
+msgstr "Nie mo¿na wczytaæ katalogu: \"%s\""
+
+#, c-format
+msgid "could not source \"%s\""
+msgstr "nie mog³em wczytaæ \"%s\""
+
+#, c-format
+msgid "line %ld: could not source \"%s\""
+msgstr "wiersz: %ld nie mog³em wczytaæ \"%s\""
+
+#, c-format
+msgid "sourcing \"%s\""
+msgstr "wczytywanie \"%s\""
+
+#, c-format
+msgid "line %ld: sourcing \"%s\""
+msgstr "wiersz %ld: wczytywanie \"%s\""
+
+#, c-format
+msgid "finished sourcing %s"
+msgstr "skoñczono wczytywanie %s"
+
+msgid "modeline"
+msgstr "modeline"
+
+msgid "--cmd argument"
+msgstr "--cmd argument"
+
+msgid "-c argument"
+msgstr "-c argument"
+
+msgid "environment variable"
+msgstr "zmienna ¶rodowiskowa"
+
+msgid "error handler"
+msgstr "obs³uga b³êdu"
+
+msgid "W15: Warning: Wrong line separator, ^M may be missing"
+msgstr "W15: OSTRZE¯ENIE: Niew³a¶ciwy separator wierszy, pewnie brak ^M"
+
+msgid "E167: :scriptencoding used outside of a sourced file"
+msgstr "E167: u¿yto :scriptencoding poza wczytywanym plikiem"
+
+msgid "E168: :finish used outside of a sourced file"
+msgstr "E168: u¿yto :finish poza wczytywanym plikiem"
+
+#, c-format
+msgid "Current %slanguage: \"%s\""
+msgstr "Bie¿±cy %sjêzyk: \"%s\""
+
+#, c-format
+msgid "E197: Cannot set language to \"%s\""
+msgstr "E197: Nie mogê ustawiæ jêzyka na \"%s\""
+
+#, c-format
+msgid "<%s>%s%s %d, Hex %02x, Octal %03o"
+msgstr "<%s>%s%s %d, Hex %02x, Oktal %03o"
+
+#, c-format
+msgid "> %d, Hex %04x, Octal %o"
+msgstr "> %d, Hex %04x, Oktal %o"
+
+#, c-format
+msgid "> %d, Hex %08x, Octal %o"
+msgstr "> %d, Hex %08x, Oktal %o"
+
+msgid "E134: Move lines into themselves"
+msgstr "E134: Przeniesienie wierszy na siebie samych"
+
+msgid "1 line moved"
+msgstr "1 wiersz przeniesiony"
+
+#, c-format
+msgid "%ld lines moved"
+msgstr "%ld wiersze przeniesione"
+
+#, c-format
+msgid "%ld lines filtered"
+msgstr "%ld wierszy przefiltrowanych"
+
+msgid "E135: *Filter* Autocommands must not change current buffer"
+msgstr "E135: Autokomendy *Filter* nie mog± zmieniaæ bie¿±cego bufora"
+
+msgid "[No write since last change]\n"
+msgstr "[Brak zapisu od czasu ostatniej zmiany]\n"
+
+#, c-format
+msgid "%sviminfo: %s in line: "
+msgstr "%sviminfo: %s w wierszu: "
+
+msgid "E136: viminfo: Too many errors, skipping rest of file"
+msgstr "E136: viminfo: Zbyt wiele b³êdów; pomijam resztê pliku"
+
+#, c-format
+msgid "Reading viminfo file \"%s\"%s%s%s"
+msgstr "Wczytujê plik viminfo \"%s\"%s%s%s"
+
+msgid " info"
+msgstr " informacja"
+
+msgid " marks"
+msgstr " zak³adki"
+
+msgid " oldfiles"
+msgstr " stare pliki"
+
+msgid " FAILED"
+msgstr " NIE POWIOD£O SIÊ"
+
+#. avoid a wait_return for this message, it's annoying
+#, c-format
+msgid "E137: Viminfo file is not writable: %s"
+msgstr "E137: Plik viminfo jest niezapisywalny: %s"
+
+#, c-format
+msgid "E138: Can't write viminfo file %s!"
+msgstr "E138: Nie mogê zapisaæ pliku viminfo %s!"
+
+#, c-format
+msgid "Writing viminfo file \"%s\""
+msgstr "Zapisujê plik viminfo \"%s\""
+
+#. Write the info:
+#, c-format
+msgid "# This viminfo file was generated by Vim %s.\n"
+msgstr "# Ten plik viminfo zosta³ wygenerowany przez Vima %s.\n"
+
+msgid ""
+"# You may edit it if you're careful!\n"
+"\n"
+msgstr ""
+"# Mo¿esz go ostro¿nie edytowaæ!\n"
+"\n"
+
+msgid "# Value of 'encoding' when this file was written\n"
+msgstr "# Warto¶æ 'encoding' w czasie zapisu tego pliku\n"
+
+msgid "Illegal starting char"
+msgstr "Niedopuszczalny pocz±tkowy znak"
+
+msgid "Write partial file?"
+msgstr "Zapisaæ czê¶ciowo plik?"
+
+msgid "E140: Use ! to write partial buffer"
+msgstr "E140: Stosuj ! do zapisania czê¶ciowo bufora"
+
+#, c-format
+msgid "Overwrite existing file \"%s\"?"
+msgstr "Nadpisaæ istniej±cy plik \"%s\"?"
+
+#, c-format
+msgid "Swap file \"%s\" exists, overwrite anyway?"
+msgstr "Plik wymiany \"%s\" istnieje, czy go nadpisaæ?"
+
+#, c-format
+msgid "E768: Swap file exists: %s (:silent! overrides)"
+msgstr "E768: Plik wymiany istnieje: %s (wymu¶ poprzez :silent!)"
+
+#, c-format
+msgid "E141: No file name for buffer %ld"
+msgstr "E141: Brak nazwy pliku dla bufora %ld"
+
+msgid "E142: File not written: Writing is disabled by 'write' option"
+msgstr "E142: Plik niezapisany: Zapis jest wy³±czony opcj± 'write'"
+
+#, c-format
+msgid ""
+"'readonly' option is set for \"%s\".\n"
+"Do you wish to write anyway?"
+msgstr ""
+"opcja 'readonly' nastawiona dla \"%s\".\n"
+"Czy chcesz go pomimo tego zapisaæ?"
+
+#, c-format
+msgid ""
+"File permissions of \"%s\" are read-only.\n"
+"It may still be possible to write it.\n"
+"Do you wish to try?"
+msgstr ""
+"Prawa pliku \"%s\" s± tylko do odczytu.\n"
+"Mimo to byæ mo¿e uda siê zmieniæ ten plik.\n"
+"Chcesz spróbowaæ?"
+
+#, c-format
+msgid "E505: \"%s\" is read-only (add ! to override)"
+msgstr "E505: \"%s\" jest tylko do odczytu (dodaj ! aby wymusiæ)"
+
+msgid "Edit File"
+msgstr "Edytuj Plik"
+
+#, c-format
+msgid "E143: Autocommands unexpectedly deleted new buffer %s"
+msgstr "E143: Autokomendy nieoczekiwanie skasowa³y nowy bufor %s"
+
+msgid "E144: non-numeric argument to :z"
+msgstr "E144: nienumeryczny argument dla :z"
+
+msgid "E145: Shell commands not allowed in rvim"
+msgstr "E145: Komendy pow³oki s± niedozwolone w rvim"
+
+msgid "E146: Regular expressions can't be delimited by letters"
+msgstr "E146: Wzorce regularne nie mog± byæ rozgraniczane literami"
+
+#, c-format
+msgid "replace with %s (y/n/a/q/l/^E/^Y)?"
+msgstr "zamieñ na %s (y/n/a/q/l/^E/^Y)?"
+
+msgid "(Interrupted) "
+msgstr "(Przerwane) "
+
+msgid "1 match"
+msgstr "1 pasuje"
+
+msgid "1 substitution"
+msgstr "1 podstawienie "
+
+#, c-format
+msgid "%ld matches"
+msgstr "%ld dopasowañ"
+
+#, c-format
+msgid "%ld substitutions"
+msgstr "%ld podstawieñ"
+
+msgid " on 1 line"
+msgstr " w 1 wierszu"
+
+#, c-format
+msgid " on %ld lines"
+msgstr " w %ld wierszach"
+
+msgid "E147: Cannot do :global recursive"
+msgstr "E147: Nie mogê wykonaæ :global rekursywnie"
+
+msgid "E148: Regular expression missing from global"
+msgstr "E148: Brak wzorca regularnego w :global"
+
+# c-format
+#, c-format
+msgid "Pattern found in every line: %s"
+msgstr "Wzorzec znaleziono w ka¿dym wierszu: %s"
+
+#, c-format
+msgid "Pattern not found: %s"
+msgstr "Nie znaleziono wzorca: %s"
+
+msgid ""
+"\n"
+"# Last Substitute String:\n"
+"$"
+msgstr ""
+"\n"
+"# Ostatni podstawiany ci±g:\n"
+"$"
+
+msgid "E478: Don't panic!"
+msgstr "E478: Nie panikuj!"
+
+#, c-format
+msgid "E661: Sorry, no '%s' help for %s"
+msgstr "E661: Przykro mi, brak '%s' pomocy dla %s"
+
+#, c-format
+msgid "E149: Sorry, no help for %s"
+msgstr "E149: Przykro mi, ale brak pomocy o %s"
+
+#, c-format
+msgid "Sorry, help file \"%s\" not found"
+msgstr "Przykro mi, nie ma pliku pomocy \"%s\""
+
+#, c-format
+msgid "E150: Not a directory: %s"
+msgstr "E150: Nie jest katalogiem: %s"
+
+#, c-format
+msgid "E152: Cannot open %s for writing"
+msgstr "E152: Nie mogê otworzyæ %s do zapisu"
+
+#, c-format
+msgid "E153: Unable to open %s for reading"
+msgstr "E153: Nie mogê otworzyæ %s do odczytu"
+
+#, c-format
+msgid "E670: Mix of help file encodings within a language: %s"
+msgstr "E670: Mieszanka kodowañ w pliku pomocy w ramach jêzyka: %s"
+
+#, c-format
+msgid "E154: Duplicate tag \"%s\" in file %s/%s"
+msgstr "E154: Powtórzony znacznik \"%s\" w pliku %s/%s"
+
+#, c-format
+msgid "E160: Unknown sign command: %s"
+msgstr "E160: Nieznana komenda znaku: %s"
+
+msgid "E156: Missing sign name"
+msgstr "E156: Brak nazwy znaku"
+
+msgid "E612: Too many signs defined"
+msgstr "E612: Zbyt wiele nazw znaków"
+
+#, c-format
+msgid "E239: Invalid sign text: %s"
+msgstr "E239: Niew³a¶ciwy tekst znaku: %s"
+
+#, c-format
+msgid "E155: Unknown sign: %s"
+msgstr "E155: Nieznany znak: %s"
+
+msgid "E159: Missing sign number"
+msgstr "E159: Brak numeru znaku"
+
+#, c-format
+msgid "E158: Invalid buffer name: %s"
+msgstr "E158: Niew³a¶ciwa nazwa bufora: %s"
+
+#, c-format
+msgid "E157: Invalid sign ID: %ld"
+msgstr "E157: Niew³a¶ciwe ID znaku: %ld"
+
+msgid " (NOT FOUND)"
+msgstr " (NIE ZNALEZIONO)"
+
+msgid " (not supported)"
+msgstr "(nie wspomagane)"
+
+msgid "[Deleted]"
+msgstr "[Skasowano]"
+
+msgid "Entering Ex mode. Type \"visual\" to go to Normal mode."
+msgstr "Wchodzê w tryb Ex. Wprowad¼ \"visual\" aby przej¶æ do trybu Normal."
+
+msgid "E501: At end-of-file"
+msgstr "E501: Na koñcu pliku"
+
+msgid "E169: Command too recursive"
+msgstr "E169: Komenda zbyt rekursywna"
+
+#, c-format
+msgid "E605: Exception not caught: %s"
+msgstr "E605: Nie znaleziono wyj±tku: %s"
+
+msgid "End of sourced file"
+msgstr "Koniec wczytywanego pliku"
+
+msgid "End of function"
+msgstr "Koniec funkcji"
+
+msgid "E464: Ambiguous use of user-defined command"
+msgstr ""
+"E464: Niejednoznaczne zastosowanie komendy zdefiniowanej przez u¿ytkownika"
+
+msgid "E492: Not an editor command"
+msgstr "E492: Nie jest komend± edytora"
+
+msgid "E493: Backwards range given"
+msgstr "E493: Dano wsteczny zakres"
+
+msgid "Backwards range given, OK to swap"
+msgstr "Dano wsteczny zakres; zamiana jest mo¿liwa"
+
+msgid "E494: Use w or w>>"
+msgstr "E494: Stosuj w lub w>>"
+
+msgid "E319: Sorry, the command is not available in this version"
+msgstr "E319: Przykro mi, ale ta komenda nie jest dostêpna w tej wersji"
+
+msgid "E172: Only one file name allowed"
+msgstr "E172: Tylko pojedyncza nazwa pliku dozwolona"
+
+msgid "1 more file to edit. Quit anyway?"
+msgstr "1 wiêcej plik do edycji. Mimo to wyj¶æ?"
+
+#, c-format
+msgid "%d more files to edit. Quit anyway?"
+msgstr "jeszcze %d plików do edycji. Mimo to wyj¶æ?"
+
+msgid "E173: 1 more file to edit"
+msgstr "E173: 1 wiêcej plik do edycji"
+
+#, c-format
+msgid "E173: %ld more files to edit"
+msgstr "E173: jeszcze %ld plików do edycji"
+
+msgid "E174: Command already exists: add ! to replace it"
+msgstr "E174: Komenda ju¿ istnieje; aby j± przedefiniowaæ stosuj !"
+
+msgid ""
+"\n"
+" Name Args Range Complete Definition"
+msgstr ""
+"\n"
+" Nazwa Arg. Zak. Gotowo¶æ Definicja"
+
+msgid "No user-defined commands found"
+msgstr "Nie znaleziono komend zdefiniowanych przez u¿ytkownika"
+
+msgid "E175: No attribute specified"
+msgstr "E175: Nie okre¶lono atrybutu"
+
+msgid "E176: Invalid number of arguments"
+msgstr "E176: Niew³a¶ciwa ilo¶æ argumentów"
+
+msgid "E177: Count cannot be specified twice"
+msgstr "E177: Mno¿nik nie mo¿e byæ podany dwukrotnie"
+
+msgid "E178: Invalid default value for count"
+msgstr "E178: Niew³a¶ciwa domy¶lna warto¶æ mno¿nika"
+
+msgid "E179: argument required for -complete"
+msgstr "E179: -complete wymaga argumentu"
+
+#, c-format
+msgid "E181: Invalid attribute: %s"
+msgstr "E181: Niew³a¶ciwy atrybut: %s"
+
+msgid "E182: Invalid command name"
+msgstr "E182: Niew³a¶ciwa nazwa komendy"
+
+msgid "E183: User defined commands must start with an uppercase letter"
+msgstr ""
+"E183: Komendy zdefiniowane przez u¿ytkownika musz± rozpoczynaæ siê du¿± "
+"liter±"
+
+msgid "E841: Reserved name, cannot be used for user defined command"
+msgstr ""
+"E841: Nazwa zastrze¿ona, nie mo¿na jej u¿yæ w komendzie u¿ytkownika"
+
+#, c-format
+msgid "E184: No such user-defined command: %s"
+msgstr "E184: Nie ma takiej komendy u¿ytkownika: %s"
+
+#, c-format
+msgid "E180: Invalid complete value: %s"
+msgstr "E180: Niew³a¶ciwa warto¶æ dope³niania: %s"
+
+msgid "E468: Completion argument only allowed for custom completion"
+msgstr ""
+"E468: Argument depe³niania dozwolony wy³±cznie dla dope³niania u¿ytkownika"
+
+msgid "E467: Custom completion requires a function argument"
+msgstr "E467: Dope³nianie u¿ytkownika wymaga funkcji jako argumentu"
+
+msgid "unknown"
+msgstr "nieznany"
+
+#, c-format
+msgid "E185: Cannot find color scheme '%s'"
+msgstr "E185: Nie mogê znale¼æ zestawu kolorów '%s'"
+
+msgid "Greetings, Vim user!"
+msgstr "Witaj u¿ytkowniku Vima!"
+
+msgid "E784: Cannot close last tab page"
+msgstr "E784: Nie mogê zamkn±æ ostatniej karty"
+
+msgid "Already only one tab page"
+msgstr "Jest ju¿ tylko jedna karta"
+
+msgid "Edit File in new window"
+msgstr "Edytuj plik w nowym oknie"
+
+#, c-format
+msgid "Tab page %d"
+msgstr "Karta %d"
+
+msgid "No swap file"
+msgstr "Brak pliku wymiany"
+
+msgid "Append File"
+msgstr "Do³±cz plik"
+
+msgid "E747: Cannot change directory, buffer is modified (add ! to override)"
+msgstr ""
+"E747: Nie mogê zmieniæ katalogu, bufor zosta³ zmodyfikowany (dodaj ! aby "
+"wymusiæ)"
+
+msgid "E186: No previous directory"
+msgstr "E186: Nie ma poprzedniego katalogu"
+
+msgid "E187: Unknown"
+msgstr "E187: Nieznany"
+
+msgid "E465: :winsize requires two number arguments"
+msgstr "E465: :winsize wymaga dwóch argumentów numerycznych"
+
+#, c-format
+msgid "Window position: X %d, Y %d"
+msgstr "Pozycja okna: X %d, Y %d"
+
+msgid "E188: Obtaining window position not implemented for this platform"
+msgstr ""
+"E188: Pozyskiwanie pozycji okna nie jest zaimplementowane dla tego systemu"
+
+msgid "E466: :winpos requires two number arguments"
+msgstr "E466: :winpos wymaga dwóch argumentów numerycznych"
+
+msgid "Save Redirection"
+msgstr "Zapisz przekierowanie"
+
+msgid "Save View"
+msgstr "Zapisz widok"
+
+msgid "Save Session"
+msgstr "Zapisz sesjê"
+
+msgid "Save Setup"
+msgstr "Zapisz ustawienia"
+
+#, c-format
+msgid "E739: Cannot create directory: %s"
+msgstr "E739: Nie mogê utworzyæ katalogu: %s"
+
+#, c-format
+msgid "E189: \"%s\" exists (add ! to override)"
+msgstr "E189: \"%s\" istnieje (wymu¶ poprzez !)"
+
+#, c-format
+msgid "E190: Cannot open \"%s\" for writing"
+msgstr "E190: Nie mogê otworzyæ \"%s\" do zapisu"
+
+#. set mark
+msgid "E191: Argument must be a letter or forward/backward quote"
+msgstr "E191: Argument musi byæ liter± albo cudzys³owem w przód/ty³"
+
+msgid "E192: Recursive use of :normal too deep"
+msgstr "E192: Rekursywne zastosowanie :normal za g³êbokie"
+
+msgid "E809: #< is not available without the +eval feature"
+msgstr "E809: #< nie jest dostêpne bez w³a¶ciwo¶ci +eval"
+
+msgid "E194: No alternate file name to substitute for '#'"
+msgstr "E194: Brak nazwy zamiennego pliku do podstawienia pod '#'"
+
+msgid "E495: no autocommand file name to substitute for \"<afile>\""
+msgstr "E495: brak nazwy pliku autokomend do podstawienia pod \"<afile>\""
+
+msgid "E496: no autocommand buffer number to substitute for \"<abuf>\""
+msgstr "E496: brak numeru bufora autokomend do podstawienia pod \"<abuf>\""
+
+msgid "E497: no autocommand match name to substitute for \"<amatch>\""
+msgstr "E497: brak nazwy dopasowania autokomend pod \"<amatch>\""
+
+msgid "E498: no :source file name to substitute for \"<sfile>\""
+msgstr "E498: brak nazwy pliku :source do postawienia pod \"<sfile>\""
+
+msgid "E842: no line number to use for \"<slnum>\""
+msgstr "E842: brak numeru linii by u¿yæ z \"<slnum>\""
+
+#, no-c-format
+msgid "E499: Empty file name for '%' or '#', only works with \":p:h\""
+msgstr "E499: Pusta nazwa pliku dla '%' lub '#', dzia³a tylko z \":p:h\""
+
+msgid "E500: Evaluates to an empty string"
+msgstr "E500: Wynikiem jest pusty ci±g"
+
+msgid "E195: Cannot open viminfo file for reading"
+msgstr "E195: Nie mogê otworzyæ pliku viminfo do odczytu"
+
+msgid "E196: No digraphs in this version"
+msgstr "E196: Brak dwugrafów w tej wersji"
+
+msgid "E608: Cannot :throw exceptions with 'Vim' prefix"
+msgstr "E608: Nie mo¿na ':throw' wyj±tków z prefiksem 'Vim'"
+
+#. always scroll up, don't overwrite
+#, c-format
+msgid "Exception thrown: %s"
+msgstr "Wyj±tek: %s"
+
+#, c-format
+msgid "Exception finished: %s"
+msgstr "Wyj±tek zakoñczony: %s"
+
+#, c-format
+msgid "Exception discarded: %s"
+msgstr "Wyj±tek odrzucony: %s"
+
+#, c-format
+msgid "%s, line %ld"
+msgstr "%s, wiersz %ld"
+
+#. always scroll up, don't overwrite
+#, c-format
+msgid "Exception caught: %s"
+msgstr "Wyj±tek przechwycony: %s"
+
+#, c-format
+msgid "%s made pending"
+msgstr "%s zosta³ zawieszony"
+
+#, c-format
+msgid "%s resumed"
+msgstr "%s przywrócony"
+
+#, c-format
+msgid "%s discarded"
+msgstr "%s odrzucony"
+
+msgid "Exception"
+msgstr "Wyj±tek"
+
+msgid "Error and interrupt"
+msgstr "B³±d i przerwanie"
+
+msgid "Error"
+msgstr "B³±d"
+
+#. if (pending & CSTP_INTERRUPT)
+msgid "Interrupt"
+msgstr "Przerwanie"
+
+msgid "E579: :if nesting too deep"
+msgstr "E579: zbyt g³êbokie zagnie¿d¿enie :if"
+
+msgid "E580: :endif without :if"
+msgstr "E580: :endif bez :if"
+
+msgid "E581: :else without :if"
+msgstr "E581: :else bez :if"
+
+msgid "E582: :elseif without :if"
+msgstr "E582: :elseif bez :if"
+
+msgid "E583: multiple :else"
+msgstr "E583: wielokrotne :else"
+
+msgid "E584: :elseif after :else"
+msgstr "E584: :elseif po :else"
+
+msgid "E585: :while/:for nesting too deep"
+msgstr "E585: zbyt g³êbokie zagnie¿d¿enie :while/:for"
+
+msgid "E586: :continue without :while or :for"
+msgstr "E586: :continue bez :while lub :for"
+
+msgid "E587: :break without :while or :for"
+msgstr "E587: :break bez :while lub :for"
+
+msgid "E732: Using :endfor with :while"
+msgstr "E732: U¿ycie :endfor z :while"
+
+msgid "E733: Using :endwhile with :for"
+msgstr "E733: U¿ycie :endwhile z :for"
+
+msgid "E601: :try nesting too deep"
+msgstr "E601: zbyt g³êbokie zagnie¿d¿enie :try"
+
+msgid "E603: :catch without :try"
+msgstr "E603: :catch bez :try"
+
+#. Give up for a ":catch" after ":finally" and ignore it.
+#. * Just parse.
+msgid "E604: :catch after :finally"
+msgstr "E604: :catch za :finally"
+
+msgid "E606: :finally without :try"
+msgstr "E606: :finally bez :try"
+
+#. Give up for a multiple ":finally" and ignore it.
+msgid "E607: multiple :finally"
+msgstr "E607: wielokrotne :finally"
+
+msgid "E602: :endtry without :try"
+msgstr "E602: :endtry bez :try"
+
+msgid "E193: :endfunction not inside a function"
+msgstr "E193: :endfunction poza funkcj±"
+
+msgid "E788: Not allowed to edit another buffer now"
+msgstr "E788: Nie mo¿na teraz edytowaæ innego bufora"
+
+msgid "E811: Not allowed to change buffer information now"
+msgstr "E811: Nie mo¿na teraz zmieniaæ informacji o buforze"
+
+msgid "tagname"
+msgstr "nazwa znacznika"
+
+msgid " kind file\n"
+msgstr " pokrewny plik\n"
+
+msgid "'history' option is zero"
+msgstr "opcja 'history' jest zerowa"
+
+#, c-format
+msgid ""
+"\n"
+"# %s History (newest to oldest):\n"
+msgstr ""
+"\n"
+"# %s Historia (od najnowszych po najstarsze):\n"
+
+msgid "Command Line"
+msgstr "Wiersz poleceñ"
+
+msgid "Search String"
+msgstr "Szukany ci±g"
+
+msgid "Expression"
+msgstr "Wyra¿enie"
+
+msgid "Input Line"
+msgstr "Wiersz wprowadzeñ"
+
+msgid "E198: cmd_pchar beyond the command length"
+msgstr "E198: cmd_pchar przekracza d³ugo¶æ polecenia"
+
+msgid "E199: Active window or buffer deleted"
+msgstr "E199: Aktywny widok lub bufor skasowany"
+
+msgid "E812: Autocommands changed buffer or buffer name"
+msgstr "E812: Autokomendy zmieni³y bufor lub jego nazwê"
+
+msgid "Illegal file name"
+msgstr "Niedopuszczalna nazwa pliku"
+
+msgid "is a directory"
+msgstr "jest katalogiem"
+
+msgid "is not a file"
+msgstr "nie jest plikiem"
+
+msgid "is a device (disabled with 'opendevice' option)"
+msgstr "jest urz±dzeniem (wy³±czonym w opcji 'opendevice')"
+
+msgid "[New File]"
+msgstr "[Nowy Plik]"
+
+msgid "[New DIRECTORY]"
+msgstr "[Nowy KATALOG]"
+
+msgid "[File too big]"
+msgstr "[Za du¿y plik]"
+
+msgid "[Permission Denied]"
+msgstr "[Nie dozwolono]"
+
+msgid "E200: *ReadPre autocommands made the file unreadable"
+msgstr "E200: Autokomendy *ReadPre zrobi³y plik nieodczytywalnym"
+
+msgid "E201: *ReadPre autocommands must not change current buffer"
+msgstr "E201: Autokomendy *ReadPre nie mog± zmieniaæ bie¿±cego bufora"
+
+msgid "Vim: Reading from stdin...\n"
+msgstr "Vim: Wczytywanie ze stdin...\n"
+
+msgid "Reading from stdin..."
+msgstr "Wczytywanie ze stdin..."
+
+#. Re-opening the original file failed!
+msgid "E202: Conversion made file unreadable!"
+msgstr "E202: Nie mo¿na otworzyæ pliku utworzonego przez przemianê!"
+
+msgid "[fifo/socket]"
+msgstr "[fifo/socket]"
+
+msgid "[fifo]"
+msgstr "[fifo]"
+
+msgid "[socket]"
+msgstr "[socket]"
+
+msgid "[character special]"
+msgstr "[specjalny znak]"
+
+msgid "[CR missing]"
+msgstr "[brak CR]'"
+
+msgid "[long lines split]"
+msgstr "[d³ugie wiersze rozdzielane]"
+
+msgid "[NOT converted]"
+msgstr "[NIE przemienione]"
+
+msgid "[converted]"
+msgstr "[przemienione]"
+
+msgid "[blowfish]"
+msgstr "[blowfish]"
+
+msgid "[crypted]"
+msgstr "[zakodowane]"
+
+#, c-format
+msgid "[CONVERSION ERROR in line %ld]"
+msgstr "[B£¡D W PRZEMIANIE w linii %ld]"
+
+#, c-format
+msgid "[ILLEGAL BYTE in line %ld]"
+msgstr "[NIEDOZWOLONY BAJT w wierszu %ld]"
+
+msgid "[READ ERRORS]"
+msgstr "[B£ÊDY W ODCZYCIE]"
+
+msgid "Can't find temp file for conversion"
+msgstr "Nie mogê znale¼æ pliku tymczasowego w celu przemiany"
+
+msgid "Conversion with 'charconvert' failed"
+msgstr "Nieudana przemiana z 'charconvert'"
+
+msgid "can't read output of 'charconvert'"
+msgstr "nie mogê odczytaæ wyj¶cia z 'charconvert'"
+
+msgid "E821: File is encrypted with unknown method"
+msgstr "E821: Plik zaszyfrowano w nieznany sposób"
+
+msgid "E676: No matching autocommands for acwrite buffer"
+msgstr "E676: Brak pasuj±cych autokomend dla bufora acwrite"
+
+msgid "E203: Autocommands deleted or unloaded buffer to be written"
+msgstr ""
+"E203: Autokomendy skasowa³y lub wy³adowa³y bufor przeznaczony do zapisu"
+
+msgid "E204: Autocommand changed number of lines in unexpected way"
+msgstr "E204: Autokomenda zmieni³a liczbê wierszy w nieoczekiwany sposób"
+
+msgid "NetBeans disallows writes of unmodified buffers"
+msgstr "NetBeans nie pozwala na zapis niezmodyfikowanych buforów"
+
+msgid "Partial writes disallowed for NetBeans buffers"
+msgstr "Czê¶ciowy zapis niemo¿liwy dla buforów NetBeans"
+
+msgid "is not a file or writable device"
+msgstr "nie jest plikiem lub zapisywalnym przyrz±dem"
+
+msgid "writing to device disabled with 'opendevice' option"
+msgstr "zapisywanie do urz±dzenia wy³±czone w opcji 'opendevice'"
+
+msgid "is read-only (add ! to override)"
+msgstr "jest tylko do odczytu (wymu¶ poprzez !)"
+
+msgid "E506: Can't write to backup file (add ! to override)"
+msgstr "E506: Nie mogê zapisaæ do pliku zabezpieczenia (wymu¶ przez !)"
+
+msgid "E507: Close error for backup file (add ! to override)"
+msgstr "E507: B³±d podczas zamykania pliku zabezpieczenia (wymu¶ przez !)"
+
+msgid "E508: Can't read file for backup (add ! to override)"
+msgstr "E508: Nie mogê odczytaæ pliku w celu zabezpieczenia (wymu¶ przez !)"
+
+msgid "E509: Cannot create backup file (add ! to override)"
+msgstr "E509: Nie mogê stworzyæ pliku zabezpieczenia (wymu¶ przez !)"
+
+msgid "E510: Can't make backup file (add ! to override)"
+msgstr "E510: Nie mogê zrobiæ pliku zabezpieczenia (wymu¶ przez !)"
+
+msgid "E460: The resource fork would be lost (add ! to override)"
+msgstr "E460: Rozdzia³ zasobów zostanie utracony (wymu¶ przez !)"
+
+msgid "E214: Can't find temp file for writing"
+msgstr "E214: Nie mogê znale¼æ pliku tymczasowego do zapisania"
+
+msgid "E213: Cannot convert (add ! to write without conversion)"
+msgstr "E213: Nie mogê przemieniæ (u¿yj ! by zapisaæ bez przemiany)"
+
+msgid "E166: Can't open linked file for writing"
+msgstr "E166: Nie mogê otworzyæ pod³±czonego pliku do zapisu"
+
+msgid "E212: Can't open file for writing"
+msgstr "E212: Nie mogê otworzyæ pliku do zapisu"
+
+msgid "E667: Fsync failed"
+msgstr "E667: Fsync nie powiód³ siê"
+
+msgid "E512: Close failed"
+msgstr "E512: Zamkniêcie siê nie powiod³o"
+
+msgid "E513: write error, conversion failed (make 'fenc' empty to override)"
+msgstr ""
+"E513: B³±d zapisu, przemiana siê nie powiod³a (opró¿nij 'fenc' aby wymusiæ)"
+
+#, c-format
+msgid ""
+"E513: write error, conversion failed in line %ld (make 'fenc' empty to "
+"override)"
+msgstr ""
+"E513: B³±d zapisu, przemiana siê nie powiod³a w wierszu %ld (opró¿nij 'fenc' "
+"by wymusiæ)"
+
+msgid "E514: write error (file system full?)"
+msgstr "E514: b³±d w zapisie (mo¿e system plików jest przepe³niony?)"
+
+msgid " CONVERSION ERROR"
+msgstr " B£¡D W PRZEMIANIE"
+
+#, c-format
+msgid " in line %ld;"
+msgstr " w wierszu %ld;"
+
+msgid "[Device]"
+msgstr "[Urz±dzenie]"
+
+msgid "[New]"
+msgstr "[Nowy]"
+
+msgid " [a]"
+msgstr " [a]"
+
+msgid " appended"
+msgstr " do³±czono"
+
+msgid " [w]"
+msgstr " [w]"
+
+msgid " written"
+msgstr " zapisano"
+
+msgid "E205: Patchmode: can't save original file"
+msgstr "E205: Patchmode: nie mogê zapisaæ oryginalnego pliku"
+
+msgid "E206: patchmode: can't touch empty original file"
+msgstr "E206: patchmode: nie mogê stworzyæ pustego oryginalnego pliku"
+
+msgid "E207: Can't delete backup file"
+msgstr "E207: Nie mogê skasowaæ pliku zabezpieczenia"
+
+msgid ""
+"\n"
+"WARNING: Original file may be lost or damaged\n"
+msgstr ""
+"\n"
+"OSTRZE¯ENIE: Oryginalny plik mo¿e zostaæ utracony lub uszkodzony\n"
+
+msgid "don't quit the editor until the file is successfully written!"
+msgstr "nie wychod¼ edytora, dopóki plik nie zosta³ poprawnie zapisany!"
+
+msgid "[dos]"
+msgstr "[dos]"
+
+msgid "[dos format]"
+msgstr "[format dos-a]"
+
+msgid "[mac]"
+msgstr "[mac]"
+
+msgid "[mac format]"
+msgstr "[format maca]"
+
+msgid "[unix]"
+msgstr "[unix]"
+
+msgid "[unix format]"
+msgstr "[format unixa]"
+
+msgid "1 line, "
+msgstr "1 wiersz, "
+
+#, c-format
+msgid "%ld lines, "
+msgstr "%ld wierszy, "
+
+msgid "1 character"
+msgstr "1 znak"
+
+#, c-format
+msgid "%lld characters"
+msgstr "%lld znaków"
+
+#. Explicit typecast avoids warning on Mac OS X 10.6
+#, c-format
+msgid "%ld characters"
+msgstr "%ld znaków"
+
+msgid "[noeol]"
+msgstr "[noeol]"
+
+msgid "[Incomplete last line]"
+msgstr "[Niekompletny ostatni wiersz]"
+
+#. don't overwrite messages here
+#. must give this prompt
+#. don't use emsg() here, don't want to flush the buffers
+msgid "WARNING: The file has been changed since reading it!!!"
+msgstr "OSTRZE¯ENIE: Plik zmieni³ siê od czasu ostatniego odczytu!!!"
+
+msgid "Do you really want to write to it"
+msgstr "Czy naprawdê chcesz go zapisaæ"
+
+#, c-format
+msgid "E208: Error writing to \"%s\""
+msgstr "E208: B³±d zapisywania do \"%s\""
+
+#, c-format
+msgid "E209: Error closing \"%s\""
+msgstr "E209: B³±d w trakcie zamykania \"%s\""
+
+#, c-format
+msgid "E210: Error reading \"%s\""
+msgstr "E210: B³±d odczytu \"%s\""
+
+msgid "E246: FileChangedShell autocommand deleted buffer"
+msgstr "E246: Autokomenda FileChangedShell skasowa³a bufor"
+
+#, c-format
+msgid "E211: File \"%s\" no longer available"
+msgstr "E211: Plik \"%s\" nie jest d³u¿ej dostêpny"
+
+#, c-format
+msgid ""
+"W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as "
+"well"
+msgstr ""
+"W12: OSTRZE¯ENIE: Plik \"%s\" zmieni³ siê od czasu rozpoczêcia edycji, bufor "
+"w Vimie równie¿ zosta³ zmieniony"
+
+msgid "See \":help W12\" for more info."
+msgstr "Zobacz \":help W12\" dla dalszych informacji."
+
+#, c-format
+msgid "W11: Warning: File \"%s\" has changed since editing started"
+msgstr "W11: OSTRZE¯ENIE: Plik \"%s\" zmieni³ siê od czasu rozpoczêcia edycji"
+
+msgid "See \":help W11\" for more info."
+msgstr "Zobacz \":help W11\" dla dalszych informacji."
+
+#, c-format
+msgid "W16: Warning: Mode of file \"%s\" has changed since editing started"
+msgstr ""
+"W16: OSTRZE¯ENIE: Tryb pliku \"%s\" zmieni³ siê od czasu rozpoczêcia edycji"
+
+msgid "See \":help W16\" for more info."
+msgstr "Zobacz \":help W16\" dla dalszych informacji."
+
+#, c-format
+msgid "W13: Warning: File \"%s\" has been created after editing started"
+msgstr "W13: OSTRZE¯ENIE: Plik \"%s\" zosta³ stworzony po rozpoczêciu edycji"
+
+msgid "Warning"
+msgstr "OSTRZE¯ENIE"
+
+msgid ""
+"&OK\n"
+"&Load File"
+msgstr ""
+"&OK\n"
+"&Za³aduj Plik"
+
+#, c-format
+msgid "E462: Could not prepare for reloading \"%s\""
+msgstr "E462: Nie mo¿na przygotowaæ prze³adowania \"%s\""
+
+#, c-format
+msgid "E321: Could not reload \"%s\""
+msgstr "E321: Nie mo¿na prze³adowaæ \"%s\""
+
+msgid "--Deleted--"
+msgstr "--Skasowano--"
+
+#, c-format
+msgid "auto-removing autocommand: %s <buffer=%d>"
+msgstr "auto-usuwanie autokomendy: %s <buffer=%d>"
+
+#. the group doesn't exist
+#, c-format
+msgid "E367: No such group: \"%s\""
+msgstr "E367: Nie ma takiej grupy: \"%s\""
+
+#, c-format
+msgid "E215: Illegal character after *: %s"
+msgstr "E215: Niedopuszczalny znak po *: %s"
+
+#, c-format
+msgid "E216: No such event: %s"
+msgstr "E216: Nie ma takiego wydarzenia: %s"
+
+#, c-format
+msgid "E216: No such group or event: %s"
+msgstr "E216: Nie ma takiej grupy lub wydarzenia: %s"
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Autocommands ---"
+msgstr ""
+"\n"
+"--- Autokomendy ---"
+
+#, c-format
+msgid "E680: <buffer=%d>: invalid buffer number "
+msgstr "E680: <buffer=%d>: niew³a¶ciwy numer bufora"
+
+msgid "E217: Can't execute autocommands for ALL events"
+msgstr "E217: Nie mo¿na wykonywaæ autokomend dla wydarzeñ ALL"
+
+msgid "No matching autocommands"
+msgstr "Brak pasuj±cych autokomend"
+
+msgid "E218: autocommand nesting too deep"
+msgstr "E218: zbyt g³êbokie zagnie¿d¿enie autokomend"
+
+#, c-format
+msgid "%s Autocommands for \"%s\""
+msgstr "%s Autokomend dla \"%s\""
+
+#, c-format
+msgid "Executing %s"
+msgstr "Wykonujê %s"
+
+#, c-format
+msgid "autocommand %s"
+msgstr "autokomenda %s"
+
+msgid "E219: Missing {."
+msgstr "E219: Brak {."
+
+msgid "E220: Missing }."
+msgstr "E220: Brak }."
+
+msgid "E490: No fold found"
+msgstr "E490: Nie znaleziono zwiniêcia"
+
+msgid "E350: Cannot create fold with current 'foldmethod'"
+msgstr "E350: Nie mo¿na utworzyæ zwiniêcia przy bie¿±cej 'foldmethod'"
+
+msgid "E351: Cannot delete fold with current 'foldmethod'"
+msgstr "E351: Nie mo¿na skasowaæ zwiniêcia przy bie¿±cej 'foldmethod'"
+
+#, c-format
+msgid "+--%3ld lines folded "
+msgstr "+--%3ld wierszy zwiniêto "
+
+msgid "E222: Add to read buffer"
+msgstr "E222: Dodaj do bufora odczytu"
+
+msgid "E223: recursive mapping"
+msgstr "E223: rekursywne przyporz±dkowanie"
+
+#, c-format
+msgid "E224: global abbreviation already exists for %s"
+msgstr "E224: istnieje ju¿ globalny skrót dla %s"
+
+#, c-format
+msgid "E225: global mapping already exists for %s"
+msgstr "E225: istnieje ju¿ globalne przyporz±dkowanie dla %s"
+
+#, c-format
+msgid "E226: abbreviation already exists for %s"
+msgstr "E226: istnieje ju¿ skrót dla %s"
+
+#, c-format
+msgid "E227: mapping already exists for %s"
+msgstr "E227: istnieje ju¿ przyporz±dkowanie dla %s"
+
+msgid "No abbreviation found"
+msgstr "Nie znaleziono skrótu"
+
+msgid "No mapping found"
+msgstr "Nie znaleziono przyporz±dkowania"
+
+msgid "E228: makemap: Illegal mode"
+msgstr "E228: makemap: Niedopuszczalny tryb"
+
+msgid "<cannot open> "
+msgstr "<nie mogê otworzyæ> "
+
+#, c-format
+msgid "E616: vim_SelFile: can't get font %s"
+msgstr "E616: vim_SelFile: nie mogê otrzymaæ czcionki %s"
+
+msgid "E614: vim_SelFile: can't return to current directory"
+msgstr "E614: vim_SelFile: nie mogê powróciæ do bie¿±cego katalogu"
+
+msgid "Pathname:"
+msgstr "Trop:"
+
+msgid "E615: vim_SelFile: can't get current directory"
+msgstr "E615: vim_SelFile: nie mogê otrzymaæ bie¿±cego katalogu"
+
+msgid "OK"
+msgstr "OK"
+
+msgid "Cancel"
+msgstr "Zakoñcz"
+
+msgid "Vim dialog"
+msgstr "VIM - Dialog"
+
+msgid "Scrollbar Widget: Could not get geometry of thumb pixmap."
+msgstr "Scrollbar Widget: Nie mog³em otrzymaæ rozmiarów rysunku na przycisku."
+
+msgid "E232: Cannot create BalloonEval with both message and callback"
+msgstr "E232: Nie mogê stworzyæ BalloonEval z powiadomieniem i wywo³aniem"
+
+msgid "E851: Failed to create a new process for the GUI"
+msgstr "E851: Nie mog³em stworzyæ nowego procesu dla GUI"
+
+msgid "E852: The child process failed to start the GUI"
+msgstr "E852: Proces potomny nie móg³ uruchomiæ GUI"
+
+msgid "E229: Cannot start the GUI"
+msgstr "E229: Nie mogê odpaliæ GUI"
+
+#, c-format
+msgid "E230: Cannot read from \"%s\""
+msgstr "E230: Nie mogê czytaæ z \"%s\""
+
+msgid "E665: Cannot start GUI, no valid font found"
+msgstr "E665: Nie mo¿na uruchomiæ GUI, brak prawid³owej czcionki"
+
+msgid "E231: 'guifontwide' invalid"
+msgstr "E231: Niew³a¶ciwe 'guifontwide'"
+
+msgid "E599: Value of 'imactivatekey' is invalid"
+msgstr "E599: Nieprawid³owa warto¶æ 'imactivatekey'"
+
+#, c-format
+msgid "E254: Cannot allocate color %s"
+msgstr "E254: Nie mogê zarezerwowaæ koloru %s"
+
+msgid "No match at cursor, finding next"
+msgstr "Brak dopasowania przy kursorze, szukam dalej"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"&Cancel"
+msgstr ""
+"&Tak\n"
+"&Nie\n"
+"&Zakoñcz"
+
+msgid "Input _Methods"
+msgstr "Input _Methods"
+
+msgid "VIM - Search and Replace..."
+msgstr "VIM - Szukaj i Zamieñ..."
+
+msgid "VIM - Search..."
+msgstr "VIM - Szukaj..."
+
+msgid "Find what:"
+msgstr "Znajd¼:"
+
+msgid "Replace with:"
+msgstr "Zamieñ na:"
+
+#. whole word only button
+msgid "Match whole word only"
+msgstr "Dopasuj tylko ca³e wyrazy"
+
+#. match case button
+msgid "Match case"
+msgstr "Dopasuj wielko¶æ liter"
+
+msgid "Direction"
+msgstr "Kierunek"
+
+#. 'Up' and 'Down' buttons
+msgid "Up"
+msgstr "W górê"
+
+msgid "Down"
+msgstr "W dó³"
+
+#. 'Find Next' button
+msgid "Find Next"
+msgstr "Znajd¼ nastêpne"
+
+#. 'Replace' button
+msgid "Replace"
+msgstr "Zamieñ"
+
+#. 'Replace All' button
+msgid "Replace All"
+msgstr "Zamieñ wszystkie"
+
+msgid "Vim: Received \"die\" request from session manager\n"
+msgstr "Vim: otrzymano ¿±danie \"die\" od mened¿era sesji\n"
+
+msgid "Close"
+msgstr "Zamknij"
+
+msgid "New tab"
+msgstr "Nowa karta"
+
+msgid "Open Tab..."
+msgstr "Otwórz kartê..."
+
+msgid "Vim: Main window unexpectedly destroyed\n"
+msgstr "Vim: G³ówne okno nieoczekiwanie zniszczone\n"
+
+msgid "&Filter"
+msgstr "&Filtr"
+
+msgid "&Cancel"
+msgstr "&Anuluj"
+
+msgid "Directories"
+msgstr "Katalogi"
+
+msgid "Filter"
+msgstr "Filtr"
+
+msgid "&Help"
+msgstr "&Pomoc"
+
+msgid "Files"
+msgstr "Pliki"
+
+msgid "&OK"
+msgstr "&OK"
+
+msgid "Selection"
+msgstr "Wybór"
+
+msgid "Find &Next"
+msgstr "Znajd¼ &nastêpne"
+
+msgid "&Replace"
+msgstr "&Zamieñ"
+
+msgid "Replace &All"
+msgstr "Zamieñ &wszystko"
+
+msgid "&Undo"
+msgstr "&Cofnij"
+
+#, c-format
+msgid "E671: Cannot find window title \"%s\""
+msgstr "E671: Nie mogê znale¼æ tytu³u okna \"%s\""
+
+#, c-format
+msgid "E243: Argument not supported: \"-%s\"; Use the OLE version."
+msgstr "E243: Argument nie jest wspomagany: \"-%s\"; U¿ywaj wersji OLE."
+
+msgid "E672: Unable to open window inside MDI application"
+msgstr "E672: Nie mo¿na otworzyæ okna wewn±trz aplikacji MDI"
+
+msgid "Close tab"
+msgstr "Zamknij kartê"
+
+msgid "Open tab..."
+msgstr "Otwórz kartê..."
+
+msgid "Find string (use '\\\\' to find a '\\')"
+msgstr "Znajd¼ ci±g (u¿yj '\\\\' do szukania '\\')"
+
+msgid "Find & Replace (use '\\\\' to find a '\\')"
+msgstr "Szukanie i Zamiana (u¿yj '\\\\' do szukania '\\')"
+
+#. We fake this: Use a filter that doesn't select anything and a default
+#. * file name that won't be used.
+msgid "Not Used"
+msgstr "Nie u¿ywany"
+
+msgid "Directory\t*.nothing\n"
+msgstr "Katalog\t*.nic\n"
+
+msgid "Vim E458: Cannot allocate colormap entry, some colors may be incorrect"
+msgstr ""
+"Vim E458: Nie mogê zarezerwowaæ mapy kolorów, pewne kolory mog± byæ "
+"nieprawid³owe"
+
+#, c-format
+msgid "E250: Fonts for the following charsets are missing in fontset %s:"
+msgstr ""
+"E250: Brak czcionek dla nastêpuj±cych zestawów znaków w zestawie czcionek %s:"
+
+#, c-format
+msgid "E252: Fontset name: %s"
+msgstr "E252: Nazwa zestawu czcionek: %s"
+
+#, c-format
+msgid "Font '%s' is not fixed-width"
+msgstr "Czcionka '%s' nie posiada znaków jednolitej szeroko¶ci"
+
+#, c-format
+msgid "E253: Fontset name: %s"
+msgstr "E253: Nazwa zestawu czcionek: %s"
+
+#, c-format
+msgid "Font0: %s"
+msgstr "Font0: %s"
+
+#, c-format
+msgid "Font1: %s"
+msgstr "Font1: %s"
+
+#, c-format
+msgid "Font%ld width is not twice that of font0"
+msgstr "Szeroko¶æ font%ld nie jest podwójn± szeroko¶ci± font0"
+
+#, c-format
+msgid "Font0 width: %ld"
+msgstr "Szeroko¶æ font0: %ld"
+
+#, c-format
+msgid "Font1 width: %ld"
+msgstr "Szeroko¶æ font1: %ld"
+
+msgid "Invalid font specification"
+msgstr "Nieprawid³owy opis czcionki"
+
+msgid "&Dismiss"
+msgstr "&Anuluj"
+
+msgid "no specific match"
+msgstr "brak okre¶lonego dopasowania"
+
+msgid "Vim - Font Selector"
+msgstr "Vim - wybór czcionki"
+
+msgid "Name:"
+msgstr "Nazwa:"
+
+#. create toggle button
+msgid "Show size in Points"
+msgstr "Poka¿ wielko¶æ w punktach"
+
+msgid "Encoding:"
+msgstr "Kodowanie:"
+
+msgid "Font:"
+msgstr "Czcionka:"
+
+msgid "Style:"
+msgstr "Styl:"
+
+msgid "Size:"
+msgstr "Wielko¶æ:"
+
+msgid "E256: Hangul automata ERROR"
+msgstr "E256: B£¡D w automacie Hangul"
+
+msgid "E550: Missing colon"
+msgstr "E550: Brak dwukropka"
+
+msgid "E551: Illegal component"
+msgstr "E551: Niedozwolona czê¶æ"
+
+msgid "E552: digit expected"
+msgstr "E552: oczekiwa³em na cyfrê"
+
+#, c-format
+msgid "Page %d"
+msgstr "Strona %d"
+
+msgid "No text to be printed"
+msgstr "Brak tekstu do drukowania"
+
+#, c-format
+msgid "Printing page %d (%d%%)"
+msgstr "Drukujê stronê %d (%d%%)"
+
+#, c-format
+msgid " Copy %d of %d"
+msgstr " Kopia %d z %d"
+
+#, c-format
+msgid "Printed: %s"
+msgstr "Wydrukowano: %s"
+
+msgid "Printing aborted"
+msgstr "Drukowanie odwo³ane"
+
+msgid "E455: Error writing to PostScript output file"
+msgstr "E455: Nie mo¿na zapisaæ do wyj¶ciowego pliku PostScriptu"
+
+#, c-format
+msgid "E624: Can't open file \"%s\""
+msgstr "E624: Nie mogê otworzyæ pliku \"%s\""
+
+#, c-format
+msgid "E457: Can't read PostScript resource file \"%s\""
+msgstr "E457: Nie mo¿na odczytaæ pliku zasobów PostScriptu \"%s\""
+
+#, c-format
+msgid "E618: file \"%s\" is not a PostScript resource file"
+msgstr "E618: plik \"%s\" nie jest plikiem zasobów PostScriptu"
+
+#, c-format
+msgid "E619: file \"%s\" is not a supported PostScript resource file"
+msgstr "E619: plik \"%s\" nie jest wspieranym plikiem zasobów PostScriptu"
+
+#, c-format
+msgid "E621: \"%s\" resource file has wrong version"
+msgstr "E621: \"%s\" nieprawid³owa wersja pliku zasobów"
+
+msgid "E673: Incompatible multi-byte encoding and character set."
+msgstr "E673: Niekompatybilne kodowanie wielobajtowe i zestaw znaków."
+
+msgid "E674: printmbcharset cannot be empty with multi-byte encoding."
+msgstr "E674: printmbcharset nie mo¿e byæ pusty przy kodowaniu wielobajtowym."
+
+msgid "E675: No default font specified for multi-byte printing."
+msgstr "E675: Nie okre¶lono domy¶lnej czcionki dla drukowania wielobajtowego."
+
+msgid "E324: Can't open PostScript output file"
+msgstr "E324: Nie mo¿na otworzyæ pliku PostScript do wyj¶cia"
+
+#, c-format
+msgid "E456: Can't open file \"%s\""
+msgstr "E456: Nie mogê otworzyæ pliku \"%s\""
+
+msgid "E456: Can't find PostScript resource file \"prolog.ps\""
+msgstr "E456: Nie mo¿na znale¼æ pliku zasobów PostScriptu \"prolog.ps\""
+
+msgid "E456: Can't find PostScript resource file \"cidfont.ps\""
+msgstr "E456: Nie mo¿na znale¼æ pliku zasobów PostScriptu \"cidfont.ps\""
+
+#, c-format
+msgid "E456: Can't find PostScript resource file \"%s.ps\""
+msgstr "E456: Nie mo¿na znale¼æ pliku zasobów PostScriptu \"%s.ps\""
+
+#, c-format
+msgid "E620: Unable to convert to print encoding \"%s\""
+msgstr "E620: Nie mo¿na przekonwertowaæ by drukowaæ kodowanie \"%s\""
+
+msgid "Sending to printer..."
+msgstr "Przesy³am do drukarki..."
+
+msgid "E365: Failed to print PostScript file"
+msgstr "E365: Drukowanie pliku PostScript nie powiod³o siê"
+
+msgid "Print job sent."
+msgstr "Zadanie drukowanie przes³ane."
+
+msgid "Add a new database"
+msgstr "Dodaj now± bazê danych"
+
+msgid "Query for a pattern"
+msgstr "Zapytane o wzorzec"
+
+msgid "Show this message"
+msgstr "Poka¿ ten komunikat"
+
+msgid "Kill a connection"
+msgstr "Zabij po³±czenie"
+
+msgid "Reinit all connections"
+msgstr "Ponów wszelkie po³±czenia"
+
+msgid "Show connections"
+msgstr "Poka¿ po³±czenia"
+
+#, c-format
+msgid "E560: Usage: cs[cope] %s"
+msgstr "E560: Zastosowanie: cs[cope] %s"
+
+msgid "This cscope command does not support splitting the window.\n"
+msgstr "Ta komenda cscope nie wspomaga podzielenia okna.\n"
+
+msgid "E562: Usage: cstag <ident>"
+msgstr "E562: Zastosowanie: cstag <ident>"
+
+msgid "E257: cstag: tag not found"
+msgstr "E257: cstag: nie znaleziono znacznika"
+
+#, c-format
+msgid "E563: stat(%s) error: %d"
+msgstr "E563: stat(%s) b³±d: %d"
+
+msgid "E563: stat error"
+msgstr "E563: b³±d stat"
+
+#, c-format
+msgid "E564: %s is not a directory or a valid cscope database"
+msgstr "E564: %s nie jest katalogiem lub poprawn± baz± danych cscope"
+
+#, c-format
+msgid "Added cscope database %s"
+msgstr "Dodano bazê danych cscope %s"
+
+#, c-format
+msgid "E262: error reading cscope connection %ld"
+msgstr "E262: b³±d odczytu po³±czenia z cscope %ld"
+
+msgid "E561: unknown cscope search type"
+msgstr "E561: nieznany typ szukania cscope"
+
+msgid "E566: Could not create cscope pipes"
+msgstr "E566: Nie mog³em stworzyæ potoku do cscope"
+
+msgid "E622: Could not fork for cscope"
+msgstr "E622: Nie mog³em utworzyæ rozwidlenia dla cscope"
+
+msgid "cs_create_connection setpgid failed"
+msgstr "nie powiod³o siê setpgid cs_create_connection"
+
+msgid "cs_create_connection exec failed"
+msgstr "wykonanie cs_create_connection nie powiod³o siê"
+
+msgid "cs_create_connection: fdopen for to_fp failed"
+msgstr "cs_create_connection: fdopen dla to_fp nie powiod³o siê"
+
+msgid "cs_create_connection: fdopen for fr_fp failed"
+msgstr "cs_create_connection: fdopen dla fr_fp nie powiod³o siê"
+
+msgid "E623: Could not spawn cscope process"
+msgstr "E623: Nie mog³em stworzyæ procesu cscope"
+
+msgid "E567: no cscope connections"
+msgstr "E567: brak po³±czenia z cscope"
+
+#, c-format
+msgid "E469: invalid cscopequickfix flag %c for %c"
+msgstr "E469: nieprawid³owa flaga cscopequickfix %c dla %c"
+
+#, c-format
+msgid "E259: no matches found for cscope query %s of %s"
+msgstr "E259: brak dopasowañ dla zapytania cscope %s o %s"
+
+msgid "cscope commands:\n"
+msgstr "komendy cscope:\n"
+
+#, c-format
+msgid "%-5s: %s%*s (Usage: %s)"
+msgstr "%-5s: %s%*s (U¿ycie: %s)"
+
+msgid ""
+"\n"
+" c: Find functions calling this function\n"
+" d: Find functions called by this function\n"
+" e: Find this egrep pattern\n"
+" f: Find this file\n"
+" g: Find this definition\n"
+" i: Find files #including this file\n"
+" s: Find this C symbol\n"
+" t: Find this text string\n"
+msgstr ""
+"\n"
+" c: znajd¼ funkcje wywo³uj±ce tê funkcjê\n"
+" d: znajd¼ funkcje wywo³ywane przez tê funkcjê\n"
+" e: znajd¼ ten wzorzec egrep\n"
+" f: znajd¼ ten plik\n"
+" g: znajd¼ tê definicjê\n"
+" i: znajd¼ pliki w³±czaj±ce (#include) ten plik\n"
+" s: znajd¼ ten symbol C\n"
+" t: znajd¼ ten ³añcuch znaków\n"
+
+#, c-format
+msgid "E625: cannot open cscope database: %s"
+msgstr "E625: nie mogê otworzyæ bazy danych cscope: %s"
+
+msgid "E626: cannot get cscope database information"
+msgstr "E626: nie mogê uzyskaæ informacji z bazy danych cscope"
+
+msgid "E568: duplicate cscope database not added"
+msgstr "E568: nie dodano duplikatu bazy danych cscope"
+
+#, c-format
+msgid "E261: cscope connection %s not found"
+msgstr "E261: nie ma po³±czenia %s z cscope"
+
+#, c-format
+msgid "cscope connection %s closed"
+msgstr "po³±czenie %s z cscope zosta³o zamkniête"
+
+#. should not reach here
+msgid "E570: fatal error in cs_manage_matches"
+msgstr "E570: b³±d krytyczny w cs_manage_matches"
+
+#, c-format
+msgid "Cscope tag: %s"
+msgstr "Znacznik cscope: %s"
+
+msgid ""
+"\n"
+" # line"
+msgstr ""
+"\n"
+" # wiersz"
+
+msgid "filename / context / line\n"
+msgstr "nazwa pliku / kontekst / wiersz\n"
+
+#, c-format
+msgid "E609: Cscope error: %s"
+msgstr "E609: B³±d cscope: %s"
+
+msgid "All cscope databases reset"
+msgstr "Wszystkie bazy danych cscope prze³adowano"
+
+msgid "no cscope connections\n"
+msgstr "brak po³±czeñ z cscope\n"
+
+msgid " # pid database name prepend path\n"
+msgstr " # pid nazwa bazy danych przedsionek tropu\n"
+
+msgid "Lua library cannot be loaded."
+msgstr "Nie mo¿na wczytaæ biblioteki Lua."
+
+msgid "cannot save undo information"
+msgstr "nie mogê zachowaæ informacji cofania"
+
+msgid ""
+"E815: Sorry, this command is disabled, the MzScheme libraries could not be "
+"loaded."
+msgstr ""
+"E815: Przykro mi, ta komenda jest wy³±czona, biblioteka MzScheme nie mo¿e "
+"byæ za³adowana."
+
+msgid "invalid expression"
+msgstr "niepoprawne wyra¿enie"
+
+msgid "expressions disabled at compile time"
+msgstr "wyra¿enia wy³±czone podczas kompilacji"
+
+msgid "hidden option"
+msgstr "ukryta opcja"
+
+msgid "unknown option"
+msgstr "nieznana opcja"
+
+msgid "window index is out of range"
+msgstr "indeks okna poza zakresem"
+
+msgid "couldn't open buffer"
+msgstr "nie mogê otworzyæ bufora"
+
+msgid "cannot delete line"
+msgstr "nie mogê skasowaæ wiersza"
+
+msgid "cannot replace line"
+msgstr "nie mogê zamieniæ wiersza"
+
+msgid "cannot insert line"
+msgstr "nie mogê wprowadziæ wiersza"
+
+msgid "string cannot contain newlines"
+msgstr "ci±g nie mo¿e zawieraæ znaków nowego wiersza"
+
+msgid "error converting Scheme values to Vim"
+msgstr "b³±d przy konwersji warto¶ci Scheme do Vima"
+
+msgid "Vim error: ~a"
+msgstr "B³±d vima: ~a"
+
+msgid "Vim error"
+msgstr "B³±d Vima"
+
+msgid "buffer is invalid"
+msgstr "bufor jest niewa¿ny"
+
+msgid "window is invalid"
+msgstr "okno jest niewa¿ne"
+
+msgid "linenr out of range"
+msgstr "numer wiersza poza zakresem"
+
+msgid "not allowed in the Vim sandbox"
+msgstr "Niedozwolone w piaskownicy Vima"
+
+msgid "E837: This Vim cannot execute :py3 after using :python"
+msgstr "E837: Python: nie mo¿na u¿ywaæ :py i :py3 w czasie jednej sesji"
+
+msgid ""
+"E263: Sorry, this command is disabled, the Python library could not be "
+"loaded."
+msgstr ""
+"E263: Przykro mi, ta komenda jest wy³±czona, bo nie mo¿na za³adowaæ "
+"biblioteki Pythona"
+
+msgid "E836: This Vim cannot execute :python after using :py3"
+msgstr "E836: Python: nie mo¿na u¿ywaæ :py i :py3 w czasie jednej sesji"
+
+msgid "E659: Cannot invoke Python recursively"
+msgstr "E659: Nie mo¿na wywo³aæ Pythona rekursywnie"
+
+msgid "E265: $_ must be an instance of String"
+msgstr "E265: $_ musi byæ reprezentacj± £añcucha"
+
+msgid ""
+"E266: Sorry, this command is disabled, the Ruby library could not be loaded."
+msgstr ""
+"E266: Przykro mi, ta komenda jest wy³±czona, bo nie mo¿na za³adowaæ "
+"biblioteki Ruby."
+
+msgid "E267: unexpected return"
+msgstr "E267: nieoczekiwany return"
+
+msgid "E268: unexpected next"
+msgstr "E268: nieoczekiwany next"
+
+msgid "E269: unexpected break"
+msgstr "E269: nieoczekiwany break"
+
+msgid "E270: unexpected redo"
+msgstr "E270: nieoczekiwane redo"
+
+msgid "E271: retry outside of rescue clause"
+msgstr "E271: ponowna próba poza klauzul± ratunku"
+
+msgid "E272: unhandled exception"
+msgstr "E272: nieobs³ugiwany wyj±tek"
+
+#, c-format
+msgid "E273: unknown longjmp status %d"
+msgstr "E273: Nieznany status longjmp %d"
+
+msgid "Toggle implementation/definition"
+msgstr "Prze³±cz miêdzy implementacj±/okre¶leniem"
+
+msgid "Show base class of"
+msgstr "Poka¿ bazê klasy"
+
+msgid "Show overridden member function"
+msgstr "Poka¿ przepisan± funkcjê cz³onow±"
+
+msgid "Retrieve from file"
+msgstr "Pobieraj z pliku"
+
+msgid "Retrieve from project"
+msgstr "Pobieraj z projektu"
+
+msgid "Retrieve from all projects"
+msgstr "Pobieraj z wszystkich projektów"
+
+msgid "Retrieve"
+msgstr "Pobierz"
+
+msgid "Show source of"
+msgstr "Poka¿ ¼ród³o dla"
+
+msgid "Find symbol"
+msgstr "Znajd¼ symbol"
+
+msgid "Browse class"
+msgstr "Przejrzyj klasê"
+
+msgid "Show class in hierarchy"
+msgstr "Poka¿ klasê w hierarchii"
+
+msgid "Show class in restricted hierarchy"
+msgstr "Poka¿ klasê w ograniczonej hierarchii"
+
+msgid "Xref refers to"
+msgstr "Xref odnosi siê do"
+
+msgid "Xref referred by"
+msgstr "Xref ma odniesienia od"
+
+msgid "Xref has a"
+msgstr "Xref ma"
+
+msgid "Xref used by"
+msgstr "Xref u¿yte przez"
+
+msgid "Show docu of"
+msgstr "Poka¿ dokumentacjê dla"
+
+msgid "Generate docu for"
+msgstr "Utwórz dokumentacjê dla"
+
+msgid ""
+"Cannot connect to SNiFF+. Check environment (sniffemacs must be found in "
+"$PATH).\n"
+msgstr ""
+"Nie mogê pod³±czyæ do SNiFF+. Sprawd¼ ¶rodowisko (sniffemacs musi byæ "
+"odnaleziony w $PATH).\n"
+
+msgid "E274: Sniff: Error during read. Disconnected"
+msgstr "E274: Sniff: B³±d podczas czytania. Roz³±czenie"
+
+msgid "SNiFF+ is currently "
+msgstr "SNiFF+ jest obecnie "
+
+msgid "not "
+msgstr "nie "
+
+msgid "connected"
+msgstr "pod³±czony"
+
+#, c-format
+msgid "E275: Unknown SNiFF+ request: %s"
+msgstr "E275: Nieznane zapytanie SNiFF+: %s"
+
+msgid "E276: Error connecting to SNiFF+"
+msgstr "E276: B³±d w trakcie pod³±czania do SNiFF+"
+
+msgid "E278: SNiFF+ not connected"
+msgstr "E278: SNiFF+ niepod³±czony"
+
+msgid "E279: Not a SNiFF+ buffer"
+msgstr "E279: Nie jest buforem SNiFF+"
+
+msgid "Sniff: Error during write. Disconnected"
+msgstr "Sniff: B³±d w trakcie zapisu. Roz³±czony"
+
+msgid "invalid buffer number"
+msgstr "niew³a¶ciwy numer bufora"
+
+msgid "not implemented yet"
+msgstr "obecnie nie zaimplementowano"
+
+#. ???
+msgid "cannot set line(s)"
+msgstr "nie mogê ustawiæ wiersza(y)"
+
+msgid "invalid mark name"
+msgstr "niepoprawna nazwa zak³adki"
+
+msgid "mark not set"
+msgstr "zak³adka nie ustawiona"
+
+#, c-format
+msgid "row %d column %d"
+msgstr "wiersz %d kolumna %d"
+
+msgid "cannot insert/append line"
+msgstr "nie mogê wprowadziæ/do³±czyæ wiersza"
+
+msgid "line number out of range"
+msgstr "numer wiersza poza zakresem"
+
+msgid "unknown flag: "
+msgstr "nieznana flaga: "
+
+msgid "unknown vimOption"
+msgstr "nieznane vimOption"
+
+msgid "keyboard interrupt"
+msgstr "przerwanie klawiatury"
+
+msgid "vim error"
+msgstr "b³±d vima"
+
+msgid "cannot create buffer/window command: object is being deleted"
+msgstr "nie mogê stworzyæ bufora/okna komendy: obiekt jest kasowany"
+
+msgid ""
+"cannot register callback command: buffer/window is already being deleted"
+msgstr ""
+"nie mogê zarejestrowaæ wstecznego wywo³ania komendy: bufor/okno ju¿ zosta³a "
+"skasowana"
+
+#. This should never happen. Famous last word?
+msgid ""
+"E280: TCL FATAL ERROR: reflist corrupt!? Please report this to vim-dev@vim."
+"org"
+msgstr ""
+"E280: TCL FATALNY B£¡D: reflist zepsuta!? Proszê z³o¿yæ raport o tym na vim-"
+"dev@vim.org"
+
+msgid "cannot register callback command: buffer/window reference not found"
+msgstr ""
+"nie mogê zarejestrowaæ wstecznego wywo³ania komendy: brak odniesienia do "
+"bufora/okna"
+
+msgid ""
+"E571: Sorry, this command is disabled: the Tcl library could not be loaded."
+msgstr ""
+"E571: Przykro mi, ta komenda jest wy³±czona, bo nie mo¿na za³adowaæ "
+"biblioteki Tcl."
+
+#, c-format
+msgid "E572: exit code %d"
+msgstr "E572: kod wyj¶cia %d"
+
+msgid "cannot get line"
+msgstr "nie mogê dostaæ wiersza"
+
+msgid "Unable to register a command server name"
+msgstr "Nie mogê zarejestrowaæ nazwy serwera komend"
+
+msgid "E248: Failed to send command to the destination program"
+msgstr "E248: Wys³anie komendy do programu docelowego nie powiod³o siê"
+
+#, c-format
+msgid "E573: Invalid server id used: %s"
+msgstr "E573: U¿yto niew³a¶ciwego id serwera: %s"
+
+msgid "E251: VIM instance registry property is badly formed. Deleted!"
+msgstr ""
+"E251: wcielenia instancji rejestru Vima jest ¼le sformowane. Skasowano!"
+
+msgid "Unknown option argument"
+msgstr "Nieznany argument opcji"
+
+msgid "Too many edit arguments"
+msgstr "Zbyt wiele argumentów"
+
+msgid "Argument missing after"
+msgstr "Brak argumentu po"
+
+msgid "Garbage after option argument"
+msgstr "¦miecie po argumencie opcji"
+
+msgid "Too many \"+command\", \"-c command\" or \"--cmd command\" arguments"
+msgstr ""
+"Zbyt wiele argumentów \"+komenda\", \"-c komenda\" lub \"--cmd komenda\""
+
+msgid "Invalid argument for"
+msgstr "Niew³a¶ciwy argument dla"
+
+#, c-format
+msgid "%d files to edit\n"
+msgstr "%d plików do edycji\n"
+
+msgid "netbeans is not supported with this GUI\n"
+msgstr "netbeans nie s± obs³ugiwane przez to GUI\n"
+
+msgid "This Vim was not compiled with the diff feature."
+msgstr "Ta wersja Vima nie by³a skompilowanego z opcj± ró¿nic (diff)."
+
+msgid "'-nb' cannot be used: not enabled at compile time\n"
+msgstr "'-nb' - nie mo¿e byæ u¿yte: nie w³±czone przy kompilacji\n"
+
+msgid "Attempt to open script file again: \""
+msgstr "Próba ponownego otworzenia pliku skryptu: \""
+
+msgid "Cannot open for reading: \""
+msgstr "Nie mogê otworzyæ do odczytu: \""
+
+msgid "Cannot open for script output: \""
+msgstr "Nie mogê otworzyæ dla wyj¶cia skryptu: \""
+
+msgid "Vim: Error: Failure to start gvim from NetBeans\n"
+msgstr "Vim: B³±d: Nie mo¿na uruchomiæ gvim z NetBeans\n"
+
+msgid "Vim: Warning: Output is not to a terminal\n"
+msgstr "Vim: OSTRZE¯ENIE: Wyj¶cie nie jest terminalem\n"
+
+msgid "Vim: Warning: Input is not from a terminal\n"
+msgstr "Vim: OSTRZE¯ENIE: Wej¶cie nie pochodzi z terminala\n"
+
+#. just in case..
+msgid "pre-vimrc command line"
+msgstr "linia poleceñ pre-vimrc"
+
+#, c-format
+msgid "E282: Cannot read from \"%s\""
+msgstr "E282: Nie mogê czytaæ z \"%s\""
+
+msgid ""
+"\n"
+"More info with: \"vim -h\"\n"
+msgstr ""
+"\n"
+"Dalsze informacje poprzez: \"vim -h\"\n"
+
+msgid "[file ..] edit specified file(s)"
+msgstr "[plik ..] edytuj zadane pliki"
+
+msgid "- read text from stdin"
+msgstr "- czytaj tekst ze stdin"
+
+msgid "-t tag edit file where tag is defined"
+msgstr "-t znacznik edytuj plik, w którym dany znacznik jest zdefiniowany"
+
+msgid "-q [errorfile] edit file with first error"
+msgstr "-q [errorfile] edytuj plik, zawieraj±cy pierwszy b³±d"
+
+msgid ""
+"\n"
+"\n"
+"Usage:"
+msgstr ""
+"\n"
+"\n"
+"u¿ycie:"
+
+msgid " vim [arguments] "
+msgstr " vim [argumenty]"
+
+msgid ""
+"\n"
+" or:"
+msgstr ""
+"\n"
+" lub:"
+
+msgid ""
+"\n"
+"Where case is ignored prepend / to make flag upper case"
+msgstr ""
+"\n"
+"gdzie wielko¶æ znaków jest ignorowana dodaj na pocz±tku / by flaga by³a "
+"wielk± liter±"
+
+msgid ""
+"\n"
+"\n"
+"Arguments:\n"
+msgstr ""
+"\n"
+"\n"
+"Argumenty:\n"
+
+msgid "--\t\t\tOnly file names after this"
+msgstr "--\t\t\tTylko nazwy plików po tym"
+
+msgid "--literal\t\tDon't expand wildcards"
+msgstr "--literal\t\tNie rozwijaj znaków specjalnych"
+
+msgid "-register\t\tRegister this gvim for OLE"
+msgstr "-register\t\tZarejestruj tego gvima w OLE"
+
+msgid "-unregister\t\tUnregister gvim for OLE"
+msgstr "-unregister\t\tWyrejestruj gvima z OLE"
+
+msgid "-g\t\t\tRun using GUI (like \"gvim\")"
+msgstr "-g\t\t\tStartuj w GUI (tak jak \"gvim\")"
+
+msgid "-f or --nofork\tForeground: Don't fork when starting GUI"
+msgstr "-f lub --nofork\tPierwszy plan: Nie wydzielaj przy odpalaniu GUI"
+
+msgid "-v\t\t\tVi mode (like \"vi\")"
+msgstr "-v\t\t\tTryb vi (jak \"vi\")"
+
+msgid "-e\t\t\tEx mode (like \"ex\")"
+msgstr "-e\t\t\tTryb ex (jak \"ex\")"
+
+msgid "-E\t\t\tImproved Ex mode"
+msgstr "-E\t\t\tUsprawniony tryb Ex"
+
+msgid "-s\t\t\tSilent (batch) mode (only for \"ex\")"
+msgstr "-s\t\t\tCichy tryb (t³a) (tylko dla \"ex\")"
+
+msgid "-d\t\t\tDiff mode (like \"vimdiff\")"
+msgstr "-d\t\t\tTryb ró¿nic (jak \"vimdiff\")"
+
+msgid "-y\t\t\tEasy mode (like \"evim\", modeless)"
+msgstr "-y\t\t\tTryb ³atwy (jak \"evim\", bez trybów)"
+
+msgid "-R\t\t\tReadonly mode (like \"view\")"
+msgstr "-R\t\t\tTryb wy³±cznie do odczytu (jak \"view\")"
+
+msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
+msgstr "-Z\t\t\tTryb ograniczenia (jak \"rvim\")"
+
+msgid "-m\t\t\tModifications (writing files) not allowed"
+msgstr "-m\t\t\tModyfikacje (zapisywanie plików) niedozwolone"
+
+msgid "-M\t\t\tModifications in text not allowed"
+msgstr "-M\t\t\tZakaz modyfikacji tekstu"
+
+msgid "-b\t\t\tBinary mode"
+msgstr "-b\t\t\tTryb binarny"
+
+msgid "-l\t\t\tLisp mode"
+msgstr "-l\t\t\tTryb lisp"
+
+msgid "-C\t\t\tCompatible with Vi: 'compatible'"
+msgstr "-C\t\t\tB±d¼ zgodny z Vi: 'compatible'"
+
+msgid "-N\t\t\tNot fully Vi compatible: 'nocompatible'"
+msgstr "-N\t\t\tB±d¼ niezupe³nie zgodny z Vi: 'nocompatible'"
+
+msgid "-V[N][fname]\t\tBe verbose [level N] [log messages to fname]"
+msgstr "-V[N][nazwap]\t\tGadatliwy [poziom N] [zapisuj wiadomo¶ci do nazwap]"
+
+msgid "-D\t\t\tDebugging mode"
+msgstr "-D\t\t\tTryb odpluskwiania"
+
+msgid "-n\t\t\tNo swap file, use memory only"
+msgstr "-n\t\t\tZamiast pliku wymiany, u¿ywaj tylko pamiêci"
+
+msgid "-r\t\t\tList swap files and exit"
+msgstr "-r\t\t\tWylicz pliki wymiany i zakoñcz"
+
+msgid "-r (with file name)\tRecover crashed session"
+msgstr "-r (z nazw± pliku)\tOdtwórz za³aman± sesjê"
+
+msgid "-L\t\t\tSame as -r"
+msgstr "-L\t\t\tTo¿same z -r"
+
+msgid "-f\t\t\tDon't use newcli to open window"
+msgstr "-f\t\t\tNie stosuj newcli do otwierania okien"
+
+msgid "-dev <device>\t\tUse <device> for I/O"
+msgstr "-dev <device>\t\tU¿ywaj <device> do I/O"
+
+msgid "-A\t\t\tStart in Arabic mode"
+msgstr "-A\t\t\trozpocznij w trybie arabskim"
+
+msgid "-H\t\t\tStart in Hebrew mode"
+msgstr "-H\t\t\trozpocznij w trybie hebrajskim"
+
+msgid "-F\t\t\tStart in Farsi mode"
+msgstr "-F\t\t\trozpocznij w trybie farsi"
+
+msgid "-T <terminal>\tSet terminal type to <terminal>"
+msgstr "-T <terminal>\tUstaw typ terminala na <terminal>"
+
+msgid "-u <vimrc>\t\tUse <vimrc> instead of any .vimrc"
+msgstr "-u <vimrc>\t\tU¿yj <vimrc> zamiast jakiegokolwiek .vimrc"
+
+msgid "-U <gvimrc>\t\tUse <gvimrc> instead of any .gvimrc"
+msgstr "-U <gvimrc>\t\tU¿yj <gvimrc> zamiast jakiegokolwiek .gvimrc"
+
+msgid "--noplugin\t\tDon't load plugin scripts"
+msgstr "--noplugin\t\tNie ³aduj skryptów wtyczek"
+
+msgid "-p[N]\t\tOpen N tab pages (default: one for each file)"
+msgstr "-p[N]\t\tOtwórz N kart (domy¶lnie: po jednej dla ka¿dego pliku)"
+
+msgid "-o[N]\t\tOpen N windows (default: one for each file)"
+msgstr "-o[N]\t\tOtwórz N okien (domy¶lnie: po jednym dla ka¿dego pliku)"
+
+msgid "-O[N]\t\tLike -o but split vertically"
+msgstr "-O[N]\t\ttak samo jak -o tylko dziel okno pionowo"
+
+msgid "+\t\t\tStart at end of file"
+msgstr "+\t\t\tZacznij na koñcu pliku"
+
+msgid "+<lnum>\t\tStart at line <lnum>"
+msgstr "+<lnum>\t\tZacznij w wierszu <lnum>"
+
+msgid "--cmd <command>\tExecute <command> before loading any vimrc file"
+msgstr ""
+"-cmd <command>\t\tWykonaj komendê <command> przed za³adowaniem "
+"jakiegokolwiek pliku vimrc"
+
+msgid "-c <command>\t\tExecute <command> after loading the first file"
+msgstr ""
+"-c <command>\t\tWykonaj komendê <command> po za³adowaniu pierwszego pliku"
+
+msgid "-S <session>\t\tSource file <session> after loading the first file"
+msgstr "-S <sesja>\t\tWczytaj plik <sesja> po za³adowaniu pierwszego pliku"
+
+msgid "-s <scriptin>\tRead Normal mode commands from file <scriptin>"
+msgstr "-s <scriptin>\tWczytuj komendy trybu normalnego z pliku <scriptin>"
+
+msgid "-w <scriptout>\tAppend all typed commands to file <scriptout>"
+msgstr ""
+"-w <scriptout>\tDo³±cz wszystkie wprowadzane komendy do pliku <scriptout>"
+
+msgid "-W <scriptout>\tWrite all typed commands to file <scriptout>"
+msgstr ""
+"-W <scriptout>\tZapisuj wszystkie wprowadzane komendy do pliku <scriptout>"
+
+msgid "-x\t\t\tEdit encrypted files"
+msgstr "-x\t\t\tEdytuj zakodowane pliki"
+
+msgid "-display <display>\tConnect vim to this particular X-server"
+msgstr "-display <display>\tPod³±cz vima to danego X-serwera"
+
+msgid "-X\t\t\tDo not connect to X server"
+msgstr "-X\t\t\tNie ³±cz z serwerem X"
+
+msgid "--remote <files>\tEdit <files> in a Vim server if possible"
+msgstr "--remote <pliki>\tEdytuj pliki w serwerze Vima je¶li mo¿liwe"
+
+msgid "--remote-silent <files> Same, don't complain if there is no server"
+msgstr "--remote-silent <pliki> To samo, nie narzekaj je¶li nie ma serwera"
+
+msgid ""
+"--remote-wait <files> As --remote but wait for files to have been edited"
+msgstr ""
+"--remote-wait <pliki>\tTak jak --remote, lecz czekaj na pliki przed edycj±"
+
+msgid ""
+"--remote-wait-silent <files> Same, don't complain if there is no server"
+msgstr ""
+"--remote-wait-silent <pliki> To samo, nie narzekaj je¶li nie ma serwera"
+
+msgid ""
+"--remote-tab[-wait][-silent] <files> As --remote but use tab page per file"
+msgstr ""
+"--remote-tab[-wait][-silent] <pliki> tak jak --remote ale u¿ywa jednej "
+"karty na plik"
+
+msgid "--remote-send <keys>\tSend <keys> to a Vim server and exit"
+msgstr "--remote-send <klawisze>\tWy¶lij <klawisze> do serwera Vima i zakoñcz"
+
+msgid "--remote-expr <expr>\tEvaluate <expr> in a Vim server and print result"
+msgstr "--remote-expr <wyr>\tWykonaj <wyra¿enie> w serwerze i wypisz wynik"
+
+msgid "--serverlist\t\tList available Vim server names and exit"
+msgstr "--serverlist\t\tWymieñ nazwy dostêpnych serwerów Vima i zakoñcz"
+
+msgid "--servername <name>\tSend to/become the Vim server <name>"
+msgstr "--servername <nazwa>\t\tOdsy³aj do/stañ siê serwerem Vim <nazwa>"
+
+msgid "--startuptime <file>\tWrite startup timing messages to <file>"
+msgstr ""
+"--startuptime <plik> "
+"Zapisz wiadomo¶ci o d³ugo¶ci startu do <plik>"
+
+msgid "-i <viminfo>\t\tUse <viminfo> instead of .viminfo"
+msgstr "-i <viminfo>\t\tU¿ywaj <viminfo> zamiast .viminfo"
+
+msgid "-h or --help\tPrint Help (this message) and exit"
+msgstr "-h lub --help\twy¶wietl Pomoc (czyli tê wiadomo¶æ) i zakoñcz"
+
+msgid "--version\t\tPrint version information and exit"
+msgstr "--version\t\twy¶wietl informacjê o wersji i zakoñcz"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Motif version):\n"
+msgstr ""
+"\n"
+"Argumenty rozpoznawane przez gvim (wersja Motif):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (neXtaw version):\n"
+msgstr ""
+"\n"
+"Argumenty rozpoznawane przez gvim (wersja neXtaw):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Athena version):\n"
+msgstr ""
+"\n"
+"Argumenty rozpoznawane przez gvim (wersja Athena):\n"
+
+msgid "-display <display>\tRun vim on <display>"
+msgstr "-display <display>\tZa³aduj vim na <display>"
+
+msgid "-iconic\t\tStart vim iconified"
+msgstr "-iconic\t\tZacznij Vim jako ikonê"
+
+msgid "-background <color>\tUse <color> for the background (also: -bg)"
+msgstr "-background <kolor>\tU¿ywaj <kolor> dla t³a (równie¿: -bg)"
+
+msgid "-foreground <color>\tUse <color> for normal text (also: -fg)"
+msgstr ""
+"-foreground <kolor>\tU¿ywaj <kolor> dla normalnego tekstu (równie¿: -fg)"
+
+msgid "-font <font>\t\tUse <font> for normal text (also: -fn)"
+msgstr "-font <font>\t\tU¿ywaj <font> dla normalnego tekstu (równie¿: -fn)"
+
+msgid "-boldfont <font>\tUse <font> for bold text"
+msgstr "-boldfont <font>\tU¿ywaj <font> dla wyt³uszczonego tekstu"
+
+msgid "-italicfont <font>\tUse <font> for italic text"
+msgstr "-italicfont <font>\tU¿ywaj <font> dla pochy³ego"
+
+msgid "-geometry <geom>\tUse <geom> for initial geometry (also: -geom)"
+msgstr ""
+"-geometry <geom>\tU¿ywaj <geom> dla pocz±tkowych rozmiarów (równie¿: -geom)"
+
+msgid "-borderwidth <width>\tUse a border width of <width> (also: -bw)"
+msgstr "-borderwidth <szer>\tU¿yj ramki o grubo¶ci <szer> (równie¿: -bw)"
+
+msgid "-scrollbarwidth <width> Use a scrollbar width of <width> (also: -sw)"
+msgstr ""
+"-scrollbarwidth <szer> U¿ywaj przewijacza o szeroko¶ci <szer> (równie¿: -sw)"
+
+msgid "-menuheight <height>\tUse a menu bar height of <height> (also: -mh)"
+msgstr ""
+"-menuheight <height>\tStosuj belkê menu o wysoko¶ci <height> (równie¿: -mh)"
+
+msgid "-reverse\t\tUse reverse video (also: -rv)"
+msgstr "-reverse\t\tStosuj negatyw kolorów (równie¿: -rv)"
+
+msgid "+reverse\t\tDon't use reverse video (also: +rv)"
+msgstr "+reverse\t\tNie stosuj negatywu kolorów (równie¿: +rv)"
+
+msgid "-xrm <resource>\tSet the specified resource"
+msgstr "-xrm <resource>\tUstaw okre¶lony zasób"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (GTK+ version):\n"
+msgstr ""
+"\n"
+"Argumenty rozpoznawane przez gvim (wersja GTK+):\n"
+
+msgid "-display <display>\tRun vim on <display> (also: --display)"
+msgstr "-display <display>\tZastartuj vim na <display> (równie¿: --display)"
+
+msgid "--role <role>\tSet a unique role to identify the main window"
+msgstr "--role <role>\tUstaw unikatow± rolê do identyfikacji g³ównego okna"
+
+msgid "--socketid <xid>\tOpen Vim inside another GTK widget"
+msgstr "--socketid <xid>\tOtwórz Vim wewn±trz innego widgetu GTK"
+
+msgid "--echo-wid\t\tMake gvim echo the Window ID on stdout"
+msgstr "-echo-wid\t\tGvim wypisze Window ID na wyj¶cie standardowe"
+
+msgid "-P <parent title>\tOpen Vim inside parent application"
+msgstr "-P <tytu³ rodzica>\tOtwórz Vima wewn±trz rodzicielskiej aplikacji"
+
+msgid "--windowid <HWND>\tOpen Vim inside another win32 widget"
+msgstr "--windowid <HWND>\tOtwórz Vima wewn±trz innego elementu win32"
+
+msgid "No display"
+msgstr "Brak display"
+
+#. Failed to send, abort.
+msgid ": Send failed.\n"
+msgstr ": Wys³anie nie powiod³o siê.\n"
+
+#. Let vim start normally.
+msgid ": Send failed. Trying to execute locally\n"
+msgstr ": Wys³anie nie powiod³o siê. Próbujê wykonaæ na miejscu\n"
+
+#, c-format
+msgid "%d of %d edited"
+msgstr "otworzono %d z %d"
+
+msgid "No display: Send expression failed.\n"
+msgstr "Brak terminala: Wys³anie wyra¿enia nie powiod³o siê.\n"
+
+msgid ": Send expression failed.\n"
+msgstr ": Wys³anie wyra¿enia nie powiod³o siê.\n"
+
+msgid "No marks set"
+msgstr "Brak zak³adek"
+
+#, c-format
+msgid "E283: No marks matching \"%s\""
+msgstr "E283: ¯adna zak³adka nie pasuje do \"%s\""
+
+#. Highlight title
+msgid ""
+"\n"
+"mark line col file/text"
+msgstr ""
+"\n"
+"zak³. wiersz kol plik/tekst"
+
+#. Highlight title
+msgid ""
+"\n"
+" jump line col file/text"
+msgstr ""
+"\n"
+" skok wiersz kol plik/tekst"
+
+#. Highlight title
+msgid ""
+"\n"
+"change line col text"
+msgstr ""
+"\n"
+"zmieñ wrsz. kol tekst"
+
+msgid ""
+"\n"
+"# File marks:\n"
+msgstr ""
+"\n"
+"# Zak³adki w plikach:\n"
+
+#. Write the jumplist with -'
+msgid ""
+"\n"
+"# Jumplist (newest first):\n"
+msgstr ""
+"\n"
+"# Lista odniesieñ (pocz±wszy od najnowszych):\n"
+
+msgid ""
+"\n"
+"# History of marks within files (newest to oldest):\n"
+msgstr ""
+"\n"
+"# Historia zak³adek w plikach (od najnowszych po najstarsze):\n"
+
+msgid "Missing '>'"
+msgstr "Brak '>'"
+
+msgid "E543: Not a valid codepage"
+msgstr "E543: To nie jest wa¿na strona kodowa"
+
+msgid "E284: Cannot set IC values"
+msgstr "E284: Nie mogê nastawiæ warto¶ci IC"
+
+msgid "E285: Failed to create input context"
+msgstr "E285: Nie mog³em stworzyæ kontekstu wprowadzeñ"
+
+msgid "E286: Failed to open input method"
+msgstr "E286: Nie mog³em otworzyæ sposobu wprowadzeñ"
+
+msgid "E287: Warning: Could not set destroy callback to IM"
+msgstr "E287: OSTRZE¯ENIE: Nie mog³em zlikwidowaæ wywo³ania dla IM"
+
+msgid "E288: input method doesn't support any style"
+msgstr "E288: metoda wprowadzeñ nie wspomaga ¿adnego stylu"
+
+msgid "E289: input method doesn't support my preedit type"
+msgstr "E289: metoda wprowadzeñ nie wspomaga mojego typu preedit"
+
+msgid "E293: block was not locked"
+msgstr "E293: blok nie by³ zablokowany"
+
+msgid "E294: Seek error in swap file read"
+msgstr "E294: B³±d w trakcie czytania pliku wymiany"
+
+msgid "E295: Read error in swap file"
+msgstr "E295: B³±d odczytu pliku wymiany"
+
+msgid "E296: Seek error in swap file write"
+msgstr "E296: B³±d szukania w pliku wymiany"
+
+msgid "E297: Write error in swap file"
+msgstr "E297: B³±d zapisu w pliku wymiany"
+
+msgid "E300: Swap file already exists (symlink attack?)"
+msgstr "E300: Plik wymiany ju¿ istnieje (atak symlink?)"
+
+msgid "E298: Didn't get block nr 0?"
+msgstr "E298: Nie otrzyma³em bloku nr 0?"
+
+msgid "E298: Didn't get block nr 1?"
+msgstr "E298: Nie otrzyma³em bloku nr 1?"
+
+msgid "E298: Didn't get block nr 2?"
+msgstr "E298: Nie otrzyma³em bloku nr 2?"
+
+msgid "E843: Error while updating swap file crypt"
+msgstr "E843: B³±d w czasie uaktualniania szyfrowania pliku wymiany"
+
+#. could not (re)open the swap file, what can we do????
+msgid "E301: Oops, lost the swap file!!!"
+msgstr "E301: Ojej, zgubi³em plik wymiany!!!"
+
+msgid "E302: Could not rename swap file"
+msgstr "E302: Nie mog³em zmieniæ nazwy pliku wymiany"
+
+#, c-format
+msgid "E303: Unable to open swap file for \"%s\", recovery impossible"
+msgstr ""
+"E303: Nie mogê otworzyæ pliku wymiany dla \"%s\"; odtworzenie niemo¿liwe"
+
+msgid "E304: ml_upd_block0(): Didn't get block 0??"
+msgstr "E304: ml_upd_block(): Nie otrzyma³em bloku 0??"
+
+#, c-format
+msgid "E305: No swap file found for %s"
+msgstr "E305: Nie znaleziono pliku wymiany dla %s"
+
+msgid "Enter number of swap file to use (0 to quit): "
+msgstr "Wprowad¼ numer pliku wymiany, którego u¿yæ (0 by wyj¶æ): "
+
+#, c-format
+msgid "E306: Cannot open %s"
+msgstr "E306: Nie mogê otworzyæ %s"
+
+msgid "Unable to read block 0 from "
+msgstr "Nie mogê odczytaæ bloku 0 z "
+
+msgid ""
+"\n"
+"Maybe no changes were made or Vim did not update the swap file."
+msgstr ""
+"\n"
+"Mo¿e nie wykonano zmian albo Vim nie zaktualizowa³ pliku wymiany."
+
+msgid " cannot be used with this version of Vim.\n"
+msgstr " nie mo¿e byæ stosowany z t± wersj± Vima.\n"
+
+msgid "Use Vim version 3.0.\n"
+msgstr "U¿yj Vima w wersji 3.0.\n"
+
+#, c-format
+msgid "E307: %s does not look like a Vim swap file"
+msgstr "E307: %s nie wygl±da na plik wymiany Vima"
+
+msgid " cannot be used on this computer.\n"
+msgstr " nie mo¿e byæ stosowany na tym komputerze.\n"
+
+msgid "The file was created on "
+msgstr "Ten plik zosta³ stworzony na "
+
+msgid ""
+",\n"
+"or the file has been damaged."
+msgstr ""
+",\n"
+"lub plik zosta³ uszkodzony."
+
+#, c-format
+msgid ""
+"E833: %s is encrypted and this version of Vim does not support encryption"
+msgstr "E833: %s jest zaszyfrowany a ta wersja Vima nie wspiera szyfrowania"
+
+msgid " has been damaged (page size is smaller than minimum value).\n"
+msgstr ""
+" zosta³ uszkodzony (wielko¶æ strony jest mniejsza ni¿ najmniejsza warto¶æ).\n"
+
+#, c-format
+msgid "Using swap file \"%s\""
+msgstr "U¿ywam pliku wymiany \"%s\""
+
+#, c-format
+msgid "Original file \"%s\""
+msgstr "Oryginalny plik \"%s\""
+
+msgid "E308: Warning: Original file may have been changed"
+msgstr "E308: OSTRZE¯ENIE: Oryginalny plik móg³ byæ zmieniony"
+
+#, c-format
+msgid "Swap file is encrypted: \"%s\""
+msgstr "Zaszyfrowany plik wymiany: \"%s\""
+
+msgid ""
+"\n"
+"If you entered a new crypt key but did not write the text file,"
+msgstr ""
+"\n"
+"Je¶li podano nowy klucz szyfruj±cy, ale nie zapisano pliku tekstowego,"
+
+msgid ""
+"\n"
+"enter the new crypt key."
+msgstr ""
+"\n"
+"wprowad¼ nowy klucz szyfruj±cy."
+
+msgid ""
+"\n"
+"If you wrote the text file after changing the crypt key press enter"
+msgstr ""
+"\n"
+"Je¶li zapisano plik tekstowy po zmianie klucza szyfruj±cego wci¶nij Enter"
+
+msgid ""
+"\n"
+"to use the same key for text file and swap file"
+msgstr ""
+"\n"
+"aby u¿yæ tego samego klucza dla pliku tekstowego i wymiany"
+
+#, c-format
+msgid "E309: Unable to read block 1 from %s"
+msgstr "E309: Nie mogê odczytaæ bloku 1 z %s"
+
+msgid "???MANY LINES MISSING"
+msgstr "???BRAKUJE WIELU WIERSZY"
+
+msgid "???LINE COUNT WRONG"
+msgstr "???LICZNIK WIERSZY NIEZGODNY"
+
+msgid "???EMPTY BLOCK"
+msgstr "???PUSTY BLOK"
+
+msgid "???LINES MISSING"
+msgstr "???BRAKUJE WIERSZY"
+
+#, c-format
+msgid "E310: Block 1 ID wrong (%s not a .swp file?)"
+msgstr "E310: Niew³a¶ciwe ID bloku 1 (mo¿e %s nie jest plikiem .swp?)"
+
+msgid "???BLOCK MISSING"
+msgstr "???BRAK BLOKU"
+
+msgid "??? from here until ???END lines may be messed up"
+msgstr "??? od tego miejsca po ???KONIEC wiersze mog± byæ pomieszane"
+
+msgid "??? from here until ???END lines may have been inserted/deleted"
+msgstr "??? od tego miejsca po ???KONIEC wiersze mog± byæ w³o¿one/skasowane"
+
+msgid "???END"
+msgstr "???KONIEC"
+
+msgid "E311: Recovery Interrupted"
+msgstr "E311: Przerwanie odtwarzania"
+
+msgid ""
+"E312: Errors detected while recovering; look for lines starting with ???"
+msgstr "E312: Wykryto b³êdy podczas odtwarzania; od których wierszy zacz±æ ???"
+
+msgid "See \":help E312\" for more information."
+msgstr "Zobacz \":help E312\" dla dalszych informacji."
+
+msgid "Recovery completed. You should check if everything is OK."
+msgstr ""
+"Odtwarzanie zakoñczono. Powiniene¶ sprawdziæ czy wszystko jest w porz±dku."
+
+msgid ""
+"\n"
+"(You might want to write out this file under another name\n"
+msgstr ""
+"\n"
+"(Mo¿esz chcieæ zapisaæ ten plik pod inn± nazw±\n"
+
+msgid "and run diff with the original file to check for changes)"
+msgstr "i wykonaæ diff z oryginalnym plikiem aby sprawdziæ zmiany)"
+
+msgid "Recovery completed. Buffer contents equals file contents."
+msgstr "Odzyskiwanie zakoñczone. Zawarto¶æ bufora jest równa zawarto¶ci pliku."
+
+msgid ""
+"\n"
+"You may want to delete the .swp file now.\n"
+"\n"
+msgstr ""
+"\n"
+"Mo¿esz teraz chcieæ usun±æ plik .swp.\n"
+"\n"
+
+msgid "Using crypt key from swap file for the text file.\n"
+msgstr "U¿ywam klucza szyfruj±cego z pliku wymiany do pliku tekstowego.\n"
+
+#. use msg() to start the scrolling properly
+msgid "Swap files found:"
+msgstr "Znalezione pliki wymiany:"
+
+msgid " In current directory:\n"
+msgstr " W bie¿±cym katalogu:\n"
+
+msgid " Using specified name:\n"
+msgstr " U¿ywam podanej nazwy:\n"
+
+msgid " In directory "
+msgstr " W katalogu "
+
+msgid " -- none --\n"
+msgstr " -- ¿aden --\n"
+
+msgid " owned by: "
+msgstr " posiadany przez: "
+
+msgid " dated: "
+msgstr " data: "
+
+msgid " dated: "
+msgstr " data: "
+
+msgid " [from Vim version 3.0]"
+msgstr " [po Vimie wersja 3.0]"
+
+msgid " [does not look like a Vim swap file]"
+msgstr " [nie wygl±da na plik wymiany Vima]"
+
+msgid " file name: "
+msgstr " nazwa pliku: "
+
+msgid ""
+"\n"
+" modified: "
+msgstr ""
+"\n"
+" zmieniono: "
+
+msgid "YES"
+msgstr "TAK"
+
+msgid "no"
+msgstr "nie"
+
+msgid ""
+"\n"
+" user name: "
+msgstr ""
+"\n"
+" u¿ytkownik: "
+
+msgid " host name: "
+msgstr " nazwa hosta: "
+
+msgid ""
+"\n"
+" host name: "
+msgstr ""
+"\n"
+" nazwa hosta: "
+
+msgid ""
+"\n"
+" process ID: "
+msgstr ""
+"\n"
+" ID procesu: "
+
+msgid " (still running)"
+msgstr " (dalej dzia³a)"
+
+msgid ""
+"\n"
+" [not usable with this version of Vim]"
+msgstr ""
+"\n"
+" [nie nadaje siê dla tej wersji Vima]"
+
+msgid ""
+"\n"
+" [not usable on this computer]"
+msgstr ""
+"\n"
+" [nie do u¿ytku na tym komputerze]"
+
+msgid " [cannot be read]"
+msgstr " [nieodczytywalny]"
+
+msgid " [cannot be opened]"
+msgstr " [nieotwieralny]"
+
+msgid "E313: Cannot preserve, there is no swap file"
+msgstr "E313: Nie mogê zabezpieczyæ, bo brak pliku wymiany"
+
+msgid "File preserved"
+msgstr "Plik zabezpieczono"
+
+msgid "E314: Preserve failed"
+msgstr "E314: Nieudane zabezpieczenie"
+
+#, c-format
+msgid "E315: ml_get: invalid lnum: %ld"
+msgstr "E315: ml_get: niew³a¶ciwy lnum: %ld"
+
+#, c-format
+msgid "E316: ml_get: cannot find line %ld"
+msgstr "E316: ml_get: nie znaleziono wiersza %ld"
+
+msgid "E317: pointer block id wrong 3"
+msgstr "E317: niepoprawne id wska¼nika bloku 3"
+
+msgid "stack_idx should be 0"
+msgstr "stack_idx powinien byæ 0"
+
+msgid "E318: Updated too many blocks?"
+msgstr "E318: Zaktualizowano zbyt wiele bloków?"
+
+msgid "E317: pointer block id wrong 4"
+msgstr "E317: niepoprawne id wska¼nika bloku 4"
+
+msgid "deleted block 1?"
+msgstr "blok nr 1 skasowany?"
+
+#, c-format
+msgid "E320: Cannot find line %ld"
+msgstr "E320: Nie mogê znale¼æ wiersza %ld"
+
+msgid "E317: pointer block id wrong"
+msgstr "E317: niepoprawne id bloku odniesienia"
+
+msgid "pe_line_count is zero"
+msgstr "pe_line_count wynosi zero"
+
+#, c-format
+msgid "E322: line number out of range: %ld past the end"
+msgstr "E322: numer wiersza poza zakresem: %ld jest poza koñcem"
+
+#, c-format
+msgid "E323: line count wrong in block %ld"
+msgstr "E323: liczba wierszy niepoprawna w bloku %ld"
+
+msgid "Stack size increases"
+msgstr "Wielko¶æ stosu wzrasta"
+
+msgid "E317: pointer block id wrong 2"
+msgstr "E317: niepoprawne id bloku odniesienia 2"
+
+#, c-format
+msgid "E773: Symlink loop for \"%s\""
+msgstr "E773: Pêtla dowi±zañ dla \"%s\""
+
+msgid "E325: ATTENTION"
+msgstr "E325: UWAGA"
+
+msgid ""
+"\n"
+"Found a swap file by the name \""
+msgstr ""
+"\n"
+"Znalaz³em plik wymiany o nazwie \""
+
+msgid "While opening file \""
+msgstr "Podczas otwierania pliku \""
+
+msgid " NEWER than swap file!\n"
+msgstr " NOWSZE od pliku wymiany!\n"
+
+#. Some of these messages are long to allow translation to
+#. * other languages.
+msgid ""
+"\n"
+"(1) Another program may be editing the same file. If this is the case,\n"
+" be careful not to end up with two different instances of the same\n"
+" file when making changes.\n"
+msgstr ""
+"\n"
+"(1) Pewnie inny program obrabia ten sam plik.\n"
+" Je¶li tak, b±d¼ ostro¿ny, aby nie skoñczyæ z dwoma\n"
+" ró¿nymi wersjami tego samego pliku po zmianach.\n"
+
+msgid " Quit, or continue with caution.\n"
+msgstr " Zakoñcz lub ostro¿nie kontynuuj.\n"
+
+msgid "(2) An edit session for this file crashed.\n"
+msgstr "(2) Sesja edycji dla pliku za³ama³a siê.\n"
+
+msgid " If this is the case, use \":recover\" or \"vim -r "
+msgstr " Je¶li tak, to u¿yj \":recover\" lub \"vim -r "
+
+msgid ""
+"\"\n"
+" to recover the changes (see \":help recovery\").\n"
+msgstr ""
+"\"\n"
+" aby odzyskaæ zmiany (zobacz \":help recovery)\").\n"
+
+msgid " If you did this already, delete the swap file \""
+msgstr " Je¶li ju¿ to zrobi³e¶, usuñ plik wymiany \""
+
+msgid ""
+"\"\n"
+" to avoid this message.\n"
+msgstr ""
+"\"\n"
+" aby unikn±æ tej wiadomo¶ci.\n"
+
+msgid "Swap file \""
+msgstr "Plik wymiany \""
+
+msgid "\" already exists!"
+msgstr "\" ju¿ istnieje!"
+
+msgid "VIM - ATTENTION"
+msgstr "VIM - UWAGA"
+
+msgid "Swap file already exists!"
+msgstr "Plik wymiany ju¿ istnieje!"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"&Otwórz Read-Only\n"
+"&Edytuj pomimo\n"
+"O&dtwórz\n"
+"&Zakoñcz\n"
+"&Porzuæ"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Delete it\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"&Otwórz Read-Only\n"
+"&Edytuj pomimo\n"
+"O&dtwórz\n"
+"&Usuñ\n"
+"&Zakoñcz\n"
+"&Porzuæ"
+
+msgid "E326: Too many swap files found"
+msgstr "E326: Znaleziono zbyt wiele plików wymiany"
+
+msgid "E327: Part of menu-item path is not sub-menu"
+msgstr "E327: Czê¶æ tropu punktu menu nie okre¶la podmenu"
+
+msgid "E328: Menu only exists in another mode"
+msgstr "E328: Menu istnieje tylko w innym trybie"
+
+#, c-format
+msgid "E329: No menu \"%s\""
+msgstr "E329: Nie ma menu \"%s\""
+
+#. Only a mnemonic or accelerator is not valid.
+msgid "E792: Empty menu name"
+msgstr "E792: Pusta nazwa menu"
+
+msgid "E330: Menu path must not lead to a sub-menu"
+msgstr "E330: Trop menu nie mo¿e prowadziæ do podmenu"
+
+msgid "E331: Must not add menu items directly to menu bar"
+msgstr "E331: Nie wolno dodawaæ punktów menu wprost do paska menu"
+
+msgid "E332: Separator cannot be part of a menu path"
+msgstr "E332: Separator nie mo¿e byæ czê¶ci± tropu menu"
+
+#. Now we have found the matching menu, and we list the mappings
+#. Highlight title
+msgid ""
+"\n"
+"--- Menus ---"
+msgstr ""
+"\n"
+"--- Menu ---"
+
+msgid "Tear off this menu"
+msgstr "Oderwij to menu"
+
+msgid "E333: Menu path must lead to a menu item"
+msgstr "E333: Trop menu musi prowadziæ do punktu menu"
+
+#, c-format
+msgid "E334: Menu not found: %s"
+msgstr "E334: Nie znaleziono menu: %s"
+
+#, c-format
+msgid "E335: Menu not defined for %s mode"
+msgstr "E335: Menu nie jest zdefiniowane dla trybu %s"
+
+msgid "E336: Menu path must lead to a sub-menu"
+msgstr "E336: Trop menu musi prowadziæ do podmenu"
+
+msgid "E337: Menu not found - check menu names"
+msgstr "E337: Nie znaleziono menu - sprawd¼ nazwy menu"
+
+#, c-format
+msgid "Error detected while processing %s:"
+msgstr "Wykryto b³±d podczas przetwarzania %s:"
+
+#, c-format
+msgid "line %4ld:"
+msgstr "wiersz %4ld:"
+
+#, c-format
+msgid "E354: Invalid register name: '%s'"
+msgstr "E354: Niew³a¶ciwa nazwa rejestru: '%s'"
+
+msgid "Messages maintainer: Bram Moolenaar <Bram@vim.org>"
+msgstr "Opiekun komunikatów: Miko³aj Machowski <mikmach@wp.pl>"
+
+msgid "Interrupt: "
+msgstr "Przerwanie: "
+
+msgid "Press ENTER or type command to continue"
+msgstr "Naci¶nij ENTER lub wprowad¼ komendê aby kontynuowaæ"
+
+#, c-format
+msgid "%s line %ld"
+msgstr "%s wiersz %ld"
+
+msgid "-- More --"
+msgstr "-- Wiêcej --"
+
+msgid " SPACE/d/j: screen/page/line down, b/u/k: up, q: quit "
+msgstr " SPACE/d/j: ekran/strona/wiersz w dó³, b/u/k: do góry, q: zakoñcz"
+
+msgid "Question"
+msgstr "Pytanie"
+
+msgid ""
+"&Yes\n"
+"&No"
+msgstr ""
+"&Tak\n"
+"&Nie"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"Save &All\n"
+"&Discard All\n"
+"&Cancel"
+msgstr ""
+"&Tak\n"
+"&Nie\n"
+"Zapisz &wszystkie\n"
+"&Odrzuæ wszystkie\n"
+"&Zakoñcz"
+
+msgid "Select Directory dialog"
+msgstr "Dialog wyboru katalogu"
+
+msgid "Save File dialog"
+msgstr "Dialog zapisywania pliku"
+
+msgid "Open File dialog"
+msgstr "Dialog otwierania pliku"
+
+#. TODO: non-GUI file selector here
+msgid "E338: Sorry, no file browser in console mode"
+msgstr "E338: Przykro mi, nie ma przegl±darki plików w trybie konsoli"
+
+msgid "E766: Insufficient arguments for printf()"
+msgstr "E766: Za ma³o argumentów dla printf()"
+
+msgid "E807: Expected Float argument for printf()"
+msgstr "E807: Spodziewany argument Zmiennoprzecinkowy w printf()"
+
+msgid "E767: Too many arguments to printf()"
+msgstr "E767: Za du¿o argumentów dla printf()"
+
+msgid "W10: Warning: Changing a readonly file"
+msgstr "W10: OSTRZE¯ENIE: Zmiany w pliku tylko do odczytu"
+
+msgid "Type number and <Enter> or click with mouse (empty cancels): "
+msgstr "Wpisz numer i <Enter> lub wybierz mysz± (pusta warto¶æ anuluje): "
+
+msgid "Type number and <Enter> (empty cancels): "
+msgstr "Wpisz numer i <Enter> (puste anuluje): "
+
+msgid "1 more line"
+msgstr "1 wiersz wiêcej"
+
+msgid "1 line less"
+msgstr "1 wiersz mniej"
+
+#, c-format
+msgid "%ld more lines"
+msgstr "dodano %ld wierszy"
+
+#, c-format
+msgid "%ld fewer lines"
+msgstr "usuniêto %ld wierszy"
+
+msgid " (Interrupted)"
+msgstr " (Przerwane)"
+
+msgid "Beep!"
+msgstr "Biiip!"
+
+msgid "Vim: preserving files...\n"
+msgstr "Vim: zachowujê plik...\n"
+
+#. close all memfiles, without deleting
+msgid "Vim: Finished.\n"
+msgstr "Vim: Zakoñczono.\n"
+
+msgid "ERROR: "
+msgstr "B£¡D: "
+
+#, c-format
+msgid ""
+"\n"
+"[bytes] total alloc-freed %lu-%lu, in use %lu, peak use %lu\n"
+msgstr ""
+"\n"
+"[bajtów] totalne alokacje-zwolnienia %lu-%lu, w u¿ytku %lu, maksymalne "
+"u¿ycie %lu\n"
+
+#, c-format
+msgid ""
+"[calls] total re/malloc()'s %lu, total free()'s %lu\n"
+"\n"
+msgstr ""
+"[wywo³ania] wszystkich re/malloc()-ów %lu, wszystkich free()-ów %lu\n"
+"\n"
+
+msgid "E340: Line is becoming too long"
+msgstr "E340: Wiersz staje siê zbyt d³ugi"
+
+#, c-format
+msgid "E341: Internal error: lalloc(%ld, )"
+msgstr "E341: Wewnêtrzny b³±d: lalloc(%ld, )"
+
+#, c-format
+msgid "E342: Out of memory! (allocating %lu bytes)"
+msgstr "E342: Brak pamiêci! (rezerwacja %lu bajtów)"
+
+#, c-format
+msgid "Calling shell to execute: \"%s\""
+msgstr "Wywo³ujê pow³okê do wykonania: \"%s\""
+
+msgid "E545: Missing colon"
+msgstr "E545: Brak dwukropka"
+
+msgid "E546: Illegal mode"
+msgstr "E546: Niedozwolony tryb"
+
+msgid "E547: Illegal mouseshape"
+msgstr "E547: Niedozwolony obrys myszki"
+
+msgid "E548: digit expected"
+msgstr "E548: oczekiwa³em na cyfrê"
+
+msgid "E549: Illegal percentage"
+msgstr "E549: Niedozwolony procent"
+
+msgid "Enter encryption key: "
+msgstr "Wprowad¼ klucz do odkodowania: "
+
+msgid "Enter same key again: "
+msgstr "Wprowad¼ ponownie ten sam klucz: "
+
+msgid "Keys don't match!"
+msgstr "Klucze nie pasuj± do siebie!"
+
+msgid "E854: path too long for completion"
+msgstr "E854: ¶cie¿ka za d³uga by uzupe³niæ"
+
+#, c-format
+msgid ""
+"E343: Invalid path: '**[number]' must be at the end of the path or be "
+"followed by '%s'."
+msgstr ""
+"E343: Niew³a¶ciwy trop: '**[numer]' musi byæ na koñcu tropu lub po nim musi "
+"byæ '%s'."
+
+#, c-format
+msgid "E344: Can't find directory \"%s\" in cdpath"
+msgstr "E344: Nie mogê znale¼æ katalogu \"%s\" w cdpath"
+
+#, c-format
+msgid "E345: Can't find file \"%s\" in path"
+msgstr "E345: Nie mogê znale¼æ pliku \"%s\" w tropie"
+
+#, c-format
+msgid "E346: No more directory \"%s\" found in cdpath"
+msgstr "E346: Katalogu \"%s\" nie ma wiêcej w cdpath"
+
+#, c-format
+msgid "E347: No more file \"%s\" found in path"
+msgstr "E347: Pliku \"%s\" nie ma wiêcej w tropie"
+
+msgid "Cannot connect to Netbeans #2"
+msgstr "Nie mo¿na po³±czyæ z Netbeans #2"
+
+msgid "Cannot connect to Netbeans"
+msgstr "Nie mo¿na po³±czyæ z Netbeans"
+
+#, c-format
+msgid "E668: Wrong access mode for NetBeans connection info file: \"%s\""
+msgstr "E668: B³êdny tryb dostêpu pliku info po³±czenia NetBeans: \"%s\""
+
+msgid "read from Netbeans socket"
+msgstr "odczyt z gniazda Netbeans"
+
+#, c-format
+msgid "E658: NetBeans connection lost for buffer %ld"
+msgstr "E658: Bufor %ld utraci³ po³±czenie z NetBeans"
+
+msgid "E838: netbeans is not supported with this GUI"
+msgstr "E838: netbeans nie s± obs³ugiwane przez to GUI"
+
+msgid "E511: netbeans already connected"
+msgstr "E511: netbeans ju¿ pod³±czone"
+
+#, c-format
+msgid "E505: %s is read-only (add ! to override)"
+msgstr "E505: %s jest tylko do odczytu (dodaj ! aby wymusiæ)"
+
+msgid "E349: No identifier under cursor"
+msgstr "E349: Brak identyfikatora pod kursorem"
+
+msgid "E774: 'operatorfunc' is empty"
+msgstr "E774: 'operatorfunc' jest pusta"
+
+msgid "E775: Eval feature not available"
+msgstr "E775: Funkcjonalno¶æ eval nie jest dostêpna"
+
+msgid "Warning: terminal cannot highlight"
+msgstr "OSTRZE¯ENIE: terminal nie wykonuje pod¶wietlania"
+
+msgid "E348: No string under cursor"
+msgstr "E348: Brak ci±gu pod kursorem"
+
+msgid "E352: Cannot erase folds with current 'foldmethod'"
+msgstr "E352: Nie mogê skasowaæ zwiniêcia z bie¿±c± 'foldmethod'"
+
+msgid "E664: changelist is empty"
+msgstr "E664: lista zmian (changelist) jest pusta"
+
+msgid "E662: At start of changelist"
+msgstr "E662: Na pocz±tku listy zmian"
+
+msgid "E663: At end of changelist"
+msgstr "E663: Na koñcu listy zmian"
+
+msgid "Type :quit<Enter> to exit Vim"
+msgstr "wprowad¼ :quit<Enter> zakoñczenie programu"
+
+#, c-format
+msgid "1 line %sed 1 time"
+msgstr "1 wiersz %sed 1 raz"
+
+#, c-format
+msgid "1 line %sed %d times"
+msgstr "1 wiersz %sed %d razy"
+
+#, c-format
+msgid "%ld lines %sed 1 time"
+msgstr "%ld wierszy %sed 1 raz"
+
+#, c-format
+msgid "%ld lines %sed %d times"
+msgstr "%ld wierszy %sed %d razy"
+
+#, c-format
+msgid "%ld lines to indent... "
+msgstr "%ld wierszy do wciêcia... "
+
+msgid "1 line indented "
+msgstr "1 wiersz wciêty "
+
+#, c-format
+msgid "%ld lines indented "
+msgstr "%ld wierszy wciêtych "
+
+msgid "E748: No previously used register"
+msgstr "E748: Brak poprzednio u¿ytego rejestru"
+
+#. must display the prompt
+msgid "cannot yank; delete anyway"
+msgstr "nie mogê skopiowaæ, mimo to kasujê"
+
+msgid "1 line changed"
+msgstr "1 wiersz zmieniono"
+
+#, c-format
+msgid "%ld lines changed"
+msgstr "%ld wierszy zmieniono"
+
+#, c-format
+msgid "freeing %ld lines"
+msgstr "zwalniam %ld wierszy"
+
+msgid "block of 1 line yanked"
+msgstr "skopiowano blok 1 wiersza"
+
+msgid "1 line yanked"
+msgstr "1 wiersz skopiowano"
+
+#, c-format
+msgid "block of %ld lines yanked"
+msgstr "%ld wierszy skopiowanych"
+
+#, c-format
+msgid "%ld lines yanked"
+msgstr "%ld wierszy skopiowanych"
+
+#, c-format
+msgid "E353: Nothing in register %s"
+msgstr "E353: Pusty rejestr %s"
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Registers ---"
+msgstr ""
+"\n"
+"--- Rejestry ---"
+
+msgid "Illegal register name"
+msgstr "Niedozwolona nazwa rejestru"
+
+msgid ""
+"\n"
+"# Registers:\n"
+msgstr ""
+"\n"
+"# Rejestry:\n"
+
+#, c-format
+msgid "E574: Unknown register type %d"
+msgstr "E574: Nieznany typ rejestru %d"
+
+#, c-format
+msgid "%ld Cols; "
+msgstr "%ld Kolumn; "
+
+#, c-format
+msgid "Selected %s%ld of %ld Lines; %ld of %ld Words; %ld of %ld Bytes"
+msgstr "Wybrano %s%ld z %ld Wierszy; %ld z %ld S³ów; %ld z %ld Bajtów"
+
+#, c-format
+msgid ""
+"Selected %s%ld of %ld Lines; %ld of %ld Words; %ld of %ld Chars; %ld of %ld "
+"Bytes"
+msgstr ""
+"Wybrano %s%ld z %ld Wierszy; %ld z %ld S³ów; %ld z %ld Znaków; %ld z %ld "
+"Bajtów"
+
+#, c-format
+msgid "Col %s of %s; Line %ld of %ld; Word %ld of %ld; Byte %ld of %ld"
+msgstr "Kol %s z %s; Wiersz %ld z %ld; S³owo %ld z %ld; Bajt %ld z %ld"
+
+#, c-format
+msgid ""
+"Col %s of %s; Line %ld of %ld; Word %ld of %ld; Char %ld of %ld; Byte %ld of "
+"%ld"
+msgstr ""
+"Kol %s z %s; Wiersz %ld z %ld; S³owo %ld z %ld; Znak %ld z %ld; Bajt %ld z "
+"%ld"
+
+#, c-format
+msgid "(+%ld for BOM)"
+msgstr "(+%ld dla BOM)"
+
+msgid "%<%f%h%m%=Page %N"
+msgstr "%<%f%h%m%=Strona %N"
+
+msgid "Thanks for flying Vim"
+msgstr "Dziêki za lot Vimem"
+
+msgid "E518: Unknown option"
+msgstr "E518: Nieznana opcja"
+
+msgid "E519: Option not supported"
+msgstr "E519: Opcja nie jest wspomagana"
+
+msgid "E520: Not allowed in a modeline"
+msgstr "E520: Niedozwolone w modeline"
+
+msgid "E846: Key code not set"
+msgstr "E846: Kod klucza nie jest ustawiony"
+
+msgid "E521: Number required after ="
+msgstr "E521: Po = wymagany jest numer"
+
+msgid "E522: Not found in termcap"
+msgstr "E522: Nie znaleziono w termcap"
+
+#, c-format
+msgid "E539: Illegal character <%s>"
+msgstr "E539: Niedozwolony znak <%s>"
+
+msgid "E529: Cannot set 'term' to empty string"
+msgstr "E529: Nie mogê ustawiæ 'term' na pusty ci±g"
+
+msgid "E530: Cannot change term in GUI"
+msgstr "E530: Nie mogê zmieniæ term w GUI"
+
+msgid "E531: Use \":gui\" to start the GUI"
+msgstr "E531: U¿yj \":gui\" do odpalenia GUI"
+
+msgid "E589: 'backupext' and 'patchmode' are equal"
+msgstr "E589: 'backupext' i 'patchmode' s± to¿same"
+
+msgid "E834: Conflicts with value of 'listchars'"
+msgstr "E834: Konflikty warto¶ci 'listchars'"
+
+msgid "E835: Conflicts with value of 'fillchars'"
+msgstr "E835: Konflikty warto¶ci 'fillchars'"
+
+msgid "E617: Cannot be changed in the GTK+ 2 GUI"
+msgstr "E617: Nie mogê zmieniæ w GTK+2 GUI"
+
+msgid "E524: Missing colon"
+msgstr "E524: Brak dwukropka"
+
+msgid "E525: Zero length string"
+msgstr "E525: Ci±g o zerowej d³ugo¶ci"
+
+#, c-format
+msgid "E526: Missing number after <%s>"
+msgstr "E526: Brak numeru po <%s>"
+
+msgid "E527: Missing comma"
+msgstr "E527: Brak przecinka"
+
+msgid "E528: Must specify a ' value"
+msgstr "E528: Musi okre¶laæ warto¶æ '"
+
+msgid "E595: contains unprintable or wide character"
+msgstr "E595: zawiera niewy¶wietlalny lub szeroki znak"
+
+msgid "E596: Invalid font(s)"
+msgstr "E596: Niedozwolona czcionka/ki"
+
+msgid "E597: can't select fontset"
+msgstr "E597: nie mogê wybraæ zestawu czcionek"
+
+msgid "E598: Invalid fontset"
+msgstr "E598: Niedozwolony zestaw czcionek"
+
+msgid "E533: can't select wide font"
+msgstr "E533: nie mogê wybraæ szerokiej czcionki"
+
+msgid "E534: Invalid wide font"
+msgstr "E534: Niedozwolona szeroka czcionka"
+
+#, c-format
+msgid "E535: Illegal character after <%c>"
+msgstr "E535: Niedozwolony znak po <%c>"
+
+msgid "E536: comma required"
+msgstr "E536: wymagany przecinek"
+
+#, c-format
+msgid "E537: 'commentstring' must be empty or contain %s"
+msgstr "E537: 'commentstring' musi byæ pusty lub zawieraæ %s"
+
+msgid "E538: No mouse support"
+msgstr "E538: Brak wspomagania myszki"
+
+msgid "E540: Unclosed expression sequence"
+msgstr "E540: Niedomkniêty ci±g wyra¿eñ"
+
+msgid "E541: too many items"
+msgstr "E541: zbyt wiele elementów"
+
+msgid "E542: unbalanced groups"
+msgstr "E542: niezbalansowane grupy"
+
+msgid "E590: A preview window already exists"
+msgstr "E590: okno podgl±du ju¿ istnieje"
+
+msgid "W17: Arabic requires UTF-8, do ':set encoding=utf-8'"
+msgstr "W17: Arabski wymaga UTF-8, zrób ':set encoding=utf-8'"
+
+#, c-format
+msgid "E593: Need at least %d lines"
+msgstr "E593: Potrzebujê przynajmniej %d wierszy"
+
+#, c-format
+msgid "E594: Need at least %d columns"
+msgstr "E594: Potrzebujê przynajmniej %d kolumn"
+
+#, c-format
+msgid "E355: Unknown option: %s"
+msgstr "E355: Nieznana opcja: %s"
+
+#. There's another character after zeros or the string
+#. * is empty. In both cases, we are trying to set a
+#. * num option using a string.
+#, c-format
+msgid "E521: Number required: &%s = '%s'"
+msgstr "E521: Wymagana Liczba: &%s = '%s'"
+
+msgid ""
+"\n"
+"--- Terminal codes ---"
+msgstr ""
+"\n"
+"--- Kody terminala ---"
+
+msgid ""
+"\n"
+"--- Global option values ---"
+msgstr ""
+"\n"
+"--- Globalne warto¶ci opcji ---"
+
+msgid ""
+"\n"
+"--- Local option values ---"
+msgstr ""
+"\n"
+"--- Lokalne warto¶ci opcji ---"
+
+msgid ""
+"\n"
+"--- Options ---"
+msgstr ""
+"\n"
+"--- Opcje ---"
+
+msgid "E356: get_varp ERROR"
+msgstr "E356: B£¡D get_varp"
+
+#, c-format
+msgid "E357: 'langmap': Matching character missing for %s"
+msgstr "E357: 'langmap': Brak pasuj±cego znaku dla %s"
+
+#, c-format
+msgid "E358: 'langmap': Extra characters after semicolon: %s"
+msgstr "E358: 'langmap': Dodatkowe znaki po ¶redniku: %s"
+
+msgid "cannot open "
+msgstr "nie mogê otworzyæ "
+
+msgid "VIM: Can't open window!\n"
+msgstr "VIM: Nie mogê otworzyæ okna!\n"
+
+msgid "Need Amigados version 2.04 or later\n"
+msgstr "Potrzebujê Amigados w wersji 2.04 lub pó¼niejsz±\n"
+
+#, c-format
+msgid "Need %s version %ld\n"
+msgstr "Potrzebujê %s w wersji %ld\n"
+
+msgid "Cannot open NIL:\n"
+msgstr "Nie mogê otworzyæ NIL:\n"
+
+msgid "Cannot create "
+msgstr "Nie mogê stworzyæ "
+
+#, c-format
+msgid "Vim exiting with %d\n"
+msgstr "Vim koñczy pracê z %d\n"
+
+msgid "cannot change console mode ?!\n"
+msgstr "nie mogê zmieniæ trybu konsoli ?!\n"
+
+msgid "mch_get_shellsize: not a console??\n"
+msgstr "mch_get_shellsize: nie jest konsol±??\n"
+
+#. if Vim opened a window: Executing a shell may cause crashes
+msgid "E360: Cannot execute shell with -f option"
+msgstr "E360: Nie mogê wykonaæ pow³oki z opcj± -f"
+
+msgid "Cannot execute "
+msgstr "Nie mogê wykonaæ "
+
+msgid "shell "
+msgstr "pow³oka "
+
+msgid " returned\n"
+msgstr " zwróci³\n"
+
+msgid "ANCHOR_BUF_SIZE too small."
+msgstr "ANCHOR_BUF_SIZE zbyt niskie."
+
+msgid "I/O ERROR"
+msgstr "B£¡D I/O"
+
+msgid "Message"
+msgstr "Wiadomo¶æ"
+
+msgid "'columns' is not 80, cannot execute external commands"
+msgstr "'columns' nie wynosi 80, nie mogê wykonaæ zewnêtrznych komend"
+
+msgid "E237: Printer selection failed"
+msgstr "E237: Wybór drukarki nie powiód³ siê"
+
+#, c-format
+msgid "to %s on %s"
+msgstr "do %s z %s"
+
+#, c-format
+msgid "E613: Unknown printer font: %s"
+msgstr "E613: Nieznana czcionka drukarki: %s"
+
+#, c-format
+msgid "E238: Print error: %s"
+msgstr "E238: B³±d drukarki: %s"
+
+#, c-format
+msgid "Printing '%s'"
+msgstr "Wydrukowano '%s'"
+
+#, c-format
+msgid "E244: Illegal charset name \"%s\" in font name \"%s\""
+msgstr ""
+"E244: Niedozwolona nazwa zestawu znaków \"%s\" w nazwie czcionki \"%s\""
+
+#, c-format
+msgid "E245: Illegal char '%c' in font name \"%s\""
+msgstr "E245: Niedozwolony znak '%c' w nazwie czcionki \"%s\""
+
+msgid "Vim: Double signal, exiting\n"
+msgstr "Vim: Podwójny sygna³, wychodzê\n"
+
+#, c-format
+msgid "Vim: Caught deadly signal %s\n"
+msgstr "Vim: Za³apa³ ¶miertelny sygna³ %s\n"
+
+#, c-format
+msgid "Vim: Caught deadly signal\n"
+msgstr "Vim: Za³apa³ ¶miertelny sygna³\n"
+
+#, c-format
+msgid "Opening the X display took %ld msec"
+msgstr "Otwieranie ekranu X trwa³o %ld msec"
+
+msgid ""
+"\n"
+"Vim: Got X error\n"
+msgstr ""
+"\n"
+"Vim: Dosta³ b³±d X\n"
+
+msgid "Testing the X display failed"
+msgstr "Test ekranu X nie powiód³ siê"
+
+msgid "Opening the X display timed out"
+msgstr "Próba otwarcia ekranu X trwa³a zbyt d³ugo"
+
+msgid ""
+"\n"
+"Could not get security context for "
+msgstr ""
+"\n"
+"Nie mogê uzyskaæ kontekstu bezpieczeñstwa dla"
+
+msgid ""
+"\n"
+"Could not set security context for "
+msgstr ""
+"\n"
+"Nie mo¿na uzyskaæ kontekstu bezpieczeñstwa dla"
+
+msgid ""
+"\n"
+"Cannot execute shell "
+msgstr ""
+"\n"
+"Nie mogê wykonaæ pow³oki "
+
+msgid ""
+"\n"
+"Cannot execute shell sh\n"
+msgstr ""
+"\n"
+"Nie mogê wykonaæ pow³oki sh\n"
+
+msgid ""
+"\n"
+"shell returned "
+msgstr ""
+"\n"
+"pow³oka zwróci³a "
+
+msgid ""
+"\n"
+"Cannot create pipes\n"
+msgstr ""
+"\n"
+"Nie mogê stworzyæ potoków\n"
+
+msgid ""
+"\n"
+"Cannot fork\n"
+msgstr ""
+"\n"
+"Nie mogê rozdzieliæ siê\n"
+
+msgid ""
+"\n"
+"Command terminated\n"
+msgstr ""
+"\n"
+"Komenda zakoñczona\n"
+
+msgid "XSMP lost ICE connection"
+msgstr "XSMP straci³ po³±czenie ICE"
+
+#, c-format
+msgid "dlerror = \"%s\""
+msgstr "dlerror = \"%s\""
+
+msgid "Opening the X display failed"
+msgstr "Otwarcie ekranu X nie powiod³o siê"
+
+msgid "XSMP handling save-yourself request"
+msgstr "XSMP obs³uguje ¿±danie samozapisu"
+
+msgid "XSMP opening connection"
+msgstr "XSMP otwiera po³±czenie"
+
+msgid "XSMP ICE connection watch failed"
+msgstr "Obserwacja po³±czenia XSMP ICE nie powiod³a siê"
+
+#, c-format
+msgid "XSMP SmcOpenConnection failed: %s"
+msgstr "XSMP SmcOpenConnection nie powiod³o siê: %s"
+
+msgid "At line"
+msgstr "W wierszu"
+
+msgid "Could not load vim32.dll!"
+msgstr "Nie mogê za³adowaæ vim32.dll!"
+
+msgid "VIM Error"
+msgstr "B³±d VIM"
+
+msgid "Could not fix up function pointers to the DLL!"
+msgstr "Nie zdo³a³em poprawiæ wska¼ników funkcji w DLL!"
+
+#, c-format
+msgid "shell returned %d"
+msgstr "pow³oka zwróci³a %d"
+
+#, c-format
+msgid "Vim: Caught %s event\n"
+msgstr "Vim: Za³apa³ wydarzenie %s\n"
+
+msgid "close"
+msgstr "zamknij"
+
+msgid "logoff"
+msgstr "wyloguj"
+
+msgid "shutdown"
+msgstr "zakoñcz"
+
+msgid "E371: Command not found"
+msgstr "E371: Nie znaleziono komendy"
+
+msgid ""
+"VIMRUN.EXE not found in your $PATH.\n"
+"External commands will not pause after completion.\n"
+"See :help win32-vimrun for more information."
+msgstr ""
+"VIMRUN.EXE nie znaleziono w twoim $PATH.\n"
+"Zewnêtrzne komendy nie bêd± wstrzymane po wykonaniu.\n"
+"Zobacz :help wim32-vimrun aby otrzymaæ wiêcej informacji."
+
+msgid "Vim Warning"
+msgstr "Vim Ostrze¿enie"
+
+#, c-format
+msgid "E372: Too many %%%c in format string"
+msgstr "E372: Zbyt wiele %%%c w ci±gu formatuj±cym"
+
+#, c-format
+msgid "E373: Unexpected %%%c in format string"
+msgstr "E373: Nieoczekiwane %%%c w ci±gu formatuj±cym"
+
+msgid "E374: Missing ] in format string"
+msgstr "E374: Brak ] w ci±gu formatuj±cym"
+
+#, c-format
+msgid "E375: Unsupported %%%c in format string"
+msgstr "E375: Niewspomagane %%%c w ci±gu formatuj±cym"
+
+#, c-format
+msgid "E376: Invalid %%%c in format string prefix"
+msgstr "E376: Niepoprawne %%%c w prefiksie ci±gu formatuj±cego"
+
+#, c-format
+msgid "E377: Invalid %%%c in format string"
+msgstr "E377: Niepoprawne %%%c w ci±gu formatuj±cym"
+
+msgid "E378: 'errorformat' contains no pattern"
+msgstr "E378: 'errorformat' nie zawiera wzorca"
+
+msgid "E379: Missing or empty directory name"
+msgstr "E379: Pusta nazwa katalogu lub jej brak"
+
+msgid "E553: No more items"
+msgstr "E553: Nie ma wiêcej elementów"
+
+#, c-format
+msgid "(%d of %d)%s%s: "
+msgstr "(%d z %d)%s%s: "
+
+msgid " (line deleted)"
+msgstr " (wiersz skasowany)"
+
+msgid "E380: At bottom of quickfix stack"
+msgstr "E380: Na dole stosu quickfix"
+
+msgid "E381: At top of quickfix stack"
+msgstr "E381: Na górze stosu quickfix"
+
+#, c-format
+msgid "error list %d of %d; %d errors"
+msgstr "lista b³êdów %d z %d; %d b³êdów"
+
+msgid "E382: Cannot write, 'buftype' option is set"
+msgstr "E382: Nie mogê zapisaæ, opcja 'buftype' jest ustawiona"
+
+msgid "Error file"
+msgstr "Plik b³êdu"
+
+msgid "E683: File name missing or invalid pattern"
+msgstr "E683: Brak nazwy pliku lub niew³a¶ciwa ¶cie¿ka"
+
+#, c-format
+msgid "Cannot open file \"%s\""
+msgstr "Nie mogê otworzyæ pliku \"%s\""
+
+msgid "E681: Buffer is not loaded"
+msgstr "E681: Bufor nie jest za³adowany"
+
+msgid "E777: String or List expected"
+msgstr "E777: Oczekiwa³em na ³añcuch lub listê"
+
+#, c-format
+msgid "E369: invalid item in %s%%[]"
+msgstr "E369: Niew³a¶ciwy element w %s%%[]"
+
+#, c-format
+msgid "E769: Missing ] after %s["
+msgstr "E769: Brak ] po %s["
+
+#, c-format
+msgid "E53: Unmatched %s%%("
+msgstr "E53: Niesparowany %s%%("
+
+#, c-format
+msgid "E54: Unmatched %s("
+msgstr "E54: Niesparowany %s("
+
+#, c-format
+msgid "E55: Unmatched %s)"
+msgstr "E55: Niesparowany %s)"
+
+msgid "E66: \\z( not allowed here"
+msgstr "E66: \\z( jest niedozwolone w tym miejscu"
+
+msgid "E67: \\z1 - \\z9 not allowed here"
+msgstr "E67: \\z1 i podobne s± niedozwolone w tym miejscu"
+
+#, c-format
+msgid "E69: Missing ] after %s%%["
+msgstr "E69: Brak ] po %s%%["
+
+#, c-format
+msgid "E70: Empty %s%%[]"
+msgstr "E70: Pusty %s%%[]"
+
+msgid "E339: Pattern too long"
+msgstr "E339: Zbyt d³ugi wzorzec"
+
+msgid "E50: Too many \\z("
+msgstr "E50: Zbyt wiele \\z("
+
+#, c-format
+msgid "E51: Too many %s("
+msgstr "E51: Zbyt wiele %s("
+
+msgid "E52: Unmatched \\z("
+msgstr "E52: Niesparowany \\z("
+
+#, c-format
+msgid "E59: invalid character after %s@"
+msgstr "E59: niedozwolony znak po %s@"
+
+#, c-format
+msgid "E60: Too many complex %s{...}s"
+msgstr "E60: Zbyt wiele z³o¿onych %s{...}"
+
+#, c-format
+msgid "E61: Nested %s*"
+msgstr "E61: Zagnie¿d¿one %s*"
+
+#, c-format
+msgid "E62: Nested %s%c"
+msgstr "E62: Zagnie¿d¿one %s%c"
+
+msgid "E63: invalid use of \\_"
+msgstr "E63: Niedozwolone u¿ycie \\_"
+
+#, c-format
+msgid "E64: %s%c follows nothing"
+msgstr "E64: %s%c po niczym"
+
+msgid "E65: Illegal back reference"
+msgstr "E65: Niew³a¶ciwe odwo³anie wsteczne"
+
+msgid "E68: Invalid character after \\z"
+msgstr "E68: niedopuszczalny znak po \\z"
+
+#, c-format
+msgid "E678: Invalid character after %s%%[dxouU]"
+msgstr "E678: Niedozwolony znak po %s%%[dxouU]"
+
+#, c-format
+msgid "E71: Invalid character after %s%%"
+msgstr "E71: Niedozwolony znak po %s%%"
+
+#, c-format
+msgid "E554: Syntax error in %s{...}"
+msgstr "E554: B³±d sk³adni w %s{...}"
+
+msgid "External submatches:\n"
+msgstr "Zewnêtrzne poddopasowania:\n"
+
+msgid ""
+"E864: \\%#= can only be followed by 0, 1, or 2. The automatic engine will be "
+"used "
+msgstr "E:864: \\%#= mo¿e byæ tylko przed 0, 1 lub 2. Zostanie u¿yty silnik automatyczny"
+
+#, c-format
+msgid "E866: (NFA regexp) Misplaced %c"
+msgstr "E866: (wyra¿enie regularne NFA) Niepoprawnie umieszczone %c"
+
+msgid "E865: (NFA) Regexp end encountered prematurely"
+msgstr "E865: (NFA) przedwczesny koniec wyra¿enia regularnego"
+
+#, c-format
+msgid "E867: (NFA) Unknown operator '\\z%c'"
+msgstr "E867: (NFA) Nieznany operator '\\z%c'"
+
+#, c-format
+msgid "E867: (NFA) Unknown operator '\\%%%c'"
+msgstr "E867: (NFA) Nieznany operator '\\%%%c'"
+
+#. should never happen
+msgid "E868: Error building NFA with equivalence class!"
+msgstr "E868: B³±d przy budowwaniu NFA z klas± ekwiwalencji"
+
+#, c-format
+msgid "E869: (NFA) Unknown operator '\\@%c'"
+msgstr "E869: (NFA) Nieznany operator '\\@%c'"
+
+msgid "E870: (NFA regexp) Error reading repetition limits"
+msgstr "E870: (wyra¿enie regularne NFA) B³±d przy odczytywaniu limitów powtórzeñ"
+
+#. Can't have a multi follow a multi.
+msgid "E871: (NFA regexp) Can't have a multi follow a multi"
+msgstr "E871: (wyra¿enie regularne NFA) wielokrotne nie mo¿e byæ po wielokrotnym"
+
+#. Too many `('
+msgid "E872: (NFA regexp) Too many '('"
+msgstr "E872: (wyra¿enie regularne NFA) Zbyt du¿o '('"
+
+msgid "E879: (NFA regexp) Too many \\z("
+msgstr "E879: (wyra¿enie regularne NFA) Za du¿o \\z("
+
+msgid "E873: (NFA regexp) proper termination error"
+msgstr "E873: (wyra¿enie regularne NFA) b³±d poprawnego zakoñczenia"
+
+msgid "E874: (NFA) Could not pop the stack!"
+msgstr "E874: (NFA) Nie mo¿na zdj±æ elementu ze stosu!"
+
+msgid ""
+"E875: (NFA regexp) (While converting from postfix to NFA), too many states "
+"left on stack"
+msgstr "E875: (wyra¿enie regularne NFA) (w trakcie konwersji postfix do NFA), za wiele stanów na stosie"
+
+msgid "E876: (NFA regexp) Not enough space to store the whole NFA "
+msgstr "E876: (wyra¿enie regularne NFA) Nie ma miejsca na ca³e NFA "
+
+msgid "E878: (NFA) Could not allocate memory for branch traversal!"
+msgstr "E878: (NFA) Nie mo¿na przydzieliæ pamiêci do przej¶cia przez ga³êzie!"
+
+msgid ""
+"Could not open temporary log file for writing, displaying on stderr... "
+msgstr "Nie mo¿na otworzyæ do zapisu tymczasowego pliku, pokazujê na stderr... "
+
+#, c-format
+msgid "(NFA) COULD NOT OPEN %s !"
+msgstr "(NFA) NIE MO¯NA OTWORZYÆ %s !"
+
+msgid "Could not open temporary log file for writing "
+msgstr "Nie mo¿na otworzyæ do zapisu tymczasowego pliku logowania"
+
+msgid " VREPLACE"
+msgstr " V-ZAMIANA"
+
+msgid " REPLACE"
+msgstr " ZAMIANA"
+
+msgid " REVERSE"
+msgstr " NEGATYW"
+
+msgid " INSERT"
+msgstr " WPROWADZANIE"
+
+msgid " (insert)"
+msgstr " (wprowadzanie)"
+
+msgid " (replace)"
+msgstr " (zamiana)"
+
+msgid " (vreplace)"
+msgstr " (v-zamiana)"
+
+msgid " Hebrew"
+msgstr " Hebrajski"
+
+msgid " Arabic"
+msgstr " Arabski"
+
+msgid " (lang)"
+msgstr " (jêzyk)"
+
+msgid " (paste)"
+msgstr " (wklejanie)"
+
+msgid " VISUAL"
+msgstr " WIZUALNY"
+
+msgid " VISUAL LINE"
+msgstr " WIZUALNY LINIOWY"
+
+msgid " VISUAL BLOCK"
+msgstr " WIZUALNY BLOKOWY"
+
+msgid " SELECT"
+msgstr " ZAZNACZANIE"
+
+msgid " SELECT LINE"
+msgstr " ZAZNACZANIE LINIOWE"
+
+msgid " SELECT BLOCK"
+msgstr " ZAZNACZANIE BLOKOWE"
+
+msgid "recording"
+msgstr "zapis"
+
+#, c-format
+msgid "E383: Invalid search string: %s"
+msgstr "E383: Niew³a¶ciwy ci±g do szukania: %s"
+
+#, c-format
+msgid "E384: search hit TOP without match for: %s"
+msgstr "E384: szukanie dobi³o GÓRY bez znalezienia: %s"
+
+#, c-format
+msgid "E385: search hit BOTTOM without match for: %s"
+msgstr "E385: szukanie dobi³o KOÑCA bez znalezienia : %s"
+
+msgid "E386: Expected '?' or '/' after ';'"
+msgstr "E386: Oczekujê '?' lub '/' po ';'"
+
+msgid " (includes previously listed match)"
+msgstr " (zawiera poprzednio wymienione dopasowanie)"
+
+#. cursor at status line
+msgid "--- Included files "
+msgstr "--- Zawarte pliki "
+
+msgid "not found "
+msgstr "nie znaleziono"
+
+msgid "in path ---\n"
+msgstr "w tropie ---\n"
+
+msgid " (Already listed)"
+msgstr " (Ju¿ wymienione)"
+
+msgid " NOT FOUND"
+msgstr " NIE ZNALEZIONO"
+
+#, c-format
+msgid "Scanning included file: %s"
+msgstr "Przegl±d w³±czonego pliku: %s"
+
+#, c-format
+msgid "Searching included file %s"
+msgstr "Przeszukiwanie w³±czonego pliku %s"
+
+msgid "E387: Match is on current line"
+msgstr "E387: Wzorzec pasuje w bie¿±cym wierszu"
+
+msgid "All included files were found"
+msgstr "Wszelkie w³±czane pliki odnaleziono"
+
+msgid "No included files"
+msgstr "Brak w³±czanych plików"
+
+msgid "E388: Couldn't find definition"
+msgstr "E388: Nie znalaz³em definicji"
+
+msgid "E389: Couldn't find pattern"
+msgstr "E389: Nie znalaz³em wzorca"
+
+msgid "Substitute "
+msgstr "Podstawienie "
+
+#, c-format
+msgid ""
+"\n"
+"# Last %sSearch Pattern:\n"
+"~"
+msgstr ""
+"\n"
+"# Ostatni %sWyszukiwany wzorzec:\n"
+"~"
+
+msgid "E759: Format error in spell file"
+msgstr "E759: Nieprawid³owy format pliku sprawdzania pisowni"
+
+msgid "E758: Truncated spell file"
+msgstr "E758: Obciêty plik sprawdzania pisowni"
+
+#, c-format
+msgid "Trailing text in %s line %d: %s"
+msgstr "Zbêdny tekst w %s wiersz %d: %s"
+
+#, c-format
+msgid "Affix name too long in %s line %d: %s"
+msgstr "Za d³uga nazwa afiksu w %s wiersz %d: %s"
+
+msgid "E761: Format error in affix file FOL, LOW or UPP"
+msgstr "E761: B³±d formatu w pliku afiksów FOL, LOW lub UPP"
+
+msgid "E762: Character in FOL, LOW or UPP is out of range"
+msgstr "E762: Znak w FOL, LOW lub UPP jest poza zasiêgiem"
+
+msgid "Compressing word tree..."
+msgstr "Kompresja drzewa s³ów..."
+
+msgid "E756: Spell checking is not enabled"
+msgstr "E756: Sprawdzanie pisowni nie jest w³±czone"
+
+#, c-format
+msgid "Warning: Cannot find word list \"%s_%s.spl\" or \"%s_ascii.spl\""
+msgstr ""
+"Ostrze¿enie: Nie mogê znale¼æ listy s³ów \"%s_%s.spl\" lub \"%s_ascii.spl\""
+
+#, c-format
+msgid "Warning: Cannot find word list \"%s.%s.spl\" or \"%s.ascii.spl\""
+msgstr ""
+"Ostrze¿enie: Nie mogê znale¼æ listy s³ów \"%s.%s.spl\" lub \"%s.ascii.spl\""
+
+#, c-format
+msgid "Reading spell file \"%s\""
+msgstr "Odczytujê plik sprawdzania pisowni \"%s\""
+
+msgid "E757: This does not look like a spell file"
+msgstr "E757: To nie wygl±da na plik sprawdzania pisowni"
+
+msgid "E771: Old spell file, needs to be updated"
+msgstr "E771: Stary plik sprawdzania pisowni, wymagane uaktualnienie"
+
+msgid "E772: Spell file is for newer version of Vim"
+msgstr "E772: Plik sprawdzania pisowni dla nowszej wersji Vima"
+
+msgid "E770: Unsupported section in spell file"
+msgstr "E770: Niewspierana sekcja w pliku sprawdzania pisowni"
+
+#, c-format
+msgid "Warning: region %s not supported"
+msgstr "Ostrze¿enie: region %s nie jest wspierany"
+
+#, c-format
+msgid "Reading affix file %s..."
+msgstr "Czytam plik afiksów %s..."
+
+#, c-format
+msgid "Conversion failure for word in %s line %d: %s"
+msgstr "Konwersja nie powiod³a siê dla wyrazu w %s wierszu %d: %s"
+
+#, c-format
+msgid "Conversion in %s not supported: from %s to %s"
+msgstr "Konwersja w %s nie jest wspierana: od %s do %s"
+
+#, c-format
+msgid "Conversion in %s not supported"
+msgstr "Konwersja w %s nie jest wspierana"
+
+#, c-format
+msgid "Invalid value for FLAG in %s line %d: %s"
+msgstr "Nieprawid³owa warto¶æ FLAG w %s wierz %d: %s"
+
+#, c-format
+msgid "FLAG after using flags in %s line %d: %s"
+msgstr "FLAG po u¿yciu flag w %s wiersz %d: %s"
+
+#, c-format
+msgid ""
+"Defining COMPOUNDFORBIDFLAG after PFX item may give wrong results in %s line "
+"%d"
+msgstr ""
+"Definiowanie COMPOUNDFORBIDFLAG po PFX mo¿e skutkowaæ z³ym wynikiem w %s "
+"wiersz %d"
+
+#, c-format
+msgid ""
+"Defining COMPOUNDPERMITFLAG after PFX item may give wrong results in %s line "
+"%d"
+msgstr ""
+"Definiowanie COMPOUNDPERMITFLAG po PFX mo¿e skutkowaæ z³ym wynikiem w %s "
+"wiersz %d"
+
+#, c-format
+msgid "Wrong COMPOUNDRULES value in %s line %d: %s"
+msgstr "Z³a warto¶æ COMPOUNDRULES w %s wiersz %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDWORDMAX value in %s line %d: %s"
+msgstr "Z³a warto¶æ COMPOUNDWORDMAX w %s wiersz %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDMIN value in %s line %d: %s"
+msgstr "Z³a warto¶æ COMPOUNDMIM w %s wiersz %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDSYLMAX value in %s line %d: %s"
+msgstr "Z³a warto¶æ COMPOUNDSYLMAX w %s wiersz %d: %s"
+
+#, c-format
+msgid "Wrong CHECKCOMPOUNDPATTERN value in %s line %d: %s"
+msgstr "Z³a warto¶æ CHECKCOMPOUNDPATTERN w %s wiersz %d: %s"
+
+#, c-format
+msgid "Different combining flag in continued affix block in %s line %d: %s"
+msgstr "Ró¿ne flagi z³o¿eñ w kontynuowanym bloku afiksu w %s wiersz %d: %s"
+
+#, c-format
+msgid "Duplicate affix in %s line %d: %s"
+msgstr "Powtórzony afiks w %s wiersz %d: %s"
+
+#, c-format
+msgid ""
+"Affix also used for BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST in %s "
+"line %d: %s"
+msgstr ""
+"Afiks u¿yty tak¿e dla BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST w "
+"%s wiersz %d: %s"
+
+#, c-format
+msgid "Expected Y or N in %s line %d: %s"
+msgstr "Oczekiwano Y lub N w %s wierszu %d: %s"
+
+#, c-format
+msgid "Broken condition in %s line %d: %s"
+msgstr "B³êdny warunek w %s wiersz %d: %s"
+
+#, c-format
+msgid "Expected REP(SAL) count in %s line %d"
+msgstr "Oczekiwano ilo¶ci REP(SAL) w %s wierszu %d"
+
+#, c-format
+msgid "Expected MAP count in %s line %d"
+msgstr "Oczekiwano ilo¶ci MAP w %s wierszu %d"
+
+#, c-format
+msgid "Duplicate character in MAP in %s line %d"
+msgstr "Powtórzony znak w MAP w %s wierszu %d"
+
+#, c-format
+msgid "Unrecognized or duplicate item in %s line %d: %s"
+msgstr "Nieznany lub powtórzony element w %s wierszu %d: %s"
+
+#, c-format
+msgid "Missing FOL/LOW/UPP line in %s"
+msgstr "Brak wiersza FOL/LOW/UPP w %s"
+
+msgid "COMPOUNDSYLMAX used without SYLLABLE"
+msgstr "COMPOUNDSYLMAX u¿yty bez SYLLABLE"
+
+msgid "Too many postponed prefixes"
+msgstr "Zbyt wiele opó¼nionych prefiksów"
+
+msgid "Too many compound flags"
+msgstr "Zbyt wiele flag z³o¿eñ"
+
+msgid "Too many postponed prefixes and/or compound flags"
+msgstr "Zbyt wiele opó¼nionych prefiksów i/lub flag z³o¿eñ"
+
+#, c-format
+msgid "Missing SOFO%s line in %s"
+msgstr "Brak wiersza SOFO%s wiersz w %s"
+
+#, c-format
+msgid "Both SAL and SOFO lines in %s"
+msgstr "Wiersze SAL i SOFO w %s"
+
+#, c-format
+msgid "Flag is not a number in %s line %d: %s"
+msgstr "Flaga nie jest liczb± w %s wiersz %d: %s"
+
+#, c-format
+msgid "Illegal flag in %s line %d: %s"
+msgstr "Nieprawid³owa flaga w %s wiersz %d: %s"
+
+#, c-format
+msgid "%s value differs from what is used in another .aff file"
+msgstr "Warto¶æ %s ró¿ni siê od tej u¿ytej w innym pliku .aff"
+
+#, c-format
+msgid "Reading dictionary file %s..."
+msgstr "Czytam plik s³ownika %s..."
+
+#, c-format
+msgid "E760: No word count in %s"
+msgstr "E760: Brak ilo¶ci s³ów w %s"
+
+#, c-format
+msgid "line %6d, word %6d - %s"
+msgstr "wiersz %6d, s³owo %6d - %s"
+
+# c-format
+#, c-format
+msgid "Duplicate word in %s line %d: %s"
+msgstr "Powtórzony wyraz w %s wierszu %d: %s"
+
+# c-format
+#, c-format
+msgid "First duplicate word in %s line %d: %s"
+msgstr "Pierwszy powtórzony wyraz w %s wiersz %d: %s"
+
+# c-format
+#, c-format
+msgid "%d duplicate word(s) in %s"
+msgstr "%d powtórzony(ch) wyraz(ów) w %s"
+
+#, c-format
+msgid "Ignored %d word(s) with non-ASCII characters in %s"
+msgstr "Zignorowa³em %d s³ów ze znakami nie ASCII w %s"
+
+#, c-format
+msgid "Reading word file %s..."
+msgstr "Odczytujê plik wyrazów %s..."
+
+#, c-format
+msgid "Duplicate /encoding= line ignored in %s line %d: %s"
+msgstr "Zignorowano powtórzony wiersz /encoding= w %s wierszu %d: %s"
+
+#, c-format
+msgid "/encoding= line after word ignored in %s line %d: %s"
+msgstr "Zignorowano wiersz /encoding= po wyrazie w %s wierszu %d: %s"
+
+#, c-format
+msgid "Duplicate /regions= line ignored in %s line %d: %s"
+msgstr "Powtórzony wiersz /regions= zignorowano w %s wierszu %d: %s"
+
+#, c-format
+msgid "Too many regions in %s line %d: %s"
+msgstr "Za du¿o regionów w %s wiersz %d: %s"
+
+#, c-format
+msgid "/ line ignored in %s line %d: %s"
+msgstr "wiersz / zignorowano w %s wierszu %d: %s"
+
+#, c-format
+msgid "Invalid region nr in %s line %d: %s"
+msgstr "Nieprawid³owy numer regionu w %s wierszu %d: %s"
+
+#, c-format
+msgid "Unrecognized flags in %s line %d: %s"
+msgstr "Nieznane flagi w %s wiersz %d: %s"
+
+#, c-format
+msgid "Ignored %d words with non-ASCII characters"
+msgstr "Zignorowa³em %d s³ów ze znakami nie ASCII"
+
+msgid "E845: Insufficient memory, word list will be incomplete"
+msgstr "E845: Nie wystarczaj±ca ilo¶æ pamiêci, lista s³ów bêdzie niekompletna"
+
+#, c-format
+msgid "Compressed %d of %d nodes; %d (%d%%) remaining"
+msgstr "Skompresowano %d z %d wêz³ów; pozostaje %d (%d%%)"
+
+msgid "Reading back spell file..."
+msgstr "Odczytujê plik sprawdzania pisowni..."
+
+#.
+#. * Go through the trie of good words, soundfold each word and add it to
+#. * the soundfold trie.
+#.
+msgid "Performing soundfolding..."
+msgstr "Wykonujê kompresjê d¼wiêkow±..."
+
+#, c-format
+msgid "Number of words after soundfolding: %ld"
+msgstr "Liczba s³ów po kompresji d¼wiêkowej: %ld"
+
+#, c-format
+msgid "Total number of words: %d"
+msgstr "Ca³kowita liczba s³ów: %d"
+
+#, c-format
+msgid "Writing suggestion file %s..."
+msgstr "Zapisujê plik sugestii %s..."
+
+#, c-format
+msgid "Estimated runtime memory use: %d bytes"
+msgstr "Oczekiwane zu¿ycie pamiêci: %d bajtów"
+
+msgid "E751: Output file name must not have region name"
+msgstr "E751: Nazwa pliku wynikowego nie mo¿e byæ nazw± regionu"
+
+msgid "E754: Only up to 8 regions supported"
+msgstr "E754: Wspieram tylko 8 regionów"
+
+#, c-format
+msgid "E755: Invalid region in %s"
+msgstr "E755: Nieprawid³owy region w %s"
+
+msgid "Warning: both compounding and NOBREAK specified"
+msgstr "Ostrze¿enie: okre¶lono zarówno z³o¿enia jak i NOBREAK"
+
+#, c-format
+msgid "Writing spell file %s..."
+msgstr "Zapisujê plik sprawdzania pisowni %s..."
+
+msgid "Done!"
+msgstr "Zrobione!"
+
+#, c-format
+msgid "E765: 'spellfile' does not have %ld entries"
+msgstr "E765: 'spellfile' nie posiada wpisów %ld"
+
+#, c-format
+msgid "Word removed from %s"
+msgstr "Usuniêto s³owo z %s"
+
+#, c-format
+msgid "Word added to %s"
+msgstr "Dodano s³owo do %s"
+
+msgid "E763: Word characters differ between spell files"
+msgstr "E763: Znaki wyrazów ró¿ni± siê miêdzy plikami sprawdzania pisowni"
+
+msgid "Sorry, no suggestions"
+msgstr "Przykro mi, brak podpowiedzi"
+
+#, c-format
+msgid "Sorry, only %ld suggestions"
+msgstr "Przykro mi, tylko %ld podpowiedzi"
+
+#. for when 'cmdheight' > 1
+#. avoid more prompt
+#, c-format
+msgid "Change \"%.*s\" to:"
+msgstr "Zmieñ \"%.*s\" na:"
+
+#, c-format
+msgid " < \"%.*s\""
+msgstr " < \"%.*s\""
+
+msgid "E752: No previous spell replacement"
+msgstr "E752: Brak poprzednich podmian sprawdzania pisowni"
+
+#, c-format
+msgid "E753: Not found: %s"
+msgstr "E753: Nie znaleziono: %s"
+
+#, c-format
+msgid "E778: This does not look like a .sug file: %s"
+msgstr "E778: Ten plik nie wygl±da na plik .sug: %s"
+
+#, c-format
+msgid "E779: Old .sug file, needs to be updated: %s"
+msgstr "E779: Stary plik .sug, konieczne jest uaktualnienie: %s"
+
+#, c-format
+msgid "E780: .sug file is for newer version of Vim: %s"
+msgstr "E780: Plik .sug dla nowszej wersji Vima: %s"
+
+#, c-format
+msgid "E781: .sug file doesn't match .spl file: %s"
+msgstr "E781: Plik .sug nie pasuje do pliku .spl: %s"
+
+#, c-format
+msgid "E782: error while reading .sug file: %s"
+msgstr "E782: B³±d w czasie odczytu pliku .sug: %s"
+
+#. This should have been checked when generating the .spl
+#. * file.
+msgid "E783: duplicate char in MAP entry"
+msgstr "E783: Podwojony znak we wpisie MAP"
+
+msgid "No Syntax items defined for this buffer"
+msgstr "Brak elementów sk³adni okre¶lonych dla tego bufora"
+
+#, c-format
+msgid "E390: Illegal argument: %s"
+msgstr "E390: Niedozwolony argument: %s"
+
+#, c-format
+msgid "E391: No such syntax cluster: %s"
+msgstr "E391: Nie ma takiego klastra sk³adni: %s"
+
+msgid "syncing on C-style comments"
+msgstr "synchronizacja komentarzy w stylu C"
+
+msgid "no syncing"
+msgstr "brak synchronizacji"
+
+msgid "syncing starts "
+msgstr "pocz±tek synchronizacji"
+
+msgid " lines before top line"
+msgstr " wierszy przed górn± lini±"
+
+msgid ""
+"\n"
+"--- Syntax sync items ---"
+msgstr ""
+"\n"
+"--- Elementy synchronizacji sk³adni ---"
+
+msgid ""
+"\n"
+"syncing on items"
+msgstr ""
+"\n"
+"synchronizujê na elementach"
+
+msgid ""
+"\n"
+"--- Syntax items ---"
+msgstr ""
+"\n"
+"--- Elementy sk³adni ---"
+
+#, c-format
+msgid "E392: No such syntax cluster: %s"
+msgstr "E392: Nie ma takiego klastra sk³adni: %s"
+
+msgid "minimal "
+msgstr "minimalnie "
+
+msgid "maximal "
+msgstr "maksymalnie "
+
+msgid "; match "
+msgstr "; pasuje "
+
+msgid " line breaks"
+msgstr "znaków nowego wiersza"
+
+msgid "E395: contains argument not accepted here"
+msgstr "E395: argument contains niedozwolony w tym miejscu"
+
+msgid "E844: invalid cchar value"
+msgstr "E844: Niew³a¶ciwa warto¶æ cchar"
+
+msgid "E393: group[t]here not accepted here"
+msgstr "E393: group[t]here niedozwolone w tym miejscu"
+
+#, c-format
+msgid "E394: Didn't find region item for %s"
+msgstr "E394: Nie znalaz³em elementów regionu dla %s"
+
+msgid "E397: Filename required"
+msgstr "E397: Wymagana nazwa pliku"
+
+msgid "E847: Too many syntax includes"
+msgstr "E847: Za du¿o w³±czonych sk³adni"
+
+#, c-format
+msgid "E789: Missing ']': %s"
+msgstr "E789: Brak ']': %s"
+
+#, c-format
+msgid "E398: Missing '=': %s"
+msgstr "E398: Brak '=': %s"
+
+#, c-format
+msgid "E399: Not enough arguments: syntax region %s"
+msgstr "E399: Za ma³o argumentów: syntax region %s"
+
+msgid "E848: Too many syntax clusters"
+msgstr "E848: Za du¿o klastrów sk³adni"
+
+msgid "E400: No cluster specified"
+msgstr "E400: Brak specyfikacji klastra"
+
+#, c-format
+msgid "E401: Pattern delimiter not found: %s"
+msgstr "E401: Brak ogranicznika wzorca: %s"
+
+#, c-format
+msgid "E402: Garbage after pattern: %s"
+msgstr "E402: ¦mieci po wzorcu: %s"
+
+msgid "E403: syntax sync: line continuations pattern specified twice"
+msgstr "E403: syntax sync: wielokrotnie podane wzorce kontynuacji wiersza"
+
+#, c-format
+msgid "E404: Illegal arguments: %s"
+msgstr "E404: Niedozwolone argumenty: %s"
+
+#, c-format
+msgid "E405: Missing equal sign: %s"
+msgstr "E405: Brak znaku równo¶ci: %s"
+
+#, c-format
+msgid "E406: Empty argument: %s"
+msgstr "E406: Pusty argument: %s"
+
+#, c-format
+msgid "E407: %s not allowed here"
+msgstr "E407: %s jest niedozwolone w tym miejscu"
+
+#, c-format
+msgid "E408: %s must be first in contains list"
+msgstr "E408: %s musi byæ pierwsze w li¶cie contains"
+
+#, c-format
+msgid "E409: Unknown group name: %s"
+msgstr "E409: Nieznana nazwa grupy: %s"
+
+#, c-format
+msgid "E410: Invalid :syntax subcommand: %s"
+msgstr "E410: Niew³a¶ciwa podkomenda :syntax : %s"
+
+msgid ""
+" TOTAL COUNT MATCH SLOWEST AVERAGE NAME PATTERN"
+msgstr ""
+" WSZYTKO ILO¦Æ PASUJE NAJWOLN. ¦REDNIO NAZWA WZORZEC"
+
+msgid "E679: recursive loop loading syncolor.vim"
+msgstr "E679: rekursywna pêtla wczytuj±ca syncolor.vim"
+
+#, c-format
+msgid "E411: highlight group not found: %s"
+msgstr "E411: nie znaleziono grupy pod¶wietlania: %s"
+
+#, c-format
+msgid "E412: Not enough arguments: \":highlight link %s\""
+msgstr "E412: Zbyt ma³o argumentów: \":highlight link %s\""
+
+#, c-format
+msgid "E413: Too many arguments: \":highlight link %s\""
+msgstr "E413: Zbyt wiele argumentów: \":highlight link %s\""
+
+msgid "E414: group has settings, highlight link ignored"
+msgstr "E414: grupa ma ustawienia; zignorowane pod³±czenie pod¶wietlania"
+
+#, c-format
+msgid "E415: unexpected equal sign: %s"
+msgstr "E415: nieoczekiwany znak równo¶ci: %s"
+
+#, c-format
+msgid "E416: missing equal sign: %s"
+msgstr "E416: brak znaku równo¶ci: %s"
+
+#, c-format
+msgid "E417: missing argument: %s"
+msgstr "E417: brak argumentu: %s"
+
+#, c-format
+msgid "E418: Illegal value: %s"
+msgstr "E418: Niedozwolona warto¶æ: %s"
+
+msgid "E419: FG color unknown"
+msgstr "E419: Kolor FG nieznany"
+
+msgid "E420: BG color unknown"
+msgstr "E420: Kolor BG nieznany"
+
+#, c-format
+msgid "E421: Color name or number not recognized: %s"
+msgstr "E421: Nazwa lub liczba koloru nierozpoznana: %s"
+
+#, c-format
+msgid "E422: terminal code too long: %s"
+msgstr "E422: za d³ugi kod terminala: %s"
+
+#, c-format
+msgid "E423: Illegal argument: %s"
+msgstr "E423: Niedozwolony argument: %s"
+
+msgid "E424: Too many different highlighting attributes in use"
+msgstr "E424: Zbyt wiele ró¿nych atrybutów podkre¶lania w u¿yciu"
+
+msgid "E669: Unprintable character in group name"
+msgstr "E669: Niedrukowalny znak w nazwie grupy"
+
+msgid "W18: Invalid character in group name"
+msgstr "W18: nieprawid³owy znak w nazwie grupy"
+
+msgid "E849: Too many highlight and syntax groups"
+msgstr "E849: Za du¿o grup pod¶wietlania i sk³adni"
+
+msgid "E555: at bottom of tag stack"
+msgstr "E555: na dole stosu znaczników"
+
+msgid "E556: at top of tag stack"
+msgstr "E556: na górze stosu znaczników"
+
+msgid "E425: Cannot go before first matching tag"
+msgstr "E425: Nie mo¿na przej¶æ przed pierwszy pasuj±cy znacznik"
+
+#, c-format
+msgid "E426: tag not found: %s"
+msgstr "E426: nie znaleziono znacznika: %s"
+
+msgid " # pri kind tag"
+msgstr " # pri rodzaj znacznik"
+
+msgid "file\n"
+msgstr "plik\n"
+
+msgid "E427: There is only one matching tag"
+msgstr "E427: Pasuje tylko jeden znacznik"
+
+msgid "E428: Cannot go beyond last matching tag"
+msgstr "E428: Nie mo¿na przej¶æ za ostatni pasuj±cy znacznik"
+
+#, c-format
+msgid "File \"%s\" does not exist"
+msgstr "Plik \"%s\" nie istnieje"
+
+#. Give an indication of the number of matching tags
+#, c-format
+msgid "tag %d of %d%s"
+msgstr "znacznik %d z %d%s"
+
+msgid " or more"
+msgstr " lub wiêcej"
+
+msgid " Using tag with different case!"
+msgstr " U¿ywam znacznika o odmiennej wielko¶ci liter!"
+
+#, c-format
+msgid "E429: File \"%s\" does not exist"
+msgstr "E429: Plik \"%s\" nie istnieje"
+
+#. Highlight title
+msgid ""
+"\n"
+" # TO tag FROM line in file/text"
+msgstr ""
+"\n"
+" # DO znacznik OD wiersza w pliku/tek¶cie"
+
+#, c-format
+msgid "Searching tags file %s"
+msgstr "Szukam w pliku znaczników %s"
+
+#, c-format
+msgid "E430: Tag file path truncated for %s\n"
+msgstr "E430: Trop szukania pliku znaczników obciêty dla %s\n"
+
+msgid "Ignoring long line in tags file"
+msgstr "Ignorujê d³ugie wiersze w pliku znaczników"
+
+#, c-format
+msgid "E431: Format error in tags file \"%s\""
+msgstr "E431: B³±d formatu w pliku znaczników \"%s\""
+
+#, c-format
+msgid "Before byte %ld"
+msgstr "Przed bajtem %ld"
+
+#, c-format
+msgid "E432: Tags file not sorted: %s"
+msgstr "E432: Plik znaczników nieuporz±dkowany: %s"
+
+#. never opened any tags file
+msgid "E433: No tags file"
+msgstr "E433: Brak pliku znaczników"
+
+msgid "E434: Can't find tag pattern"
+msgstr "E434: Nie mogê znale¼æ wzorca znacznika"
+
+msgid "E435: Couldn't find tag, just guessing!"
+msgstr "E435: Nie znalaz³em znacznika - tylko zgadujê!"
+
+#, c-format
+msgid "Duplicate field name: %s"
+msgstr "Powtórzona nazwa pola: %s"
+
+msgid "' not known. Available builtin terminals are:"
+msgstr "' nieznany. Mo¿liwe typy wbudowanych terminali:"
+
+msgid "defaulting to '"
+msgstr "domy¶lnie jest '"
+
+msgid "E557: Cannot open termcap file"
+msgstr "E557: Nie mogê otworzyæ pliku termcap"
+
+msgid "E558: Terminal entry not found in terminfo"
+msgstr "E558: Nie ma opisu takiego terminala w terminfo"
+
+msgid "E559: Terminal entry not found in termcap"
+msgstr "E559: Nie ma opisu takiego terminala w termcap"
+
+#, c-format
+msgid "E436: No \"%s\" entry in termcap"
+msgstr "E436: Brak opisu \"%s\" w termcap"
+
+msgid "E437: terminal capability \"cm\" required"
+msgstr "E437: wymagana zdolno¶æ \"cm\" terminala"
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Terminal keys ---"
+msgstr ""
+"\n"
+"--- Klawisze terminala ---"
+
+msgid "new shell started\n"
+msgstr "uruchomiono now± pow³okê\n"
+
+msgid "Vim: Error reading input, exiting...\n"
+msgstr "Vim: B³±d podczas wczytywania wej¶cia, koñczê...\n"
+
+msgid "Used CUT_BUFFER0 instead of empty selection"
+msgstr "U¿ywam CUT_BUFFER0 zamiast pustego wyboru"
+
+#. This happens when the FileChangedRO autocommand changes the
+#. * file in a way it becomes shorter.
+msgid "E834: Line count changed unexpectedly"
+msgstr "E834: Niespodziewana zmiana ilo¶ci linii"
+
+#. must display the prompt
+msgid "No undo possible; continue anyway"
+msgstr "Cofniêcie niemo¿liwe; mimo to kontynuujê"
+
+#, c-format
+msgid "E828: Cannot open undo file for writing: %s"
+msgstr "E828: Nie mogê otworzyæ do zapisu pliku undo: %s"
+
+#, c-format
+msgid "E825: Corrupted undo file (%s): %s"
+msgstr "E825: Uszkodzony plik undo (%s): %s"
+
+msgid "Cannot write undo file in any directory in 'undodir'"
+msgstr "Nie mo¿na zapisaæ pliku undo w ¿adnym katalogu z 'undodir'"
+
+#, c-format
+msgid "Will not overwrite with undo file, cannot read: %s"
+msgstr "Nie nadpiszê plikiem undo, nie mogê odczytaæ: %s"
+
+#, c-format
+msgid "Will not overwrite, this is not an undo file: %s"
+msgstr "Nie nadpiszê, to nie jest plik undo: %s"
+
+msgid "Skipping undo file write, nothing to undo"
+msgstr "Pomijam zapis pliku undo, nic do cofniêcia"
+
+#, c-format
+msgid "Writing undo file: %s"
+msgstr "Zapisujê plik undo: %s"
+
+#, c-format
+msgid "E829: write error in undo file: %s"
+msgstr "E829: B³±d zapisu w pliku undo: %s"
+
+#, c-format
+msgid "Not reading undo file, owner differs: %s"
+msgstr "Nie wczytujê pliku undo, inny w³a¶ciciel: %s"
+
+#, c-format
+msgid "Reading undo file: %s"
+msgstr "Wczytujê plik undo: %s"
+
+#, c-format
+msgid "E822: Cannot open undo file for reading: %s"
+msgstr "E822: Nie mogê otworzyæ pliku undo do odczytu: %s"
+
+#, c-format
+msgid "E823: Not an undo file: %s"
+msgstr "E823: To nie jest plik undo: %s"
+
+#, c-format
+msgid "E832: Non-encrypted file has encrypted undo file: %s"
+msgstr "E832: Nie zaszyfrowany plik ma zaszyfrowany plik undo: %s"
+
+#, c-format
+msgid "E826: Undo file decryption failed: %s"
+msgstr "E826: Nie powiod³o siê odszyfrowywanie pliku undo: %s"
+
+#, c-format
+msgid "E827: Undo file is encrypted: %s"
+msgstr "E827: Plik undo jest zaszyfrowany: %s"
+
+#, c-format
+msgid "E824: Incompatible undo file: %s"
+msgstr "E824: Niekompatybilny plik undo: %s"
+
+msgid "File contents changed, cannot use undo info"
+msgstr "Zawarto¶æ pliku siê zmieni³a, nie mogê u¿yæ pliku undo"
+
+#, c-format
+msgid "Finished reading undo file %s"
+msgstr "Skoñczono wczytywanie pliku undo %s"
+
+msgid "Already at oldest change"
+msgstr "Ju¿ w miejscu ostatniej zmiany"
+
+msgid "Already at newest change"
+msgstr "Ju¿ w miejscu najnowszej zmiany"
+
+#, c-format
+msgid "E830: Undo number %ld not found"
+msgstr "E830: Nie znaleziono numeru cofniêcia %ld"
+
+msgid "E438: u_undo: line numbers wrong"
+msgstr "E438: u_undo: niew³a¶ciwe numery wierszy"
+
+msgid "more line"
+msgstr "1 wiersz wiêcej"
+
+msgid "more lines"
+msgstr "wiêcej wierszy"
+
+msgid "line less"
+msgstr "1 wiersz mniej"
+
+msgid "fewer lines"
+msgstr "mniej wierszy"
+
+msgid "change"
+msgstr "1 zmiana"
+
+msgid "changes"
+msgstr "zmiany"
+
+#, c-format
+msgid "%ld %s; %s #%ld %s"
+msgstr "%ld %s; %s #%ld %s"
+
+msgid "before"
+msgstr "przed"
+
+msgid "after"
+msgstr "za"
+
+msgid "Nothing to undo"
+msgstr "Nie ma zmian do cofniêcia"
+
+msgid "number changes when saved"
+msgstr "liczba zmiany kiedy zapisano"
+
+#, c-format
+msgid "%ld seconds ago"
+msgstr "%ld sekund temu"
+
+msgid "E790: undojoin is not allowed after undo"
+msgstr "E790: undojoin nie jest dozwolone po undo"
+
+msgid "E439: undo list corrupt"
+msgstr "E439: uszkodzona lista cofania"
+
+msgid "E440: undo line missing"
+msgstr "E440: brak wiersza cofania"
+
+#. Only MS VC 4.1 and earlier can do Win32s
+msgid ""
+"\n"
+"MS-Windows 16/32-bit GUI version"
+msgstr ""
+"\n"
+"16/32-bit wersja GUI dla MS-Windows"
+
+msgid ""
+"\n"
+"MS-Windows 64-bit GUI version"
+msgstr ""
+"\n"
+"64 bitowa wersja GUI dla MS-Windows"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit GUI version"
+msgstr ""
+"\n"
+"32 bitowa wersja GUI dla MS-Windows"
+
+msgid " in Win32s mode"
+msgstr " w trybie Win32s"
+
+msgid " with OLE support"
+msgstr " ze wspomaganiem OLE"
+
+msgid ""
+"\n"
+"MS-Windows 64-bit console version"
+msgstr ""
+"\n"
+"32 bitowa wersja na konsolê dla MS-Windows"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit console version"
+msgstr ""
+"\n"
+"32 bitowa wersja na konsolê dla MS-Windows"
+
+msgid ""
+"\n"
+"MS-Windows 16-bit version"
+msgstr ""
+"\n"
+"16 bitowa wersja dla MS-Windows"
+
+msgid ""
+"\n"
+"32-bit MS-DOS version"
+msgstr ""
+"\n"
+"32 bitowa wersja dla MS-DOS"
+
+msgid ""
+"\n"
+"16-bit MS-DOS version"
+msgstr ""
+"\n"
+"16 bitowa wersja dla MS-DOS"
+
+msgid ""
+"\n"
+"MacOS X (unix) version"
+msgstr ""
+"\n"
+"wersja dla MacOS X (unix)"
+
+msgid ""
+"\n"
+"MacOS X version"
+msgstr ""
+"\n"
+"wersja dla MacOS X"
+
+msgid ""
+"\n"
+"MacOS version"
+msgstr ""
+"\n"
+"wersja dla MacOS"
+
+msgid ""
+"\n"
+"OpenVMS version"
+msgstr ""
+"\n"
+"wersja dla OpenVMS"
+
+msgid ""
+"\n"
+"Included patches: "
+msgstr ""
+"\n"
+"Zadane ³aty: "
+
+msgid ""
+"\n"
+"Extra patches: "
+msgstr ""
+"\n"
+"Ekstra ³aty: "
+
+msgid "Modified by "
+msgstr "Zmieniony przez "
+
+msgid ""
+"\n"
+"Compiled "
+msgstr ""
+"\n"
+"Skompilowany "
+
+msgid "by "
+msgstr "przez "
+
+msgid ""
+"\n"
+"Huge version "
+msgstr ""
+"\n"
+"Olbrzymia wersja "
+
+msgid ""
+"\n"
+"Big version "
+msgstr ""
+"\n"
+"Du¿a wersja "
+
+msgid ""
+"\n"
+"Normal version "
+msgstr ""
+"\n"
+"Normalna wersja "
+
+msgid ""
+"\n"
+"Small version "
+msgstr ""
+"\n"
+"Ma³a wersja "
+
+msgid ""
+"\n"
+"Tiny version "
+msgstr ""
+"\n"
+"Malutka wersja "
+
+msgid "without GUI."
+msgstr "bez GUI."
+
+msgid "with GTK2-GNOME GUI."
+msgstr "z GTK2-GNOME GUI."
+
+msgid "with GTK2 GUI."
+msgstr "z GTK2 GUI."
+
+msgid "with X11-Motif GUI."
+msgstr "z X11-Motif GUI."
+
+msgid "with X11-neXtaw GUI."
+msgstr "z X11-neXtaw GUI."
+
+msgid "with X11-Athena GUI."
+msgstr "z X11-Athena GUI."
+
+msgid "with Photon GUI."
+msgstr "z Photon GUI."
+
+msgid "with GUI."
+msgstr "z GUI."
+
+msgid "with Carbon GUI."
+msgstr "z Carbon GUI."
+
+msgid "with Cocoa GUI."
+msgstr "z Cocoa GUI."
+
+msgid "with (classic) GUI."
+msgstr "z (klasycznym) GUI."
+
+msgid " Features included (+) or not (-):\n"
+msgstr " Opcje w³±czone (+) lub nie (-):\n"
+
+msgid " system vimrc file: \""
+msgstr " vimrc systemu: \""
+
+msgid " user vimrc file: \""
+msgstr " vimrc u¿ytkownika: \""
+
+msgid " 2nd user vimrc file: \""
+msgstr " 2-gi plik vimrc u¿ytkownika: \""
+
+msgid " 3rd user vimrc file: \""
+msgstr " 3-ci plik vimrc u¿ytkownika: \""
+
+msgid " user exrc file: \""
+msgstr " exrc u¿ytkownika: \""
+
+msgid " 2nd user exrc file: \""
+msgstr " 2-gi plik exrc u¿ytkownika: \""
+
+msgid " system gvimrc file: \""
+msgstr " gvimrc systemu: \""
+
+msgid " user gvimrc file: \""
+msgstr " gvimrc u¿ytkownika: \""
+
+msgid "2nd user gvimrc file: \""
+msgstr "2-gi plik gvimrc u¿ytkownika: \""
+
+msgid "3rd user gvimrc file: \""
+msgstr "3-ci plik gvimrc u¿ytkownika: \""
+
+msgid " system menu file: \""
+msgstr " systemowy plik menu: \""
+
+msgid " fall-back for $VIM: \""
+msgstr " odwet dla $VIM-a: \""
+
+msgid " f-b for $VIMRUNTIME: \""
+msgstr "f-b dla $VIMRUNTIME: \""
+
+msgid "Compilation: "
+msgstr "Kompilacja: "
+
+msgid "Compiler: "
+msgstr "Kompilator: "
+
+msgid "Linking: "
+msgstr "Konsolidacja: "
+
+msgid " DEBUG BUILD"
+msgstr " KOMPILACJA DEBUG"
+
+msgid "VIM - Vi IMproved"
+msgstr "VIM - Vi rozbudowany"
+
+msgid "version "
+msgstr "wersja "
+
+msgid "by Bram Moolenaar et al."
+msgstr "Autor: Bram Moolenaar i Inni."
+
+msgid "Vim is open source and freely distributable"
+msgstr "Vim jest open source i rozprowadzany darmowo"
+
+msgid "Help poor children in Uganda!"
+msgstr "Pomó¿ biednym dzieciom w Ugandzie!"
+
+msgid "type :help iccf<Enter> for information "
+msgstr "wprowad¼ :help iccf<Enter> dla informacji o tym "
+
+msgid "type :q<Enter> to exit "
+msgstr "wprowad¼ :q<Enter> zakoñczenie programu "
+
+msgid "type :help<Enter> or <F1> for on-line help"
+msgstr "wprowad¼ :help<Enter> lub <F1> pomoc na bie¿±co "
+
+msgid "type :help version8<Enter> for version info"
+msgstr "wprowad¼ :help version8<Enter> dla informacji o wersji"
+
+msgid "Running in Vi compatible mode"
+msgstr "Dzia³am w trybie zgodno¶ci z Vi"
+
+msgid "type :set nocp<Enter> for Vim defaults"
+msgstr "wprowad¼ :set nocp<Enter> warto¶ci domy¶lne Vim-a"
+
+msgid "type :help cp-default<Enter> for info on this"
+msgstr "wprowad¼ :help cp-default<Enter> dla informacji to tym "
+
+msgid "menu Help->Orphans for information "
+msgstr "menu Pomoc->Sieroty dla informacji to tym "
+
+msgid "Running modeless, typed text is inserted"
+msgstr "Uruchomiony bez trybów, wpisany tekst jest wprowadzany"
+
+msgid "menu Edit->Global Settings->Toggle Insert Mode "
+msgstr "menu Edytuj->Ustawienia globalne->Tryb wstawiania"
+
+msgid " for two modes "
+msgstr " dla dwóch trybów "
+
+msgid "menu Edit->Global Settings->Toggle Vi Compatible"
+msgstr "menu Edytuj->Ustawienia globalne->Kompatybilno¶æ z Vi"
+
+msgid " for Vim defaults "
+msgstr " dla domy¶lnych ustawieñ Vima "
+
+msgid "Sponsor Vim development!"
+msgstr "Sponsoruj rozwój Vima!"
+
+msgid "Become a registered Vim user!"
+msgstr "Zostañ zarejestrowanym u¿ytkownikiem Vima!"
+
+msgid "type :help sponsor<Enter> for information "
+msgstr "wprowad¼ :help sponsor<Enter> dla informacji"
+
+msgid "type :help register<Enter> for information "
+msgstr "wprowad¼ :help register<Enter> dla informacji"
+
+msgid "menu Help->Sponsor/Register for information "
+msgstr "menu Pomoc->Sponsoruj/Zarejestruj siê dla informacji"
+
+msgid "WARNING: Windows 95/98/ME detected"
+msgstr "OSTRZE¯ENIE: wykryto Windows 95/98/ME"
+
+msgid "type :help windows95<Enter> for info on this"
+msgstr "wprowad¼ :help windows95<Enter> dla informacji to tym "
+
+msgid "Already only one window"
+msgstr "Ju¿ jest tylko jeden widok"
+
+msgid "E441: There is no preview window"
+msgstr "E441: Nie ma okna podgl±du"
+
+msgid "E442: Can't split topleft and botright at the same time"
+msgstr "E442: Nie mogê rozdzieliæ lewo-górnego i prawo-dolnego jednocze¶nie"
+
+msgid "E443: Cannot rotate when another window is split"
+msgstr "E443: Nie mogê przekrêciæ, gdy inne okno jest rozdzielone"
+
+msgid "E444: Cannot close last window"
+msgstr "E444: Nie mogê zamkn±æ ostatniego okna"
+
+msgid "E813: Cannot close autocmd window"
+msgstr "E813: Nie mo¿na zamkn±æ okna autocmd"
+
+msgid "E814: Cannot close window, only autocmd window would remain"
+msgstr "E814: Nie mo¿na zamkn±æ okna, zosta³oby tylko okno autocmd"
+
+msgid "E445: Other window contains changes"
+msgstr "E445: Inne okno zawiera zmiany"
+
+msgid "E446: No file name under cursor"
+msgstr "E446: Brak nazwy pliku pod kursorem"
+
+#, c-format
+msgid "E447: Can't find file \"%s\" in path"
+msgstr "E447: Nie mogê znale¼æ pliku \"%s\" w tropie"
+
+#, c-format
+msgid "E370: Could not load library %s"
+msgstr "E370: Nie mog³em za³adowaæ biblioteki %s"
+
+msgid "Sorry, this command is disabled: the Perl library could not be loaded."
+msgstr ""
+"Przykro mi, ta komenda jest wy³±czona: nie mog³em za³adowaæ biblioteki Perla."
+
+msgid "E299: Perl evaluation forbidden in sandbox without the Safe module"
+msgstr "E299: wyliczenie Perla zabronione w piaskownicy bez modu³u Safe"
+
+msgid "Edit with &multiple Vims"
+msgstr "Edytuj w &wielu Vimach"
+
+msgid "Edit with single &Vim"
+msgstr "Edytuj w pojedynczym &Vimie"
+
+msgid "Diff with Vim"
+msgstr "Diff z Vimem"
+
+msgid "Edit with &Vim"
+msgstr "Edytuj w &Vimie"
+
+#. Now concatenate
+msgid "Edit with existing Vim - "
+msgstr "Edytuj z istniej±cym Vimem - "
+
+msgid "Edits the selected file(s) with Vim"
+msgstr "Edytuj wybrane pliki w Vimie"
+
+msgid "Error creating process: Check if gvim is in your path!"
+msgstr "B³±d tworzenia procesu: Sprawd¼ czy gvim jest w twojej ¶cie¿ce!"
+
+msgid "gvimext.dll error"
+msgstr "b³±d gvimext.dll"
+
+msgid "Path length too long!"
+msgstr "Za d³uga ¶cie¿ka!"
+
+msgid "--No lines in buffer--"
+msgstr "--Brak wierszy w buforze--"
+
+#.
+#. * The error messages that can be shared are included here.
+#. * Excluded are errors that are only used once and debugging messages.
+#.
+msgid "E470: Command aborted"
+msgstr "E470: Przerwanie komendy"
+
+msgid "E471: Argument required"
+msgstr "E471: wymagany argument"
+
+msgid "E10: \\ should be followed by /, ? or &"
+msgstr "E10: po \\ powinno byæ /, ? lub &"
+
+msgid "E11: Invalid in command-line window; <CR> executes, CTRL-C quits"
+msgstr ""
+"E11: Niedozwolone w oknie wiersza poleceñ; <CR> wykonuje, CTRL-C opuszcza"
+
+msgid "E12: Command not allowed from exrc/vimrc in current dir or tag search"
+msgstr ""
+"E12: Komenda niedozwolona z exrc/vimrc w bie¿±cym szukaniu katalogu lub "
+"znacznika"
+
+msgid "E171: Missing :endif"
+msgstr "E171: Brak :endif"
+
+msgid "E600: Missing :endtry"
+msgstr "E600: Brak :endtry"
+
+msgid "E170: Missing :endwhile"
+msgstr "E170: Brak :endwhile"
+
+msgid "E170: Missing :endfor"
+msgstr "E170: Brak :endfor"
+
+msgid "E588: :endwhile without :while"
+msgstr "E588: :endwhile bez :while"
+
+msgid "E588: :endfor without :for"
+msgstr "E588: :endfor bez :for"
+
+msgid "E13: File exists (add ! to override)"
+msgstr "E13: Plik istnieje (wymu¶ poprzez !)"
+
+msgid "E472: Command failed"
+msgstr "E472: Komenda nie powiod³a siê"
+
+#, c-format
+msgid "E234: Unknown fontset: %s"
+msgstr "E234: Nieznany zestaw czcionek: %s"
+
+#, c-format
+msgid "E235: Unknown font: %s"
+msgstr "E235: Nieznana czcionka: %s"
+
+#, c-format
+msgid "E236: Font \"%s\" is not fixed-width"
+msgstr "E236: Czcionka \"%s\" nie ma sta³ej szeroko¶ci znaków"
+
+msgid "E473: Internal error"
+msgstr "E473: B³±d wewnêtrzny"
+
+msgid "Interrupted"
+msgstr "Przerwane"
+
+msgid "E14: Invalid address"
+msgstr "E14: Niew³a¶ciwy adres"
+
+msgid "E474: Invalid argument"
+msgstr "E474: Niew³a¶ciwy argument"
+
+#, c-format
+msgid "E475: Invalid argument: %s"
+msgstr "E475: Niew³a¶ciwy argument: %s"
+
+#, c-format
+msgid "E15: Invalid expression: %s"
+msgstr "E15: Niew³a¶ciwe wyra¿enie: %s"
+
+msgid "E16: Invalid range"
+msgstr "E16: Niew³a¶ciwy zakres"
+
+msgid "E476: Invalid command"
+msgstr "E476: Niew³a¶ciwa komenda"
+
+#, c-format
+msgid "E17: \"%s\" is a directory"
+msgstr "E17: \"%s\" jest katalogiem"
+
+#, c-format
+msgid "E364: Library call failed for \"%s()\""
+msgstr "E364: Wywo³anie z biblioteki nie powiod³o siê dla \"%s()\""
+
+#, c-format
+msgid "E448: Could not load library function %s"
+msgstr "E448: Nie mo¿na za³adowaæ funkcji biblioteki %s"
+
+msgid "E19: Mark has invalid line number"
+msgstr "E19: Zak³adka ma niew³a¶ciwy numer wiersza"
+
+msgid "E20: Mark not set"
+msgstr "E20: Zak³adka nienastawiona"
+
+msgid "E21: Cannot make changes, 'modifiable' is off"
+msgstr "E21: Nie mogê wykonaæ zmian, 'modifiable' jest wy³±czone"
+
+msgid "E22: Scripts nested too deep"
+msgstr "E22: Zbyt g³êbokie zagnie¿d¿enie skryptów"
+
+msgid "E23: No alternate file"
+msgstr "E23: Brak pliku zamiany"
+
+msgid "E24: No such abbreviation"
+msgstr "E24: Nie ma takiego skrótu"
+
+msgid "E477: No ! allowed"
+msgstr "E477: Niedozwolone !"
+
+msgid "E25: GUI cannot be used: Not enabled at compile time"
+msgstr "E25: GUI nie mo¿e byæ u¿yte: Nie w³±czono podczas kompilacji"
+
+msgid "E26: Hebrew cannot be used: Not enabled at compile time\n"
+msgstr "E26: Hebrajski nie mo¿e byæ u¿yty: Nie w³±czono podczas kompilacji\n"
+
+msgid "E27: Farsi cannot be used: Not enabled at compile time\n"
+msgstr "E27: Farsi nie mo¿e byæ u¿yty: Nie w³±czono podczas kompilacji\n"
+
+msgid "E800: Arabic cannot be used: Not enabled at compile time\n"
+msgstr "E800: Arabski nie mo¿e byæ u¿yty: Nie w³±czono podczas kompilacji\n"
+
+#, c-format
+msgid "E28: No such highlight group name: %s"
+msgstr "E28: Brak takiej nazwy grupy pod¶wietlania: %s"
+
+msgid "E29: No inserted text yet"
+msgstr "E29: Nie wprowadzono jeszcze ¿adnego tekstu"
+
+msgid "E30: No previous command line"
+msgstr "E30: Nie ma poprzedniego wiersza poleceñ"
+
+msgid "E31: No such mapping"
+msgstr "E31: Nie ma takiego przyporz±dkowania"
+
+msgid "E479: No match"
+msgstr "E479: Brak dopasowañ"
+
+#, c-format
+msgid "E480: No match: %s"
+msgstr "E480: Brak dopasowañ: %s"
+
+msgid "E32: No file name"
+msgstr "E32: Brak nazwy pliku"
+
+msgid "E33: No previous substitute regular expression"
+msgstr "E33: Brak poprzedniego podstawieniowego wyra¿enia regularnego"
+
+msgid "E34: No previous command"
+msgstr "E34: Brak poprzedniej komendy"
+
+msgid "E35: No previous regular expression"
+msgstr "E35: Brak poprzedniego wyra¿enia regularnego"
+
+msgid "E481: No range allowed"
+msgstr "E481: Zakres niedozwolony"
+
+msgid "E36: Not enough room"
+msgstr "E36: Brak miejsca"
+
+#, c-format
+msgid "E247: no registered server named \"%s\""
+msgstr "E247: brak zarejestrowanego serwera o nazwie \"%s\""
+
+#, c-format
+msgid "E482: Can't create file %s"
+msgstr "E482: Nie mogê stworzyæ pliku %s"
+
+msgid "E483: Can't get temp file name"
+msgstr "E483: Nie mogê pobraæ nazwy pliku tymczasowego"
+
+#, c-format
+msgid "E484: Can't open file %s"
+msgstr "E484: Nie mogê otworzyæ pliku %s"
+
+#, c-format
+msgid "E485: Can't read file %s"
+msgstr "E485: Nie mogê odczytaæ pliku %s"
+
+msgid "E37: No write since last change (add ! to override)"
+msgstr "E37: Nie zapisano od ostatniej zmiany (wymu¶ przez !)"
+
+msgid "E38: Null argument"
+msgstr "E38: Zerowy argument"
+
+msgid "E39: Number expected"
+msgstr "E39: Oczekujê liczby"
+
+#, c-format
+msgid "E40: Can't open errorfile %s"
+msgstr "E40: Nie mogê otworzyæ pliku b³êdów %s"
+
+msgid "E233: cannot open display"
+msgstr "E233: nie mogê otworzyæ ekranu"
+
+msgid "E41: Out of memory!"
+msgstr "E41: Pamiêæ wyczerpana!"
+
+msgid "Pattern not found"
+msgstr "Nie znaleziono wzorca"
+
+#, c-format
+msgid "E486: Pattern not found: %s"
+msgstr "E486: Nie znaleziono wzorca: %s"
+
+msgid "E487: Argument must be positive"
+msgstr "E487: Argument musi byæ dodatni"
+
+msgid "E459: Cannot go back to previous directory"
+msgstr "E459: Nie mo¿na przej¶æ do poprzedniego katalogu"
+
+msgid "E42: No Errors"
+msgstr "E42: Brak B³êdów"
+
+msgid "E776: No location list"
+msgstr "E776: Brak listy lokacji"
+
+msgid "E43: Damaged match string"
+msgstr "E43: Popsuty ci±g wzorca"
+
+msgid "E44: Corrupted regexp program"
+msgstr "E44: Zepsuty program wyra¿eñ regularnych"
+
+msgid "E45: 'readonly' option is set (add ! to override)"
+msgstr "E45: opcja 'readonly' jest ustawiona (wymu¶ poprzez !)"
+
+#, c-format
+msgid "E46: Cannot change read-only variable \"%s\""
+msgstr "E46: Nie mogê zmieniæ zmiennej tylko do odczytu \"%s\""
+
+#, c-format
+msgid "E794: Cannot set variable in the sandbox: \"%s\""
+msgstr "E794: Nie mogê ustawiæ zmiennej w piaskownicy: \"%s\""
+
+msgid "E47: Error while reading errorfile"
+msgstr "E47: B³±d w trakcie czytania pliku b³êdów"
+
+msgid "E48: Not allowed in sandbox"
+msgstr "E48: Niedozwolone w piaskownicy"
+
+msgid "E523: Not allowed here"
+msgstr "E523: Niedozwolone w tym miejscu"
+
+msgid "E359: Screen mode setting not supported"
+msgstr "E359: Ustawianie trybu ekranu niewspomagane"
+
+msgid "E49: Invalid scroll size"
+msgstr "E49: Niew³a¶ciwa wielko¶æ przewiniêcia"
+
+msgid "E91: 'shell' option is empty"
+msgstr "E91: opcja 'shell' jest pusta"
+
+msgid "E255: Couldn't read in sign data!"
+msgstr "E255: Nie mog³em wczytaæ danych znaku!"
+
+msgid "E72: Close error on swap file"
+msgstr "E72: B³±d podczas zamykania pliku wymiany"
+
+msgid "E73: tag stack empty"
+msgstr "E73: stos znaczników jest pusty"
+
+msgid "E74: Command too complex"
+msgstr "E74: Komenda jest zbyt skomplikowana"
+
+msgid "E75: Name too long"
+msgstr "E75: Zbyt d³uga nazwa"
+
+msgid "E76: Too many ["
+msgstr "E76: Zbyt wiele ["
+
+msgid "E77: Too many file names"
+msgstr "E77: Zbyt wiele nazw plików"
+
+msgid "E488: Trailing characters"
+msgstr "E488: Nadstêpne znaczki"
+
+msgid "E78: Unknown mark"
+msgstr "E78: Nieznana zak³adka"
+
+msgid "E79: Cannot expand wildcards"
+msgstr "E79: Nie mog± rozwin±æ znaków wieloznacznych"
+
+msgid "E591: 'winheight' cannot be smaller than 'winminheight'"
+msgstr "E591: 'winheight' nie mo¿e byæ mniejsze ni¿ 'winminheight'"
+
+msgid "E592: 'winwidth' cannot be smaller than 'winminwidth'"
+msgstr "E592: 'winwidth' nie mo¿e byæ mniejsze ni¿ 'winminwidth'"
+
+msgid "E80: Error while writing"
+msgstr "E80: B³±d w trakcie zapisu"
+
+msgid "Zero count"
+msgstr "Zerowy licznik"
+
+msgid "E81: Using <SID> not in a script context"
+msgstr "E81: U¿ycie <SID> poza kontekstem skryptu"
+
+msgid "E449: Invalid expression received"
+msgstr "E449: Odebra³em niew³a¶ciwe wyra¿enie"
+
+msgid "E463: Region is guarded, cannot modify"
+msgstr "E463: Region jest chroniony, nie mogê zmieniæ"
+
+msgid "E744: NetBeans does not allow changes in read-only files"
+msgstr "E744: NetBeans nie zezwala na zmiany w plikach tylko do odczytu"
+
+#, c-format
+msgid "E685: Internal error: %s"
+msgstr "E685: B³±d wewnêtrzny: %s"
+
+msgid "E363: pattern uses more memory than 'maxmempattern'"
+msgstr "E363: Wzorzec u¿ywa wiêcej pamiêci ni¿ 'maxmempattern'"
+
+msgid "E749: empty buffer"
+msgstr "E749: pusty bufor"
+
+msgid "E682: Invalid search pattern or delimiter"
+msgstr "E682: Niew³a¶ciwy wzorzec wyszukiwania lub delimiter"
+
+msgid "E139: File is loaded in another buffer"
+msgstr "E139: Plik jest za³adowany w innym buforze"
+
+#, c-format
+msgid "E764: Option '%s' is not set"
+msgstr "E764: Nie ustawiono opcji '%s'"
+
+msgid "E850: Invalid register name"
+msgstr "E850: Niew³a¶ciwa nazwa rejestru"
+
+msgid "search hit TOP, continuing at BOTTOM"
+msgstr "szukanie dobi³o GÓRY; kontynuacja od KOÑCA"
+
+msgid "search hit BOTTOM, continuing at TOP"
+msgstr "szukanie dobi³o KOÑCA; kontynuacja od GÓRY"
+
+#, c-format
+msgid "Need encryption key for \"%s\""
+msgstr "Potrzebujê klucza szyfrowania dla \"%s\""
+
+msgid "empty keys are not allowed"
+msgstr "puste klucze nie s± dozwolone"
+
+msgid "dictionary is locked"
+msgstr "s³ownik jest zablokowany"
+
+msgid "list is locked"
+msgstr "lista jest zablokowana"
+
+#, c-format
+msgid "failed to add key '%s' to dictionary"
+msgstr "nie powiod³o siê dodanie klucza '%s' do s³ownika"
+
+#, c-format
+msgid "index must be int or slice, not %s"
+msgstr "indeks musi byæ liczb± lub wycinkiem, nie %s"
+
+#, c-format
+msgid "expected str() or unicode() instance, but got %s"
+msgstr "czeka³em na str() lub unicode(), a dosta³em %s"
+
+#, c-format
+msgid "expected bytes() or str() instance, but got %s"
+msgstr "czeka³em na bytes() lub str(), a dosta³em %s"
+
+#, c-format
+msgid ""
+"expected int(), long() or something supporting coercing to long(), but got %s"
+msgstr ""
+"czeka³em na int(), long() lub co¶ co mo¿na zmieniæ na long(), ale dosta³em %s"
+
+#, c-format
+msgid "expected int() or something supporting coercing to int(), but got %s"
+msgstr "czeka³em na int() lub co¶ co mo¿na zmieniæ na int(), ale dosta³em %s"
+
+msgid "value is too large to fit into C int type"
+msgstr "warto¶æ zbyt du¿a by zmie¶ci³a siê w typie int C"
+
+msgid "value is too small to fit into C int type"
+msgstr "warto¶æ jest zbyt ma³a by zmie¶ci³a siê w typie int C"
+
+msgid "number must be greater then zero"
+msgstr "liczba musi byæ wiêksza ni¿ zero"
+
+msgid "number must be greater or equal to zero"
+msgstr "liczba musi byæ wiêksza lub mniejsza ni¿ zero"
+
+msgid "can't delete OutputObject attributes"
+msgstr "nie mogê skasowaæ atrybutów OutputObject"
+
+#, c-format
+msgid "invalid attribute: %s"
+msgstr "niepoprawny atrybut: %s"
+
+msgid "E264: Python: Error initialising I/O objects"
+msgstr "E264: Python: B³±d w uruchomieniu obiektów I/O"
+
+msgid "failed to change directory"
+msgstr "nie powiod³a siê zmiana katalogu"
+
+#, c-format
+msgid "expected 3-tuple as imp.find_module() result, but got %s"
+msgstr "czeka³em na 3-krotkê jako wynik imp.find_module(), a dosta³em %s"
+
+#, c-format
+msgid "expected 3-tuple as imp.find_module() result, but got tuple of size %d"
+msgstr "czeka³em na 3-krotkê jako wynik imp.find_module(), a dosta³em krotkê o wielko¶ci %d"
+
+msgid "internal error: imp.find_module returned tuple with NULL"
+msgstr "wewnêtrzny b³±d: imp.find_module zwróci³ krotkê z NULL"
+
+msgid "cannot delete vim.Dictionary attributes"
+msgstr "nie mogê usun±æ atrybutów vim.Dictionary"
+
+msgid "cannot modify fixed dictionary"
+msgstr "nie mogê zmieniæ zablokowanego s³ownika"
+
+#, c-format
+msgid "cannot set attribute %s"
+msgstr "nie mogê ustawiæ atrybutu %s"
+
+msgid "hashtab changed during iteration"
+msgstr "hashtab zmieni³ siê w czasie iteracji"
+
+#, c-format
+msgid "expected sequence element of size 2, but got sequence of size %d"
+msgstr "czeka³em na element sekwencyjny od d³ugo¶ci 2, a dosta³em sekwencjê o d³ugo¶ci %d"
+
+msgid "list constructor does not accept keyword arguments"
+msgstr "konstruktor listy nie akceptuje s³ów kluczowych jako argumentów"
+
+msgid "list index out of range"
+msgstr "indeks listy poza zakresem"
+
+#. No more suitable format specifications in python-2.3
+#, c-format
+msgid "internal error: failed to get vim list item %d"
+msgstr "b³±d wewnêtrzny: nie powiod³o siê pobranie z listy Vima elementu %d"
+
+msgid "failed to add item to list"
+msgstr "nie powiod³o siê dodanie elementu do listy"
+
+#, c-format
+msgid "internal error: no vim list item %d"
+msgstr "b³±d wewnêtrzny: w li¶cie Vima brak elementu %d"
+
+msgid "internal error: failed to add item to list"
+msgstr "b³±d wewnêtrzny: nie powiod³o siê dodanie elementu do listy"
+
+msgid "cannot delete vim.List attributes"
+msgstr "nie mogê usun±æ atrybutów vim.List"
+
+msgid "cannot modify fixed list"
+msgstr "nie mogê zmieniæ zablokowanej listy"
+
+#, c-format
+msgid "unnamed function %s does not exist"
+msgstr "nie nazwana funkcja %s nie istnieje"
+
+#, c-format
+msgid "function %s does not exist"
+msgstr "funkcja %s nie istnieje"
+
+msgid "function constructor does not accept keyword arguments"
+msgstr "konstruktor funkcji nie akceptuje s³ów kluczowych jako argumentów"
+
+#, c-format
+msgid "failed to run function %s"
+msgstr "nie mogê uruchomiæ funkcji %s"
+
+msgid "unable to get option value"
+msgstr "nie mogê pobraæ warto¶ci opcji"
+
+msgid "internal error: unknown option type"
+msgstr "b³±d wewnêtrzny: nieznany typ opcji"
+
+msgid "problem while switching windows"
+msgstr "wyst±pi³ problem w czasie zmiany okien"
+
+#, c-format
+msgid "unable to unset global option %s"
+msgstr "nie mogê wyzerowaæ opcji globalnej %s"
+
+#, c-format
+msgid "unable to unset option %s which does not have global value"
+msgstr "nie mogê wyzerowaæ opcji %s, która nie ma warto¶ci globalnej"
+
+msgid "attempt to refer to deleted tab page"
+msgstr "próba odniesienia do skasowanej karty"
+
+msgid "no such tab page"
+msgstr "nie ma takiej karty"
+
+msgid "attempt to refer to deleted window"
+msgstr "próba odniesienia do skasowanego okna"
+
+msgid "readonly attribute: buffer"
+msgstr "atrybut tylko do odczytu: bufor"
+
+msgid "cursor position outside buffer"
+msgstr "pozycja kursora poza buforem"
+
+msgid "no such window"
+msgstr "nie ma takiego okna"
+
+msgid "attempt to refer to deleted buffer"
+msgstr "próba odniesienia do skasowanego bufora"
+
+msgid "failed to rename buffer"
+msgstr "nie powiod³a siê zmiana nazwy bufora"
+
+msgid "mark name must be a single character"
+msgstr "nazwa zak³adki musi byæ pojedynczym znakiem"
+
+#, c-format
+msgid "expected vim.Buffer object, but got %s"
+msgstr "oczekiwa³em na obiekt vim.Buffer, a dosta³em %s"
+
+#, c-format
+msgid "failed to switch to buffer %d"
+msgstr "nie przeszed³em do bufora %d"
+
+#, c-format
+msgid "expected vim.Window object, but got %s"
+msgstr "oczekiwa³em na obiekt vim.Window, a dosta³em %s"
+
+msgid "failed to find window in the current tab page"
+msgstr "nie znaleziono okna na bie¿±cej karcie"
+
+msgid "did not switch to the specified window"
+msgstr "nie przeszed³em do okre¶lonego okna"
+
+#, c-format
+msgid "expected vim.TabPage object, but got %s"
+msgstr "oczekiwa³em na obiekt vim.TabPage, a dosta³em %s"
+
+msgid "did not switch to the specified tab page"
+msgstr "nie przeszed³em do okre¶lonej karty"
+
+msgid "failed to run the code"
+msgstr "uruchomienie kodu siê nie powiod³o"
+
+msgid "E858: Eval did not return a valid python object"
+msgstr "E858: eval nie zwróci³o odpowiedniego obiektu pythona"
+
+msgid "E859: Failed to convert returned python object to vim value"
+msgstr "E859: Nie powiod³a siê konwersja obiektu pythona do warto¶ci Vima"
+
+#, c-format
+msgid "unable to convert %s to vim dictionary"
+msgstr "nie mo¿na konwertowaæ %s do s³ownika Vima"
+
+#, c-format
+msgid "unable to convert %s to vim structure"
+msgstr "nie mo¿na konwertowaæ %s do struktury Vima"
+
+msgid "internal error: NULL reference passed"
+msgstr "b³±d wewnêtrzny: przekazano referencjê NULL"
+
+msgid "internal error: invalid value type"
+msgstr "b³±d wewnêtrzny: b³êdny typ warto¶ci"
+
+msgid ""
+"Failed to set path hook: sys.path_hooks is not a list\n"
+"You should now do the following:\n"
+"- append vim.path_hook to sys.path_hooks\n"
+"- append vim.VIM_SPECIAL_PATH to sys.path\n"
+msgstr ""
+"Nie mogê ustawiæ haka ¶cie¿ki: sys.path_hooks nie jest list±\n"
+"Powiniene¶ teraz wykonaæ nastêpuj±ce czynno¶ci:\n"
+"- dodaæ vim.path_hook do sys.path_hooks\n"
+"- dodaæ vim.VIM_SPECIAL_PATH do sys.path\n"
+
+msgid ""
+"Failed to set path: sys.path is not a list\n"
+"You should now append vim.VIM_SPECIAL_PATH to sys.path"
+msgstr ""
+"Nie mogê ustawiæ ¶cie¿ki: sys.path nie jest list±\n"
+"Powinno siê teraz dodaæ vim.VIM_SPECIAL_PATH do sys.path"
+
+#~ msgid "softspace must be an integer"
+#~ msgstr "softspace musi byæ liczb± ca³kowit±"
+
+#~ msgid "<buffer object (deleted) at %p>"
+#~ msgstr "<obiekt bufora (skasowany) w %p>"
+
+#~ msgid ""
+#~ "E281: TCL ERROR: exit code is not int!? Please report this to vim-dev@vim."
+#~ "org"
+#~ msgstr ""
+#~ "E281: B£¡D TCL: kod zakoñczeniowy nie jest ca³kowity!? Proszê z³o¿yæ "
+#~ "raport o tym na vim-dev@vim.org"
+
+#~ msgid ""
+#~ "\n"
+#~ "Arguments recognised by gvim (RISC OS version):\n"
+#~ msgstr ""
+#~ "\n"
+#~ "Argumenty rozpoznawane przez gvim (wersja RISC OS):\n"
+
+#~ msgid "--columns <number>\tInitial width of window in columns"
+#~ msgstr "--columns <number>\tPocz±tkowa szeroko¶æ okna w kolumnach"
+
+#~ msgid "--rows <number>\tInitial height of window in rows"
+#~ msgstr "--rows <number>\tPocz±tkowa wysoko¶æ okna w wierszach"
+
+#~ msgid "E505: "
+#~ msgstr "E505: "
+
+#~ msgid ""
+#~ "\n"
+#~ "RISC OS version"
+#~ msgstr ""
+#~ "\n"
+#~ "wersja dla RISC OS"
+
+#~ msgid "writelines() requires list of strings"
+#~ msgstr "writelines() wymaga listy ci±gów"
+
+#~ msgid "<window object (deleted) at %p>"
+#~ msgstr "<obiekt okna (skasowany) w %p>"
+
+#~ msgid "<window object (unknown) at %p>"
+#~ msgstr "<obiekt okna (nieznany) w %p>"
+
+#~ msgid "<window %d>"
+#~ msgstr "<okno %d>"
+
+#~ msgid "-name <name>\t\tUse resource as if vim was <name>"
+#~ msgstr "-name <nazwa>\t\tU¿ywaj zasobów tak jak by Vim by³ <nazwa>"
+
+#~ msgid "\t\t\t (Unimplemented)\n"
+#~ msgstr "\t\t\t (Niezaimplementowane)\n"
+
+#~ msgid "E396: containedin argument not accepted here"
+#~ msgstr "E396: argument containedin niedozwolony w tym miejscu"
+
+#~ msgid "Vim dialog..."
+#~ msgstr "Dialog Vima..."
+
+#~ msgid "Font Selection"
+#~ msgstr "Wybór czcionki"
+
+#~ msgid "E290: over-the-spot style requires fontset"
+#~ msgstr "E290: styl nadpunktowy wymaga +fontset"
+
+#~ msgid "E291: Your GTK+ is older than 1.2.3. Status area disabled"
+#~ msgstr "E291: Twój GTK+ jest starszy ni¿ 1.2.3. Pole statusu wy³±czono"
+
+#~ msgid "E292: Input Method Server is not running"
+#~ msgstr "E292: Serwer metod wprowadzeñ nie jest uruchomiony"
+
+#~ msgid "with GTK-GNOME GUI."
+#~ msgstr "z GTK-GNOME GUI."
+
+#~ msgid "with GTK GUI."
+#~ msgstr "z GTK GUI."
+
+#~ msgid "[NL found]"
+#~ msgstr "[znaleziono NL]"
+
+#~ msgid "E569: maximum number of cscope connections reached"
+#~ msgstr "E569: wyczerpano maksymaln± liczbê po³±czeñ cscope"
diff --git a/src/po/pt_BR.po b/src/po/pt_BR.po
new file mode 100644
index 0000000..82054ec
--- /dev/null
+++ b/src/po/pt_BR.po
@@ -0,0 +1,7015 @@
+# Brazilian Portuguese Translation for Vim vim:set foldmethod=marker:
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Vim 8.0\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2017-09-10 11:11-0300\n"
+"PO-Revision-Date: 2017-09-10 11:12-0300\n"
+"Last-Translator: Eduardo S. Dobay <edudobay@gmail.com>\n"
+"Language-Team: Brazilian Portuguese\n"
+"Language: pt_BR\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\n"
+"X-Language: pt_BR\n"
+"X-Source-Language: en\n"
+
+msgid "E831: bf_key_init() called with empty password"
+msgstr "E831: bf_key_init() chamado com senha vazia"
+
+msgid "E820: sizeof(uint32_t) != 4"
+msgstr "E820: sizeof(uint32_t) != 4"
+
+msgid "E817: Blowfish big/little endian use wrong"
+msgstr "E817: Uso incorreto de Blowfish big/little endian"
+
+msgid "E818: sha256 test failed"
+msgstr "E818: verificação sha256 falhou"
+
+msgid "E819: Blowfish test failed"
+msgstr "E819: verificação Blowfish falhou"
+
+msgid "[Location List]"
+msgstr "[Lista de locais]"
+
+msgid "[Quickfix List]"
+msgstr "[Lista quickfix]"
+
+msgid "E855: Autocommands caused command to abort"
+msgstr "E855: Comando abortado devido a autocomandos"
+
+msgid "E82: Cannot allocate any buffer, exiting..."
+msgstr "E82: Não foi possível alocar nenhum buffer, saindo..."
+
+msgid "E83: Cannot allocate buffer, using other one..."
+msgstr "E83: Impossível alocar buffer; tentando usar outro..."
+
+msgid "E931: Buffer cannot be registered"
+msgstr "E931: Buffer não pode ser registrado"
+
+msgid "E937: Attempt to delete a buffer that is in use"
+msgstr "E937: Tentativa de deletar um buffer em uso"
+
+msgid "E515: No buffers were unloaded"
+msgstr "E515: Nenhum buffer foi descarregado"
+
+msgid "E516: No buffers were deleted"
+msgstr "E516: Nenhum buffer foi apagado"
+
+msgid "E517: No buffers were wiped out"
+msgstr "E517: Nenhum buffer foi eliminado"
+
+msgid "1 buffer unloaded"
+msgstr "1 buffer descarregado"
+
+#, c-format
+msgid "%d buffers unloaded"
+msgstr "%d buffers descarregados"
+
+msgid "1 buffer deleted"
+msgstr "1 buffer apagado"
+
+#, c-format
+msgid "%d buffers deleted"
+msgstr "%d buffers apagados"
+
+msgid "1 buffer wiped out"
+msgstr "1 buffer eliminado"
+
+#, c-format
+msgid "%d buffers wiped out"
+msgstr "%d buffers eliminados"
+
+msgid "E90: Cannot unload last buffer"
+msgstr "E90: Impossível descarregar último buffer"
+
+msgid "E84: No modified buffer found"
+msgstr "E84: Não foram encontrados buffers modificados"
+
+msgid "E85: There is no listed buffer"
+msgstr "E85: Não há buffers listados"
+
+msgid "E87: Cannot go beyond last buffer"
+msgstr "E87: Não é possível ir além do último buffer"
+
+msgid "E88: Cannot go before first buffer"
+msgstr "E88: Não é possível ir para antes do primeiro buffer"
+
+#, c-format
+msgid "E89: No write since last change for buffer %ld (add ! to override)"
+msgstr ""
+"E89: Alterações no buffer %ld não foram gravadas (adicione ! para forçar)"
+
+msgid "E948: Job still running (add ! to end the job)"
+msgstr "E948: Tarefa ainda em execução (adicione ! para finalizá-la)"
+
+msgid "E37: No write since last change (add ! to override)"
+msgstr "E37: Alterações não foram gravadas (adicione ! para forçar)"
+
+msgid "E948: Job still running"
+msgstr "E948: Tarefa ainda em execução"
+
+msgid "E37: No write since last change"
+msgstr "E37: Não foi salvo desde a última alteração"
+
+msgid "W14: Warning: List of file names overflow"
+msgstr "W14: Aviso: Estouro da lista de nomes de arquivos"
+
+#, c-format
+msgid "E92: Buffer %ld not found"
+msgstr "E92: Buffer %ld não encontrado"
+
+#, c-format
+msgid "E93: More than one match for %s"
+msgstr "E93: Mais de uma correspondência com %s"
+
+#, c-format
+msgid "E94: No matching buffer for %s"
+msgstr "E94: Nenhum buffer coincide com %s"
+
+#, c-format
+msgid "line %ld"
+msgstr "linha %ld"
+
+msgid "E95: Buffer with this name already exists"
+msgstr "E95: Já existe um buffer com esse nome"
+
+msgid " [Modified]"
+msgstr " [Modificado]"
+
+msgid "[Not edited]"
+msgstr "[Não editado]"
+
+msgid "[New file]"
+msgstr "[Novo arquivo]"
+
+msgid "[Read errors]"
+msgstr "[Erros de leitura]"
+
+msgid "[RO]"
+msgstr "[S/L]"
+
+msgid "[readonly]"
+msgstr "[somente-leitura]"
+
+#, c-format
+msgid "1 line --%d%%--"
+msgstr "1 linha --%d%%--"
+
+#, c-format
+msgid "%ld lines --%d%%--"
+msgstr "%ld linhas --%d%%--"
+
+#, c-format
+msgid "line %ld of %ld --%d%%-- col "
+msgstr "linha %ld de %ld --%d%%-- col "
+
+msgid "[No Name]"
+msgstr "[Sem nome]"
+
+msgid "help"
+msgstr "ajuda"
+
+msgid "[Help]"
+msgstr "[Ajuda]"
+
+msgid "[Preview]"
+msgstr "[Visualização]"
+
+msgid "All"
+msgstr "Tudo"
+
+msgid "Bot"
+msgstr "Fim"
+
+msgid "Top"
+msgstr "Topo"
+
+msgid ""
+"\n"
+"# Buffer list:\n"
+msgstr ""
+"\n"
+"# Lista de buffers:\n"
+
+msgid "E382: Cannot write, 'buftype' option is set"
+msgstr "E382: Impossível gravar, opção 'buftype' foi definida"
+
+msgid "[Scratch]"
+msgstr "[Rascunho]"
+
+msgid ""
+"\n"
+"--- Signs ---"
+msgstr ""
+"\n"
+"--- Sinais ---"
+
+#, c-format
+msgid "Signs for %s:"
+msgstr "Sinais para %s:"
+
+#, c-format
+msgid " line=%ld id=%d name=%s"
+msgstr " linha=%ld id=%d nome=%s"
+
+msgid "E902: Cannot connect to port"
+msgstr "E902: Não foi possível conectar-se à porta"
+
+msgid "E901: gethostbyname() in channel_open()"
+msgstr "E901: gethostbyname() em channel_open()"
+
+msgid "E898: socket() in channel_open()"
+msgstr "E898: socket() em channel_open()"
+
+msgid "E903: received command with non-string argument"
+msgstr "E903: comando recebido com argumento não-string"
+
+msgid "E904: last argument for expr/call must be a number"
+msgstr "E904: último argumento para expr/call deve ser numérico"
+
+msgid "E904: third argument for call must be a list"
+msgstr "E904: terceiro argumento para call deve ser uma lista"
+
+#, c-format
+msgid "E905: received unknown command: %s"
+msgstr "E905: comando desconhecido recebido: %s"
+
+#, c-format
+msgid "E630: %s(): write while not connected"
+msgstr "E630: %s(): tentativa de escrita enquanto desconectado"
+
+#, c-format
+msgid "E631: %s(): write failed"
+msgstr "E631: %s(): escrita falhou"
+
+#, c-format
+msgid "E917: Cannot use a callback with %s()"
+msgstr "E917: Impossível usar callback com %s()"
+
+msgid "E912: cannot use ch_evalexpr()/ch_sendexpr() with a raw or nl channel"
+msgstr ""
+"E912: ch_evalexpr()/ch_sendexpr() não pode ser usado com canal raw ou nl"
+
+msgid "E906: not an open channel"
+msgstr "E906: não é um canal aberto"
+
+msgid "E920: _io file requires _name to be set"
+msgstr "E920: arquivo _io requer definição de _name"
+
+msgid "E915: in_io buffer requires in_buf or in_name to be set"
+msgstr "E915: buffer in_io requer definição de in_buf ou in_name"
+
+#, c-format
+msgid "E918: buffer must be loaded: %s"
+msgstr "E918: buffer precisa ser carregado: %s"
+
+msgid "E821: File is encrypted with unknown method"
+msgstr "E821: Arquivo criptografado com método desconhecido"
+
+msgid "Warning: Using a weak encryption method; see :help 'cm'"
+msgstr "Alerta: Método fraco de criptografia; veja :help 'cm'"
+
+msgid "Enter encryption key: "
+msgstr "Insira a chave criptográfica: "
+
+msgid "Enter same key again: "
+msgstr "Insira a mesma chave novamente: "
+
+msgid "Keys don't match!"
+msgstr "As chaves não coincidem!"
+
+msgid "[crypted]"
+msgstr "[criptografado]"
+
+#, c-format
+msgid "E720: Missing colon in Dictionary: %s"
+msgstr "E720: Dois-pontos faltando no Dicionário: %s"
+
+#, c-format
+msgid "E721: Duplicate key in Dictionary: \"%s\""
+msgstr "E721: Chave duplicada no Dicionário: \"%s\""
+
+#, c-format
+msgid "E722: Missing comma in Dictionary: %s"
+msgstr "E722: Vírgula faltando no Dicionário: %s"
+
+#, c-format
+msgid "E723: Missing end of Dictionary '}': %s"
+msgstr "E723: Dicionário não finalizado com '}': %s"
+
+msgid "extend() argument"
+msgstr "argumento extend()"
+
+#, c-format
+msgid "E737: Key already exists: %s"
+msgstr "E737: Chave já existe: %s"
+
+#, c-format
+msgid "E96: Cannot diff more than %ld buffers"
+msgstr "E96: Não é possível um diff com mais de %ld buffers"
+
+msgid "E810: Cannot read or write temp files"
+msgstr "E810: Não foi possível ler ou gravar arquivos temporários"
+
+msgid "E97: Cannot create diffs"
+msgstr "E97: diff não funcionou"
+
+msgid "Patch file"
+msgstr "Selecionar arquivo de patch"
+
+msgid "E816: Cannot read patch output"
+msgstr "E816: Não foi possível ler o resultado do patch"
+
+msgid "E98: Cannot read diff output"
+msgstr "E98: Não foi possível ler o resultado do diff"
+
+msgid "E99: Current buffer is not in diff mode"
+msgstr "E99: O buffer atual não está no modo diff"
+
+msgid "E793: No other buffer in diff mode is modifiable"
+msgstr "E793: Não há nenhum outro buffer modificável em modo diff"
+
+msgid "E100: No other buffer in diff mode"
+msgstr "E100: Não há nenhum outro buffer no modo diff"
+
+msgid "E101: More than two buffers in diff mode, don't know which one to use"
+msgstr "E101: Há mais de dois buffers no modo diff; não sei quais usar"
+
+#, c-format
+msgid "E102: Can't find buffer \"%s\""
+msgstr "E102: Buffer \"%s\" não encontrado"
+
+#, c-format
+msgid "E103: Buffer \"%s\" is not in diff mode"
+msgstr "E103: Buffer \"%s\" não está no modo diff"
+
+msgid "E787: Buffer changed unexpectedly"
+msgstr "E787: Buffer foi alterado inesperadamente"
+
+msgid "E104: Escape not allowed in digraph"
+msgstr "E104: Caractere escape não é permitido em dígrafos"
+
+msgid "E544: Keymap file not found"
+msgstr "E544: Arquivo de mapa de teclado não encontrado"
+
+msgid "E105: Using :loadkeymap not in a sourced file"
+msgstr "E105: :loadkeymap usado fora de um script Vim"
+
+msgid "E791: Empty keymap entry"
+msgstr "E791: Entrada vazia no mapa de teclado"
+
+msgid " Keyword completion (^N^P)"
+msgstr " Completar palavra-chave (^N^P)"
+
+msgid " ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+msgstr " modo ^X (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+
+msgid " Whole line completion (^L^N^P)"
+msgstr " Completar linha inteira (^L^N^P)"
+
+msgid " File name completion (^F^N^P)"
+msgstr " Completar nome de arquivo (^F^N^P)"
+
+msgid " Tag completion (^]^N^P)"
+msgstr " Completar marcador (^]^N^P)"
+
+msgid " Path pattern completion (^N^P)"
+msgstr " Completar padrão de caminho (^N^P)"
+
+msgid " Definition completion (^D^N^P)"
+msgstr " Completar definição (^D^N^P)"
+
+msgid " Dictionary completion (^K^N^P)"
+msgstr " Completar do dicionário (^K^N^P)"
+
+msgid " Thesaurus completion (^T^N^P)"
+msgstr " Completar do dicionário de sinônimos (^T^N^P)"
+
+msgid " Command-line completion (^V^N^P)"
+msgstr " Completar da linha de comando (^V^N^P)"
+
+msgid " User defined completion (^U^N^P)"
+msgstr " Completar definido pelo usuário (^U^N^P)"
+
+msgid " Omni completion (^O^N^P)"
+msgstr " Completação inteligente (^O^N^P)"
+
+msgid " Spelling suggestion (s^N^P)"
+msgstr " Sugestão de ortografia (s^N^P)"
+
+msgid " Keyword Local completion (^N^P)"
+msgstr " Completar palavra-chave local (^N^P)"
+
+msgid "Hit end of paragraph"
+msgstr "Fim do parágrafo atingido"
+
+msgid "E839: Completion function changed window"
+msgstr "E839: Janela alterada por função de completamento"
+
+msgid "E840: Completion function deleted text"
+msgstr "E840: Função de completamento apagou texto"
+
+msgid "'dictionary' option is empty"
+msgstr "opção 'dictionary' vazia"
+
+msgid "'thesaurus' option is empty"
+msgstr "opção 'thesaurus' vazia"
+
+#, c-format
+msgid "Scanning dictionary: %s"
+msgstr "Examinando dicionário: %s"
+
+msgid " (insert) Scroll (^E/^Y)"
+msgstr " (inserção) Rolagem (^E/^Y)"
+
+msgid " (replace) Scroll (^E/^Y)"
+msgstr " (substituição) Rolagem (^E/^Y)"
+
+#, c-format
+msgid "Scanning: %s"
+msgstr "Examinando: %s"
+
+msgid "Scanning tags."
+msgstr "Examinando tags."
+
+msgid "match in file"
+msgstr "coincidência no arquivo"
+
+msgid " Adding"
+msgstr " Adicionando"
+
+msgid "-- Searching..."
+msgstr "-- Procurando..."
+
+msgid "Back at original"
+msgstr "De volta ao original"
+
+msgid "Word from other line"
+msgstr "Palavra de outra linha"
+
+msgid "The only match"
+msgstr "A única correspondência"
+
+#, c-format
+msgid "match %d of %d"
+msgstr "correspondência %d de %d"
+
+#, c-format
+msgid "match %d"
+msgstr "correspondência %d"
+
+msgid "E18: Unexpected characters in :let"
+msgstr "E18: Caracteres inesperados em :let"
+
+#, c-format
+msgid "E121: Undefined variable: %s"
+msgstr "E121: Variável indefinida: %s"
+
+msgid "E111: Missing ']'"
+msgstr "E111: ']' faltando"
+
+msgid "E719: Cannot use [:] with a Dictionary"
+msgstr "E719: Não é possível usar [:] com um Dicionário"
+
+#, c-format
+msgid "E734: Wrong variable type for %s="
+msgstr "E734: Variável de tipo errado para %s="
+
+#, c-format
+msgid "E461: Illegal variable name: %s"
+msgstr "E461: Nome ilegal para variável: %s"
+
+msgid "E806: using Float as a String"
+msgstr "E806: Float usado como String"
+
+msgid "E687: Less targets than List items"
+msgstr "E687: Há menos destinos que itens na Lista"
+
+msgid "E688: More targets than List items"
+msgstr "E688: Há mais destinos que itens na Lista"
+
+msgid "Double ; in list of variables"
+msgstr "; duplo na lista de variáveis"
+
+#, c-format
+msgid "E738: Can't list variables for %s"
+msgstr "E738: Impossível listar variáveis %s"
+
+msgid "E689: Can only index a List or Dictionary"
+msgstr "E689: Só Listas ou Dicionários podem ser indexados"
+
+msgid "E708: [:] must come last"
+msgstr "E708: [:] deve vir por último"
+
+msgid "E709: [:] requires a List value"
+msgstr "E709: [:] requer uma Lista"
+
+msgid "E710: List value has more items than target"
+msgstr "E710: a Lista tem mais itens que o destino"
+
+msgid "E711: List value has not enough items"
+msgstr "E711: a Lista não tem itens suficientes"
+
+msgid "E690: Missing \"in\" after :for"
+msgstr "E690: \"in\" faltando após :for"
+
+#, c-format
+msgid "E108: No such variable: \"%s\""
+msgstr "E108: Variável inexistente: \"%s\""
+
+#, c-format
+msgid "E940: Cannot lock or unlock variable %s"
+msgstr "E940: Impossível travar ou destravar variável %s"
+
+msgid "E743: variable nested too deep for (un)lock"
+msgstr "E743: variável aninhada demais para (des)bloquear"
+
+msgid "E109: Missing ':' after '?'"
+msgstr "E109: ':' faltando depois de '?'"
+
+msgid "E691: Can only compare List with List"
+msgstr "E691: Uma Lista só pode ser comparada com outra Lista"
+
+msgid "E692: Invalid operation for List"
+msgstr "E692: Operação inválida para Lista"
+
+msgid "E735: Can only compare Dictionary with Dictionary"
+msgstr "E735: Um Dicionário só pode ser comparado com outro Dicionário"
+
+msgid "E736: Invalid operation for Dictionary"
+msgstr "E736: Operação inválida para um Dicionário"
+
+msgid "E694: Invalid operation for Funcrefs"
+msgstr "E694: Operação inválida para Funcrefs"
+
+msgid "E804: Cannot use '%' with Float"
+msgstr "E804: Não é possível usar '%' com Float"
+
+msgid "E110: Missing ')'"
+msgstr "E110: ')' faltando"
+
+msgid "E695: Cannot index a Funcref"
+msgstr "E695: Não é possível indexar uma Funcref"
+
+msgid "E909: Cannot index a special variable"
+msgstr "E909: Não é possível indexar uma variável especial"
+
+#, c-format
+msgid "E112: Option name missing: %s"
+msgstr "E112: Nome de opção faltando: %s"
+
+#, c-format
+msgid "E113: Unknown option: %s"
+msgstr "E113: Opção desconhecida: %s"
+
+#, c-format
+msgid "E114: Missing quote: %s"
+msgstr "E114: Aspas duplas (\") faltando: %s"
+
+#, c-format
+msgid "E115: Missing quote: %s"
+msgstr "E115: Aspas simples (') faltando: %s"
+
+msgid "Not enough memory to set references, garbage collection aborted!"
+msgstr ""
+"Sem memória suficiente para definir referências, coleta de lixo abortada!"
+
+msgid "E724: variable nested too deep for displaying"
+msgstr "E724: variável aninhada demais para ser exibida"
+
+msgid "E805: Using a Float as a Number"
+msgstr "E805: Float usado como Número"
+
+msgid "E703: Using a Funcref as a Number"
+msgstr "E703: Funcref usada como Número"
+
+msgid "E745: Using a List as a Number"
+msgstr "E745: Lista usada como Número"
+
+msgid "E728: Using a Dictionary as a Number"
+msgstr "E728: Dicionário usado como Número"
+
+msgid "E910: Using a Job as a Number"
+msgstr "E910: Job usado como Número"
+
+msgid "E913: Using a Channel as a Number"
+msgstr "E913: Canal usado como Número"
+
+msgid "E891: Using a Funcref as a Float"
+msgstr "E891: Funcref usada como Float"
+
+msgid "E892: Using a String as a Float"
+msgstr "E892: String usada como Float"
+
+msgid "E893: Using a List as a Float"
+msgstr "E893: Lista usada como Float"
+
+msgid "E894: Using a Dictionary as a Float"
+msgstr "E894: Dicionário usado como Float"
+
+msgid "E907: Using a special value as a Float"
+msgstr "E907: Valor especial usado como Float"
+
+msgid "E911: Using a Job as a Float"
+msgstr "E911: Job usado como Float"
+
+msgid "E914: Using a Channel as a Float"
+msgstr "E914: Usando Canal como Float"
+
+msgid "E729: using Funcref as a String"
+msgstr "E729: Funcref usada como String"
+
+msgid "E730: using List as a String"
+msgstr "E730: Lista usada como String"
+
+msgid "E731: using Dictionary as a String"
+msgstr "E731: Dicionário usado como String"
+
+msgid "E908: using an invalid value as a String"
+msgstr "E908: valor inválido usado como String"
+
+#, c-format
+msgid "E795: Cannot delete variable %s"
+msgstr "E795: Impossível excluir variável %s"
+
+#, c-format
+msgid "E704: Funcref variable name must start with a capital: %s"
+msgstr "E704: Nome de variável Funcref deve começar com letra maiúscula: %s"
+
+#, c-format
+msgid "E705: Variable name conflicts with existing function: %s"
+msgstr "E705: Nome da variável em conflito com função já existente: %s"
+
+#, c-format
+msgid "E741: Value is locked: %s"
+msgstr "E741: Valor bloqueado: %s"
+
+msgid "Unknown"
+msgstr "Desconhecido"
+
+#, c-format
+msgid "E742: Cannot change value of %s"
+msgstr "E742: Não é possível mudar valor de %s"
+
+msgid "E698: variable nested too deep for making a copy"
+msgstr "E698: variável aninhada demais para fazer uma cópia"
+
+msgid ""
+"\n"
+"# global variables:\n"
+msgstr ""
+"\n"
+"# variáveis globais:\n"
+
+msgid ""
+"\n"
+"\tLast set from "
+msgstr ""
+"\n"
+"\tDefinido pela última vez em "
+
+msgid "map() argument"
+msgstr "argumento de map()"
+
+msgid "filter() argument"
+msgstr "argumento de filter()"
+
+#, c-format
+msgid "E686: Argument of %s must be a List"
+msgstr "E686: Argumento de %s deve ser uma Lista"
+
+msgid "E928: String required"
+msgstr "E928: String requerida"
+
+msgid "E808: Number or Float required"
+msgstr "E808: Número ou Float requerido"
+
+msgid "add() argument"
+msgstr "argumento de add()"
+
+msgid "E785: complete() can only be used in Insert mode"
+msgstr "E785: complete() só pode ser usado no modo de Inserção"
+
+msgid "&Ok"
+msgstr "&OK"
+
+#, c-format
+msgid "E700: Unknown function: %s"
+msgstr "E700: Função desconhecida: %s"
+
+msgid "E922: expected a dict"
+msgstr "E922: esperava um dict"
+
+msgid "E923: Second argument of function() must be a list or a dict"
+msgstr "E923: Segundo argumento de function() deve ser list ou dict"
+
+msgid ""
+"&OK\n"
+"&Cancel"
+msgstr ""
+"&OK\n"
+"&Cancelar"
+
+msgid "called inputrestore() more often than inputsave()"
+msgstr "inputrestore() foi chamado mais vezes que inputsave()"
+
+msgid "insert() argument"
+msgstr "argumento de insert()"
+
+msgid "E786: Range not allowed"
+msgstr "E786: Intervalos não são permitidos"
+
+msgid "E916: not a valid job"
+msgstr "E916: não é um trabalho válido"
+
+msgid "E701: Invalid type for len()"
+msgstr "E701: Tipo inválido para len()"
+
+#, c-format
+msgid "E798: ID is reserved for \":match\": %ld"
+msgstr "E798: ID reservado para \":match\": %ld"
+
+msgid "E726: Stride is zero"
+msgstr "E726: Incremento nulo"
+
+msgid "E727: Start past end"
+msgstr "E727: O início está depois do fim"
+
+msgid "<empty>"
+msgstr "<vazio>"
+
+msgid "E240: No connection to the X server"
+msgstr "E240: Sem conexão ao servidor X"
+
+#, c-format
+msgid "E241: Unable to send to %s"
+msgstr "E241: Não foi possível enviar para %s"
+
+msgid "E277: Unable to read a server reply"
+msgstr "E277: Não foi possível ler a resposta do servidor"
+
+msgid "E941: already started a server"
+msgstr "E941: servidor já iniciado"
+
+msgid "E942: +clientserver feature not available"
+msgstr "E942: recurso +clientserver não disponível"
+
+msgid "remove() argument"
+msgstr "argumento de remove()"
+
+msgid "E655: Too many symbolic links (cycle?)"
+msgstr "E655: Links simbólicos em excesso (cíclicos?)"
+
+msgid "reverse() argument"
+msgstr "argumento de reverse()"
+
+msgid "E258: Unable to send to client"
+msgstr "E258: Não foi possível enviar ao cliente"
+
+#, c-format
+msgid "E927: Invalid action: '%s'"
+msgstr "E927: Ação inválida: '%s'"
+
+msgid "sort() argument"
+msgstr "argumento de sort()"
+
+msgid "uniq() argument"
+msgstr "argumento de uniq()"
+
+msgid "E702: Sort compare function failed"
+msgstr "E702: Falha na função de comparação para ordenação"
+
+msgid "E882: Uniq compare function failed"
+msgstr "E882: Falha na função de comparação para uniq"
+
+msgid "(Invalid)"
+msgstr "(Inválido)"
+
+#, c-format
+msgid "E935: invalid submatch number: %d"
+msgstr "E935: número inválido para subpadrão: %d"
+
+msgid "E677: Error writing temp file"
+msgstr "E677: Erro ao gravar o arquivo temporário"
+
+msgid "E921: Invalid callback argument"
+msgstr "E921: Argumento inválido para callback"
+
+#, c-format
+msgid "<%s>%s%s %d, Hex %02x, Octal %03o"
+msgstr "<%s>%s%s %d, Hex %02x, Octal %03o"
+
+#, c-format
+msgid "> %d, Hex %04x, Octal %o"
+msgstr "> %d, Hex %04x, Octal %o"
+
+#, c-format
+msgid "> %d, Hex %08x, Octal %o"
+msgstr "> %d, Hex %08x, Octal %o"
+
+msgid "E134: Move lines into themselves"
+msgstr "E134: O destino coincide com a origem"
+
+msgid "1 line moved"
+msgstr "1 linha movida"
+
+#, c-format
+msgid "%ld lines moved"
+msgstr "%ld linhas movidas"
+
+#, c-format
+msgid "%ld lines filtered"
+msgstr "%ld linhas filtradas"
+
+msgid "E135: *Filter* Autocommands must not change current buffer"
+msgstr "E135: Os autocomandos *Filter* não devem modificar o buffer atual"
+
+msgid "[No write since last change]\n"
+msgstr "[Alterações não gravadas]\n"
+
+#, c-format
+msgid "%sviminfo: %s in line: "
+msgstr "%sviminfo: %s na linha: "
+
+msgid "E136: viminfo: Too many errors, skipping rest of file"
+msgstr "E136: viminfo: Há erros demais; abandonando a leitura do arquivo"
+
+#, c-format
+msgid "Reading viminfo file \"%s\"%s%s%s"
+msgstr "Lendo arquivo viminfo \"%s\"%s%s%s"
+
+msgid " info"
+msgstr " info"
+
+msgid " marks"
+msgstr " marcas"
+
+msgid " oldfiles"
+msgstr " arquivos antigos"
+
+msgid " FAILED"
+msgstr " FALHOU"
+
+#, c-format
+msgid "E137: Viminfo file is not writable: %s"
+msgstr "E137: O arquivo viminfo não pode ser escrito: %s"
+
+#, c-format
+msgid "E929: Too many viminfo temp files, like %s!"
+msgstr "E929: Muitos arquivos viminfo temporários para %s!"
+
+#, c-format
+msgid "E138: Can't write viminfo file %s!"
+msgstr "E138: Não é possível gravar o arquivo viminfo %s!"
+
+#, c-format
+msgid "Writing viminfo file \"%s\""
+msgstr "Gravando arquivo viminfo \"%s\""
+
+#, c-format
+msgid "E886: Can't rename viminfo file to %s!"
+msgstr "E886: Não é possível renomear o arquivo viminfo para %s!"
+
+#, c-format
+msgid "# This viminfo file was generated by Vim %s.\n"
+msgstr "# Este arquivo viminfo foi gerado pelo Vim %s.\n"
+
+msgid ""
+"# You may edit it if you're careful!\n"
+"\n"
+msgstr ""
+"# Você pode editá-lo se for cuidadoso!\n"
+"\n"
+
+msgid "# Value of 'encoding' when this file was written\n"
+msgstr "# Valor de 'encoding' quando este arquivo foi escrito\n"
+
+msgid "Illegal starting char"
+msgstr "Caractere inicial inválido"
+
+msgid ""
+"\n"
+"# Bar lines, copied verbatim:\n"
+msgstr ""
+"\n"
+"# Linhas com barra, copiadas literalmente:\n"
+
+msgid "Save As"
+msgstr "Salvar como"
+
+msgid "Write partial file?"
+msgstr "Gravar arquivo parcial?"
+
+msgid "E140: Use ! to write partial buffer"
+msgstr "E140: Use ! para gravar o buffer apenas parcialmente"
+
+#, c-format
+msgid "Overwrite existing file \"%s\"?"
+msgstr "Sobrescrever arquivo existente \"%s\"?"
+
+#, c-format
+msgid "Swap file \"%s\" exists, overwrite anyway?"
+msgstr "O arquivo de troca \"%s\" existe. Sobrescrevê-lo?"
+
+#, c-format
+msgid "E768: Swap file exists: %s (:silent! overrides)"
+msgstr "E768: Arquivo de troca existe: %s (:silent! para forçar)"
+
+#, c-format
+msgid "E141: No file name for buffer %ld"
+msgstr "E141: Sem nome de arquivo para o buffer %ld"
+
+msgid "E142: File not written: Writing is disabled by 'write' option"
+msgstr "E142: Arquivo não gravado: gravação desativada pela opção 'write'"
+
+#, c-format
+msgid ""
+"'readonly' option is set for \"%s\".\n"
+"Do you wish to write anyway?"
+msgstr ""
+"\"%s\" está com a opção 'readonly' (somente-leitura) ativada.\n"
+"Você deseja gravar assim mesmo?"
+
+#, c-format
+msgid ""
+"File permissions of \"%s\" are read-only.\n"
+"It may still be possible to write it.\n"
+"Do you wish to try?"
+msgstr ""
+"As permissões para \"%s\" são somente-leitura.\n"
+"Ainda pode ser possível gravar no arquivo.\n"
+"Você deseja tentar?"
+
+#, c-format
+msgid "E505: \"%s\" is read-only (add ! to override)"
+msgstr "E505: \"%s\" é somente-leitura (adicione ! para forçar)"
+
+msgid "Edit File"
+msgstr "Editar arquivo"
+
+#, c-format
+msgid "E143: Autocommands unexpectedly deleted new buffer %s"
+msgstr ""
+"E143: Algum autocomando inesperadamente apagou o buffer %s recém-criado"
+
+msgid "E144: non-numeric argument to :z"
+msgstr "E144: argumento não-numérico passado a :z"
+
+msgid "E145: Shell commands not allowed in rvim"
+msgstr "E145: Comandos do shell não são permitidos no rvim"
+
+msgid "E146: Regular expressions can't be delimited by letters"
+msgstr "E146: Expressões regulares não podem ser delimitadas por letras"
+
+#, c-format
+msgid "replace with %s (y/n/a/q/l/^E/^Y)?"
+msgstr "substituir por %s (y/n/a/q/l/^E/^Y)?"
+
+msgid "(Interrupted) "
+msgstr "(Interrompido) "
+
+msgid "1 match"
+msgstr "1 correspondência"
+
+msgid "1 substitution"
+msgstr "1 substituição"
+
+#, c-format
+msgid "%ld matches"
+msgstr "%ld correspondências"
+
+#, c-format
+msgid "%ld substitutions"
+msgstr "%ld substituições"
+
+msgid " on 1 line"
+msgstr " em 1 linha"
+
+#, c-format
+msgid " on %ld lines"
+msgstr " em %ld linhas"
+
+msgid "E147: Cannot do :global recursive with a range"
+msgstr "E147: Não é possível fazer :global recursivamente com um intervalo"
+
+msgid "E148: Regular expression missing from global"
+msgstr "E148: Expressão regular faltando no comando :global"
+
+#, c-format
+msgid "Pattern found in every line: %s"
+msgstr "Padrão encontrado em toda linha: %s"
+
+#, c-format
+msgid "Pattern not found: %s"
+msgstr "Padrão não encontrado: %s"
+
+msgid ""
+"\n"
+"# Last Substitute String:\n"
+"$"
+msgstr ""
+"\n"
+"# Última string de substituição:\n"
+"$"
+
+msgid "E478: Don't panic!"
+msgstr "E478: Não entre em pânico!"
+
+#, c-format
+msgid "E661: Sorry, no '%s' help for %s"
+msgstr "E661: Desculpe, nenhuma ajuda para %s em '%s'"
+
+#, c-format
+msgid "E149: Sorry, no help for %s"
+msgstr "E149: Desculpe, nenhuma ajuda para %s"
+
+#, c-format
+msgid "Sorry, help file \"%s\" not found"
+msgstr "Desculpe, arquivo de ajuda \"%s\" não encontrado"
+
+#, c-format
+msgid "E151: No match: %s"
+msgstr "E151: Nenhuma correspondência: %s"
+
+#, c-format
+msgid "E152: Cannot open %s for writing"
+msgstr "E152: Não foi possível abrir %s para escrita"
+
+#, c-format
+msgid "E153: Unable to open %s for reading"
+msgstr "E153: Não foi possível abrir %s para leitura"
+
+#, c-format
+msgid "E670: Mix of help file encodings within a language: %s"
+msgstr "E670: Mistura de codificações nos arquivos de ajuda na língua: %s"
+
+#, c-format
+msgid "E154: Duplicate tag \"%s\" in file %s/%s"
+msgstr "E154: Marcador duplicado \"%s\" no arquivo %s/%s"
+
+#, c-format
+msgid "E150: Not a directory: %s"
+msgstr "E150: Não é um diretório: %s"
+
+#, c-format
+msgid "E160: Unknown sign command: %s"
+msgstr "E160: Subcomando sign desconhecido: %s"
+
+msgid "E156: Missing sign name"
+msgstr "E156: Nome do sinal faltando"
+
+msgid "E612: Too many signs defined"
+msgstr "E612: Muitos sinais definidos"
+
+#, c-format
+msgid "E239: Invalid sign text: %s"
+msgstr "E239: Texto de sinal inválido: %s"
+
+#, c-format
+msgid "E155: Unknown sign: %s"
+msgstr "E155: Sinal desconhecido: %s"
+
+msgid "E159: Missing sign number"
+msgstr "E159: Número do sinal faltando"
+
+#, c-format
+msgid "E158: Invalid buffer name: %s"
+msgstr "E158: Nome de buffer inválido: %s"
+
+msgid "E934: Cannot jump to a buffer that does not have a name"
+msgstr "E934: Impossível pular para um buffer sem nome"
+
+#, c-format
+msgid "E157: Invalid sign ID: %ld"
+msgstr "E157: ID de sinal inválido: %ld"
+
+#, c-format
+msgid "E885: Not possible to change sign %s"
+msgstr "E885: Não é possível mudar o sinal %s"
+
+msgid " (NOT FOUND)"
+msgstr " (NÃO ENCONTRADO)"
+
+msgid " (not supported)"
+msgstr " (não suportado)"
+
+msgid "[Deleted]"
+msgstr "[Excluído]"
+
+msgid "No old files"
+msgstr "Não há arquivos antigos"
+
+msgid "Entering Debug mode. Type \"cont\" to continue."
+msgstr "Entrando modo de depuração. Digite \"cont\" para continuar."
+
+#, c-format
+msgid "line %ld: %s"
+msgstr "linha %ld: %s"
+
+#, c-format
+msgid "cmd: %s"
+msgstr "cmdo: %s"
+
+msgid "frame is zero"
+msgstr "quadro é zero"
+
+#, c-format
+msgid "frame at highest level: %d"
+msgstr "quadro no nível mais alto: %d"
+
+#, c-format
+msgid "Breakpoint in \"%s%s\" line %ld"
+msgstr "Ponto de interrupção em \"%s%s\", linha %ld"
+
+#, c-format
+msgid "E161: Breakpoint not found: %s"
+msgstr "E161: Ponto de interrupção não encontrado: %s"
+
+msgid "No breakpoints defined"
+msgstr "Nenhum ponto de interrupção definido"
+
+#, c-format
+msgid "%3d %s %s line %ld"
+msgstr "%3d %s %s linha %ld"
+
+msgid "E750: First use \":profile start {fname}\""
+msgstr "E750: Primeiro digite \":profile start {nome_arquivo}\""
+
+#, c-format
+msgid "Save changes to \"%s\"?"
+msgstr "Salvar as alterações em \"%s\"?"
+
+#, c-format
+msgid "E947: Job still running in buffer \"%s\""
+msgstr "E947: Tarefa em execução no buffer \"%s\""
+
+#, c-format
+msgid "E162: No write since last change for buffer \"%s\""
+msgstr "E162: Alterações no buffer \"%s\" não foram gravadas"
+
+msgid "Warning: Entered other buffer unexpectedly (check autocommands)"
+msgstr "Aviso: Entrada inesperada em outro buffer (verifique os autocomandos)"
+
+msgid "E163: There is only one file to edit"
+msgstr "E163: Só há um arquivo para editar"
+
+msgid "E164: Cannot go before first file"
+msgstr "E164: Impossível ir antes do primeiro arquivo"
+
+msgid "E165: Cannot go beyond last file"
+msgstr "E165: Impossível ir além do último arquivo"
+
+#, c-format
+msgid "E666: compiler not supported: %s"
+msgstr "E666: compilador não suportado: %s"
+
+#, c-format
+msgid "Searching for \"%s\" in \"%s\""
+msgstr "Procurando por \"%s\" em \"%s\""
+
+#, c-format
+msgid "Searching for \"%s\""
+msgstr "Procurando por \"%s\""
+
+#, c-format
+msgid "not found in '%s': \"%s\""
+msgstr "não encontrado em '%s': \"%s\""
+
+#, c-format
+msgid "W20: Required python version 2.x not supported, ignoring file: %s"
+msgstr "W20: Versão 2.x do python não suportada; ignorando arquivo: %s"
+
+#, c-format
+msgid "W21: Required python version 3.x not supported, ignoring file: %s"
+msgstr "W21: Versão 3.x do python não suportada; ignorando arquivo: %s"
+
+msgid "Source Vim script"
+msgstr "Executar script do Vim"
+
+#, c-format
+msgid "Cannot source a directory: \"%s\""
+msgstr "Impossível executar um diretório: \"%s\""
+
+#, c-format
+msgid "could not source \"%s\""
+msgstr "não foi possível executar \"%s\""
+
+#, c-format
+msgid "line %ld: could not source \"%s\""
+msgstr "linha %ld: não foi possível executar \"%s\""
+
+#, c-format
+msgid "sourcing \"%s\""
+msgstr "executando \"%s\""
+
+#, c-format
+msgid "line %ld: sourcing \"%s\""
+msgstr "linha %ld: executando \"%s\""
+
+#, c-format
+msgid "finished sourcing %s"
+msgstr "fim da execução de %s"
+
+#, c-format
+msgid "continuing in %s"
+msgstr "continuando em %s"
+
+msgid "modeline"
+msgstr "modeline"
+
+msgid "--cmd argument"
+msgstr "argumento --cmd"
+
+msgid "-c argument"
+msgstr "argumento -c"
+
+msgid "environment variable"
+msgstr "variável de ambiente"
+
+msgid "error handler"
+msgstr "tratador de erro"
+
+msgid "W15: Warning: Wrong line separator, ^M may be missing"
+msgstr "W15: Aviso: Separador de linha incorreto; ^M pode estar faltando"
+
+msgid "E167: :scriptencoding used outside of a sourced file"
+msgstr "E167: :scriptencoding usado fora de um script"
+
+msgid "E168: :finish used outside of a sourced file"
+msgstr "E168: :finish usado fora de um script"
+
+#, c-format
+msgid "Current %slanguage: \"%s\""
+msgstr "Idioma atual para %s: \"%s\""
+
+#, c-format
+msgid "E197: Cannot set language to \"%s\""
+msgstr "E197: Impossível definir idioma como \"%s\""
+
+msgid "Entering Ex mode. Type \"visual\" to go to Normal mode."
+msgstr "Entrando no modo Ex. Digite \"visual\" para ir para o modo Normal."
+
+msgid "E501: At end-of-file"
+msgstr "E501: Fim do arquivo"
+
+msgid "E169: Command too recursive"
+msgstr "E169: Comando recursivo demais"
+
+#, c-format
+msgid "E605: Exception not caught: %s"
+msgstr "E605: Exceção não interceptada: %s"
+
+msgid "End of sourced file"
+msgstr "Fim do arquivo executado"
+
+msgid "End of function"
+msgstr "Fim da função"
+
+msgid "E464: Ambiguous use of user-defined command"
+msgstr "E464: Uso ambíguo de comando definido pelo usuário"
+
+msgid "E492: Not an editor command"
+msgstr "E492: Não é um comando do editor"
+
+msgid "E493: Backwards range given"
+msgstr "E493: Intervalo com limites invertidos"
+
+msgid "Backwards range given, OK to swap"
+msgstr "O intervalo dado está com os limites invertidos. OK para reverter"
+
+msgid "E494: Use w or w>>"
+msgstr "E494: Use w ou w>>"
+
+msgid "E943: Command table needs to be updated, run 'make cmdidxs'"
+msgstr ""
+"E943: Tabela de comandos precisa ser atualizada, execute 'make cmdidxs'"
+
+msgid "E319: Sorry, the command is not available in this version"
+msgstr "E319: Desculpe, esse comando não está disponível nesta versão"
+
+msgid "E172: Only one file name allowed"
+msgstr "E172: Só é permitido um nome de arquivo"
+
+msgid "1 more file to edit. Quit anyway?"
+msgstr "Ainda há 1 arquivo para editar. Sair mesmo assim?"
+
+#, c-format
+msgid "%d more files to edit. Quit anyway?"
+msgstr "Há mais %d arquivos para editar. Sair mesmo assim?"
+
+msgid "E173: 1 more file to edit"
+msgstr "E173: Mais 1 arquivo para editar"
+
+#, c-format
+msgid "E173: %ld more files to edit"
+msgstr "E173: Mais %ld arquivos para editar"
+
+msgid "E174: Command already exists: add ! to replace it"
+msgstr "E174: Comando já existe; adicione ! para substituí-lo"
+
+msgid ""
+"\n"
+" Name Args Address Complete Definition"
+msgstr ""
+"\n"
+" Nome Args Intrv Complet. Definição"
+
+msgid "No user-defined commands found"
+msgstr "Nenhum comando definido pelo usuário foi encontrado"
+
+msgid "E175: No attribute specified"
+msgstr "E175: Nenhum atributo foi especificado"
+
+msgid "E176: Invalid number of arguments"
+msgstr "E176: Número inválido de argumentos"
+
+msgid "E177: Count cannot be specified twice"
+msgstr "E177: Quantificador não pode ser especificado duas vezes"
+
+msgid "E178: Invalid default value for count"
+msgstr "E178: Valor padrão inválido para o quantificador"
+
+msgid "E179: argument required for -complete"
+msgstr "E179: argumento necessário para -complete"
+
+msgid "E179: argument required for -addr"
+msgstr "E179: argumento necessário para -addr"
+
+#, c-format
+msgid "E181: Invalid attribute: %s"
+msgstr "E181: Atributo inválido: %s"
+
+msgid "E182: Invalid command name"
+msgstr "E182: Nome de comando inválido"
+
+msgid "E183: User defined commands must start with an uppercase letter"
+msgstr ""
+"E183: Comandos definidos pelo usuário devem começar com letra maiúscula"
+
+msgid "E841: Reserved name, cannot be used for user defined command"
+msgstr ""
+"E841: Nome reservado, não pode ser usado para comando definido pelo usuário"
+
+#, c-format
+msgid "E184: No such user-defined command: %s"
+msgstr "E184: Não existe tal comando definido pelo usuário: %s"
+
+#, c-format
+msgid "E180: Invalid address type value: %s"
+msgstr "E180: Tipo de endereço inválido: %s"
+
+#, c-format
+msgid "E180: Invalid complete value: %s"
+msgstr "E180: Valor inválido para -complete: %s"
+
+msgid "E468: Completion argument only allowed for custom completion"
+msgstr "E468: Argumento só é permitido para completação personalizada"
+
+msgid "E467: Custom completion requires a function argument"
+msgstr "E467: Completação automática requer função como argumento"
+
+msgid "unknown"
+msgstr "desconhecido"
+
+#, c-format
+msgid "E185: Cannot find color scheme '%s'"
+msgstr "E185: Esquema de cores '%s' não encontrado"
+
+msgid "Greetings, Vim user!"
+msgstr "Saudações, usuário do Vim!"
+
+msgid "E784: Cannot close last tab page"
+msgstr "E784: Não é possível fechar a última aba"
+
+msgid "Already only one tab page"
+msgstr "Já há apenas uma aba"
+
+msgid "Edit File in new window"
+msgstr "Editar arquivo em nova janela"
+
+#, c-format
+msgid "Tab page %d"
+msgstr "Aba %d"
+
+msgid "No swap file"
+msgstr "Sem arquivo de troca"
+
+msgid "Append File"
+msgstr "Adicionar arquivo"
+
+msgid "E747: Cannot change directory, buffer is modified (add ! to override)"
+msgstr ""
+"E747: Impossível mudar de diretório, o buffer foi alterado (adicione ! para "
+"forçar)"
+
+msgid "E186: No previous directory"
+msgstr "E186: Não há diretório anterior"
+
+msgid "E187: Unknown"
+msgstr "E187: Desconhecido"
+
+msgid "E465: :winsize requires two number arguments"
+msgstr "E465: :winsize requer dois argumentos numéricos"
+
+#, c-format
+msgid "Window position: X %d, Y %d"
+msgstr "Posição da janela: X %d, Y %d"
+
+msgid "E188: Obtaining window position not implemented for this platform"
+msgstr ""
+"E188: A obtenção da posição da janela não foi implementada para esta "
+"plataforma"
+
+msgid "E466: :winpos requires two number arguments"
+msgstr "E466: :winpos requer dois argumentos numéricos"
+
+msgid "E930: Cannot use :redir inside execute()"
+msgstr "E930: Impossível usar :redir dentro de execute()"
+
+msgid "Save Redirection"
+msgstr "Salvar redirecionamento"
+
+msgid "Save View"
+msgstr "Salvar visão atual"
+
+msgid "Save Session"
+msgstr "Salvar sessão"
+
+msgid "Save Setup"
+msgstr "Salvar configurações"
+
+#, c-format
+msgid "E739: Cannot create directory: %s"
+msgstr "E739: Diretório não pode ser criado: %s"
+
+#, c-format
+msgid "E189: \"%s\" exists (add ! to override)"
+msgstr "E189: \"%s\" existe (adicione ! para forçar)"
+
+#, c-format
+msgid "E190: Cannot open \"%s\" for writing"
+msgstr "E190: \"%s\" não pode ser aberto para escrita"
+
+msgid "E191: Argument must be a letter or forward/backward quote"
+msgstr "E191: Argumento deve ser uma letra ou aspa (` ou ')"
+
+msgid "E192: Recursive use of :normal too deep"
+msgstr "E192: Recursão excessiva de :normal"
+
+msgid "E809: #< is not available without the +eval feature"
+msgstr "E809: #< não está disponível sem o recurso +eval"
+
+msgid "E194: No alternate file name to substitute for '#'"
+msgstr "E194: Sem nome de arquivo alternativo para substituir '#'"
+
+msgid "E495: no autocommand file name to substitute for \"<afile>\""
+msgstr ""
+"E495: nenhum nome de arquivo de autocomandos para substituir \"<afile>\""
+
+msgid "E496: no autocommand buffer number to substitute for \"<abuf>\""
+msgstr ""
+"E496: nenhum número de buffer de autocomandos para substituir \"<abuf>\""
+
+msgid "E497: no autocommand match name to substitute for \"<amatch>\""
+msgstr "E497: nenhum critério de autocomando para substituir \"<amatch>\""
+
+msgid "E498: no :source file name to substitute for \"<sfile>\""
+msgstr "E498: nenhum nome de arquivo :source para substituir \"<sfile>\""
+
+msgid "E842: no line number to use for \"<slnum>\""
+msgstr "E842: sem número de linha para substituir \"<slnum>\""
+
+#, no-c-format
+msgid "E499: Empty file name for '%' or '#', only works with \":p:h\""
+msgstr "E499: Nome de arquivo vazio para '%' ou '#' só funciona com \":p:h\""
+
+msgid "E500: Evaluates to an empty string"
+msgstr "E500: Expressão resulta em string vazia"
+
+msgid "E195: Cannot open viminfo file for reading"
+msgstr "E195: O arquivo viminfo não pode ser aberto para leitura"
+
+msgid "Untitled"
+msgstr "Sem título"
+
+msgid "E196: No digraphs in this version"
+msgstr "E196: Sem suporte a dígrafos nesta versão"
+
+msgid "E608: Cannot :throw exceptions with 'Vim' prefix"
+msgstr "E608: Não é possível lançar exceções com o prefixo 'Vim'"
+
+#, c-format
+msgid "Exception thrown: %s"
+msgstr "Exceção lançada: %s"
+
+#, c-format
+msgid "Exception finished: %s"
+msgstr "Exceção concluída: %s"
+
+#, c-format
+msgid "Exception discarded: %s"
+msgstr "Exceção descartada: %s"
+
+#, c-format
+msgid "%s, line %ld"
+msgstr "%s, linha %ld"
+
+#, c-format
+msgid "Exception caught: %s"
+msgstr "Exceção interceptada: %s"
+
+#, c-format
+msgid "%s made pending"
+msgstr "%s tornado(s) pendente(s)"
+
+#, c-format
+msgid "%s resumed"
+msgstr "%s continuado(s)"
+
+#, c-format
+msgid "%s discarded"
+msgstr "%s descartado(s)"
+
+msgid "Exception"
+msgstr "Exceção"
+
+msgid "Error and interrupt"
+msgstr "Erro e interrupção"
+
+msgid "Error"
+msgstr "Erro"
+
+msgid "Interrupt"
+msgstr "Interrupção"
+
+msgid "E579: :if nesting too deep"
+msgstr "E579: :if aninhado demais"
+
+msgid "E580: :endif without :if"
+msgstr "E580: :endif sem :if"
+
+msgid "E581: :else without :if"
+msgstr "E581: :else sem :if"
+
+msgid "E582: :elseif without :if"
+msgstr "E582: :elseif sem :if"
+
+msgid "E583: multiple :else"
+msgstr "E583: mais de um :else"
+
+msgid "E584: :elseif after :else"
+msgstr "E584: :elseif depois de :else"
+
+msgid "E585: :while/:for nesting too deep"
+msgstr "E585: :while/:for aninhados demais"
+
+msgid "E586: :continue without :while or :for"
+msgstr "E586: :continue sem :while ou :for"
+
+msgid "E587: :break without :while or :for"
+msgstr "E587: :break sem :while ou :for"
+
+msgid "E732: Using :endfor with :while"
+msgstr "E732: :endfor usado com :while"
+
+msgid "E733: Using :endwhile with :for"
+msgstr "E733: :endwhile usado com :for"
+
+msgid "E601: :try nesting too deep"
+msgstr "E601: :try aninhado demais"
+
+msgid "E603: :catch without :try"
+msgstr "E603: :catch sem :try"
+
+msgid "E604: :catch after :finally"
+msgstr "E604: :catch depois de :finally"
+
+msgid "E606: :finally without :try"
+msgstr "E606: :finally sem :try"
+
+msgid "E607: multiple :finally"
+msgstr "E607: mais de um :finally"
+
+msgid "E602: :endtry without :try"
+msgstr "E602: :endtry sem :try"
+
+msgid "E193: :endfunction not inside a function"
+msgstr "E193: :endfunction fora de uma função"
+
+msgid "E788: Not allowed to edit another buffer now"
+msgstr "E788: Não é possível editar outro buffer agora"
+
+msgid "E811: Not allowed to change buffer information now"
+msgstr "E811: Não é permitido mudar as informações do buffer agora"
+
+msgid "tagname"
+msgstr "marcador"
+
+msgid " kind file\n"
+msgstr " tipo arquivo\n"
+
+msgid "'history' option is zero"
+msgstr "opção 'history' vale zero"
+
+#, c-format
+msgid ""
+"\n"
+"# %s History (newest to oldest):\n"
+msgstr ""
+"\n"
+"# Histórico de %s (mais recente primeiro):\n"
+
+msgid "Command Line"
+msgstr "linha de comando"
+
+msgid "Search String"
+msgstr "expressões de busca"
+
+msgid "Expression"
+msgstr "expressões"
+
+msgid "Input Line"
+msgstr "linha de entrada"
+
+msgid "Debug Line"
+msgstr "linha de debug"
+
+msgid "E198: cmd_pchar beyond the command length"
+msgstr "E198: cmd_pchar além do final do comando"
+
+msgid "E199: Active window or buffer deleted"
+msgstr "E199: A janela ou buffer ativo foi apagado"
+
+msgid "E812: Autocommands changed buffer or buffer name"
+msgstr "E812: Autocomandos alteraram o buffer ou o nome do buffer"
+
+msgid "Illegal file name"
+msgstr "Nome de arquivo inválido"
+
+msgid "is a directory"
+msgstr "é um diretório"
+
+msgid "is not a file"
+msgstr "não é um arquivo"
+
+msgid "is a device (disabled with 'opendevice' option)"
+msgstr "é um dispositivo (desativado pela opção 'opendevice')"
+
+msgid "[New File]"
+msgstr "[Novo arquivo]"
+
+msgid "[New DIRECTORY]"
+msgstr "[Novo DIRETÓRIO]"
+
+msgid "[File too big]"
+msgstr "[Arquivo muito grande]"
+
+msgid "[Permission Denied]"
+msgstr "[Permissão negada]"
+
+msgid "E200: *ReadPre autocommands made the file unreadable"
+msgstr "E200: Autocomandos *ReadPre tornaram o arquivo ilegível"
+
+msgid "E201: *ReadPre autocommands must not change current buffer"
+msgstr "E201: Os autocomandos *ReadPre não devem alterar o buffer atual"
+
+msgid "Vim: Reading from stdin...\n"
+msgstr "Vim: Lendo da entrada padrão...\n"
+
+msgid "Reading from stdin..."
+msgstr "Lendo da entrada padrão..."
+
+msgid "E202: Conversion made file unreadable!"
+msgstr "E202: A conversão tornou o arquivo ilegível!"
+
+msgid "[fifo/socket]"
+msgstr "[fifo/socket]"
+
+msgid "[fifo]"
+msgstr "[fifo]"
+
+msgid "[socket]"
+msgstr "[socket]"
+
+msgid "[character special]"
+msgstr "[dispositivo de caractere]"
+
+msgid "[CR missing]"
+msgstr "[CR faltando]"
+
+msgid "[long lines split]"
+msgstr "[linhas longas divididas]"
+
+msgid "[NOT converted]"
+msgstr "[NÃO convertido]"
+
+msgid "[converted]"
+msgstr "[convertido]"
+
+#, c-format
+msgid "[CONVERSION ERROR in line %ld]"
+msgstr "[ERRO DE CONVERSÃO na linha %ld]"
+
+#, c-format
+msgid "[ILLEGAL BYTE in line %ld]"
+msgstr "[BYTE INVÃLIDO na linha %ld]"
+
+msgid "[READ ERRORS]"
+msgstr "[ERROS DE LEITURA]"
+
+msgid "Can't find temp file for conversion"
+msgstr "Não foi possível encontrar um arquivo temporário para a conversão"
+
+msgid "Conversion with 'charconvert' failed"
+msgstr "Conversão com 'charconvert' falhou"
+
+msgid "can't read output of 'charconvert'"
+msgstr "não foi possível ler o resultado de 'charconvert'"
+
+msgid "E676: No matching autocommands for acwrite buffer"
+msgstr "E676: Nenhum comando automático correspondente para acwrite buffer"
+
+msgid "E203: Autocommands deleted or unloaded buffer to be written"
+msgstr "E203: Os autocomandos apagaram ou descarregaram o buffer a ser gravado"
+
+msgid "E204: Autocommand changed number of lines in unexpected way"
+msgstr "E204: Autocomando alterou número de linhas de maneira inesperada"
+
+msgid "NetBeans disallows writes of unmodified buffers"
+msgstr "NetBeans não permite gravação de buffers não modificados"
+
+msgid "Partial writes disallowed for NetBeans buffers"
+msgstr "Gravação parcial não é permitida em buffers do NetBeans"
+
+msgid "is not a file or writable device"
+msgstr "não é um arquivo ou dispositivo com permissão de escrita"
+
+msgid "writing to device disabled with 'opendevice' option"
+msgstr "escrita em dispositivo desativada pela opção 'opendevice'"
+
+msgid "is read-only (add ! to override)"
+msgstr "é somente-leitura (adicione ! para forçar)"
+
+msgid "E506: Can't write to backup file (add ! to override)"
+msgstr "E506: Impossível gravar arquivo de backup (adicione ! para forçar)"
+
+msgid "E507: Close error for backup file (add ! to override)"
+msgstr "E507: Erro de fechamento no arquivo de backup (adicione ! para forçar)"
+
+msgid "E508: Can't read file for backup (add ! to override)"
+msgstr "E508: Impossível ler o arquivo para backup (adicione ! para forçar)"
+
+msgid "E509: Cannot create backup file (add ! to override)"
+msgstr "E509: Impossível criar arquivo de backup (adicione ! para forçar)"
+
+msgid "E510: Can't make backup file (add ! to override)"
+msgstr "E510: Impossível fazer o backup (adicione ! para forçar)"
+
+msgid "E460: The resource fork would be lost (add ! to override)"
+msgstr "E460: O resource fork seria perdido (adicione ! para forçar)"
+
+msgid "E214: Can't find temp file for writing"
+msgstr "E214: Não foi possível encontrar arquivo temporário para escrita"
+
+msgid "E213: Cannot convert (add ! to write without conversion)"
+msgstr "E213: Impossível converter (adicione ! para gravar sem converter)"
+
+msgid "E166: Can't open linked file for writing"
+msgstr "E166: Impossível abrir ligação para escrita"
+
+msgid "E212: Can't open file for writing"
+msgstr "E212: Impossível abrir arquivo para escrita"
+
+msgid "E667: Fsync failed"
+msgstr "E667: Fsync falhou"
+
+msgid "E512: Close failed"
+msgstr "E512: Falha no fechamento do arquivo"
+
+msgid "E513: write error, conversion failed (make 'fenc' empty to override)"
+msgstr ""
+"E513: erro de gravação, conversão falhou (torne 'fenc' vazio para forçar)"
+
+#, c-format
+msgid ""
+"E513: write error, conversion failed in line %ld (make 'fenc' empty to "
+"override)"
+msgstr ""
+"E513: erro de gravação, conversão falhou na linha %ld (deixe 'fenc' vazio "
+"para forçar)"
+
+msgid "E514: write error (file system full?)"
+msgstr "E514: erro de gravação (sistema de arquivos cheio?)"
+
+msgid " CONVERSION ERROR"
+msgstr " ERRO DE CONVERSÃO"
+
+#, c-format
+msgid " in line %ld;"
+msgstr "na linha %ld;"
+
+msgid "[Device]"
+msgstr "[Dispositivo]"
+
+msgid "[New]"
+msgstr "[Novo]"
+
+msgid " [a]"
+msgstr " [a]"
+
+msgid " appended"
+msgstr " adicionado(s)"
+
+msgid " [w]"
+msgstr " [g]"
+
+msgid " written"
+msgstr " gravado(s)"
+
+msgid "E205: Patchmode: can't save original file"
+msgstr "E205: patchmode: impossível salvar o arquivo original"
+
+msgid "E206: patchmode: can't touch empty original file"
+msgstr "E206: patchmode: impossível criar arquivo original vazio"
+
+msgid "E207: Can't delete backup file"
+msgstr "E207: Impossível excluir arquivo de backup"
+
+msgid ""
+"\n"
+"WARNING: Original file may be lost or damaged\n"
+msgstr ""
+"\n"
+"AVISO: O arquivo original pode ter sido perdido ou danificado\n"
+
+msgid "don't quit the editor until the file is successfully written!"
+msgstr "não saia do editor até que o arquivo tenha sido gravado com sucesso!"
+
+msgid "[dos]"
+msgstr "[dos]"
+
+msgid "[dos format]"
+msgstr "[formato dos]"
+
+msgid "[mac]"
+msgstr "[mac]"
+
+msgid "[mac format]"
+msgstr "[formato mac]"
+
+msgid "[unix]"
+msgstr "[unix]"
+
+msgid "[unix format]"
+msgstr "[formato unix]"
+
+msgid "1 line, "
+msgstr "1 linha, "
+
+#, c-format
+msgid "%ld lines, "
+msgstr "%ld linhas, "
+
+msgid "1 character"
+msgstr "1 caractere"
+
+#, c-format
+msgid "%lld characters"
+msgstr "%lld caracteres"
+
+msgid "[noeol]"
+msgstr "[sem fim de linha]"
+
+msgid "[Incomplete last line]"
+msgstr "[Última linha incompleta]"
+
+msgid "WARNING: The file has been changed since reading it!!!"
+msgstr "AVISO: O arquivo foi alterado desde que foi carregado!!!"
+
+msgid "Do you really want to write to it"
+msgstr "Você realmente deseja gravá-lo"
+
+#, c-format
+msgid "E208: Error writing to \"%s\""
+msgstr "E208: Erro ao gravar \"%s\""
+
+#, c-format
+msgid "E209: Error closing \"%s\""
+msgstr "E209: Erro ao fechar \"%s\""
+
+#, c-format
+msgid "E210: Error reading \"%s\""
+msgstr "E210: Erro ao ler \"%s\""
+
+msgid "E246: FileChangedShell autocommand deleted buffer"
+msgstr "E246: O autocomando FileChangedShell apagou o buffer"
+
+#, c-format
+msgid "E211: File \"%s\" no longer available"
+msgstr "E211: Arquivo \"%s\" não está mais disponível"
+
+#, c-format
+msgid ""
+"W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as "
+"well"
+msgstr ""
+"W12: Aviso: arquivo \"%s\" foi alterado e o buffer também foi alterado no Vim"
+
+msgid "See \":help W12\" for more info."
+msgstr "Veja \":help W12\" para mais informações."
+
+#, c-format
+msgid "W11: Warning: File \"%s\" has changed since editing started"
+msgstr "W11: Aviso: arquivo \"%s\" foi alterado desde o início da edição"
+
+msgid "See \":help W11\" for more info."
+msgstr "Veja \":help W11\" para mais informações."
+
+#, c-format
+msgid "W16: Warning: Mode of file \"%s\" has changed since editing started"
+msgstr "W16: Aviso: modo do arquivo \"%s\" alterado desde o início da edição"
+
+msgid "See \":help W16\" for more info."
+msgstr "Veja \":help W16\" para mais informações."
+
+#, c-format
+msgid "W13: Warning: File \"%s\" has been created after editing started"
+msgstr ""
+"W13: Aviso: arquivo \"%s\" foi criado por outro programa desde o início da "
+"edição"
+
+msgid "Warning"
+msgstr "Aviso"
+
+msgid ""
+"&OK\n"
+"&Load File"
+msgstr ""
+"&OK\n"
+"&Carregar arquivo"
+
+#, c-format
+msgid "E462: Could not prepare for reloading \"%s\""
+msgstr "E462: Não foi possível preparar \"%s\" para ser recarregado"
+
+#, c-format
+msgid "E321: Could not reload \"%s\""
+msgstr "E321: Não foi possível recarregar \"%s\""
+
+msgid "--Deleted--"
+msgstr "--Excluído--"
+
+#, c-format
+msgid "auto-removing autocommand: %s <buffer=%d>"
+msgstr "removendo automaticamente o autocomando: %s <buffer=%d>"
+
+#, c-format
+msgid "E367: No such group: \"%s\""
+msgstr "E367: Grupo inexistente: \"%s\""
+
+msgid "E936: Cannot delete the current group"
+msgstr "E936: Impossível deletar o grupo atual"
+
+msgid "W19: Deleting augroup that is still in use"
+msgstr "W19: Deletando augroup em uso"
+
+#, c-format
+msgid "E215: Illegal character after *: %s"
+msgstr "E215: Caractere inválido após *: %s"
+
+#, c-format
+msgid "E216: No such event: %s"
+msgstr "E216: Evento inexistente: %s"
+
+#, c-format
+msgid "E216: No such group or event: %s"
+msgstr "E216: Grupo ou evento inexistente: %s"
+
+msgid ""
+"\n"
+"--- Autocommands ---"
+msgstr ""
+"\n"
+"--- Autocomandos ---"
+
+#, c-format
+msgid "E680: <buffer=%d>: invalid buffer number "
+msgstr "E680: <buffer=%d>: número inválido de buffer "
+
+msgid "E217: Can't execute autocommands for ALL events"
+msgstr "E217: Não é possível executar autocomandos para TODOS os eventos"
+
+msgid "No matching autocommands"
+msgstr "Nenhum autocomando coincidente"
+
+msgid "E218: autocommand nesting too deep"
+msgstr "E218: autocomandos aninhados demais"
+
+#, c-format
+msgid "%s Autocommands for \"%s\""
+msgstr "Comandos automáticos %s para \"%s\""
+
+#, c-format
+msgid "Executing %s"
+msgstr "Executando %s"
+
+#, c-format
+msgid "autocommand %s"
+msgstr "autocomando %s"
+
+msgid "E219: Missing {."
+msgstr "E219: { faltando."
+
+msgid "E220: Missing }."
+msgstr "E220: } faltando."
+
+msgid "E490: No fold found"
+msgstr "E490: Nenhuma dobra encontrada"
+
+msgid "E350: Cannot create fold with current 'foldmethod'"
+msgstr "E350: Impossível criar dobra com a configuração atual de 'foldmethod'"
+
+msgid "E351: Cannot delete fold with current 'foldmethod'"
+msgstr ""
+"E351: Impossível excluir dobra com a configuração atual de 'foldmethod'"
+
+msgid "E222: Add to read buffer"
+msgstr "E222: Adição a um buffer já lido"
+
+msgid "E223: recursive mapping"
+msgstr "E223: associação recursiva"
+
+#, c-format
+msgid "E224: global abbreviation already exists for %s"
+msgstr "E224: já existe uma abreviação global para %s"
+
+#, c-format
+msgid "E225: global mapping already exists for %s"
+msgstr "E225: já existe uma associação global para %s"
+
+#, c-format
+msgid "E226: abbreviation already exists for %s"
+msgstr "E226: já existe uma abreviação para %s"
+
+#, c-format
+msgid "E227: mapping already exists for %s"
+msgstr "E227: já existe uma associação para %s"
+
+msgid "No abbreviation found"
+msgstr "Nenhuma abreviação encontrada"
+
+msgid "No mapping found"
+msgstr "Nenhuma associação encontrada"
+
+msgid "E228: makemap: Illegal mode"
+msgstr "E228: makemap: Modo inválido"
+
+msgid "E851: Failed to create a new process for the GUI"
+msgstr "E851: Falha ao criar novo processo para interface gráfica"
+
+msgid "E852: The child process failed to start the GUI"
+msgstr "E852: Inicialização da interface falhou no processo filho"
+
+msgid "E229: Cannot start the GUI"
+msgstr "E229: Não é possível iniciar a interface gráfica"
+
+#, c-format
+msgid "E230: Cannot read from \"%s\""
+msgstr "E230: Impossível ler de \"%s\""
+
+msgid "E665: Cannot start GUI, no valid font found"
+msgstr ""
+"E665: Impossível iniciar a interface gráfica, nenhuma fonte válida encontrada"
+
+msgid "E231: 'guifontwide' invalid"
+msgstr "E231: Valor inválido para 'guifontwide'"
+
+msgid "E599: Value of 'imactivatekey' is invalid"
+msgstr "E599: Valor inválido para 'imactivatekey'"
+
+#, c-format
+msgid "E254: Cannot allocate color %s"
+msgstr "E254: Impossível alocar cor %s"
+
+msgid "No match at cursor, finding next"
+msgstr "Nenhum resultado sob o cursor; procurando próximo"
+
+msgid "<cannot open> "
+msgstr "<impossível abrir> "
+
+#, c-format
+msgid "E616: vim_SelFile: can't get font %s"
+msgstr "E616: vim_SelFile: impossível obter fonte %s"
+
+msgid "E614: vim_SelFile: can't return to current directory"
+msgstr "E614: vim_SelFile: impossível voltar ao diretório atual"
+
+msgid "Pathname:"
+msgstr "Caminho:"
+
+msgid "E615: vim_SelFile: can't get current directory"
+msgstr "E615: vim_SelFile: impossível obter diretório atual"
+
+msgid "OK"
+msgstr "OK"
+
+msgid "Cancel"
+msgstr "Cancelar"
+
+msgid "Scrollbar Widget: Could not get geometry of thumb pixmap."
+msgstr "Widget barra de rolagem: impossível obter geometria do pixmap 'thumb'."
+
+msgid "Vim dialog"
+msgstr "Diálogo do Vim"
+
+msgid "E232: Cannot create BalloonEval with both message and callback"
+msgstr "E232: Impossível criar BalloonEval com mensagem E callback"
+
+msgid "_Cancel"
+msgstr "_Cancelar"
+
+msgid "_Save"
+msgstr "_Salvar"
+
+msgid "_Open"
+msgstr "_Abrir"
+
+msgid "_OK"
+msgstr "_OK"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"&Cancel"
+msgstr ""
+"&Sim\n"
+"&Não\n"
+"&Cancelar"
+
+msgid "Yes"
+msgstr "Sim"
+
+msgid "No"
+msgstr "Não"
+
+msgid "Input _Methods"
+msgstr "_Métodos de entrada"
+
+msgid "VIM - Search and Replace..."
+msgstr "VIM - Procurar e substituir..."
+
+msgid "VIM - Search..."
+msgstr "VIM - Procurar..."
+
+msgid "Find what:"
+msgstr "Localizar:"
+
+msgid "Replace with:"
+msgstr "Substituir por:"
+
+msgid "Match whole word only"
+msgstr "Coincidir palavra inteira"
+
+msgid "Match case"
+msgstr "Diferenciar maiúsculas/minúsculas"
+
+msgid "Direction"
+msgstr "Direção"
+
+msgid "Up"
+msgstr "Acima"
+
+msgid "Down"
+msgstr "Abaixo"
+
+msgid "Find Next"
+msgstr "Localizar próxima"
+
+msgid "Replace"
+msgstr "Substituir"
+
+msgid "Replace All"
+msgstr "Substituir todas"
+
+msgid "_Close"
+msgstr "_Fechar"
+
+msgid "Vim: Received \"die\" request from session manager\n"
+msgstr "Vim: Pedido \"die\" recebido do gerenciador de sessão\n"
+
+msgid "Close tab"
+msgstr "Fechar aba"
+
+msgid "New tab"
+msgstr "Nova aba"
+
+msgid "Open Tab..."
+msgstr "Abrir aba..."
+
+msgid "Vim: Main window unexpectedly destroyed\n"
+msgstr "Vim: Janela principal destruída inesperadamente\n"
+
+msgid "&Filter"
+msgstr "&Filtrar"
+
+msgid "&Cancel"
+msgstr "&Cancelar"
+
+msgid "Directories"
+msgstr "Diretórios"
+
+msgid "Filter"
+msgstr "Filtro"
+
+msgid "&Help"
+msgstr "A&juda"
+
+msgid "Files"
+msgstr "Arquivos"
+
+msgid "&OK"
+msgstr "&OK"
+
+msgid "Selection"
+msgstr "Seleção"
+
+msgid "Find &Next"
+msgstr "Localizar &próxima"
+
+msgid "&Replace"
+msgstr "&Substituir"
+
+msgid "Replace &All"
+msgstr "Substituir &todas"
+
+msgid "&Undo"
+msgstr "&Desfazer"
+
+msgid "Open tab..."
+msgstr "Abrir aba..."
+
+msgid "Find string (use '\\\\' to find a '\\')"
+msgstr "Localizar cadeia de caracteres (use '\\\\' para procurar por '\\')"
+
+msgid "Find & Replace (use '\\\\' to find a '\\')"
+msgstr "Localizar e Substituir (use '\\\\' para procurar por '\\')"
+
+msgid "Not Used"
+msgstr "Não usado"
+
+msgid "Directory\t*.nothing\n"
+msgstr "Diretório\t*.nada\n"
+
+#, c-format
+msgid "E671: Cannot find window title \"%s\""
+msgstr "E671: Impossível encontrar janela de título \"%s\""
+
+#, c-format
+msgid "E243: Argument not supported: \"-%s\"; Use the OLE version."
+msgstr "E243: Argumento não suportado: \"-%s\"; Use a versão OLE."
+
+msgid "E672: Unable to open window inside MDI application"
+msgstr "E672: Impossível abrir janela dentro de aplicação MDI"
+
+msgid "Vim E458: Cannot allocate colormap entry, some colors may be incorrect"
+msgstr ""
+"Vim E458: Impossível alocar entrada do mapa de cores; algumas cores podem "
+"estar erradas"
+
+#, c-format
+msgid "E250: Fonts for the following charsets are missing in fontset %s:"
+msgstr ""
+"E250: Faltam fontes para os seguintes conjuntos de caracteres no conjunto de "
+"fontes %s:"
+
+#, c-format
+msgid "E252: Fontset name: %s"
+msgstr "E252: Nome do conjunto de fontes: %s"
+
+#, c-format
+msgid "Font '%s' is not fixed-width"
+msgstr "Fonte '%s' não é de largura fixa"
+
+#, c-format
+msgid "E253: Fontset name: %s"
+msgstr "E253: Nome do conjunto de fontes: %s"
+
+#, c-format
+msgid "Font0: %s"
+msgstr "Fonte0: %s"
+
+#, c-format
+msgid "Font1: %s"
+msgstr "Fonte1: %s"
+
+#, c-format
+msgid "Font%ld width is not twice that of font0"
+msgstr "Largura da Fonte%ld não é o dobro da Fonte0"
+
+#, c-format
+msgid "Font0 width: %ld"
+msgstr "Largura da Fonte0: %ld"
+
+#, c-format
+msgid "Font1 width: %ld"
+msgstr "Largura da Fonte1: %ld"
+
+msgid "Invalid font specification"
+msgstr "Especificação de fonte inválida"
+
+msgid "&Dismiss"
+msgstr "&Dispensar"
+
+msgid "no specific match"
+msgstr "nenhuma coincidência exata"
+
+msgid "Vim - Font Selector"
+msgstr "Vim - Seletor de fontes"
+
+msgid "Name:"
+msgstr "Nome:"
+
+msgid "Show size in Points"
+msgstr "Mostrar tamanho em pontos"
+
+msgid "Encoding:"
+msgstr "Codificação:"
+
+msgid "Font:"
+msgstr "Fonte:"
+
+msgid "Style:"
+msgstr "Estilo:"
+
+msgid "Size:"
+msgstr "Tamanho:"
+
+msgid "E256: Hangul automata ERROR"
+msgstr "E256: ERRO no autômato Hangul"
+
+msgid "E550: Missing colon"
+msgstr "E550: Dois-pontos faltando"
+
+msgid "E551: Illegal component"
+msgstr "E551: Elemento inválido"
+
+msgid "E552: digit expected"
+msgstr "E552: era esperado um algarismo"
+
+#, c-format
+msgid "Page %d"
+msgstr "Página %d"
+
+msgid "No text to be printed"
+msgstr "Sem texto para imprimir"
+
+#, c-format
+msgid "Printing page %d (%d%%)"
+msgstr "Imprimindo página %d (%d%%)"
+
+#, c-format
+msgid " Copy %d of %d"
+msgstr " Cópia %d de %d"
+
+#, c-format
+msgid "Printed: %s"
+msgstr "Impresso: %s"
+
+msgid "Printing aborted"
+msgstr "Impressão cancelada"
+
+msgid "E455: Error writing to PostScript output file"
+msgstr "E455: Erro ao escrever no arquivo PostScript"
+
+#, c-format
+msgid "E624: Can't open file \"%s\""
+msgstr "E624: Impossível abrir arquivo \"%s\""
+
+#, c-format
+msgid "E457: Can't read PostScript resource file \"%s\""
+msgstr "E457: Impossível ler o arquivo de recursos de PostScript \"%s\""
+
+#, c-format
+msgid "E618: file \"%s\" is not a PostScript resource file"
+msgstr "E618: arquivo \"%s\" não é um arquivo de recursos de PostScript"
+
+#, c-format
+msgid "E619: file \"%s\" is not a supported PostScript resource file"
+msgstr ""
+"E619: arquivo \"%s\" não é um arquivo de recursos de PostScript suportado"
+
+#, c-format
+msgid "E621: \"%s\" resource file has wrong version"
+msgstr "E621: versão errada do arquivo de recursos \"%s\""
+
+msgid "E673: Incompatible multi-byte encoding and character set."
+msgstr ""
+"E673: Codificação multi-byte incompatível com o conjunto de caracteres."
+
+msgid "E674: printmbcharset cannot be empty with multi-byte encoding."
+msgstr ""
+"E674: 'printmbcharset' não pode estar vazio com codificações multi-byte."
+
+msgid "E675: No default font specified for multi-byte printing."
+msgstr "E675: Nenhuma fonte padrão especificada para impressão em multi-byte."
+
+msgid "E324: Can't open PostScript output file"
+msgstr "E324: Impossível abrir arquivo PostScript para saída"
+
+#, c-format
+msgid "E456: Can't open file \"%s\""
+msgstr "E456: Impossível abrir arquivo \"%s\""
+
+msgid "E456: Can't find PostScript resource file \"prolog.ps\""
+msgstr "E456: Arquivo de recursos de PostScript \"prolog.ps\" não encontrado"
+
+msgid "E456: Can't find PostScript resource file \"cidfont.ps\""
+msgstr "E456: Arquivo de recursos de PostScript \"cidfont.ps\" não encontrado"
+
+#, c-format
+msgid "E456: Can't find PostScript resource file \"%s.ps\""
+msgstr "E456: Arquivo de recursos de PostScript \"%s.ps\" não encontrado"
+
+#, c-format
+msgid "E620: Unable to convert to print encoding \"%s\""
+msgstr "E620: Impossível converter para a codificação \"%s\" para impressão"
+
+msgid "Sending to printer..."
+msgstr "Enviando à impressora..."
+
+msgid "E365: Failed to print PostScript file"
+msgstr "E365: Não foi possível imprimir o arquivo PostScript"
+
+msgid "Print job sent."
+msgstr "Trabalho de impressão enviado."
+
+msgid "Add a new database"
+msgstr "Adicionar novo banco de dados"
+
+msgid "Query for a pattern"
+msgstr "Procurar por um padrão"
+
+msgid "Show this message"
+msgstr "Mostrar esta mensagem"
+
+msgid "Kill a connection"
+msgstr "Terminar uma conexão"
+
+msgid "Reinit all connections"
+msgstr "Reinicializar todas as conexões"
+
+msgid "Show connections"
+msgstr "Mostrar conexões"
+
+#, c-format
+msgid "E560: Usage: cs[cope] %s"
+msgstr "E560: Forma de uso: cs[cope] %s"
+
+msgid "This cscope command does not support splitting the window.\n"
+msgstr "Este comando cscope não suporta a divisão da janela.\n"
+
+msgid "E562: Usage: cstag <ident>"
+msgstr "E562: Forma de uso: cstag <ident>"
+
+msgid "E257: cstag: tag not found"
+msgstr "E257: cstag: marcador não encontrado"
+
+#, c-format
+msgid "E563: stat(%s) error: %d"
+msgstr "E563: erro em stat(%s): %d"
+
+msgid "E563: stat error"
+msgstr "E563: erro em stat"
+
+#, c-format
+msgid "E564: %s is not a directory or a valid cscope database"
+msgstr "E564: %s não é um diretório ou um banco de dados válido do cscope"
+
+#, c-format
+msgid "Added cscope database %s"
+msgstr "Adicionado banco de dados do cscope %s"
+
+#, c-format
+msgid "E262: error reading cscope connection %ld"
+msgstr "E262: erro ao ler a conexão %ld do cscope"
+
+msgid "E561: unknown cscope search type"
+msgstr "E561: tipo desconhecido de busca do cscope"
+
+msgid "E566: Could not create cscope pipes"
+msgstr "E566: Não foi possível criar os pipes para comunicação com o cscope"
+
+msgid "E622: Could not fork for cscope"
+msgstr "E622: Não foi possível fazer a bifurcação de processo para o cscope"
+
+msgid "cs_create_connection setpgid failed"
+msgstr "falha de setpgid em cs_create_connection"
+
+msgid "cs_create_connection exec failed"
+msgstr "falha na execução do cscope em cs_create_connection"
+
+msgid "cs_create_connection: fdopen for to_fp failed"
+msgstr "cs_create_connection: fdopen para to_fp falhou"
+
+msgid "cs_create_connection: fdopen for fr_fp failed"
+msgstr "cs_create_connection: fdopen para fr_fp falhou"
+
+msgid "E623: Could not spawn cscope process"
+msgstr "E623: Não foi possível invocar o processo do cscope"
+
+msgid "E567: no cscope connections"
+msgstr "E567: não há conexões com o cscope"
+
+#, c-format
+msgid "E469: invalid cscopequickfix flag %c for %c"
+msgstr "E469: marca %c inválida para %c em 'cscopequickfix'"
+
+#, c-format
+msgid "E259: no matches found for cscope query %s of %s"
+msgstr "E259: nenhum resultado para a busca cscope %s de %s"
+
+msgid "cscope commands:\n"
+msgstr "comandos do cscope:\n"
+
+#, c-format
+msgid "%-5s: %s%*s (Usage: %s)"
+msgstr "%-5s: %s%*s (Forma de uso: %s)"
+
+msgid ""
+"\n"
+" a: Find assignments to this symbol\n"
+" c: Find functions calling this function\n"
+" d: Find functions called by this function\n"
+" e: Find this egrep pattern\n"
+" f: Find this file\n"
+" g: Find this definition\n"
+" i: Find files #including this file\n"
+" s: Find this C symbol\n"
+" t: Find this text string\n"
+msgstr ""
+"\n"
+" a: Buscar atribuição a este símbolo\n"
+" c: Buscar funções que chamam esta função\n"
+" d: Buscar funções chamadas por esta função\n"
+" e: Buscar este padrão do egrep\n"
+" f: Buscar este arquivo\n"
+" g: Buscar esta definição\n"
+" i: Buscar arquivos com #include para este arquivo\n"
+" s: Buscar este símbolo do C\n"
+" t: Buscar esta string de texto\n"
+
+#, c-format
+msgid "E625: cannot open cscope database: %s"
+msgstr "E625: impossível abrir banco de dados do cscope: %s"
+
+msgid "E626: cannot get cscope database information"
+msgstr "E626: impossível obter informações do banco de dados do cscope"
+
+msgid "E568: duplicate cscope database not added"
+msgstr "E568: banco de dados do cscope repetido; não foi adicionado"
+
+#, c-format
+msgid "E261: cscope connection %s not found"
+msgstr "E261: conexão %s com o cscope não encontrada"
+
+#, c-format
+msgid "cscope connection %s closed"
+msgstr "conexão %s com o cscope fechada"
+
+msgid "E570: fatal error in cs_manage_matches"
+msgstr "E570: erro fatal em cs_manage_matches"
+
+#, c-format
+msgid "Cscope tag: %s"
+msgstr "Tag do cscope: %s"
+
+msgid ""
+"\n"
+" # line"
+msgstr ""
+"\n"
+" # linha"
+
+msgid "filename / context / line\n"
+msgstr "arquivo / contexto / linha\n"
+
+#, c-format
+msgid "E609: Cscope error: %s"
+msgstr "E609: Erro do cscope: %s"
+
+msgid "All cscope databases reset"
+msgstr "Todos os bancos de dados do cscope redefinidos"
+
+msgid "no cscope connections\n"
+msgstr "nenhuma conexão ao cscope\n"
+
+msgid " # pid database name prepend path\n"
+msgstr " # pid nome do banco de dados adicionar caminho\n"
+
+msgid "Lua library cannot be loaded."
+msgstr "Biblioteca Lua não pôde ser carregada."
+
+msgid "cannot save undo information"
+msgstr "impossível salvar informações para desfazer"
+
+msgid ""
+"E815: Sorry, this command is disabled, the MzScheme libraries could not be "
+"loaded."
+msgstr ""
+"E815: Desculpe, este comando está desativado. As bibliotecas do MzScheme não "
+"puderam ser carregadas."
+
+msgid ""
+"E895: Sorry, this command is disabled, the MzScheme's racket/base module "
+"could not be loaded."
+msgstr ""
+"E895: Desculpe, este comando está desativado. O módulo racket/base do "
+"MzScheme não pôde ser carregado."
+
+msgid "invalid expression"
+msgstr "expressão inválida"
+
+msgid "expressions disabled at compile time"
+msgstr "expressões desativadas na compilação"
+
+msgid "hidden option"
+msgstr "opção oculta"
+
+msgid "unknown option"
+msgstr "opção desconhecida"
+
+msgid "window index is out of range"
+msgstr "número da janela fora dos limites"
+
+msgid "couldn't open buffer"
+msgstr "impossível abrir buffer"
+
+msgid "cannot delete line"
+msgstr "impossível excluir linha"
+
+msgid "cannot replace line"
+msgstr "impossível substituir linha"
+
+msgid "cannot insert line"
+msgstr "impossível inserir linha"
+
+msgid "string cannot contain newlines"
+msgstr "a cadeia não pode conter quebras de linha"
+
+msgid "error converting Scheme values to Vim"
+msgstr "erro convertendo valores Scheme para Vim"
+
+msgid "Vim error: ~a"
+msgstr "Erro do Vim: ~a"
+
+msgid "Vim error"
+msgstr "Erro do Vim"
+
+msgid "buffer is invalid"
+msgstr "buffer inválido"
+
+msgid "window is invalid"
+msgstr "janela inválida"
+
+msgid "linenr out of range"
+msgstr "número de linha fora dos limites"
+
+msgid "not allowed in the Vim sandbox"
+msgstr "não permitido na caixa de areia do Vim"
+
+msgid "E836: This Vim cannot execute :python after using :py3"
+msgstr "E836: Este Vim não pode executar :python após ter usado :py3"
+
+msgid ""
+"E263: Sorry, this command is disabled, the Python library could not be "
+"loaded."
+msgstr ""
+"E263: Desculpe, este comando está desativado. A biblioteca do Python não "
+"pôde ser carregada."
+
+msgid ""
+"E887: Sorry, this command is disabled, the Python's site module could not be "
+"loaded."
+msgstr ""
+"E887: Desculpe, este comando está desativado. O módulo site do Python não "
+"pôde ser carregado."
+
+msgid "E659: Cannot invoke Python recursively"
+msgstr "E659: Não é possível invocar o Python recursivamente"
+
+msgid "E837: This Vim cannot execute :py3 after using :python"
+msgstr "E837: Este Vim não pode executar :py3 depois de usar :python"
+
+msgid "E265: $_ must be an instance of String"
+msgstr "E265: $_ deve ser uma instância de String"
+
+msgid ""
+"E266: Sorry, this command is disabled, the Ruby library could not be loaded."
+msgstr ""
+"E266: Desculpe, este comando está desativado. A biblioteca do Ruby não pôde "
+"ser carregada."
+
+msgid "E267: unexpected return"
+msgstr "E267: \"return\" inesperado"
+
+msgid "E268: unexpected next"
+msgstr "E268: \"next\" inesperado"
+
+msgid "E269: unexpected break"
+msgstr "E269: \"break\" inesperado"
+
+msgid "E270: unexpected redo"
+msgstr "E270: \"redo\" inesperado"
+
+msgid "E271: retry outside of rescue clause"
+msgstr "E271: \"retry\" fora de bloco \"rescue\""
+
+msgid "E272: unhandled exception"
+msgstr "E272: exceção não tratada"
+
+#, c-format
+msgid "E273: unknown longjmp status %d"
+msgstr "E273: status %d de longjmp desconhecido"
+
+msgid "invalid buffer number"
+msgstr "número inválido de buffer"
+
+msgid "not implemented yet"
+msgstr "ainda não implementado"
+
+msgid "cannot set line(s)"
+msgstr "não foi possível redefinir a(s) linha(s)"
+
+msgid "invalid mark name"
+msgstr "nome de marca inválido"
+
+msgid "mark not set"
+msgstr "marca não definida"
+
+#, c-format
+msgid "row %d column %d"
+msgstr "linha %d coluna %d"
+
+msgid "cannot insert/append line"
+msgstr "impossível inserir/adicionar linha"
+
+msgid "line number out of range"
+msgstr "número de linha fora dos limites"
+
+msgid "unknown flag: "
+msgstr "opção desconhecida: "
+
+msgid "unknown vimOption"
+msgstr "opção do Vim desconhecida"
+
+msgid "keyboard interrupt"
+msgstr "interrompido pelo teclado"
+
+msgid "vim error"
+msgstr "erro do vim"
+
+msgid "cannot create buffer/window command: object is being deleted"
+msgstr ""
+"impossível criar comando de buffer/janela: o objeto está sendo excluído"
+
+msgid ""
+"cannot register callback command: buffer/window is already being deleted"
+msgstr ""
+"não foi possível registrar o comando de callback: o buffer/janela já está "
+"sendo excluído"
+
+msgid ""
+"E280: TCL FATAL ERROR: reflist corrupt!? Please report this to vim-dev@vim."
+"org"
+msgstr ""
+"E280: ERRO FATAL DO TCL: reflist corrompida!? Por favor relate isso para vim-"
+"dev@vim.org"
+
+msgid "cannot register callback command: buffer/window reference not found"
+msgstr ""
+"não foi possível registrar o comando de callback: referência a buffer/janela "
+"não encontrada"
+
+msgid ""
+"E571: Sorry, this command is disabled: the Tcl library could not be loaded."
+msgstr ""
+"E571: Desculpe, este comando está desativado. A biblioteca do Tcl não pôde "
+"ser carregada."
+
+#, c-format
+msgid "E572: exit code %d"
+msgstr "E572: código de saída %d"
+
+msgid "cannot get line"
+msgstr "não foi possível obter a linha"
+
+msgid "Unable to register a command server name"
+msgstr "Não foi possível registrar um nome para o servidor de comandos"
+
+msgid "E248: Failed to send command to the destination program"
+msgstr "E248: Falha ao enviar comando ao programa de destino"
+
+#, c-format
+msgid "E573: Invalid server id used: %s"
+msgstr "E573: Foi usada uma id de servidor inválida: %s"
+
+msgid "E251: VIM instance registry property is badly formed. Deleted!"
+msgstr ""
+"E251: Propriedade de registro de instância do VIM malformada encontrada e "
+"excluída!"
+
+#, c-format
+msgid "E938: Duplicate key in JSON: \"%s\""
+msgstr "E938: Chave duplicada no objeto JSON: \"%s\""
+
+#, c-format
+msgid "E696: Missing comma in List: %s"
+msgstr "E696: Falta uma vírgula na Lista: %s"
+
+#, c-format
+msgid "E697: Missing end of List ']': %s"
+msgstr "E697: Lista não finalizada com ']': %s"
+
+msgid "Unknown option argument"
+msgstr "Argumento de opção desconhecido"
+
+msgid "Too many edit arguments"
+msgstr "Argumentos de edição em excesso"
+
+msgid "Argument missing after"
+msgstr "Argumento faltando após"
+
+msgid "Garbage after option argument"
+msgstr "Lixo após argumento de opção"
+
+msgid "Too many \"+command\", \"-c command\" or \"--cmd command\" arguments"
+msgstr ""
+"Demasiados argumentos \"+comando\", \"-c comando\" ou \"--cmd comando\""
+
+msgid "Invalid argument for"
+msgstr "Argumento inválido para"
+
+#, c-format
+msgid "%d files to edit\n"
+msgstr "%d arquivos para editar\n"
+
+msgid "netbeans is not supported with this GUI\n"
+msgstr "netbeans não suportado com esta GUI\n"
+
+msgid "'-nb' cannot be used: not enabled at compile time\n"
+msgstr "'-nb' não pode ser usado: não foi ativado na compilação\n"
+
+msgid "This Vim was not compiled with the diff feature."
+msgstr "Este Vim não foi compilado com o recurso diff."
+
+msgid "Attempt to open script file again: \""
+msgstr "Tentando abrir novamente arquivo de script: \""
+
+msgid "Cannot open for reading: \""
+msgstr "Impossível abrir para leitura: \""
+
+msgid "Cannot open for script output: \""
+msgstr "Impossível abrir para transcrição do script: \""
+
+msgid "Vim: Error: Failure to start gvim from NetBeans\n"
+msgstr "Vim: Erro: Não foi possível iniciar o gvim a partir do NetBeans\n"
+
+msgid "Vim: Error: This version of Vim does not run in a Cygwin terminal\n"
+msgstr "Vim: Erro: Esta versão do Vim não executa num terminal Cygwin\n"
+
+msgid "Vim: Warning: Output is not to a terminal\n"
+msgstr "Vim: Aviso: Saída não é um terminal\n"
+
+msgid "Vim: Warning: Input is not from a terminal\n"
+msgstr "Vim: Aviso: Entrada não é de um terminal\n"
+
+msgid "pre-vimrc command line"
+msgstr "linha de comando pré-vimrc"
+
+#, c-format
+msgid "E282: Cannot read from \"%s\""
+msgstr "E282: Impossível ler de \"%s\""
+
+msgid ""
+"\n"
+"More info with: \"vim -h\"\n"
+msgstr ""
+"\n"
+"Mais informações com: \"vim -h\"\n"
+
+msgid "[file ..] edit specified file(s)"
+msgstr "[arquivo ..] abrir o(s) arquivo(s) especificado(s)"
+
+msgid "- read text from stdin"
+msgstr "- ler texto a partir da entrada padrão"
+
+msgid "-t tag edit file where tag is defined"
+msgstr "-t marcador editar arquivo onde o marcador é definido"
+
+msgid "-q [errorfile] edit file with first error"
+msgstr "-q [arq.erro] editar arquivo e abrir no primeiro erro"
+
+msgid ""
+"\n"
+"\n"
+"Usage:"
+msgstr ""
+"\n"
+"\n"
+"uso:"
+
+msgid " vim [arguments] "
+msgstr " vim [argumentos] "
+
+msgid ""
+"\n"
+" or:"
+msgstr ""
+"\n"
+" ou:"
+
+msgid ""
+"\n"
+"Where case is ignored prepend / to make flag upper case"
+msgstr ""
+"\n"
+"Se a caixa é ignorada, insira / antes da opção para torná-la maiúscula"
+
+msgid ""
+"\n"
+"\n"
+"Arguments:\n"
+msgstr ""
+"\n"
+"\n"
+"Argumentos:\n"
+
+msgid "--\t\t\tOnly file names after this"
+msgstr "--\t\t\tApenas nomes de arquivo depois daqui"
+
+msgid "--literal\t\tDon't expand wildcards"
+msgstr "--literal\t\tNão expandir caracteres-curinga"
+
+msgid "-register\t\tRegister this gvim for OLE"
+msgstr "-register\t\tRegistrar o gvim para o OLE"
+
+msgid "-unregister\t\tUnregister gvim for OLE"
+msgstr "-unregister\t\tDesregistrar o gvim para o OLE"
+
+msgid "-g\t\t\tRun using GUI (like \"gvim\")"
+msgstr "-g\t\t\tExecutar a interface gráfica (como \"gvim\")"
+
+msgid "-f or --nofork\tForeground: Don't fork when starting GUI"
+msgstr ""
+"-f ou --nofork\tPrimeiro plano: Não separar a interface gráfica do terminal"
+
+msgid "-v\t\t\tVi mode (like \"vi\")"
+msgstr "-v\t\t\tModo Vi (como \"vi\")"
+
+msgid "-e\t\t\tEx mode (like \"ex\")"
+msgstr "-e\t\t\tModo Ex (como \"ex\")"
+
+msgid "-E\t\t\tImproved Ex mode"
+msgstr "-E\t\t\tMovo Ex melhorado"
+
+msgid "-s\t\t\tSilent (batch) mode (only for \"ex\")"
+msgstr "-s\t\t\tModo silencioso ou \"batch\" (apenas para \"ex\")"
+
+msgid "-d\t\t\tDiff mode (like \"vimdiff\")"
+msgstr "-d\t\t\tModo diff (como \"vimdiff\")"
+
+msgid "-y\t\t\tEasy mode (like \"evim\", modeless)"
+msgstr "-y\t\t\tModo fácil (como \"evim\", o Vim não modal)"
+
+msgid "-R\t\t\tReadonly mode (like \"view\")"
+msgstr "-R\t\t\tmodo somente-leitura (como \"view\")"
+
+msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
+msgstr "-Z\t\t\tmodo restrito (como \"rvim\")"
+
+msgid "-m\t\t\tModifications (writing files) not allowed"
+msgstr "-m\t\t\tNão permitir alterações (gravação de arquivos)"
+
+msgid "-M\t\t\tModifications in text not allowed"
+msgstr "-M\t\t\tNão permitir alterações no texto"
+
+msgid "-b\t\t\tBinary mode"
+msgstr "-b\t\t\tModo binário"
+
+msgid "-l\t\t\tLisp mode"
+msgstr "-l\t\t\tModo Lisp"
+
+msgid "-C\t\t\tCompatible with Vi: 'compatible'"
+msgstr "-C\t\t\tCompatível com o Vi: 'compatible'"
+
+msgid "-N\t\t\tNot fully Vi compatible: 'nocompatible'"
+msgstr "-N\t\t\tNão totalmente compatível com o Vi: 'nocompatible'"
+
+msgid "-V[N][fname]\t\tBe verbose [level N] [log messages to fname]"
+msgstr "-V[N][arq]\t\tDetalhado [nível N] [gravar mensagens em 'arq']"
+
+msgid "-D\t\t\tDebugging mode"
+msgstr "-D\t\t\tModo de depuração (debug)"
+
+msgid "-n\t\t\tNo swap file, use memory only"
+msgstr "-n\t\t\tNão usar arquivo de troca, apenas a memória"
+
+msgid "-r\t\t\tList swap files and exit"
+msgstr "-r\t\t\tListar arquivos de troca e sair"
+
+msgid "-r (with file name)\tRecover crashed session"
+msgstr "-r (nome de arquivo)\tRecuperar sessão perdida"
+
+msgid "-L\t\t\tSame as -r"
+msgstr "-L\t\t\tMesmo que -r"
+
+msgid "-f\t\t\tDon't use newcli to open window"
+msgstr "-f\t\t\tNão usar newcli para abrir janela"
+
+msgid "-dev <device>\t\tUse <device> for I/O"
+msgstr "-dev <dispositivo>\tUsar <dispositivo> para E/S"
+
+msgid "-A\t\t\tStart in Arabic mode"
+msgstr "-A\t\t\tiniciar no modo Ãrabe"
+
+msgid "-H\t\t\tStart in Hebrew mode"
+msgstr "-H\t\t\tIniciar no modo Hebraico"
+
+msgid "-F\t\t\tStart in Farsi mode"
+msgstr "-F\t\t\tIniciar no modo Farsi (persa)"
+
+msgid "-T <terminal>\tSet terminal type to <terminal>"
+msgstr "-T <terminal>\tDefinir tipo de terminal como <terminal>"
+
+msgid "--not-a-term\t\tSkip warning for input/output not being a terminal"
+msgstr "--not-a-term\t\tOmite aviso sobre entrada/saída não ser um terminal"
+
+msgid "--ttyfail\t\tExit if input or output is not a terminal"
+msgstr "--ttyfail\t\tSai se entrada/saída não for um terminal"
+
+msgid "-u <vimrc>\t\tUse <vimrc> instead of any .vimrc"
+msgstr "-u <vimrc>\t\tUsar <vimrc> em vez de qualquer outro .vimrc"
+
+msgid "-U <gvimrc>\t\tUse <gvimrc> instead of any .gvimrc"
+msgstr "-U <gvimrc>\t\tUsar <gvimrc> em vez de qualquer outro .gvimrc"
+
+msgid "--noplugin\t\tDon't load plugin scripts"
+msgstr "--noplugin\t\tNão carregar scripts de plugins"
+
+msgid "-p[N]\t\tOpen N tab pages (default: one for each file)"
+msgstr "-p[N]\t\tAbrir N abas (padrão: uma para cada arquivo)"
+
+msgid "-o[N]\t\tOpen N windows (default: one for each file)"
+msgstr "-o[N]\t\tAbrir N janelas (padrão: uma para cada arquivo)"
+
+msgid "-O[N]\t\tLike -o but split vertically"
+msgstr "-O[N]\t\tComo -o, mas dividindo verticalmente"
+
+msgid "+\t\t\tStart at end of file"
+msgstr "+\t\t\tAbrir no final do arquivo"
+
+msgid "+<lnum>\t\tStart at line <lnum>"
+msgstr "+<núm.l>\t\tComeçar na linha <núm.l>"
+
+msgid "--cmd <command>\tExecute <command> before loading any vimrc file"
+msgstr "--cmd <comando>\tExecutar <comando> antes de carregar qualquer vimrc"
+
+msgid "-c <command>\t\tExecute <command> after loading the first file"
+msgstr ""
+"-c <comando>\t\tExecutar <comando> depois de carregar o primeiro arquivo"
+
+msgid "-S <session>\t\tSource file <session> after loading the first file"
+msgstr ""
+"-S <sessão>\t\tExecutar o arquivo <sessão> depois de carregar o primeiro "
+"arquivo"
+
+msgid "-s <scriptin>\tRead Normal mode commands from file <scriptin>"
+msgstr "-s <script>\t\tLer comandos do modo Normal do arquivo <script>"
+
+msgid "-w <scriptout>\tAppend all typed commands to file <scriptout>"
+msgstr ""
+"-w <script>\t\tAdicionar todos os comandos digitados ao arquivo <script>"
+
+msgid "-W <scriptout>\tWrite all typed commands to file <scriptout>"
+msgstr "-W <script>\t\tGravar todos os comandos digitados no arquivo <script>"
+
+msgid "-x\t\t\tEdit encrypted files"
+msgstr "-x\t\t\tEditar arquivos criptografados"
+
+msgid "-display <display>\tConnect vim to this particular X-server"
+msgstr "-display <display>\tConectar o vim a este servidor X específico"
+
+msgid "-X\t\t\tDo not connect to X server"
+msgstr "-X\t\t\tNão conectar ao servidor X"
+
+msgid "--remote <files>\tEdit <files> in a Vim server if possible"
+msgstr "--remote <arquivos>\tEditar <arquivos> num servidor Vim se possível"
+
+msgid "--remote-silent <files> Same, don't complain if there is no server"
+msgstr "--remote-silent <arqs.> Idem, sem reclamar se não houver servidor"
+
+msgid ""
+"--remote-wait <files> As --remote but wait for files to have been edited"
+msgstr ""
+"--remote-wait <arqs.> Como --remote, mas esperar a edição dos arquivos"
+
+msgid ""
+"--remote-wait-silent <files> Same, don't complain if there is no server"
+msgstr ""
+"--remote-wait-silent <arqs.> Idem, sem reclamar se não houver servidor"
+
+msgid ""
+"--remote-tab[-wait][-silent] <files> As --remote but use tab page per file"
+msgstr ""
+"--remote-tab[-wait][-silent] <arqs.> Como --remote, mas com uma aba por "
+"arquivo"
+
+msgid "--remote-send <keys>\tSend <keys> to a Vim server and exit"
+msgstr "--remote-send <teclas> Enviar <teclas> para um servidor Vim e sair"
+
+msgid "--remote-expr <expr>\tEvaluate <expr> in a Vim server and print result"
+msgstr ""
+"--remote-expr <expr>\tAvaliar <expr> num servidor Vim e exibir o resultado"
+
+msgid "--serverlist\t\tList available Vim server names and exit"
+msgstr "--serverlist\t\tListar servidores Vim disponíveis e sair"
+
+msgid "--servername <name>\tSend to/become the Vim server <name>"
+msgstr "--servername <nome>\tEnviar para/tornar-se o servidor Vim <nome>"
+
+msgid "--startuptime <file>\tWrite startup timing messages to <file>"
+msgstr ""
+"--startuptime <arq.>\tGravar mensagens de cronometragem da inicialização "
+"para <arquivo>"
+
+msgid "-i <viminfo>\t\tUse <viminfo> instead of .viminfo"
+msgstr "-i <viminfo>\t\tUsar <viminfo> em vez do .viminfo normal"
+
+msgid "--clean\t\t'nocompatible', Vim defaults, no plugins, no viminfo"
+msgstr "--clean\t\t'nocompatible', padrões do Vim, sem plugins, sem viminfo"
+
+msgid "-h or --help\tPrint Help (this message) and exit"
+msgstr "-h ou --help\tImprimir a ajuda (esta mensagem) e sair"
+
+msgid "--version\t\tPrint version information and exit"
+msgstr "--version\t\tImprimir informações da versão e sair"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Motif version):\n"
+msgstr ""
+"\n"
+"Argumentos reconhecidos pelo gvim (versão Motif):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (neXtaw version):\n"
+msgstr ""
+"\n"
+"Argumentos reconhecidos pelo gvim (versão neXtaw):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Athena version):\n"
+msgstr ""
+"\n"
+"Argumentos reconhecidos pelo gvim (versão Athena):\n"
+
+msgid "-display <display>\tRun vim on <display>"
+msgstr "-display <display>\tExecutar vim em <display>"
+
+msgid "-iconic\t\tStart vim iconified"
+msgstr "-iconic\t\tIniciar vim iconizado"
+
+msgid "-background <color>\tUse <color> for the background (also: -bg)"
+msgstr "-background <cor>\tUsar <cor> para o fundo (abrev.: -bg)"
+
+msgid "-foreground <color>\tUse <color> for normal text (also: -fg)"
+msgstr "-foreground <cor>\tUsar <cor> para texto normal (abrev.: -fg)"
+
+msgid "-font <font>\t\tUse <font> for normal text (also: -fn)"
+msgstr "-font <fonte>\tUsar <fonte> para texto normal (abrev.: -fn)"
+
+msgid "-boldfont <font>\tUse <font> for bold text"
+msgstr "-boldfont <fonte>\tUsar <fonte> para texto em negrito"
+
+msgid "-italicfont <font>\tUse <font> for italic text"
+msgstr "-italicfont <fonte>\tUsar <fonte> para texto em itálico"
+
+msgid "-geometry <geom>\tUse <geom> for initial geometry (also: -geom)"
+msgstr "-geometry <geom>\tUsar <geom> como geometria inicial (abrev.: -geom)"
+
+msgid "-borderwidth <width>\tUse a border width of <width> (also: -bw)"
+msgstr "-borderwidth <larg.>\tUsar <larg.> como largura da borda (abrev.: -bw)"
+
+msgid "-scrollbarwidth <width> Use a scrollbar width of <width> (also: -sw)"
+msgstr ""
+"-scrollbarwidth <larg.> Usar <larg.> como largura da barra de rolagem "
+"(abrev.: -sw)"
+
+msgid "-menuheight <height>\tUse a menu bar height of <height> (also: -mh)"
+msgstr ""
+"-menuheight <altura>\tUsar <altura> para a barra de menus (abrev.: -mh)"
+
+msgid "-reverse\t\tUse reverse video (also: -rv)"
+msgstr "-reverse\t\tUsar vídeo reverso (abrev.: -rv)"
+
+msgid "+reverse\t\tDon't use reverse video (also: +rv)"
+msgstr "+reverse\t\tNão usar vídeo reverso (abrev.: +rv)"
+
+msgid "-xrm <resource>\tSet the specified resource"
+msgstr "-xrm <recurso>\tDefinir o recurso especificado"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (GTK+ version):\n"
+msgstr ""
+"\n"
+"Argumentos reconhecidos pelo gvim (versão GTK+):\n"
+
+msgid "-display <display>\tRun vim on <display> (also: --display)"
+msgstr "-display <display>\tExecutar vim no <display> (alt.: --display)"
+
+msgid "--role <role>\tSet a unique role to identify the main window"
+msgstr ""
+"--role <papel>\tDefine um papel único para identificar a janela principal"
+
+msgid "--socketid <xid>\tOpen Vim inside another GTK widget"
+msgstr "--socketid <xid>\tAbrir o Vim dentro de outro widget do GTK"
+
+msgid "--echo-wid\t\tMake gvim echo the Window ID on stdout"
+msgstr "--echo-wid\t\tFaz o gvim mostrar o ID da janela na saída padrão"
+
+msgid "-P <parent title>\tOpen Vim inside parent application"
+msgstr "-P <título pai>\tAbrir o Vim dentro de uma aplicação-pai"
+
+msgid "--windowid <HWND>\tOpen Vim inside another win32 widget"
+msgstr "--windowid <HWND>\tAbrir o Vim dentro de outro widget win32"
+
+msgid "No display"
+msgstr "Não há display"
+
+msgid ": Send failed.\n"
+msgstr ": Envio falhou.\n"
+
+msgid ": Send failed. Trying to execute locally\n"
+msgstr ": Envio falhou. Tentando executar localmente\n"
+
+#, c-format
+msgid "%d of %d edited"
+msgstr "%d de %d editados"
+
+msgid "No display: Send expression failed.\n"
+msgstr "Não há display: Envio da expressão falhou.\n"
+
+msgid ": Send expression failed.\n"
+msgstr ": Envio da expressão falhou.\n"
+
+msgid "No marks set"
+msgstr "Nenhuma marca definida"
+
+#, c-format
+msgid "E283: No marks matching \"%s\""
+msgstr "E283: Nenhuma marca coincide com \"%s\""
+
+msgid ""
+"\n"
+"mark line col file/text"
+msgstr ""
+"\n"
+"marc linha col arquivo/texto"
+
+msgid ""
+"\n"
+" jump line col file/text"
+msgstr ""
+"\n"
+"salto linha col arquivo/texto"
+
+msgid ""
+"\n"
+"change line col text"
+msgstr ""
+"\n"
+"alter. linha col texto"
+
+msgid ""
+"\n"
+"# File marks:\n"
+msgstr ""
+"\n"
+"# Marcas nos arquivos:\n"
+
+msgid ""
+"\n"
+"# Jumplist (newest first):\n"
+msgstr ""
+"\n"
+"# Lista de saltos (mais recente primeiro):\n"
+
+msgid ""
+"\n"
+"# History of marks within files (newest to oldest):\n"
+msgstr ""
+"\n"
+"# Histórico de marcas nos arquivos (mais recente primeiro):\n"
+
+msgid "Missing '>'"
+msgstr "'>' faltando"
+
+msgid "E543: Not a valid codepage"
+msgstr "E543: Página de códigos inválida"
+
+msgid "E284: Cannot set IC values"
+msgstr "E284: Não foi possível definir os valores do contexto de entrada"
+
+msgid "E285: Failed to create input context"
+msgstr "E285: Falha ao criar o contexto de entrada"
+
+msgid "E286: Failed to open input method"
+msgstr "E286: Falha ao abrir o método de entrada"
+
+msgid "E287: Warning: Could not set destroy callback to IM"
+msgstr "E287: Aviso: Não foi possível definir o callback de destruição do ME"
+
+msgid "E288: input method doesn't support any style"
+msgstr "E288: o método de entrada não suporta nenhum estilo"
+
+msgid "E289: input method doesn't support my preedit type"
+msgstr "E289: o método de entrada não suporta meu tipo de pré-edição"
+
+msgid "E293: block was not locked"
+msgstr "E293: o bloco não estava travado"
+
+msgid "E294: Seek error in swap file read"
+msgstr "E294: Erro de posicionamento na leitura do arquivo de troca"
+
+msgid "E295: Read error in swap file"
+msgstr "E295: Erro de leitura no arquivo de troca"
+
+msgid "E296: Seek error in swap file write"
+msgstr "E296: Erro de posicionamento na escrita do arquivo de troca"
+
+msgid "E297: Write error in swap file"
+msgstr "E297: Erro de escrita no arquivo de troca"
+
+msgid "E300: Swap file already exists (symlink attack?)"
+msgstr "E300: Arquivo de troca já existe (ataque de symlink?)"
+
+msgid "E298: Didn't get block nr 0?"
+msgstr "E298: Não foi obtido o bloco nº 0?"
+
+msgid "E298: Didn't get block nr 1?"
+msgstr "E298: Não foi obtido o bloco nº 1?"
+
+msgid "E298: Didn't get block nr 2?"
+msgstr "E298: Não foi obtido o bloco nº 2?"
+
+msgid "E843: Error while updating swap file crypt"
+msgstr "E843: Erro ao atualizar criptografia do arquivo de troca"
+
+msgid "E301: Oops, lost the swap file!!!"
+msgstr "E301: Oops, o arquivo de troca foi perdido!!!"
+
+msgid "E302: Could not rename swap file"
+msgstr "E302: Não foi possível renomear o arquivo de troca"
+
+#, c-format
+msgid "E303: Unable to open swap file for \"%s\", recovery impossible"
+msgstr ""
+"E303: Impossível abrir arquivo de troca para \"%s\", recuperação impossível"
+
+msgid "E304: ml_upd_block0(): Didn't get block 0??"
+msgstr "E304: ml_upd_block0(): Não foi obtido o bloco 0??"
+
+#, c-format
+msgid "E305: No swap file found for %s"
+msgstr "E305: Nenhum arquivo de troca encontrado para %s"
+
+msgid "Enter number of swap file to use (0 to quit): "
+msgstr "Insira o número do arquivo de troca a usar (0 para sair): "
+
+#, c-format
+msgid "E306: Cannot open %s"
+msgstr "E306: Impossível abrir %s"
+
+msgid "Unable to read block 0 from "
+msgstr "Impossível ler o bloco 0 de "
+
+msgid ""
+"\n"
+"Maybe no changes were made or Vim did not update the swap file."
+msgstr ""
+"\n"
+"Talvez nenhuma mudança tenha sido feita ou o Vim não tenha atualizado o "
+"arquivo de troca."
+
+msgid " cannot be used with this version of Vim.\n"
+msgstr " não pode ser usado com esta versão do Vim.\n"
+
+msgid "Use Vim version 3.0.\n"
+msgstr "Use o Vim versão 3.0.\n"
+
+#, c-format
+msgid "E307: %s does not look like a Vim swap file"
+msgstr "E307: %s não se parece com um arquivo de troca do Vim"
+
+msgid " cannot be used on this computer.\n"
+msgstr " não pode ser usado neste computador.\n"
+
+msgid "The file was created on "
+msgstr "O arquivo foi criado em "
+
+msgid ""
+",\n"
+"or the file has been damaged."
+msgstr ""
+",\n"
+"ou o arquivo foi danificado."
+
+#, c-format
+msgid ""
+"E833: %s is encrypted and this version of Vim does not support encryption"
+msgstr ""
+"E833: %s está criptografado e esta versão do Vim não suporta criptografia"
+
+msgid " has been damaged (page size is smaller than minimum value).\n"
+msgstr " foi danificado (o tamanho da página é menor que o valor mínimo).\n"
+
+#, c-format
+msgid "Using swap file \"%s\""
+msgstr "Usando arquivo de troca \"%s\""
+
+#, c-format
+msgid "Original file \"%s\""
+msgstr "Arquivo original \"%s\""
+
+msgid "E308: Warning: Original file may have been changed"
+msgstr "E308: Aviso: O arquivo original pode ter sido alterado"
+
+#, c-format
+msgid "Swap file is encrypted: \"%s\""
+msgstr "Arquivo de troca criptografado: \"%s\""
+
+msgid ""
+"\n"
+"If you entered a new crypt key but did not write the text file,"
+msgstr ""
+"\n"
+"Se você inseriu uma nova chave criptográfica sem gravar o arquivo de texto,"
+
+msgid ""
+"\n"
+"enter the new crypt key."
+msgstr ""
+"\n"
+"insira a nova chave criptográfica."
+
+msgid ""
+"\n"
+"If you wrote the text file after changing the crypt key press enter"
+msgstr ""
+"\n"
+"Se você gravou o arquivo após alterar a chave, aperte Enter"
+
+msgid ""
+"\n"
+"to use the same key for text file and swap file"
+msgstr ""
+"\n"
+"para usar a mesma chave para o arquivo de texto e o de troca"
+
+#, c-format
+msgid "E309: Unable to read block 1 from %s"
+msgstr "E309: Impossível ler o bloco 1 de %s"
+
+msgid "???MANY LINES MISSING"
+msgstr "???MUITAS LINHAS FALTANDO"
+
+msgid "???LINE COUNT WRONG"
+msgstr "???NÚMERO DE LINHAS ERRADO"
+
+msgid "???EMPTY BLOCK"
+msgstr "???BLOCO VAZIO"
+
+msgid "???LINES MISSING"
+msgstr "???LINHAS FALTANDO"
+
+#, c-format
+msgid "E310: Block 1 ID wrong (%s not a .swp file?)"
+msgstr "E310: ID do bloco 1 está errado (%s não é um arquivo .swp?)"
+
+msgid "???BLOCK MISSING"
+msgstr "???BLOCO FALTANDO"
+
+msgid "??? from here until ???END lines may be messed up"
+msgstr "??? daqui até ???FIM as linhas podem estar corrompidas"
+
+msgid "??? from here until ???END lines may have been inserted/deleted"
+msgstr "??? daqui até ???FIM linhas podem ter sido inseridas/excluídas"
+
+msgid "???END"
+msgstr "???FIM"
+
+msgid "E311: Recovery Interrupted"
+msgstr "E311: Recuperação interrompida"
+
+msgid ""
+"E312: Errors detected while recovering; look for lines starting with ???"
+msgstr ""
+"E312: Erros detectados durante a recuperação; procure por linhas começando "
+"com ???"
+
+msgid "See \":help E312\" for more information."
+msgstr "Veja \":help E312\" para mais informações."
+
+msgid "Recovery completed. You should check if everything is OK."
+msgstr "Recuperação concluída. Você deve verificar se está tudo certo."
+
+msgid ""
+"\n"
+"(You might want to write out this file under another name\n"
+msgstr ""
+"\n"
+"(Você talvez queira salvar este arquivo com outro nome\n"
+
+msgid "and run diff with the original file to check for changes)"
+msgstr "e execute diff com o arquivo original para verificar mudanças)"
+
+msgid "Recovery completed. Buffer contents equals file contents."
+msgstr "Recuperação completa. Buffer e arquivo têm o mesmo conteúdo."
+
+msgid ""
+"\n"
+"You may want to delete the .swp file now.\n"
+"\n"
+msgstr ""
+"\n"
+"Você pode querer excluir o arquivo .swp agora.\n"
+"\n"
+
+msgid "Using crypt key from swap file for the text file.\n"
+msgstr ""
+"Usando chave criptográfica do arquivo de troca para o arquivo de texto.\n"
+
+msgid "Swap files found:"
+msgstr "Arquivos de troca encontrados:"
+
+msgid " In current directory:\n"
+msgstr " No diretório atual:\n"
+
+msgid " Using specified name:\n"
+msgstr " Usando o nome especificado:\n"
+
+msgid " In directory "
+msgstr " No diretório "
+
+msgid " -- none --\n"
+msgstr " -- nenhum --\n"
+
+msgid " owned by: "
+msgstr " pertence a: "
+
+msgid " dated: "
+msgstr "com data: "
+
+msgid " dated: "
+msgstr " com data de: "
+
+msgid " [from Vim version 3.0]"
+msgstr " [do Vim versão 3.0]"
+
+msgid " [does not look like a Vim swap file]"
+msgstr " [não se parece com um arquivo de troca do Vim]"
+
+msgid " file name: "
+msgstr " nome do arquivo: "
+
+msgid ""
+"\n"
+" modified: "
+msgstr ""
+"\n"
+" modificado: "
+
+msgid "YES"
+msgstr "SIM"
+
+msgid "no"
+msgstr "não"
+
+msgid ""
+"\n"
+" user name: "
+msgstr ""
+"\n"
+" nome de usuário: "
+
+msgid " host name: "
+msgstr " nome do host: "
+
+msgid ""
+"\n"
+" host name: "
+msgstr ""
+"\n"
+" nome do host: "
+
+msgid ""
+"\n"
+" process ID: "
+msgstr ""
+"\n"
+" ID do processo: "
+
+msgid " (still running)"
+msgstr " (ainda executando)"
+
+msgid ""
+"\n"
+" [not usable with this version of Vim]"
+msgstr ""
+"\n"
+" [não pode ser usado com esta versão do Vim]"
+
+msgid ""
+"\n"
+" [not usable on this computer]"
+msgstr ""
+"\n"
+" [não pode ser usado neste computador]"
+
+msgid " [cannot be read]"
+msgstr " [não pode ser lido]"
+
+msgid " [cannot be opened]"
+msgstr " [não pode ser aberto]"
+
+msgid "E313: Cannot preserve, there is no swap file"
+msgstr "E313: Impossível preservar, não há um arquivo de troca"
+
+msgid "File preserved"
+msgstr "Arquivo preservado"
+
+msgid "E314: Preserve failed"
+msgstr "E314: Preservação falhou"
+
+#, c-format
+msgid "E315: ml_get: invalid lnum: %ld"
+msgstr "E315: ml_get: número de linha inválido: %ld"
+
+#, c-format
+msgid "E316: ml_get: cannot find line %ld"
+msgstr "E316: ml_get: linha %ld não encontrada"
+
+msgid "E317: pointer block id wrong 3"
+msgstr "E317: id do bloco de ponteiros incorreto: 3"
+
+msgid "stack_idx should be 0"
+msgstr "stack_idx deveria ser 0"
+
+msgid "E318: Updated too many blocks?"
+msgstr "E318: Foram atualizados blocos demais?"
+
+msgid "E317: pointer block id wrong 4"
+msgstr "E317: id do bloco de ponteiros incorreto: 4"
+
+msgid "deleted block 1?"
+msgstr "bloco 1 apagado?"
+
+#, c-format
+msgid "E320: Cannot find line %ld"
+msgstr "E320: Linha %ld não encontrada"
+
+msgid "E317: pointer block id wrong"
+msgstr "E317: id do bloco de ponteiros incorreto"
+
+msgid "pe_line_count is zero"
+msgstr "pe_line_count é zero"
+
+#, c-format
+msgid "E322: line number out of range: %ld past the end"
+msgstr "E322: número da linha fora dos limites: %ld além do fim"
+
+#, c-format
+msgid "E323: line count wrong in block %ld"
+msgstr "E323: número de linhas incorreto no bloco %ld"
+
+msgid "Stack size increases"
+msgstr "Aumenta o tamanho da pilha"
+
+msgid "E317: pointer block id wrong 2"
+msgstr "E317: id do bloco de ponteiros incorreto: 2"
+
+#, c-format
+msgid "E773: Symlink loop for \"%s\""
+msgstr "E773: Links simbólicos cíclicos para \"%s\""
+
+msgid "E325: ATTENTION"
+msgstr "E325: ATENÇÃO"
+
+msgid ""
+"\n"
+"Found a swap file by the name \""
+msgstr ""
+"\n"
+"Foi encontrado um arquivo de troca de nome \""
+
+msgid "While opening file \""
+msgstr "Ao abrir o arquivo \""
+
+msgid " NEWER than swap file!\n"
+msgstr " MAIS NOVO que o arquivo de troca!\n"
+
+msgid ""
+"\n"
+"(1) Another program may be editing the same file. If this is the case,\n"
+" be careful not to end up with two different instances of the same\n"
+" file when making changes. Quit, or continue with caution.\n"
+msgstr ""
+"\n"
+"(1) Outro programa pode estar editando o mesmo arquivo. Se for esse\n"
+" o caso, cuidado para não acabar com duas versões do mesmo arquivo\n"
+" ao fazer alterações. Saia, ou continue com cuidado.\n"
+
+msgid "(2) An edit session for this file crashed.\n"
+msgstr "(2) Uma sessão de edição para esse arquivo travou.\n"
+
+msgid " If this is the case, use \":recover\" or \"vim -r "
+msgstr " Se for esse o caso, use \":recover\" ou \"vim -r "
+
+msgid ""
+"\"\n"
+" to recover the changes (see \":help recovery\").\n"
+msgstr ""
+"\"\n"
+" para recuperar as alterações (veja \":help recovery\").\n"
+
+msgid " If you did this already, delete the swap file \""
+msgstr " Se você já vez isso, exclua o arquivo de troca \""
+
+msgid ""
+"\"\n"
+" to avoid this message.\n"
+msgstr ""
+"\"\n"
+" para evitar esta mensagem.\n"
+
+msgid "Swap file \""
+msgstr "O arquivo de troca \""
+
+msgid "\" already exists!"
+msgstr "\" já existe!"
+
+msgid "VIM - ATTENTION"
+msgstr "VIM - ATENÇÃO"
+
+msgid "Swap file already exists!"
+msgstr "O arquivo de troca já existe!"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"&Abrir somente-leitura\n"
+"&Editar mesmo assim\n"
+"&Recuperar\n"
+"&Sair\n"
+"&Cancelar"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Delete it\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"&Abrir somente-leitura\n"
+"&Editar mesmo assim\n"
+"&Recuperar\n"
+"E&xcluí-lo\n"
+"&Sair\n"
+"&Cancelar"
+
+msgid "E326: Too many swap files found"
+msgstr "E326: Foram encontrados arquivos de troca demais"
+
+msgid "E327: Part of menu-item path is not sub-menu"
+msgstr "E327: Parte do caminho do item do menu não é um submenu"
+
+msgid "E328: Menu only exists in another mode"
+msgstr "E328: Menu só existe em outro modo"
+
+#, c-format
+msgid "E329: No menu \"%s\""
+msgstr "E329: Não há o menu \"%s\""
+
+msgid "E792: Empty menu name"
+msgstr "E792: Menu com nome vazio"
+
+msgid "E330: Menu path must not lead to a sub-menu"
+msgstr "E330: Caminho do menu não deve levar a um submenu"
+
+msgid "E331: Must not add menu items directly to menu bar"
+msgstr "E331: Itens não devem ser adicionados diretamente à barra de menus"
+
+msgid "E332: Separator cannot be part of a menu path"
+msgstr "E332: Um separador não pode ser parte de um caminho de menu"
+
+msgid ""
+"\n"
+"--- Menus ---"
+msgstr ""
+"\n"
+"--- Menus ---"
+
+msgid "Tear off this menu"
+msgstr "Destacar este menu"
+
+msgid "E333: Menu path must lead to a menu item"
+msgstr "E333: Caminho de menu deve levar a um item de menu"
+
+#, c-format
+msgid "E334: Menu not found: %s"
+msgstr "E334: Menu não encontrado: %s"
+
+#, c-format
+msgid "E335: Menu not defined for %s mode"
+msgstr "E335: Menu não definido para o modo %s"
+
+msgid "E336: Menu path must lead to a sub-menu"
+msgstr "E336: O caminho do menu deve levar a um submenu"
+
+msgid "E337: Menu not found - check menu names"
+msgstr "E337: Menu não encontrado - verifique os nomes dos menus"
+
+#, c-format
+msgid "Error detected while processing %s:"
+msgstr "Erro detectado ao processar %s:"
+
+#, c-format
+msgid "line %4ld:"
+msgstr "linha %4ld:"
+
+#, c-format
+msgid "E354: Invalid register name: '%s'"
+msgstr "E354: Nome de registrador inválido: '%s'"
+
+msgid "Messages maintainer: Bram Moolenaar <Bram@vim.org>"
+msgstr "Tradutor das mensagens: Eduardo Dobay <edudobay@gmail.com>"
+
+msgid "Interrupt: "
+msgstr "Interrupção: "
+
+msgid "Press ENTER or type command to continue"
+msgstr "Aperte ENTER ou digite um comando para continuar"
+
+#, c-format
+msgid "%s line %ld"
+msgstr "%s, linha %ld"
+
+msgid "-- More --"
+msgstr "-- Mais --"
+
+msgid " SPACE/d/j: screen/page/line down, b/u/k: up, q: quit "
+msgstr " ESPAÇO/d/j: tela/página/linha abaixo, b/u/k: acima, q: sair "
+
+msgid "Question"
+msgstr "Questão"
+
+msgid ""
+"&Yes\n"
+"&No"
+msgstr ""
+"&Sim\n"
+"&Não"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"Save &All\n"
+"&Discard All\n"
+"&Cancel"
+msgstr ""
+"&Sim\n"
+"&Não\n"
+"Salvar &tudo\n"
+"&Descartar tudo\n"
+"&Cancelar"
+
+msgid "Select Directory dialog"
+msgstr "Seletor de diretório"
+
+msgid "Save File dialog"
+msgstr "Salvar arquivo"
+
+msgid "Open File dialog"
+msgstr "Abrir arquivo"
+
+msgid "E338: Sorry, no file browser in console mode"
+msgstr "E338: Desculpe, não há um seletor de arquivos no modo console"
+
+msgid "E766: Insufficient arguments for printf()"
+msgstr "E766: Argumentos insuficientes para printf()"
+
+msgid "E807: Expected Float argument for printf()"
+msgstr "E807: Era esperado um argumento Float para printf()"
+
+msgid "E767: Too many arguments to printf()"
+msgstr "E767: Argumentos demais para printf()"
+
+msgid "W10: Warning: Changing a readonly file"
+msgstr "W10: Aviso: Modificando um arquivo somente-leitura"
+
+msgid "Type number and <Enter> or click with mouse (empty cancels): "
+msgstr ""
+"Digite um número e <Enter> ou clique com o mouse (deixe em branco para "
+"cancelar): "
+
+msgid "Type number and <Enter> (empty cancels): "
+msgstr "Digite um número e <Enter> (deixe em branco para cancelar): "
+
+msgid "1 more line"
+msgstr "1 linha a mais"
+
+msgid "1 line less"
+msgstr "1 linha a menos"
+
+#, c-format
+msgid "%ld more lines"
+msgstr "%ld linhas a mais"
+
+#, c-format
+msgid "%ld fewer lines"
+msgstr "%ld linhas a menos"
+
+msgid " (Interrupted)"
+msgstr " (Interrompido)"
+
+msgid "Beep!"
+msgstr "Bip!"
+
+msgid "ERROR: "
+msgstr "ERRO: "
+
+#, c-format
+msgid ""
+"\n"
+"[bytes] total alloc-freed %lu-%lu, in use %lu, peak use %lu\n"
+msgstr ""
+"\n"
+"[bytes] total alocado-liberado %lu-%lu, em uso %lu, pico %lu\n"
+
+#, c-format
+msgid ""
+"[calls] total re/malloc()'s %lu, total free()'s %lu\n"
+"\n"
+msgstr ""
+"[total de chamadas] re/malloc() %lu, free() %lu\n"
+"\n"
+
+msgid "E340: Line is becoming too long"
+msgstr "E340: A linha está tornando-se muito longa"
+
+#, c-format
+msgid "E341: Internal error: lalloc(%ld, )"
+msgstr "E341: Erro interno: lalloc(%ld, )"
+
+#, c-format
+msgid "E342: Out of memory! (allocating %lu bytes)"
+msgstr "E342: Memória esgotada! (ao alocar %lu bytes)"
+
+#, c-format
+msgid "Calling shell to execute: \"%s\""
+msgstr "Chamando o shell para executar: \"%s\""
+
+msgid "E545: Missing colon"
+msgstr "E545: Dois-pontos faltando"
+
+msgid "E546: Illegal mode"
+msgstr "E546: Modo de operação inválido"
+
+msgid "E547: Illegal mouseshape"
+msgstr "E547: 'mouseshape' inválido"
+
+msgid "E548: digit expected"
+msgstr "E548: era esperado um algarismo"
+
+msgid "E549: Illegal percentage"
+msgstr "E549: Porcentagem inválida"
+
+msgid "E854: path too long for completion"
+msgstr "E854: caminho muito longo para completar"
+
+#, c-format
+msgid ""
+"E343: Invalid path: '**[number]' must be at the end of the path or be "
+"followed by '%s'."
+msgstr ""
+"E343: Caminho inválido: '**[número]' deve estar no final do caminho ou "
+"seguido de '%s'."
+
+#, c-format
+msgid "E344: Can't find directory \"%s\" in cdpath"
+msgstr "E344: Diretório \"%s\" não encontrado em 'cdpath'"
+
+#, c-format
+msgid "E345: Can't find file \"%s\" in path"
+msgstr "E345: Arquivo \"%s\" não encontrado em 'path'"
+
+#, c-format
+msgid "E346: No more directory \"%s\" found in cdpath"
+msgstr "E346: Mais nenhum diretório \"%s\" encontrado em 'cdpath'"
+
+#, c-format
+msgid "E347: No more file \"%s\" found in path"
+msgstr "E347: Mais nenhum arquivo \"%s\" encontrado em 'path'"
+
+#, c-format
+msgid "E668: Wrong access mode for NetBeans connection info file: \"%s\""
+msgstr ""
+"E668: Modo de acesso errado para o arquivo de informação de conexão do "
+"NetBeans: \"%s\""
+
+#, c-format
+msgid "E658: NetBeans connection lost for buffer %ld"
+msgstr "E658: Conexão com o NetBeans perdida para o buffer %ld"
+
+msgid "E838: netbeans is not supported with this GUI"
+msgstr "E838: netbeans não suportado com esta GUI"
+
+msgid "E511: netbeans already connected"
+msgstr "E511: netbeans já conectado"
+
+#, c-format
+msgid "E505: %s is read-only (add ! to override)"
+msgstr "E505: %s é somente-leitura (adicione ! para forçar)"
+
+msgid "E349: No identifier under cursor"
+msgstr "E349: Nenhum identificador sob o cursor"
+
+msgid "E774: 'operatorfunc' is empty"
+msgstr "E774: 'operatorfunc' está vazio"
+
+msgid "E775: Eval feature not available"
+msgstr "E775: O recurso eval não está disponível"
+
+msgid "Warning: terminal cannot highlight"
+msgstr "Aviso: o terminal não suporta destaque no modo visual"
+
+msgid "E348: No string under cursor"
+msgstr "E348: Nenhuma cadeia de caracteres sob o cursor"
+
+msgid "E352: Cannot erase folds with current 'foldmethod'"
+msgstr "E352: Impossível eliminar dobras com o 'foldmethod' atual"
+
+msgid "E664: changelist is empty"
+msgstr "E664: lista de modificações está vazia"
+
+msgid "E662: At start of changelist"
+msgstr "E662: No início da lista de modificações"
+
+msgid "E663: At end of changelist"
+msgstr "E663: No final da lista de modificações"
+
+msgid "Type :qa! and press <Enter> to abandon all changes and exit Vim"
+msgstr ""
+"Digite :qa! e aperte <Enter> para abandonar as alterações e sair do Vim"
+
+#, c-format
+msgid "1 line %sed 1 time"
+msgstr "1 linha %sada 1 vez"
+
+#, c-format
+msgid "1 line %sed %d times"
+msgstr "1 linha %sada %d vezes"
+
+#, c-format
+msgid "%ld lines %sed 1 time"
+msgstr "%ld linhas %sadas 1 vez"
+
+#, c-format
+msgid "%ld lines %sed %d times"
+msgstr "%ld linhas %sadas %d vezes"
+
+#, c-format
+msgid "%ld lines to indent... "
+msgstr "%ld linhas para indentar... "
+
+msgid "1 line indented "
+msgstr "1 linha indentada "
+
+#, c-format
+msgid "%ld lines indented "
+msgstr "%ld linhas indentadas "
+
+msgid "E748: No previously used register"
+msgstr "E748: Nenhum registrador foi anteriormente utilizado"
+
+msgid "cannot yank; delete anyway"
+msgstr "impossível copiar; excluir assim mesmo"
+
+msgid "1 line changed"
+msgstr "1 linha alterada"
+
+#, c-format
+msgid "%ld lines changed"
+msgstr "%ld linhas alteradas"
+
+#, c-format
+msgid "freeing %ld lines"
+msgstr "liberando %ld linhas"
+
+#, c-format
+msgid " into \"%c"
+msgstr " para \"%c"
+
+#, c-format
+msgid "block of 1 line yanked%s"
+msgstr "bloco de 1 linha copiado%s"
+
+#, c-format
+msgid "1 line yanked%s"
+msgstr "1 linha copiada%s"
+
+#, c-format
+msgid "block of %ld lines yanked%s"
+msgstr "bloco de %ld linhas copiado%s"
+
+#, c-format
+msgid "%ld lines yanked%s"
+msgstr "%ld linhas copiadas%s"
+
+#, c-format
+msgid "E353: Nothing in register %s"
+msgstr "E353: Não há nada no registrador %s"
+
+msgid ""
+"\n"
+"--- Registers ---"
+msgstr ""
+"\n"
+"--- Registradores ---"
+
+msgid "Illegal register name"
+msgstr "Nome de registrador inválido"
+
+msgid ""
+"\n"
+"# Registers:\n"
+msgstr ""
+"\n"
+"# Registradores:\n"
+
+#, c-format
+msgid "E574: Unknown register type %d"
+msgstr "E574: Registrador de tipo desconhecido %d"
+
+msgid ""
+"E883: search pattern and expression register may not contain two or more "
+"lines"
+msgstr ""
+"E883: padrão de busca e registro de expressões não podem conter duas ou mais "
+"linhas"
+
+#, c-format
+msgid "%ld Cols; "
+msgstr "%ld colunas; "
+
+#, c-format
+msgid "Selected %s%ld of %ld Lines; %lld of %lld Words; %lld of %lld Bytes"
+msgstr ""
+"Selecionadas %s%ld de %ld linhas; %lld de %lld palavras; %lld de %lld bytes"
+
+#, c-format
+msgid ""
+"Selected %s%ld of %ld Lines; %lld of %lld Words; %lld of %lld Chars; %lld of "
+"%lld Bytes"
+msgstr ""
+"Selecionadas %s%ld de %ld linhas; %lld de %lld palavras; %lld de %lld "
+"caracteres; %lld de %lld bytes"
+
+#, c-format
+msgid "Col %s of %s; Line %ld of %ld; Word %lld of %lld; Byte %lld of %lld"
+msgstr ""
+"Coluna %s de %s; linha %ld de %ld; palavra %lld de %lld; byte %lld de %lld"
+
+#, c-format
+msgid ""
+"Col %s of %s; Line %ld of %ld; Word %lld of %lld; Char %lld of %lld; Byte "
+"%lld of %lld"
+msgstr ""
+"Coluna %s de %s; linha %ld de %ld; palavra %lld de %lld; caractere %lld de "
+"%lld; byte %lld de %lld"
+
+#, c-format
+msgid "(+%ld for BOM)"
+msgstr "(+%ld para BOM)"
+
+msgid "Thanks for flying Vim"
+msgstr "Obrigado por voar com o Vim"
+
+msgid "E518: Unknown option"
+msgstr "E518: Opção desconhecida"
+
+msgid "E519: Option not supported"
+msgstr "E519: Opção não suportada"
+
+msgid "E520: Not allowed in a modeline"
+msgstr "E520: Não permitido em modelines"
+
+msgid "E846: Key code not set"
+msgstr "E846: Código de tecla não definido"
+
+msgid "E521: Number required after ="
+msgstr "E521: Número requerido após ="
+
+msgid "E522: Not found in termcap"
+msgstr "E522: Não encontrado no termcap"
+
+#, c-format
+msgid "E539: Illegal character <%s>"
+msgstr "E539: Caractere ilegal <%s>"
+
+#, c-format
+msgid "For option %s"
+msgstr "Para opção %s"
+
+msgid "E529: Cannot set 'term' to empty string"
+msgstr "E529: 'term' não pode ser uma string vazia"
+
+msgid "E530: Cannot change term in GUI"
+msgstr "E530: term não pode ser alterado na interface gráfica"
+
+msgid "E531: Use \":gui\" to start the GUI"
+msgstr "E531: Use \":gui\" para iniciar a interface gráfica"
+
+msgid "E589: 'backupext' and 'patchmode' are equal"
+msgstr "E589: 'backupext' e 'patchmode' são iguais"
+
+msgid "E834: Conflicts with value of 'listchars'"
+msgstr "E834: Conflita com valor de 'listchars'"
+
+msgid "E835: Conflicts with value of 'fillchars'"
+msgstr "E835: Conflita com valor de 'fillchars'"
+
+msgid "E617: Cannot be changed in the GTK+ 2 GUI"
+msgstr "E617: Não pode ser modificado na interface GTK+ 2"
+
+msgid "E524: Missing colon"
+msgstr "E524: Dois-pontos faltando"
+
+msgid "E525: Zero length string"
+msgstr "E525: Cadeia de comprimento zero"
+
+#, c-format
+msgid "E526: Missing number after <%s>"
+msgstr "E526: Número faltando após <%s>"
+
+msgid "E527: Missing comma"
+msgstr "E527: Vírgula faltando"
+
+msgid "E528: Must specify a ' value"
+msgstr "E528: É necessário especificar um valor para '"
+
+msgid "E595: contains unprintable or wide character"
+msgstr "E595: contém caracteres não-imprimíveis ou largos"
+
+msgid "E596: Invalid font(s)"
+msgstr "E596: Fonte(s) inválida(s)"
+
+msgid "E597: can't select fontset"
+msgstr "E597: impossível selecionar conjunto de fontes"
+
+msgid "E598: Invalid fontset"
+msgstr "E598: Conjunto de fontes inválido"
+
+msgid "E533: can't select wide font"
+msgstr "E533: impossível selecionar fonte de caracteres largos"
+
+msgid "E534: Invalid wide font"
+msgstr "E534: Fonte de caracteres largos inválida"
+
+#, c-format
+msgid "E535: Illegal character after <%c>"
+msgstr "E535: Caractere inválido após <%c>"
+
+msgid "E536: comma required"
+msgstr "E536: vírgula requerida"
+
+#, c-format
+msgid "E537: 'commentstring' must be empty or contain %s"
+msgstr "E537: 'commentstring' deve estar vazia ou conter %s"
+
+msgid "E538: No mouse support"
+msgstr "E538: Não há suporte a mouse"
+
+msgid "E540: Unclosed expression sequence"
+msgstr "E540: Expressão não terminada com '}'"
+
+msgid "E541: too many items"
+msgstr "E541: itens demais"
+
+msgid "E542: unbalanced groups"
+msgstr "E542: parênteses desequilibrados"
+
+msgid "E946: Cannot make a terminal with running job modifiable"
+msgstr "E946: Um terminal com trabalho em execução não pode ser modificável"
+
+msgid "E590: A preview window already exists"
+msgstr "E590: Já existe uma janela de visualização"
+
+msgid "W17: Arabic requires UTF-8, do ':set encoding=utf-8'"
+msgstr "W17: Ãrabe requer UTF-8; digite ':set encoding=utf-8'"
+
+#, c-format
+msgid "E593: Need at least %d lines"
+msgstr "E593: São necessárias pelo menos %d linhas"
+
+#, c-format
+msgid "E594: Need at least %d columns"
+msgstr "E594: São necessárias pelo menos %d colunas"
+
+#, c-format
+msgid "E355: Unknown option: %s"
+msgstr "E355: Opção desconhecida: %s"
+
+#, c-format
+msgid "E521: Number required: &%s = '%s'"
+msgstr "E521: Número requerido: &%s = '%s'"
+
+msgid ""
+"\n"
+"--- Terminal codes ---"
+msgstr ""
+"\n"
+"--- Códigos de terminal ---"
+
+msgid ""
+"\n"
+"--- Global option values ---"
+msgstr ""
+"\n"
+"--- Valores de opções globais ---"
+
+msgid ""
+"\n"
+"--- Local option values ---"
+msgstr ""
+"\n"
+"--- Valores de opções locais ---"
+
+msgid ""
+"\n"
+"--- Options ---"
+msgstr ""
+"\n"
+"--- Opções ---"
+
+msgid "E356: get_varp ERROR"
+msgstr "E356: ERRO em get_varp"
+
+#, c-format
+msgid "E357: 'langmap': Matching character missing for %s"
+msgstr "E357: 'langmap': Falta um caractere para corresponder com %s"
+
+#, c-format
+msgid "E358: 'langmap': Extra characters after semicolon: %s"
+msgstr "E358: 'langmap': Caracteres a mais após ponto-e-vírgula: %s"
+
+msgid "cannot open "
+msgstr "impossível abrir "
+
+msgid "VIM: Can't open window!\n"
+msgstr "VIM: Não foi possível abrir a janela!\n"
+
+msgid "Need Amigados version 2.04 or later\n"
+msgstr "Necessário Amigados versão 2.04 ou mais nova\n"
+
+#, c-format
+msgid "Need %s version %ld\n"
+msgstr "Necessário %s versão %ld\n"
+
+msgid "Cannot open NIL:\n"
+msgstr "Impossível abrir NIL:\n"
+
+msgid "Cannot create "
+msgstr "Impossível criar "
+
+#, c-format
+msgid "Vim exiting with %d\n"
+msgstr "Vim terminando com %d\n"
+
+msgid "cannot change console mode ?!\n"
+msgstr "impossível alterar o modo de console ?!\n"
+
+msgid "mch_get_shellsize: not a console??\n"
+msgstr "mch_get_shellsize: não é um console??\n"
+
+msgid "E360: Cannot execute shell with -f option"
+msgstr "E360: Impossível executar shell com opção -f"
+
+msgid "Cannot execute "
+msgstr "Não é possível executar "
+
+msgid "shell "
+msgstr "shell "
+
+msgid " returned\n"
+msgstr " devolveu\n"
+
+msgid "ANCHOR_BUF_SIZE too small."
+msgstr "ANCHOR_BUF_SIZE pequeno demais."
+
+msgid "I/O ERROR"
+msgstr "ERRO DE E/S"
+
+msgid "Message"
+msgstr "Mensagem"
+
+msgid "E237: Printer selection failed"
+msgstr "E237: Seleção da impressora falhou"
+
+#, c-format
+msgid "to %s on %s"
+msgstr "para %s em %s"
+
+#, c-format
+msgid "E613: Unknown printer font: %s"
+msgstr "E613: Fonte de impressão desconhecida: %s"
+
+#, c-format
+msgid "E238: Print error: %s"
+msgstr "E238: Erro de impressão: %s"
+
+#, c-format
+msgid "Printing '%s'"
+msgstr "Imprimindo '%s'"
+
+#, c-format
+msgid "E244: Illegal charset name \"%s\" in font name \"%s\""
+msgstr "E244: Conjunto de caracteres \"%s\" inválido no nome da fonte \"%s\""
+
+#, c-format
+msgid "E244: Illegal quality name \"%s\" in font name \"%s\""
+msgstr "E244: Qualidade \"%s\" inválida no nome da fonte \"%s\""
+
+#, c-format
+msgid "E245: Illegal char '%c' in font name \"%s\""
+msgstr "E245: Caractere '%c' inválido no nome da fonte \"%s\""
+
+#, c-format
+msgid "Opening the X display took %ld msec"
+msgstr "Abertura do display X demorou %ld ms"
+
+msgid ""
+"\n"
+"Vim: Got X error\n"
+msgstr ""
+"\n"
+"Vim: Recebido erro do X\n"
+
+msgid "Testing the X display failed"
+msgstr "Teste do display X falhou"
+
+msgid "Opening the X display timed out"
+msgstr "Abertura do display X excedeu o tempo-limite"
+
+msgid ""
+"\n"
+"Could not get security context for "
+msgstr ""
+"\n"
+"Não foi possível obter o contexto de segurança para "
+
+msgid ""
+"\n"
+"Could not set security context for "
+msgstr ""
+"\n"
+"Não foi possível definir o contexto de segurança para "
+
+#, c-format
+msgid "Could not set security context %s for %s"
+msgstr "Não foi possível definir o contexto de segurança %s para %s"
+
+#, c-format
+msgid "Could not get security context %s for %s. Removing it!"
+msgstr "Não foi possível obter o contexto de segurança %s para %s. Removendo!"
+
+msgid ""
+"\n"
+"Cannot execute shell sh\n"
+msgstr ""
+"\n"
+"Não foi possível executar o shell sh\n"
+
+msgid ""
+"\n"
+"shell returned "
+msgstr ""
+"\n"
+"o shell devolveu "
+
+msgid ""
+"\n"
+"Cannot create pipes\n"
+msgstr ""
+"\n"
+"Impossível criar pipes de comunicação\n"
+
+msgid ""
+"\n"
+"Cannot fork\n"
+msgstr ""
+"\n"
+"Impossível realizar bifurcação de processo\n"
+
+msgid ""
+"\n"
+"Cannot execute shell "
+msgstr ""
+"\n"
+"Não foi possível executar o shell "
+
+msgid ""
+"\n"
+"Command terminated\n"
+msgstr ""
+"\n"
+"Comando interrompido\n"
+
+msgid "XSMP lost ICE connection"
+msgstr "XSMP perdeu a conexão ICE"
+
+#, c-format
+msgid "dlerror = \"%s\""
+msgstr "dlerror = \"%s\""
+
+msgid "Opening the X display failed"
+msgstr "Abertura do display X falhou"
+
+msgid "XSMP handling save-yourself request"
+msgstr "XSMP tratando pedido de auto-salvamento"
+
+msgid "XSMP opening connection"
+msgstr "XSMP abrindo conexão"
+
+msgid "XSMP ICE connection watch failed"
+msgstr "Falha no vigia de conexões ICE do XSMP"
+
+#, c-format
+msgid "XSMP SmcOpenConnection failed: %s"
+msgstr "Falha em SmcOpenConnection do XSMP: %s"
+
+msgid "At line"
+msgstr "Na linha"
+
+msgid "Could not load vim32.dll!"
+msgstr "Não foi possível carregar vim32.dll!"
+
+msgid "VIM Error"
+msgstr "Erro do VIM"
+
+msgid "Could not fix up function pointers to the DLL!"
+msgstr "Não foi possível definir os ponteiros de função para a DLL!"
+
+#, c-format
+msgid "Vim: Caught %s event\n"
+msgstr "Vim: Evento %s interceptado\n"
+
+msgid "close"
+msgstr "de fechamento"
+
+msgid "logoff"
+msgstr "de logoff"
+
+msgid "shutdown"
+msgstr "de desligamento"
+
+msgid "E371: Command not found"
+msgstr "E371: Comando não encontrado"
+
+msgid ""
+"VIMRUN.EXE not found in your $PATH.\n"
+"External commands will not pause after completion.\n"
+"See :help win32-vimrun for more information."
+msgstr ""
+"VIMRUN.EXE não foi encontrado no seu $PATH.\n"
+"Comandos externos não farão uma pausa ao terminar.\n"
+"Veja :help win32-vimrun para mais informações."
+
+msgid "Vim Warning"
+msgstr "Alerta do Vim"
+
+#, c-format
+msgid "shell returned %d"
+msgstr "shell devolveu %d"
+
+#, c-format
+msgid "E372: Too many %%%c in format string"
+msgstr "E372: Muitos %%%c na especificação do formato"
+
+#, c-format
+msgid "E373: Unexpected %%%c in format string"
+msgstr "E373: %%%c inesperado na especificação do formato"
+
+msgid "E374: Missing ] in format string"
+msgstr "E374: ] faltando na especificação do formato"
+
+#, c-format
+msgid "E375: Unsupported %%%c in format string"
+msgstr "E375: %%%c não suportado na especificação de formato"
+
+#, c-format
+msgid "E376: Invalid %%%c in format string prefix"
+msgstr "E376: %%%c inválido no prefixo da especificação de formato"
+
+#, c-format
+msgid "E377: Invalid %%%c in format string"
+msgstr "E377: %%%c inválido na especificação de formato"
+
+msgid "E378: 'errorformat' contains no pattern"
+msgstr "E378: 'errorformat' não contém nenhum padrão"
+
+msgid "E379: Missing or empty directory name"
+msgstr "E379: O nome do diretório está faltando ou vazio"
+
+msgid "E553: No more items"
+msgstr "E553: Não há mais itens"
+
+msgid "E924: Current window was closed"
+msgstr "E924: Janela atual foi fechada"
+
+msgid "E925: Current quickfix was changed"
+msgstr "E925: Quickfix atual foi alterada"
+
+msgid "E926: Current location list was changed"
+msgstr "E926: Lista de locais atual foi alterada"
+
+#, c-format
+msgid "(%d of %d)%s%s: "
+msgstr "(%d de %d)%s%s: "
+
+msgid " (line deleted)"
+msgstr " (linha excluída)"
+
+#, c-format
+msgid "%serror list %d of %d; %d errors "
+msgstr "%slista de erros %d de %d; %d erros "
+
+msgid "E380: At bottom of quickfix stack"
+msgstr "E380: No final da pilha do quickfix"
+
+msgid "E381: At top of quickfix stack"
+msgstr "E381: No topo da pilha do quickfix"
+
+msgid "No entries"
+msgstr "Sem entradas"
+
+msgid "Error file"
+msgstr "Arquivo de erro"
+
+msgid "E683: File name missing or invalid pattern"
+msgstr "E683: Nome de arquivo faltando ou padrão inválido"
+
+#, c-format
+msgid "Cannot open file \"%s\""
+msgstr "Impossível abrir arquivo \"%s\""
+
+msgid "E681: Buffer is not loaded"
+msgstr "E681: Buffer não está carregado"
+
+msgid "E777: String or List expected"
+msgstr "E777: Era esperada uma String ou uma Lista"
+
+#, c-format
+msgid "E369: invalid item in %s%%[]"
+msgstr "E369: item inválido em %s%%[]"
+
+#, c-format
+msgid "E769: Missing ] after %s["
+msgstr "E769: ] faltando após %s["
+
+msgid "E944: Reverse range in character class"
+msgstr "E944: Intervalo invertido em classe de caracteres"
+
+msgid "E945: Range too large in character class"
+msgstr "E945: Intervalo muito grande em classe de caracteres"
+
+#, c-format
+msgid "E53: Unmatched %s%%("
+msgstr "E53: %s%%( sem correspondente"
+
+#, c-format
+msgid "E54: Unmatched %s("
+msgstr "E54: %s( sem correspondente"
+
+#, c-format
+msgid "E55: Unmatched %s)"
+msgstr "E55: %s) sem correspondente"
+
+msgid "E66: \\z( not allowed here"
+msgstr "E66: \\z( não é permitido aqui"
+
+msgid "E67: \\z1 - \\z9 not allowed here"
+msgstr "E67: \\z1 e cia. não são permitidos aqui"
+
+#, c-format
+msgid "E69: Missing ] after %s%%["
+msgstr "E69: ] faltando após %s%%["
+
+#, c-format
+msgid "E70: Empty %s%%[]"
+msgstr "E70: %s%%[] vazio"
+
+msgid "E65: Illegal back reference"
+msgstr "E65: Retrorreferência inválida"
+
+msgid "E339: Pattern too long"
+msgstr "E339: Padrão longo demais"
+
+msgid "E50: Too many \\z("
+msgstr "E50: Muitos \\z("
+
+#, c-format
+msgid "E51: Too many %s("
+msgstr "E51: Muitos %s("
+
+msgid "E52: Unmatched \\z("
+msgstr "E52: \\z( sem correspondente"
+
+#, c-format
+msgid "E59: invalid character after %s@"
+msgstr "E59: caractere inválido após %s@"
+
+#, c-format
+msgid "E60: Too many complex %s{...}s"
+msgstr "E60: Muitos %s{...}s complexos"
+
+#, c-format
+msgid "E61: Nested %s*"
+msgstr "E61: %s* aninhado"
+
+#, c-format
+msgid "E62: Nested %s%c"
+msgstr "E62: %s%c aninhado"
+
+msgid "E63: invalid use of \\_"
+msgstr "E63: uso inválido de \\_"
+
+#, c-format
+msgid "E64: %s%c follows nothing"
+msgstr "E64: %s%c não segue nenhum item"
+
+msgid "E68: Invalid character after \\z"
+msgstr "E68: Caractere inválido após \\z"
+
+#, c-format
+msgid "E678: Invalid character after %s%%[dxouU]"
+msgstr "E678: Caractere inválido após %s%%[dxouU]"
+
+#, c-format
+msgid "E71: Invalid character after %s%%"
+msgstr "E71: Caractere inválido após %s%%"
+
+#, c-format
+msgid "E554: Syntax error in %s{...}"
+msgstr "E554: Erro de sintaxe em %s{...}"
+
+msgid "External submatches:\n"
+msgstr "Subcoincidências externas:\n"
+
+#, c-format
+msgid "E888: (NFA regexp) cannot repeat %s"
+msgstr "E888: (NFA regexp) %s não pode ser repetido"
+
+msgid ""
+"E864: \\%#= can only be followed by 0, 1, or 2. The automatic engine will be "
+"used "
+msgstr ""
+"E864: \\%#= só pode ser seguido por 0, 1 ou 2. Será usada a seleção "
+"automática do mecanismo de regex"
+
+msgid "Switching to backtracking RE engine for pattern: "
+msgstr "Usando mecanismo de regexp com backtracking para o padrão: "
+
+msgid "E865: (NFA) Regexp end encountered prematurely"
+msgstr "E865: (NFA) Fim prematuro de regexp"
+
+#, c-format
+msgid "E866: (NFA regexp) Misplaced %c"
+msgstr "E866: (NFA regexp) %c mal colocado"
+
+#, c-format
+msgid "E877: (NFA regexp) Invalid character class: %ld"
+msgstr "E877: (NFA regexp) Classe de caracteres inválida: %ld"
+
+#, c-format
+msgid "E867: (NFA) Unknown operator '\\z%c'"
+msgstr "E867: (NFA) Operador '\\z%c' desconhecido"
+
+#, c-format
+msgid "E867: (NFA) Unknown operator '\\%%%c'"
+msgstr "E867: (NFA) Operador '\\%%%c' desconhecido"
+
+msgid "E868: Error building NFA with equivalence class!"
+msgstr "E868: Erro ao construir NFA com classe de equivalência!"
+
+#, c-format
+msgid "E869: (NFA) Unknown operator '\\@%c'"
+msgstr "E869: (NFA) Operador '\\@%c' desconhecido"
+
+msgid "E870: (NFA regexp) Error reading repetition limits"
+msgstr "E870: (NFA regexp) Erro ao ler limites de repetição"
+
+msgid "E871: (NFA regexp) Can't have a multi follow a multi"
+msgstr "E871: (NFA regexp) Não é possível um multi seguindo outro multi"
+
+msgid "E872: (NFA regexp) Too many '('"
+msgstr "E872: (NFA regexp) Muitos '('"
+
+msgid "E879: (NFA regexp) Too many \\z("
+msgstr "E879: (NFA regexp) Muitos \\z("
+
+msgid "E873: (NFA regexp) proper termination error"
+msgstr "E873: (NFA regexp) terminação imprópria"
+
+msgid "E874: (NFA) Could not pop the stack!"
+msgstr "E874: (NFA) não foi possível desempilhar a pilha!"
+
+msgid ""
+"E875: (NFA regexp) (While converting from postfix to NFA), too many states "
+"left on stack"
+msgstr ""
+"E875: (NFA regexp) (ao converter de postfix para NFA), muitos estados "
+"sobraram na pilha"
+
+msgid "E876: (NFA regexp) Not enough space to store the whole NFA "
+msgstr "E876: (NFA regexp) espaço insuficiente para guardar todo o NFA "
+
+msgid "E878: (NFA) Could not allocate memory for branch traversal!"
+msgstr "E878: (NFA) memória não pôde ser alocada para percorrer os ramos!"
+
+msgid ""
+"Could not open temporary log file for writing, displaying on stderr... "
+msgstr ""
+"Arquivo de log temporário não pôde ser gravado, mostrando no stderr... "
+
+#, c-format
+msgid "(NFA) COULD NOT OPEN %s !"
+msgstr "(NFA) %s NÃO PÔDE SER ABERTO !"
+
+msgid "Could not open temporary log file for writing "
+msgstr "Não foi possível abrir arquivo de log temporário para escrita "
+
+msgid " VREPLACE"
+msgstr " SUBSTITUIÇÃO VISUAL"
+
+msgid " REPLACE"
+msgstr " SUBSTITUIÇÃO"
+
+# ESD - In Portuguese it would sound more natural if the message for
+# "REVERSE" came *after* the message for "INSERT".
+msgid " REVERSE"
+msgstr " (INVERTIDA)"
+
+msgid " INSERT"
+msgstr " INSERÇÃO"
+
+msgid " (insert)"
+msgstr " (inserção)"
+
+msgid " (replace)"
+msgstr " (substituição)"
+
+msgid " (vreplace)"
+msgstr " (substituição visual)"
+
+msgid " Hebrew"
+msgstr " Hebraico"
+
+msgid " Arabic"
+msgstr " Ãrabe"
+
+msgid " (paste)"
+msgstr " (colar)"
+
+msgid " VISUAL"
+msgstr " VISUAL"
+
+msgid " VISUAL LINE"
+msgstr " VISUAL/LINHA"
+
+msgid " VISUAL BLOCK"
+msgstr " VISUAL/BLOCO"
+
+msgid " SELECT"
+msgstr " SELEÇÃO"
+
+msgid " SELECT LINE"
+msgstr " SELEÇÃO DE LINHAS"
+
+msgid " SELECT BLOCK"
+msgstr " SELEÇÃO EM BLOCO"
+
+msgid "recording"
+msgstr "gravando"
+
+#, c-format
+msgid "E383: Invalid search string: %s"
+msgstr "E383: Texto de busca inválido: %s"
+
+#, c-format
+msgid "E384: search hit TOP without match for: %s"
+msgstr "E384: busca atingiu o TOPO sem encontrar: %s"
+
+#, c-format
+msgid "E385: search hit BOTTOM without match for: %s"
+msgstr "E385: busca atingiu o FIM sem encontrar: %s"
+
+msgid "E386: Expected '?' or '/' after ';'"
+msgstr "E386: '?' ou '/' esperado após ';'"
+
+msgid " (includes previously listed match)"
+msgstr " (inclui coincidências listadas anteriormente)"
+
+msgid "--- Included files "
+msgstr "--- Arquivos incluídos "
+
+msgid "not found "
+msgstr "não encontrados "
+
+msgid "in path ---\n"
+msgstr "no caminho de busca ---\n"
+
+msgid " (Already listed)"
+msgstr " (Já listado)"
+
+msgid " NOT FOUND"
+msgstr " NÃO ENCONTRADO"
+
+#, c-format
+msgid "Scanning included file: %s"
+msgstr "Examinando arquivo incluído: %s"
+
+#, c-format
+msgid "Searching included file %s"
+msgstr "Examinando arquivo incluído %s"
+
+msgid "E387: Match is on current line"
+msgstr "E387: A correspondência está na linha atual"
+
+msgid "All included files were found"
+msgstr "Todos os arquivos incluídos foram encontrados"
+
+msgid "No included files"
+msgstr "Não há arquivos incluídos"
+
+msgid "E388: Couldn't find definition"
+msgstr "E388: Definição não foi encontrada"
+
+msgid "E389: Couldn't find pattern"
+msgstr "E389: Padrão não foi encontrado"
+
+msgid "Substitute "
+msgstr " de substituição"
+
+# ESD - The %s is replaced by the argument which is given to the wvsp_one()
+# function (search.c). The "Substitute " argument which may be given
+# to it should be translated as well.
+#, c-format
+msgid ""
+"\n"
+"# Last %sSearch Pattern:\n"
+"~"
+msgstr ""
+"\n"
+"# Último padrão de busca %s:\n"
+"~"
+
+msgid "E756: Spell checking is not enabled"
+msgstr "E756: A verificação ortográfica não está ativada"
+
+#, c-format
+msgid "Warning: Cannot find word list \"%s_%s.spl\" or \"%s_ascii.spl\""
+msgstr ""
+"Aviso: Não encontrada a lista de palavras \"%s_%s.spl\" ou \"%s_ascii.spl\""
+
+#, c-format
+msgid "Warning: Cannot find word list \"%s.%s.spl\" or \"%s.ascii.spl\""
+msgstr ""
+"Aviso: Não encontrada a lista de palavras \"%s.%s.spl\" ou \"%s.ascii.spl\""
+
+msgid "E797: SpellFileMissing autocommand deleted buffer"
+msgstr "E797: O autocomando SpellFileMissing apagou o buffer"
+
+#, c-format
+msgid "Warning: region %s not supported"
+msgstr "Aviso: região %s não é suportada"
+
+msgid "Sorry, no suggestions"
+msgstr "Desculpe, não há sugestões"
+
+#, c-format
+msgid "Sorry, only %ld suggestions"
+msgstr "Desculpe, apenas %ld sugestões"
+
+#, c-format
+msgid "Change \"%.*s\" to:"
+msgstr "Alterar \"%.*s\" para:"
+
+#, c-format
+msgid " < \"%.*s\""
+msgstr " < \"%.*s\""
+
+msgid "E752: No previous spell replacement"
+msgstr "E752: Nenhuma substituição ortográfica anterior"
+
+#, c-format
+msgid "E753: Not found: %s"
+msgstr "E753: Não encontrado: %s"
+
+msgid "E758: Truncated spell file"
+msgstr "E758: Arquivo de verificação ortográfica truncado"
+
+#, c-format
+msgid "Trailing text in %s line %d: %s"
+msgstr "Texto a mais em %s, linha %d: %s"
+
+#, c-format
+msgid "Affix name too long in %s line %d: %s"
+msgstr "Nome do afixo longo demais em %s, linha %d: %s"
+
+msgid "E761: Format error in affix file FOL, LOW or UPP"
+msgstr "E761: Erro de formato em FOL, LOW ou UPP no arquivo de afixos"
+
+msgid "E762: Character in FOL, LOW or UPP is out of range"
+msgstr "E762: Há um caractere fora dos limites em FOL, LOW ou UPP"
+
+msgid "Compressing word tree..."
+msgstr "Comprimindo árvore de palavras..."
+
+#, c-format
+msgid "Reading spell file \"%s\""
+msgstr "Lendo arquivo de verificação ortográfica \"%s\""
+
+msgid "E757: This does not look like a spell file"
+msgstr "E757: Este não se parece com um arquivo de verificação ortográfica"
+
+msgid "E771: Old spell file, needs to be updated"
+msgstr ""
+"E771: Arquivo de verificação ortográfica antigo; é necessário atualizá-lo"
+
+msgid "E772: Spell file is for newer version of Vim"
+msgstr ""
+"E772: Arquivo de verificação ortográfica é para uma versão mais nova do Vim"
+
+msgid "E770: Unsupported section in spell file"
+msgstr "E770: Seção não suportada no arquivo de verificação ortográfica"
+
+#, c-format
+msgid "E778: This does not look like a .sug file: %s"
+msgstr "E778: Este não parece com um arquivo .sug: %s"
+
+#, c-format
+msgid "E779: Old .sug file, needs to be updated: %s"
+msgstr "E779: Arquivo .sug antigo, precisa ser atualizado: %s"
+
+#, c-format
+msgid "E780: .sug file is for newer version of Vim: %s"
+msgstr "E780: Arquivo .sug é para uma versão mais nova do Vim: %s"
+
+#, c-format
+msgid "E781: .sug file doesn't match .spl file: %s"
+msgstr "E781: O arquivo .sug não corresponde ao arquivo .spl: %s"
+
+#, c-format
+msgid "E782: error while reading .sug file: %s"
+msgstr "E782: erro ao ler o arquivo .sug: %s"
+
+#, c-format
+msgid "Reading affix file %s..."
+msgstr "Lendo arquivo de afixos %s..."
+
+#, c-format
+msgid "Conversion failure for word in %s line %d: %s"
+msgstr "Falha na conversão para palavra em %s, linha %d: %s"
+
+#, c-format
+msgid "Conversion in %s not supported: from %s to %s"
+msgstr "Conversão em %s não é suportada: de %s para %s"
+
+#, c-format
+msgid "Conversion in %s not supported"
+msgstr "Conversão em %s não é suportada"
+
+#, c-format
+msgid "Invalid value for FLAG in %s line %d: %s"
+msgstr "Valor inválido para FLAG em %s, linha %d: %s"
+
+#, c-format
+msgid "FLAG after using flags in %s line %d: %s"
+msgstr "FLAG encontrado após outros indicadores em %s, linha %d: %s"
+
+#, c-format
+msgid ""
+"Defining COMPOUNDFORBIDFLAG after PFX item may give wrong results in %s line "
+"%d"
+msgstr ""
+"Definir COMPOUNDFORBIDFLAG após um item PFX pode causar resultados errados "
+"em %s, linha %d"
+
+#, c-format
+msgid ""
+"Defining COMPOUNDPERMITFLAG after PFX item may give wrong results in %s line "
+"%d"
+msgstr ""
+"Definir COMPOUNDPERMITFLAG após um item PFX pode causar resultados errados "
+"em %s, linha %d"
+
+#, c-format
+msgid "Wrong COMPOUNDRULES value in %s line %d: %s"
+msgstr "Valor COMPOUNDRULES incorreto em %s, linha %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDWORDMAX value in %s line %d: %s"
+msgstr "Valor COMPOUNDWORDMAX incorreto em %s, linha %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDMIN value in %s line %d: %s"
+msgstr "Valor COMPOUNDMIN incorreto em %s, linha %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDSYLMAX value in %s line %d: %s"
+msgstr "Valor COMPOUNDSYLMAX incorreto em %s, linha %d: %s"
+
+#, c-format
+msgid "Wrong CHECKCOMPOUNDPATTERN value in %s line %d: %s"
+msgstr "Valor CHECKCOMPOUNDPATTERN incorreto em %s, linha %d: %s"
+
+#, c-format
+msgid "Different combining flag in continued affix block in %s line %d: %s"
+msgstr ""
+"Indicadores de combinação diferentes no bloco de afixos continuado em %s "
+"linha %d: %s"
+
+#, c-format
+msgid "Duplicate affix in %s line %d: %s"
+msgstr "Afixo duplicado em %s, linha %d: %s"
+
+#, c-format
+msgid ""
+"Affix also used for BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST in %s "
+"line %d: %s"
+msgstr ""
+"Afixo também usado para BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST "
+"em %s, linha %d: %s"
+
+#, c-format
+msgid "Expected Y or N in %s line %d: %s"
+msgstr "Esperado Y ou N em %s, linha %d: %s"
+
+#, c-format
+msgid "Broken condition in %s line %d: %s"
+msgstr "Condição defeituosa em %s, linha %d: %s"
+
+#, c-format
+msgid "Expected REP(SAL) count in %s line %d"
+msgstr "Esperado número de REP(SAL) em %s, linha %d"
+
+#, c-format
+msgid "Expected MAP count in %s line %d"
+msgstr "Esperado número de MAP em %s, linha %d"
+
+#, c-format
+msgid "Duplicate character in MAP in %s line %d"
+msgstr "Caractere duplicado em MAP em %s, linha %d"
+
+#, c-format
+msgid "Unrecognized or duplicate item in %s line %d: %s"
+msgstr "Item não reconhecido ou duplicado em %s, linha %d: %s"
+
+#, c-format
+msgid "Missing FOL/LOW/UPP line in %s"
+msgstr "Linha FOL/LOW/UPP faltando em %s"
+
+msgid "COMPOUNDSYLMAX used without SYLLABLE"
+msgstr "COMPOUNDSYLMAX usado sem SYLLABLE"
+
+msgid "Too many postponed prefixes"
+msgstr "Há muitos prefixos postergados"
+
+msgid "Too many compound flags"
+msgstr "Há muitos indicadores de composição"
+
+msgid "Too many postponed prefixes and/or compound flags"
+msgstr "Há muitos prefixos postergados e/ou indicadores de composição"
+
+#, c-format
+msgid "Missing SOFO%s line in %s"
+msgstr "Linha SOFO%s faltando em %s"
+
+#, c-format
+msgid "Both SAL and SOFO lines in %s"
+msgstr "Linhas SAL e SOFO presentes em %s"
+
+#, c-format
+msgid "Flag is not a number in %s line %d: %s"
+msgstr "Indicador não numérico em %s, linha %d: %s"
+
+#, c-format
+msgid "Illegal flag in %s line %d: %s"
+msgstr "Indicador inválido em %s, linha %d: %s"
+
+#, c-format
+msgid "%s value differs from what is used in another .aff file"
+msgstr "O valor de %s é diferente daquele usado em outro arquivo .aff"
+
+#, c-format
+msgid "Reading dictionary file %s..."
+msgstr "Lendo arquivo-dicionário %s..."
+
+#, c-format
+msgid "E760: No word count in %s"
+msgstr "E760: Número de palavras não indicado em %s"
+
+#, c-format
+msgid "line %6d, word %6d - %s"
+msgstr "linha %6d, palavra %6d - %s"
+
+#, c-format
+msgid "Duplicate word in %s line %d: %s"
+msgstr "Palavra duplicada em %s, linha %d: %s"
+
+#, c-format
+msgid "First duplicate word in %s line %d: %s"
+msgstr "Primeira palavra duplicada em %s, linha %d: %s"
+
+#, c-format
+msgid "%d duplicate word(s) in %s"
+msgstr "%d palavra(s) duplicada(s) em %s"
+
+#, c-format
+msgid "Ignored %d word(s) with non-ASCII characters in %s"
+msgstr "Foram ignoradas %d palavra(s) com caracteres não-ASCII em %s"
+
+#, c-format
+msgid "Reading word file %s..."
+msgstr "Lendo arquivo de palavras %s..."
+
+#, c-format
+msgid "Duplicate /encoding= line ignored in %s line %d: %s"
+msgstr "Linha /encoding= duplicada ignorada em %s, linha %d: %s"
+
+#, c-format
+msgid "/encoding= line after word ignored in %s line %d: %s"
+msgstr "Linha /encoding= ignorada após uma palavra em %s, linha %d: %s"
+
+#, c-format
+msgid "Duplicate /regions= line ignored in %s line %d: %s"
+msgstr "Linha /regions= duplicada ignorada em %s, linha %d: %s"
+
+#, c-format
+msgid "Too many regions in %s line %d: %s"
+msgstr "Regiões demais em %s, linha %d: %s"
+
+#, c-format
+msgid "/ line ignored in %s line %d: %s"
+msgstr "Linha / ignorada em %s, linha %d: %s"
+
+#, c-format
+msgid "Invalid region nr in %s line %d: %s"
+msgstr "Núm. de região inválido em %s, linha %d: %s"
+
+#, c-format
+msgid "Unrecognized flags in %s line %d: %s"
+msgstr "Indicadores não reconhecidos em %s, linha %d: %s"
+
+#, c-format
+msgid "Ignored %d words with non-ASCII characters"
+msgstr "Ignoradas %d palavras com caracteres não-ASCII"
+
+msgid "E845: Insufficient memory, word list will be incomplete"
+msgstr "E845: Memória insuficiente, a lista de palavras ficará incompleta"
+
+#, c-format
+msgid "Compressed %d of %d nodes; %d (%d%%) remaining"
+msgstr "%d de %d nós comprimidos; %d (%d%%) restantes"
+
+msgid "Reading back spell file..."
+msgstr "Relendo o arquivo de verificação ortográfica..."
+
+msgid "Performing soundfolding..."
+msgstr "Realizando análise fonética..."
+
+#, c-format
+msgid "Number of words after soundfolding: %ld"
+msgstr "Número de palavras após análise fonética: %ld"
+
+#, c-format
+msgid "Total number of words: %d"
+msgstr "Número total de palavras: %d"
+
+#, c-format
+msgid "Writing suggestion file %s..."
+msgstr "Gravando arquivo de sugestões %s..."
+
+#, c-format
+msgid "Estimated runtime memory use: %d bytes"
+msgstr "Consumo estimado de memória: %d bytes"
+
+msgid "E751: Output file name must not have region name"
+msgstr "E751: O nome do arquivo não deve conter o nome da região"
+
+msgid "E754: Only up to 8 regions supported"
+msgstr "E754: São suportadas apenas 8 regiões no máximo"
+
+#, c-format
+msgid "E755: Invalid region in %s"
+msgstr "E755: Região inválida em %s"
+
+msgid "Warning: both compounding and NOBREAK specified"
+msgstr "Aviso: tanto composição quanto NOBREAK foram especificados"
+
+#, c-format
+msgid "Writing spell file %s..."
+msgstr "Gravando arquivo de verificação ortográfica %s..."
+
+msgid "Done!"
+msgstr "Concluído!"
+
+#, c-format
+msgid "E765: 'spellfile' does not have %ld entries"
+msgstr "E765: 'spellfile' não contém %ld elementos"
+
+#, c-format
+msgid "Word '%.*s' removed from %s"
+msgstr "Palavra '%.*s' removida de %s"
+
+#, c-format
+msgid "Word '%.*s' added to %s"
+msgstr "Palavra '%.*s' adicionada a %s"
+
+msgid "E763: Word characters differ between spell files"
+msgstr "E763: Caracteres das palavras diferem entre os arquivos ortográficos"
+
+msgid "E783: duplicate char in MAP entry"
+msgstr "E783: caractere duplicado na entrada MAP"
+
+msgid "No Syntax items defined for this buffer"
+msgstr "Nenhum item sintático definido para este buffer"
+
+msgid "syntax conceal on"
+msgstr "sintaxe com ocultamento ativado"
+
+msgid "syntax conceal off"
+msgstr "sintaxe com ocultamento desativado"
+
+#, c-format
+msgid "E390: Illegal argument: %s"
+msgstr "E390: Argumento inválido: %s"
+
+msgid "syntax case ignore"
+msgstr "sintaxe insensível a maiúsculas/minúsculas"
+
+msgid "syntax case match"
+msgstr "sintaxe sensível a maiúsculas/minúsculas"
+
+#~ msgid "syntax spell toplevel"
+#~ msgstr ""
+
+#~ msgid "syntax spell notoplevel"
+#~ msgstr ""
+
+#~ msgid "syntax spell default"
+#~ msgstr ""
+
+#~ msgid "syntax iskeyword "
+#~ msgstr ""
+
+#, c-format
+msgid "E391: No such syntax cluster: %s"
+msgstr "E391: Não existe o agrupamento sintático: %s"
+
+msgid "syncing on C-style comments"
+msgstr "sincronização nos comentários no estilo do C"
+
+msgid "no syncing"
+msgstr "sem sincronização"
+
+msgid "syncing starts "
+msgstr "sincronização começa "
+
+msgid " lines before top line"
+msgstr " linhas antes do topo da tela"
+
+msgid ""
+"\n"
+"--- Syntax sync items ---"
+msgstr ""
+"\n"
+"--- Elementos de sincronização da sintaxe ---"
+
+msgid ""
+"\n"
+"syncing on items"
+msgstr ""
+"\n"
+"sincronização sobre elementos"
+
+msgid ""
+"\n"
+"--- Syntax items ---"
+msgstr ""
+"\n"
+"--- Elementos de sintaxe ---"
+
+#, c-format
+msgid "E392: No such syntax cluster: %s"
+msgstr "E392: Não existe o agrupamento de sintaxe: %s"
+
+msgid "minimal "
+msgstr "mínimo "
+
+msgid "maximal "
+msgstr "máximo "
+
+msgid "; match "
+msgstr "; corresponder com "
+
+msgid " line breaks"
+msgstr " quebras de linha"
+
+msgid "E395: contains argument not accepted here"
+msgstr "E395: o parâmetro \"contains\" não é aceito aqui"
+
+msgid "E844: invalid cchar value"
+msgstr "E844: cchar inválido"
+
+msgid "E393: group[t]here not accepted here"
+msgstr "E393: group[t]here não é aceito aqui"
+
+#, c-format
+msgid "E394: Didn't find region item for %s"
+msgstr "E394: Não foi encontrado um item de região para %s"
+
+msgid "E397: Filename required"
+msgstr "E397: Nome de arquivo requerido"
+
+msgid "E847: Too many syntax includes"
+msgstr "E847: Muitas inclusões de sintaxe"
+
+#, c-format
+msgid "E789: Missing ']': %s"
+msgstr "E789: ']' faltando: %s"
+
+#, c-format
+msgid "E890: trailing char after ']': %s]%s"
+msgstr "E890: caractere sobrando após ']': %s]%s"
+
+#, c-format
+msgid "E398: Missing '=': %s"
+msgstr "E398: '=' faltando: %s"
+
+#, c-format
+msgid "E399: Not enough arguments: syntax region %s"
+msgstr "E399: Argumentos insuficientes: syntax region %s"
+
+msgid "E848: Too many syntax clusters"
+msgstr "E848: Muitos agrupamentos sintáticos"
+
+msgid "E400: No cluster specified"
+msgstr "E400: Nenhum agrupamento especificado"
+
+#, c-format
+msgid "E401: Pattern delimiter not found: %s"
+msgstr "E401: Delimitador de padrão não encontrado: %s"
+
+#, c-format
+msgid "E402: Garbage after pattern: %s"
+msgstr "E402: Caracteres indevidos após o padrão: %s"
+
+msgid "E403: syntax sync: line continuations pattern specified twice"
+msgstr "E403: syntax sync: padrão de continuação de linha informado duas vezes"
+
+#, c-format
+msgid "E404: Illegal arguments: %s"
+msgstr "E404: Argumentos inválidos: %s"
+
+#, c-format
+msgid "E405: Missing equal sign: %s"
+msgstr "E405: Sinal de igual faltando: %s"
+
+#, c-format
+msgid "E406: Empty argument: %s"
+msgstr "E406: Argumento vazio: %s"
+
+#, c-format
+msgid "E407: %s not allowed here"
+msgstr "E407: %s não é permitido aqui"
+
+#, c-format
+msgid "E408: %s must be first in contains list"
+msgstr "E408: %s deve ser o primeiro na lista de \"contains\""
+
+#, c-format
+msgid "E409: Unknown group name: %s"
+msgstr "E409: Nome de grupo desconhecido: %s"
+
+#, c-format
+msgid "E410: Invalid :syntax subcommand: %s"
+msgstr "E410: Subcomando inválido para :syntax: %s"
+
+msgid ""
+" TOTAL COUNT MATCH SLOWEST AVERAGE NAME PATTERN"
+msgstr ""
+" TOTAL CONT. COINC. MAIS LENTO MÉDIA NOME PADRÃO"
+
+msgid "E679: recursive loop loading syncolor.vim"
+msgstr "E679: loop recursivo ao carregar syncolor.vim"
+
+#, c-format
+msgid "E411: highlight group not found: %s"
+msgstr "E411: grupo de destaque não encontrado: %s"
+
+#, c-format
+msgid "E412: Not enough arguments: \":highlight link %s\""
+msgstr "E412: Argumentos insuficientes: \":highlight link %s\""
+
+#, c-format
+msgid "E413: Too many arguments: \":highlight link %s\""
+msgstr "E413: Argumentos demais: \":highlight link %s\""
+
+msgid "E414: group has settings, highlight link ignored"
+msgstr "E414: o grupo já tem suas definições; associação de destaque ignorada"
+
+#, c-format
+msgid "E415: unexpected equal sign: %s"
+msgstr "E415: sinal de igual inesperado: %s"
+
+#, c-format
+msgid "E416: missing equal sign: %s"
+msgstr "E416: sinal de igual faltando: %s"
+
+#, c-format
+msgid "E417: missing argument: %s"
+msgstr "E417: argumento faltando: %s"
+
+#, c-format
+msgid "E418: Illegal value: %s"
+msgstr "E418: Valor inválido: %s"
+
+msgid "E419: FG color unknown"
+msgstr "E419: cor do texto desconhecida"
+
+msgid "E420: BG color unknown"
+msgstr "E420: cor de fundo desconhecida"
+
+#, c-format
+msgid "E421: Color name or number not recognized: %s"
+msgstr "E421: Nome ou número de cor não reconhecido: %s"
+
+#, c-format
+msgid "E422: terminal code too long: %s"
+msgstr "E422: código de terminal longo demais: %s"
+
+#, c-format
+msgid "E423: Illegal argument: %s"
+msgstr "E423: Argumento inválido: %s"
+
+msgid "E424: Too many different highlighting attributes in use"
+msgstr ""
+"E424: Muitos atributos diferentes de destaque sendo usados simultaneamente"
+
+msgid "E669: Unprintable character in group name"
+msgstr "E669: Caractere não-imprimível no nome do grupo"
+
+msgid "W18: Invalid character in group name"
+msgstr "W18: Caractere inválido no nome do grupo"
+
+msgid "E849: Too many highlight and syntax groups"
+msgstr "E849: Muitos grupos de destaque e sintaxe"
+
+msgid "E555: at bottom of tag stack"
+msgstr "E555: no fim da pilha de marcadores"
+
+msgid "E556: at top of tag stack"
+msgstr "E556: no topo da pilha de marcadores"
+
+msgid "E425: Cannot go before first matching tag"
+msgstr "E425: Impossível ir para antes do primeiro marcador correspondente"
+
+#, c-format
+msgid "E426: tag not found: %s"
+msgstr "E426: marcador não encontrado: %s"
+
+msgid " # pri kind tag"
+msgstr " # pri tipo marcador"
+
+msgid "file\n"
+msgstr "arquivo\n"
+
+msgid "E427: There is only one matching tag"
+msgstr "E427: Só há um marcador coincidente"
+
+msgid "E428: Cannot go beyond last matching tag"
+msgstr "E428: Impossível ir além do último marcador coincidente"
+
+#, c-format
+msgid "File \"%s\" does not exist"
+msgstr "Arquivo \"%s\" não existe"
+
+#, c-format
+msgid "tag %d of %d%s"
+msgstr "marcador %d de %d%s"
+
+msgid " or more"
+msgstr " ou mais"
+
+msgid " Using tag with different case!"
+msgstr " Usando etiqueta com caixa diferente!"
+
+#, c-format
+msgid "E429: File \"%s\" does not exist"
+msgstr "E429: Arquivo \"%s\" não existe"
+
+msgid ""
+"\n"
+" # TO tag FROM line in file/text"
+msgstr ""
+"\n"
+" # PARA marcador DA linha no arquivo/texto"
+
+#, c-format
+msgid "Searching tags file %s"
+msgstr "Examinando arquivo de marcadores %s"
+
+#, c-format
+msgid "E430: Tag file path truncated for %s\n"
+msgstr "E430: Caminho dos arquivos de marcadores truncado para %s\n"
+
+msgid "Ignoring long line in tags file"
+msgstr "Ignorando linha muito longa no arquivo de marcas"
+
+#, c-format
+msgid "E431: Format error in tags file \"%s\""
+msgstr "E431: Erro de formato no arquivo de marcadores \"%s\""
+
+#, c-format
+msgid "Before byte %ld"
+msgstr "Antes do byte %ld"
+
+#, c-format
+msgid "E432: Tags file not sorted: %s"
+msgstr "E432: Arquivo de marcadores não ordenado: %s"
+
+msgid "E433: No tags file"
+msgstr "E433: Não há arquivo de marcadores"
+
+msgid "E434: Can't find tag pattern"
+msgstr "E434: Padrão do marcador não encontrado"
+
+msgid "E435: Couldn't find tag, just guessing!"
+msgstr "E435: Marcador não foi encontrado, tentando adivinhar apenas!"
+
+#, c-format
+msgid "Duplicate field name: %s"
+msgstr "Nome de campo duplicado: %s"
+
+msgid "' not known. Available builtin terminals are:"
+msgstr "' desconhecido. Os terminais incorporados disponíveis são:"
+
+msgid "defaulting to '"
+msgstr "usando por omissão '"
+
+msgid "E557: Cannot open termcap file"
+msgstr "E557: Impossível abrir arquivo termcap"
+
+msgid "E558: Terminal entry not found in terminfo"
+msgstr "E558: Descrição do terminal não encontrada em terminfo"
+
+msgid "E559: Terminal entry not found in termcap"
+msgstr "E559: Descrição do terminal não encontrada em termcap"
+
+#, c-format
+msgid "E436: No \"%s\" entry in termcap"
+msgstr "E436: Nenhuma entrada \"%s\" em termcap"
+
+msgid "E437: terminal capability \"cm\" required"
+msgstr "E437: é necessário o recurso de terminal \"cm\""
+
+msgid ""
+"\n"
+"--- Terminal keys ---"
+msgstr ""
+"\n"
+"--- Teclas do terminal ---"
+
+msgid "Cannot open $VIMRUNTIME/rgb.txt"
+msgstr "$VIMRUNTIME/rgb.txt não pode ser aberto"
+
+msgid "Terminal"
+msgstr "Terminal"
+
+msgid "Terminal-finished"
+msgstr "Terminal-concluído"
+
+msgid "active"
+msgstr "ativo"
+
+msgid "running"
+msgstr "executando"
+
+msgid "finished"
+msgstr "concluído"
+
+msgid "new shell started\n"
+msgstr "novo shell iniciado\n"
+
+msgid "Vim: Error reading input, exiting...\n"
+msgstr "Vim: Erro ao ler a entrada; saindo...\n"
+
+msgid "Used CUT_BUFFER0 instead of empty selection"
+msgstr "Foi usado CUT_BUFFER0 em vez de uma seleção vazia"
+
+msgid "E881: Line count changed unexpectedly"
+msgstr "E881: Número de linhas alterado inesperadamente"
+
+msgid "No undo possible; continue anyway"
+msgstr "Impossível desfazer; continuando assim mesmo"
+
+#, c-format
+msgid "E828: Cannot open undo file for writing: %s"
+msgstr "E828: Impossível abrir arquivo de desfazer para escrita: %s"
+
+#, c-format
+msgid "E825: Corrupted undo file (%s): %s"
+msgstr "E825: Arquivo de desfazer corrompido (%s): %s"
+
+msgid "Cannot write undo file in any directory in 'undodir'"
+msgstr ""
+"Arquivo de desfazer não pode ser gravado em nenhum diretório de 'undodir'"
+
+#, c-format
+msgid "Will not overwrite with undo file, cannot read: %s"
+msgstr "Não será sobrescrito pelo arquivo de desfazer; ilegível: %s"
+
+#, c-format
+msgid "Will not overwrite, this is not an undo file: %s"
+msgstr "Não é um arquivo de desfazer; não será sobrescrito: %s"
+
+msgid "Skipping undo file write, nothing to undo"
+msgstr "Ignorando gravação do arquivo de desfazer; nada para desfazer"
+
+#, c-format
+msgid "Writing undo file: %s"
+msgstr "Gravando arquivo de desfazer: \"%s\""
+
+#, c-format
+msgid "E829: write error in undo file: %s"
+msgstr "E829: erro de escrita no arquivo de desfazer: %s"
+
+#, c-format
+msgid "Not reading undo file, owner differs: %s"
+msgstr "Arquivo de desfazer não lido; proprietário difere: %s"
+
+#, c-format
+msgid "Reading undo file: %s"
+msgstr "Lendo arquivo de desfazer: %s"
+
+#, c-format
+msgid "E822: Cannot open undo file for reading: %s"
+msgstr "E822: Arquivo de desfazer não pode ser aberto para leitura: %s"
+
+#, c-format
+msgid "E823: Not an undo file: %s"
+msgstr "E823: Não é um arquivo de desfazer: %s"
+
+#, c-format
+msgid "E832: Non-encrypted file has encrypted undo file: %s"
+msgstr ""
+"E832: Arquivo de desfazer criptografado para arquivo não criptografado: %s"
+
+#, c-format
+msgid "E826: Undo file decryption failed: %s"
+msgstr "E826: Falha na descriptografia do arquivo de desfazer: %s"
+
+#, c-format
+msgid "E827: Undo file is encrypted: %s"
+msgstr "E827: Arquivo de desfazer criptografado: %s"
+
+#, c-format
+msgid "E824: Incompatible undo file: %s"
+msgstr "E824: Arquivo de desfazer incompatível: %s"
+
+msgid "File contents changed, cannot use undo info"
+msgstr "Conteúdo do arquivo mudou; não posso usar informação de desfazer"
+
+#, c-format
+msgid "Finished reading undo file %s"
+msgstr "Fim da leitura do arquivo de desfazer %s"
+
+msgid "Already at oldest change"
+msgstr "Já está na alteração mais antiga"
+
+msgid "Already at newest change"
+msgstr "Já está na alteração mais nova"
+
+#, c-format
+msgid "E830: Undo number %ld not found"
+msgstr "E830: Registro desfazer %ld não encontrado"
+
+msgid "E438: u_undo: line numbers wrong"
+msgstr "E438: u_undo: números de linha errados"
+
+msgid "more line"
+msgstr "linha a mais"
+
+msgid "more lines"
+msgstr "linhas a mais"
+
+msgid "line less"
+msgstr "linha a menos"
+
+msgid "fewer lines"
+msgstr "linhas a menos"
+
+msgid "change"
+msgstr "alteração"
+
+msgid "changes"
+msgstr "alterações"
+
+#, c-format
+msgid "%ld %s; %s #%ld %s"
+msgstr "%ld %s; %s #%ld %s"
+
+msgid "before"
+msgstr "antes de"
+
+msgid "after"
+msgstr "após"
+
+msgid "Nothing to undo"
+msgstr "Nada a desfazer"
+
+msgid "number changes when saved"
+msgstr "número mudanças quando salvo"
+
+#, c-format
+msgid "%ld seconds ago"
+msgstr "%ld segundos atrás"
+
+msgid "E790: undojoin is not allowed after undo"
+msgstr "E790: undojoin não é permitido depois de desfazer"
+
+msgid "E439: undo list corrupt"
+msgstr "E439: lista de desfazimentos corrompida"
+
+msgid "E440: undo line missing"
+msgstr "E440: a linha para desfazer está faltando"
+
+#, c-format
+msgid "E122: Function %s already exists, add ! to replace it"
+msgstr "E122: Função %s já existe, adicione ! para substituí-la"
+
+msgid "E717: Dictionary entry already exists"
+msgstr "E717: Entrada do Dicionário já existente"
+
+msgid "E718: Funcref required"
+msgstr "E718: Referência de função (Funcref) requerida"
+
+#, c-format
+msgid "E130: Unknown function: %s"
+msgstr "E130: Função desconhecida: %s"
+
+#, c-format
+msgid "E125: Illegal argument: %s"
+msgstr "E125: Argumento inválido: %s"
+
+#, c-format
+msgid "E853: Duplicate argument name: %s"
+msgstr "E853: Nome de argumento duplicado: %s"
+
+#, c-format
+msgid "E740: Too many arguments for function %s"
+msgstr "E740: Argumentos demais para a função %s"
+
+#, c-format
+msgid "E116: Invalid arguments for function %s"
+msgstr "E116: Argumentos inválidos para a função %s"
+
+msgid "E132: Function call depth is higher than 'maxfuncdepth'"
+msgstr "E132: Profundidade de chamadas de função é maior que 'maxfuncdepth'"
+
+#, c-format
+msgid "calling %s"
+msgstr "chamando %s"
+
+#, c-format
+msgid "%s aborted"
+msgstr "%s cancelada"
+
+#, c-format
+msgid "%s returning #%ld"
+msgstr "%s devolveu #%ld"
+
+#, c-format
+msgid "%s returning %s"
+msgstr "%s devolveu %s"
+
+msgid "E699: Too many arguments"
+msgstr "E699: Argumentos demais"
+
+#, c-format
+msgid "E117: Unknown function: %s"
+msgstr "E117: Função desconhecida: %s"
+
+#, c-format
+msgid "E933: Function was deleted: %s"
+msgstr "E933: Função foi deletada: %s"
+
+#, c-format
+msgid "E119: Not enough arguments for function: %s"
+msgstr "E119: Argumentos insuficientes para a função: %s"
+
+#, c-format
+msgid "E120: Using <SID> not in a script context: %s"
+msgstr "E120: <SID> usado fora de um script: %s"
+
+#, c-format
+msgid "E725: Calling dict function without Dictionary: %s"
+msgstr "E725: Função dict chamada sem um Dicionário: %s"
+
+msgid "E129: Function name required"
+msgstr "E129: Nome da função requerido"
+
+#, c-format
+msgid "E128: Function name must start with a capital or \"s:\": %s"
+msgstr "E128: Nome da função deve começar com maiúscula ou \"s:\": %s"
+
+#, c-format
+msgid "E884: Function name cannot contain a colon: %s"
+msgstr "E884: Nome da função não pode conter dois-pontos: %s"
+
+#, c-format
+msgid "E123: Undefined function: %s"
+msgstr "E123: Função indefinida: %s"
+
+#, c-format
+msgid "E124: Missing '(': %s"
+msgstr "E124: '(' faltando: %s"
+
+msgid "E862: Cannot use g: here"
+msgstr "E862: g: não pode ser usado aqui"
+
+#, c-format
+msgid "E932: Closure function should not be at top level: %s"
+msgstr "E932: Função closure não deve estar no nível superior: %s"
+
+msgid "E126: Missing :endfunction"
+msgstr "E126: :endfunction faltando"
+
+#, c-format
+msgid "W22: Text found after :endfunction: %s"
+msgstr "W22: Texto extra após :endfunction: %s"
+
+#, c-format
+msgid "E707: Function name conflicts with variable: %s"
+msgstr "E707: Nome da função em conflito com variável: %s"
+
+#, c-format
+msgid "E127: Cannot redefine function %s: It is in use"
+msgstr "E127: Não é possível redefinir a função %s: ela está em uso"
+
+#, c-format
+msgid "E746: Function name does not match script file name: %s"
+msgstr "E746: Nome da função não coincide com o nome de arquivo do script: %s"
+
+#, c-format
+msgid "E131: Cannot delete function %s: It is in use"
+msgstr "E131: Não é possível excluir a função %s: ela está em uso"
+
+msgid "E133: :return not inside a function"
+msgstr "E133: :return fora de uma função"
+
+#, c-format
+msgid "E107: Missing parentheses: %s"
+msgstr "E107: Parênteses faltando: %s"
+
+msgid ""
+"\n"
+"MS-Windows 64-bit GUI version"
+msgstr ""
+"\n"
+"Versão gráfica para MS-Windows 64 bits"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit GUI version"
+msgstr ""
+"\n"
+"Versão gráfica para MS-Windows 32 bits"
+
+msgid " with OLE support"
+msgstr " com suporte a OLE"
+
+msgid ""
+"\n"
+"MS-Windows 64-bit console version"
+msgstr ""
+"\n"
+"Versão console para MS-Windows 64 bits"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit console version"
+msgstr ""
+"\n"
+"Versão console para MS-Windows 32 bits"
+
+msgid ""
+"\n"
+"MacOS X (unix) version"
+msgstr ""
+"\n"
+"Versão MacOS X (unix)"
+
+msgid ""
+"\n"
+"MacOS X version"
+msgstr ""
+"\n"
+"Versão MacOS X"
+
+msgid ""
+"\n"
+"MacOS version"
+msgstr ""
+"\n"
+"Versão MacOS"
+
+msgid ""
+"\n"
+"OpenVMS version"
+msgstr ""
+"\n"
+"Versão OpenVMS"
+
+msgid ""
+"\n"
+"Included patches: "
+msgstr ""
+"\n"
+"Correções incluídas: "
+
+msgid ""
+"\n"
+"Extra patches: "
+msgstr ""
+"\n"
+"Correções extras:"
+
+msgid "Modified by "
+msgstr "Modificado por "
+
+msgid ""
+"\n"
+"Compiled "
+msgstr ""
+"\n"
+"Compilado "
+
+msgid "by "
+msgstr "por "
+
+msgid ""
+"\n"
+"Huge version "
+msgstr ""
+"\n"
+"Versão enorme "
+
+msgid ""
+"\n"
+"Big version "
+msgstr ""
+"\n"
+"Versão grande "
+
+msgid ""
+"\n"
+"Normal version "
+msgstr ""
+"\n"
+"Versão normal "
+
+msgid ""
+"\n"
+"Small version "
+msgstr ""
+"\n"
+"Versão pequena "
+
+msgid ""
+"\n"
+"Tiny version "
+msgstr ""
+"\n"
+"Versão minúscula "
+
+msgid "without GUI."
+msgstr "sem interface gráfica."
+
+msgid "with GTK3 GUI."
+msgstr "com interface GTK3."
+
+msgid "with GTK2-GNOME GUI."
+msgstr "com interface GTK2-GNOME."
+
+msgid "with GTK2 GUI."
+msgstr "com interface GTK2."
+
+msgid "with X11-Motif GUI."
+msgstr "com interface X11-Motif."
+
+msgid "with X11-neXtaw GUI."
+msgstr "com interface X11-neXtaw."
+
+msgid "with X11-Athena GUI."
+msgstr "com interface X11-Athena."
+
+msgid "with Photon GUI."
+msgstr "com interface Photon."
+
+msgid "with GUI."
+msgstr "com interface gráfica."
+
+msgid "with Carbon GUI."
+msgstr "com interface Carbon."
+
+msgid "with Cocoa GUI."
+msgstr "com interface Cocoa."
+
+msgid "with (classic) GUI."
+msgstr "com interface gráfica (clássica)."
+
+msgid " Features included (+) or not (-):\n"
+msgstr " Recursos incluídos (+) ou não (-):\n"
+
+msgid " system vimrc file: \""
+msgstr " arquivo vimrc de sistema: \""
+
+msgid " user vimrc file: \""
+msgstr " arquivo vimrc do usuário: \""
+
+msgid " 2nd user vimrc file: \""
+msgstr " 2º arquivo vimrc do usuário: \""
+
+msgid " 3rd user vimrc file: \""
+msgstr " 3º arquivo vimrc do usuário: \""
+
+msgid " user exrc file: \""
+msgstr " arquivo exrc do usuário: \""
+
+msgid " 2nd user exrc file: \""
+msgstr " 2º arquivo exrc do usuário: \""
+
+msgid " system gvimrc file: \""
+msgstr " arquivo gvimrc de sistema: \""
+
+msgid " user gvimrc file: \""
+msgstr " arquivo gvimrc do usuário: \""
+
+msgid "2nd user gvimrc file: \""
+msgstr "2º arquivo gvimrc do usuário: \""
+
+msgid "3rd user gvimrc file: \""
+msgstr "3º arquivo gvimrc do usuário: \""
+
+msgid " defaults file: \""
+msgstr " arquivo de padrões: \""
+
+msgid " system menu file: \""
+msgstr " arquivo de menu do sistema: \""
+
+msgid " fall-back for $VIM: \""
+msgstr " padrão para $VIM: \""
+
+msgid " f-b for $VIMRUNTIME: \""
+msgstr " padrão para $VIMRUNTIME: \""
+
+msgid "Compilation: "
+msgstr "Compilação: "
+
+msgid "Compiler: "
+msgstr "Compilador: "
+
+msgid "Linking: "
+msgstr "Vinculação: "
+
+msgid " DEBUG BUILD"
+msgstr " VERSÃO DE DEPURAÇÃO"
+
+msgid "VIM - Vi IMproved"
+msgstr "VIM - VI Melhorado"
+
+msgid "version "
+msgstr "versão "
+
+msgid "by Bram Moolenaar et al."
+msgstr "por Bram Moolenaar et al."
+
+msgid "Vim is open source and freely distributable"
+msgstr "Vim tem código aberto e é livremente distribuível"
+
+msgid "Help poor children in Uganda!"
+msgstr "Ajude crianças pobres em Uganda!"
+
+msgid "type :help iccf<Enter> for information "
+msgstr "digite :help iccf<Enter> para informações "
+
+msgid "type :q<Enter> to exit "
+msgstr "digite :q<Enter> para sair "
+
+msgid "type :help<Enter> or <F1> for on-line help"
+msgstr "digite :help<Enter> ou <F1> para ajuda on-line "
+
+msgid "type :help version8<Enter> for version info"
+msgstr "digite :help version8<Enter> para info da versão"
+
+msgid "Running in Vi compatible mode"
+msgstr "Executando no modo compatível com Vi"
+
+msgid "type :set nocp<Enter> for Vim defaults"
+msgstr "digite :set nocp<Enter> para restaurar padrões do Vim"
+
+msgid "type :help cp-default<Enter> for info on this"
+msgstr "digite :help cp-default<Enter> para informações sobre isso"
+
+msgid "menu Help->Orphans for information "
+msgstr " menu Ajuda->Órfãos para informações "
+
+msgid "Running modeless, typed text is inserted"
+msgstr "Execução não modal; todo texto digitado é inserido"
+
+msgid "menu Edit->Global Settings->Toggle Insert Mode "
+msgstr " menu Editar->Opções globais->Alternar modo de inserção "
+
+msgid " for two modes "
+msgstr " para voltar à execução modal "
+
+msgid "menu Edit->Global Settings->Toggle Vi Compatible"
+msgstr " menu Editar->Opções globais->Alternar compatível com Vi "
+
+msgid " for Vim defaults "
+msgstr " para restaurar padrões do Vim"
+
+msgid "Sponsor Vim development!"
+msgstr "Patrocine o desenvolvimento do Vim!"
+
+msgid "Become a registered Vim user!"
+msgstr "Torne-se um usuário registrado do Vim!"
+
+msgid "type :help sponsor<Enter> for information "
+msgstr "digite :help sponsor<Enter> para informações "
+
+msgid "type :help register<Enter> for information "
+msgstr "digite :help register<Enter> para informações "
+
+msgid "menu Help->Sponsor/Register for information "
+msgstr "menu Ajuda->Doar/Registrar para informações"
+
+msgid "Already only one window"
+msgstr "Já há apenas uma janela"
+
+msgid "E441: There is no preview window"
+msgstr "E441: Não há janela de visualização"
+
+msgid "E442: Can't split topleft and botright at the same time"
+msgstr ""
+"E442: Impossível dividir nos cantos sup.esquerdo e inf.direito ao mesmo tempo"
+
+msgid "E443: Cannot rotate when another window is split"
+msgstr "E443: Impossível rodar quando outra janela está dividida"
+
+msgid "E444: Cannot close last window"
+msgstr "E444: Não posso fechar a última janela"
+
+msgid "E813: Cannot close autocmd window"
+msgstr "E813: Não é possível fechar a janela autocmd"
+
+msgid "E814: Cannot close window, only autocmd window would remain"
+msgstr "E814: Não é possível fechar a janela, só restaria a janela autocmd"
+
+msgid "E445: Other window contains changes"
+msgstr "E445: Outra janela contém alterações"
+
+msgid "E446: No file name under cursor"
+msgstr "E446: Nenhum nome de arquivo sob o cursor"
+
+#, c-format
+msgid "E447: Can't find file \"%s\" in path"
+msgstr "E447: Arquivo \"%s\" não encontrado nos caminhos de busca"
+
+#, c-format
+msgid "E799: Invalid ID: %ld (must be greater than or equal to 1)"
+msgstr "E799: ID inválido: %ld (deve ser maior ou igual a 1)"
+
+#, c-format
+msgid "E801: ID already taken: %ld"
+msgstr "E801: ID já atribuído: %ld"
+
+msgid "List or number required"
+msgstr "Necessária Lista ou número"
+
+#, c-format
+msgid "E802: Invalid ID: %ld (must be greater than or equal to 1)"
+msgstr "E802: ID inválido: %ld (deve ser maior ou igual a 1)"
+
+#, c-format
+msgid "E803: ID not found: %ld"
+msgstr "E803: ID não encontrado: %ld"
+
+#, c-format
+msgid "E370: Could not load library %s"
+msgstr "E370: Não foi possível carregar a biblioteca %s"
+
+msgid "Sorry, this command is disabled: the Perl library could not be loaded."
+msgstr ""
+"Desculpe, este comando está desativado: a biblioteca do Perl não pôde ser "
+"carregada."
+
+msgid "E299: Perl evaluation forbidden in sandbox without the Safe module"
+msgstr ""
+"E299: Avaliação de expressões Perl na caixa de areia proibida sem o módulo "
+"Safe"
+
+msgid "Edit with &multiple Vims"
+msgstr "Editar em &múltiplos Vims"
+
+msgid "Edit with single &Vim"
+msgstr "Editar com único &Vim"
+
+msgid "Diff with Vim"
+msgstr "Comparar (diff) com Vim"
+
+msgid "Edit with &Vim"
+msgstr "Editar com &Vim"
+
+msgid "Edit with existing Vim - "
+msgstr "Editar com Vim existente - "
+
+msgid "Edits the selected file(s) with Vim"
+msgstr "Edita o(s) arquivo(s) selecionado(s) com o Vim"
+
+msgid "Error creating process: Check if gvim is in your path!"
+msgstr "Erro ao criar processo: verifique se o gvim está no caminho de busca!"
+
+msgid "gvimext.dll error"
+msgstr "erro da gvimext.dll"
+
+msgid "Path length too long!"
+msgstr "Caminho comprido demais!"
+
+msgid "--No lines in buffer--"
+msgstr "--Sem linhas no buffer--"
+
+msgid "E470: Command aborted"
+msgstr "E470: Comando cancelado"
+
+msgid "E471: Argument required"
+msgstr "E471: Argumento requerido"
+
+msgid "E10: \\ should be followed by /, ? or &"
+msgstr "E10: \\ deve ser seguido de /, ? ou &"
+
+msgid "E11: Invalid in command-line window; <CR> executes, CTRL-C quits"
+msgstr "E11: Inválido na janela da linha de comando; <CR> executa, CTRL-C sai"
+
+msgid "E12: Command not allowed from exrc/vimrc in current dir or tag search"
+msgstr ""
+"E12: Comando não permitido no exrc/vimrc do diretório atual ou num arquivo "
+"de marcadores"
+
+msgid "E171: Missing :endif"
+msgstr "E171: :endif faltando"
+
+msgid "E600: Missing :endtry"
+msgstr "E600: :endtry faltando"
+
+msgid "E170: Missing :endwhile"
+msgstr "E170: :endwhile faltando"
+
+msgid "E170: Missing :endfor"
+msgstr "E170: :endfor faltando"
+
+msgid "E588: :endwhile without :while"
+msgstr "E588: :endwhile sem :while"
+
+msgid "E588: :endfor without :for"
+msgstr "E588: :endfor sem :for"
+
+msgid "E13: File exists (add ! to override)"
+msgstr "E13: Arquivo existe (adicione ! para forçar)"
+
+msgid "E472: Command failed"
+msgstr "E472: Comando falhou"
+
+#, c-format
+msgid "E234: Unknown fontset: %s"
+msgstr "E234: Conjunto de fontes desconhecido: %s"
+
+#, c-format
+msgid "E235: Unknown font: %s"
+msgstr "E235: Fonte desconhecida: %s"
+
+#, c-format
+msgid "E236: Font \"%s\" is not fixed-width"
+msgstr "E236: Fonte \"%s\" não é de largura fixa"
+
+msgid "E473: Internal error"
+msgstr "E473: Erro interno"
+
+#, c-format
+msgid "E685: Internal error: %s"
+msgstr "E685: Erro interno: %s"
+
+msgid "Interrupted"
+msgstr "Interrompido"
+
+msgid "E14: Invalid address"
+msgstr "E14: Endereço inválido"
+
+msgid "E474: Invalid argument"
+msgstr "E474: Argumento inválido"
+
+#, c-format
+msgid "E475: Invalid argument: %s"
+msgstr "E475: Argumento inválido: %s"
+
+#, c-format
+msgid "E15: Invalid expression: %s"
+msgstr "E15: Expressão inválida: %s"
+
+msgid "E16: Invalid range"
+msgstr "E16: Intervalo inválido"
+
+msgid "E476: Invalid command"
+msgstr "E476: Comando inválido"
+
+#, c-format
+msgid "E17: \"%s\" is a directory"
+msgstr "E17: \"%s\" é um diretório"
+
+#, c-format
+msgid "E364: Library call failed for \"%s()\""
+msgstr "E364: Chamada à biblioteca falhou para \"%s()\""
+
+#, c-format
+msgid "E448: Could not load library function %s"
+msgstr "E448: Não foi possível carregar a função %s de biblioteca"
+
+msgid "E19: Mark has invalid line number"
+msgstr "E19: Marca tem número de linha inválido"
+
+msgid "E20: Mark not set"
+msgstr "E20: Marca não definida"
+
+msgid "E21: Cannot make changes, 'modifiable' is off"
+msgstr "E21: Impossível fazer mudanças, 'modifiable' está desativado"
+
+msgid "E22: Scripts nested too deep"
+msgstr "E22: Scripts excessivamente aninhados"
+
+msgid "E23: No alternate file"
+msgstr "E23: Nenhum arquivo alternativo"
+
+msgid "E24: No such abbreviation"
+msgstr "E24: Abreviação inexistente"
+
+msgid "E477: No ! allowed"
+msgstr "E477: '!' não permitido"
+
+msgid "E25: GUI cannot be used: Not enabled at compile time"
+msgstr ""
+"E25: Interface gráfica não pode ser usada, não foi ativada na compilação"
+
+msgid "E26: Hebrew cannot be used: Not enabled at compile time\n"
+msgstr "E26: Hebraico não pode ser usado, não foi ativado na compilação\n"
+
+msgid "E27: Farsi cannot be used: Not enabled at compile time\n"
+msgstr "E27: Farsi (persa) não pode ser usado, não foi ativado na compilação\n"
+
+msgid "E800: Arabic cannot be used: Not enabled at compile time\n"
+msgstr "E800: Ãrabe não pode ser usado, não foi ativado na compilação\n"
+
+#, c-format
+msgid "E28: No such highlight group name: %s"
+msgstr "E28: Não existe grupo de destaque com tal nome: %s"
+
+msgid "E29: No inserted text yet"
+msgstr "E29: Nenhum texto foi inserido ainda"
+
+msgid "E30: No previous command line"
+msgstr "E30: Nenhuma linha de comando anterior"
+
+msgid "E31: No such mapping"
+msgstr "E31: Associação inexistente"
+
+msgid "E479: No match"
+msgstr "E479: Nenhuma correspondência"
+
+#, c-format
+msgid "E480: No match: %s"
+msgstr "E480: Nenhuma correspondência: %s"
+
+msgid "E32: No file name"
+msgstr "E32: Nenhum nome de arquivo"
+
+msgid "E33: No previous substitute regular expression"
+msgstr "E33: Nenhuma expressão regular de substituição anterior"
+
+msgid "E34: No previous command"
+msgstr "E34: Nenhum comando anterior"
+
+msgid "E35: No previous regular expression"
+msgstr "E35: Nenhuma expressão regular anterior"
+
+msgid "E481: No range allowed"
+msgstr "E481: Intervalos não são permitidos"
+
+msgid "E36: Not enough room"
+msgstr "E36: Não há espaço suficiente"
+
+#, c-format
+msgid "E247: no registered server named \"%s\""
+msgstr "E247: nenhum servidor registrado com o nome \"%s\""
+
+#, c-format
+msgid "E482: Can't create file %s"
+msgstr "E482: Impossível criar arquivo %s"
+
+msgid "E483: Can't get temp file name"
+msgstr "E483: Impossível obter nome do arquivo temporário"
+
+#, c-format
+msgid "E484: Can't open file %s"
+msgstr "E484: Impossível abrir arquivo %s"
+
+#, c-format
+msgid "E485: Can't read file %s"
+msgstr "E485: Impossível ler arquivo %s"
+
+msgid "E38: Null argument"
+msgstr "E38: Argumento nulo"
+
+msgid "E39: Number expected"
+msgstr "E39: Número era esperado"
+
+#, c-format
+msgid "E40: Can't open errorfile %s"
+msgstr "E40: Impossível abrir o arquivo de erros %s"
+
+msgid "E233: cannot open display"
+msgstr "E233: impossível abrir display"
+
+msgid "E41: Out of memory!"
+msgstr "E41: Memória esgotada!"
+
+msgid "Pattern not found"
+msgstr "Padrão não encontrado"
+
+#, c-format
+msgid "E486: Pattern not found: %s"
+msgstr "E486: Padrão não encontrado: %s"
+
+msgid "E487: Argument must be positive"
+msgstr "E487: Argumento deve ser positivo"
+
+msgid "E459: Cannot go back to previous directory"
+msgstr "E459: Impossível voltar ao diretório anterior"
+
+msgid "E42: No Errors"
+msgstr "E42: Nenhum erro"
+
+msgid "E776: No location list"
+msgstr "E776: Nenhuma lista de locais"
+
+msgid "E43: Damaged match string"
+msgstr "E43: String de busca danificada"
+
+msgid "E44: Corrupted regexp program"
+msgstr "E44: Autômato de expressão regular corrompido"
+
+msgid "E45: 'readonly' option is set (add ! to override)"
+msgstr "E45: opção 'readonly' está definida (adicione ! para forçar)"
+
+#, c-format
+msgid "E46: Cannot change read-only variable \"%s\""
+msgstr "E46: Impossível alterar variável somente-leitura \"%s\""
+
+#, c-format
+msgid "E794: Cannot set variable in the sandbox: \"%s\""
+msgstr "E794: Não é possível definir a variável na caixa de areia: \"%s\""
+
+msgid "E713: Cannot use empty key for Dictionary"
+msgstr "E713: Impossível usar chave vazia num Dicionário"
+
+msgid "E715: Dictionary required"
+msgstr "E715: Dicionário requerido"
+
+#, c-format
+msgid "E684: list index out of range: %ld"
+msgstr "E684: índice da lista fora dos limites: %ld"
+
+#, c-format
+msgid "E118: Too many arguments for function: %s"
+msgstr "E118: Muitos argumentos para a função: %s"
+
+#, c-format
+msgid "E716: Key not present in Dictionary: %s"
+msgstr "E716: Chave inexistente no Dicionário: %s"
+
+msgid "E714: List required"
+msgstr "E714: Lista requerida"
+
+#, c-format
+msgid "E712: Argument of %s must be a List or Dictionary"
+msgstr "E712: Argumento de %s deve ser uma Lista ou Dicionário"
+
+msgid "E47: Error while reading errorfile"
+msgstr "E47: Erro ao ler arquivo de erros"
+
+msgid "E48: Not allowed in sandbox"
+msgstr "E48: Isso não é permitido na caixa de areia"
+
+msgid "E523: Not allowed here"
+msgstr "E523: Isso não é permitido aqui"
+
+msgid "E359: Screen mode setting not supported"
+msgstr "E359: Configuração do modo de tela não é suportada"
+
+msgid "E49: Invalid scroll size"
+msgstr "E49: Tamanho de rolagem inválido"
+
+msgid "E91: 'shell' option is empty"
+msgstr "E91: Opção 'shell' está vazia"
+
+msgid "E255: Couldn't read in sign data!"
+msgstr "E255: Não foi possível ler os dados dos símbolos!"
+
+msgid "E72: Close error on swap file"
+msgstr "E72: Erro ao fechar o arquivo de troca"
+
+msgid "E73: tag stack empty"
+msgstr "E73: pilha de marcadores vazia"
+
+msgid "E74: Command too complex"
+msgstr "E74: Comando complexo demais"
+
+msgid "E75: Name too long"
+msgstr "E75: Nome longo demais"
+
+msgid "E76: Too many ["
+msgstr "E76: Muitos ["
+
+msgid "E77: Too many file names"
+msgstr "E77: Muitos nomes de arquivos"
+
+msgid "E488: Trailing characters"
+msgstr "E488: Caracteres em excesso no final da linha"
+
+msgid "E78: Unknown mark"
+msgstr "E78: Marca desconhecida"
+
+msgid "E79: Cannot expand wildcards"
+msgstr "E79: Impossível expandir os caracteres-curinga"
+
+msgid "E591: 'winheight' cannot be smaller than 'winminheight'"
+msgstr "E591: 'winheight' não pode ser menor que 'winminheight'"
+
+msgid "E592: 'winwidth' cannot be smaller than 'winminwidth'"
+msgstr "E592: 'winwidth' não pode ser menor que 'winminwidth'"
+
+msgid "E80: Error while writing"
+msgstr "E80: Erro na escrita"
+
+msgid "E939: Positive count required"
+msgstr "E939: Contador positivo necessário"
+
+msgid "E81: Using <SID> not in a script context"
+msgstr "E81: <SID> usado fora de um script"
+
+msgid "E449: Invalid expression received"
+msgstr "E449: Expressão inválida recebida"
+
+msgid "E463: Region is guarded, cannot modify"
+msgstr "E463: A região é protegida; impossível modificá-la"
+
+msgid "E744: NetBeans does not allow changes in read-only files"
+msgstr "E744: O NetBeans não permite alterações em arquivos somente-leitura"
+
+msgid "E363: pattern uses more memory than 'maxmempattern'"
+msgstr "E363: padrão usa mais memória que 'maxmempattern'"
+
+msgid "E749: empty buffer"
+msgstr "E749: buffer vazio"
+
+#, c-format
+msgid "E86: Buffer %ld does not exist"
+msgstr "E86: Buffer %ld não existe"
+
+msgid "E682: Invalid search pattern or delimiter"
+msgstr "E682: Padrão de busca ou delimitador inválido"
+
+msgid "E139: File is loaded in another buffer"
+msgstr "E139: O arquivo está carregado em outro buffer"
+
+#, c-format
+msgid "E764: Option '%s' is not set"
+msgstr "E764: Opção '%s' não está definida"
+
+msgid "E850: Invalid register name"
+msgstr "E850: Nome de registrador inválido"
+
+#, c-format
+msgid "E919: Directory not found in '%s': \"%s\""
+msgstr "E919: Diretório não encontrado em '%s': \"%s\""
+
+msgid "search hit TOP, continuing at BOTTOM"
+msgstr "busca atingiu TOPO; continuando do FIM"
+
+msgid "search hit BOTTOM, continuing at TOP"
+msgstr "busca atingiu FIM; continuando do TOPO"
+
+#, c-format
+msgid "Need encryption key for \"%s\""
+msgstr "Necessária chave criptográfica para \"%s\""
+
+msgid "empty keys are not allowed"
+msgstr "chaves vazias não são permitidas"
+
+msgid "dictionary is locked"
+msgstr "dicionário está travado"
+
+msgid "list is locked"
+msgstr "lista está travada"
+
+#, c-format
+msgid "failed to add key '%s' to dictionary"
+msgstr "falha ao adicionar chave '%s' ao dicionário"
+
+#, c-format
+msgid "index must be int or slice, not %s"
+msgstr "índice deve ser int ou slice, não %s"
+
+#, c-format
+msgid "expected str() or unicode() instance, but got %s"
+msgstr "esperava instância de str() ou unicode(); recebi %s"
+
+#, c-format
+msgid "expected bytes() or str() instance, but got %s"
+msgstr "esperava instância de bytes() ou str(); recebi %s"
+
+#, c-format
+msgid ""
+"expected int(), long() or something supporting coercing to long(), but got %s"
+msgstr "esperava int(), long() ou algo coercível para long(); recebi %s"
+
+#, c-format
+msgid "expected int() or something supporting coercing to int(), but got %s"
+msgstr "esperava int() ou algo coercível para int(); recebi %s"
+
+msgid "value is too large to fit into C int type"
+msgstr "valor muito grande para o tipo int do C"
+
+msgid "value is too small to fit into C int type"
+msgstr "valor muito pequeno para o tipo int do C"
+
+msgid "number must be greater than zero"
+msgstr "número deve ser maior que zero"
+
+msgid "number must be greater or equal to zero"
+msgstr "número deve ser maior que ou igual a zero"
+
+msgid "can't delete OutputObject attributes"
+msgstr "impossível excluir os atributos do OutputObject"
+
+#, c-format
+msgid "invalid attribute: %s"
+msgstr "atributo inválido: %s"
+
+msgid "E264: Python: Error initialising I/O objects"
+msgstr "E264: Python: Erro ao inicializar objetos de E/S"
+
+msgid "failed to change directory"
+msgstr "falha ao mudar diretório"
+
+#, c-format
+msgid "expected 3-tuple as imp.find_module() result, but got %s"
+msgstr "esperava 3-tupla como resultado de imp.find_module(); recebi %s"
+
+#, c-format
+msgid "expected 3-tuple as imp.find_module() result, but got tuple of size %d"
+msgstr ""
+"esperava 3-tupla como resultado de imp.find_module(); recebi tupla de "
+"tamanho %d"
+
+msgid "internal error: imp.find_module returned tuple with NULL"
+msgstr "erro interno: imp.find_module devolveu tupla com NULL"
+
+msgid "cannot delete vim.Dictionary attributes"
+msgstr "impossível excluir os atributos de vim.Dictionary"
+
+msgid "cannot modify fixed dictionary"
+msgstr "impossível modificar dicionário fixo"
+
+#, c-format
+msgid "cannot set attribute %s"
+msgstr "não foi possível definir o atributo %s"
+
+msgid "hashtab changed during iteration"
+msgstr "tabela hash alterada durante iteração"
+
+#, c-format
+msgid "expected sequence element of size 2, but got sequence of size %d"
+msgstr ""
+"esperava elemento sequência de tamanho 2, mas obtive sequência de tamanho %d"
+
+msgid "list constructor does not accept keyword arguments"
+msgstr "construtor de lista não aceita argumentos por palavra-chave"
+
+msgid "list index out of range"
+msgstr "índice de lista fora dos limites"
+
+#, c-format
+msgid "internal error: failed to get vim list item %d"
+msgstr "erro interno: não consegui obter item %d de lista do Vim"
+
+msgid "slice step cannot be zero"
+msgstr "passo de slice não pode ser zero"
+
+#, c-format
+msgid "attempt to assign sequence of size greater than %d to extended slice"
+msgstr ""
+"tentativa de atribuir sequência de tamanho maior que %d a slice estendida"
+
+#, c-format
+msgid "internal error: no vim list item %d"
+msgstr "erro interno: não existe o item %d na lista do vim"
+
+msgid "internal error: not enough list items"
+msgstr "erro interno: não há itens suficientes na lista"
+
+msgid "internal error: failed to add item to list"
+msgstr "erro interno: falha ao adicionar item à lista"
+
+#, c-format
+msgid "attempt to assign sequence of size %d to extended slice of size %d"
+msgstr ""
+"tentativa de atribuir sequência de tamanho %d a slice estendida de tamanho %d"
+
+msgid "failed to add item to list"
+msgstr "falha ao adicionar item a lista"
+
+msgid "cannot delete vim.List attributes"
+msgstr "impossível excluir os atributos de vim.List"
+
+msgid "cannot modify fixed list"
+msgstr "impossível modificar lista fixa"
+
+#, c-format
+msgid "unnamed function %s does not exist"
+msgstr "função anônima %s não existe"
+
+#, c-format
+msgid "function %s does not exist"
+msgstr "função %s não existe"
+
+#, c-format
+msgid "failed to run function %s"
+msgstr "falha ao executar função %s"
+
+msgid "unable to get option value"
+msgstr "impossível obter valor da opção"
+
+msgid "internal error: unknown option type"
+msgstr "erro interno: opção de tipo desconhecido"
+
+msgid "problem while switching windows"
+msgstr "problema ao alternar janelas"
+
+#, c-format
+msgid "unable to unset global option %s"
+msgstr "impossível remover definição global para %s"
+
+#, c-format
+msgid "unable to unset option %s which does not have global value"
+msgstr "impossível remover definição %s sem valor global"
+
+msgid "attempt to refer to deleted tab page"
+msgstr "tentativa de referência a aba removida"
+
+msgid "no such tab page"
+msgstr "aba inexistente"
+
+msgid "attempt to refer to deleted window"
+msgstr "tentativa de referência a janela excluída"
+
+msgid "readonly attribute: buffer"
+msgstr "atributo somente-leitura: buffer"
+
+msgid "cursor position outside buffer"
+msgstr "cursor posicionado fora do buffer"
+
+msgid "no such window"
+msgstr "janela inexistente"
+
+msgid "attempt to refer to deleted buffer"
+msgstr "tentativa de referência a buffer apagado"
+
+msgid "failed to rename buffer"
+msgstr "falha ao renomear buffer"
+
+msgid "mark name must be a single character"
+msgstr "nome da marca deve ser um único caractere"
+
+#, c-format
+msgid "expected vim.Buffer object, but got %s"
+msgstr "esperava objeto vim.Buffer, mas recebi %s"
+
+#, c-format
+msgid "failed to switch to buffer %d"
+msgstr "falha ao alternar para buffer %d"
+
+#, c-format
+msgid "expected vim.Window object, but got %s"
+msgstr "esperava objeto vim.Window, mas recebi %s"
+
+msgid "failed to find window in the current tab page"
+msgstr "não pude encontrar a janela na aba atual"
+
+msgid "did not switch to the specified window"
+msgstr "não pude alternar para a janela especificada"
+
+#, c-format
+msgid "expected vim.TabPage object, but got %s"
+msgstr "esperava objeto vim.TabPage, mas recebi %s"
+
+msgid "did not switch to the specified tab page"
+msgstr "não pude alternar para a aba especificada"
+
+msgid "failed to run the code"
+msgstr "falha ao executar o código"
+
+msgid "E858: Eval did not return a valid python object"
+msgstr "E858: Eval não devolveu um objeto python válido"
+
+msgid "E859: Failed to convert returned python object to vim value"
+msgstr ""
+"E859: Falha ao converter o objeto devolvido pelo python para um valor do vim"
+
+#, c-format
+msgid "unable to convert %s to vim dictionary"
+msgstr "impossível converter %s para dicionário do vim"
+
+#, c-format
+msgid "unable to convert %s to vim list"
+msgstr "impossível converter %s para lista do vim"
+
+#, c-format
+msgid "unable to convert %s to vim structure"
+msgstr "impossível converter %s para estrutura do vim"
+
+msgid "internal error: NULL reference passed"
+msgstr "erro interno: referência NULL recebida"
+
+msgid "internal error: invalid value type"
+msgstr "erro interno: valor de tipo inválido"
+
+msgid ""
+"Failed to set path hook: sys.path_hooks is not a list\n"
+"You should now do the following:\n"
+"- append vim.path_hook to sys.path_hooks\n"
+"- append vim.VIM_SPECIAL_PATH to sys.path\n"
+msgstr ""
+"Falha ao definir path hook: sys.path_hooks não é uma lista\n"
+"Você deve fazer o seguinte:\n"
+"- adicionar vim.path_hook ao sys.path_hooks\n"
+"- adicionar vim.VIM_SPECIAL_PATH ao sys.path\n"
+
+msgid ""
+"Failed to set path: sys.path is not a list\n"
+"You should now append vim.VIM_SPECIAL_PATH to sys.path"
+msgstr ""
+"Falha ao definir path: sys.path não é uma lista\n"
+"Você deve adicionar vim.VIM_SPECIAL_PATH ao sys.path"
diff --git a/src/po/ru.cp1251.po b/src/po/ru.cp1251.po
new file mode 100644
index 0000000..b8a3582
--- /dev/null
+++ b/src/po/ru.cp1251.po
@@ -0,0 +1,7111 @@
+# Russian translation for Vim
+#
+# Îá óñëîâèÿõ èñïîëüçîâàíèÿ ÷èòàéòå â ðåäàêòîðå Vim ":help uganda"
+#
+# vassily "vr" ragosin <vrr@users.sourceforge.net>, 2004
+# Sergey Alyoshin <alyoshin.s@gmail.com>, 2013-2014, 2016, 2018
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: vim_ru\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2018-04-28 21:50+0300\n"
+"PO-Revision-Date: 2018-04-28 21:51+0300\n"
+"Last-Translator: Sergey Alyoshin <alyoshin.s@gmail.com>\n"
+"Language-Team: \n"
+"Language: Russian\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=cp1251\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
+"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
+
+msgid "E831: bf_key_init() called with empty password"
+msgstr "E831: bf_key_init() âûçâàí ñ ïóñòûì ïàðîëåì"
+
+msgid "E820: sizeof(uint32_t) != 4"
+msgstr "E820: sizeof(uint32_t) != 4"
+
+msgid "E817: Blowfish big/little endian use wrong"
+msgstr ""
+"E817: Íåïðàâèëüíîå èñïîëüçîâàíèå îáðàòíîãî/ïðÿìîãî ïîðÿäêà áàéò â Blowfish"
+
+msgid "E818: sha256 test failed"
+msgstr "E818: Íå óäàëîñü âûïîëíèòü òåñò sha256"
+
+msgid "E819: Blowfish test failed"
+msgstr "E819: Íå óäàëîñü âûïîëíèòü òåñò Blowfish"
+
+msgid "[Location List]"
+msgstr "[Ñïèñîê ðàñïîëîæåíèé]"
+
+msgid "[Quickfix List]"
+msgstr "[Ñïèñîê áûñòðûõ èñïðàâëåíèé]"
+
+msgid "E855: Autocommands caused command to abort"
+msgstr "E855: Àâòîêîìàíäû âûçâàëè ïðåêðàùåíèå êîìàíäû"
+
+msgid "E82: Cannot allocate any buffer, exiting..."
+msgstr "E82: Íåâîçìîæíî âûäåëèòü ïàìÿòü äàæå äëÿ îäíîãî áóôåðà, âûõîä..."
+
+msgid "E83: Cannot allocate buffer, using other one..."
+msgstr "E83: Íåâîçìîæíî âûäåëèòü ïàìÿòü äëÿ áóôåðà, èñïîëüçóåì äðóãîé áóôåð..."
+
+msgid "E931: Buffer cannot be registered"
+msgstr "E931: Íåâîçìîæíî çàðåãèñòðèðîâàòü áóôåð"
+
+msgid "E937: Attempt to delete a buffer that is in use"
+msgstr "E937: Ïîïûòêà óäàëèòü èñïîëüçóåìûé áóôåð"
+
+msgid "E515: No buffers were unloaded"
+msgstr "E515: Íè îäèí áóôåð íå áûë âûãðóæåí èç ïàìÿòè"
+
+msgid "E516: No buffers were deleted"
+msgstr "E516: Íè îäèí áóôåð íå áûë óäàë¸í"
+
+msgid "E517: No buffers were wiped out"
+msgstr "E517: Íè îäèí áóôåð íå áûë î÷èùåí"
+
+msgid "1 buffer unloaded"
+msgstr "Îäèí áóôåð âûãðóæåí èç ïàìÿòè"
+
+#, c-format
+msgid "%d buffers unloaded"
+msgstr "Âñåãî âûãðóæåíî áóôåðîâ èç ïàìÿòè: %d"
+
+msgid "1 buffer deleted"
+msgstr "Îäèí áóôåð óäàë¸í"
+
+#, c-format
+msgid "%d buffers deleted"
+msgstr "Âñåãî óäàëåíî áóôåðîâ: %d"
+
+msgid "1 buffer wiped out"
+msgstr "Îäèí áóôåð î÷èùåí"
+
+#, c-format
+msgid "%d buffers wiped out"
+msgstr "Âñåãî î÷èùåíî áóôåðîâ: %d"
+
+msgid "E90: Cannot unload last buffer"
+msgstr "E90: Íåâîçìîæíî âûãðóçèòü èç ïàìÿòè ïîñëåäíèé áóôåð"
+
+msgid "E84: No modified buffer found"
+msgstr "E84: Èçìåí¸ííûõ áóôåðîâ íå îáíàðóæåíî"
+
+msgid "E85: There is no listed buffer"
+msgstr "E85: Áóôåðû â ñïèñêå îòñóòñòâóþò"
+
+msgid "E87: Cannot go beyond last buffer"
+msgstr "E87: Ýòî ïîñëåäíèé áóôåð"
+
+msgid "E88: Cannot go before first buffer"
+msgstr "E88: Ýòî ïåðâûé áóôåð"
+
+#, c-format
+msgid "E89: No write since last change for buffer %ld (add ! to override)"
+msgstr ""
+"E89: Èçìåíåíèÿ â áóôåðå %ld íå ñîõðàíåíû (äîáàâüòå !, ÷òîáû îáîéòè ïðîâåðêó)"
+
+msgid "E948: Job still running (add ! to end the job)"
+msgstr "E948: Çàäàíèå åù¸ âûïîëíÿåòñÿ (äîáàâüòå !, ÷òîáû çàâåðøèòü)"
+
+msgid "E37: No write since last change (add ! to override)"
+msgstr "E37: Èçìåíåíèÿ íå ñîõðàíåíû (äîáàâüòå !, ÷òîáû îáîéòè ïðîâåðêó)"
+
+msgid "E948: Job still running"
+msgstr "E948: Çàäàíèå åù¸ âûïîëíÿåòñÿ"
+
+msgid "E37: No write since last change"
+msgstr "E37: Èçìåíåíèÿ íå ñîõðàíåíû"
+
+msgid "W14: Warning: List of file names overflow"
+msgstr "W14: Ïðåäóïðåæäåíèå: ïåðåïîëíåíèå ñïèñêà èì¸í ôàéëîâ"
+
+#, c-format
+msgid "E92: Buffer %ld not found"
+msgstr "E92: Áóôåð %ld íå íàéäåí"
+
+#, c-format
+msgid "E93: More than one match for %s"
+msgstr "E93: Íåñêîëüêî ñîîòâåòñòâèé äëÿ %s"
+
+#, c-format
+msgid "E94: No matching buffer for %s"
+msgstr "E94: Íåò ñîîòâåòñòâóþùåãî %s áóôåðà"
+
+#, c-format
+msgid "line %ld"
+msgstr "ñòðîêà %ld"
+
+msgid "E95: Buffer with this name already exists"
+msgstr "E95: Áóôåð ñ òàêèì èìåíåì óæå ñóùåñòâóåò"
+
+msgid " [Modified]"
+msgstr " [Èçìåí¸í]"
+
+msgid "[Not edited]"
+msgstr "[Íå ðåäàêòèðîâàëñÿ]"
+
+msgid "[New file]"
+msgstr "[Íîâûé ôàéë]"
+
+msgid "[Read errors]"
+msgstr "[Îøèáêè ÷òåíèÿ]"
+
+msgid "[RO]"
+msgstr "[Ò×]"
+
+msgid "[readonly]"
+msgstr "[òîëüêî äëÿ ÷òåíèÿ]"
+
+#, c-format
+msgid "1 line --%d%%--"
+msgstr "Îäíà ñòðîêà --%d%%--"
+
+#, c-format
+msgid "%ld lines --%d%%--"
+msgstr "%ld ñòð. --%d%%--"
+
+#, c-format
+msgid "line %ld of %ld --%d%%-- col "
+msgstr "ñòð. %ld èç %ld --%d%%-- êîë. "
+
+msgid "[No Name]"
+msgstr "[Íåò èìåíè]"
+
+msgid "help"
+msgstr "ñïðàâêà"
+
+msgid "[Help]"
+msgstr "[Ñïðàâêà]"
+
+msgid "[Preview]"
+msgstr "[Ïðåäïðîñìîòð]"
+
+msgid "All"
+msgstr "Âåñü"
+
+msgid "Bot"
+msgstr "Âíèçó"
+
+msgid "Top"
+msgstr "Íàâåðõó"
+
+msgid ""
+"\n"
+"# Buffer list:\n"
+msgstr ""
+"\n"
+"# Ñïèñîê áóôåðîâ:\n"
+
+msgid "E382: Cannot write, 'buftype' option is set"
+msgstr ""
+"E382: Çàïèñü íåâîçìîæíà, çíà÷åíèå îïöèè 'buftype' íå ÿâëÿåòñÿ ïóñòîé ñòðîêîé"
+
+msgid "[Scratch]"
+msgstr "[Âðåìåííûé]"
+
+msgid ""
+"\n"
+"--- Signs ---"
+msgstr ""
+"\n"
+"--- Çíà÷êè ---"
+
+#, c-format
+msgid "Signs for %s:"
+msgstr "Çíà÷êè äëÿ %s:"
+
+#, c-format
+msgid " line=%ld id=%d name=%s"
+msgstr " ñòðîêà=%ld id=%d èìÿ=%s"
+
+msgid "E902: Cannot connect to port"
+msgstr "E902: Íåâîçìîæíî ñîåäèíèòüñÿ ñ ïîðòîì"
+
+msgid "E901: gethostbyname() in channel_open()"
+msgstr "E901: gethostbyname() â channel_open()"
+
+msgid "E898: socket() in channel_open()"
+msgstr "E898: socket() â channel_open()"
+
+msgid "E903: received command with non-string argument"
+msgstr "E903: Ïîëó÷åíà êîìàíäà ñ íå ñòðîêîâûì ïàðàìåòðîì"
+
+msgid "E904: last argument for expr/call must be a number"
+msgstr "E904: Ïîñëåäíèé ïàðàìåòð äëÿ âûðàæåíèÿ èëè âûçîâà äîëæåí áûòü ÷èñëîì"
+
+msgid "E904: third argument for call must be a list"
+msgstr "E904: Òðåòèé ïàðàìåòð äëÿ âûçîâà äîëæåí áûòü ñïèñêîì"
+
+#, c-format
+msgid "E905: received unknown command: %s"
+msgstr "E905: Ïîëó÷åíà íåèçâåñòíàÿ êîìàíäà %s"
+
+#, c-format
+msgid "E630: %s(): write while not connected"
+msgstr "E630: %s(): çàïèñü áåç ñîåäèíåíèÿ"
+
+#, c-format
+msgid "E631: %s(): write failed"
+msgstr "E631: Îøèáêà çàïèñè â %s()"
+
+#, c-format
+msgid "E917: Cannot use a callback with %s()"
+msgstr "E917: Íåâîçìîæíî èñïîëüçîâàòü îáðàòíûé âûçîâ ñ %s()"
+
+msgid "E912: cannot use ch_evalexpr()/ch_sendexpr() with a raw or nl channel"
+msgstr ""
+"E912: Íåâîçìîæíî èñïîëüçîâàòü ch_evalexpr() èëè ch_sendexpr() ñ êàíàëîì nl "
+"èëè raw"
+
+msgid "E906: not an open channel"
+msgstr "E906: Íå îòêðûòûé êàíàë"
+
+msgid "E920: _io file requires _name to be set"
+msgstr "E920: Ôàéë _io òðåáóåò óñòàíîâëåííîãî _name"
+
+msgid "E915: in_io buffer requires in_buf or in_name to be set"
+msgstr "E915: áóôåð in_io òðåáóåò óñòàíîâëåííîãî in_buf èëè in_name"
+
+#, c-format
+msgid "E918: buffer must be loaded: %s"
+msgstr "E918: Áóôåð äîëæåí áûòü çàãðóæåí: %s"
+
+msgid "E821: File is encrypted with unknown method"
+msgstr "E821: Ôàéë çàøèôðîâàí íåèçâåñòíûì ìåòîäîì"
+
+msgid "Warning: Using a weak encryption method; see :help 'cm'"
+msgstr "Ïðåäóïðåæäåíèå: Èñïîëüçóåòñÿ ñëàáûé ìåòîä øèôðîâàíèÿ, ñì. :help 'cm'"
+
+msgid "Enter encryption key: "
+msgstr "Ââåäèòå ïàðîëü äëÿ øèôðîâàíèÿ: "
+
+msgid "Enter same key again: "
+msgstr "Ïîâòîðèòå ââîä ïàðîëÿ: "
+
+msgid "Keys don't match!"
+msgstr "Ââåä¸ííûå ïàðîëè íå ñîâïàäàþò!"
+
+msgid "[crypted]"
+msgstr "[çàøèôðîâàíî]"
+
+#, c-format
+msgid "E720: Missing colon in Dictionary: %s"
+msgstr "E720: Ïðîïóùåíî äâîåòî÷èå â ñëîâàðå: %s"
+
+#, c-format
+msgid "E721: Duplicate key in Dictionary: \"%s\""
+msgstr "E721: Ïîâòîð êëþ÷à â ñëîâàðå: \"%s\""
+
+#, c-format
+msgid "E722: Missing comma in Dictionary: %s"
+msgstr "E722: Ïðîïóùåíà çàïÿòàÿ â ñëîâàðå: %s"
+
+#, c-format
+msgid "E723: Missing end of Dictionary '}': %s"
+msgstr "E723: Ïðîïóùåíî îêîí÷àíèå ñëîâàðÿ '}': %s"
+
+msgid "extend() argument"
+msgstr "ïàðàìåòðà extend()"
+
+#, c-format
+msgid "E737: Key already exists: %s"
+msgstr "E737: Êëþ÷ óæå ñóùåñòâóåò: %s"
+
+#, c-format
+msgid "E96: Cannot diff more than %ld buffers"
+msgstr "E96: Ñëåäèòü çà îòëè÷èÿìè ìîæíî íå áîëåå ÷åì â %ld áóôåðàõ"
+
+msgid "E810: Cannot read or write temp files"
+msgstr "E810: Íåâîçìîæíî ïðî÷èòàòü èëè çàïèñàòü âðåìåííûå ôàéëû"
+
+msgid "E97: Cannot create diffs"
+msgstr "E97: Íåâîçìîæíî ñîçäàòü ôàéëû îòëè÷èé"
+
+msgid "Patch file"
+msgstr "Ôàéë-çàïëàòêà"
+
+msgid "E816: Cannot read patch output"
+msgstr "E816: Íåâîçìîæíî ïðî÷èòàòü âûâîä patch"
+
+msgid "E98: Cannot read diff output"
+msgstr "E98: Íåâîçìîæíî ïðî÷èòàòü âûâîä diff"
+
+msgid "E99: Current buffer is not in diff mode"
+msgstr "E99: Àêòèâíûé áóôåð íå íàõîäèòñÿ â ðåæèìå îòëè÷èé"
+
+msgid "E793: No other buffer in diff mode is modifiable"
+msgstr "E793: Áîëüøå íåò èçìåíÿåìûõ áóôåðîâ â ðåæèìå îòëè÷èé"
+
+msgid "E100: No other buffer in diff mode"
+msgstr "E100: Áîëüøå íåò áóôåðîâ â ðåæèìå îòëè÷èé"
+
+msgid "E101: More than two buffers in diff mode, don't know which one to use"
+msgstr "E101:  ðåæèìå îòëè÷èé áîëåå äâóõ áóôåðîâ, íå ìîãó âûáðàòü"
+
+#, c-format
+msgid "E102: Can't find buffer \"%s\""
+msgstr "E102: Íå ìîãó íàéòè áóôåð \"%s\""
+
+#, c-format
+msgid "E103: Buffer \"%s\" is not in diff mode"
+msgstr "E103: Áóôåð \"%s\" íå íàõîäèòñÿ â ðåæèìå îòëè÷èé"
+
+msgid "E787: Buffer changed unexpectedly"
+msgstr "E787: Áóôåð íåîæèäàííî èçìåíèëñÿ"
+
+msgid "E104: Escape not allowed in digraph"
+msgstr "E104: Ýêðàíèðóþùèé ñèìâîë Escape íåëüçÿ èñïîëüçîâàòü â äèãðàôå"
+
+msgid "E544: Keymap file not found"
+msgstr "E544: Ôàéë ñ ðàñêëàäêîé êëàâèàòóðû íå íàéäåí"
+
+msgid "E105: Using :loadkeymap not in a sourced file"
+msgstr "E105: Êîìàíäà :loadkeymap ïðèìåíåíà âíå ôàéëà ñöåíàðèÿ"
+
+msgid "E791: Empty keymap entry"
+msgstr "E791: ïóñòàÿ çàïèñü ðàñêëàäêè êëàâèàòóðû"
+
+msgid " Keyword completion (^N^P)"
+msgstr " Àâòîäîïîëíåíèå êëþ÷åâîãî ñëîâà (^N^P)"
+
+msgid " ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+msgstr " Ðåæèì ^X (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+
+msgid " Whole line completion (^L^N^P)"
+msgstr " Àâòîäîïîëíåíèå öåëîé ñòðîêè (^L^N^P)"
+
+msgid " File name completion (^F^N^P)"
+msgstr " Àâòîäîïîëíåíèå èìåíè ôàéëà (^F^N^P)"
+
+msgid " Tag completion (^]^N^P)"
+msgstr " Àâòîäîïîëíåíèå ìåòêè (^]^N^P)"
+
+msgid " Path pattern completion (^N^P)"
+msgstr " Àâòîäîïîëíåíèå øàáëîíà ïóòè (^N^P)"
+
+msgid " Definition completion (^D^N^P)"
+msgstr " Àâòîäîïîëíåíèå îïðåäåëåíèÿ (^D^N^P)"
+
+msgid " Dictionary completion (^K^N^P)"
+msgstr " Àâòîäîïîëíåíèå ïî ñëîâàðþ (^K^N^P)"
+
+msgid " Thesaurus completion (^T^N^P)"
+msgstr " Àâòîäîïîëíåíèå ñèíîíèìîâ (^T^N^P)"
+
+msgid " Command-line completion (^V^N^P)"
+msgstr " Àâòîäîïîëíåíèå êîìàíäíîé ñòðîêè (^V^N^P)"
+
+msgid " User defined completion (^U^N^P)"
+msgstr " Ïîëüçîâàòåëüñêîå àâòîäîïîëíåíèå (^U^N^P)"
+
+msgid " Omni completion (^O^N^P)"
+msgstr " Omni-äîïîëíåíèå (^O^N^P)"
+
+msgid " Spelling suggestion (s^N^P)"
+msgstr " Ïðåäëîæåíèå èñïðàâëåíèÿ ïðàâîïèñàíèÿ (s^N^P)"
+
+msgid " Keyword Local completion (^N^P)"
+msgstr " Ìåñòíîå àâòîäîïîëíåíèå êëþ÷åâîãî ñëîâà (^N^P)"
+
+msgid "Hit end of paragraph"
+msgstr "Êîíåö àáçàöà"
+
+msgid "E839: Completion function changed window"
+msgstr "E839: Ôóíêöèÿ àâòîäîïîëíåíèÿ èçìåíèëà îêíî"
+
+msgid "E840: Completion function deleted text"
+msgstr "E840: Ôóíêöèÿ àâòîäîïîëíåíèÿ óäàëèëà òåêñò"
+
+msgid "'dictionary' option is empty"
+msgstr "Íå çàäàíî çíà÷åíèå îïöèè 'dictionary'"
+
+msgid "'thesaurus' option is empty"
+msgstr "Íå çàäàíî çíà÷åíèå îïöèè 'thesaurus'"
+
+#, c-format
+msgid "Scanning dictionary: %s"
+msgstr "Ïðîñìîòð ñëîâàðÿ: %s"
+
+msgid " (insert) Scroll (^E/^Y)"
+msgstr " (âñòàâêà) Ïðîêðóòêà (^E/^Y)"
+
+msgid " (replace) Scroll (^E/^Y)"
+msgstr " (çàìåíà) Ïðîêðóòêà (^E/^Y)"
+
+#, c-format
+msgid "Scanning: %s"
+msgstr "Ïðîñìîòð: %s"
+
+msgid "Scanning tags."
+msgstr "Âûïîëíÿåòñÿ ïîèñê ñðåäè ìåòîê."
+
+msgid "match in file"
+msgstr "ñîîòâåòñòâèå â ôàéëå"
+
+msgid " Adding"
+msgstr " Äîáàâëåíèå"
+
+msgid "-- Searching..."
+msgstr "-- Ïîèñê..."
+
+msgid "Back at original"
+msgstr "Èñõîäíîå ñëîâî"
+
+msgid "Word from other line"
+msgstr "Ñëîâî èç äðóãîé ñòðîêè"
+
+msgid "The only match"
+msgstr "Åäèíñòâåííîå ñîîòâåòñòâèå"
+
+#, c-format
+msgid "match %d of %d"
+msgstr "ñîîòâåòñòâèå %d èç %d"
+
+#, c-format
+msgid "match %d"
+msgstr "ñîîòâåòñòâèå %d"
+
+msgid "E18: Unexpected characters in :let"
+msgstr "E18: Íåîæèäàííûå ñèìâîëû â :let"
+
+#, c-format
+msgid "E121: Undefined variable: %s"
+msgstr "E121: Íåîïðåäåë¸ííàÿ ïåðåìåííàÿ: %s"
+
+msgid "E111: Missing ']'"
+msgstr "E111: Ïðîïóùåíà ']'"
+
+msgid "E719: Cannot use [:] with a Dictionary"
+msgstr "E719: Íåâîçìîæíî èñïîëüçîâàòü [:] ñî ñëîâàð¸ì"
+
+#, c-format
+msgid "E734: Wrong variable type for %s="
+msgstr "E734: Íåïðàâèëüíûé òèï ïåðåìåííîé äëÿ %s="
+
+#, c-format
+msgid "E461: Illegal variable name: %s"
+msgstr "E461: Íåäîïóñòèìîå èìÿ ïåðåìåííîé: %s"
+
+msgid "E806: using Float as a String"
+msgstr "E806: Èñïîëüçîâàíèå ÷èñëà ñ ïëàâàþùåé òî÷êîé êàê ñòðîêè"
+
+msgid "E687: Less targets than List items"
+msgstr "E687: Öåëåé ìåíüøå ÷åì ýëåìåíòîâ ñïèñêà"
+
+msgid "E688: More targets than List items"
+msgstr "E688: Öåëåé áîëüøå ÷åì ýëåìåíòîâ ñïèñêà"
+
+msgid "Double ; in list of variables"
+msgstr "Äâîéíàÿ ; â ñïèñêå ïåðåìåííûõ"
+
+#, c-format
+msgid "E738: Can't list variables for %s"
+msgstr "E738: Íåâîçìîæíî îòîáðàçèòü ïåðåìåííûå äëÿ %s"
+
+msgid "E689: Can only index a List or Dictionary"
+msgstr "E689: Èíäåêñèðîâàíèå âîçìîæíî òîëüêî ñïèñêà èëè ñëîâàðÿ"
+
+msgid "E708: [:] must come last"
+msgstr "E708: [:] äîëæíî áûòü ïîñëåäíèì"
+
+msgid "E709: [:] requires a List value"
+msgstr "E709: [:] òðåáóåò çíà÷åíèåì ñïèñîê"
+
+msgid "E710: List value has more items than target"
+msgstr "E710: Ýëåìåíòîâ ñïèñêà-çíà÷åíèÿ áîëüøå ÷åì â öåëè"
+
+msgid "E711: List value has not enough items"
+msgstr "E711: Ñïèñîê-çíà÷åíèå íå ñîäåðæèò äîñòàòî÷íî ýëåìåíòîâ"
+
+msgid "E690: Missing \"in\" after :for"
+msgstr "E690: Ïðîïóùåíî \"in\" ïîñëå :for"
+
+#, c-format
+msgid "E108: No such variable: \"%s\""
+msgstr "E108: Íåò òàêîé ïåðåìåííîé: \"%s\""
+
+#, c-format
+msgid "E940: Cannot lock or unlock variable %s"
+msgstr "E940: Íåâîçìîæíî (ðàç)áëîêèðîâàòü ïåðåìåííóþ %s"
+
+msgid "E743: variable nested too deep for (un)lock"
+msgstr "E743: Ñëèøêîì ãëóáîêî âëîæåííûå ïåðåìåííûå äëÿ (ðàç)áëîêèðîâêè"
+
+msgid "E109: Missing ':' after '?'"
+msgstr "E109: Ïðîïóùåíî ':' ïîñëå '?'"
+
+msgid "E804: Cannot use '%' with Float"
+msgstr "E804: Íåâîçìîæíî èñïîëüçîâàòü '%' ñ ÷èñëîì ñ ïëàâàþùåé òî÷êîé"
+
+msgid "E110: Missing ')'"
+msgstr "E110: Ïðîïóùåíà ')'"
+
+msgid "E695: Cannot index a Funcref"
+msgstr "E695: Íåâîçìîæíî èíäåêñèðîâàòü ññûëêó íà ôóíêöèþ"
+
+msgid "E909: Cannot index a special variable"
+msgstr "E909: Íåâîçìîæíî èíäåêñèðîâàòü ñïåöèàëüíóþ ïåðåìåííóþ"
+
+#, c-format
+msgid "E112: Option name missing: %s"
+msgstr "E112: Íå óêàçàíî èìÿ îïöèè: %s"
+
+#, c-format
+msgid "E113: Unknown option: %s"
+msgstr "E113: Íåèçâåñòíàÿ îïöèÿ: %s"
+
+#, c-format
+msgid "E114: Missing quote: %s"
+msgstr "E114: Ïðîïóùåíà êàâû÷êà: %s"
+
+#, c-format
+msgid "E115: Missing quote: %s"
+msgstr "E115: Ïðîïóùåíà êàâû÷êà: %s"
+
+msgid "Not enough memory to set references, garbage collection aborted!"
+msgstr "Íåäîñòàòî÷íî ïàìÿòè äëÿ óñòàíîâêè ññûëêè, ñáîðêà ìóñîðà ïðåêðàùåíà!"
+
+msgid "E724: variable nested too deep for displaying"
+msgstr "E724: Ñëèøêîì ãëóáîêî âëîæåííûå ïåðåìåííûå äëÿ îòîáðàæåíèÿ"
+
+msgid "E805: Using a Float as a Number"
+msgstr "E805: Èñïîëüçîâàíèå ÷èñëà ñ ïëàâàþùåé òî÷êîé êàê öåëîãî"
+
+msgid "E703: Using a Funcref as a Number"
+msgstr "E703: Èñïîëüçîâàíèå ññûëêè íà ôóíêöèþ êàê ÷èñëà"
+
+msgid "E745: Using a List as a Number"
+msgstr "E745: Èñïîëüçîâàíèå ñïèñêà êàê ÷èñëà"
+
+msgid "E728: Using a Dictionary as a Number"
+msgstr "E728: Èñïîëüçîâàíèå ñëîâàðÿ êàê ÷èñëà"
+
+msgid "E910: Using a Job as a Number"
+msgstr "E910: Èñïîëüçîâàíèå çàäàíèÿ êàê ÷èñëà"
+
+msgid "E913: Using a Channel as a Number"
+msgstr "E913: Èñïîëüçîâàíèå êàíàëà êàê ÷èñëà"
+
+msgid "E891: Using a Funcref as a Float"
+msgstr "E891: Èñïîëüçîâàíèå ññûëêè íà ôóíêöèþ êàê ÷èñëà ñ ïëàâàþùåé òî÷êîé"
+
+msgid "E892: Using a String as a Float"
+msgstr "E892: Èñïîëüçîâàíèå ñòðîêè êàê ÷èñëà ñ ïëàâàþùåé òî÷êîé"
+
+msgid "E893: Using a List as a Float"
+msgstr "E893: Èñïîëüçîâàíèå ñïèñêà êàê ÷èñëà ñ ïëàâàþùåé òî÷êîé"
+
+msgid "E894: Using a Dictionary as a Float"
+msgstr "E894: Èñïîëüçîâàíèå ñëîâàðÿ êàê ÷èñëà ñ ïëàâàþùåé òî÷êîé"
+
+msgid "E907: Using a special value as a Float"
+msgstr "E907: Èñïîëüçîâàíèå ñïåöèàëüíîãî çíà÷åíèÿ êàê ÷èñëà ñ ïëàâàþùåé òî÷êîé"
+
+msgid "E911: Using a Job as a Float"
+msgstr "E911: Èñïîëüçîâàíèå çàäàíèÿ êàê ÷èñëà ñ ïëàâàþùåé òî÷êîé"
+
+msgid "E914: Using a Channel as a Float"
+msgstr "E914: Èñïîëüçîâàíèå êàíàëà êàê ÷èñëà ñ ïëàâàþùåé òî÷êîé"
+
+msgid "E729: using Funcref as a String"
+msgstr "E729: Èñïîëüçîâàíèå ññûëêè íà ôóíêöèþ êàê ñòðîêè"
+
+msgid "E730: using List as a String"
+msgstr "E730: Èñïîëüçîâàíèå ñïèñêà êàê ñòðîêè"
+
+msgid "E731: using Dictionary as a String"
+msgstr "E731: Èñïîëüçîâàíèå ñëîâàðÿ êàê ñòðîêè"
+
+msgid "E908: using an invalid value as a String"
+msgstr "E908: Èñïîëüçîâàíèå íåïðàâèëüíîãî çíà÷åíèÿ êàê ñòðîêè"
+
+#, c-format
+msgid "E795: Cannot delete variable %s"
+msgstr "E795: Íåâîçìîæíî óäàëèòü ïåðåìåííóþ %s"
+
+#, c-format
+msgid "E704: Funcref variable name must start with a capital: %s"
+msgstr ""
+"E704: Èìÿ ïåðåìåííîé ññûëêè íà ôóíêöèþ äîëæíî íà÷èíàòüñÿ ñ çàãëàâíîé áóêâû: "
+"%s"
+
+#, c-format
+msgid "E705: Variable name conflicts with existing function: %s"
+msgstr "E705: Èìÿ ïåðåìåííîé êîíôëèêòóåò ñ ñóùåñòâóþùåé ôóíêöèåé: %s"
+
+#, c-format
+msgid "E741: Value is locked: %s"
+msgstr "E741: Çíà÷åíèå %s çàáëîêèðîâàíî"
+
+msgid "Unknown"
+msgstr "Íåèçâåñòíî"
+
+#, c-format
+msgid "E742: Cannot change value of %s"
+msgstr "E742: Íåâîçìîæíî èçìåíèòü çíà÷åíèå %s"
+
+msgid "E698: variable nested too deep for making a copy"
+msgstr "E698: Ñëèøêîì ãëóáîêî âëîæåííûå ïåðåìåííûå äëÿ êîïèðîâàíèÿ"
+
+msgid ""
+"\n"
+"# global variables:\n"
+msgstr ""
+"\n"
+"# ãëîáàëüíûå ïåðåìåííûå:\n"
+
+msgid ""
+"\n"
+"\tLast set from "
+msgstr ""
+"\n"
+"\t ïîñëåäíèé ðàç îïöèÿ èçìåíåíà â "
+
+msgid "E691: Can only compare List with List"
+msgstr "E691: Ñïèñîê ìîæíî ñðàâíèâàòü òîëüêî ñî ñïèñêîì"
+
+msgid "E692: Invalid operation for List"
+msgstr "E692: Íåäîïóñòèìàÿ îïåðàöèÿ äëÿ ñïèñêîâ"
+
+msgid "E735: Can only compare Dictionary with Dictionary"
+msgstr "E735: Ñëîâàðü ìîæíî ñðàâíèâàòü òîëüêî ñî ñëîâàð¸ì"
+
+msgid "E736: Invalid operation for Dictionary"
+msgstr "E736: Íåäîïóñòèìàÿ îïåðàöèÿ äëÿ ñëîâàðÿ"
+
+msgid "E694: Invalid operation for Funcrefs"
+msgstr "E694: Íåäîïóñòèìàÿ îïåðàöèÿ äëÿ ññûëêè íà ôóíêöèþ"
+
+msgid "map() argument"
+msgstr "ïàðàìåòðà map()"
+
+msgid "filter() argument"
+msgstr "ïàðàìåòðà filter()"
+
+#, c-format
+msgid "E686: Argument of %s must be a List"
+msgstr "E686: Ïàðàìåòð %s äîëæåí áûòü ñïèñêîì"
+
+msgid "E928: String required"
+msgstr "E928: Òðåáóåòñÿ ñòðîêà"
+
+msgid "E808: Number or Float required"
+msgstr "E808: Òðåáóåòñÿ öåëîå ÷èñëî èëè ñ ïëàâàþùåé òî÷êîé"
+
+msgid "add() argument"
+msgstr "ïàðàìåòðà add()"
+
+msgid "E785: complete() can only be used in Insert mode"
+msgstr "E785: complete() ìîæåò èñïîëüçîâàòüñÿ òîëüêî â ðåæèìå Âñòàâêè"
+
+msgid "&Ok"
+msgstr "&Ok"
+
+#, c-format
+msgid "+-%s%3ld line: "
+msgid_plural "+-%s%3ld lines: "
+msgstr[0] "+-%s%3ld ñòðîêà: "
+msgstr[1] "+-%s%3ld ñòðîêè: "
+msgstr[2] "+-%s%3ld ñòðîê: "
+
+#, c-format
+msgid "E700: Unknown function: %s"
+msgstr "E700: Íåèçâåñòíàÿ ôóíêöèÿ: %s"
+
+msgid "E922: expected a dict"
+msgstr "E922: Îæèäàëñÿ ñëîâàðü"
+
+msgid "E923: Second argument of function() must be a list or a dict"
+msgstr "E923: Âòîðîé ïàðàìåòð ôóíêöèè() äîëæåí áûòü ñïèñêîì èëè ñëîâàð¸ì"
+
+msgid ""
+"&OK\n"
+"&Cancel"
+msgstr ""
+"&OK\n"
+"&C Îòìåíà"
+
+msgid "called inputrestore() more often than inputsave()"
+msgstr "Ôóíêöèÿ inputrestore() âûçûâàåòñÿ ÷àùå, ÷åì ôóíêöèÿ inputsave()"
+
+msgid "insert() argument"
+msgstr "ïàðàìåòðà insert()"
+
+msgid "E786: Range not allowed"
+msgstr "E786: Äèàïàçîí íå äîïóñêàåòñÿ"
+
+msgid "E916: not a valid job"
+msgstr "E916: Íåäîïóñòèìîå çàäàíèå"
+
+msgid "E701: Invalid type for len()"
+msgstr "E701: Íåïðàâèëüíûå òèï äëÿ len()"
+
+#, c-format
+msgid "E798: ID is reserved for \":match\": %ld"
+msgstr "E798: ID çàðåçåðâèðîâàí äëÿ \":match\": %ld"
+
+msgid "E726: Stride is zero"
+msgstr "E726: Íóëåâîé øàã"
+
+msgid "E727: Start past end"
+msgstr "E727: Íà÷àëî ïîñëå êîíöà"
+
+msgid "<empty>"
+msgstr "<ïóñòî>"
+
+msgid "E240: No connection to the X server"
+msgstr "E240: Íåò ñâÿçè ñ X-ñåðâåðîì"
+
+#, c-format
+msgid "E241: Unable to send to %s"
+msgstr "E241: Íå ìîãó îòïðàâèòü ñîîáùåíèå äëÿ %s"
+
+msgid "E277: Unable to read a server reply"
+msgstr "E277: Ñåðâåð íå îòâå÷àåò"
+
+msgid "E941: already started a server"
+msgstr "E941: Ñåðâåð óæå çàïóùåí"
+
+msgid "E942: +clientserver feature not available"
+msgstr "E942: Îñîáåííîñòü +clientserver íåäîñòóïíà"
+
+msgid "remove() argument"
+msgstr "ïàðàìåòðà remove()"
+
+msgid "E655: Too many symbolic links (cycle?)"
+msgstr "E655: Ñëèøêîì ìíîãî ñèìâîëè÷åñêèõ ññûëîê (öèêë?)"
+
+msgid "reverse() argument"
+msgstr "ïàðàìåòðà reverse()"
+
+msgid "E258: Unable to send to client"
+msgstr "E258: Íå ìîãó îòâåòèòü êëèåíòó"
+
+#, c-format
+msgid "E927: Invalid action: '%s'"
+msgstr "E927: Íåïðàâèëüíîå äåéñòâèå: '%s'"
+
+msgid "sort() argument"
+msgstr "ïàðàìåòðà sort()"
+
+msgid "uniq() argument"
+msgstr "ïàðàìåòðà uniq()"
+
+msgid "E702: Sort compare function failed"
+msgstr "E702: Íåóäà÷íîå çàâåðøåíèå ôóíêöèè ñðàâíåíèÿ ïðè ñîðòèðîâêå"
+
+msgid "E882: Uniq compare function failed"
+msgstr ""
+"E882: Íåóäà÷íîå çàâåðøåíèå ôóíêöèè ñðàâíåíèÿ ïðè ïðîâåðêå åäèíñòâåííîñòè"
+
+msgid "(Invalid)"
+msgstr "(Íåïðàâèëüíî)"
+
+#, c-format
+msgid "E935: invalid submatch number: %d"
+msgstr "E935: Íåäîïóñòèìûé íîìåð ïîäñîîòâåòñòâèÿ: %d"
+
+msgid "E677: Error writing temp file"
+msgstr "E677: Îøèáêà çàïèñè âî âðåìåííûé ôàéë"
+
+msgid "E921: Invalid callback argument"
+msgstr "E921: Íåäîïóñòèìûé ïàðàìåòð îáðàòíîãî âûçîâà"
+
+#, c-format
+msgid "<%s>%s%s %d, Hex %02x, Oct %03o, Digr %s"
+msgstr "<%s>%s%s %d, Øåñ %02x, Âîñ %03o, Äèãð %s"
+
+#, c-format
+msgid "<%s>%s%s %d, Hex %02x, Octal %03o"
+msgstr "<%s>%s%s %d, Øåñ %02x, Âîñ %03o"
+
+#, c-format
+msgid "> %d, Hex %04x, Oct %o, Digr %s"
+msgstr "> %d, Øåñ %04x, Âîñ %o, Äèãð %s"
+
+#, c-format
+msgid "> %d, Hex %08x, Oct %o, Digr %s"
+msgstr "> %d, Øåñ %08x, Âîñ %o, Äèãð %s"
+
+#, c-format
+msgid "> %d, Hex %04x, Octal %o"
+msgstr "> %d, Øåñ %04x, Âîñ %o"
+
+#, c-format
+msgid "> %d, Hex %08x, Octal %o"
+msgstr "> %d, Øåñ %08x, Âîñ %o"
+
+msgid "E134: Move lines into themselves"
+msgstr "E134: Ñòðîêè ïåðåìåùàþòñÿ ñàìè íà ñåáÿ"
+
+msgid "1 line moved"
+msgstr "Ïåðåìåùåíà îäíà ñòðîêà"
+
+#, c-format
+msgid "%ld lines moved"
+msgstr "Ïåðåìåùåíî ñòðîê: %ld"
+
+#, c-format
+msgid "%ld lines filtered"
+msgstr "Ïðîïóùåíî ÷åðåç ôèëüòð ñòðîê: %ld"
+
+msgid "E135: *Filter* Autocommands must not change current buffer"
+msgstr "E135: Àâòîêîìàíäû *Filter* íå äîëæíû èçìåíÿòü àêòèâíûé áóôåð"
+
+msgid "[No write since last change]\n"
+msgstr "[Èçìåíåíèÿ íå ñîõðàíåíû]\n"
+
+#, c-format
+msgid "%sviminfo: %s in line: "
+msgstr "%sviminfo: %s â ñòðîêå: "
+
+msgid "E136: viminfo: Too many errors, skipping rest of file"
+msgstr ""
+"E136: viminfo: Ñëèøêîì ìíîãî îøèáîê, îñòàëüíàÿ ÷àñòü ôàéëà áóäåò ïðîïóùåíà"
+
+#, c-format
+msgid "Reading viminfo file \"%s\"%s%s%s"
+msgstr "×òåíèå ôàéëà viminfo \"%s\"%s%s%s"
+
+msgid " info"
+msgstr " èíôî"
+
+msgid " marks"
+msgstr " îòìåòîê"
+
+msgid " oldfiles"
+msgstr " ñòàðûõ ôàéëîâ"
+
+msgid " FAILED"
+msgstr " ÍÅÓÄÀ×ÍÎ"
+
+#, c-format
+msgid "E137: Viminfo file is not writable: %s"
+msgstr "E137: Ïðàâà íà çàïèñü ôàéëà viminfo îòñóòñòâóþò: %s"
+
+#, c-format
+msgid "E929: Too many viminfo temp files, like %s!"
+msgstr "E929: Ñëèøêîì ìíîãî âðåìåííûõ ôàéëîâ viminfo, òàêèõ êàê %s"
+
+#, c-format
+msgid "E138: Can't write viminfo file %s!"
+msgstr "E138: Íåâîçìîæíî çàïèñàòü ôàéë viminfo %s!"
+
+#, c-format
+msgid "Writing viminfo file \"%s\""
+msgstr "Çàïèñü ôàéëà viminfo \"%s\""
+
+#, c-format
+msgid "E886: Can't rename viminfo file to %s!"
+msgstr "E886: Íåâîçìîæíî ïåðåèìåíîâàòü ôàéë viminfo â %s!"
+
+#, c-format
+msgid "# This viminfo file was generated by Vim %s.\n"
+msgstr "# Ýòîò ôàéë viminfo àâòîìàòè÷åñêè ñîçäàí Vim %s.\n"
+
+msgid ""
+"# You may edit it if you're careful!\n"
+"\n"
+msgstr ""
+"# Åãî ìîæíî (îñòîðîæíî!) ðåäàêòèðîâàòü.\n"
+"\n"
+
+msgid "# Value of 'encoding' when this file was written\n"
+msgstr "# Çíà÷åíèå îïöèè 'encoding' â ìîìåíò çàïèñè ôàéëà\n"
+
+msgid "Illegal starting char"
+msgstr "Íåäîïóñòèìûé íà÷àëüíûé ñèìâîë"
+
+msgid ""
+"\n"
+"# Bar lines, copied verbatim:\n"
+msgstr ""
+"\n"
+"# Ñòðîê ñ '|', òî÷íî ñêîïèðîâàíî:\n"
+
+msgid "Save As"
+msgstr "Ñîõðàíèòü êàê"
+
+msgid "Write partial file?"
+msgstr "Çàïèñàòü ôàéë ÷àñòè÷íî?"
+
+msgid "E140: Use ! to write partial buffer"
+msgstr "E140: Äëÿ çàïèñè ÷àñòè áóôåðà èñïîëüçóéòå !"
+
+#, c-format
+msgid "Overwrite existing file \"%s\"?"
+msgstr "Ïåðåçàïèñàòü ñóùåñòâóþùèé ôàéë \"%s\"?"
+
+#, c-format
+msgid "Swap file \"%s\" exists, overwrite anyway?"
+msgstr "Ñâîï-ôàéë \"%s\" ñóùåñòâóåò, ïåðåçàïèñàòü?"
+
+#, c-format
+msgid "E768: Swap file exists: %s (:silent! overrides)"
+msgstr "E768: Ñâîï-ôàéë ñóùåñòâóåò: %s (:silent! ÷òîáû îáîéòè ïðîâåðêó)"
+
+#, c-format
+msgid "E141: No file name for buffer %ld"
+msgstr "E141: Áóôåð %ld íå ñâÿçàí ñ èìåíåì ôàéëà"
+
+msgid "E142: File not written: Writing is disabled by 'write' option"
+msgstr "E142: Ôàéë íå ñîõðàí¸í: çàïèñü îòêëþ÷åíà îïöèåé 'write'"
+
+#, c-format
+msgid ""
+"'readonly' option is set for \"%s\".\n"
+"Do you wish to write anyway?"
+msgstr ""
+"Äëÿ \"%s\" âêëþ÷åíà îïöèÿ 'readonly'.\n"
+"Çàïèñàòü?"
+
+#, c-format
+msgid ""
+"File permissions of \"%s\" are read-only.\n"
+"It may still be possible to write it.\n"
+"Do you wish to try?"
+msgstr ""
+"Ôàéë \"%s\" èìååò ðåæèì äîñòóïà òîëüêî äëÿ ÷òåíèÿ.\n"
+"Íî, âîçìîæíî, ôàéë óäàñòñÿ çàïèñàòü.\n"
+"Õîòèòå ïîïðîáîâàòü?"
+
+#, c-format
+msgid "E505: \"%s\" is read-only (add ! to override)"
+msgstr ""
+"E505: \"%s\" îòêðûò òîëüêî äëÿ ÷òåíèÿ (äîáàâüòå !, ÷òîáû îáîéòè ïðîâåðêó)"
+
+msgid "Edit File"
+msgstr "Ðåäàêòèðîâàíèå ôàéëà"
+
+#, c-format
+msgid "E143: Autocommands unexpectedly deleted new buffer %s"
+msgstr "E143: Àâòîêîìàíäû íåîæèäàííî óáèëè íîâûé áóôåð %s"
+
+msgid "E144: non-numeric argument to :z"
+msgstr "E144: Ïàðàìåòð êîìàíäû :z äîëæåí áûòü ÷èñëîì"
+
+msgid "E145: Shell commands not allowed in rvim"
+msgstr "E145: Èñïîëüçîâàíèå êîìàíä îáîëî÷êè íå äîïóñêàåòñÿ â rvim."
+
+msgid "E146: Regular expressions can't be delimited by letters"
+msgstr "E146: Ðåãóëÿðíûå âûðàæåíèÿ íå ìîãóò ðàçäåëÿòüñÿ áóêâàìè"
+
+#, c-format
+msgid "replace with %s (y/n/a/q/l/^E/^Y)?"
+msgstr "çàìåíèòü íà %s? (y/n/a/q/l/^E/^Y)"
+
+msgid "(Interrupted) "
+msgstr "(Ïðåðâàíî)"
+
+msgid "1 match"
+msgstr "Îäíî ñîîòâåòñòâèå"
+
+msgid "1 substitution"
+msgstr "Îäíà çàìåíà"
+
+#, c-format
+msgid "%ld matches"
+msgstr "%ld ñîîòâåòñòâèé"
+
+#, c-format
+msgid "%ld substitutions"
+msgstr "%ld çàìåí"
+
+msgid " on 1 line"
+msgstr " â 1 ñòð."
+
+#, c-format
+msgid " on %ld lines"
+msgstr " â %ld ñòð."
+
+msgid "E147: Cannot do :global recursive with a range"
+msgstr "E147: Íåâîçìîæíî âûïîëíèòü :global ðåêóðñèâíî ñ äèàïàçîíîì"
+
+msgid "E148: Regular expression missing from global"
+msgstr "E148: Â êîìàíäå :global ïðîïóùåíî ðåãóëÿðíîå âûðàæåíèå"
+
+#, c-format
+msgid "Pattern found in every line: %s"
+msgstr "Ñîîòâåòñòâèå øàáëîíó íàéäåíî íà êàæäîé ñòðîêå: %s"
+
+#, c-format
+msgid "Pattern not found: %s"
+msgstr "Øàáëîí íå íàéäåí: %s"
+
+msgid ""
+"\n"
+"# Last Substitute String:\n"
+"$"
+msgstr ""
+"\n"
+"# Ïîñëåäíÿÿ ñòðîêà äëÿ çàìåíû:\n"
+"$"
+
+msgid "E478: Don't panic!"
+msgstr "E478: Ñïîêîéñòâèå, òîëüêî ñïîêîéñòâèå!"
+
+#, c-format
+msgid "E661: Sorry, no '%s' help for %s"
+msgstr "E661: Ê ñîæàëåíèþ, ñïðàâêà '%s' äëÿ %s îòñóòñòâóåò"
+
+#, c-format
+msgid "E149: Sorry, no help for %s"
+msgstr "E149: Ê ñîæàëåíèþ ñïðàâêà äëÿ %s îòñóòñòâóåò"
+
+#, c-format
+msgid "Sorry, help file \"%s\" not found"
+msgstr "Èçâèíèòå, ôàéë ñïðàâêè \"%s\" íå íàéäåí"
+
+#, c-format
+msgid "E151: No match: %s"
+msgstr "E151: Íåò ñîîòâåòñòâèÿ: %s"
+
+#, c-format
+msgid "E152: Cannot open %s for writing"
+msgstr "E152: Íåâîçìîæíî îòêðûòü %s äëÿ çàïèñè"
+
+#, c-format
+msgid "E153: Unable to open %s for reading"
+msgstr "E153: Íåâîçìîæíî îòêðûòü %s äëÿ ÷òåíèÿ"
+
+#, c-format
+msgid "E670: Mix of help file encodings within a language: %s"
+msgstr "E670: Ôàéëû ñïðàâêè èñïîëüçóþò ðàçíûå êîäèðîâêè äëÿ îäíîãî ÿçûêà: %s"
+
+#, c-format
+msgid "E154: Duplicate tag \"%s\" in file %s/%s"
+msgstr "E154: Ïîâòîðÿþùàÿñÿ ìåòêà \"%s\" â ôàéëå %s/%s"
+
+#, c-format
+msgid "E150: Not a directory: %s"
+msgstr "E150: %s íå ÿâëÿåòñÿ êàòàëîãîì"
+
+#, c-format
+msgid "E160: Unknown sign command: %s"
+msgstr "E160: Íåèçâåñòíàÿ êîìàíäà çíà÷êà %s"
+
+msgid "E156: Missing sign name"
+msgstr "E156: Ïðîïóùåíî èìÿ çíà÷êà"
+
+msgid "E612: Too many signs defined"
+msgstr "E612: Îïðåäåëåíî ñëèøêîì ìíîãî çíà÷êîâ"
+
+#, c-format
+msgid "E239: Invalid sign text: %s"
+msgstr "E239: Íåïðàâèëüíûé òåêñò çíà÷êà: %s"
+
+#, c-format
+msgid "E155: Unknown sign: %s"
+msgstr "E155: Íåèçâåñòíûé çíà÷îê: %s"
+
+msgid "E159: Missing sign number"
+msgstr "E159: Ïðîïóùåí íîìåð çíà÷êà"
+
+#, c-format
+msgid "E158: Invalid buffer name: %s"
+msgstr "E158: Íåïðàâèëüíîå èìÿ áóôåðà: %s"
+
+msgid "E934: Cannot jump to a buffer that does not have a name"
+msgstr "E934: Íåâîçìîæíî ïåðåéòè ê áóôåðó áåç èìåíè"
+
+#, c-format
+msgid "E157: Invalid sign ID: %ld"
+msgstr "E157: Íåïðàâèëüíûé ID çíà÷êà: %ld"
+
+#, c-format
+msgid "E885: Not possible to change sign %s"
+msgstr "E885: Íåâîçìîæíî èçìåíèòü çíà÷îê %s"
+
+msgid " (NOT FOUND)"
+msgstr " (ÍÅ ÍÀÉÄÅÍÎ)"
+
+msgid " (not supported)"
+msgstr " (íå ïîääåðæèâàåòñÿ)"
+
+msgid "[Deleted]"
+msgstr "[Óäàëåíî]"
+
+msgid "No old files"
+msgstr "Íåò ñòàðûõ ôàéëîâ"
+
+msgid "Entering Debug mode. Type \"cont\" to continue."
+msgstr "Âêëþ÷¸í ðåæèì îòëàäêè. Äëÿ ïðîäîëæåíèÿ íàáåðèòå \"cont\""
+
+#, c-format
+msgid "Oldval = \"%s\""
+msgstr "Ïðåæ.çí. = \"%s\""
+
+#, c-format
+msgid "Newval = \"%s\""
+msgstr "Íîâ.çí. = \"%s\""
+
+#, c-format
+msgid "line %ld: %s"
+msgstr "ñòðîêà %ld: %s"
+
+#, c-format
+msgid "cmd: %s"
+msgstr "êîìàíäà: %s"
+
+msgid "frame is zero"
+msgstr "íóëåâîé ôðåéì"
+
+#, c-format
+msgid "frame at highest level: %d"
+msgstr "ìàêñèìàëüíûé ôðåéì: %d"
+
+#, c-format
+msgid "Breakpoint in \"%s%s\" line %ld"
+msgstr "Òî÷êà îñòàíîâêè â \"%s%s\" ñòð. %ld"
+
+#, c-format
+msgid "E161: Breakpoint not found: %s"
+msgstr "E161: Òî÷êà îñòàíîâêè íå íàéäåíà: %s"
+
+msgid "No breakpoints defined"
+msgstr "Òî÷êè îñòàíîâêè íå îïðåäåëåíû"
+
+#, c-format
+msgid "%3d %s %s line %ld"
+msgstr "%3d %s %s ñòð. %ld"
+
+#, c-format
+msgid "%3d expr %s"
+msgstr "%3d âûð. %s"
+
+msgid "E750: First use \":profile start {fname}\""
+msgstr "E750: Ïåðâîå èñïîëüçîâàíèå \":profile start {èìÿ-ôàéëà}\""
+
+#, c-format
+msgid "Save changes to \"%s\"?"
+msgstr "Ñîõðàíèòü èçìåíåíèÿ â \"%s\"?"
+
+#, c-format
+msgid "E947: Job still running in buffer \"%s\""
+msgstr "E947: Çàäàíèå åù¸ âûïîëíÿåòñÿ â áóôåðå \"%s\""
+
+#, c-format
+msgid "E162: No write since last change for buffer \"%s\""
+msgstr "E162: Íåñîõðàí¸ííûå èçìåíåíèÿ â áóôåðå \"%s\""
+
+msgid "Warning: Entered other buffer unexpectedly (check autocommands)"
+msgstr ""
+"Ïðåäóïðåæäåíèå: Íåîæèäàííûé ïåðåõîä â äðóãîé áóôåð (ïðîâåðüòå àâòîêîìàíäû)"
+
+msgid "E163: There is only one file to edit"
+msgstr "E163: Äëÿ ðåäàêòèðîâàíèÿ äîñòóïåí òîëüêî îäèí ôàéë"
+
+msgid "E164: Cannot go before first file"
+msgstr "E164: Ýòî ïåðâûé ôàéë"
+
+msgid "E165: Cannot go beyond last file"
+msgstr "E165: Ýòî ïîñëåäíèé ôàéë"
+
+#, c-format
+msgid "E666: compiler not supported: %s"
+msgstr "E666: Êîìïèëÿòîð íå ïîääåðæèâàåòñÿ: %s"
+
+#, c-format
+msgid "Searching for \"%s\" in \"%s\""
+msgstr "Ïîèñê \"%s\" â \"%s\""
+
+#, c-format
+msgid "Searching for \"%s\""
+msgstr "Ïîèñê \"%s\""
+
+#, c-format
+msgid "not found in '%s': \"%s\""
+msgstr "íå íàéäåíî â '%s': \"%s\""
+
+#, c-format
+msgid "W20: Required python version 2.x not supported, ignoring file: %s"
+msgstr ""
+"W20: Íå ïîääåðæèâàåòñÿ python òðåáóåìîé âåðñèè 2.x, ôàéë ïðîèãíîðèðîâàí: %s"
+
+#, c-format
+msgid "W21: Required python version 3.x not supported, ignoring file: %s"
+msgstr ""
+"W21: Íå ïîääåðæèâàåòñÿ python òðåáóåìîé âåðñèè 3.x, ôàéë ïðîèãíîðèðîâàí: %s"
+
+msgid "Source Vim script"
+msgstr "Âûïîëíèòü ñöåíàðèé Vim"
+
+#, c-format
+msgid "Cannot source a directory: \"%s\""
+msgstr "Íåëüçÿ ñ÷èòàòü êàòàëîã: \"%s\""
+
+#, c-format
+msgid "could not source \"%s\""
+msgstr "íåâîçìîæíî ñ÷èòàòü \"%s\""
+
+#, c-format
+msgid "line %ld: could not source \"%s\""
+msgstr "ñòðîêà %ld: íåâîçìîæíî ñ÷èòàòü \"%s\""
+
+#, c-format
+msgid "sourcing \"%s\""
+msgstr "ñ÷èòûâàíèå ñöåíàðèÿ \"%s\""
+
+#, c-format
+msgid "line %ld: sourcing \"%s\""
+msgstr "ñòðîêà %ld: ñ÷èòûâàíèå \"%s\""
+
+#, c-format
+msgid "finished sourcing %s"
+msgstr "ñ÷èòûâàíèå ñöåíàðèÿ %s çàâåðøåíî"
+
+#, c-format
+msgid "continuing in %s"
+msgstr "ïðîäîëæåíèå â %s"
+
+msgid "modeline"
+msgstr "ðåæèìíàÿ ñòðîêà"
+
+msgid "--cmd argument"
+msgstr "--cmd ïàðàìåòð"
+
+msgid "-c argument"
+msgstr "-c ïàðàìåòð"
+
+msgid "environment variable"
+msgstr "ïåðåìåííàÿ îêðóæåíèÿ"
+
+msgid "error handler"
+msgstr "îáðàáîò÷èê îøèáêè"
+
+msgid "W15: Warning: Wrong line separator, ^M may be missing"
+msgstr ""
+"W15: Ïðåäóïðåæäåíèå: íåïðàâèëüíûé ðàçäåëèòåëü ñòðîêè. Âîçìîæíî ïðîïóùåíî ^M"
+
+msgid "E167: :scriptencoding used outside of a sourced file"
+msgstr "E167: Êîìàíäà :scriptencoding èñïîëüçóåòñÿ âíå ôàéëà ñöåíàðèÿ"
+
+msgid "E168: :finish used outside of a sourced file"
+msgstr "E168: Êîìàíäà :finish èñïîëüçóåòñÿ âíå ôàéëà ñöåíàðèÿ"
+
+#, c-format
+msgid "Current %slanguage: \"%s\""
+msgstr "Àêòèâíûé %sÿçûê: \"%s\""
+
+#, c-format
+msgid "E197: Cannot set language to \"%s\""
+msgstr "E197: Íåâîçìîæíî ñìåíèòü ÿçûê íà \"%s\""
+
+msgid "Entering Ex mode. Type \"visual\" to go to Normal mode."
+msgstr "Ïåðåõîä â ðåæèì Ex. Äëÿ ïåðåõîäà â Îáû÷íûé ðåæèì íàáåðèòå \"visual\""
+
+msgid "E501: At end-of-file"
+msgstr "E501: Â êîíöå ôàéëà"
+
+msgid "E169: Command too recursive"
+msgstr "E169: Ñëèøêîì ðåêóðñèâíàÿ êîìàíäà"
+
+#, c-format
+msgid "E605: Exception not caught: %s"
+msgstr "E605: Èñêëþ÷èòåëüíàÿ ñèòóàöèÿ íå îáðàáîòàíà: %s"
+
+msgid "End of sourced file"
+msgstr "Êîíåö ñ÷èòàííîãî ôàéëà"
+
+msgid "End of function"
+msgstr "Êîíåö ôóíêöèè"
+
+msgid "E464: Ambiguous use of user-defined command"
+msgstr "E464: Íåîäíîçíà÷íîå èñïîëüçîâàíèå êîìàíäû ïîëüçîâàòåëÿ"
+
+msgid "E492: Not an editor command"
+msgstr "E492: Ýòî íå êîìàíäà ðåäàêòîðà"
+
+msgid "E493: Backwards range given"
+msgstr "E493: Çàäàí îáðàòíûé äèàïàçîí"
+
+msgid "Backwards range given, OK to swap"
+msgstr "Çàäàí îáðàòíûé äèàïàçîí, ìåíÿåì ãðàíèöû ìåñòàìè"
+
+msgid "E494: Use w or w>>"
+msgstr "E494: Èñïîëüçóéòå w èëè w>>"
+
+msgid "E943: Command table needs to be updated, run 'make cmdidxs'"
+msgstr "E943: Òàáëèöà êîìàíä äîëæíà áûòü îáíîâëåíà, âûïîëíèòå 'make cmdidxs'"
+
+msgid "E319: Sorry, the command is not available in this version"
+msgstr "E319: Èçâèíèòå, ýòà êîìàíäà íåäîñòóïíà â äàííîé âåðñèè"
+
+msgid "1 more file to edit. Quit anyway?"
+msgstr "1 ôàéë îæèäàåò ðåäàêòèðîâàíèÿ. Âûéòè?"
+
+#, c-format
+msgid "%d more files to edit. Quit anyway?"
+msgstr "Åñòü íåîòðåäàêòèðîâàííûå ôàéëû (%d). Âûéòè?"
+
+msgid "E173: 1 more file to edit"
+msgstr "E173: 1 ôàéë îæèäàåò ðåäàêòèðîâàíèÿ."
+
+#, c-format
+msgid "E173: %ld more files to edit"
+msgstr "E173: Åñòü íåîòðåäàêòèðîâàííûå ôàéëû (%ld)."
+
+msgid "E174: Command already exists: add ! to replace it"
+msgstr "E174: Êîìàíäà óæå ñóùåñòâóåò. Äîáàâüòå ! äëÿ çàìåíû."
+
+msgid ""
+"\n"
+" Name Args Address Complete Definition"
+msgstr ""
+"\n"
+" Èìÿ Ïàðàì. Äèàï. Äîïîëí. Îïðåäåëåíèå"
+
+msgid "No user-defined commands found"
+msgstr "Êîìàíäû, îïðåäåë¸ííûå ïîëüçîâàòåëåì, íå îáíàðóæåíû."
+
+msgid "E175: No attribute specified"
+msgstr "E175: Ïàðàìåòð íå çàäàí"
+
+msgid "E176: Invalid number of arguments"
+msgstr "E176: Íåïðàâèëüíîå êîëè÷åñòâî ïàðàìåòðîâ"
+
+msgid "E177: Count cannot be specified twice"
+msgstr "E177: ×èñëî-ïðèñòàâêó íåëüçÿ óêàçûâàòü äâàæäû"
+
+msgid "E178: Invalid default value for count"
+msgstr "E178: Íåïðàâèëüíîå çíà÷åíèå ÷èñëà-ïðèñòàâêè ïî óìîë÷àíèþ"
+
+msgid "E179: argument required for -complete"
+msgstr "E179: Äëÿ -complete òðåáóåòñÿ óêàçàòü ïàðàìåòð"
+
+msgid "E179: argument required for -addr"
+msgstr "E179: Äëÿ -addr òðåáóåòñÿ óêàçàòü ïàðàìåòð"
+
+#, c-format
+msgid "E181: Invalid attribute: %s"
+msgstr "E181: Íåïðàâèëüíûé àòðèáóò: %s"
+
+msgid "E182: Invalid command name"
+msgstr "E182: Íåïðàâèëüíîå èìÿ êîìàíäû"
+
+msgid "E183: User defined commands must start with an uppercase letter"
+msgstr "E183: Êîìàíäà ïîëüçîâàòåëÿ äîëæíà íà÷èíàòüñÿ ñ çàãëàâíîé áóêâû"
+
+msgid "E841: Reserved name, cannot be used for user defined command"
+msgstr ""
+"E841: Çàðåçåðâèðîâàííîå èìÿ íå ìîæåò èñïîëüçîâàòüñÿ äëÿ êîìàíä ïîëüçîâàòåëÿ"
+
+#, c-format
+msgid "E184: No such user-defined command: %s"
+msgstr "E184: Íåò òàêîé êîìàíäû ïîëüçîâàòåëÿ: %s"
+
+#, c-format
+msgid "E180: Invalid address type value: %s"
+msgstr "E180: Íåïðàâèëüíîå çíà÷åíèå òèïà àäðåñà: %s"
+
+#, c-format
+msgid "E180: Invalid complete value: %s"
+msgstr "E180: Íåïðàâèëüíîå çíà÷åíèå äîïîëíåíèÿ: %s"
+
+msgid "E468: Completion argument only allowed for custom completion"
+msgstr ""
+"E468: Ïàðàìåòð àâòîäîïîëíåíèÿ ìîæíî èñïîëüçîâàòü òîëüêî ñ îñîáûì äîïîëíåíèåì"
+
+msgid "E467: Custom completion requires a function argument"
+msgstr "E467: Îñîáîå äîïîëíåíèå òðåáóåò óêàçàíèÿ ïàðàìåòðà ôóíêöèè"
+
+msgid "unknown"
+msgstr "íåèçâåñòíî"
+
+#, c-format
+msgid "E185: Cannot find color scheme '%s'"
+msgstr "E185: Íåâîçìîæíî íàéòè öâåòîâóþ ñõåìó '%s'"
+
+msgid "Greetings, Vim user!"
+msgstr "Ïðèâåòñòâóåì âàñ, ïîëüçîâàòåëü Vim!"
+
+msgid "E784: Cannot close last tab page"
+msgstr "E784: Íåëüçÿ çàêðûòü ïîñëåäíþþ âêëàäêó"
+
+msgid "Already only one tab page"
+msgstr "Íà ýêðàíå âñåãî îäíà âêëàäêà"
+
+msgid "Edit File in new window"
+msgstr "Ðåäàêòèðîâàòü ôàéë â íîâîì îêíå"
+
+#, c-format
+msgid "Tab page %d"
+msgstr "Âêëàäêà %d"
+
+msgid "No swap file"
+msgstr "Áåç ñâîï-ôàéëà"
+
+msgid "Append File"
+msgstr "Äîáàâèòü ôàéë"
+
+msgid "E747: Cannot change directory, buffer is modified (add ! to override)"
+msgstr ""
+"E747: Ñìåíà êàòàëîãà íåâîçìîæíà, áóôåð èçìåí¸í (äîáàâüòå !, ÷òîáû îáîéòè "
+"ïðîâåðêó)"
+
+msgid "E186: No previous directory"
+msgstr "E186: Íåò ïðåäûäóùåãî êàòàëîãà"
+
+msgid "E187: Unknown"
+msgstr "E187: Íåèçâåñòíî"
+
+msgid "E465: :winsize requires two number arguments"
+msgstr "E465: Êîìàíäà :winsize òðåáóåò óêàçàíèÿ äâóõ ÷èñëîâûõ ïàðàìåòðîâ"
+
+#, c-format
+msgid "Window position: X %d, Y %d"
+msgstr "Ïîëîæåíèå îêíà: X %d, Y %d"
+
+msgid "E188: Obtaining window position not implemented for this platform"
+msgstr "E188: Â äàííîé ñèñòåìå îïðåäåëåíèå ïîëîæåíèÿ îêíà íå ðàáîòàåò"
+
+msgid "E466: :winpos requires two number arguments"
+msgstr "E466: Êîìàíäà :winpos òðåáóåò óêàçàíèÿ äâóõ ÷èñëîâûõ ïàðàìåòðîâ"
+
+msgid "E930: Cannot use :redir inside execute()"
+msgstr "E930: Íåâîçìîæíî èñïîëüçîâàòü :redir âíóòðè execute()"
+
+msgid "Save Redirection"
+msgstr "Ïåðåíàïðàâëåíèå çàïèñè"
+
+msgid "Save View"
+msgstr "Ñîõðàíåíèå âèäà"
+
+msgid "Save Session"
+msgstr "Ñîõðàíåíèå ñåàíñà"
+
+msgid "Save Setup"
+msgstr "Ñîõðàíåíèå íàñòðîåê"
+
+#, c-format
+msgid "E739: Cannot create directory: %s"
+msgstr "E739: Íåâîçìîæíî ñîçäàòü êàòàëîã: %s"
+
+#, c-format
+msgid "E189: \"%s\" exists (add ! to override)"
+msgstr "E189: \"%s\" ñóùåñòâóåò (äîáàâüòå !, ÷òîáû îáîéòè ïðîâåðêó)"
+
+#, c-format
+msgid "E190: Cannot open \"%s\" for writing"
+msgstr "E190: Íåâîçìîæíî îòêðûòü äëÿ çàïèñè \"%s\""
+
+msgid "E191: Argument must be a letter or forward/backward quote"
+msgstr "E191: Ïàðàìåòð äîëæåí áûòü ïðÿìîé/îáðàòíîé êàâû÷êîé èëè áóêâîé"
+
+msgid "E192: Recursive use of :normal too deep"
+msgstr "E192: Ñëèøêîì ãëóáîêàÿ ðåêóðñèÿ ïðè èñïîëüçîâàíèè êîìàíäû :normal"
+
+msgid "E809: #< is not available without the +eval feature"
+msgstr "E809: #< íå äîñòóïíî áåç îñîáåííîñòè +eval"
+
+msgid "E194: No alternate file name to substitute for '#'"
+msgstr "E194: Íåò ñîñåäíåãî èìåíè ôàéëà äëÿ çàìåíû '#'"
+
+msgid "E495: no autocommand file name to substitute for \"<afile>\""
+msgstr "E495: Íåò àâòîêîìàíäíîãî èìåíè ôàéëà äëÿ çàìåíû \"<afile>\""
+
+msgid "E496: no autocommand buffer number to substitute for \"<abuf>\""
+msgstr "E496: Íåò àâòîêîìàíäíîãî íîìåðà áóôåðà äëÿ çàìåíû \"<abuf>\""
+
+msgid "E497: no autocommand match name to substitute for \"<amatch>\""
+msgstr "E497: Íåò àâòîêîìàíäíîãî èìåíè ñîîòâåòñòâèÿ äëÿ çàìåíû \"<amatch>\""
+
+msgid "E498: no :source file name to substitute for \"<sfile>\""
+msgstr "E498: Íåò èìåíè ôàéëà :source äëÿ çàìåíû \"<sfile>\""
+
+msgid "E842: no line number to use for \"<slnum>\""
+msgstr "E842: Íåò íîìåðà ñòðîêè äëÿ èñïîëüçîâàíèÿ \"<slnum>\""
+
+#, no-c-format
+msgid "E499: Empty file name for '%' or '#', only works with \":p:h\""
+msgstr "E499: Ïóñòîå èìÿ ôàéëà äëÿ '%' èëè '#', âîçìîæíî òîëüêî c \":p:h\""
+
+msgid "E500: Evaluates to an empty string"
+msgstr "E500: Ðåçóëüòàòîì âûðàæåíèÿ ÿâëÿåòñÿ ïóñòàÿ ñòðîêà"
+
+msgid "E195: Cannot open viminfo file for reading"
+msgstr "E195: Íåâîçìîæíî îòêðûòü ôàéë viminfo äëÿ ÷òåíèÿ"
+
+msgid "Untitled"
+msgstr "Áåç èìåíè"
+
+msgid "E196: No digraphs in this version"
+msgstr "E196: Â ýòîé âåðñèè äèãðàôû íå ðàáîòàþò"
+
+msgid "E608: Cannot :throw exceptions with 'Vim' prefix"
+msgstr ""
+"E608: Íåâîçìîæíî âûïîëíèòü êîìàíäó :throw äëÿ èñêëþ÷åíèé ñ ïðèñòàâêîé 'Vim'"
+
+#, c-format
+msgid "Exception thrown: %s"
+msgstr "Èñêëþ÷èòåëüíàÿ ñèòóàöèÿ: %s"
+
+#, c-format
+msgid "Exception finished: %s"
+msgstr "Çàâåðøåíà îáðàáîòêà èñêëþ÷èòåëüíîé ñèòóàöèè: %s"
+
+#, c-format
+msgid "Exception discarded: %s"
+msgstr "Èñêëþ÷èòåëüíàÿ ñèòóàöèÿ ïðîèãíîðèðîâàíà: %s"
+
+#, c-format
+msgid "%s, line %ld"
+msgstr "%s, ñòðîêà %ld"
+
+#, c-format
+msgid "Exception caught: %s"
+msgstr "Îáðàáîòêà èñêëþ÷èòåëüíîé ñèòóàöèè: %s"
+
+#, c-format
+msgid "%s made pending"
+msgstr "%s âûïîëíÿåò îæèäàíèå"
+
+#, c-format
+msgid "%s resumed"
+msgstr "%s âîçîáíîâëåíî"
+
+#, c-format
+msgid "%s discarded"
+msgstr "%s ïðîïóùåíî"
+
+msgid "Exception"
+msgstr "Èñêëþ÷èòåëüíàÿ ñèòóàöèÿ"
+
+msgid "Error and interrupt"
+msgstr "Îøèáêà è ïðåðûâàíèå"
+
+msgid "Error"
+msgstr "Îøèáêà"
+
+msgid "Interrupt"
+msgstr "Ïðåðûâàíèå"
+
+msgid "E579: :if nesting too deep"
+msgstr "E579: Ñëèøêîì ãëóáîêî âëîæåííûé :if"
+
+msgid "E580: :endif without :if"
+msgstr "E580: :endif áåç :if"
+
+msgid "E581: :else without :if"
+msgstr "E581: :else áåç :if"
+
+msgid "E582: :elseif without :if"
+msgstr "E582: :elseif áåç :if"
+
+msgid "E583: multiple :else"
+msgstr "E583: Îáíàðóæåíî íåñêîëüêî :else"
+
+msgid "E584: :elseif after :else"
+msgstr "E584: :elseif ïîñëå :else"
+
+msgid "E585: :while/:for nesting too deep"
+msgstr "E585: Ñëèøêîì ãëóáîêîå âëîæåíèå :while èëè :for"
+
+msgid "E586: :continue without :while or :for"
+msgstr "E586: :continue áåç :while èëè :for"
+
+msgid "E587: :break without :while or :for"
+msgstr "E587: :break áåç :while èëè :for"
+
+msgid "E732: Using :endfor with :while"
+msgstr "E732: Èñïîëüçîâàíèå :endfor ñ :while"
+
+msgid "E733: Using :endwhile with :for"
+msgstr "E733: Èñïîëüçîâàíèå :endwhile ñ :for"
+
+msgid "E601: :try nesting too deep"
+msgstr "E601: Ñëèøêîì ãëóáîêî âëîæåííûé :try"
+
+msgid "E603: :catch without :try"
+msgstr "E603: :catch áåç :try"
+
+msgid "E604: :catch after :finally"
+msgstr "E604: :catch ïîñëå :finally"
+
+msgid "E606: :finally without :try"
+msgstr "E606: :finally áåç :try"
+
+msgid "E607: multiple :finally"
+msgstr "E607: Îáíàðóæåíî íåñêîëüêî :finally"
+
+msgid "E602: :endtry without :try"
+msgstr "E602: :endtry áåç :try"
+
+msgid "E193: :endfunction not inside a function"
+msgstr "E193: Êîìàíäà :endfunction ìîæåò èñïîëüçîâàòüñÿ òîëüêî âíóòðè ôóíêöèè"
+
+msgid "E788: Not allowed to edit another buffer now"
+msgstr "E788: Ñåé÷àñ íå äîïóñêàåòñÿ ðåäàêòèðîâàíèå äðóãîãî áóôåðà"
+
+msgid "E811: Not allowed to change buffer information now"
+msgstr "E811: Ñåé÷àñ íå äîïóñêàåòñÿ èçìåíåíèå èíôîðìàöèè î áóôåðå"
+
+msgid "tagname"
+msgstr "èìÿ ìåòêè"
+
+msgid " kind file\n"
+msgstr " òèï ôàéëà\n"
+
+msgid "'history' option is zero"
+msgstr "çíà÷åíèå îïöèè 'history' ðàâíî íóëþ"
+
+#, c-format
+msgid ""
+"\n"
+"# %s History (newest to oldest):\n"
+msgstr ""
+"\n"
+"# %s, èñòîðèÿ (íà÷èíàÿ îò ñâåæåãî ê ñòàðîìó):\n"
+
+msgid "Command Line"
+msgstr "Êîìàíäíàÿ ñòðîêà"
+
+msgid "Search String"
+msgstr "Ñòðîêà ïîèñêà"
+
+msgid "Expression"
+msgstr "Âûðàæåíèå"
+
+msgid "Input Line"
+msgstr "Ñòðîêà ââîäà"
+
+msgid "Debug Line"
+msgstr "Ñòðîêà îòëàäêè"
+
+msgid "E198: cmd_pchar beyond the command length"
+msgstr "E198: cmd_pchar áîëüøå äëèíû êîìàíäû"
+
+msgid "E199: Active window or buffer deleted"
+msgstr "E199: Óäàëåíî àêòèâíîå îêíî èëè áóôåð"
+
+msgid "E812: Autocommands changed buffer or buffer name"
+msgstr "E812: Àâòîêîìàíäû èçìåíèëè áóôåð èëè èìÿ áóôåðà"
+
+msgid "Illegal file name"
+msgstr "Íåäîïóñòèìîå èìÿ ôàéëà"
+
+msgid "is a directory"
+msgstr "ÿâëÿåòñÿ êàòàëîãîì"
+
+msgid "is not a file"
+msgstr "íå ÿâëÿåòñÿ ôàéëîì"
+
+msgid "is a device (disabled with 'opendevice' option)"
+msgstr "ÿâëÿåòñÿ óñòðîéñòâîì (îòêëþ÷åíî ïðè îïöèè 'opendevice')"
+
+msgid "[New File]"
+msgstr "[Íîâûé ôàéë]"
+
+msgid "[New DIRECTORY]"
+msgstr "[Íîâûé ÊÀÒÀËÎÃ]"
+
+msgid "[File too big]"
+msgstr "[Ôàéë ñëèøêîì áîëüøîé]"
+
+msgid "[Permission Denied]"
+msgstr "[Äîñòóï çàïðåù¸í]"
+
+msgid "E200: *ReadPre autocommands made the file unreadable"
+msgstr "E200:  ðåçóëüòàòå âûïîëíåíèÿ àâòîêîìàíä *ReadPre ôàéë ñòàë íå÷èòàåìûì"
+
+msgid "E201: *ReadPre autocommands must not change current buffer"
+msgstr "E201: Àâòîêîìàíäû *ReadPre íå äîëæíû èçìåíÿòü àêòèâíûé áóôåð"
+
+msgid "Vim: Reading from stdin...\n"
+msgstr "Vim: ×òåíèå èç ñòàíäàðòíîãî ïîòîêà ââîäà stdin...\n"
+
+msgid "Reading from stdin..."
+msgstr "×òåíèå èç ñòàíäàðòíîãî ïîòîêà ââîäà stdin..."
+
+msgid "E202: Conversion made file unreadable!"
+msgstr "E202:  ðåçóëüòàòå ïðåîáðàçîâàíèÿ ôàéë ñòàë íå÷èòàåìûì!"
+
+msgid "[fifo/socket]"
+msgstr "[fifo/ãíåçäî]"
+
+msgid "[fifo]"
+msgstr "[fifo]"
+
+msgid "[socket]"
+msgstr "[ãíåçäî]"
+
+msgid "[character special]"
+msgstr "[ñïåöèàëüíûé ñèìâîëüíûé]"
+
+msgid "[CR missing]"
+msgstr "[ïðîïóùåíû ñèìâîëû CR]"
+
+msgid "[long lines split]"
+msgstr "[äëèííûå ñòðîêè ðàçáèòû]"
+
+msgid "[NOT converted]"
+msgstr "[ÁÅÇ ïðåîáðàçîâàíèé]"
+
+msgid "[converted]"
+msgstr "[ïåðåêîäèðîâàíî]"
+
+#, c-format
+msgid "[CONVERSION ERROR in line %ld]"
+msgstr "[ÎØÈÁÊÀ ÏÐÅÎÁÐÀÇÎÂÀÍÈß â ñòðîêå %ld]"
+
+#, c-format
+msgid "[ILLEGAL BYTE in line %ld]"
+msgstr "[ÍÅÄÎÏÓÑÒÈÌÛÉ ÁÀÉÒ â ñòðîêå %ld]"
+
+msgid "[READ ERRORS]"
+msgstr "[ÎØÈÁÊÈ ×ÒÅÍÈß]"
+
+msgid "Can't find temp file for conversion"
+msgstr "Âðåìåííûé ôàéë äëÿ ïåðåêîäèðîâàíèÿ íå íàéäåí"
+
+msgid "Conversion with 'charconvert' failed"
+msgstr "Ïðåîáðàçîâàíèå ñ ïîìîùüþ 'charconvert' íå âûïîëíåíî"
+
+msgid "can't read output of 'charconvert'"
+msgstr "íåâîçìîæíî ïðî÷èòàòü âûâîä 'charconvert'"
+
+msgid "E676: No matching autocommands for acwrite buffer"
+msgstr "E676: Íåò ïîäõîäÿùèõ àâòîêîìàíä äëÿ áóôåðà acwrite"
+
+msgid "E203: Autocommands deleted or unloaded buffer to be written"
+msgstr ""
+"E203: Áóôåð, êîòîðûé òðåáîâàëîñü çàïèñàòü, óäàë¸í èëè âûãðóæåí àâòîêîìàíäîé"
+
+msgid "E204: Autocommand changed number of lines in unexpected way"
+msgstr "E204: Êîëè÷åñòâî ñòðîê èçìåíåíî àâòîêîìàíäîé íåîæèäàííûì îáðàçîì"
+
+msgid "NetBeans disallows writes of unmodified buffers"
+msgstr "NetBeans íå ïîçâîëÿåò âûïîëíÿòü çàïèñü íåèçìåí¸ííûõ áóôåðîâ"
+
+msgid "Partial writes disallowed for NetBeans buffers"
+msgstr "×àñòè÷íàÿ çàïèñü áóôåðîâ NetBeans íå äîïóñêàåòñÿ"
+
+msgid "is not a file or writable device"
+msgstr "íå ÿâëÿåòñÿ ôàéëîì èëè óñòðîéñòâîì, äîñòóïíûì äëÿ çàïèñè"
+
+msgid "writing to device disabled with 'opendevice' option"
+msgstr "çàïèñü â óñòðîéñòâî îòêëþ÷åíà ïðè îïöèè 'opendevice'"
+
+msgid "is read-only (add ! to override)"
+msgstr "îòêðûò òîëüêî äëÿ ÷òåíèÿ (äîáàâüòå !, ÷òîáû îáîéòè ïðîâåðêó)"
+
+msgid "E506: Can't write to backup file (add ! to override)"
+msgstr ""
+"E506: Çàïèñü â ðåçåðâíûé ôàéë íåâîçìîæíà (äîáàâüòå !, ÷òîáû îáîéòè ïðîâåðêó)"
+
+msgid "E507: Close error for backup file (add ! to override)"
+msgstr ""
+"E507: Îøèáêà çàêðûòèÿ ðåçåðâíîãî ôàéëà (äîáàâüòå !, ÷òîáû îáîéòè ïðîâåðêó)"
+
+msgid "E508: Can't read file for backup (add ! to override)"
+msgstr ""
+"E508: Íåâîçìîæíî ïðî÷èòàòü ðåçåðâíûé ôàéë (äîáàâüòå !, ÷òîáû îáîéòè ïðîâåðêó)"
+
+msgid "E509: Cannot create backup file (add ! to override)"
+msgstr ""
+"E509: Íåâîçìîæíî ñîçäàòü ðåçåðâíûé ôàéë (äîáàâüòå !, ÷òîáû îáîéòè ïðîâåðêó)"
+
+msgid "E510: Can't make backup file (add ! to override)"
+msgstr ""
+"E510: Íåâîçìîæíî ñîçäàòü ðåçåðâíûé ôàéë (äîáàâüòå !, ÷òîáû îáîéòè ïðîâåðêó)"
+
+msgid "E214: Can't find temp file for writing"
+msgstr "E214: Âðåìåííûé ôàéë äëÿ çàïèñè íå íàéäåí"
+
+msgid "E213: Cannot convert (add ! to write without conversion)"
+msgstr ""
+"E213: Ïåðåêîäèðîâêà íåâîçìîæíà (äîáàâüòå ! äëÿ çàïèñè áåç ïåðåêîäèðîâêè)"
+
+msgid "E166: Can't open linked file for writing"
+msgstr "E166: Íåâîçìîæíî îòêðûòü ôàéë ïî ññûëêå äëÿ çàïèñè"
+
+msgid "E212: Can't open file for writing"
+msgstr "E212: Íåâîçìîæíî îòêðûòü ôàéë äëÿ çàïèñè"
+
+msgid "E949: File changed while writing"
+msgstr "E949: Ôàéë áûë èçìåí¸í ïîñëå çàïèñè"
+
+msgid "E512: Close failed"
+msgstr "E512: Îïåðàöèÿ çàêðûòèÿ íå óäàëàñü"
+
+msgid "E513: write error, conversion failed (make 'fenc' empty to override)"
+msgstr ""
+"E513: Îøèáêà çàïèñè, ïðåîáðàçîâàíèå íå óäàëîñü (î÷èñòèòå 'fenc', ÷òîáû "
+"îáîéòè)"
+
+#, c-format
+msgid ""
+"E513: write error, conversion failed in line %ld (make 'fenc' empty to "
+"override)"
+msgstr ""
+"E513: Îøèáêà çàïèñè, ïðåîáðàçîâàíèå íå óäàëîñü íà ñòðîêå %ld (î÷èñòèòå "
+"'fenc', ÷òîáû îáîéòè)"
+
+msgid "E514: write error (file system full?)"
+msgstr "E514: Îøèáêà çàïèñè (íåò ñâîáîäíîãî ìåñòà?)"
+
+msgid " CONVERSION ERROR"
+msgstr " ÎØÈÁÊÀ ÏÐÅÎÁÐÀÇÎÂÀÍÈß"
+
+#, c-format
+msgid " in line %ld;"
+msgstr " íà ñòðîêå %ld;"
+
+msgid "[Device]"
+msgstr "[Óñòðîéñòâî]"
+
+msgid "[New]"
+msgstr "[Íîâûé]"
+
+msgid " [a]"
+msgstr " [ä]"
+
+msgid " appended"
+msgstr " äîáàâëåíî"
+
+msgid " [w]"
+msgstr " [ç]"
+
+msgid " written"
+msgstr " çàïèñàíî"
+
+msgid "E205: Patchmode: can't save original file"
+msgstr "E205: Ðåæèì çàïëàòêè: íåâîçìîæíî ñîõðàíåíèå èñõîäíîãî ôàéëà"
+
+msgid "E206: patchmode: can't touch empty original file"
+msgstr ""
+"E206: Ðåæèì çàïëàòêè: íåâîçìîæíî ñìåíèòü ïàðàìåòðû ïóñòîãî èñõîäíîãî ôàéëà"
+
+msgid "E207: Can't delete backup file"
+msgstr "E207: Íåâîçìîæíî óäàëèòü ðåçåðâíûé ôàéë"
+
+msgid ""
+"\n"
+"WARNING: Original file may be lost or damaged\n"
+msgstr ""
+"\n"
+"ÏÐÅÄÓÏÐÅÆÄÅÍÈÅ: Èñõîäíûé ôàéë ìîæåò áûòü óòðà÷åí èëè ïîâðåæä¸í\n"
+
+msgid "don't quit the editor until the file is successfully written!"
+msgstr "íå âûõîäèòå èç ðåäàêòîðà, ïîêà ôàéë íå áóäåò óñïåøíî çàïèñàí!"
+
+msgid "[dos]"
+msgstr "[dos]"
+
+msgid "[dos format]"
+msgstr "[ôîðìàò dos]"
+
+msgid "[mac]"
+msgstr "[mac]"
+
+msgid "[mac format]"
+msgstr "[ôîðìàò mac]"
+
+msgid "[unix]"
+msgstr "[unix]"
+
+msgid "[unix format]"
+msgstr "[ôîðìàò unix]"
+
+msgid "1 line, "
+msgstr "1 ñòðîêà, "
+
+#, c-format
+msgid "%ld lines, "
+msgstr "ñòðîê: %ld, "
+
+msgid "1 character"
+msgstr "1 ñèìâîë"
+
+#, c-format
+msgid "%lld characters"
+msgstr "ñèìâîëîâ: %lld"
+
+msgid "[noeol]"
+msgstr "[noeol]"
+
+msgid "[Incomplete last line]"
+msgstr "[Íåçàâåðø¸ííàÿ ïîñëåäíÿÿ ñòðîêà]"
+
+msgid "WARNING: The file has been changed since reading it!!!"
+msgstr "ÏÐÅÄÓÏÐÅÆÄÅÍÈÅ: Ôàéë èçìåí¸í ñ ìîìåíòà ÷òåíèÿ!!!"
+
+msgid "Do you really want to write to it"
+msgstr "Ñåðü¸çíî õîòèòå çàïèñàòü â ýòîò ôàéë"
+
+#, c-format
+msgid "E208: Error writing to \"%s\""
+msgstr "E208: Îøèáêà çàïèñè â \"%s\""
+
+#, c-format
+msgid "E209: Error closing \"%s\""
+msgstr "E209: Îøèáêà çàêðûòèÿ \"%s\""
+
+#, c-format
+msgid "E210: Error reading \"%s\""
+msgstr "E210: Îøèáêà ÷òåíèÿ \"%s\""
+
+msgid "E246: FileChangedShell autocommand deleted buffer"
+msgstr "E246: Áóôåð óäàë¸í ïðè âûïîëíåíèè àâòîêîìàíäû FileChangedShell"
+
+#, c-format
+msgid "E211: File \"%s\" no longer available"
+msgstr "E211: Ôàéë \"%s\" áîëüøå íå äîñòóïåí"
+
+#, c-format
+msgid ""
+"W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as "
+"well"
+msgstr ""
+"W12: Ïðåäóïðåæäåíèå: ôàéë \"%s\" è áóôåð Vim áûëè èçìåíåíû íåçàâèñèìî äðóã "
+"îò äðóãà"
+
+msgid "See \":help W12\" for more info."
+msgstr "Ñì. \":help W12\" äëÿ äîïîëíèòåëüíîé èíôîðìàöèè."
+
+#, c-format
+msgid "W11: Warning: File \"%s\" has changed since editing started"
+msgstr ""
+"W11: Ïðåäóïðåæäåíèå: ôàéë \"%s\" áûë èçìåí¸í ïîñëå íà÷àëà ðåäàêòèðîâàíèÿ"
+
+msgid "See \":help W11\" for more info."
+msgstr "Ñì. \":help W11\" äëÿ äîïîëíèòåëüíîé èíôîðìàöèè."
+
+#, c-format
+msgid "W16: Warning: Mode of file \"%s\" has changed since editing started"
+msgstr ""
+"W16: Ïðåäóïðåæäåíèå: ðåæèì äîñòóïà ê ôàéëó \"%s\" áûë èçìåí¸í ïîñëå íà÷àëà "
+"ðåäàêòèðîâàíèÿ"
+
+msgid "See \":help W16\" for more info."
+msgstr "Ñì. \":help W16\" äëÿ äîïîëíèòåëüíîé èíôîðìàöèè."
+
+#, c-format
+msgid "W13: Warning: File \"%s\" has been created after editing started"
+msgstr ""
+"W13: Ïðåäóïðåæäåíèå: ôàéë \"%s\" áûë ñîçäàí ïîñëå íà÷àëà ðåäàêòèðîâàíèÿ"
+
+msgid "Warning"
+msgstr "Ïðåäóïðåæäåíèå"
+
+msgid ""
+"&OK\n"
+"&Load File"
+msgstr ""
+"&OK\n"
+"&L Çàãðóçèòü ôàéë"
+
+#, c-format
+msgid "E462: Could not prepare for reloading \"%s\""
+msgstr "E462: Íåâîçìîæíî ïîäãîòîâèòüñÿ ê ïåðåçàãðóçêå \"%s\""
+
+#, c-format
+msgid "E321: Could not reload \"%s\""
+msgstr "E321: Íåâîçìîæíî âûïîëíèòü ïåðåçàãðóçêó \"%s\""
+
+msgid "--Deleted--"
+msgstr "--Óäàëåíî--"
+
+#, c-format
+msgid "auto-removing autocommand: %s <buffer=%d>"
+msgstr "àâòî-óäàëåíèå àâòîêîìàíäû: %s <áóôôåð=%d>"
+
+#, c-format
+msgid "E367: No such group: \"%s\""
+msgstr "E367: Ãðóïïà \"%s\" íå ñóùåñòâóåò"
+
+msgid "E936: Cannot delete the current group"
+msgstr "E936: Íåâîçìîæíî óäàëèòü òåêóùóþ ãðóïïó"
+
+msgid "W19: Deleting augroup that is still in use"
+msgstr "W19: Óäàëåíèå åù¸ èñïîëüçóåìîé ãðóïïû àâòîêîìàíä"
+
+#, c-format
+msgid "E215: Illegal character after *: %s"
+msgstr "E215: Íåäîïóñòèìûå ñèìâîëû ïîñëå *: %s"
+
+#, c-format
+msgid "E216: No such event: %s"
+msgstr "E216: Íåñóùåñòâóþùåå ñîáûòèå: %s"
+
+#, c-format
+msgid "E216: No such group or event: %s"
+msgstr "E216: Íåñóùåñòâóþùàÿ ãðóïïà èëè ñîáûòèå: %s"
+
+msgid ""
+"\n"
+"--- Autocommands ---"
+msgstr ""
+"\n"
+"--- Àâòîêîìàíäû ---"
+
+#, c-format
+msgid "E680: <buffer=%d>: invalid buffer number "
+msgstr "E680: <buffer=%d>: íåïðàâèëüíûé íîìåð áóôåðà "
+
+msgid "E217: Can't execute autocommands for ALL events"
+msgstr "E217: Íåâîçìîæíî âûïîëíèòü àâòîêîìàíäû äëÿ ÂÑÅÕ ñîáûòèé"
+
+msgid "No matching autocommands"
+msgstr "Íåò ïîäõîäÿùèõ àâòîêîìàíä"
+
+msgid "E218: autocommand nesting too deep"
+msgstr "E218: ñëèøêîì ãëóáîêî âëîæåííûå àâòîêîìàíäû"
+
+#, c-format
+msgid "%s Autocommands for \"%s\""
+msgstr "%s Àâòîêîìàíäû äëÿ \"%s\""
+
+#, c-format
+msgid "Executing %s"
+msgstr "Âûïîëíåíèå %s"
+
+#, c-format
+msgid "autocommand %s"
+msgstr "àâòîêîìàíäà %s"
+
+msgid "E219: Missing {."
+msgstr "E219: Ïðîïóùåíà {."
+
+msgid "E220: Missing }."
+msgstr "E220: Ïðîïóùåíà }."
+
+msgid "E490: No fold found"
+msgstr "E490: Ñêëàäîê íå îáíàðóæåíî"
+
+msgid "E350: Cannot create fold with current 'foldmethod'"
+msgstr ""
+"E350: Ñêëàäêà íå ìîæåò áûòü ñîçäàíà ñ òåêóùèì çíà÷åíèåì îïöèè 'foldmethod'"
+
+msgid "E351: Cannot delete fold with current 'foldmethod'"
+msgstr ""
+"E351: Ñêëàäêà íå ìîæåò áûòü óäàëåíà ñ òåêóùèì çíà÷åíèåì îïöèè 'foldmethod'"
+
+#, c-format
+msgid "+--%3ld line folded "
+msgid_plural "+--%3ld lines folded "
+msgstr[0] "+--%3ld ñòðîêà â ñêëàäêå "
+msgstr[1] "+--%3ld ñòðîêè â ñêëàäêå "
+msgstr[2] "+--%3ld ñòðîê â ñêëàäêå "
+
+msgid "E222: Add to read buffer"
+msgstr "E222: Äîáàâëåíèå â áóôåð ÷òåíèÿ"
+
+msgid "E223: recursive mapping"
+msgstr "E223: Ðåêóðñèâíàÿ ïðèâÿçêà"
+
+#, c-format
+msgid "E224: global abbreviation already exists for %s"
+msgstr "E224: Óæå åñòü ãëîáàëüíîå ñîêðàùåíèå äëÿ %s"
+
+#, c-format
+msgid "E225: global mapping already exists for %s"
+msgstr "E225: Óæå åñòü ãëîáàëüíàÿ ïðèâÿçêà äëÿ %s"
+
+#, c-format
+msgid "E226: abbreviation already exists for %s"
+msgstr "E226: Óæå åñòü ñîêðàùåíèå äëÿ %s"
+
+#, c-format
+msgid "E227: mapping already exists for %s"
+msgstr "E227: Óæå åñòü ïðèâÿçêà äëÿ %s"
+
+msgid "No abbreviation found"
+msgstr "Ñîêðàùåíèÿ íå íàéäåíû"
+
+msgid "No mapping found"
+msgstr "Ïðèâÿçêè íå íàéäåíû"
+
+msgid "E228: makemap: Illegal mode"
+msgstr "E228: makemap: íåäîïóñòèìûé ðåæèì"
+
+msgid "E851: Failed to create a new process for the GUI"
+msgstr "E851: Íåâîçìîæíî ñîçäàòü íîâûé ïðîöåññ äëÿ ãðàô. èíòåðôåéñà"
+
+msgid "E852: The child process failed to start the GUI"
+msgstr "E852: Ïðîöåññó-ïîòîìêó íå óäàëîñü çàïóñòèòü ãðàô. èíòåðôåéñ"
+
+msgid "E229: Cannot start the GUI"
+msgstr "E229: Íåâîçìîæíî ïåðåéòè â ðåæèì ãðàôè÷åñêîãî èíòåðôåéñà"
+
+#, c-format
+msgid "E230: Cannot read from \"%s\""
+msgstr "E230: Íåâîçìîæíî âûïîëíèòü ÷òåíèå \"%s\""
+
+msgid "E665: Cannot start GUI, no valid font found"
+msgstr ""
+"E665: Íåâîçìîæíî ïåðåéòè â ðåæèì ãðàô. èíòåðôåéñà, íåïðàâèëüíî çàäàíû øðèôòû"
+
+msgid "E231: 'guifontwide' invalid"
+msgstr "E231: Íåïðàâèëüíîå çíà÷åíèå îïöèè 'guifontwide'"
+
+msgid "E599: Value of 'imactivatekey' is invalid"
+msgstr "E599: Íåïðàâèëüíîå çíà÷åíèå îïöèè 'imactivatekey'"
+
+#, c-format
+msgid "E254: Cannot allocate color %s"
+msgstr "E254: Íåâîçìîæíî íàçíà÷èòü öâåò %s"
+
+msgid "No match at cursor, finding next"
+msgstr "Íåò ñîâïàäåíèÿ ïîä êóðñîðîì, ïîèñê ñëåäóþùåãî"
+
+msgid "<cannot open> "
+msgstr "<íåëüçÿ îòêðûòü> "
+
+#, c-format
+msgid "E616: vim_SelFile: can't get font %s"
+msgstr "E616: vim_SelFile: øðèôò %s íå íàéäåí"
+
+msgid "E614: vim_SelFile: can't return to current directory"
+msgstr "E614: vim_SelFile: âîçâðàò â òåêóùèé êàòàëîã íåâîçìîæåí"
+
+msgid "Pathname:"
+msgstr "Ïóòü ê ôàéëó:"
+
+msgid "E615: vim_SelFile: can't get current directory"
+msgstr "E615: vim_SelFile: íå ìîãó íàéòè òåêóùèé êàòàëîã"
+
+msgid "OK"
+msgstr "Äà"
+
+msgid "Cancel"
+msgstr "Îòìåíà"
+
+msgid "Scrollbar Widget: Could not get geometry of thumb pixmap."
+msgstr "Ïîëîñà ïðîêðóòêè: íå ìîãó îïðåäåëèòü ãåîìåòðèþ ïîëçóíêà"
+
+msgid "Vim dialog"
+msgstr "Äèàëîãîâîå îêíî Vim"
+
+msgid "E232: Cannot create BalloonEval with both message and callback"
+msgstr ""
+"E232: \"Ïóçûðü\" äëÿ âû÷èñëåíèé, âêëþ÷àþùèé è ñîîáùåíèå, è îáðàòíûé âûçîâ, "
+"íå ìîæåò áûòü ñîçäàí"
+
+msgid "_Cancel"
+msgstr "Î_òìåíà"
+
+msgid "_Save"
+msgstr "Ñîõðàíèòü _êàê"
+
+msgid "_Open"
+msgstr "_Îòêðûòü"
+
+msgid "_OK"
+msgstr "_Äà"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"&Cancel"
+msgstr ""
+"&Äà\n"
+"&Íåò\n"
+"Î&òìåíà"
+
+msgid "Yes"
+msgstr "Äà"
+
+msgid "No"
+msgstr "Íåò"
+
+msgid "Input _Methods"
+msgstr "_Ìåòîäû ââîäà"
+
+msgid "VIM - Search and Replace..."
+msgstr "VIM — Ïîèñê è çàìåíà..."
+
+msgid "VIM - Search..."
+msgstr "VIM — Ïîèñê..."
+
+msgid "Find what:"
+msgstr "×òî íàéòè:"
+
+msgid "Replace with:"
+msgstr "Çàìåíèòü íà:"
+
+msgid "Match whole word only"
+msgstr "Òîëüêî òî÷íûå ñîîòâåòñòâèÿ"
+
+msgid "Match case"
+msgstr "Ó÷èòûâàòü ðåãèñòð"
+
+msgid "Direction"
+msgstr "Íàïðàâëåíèå"
+
+msgid "Up"
+msgstr "Ââåðõ"
+
+msgid "Down"
+msgstr "Âíèç"
+
+msgid "Find Next"
+msgstr "Íàéòè ñëåäóþùåå"
+
+msgid "Replace"
+msgstr "Çàìåíèòü"
+
+msgid "Replace All"
+msgstr "Çàìåíèòü âñå"
+
+msgid "_Close"
+msgstr "_Çàêðûòü"
+
+msgid "Vim: Received \"die\" request from session manager\n"
+msgstr "Vim: Ïîëó÷åí çàïðîñ íà ïðåêðàùåíèå ðàáîòû îò äèñïåò÷åðà ñåàíñîâ\n"
+
+msgid "Close tab"
+msgstr "Çàêðûòü âêëàäêó"
+
+msgid "New tab"
+msgstr "Íîâàÿ âêëàäêà"
+
+msgid "Open Tab..."
+msgstr "Îòêðûòü âêëàäêó..."
+
+msgid "Vim: Main window unexpectedly destroyed\n"
+msgstr "Vim: Îñíîâíîå îêíî áûëî íåîæèäàííî çàêðûòî\n"
+
+msgid "&Filter"
+msgstr "&Ôèëüòð"
+
+msgid "&Cancel"
+msgstr "Î&òìåíà"
+
+msgid "Directories"
+msgstr "Êàòàëîãè"
+
+msgid "Filter"
+msgstr "Ôèëüòð"
+
+msgid "&Help"
+msgstr "&Ñïðàâêà"
+
+msgid "Files"
+msgstr "Ôàéëû"
+
+msgid "&OK"
+msgstr "&Äà"
+
+msgid "Selection"
+msgstr "Âûäåëåíèå"
+
+msgid "Find &Next"
+msgstr "Íàéòè &ñëåäóþùåå"
+
+msgid "&Replace"
+msgstr "Çà&ìåíà"
+
+msgid "Replace &All"
+msgstr "Çàìåíèòü &âñå"
+
+msgid "&Undo"
+msgstr "Î&òìåíà"
+
+msgid "Open tab..."
+msgstr "Îòêðûòü âêëàäêó..."
+
+msgid "Find string (use '\\\\' to find a '\\')"
+msgstr "Ïîèñê ñòðîêè (èñïîëüçóéòå '\\\\' äëÿ ïîèñêà '\\')"
+
+msgid "Find & Replace (use '\\\\' to find a '\\')"
+msgstr "Ïîèñê è çàìåíà (èñïîëüçóéòå '\\\\' äëÿ ïîèñêà '\\')"
+
+msgid "Not Used"
+msgstr "Íå èñïîëüçóåòñÿ"
+
+msgid "Directory\t*.nothing\n"
+msgstr "Êàòàëîã\t*.íè÷åãî\n"
+
+#, c-format
+msgid "E671: Cannot find window title \"%s\""
+msgstr "E671: Îêíî ñ çàãîëîâêîì \"%s\" íå îáíàðóæåíî"
+
+#, c-format
+msgid "E243: Argument not supported: \"-%s\"; Use the OLE version."
+msgstr "E243: Ïàðàìåòð íå ïîääåðæèâàåòñÿ: \"-%s\"; èñïîëüçóéòå âåðñèþ OLE."
+
+msgid "E672: Unable to open window inside MDI application"
+msgstr "E672: Íåâîçìîæíî îòêðûòü îêíî âíóòðè ïðèëîæåíèÿ MDI"
+
+msgid "Vim E458: Cannot allocate colormap entry, some colors may be incorrect"
+msgstr ""
+"Vim E458: Íåâîçìîæíî âûäåëèòü çàïèñü â òàáëèöå öâåòà, íåêîòîðûå öâåòà ìîãóò "
+"îòîáðàæàòüñÿ íåïðàâèëüíî"
+
+#, c-format
+msgid "E250: Fonts for the following charsets are missing in fontset %s:"
+msgstr "E250: Â íàáîðå øðèôòîâ %s îòñóòñòâóþò øðèôòû äëÿ ñëåäóþùèõ êîäèðîâîê:"
+
+#, c-format
+msgid "E252: Fontset name: %s"
+msgstr "E252: Íàáîð øðèôòîâ: %s"
+
+#, c-format
+msgid "Font '%s' is not fixed-width"
+msgstr "Øðèôò '%s' íå ÿâëÿåòñÿ ìîíîøèðèííûì"
+
+#, c-format
+msgid "E253: Fontset name: %s"
+msgstr "E253: Íàáîð øðèôòîâ: %s"
+
+#, c-format
+msgid "Font0: %s"
+msgstr "Font0: %s"
+
+#, c-format
+msgid "Font1: %s"
+msgstr "Font1: %s"
+
+#, c-format
+msgid "Font%ld width is not twice that of font0"
+msgstr "Øèðèíà øðèôòà font%ld äîëæíà áûòü âäâîå áîëüøå øèðèíû øðèôòà font0"
+
+#, c-format
+msgid "Font0 width: %ld"
+msgstr "Øèðèíà øðèôòà font0: %ld"
+
+#, c-format
+msgid "Font1 width: %ld"
+msgstr "Øèðèíà øðèôòà font1: %ld"
+
+msgid "Invalid font specification"
+msgstr "Íåïðàâèëüíîå îïðåäåëåíèå øðèôòà"
+
+msgid "&Dismiss"
+msgstr "Î&òêëîíèòü"
+
+msgid "no specific match"
+msgstr "íåò ñïåöèàëüíîãî ñîâïàäåíèÿ"
+
+msgid "Vim - Font Selector"
+msgstr "Vim — Âûáîð øðèôòà"
+
+msgid "Name:"
+msgstr "Íàçâàíèå:"
+
+msgid "Show size in Points"
+msgstr "Ïîêàçûâàòü ðàçìåð â ïóíêòàõ"
+
+msgid "Encoding:"
+msgstr "Êîäèðîâêà:"
+
+msgid "Font:"
+msgstr "Øðèôò:"
+
+msgid "Style:"
+msgstr "Ñòèëü:"
+
+msgid "Size:"
+msgstr "Ðàçìåð:"
+
+msgid "E256: Hangul automata ERROR"
+msgstr "E256: ÎØÈÁÊÀ àâòîìàòèêè Õàíãûë"
+
+msgid "E550: Missing colon"
+msgstr "E550: Ïðîïóùåíî äâîåòî÷èå"
+
+msgid "E551: Illegal component"
+msgstr "E551: Íåäîïóñòèìûé êîìïîíåíò"
+
+msgid "E552: digit expected"
+msgstr "E552: Òðåáóåòñÿ óêàçàòü öèôðó"
+
+#, c-format
+msgid "Page %d"
+msgstr "Ñòðàíèöà %d"
+
+msgid "No text to be printed"
+msgstr "Ïå÷àòàòü íå÷åãî"
+
+#, c-format
+msgid "Printing page %d (%d%%)"
+msgstr "Ïå÷àòü ñòð. %d (%d%%)"
+
+#, c-format
+msgid " Copy %d of %d"
+msgstr " Êîïèÿ %d èç %d"
+
+#, c-format
+msgid "Printed: %s"
+msgstr "Íàïå÷àòàíî: %s"
+
+msgid "Printing aborted"
+msgstr "Ïå÷àòü ïðåêðàùåíà"
+
+msgid "E455: Error writing to PostScript output file"
+msgstr "E455: Îøèáêà çàïèñè â ôàéë PostScript"
+
+#, c-format
+msgid "E624: Can't open file \"%s\""
+msgstr "E624: Íåâîçìîæíî îòêðûòü ôàéë \"%s\""
+
+#, c-format
+msgid "E457: Can't read PostScript resource file \"%s\""
+msgstr "E457: Íåâîçìîæíî ïðî÷èòàòü ôàéë ðåñóðñîâ PostScript \"%s\""
+
+#, c-format
+msgid "E618: file \"%s\" is not a PostScript resource file"
+msgstr "E618: Ôàéë \"%s\" íå ÿâëÿåòñÿ ôàéëîì ðåñóðñîâ PostScript"
+
+#, c-format
+msgid "E619: file \"%s\" is not a supported PostScript resource file"
+msgstr "E619: Ôàéë \"%s\" íå ÿâëÿåòñÿ äîïóñòèìûì ôàéëîì ðåñóðñîâ PostScript"
+
+#, c-format
+msgid "E621: \"%s\" resource file has wrong version"
+msgstr "E621: Ôàéë ðåñóðñîâ \"%s\" íåèçâåñòíîé âåðñèè"
+
+msgid "E673: Incompatible multi-byte encoding and character set."
+msgstr "E673: Íåñîâìåñòèìûå ìíîãîáàéòîâàÿ êîäèðîâêà è íàáîð ñèìâîëîâ."
+
+msgid "E674: printmbcharset cannot be empty with multi-byte encoding."
+msgstr "E674: printmbcharset íå ìîæåò áûòü ïóñòûì ïðè ìíîãîáàéòîâîé êîäèðîâêå."
+
+msgid "E675: No default font specified for multi-byte printing."
+msgstr "E675: Íåò îïðåäåëåíèÿ øðèôòà ïî óìîë÷àíèþ äëÿ ìíîãîáàéòîâîé ïå÷àòè."
+
+msgid "E324: Can't open PostScript output file"
+msgstr "E324: Íåâîçìîæíî îòêðûòü ôàéë PostScript"
+
+#, c-format
+msgid "E456: Can't open file \"%s\""
+msgstr "E456: Íåâîçìîæíî îòêðûòü ôàéë \"%s\""
+
+msgid "E456: Can't find PostScript resource file \"prolog.ps\""
+msgstr "E456: Ôàéë ðåñóðñîâ PostScript \"prolog.ps\" íå íàéäåí"
+
+msgid "E456: Can't find PostScript resource file \"cidfont.ps\""
+msgstr "E456: Ôàéë ðåñóðñîâ PostScript \"cidfont.ps\" íå íàéäåí"
+
+#, c-format
+msgid "E456: Can't find PostScript resource file \"%s.ps\""
+msgstr "E456: Ôàéë ðåñóðñîâ PostScript \"%s.ps\" íå íàéäåí"
+
+#, c-format
+msgid "E620: Unable to convert to print encoding \"%s\""
+msgstr "E620: Íåâîçìîæíî ïðåîáðàçîâàòü â êîäèðîâêó ïå÷àòü \"%s\""
+
+msgid "Sending to printer..."
+msgstr "Îòïðàâêà íà ïå÷àòü..."
+
+msgid "E365: Failed to print PostScript file"
+msgstr "E365: Íå óäàëîñü âûïîëíèòü ïå÷àòü ôàéëà PostScript"
+
+msgid "Print job sent."
+msgstr "Çàäàíèå íà ïå÷àòü îòïðàâëåíî."
+
+msgid "Add a new database"
+msgstr "Äîáàâèòü íîâóþ áàçó äàííûõ"
+
+msgid "Query for a pattern"
+msgstr "Çàïðîñ ïî øàáëîíó"
+
+msgid "Show this message"
+msgstr "Ïîêàçàòü ýòî ñîîáùåíèå"
+
+msgid "Kill a connection"
+msgstr "Óáèòü ñîåäèíåíèå"
+
+msgid "Reinit all connections"
+msgstr "Çàíîâî èíèöèàëèçèðîâàòü âñå ñîåäèíåíèÿ"
+
+msgid "Show connections"
+msgstr "Ïîêàçàòü ñîåäèíåíèÿ"
+
+#, c-format
+msgid "E560: Usage: cs[cope] %s"
+msgstr "E560: Èñïîëüçîâàíèå: cs[cope] %s"
+
+msgid "This cscope command does not support splitting the window.\n"
+msgstr "Ýòà êîìàíäà cscope íå ïîääåðæèâàåò ðàçäåëåíèå îêíà.\n"
+
+msgid "E562: Usage: cstag <ident>"
+msgstr "E562: Èñïîëüçîâàíèå: cstag <èìÿ>"
+
+msgid "E257: cstag: tag not found"
+msgstr "E257: cstag: ìåòêà íå íàéäåíà"
+
+#, c-format
+msgid "E563: stat(%s) error: %d"
+msgstr "E563: Îøèáêà stat(%s): %d"
+
+msgid "E563: stat error"
+msgstr "E563: Îøèáêà stat"
+
+#, c-format
+msgid "E564: %s is not a directory or a valid cscope database"
+msgstr "E564: %s íå ÿâëÿåòñÿ êàòàëîãîì èëè èìåíåì áàçû cscope"
+
+#, c-format
+msgid "Added cscope database %s"
+msgstr "Äîáàâëåíà áàçà äàííûõ cscope %s"
+
+#, c-format
+msgid "E262: error reading cscope connection %ld"
+msgstr "E262: Îøèáêà ïîëó÷åíèÿ èíôîðìàöèè îò ñîåäèíåíèÿ cscope %ld"
+
+msgid "E561: unknown cscope search type"
+msgstr "E561: Íåèçâåñòíûé òèï ïîèñêà cscope"
+
+msgid "E566: Could not create cscope pipes"
+msgstr "E566: Íåâîçìîæíî ñîçäàòü òðóáó äëÿ cscope"
+
+msgid "E622: Could not fork for cscope"
+msgstr "E622: Íåâîçìîæíî âûïîëíèòü fork() äëÿ cscope"
+
+msgid "cs_create_connection setpgid failed"
+msgstr "cs_create_connection: íå óäàëîñü âûïîëíèòü setpgid"
+
+msgid "cs_create_connection exec failed"
+msgstr "cs_create_connection: íå óäàëîñü âûïîëíèòü exec"
+
+msgid "cs_create_connection: fdopen for to_fp failed"
+msgstr "cs_create_connection: íå óäàëîñü âûïîëíèòü fdopen äëÿ to_fp"
+
+msgid "cs_create_connection: fdopen for fr_fp failed"
+msgstr "cs_create_connection: íå óäàëîñü âûïîëíèòü fdopen äëÿ fr_fp"
+
+msgid "E623: Could not spawn cscope process"
+msgstr "E623: Íå óäàëîñü çàïóñòèòü ïðîöåññ cscope"
+
+msgid "E567: no cscope connections"
+msgstr "E567: Ñîåäèíåíèé ñ cscope íå ñîçäàíî"
+
+#, c-format
+msgid "E469: invalid cscopequickfix flag %c for %c"
+msgstr "E469: Íåïðàâèëüíûé ôëàã cscopequickfix %c äëÿ %c"
+
+#, c-format
+msgid "E259: no matches found for cscope query %s of %s"
+msgstr "E259: Íå íàéäåíî ñîîòâåòñòâèé ïî çàïðîñó cscope %s äëÿ %s"
+
+msgid "cscope commands:\n"
+msgstr "Êîìàíäû cscope:\n"
+
+#, c-format
+msgid "%-5s: %s%*s (Usage: %s)"
+msgstr "%-5s: %s%*s (èñïîëüçîâàíèå: %s)"
+
+msgid ""
+"\n"
+" a: Find assignments to this symbol\n"
+" c: Find functions calling this function\n"
+" d: Find functions called by this function\n"
+" e: Find this egrep pattern\n"
+" f: Find this file\n"
+" g: Find this definition\n"
+" i: Find files #including this file\n"
+" s: Find this C symbol\n"
+" t: Find this text string\n"
+msgstr ""
+"\n"
+" a: Íàéòè ïðèñâàèâàíèÿ äëÿ ýòîãî ñèìâîëà\n"
+" c: Íàéòè ôóíêöèè âûçûâàþùèå ýòó ôóíêöèþ\n"
+" d: Íàéòè ôóíêöèè âûçûâàåìûå ýòîé ôóíêöèåé\n"
+" e: Íàéòè ýòîò øàáëîí egrep\n"
+" f: Íàéòè ýòîò ôàéë\n"
+" g: Íàéòè ýòî îïðåäåëåíèå\n"
+" i: Íàéòè ôàéëû âêëþ÷àþùèå (#include) ýòîò ôàéë\n"
+" s: Íàéòè ýòîò C-ñèìâîë\n"
+" t: Íàéòè ýòó òåêñòîâóþ ñòðîêó\n"
+
+#, c-format
+msgid "E625: cannot open cscope database: %s"
+msgstr "E625: Íåâîçìîæíî îòêðûòü áàçó äàííûõ cscope: %s"
+
+msgid "E626: cannot get cscope database information"
+msgstr "E626: Èíôîðìàöèÿ î áàçå äàííûõ cscope íåäîñòóïíà"
+
+msgid "E568: duplicate cscope database not added"
+msgstr "E568: Äàííàÿ áàçà äàííûõ cscope óæå ïîäñîåäèíåíà"
+
+#, c-format
+msgid "E261: cscope connection %s not found"
+msgstr "E261: Ñîåäèíåíèå ñ cscope %s íå îáíàðóæåíî"
+
+#, c-format
+msgid "cscope connection %s closed"
+msgstr "ñîåäèíåíèå ñ cscope %s çàêðûòî"
+
+msgid "E570: fatal error in cs_manage_matches"
+msgstr "E570: Êðèòè÷åñêàÿ îøèáêà â cs_manage_matches"
+
+#, c-format
+msgid "Cscope tag: %s"
+msgstr "Ìåòêà cscope: %s"
+
+msgid ""
+"\n"
+" # line"
+msgstr ""
+"\n"
+" # ñòðîêà"
+
+msgid "filename / context / line\n"
+msgstr "èìÿ ôàéëà / êîíòåêñò / ñòðîêà\n"
+
+#, c-format
+msgid "E609: Cscope error: %s"
+msgstr "E609: Îøèáêà cscope: %s"
+
+msgid "All cscope databases reset"
+msgstr "Ïåðåçàãðóçêà âñåõ áàç äàííûõ cscope"
+
+msgid "no cscope connections\n"
+msgstr "ñîåäèíåíèÿ ñ cscope îòñóòñòâóþò\n"
+
+msgid " # pid database name prepend path\n"
+msgstr " # pid áàçà äàííûõ íà÷àëüíûé ïóòü\n"
+
+msgid "Lua library cannot be loaded."
+msgstr "Áèáëèîòåêà Lua íå ìîæåò áûòü çàãðóæåíà."
+
+msgid "cannot save undo information"
+msgstr "íåâîçìîæíî ñîõðàíèòü èíôîðìàöèþ îá îòìåíå îïåðàöèè"
+
+msgid ""
+"E815: Sorry, this command is disabled, the MzScheme libraries could not be "
+"loaded."
+msgstr ""
+"E815: Ê ñîæàëåíèþ ýòà êîìàíäà íå ðàáîòàåò, ïîñêîëüêó íå çàãðóæåíà áèáëèîòåêà "
+"MzScheme."
+
+msgid ""
+"E895: Sorry, this command is disabled, the MzScheme's racket/base module "
+"could not be loaded."
+msgstr ""
+"E895: Ê ñîæàëåíèþ ýòà êîìàíäà íå ðàáîòàåò, ïîñêîëüêó íå çàãðóæåí ìîäóëü "
+"racket/base äëÿ MzScheme."
+
+msgid "invalid expression"
+msgstr "íåïðàâèëüíîå âûðàæåíèå"
+
+msgid "expressions disabled at compile time"
+msgstr "âûðàæåíèÿ îòêëþ÷åíû ïðè êîìïèëÿöèè"
+
+msgid "hidden option"
+msgstr "ñêðûòàÿ îïöèÿ"
+
+msgid "unknown option"
+msgstr "íåèçâåñòíàÿ îïöèÿ"
+
+msgid "window index is out of range"
+msgstr "èíäåêñ îêíà çà ïðåäåëàìè äèàïàçîíà"
+
+msgid "couldn't open buffer"
+msgstr "íåâîçìîæíî îòêðûòü áóôåð"
+
+msgid "cannot delete line"
+msgstr "íåâîçìîæíî óäàëèòü ñòðîêó"
+
+msgid "cannot replace line"
+msgstr "íåâîçìîæíî çàìåíèòü ñòðîêó"
+
+msgid "cannot insert line"
+msgstr "íåâîçìîæíî âñòàâèòü ñòðîêó"
+
+msgid "string cannot contain newlines"
+msgstr "ñòðîêà íå ìîæåò ñîäåðæàòü ñèìâîë íîâîé ñòðîêè"
+
+msgid "error converting Scheme values to Vim"
+msgstr "íåâîçìîæíî ïðåîáðàçîâàòü çíà÷åíèÿ Scheme â Vim"
+
+msgid "Vim error: ~a"
+msgstr "îøèáêà Vim: ~a"
+
+msgid "Vim error"
+msgstr "îøèáêà Vim"
+
+msgid "buffer is invalid"
+msgstr "íåïðàâèëüíûé áóôåð"
+
+msgid "window is invalid"
+msgstr "íåïðàâèëüíîå îêíî"
+
+msgid "linenr out of range"
+msgstr "íîìåð ñòðîêè çà ïðåäåëàìè äèàïàçîíà"
+
+msgid "not allowed in the Vim sandbox"
+msgstr "íå äîïóñêàåòñÿ â ïåñî÷íèöå Vim"
+
+msgid "E836: This Vim cannot execute :python after using :py3"
+msgstr "E836: Äàííûé Vim íå ìîæåò âûïîëíèòü :python ïîñëå èñïîëüçîâàíèÿ :py3"
+
+msgid ""
+"E263: Sorry, this command is disabled, the Python library could not be "
+"loaded."
+msgstr ""
+"E263: Ê ñîæàëåíèþ ýòà êîìàíäà íå ðàáîòàåò, ïîñêîëüêó íå çàãðóæåíà áèáëèîòåêà "
+"Python"
+
+msgid ""
+"E887: Sorry, this command is disabled, the Python's site module could not be "
+"loaded."
+msgstr ""
+"E887: Ê ñîæàëåíèþ ýòà êîìàíäà íå ðàáîòàåò, ïîñêîëüêó íå çàãðóæåí ìîäóëü "
+"Python site."
+
+msgid "E659: Cannot invoke Python recursively"
+msgstr "E659: Íåâîçìîæíî âûïîëíèòü ðåêóðñèâíûé âûçîâ Python"
+
+msgid "E837: This Vim cannot execute :py3 after using :python"
+msgstr "E837: Äàííûé Vim íå ìîæåò âûïîëíèòü :py3 ïîñëå èñïîëüçîâàíèÿ :python"
+
+msgid "E265: $_ must be an instance of String"
+msgstr "E265: $_ äîëæåí áûòü ýêçåìïëÿðîì èëè ñòðîêîé"
+
+msgid ""
+"E266: Sorry, this command is disabled, the Ruby library could not be loaded."
+msgstr ""
+"E266: Ê ñîæàëåíèþ ýòà êîìàíäà íå ðàáîòàåò, ïîñêîëüêó íå çàãðóæåíà áèáëèîòåêà "
+"Ruby"
+
+msgid "E267: unexpected return"
+msgstr "E267: Íåîæèäàííûé return"
+
+msgid "E268: unexpected next"
+msgstr "E268: Íåîæèäàííûé next"
+
+msgid "E269: unexpected break"
+msgstr "E269: Íåîæèäàííûé break"
+
+msgid "E270: unexpected redo"
+msgstr "E270: Íåîæèäàííûé redo"
+
+msgid "E271: retry outside of rescue clause"
+msgstr "E271: retry âíå îïåðàòîðà rescue"
+
+msgid "E272: unhandled exception"
+msgstr "E272: Íåîáðàáîòàííîå èñêëþ÷åíèå"
+
+#, c-format
+msgid "E273: unknown longjmp status %d"
+msgstr "E273: Íåèçâåñòíîå ñîñòîÿíèå longjmp %d"
+
+msgid "invalid buffer number"
+msgstr "íåïðàâèëüíûé íîìåð áóôåðà"
+
+msgid "not implemented yet"
+msgstr "ïîêà íå ðåàëèçîâàíî"
+
+msgid "cannot set line(s)"
+msgstr "íåâîçìîæíî íàçíà÷èòü ñòðîêó èëè ñòðîêè"
+
+msgid "invalid mark name"
+msgstr "íåïðàâèëüíîå èìÿ îòìåòêè"
+
+msgid "mark not set"
+msgstr "îòìåòêà íå óñòàíîâëåíà"
+
+#, c-format
+msgid "row %d column %d"
+msgstr "ðÿä %d êîëîíêà %d"
+
+msgid "cannot insert/append line"
+msgstr "íåâîçìîæíî âñòàâèòü èëè äîáàâèòü ñòðîêó"
+
+msgid "line number out of range"
+msgstr "íîìåð ñòðîêè çà ïðåäåëàìè äèàïàçîíà"
+
+msgid "unknown flag: "
+msgstr "íåèçâåñòíûé ôëàã: "
+
+msgid "unknown vimOption"
+msgstr "íåèçâåñòíàÿ vimOption"
+
+msgid "keyboard interrupt"
+msgstr "êëàâèàòóðíîå ïðåðûâàíèå"
+
+msgid "vim error"
+msgstr "îøèáêà VIM"
+
+msgid "cannot create buffer/window command: object is being deleted"
+msgstr "íåâîçìîæíî ñîçäàòü êîìàíäó áóôåðà èëè îêíà: îáúåêò â ïðîöåññå óäàëåíèÿ"
+
+msgid ""
+"cannot register callback command: buffer/window is already being deleted"
+msgstr ""
+"íåâîçìîæíî çàðåãèñòðèðîâàòü êîìàíäó ñ îáðàòíûì âûçîâîì: áóôåð èëè îêíî â "
+"ïðîöåññå óäàëåíèÿ"
+
+msgid ""
+"E280: TCL FATAL ERROR: reflist corrupt!? Please report this to vim-dev@vim."
+"org"
+msgstr ""
+"E280: ÊÐÈÒÈ×ÅÑÊÀß ÎØÈÁÊÀ TCL: ïîâðåæä¸í ñïèñîê ññûëîê?! Ñîîáùèòå îá ýòîì ïî "
+"àäðåñó vim-dev@vim.org"
+
+msgid "cannot register callback command: buffer/window reference not found"
+msgstr ""
+"íåâîçìîæíî çàðåãèñòðèðîâàòü êîìàíäó ñ îáðàòíûì âûçîâîì: ññûëêà íà áóôåð èëè "
+"îêíî íå îáíàðóæåíà"
+
+msgid ""
+"E571: Sorry, this command is disabled: the Tcl library could not be loaded."
+msgstr ""
+"E571: Ê ñîæàëåíèþ ýòà êîìàíäà íå ðàáîòàåò, ïîñêîëüêó íå çàãðóæåíà áèáëèîòåêà "
+"Tcl"
+
+#, c-format
+msgid "E572: exit code %d"
+msgstr "E572: Êîä âûõîäà %d"
+
+msgid "cannot get line"
+msgstr "íåâîçìîæíî ïîëó÷èòü ñòðîêó"
+
+msgid "Unable to register a command server name"
+msgstr "Íåâîçìîæíî çàðåãèñòðèðîâàòü èìÿ ñåðâåðà êîìàíä"
+
+msgid "E248: Failed to send command to the destination program"
+msgstr "E248: Íå óäàëàñü îòïðàâêà êîìàíäû â äðóãóþ ïðîãðàììó"
+
+#, c-format
+msgid "E573: Invalid server id used: %s"
+msgstr "E573: Èñïîëüçóåòñÿ íåïðàâèëüíûé id ñåðâåðà: %s"
+
+msgid "E251: VIM instance registry property is badly formed. Deleted!"
+msgstr ""
+"E251: Íåïðàâèëüíî ñôîðìèðîâàíî çíà÷åíèå äàííîãî ïðîöåññà VIM â ðååñòðå. "
+"Óäàëåíî!"
+
+#, c-format
+msgid "E938: Duplicate key in JSON: \"%s\""
+msgstr "E938: Ïîâòîð êëþ÷à â JSON: \"%s\""
+
+#, c-format
+msgid "E696: Missing comma in List: %s"
+msgstr "E696: Ïðîïóùåíà çàïÿòàÿ â ñïèñêå: %s"
+
+#, c-format
+msgid "E697: Missing end of List ']': %s"
+msgstr "E697: Ïðîïóùåíî îêîí÷àíèå ñïèñêà ']': %s"
+
+msgid "Unknown option argument"
+msgstr "Íåèçâåñòíûé íåîáÿçàòåëüíûé ïàðàìåòð"
+
+msgid "Too many edit arguments"
+msgstr "Ñëèøêîì ìíîãî ïàðàìåòðîâ ðåäàêòèðîâàíèÿ"
+
+msgid "Argument missing after"
+msgstr "Ïðîïóùåí ïàðàìåòð ïîñëå"
+
+msgid "Garbage after option argument"
+msgstr "Ìóñîð ïîñëå íåîáÿçàòåëüíîãî ïàðàìåòðà"
+
+msgid "Too many \"+command\", \"-c command\" or \"--cmd command\" arguments"
+msgstr ""
+"Ñëèøêîì ìíîãî ïàðàìåòðîâ \"+êîìàíäà\", \"-c êîìàíäà\" èëè \"--cmd êîìàíäà\""
+
+msgid "Invalid argument for"
+msgstr "Íåäîïóñòèìûé ïàðàìåòð äëÿ"
+
+#, c-format
+msgid "%d files to edit\n"
+msgstr "Ôàéëîâ äëÿ ðåäàêòèðîâàíèÿ: %d\n"
+
+msgid "netbeans is not supported with this GUI\n"
+msgstr "NetBeans íå ïîääåðæèâàåòñÿ ñ ýòèì ãðàôè÷åñêèì èíòåðôåéñîì\n"
+
+msgid "'-nb' cannot be used: not enabled at compile time\n"
+msgstr "Íåâîçìîæíî èñïîëüçîâàòü '-nb': íå âêëþ÷åíî ïðè êîìïèëÿöèè\n"
+
+msgid "This Vim was not compiled with the diff feature."
+msgstr ""
+"Äàííûé Vim áûë ñêîìïèëèðîâàí ñ âûêëþ÷åííîé îñîáåííîñòüþ ïðîñìîòðà îòëè÷èé"
+
+msgid "Attempt to open script file again: \""
+msgstr "Ïîïûòêà ïîâòîðíîãî îòêðûòèÿ ôàéëà ñöåíàðèÿ: \""
+
+msgid "Cannot open for reading: \""
+msgstr "Íåâîçìîæíî îòêðûòü äëÿ ÷òåíèÿ: \""
+
+msgid "Cannot open for script output: \""
+msgstr "Íåâîçìîæíî îòêðûòü äëÿ âûâîäà ñöåíàðèÿ: \""
+
+msgid "Vim: Error: Failure to start gvim from NetBeans\n"
+msgstr "Vim: Îøèáêà: Íå óäàëîñü çàïóñòèòü gvim èç NetBeans\n"
+
+msgid "Vim: Error: This version of Vim does not run in a Cygwin terminal\n"
+msgstr "Vim: Îøèáêà: Äàííàÿ âåðñèÿ Vim íå ðàáîòàåò â òåðìèíàëå Cygwin\n"
+
+msgid "Vim: Warning: Output is not to a terminal\n"
+msgstr "Vim: Ïðåäóïðåæäåíèå: Âûâîä îñóùåñòâëÿåòñÿ íå íà òåðìèíàë\n"
+
+msgid "Vim: Warning: Input is not from a terminal\n"
+msgstr "Vim: Ïðåäóïðåæäåíèå: Ââîä ïðîèñõîäèò íå ñ òåðìèíàëà\n"
+
+msgid "pre-vimrc command line"
+msgstr "êîìàíäíàÿ ñòðîêà ïåðåä âûïîëíåíèåì vimrc"
+
+#, c-format
+msgid "E282: Cannot read from \"%s\""
+msgstr "E282: Íåâîçìîæíî âûïîëíèòü ÷òåíèå èç \"%s\""
+
+msgid ""
+"\n"
+"More info with: \"vim -h\"\n"
+msgstr ""
+"\n"
+"Äîïîëíèòåëüíàÿ èíôîðìàöèÿ: \"vim -h\"\n"
+
+msgid "[file ..] edit specified file(s)"
+msgstr "[ôàéë ..] ðåäàêòèðîâàíèå óêàçàííûõ ôàéëîâ"
+
+msgid "- read text from stdin"
+msgstr "- ÷òåíèå òåêñòà èç ïîòîêà ââîäà stdin"
+
+msgid "-t tag edit file where tag is defined"
+msgstr "-t ìåòêà ðåäàêòèðîâàíèå ôàéëà ñ óêàçàííîé ìåòêîé"
+
+# \n\t\t.. äëÿ óìåùåíèÿ â 80 ñòîëáöîâ
+msgid "-q [errorfile] edit file with first error"
+msgstr ""
+"-q [ôàéë-îøèáîê]\n"
+"\t\t\t\t ðåäàêòèðîâàíèå ôàéëà ñ ïåðâîé îøèáêîé"
+
+msgid ""
+"\n"
+"\n"
+"Usage:"
+msgstr ""
+"\n"
+"\n"
+"Èñïîëüçîâàíèå:"
+
+msgid " vim [arguments] "
+msgstr " vim [ïàðàìåòðû] "
+
+msgid ""
+"\n"
+" or:"
+msgstr ""
+"\n"
+" èëè:"
+
+msgid ""
+"\n"
+"Where case is ignored prepend / to make flag upper case"
+msgstr ""
+"\n"
+"Åñëè ðåãèñòð èãíîðèðóåòñÿ, äîáàâüòå ïåðåä ôëàãîì / äëÿ âåðõíåãî ðåãèñòðà"
+
+msgid ""
+"\n"
+"\n"
+"Arguments:\n"
+msgstr ""
+"\n"
+"\n"
+"Ïàðàìåòðû:\n"
+
+msgid "--\t\t\tOnly file names after this"
+msgstr "--\t\t\tÄàëåå óêàçûâàþòñÿ òîëüêî èìåíà ôàéëîâ"
+
+msgid "--literal\t\tDon't expand wildcards"
+msgstr "--literal\t\tÍå âûïîëíÿòü ïîäñòàíîâêó ïî ìàñêå"
+
+msgid "-register\t\tRegister this gvim for OLE"
+msgstr "-register\t\tÇàðåãèñòðèðîâàòü ýòîò gvim äëÿ OLE"
+
+msgid "-unregister\t\tUnregister gvim for OLE"
+msgstr "-unregister\t\tÎòêëþ÷èòü ðåãèñòðàöèþ äàííîãî gvim äëÿ OLE"
+
+msgid "-g\t\t\tRun using GUI (like \"gvim\")"
+msgstr "-g\t\t\tÇàïóñòèòü ñ ãðàôè÷åñêèì èíòåðôåéñîì (êàê \"gvim\")"
+
+msgid "-f or --nofork\tForeground: Don't fork when starting GUI"
+msgstr "-f èëè --nofork\t àêòèâíîé çàäà÷å: Íå âûïîëíÿòü fork ïðè çàïóñêå GUI"
+
+msgid "-v\t\t\tVi mode (like \"vi\")"
+msgstr "-v\t\t\tÐåæèì Vi (êàê \"vi\")"
+
+msgid "-e\t\t\tEx mode (like \"ex\")"
+msgstr "-e\t\t\tÐåæèì Ex (êàê \"ex\")"
+
+msgid "-E\t\t\tImproved Ex mode"
+msgstr "-E\t\t\tÓëó÷øåííûé ðåæèì Ex"
+
+msgid "-s\t\t\tSilent (batch) mode (only for \"ex\")"
+msgstr "-s\t\t\tÒèõèé (ïàêåòíûé) ðåæèì (òîëüêî äëÿ \"ex\")"
+
+msgid "-d\t\t\tDiff mode (like \"vimdiff\")"
+msgstr "-d\t\t\tÐåæèì îòëè÷èé (êàê \"vimdiff\")"
+
+msgid "-y\t\t\tEasy mode (like \"evim\", modeless)"
+msgstr "-y\t\t\tÏðîñòîé ðåæèì (êàê \"evim\", áåçðåæèìíûé)"
+
+msgid "-R\t\t\tReadonly mode (like \"view\")"
+msgstr "-R\t\t\tÒîëüêî äëÿ ÷òåíèÿ (êàê \"view\")"
+
+msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
+msgstr "-Z\t\t\tÎãðàíè÷åííûé ðåæèì (êàê \"rvim\")"
+
+msgid "-m\t\t\tModifications (writing files) not allowed"
+msgstr "-m\t\t\tÁåç âîçìîæíîñòè ñîõðàíåíèÿ èçìåíåíèé (çàïèñè ôàéëîâ)"
+
+msgid "-M\t\t\tModifications in text not allowed"
+msgstr "-M\t\t\tÁåç âîçìîæíîñòè âíåñåíèÿ èçìåíåíèé â òåêñò"
+
+msgid "-b\t\t\tBinary mode"
+msgstr "-b\t\t\tÄâîè÷íûé ðåæèì"
+
+msgid "-l\t\t\tLisp mode"
+msgstr "-l\t\t\tÐåæèì Lisp"
+
+msgid "-C\t\t\tCompatible with Vi: 'compatible'"
+msgstr "-C\t\t\tÐåæèì ñîâìåñòèìîñòè ñ Vi: 'compatible'"
+
+msgid "-N\t\t\tNot fully Vi compatible: 'nocompatible'"
+msgstr "-N\t\t\tÐåæèì íåïîëíîé ñîâìåñòèìîñòè ñ Vi: 'nocompatible'"
+
+# \n\t\t.. äëÿ óìåùåíèÿ â 80 ñòîëáöîâ
+msgid "-V[N][fname]\t\tBe verbose [level N] [log messages to fname]"
+msgstr ""
+"-V[N][ôàéë]\t\tÂûâîäèòü äîïîëíèòåëüíûå ñîîáùåíèÿ\n"
+"\t\t\t\t[óðîâåíü N] [çàïèñûâàòü â ôàéë]"
+
+msgid "-D\t\t\tDebugging mode"
+msgstr "-D\t\t\tÐåæèì îòëàäêè"
+
+msgid "-n\t\t\tNo swap file, use memory only"
+msgstr "-n\t\t\tÁåç ñâîï-ôàéëà, èñïîëüçóåòñÿ òîëüêî ïàìÿòü"
+
+msgid "-r\t\t\tList swap files and exit"
+msgstr "-r\t\t\tÂûâåñòè ñïèñîê ñâîï-ôàéëîâ è çàâåðøèòü ðàáîòó"
+
+msgid "-r (with file name)\tRecover crashed session"
+msgstr "-r (ñ èìåíåì ôàéëà)\tÂîññòàíîâèòü àâàðèéíî çàâåðø¸ííûé ñåàíñ"
+
+msgid "-L\t\t\tSame as -r"
+msgstr "-L\t\t\tÒî æå, ÷òî è -r"
+
+msgid "-f\t\t\tDon't use newcli to open window"
+msgstr "-f\t\t\tÍå èñïîëüçîâàòü newcli äëÿ îòêðûòèÿ îêíà"
+
+msgid "-dev <device>\t\tUse <device> for I/O"
+msgstr "-dev <óñòðîéñòâî>\t\tÈñïîëüçîâàòü äëÿ I/O óêàçàííîå <óñòðîéñòâî>"
+
+msgid "-A\t\t\tStart in Arabic mode"
+msgstr "-A\t\t\tÇàïóñê â Àðàáñêîì ðåæèìå"
+
+msgid "-H\t\t\tStart in Hebrew mode"
+msgstr "-H\t\t\tÇàïóñê â ðåæèìå \"Èâðèò\""
+
+msgid "-F\t\t\tStart in Farsi mode"
+msgstr "-F\t\t\tÇàïóñê â ðåæèìå \"Ôàðñè\""
+
+msgid "-T <terminal>\tSet terminal type to <terminal>"
+msgstr "-T <òåðìèíàë>\tÍàçíà÷èòü óêàçàííûé òèï <òåðìèíàëà>"
+
+msgid "--not-a-term\t\tSkip warning for input/output not being a terminal"
+msgstr "--not-a-term\t\tÍå ïðåäóïðåæäàòü ïðè ââîäå/âûâîäå íå â òåðìèíàë"
+
+msgid "--ttyfail\t\tExit if input or output is not a terminal"
+msgstr "--ttyfail\t\tÂûéòè ïðè ââîäå/âûâîäå íå â òåðìèíàë"
+
+msgid "-u <vimrc>\t\tUse <vimrc> instead of any .vimrc"
+msgstr "-u <vimrc>\t\tÈñïîëüçîâàòü <vimrc> âìåñòî ëþáûõ ôàéëîâ .vimrc"
+
+msgid "-U <gvimrc>\t\tUse <gvimrc> instead of any .gvimrc"
+msgstr "-U <gvimrc>\t\tÈñïîëüçîâàòü <gvimrc> âìåñòî ëþáûõ ôàéëîâ .gvimrc"
+
+msgid "--noplugin\t\tDon't load plugin scripts"
+msgstr "--noplugin\t\tÍå çàãðóæàòü ñöåíàðèè ìîäóëåé"
+
+# \n\t\t.. äëÿ óìåùåíèÿ â 80 ñòîëáöîâ
+msgid "-p[N]\t\tOpen N tab pages (default: one for each file)"
+msgstr ""
+"-p[N]\t\tÎòêðûòü N âêëàäîê (ïî óìîë÷àíèþ: ïî îäíîé\n"
+"\t\t\t\tíà êàæäûé ôàéë)"
+
+# \n\t\t.. äëÿ óìåùåíèÿ â 80 ñòîëáöîâ
+msgid "-o[N]\t\tOpen N windows (default: one for each file)"
+msgstr ""
+"-o[N]\t\tÎòêðûòü N îêîí (ïî óìîë÷àíèþ: ïî îäíîìó\n"
+"\t\t\t\tíà êàæäûé ôàéë)"
+
+msgid "-O[N]\t\tLike -o but split vertically"
+msgstr "-O[N]\t\tÒî æå, ÷òî è -o, íî ñ âåðòèêàëüíûì ðàçäåëåíèåì îêîí"
+
+msgid "+\t\t\tStart at end of file"
+msgstr "+\t\t\tÍà÷àòü ðåäàêòèðîâàíèå â êîíöå ôàéëà"
+
+msgid "+<lnum>\t\tStart at line <lnum>"
+msgstr "+<lnum>\t\tÍà÷àòü ðåäàêòèðîâàíèå â ñòðîêå ñ íîìåðîì <lnum>"
+
+msgid "--cmd <command>\tExecute <command> before loading any vimrc file"
+msgstr "--cmd <êîìàíäà>\tÂûïîëíèòü <êîìàíäó> ïåðåä çàãðóçêîé ôàéëà vimrc"
+
+msgid "-c <command>\t\tExecute <command> after loading the first file"
+msgstr "-c <êîìàíäà>\t\tÂûïîëíèòü <êîìàíäó> ïîñëå çàãðóçêè ïåðâîãî ôàéëà"
+
+# \n\t\t.. äëÿ óìåùåíèÿ â 80 ñòîëáöîâ
+msgid "-S <session>\t\tSource file <session> after loading the first file"
+msgstr ""
+"-S <ñåàíñ>\t\tÏðî÷èòàòü ñöåíàðèé <ñåàíñà> ïîñëå çàãðóçêè\n"
+"\t\t\t\tïåðâîãî ôàéëà"
+
+# \n\t\t.. äëÿ óìåùåíèÿ â 80 ñòîëáöîâ
+msgid "-s <scriptin>\tRead Normal mode commands from file <scriptin>"
+msgstr ""
+"-s <ñöåíàðèé>\tÏðî÷èòàòü êîìàíäû Îáû÷íîãî ðåæèìà èç\n"
+"\t\t\t\tôàéëà <ñöåíàðèÿ>"
+
+msgid "-w <scriptout>\tAppend all typed commands to file <scriptout>"
+msgstr "-w <ñöåíàðèé>\tÄîáàâëÿòü âñå ââåä¸ííûå êîìàíäû â ôàéë <ñöåíàðèÿ>"
+
+msgid "-W <scriptout>\tWrite all typed commands to file <scriptout>"
+msgstr "-W <ñöåíàðèé>\tÇàïèñàòü âñå ââåä¸ííûå êîìàíäû â ôàéë <ñöåíàðèÿ>"
+
+msgid "-x\t\t\tEdit encrypted files"
+msgstr "-x\t\t\tÐåäàêòèðîâàíèå çàøèôðîâàííûõ ôàéëîâ"
+
+msgid "-display <display>\tConnect vim to this particular X-server"
+msgstr "-display <ýêðàí>\tÏîäñîåäèíèòü Vim ê óêàçàííîìó X-ñåðâåðó"
+
+msgid "-X\t\t\tDo not connect to X server"
+msgstr "-X\t\t\tÍå âûïîëíÿòü ñîåäèíåíèå ñ ñåðâåðîì X"
+
+msgid "--remote <files>\tEdit <files> in a Vim server if possible"
+msgstr "--remote <ôàéëû>\tÏî âîçìîæíîñòè ðåäàêòèðîâàòü <ôàéëû> íà ñåðâåðå Vim"
+
+msgid "--remote-silent <files> Same, don't complain if there is no server"
+msgstr "--remote-silent <ôàéëû> Òî æå, íî áåç æàëîá íà îòñóòñòâèå ñåðâåðà"
+
+msgid ""
+"--remote-wait <files> As --remote but wait for files to have been edited"
+msgstr ""
+"--remote-wait <ôàéëû> Òî æå, ÷òî è --remote, íî ñ îæèäàíèåì çàâåðøåíèÿ"
+
+msgid ""
+"--remote-wait-silent <files> Same, don't complain if there is no server"
+msgstr ""
+"--remote-wait-silent <ôàéëû> Òî æå, íî áåç æàëîá íà îòñóòñòâèå ñåðâåðà"
+
+msgid ""
+"--remote-tab[-wait][-silent] <files> As --remote but use tab page per file"
+msgstr ""
+"--remote-tab[-wait][-silent] <ôàéëû> Òî æå, ÷òî è --remote, íî ñ âêëàäêàìè"
+
+msgid "--remote-send <keys>\tSend <keys> to a Vim server and exit"
+msgstr "--remote-send <êíîïêè>\tÎòïðàâèòü <êíîïêè> íà ñåðâåð Vim è âûéòè"
+
+msgid "--remote-expr <expr>\tEvaluate <expr> in a Vim server and print result"
+msgstr "--remote-expr <âûðàæ>\tÂû÷èñëèòü <âûðàæ> íà ñåðâåðå Vim è íàïå÷àòàòü"
+
+msgid "--serverlist\t\tList available Vim server names and exit"
+msgstr "--serverlist\t\tÏîêàçàòü ñïèñîê èì¸í ñåðâåðîâ Vim è çàâåðøèòü ðàáîòó"
+
+msgid "--servername <name>\tSend to/become the Vim server <name>"
+msgstr ""
+"--servername <èìÿ>\tÎòïðàâèòü íà/ñòàòü ñåðâåðîì Vim ñ óêàçàííûì <èìåíåì>"
+
+msgid "--startuptime <file>\tWrite startup timing messages to <file>"
+msgstr "--startuptime <ôàéë>\tÇàïèñàòü âðåìåííóþ ìåòêó î çàïóñêå â <ôàéë>"
+
+msgid "-i <viminfo>\t\tUse <viminfo> instead of .viminfo"
+msgstr "-i <viminfo>\t\tÈñïîëüçîâàòü âìåñòî .viminfo ôàéë <viminfo>"
+
+msgid "--clean\t\t'nocompatible', Vim defaults, no plugins, no viminfo"
+msgstr ""
+"--clean\t\tÍåïîëíàÿ ñîâìåñòèìîñòü ñ Vi, Vim ïî óìîë÷àíèþ,\n"
+"\t\t\t\táåç ìîäóëåé, áåç viminfo"
+
+msgid "-h or --help\tPrint Help (this message) and exit"
+msgstr "-h èëè --help\tÂûâåñòè ñïðàâêó (ýòî ñîîáùåíèå) è çàâåðøèòü ðàáîòó"
+
+msgid "--version\t\tPrint version information and exit"
+msgstr "--version\t\tÂûâåñòè èíôîðìàöèþ î âåðñèè Vim è çàâåðøèòü ðàáîòó"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Motif version):\n"
+msgstr ""
+"\n"
+"Ïàðàìåòðû äëÿ gvim (âåðñèÿ Motif):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (neXtaw version):\n"
+msgstr ""
+"\n"
+"Ïàðàìåòðû äëÿ gvim (âåðñèÿ neXtaw):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Athena version):\n"
+msgstr ""
+"\n"
+"Ïàðàìåòðû äëÿ gvim (âåðñèÿ Athena):\n"
+
+msgid "-display <display>\tRun vim on <display>"
+msgstr "-display <äèñïëåé>\tÇàïóñòèòü Vim íà óêàçàííîì <äèñïëåå>"
+
+msgid "-iconic\t\tStart vim iconified"
+msgstr "-iconic\t\tÇàïóñòèòü Vim â ñâ¸ðíóòîì âèäå"
+
+msgid "-background <color>\tUse <color> for the background (also: -bg)"
+msgstr "-background <öâåò>\tÈñïîëüçîâàòü óêàçàííûé <öâåò> äëÿ ôîíà (èëè -bg)"
+
+msgid "-foreground <color>\tUse <color> for normal text (also: -fg)"
+msgstr "-foreground <öâåò>\tÈñïîëüçîâàòü <öâåò> äëÿ îáû÷íîãî òåêñòà (èëè -fg)"
+
+msgid "-font <font>\t\tUse <font> for normal text (also: -fn)"
+msgstr "-font <øðèôò>\tÈñïîëüçîâàòü <øðèôò> äëÿ îáû÷íîãî òåêñòà (èëè -fn)"
+
+msgid "-boldfont <font>\tUse <font> for bold text"
+msgstr "-boldfont <øðèôò>\tÈñïîëüçîâàòü <øðèôò> äëÿ æèðíîãî òåêñòà"
+
+msgid "-italicfont <font>\tUse <font> for italic text"
+msgstr "-italicfont <øðèôò>\tÈñïîëüçîâàòü <øðèôò> äëÿ íàêëîííîãî òåêñòà"
+
+msgid "-geometry <geom>\tUse <geom> for initial geometry (also: -geom)"
+msgstr "-geometry <ãåîìåòðèÿ>\tÈñïîëüçîâàòü íà÷àëüíóþ <ãåîìåòðèþ> (èëè -geom)"
+
+msgid "-borderwidth <width>\tUse a border width of <width> (also: -bw)"
+msgstr "-borderwidth <øèðèíà>\tÈñïîëüçîâàòü <øèðèíó> áîðäþðà (èëè -bw)"
+
+msgid "-scrollbarwidth <width> Use a scrollbar width of <width> (also: -sw)"
+msgstr ""
+"-scrollbarwidth <øèðèíà> Èñïîëüçîâàòü øèðèíó ïîëîñû ïðîêðóòêè (èëè -sw)"
+
+msgid "-menuheight <height>\tUse a menu bar height of <height> (also: -mh)"
+msgstr "-menuheight <âûñîòà>\tÈñïîëüçîâàòü <âûñîòó> ìåíþ (èëè -mh)"
+
+msgid "-reverse\t\tUse reverse video (also: -rv)"
+msgstr "-reverse\t\tÈñïîëüçîâàòü èíâåðñíûé âèäåîðåæèì (èëè -rv)"
+
+msgid "+reverse\t\tDon't use reverse video (also: +rv)"
+msgstr "+reverse\t\tÍå èñïîëüçîâàòü èíâåðñíûé âèäåîðåæèì (èëè +rv)"
+
+msgid "-xrm <resource>\tSet the specified resource"
+msgstr "-xrm <ðåñóðñ>\tÓñòàíîâèòü óêàçàííûé <ðåñóðñ>"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (GTK+ version):\n"
+msgstr ""
+"\n"
+"Ïàðàìåòðû äëÿ gvim (âåðñèÿ GTK+):\n"
+
+msgid "-display <display>\tRun vim on <display> (also: --display)"
+msgstr ""
+"-display <äèñïëåé>\tÇàïóñòèòü Vim íà óêàçàííîì <äèñïëåå> (èëè --display)"
+
+msgid "--role <role>\tSet a unique role to identify the main window"
+msgstr ""
+"--role <ðîëü>\tÓñòàíîâèòü óíèêàëüíóþ <ðîëü>\n"
+"\t\t\t\täëÿ èäåíòèôèêàöèè ãëàâíîãî îêíà"
+
+msgid "--socketid <xid>\tOpen Vim inside another GTK widget"
+msgstr "--socketid <xid>\tÎòêðûòü Vim âíóòðè äðóãîãî êîìïîíåíòà GTK"
+
+msgid "--echo-wid\t\tMake gvim echo the Window ID on stdout"
+msgstr "--echo-wid\t\tÂûâåñòè Window ID äëÿ gvim íà ñòàíäàðòíûé ïîòîê âûâîäà"
+
+msgid "-P <parent title>\tOpen Vim inside parent application"
+msgstr "-P <çàãîëîâîê ðîäèòåëÿ>\tÎòêðûòü Vim â ðîäèòåëüñêîì ïðèëîæåíèè"
+
+msgid "--windowid <HWND>\tOpen Vim inside another win32 widget"
+msgstr "--windowid <HWND>\tÎòêðûòü Vim âíóòðè äðóãîãî êîìïîíåíòà win32"
+
+msgid "No display"
+msgstr "Íåò äèñïëåÿ"
+
+msgid ": Send failed.\n"
+msgstr ": Îòïðàâêà íå óäàëàñü.\n"
+
+msgid ": Send failed. Trying to execute locally\n"
+msgstr ": Îòïðàâêà íå óäàëàñü. Ïîïûòêà ìåñòíîãî âûïîëíåíèÿ\n"
+
+#, c-format
+msgid "%d of %d edited"
+msgstr "îòðåäàêòèðîâàíî %d èç %d"
+
+msgid "No display: Send expression failed.\n"
+msgstr "Íåò äèñïëåÿ: îòïðàâêà âûðàæåíèÿ íå óäàëàñü.\n"
+
+msgid ": Send expression failed.\n"
+msgstr ": Îòïðàâêà âûðàæåíèÿ íå óäàëàñü.\n"
+
+msgid "No marks set"
+msgstr "Íåò óñòàíîâëåííûõ îòìåòîê"
+
+#, c-format
+msgid "E283: No marks matching \"%s\""
+msgstr "E283: Íåò îòìåòîê, ñîâïàäàþùèõ ñ \"%s\""
+
+msgid ""
+"\n"
+"mark line col file/text"
+msgstr ""
+"\n"
+"îòìåò ñòð êîë ôàéë/òåêñò"
+
+msgid ""
+"\n"
+" jump line col file/text"
+msgstr ""
+"\n"
+"ïðûæîê ñòð êîë ôàéë/òåêñò"
+
+msgid ""
+"\n"
+"change line col text"
+msgstr ""
+"\n"
+"èçìåí. ñòð êîë òåêñò"
+
+msgid ""
+"\n"
+"# File marks:\n"
+msgstr ""
+"\n"
+"# Ãëîáàëüíûå îòìåòêè:\n"
+
+msgid ""
+"\n"
+"# Jumplist (newest first):\n"
+msgstr ""
+"\n"
+"# Ñïèñîê ïðûæêîâ (ñíà÷àëà áîëåå ñâåæèå):\n"
+
+msgid ""
+"\n"
+"# History of marks within files (newest to oldest):\n"
+msgstr ""
+"\n"
+"# Èñòîðèÿ ìåñòíûõ îòìåòîê (îò áîëåå ñâåæèõ ê ñòàðûì):\n"
+
+msgid "Missing '>'"
+msgstr "Ïðîïóùåíà '>'"
+
+msgid "E543: Not a valid codepage"
+msgstr "E543: Íåäîïóñòèìîå èìÿ êîäèðîâêè"
+
+msgid "E284: Cannot set IC values"
+msgstr "E284: Íåâîçìîæíî íàçíà÷èòü çíà÷åíèÿ êîíòåêñòà ââîäà"
+
+msgid "E285: Failed to create input context"
+msgstr "E285: Íåâîçìîæíî ñîçäàòü êîíòåêñò ââîäà"
+
+msgid "E286: Failed to open input method"
+msgstr "E286: Íåóäà÷íàÿ ïîïûòêà îòêðûòü ìåòîä ââîäà"
+
+msgid "E287: Warning: Could not set destroy callback to IM"
+msgstr ""
+"E287: Ïðåäóïðåæäåíèå: íåâîçìîæíî íàçíà÷èòü îáð. âûçîâ óíè÷òîæåíèÿ ìåòîäà "
+"ââîäà"
+
+msgid "E288: input method doesn't support any style"
+msgstr "E288: Ìåòîä ââîäà íå ïîääåðæèâàåò ñòèëè"
+
+msgid "E289: input method doesn't support my preedit type"
+msgstr ""
+"E289: Ìåòîä ââîäà íå ïîääåðæèâàåò ìîé òèï ïðåäâàðèòåëüíîãî ðåäàêòèðîâàíèÿ"
+
+msgid "E293: block was not locked"
+msgstr "E293: Áëîê íå çàáëîêèðîâàí"
+
+msgid "E294: Seek error in swap file read"
+msgstr "E294: Îøèáêà ïîèñêà ïðè ÷òåíèè ñâîï-ôàéëà"
+
+msgid "E295: Read error in swap file"
+msgstr "E295: Îøèáêà ÷òåíèÿ ñâîï-ôàéëà"
+
+msgid "E296: Seek error in swap file write"
+msgstr "E296: Îøèáêà ïîèñêà ïðè çàïèñè ñâîï-ôàéëà"
+
+msgid "E297: Write error in swap file"
+msgstr "E297: Îøèáêà ïðè çàïèñè ñâîï-ôàéëà"
+
+msgid "E300: Swap file already exists (symlink attack?)"
+msgstr ""
+"E300: Ñâîï-ôàéë óæå ñóùåñòâóåò (àòàêà ñ èñïîëüçîâàíèåì ñèìâîëüíîé ññûëêè?)"
+
+msgid "E298: Didn't get block nr 0?"
+msgstr "E298: Íå ïîëó÷åí áëîê íîìåð 0?"
+
+msgid "E298: Didn't get block nr 1?"
+msgstr "E298: Íå ïîëó÷åí áëîê íîìåð 1?"
+
+msgid "E298: Didn't get block nr 2?"
+msgstr "E298: Íå ïîëó÷åí áëîê íîìåð 2?"
+
+msgid "E843: Error while updating swap file crypt"
+msgstr "E843: Îøèáêà ïðè îáíîâëåíèè øèôðîâàíèÿ ñâîï-ôàéëà"
+
+msgid "E301: Oops, lost the swap file!!!"
+msgstr "E301: Îé, ïîòåðÿëñÿ ñâîï-ôàéë!!!"
+
+msgid "E302: Could not rename swap file"
+msgstr "E302: Íåâîçìîæíî ïåðåèìåíîâàòü ñâîï-ôàéë"
+
+#, c-format
+msgid "E303: Unable to open swap file for \"%s\", recovery impossible"
+msgstr ""
+"E303: Íå óäàëîñü îòêðûòü ñâîï-ôàéë äëÿ \"%s\", âîññòàíîâëåíèå íåâîçìîæíî"
+
+msgid "E304: ml_upd_block0(): Didn't get block 0??"
+msgstr "E304: ml_upd_block0(): Íå ïîëó÷åí áëîê 0??"
+
+#, c-format
+msgid "E305: No swap file found for %s"
+msgstr "E305: Ñâîï-ôàéë äëÿ %s íå íàéäåí"
+
+msgid "Enter number of swap file to use (0 to quit): "
+msgstr ""
+"Ââåäèòå íîìåð ñâîï-ôàéëà, êîòîðûé ñëåäóåò èñïîëüçîâàòü (0 äëÿ âûõîäà): "
+
+#, c-format
+msgid "E306: Cannot open %s"
+msgstr "E306: Íå ìîãó îòêðûòü %s"
+
+msgid "Unable to read block 0 from "
+msgstr "Íåâîçìîæíî ïðî÷èòàòü áëîê 0 èç "
+
+msgid ""
+"\n"
+"Maybe no changes were made or Vim did not update the swap file."
+msgstr ""
+"\n"
+"Íåò èçìåíåíèé, èëè Vim íå ñìîã îáíîâèòü ñâîï-ôàéë"
+
+msgid " cannot be used with this version of Vim.\n"
+msgstr " íåëüçÿ èñïîëüçîâàòü â äàííîé âåðñèè Vim.\n"
+
+msgid "Use Vim version 3.0.\n"
+msgstr "Èñïîëüçóéòå Vim âåðñèè 3.0.\n"
+
+#, c-format
+msgid "E307: %s does not look like a Vim swap file"
+msgstr "E307: %s íå ÿâëÿåòñÿ ñâîï-ôàéëîì Vim"
+
+msgid " cannot be used on this computer.\n"
+msgstr " íåëüçÿ èñïîëüçîâàòü íà ýòîì êîìïüþòåðå.\n"
+
+msgid "The file was created on "
+msgstr "Ôàéë áûë ñîçäàí "
+
+msgid ""
+",\n"
+"or the file has been damaged."
+msgstr ""
+",\n"
+"ëèáî ôàéë áûë ïîâðåæä¸í."
+
+#, c-format
+msgid ""
+"E833: %s is encrypted and this version of Vim does not support encryption"
+msgstr "E833: %s çàøèôðîâàí, à ýòà âåðñèÿ Vim íå ïîääåðæèâàåò øèôðîâàíèå"
+
+msgid " has been damaged (page size is smaller than minimum value).\n"
+msgstr " áûë ïîâðåæä¸í (ðàçìåð ñòðàíèöû ìåíüøå ìèíèìàëüíîãî çíà÷åíèÿ).\n"
+
+#, c-format
+msgid "Using swap file \"%s\""
+msgstr "Èñïîëüçóåòñÿ ñâîï-ôàéë \"%s\""
+
+#, c-format
+msgid "Original file \"%s\""
+msgstr "Èñõîäíûé ôàéë \"%s\""
+
+msgid "E308: Warning: Original file may have been changed"
+msgstr "E308: Ïðåäóïðåæäåíèå: èñõîäíûé ôàéë ìîã áûòü èçìåí¸í"
+
+#, c-format
+msgid "Swap file is encrypted: \"%s\""
+msgstr "Ñâîï-ôàéë çàøèôðîâàí: \"%s\""
+
+msgid ""
+"\n"
+"If you entered a new crypt key but did not write the text file,"
+msgstr ""
+"\n"
+"Åñëè âû ââåëè íîâûé ïàðîëü äëÿ øèôðîâàíèÿ, íî íå çàïèñàëè òåêñòîâûé ôàéë,"
+
+msgid ""
+"\n"
+"enter the new crypt key."
+msgstr ""
+"\n"
+"òî ââåäèòå íîâûé ïàðîëü äëÿ øèôðîâàíèÿ."
+
+# Ïåðåâîä ñîîáùåíèÿ ðàçäåë¸í íà äâå ÷àñòè, ÷àñòü ïåðâàÿ
+msgid ""
+"\n"
+"If you wrote the text file after changing the crypt key press enter"
+msgstr ""
+"\n"
+"Åñëè âû çàïèñàëè òåêñòîâûé ôàéë ïîñëå èçìåíåíèÿ ïàðîëÿ øèôðîâàíèÿ, òî íàæìèòå"
+
+# Ïåðåâîä ñîîáùåíèÿ ðàçäåë¸í íà äâå ÷àñòè, ÷àñòü âòîðàÿ
+msgid ""
+"\n"
+"to use the same key for text file and swap file"
+msgstr ""
+"\n"
+"Enter äëÿ èñïîëüçîâàíèÿ îäíîãî êëþ÷à äëÿ òåêñòîâîãî ôàéëà è ñâîï-ôàéëà"
+
+#, c-format
+msgid "E309: Unable to read block 1 from %s"
+msgstr "E309: Íåâîçìîæíî ïðî÷èòàòü áëîê 1 èç %s"
+
+msgid "???MANY LINES MISSING"
+msgstr "???ÎÒÑÓÒÑÒÂÓÅÒ ÌÍÎÃÎ ÑÒÐÎÊ"
+
+msgid "???LINE COUNT WRONG"
+msgstr "???ÍÅÏÐÀÂÈËÜÍÎÅ ÇÍÀ×ÅÍÈÅ ÑרÒ×ÈÊÀ ÑÒÐÎÊ"
+
+msgid "???EMPTY BLOCK"
+msgstr "???ÏÓÑÒÎÉ ÁËÎÊ"
+
+msgid "???LINES MISSING"
+msgstr "???ÎÒÑÓÒÑÒÂÓÞÒ ÑÒÐÎÊÈ"
+
+#, c-format
+msgid "E310: Block 1 ID wrong (%s not a .swp file?)"
+msgstr "E310: Íåïðàâèëüíûé áëîê 1 ID (%s íå ÿâëÿåòñÿ ôàéëîì .swp?)"
+
+msgid "???BLOCK MISSING"
+msgstr "???ÏÐÎÏÓÙÅÍ ÁËÎÊ"
+
+msgid "??? from here until ???END lines may be messed up"
+msgstr "???ñòðîêè ìîãóò áûòü èñïîð÷åíû îòñþäà äî ???ÊÎÍÖÀ"
+
+msgid "??? from here until ???END lines may have been inserted/deleted"
+msgstr "???ñòðîêè ìîãëè áûòü âñòàâëåíû èëè óäàëåíû îòñþäà äî ???ÊÎÍÖÀ"
+
+msgid "???END"
+msgstr "???ÊÎÍÅÖ"
+
+msgid "E311: Recovery Interrupted"
+msgstr "E311: Âîññòàíîâëåíèå ïðåðâàíî"
+
+msgid ""
+"E312: Errors detected while recovering; look for lines starting with ???"
+msgstr ""
+"E312: Âî âðåìÿ âîññòàíîâëåíèÿ îáíàðóæåíû îøèáêè; ñì. ñòðîêè, íà÷èíàþùèåñÿ "
+"ñ ???"
+
+msgid "See \":help E312\" for more information."
+msgstr "Ñì. \":help E312\" äëÿ äîïîëíèòåëüíîé èíôîðìàöèè."
+
+msgid "Recovery completed. You should check if everything is OK."
+msgstr "Âîññòàíîâëåíèå çàâåðøåíî. Ïðîâåðüòå, âñ¸ ëè â ïîðÿäêå."
+
+msgid ""
+"\n"
+"(You might want to write out this file under another name\n"
+msgstr ""
+"\n"
+"(Ìîæåòå çàïèñàòü ôàéë ïîä äðóãèì èìåíåì è ñðàâíèòü åãî ñ èñõîäíûì\n"
+
+msgid "and run diff with the original file to check for changes)"
+msgstr "ôàéëîì ïðè ïîìîùè ïðîãðàììû diff)"
+
+msgid "Recovery completed. Buffer contents equals file contents."
+msgstr "Âîññòàíîâëåíèå çàâåðøåíî. Ñîäåðæèìîå áóôåðîâ è ôàéëîâ ýêâèâàëåíòíî."
+
+msgid ""
+"\n"
+"You may want to delete the .swp file now.\n"
+"\n"
+msgstr ""
+"\n"
+"Âåðîÿòíî, ñåé÷àñ âû çàõîòèòå óäàëèòü ôàéë .swp.\n"
+"\n"
+
+msgid "Using crypt key from swap file for the text file.\n"
+msgstr "Èñïîëüçîâàíèå êëþ÷à øèôðîâàíèÿ èç ñâîï-ôàéëà äëÿ òåêñòîâîãî ôàéëà.\n"
+
+msgid "Swap files found:"
+msgstr "Îáíàðóæåíû ñâîï-ôàéëû:"
+
+msgid " In current directory:\n"
+msgstr " Â òåêóùåì êàòàëîãå:\n"
+
+msgid " Using specified name:\n"
+msgstr " Ñ óêàçàííûì èìåíåì:\n"
+
+msgid " In directory "
+msgstr " Â êàòàëîãå "
+
+msgid " -- none --\n"
+msgstr " -- íåò --\n"
+
+msgid " owned by: "
+msgstr " âëàäåëåö: "
+
+msgid " dated: "
+msgstr " äàòà: "
+
+msgid " dated: "
+msgstr " äàòà: "
+
+msgid " [from Vim version 3.0]"
+msgstr " [îò Vim âåðñèè 3.0]"
+
+msgid " [does not look like a Vim swap file]"
+msgstr " [íå ÿâëÿåòñÿ ñâîï-ôàéëîì Vim]"
+
+msgid " file name: "
+msgstr " èìÿ ôàéëà: "
+
+msgid ""
+"\n"
+" modified: "
+msgstr ""
+"\n"
+" èçìåí¸í: "
+
+msgid "YES"
+msgstr "ÄÀ"
+
+msgid "no"
+msgstr "íåò"
+
+msgid ""
+"\n"
+" user name: "
+msgstr ""
+"\n"
+" ïîëüçîâàòåëü: "
+
+msgid " host name: "
+msgstr " êîìïüþòåð: "
+
+msgid ""
+"\n"
+" host name: "
+msgstr ""
+"\n"
+" êîìïüþòåð: "
+
+msgid ""
+"\n"
+" process ID: "
+msgstr ""
+"\n"
+" ïðîöåññ: "
+
+msgid " (still running)"
+msgstr " (åù¸ âûïîëíÿåòñÿ)"
+
+msgid ""
+"\n"
+" [not usable with this version of Vim]"
+msgstr ""
+"\n"
+" [íå ïðèãîäåí äëÿ èñïîëüçîâàíèÿ ñ äàííîé âåðñèåé Vim]"
+
+msgid ""
+"\n"
+" [not usable on this computer]"
+msgstr ""
+"\n"
+" [íå ïðèãîäåí äëÿ èñïîëüçîâàíèÿ íà ýòîì êîìïüþòåðå]"
+
+msgid " [cannot be read]"
+msgstr " [íå ÷èòàåòñÿ]"
+
+msgid " [cannot be opened]"
+msgstr " [íå îòêðûâàåòñÿ]"
+
+msgid "E313: Cannot preserve, there is no swap file"
+msgstr "E313: Íåâîçìîæíî îáíîâèòü ñâîï-ôàéë, ïîñêîëüêó îí íå îáíàðóæåí"
+
+msgid "File preserved"
+msgstr "Ñâîï-ôàéë îáíîâë¸í"
+
+msgid "E314: Preserve failed"
+msgstr "E314: Íåóäà÷íàÿ ïîïûòêà îáíîâëåíèÿ ñâîï-ôàéëà"
+
+#, c-format
+msgid "E315: ml_get: invalid lnum: %ld"
+msgstr "E315: ml_get: íåïðàâèëüíîå çíà÷åíèå lnum: %ld"
+
+#, c-format
+msgid "E316: ml_get: cannot find line %ld"
+msgstr "E316: ml_get: íåâîçìîæíî íàéòè ñòðîêó %ld"
+
+msgid "E317: pointer block id wrong 3"
+msgstr "E317: Íåïðàâèëüíîå çíà÷åíèå óêàçàòåëÿ áëîêà 3"
+
+msgid "stack_idx should be 0"
+msgstr "çíà÷åíèå stack_idx äîëæíî áûòü ðàâíî 0"
+
+msgid "E318: Updated too many blocks?"
+msgstr "E318: Îáíîâëåíî ñëèøêîì ìíîãî áëîêîâ?"
+
+msgid "E317: pointer block id wrong 4"
+msgstr "E317: Íåïðàâèëüíîå çíà÷åíèå óêàçàòåëÿ áëîêà 4"
+
+msgid "deleted block 1?"
+msgstr "óäàë¸í áëîê 1?"
+
+#, c-format
+msgid "E320: Cannot find line %ld"
+msgstr "E320: Ñòðîêà %ld íå îáíàðóæåíà"
+
+msgid "E317: pointer block id wrong"
+msgstr "E317: Íåïðàâèëüíîå çíà÷åíèå óêàçàòåëÿ áëîêà"
+
+msgid "pe_line_count is zero"
+msgstr "çíà÷åíèå pe_line_count ðàâíî íóëþ"
+
+#, c-format
+msgid "E322: line number out of range: %ld past the end"
+msgstr "E322: Íîìåð ñòðîêè çà ïðåäåëàìè äèàïàçîíà: %ld"
+
+#, c-format
+msgid "E323: line count wrong in block %ld"
+msgstr "E323: Íåïðàâèëüíîå çíà÷åíèå ñ÷¸ò÷èêà ñòðîê â áëîêå %ld"
+
+msgid "Stack size increases"
+msgstr "Ðàçìåð ñòåêà óâåëè÷åí"
+
+msgid "E317: pointer block id wrong 2"
+msgstr "E317: Íåïðàâèëüíîå çíà÷åíèå óêàçàòåëÿ áëîêà 2"
+
+#, c-format
+msgid "E773: Symlink loop for \"%s\""
+msgstr "E773: Ïåòëÿ ñèìâîëüíûõ ññûëîê äëÿ \"%s\""
+
+msgid "E325: ATTENTION"
+msgstr "E325: ÂÍÈÌÀÍÈÅ"
+
+msgid ""
+"\n"
+"Found a swap file by the name \""
+msgstr ""
+"\n"
+"Îáíàðóæåí ñâîï-ôàéë ñ èìåíåì \""
+
+# Ñ ìàëåíüêîé áóêâû, ÷òîáû ñîîòâåòñòâîâàëî ïî ñòèëþ ñîñåäíèì ñîîáùåíèÿì.
+msgid "While opening file \""
+msgstr "ïðè îòêðûòèè ôàéëà: \""
+
+msgid " NEWER than swap file!\n"
+msgstr " Áîëåå ÑÂÅÆÈÉ, ÷åì ñâîï-ôàéë!\n"
+
+msgid ""
+"\n"
+"(1) Another program may be editing the same file. If this is the case,\n"
+" be careful not to end up with two different instances of the same\n"
+" file when making changes. Quit, or continue with caution.\n"
+msgstr ""
+"\n"
+"(1) Âîçìîæíî, ðåäàêòèðîâàíèå ýòîãî æå ôàéëà âûïîëíÿåòñÿ â äðóãîé ïðîãðàììå.\n"
+" Åñëè ýòî òàê, òî áóäüòå âíèìàòåëüíû ïðè âíåñåíèè èçìåíåíèé, ÷òîáû\n"
+" ó âàñ íå ïîÿâèëîñü äâà ðàçíûõ âàðèàíòà îäíîãî è òîãî æå ôàéëà.\n"
+" Âûéäèòå èëè ïðîäîëæàéòå ñ îñòîðîæíîñòüþ.\n"
+
+msgid "(2) An edit session for this file crashed.\n"
+msgstr "(2) Ñåàíñ ðåäàêòèðîâàíèÿ ýòîãî ôàéëà çàâåðø¸í àâàðèéíî.\n"
+
+msgid " If this is the case, use \":recover\" or \"vim -r "
+msgstr "  ýòîì ñëó÷àå, èñïîëüçóéòå êîìàíäó \":recover\" èëè \"vim -r "
+
+msgid ""
+"\"\n"
+" to recover the changes (see \":help recovery\").\n"
+msgstr ""
+"\"\n"
+" äëÿ âîññòàíîâëåíèÿ èçìåíåíèé (ñì. \":help recovery\").\n"
+
+msgid " If you did this already, delete the swap file \""
+msgstr " Åñëè âû óæå âûïîëíÿëè ýòó îïåðàöèþ, óäàëèòå ñâîï-ôàéë \""
+
+msgid ""
+"\"\n"
+" to avoid this message.\n"
+msgstr ""
+"\"\n"
+" ÷òîáû èçáåæàòü ïîÿâëåíèÿ ýòîãî ñîîáùåíèÿ â áóäóùåì.\n"
+
+msgid "Swap file \""
+msgstr "Ñâîï-ôàéë \""
+
+msgid "\" already exists!"
+msgstr "\" óæå ñóùåñòâóåò!"
+
+msgid "VIM - ATTENTION"
+msgstr "VIM — ÂÍÈÌÀÍÈÅ"
+
+msgid "Swap file already exists!"
+msgstr "Ñâîï-ôàéë óæå ñóùåñòâóåò!"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"&O Îòêðûòü äëÿ ÷òåíèÿ\n"
+"&E Ðåäàêòèðîâàòü\n"
+"&R Âîññòàíîâèòü\n"
+"&Q Âûõîä\n"
+"&A Ïðåðâàòü"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Delete it\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"&O Îòêðûòü äëÿ ÷òåíèÿ\n"
+"&E Ðåäàêòèðîâàòü\n"
+"&R Âîññòàíîâèòü\n"
+"&D Óäàëèòü\n"
+"&Q Âûõîä\n"
+"&A Ïðåðâàòü"
+
+msgid "E326: Too many swap files found"
+msgstr "E326: Îáíàðóæåíî ñëèøêîì ìíîãî ñâîï-ôàéëîâ"
+
+msgid "E327: Part of menu-item path is not sub-menu"
+msgstr "E327: Êîìïîíåíò ïóòè ê ýëåìåíòó ìåíþ íå ÿâëÿåòñÿ ïîäìåíþ"
+
+msgid "E328: Menu only exists in another mode"
+msgstr "E328: Ìåíþ â ýòîì ðåæèìå íå ñóùåñòâóåò"
+
+#, c-format
+msgid "E329: No menu \"%s\""
+msgstr "E329: Íåò ìåíþ %s"
+
+msgid "E792: Empty menu name"
+msgstr "E792: Ïóñòîå èìÿ ìåíþ"
+
+msgid "E330: Menu path must not lead to a sub-menu"
+msgstr "E330: Ïóòü ê ìåíþ íå äîëæåí âåñòè ê ïîäìåíþ"
+
+msgid "E331: Must not add menu items directly to menu bar"
+msgstr "E331: Ýëåìåíòû ìåíþ íåëüçÿ äîáàâëÿòü íåïîñðåäñòâåííî â ïîëîñêó ìåíþ"
+
+msgid "E332: Separator cannot be part of a menu path"
+msgstr "E332: Ðàçäåëèòåëè íå ìîãóò áûòü êîìïîíåíòîì ïóòè ê ìåíþ"
+
+msgid ""
+"\n"
+"--- Menus ---"
+msgstr ""
+"\n"
+"--- Ìåíþ ---"
+
+msgid "Tear off this menu"
+msgstr "Îòîðâàòü ýòî ìåíþ"
+
+#, c-format
+msgid "E335: Menu not defined for %s mode"
+msgstr "E335: Ìåíþ íå îïðåäåëåíî äëÿ ðåæèìà %s"
+
+msgid "E333: Menu path must lead to a menu item"
+msgstr "E333: Ïóòü ê ìåíþ äîëæåí âåñòè ê ýëåìåíòó ìåíþ"
+
+#, c-format
+msgid "E334: Menu not found: %s"
+msgstr "E334: Ìåíþ íå íàéäåíî: %s"
+
+msgid "E336: Menu path must lead to a sub-menu"
+msgstr "E336: Ïóòü ê ìåíþ äîëæåí âåñòè ê ïîäìåíþ"
+
+msgid "E337: Menu not found - check menu names"
+msgstr "E337: Ìåíþ íå íàéäåíî — ïðîâåðüòå èìåíà ìåíþ"
+
+#, c-format
+msgid "Error detected while processing %s:"
+msgstr "Îáíàðóæåíà îøèáêà ïðè îáðàáîòêå %s:"
+
+#, c-format
+msgid "line %4ld:"
+msgstr "ñòðîêà %4ld:"
+
+#, c-format
+msgid "E354: Invalid register name: '%s'"
+msgstr "E354: Íåäîïóñòèìîå èìÿ ðåãèñòðà: '%s'"
+
+msgid "Messages maintainer: Bram Moolenaar <Bram@vim.org>"
+msgstr ""
+"Ïåðåâîä ñîîáùåíèé íà ðóññêèé ÿçûê: Âàñèëèé Ðàãîçèí <vrr@users.sourceforge."
+"net>, Ñåðãåé Àë¸øèí <alyoshin.s@gmail.com>"
+
+msgid "Interrupt: "
+msgstr "Ïðåðûâàíèå: "
+
+msgid "Press ENTER or type command to continue"
+msgstr "Íàæìèòå ENTER èëè ââåäèòå êîìàíäó äëÿ ïðîäîëæåíèÿ"
+
+#, c-format
+msgid "%s line %ld"
+msgstr "%s ñòðîêà %ld"
+
+msgid "-- More --"
+msgstr "-- Ïðîäîëæåíèå ñëåäóåò --"
+
+msgid " SPACE/d/j: screen/page/line down, b/u/k: up, q: quit "
+msgstr " SPACE/d/j: ýêðàí/ñòðàíèöà/ñòðîêà âíèç, b/u/k: ââåðõ, q: âûõîä "
+
+msgid "Question"
+msgstr "Âîïðîñ"
+
+msgid ""
+"&Yes\n"
+"&No"
+msgstr ""
+"&Y Äà\n"
+"&N Íåò"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"Save &All\n"
+"&Discard All\n"
+"&Cancel"
+msgstr ""
+"&Y Äà\n"
+"&N Íåò\n"
+"&A Ñîõðàíèòü âñå\n"
+"&D Ïîòåðÿòü âñå\n"
+"&C Îòìåíà"
+
+msgid "Select Directory dialog"
+msgstr "Âûáîð êàòàëîãà"
+
+msgid "Save File dialog"
+msgstr "Ñîõðàíåíèå ôàéëà"
+
+msgid "Open File dialog"
+msgstr "Îòêðûòèå ôàéëà"
+
+msgid "E338: Sorry, no file browser in console mode"
+msgstr ""
+"E338: Èçâèíèòå, íî â êîíñîëüíîì ðåæèìå íåò ïðîâîäíèêà ïî ôàéëîâîé ñèñòåìå"
+
+msgid "E766: Insufficient arguments for printf()"
+msgstr "E766: Íåäîñòàòî÷íî ïàðàìåòðîâ äëÿ printf()"
+
+msgid "E807: Expected Float argument for printf()"
+msgstr "E807: Îæèäàëñÿ ïàðàìåòð òèïà ñ ïëàâàþùåé òî÷êîé äëÿ printf()"
+
+msgid "E767: Too many arguments to printf()"
+msgstr "E767: Ñëèøêîì ìíîãî ïàðàìåòðîâ äëÿ printf()"
+
+msgid "W10: Warning: Changing a readonly file"
+msgstr "W10: Ïðåäóïðåæäåíèå: Èçìåíåíèå ôàéëà ñ ïðàâàìè òîëüêî äëÿ ÷òåíèÿ"
+
+msgid "Type number and <Enter> or click with mouse (empty cancels): "
+msgstr "Ââåäèòå íîìåð è <Enter> èëè ù¸ëêíèòå ìûøüþ (ïóñòî äëÿ îòìåíû): "
+
+msgid "Type number and <Enter> (empty cancels): "
+msgstr "Ââåäèòå íîìåð è <Enter> (ïóñòî äëÿ îòìåíû): "
+
+msgid "1 more line"
+msgstr "Äîáàâëåíà îäíà ñòðîêà"
+
+msgid "1 line less"
+msgstr "Óáðàíà îäíà ñòðîêà"
+
+#, c-format
+msgid "%ld more lines"
+msgstr "Äîáàâëåíî ñòðîê: %ld"
+
+#, c-format
+msgid "%ld fewer lines"
+msgstr "Óáðàíî ñòðîê: %ld"
+
+msgid " (Interrupted)"
+msgstr " (Ïðåðâàíî)"
+
+msgid "Beep!"
+msgstr "Áè-áè!"
+
+msgid "ERROR: "
+msgstr "ÎØÈÁÊÀ: "
+
+#, c-format
+msgid ""
+"\n"
+"[bytes] total alloc-freed %lu-%lu, in use %lu, peak use %lu\n"
+msgstr ""
+"\n"
+"[áàéò] âñåãî âûäåë.-îñâîá. %lu-%lu, èñïîëüç. %lu, ìàêñ. èñïîëüç. %lu\n"
+
+#, c-format
+msgid ""
+"[calls] total re/malloc()'s %lu, total free()'s %lu\n"
+"\n"
+msgstr ""
+"[âûçîâû] re/malloc() âñåãî %lu, free() âñåãî %lu\n"
+"\n"
+
+msgid "E340: Line is becoming too long"
+msgstr "E340: Ñòðîêà ñòàíîâèòñÿ ñëèøêîì äëèííîé"
+
+#, c-format
+msgid "E341: Internal error: lalloc(%ld, )"
+msgstr "E341: Âíóòðåííÿÿ îøèáêà: lalloc(%ld, )"
+
+#, c-format
+msgid "E342: Out of memory! (allocating %lu bytes)"
+msgstr "E342: Íå õâàòàåò ïàìÿòè! (âûäåëÿåòñÿ %lu áàéò)"
+
+#, c-format
+msgid "Calling shell to execute: \"%s\""
+msgstr "Âûçîâ îáîëî÷êè äëÿ èñïîëíåíèÿ: \"%s\""
+
+msgid "E545: Missing colon"
+msgstr "E545: Ïðîïóùåíî äâîåòî÷èå"
+
+msgid "E546: Illegal mode"
+msgstr "E546: Íåäîïóñòèìûé ðåæèì"
+
+msgid "E547: Illegal mouseshape"
+msgstr "E547: Íåäîïóñòèìàÿ ôîðìà êóðñîðà"
+
+msgid "E548: digit expected"
+msgstr "E548: Òðåáóåòñÿ ââåñòè öèôðó"
+
+msgid "E549: Illegal percentage"
+msgstr "E549: Íåäîïóñòèìîå çíà÷åíèå ïðîöåíòîâ"
+
+msgid "E854: path too long for completion"
+msgstr "E854: ñëèøêîì áîëüøîé ïóòü äëÿ àâòîäîïîëíåíèÿ"
+
+#, c-format
+msgid ""
+"E343: Invalid path: '**[number]' must be at the end of the path or be "
+"followed by '%s'."
+msgstr ""
+"E343: Íåïðàâèëüíî çàäàí ïóòü: '**[÷èñëî]' äîëæíî áûòü ëèáî â êîíöå ïóòè, "
+"ëèáî çà íèì äîëæíî ñëåäîâàòü '%s'"
+
+#, c-format
+msgid "E344: Can't find directory \"%s\" in cdpath"
+msgstr "E344: Êàòàëîã \"%s\" íå íàéäåí â ïóòè äëÿ ñìåíû êàòàëîãà"
+
+#, c-format
+msgid "E345: Can't find file \"%s\" in path"
+msgstr "E345: Ôàéë \"%s\" â èçâåñòíûõ êàòàëîãàõ íå íàéäåí"
+
+#, c-format
+msgid "E346: No more directory \"%s\" found in cdpath"
+msgstr "E346: Â ïóòè ñìåíû êàòàëîãà áîëüøå íåò êàòàëîãîâ \"%s\""
+
+#, c-format
+msgid "E347: No more file \"%s\" found in path"
+msgstr "E347: Â èçâåñòíûõ êàòàëîãàõ áîëüøå íåò ôàéëîâ \"%s\""
+
+#, c-format
+msgid "E668: Wrong access mode for NetBeans connection info file: \"%s\""
+msgstr ""
+"E668: Íåïðàâèëüíûé ðåæèì äîñòóïà ê èíôîðìàöèè î ñîåäèíåíèè ñ NetBeans: \"%s\""
+
+#, c-format
+msgid "E658: NetBeans connection lost for buffer %ld"
+msgstr "E658: Ïîòåðÿíî ñîåäèíåíèå ñ NetBeans äëÿ áóôåðà %ld"
+
+msgid "E838: netbeans is not supported with this GUI"
+msgstr "E838: NetBeans íå ïîääåðæèâàåòñÿ ñ ýòèì ãðàôè÷åñêèì èíòåðôåéñîì"
+
+msgid "E511: netbeans already connected"
+msgstr "E511: óæå ñîåäèí¸í ñ NetBeans"
+
+#, c-format
+msgid "E505: %s is read-only (add ! to override)"
+msgstr "E505: %s îòêðûò òîëüêî äëÿ ÷òåíèÿ (äîáàâüòå !, ÷òîáû îáîéòè ïðîâåðêó)"
+
+msgid "E349: No identifier under cursor"
+msgstr "E349: Íåò èìåíè â ïîçèöèè êóðñîðà"
+
+msgid "E774: 'operatorfunc' is empty"
+msgstr "E774: Çíà÷åíèåì îïöèè 'operatorfunc' ÿâëÿåòñÿ ïóñòàÿ ñòðîêà"
+
+msgid "E775: Eval feature not available"
+msgstr "E775: eval íåäîñòóïíà"
+
+msgid "Warning: terminal cannot highlight"
+msgstr "Ïðåäóïðåæäåíèå: òåðìèíàë íå ìîæåò âûïîëíÿòü ïîäñâåòêó"
+
+msgid "E348: No string under cursor"
+msgstr "E348: Íåò ñòðîêè â ïîçèöèè êóðñîðà"
+
+msgid "E352: Cannot erase folds with current 'foldmethod'"
+msgstr ""
+"E352: Íåâîçìîæíî ñòåðåòü ñêëàäêè ñ òåêóùèì çíà÷åíèåì îïöèè 'foldmethod'"
+
+msgid "E664: changelist is empty"
+msgstr "E664: Ñïèñîê èçìåíåíèé ïóñòîé"
+
+msgid "E662: At start of changelist"
+msgstr "E662:  íà÷àëå ñïèñêà èçìåíåíèé"
+
+msgid "E663: At end of changelist"
+msgstr "E663: Â êîíöå ñïèñêà èçìåíåíèé"
+
+msgid "Type :qa! and press <Enter> to abandon all changes and exit Vim"
+msgstr ""
+"Ââåäèòå :qa! è íàæìèòå <Enter> äëÿ îòìåíû âñåõ èçìåíåíèé è âûõîäà èç Vim"
+
+#, c-format
+msgid "1 line %sed 1 time"
+msgstr "Èçìåíåíû îòñòóïû â 1 ñòðîêå (%s 1 ðàç)"
+
+#, c-format
+msgid "1 line %sed %d times"
+msgstr "Èçìåíåíû îòñòóïû â 1 ñòðîêå (%s %d ðàç)"
+
+#, c-format
+msgid "%ld lines %sed 1 time"
+msgstr "Èçìåíåíû îòñòóïû, %ld ñòðîê (%s 1 ðàç)"
+
+#, c-format
+msgid "%ld lines %sed %d times"
+msgstr "Èçìåíåíû îòñòóïû, %ld ñòðîê (%s %d ðàç)"
+
+#, c-format
+msgid "%ld lines to indent... "
+msgstr "Èçìåíÿþòñÿ îòñòóïû ñòðîêàõ (%ld)..."
+
+msgid "1 line indented "
+msgstr "Èçìåí¸í îòñòóï â îäíîé ñòðîêå "
+
+#, c-format
+msgid "%ld lines indented "
+msgstr "Èçìåíåíû îòñòóïû â ñòðîêàõ (%ld) "
+
+msgid "E748: No previously used register"
+msgstr "E748: Íåò ïðåäûäóùåãî èñïîëüçîâàííîãî ðåãèñòðà"
+
+msgid "cannot yank; delete anyway"
+msgstr "ñêîïèðîâàòü íå óäàëîñü, óäàëåíèå âûïîëíåíî"
+
+msgid "1 line changed"
+msgstr "èçìåíåíà 1 ñòðîêà"
+
+#, c-format
+msgid "%ld lines changed"
+msgstr "èçìåíåíî ñòðîê: %ld"
+
+#, c-format
+msgid "freeing %ld lines"
+msgstr "î÷èùåíî ñòðîê: %ld"
+
+#, c-format
+msgid " into \"%c"
+msgstr " â \"%c"
+
+#, c-format
+msgid "block of 1 line yanked%s"
+msgstr "ñêîïèðîâàí áëîê èç îäíîé ñòðîêè%s"
+
+#, c-format
+msgid "1 line yanked%s"
+msgstr "ñêîïèðîâàíà îäíà ñòðîêà%s"
+
+#, c-format
+msgid "block of %ld lines yanked%s"
+msgstr "ñêîïèðîâàí áëîê èç %ld ñòðîê%s"
+
+#, c-format
+msgid "%ld lines yanked%s"
+msgstr "ñêîïèðîâàíî %ld ñòðîê%s"
+
+#, c-format
+msgid "E353: Nothing in register %s"
+msgstr "E353:  ðåãèñòðå %s íè÷åãî íåò"
+
+msgid ""
+"\n"
+"--- Registers ---"
+msgstr ""
+"\n"
+"--- Ðåãèñòðû ---"
+
+msgid "Illegal register name"
+msgstr "Íåäîïóñòèìîå èìÿ ðåãèñòðà"
+
+msgid ""
+"\n"
+"# Registers:\n"
+msgstr ""
+"\n"
+"# Ðåãèñòðû:\n"
+
+#, c-format
+msgid "E574: Unknown register type %d"
+msgstr "E574: Íåèçâåñòíûé òèï ðåãèñòðà %d"
+
+msgid ""
+"E883: search pattern and expression register may not contain two or more "
+"lines"
+msgstr ""
+"E883: øàáëîí ïîèñêà è ðåãèñòð âûðàæåíèÿ íå ìîãóò ñîäåðæàòü äâóõ èëè áîëåå "
+"ñòðîê"
+
+#, c-format
+msgid "%ld Cols; "
+msgstr "Êîëîíîê: %ld; "
+
+#, c-format
+msgid "Selected %s%ld of %ld Lines; %lld of %lld Words; %lld of %lld Bytes"
+msgstr "Âûäåëåíî %s%ld èç %ld ñòðîê; %lld èç %lld ñëîâ; %lld èç %lld áàéò"
+
+#, c-format
+msgid ""
+"Selected %s%ld of %ld Lines; %lld of %lld Words; %lld of %lld Chars; %lld of "
+"%lld Bytes"
+msgstr ""
+"Âûäåëåíî %s%ld èç %ld ñòð.; %lld èç %lld ñëîâ; %lld èç %lld ñèìâ.; %lld èç "
+"%lld áàéò"
+
+#, c-format
+msgid "Col %s of %s; Line %ld of %ld; Word %lld of %lld; Byte %lld of %lld"
+msgstr "Êîë. %s èç %s; ñòð. %ld èç %ld; ñë. %lld èç %lld; áàéò %lld èç %lld"
+
+#, c-format
+msgid ""
+"Col %s of %s; Line %ld of %ld; Word %lld of %lld; Char %lld of %lld; Byte "
+"%lld of %lld"
+msgstr ""
+"Êîë. %s èç %s; ñòð. %ld èç %ld; ñë. %lld èç %lld; ñèìâ. %lld èç %lld; áàéò "
+"%lld èç %lld"
+
+#, c-format
+msgid "(+%lld for BOM)"
+msgstr "(+%lld ñ ó÷¸òîì BOM)"
+
+msgid "Thanks for flying Vim"
+msgstr "Áëàãîäàðèì çà èñïîëüçîâàíèå Vim"
+
+msgid "E518: Unknown option"
+msgstr "E518: Íåèçâåñòíàÿ îïöèÿ"
+
+msgid "E519: Option not supported"
+msgstr "E519: Îïöèÿ íå ïîääåðæèâàåòñÿ"
+
+msgid "E520: Not allowed in a modeline"
+msgstr "E520: Íå äîïóñêàåòñÿ â ðåæèìíîé ñòðîêå"
+
+msgid "E846: Key code not set"
+msgstr "E846: Êîä êëàâèøè íå óñòàíîâëåí"
+
+msgid "E521: Number required after ="
+msgstr "E521: Ïîñëå = òðåáóåòñÿ óêàçàòü ÷èñëî"
+
+msgid "E522: Not found in termcap"
+msgstr "E522: Íå îáíàðóæåíî â termcap"
+
+#, c-format
+msgid "E539: Illegal character <%s>"
+msgstr "E539: Íåäîïóñòèìûé ñèìâîë <%s>"
+
+#, c-format
+msgid "For option %s"
+msgstr "Äëÿ îïöèè %s"
+
+msgid "E529: Cannot set 'term' to empty string"
+msgstr "E529: Çíà÷åíèå îïöèè 'term' íå ìîæåò áûòü ïóñòîé ñòðîêîé"
+
+msgid "E530: Cannot change term in GUI"
+msgstr "E530:  ãðàôè÷åñêîì èíòåðôåéñå èçìåíÿòü òåðìèíàë íåâîçìîæíî"
+
+msgid "E531: Use \":gui\" to start the GUI"
+msgstr "E531: Äëÿ çàïóñêà ãðàôè÷åñêîãî èíòåðôåéñà èñïîëüçóéòå \":gui\""
+
+msgid "E589: 'backupext' and 'patchmode' are equal"
+msgstr "E589: Çíà÷åíèÿ îïöèé 'backupext' è 'patchmode' ðàâíû"
+
+msgid "E834: Conflicts with value of 'listchars'"
+msgstr "E834: Êîíôëèêòóåò ñî çíà÷åíèåì 'listchars'"
+
+msgid "E835: Conflicts with value of 'fillchars'"
+msgstr "E835: Êîíôëèêòóåò ñî çíà÷åíèåì 'fillchars'"
+
+msgid "E617: Cannot be changed in the GTK+ 2 GUI"
+msgstr "E617: Íå ìîæåò áûòü èçìåíåíî â ãðàôè÷åñêîì èíòåðôåéñå GTK+ 2"
+
+#, c-format
+msgid "E950: Cannot convert between %s and %s"
+msgstr "E950: Íåâîçìîæíî ïðåîáðàçîâàòü %s è %s"
+
+msgid "E524: Missing colon"
+msgstr "E524: Ïðîïóùåíî äâîåòî÷èå"
+
+msgid "E525: Zero length string"
+msgstr "E525: Ñòðîêà ñ íóëåâîé äëèíîé"
+
+#, c-format
+msgid "E526: Missing number after <%s>"
+msgstr "E526: Ïðîïóùåíî ÷èñëî ïîñëå <%s>"
+
+msgid "E527: Missing comma"
+msgstr "E527: Ïðîïóùåíà çàïÿòàÿ"
+
+msgid "E528: Must specify a ' value"
+msgstr "E528: Íåîáõîäèìî óêàçàòü çíà÷åíèå äëÿ '"
+
+msgid "E595: contains unprintable or wide character"
+msgstr "E595: Ñîäåðæèò íåïå÷àòíûé ñèìâîë èëè ñèìâîë äâîéíîé øèðèíû"
+
+msgid "E596: Invalid font(s)"
+msgstr "E596: Íåïðàâèëüíûå øðèôòû"
+
+msgid "E597: can't select fontset"
+msgstr "E597: Íåâîçìîæíî âûáðàòü øðèôòîâîé íàáîð"
+
+msgid "E598: Invalid fontset"
+msgstr "E598: Íåïðàâèëüíûé øðèôòîâîé íàáîð"
+
+msgid "E533: can't select wide font"
+msgstr "E533: Íåâîçìîæíî âûáðàòü øðèôò ñ ñèìâîëàìè äâîéíîé øèðèíû"
+
+msgid "E534: Invalid wide font"
+msgstr "E534: Íåïðàâèëüíûé øðèôò ñ ñèìâîëàìè äâîéíîé øèðèíû"
+
+#, c-format
+msgid "E535: Illegal character after <%c>"
+msgstr "E535: Íåïðàâèëüíûé ñèìâîë ïîñëå <%c>"
+
+msgid "E536: comma required"
+msgstr "E536: Òðåáóåòñÿ çàïÿòàÿ"
+
+#, c-format
+msgid "E537: 'commentstring' must be empty or contain %s"
+msgstr ""
+"E537: Çíà÷åíèå îïöèÿ 'commentstring' äîëæíî áûòü ïóñòîé ñòðîêîé èëè "
+"ñîäåðæàòü %s"
+
+msgid "E538: No mouse support"
+msgstr "E538: Ìûøü íå ïîääåðæèâàåòñÿ"
+
+msgid "E540: Unclosed expression sequence"
+msgstr "E540: Íåçàêðûòàÿ ïîñëåäîâàòåëüíîñòü âûðàæåíèÿ"
+
+msgid "E541: too many items"
+msgstr "E541: Ñëèøêîì ìíîãî ýëåìåíòîâ"
+
+msgid "E542: unbalanced groups"
+msgstr "E542: Íåñáàëàíñèðîâàííûå ãðóïïû"
+
+msgid "E946: Cannot make a terminal with running job modifiable"
+msgstr "E946: Íåâîçìîæíî ñäåëàòü òåðìèíàë èçìåí¸ííûì ñ çàïóùåííûì çàäàíèåì"
+
+msgid "E590: A preview window already exists"
+msgstr "E590: Îêíî ïðåäïðîñìîòðà óæå åñòü"
+
+msgid "W17: Arabic requires UTF-8, do ':set encoding=utf-8'"
+msgstr ""
+"W17: Àðàáñêèé òðåáóåò èñïîëüçîâàíèÿ UTF-8, ââåäèòå ':set encoding=utf-8'"
+
+msgid "E954: 24-bit colors are not supported on this environment"
+msgstr "E954: 24 áèòíûé öâåò íå ïîääåðæèâàåòñÿ â ýòîì îêðóæåíèè"
+
+#, c-format
+msgid "E593: Need at least %d lines"
+msgstr "E593: Íóæíî õîòÿ áû %d ñòðîê"
+
+#, c-format
+msgid "E594: Need at least %d columns"
+msgstr "E594: Íóæíî õîòÿ áû %d êîëîíîê"
+
+#, c-format
+msgid "E355: Unknown option: %s"
+msgstr "E355: Íåèçâåñòíàÿ îïöèÿ: %s"
+
+#, c-format
+msgid "E521: Number required: &%s = '%s'"
+msgstr "E521: Òðåáóåòñÿ óêàçàòü ÷èñëî: &%s = '%s'"
+
+msgid ""
+"\n"
+"--- Terminal codes ---"
+msgstr ""
+"\n"
+"--- Òåðìèíàëüíûå êîäû ---"
+
+msgid ""
+"\n"
+"--- Global option values ---"
+msgstr ""
+"\n"
+"--- Ãëîáàëüíûå çíà÷åíèÿ îïöèé ---"
+
+msgid ""
+"\n"
+"--- Local option values ---"
+msgstr ""
+"\n"
+"--- Ëîêàëüíûå çíà÷åíèÿ îïöèé ---"
+
+msgid ""
+"\n"
+"--- Options ---"
+msgstr ""
+"\n"
+"--- Îïöèè ---"
+
+msgid "E356: get_varp ERROR"
+msgstr "E356: ÎØÈÁÊÀ get_varp"
+
+#, c-format
+msgid "E357: 'langmap': Matching character missing for %s"
+msgstr "E357: 'langmap': Íåò ñîîòâåòñòâóþùåãî ñèìâîëà äëÿ %s"
+
+#, c-format
+msgid "E358: 'langmap': Extra characters after semicolon: %s"
+msgstr "E358: 'langmap': Ëèøíèå ñèìâîëû ïîñëå òî÷êè ñ çàïÿòîé: %s"
+
+msgid "cannot open "
+msgstr "íåâîçìîæíî îòêðûòü "
+
+msgid "VIM: Can't open window!\n"
+msgstr "VIM: Íåâîçìîæíî îòêðûòü îêíî!\n"
+
+msgid "Need Amigados version 2.04 or later\n"
+msgstr "Íåîáõîäèìà Amigados âåðñèè 2.04 èëè áîëåå ïîçäíåé\n"
+
+#, c-format
+msgid "Need %s version %ld\n"
+msgstr "Íåîáõîäèìà %s âåðñèè %ld\n"
+
+msgid "Cannot open NIL:\n"
+msgstr "Íåâîçìîæíî îòêðûòü NIL:\n"
+
+msgid "Cannot create "
+msgstr "Íåâîçìîæíî ñîçäàòü "
+
+#, c-format
+msgid "Vim exiting with %d\n"
+msgstr "Ïðåêðàùåíèå ðàáîòû Vim ñ êîäîì %d\n"
+
+msgid "cannot change console mode ?!\n"
+msgstr "íåâîçìîæíî ñìåíèòü ðåæèì êîíñîëè?!\n"
+
+msgid "mch_get_shellsize: not a console??\n"
+msgstr "mch_get_shellsize: íå â êîíñîëè??\n"
+
+msgid "E360: Cannot execute shell with -f option"
+msgstr "E360: Íåâîçìîæíî âûïîëíèòü îáîëî÷êó ñ ïàðàìåòðîì -f"
+
+msgid "Cannot execute "
+msgstr "Íåâîçìîæíî âûïîëíèòü "
+
+msgid "shell "
+msgstr "îáîëî÷êà "
+
+msgid " returned\n"
+msgstr " çàâåðøèëà ðàáîòó\n"
+
+msgid "ANCHOR_BUF_SIZE too small."
+msgstr "ñëèøêîì ìàëàÿ âåëè÷èíà ANCHOR_BUF_SIZE."
+
+msgid "I/O ERROR"
+msgstr "ÎØÈÁÊÀ ÂÂÎÄÀ/ÂÛÂÎÄÀ"
+
+msgid "Message"
+msgstr "Ñîîáùåíèå"
+
+msgid "E237: Printer selection failed"
+msgstr "E237: Íåóäà÷íîå çàâåðøåíèå âûáîðà ïðèíòåðà"
+
+#, c-format
+msgid "to %s on %s"
+msgstr "â %s íà %s"
+
+#, c-format
+msgid "E613: Unknown printer font: %s"
+msgstr "E613: Íåèçâåñòíûé øðèôò ïðèíòåðà: %s"
+
+#, c-format
+msgid "E238: Print error: %s"
+msgstr "E238: Îøèáêà ïå÷àòè: %s"
+
+#, c-format
+msgid "Printing '%s'"
+msgstr "Ïå÷àòü '%s'"
+
+#, c-format
+msgid "E244: Illegal charset name \"%s\" in font name \"%s\""
+msgstr "E244: Íåäîïóñòèìîå èìÿ êîäèðîâêè \"%s\" â èìåíè øðèôòà \"%s\""
+
+#, c-format
+msgid "E244: Illegal quality name \"%s\" in font name \"%s\""
+msgstr "E244: Íåäîïóñòèìîå èìÿ ñâîéñòâà \"%s\" â èìåíè øðèôòà \"%s\""
+
+#, c-format
+msgid "E245: Illegal char '%c' in font name \"%s\""
+msgstr "E245: Íåäîïóñòèìûé ñèìâîë '%c' â èìåíè øðèôòà \"%s\""
+
+#, c-format
+msgid "Opening the X display took %ld msec"
+msgstr "Îòêðûòèå äèñïëåÿ X çàíÿëî %ld msec"
+
+msgid ""
+"\n"
+"Vim: Got X error\n"
+msgstr ""
+"\n"
+"Vim: Îøèáêà X\n"
+
+msgid "Testing the X display failed"
+msgstr "Ïðîâåðêà äèñïëåÿ X çàâåðøåíà íåóäà÷íî"
+
+msgid "Opening the X display timed out"
+msgstr "Îòêðûòèå äèñïëåÿ X íå âûïîëíåíî â îòâåä¸ííîå âðåìÿ"
+
+msgid ""
+"\n"
+"Could not get security context for "
+msgstr ""
+"\n"
+"Íåâîçìîæíî ïîëó÷èòü êîíòåêñò áåçîïàñíîñòè äëÿ "
+
+msgid ""
+"\n"
+"Could not set security context for "
+msgstr ""
+"\n"
+"Íåâîçìîæíî óñòàíîâèòü êîíòåêñò áåçîïàñíîñòè äëÿ "
+
+#, c-format
+msgid "Could not set security context %s for %s"
+msgstr "Íåâîçìîæíî óñòàíîâèòü êîíòåêñò áåçîïàñíîñòè %s äëÿ äëÿ %s"
+
+#, c-format
+msgid "Could not get security context %s for %s. Removing it!"
+msgstr "Íåâîçìîæíî ïîëó÷èòü êîíòåêñò áåçîïàñíîñòè %s äëÿ %s. Áóäåò óäàëåíî!"
+
+msgid ""
+"\n"
+"Cannot execute shell sh\n"
+msgstr ""
+"\n"
+"Íåâîçìîæíî çàïóñòèòü îáîëî÷êó sh\n"
+
+msgid ""
+"\n"
+"shell returned "
+msgstr ""
+"\n"
+"Îáîëî÷êà çàâåðøèëà ðàáîòó "
+
+msgid ""
+"\n"
+"Cannot create pipes\n"
+msgstr ""
+"\n"
+"Íåâîçìîæíî ñîçäàòü òðóáû\n"
+
+msgid ""
+"\n"
+"Cannot fork\n"
+msgstr ""
+"\n"
+"Íåâîçìîæíî âûïîëíèòü fork()\n"
+
+msgid ""
+"\n"
+"Cannot execute shell "
+msgstr ""
+"\n"
+"Íåâîçìîæíî çàïóñòèòü îáîëî÷êó "
+
+msgid ""
+"\n"
+"Command terminated\n"
+msgstr ""
+"\n"
+"Âûïîëíåíèå êîìàíäû ïðåðâàíî\n"
+
+msgid "XSMP lost ICE connection"
+msgstr "XSMP óòåðÿíî ñîåäèíåíèå ICE"
+
+#, c-format
+msgid "dlerror = \"%s\""
+msgstr "dlerror = \"%s\""
+
+msgid "Opening the X display failed"
+msgstr "Íåóäà÷íîå îòêðûòèå äèñïëåÿ X"
+
+msgid "XSMP handling save-yourself request"
+msgstr "XSMP îáðàáàòûâàåò çàïðîñ ñàìîñîõðàíåíèÿ"
+
+msgid "XSMP opening connection"
+msgstr "XSMP îòêðûâàåò ñîåäèíåíèå"
+
+msgid "XSMP ICE connection watch failed"
+msgstr "XSMP ïîòåðÿíî ñëåæåíèå çà ñîåäèíåíèåì ICE"
+
+#, c-format
+msgid "XSMP SmcOpenConnection failed: %s"
+msgstr "XSMP íåóäà÷íî âûïîëíåíî SmcOpenConnection: %s"
+
+msgid "At line"
+msgstr "Â ñòðîêå"
+
+msgid "Could not load vim32.dll!"
+msgstr "Íåâîçìîæíî çàãðóçèòü vim32.dll!"
+
+msgid "VIM Error"
+msgstr "Îøèáêà VIM"
+
+msgid "Could not fix up function pointers to the DLL!"
+msgstr "Íåâîçìîæíî èñïðàâèòü óêàçàòåëè ôóíêöèé äëÿ DLL!"
+
+#, c-format
+msgid "Vim: Caught %s event\n"
+msgstr "Vim: Ïåðåõâà÷åíî ñîáûòèå %s\n"
+
+msgid "close"
+msgstr "çàêðûòèå"
+
+msgid "logoff"
+msgstr "îòêëþ÷åíèå"
+
+msgid "shutdown"
+msgstr "çàâåðøåíèå"
+
+msgid "E371: Command not found"
+msgstr "E371: Êîìàíäà íå íàéäåíà"
+
+msgid ""
+"VIMRUN.EXE not found in your $PATH.\n"
+"External commands will not pause after completion.\n"
+"See :help win32-vimrun for more information."
+msgstr ""
+"VIMRUN.EXE íå íàéäåí â ïóòè, çàäàííîì â $PATH.\n"
+"Âíåøíèå êîìàíäû íå áóäóò îñòàíàâëèâàòüñÿ ïîñëå âûïîëíåíèÿ.\n"
+"Äîïîëíèòåëüíàÿ èíôîðìàöèÿ â :help win32-vimrun"
+
+msgid "Vim Warning"
+msgstr "Ïðåäóïðåæäåíèå Vim"
+
+#, c-format
+msgid "shell returned %d"
+msgstr "çàâåðøåíèå ðàáîòû îáîëî÷êè ñ êîäîì %d"
+
+msgid "E926: Current location list was changed"
+msgstr "E926: Èçìåí¸í ñïèñîê òåêóùèõ ðàñïîëîæåíèé"
+
+#, c-format
+msgid "E372: Too many %%%c in format string"
+msgstr "E372: Â ñòðîêå ôîðìàòà ñëèøêîì ìíîãî %%%c"
+
+#, c-format
+msgid "E373: Unexpected %%%c in format string"
+msgstr "E373: Íåîæèäàííûé ýëåìåíò %%%c â ñòðîêå ôîðìàòà"
+
+msgid "E374: Missing ] in format string"
+msgstr "E374: Â ñòðîêå ôîðìàòà ïðîïóùåíà ]"
+
+#, c-format
+msgid "E375: Unsupported %%%c in format string"
+msgstr "E375: %%%c íå ïîääåðæèâàåòñÿ â ñòðîêå ôîðìàòà"
+
+#, c-format
+msgid "E376: Invalid %%%c in format string prefix"
+msgstr "E376: Íåäîïóñòèìûé %%%c â ïðèñòàâêå â ñòðîêå ôîðìàòà"
+
+#, c-format
+msgid "E377: Invalid %%%c in format string"
+msgstr "E377: Íåäîïóñòèìûé %%%c â ñòðîêå ôîðìàòà"
+
+msgid "E378: 'errorformat' contains no pattern"
+msgstr "E378:  çíà÷åíèè îïöèè 'errorformat' îòñóòñòâóåò øàáëîí"
+
+msgid "E379: Missing or empty directory name"
+msgstr "E379: Èìÿ êàòàëîãà íå çàäàíî èëè ðàâíî ïóñòîé ñòðîêå"
+
+msgid "E553: No more items"
+msgstr "E553: Áîëüøå íåò ýëåìåíòîâ"
+
+msgid "E924: Current window was closed"
+msgstr "E924: Òåêóùåå îêíî áûëî çàêðûòî"
+
+msgid "E925: Current quickfix was changed"
+msgstr "E925: Èçìåí¸í ñïèñîê òåêóùèõ áûñòðûõ èñïðàâëåíèé"
+
+#, c-format
+msgid "(%d of %d)%s%s: "
+msgstr "(%d èç %d)%s%s: "
+
+msgid " (line deleted)"
+msgstr " (ñòðîêà óäàëåíà)"
+
+#, c-format
+msgid "%serror list %d of %d; %d errors "
+msgstr "%sñïèñîê îøèáîê %d èç %d; %d îøèáîê"
+
+msgid "E380: At bottom of quickfix stack"
+msgstr "E380: Âíèçó ñòåêà áûñòðûõ èñïðàâëåíèé"
+
+msgid "E381: At top of quickfix stack"
+msgstr "E381: Íàâåðõó ñòåêà áûñòðûõ èñïðàâëåíèé"
+
+msgid "No entries"
+msgstr "Íåò ýëåìåíòîâ"
+
+msgid "Error file"
+msgstr "Ôàéë îøèáîê"
+
+msgid "E683: File name missing or invalid pattern"
+msgstr "E683: Íåò èìåíè ôàéëà èëè íåïðàâèëüíûé øàáëîí"
+
+#, c-format
+msgid "Cannot open file \"%s\""
+msgstr "Íåâîçìîæíî îòêðûòü ôàéë \"%s\""
+
+msgid "E681: Buffer is not loaded"
+msgstr "E681: Áóôåð íå âûãðóæåí"
+
+msgid "E777: String or List expected"
+msgstr "E777: Òðåáóåòñÿ ñòðîêà èëè ñïèñîê"
+
+#, c-format
+msgid "E369: invalid item in %s%%[]"
+msgstr "E369: Íåäîïóñòèìûé ýëåìåíò â %s%%[]"
+
+#, c-format
+msgid "E769: Missing ] after %s["
+msgstr "E769: Ïðîïóùåíà ] ïîñëå %s["
+
+msgid "E944: Reverse range in character class"
+msgstr "E944: Îáðàòíûé äèàïàçîí â ñèìâîëüíîì êëàññå"
+
+msgid "E945: Range too large in character class"
+msgstr "E945: Äèàïàçîí ñëèøêîì âåëèê â ñèìâîëüíîì êëàññå"
+
+#, c-format
+msgid "E53: Unmatched %s%%("
+msgstr "E53: Íåò ïàðû äëÿ %s%%("
+
+#, c-format
+msgid "E54: Unmatched %s("
+msgstr "E54: Íåò ïàðû äëÿ %s("
+
+#, c-format
+msgid "E55: Unmatched %s)"
+msgstr "E55: Íåò ïàðû äëÿ %s)"
+
+msgid "E66: \\z( not allowed here"
+msgstr "E66: \\z( íå ìîæåò áûòü èñïîëüçîâàíî çäåñü"
+
+msgid "E67: \\z1 - \\z9 not allowed here"
+msgstr "E67: \\z1 è ò.ï. íå ìîãóò áûòü èñïîëüçîâàíû çäåñü"
+
+#, c-format
+msgid "E69: Missing ] after %s%%["
+msgstr "E69: Ïðîïóùåíà ] ïîñëå %s%%["
+
+#, c-format
+msgid "E70: Empty %s%%[]"
+msgstr "E70: Ïóñòîå %s%%[]"
+
+msgid "E65: Illegal back reference"
+msgstr "E65: Íåäîïóñòèìàÿ îáðàòíàÿ ññûëêà"
+
+msgid "E339: Pattern too long"
+msgstr "E339: Ñëèøêîì äëèííûé øàáëîí"
+
+msgid "E50: Too many \\z("
+msgstr "E50: Ñëèøêîì ìíîãî \\z("
+
+#, c-format
+msgid "E51: Too many %s("
+msgstr "E51: Ñëèøêîì ìíîãî %s("
+
+msgid "E52: Unmatched \\z("
+msgstr "E52: Íåò ïàðû äëÿ \\z("
+
+#, c-format
+msgid "E59: invalid character after %s@"
+msgstr "E59: Íåäîïóñòèìûé ñèìâîë ïîñëå %s@"
+
+#, c-format
+msgid "E60: Too many complex %s{...}s"
+msgstr "E60: Ñëèøêîì ìíîãî ñëîæíûõ êîíñòðóêöèé %s{...}"
+
+#, c-format
+msgid "E61: Nested %s*"
+msgstr "E61: Âëîæåííûå %s*"
+
+#, c-format
+msgid "E62: Nested %s%c"
+msgstr "E62: Âëîæåííûå %s%c"
+
+msgid "E63: invalid use of \\_"
+msgstr "E63: Íåäîïóñòèìîå èñïîëüçîâàíèå \\_"
+
+#, c-format
+msgid "E64: %s%c follows nothing"
+msgstr "E64: %s%c íè çà ÷åì íå ñëåäóåò"
+
+msgid "E68: Invalid character after \\z"
+msgstr "E68: Íåäîïóñòèìûé ñèìâîë ïîñëå \\z"
+
+#, c-format
+msgid "E678: Invalid character after %s%%[dxouU]"
+msgstr "E678: Íåäîïóñòèìûé ñèìâîë ïîñëå %s%%[dxouU]"
+
+#, c-format
+msgid "E71: Invalid character after %s%%"
+msgstr "E71: Íåäîïóñòèìûé ñèìâîë ïîñëå %s%%"
+
+#, c-format
+msgid "E554: Syntax error in %s{...}"
+msgstr "E554: Ñèíòàêñè÷åñêàÿ îøèáêà â %s{...}"
+
+msgid "External submatches:\n"
+msgstr "Âíåøíèå ïîäñîîòâåòñòâèÿ:\n"
+
+#, c-format
+msgid "E888: (NFA regexp) cannot repeat %s"
+msgstr "E888: (ðåã. âûðàæåíèå ÍÊÀ) íåâîçìîæíî ïîâòîðèòü %s"
+
+msgid ""
+"E864: \\%#= can only be followed by 0, 1, or 2. The automatic engine will be "
+"used "
+msgstr ""
+"E864: ïîñëå \\%#= ìîæåò áûòü òîëüêî 0, 1 èëè 2. Áóäåò èñïîëüçîâàòüñÿ "
+"àâòîìàòè÷åñêàÿ ìàøèíà"
+
+msgid "Switching to backtracking RE engine for pattern: "
+msgstr "Âêëþ÷åíî îòñëåæèâàíèå äâèæêà ðåã. âûðàæåíèé äëÿ øàáëîíà: "
+
+msgid "E865: (NFA) Regexp end encountered prematurely"
+msgstr "E865: (ÍÊÀ) íåîæèäàííûé êîíåö ðåãóëÿðíîãî âûðàæåíèÿ"
+
+#, c-format
+msgid "E866: (NFA regexp) Misplaced %c"
+msgstr "E866: (ðåã. âûðàæåíèå ÍÊÀ) íåîæèäàííûé %c"
+
+#, c-format
+msgid "E877: (NFA regexp) Invalid character class: %ld"
+msgstr "E877: (ðåã. âûðàæåíèå ÍÊÀ) íåïðàâèëüíûé êëàññ ñèìâîëîâ: %ld"
+
+#, c-format
+msgid "E867: (NFA) Unknown operator '\\z%c'"
+msgstr "E867: (ÍÊÀ) íåèçâåñòíûé îïåðàòîð '\\z%c'"
+
+msgid "E951: \\% value too large"
+msgstr "E951: \\% çíà÷åíèå ñëèøêîì áîëüøîå"
+
+#, c-format
+msgid "E867: (NFA) Unknown operator '\\%%%c'"
+msgstr "E867: (ÍÊÀ) íåèçâåñòíûé îïåðàòîð '\\%%%c'"
+
+msgid "E868: Error building NFA with equivalence class!"
+msgstr "E868: îøèáêà ïðè ñîçäàíèè ÍÊÀ ñ êëàññîì ýêâèâàëåíòíîñòè!"
+
+#, c-format
+msgid "E869: (NFA) Unknown operator '\\@%c'"
+msgstr "E869: (ÍÊÀ) íåèçâåñòíûé îïåðàòîð '\\@%c'"
+
+msgid "E870: (NFA regexp) Error reading repetition limits"
+msgstr "E870: (ðåã. âûðàæåíèå ÍÊÀ) îøèáêà ïðè ÷òåíèè ãðàíèö ïîâòîðåíèÿ"
+
+msgid "E871: (NFA regexp) Can't have a multi follow a multi"
+msgstr "E871: (ðåã. âûðàæåíèå ÍÊÀ) ìíîæåñòâî íå ìîæåò ñëåäîâàòü çà ìíîæåñòâîì"
+
+msgid "E872: (NFA regexp) Too many '('"
+msgstr "E872: (ðåã. âûðàæåíèå ÍÊÀ) ñëèøêîì ìíîãî '('"
+
+msgid "E879: (NFA regexp) Too many \\z("
+msgstr "E879: (ðåã. âûðàæåíèå ÍÊÀ) ñëèøêîì ìíîãî \\z("
+
+msgid "E873: (NFA regexp) proper termination error"
+msgstr "E873: (ðåã. âûðàæåíèå ÍÊÀ) îøèáêà êîððåêòíîãî çàâåðøåíèÿ"
+
+msgid "E874: (NFA) Could not pop the stack!"
+msgstr "E874: (ðåã. âûðàæåíèå ÍÊÀ) íåâîçìîæíî âçÿòü èç ñòåêà!"
+
+msgid ""
+"E875: (NFA regexp) (While converting from postfix to NFA), too many states "
+"left on stack"
+msgstr ""
+"E875: (ðåã. âûðàæåíèå ÍÊÀ) â ñòåêå îñòàëîñü ñëèøêîì ìíîãî ñîñòîÿíèé (ïðè "
+"ïðåîáðàçîâàíèè èç postfix â ÍÊÀ)"
+
+msgid "E876: (NFA regexp) Not enough space to store the whole NFA "
+msgstr "E876: (ðåã. âûðàæåíèå ÍÊÀ) íåäîñòàòî÷íî ìåñòà äëÿ õðàíåíèÿ âñåãî ÍÊÀ"
+
+msgid "E878: (NFA) Could not allocate memory for branch traversal!"
+msgstr "E878: (ÍÊÀ) íåâîçìîæíî âûäåëèòü ïàìÿòü äëÿ ïðîõîäà âåòâè!"
+
+msgid ""
+"Could not open temporary log file for writing, displaying on stderr... "
+msgstr ""
+"Íåâîçìîæíî îòêðûòü ôàéë âðåìåííîãî æóðíàëà äëÿ çàïèñè, âûâîä íà stderr..."
+
+#, c-format
+msgid "(NFA) COULD NOT OPEN %s !"
+msgstr "(ÍÊÀ) íåâîçìîæíî îòêðûòü %s!"
+
+msgid "Could not open temporary log file for writing "
+msgstr "Íåâîçìîæíî îòêðûòü ôàéë âðåìåííîãî æóðíàëà äëÿ çàïèñè"
+
+msgid " VREPLACE"
+msgstr " ÂÈÐÒÓÀËÜÍÀß ÇÀÌÅÍÀ"
+
+msgid " REPLACE"
+msgstr " ÇÀÌÅÍÀ"
+
+msgid " REVERSE"
+msgstr " ÎÁÐÀÒÍÀß"
+
+msgid " INSERT"
+msgstr " ÂÑÒÀÂÊÀ"
+
+msgid " (insert)"
+msgstr " (âñòàâêà)"
+
+msgid " (replace)"
+msgstr " (çàìåíà)"
+
+msgid " (vreplace)"
+msgstr " (âèðòóàëüíàÿ çàìåíà)"
+
+msgid " Hebrew"
+msgstr " Èâðèò"
+
+msgid " Arabic"
+msgstr " Àðàáñêèé"
+
+msgid " (paste)"
+msgstr " (âêëåéêà)"
+
+msgid " VISUAL"
+msgstr " ÂÈÇÓÀËÜÍÛÉ ÐÅÆÈÌ"
+
+msgid " VISUAL LINE"
+msgstr " ÂÈÇÓÀËÜÍÀß ÑÒÐÎÊÀ"
+
+msgid " VISUAL BLOCK"
+msgstr " ÂÈÇÓÀËÜÍÛÉ ÁËÎÊ"
+
+msgid " SELECT"
+msgstr " ÂÛÄÅËÅÍÈÅ"
+
+msgid " SELECT LINE"
+msgstr " ÂÛÄÅËÅÍÈÅ ÑÒÐÎÊÈ"
+
+msgid " SELECT BLOCK"
+msgstr " ÂÛÄÅËÅÍÈÅ ÁËÎÊÀ"
+
+msgid "recording"
+msgstr "çàïèñü"
+
+#, c-format
+msgid "E383: Invalid search string: %s"
+msgstr "E383: Íåïðàâèëüíàÿ ñòðîêà ïîèñêà: %s"
+
+#, c-format
+msgid "E384: search hit TOP without match for: %s"
+msgstr "E384: Ïîèñê çàêîí÷åí â ÍÀ×ÀËÅ äîêóìåíòà; %s íå íàéäåíî"
+
+#, c-format
+msgid "E385: search hit BOTTOM without match for: %s"
+msgstr "E385: Ïîèñê çàêîí÷åí â ÊÎÍÖÅ äîêóìåíòà; %s íå íàéäåíî"
+
+msgid "E386: Expected '?' or '/' after ';'"
+msgstr "E386: Ïîñëå ';' îæèäàåòñÿ ââîä '?' èëè '/'"
+
+msgid " (includes previously listed match)"
+msgstr " (âêëþ÷àåò ðàííåå ïîêàçàííûå ñîîòâåòñòâèÿ)"
+
+msgid "--- Included files "
+msgstr "--- Âêëþ÷¸ííûå ôàéëû "
+
+msgid "not found "
+msgstr "íå íàéäåíî "
+
+msgid "in path ---\n"
+msgstr "ïî ïóòè ---\n"
+
+msgid " (Already listed)"
+msgstr " (Óæå ïîêàçàíî)"
+
+msgid " NOT FOUND"
+msgstr " ÍÅ ÍÀÉÄÅÍÎ"
+
+#, c-format
+msgid "Scanning included file: %s"
+msgstr "Ïðîñìîòð âêëþ÷¸ííûõ ôàéëîâ: %s"
+
+#, c-format
+msgid "Searching included file %s"
+msgstr "Ïîèñê âêëþ÷¸ííîãî ôàéëà %s"
+
+msgid "E387: Match is on current line"
+msgstr "E387: Ñîîòâåòñòâèå â òåêóùåé ñòðîêå"
+
+msgid "All included files were found"
+msgstr "Íàéäåíû âñå âêëþ÷¸ííûå ôàéëû"
+
+msgid "No included files"
+msgstr "Âêëþ÷¸ííûõ ôàéëîâ íåò"
+
+msgid "E388: Couldn't find definition"
+msgstr "E388: Îïðåäåëåíèå íå íàéäåíî"
+
+msgid "E389: Couldn't find pattern"
+msgstr "E389: Øàáëîí íå íàéäåí"
+
+msgid "Substitute "
+msgstr "Çàìåíà "
+
+#, c-format
+msgid ""
+"\n"
+"# Last %sSearch Pattern:\n"
+"~"
+msgstr ""
+"\n"
+"# Ïîñëåäíèé %sØàáëîí ïîèñêà:\n"
+"~"
+
+msgid "E756: Spell checking is not enabled"
+msgstr "E756: Ïðîâåðêà ïðàâîïèñàíèÿ âûêëþ÷åíà"
+
+#, c-format
+msgid "Warning: Cannot find word list \"%s_%s.spl\" or \"%s_ascii.spl\""
+msgstr ""
+"Ïðåäóïðåæäåíèå: Íåâîçìîæíî íàéòè ñïèñîê ñëîâ \"%s_%s.spl\" èëè \"%s_ascii.spl"
+"\""
+
+#, c-format
+msgid "Warning: Cannot find word list \"%s.%s.spl\" or \"%s.ascii.spl\""
+msgstr ""
+"Ïðåäóïðåæäåíèå: Íåâîçìîæíî íàéòè ñïèñîê ñëîâ \"%s.%s.spl\" èëè \"%s.ascii.spl"
+"\""
+
+msgid "E797: SpellFileMissing autocommand deleted buffer"
+msgstr "E797: Áóôåð óäàë¸í ïðè âûïîëíåíèè àâòîêîìàíäû SpellFileMissing"
+
+#, c-format
+msgid "Warning: region %s not supported"
+msgstr "Ïðåäóïðåæäåíèå: ðåãèîí %s íå ïîääåðæèâàåòñÿ"
+
+msgid "Sorry, no suggestions"
+msgstr "Èçâèíèòå, íåò ïðåäïîëîæåíèé"
+
+#, c-format
+msgid "Sorry, only %ld suggestions"
+msgstr "Èçâèíèòå, òîëüêî %ld ïðåäïîëîæåíèé"
+
+#, c-format
+msgid "Change \"%.*s\" to:"
+msgstr "Çàìåíèòü \"%.*s\" íà:"
+
+#, c-format
+msgid " < \"%.*s\""
+msgstr " < \"%.*s\""
+
+msgid "E752: No previous spell replacement"
+msgstr "E752: Íåò ïðåäûäóùåé çàìåíû ïðàâîïèñàíèÿ"
+
+#, c-format
+msgid "E753: Not found: %s"
+msgstr "E753: Íå íàéäåíî: %s"
+
+msgid "E758: Truncated spell file"
+msgstr "E758: Ôàéë ïðàâîïèñàíèÿ îáðåçàí"
+
+#, c-format
+msgid "Trailing text in %s line %d: %s"
+msgstr "Ëèøíèé òåêñò íà õâîñòå â %s ñòð. %d: %s"
+
+#, c-format
+msgid "Affix name too long in %s line %d: %s"
+msgstr "Èìÿ àôôèêñà ñëèøêîì äëèííîå â %s, ñòðîêà %d: %s"
+
+msgid "E761: Format error in affix file FOL, LOW or UPP"
+msgstr "E761: Îøèáêà ôîðìàòà â ôàéëå àôôèêñîâ FOL, LOW èëè UPP"
+
+msgid "E762: Character in FOL, LOW or UPP is out of range"
+msgstr "E762: Ñèìâîëû â FOL, LOW èëè UPP çà ïðåäåëàìè äèàïàçîíà"
+
+msgid "Compressing word tree..."
+msgstr "Ñæàòèå äåðåâà ñëîâ..."
+
+#, c-format
+msgid "Reading spell file \"%s\""
+msgstr "×òåíèå ôàéëà ïðàâîïèñàíèÿ \"%s\""
+
+msgid "E757: This does not look like a spell file"
+msgstr "E757: Ýòî íå ïîõîæå íà ôàéë ïðàâîïèñàíèÿ"
+
+msgid "E771: Old spell file, needs to be updated"
+msgstr "E771: Ñòàðûé ôàéë ïðàâîïèñàíèÿ, òðåáóåòñÿ åãî îáíîâëåíèå"
+
+msgid "E772: Spell file is for newer version of Vim"
+msgstr "E772: Ôàéë ïðàâîïèñàíèÿ ïðåäíàçíà÷åí äëÿ áîëåå íîâîé âåðñèè Vim"
+
+msgid "E770: Unsupported section in spell file"
+msgstr "E770: Íåïîääåðæèâàåìûé ðàçäåë â ôàéëå ïðàâîïèñàíèÿ"
+
+#, c-format
+msgid "E778: This does not look like a .sug file: %s"
+msgstr "E778: Ýòî íå ïîõîæå íà ôàéë .sug: %s"
+
+#, c-format
+msgid "E779: Old .sug file, needs to be updated: %s"
+msgstr "E779: Ñòàðûé ôàéë .sug, òðåáóåò îáíîâëåíèÿ: %s"
+
+#, c-format
+msgid "E780: .sug file is for newer version of Vim: %s"
+msgstr "E780: Ôàéë .sug äëÿ áîëåå íîâîé âåðñèè Vim: %s"
+
+#, c-format
+msgid "E781: .sug file doesn't match .spl file: %s"
+msgstr "E781: Ôàéë .sug íå ñîîòâåòñòâóåò ôàéëó .spl: %s"
+
+#, c-format
+msgid "E782: error while reading .sug file: %s"
+msgstr "E782: Îøèáêà ïðè ÷òåíèè ôàéëà .sug: %s"
+
+#, c-format
+msgid "Reading affix file %s..."
+msgstr "×òåíèå ôàéëà àôôèêñîâ %s..."
+
+#, c-format
+msgid "Conversion failure for word in %s line %d: %s"
+msgstr "Íå óäàëîñü ïðåîáðàçîâàòü ñëîâî â %s, ñòðîêà %d: %s"
+
+#, c-format
+msgid "Conversion in %s not supported: from %s to %s"
+msgstr "Ïðåîáðàçîâàíèå â %s íå ïîääåðæèâàåòñÿ: èç %s â %s"
+
+#, c-format
+msgid "Conversion in %s not supported"
+msgstr "Ïðåîáðàçîâàíèå â %s íå ïîääåðæèâàåòñÿ"
+
+#, c-format
+msgid "Invalid value for FLAG in %s line %d: %s"
+msgstr "Íåïðàâèëüíîå çíà÷åíèå FLAG â %s, ñòðîêà %d: %s"
+
+#, c-format
+msgid "FLAG after using flags in %s line %d: %s"
+msgstr "FLAG ïîñëå èñïîëüçîâàíèÿ ôëàãîâ â %s, ñòðîêà %d: %s"
+
+#, c-format
+msgid ""
+"Defining COMPOUNDFORBIDFLAG after PFX item may give wrong results in %s line "
+"%d"
+msgstr ""
+"Îïðåäåëåíèå COMPOUNDFORBIDFLAG ïîñëå ýëåìåíòà PFX ìîæåò äàòü íåïðàâèëüíûå "
+"ðåçóëüòàòû â %s, ñòðîêà %d"
+
+#, c-format
+msgid ""
+"Defining COMPOUNDPERMITFLAG after PFX item may give wrong results in %s line "
+"%d"
+msgstr ""
+"Îïðåäåëåíèå COMPOUNDPERMITFLAG ïîñëå ýëåìåíòà PFX ìîæåò äàòü íåïðàâèëüíûå "
+"ðåçóëüòàòû â %s, ñòðîêà %d"
+
+#, c-format
+msgid "Wrong COMPOUNDRULES value in %s line %d: %s"
+msgstr "Íåïðàâèëüíîå çíà÷åíèå COMPOUNDRULES â %s, ñòðîêà %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDWORDMAX value in %s line %d: %s"
+msgstr "Íåïðàâèëüíîå çíà÷åíèå COMPOUNDWORDMAX â %s, ñòðîêà %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDMIN value in %s line %d: %s"
+msgstr "Íåïðàâèëüíîå çíà÷åíèå COMPOUNDMIN â %s, ñòðîêà %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDSYLMAX value in %s line %d: %s"
+msgstr "Íåïðàâèëüíîå çíà÷åíèå COMPOUNDSYLMAX â %s, ñòðîêà %d: %s"
+
+#, c-format
+msgid "Wrong CHECKCOMPOUNDPATTERN value in %s line %d: %s"
+msgstr "Íåïðàâèëüíîå çíà÷åíèå CHECKCOMPOUNDPATTERN â %s, ñòðîêà %d: %s"
+
+#, c-format
+msgid "Different combining flag in continued affix block in %s line %d: %s"
+msgstr ""
+"Äðóãîé îáúåäèíÿþùèé ôëàã â ïðîäîëæàþùåì áëîêå àôôèêñà â %s, ñòðîêà %d: %s"
+
+#, c-format
+msgid "Duplicate affix in %s line %d: %s"
+msgstr "Ïîâòîðÿþùèéñÿ àôôèêñ â %s, ñòðîêà %d: %s"
+
+#, c-format
+msgid ""
+"Affix also used for BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST in %s "
+"line %d: %s"
+msgstr ""
+"Àôôèêñ òàêæå èñïîëüçóåòñÿ äëÿ BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/"
+"NOSUGGEST â %s, ñòðîêà %d: %s"
+
+#, c-format
+msgid "Expected Y or N in %s line %d: %s"
+msgstr "Îæèäàëîñü Y èëè N â %s, ñòðîêà %d: %s"
+
+#, c-format
+msgid "Broken condition in %s line %d: %s"
+msgstr "Íàðóøåííîå óñëîâèå â %s, ñòðîêà %d: %s"
+
+#, c-format
+msgid "Expected REP(SAL) count in %s line %d"
+msgstr "Îæèäàëñÿ ñ÷¸ò÷èê REP(SAL) â %s, ñòðîêà %d"
+
+#, c-format
+msgid "Expected MAP count in %s line %d"
+msgstr "Îæèäàëñÿ ñ÷¸ò÷èê MAP â %s, ñòðîêà %d"
+
+#, c-format
+msgid "Duplicate character in MAP in %s line %d"
+msgstr "Ïîâòîðÿþùèéñÿ ñèìâîë â MAP â %s, ñòðîêà %d"
+
+#, c-format
+msgid "Unrecognized or duplicate item in %s line %d: %s"
+msgstr "Íåðàñïîçíàííûé èëè ïîâòîðÿþùèéñÿ ýëåìåíò â %s, ñòðîêà %d: %s"
+
+#, c-format
+msgid "Missing FOL/LOW/UPP line in %s"
+msgstr "Ïðîïóùåíà ñòðîêà FOL/LOW/UPP â %s"
+
+msgid "COMPOUNDSYLMAX used without SYLLABLE"
+msgstr "COMPOUNDSYLMAX èñïîëüçóåòñÿ áåç SYLLABLE"
+
+msgid "Too many postponed prefixes"
+msgstr "Ñëèøêîì ìíîãî îòëîæåííûõ ïðåôèêñîâ"
+
+msgid "Too many compound flags"
+msgstr "Ñëèøêîì ìíîãî ñîñòàâíûõ ôëàãîâ"
+
+msgid "Too many postponed prefixes and/or compound flags"
+msgstr "Ñëèøêîì ìíîãî îòëîæåííûõ ïðåôèêñîâ è/èëè ñîñòàâíûõ ôëàãîâ"
+
+#, c-format
+msgid "Missing SOFO%s line in %s"
+msgstr "Ïðîïóùåíà ñòðîêà SOFO%s â %s"
+
+#, c-format
+msgid "Both SAL and SOFO lines in %s"
+msgstr "Îáå ñòðîêè SAL è SOFO â %s"
+
+#, c-format
+msgid "Flag is not a number in %s line %d: %s"
+msgstr "Ôëàã íå ÿâëÿåòñÿ ÷èñëîì â %s, ñòðîêà %d: %s"
+
+#, c-format
+msgid "Illegal flag in %s line %d: %s"
+msgstr "Íåäîïóñòèìûé ôëàã â %s íà ñòðîêå %d: %s"
+
+#, c-format
+msgid "%s value differs from what is used in another .aff file"
+msgstr "%s èìååò äðóãîå çíà÷åíèå, ÷åì â ôàéëå .aff"
+
+#, c-format
+msgid "Reading dictionary file %s..."
+msgstr "×òåíèå ôàéëà ñëîâàðÿ %s..."
+
+#, c-format
+msgid "E760: No word count in %s"
+msgstr "E760: Êîëè÷åñòâî ñëîâ íå óêàçàíî â %s"
+
+#, c-format
+msgid "line %6d, word %6ld - %s"
+msgstr "ñòðîêà %6d, ñëîâî %6ld — %s"
+
+#, c-format
+msgid "Duplicate word in %s line %d: %s"
+msgstr "Ïîâòîð ñëîâà â %s íà ñòðîêå %d: %s "
+
+#, c-format
+msgid "First duplicate word in %s line %d: %s"
+msgstr "Ïåðâûé ïîâòîð ñëîâà â %s íà ñòðîêå %d: %s"
+
+#, c-format
+msgid "%d duplicate word(s) in %s"
+msgstr "%d ïîâòîðÿþùèõñÿ ñëîâ â %s"
+
+#, c-format
+msgid "Ignored %d word(s) with non-ASCII characters in %s"
+msgstr "Ïðîïóùåíî %d ñëîâ ñ íå ASCII ñèìâîëàìè â %s"
+
+#, c-format
+msgid "Reading word file %s..."
+msgstr "×òåíèå ôàéëà ñëîâ %s..."
+
+#, c-format
+msgid "Duplicate /encoding= line ignored in %s line %d: %s"
+msgstr "Ïðîèãíîðèðîâàíà ïîâòîðÿþùàÿñÿ ñòðîêà /encoding= â %s, ñòðîêà %d: %s"
+
+#, c-format
+msgid "/encoding= line after word ignored in %s line %d: %s"
+msgstr "Ïðîèãíîðèðîâàíà ñòðîêà /encoding= ïîñëå ñëîâà â %s, ñòðîêà %d: %s"
+
+#, c-format
+msgid "Duplicate /regions= line ignored in %s line %d: %s"
+msgstr "Ïðîïóñêàåòñÿ ïîâòîð ñòðîêè /regions= â %s, ñòðîêà %d: %s"
+
+#, c-format
+msgid "Too many regions in %s line %d: %s"
+msgstr "Ñëèøêîì ìíîãî ðåãèîíîâ â %s, ñòðîêà %d: %s"
+
+#, c-format
+msgid "/ line ignored in %s line %d: %s"
+msgstr "/ ñòðîêà ïðîïóñêàåòñÿ â %s, ñòðîêà %d: %s"
+
+#, c-format
+msgid "Invalid region nr in %s line %d: %s"
+msgstr "Íåäîïóñòèìûé íîìåð ðåãèîíà â %s, ñòðîêà %d: %s"
+
+#, c-format
+msgid "Unrecognized flags in %s line %d: %s"
+msgstr "Íåðàñïîçíàííûå ôëàãè â %s, ñòðîêà %d: %s"
+
+#, c-format
+msgid "Ignored %d words with non-ASCII characters"
+msgstr "Ïðîïóùåíî %d ñëîâ ñ íå ASCII ñèìâîëàìè"
+
+msgid "E845: Insufficient memory, word list will be incomplete"
+msgstr "E845: Íåäîñòàòî÷íî îïåðàòèâíîé ïàìÿòè, ñïèñîê ñëîâ áóäåò íå ïîëîí"
+
+#, c-format
+msgid "Compressed %d of %d nodes; %d (%d%%) remaining"
+msgstr "Ñæàòî %d èç %d óçëîâ; îñòàëîñü %d (%d%%)"
+
+msgid "Reading back spell file..."
+msgstr "×òåíèå çàïèñàííîãî ôàéëà ïðàâîïèñàíèÿ..."
+
+msgid "Performing soundfolding..."
+msgstr "Âûïîëíåíèå çâóêîâîé ñâ¸ðòêè..."
+
+#, c-format
+msgid "Number of words after soundfolding: %ld"
+msgstr "Êîëè÷åñòâî ñëîâ ïîñëå çâóêîâîé ñâ¸ðòêè: %ld"
+
+#, c-format
+msgid "Total number of words: %d"
+msgstr "Îáùåå êîëè÷åñòâî ñëîâ: %d"
+
+#, c-format
+msgid "Writing suggestion file %s..."
+msgstr "Çàïèñü ôàéëà ïðåäëîæåíèÿ èñïðàâëåíèé ïðàâîïèñàíèÿ %s"
+
+#, c-format
+msgid "Estimated runtime memory use: %d bytes"
+msgstr "Îöåíêà èñïîëüçîâàíèÿ ïàìÿòè ïðè âûïîëíåíèè: %d áàéò"
+
+msgid "E751: Output file name must not have region name"
+msgstr "E751: Èìÿ âûõîäíîãî ôàéëà íå äîëæíî ñîäåðæàòü íàçâàíèÿ ðåãèîíà"
+
+#, c-format
+msgid "E754: Only up to %ld regions supported"
+msgstr "E754: Ïîääåðæèâàåòñÿ íå áîëåå %ld ðåãèîíîâ"
+
+#, c-format
+msgid "E755: Invalid region in %s"
+msgstr "E755: Íåäîïóñòèìûé ðåãèîí â %s"
+
+msgid "Warning: both compounding and NOBREAK specified"
+msgstr "Ïðåäóïðåæäåíèå: îáà ñîñòàâíûå è óêàçàíî NOBREAK"
+
+#, c-format
+msgid "Writing spell file %s..."
+msgstr "Çàïèñü ôàéëà ïðàâîïèñàíèÿ %s..."
+
+msgid "Done!"
+msgstr "Çàâåðøåíî!"
+
+#, c-format
+msgid "E765: 'spellfile' does not have %ld entries"
+msgstr "E765: 'spellfile' íå ñîäåðæèò %ld ýëåìåíòîâ"
+
+#, c-format
+msgid "Word '%.*s' removed from %s"
+msgstr "Ñëîâî '%.*s' óäàëåíî èç %s"
+
+#, c-format
+msgid "Word '%.*s' added to %s"
+msgstr "Ñëîâî '%.*s' äîáàâëåíî â %s"
+
+msgid "E763: Word characters differ between spell files"
+msgstr "E763: Ñèìâîëû ñëîâ îòëè÷àþòñÿ â ôàéëàõ ïðàâîïèñàíèÿ"
+
+msgid "E783: duplicate char in MAP entry"
+msgstr "E783: Ïîâòîðÿþùèéñÿ ñèìâîë â ýëåìåíòå MAP"
+
+msgid "No Syntax items defined for this buffer"
+msgstr "Ñèíòàêñè÷åñêèå ýëåìåíòû äëÿ äàííîãî áóôåðà íå îïðåäåëåíû"
+
+msgid "syntax conceal on"
+msgstr "ñèíòàêñè÷åñêîå ñêðûòèå âêëþ÷åíî"
+
+msgid "syntax conceal off"
+msgstr "ñèíòàêñè÷åñêîå ñêðûòèå îòêëþ÷åíî"
+
+#, c-format
+msgid "E390: Illegal argument: %s"
+msgstr "E390: Íåäîïóñòèìûé ïàðàìåòð: %s"
+
+msgid "syntax case ignore"
+msgstr "ñèíòàêñè÷åñêîå èãíîðèðîâàíèå ðåãèñòðà"
+
+msgid "syntax case match"
+msgstr "ñèíòàêñè÷åñêîå ñîîòâåòñòâèå ðåãèñòðà"
+
+msgid "syntax spell toplevel"
+msgstr "ñèíòàêñè÷åñêàÿ ïðîâåðêà ïðàâîïèñàíèÿ âåðõíåãî óðîâíÿ"
+
+msgid "syntax spell notoplevel"
+msgstr "ñèíòàêñè÷åñêàÿ ïðîâåðêà ïðàâîïèñàíèÿ áåç âåðõíåãî óðîâíÿ"
+
+msgid "syntax spell default"
+msgstr "ñèíòàêñè÷åñêàÿ ïðîâåðêà ïðàâîïèñàíèÿ ïî óìîë÷àíèþ"
+
+msgid "syntax iskeyword "
+msgstr "ñèíòàêñè÷åñêîå êëþ÷åâîå ñëîâî"
+
+#, c-format
+msgid "E391: No such syntax cluster: %s"
+msgstr "E391: Ñèíòàêñè÷åñêèé êëàñòåð %s íå íàéäåí"
+
+msgid "syncing on C-style comments"
+msgstr "Ñèíõðîíèçàöèÿ ïî êîììåíòàðèÿì â ñòèëå ÿçûêà C"
+
+msgid "no syncing"
+msgstr "áåç ñèíõðîíèçàöèè"
+
+msgid "syncing starts "
+msgstr "ñèíõðîíèçàöèÿ íà÷àòà "
+
+msgid " lines before top line"
+msgstr " ñòðîê ïåðåä âåðõíåé ñòðîêîé"
+
+msgid ""
+"\n"
+"--- Syntax sync items ---"
+msgstr ""
+"\n"
+"--- Ýëåìåíòû ñèíõðîíèçàöèè ñèíòàêñèñà ---"
+
+msgid ""
+"\n"
+"syncing on items"
+msgstr ""
+"\n"
+"ñèíõðîíèçàöèÿ ïî ýëåìåíòàì"
+
+msgid ""
+"\n"
+"--- Syntax items ---"
+msgstr ""
+"\n"
+"--- Ñèíòàêñè÷åñêèå ýëåìåíòû ---"
+
+#, c-format
+msgid "E392: No such syntax cluster: %s"
+msgstr "E392: Ñèíòàêñè÷åñêèé êëàñòåð %s íå íàéäåí"
+
+msgid "minimal "
+msgstr "ìèíèìóì "
+
+msgid "maximal "
+msgstr "ìàêñèìóì "
+
+msgid "; match "
+msgstr "; ñîîòâåòñòâèå "
+
+msgid " line breaks"
+msgstr " ïåðåíîñîâ ñòðîê"
+
+msgid "E395: contains argument not accepted here"
+msgstr "E395: Çäåñü íåëüçÿ èñïîëüçîâàòü ïàðàìåòð contains"
+
+msgid "E844: invalid cchar value"
+msgstr "E844: Íåäîïóñòèìîå çíà÷åíèå cchar"
+
+msgid "E393: group[t]here not accepted here"
+msgstr "E393: Çäåñü íåëüçÿ èñïîëüçîâàòü group[t]here"
+
+#, c-format
+msgid "E394: Didn't find region item for %s"
+msgstr "E394: Ýëåìåíò îáëàñòè äëÿ %s íå íàéäåí"
+
+msgid "E397: Filename required"
+msgstr "E397: Òðåáóåòñÿ óêàçàòü èìÿ ôàéëà"
+
+msgid "E847: Too many syntax includes"
+msgstr "E847: Ñëèøêîì ìíîãî ñèíòàêñè÷åñêèõ âêëþ÷åíèé"
+
+#, c-format
+msgid "E789: Missing ']': %s"
+msgstr "E789: Ïðîïóùåíî ']': %s"
+
+#, c-format
+msgid "E890: trailing char after ']': %s]%s"
+msgstr "E890: Ëèøíèå ñèìâîëû ïîñëå ']': %s]%s"
+
+#, c-format
+msgid "E398: Missing '=': %s"
+msgstr "E398: Ïðîïóùåíî '=': %s"
+
+#, c-format
+msgid "E399: Not enough arguments: syntax region %s"
+msgstr "E399: Íå õâàòàåò ïàðàìåòðîâ: ñèíòàêñè÷åñêèé ðåãèîí %s"
+
+msgid "E848: Too many syntax clusters"
+msgstr "E848: Ñëèøêîì ìíîãî ñèíòàêñè÷åñêèõ êëàñòåðîâ"
+
+msgid "E400: No cluster specified"
+msgstr "E400: Êëàñòåð íå óêàçàí"
+
+#, c-format
+msgid "E401: Pattern delimiter not found: %s"
+msgstr "E401: Íå íàéäåí ðàçäåëèòåëü øàáëîíîâ: %s"
+
+#, c-format
+msgid "E402: Garbage after pattern: %s"
+msgstr "E402: Ìóñîð ïîñëå øàáëîíà: %s"
+
+msgid "E403: syntax sync: line continuations pattern specified twice"
+msgstr ""
+"E403: Ñèíõðîíèçàöèÿ ñèíòàêñèñà: øàáëîí ïðîäîëæåíèé ñòðîêè óêàçàí äâàæäû"
+
+#, c-format
+msgid "E404: Illegal arguments: %s"
+msgstr "E404: Íåäîïóñòèìûå ïàðàìåòðû: %s"
+
+#, c-format
+msgid "E405: Missing equal sign: %s"
+msgstr "E405: Ïðîïóùåí çíàê ðàâåíñòâà: %s"
+
+#, c-format
+msgid "E406: Empty argument: %s"
+msgstr "E406: Ïóñòîé ïàðàìåòð: %s"
+
+#, c-format
+msgid "E407: %s not allowed here"
+msgstr "E407: %s íå äîïóñêàåòñÿ â ýòîì ìåñòå"
+
+#, c-format
+msgid "E408: %s must be first in contains list"
+msgstr "E408: %s äîëæíî áûòü ïåðâûì â ñïèñêå contains"
+
+#, c-format
+msgid "E409: Unknown group name: %s"
+msgstr "E409: Íåèçâåñòíàÿ ãðóïïà: %s"
+
+#, c-format
+msgid "E410: Invalid :syntax subcommand: %s"
+msgstr "E410: Íåïðàâèëüíàÿ ïîäêîìàíäà :syntax: %s"
+
+msgid ""
+" TOTAL COUNT MATCH SLOWEST AVERAGE NAME PATTERN"
+msgstr ""
+" ÂÑÅÃÎ ÊÎË. ÑÎÎÒÂ. ÎÒÑÒÀÞÙÈÉ ÑÐÅÄÍÈÉ ÈÌß ØÀÁËÎÍ"
+
+msgid "E679: recursive loop loading syncolor.vim"
+msgstr "E679: Ðåêóðñèâíàÿ ïåòëÿ ïðè çàãðóçêå syncolor.vim"
+
+#, c-format
+msgid "E411: highlight group not found: %s"
+msgstr "E411: Ãðóïïà ïîäñâåòêè ñèíòàêñèñà %s íå íàéäåíà"
+
+#, c-format
+msgid "E412: Not enough arguments: \":highlight link %s\""
+msgstr "E412: Íå õâàòàåò ïàðàìåòðîâ: \":highlight link %s\""
+
+#, c-format
+msgid "E413: Too many arguments: \":highlight link %s\""
+msgstr "E413: Ñëèøêîì ìíîãî ïàðàìåòðîâ: \":highlight link %s\""
+
+msgid "E414: group has settings, highlight link ignored"
+msgstr "E414: Ó ãðóïïû åñòü íàñòðîéêè, ïðîïóñêàåòñÿ highlight link"
+
+#, c-format
+msgid "E415: unexpected equal sign: %s"
+msgstr "E415: Íåîæèäàííûé çíàê ðàâåíñòâà: %s"
+
+#, c-format
+msgid "E416: missing equal sign: %s"
+msgstr "E416: Ïðîïóùåí çíàê ðàâåíñòâà: %s"
+
+#, c-format
+msgid "E417: missing argument: %s"
+msgstr "E417: Ïðîïóùåí ïàðàìåòð: %s"
+
+#, c-format
+msgid "E418: Illegal value: %s"
+msgstr "E418: Íåäîïóñòèìîå çíà÷åíèå: %s"
+
+msgid "E419: FG color unknown"
+msgstr "E419: Íåèçâåñòíûé öâåò òåêñòà"
+
+msgid "E420: BG color unknown"
+msgstr "E420: Íåèçâåñòíûé öâåò ôîíà"
+
+#, c-format
+msgid "E421: Color name or number not recognized: %s"
+msgstr "E421: Èìÿ èëè íîìåð öâåòà íå èçâåñòíî: %s"
+
+#, c-format
+msgid "E422: terminal code too long: %s"
+msgstr "E422: Ñëèøêîì äëèííûé êîä òåðìèíàëà: %s"
+
+#, c-format
+msgid "E423: Illegal argument: %s"
+msgstr "E423: Íåäîïóñòèìûé ïàðàìåòð: %s"
+
+msgid "E424: Too many different highlighting attributes in use"
+msgstr "E424: Èñïîëüçóåòñÿ ñëèøêîì ìíîãî ðàçíûõ àòðèáóòîâ ïîäñâåòêè ñèíòàêñèñà"
+
+msgid "E669: Unprintable character in group name"
+msgstr "E669: Íåïå÷àòíûé ñèìâîë â èìåíè ãðóïïû"
+
+msgid "W18: Invalid character in group name"
+msgstr "W18: Íåäîïóñòèìûé ñèìâîë â èìåíè ãðóïïû"
+
+msgid "E849: Too many highlight and syntax groups"
+msgstr "E849: Ñëèøêîì ìíîãî ãðóïï ïîäñâåòêè è ñèíòàêñèñà"
+
+msgid "E555: at bottom of tag stack"
+msgstr "E555: Âíèçó ñòåêà ìåòîê"
+
+msgid "E556: at top of tag stack"
+msgstr "E556: Íàâåðõó ñòåêà ìåòîê"
+
+msgid "E425: Cannot go before first matching tag"
+msgstr "E425: Íåâîçìîæíî ïåðåéòè â ïîçèöèþ äî ïåðâîé ñîâïàäàþùåé ìåòêè"
+
+#, c-format
+msgid "E426: tag not found: %s"
+msgstr "E426: Ìåòêà íå íàéäåíà: %s"
+
+msgid " # pri kind tag"
+msgstr " # ïðè òèï ìåòêà"
+
+msgid "file\n"
+msgstr "ôàéë\n"
+
+msgid "E427: There is only one matching tag"
+msgstr "E427: Åñòü òîëüêî îäíà ñîâïàäàþùàÿ ìåòêà"
+
+msgid "E428: Cannot go beyond last matching tag"
+msgstr "E428: Íåâîçìîæíî ïåðåéòè â ïîçèöèþ çà ïîñëåäíåé ñîâïàäàþùåé ìåòêîé"
+
+#, c-format
+msgid "File \"%s\" does not exist"
+msgstr "Ôàéë \"%s\" íå ñóùåñòâóåò"
+
+#, c-format
+msgid "tag %d of %d%s"
+msgstr "ìåòêà %d èç %d%s"
+
+msgid " or more"
+msgstr " è áîëåå"
+
+msgid " Using tag with different case!"
+msgstr " Èñïîëüçóåòñÿ ìåòêà ñ ñèìâîëàìè â äðóãîì ðåãèñòðå!"
+
+#, c-format
+msgid "E429: File \"%s\" does not exist"
+msgstr "E429: Ôàéë \"%s\" íå ñóùåñòâóåò"
+
+msgid ""
+"\n"
+" # TO tag FROM line in file/text"
+msgstr ""
+"\n"
+" # Ê ìåòêå ÎÒ ñòð. â ôàéëå/òåêñòå"
+
+#, c-format
+msgid "Searching tags file %s"
+msgstr "Ïîèñê â ôàéëå ìåòîê %s"
+
+#, c-format
+msgid "E430: Tag file path truncated for %s\n"
+msgstr "E430: Ïóòü ê ôàéëó ìåòîê %s îáðåçàí\n"
+
+msgid "Ignoring long line in tags file"
+msgstr "Èãíîðèðîâàíèå äëèííîé ñòðîêè â ôàéëå tags"
+
+#, c-format
+msgid "E431: Format error in tags file \"%s\""
+msgstr "E431: Îøèáêà ôîðìàòà â ôàéëå ìåòîê \"%s\""
+
+#, c-format
+msgid "Before byte %ld"
+msgstr "Ïåðåä áàéòîì %ld"
+
+#, c-format
+msgid "E432: Tags file not sorted: %s"
+msgstr "E432: Ôàéë ìåòîê íå îòñîðòèðîâàí: %s"
+
+msgid "E433: No tags file"
+msgstr "E433: Ôàéë ìåòîê íå îáíàðóæåí"
+
+msgid "E434: Can't find tag pattern"
+msgstr "E434: Íå íàéäåí øàáëîí ìåòêè"
+
+msgid "E435: Couldn't find tag, just guessing!"
+msgstr "E435: Ìåòêà íå íàéäåíà, ïûòàåìñÿ óãàäàòü!"
+
+#, c-format
+msgid "Duplicate field name: %s"
+msgstr "Ïîâòîðÿþùååñÿ èìÿ ïîëÿ: %s"
+
+msgid "' not known. Available builtin terminals are:"
+msgstr "' íå èçâåñòåí. Äîñòóïíû âñòðîåííûå òåðìèíàëû:"
+
+msgid "defaulting to '"
+msgstr "ïî óìîë÷àíèþ '"
+
+msgid "E557: Cannot open termcap file"
+msgstr "E557: Íåâîçìîæíî îòêðûòü ôàéë termcap"
+
+msgid "E558: Terminal entry not found in terminfo"
+msgstr "E558: Â terminfo íåò çàïèñè îá ýòîì òåðìèíàëå"
+
+msgid "E559: Terminal entry not found in termcap"
+msgstr "E559: Â termcap íåò çàïèñè îá ýòîì òåðìèíàëå"
+
+#, c-format
+msgid "E436: No \"%s\" entry in termcap"
+msgstr "E436: Â termcap íåò çàïèñè \"%s\""
+
+msgid "E437: terminal capability \"cm\" required"
+msgstr "E437: Òðåáóåòñÿ ñïîñîáíîñòü òåðìèíàëà \"cm\""
+
+msgid ""
+"\n"
+"--- Terminal keys ---"
+msgstr ""
+"\n"
+"--- Êíîïêè òåðìèíàëà ---"
+
+msgid "Cannot open $VIMRUNTIME/rgb.txt"
+msgstr "Íåâîçìîæíî îòêðûòü $VIMRUNTIME/rgb.txt"
+
+#, c-format
+msgid "Kill job in \"%s\"?"
+msgstr "Óáèòü çàäàíèå â \"%s\"?"
+
+msgid "Terminal"
+msgstr "Òåðìèíàë"
+
+msgid "Terminal-finished"
+msgstr "Òåðìèíàë-çàâåðøåíî"
+
+msgid "active"
+msgstr "àêòèâíî"
+
+msgid "running"
+msgstr "âûïîëíåíèå"
+
+msgid "finished"
+msgstr "çàâåðøåíî"
+
+#, c-format
+msgid "E953: File exists: %s"
+msgstr "E953: Ôàéë ñóùåñòâóåò: %s"
+
+msgid "E955: Not a terminal buffer"
+msgstr "E955: Íå ÿâëÿåòñÿ áóôåðîì òåðìèíàëà"
+
+msgid "new shell started\n"
+msgstr "çàïóñê íîâîé îáîëî÷êè\n"
+
+msgid "Vim: Error reading input, exiting...\n"
+msgstr "Vim: Îøèáêà ÷òåíèÿ ââîäà, âûõîä...\n"
+
+msgid "Used CUT_BUFFER0 instead of empty selection"
+msgstr "Âìåñòî ïóñòîãî âûäåëåíèÿ èñïîëüçóåòñÿ CUT_BUFFER0"
+
+msgid "E881: Line count changed unexpectedly"
+msgstr "E881: Íåîæèäàííî èçìåíèëñÿ ñ÷¸ò÷èê ñòðîê"
+
+msgid "No undo possible; continue anyway"
+msgstr "Îòìåíà íåâîçìîæíà; ïðîäîëæàòü âûïîëíåíèå"
+
+#, c-format
+msgid "E828: Cannot open undo file for writing: %s"
+msgstr "E828: Íåâîçìîæíî îòêðûòü ôàéë îòìåí äëÿ çàïèñè: %s"
+
+#, c-format
+msgid "E825: Corrupted undo file (%s): %s"
+msgstr "E825: Ôàéë îòìåí ïîâðåæä¸í (%s): %s"
+
+msgid "Cannot write undo file in any directory in 'undodir'"
+msgstr "Íåâîçìîæíî çàïèñàòü ôàéë îòìåí â êàêîì-ëèáî êàòàëîãå èç 'undodir'"
+
+#, c-format
+msgid "Will not overwrite with undo file, cannot read: %s"
+msgstr "Ôàéë îòìåí íå ïåðåçàïèñàí, íåâîçìîæíî ïðî÷èòàòü: %s"
+
+#, c-format
+msgid "Will not overwrite, this is not an undo file: %s"
+msgstr "Ïåðåçàïèñü íå âûïîëíåíà, ýòî íå ôàéë îòìåí: %s"
+
+msgid "Skipping undo file write, nothing to undo"
+msgstr "Ïðîïóùåíà çàïèñü ôàéëà îòìåí, íå÷åãî îòìåíÿòü"
+
+#, c-format
+msgid "Writing undo file: %s"
+msgstr "Çàïèñü ôàéëà îòìåí: %s"
+
+#, c-format
+msgid "E829: write error in undo file: %s"
+msgstr "E829: Îøèáêà ïðè çàïèñè ôàéëà îòìåí: %s"
+
+#, c-format
+msgid "Not reading undo file, owner differs: %s"
+msgstr "Ôàéë îòìåí íå ïðî÷èòàí, äðóãîé âëàäåëåö: %s"
+
+#, c-format
+msgid "Reading undo file: %s"
+msgstr "×òåíèå ôàéëà îòìåí: %s"
+
+#, c-format
+msgid "E822: Cannot open undo file for reading: %s"
+msgstr "E822: Íåâîçìîæíî îòêðûòü ôàéë îòìåí äëÿ ÷òåíèÿ: %s"
+
+#, c-format
+msgid "E823: Not an undo file: %s"
+msgstr "E823: Ýòî íå ôàéë îòìåí: %s"
+
+#, c-format
+msgid "E832: Non-encrypted file has encrypted undo file: %s"
+msgstr "E832: Íå çàøèôðîâàííûé ôàéë èìååò çàøèôðîâàííûé ôàéë îòìåí: %s"
+
+#, c-format
+msgid "E826: Undo file decryption failed: %s"
+msgstr "E826: Íå óäàëîñü äåøèôðîâàòü ôàéë îòìåí: %s"
+
+#, c-format
+msgid "E827: Undo file is encrypted: %s"
+msgstr "E827: Ôàéë îòìåí çàøèôðîâàí: %s"
+
+#, c-format
+msgid "E824: Incompatible undo file: %s"
+msgstr "E824: Íåñîâìåñòèìûé ôàéë îòìåí: %s"
+
+msgid "File contents changed, cannot use undo info"
+msgstr "Èçìåíèëîñü ñîäåðæèìîå ôàéëà, íåâîçìîæíî èñïîëüçîâàòü èíôîðìàöèþ îòìåí"
+
+#, c-format
+msgid "Finished reading undo file %s"
+msgstr "Çàâåðøåíî ÷òåíèå ôàéëà îòìåí %s"
+
+msgid "Already at oldest change"
+msgstr "Óæå íà ñàìîì ïåðâîì èçìåíåíèè"
+
+msgid "Already at newest change"
+msgstr "Óæå íà ñàìîì ïîñëåäíåì èçìåíåíèè"
+
+#, c-format
+msgid "E830: Undo number %ld not found"
+msgstr "E830: Íå íàéäåíà îòìåíà íîìåð %ld"
+
+msgid "E438: u_undo: line numbers wrong"
+msgstr "E438: u_undo: íåïðàâèëüíûå íîìåðà ñòðîê"
+
+msgid "more line"
+msgstr "ñòð. äîáàâëåíà"
+
+msgid "more lines"
+msgstr "ñòð. äîáàâëåíî"
+
+msgid "line less"
+msgstr "ñòð. óäàëåíà"
+
+msgid "fewer lines"
+msgstr "ñòð. óäàëåíî"
+
+msgid "change"
+msgstr "èçì."
+
+msgid "changes"
+msgstr "èçì."
+
+#, c-format
+msgid "%ld %s; %s #%ld %s"
+msgstr "%ld %s; %s #%ld %s"
+
+msgid "before"
+msgstr "ïåðåä"
+
+msgid "after"
+msgstr "ïîñëå"
+
+msgid "Nothing to undo"
+msgstr "Íå÷åãî îòìåíÿòü"
+
+# Çàãîëîâîê òàáëèöû :undolist
+msgid "number changes when saved"
+msgstr " íîìåð èçìåí. êîãäà ñîõðàíåíî"
+
+#, c-format
+msgid "%ld seconds ago"
+msgstr "%ldñ íàçàä"
+
+msgid "E790: undojoin is not allowed after undo"
+msgstr "E790: Îáúåäèíåíèå îòìåí íå äîïóñêàåòñÿ ïîñëå îòìåíû"
+
+msgid "E439: undo list corrupt"
+msgstr "E439: Ïîâðåæä¸í ñïèñîê îòìåíû"
+
+msgid "E440: undo line missing"
+msgstr "E440: Ïîòåðÿíà ñòðîêà îòìåíû"
+
+#, c-format
+msgid "E122: Function %s already exists, add ! to replace it"
+msgstr "E122: Ôóíêöèÿ %s óæå ñóùåñòâóåò. Äîáàâüòå !, ÷òîáû çàìåíèòü å¸."
+
+msgid "E717: Dictionary entry already exists"
+msgstr "E717: Çàïèñü óæå ñóùåñòâóåò â ñëîâàðå"
+
+msgid "E718: Funcref required"
+msgstr "E718: Òðåáóåòñÿ ññûëêà íà ôóíêöèþ"
+
+#, c-format
+msgid "E130: Unknown function: %s"
+msgstr "E130: Íåèçâåñòíàÿ ôóíêöèÿ: %s"
+
+#, c-format
+msgid "E125: Illegal argument: %s"
+msgstr "E125: Íåäîïóñòèìûé ïàðàìåòð: %s"
+
+#, c-format
+msgid "E853: Duplicate argument name: %s"
+msgstr "E853: Ïîâòîðÿþùååñÿ èìÿ ïàðàìåòðà: %s"
+
+#, c-format
+msgid "E740: Too many arguments for function %s"
+msgstr "E740: Ñëèøêîì ìíîãî ïàðàìåòðîâ äëÿ ôóíêöèè %s"
+
+#, c-format
+msgid "E116: Invalid arguments for function %s"
+msgstr "E116: Ïàðàìåòðû äëÿ ôóíêöèè %s çàäàíû íåâåðíî"
+
+msgid "E132: Function call depth is higher than 'maxfuncdepth'"
+msgstr "E132: Ãëóáèíà âûçîâà ôóíêöèè áîëüøå, ÷åì çíà÷åíèå 'maxfuncdepth'"
+
+#, c-format
+msgid "calling %s"
+msgstr "âûçîâ %s"
+
+#, c-format
+msgid "%s aborted"
+msgstr "%s ïðåðâàíà"
+
+#, c-format
+msgid "%s returning #%ld"
+msgstr "%s âîçâðàùàåò #%ld"
+
+#, c-format
+msgid "%s returning %s"
+msgstr "%s âîçâðàùàåò %s"
+
+msgid "E699: Too many arguments"
+msgstr "E699: Ñëèøêîì ìíîãî ïàðàìåòðîâ"
+
+#, c-format
+msgid "E117: Unknown function: %s"
+msgstr "E117: Íåèçâåñòíàÿ ôóíêöèÿ: %s"
+
+#, c-format
+msgid "E933: Function was deleted: %s"
+msgstr "E933: Ôóíêöèÿ óäàëåíà: %s"
+
+#, c-format
+msgid "E119: Not enough arguments for function: %s"
+msgstr "E119: Íåäîñòàòî÷íî ïàðàìåòðîâ äëÿ ôóíêöèè %s"
+
+#, c-format
+msgid "E120: Using <SID> not in a script context: %s"
+msgstr "E120: <SID> èñïîëüçóåòñÿ âíå ñöåíàðèÿ: %s"
+
+#, c-format
+msgid "E725: Calling dict function without Dictionary: %s"
+msgstr "E725: Âûçîâ ôóíêöèè dict áåç ñëîâàðÿ: %s"
+
+msgid "E129: Function name required"
+msgstr "E129: Òðåáóåòñÿ èìÿ ôóíêöèè"
+
+#, c-format
+msgid "E128: Function name must start with a capital or \"s:\": %s"
+msgstr "E128: Èìÿ ôóíêöèè äîëæíî íà÷èíàòüñÿ ñ çàãëàâíîé áóêâû èëè \"s:\": %s"
+
+#, c-format
+msgid "E884: Function name cannot contain a colon: %s"
+msgstr "E884: Èìÿ ôóíêöèè íå ìîæåò ñîäåðæàòü äâîåòî÷èå: %s"
+
+#, c-format
+msgid "E123: Undefined function: %s"
+msgstr "E123: Íåîïðåäåë¸ííàÿ ôóíêöèÿ: %s"
+
+#, c-format
+msgid "E124: Missing '(': %s"
+msgstr "E124: Ïðîïóùåíà '(': %s"
+
+msgid "E862: Cannot use g: here"
+msgstr "E862: Çäåñü íåâîçìîæíî èñïîëüçîâàòü g:"
+
+#, c-format
+msgid "E932: Closure function should not be at top level: %s"
+msgstr "E932: ôóíêöèÿ-çàìûêàíèå íå äîëæíà áûòü íà âåðõíåì óðîâíå: %s"
+
+msgid "E126: Missing :endfunction"
+msgstr "E126: Ïðîïóùåíà êîìàíäà :endfunction"
+
+#, c-format
+msgid "W22: Text found after :endfunction: %s"
+msgstr "W22: Òåêñò ïîñëå :endfunction: %s"
+
+#, c-format
+msgid "E707: Function name conflicts with variable: %s"
+msgstr "E707: Èìÿ ôóíêöèè êîíôëèêòóåò ñ ïåðåìåííîé: %s"
+
+#, c-format
+msgid "E127: Cannot redefine function %s: It is in use"
+msgstr "E127: Íåâîçìîæíî ïåðåîïðåäåëèòü ôóíêöèþ %s, îíà èñïîëüçóåòñÿ"
+
+#, c-format
+msgid "E746: Function name does not match script file name: %s"
+msgstr "E746: Èìÿ ôóíêöèè íå ñîîòâåòñòâóåò èìåíè ôàéëà ñöåíàðèÿ: %s"
+
+#, c-format
+msgid "E131: Cannot delete function %s: It is in use"
+msgstr "E131: Íåâîçìîæíî óäàëèòü ôóíêöèþ %s, îíà èñïîëüçóåòñÿ"
+
+msgid "E133: :return not inside a function"
+msgstr "E133: êîìàíäà :return âíå ôóíêöèè"
+
+#, c-format
+msgid "E107: Missing parentheses: %s"
+msgstr "E107: Ïðîïóùåíû ñêîáêè: %s"
+
+msgid ""
+"\n"
+"MS-Windows 64-bit GUI version"
+msgstr ""
+"\n"
+"Âåðñèÿ ñ ãðàôè÷åñêèì èíòåðôåéñîì äëÿ MS-Windows 64 áèò"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit GUI version"
+msgstr ""
+"\n"
+"Âåðñèÿ ñ ãðàôè÷åñêèì èíòåðôåéñîì äëÿ MS-Windows 32 áèò"
+
+msgid " with OLE support"
+msgstr " ñ ïîääåðæêîé OLE"
+
+msgid ""
+"\n"
+"MS-Windows 64-bit console version"
+msgstr ""
+"\n"
+"Êîíñîëüíàÿ âåðñèÿ äëÿ MS-Windows 64 áèò"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit console version"
+msgstr ""
+"\n"
+"Êîíñîëüíàÿ âåðñèÿ äëÿ MS-Windows 32 áèò"
+
+msgid ""
+"\n"
+"macOS version"
+msgstr ""
+"\n"
+"Âåðñèÿ äëÿ macOS"
+
+msgid ""
+"\n"
+"macOS version w/o darwin feat."
+msgstr ""
+"\n"
+"Âåðñèÿ äëÿ macOS áåç darwin"
+
+msgid ""
+"\n"
+"OpenVMS version"
+msgstr ""
+"\n"
+"Âåðñèÿ äëÿ OpenVMS"
+
+msgid ""
+"\n"
+"Included patches: "
+msgstr ""
+"\n"
+"Çàïëàòêè: "
+
+msgid ""
+"\n"
+"Extra patches: "
+msgstr ""
+"\n"
+"Äîïîëíèòåëüíûå çàïëàòêè: "
+
+msgid "Modified by "
+msgstr "Ñ èçìåíåíèÿìè, âíåñ¸ííûìè "
+
+msgid ""
+"\n"
+"Compiled "
+msgstr ""
+"\n"
+"Ñêîìïèëèðîâàíî: "
+
+msgid "by "
+msgstr " "
+
+msgid ""
+"\n"
+"Huge version "
+msgstr ""
+"\n"
+"Îãðîìíàÿ âåðñèÿ "
+
+msgid ""
+"\n"
+"Big version "
+msgstr ""
+"\n"
+"Áîëüøàÿ âåðñèÿ "
+
+msgid ""
+"\n"
+"Normal version "
+msgstr ""
+"\n"
+"Îáû÷íàÿ âåðñèÿ "
+
+msgid ""
+"\n"
+"Small version "
+msgstr ""
+"\n"
+"Ìàëàÿ âåðñèÿ "
+
+msgid ""
+"\n"
+"Tiny version "
+msgstr ""
+"\n"
+"Êðîõîòíàÿ âåðñèÿ "
+
+msgid "without GUI."
+msgstr "áåç ãðàôè÷åñêîãî èíòåðôåéñà."
+
+msgid "with GTK3 GUI."
+msgstr "ñ ãðàôè÷åñêèì èíòåðôåéñîì GTK3."
+
+msgid "with GTK2-GNOME GUI."
+msgstr "ñ ãðàôè÷åñêèì èíòåðôåéñîì GTK2-GNOME."
+
+msgid "with GTK2 GUI."
+msgstr "ñ ãðàôè÷åñêèì èíòåðôåéñîì GTK2."
+
+msgid "with X11-Motif GUI."
+msgstr "ñ ãðàôè÷åñêèì èíòåðôåéñîì X11-Motif."
+
+msgid "with X11-neXtaw GUI."
+msgstr "ñ ãðàôè÷åñêèì èíòåðôåéñîì X11-neXtaw."
+
+msgid "with X11-Athena GUI."
+msgstr "ñ ãðàôè÷åñêèì èíòåðôåéñîì X11-Athena."
+
+msgid "with Photon GUI."
+msgstr "ñ ãðàôè÷åñêèì èíòåðôåéñîì Photon."
+
+msgid "with GUI."
+msgstr "ñ ãðàôè÷åñêèì èíòåðôåéñîì."
+
+msgid "with Carbon GUI."
+msgstr "ñ ãðàôè÷åñêèì èíòåðôåéñîì Carbon."
+
+msgid "with Cocoa GUI."
+msgstr "ñ ãðàôè÷åñêèì èíòåðôåéñîì Cocoa."
+
+msgid " Features included (+) or not (-):\n"
+msgstr " Âêëþ÷¸ííûå(+) è îòêëþ÷¸ííûå(-) îñîáåííîñòè:\n"
+
+msgid " system vimrc file: \""
+msgstr " îáùåñèñòåìíûé ôàéë vimrc: \""
+
+msgid " user vimrc file: \""
+msgstr " ïîëüçîâàòåëüñêèé ôàéë vimrc: \""
+
+msgid " 2nd user vimrc file: \""
+msgstr " âòîðîé ïîëüçîâàòåëüñêèé ôàéë vimrc: \""
+
+msgid " 3rd user vimrc file: \""
+msgstr " òðåòèé ïîëüçîâàòåëüñêèé ôàéë vimrc: \""
+
+msgid " user exrc file: \""
+msgstr " ïîëüçîâàòåëüñêèé ôàéë exrc: \""
+
+msgid " 2nd user exrc file: \""
+msgstr " âòîðîé ïîëüçîâàòåëüñêèé ôàéë exrc: \""
+
+msgid " system gvimrc file: \""
+msgstr " îáùåñèñòåìíûé ôàéë gvimrc: \""
+
+msgid " user gvimrc file: \""
+msgstr " ïîëüçîâàòåëüñêèé ôàéë gvimrc: \""
+
+msgid "2nd user gvimrc file: \""
+msgstr " âòîðîé ïîëüçîâàòåëüñêèé ôàéë gvimrc: \""
+
+msgid "3rd user gvimrc file: \""
+msgstr " òðåòèé ïîëüçîâàòåëüñêèé ôàéë gvimrc: \""
+
+msgid " defaults file: \""
+msgstr " ôàéë óìîë÷àíèé: \""
+
+msgid " system menu file: \""
+msgstr " îáùåñèñòåìíûé ôàéë ìåíþ: \""
+
+msgid " fall-back for $VIM: \""
+msgstr " çíà÷åíèå $VIM ïî óìîë÷àíèþ: \""
+
+msgid " f-b for $VIMRUNTIME: \""
+msgstr " çíà÷åíèå $VIMRUNTIME ïî óìîë÷àíèþ: \""
+
+msgid "Compilation: "
+msgstr "Ïàðàìåòðû êîìïèëÿöèè: "
+
+msgid "Compiler: "
+msgstr "Êîìïèëÿòîð: "
+
+msgid "Linking: "
+msgstr "Ñáîðêà: "
+
+msgid " DEBUG BUILD"
+msgstr " ÎÒËÀÄÎ×ÍÀß ÑÁÎÐÊÀ"
+
+msgid "VIM - Vi IMproved"
+msgstr "VIM — Vi IMproved (óëó÷øåííûé Vi)"
+
+msgid "version "
+msgstr "âåðñèÿ "
+
+msgid "by Bram Moolenaar et al."
+msgstr "Áðàì Ìîîëåíààð è äðóãèå"
+
+msgid "Vim is open source and freely distributable"
+msgstr "Vim — ñâîáîäíî ðàñïðîñòðàíÿåìàÿ ïðîãðàììà ñ îòêðûòûì êîäîì"
+
+msgid "Help poor children in Uganda!"
+msgstr "Áåäíûì äåòÿì â Óãàíäå íóæíà âàøà ïîìîùü!"
+
+msgid "type :help iccf<Enter> for information "
+msgstr "íàáåðèòå :help iccf<Enter> äëÿ äîïîëíèòåëüíîé èíôîðìàöèè"
+
+msgid "type :q<Enter> to exit "
+msgstr "íàáåðèòå :q<Enter> ÷òîáû âûéòè èç ïðîãðàììû "
+
+msgid "type :help<Enter> or <F1> for on-line help"
+msgstr "íàáåðèòå :help<Enter> èëè <F1> äëÿ ïîëó÷åíèÿ ñïðàâêè "
+
+msgid "type :help version8<Enter> for version info"
+msgstr "íàáåðèòå :help version8<Enter> äëÿ èíôîðìàöèè î âåðñèè "
+
+msgid "Running in Vi compatible mode"
+msgstr "Ðàáîòà â Vi-ñîâìåñòèìîì ðåæèìå"
+
+msgid "type :set nocp<Enter> for Vim defaults"
+msgstr "íàáåðèòå :set nocp<Enter> äëÿ ïåðåõîäà â ðåæèì Vim "
+
+msgid "type :help cp-default<Enter> for info on this"
+msgstr "íàáåðèòå :help cp-default<Enter> äëÿ äîïîëíèòåëüíîé èíôîðìàöèè"
+
+msgid "menu Help->Orphans for information "
+msgstr "ìåíþ Ñïðàâêà->Ñèðîòû äëÿ ïîëó÷åíèÿ èíôîðìàöèè "
+
+msgid "Running modeless, typed text is inserted"
+msgstr "Áåçðåæèìíàÿ ðàáîòà, âñòàâêà ââåä¸ííîãî òåêñòà"
+
+msgid "menu Edit->Global Settings->Toggle Insert Mode "
+msgstr "ìåíþ Ïðàâêà->Ãëîáàëüíûå íàñòðîéêè->Ðåæèì Âñòàâêè "
+
+msgid " for two modes "
+msgstr " äëÿ äâóõ ðåæèìîâ "
+
+msgid "menu Edit->Global Settings->Toggle Vi Compatible"
+msgstr "ìåíþ Ïðàâêà->Ãëîáàëüíûå íàñòðîéêè->Ñîâìåñòèìîñòü ñ Vi "
+
+msgid " for Vim defaults "
+msgstr " äëÿ ïåðåõîäà â ðåæèì Vim "
+
+msgid "Sponsor Vim development!"
+msgstr "Ïîìîãèòå â ðàçðàáîòêå Vim!"
+
+msgid "Become a registered Vim user!"
+msgstr "Ñòàíüòå çàðåãèñòðèðîâàííûì ïîëüçîâàòåëåì Vim!"
+
+msgid "type :help sponsor<Enter> for information "
+msgstr "íàáåðèòå :help sponsor<Enter> äëÿ ïîëó÷åíèÿ èíôîðìàöèè "
+
+msgid "type :help register<Enter> for information "
+msgstr "íàáåðèòå :help register<Enter> äëÿ ïîëó÷åíèÿ èíôîðìàöèè "
+
+msgid "menu Help->Sponsor/Register for information "
+msgstr "ìåíþ Ñïðàâêà->Ïîìîùü/Ðåãèñòðàöèÿ äëÿ ïîëó÷åíèÿ èíôîðìàöèè "
+
+msgid "Already only one window"
+msgstr "Íà ýêðàíå âñåãî îäíî îêíî"
+
+msgid "E441: There is no preview window"
+msgstr "E441: Îêíî ïðåäïðîñìîòðà îòñóòñòâóåò"
+
+msgid "E442: Can't split topleft and botright at the same time"
+msgstr "E442: Îêíî íå ìîæåò áûòü îäíîâðåìåííî ñëåâà ââåðõó è ñïðàâà âíèçó"
+
+msgid "E443: Cannot rotate when another window is split"
+msgstr "E443: Íåâîçìîæíî ïîìåíÿòü ìåñòàìè, ïîêà äðóãîå îêíî ðàçäåëåíî"
+
+msgid "E444: Cannot close last window"
+msgstr "E444: Íåëüçÿ çàêðûòü ïîñëåäíåå îêíî"
+
+msgid "E813: Cannot close autocmd window"
+msgstr "E813: Íåëüçÿ çàêðûòü îêíî àâòîêîìàíä"
+
+msgid "E814: Cannot close window, only autocmd window would remain"
+msgstr "E814: Íåëüçÿ çàêðûòü îêíî, îñòàíåòñÿ òîëüêî îêíî àâòîêîìàíä"
+
+msgid "E445: Other window contains changes"
+msgstr "E445:  äðóãîì îêíå åñòü íåñîõðàí¸ííûå èçìåíåíèÿ"
+
+msgid "E446: No file name under cursor"
+msgstr "E446: Íåò èìåíè ôàéëà â ïîçèöèè êóðñîðà"
+
+#, c-format
+msgid "E447: Can't find file \"%s\" in path"
+msgstr "E447: Ôàéë \"%s\" íå íàéäåí ïî èçâåñòíûì ïóòÿì"
+
+#, c-format
+msgid "E799: Invalid ID: %ld (must be greater than or equal to 1)"
+msgstr "E799: Íåâåðíûé ID: %ld (äîëæåí áûòü áîëüøå èëè ðàâåí 1)"
+
+#, c-format
+msgid "E801: ID already taken: %ld"
+msgstr "E801: ID óæå çàíÿò: %ld"
+
+msgid "List or number required"
+msgstr "Òðåáóåòñÿ ñïèñîê èëè ÷èñëî"
+
+#, c-format
+msgid "E802: Invalid ID: %ld (must be greater than or equal to 1)"
+msgstr "E802: Íåâåðíûé ID: %ld (äîëæåí áûòü áîëüøå èëè ðàâåí 1)"
+
+#, c-format
+msgid "E803: ID not found: %ld"
+msgstr "E803: ID íå íàéäåí: %ld"
+
+#, c-format
+msgid "E370: Could not load library %s"
+msgstr "E370: Íåâîçìîæíî çàãðóçèòü áèáëèîòåêó %s"
+
+msgid "Sorry, this command is disabled: the Perl library could not be loaded."
+msgstr ""
+"Èçâèíèòå, äàííàÿ êîìàíäà îòêëþ÷åíà: íåâîçìîæíî çàãðóçèòü áèáëèîòåêó Perl"
+
+msgid "E299: Perl evaluation forbidden in sandbox without the Safe module"
+msgstr ""
+"E299: Íå äîïóñêàåòñÿ âû÷èñëåíèå Perl â ïåñî÷íèöå áåç ìîäóëÿ áåçîïàñíîñòè"
+
+msgid "Edit with &multiple Vims"
+msgstr "Ðåäàêòèðîâàòü â &ðàçíûõ Vim-àõ"
+
+msgid "Edit with single &Vim"
+msgstr "Ðåäàêòèðîâàòü â &îäíîì Vim"
+
+msgid "Diff with Vim"
+msgstr "Ñðàâíèòü ñ ïîìîùüþ Vim"
+
+msgid "Edit with &Vim"
+msgstr "Ðå&äàêòèðîâàòü ñ ïîìîùüþ Vim"
+
+msgid "Edit with existing Vim - "
+msgstr "Ðåäàêòèðîâàòü â çàïóùåííîì Vim — "
+
+msgid "Edits the selected file(s) with Vim"
+msgstr "Ðåäàêòèðîâàòü âûäåëåííûå ôàéëû ñ ïîìîùüþ Vim"
+
+msgid "Error creating process: Check if gvim is in your path!"
+msgstr "Îøèáêà ñîçäàíèÿ ïðîöåññà: ïðîâåðüòå äîñòóïíîñòü gvim â ïóòè!"
+
+msgid "gvimext.dll error"
+msgstr "îøèáêà gvimext.dll"
+
+msgid "Path length too long!"
+msgstr "Ñëèøêîì äëèííûé ïóòü!"
+
+msgid "--No lines in buffer--"
+msgstr "-- Íåò ñòðîê â áóôåðå --"
+
+msgid "E470: Command aborted"
+msgstr "E470: Âûïîëíåíèå êîìàíäû ïðåðâàíî"
+
+msgid "E471: Argument required"
+msgstr "E471: Òðåáóåòñÿ óêàçàòü ïàðàìåòð"
+
+msgid "E10: \\ should be followed by /, ? or &"
+msgstr "E10: Ïîñëå \\ äîëæåí èäòè ñèìâîë /, ? èëè &"
+
+msgid "E11: Invalid in command-line window; <CR> executes, CTRL-C quits"
+msgstr ""
+"E11: Íåäîïóñòèìî â îêíå êîìàíäíîé ñòðîêè; <CR> âûïîëíåíèå, CTRL-C âûõîä"
+
+msgid "E12: Command not allowed from exrc/vimrc in current dir or tag search"
+msgstr ""
+"E12: Êîìàíäà íå äîïóñêàåòñÿ â exrc/vimrc â òåêóùåì êàòàëîãå èëè ïîèñêå ìåòîê"
+
+msgid "E171: Missing :endif"
+msgstr "E171: Îòñóòñòâóåò êîìàíäà :endif"
+
+msgid "E600: Missing :endtry"
+msgstr "E600: Îòñóòñòâóåò êîìàíäà :endtry"
+
+msgid "E170: Missing :endwhile"
+msgstr "E170: Îòñóòñòâóåò êîìàíäà :endwhile"
+
+msgid "E170: Missing :endfor"
+msgstr "E170: Îòñóòñòâóåò êîìàíäà :endfor"
+
+msgid "E588: :endwhile without :while"
+msgstr "E588: Êîìàíäà :endwhile áåç ïàðíîé êîìàíäû :while"
+
+msgid "E588: :endfor without :for"
+msgstr "E588: :endfor áåç :for"
+
+msgid "E13: File exists (add ! to override)"
+msgstr "E13: Ôàéë ñóùåñòâóåò (äîáàâüòå !, ÷òîáû ïåðåçàïèñàòü)"
+
+msgid "E472: Command failed"
+msgstr "E472: Íå óäàëîñü âûïîëíèòü êîìàíäó"
+
+#, c-format
+msgid "E234: Unknown fontset: %s"
+msgstr "E234: Íåèçâåñòíûé øðèôòîâîé íàáîð: %s"
+
+#, c-format
+msgid "E235: Unknown font: %s"
+msgstr "E235: Íåèçâåñòíûé øðèôò: %s"
+
+#, c-format
+msgid "E236: Font \"%s\" is not fixed-width"
+msgstr "E236: Øðèôò \"%s\" íå ÿâëÿåòñÿ ìîíîøèðèííûì"
+
+msgid "E473: Internal error"
+msgstr "E473: Âíóòðåííÿÿ îøèáêà"
+
+#, c-format
+msgid "E685: Internal error: %s"
+msgstr "E685: Âíóòðåííÿÿ îøèáêà: %s"
+
+msgid "Interrupted"
+msgstr "Ïðåðâàíî"
+
+msgid "E14: Invalid address"
+msgstr "E14: Íåäîïóñòèìûé àäðåñ"
+
+msgid "E474: Invalid argument"
+msgstr "E474: Íåäîïóñòèìûé ïàðàìåòð"
+
+#, c-format
+msgid "E475: Invalid argument: %s"
+msgstr "E475: Íåäîïóñòèìûé ïàðàìåòð: %s"
+
+#, c-format
+msgid "E475: Invalid value for argument %s"
+msgstr "E475: Íåäîïóñòèìîå çíà÷åíèå ïàðàìåòðà: %s"
+
+#, c-format
+msgid "E475: Invalid value for argument %s: %s"
+msgstr "E475: Íåäîïóñòèìîå çíà÷åíèå ïàðàìåòðà %s: %s"
+
+#, c-format
+msgid "E15: Invalid expression: %s"
+msgstr "E15: Íåäîïóñòèìîå âûðàæåíèå: %s"
+
+msgid "E16: Invalid range"
+msgstr "E16: Íåäîïóñòèìûé äèàïàçîí"
+
+msgid "E476: Invalid command"
+msgstr "E476: Íåäîïóñòèìàÿ êîìàíäà"
+
+#, c-format
+msgid "E17: \"%s\" is a directory"
+msgstr "E17: \"%s\" ÿâëÿåòñÿ êàòàëîãîì"
+
+#, c-format
+msgid "E364: Library call failed for \"%s()\""
+msgstr "E364: Íåóäà÷íûé âûçîâ ôóíêöèè \"%s()\" èç áèáëèîòåêè"
+
+msgid "E667: Fsync failed"
+msgstr "E667: Íå óäàëîñü âûïîëíèòü ôóíêöèþ fsync()"
+
+#, c-format
+msgid "E448: Could not load library function %s"
+msgstr "E448: Íå óäàëîñü çàãðóçèòü ôóíêöèþ %s èç áèáëèîòåêè"
+
+msgid "E19: Mark has invalid line number"
+msgstr "E19: Îòìåòêà óêàçûâàåò íà íåïðàâèëüíûé íîìåð ñòðîêè"
+
+msgid "E20: Mark not set"
+msgstr "E20: Îòìåòêà íå îïðåäåëåíà"
+
+msgid "E21: Cannot make changes, 'modifiable' is off"
+msgstr "E21: Èçìåíåíèÿ íåâîçìîæíû, òàê êàê îòêëþ÷åíà îïöèÿ 'modifiable'"
+
+msgid "E22: Scripts nested too deep"
+msgstr "E22: Ñëèøêîì ãëóáîêî âëîæåííûå ñöåíàðèè"
+
+msgid "E23: No alternate file"
+msgstr "E23: Ñîñåäíèé ôàéë íå ñóùåñòâóåò"
+
+msgid "E24: No such abbreviation"
+msgstr "E24: Íåò òàêîãî ñîêðàùåíèÿ"
+
+msgid "E477: No ! allowed"
+msgstr "E477: ! íå äîïóñêàåòñÿ"
+
+msgid "E25: GUI cannot be used: Not enabled at compile time"
+msgstr ""
+"E25: Âîçìîæíîñòü èñïîëüçîâàíèÿ ãðàôè÷åñêîãî èíòåðôåéñà âûêëþ÷åíà ïðè "
+"êîìïèëÿöèè"
+
+msgid "E26: Hebrew cannot be used: Not enabled at compile time\n"
+msgstr "E26: Èâðèò âûêëþ÷åí ïðè êîìïèëÿöèè\n"
+
+msgid "E27: Farsi cannot be used: Not enabled at compile time\n"
+msgstr "E27: Ôàðñè âûêëþ÷åíî ïðè êîìïèëÿöèè\n"
+
+msgid "E800: Arabic cannot be used: Not enabled at compile time\n"
+msgstr "E800: Àðàáñêèé âûêëþ÷åí ïðè êîìïèëÿöèè\n"
+
+#, c-format
+msgid "E28: No such highlight group name: %s"
+msgstr "E28: Ãðóïïà ïîäñâåòêè ñèíòàêñèñà %s íå ñóùåñòâóåò"
+
+msgid "E29: No inserted text yet"
+msgstr "E29: Ïîêà íåò âñòàâëåííîãî òåêñòà"
+
+msgid "E30: No previous command line"
+msgstr "E30: Ïðåäûäóùåé êîìàíäíîé ñòðîêè íåò"
+
+msgid "E31: No such mapping"
+msgstr "E31: Òàêîé ïðèâÿçêè íå ñóùåñòâóåò"
+
+msgid "E479: No match"
+msgstr "E479: Íåò ñîîòâåòñòâèÿ"
+
+#, c-format
+msgid "E480: No match: %s"
+msgstr "E480: Íåò ñîîòâåòñòâèÿ: %s"
+
+msgid "E32: No file name"
+msgstr "E32: Íåò èìåíè ôàéëà"
+
+msgid "E33: No previous substitute regular expression"
+msgstr "E33: Íåò ïðåäûäóùåãî ðåãóëÿðíîãî âûðàæåíèÿ äëÿ çàìåíû"
+
+msgid "E34: No previous command"
+msgstr "E34: Íåò ïðåäûäóùåé êîìàíäû"
+
+msgid "E35: No previous regular expression"
+msgstr "E35: Íåò ïðåäûäóùåãî ðåãóëÿðíîãî âûðàæåíèÿ"
+
+msgid "E481: No range allowed"
+msgstr "E481: Èñïîëüçîâàíèå äèàïàçîíà íå äîïóñêàåòñÿ"
+
+msgid "E36: Not enough room"
+msgstr "E36: Íåäîñòàòî÷íî ìåñòà"
+
+#, c-format
+msgid "E247: no registered server named \"%s\""
+msgstr "E247: Ñåðâåð \"%s\" íå çàðåãèñòðèðîâàí"
+
+#, c-format
+msgid "E482: Can't create file %s"
+msgstr "E482: Íåâîçìîæíî ñîçäàòü ôàéë %s"
+
+msgid "E483: Can't get temp file name"
+msgstr "E483: Íåâîçìîæíî ïîëó÷èòü èìÿ âðåìåííîãî ôàéëà"
+
+#, c-format
+msgid "E484: Can't open file %s"
+msgstr "E484: Íåâîçìîæíî îòêðûòü ôàéë %s"
+
+#, c-format
+msgid "E485: Can't read file %s"
+msgstr "E485: Íåâîçìîæíî ïðî÷èòàòü ôàéë %s"
+
+msgid "E38: Null argument"
+msgstr "E38: Íóëåâîé ïàðàìåòð"
+
+msgid "E39: Number expected"
+msgstr "E39: Òðåáóåòñÿ ÷èñëî"
+
+#, c-format
+msgid "E40: Can't open errorfile %s"
+msgstr "E40: Íå óäàëîñü îòêðûòü ôàéë îøèáîê %s"
+
+msgid "E233: cannot open display"
+msgstr "E233: Íåâîçìîæíî îòêðûòü äèñïëåé"
+
+msgid "E41: Out of memory!"
+msgstr "E41: Íå õâàòàåò ïàìÿòè!"
+
+msgid "Pattern not found"
+msgstr "Øàáëîí íå íàéäåí"
+
+#, c-format
+msgid "E486: Pattern not found: %s"
+msgstr "E486: Øàáëîí íå íàéäåí: %s"
+
+msgid "E487: Argument must be positive"
+msgstr "E487: Ïàðàìåòð äîëæåí áûòü ïîëîæèòåëüíûì ÷èñëîì"
+
+msgid "E459: Cannot go back to previous directory"
+msgstr "E459: Âîçâðàò â ïðåäûäóùèé êàòàëîã íåâîçìîæåí"
+
+msgid "E42: No Errors"
+msgstr "E42: Íåò îøèáîê"
+
+msgid "E776: No location list"
+msgstr "E776: Íåò ñïèñêà ðàñïîëîæåíèé"
+
+msgid "E43: Damaged match string"
+msgstr "E43: Ïîâðåæäåíà ñòðîêà ñîîòâåòñòâèÿ"
+
+msgid "E44: Corrupted regexp program"
+msgstr "E44: Ïðîãðàììà îáðàáîòêè ðåãóëÿðíûõ âûðàæåíèé ïîâðåæäåíà"
+
+msgid "E45: 'readonly' option is set (add ! to override)"
+msgstr "E45: Âêëþ÷åíà îïöèÿ 'readonly' (äîáàâüòå !, ÷òîáû îáîéòè ïðîâåðêó)"
+
+#, c-format
+msgid "E46: Cannot change read-only variable \"%s\""
+msgstr "E46: Íåâîçìîæíî èçìåíèòü ïåðåìåííóþ òîëüêî äëÿ ÷òåíèÿ \"%s\""
+
+#, c-format
+msgid "E794: Cannot set variable in the sandbox: \"%s\""
+msgstr "E794: Íåâîçìîæíî èçìåíèòü ïåðåìåííóþ â ïåñî÷íèöå: \"%s\""
+
+msgid "E713: Cannot use empty key for Dictionary"
+msgstr "E713: Íåâîçìîæíî èñïîëüçîâàòü ïóñòîé êëþ÷ äëÿ ñëîâàðÿ"
+
+msgid "E715: Dictionary required"
+msgstr "E715: Òðåáóåòñÿ ñëîâàðü"
+
+#, c-format
+msgid "E684: list index out of range: %ld"
+msgstr "E684: Èíäåêñ ñïèñêà çà ïðåäåëàìè äèàïàçîíà: %ld"
+
+#, c-format
+msgid "E118: Too many arguments for function: %s"
+msgstr "E118: Ñëèøêîì ìíîãî ïàðàìåòðîâ äëÿ ôóíêöèè %s"
+
+#, c-format
+msgid "E716: Key not present in Dictionary: %s"
+msgstr "E716: Íåò êëþ÷à â ñëîâàðå: %s"
+
+msgid "E714: List required"
+msgstr "E714: Òðåáóåòñÿ ñïèñîê"
+
+#, c-format
+msgid "E712: Argument of %s must be a List or Dictionary"
+msgstr "E712: Ïàðàìåòð %s äîëæåí áûòü ñïèñêîì èëè ñëîâàð¸ì"
+
+msgid "E47: Error while reading errorfile"
+msgstr "E47: Îøèáêà ïðè ÷òåíèè ôàéëà îøèáîê"
+
+msgid "E48: Not allowed in sandbox"
+msgstr "E48: Íå äîïóñêàåòñÿ â ïåñî÷íèöå"
+
+msgid "E523: Not allowed here"
+msgstr "E523: Çäåñü íå ðàçðåøåíî"
+
+msgid "E359: Screen mode setting not supported"
+msgstr "E359: Äàííûé ðåæèì ýêðàíà íå ïîääåðæèâàåòñÿ"
+
+msgid "E49: Invalid scroll size"
+msgstr "E49: Íåäîïóñòèìûé ðàçìåð ïðîêðóòêè"
+
+msgid "E91: 'shell' option is empty"
+msgstr "E91: Çíà÷åíèåì îïöèè 'shell' ÿâëÿåòñÿ ïóñòàÿ ñòðîêà"
+
+msgid "E255: Couldn't read in sign data!"
+msgstr "E255: Íåâîçìîæíî ïðî÷èòàòü äàííûå î çíà÷êàõ!"
+
+msgid "E72: Close error on swap file"
+msgstr "E72: Îøèáêà çàêðûòèÿ ñâîï-ôàéëà"
+
+msgid "E73: tag stack empty"
+msgstr "E73: Ñòåê ìåòîê ïóñòîé"
+
+msgid "E74: Command too complex"
+msgstr "E74: Ñëèøêîì ñëîæíàÿ êîìàíäà"
+
+msgid "E75: Name too long"
+msgstr "E75: Ñëèøêîì äëèííîå èìÿ"
+
+msgid "E76: Too many ["
+msgstr "E76: Ñëèøêîì ìíîãî ñèìâîëîâ ["
+
+msgid "E77: Too many file names"
+msgstr "E77: Ñëèøêîì ìíîãî èì¸í ôàéëîâ"
+
+msgid "E488: Trailing characters"
+msgstr "E488: Ëèøíèå ñèìâîëû íà õâîñòå"
+
+msgid "E78: Unknown mark"
+msgstr "E78: Íåèçâåñòíàÿ îòìåòêà"
+
+msgid "E79: Cannot expand wildcards"
+msgstr "E79: Íåâîçìîæíî âûïîëíèòü ïîäñòàíîâêó ïî ìàñêå"
+
+msgid "E591: 'winheight' cannot be smaller than 'winminheight'"
+msgstr ""
+"E591: Çíà÷åíèå îïöèè 'winheight' íå ìîæåò áûòü ìåíüøå çíà÷åíèÿ 'winminheight'"
+
+msgid "E592: 'winwidth' cannot be smaller than 'winminwidth'"
+msgstr ""
+"E592: Çíà÷åíèå îïöèè 'winwidth' íå ìîæåò áûòü ìåíüøå çíà÷åíèÿ 'winminwidth'"
+
+msgid "E80: Error while writing"
+msgstr "E80: Îøèáêà ïðè çàïèñè"
+
+msgid "E939: Positive count required"
+msgstr "E939: Òðåáóåòñÿ ïîëîæèòåëüíûé ñ÷¸ò÷èê"
+
+msgid "E81: Using <SID> not in a script context"
+msgstr "E81: Èñïîëüçîâàíèå <SID> âíå êîíòåêñòà ñöåíàðèÿ"
+
+msgid "E449: Invalid expression received"
+msgstr "E449: Ïîëó÷åíî íåäîïóñòèìîå âûðàæåíèå"
+
+msgid "E463: Region is guarded, cannot modify"
+msgstr "E463: Íåâîçìîæíî èçìåíèòü îõðàíÿåìóþ îáëàñòü"
+
+msgid "E744: NetBeans does not allow changes in read-only files"
+msgstr "E744: NetBeans íå äîïóñêàåò èçìåíåíèé â ôàéëàõ òîëüêî äëÿ ÷òåíèÿ"
+
+msgid "E363: pattern uses more memory than 'maxmempattern'"
+msgstr "E363: Øàáëîí èñïîëüçóåò áîëüøå ïàìÿòè ÷åì 'maxmempattern'"
+
+msgid "E749: empty buffer"
+msgstr "E749: Ïóñòîé áóôåð"
+
+#, c-format
+msgid "E86: Buffer %ld does not exist"
+msgstr "E86: Áóôåð %ld íå ñóùåñòâóåò"
+
+msgid "E682: Invalid search pattern or delimiter"
+msgstr "E682: Íåïðàâèëüíàÿ ñòðîêà ïîèñêà èëè ðàçäåëèòåëü"
+
+msgid "E139: File is loaded in another buffer"
+msgstr "E139: Ôàéë çàãðóæåí â äðóãîì áóôåðå"
+
+#, c-format
+msgid "E764: Option '%s' is not set"
+msgstr "E764: Îïöèÿ '%s' íå óñòàíîâëåíà"
+
+msgid "E850: Invalid register name"
+msgstr "E850: Íåäîïóñòèìîå èìÿ ðåãèñòðà"
+
+#, c-format
+msgid "E919: Directory not found in '%s': \"%s\""
+msgstr "E919: Êàòàëîã íå íàéäåí â '%s': \"%s\""
+
+msgid "E952: Autocommand caused recursive behavior"
+msgstr "E952: Àâòîêîìàíäà âûçâàëà ðåêóðñèâíîå ïîâåäåíèå"
+
+msgid "search hit TOP, continuing at BOTTOM"
+msgstr "Ïîèñê áóäåò ïðîäîëæåí ñ ÊÎÍÖÀ äîêóìåíòà"
+
+msgid "search hit BOTTOM, continuing at TOP"
+msgstr "Ïîèñê áóäåò ïðîäîëæåí ñ ÍÀ×ÀËÀ äîêóìåíòà"
+
+#, c-format
+msgid "Need encryption key for \"%s\""
+msgstr "Òðåáóåòñÿ êëþ÷ øèôðîâàíèÿ äëÿ \"%s\""
+
+msgid "empty keys are not allowed"
+msgstr "Ïóñòûå êëþ÷è íå äîïóñòèìû"
+
+msgid "dictionary is locked"
+msgstr "Ñëîâàðü çàáëîêèðîâàí"
+
+msgid "list is locked"
+msgstr "Ñïèñîê çàáëîêèðîâàí"
+
+#, c-format
+msgid "failed to add key '%s' to dictionary"
+msgstr "Íåâîçìîæíî äîáàâèòü êëþ÷ '%s' ê ñëîâàðþ"
+
+#, c-format
+msgid "index must be int or slice, not %s"
+msgstr "Èíäåêñ äîëæåí áûòü öåëûì ÷èñëîì èëè âûáîðêîé, à íå %s"
+
+#, c-format
+msgid "expected str() or unicode() instance, but got %s"
+msgstr "Îæèäàëñÿ ýêçåìïëÿð str() èëè unicode(), íî ïîëó÷åí %s"
+
+#, c-format
+msgid "expected bytes() or str() instance, but got %s"
+msgstr "Îæèäàëñÿ ýêçåìïëÿð bytes() èëè str(), íî ïîëó÷åí %s"
+
+#, c-format
+msgid ""
+"expected int(), long() or something supporting coercing to long(), but got %s"
+msgstr "Îæèäàëîñü int(), long() èëè ÷òî-òî ïðèâîäèìîå ê long(), íî ïîëó÷åíî %s"
+
+#, c-format
+msgid "expected int() or something supporting coercing to int(), but got %s"
+msgstr "Îæèäàëîñü int() èëè ÷òî-òî ïðèâîäèìîå ê int(), íî ïîëó÷åíî %s"
+
+msgid "value is too large to fit into C int type"
+msgstr "Çíà÷åíèå ñëèøêîì âåëèêî äëÿ öåëî÷èñëåííîãî òèïà C"
+
+msgid "value is too small to fit into C int type"
+msgstr "Çíà÷åíèå ñëèøêîì ìàëî äëÿ öåëî÷èñëåííîãî òèïà C"
+
+msgid "number must be greater than zero"
+msgstr "Íîìåð äîëæåí áûòü áîëüøå íóëÿ"
+
+msgid "number must be greater or equal to zero"
+msgstr "Íîìåð äîëæåí áûòü áîëüøå èëè ðàâåí íóëþ"
+
+msgid "can't delete OutputObject attributes"
+msgstr "Íåâîçìîæíî óäàëèòü àòðèáóòû OutputObject"
+
+#, c-format
+msgid "invalid attribute: %s"
+msgstr "Íåïðàâèëüíûé àòðèáóò: %s"
+
+msgid "E264: Python: Error initialising I/O objects"
+msgstr "E264: Python: Îøèáêà èíèöèàëèçàöèè îáúåêòîâ I/O"
+
+msgid "failed to change directory"
+msgstr "Íåâîçìîæíî ñìåíèòü êàòàëîã"
+
+#, c-format
+msgid "expected 3-tuple as imp.find_module() result, but got %s"
+msgstr "Îæèäàëñÿ 3-êîðòåæ êàê ðåçóëüòàò imp.find_module(), íî ïîëó÷åí %s"
+
+#, c-format
+msgid "expected 3-tuple as imp.find_module() result, but got tuple of size %d"
+msgstr ""
+"Îæèäàëñÿ 3-êîðòåæ êàê ðåçóëüòàò imp.find_module(), íî ïîëó÷åí êîðòåæ ñ "
+"ðàçìåðîì %d"
+
+msgid "internal error: imp.find_module returned tuple with NULL"
+msgstr "Âíóòðåííÿÿ îøèáêà: imp.find_module âîçâðàòèë "
+
+msgid "cannot delete vim.Dictionary attributes"
+msgstr "Íåâîçìîæíî óäàëèòü àòðèáóòû vim.Dictionary"
+
+msgid "cannot modify fixed dictionary"
+msgstr "Íåâîçìîæíî èçìåíèòü ôèêñèðîâàííûé ñëîâàðü"
+
+#, c-format
+msgid "cannot set attribute %s"
+msgstr "Íåâîçìîæíî óñòàíîâèòü àòðèáóò %s"
+
+msgid "hashtab changed during iteration"
+msgstr "Õýø-òàáëèöà èçìåíèëàñü ïðè èòåðàöèè"
+
+#, c-format
+msgid "expected sequence element of size 2, but got sequence of size %d"
+msgstr ""
+"Îæèäàëñÿ ýëåìåíò-ïîñëåäîâàòåëüíîñòü ðàçìåðà 2, à ðàçìåð ïîëó÷åííîé "
+"ïîñëåäîâàòåëüíîñòè %d"
+
+msgid "list constructor does not accept keyword arguments"
+msgstr "Êîíñòðóêòîð ñïèñêà íå äîïóñêàåò êëþ÷åâûå ñëîâà êàê àðãóìåíòû"
+
+msgid "list index out of range"
+msgstr "Èíäåêñ ñïèñêà çà ïðåäåëàìè äèàïàçîíà"
+
+#, c-format
+msgid "internal error: failed to get vim list item %d"
+msgstr "Âíóòðåííÿÿ îøèáêà: íå óäàëîñü ïîëó÷èòü ýëåìåíò VIM-ñïèñêà %d"
+
+msgid "slice step cannot be zero"
+msgstr "Øàã âûáîðêè íå ìîæåò áûòü íóëåâûì"
+
+#, c-format
+msgid "attempt to assign sequence of size greater than %d to extended slice"
+msgstr ""
+"Ïîïûòêà ïðèñâîèòü ïîñëåäîâàòåëüíîñòü ðàçìåðîì áîëüøå ÷åì %d ê ðàñøèðåííîé "
+"âûáîðêå"
+
+#, c-format
+msgid "internal error: no vim list item %d"
+msgstr "Âíóòðåííÿÿ îøèáêà: íåò ýëåìåíòà VIM-ñïèñêà %d"
+
+msgid "internal error: not enough list items"
+msgstr "Âíóòðåííÿÿ îøèáêà: íåäîñòàòî÷íî ýëåìíòîâ ñïèñêà"
+
+msgid "internal error: failed to add item to list"
+msgstr "Âíóòðåííÿÿ îøèáêà: íå óäàëîñü äîáàâèòü ýëåìåíò â ñïèñîê"
+
+#, c-format
+msgid "attempt to assign sequence of size %d to extended slice of size %d"
+msgstr ""
+"Ïîïûòêà ïðèñâîèòü ïîñëåäîâàòåëüíîñòü ðàçìåðîì %d ê ðàñøèðåííîé âûáîðêå "
+"ðàçìåðîì %d"
+
+msgid "failed to add item to list"
+msgstr "Íåâîçìîæíî äîáàâèòü ýëåìåíò â ñïèñîê"
+
+msgid "cannot delete vim.List attributes"
+msgstr "Íåâîçìîæíî óäàëèòü àòðèáóòû vim.List"
+
+msgid "cannot modify fixed list"
+msgstr "Íåâîçìîæíî èçìåíèòü ôèêñèðîâàííûé ñïèñîê"
+
+#, c-format
+msgid "unnamed function %s does not exist"
+msgstr "Íå ñóùåñòâóåò áåçûìÿííîé ôóíêöèè %s"
+
+#, c-format
+msgid "function %s does not exist"
+msgstr "Ôóíêöèÿ %s íå ñóùåñòâóåò"
+
+#, c-format
+msgid "failed to run function %s"
+msgstr "Íåâîçìîæíî âûïîëíèòü ôóíêöèþ %s"
+
+msgid "unable to get option value"
+msgstr "Íåâîçìîæíî ïîëó÷èòü çíà÷åíèå îïöèè"
+
+msgid "internal error: unknown option type"
+msgstr "Âíóòðåííÿÿ îøèáêà: íåèçâåñòíûé òèï îïöèè"
+
+msgid "problem while switching windows"
+msgstr "Ïðîáëåìà ïðè ïåðåêëþ÷åíèè îêîí"
+
+#, c-format
+msgid "unable to unset global option %s"
+msgstr "Íåâîçìîæíî ñáðîñèòü ãëîáàëüíóþ îïöèþ %s"
+
+#, c-format
+msgid "unable to unset option %s which does not have global value"
+msgstr "Íåâîçìîæíî ñáðîñèòü îïöèþ %s áåç ãëîáàëüíîãî çíà÷åíèÿ"
+
+msgid "attempt to refer to deleted tab page"
+msgstr "Ïîïûòêà ñîñëàòüñÿ íà óäàë¸ííóþ âêëàäêó"
+
+msgid "no such tab page"
+msgstr "Íåò òàêîé âêëàäêè"
+
+msgid "attempt to refer to deleted window"
+msgstr "Ïîïûòêà ñîñëàòüñÿ íà çàêðûòîå îêíî"
+
+msgid "readonly attribute: buffer"
+msgstr "Àòðèáóò òîëüêî äëÿ ÷òåíèÿ: áóôåð"
+
+msgid "cursor position outside buffer"
+msgstr "Ïîçèöèÿ êóðñîðà íàõîäèòñÿ âíå áóôåðà"
+
+msgid "no such window"
+msgstr "Íåò òàêîãî îêíà"
+
+msgid "attempt to refer to deleted buffer"
+msgstr "Ïîïûòêà ñîñëàòüñÿ íà óíè÷òîæåííûé áóôåð"
+
+msgid "failed to rename buffer"
+msgstr "Íåâîçìîæíî ïåðåèìåíîâàòü áóôåð"
+
+msgid "mark name must be a single character"
+msgstr "Íàçâàíèå îòìåòêè äîëæíî áûòü îäíèì ñèìâîëîì"
+
+#, c-format
+msgid "expected vim.Buffer object, but got %s"
+msgstr "Îæèäàëñÿ îáúåêò vim.Buffer, íî ïîëó÷åí %s"
+
+#, c-format
+msgid "failed to switch to buffer %d"
+msgstr "Íåâîçìîæíî ïåðåêëþ÷èòüñÿ íà áóôåð %d"
+
+#, c-format
+msgid "expected vim.Window object, but got %s"
+msgstr "Îæèäàëñÿ îáúåêò vim.Window, íî ïîëó÷åí %s"
+
+msgid "failed to find window in the current tab page"
+msgstr "Íåâîçìîæíî íàéòè îêíî â òåêóùåé âêëàäêå"
+
+msgid "did not switch to the specified window"
+msgstr "Íåâîçìîæíî ïåðåêëþ÷èòüñÿ íà óêàçàííîå îêíî"
+
+#, c-format
+msgid "expected vim.TabPage object, but got %s"
+msgstr "Îæèäàëñÿ îáúåêò vim.TabPage, íî ïîëó÷åí %s"
+
+msgid "did not switch to the specified tab page"
+msgstr "Íåâîçìîæíî ïåðåêëþ÷èòüñÿ íà óêàçàííóþ âêëàäêó"
+
+msgid "failed to run the code"
+msgstr "Íåâîçìîæíî âûïîëíèòü êîä"
+
+msgid "E858: Eval did not return a valid python object"
+msgstr "E858: Eval íå âîçâðàòèë äîïóñòèìîãî îáúåêòà Python"
+
+msgid "E859: Failed to convert returned python object to vim value"
+msgstr ""
+"E859: Íå óäàëîñü ïðåîáðàçîâàòü âîçâðàù¸ííûé îáúåêò Python â çíà÷åíèå VIM"
+
+#, c-format
+msgid "unable to convert %s to vim dictionary"
+msgstr "Íåâîçìîæíî ïðåîáðàçîâàòü %s â ñëîâàðü VIM"
+
+#, c-format
+msgid "unable to convert %s to vim list"
+msgstr "Íåâîçìîæíî ïðåîáðàçîâàòü %s â ñïèñîê VIM"
+
+#, c-format
+msgid "unable to convert %s to vim structure"
+msgstr "Íåâîçìîæíî ïðåîáðàçîâàòü %s â ñòðóêòóðó VIM"
+
+msgid "internal error: NULL reference passed"
+msgstr "Âíóòðåííÿÿ îøèáêà: ïåðåäàíà ññûëêà íà NULL"
+
+msgid "internal error: invalid value type"
+msgstr "Âíóòðåííÿÿ îøèáêà: íåïðàâèëüíûé òèï çíà÷åíèÿ"
+
+msgid ""
+"Failed to set path hook: sys.path_hooks is not a list\n"
+"You should now do the following:\n"
+"- append vim.path_hook to sys.path_hooks\n"
+"- append vim.VIM_SPECIAL_PATH to sys.path\n"
+msgstr ""
+"Îøèáêà ïðè óñòàíîâêå ïåðåõâàò÷èêà ïóòè: sys.path_hooks íå ÿâëÿåòñÿ ñïèñêîì\n"
+"Ñëåäóåò ñäåëàòü ñëåäóþùåå:\n"
+"— Äîáàâèòü vim.path_hook â sys.path_hooks\n"
+"— Äîáàâèòü vim.VIM_SPECIAL_PATH â sys.path\n"
+
+msgid ""
+"Failed to set path: sys.path is not a list\n"
+"You should now append vim.VIM_SPECIAL_PATH to sys.path"
+msgstr ""
+"Îøèáêà ïðè óñòàíîâêå ïóòè: sys.path íå ÿâëÿåòñÿ ñïèñêîì\n"
+"Ñëåäóåò äîáàâèòü vim.VIM_SPECIAL_PATH â sys.path"
+
+
diff --git a/src/po/ru.po b/src/po/ru.po
new file mode 100644
index 0000000..dad0d9c
--- /dev/null
+++ b/src/po/ru.po
@@ -0,0 +1,7111 @@
+# Russian translation for Vim
+#
+# Об уÑловиÑÑ… иÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ñ‡Ð¸Ñ‚Ð°Ð¹Ñ‚Ðµ в редакторе Vim ":help uganda"
+#
+# vassily "vr" ragosin <vrr@users.sourceforge.net>, 2004
+# Sergey Alyoshin <alyoshin.s@gmail.com>, 2013-2014, 2016, 2018
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: vim_ru\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2018-04-28 21:50+0300\n"
+"PO-Revision-Date: 2018-04-28 21:51+0300\n"
+"Last-Translator: Sergey Alyoshin <alyoshin.s@gmail.com>\n"
+"Language-Team: \n"
+"Language: Russian\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
+"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
+
+msgid "E831: bf_key_init() called with empty password"
+msgstr "E831: bf_key_init() вызван Ñ Ð¿ÑƒÑтым паролем"
+
+msgid "E820: sizeof(uint32_t) != 4"
+msgstr "E820: sizeof(uint32_t) != 4"
+
+msgid "E817: Blowfish big/little endian use wrong"
+msgstr ""
+"E817: Ðеправильное иÑпользование обратного/прÑмого порÑдка байт в Blowfish"
+
+msgid "E818: sha256 test failed"
+msgstr "E818: Ðе удалоÑÑŒ выполнить теÑÑ‚ sha256"
+
+msgid "E819: Blowfish test failed"
+msgstr "E819: Ðе удалоÑÑŒ выполнить теÑÑ‚ Blowfish"
+
+msgid "[Location List]"
+msgstr "[СпиÑок раÑположений]"
+
+msgid "[Quickfix List]"
+msgstr "[СпиÑок быÑтрых иÑправлений]"
+
+msgid "E855: Autocommands caused command to abort"
+msgstr "E855: Ðвтокоманды вызвали прекращение команды"
+
+msgid "E82: Cannot allocate any buffer, exiting..."
+msgstr "E82: Ðевозможно выделить памÑÑ‚ÑŒ даже Ð´Ð»Ñ Ð¾Ð´Ð½Ð¾Ð³Ð¾ буфера, выход..."
+
+msgid "E83: Cannot allocate buffer, using other one..."
+msgstr "E83: Ðевозможно выделить памÑÑ‚ÑŒ Ð´Ð»Ñ Ð±ÑƒÑ„ÐµÑ€Ð°, иÑпользуем другой буфер..."
+
+msgid "E931: Buffer cannot be registered"
+msgstr "E931: Ðевозможно зарегиÑтрировать буфер"
+
+msgid "E937: Attempt to delete a buffer that is in use"
+msgstr "E937: Попытка удалить иÑпользуемый буфер"
+
+msgid "E515: No buffers were unloaded"
+msgstr "E515: Ðи один буфер не был выгружен из памÑти"
+
+msgid "E516: No buffers were deleted"
+msgstr "E516: Ðи один буфер не был удалён"
+
+msgid "E517: No buffers were wiped out"
+msgstr "E517: Ðи один буфер не был очищен"
+
+msgid "1 buffer unloaded"
+msgstr "Один буфер выгружен из памÑти"
+
+#, c-format
+msgid "%d buffers unloaded"
+msgstr "Ð’Ñего выгружено буферов из памÑти: %d"
+
+msgid "1 buffer deleted"
+msgstr "Один буфер удалён"
+
+#, c-format
+msgid "%d buffers deleted"
+msgstr "Ð’Ñего удалено буферов: %d"
+
+msgid "1 buffer wiped out"
+msgstr "Один буфер очищен"
+
+#, c-format
+msgid "%d buffers wiped out"
+msgstr "Ð’Ñего очищено буферов: %d"
+
+msgid "E90: Cannot unload last buffer"
+msgstr "E90: Ðевозможно выгрузить из памÑти поÑледний буфер"
+
+msgid "E84: No modified buffer found"
+msgstr "E84: Изменённых буферов не обнаружено"
+
+msgid "E85: There is no listed buffer"
+msgstr "E85: Буферы в ÑпиÑке отÑутÑтвуют"
+
+msgid "E87: Cannot go beyond last buffer"
+msgstr "E87: Это поÑледний буфер"
+
+msgid "E88: Cannot go before first buffer"
+msgstr "E88: Это первый буфер"
+
+#, c-format
+msgid "E89: No write since last change for buffer %ld (add ! to override)"
+msgstr ""
+"E89: Ð˜Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð² буфере %ld не Ñохранены (добавьте !, чтобы обойти проверку)"
+
+msgid "E948: Job still running (add ! to end the job)"
+msgstr "E948: Задание ещё выполнÑетÑÑ (добавьте !, чтобы завершить)"
+
+msgid "E37: No write since last change (add ! to override)"
+msgstr "E37: Ð˜Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð½Ðµ Ñохранены (добавьте !, чтобы обойти проверку)"
+
+msgid "E948: Job still running"
+msgstr "E948: Задание ещё выполнÑетÑÑ"
+
+msgid "E37: No write since last change"
+msgstr "E37: Ð˜Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð½Ðµ Ñохранены"
+
+msgid "W14: Warning: List of file names overflow"
+msgstr "W14: Предупреждение: переполнение ÑпиÑка имён файлов"
+
+#, c-format
+msgid "E92: Buffer %ld not found"
+msgstr "E92: Буфер %ld не найден"
+
+#, c-format
+msgid "E93: More than one match for %s"
+msgstr "E93: ÐеÑколько ÑоответÑтвий Ð´Ð»Ñ %s"
+
+#, c-format
+msgid "E94: No matching buffer for %s"
+msgstr "E94: Ðет ÑоответÑтвующего %s буфера"
+
+#, c-format
+msgid "line %ld"
+msgstr "Ñтрока %ld"
+
+msgid "E95: Buffer with this name already exists"
+msgstr "E95: Буфер Ñ Ñ‚Ð°ÐºÐ¸Ð¼ именем уже ÑущеÑтвует"
+
+msgid " [Modified]"
+msgstr " [Изменён]"
+
+msgid "[Not edited]"
+msgstr "[Ðе редактировалÑÑ]"
+
+msgid "[New file]"
+msgstr "[Ðовый файл]"
+
+msgid "[Read errors]"
+msgstr "[Ошибки чтениÑ]"
+
+msgid "[RO]"
+msgstr "[ТЧ]"
+
+msgid "[readonly]"
+msgstr "[только Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ]"
+
+#, c-format
+msgid "1 line --%d%%--"
+msgstr "Одна Ñтрока --%d%%--"
+
+#, c-format
+msgid "%ld lines --%d%%--"
+msgstr "%ld ÑÑ‚Ñ€. --%d%%--"
+
+#, c-format
+msgid "line %ld of %ld --%d%%-- col "
+msgstr "ÑÑ‚Ñ€. %ld из %ld --%d%%-- кол. "
+
+msgid "[No Name]"
+msgstr "[Ðет имени]"
+
+msgid "help"
+msgstr "Ñправка"
+
+msgid "[Help]"
+msgstr "[Справка]"
+
+msgid "[Preview]"
+msgstr "[ПредпроÑмотр]"
+
+msgid "All"
+msgstr "ВеÑÑŒ"
+
+msgid "Bot"
+msgstr "Внизу"
+
+msgid "Top"
+msgstr "Ðаверху"
+
+msgid ""
+"\n"
+"# Buffer list:\n"
+msgstr ""
+"\n"
+"# СпиÑок буферов:\n"
+
+msgid "E382: Cannot write, 'buftype' option is set"
+msgstr ""
+"E382: ЗапиÑÑŒ невозможна, значение опции 'buftype' не ÑвлÑетÑÑ Ð¿ÑƒÑтой Ñтрокой"
+
+msgid "[Scratch]"
+msgstr "[Временный]"
+
+msgid ""
+"\n"
+"--- Signs ---"
+msgstr ""
+"\n"
+"--- Значки ---"
+
+#, c-format
+msgid "Signs for %s:"
+msgstr "Значки Ð´Ð»Ñ %s:"
+
+#, c-format
+msgid " line=%ld id=%d name=%s"
+msgstr " Ñтрока=%ld id=%d имÑ=%s"
+
+msgid "E902: Cannot connect to port"
+msgstr "E902: Ðевозможно ÑоединитьÑÑ Ñ Ð¿Ð¾Ñ€Ñ‚Ð¾Ð¼"
+
+msgid "E901: gethostbyname() in channel_open()"
+msgstr "E901: gethostbyname() в channel_open()"
+
+msgid "E898: socket() in channel_open()"
+msgstr "E898: socket() в channel_open()"
+
+msgid "E903: received command with non-string argument"
+msgstr "E903: Получена команда Ñ Ð½Ðµ Ñтроковым параметром"
+
+msgid "E904: last argument for expr/call must be a number"
+msgstr "E904: ПоÑледний параметр Ð´Ð»Ñ Ð²Ñ‹Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð¸Ð»Ð¸ вызова должен быть чиÑлом"
+
+msgid "E904: third argument for call must be a list"
+msgstr "E904: Третий параметр Ð´Ð»Ñ Ð²Ñ‹Ð·Ð¾Ð²Ð° должен быть ÑпиÑком"
+
+#, c-format
+msgid "E905: received unknown command: %s"
+msgstr "E905: Получена неизвеÑÑ‚Ð½Ð°Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð° %s"
+
+#, c-format
+msgid "E630: %s(): write while not connected"
+msgstr "E630: %s(): запиÑÑŒ без ÑоединениÑ"
+
+#, c-format
+msgid "E631: %s(): write failed"
+msgstr "E631: Ошибка запиÑи в %s()"
+
+#, c-format
+msgid "E917: Cannot use a callback with %s()"
+msgstr "E917: Ðевозможно иÑпользовать обратный вызов Ñ %s()"
+
+msgid "E912: cannot use ch_evalexpr()/ch_sendexpr() with a raw or nl channel"
+msgstr ""
+"E912: Ðевозможно иÑпользовать ch_evalexpr() или ch_sendexpr() Ñ ÐºÐ°Ð½Ð°Ð»Ð¾Ð¼ nl "
+"или raw"
+
+msgid "E906: not an open channel"
+msgstr "E906: Ðе открытый канал"
+
+msgid "E920: _io file requires _name to be set"
+msgstr "E920: Файл _io требует уÑтановленного _name"
+
+msgid "E915: in_io buffer requires in_buf or in_name to be set"
+msgstr "E915: буфер in_io требует уÑтановленного in_buf или in_name"
+
+#, c-format
+msgid "E918: buffer must be loaded: %s"
+msgstr "E918: Буфер должен быть загружен: %s"
+
+msgid "E821: File is encrypted with unknown method"
+msgstr "E821: Файл зашифрован неизвеÑтным методом"
+
+msgid "Warning: Using a weak encryption method; see :help 'cm'"
+msgstr "Предупреждение: ИÑпользуетÑÑ Ñлабый метод шифрованиÑ, Ñм. :help 'cm'"
+
+msgid "Enter encryption key: "
+msgstr "Введите пароль Ð´Ð»Ñ ÑˆÐ¸Ñ„Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ: "
+
+msgid "Enter same key again: "
+msgstr "Повторите ввод паролÑ: "
+
+msgid "Keys don't match!"
+msgstr "Введённые пароли не Ñовпадают!"
+
+msgid "[crypted]"
+msgstr "[зашифровано]"
+
+#, c-format
+msgid "E720: Missing colon in Dictionary: %s"
+msgstr "E720: Пропущено двоеточие в Ñловаре: %s"
+
+#, c-format
+msgid "E721: Duplicate key in Dictionary: \"%s\""
+msgstr "E721: Повтор ключа в Ñловаре: \"%s\""
+
+#, c-format
+msgid "E722: Missing comma in Dictionary: %s"
+msgstr "E722: Пропущена запÑÑ‚Ð°Ñ Ð² Ñловаре: %s"
+
+#, c-format
+msgid "E723: Missing end of Dictionary '}': %s"
+msgstr "E723: Пропущено окончание ÑÐ»Ð¾Ð²Ð°Ñ€Ñ '}': %s"
+
+msgid "extend() argument"
+msgstr "параметра extend()"
+
+#, c-format
+msgid "E737: Key already exists: %s"
+msgstr "E737: Ключ уже ÑущеÑтвует: %s"
+
+#, c-format
+msgid "E96: Cannot diff more than %ld buffers"
+msgstr "E96: Следить за отличиÑми можно не более чем в %ld буферах"
+
+msgid "E810: Cannot read or write temp files"
+msgstr "E810: Ðевозможно прочитать или запиÑать временные файлы"
+
+msgid "E97: Cannot create diffs"
+msgstr "E97: Ðевозможно Ñоздать файлы отличий"
+
+msgid "Patch file"
+msgstr "Файл-заплатка"
+
+msgid "E816: Cannot read patch output"
+msgstr "E816: Ðевозможно прочитать вывод patch"
+
+msgid "E98: Cannot read diff output"
+msgstr "E98: Ðевозможно прочитать вывод diff"
+
+msgid "E99: Current buffer is not in diff mode"
+msgstr "E99: Ðктивный буфер не находитÑÑ Ð² режиме отличий"
+
+msgid "E793: No other buffer in diff mode is modifiable"
+msgstr "E793: Больше нет изменÑемых буферов в режиме отличий"
+
+msgid "E100: No other buffer in diff mode"
+msgstr "E100: Больше нет буферов в режиме отличий"
+
+msgid "E101: More than two buffers in diff mode, don't know which one to use"
+msgstr "E101: В режиме отличий более двух буферов, не могу выбрать"
+
+#, c-format
+msgid "E102: Can't find buffer \"%s\""
+msgstr "E102: Ðе могу найти буфер \"%s\""
+
+#, c-format
+msgid "E103: Buffer \"%s\" is not in diff mode"
+msgstr "E103: Буфер \"%s\" не находитÑÑ Ð² режиме отличий"
+
+msgid "E787: Buffer changed unexpectedly"
+msgstr "E787: Буфер неожиданно изменилÑÑ"
+
+msgid "E104: Escape not allowed in digraph"
+msgstr "E104: Экранирующий Ñимвол Escape Ð½ÐµÐ»ÑŒÐ·Ñ Ð¸Ñпользовать в диграфе"
+
+msgid "E544: Keymap file not found"
+msgstr "E544: Файл Ñ Ñ€Ð°Ñкладкой клавиатуры не найден"
+
+msgid "E105: Using :loadkeymap not in a sourced file"
+msgstr "E105: Команда :loadkeymap применена вне файла ÑценариÑ"
+
+msgid "E791: Empty keymap entry"
+msgstr "E791: пуÑÑ‚Ð°Ñ Ð·Ð°Ð¿Ð¸ÑÑŒ раÑкладки клавиатуры"
+
+msgid " Keyword completion (^N^P)"
+msgstr " Ðвтодополнение ключевого Ñлова (^N^P)"
+
+msgid " ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+msgstr " Режим ^X (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+
+msgid " Whole line completion (^L^N^P)"
+msgstr " Ðвтодополнение целой Ñтроки (^L^N^P)"
+
+msgid " File name completion (^F^N^P)"
+msgstr " Ðвтодополнение имени файла (^F^N^P)"
+
+msgid " Tag completion (^]^N^P)"
+msgstr " Ðвтодополнение метки (^]^N^P)"
+
+msgid " Path pattern completion (^N^P)"
+msgstr " Ðвтодополнение шаблона пути (^N^P)"
+
+msgid " Definition completion (^D^N^P)"
+msgstr " Ðвтодополнение Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ (^D^N^P)"
+
+msgid " Dictionary completion (^K^N^P)"
+msgstr " Ðвтодополнение по Ñловарю (^K^N^P)"
+
+msgid " Thesaurus completion (^T^N^P)"
+msgstr " Ðвтодополнение Ñинонимов (^T^N^P)"
+
+msgid " Command-line completion (^V^N^P)"
+msgstr " Ðвтодополнение командной Ñтроки (^V^N^P)"
+
+msgid " User defined completion (^U^N^P)"
+msgstr " ПользовательÑкое автодополнение (^U^N^P)"
+
+msgid " Omni completion (^O^N^P)"
+msgstr " Omni-дополнение (^O^N^P)"
+
+msgid " Spelling suggestion (s^N^P)"
+msgstr " Предложение иÑÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð°Ð²Ð¾Ð¿Ð¸ÑÐ°Ð½Ð¸Ñ (s^N^P)"
+
+msgid " Keyword Local completion (^N^P)"
+msgstr " МеÑтное автодополнение ключевого Ñлова (^N^P)"
+
+msgid "Hit end of paragraph"
+msgstr "Конец абзаца"
+
+msgid "E839: Completion function changed window"
+msgstr "E839: Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ Ð°Ð²Ñ‚Ð¾Ð´Ð¾Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ð¸Ð·Ð¼ÐµÐ½Ð¸Ð»Ð° окно"
+
+msgid "E840: Completion function deleted text"
+msgstr "E840: Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ Ð°Ð²Ñ‚Ð¾Ð´Ð¾Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ ÑƒÐ´Ð°Ð»Ð¸Ð»Ð° текÑÑ‚"
+
+msgid "'dictionary' option is empty"
+msgstr "Ðе задано значение опции 'dictionary'"
+
+msgid "'thesaurus' option is empty"
+msgstr "Ðе задано значение опции 'thesaurus'"
+
+#, c-format
+msgid "Scanning dictionary: %s"
+msgstr "ПроÑмотр ÑловарÑ: %s"
+
+msgid " (insert) Scroll (^E/^Y)"
+msgstr " (вÑтавка) Прокрутка (^E/^Y)"
+
+msgid " (replace) Scroll (^E/^Y)"
+msgstr " (замена) Прокрутка (^E/^Y)"
+
+#, c-format
+msgid "Scanning: %s"
+msgstr "ПроÑмотр: %s"
+
+msgid "Scanning tags."
+msgstr "ВыполнÑетÑÑ Ð¿Ð¾Ð¸Ñк Ñреди меток."
+
+msgid "match in file"
+msgstr "ÑоответÑтвие в файле"
+
+msgid " Adding"
+msgstr " Добавление"
+
+msgid "-- Searching..."
+msgstr "-- ПоиÑк..."
+
+msgid "Back at original"
+msgstr "ИÑходное Ñлово"
+
+msgid "Word from other line"
+msgstr "Слово из другой Ñтроки"
+
+msgid "The only match"
+msgstr "ЕдинÑтвенное ÑоответÑтвие"
+
+#, c-format
+msgid "match %d of %d"
+msgstr "ÑоответÑтвие %d из %d"
+
+#, c-format
+msgid "match %d"
+msgstr "ÑоответÑтвие %d"
+
+msgid "E18: Unexpected characters in :let"
+msgstr "E18: Ðеожиданные Ñимволы в :let"
+
+#, c-format
+msgid "E121: Undefined variable: %s"
+msgstr "E121: ÐÐµÐ¾Ð¿Ñ€ÐµÐ´ÐµÐ»Ñ‘Ð½Ð½Ð°Ñ Ð¿ÐµÑ€ÐµÐ¼ÐµÐ½Ð½Ð°Ñ: %s"
+
+msgid "E111: Missing ']'"
+msgstr "E111: Пропущена ']'"
+
+msgid "E719: Cannot use [:] with a Dictionary"
+msgstr "E719: Ðевозможно иÑпользовать [:] Ñо Ñловарём"
+
+#, c-format
+msgid "E734: Wrong variable type for %s="
+msgstr "E734: Ðеправильный тип переменной Ð´Ð»Ñ %s="
+
+#, c-format
+msgid "E461: Illegal variable name: %s"
+msgstr "E461: ÐедопуÑтимое Ð¸Ð¼Ñ Ð¿ÐµÑ€ÐµÐ¼ÐµÐ½Ð½Ð¾Ð¹: %s"
+
+msgid "E806: using Float as a String"
+msgstr "E806: ИÑпользование чиÑла Ñ Ð¿Ð»Ð°Ð²Ð°ÑŽÑ‰ÐµÐ¹ точкой как Ñтроки"
+
+msgid "E687: Less targets than List items"
+msgstr "E687: Целей меньше чем Ñлементов ÑпиÑка"
+
+msgid "E688: More targets than List items"
+msgstr "E688: Целей больше чем Ñлементов ÑпиÑка"
+
+msgid "Double ; in list of variables"
+msgstr "Ð”Ð²Ð¾Ð¹Ð½Ð°Ñ ; в ÑпиÑке переменных"
+
+#, c-format
+msgid "E738: Can't list variables for %s"
+msgstr "E738: Ðевозможно отобразить переменные Ð´Ð»Ñ %s"
+
+msgid "E689: Can only index a List or Dictionary"
+msgstr "E689: ИндекÑирование возможно только ÑпиÑка или ÑловарÑ"
+
+msgid "E708: [:] must come last"
+msgstr "E708: [:] должно быть поÑледним"
+
+msgid "E709: [:] requires a List value"
+msgstr "E709: [:] требует значением ÑпиÑок"
+
+msgid "E710: List value has more items than target"
+msgstr "E710: Элементов ÑпиÑка-Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð±Ð¾Ð»ÑŒÑˆÐµ чем в цели"
+
+msgid "E711: List value has not enough items"
+msgstr "E711: СпиÑок-значение не Ñодержит доÑтаточно Ñлементов"
+
+msgid "E690: Missing \"in\" after :for"
+msgstr "E690: Пропущено \"in\" поÑле :for"
+
+#, c-format
+msgid "E108: No such variable: \"%s\""
+msgstr "E108: Ðет такой переменной: \"%s\""
+
+#, c-format
+msgid "E940: Cannot lock or unlock variable %s"
+msgstr "E940: Ðевозможно (раз)блокировать переменную %s"
+
+msgid "E743: variable nested too deep for (un)lock"
+msgstr "E743: Слишком глубоко вложенные переменные Ð´Ð»Ñ (раз)блокировки"
+
+msgid "E109: Missing ':' after '?'"
+msgstr "E109: Пропущено ':' поÑле '?'"
+
+msgid "E804: Cannot use '%' with Float"
+msgstr "E804: Ðевозможно иÑпользовать '%' Ñ Ñ‡Ð¸Ñлом Ñ Ð¿Ð»Ð°Ð²Ð°ÑŽÑ‰ÐµÐ¹ точкой"
+
+msgid "E110: Missing ')'"
+msgstr "E110: Пропущена ')'"
+
+msgid "E695: Cannot index a Funcref"
+msgstr "E695: Ðевозможно индекÑировать ÑÑылку на функцию"
+
+msgid "E909: Cannot index a special variable"
+msgstr "E909: Ðевозможно индекÑировать Ñпециальную переменную"
+
+#, c-format
+msgid "E112: Option name missing: %s"
+msgstr "E112: Ðе указано Ð¸Ð¼Ñ Ð¾Ð¿Ñ†Ð¸Ð¸: %s"
+
+#, c-format
+msgid "E113: Unknown option: %s"
+msgstr "E113: ÐеизвеÑÑ‚Ð½Ð°Ñ Ð¾Ð¿Ñ†Ð¸Ñ: %s"
+
+#, c-format
+msgid "E114: Missing quote: %s"
+msgstr "E114: Пропущена кавычка: %s"
+
+#, c-format
+msgid "E115: Missing quote: %s"
+msgstr "E115: Пропущена кавычка: %s"
+
+msgid "Not enough memory to set references, garbage collection aborted!"
+msgstr "ÐедоÑтаточно памÑти Ð´Ð»Ñ ÑƒÑтановки ÑÑылки, Ñборка муÑора прекращена!"
+
+msgid "E724: variable nested too deep for displaying"
+msgstr "E724: Слишком глубоко вложенные переменные Ð´Ð»Ñ Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ"
+
+msgid "E805: Using a Float as a Number"
+msgstr "E805: ИÑпользование чиÑла Ñ Ð¿Ð»Ð°Ð²Ð°ÑŽÑ‰ÐµÐ¹ точкой как целого"
+
+msgid "E703: Using a Funcref as a Number"
+msgstr "E703: ИÑпользование ÑÑылки на функцию как чиÑла"
+
+msgid "E745: Using a List as a Number"
+msgstr "E745: ИÑпользование ÑпиÑка как чиÑла"
+
+msgid "E728: Using a Dictionary as a Number"
+msgstr "E728: ИÑпользование ÑÐ»Ð¾Ð²Ð°Ñ€Ñ ÐºÐ°Ðº чиÑла"
+
+msgid "E910: Using a Job as a Number"
+msgstr "E910: ИÑпользование Ð·Ð°Ð´Ð°Ð½Ð¸Ñ ÐºÐ°Ðº чиÑла"
+
+msgid "E913: Using a Channel as a Number"
+msgstr "E913: ИÑпользование канала как чиÑла"
+
+msgid "E891: Using a Funcref as a Float"
+msgstr "E891: ИÑпользование ÑÑылки на функцию как чиÑла Ñ Ð¿Ð»Ð°Ð²Ð°ÑŽÑ‰ÐµÐ¹ точкой"
+
+msgid "E892: Using a String as a Float"
+msgstr "E892: ИÑпользование Ñтроки как чиÑла Ñ Ð¿Ð»Ð°Ð²Ð°ÑŽÑ‰ÐµÐ¹ точкой"
+
+msgid "E893: Using a List as a Float"
+msgstr "E893: ИÑпользование ÑпиÑка как чиÑла Ñ Ð¿Ð»Ð°Ð²Ð°ÑŽÑ‰ÐµÐ¹ точкой"
+
+msgid "E894: Using a Dictionary as a Float"
+msgstr "E894: ИÑпользование ÑÐ»Ð¾Ð²Ð°Ñ€Ñ ÐºÐ°Ðº чиÑла Ñ Ð¿Ð»Ð°Ð²Ð°ÑŽÑ‰ÐµÐ¹ точкой"
+
+msgid "E907: Using a special value as a Float"
+msgstr "E907: ИÑпользование Ñпециального Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ ÐºÐ°Ðº чиÑла Ñ Ð¿Ð»Ð°Ð²Ð°ÑŽÑ‰ÐµÐ¹ точкой"
+
+msgid "E911: Using a Job as a Float"
+msgstr "E911: ИÑпользование Ð·Ð°Ð´Ð°Ð½Ð¸Ñ ÐºÐ°Ðº чиÑла Ñ Ð¿Ð»Ð°Ð²Ð°ÑŽÑ‰ÐµÐ¹ точкой"
+
+msgid "E914: Using a Channel as a Float"
+msgstr "E914: ИÑпользование канала как чиÑла Ñ Ð¿Ð»Ð°Ð²Ð°ÑŽÑ‰ÐµÐ¹ точкой"
+
+msgid "E729: using Funcref as a String"
+msgstr "E729: ИÑпользование ÑÑылки на функцию как Ñтроки"
+
+msgid "E730: using List as a String"
+msgstr "E730: ИÑпользование ÑпиÑка как Ñтроки"
+
+msgid "E731: using Dictionary as a String"
+msgstr "E731: ИÑпользование ÑÐ»Ð¾Ð²Ð°Ñ€Ñ ÐºÐ°Ðº Ñтроки"
+
+msgid "E908: using an invalid value as a String"
+msgstr "E908: ИÑпользование неправильного Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ ÐºÐ°Ðº Ñтроки"
+
+#, c-format
+msgid "E795: Cannot delete variable %s"
+msgstr "E795: Ðевозможно удалить переменную %s"
+
+#, c-format
+msgid "E704: Funcref variable name must start with a capital: %s"
+msgstr ""
+"E704: Ð˜Ð¼Ñ Ð¿ÐµÑ€ÐµÐ¼ÐµÐ½Ð½Ð¾Ð¹ ÑÑылки на функцию должно начинатьÑÑ Ñ Ð·Ð°Ð³Ð»Ð°Ð²Ð½Ð¾Ð¹ буквы: "
+"%s"
+
+#, c-format
+msgid "E705: Variable name conflicts with existing function: %s"
+msgstr "E705: Ð˜Ð¼Ñ Ð¿ÐµÑ€ÐµÐ¼ÐµÐ½Ð½Ð¾Ð¹ конфликтует Ñ ÑущеÑтвующей функцией: %s"
+
+#, c-format
+msgid "E741: Value is locked: %s"
+msgstr "E741: Значение %s заблокировано"
+
+msgid "Unknown"
+msgstr "ÐеизвеÑтно"
+
+#, c-format
+msgid "E742: Cannot change value of %s"
+msgstr "E742: Ðевозможно изменить значение %s"
+
+msgid "E698: variable nested too deep for making a copy"
+msgstr "E698: Слишком глубоко вложенные переменные Ð´Ð»Ñ ÐºÐ¾Ð¿Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ"
+
+msgid ""
+"\n"
+"# global variables:\n"
+msgstr ""
+"\n"
+"# глобальные переменные:\n"
+
+msgid ""
+"\n"
+"\tLast set from "
+msgstr ""
+"\n"
+"\tÐ’ поÑледний раз Ð¾Ð¿Ñ†Ð¸Ñ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð° в "
+
+msgid "E691: Can only compare List with List"
+msgstr "E691: СпиÑок можно Ñравнивать только Ñо ÑпиÑком"
+
+msgid "E692: Invalid operation for List"
+msgstr "E692: ÐедопуÑÑ‚Ð¸Ð¼Ð°Ñ Ð¾Ð¿ÐµÑ€Ð°Ñ†Ð¸Ñ Ð´Ð»Ñ ÑпиÑков"
+
+msgid "E735: Can only compare Dictionary with Dictionary"
+msgstr "E735: Словарь можно Ñравнивать только Ñо Ñловарём"
+
+msgid "E736: Invalid operation for Dictionary"
+msgstr "E736: ÐедопуÑÑ‚Ð¸Ð¼Ð°Ñ Ð¾Ð¿ÐµÑ€Ð°Ñ†Ð¸Ñ Ð´Ð»Ñ ÑловарÑ"
+
+msgid "E694: Invalid operation for Funcrefs"
+msgstr "E694: ÐедопуÑÑ‚Ð¸Ð¼Ð°Ñ Ð¾Ð¿ÐµÑ€Ð°Ñ†Ð¸Ñ Ð´Ð»Ñ ÑÑылки на функцию"
+
+msgid "map() argument"
+msgstr "параметра map()"
+
+msgid "filter() argument"
+msgstr "параметра filter()"
+
+#, c-format
+msgid "E686: Argument of %s must be a List"
+msgstr "E686: Параметр %s должен быть ÑпиÑком"
+
+msgid "E928: String required"
+msgstr "E928: ТребуетÑÑ Ñтрока"
+
+msgid "E808: Number or Float required"
+msgstr "E808: ТребуетÑÑ Ñ†ÐµÐ»Ð¾Ðµ чиÑло или Ñ Ð¿Ð»Ð°Ð²Ð°ÑŽÑ‰ÐµÐ¹ точкой"
+
+msgid "add() argument"
+msgstr "параметра add()"
+
+msgid "E785: complete() can only be used in Insert mode"
+msgstr "E785: complete() может иÑпользоватьÑÑ Ñ‚Ð¾Ð»ÑŒÐºÐ¾ в режиме Ð’Ñтавки"
+
+msgid "&Ok"
+msgstr "&Ok"
+
+#, c-format
+msgid "+-%s%3ld line: "
+msgid_plural "+-%s%3ld lines: "
+msgstr[0] "+-%s%3ld Ñтрока: "
+msgstr[1] "+-%s%3ld Ñтроки: "
+msgstr[2] "+-%s%3ld Ñтрок: "
+
+#, c-format
+msgid "E700: Unknown function: %s"
+msgstr "E700: ÐеизвеÑÑ‚Ð½Ð°Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ: %s"
+
+msgid "E922: expected a dict"
+msgstr "E922: ОжидалÑÑ Ñловарь"
+
+msgid "E923: Second argument of function() must be a list or a dict"
+msgstr "E923: Второй параметр функции() должен быть ÑпиÑком или Ñловарём"
+
+msgid ""
+"&OK\n"
+"&Cancel"
+msgstr ""
+"&OK\n"
+"&C Отмена"
+
+msgid "called inputrestore() more often than inputsave()"
+msgstr "Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ inputrestore() вызываетÑÑ Ñ‡Ð°Ñ‰Ðµ, чем Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ inputsave()"
+
+msgid "insert() argument"
+msgstr "параметра insert()"
+
+msgid "E786: Range not allowed"
+msgstr "E786: Диапазон не допуÑкаетÑÑ"
+
+msgid "E916: not a valid job"
+msgstr "E916: ÐедопуÑтимое задание"
+
+msgid "E701: Invalid type for len()"
+msgstr "E701: Ðеправильные тип Ð´Ð»Ñ len()"
+
+#, c-format
+msgid "E798: ID is reserved for \":match\": %ld"
+msgstr "E798: ID зарезервирован Ð´Ð»Ñ \":match\": %ld"
+
+msgid "E726: Stride is zero"
+msgstr "E726: Ðулевой шаг"
+
+msgid "E727: Start past end"
+msgstr "E727: Ðачало поÑле конца"
+
+msgid "<empty>"
+msgstr "<пуÑто>"
+
+msgid "E240: No connection to the X server"
+msgstr "E240: Ðет ÑвÑзи Ñ X-Ñервером"
+
+#, c-format
+msgid "E241: Unable to send to %s"
+msgstr "E241: Ðе могу отправить Ñообщение Ð´Ð»Ñ %s"
+
+msgid "E277: Unable to read a server reply"
+msgstr "E277: Сервер не отвечает"
+
+msgid "E941: already started a server"
+msgstr "E941: Сервер уже запущен"
+
+msgid "E942: +clientserver feature not available"
+msgstr "E942: ОÑобенноÑÑ‚ÑŒ +clientserver недоÑтупна"
+
+msgid "remove() argument"
+msgstr "параметра remove()"
+
+msgid "E655: Too many symbolic links (cycle?)"
+msgstr "E655: Слишком много ÑимволичеÑких ÑÑылок (цикл?)"
+
+msgid "reverse() argument"
+msgstr "параметра reverse()"
+
+msgid "E258: Unable to send to client"
+msgstr "E258: Ðе могу ответить клиенту"
+
+#, c-format
+msgid "E927: Invalid action: '%s'"
+msgstr "E927: Ðеправильное дейÑтвие: '%s'"
+
+msgid "sort() argument"
+msgstr "параметра sort()"
+
+msgid "uniq() argument"
+msgstr "параметра uniq()"
+
+msgid "E702: Sort compare function failed"
+msgstr "E702: Ðеудачное завершение функции ÑÑ€Ð°Ð²Ð½ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¸ Ñортировке"
+
+msgid "E882: Uniq compare function failed"
+msgstr ""
+"E882: Ðеудачное завершение функции ÑÑ€Ð°Ð²Ð½ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¸ проверке единÑтвенноÑти"
+
+msgid "(Invalid)"
+msgstr "(Ðеправильно)"
+
+#, c-format
+msgid "E935: invalid submatch number: %d"
+msgstr "E935: ÐедопуÑтимый номер подÑоответÑтвиÑ: %d"
+
+msgid "E677: Error writing temp file"
+msgstr "E677: Ошибка запиÑи во временный файл"
+
+msgid "E921: Invalid callback argument"
+msgstr "E921: ÐедопуÑтимый параметр обратного вызова"
+
+#, c-format
+msgid "<%s>%s%s %d, Hex %02x, Oct %03o, Digr %s"
+msgstr "<%s>%s%s %d, Ð¨ÐµÑ %02x, Ð’Ð¾Ñ %03o, Дигр %s"
+
+#, c-format
+msgid "<%s>%s%s %d, Hex %02x, Octal %03o"
+msgstr "<%s>%s%s %d, Ð¨ÐµÑ %02x, Ð’Ð¾Ñ %03o"
+
+#, c-format
+msgid "> %d, Hex %04x, Oct %o, Digr %s"
+msgstr "> %d, Ð¨ÐµÑ %04x, Ð’Ð¾Ñ %o, Дигр %s"
+
+#, c-format
+msgid "> %d, Hex %08x, Oct %o, Digr %s"
+msgstr "> %d, Ð¨ÐµÑ %08x, Ð’Ð¾Ñ %o, Дигр %s"
+
+#, c-format
+msgid "> %d, Hex %04x, Octal %o"
+msgstr "> %d, Ð¨ÐµÑ %04x, Ð’Ð¾Ñ %o"
+
+#, c-format
+msgid "> %d, Hex %08x, Octal %o"
+msgstr "> %d, Ð¨ÐµÑ %08x, Ð’Ð¾Ñ %o"
+
+msgid "E134: Move lines into themselves"
+msgstr "E134: Строки перемещаютÑÑ Ñами на ÑебÑ"
+
+msgid "1 line moved"
+msgstr "Перемещена одна Ñтрока"
+
+#, c-format
+msgid "%ld lines moved"
+msgstr "Перемещено Ñтрок: %ld"
+
+#, c-format
+msgid "%ld lines filtered"
+msgstr "Пропущено через фильтр Ñтрок: %ld"
+
+msgid "E135: *Filter* Autocommands must not change current buffer"
+msgstr "E135: Ðвтокоманды *Filter* не должны изменÑÑ‚ÑŒ активный буфер"
+
+msgid "[No write since last change]\n"
+msgstr "[Ð˜Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð½Ðµ Ñохранены]\n"
+
+#, c-format
+msgid "%sviminfo: %s in line: "
+msgstr "%sviminfo: %s в Ñтроке: "
+
+msgid "E136: viminfo: Too many errors, skipping rest of file"
+msgstr ""
+"E136: viminfo: Слишком много ошибок, оÑÑ‚Ð°Ð»ÑŒÐ½Ð°Ñ Ñ‡Ð°ÑÑ‚ÑŒ файла будет пропущена"
+
+#, c-format
+msgid "Reading viminfo file \"%s\"%s%s%s"
+msgstr "Чтение файла viminfo \"%s\"%s%s%s"
+
+msgid " info"
+msgstr " инфо"
+
+msgid " marks"
+msgstr " отметок"
+
+msgid " oldfiles"
+msgstr " Ñтарых файлов"
+
+msgid " FAILED"
+msgstr " ÐЕУДÐЧÐО"
+
+#, c-format
+msgid "E137: Viminfo file is not writable: %s"
+msgstr "E137: Права на запиÑÑŒ файла viminfo отÑутÑтвуют: %s"
+
+#, c-format
+msgid "E929: Too many viminfo temp files, like %s!"
+msgstr "E929: Слишком много временных файлов viminfo, таких как %s"
+
+#, c-format
+msgid "E138: Can't write viminfo file %s!"
+msgstr "E138: Ðевозможно запиÑать файл viminfo %s!"
+
+#, c-format
+msgid "Writing viminfo file \"%s\""
+msgstr "ЗапиÑÑŒ файла viminfo \"%s\""
+
+#, c-format
+msgid "E886: Can't rename viminfo file to %s!"
+msgstr "E886: Ðевозможно переименовать файл viminfo в %s!"
+
+#, c-format
+msgid "# This viminfo file was generated by Vim %s.\n"
+msgstr "# Этот файл viminfo автоматичеÑки Ñоздан Vim %s.\n"
+
+msgid ""
+"# You may edit it if you're careful!\n"
+"\n"
+msgstr ""
+"# Его можно (оÑторожно!) редактировать.\n"
+"\n"
+
+msgid "# Value of 'encoding' when this file was written\n"
+msgstr "# Значение опции 'encoding' в момент запиÑи файла\n"
+
+msgid "Illegal starting char"
+msgstr "ÐедопуÑтимый начальный Ñимвол"
+
+msgid ""
+"\n"
+"# Bar lines, copied verbatim:\n"
+msgstr ""
+"\n"
+"# Строк Ñ '|', точно Ñкопировано:\n"
+
+msgid "Save As"
+msgstr "Сохранить как"
+
+msgid "Write partial file?"
+msgstr "ЗапиÑать файл чаÑтично?"
+
+msgid "E140: Use ! to write partial buffer"
+msgstr "E140: Ð”Ð»Ñ Ð·Ð°Ð¿Ð¸Ñи чаÑти буфера иÑпользуйте !"
+
+#, c-format
+msgid "Overwrite existing file \"%s\"?"
+msgstr "ПерезапиÑать ÑущеÑтвующий файл \"%s\"?"
+
+#, c-format
+msgid "Swap file \"%s\" exists, overwrite anyway?"
+msgstr "Своп-файл \"%s\" ÑущеÑтвует, перезапиÑать?"
+
+#, c-format
+msgid "E768: Swap file exists: %s (:silent! overrides)"
+msgstr "E768: Своп-файл ÑущеÑтвует: %s (:silent! чтобы обойти проверку)"
+
+#, c-format
+msgid "E141: No file name for buffer %ld"
+msgstr "E141: Буфер %ld не ÑвÑзан Ñ Ð¸Ð¼ÐµÐ½ÐµÐ¼ файла"
+
+msgid "E142: File not written: Writing is disabled by 'write' option"
+msgstr "E142: Файл не Ñохранён: запиÑÑŒ отключена опцией 'write'"
+
+#, c-format
+msgid ""
+"'readonly' option is set for \"%s\".\n"
+"Do you wish to write anyway?"
+msgstr ""
+"Ð”Ð»Ñ \"%s\" включена Ð¾Ð¿Ñ†Ð¸Ñ 'readonly'.\n"
+"ЗапиÑать?"
+
+#, c-format
+msgid ""
+"File permissions of \"%s\" are read-only.\n"
+"It may still be possible to write it.\n"
+"Do you wish to try?"
+msgstr ""
+"Файл \"%s\" имеет режим доÑтупа только Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ.\n"
+"Ðо, возможно, файл удаÑÑ‚ÑÑ Ð·Ð°Ð¿Ð¸Ñать.\n"
+"Хотите попробовать?"
+
+#, c-format
+msgid "E505: \"%s\" is read-only (add ! to override)"
+msgstr ""
+"E505: \"%s\" открыт только Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ (добавьте !, чтобы обойти проверку)"
+
+msgid "Edit File"
+msgstr "Редактирование файла"
+
+#, c-format
+msgid "E143: Autocommands unexpectedly deleted new buffer %s"
+msgstr "E143: Ðвтокоманды неожиданно убили новый буфер %s"
+
+msgid "E144: non-numeric argument to :z"
+msgstr "E144: Параметр команды :z должен быть чиÑлом"
+
+msgid "E145: Shell commands not allowed in rvim"
+msgstr "E145: ИÑпользование команд оболочки не допуÑкаетÑÑ Ð² rvim."
+
+msgid "E146: Regular expressions can't be delimited by letters"
+msgstr "E146: РегулÑрные Ð²Ñ‹Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð½Ðµ могут разделÑÑ‚ÑŒÑÑ Ð±ÑƒÐºÐ²Ð°Ð¼Ð¸"
+
+#, c-format
+msgid "replace with %s (y/n/a/q/l/^E/^Y)?"
+msgstr "заменить на %s? (y/n/a/q/l/^E/^Y)"
+
+msgid "(Interrupted) "
+msgstr "(Прервано)"
+
+msgid "1 match"
+msgstr "Одно ÑоответÑтвие"
+
+msgid "1 substitution"
+msgstr "Одна замена"
+
+#, c-format
+msgid "%ld matches"
+msgstr "%ld ÑоответÑтвий"
+
+#, c-format
+msgid "%ld substitutions"
+msgstr "%ld замен"
+
+msgid " on 1 line"
+msgstr " в 1 ÑÑ‚Ñ€."
+
+#, c-format
+msgid " on %ld lines"
+msgstr " в %ld ÑÑ‚Ñ€."
+
+msgid "E147: Cannot do :global recursive with a range"
+msgstr "E147: Ðевозможно выполнить :global рекурÑивно Ñ Ð´Ð¸Ð°Ð¿Ð°Ð·Ð¾Ð½Ð¾Ð¼"
+
+msgid "E148: Regular expression missing from global"
+msgstr "E148: Ð’ команде :global пропущено регулÑрное выражение"
+
+#, c-format
+msgid "Pattern found in every line: %s"
+msgstr "СоответÑтвие шаблону найдено на каждой Ñтроке: %s"
+
+#, c-format
+msgid "Pattern not found: %s"
+msgstr "Шаблон не найден: %s"
+
+msgid ""
+"\n"
+"# Last Substitute String:\n"
+"$"
+msgstr ""
+"\n"
+"# ПоÑледнÑÑ Ñтрока Ð´Ð»Ñ Ð·Ð°Ð¼ÐµÐ½Ñ‹:\n"
+"$"
+
+msgid "E478: Don't panic!"
+msgstr "E478: СпокойÑтвие, только ÑпокойÑтвие!"
+
+#, c-format
+msgid "E661: Sorry, no '%s' help for %s"
+msgstr "E661: К Ñожалению, Ñправка '%s' Ð´Ð»Ñ %s отÑутÑтвует"
+
+#, c-format
+msgid "E149: Sorry, no help for %s"
+msgstr "E149: К Ñожалению Ñправка Ð´Ð»Ñ %s отÑутÑтвует"
+
+#, c-format
+msgid "Sorry, help file \"%s\" not found"
+msgstr "Извините, файл Ñправки \"%s\" не найден"
+
+#, c-format
+msgid "E151: No match: %s"
+msgstr "E151: Ðет ÑоответÑтвиÑ: %s"
+
+#, c-format
+msgid "E152: Cannot open %s for writing"
+msgstr "E152: Ðевозможно открыть %s Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñи"
+
+#, c-format
+msgid "E153: Unable to open %s for reading"
+msgstr "E153: Ðевозможно открыть %s Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ"
+
+#, c-format
+msgid "E670: Mix of help file encodings within a language: %s"
+msgstr "E670: Файлы Ñправки иÑпользуют разные кодировки Ð´Ð»Ñ Ð¾Ð´Ð½Ð¾Ð³Ð¾ Ñзыка: %s"
+
+#, c-format
+msgid "E154: Duplicate tag \"%s\" in file %s/%s"
+msgstr "E154: ПовторÑющаÑÑÑ Ð¼ÐµÑ‚ÐºÐ° \"%s\" в файле %s/%s"
+
+#, c-format
+msgid "E150: Not a directory: %s"
+msgstr "E150: %s не ÑвлÑетÑÑ ÐºÐ°Ñ‚Ð°Ð»Ð¾Ð³Ð¾Ð¼"
+
+#, c-format
+msgid "E160: Unknown sign command: %s"
+msgstr "E160: ÐеизвеÑÑ‚Ð½Ð°Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð° значка %s"
+
+msgid "E156: Missing sign name"
+msgstr "E156: Пропущено Ð¸Ð¼Ñ Ð·Ð½Ð°Ñ‡ÐºÐ°"
+
+msgid "E612: Too many signs defined"
+msgstr "E612: Определено Ñлишком много значков"
+
+#, c-format
+msgid "E239: Invalid sign text: %s"
+msgstr "E239: Ðеправильный текÑÑ‚ значка: %s"
+
+#, c-format
+msgid "E155: Unknown sign: %s"
+msgstr "E155: ÐеизвеÑтный значок: %s"
+
+msgid "E159: Missing sign number"
+msgstr "E159: Пропущен номер значка"
+
+#, c-format
+msgid "E158: Invalid buffer name: %s"
+msgstr "E158: Ðеправильное Ð¸Ð¼Ñ Ð±ÑƒÑ„ÐµÑ€Ð°: %s"
+
+msgid "E934: Cannot jump to a buffer that does not have a name"
+msgstr "E934: Ðевозможно перейти к буферу без имени"
+
+#, c-format
+msgid "E157: Invalid sign ID: %ld"
+msgstr "E157: Ðеправильный ID значка: %ld"
+
+#, c-format
+msgid "E885: Not possible to change sign %s"
+msgstr "E885: Ðевозможно изменить значок %s"
+
+msgid " (NOT FOUND)"
+msgstr " (ÐЕ ÐÐЙДЕÐО)"
+
+msgid " (not supported)"
+msgstr " (не поддерживаетÑÑ)"
+
+msgid "[Deleted]"
+msgstr "[Удалено]"
+
+msgid "No old files"
+msgstr "Ðет Ñтарых файлов"
+
+msgid "Entering Debug mode. Type \"cont\" to continue."
+msgstr "Включён режим отладки. Ð”Ð»Ñ Ð¿Ñ€Ð¾Ð´Ð¾Ð»Ð¶ÐµÐ½Ð¸Ñ Ð½Ð°Ð±ÐµÑ€Ð¸Ñ‚Ðµ \"cont\""
+
+#, c-format
+msgid "Oldval = \"%s\""
+msgstr "Преж.зн. = \"%s\""
+
+#, c-format
+msgid "Newval = \"%s\""
+msgstr "Ðов.зн. = \"%s\""
+
+#, c-format
+msgid "line %ld: %s"
+msgstr "Ñтрока %ld: %s"
+
+#, c-format
+msgid "cmd: %s"
+msgstr "команда: %s"
+
+msgid "frame is zero"
+msgstr "нулевой фрейм"
+
+#, c-format
+msgid "frame at highest level: %d"
+msgstr "макÑимальный фрейм: %d"
+
+#, c-format
+msgid "Breakpoint in \"%s%s\" line %ld"
+msgstr "Точка оÑтановки в \"%s%s\" ÑÑ‚Ñ€. %ld"
+
+#, c-format
+msgid "E161: Breakpoint not found: %s"
+msgstr "E161: Точка оÑтановки не найдена: %s"
+
+msgid "No breakpoints defined"
+msgstr "Точки оÑтановки не определены"
+
+#, c-format
+msgid "%3d %s %s line %ld"
+msgstr "%3d %s %s ÑÑ‚Ñ€. %ld"
+
+#, c-format
+msgid "%3d expr %s"
+msgstr "%3d выр. %s"
+
+msgid "E750: First use \":profile start {fname}\""
+msgstr "E750: Первое иÑпользование \":profile start {имÑ-файла}\""
+
+#, c-format
+msgid "Save changes to \"%s\"?"
+msgstr "Сохранить Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð² \"%s\"?"
+
+#, c-format
+msgid "E947: Job still running in buffer \"%s\""
+msgstr "E947: Задание ещё выполнÑетÑÑ Ð² буфере \"%s\""
+
+#, c-format
+msgid "E162: No write since last change for buffer \"%s\""
+msgstr "E162: ÐеÑохранённые Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð² буфере \"%s\""
+
+msgid "Warning: Entered other buffer unexpectedly (check autocommands)"
+msgstr ""
+"Предупреждение: Ðеожиданный переход в другой буфер (проверьте автокоманды)"
+
+msgid "E163: There is only one file to edit"
+msgstr "E163: Ð”Ð»Ñ Ñ€ÐµÐ´Ð°ÐºÑ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð´Ð¾Ñтупен только один файл"
+
+msgid "E164: Cannot go before first file"
+msgstr "E164: Это первый файл"
+
+msgid "E165: Cannot go beyond last file"
+msgstr "E165: Это поÑледний файл"
+
+#, c-format
+msgid "E666: compiler not supported: %s"
+msgstr "E666: КомпилÑтор не поддерживаетÑÑ: %s"
+
+#, c-format
+msgid "Searching for \"%s\" in \"%s\""
+msgstr "ПоиÑк \"%s\" в \"%s\""
+
+#, c-format
+msgid "Searching for \"%s\""
+msgstr "ПоиÑк \"%s\""
+
+#, c-format
+msgid "not found in '%s': \"%s\""
+msgstr "не найдено в '%s': \"%s\""
+
+#, c-format
+msgid "W20: Required python version 2.x not supported, ignoring file: %s"
+msgstr ""
+"W20: Ðе поддерживаетÑÑ python требуемой верÑии 2.x, файл проигнорирован: %s"
+
+#, c-format
+msgid "W21: Required python version 3.x not supported, ignoring file: %s"
+msgstr ""
+"W21: Ðе поддерживаетÑÑ python требуемой верÑии 3.x, файл проигнорирован: %s"
+
+msgid "Source Vim script"
+msgstr "Выполнить Ñценарий Vim"
+
+#, c-format
+msgid "Cannot source a directory: \"%s\""
+msgstr "ÐÐµÐ»ÑŒÐ·Ñ Ñчитать каталог: \"%s\""
+
+#, c-format
+msgid "could not source \"%s\""
+msgstr "невозможно Ñчитать \"%s\""
+
+#, c-format
+msgid "line %ld: could not source \"%s\""
+msgstr "Ñтрока %ld: невозможно Ñчитать \"%s\""
+
+#, c-format
+msgid "sourcing \"%s\""
+msgstr "Ñчитывание ÑÑ†ÐµÐ½Ð°Ñ€Ð¸Ñ \"%s\""
+
+#, c-format
+msgid "line %ld: sourcing \"%s\""
+msgstr "Ñтрока %ld: Ñчитывание \"%s\""
+
+#, c-format
+msgid "finished sourcing %s"
+msgstr "Ñчитывание ÑÑ†ÐµÐ½Ð°Ñ€Ð¸Ñ %s завершено"
+
+#, c-format
+msgid "continuing in %s"
+msgstr "продолжение в %s"
+
+msgid "modeline"
+msgstr "Ñ€ÐµÐ¶Ð¸Ð¼Ð½Ð°Ñ Ñтрока"
+
+msgid "--cmd argument"
+msgstr "--cmd параметр"
+
+msgid "-c argument"
+msgstr "-c параметр"
+
+msgid "environment variable"
+msgstr "Ð¿ÐµÑ€ÐµÐ¼ÐµÐ½Ð½Ð°Ñ Ð¾ÐºÑ€ÑƒÐ¶ÐµÐ½Ð¸Ñ"
+
+msgid "error handler"
+msgstr "обработчик ошибки"
+
+msgid "W15: Warning: Wrong line separator, ^M may be missing"
+msgstr ""
+"W15: Предупреждение: неправильный разделитель Ñтроки. Возможно пропущено ^M"
+
+msgid "E167: :scriptencoding used outside of a sourced file"
+msgstr "E167: Команда :scriptencoding иÑпользуетÑÑ Ð²Ð½Ðµ файла ÑценариÑ"
+
+msgid "E168: :finish used outside of a sourced file"
+msgstr "E168: Команда :finish иÑпользуетÑÑ Ð²Ð½Ðµ файла ÑценариÑ"
+
+#, c-format
+msgid "Current %slanguage: \"%s\""
+msgstr "Ðктивный %sÑзык: \"%s\""
+
+#, c-format
+msgid "E197: Cannot set language to \"%s\""
+msgstr "E197: Ðевозможно Ñменить Ñзык на \"%s\""
+
+msgid "Entering Ex mode. Type \"visual\" to go to Normal mode."
+msgstr "Переход в режим Ex. Ð”Ð»Ñ Ð¿ÐµÑ€ÐµÑ…Ð¾Ð´Ð° в Обычный режим наберите \"visual\""
+
+msgid "E501: At end-of-file"
+msgstr "E501: В конце файла"
+
+msgid "E169: Command too recursive"
+msgstr "E169: Слишком рекурÑÐ¸Ð²Ð½Ð°Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð°"
+
+#, c-format
+msgid "E605: Exception not caught: %s"
+msgstr "E605: ИÑÐºÐ»ÑŽÑ‡Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð°Ñ ÑÐ¸Ñ‚ÑƒÐ°Ñ†Ð¸Ñ Ð½Ðµ обработана: %s"
+
+msgid "End of sourced file"
+msgstr "Конец Ñчитанного файла"
+
+msgid "End of function"
+msgstr "Конец функции"
+
+msgid "E464: Ambiguous use of user-defined command"
+msgstr "E464: Ðеоднозначное иÑпользование команды пользователÑ"
+
+msgid "E492: Not an editor command"
+msgstr "E492: Это не команда редактора"
+
+msgid "E493: Backwards range given"
+msgstr "E493: Задан обратный диапазон"
+
+msgid "Backwards range given, OK to swap"
+msgstr "Задан обратный диапазон, менÑем границы меÑтами"
+
+msgid "E494: Use w or w>>"
+msgstr "E494: ИÑпользуйте w или w>>"
+
+msgid "E943: Command table needs to be updated, run 'make cmdidxs'"
+msgstr "E943: Таблица команд должна быть обновлена, выполните 'make cmdidxs'"
+
+msgid "E319: Sorry, the command is not available in this version"
+msgstr "E319: Извините, Ñта команда недоÑтупна в данной верÑии"
+
+msgid "1 more file to edit. Quit anyway?"
+msgstr "1 файл ожидает редактированиÑ. Выйти?"
+
+#, c-format
+msgid "%d more files to edit. Quit anyway?"
+msgstr "ЕÑÑ‚ÑŒ неотредактированные файлы (%d). Выйти?"
+
+msgid "E173: 1 more file to edit"
+msgstr "E173: 1 файл ожидает редактированиÑ."
+
+#, c-format
+msgid "E173: %ld more files to edit"
+msgstr "E173: ЕÑÑ‚ÑŒ неотредактированные файлы (%ld)."
+
+msgid "E174: Command already exists: add ! to replace it"
+msgstr "E174: Команда уже ÑущеÑтвует. Добавьте ! Ð´Ð»Ñ Ð·Ð°Ð¼ÐµÐ½Ñ‹."
+
+msgid ""
+"\n"
+" Name Args Address Complete Definition"
+msgstr ""
+"\n"
+" Ð˜Ð¼Ñ ÐŸÐ°Ñ€Ð°Ð¼. Диап. Дополн. Определение"
+
+msgid "No user-defined commands found"
+msgstr "Команды, определённые пользователем, не обнаружены."
+
+msgid "E175: No attribute specified"
+msgstr "E175: Параметр не задан"
+
+msgid "E176: Invalid number of arguments"
+msgstr "E176: Ðеправильное количеÑтво параметров"
+
+msgid "E177: Count cannot be specified twice"
+msgstr "E177: ЧиÑло-приÑтавку Ð½ÐµÐ»ÑŒÐ·Ñ ÑƒÐºÐ°Ð·Ñ‹Ð²Ð°Ñ‚ÑŒ дважды"
+
+msgid "E178: Invalid default value for count"
+msgstr "E178: Ðеправильное значение чиÑла-приÑтавки по умолчанию"
+
+msgid "E179: argument required for -complete"
+msgstr "E179: Ð”Ð»Ñ -complete требуетÑÑ ÑƒÐºÐ°Ð·Ð°Ñ‚ÑŒ параметр"
+
+msgid "E179: argument required for -addr"
+msgstr "E179: Ð”Ð»Ñ -addr требуетÑÑ ÑƒÐºÐ°Ð·Ð°Ñ‚ÑŒ параметр"
+
+#, c-format
+msgid "E181: Invalid attribute: %s"
+msgstr "E181: Ðеправильный атрибут: %s"
+
+msgid "E182: Invalid command name"
+msgstr "E182: Ðеправильное Ð¸Ð¼Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ‹"
+
+msgid "E183: User defined commands must start with an uppercase letter"
+msgstr "E183: Команда Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð´Ð¾Ð»Ð¶Ð½Ð° начинатьÑÑ Ñ Ð·Ð°Ð³Ð»Ð°Ð²Ð½Ð¾Ð¹ буквы"
+
+msgid "E841: Reserved name, cannot be used for user defined command"
+msgstr ""
+"E841: Зарезервированное Ð¸Ð¼Ñ Ð½Ðµ может иÑпользоватьÑÑ Ð´Ð»Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´ пользователÑ"
+
+#, c-format
+msgid "E184: No such user-defined command: %s"
+msgstr "E184: Ðет такой команды пользователÑ: %s"
+
+#, c-format
+msgid "E180: Invalid address type value: %s"
+msgstr "E180: Ðеправильное значение типа адреÑа: %s"
+
+#, c-format
+msgid "E180: Invalid complete value: %s"
+msgstr "E180: Ðеправильное значение дополнениÑ: %s"
+
+msgid "E468: Completion argument only allowed for custom completion"
+msgstr ""
+"E468: Параметр Ð°Ð²Ñ‚Ð¾Ð´Ð¾Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð¶Ð½Ð¾ иÑпользовать только Ñ Ð¾Ñобым дополнением"
+
+msgid "E467: Custom completion requires a function argument"
+msgstr "E467: ОÑобое дополнение требует ÑƒÐºÐ°Ð·Ð°Ð½Ð¸Ñ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ð° функции"
+
+msgid "unknown"
+msgstr "неизвеÑтно"
+
+#, c-format
+msgid "E185: Cannot find color scheme '%s'"
+msgstr "E185: Ðевозможно найти цветовую Ñхему '%s'"
+
+msgid "Greetings, Vim user!"
+msgstr "ПриветÑтвуем ваÑ, пользователь Vim!"
+
+msgid "E784: Cannot close last tab page"
+msgstr "E784: ÐÐµÐ»ÑŒÐ·Ñ Ð·Ð°ÐºÑ€Ñ‹Ñ‚ÑŒ поÑледнюю вкладку"
+
+msgid "Already only one tab page"
+msgstr "Ðа Ñкране вÑего одна вкладка"
+
+msgid "Edit File in new window"
+msgstr "Редактировать файл в новом окне"
+
+#, c-format
+msgid "Tab page %d"
+msgstr "Вкладка %d"
+
+msgid "No swap file"
+msgstr "Без Ñвоп-файла"
+
+msgid "Append File"
+msgstr "Добавить файл"
+
+msgid "E747: Cannot change directory, buffer is modified (add ! to override)"
+msgstr ""
+"E747: Смена каталога невозможна, буфер изменён (добавьте !, чтобы обойти "
+"проверку)"
+
+msgid "E186: No previous directory"
+msgstr "E186: Ðет предыдущего каталога"
+
+msgid "E187: Unknown"
+msgstr "E187: ÐеизвеÑтно"
+
+msgid "E465: :winsize requires two number arguments"
+msgstr "E465: Команда :winsize требует ÑƒÐºÐ°Ð·Ð°Ð½Ð¸Ñ Ð´Ð²ÑƒÑ… чиÑловых параметров"
+
+#, c-format
+msgid "Window position: X %d, Y %d"
+msgstr "Положение окна: X %d, Y %d"
+
+msgid "E188: Obtaining window position not implemented for this platform"
+msgstr "E188: Ð’ данной ÑиÑтеме определение Ð¿Ð¾Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¾ÐºÐ½Ð° не работает"
+
+msgid "E466: :winpos requires two number arguments"
+msgstr "E466: Команда :winpos требует ÑƒÐºÐ°Ð·Ð°Ð½Ð¸Ñ Ð´Ð²ÑƒÑ… чиÑловых параметров"
+
+msgid "E930: Cannot use :redir inside execute()"
+msgstr "E930: Ðевозможно иÑпользовать :redir внутри execute()"
+
+msgid "Save Redirection"
+msgstr "Перенаправление запиÑи"
+
+msgid "Save View"
+msgstr "Сохранение вида"
+
+msgid "Save Session"
+msgstr "Сохранение ÑеанÑа"
+
+msgid "Save Setup"
+msgstr "Сохранение наÑтроек"
+
+#, c-format
+msgid "E739: Cannot create directory: %s"
+msgstr "E739: Ðевозможно Ñоздать каталог: %s"
+
+#, c-format
+msgid "E189: \"%s\" exists (add ! to override)"
+msgstr "E189: \"%s\" ÑущеÑтвует (добавьте !, чтобы обойти проверку)"
+
+#, c-format
+msgid "E190: Cannot open \"%s\" for writing"
+msgstr "E190: Ðевозможно открыть Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñи \"%s\""
+
+msgid "E191: Argument must be a letter or forward/backward quote"
+msgstr "E191: Параметр должен быть прÑмой/обратной кавычкой или буквой"
+
+msgid "E192: Recursive use of :normal too deep"
+msgstr "E192: Слишком Ð³Ð»ÑƒÐ±Ð¾ÐºÐ°Ñ Ñ€ÐµÐºÑƒÑ€ÑÐ¸Ñ Ð¿Ñ€Ð¸ иÑпользовании команды :normal"
+
+msgid "E809: #< is not available without the +eval feature"
+msgstr "E809: #< не доÑтупно без оÑобенноÑти +eval"
+
+msgid "E194: No alternate file name to substitute for '#'"
+msgstr "E194: Ðет ÑоÑеднего имени файла Ð´Ð»Ñ Ð·Ð°Ð¼ÐµÐ½Ñ‹ '#'"
+
+msgid "E495: no autocommand file name to substitute for \"<afile>\""
+msgstr "E495: Ðет автокомандного имени файла Ð´Ð»Ñ Ð·Ð°Ð¼ÐµÐ½Ñ‹ \"<afile>\""
+
+msgid "E496: no autocommand buffer number to substitute for \"<abuf>\""
+msgstr "E496: Ðет автокомандного номера буфера Ð´Ð»Ñ Ð·Ð°Ð¼ÐµÐ½Ñ‹ \"<abuf>\""
+
+msgid "E497: no autocommand match name to substitute for \"<amatch>\""
+msgstr "E497: Ðет автокомандного имени ÑоответÑÑ‚Ð²Ð¸Ñ Ð´Ð»Ñ Ð·Ð°Ð¼ÐµÐ½Ñ‹ \"<amatch>\""
+
+msgid "E498: no :source file name to substitute for \"<sfile>\""
+msgstr "E498: Ðет имени файла :source Ð´Ð»Ñ Ð·Ð°Ð¼ÐµÐ½Ñ‹ \"<sfile>\""
+
+msgid "E842: no line number to use for \"<slnum>\""
+msgstr "E842: Ðет номера Ñтроки Ð´Ð»Ñ Ð¸ÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ \"<slnum>\""
+
+#, no-c-format
+msgid "E499: Empty file name for '%' or '#', only works with \":p:h\""
+msgstr "E499: ПуÑтое Ð¸Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð° Ð´Ð»Ñ '%' или '#', возможно только c \":p:h\""
+
+msgid "E500: Evaluates to an empty string"
+msgstr "E500: Результатом Ð²Ñ‹Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ ÑвлÑетÑÑ Ð¿ÑƒÑÑ‚Ð°Ñ Ñтрока"
+
+msgid "E195: Cannot open viminfo file for reading"
+msgstr "E195: Ðевозможно открыть файл viminfo Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ"
+
+msgid "Untitled"
+msgstr "Без имени"
+
+msgid "E196: No digraphs in this version"
+msgstr "E196: Ð’ Ñтой верÑии диграфы не работают"
+
+msgid "E608: Cannot :throw exceptions with 'Vim' prefix"
+msgstr ""
+"E608: Ðевозможно выполнить команду :throw Ð´Ð»Ñ Ð¸Ñключений Ñ Ð¿Ñ€Ð¸Ñтавкой 'Vim'"
+
+#, c-format
+msgid "Exception thrown: %s"
+msgstr "ИÑÐºÐ»ÑŽÑ‡Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð°Ñ ÑитуациÑ: %s"
+
+#, c-format
+msgid "Exception finished: %s"
+msgstr "Завершена обработка иÑключительной Ñитуации: %s"
+
+#, c-format
+msgid "Exception discarded: %s"
+msgstr "ИÑÐºÐ»ÑŽÑ‡Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð°Ñ ÑÐ¸Ñ‚ÑƒÐ°Ñ†Ð¸Ñ Ð¿Ñ€Ð¾Ð¸Ð³Ð½Ð¾Ñ€Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð°: %s"
+
+#, c-format
+msgid "%s, line %ld"
+msgstr "%s, Ñтрока %ld"
+
+#, c-format
+msgid "Exception caught: %s"
+msgstr "Обработка иÑключительной Ñитуации: %s"
+
+#, c-format
+msgid "%s made pending"
+msgstr "%s выполнÑет ожидание"
+
+#, c-format
+msgid "%s resumed"
+msgstr "%s возобновлено"
+
+#, c-format
+msgid "%s discarded"
+msgstr "%s пропущено"
+
+msgid "Exception"
+msgstr "ИÑÐºÐ»ÑŽÑ‡Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð°Ñ ÑитуациÑ"
+
+msgid "Error and interrupt"
+msgstr "Ошибка и прерывание"
+
+msgid "Error"
+msgstr "Ошибка"
+
+msgid "Interrupt"
+msgstr "Прерывание"
+
+msgid "E579: :if nesting too deep"
+msgstr "E579: Слишком глубоко вложенный :if"
+
+msgid "E580: :endif without :if"
+msgstr "E580: :endif без :if"
+
+msgid "E581: :else without :if"
+msgstr "E581: :else без :if"
+
+msgid "E582: :elseif without :if"
+msgstr "E582: :elseif без :if"
+
+msgid "E583: multiple :else"
+msgstr "E583: Обнаружено неÑколько :else"
+
+msgid "E584: :elseif after :else"
+msgstr "E584: :elseif поÑле :else"
+
+msgid "E585: :while/:for nesting too deep"
+msgstr "E585: Слишком глубокое вложение :while или :for"
+
+msgid "E586: :continue without :while or :for"
+msgstr "E586: :continue без :while или :for"
+
+msgid "E587: :break without :while or :for"
+msgstr "E587: :break без :while или :for"
+
+msgid "E732: Using :endfor with :while"
+msgstr "E732: ИÑпользование :endfor Ñ :while"
+
+msgid "E733: Using :endwhile with :for"
+msgstr "E733: ИÑпользование :endwhile Ñ :for"
+
+msgid "E601: :try nesting too deep"
+msgstr "E601: Слишком глубоко вложенный :try"
+
+msgid "E603: :catch without :try"
+msgstr "E603: :catch без :try"
+
+msgid "E604: :catch after :finally"
+msgstr "E604: :catch поÑле :finally"
+
+msgid "E606: :finally without :try"
+msgstr "E606: :finally без :try"
+
+msgid "E607: multiple :finally"
+msgstr "E607: Обнаружено неÑколько :finally"
+
+msgid "E602: :endtry without :try"
+msgstr "E602: :endtry без :try"
+
+msgid "E193: :endfunction not inside a function"
+msgstr "E193: Команда :endfunction может иÑпользоватьÑÑ Ñ‚Ð¾Ð»ÑŒÐºÐ¾ внутри функции"
+
+msgid "E788: Not allowed to edit another buffer now"
+msgstr "E788: Ð¡ÐµÐ¹Ñ‡Ð°Ñ Ð½Ðµ допуÑкаетÑÑ Ñ€ÐµÐ´Ð°ÐºÑ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ðµ другого буфера"
+
+msgid "E811: Not allowed to change buffer information now"
+msgstr "E811: Ð¡ÐµÐ¹Ñ‡Ð°Ñ Ð½Ðµ допуÑкаетÑÑ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ðµ информации о буфере"
+
+msgid "tagname"
+msgstr "Ð¸Ð¼Ñ Ð¼ÐµÑ‚ÐºÐ¸"
+
+msgid " kind file\n"
+msgstr " тип файла\n"
+
+msgid "'history' option is zero"
+msgstr "значение опции 'history' равно нулю"
+
+#, c-format
+msgid ""
+"\n"
+"# %s History (newest to oldest):\n"
+msgstr ""
+"\n"
+"# %s, иÑÑ‚Ð¾Ñ€Ð¸Ñ (Ð½Ð°Ñ‡Ð¸Ð½Ð°Ñ Ð¾Ñ‚ Ñвежего к Ñтарому):\n"
+
+msgid "Command Line"
+msgstr "ÐšÐ¾Ð¼Ð°Ð½Ð´Ð½Ð°Ñ Ñтрока"
+
+msgid "Search String"
+msgstr "Строка поиÑка"
+
+msgid "Expression"
+msgstr "Выражение"
+
+msgid "Input Line"
+msgstr "Строка ввода"
+
+msgid "Debug Line"
+msgstr "Строка отладки"
+
+msgid "E198: cmd_pchar beyond the command length"
+msgstr "E198: cmd_pchar больше длины команды"
+
+msgid "E199: Active window or buffer deleted"
+msgstr "E199: Удалено активное окно или буфер"
+
+msgid "E812: Autocommands changed buffer or buffer name"
+msgstr "E812: Ðвтокоманды изменили буфер или Ð¸Ð¼Ñ Ð±ÑƒÑ„ÐµÑ€Ð°"
+
+msgid "Illegal file name"
+msgstr "ÐедопуÑтимое Ð¸Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð°"
+
+msgid "is a directory"
+msgstr "ÑвлÑетÑÑ ÐºÐ°Ñ‚Ð°Ð»Ð¾Ð³Ð¾Ð¼"
+
+msgid "is not a file"
+msgstr "не ÑвлÑетÑÑ Ñ„Ð°Ð¹Ð»Ð¾Ð¼"
+
+msgid "is a device (disabled with 'opendevice' option)"
+msgstr "ÑвлÑетÑÑ ÑƒÑтройÑтвом (отключено при опции 'opendevice')"
+
+msgid "[New File]"
+msgstr "[Ðовый файл]"
+
+msgid "[New DIRECTORY]"
+msgstr "[Ðовый КÐТÐЛОГ]"
+
+msgid "[File too big]"
+msgstr "[Файл Ñлишком большой]"
+
+msgid "[Permission Denied]"
+msgstr "[ДоÑтуп запрещён]"
+
+msgid "E200: *ReadPre autocommands made the file unreadable"
+msgstr "E200: Ð’ результате Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ð°Ð²Ñ‚Ð¾ÐºÐ¾Ð¼Ð°Ð½Ð´ *ReadPre файл Ñтал нечитаемым"
+
+msgid "E201: *ReadPre autocommands must not change current buffer"
+msgstr "E201: Ðвтокоманды *ReadPre не должны изменÑÑ‚ÑŒ активный буфер"
+
+msgid "Vim: Reading from stdin...\n"
+msgstr "Vim: Чтение из Ñтандартного потока ввода stdin...\n"
+
+msgid "Reading from stdin..."
+msgstr "Чтение из Ñтандартного потока ввода stdin..."
+
+msgid "E202: Conversion made file unreadable!"
+msgstr "E202: Ð’ результате Ð¿Ñ€ÐµÐ¾Ð±Ñ€Ð°Ð·Ð¾Ð²Ð°Ð½Ð¸Ñ Ñ„Ð°Ð¹Ð» Ñтал нечитаемым!"
+
+msgid "[fifo/socket]"
+msgstr "[fifo/гнездо]"
+
+msgid "[fifo]"
+msgstr "[fifo]"
+
+msgid "[socket]"
+msgstr "[гнездо]"
+
+msgid "[character special]"
+msgstr "[Ñпециальный Ñимвольный]"
+
+msgid "[CR missing]"
+msgstr "[пропущены Ñимволы CR]"
+
+msgid "[long lines split]"
+msgstr "[длинные Ñтроки разбиты]"
+
+msgid "[NOT converted]"
+msgstr "[БЕЗ преобразований]"
+
+msgid "[converted]"
+msgstr "[перекодировано]"
+
+#, c-format
+msgid "[CONVERSION ERROR in line %ld]"
+msgstr "[ОШИБКРПРЕОБРÐЗОВÐÐИЯ в Ñтроке %ld]"
+
+#, c-format
+msgid "[ILLEGAL BYTE in line %ld]"
+msgstr "[ÐЕДОПУСТИМЫЙ БÐЙТ в Ñтроке %ld]"
+
+msgid "[READ ERRORS]"
+msgstr "[ОШИБКИ ЧТЕÐИЯ]"
+
+msgid "Can't find temp file for conversion"
+msgstr "Временный файл Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐºÐ¾Ð´Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð½Ðµ найден"
+
+msgid "Conversion with 'charconvert' failed"
+msgstr "Преобразование Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ 'charconvert' не выполнено"
+
+msgid "can't read output of 'charconvert'"
+msgstr "невозможно прочитать вывод 'charconvert'"
+
+msgid "E676: No matching autocommands for acwrite buffer"
+msgstr "E676: Ðет подходÑщих автокоманд Ð´Ð»Ñ Ð±ÑƒÑ„ÐµÑ€Ð° acwrite"
+
+msgid "E203: Autocommands deleted or unloaded buffer to be written"
+msgstr ""
+"E203: Буфер, который требовалоÑÑŒ запиÑать, удалён или выгружен автокомандой"
+
+msgid "E204: Autocommand changed number of lines in unexpected way"
+msgstr "E204: КоличеÑтво Ñтрок изменено автокомандой неожиданным образом"
+
+msgid "NetBeans disallows writes of unmodified buffers"
+msgstr "NetBeans не позволÑет выполнÑÑ‚ÑŒ запиÑÑŒ неизменённых буферов"
+
+msgid "Partial writes disallowed for NetBeans buffers"
+msgstr "ЧаÑÑ‚Ð¸Ñ‡Ð½Ð°Ñ Ð·Ð°Ð¿Ð¸ÑÑŒ буферов NetBeans не допуÑкаетÑÑ"
+
+msgid "is not a file or writable device"
+msgstr "не ÑвлÑетÑÑ Ñ„Ð°Ð¹Ð»Ð¾Ð¼ или уÑтройÑтвом, доÑтупным Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñи"
+
+msgid "writing to device disabled with 'opendevice' option"
+msgstr "запиÑÑŒ в уÑтройÑтво отключена при опции 'opendevice'"
+
+msgid "is read-only (add ! to override)"
+msgstr "открыт только Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ (добавьте !, чтобы обойти проверку)"
+
+msgid "E506: Can't write to backup file (add ! to override)"
+msgstr ""
+"E506: ЗапиÑÑŒ в резервный файл невозможна (добавьте !, чтобы обойти проверку)"
+
+msgid "E507: Close error for backup file (add ! to override)"
+msgstr ""
+"E507: Ошибка Ð·Ð°ÐºÑ€Ñ‹Ñ‚Ð¸Ñ Ñ€ÐµÐ·ÐµÑ€Ð²Ð½Ð¾Ð³Ð¾ файла (добавьте !, чтобы обойти проверку)"
+
+msgid "E508: Can't read file for backup (add ! to override)"
+msgstr ""
+"E508: Ðевозможно прочитать резервный файл (добавьте !, чтобы обойти проверку)"
+
+msgid "E509: Cannot create backup file (add ! to override)"
+msgstr ""
+"E509: Ðевозможно Ñоздать резервный файл (добавьте !, чтобы обойти проверку)"
+
+msgid "E510: Can't make backup file (add ! to override)"
+msgstr ""
+"E510: Ðевозможно Ñоздать резервный файл (добавьте !, чтобы обойти проверку)"
+
+msgid "E214: Can't find temp file for writing"
+msgstr "E214: Временный файл Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñи не найден"
+
+msgid "E213: Cannot convert (add ! to write without conversion)"
+msgstr ""
+"E213: Перекодировка невозможна (добавьте ! Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñи без перекодировки)"
+
+msgid "E166: Can't open linked file for writing"
+msgstr "E166: Ðевозможно открыть файл по ÑÑылке Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñи"
+
+msgid "E212: Can't open file for writing"
+msgstr "E212: Ðевозможно открыть файл Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñи"
+
+msgid "E949: File changed while writing"
+msgstr "E949: Файл был изменён поÑле запиÑи"
+
+msgid "E512: Close failed"
+msgstr "E512: ÐžÐ¿ÐµÑ€Ð°Ñ†Ð¸Ñ Ð·Ð°ÐºÑ€Ñ‹Ñ‚Ð¸Ñ Ð½Ðµ удалаÑÑŒ"
+
+msgid "E513: write error, conversion failed (make 'fenc' empty to override)"
+msgstr ""
+"E513: Ошибка запиÑи, преобразование не удалоÑÑŒ (очиÑтите 'fenc', чтобы "
+"обойти)"
+
+#, c-format
+msgid ""
+"E513: write error, conversion failed in line %ld (make 'fenc' empty to "
+"override)"
+msgstr ""
+"E513: Ошибка запиÑи, преобразование не удалоÑÑŒ на Ñтроке %ld (очиÑтите "
+"'fenc', чтобы обойти)"
+
+msgid "E514: write error (file system full?)"
+msgstr "E514: Ошибка запиÑи (нет Ñвободного меÑта?)"
+
+msgid " CONVERSION ERROR"
+msgstr " ОШИБКРПРЕОБРÐЗОВÐÐИЯ"
+
+#, c-format
+msgid " in line %ld;"
+msgstr " на Ñтроке %ld;"
+
+msgid "[Device]"
+msgstr "[УÑтройÑтво]"
+
+msgid "[New]"
+msgstr "[Ðовый]"
+
+msgid " [a]"
+msgstr " [д]"
+
+msgid " appended"
+msgstr " добавлено"
+
+msgid " [w]"
+msgstr " [з]"
+
+msgid " written"
+msgstr " запиÑано"
+
+msgid "E205: Patchmode: can't save original file"
+msgstr "E205: Режим заплатки: невозможно Ñохранение иÑходного файла"
+
+msgid "E206: patchmode: can't touch empty original file"
+msgstr ""
+"E206: Режим заплатки: невозможно Ñменить параметры пуÑтого иÑходного файла"
+
+msgid "E207: Can't delete backup file"
+msgstr "E207: Ðевозможно удалить резервный файл"
+
+msgid ""
+"\n"
+"WARNING: Original file may be lost or damaged\n"
+msgstr ""
+"\n"
+"ПРЕДУПРЕЖДЕÐИЕ: ИÑходный файл может быть утрачен или повреждён\n"
+
+msgid "don't quit the editor until the file is successfully written!"
+msgstr "не выходите из редактора, пока файл не будет уÑпешно запиÑан!"
+
+msgid "[dos]"
+msgstr "[dos]"
+
+msgid "[dos format]"
+msgstr "[формат dos]"
+
+msgid "[mac]"
+msgstr "[mac]"
+
+msgid "[mac format]"
+msgstr "[формат mac]"
+
+msgid "[unix]"
+msgstr "[unix]"
+
+msgid "[unix format]"
+msgstr "[формат unix]"
+
+msgid "1 line, "
+msgstr "1 Ñтрока, "
+
+#, c-format
+msgid "%ld lines, "
+msgstr "Ñтрок: %ld, "
+
+msgid "1 character"
+msgstr "1 Ñимвол"
+
+#, c-format
+msgid "%lld characters"
+msgstr "Ñимволов: %lld"
+
+msgid "[noeol]"
+msgstr "[noeol]"
+
+msgid "[Incomplete last line]"
+msgstr "[ÐÐµÐ·Ð°Ð²ÐµÑ€ÑˆÑ‘Ð½Ð½Ð°Ñ Ð¿Ð¾ÑледнÑÑ Ñтрока]"
+
+msgid "WARNING: The file has been changed since reading it!!!"
+msgstr "ПРЕДУПРЕЖДЕÐИЕ: Файл изменён Ñ Ð¼Ð¾Ð¼ÐµÐ½Ñ‚Ð° чтениÑ!!!"
+
+msgid "Do you really want to write to it"
+msgstr "Серьёзно хотите запиÑать в Ñтот файл"
+
+#, c-format
+msgid "E208: Error writing to \"%s\""
+msgstr "E208: Ошибка запиÑи в \"%s\""
+
+#, c-format
+msgid "E209: Error closing \"%s\""
+msgstr "E209: Ошибка Ð·Ð°ÐºÑ€Ñ‹Ñ‚Ð¸Ñ \"%s\""
+
+#, c-format
+msgid "E210: Error reading \"%s\""
+msgstr "E210: Ошибка Ñ‡Ñ‚ÐµÐ½Ð¸Ñ \"%s\""
+
+msgid "E246: FileChangedShell autocommand deleted buffer"
+msgstr "E246: Буфер удалён при выполнении автокоманды FileChangedShell"
+
+#, c-format
+msgid "E211: File \"%s\" no longer available"
+msgstr "E211: Файл \"%s\" больше не доÑтупен"
+
+#, c-format
+msgid ""
+"W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as "
+"well"
+msgstr ""
+"W12: Предупреждение: файл \"%s\" и буфер Vim были изменены незавиÑимо друг "
+"от друга"
+
+msgid "See \":help W12\" for more info."
+msgstr "См. \":help W12\" Ð´Ð»Ñ Ð´Ð¾Ð¿Ð¾Ð»Ð½Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð¾Ð¹ информации."
+
+#, c-format
+msgid "W11: Warning: File \"%s\" has changed since editing started"
+msgstr ""
+"W11: Предупреждение: файл \"%s\" был изменён поÑле начала редактированиÑ"
+
+msgid "See \":help W11\" for more info."
+msgstr "См. \":help W11\" Ð´Ð»Ñ Ð´Ð¾Ð¿Ð¾Ð»Ð½Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð¾Ð¹ информации."
+
+#, c-format
+msgid "W16: Warning: Mode of file \"%s\" has changed since editing started"
+msgstr ""
+"W16: Предупреждение: режим доÑтупа к файлу \"%s\" был изменён поÑле начала "
+"редактированиÑ"
+
+msgid "See \":help W16\" for more info."
+msgstr "См. \":help W16\" Ð´Ð»Ñ Ð´Ð¾Ð¿Ð¾Ð»Ð½Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð¾Ð¹ информации."
+
+#, c-format
+msgid "W13: Warning: File \"%s\" has been created after editing started"
+msgstr ""
+"W13: Предупреждение: файл \"%s\" был Ñоздан поÑле начала редактированиÑ"
+
+msgid "Warning"
+msgstr "Предупреждение"
+
+msgid ""
+"&OK\n"
+"&Load File"
+msgstr ""
+"&OK\n"
+"&L Загрузить файл"
+
+#, c-format
+msgid "E462: Could not prepare for reloading \"%s\""
+msgstr "E462: Ðевозможно подготовитьÑÑ Ðº перезагрузке \"%s\""
+
+#, c-format
+msgid "E321: Could not reload \"%s\""
+msgstr "E321: Ðевозможно выполнить перезагрузку \"%s\""
+
+msgid "--Deleted--"
+msgstr "--Удалено--"
+
+#, c-format
+msgid "auto-removing autocommand: %s <buffer=%d>"
+msgstr "авто-удаление автокоманды: %s <буффер=%d>"
+
+#, c-format
+msgid "E367: No such group: \"%s\""
+msgstr "E367: Группа \"%s\" не ÑущеÑтвует"
+
+msgid "E936: Cannot delete the current group"
+msgstr "E936: Ðевозможно удалить текущую группу"
+
+msgid "W19: Deleting augroup that is still in use"
+msgstr "W19: Удаление ещё иÑпользуемой группы автокоманд"
+
+#, c-format
+msgid "E215: Illegal character after *: %s"
+msgstr "E215: ÐедопуÑтимые Ñимволы поÑле *: %s"
+
+#, c-format
+msgid "E216: No such event: %s"
+msgstr "E216: ÐеÑущеÑтвующее Ñобытие: %s"
+
+#, c-format
+msgid "E216: No such group or event: %s"
+msgstr "E216: ÐеÑущеÑÑ‚Ð²ÑƒÑŽÑ‰Ð°Ñ Ð³Ñ€ÑƒÐ¿Ð¿Ð° или Ñобытие: %s"
+
+msgid ""
+"\n"
+"--- Autocommands ---"
+msgstr ""
+"\n"
+"--- Ðвтокоманды ---"
+
+#, c-format
+msgid "E680: <buffer=%d>: invalid buffer number "
+msgstr "E680: <buffer=%d>: неправильный номер буфера "
+
+msgid "E217: Can't execute autocommands for ALL events"
+msgstr "E217: Ðевозможно выполнить автокоманды Ð´Ð»Ñ Ð’Ð¡Ð•Ð¥ Ñобытий"
+
+msgid "No matching autocommands"
+msgstr "Ðет подходÑщих автокоманд"
+
+msgid "E218: autocommand nesting too deep"
+msgstr "E218: Ñлишком глубоко вложенные автокоманды"
+
+#, c-format
+msgid "%s Autocommands for \"%s\""
+msgstr "%s Ðвтокоманды Ð´Ð»Ñ \"%s\""
+
+#, c-format
+msgid "Executing %s"
+msgstr "Выполнение %s"
+
+#, c-format
+msgid "autocommand %s"
+msgstr "автокоманда %s"
+
+msgid "E219: Missing {."
+msgstr "E219: Пропущена {."
+
+msgid "E220: Missing }."
+msgstr "E220: Пропущена }."
+
+msgid "E490: No fold found"
+msgstr "E490: Складок не обнаружено"
+
+msgid "E350: Cannot create fold with current 'foldmethod'"
+msgstr ""
+"E350: Складка не может быть Ñоздана Ñ Ñ‚ÐµÐºÑƒÑ‰Ð¸Ð¼ значением опции 'foldmethod'"
+
+msgid "E351: Cannot delete fold with current 'foldmethod'"
+msgstr ""
+"E351: Складка не может быть удалена Ñ Ñ‚ÐµÐºÑƒÑ‰Ð¸Ð¼ значением опции 'foldmethod'"
+
+#, c-format
+msgid "+--%3ld line folded "
+msgid_plural "+--%3ld lines folded "
+msgstr[0] "+--%3ld Ñтрока в Ñкладке "
+msgstr[1] "+--%3ld Ñтроки в Ñкладке "
+msgstr[2] "+--%3ld Ñтрок в Ñкладке "
+
+msgid "E222: Add to read buffer"
+msgstr "E222: Добавление в буфер чтениÑ"
+
+msgid "E223: recursive mapping"
+msgstr "E223: РекурÑÐ¸Ð²Ð½Ð°Ñ Ð¿Ñ€Ð¸Ð²Ñзка"
+
+#, c-format
+msgid "E224: global abbreviation already exists for %s"
+msgstr "E224: Уже еÑÑ‚ÑŒ глобальное Ñокращение Ð´Ð»Ñ %s"
+
+#, c-format
+msgid "E225: global mapping already exists for %s"
+msgstr "E225: Уже еÑÑ‚ÑŒ Ð³Ð»Ð¾Ð±Ð°Ð»ÑŒÐ½Ð°Ñ Ð¿Ñ€Ð¸Ð²Ñзка Ð´Ð»Ñ %s"
+
+#, c-format
+msgid "E226: abbreviation already exists for %s"
+msgstr "E226: Уже еÑÑ‚ÑŒ Ñокращение Ð´Ð»Ñ %s"
+
+#, c-format
+msgid "E227: mapping already exists for %s"
+msgstr "E227: Уже еÑÑ‚ÑŒ привÑзка Ð´Ð»Ñ %s"
+
+msgid "No abbreviation found"
+msgstr "Ð¡Ð¾ÐºÑ€Ð°Ñ‰ÐµÐ½Ð¸Ñ Ð½Ðµ найдены"
+
+msgid "No mapping found"
+msgstr "ПривÑзки не найдены"
+
+msgid "E228: makemap: Illegal mode"
+msgstr "E228: makemap: недопуÑтимый режим"
+
+msgid "E851: Failed to create a new process for the GUI"
+msgstr "E851: Ðевозможно Ñоздать новый процеÑÑ Ð´Ð»Ñ Ð³Ñ€Ð°Ñ„. интерфейÑа"
+
+msgid "E852: The child process failed to start the GUI"
+msgstr "E852: ПроцеÑÑу-потомку не удалоÑÑŒ запуÑтить граф. интерфейÑ"
+
+msgid "E229: Cannot start the GUI"
+msgstr "E229: Ðевозможно перейти в режим графичеÑкого интерфейÑа"
+
+#, c-format
+msgid "E230: Cannot read from \"%s\""
+msgstr "E230: Ðевозможно выполнить чтение \"%s\""
+
+msgid "E665: Cannot start GUI, no valid font found"
+msgstr ""
+"E665: Ðевозможно перейти в режим граф. интерфейÑа, неправильно заданы шрифты"
+
+msgid "E231: 'guifontwide' invalid"
+msgstr "E231: Ðеправильное значение опции 'guifontwide'"
+
+msgid "E599: Value of 'imactivatekey' is invalid"
+msgstr "E599: Ðеправильное значение опции 'imactivatekey'"
+
+#, c-format
+msgid "E254: Cannot allocate color %s"
+msgstr "E254: Ðевозможно назначить цвет %s"
+
+msgid "No match at cursor, finding next"
+msgstr "Ðет ÑÐ¾Ð²Ð¿Ð°Ð´ÐµÐ½Ð¸Ñ Ð¿Ð¾Ð´ курÑором, поиÑк Ñледующего"
+
+msgid "<cannot open> "
+msgstr "<Ð½ÐµÐ»ÑŒÐ·Ñ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚ÑŒ> "
+
+#, c-format
+msgid "E616: vim_SelFile: can't get font %s"
+msgstr "E616: vim_SelFile: шрифт %s не найден"
+
+msgid "E614: vim_SelFile: can't return to current directory"
+msgstr "E614: vim_SelFile: возврат в текущий каталог невозможен"
+
+msgid "Pathname:"
+msgstr "Путь к файлу:"
+
+msgid "E615: vim_SelFile: can't get current directory"
+msgstr "E615: vim_SelFile: не могу найти текущий каталог"
+
+msgid "OK"
+msgstr "Да"
+
+msgid "Cancel"
+msgstr "Отмена"
+
+msgid "Scrollbar Widget: Could not get geometry of thumb pixmap."
+msgstr "ПолоÑа прокрутки: не могу определить геометрию ползунка"
+
+msgid "Vim dialog"
+msgstr "Диалоговое окно Vim"
+
+msgid "E232: Cannot create BalloonEval with both message and callback"
+msgstr ""
+"E232: \"Пузырь\" Ð´Ð»Ñ Ð²Ñ‹Ñ‡Ð¸Ñлений, включающий и Ñообщение, и обратный вызов, "
+"не может быть Ñоздан"
+
+msgid "_Cancel"
+msgstr "О_тмена"
+
+msgid "_Save"
+msgstr "Сохранить _как"
+
+msgid "_Open"
+msgstr "_Открыть"
+
+msgid "_OK"
+msgstr "_Да"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"&Cancel"
+msgstr ""
+"&Да\n"
+"&Ðет\n"
+"О&тмена"
+
+msgid "Yes"
+msgstr "Да"
+
+msgid "No"
+msgstr "Ðет"
+
+msgid "Input _Methods"
+msgstr "_Методы ввода"
+
+msgid "VIM - Search and Replace..."
+msgstr "VIM — ПоиÑк и замена..."
+
+msgid "VIM - Search..."
+msgstr "VIM — ПоиÑк..."
+
+msgid "Find what:"
+msgstr "Что найти:"
+
+msgid "Replace with:"
+msgstr "Заменить на:"
+
+msgid "Match whole word only"
+msgstr "Только точные ÑоответÑтвиÑ"
+
+msgid "Match case"
+msgstr "Учитывать региÑÑ‚Ñ€"
+
+msgid "Direction"
+msgstr "Ðаправление"
+
+msgid "Up"
+msgstr "Вверх"
+
+msgid "Down"
+msgstr "Вниз"
+
+msgid "Find Next"
+msgstr "Ðайти Ñледующее"
+
+msgid "Replace"
+msgstr "Заменить"
+
+msgid "Replace All"
+msgstr "Заменить вÑе"
+
+msgid "_Close"
+msgstr "_Закрыть"
+
+msgid "Vim: Received \"die\" request from session manager\n"
+msgstr "Vim: Получен Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð½Ð° прекращение работы от диÑпетчера ÑеанÑов\n"
+
+msgid "Close tab"
+msgstr "Закрыть вкладку"
+
+msgid "New tab"
+msgstr "ÐÐ¾Ð²Ð°Ñ Ð²ÐºÐ»Ð°Ð´ÐºÐ°"
+
+msgid "Open Tab..."
+msgstr "Открыть вкладку..."
+
+msgid "Vim: Main window unexpectedly destroyed\n"
+msgstr "Vim: ОÑновное окно было неожиданно закрыто\n"
+
+msgid "&Filter"
+msgstr "&Фильтр"
+
+msgid "&Cancel"
+msgstr "О&тмена"
+
+msgid "Directories"
+msgstr "Каталоги"
+
+msgid "Filter"
+msgstr "Фильтр"
+
+msgid "&Help"
+msgstr "&Справка"
+
+msgid "Files"
+msgstr "Файлы"
+
+msgid "&OK"
+msgstr "&Да"
+
+msgid "Selection"
+msgstr "Выделение"
+
+msgid "Find &Next"
+msgstr "Ðайти &Ñледующее"
+
+msgid "&Replace"
+msgstr "За&мена"
+
+msgid "Replace &All"
+msgstr "Заменить &вÑе"
+
+msgid "&Undo"
+msgstr "О&тмена"
+
+msgid "Open tab..."
+msgstr "Открыть вкладку..."
+
+msgid "Find string (use '\\\\' to find a '\\')"
+msgstr "ПоиÑк Ñтроки (иÑпользуйте '\\\\' Ð´Ð»Ñ Ð¿Ð¾Ð¸Ñка '\\')"
+
+msgid "Find & Replace (use '\\\\' to find a '\\')"
+msgstr "ПоиÑк и замена (иÑпользуйте '\\\\' Ð´Ð»Ñ Ð¿Ð¾Ð¸Ñка '\\')"
+
+msgid "Not Used"
+msgstr "Ðе иÑпользуетÑÑ"
+
+msgid "Directory\t*.nothing\n"
+msgstr "Каталог\t*.ничего\n"
+
+#, c-format
+msgid "E671: Cannot find window title \"%s\""
+msgstr "E671: Окно Ñ Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²ÐºÐ¾Ð¼ \"%s\" не обнаружено"
+
+#, c-format
+msgid "E243: Argument not supported: \"-%s\"; Use the OLE version."
+msgstr "E243: Параметр не поддерживаетÑÑ: \"-%s\"; иÑпользуйте верÑию OLE."
+
+msgid "E672: Unable to open window inside MDI application"
+msgstr "E672: Ðевозможно открыть окно внутри Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ MDI"
+
+msgid "Vim E458: Cannot allocate colormap entry, some colors may be incorrect"
+msgstr ""
+"Vim E458: Ðевозможно выделить запиÑÑŒ в таблице цвета, некоторые цвета могут "
+"отображатьÑÑ Ð½ÐµÐ¿Ñ€Ð°Ð²Ð¸Ð»ÑŒÐ½Ð¾"
+
+#, c-format
+msgid "E250: Fonts for the following charsets are missing in fontset %s:"
+msgstr "E250: Ð’ наборе шрифтов %s отÑутÑтвуют шрифты Ð´Ð»Ñ Ñледующих кодировок:"
+
+#, c-format
+msgid "E252: Fontset name: %s"
+msgstr "E252: Ðабор шрифтов: %s"
+
+#, c-format
+msgid "Font '%s' is not fixed-width"
+msgstr "Шрифт '%s' не ÑвлÑетÑÑ Ð¼Ð¾Ð½Ð¾ÑˆÐ¸Ñ€Ð¸Ð½Ð½Ñ‹Ð¼"
+
+#, c-format
+msgid "E253: Fontset name: %s"
+msgstr "E253: Ðабор шрифтов: %s"
+
+#, c-format
+msgid "Font0: %s"
+msgstr "Font0: %s"
+
+#, c-format
+msgid "Font1: %s"
+msgstr "Font1: %s"
+
+#, c-format
+msgid "Font%ld width is not twice that of font0"
+msgstr "Ширина шрифта font%ld должна быть вдвое больше ширины шрифта font0"
+
+#, c-format
+msgid "Font0 width: %ld"
+msgstr "Ширина шрифта font0: %ld"
+
+#, c-format
+msgid "Font1 width: %ld"
+msgstr "Ширина шрифта font1: %ld"
+
+msgid "Invalid font specification"
+msgstr "Ðеправильное определение шрифта"
+
+msgid "&Dismiss"
+msgstr "О&тклонить"
+
+msgid "no specific match"
+msgstr "нет Ñпециального ÑовпадениÑ"
+
+msgid "Vim - Font Selector"
+msgstr "Vim — Выбор шрифта"
+
+msgid "Name:"
+msgstr "Ðазвание:"
+
+msgid "Show size in Points"
+msgstr "Показывать размер в пунктах"
+
+msgid "Encoding:"
+msgstr "Кодировка:"
+
+msgid "Font:"
+msgstr "Шрифт:"
+
+msgid "Style:"
+msgstr "Стиль:"
+
+msgid "Size:"
+msgstr "Размер:"
+
+msgid "E256: Hangul automata ERROR"
+msgstr "E256: ОШИБКРавтоматики Хангыл"
+
+msgid "E550: Missing colon"
+msgstr "E550: Пропущено двоеточие"
+
+msgid "E551: Illegal component"
+msgstr "E551: ÐедопуÑтимый компонент"
+
+msgid "E552: digit expected"
+msgstr "E552: ТребуетÑÑ ÑƒÐºÐ°Ð·Ð°Ñ‚ÑŒ цифру"
+
+#, c-format
+msgid "Page %d"
+msgstr "Страница %d"
+
+msgid "No text to be printed"
+msgstr "Печатать нечего"
+
+#, c-format
+msgid "Printing page %d (%d%%)"
+msgstr "Печать ÑÑ‚Ñ€. %d (%d%%)"
+
+#, c-format
+msgid " Copy %d of %d"
+msgstr " ÐšÐ¾Ð¿Ð¸Ñ %d из %d"
+
+#, c-format
+msgid "Printed: %s"
+msgstr "Ðапечатано: %s"
+
+msgid "Printing aborted"
+msgstr "Печать прекращена"
+
+msgid "E455: Error writing to PostScript output file"
+msgstr "E455: Ошибка запиÑи в файл PostScript"
+
+#, c-format
+msgid "E624: Can't open file \"%s\""
+msgstr "E624: Ðевозможно открыть файл \"%s\""
+
+#, c-format
+msgid "E457: Can't read PostScript resource file \"%s\""
+msgstr "E457: Ðевозможно прочитать файл реÑурÑов PostScript \"%s\""
+
+#, c-format
+msgid "E618: file \"%s\" is not a PostScript resource file"
+msgstr "E618: Файл \"%s\" не ÑвлÑетÑÑ Ñ„Ð°Ð¹Ð»Ð¾Ð¼ реÑурÑов PostScript"
+
+#, c-format
+msgid "E619: file \"%s\" is not a supported PostScript resource file"
+msgstr "E619: Файл \"%s\" не ÑвлÑетÑÑ Ð´Ð¾Ð¿ÑƒÑтимым файлом реÑурÑов PostScript"
+
+#, c-format
+msgid "E621: \"%s\" resource file has wrong version"
+msgstr "E621: Файл реÑурÑов \"%s\" неизвеÑтной верÑии"
+
+msgid "E673: Incompatible multi-byte encoding and character set."
+msgstr "E673: ÐеÑовмеÑтимые Ð¼Ð½Ð¾Ð³Ð¾Ð±Ð°Ð¹Ñ‚Ð¾Ð²Ð°Ñ ÐºÐ¾Ð´Ð¸Ñ€Ð¾Ð²ÐºÐ° и набор Ñимволов."
+
+msgid "E674: printmbcharset cannot be empty with multi-byte encoding."
+msgstr "E674: printmbcharset не может быть пуÑтым при многобайтовой кодировке."
+
+msgid "E675: No default font specified for multi-byte printing."
+msgstr "E675: Ðет Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ ÑˆÑ€Ð¸Ñ„Ñ‚Ð° по умолчанию Ð´Ð»Ñ Ð¼Ð½Ð¾Ð³Ð¾Ð±Ð°Ð¹Ñ‚Ð¾Ð²Ð¾Ð¹ печати."
+
+msgid "E324: Can't open PostScript output file"
+msgstr "E324: Ðевозможно открыть файл PostScript"
+
+#, c-format
+msgid "E456: Can't open file \"%s\""
+msgstr "E456: Ðевозможно открыть файл \"%s\""
+
+msgid "E456: Can't find PostScript resource file \"prolog.ps\""
+msgstr "E456: Файл реÑурÑов PostScript \"prolog.ps\" не найден"
+
+msgid "E456: Can't find PostScript resource file \"cidfont.ps\""
+msgstr "E456: Файл реÑурÑов PostScript \"cidfont.ps\" не найден"
+
+#, c-format
+msgid "E456: Can't find PostScript resource file \"%s.ps\""
+msgstr "E456: Файл реÑурÑов PostScript \"%s.ps\" не найден"
+
+#, c-format
+msgid "E620: Unable to convert to print encoding \"%s\""
+msgstr "E620: Ðевозможно преобразовать в кодировку печать \"%s\""
+
+msgid "Sending to printer..."
+msgstr "Отправка на печать..."
+
+msgid "E365: Failed to print PostScript file"
+msgstr "E365: Ðе удалоÑÑŒ выполнить печать файла PostScript"
+
+msgid "Print job sent."
+msgstr "Задание на печать отправлено."
+
+msgid "Add a new database"
+msgstr "Добавить новую базу данных"
+
+msgid "Query for a pattern"
+msgstr "Ð—Ð°Ð¿Ñ€Ð¾Ñ Ð¿Ð¾ шаблону"
+
+msgid "Show this message"
+msgstr "Показать Ñто Ñообщение"
+
+msgid "Kill a connection"
+msgstr "Убить Ñоединение"
+
+msgid "Reinit all connections"
+msgstr "Заново инициализировать вÑе ÑоединениÑ"
+
+msgid "Show connections"
+msgstr "Показать ÑоединениÑ"
+
+#, c-format
+msgid "E560: Usage: cs[cope] %s"
+msgstr "E560: ИÑпользование: cs[cope] %s"
+
+msgid "This cscope command does not support splitting the window.\n"
+msgstr "Эта команда cscope не поддерживает разделение окна.\n"
+
+msgid "E562: Usage: cstag <ident>"
+msgstr "E562: ИÑпользование: cstag <имÑ>"
+
+msgid "E257: cstag: tag not found"
+msgstr "E257: cstag: метка не найдена"
+
+#, c-format
+msgid "E563: stat(%s) error: %d"
+msgstr "E563: Ошибка stat(%s): %d"
+
+msgid "E563: stat error"
+msgstr "E563: Ошибка stat"
+
+#, c-format
+msgid "E564: %s is not a directory or a valid cscope database"
+msgstr "E564: %s не ÑвлÑетÑÑ ÐºÐ°Ñ‚Ð°Ð»Ð¾Ð³Ð¾Ð¼ или именем базы cscope"
+
+#, c-format
+msgid "Added cscope database %s"
+msgstr "Добавлена база данных cscope %s"
+
+#, c-format
+msgid "E262: error reading cscope connection %ld"
+msgstr "E262: Ошибка Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ð¸ от ÑÐ¾ÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ cscope %ld"
+
+msgid "E561: unknown cscope search type"
+msgstr "E561: ÐеизвеÑтный тип поиÑка cscope"
+
+msgid "E566: Could not create cscope pipes"
+msgstr "E566: Ðевозможно Ñоздать трубу Ð´Ð»Ñ cscope"
+
+msgid "E622: Could not fork for cscope"
+msgstr "E622: Ðевозможно выполнить fork() Ð´Ð»Ñ cscope"
+
+msgid "cs_create_connection setpgid failed"
+msgstr "cs_create_connection: не удалоÑÑŒ выполнить setpgid"
+
+msgid "cs_create_connection exec failed"
+msgstr "cs_create_connection: не удалоÑÑŒ выполнить exec"
+
+msgid "cs_create_connection: fdopen for to_fp failed"
+msgstr "cs_create_connection: не удалоÑÑŒ выполнить fdopen Ð´Ð»Ñ to_fp"
+
+msgid "cs_create_connection: fdopen for fr_fp failed"
+msgstr "cs_create_connection: не удалоÑÑŒ выполнить fdopen Ð´Ð»Ñ fr_fp"
+
+msgid "E623: Could not spawn cscope process"
+msgstr "E623: Ðе удалоÑÑŒ запуÑтить процеÑÑ cscope"
+
+msgid "E567: no cscope connections"
+msgstr "E567: Соединений Ñ cscope не Ñоздано"
+
+#, c-format
+msgid "E469: invalid cscopequickfix flag %c for %c"
+msgstr "E469: Ðеправильный флаг cscopequickfix %c Ð´Ð»Ñ %c"
+
+#, c-format
+msgid "E259: no matches found for cscope query %s of %s"
+msgstr "E259: Ðе найдено ÑоответÑтвий по запроÑу cscope %s Ð´Ð»Ñ %s"
+
+msgid "cscope commands:\n"
+msgstr "Команды cscope:\n"
+
+#, c-format
+msgid "%-5s: %s%*s (Usage: %s)"
+msgstr "%-5s: %s%*s (иÑпользование: %s)"
+
+msgid ""
+"\n"
+" a: Find assignments to this symbol\n"
+" c: Find functions calling this function\n"
+" d: Find functions called by this function\n"
+" e: Find this egrep pattern\n"
+" f: Find this file\n"
+" g: Find this definition\n"
+" i: Find files #including this file\n"
+" s: Find this C symbol\n"
+" t: Find this text string\n"
+msgstr ""
+"\n"
+" a: Ðайти приÑÐ²Ð°Ð¸Ð²Ð°Ð½Ð¸Ñ Ð´Ð»Ñ Ñтого Ñимвола\n"
+" c: Ðайти функции вызывающие Ñту функцию\n"
+" d: Ðайти функции вызываемые Ñтой функцией\n"
+" e: Ðайти Ñтот шаблон egrep\n"
+" f: Ðайти Ñтот файл\n"
+" g: Ðайти Ñто определение\n"
+" i: Ðайти файлы включающие (#include) Ñтот файл\n"
+" s: Ðайти Ñтот C-Ñимвол\n"
+" t: Ðайти Ñту текÑтовую Ñтроку\n"
+
+#, c-format
+msgid "E625: cannot open cscope database: %s"
+msgstr "E625: Ðевозможно открыть базу данных cscope: %s"
+
+msgid "E626: cannot get cscope database information"
+msgstr "E626: Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾ базе данных cscope недоÑтупна"
+
+msgid "E568: duplicate cscope database not added"
+msgstr "E568: Ð”Ð°Ð½Ð½Ð°Ñ Ð±Ð°Ð·Ð° данных cscope уже подÑоединена"
+
+#, c-format
+msgid "E261: cscope connection %s not found"
+msgstr "E261: Соединение Ñ cscope %s не обнаружено"
+
+#, c-format
+msgid "cscope connection %s closed"
+msgstr "Ñоединение Ñ cscope %s закрыто"
+
+msgid "E570: fatal error in cs_manage_matches"
+msgstr "E570: КритичеÑÐºÐ°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ° в cs_manage_matches"
+
+#, c-format
+msgid "Cscope tag: %s"
+msgstr "Метка cscope: %s"
+
+msgid ""
+"\n"
+" # line"
+msgstr ""
+"\n"
+" # Ñтрока"
+
+msgid "filename / context / line\n"
+msgstr "Ð¸Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð° / контекÑÑ‚ / Ñтрока\n"
+
+#, c-format
+msgid "E609: Cscope error: %s"
+msgstr "E609: Ошибка cscope: %s"
+
+msgid "All cscope databases reset"
+msgstr "Перезагрузка вÑех баз данных cscope"
+
+msgid "no cscope connections\n"
+msgstr "ÑÐ¾ÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ Ñ cscope отÑутÑтвуют\n"
+
+msgid " # pid database name prepend path\n"
+msgstr " # pid база данных начальный путь\n"
+
+msgid "Lua library cannot be loaded."
+msgstr "Библиотека Lua не может быть загружена."
+
+msgid "cannot save undo information"
+msgstr "невозможно Ñохранить информацию об отмене операции"
+
+msgid ""
+"E815: Sorry, this command is disabled, the MzScheme libraries could not be "
+"loaded."
+msgstr ""
+"E815: К Ñожалению Ñта команда не работает, поÑкольку не загружена библиотека "
+"MzScheme."
+
+msgid ""
+"E895: Sorry, this command is disabled, the MzScheme's racket/base module "
+"could not be loaded."
+msgstr ""
+"E895: К Ñожалению Ñта команда не работает, поÑкольку не загружен модуль "
+"racket/base Ð´Ð»Ñ MzScheme."
+
+msgid "invalid expression"
+msgstr "неправильное выражение"
+
+msgid "expressions disabled at compile time"
+msgstr "Ð²Ñ‹Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð¾Ñ‚ÐºÐ»ÑŽÑ‡ÐµÐ½Ñ‹ при компилÑции"
+
+msgid "hidden option"
+msgstr "ÑÐºÑ€Ñ‹Ñ‚Ð°Ñ Ð¾Ð¿Ñ†Ð¸Ñ"
+
+msgid "unknown option"
+msgstr "неизвеÑÑ‚Ð½Ð°Ñ Ð¾Ð¿Ñ†Ð¸Ñ"
+
+msgid "window index is out of range"
+msgstr "Ð¸Ð½Ð´ÐµÐºÑ Ð¾ÐºÐ½Ð° за пределами диапазона"
+
+msgid "couldn't open buffer"
+msgstr "невозможно открыть буфер"
+
+msgid "cannot delete line"
+msgstr "невозможно удалить Ñтроку"
+
+msgid "cannot replace line"
+msgstr "невозможно заменить Ñтроку"
+
+msgid "cannot insert line"
+msgstr "невозможно вÑтавить Ñтроку"
+
+msgid "string cannot contain newlines"
+msgstr "Ñтрока не может Ñодержать Ñимвол новой Ñтроки"
+
+msgid "error converting Scheme values to Vim"
+msgstr "невозможно преобразовать Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Scheme в Vim"
+
+msgid "Vim error: ~a"
+msgstr "ошибка Vim: ~a"
+
+msgid "Vim error"
+msgstr "ошибка Vim"
+
+msgid "buffer is invalid"
+msgstr "неправильный буфер"
+
+msgid "window is invalid"
+msgstr "неправильное окно"
+
+msgid "linenr out of range"
+msgstr "номер Ñтроки за пределами диапазона"
+
+msgid "not allowed in the Vim sandbox"
+msgstr "не допуÑкаетÑÑ Ð² пеÑочнице Vim"
+
+msgid "E836: This Vim cannot execute :python after using :py3"
+msgstr "E836: Данный Vim не может выполнить :python поÑле иÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ :py3"
+
+msgid ""
+"E263: Sorry, this command is disabled, the Python library could not be "
+"loaded."
+msgstr ""
+"E263: К Ñожалению Ñта команда не работает, поÑкольку не загружена библиотека "
+"Python"
+
+msgid ""
+"E887: Sorry, this command is disabled, the Python's site module could not be "
+"loaded."
+msgstr ""
+"E887: К Ñожалению Ñта команда не работает, поÑкольку не загружен модуль "
+"Python site."
+
+msgid "E659: Cannot invoke Python recursively"
+msgstr "E659: Ðевозможно выполнить рекурÑивный вызов Python"
+
+msgid "E837: This Vim cannot execute :py3 after using :python"
+msgstr "E837: Данный Vim не может выполнить :py3 поÑле иÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ :python"
+
+msgid "E265: $_ must be an instance of String"
+msgstr "E265: $_ должен быть ÑкземплÑром или Ñтрокой"
+
+msgid ""
+"E266: Sorry, this command is disabled, the Ruby library could not be loaded."
+msgstr ""
+"E266: К Ñожалению Ñта команда не работает, поÑкольку не загружена библиотека "
+"Ruby"
+
+msgid "E267: unexpected return"
+msgstr "E267: Ðеожиданный return"
+
+msgid "E268: unexpected next"
+msgstr "E268: Ðеожиданный next"
+
+msgid "E269: unexpected break"
+msgstr "E269: Ðеожиданный break"
+
+msgid "E270: unexpected redo"
+msgstr "E270: Ðеожиданный redo"
+
+msgid "E271: retry outside of rescue clause"
+msgstr "E271: retry вне оператора rescue"
+
+msgid "E272: unhandled exception"
+msgstr "E272: Ðеобработанное иÑключение"
+
+#, c-format
+msgid "E273: unknown longjmp status %d"
+msgstr "E273: ÐеизвеÑтное ÑоÑтоÑние longjmp %d"
+
+msgid "invalid buffer number"
+msgstr "неправильный номер буфера"
+
+msgid "not implemented yet"
+msgstr "пока не реализовано"
+
+msgid "cannot set line(s)"
+msgstr "невозможно назначить Ñтроку или Ñтроки"
+
+msgid "invalid mark name"
+msgstr "неправильное Ð¸Ð¼Ñ Ð¾Ñ‚Ð¼ÐµÑ‚ÐºÐ¸"
+
+msgid "mark not set"
+msgstr "отметка не уÑтановлена"
+
+#, c-format
+msgid "row %d column %d"
+msgstr "Ñ€Ñд %d колонка %d"
+
+msgid "cannot insert/append line"
+msgstr "невозможно вÑтавить или добавить Ñтроку"
+
+msgid "line number out of range"
+msgstr "номер Ñтроки за пределами диапазона"
+
+msgid "unknown flag: "
+msgstr "неизвеÑтный флаг: "
+
+msgid "unknown vimOption"
+msgstr "неизвеÑÑ‚Ð½Ð°Ñ vimOption"
+
+msgid "keyboard interrupt"
+msgstr "клавиатурное прерывание"
+
+msgid "vim error"
+msgstr "ошибка VIM"
+
+msgid "cannot create buffer/window command: object is being deleted"
+msgstr "невозможно Ñоздать команду буфера или окна: объект в процеÑÑе удалениÑ"
+
+msgid ""
+"cannot register callback command: buffer/window is already being deleted"
+msgstr ""
+"невозможно зарегиÑтрировать команду Ñ Ð¾Ð±Ñ€Ð°Ñ‚Ð½Ñ‹Ð¼ вызовом: буфер или окно в "
+"процеÑÑе удалениÑ"
+
+msgid ""
+"E280: TCL FATAL ERROR: reflist corrupt!? Please report this to vim-dev@vim."
+"org"
+msgstr ""
+"E280: КРИТИЧЕСКÐЯ ОШИБКРTCL: повреждён ÑпиÑок ÑÑылок?! Сообщите об Ñтом по "
+"адреÑу vim-dev@vim.org"
+
+msgid "cannot register callback command: buffer/window reference not found"
+msgstr ""
+"невозможно зарегиÑтрировать команду Ñ Ð¾Ð±Ñ€Ð°Ñ‚Ð½Ñ‹Ð¼ вызовом: ÑÑылка на буфер или "
+"окно не обнаружена"
+
+msgid ""
+"E571: Sorry, this command is disabled: the Tcl library could not be loaded."
+msgstr ""
+"E571: К Ñожалению Ñта команда не работает, поÑкольку не загружена библиотека "
+"Tcl"
+
+#, c-format
+msgid "E572: exit code %d"
+msgstr "E572: Код выхода %d"
+
+msgid "cannot get line"
+msgstr "невозможно получить Ñтроку"
+
+msgid "Unable to register a command server name"
+msgstr "Ðевозможно зарегиÑтрировать Ð¸Ð¼Ñ Ñервера команд"
+
+msgid "E248: Failed to send command to the destination program"
+msgstr "E248: Ðе удалаÑÑŒ отправка команды в другую программу"
+
+#, c-format
+msgid "E573: Invalid server id used: %s"
+msgstr "E573: ИÑпользуетÑÑ Ð½ÐµÐ¿Ñ€Ð°Ð²Ð¸Ð»ÑŒÐ½Ñ‹Ð¹ id Ñервера: %s"
+
+msgid "E251: VIM instance registry property is badly formed. Deleted!"
+msgstr ""
+"E251: Ðеправильно Ñформировано значение данного процеÑÑа VIM в рееÑтре. "
+"Удалено!"
+
+#, c-format
+msgid "E938: Duplicate key in JSON: \"%s\""
+msgstr "E938: Повтор ключа в JSON: \"%s\""
+
+#, c-format
+msgid "E696: Missing comma in List: %s"
+msgstr "E696: Пропущена запÑÑ‚Ð°Ñ Ð² ÑпиÑке: %s"
+
+#, c-format
+msgid "E697: Missing end of List ']': %s"
+msgstr "E697: Пропущено окончание ÑпиÑка ']': %s"
+
+msgid "Unknown option argument"
+msgstr "ÐеизвеÑтный необÑзательный параметр"
+
+msgid "Too many edit arguments"
+msgstr "Слишком много параметров редактированиÑ"
+
+msgid "Argument missing after"
+msgstr "Пропущен параметр поÑле"
+
+msgid "Garbage after option argument"
+msgstr "МуÑор поÑле необÑзательного параметра"
+
+msgid "Too many \"+command\", \"-c command\" or \"--cmd command\" arguments"
+msgstr ""
+"Слишком много параметров \"+команда\", \"-c команда\" или \"--cmd команда\""
+
+msgid "Invalid argument for"
+msgstr "ÐедопуÑтимый параметр длÑ"
+
+#, c-format
+msgid "%d files to edit\n"
+msgstr "Файлов Ð´Ð»Ñ Ñ€ÐµÐ´Ð°ÐºÑ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ: %d\n"
+
+msgid "netbeans is not supported with this GUI\n"
+msgstr "NetBeans не поддерживаетÑÑ Ñ Ñтим графичеÑким интерфейÑом\n"
+
+msgid "'-nb' cannot be used: not enabled at compile time\n"
+msgstr "Ðевозможно иÑпользовать '-nb': не включено при компилÑции\n"
+
+msgid "This Vim was not compiled with the diff feature."
+msgstr ""
+"Данный Vim был Ñкомпилирован Ñ Ð²Ñ‹ÐºÐ»ÑŽÑ‡ÐµÐ½Ð½Ð¾Ð¹ оÑобенноÑтью проÑмотра отличий"
+
+msgid "Attempt to open script file again: \""
+msgstr "Попытка повторного Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ð¸Ñ Ñ„Ð°Ð¹Ð»Ð° ÑценариÑ: \""
+
+msgid "Cannot open for reading: \""
+msgstr "Ðевозможно открыть Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ: \""
+
+msgid "Cannot open for script output: \""
+msgstr "Ðевозможно открыть Ð´Ð»Ñ Ð²Ñ‹Ð²Ð¾Ð´Ð° ÑценариÑ: \""
+
+msgid "Vim: Error: Failure to start gvim from NetBeans\n"
+msgstr "Vim: Ошибка: Ðе удалоÑÑŒ запуÑтить gvim из NetBeans\n"
+
+msgid "Vim: Error: This version of Vim does not run in a Cygwin terminal\n"
+msgstr "Vim: Ошибка: Ð”Ð°Ð½Ð½Ð°Ñ Ð²ÐµÑ€ÑÐ¸Ñ Vim не работает в терминале Cygwin\n"
+
+msgid "Vim: Warning: Output is not to a terminal\n"
+msgstr "Vim: Предупреждение: Вывод оÑущеÑтвлÑетÑÑ Ð½Ðµ на терминал\n"
+
+msgid "Vim: Warning: Input is not from a terminal\n"
+msgstr "Vim: Предупреждение: Ввод проиÑходит не Ñ Ñ‚ÐµÑ€Ð¼Ð¸Ð½Ð°Ð»Ð°\n"
+
+msgid "pre-vimrc command line"
+msgstr "ÐºÐ¾Ð¼Ð°Ð½Ð´Ð½Ð°Ñ Ñтрока перед выполнением vimrc"
+
+#, c-format
+msgid "E282: Cannot read from \"%s\""
+msgstr "E282: Ðевозможно выполнить чтение из \"%s\""
+
+msgid ""
+"\n"
+"More info with: \"vim -h\"\n"
+msgstr ""
+"\n"
+"Ð”Ð¾Ð¿Ð¾Ð»Ð½Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð°Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ: \"vim -h\"\n"
+
+msgid "[file ..] edit specified file(s)"
+msgstr "[файл ..] редактирование указанных файлов"
+
+msgid "- read text from stdin"
+msgstr "- чтение текÑта из потока ввода stdin"
+
+msgid "-t tag edit file where tag is defined"
+msgstr "-t метка редактирование файла Ñ ÑƒÐºÐ°Ð·Ð°Ð½Ð½Ð¾Ð¹ меткой"
+
+# \n\t\t.. Ð´Ð»Ñ ÑƒÐ¼ÐµÑ‰ÐµÐ½Ð¸Ñ Ð² 80 Ñтолбцов
+msgid "-q [errorfile] edit file with first error"
+msgstr ""
+"-q [файл-ошибок]\n"
+"\t\t\t\t редактирование файла Ñ Ð¿ÐµÑ€Ð²Ð¾Ð¹ ошибкой"
+
+msgid ""
+"\n"
+"\n"
+"Usage:"
+msgstr ""
+"\n"
+"\n"
+"ИÑпользование:"
+
+msgid " vim [arguments] "
+msgstr " vim [параметры] "
+
+msgid ""
+"\n"
+" or:"
+msgstr ""
+"\n"
+" или:"
+
+msgid ""
+"\n"
+"Where case is ignored prepend / to make flag upper case"
+msgstr ""
+"\n"
+"ЕÑли региÑÑ‚Ñ€ игнорируетÑÑ, добавьте перед флагом / Ð´Ð»Ñ Ð²ÐµÑ€Ñ…Ð½ÐµÐ³Ð¾ региÑтра"
+
+msgid ""
+"\n"
+"\n"
+"Arguments:\n"
+msgstr ""
+"\n"
+"\n"
+"Параметры:\n"
+
+msgid "--\t\t\tOnly file names after this"
+msgstr "--\t\t\tДалее указываютÑÑ Ñ‚Ð¾Ð»ÑŒÐºÐ¾ имена файлов"
+
+msgid "--literal\t\tDon't expand wildcards"
+msgstr "--literal\t\tÐе выполнÑÑ‚ÑŒ подÑтановку по маÑке"
+
+msgid "-register\t\tRegister this gvim for OLE"
+msgstr "-register\t\tЗарегиÑтрировать Ñтот gvim Ð´Ð»Ñ OLE"
+
+msgid "-unregister\t\tUnregister gvim for OLE"
+msgstr "-unregister\t\tОтключить региÑтрацию данного gvim Ð´Ð»Ñ OLE"
+
+msgid "-g\t\t\tRun using GUI (like \"gvim\")"
+msgstr "-g\t\t\tЗапуÑтить Ñ Ð³Ñ€Ð°Ñ„Ð¸Ñ‡ÐµÑким интерфейÑом (как \"gvim\")"
+
+msgid "-f or --nofork\tForeground: Don't fork when starting GUI"
+msgstr "-f или --nofork\tÐ’ активной задаче: Ðе выполнÑÑ‚ÑŒ fork при запуÑке GUI"
+
+msgid "-v\t\t\tVi mode (like \"vi\")"
+msgstr "-v\t\t\tРежим Vi (как \"vi\")"
+
+msgid "-e\t\t\tEx mode (like \"ex\")"
+msgstr "-e\t\t\tРежим Ex (как \"ex\")"
+
+msgid "-E\t\t\tImproved Ex mode"
+msgstr "-E\t\t\tУлучшенный режим Ex"
+
+msgid "-s\t\t\tSilent (batch) mode (only for \"ex\")"
+msgstr "-s\t\t\tТихий (пакетный) режим (только Ð´Ð»Ñ \"ex\")"
+
+msgid "-d\t\t\tDiff mode (like \"vimdiff\")"
+msgstr "-d\t\t\tРежим отличий (как \"vimdiff\")"
+
+msgid "-y\t\t\tEasy mode (like \"evim\", modeless)"
+msgstr "-y\t\t\tПроÑтой режим (как \"evim\", безрежимный)"
+
+msgid "-R\t\t\tReadonly mode (like \"view\")"
+msgstr "-R\t\t\tТолько Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ (как \"view\")"
+
+msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
+msgstr "-Z\t\t\tОграниченный режим (как \"rvim\")"
+
+msgid "-m\t\t\tModifications (writing files) not allowed"
+msgstr "-m\t\t\tБез возможноÑти ÑÐ¾Ñ…Ñ€Ð°Ð½ÐµÐ½Ð¸Ñ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ð¹ (запиÑи файлов)"
+
+msgid "-M\t\t\tModifications in text not allowed"
+msgstr "-M\t\t\tБез возможноÑти внеÑÐµÐ½Ð¸Ñ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ð¹ в текÑÑ‚"
+
+msgid "-b\t\t\tBinary mode"
+msgstr "-b\t\t\tДвоичный режим"
+
+msgid "-l\t\t\tLisp mode"
+msgstr "-l\t\t\tРежим Lisp"
+
+msgid "-C\t\t\tCompatible with Vi: 'compatible'"
+msgstr "-C\t\t\tРежим ÑовмеÑтимоÑти Ñ Vi: 'compatible'"
+
+msgid "-N\t\t\tNot fully Vi compatible: 'nocompatible'"
+msgstr "-N\t\t\tРежим неполной ÑовмеÑтимоÑти Ñ Vi: 'nocompatible'"
+
+# \n\t\t.. Ð´Ð»Ñ ÑƒÐ¼ÐµÑ‰ÐµÐ½Ð¸Ñ Ð² 80 Ñтолбцов
+msgid "-V[N][fname]\t\tBe verbose [level N] [log messages to fname]"
+msgstr ""
+"-V[N][файл]\t\tВыводить дополнительные ÑообщениÑ\n"
+"\t\t\t\t[уровень N] [запиÑывать в файл]"
+
+msgid "-D\t\t\tDebugging mode"
+msgstr "-D\t\t\tРежим отладки"
+
+msgid "-n\t\t\tNo swap file, use memory only"
+msgstr "-n\t\t\tБез Ñвоп-файла, иÑпользуетÑÑ Ñ‚Ð¾Ð»ÑŒÐºÐ¾ памÑÑ‚ÑŒ"
+
+msgid "-r\t\t\tList swap files and exit"
+msgstr "-r\t\t\tВывеÑти ÑпиÑок Ñвоп-файлов и завершить работу"
+
+msgid "-r (with file name)\tRecover crashed session"
+msgstr "-r (Ñ Ð¸Ð¼ÐµÐ½ÐµÐ¼ файла)\tВоÑÑтановить аварийно завершённый ÑеанÑ"
+
+msgid "-L\t\t\tSame as -r"
+msgstr "-L\t\t\tТо же, что и -r"
+
+msgid "-f\t\t\tDon't use newcli to open window"
+msgstr "-f\t\t\tÐе иÑпользовать newcli Ð´Ð»Ñ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ð¸Ñ Ð¾ÐºÐ½Ð°"
+
+msgid "-dev <device>\t\tUse <device> for I/O"
+msgstr "-dev <уÑтройÑтво>\t\tИÑпользовать Ð´Ð»Ñ I/O указанное <уÑтройÑтво>"
+
+msgid "-A\t\t\tStart in Arabic mode"
+msgstr "-A\t\t\tЗапуÑк в ÐрабÑком режиме"
+
+msgid "-H\t\t\tStart in Hebrew mode"
+msgstr "-H\t\t\tЗапуÑк в режиме \"Иврит\""
+
+msgid "-F\t\t\tStart in Farsi mode"
+msgstr "-F\t\t\tЗапуÑк в режиме \"ФарÑи\""
+
+msgid "-T <terminal>\tSet terminal type to <terminal>"
+msgstr "-T <терминал>\tÐазначить указанный тип <терминала>"
+
+msgid "--not-a-term\t\tSkip warning for input/output not being a terminal"
+msgstr "--not-a-term\t\tÐе предупреждать при вводе/выводе не в терминал"
+
+msgid "--ttyfail\t\tExit if input or output is not a terminal"
+msgstr "--ttyfail\t\tВыйти при вводе/выводе не в терминал"
+
+msgid "-u <vimrc>\t\tUse <vimrc> instead of any .vimrc"
+msgstr "-u <vimrc>\t\tИÑпользовать <vimrc> вмеÑто любых файлов .vimrc"
+
+msgid "-U <gvimrc>\t\tUse <gvimrc> instead of any .gvimrc"
+msgstr "-U <gvimrc>\t\tИÑпользовать <gvimrc> вмеÑто любых файлов .gvimrc"
+
+msgid "--noplugin\t\tDon't load plugin scripts"
+msgstr "--noplugin\t\tÐе загружать Ñценарии модулей"
+
+# \n\t\t.. Ð´Ð»Ñ ÑƒÐ¼ÐµÑ‰ÐµÐ½Ð¸Ñ Ð² 80 Ñтолбцов
+msgid "-p[N]\t\tOpen N tab pages (default: one for each file)"
+msgstr ""
+"-p[N]\t\tОткрыть N вкладок (по умолчанию: по одной\n"
+"\t\t\t\tна каждый файл)"
+
+# \n\t\t.. Ð´Ð»Ñ ÑƒÐ¼ÐµÑ‰ÐµÐ½Ð¸Ñ Ð² 80 Ñтолбцов
+msgid "-o[N]\t\tOpen N windows (default: one for each file)"
+msgstr ""
+"-o[N]\t\tОткрыть N окон (по умолчанию: по одному\n"
+"\t\t\t\tна каждый файл)"
+
+msgid "-O[N]\t\tLike -o but split vertically"
+msgstr "-O[N]\t\tТо же, что и -o, но Ñ Ð²ÐµÑ€Ñ‚Ð¸ÐºÐ°Ð»ÑŒÐ½Ñ‹Ð¼ разделением окон"
+
+msgid "+\t\t\tStart at end of file"
+msgstr "+\t\t\tÐачать редактирование в конце файла"
+
+msgid "+<lnum>\t\tStart at line <lnum>"
+msgstr "+<lnum>\t\tÐачать редактирование в Ñтроке Ñ Ð½Ð¾Ð¼ÐµÑ€Ð¾Ð¼ <lnum>"
+
+msgid "--cmd <command>\tExecute <command> before loading any vimrc file"
+msgstr "--cmd <команда>\tВыполнить <команду> перед загрузкой файла vimrc"
+
+msgid "-c <command>\t\tExecute <command> after loading the first file"
+msgstr "-c <команда>\t\tВыполнить <команду> поÑле загрузки первого файла"
+
+# \n\t\t.. Ð´Ð»Ñ ÑƒÐ¼ÐµÑ‰ÐµÐ½Ð¸Ñ Ð² 80 Ñтолбцов
+msgid "-S <session>\t\tSource file <session> after loading the first file"
+msgstr ""
+"-S <ÑеанÑ>\t\tПрочитать Ñценарий <ÑеанÑа> поÑле загрузки\n"
+"\t\t\t\tпервого файла"
+
+# \n\t\t.. Ð´Ð»Ñ ÑƒÐ¼ÐµÑ‰ÐµÐ½Ð¸Ñ Ð² 80 Ñтолбцов
+msgid "-s <scriptin>\tRead Normal mode commands from file <scriptin>"
+msgstr ""
+"-s <Ñценарий>\tПрочитать команды Обычного режима из\n"
+"\t\t\t\tфайла <ÑценариÑ>"
+
+msgid "-w <scriptout>\tAppend all typed commands to file <scriptout>"
+msgstr "-w <Ñценарий>\tДобавлÑÑ‚ÑŒ вÑе введённые команды в файл <ÑценариÑ>"
+
+msgid "-W <scriptout>\tWrite all typed commands to file <scriptout>"
+msgstr "-W <Ñценарий>\tЗапиÑать вÑе введённые команды в файл <ÑценариÑ>"
+
+msgid "-x\t\t\tEdit encrypted files"
+msgstr "-x\t\t\tРедактирование зашифрованных файлов"
+
+msgid "-display <display>\tConnect vim to this particular X-server"
+msgstr "-display <Ñкран>\tПодÑоединить Vim к указанному X-Ñерверу"
+
+msgid "-X\t\t\tDo not connect to X server"
+msgstr "-X\t\t\tÐе выполнÑÑ‚ÑŒ Ñоединение Ñ Ñервером X"
+
+msgid "--remote <files>\tEdit <files> in a Vim server if possible"
+msgstr "--remote <файлы>\tПо возможноÑти редактировать <файлы> на Ñервере Vim"
+
+msgid "--remote-silent <files> Same, don't complain if there is no server"
+msgstr "--remote-silent <файлы> То же, но без жалоб на отÑутÑтвие Ñервера"
+
+msgid ""
+"--remote-wait <files> As --remote but wait for files to have been edited"
+msgstr ""
+"--remote-wait <файлы> То же, что и --remote, но Ñ Ð¾Ð¶Ð¸Ð´Ð°Ð½Ð¸ÐµÐ¼ завершениÑ"
+
+msgid ""
+"--remote-wait-silent <files> Same, don't complain if there is no server"
+msgstr ""
+"--remote-wait-silent <файлы> То же, но без жалоб на отÑутÑтвие Ñервера"
+
+msgid ""
+"--remote-tab[-wait][-silent] <files> As --remote but use tab page per file"
+msgstr ""
+"--remote-tab[-wait][-silent] <файлы> То же, что и --remote, но Ñ Ð²ÐºÐ»Ð°Ð´ÐºÐ°Ð¼Ð¸"
+
+msgid "--remote-send <keys>\tSend <keys> to a Vim server and exit"
+msgstr "--remote-send <кнопки>\tОтправить <кнопки> на Ñервер Vim и выйти"
+
+msgid "--remote-expr <expr>\tEvaluate <expr> in a Vim server and print result"
+msgstr "--remote-expr <выраж>\tВычиÑлить <выраж> на Ñервере Vim и напечатать"
+
+msgid "--serverlist\t\tList available Vim server names and exit"
+msgstr "--serverlist\t\tПоказать ÑпиÑок имён Ñерверов Vim и завершить работу"
+
+msgid "--servername <name>\tSend to/become the Vim server <name>"
+msgstr ""
+"--servername <имÑ>\tОтправить на/Ñтать Ñервером Vim Ñ ÑƒÐºÐ°Ð·Ð°Ð½Ð½Ñ‹Ð¼ <именем>"
+
+msgid "--startuptime <file>\tWrite startup timing messages to <file>"
+msgstr "--startuptime <файл>\tЗапиÑать временную метку о запуÑке в <файл>"
+
+msgid "-i <viminfo>\t\tUse <viminfo> instead of .viminfo"
+msgstr "-i <viminfo>\t\tИÑпользовать вмеÑто .viminfo файл <viminfo>"
+
+msgid "--clean\t\t'nocompatible', Vim defaults, no plugins, no viminfo"
+msgstr ""
+"--clean\t\tÐÐµÐ¿Ð¾Ð»Ð½Ð°Ñ ÑовмеÑтимоÑÑ‚ÑŒ Ñ Vi, Vim по умолчанию,\n"
+"\t\t\t\tбез модулей, без viminfo"
+
+msgid "-h or --help\tPrint Help (this message) and exit"
+msgstr "-h или --help\tВывеÑти Ñправку (Ñто Ñообщение) и завершить работу"
+
+msgid "--version\t\tPrint version information and exit"
+msgstr "--version\t\tВывеÑти информацию о верÑии Vim и завершить работу"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Motif version):\n"
+msgstr ""
+"\n"
+"Параметры Ð´Ð»Ñ gvim (верÑÐ¸Ñ Motif):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (neXtaw version):\n"
+msgstr ""
+"\n"
+"Параметры Ð´Ð»Ñ gvim (верÑÐ¸Ñ neXtaw):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Athena version):\n"
+msgstr ""
+"\n"
+"Параметры Ð´Ð»Ñ gvim (верÑÐ¸Ñ Athena):\n"
+
+msgid "-display <display>\tRun vim on <display>"
+msgstr "-display <диÑплей>\tЗапуÑтить Vim на указанном <диÑплее>"
+
+msgid "-iconic\t\tStart vim iconified"
+msgstr "-iconic\t\tЗапуÑтить Vim в Ñвёрнутом виде"
+
+msgid "-background <color>\tUse <color> for the background (also: -bg)"
+msgstr "-background <цвет>\tИÑпользовать указанный <цвет> Ð´Ð»Ñ Ñ„Ð¾Ð½Ð° (или -bg)"
+
+msgid "-foreground <color>\tUse <color> for normal text (also: -fg)"
+msgstr "-foreground <цвет>\tИÑпользовать <цвет> Ð´Ð»Ñ Ð¾Ð±Ñ‹Ñ‡Ð½Ð¾Ð³Ð¾ текÑта (или -fg)"
+
+msgid "-font <font>\t\tUse <font> for normal text (also: -fn)"
+msgstr "-font <шрифт>\tИÑпользовать <шрифт> Ð´Ð»Ñ Ð¾Ð±Ñ‹Ñ‡Ð½Ð¾Ð³Ð¾ текÑта (или -fn)"
+
+msgid "-boldfont <font>\tUse <font> for bold text"
+msgstr "-boldfont <шрифт>\tИÑпользовать <шрифт> Ð´Ð»Ñ Ð¶Ð¸Ñ€Ð½Ð¾Ð³Ð¾ текÑта"
+
+msgid "-italicfont <font>\tUse <font> for italic text"
+msgstr "-italicfont <шрифт>\tИÑпользовать <шрифт> Ð´Ð»Ñ Ð½Ð°ÐºÐ»Ð¾Ð½Ð½Ð¾Ð³Ð¾ текÑта"
+
+msgid "-geometry <geom>\tUse <geom> for initial geometry (also: -geom)"
+msgstr "-geometry <геометриÑ>\tИÑпользовать начальную <геометрию> (или -geom)"
+
+msgid "-borderwidth <width>\tUse a border width of <width> (also: -bw)"
+msgstr "-borderwidth <ширина>\tИÑпользовать <ширину> бордюра (или -bw)"
+
+msgid "-scrollbarwidth <width> Use a scrollbar width of <width> (also: -sw)"
+msgstr ""
+"-scrollbarwidth <ширина> ИÑпользовать ширину полоÑÑ‹ прокрутки (или -sw)"
+
+msgid "-menuheight <height>\tUse a menu bar height of <height> (also: -mh)"
+msgstr "-menuheight <выÑота>\tИÑпользовать <выÑоту> меню (или -mh)"
+
+msgid "-reverse\t\tUse reverse video (also: -rv)"
+msgstr "-reverse\t\tИÑпользовать инверÑный видеорежим (или -rv)"
+
+msgid "+reverse\t\tDon't use reverse video (also: +rv)"
+msgstr "+reverse\t\tÐе иÑпользовать инверÑный видеорежим (или +rv)"
+
+msgid "-xrm <resource>\tSet the specified resource"
+msgstr "-xrm <реÑурÑ>\tУÑтановить указанный <реÑурÑ>"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (GTK+ version):\n"
+msgstr ""
+"\n"
+"Параметры Ð´Ð»Ñ gvim (верÑÐ¸Ñ GTK+):\n"
+
+msgid "-display <display>\tRun vim on <display> (also: --display)"
+msgstr ""
+"-display <диÑплей>\tЗапуÑтить Vim на указанном <диÑплее> (или --display)"
+
+msgid "--role <role>\tSet a unique role to identify the main window"
+msgstr ""
+"--role <роль>\tУÑтановить уникальную <роль>\n"
+"\t\t\t\tÐ´Ð»Ñ Ð¸Ð´ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ð¸ главного окна"
+
+msgid "--socketid <xid>\tOpen Vim inside another GTK widget"
+msgstr "--socketid <xid>\tОткрыть Vim внутри другого компонента GTK"
+
+msgid "--echo-wid\t\tMake gvim echo the Window ID on stdout"
+msgstr "--echo-wid\t\tВывеÑти Window ID Ð´Ð»Ñ gvim на Ñтандартный поток вывода"
+
+msgid "-P <parent title>\tOpen Vim inside parent application"
+msgstr "-P <заголовок родителÑ>\tОткрыть Vim в родительÑком приложении"
+
+msgid "--windowid <HWND>\tOpen Vim inside another win32 widget"
+msgstr "--windowid <HWND>\tОткрыть Vim внутри другого компонента win32"
+
+msgid "No display"
+msgstr "Ðет диÑплеÑ"
+
+msgid ": Send failed.\n"
+msgstr ": Отправка не удалаÑÑŒ.\n"
+
+msgid ": Send failed. Trying to execute locally\n"
+msgstr ": Отправка не удалаÑÑŒ. Попытка меÑтного выполнениÑ\n"
+
+#, c-format
+msgid "%d of %d edited"
+msgstr "отредактировано %d из %d"
+
+msgid "No display: Send expression failed.\n"
+msgstr "Ðет диÑплеÑ: отправка Ð²Ñ‹Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð½Ðµ удалаÑÑŒ.\n"
+
+msgid ": Send expression failed.\n"
+msgstr ": Отправка Ð²Ñ‹Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð½Ðµ удалаÑÑŒ.\n"
+
+msgid "No marks set"
+msgstr "Ðет уÑтановленных отметок"
+
+#, c-format
+msgid "E283: No marks matching \"%s\""
+msgstr "E283: Ðет отметок, Ñовпадающих Ñ \"%s\""
+
+msgid ""
+"\n"
+"mark line col file/text"
+msgstr ""
+"\n"
+"отмет ÑÑ‚Ñ€ кол файл/текÑÑ‚"
+
+msgid ""
+"\n"
+" jump line col file/text"
+msgstr ""
+"\n"
+"прыжок ÑÑ‚Ñ€ кол файл/текÑÑ‚"
+
+msgid ""
+"\n"
+"change line col text"
+msgstr ""
+"\n"
+"измен. ÑÑ‚Ñ€ кол текÑÑ‚"
+
+msgid ""
+"\n"
+"# File marks:\n"
+msgstr ""
+"\n"
+"# Глобальные отметки:\n"
+
+msgid ""
+"\n"
+"# Jumplist (newest first):\n"
+msgstr ""
+"\n"
+"# СпиÑок прыжков (Ñначала более Ñвежие):\n"
+
+msgid ""
+"\n"
+"# History of marks within files (newest to oldest):\n"
+msgstr ""
+"\n"
+"# ИÑÑ‚Ð¾Ñ€Ð¸Ñ Ð¼ÐµÑтных отметок (от более Ñвежих к Ñтарым):\n"
+
+msgid "Missing '>'"
+msgstr "Пропущена '>'"
+
+msgid "E543: Not a valid codepage"
+msgstr "E543: ÐедопуÑтимое Ð¸Ð¼Ñ ÐºÐ¾Ð´Ð¸Ñ€Ð¾Ð²ÐºÐ¸"
+
+msgid "E284: Cannot set IC values"
+msgstr "E284: Ðевозможно назначить Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ ÐºÐ¾Ð½Ñ‚ÐµÐºÑта ввода"
+
+msgid "E285: Failed to create input context"
+msgstr "E285: Ðевозможно Ñоздать контекÑÑ‚ ввода"
+
+msgid "E286: Failed to open input method"
+msgstr "E286: ÐÐµÑƒÐ´Ð°Ñ‡Ð½Ð°Ñ Ð¿Ð¾Ð¿Ñ‹Ñ‚ÐºÐ° открыть метод ввода"
+
+msgid "E287: Warning: Could not set destroy callback to IM"
+msgstr ""
+"E287: Предупреждение: невозможно назначить обр. вызов ÑƒÐ½Ð¸Ñ‡Ñ‚Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼ÐµÑ‚Ð¾Ð´Ð° "
+"ввода"
+
+msgid "E288: input method doesn't support any style"
+msgstr "E288: Метод ввода не поддерживает Ñтили"
+
+msgid "E289: input method doesn't support my preedit type"
+msgstr ""
+"E289: Метод ввода не поддерживает мой тип предварительного редактированиÑ"
+
+msgid "E293: block was not locked"
+msgstr "E293: Блок не заблокирован"
+
+msgid "E294: Seek error in swap file read"
+msgstr "E294: Ошибка поиÑка при чтении Ñвоп-файла"
+
+msgid "E295: Read error in swap file"
+msgstr "E295: Ошибка Ñ‡Ñ‚ÐµÐ½Ð¸Ñ Ñвоп-файла"
+
+msgid "E296: Seek error in swap file write"
+msgstr "E296: Ошибка поиÑка при запиÑи Ñвоп-файла"
+
+msgid "E297: Write error in swap file"
+msgstr "E297: Ошибка при запиÑи Ñвоп-файла"
+
+msgid "E300: Swap file already exists (symlink attack?)"
+msgstr ""
+"E300: Своп-файл уже ÑущеÑтвует (атака Ñ Ð¸Ñпользованием Ñимвольной ÑÑылки?)"
+
+msgid "E298: Didn't get block nr 0?"
+msgstr "E298: Ðе получен блок номер 0?"
+
+msgid "E298: Didn't get block nr 1?"
+msgstr "E298: Ðе получен блок номер 1?"
+
+msgid "E298: Didn't get block nr 2?"
+msgstr "E298: Ðе получен блок номер 2?"
+
+msgid "E843: Error while updating swap file crypt"
+msgstr "E843: Ошибка при обновлении ÑˆÐ¸Ñ„Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ñвоп-файла"
+
+msgid "E301: Oops, lost the swap file!!!"
+msgstr "E301: Ой, потерÑлÑÑ Ñвоп-файл!!!"
+
+msgid "E302: Could not rename swap file"
+msgstr "E302: Ðевозможно переименовать Ñвоп-файл"
+
+#, c-format
+msgid "E303: Unable to open swap file for \"%s\", recovery impossible"
+msgstr ""
+"E303: Ðе удалоÑÑŒ открыть Ñвоп-файл Ð´Ð»Ñ \"%s\", воÑÑтановление невозможно"
+
+msgid "E304: ml_upd_block0(): Didn't get block 0??"
+msgstr "E304: ml_upd_block0(): Ðе получен блок 0??"
+
+#, c-format
+msgid "E305: No swap file found for %s"
+msgstr "E305: Своп-файл Ð´Ð»Ñ %s не найден"
+
+msgid "Enter number of swap file to use (0 to quit): "
+msgstr ""
+"Введите номер Ñвоп-файла, который Ñледует иÑпользовать (0 Ð´Ð»Ñ Ð²Ñ‹Ñ…Ð¾Ð´Ð°): "
+
+#, c-format
+msgid "E306: Cannot open %s"
+msgstr "E306: Ðе могу открыть %s"
+
+msgid "Unable to read block 0 from "
+msgstr "Ðевозможно прочитать блок 0 из "
+
+msgid ""
+"\n"
+"Maybe no changes were made or Vim did not update the swap file."
+msgstr ""
+"\n"
+"Ðет изменений, или Vim не Ñмог обновить Ñвоп-файл"
+
+msgid " cannot be used with this version of Vim.\n"
+msgstr " Ð½ÐµÐ»ÑŒÐ·Ñ Ð¸Ñпользовать в данной верÑии Vim.\n"
+
+msgid "Use Vim version 3.0.\n"
+msgstr "ИÑпользуйте Vim верÑии 3.0.\n"
+
+#, c-format
+msgid "E307: %s does not look like a Vim swap file"
+msgstr "E307: %s не ÑвлÑетÑÑ Ñвоп-файлом Vim"
+
+msgid " cannot be used on this computer.\n"
+msgstr " Ð½ÐµÐ»ÑŒÐ·Ñ Ð¸Ñпользовать на Ñтом компьютере.\n"
+
+msgid "The file was created on "
+msgstr "Файл был Ñоздан "
+
+msgid ""
+",\n"
+"or the file has been damaged."
+msgstr ""
+",\n"
+"либо файл был повреждён."
+
+#, c-format
+msgid ""
+"E833: %s is encrypted and this version of Vim does not support encryption"
+msgstr "E833: %s зашифрован, а Ñта верÑÐ¸Ñ Vim не поддерживает шифрование"
+
+msgid " has been damaged (page size is smaller than minimum value).\n"
+msgstr " был повреждён (размер Ñтраницы меньше минимального значениÑ).\n"
+
+#, c-format
+msgid "Using swap file \"%s\""
+msgstr "ИÑпользуетÑÑ Ñвоп-файл \"%s\""
+
+#, c-format
+msgid "Original file \"%s\""
+msgstr "ИÑходный файл \"%s\""
+
+msgid "E308: Warning: Original file may have been changed"
+msgstr "E308: Предупреждение: иÑходный файл мог быть изменён"
+
+#, c-format
+msgid "Swap file is encrypted: \"%s\""
+msgstr "Своп-файл зашифрован: \"%s\""
+
+msgid ""
+"\n"
+"If you entered a new crypt key but did not write the text file,"
+msgstr ""
+"\n"
+"ЕÑли вы ввели новый пароль Ð´Ð»Ñ ÑˆÐ¸Ñ„Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ, но не запиÑали текÑтовый файл,"
+
+msgid ""
+"\n"
+"enter the new crypt key."
+msgstr ""
+"\n"
+"то введите новый пароль Ð´Ð»Ñ ÑˆÐ¸Ñ„Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ."
+
+# Перевод ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ñ€Ð°Ð·Ð´ÐµÐ»Ñ‘Ð½ на две чаÑти, чаÑÑ‚ÑŒ перваÑ
+msgid ""
+"\n"
+"If you wrote the text file after changing the crypt key press enter"
+msgstr ""
+"\n"
+"ЕÑли вы запиÑали текÑтовый файл поÑле Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð¿Ð°Ñ€Ð¾Ð»Ñ ÑˆÐ¸Ñ„Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ, то нажмите"
+
+# Перевод ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ñ€Ð°Ð·Ð´ÐµÐ»Ñ‘Ð½ на две чаÑти, чаÑÑ‚ÑŒ втораÑ
+msgid ""
+"\n"
+"to use the same key for text file and swap file"
+msgstr ""
+"\n"
+"Enter Ð´Ð»Ñ Ð¸ÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¾Ð´Ð½Ð¾Ð³Ð¾ ключа Ð´Ð»Ñ Ñ‚ÐµÐºÑтового файла и Ñвоп-файла"
+
+#, c-format
+msgid "E309: Unable to read block 1 from %s"
+msgstr "E309: Ðевозможно прочитать блок 1 из %s"
+
+msgid "???MANY LINES MISSING"
+msgstr "???ОТСУТСТВУЕТ ÐœÐОГО СТРОК"
+
+msgid "???LINE COUNT WRONG"
+msgstr "???ÐЕПРÐВИЛЬÐОЕ ЗÐÐЧЕÐИЕ СЧÐТЧИКРСТРОК"
+
+msgid "???EMPTY BLOCK"
+msgstr "???ПУСТОЙ БЛОК"
+
+msgid "???LINES MISSING"
+msgstr "???ОТСУТСТВУЮТ СТРОКИ"
+
+#, c-format
+msgid "E310: Block 1 ID wrong (%s not a .swp file?)"
+msgstr "E310: Ðеправильный блок 1 ID (%s не ÑвлÑетÑÑ Ñ„Ð°Ð¹Ð»Ð¾Ð¼ .swp?)"
+
+msgid "???BLOCK MISSING"
+msgstr "???ПРОПУЩЕРБЛОК"
+
+msgid "??? from here until ???END lines may be messed up"
+msgstr "???Ñтроки могут быть иÑпорчены отÑюда до ???КОÐЦÐ"
+
+msgid "??? from here until ???END lines may have been inserted/deleted"
+msgstr "???Ñтроки могли быть вÑтавлены или удалены отÑюда до ???КОÐЦÐ"
+
+msgid "???END"
+msgstr "???КОÐЕЦ"
+
+msgid "E311: Recovery Interrupted"
+msgstr "E311: ВоÑÑтановление прервано"
+
+msgid ""
+"E312: Errors detected while recovering; look for lines starting with ???"
+msgstr ""
+"E312: Во Ð²Ñ€ÐµÐ¼Ñ Ð²Ð¾ÑÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ð¾Ð±Ð½Ð°Ñ€ÑƒÐ¶ÐµÐ½Ñ‹ ошибки; Ñм. Ñтроки, начинающиеÑÑ "
+"Ñ ???"
+
+msgid "See \":help E312\" for more information."
+msgstr "См. \":help E312\" Ð´Ð»Ñ Ð´Ð¾Ð¿Ð¾Ð»Ð½Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð¾Ð¹ информации."
+
+msgid "Recovery completed. You should check if everything is OK."
+msgstr "ВоÑÑтановление завершено. Проверьте, вÑÑ‘ ли в порÑдке."
+
+msgid ""
+"\n"
+"(You might want to write out this file under another name\n"
+msgstr ""
+"\n"
+"(Можете запиÑать файл под другим именем и Ñравнить его Ñ Ð¸Ñходным\n"
+
+msgid "and run diff with the original file to check for changes)"
+msgstr "файлом при помощи программы diff)"
+
+msgid "Recovery completed. Buffer contents equals file contents."
+msgstr "ВоÑÑтановление завершено. Содержимое буферов и файлов Ñквивалентно."
+
+msgid ""
+"\n"
+"You may want to delete the .swp file now.\n"
+"\n"
+msgstr ""
+"\n"
+"ВероÑтно, ÑÐµÐ¹Ñ‡Ð°Ñ Ð²Ñ‹ захотите удалить файл .swp.\n"
+"\n"
+
+msgid "Using crypt key from swap file for the text file.\n"
+msgstr "ИÑпользование ключа ÑˆÐ¸Ñ„Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¸Ð· Ñвоп-файла Ð´Ð»Ñ Ñ‚ÐµÐºÑтового файла.\n"
+
+msgid "Swap files found:"
+msgstr "Обнаружены Ñвоп-файлы:"
+
+msgid " In current directory:\n"
+msgstr " В текущем каталоге:\n"
+
+msgid " Using specified name:\n"
+msgstr " С указанным именем:\n"
+
+msgid " In directory "
+msgstr " В каталоге "
+
+msgid " -- none --\n"
+msgstr " -- нет --\n"
+
+msgid " owned by: "
+msgstr " владелец: "
+
+msgid " dated: "
+msgstr " дата: "
+
+msgid " dated: "
+msgstr " дата: "
+
+msgid " [from Vim version 3.0]"
+msgstr " [от Vim верÑии 3.0]"
+
+msgid " [does not look like a Vim swap file]"
+msgstr " [не ÑвлÑетÑÑ Ñвоп-файлом Vim]"
+
+msgid " file name: "
+msgstr " Ð¸Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð°: "
+
+msgid ""
+"\n"
+" modified: "
+msgstr ""
+"\n"
+" изменён: "
+
+msgid "YES"
+msgstr "ДÐ"
+
+msgid "no"
+msgstr "нет"
+
+msgid ""
+"\n"
+" user name: "
+msgstr ""
+"\n"
+" пользователь: "
+
+msgid " host name: "
+msgstr " компьютер: "
+
+msgid ""
+"\n"
+" host name: "
+msgstr ""
+"\n"
+" компьютер: "
+
+msgid ""
+"\n"
+" process ID: "
+msgstr ""
+"\n"
+" процеÑÑ: "
+
+msgid " (still running)"
+msgstr " (ещё выполнÑетÑÑ)"
+
+msgid ""
+"\n"
+" [not usable with this version of Vim]"
+msgstr ""
+"\n"
+" [не пригоден Ð´Ð»Ñ Ð¸ÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ñ Ð´Ð°Ð½Ð½Ð¾Ð¹ верÑией Vim]"
+
+msgid ""
+"\n"
+" [not usable on this computer]"
+msgstr ""
+"\n"
+" [не пригоден Ð´Ð»Ñ Ð¸ÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð½Ð° Ñтом компьютере]"
+
+msgid " [cannot be read]"
+msgstr " [не читаетÑÑ]"
+
+msgid " [cannot be opened]"
+msgstr " [не открываетÑÑ]"
+
+msgid "E313: Cannot preserve, there is no swap file"
+msgstr "E313: Ðевозможно обновить Ñвоп-файл, поÑкольку он не обнаружен"
+
+msgid "File preserved"
+msgstr "Своп-файл обновлён"
+
+msgid "E314: Preserve failed"
+msgstr "E314: ÐÐµÑƒÐ´Ð°Ñ‡Ð½Ð°Ñ Ð¿Ð¾Ð¿Ñ‹Ñ‚ÐºÐ° Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ñвоп-файла"
+
+#, c-format
+msgid "E315: ml_get: invalid lnum: %ld"
+msgstr "E315: ml_get: неправильное значение lnum: %ld"
+
+#, c-format
+msgid "E316: ml_get: cannot find line %ld"
+msgstr "E316: ml_get: невозможно найти Ñтроку %ld"
+
+msgid "E317: pointer block id wrong 3"
+msgstr "E317: Ðеправильное значение ÑƒÐºÐ°Ð·Ð°Ñ‚ÐµÐ»Ñ Ð±Ð»Ð¾ÐºÐ° 3"
+
+msgid "stack_idx should be 0"
+msgstr "значение stack_idx должно быть равно 0"
+
+msgid "E318: Updated too many blocks?"
+msgstr "E318: Обновлено Ñлишком много блоков?"
+
+msgid "E317: pointer block id wrong 4"
+msgstr "E317: Ðеправильное значение ÑƒÐºÐ°Ð·Ð°Ñ‚ÐµÐ»Ñ Ð±Ð»Ð¾ÐºÐ° 4"
+
+msgid "deleted block 1?"
+msgstr "удалён блок 1?"
+
+#, c-format
+msgid "E320: Cannot find line %ld"
+msgstr "E320: Строка %ld не обнаружена"
+
+msgid "E317: pointer block id wrong"
+msgstr "E317: Ðеправильное значение ÑƒÐºÐ°Ð·Ð°Ñ‚ÐµÐ»Ñ Ð±Ð»Ð¾ÐºÐ°"
+
+msgid "pe_line_count is zero"
+msgstr "значение pe_line_count равно нулю"
+
+#, c-format
+msgid "E322: line number out of range: %ld past the end"
+msgstr "E322: Ðомер Ñтроки за пределами диапазона: %ld"
+
+#, c-format
+msgid "E323: line count wrong in block %ld"
+msgstr "E323: Ðеправильное значение Ñчётчика Ñтрок в блоке %ld"
+
+msgid "Stack size increases"
+msgstr "Размер Ñтека увеличен"
+
+msgid "E317: pointer block id wrong 2"
+msgstr "E317: Ðеправильное значение ÑƒÐºÐ°Ð·Ð°Ñ‚ÐµÐ»Ñ Ð±Ð»Ð¾ÐºÐ° 2"
+
+#, c-format
+msgid "E773: Symlink loop for \"%s\""
+msgstr "E773: ÐŸÐµÑ‚Ð»Ñ Ñимвольных ÑÑылок Ð´Ð»Ñ \"%s\""
+
+msgid "E325: ATTENTION"
+msgstr "E325: Ð’ÐИМÐÐИЕ"
+
+msgid ""
+"\n"
+"Found a swap file by the name \""
+msgstr ""
+"\n"
+"Обнаружен Ñвоп-файл Ñ Ð¸Ð¼ÐµÐ½ÐµÐ¼ \""
+
+# С маленькой буквы, чтобы ÑоответÑтвовало по Ñтилю ÑоÑедним ÑообщениÑм.
+msgid "While opening file \""
+msgstr "при открытии файла: \""
+
+msgid " NEWER than swap file!\n"
+msgstr " Более СВЕЖИЙ, чем Ñвоп-файл!\n"
+
+msgid ""
+"\n"
+"(1) Another program may be editing the same file. If this is the case,\n"
+" be careful not to end up with two different instances of the same\n"
+" file when making changes. Quit, or continue with caution.\n"
+msgstr ""
+"\n"
+"(1) Возможно, редактирование Ñтого же файла выполнÑетÑÑ Ð² другой программе.\n"
+" ЕÑли Ñто так, то будьте внимательны при внеÑении изменений, чтобы\n"
+" у Ð²Ð°Ñ Ð½Ðµ поÑвилоÑÑŒ два разных варианта одного и того же файла.\n"
+" Выйдите или продолжайте Ñ Ð¾ÑторожноÑтью.\n"
+
+msgid "(2) An edit session for this file crashed.\n"
+msgstr "(2) Ð¡ÐµÐ°Ð½Ñ Ñ€ÐµÐ´Ð°ÐºÑ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ñтого файла завершён аварийно.\n"
+
+msgid " If this is the case, use \":recover\" or \"vim -r "
+msgstr " Ð’ Ñтом Ñлучае, иÑпользуйте команду \":recover\" или \"vim -r "
+
+msgid ""
+"\"\n"
+" to recover the changes (see \":help recovery\").\n"
+msgstr ""
+"\"\n"
+" Ð´Ð»Ñ Ð²Ð¾ÑÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ð¹ (Ñм. \":help recovery\").\n"
+
+msgid " If you did this already, delete the swap file \""
+msgstr " ЕÑли вы уже выполнÑли Ñту операцию, удалите Ñвоп-файл \""
+
+msgid ""
+"\"\n"
+" to avoid this message.\n"
+msgstr ""
+"\"\n"
+" чтобы избежать поÑÐ²Ð»ÐµÐ½Ð¸Ñ Ñтого ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð² будущем.\n"
+
+msgid "Swap file \""
+msgstr "Своп-файл \""
+
+msgid "\" already exists!"
+msgstr "\" уже ÑущеÑтвует!"
+
+msgid "VIM - ATTENTION"
+msgstr "VIM — Ð’ÐИМÐÐИЕ"
+
+msgid "Swap file already exists!"
+msgstr "Своп-файл уже ÑущеÑтвует!"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"&O Открыть Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ\n"
+"&E Редактировать\n"
+"&R ВоÑÑтановить\n"
+"&Q Выход\n"
+"&A Прервать"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Delete it\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"&O Открыть Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ\n"
+"&E Редактировать\n"
+"&R ВоÑÑтановить\n"
+"&D Удалить\n"
+"&Q Выход\n"
+"&A Прервать"
+
+msgid "E326: Too many swap files found"
+msgstr "E326: Обнаружено Ñлишком много Ñвоп-файлов"
+
+msgid "E327: Part of menu-item path is not sub-menu"
+msgstr "E327: Компонент пути к Ñлементу меню не ÑвлÑетÑÑ Ð¿Ð¾Ð´Ð¼ÐµÐ½ÑŽ"
+
+msgid "E328: Menu only exists in another mode"
+msgstr "E328: Меню в Ñтом режиме не ÑущеÑтвует"
+
+#, c-format
+msgid "E329: No menu \"%s\""
+msgstr "E329: Ðет меню %s"
+
+msgid "E792: Empty menu name"
+msgstr "E792: ПуÑтое Ð¸Ð¼Ñ Ð¼ÐµÐ½ÑŽ"
+
+msgid "E330: Menu path must not lead to a sub-menu"
+msgstr "E330: Путь к меню не должен веÑти к подменю"
+
+msgid "E331: Must not add menu items directly to menu bar"
+msgstr "E331: Элементы меню Ð½ÐµÐ»ÑŒÐ·Ñ Ð´Ð¾Ð±Ð°Ð²Ð»ÑÑ‚ÑŒ непоÑредÑтвенно в полоÑку меню"
+
+msgid "E332: Separator cannot be part of a menu path"
+msgstr "E332: Разделители не могут быть компонентом пути к меню"
+
+msgid ""
+"\n"
+"--- Menus ---"
+msgstr ""
+"\n"
+"--- Меню ---"
+
+msgid "Tear off this menu"
+msgstr "Оторвать Ñто меню"
+
+#, c-format
+msgid "E335: Menu not defined for %s mode"
+msgstr "E335: Меню не определено Ð´Ð»Ñ Ñ€ÐµÐ¶Ð¸Ð¼Ð° %s"
+
+msgid "E333: Menu path must lead to a menu item"
+msgstr "E333: Путь к меню должен веÑти к Ñлементу меню"
+
+#, c-format
+msgid "E334: Menu not found: %s"
+msgstr "E334: Меню не найдено: %s"
+
+msgid "E336: Menu path must lead to a sub-menu"
+msgstr "E336: Путь к меню должен веÑти к подменю"
+
+msgid "E337: Menu not found - check menu names"
+msgstr "E337: Меню не найдено — проверьте имена меню"
+
+#, c-format
+msgid "Error detected while processing %s:"
+msgstr "Обнаружена ошибка при обработке %s:"
+
+#, c-format
+msgid "line %4ld:"
+msgstr "Ñтрока %4ld:"
+
+#, c-format
+msgid "E354: Invalid register name: '%s'"
+msgstr "E354: ÐедопуÑтимое Ð¸Ð¼Ñ Ñ€ÐµÐ³Ð¸Ñтра: '%s'"
+
+msgid "Messages maintainer: Bram Moolenaar <Bram@vim.org>"
+msgstr ""
+"Перевод Ñообщений на руÑÑкий Ñзык: ВаÑилий Рагозин <vrr@users.sourceforge."
+"net>, Сергей Ðлёшин <alyoshin.s@gmail.com>"
+
+msgid "Interrupt: "
+msgstr "Прерывание: "
+
+msgid "Press ENTER or type command to continue"
+msgstr "Ðажмите ENTER или введите команду Ð´Ð»Ñ Ð¿Ñ€Ð¾Ð´Ð¾Ð»Ð¶ÐµÐ½Ð¸Ñ"
+
+#, c-format
+msgid "%s line %ld"
+msgstr "%s Ñтрока %ld"
+
+msgid "-- More --"
+msgstr "-- Продолжение Ñледует --"
+
+msgid " SPACE/d/j: screen/page/line down, b/u/k: up, q: quit "
+msgstr " SPACE/d/j: Ñкран/Ñтраница/Ñтрока вниз, b/u/k: вверх, q: выход "
+
+msgid "Question"
+msgstr "ВопроÑ"
+
+msgid ""
+"&Yes\n"
+"&No"
+msgstr ""
+"&Y Да\n"
+"&N Ðет"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"Save &All\n"
+"&Discard All\n"
+"&Cancel"
+msgstr ""
+"&Y Да\n"
+"&N Ðет\n"
+"&A Сохранить вÑе\n"
+"&D ПотерÑÑ‚ÑŒ вÑе\n"
+"&C Отмена"
+
+msgid "Select Directory dialog"
+msgstr "Выбор каталога"
+
+msgid "Save File dialog"
+msgstr "Сохранение файла"
+
+msgid "Open File dialog"
+msgstr "Открытие файла"
+
+msgid "E338: Sorry, no file browser in console mode"
+msgstr ""
+"E338: Извините, но в конÑольном режиме нет проводника по файловой ÑиÑтеме"
+
+msgid "E766: Insufficient arguments for printf()"
+msgstr "E766: ÐедоÑтаточно параметров Ð´Ð»Ñ printf()"
+
+msgid "E807: Expected Float argument for printf()"
+msgstr "E807: ОжидалÑÑ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€ типа Ñ Ð¿Ð»Ð°Ð²Ð°ÑŽÑ‰ÐµÐ¹ точкой Ð´Ð»Ñ printf()"
+
+msgid "E767: Too many arguments to printf()"
+msgstr "E767: Слишком много параметров Ð´Ð»Ñ printf()"
+
+msgid "W10: Warning: Changing a readonly file"
+msgstr "W10: Предупреждение: Изменение файла Ñ Ð¿Ñ€Ð°Ð²Ð°Ð¼Ð¸ только Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ"
+
+msgid "Type number and <Enter> or click with mouse (empty cancels): "
+msgstr "Введите номер и <Enter> или щёлкните мышью (пуÑто Ð´Ð»Ñ Ð¾Ñ‚Ð¼ÐµÐ½Ñ‹): "
+
+msgid "Type number and <Enter> (empty cancels): "
+msgstr "Введите номер и <Enter> (пуÑто Ð´Ð»Ñ Ð¾Ñ‚Ð¼ÐµÐ½Ñ‹): "
+
+msgid "1 more line"
+msgstr "Добавлена одна Ñтрока"
+
+msgid "1 line less"
+msgstr "Убрана одна Ñтрока"
+
+#, c-format
+msgid "%ld more lines"
+msgstr "Добавлено Ñтрок: %ld"
+
+#, c-format
+msgid "%ld fewer lines"
+msgstr "Убрано Ñтрок: %ld"
+
+msgid " (Interrupted)"
+msgstr " (Прервано)"
+
+msgid "Beep!"
+msgstr "Би-би!"
+
+msgid "ERROR: "
+msgstr "ОШИБКÐ: "
+
+#, c-format
+msgid ""
+"\n"
+"[bytes] total alloc-freed %lu-%lu, in use %lu, peak use %lu\n"
+msgstr ""
+"\n"
+"[байт] вÑего выдел.-оÑвоб. %lu-%lu, иÑпольз. %lu, макÑ. иÑпольз. %lu\n"
+
+#, c-format
+msgid ""
+"[calls] total re/malloc()'s %lu, total free()'s %lu\n"
+"\n"
+msgstr ""
+"[вызовы] re/malloc() вÑего %lu, free() вÑего %lu\n"
+"\n"
+
+msgid "E340: Line is becoming too long"
+msgstr "E340: Строка ÑтановитÑÑ Ñлишком длинной"
+
+#, c-format
+msgid "E341: Internal error: lalloc(%ld, )"
+msgstr "E341: ВнутреннÑÑ Ð¾ÑˆÐ¸Ð±ÐºÐ°: lalloc(%ld, )"
+
+#, c-format
+msgid "E342: Out of memory! (allocating %lu bytes)"
+msgstr "E342: Ðе хватает памÑти! (выделÑетÑÑ %lu байт)"
+
+#, c-format
+msgid "Calling shell to execute: \"%s\""
+msgstr "Вызов оболочки Ð´Ð»Ñ Ð¸ÑполнениÑ: \"%s\""
+
+msgid "E545: Missing colon"
+msgstr "E545: Пропущено двоеточие"
+
+msgid "E546: Illegal mode"
+msgstr "E546: ÐедопуÑтимый режим"
+
+msgid "E547: Illegal mouseshape"
+msgstr "E547: ÐедопуÑÑ‚Ð¸Ð¼Ð°Ñ Ñ„Ð¾Ñ€Ð¼Ð° курÑора"
+
+msgid "E548: digit expected"
+msgstr "E548: ТребуетÑÑ Ð²Ð²ÐµÑти цифру"
+
+msgid "E549: Illegal percentage"
+msgstr "E549: ÐедопуÑтимое значение процентов"
+
+msgid "E854: path too long for completion"
+msgstr "E854: Ñлишком большой путь Ð´Ð»Ñ Ð°Ð²Ñ‚Ð¾Ð´Ð¾Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ"
+
+#, c-format
+msgid ""
+"E343: Invalid path: '**[number]' must be at the end of the path or be "
+"followed by '%s'."
+msgstr ""
+"E343: Ðеправильно задан путь: '**[чиÑло]' должно быть либо в конце пути, "
+"либо за ним должно Ñледовать '%s'"
+
+#, c-format
+msgid "E344: Can't find directory \"%s\" in cdpath"
+msgstr "E344: Каталог \"%s\" не найден в пути Ð´Ð»Ñ Ñмены каталога"
+
+#, c-format
+msgid "E345: Can't find file \"%s\" in path"
+msgstr "E345: Файл \"%s\" в извеÑтных каталогах не найден"
+
+#, c-format
+msgid "E346: No more directory \"%s\" found in cdpath"
+msgstr "E346: Ð’ пути Ñмены каталога больше нет каталогов \"%s\""
+
+#, c-format
+msgid "E347: No more file \"%s\" found in path"
+msgstr "E347: Ð’ извеÑтных каталогах больше нет файлов \"%s\""
+
+#, c-format
+msgid "E668: Wrong access mode for NetBeans connection info file: \"%s\""
+msgstr ""
+"E668: Ðеправильный режим доÑтупа к информации о Ñоединении Ñ NetBeans: \"%s\""
+
+#, c-format
+msgid "E658: NetBeans connection lost for buffer %ld"
+msgstr "E658: ПотерÑно Ñоединение Ñ NetBeans Ð´Ð»Ñ Ð±ÑƒÑ„ÐµÑ€Ð° %ld"
+
+msgid "E838: netbeans is not supported with this GUI"
+msgstr "E838: NetBeans не поддерживаетÑÑ Ñ Ñтим графичеÑким интерфейÑом"
+
+msgid "E511: netbeans already connected"
+msgstr "E511: уже Ñоединён Ñ NetBeans"
+
+#, c-format
+msgid "E505: %s is read-only (add ! to override)"
+msgstr "E505: %s открыт только Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ (добавьте !, чтобы обойти проверку)"
+
+msgid "E349: No identifier under cursor"
+msgstr "E349: Ðет имени в позиции курÑора"
+
+msgid "E774: 'operatorfunc' is empty"
+msgstr "E774: Значением опции 'operatorfunc' ÑвлÑетÑÑ Ð¿ÑƒÑÑ‚Ð°Ñ Ñтрока"
+
+msgid "E775: Eval feature not available"
+msgstr "E775: eval недоÑтупна"
+
+msgid "Warning: terminal cannot highlight"
+msgstr "Предупреждение: терминал не может выполнÑÑ‚ÑŒ подÑветку"
+
+msgid "E348: No string under cursor"
+msgstr "E348: Ðет Ñтроки в позиции курÑора"
+
+msgid "E352: Cannot erase folds with current 'foldmethod'"
+msgstr ""
+"E352: Ðевозможно Ñтереть Ñкладки Ñ Ñ‚ÐµÐºÑƒÑ‰Ð¸Ð¼ значением опции 'foldmethod'"
+
+msgid "E664: changelist is empty"
+msgstr "E664: СпиÑок изменений пуÑтой"
+
+msgid "E662: At start of changelist"
+msgstr "E662: Ð’ начале ÑпиÑка изменений"
+
+msgid "E663: At end of changelist"
+msgstr "E663: Ð’ конце ÑпиÑка изменений"
+
+msgid "Type :qa! and press <Enter> to abandon all changes and exit Vim"
+msgstr ""
+"Введите :qa! и нажмите <Enter> Ð´Ð»Ñ Ð¾Ñ‚Ð¼ÐµÐ½Ñ‹ вÑех изменений и выхода из Vim"
+
+#, c-format
+msgid "1 line %sed 1 time"
+msgstr "Изменены отÑтупы в 1 Ñтроке (%s 1 раз)"
+
+#, c-format
+msgid "1 line %sed %d times"
+msgstr "Изменены отÑтупы в 1 Ñтроке (%s %d раз)"
+
+#, c-format
+msgid "%ld lines %sed 1 time"
+msgstr "Изменены отÑтупы, %ld Ñтрок (%s 1 раз)"
+
+#, c-format
+msgid "%ld lines %sed %d times"
+msgstr "Изменены отÑтупы, %ld Ñтрок (%s %d раз)"
+
+#, c-format
+msgid "%ld lines to indent... "
+msgstr "ИзменÑÑŽÑ‚ÑÑ Ð¾Ñ‚Ñтупы Ñтроках (%ld)..."
+
+msgid "1 line indented "
+msgstr "Изменён отÑтуп в одной Ñтроке "
+
+#, c-format
+msgid "%ld lines indented "
+msgstr "Изменены отÑтупы в Ñтроках (%ld) "
+
+msgid "E748: No previously used register"
+msgstr "E748: Ðет предыдущего иÑпользованного региÑтра"
+
+msgid "cannot yank; delete anyway"
+msgstr "Ñкопировать не удалоÑÑŒ, удаление выполнено"
+
+msgid "1 line changed"
+msgstr "изменена 1 Ñтрока"
+
+#, c-format
+msgid "%ld lines changed"
+msgstr "изменено Ñтрок: %ld"
+
+#, c-format
+msgid "freeing %ld lines"
+msgstr "очищено Ñтрок: %ld"
+
+#, c-format
+msgid " into \"%c"
+msgstr " в \"%c"
+
+#, c-format
+msgid "block of 1 line yanked%s"
+msgstr "Ñкопирован блок из одной Ñтроки%s"
+
+#, c-format
+msgid "1 line yanked%s"
+msgstr "Ñкопирована одна Ñтрока%s"
+
+#, c-format
+msgid "block of %ld lines yanked%s"
+msgstr "Ñкопирован блок из %ld Ñтрок%s"
+
+#, c-format
+msgid "%ld lines yanked%s"
+msgstr "Ñкопировано %ld Ñтрок%s"
+
+#, c-format
+msgid "E353: Nothing in register %s"
+msgstr "E353: Ð’ региÑтре %s ничего нет"
+
+msgid ""
+"\n"
+"--- Registers ---"
+msgstr ""
+"\n"
+"--- РегиÑтры ---"
+
+msgid "Illegal register name"
+msgstr "ÐедопуÑтимое Ð¸Ð¼Ñ Ñ€ÐµÐ³Ð¸Ñтра"
+
+msgid ""
+"\n"
+"# Registers:\n"
+msgstr ""
+"\n"
+"# РегиÑтры:\n"
+
+#, c-format
+msgid "E574: Unknown register type %d"
+msgstr "E574: ÐеизвеÑтный тип региÑтра %d"
+
+msgid ""
+"E883: search pattern and expression register may not contain two or more "
+"lines"
+msgstr ""
+"E883: шаблон поиÑка и региÑÑ‚Ñ€ Ð²Ñ‹Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð½Ðµ могут Ñодержать двух или более "
+"Ñтрок"
+
+#, c-format
+msgid "%ld Cols; "
+msgstr "Колонок: %ld; "
+
+#, c-format
+msgid "Selected %s%ld of %ld Lines; %lld of %lld Words; %lld of %lld Bytes"
+msgstr "Выделено %s%ld из %ld Ñтрок; %lld из %lld Ñлов; %lld из %lld байт"
+
+#, c-format
+msgid ""
+"Selected %s%ld of %ld Lines; %lld of %lld Words; %lld of %lld Chars; %lld of "
+"%lld Bytes"
+msgstr ""
+"Выделено %s%ld из %ld ÑÑ‚Ñ€.; %lld из %lld Ñлов; %lld из %lld Ñимв.; %lld из "
+"%lld байт"
+
+#, c-format
+msgid "Col %s of %s; Line %ld of %ld; Word %lld of %lld; Byte %lld of %lld"
+msgstr "Кол. %s из %s; ÑÑ‚Ñ€. %ld из %ld; Ñл. %lld из %lld; байт %lld из %lld"
+
+#, c-format
+msgid ""
+"Col %s of %s; Line %ld of %ld; Word %lld of %lld; Char %lld of %lld; Byte "
+"%lld of %lld"
+msgstr ""
+"Кол. %s из %s; ÑÑ‚Ñ€. %ld из %ld; Ñл. %lld из %lld; Ñимв. %lld из %lld; байт "
+"%lld из %lld"
+
+#, c-format
+msgid "(+%lld for BOM)"
+msgstr "(+%lld Ñ ÑƒÑ‡Ñ‘Ñ‚Ð¾Ð¼ BOM)"
+
+msgid "Thanks for flying Vim"
+msgstr "Благодарим за иÑпользование Vim"
+
+msgid "E518: Unknown option"
+msgstr "E518: ÐеизвеÑÑ‚Ð½Ð°Ñ Ð¾Ð¿Ñ†Ð¸Ñ"
+
+msgid "E519: Option not supported"
+msgstr "E519: ÐžÐ¿Ñ†Ð¸Ñ Ð½Ðµ поддерживаетÑÑ"
+
+msgid "E520: Not allowed in a modeline"
+msgstr "E520: Ðе допуÑкаетÑÑ Ð² режимной Ñтроке"
+
+msgid "E846: Key code not set"
+msgstr "E846: Код клавиши не уÑтановлен"
+
+msgid "E521: Number required after ="
+msgstr "E521: ПоÑле = требуетÑÑ ÑƒÐºÐ°Ð·Ð°Ñ‚ÑŒ чиÑло"
+
+msgid "E522: Not found in termcap"
+msgstr "E522: Ðе обнаружено в termcap"
+
+#, c-format
+msgid "E539: Illegal character <%s>"
+msgstr "E539: ÐедопуÑтимый Ñимвол <%s>"
+
+#, c-format
+msgid "For option %s"
+msgstr "Ð”Ð»Ñ Ð¾Ð¿Ñ†Ð¸Ð¸ %s"
+
+msgid "E529: Cannot set 'term' to empty string"
+msgstr "E529: Значение опции 'term' не может быть пуÑтой Ñтрокой"
+
+msgid "E530: Cannot change term in GUI"
+msgstr "E530: Ð’ графичеÑком интерфейÑе изменÑÑ‚ÑŒ терминал невозможно"
+
+msgid "E531: Use \":gui\" to start the GUI"
+msgstr "E531: Ð”Ð»Ñ Ð·Ð°Ð¿ÑƒÑка графичеÑкого интерфейÑа иÑпользуйте \":gui\""
+
+msgid "E589: 'backupext' and 'patchmode' are equal"
+msgstr "E589: Ð—Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð¾Ð¿Ñ†Ð¸Ð¹ 'backupext' и 'patchmode' равны"
+
+msgid "E834: Conflicts with value of 'listchars'"
+msgstr "E834: Конфликтует Ñо значением 'listchars'"
+
+msgid "E835: Conflicts with value of 'fillchars'"
+msgstr "E835: Конфликтует Ñо значением 'fillchars'"
+
+msgid "E617: Cannot be changed in the GTK+ 2 GUI"
+msgstr "E617: Ðе может быть изменено в графичеÑком интерфейÑе GTK+ 2"
+
+#, c-format
+msgid "E950: Cannot convert between %s and %s"
+msgstr "E950: Ðевозможно преобразовать %s и %s"
+
+msgid "E524: Missing colon"
+msgstr "E524: Пропущено двоеточие"
+
+msgid "E525: Zero length string"
+msgstr "E525: Строка Ñ Ð½ÑƒÐ»ÐµÐ²Ð¾Ð¹ длиной"
+
+#, c-format
+msgid "E526: Missing number after <%s>"
+msgstr "E526: Пропущено чиÑло поÑле <%s>"
+
+msgid "E527: Missing comma"
+msgstr "E527: Пропущена запÑтаÑ"
+
+msgid "E528: Must specify a ' value"
+msgstr "E528: Ðеобходимо указать значение Ð´Ð»Ñ '"
+
+msgid "E595: contains unprintable or wide character"
+msgstr "E595: Содержит непечатный Ñимвол или Ñимвол двойной ширины"
+
+msgid "E596: Invalid font(s)"
+msgstr "E596: Ðеправильные шрифты"
+
+msgid "E597: can't select fontset"
+msgstr "E597: Ðевозможно выбрать шрифтовой набор"
+
+msgid "E598: Invalid fontset"
+msgstr "E598: Ðеправильный шрифтовой набор"
+
+msgid "E533: can't select wide font"
+msgstr "E533: Ðевозможно выбрать шрифт Ñ Ñимволами двойной ширины"
+
+msgid "E534: Invalid wide font"
+msgstr "E534: Ðеправильный шрифт Ñ Ñимволами двойной ширины"
+
+#, c-format
+msgid "E535: Illegal character after <%c>"
+msgstr "E535: Ðеправильный Ñимвол поÑле <%c>"
+
+msgid "E536: comma required"
+msgstr "E536: ТребуетÑÑ Ð·Ð°Ð¿ÑтаÑ"
+
+#, c-format
+msgid "E537: 'commentstring' must be empty or contain %s"
+msgstr ""
+"E537: Значение Ð¾Ð¿Ñ†Ð¸Ñ 'commentstring' должно быть пуÑтой Ñтрокой или "
+"Ñодержать %s"
+
+msgid "E538: No mouse support"
+msgstr "E538: Мышь не поддерживаетÑÑ"
+
+msgid "E540: Unclosed expression sequence"
+msgstr "E540: ÐÐµÐ·Ð°ÐºÑ€Ñ‹Ñ‚Ð°Ñ Ð¿Ð¾ÑледовательноÑÑ‚ÑŒ выражениÑ"
+
+msgid "E541: too many items"
+msgstr "E541: Слишком много Ñлементов"
+
+msgid "E542: unbalanced groups"
+msgstr "E542: ÐеÑбаланÑированные группы"
+
+msgid "E946: Cannot make a terminal with running job modifiable"
+msgstr "E946: Ðевозможно Ñделать терминал изменённым Ñ Ð·Ð°Ð¿ÑƒÑ‰ÐµÐ½Ð½Ñ‹Ð¼ заданием"
+
+msgid "E590: A preview window already exists"
+msgstr "E590: Окно предпроÑмотра уже еÑÑ‚ÑŒ"
+
+msgid "W17: Arabic requires UTF-8, do ':set encoding=utf-8'"
+msgstr ""
+"W17: ÐрабÑкий требует иÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ UTF-8, введите ':set encoding=utf-8'"
+
+msgid "E954: 24-bit colors are not supported on this environment"
+msgstr "E954: 24 битный цвет не поддерживаетÑÑ Ð² Ñтом окружении"
+
+#, c-format
+msgid "E593: Need at least %d lines"
+msgstr "E593: Ðужно Ñ…Ð¾Ñ‚Ñ Ð±Ñ‹ %d Ñтрок"
+
+#, c-format
+msgid "E594: Need at least %d columns"
+msgstr "E594: Ðужно Ñ…Ð¾Ñ‚Ñ Ð±Ñ‹ %d колонок"
+
+#, c-format
+msgid "E355: Unknown option: %s"
+msgstr "E355: ÐеизвеÑÑ‚Ð½Ð°Ñ Ð¾Ð¿Ñ†Ð¸Ñ: %s"
+
+#, c-format
+msgid "E521: Number required: &%s = '%s'"
+msgstr "E521: ТребуетÑÑ ÑƒÐºÐ°Ð·Ð°Ñ‚ÑŒ чиÑло: &%s = '%s'"
+
+msgid ""
+"\n"
+"--- Terminal codes ---"
+msgstr ""
+"\n"
+"--- Терминальные коды ---"
+
+msgid ""
+"\n"
+"--- Global option values ---"
+msgstr ""
+"\n"
+"--- Глобальные Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð¾Ð¿Ñ†Ð¸Ð¹ ---"
+
+msgid ""
+"\n"
+"--- Local option values ---"
+msgstr ""
+"\n"
+"--- Локальные Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð¾Ð¿Ñ†Ð¸Ð¹ ---"
+
+msgid ""
+"\n"
+"--- Options ---"
+msgstr ""
+"\n"
+"--- Опции ---"
+
+msgid "E356: get_varp ERROR"
+msgstr "E356: ОШИБКРget_varp"
+
+#, c-format
+msgid "E357: 'langmap': Matching character missing for %s"
+msgstr "E357: 'langmap': Ðет ÑоответÑтвующего Ñимвола Ð´Ð»Ñ %s"
+
+#, c-format
+msgid "E358: 'langmap': Extra characters after semicolon: %s"
+msgstr "E358: 'langmap': Лишние Ñимволы поÑле точки Ñ Ð·Ð°Ð¿Ñтой: %s"
+
+msgid "cannot open "
+msgstr "невозможно открыть "
+
+msgid "VIM: Can't open window!\n"
+msgstr "VIM: Ðевозможно открыть окно!\n"
+
+msgid "Need Amigados version 2.04 or later\n"
+msgstr "Ðеобходима Amigados верÑии 2.04 или более поздней\n"
+
+#, c-format
+msgid "Need %s version %ld\n"
+msgstr "Ðеобходима %s верÑии %ld\n"
+
+msgid "Cannot open NIL:\n"
+msgstr "Ðевозможно открыть NIL:\n"
+
+msgid "Cannot create "
+msgstr "Ðевозможно Ñоздать "
+
+#, c-format
+msgid "Vim exiting with %d\n"
+msgstr "Прекращение работы Vim Ñ ÐºÐ¾Ð´Ð¾Ð¼ %d\n"
+
+msgid "cannot change console mode ?!\n"
+msgstr "невозможно Ñменить режим конÑоли?!\n"
+
+msgid "mch_get_shellsize: not a console??\n"
+msgstr "mch_get_shellsize: не в конÑоли??\n"
+
+msgid "E360: Cannot execute shell with -f option"
+msgstr "E360: Ðевозможно выполнить оболочку Ñ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ð¾Ð¼ -f"
+
+msgid "Cannot execute "
+msgstr "Ðевозможно выполнить "
+
+msgid "shell "
+msgstr "оболочка "
+
+msgid " returned\n"
+msgstr " завершила работу\n"
+
+msgid "ANCHOR_BUF_SIZE too small."
+msgstr "Ñлишком Ð¼Ð°Ð»Ð°Ñ Ð²ÐµÐ»Ð¸Ñ‡Ð¸Ð½Ð° ANCHOR_BUF_SIZE."
+
+msgid "I/O ERROR"
+msgstr "ОШИБКРВВОДÐ/ВЫВОДÐ"
+
+msgid "Message"
+msgstr "Сообщение"
+
+msgid "E237: Printer selection failed"
+msgstr "E237: Ðеудачное завершение выбора принтера"
+
+#, c-format
+msgid "to %s on %s"
+msgstr "в %s на %s"
+
+#, c-format
+msgid "E613: Unknown printer font: %s"
+msgstr "E613: ÐеизвеÑтный шрифт принтера: %s"
+
+#, c-format
+msgid "E238: Print error: %s"
+msgstr "E238: Ошибка печати: %s"
+
+#, c-format
+msgid "Printing '%s'"
+msgstr "Печать '%s'"
+
+#, c-format
+msgid "E244: Illegal charset name \"%s\" in font name \"%s\""
+msgstr "E244: ÐедопуÑтимое Ð¸Ð¼Ñ ÐºÐ¾Ð´Ð¸Ñ€Ð¾Ð²ÐºÐ¸ \"%s\" в имени шрифта \"%s\""
+
+#, c-format
+msgid "E244: Illegal quality name \"%s\" in font name \"%s\""
+msgstr "E244: ÐедопуÑтимое Ð¸Ð¼Ñ ÑвойÑтва \"%s\" в имени шрифта \"%s\""
+
+#, c-format
+msgid "E245: Illegal char '%c' in font name \"%s\""
+msgstr "E245: ÐедопуÑтимый Ñимвол '%c' в имени шрифта \"%s\""
+
+#, c-format
+msgid "Opening the X display took %ld msec"
+msgstr "Открытие диÑÐ¿Ð»ÐµÑ X занÑло %ld msec"
+
+msgid ""
+"\n"
+"Vim: Got X error\n"
+msgstr ""
+"\n"
+"Vim: Ошибка X\n"
+
+msgid "Testing the X display failed"
+msgstr "Проверка диÑÐ¿Ð»ÐµÑ X завершена неудачно"
+
+msgid "Opening the X display timed out"
+msgstr "Открытие диÑÐ¿Ð»ÐµÑ X не выполнено в отведённое времÑ"
+
+msgid ""
+"\n"
+"Could not get security context for "
+msgstr ""
+"\n"
+"Ðевозможно получить контекÑÑ‚ безопаÑноÑти Ð´Ð»Ñ "
+
+msgid ""
+"\n"
+"Could not set security context for "
+msgstr ""
+"\n"
+"Ðевозможно уÑтановить контекÑÑ‚ безопаÑноÑти Ð´Ð»Ñ "
+
+#, c-format
+msgid "Could not set security context %s for %s"
+msgstr "Ðевозможно уÑтановить контекÑÑ‚ безопаÑноÑти %s Ð´Ð»Ñ Ð´Ð»Ñ %s"
+
+#, c-format
+msgid "Could not get security context %s for %s. Removing it!"
+msgstr "Ðевозможно получить контекÑÑ‚ безопаÑноÑти %s Ð´Ð»Ñ %s. Будет удалено!"
+
+msgid ""
+"\n"
+"Cannot execute shell sh\n"
+msgstr ""
+"\n"
+"Ðевозможно запуÑтить оболочку sh\n"
+
+msgid ""
+"\n"
+"shell returned "
+msgstr ""
+"\n"
+"Оболочка завершила работу "
+
+msgid ""
+"\n"
+"Cannot create pipes\n"
+msgstr ""
+"\n"
+"Ðевозможно Ñоздать трубы\n"
+
+msgid ""
+"\n"
+"Cannot fork\n"
+msgstr ""
+"\n"
+"Ðевозможно выполнить fork()\n"
+
+msgid ""
+"\n"
+"Cannot execute shell "
+msgstr ""
+"\n"
+"Ðевозможно запуÑтить оболочку "
+
+msgid ""
+"\n"
+"Command terminated\n"
+msgstr ""
+"\n"
+"Выполнение команды прервано\n"
+
+msgid "XSMP lost ICE connection"
+msgstr "XSMP утерÑно Ñоединение ICE"
+
+#, c-format
+msgid "dlerror = \"%s\""
+msgstr "dlerror = \"%s\""
+
+msgid "Opening the X display failed"
+msgstr "Ðеудачное открытие диÑÐ¿Ð»ÐµÑ X"
+
+msgid "XSMP handling save-yourself request"
+msgstr "XSMP обрабатывает Ð·Ð°Ð¿Ñ€Ð¾Ñ ÑамоÑохранениÑ"
+
+msgid "XSMP opening connection"
+msgstr "XSMP открывает Ñоединение"
+
+msgid "XSMP ICE connection watch failed"
+msgstr "XSMP потерÑно Ñлежение за Ñоединением ICE"
+
+#, c-format
+msgid "XSMP SmcOpenConnection failed: %s"
+msgstr "XSMP неудачно выполнено SmcOpenConnection: %s"
+
+msgid "At line"
+msgstr "Ð’ Ñтроке"
+
+msgid "Could not load vim32.dll!"
+msgstr "Ðевозможно загрузить vim32.dll!"
+
+msgid "VIM Error"
+msgstr "Ошибка VIM"
+
+msgid "Could not fix up function pointers to the DLL!"
+msgstr "Ðевозможно иÑправить указатели функций Ð´Ð»Ñ DLL!"
+
+#, c-format
+msgid "Vim: Caught %s event\n"
+msgstr "Vim: Перехвачено Ñобытие %s\n"
+
+msgid "close"
+msgstr "закрытие"
+
+msgid "logoff"
+msgstr "отключение"
+
+msgid "shutdown"
+msgstr "завершение"
+
+msgid "E371: Command not found"
+msgstr "E371: Команда не найдена"
+
+msgid ""
+"VIMRUN.EXE not found in your $PATH.\n"
+"External commands will not pause after completion.\n"
+"See :help win32-vimrun for more information."
+msgstr ""
+"VIMRUN.EXE не найден в пути, заданном в $PATH.\n"
+"Внешние команды не будут оÑтанавливатьÑÑ Ð¿Ð¾Ñле выполнениÑ.\n"
+"Ð”Ð¾Ð¿Ð¾Ð»Ð½Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð°Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð² :help win32-vimrun"
+
+msgid "Vim Warning"
+msgstr "Предупреждение Vim"
+
+#, c-format
+msgid "shell returned %d"
+msgstr "завершение работы оболочки Ñ ÐºÐ¾Ð´Ð¾Ð¼ %d"
+
+msgid "E926: Current location list was changed"
+msgstr "E926: Изменён ÑпиÑок текущих раÑположений"
+
+#, c-format
+msgid "E372: Too many %%%c in format string"
+msgstr "E372: Ð’ Ñтроке формата Ñлишком много %%%c"
+
+#, c-format
+msgid "E373: Unexpected %%%c in format string"
+msgstr "E373: Ðеожиданный Ñлемент %%%c в Ñтроке формата"
+
+msgid "E374: Missing ] in format string"
+msgstr "E374: Ð’ Ñтроке формата пропущена ]"
+
+#, c-format
+msgid "E375: Unsupported %%%c in format string"
+msgstr "E375: %%%c не поддерживаетÑÑ Ð² Ñтроке формата"
+
+#, c-format
+msgid "E376: Invalid %%%c in format string prefix"
+msgstr "E376: ÐедопуÑтимый %%%c в приÑтавке в Ñтроке формата"
+
+#, c-format
+msgid "E377: Invalid %%%c in format string"
+msgstr "E377: ÐедопуÑтимый %%%c в Ñтроке формата"
+
+msgid "E378: 'errorformat' contains no pattern"
+msgstr "E378: Ð’ значении опции 'errorformat' отÑутÑтвует шаблон"
+
+msgid "E379: Missing or empty directory name"
+msgstr "E379: Ð˜Ð¼Ñ ÐºÐ°Ñ‚Ð°Ð»Ð¾Ð³Ð° не задано или равно пуÑтой Ñтроке"
+
+msgid "E553: No more items"
+msgstr "E553: Больше нет Ñлементов"
+
+msgid "E924: Current window was closed"
+msgstr "E924: Текущее окно было закрыто"
+
+msgid "E925: Current quickfix was changed"
+msgstr "E925: Изменён ÑпиÑок текущих быÑтрых иÑправлений"
+
+#, c-format
+msgid "(%d of %d)%s%s: "
+msgstr "(%d из %d)%s%s: "
+
+msgid " (line deleted)"
+msgstr " (Ñтрока удалена)"
+
+#, c-format
+msgid "%serror list %d of %d; %d errors "
+msgstr "%sÑпиÑок ошибок %d из %d; %d ошибок"
+
+msgid "E380: At bottom of quickfix stack"
+msgstr "E380: Внизу Ñтека быÑтрых иÑправлений"
+
+msgid "E381: At top of quickfix stack"
+msgstr "E381: Ðаверху Ñтека быÑтрых иÑправлений"
+
+msgid "No entries"
+msgstr "Ðет Ñлементов"
+
+msgid "Error file"
+msgstr "Файл ошибок"
+
+msgid "E683: File name missing or invalid pattern"
+msgstr "E683: Ðет имени файла или неправильный шаблон"
+
+#, c-format
+msgid "Cannot open file \"%s\""
+msgstr "Ðевозможно открыть файл \"%s\""
+
+msgid "E681: Buffer is not loaded"
+msgstr "E681: Буфер не выгружен"
+
+msgid "E777: String or List expected"
+msgstr "E777: ТребуетÑÑ Ñтрока или ÑпиÑок"
+
+#, c-format
+msgid "E369: invalid item in %s%%[]"
+msgstr "E369: ÐедопуÑтимый Ñлемент в %s%%[]"
+
+#, c-format
+msgid "E769: Missing ] after %s["
+msgstr "E769: Пропущена ] поÑле %s["
+
+msgid "E944: Reverse range in character class"
+msgstr "E944: Обратный диапазон в Ñимвольном клаÑÑе"
+
+msgid "E945: Range too large in character class"
+msgstr "E945: Диапазон Ñлишком велик в Ñимвольном клаÑÑе"
+
+#, c-format
+msgid "E53: Unmatched %s%%("
+msgstr "E53: Ðет пары Ð´Ð»Ñ %s%%("
+
+#, c-format
+msgid "E54: Unmatched %s("
+msgstr "E54: Ðет пары Ð´Ð»Ñ %s("
+
+#, c-format
+msgid "E55: Unmatched %s)"
+msgstr "E55: Ðет пары Ð´Ð»Ñ %s)"
+
+msgid "E66: \\z( not allowed here"
+msgstr "E66: \\z( не может быть иÑпользовано здеÑÑŒ"
+
+msgid "E67: \\z1 - \\z9 not allowed here"
+msgstr "E67: \\z1 и Ñ‚.п. не могут быть иÑпользованы здеÑÑŒ"
+
+#, c-format
+msgid "E69: Missing ] after %s%%["
+msgstr "E69: Пропущена ] поÑле %s%%["
+
+#, c-format
+msgid "E70: Empty %s%%[]"
+msgstr "E70: ПуÑтое %s%%[]"
+
+msgid "E65: Illegal back reference"
+msgstr "E65: ÐедопуÑÑ‚Ð¸Ð¼Ð°Ñ Ð¾Ð±Ñ€Ð°Ñ‚Ð½Ð°Ñ ÑÑылка"
+
+msgid "E339: Pattern too long"
+msgstr "E339: Слишком длинный шаблон"
+
+msgid "E50: Too many \\z("
+msgstr "E50: Слишком много \\z("
+
+#, c-format
+msgid "E51: Too many %s("
+msgstr "E51: Слишком много %s("
+
+msgid "E52: Unmatched \\z("
+msgstr "E52: Ðет пары Ð´Ð»Ñ \\z("
+
+#, c-format
+msgid "E59: invalid character after %s@"
+msgstr "E59: ÐедопуÑтимый Ñимвол поÑле %s@"
+
+#, c-format
+msgid "E60: Too many complex %s{...}s"
+msgstr "E60: Слишком много Ñложных конÑтрукций %s{...}"
+
+#, c-format
+msgid "E61: Nested %s*"
+msgstr "E61: Вложенные %s*"
+
+#, c-format
+msgid "E62: Nested %s%c"
+msgstr "E62: Вложенные %s%c"
+
+msgid "E63: invalid use of \\_"
+msgstr "E63: ÐедопуÑтимое иÑпользование \\_"
+
+#, c-format
+msgid "E64: %s%c follows nothing"
+msgstr "E64: %s%c ни за чем не Ñледует"
+
+msgid "E68: Invalid character after \\z"
+msgstr "E68: ÐедопуÑтимый Ñимвол поÑле \\z"
+
+#, c-format
+msgid "E678: Invalid character after %s%%[dxouU]"
+msgstr "E678: ÐедопуÑтимый Ñимвол поÑле %s%%[dxouU]"
+
+#, c-format
+msgid "E71: Invalid character after %s%%"
+msgstr "E71: ÐедопуÑтимый Ñимвол поÑле %s%%"
+
+#, c-format
+msgid "E554: Syntax error in %s{...}"
+msgstr "E554: СинтакÑичеÑÐºÐ°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ° в %s{...}"
+
+msgid "External submatches:\n"
+msgstr "Внешние подÑоответÑтвиÑ:\n"
+
+#, c-format
+msgid "E888: (NFA regexp) cannot repeat %s"
+msgstr "E888: (рег. выражение ÐКÐ) невозможно повторить %s"
+
+msgid ""
+"E864: \\%#= can only be followed by 0, 1, or 2. The automatic engine will be "
+"used "
+msgstr ""
+"E864: поÑле \\%#= может быть только 0, 1 или 2. Будет иÑпользоватьÑÑ "
+"автоматичеÑÐºÐ°Ñ Ð¼Ð°ÑˆÐ¸Ð½Ð°"
+
+msgid "Switching to backtracking RE engine for pattern: "
+msgstr "Включено отÑлеживание движка рег. выражений Ð´Ð»Ñ ÑˆÐ°Ð±Ð»Ð¾Ð½Ð°: "
+
+msgid "E865: (NFA) Regexp end encountered prematurely"
+msgstr "E865: (ÐКÐ) неожиданный конец регулÑрного выражениÑ"
+
+#, c-format
+msgid "E866: (NFA regexp) Misplaced %c"
+msgstr "E866: (рег. выражение ÐКÐ) неожиданный %c"
+
+#, c-format
+msgid "E877: (NFA regexp) Invalid character class: %ld"
+msgstr "E877: (рег. выражение ÐКÐ) неправильный клаÑÑ Ñимволов: %ld"
+
+#, c-format
+msgid "E867: (NFA) Unknown operator '\\z%c'"
+msgstr "E867: (ÐКÐ) неизвеÑтный оператор '\\z%c'"
+
+msgid "E951: \\% value too large"
+msgstr "E951: \\% значение Ñлишком большое"
+
+#, c-format
+msgid "E867: (NFA) Unknown operator '\\%%%c'"
+msgstr "E867: (ÐКÐ) неизвеÑтный оператор '\\%%%c'"
+
+msgid "E868: Error building NFA with equivalence class!"
+msgstr "E868: ошибка при Ñоздании ÐÐšÐ Ñ ÐºÐ»Ð°ÑÑом ÑквивалентноÑти!"
+
+#, c-format
+msgid "E869: (NFA) Unknown operator '\\@%c'"
+msgstr "E869: (ÐКÐ) неизвеÑтный оператор '\\@%c'"
+
+msgid "E870: (NFA regexp) Error reading repetition limits"
+msgstr "E870: (рег. выражение ÐКÐ) ошибка при чтении границ повторениÑ"
+
+msgid "E871: (NFA regexp) Can't have a multi follow a multi"
+msgstr "E871: (рег. выражение ÐКÐ) множеÑтво не может Ñледовать за множеÑтвом"
+
+msgid "E872: (NFA regexp) Too many '('"
+msgstr "E872: (рег. выражение ÐКÐ) Ñлишком много '('"
+
+msgid "E879: (NFA regexp) Too many \\z("
+msgstr "E879: (рег. выражение ÐКÐ) Ñлишком много \\z("
+
+msgid "E873: (NFA regexp) proper termination error"
+msgstr "E873: (рег. выражение ÐКÐ) ошибка корректного завершениÑ"
+
+msgid "E874: (NFA) Could not pop the stack!"
+msgstr "E874: (рег. выражение ÐКÐ) невозможно взÑÑ‚ÑŒ из Ñтека!"
+
+msgid ""
+"E875: (NFA regexp) (While converting from postfix to NFA), too many states "
+"left on stack"
+msgstr ""
+"E875: (рег. выражение ÐКÐ) в Ñтеке оÑталоÑÑŒ Ñлишком много ÑоÑтоÑний (при "
+"преобразовании из postfix в ÐКÐ)"
+
+msgid "E876: (NFA regexp) Not enough space to store the whole NFA "
+msgstr "E876: (рег. выражение ÐКÐ) недоÑтаточно меÑта Ð´Ð»Ñ Ñ…Ñ€Ð°Ð½ÐµÐ½Ð¸Ñ Ð²Ñего ÐКÐ"
+
+msgid "E878: (NFA) Could not allocate memory for branch traversal!"
+msgstr "E878: (ÐКÐ) невозможно выделить памÑÑ‚ÑŒ Ð´Ð»Ñ Ð¿Ñ€Ð¾Ñ…Ð¾Ð´Ð° ветви!"
+
+msgid ""
+"Could not open temporary log file for writing, displaying on stderr... "
+msgstr ""
+"Ðевозможно открыть файл временного журнала Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñи, вывод на stderr..."
+
+#, c-format
+msgid "(NFA) COULD NOT OPEN %s !"
+msgstr "(ÐКÐ) невозможно открыть %s!"
+
+msgid "Could not open temporary log file for writing "
+msgstr "Ðевозможно открыть файл временного журнала Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñи"
+
+msgid " VREPLACE"
+msgstr " ВИРТУÐЛЬÐÐЯ ЗÐМЕÐÐ"
+
+msgid " REPLACE"
+msgstr " ЗÐМЕÐÐ"
+
+msgid " REVERSE"
+msgstr " ОБРÐТÐÐЯ"
+
+msgid " INSERT"
+msgstr " ВСТÐВКÐ"
+
+msgid " (insert)"
+msgstr " (вÑтавка)"
+
+msgid " (replace)"
+msgstr " (замена)"
+
+msgid " (vreplace)"
+msgstr " (Ð²Ð¸Ñ€Ñ‚ÑƒÐ°Ð»ÑŒÐ½Ð°Ñ Ð·Ð°Ð¼ÐµÐ½Ð°)"
+
+msgid " Hebrew"
+msgstr " Иврит"
+
+msgid " Arabic"
+msgstr " ÐрабÑкий"
+
+msgid " (paste)"
+msgstr " (вклейка)"
+
+msgid " VISUAL"
+msgstr " ВИЗУÐЛЬÐЫЙ РЕЖИМ"
+
+msgid " VISUAL LINE"
+msgstr " ВИЗУÐЛЬÐÐЯ СТРОКÐ"
+
+msgid " VISUAL BLOCK"
+msgstr " ВИЗУÐЛЬÐЫЙ БЛОК"
+
+msgid " SELECT"
+msgstr " ВЫДЕЛЕÐИЕ"
+
+msgid " SELECT LINE"
+msgstr " ВЫДЕЛЕÐИЕ СТРОКИ"
+
+msgid " SELECT BLOCK"
+msgstr " ВЫДЕЛЕÐИЕ БЛОКÐ"
+
+msgid "recording"
+msgstr "запиÑÑŒ"
+
+#, c-format
+msgid "E383: Invalid search string: %s"
+msgstr "E383: ÐÐµÐ¿Ñ€Ð°Ð²Ð¸Ð»ÑŒÐ½Ð°Ñ Ñтрока поиÑка: %s"
+
+#, c-format
+msgid "E384: search hit TOP without match for: %s"
+msgstr "E384: ПоиÑк закончен в ÐÐЧÐЛЕ документа; %s не найдено"
+
+#, c-format
+msgid "E385: search hit BOTTOM without match for: %s"
+msgstr "E385: ПоиÑк закончен в КОÐЦЕ документа; %s не найдено"
+
+msgid "E386: Expected '?' or '/' after ';'"
+msgstr "E386: ПоÑле ';' ожидаетÑÑ Ð²Ð²Ð¾Ð´ '?' или '/'"
+
+msgid " (includes previously listed match)"
+msgstr " (включает раннее показанные ÑоответÑтвиÑ)"
+
+msgid "--- Included files "
+msgstr "--- Включённые файлы "
+
+msgid "not found "
+msgstr "не найдено "
+
+msgid "in path ---\n"
+msgstr "по пути ---\n"
+
+msgid " (Already listed)"
+msgstr " (Уже показано)"
+
+msgid " NOT FOUND"
+msgstr " ÐЕ ÐÐЙДЕÐО"
+
+#, c-format
+msgid "Scanning included file: %s"
+msgstr "ПроÑмотр включённых файлов: %s"
+
+#, c-format
+msgid "Searching included file %s"
+msgstr "ПоиÑк включённого файла %s"
+
+msgid "E387: Match is on current line"
+msgstr "E387: СоответÑтвие в текущей Ñтроке"
+
+msgid "All included files were found"
+msgstr "Ðайдены вÑе включённые файлы"
+
+msgid "No included files"
+msgstr "Включённых файлов нет"
+
+msgid "E388: Couldn't find definition"
+msgstr "E388: Определение не найдено"
+
+msgid "E389: Couldn't find pattern"
+msgstr "E389: Шаблон не найден"
+
+msgid "Substitute "
+msgstr "Замена "
+
+#, c-format
+msgid ""
+"\n"
+"# Last %sSearch Pattern:\n"
+"~"
+msgstr ""
+"\n"
+"# ПоÑледний %sШаблон поиÑка:\n"
+"~"
+
+msgid "E756: Spell checking is not enabled"
+msgstr "E756: Проверка правопиÑÐ°Ð½Ð¸Ñ Ð²Ñ‹ÐºÐ»ÑŽÑ‡ÐµÐ½Ð°"
+
+#, c-format
+msgid "Warning: Cannot find word list \"%s_%s.spl\" or \"%s_ascii.spl\""
+msgstr ""
+"Предупреждение: Ðевозможно найти ÑпиÑок Ñлов \"%s_%s.spl\" или \"%s_ascii.spl"
+"\""
+
+#, c-format
+msgid "Warning: Cannot find word list \"%s.%s.spl\" or \"%s.ascii.spl\""
+msgstr ""
+"Предупреждение: Ðевозможно найти ÑпиÑок Ñлов \"%s.%s.spl\" или \"%s.ascii.spl"
+"\""
+
+msgid "E797: SpellFileMissing autocommand deleted buffer"
+msgstr "E797: Буфер удалён при выполнении автокоманды SpellFileMissing"
+
+#, c-format
+msgid "Warning: region %s not supported"
+msgstr "Предупреждение: регион %s не поддерживаетÑÑ"
+
+msgid "Sorry, no suggestions"
+msgstr "Извините, нет предположений"
+
+#, c-format
+msgid "Sorry, only %ld suggestions"
+msgstr "Извините, только %ld предположений"
+
+#, c-format
+msgid "Change \"%.*s\" to:"
+msgstr "Заменить \"%.*s\" на:"
+
+#, c-format
+msgid " < \"%.*s\""
+msgstr " < \"%.*s\""
+
+msgid "E752: No previous spell replacement"
+msgstr "E752: Ðет предыдущей замены правопиÑаниÑ"
+
+#, c-format
+msgid "E753: Not found: %s"
+msgstr "E753: Ðе найдено: %s"
+
+msgid "E758: Truncated spell file"
+msgstr "E758: Файл правопиÑÐ°Ð½Ð¸Ñ Ð¾Ð±Ñ€ÐµÐ·Ð°Ð½"
+
+#, c-format
+msgid "Trailing text in %s line %d: %s"
+msgstr "Лишний текÑÑ‚ на хвоÑте в %s ÑÑ‚Ñ€. %d: %s"
+
+#, c-format
+msgid "Affix name too long in %s line %d: %s"
+msgstr "Ð˜Ð¼Ñ Ð°Ñ„Ñ„Ð¸ÐºÑа Ñлишком длинное в %s, Ñтрока %d: %s"
+
+msgid "E761: Format error in affix file FOL, LOW or UPP"
+msgstr "E761: Ошибка формата в файле аффикÑов FOL, LOW или UPP"
+
+msgid "E762: Character in FOL, LOW or UPP is out of range"
+msgstr "E762: Символы в FOL, LOW или UPP за пределами диапазона"
+
+msgid "Compressing word tree..."
+msgstr "Сжатие дерева Ñлов..."
+
+#, c-format
+msgid "Reading spell file \"%s\""
+msgstr "Чтение файла правопиÑÐ°Ð½Ð¸Ñ \"%s\""
+
+msgid "E757: This does not look like a spell file"
+msgstr "E757: Это не похоже на файл правопиÑаниÑ"
+
+msgid "E771: Old spell file, needs to be updated"
+msgstr "E771: Старый файл правопиÑаниÑ, требуетÑÑ ÐµÐ³Ð¾ обновление"
+
+msgid "E772: Spell file is for newer version of Vim"
+msgstr "E772: Файл правопиÑÐ°Ð½Ð¸Ñ Ð¿Ñ€ÐµÐ´Ð½Ð°Ð·Ð½Ð°Ñ‡ÐµÐ½ Ð´Ð»Ñ Ð±Ð¾Ð»ÐµÐµ новой верÑии Vim"
+
+msgid "E770: Unsupported section in spell file"
+msgstr "E770: Ðеподдерживаемый раздел в файле правопиÑаниÑ"
+
+#, c-format
+msgid "E778: This does not look like a .sug file: %s"
+msgstr "E778: Это не похоже на файл .sug: %s"
+
+#, c-format
+msgid "E779: Old .sug file, needs to be updated: %s"
+msgstr "E779: Старый файл .sug, требует обновлениÑ: %s"
+
+#, c-format
+msgid "E780: .sug file is for newer version of Vim: %s"
+msgstr "E780: Файл .sug Ð´Ð»Ñ Ð±Ð¾Ð»ÐµÐµ новой верÑии Vim: %s"
+
+#, c-format
+msgid "E781: .sug file doesn't match .spl file: %s"
+msgstr "E781: Файл .sug не ÑоответÑтвует файлу .spl: %s"
+
+#, c-format
+msgid "E782: error while reading .sug file: %s"
+msgstr "E782: Ошибка при чтении файла .sug: %s"
+
+#, c-format
+msgid "Reading affix file %s..."
+msgstr "Чтение файла аффикÑов %s..."
+
+#, c-format
+msgid "Conversion failure for word in %s line %d: %s"
+msgstr "Ðе удалоÑÑŒ преобразовать Ñлово в %s, Ñтрока %d: %s"
+
+#, c-format
+msgid "Conversion in %s not supported: from %s to %s"
+msgstr "Преобразование в %s не поддерживаетÑÑ: из %s в %s"
+
+#, c-format
+msgid "Conversion in %s not supported"
+msgstr "Преобразование в %s не поддерживаетÑÑ"
+
+#, c-format
+msgid "Invalid value for FLAG in %s line %d: %s"
+msgstr "Ðеправильное значение FLAG в %s, Ñтрока %d: %s"
+
+#, c-format
+msgid "FLAG after using flags in %s line %d: %s"
+msgstr "FLAG поÑле иÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ñ„Ð»Ð°Ð³Ð¾Ð² в %s, Ñтрока %d: %s"
+
+#, c-format
+msgid ""
+"Defining COMPOUNDFORBIDFLAG after PFX item may give wrong results in %s line "
+"%d"
+msgstr ""
+"Определение COMPOUNDFORBIDFLAG поÑле Ñлемента PFX может дать неправильные "
+"результаты в %s, Ñтрока %d"
+
+#, c-format
+msgid ""
+"Defining COMPOUNDPERMITFLAG after PFX item may give wrong results in %s line "
+"%d"
+msgstr ""
+"Определение COMPOUNDPERMITFLAG поÑле Ñлемента PFX может дать неправильные "
+"результаты в %s, Ñтрока %d"
+
+#, c-format
+msgid "Wrong COMPOUNDRULES value in %s line %d: %s"
+msgstr "Ðеправильное значение COMPOUNDRULES в %s, Ñтрока %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDWORDMAX value in %s line %d: %s"
+msgstr "Ðеправильное значение COMPOUNDWORDMAX в %s, Ñтрока %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDMIN value in %s line %d: %s"
+msgstr "Ðеправильное значение COMPOUNDMIN в %s, Ñтрока %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDSYLMAX value in %s line %d: %s"
+msgstr "Ðеправильное значение COMPOUNDSYLMAX в %s, Ñтрока %d: %s"
+
+#, c-format
+msgid "Wrong CHECKCOMPOUNDPATTERN value in %s line %d: %s"
+msgstr "Ðеправильное значение CHECKCOMPOUNDPATTERN в %s, Ñтрока %d: %s"
+
+#, c-format
+msgid "Different combining flag in continued affix block in %s line %d: %s"
+msgstr ""
+"Другой объединÑющий флаг в продолжающем блоке аффикÑа в %s, Ñтрока %d: %s"
+
+#, c-format
+msgid "Duplicate affix in %s line %d: %s"
+msgstr "ПовторÑющийÑÑ Ð°Ñ„Ñ„Ð¸ÐºÑ Ð² %s, Ñтрока %d: %s"
+
+#, c-format
+msgid ""
+"Affix also used for BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST in %s "
+"line %d: %s"
+msgstr ""
+"ÐÑ„Ñ„Ð¸ÐºÑ Ñ‚Ð°ÐºÐ¶Ðµ иÑпользуетÑÑ Ð´Ð»Ñ BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/"
+"NOSUGGEST в %s, Ñтрока %d: %s"
+
+#, c-format
+msgid "Expected Y or N in %s line %d: %s"
+msgstr "ОжидалоÑÑŒ Y или N в %s, Ñтрока %d: %s"
+
+#, c-format
+msgid "Broken condition in %s line %d: %s"
+msgstr "Ðарушенное уÑловие в %s, Ñтрока %d: %s"
+
+#, c-format
+msgid "Expected REP(SAL) count in %s line %d"
+msgstr "ОжидалÑÑ Ñчётчик REP(SAL) в %s, Ñтрока %d"
+
+#, c-format
+msgid "Expected MAP count in %s line %d"
+msgstr "ОжидалÑÑ Ñчётчик MAP в %s, Ñтрока %d"
+
+#, c-format
+msgid "Duplicate character in MAP in %s line %d"
+msgstr "ПовторÑющийÑÑ Ñимвол в MAP в %s, Ñтрока %d"
+
+#, c-format
+msgid "Unrecognized or duplicate item in %s line %d: %s"
+msgstr "ÐераÑпознанный или повторÑющийÑÑ Ñлемент в %s, Ñтрока %d: %s"
+
+#, c-format
+msgid "Missing FOL/LOW/UPP line in %s"
+msgstr "Пропущена Ñтрока FOL/LOW/UPP в %s"
+
+msgid "COMPOUNDSYLMAX used without SYLLABLE"
+msgstr "COMPOUNDSYLMAX иÑпользуетÑÑ Ð±ÐµÐ· SYLLABLE"
+
+msgid "Too many postponed prefixes"
+msgstr "Слишком много отложенных префикÑов"
+
+msgid "Too many compound flags"
+msgstr "Слишком много ÑоÑтавных флагов"
+
+msgid "Too many postponed prefixes and/or compound flags"
+msgstr "Слишком много отложенных префикÑов и/или ÑоÑтавных флагов"
+
+#, c-format
+msgid "Missing SOFO%s line in %s"
+msgstr "Пропущена Ñтрока SOFO%s в %s"
+
+#, c-format
+msgid "Both SAL and SOFO lines in %s"
+msgstr "Обе Ñтроки SAL и SOFO в %s"
+
+#, c-format
+msgid "Flag is not a number in %s line %d: %s"
+msgstr "Флаг не ÑвлÑетÑÑ Ñ‡Ð¸Ñлом в %s, Ñтрока %d: %s"
+
+#, c-format
+msgid "Illegal flag in %s line %d: %s"
+msgstr "ÐедопуÑтимый флаг в %s на Ñтроке %d: %s"
+
+#, c-format
+msgid "%s value differs from what is used in another .aff file"
+msgstr "%s имеет другое значение, чем в файле .aff"
+
+#, c-format
+msgid "Reading dictionary file %s..."
+msgstr "Чтение файла ÑÐ»Ð¾Ð²Ð°Ñ€Ñ %s..."
+
+#, c-format
+msgid "E760: No word count in %s"
+msgstr "E760: КоличеÑтво Ñлов не указано в %s"
+
+#, c-format
+msgid "line %6d, word %6ld - %s"
+msgstr "Ñтрока %6d, Ñлово %6ld — %s"
+
+#, c-format
+msgid "Duplicate word in %s line %d: %s"
+msgstr "Повтор Ñлова в %s на Ñтроке %d: %s "
+
+#, c-format
+msgid "First duplicate word in %s line %d: %s"
+msgstr "Первый повтор Ñлова в %s на Ñтроке %d: %s"
+
+#, c-format
+msgid "%d duplicate word(s) in %s"
+msgstr "%d повторÑющихÑÑ Ñлов в %s"
+
+#, c-format
+msgid "Ignored %d word(s) with non-ASCII characters in %s"
+msgstr "Пропущено %d Ñлов Ñ Ð½Ðµ ASCII Ñимволами в %s"
+
+#, c-format
+msgid "Reading word file %s..."
+msgstr "Чтение файла Ñлов %s..."
+
+#, c-format
+msgid "Duplicate /encoding= line ignored in %s line %d: %s"
+msgstr "Проигнорирована повторÑющаÑÑÑ Ñтрока /encoding= в %s, Ñтрока %d: %s"
+
+#, c-format
+msgid "/encoding= line after word ignored in %s line %d: %s"
+msgstr "Проигнорирована Ñтрока /encoding= поÑле Ñлова в %s, Ñтрока %d: %s"
+
+#, c-format
+msgid "Duplicate /regions= line ignored in %s line %d: %s"
+msgstr "ПропуÑкаетÑÑ Ð¿Ð¾Ð²Ñ‚Ð¾Ñ€ Ñтроки /regions= в %s, Ñтрока %d: %s"
+
+#, c-format
+msgid "Too many regions in %s line %d: %s"
+msgstr "Слишком много регионов в %s, Ñтрока %d: %s"
+
+#, c-format
+msgid "/ line ignored in %s line %d: %s"
+msgstr "/ Ñтрока пропуÑкаетÑÑ Ð² %s, Ñтрока %d: %s"
+
+#, c-format
+msgid "Invalid region nr in %s line %d: %s"
+msgstr "ÐедопуÑтимый номер региона в %s, Ñтрока %d: %s"
+
+#, c-format
+msgid "Unrecognized flags in %s line %d: %s"
+msgstr "ÐераÑпознанные флаги в %s, Ñтрока %d: %s"
+
+#, c-format
+msgid "Ignored %d words with non-ASCII characters"
+msgstr "Пропущено %d Ñлов Ñ Ð½Ðµ ASCII Ñимволами"
+
+msgid "E845: Insufficient memory, word list will be incomplete"
+msgstr "E845: ÐедоÑтаточно оперативной памÑти, ÑпиÑок Ñлов будет не полон"
+
+#, c-format
+msgid "Compressed %d of %d nodes; %d (%d%%) remaining"
+msgstr "Сжато %d из %d узлов; оÑталоÑÑŒ %d (%d%%)"
+
+msgid "Reading back spell file..."
+msgstr "Чтение запиÑанного файла правопиÑаниÑ..."
+
+msgid "Performing soundfolding..."
+msgstr "Выполнение звуковой Ñвёртки..."
+
+#, c-format
+msgid "Number of words after soundfolding: %ld"
+msgstr "КоличеÑтво Ñлов поÑле звуковой Ñвёртки: %ld"
+
+#, c-format
+msgid "Total number of words: %d"
+msgstr "Общее количеÑтво Ñлов: %d"
+
+#, c-format
+msgid "Writing suggestion file %s..."
+msgstr "ЗапиÑÑŒ файла Ð¿Ñ€ÐµÐ´Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¸Ñправлений правопиÑÐ°Ð½Ð¸Ñ %s"
+
+#, c-format
+msgid "Estimated runtime memory use: %d bytes"
+msgstr "Оценка иÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¿Ð°Ð¼Ñти при выполнении: %d байт"
+
+msgid "E751: Output file name must not have region name"
+msgstr "E751: Ð˜Ð¼Ñ Ð²Ñ‹Ñ…Ð¾Ð´Ð½Ð¾Ð³Ð¾ файла не должно Ñодержать Ð½Ð°Ð·Ð²Ð°Ð½Ð¸Ñ Ñ€ÐµÐ³Ð¸Ð¾Ð½Ð°"
+
+#, c-format
+msgid "E754: Only up to %ld regions supported"
+msgstr "E754: ПоддерживаетÑÑ Ð½Ðµ более %ld регионов"
+
+#, c-format
+msgid "E755: Invalid region in %s"
+msgstr "E755: ÐедопуÑтимый регион в %s"
+
+msgid "Warning: both compounding and NOBREAK specified"
+msgstr "Предупреждение: оба ÑоÑтавные и указано NOBREAK"
+
+#, c-format
+msgid "Writing spell file %s..."
+msgstr "ЗапиÑÑŒ файла правопиÑÐ°Ð½Ð¸Ñ %s..."
+
+msgid "Done!"
+msgstr "Завершено!"
+
+#, c-format
+msgid "E765: 'spellfile' does not have %ld entries"
+msgstr "E765: 'spellfile' не Ñодержит %ld Ñлементов"
+
+#, c-format
+msgid "Word '%.*s' removed from %s"
+msgstr "Слово '%.*s' удалено из %s"
+
+#, c-format
+msgid "Word '%.*s' added to %s"
+msgstr "Слово '%.*s' добавлено в %s"
+
+msgid "E763: Word characters differ between spell files"
+msgstr "E763: Символы Ñлов отличаютÑÑ Ð² файлах правопиÑаниÑ"
+
+msgid "E783: duplicate char in MAP entry"
+msgstr "E783: ПовторÑющийÑÑ Ñимвол в Ñлементе MAP"
+
+msgid "No Syntax items defined for this buffer"
+msgstr "СинтакÑичеÑкие Ñлементы Ð´Ð»Ñ Ð´Ð°Ð½Ð½Ð¾Ð³Ð¾ буфера не определены"
+
+msgid "syntax conceal on"
+msgstr "ÑинтакÑичеÑкое Ñкрытие включено"
+
+msgid "syntax conceal off"
+msgstr "ÑинтакÑичеÑкое Ñкрытие отключено"
+
+#, c-format
+msgid "E390: Illegal argument: %s"
+msgstr "E390: ÐедопуÑтимый параметр: %s"
+
+msgid "syntax case ignore"
+msgstr "ÑинтакÑичеÑкое игнорирование региÑтра"
+
+msgid "syntax case match"
+msgstr "ÑинтакÑичеÑкое ÑоответÑтвие региÑтра"
+
+msgid "syntax spell toplevel"
+msgstr "ÑинтакÑичеÑÐºÐ°Ñ Ð¿Ñ€Ð¾Ð²ÐµÑ€ÐºÐ° правопиÑÐ°Ð½Ð¸Ñ Ð²ÐµÑ€Ñ…Ð½ÐµÐ³Ð¾ уровнÑ"
+
+msgid "syntax spell notoplevel"
+msgstr "ÑинтакÑичеÑÐºÐ°Ñ Ð¿Ñ€Ð¾Ð²ÐµÑ€ÐºÐ° правопиÑÐ°Ð½Ð¸Ñ Ð±ÐµÐ· верхнего уровнÑ"
+
+msgid "syntax spell default"
+msgstr "ÑинтакÑичеÑÐºÐ°Ñ Ð¿Ñ€Ð¾Ð²ÐµÑ€ÐºÐ° правопиÑÐ°Ð½Ð¸Ñ Ð¿Ð¾ умолчанию"
+
+msgid "syntax iskeyword "
+msgstr "ÑинтакÑичеÑкое ключевое Ñлово"
+
+#, c-format
+msgid "E391: No such syntax cluster: %s"
+msgstr "E391: СинтакÑичеÑкий клаÑтер %s не найден"
+
+msgid "syncing on C-style comments"
+msgstr "Ð¡Ð¸Ð½Ñ…Ñ€Ð¾Ð½Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð¿Ð¾ комментариÑм в Ñтиле Ñзыка C"
+
+msgid "no syncing"
+msgstr "без Ñинхронизации"
+
+msgid "syncing starts "
+msgstr "ÑÐ¸Ð½Ñ…Ñ€Ð¾Ð½Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð½Ð°Ñ‡Ð°Ñ‚Ð° "
+
+msgid " lines before top line"
+msgstr " Ñтрок перед верхней Ñтрокой"
+
+msgid ""
+"\n"
+"--- Syntax sync items ---"
+msgstr ""
+"\n"
+"--- Элементы Ñинхронизации ÑинтакÑиÑа ---"
+
+msgid ""
+"\n"
+"syncing on items"
+msgstr ""
+"\n"
+"ÑÐ¸Ð½Ñ…Ñ€Ð¾Ð½Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð¿Ð¾ Ñлементам"
+
+msgid ""
+"\n"
+"--- Syntax items ---"
+msgstr ""
+"\n"
+"--- СинтакÑичеÑкие Ñлементы ---"
+
+#, c-format
+msgid "E392: No such syntax cluster: %s"
+msgstr "E392: СинтакÑичеÑкий клаÑтер %s не найден"
+
+msgid "minimal "
+msgstr "минимум "
+
+msgid "maximal "
+msgstr "макÑимум "
+
+msgid "; match "
+msgstr "; ÑоответÑтвие "
+
+msgid " line breaks"
+msgstr " переноÑов Ñтрок"
+
+msgid "E395: contains argument not accepted here"
+msgstr "E395: ЗдеÑÑŒ Ð½ÐµÐ»ÑŒÐ·Ñ Ð¸Ñпользовать параметр contains"
+
+msgid "E844: invalid cchar value"
+msgstr "E844: ÐедопуÑтимое значение cchar"
+
+msgid "E393: group[t]here not accepted here"
+msgstr "E393: ЗдеÑÑŒ Ð½ÐµÐ»ÑŒÐ·Ñ Ð¸Ñпользовать group[t]here"
+
+#, c-format
+msgid "E394: Didn't find region item for %s"
+msgstr "E394: Элемент облаÑти Ð´Ð»Ñ %s не найден"
+
+msgid "E397: Filename required"
+msgstr "E397: ТребуетÑÑ ÑƒÐºÐ°Ð·Ð°Ñ‚ÑŒ Ð¸Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð°"
+
+msgid "E847: Too many syntax includes"
+msgstr "E847: Слишком много ÑинтакÑичеÑких включений"
+
+#, c-format
+msgid "E789: Missing ']': %s"
+msgstr "E789: Пропущено ']': %s"
+
+#, c-format
+msgid "E890: trailing char after ']': %s]%s"
+msgstr "E890: Лишние Ñимволы поÑле ']': %s]%s"
+
+#, c-format
+msgid "E398: Missing '=': %s"
+msgstr "E398: Пропущено '=': %s"
+
+#, c-format
+msgid "E399: Not enough arguments: syntax region %s"
+msgstr "E399: Ðе хватает параметров: ÑинтакÑичеÑкий регион %s"
+
+msgid "E848: Too many syntax clusters"
+msgstr "E848: Слишком много ÑинтакÑичеÑких клаÑтеров"
+
+msgid "E400: No cluster specified"
+msgstr "E400: КлаÑтер не указан"
+
+#, c-format
+msgid "E401: Pattern delimiter not found: %s"
+msgstr "E401: Ðе найден разделитель шаблонов: %s"
+
+#, c-format
+msgid "E402: Garbage after pattern: %s"
+msgstr "E402: МуÑор поÑле шаблона: %s"
+
+msgid "E403: syntax sync: line continuations pattern specified twice"
+msgstr ""
+"E403: Ð¡Ð¸Ð½Ñ…Ñ€Ð¾Ð½Ð¸Ð·Ð°Ñ†Ð¸Ñ ÑинтакÑиÑа: шаблон продолжений Ñтроки указан дважды"
+
+#, c-format
+msgid "E404: Illegal arguments: %s"
+msgstr "E404: ÐедопуÑтимые параметры: %s"
+
+#, c-format
+msgid "E405: Missing equal sign: %s"
+msgstr "E405: Пропущен знак равенÑтва: %s"
+
+#, c-format
+msgid "E406: Empty argument: %s"
+msgstr "E406: ПуÑтой параметр: %s"
+
+#, c-format
+msgid "E407: %s not allowed here"
+msgstr "E407: %s не допуÑкаетÑÑ Ð² Ñтом меÑте"
+
+#, c-format
+msgid "E408: %s must be first in contains list"
+msgstr "E408: %s должно быть первым в ÑпиÑке contains"
+
+#, c-format
+msgid "E409: Unknown group name: %s"
+msgstr "E409: ÐеизвеÑÑ‚Ð½Ð°Ñ Ð³Ñ€ÑƒÐ¿Ð¿Ð°: %s"
+
+#, c-format
+msgid "E410: Invalid :syntax subcommand: %s"
+msgstr "E410: ÐÐµÐ¿Ñ€Ð°Ð²Ð¸Ð»ÑŒÐ½Ð°Ñ Ð¿Ð¾Ð´ÐºÐ¾Ð¼Ð°Ð½Ð´Ð° :syntax: %s"
+
+msgid ""
+" TOTAL COUNT MATCH SLOWEST AVERAGE NAME PATTERN"
+msgstr ""
+" ВСЕГО КОЛ. СООТВ. ОТСТÐЮЩИЙ СРЕДÐИЙ ИМЯ ШÐБЛОÐ"
+
+msgid "E679: recursive loop loading syncolor.vim"
+msgstr "E679: РекурÑÐ¸Ð²Ð½Ð°Ñ Ð¿ÐµÑ‚Ð»Ñ Ð¿Ñ€Ð¸ загрузке syncolor.vim"
+
+#, c-format
+msgid "E411: highlight group not found: %s"
+msgstr "E411: Группа подÑветки ÑинтакÑиÑа %s не найдена"
+
+#, c-format
+msgid "E412: Not enough arguments: \":highlight link %s\""
+msgstr "E412: Ðе хватает параметров: \":highlight link %s\""
+
+#, c-format
+msgid "E413: Too many arguments: \":highlight link %s\""
+msgstr "E413: Слишком много параметров: \":highlight link %s\""
+
+msgid "E414: group has settings, highlight link ignored"
+msgstr "E414: У группы еÑÑ‚ÑŒ наÑтройки, пропуÑкаетÑÑ highlight link"
+
+#, c-format
+msgid "E415: unexpected equal sign: %s"
+msgstr "E415: Ðеожиданный знак равенÑтва: %s"
+
+#, c-format
+msgid "E416: missing equal sign: %s"
+msgstr "E416: Пропущен знак равенÑтва: %s"
+
+#, c-format
+msgid "E417: missing argument: %s"
+msgstr "E417: Пропущен параметр: %s"
+
+#, c-format
+msgid "E418: Illegal value: %s"
+msgstr "E418: ÐедопуÑтимое значение: %s"
+
+msgid "E419: FG color unknown"
+msgstr "E419: ÐеизвеÑтный цвет текÑта"
+
+msgid "E420: BG color unknown"
+msgstr "E420: ÐеизвеÑтный цвет фона"
+
+#, c-format
+msgid "E421: Color name or number not recognized: %s"
+msgstr "E421: Ð˜Ð¼Ñ Ð¸Ð»Ð¸ номер цвета не извеÑтно: %s"
+
+#, c-format
+msgid "E422: terminal code too long: %s"
+msgstr "E422: Слишком длинный код терминала: %s"
+
+#, c-format
+msgid "E423: Illegal argument: %s"
+msgstr "E423: ÐедопуÑтимый параметр: %s"
+
+msgid "E424: Too many different highlighting attributes in use"
+msgstr "E424: ИÑпользуетÑÑ Ñлишком много разных атрибутов подÑветки ÑинтакÑиÑа"
+
+msgid "E669: Unprintable character in group name"
+msgstr "E669: Ðепечатный Ñимвол в имени группы"
+
+msgid "W18: Invalid character in group name"
+msgstr "W18: ÐедопуÑтимый Ñимвол в имени группы"
+
+msgid "E849: Too many highlight and syntax groups"
+msgstr "E849: Слишком много групп подÑветки и ÑинтакÑиÑа"
+
+msgid "E555: at bottom of tag stack"
+msgstr "E555: Внизу Ñтека меток"
+
+msgid "E556: at top of tag stack"
+msgstr "E556: Ðаверху Ñтека меток"
+
+msgid "E425: Cannot go before first matching tag"
+msgstr "E425: Ðевозможно перейти в позицию до первой Ñовпадающей метки"
+
+#, c-format
+msgid "E426: tag not found: %s"
+msgstr "E426: Метка не найдена: %s"
+
+msgid " # pri kind tag"
+msgstr " # при тип метка"
+
+msgid "file\n"
+msgstr "файл\n"
+
+msgid "E427: There is only one matching tag"
+msgstr "E427: ЕÑÑ‚ÑŒ только одна ÑÐ¾Ð²Ð¿Ð°Ð´Ð°ÑŽÑ‰Ð°Ñ Ð¼ÐµÑ‚ÐºÐ°"
+
+msgid "E428: Cannot go beyond last matching tag"
+msgstr "E428: Ðевозможно перейти в позицию за поÑледней Ñовпадающей меткой"
+
+#, c-format
+msgid "File \"%s\" does not exist"
+msgstr "Файл \"%s\" не ÑущеÑтвует"
+
+#, c-format
+msgid "tag %d of %d%s"
+msgstr "метка %d из %d%s"
+
+msgid " or more"
+msgstr " и более"
+
+msgid " Using tag with different case!"
+msgstr " ИÑпользуетÑÑ Ð¼ÐµÑ‚ÐºÐ° Ñ Ñимволами в другом региÑтре!"
+
+#, c-format
+msgid "E429: File \"%s\" does not exist"
+msgstr "E429: Файл \"%s\" не ÑущеÑтвует"
+
+msgid ""
+"\n"
+" # TO tag FROM line in file/text"
+msgstr ""
+"\n"
+" # К метке ОТ ÑÑ‚Ñ€. в файле/текÑте"
+
+#, c-format
+msgid "Searching tags file %s"
+msgstr "ПоиÑк в файле меток %s"
+
+#, c-format
+msgid "E430: Tag file path truncated for %s\n"
+msgstr "E430: Путь к файлу меток %s обрезан\n"
+
+msgid "Ignoring long line in tags file"
+msgstr "Игнорирование длинной Ñтроки в файле tags"
+
+#, c-format
+msgid "E431: Format error in tags file \"%s\""
+msgstr "E431: Ошибка формата в файле меток \"%s\""
+
+#, c-format
+msgid "Before byte %ld"
+msgstr "Перед байтом %ld"
+
+#, c-format
+msgid "E432: Tags file not sorted: %s"
+msgstr "E432: Файл меток не отÑортирован: %s"
+
+msgid "E433: No tags file"
+msgstr "E433: Файл меток не обнаружен"
+
+msgid "E434: Can't find tag pattern"
+msgstr "E434: Ðе найден шаблон метки"
+
+msgid "E435: Couldn't find tag, just guessing!"
+msgstr "E435: Метка не найдена, пытаемÑÑ ÑƒÐ³Ð°Ð´Ð°Ñ‚ÑŒ!"
+
+#, c-format
+msgid "Duplicate field name: %s"
+msgstr "ПовторÑющееÑÑ Ð¸Ð¼Ñ Ð¿Ð¾Ð»Ñ: %s"
+
+msgid "' not known. Available builtin terminals are:"
+msgstr "' не извеÑтен. ДоÑтупны вÑтроенные терминалы:"
+
+msgid "defaulting to '"
+msgstr "по умолчанию '"
+
+msgid "E557: Cannot open termcap file"
+msgstr "E557: Ðевозможно открыть файл termcap"
+
+msgid "E558: Terminal entry not found in terminfo"
+msgstr "E558: Ð’ terminfo нет запиÑи об Ñтом терминале"
+
+msgid "E559: Terminal entry not found in termcap"
+msgstr "E559: Ð’ termcap нет запиÑи об Ñтом терминале"
+
+#, c-format
+msgid "E436: No \"%s\" entry in termcap"
+msgstr "E436: Ð’ termcap нет запиÑи \"%s\""
+
+msgid "E437: terminal capability \"cm\" required"
+msgstr "E437: ТребуетÑÑ ÑпоÑобноÑÑ‚ÑŒ терминала \"cm\""
+
+msgid ""
+"\n"
+"--- Terminal keys ---"
+msgstr ""
+"\n"
+"--- Кнопки терминала ---"
+
+msgid "Cannot open $VIMRUNTIME/rgb.txt"
+msgstr "Ðевозможно открыть $VIMRUNTIME/rgb.txt"
+
+#, c-format
+msgid "Kill job in \"%s\"?"
+msgstr "Убить задание в \"%s\"?"
+
+msgid "Terminal"
+msgstr "Терминал"
+
+msgid "Terminal-finished"
+msgstr "Терминал-завершено"
+
+msgid "active"
+msgstr "активно"
+
+msgid "running"
+msgstr "выполнение"
+
+msgid "finished"
+msgstr "завершено"
+
+#, c-format
+msgid "E953: File exists: %s"
+msgstr "E953: Файл ÑущеÑтвует: %s"
+
+msgid "E955: Not a terminal buffer"
+msgstr "E955: Ðе ÑвлÑетÑÑ Ð±ÑƒÑ„ÐµÑ€Ð¾Ð¼ терминала"
+
+msgid "new shell started\n"
+msgstr "запуÑк новой оболочки\n"
+
+msgid "Vim: Error reading input, exiting...\n"
+msgstr "Vim: Ошибка Ñ‡Ñ‚ÐµÐ½Ð¸Ñ Ð²Ð²Ð¾Ð´Ð°, выход...\n"
+
+msgid "Used CUT_BUFFER0 instead of empty selection"
+msgstr "ВмеÑто пуÑтого Ð²Ñ‹Ð´ÐµÐ»ÐµÐ½Ð¸Ñ Ð¸ÑпользуетÑÑ CUT_BUFFER0"
+
+msgid "E881: Line count changed unexpectedly"
+msgstr "E881: Ðеожиданно изменилÑÑ Ñчётчик Ñтрок"
+
+msgid "No undo possible; continue anyway"
+msgstr "Отмена невозможна; продолжать выполнение"
+
+#, c-format
+msgid "E828: Cannot open undo file for writing: %s"
+msgstr "E828: Ðевозможно открыть файл отмен Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñи: %s"
+
+#, c-format
+msgid "E825: Corrupted undo file (%s): %s"
+msgstr "E825: Файл отмен повреждён (%s): %s"
+
+msgid "Cannot write undo file in any directory in 'undodir'"
+msgstr "Ðевозможно запиÑать файл отмен в каком-либо каталоге из 'undodir'"
+
+#, c-format
+msgid "Will not overwrite with undo file, cannot read: %s"
+msgstr "Файл отмен не перезапиÑан, невозможно прочитать: %s"
+
+#, c-format
+msgid "Will not overwrite, this is not an undo file: %s"
+msgstr "ПерезапиÑÑŒ не выполнена, Ñто не файл отмен: %s"
+
+msgid "Skipping undo file write, nothing to undo"
+msgstr "Пропущена запиÑÑŒ файла отмен, нечего отменÑÑ‚ÑŒ"
+
+#, c-format
+msgid "Writing undo file: %s"
+msgstr "ЗапиÑÑŒ файла отмен: %s"
+
+#, c-format
+msgid "E829: write error in undo file: %s"
+msgstr "E829: Ошибка при запиÑи файла отмен: %s"
+
+#, c-format
+msgid "Not reading undo file, owner differs: %s"
+msgstr "Файл отмен не прочитан, другой владелец: %s"
+
+#, c-format
+msgid "Reading undo file: %s"
+msgstr "Чтение файла отмен: %s"
+
+#, c-format
+msgid "E822: Cannot open undo file for reading: %s"
+msgstr "E822: Ðевозможно открыть файл отмен Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ: %s"
+
+#, c-format
+msgid "E823: Not an undo file: %s"
+msgstr "E823: Это не файл отмен: %s"
+
+#, c-format
+msgid "E832: Non-encrypted file has encrypted undo file: %s"
+msgstr "E832: Ðе зашифрованный файл имеет зашифрованный файл отмен: %s"
+
+#, c-format
+msgid "E826: Undo file decryption failed: %s"
+msgstr "E826: Ðе удалоÑÑŒ дешифровать файл отмен: %s"
+
+#, c-format
+msgid "E827: Undo file is encrypted: %s"
+msgstr "E827: Файл отмен зашифрован: %s"
+
+#, c-format
+msgid "E824: Incompatible undo file: %s"
+msgstr "E824: ÐеÑовмеÑтимый файл отмен: %s"
+
+msgid "File contents changed, cannot use undo info"
+msgstr "ИзменилоÑÑŒ Ñодержимое файла, невозможно иÑпользовать информацию отмен"
+
+#, c-format
+msgid "Finished reading undo file %s"
+msgstr "Завершено чтение файла отмен %s"
+
+msgid "Already at oldest change"
+msgstr "Уже на Ñамом первом изменении"
+
+msgid "Already at newest change"
+msgstr "Уже на Ñамом поÑледнем изменении"
+
+#, c-format
+msgid "E830: Undo number %ld not found"
+msgstr "E830: Ðе найдена отмена номер %ld"
+
+msgid "E438: u_undo: line numbers wrong"
+msgstr "E438: u_undo: неправильные номера Ñтрок"
+
+msgid "more line"
+msgstr "ÑÑ‚Ñ€. добавлена"
+
+msgid "more lines"
+msgstr "ÑÑ‚Ñ€. добавлено"
+
+msgid "line less"
+msgstr "ÑÑ‚Ñ€. удалена"
+
+msgid "fewer lines"
+msgstr "ÑÑ‚Ñ€. удалено"
+
+msgid "change"
+msgstr "изм."
+
+msgid "changes"
+msgstr "изм."
+
+#, c-format
+msgid "%ld %s; %s #%ld %s"
+msgstr "%ld %s; %s #%ld %s"
+
+msgid "before"
+msgstr "перед"
+
+msgid "after"
+msgstr "поÑле"
+
+msgid "Nothing to undo"
+msgstr "Ðечего отменÑÑ‚ÑŒ"
+
+# Заголовок таблицы :undolist
+msgid "number changes when saved"
+msgstr " номер измен. когда Ñохранено"
+
+#, c-format
+msgid "%ld seconds ago"
+msgstr "%ldÑ Ð½Ð°Ð·Ð°Ð´"
+
+msgid "E790: undojoin is not allowed after undo"
+msgstr "E790: Объединение отмен не допуÑкаетÑÑ Ð¿Ð¾Ñле отмены"
+
+msgid "E439: undo list corrupt"
+msgstr "E439: Повреждён ÑпиÑок отмены"
+
+msgid "E440: undo line missing"
+msgstr "E440: ПотерÑна Ñтрока отмены"
+
+#, c-format
+msgid "E122: Function %s already exists, add ! to replace it"
+msgstr "E122: Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ %s уже ÑущеÑтвует. Добавьте !, чтобы заменить её."
+
+msgid "E717: Dictionary entry already exists"
+msgstr "E717: ЗапиÑÑŒ уже ÑущеÑтвует в Ñловаре"
+
+msgid "E718: Funcref required"
+msgstr "E718: ТребуетÑÑ ÑÑылка на функцию"
+
+#, c-format
+msgid "E130: Unknown function: %s"
+msgstr "E130: ÐеизвеÑÑ‚Ð½Ð°Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ: %s"
+
+#, c-format
+msgid "E125: Illegal argument: %s"
+msgstr "E125: ÐедопуÑтимый параметр: %s"
+
+#, c-format
+msgid "E853: Duplicate argument name: %s"
+msgstr "E853: ПовторÑющееÑÑ Ð¸Ð¼Ñ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ð°: %s"
+
+#, c-format
+msgid "E740: Too many arguments for function %s"
+msgstr "E740: Слишком много параметров Ð´Ð»Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ð¸ %s"
+
+#, c-format
+msgid "E116: Invalid arguments for function %s"
+msgstr "E116: Параметры Ð´Ð»Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ð¸ %s заданы неверно"
+
+msgid "E132: Function call depth is higher than 'maxfuncdepth'"
+msgstr "E132: Глубина вызова функции больше, чем значение 'maxfuncdepth'"
+
+#, c-format
+msgid "calling %s"
+msgstr "вызов %s"
+
+#, c-format
+msgid "%s aborted"
+msgstr "%s прервана"
+
+#, c-format
+msgid "%s returning #%ld"
+msgstr "%s возвращает #%ld"
+
+#, c-format
+msgid "%s returning %s"
+msgstr "%s возвращает %s"
+
+msgid "E699: Too many arguments"
+msgstr "E699: Слишком много параметров"
+
+#, c-format
+msgid "E117: Unknown function: %s"
+msgstr "E117: ÐеизвеÑÑ‚Ð½Ð°Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ: %s"
+
+#, c-format
+msgid "E933: Function was deleted: %s"
+msgstr "E933: Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ ÑƒÐ´Ð°Ð»ÐµÐ½Ð°: %s"
+
+#, c-format
+msgid "E119: Not enough arguments for function: %s"
+msgstr "E119: ÐедоÑтаточно параметров Ð´Ð»Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ð¸ %s"
+
+#, c-format
+msgid "E120: Using <SID> not in a script context: %s"
+msgstr "E120: <SID> иÑпользуетÑÑ Ð²Ð½Ðµ ÑценариÑ: %s"
+
+#, c-format
+msgid "E725: Calling dict function without Dictionary: %s"
+msgstr "E725: Вызов функции dict без ÑловарÑ: %s"
+
+msgid "E129: Function name required"
+msgstr "E129: ТребуетÑÑ Ð¸Ð¼Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ð¸"
+
+#, c-format
+msgid "E128: Function name must start with a capital or \"s:\": %s"
+msgstr "E128: Ð˜Ð¼Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ð¸ должно начинатьÑÑ Ñ Ð·Ð°Ð³Ð»Ð°Ð²Ð½Ð¾Ð¹ буквы или \"s:\": %s"
+
+#, c-format
+msgid "E884: Function name cannot contain a colon: %s"
+msgstr "E884: Ð˜Ð¼Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ð¸ не может Ñодержать двоеточие: %s"
+
+#, c-format
+msgid "E123: Undefined function: %s"
+msgstr "E123: ÐÐµÐ¾Ð¿Ñ€ÐµÐ´ÐµÐ»Ñ‘Ð½Ð½Ð°Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ: %s"
+
+#, c-format
+msgid "E124: Missing '(': %s"
+msgstr "E124: Пропущена '(': %s"
+
+msgid "E862: Cannot use g: here"
+msgstr "E862: ЗдеÑÑŒ невозможно иÑпользовать g:"
+
+#, c-format
+msgid "E932: Closure function should not be at top level: %s"
+msgstr "E932: функциÑ-замыкание не должна быть на верхнем уровне: %s"
+
+msgid "E126: Missing :endfunction"
+msgstr "E126: Пропущена команда :endfunction"
+
+#, c-format
+msgid "W22: Text found after :endfunction: %s"
+msgstr "W22: ТекÑÑ‚ поÑле :endfunction: %s"
+
+#, c-format
+msgid "E707: Function name conflicts with variable: %s"
+msgstr "E707: Ð˜Ð¼Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ð¸ конфликтует Ñ Ð¿ÐµÑ€ÐµÐ¼ÐµÐ½Ð½Ð¾Ð¹: %s"
+
+#, c-format
+msgid "E127: Cannot redefine function %s: It is in use"
+msgstr "E127: Ðевозможно переопределить функцию %s, она иÑпользуетÑÑ"
+
+#, c-format
+msgid "E746: Function name does not match script file name: %s"
+msgstr "E746: Ð˜Ð¼Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ð¸ не ÑоответÑтвует имени файла ÑценариÑ: %s"
+
+#, c-format
+msgid "E131: Cannot delete function %s: It is in use"
+msgstr "E131: Ðевозможно удалить функцию %s, она иÑпользуетÑÑ"
+
+msgid "E133: :return not inside a function"
+msgstr "E133: команда :return вне функции"
+
+#, c-format
+msgid "E107: Missing parentheses: %s"
+msgstr "E107: Пропущены Ñкобки: %s"
+
+msgid ""
+"\n"
+"MS-Windows 64-bit GUI version"
+msgstr ""
+"\n"
+"ВерÑÐ¸Ñ Ñ Ð³Ñ€Ð°Ñ„Ð¸Ñ‡ÐµÑким интерфейÑом Ð´Ð»Ñ MS-Windows 64 бит"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit GUI version"
+msgstr ""
+"\n"
+"ВерÑÐ¸Ñ Ñ Ð³Ñ€Ð°Ñ„Ð¸Ñ‡ÐµÑким интерфейÑом Ð´Ð»Ñ MS-Windows 32 бит"
+
+msgid " with OLE support"
+msgstr " Ñ Ð¿Ð¾Ð´Ð´ÐµÑ€Ð¶ÐºÐ¾Ð¹ OLE"
+
+msgid ""
+"\n"
+"MS-Windows 64-bit console version"
+msgstr ""
+"\n"
+"КонÑÐ¾Ð»ÑŒÐ½Ð°Ñ Ð²ÐµÑ€ÑÐ¸Ñ Ð´Ð»Ñ MS-Windows 64 бит"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit console version"
+msgstr ""
+"\n"
+"КонÑÐ¾Ð»ÑŒÐ½Ð°Ñ Ð²ÐµÑ€ÑÐ¸Ñ Ð´Ð»Ñ MS-Windows 32 бит"
+
+msgid ""
+"\n"
+"macOS version"
+msgstr ""
+"\n"
+"ВерÑÐ¸Ñ Ð´Ð»Ñ macOS"
+
+msgid ""
+"\n"
+"macOS version w/o darwin feat."
+msgstr ""
+"\n"
+"ВерÑÐ¸Ñ Ð´Ð»Ñ macOS без darwin"
+
+msgid ""
+"\n"
+"OpenVMS version"
+msgstr ""
+"\n"
+"ВерÑÐ¸Ñ Ð´Ð»Ñ OpenVMS"
+
+msgid ""
+"\n"
+"Included patches: "
+msgstr ""
+"\n"
+"Заплатки: "
+
+msgid ""
+"\n"
+"Extra patches: "
+msgstr ""
+"\n"
+"Дополнительные заплатки: "
+
+msgid "Modified by "
+msgstr "С изменениÑми, внеÑёнными "
+
+msgid ""
+"\n"
+"Compiled "
+msgstr ""
+"\n"
+"Скомпилировано: "
+
+msgid "by "
+msgstr " "
+
+msgid ""
+"\n"
+"Huge version "
+msgstr ""
+"\n"
+"ÐžÐ³Ñ€Ð¾Ð¼Ð½Ð°Ñ Ð²ÐµÑ€ÑÐ¸Ñ "
+
+msgid ""
+"\n"
+"Big version "
+msgstr ""
+"\n"
+"Ð‘Ð¾Ð»ÑŒÑˆÐ°Ñ Ð²ÐµÑ€ÑÐ¸Ñ "
+
+msgid ""
+"\n"
+"Normal version "
+msgstr ""
+"\n"
+"ÐžÐ±Ñ‹Ñ‡Ð½Ð°Ñ Ð²ÐµÑ€ÑÐ¸Ñ "
+
+msgid ""
+"\n"
+"Small version "
+msgstr ""
+"\n"
+"ÐœÐ°Ð»Ð°Ñ Ð²ÐµÑ€ÑÐ¸Ñ "
+
+msgid ""
+"\n"
+"Tiny version "
+msgstr ""
+"\n"
+"ÐšÑ€Ð¾Ñ…Ð¾Ñ‚Ð½Ð°Ñ Ð²ÐµÑ€ÑÐ¸Ñ "
+
+msgid "without GUI."
+msgstr "без графичеÑкого интерфейÑа."
+
+msgid "with GTK3 GUI."
+msgstr "Ñ Ð³Ñ€Ð°Ñ„Ð¸Ñ‡ÐµÑким интерфейÑом GTK3."
+
+msgid "with GTK2-GNOME GUI."
+msgstr "Ñ Ð³Ñ€Ð°Ñ„Ð¸Ñ‡ÐµÑким интерфейÑом GTK2-GNOME."
+
+msgid "with GTK2 GUI."
+msgstr "Ñ Ð³Ñ€Ð°Ñ„Ð¸Ñ‡ÐµÑким интерфейÑом GTK2."
+
+msgid "with X11-Motif GUI."
+msgstr "Ñ Ð³Ñ€Ð°Ñ„Ð¸Ñ‡ÐµÑким интерфейÑом X11-Motif."
+
+msgid "with X11-neXtaw GUI."
+msgstr "Ñ Ð³Ñ€Ð°Ñ„Ð¸Ñ‡ÐµÑким интерфейÑом X11-neXtaw."
+
+msgid "with X11-Athena GUI."
+msgstr "Ñ Ð³Ñ€Ð°Ñ„Ð¸Ñ‡ÐµÑким интерфейÑом X11-Athena."
+
+msgid "with Photon GUI."
+msgstr "Ñ Ð³Ñ€Ð°Ñ„Ð¸Ñ‡ÐµÑким интерфейÑом Photon."
+
+msgid "with GUI."
+msgstr "Ñ Ð³Ñ€Ð°Ñ„Ð¸Ñ‡ÐµÑким интерфейÑом."
+
+msgid "with Carbon GUI."
+msgstr "Ñ Ð³Ñ€Ð°Ñ„Ð¸Ñ‡ÐµÑким интерфейÑом Carbon."
+
+msgid "with Cocoa GUI."
+msgstr "Ñ Ð³Ñ€Ð°Ñ„Ð¸Ñ‡ÐµÑким интерфейÑом Cocoa."
+
+msgid " Features included (+) or not (-):\n"
+msgstr " Включённые(+) и отключённые(-) оÑобенноÑти:\n"
+
+msgid " system vimrc file: \""
+msgstr " общеÑиÑтемный файл vimrc: \""
+
+msgid " user vimrc file: \""
+msgstr " пользовательÑкий файл vimrc: \""
+
+msgid " 2nd user vimrc file: \""
+msgstr " второй пользовательÑкий файл vimrc: \""
+
+msgid " 3rd user vimrc file: \""
+msgstr " третий пользовательÑкий файл vimrc: \""
+
+msgid " user exrc file: \""
+msgstr " пользовательÑкий файл exrc: \""
+
+msgid " 2nd user exrc file: \""
+msgstr " второй пользовательÑкий файл exrc: \""
+
+msgid " system gvimrc file: \""
+msgstr " общеÑиÑтемный файл gvimrc: \""
+
+msgid " user gvimrc file: \""
+msgstr " пользовательÑкий файл gvimrc: \""
+
+msgid "2nd user gvimrc file: \""
+msgstr " второй пользовательÑкий файл gvimrc: \""
+
+msgid "3rd user gvimrc file: \""
+msgstr " третий пользовательÑкий файл gvimrc: \""
+
+msgid " defaults file: \""
+msgstr " файл умолчаний: \""
+
+msgid " system menu file: \""
+msgstr " общеÑиÑтемный файл меню: \""
+
+msgid " fall-back for $VIM: \""
+msgstr " значение $VIM по умолчанию: \""
+
+msgid " f-b for $VIMRUNTIME: \""
+msgstr " значение $VIMRUNTIME по умолчанию: \""
+
+msgid "Compilation: "
+msgstr "Параметры компилÑции: "
+
+msgid "Compiler: "
+msgstr "КомпилÑтор: "
+
+msgid "Linking: "
+msgstr "Сборка: "
+
+msgid " DEBUG BUILD"
+msgstr " ОТЛÐДОЧÐÐЯ СБОРКÐ"
+
+msgid "VIM - Vi IMproved"
+msgstr "VIM — Vi IMproved (улучшенный Vi)"
+
+msgid "version "
+msgstr "верÑÐ¸Ñ "
+
+msgid "by Bram Moolenaar et al."
+msgstr "Брам Мооленаар и другие"
+
+msgid "Vim is open source and freely distributable"
+msgstr "Vim — Ñвободно раÑпроÑтранÑÐµÐ¼Ð°Ñ Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð¼Ð° Ñ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ñ‹Ð¼ кодом"
+
+msgid "Help poor children in Uganda!"
+msgstr "Бедным детÑм в Уганде нужна ваша помощь!"
+
+msgid "type :help iccf<Enter> for information "
+msgstr "наберите :help iccf<Enter> Ð´Ð»Ñ Ð´Ð¾Ð¿Ð¾Ð»Ð½Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð¾Ð¹ информации"
+
+msgid "type :q<Enter> to exit "
+msgstr "наберите :q<Enter> чтобы выйти из программы "
+
+msgid "type :help<Enter> or <F1> for on-line help"
+msgstr "наберите :help<Enter> или <F1> Ð´Ð»Ñ Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ Ñправки "
+
+msgid "type :help version8<Enter> for version info"
+msgstr "наберите :help version8<Enter> Ð´Ð»Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ð¸ о верÑии "
+
+msgid "Running in Vi compatible mode"
+msgstr "Работа в Vi-ÑовмеÑтимом режиме"
+
+msgid "type :set nocp<Enter> for Vim defaults"
+msgstr "наберите :set nocp<Enter> Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÑ…Ð¾Ð´Ð° в режим Vim "
+
+msgid "type :help cp-default<Enter> for info on this"
+msgstr "наберите :help cp-default<Enter> Ð´Ð»Ñ Ð´Ð¾Ð¿Ð¾Ð»Ð½Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð¾Ð¹ информации"
+
+msgid "menu Help->Orphans for information "
+msgstr "меню Справка->Сироты Ð´Ð»Ñ Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ð¸ "
+
+msgid "Running modeless, typed text is inserted"
+msgstr "Ð‘ÐµÐ·Ñ€ÐµÐ¶Ð¸Ð¼Ð½Ð°Ñ Ñ€Ð°Ð±Ð¾Ñ‚Ð°, вÑтавка введённого текÑта"
+
+msgid "menu Edit->Global Settings->Toggle Insert Mode "
+msgstr "меню Правка->Глобальные наÑтройки->Режим Ð’Ñтавки "
+
+msgid " for two modes "
+msgstr " Ð´Ð»Ñ Ð´Ð²ÑƒÑ… режимов "
+
+msgid "menu Edit->Global Settings->Toggle Vi Compatible"
+msgstr "меню Правка->Глобальные наÑтройки->СовмеÑтимоÑÑ‚ÑŒ Ñ Vi "
+
+msgid " for Vim defaults "
+msgstr " Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÑ…Ð¾Ð´Ð° в режим Vim "
+
+msgid "Sponsor Vim development!"
+msgstr "Помогите в разработке Vim!"
+
+msgid "Become a registered Vim user!"
+msgstr "Станьте зарегиÑтрированным пользователем Vim!"
+
+msgid "type :help sponsor<Enter> for information "
+msgstr "наберите :help sponsor<Enter> Ð´Ð»Ñ Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ð¸ "
+
+msgid "type :help register<Enter> for information "
+msgstr "наберите :help register<Enter> Ð´Ð»Ñ Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ð¸ "
+
+msgid "menu Help->Sponsor/Register for information "
+msgstr "меню Справка->Помощь/РегиÑÑ‚Ñ€Ð°Ñ†Ð¸Ñ Ð´Ð»Ñ Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ð¸ "
+
+msgid "Already only one window"
+msgstr "Ðа Ñкране вÑего одно окно"
+
+msgid "E441: There is no preview window"
+msgstr "E441: Окно предпроÑмотра отÑутÑтвует"
+
+msgid "E442: Can't split topleft and botright at the same time"
+msgstr "E442: Окно не может быть одновременно Ñлева вверху и Ñправа внизу"
+
+msgid "E443: Cannot rotate when another window is split"
+msgstr "E443: Ðевозможно поменÑÑ‚ÑŒ меÑтами, пока другое окно разделено"
+
+msgid "E444: Cannot close last window"
+msgstr "E444: ÐÐµÐ»ÑŒÐ·Ñ Ð·Ð°ÐºÑ€Ñ‹Ñ‚ÑŒ поÑледнее окно"
+
+msgid "E813: Cannot close autocmd window"
+msgstr "E813: ÐÐµÐ»ÑŒÐ·Ñ Ð·Ð°ÐºÑ€Ñ‹Ñ‚ÑŒ окно автокоманд"
+
+msgid "E814: Cannot close window, only autocmd window would remain"
+msgstr "E814: ÐÐµÐ»ÑŒÐ·Ñ Ð·Ð°ÐºÑ€Ñ‹Ñ‚ÑŒ окно, оÑтанетÑÑ Ñ‚Ð¾Ð»ÑŒÐºÐ¾ окно автокоманд"
+
+msgid "E445: Other window contains changes"
+msgstr "E445: Ð’ другом окне еÑÑ‚ÑŒ неÑохранённые изменениÑ"
+
+msgid "E446: No file name under cursor"
+msgstr "E446: Ðет имени файла в позиции курÑора"
+
+#, c-format
+msgid "E447: Can't find file \"%s\" in path"
+msgstr "E447: Файл \"%s\" не найден по извеÑтным путÑм"
+
+#, c-format
+msgid "E799: Invalid ID: %ld (must be greater than or equal to 1)"
+msgstr "E799: Ðеверный ID: %ld (должен быть больше или равен 1)"
+
+#, c-format
+msgid "E801: ID already taken: %ld"
+msgstr "E801: ID уже занÑÑ‚: %ld"
+
+msgid "List or number required"
+msgstr "ТребуетÑÑ ÑпиÑок или чиÑло"
+
+#, c-format
+msgid "E802: Invalid ID: %ld (must be greater than or equal to 1)"
+msgstr "E802: Ðеверный ID: %ld (должен быть больше или равен 1)"
+
+#, c-format
+msgid "E803: ID not found: %ld"
+msgstr "E803: ID не найден: %ld"
+
+#, c-format
+msgid "E370: Could not load library %s"
+msgstr "E370: Ðевозможно загрузить библиотеку %s"
+
+msgid "Sorry, this command is disabled: the Perl library could not be loaded."
+msgstr ""
+"Извините, Ð´Ð°Ð½Ð½Ð°Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð° отключена: невозможно загрузить библиотеку Perl"
+
+msgid "E299: Perl evaluation forbidden in sandbox without the Safe module"
+msgstr ""
+"E299: Ðе допуÑкаетÑÑ Ð²Ñ‹Ñ‡Ð¸Ñление Perl в пеÑочнице без Ð¼Ð¾Ð´ÑƒÐ»Ñ Ð±ÐµÐ·Ð¾Ð¿Ð°ÑноÑти"
+
+msgid "Edit with &multiple Vims"
+msgstr "Редактировать в &разных Vim-ах"
+
+msgid "Edit with single &Vim"
+msgstr "Редактировать в &одном Vim"
+
+msgid "Diff with Vim"
+msgstr "Сравнить Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ Vim"
+
+msgid "Edit with &Vim"
+msgstr "Ре&дактировать Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ Vim"
+
+msgid "Edit with existing Vim - "
+msgstr "Редактировать в запущенном Vim — "
+
+msgid "Edits the selected file(s) with Vim"
+msgstr "Редактировать выделенные файлы Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ Vim"
+
+msgid "Error creating process: Check if gvim is in your path!"
+msgstr "Ошибка ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ð¿Ñ€Ð¾Ñ†ÐµÑÑа: проверьте доÑтупноÑÑ‚ÑŒ gvim в пути!"
+
+msgid "gvimext.dll error"
+msgstr "ошибка gvimext.dll"
+
+msgid "Path length too long!"
+msgstr "Слишком длинный путь!"
+
+msgid "--No lines in buffer--"
+msgstr "-- Ðет Ñтрок в буфере --"
+
+msgid "E470: Command aborted"
+msgstr "E470: Выполнение команды прервано"
+
+msgid "E471: Argument required"
+msgstr "E471: ТребуетÑÑ ÑƒÐºÐ°Ð·Ð°Ñ‚ÑŒ параметр"
+
+msgid "E10: \\ should be followed by /, ? or &"
+msgstr "E10: ПоÑле \\ должен идти Ñимвол /, ? или &"
+
+msgid "E11: Invalid in command-line window; <CR> executes, CTRL-C quits"
+msgstr ""
+"E11: ÐедопуÑтимо в окне командной Ñтроки; <CR> выполнение, CTRL-C выход"
+
+msgid "E12: Command not allowed from exrc/vimrc in current dir or tag search"
+msgstr ""
+"E12: Команда не допуÑкаетÑÑ Ð² exrc/vimrc в текущем каталоге или поиÑке меток"
+
+msgid "E171: Missing :endif"
+msgstr "E171: ОтÑутÑтвует команда :endif"
+
+msgid "E600: Missing :endtry"
+msgstr "E600: ОтÑутÑтвует команда :endtry"
+
+msgid "E170: Missing :endwhile"
+msgstr "E170: ОтÑутÑтвует команда :endwhile"
+
+msgid "E170: Missing :endfor"
+msgstr "E170: ОтÑутÑтвует команда :endfor"
+
+msgid "E588: :endwhile without :while"
+msgstr "E588: Команда :endwhile без парной команды :while"
+
+msgid "E588: :endfor without :for"
+msgstr "E588: :endfor без :for"
+
+msgid "E13: File exists (add ! to override)"
+msgstr "E13: Файл ÑущеÑтвует (добавьте !, чтобы перезапиÑать)"
+
+msgid "E472: Command failed"
+msgstr "E472: Ðе удалоÑÑŒ выполнить команду"
+
+#, c-format
+msgid "E234: Unknown fontset: %s"
+msgstr "E234: ÐеизвеÑтный шрифтовой набор: %s"
+
+#, c-format
+msgid "E235: Unknown font: %s"
+msgstr "E235: ÐеизвеÑтный шрифт: %s"
+
+#, c-format
+msgid "E236: Font \"%s\" is not fixed-width"
+msgstr "E236: Шрифт \"%s\" не ÑвлÑетÑÑ Ð¼Ð¾Ð½Ð¾ÑˆÐ¸Ñ€Ð¸Ð½Ð½Ñ‹Ð¼"
+
+msgid "E473: Internal error"
+msgstr "E473: ВнутреннÑÑ Ð¾ÑˆÐ¸Ð±ÐºÐ°"
+
+#, c-format
+msgid "E685: Internal error: %s"
+msgstr "E685: ВнутреннÑÑ Ð¾ÑˆÐ¸Ð±ÐºÐ°: %s"
+
+msgid "Interrupted"
+msgstr "Прервано"
+
+msgid "E14: Invalid address"
+msgstr "E14: ÐедопуÑтимый адреÑ"
+
+msgid "E474: Invalid argument"
+msgstr "E474: ÐедопуÑтимый параметр"
+
+#, c-format
+msgid "E475: Invalid argument: %s"
+msgstr "E475: ÐедопуÑтимый параметр: %s"
+
+#, c-format
+msgid "E475: Invalid value for argument %s"
+msgstr "E475: ÐедопуÑтимое значение параметра: %s"
+
+#, c-format
+msgid "E475: Invalid value for argument %s: %s"
+msgstr "E475: ÐедопуÑтимое значение параметра %s: %s"
+
+#, c-format
+msgid "E15: Invalid expression: %s"
+msgstr "E15: ÐедопуÑтимое выражение: %s"
+
+msgid "E16: Invalid range"
+msgstr "E16: ÐедопуÑтимый диапазон"
+
+msgid "E476: Invalid command"
+msgstr "E476: ÐедопуÑÑ‚Ð¸Ð¼Ð°Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð°"
+
+#, c-format
+msgid "E17: \"%s\" is a directory"
+msgstr "E17: \"%s\" ÑвлÑетÑÑ ÐºÐ°Ñ‚Ð°Ð»Ð¾Ð³Ð¾Ð¼"
+
+#, c-format
+msgid "E364: Library call failed for \"%s()\""
+msgstr "E364: Ðеудачный вызов функции \"%s()\" из библиотеки"
+
+msgid "E667: Fsync failed"
+msgstr "E667: Ðе удалоÑÑŒ выполнить функцию fsync()"
+
+#, c-format
+msgid "E448: Could not load library function %s"
+msgstr "E448: Ðе удалоÑÑŒ загрузить функцию %s из библиотеки"
+
+msgid "E19: Mark has invalid line number"
+msgstr "E19: Отметка указывает на неправильный номер Ñтроки"
+
+msgid "E20: Mark not set"
+msgstr "E20: Отметка не определена"
+
+msgid "E21: Cannot make changes, 'modifiable' is off"
+msgstr "E21: Ð˜Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð½ÐµÐ²Ð¾Ð·Ð¼Ð¾Ð¶Ð½Ñ‹, так как отключена Ð¾Ð¿Ñ†Ð¸Ñ 'modifiable'"
+
+msgid "E22: Scripts nested too deep"
+msgstr "E22: Слишком глубоко вложенные Ñценарии"
+
+msgid "E23: No alternate file"
+msgstr "E23: СоÑедний файл не ÑущеÑтвует"
+
+msgid "E24: No such abbreviation"
+msgstr "E24: Ðет такого ÑокращениÑ"
+
+msgid "E477: No ! allowed"
+msgstr "E477: ! не допуÑкаетÑÑ"
+
+msgid "E25: GUI cannot be used: Not enabled at compile time"
+msgstr ""
+"E25: ВозможноÑÑ‚ÑŒ иÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð³Ñ€Ð°Ñ„Ð¸Ñ‡ÐµÑкого интерфейÑа выключена при "
+"компилÑции"
+
+msgid "E26: Hebrew cannot be used: Not enabled at compile time\n"
+msgstr "E26: Иврит выключен при компилÑции\n"
+
+msgid "E27: Farsi cannot be used: Not enabled at compile time\n"
+msgstr "E27: ФарÑи выключено при компилÑции\n"
+
+msgid "E800: Arabic cannot be used: Not enabled at compile time\n"
+msgstr "E800: ÐрабÑкий выключен при компилÑции\n"
+
+#, c-format
+msgid "E28: No such highlight group name: %s"
+msgstr "E28: Группа подÑветки ÑинтакÑиÑа %s не ÑущеÑтвует"
+
+msgid "E29: No inserted text yet"
+msgstr "E29: Пока нет вÑтавленного текÑта"
+
+msgid "E30: No previous command line"
+msgstr "E30: Предыдущей командной Ñтроки нет"
+
+msgid "E31: No such mapping"
+msgstr "E31: Такой привÑзки не ÑущеÑтвует"
+
+msgid "E479: No match"
+msgstr "E479: Ðет ÑоответÑтвиÑ"
+
+#, c-format
+msgid "E480: No match: %s"
+msgstr "E480: Ðет ÑоответÑтвиÑ: %s"
+
+msgid "E32: No file name"
+msgstr "E32: Ðет имени файла"
+
+msgid "E33: No previous substitute regular expression"
+msgstr "E33: Ðет предыдущего регулÑрного Ð²Ñ‹Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð´Ð»Ñ Ð·Ð°Ð¼ÐµÐ½Ñ‹"
+
+msgid "E34: No previous command"
+msgstr "E34: Ðет предыдущей команды"
+
+msgid "E35: No previous regular expression"
+msgstr "E35: Ðет предыдущего регулÑрного выражениÑ"
+
+msgid "E481: No range allowed"
+msgstr "E481: ИÑпользование диапазона не допуÑкаетÑÑ"
+
+msgid "E36: Not enough room"
+msgstr "E36: ÐедоÑтаточно меÑта"
+
+#, c-format
+msgid "E247: no registered server named \"%s\""
+msgstr "E247: Сервер \"%s\" не зарегиÑтрирован"
+
+#, c-format
+msgid "E482: Can't create file %s"
+msgstr "E482: Ðевозможно Ñоздать файл %s"
+
+msgid "E483: Can't get temp file name"
+msgstr "E483: Ðевозможно получить Ð¸Ð¼Ñ Ð²Ñ€ÐµÐ¼ÐµÐ½Ð½Ð¾Ð³Ð¾ файла"
+
+#, c-format
+msgid "E484: Can't open file %s"
+msgstr "E484: Ðевозможно открыть файл %s"
+
+#, c-format
+msgid "E485: Can't read file %s"
+msgstr "E485: Ðевозможно прочитать файл %s"
+
+msgid "E38: Null argument"
+msgstr "E38: Ðулевой параметр"
+
+msgid "E39: Number expected"
+msgstr "E39: ТребуетÑÑ Ñ‡Ð¸Ñло"
+
+#, c-format
+msgid "E40: Can't open errorfile %s"
+msgstr "E40: Ðе удалоÑÑŒ открыть файл ошибок %s"
+
+msgid "E233: cannot open display"
+msgstr "E233: Ðевозможно открыть диÑплей"
+
+msgid "E41: Out of memory!"
+msgstr "E41: Ðе хватает памÑти!"
+
+msgid "Pattern not found"
+msgstr "Шаблон не найден"
+
+#, c-format
+msgid "E486: Pattern not found: %s"
+msgstr "E486: Шаблон не найден: %s"
+
+msgid "E487: Argument must be positive"
+msgstr "E487: Параметр должен быть положительным чиÑлом"
+
+msgid "E459: Cannot go back to previous directory"
+msgstr "E459: Возврат в предыдущий каталог невозможен"
+
+msgid "E42: No Errors"
+msgstr "E42: Ðет ошибок"
+
+msgid "E776: No location list"
+msgstr "E776: Ðет ÑпиÑка раÑположений"
+
+msgid "E43: Damaged match string"
+msgstr "E43: Повреждена Ñтрока ÑоответÑтвиÑ"
+
+msgid "E44: Corrupted regexp program"
+msgstr "E44: Программа обработки регулÑрных выражений повреждена"
+
+msgid "E45: 'readonly' option is set (add ! to override)"
+msgstr "E45: Включена Ð¾Ð¿Ñ†Ð¸Ñ 'readonly' (добавьте !, чтобы обойти проверку)"
+
+#, c-format
+msgid "E46: Cannot change read-only variable \"%s\""
+msgstr "E46: Ðевозможно изменить переменную только Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ \"%s\""
+
+#, c-format
+msgid "E794: Cannot set variable in the sandbox: \"%s\""
+msgstr "E794: Ðевозможно изменить переменную в пеÑочнице: \"%s\""
+
+msgid "E713: Cannot use empty key for Dictionary"
+msgstr "E713: Ðевозможно иÑпользовать пуÑтой ключ Ð´Ð»Ñ ÑловарÑ"
+
+msgid "E715: Dictionary required"
+msgstr "E715: ТребуетÑÑ Ñловарь"
+
+#, c-format
+msgid "E684: list index out of range: %ld"
+msgstr "E684: Ð˜Ð½Ð´ÐµÐºÑ ÑпиÑка за пределами диапазона: %ld"
+
+#, c-format
+msgid "E118: Too many arguments for function: %s"
+msgstr "E118: Слишком много параметров Ð´Ð»Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ð¸ %s"
+
+#, c-format
+msgid "E716: Key not present in Dictionary: %s"
+msgstr "E716: Ðет ключа в Ñловаре: %s"
+
+msgid "E714: List required"
+msgstr "E714: ТребуетÑÑ ÑпиÑок"
+
+#, c-format
+msgid "E712: Argument of %s must be a List or Dictionary"
+msgstr "E712: Параметр %s должен быть ÑпиÑком или Ñловарём"
+
+msgid "E47: Error while reading errorfile"
+msgstr "E47: Ошибка при чтении файла ошибок"
+
+msgid "E48: Not allowed in sandbox"
+msgstr "E48: Ðе допуÑкаетÑÑ Ð² пеÑочнице"
+
+msgid "E523: Not allowed here"
+msgstr "E523: ЗдеÑÑŒ не разрешено"
+
+msgid "E359: Screen mode setting not supported"
+msgstr "E359: Данный режим Ñкрана не поддерживаетÑÑ"
+
+msgid "E49: Invalid scroll size"
+msgstr "E49: ÐедопуÑтимый размер прокрутки"
+
+msgid "E91: 'shell' option is empty"
+msgstr "E91: Значением опции 'shell' ÑвлÑетÑÑ Ð¿ÑƒÑÑ‚Ð°Ñ Ñтрока"
+
+msgid "E255: Couldn't read in sign data!"
+msgstr "E255: Ðевозможно прочитать данные о значках!"
+
+msgid "E72: Close error on swap file"
+msgstr "E72: Ошибка Ð·Ð°ÐºÑ€Ñ‹Ñ‚Ð¸Ñ Ñвоп-файла"
+
+msgid "E73: tag stack empty"
+msgstr "E73: Стек меток пуÑтой"
+
+msgid "E74: Command too complex"
+msgstr "E74: Слишком ÑÐ»Ð¾Ð¶Ð½Ð°Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð°"
+
+msgid "E75: Name too long"
+msgstr "E75: Слишком длинное имÑ"
+
+msgid "E76: Too many ["
+msgstr "E76: Слишком много Ñимволов ["
+
+msgid "E77: Too many file names"
+msgstr "E77: Слишком много имён файлов"
+
+msgid "E488: Trailing characters"
+msgstr "E488: Лишние Ñимволы на хвоÑте"
+
+msgid "E78: Unknown mark"
+msgstr "E78: ÐеизвеÑÑ‚Ð½Ð°Ñ Ð¾Ñ‚Ð¼ÐµÑ‚ÐºÐ°"
+
+msgid "E79: Cannot expand wildcards"
+msgstr "E79: Ðевозможно выполнить подÑтановку по маÑке"
+
+msgid "E591: 'winheight' cannot be smaller than 'winminheight'"
+msgstr ""
+"E591: Значение опции 'winheight' не может быть меньше Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ 'winminheight'"
+
+msgid "E592: 'winwidth' cannot be smaller than 'winminwidth'"
+msgstr ""
+"E592: Значение опции 'winwidth' не может быть меньше Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ 'winminwidth'"
+
+msgid "E80: Error while writing"
+msgstr "E80: Ошибка при запиÑи"
+
+msgid "E939: Positive count required"
+msgstr "E939: ТребуетÑÑ Ð¿Ð¾Ð»Ð¾Ð¶Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ñ‹Ð¹ Ñчётчик"
+
+msgid "E81: Using <SID> not in a script context"
+msgstr "E81: ИÑпользование <SID> вне контекÑта ÑценариÑ"
+
+msgid "E449: Invalid expression received"
+msgstr "E449: Получено недопуÑтимое выражение"
+
+msgid "E463: Region is guarded, cannot modify"
+msgstr "E463: Ðевозможно изменить охранÑемую облаÑÑ‚ÑŒ"
+
+msgid "E744: NetBeans does not allow changes in read-only files"
+msgstr "E744: NetBeans не допуÑкает изменений в файлах только Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ"
+
+msgid "E363: pattern uses more memory than 'maxmempattern'"
+msgstr "E363: Шаблон иÑпользует больше памÑти чем 'maxmempattern'"
+
+msgid "E749: empty buffer"
+msgstr "E749: ПуÑтой буфер"
+
+#, c-format
+msgid "E86: Buffer %ld does not exist"
+msgstr "E86: Буфер %ld не ÑущеÑтвует"
+
+msgid "E682: Invalid search pattern or delimiter"
+msgstr "E682: ÐÐµÐ¿Ñ€Ð°Ð²Ð¸Ð»ÑŒÐ½Ð°Ñ Ñтрока поиÑка или разделитель"
+
+msgid "E139: File is loaded in another buffer"
+msgstr "E139: Файл загружен в другом буфере"
+
+#, c-format
+msgid "E764: Option '%s' is not set"
+msgstr "E764: ÐžÐ¿Ñ†Ð¸Ñ '%s' не уÑтановлена"
+
+msgid "E850: Invalid register name"
+msgstr "E850: ÐедопуÑтимое Ð¸Ð¼Ñ Ñ€ÐµÐ³Ð¸Ñтра"
+
+#, c-format
+msgid "E919: Directory not found in '%s': \"%s\""
+msgstr "E919: Каталог не найден в '%s': \"%s\""
+
+msgid "E952: Autocommand caused recursive behavior"
+msgstr "E952: Ðвтокоманда вызвала рекурÑивное поведение"
+
+msgid "search hit TOP, continuing at BOTTOM"
+msgstr "ПоиÑк будет продолжен Ñ ÐšÐžÐЦРдокумента"
+
+msgid "search hit BOTTOM, continuing at TOP"
+msgstr "ПоиÑк будет продолжен Ñ ÐÐЧÐЛРдокумента"
+
+#, c-format
+msgid "Need encryption key for \"%s\""
+msgstr "ТребуетÑÑ ÐºÐ»ÑŽÑ‡ ÑˆÐ¸Ñ„Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð´Ð»Ñ \"%s\""
+
+msgid "empty keys are not allowed"
+msgstr "ПуÑтые ключи не допуÑтимы"
+
+msgid "dictionary is locked"
+msgstr "Словарь заблокирован"
+
+msgid "list is locked"
+msgstr "СпиÑок заблокирован"
+
+#, c-format
+msgid "failed to add key '%s' to dictionary"
+msgstr "Ðевозможно добавить ключ '%s' к Ñловарю"
+
+#, c-format
+msgid "index must be int or slice, not %s"
+msgstr "Ð˜Ð½Ð´ÐµÐºÑ Ð´Ð¾Ð»Ð¶ÐµÐ½ быть целым чиÑлом или выборкой, а не %s"
+
+#, c-format
+msgid "expected str() or unicode() instance, but got %s"
+msgstr "ОжидалÑÑ ÑкземплÑÑ€ str() или unicode(), но получен %s"
+
+#, c-format
+msgid "expected bytes() or str() instance, but got %s"
+msgstr "ОжидалÑÑ ÑкземплÑÑ€ bytes() или str(), но получен %s"
+
+#, c-format
+msgid ""
+"expected int(), long() or something supporting coercing to long(), but got %s"
+msgstr "ОжидалоÑÑŒ int(), long() или что-то приводимое к long(), но получено %s"
+
+#, c-format
+msgid "expected int() or something supporting coercing to int(), but got %s"
+msgstr "ОжидалоÑÑŒ int() или что-то приводимое к int(), но получено %s"
+
+msgid "value is too large to fit into C int type"
+msgstr "Значение Ñлишком велико Ð´Ð»Ñ Ñ†ÐµÐ»Ð¾Ñ‡Ð¸Ñленного типа C"
+
+msgid "value is too small to fit into C int type"
+msgstr "Значение Ñлишком мало Ð´Ð»Ñ Ñ†ÐµÐ»Ð¾Ñ‡Ð¸Ñленного типа C"
+
+msgid "number must be greater than zero"
+msgstr "Ðомер должен быть больше нулÑ"
+
+msgid "number must be greater or equal to zero"
+msgstr "Ðомер должен быть больше или равен нулю"
+
+msgid "can't delete OutputObject attributes"
+msgstr "Ðевозможно удалить атрибуты OutputObject"
+
+#, c-format
+msgid "invalid attribute: %s"
+msgstr "Ðеправильный атрибут: %s"
+
+msgid "E264: Python: Error initialising I/O objects"
+msgstr "E264: Python: Ошибка инициализации объектов I/O"
+
+msgid "failed to change directory"
+msgstr "Ðевозможно Ñменить каталог"
+
+#, c-format
+msgid "expected 3-tuple as imp.find_module() result, but got %s"
+msgstr "ОжидалÑÑ 3-кортеж как результат imp.find_module(), но получен %s"
+
+#, c-format
+msgid "expected 3-tuple as imp.find_module() result, but got tuple of size %d"
+msgstr ""
+"ОжидалÑÑ 3-кортеж как результат imp.find_module(), но получен кортеж Ñ "
+"размером %d"
+
+msgid "internal error: imp.find_module returned tuple with NULL"
+msgstr "ВнутреннÑÑ Ð¾ÑˆÐ¸Ð±ÐºÐ°: imp.find_module возвратил "
+
+msgid "cannot delete vim.Dictionary attributes"
+msgstr "Ðевозможно удалить атрибуты vim.Dictionary"
+
+msgid "cannot modify fixed dictionary"
+msgstr "Ðевозможно изменить фикÑированный Ñловарь"
+
+#, c-format
+msgid "cannot set attribute %s"
+msgstr "Ðевозможно уÑтановить атрибут %s"
+
+msgid "hashtab changed during iteration"
+msgstr "Ð¥Ñш-таблица изменилаÑÑŒ при итерации"
+
+#, c-format
+msgid "expected sequence element of size 2, but got sequence of size %d"
+msgstr ""
+"ОжидалÑÑ Ñлемент-поÑледовательноÑÑ‚ÑŒ размера 2, а размер полученной "
+"поÑледовательноÑти %d"
+
+msgid "list constructor does not accept keyword arguments"
+msgstr "КонÑтруктор ÑпиÑка не допуÑкает ключевые Ñлова как аргументы"
+
+msgid "list index out of range"
+msgstr "Ð˜Ð½Ð´ÐµÐºÑ ÑпиÑка за пределами диапазона"
+
+#, c-format
+msgid "internal error: failed to get vim list item %d"
+msgstr "ВнутреннÑÑ Ð¾ÑˆÐ¸Ð±ÐºÐ°: не удалоÑÑŒ получить Ñлемент VIM-ÑпиÑка %d"
+
+msgid "slice step cannot be zero"
+msgstr "Шаг выборки не может быть нулевым"
+
+#, c-format
+msgid "attempt to assign sequence of size greater than %d to extended slice"
+msgstr ""
+"Попытка приÑвоить поÑледовательноÑÑ‚ÑŒ размером больше чем %d к раÑширенной "
+"выборке"
+
+#, c-format
+msgid "internal error: no vim list item %d"
+msgstr "ВнутреннÑÑ Ð¾ÑˆÐ¸Ð±ÐºÐ°: нет Ñлемента VIM-ÑпиÑка %d"
+
+msgid "internal error: not enough list items"
+msgstr "ВнутреннÑÑ Ð¾ÑˆÐ¸Ð±ÐºÐ°: недоÑтаточно Ñлемнтов ÑпиÑка"
+
+msgid "internal error: failed to add item to list"
+msgstr "ВнутреннÑÑ Ð¾ÑˆÐ¸Ð±ÐºÐ°: не удалоÑÑŒ добавить Ñлемент в ÑпиÑок"
+
+#, c-format
+msgid "attempt to assign sequence of size %d to extended slice of size %d"
+msgstr ""
+"Попытка приÑвоить поÑледовательноÑÑ‚ÑŒ размером %d к раÑширенной выборке "
+"размером %d"
+
+msgid "failed to add item to list"
+msgstr "Ðевозможно добавить Ñлемент в ÑпиÑок"
+
+msgid "cannot delete vim.List attributes"
+msgstr "Ðевозможно удалить атрибуты vim.List"
+
+msgid "cannot modify fixed list"
+msgstr "Ðевозможно изменить фикÑированный ÑпиÑок"
+
+#, c-format
+msgid "unnamed function %s does not exist"
+msgstr "Ðе ÑущеÑтвует безымÑнной функции %s"
+
+#, c-format
+msgid "function %s does not exist"
+msgstr "Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ %s не ÑущеÑтвует"
+
+#, c-format
+msgid "failed to run function %s"
+msgstr "Ðевозможно выполнить функцию %s"
+
+msgid "unable to get option value"
+msgstr "Ðевозможно получить значение опции"
+
+msgid "internal error: unknown option type"
+msgstr "ВнутреннÑÑ Ð¾ÑˆÐ¸Ð±ÐºÐ°: неизвеÑтный тип опции"
+
+msgid "problem while switching windows"
+msgstr "Проблема при переключении окон"
+
+#, c-format
+msgid "unable to unset global option %s"
+msgstr "Ðевозможно ÑброÑить глобальную опцию %s"
+
+#, c-format
+msgid "unable to unset option %s which does not have global value"
+msgstr "Ðевозможно ÑброÑить опцию %s без глобального значениÑ"
+
+msgid "attempt to refer to deleted tab page"
+msgstr "Попытка ÑоÑлатьÑÑ Ð½Ð° удалённую вкладку"
+
+msgid "no such tab page"
+msgstr "Ðет такой вкладки"
+
+msgid "attempt to refer to deleted window"
+msgstr "Попытка ÑоÑлатьÑÑ Ð½Ð° закрытое окно"
+
+msgid "readonly attribute: buffer"
+msgstr "Ðтрибут только Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ: буфер"
+
+msgid "cursor position outside buffer"
+msgstr "ÐŸÐ¾Ð·Ð¸Ñ†Ð¸Ñ ÐºÑƒÑ€Ñора находитÑÑ Ð²Ð½Ðµ буфера"
+
+msgid "no such window"
+msgstr "Ðет такого окна"
+
+msgid "attempt to refer to deleted buffer"
+msgstr "Попытка ÑоÑлатьÑÑ Ð½Ð° уничтоженный буфер"
+
+msgid "failed to rename buffer"
+msgstr "Ðевозможно переименовать буфер"
+
+msgid "mark name must be a single character"
+msgstr "Ðазвание отметки должно быть одним Ñимволом"
+
+#, c-format
+msgid "expected vim.Buffer object, but got %s"
+msgstr "ОжидалÑÑ Ð¾Ð±ÑŠÐµÐºÑ‚ vim.Buffer, но получен %s"
+
+#, c-format
+msgid "failed to switch to buffer %d"
+msgstr "Ðевозможно переключитьÑÑ Ð½Ð° буфер %d"
+
+#, c-format
+msgid "expected vim.Window object, but got %s"
+msgstr "ОжидалÑÑ Ð¾Ð±ÑŠÐµÐºÑ‚ vim.Window, но получен %s"
+
+msgid "failed to find window in the current tab page"
+msgstr "Ðевозможно найти окно в текущей вкладке"
+
+msgid "did not switch to the specified window"
+msgstr "Ðевозможно переключитьÑÑ Ð½Ð° указанное окно"
+
+#, c-format
+msgid "expected vim.TabPage object, but got %s"
+msgstr "ОжидалÑÑ Ð¾Ð±ÑŠÐµÐºÑ‚ vim.TabPage, но получен %s"
+
+msgid "did not switch to the specified tab page"
+msgstr "Ðевозможно переключитьÑÑ Ð½Ð° указанную вкладку"
+
+msgid "failed to run the code"
+msgstr "Ðевозможно выполнить код"
+
+msgid "E858: Eval did not return a valid python object"
+msgstr "E858: Eval не возвратил допуÑтимого объекта Python"
+
+msgid "E859: Failed to convert returned python object to vim value"
+msgstr ""
+"E859: Ðе удалоÑÑŒ преобразовать возвращённый объект Python в значение VIM"
+
+#, c-format
+msgid "unable to convert %s to vim dictionary"
+msgstr "Ðевозможно преобразовать %s в Ñловарь VIM"
+
+#, c-format
+msgid "unable to convert %s to vim list"
+msgstr "Ðевозможно преобразовать %s в ÑпиÑок VIM"
+
+#, c-format
+msgid "unable to convert %s to vim structure"
+msgstr "Ðевозможно преобразовать %s в Ñтруктуру VIM"
+
+msgid "internal error: NULL reference passed"
+msgstr "ВнутреннÑÑ Ð¾ÑˆÐ¸Ð±ÐºÐ°: передана ÑÑылка на NULL"
+
+msgid "internal error: invalid value type"
+msgstr "ВнутреннÑÑ Ð¾ÑˆÐ¸Ð±ÐºÐ°: неправильный тип значениÑ"
+
+msgid ""
+"Failed to set path hook: sys.path_hooks is not a list\n"
+"You should now do the following:\n"
+"- append vim.path_hook to sys.path_hooks\n"
+"- append vim.VIM_SPECIAL_PATH to sys.path\n"
+msgstr ""
+"Ошибка при уÑтановке перехватчика пути: sys.path_hooks не ÑвлÑетÑÑ ÑпиÑком\n"
+"Следует Ñделать Ñледующее:\n"
+"— Добавить vim.path_hook в sys.path_hooks\n"
+"— Добавить vim.VIM_SPECIAL_PATH в sys.path\n"
+
+msgid ""
+"Failed to set path: sys.path is not a list\n"
+"You should now append vim.VIM_SPECIAL_PATH to sys.path"
+msgstr ""
+"Ошибка при уÑтановке пути: sys.path не ÑвлÑетÑÑ ÑпиÑком\n"
+"Следует добавить vim.VIM_SPECIAL_PATH в sys.path"
+
+
diff --git a/src/po/sjiscorr.c b/src/po/sjiscorr.c
new file mode 100644
index 0000000..7aa0533
--- /dev/null
+++ b/src/po/sjiscorr.c
@@ -0,0 +1,48 @@
+/*
+ * Simplistic program to correct SJIS inside strings. When a trail byte is a
+ * backslash it needs to be doubled.
+ * Public domain.
+ */
+#include <stdio.h>
+#include <string.h>
+
+ int
+main(int argc, char **argv)
+{
+ char buffer[BUFSIZ];
+ char *p;
+
+ while (fgets(buffer, BUFSIZ, stdin) != NULL)
+ {
+ for (p = buffer; *p != 0; p++)
+ {
+ if (strncmp(p, "charset=utf-8", 13) == 0
+ || strncmp(p, "charset=UTF-8", 13) == 0)
+ {
+ fputs("charset=cp932", stdout);
+ p += 12;
+ }
+ else if (strncmp(p, "# Original translations", 23) == 0)
+ {
+ fputs("# generated from ja.po, DO NOT EDIT", stdout);
+ while (p[1] != '\n')
+ ++p;
+ }
+ else if (*(unsigned char *)p == 0x81 && p[1] == '_')
+ {
+ putchar('\\');
+ ++p;
+ }
+ else
+ {
+ if (*p & 0x80)
+ {
+ putchar(*p++);
+ if (*p == '\\')
+ putchar(*p);
+ }
+ putchar(*p);
+ }
+ }
+ }
+}
diff --git a/src/po/sk.cp1250.po b/src/po/sk.cp1250.po
new file mode 100644
index 0000000..5bbff55
--- /dev/null
+++ b/src/po/sk.cp1250.po
@@ -0,0 +1,5822 @@
+# Slovak translation of vim
+# Lubomir Host 'rajo' <rajo AT platon.sk>
+# 2005 - Platon Group, http://platon.sk/
+# $Revision: 1.4 $
+# $LastChangedDate: 2005-10-08 12:00:24 +0200 (Sat, 08 Oct 2005) $
+msgid ""
+msgstr ""
+"Project-Id-Version: vim\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2005-09-30 15:58+0200\n"
+"PO-Revision-Date: 2005-09-30 15:58+0200\n"
+"Last-Translator: Lubomir Host <rajo@platon.sk>\n"
+"Language-Team: Slovak <sk-i18n@lists.linux.sk>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=cp1250\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Vim 7.x\n"
+
+msgid "E82: Cannot allocate any buffer, exiting..."
+msgstr "E82: Nedá sa alokova buffer, konèím..."
+
+msgid "E83: Cannot allocate buffer, using other one..."
+msgstr "E83: Nedá sa alokova buffer, použijem iný..."
+
+msgid "E515: No buffers were unloaded"
+msgstr "E515: Žiadny buffer nebol uvo¾nený"
+
+msgid "E516: No buffers were deleted"
+msgstr "E516: Žiadny buffer nebol vymazaný"
+
+msgid "E517: No buffers were wiped out"
+msgstr "E517: Žiadny buffer nebol vymazaný"
+
+msgid "1 buffer unloaded"
+msgstr "1 buffer uvo¾nený"
+
+#, c-format
+msgid "%d buffers unloaded"
+msgstr "%d bufferov uvo¾nených"
+
+msgid "1 buffer deleted"
+msgstr "1 buffer vymazaný"
+
+#, c-format
+msgid "%d buffers deleted"
+msgstr "%d bufferov vymazaných"
+
+msgid "1 buffer wiped out"
+msgstr "1 buffer odstránený"
+
+#, c-format
+msgid "%d buffers wiped out"
+msgstr "%d bufferov odstránených"
+
+msgid "E84: No modified buffer found"
+msgstr "E84: Nebol nájdený žiadny zmenený buffer"
+
+#. back where we started, didn't find anything.
+msgid "E85: There is no listed buffer"
+msgstr "E85: Nenašiel som žiadny buffer"
+
+msgid "E86: Buffer %ld does not exist"
+msgstr "E86: Buffer %ld neexistuje"
+
+msgid "E87: Cannot go beyond last buffer"
+msgstr "E87: Za posledný buffer sa nedá preskoèi"
+
+msgid "E88: Cannot go before first buffer"
+msgstr "E88: Pred prvý buffer sa nedá preskoèi"
+
+msgid "E89: No write since last change for buffer %ld (add ! to override)"
+msgstr "E89: Zmeny v bufferi %ld neboli uložené (! pre vynútenie)"
+
+msgid "E90: Cannot unload last buffer"
+msgstr "E90: Posledný buffer sa nedá odstráni"
+
+msgid "W14: Warning: List of file names overflow"
+msgstr "W14: Varovanie: preteèenie zoznamu s názvami súborov"
+
+#, c-format
+msgid "E92: Buffer %ld not found"
+msgstr "E92: buffer %ld nenájdený"
+
+#, c-format
+msgid "E93: More than one match for %s"
+msgstr "E93: Vzoru %s vyhovuje viac bufferov"
+
+#, c-format
+msgid "E94: No matching buffer for %s"
+msgstr "E94: Vzoru %s nevyhovuje žiadny buffer"
+
+#, c-format
+msgid "line %ld"
+msgstr "riadok %ld"
+
+msgid "E95: Buffer with this name already exists"
+msgstr "E95: Buffer takéhoto mena už existuje"
+
+msgid " [Modified]"
+msgstr " [Zmenený]"
+
+msgid "[Not edited]"
+msgstr "[Neupravovaný]"
+
+msgid "[New file]"
+msgstr "[Nový súbor]"
+
+msgid "[Read errors]"
+msgstr "[Chyby pri èítaní]"
+
+msgid "[readonly]"
+msgstr "[iba pre èítanie]"
+
+#, c-format
+msgid "1 line --%d%%--"
+msgstr "1 riadok --%d%%--"
+
+#, c-format
+msgid "%ld lines --%d%%--"
+msgstr "%ld riadkov --%d%%--"
+
+#, c-format
+msgid "line %ld of %ld --%d%%-- col "
+msgstr "riadok %ld z %ld --%d%%-- ståpec"
+
+msgid "[No Name]"
+msgstr "[Bez mena]"
+
+#. must be a help buffer
+msgid "help"
+msgstr "pomocník"
+
+msgid "[help]"
+msgstr "[pomocník]"
+
+msgid "[Preview]"
+msgstr "[Náh¾ad]"
+
+msgid "All"
+msgstr "Všetko"
+
+msgid "Bot"
+msgstr "Koniec"
+
+msgid "Top"
+msgstr "Zaèiatok"
+
+#, c-format
+msgid ""
+"\n"
+"# Buffer list:\n"
+msgstr ""
+"\n"
+"# Zoznam bufferov:\n"
+
+msgid "[Error List]"
+msgstr "[Zoznam chýb]"
+
+msgid ""
+"\n"
+"--- Signs ---"
+msgstr ""
+"\n"
+"--- Znaky ---"
+
+#, c-format
+msgid "Signs for %s:"
+msgstr "Znaky pre %s:"
+
+#, c-format
+msgid " line=%ld id=%d name=%s"
+msgstr " riadok=%ld id=%d meno=%s"
+
+#, c-format
+msgid "E96: Can not diff more than %ld buffers"
+msgstr "E96: Nemôžem porovna viac ako %ld bufferov"
+
+msgid "E97: Cannot create diffs"
+msgstr "E97: Nedajú sa vytvori porovnania"
+
+msgid "Patch file"
+msgstr "Záplatový súbor"
+
+msgid "E98: Cannot read diff output"
+msgstr "E98: Nedá sa èíta výstup porovnania"
+
+msgid "E99: Current buffer is not in diff mode"
+msgstr "E99: Aktuálny buffer nie je v porovnávacom móde"
+
+msgid "E100: No other buffer in diff mode"
+msgstr "E100: V porovnávacom móde sa nenachádza iný buffer"
+
+msgid "E101: More than two buffers in diff mode, don't know which one to use"
+msgstr "E101: Viac ako dva buffery v porovnávacom móde; neviem, ktorý použi"
+
+#, c-format
+msgid "E102: Can't find buffer \"%s\""
+msgstr "E102: Nedá sa nájs buffer \"%s\""
+
+#, c-format
+msgid "E103: Buffer \"%s\" is not in diff mode"
+msgstr "E103: Buffer \"%s\" nie je v porovnávacom móde"
+
+# TODO: digraph
+msgid "E104: Escape not allowed in digraph"
+msgstr "E104: digraph nesmie obsahova znak Escape"
+
+msgid "E544: Keymap file not found"
+msgstr "E544: Mapa kláves nenájdená"
+
+msgid "E105: Using :loadkeymap not in a sourced file"
+msgstr "E105: Použitý príkaz :loadkeymap v súbore, ktorý nie je interpretovaný"
+
+msgid " Keyword completion (^N^P)"
+msgstr " Doplòovanie k¾úèových slov (^N^P)"
+
+#. ctrl_x_mode == 0, ^P/^N compl.
+msgid " ^X mode (^]^D^E^F^I^K^L^N^O^P^S^U^V^Y)"
+msgstr " ^X režim (^]^D^E^F^I^K^L^N^O^P^S^U^V^Y)"
+
+msgid " Whole line completion (^L^N^P)"
+msgstr " Doplòovanie celých riadkov (^L^N^P)"
+
+msgid " File name completion (^F^N^P)"
+msgstr " Doplòovanie názvov súborov (^F^N^P)"
+
+msgid " Tag completion (^]^N^P)"
+msgstr " Doplòovanie tagov (^]^N^P)"
+
+msgid " Path pattern completion (^N^P)"
+msgstr " Doplòovanie vzoru ciest (^N^P)"
+
+msgid " Definition completion (^D^N^P)"
+msgstr " Doplòovanie definícií (^D^N^P)"
+
+msgid " Dictionary completion (^K^N^P)"
+msgstr " Doplòovanie pod¾a slovníka (^K^N^P)"
+
+msgid " Thesaurus completion (^T^N^P)"
+msgstr " Doplòovanie pod¾a lexikonu (^T^N^P)"
+
+msgid " Command-line completion (^V^N^P)"
+msgstr " Doplòovanie príkazového riadka (^V^N^P)"
+
+msgid " User defined completion (^U^N^P)"
+msgstr " Doplòovanie celých riadkov (^U^N^P)"
+
+msgid " Omni completion (^O^N^P)"
+msgstr " Doplòovanie tagov (^O^N^P)"
+
+msgid " Spelling suggestion (^S^N^P)"
+msgstr " Doplòovanie celých riadkov (^S^N^P)"
+
+msgid " Keyword Local completion (^N^P)"
+msgstr " Miestne doplòovanie k¾úèových slov (^N^P)"
+
+msgid "Hit end of paragraph"
+msgstr "Koniec odstavca"
+
+msgid "'dictionary' option is empty"
+msgstr "vo¾ba 'dictionary' (slovník) je prázdna"
+
+msgid "'thesaurus' option is empty"
+msgstr "vo¾ba 'thesaurus' (lexikon) je prázdna"
+
+#, c-format
+msgid "Scanning dictionary: %s"
+msgstr "preh¾adávam slovník %s"
+
+msgid " (insert) Scroll (^E/^Y)"
+msgstr " (insert) Rolovanie (^E/^Y)"
+
+msgid " (replace) Scroll (^E/^Y)"
+msgstr " (replace) Rolovanie (^E/^Y)"
+
+#, c-format
+msgid "Scanning: %s"
+msgstr "Preh¾adávam: %s"
+
+#, c-format
+msgid "Scanning tags."
+msgstr "Preh¾adávam tagy."
+
+msgid " Adding"
+msgstr " Pridávam"
+
+#. showmode might reset the internal line pointers, so it must
+#. * be called before line = ml_get(), or when this address is no
+#. * longer needed. -- Acevedo.
+#.
+msgid "-- Searching..."
+msgstr "-- H¾adám..."
+
+msgid "Back at original"
+msgstr "Východzia podoba"
+
+msgid "Word from other line"
+msgstr "Slovo z iného riadku"
+
+msgid "The only match"
+msgstr "Jediná zhoda"
+
+#, c-format
+msgid "match %d of %d"
+msgstr "zhoda %d z %d"
+
+#, c-format
+msgid "match %d"
+msgstr "zhoda %d"
+
+msgid "E18: Unexpected characters in :let"
+msgstr "E18: Neoèekávané znaky v :let"
+
+msgid "E684: list index out of range: %ld"
+msgstr "E684: index v zozname je mimo rozsah: %ld"
+
+#, c-format
+msgid "E121: Undefined variable: %s"
+msgstr "E121: Nedefinovaná premenná: %s"
+
+msgid "E111: Missing ']'"
+msgstr "E111: Chýba ']'"
+
+msgid "E686: Argument of %s must be a List"
+msgstr "E686: Argument %s musí by Zoznam (List)"
+
+#, c-format
+msgid "E712: Argument of %s must be a List or Dictionary"
+msgstr "E712: Argument %s musí by Zoznam (List) alebo Slovník (Dictionary)"
+
+msgid "E713: Cannot use empty key for Dictionary"
+msgstr "E713: Nemožno použi prázdny k¾úè pre Slovník (Dictionary)"
+
+msgid "E714: List required"
+msgstr "E714: vyžaduje sa Zoznam (List)"
+
+msgid "E715: Dictionary required"
+msgstr "E715: Vyžaduje sa Slovník (Dictionary)"
+
+#, c-format
+msgid "E118: Too many arguments for function: %s"
+msgstr "E118: Príliš mnoho argumentov pre funkciu %s"
+
+#, c-format
+msgid "E716: Key not present in Dictionary: %s"
+msgstr "E716: k¾úè sa v Slovníku (Dictionary) nenachádza: %s"
+
+msgid "E122: Function %s already exists, add ! to replace it"
+msgstr "E122: Funkcia %s už existuje. Použite ! pre jej nahradenie."
+
+msgid "E717: Dictionary entry already exists"
+msgstr "E717: Záznam v Slovníku (Dictionary) už existuje"
+
+msgid "E718: Funcref required"
+msgstr "E718: Je vyžadovaný odkaz na Funkciu (Funcref)"
+
+msgid "E719: Cannot use [:] with a Dictionary"
+msgstr "E719: Nemožno použit [:] so Slovníkom (Dictionary)"
+
+#, c-format
+msgid "E734: Wrong variable type for %s="
+msgstr "E734: Zlý typ premennej pre %s="
+
+msgid "E130: Unknown function: %s"
+msgstr "E130: Neznáma funkcia: %s"
+
+msgid "E461: Illegal variable name: %s"
+msgstr "E461: Neprípustné meno premennej: %s"
+
+msgid "E687: Less targets than List items"
+msgstr "E687: Menej cie¾ov ako položiek Po¾a (List items)"
+
+msgid "E688: More targets than List items"
+msgstr "E688: Viac cie¾ov ako položiek Po¾a (List items)"
+
+msgid "Double ; in list of variables"
+msgstr "Dvojitá ; v zozname premenných"
+
+msgid "E738: Can't list variables for %s"
+msgstr "E738: Nemožno vypísa premenné pre %s"
+
+msgid "E689: Can only index a List or Dictionary"
+msgstr "E689: Indexova možno iba Zoznam (List) alebo Slovník (Dictionary)"
+
+msgid "E708: [:] must come last"
+msgstr "E708: [:] musí prís ako posledná"
+
+msgid "E709: [:] requires a List value"
+msgstr "E709: [:] vyžaduje hodnotu Po¾a (List value)"
+
+msgid "E710: List value has more items than target"
+msgstr "E710: Hodnota Po¾a (List value) má viac položiek ako cie¾"
+
+msgid "E711: List value has not enough items"
+msgstr "E711: Hodnota Po¾a (List value) nemá dostatok položiek"
+
+msgid "E690: Missing \"in\" after :for"
+msgstr "E690: Chýba \"in\" po :for"
+
+#, c-format
+msgid "E107: Missing parentheses: %s"
+msgstr "E107: Chýbajú zátvorky: %s"
+
+#, c-format
+msgid "E108: No such variable: \"%s\""
+msgstr "E108: Premenná \"%s\" neexistuje"
+
+msgid "E743: variable nested too deep for (un)lock"
+msgstr "E743: premenná je príliš vnorená na (od)blokovanie"
+
+msgid "E109: Missing ':' after '?'"
+msgstr "E109: Po '?' chýba ':'"
+
+msgid "E691: Can only compare List with List"
+msgstr "E691: Porovnáva možno iba Zoznam so Zoznamom (List with List)"
+
+msgid "E692: Invalid operation for List"
+msgstr "E692: Neplatná operácia pre Zoznamy (List)"
+
+msgid "E735: Can only compare Dictionary with Dictionary"
+msgstr "E735: Porovnáva možno iba Slovník so Slovníkom (Dictionary with Dictionary)"
+
+msgid "E736: Invalid operation for Dictionary"
+msgstr "E736: Neplatná operácia pre Slovník"
+
+msgid "E693: Can only compare Funcref with Funcref"
+msgstr "E693: Porovnáva možno iba odkaz na Funkciu s odkazom na Funkciu (Funcref with Funcref)"
+
+msgid "E694: Invalid operation for Funcrefs"
+msgstr "E694: Neplatná operácia pre odkazy na Funkcie (Funcrefs)"
+
+msgid "E110: Missing ')'"
+msgstr "E110: Chýba ')'"
+
+msgid "E695: Cannot index a Funcref"
+msgstr "E695: Nemožno indexova odkaz na Funkciu (Funcref)"
+
+#, c-format
+msgid "E112: Option name missing: %s"
+msgstr "E112: Chýba meno vo¾by: %s"
+
+#, c-format
+msgid "E113: Unknown option: %s"
+msgstr "E113: Neznáma vo¾ba: %s"
+
+#, c-format
+msgid "E114: Missing quote: %s"
+msgstr "E114: Chýbajú úvodzovky: %s"
+
+#, c-format
+msgid "E115: Missing quote: %s"
+msgstr "E115: Chýbajú úvodzovky: %s"
+
+msgid "E696: Missing comma in List: %s"
+msgstr "E696: Chýba èiarka v Zozname: %s"
+
+msgid "E697: Missing end of List ']': %s"
+msgstr "E697: Chýba koniec Zoznamu (List) ']': %s"
+
+msgid "E720: Missing colon in Dictionary: %s"
+msgstr "E720: Chýba dvojbodka v Slovníku (Dictionary): %s"
+
+#, c-format
+msgid "E721: Duplicate key in Dictionary: \"%s\""
+msgstr "E721: Duplikovaný k¾úè v Slovníku (Dictionary): \"%s\""
+
+msgid "E722: Missing comma in Dictionary: %s"
+msgstr "E722: Chýba èiarka v Slovníku (Dictionary): %s"
+
+msgid "E723: Missing end of Dictionary '}': %s"
+msgstr "E723: Chýba koniec Slovníka (Dictionary) '}': %s"
+
+msgid "E724: variable nested too deep for displaying"
+msgstr "E724: premenná je vnorená príliš hlboko pre zobrazenie"
+
+msgid "E699: Too many arguments"
+msgstr "E699: Príliš mnoho argumentov"
+
+#.
+#. * Yes this is ugly, I don't particularly like it either. But doing it
+#. * this way has the compelling advantage that translations need not to
+#. * be touched at all. See below what 'ok' and 'ync' are used for.
+#.
+msgid "&Ok"
+msgstr "&Ok"
+
+msgid "E737: Key already exists: %s"
+msgstr "E737: K¾úè už existuje: %s"
+
+#, c-format
+msgid "+-%s%3ld lines: "
+msgstr "+-%s%3ld riadky: "
+
+msgid "E700: Unknown function: %s"
+msgstr "E700: Neznáma funkcia: %s"
+
+msgid ""
+"&OK\n"
+"&Cancel"
+msgstr ""
+"&OK\n"
+"&Zruši"
+
+msgid "called inputrestore() more often than inputsave()"
+msgstr "funkcia inputrestore() volaná èastejšie ako inputsave()"
+
+msgid "E745: Range not allowed"
+msgstr "E745: Rozsah nie je povolený"
+
+msgid "E701: Invalid type for len()"
+msgstr "E701: Neplatný typ pre len()"
+
+msgid "E726: Stride is zero"
+msgstr "E726: Krok je nulový"
+
+msgid "E727: Start past end"
+msgstr "E727: Zaèiatok presahuje koniec"
+
+msgid "<empty>"
+msgstr "<prázdny>"
+
+msgid "E240: No connection to Vim server"
+msgstr "E240: Neexistuje pripojenie k Vim serveru"
+
+#, c-format
+msgid "E241: Unable to send to %s"
+msgstr "E241: Nemôžem posla na %s"
+
+msgid "E277: Unable to read a server reply"
+msgstr "E277: Nemôžem èíta odpoveï servra"
+
+msgid "E655: Too many symbolic links (cycle?)"
+msgstr "E655: Príliš mnoho symbolických odkazov (sluèka?)"
+
+msgid "E258: Unable to send to client"
+msgstr "E258: Nemôžem posla klientovi"
+
+msgid "E702: Sort compare function failed"
+msgstr "E702: Funkcia na utriedenie/porovnanie zlyhala"
+
+msgid "(Invalid)"
+msgstr "(Chybný)"
+
+msgid "E677: Error writing temp file"
+msgstr "E677: Chyba pri zápise doèasného súboru"
+
+msgid "E703: Using a Funcref as a Number"
+msgstr "E703: Použitý odkaz na Funkciu (Funcref) ako èíslo"
+
+msgid "E745: Using a List as a Number"
+msgstr "E745: Zoznam (List) použitý ako èíslo"
+
+msgid "E728: Using a Dictionary as a Number"
+msgstr "E728: Slovník (Dictionary) použitý ako èíslo"
+
+msgid "E729: using Funcref as a String"
+msgstr "E729: Odkaz na Funkciu (Funcref) použitý ako Reazec (String)"
+
+msgid "E730: using List as a String"
+msgstr "E730: Zoznam (List) použitý ako Reazec (String)"
+
+msgid "E731: using Dictionary as a String"
+msgstr "E731: Slovník (Dictionary) použitý ako Reazec (String)"
+
+msgid "E704: Funcref variable name must start with a capital: %s"
+msgstr "E704: Premenná typu odkaz na Funkciu (Funcref) musí zaèína s ve¾kým písmenom: %s"
+
+#, c-format
+msgid "E705: Variable name conflicts with existing function: %s"
+msgstr "E705: Meno premennej je v konflikte s existujúcou funkciou: %s"
+
+msgid "E706: Variable type mismatch for: %s"
+msgstr "E706: Typ premennej sa nezhoduje: %s"
+
+#, c-format
+msgid "E741: Value is locked: %s"
+msgstr "E741: Hodnota je uzamknutá: %s"
+
+msgid "Unknown"
+msgstr "Neznámy"
+
+msgid "E742: Cannot change value of %s"
+msgstr "E742: Nemožno zmeni hodnotu %s"
+
+msgid "E698: variable nested too deep for making a copy"
+msgstr "E698: premenná je vnorená príliš hlboko pre skopírovanie"
+
+#, c-format
+msgid "E124: Missing '(': %s"
+msgstr "E124: Chýba '(': %s"
+
+#, c-format
+msgid "E125: Illegal argument: %s"
+msgstr "E125: Neprípustný argument: %s"
+
+msgid "E126: Missing :endfunction"
+msgstr "E126: Chýba :endfunction"
+
+msgid "E746: Function name does not match script file name: %s"
+msgstr "E746: Meno funkcie sa nezhoduje s menom interpretovaného súboru: %s"
+
+msgid "E129: Function name required"
+msgstr "E129: Je vyžadované meno funkcie"
+
+msgid "E128: Function name must start with a capital or contain a colon: %s"
+msgstr "E128: Názov funkcie musí zaèína ve¾kým písmenom alebo obsahova dvojbodku: %s"
+
+#, c-format
+msgid "E131: Cannot delete function %s: It is in use"
+msgstr "E131: Nedá sa vymaza funkcia %s: je používaná"
+
+msgid "E132: Function call depth is higher than 'maxfuncdepth'"
+msgstr "E132: Zanorenie funkcií je hlbšie než 'maxfuncdepth'"
+
+#, c-format
+msgid "calling %s"
+msgstr "volám %s"
+
+msgid "%s aborted"
+msgstr "%s zrušený"
+
+#, c-format
+msgid "%s returning #%ld"
+msgstr "%s vrátilo #%ld"
+
+msgid "%s returning %s"
+msgstr "%s vrátilo %s"
+
+#, c-format
+msgid "continuing in %s"
+msgstr "pokraèujem v %s"
+
+msgid "E133: :return not inside a function"
+msgstr "E133: :return mimo funkciu"
+
+#, c-format
+msgid ""
+"\n"
+"# global variables:\n"
+msgstr ""
+"\n"
+"# globálne premenné:\n"
+
+msgid ""
+"\n"
+"\tLast set from "
+msgstr ""
+"\n"
+"\tPosledné nastavenie z "
+
+#, c-format
+msgid "<%s>%s%s %d, Hex %02x, Octal %03o"
+msgstr "<%s>%s%s %d, šestnástkovo %02x, osmièkovo %03o"
+
+msgid "> %d, Hex %04x, Octal %o"
+msgstr "> %d, šestnástkovo %04x, osmièkovo %o"
+
+msgid "> %d, Hex %08x, Octal %o"
+msgstr "> %d, šestnástkovo %08x, osmièkovo %o"
+
+msgid "E134: Move lines into themselves"
+msgstr "E134: Prekrytie riadkov sebou samými"
+
+msgid "1 line moved"
+msgstr "1 riadok presunutý"
+
+#, c-format
+msgid "%ld lines moved"
+msgstr "%ld riadkov presunutých"
+
+#, c-format
+msgid "%ld lines filtered"
+msgstr "%ld riadkov filtrovaných"
+
+msgid "E135: *Filter* Autocommands must not change current buffer"
+msgstr "E135: Automatické príkazy *Filter* nesmú meni aktuálny buffer"
+
+msgid "[No write since last change]\n"
+msgstr "[Neuložené zmeny]\n"
+
+msgid "%sviminfo: %s in line: "
+msgstr "%sviminfo: %s na riadku: "
+
+msgid "E136: viminfo: Too many errors, skipping rest of file"
+msgstr "E136: viminfo: príliš mnoho chýb, preskakujem zbytok súboru"
+
+#, c-format
+msgid "Reading viminfo file \"%s\"%s%s%s"
+msgstr "Èítam viminfo súbor \"%s\"%s%s%s"
+
+msgid " info"
+msgstr " informácie"
+
+msgid " marks"
+msgstr " znaèky"
+
+msgid " FAILED"
+msgstr " ZLYHALO"
+
+#, c-format
+msgid "E137: Viminfo file is not writable: %s"
+msgstr "E137: Do viminfo súboru %s sa nedá zapisova"
+
+#, c-format
+msgid "E138: Can't write viminfo file %s!"
+msgstr "E138: Nedá sa uloži viminfo súbor %s!"
+
+#, c-format
+msgid "Writing viminfo file \"%s\""
+msgstr "Ukládám viminfo súboru \"%s\""
+
+#. Write the info:
+#, c-format
+msgid "# This viminfo file was generated by Vim %s.\n"
+msgstr "# Tento viminfo súbor bol vytvorený editorom Vim %s.\n"
+
+#, c-format
+msgid ""
+"# You may edit it if you're careful!\n"
+"\n"
+msgstr ""
+"# Pokia¾ budete opatrný, môžete ho upravova.\n"
+"\n"
+
+#, c-format
+msgid "# Value of 'encoding' when this file was written\n"
+msgstr "# Hodnota 'encoding' (kódovania) poèas zápisu tohoto súboru\n"
+
+msgid "Illegal starting char"
+msgstr "Neprípustný zaèiatoèný znak"
+
+msgid "Save As"
+msgstr "Uloži ako"
+
+msgid "Write partial file?"
+msgstr "Uloži neúplný súbor?"
+
+msgid "E140: Use ! to write partial buffer"
+msgstr "E140: Použite ! pre uloženie neúplného bufferu"
+
+msgid "Overwrite existing file \"%s\"?"
+msgstr "Prepísa existujúci súbor \"%s\"?"
+
+#, c-format
+msgid "Swap file \"%s\" exists, overwrite anyway?"
+msgstr "Odkladací súbor \"%s\" existuje, aj tak prepísa?"
+
+msgid "E768: Swap file exists: %s (:silent! overrides)"
+msgstr "E768: Odkladací súbor existuje: %s (použite :silent! pre prepísanie)"
+
+#, c-format
+msgid "E141: No file name for buffer %ld"
+msgstr "E141: Žiadny názov súboru pre buffer %ld"
+
+msgid "E142: File not written: Writing is disabled by 'write' option"
+msgstr "E142: Súbor nebol uložený: ukladanie je zakázané vo¾bou 'write'"
+
+msgid ""
+"'readonly' option is set for \"%s\".\n"
+"Do you wish to write anyway?"
+msgstr ""
+"Pre \"%s\" je nastavená vo¾ba 'readonly' (iba na èítanie).\n"
+"Prajete si aj tak uloži?"
+
+msgid "Edit File"
+msgstr "Upravova súbor"
+
+#, c-format
+msgid "E143: Autocommands unexpectedly deleted new buffer %s"
+msgstr "E143: Automatické príkazy neoèakávane zmazali nový buffer %s"
+
+msgid "E144: non-numeric argument to :z"
+msgstr "E144: neèíselný argument pre :z"
+
+msgid "E145: Shell commands not allowed in rvim"
+msgstr "E145: rvim nepovo¾uje použitie príkazov shellu"
+
+msgid "E146: Regular expressions can't be delimited by letters"
+msgstr "E146: Regulárne výrazy nesmú by oddelené písmenami"
+
+#, c-format
+msgid "replace with %s (y/n/a/q/l/^E/^Y)?"
+msgstr "nahradi %s (y/n/a/q/l/^E/^Y)?"
+
+msgid "(Interrupted) "
+msgstr "(prerušený) "
+
+msgid "1 match"
+msgstr "1 zhoda"
+
+msgid "1 substitution"
+msgstr "1 nahradenie"
+
+msgid "%ld matches"
+msgstr "%ld zhôd"
+
+#, c-format
+msgid "%ld substitutions"
+msgstr "%ld nahradení"
+
+msgid " on 1 line"
+msgstr " na 1 riadku"
+
+#, c-format
+msgid " on %ld lines"
+msgstr " na %ld riadkov"
+
+msgid "E147: Cannot do :global recursive"
+msgstr "E147: :global sa nedá vola rekurzívne"
+
+msgid "E148: Regular expression missing from global"
+msgstr "E148: Pri príkaze global chýba regulárny výraz"
+
+#, c-format
+msgid "Pattern found in every line: %s"
+msgstr "Vzor nájdený na každom riadku: %s"
+
+#, c-format
+msgid ""
+"\n"
+"# Last Substitute String:\n"
+"$"
+msgstr ""
+"\n"
+"# Posledný zamieòaný reazec:\n"
+"$"
+
+msgid "E478: Don't panic!"
+msgstr "E478: Žiadnu paniku!"
+
+msgid "E661: Sorry, no '%s' help for %s"
+msgstr "E661: ¼utujem, žiadny '%s' pomocník pre %s"
+
+#, c-format
+msgid "E149: Sorry, no help for %s"
+msgstr "E149: ¼utujem, pre %s nie je žiadny pomocník"
+
+#, c-format
+msgid "Sorry, help file \"%s\" not found"
+msgstr "¼utujem, súbor \"%s\" s pomocníkom nebol nájdený"
+
+#, c-format
+msgid "E150: Not a directory: %s"
+msgstr "E150: %s nie je adresárom"
+
+#, c-format
+msgid "E152: Cannot open %s for writing"
+msgstr "E152: %s sa nedá sa otvori pre zápis"
+
+#, c-format
+msgid "E153: Unable to open %s for reading"
+msgstr "E153: %s as nedá otvori pre èítanie"
+
+#, c-format
+msgid "E670: Mix of help file encodings within a language: %s"
+msgstr "E670: Rôzne kódovania pre súbory s pomocníkom pre jazyk: %s"
+
+msgid "E154: Duplicate tag \"%s\" in file %s/%s"
+msgstr "E154: Duplicitný tag \"%s\" v súbore %s/%s"
+
+#, c-format
+msgid "E160: Unknown sign command: %s"
+msgstr "E160: Neznámu príkaz pre znaèky: %s"
+
+msgid "E156: Missing sign name"
+msgstr "E156: Chýba meno pre znaèku"
+
+msgid "E612: Too many signs defined"
+msgstr "E612: Príliš mnoho definovaných znaèiek"
+
+#, c-format
+msgid "E239: Invalid sign text: %s"
+msgstr "E239: Chybný text znaèky: %s"
+
+#, c-format
+msgid "E155: Unknown sign: %s"
+msgstr "E155: Neznáma znaèka: %s"
+
+msgid "E159: Missing sign number"
+msgstr "E159: Chýba èislo znaèky"
+
+#, c-format
+msgid "E158: Invalid buffer name: %s"
+msgstr "E158: Chybné meno bufferu: %s"
+
+#, c-format
+msgid "E157: Invalid sign ID: %ld"
+msgstr "E157: Chybné ID znaèky: %ld"
+
+msgid " (NOT FOUND)"
+msgstr " (NENÁJDENÉ)"
+
+msgid " (not supported)"
+msgstr " (nepodporované)"
+
+msgid "[Deleted]"
+msgstr "[vymazaný]"
+
+msgid "Entering Debug mode. Type \"cont\" to continue."
+msgstr "Spúšam režim ladenia. Pre ukonèenie napíšte \"cont\"."
+
+#, c-format
+msgid "line %ld: %s"
+msgstr "riadok %ld: %s"
+
+#, c-format
+msgid "cmd: %s"
+msgstr "príkaz: %s"
+
+#, c-format
+msgid "Breakpoint in \"%s%s\" line %ld"
+msgstr "Bod prerušenia v \"%s%s\" na riadku %ld"
+
+#, c-format
+msgid "E161: Breakpoint not found: %s"
+msgstr "E161: Bod prerušenia nenájdený: %s"
+
+msgid "No breakpoints defined"
+msgstr "Neboli definovné žiadne body prerušenia"
+
+#, c-format
+msgid "%3d %s %s line %ld"
+msgstr "%3d %s %s riadok %ld"
+
+msgid "E750: First use :profile start <fname>"
+msgstr "E750: Najprv použite príkaz :profile start <meno_suboru>"
+
+msgid "Save changes to \"%s\"?"
+msgstr "Uloži zmeny do \"%s\"?"
+
+msgid "Untitled"
+msgstr "Bez mena"
+
+#, c-format
+msgid "E162: No write since last change for buffer \"%s\""
+msgstr "E162: Buffer \"%s\" obsahuje neuložené zmeny"
+
+msgid "Warning: Entered other buffer unexpectedly (check autocommands)"
+msgstr ""
+"Varovanie: Neèakaný vstup do iného bufferu (skontrolujte automatické príkazy)"
+
+msgid "E163: There is only one file to edit"
+msgstr "E163: Pre úpravu bol zadaný iba jeden súbor"
+
+msgid "E164: Cannot go before first file"
+msgstr "E164: Nedá sa preskoèi pred prvý súbor"
+
+msgid "E165: Cannot go beyond last file"
+msgstr "E165: Nedá sa preskoèi za posledný súbor"
+
+msgid "E666: compiler not supported: %s"
+msgstr "E666: prekladaè nie je podporovaný: %s"
+
+#, c-format
+msgid "Searching for \"%s\" in \"%s\""
+msgstr "H¾adám \"%s\" v \"%s\""
+
+#, c-format
+msgid "Searching for \"%s\""
+msgstr "H¾adám \"%s\""
+
+#, c-format
+msgid "not found in 'runtimepath': \"%s\""
+msgstr "súbor \"%s\" nebol nájdený v 'runtimepath'"
+
+msgid "Source Vim script"
+msgstr "Zdrojový skript Vim"
+
+#, c-format
+msgid "Cannot source a directory: \"%s\""
+msgstr "Nemožno interpretova adresár: \"%s\""
+
+#, c-format
+msgid "could not source \"%s\""
+msgstr "nedá sa interpretova \"%s\""
+
+#, c-format
+msgid "line %ld: could not source \"%s\""
+msgstr "riadok %ld: nemôžno interpretova \"%s\""
+
+#, c-format
+msgid "sourcing \"%s\""
+msgstr "interpretujem \"%s\""
+
+#, c-format
+msgid "line %ld: sourcing \"%s\""
+msgstr "riadok %ld: interpretujem \"%s\""
+
+#, c-format
+msgid "finished sourcing %s"
+msgstr "dokonèená interpretácia %s"
+
+msgid "W15: Warning: Wrong line separator, ^M may be missing"
+msgstr "W15: Varovanie: chybný odde¾ovaè riadkov. Možno chýba ^M"
+
+msgid "E167: :scriptencoding used outside of a sourced file"
+msgstr "E167: príkaz :scriptencoding použitý mimo interpretovaný súbor"
+
+msgid "E168: :finish used outside of a sourced file"
+msgstr "E168: príkaz :finish použitý mimo interpretovaný súbor"
+
+#, c-format
+msgid "Current %slanguage: \"%s\""
+msgstr "Aktuálny %sjazyk: \"%s\""
+
+#, c-format
+msgid "E197: Cannot set language to \"%s\""
+msgstr "E197: Nedá sa nastavi jazyk na \"%s\""
+
+msgid "Entering Ex mode. Type \"visual\" to go to Normal mode."
+msgstr "Spúšam Ex režim. Napíšte \"visual\" pre návrat do Normálneho režimu."
+
+msgid "E501: At end-of-file"
+msgstr "E501: Koniec súboru"
+
+msgid "E169: Command too recursive"
+msgstr "E169: Príkaz je príliš rekurzívny"
+
+msgid "E605: Exception not caught: %s"
+msgstr "E605: Výnimka nezachytená: %s"
+
+msgid "End of sourced file"
+msgstr "Koniec interpretovaného súboru"
+
+msgid "End of function"
+msgstr "Koniec funkcie"
+
+msgid "E464: Ambiguous use of user-defined command"
+msgstr "E464: Nejednoznaèné použitie používate¾om definovaného príkazu"
+
+msgid "E492: Not an editor command"
+msgstr "E492: Nie je príkazom editoru"
+
+msgid "E493: Backwards range given"
+msgstr "E493: Zadaný spätný rozsah"
+
+msgid "Backwards range given, OK to swap"
+msgstr "Zadaný spätný rozsah. OK pre zámenu"
+
+msgid "E494: Use w or w>>"
+msgstr "E494: Použite w alebo w>>"
+
+msgid "E319: Sorry, the command is not available in this version"
+msgstr "E319: ¼utujem, ale tento príkaz nie je dostupný v tejto verzii"
+
+msgid "E172: Only one file name allowed"
+msgstr "E172: Prípustný je iba jeden názov súboru"
+
+msgid "1 more file to edit. Quit anyway?"
+msgstr "Ešte zostáva 1 súbor k úprave. Chcete napriek tomu ukonèi editor?"
+
+#, c-format
+msgid "%d more files to edit. Quit anyway?"
+msgstr "Ešte zostáva %d súborov k úprave. Chcete napriek tomu ukonèi editor?"
+
+msgid "E173: 1 more file to edit"
+msgstr "E173: Ešte zostáva 1 súbor k úprave."
+
+#, c-format
+msgid "E173: %ld more files to edit"
+msgstr "E173: Ešte zostáva %ld súborov k úprave."
+
+msgid "E174: Command already exists: add ! to replace it"
+msgstr "E174: Príkaz už existuje: použite ! pre predefinovanie"
+
+msgid ""
+"\n"
+" Name Args Range Complete Definition"
+msgstr ""
+"\n"
+" Meno Args Rozsah Úplnos Definícia"
+
+msgid "No user-defined commands found"
+msgstr "Neboli nájdené žiadne použivate¾om definované príkazy"
+
+msgid "E175: No attribute specified"
+msgstr "E175: Neboli zadané žiadne vlastnosti"
+
+msgid "E176: Invalid number of arguments"
+msgstr "E176: Chybný poèet argumentov"
+
+msgid "E177: Count cannot be specified twice"
+msgstr "E177: Poèet nemôže by zadaný dvakrát"
+
+msgid "E178: Invalid default value for count"
+msgstr "E178: Chybná implicitná hodnota pre poèet"
+
+msgid "E179: argument required for -complete"
+msgstr "E179: pre doplnenie (-complete) je potrebný argument"
+
+#, c-format
+msgid "E181: Invalid attribute: %s"
+msgstr "E181: Chybná vlastnos: %s"
+
+msgid "E182: Invalid command name"
+msgstr "E182: Chybné meno príkazu"
+
+msgid "E183: User defined commands must start with an uppercase letter"
+msgstr "E183: Používate¾om definované príkazy musia zaèína ve¾kým písmenom"
+
+#, c-format
+msgid "E184: No such user-defined command: %s"
+msgstr "E184: Používate¾om definovaný príkaz %s neexistuje"
+
+#, c-format
+msgid "E180: Invalid complete value: %s"
+msgstr "E180: Chybná hodnota doplnenia: %s"
+
+msgid "E468: Completion argument only allowed for custom completion"
+msgstr "E468: Argument doplnenia je povolený iba pre vlastné dopåòania (completion)"
+
+msgid "E467: Custom completion requires a function argument"
+msgstr "E467: Vlastné doplnenia vyžadujú meno funkcie ako argument"
+
+#, c-format
+msgid "E185: Cannot find color scheme %s"
+msgstr "E185: Schéma farieb %s nenájdená"
+
+msgid "Greetings, Vim user!"
+msgstr "Pozdravujem, užívate¾ Vimu!"
+
+msgid "Edit File in new window"
+msgstr "Upravi súbor v novom okne"
+
+msgid "No swap file"
+msgstr "Žiadny odkladací súbor"
+
+msgid "Append File"
+msgstr "Pripoji súbor"
+
+msgid "E747: Cannot change directory, buffer is modified (add ! to override)"
+msgstr "E747: Nemožno zmeni adresár, buffer je modifikovaný (použite ! pre vynútenie)"
+
+msgid "E186: No previous directory"
+msgstr "E186: Žiadny predchádzajúci adresár"
+
+msgid "E187: Unknown"
+msgstr "E187: Neznámy"
+
+msgid "E465: :winsize requires two number arguments"
+msgstr "E465: :winsize (ve¾kos okna) vyžaduje dva argumenty"
+
+#, c-format
+msgid "Window position: X %d, Y %d"
+msgstr "Pozícia okna: X %d, Y %d"
+
+msgid "E188: Obtaining window position not implemented for this platform"
+msgstr "E188: Na tejto platforme sa nedá zisti umiestnenie okna"
+
+msgid "E466: :winpos requires two number arguments"
+msgstr "E466: :winpos (pozícia okna) vyžaduje dva argumenty"
+
+msgid "Save Redirection"
+msgstr "Uloži presmerovanie"
+
+msgid "Save View"
+msgstr "Uloži poh¾ad"
+
+msgid "Save Session"
+msgstr "Uloži sedenie"
+
+msgid "Save Setup"
+msgstr "Uloži nastavenie"
+
+msgid "E739: Cannot create directory: %s"
+msgstr "E739: Nemožno vytvori adresár: %s"
+
+msgid "E189: \"%s\" exists (add ! to override)"
+msgstr "E189: \"%s\" existuje (použite ! pre vynútenie)"
+
+#, c-format
+msgid "E190: Cannot open \"%s\" for writing"
+msgstr "E190: \"%s\" sa nedá otvori pre zápis"
+
+#. set mark
+msgid "E191: Argument must be a letter or forward/backward quote"
+msgstr "E191: Argumentem môže by iba písmeno alebo pravý èi ¾avý apostrof"
+
+msgid "E192: Recursive use of :normal too deep"
+msgstr "E192: Rekurzívne použitie príkazu :normal príliš hlboké"
+
+msgid "E194: No alternate file name to substitute for '#'"
+msgstr ""
+"E194: Žiadny alternatívny názov súboru, ktorým by bolo možné nahradi '#'"
+
+msgid "E495: no autocommand file name to substitute for \"<afile>\""
+msgstr "E495: žiadny názov súboru, ktorým by bolo možné nahradi \"<afile>\""
+
+msgid "E496: no autocommand buffer number to substitute for \"<abuf>\""
+msgstr "E496: žiadne èíslo bufferu, ktorým by bolo možné nahradi \"<abuf>\""
+
+msgid "E497: no autocommand match name to substitute for \"<amatch>\""
+msgstr ""
+"E497: žiadna zhoda automatických príkazov, ktorou by bolo možné nahradi \"<amatch>"
+"\""
+
+msgid "E498: no :source file name to substitute for \"<sfile>\""
+msgstr "E498: žiadny :source súbor, ktorým by bolo možné nahradi \"<sfile>\""
+
+msgid "E499: Empty file name for '%' or '#', only works with \":p:h\""
+msgstr "E499: Prázdný názov súboru pre '%' alebo '#', funguje iba s \":p:h\""
+
+msgid "E500: Evaluates to an empty string"
+msgstr "E500: Výsledkom vyhodnotenia je prázdny reazec"
+
+msgid "E195: Cannot open viminfo file for reading"
+msgstr "E195: Súbor viminfo sa nedá sa otvori na èítanie"
+
+msgid "E196: No digraphs in this version"
+msgstr "E196: V tejto verzi nie sú digraphy podporované"
+
+msgid "E608: Cannot :throw exceptions with 'Vim' prefix"
+msgstr "E608: Nemožno spracova výnimku :throw s preponou 'Vim'"
+
+#. always scroll up, don't overwrite
+#, c-format
+msgid "Exception thrown: %s"
+msgstr "Spracovanie výnimky: %s"
+
+#, c-format
+msgid "Exception finished: %s"
+msgstr "Výnimka ukonèená: %s"
+
+#, c-format
+msgid "Exception discarded: %s"
+msgstr "Výnimka zahodená: %s"
+
+msgid "%s, line %ld"
+msgstr "%s, riadok %ld"
+
+#. always scroll up, don't overwrite
+msgid "Exception caught: %s"
+msgstr "Zachytená výnimka: %s"
+
+#, c-format
+msgid "%s made pending"
+msgstr "%s prebieha"
+
+msgid "%s resumed"
+msgstr "%s vrátené"
+
+#, c-format
+msgid "%s discarded"
+msgstr "%s zahodené"
+
+msgid "Exception"
+msgstr "Výnimka"
+
+msgid "Error and interrupt"
+msgstr "Chyba a prerušené"
+
+msgid "Error"
+msgstr "Chyba"
+
+#. if (pending & CSTP_INTERRUPT)
+msgid "Interrupt"
+msgstr "Prerušené"
+
+msgid "E579: :if nesting too deep"
+msgstr "E579: vnorenie :if je príliš hlboké"
+
+msgid "E580: :endif without :if"
+msgstr "E580: :endif bez zodpovedajúceho :if"
+
+msgid "E581: :else without :if"
+msgstr "E581: :else bez zodpovedajúceho :if"
+
+msgid "E582: :elseif without :if"
+msgstr "E582: :elseif bez zodpovedajúceho :if"
+
+msgid "E583: multiple :else"
+msgstr "E583: viacnásobné :else"
+
+msgid "E584: :elseif after :else"
+msgstr "E584: :elseif nasleduje po :else"
+
+msgid "E585: :while/:for nesting too deep"
+msgstr "E585: vnorenie :while/:for je príliš hlboké"
+
+msgid "E586: :continue without :while or :for"
+msgstr "E586: :continue bez zodpovedajúceho :while alebo :for"
+
+msgid "E587: :break without :while or :for"
+msgstr "E587: :break bez zodpovedajúceho :while alebo :for"
+
+msgid "E732: Using :endfor with :while"
+msgstr "E732: Použité :endfor spolu s :while"
+
+msgid "E733: Using :endwhile with :for"
+msgstr "E733: Použité :endwhile spolu s :for"
+
+msgid "E601: :try nesting too deep"
+msgstr "E601: vnorenie :try je príliš hlboké"
+
+msgid "E603: :catch without :try"
+msgstr "E603: :catch bez :try"
+
+#. Give up for a ":catch" after ":finally" and ignore it.
+#. * Just parse.
+msgid "E604: :catch after :finally"
+msgstr "E604: :catch nasleduje po :finally"
+
+msgid "E606: :finally without :try"
+msgstr "E606: :finally bez :try"
+
+#. Give up for a multiple ":finally" and ignore it.
+msgid "E607: multiple :finally"
+msgstr "E607: viacnásobné použité :finally"
+
+msgid "E602: :endtry without :try"
+msgstr "E602: :endtry bez :try"
+
+msgid "E193: :endfunction not inside a function"
+msgstr "E193: :endfunction mimo funkciu"
+
+msgid "tagname"
+msgstr "meno tagu"
+
+msgid " kind file\n"
+msgstr " typ súboru\n"
+
+msgid "'history' option is zero"
+msgstr "'vo¾ba 'history' je nastavená na nulu"
+
+#, c-format
+msgid ""
+"\n"
+"# %s History (newest to oldest):\n"
+msgstr ""
+"\n"
+"# História %s (zaèínajúci najnovšou položkou):\n"
+
+msgid "Command Line"
+msgstr "Príkazový riadok"
+
+msgid "Search String"
+msgstr "Vyh¾adávaný reazec"
+
+msgid "Expression"
+msgstr "Výraz"
+
+msgid "Input Line"
+msgstr "Vstupný riadok"
+
+msgid "E198: cmd_pchar beyond the command length"
+msgstr "E198: cmd_pchar prevyšuje dåžku príkazu"
+
+msgid "E199: Active window or buffer deleted"
+msgstr "E199: Aktívne okno alebo buffer bol vymazaný"
+
+msgid "Illegal file name"
+msgstr "Neprípustný názov súboru"
+
+msgid "is a directory"
+msgstr "je adresárom"
+
+msgid "is not a file"
+msgstr "nie je súborom"
+
+msgid "[New File]"
+msgstr "[nový súbor]"
+
+msgid "[Permission Denied]"
+msgstr "[prístup odmietnutý]"
+
+msgid "E200: *ReadPre autocommands made the file unreadable"
+msgstr "E200: automatické príkazy *ReadPre urobili súbor neèitate¾ným"
+
+msgid "E201: *ReadPre autocommands must not change current buffer"
+msgstr "E201: automatické príkazy *ReadPre nesmú meni aktuálny buffer"
+
+msgid "Vim: Reading from stdin...\n"
+msgstr "Vim: èítam zo štandardného vstupu...\n"
+
+msgid "Reading from stdin..."
+msgstr "Èítam zo štandardného vstupu..."
+
+#. Re-opening the original file failed!
+msgid "E202: Conversion made file unreadable!"
+msgstr "E202: Po konverzii je súbor neèitate¾ný!"
+
+msgid "[fifo/socket]"
+msgstr "[pomenovaná rúra/soket]"
+
+msgid "[fifo]"
+msgstr "[pomenovaná rúra]"
+
+msgid "[socket]"
+msgstr "[soket]"
+
+msgid "[RO]"
+msgstr "[RO]"
+
+msgid "[CR missing]"
+msgstr "[chýba CR]"
+
+msgid "[NL found]"
+msgstr "[nájdené NL]"
+
+msgid "[long lines split]"
+msgstr "[dlhé riadky zalomené]"
+
+msgid "[NOT converted]"
+msgstr "[neskonvertovaný]"
+
+msgid "[converted]"
+msgstr "[skonvertovaný]"
+
+msgid "[crypted]"
+msgstr "[šifrovaný]"
+
+msgid "[CONVERSION ERROR]"
+msgstr "[CHYBA PREVODU]"
+
+#, c-format
+msgid "[ILLEGAL BYTE in line %ld]"
+msgstr "[NEPRÍPUSTNÝ BAJT na riadku %ld]"
+
+msgid "[READ ERRORS]"
+msgstr "[CHYBY ÈÍTANIA]"
+
+msgid "Can't find temp file for conversion"
+msgstr "Nedá sa nájs doèasný súbor pre konverziu"
+
+msgid "Conversion with 'charconvert' failed"
+msgstr "Konverzia s 'charconvert' sa nepodarila"
+
+msgid "can't read output of 'charconvert'"
+msgstr "nedá sa èíta výstup 'charconvert'"
+
+msgid "E676: No matching autocommands for acwrite buffer"
+msgstr "E676: Žiadne vyhovujúce automatické príkazy pre acwrite buffer "
+
+msgid "E203: Autocommands deleted or unloaded buffer to be written"
+msgstr ""
+"E203: Automatické príkazy zmazali èi deaktivovali buffer, ktorý mal by "
+"uložený"
+
+msgid "E204: Autocommand changed number of lines in unexpected way"
+msgstr "E204: Automatický príkaz neoèakávaným spôsobom zmenil poèet riadkov"
+
+msgid "NetBeans disallows writes of unmodified buffers"
+msgstr "NetBeans rozhranie nedovolilo zapísa nemodifikované buffre"
+
+msgid "Partial writes disallowed for NetBeans buffers"
+msgstr "Èiastoèné zápisy nie sú povolené pre NetBeans buffre"
+
+msgid "is not a file or writable device"
+msgstr "nie je súborom ani zapisovatelným zariadením"
+
+msgid "is read-only (add ! to override)"
+msgstr "je iba pre èítanie (použite ! pre vynútenie)"
+
+msgid "E506: Can't write to backup file (add ! to override)"
+msgstr "E506: Nedá sa zapisova do záložného súboru (použite ! pre vynútenie)"
+
+msgid "E507: Close error for backup file (add ! to override)"
+msgstr "E507: Chyba pri uzatváraní záložného súboru (použite ! pre vynútenie)"
+
+msgid "E508: Can't read file for backup (add ! to override)"
+msgstr "E508: Nedá sa naèíta súbor pre zálohu (použite ! pre vynútenie)"
+
+msgid "E509: Cannot create backup file (add ! to override)"
+msgstr "E509: Nedá sa vytvori záložný súbor (použite ! pre vynútenie)"
+
+msgid "E510: Can't make backup file (add ! to override)"
+msgstr "E510: Nedá sa vytvori záložný súbor (použite ! pre vynútenie)"
+
+# TODO: resource fork ?! Note: used only in MACOS_X version
+msgid "E460: The resource fork would be lost (add ! to override)"
+msgstr "E460: 'Resource fork' bude stratený (použite ! pre vynútenie)"
+
+msgid "E214: Can't find temp file for writing"
+msgstr "E214: Nedá sa nájs doèasný súbor pre ukladanie"
+
+msgid "E213: Cannot convert (add ! to write without conversion)"
+msgstr "E213: Nedá sa spravi konverzia (použite ! pre zápis bez konverzie)"
+
+msgid "E166: Can't open linked file for writing"
+msgstr "E166: Súbor sa nedá otvori pre ukladanie"
+
+msgid "E212: Can't open file for writing"
+msgstr "E212: Súbor sa nedá otvori pre ukladanie"
+
+msgid "E667: Fsync failed"
+msgstr "E667: Fsync zlyhal"
+
+msgid "E512: Close failed"
+msgstr "E512: Zatvorenie zlyhalo"
+
+msgid "E513: write error, conversion failed (make 'fenc' empty to override)"
+msgstr "E513: chyba pri zápise, konverzia sa nepodarila (nastavte vo¾bu 'fenc' na prázdnu pre vynútenie)"
+
+msgid "E514: write error (file system full?)"
+msgstr "E514: chyba pri ukladaní (plný disk?)"
+
+msgid " CONVERSION ERROR"
+msgstr " CHYBA PREVODU"
+
+msgid "[Device]"
+msgstr "[zariadenie]"
+
+msgid "[New]"
+msgstr "[nový]"
+
+msgid " [a]"
+msgstr " [p]"
+
+msgid " appended"
+msgstr " pripojený"
+
+msgid " [w]"
+msgstr " [u]"
+
+msgid " written"
+msgstr " uložený"
+
+msgid "E205: Patchmode: can't save original file"
+msgstr "E205: patchmode: nedá sa uloži pôvodný súbor"
+
+msgid "E206: patchmode: can't touch empty original file"
+msgstr "E206: patchmode: nedá sa zapisova do prázdneho pôvodného súboru"
+
+msgid "E207: Can't delete backup file"
+msgstr "E207: Nedá sa vymaza záložný súbor"
+
+msgid ""
+"\n"
+"WARNING: Original file may be lost or damaged\n"
+msgstr ""
+"\n"
+"VAROVANIE: Obsah pôvodného súboru môže by stratený alebo poškodený\n"
+
+msgid "don't quit the editor until the file is successfully written!"
+msgstr "neukonèujte editor skôr, než bude súbor úspešne uložený!"
+
+msgid "[dos]"
+msgstr "[dos]"
+
+msgid "[dos format]"
+msgstr "[dos formát]"
+
+msgid "[mac]"
+msgstr "[mac]"
+
+msgid "[mac format]"
+msgstr "[mac formát]"
+
+msgid "[unix]"
+msgstr "[unix]"
+
+msgid "[unix format]"
+msgstr "[unix formát]"
+
+msgid "1 line, "
+msgstr "1 riadok, "
+
+#, c-format
+msgid "%ld lines, "
+msgstr "%ld riadkov, "
+
+msgid "1 character"
+msgstr "1 znak"
+
+#, c-format
+msgid "%ld characters"
+msgstr "%ld znakov"
+
+msgid "[noeol]"
+msgstr "[bez znaku konca riadku]"
+
+msgid "[Incomplete last line]"
+msgstr "[neúplný posledný riadok]"
+
+#. don't overwrite messages here
+#. must give this prompt
+#. don't use emsg() here, don't want to flush the buffers
+msgid "WARNING: The file has been changed since reading it!!!"
+msgstr "VAROVANIE: Súbor bol zmenený od jeho naèítania!!!"
+
+msgid "Do you really want to write to it"
+msgstr "Chcete ho naozaj uloži"
+
+#, c-format
+msgid "E208: Error writing to \"%s\""
+msgstr "E208: Chyba pri zápise do \"%s\""
+
+#, c-format
+msgid "E209: Error closing \"%s\""
+msgstr "E209: Chyba pri uzatváraní \"%s\""
+
+#, c-format
+msgid "E210: Error reading \"%s\""
+msgstr "E210: Chyba pri èítaní \"%s\""
+
+msgid "E246: FileChangedShell autocommand deleted buffer"
+msgstr "E246: automatický príkaz FileChangedShell vymazal buffer"
+
+msgid "E211: File \"%s\" no longer available"
+msgstr "E211: Varovanie: súbor \"%s\" už nie je dostupný"
+
+#, c-format
+msgid ""
+"W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as "
+"well"
+msgstr ""
+"W12: Varovanie: súbor \"%s\" bol po zaèatí úpravy zmenený a buffer sa tiež "
+"zmenil "
+
+msgid "See \":help W12\" for more info."
+msgstr "Pozrite \":help W12\" pre viac informácií."
+
+#, c-format
+msgid "W11: Warning: File \"%s\" has changed since editing started"
+msgstr "W11: Varovanie: súbor \"%s\" bol po zaèatí úpravy zmenený"
+
+msgid "See \":help W11\" for more info."
+msgstr "Pozrite \":help W11\" pre viac informácií."
+
+#, c-format
+msgid "W16: Warning: Mode of file \"%s\" has changed since editing started"
+msgstr ""
+"W16: Varovanie: Prístupové práva k súboru \"%s\" boli po zaèatí úprav zmenené"
+
+msgid "See \":help W16\" for more info."
+msgstr "Pozrite \":help W16\" pre viac informácií."
+
+#, c-format
+msgid "W13: Warning: File \"%s\" has been created after editing started"
+msgstr "W13: Varovanie: Súbor \"%s\" bol vytvorený po zaèatí úpravy"
+
+msgid "Warning"
+msgstr "Varovanie"
+
+msgid ""
+"&OK\n"
+"&Load File"
+msgstr ""
+"&OK\n"
+"&Naèíta súbor"
+
+msgid "E462: Could not prepare for reloading \"%s\""
+msgstr "E462: Nemožno pripravi na opätovné naèítanie \"%s\""
+
+#, c-format
+msgid "E321: Could not reload \"%s\""
+msgstr "E321: nedá sa obnovi \"%s\""
+
+msgid "--Deleted--"
+msgstr "--Vymazaný--"
+
+#, c-format
+msgid "auto-removing autocommand: %s <buffer=%d>"
+msgstr "samomazací automatický príkaz: %s <buffer=%d>"
+
+#. the group doesn't exist
+#, c-format
+msgid "E367: No such group: \"%s\""
+msgstr "E367: Skupina \"%s\" neexistuje"
+
+#, c-format
+msgid "E215: Illegal character after *: %s"
+msgstr "E215: Neprípustný znak po *: %s"
+
+#, c-format
+msgid "E216: No such event: %s"
+msgstr "E216: Udalos %s neexistuje"
+
+msgid "E216: No such group or event: %s"
+msgstr "E216: Udalos alebo skupina %s neexistuje"
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Autocommands ---"
+msgstr ""
+"\n"
+"--- Automatické príkazy ---"
+
+msgid "E680: <buffer=%d>: invalid buffer number "
+msgstr "E680: <buffer=%d>: chybné èíslo bufferu"
+
+msgid "E217: Can't execute autocommands for ALL events"
+msgstr "E217: Automatické príkazy sa nedajú spusti pre VŠETKY udalosti"
+
+msgid "No matching autocommands"
+msgstr "Žiadne vyhovujúce automatické príkazy"
+
+msgid "E218: autocommand nesting too deep"
+msgstr "E218: vnorenia automatického príkazu sú príliš hlboké"
+
+#, c-format
+msgid "%s Autocommands for \"%s\""
+msgstr "%s Automatické príkazy pre \"%s\""
+
+#, c-format
+msgid "Executing %s"
+msgstr "Spúšam %s"
+
+#, c-format
+msgid "autocommand %s"
+msgstr "automatický príkaz %s"
+
+msgid "E219: Missing {."
+msgstr "E219: Chýba {."
+
+msgid "E220: Missing }."
+msgstr "E220: Chýba }."
+
+msgid "E490: No fold found"
+msgstr "E490: Nebol nájdené žiadne vnorenie"
+
+msgid "E350: Cannot create fold with current 'foldmethod'"
+msgstr "E350: Nedá sa vytvori vnorenie s aktuálnou metódou 'foldmethod'"
+
+msgid "E351: Cannot delete fold with current 'foldmethod'"
+msgstr "E351: Nedá sa zruši vnorenie s aktuálnou metódou 'foldmethod'"
+
+#, c-format
+msgid "+--%3ld lines folded "
+msgstr "+--%3ld riadkov zahnutých "
+
+msgid "E222: Add to read buffer"
+msgstr "E222: Prida do bufferu pre èítanie"
+
+msgid "E223: recursive mapping"
+msgstr "E223: rekurzívne mapovanie"
+
+#, c-format
+msgid "E224: global abbreviation already exists for %s"
+msgstr "E224: pre %s už globálna skratka existuje"
+
+#, c-format
+msgid "E225: global mapping already exists for %s"
+msgstr "E225: pre %s už globálne mapovanie existuje"
+
+#, c-format
+msgid "E226: abbreviation already exists for %s"
+msgstr "E226: pre %s už skratka existuje"
+
+#, c-format
+msgid "E227: mapping already exists for %s"
+msgstr "E227: pre %s už mapovanie existuje"
+
+msgid "No abbreviation found"
+msgstr "Žiadna skratka nebola nájdená"
+
+msgid "No mapping found"
+msgstr "Žiadne mapovanie nebolo nájdené"
+
+msgid "E228: makemap: Illegal mode"
+msgstr "E228: makemap: neprípustný mód"
+
+msgid "E229: Cannot start the GUI"
+msgstr "E229: Nedá sa spusti GUI (grafické rozhranie)"
+
+#, c-format
+msgid "E230: Cannot read from \"%s\""
+msgstr "E230: Nedá sa èíta z \"%s\""
+
+msgid "E665: Cannot start GUI, no valid font found"
+msgstr "E665: Nemožno naštartova grafické rozhranie, nenájdený žiaden použitelný font"
+
+msgid "E231: 'guifontwide' invalid"
+msgstr ""
+"E231: vo¾ba 'guifontwide' (nastavenie širokého písma) je chybne nastavená"
+
+msgid "E599: Value of 'imactivatekey' is invalid"
+msgstr "E599: Hodnota 'imactivatekey' je nesprávne nastavená"
+
+#, c-format
+msgid "E254: Cannot allocate color %s"
+msgstr "E254: Nedá sa alokova farba %s"
+
+msgid "No match at cursor, finding next"
+msgstr "Žiadna zhoda na pozícii kurzora, h¾adám ïalej"
+
+msgid "<cannot open> "
+msgstr "<nedá sa otvori> "
+
+msgid "E616: vim_SelFile: can't get font %s"
+msgstr "E616: vim_SelFile: písmo %s nie je dostupné"
+
+msgid "E614: vim_SelFile: can't return to current directory"
+msgstr "E614: vim_SelFile: nedá sa vráti do aktuálneho adresára"
+
+msgid "Pathname:"
+msgstr "Názov cesty:"
+
+msgid "E615: vim_SelFile: can't get current directory"
+msgstr "E615: vim_SelFile: nedá sa zisti aktuálny adresár"
+
+msgid "OK"
+msgstr "OK"
+
+msgid "Cancel"
+msgstr "Zruši"
+
+msgid "Scrollbar Widget: Could not get geometry of thumb pixmap."
+msgstr "Prípravok posuvnej lišty: nedá sa zisti geometria náh¾adu obrázku."
+
+msgid "Vim dialog"
+msgstr "Vim dialóg"
+
+msgid "E232: Cannot create BalloonEval with both message and callback"
+msgstr "E232: BalloonEval nedá sa vytvori správou a zároveò spätným volaním"
+
+msgid "Vim dialog..."
+msgstr "Vim dialóg.."
+
+# TODO: Translate as "&Ano\n&Nie\n&Zruši" ?
+msgid ""
+"&Yes\n"
+"&No\n"
+"&Cancel"
+msgstr ""
+"&Ano\n"
+"&Nie\n"
+"&Zruši"
+
+msgid "Input _Methods"
+msgstr "Vstupné metódy (_Methods)"
+
+msgid "VIM - Search and Replace..."
+msgstr "VIM - Nájs a nahradi..."
+
+msgid "VIM - Search..."
+msgstr "VIM - Nájs..."
+
+msgid "Find what:"
+msgstr "Vyh¾ada:"
+
+msgid "Replace with:"
+msgstr "Nahradi s:"
+
+#. whole word only button
+msgid "Match whole word only"
+msgstr "H¾ada len celé slová"
+
+#. match case button
+msgid "Match case"
+msgstr "Zhoda ve¾kosti písmen"
+
+msgid "Direction"
+msgstr "Smer"
+
+#. 'Up' and 'Down' buttons
+msgid "Up"
+msgstr "Hore"
+
+msgid "Down"
+msgstr "Dolu"
+
+msgid "Find Next"
+msgstr "Nájs ïalšie"
+
+msgid "Replace"
+msgstr "Nahradi"
+
+msgid "Replace All"
+msgstr "Nahradi Všetko"
+
+msgid "Vim: Received \"die\" request from session manager\n"
+msgstr "Vim: Prijatá požiadavka na ukonèenie (die) od manažéra sedení\n"
+
+msgid "Vim: Main window unexpectedly destroyed\n"
+msgstr "Vim: Hlavné okno neoèakávane zrušené\n"
+
+msgid "Font Selection"
+msgstr "Výber Písma"
+
+msgid "Used CUT_BUFFER0 instead of empty selection"
+msgstr "Použitý CUT_BUFFER0 namiesto prázdneho výberu"
+
+msgid "&Filter"
+msgstr "&Filter"
+
+msgid "&Cancel"
+msgstr "&Zruši"
+
+msgid "Directories"
+msgstr "Adresáre"
+
+msgid "Filter"
+msgstr "Filter"
+
+msgid "&Help"
+msgstr "&Pomocník"
+
+msgid "Files"
+msgstr "Súbory"
+
+msgid "&OK"
+msgstr "&OK"
+
+msgid "Selection"
+msgstr "Výber"
+
+msgid "Find &Next"
+msgstr "Nájs ïa&lšie"
+
+msgid "&Replace"
+msgstr "&Nahradi"
+
+msgid "Replace &All"
+msgstr "Nahradi &Všetko"
+
+msgid "&Undo"
+msgstr "&Spä"
+
+msgid "E671: Cannot find window title \"%s\""
+msgstr "E671: Nemožno nájs okno s titulkom \"%s\""
+
+#, c-format
+msgid "E243: Argument not supported: \"-%s\"; Use the OLE version."
+msgstr "E243: Argument nie je podporovaný: \"-%s\"; Použite OLE verziu."
+
+msgid "E672: Unable to open window inside MDI application"
+msgstr "E672: Nemožno otvori okno vnútri MDI aplikácie"
+
+msgid "Find string (use '\\\\' to find a '\\')"
+msgstr "Nájs reazec (použite '\\\\' ak chete nájs '\\')"
+
+# Following warning can be ignored:
+# msgfmt -v --statistics --check -C --check-accelerators="&" -o sk.mo sk.po
+# sk.po:2497: msgstr lacks the keyboard accelerator mark '&'
+msgid "Find & Replace (use '\\\\' to find a '\\')"
+msgstr "Nájs a Nahradi (použite '\\\\' ak chcete nájs '\\')"
+
+#. We fake this: Use a filter that doesn't select anything and a default
+#. * file name that won't be used.
+msgid "Not Used"
+msgstr "[neupravovaný]"
+
+msgid "Directory\t*.nothing\n"
+msgstr "Adresár\t*.niè\n"
+
+msgid "Vim E458: Cannot allocate colormap entry, some colors may be incorrect"
+msgstr ""
+"Vim E458: Nedá sa alokova položka mapy farieb, niektoré farby môžu by "
+"nesprávne"
+
+#, c-format
+msgid "E250: Fonts for the following charsets are missing in fontset %s:"
+msgstr "E250: Chýba písmo pre nasledujúce znakové sady %s:"
+
+#, c-format
+msgid "E252: Fontset name: %s"
+msgstr "E252: Názov sady písiem: %s"
+
+#, c-format
+msgid "Font '%s' is not fixed-width"
+msgstr "Písmo '%s' nemá pevnou šírku"
+
+#, c-format
+msgid "E253: Fontset name: %s\n"
+msgstr "E253: Názov sady písiem: %s\n"
+
+#, c-format
+msgid "Font0: %s\n"
+msgstr "Písmo0: %s\n"
+
+#, c-format
+msgid "Font1: %s\n"
+msgstr "Písmo1: %s\n"
+
+msgid "Font%ld width is not twice that of font0\n"
+msgstr "Písmo%ld nie je dvakrát širšie ako písmo0\n"
+
+#, c-format
+msgid "Font0 width: %ld\n"
+msgstr "Šírka písma0: %ld\n"
+
+#, c-format
+msgid ""
+"Font1 width: %ld\n"
+"\n"
+msgstr ""
+"Šírka písma1: %ld\n"
+"\n"
+
+msgid "Invalid font specification"
+msgstr "Chybná špecifikácia písma"
+
+msgid "&Dismiss"
+msgstr "&Zruši"
+
+msgid "no specific match"
+msgstr "žiadna špecifická zhoda"
+
+msgid "Vim - Font Selector"
+msgstr "Vim - Výber písma"
+
+msgid "Name:"
+msgstr "Meno:"
+
+#. create toggle button
+msgid "Show size in Points"
+msgstr "Ukazuj ve¾kos v bodoch"
+
+msgid "Encoding:"
+msgstr "Kódujem:"
+
+msgid "Font:"
+msgstr "Písmo:"
+
+msgid "Style:"
+msgstr "Štýl"
+
+msgid "Size:"
+msgstr "Ve¾kos:"
+
+msgid "E256: Hangul automata ERROR"
+msgstr "E256: Hangul ERROR - chyba kórejského spôsobu vkladania znakov"
+
+msgid "E550: Missing colon"
+msgstr "E550: Chýba dvojbodka"
+
+msgid "E551: Illegal component"
+msgstr "E551: Neprípustný komponent"
+
+msgid "E552: digit expected"
+msgstr "E552: oèakávaná èíslica"
+
+#, c-format
+msgid "Page %d"
+msgstr "Strana %d"
+
+msgid "No text to be printed"
+msgstr "Žiadny text na tlaè"
+
+#, c-format
+msgid "Printing page %d (%d%%)"
+msgstr "Tlaèím stranu %d (%d%%)"
+
+#, c-format
+msgid " Copy %d of %d"
+msgstr " Kópia %d z %d"
+
+#, c-format
+msgid "Printed: %s"
+msgstr "Vytlaèené: %s"
+
+msgid "Printing aborted"
+msgstr "Tlaè bola zrušená"
+
+msgid "E455: Error writing to PostScript output file"
+msgstr "E455: Nedá sa zapisova do výstupného PostScriptového súboru"
+
+msgid "E624: Can't open file \"%s\""
+msgstr "E624: Nedá sa otvori súbor \"%s\""
+
+#, c-format
+msgid "E457: Can't read PostScript resource file \"%s\""
+msgstr "E457: Nedá sa èíta PostScriptový súbor \"%s\""
+
+msgid "E618: file \"%s\" is not a PostScript resource file"
+msgstr "E618: súbor \"%s\" nie je vo formáte PostScript"
+
+msgid "E619: file \"%s\" is not a supported PostScript resource file"
+msgstr "E619: súbor \"%s\" nie je podporvaný PostScriptový súbor"
+
+#, c-format
+msgid "E621: \"%s\" resource file has wrong version"
+msgstr "E621: \"%s\" zdrojový súbor má zlé èíslo verzie"
+
+msgid "E673: Incompatible multi-byte encoding and character set."
+msgstr "E673: nekompatibilné viacbajtové kódovanie a znaková sada."
+
+msgid "E674: printmbcharset cannot be empty with multi-byte encoding."
+msgstr "E674: vo¾ba printmbcharset nemôže by prázdna pri viacbajtovom kódovaní."
+
+msgid "E675: No default font specified for multi-byte printing."
+msgstr "E675: Nie je špecifikované žiadne písmo pre viacbajtové tlaèenie."
+
+msgid "E324: Can't open PostScript output file"
+msgstr "E324: Nedá sa otvori výstupný PostScriptový súbor"
+
+#, c-format
+msgid "E456: Can't open file \"%s\""
+msgstr "E456: Nedá sa otvori súbor \"%s\""
+
+msgid "E456: Can't find PostScript resource file \"prolog.ps\""
+msgstr "E456: Nemožno nájs PostScriptový zdrojový súbor \"prolog.ps\""
+
+msgid "E456: Can't find PostScript resource file \"cidfont.ps\""
+msgstr "E456: Nemožno nájs PostScriptový zdrojový súbor \"cidfont.ps\""
+
+msgid "E456: Can't find PostScript resource file \"%s.ps\""
+msgstr "E456: Nemožno nájs PostScriptový zdrojový súbor \"%s.ps\""
+
+#, c-format
+msgid "E620: Unable to convert to print encoding \"%s\""
+msgstr "E620: Nemožno skonvertova do kódovania na tlaèenie \"%s\""
+
+msgid "Sending to printer..."
+msgstr "Posielam na tlaèiareò..."
+
+msgid "E365: Failed to print PostScript file"
+msgstr "E365: PostScriptový súbor sa nepodarilo vytlaèi"
+
+msgid "Print job sent."
+msgstr "Tlaèová úloha bola odoslaná."
+
+msgid "Add a new database"
+msgstr "Prida novú databázu"
+
+msgid "Query for a pattern"
+msgstr "H¾adanie vzoru"
+
+msgid "Show this message"
+msgstr "Zobrazi túto správu"
+
+msgid "Kill a connection"
+msgstr "Ukonèi spojenie"
+
+msgid "Reinit all connections"
+msgstr "Znovu inicializova všetky spojenia"
+
+msgid "Show connections"
+msgstr "Zobrazi spojenia"
+
+msgid "E560: Usage: cs[cope] %s"
+msgstr "E560: Použitie: cs[cope] %s"
+
+msgid "This cscope command does not support splitting the window.\n"
+msgstr "Tento cscope príkaz nepodporuje rozde¾ovanie okna.\n"
+
+msgid "E562: Usage: cstag <ident>"
+msgstr "E562: Použitie: cstag <odsadenie>"
+
+msgid "E257: cstag: tag not found"
+msgstr "E257: cstag: tag nenájdený"
+
+msgid "E563: stat(%s) error: %d"
+msgstr "E563: stat(%s) chyba: %d"
+
+msgid "E563: stat error"
+msgstr "E563: chyba stat"
+
+msgid "E564: %s is not a directory or a valid cscope database"
+msgstr "E564: %s nie je ani adresárom ani správnou cscope databázou"
+
+#, c-format
+msgid "Added cscope database %s"
+msgstr "Pridaná cscope databáza %s"
+
+msgid "E262: error reading cscope connection %ld"
+msgstr "E262: chyba pri èítaní cscope spojenia %ld"
+
+msgid "E561: unknown cscope search type"
+msgstr "E561: neznámy typ cscope h¾adania"
+
+msgid "E566: Could not create cscope pipes"
+msgstr "E566: Nedajú sa vytvori cscope rúry"
+
+msgid "E622: Could not fork for cscope"
+msgstr "E622: Nemožno spusti proces pre cscope"
+
+msgid "cs_create_connection exec failed"
+msgstr "spustenie cs_create_connection zlyhalo"
+
+msgid "E623: Could not spawn cscope process"
+msgstr "E623: Nedajú sa vytvori cscope rúry"
+
+msgid "cs_create_connection: fdopen for to_fp failed"
+msgstr "cs_create_connection: volanie fdopen pre to_fp zlyhalo"
+
+msgid "cs_create_connection: fdopen for fr_fp failed"
+msgstr "cs_create_connection: volanie fdopen pre fr_fp zlyhalo"
+
+msgid "E567: no cscope connections"
+msgstr "E567: žiadne cscope spojenia"
+
+#, c-format
+msgid "E259: no matches found for cscope query %s of %s"
+msgstr "E259: cscope h¾adanie %s vo vzore %s nenašlo žiadnu zhodu"
+
+#, c-format
+msgid "E469: invalid cscopequickfix flag %c for %c"
+msgstr "E469: chybný cscopequickfix príznak %c pre %c"
+
+msgid "cscope commands:\n"
+msgstr "príkazy cscope:\n"
+
+msgid "%-5s: %-30s (Usage: %s)"
+msgstr "%-5s: %-30s (Použitie: %s)"
+
+msgid "E625: cannot open cscope database: %s"
+msgstr "E625: nemožno otvori cscope databázu: %s"
+
+msgid "E626: cannot get cscope database information"
+msgstr "E626: nemožno získa cscope databázové informácie"
+
+msgid "E568: duplicate cscope database not added"
+msgstr "E568: duplicitná cscope databáza nebola pridaná"
+
+msgid "E569: maximum number of cscope connections reached"
+msgstr "E569: dosiahnutý maximálny poèet cscope spojení"
+
+#, c-format
+msgid "E261: cscope connection %s not found"
+msgstr "E261: cscope spojenie %s nenájdené"
+
+msgid "cscope connection %s closed"
+msgstr "cscope spojenie %s ukonèené"
+
+#. should not reach here
+msgid "E570: fatal error in cs_manage_matches"
+msgstr "E570: vážna chyba v cs_manage_matches"
+
+msgid "Cscope tag: %s"
+msgstr "Cscope tag: %s"
+
+msgid ""
+"\n"
+" # line"
+msgstr ""
+"\n"
+" # riadok"
+
+msgid "filename / context / line\n"
+msgstr "názov súboru/ kontext / riadok\n"
+
+msgid "E609: Cscope error: %s"
+msgstr "E609: Chyba cscope: %s"
+
+msgid "All cscope databases reset"
+msgstr "Všetky cscope databáze resetované"
+
+msgid "no cscope connections\n"
+msgstr "žiadne cscope spojenia\n"
+
+msgid " # pid database name prepend path\n"
+msgstr " # pid názov databázy predpona cesty\n"
+
+msgid ""
+"???: Sorry, this command is disabled, the MzScheme library could not be "
+"loaded."
+msgstr "???: Prepáète, tento príkaz je vypnutý, MzScheme knižnica nemôže by naèítaná."
+
+msgid "invalid expression"
+msgstr "chybný výraz"
+
+msgid "expressions disabled at compile time"
+msgstr "podpora výrazov bola vypnutá pri preklade programu"
+
+msgid "hidden option"
+msgstr "skrytá vo¾ba"
+
+msgid "unknown option"
+msgstr "neznáma vo¾ba"
+
+msgid "window index is out of range"
+msgstr "èíslo okna mimo rozsah"
+
+msgid "couldn't open buffer"
+msgstr "nemožno otvori buffer"
+
+msgid "cannot save undo information"
+msgstr "nedajú sa uloži záložne (opravné) informácie"
+
+msgid "cannot delete line"
+msgstr "nedá sa vymaza riadok"
+
+msgid "cannot replace line"
+msgstr "nedá sa nahradi riadok"
+
+msgid "cannot insert line"
+msgstr "nedá sa vloži riadok"
+
+msgid "string cannot contain newlines"
+msgstr "reazec nesmie obsahova znaky nového riadku"
+
+msgid "Vim error: ~a"
+msgstr "Chyba Vim: ~a"
+
+msgid "Vim error"
+msgstr "Chyba Vim"
+
+msgid "buffer is invalid"
+msgstr "buffer je neplatný"
+
+msgid "window is invalid"
+msgstr "okno je neplatné"
+
+msgid "linenr out of range"
+msgstr "èíslo riadka mimo rozsah"
+
+msgid "not allowed in the Vim sandbox"
+msgstr "nie je dovolené v bezpeènostnej schránke"
+
+msgid ""
+"E263: Sorry, this command is disabled, the Python library could not be "
+"loaded."
+msgstr ""
+"E262: Prepáète, tento príkaz je vypnutý, Python knižnica nemôže by naèítaná."
+
+msgid "E659: Cannot invoke Python recursively"
+msgstr "E659: Python nemôže by spustený rekurzívne"
+
+msgid "can't delete OutputObject attributes"
+msgstr "nedá sa vymaza vlastnos OutputObject"
+
+msgid "softspace must be an integer"
+msgstr "softspace musí by kladné celé èíslo"
+
+msgid "invalid attribute"
+msgstr "chybná vlastnos"
+
+msgid "writelines() requires list of strings"
+msgstr "writelines() vyžaduje zoznam reazcov"
+
+msgid "E264: Python: Error initialising I/O objects"
+msgstr "E264: Python: Chyba pri inicializácii I/O objektov"
+
+msgid "attempt to refer to deleted buffer"
+msgstr "pokus o odkaz na vymazaný buffer"
+
+msgid "line number out of range"
+msgstr "èíslo riadka mimo rozsah"
+
+#, c-format
+msgid "<buffer object (deleted) at %8lX>"
+msgstr "<objekt bufferu (vymazaný) na %8lX>"
+
+msgid "invalid mark name"
+msgstr "chybné meno znaèky"
+
+msgid "no such buffer"
+msgstr "žiadny taký buffer"
+
+msgid "attempt to refer to deleted window"
+msgstr "pokus o odkaz na vymazané okno"
+
+msgid "readonly attribute"
+msgstr "vlastnos iba pre èítanie"
+
+msgid "cursor position outside buffer"
+msgstr "umiestnenie kurzoru mimo buffer"
+
+#, c-format
+msgid "<window object (deleted) at %.8lX>"
+msgstr "<objekt okna (vymazaný) na %.8lX>"
+
+#, c-format
+msgid "<window object (unknown) at %.8lX>"
+msgstr "<objekt okna (neznámy) na %.8lX>"
+
+#, c-format
+msgid "<window %d>"
+msgstr "<okno %d>"
+
+msgid "no such window"
+msgstr "žiadne také okno"
+
+msgid ""
+"E266: Sorry, this command is disabled, the Ruby library could not be loaded."
+msgstr ""
+"E266: Prepáète, tento príkaz je vypnutý, Ruby knižnica nemôže by naèítaná."
+
+#, c-format
+msgid "E273: unknown longjmp status %d"
+msgstr "E273: Neznámy 'longjmp' stav %d"
+
+msgid "Toggle implementation/definition"
+msgstr "Prepnú implementáciu/definíciu"
+
+msgid "Show base class of"
+msgstr "Ukáza základnú triedu"
+
+msgid "Show overridden member function"
+msgstr "Ukáza preaženú èlenskú funkciu"
+
+msgid "Retrieve from file"
+msgstr "Obnovi zo súboru"
+
+msgid "Retrieve from project"
+msgstr "Obnovi z projektu"
+
+msgid "Retrieve from all projects"
+msgstr "Obnovi zo všetkých projektov"
+
+msgid "Retrieve"
+msgstr "Obnovi"
+
+msgid "Show source of"
+msgstr "Ukáza zdroj"
+
+msgid "Find symbol"
+msgstr "Nájs znak"
+
+msgid "Browse class"
+msgstr "Prezrie triedu"
+
+msgid "Show class in hierarchy"
+msgstr "Ukáza triedu v hierarchii"
+
+msgid "Show class in restricted hierarchy"
+msgstr "Ukáza triedu v obmedzenej hierarchii"
+
+msgid "Xref refers to"
+msgstr "Xref odkazuje na"
+
+msgid "Xref referred by"
+msgstr "Xref odkázaný z"
+
+msgid "Xref has a"
+msgstr "Xref má"
+
+msgid "Xref used by"
+msgstr "Xref použitý"
+
+msgid "Show docu of"
+msgstr "Ukáza dokumentáciu"
+
+msgid "Generate docu for"
+msgstr "Vytvori dokumentáciu pre"
+
+msgid ""
+"Cannot connect to SNiFF+. Check environment (sniffemacs must be found in "
+"$PATH).\n"
+msgstr ""
+"Zlyhalo pripojenie na SNiFF+, Preverte prostredie (sniffemacs sa musí "
+"nachádza v $PATH).\n"
+
+msgid "E274: Sniff: Error during read. Disconnected"
+msgstr "E274: Sniff: Chyba poèas èítania. Odpojené"
+
+msgid "SNiFF+ is currently "
+msgstr "SNiFF+ je aktuálne "
+
+msgid "not "
+msgstr "ne"
+
+msgid "connected"
+msgstr "pripojený"
+
+#, c-format
+msgid "E275: Unknown SNiFF+ request: %s"
+msgstr "E275: Neznáma SNiFF+ požiadavka: %s"
+
+msgid "E276: Error connecting to SNiFF+"
+msgstr "E276: Chyba pripojenia na SNiFF+"
+
+msgid "E278: SNiFF+ not connected"
+msgstr "E278: SNiFF+ nie je pripojený"
+
+msgid "E279: Not a SNiFF+ buffer"
+msgstr "E279: Nie je SNiFF+ bufferom"
+
+msgid "Sniff: Error during write. Disconnected"
+msgstr "Sniff: Chyba zápisu. Odpojené"
+
+msgid "invalid buffer number"
+msgstr "chybné èíslo bufferu"
+
+msgid "not implemented yet"
+msgstr "nie je ešte podporované"
+
+#. ???
+msgid "cannot set line(s)"
+msgstr "nedajú sa nastavi riadky"
+
+msgid "mark not set"
+msgstr "znaèka nie je nastavená"
+
+#, c-format
+msgid "row %d column %d"
+msgstr "riadok %d ståpec %d"
+
+msgid "cannot insert/append line"
+msgstr "nedá sa vloži/pripoji riadok"
+
+msgid "unknown flag: "
+msgstr "neznámy príznak: "
+
+msgid "unknown vimOption"
+msgstr "neznáma vo¾ba (vimOption)"
+
+msgid "keyboard interrupt"
+msgstr "prerušenie z klávesnice"
+
+msgid "vim error"
+msgstr "chyba Vim"
+
+msgid "cannot create buffer/window command: object is being deleted"
+msgstr "nedá sa vytvori príkaz bufferu/okna: objekt bude vymazaný"
+
+msgid ""
+"cannot register callback command: buffer/window is already being deleted"
+msgstr ""
+"nedá sa zaregistrova príkaz spätného volania: buffer/okno už bol vymazaný"
+
+#. This should never happen. Famous last word?
+msgid ""
+"E280: TCL FATAL ERROR: reflist corrupt!? Please report this to vim-dev@vim."
+"org"
+msgstr ""
+"E280: TCL FATAL ERROR: reflist poškodený!? Oznámte, prosím, túto chybu na "
+"vim-dev@vim.org"
+
+msgid "cannot register callback command: buffer/window reference not found"
+msgstr ""
+"nedá sa zaregistrova príkaz spätného volania: odkaz na buffer/okno nenájdený"
+
+msgid ""
+"E571: Sorry, this command is disabled: the Tcl library could not be loaded."
+msgstr ""
+"E571: Prepáète, tento príkaz je vypnutý, Tcl knižnica nemôže by naèítaná."
+
+msgid ""
+"E281: TCL ERROR: exit code is not int!? Please report this to vim-dev@vim.org"
+msgstr ""
+"E281: TCL CHYBA: návratový kód nie je celé èíslo!? Oznámte, prosím, túto "
+"chybu na vim-dev@vim.org"
+
+#, c-format
+msgid "E572: exit code %d"
+msgstr "E572: návratový kód %d"
+
+msgid "cannot get line"
+msgstr "nedá sa preèíta riadok"
+
+msgid "Unable to register a command server name"
+msgstr "Nemôžem zaregistrova meno príkazového servra"
+
+msgid "E248: Failed to send command to the destination program"
+msgstr "E248: Chyba poèas prenosu príkazu do cie¾ového programu"
+
+msgid "E573: Invalid server id used: %s"
+msgstr "E573: Použíté chybné èíslo servera: %s"
+
+msgid "E251: VIM instance registry property is badly formed. Deleted!"
+msgstr "E251: VIM registrová vlastnos je zle formátovaná. Vymazané!"
+
+msgid "Unknown option argument"
+msgstr "Neznámy parameter vo¾by"
+
+msgid "Too many edit arguments"
+msgstr "Príliš mnoho upravovacích argumentov"
+
+msgid "Argument missing after"
+msgstr "Chýba argument po"
+
+msgid "Garbage after option argument"
+msgstr "Chyby za parametrom vo¾by"
+
+msgid "Too many \"+command\", \"-c command\" or \"--cmd command\" arguments"
+msgstr "Príliš mnoho \"+príkaz\", \"-c príkaz\" alebo \"--cmd príkaz\" argumentov"
+
+msgid "Invalid argument for"
+msgstr "Chybný argument pre"
+
+#, c-format
+msgid "%d files to edit\n"
+msgstr "%d súborov pre úpravu\n"
+
+msgid "This Vim was not compiled with the diff feature."
+msgstr "Tento Vim nebol kompilovaný s porovnávacími funkciami."
+
+msgid "Attempt to open script file again: \""
+msgstr "Pokus o opätovné otvorenie skriptu: \""
+
+msgid "Cannot open for reading: \""
+msgstr "Nedá sa otvori pre zápis: \""
+
+msgid "Cannot open for script output: \""
+msgstr "Nedá sa otvori pre výstup skriptu: \""
+
+msgid "Vim: Error: Failure to start gvim from NetBeans\n"
+msgstr "Vim: Chyba: Chyba spúšania gvim pre NetBeans\n"
+
+msgid "Vim: Warning: Output is not to a terminal\n"
+msgstr "Vim: Varovanie: Výstup nesmeruje na terminál\n"
+
+msgid "Vim: Warning: Input is not from a terminal\n"
+msgstr "Vim: Varovanie: Vstup nepochádza z terminálu\n"
+
+#. just in case..
+msgid "pre-vimrc command line"
+msgstr "pre-vimrc príkazový riadok"
+
+#, c-format
+msgid "E282: Cannot read from \"%s\""
+msgstr "E282: Nedá sa èíta z \"%s\""
+
+msgid ""
+"\n"
+"More info with: \"vim -h\"\n"
+msgstr ""
+"\n"
+"Podrobnejšie informácie získáte pomocou \"vim -h\"\n"
+
+msgid "[file ..] edit specified file(s)"
+msgstr "[súbor ..] .. upravi súbor(y)"
+
+msgid "- read text from stdin"
+msgstr "- èíta text z štandardného vstupu"
+
+msgid "-t tag edit file where tag is defined"
+msgstr "-t tag upravi súbor na mieste definície tagu"
+
+msgid "-q [errorfile] edit file with first error"
+msgstr "-q [chybový súbor] upravi súbor na mieste výskytu prvej chyby"
+
+msgid ""
+"\n"
+"\n"
+"Usage:"
+msgstr ""
+"\n"
+"\n"
+"použitie:"
+
+msgid " vim [arguments] "
+msgstr "vim [argumenty] "
+
+msgid ""
+"\n"
+" or:"
+msgstr ""
+"\n"
+" alebo:"
+
+#. TODO: is translation correct?
+msgid "where case is ignored prepend / to make flag upper case"
+msgstr "v prípade, že je ignorovaná ve¾kos písmen, použite znak '/' na zaèiatku, aby mal príznak význam ve¾kého písmena"
+
+msgid ""
+"\n"
+"\n"
+"Arguments:\n"
+msgstr ""
+"\n"
+"\n"
+"Argumenty:\n"
+
+msgid "--\t\t\tOnly file names after this"
+msgstr "--\t\t\tMôžu nasledova iba názvy súborov"
+
+msgid "--literal\t\tDon't expand wildcards"
+msgstr "--literal\t\tNexpandova žolíkové znaky (wildcards)"
+
+msgid "-register\t\tRegister this gvim for OLE"
+msgstr "-register\t\tPrihlási gvim na OLE"
+
+msgid "-unregister\t\tUnregister gvim for OLE"
+msgstr "-register\t\tOdhlási gvim z OLE"
+
+msgid "-g\t\t\tRun using GUI (like \"gvim\")"
+msgstr "-g\t\t\tSpusti v grafickom (GUI) móde (rovnaké ako \"gvim\")"
+
+msgid "-f or --nofork\tForeground: Don't fork when starting GUI"
+msgstr ""
+"-f alebo --nofork\tPopredie: Pri spustení grafického (GUI) módu sa nepresunie do pozadia"
+
+msgid "-v\t\t\tVi mode (like \"vi\")"
+msgstr "-v\t\t\tVi mód (rovnaké ako \"vi\")"
+
+msgid "-e\t\t\tEx mode (like \"ex\")"
+msgstr "-e\t\t\tEx mód (rovnaké ako \"ex\")"
+
+msgid "-s\t\t\tSilent (batch) mode (only for \"ex\")"
+msgstr "-s\t\t\tTichý (dávkový) mód (iba pre \"ex\")"
+
+msgid "-d\t\t\tDiff mode (like \"vimdiff\")"
+msgstr "-d\t\t\tPorovnávací mód (rovnaké ako \"vimdiff\")"
+
+msgid "-y\t\t\tEasy mode (like \"evim\", modeless)"
+msgstr "-y\t\t\tJednoduchý mód (rovnaké ako \"evim\", bezmódový)"
+
+msgid "-R\t\t\tReadonly mode (like \"view\")"
+msgstr "-R\t\t\tMód iba pre èítanie (ako \"view\")"
+
+msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
+msgstr "-Z\t\t\tObmedzený mód (rovnaké ako \"rvim\")"
+
+msgid "-m\t\t\tModifications (writing files) not allowed"
+msgstr "-m\t\t\tZmeny (ukladanie súborov) zakázané"
+
+msgid "-M\t\t\tModifications in text not allowed"
+msgstr "-M\t\t\tZmeny v texte zakázané"
+
+msgid "-b\t\t\tBinary mode"
+msgstr "-b\t\t\tBinárny mód"
+
+msgid "-l\t\t\tLisp mode"
+msgstr "-l\t\t\tLisp mód"
+
+msgid "-C\t\t\tCompatible with Vi: 'compatible'"
+msgstr "-C\t\t\tKompatabilný s Vi: 'compatible'"
+
+msgid "-N\t\t\tNot fully Vi compatible: 'nocompatible'"
+msgstr "-N\t\t\tKompatibilita s Vi vypnutá: 'nocompatible'"
+
+msgid "-V[N]\t\tVerbose level"
+msgstr "-V[N]\t\tÚroveò výpisu hlášok"
+
+msgid "-D\t\t\tDebugging mode"
+msgstr "-D\t\t\tLadiaci mód"
+
+msgid "-n\t\t\tNo swap file, use memory only"
+msgstr "-n\t\t\tNevytvára odkladací súbor, používa iba pamä"
+
+msgid "-r\t\t\tList swap files and exit"
+msgstr "-r\t\t\tVypíš zoznam odkladacích súborov a skonèi"
+
+msgid "-r (with file name)\tRecover crashed session"
+msgstr "-r (s názvom súboru)\tObnoví prerušené sedenie"
+
+msgid "-L\t\t\tSame as -r"
+msgstr "-L\t\t\tRovnaké ako -r"
+
+msgid "-f\t\t\tDon't use newcli to open window"
+msgstr "-f\t\t\tNebude používa newcli pre otvorenie okna"
+
+msgid "-dev <device>\t\tUse <device> for I/O"
+msgstr "-dev <zariadenie>\t\tPouži <zariadenie> pre I/O"
+
+msgid "-A\t\t\tStart in Arabic mode"
+msgstr "-A\t\t\tspusti v Arabic móde"
+
+msgid "-H\t\t\tStart in Hebrew mode"
+msgstr "-H\t\t\tspusti v hebrejskom móde"
+
+msgid "-F\t\t\tStart in Farsi mode"
+msgstr "-F\t\t\tspusti vo Farsi móde"
+
+msgid "-T <terminal>\tSet terminal type to <terminal>"
+msgstr "-T <terminál>\tNastaví typ terminálu na <terminál>"
+
+msgid "-u <vimrc>\t\tUse <vimrc> instead of any .vimrc"
+msgstr "-u <vimrc>\t\tPoužije <vimrc> namiesto akéhoko¾vek .vimrc"
+
+msgid "-U <gvimrc>\t\tUse <gvimrc> instead of any .gvimrc"
+msgstr "-U <gvimrc>\t\tPoužije <gvimrc> namiesto akéhoko¾vek .gvimrc"
+
+msgid "--noplugin\t\tDon't load plugin scripts"
+msgstr "--noplugin\t\tNenahrá zásuvné moduly(plugin skripty)"
+
+msgid "-o[N]\t\tOpen N windows (default: one for each file)"
+msgstr "-o[N]\t\tOtvorí N okien (implicitne jedno pre každý súbor)"
+
+msgid "-O[N]\t\tLike -o but split vertically"
+msgstr "-O[N]\t\tAko -o ale rozdelí vertikálne"
+
+msgid "+\t\t\tStart at end of file"
+msgstr "+\t\t\tNastaví kurzor na koniec súboru"
+
+msgid "+<lnum>\t\tStart at line <lnum>"
+msgstr "+<riadok>\t\tNastaví kurzor na <riadok>"
+
+msgid "--cmd <command>\tExecute <command> before loading any vimrc file"
+msgstr "--cmd <príkaz>\t\tVykoná <príkaz> pred nahratím vimrc súboru"
+
+msgid "-c <command>\t\tExecute <command> after loading the first file"
+msgstr "-c <príkaz>\t\tPo nahratí prvého súboru vykoná <príkaz>"
+
+msgid "-S <session>\t\tSource file <session> after loading the first file"
+msgstr ""
+"-S <sedenie>\t\tPo nahratí prvého súboru vykoná príkazy v súbore <sedenie>"
+
+msgid "-s <scriptin>\tRead Normal mode commands from file <scriptin>"
+msgstr "-s <skript>\t\tNaèíta príkazy normálneho módu zo <skriptu>"
+
+msgid "-w <scriptout>\tAppend all typed commands to file <scriptout>"
+msgstr "-w <skript>\t\tPripojí všetky napísané príkazy do súboru <skript>"
+
+msgid "-W <scriptout>\tWrite all typed commands to file <scriptout>"
+msgstr "-W <skript>\t\tUloží všetky napísané príkazy do súboru <skript>"
+
+msgid "-x\t\t\tEdit encrypted files"
+msgstr "-x\t\t\tÚprava zašifrovaných súborov"
+
+msgid "-display <display>\tConnect vim to this particular X-server"
+msgstr "-display <displej>\tPripojí vim na príslušný X-server"
+
+msgid "-X\t\t\tDo not connect to X server"
+msgstr "-X\t\t\tNepripojí sa k X serveru"
+
+msgid "--remote <files>\tEdit <files> in a Vim server if possible"
+msgstr "--remote <súbory>\tUpravi <súbory> na Vim servri ak je to možné"
+
+msgid "--remote-silent <files> Same, don't complain if there is no server"
+msgstr "--remote-silent <súbory>\tTo isté, ale nesažuj si, ak neexistuje server"
+
+msgid ""
+"--remote-wait <files> As --remote but wait for files to have been edited"
+msgstr ""
+"--remote-wait <súbory>\tAko --remote ale èaká na súbory pre ukonèenie úprav"
+
+msgid ""
+"--remote-wait-silent <files> Same, don't complain if there is no server"
+msgstr "--remote-wait-silent <súbory>\tTo isté, ale nesažuj si, ak neexistuje server"
+
+msgid "--remote-send <keys>\tSend <keys> to a Vim server and exit"
+msgstr "--remote-send <vo¾by>\tOdošle <vo¾by> na Vim server a skonèí"
+
+msgid "--remote-expr <expr>\tEvaluate <expr> in a Vim server and print result"
+msgstr "--remote-expr <výraz>\tSpusti <výraz> na servri a vytlaèí výsledok"
+
+msgid "--serverlist\t\tList available Vim server names and exit"
+msgstr "--serverlist\t\tVypíše zoznam mien dostupných Vim servrov a skonèí"
+
+msgid "--servername <name>\tSend to/become the Vim server <name>"
+msgstr "--servername <názov>\tOdošle na Vim server <názov>"
+
+msgid "-i <viminfo>\t\tUse <viminfo> instead of .viminfo"
+msgstr "-i <viminfo>\t\tPoužije <viminfo> namiesto akéhoko¾vek .viminfo"
+
+msgid "-h or --help\tPrint Help (this message) and exit"
+msgstr "-h alebo --help\tVypíše túto nápovedu a skonèí"
+
+msgid "--version\t\tPrint version information and exit"
+msgstr "--version\t\tVypíše informácie o verzii a skonèí"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Motif version):\n"
+msgstr ""
+"\n"
+"Argumenty dostupné pre gvim (Motif verzia):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (neXtaw version):\n"
+msgstr ""
+"\n"
+"Argumenty dostupné pre gvim (neXtaw verzia):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Athena version):\n"
+msgstr ""
+"\n"
+"Argumenty dostupné pre gvim (Athena verzia):\n"
+
+msgid "-display <display>\tRun vim on <display>"
+msgstr "-display <displej>\tSpustí vim na <displej>"
+
+msgid "-iconic\t\tStart vim iconified"
+msgstr "-iconic\t\tSpustí vim minimalizované"
+
+msgid "-name <name>\t\tUse resource as if vim was <name>"
+msgstr "-name <názov>\t\tPoužije resource ako by vim mal <názov>"
+
+msgid "\t\t\t (Unimplemented)\n"
+msgstr "\t\t\t (nie je implementované)\n"
+
+msgid "-background <color>\tUse <color> for the background (also: -bg)"
+msgstr "-background <farba>\tNastaví sa <farba> pozadia (tiež -bg)"
+
+msgid "-foreground <color>\tUse <color> for normal text (also: -fg)"
+msgstr "-foreground <farba>\tNastaví sa <farba> popredia (tiež -fg)"
+
+msgid "-font <font>\t\tUse <font> for normal text (also: -fn)"
+msgstr "-font <písmo>\t\tNastaví <písmo> normálneho textu (tiež -fn)"
+
+msgid "-boldfont <font>\tUse <font> for bold text"
+msgstr "-boldfont <písmo>\tNastaví <písmo> pre zvýraznený text"
+
+msgid "-italicfont <font>\tUse <font> for italic text"
+msgstr "-italicfont <písmo>\tNastaví <písmo> pre kurzívu"
+
+msgid "-geometry <geom>\tUse <geom> for initial geometry (also: -geom)"
+msgstr "-geometry <geometrie>\tNastaví sa <geometria> (tiež -geom)"
+
+msgid "-borderwidth <width>\tUse a border width of <width> (also: -bw)"
+msgstr "-borderwidth <šírka>\tNastaví <šírku> okrajov (tiež -bw)"
+
+msgid "-scrollbarwidth <width> Use a scrollbar width of <width> (also: -sw)"
+msgstr "-scrollbarwidth <šírka> Nastaví <šírku> posuvnej lišty (tiež -sw)"
+
+msgid "-menuheight <height>\tUse a menu bar height of <height> (also: -mh)"
+msgstr "-menuheight <výška>\tNastaví <výšku> ponuky (tiež -mh)"
+
+msgid "-reverse\t\tUse reverse video (also: -rv)"
+msgstr "-reverse\t\tPoužije reverzné farby (tiež -rv)"
+
+msgid "+reverse\t\tDon't use reverse video (also: +rv)"
+msgstr "+reverse\t\tNepoužije reverzné farby (tiež +rv)"
+
+# TODO: howto translate 'resource' in this case?
+msgid "-xrm <resource>\tSet the specified resource"
+msgstr "-xrm <resource>\tNastaví zadaný <resource>"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (RISC OS version):\n"
+msgstr ""
+"\n"
+"Argumenty dostupné pre gvim (RISC OS verzia):\n"
+
+msgid "--columns <number>\tInitial width of window in columns"
+msgstr "--columns <poèet>\tPoèiatoèná šírka okna v ståpcoch"
+
+msgid "--rows <number>\tInitial height of window in rows"
+msgstr "--rows <poèet>\tPoèiatoèná výška okna v riadkoch"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (GTK+ version):\n"
+msgstr ""
+"\n"
+"Argumenty dostupné pre gvim (GTK+ verzia):\n"
+
+msgid "-display <display>\tRun vim on <display> (also: --display)"
+msgstr "-display <displej>\tSpustí vim na <displej> (tiež --display)"
+
+msgid "--role <role>\tSet a unique role to identify the main window"
+msgstr "-role <rola>\tNastaví unikátnu rolu pre identifikáciu hlavného okna"
+
+msgid "--socketid <xid>\tOpen Vim inside another GTK widget"
+msgstr "--socketid <xid>\tOtvorí Vim vnútri iného GTK programu."
+
+msgid ""
+"\n"
+"Arguments recognised by kvim (KDE version):\n"
+msgstr ""
+"\n"
+"Argumenty dostupné pre kvim (KDE verzia):\n"
+
+msgid "-black\t\tUse reverse video"
+msgstr "-black\t\tPoužije reverzné farby"
+
+msgid "-tip\t\t\tDisplay the tip dialog on startup"
+msgstr "-tip\t\t\tZobraz tip pri štarte"
+
+msgid "-notip\t\tDisable the tip dialog"
+msgstr "-notip\t\tNezobrazuj tip pri štarte"
+
+msgid "--display <display>\tRun vim on <display>"
+msgstr "-display <displej>\tSpustí vim na <displej>"
+
+msgid "-P <parent title>\tOpen Vim inside parent application"
+msgstr "-P <titulok rodièa>\tOtvor Vim vnútri materskej aplikácie"
+
+msgid "No display"
+msgstr "Bez grafického rozhrania"
+
+#. Failed to send, abort.
+msgid ": Send failed.\n"
+msgstr ": Odoslanie zlyhalo.\n"
+
+#. Let vim start normally.
+msgid ": Send failed. Trying to execute locally\n"
+msgstr ": Odoslanie zlyhalo. Pokúšam sa spusti lokálne\n"
+
+#, c-format
+msgid "%d of %d edited"
+msgstr "%d upravených súborov z %d"
+
+msgid "No display: Send expression failed.\n"
+msgstr "Žiaden graf. mód: Odoslanie výrazu zlyhalo.\n"
+
+msgid ": Send expression failed.\n"
+msgstr ": Odoslanie výrazu zlyhalo.\n"
+
+msgid "No marks set"
+msgstr "Nie sú nastavené žiadne znaèky"
+
+#, c-format
+msgid "E283: No marks matching \"%s\""
+msgstr "E283:\"%s\" nevyhovujú žiadne znaèky"
+
+#. Highlight title
+msgid ""
+"\n"
+"mark line col file/text"
+msgstr ""
+"\n"
+"znaèka riadok ståpec súbor/text"
+
+#. Highlight title
+msgid ""
+"\n"
+" jump line col file/text"
+msgstr ""
+"\n"
+" skok riadok ståpec súbor/text"
+
+#. Highlight title
+msgid ""
+"\n"
+"change line col text"
+msgstr ""
+"\n"
+"znaèka riadok ståpec text"
+
+#, c-format
+msgid ""
+"\n"
+"# File marks:\n"
+msgstr ""
+"\n"
+"# Súborové znaèky:\n"
+
+#. Write the jumplist with -'
+#, c-format
+msgid ""
+"\n"
+"# Jumplist (newest first):\n"
+msgstr ""
+"\n"
+"# Zoznam skokov (zaèínajúci najnovšou položkou):\n"
+
+#, c-format
+msgid ""
+"\n"
+"# History of marks within files (newest to oldest):\n"
+msgstr ""
+"\n"
+"# História znaèiek v súboroch (zaèínajúci najnovšou položkou):\n"
+
+msgid "Missing '>'"
+msgstr "Chýba '>'"
+
+msgid "E543: Not a valid codepage"
+msgstr "E543: Chybná kódová stránka"
+
+msgid "E284: Cannot set IC values"
+msgstr "E284: Nedajú sa nastavi IC hodnoty"
+
+msgid "E285: Failed to create input context"
+msgstr "E285: Nepodarilo sa vytvori vstupný kontext"
+
+msgid "E286: Failed to open input method"
+msgstr "E286: Nepodarilo sa otvori vstupnú metódu"
+
+msgid "E287: Warning: Could not set destroy callback to IM"
+msgstr "E287: Varovanie: likvidaèné spätné volanie sa nedá nastavi na IM"
+
+msgid "E288: input method doesn't support any style"
+msgstr "E288: vstupná metóda nepodporuje žiadny štýl"
+
+msgid "E289: input method doesn't support my preedit type"
+msgstr "E289: vstupná metóda nepodporuje môj 'preedit' typ"
+
+msgid "E290: over-the-spot style requires fontset"
+msgstr "E290: Nadbodový štýl vyžaduje sadu fontov (fontset)"
+
+msgid "E291: Your GTK+ is older than 1.2.3. Status area disabled"
+msgstr "E291: Máte GTK+ verziu staršiu než 1.2.3. Stavová plocha vypnutá."
+
+msgid "E292: Input Method Server is not running"
+msgstr "E292: Server vstupných metód nebeží"
+
+msgid "E293: block was not locked"
+msgstr "E293: blok nebol zamknutý"
+
+msgid "E294: Seek error in swap file read"
+msgstr "E294: Chyba posunu pri èítaní odkladacieho súboru"
+
+msgid "E295: Read error in swap file"
+msgstr "E295: Chyba pri èítaní odkladacieho súboru"
+
+msgid "E296: Seek error in swap file write"
+msgstr "E296: Chyba posunu pri ukladaní do odkladacieho súboru"
+
+msgid "E297: Write error in swap file"
+msgstr "E297: Chyba pri ukladaní do odkladacieho súboru"
+
+msgid "E300: Swap file already exists (symlink attack?)"
+msgstr "E300: Odkladací súbor už existuje (symlink útok?)"
+
+msgid "E298: Didn't get block nr 0?"
+msgstr "E298: Nedá sa získa blok 0?"
+
+msgid "E298: Didn't get block nr 1?"
+msgstr "E298: Nedá sa získa blok 1?"
+
+msgid "E298: Didn't get block nr 2?"
+msgstr "E298: Nedá sa získa blok 2?"
+
+#. could not (re)open the swap file, what can we do????
+msgid "E301: Oops, lost the swap file!!!"
+msgstr "E301: Ups, odkladací súbor bol stratený!!!"
+
+msgid "E302: Could not rename swap file"
+msgstr "E302: Nedá sa premenova odkladací súbor"
+
+#, c-format
+msgid "E303: Unable to open swap file for \"%s\", recovery impossible"
+msgstr "E303: Nedá sa otvori odkladací súbor pre \"%s\", oprava nemožná"
+
+msgid "E304: ml_upd_block0(): Didn't get block 0??"
+msgstr "E304: ml_upd_block0(): nedá sa získa blok 0??"
+
+#, c-format
+msgid "E305: No swap file found for %s"
+msgstr "E305: Odkladací súbor pre %s nebol nájdený"
+
+msgid "Enter number of swap file to use (0 to quit): "
+msgstr ""
+"Zadajte èíslo odkladacieho súboru, ktorý sa má použit (0 pre ukonèenie): "
+
+#, c-format
+msgid "E306: Cannot open %s"
+msgstr "E306: Nedá sa otvori %s"
+
+msgid "Unable to read block 0 from "
+msgstr "Nedá sa èíta blok 0 z "
+
+msgid ""
+"\n"
+"Maybe no changes were made or Vim did not update the swap file."
+msgstr ""
+"\n"
+"Možno nedošlo k žiadnym zmenám, alebo Vim neaktualizoval odkladací súbor."
+
+msgid " cannot be used with this version of Vim.\n"
+msgstr " nedá sa použi s touto verziou Vim.\n"
+
+msgid "Use Vim version 3.0.\n"
+msgstr "Použite Vim verziu 3.0.\n"
+
+#, c-format
+msgid "E307: %s does not look like a Vim swap file"
+msgstr "E307: %s sa nezdá by odkladacím súborom Vim"
+
+msgid " cannot be used on this computer.\n"
+msgstr " nedá sa použí na tomto poèítaèi.\n"
+
+msgid "The file was created on "
+msgstr "Súbor bol vytvorený "
+
+msgid ""
+",\n"
+"or the file has been damaged."
+msgstr ""
+",\n"
+"alebo bol súbor poškodený."
+
+#, c-format
+msgid "Using swap file \"%s\""
+msgstr "Používam odkladací súbor \"%s\""
+
+#, c-format
+msgid "Original file \"%s\""
+msgstr "Pôvodný súbor \"%s\""
+
+msgid "E308: Warning: Original file may have been changed"
+msgstr "E308: Varovanie: Pôvodný súbor mohol by zmenený"
+
+#, c-format
+msgid "E309: Unable to read block 1 from %s"
+msgstr "E309: Nedá sa èíta blok 1 z %s"
+
+msgid "???MANY LINES MISSING"
+msgstr "???CHÝBA MNOHO RIADKOV"
+
+msgid "???LINE COUNT WRONG"
+msgstr "???CHYBNÝ POÈET RIADKOV"
+
+msgid "???EMPTY BLOCK"
+msgstr "???PRÁZDNY BLOK"
+
+msgid "???LINES MISSING"
+msgstr "???CHÝBAJÚCE RIADKY"
+
+#, c-format
+msgid "E310: Block 1 ID wrong (%s not a .swp file?)"
+msgstr "E310: ID bloku 1 je chybné (je %s odkladacím súborom?)"
+
+msgid "???BLOCK MISSING"
+msgstr "???CHÝBA BLOK"
+
+msgid "??? from here until ???END lines may be messed up"
+msgstr "od ??? po ???END môžu by riadky pomiešané"
+
+msgid "??? from here until ???END lines may have been inserted/deleted"
+msgstr "od ??? po ???END môžu by riadky vložené/vymazané"
+
+msgid "???END"
+msgstr "???KONIEC"
+
+msgid "E311: Recovery Interrupted"
+msgstr "E311: Obnova prerušená"
+
+msgid ""
+"E312: Errors detected while recovering; look for lines starting with ???"
+msgstr ""
+"E312: V priebehu obnovy došlo k chybám; skontrolujte riadky zaèínajúce na ???"
+
+msgid "See \":help E312\" for more information."
+msgstr "Pozrite \":help E312\" pre ïalšie informácie"
+
+msgid "Recovery completed. You should check if everything is OK."
+msgstr "Obnova dokonèená. Skontrolujte, èi je všetko v poriadku."
+
+msgid ""
+"\n"
+"(You might want to write out this file under another name\n"
+msgstr ""
+"\n"
+"(Zvážte uloženie tohoto súboru pod iným menom\n"
+
+msgid "and run diff with the original file to check for changes)\n"
+msgstr "a pomocou programu diff zistite zmeny oproti pôvodnému súboru)\n"
+
+msgid ""
+"Delete the .swp file afterwards.\n"
+"\n"
+msgstr "Potom vymažte odkladací súbor s príponou .swp.\n"
+"\n"
+
+#. use msg() to start the scrolling properly
+msgid "Swap files found:"
+msgstr "Nájdené odkladacie súbory:"
+
+msgid " In current directory:\n"
+msgstr " V aktuálnom adresári:\n"
+
+msgid " Using specified name:\n"
+msgstr " So zadaným menom:\n"
+
+msgid " In directory "
+msgstr " V adresári "
+
+msgid " -- none --\n"
+msgstr " -- žiadne --\n"
+
+msgid " owned by: "
+msgstr " vlastník: "
+
+msgid " dated: "
+msgstr " dátum vytvorenia: "
+
+msgid " dated: "
+msgstr " dátum vytvorenia: "
+
+msgid " [from Vim version 3.0]"
+msgstr " [od Vim verzie 3.0]"
+
+msgid " [does not look like a Vim swap file]"
+msgstr " [nevyzerá ako odkladací súbor Vim]"
+
+msgid " file name: "
+msgstr " názov súboru: "
+
+msgid ""
+"\n"
+" modified: "
+msgstr ""
+"\n"
+" zmenený: "
+
+msgid "YES"
+msgstr "ÁNO"
+
+msgid "no"
+msgstr "nie"
+
+msgid ""
+"\n"
+" user name: "
+msgstr ""
+"\n"
+" užívate¾ské meno: "
+
+msgid " host name: "
+msgstr " názov poèítaèa: "
+
+msgid ""
+"\n"
+" host name: "
+msgstr ""
+"\n"
+" názov poèítaèa: "
+
+msgid ""
+"\n"
+" process ID: "
+msgstr ""
+"\n"
+" ID procesu : "
+
+msgid " (still running)"
+msgstr " (stále beží)"
+
+msgid ""
+"\n"
+" [not usable with this version of Vim]"
+msgstr ""
+"\n"
+" [nepoužite¾né s touto verziou Vim]"
+
+msgid ""
+"\n"
+" [not usable on this computer]"
+msgstr ""
+"\n"
+" [nepoužitelné na tomto poèítaèi]"
+
+msgid " [cannot be read]"
+msgstr " [nedá sa preèíta]"
+
+msgid " [cannot be opened]"
+msgstr " [nedá sa otvori]"
+
+msgid "E313: Cannot preserve, there is no swap file"
+msgstr "E313: Nedá sa zachova - odkladací súbor neexistuje"
+
+msgid "File preserved"
+msgstr "Súbor zachovaný"
+
+msgid "E314: Preserve failed"
+msgstr "E314: Uchovanie sa nepodarilo"
+
+#, c-format
+msgid "E315: ml_get: invalid lnum: %ld"
+msgstr "E315: ml_get: chybné èíslo riadku: %ld"
+
+#, c-format
+msgid "E316: ml_get: cannot find line %ld"
+msgstr "E316: ml_get: nedá sa nájs riadok %ld"
+
+msgid "E317: pointer block id wrong 3"
+msgstr "E317: chybné èíslo ukazovate¾a na blok 3"
+
+msgid "stack_idx should be 0"
+msgstr "stack_idx by mal ma hodnotu 3"
+
+msgid "E318: Updated too many blocks?"
+msgstr "E318: Aktualizovaných príliš ve¾a blokov?"
+
+msgid "E317: pointer block id wrong 4"
+msgstr "E317: chybné èíslo ukazovate¾a na blok 4"
+
+msgid "deleted block 1?"
+msgstr "vymazaný blok 1?"
+
+#, c-format
+msgid "E320: Cannot find line %ld"
+msgstr "E320: Nedá sa nájs riadok %ld"
+
+msgid "E317: pointer block id wrong"
+msgstr "E317: chybné èíslo ukazovate¾a na blok"
+
+msgid "pe_line_count is zero"
+msgstr "pe_line_count má nulovú hodnotu"
+
+#, c-format
+msgid "E322: line number out of range: %ld past the end"
+msgstr "E322: èíslo riadku je mimo rozsah: %ld (za koncom)"
+
+#, c-format
+msgid "E323: line count wrong in block %ld"
+msgstr "E323: chybný poèet riadkov v bloku %ld"
+
+msgid "Stack size increases"
+msgstr "Nárast ve¾kosti zásobníku"
+
+msgid "E317: pointer block id wrong 2"
+msgstr "E317: chybný èíslo ukazovate¾a na blok 2"
+
+msgid "E325: ATTENTION"
+msgstr "E325: POZOR"
+
+msgid ""
+"\n"
+"Found a swap file by the name \""
+msgstr ""
+"\n"
+"Nájdený odkladací súbor s menom \""
+
+msgid "While opening file \""
+msgstr "Pri otváraní súboru \""
+
+msgid " NEWER than swap file!\n"
+msgstr " NOVŠÍ ako odkladací súbor!\n"
+
+#. Some of these messages are long to allow translation to
+#. * other languages.
+msgid ""
+"\n"
+"(1) Another program may be editing the same file.\n"
+" If this is the case, be careful not to end up with two\n"
+" different instances of the same file when making changes.\n"
+msgstr ""
+"\n"
+"(1) Súbor môže by upravovaný iným programom.\n"
+" Ak je tomu tak, potom si dajte pozor, aby ste po uložení zmien\n"
+" nemali dve rôzne verzie toho istého súboru.\n"
+
+msgid " Quit, or continue with caution.\n"
+msgstr " Ukonèite program, alebo opatrne pokraèujte v úpravách.\n"
+
+msgid ""
+"\n"
+"(2) An edit session for this file crashed.\n"
+msgstr ""
+"\n"
+"(2) Úprava tohoto súboru bola prerušená neoèakávaným ukonèením programu.\n"
+
+msgid " If this is the case, use \":recover\" or \"vim -r "
+msgstr " Ak je tomu tak, potom použite \":recover\" alebo \"vim -r "
+
+msgid ""
+"\"\n"
+" to recover the changes (see \":help recovery\").\n"
+msgstr ""
+"\"\n"
+" pre obnovenie zmien (viï \":help recovery)\".\n"
+
+msgid " If you did this already, delete the swap file \""
+msgstr " Pokia¾ ste tak už urobili, tak vymažte odkladací súbor \""
+
+msgid ""
+"\"\n"
+" to avoid this message.\n"
+msgstr ""
+"\"\n"
+" a táto správa sa už nebude objavova.\n"
+
+msgid "Swap file \""
+msgstr "Odkladací súbor \""
+
+msgid "\" already exists!"
+msgstr "\" už existuje!"
+
+msgid "VIM - ATTENTION"
+msgstr "VIM - POZOR"
+
+msgid "Swap file already exists!"
+msgstr "Odkladací súbor už existuje!"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"&Otvori iba pre èítanie\n"
+"&Pokraèova v úpravách\n"
+"O&bnovi súbor\n"
+"&Koniec\n"
+"&Zruši"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Quit\n"
+"&Abort\n"
+"&Delete it"
+msgstr ""
+"&Otvori iba pre èítanie\n"
+"&Pokraèovat v úpravách\n"
+"O&bnovi súbor\n"
+"&Koniec\n"
+"&Zruši\n"
+"Z&maza"
+
+msgid "E326: Too many swap files found"
+msgstr "E326: Príliš mnoho odkladacích súborov"
+
+msgid "E327: Part of menu-item path is not sub-menu"
+msgstr "E327: Èas cesty k predmetu ponuky nie je podponukou"
+
+msgid "E328: Menu only exists in another mode"
+msgstr "E328: Ponuka existuje iba v inom móde"
+
+msgid "E329: No menu \"%s\""
+msgstr "E329: Ponuka \"%s\" neexistuje"
+
+msgid "E330: Menu path must not lead to a sub-menu"
+msgstr "E330: Cesta ponuky nesmie vies do podponuky"
+
+msgid "E331: Must not add menu items directly to menu bar"
+msgstr "E331: Položky ponuky sa nejdú pridáva priamo na lištu"
+
+msgid "E332: Separator cannot be part of a menu path"
+msgstr "E332: Odde¾ovaè nesmie by èasou cesty ponuky"
+
+#. Now we have found the matching menu, and we list the mappings
+#. Highlight title
+msgid ""
+"\n"
+"--- Menus ---"
+msgstr ""
+"\n"
+"--- Ponuky ---"
+
+msgid "Tear off this menu"
+msgstr "Odtrhnú tuto ponuku"
+
+msgid "E333: Menu path must lead to a menu item"
+msgstr "E333: Cesta ponuky musí vies k položke ponuky"
+
+#, c-format
+msgid "E334: Menu not found: %s"
+msgstr "E334: Ponuka nenájdená: %s"
+
+#, c-format
+msgid "E335: Menu not defined for %s mode"
+msgstr "E335: V %s móde nie je ponuka definovaná"
+
+msgid "E336: Menu path must lead to a sub-menu"
+msgstr "E336: Cesta ponuky musí vies do podponuky"
+
+msgid "E337: Menu not found - check menu names"
+msgstr "E337: Ponuka nenájdená - skontrolujte názvy ponúk"
+
+#, c-format
+msgid "Error detected while processing %s:"
+msgstr "Chyba pri spracovaní %s:"
+
+#, c-format
+msgid "line %4ld:"
+msgstr "riadok %4ld:"
+
+#, c-format
+msgid "E354: Invalid register name: '%s'"
+msgstr "E354: '%s' nie je prístupné meno registru"
+
+msgid "Messages maintainer: Bram Moolenaar <Bram@vim.org>"
+msgstr "Správca prekladu: Lubomir Host <rajo@platon.sk>"
+
+msgid "Interrupt: "
+msgstr "Prerušenie: "
+
+msgid "Press ENTER or type command to continue"
+msgstr "Stlaète ENTER alebo zadajte príkaz pre pokraèovanie"
+
+msgid "-- More --"
+msgstr "-- Pokraèovanie --"
+
+msgid " SPACE/d/j: screen/page/line down, b/u/k: up, q: quit "
+msgstr " MEDZERA/d/j: obrazovka/stránka/riadok dole, b/u/k: hore, q: koniec "
+
+msgid "Question"
+msgstr "Otázka"
+
+# TODO: Translate as "&Ano\n&Nie" ?
+msgid ""
+"&Yes\n"
+"&No"
+msgstr ""
+"&Ano\n"
+"&Nie"
+
+# TODO: Translate as "&Ano\n&Nie\n&Uloži všetko\nZahodi &všetko\n&Zruši" ?
+msgid ""
+"&Yes\n"
+"&No\n"
+"Save &All\n"
+"&Discard All\n"
+"&Cancel"
+msgstr ""
+"&Ano\n"
+"&Nie\n"
+"&Uloži všetko\n"
+"Zahodi &všetko\n"
+"&Zruši"
+
+msgid "Select Directory dialog"
+msgstr "Dialóg pre vytvorenie adresára"
+
+msgid "Save File dialog"
+msgstr "Dialóg pre ukladanie súborov"
+
+msgid "Open File dialog"
+msgstr "Dialóg pre otváranie súborov"
+
+msgid "E338: Sorry, no file browser in console mode"
+msgstr "E338: ¼utujem, ale konzolová verzia nepodporuje prehliadaè súborov"
+
+msgid "E766: Insufficient arguments for printf()"
+msgstr "E766: Chybné argumenty pre funkciu printf()"
+
+msgid "E767: Too many arguments to printf()"
+msgstr "E767: Príliš mnoho argumentov pre funkciu printf()"
+
+msgid "W10: Warning: Changing a readonly file"
+msgstr "W10: Varovanie: mením súbor iba pre èítanie"
+
+msgid "Type number or click with mouse (<Enter> cancels): "
+msgstr "Zadajte èíslo ale kliknite myšou (<Enter> zruší): "
+
+msgid "Choice number (<Enter> cancels): "
+msgstr "Zvo¾te èíslo (<Enter> zruší): "
+
+msgid "1 more line"
+msgstr "1 nový riadok"
+
+msgid "1 line less"
+msgstr "1 vymazaný riadok"
+
+#, c-format
+msgid "%ld more lines"
+msgstr "%ld nových riadkov"
+
+#, c-format
+msgid "%ld fewer lines"
+msgstr "%ld vymazaných riadkov"
+
+msgid " (Interrupted)"
+msgstr " (Prerušené)"
+
+msgid "Beep!"
+msgstr "Piip!"
+
+msgid "Vim: preserving files...\n"
+msgstr "Vim: zachovávam súbory...\n"
+
+#. close all memfiles, without deleting
+msgid "Vim: Finished.\n"
+msgstr "Vim: ukonèený\n"
+
+#, c-format
+msgid "ERROR: "
+msgstr "CHYBA: "
+
+#, c-format
+msgid ""
+"\n"
+"[bytes] total alloc-freed %lu-%lu, in use %lu, peak use %lu\n"
+msgstr ""
+"\n"
+"[bajtov] celkom uvolnené-alokované %lu-%lu, využité %lu, maximálne využitie %lu\n"
+
+#, c-format
+msgid ""
+"[calls] total re/malloc()'s %lu, total free()'s %lu\n"
+"\n"
+msgstr ""
+"[volanie] celkom re/malloc(): %lu, celkom free() %lu\n"
+"\n"
+
+msgid "E340: Line is becoming too long"
+msgstr "E340: Riadok sa stáva príliš dlhým"
+
+#, c-format
+msgid "E341: Internal error: lalloc(%ld, )"
+msgstr "E341: Vnútorná chyba: lalloc(%ld, )"
+
+#, c-format
+msgid "E342: Out of memory! (allocating %lu bytes)"
+msgstr "E342: Nedostatok pamäte! (alokujem %lu bajtov)"
+
+#, c-format
+msgid "Calling shell to execute: \"%s\""
+msgstr "Volám shell na spustenie: \"%s\""
+
+msgid "E545: Missing colon"
+msgstr "E545: Chýba dvojbodka"
+
+msgid "E546: Illegal mode"
+msgstr "E546: Neprípustný mód"
+
+msgid "E547: Illegal mouseshape"
+msgstr "E547: Chybný tvar myši"
+
+msgid "E548: digit expected"
+msgstr "E548: oèakávaná èíslica"
+
+msgid "E549: Illegal percentage"
+msgstr "E549: Neprípustné percento"
+
+msgid "Enter encryption key: "
+msgstr "Zadajte šifrovací k¾úè: "
+
+msgid "Enter same key again: "
+msgstr "Vložte ten istý k¾úè znova: "
+
+msgid "Keys don't match!"
+msgstr "K¾úèe sa nezhodujú!"
+
+#, c-format
+msgid ""
+"E343: Invalid path: '**[number]' must be at the end of the path or be "
+"followed by '%s'."
+msgstr ""
+"E343: Chybná cesta: '**[èíslo] musí by buï na konci cesty, alebo musí by "
+"nasledované '%s. Viï :help path."
+
+#, c-format
+msgid "E344: Can't find directory \"%s\" in cdpath"
+msgstr "E344: Adresár \"%s\" sa nedá nájs v cdpath"
+
+#, c-format
+msgid "E345: Can't find file \"%s\" in path"
+msgstr "E345: Súbor \"%s\" sa nepodarilo nájs"
+
+#, c-format
+msgid "E346: No more directory \"%s\" found in cdpath"
+msgstr "E346: Žiadny ïalší adresár \"%s\" nebol v cdpath nájdený"
+
+#, c-format
+msgid "E347: No more file \"%s\" found in path"
+msgstr "E347: Žiadny ïalší súbor \"%s\" nebol v ceste nájdený"
+
+#. Get here when the server can't be found.
+msgid "Cannot connect to Netbeans #2"
+msgstr "Nedá sa pripoji na Netbeans #2"
+
+msgid "Cannot connect to Netbeans"
+msgstr "Nedá sa pripoji na Netbeans"
+
+#, c-format
+msgid "E668: Wrong access mode for NetBeans connection info file: \"%s\""
+msgstr "E668: Zlé prístupové práva pre súbor s informáciami pre NetBeans spojenie: \"%s\""
+
+msgid "read from Netbeans socket"
+msgstr "èítanie z Netbeans soketu"
+
+msgid "E658: NetBeans connection lost for buffer %ld"
+msgstr "E658: Stratené NetBeans spojenie pre buffer %ld"
+
+msgid "E505: "
+msgstr "E505: "
+
+msgid "Warning: terminal cannot highlight"
+msgstr "Varovanie: terminál nepodporuje zvýrazòovanie"
+
+msgid "E348: No string under cursor"
+msgstr "E348: Pod kurzorom nie je žiadny reazec"
+
+msgid "E349: No identifier under cursor"
+msgstr "E349: Pod kurzorom nie je žiadny identifikátor"
+
+msgid "E352: Cannot erase folds with current 'foldmethod'"
+msgstr "E352: Pomocou 'foldmethod' sa nedá vymaza vnorenie"
+
+msgid "E664: changelist is empty"
+msgstr "E664: zoznam zmien je prázdny"
+
+msgid "E662: At start of changelist"
+msgstr "E662: Na zaèiatku zoznamu zmien"
+
+msgid "E663: At end of changelist"
+msgstr "E663: Na konci zoznamu zmien"
+
+msgid "Type :quit<Enter> to exit Vim"
+msgstr "Zadajte :quit<Enter> pre ukonèenie programu Vim"
+
+#, c-format
+msgid "1 line %sed 1 time"
+msgstr "poèet riadkov upravených naraz pomocou %s: 1"
+
+#, c-format
+msgid "1 line %sed %d times"
+msgstr "1 riadok upravený pomocou %s %d krát"
+
+#, c-format
+msgid "%ld lines %sed 1 time"
+msgstr "%ld riadkov upravených naraz pomocou %s"
+
+#, c-format
+msgid "%ld lines %sed %d times"
+msgstr "%ld riadkov upravených pomocou %s %d krát"
+
+#, c-format
+msgid "%ld lines to indent... "
+msgstr "%ld riadkov pre odsadenie..."
+
+msgid "1 line indented "
+msgstr "1 riadok odsadený "
+
+#, c-format
+msgid "%ld lines indented "
+msgstr "%ld riadkov odsadených "
+
+msgid "E748: No previously used register"
+msgstr "E748: Žiadny predtým používaný register"
+
+#. must display the prompt
+msgid "cannot yank; delete anyway"
+msgstr "nedá sa kopírova; napriek tomu vymazané"
+
+msgid "1 line changed"
+msgstr "1 riadok zmenený"
+
+#, c-format
+msgid "%ld lines changed"
+msgstr "%ld zmenených riadkov"
+
+#, c-format
+msgid "freeing %ld lines"
+msgstr "uvolòujem %ld riadkov"
+
+msgid "block of 1 line yanked"
+msgstr "skopírovaný blok 1 riadku"
+
+msgid "1 line yanked"
+msgstr "1 riadok skopírovaný"
+
+msgid "block of %ld lines yanked"
+msgstr "skopírovaný blok %ld riadkov"
+
+#, c-format
+msgid "%ld lines yanked"
+msgstr "%ld skopírovaných riadkov"
+
+#, c-format
+msgid "E353: Nothing in register %s"
+msgstr "E353: Register %s je prázdny"
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Registers ---"
+msgstr ""
+"\n"
+"--- Registre ---"
+
+msgid "Illegal register name"
+msgstr "Neprípustný názov registra"
+
+#, c-format
+msgid ""
+"\n"
+"# Registers:\n"
+msgstr ""
+"\n"
+"# Registre:\n"
+
+msgid "E574: Unknown register type %d"
+msgstr "E574: Neznámy typ registra %d"
+
+#, c-format
+msgid "%ld Cols; "
+msgstr "%ld Ståpcov; "
+
+#, c-format
+msgid "Selected %s%ld of %ld Lines; %ld of %ld Words; %ld of %ld Bytes"
+msgstr "Vybraných %s%ld z %ld Riadkov; %ld zo %ld Slov; %ld z %ld Bajtov"
+
+msgid ""
+"Selected %s%ld of %ld Lines; %ld of %ld Words; %ld of %ld Chars; %ld of %ld "
+"Bytes"
+msgstr "Vybraných %s%ld z %ld Riadkov; %ld zo %ld Slov; %ld z %ld Znakov; %ld z %ld Bajtov"
+
+#, c-format
+msgid "Col %s of %s; Line %ld of %ld; Word %ld of %ld; Byte %ld of %ld"
+msgstr "Ståpec %s z %s; Riadok %ld z %ld; Slovo %ld z %ld; Bajt %ld z %ld"
+
+#, c-format
+msgid ""
+"Col %s of %s; Line %ld of %ld; Word %ld of %ld; Char %ld of %ld; Byte %ld of "
+"%ld"
+msgstr "Ståpec %s z %s; Riadok %ld z %ld; Slovo %ld z %ld; Znak %ld z %ld; Bajt %ld z %ld"
+
+#, c-format
+msgid "(+%ld for BOM)"
+msgstr "(+%ld pre BOM)"
+
+msgid "%<%f%h%m%=Page %N"
+msgstr "%<%f%h%m%=Strana %N"
+
+msgid "Thanks for flying Vim"
+msgstr "Ïakujeme za použitie Vim"
+
+msgid "E518: Unknown option"
+msgstr "E518: Neznáma vo¾ba"
+
+msgid "E519: Option not supported"
+msgstr "E519: Vo¾ba nie je podporovaná"
+
+msgid "E520: Not allowed in a modeline"
+msgstr "E520: Nie je v modeline povolené"
+
+msgid "E521: Number required after ="
+msgstr "E521: Po = je vyžadované èíslo"
+
+msgid "E522: Not found in termcap"
+msgstr "E522: Nenájdený v termcape"
+
+#, c-format
+msgid "E539: Illegal character <%s>"
+msgstr "E539: Neprípustný znak <%s>"
+
+msgid "E529: Cannot set 'term' to empty string"
+msgstr "E529: Vo¾ba 'term' nemôže by prázdna"
+
+msgid "E530: Cannot change term in GUI"
+msgstr "E530: V grafickom móde (GUI) sa nedá meni typ terminálu"
+
+msgid "E531: Use \":gui\" to start the GUI"
+msgstr "E531: Použite \"gui\" pre spustenie GUI"
+
+msgid "E589: 'backupext' and 'patchmode' are equal"
+msgstr "E589: vo¾by 'backupext' a 'patchmode' majú rovnakú hodnotu"
+
+msgid "E617: Cannot be changed in the GTK+ 2 GUI"
+msgstr "E617: Nedá sa zmeni v grafickom rozhraní GTK+ 2"
+
+msgid "E524: Missing colon"
+msgstr "E524: Chýba dvojbodka"
+
+msgid "E525: Zero length string"
+msgstr "E525: Reazec s nulovou dåžkou"
+
+#, c-format
+msgid "E526: Missing number after <%s>"
+msgstr "E526: Po <%s> chýba èíslo"
+
+msgid "E527: Missing comma"
+msgstr "E527: Chýba èiarka"
+
+msgid "E528: Must specify a ' value"
+msgstr "E528: Je nutné zada hodnotu '"
+
+msgid "E595: contains unprintable or wide character"
+msgstr "E595: obsahuje netlaèite¾né znaky"
+
+msgid "E596: Invalid font(s)"
+msgstr "E596: Chybné písma"
+
+msgid "E597: can't select fontset"
+msgstr "E597: nedá sa vybra sada písiem"
+
+msgid "E598: Invalid fontset"
+msgstr "E598: Chybná sada písiem"
+
+msgid "E533: can't select wide font"
+msgstr "E533: nedá sa vybra široký font"
+
+msgid "E534: Invalid wide font"
+msgstr "E534: Chybné široké písmo"
+
+#, c-format
+msgid "E535: Illegal character after <%c>"
+msgstr "E535: Neprípustný znak po <%c>"
+
+msgid "E536: comma required"
+msgstr "E536: je nutná èiarka"
+
+#, c-format
+msgid "E537: 'commentstring' must be empty or contain %s"
+msgstr "E537: 'commentstring' (komentár) musí by prázdny alebo musí obsahova %s"
+
+msgid "E538: No mouse support"
+msgstr "E538: Bez podpory myši"
+
+msgid "E540: Unclosed expression sequence"
+msgstr "E540: Neuzatvorené zoskupenie výrazov"
+
+msgid "E541: too many items"
+msgstr "E541: príliš mnoho položiek"
+
+msgid "E542: unbalanced groups"
+msgstr "E542: nevyvážené skupiny"
+
+msgid "E590: A preview window already exists"
+msgstr "E590: Okno náh¾adu už existuje"
+
+msgid "W17: Arabic requires UTF-8, do ':set encoding=utf-8'"
+msgstr "W17: Mód Arabic vyžaduje kódovanie UTF-8, nastavte to príkazom ':set encoding=utf-8'"
+
+#, c-format
+msgid "E593: Need at least %d lines"
+msgstr "E593: Minimálny potrebný poèet riadkov je %d"
+
+#, c-format
+msgid "E594: Need at least %d columns"
+msgstr "E594: Minimálne potrebný poèet ståpcov je %d"
+
+#, c-format
+msgid "E355: Unknown option: %s"
+msgstr "E355: Neznáma vo¾ba: %s"
+
+msgid ""
+"\n"
+"--- Terminal codes ---"
+msgstr ""
+"\n"
+"--- Kódy terminálu ---"
+
+msgid ""
+"\n"
+"--- Global option values ---"
+msgstr ""
+"\n"
+"--- Nastavenie globálnych volieb ---"
+
+msgid ""
+"\n"
+"--- Local option values ---"
+msgstr ""
+"\n"
+"--- Nastavenie lokálnych volieb ---"
+
+msgid ""
+"\n"
+"--- Options ---"
+msgstr ""
+"\n"
+"--- Možnosti ---"
+
+msgid "E356: get_varp ERROR"
+msgstr "E356: get_varp CHYBA"
+
+#, c-format
+msgid "E357: 'langmap': Matching character missing for %s"
+msgstr "E357: 'langmap': pre %s chýba vyhovujúci znak"
+
+#, c-format
+msgid "E358: 'langmap': Extra characters after semicolon: %s"
+msgstr "E358: 'langmap': nadbytoèné znaky po bodkoèiarke: %s"
+
+msgid "cannot open "
+msgstr "nedá sa otvori "
+
+msgid "VIM: Can't open window!\n"
+msgstr "VIM: Nedá sa otvori okno!\n"
+
+msgid "Need Amigados version 2.04 or later\n"
+msgstr "Je potrebná Amigados verzia 2.04 alebo novšia\n"
+
+#, c-format
+msgid "Need %s version %ld\n"
+msgstr "Potrebná %s verzia %ld\n"
+
+msgid "Cannot open NIL:\n"
+msgstr "Nedá sa otvori NIL:\n"
+
+msgid "Cannot create "
+msgstr "Nedá sa vytvori "
+
+#, c-format
+msgid "Vim exiting with %d\n"
+msgstr "Vim ukonèený s %d\n"
+
+msgid "cannot change console mode ?!\n"
+msgstr "nemôžem zmeni konzolový mód ?!\n"
+
+msgid "mch_get_shellsize: not a console??\n"
+msgstr "mch_get_shellsize: nie je konzolou??\n"
+
+#. if Vim opened a window: Executing a shell may cause crashes
+msgid "E360: Cannot execute shell with -f option"
+msgstr "E360: Nedá sa spusti shell s -f vo¾bou"
+
+msgid "Cannot execute "
+msgstr "Nedá sa spusti "
+
+msgid "shell "
+msgstr "shell "
+
+msgid " returned\n"
+msgstr " vrátené\n"
+
+msgid "ANCHOR_BUF_SIZE too small."
+msgstr "ANCHOR_BUF_SIZE príliš malá."
+
+msgid "I/O ERROR"
+msgstr "I/O CHYBA"
+
+msgid "...(truncated)"
+msgstr "...(skrátené)"
+
+msgid "'columns' is not 80, cannot execute external commands"
+msgstr "'ståpce' nie je 80, nemôžem spusti externý príkaz"
+
+msgid "E237: Printer selection failed"
+msgstr "E237: Zlyhal výber tlaèiarne"
+
+#, c-format
+msgid "to %s on %s"
+msgstr "%s na %s"
+
+#, c-format
+msgid "E613: Unknown printer font: %s"
+msgstr "E613: Neznámy font tlaèiarne: %s"
+
+#, c-format
+msgid "E238: Print error: %s"
+msgstr "E238: Chyba tlaèe: %s"
+
+#, c-format
+msgid "Printing '%s'"
+msgstr "Tlaèím '%s'"
+
+#, c-format
+msgid "E244: Illegal charset name \"%s\" in font name \"%s\""
+msgstr "E244: Chybný názov znakovej sady \"%s\" v názve písma \"%s\""
+
+#, c-format
+msgid "E245: Illegal char '%c' in font name \"%s\""
+msgstr "E245: Chybný znak '%c' v názve písma \"%s\""
+
+msgid "Vim: Double signal, exiting\n"
+msgstr "Vim: dvojitý signál, konèím\n"
+
+#, c-format
+msgid "Vim: Caught deadly signal %s\n"
+msgstr "Vim: Zachytený smrtiaci signál %s\n"
+
+#, c-format
+msgid "Vim: Caught deadly signal\n"
+msgstr "Vim: Zachytený smrtiaci signál\n"
+
+#, c-format
+msgid "Opening the X display took %ld msec"
+msgstr "Otvorenie X displej zabralo %ld msec"
+
+#. KDE sometimes produces X error that we want to ignore
+msgid ""
+"\n"
+"Vim: Got X error but we continue...\n"
+msgstr ""
+"\n"
+"Vim: Chyba X ale pokraèujem ...\n"
+
+msgid ""
+"\n"
+"Vim: Got X error\n"
+msgstr ""
+"\n"
+"Vim: Chyba X\n"
+
+msgid "Testing the X display failed"
+msgstr "Testovanie X displeja zlyhalo"
+
+msgid "Opening the X display timed out"
+msgstr "Uplynul èas otvorenia X displeja"
+
+msgid ""
+"\n"
+"Cannot execute shell "
+msgstr ""
+"\n"
+"Nedá sa spusti shell "
+
+msgid ""
+"\n"
+"Cannot execute shell sh\n"
+msgstr ""
+"\n"
+"Nedá sa spusti sh shell\n"
+
+msgid ""
+"\n"
+"shell returned "
+msgstr ""
+"\n"
+" návratová hodnota shellu "
+
+msgid ""
+"\n"
+"Cannot create pipes\n"
+msgstr ""
+"\n"
+"Nedjú sa vytvori rúry\n"
+
+msgid ""
+"\n"
+"Cannot fork\n"
+msgstr ""
+"\n"
+"Vyvolanie fork zlyhalo\n"
+
+msgid ""
+"\n"
+"Command terminated\n"
+msgstr ""
+"\n"
+"Príkaz ukonèený\n"
+
+msgid "XSMP lost ICE connection"
+msgstr "XSMP stratilo ICE spojenie"
+
+#, c-format
+msgid "dlerror = \"%s\""
+msgstr "dlerror = \"%s\""
+
+msgid "Opening the X display failed"
+msgstr "Otvorenie X displeja zlyhalo"
+
+msgid "XSMP handling save-yourself request"
+msgstr "XSMP spracuváva požiadavku na samouloženie"
+
+msgid "XSMP opening connection"
+msgstr "XSMP otvára spojenie"
+
+msgid "XSMP ICE connection watch failed"
+msgstr "XSMP kontrola spojenia ICE zlyhala"
+
+#, c-format
+msgid "XSMP SmcOpenConnection failed: %s"
+msgstr "XSMP SmcOpenConnection zlyhalo: %s"
+
+msgid "At line"
+msgstr "Na riadku"
+
+msgid "Could not load vim32.dll!"
+msgstr "Nemôžem nahra vim32.dll!"
+
+msgid "VIM Error"
+msgstr "VIM Chyba"
+
+msgid "Could not fix up function pointers to the DLL!"
+msgstr "Nemôžem opravi odkazy funkcií na DLL!"
+
+#, c-format
+msgid "shell returned %d"
+msgstr "návratová hodnota shellu %d"
+
+#, c-format
+msgid "Vim: Caught %s event\n"
+msgstr "Vim: Zachytená udalos %s\n"
+
+msgid "close"
+msgstr "zavrie"
+
+msgid "logoff"
+msgstr "odhlási"
+
+msgid "shutdown"
+msgstr "vypnú"
+
+msgid "E371: Command not found"
+msgstr "E371: Príkaz nenájdený"
+
+msgid ""
+"VIMRUN.EXE not found in your $PATH.\n"
+"External commands will not pause after completion.\n"
+"See :help win32-vimrun for more information."
+msgstr ""
+"VIMRUN.EXE nenájdený v $PATH.\n"
+"Po dokonèení externých príkazov nebude výstup pozastavený.\n"
+"Pozrite :help win32-vimrun pre viac informácií."
+
+msgid "Vim Warning"
+msgstr "Vim Varovanie"
+
+#, c-format
+msgid "E372: Too many %%%c in format string"
+msgstr "E372: Príliš mnoho %%%c vo formátovacom reazci"
+
+#, c-format
+msgid "E373: Unexpected %%%c in format string"
+msgstr "E373: Neoèakávaný výskyt %%%c vo formátovacom reazci"
+
+msgid "E374: Missing ] in format string"
+msgstr "E374: Vo formátovacom reazci chýba ]"
+
+#, c-format
+msgid "E375: Unsupported %%%c in format string"
+msgstr ""
+"E375: Nepodporovaná formátová špecifikácia %%%c vo formátovacom reazci"
+
+#, c-format
+msgid "E376: Invalid %%%c in format string prefix"
+msgstr "E376: Neprístupné %%%c v prefixe formátovacieho reazca"
+
+#, c-format
+msgid "E377: Invalid %%%c in format string"
+msgstr "E377: Neprístupné %%%c vo formátovacom reazci"
+
+msgid "E378: 'errorformat' contains no pattern"
+msgstr "E378: 'errorformat' neobsahuje žiadny vzor"
+
+msgid "E379: Missing or empty directory name"
+msgstr "E379: Chýbajúci alebo prázdny názov adresára"
+
+msgid "E553: No more items"
+msgstr "E553: Žiadne ïalšie položky"
+
+#, c-format
+msgid "(%d of %d)%s%s: "
+msgstr "(%d z %d)%s%s: "
+
+msgid " (line deleted)"
+msgstr " (riadok vymazaný)"
+
+msgid "E380: At bottom of quickfix stack"
+msgstr "E380: Koniec quickfix zoznamu"
+
+msgid "E381: At top of quickfix stack"
+msgstr "E381: Zaèiatok quickfix zoznamu"
+
+#, c-format
+msgid "error list %d of %d; %d errors"
+msgstr "zoznam chýb %d z %d; %d chýb"
+
+msgid "E382: Cannot write, 'buftype' option is set"
+msgstr "E382: Nedá sa uloži, je nastavená vo¾ba 'buftype'"
+
+msgid "E683: File name missing or invalid pattern"
+msgstr "E683: Chýba meno súboru alebo chybný vzor"
+
+msgid "Cannot open file \"%s\""
+msgstr "Nedá sa otvori súbor \"%s\""
+
+msgid "E681: Buffer is not loaded"
+msgstr "E681: Buffer nie je naèítaný"
+
+#, c-format
+msgid "E369: invalid item in %s%%[]"
+msgstr "E369: chybná položka v %s%%[]"
+
+msgid "E339: Pattern too long"
+msgstr "E339: Vzor je príliš dlhý"
+
+msgid "E50: Too many \\z("
+msgstr "E50: Príliš mnoho \\z("
+
+#, c-format
+msgid "E51: Too many %s("
+msgstr "E51: Príliš mnoho %s("
+
+msgid "E52: Unmatched \\z("
+msgstr "E52: Nespárované \\z("
+
+#, c-format
+msgid "E53: Unmatched %s%%("
+msgstr "E53: Nespárované %s%%("
+
+#, c-format
+msgid "E54: Unmatched %s("
+msgstr "E54: Nespárované %s("
+
+#, c-format
+msgid "E55: Unmatched %s)"
+msgstr "E55: Nespárované %s)"
+
+#, c-format
+msgid "E59: invalid character after %s@"
+msgstr "E59: Neprípustný znak po %s@"
+
+#, c-format
+msgid "E60: Too many complex %s{...}s"
+msgstr "E60: Príliš komplexné %s{...}"
+
+#, c-format
+msgid "E61: Nested %s*"
+msgstr "E61: Vnorený %s*"
+
+#, c-format
+msgid "E62: Nested %s%c"
+msgstr "E62: Vnorený %s%c"
+
+msgid "E63: invalid use of \\_"
+msgstr "E63: Chybne použité \\_"
+
+#, c-format
+msgid "E64: %s%c follows nothing"
+msgstr "E64: %s%c niè nenasleduje"
+
+msgid "E65: Illegal back reference"
+msgstr "E65: Chybná spätná referencia"
+
+msgid "E66: \\z( not allowed here"
+msgstr "E66: \\z( tu nie je povolené"
+
+msgid "E67: \\z1 - \\z9 not allowed here"
+msgstr "E67: \\z1 a spol. tu nie je povolené"
+
+msgid "E68: Invalid character after \\z"
+msgstr "E68: Neprípustný znak po \\z"
+
+#, c-format
+msgid "E69: Missing ] after %s%%["
+msgstr "E69: Chýbajúca ] po %s%%["
+
+#, c-format
+msgid "E70: Empty %s%%[]"
+msgstr "E70: Prázdny %s%%[]"
+
+#, c-format
+msgid "E678: Invalid character after %s%%[dxouU]"
+msgstr "E678: Neprípustný znak po %s%%[dxouU]"
+
+#, c-format
+msgid "E71: Invalid character after %s%%"
+msgstr "E71: Neprípustný znak po %s%%"
+
+#, c-format
+msgid "E769: Missing ] after %s["
+msgstr "E769: Chýbajúca ] po %s["
+
+#, c-format
+msgid "E554: Syntax error in %s{...}"
+msgstr "E554: Chyba syntaxe v %s{...}"
+
+msgid "External submatches:\n"
+msgstr "Vnútorné podradené zhody:\n"
+
+msgid " VREPLACE"
+msgstr " NAHRADI VERTIKÁLNE"
+
+msgid " REPLACE"
+msgstr " NAHRADI"
+
+msgid " REVERSE"
+msgstr " OBRÁTI"
+
+msgid " INSERT"
+msgstr " VLOŽI"
+
+msgid " (insert)"
+msgstr " (vloži)"
+
+msgid " (replace)"
+msgstr " (nahradi)"
+
+msgid " (vreplace)"
+msgstr " (nahradi vertikálne)"
+
+msgid " Hebrew"
+msgstr " Hebrejský"
+
+msgid " Arabic"
+msgstr " Arabský"
+
+msgid " (lang)"
+msgstr " (jazyk)"
+
+msgid " (paste)"
+msgstr " (vloži)"
+
+msgid " VISUAL"
+msgstr " VIZUÁLNE"
+
+msgid " VISUAL LINE"
+msgstr " VIZUÁLNY RIADOK"
+
+msgid " VISUAL BLOCK"
+msgstr " VIZUÁLNY BLOK"
+
+msgid " SELECT"
+msgstr " ZHODY"
+
+msgid " SELECT LINE"
+msgstr " OZNAÈ RIADOK"
+
+msgid " SELECT BLOCK"
+msgstr " OZNAÈ BLOK"
+
+msgid "recording"
+msgstr "nahrávam"
+
+#, c-format
+msgid "E383: Invalid search string: %s"
+msgstr "E383: Neprípustný h¾adaný reazec: %s"
+
+#, c-format
+msgid "E384: search hit TOP without match for: %s"
+msgstr "E384: h¾adanie dosiahlo zaèiatok bez nájdenia %s"
+
+#, c-format
+msgid "E385: search hit BOTTOM without match for: %s"
+msgstr "E385: h¾adanie dosiahlo koniec bez nájdenia %s"
+
+msgid "E386: Expected '?' or '/' after ';'"
+msgstr "E386: Po ';' oèakávam '?' alebo '/'"
+
+msgid " (includes previously listed match)"
+msgstr " (vrátane už vypísaných zhôd)"
+
+#. cursor at status line
+msgid "--- Included files "
+msgstr "--- Vložené súbory"
+
+msgid "not found "
+msgstr "nenájdené "
+
+msgid "in path ---\n"
+msgstr "v ceste ---\n"
+
+msgid " (Already listed)"
+msgstr " (Už vypísané)"
+
+msgid " NOT FOUND"
+msgstr " NENÁJDENÉ"
+
+#, c-format
+msgid "Scanning included file: %s"
+msgstr "Preh¾adávam vložené súbory: %s"
+
+msgid "E387: Match is on current line"
+msgstr "E387: Zhoda je na aktuálnom riadku"
+
+msgid "All included files were found"
+msgstr "Všetky vložené súbory boli nájdené"
+
+msgid "No included files"
+msgstr "Žiadne vložené súbory"
+
+msgid "E388: Couldn't find definition"
+msgstr "E388: Nedá sa nájs definícia"
+
+msgid "E389: Couldn't find pattern"
+msgstr "E389: Nedá sa nájs vzor"
+
+msgid "E759: Format error in spell file"
+msgstr "E759: Chyba formátovania v spell súbore (kontrola pravopisu)"
+
+msgid "E758: Truncated spell file"
+msgstr "E758: Odseknutý spell súbor (kontrola pravopisu)"
+
+#, c-format
+msgid "Trailing text in %s line %d: %s"
+msgstr "Prebytoèný text v %s na riadku %d: %s"
+
+#, c-format
+msgid "Affix name too long in %s line %d: %s"
+msgstr "Prípona príliœ dlhá v %s riadok %d: %s"
+
+msgid "E761: Format error in affix file FOL, LOW or UPP"
+msgstr "E761: Chyba formátovania v súbore prípon FOL, LOW alebo UPP (NASLEDUJE, MALÉ alebo VE¼KÉ)"
+
+msgid "E762: Character in FOL, LOW or UPP is out of range"
+msgstr "E762: Znak v FOL, LOW alebo UPP (NASLEDUJE, MALÉ alebo VE¼KÉ) je mimo rozsah"
+
+msgid "Compressing word tree..."
+msgstr "Robím kompresiu stromu slov..."
+
+msgid "E756: Spell checking is not enabled"
+msgstr "E756: Kontrola pravopisu nie je zapnutá"
+
+#, c-format
+msgid "Warning: Cannot find word list \"%s.%s.spl\" or \"%s.ascii.spl\""
+msgstr "Varovanie: Nemožno nájs zoznam slov \"%s.%s.spl\" alebo \"%s.ascii.spl\""
+
+#, c-format
+msgid "Reading spell file \"%s\""
+msgstr "Èítam slovníkový súbor \"%s\""
+
+msgid "E757: This does not look like a spell file"
+msgstr "E757: Toto sa nezdá by slovníkovým súborom"
+
+msgid "E771: Old spell file, needs to be updated"
+msgstr "E771: Starý slovníkový súbor, potrebuje by zaktualizovaný"
+
+msgid "E772: Spell file is for newer version of Vim"
+msgstr "E772: Slovníkový súbor je pre novšiu verziu Vim"
+
+msgid "E770: Unsupported section in spell file"
+msgstr "E770: Nepodporovaná sekcia v slovníkovom súbore"
+
+#, c-format
+msgid "Warning: region %s not supported"
+msgstr "Varovanie: región %s nie je podporovaný"
+
+#, c-format
+msgid "Reading affix file %s..."
+msgstr "Naèítavam súbor s príponami %s..."
+
+#, c-format
+msgid "Conversion failure for word in %s line %d: %s"
+msgstr "Konverzia slova zlyhala v %s riadok %d: %s"
+
+#, c-format
+msgid "Conversion in %s not supported: from %s to %s"
+msgstr "Konverzia v %s nie je podporovaná: z %s do %s"
+
+#, c-format
+msgid "Conversion in %s not supported"
+msgstr "Konverzia v %s nie je podporovaná"
+
+#, c-format
+msgid "Invalid value for FLAG in %s line %d: %s"
+msgstr "Neplatná hodnota pre príznak (FLAG) v %s riadok %d: %s"
+
+#, c-format
+msgid "FLAG after using flags in %s line %d: %s"
+msgstr "Príznak (FLAG) po použití príznakov v %s riadok %d: %s"
+
+#, c-format
+msgid "Character used for SLASH must be ASCII; in %s line %d: %s"
+msgstr "Znak použitý pre SLASH musí by ASCII; v %s riadok %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDMAX value in %s line %d: %s"
+msgstr "Zlá hodnota COMPOUNDMAX v %s riadok %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDMIN value in %s line %d: %s"
+msgstr "Zlá hodnota COMPOUNDMIN v %s riadok %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDSYLMAX value in %s line %d: %s"
+msgstr "Zlá hodnota COMPOUNDSYLMAX v %s riadok %d: %s"
+
+#, c-format
+msgid "Different combining flag in continued affix block in %s line %d: %s"
+msgstr "Rozdielna kombinácia príznakov v nasledujúcom bloku prípon v %s riadok %d: %s"
+
+#, c-format
+msgid "Duplicate affix in %s line %d: %s"
+msgstr "Duplicitná prípona v %s riadok %d: %s"
+
+#, c-format
+msgid ""
+"Affix also used for BAD/RAR/KEP/NEEDAFFIX/NEEDCOMPOUND in %s line %d: %s"
+msgstr ""
+"Prípona použitá aj pre BAD/RAR/KEP/NEEDAFFIX/NEEDCOMPOUND in %s line %d: %s"
+
+#, c-format
+msgid "Expected Y or N in %s line %d: %s"
+msgstr "Oèakávane Y alebo N v %s riadok %d: %s"
+
+#, c-format
+msgid "Broken condition in %s line %d: %s"
+msgstr "Narušená podmienka v %s riadok %d: %s"
+
+#, c-format
+msgid "Expected REP count in %s line %d"
+msgstr "Oèakávam poèet REP v %s riadok %d"
+
+#, c-format
+msgid "Expected MAP count in %s line %d"
+msgstr "Oèakávam poèet MAP v %s riadok %d"
+
+#, c-format
+msgid "Duplicate character in MAP in %s line %d"
+msgstr "Opakovaný znak v MAP v %s riadok %d"
+
+#, c-format
+msgid "Unrecognized or duplicate item in %s line %d: %s"
+msgstr "Nerozpoznaná alebo opakujúca sa položka v %s riadok %d: %s"
+
+#, c-format
+msgid "Missing FOL/LOW/UPP line in %s"
+msgstr "Chýbajúci riadok FOL/LOW/UPP v %s"
+
+msgid "COMPOUNDSYLMAX used without SYLLABLE"
+msgstr "COMPOUNDSYLMAX použitý bez SYLLABLE"
+
+msgid "Too many postponed prefixes"
+msgstr "Príliš mnoho odložených prípon"
+
+msgid "Too many compound flags"
+msgstr "Príliš mnoho upravovacích príznakov"
+
+msgid "Too many postponed prefixes and/or compound flags"
+msgstr "Príliš mnoho odložených prípon a/alebo upravovacích príznakov"
+
+#, c-format
+msgid "Missing SOFO%s line in %s"
+msgstr "Chýba SOFO%s riadok v %s"
+
+#, c-format
+msgid "Both SAL and SOFO lines in %s"
+msgstr "SAL a SOFO riadky zároveò v %s"
+
+#, c-format
+msgid "Flag is not a number in %s line %d: %s"
+msgstr "Príznak nie je èíslo v %s na riadku %d: %s"
+
+#, c-format
+msgid "Illegal flag in %s line %d: %s"
+msgstr "Neprípustný príznak v %s riadok %d: %s"
+
+#, c-format
+msgid "%s value differs from what is used in another .aff file"
+msgstr "Hodnota %s sa odlišuje od hodnoty použitej v inom .aff súbore"
+
+#, c-format
+msgid "Reading dictionary file %s..."
+msgstr "Naèítavam slovník %s..."
+
+#, c-format
+msgid "E760: No word count in %s"
+msgstr "E760: Chýajúci poèet slov v %s"
+
+#, c-format
+msgid "line %6d, word %6d - %s"
+msgstr "riadok %6d, slovo %6d - %s"
+
+#, c-format
+msgid "Duplicate word in %s line %d: %s"
+msgstr "Opakujúce sa slovo v %s riadok %d: %s"
+
+#, c-format
+msgid "First duplicate word in %s line %d: %s"
+msgstr "Prvé duplicitné slovo v %s riadok %d: %s"
+
+#, c-format
+msgid "%d duplicate word(s) in %s"
+msgstr "%d duplicitné slovo(á) v %s"
+
+#, c-format
+msgid "Ignored %d word(s) with non-ASCII characters in %s"
+msgstr "Ignorovaných %d slov s nepísmennými znakmi v %s"
+
+#, c-format
+msgid "Reading word file %s..."
+msgstr "Naèítavam súbor so slovami %s..."
+
+#, c-format
+msgid "Duplicate /encoding= line ignored in %s line %d: %s"
+msgstr "Duplicitný riadok /encoding= v %s riadok %d ignorovaný: %s "
+
+#, c-format
+msgid "/encoding= line after word ignored in %s line %d: %s"
+msgstr "/encoding= riadok nasledujúci po slove v %s riadok %d ignorovaný: %s"
+
+#, c-format
+msgid "Duplicate /regions= line ignored in %s line %d: %s"
+msgstr "Duplicitný riadok /regions= v %s riadok %d ignorovaný: %s"
+
+#, c-format
+msgid "Too many regions in %s line %d: %s"
+msgstr "Príliš mnoho regiónov v %s riadok %d: %s"
+
+#, c-format
+msgid "/ line ignored in %s line %d: %s"
+msgstr "Riadok / v %s riadok %d ignorovaný: %s"
+
+#, c-format
+msgid "Invalid region nr in %s line %d: %s"
+msgstr "Použíté chybné èíslo regiónu v %s riadok %d: %s"
+
+#, c-format
+msgid "Unrecognized flags in %s line %d: %s"
+msgstr "Nerozpoznaný príznak v %s riadok %d: %s"
+
+#, c-format
+msgid "Ignored %d words with non-ASCII characters"
+msgstr "Ignorovaných %d slov s nepísmennými znakmi"
+
+#, c-format
+msgid "Compressed %d of %d nodes; %d%% remaining"
+msgstr "Skomprimovaných %d z %d uzlov; %d%% zostáva"
+
+msgid "E751: Output file name must not have region name"
+msgstr "E751: Výstupné meno súboru nesmie ma názov regiónu"
+
+msgid "E754: Only up to 8 regions supported"
+msgstr "E754: Podporovaných max. 8 regiónov"
+
+#, c-format
+msgid "E755: Invalid region in %s"
+msgstr "E755: Chybný región v %s"
+
+msgid "Warning: both compounding and NOBREAK specified"
+msgstr "Varovanie: špecifikované spájanie a nezalamovanie"
+
+#, c-format
+msgid "Writing spell file %s..."
+msgstr "Ukládám slovníkový súbor %s..."
+
+msgid "Done!"
+msgstr "Hotovo!"
+
+#, c-format
+msgid "Estimated runtime memory use: %d bytes"
+msgstr "Ve¾kos používanej pamäte: %d bajtov"
+
+#, c-format
+msgid "E765: 'spellfile' does not have %ld entries"
+msgstr "E765: 'spellfile' nemá %ld položiek"
+
+msgid "E763: Word characters differ between spell files"
+msgstr "E763: Znaky slov sa odlišujú medzi slovníkovými súbormi"
+
+msgid "Sorry, no suggestions"
+msgstr "Prepáète, žiadne návrhy"
+
+#, c-format
+msgid "Sorry, only %ld suggestions"
+msgstr "Prepáète, iba %ld návrhov"
+
+#. avoid more prompt
+#, c-format
+msgid "Change \"%.*s\" to:"
+msgstr "Zmeni \"%.*s\" na:"
+
+#, c-format
+msgid " < \"%.*s\""
+msgstr " < \"%.*s\""
+
+msgid "E752: No previous spell replacement"
+msgstr "E752: Žiadny predchádzajúce nahradenie pod¾a slovníka"
+
+#, c-format
+msgid "E753: Not found: %s"
+msgstr "E753: Nenájdené: %s"
+
+#. This should have been checked when generating the .spl
+#. * file.
+msgid "E783: duplicate char in MAP entry"
+msgstr "E783: duplicitný znak v MAP položke"
+
+#, c-format
+msgid "E390: Illegal argument: %s"
+msgstr "E390: Neprípustný argument: %s"
+
+#, c-format
+msgid "E391: No such syntax cluster: %s"
+msgstr "E391: Syntaktická zostava %s neexistuje"
+
+msgid "No Syntax items defined for this buffer"
+msgstr "Pre tento buffer nie sú definované žiadne položky syntaxe"
+
+msgid "syncing on C-style comments"
+msgstr "synchronizujem pod¾a komentárov jazyka C"
+
+msgid "no syncing"
+msgstr "žiadne synchronizácie"
+
+msgid "syncing starts "
+msgstr "synchronizácia zaèína "
+
+msgid " lines before top line"
+msgstr " riadkov pred zaèiatkom"
+
+msgid ""
+"\n"
+"--- Syntax sync items ---"
+msgstr ""
+"\n"
+"--- Položky synchronizácie syntaxe ---"
+
+msgid ""
+"\n"
+"syncing on items"
+msgstr ""
+"\n"
+"synchronizujem položky"
+
+msgid ""
+"\n"
+"--- Syntax items ---"
+msgstr ""
+"\n"
+"--- Položky syntaxe ---"
+
+#, c-format
+msgid "E392: No such syntax cluster: %s"
+msgstr "E392: Syntaktická zostava %s neexistuje"
+
+msgid "minimal "
+msgstr "minimálne "
+
+msgid "maximal "
+msgstr "maximálne "
+
+msgid "; match "
+msgstr "; zhoda "
+
+msgid " line breaks"
+msgstr " zalomení riadkov"
+
+msgid "E395: contains argument not accepted here"
+msgstr "E395: obsahuje argumenty, ktoré tu nie sú povolené"
+
+msgid "E396: containedin argument not accepted here"
+msgstr "E396: obsahuje argumenty, ktoré tu nie sú povolené"
+
+msgid "E393: group[t]here not accepted here"
+msgstr "E393: group[t]here nesmie by na tomto mieste"
+
+#, c-format
+msgid "E394: Didn't find region item for %s"
+msgstr "E394: Pre %s chýba položka regiónu"
+
+msgid "E397: Filename required"
+msgstr "E397: Vyžadovaný názov súboru"
+
+#, c-format
+msgid "E789: Missing ']': %s"
+msgstr "E789: Chýba ']': %s"
+
+#, c-format
+msgid "E398: Missing '=': %s"
+msgstr "E398: Chýba '=': %s"
+
+#, c-format
+msgid "E399: Not enough arguments: syntax region %s"
+msgstr "E399: Príliš málo argumentov: oblas syntaxe %s"
+
+msgid "E400: No cluster specified"
+msgstr "E400: Nebola zadaná žiadna zostava"
+
+#, c-format
+msgid "E401: Pattern delimiter not found: %s"
+msgstr "E401: Odde¾ovaè vzoru %s nenájdený"
+
+#, c-format
+msgid "E402: Garbage after pattern: %s"
+msgstr "E402: Chyba za vzorom: %s"
+
+msgid "E403: syntax sync: line continuations pattern specified twice"
+msgstr "E403: synchronizácia syntaxe: vzor pokraèovania riadkov zadaný dvakrát"
+
+#, c-format
+msgid "E404: Illegal arguments: %s"
+msgstr "E404: Chybné argumenty: %s"
+
+#, c-format
+msgid "E405: Missing equal sign: %s"
+msgstr "E405: Chýba znamienko rovná sa: %s"
+
+#, c-format
+msgid "E406: Empty argument: %s"
+msgstr "E406: Prázdny argument: %s"
+
+#, c-format
+msgid "E407: %s not allowed here"
+msgstr "E407: %s tu nie je povolené"
+
+#, c-format
+msgid "E408: %s must be first in contains list"
+msgstr "E408: %s musí by prvý v 'contains' zozname"
+
+#, c-format
+msgid "E409: Unknown group name: %s"
+msgstr "E409: Neznámy názov skupiny: %s"
+
+#, c-format
+msgid "E410: Invalid :syntax subcommand: %s"
+msgstr "E410: Chybný podradený príkaz :syntax : %s "
+
+msgid "E679: recursive loop loading syncolor.vim"
+msgstr "E679: rekurzívna sluèka pri naèítavaní syncolor.vim"
+
+#, c-format
+msgid "E411: highlight group not found: %s"
+msgstr "E411: skupina zvýraznenia %s nebola nájdená"
+
+#, c-format
+msgid "E412: Not enough arguments: \":highlight link %s\""
+msgstr "E412: Príliš málo argumentov: \":highlight link %s\""
+
+#, c-format
+msgid "E413: Too many arguments: \":highlight link %s\""
+msgstr "E413: Príliš mnoho argumentov: \":highlight link %s\""
+
+msgid "E414: group has settings, highlight link ignored"
+msgstr "E414: skupina je nastavená, odkaz na zvýrazòovaciu skupinu ignorovaný"
+
+#, c-format
+msgid "E415: unexpected equal sign: %s"
+msgstr "E415: neoèakávané znamienko rovná sa: %s"
+
+#, c-format
+msgid "E416: missing equal sign: %s"
+msgstr "E416: chýba znamienko rovná sa: %s"
+
+#, c-format
+msgid "E417: missing argument: %s"
+msgstr "E417: chýba argument: %s"
+
+#, c-format
+msgid "E418: Illegal value: %s"
+msgstr "E418: Neprípustná hodnota: %s"
+
+msgid "E419: FG color unknown"
+msgstr "E419: farba popredia nie je známa"
+
+msgid "E420: BG color unknown"
+msgstr "E420: farba pozadia nie je známa"
+
+#, c-format
+msgid "E421: Color name or number not recognized: %s"
+msgstr "E421: Názov alebo èíslo farby nebolo rozpoznané: %s"
+
+#, c-format
+msgid "E422: terminal code too long: %s"
+msgstr "E422: terminálový kód je príliš dlhý: %s"
+
+#, c-format
+msgid "E423: Illegal argument: %s"
+msgstr "E423: Neprípustný argument: %s"
+
+msgid "E424: Too many different highlighting attributes in use"
+msgstr "E424: Používaných príliš ve¾a odlišných zvýrazòovacích vlastností"
+
+msgid "E669: Unprintable character in group name"
+msgstr "E669: Netlaèitelný znak v mene skupiny"
+
+msgid "W18: Invalid character in group name"
+msgstr "W18: Chybný znak v mene skupiny"
+
+msgid "E555: at bottom of tag stack"
+msgstr "E555: na konci zoznamu tagov"
+
+msgid "E556: at top of tag stack"
+msgstr "E556: na zaèiatku zoznamu tagov"
+
+msgid "E425: Cannot go before first matching tag"
+msgstr "E425: Nedá sa skoèi pred prvý vyhovujúci tag"
+
+#, c-format
+msgid "E426: tag not found: %s"
+msgstr "E426: tag %s nenájdený"
+
+msgid " # pri kind tag"
+msgstr " # pri typ tag"
+
+msgid "file\n"
+msgstr "súbor\n"
+
+msgid "E427: There is only one matching tag"
+msgstr "E427: Vyhovuje iba jeden tag"
+
+msgid "E428: Cannot go beyond last matching tag"
+msgstr "E428: Za posledný vyhovujúci tag sa nedá preskoèi"
+
+#, c-format
+msgid "File \"%s\" does not exist"
+msgstr "Súbor \"%s\" neexistuje"
+
+#. Give an indication of the number of matching tags
+#, c-format
+msgid "tag %d of %d%s"
+msgstr "tag %d z %d%s"
+
+msgid " or more"
+msgstr " alebo viac"
+
+msgid " Using tag with different case!"
+msgstr " Používam tag s písmom inej ve¾kosti!"
+
+#, c-format
+msgid "E429: File \"%s\" does not exist"
+msgstr "E429: Súbor \"%s\" neexistuje"
+
+#. Highlight title
+msgid ""
+"\n"
+" # TO tag FROM line in file/text"
+msgstr ""
+"\n"
+" # CIE¼ tag ŠTART riadok v súbore/texte"
+
+#, c-format
+msgid "Searching tags file %s"
+msgstr "Preh¾adávam súbor tagov %s"
+
+#, c-format
+msgid "E430: Tag file path truncated for %s\n"
+msgstr "E430: Cesta k súboru tagov %s bola orezaná\n"
+
+#, c-format
+msgid "E431: Format error in tags file \"%s\""
+msgstr "E431: Chyba formátovania v súbore tagov \"%s\""
+
+#, c-format
+msgid "Before byte %ld"
+msgstr "Pred bajtom %ld"
+
+#, c-format
+msgid "E432: Tags file not sorted: %s"
+msgstr "E432: Obsah súboru tagov %s nie je zoradený"
+
+#. never opened any tags file
+msgid "E433: No tags file"
+msgstr "E433: Žiadny súbor tagov"
+
+msgid "E434: Can't find tag pattern"
+msgstr "E434: Nedá sa nájs vzor tagov"
+
+msgid "E435: Couldn't find tag, just guessing!"
+msgstr "E435: Tag sa nedá nájs, iba hádam!"
+
+msgid "' not known. Available builtin terminals are:"
+msgstr "' nie je známy. Dostupné vstavané terminály:"
+
+msgid "defaulting to '"
+msgstr "nastavujem na '"
+
+msgid "E557: Cannot open termcap file"
+msgstr "E557: Nedá sa otvori termcap súbor"
+
+msgid "E558: Terminal entry not found in terminfo"
+msgstr "E558: Terminfo neobsahuje položku pre tento terminál"
+
+msgid "E559: Terminal entry not found in termcap"
+msgstr "E559: Termcap neobsahuje položku pre tento terminál"
+
+#, c-format
+msgid "E436: No \"%s\" entry in termcap"
+msgstr "E436: Termcap neobsahuje položku \"%s\""
+
+msgid "E437: terminal capability \"cm\" required"
+msgstr "E437: Terminál musí ma schopnos \"cm\" (schopnos pohybu kurzora)"
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Terminal keys ---"
+msgstr ""
+"\n"
+"--- Klávesy terminálu ---"
+
+msgid "new shell started\n"
+msgstr "spustený nový shell\n"
+
+msgid "Vim: Error reading input, exiting...\n"
+msgstr "Vim: Chyba pri èítaní vstupu, konèím...\n"
+
+#. must display the prompt
+msgid "No undo possible; continue anyway"
+msgstr "Odstránenie zmien nie je možné; chcete napriek tomu pokraèova"
+
+msgid "E438: u_undo: line numbers wrong"
+msgstr "E438: u_undo: èísla riadkov sú chybné"
+
+msgid "1 change"
+msgstr "1 zmena"
+
+#, c-format
+msgid "%ld changes"
+msgstr "%ld zmien"
+
+msgid "E439: undo list corrupt"
+msgstr "E439: záznam o zmenách poškodený"
+
+msgid "E440: undo line missing"
+msgstr "E440: chýba opravný riadok"
+
+#. Only MS VC 4.1 and earlier can do Win32s
+msgid ""
+"\n"
+"MS-Windows 16/32-bit GUI version"
+msgstr ""
+"\n"
+"16/32 bitová GUI verzia pre MS Windows"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit GUI version"
+msgstr ""
+"\n"
+"32 bitová GUI verzia pre MS Windows"
+
+msgid " in Win32s mode"
+msgstr " vo Win32 režime"
+
+msgid " with OLE support"
+msgstr " s OLE podporou"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit console version"
+msgstr ""
+"\n"
+"32 bitová verzia pre MS Windows konzolu"
+
+msgid ""
+"\n"
+"MS-Windows 16-bit version"
+msgstr ""
+"\n"
+"16 bitová verzia pre MS Windows"
+
+msgid ""
+"\n"
+"32-bit MS-DOS version"
+msgstr ""
+"\n"
+"32 bitová verzia pre MS-DOS"
+
+msgid ""
+"\n"
+"16-bit MS-DOS version"
+msgstr ""
+"\n"
+"16 bitová MS-DOS verzia"
+
+msgid ""
+"\n"
+"MacOS X (unix) version"
+msgstr ""
+"\n"
+"MacOS X (unix) verzia"
+
+msgid ""
+"\n"
+"MacOS X version"
+msgstr ""
+"\n"
+"MacOS X verzia"
+
+msgid ""
+"\n"
+"MacOS version"
+msgstr ""
+"\n"
+"MacOS verzia"
+
+msgid ""
+"\n"
+"RISC OS version"
+msgstr ""
+"\n"
+"RISC OS verzia"
+
+msgid ""
+"\n"
+"Included patches: "
+msgstr ""
+"\n"
+"Použité záplaty: "
+
+msgid "Modified by "
+msgstr "Zmenil "
+
+msgid ""
+"\n"
+"Compiled "
+msgstr ""
+"\n"
+"Preložená "
+
+msgid "by "
+msgstr " "
+
+msgid ""
+"\n"
+"Huge version "
+msgstr ""
+"\n"
+"Maximálna verzia"
+
+msgid ""
+"\n"
+"Big version "
+msgstr ""
+"\n"
+"Ve¾ká verzia "
+
+msgid ""
+"\n"
+"Normal version "
+msgstr ""
+"\n"
+"Normálna verzia"
+
+msgid ""
+"\n"
+"Small version "
+msgstr ""
+"\n"
+"Malá verzia "
+
+msgid ""
+"\n"
+"Tiny version "
+msgstr ""
+"\n"
+"Minimálna verzia "
+
+msgid "without GUI."
+msgstr "bez grafického rozhrania."
+
+msgid "with GTK2-GNOME GUI."
+msgstr "s grafickým rozhraním GTK2-GNOME."
+
+msgid "with GTK-GNOME GUI."
+msgstr "s grafickým rozhraním GTK-GNOME."
+
+msgid "with GTK2 GUI."
+msgstr "s grafickým rozhraním GTK2."
+
+msgid "with GTK GUI."
+msgstr "s grafickým rozhraním GTK."
+
+msgid "with X11-Motif GUI."
+msgstr "s grafickým rozhraním X11-Motif."
+
+msgid "with X11-neXtaw GUI."
+msgstr "s grafickým rozhraním X11-neXtaw."
+
+msgid "with X11-Athena GUI."
+msgstr "s grafickým rozhraním X11-Athena."
+
+msgid "with Photon GUI."
+msgstr "s grafickým rozhraním Photon."
+
+msgid "with GUI."
+msgstr "s grafickým rozhraním."
+
+msgid "with Carbon GUI."
+msgstr "s grafickým rozhraním Carbon."
+
+msgid "with Cocoa GUI."
+msgstr "s grafickým rozhraním Cocoa."
+
+msgid "with (classic) GUI."
+msgstr "s klasickým grafickým rozhraním."
+
+msgid "with KDE GUI."
+msgstr "s grafickým rozhraním KDE."
+
+msgid " Features included (+) or not (-):\n"
+msgstr " Vlastnosti zahrnuté (+) a nezahrnuté (-):\n"
+
+msgid " system vimrc file: \""
+msgstr " systémový vimrc súbor: \""
+
+msgid " user vimrc file: \""
+msgstr " užívate¾ský vimrc súbor: \""
+
+msgid " 2nd user vimrc file: \""
+msgstr " druhý užívate¾ský vimrc súbor: \""
+
+msgid " 3rd user vimrc file: \""
+msgstr " tretí užívate¾ský vimrc súbor: \""
+
+msgid " user exrc file: \""
+msgstr " užívate¾ský exrc súbor: \""
+
+msgid " 2nd user exrc file: \""
+msgstr " druhý užívate¾ský exrc súbor: \""
+
+msgid " system gvimrc file: \""
+msgstr " systémový gvimrc súbor: \""
+
+msgid " user gvimrc file: \""
+msgstr " užívate¾ský gvimrc súbor: \""
+
+msgid "2nd user gvimrc file: \""
+msgstr "druhý užívate¾ský gvimrc súbor: \""
+
+msgid "3rd user gvimrc file: \""
+msgstr "tretí užívate¾ský gvimrc súbor: \""
+
+msgid " system menu file: \""
+msgstr " systémový súbor s ponukou: \""
+
+msgid " fall-back for $VIM: \""
+msgstr " implicitná hodnota $VIM:\""
+
+msgid " f-b for $VIMRUNTIME: \""
+msgstr " f-b pre $VIMRUNTIME: \""
+
+msgid "Compilation: "
+msgstr "Preklad: "
+
+msgid "Compiler: "
+msgstr "Prekladaè: "
+
+msgid "Linking: "
+msgstr "Zlinkované: "
+
+msgid " DEBUG BUILD"
+msgstr " PODPORA LADENIA"
+
+msgid "VIM - Vi IMproved"
+msgstr "VIM - Vi IMproved"
+
+msgid "version "
+msgstr "verzia "
+
+msgid "by Bram Moolenaar et al."
+msgstr "od Brama Moolenaara a ïalších"
+
+msgid "Vim is open source and freely distributable"
+msgstr "Vim je vo¾ne šírite¾ný program s otvoreným kódom"
+
+msgid "Help poor children in Uganda!"
+msgstr "Pomôžte chudobným deom v Ugande!"
+
+msgid "type :help iccf<Enter> for information "
+msgstr "zadajte :help iccf<Enter> pre informácie "
+
+msgid "type :q<Enter> to exit "
+msgstr "zadajte :q<Enter> pre ukonèenie programu "
+
+msgid "type :help<Enter> or <F1> for on-line help"
+msgstr "zadajte :help<Enter> alebo <F1> pre pomocníka "
+
+msgid "type :help version8<Enter> for version info"
+msgstr "zadajte :help version8<Enter> pre informácie o verzii"
+
+msgid "Running in Vi compatible mode"
+msgstr "Pracujem v režime kompatibility s Vi"
+
+msgid "type :set nocp<Enter> for Vim defaults"
+msgstr "zadajte :set nocp<Enter> pre implicitné nastavenie Vim"
+
+msgid "type :help cp-default<Enter> for info on this"
+msgstr "podrobnejšie informácie získate pomocou :help cp-default<Enter>"
+
+msgid "menu Help->Orphans for information "
+msgstr "bližšie informácie v ponuke Pomocník->Samostatné"
+
+msgid "Running modeless, typed text is inserted"
+msgstr "Spúšam v bezmódovom režime, písaný text je vložený"
+
+msgid "menu Edit->Global Settings->Toggle Insert Mode "
+msgstr "ponuka Úpravy->Globálne možnosti->Prepnú režim vloženia "
+
+msgid " for two modes "
+msgstr " pre dva režimy "
+
+msgid "menu Edit->Global Settings->Toggle Vi Compatible"
+msgstr "ponuka Úpravy->Globálne možnostt->Prepnú Vi kompatibilný režim"
+
+msgid " for Vim defaults "
+msgstr " pre predvolené vlastnosti Vim "
+
+msgid "Sponsor Vim development!"
+msgstr "Zasponzorujte vývoj Vimu!"
+
+msgid "Become a registered Vim user!"
+msgstr "Staòte sa registrovaným užívate¾om Vimu!"
+
+msgid "type :help sponsor<Enter> for information "
+msgstr "zadajte :help sponsor<Enter> pre informácie "
+
+msgid "type :help register<Enter> for information "
+msgstr "zadajte :help register<Enter> pre informácie "
+
+msgid "menu Help->Sponsor/Register for information "
+msgstr "bližšie informácie v ponuke Pomocník->Sponzor/Registrácia"
+
+msgid "WARNING: Windows 95/98/ME detected"
+msgstr "VAROVANIE: detekované Windows 95/98/ME"
+
+msgid "type :help windows95<Enter> for info on this"
+msgstr "zadajte :help windows95<Enter> pre podrobnejšie informácie"
+
+msgid "E441: There is no preview window"
+msgstr "E441: Nenájdené žiadne okno náh¾adu"
+
+msgid "E442: Can't split topleft and botright at the same time"
+msgstr ""
+"E442: Okno sa nedá rozdeli zároveò v móde 'vrchný-¾avý' a 'spodný-"
+"pravý' ('topleft' a 'botright')"
+
+msgid "E443: Cannot rotate when another window is split"
+msgstr "E443: Nedá sa rotova, ak je iné okno rozdelené"
+
+msgid "E444: Cannot close last window"
+msgstr "E444: Posledné okno sa nedá zatvori"
+
+msgid "Already only one window"
+msgstr "Existuje už iba jedno okno"
+
+msgid "E445: Other window contains changes"
+msgstr "E445: Iné okno obsahuje zmeny"
+
+msgid "E446: No file name under cursor"
+msgstr "E446: Pod kurzorom sa nenachádza názov súboru"
+
+#, c-format
+msgid "E447: Can't find file \"%s\" in path"
+msgstr "E447: Súbor \"%s\" sa nedá nájs v ceste"
+
+#, c-format
+msgid "E370: Could not load library %s"
+msgstr "E370: Nepodarilo sa nahra knižnicu %s"
+
+msgid "Sorry, this command is disabled: the Perl library could not be loaded."
+msgstr "Prepáète, tento príkaz je vypnutý, Perl knižnica nemôže by naèítaná."
+
+msgid "E299: Perl evaluation forbidden in sandbox without the Safe module"
+msgstr "E299: Vykonanie kódu v jazyku Perl nie je možné v bezpeènostnej schránke bez bezpeènostného modulu"
+
+msgid "Edit with &multiple Vims"
+msgstr "Upravi s viacerý&mi Vimmi"
+
+msgid "Edit with single &Vim"
+msgstr "Upravi s jedným &Vimom"
+
+msgid "Diff with Vim"
+msgstr "Porovna &Vimom"
+
+msgid "Edit with &Vim"
+msgstr "Upravi s &Vimom"
+
+#. Now concatenate
+msgid "Edit with existing Vim - "
+msgstr "Upravi s existujúcim Vimom - "
+
+msgid "Edits the selected file(s) with Vim"
+msgstr "Upravi vybrané súbory s Vimom"
+
+msgid "Error creating process: Check if gvim is in your path!"
+msgstr "Chyba vytvárania procesu: Skontrolujte, èi je gvim vo vašej ceste!"
+
+msgid "gvimext.dll error"
+msgstr "chyba gvimext.dll"
+
+msgid "Path length too long!"
+msgstr "Príliš dlhá cesta!"
+
+msgid "--No lines in buffer--"
+msgstr "--Buffer neobsahuje žiadne riadky--"
+
+#.
+#. * The error messages that can be shared are included here.
+#. * Excluded are errors that are only used once and debugging messages.
+#.
+msgid "E470: Command aborted"
+msgstr "E470: Príkaz prerušený"
+
+msgid "E471: Argument required"
+msgstr "E471: Je vyžadovaný argument"
+
+msgid "E10: \\ should be followed by /, ? or &"
+msgstr "E10: po \\ by malo nasledova /, ? alebo &"
+
+msgid "E11: Invalid in command-line window; <CR> executes, CTRL-C quits"
+msgstr ""
+"E11: Chybný príkaz v okne príkazového riadku; <Enter> spúša, CTRL-C ukonèuje"
+
+msgid "E12: Command not allowed from exrc/vimrc in current dir or tag search"
+msgstr ""
+"E12: Príkaz nie je z exrc/vimrc v aktuálnom adresári alebo pri h¾adaní tagu "
+"povolený."
+
+msgid "E171: Missing :endif"
+msgstr "E171: Chýba :endif"
+
+msgid "E600: Missing :endtry"
+msgstr "E600: Chýba :endtry"
+
+msgid "E170: Missing :endwhile"
+msgstr "E170: Chýba :endwhile"
+
+msgid "E170: Missing :endfor"
+msgstr "E170: Chýba :endfor"
+
+msgid "E588: :endwhile without :while"
+msgstr "E588: :endwhile bez zodpovedajúceho :while"
+
+msgid "E588: :endfor without :for"
+msgstr "E588: :endfor bez zodpovedajúceho :for"
+
+msgid "E13: File exists (add ! to override)"
+msgstr "E13: Súbor existuje (použite ! pre prepísanie)"
+
+msgid "E472: Command failed"
+msgstr "E472: Príkaz zlyhal"
+
+#, c-format
+msgid "E234: Unknown fontset: %s"
+msgstr "E234: Neznáma sada písiem: %s"
+
+#, c-format
+msgid "E235: Unknown font: %s"
+msgstr "E235: Neznáme písmo: %s"
+
+#, c-format
+msgid "E236: Font \"%s\" is not fixed-width"
+msgstr "E236: Písmo \"%s\" nemá pevnú šírku"
+
+msgid "E473: Internal error"
+msgstr "E473: Vnútorná chyba"
+
+msgid "Interrupted"
+msgstr "Prerušené"
+
+msgid "E14: Invalid address"
+msgstr "E14: Chybná adresa"
+
+msgid "E474: Invalid argument"
+msgstr "E474: Chybný argument"
+
+#, c-format
+msgid "E475: Invalid argument: %s"
+msgstr "E475: Chybný argument: %s"
+
+#, c-format
+msgid "E15: Invalid expression: %s"
+msgstr "E15: Chybný výraz: %s"
+
+msgid "E16: Invalid range"
+msgstr "E16: Chybný rozsah"
+
+msgid "E476: Invalid command"
+msgstr "E476: Chybný príkaz"
+
+#, c-format
+msgid "E17: \"%s\" is a directory"
+msgstr "E17: \"%s\" je adresárom"
+
+#, c-format
+msgid "E364: Library call failed for \"%s()\""
+msgstr "E364: Vyvolanie knižniènej funkcia zlyhalo pre \"%s()\""
+
+#, c-format
+msgid "E448: Could not load library function %s"
+msgstr "E448: Nepodarilo sa nahra funkciu knižnice %s"
+
+msgid "E19: Mark has invalid line number"
+msgstr "E19: Znaèka má chybné èíslo riadku"
+
+msgid "E20: Mark not set"
+msgstr "E20: Znaèka nie je nastavená"
+
+msgid "E21: Cannot make changes, 'modifiable' is off"
+msgstr "E21: Nemožno robi zmeny, vo¾ba 'modifiable' je vypnutá"
+
+msgid "E22: Scripts nested too deep"
+msgstr "E22: Skripty vnorené príliš hlboko"
+
+msgid "E23: No alternate file"
+msgstr "E23: Žiadny alternatívny súbor"
+
+msgid "E24: No such abbreviation"
+msgstr "E24: Taká skratka neexistuje"
+
+msgid "E477: No ! allowed"
+msgstr "E477: ! nie je povolený"
+
+msgid "E25: GUI cannot be used: Not enabled at compile time"
+msgstr "E25: Nedá sa použí GUI: nebolo zapnuté pri preklade programu"
+
+msgid "E26: Hebrew cannot be used: Not enabled at compile time\n"
+msgstr ""
+"E26: Nedá sa použí hebrejský režim: nebol zapnutý pri preklade programu\n"
+
+msgid "E27: Farsi cannot be used: Not enabled at compile time\n"
+msgstr "E27: Nedá sa použí farsi režim: nebol zapnutý pri preklade programu\n"
+
+msgid "E800: Arabic cannot be used: Not enabled at compile time\n"
+msgstr "E800: Nedá sa použí arabic režim: nebol zapnutý pri preklade programu\n"
+
+#, c-format
+msgid "E28: No such highlight group name: %s"
+msgstr "E28: Skupina zvýraznenia %s neexistuje"
+
+msgid "E29: No inserted text yet"
+msgstr "E29: Zatia¾ nie je vložený žiaden text"
+
+msgid "E30: No previous command line"
+msgstr "E30: Žiadny predchádzajúci príkazový riadok"
+
+msgid "E31: No such mapping"
+msgstr "E31: Mapovanie nenájdené"
+
+msgid "E479: No match"
+msgstr "E479: Žiadna zhoda"
+
+#, c-format
+msgid "E480: No match: %s"
+msgstr "E480: Žiadna zhoda: %s"
+
+msgid "E32: No file name"
+msgstr "E32: Žiadny názov súboru"
+
+msgid "E33: No previous substitute regular expression"
+msgstr "E33: Žiadny predchádzajúci prislúchajúci správny výraz"
+
+msgid "E34: No previous command"
+msgstr "E34: Žiadny predchádzajúci príkaz"
+
+msgid "E35: No previous regular expression"
+msgstr "E35: Žiadny predchádzajúci regulárny výraz"
+
+msgid "E481: No range allowed"
+msgstr "E481: Rozsah nie je povolený"
+
+msgid "E36: Not enough room"
+msgstr "E36: Nedostatok miesta"
+
+#, c-format
+msgid "E247: no registered server named \"%s\""
+msgstr "E247: žiaden registrovaný server pomenovaný \"%s\""
+
+#, c-format
+msgid "E482: Can't create file %s"
+msgstr "E482: Nedá sa vytvori súbor %s"
+
+msgid "E483: Can't get temp file name"
+msgstr "E483: Nedá sa získa názov doèasného súboru"
+
+#, c-format
+msgid "E484: Can't open file %s"
+msgstr "E484: Nedá sa otvori súbor %s"
+
+#, c-format
+msgid "E485: Can't read file %s"
+msgstr "E485: Nedá sa èíta súbor %s"
+
+msgid "E37: No write since last change (add ! to override)"
+msgstr "E37: Neuložené zmeny (použite ! pre vynútenie)"
+
+msgid "E38: Null argument"
+msgstr "E38: Nulový argument"
+
+msgid "E39: Number expected"
+msgstr "E39: Oèakávané èíslo"
+
+#, c-format
+msgid "E40: Can't open errorfile %s"
+msgstr "E40: Nedá sa otvori chybový súbor %s"
+
+msgid "E233: cannot open display"
+msgstr "E233: nedá sa otvori displej"
+
+msgid "E41: Out of memory!"
+msgstr "E41: Nedostatok pamäti!"
+
+msgid "Pattern not found"
+msgstr "Vzor nenájdený"
+
+#, c-format
+msgid "E486: Pattern not found: %s"
+msgstr "E486: Vzor nenájdený: %s"
+
+msgid "E487: Argument must be positive"
+msgstr "E487: Argument musí by kladný"
+
+msgid "E459: Cannot go back to previous directory"
+msgstr "E459: Žiadny predchádzajúci adresár"
+
+msgid "E42: No Errors"
+msgstr "E42: Žiadne chyby"
+
+msgid "E43: Damaged match string"
+msgstr "E43: Poškodený reazac pre vyh¾adávanie"
+
+msgid "E44: Corrupted regexp program"
+msgstr "E44: Poškodený regexp program"
+
+msgid "E45: 'readonly' option is set (add ! to override)"
+msgstr ""
+"E45: vo¾ba 'readonly' (iba na èítanie) je nastavená (použite ! pre "
+"prepísanie)"
+
+#, c-format
+msgid "E46: Cannot change read-only variable \"%s\""
+msgstr "E46: Nedá sa nastavi premenná len na èítanie \"%s\""
+
+#, c-format
+msgid "E46: Cannot set variable in the sandbox: \"%s\""
+msgstr "E46: Nedá sa nastavi premenná v bezpeènostnej schránke: \"%s\""
+
+msgid "E47: Error while reading errorfile"
+msgstr "E47: Chyba pri èítaní chybového súboru"
+
+msgid "E48: Not allowed in sandbox"
+msgstr "E48: Nie je dovolené v bezpeènostnej schránke"
+
+msgid "E523: Not allowed here"
+msgstr "E523: Nie je na povolené na tomto mieste"
+
+msgid "E359: Screen mode setting not supported"
+msgstr "E359: Nastavovanie režimu obrazovky nie je podporované"
+
+msgid "E49: Invalid scroll size"
+msgstr "E49: Chybná hodnota ve¾kosti rolovania"
+
+msgid "E91: 'shell' option is empty"
+msgstr "E91: vo¾ba 'shell' je prázdna"
+
+msgid "E255: Couldn't read in sign data!"
+msgstr "E255: Chyba -- nedájú sa preèíta oznaèovacie dáta!"
+
+msgid "E72: Close error on swap file"
+msgstr "E72: Chyba pri uzatváraní odkladacieho súboru"
+
+msgid "E73: tag stack empty"
+msgstr "E73: zoznam tagov je prázdny"
+
+msgid "E74: Command too complex"
+msgstr "E74: Príkaz je príliš zložitý"
+
+msgid "E75: Name too long"
+msgstr "E75: Názov je príliš dlhý"
+
+msgid "E76: Too many ["
+msgstr "E76: Príliš mnoho ["
+
+msgid "E77: Too many file names"
+msgstr "E77: Príliš mnoho názvov súborov"
+
+msgid "E488: Trailing characters"
+msgstr "E488: Nadbytoèné znaky na konci"
+
+msgid "E78: Unknown mark"
+msgstr "E78: Neznáma znaèka"
+
+msgid "E79: Cannot expand wildcards"
+msgstr "E79: Nemožno expandova žolíkové znaky (wildcards)"
+
+msgid "E591: 'winheight' cannot be smaller than 'winminheight'"
+msgstr ""
+"E591: hodnota vo¾by 'winheight' (výška okna) nesmie by menšia než hodnota vo¾by 'winminheight' (minimálna výška okna)"
+
+msgid "E592: 'winwidth' cannot be smaller than 'winminwidth'"
+msgstr ""
+"E592: hodnota vo¾by 'winwidth' (šírka okna) nesmie by menšia než hodnota vol¾y 'winminwidth' (minimálna šírka okna)"
+
+msgid "E80: Error while writing"
+msgstr "E80: Chyba pri ukladaní"
+
+msgid "Zero count"
+msgstr "Nulový poèet"
+
+msgid "E81: Using <SID> not in a script context"
+msgstr "E81: Použitie <SID> mimo kontext skriptu"
+
+msgid "E449: Invalid expression received"
+msgstr "E449: Bol prijatý chybný výraz"
+
+msgid "E463: Region is guarded, cannot modify"
+msgstr "E463: Región je uzamknutý, nemožno modifikova"
+
+msgid "E744: NetBeans does not allow changes in read-only files"
+msgstr "E744: NetBeans nepovo¾uje zmeny v súboroch len na èítanie"
+
+#, c-format
+msgid "E685: Internal error: %s"
+msgstr "E685: Vnútorná chyba: %s"
+
+msgid "E363: pattern uses more memory than 'maxmempattern'"
+msgstr "E363: vzor používa viac pamäte ako 'maxmempattern'"
+
+msgid "E749: empty buffer"
+msgstr "E749: prázdny buffer"
+
+msgid "E682: Invalid search pattern or delimiter"
+msgstr "E682: Neprípustný h¾adaný reazec alebo odde¾ovaè"
+
+msgid "E139: File is loaded in another buffer"
+msgstr "E139: Súbor je naèítaný v inom buffere"
+
+#, c-format
+msgid "E764: Option '%s' is not set"
+msgstr "E764: Vo¾ba \"%s\" nie je nastavená"
+
+msgid "search hit TOP, continuing at BOTTOM"
+msgstr "h¾adanie dosiahlo zaèiatok, pokraèovanie od konca"
+
+msgid "search hit BOTTOM, continuing at TOP"
+msgstr "h¾adanie dosiahlo koniec, pokraèovanie od zaèiatku"
+
diff --git a/src/po/sk.po b/src/po/sk.po
new file mode 100644
index 0000000..602d226
--- /dev/null
+++ b/src/po/sk.po
@@ -0,0 +1,5822 @@
+# Slovak translation of vim
+# Lubomir Host 'rajo' <rajo AT platon.sk>
+# 2005 - Platon Group, http://platon.sk/
+# $Revision: 1.4 $
+# $LastChangedDate: 2005-10-08 12:00:24 +0200 (Sat, 08 Oct 2005) $
+msgid ""
+msgstr ""
+"Project-Id-Version: vim\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2005-09-30 15:58+0200\n"
+"PO-Revision-Date: 2005-09-30 15:58+0200\n"
+"Last-Translator: Lubomir Host <rajo@platon.sk>\n"
+"Language-Team: Slovak <sk-i18n@lists.linux.sk>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-2\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Vim 7.x\n"
+
+msgid "E82: Cannot allocate any buffer, exiting..."
+msgstr "E82: Nedá sa alokova» buffer, konèím..."
+
+msgid "E83: Cannot allocate buffer, using other one..."
+msgstr "E83: Nedá sa alokova» buffer, pou¾ijem iný..."
+
+msgid "E515: No buffers were unloaded"
+msgstr "E515: ®iadny buffer nebol uvoµnený"
+
+msgid "E516: No buffers were deleted"
+msgstr "E516: ®iadny buffer nebol vymazaný"
+
+msgid "E517: No buffers were wiped out"
+msgstr "E517: ®iadny buffer nebol vymazaný"
+
+msgid "1 buffer unloaded"
+msgstr "1 buffer uvoµnený"
+
+#, c-format
+msgid "%d buffers unloaded"
+msgstr "%d bufferov uvoµnených"
+
+msgid "1 buffer deleted"
+msgstr "1 buffer vymazaný"
+
+#, c-format
+msgid "%d buffers deleted"
+msgstr "%d bufferov vymazaných"
+
+msgid "1 buffer wiped out"
+msgstr "1 buffer odstránený"
+
+#, c-format
+msgid "%d buffers wiped out"
+msgstr "%d bufferov odstránených"
+
+msgid "E84: No modified buffer found"
+msgstr "E84: Nebol nájdený ¾iadny zmenený buffer"
+
+#. back where we started, didn't find anything.
+msgid "E85: There is no listed buffer"
+msgstr "E85: Nena¹iel som ¾iadny buffer"
+
+msgid "E86: Buffer %ld does not exist"
+msgstr "E86: Buffer %ld neexistuje"
+
+msgid "E87: Cannot go beyond last buffer"
+msgstr "E87: Za posledný buffer sa nedá preskoèi»"
+
+msgid "E88: Cannot go before first buffer"
+msgstr "E88: Pred prvý buffer sa nedá preskoèi»"
+
+msgid "E89: No write since last change for buffer %ld (add ! to override)"
+msgstr "E89: Zmeny v bufferi %ld neboli ulo¾ené (! pre vynútenie)"
+
+msgid "E90: Cannot unload last buffer"
+msgstr "E90: Posledný buffer sa nedá odstráni»"
+
+msgid "W14: Warning: List of file names overflow"
+msgstr "W14: Varovanie: preteèenie zoznamu s názvami súborov"
+
+#, c-format
+msgid "E92: Buffer %ld not found"
+msgstr "E92: buffer %ld nenájdený"
+
+#, c-format
+msgid "E93: More than one match for %s"
+msgstr "E93: Vzoru %s vyhovuje viac bufferov"
+
+#, c-format
+msgid "E94: No matching buffer for %s"
+msgstr "E94: Vzoru %s nevyhovuje ¾iadny buffer"
+
+#, c-format
+msgid "line %ld"
+msgstr "riadok %ld"
+
+msgid "E95: Buffer with this name already exists"
+msgstr "E95: Buffer takéhoto mena u¾ existuje"
+
+msgid " [Modified]"
+msgstr " [Zmenený]"
+
+msgid "[Not edited]"
+msgstr "[Neupravovaný]"
+
+msgid "[New file]"
+msgstr "[Nový súbor]"
+
+msgid "[Read errors]"
+msgstr "[Chyby pri èítaní]"
+
+msgid "[readonly]"
+msgstr "[iba pre èítanie]"
+
+#, c-format
+msgid "1 line --%d%%--"
+msgstr "1 riadok --%d%%--"
+
+#, c-format
+msgid "%ld lines --%d%%--"
+msgstr "%ld riadkov --%d%%--"
+
+#, c-format
+msgid "line %ld of %ld --%d%%-- col "
+msgstr "riadok %ld z %ld --%d%%-- ståpec"
+
+msgid "[No Name]"
+msgstr "[Bez mena]"
+
+#. must be a help buffer
+msgid "help"
+msgstr "pomocník"
+
+msgid "[help]"
+msgstr "[pomocník]"
+
+msgid "[Preview]"
+msgstr "[Náhµad]"
+
+msgid "All"
+msgstr "V¹etko"
+
+msgid "Bot"
+msgstr "Koniec"
+
+msgid "Top"
+msgstr "Zaèiatok"
+
+#, c-format
+msgid ""
+"\n"
+"# Buffer list:\n"
+msgstr ""
+"\n"
+"# Zoznam bufferov:\n"
+
+msgid "[Error List]"
+msgstr "[Zoznam chýb]"
+
+msgid ""
+"\n"
+"--- Signs ---"
+msgstr ""
+"\n"
+"--- Znaky ---"
+
+#, c-format
+msgid "Signs for %s:"
+msgstr "Znaky pre %s:"
+
+#, c-format
+msgid " line=%ld id=%d name=%s"
+msgstr " riadok=%ld id=%d meno=%s"
+
+#, c-format
+msgid "E96: Can not diff more than %ld buffers"
+msgstr "E96: Nemô¾em porovna» viac ako %ld bufferov"
+
+msgid "E97: Cannot create diffs"
+msgstr "E97: Nedajú sa vytvori» porovnania"
+
+msgid "Patch file"
+msgstr "Záplatový súbor"
+
+msgid "E98: Cannot read diff output"
+msgstr "E98: Nedá sa èíta» výstup porovnania"
+
+msgid "E99: Current buffer is not in diff mode"
+msgstr "E99: Aktuálny buffer nie je v porovnávacom móde"
+
+msgid "E100: No other buffer in diff mode"
+msgstr "E100: V porovnávacom móde sa nenachádza iný buffer"
+
+msgid "E101: More than two buffers in diff mode, don't know which one to use"
+msgstr "E101: Viac ako dva buffery v porovnávacom móde; neviem, ktorý pou¾i»"
+
+#, c-format
+msgid "E102: Can't find buffer \"%s\""
+msgstr "E102: Nedá sa nájs» buffer \"%s\""
+
+#, c-format
+msgid "E103: Buffer \"%s\" is not in diff mode"
+msgstr "E103: Buffer \"%s\" nie je v porovnávacom móde"
+
+# TODO: digraph
+msgid "E104: Escape not allowed in digraph"
+msgstr "E104: digraph nesmie obsahova» znak Escape"
+
+msgid "E544: Keymap file not found"
+msgstr "E544: Mapa kláves nenájdená"
+
+msgid "E105: Using :loadkeymap not in a sourced file"
+msgstr "E105: Pou¾itý príkaz :loadkeymap v súbore, ktorý nie je interpretovaný"
+
+msgid " Keyword completion (^N^P)"
+msgstr " Doplòovanie kµúèových slov (^N^P)"
+
+#. ctrl_x_mode == 0, ^P/^N compl.
+msgid " ^X mode (^]^D^E^F^I^K^L^N^O^P^S^U^V^Y)"
+msgstr " ^X re¾im (^]^D^E^F^I^K^L^N^O^P^S^U^V^Y)"
+
+msgid " Whole line completion (^L^N^P)"
+msgstr " Doplòovanie celých riadkov (^L^N^P)"
+
+msgid " File name completion (^F^N^P)"
+msgstr " Doplòovanie názvov súborov (^F^N^P)"
+
+msgid " Tag completion (^]^N^P)"
+msgstr " Doplòovanie tagov (^]^N^P)"
+
+msgid " Path pattern completion (^N^P)"
+msgstr " Doplòovanie vzoru ciest (^N^P)"
+
+msgid " Definition completion (^D^N^P)"
+msgstr " Doplòovanie definícií (^D^N^P)"
+
+msgid " Dictionary completion (^K^N^P)"
+msgstr " Doplòovanie podµa slovníka (^K^N^P)"
+
+msgid " Thesaurus completion (^T^N^P)"
+msgstr " Doplòovanie podµa lexikonu (^T^N^P)"
+
+msgid " Command-line completion (^V^N^P)"
+msgstr " Doplòovanie príkazového riadka (^V^N^P)"
+
+msgid " User defined completion (^U^N^P)"
+msgstr " Doplòovanie celých riadkov (^U^N^P)"
+
+msgid " Omni completion (^O^N^P)"
+msgstr " Doplòovanie tagov (^O^N^P)"
+
+msgid " Spelling suggestion (^S^N^P)"
+msgstr " Doplòovanie celých riadkov (^S^N^P)"
+
+msgid " Keyword Local completion (^N^P)"
+msgstr " Miestne doplòovanie kµúèových slov (^N^P)"
+
+msgid "Hit end of paragraph"
+msgstr "Koniec odstavca"
+
+msgid "'dictionary' option is empty"
+msgstr "voµba 'dictionary' (slovník) je prázdna"
+
+msgid "'thesaurus' option is empty"
+msgstr "voµba 'thesaurus' (lexikon) je prázdna"
+
+#, c-format
+msgid "Scanning dictionary: %s"
+msgstr "prehµadávam slovník %s"
+
+msgid " (insert) Scroll (^E/^Y)"
+msgstr " (insert) Rolovanie (^E/^Y)"
+
+msgid " (replace) Scroll (^E/^Y)"
+msgstr " (replace) Rolovanie (^E/^Y)"
+
+#, c-format
+msgid "Scanning: %s"
+msgstr "Prehµadávam: %s"
+
+#, c-format
+msgid "Scanning tags."
+msgstr "Prehµadávam tagy."
+
+msgid " Adding"
+msgstr " Pridávam"
+
+#. showmode might reset the internal line pointers, so it must
+#. * be called before line = ml_get(), or when this address is no
+#. * longer needed. -- Acevedo.
+#.
+msgid "-- Searching..."
+msgstr "-- Hµadám..."
+
+msgid "Back at original"
+msgstr "Východzia podoba"
+
+msgid "Word from other line"
+msgstr "Slovo z iného riadku"
+
+msgid "The only match"
+msgstr "Jediná zhoda"
+
+#, c-format
+msgid "match %d of %d"
+msgstr "zhoda %d z %d"
+
+#, c-format
+msgid "match %d"
+msgstr "zhoda %d"
+
+msgid "E18: Unexpected characters in :let"
+msgstr "E18: Neoèekávané znaky v :let"
+
+msgid "E684: list index out of range: %ld"
+msgstr "E684: index v zozname je mimo rozsah: %ld"
+
+#, c-format
+msgid "E121: Undefined variable: %s"
+msgstr "E121: Nedefinovaná premenná: %s"
+
+msgid "E111: Missing ']'"
+msgstr "E111: Chýba ']'"
+
+msgid "E686: Argument of %s must be a List"
+msgstr "E686: Argument %s musí by» Zoznam (List)"
+
+#, c-format
+msgid "E712: Argument of %s must be a List or Dictionary"
+msgstr "E712: Argument %s musí by» Zoznam (List) alebo Slovník (Dictionary)"
+
+msgid "E713: Cannot use empty key for Dictionary"
+msgstr "E713: Nemo¾no pou¾i» prázdny kµúè pre Slovník (Dictionary)"
+
+msgid "E714: List required"
+msgstr "E714: vy¾aduje sa Zoznam (List)"
+
+msgid "E715: Dictionary required"
+msgstr "E715: Vy¾aduje sa Slovník (Dictionary)"
+
+#, c-format
+msgid "E118: Too many arguments for function: %s"
+msgstr "E118: Príli¹ mnoho argumentov pre funkciu %s"
+
+#, c-format
+msgid "E716: Key not present in Dictionary: %s"
+msgstr "E716: kµúè sa v Slovníku (Dictionary) nenachádza: %s"
+
+msgid "E122: Function %s already exists, add ! to replace it"
+msgstr "E122: Funkcia %s u¾ existuje. Pou¾ite ! pre jej nahradenie."
+
+msgid "E717: Dictionary entry already exists"
+msgstr "E717: Záznam v Slovníku (Dictionary) u¾ existuje"
+
+msgid "E718: Funcref required"
+msgstr "E718: Je vy¾adovaný odkaz na Funkciu (Funcref)"
+
+msgid "E719: Cannot use [:] with a Dictionary"
+msgstr "E719: Nemo¾no pou¾it [:] so Slovníkom (Dictionary)"
+
+#, c-format
+msgid "E734: Wrong variable type for %s="
+msgstr "E734: Zlý typ premennej pre %s="
+
+msgid "E130: Unknown function: %s"
+msgstr "E130: Neznáma funkcia: %s"
+
+msgid "E461: Illegal variable name: %s"
+msgstr "E461: Neprípustné meno premennej: %s"
+
+msgid "E687: Less targets than List items"
+msgstr "E687: Menej cieµov ako polo¾iek Poµa (List items)"
+
+msgid "E688: More targets than List items"
+msgstr "E688: Viac cieµov ako polo¾iek Poµa (List items)"
+
+msgid "Double ; in list of variables"
+msgstr "Dvojitá ; v zozname premenných"
+
+msgid "E738: Can't list variables for %s"
+msgstr "E738: Nemo¾no vypísa» premenné pre %s"
+
+msgid "E689: Can only index a List or Dictionary"
+msgstr "E689: Indexova» mo¾no iba Zoznam (List) alebo Slovník (Dictionary)"
+
+msgid "E708: [:] must come last"
+msgstr "E708: [:] musí prís» ako posledná"
+
+msgid "E709: [:] requires a List value"
+msgstr "E709: [:] vy¾aduje hodnotu Poµa (List value)"
+
+msgid "E710: List value has more items than target"
+msgstr "E710: Hodnota Poµa (List value) má viac polo¾iek ako cieµ"
+
+msgid "E711: List value has not enough items"
+msgstr "E711: Hodnota Poµa (List value) nemá dostatok polo¾iek"
+
+msgid "E690: Missing \"in\" after :for"
+msgstr "E690: Chýba \"in\" po :for"
+
+#, c-format
+msgid "E107: Missing parentheses: %s"
+msgstr "E107: Chýbajú zátvorky: %s"
+
+#, c-format
+msgid "E108: No such variable: \"%s\""
+msgstr "E108: Premenná \"%s\" neexistuje"
+
+msgid "E743: variable nested too deep for (un)lock"
+msgstr "E743: premenná je príli¹ vnorená na (od)blokovanie"
+
+msgid "E109: Missing ':' after '?'"
+msgstr "E109: Po '?' chýba ':'"
+
+msgid "E691: Can only compare List with List"
+msgstr "E691: Porovnáva» mo¾no iba Zoznam so Zoznamom (List with List)"
+
+msgid "E692: Invalid operation for List"
+msgstr "E692: Neplatná operácia pre Zoznamy (List)"
+
+msgid "E735: Can only compare Dictionary with Dictionary"
+msgstr "E735: Porovnáva» mo¾no iba Slovník so Slovníkom (Dictionary with Dictionary)"
+
+msgid "E736: Invalid operation for Dictionary"
+msgstr "E736: Neplatná operácia pre Slovník"
+
+msgid "E693: Can only compare Funcref with Funcref"
+msgstr "E693: Porovnáva» mo¾no iba odkaz na Funkciu s odkazom na Funkciu (Funcref with Funcref)"
+
+msgid "E694: Invalid operation for Funcrefs"
+msgstr "E694: Neplatná operácia pre odkazy na Funkcie (Funcrefs)"
+
+msgid "E110: Missing ')'"
+msgstr "E110: Chýba ')'"
+
+msgid "E695: Cannot index a Funcref"
+msgstr "E695: Nemo¾no indexova» odkaz na Funkciu (Funcref)"
+
+#, c-format
+msgid "E112: Option name missing: %s"
+msgstr "E112: Chýba meno voµby: %s"
+
+#, c-format
+msgid "E113: Unknown option: %s"
+msgstr "E113: Neznáma voµba: %s"
+
+#, c-format
+msgid "E114: Missing quote: %s"
+msgstr "E114: Chýbajú úvodzovky: %s"
+
+#, c-format
+msgid "E115: Missing quote: %s"
+msgstr "E115: Chýbajú úvodzovky: %s"
+
+msgid "E696: Missing comma in List: %s"
+msgstr "E696: Chýba èiarka v Zozname: %s"
+
+msgid "E697: Missing end of List ']': %s"
+msgstr "E697: Chýba koniec Zoznamu (List) ']': %s"
+
+msgid "E720: Missing colon in Dictionary: %s"
+msgstr "E720: Chýba dvojbodka v Slovníku (Dictionary): %s"
+
+#, c-format
+msgid "E721: Duplicate key in Dictionary: \"%s\""
+msgstr "E721: Duplikovaný kµúè v Slovníku (Dictionary): \"%s\""
+
+msgid "E722: Missing comma in Dictionary: %s"
+msgstr "E722: Chýba èiarka v Slovníku (Dictionary): %s"
+
+msgid "E723: Missing end of Dictionary '}': %s"
+msgstr "E723: Chýba koniec Slovníka (Dictionary) '}': %s"
+
+msgid "E724: variable nested too deep for displaying"
+msgstr "E724: premenná je vnorená príli¹ hlboko pre zobrazenie"
+
+msgid "E699: Too many arguments"
+msgstr "E699: Príli¹ mnoho argumentov"
+
+#.
+#. * Yes this is ugly, I don't particularly like it either. But doing it
+#. * this way has the compelling advantage that translations need not to
+#. * be touched at all. See below what 'ok' and 'ync' are used for.
+#.
+msgid "&Ok"
+msgstr "&Ok"
+
+msgid "E737: Key already exists: %s"
+msgstr "E737: Kµúè u¾ existuje: %s"
+
+#, c-format
+msgid "+-%s%3ld lines: "
+msgstr "+-%s%3ld riadky: "
+
+msgid "E700: Unknown function: %s"
+msgstr "E700: Neznáma funkcia: %s"
+
+msgid ""
+"&OK\n"
+"&Cancel"
+msgstr ""
+"&OK\n"
+"&Zru¹i»"
+
+msgid "called inputrestore() more often than inputsave()"
+msgstr "funkcia inputrestore() volaná èastej¹ie ako inputsave()"
+
+msgid "E745: Range not allowed"
+msgstr "E745: Rozsah nie je povolený"
+
+msgid "E701: Invalid type for len()"
+msgstr "E701: Neplatný typ pre len()"
+
+msgid "E726: Stride is zero"
+msgstr "E726: Krok je nulový"
+
+msgid "E727: Start past end"
+msgstr "E727: Zaèiatok presahuje koniec"
+
+msgid "<empty>"
+msgstr "<prázdny>"
+
+msgid "E240: No connection to Vim server"
+msgstr "E240: Neexistuje pripojenie k Vim serveru"
+
+#, c-format
+msgid "E241: Unable to send to %s"
+msgstr "E241: Nemô¾em posla» na %s"
+
+msgid "E277: Unable to read a server reply"
+msgstr "E277: Nemô¾em èíta» odpoveï servra"
+
+msgid "E655: Too many symbolic links (cycle?)"
+msgstr "E655: Príli¹ mnoho symbolických odkazov (sluèka?)"
+
+msgid "E258: Unable to send to client"
+msgstr "E258: Nemô¾em posla» klientovi"
+
+msgid "E702: Sort compare function failed"
+msgstr "E702: Funkcia na utriedenie/porovnanie zlyhala"
+
+msgid "(Invalid)"
+msgstr "(Chybný)"
+
+msgid "E677: Error writing temp file"
+msgstr "E677: Chyba pri zápise doèasného súboru"
+
+msgid "E703: Using a Funcref as a Number"
+msgstr "E703: Pou¾itý odkaz na Funkciu (Funcref) ako èíslo"
+
+msgid "E745: Using a List as a Number"
+msgstr "E745: Zoznam (List) pou¾itý ako èíslo"
+
+msgid "E728: Using a Dictionary as a Number"
+msgstr "E728: Slovník (Dictionary) pou¾itý ako èíslo"
+
+msgid "E729: using Funcref as a String"
+msgstr "E729: Odkaz na Funkciu (Funcref) pou¾itý ako Re»azec (String)"
+
+msgid "E730: using List as a String"
+msgstr "E730: Zoznam (List) pou¾itý ako Re»azec (String)"
+
+msgid "E731: using Dictionary as a String"
+msgstr "E731: Slovník (Dictionary) pou¾itý ako Re»azec (String)"
+
+msgid "E704: Funcref variable name must start with a capital: %s"
+msgstr "E704: Premenná typu odkaz na Funkciu (Funcref) musí zaèína» s veµkým písmenom: %s"
+
+#, c-format
+msgid "E705: Variable name conflicts with existing function: %s"
+msgstr "E705: Meno premennej je v konflikte s existujúcou funkciou: %s"
+
+msgid "E706: Variable type mismatch for: %s"
+msgstr "E706: Typ premennej sa nezhoduje: %s"
+
+#, c-format
+msgid "E741: Value is locked: %s"
+msgstr "E741: Hodnota je uzamknutá: %s"
+
+msgid "Unknown"
+msgstr "Neznámy"
+
+msgid "E742: Cannot change value of %s"
+msgstr "E742: Nemo¾no zmeni» hodnotu %s"
+
+msgid "E698: variable nested too deep for making a copy"
+msgstr "E698: premenná je vnorená príli¹ hlboko pre skopírovanie"
+
+#, c-format
+msgid "E124: Missing '(': %s"
+msgstr "E124: Chýba '(': %s"
+
+#, c-format
+msgid "E125: Illegal argument: %s"
+msgstr "E125: Neprípustný argument: %s"
+
+msgid "E126: Missing :endfunction"
+msgstr "E126: Chýba :endfunction"
+
+msgid "E746: Function name does not match script file name: %s"
+msgstr "E746: Meno funkcie sa nezhoduje s menom interpretovaného súboru: %s"
+
+msgid "E129: Function name required"
+msgstr "E129: Je vy¾adované meno funkcie"
+
+msgid "E128: Function name must start with a capital or contain a colon: %s"
+msgstr "E128: Názov funkcie musí zaèína» veµkým písmenom alebo obsahova» dvojbodku: %s"
+
+#, c-format
+msgid "E131: Cannot delete function %s: It is in use"
+msgstr "E131: Nedá sa vymaza» funkcia %s: je pou¾ívaná"
+
+msgid "E132: Function call depth is higher than 'maxfuncdepth'"
+msgstr "E132: Zanorenie funkcií je hlb¹ie ne¾ 'maxfuncdepth'"
+
+#, c-format
+msgid "calling %s"
+msgstr "volám %s"
+
+msgid "%s aborted"
+msgstr "%s zru¹ený"
+
+#, c-format
+msgid "%s returning #%ld"
+msgstr "%s vrátilo #%ld"
+
+msgid "%s returning %s"
+msgstr "%s vrátilo %s"
+
+#, c-format
+msgid "continuing in %s"
+msgstr "pokraèujem v %s"
+
+msgid "E133: :return not inside a function"
+msgstr "E133: :return mimo funkciu"
+
+#, c-format
+msgid ""
+"\n"
+"# global variables:\n"
+msgstr ""
+"\n"
+"# globálne premenné:\n"
+
+msgid ""
+"\n"
+"\tLast set from "
+msgstr ""
+"\n"
+"\tPosledné nastavenie z "
+
+#, c-format
+msgid "<%s>%s%s %d, Hex %02x, Octal %03o"
+msgstr "<%s>%s%s %d, ¹estnástkovo %02x, osmièkovo %03o"
+
+msgid "> %d, Hex %04x, Octal %o"
+msgstr "> %d, ¹estnástkovo %04x, osmièkovo %o"
+
+msgid "> %d, Hex %08x, Octal %o"
+msgstr "> %d, ¹estnástkovo %08x, osmièkovo %o"
+
+msgid "E134: Move lines into themselves"
+msgstr "E134: Prekrytie riadkov sebou samými"
+
+msgid "1 line moved"
+msgstr "1 riadok presunutý"
+
+#, c-format
+msgid "%ld lines moved"
+msgstr "%ld riadkov presunutých"
+
+#, c-format
+msgid "%ld lines filtered"
+msgstr "%ld riadkov filtrovaných"
+
+msgid "E135: *Filter* Autocommands must not change current buffer"
+msgstr "E135: Automatické príkazy *Filter* nesmú meni» aktuálny buffer"
+
+msgid "[No write since last change]\n"
+msgstr "[Neulo¾ené zmeny]\n"
+
+msgid "%sviminfo: %s in line: "
+msgstr "%sviminfo: %s na riadku: "
+
+msgid "E136: viminfo: Too many errors, skipping rest of file"
+msgstr "E136: viminfo: príli¹ mnoho chýb, preskakujem zbytok súboru"
+
+#, c-format
+msgid "Reading viminfo file \"%s\"%s%s%s"
+msgstr "Èítam viminfo súbor \"%s\"%s%s%s"
+
+msgid " info"
+msgstr " informácie"
+
+msgid " marks"
+msgstr " znaèky"
+
+msgid " FAILED"
+msgstr " ZLYHALO"
+
+#, c-format
+msgid "E137: Viminfo file is not writable: %s"
+msgstr "E137: Do viminfo súboru %s sa nedá zapisova»"
+
+#, c-format
+msgid "E138: Can't write viminfo file %s!"
+msgstr "E138: Nedá sa ulo¾i» viminfo súbor %s!"
+
+#, c-format
+msgid "Writing viminfo file \"%s\""
+msgstr "Ukládám viminfo súboru \"%s\""
+
+#. Write the info:
+#, c-format
+msgid "# This viminfo file was generated by Vim %s.\n"
+msgstr "# Tento viminfo súbor bol vytvorený editorom Vim %s.\n"
+
+#, c-format
+msgid ""
+"# You may edit it if you're careful!\n"
+"\n"
+msgstr ""
+"# Pokiaµ budete opatrný, mô¾ete ho upravova».\n"
+"\n"
+
+#, c-format
+msgid "# Value of 'encoding' when this file was written\n"
+msgstr "# Hodnota 'encoding' (kódovania) poèas zápisu tohoto súboru\n"
+
+msgid "Illegal starting char"
+msgstr "Neprípustný zaèiatoèný znak"
+
+msgid "Save As"
+msgstr "Ulo¾i» ako"
+
+msgid "Write partial file?"
+msgstr "Ulo¾i» neúplný súbor?"
+
+msgid "E140: Use ! to write partial buffer"
+msgstr "E140: Pou¾ite ! pre ulo¾enie neúplného bufferu"
+
+msgid "Overwrite existing file \"%s\"?"
+msgstr "Prepísa» existujúci súbor \"%s\"?"
+
+#, c-format
+msgid "Swap file \"%s\" exists, overwrite anyway?"
+msgstr "Odkladací súbor \"%s\" existuje, aj tak prepísa»?"
+
+msgid "E768: Swap file exists: %s (:silent! overrides)"
+msgstr "E768: Odkladací súbor existuje: %s (pou¾ite :silent! pre prepísanie)"
+
+#, c-format
+msgid "E141: No file name for buffer %ld"
+msgstr "E141: ®iadny názov súboru pre buffer %ld"
+
+msgid "E142: File not written: Writing is disabled by 'write' option"
+msgstr "E142: Súbor nebol ulo¾ený: ukladanie je zakázané voµbou 'write'"
+
+msgid ""
+"'readonly' option is set for \"%s\".\n"
+"Do you wish to write anyway?"
+msgstr ""
+"Pre \"%s\" je nastavená voµba 'readonly' (iba na èítanie).\n"
+"Prajete si aj tak ulo¾i»?"
+
+msgid "Edit File"
+msgstr "Upravova» súbor"
+
+#, c-format
+msgid "E143: Autocommands unexpectedly deleted new buffer %s"
+msgstr "E143: Automatické príkazy neoèakávane zmazali nový buffer %s"
+
+msgid "E144: non-numeric argument to :z"
+msgstr "E144: neèíselný argument pre :z"
+
+msgid "E145: Shell commands not allowed in rvim"
+msgstr "E145: rvim nepovoµuje pou¾itie príkazov shellu"
+
+msgid "E146: Regular expressions can't be delimited by letters"
+msgstr "E146: Regulárne výrazy nesmú by» oddelené písmenami"
+
+#, c-format
+msgid "replace with %s (y/n/a/q/l/^E/^Y)?"
+msgstr "nahradi» %s (y/n/a/q/l/^E/^Y)?"
+
+msgid "(Interrupted) "
+msgstr "(preru¹ený) "
+
+msgid "1 match"
+msgstr "1 zhoda"
+
+msgid "1 substitution"
+msgstr "1 nahradenie"
+
+msgid "%ld matches"
+msgstr "%ld zhôd"
+
+#, c-format
+msgid "%ld substitutions"
+msgstr "%ld nahradení"
+
+msgid " on 1 line"
+msgstr " na 1 riadku"
+
+#, c-format
+msgid " on %ld lines"
+msgstr " na %ld riadkov"
+
+msgid "E147: Cannot do :global recursive"
+msgstr "E147: :global sa nedá vola» rekurzívne"
+
+msgid "E148: Regular expression missing from global"
+msgstr "E148: Pri príkaze global chýba regulárny výraz"
+
+#, c-format
+msgid "Pattern found in every line: %s"
+msgstr "Vzor nájdený na ka¾dom riadku: %s"
+
+#, c-format
+msgid ""
+"\n"
+"# Last Substitute String:\n"
+"$"
+msgstr ""
+"\n"
+"# Posledný zamieòaný re»azec:\n"
+"$"
+
+msgid "E478: Don't panic!"
+msgstr "E478: ®iadnu paniku!"
+
+msgid "E661: Sorry, no '%s' help for %s"
+msgstr "E661: ¥utujem, ¾iadny '%s' pomocník pre %s"
+
+#, c-format
+msgid "E149: Sorry, no help for %s"
+msgstr "E149: ¥utujem, pre %s nie je ¾iadny pomocník"
+
+#, c-format
+msgid "Sorry, help file \"%s\" not found"
+msgstr "¥utujem, súbor \"%s\" s pomocníkom nebol nájdený"
+
+#, c-format
+msgid "E150: Not a directory: %s"
+msgstr "E150: %s nie je adresárom"
+
+#, c-format
+msgid "E152: Cannot open %s for writing"
+msgstr "E152: %s sa nedá sa otvori» pre zápis"
+
+#, c-format
+msgid "E153: Unable to open %s for reading"
+msgstr "E153: %s as nedá otvori» pre èítanie"
+
+#, c-format
+msgid "E670: Mix of help file encodings within a language: %s"
+msgstr "E670: Rôzne kódovania pre súbory s pomocníkom pre jazyk: %s"
+
+msgid "E154: Duplicate tag \"%s\" in file %s/%s"
+msgstr "E154: Duplicitný tag \"%s\" v súbore %s/%s"
+
+#, c-format
+msgid "E160: Unknown sign command: %s"
+msgstr "E160: Neznámu príkaz pre znaèky: %s"
+
+msgid "E156: Missing sign name"
+msgstr "E156: Chýba meno pre znaèku"
+
+msgid "E612: Too many signs defined"
+msgstr "E612: Príli¹ mnoho definovaných znaèiek"
+
+#, c-format
+msgid "E239: Invalid sign text: %s"
+msgstr "E239: Chybný text znaèky: %s"
+
+#, c-format
+msgid "E155: Unknown sign: %s"
+msgstr "E155: Neznáma znaèka: %s"
+
+msgid "E159: Missing sign number"
+msgstr "E159: Chýba èislo znaèky"
+
+#, c-format
+msgid "E158: Invalid buffer name: %s"
+msgstr "E158: Chybné meno bufferu: %s"
+
+#, c-format
+msgid "E157: Invalid sign ID: %ld"
+msgstr "E157: Chybné ID znaèky: %ld"
+
+msgid " (NOT FOUND)"
+msgstr " (NENÁJDENÉ)"
+
+msgid " (not supported)"
+msgstr " (nepodporované)"
+
+msgid "[Deleted]"
+msgstr "[vymazaný]"
+
+msgid "Entering Debug mode. Type \"cont\" to continue."
+msgstr "Spú¹»am re¾im ladenia. Pre ukonèenie napí¹te \"cont\"."
+
+#, c-format
+msgid "line %ld: %s"
+msgstr "riadok %ld: %s"
+
+#, c-format
+msgid "cmd: %s"
+msgstr "príkaz: %s"
+
+#, c-format
+msgid "Breakpoint in \"%s%s\" line %ld"
+msgstr "Bod preru¹enia v \"%s%s\" na riadku %ld"
+
+#, c-format
+msgid "E161: Breakpoint not found: %s"
+msgstr "E161: Bod preru¹enia nenájdený: %s"
+
+msgid "No breakpoints defined"
+msgstr "Neboli definovné ¾iadne body preru¹enia"
+
+#, c-format
+msgid "%3d %s %s line %ld"
+msgstr "%3d %s %s riadok %ld"
+
+msgid "E750: First use :profile start <fname>"
+msgstr "E750: Najprv pou¾ite príkaz :profile start <meno_suboru>"
+
+msgid "Save changes to \"%s\"?"
+msgstr "Ulo¾i» zmeny do \"%s\"?"
+
+msgid "Untitled"
+msgstr "Bez mena"
+
+#, c-format
+msgid "E162: No write since last change for buffer \"%s\""
+msgstr "E162: Buffer \"%s\" obsahuje neulo¾ené zmeny"
+
+msgid "Warning: Entered other buffer unexpectedly (check autocommands)"
+msgstr ""
+"Varovanie: Neèakaný vstup do iného bufferu (skontrolujte automatické príkazy)"
+
+msgid "E163: There is only one file to edit"
+msgstr "E163: Pre úpravu bol zadaný iba jeden súbor"
+
+msgid "E164: Cannot go before first file"
+msgstr "E164: Nedá sa preskoèi» pred prvý súbor"
+
+msgid "E165: Cannot go beyond last file"
+msgstr "E165: Nedá sa preskoèi» za posledný súbor"
+
+msgid "E666: compiler not supported: %s"
+msgstr "E666: prekladaè nie je podporovaný: %s"
+
+#, c-format
+msgid "Searching for \"%s\" in \"%s\""
+msgstr "Hµadám \"%s\" v \"%s\""
+
+#, c-format
+msgid "Searching for \"%s\""
+msgstr "Hµadám \"%s\""
+
+#, c-format
+msgid "not found in 'runtimepath': \"%s\""
+msgstr "súbor \"%s\" nebol nájdený v 'runtimepath'"
+
+msgid "Source Vim script"
+msgstr "Zdrojový skript Vim"
+
+#, c-format
+msgid "Cannot source a directory: \"%s\""
+msgstr "Nemo¾no interpretova» adresár: \"%s\""
+
+#, c-format
+msgid "could not source \"%s\""
+msgstr "nedá sa interpretova» \"%s\""
+
+#, c-format
+msgid "line %ld: could not source \"%s\""
+msgstr "riadok %ld: nemô¾no interpretova» \"%s\""
+
+#, c-format
+msgid "sourcing \"%s\""
+msgstr "interpretujem \"%s\""
+
+#, c-format
+msgid "line %ld: sourcing \"%s\""
+msgstr "riadok %ld: interpretujem \"%s\""
+
+#, c-format
+msgid "finished sourcing %s"
+msgstr "dokonèená interpretácia %s"
+
+msgid "W15: Warning: Wrong line separator, ^M may be missing"
+msgstr "W15: Varovanie: chybný oddeµovaè riadkov. Mo¾no chýba ^M"
+
+msgid "E167: :scriptencoding used outside of a sourced file"
+msgstr "E167: príkaz :scriptencoding pou¾itý mimo interpretovaný súbor"
+
+msgid "E168: :finish used outside of a sourced file"
+msgstr "E168: príkaz :finish pou¾itý mimo interpretovaný súbor"
+
+#, c-format
+msgid "Current %slanguage: \"%s\""
+msgstr "Aktuálny %sjazyk: \"%s\""
+
+#, c-format
+msgid "E197: Cannot set language to \"%s\""
+msgstr "E197: Nedá sa nastavi» jazyk na \"%s\""
+
+msgid "Entering Ex mode. Type \"visual\" to go to Normal mode."
+msgstr "Spú¹»am Ex re¾im. Napí¹te \"visual\" pre návrat do Normálneho re¾imu."
+
+msgid "E501: At end-of-file"
+msgstr "E501: Koniec súboru"
+
+msgid "E169: Command too recursive"
+msgstr "E169: Príkaz je príli¹ rekurzívny"
+
+msgid "E605: Exception not caught: %s"
+msgstr "E605: Výnimka nezachytená: %s"
+
+msgid "End of sourced file"
+msgstr "Koniec interpretovaného súboru"
+
+msgid "End of function"
+msgstr "Koniec funkcie"
+
+msgid "E464: Ambiguous use of user-defined command"
+msgstr "E464: Nejednoznaèné pou¾itie pou¾ívateµom definovaného príkazu"
+
+msgid "E492: Not an editor command"
+msgstr "E492: Nie je príkazom editoru"
+
+msgid "E493: Backwards range given"
+msgstr "E493: Zadaný spätný rozsah"
+
+msgid "Backwards range given, OK to swap"
+msgstr "Zadaný spätný rozsah. OK pre zámenu"
+
+msgid "E494: Use w or w>>"
+msgstr "E494: Pou¾ite w alebo w>>"
+
+msgid "E319: Sorry, the command is not available in this version"
+msgstr "E319: ¥utujem, ale tento príkaz nie je dostupný v tejto verzii"
+
+msgid "E172: Only one file name allowed"
+msgstr "E172: Prípustný je iba jeden názov súboru"
+
+msgid "1 more file to edit. Quit anyway?"
+msgstr "E¹te zostáva 1 súbor k úprave. Chcete napriek tomu ukonèi» editor?"
+
+#, c-format
+msgid "%d more files to edit. Quit anyway?"
+msgstr "E¹te zostáva %d súborov k úprave. Chcete napriek tomu ukonèi» editor?"
+
+msgid "E173: 1 more file to edit"
+msgstr "E173: E¹te zostáva 1 súbor k úprave."
+
+#, c-format
+msgid "E173: %ld more files to edit"
+msgstr "E173: E¹te zostáva %ld súborov k úprave."
+
+msgid "E174: Command already exists: add ! to replace it"
+msgstr "E174: Príkaz u¾ existuje: pou¾ite ! pre predefinovanie"
+
+msgid ""
+"\n"
+" Name Args Range Complete Definition"
+msgstr ""
+"\n"
+" Meno Args Rozsah Úplnos» Definícia"
+
+msgid "No user-defined commands found"
+msgstr "Neboli nájdené ¾iadne pou¾ivateµom definované príkazy"
+
+msgid "E175: No attribute specified"
+msgstr "E175: Neboli zadané ¾iadne vlastnosti"
+
+msgid "E176: Invalid number of arguments"
+msgstr "E176: Chybný poèet argumentov"
+
+msgid "E177: Count cannot be specified twice"
+msgstr "E177: Poèet nemô¾e by» zadaný dvakrát"
+
+msgid "E178: Invalid default value for count"
+msgstr "E178: Chybná implicitná hodnota pre poèet"
+
+msgid "E179: argument required for -complete"
+msgstr "E179: pre doplnenie (-complete) je potrebný argument"
+
+#, c-format
+msgid "E181: Invalid attribute: %s"
+msgstr "E181: Chybná vlastnos»: %s"
+
+msgid "E182: Invalid command name"
+msgstr "E182: Chybné meno príkazu"
+
+msgid "E183: User defined commands must start with an uppercase letter"
+msgstr "E183: Pou¾ívateµom definované príkazy musia zaèína» veµkým písmenom"
+
+#, c-format
+msgid "E184: No such user-defined command: %s"
+msgstr "E184: Pou¾ívateµom definovaný príkaz %s neexistuje"
+
+#, c-format
+msgid "E180: Invalid complete value: %s"
+msgstr "E180: Chybná hodnota doplnenia: %s"
+
+msgid "E468: Completion argument only allowed for custom completion"
+msgstr "E468: Argument doplnenia je povolený iba pre vlastné dopåòania (completion)"
+
+msgid "E467: Custom completion requires a function argument"
+msgstr "E467: Vlastné doplnenia vy¾adujú meno funkcie ako argument"
+
+#, c-format
+msgid "E185: Cannot find color scheme %s"
+msgstr "E185: Schéma farieb %s nenájdená"
+
+msgid "Greetings, Vim user!"
+msgstr "Pozdravujem, u¾ívateµ Vimu!"
+
+msgid "Edit File in new window"
+msgstr "Upravi» súbor v novom okne"
+
+msgid "No swap file"
+msgstr "®iadny odkladací súbor"
+
+msgid "Append File"
+msgstr "Pripoji» súbor"
+
+msgid "E747: Cannot change directory, buffer is modified (add ! to override)"
+msgstr "E747: Nemo¾no zmeni» adresár, buffer je modifikovaný (pou¾ite ! pre vynútenie)"
+
+msgid "E186: No previous directory"
+msgstr "E186: ®iadny predchádzajúci adresár"
+
+msgid "E187: Unknown"
+msgstr "E187: Neznámy"
+
+msgid "E465: :winsize requires two number arguments"
+msgstr "E465: :winsize (veµkos» okna) vy¾aduje dva argumenty"
+
+#, c-format
+msgid "Window position: X %d, Y %d"
+msgstr "Pozícia okna: X %d, Y %d"
+
+msgid "E188: Obtaining window position not implemented for this platform"
+msgstr "E188: Na tejto platforme sa nedá zisti» umiestnenie okna"
+
+msgid "E466: :winpos requires two number arguments"
+msgstr "E466: :winpos (pozícia okna) vy¾aduje dva argumenty"
+
+msgid "Save Redirection"
+msgstr "Ulo¾i» presmerovanie"
+
+msgid "Save View"
+msgstr "Ulo¾i» pohµad"
+
+msgid "Save Session"
+msgstr "Ulo¾i» sedenie"
+
+msgid "Save Setup"
+msgstr "Ulo¾i» nastavenie"
+
+msgid "E739: Cannot create directory: %s"
+msgstr "E739: Nemo¾no vytvori» adresár: %s"
+
+msgid "E189: \"%s\" exists (add ! to override)"
+msgstr "E189: \"%s\" existuje (pou¾ite ! pre vynútenie)"
+
+#, c-format
+msgid "E190: Cannot open \"%s\" for writing"
+msgstr "E190: \"%s\" sa nedá otvori» pre zápis"
+
+#. set mark
+msgid "E191: Argument must be a letter or forward/backward quote"
+msgstr "E191: Argumentem mô¾e by» iba písmeno alebo pravý èi µavý apostrof"
+
+msgid "E192: Recursive use of :normal too deep"
+msgstr "E192: Rekurzívne pou¾itie príkazu :normal príli¹ hlboké"
+
+msgid "E194: No alternate file name to substitute for '#'"
+msgstr ""
+"E194: ®iadny alternatívny názov súboru, ktorým by bolo mo¾né nahradi» '#'"
+
+msgid "E495: no autocommand file name to substitute for \"<afile>\""
+msgstr "E495: ¾iadny názov súboru, ktorým by bolo mo¾né nahradi» \"<afile>\""
+
+msgid "E496: no autocommand buffer number to substitute for \"<abuf>\""
+msgstr "E496: ¾iadne èíslo bufferu, ktorým by bolo mo¾né nahradi» \"<abuf>\""
+
+msgid "E497: no autocommand match name to substitute for \"<amatch>\""
+msgstr ""
+"E497: ¾iadna zhoda automatických príkazov, ktorou by bolo mo¾né nahradi» \"<amatch>"
+"\""
+
+msgid "E498: no :source file name to substitute for \"<sfile>\""
+msgstr "E498: ¾iadny :source súbor, ktorým by bolo mo¾né nahradi» \"<sfile>\""
+
+msgid "E499: Empty file name for '%' or '#', only works with \":p:h\""
+msgstr "E499: Prázdný názov súboru pre '%' alebo '#', funguje iba s \":p:h\""
+
+msgid "E500: Evaluates to an empty string"
+msgstr "E500: Výsledkom vyhodnotenia je prázdny re»azec"
+
+msgid "E195: Cannot open viminfo file for reading"
+msgstr "E195: Súbor viminfo sa nedá sa otvori» na èítanie"
+
+msgid "E196: No digraphs in this version"
+msgstr "E196: V tejto verzi nie sú digraphy podporované"
+
+msgid "E608: Cannot :throw exceptions with 'Vim' prefix"
+msgstr "E608: Nemo¾no spracova» výnimku :throw s preponou 'Vim'"
+
+#. always scroll up, don't overwrite
+#, c-format
+msgid "Exception thrown: %s"
+msgstr "Spracovanie výnimky: %s"
+
+#, c-format
+msgid "Exception finished: %s"
+msgstr "Výnimka ukonèená: %s"
+
+#, c-format
+msgid "Exception discarded: %s"
+msgstr "Výnimka zahodená: %s"
+
+msgid "%s, line %ld"
+msgstr "%s, riadok %ld"
+
+#. always scroll up, don't overwrite
+msgid "Exception caught: %s"
+msgstr "Zachytená výnimka: %s"
+
+#, c-format
+msgid "%s made pending"
+msgstr "%s prebieha"
+
+msgid "%s resumed"
+msgstr "%s vrátené"
+
+#, c-format
+msgid "%s discarded"
+msgstr "%s zahodené"
+
+msgid "Exception"
+msgstr "Výnimka"
+
+msgid "Error and interrupt"
+msgstr "Chyba a preru¹ené"
+
+msgid "Error"
+msgstr "Chyba"
+
+#. if (pending & CSTP_INTERRUPT)
+msgid "Interrupt"
+msgstr "Preru¹ené"
+
+msgid "E579: :if nesting too deep"
+msgstr "E579: vnorenie :if je príli¹ hlboké"
+
+msgid "E580: :endif without :if"
+msgstr "E580: :endif bez zodpovedajúceho :if"
+
+msgid "E581: :else without :if"
+msgstr "E581: :else bez zodpovedajúceho :if"
+
+msgid "E582: :elseif without :if"
+msgstr "E582: :elseif bez zodpovedajúceho :if"
+
+msgid "E583: multiple :else"
+msgstr "E583: viacnásobné :else"
+
+msgid "E584: :elseif after :else"
+msgstr "E584: :elseif nasleduje po :else"
+
+msgid "E585: :while/:for nesting too deep"
+msgstr "E585: vnorenie :while/:for je príli¹ hlboké"
+
+msgid "E586: :continue without :while or :for"
+msgstr "E586: :continue bez zodpovedajúceho :while alebo :for"
+
+msgid "E587: :break without :while or :for"
+msgstr "E587: :break bez zodpovedajúceho :while alebo :for"
+
+msgid "E732: Using :endfor with :while"
+msgstr "E732: Pou¾ité :endfor spolu s :while"
+
+msgid "E733: Using :endwhile with :for"
+msgstr "E733: Pou¾ité :endwhile spolu s :for"
+
+msgid "E601: :try nesting too deep"
+msgstr "E601: vnorenie :try je príli¹ hlboké"
+
+msgid "E603: :catch without :try"
+msgstr "E603: :catch bez :try"
+
+#. Give up for a ":catch" after ":finally" and ignore it.
+#. * Just parse.
+msgid "E604: :catch after :finally"
+msgstr "E604: :catch nasleduje po :finally"
+
+msgid "E606: :finally without :try"
+msgstr "E606: :finally bez :try"
+
+#. Give up for a multiple ":finally" and ignore it.
+msgid "E607: multiple :finally"
+msgstr "E607: viacnásobné pou¾ité :finally"
+
+msgid "E602: :endtry without :try"
+msgstr "E602: :endtry bez :try"
+
+msgid "E193: :endfunction not inside a function"
+msgstr "E193: :endfunction mimo funkciu"
+
+msgid "tagname"
+msgstr "meno tagu"
+
+msgid " kind file\n"
+msgstr " typ súboru\n"
+
+msgid "'history' option is zero"
+msgstr "'voµba 'history' je nastavená na nulu"
+
+#, c-format
+msgid ""
+"\n"
+"# %s History (newest to oldest):\n"
+msgstr ""
+"\n"
+"# História %s (zaèínajúci najnov¹ou polo¾kou):\n"
+
+msgid "Command Line"
+msgstr "Príkazový riadok"
+
+msgid "Search String"
+msgstr "Vyhµadávaný re»azec"
+
+msgid "Expression"
+msgstr "Výraz"
+
+msgid "Input Line"
+msgstr "Vstupný riadok"
+
+msgid "E198: cmd_pchar beyond the command length"
+msgstr "E198: cmd_pchar prevy¹uje då¾ku príkazu"
+
+msgid "E199: Active window or buffer deleted"
+msgstr "E199: Aktívne okno alebo buffer bol vymazaný"
+
+msgid "Illegal file name"
+msgstr "Neprípustný názov súboru"
+
+msgid "is a directory"
+msgstr "je adresárom"
+
+msgid "is not a file"
+msgstr "nie je súborom"
+
+msgid "[New File]"
+msgstr "[nový súbor]"
+
+msgid "[Permission Denied]"
+msgstr "[prístup odmietnutý]"
+
+msgid "E200: *ReadPre autocommands made the file unreadable"
+msgstr "E200: automatické príkazy *ReadPre urobili súbor neèitateµným"
+
+msgid "E201: *ReadPre autocommands must not change current buffer"
+msgstr "E201: automatické príkazy *ReadPre nesmú meni» aktuálny buffer"
+
+msgid "Vim: Reading from stdin...\n"
+msgstr "Vim: èítam zo ¹tandardného vstupu...\n"
+
+msgid "Reading from stdin..."
+msgstr "Èítam zo ¹tandardného vstupu..."
+
+#. Re-opening the original file failed!
+msgid "E202: Conversion made file unreadable!"
+msgstr "E202: Po konverzii je súbor neèitateµný!"
+
+msgid "[fifo/socket]"
+msgstr "[pomenovaná rúra/soket]"
+
+msgid "[fifo]"
+msgstr "[pomenovaná rúra]"
+
+msgid "[socket]"
+msgstr "[soket]"
+
+msgid "[RO]"
+msgstr "[RO]"
+
+msgid "[CR missing]"
+msgstr "[chýba CR]"
+
+msgid "[NL found]"
+msgstr "[nájdené NL]"
+
+msgid "[long lines split]"
+msgstr "[dlhé riadky zalomené]"
+
+msgid "[NOT converted]"
+msgstr "[neskonvertovaný]"
+
+msgid "[converted]"
+msgstr "[skonvertovaný]"
+
+msgid "[crypted]"
+msgstr "[¹ifrovaný]"
+
+msgid "[CONVERSION ERROR]"
+msgstr "[CHYBA PREVODU]"
+
+#, c-format
+msgid "[ILLEGAL BYTE in line %ld]"
+msgstr "[NEPRÍPUSTNÝ BAJT na riadku %ld]"
+
+msgid "[READ ERRORS]"
+msgstr "[CHYBY ÈÍTANIA]"
+
+msgid "Can't find temp file for conversion"
+msgstr "Nedá sa nájs» doèasný súbor pre konverziu"
+
+msgid "Conversion with 'charconvert' failed"
+msgstr "Konverzia s 'charconvert' sa nepodarila"
+
+msgid "can't read output of 'charconvert'"
+msgstr "nedá sa èíta» výstup 'charconvert'"
+
+msgid "E676: No matching autocommands for acwrite buffer"
+msgstr "E676: ®iadne vyhovujúce automatické príkazy pre acwrite buffer "
+
+msgid "E203: Autocommands deleted or unloaded buffer to be written"
+msgstr ""
+"E203: Automatické príkazy zmazali èi deaktivovali buffer, ktorý mal by» "
+"ulo¾ený"
+
+msgid "E204: Autocommand changed number of lines in unexpected way"
+msgstr "E204: Automatický príkaz neoèakávaným spôsobom zmenil poèet riadkov"
+
+msgid "NetBeans disallows writes of unmodified buffers"
+msgstr "NetBeans rozhranie nedovolilo zapísa» nemodifikované buffre"
+
+msgid "Partial writes disallowed for NetBeans buffers"
+msgstr "Èiastoèné zápisy nie sú povolené pre NetBeans buffre"
+
+msgid "is not a file or writable device"
+msgstr "nie je súborom ani zapisovatelným zariadením"
+
+msgid "is read-only (add ! to override)"
+msgstr "je iba pre èítanie (pou¾ite ! pre vynútenie)"
+
+msgid "E506: Can't write to backup file (add ! to override)"
+msgstr "E506: Nedá sa zapisova» do zálo¾ného súboru (pou¾ite ! pre vynútenie)"
+
+msgid "E507: Close error for backup file (add ! to override)"
+msgstr "E507: Chyba pri uzatváraní zálo¾ného súboru (pou¾ite ! pre vynútenie)"
+
+msgid "E508: Can't read file for backup (add ! to override)"
+msgstr "E508: Nedá sa naèíta» súbor pre zálohu (pou¾ite ! pre vynútenie)"
+
+msgid "E509: Cannot create backup file (add ! to override)"
+msgstr "E509: Nedá sa vytvori» zálo¾ný súbor (pou¾ite ! pre vynútenie)"
+
+msgid "E510: Can't make backup file (add ! to override)"
+msgstr "E510: Nedá sa vytvori» zálo¾ný súbor (pou¾ite ! pre vynútenie)"
+
+# TODO: resource fork ?! Note: used only in MACOS_X version
+msgid "E460: The resource fork would be lost (add ! to override)"
+msgstr "E460: 'Resource fork' bude stratený (pou¾ite ! pre vynútenie)"
+
+msgid "E214: Can't find temp file for writing"
+msgstr "E214: Nedá sa nájs» doèasný súbor pre ukladanie"
+
+msgid "E213: Cannot convert (add ! to write without conversion)"
+msgstr "E213: Nedá sa spravi» konverzia (pou¾ite ! pre zápis bez konverzie)"
+
+msgid "E166: Can't open linked file for writing"
+msgstr "E166: Súbor sa nedá otvori» pre ukladanie"
+
+msgid "E212: Can't open file for writing"
+msgstr "E212: Súbor sa nedá otvori» pre ukladanie"
+
+msgid "E667: Fsync failed"
+msgstr "E667: Fsync zlyhal"
+
+msgid "E512: Close failed"
+msgstr "E512: Zatvorenie zlyhalo"
+
+msgid "E513: write error, conversion failed (make 'fenc' empty to override)"
+msgstr "E513: chyba pri zápise, konverzia sa nepodarila (nastavte voµbu 'fenc' na prázdnu pre vynútenie)"
+
+msgid "E514: write error (file system full?)"
+msgstr "E514: chyba pri ukladaní (plný disk?)"
+
+msgid " CONVERSION ERROR"
+msgstr " CHYBA PREVODU"
+
+msgid "[Device]"
+msgstr "[zariadenie]"
+
+msgid "[New]"
+msgstr "[nový]"
+
+msgid " [a]"
+msgstr " [p]"
+
+msgid " appended"
+msgstr " pripojený"
+
+msgid " [w]"
+msgstr " [u]"
+
+msgid " written"
+msgstr " ulo¾ený"
+
+msgid "E205: Patchmode: can't save original file"
+msgstr "E205: patchmode: nedá sa ulo¾i» pôvodný súbor"
+
+msgid "E206: patchmode: can't touch empty original file"
+msgstr "E206: patchmode: nedá sa zapisova» do prázdneho pôvodného súboru"
+
+msgid "E207: Can't delete backup file"
+msgstr "E207: Nedá sa vymaza» zálo¾ný súbor"
+
+msgid ""
+"\n"
+"WARNING: Original file may be lost or damaged\n"
+msgstr ""
+"\n"
+"VAROVANIE: Obsah pôvodného súboru mô¾e by» stratený alebo po¹kodený\n"
+
+msgid "don't quit the editor until the file is successfully written!"
+msgstr "neukonèujte editor skôr, ne¾ bude súbor úspe¹ne ulo¾ený!"
+
+msgid "[dos]"
+msgstr "[dos]"
+
+msgid "[dos format]"
+msgstr "[dos formát]"
+
+msgid "[mac]"
+msgstr "[mac]"
+
+msgid "[mac format]"
+msgstr "[mac formát]"
+
+msgid "[unix]"
+msgstr "[unix]"
+
+msgid "[unix format]"
+msgstr "[unix formát]"
+
+msgid "1 line, "
+msgstr "1 riadok, "
+
+#, c-format
+msgid "%ld lines, "
+msgstr "%ld riadkov, "
+
+msgid "1 character"
+msgstr "1 znak"
+
+#, c-format
+msgid "%ld characters"
+msgstr "%ld znakov"
+
+msgid "[noeol]"
+msgstr "[bez znaku konca riadku]"
+
+msgid "[Incomplete last line]"
+msgstr "[neúplný posledný riadok]"
+
+#. don't overwrite messages here
+#. must give this prompt
+#. don't use emsg() here, don't want to flush the buffers
+msgid "WARNING: The file has been changed since reading it!!!"
+msgstr "VAROVANIE: Súbor bol zmenený od jeho naèítania!!!"
+
+msgid "Do you really want to write to it"
+msgstr "Chcete ho naozaj ulo¾i»"
+
+#, c-format
+msgid "E208: Error writing to \"%s\""
+msgstr "E208: Chyba pri zápise do \"%s\""
+
+#, c-format
+msgid "E209: Error closing \"%s\""
+msgstr "E209: Chyba pri uzatváraní \"%s\""
+
+#, c-format
+msgid "E210: Error reading \"%s\""
+msgstr "E210: Chyba pri èítaní \"%s\""
+
+msgid "E246: FileChangedShell autocommand deleted buffer"
+msgstr "E246: automatický príkaz FileChangedShell vymazal buffer"
+
+msgid "E211: File \"%s\" no longer available"
+msgstr "E211: Varovanie: súbor \"%s\" u¾ nie je dostupný"
+
+#, c-format
+msgid ""
+"W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as "
+"well"
+msgstr ""
+"W12: Varovanie: súbor \"%s\" bol po zaèatí úpravy zmenený a buffer sa tie¾ "
+"zmenil "
+
+msgid "See \":help W12\" for more info."
+msgstr "Pozrite \":help W12\" pre viac informácií."
+
+#, c-format
+msgid "W11: Warning: File \"%s\" has changed since editing started"
+msgstr "W11: Varovanie: súbor \"%s\" bol po zaèatí úpravy zmenený"
+
+msgid "See \":help W11\" for more info."
+msgstr "Pozrite \":help W11\" pre viac informácií."
+
+#, c-format
+msgid "W16: Warning: Mode of file \"%s\" has changed since editing started"
+msgstr ""
+"W16: Varovanie: Prístupové práva k súboru \"%s\" boli po zaèatí úprav zmenené"
+
+msgid "See \":help W16\" for more info."
+msgstr "Pozrite \":help W16\" pre viac informácií."
+
+#, c-format
+msgid "W13: Warning: File \"%s\" has been created after editing started"
+msgstr "W13: Varovanie: Súbor \"%s\" bol vytvorený po zaèatí úpravy"
+
+msgid "Warning"
+msgstr "Varovanie"
+
+msgid ""
+"&OK\n"
+"&Load File"
+msgstr ""
+"&OK\n"
+"&Naèíta» súbor"
+
+msgid "E462: Could not prepare for reloading \"%s\""
+msgstr "E462: Nemo¾no pripravi» na opätovné naèítanie \"%s\""
+
+#, c-format
+msgid "E321: Could not reload \"%s\""
+msgstr "E321: nedá sa obnovi» \"%s\""
+
+msgid "--Deleted--"
+msgstr "--Vymazaný--"
+
+#, c-format
+msgid "auto-removing autocommand: %s <buffer=%d>"
+msgstr "samomazací automatický príkaz: %s <buffer=%d>"
+
+#. the group doesn't exist
+#, c-format
+msgid "E367: No such group: \"%s\""
+msgstr "E367: Skupina \"%s\" neexistuje"
+
+#, c-format
+msgid "E215: Illegal character after *: %s"
+msgstr "E215: Neprípustný znak po *: %s"
+
+#, c-format
+msgid "E216: No such event: %s"
+msgstr "E216: Udalos» %s neexistuje"
+
+msgid "E216: No such group or event: %s"
+msgstr "E216: Udalos» alebo skupina %s neexistuje"
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Autocommands ---"
+msgstr ""
+"\n"
+"--- Automatické príkazy ---"
+
+msgid "E680: <buffer=%d>: invalid buffer number "
+msgstr "E680: <buffer=%d>: chybné èíslo bufferu"
+
+msgid "E217: Can't execute autocommands for ALL events"
+msgstr "E217: Automatické príkazy sa nedajú spusti» pre V©ETKY udalosti"
+
+msgid "No matching autocommands"
+msgstr "®iadne vyhovujúce automatické príkazy"
+
+msgid "E218: autocommand nesting too deep"
+msgstr "E218: vnorenia automatického príkazu sú príli¹ hlboké"
+
+#, c-format
+msgid "%s Autocommands for \"%s\""
+msgstr "%s Automatické príkazy pre \"%s\""
+
+#, c-format
+msgid "Executing %s"
+msgstr "Spú¹»am %s"
+
+#, c-format
+msgid "autocommand %s"
+msgstr "automatický príkaz %s"
+
+msgid "E219: Missing {."
+msgstr "E219: Chýba {."
+
+msgid "E220: Missing }."
+msgstr "E220: Chýba }."
+
+msgid "E490: No fold found"
+msgstr "E490: Nebol nájdené ¾iadne vnorenie"
+
+msgid "E350: Cannot create fold with current 'foldmethod'"
+msgstr "E350: Nedá sa vytvori» vnorenie s aktuálnou metódou 'foldmethod'"
+
+msgid "E351: Cannot delete fold with current 'foldmethod'"
+msgstr "E351: Nedá sa zru¹i» vnorenie s aktuálnou metódou 'foldmethod'"
+
+#, c-format
+msgid "+--%3ld lines folded "
+msgstr "+--%3ld riadkov zahnutých "
+
+msgid "E222: Add to read buffer"
+msgstr "E222: Prida» do bufferu pre èítanie"
+
+msgid "E223: recursive mapping"
+msgstr "E223: rekurzívne mapovanie"
+
+#, c-format
+msgid "E224: global abbreviation already exists for %s"
+msgstr "E224: pre %s u¾ globálna skratka existuje"
+
+#, c-format
+msgid "E225: global mapping already exists for %s"
+msgstr "E225: pre %s u¾ globálne mapovanie existuje"
+
+#, c-format
+msgid "E226: abbreviation already exists for %s"
+msgstr "E226: pre %s u¾ skratka existuje"
+
+#, c-format
+msgid "E227: mapping already exists for %s"
+msgstr "E227: pre %s u¾ mapovanie existuje"
+
+msgid "No abbreviation found"
+msgstr "®iadna skratka nebola nájdená"
+
+msgid "No mapping found"
+msgstr "®iadne mapovanie nebolo nájdené"
+
+msgid "E228: makemap: Illegal mode"
+msgstr "E228: makemap: neprípustný mód"
+
+msgid "E229: Cannot start the GUI"
+msgstr "E229: Nedá sa spusti» GUI (grafické rozhranie)"
+
+#, c-format
+msgid "E230: Cannot read from \"%s\""
+msgstr "E230: Nedá sa èíta» z \"%s\""
+
+msgid "E665: Cannot start GUI, no valid font found"
+msgstr "E665: Nemo¾no na¹tartova» grafické rozhranie, nenájdený ¾iaden pou¾itelný font"
+
+msgid "E231: 'guifontwide' invalid"
+msgstr ""
+"E231: voµba 'guifontwide' (nastavenie ¹irokého písma) je chybne nastavená"
+
+msgid "E599: Value of 'imactivatekey' is invalid"
+msgstr "E599: Hodnota 'imactivatekey' je nesprávne nastavená"
+
+#, c-format
+msgid "E254: Cannot allocate color %s"
+msgstr "E254: Nedá sa alokova» farba %s"
+
+msgid "No match at cursor, finding next"
+msgstr "®iadna zhoda na pozícii kurzora, hµadám ïalej"
+
+msgid "<cannot open> "
+msgstr "<nedá sa otvori»> "
+
+msgid "E616: vim_SelFile: can't get font %s"
+msgstr "E616: vim_SelFile: písmo %s nie je dostupné"
+
+msgid "E614: vim_SelFile: can't return to current directory"
+msgstr "E614: vim_SelFile: nedá sa vráti» do aktuálneho adresára"
+
+msgid "Pathname:"
+msgstr "Názov cesty:"
+
+msgid "E615: vim_SelFile: can't get current directory"
+msgstr "E615: vim_SelFile: nedá sa zisti» aktuálny adresár"
+
+msgid "OK"
+msgstr "OK"
+
+msgid "Cancel"
+msgstr "Zru¹i»"
+
+msgid "Scrollbar Widget: Could not get geometry of thumb pixmap."
+msgstr "Prípravok posuvnej li¹ty: nedá sa zisti» geometria náhµadu obrázku."
+
+msgid "Vim dialog"
+msgstr "Vim dialóg"
+
+msgid "E232: Cannot create BalloonEval with both message and callback"
+msgstr "E232: BalloonEval nedá sa vytvori» správou a zároveò spätným volaním"
+
+msgid "Vim dialog..."
+msgstr "Vim dialóg.."
+
+# TODO: Translate as "&Ano\n&Nie\n&Zru¹i»" ?
+msgid ""
+"&Yes\n"
+"&No\n"
+"&Cancel"
+msgstr ""
+"&Ano\n"
+"&Nie\n"
+"&Zru¹i»"
+
+msgid "Input _Methods"
+msgstr "Vstupné metódy (_Methods)"
+
+msgid "VIM - Search and Replace..."
+msgstr "VIM - Nájs» a nahradi»..."
+
+msgid "VIM - Search..."
+msgstr "VIM - Nájs»..."
+
+msgid "Find what:"
+msgstr "Vyhµada»:"
+
+msgid "Replace with:"
+msgstr "Nahradi» s:"
+
+#. whole word only button
+msgid "Match whole word only"
+msgstr "Hµada» len celé slová"
+
+#. match case button
+msgid "Match case"
+msgstr "Zhoda veµkosti písmen"
+
+msgid "Direction"
+msgstr "Smer"
+
+#. 'Up' and 'Down' buttons
+msgid "Up"
+msgstr "Hore"
+
+msgid "Down"
+msgstr "Dolu"
+
+msgid "Find Next"
+msgstr "Nájs» ïal¹ie"
+
+msgid "Replace"
+msgstr "Nahradi»"
+
+msgid "Replace All"
+msgstr "Nahradi» V¹etko"
+
+msgid "Vim: Received \"die\" request from session manager\n"
+msgstr "Vim: Prijatá po¾iadavka na ukonèenie (die) od mana¾éra sedení\n"
+
+msgid "Vim: Main window unexpectedly destroyed\n"
+msgstr "Vim: Hlavné okno neoèakávane zru¹ené\n"
+
+msgid "Font Selection"
+msgstr "Výber Písma"
+
+msgid "Used CUT_BUFFER0 instead of empty selection"
+msgstr "Pou¾itý CUT_BUFFER0 namiesto prázdneho výberu"
+
+msgid "&Filter"
+msgstr "&Filter"
+
+msgid "&Cancel"
+msgstr "&Zru¹i»"
+
+msgid "Directories"
+msgstr "Adresáre"
+
+msgid "Filter"
+msgstr "Filter"
+
+msgid "&Help"
+msgstr "&Pomocník"
+
+msgid "Files"
+msgstr "Súbory"
+
+msgid "&OK"
+msgstr "&OK"
+
+msgid "Selection"
+msgstr "Výber"
+
+msgid "Find &Next"
+msgstr "Nájs» ïa&l¹ie"
+
+msgid "&Replace"
+msgstr "&Nahradi»"
+
+msgid "Replace &All"
+msgstr "Nahradi» &V¹etko"
+
+msgid "&Undo"
+msgstr "&Spä»"
+
+msgid "E671: Cannot find window title \"%s\""
+msgstr "E671: Nemo¾no nájs» okno s titulkom \"%s\""
+
+#, c-format
+msgid "E243: Argument not supported: \"-%s\"; Use the OLE version."
+msgstr "E243: Argument nie je podporovaný: \"-%s\"; Pou¾ite OLE verziu."
+
+msgid "E672: Unable to open window inside MDI application"
+msgstr "E672: Nemo¾no otvori» okno vnútri MDI aplikácie"
+
+msgid "Find string (use '\\\\' to find a '\\')"
+msgstr "Nájs» re»azec (pou¾ite '\\\\' ak chete nájs» '\\')"
+
+# Following warning can be ignored:
+# msgfmt -v --statistics --check -C --check-accelerators="&" -o sk.mo sk.po
+# sk.po:2497: msgstr lacks the keyboard accelerator mark '&'
+msgid "Find & Replace (use '\\\\' to find a '\\')"
+msgstr "Nájs» a Nahradi» (pou¾ite '\\\\' ak chcete nájs» '\\')"
+
+#. We fake this: Use a filter that doesn't select anything and a default
+#. * file name that won't be used.
+msgid "Not Used"
+msgstr "[neupravovaný]"
+
+msgid "Directory\t*.nothing\n"
+msgstr "Adresár\t*.niè\n"
+
+msgid "Vim E458: Cannot allocate colormap entry, some colors may be incorrect"
+msgstr ""
+"Vim E458: Nedá sa alokova» polo¾ka mapy farieb, niektoré farby mô¾u by» "
+"nesprávne"
+
+#, c-format
+msgid "E250: Fonts for the following charsets are missing in fontset %s:"
+msgstr "E250: Chýba písmo pre nasledujúce znakové sady %s:"
+
+#, c-format
+msgid "E252: Fontset name: %s"
+msgstr "E252: Názov sady písiem: %s"
+
+#, c-format
+msgid "Font '%s' is not fixed-width"
+msgstr "Písmo '%s' nemá pevnou ¹írku"
+
+#, c-format
+msgid "E253: Fontset name: %s\n"
+msgstr "E253: Názov sady písiem: %s\n"
+
+#, c-format
+msgid "Font0: %s\n"
+msgstr "Písmo0: %s\n"
+
+#, c-format
+msgid "Font1: %s\n"
+msgstr "Písmo1: %s\n"
+
+msgid "Font%ld width is not twice that of font0\n"
+msgstr "Písmo%ld nie je dvakrát ¹ir¹ie ako písmo0\n"
+
+#, c-format
+msgid "Font0 width: %ld\n"
+msgstr "©írka písma0: %ld\n"
+
+#, c-format
+msgid ""
+"Font1 width: %ld\n"
+"\n"
+msgstr ""
+"©írka písma1: %ld\n"
+"\n"
+
+msgid "Invalid font specification"
+msgstr "Chybná ¹pecifikácia písma"
+
+msgid "&Dismiss"
+msgstr "&Zru¹i»"
+
+msgid "no specific match"
+msgstr "¾iadna ¹pecifická zhoda"
+
+msgid "Vim - Font Selector"
+msgstr "Vim - Výber písma"
+
+msgid "Name:"
+msgstr "Meno:"
+
+#. create toggle button
+msgid "Show size in Points"
+msgstr "Ukazuj veµkos» v bodoch"
+
+msgid "Encoding:"
+msgstr "Kódujem:"
+
+msgid "Font:"
+msgstr "Písmo:"
+
+msgid "Style:"
+msgstr "©týl"
+
+msgid "Size:"
+msgstr "Veµkos»:"
+
+msgid "E256: Hangul automata ERROR"
+msgstr "E256: Hangul ERROR - chyba kórejského spôsobu vkladania znakov"
+
+msgid "E550: Missing colon"
+msgstr "E550: Chýba dvojbodka"
+
+msgid "E551: Illegal component"
+msgstr "E551: Neprípustný komponent"
+
+msgid "E552: digit expected"
+msgstr "E552: oèakávaná èíslica"
+
+#, c-format
+msgid "Page %d"
+msgstr "Strana %d"
+
+msgid "No text to be printed"
+msgstr "®iadny text na tlaè"
+
+#, c-format
+msgid "Printing page %d (%d%%)"
+msgstr "Tlaèím stranu %d (%d%%)"
+
+#, c-format
+msgid " Copy %d of %d"
+msgstr " Kópia %d z %d"
+
+#, c-format
+msgid "Printed: %s"
+msgstr "Vytlaèené: %s"
+
+msgid "Printing aborted"
+msgstr "Tlaè bola zru¹ená"
+
+msgid "E455: Error writing to PostScript output file"
+msgstr "E455: Nedá sa zapisova» do výstupného PostScriptového súboru"
+
+msgid "E624: Can't open file \"%s\""
+msgstr "E624: Nedá sa otvori» súbor \"%s\""
+
+#, c-format
+msgid "E457: Can't read PostScript resource file \"%s\""
+msgstr "E457: Nedá sa èíta» PostScriptový súbor \"%s\""
+
+msgid "E618: file \"%s\" is not a PostScript resource file"
+msgstr "E618: súbor \"%s\" nie je vo formáte PostScript"
+
+msgid "E619: file \"%s\" is not a supported PostScript resource file"
+msgstr "E619: súbor \"%s\" nie je podporvaný PostScriptový súbor"
+
+#, c-format
+msgid "E621: \"%s\" resource file has wrong version"
+msgstr "E621: \"%s\" zdrojový súbor má zlé èíslo verzie"
+
+msgid "E673: Incompatible multi-byte encoding and character set."
+msgstr "E673: nekompatibilné viacbajtové kódovanie a znaková sada."
+
+msgid "E674: printmbcharset cannot be empty with multi-byte encoding."
+msgstr "E674: voµba printmbcharset nemô¾e by» prázdna pri viacbajtovom kódovaní."
+
+msgid "E675: No default font specified for multi-byte printing."
+msgstr "E675: Nie je ¹pecifikované ¾iadne písmo pre viacbajtové tlaèenie."
+
+msgid "E324: Can't open PostScript output file"
+msgstr "E324: Nedá sa otvori» výstupný PostScriptový súbor"
+
+#, c-format
+msgid "E456: Can't open file \"%s\""
+msgstr "E456: Nedá sa otvori» súbor \"%s\""
+
+msgid "E456: Can't find PostScript resource file \"prolog.ps\""
+msgstr "E456: Nemo¾no nájs» PostScriptový zdrojový súbor \"prolog.ps\""
+
+msgid "E456: Can't find PostScript resource file \"cidfont.ps\""
+msgstr "E456: Nemo¾no nájs» PostScriptový zdrojový súbor \"cidfont.ps\""
+
+msgid "E456: Can't find PostScript resource file \"%s.ps\""
+msgstr "E456: Nemo¾no nájs» PostScriptový zdrojový súbor \"%s.ps\""
+
+#, c-format
+msgid "E620: Unable to convert to print encoding \"%s\""
+msgstr "E620: Nemo¾no skonvertova» do kódovania na tlaèenie \"%s\""
+
+msgid "Sending to printer..."
+msgstr "Posielam na tlaèiareò..."
+
+msgid "E365: Failed to print PostScript file"
+msgstr "E365: PostScriptový súbor sa nepodarilo vytlaèi»"
+
+msgid "Print job sent."
+msgstr "Tlaèová úloha bola odoslaná."
+
+msgid "Add a new database"
+msgstr "Prida» novú databázu"
+
+msgid "Query for a pattern"
+msgstr "Hµadanie vzoru"
+
+msgid "Show this message"
+msgstr "Zobrazi» túto správu"
+
+msgid "Kill a connection"
+msgstr "Ukonèi» spojenie"
+
+msgid "Reinit all connections"
+msgstr "Znovu inicializova» v¹etky spojenia"
+
+msgid "Show connections"
+msgstr "Zobrazi» spojenia"
+
+msgid "E560: Usage: cs[cope] %s"
+msgstr "E560: Pou¾itie: cs[cope] %s"
+
+msgid "This cscope command does not support splitting the window.\n"
+msgstr "Tento cscope príkaz nepodporuje rozdeµovanie okna.\n"
+
+msgid "E562: Usage: cstag <ident>"
+msgstr "E562: Pou¾itie: cstag <odsadenie>"
+
+msgid "E257: cstag: tag not found"
+msgstr "E257: cstag: tag nenájdený"
+
+msgid "E563: stat(%s) error: %d"
+msgstr "E563: stat(%s) chyba: %d"
+
+msgid "E563: stat error"
+msgstr "E563: chyba stat"
+
+msgid "E564: %s is not a directory or a valid cscope database"
+msgstr "E564: %s nie je ani adresárom ani správnou cscope databázou"
+
+#, c-format
+msgid "Added cscope database %s"
+msgstr "Pridaná cscope databáza %s"
+
+msgid "E262: error reading cscope connection %ld"
+msgstr "E262: chyba pri èítaní cscope spojenia %ld"
+
+msgid "E561: unknown cscope search type"
+msgstr "E561: neznámy typ cscope hµadania"
+
+msgid "E566: Could not create cscope pipes"
+msgstr "E566: Nedajú sa vytvori» cscope rúry"
+
+msgid "E622: Could not fork for cscope"
+msgstr "E622: Nemo¾no spusti» proces pre cscope"
+
+msgid "cs_create_connection exec failed"
+msgstr "spustenie cs_create_connection zlyhalo"
+
+msgid "E623: Could not spawn cscope process"
+msgstr "E623: Nedajú sa vytvori» cscope rúry"
+
+msgid "cs_create_connection: fdopen for to_fp failed"
+msgstr "cs_create_connection: volanie fdopen pre to_fp zlyhalo"
+
+msgid "cs_create_connection: fdopen for fr_fp failed"
+msgstr "cs_create_connection: volanie fdopen pre fr_fp zlyhalo"
+
+msgid "E567: no cscope connections"
+msgstr "E567: ¾iadne cscope spojenia"
+
+#, c-format
+msgid "E259: no matches found for cscope query %s of %s"
+msgstr "E259: cscope hµadanie %s vo vzore %s nena¹lo ¾iadnu zhodu"
+
+#, c-format
+msgid "E469: invalid cscopequickfix flag %c for %c"
+msgstr "E469: chybný cscopequickfix príznak %c pre %c"
+
+msgid "cscope commands:\n"
+msgstr "príkazy cscope:\n"
+
+msgid "%-5s: %-30s (Usage: %s)"
+msgstr "%-5s: %-30s (Pou¾itie: %s)"
+
+msgid "E625: cannot open cscope database: %s"
+msgstr "E625: nemo¾no otvori» cscope databázu: %s"
+
+msgid "E626: cannot get cscope database information"
+msgstr "E626: nemo¾no získa» cscope databázové informácie"
+
+msgid "E568: duplicate cscope database not added"
+msgstr "E568: duplicitná cscope databáza nebola pridaná"
+
+msgid "E569: maximum number of cscope connections reached"
+msgstr "E569: dosiahnutý maximálny poèet cscope spojení"
+
+#, c-format
+msgid "E261: cscope connection %s not found"
+msgstr "E261: cscope spojenie %s nenájdené"
+
+msgid "cscope connection %s closed"
+msgstr "cscope spojenie %s ukonèené"
+
+#. should not reach here
+msgid "E570: fatal error in cs_manage_matches"
+msgstr "E570: vá¾na chyba v cs_manage_matches"
+
+msgid "Cscope tag: %s"
+msgstr "Cscope tag: %s"
+
+msgid ""
+"\n"
+" # line"
+msgstr ""
+"\n"
+" # riadok"
+
+msgid "filename / context / line\n"
+msgstr "názov súboru/ kontext / riadok\n"
+
+msgid "E609: Cscope error: %s"
+msgstr "E609: Chyba cscope: %s"
+
+msgid "All cscope databases reset"
+msgstr "V¹etky cscope databáze resetované"
+
+msgid "no cscope connections\n"
+msgstr "¾iadne cscope spojenia\n"
+
+msgid " # pid database name prepend path\n"
+msgstr " # pid názov databázy predpona cesty\n"
+
+msgid ""
+"???: Sorry, this command is disabled, the MzScheme library could not be "
+"loaded."
+msgstr "???: Prepáète, tento príkaz je vypnutý, MzScheme kni¾nica nemô¾e by» naèítaná."
+
+msgid "invalid expression"
+msgstr "chybný výraz"
+
+msgid "expressions disabled at compile time"
+msgstr "podpora výrazov bola vypnutá pri preklade programu"
+
+msgid "hidden option"
+msgstr "skrytá voµba"
+
+msgid "unknown option"
+msgstr "neznáma voµba"
+
+msgid "window index is out of range"
+msgstr "èíslo okna mimo rozsah"
+
+msgid "couldn't open buffer"
+msgstr "nemo¾no otvori» buffer"
+
+msgid "cannot save undo information"
+msgstr "nedajú sa ulo¾i» zálo¾ne (opravné) informácie"
+
+msgid "cannot delete line"
+msgstr "nedá sa vymaza» riadok"
+
+msgid "cannot replace line"
+msgstr "nedá sa nahradi» riadok"
+
+msgid "cannot insert line"
+msgstr "nedá sa vlo¾i» riadok"
+
+msgid "string cannot contain newlines"
+msgstr "re»azec nesmie obsahova» znaky nového riadku"
+
+msgid "Vim error: ~a"
+msgstr "Chyba Vim: ~a"
+
+msgid "Vim error"
+msgstr "Chyba Vim"
+
+msgid "buffer is invalid"
+msgstr "buffer je neplatný"
+
+msgid "window is invalid"
+msgstr "okno je neplatné"
+
+msgid "linenr out of range"
+msgstr "èíslo riadka mimo rozsah"
+
+msgid "not allowed in the Vim sandbox"
+msgstr "nie je dovolené v bezpeènostnej schránke"
+
+msgid ""
+"E263: Sorry, this command is disabled, the Python library could not be "
+"loaded."
+msgstr ""
+"E262: Prepáète, tento príkaz je vypnutý, Python kni¾nica nemô¾e by» naèítaná."
+
+msgid "E659: Cannot invoke Python recursively"
+msgstr "E659: Python nemô¾e by» spustený rekurzívne"
+
+msgid "can't delete OutputObject attributes"
+msgstr "nedá sa vymaza» vlastnos» OutputObject"
+
+msgid "softspace must be an integer"
+msgstr "softspace musí by» kladné celé èíslo"
+
+msgid "invalid attribute"
+msgstr "chybná vlastnos»"
+
+msgid "writelines() requires list of strings"
+msgstr "writelines() vy¾aduje zoznam re»azcov"
+
+msgid "E264: Python: Error initialising I/O objects"
+msgstr "E264: Python: Chyba pri inicializácii I/O objektov"
+
+msgid "attempt to refer to deleted buffer"
+msgstr "pokus o odkaz na vymazaný buffer"
+
+msgid "line number out of range"
+msgstr "èíslo riadka mimo rozsah"
+
+#, c-format
+msgid "<buffer object (deleted) at %8lX>"
+msgstr "<objekt bufferu (vymazaný) na %8lX>"
+
+msgid "invalid mark name"
+msgstr "chybné meno znaèky"
+
+msgid "no such buffer"
+msgstr "¾iadny taký buffer"
+
+msgid "attempt to refer to deleted window"
+msgstr "pokus o odkaz na vymazané okno"
+
+msgid "readonly attribute"
+msgstr "vlastnos» iba pre èítanie"
+
+msgid "cursor position outside buffer"
+msgstr "umiestnenie kurzoru mimo buffer"
+
+#, c-format
+msgid "<window object (deleted) at %.8lX>"
+msgstr "<objekt okna (vymazaný) na %.8lX>"
+
+#, c-format
+msgid "<window object (unknown) at %.8lX>"
+msgstr "<objekt okna (neznámy) na %.8lX>"
+
+#, c-format
+msgid "<window %d>"
+msgstr "<okno %d>"
+
+msgid "no such window"
+msgstr "¾iadne také okno"
+
+msgid ""
+"E266: Sorry, this command is disabled, the Ruby library could not be loaded."
+msgstr ""
+"E266: Prepáète, tento príkaz je vypnutý, Ruby kni¾nica nemô¾e by» naèítaná."
+
+#, c-format
+msgid "E273: unknown longjmp status %d"
+msgstr "E273: Neznámy 'longjmp' stav %d"
+
+msgid "Toggle implementation/definition"
+msgstr "Prepnú» implementáciu/definíciu"
+
+msgid "Show base class of"
+msgstr "Ukáza» základnú triedu"
+
+msgid "Show overridden member function"
+msgstr "Ukáza» pre»a¾enú èlenskú funkciu"
+
+msgid "Retrieve from file"
+msgstr "Obnovi» zo súboru"
+
+msgid "Retrieve from project"
+msgstr "Obnovi» z projektu"
+
+msgid "Retrieve from all projects"
+msgstr "Obnovi» zo v¹etkých projektov"
+
+msgid "Retrieve"
+msgstr "Obnovi»"
+
+msgid "Show source of"
+msgstr "Ukáza» zdroj"
+
+msgid "Find symbol"
+msgstr "Nájs» znak"
+
+msgid "Browse class"
+msgstr "Prezrie» triedu"
+
+msgid "Show class in hierarchy"
+msgstr "Ukáza» triedu v hierarchii"
+
+msgid "Show class in restricted hierarchy"
+msgstr "Ukáza» triedu v obmedzenej hierarchii"
+
+msgid "Xref refers to"
+msgstr "Xref odkazuje na"
+
+msgid "Xref referred by"
+msgstr "Xref odkázaný z"
+
+msgid "Xref has a"
+msgstr "Xref má"
+
+msgid "Xref used by"
+msgstr "Xref pou¾itý"
+
+msgid "Show docu of"
+msgstr "Ukáza» dokumentáciu"
+
+msgid "Generate docu for"
+msgstr "Vytvori» dokumentáciu pre"
+
+msgid ""
+"Cannot connect to SNiFF+. Check environment (sniffemacs must be found in "
+"$PATH).\n"
+msgstr ""
+"Zlyhalo pripojenie na SNiFF+, Preverte prostredie (sniffemacs sa musí "
+"nachádza» v $PATH).\n"
+
+msgid "E274: Sniff: Error during read. Disconnected"
+msgstr "E274: Sniff: Chyba poèas èítania. Odpojené"
+
+msgid "SNiFF+ is currently "
+msgstr "SNiFF+ je aktuálne "
+
+msgid "not "
+msgstr "ne"
+
+msgid "connected"
+msgstr "pripojený"
+
+#, c-format
+msgid "E275: Unknown SNiFF+ request: %s"
+msgstr "E275: Neznáma SNiFF+ po¾iadavka: %s"
+
+msgid "E276: Error connecting to SNiFF+"
+msgstr "E276: Chyba pripojenia na SNiFF+"
+
+msgid "E278: SNiFF+ not connected"
+msgstr "E278: SNiFF+ nie je pripojený"
+
+msgid "E279: Not a SNiFF+ buffer"
+msgstr "E279: Nie je SNiFF+ bufferom"
+
+msgid "Sniff: Error during write. Disconnected"
+msgstr "Sniff: Chyba zápisu. Odpojené"
+
+msgid "invalid buffer number"
+msgstr "chybné èíslo bufferu"
+
+msgid "not implemented yet"
+msgstr "nie je e¹te podporované"
+
+#. ???
+msgid "cannot set line(s)"
+msgstr "nedajú sa nastavi» riadky"
+
+msgid "mark not set"
+msgstr "znaèka nie je nastavená"
+
+#, c-format
+msgid "row %d column %d"
+msgstr "riadok %d ståpec %d"
+
+msgid "cannot insert/append line"
+msgstr "nedá sa vlo¾i»/pripoji» riadok"
+
+msgid "unknown flag: "
+msgstr "neznámy príznak: "
+
+msgid "unknown vimOption"
+msgstr "neznáma voµba (vimOption)"
+
+msgid "keyboard interrupt"
+msgstr "preru¹enie z klávesnice"
+
+msgid "vim error"
+msgstr "chyba Vim"
+
+msgid "cannot create buffer/window command: object is being deleted"
+msgstr "nedá sa vytvori» príkaz bufferu/okna: objekt bude vymazaný"
+
+msgid ""
+"cannot register callback command: buffer/window is already being deleted"
+msgstr ""
+"nedá sa zaregistrova» príkaz spätného volania: buffer/okno u¾ bol vymazaný"
+
+#. This should never happen. Famous last word?
+msgid ""
+"E280: TCL FATAL ERROR: reflist corrupt!? Please report this to vim-dev@vim."
+"org"
+msgstr ""
+"E280: TCL FATAL ERROR: reflist po¹kodený!? Oznámte, prosím, túto chybu na "
+"vim-dev@vim.org"
+
+msgid "cannot register callback command: buffer/window reference not found"
+msgstr ""
+"nedá sa zaregistrova» príkaz spätného volania: odkaz na buffer/okno nenájdený"
+
+msgid ""
+"E571: Sorry, this command is disabled: the Tcl library could not be loaded."
+msgstr ""
+"E571: Prepáète, tento príkaz je vypnutý, Tcl kni¾nica nemô¾e by» naèítaná."
+
+msgid ""
+"E281: TCL ERROR: exit code is not int!? Please report this to vim-dev@vim.org"
+msgstr ""
+"E281: TCL CHYBA: návratový kód nie je celé èíslo!? Oznámte, prosím, túto "
+"chybu na vim-dev@vim.org"
+
+#, c-format
+msgid "E572: exit code %d"
+msgstr "E572: návratový kód %d"
+
+msgid "cannot get line"
+msgstr "nedá sa preèíta» riadok"
+
+msgid "Unable to register a command server name"
+msgstr "Nemô¾em zaregistrova» meno príkazového servra"
+
+msgid "E248: Failed to send command to the destination program"
+msgstr "E248: Chyba poèas prenosu príkazu do cieµového programu"
+
+msgid "E573: Invalid server id used: %s"
+msgstr "E573: Pou¾íté chybné èíslo servera: %s"
+
+msgid "E251: VIM instance registry property is badly formed. Deleted!"
+msgstr "E251: VIM registrová vlastnos» je zle formátovaná. Vymazané!"
+
+msgid "Unknown option argument"
+msgstr "Neznámy parameter voµby"
+
+msgid "Too many edit arguments"
+msgstr "Príli¹ mnoho upravovacích argumentov"
+
+msgid "Argument missing after"
+msgstr "Chýba argument po"
+
+msgid "Garbage after option argument"
+msgstr "Chyby za parametrom voµby"
+
+msgid "Too many \"+command\", \"-c command\" or \"--cmd command\" arguments"
+msgstr "Príli¹ mnoho \"+príkaz\", \"-c príkaz\" alebo \"--cmd príkaz\" argumentov"
+
+msgid "Invalid argument for"
+msgstr "Chybný argument pre"
+
+#, c-format
+msgid "%d files to edit\n"
+msgstr "%d súborov pre úpravu\n"
+
+msgid "This Vim was not compiled with the diff feature."
+msgstr "Tento Vim nebol kompilovaný s porovnávacími funkciami."
+
+msgid "Attempt to open script file again: \""
+msgstr "Pokus o opätovné otvorenie skriptu: \""
+
+msgid "Cannot open for reading: \""
+msgstr "Nedá sa otvori» pre zápis: \""
+
+msgid "Cannot open for script output: \""
+msgstr "Nedá sa otvori» pre výstup skriptu: \""
+
+msgid "Vim: Error: Failure to start gvim from NetBeans\n"
+msgstr "Vim: Chyba: Chyba spú¹»ania gvim pre NetBeans\n"
+
+msgid "Vim: Warning: Output is not to a terminal\n"
+msgstr "Vim: Varovanie: Výstup nesmeruje na terminál\n"
+
+msgid "Vim: Warning: Input is not from a terminal\n"
+msgstr "Vim: Varovanie: Vstup nepochádza z terminálu\n"
+
+#. just in case..
+msgid "pre-vimrc command line"
+msgstr "pre-vimrc príkazový riadok"
+
+#, c-format
+msgid "E282: Cannot read from \"%s\""
+msgstr "E282: Nedá sa èíta» z \"%s\""
+
+msgid ""
+"\n"
+"More info with: \"vim -h\"\n"
+msgstr ""
+"\n"
+"Podrobnej¹ie informácie získáte pomocou \"vim -h\"\n"
+
+msgid "[file ..] edit specified file(s)"
+msgstr "[súbor ..] .. upravi» súbor(y)"
+
+msgid "- read text from stdin"
+msgstr "- èíta» text z ¹tandardného vstupu"
+
+msgid "-t tag edit file where tag is defined"
+msgstr "-t tag upravi» súbor na mieste definície tagu"
+
+msgid "-q [errorfile] edit file with first error"
+msgstr "-q [chybový súbor] upravi» súbor na mieste výskytu prvej chyby"
+
+msgid ""
+"\n"
+"\n"
+"Usage:"
+msgstr ""
+"\n"
+"\n"
+"pou¾itie:"
+
+msgid " vim [arguments] "
+msgstr "vim [argumenty] "
+
+msgid ""
+"\n"
+" or:"
+msgstr ""
+"\n"
+" alebo:"
+
+#. TODO: is translation correct?
+msgid "where case is ignored prepend / to make flag upper case"
+msgstr "v prípade, ¾e je ignorovaná veµkos» písmen, pou¾ite znak '/' na zaèiatku, aby mal príznak význam veµkého písmena"
+
+msgid ""
+"\n"
+"\n"
+"Arguments:\n"
+msgstr ""
+"\n"
+"\n"
+"Argumenty:\n"
+
+msgid "--\t\t\tOnly file names after this"
+msgstr "--\t\t\tMô¾u nasledova» iba názvy súborov"
+
+msgid "--literal\t\tDon't expand wildcards"
+msgstr "--literal\t\tNexpandova» ¾olíkové znaky (wildcards)"
+
+msgid "-register\t\tRegister this gvim for OLE"
+msgstr "-register\t\tPrihlási» gvim na OLE"
+
+msgid "-unregister\t\tUnregister gvim for OLE"
+msgstr "-register\t\tOdhlási» gvim z OLE"
+
+msgid "-g\t\t\tRun using GUI (like \"gvim\")"
+msgstr "-g\t\t\tSpusti» v grafickom (GUI) móde (rovnaké ako \"gvim\")"
+
+msgid "-f or --nofork\tForeground: Don't fork when starting GUI"
+msgstr ""
+"-f alebo --nofork\tPopredie: Pri spustení grafického (GUI) módu sa nepresunie do pozadia"
+
+msgid "-v\t\t\tVi mode (like \"vi\")"
+msgstr "-v\t\t\tVi mód (rovnaké ako \"vi\")"
+
+msgid "-e\t\t\tEx mode (like \"ex\")"
+msgstr "-e\t\t\tEx mód (rovnaké ako \"ex\")"
+
+msgid "-s\t\t\tSilent (batch) mode (only for \"ex\")"
+msgstr "-s\t\t\tTichý (dávkový) mód (iba pre \"ex\")"
+
+msgid "-d\t\t\tDiff mode (like \"vimdiff\")"
+msgstr "-d\t\t\tPorovnávací mód (rovnaké ako \"vimdiff\")"
+
+msgid "-y\t\t\tEasy mode (like \"evim\", modeless)"
+msgstr "-y\t\t\tJednoduchý mód (rovnaké ako \"evim\", bezmódový)"
+
+msgid "-R\t\t\tReadonly mode (like \"view\")"
+msgstr "-R\t\t\tMód iba pre èítanie (ako \"view\")"
+
+msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
+msgstr "-Z\t\t\tObmedzený mód (rovnaké ako \"rvim\")"
+
+msgid "-m\t\t\tModifications (writing files) not allowed"
+msgstr "-m\t\t\tZmeny (ukladanie súborov) zakázané"
+
+msgid "-M\t\t\tModifications in text not allowed"
+msgstr "-M\t\t\tZmeny v texte zakázané"
+
+msgid "-b\t\t\tBinary mode"
+msgstr "-b\t\t\tBinárny mód"
+
+msgid "-l\t\t\tLisp mode"
+msgstr "-l\t\t\tLisp mód"
+
+msgid "-C\t\t\tCompatible with Vi: 'compatible'"
+msgstr "-C\t\t\tKompatabilný s Vi: 'compatible'"
+
+msgid "-N\t\t\tNot fully Vi compatible: 'nocompatible'"
+msgstr "-N\t\t\tKompatibilita s Vi vypnutá: 'nocompatible'"
+
+msgid "-V[N]\t\tVerbose level"
+msgstr "-V[N]\t\tÚroveò výpisu hlá¹ok"
+
+msgid "-D\t\t\tDebugging mode"
+msgstr "-D\t\t\tLadiaci mód"
+
+msgid "-n\t\t\tNo swap file, use memory only"
+msgstr "-n\t\t\tNevytvára» odkladací súbor, pou¾íva» iba pamä»"
+
+msgid "-r\t\t\tList swap files and exit"
+msgstr "-r\t\t\tVypí¹ zoznam odkladacích súborov a skonèi"
+
+msgid "-r (with file name)\tRecover crashed session"
+msgstr "-r (s názvom súboru)\tObnoví preru¹ené sedenie"
+
+msgid "-L\t\t\tSame as -r"
+msgstr "-L\t\t\tRovnaké ako -r"
+
+msgid "-f\t\t\tDon't use newcli to open window"
+msgstr "-f\t\t\tNebude pou¾íva» newcli pre otvorenie okna"
+
+msgid "-dev <device>\t\tUse <device> for I/O"
+msgstr "-dev <zariadenie>\t\tPou¾i» <zariadenie> pre I/O"
+
+msgid "-A\t\t\tStart in Arabic mode"
+msgstr "-A\t\t\tspusti v Arabic móde"
+
+msgid "-H\t\t\tStart in Hebrew mode"
+msgstr "-H\t\t\tspusti v hebrejskom móde"
+
+msgid "-F\t\t\tStart in Farsi mode"
+msgstr "-F\t\t\tspusti vo Farsi móde"
+
+msgid "-T <terminal>\tSet terminal type to <terminal>"
+msgstr "-T <terminál>\tNastaví typ terminálu na <terminál>"
+
+msgid "-u <vimrc>\t\tUse <vimrc> instead of any .vimrc"
+msgstr "-u <vimrc>\t\tPou¾ije <vimrc> namiesto akéhokoµvek .vimrc"
+
+msgid "-U <gvimrc>\t\tUse <gvimrc> instead of any .gvimrc"
+msgstr "-U <gvimrc>\t\tPou¾ije <gvimrc> namiesto akéhokoµvek .gvimrc"
+
+msgid "--noplugin\t\tDon't load plugin scripts"
+msgstr "--noplugin\t\tNenahrá zásuvné moduly(plugin skripty)"
+
+msgid "-o[N]\t\tOpen N windows (default: one for each file)"
+msgstr "-o[N]\t\tOtvorí N okien (implicitne jedno pre ka¾dý súbor)"
+
+msgid "-O[N]\t\tLike -o but split vertically"
+msgstr "-O[N]\t\tAko -o ale rozdelí vertikálne"
+
+msgid "+\t\t\tStart at end of file"
+msgstr "+\t\t\tNastaví kurzor na koniec súboru"
+
+msgid "+<lnum>\t\tStart at line <lnum>"
+msgstr "+<riadok>\t\tNastaví kurzor na <riadok>"
+
+msgid "--cmd <command>\tExecute <command> before loading any vimrc file"
+msgstr "--cmd <príkaz>\t\tVykoná <príkaz> pred nahratím vimrc súboru"
+
+msgid "-c <command>\t\tExecute <command> after loading the first file"
+msgstr "-c <príkaz>\t\tPo nahratí prvého súboru vykoná <príkaz>"
+
+msgid "-S <session>\t\tSource file <session> after loading the first file"
+msgstr ""
+"-S <sedenie>\t\tPo nahratí prvého súboru vykoná príkazy v súbore <sedenie>"
+
+msgid "-s <scriptin>\tRead Normal mode commands from file <scriptin>"
+msgstr "-s <skript>\t\tNaèíta príkazy normálneho módu zo <skriptu>"
+
+msgid "-w <scriptout>\tAppend all typed commands to file <scriptout>"
+msgstr "-w <skript>\t\tPripojí v¹etky napísané príkazy do súboru <skript>"
+
+msgid "-W <scriptout>\tWrite all typed commands to file <scriptout>"
+msgstr "-W <skript>\t\tUlo¾í v¹etky napísané príkazy do súboru <skript>"
+
+msgid "-x\t\t\tEdit encrypted files"
+msgstr "-x\t\t\tÚprava za¹ifrovaných súborov"
+
+msgid "-display <display>\tConnect vim to this particular X-server"
+msgstr "-display <displej>\tPripojí vim na príslu¹ný X-server"
+
+msgid "-X\t\t\tDo not connect to X server"
+msgstr "-X\t\t\tNepripojí sa k X serveru"
+
+msgid "--remote <files>\tEdit <files> in a Vim server if possible"
+msgstr "--remote <súbory>\tUpravi» <súbory> na Vim servri ak je to mo¾né"
+
+msgid "--remote-silent <files> Same, don't complain if there is no server"
+msgstr "--remote-silent <súbory>\tTo isté, ale nes»a¾uj si, ak neexistuje server"
+
+msgid ""
+"--remote-wait <files> As --remote but wait for files to have been edited"
+msgstr ""
+"--remote-wait <súbory>\tAko --remote ale èaká na súbory pre ukonèenie úprav"
+
+msgid ""
+"--remote-wait-silent <files> Same, don't complain if there is no server"
+msgstr "--remote-wait-silent <súbory>\tTo isté, ale nes»a¾uj si, ak neexistuje server"
+
+msgid "--remote-send <keys>\tSend <keys> to a Vim server and exit"
+msgstr "--remote-send <voµby>\tOdo¹le <voµby> na Vim server a skonèí"
+
+msgid "--remote-expr <expr>\tEvaluate <expr> in a Vim server and print result"
+msgstr "--remote-expr <výraz>\tSpusti <výraz> na servri a vytlaèí výsledok"
+
+msgid "--serverlist\t\tList available Vim server names and exit"
+msgstr "--serverlist\t\tVypí¹e zoznam mien dostupných Vim servrov a skonèí"
+
+msgid "--servername <name>\tSend to/become the Vim server <name>"
+msgstr "--servername <názov>\tOdo¹le na Vim server <názov>"
+
+msgid "-i <viminfo>\t\tUse <viminfo> instead of .viminfo"
+msgstr "-i <viminfo>\t\tPou¾ije <viminfo> namiesto akéhokoµvek .viminfo"
+
+msgid "-h or --help\tPrint Help (this message) and exit"
+msgstr "-h alebo --help\tVypí¹e túto nápovedu a skonèí"
+
+msgid "--version\t\tPrint version information and exit"
+msgstr "--version\t\tVypí¹e informácie o verzii a skonèí"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Motif version):\n"
+msgstr ""
+"\n"
+"Argumenty dostupné pre gvim (Motif verzia):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (neXtaw version):\n"
+msgstr ""
+"\n"
+"Argumenty dostupné pre gvim (neXtaw verzia):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Athena version):\n"
+msgstr ""
+"\n"
+"Argumenty dostupné pre gvim (Athena verzia):\n"
+
+msgid "-display <display>\tRun vim on <display>"
+msgstr "-display <displej>\tSpustí vim na <displej>"
+
+msgid "-iconic\t\tStart vim iconified"
+msgstr "-iconic\t\tSpustí vim minimalizované"
+
+msgid "-name <name>\t\tUse resource as if vim was <name>"
+msgstr "-name <názov>\t\tPou¾ije resource ako by vim mal <názov>"
+
+msgid "\t\t\t (Unimplemented)\n"
+msgstr "\t\t\t (nie je implementované)\n"
+
+msgid "-background <color>\tUse <color> for the background (also: -bg)"
+msgstr "-background <farba>\tNastaví sa <farba> pozadia (tie¾ -bg)"
+
+msgid "-foreground <color>\tUse <color> for normal text (also: -fg)"
+msgstr "-foreground <farba>\tNastaví sa <farba> popredia (tie¾ -fg)"
+
+msgid "-font <font>\t\tUse <font> for normal text (also: -fn)"
+msgstr "-font <písmo>\t\tNastaví <písmo> normálneho textu (tie¾ -fn)"
+
+msgid "-boldfont <font>\tUse <font> for bold text"
+msgstr "-boldfont <písmo>\tNastaví <písmo> pre zvýraznený text"
+
+msgid "-italicfont <font>\tUse <font> for italic text"
+msgstr "-italicfont <písmo>\tNastaví <písmo> pre kurzívu"
+
+msgid "-geometry <geom>\tUse <geom> for initial geometry (also: -geom)"
+msgstr "-geometry <geometrie>\tNastaví sa <geometria> (tie¾ -geom)"
+
+msgid "-borderwidth <width>\tUse a border width of <width> (also: -bw)"
+msgstr "-borderwidth <¹írka>\tNastaví <¹írku> okrajov (tie¾ -bw)"
+
+msgid "-scrollbarwidth <width> Use a scrollbar width of <width> (also: -sw)"
+msgstr "-scrollbarwidth <¹írka> Nastaví <¹írku> posuvnej li¹ty (tie¾ -sw)"
+
+msgid "-menuheight <height>\tUse a menu bar height of <height> (also: -mh)"
+msgstr "-menuheight <vý¹ka>\tNastaví <vý¹ku> ponuky (tie¾ -mh)"
+
+msgid "-reverse\t\tUse reverse video (also: -rv)"
+msgstr "-reverse\t\tPou¾ije reverzné farby (tie¾ -rv)"
+
+msgid "+reverse\t\tDon't use reverse video (also: +rv)"
+msgstr "+reverse\t\tNepou¾ije reverzné farby (tie¾ +rv)"
+
+# TODO: howto translate 'resource' in this case?
+msgid "-xrm <resource>\tSet the specified resource"
+msgstr "-xrm <resource>\tNastaví zadaný <resource>"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (RISC OS version):\n"
+msgstr ""
+"\n"
+"Argumenty dostupné pre gvim (RISC OS verzia):\n"
+
+msgid "--columns <number>\tInitial width of window in columns"
+msgstr "--columns <poèet>\tPoèiatoèná ¹írka okna v ståpcoch"
+
+msgid "--rows <number>\tInitial height of window in rows"
+msgstr "--rows <poèet>\tPoèiatoèná vý¹ka okna v riadkoch"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (GTK+ version):\n"
+msgstr ""
+"\n"
+"Argumenty dostupné pre gvim (GTK+ verzia):\n"
+
+msgid "-display <display>\tRun vim on <display> (also: --display)"
+msgstr "-display <displej>\tSpustí vim na <displej> (tie¾ --display)"
+
+msgid "--role <role>\tSet a unique role to identify the main window"
+msgstr "-role <rola>\tNastaví unikátnu rolu pre identifikáciu hlavného okna"
+
+msgid "--socketid <xid>\tOpen Vim inside another GTK widget"
+msgstr "--socketid <xid>\tOtvorí Vim vnútri iného GTK programu."
+
+msgid ""
+"\n"
+"Arguments recognised by kvim (KDE version):\n"
+msgstr ""
+"\n"
+"Argumenty dostupné pre kvim (KDE verzia):\n"
+
+msgid "-black\t\tUse reverse video"
+msgstr "-black\t\tPou¾ije reverzné farby"
+
+msgid "-tip\t\t\tDisplay the tip dialog on startup"
+msgstr "-tip\t\t\tZobraz tip pri ¹tarte"
+
+msgid "-notip\t\tDisable the tip dialog"
+msgstr "-notip\t\tNezobrazuj tip pri ¹tarte"
+
+msgid "--display <display>\tRun vim on <display>"
+msgstr "-display <displej>\tSpustí vim na <displej>"
+
+msgid "-P <parent title>\tOpen Vim inside parent application"
+msgstr "-P <titulok rodièa>\tOtvor Vim vnútri materskej aplikácie"
+
+msgid "No display"
+msgstr "Bez grafického rozhrania"
+
+#. Failed to send, abort.
+msgid ": Send failed.\n"
+msgstr ": Odoslanie zlyhalo.\n"
+
+#. Let vim start normally.
+msgid ": Send failed. Trying to execute locally\n"
+msgstr ": Odoslanie zlyhalo. Pokú¹am sa spusti» lokálne\n"
+
+#, c-format
+msgid "%d of %d edited"
+msgstr "%d upravených súborov z %d"
+
+msgid "No display: Send expression failed.\n"
+msgstr "®iaden graf. mód: Odoslanie výrazu zlyhalo.\n"
+
+msgid ": Send expression failed.\n"
+msgstr ": Odoslanie výrazu zlyhalo.\n"
+
+msgid "No marks set"
+msgstr "Nie sú nastavené ¾iadne znaèky"
+
+#, c-format
+msgid "E283: No marks matching \"%s\""
+msgstr "E283:\"%s\" nevyhovujú ¾iadne znaèky"
+
+#. Highlight title
+msgid ""
+"\n"
+"mark line col file/text"
+msgstr ""
+"\n"
+"znaèka riadok ståpec súbor/text"
+
+#. Highlight title
+msgid ""
+"\n"
+" jump line col file/text"
+msgstr ""
+"\n"
+" skok riadok ståpec súbor/text"
+
+#. Highlight title
+msgid ""
+"\n"
+"change line col text"
+msgstr ""
+"\n"
+"znaèka riadok ståpec text"
+
+#, c-format
+msgid ""
+"\n"
+"# File marks:\n"
+msgstr ""
+"\n"
+"# Súborové znaèky:\n"
+
+#. Write the jumplist with -'
+#, c-format
+msgid ""
+"\n"
+"# Jumplist (newest first):\n"
+msgstr ""
+"\n"
+"# Zoznam skokov (zaèínajúci najnov¹ou polo¾kou):\n"
+
+#, c-format
+msgid ""
+"\n"
+"# History of marks within files (newest to oldest):\n"
+msgstr ""
+"\n"
+"# História znaèiek v súboroch (zaèínajúci najnov¹ou polo¾kou):\n"
+
+msgid "Missing '>'"
+msgstr "Chýba '>'"
+
+msgid "E543: Not a valid codepage"
+msgstr "E543: Chybná kódová stránka"
+
+msgid "E284: Cannot set IC values"
+msgstr "E284: Nedajú sa nastavi» IC hodnoty"
+
+msgid "E285: Failed to create input context"
+msgstr "E285: Nepodarilo sa vytvori» vstupný kontext"
+
+msgid "E286: Failed to open input method"
+msgstr "E286: Nepodarilo sa otvori» vstupnú metódu"
+
+msgid "E287: Warning: Could not set destroy callback to IM"
+msgstr "E287: Varovanie: likvidaèné spätné volanie sa nedá nastavi» na IM"
+
+msgid "E288: input method doesn't support any style"
+msgstr "E288: vstupná metóda nepodporuje ¾iadny ¹týl"
+
+msgid "E289: input method doesn't support my preedit type"
+msgstr "E289: vstupná metóda nepodporuje môj 'preedit' typ"
+
+msgid "E290: over-the-spot style requires fontset"
+msgstr "E290: Nadbodový ¹týl vy¾aduje sadu fontov (fontset)"
+
+msgid "E291: Your GTK+ is older than 1.2.3. Status area disabled"
+msgstr "E291: Máte GTK+ verziu star¹iu ne¾ 1.2.3. Stavová plocha vypnutá."
+
+msgid "E292: Input Method Server is not running"
+msgstr "E292: Server vstupných metód nebe¾í"
+
+msgid "E293: block was not locked"
+msgstr "E293: blok nebol zamknutý"
+
+msgid "E294: Seek error in swap file read"
+msgstr "E294: Chyba posunu pri èítaní odkladacieho súboru"
+
+msgid "E295: Read error in swap file"
+msgstr "E295: Chyba pri èítaní odkladacieho súboru"
+
+msgid "E296: Seek error in swap file write"
+msgstr "E296: Chyba posunu pri ukladaní do odkladacieho súboru"
+
+msgid "E297: Write error in swap file"
+msgstr "E297: Chyba pri ukladaní do odkladacieho súboru"
+
+msgid "E300: Swap file already exists (symlink attack?)"
+msgstr "E300: Odkladací súbor u¾ existuje (symlink útok?)"
+
+msgid "E298: Didn't get block nr 0?"
+msgstr "E298: Nedá sa získa» blok 0?"
+
+msgid "E298: Didn't get block nr 1?"
+msgstr "E298: Nedá sa získa» blok 1?"
+
+msgid "E298: Didn't get block nr 2?"
+msgstr "E298: Nedá sa získa» blok 2?"
+
+#. could not (re)open the swap file, what can we do????
+msgid "E301: Oops, lost the swap file!!!"
+msgstr "E301: Ups, odkladací súbor bol stratený!!!"
+
+msgid "E302: Could not rename swap file"
+msgstr "E302: Nedá sa premenova» odkladací súbor"
+
+#, c-format
+msgid "E303: Unable to open swap file for \"%s\", recovery impossible"
+msgstr "E303: Nedá sa otvori» odkladací súbor pre \"%s\", oprava nemo¾ná"
+
+msgid "E304: ml_upd_block0(): Didn't get block 0??"
+msgstr "E304: ml_upd_block0(): nedá sa získa» blok 0??"
+
+#, c-format
+msgid "E305: No swap file found for %s"
+msgstr "E305: Odkladací súbor pre %s nebol nájdený"
+
+msgid "Enter number of swap file to use (0 to quit): "
+msgstr ""
+"Zadajte èíslo odkladacieho súboru, ktorý sa má pou¾it (0 pre ukonèenie): "
+
+#, c-format
+msgid "E306: Cannot open %s"
+msgstr "E306: Nedá sa otvori» %s"
+
+msgid "Unable to read block 0 from "
+msgstr "Nedá sa èíta» blok 0 z "
+
+msgid ""
+"\n"
+"Maybe no changes were made or Vim did not update the swap file."
+msgstr ""
+"\n"
+"Mo¾no nedo¹lo k ¾iadnym zmenám, alebo Vim neaktualizoval odkladací súbor."
+
+msgid " cannot be used with this version of Vim.\n"
+msgstr " nedá sa pou¾i» s touto verziou Vim.\n"
+
+msgid "Use Vim version 3.0.\n"
+msgstr "Pou¾ite Vim verziu 3.0.\n"
+
+#, c-format
+msgid "E307: %s does not look like a Vim swap file"
+msgstr "E307: %s sa nezdá by» odkladacím súborom Vim"
+
+msgid " cannot be used on this computer.\n"
+msgstr " nedá sa pou¾í» na tomto poèítaèi.\n"
+
+msgid "The file was created on "
+msgstr "Súbor bol vytvorený "
+
+msgid ""
+",\n"
+"or the file has been damaged."
+msgstr ""
+",\n"
+"alebo bol súbor po¹kodený."
+
+#, c-format
+msgid "Using swap file \"%s\""
+msgstr "Pou¾ívam odkladací súbor \"%s\""
+
+#, c-format
+msgid "Original file \"%s\""
+msgstr "Pôvodný súbor \"%s\""
+
+msgid "E308: Warning: Original file may have been changed"
+msgstr "E308: Varovanie: Pôvodný súbor mohol by» zmenený"
+
+#, c-format
+msgid "E309: Unable to read block 1 from %s"
+msgstr "E309: Nedá sa èíta» blok 1 z %s"
+
+msgid "???MANY LINES MISSING"
+msgstr "???CHÝBA MNOHO RIADKOV"
+
+msgid "???LINE COUNT WRONG"
+msgstr "???CHYBNÝ POÈET RIADKOV"
+
+msgid "???EMPTY BLOCK"
+msgstr "???PRÁZDNY BLOK"
+
+msgid "???LINES MISSING"
+msgstr "???CHÝBAJÚCE RIADKY"
+
+#, c-format
+msgid "E310: Block 1 ID wrong (%s not a .swp file?)"
+msgstr "E310: ID bloku 1 je chybné (je %s odkladacím súborom?)"
+
+msgid "???BLOCK MISSING"
+msgstr "???CHÝBA BLOK"
+
+msgid "??? from here until ???END lines may be messed up"
+msgstr "od ??? po ???END mô¾u by» riadky pomie¹ané"
+
+msgid "??? from here until ???END lines may have been inserted/deleted"
+msgstr "od ??? po ???END mô¾u by» riadky vlo¾ené/vymazané"
+
+msgid "???END"
+msgstr "???KONIEC"
+
+msgid "E311: Recovery Interrupted"
+msgstr "E311: Obnova preru¹ená"
+
+msgid ""
+"E312: Errors detected while recovering; look for lines starting with ???"
+msgstr ""
+"E312: V priebehu obnovy do¹lo k chybám; skontrolujte riadky zaèínajúce na ???"
+
+msgid "See \":help E312\" for more information."
+msgstr "Pozrite \":help E312\" pre ïal¹ie informácie"
+
+msgid "Recovery completed. You should check if everything is OK."
+msgstr "Obnova dokonèená. Skontrolujte, èi je v¹etko v poriadku."
+
+msgid ""
+"\n"
+"(You might want to write out this file under another name\n"
+msgstr ""
+"\n"
+"(Zvá¾te ulo¾enie tohoto súboru pod iným menom\n"
+
+msgid "and run diff with the original file to check for changes)\n"
+msgstr "a pomocou programu diff zistite zmeny oproti pôvodnému súboru)\n"
+
+msgid ""
+"Delete the .swp file afterwards.\n"
+"\n"
+msgstr "Potom vyma¾te odkladací súbor s príponou .swp.\n"
+"\n"
+
+#. use msg() to start the scrolling properly
+msgid "Swap files found:"
+msgstr "Nájdené odkladacie súbory:"
+
+msgid " In current directory:\n"
+msgstr " V aktuálnom adresári:\n"
+
+msgid " Using specified name:\n"
+msgstr " So zadaným menom:\n"
+
+msgid " In directory "
+msgstr " V adresári "
+
+msgid " -- none --\n"
+msgstr " -- ¾iadne --\n"
+
+msgid " owned by: "
+msgstr " vlastník: "
+
+msgid " dated: "
+msgstr " dátum vytvorenia: "
+
+msgid " dated: "
+msgstr " dátum vytvorenia: "
+
+msgid " [from Vim version 3.0]"
+msgstr " [od Vim verzie 3.0]"
+
+msgid " [does not look like a Vim swap file]"
+msgstr " [nevyzerá ako odkladací súbor Vim]"
+
+msgid " file name: "
+msgstr " názov súboru: "
+
+msgid ""
+"\n"
+" modified: "
+msgstr ""
+"\n"
+" zmenený: "
+
+msgid "YES"
+msgstr "ÁNO"
+
+msgid "no"
+msgstr "nie"
+
+msgid ""
+"\n"
+" user name: "
+msgstr ""
+"\n"
+" u¾ívateµské meno: "
+
+msgid " host name: "
+msgstr " názov poèítaèa: "
+
+msgid ""
+"\n"
+" host name: "
+msgstr ""
+"\n"
+" názov poèítaèa: "
+
+msgid ""
+"\n"
+" process ID: "
+msgstr ""
+"\n"
+" ID procesu : "
+
+msgid " (still running)"
+msgstr " (stále be¾í)"
+
+msgid ""
+"\n"
+" [not usable with this version of Vim]"
+msgstr ""
+"\n"
+" [nepou¾iteµné s touto verziou Vim]"
+
+msgid ""
+"\n"
+" [not usable on this computer]"
+msgstr ""
+"\n"
+" [nepou¾itelné na tomto poèítaèi]"
+
+msgid " [cannot be read]"
+msgstr " [nedá sa preèíta»]"
+
+msgid " [cannot be opened]"
+msgstr " [nedá sa otvori»]"
+
+msgid "E313: Cannot preserve, there is no swap file"
+msgstr "E313: Nedá sa zachova» - odkladací súbor neexistuje"
+
+msgid "File preserved"
+msgstr "Súbor zachovaný"
+
+msgid "E314: Preserve failed"
+msgstr "E314: Uchovanie sa nepodarilo"
+
+#, c-format
+msgid "E315: ml_get: invalid lnum: %ld"
+msgstr "E315: ml_get: chybné èíslo riadku: %ld"
+
+#, c-format
+msgid "E316: ml_get: cannot find line %ld"
+msgstr "E316: ml_get: nedá sa nájs» riadok %ld"
+
+msgid "E317: pointer block id wrong 3"
+msgstr "E317: chybné èíslo ukazovateµa na blok 3"
+
+msgid "stack_idx should be 0"
+msgstr "stack_idx by mal ma» hodnotu 3"
+
+msgid "E318: Updated too many blocks?"
+msgstr "E318: Aktualizovaných príli¹ veµa blokov?"
+
+msgid "E317: pointer block id wrong 4"
+msgstr "E317: chybné èíslo ukazovateµa na blok 4"
+
+msgid "deleted block 1?"
+msgstr "vymazaný blok 1?"
+
+#, c-format
+msgid "E320: Cannot find line %ld"
+msgstr "E320: Nedá sa nájs» riadok %ld"
+
+msgid "E317: pointer block id wrong"
+msgstr "E317: chybné èíslo ukazovateµa na blok"
+
+msgid "pe_line_count is zero"
+msgstr "pe_line_count má nulovú hodnotu"
+
+#, c-format
+msgid "E322: line number out of range: %ld past the end"
+msgstr "E322: èíslo riadku je mimo rozsah: %ld (za koncom)"
+
+#, c-format
+msgid "E323: line count wrong in block %ld"
+msgstr "E323: chybný poèet riadkov v bloku %ld"
+
+msgid "Stack size increases"
+msgstr "Nárast veµkosti zásobníku"
+
+msgid "E317: pointer block id wrong 2"
+msgstr "E317: chybný èíslo ukazovateµa na blok 2"
+
+msgid "E325: ATTENTION"
+msgstr "E325: POZOR"
+
+msgid ""
+"\n"
+"Found a swap file by the name \""
+msgstr ""
+"\n"
+"Nájdený odkladací súbor s menom \""
+
+msgid "While opening file \""
+msgstr "Pri otváraní súboru \""
+
+msgid " NEWER than swap file!\n"
+msgstr " NOV©Í ako odkladací súbor!\n"
+
+#. Some of these messages are long to allow translation to
+#. * other languages.
+msgid ""
+"\n"
+"(1) Another program may be editing the same file.\n"
+" If this is the case, be careful not to end up with two\n"
+" different instances of the same file when making changes.\n"
+msgstr ""
+"\n"
+"(1) Súbor mô¾e by» upravovaný iným programom.\n"
+" Ak je tomu tak, potom si dajte pozor, aby ste po ulo¾ení zmien\n"
+" nemali dve rôzne verzie toho istého súboru.\n"
+
+msgid " Quit, or continue with caution.\n"
+msgstr " Ukonèite program, alebo opatrne pokraèujte v úpravách.\n"
+
+msgid ""
+"\n"
+"(2) An edit session for this file crashed.\n"
+msgstr ""
+"\n"
+"(2) Úprava tohoto súboru bola preru¹ená neoèakávaným ukonèením programu.\n"
+
+msgid " If this is the case, use \":recover\" or \"vim -r "
+msgstr " Ak je tomu tak, potom pou¾ite \":recover\" alebo \"vim -r "
+
+msgid ""
+"\"\n"
+" to recover the changes (see \":help recovery\").\n"
+msgstr ""
+"\"\n"
+" pre obnovenie zmien (viï \":help recovery)\".\n"
+
+msgid " If you did this already, delete the swap file \""
+msgstr " Pokiaµ ste tak u¾ urobili, tak vyma¾te odkladací súbor \""
+
+msgid ""
+"\"\n"
+" to avoid this message.\n"
+msgstr ""
+"\"\n"
+" a táto správa sa u¾ nebude objavova».\n"
+
+msgid "Swap file \""
+msgstr "Odkladací súbor \""
+
+msgid "\" already exists!"
+msgstr "\" u¾ existuje!"
+
+msgid "VIM - ATTENTION"
+msgstr "VIM - POZOR"
+
+msgid "Swap file already exists!"
+msgstr "Odkladací súbor u¾ existuje!"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"&Otvori» iba pre èítanie\n"
+"&Pokraèova» v úpravách\n"
+"O&bnovi» súbor\n"
+"&Koniec\n"
+"&Zru¹i»"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Quit\n"
+"&Abort\n"
+"&Delete it"
+msgstr ""
+"&Otvori» iba pre èítanie\n"
+"&Pokraèovat v úpravách\n"
+"O&bnovi» súbor\n"
+"&Koniec\n"
+"&Zru¹i»\n"
+"Z&maza»"
+
+msgid "E326: Too many swap files found"
+msgstr "E326: Príli¹ mnoho odkladacích súborov"
+
+msgid "E327: Part of menu-item path is not sub-menu"
+msgstr "E327: Èas» cesty k predmetu ponuky nie je podponukou"
+
+msgid "E328: Menu only exists in another mode"
+msgstr "E328: Ponuka existuje iba v inom móde"
+
+msgid "E329: No menu \"%s\""
+msgstr "E329: Ponuka \"%s\" neexistuje"
+
+msgid "E330: Menu path must not lead to a sub-menu"
+msgstr "E330: Cesta ponuky nesmie vies» do podponuky"
+
+msgid "E331: Must not add menu items directly to menu bar"
+msgstr "E331: Polo¾ky ponuky sa nejdú pridáva» priamo na li¹tu"
+
+msgid "E332: Separator cannot be part of a menu path"
+msgstr "E332: Oddeµovaè nesmie by» èas»ou cesty ponuky"
+
+#. Now we have found the matching menu, and we list the mappings
+#. Highlight title
+msgid ""
+"\n"
+"--- Menus ---"
+msgstr ""
+"\n"
+"--- Ponuky ---"
+
+msgid "Tear off this menu"
+msgstr "Odtrhnú» tuto ponuku"
+
+msgid "E333: Menu path must lead to a menu item"
+msgstr "E333: Cesta ponuky musí vies» k polo¾ke ponuky"
+
+#, c-format
+msgid "E334: Menu not found: %s"
+msgstr "E334: Ponuka nenájdená: %s"
+
+#, c-format
+msgid "E335: Menu not defined for %s mode"
+msgstr "E335: V %s móde nie je ponuka definovaná"
+
+msgid "E336: Menu path must lead to a sub-menu"
+msgstr "E336: Cesta ponuky musí vies» do podponuky"
+
+msgid "E337: Menu not found - check menu names"
+msgstr "E337: Ponuka nenájdená - skontrolujte názvy ponúk"
+
+#, c-format
+msgid "Error detected while processing %s:"
+msgstr "Chyba pri spracovaní %s:"
+
+#, c-format
+msgid "line %4ld:"
+msgstr "riadok %4ld:"
+
+#, c-format
+msgid "E354: Invalid register name: '%s'"
+msgstr "E354: '%s' nie je prístupné meno registru"
+
+msgid "Messages maintainer: Bram Moolenaar <Bram@vim.org>"
+msgstr "Správca prekladu: Lubomir Host <rajo@platon.sk>"
+
+msgid "Interrupt: "
+msgstr "Preru¹enie: "
+
+msgid "Press ENTER or type command to continue"
+msgstr "Stlaète ENTER alebo zadajte príkaz pre pokraèovanie"
+
+msgid "-- More --"
+msgstr "-- Pokraèovanie --"
+
+msgid " SPACE/d/j: screen/page/line down, b/u/k: up, q: quit "
+msgstr " MEDZERA/d/j: obrazovka/stránka/riadok dole, b/u/k: hore, q: koniec "
+
+msgid "Question"
+msgstr "Otázka"
+
+# TODO: Translate as "&Ano\n&Nie" ?
+msgid ""
+"&Yes\n"
+"&No"
+msgstr ""
+"&Ano\n"
+"&Nie"
+
+# TODO: Translate as "&Ano\n&Nie\n&Ulo¾i» v¹etko\nZahodi» &v¹etko\n&Zru¹i»" ?
+msgid ""
+"&Yes\n"
+"&No\n"
+"Save &All\n"
+"&Discard All\n"
+"&Cancel"
+msgstr ""
+"&Ano\n"
+"&Nie\n"
+"&Ulo¾i» v¹etko\n"
+"Zahodi» &v¹etko\n"
+"&Zru¹i»"
+
+msgid "Select Directory dialog"
+msgstr "Dialóg pre vytvorenie adresára"
+
+msgid "Save File dialog"
+msgstr "Dialóg pre ukladanie súborov"
+
+msgid "Open File dialog"
+msgstr "Dialóg pre otváranie súborov"
+
+msgid "E338: Sorry, no file browser in console mode"
+msgstr "E338: ¥utujem, ale konzolová verzia nepodporuje prehliadaè súborov"
+
+msgid "E766: Insufficient arguments for printf()"
+msgstr "E766: Chybné argumenty pre funkciu printf()"
+
+msgid "E767: Too many arguments to printf()"
+msgstr "E767: Príli¹ mnoho argumentov pre funkciu printf()"
+
+msgid "W10: Warning: Changing a readonly file"
+msgstr "W10: Varovanie: mením súbor iba pre èítanie"
+
+msgid "Type number or click with mouse (<Enter> cancels): "
+msgstr "Zadajte èíslo ale kliknite my¹ou (<Enter> zru¹í): "
+
+msgid "Choice number (<Enter> cancels): "
+msgstr "Zvoµte èíslo (<Enter> zru¹í): "
+
+msgid "1 more line"
+msgstr "1 nový riadok"
+
+msgid "1 line less"
+msgstr "1 vymazaný riadok"
+
+#, c-format
+msgid "%ld more lines"
+msgstr "%ld nových riadkov"
+
+#, c-format
+msgid "%ld fewer lines"
+msgstr "%ld vymazaných riadkov"
+
+msgid " (Interrupted)"
+msgstr " (Preru¹ené)"
+
+msgid "Beep!"
+msgstr "Piip!"
+
+msgid "Vim: preserving files...\n"
+msgstr "Vim: zachovávam súbory...\n"
+
+#. close all memfiles, without deleting
+msgid "Vim: Finished.\n"
+msgstr "Vim: ukonèený\n"
+
+#, c-format
+msgid "ERROR: "
+msgstr "CHYBA: "
+
+#, c-format
+msgid ""
+"\n"
+"[bytes] total alloc-freed %lu-%lu, in use %lu, peak use %lu\n"
+msgstr ""
+"\n"
+"[bajtov] celkom uvolnené-alokované %lu-%lu, vyu¾ité %lu, maximálne vyu¾itie %lu\n"
+
+#, c-format
+msgid ""
+"[calls] total re/malloc()'s %lu, total free()'s %lu\n"
+"\n"
+msgstr ""
+"[volanie] celkom re/malloc(): %lu, celkom free() %lu\n"
+"\n"
+
+msgid "E340: Line is becoming too long"
+msgstr "E340: Riadok sa stáva príli¹ dlhým"
+
+#, c-format
+msgid "E341: Internal error: lalloc(%ld, )"
+msgstr "E341: Vnútorná chyba: lalloc(%ld, )"
+
+#, c-format
+msgid "E342: Out of memory! (allocating %lu bytes)"
+msgstr "E342: Nedostatok pamäte! (alokujem %lu bajtov)"
+
+#, c-format
+msgid "Calling shell to execute: \"%s\""
+msgstr "Volám shell na spustenie: \"%s\""
+
+msgid "E545: Missing colon"
+msgstr "E545: Chýba dvojbodka"
+
+msgid "E546: Illegal mode"
+msgstr "E546: Neprípustný mód"
+
+msgid "E547: Illegal mouseshape"
+msgstr "E547: Chybný tvar my¹i"
+
+msgid "E548: digit expected"
+msgstr "E548: oèakávaná èíslica"
+
+msgid "E549: Illegal percentage"
+msgstr "E549: Neprípustné percento"
+
+msgid "Enter encryption key: "
+msgstr "Zadajte ¹ifrovací kµúè: "
+
+msgid "Enter same key again: "
+msgstr "Vlo¾te ten istý kµúè znova: "
+
+msgid "Keys don't match!"
+msgstr "Kµúèe sa nezhodujú!"
+
+#, c-format
+msgid ""
+"E343: Invalid path: '**[number]' must be at the end of the path or be "
+"followed by '%s'."
+msgstr ""
+"E343: Chybná cesta: '**[èíslo] musí by» buï na konci cesty, alebo musí by» "
+"nasledované '%s. Viï :help path."
+
+#, c-format
+msgid "E344: Can't find directory \"%s\" in cdpath"
+msgstr "E344: Adresár \"%s\" sa nedá nájs» v cdpath"
+
+#, c-format
+msgid "E345: Can't find file \"%s\" in path"
+msgstr "E345: Súbor \"%s\" sa nepodarilo nájs»"
+
+#, c-format
+msgid "E346: No more directory \"%s\" found in cdpath"
+msgstr "E346: ®iadny ïal¹í adresár \"%s\" nebol v cdpath nájdený"
+
+#, c-format
+msgid "E347: No more file \"%s\" found in path"
+msgstr "E347: ®iadny ïal¹í súbor \"%s\" nebol v ceste nájdený"
+
+#. Get here when the server can't be found.
+msgid "Cannot connect to Netbeans #2"
+msgstr "Nedá sa pripoji» na Netbeans #2"
+
+msgid "Cannot connect to Netbeans"
+msgstr "Nedá sa pripoji» na Netbeans"
+
+#, c-format
+msgid "E668: Wrong access mode for NetBeans connection info file: \"%s\""
+msgstr "E668: Zlé prístupové práva pre súbor s informáciami pre NetBeans spojenie: \"%s\""
+
+msgid "read from Netbeans socket"
+msgstr "èítanie z Netbeans soketu"
+
+msgid "E658: NetBeans connection lost for buffer %ld"
+msgstr "E658: Stratené NetBeans spojenie pre buffer %ld"
+
+msgid "E505: "
+msgstr "E505: "
+
+msgid "Warning: terminal cannot highlight"
+msgstr "Varovanie: terminál nepodporuje zvýrazòovanie"
+
+msgid "E348: No string under cursor"
+msgstr "E348: Pod kurzorom nie je ¾iadny re»azec"
+
+msgid "E349: No identifier under cursor"
+msgstr "E349: Pod kurzorom nie je ¾iadny identifikátor"
+
+msgid "E352: Cannot erase folds with current 'foldmethod'"
+msgstr "E352: Pomocou 'foldmethod' sa nedá vymaza» vnorenie"
+
+msgid "E664: changelist is empty"
+msgstr "E664: zoznam zmien je prázdny"
+
+msgid "E662: At start of changelist"
+msgstr "E662: Na zaèiatku zoznamu zmien"
+
+msgid "E663: At end of changelist"
+msgstr "E663: Na konci zoznamu zmien"
+
+msgid "Type :quit<Enter> to exit Vim"
+msgstr "Zadajte :quit<Enter> pre ukonèenie programu Vim"
+
+#, c-format
+msgid "1 line %sed 1 time"
+msgstr "poèet riadkov upravených naraz pomocou %s: 1"
+
+#, c-format
+msgid "1 line %sed %d times"
+msgstr "1 riadok upravený pomocou %s %d krát"
+
+#, c-format
+msgid "%ld lines %sed 1 time"
+msgstr "%ld riadkov upravených naraz pomocou %s"
+
+#, c-format
+msgid "%ld lines %sed %d times"
+msgstr "%ld riadkov upravených pomocou %s %d krát"
+
+#, c-format
+msgid "%ld lines to indent... "
+msgstr "%ld riadkov pre odsadenie..."
+
+msgid "1 line indented "
+msgstr "1 riadok odsadený "
+
+#, c-format
+msgid "%ld lines indented "
+msgstr "%ld riadkov odsadených "
+
+msgid "E748: No previously used register"
+msgstr "E748: ®iadny predtým pou¾ívaný register"
+
+#. must display the prompt
+msgid "cannot yank; delete anyway"
+msgstr "nedá sa kopírova»; napriek tomu vymazané"
+
+msgid "1 line changed"
+msgstr "1 riadok zmenený"
+
+#, c-format
+msgid "%ld lines changed"
+msgstr "%ld zmenených riadkov"
+
+#, c-format
+msgid "freeing %ld lines"
+msgstr "uvolòujem %ld riadkov"
+
+msgid "block of 1 line yanked"
+msgstr "skopírovaný blok 1 riadku"
+
+msgid "1 line yanked"
+msgstr "1 riadok skopírovaný"
+
+msgid "block of %ld lines yanked"
+msgstr "skopírovaný blok %ld riadkov"
+
+#, c-format
+msgid "%ld lines yanked"
+msgstr "%ld skopírovaných riadkov"
+
+#, c-format
+msgid "E353: Nothing in register %s"
+msgstr "E353: Register %s je prázdny"
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Registers ---"
+msgstr ""
+"\n"
+"--- Registre ---"
+
+msgid "Illegal register name"
+msgstr "Neprípustný názov registra"
+
+#, c-format
+msgid ""
+"\n"
+"# Registers:\n"
+msgstr ""
+"\n"
+"# Registre:\n"
+
+msgid "E574: Unknown register type %d"
+msgstr "E574: Neznámy typ registra %d"
+
+#, c-format
+msgid "%ld Cols; "
+msgstr "%ld Ståpcov; "
+
+#, c-format
+msgid "Selected %s%ld of %ld Lines; %ld of %ld Words; %ld of %ld Bytes"
+msgstr "Vybraných %s%ld z %ld Riadkov; %ld zo %ld Slov; %ld z %ld Bajtov"
+
+msgid ""
+"Selected %s%ld of %ld Lines; %ld of %ld Words; %ld of %ld Chars; %ld of %ld "
+"Bytes"
+msgstr "Vybraných %s%ld z %ld Riadkov; %ld zo %ld Slov; %ld z %ld Znakov; %ld z %ld Bajtov"
+
+#, c-format
+msgid "Col %s of %s; Line %ld of %ld; Word %ld of %ld; Byte %ld of %ld"
+msgstr "Ståpec %s z %s; Riadok %ld z %ld; Slovo %ld z %ld; Bajt %ld z %ld"
+
+#, c-format
+msgid ""
+"Col %s of %s; Line %ld of %ld; Word %ld of %ld; Char %ld of %ld; Byte %ld of "
+"%ld"
+msgstr "Ståpec %s z %s; Riadok %ld z %ld; Slovo %ld z %ld; Znak %ld z %ld; Bajt %ld z %ld"
+
+#, c-format
+msgid "(+%ld for BOM)"
+msgstr "(+%ld pre BOM)"
+
+msgid "%<%f%h%m%=Page %N"
+msgstr "%<%f%h%m%=Strana %N"
+
+msgid "Thanks for flying Vim"
+msgstr "Ïakujeme za pou¾itie Vim"
+
+msgid "E518: Unknown option"
+msgstr "E518: Neznáma voµba"
+
+msgid "E519: Option not supported"
+msgstr "E519: Voµba nie je podporovaná"
+
+msgid "E520: Not allowed in a modeline"
+msgstr "E520: Nie je v modeline povolené"
+
+msgid "E521: Number required after ="
+msgstr "E521: Po = je vy¾adované èíslo"
+
+msgid "E522: Not found in termcap"
+msgstr "E522: Nenájdený v termcape"
+
+#, c-format
+msgid "E539: Illegal character <%s>"
+msgstr "E539: Neprípustný znak <%s>"
+
+msgid "E529: Cannot set 'term' to empty string"
+msgstr "E529: Voµba 'term' nemô¾e by» prázdna"
+
+msgid "E530: Cannot change term in GUI"
+msgstr "E530: V grafickom móde (GUI) sa nedá meni» typ terminálu"
+
+msgid "E531: Use \":gui\" to start the GUI"
+msgstr "E531: Pou¾ite \"gui\" pre spustenie GUI"
+
+msgid "E589: 'backupext' and 'patchmode' are equal"
+msgstr "E589: voµby 'backupext' a 'patchmode' majú rovnakú hodnotu"
+
+msgid "E617: Cannot be changed in the GTK+ 2 GUI"
+msgstr "E617: Nedá sa zmeni» v grafickom rozhraní GTK+ 2"
+
+msgid "E524: Missing colon"
+msgstr "E524: Chýba dvojbodka"
+
+msgid "E525: Zero length string"
+msgstr "E525: Re»azec s nulovou då¾kou"
+
+#, c-format
+msgid "E526: Missing number after <%s>"
+msgstr "E526: Po <%s> chýba èíslo"
+
+msgid "E527: Missing comma"
+msgstr "E527: Chýba èiarka"
+
+msgid "E528: Must specify a ' value"
+msgstr "E528: Je nutné zada» hodnotu '"
+
+msgid "E595: contains unprintable or wide character"
+msgstr "E595: obsahuje netlaèiteµné znaky"
+
+msgid "E596: Invalid font(s)"
+msgstr "E596: Chybné písma"
+
+msgid "E597: can't select fontset"
+msgstr "E597: nedá sa vybra» sada písiem"
+
+msgid "E598: Invalid fontset"
+msgstr "E598: Chybná sada písiem"
+
+msgid "E533: can't select wide font"
+msgstr "E533: nedá sa vybra» ¹iroký font"
+
+msgid "E534: Invalid wide font"
+msgstr "E534: Chybné ¹iroké písmo"
+
+#, c-format
+msgid "E535: Illegal character after <%c>"
+msgstr "E535: Neprípustný znak po <%c>"
+
+msgid "E536: comma required"
+msgstr "E536: je nutná èiarka"
+
+#, c-format
+msgid "E537: 'commentstring' must be empty or contain %s"
+msgstr "E537: 'commentstring' (komentár) musí by» prázdny alebo musí obsahova» %s"
+
+msgid "E538: No mouse support"
+msgstr "E538: Bez podpory my¹i"
+
+msgid "E540: Unclosed expression sequence"
+msgstr "E540: Neuzatvorené zoskupenie výrazov"
+
+msgid "E541: too many items"
+msgstr "E541: príli¹ mnoho polo¾iek"
+
+msgid "E542: unbalanced groups"
+msgstr "E542: nevyvá¾ené skupiny"
+
+msgid "E590: A preview window already exists"
+msgstr "E590: Okno náhµadu u¾ existuje"
+
+msgid "W17: Arabic requires UTF-8, do ':set encoding=utf-8'"
+msgstr "W17: Mód Arabic vy¾aduje kódovanie UTF-8, nastavte to príkazom ':set encoding=utf-8'"
+
+#, c-format
+msgid "E593: Need at least %d lines"
+msgstr "E593: Minimálny potrebný poèet riadkov je %d"
+
+#, c-format
+msgid "E594: Need at least %d columns"
+msgstr "E594: Minimálne potrebný poèet ståpcov je %d"
+
+#, c-format
+msgid "E355: Unknown option: %s"
+msgstr "E355: Neznáma voµba: %s"
+
+msgid ""
+"\n"
+"--- Terminal codes ---"
+msgstr ""
+"\n"
+"--- Kódy terminálu ---"
+
+msgid ""
+"\n"
+"--- Global option values ---"
+msgstr ""
+"\n"
+"--- Nastavenie globálnych volieb ---"
+
+msgid ""
+"\n"
+"--- Local option values ---"
+msgstr ""
+"\n"
+"--- Nastavenie lokálnych volieb ---"
+
+msgid ""
+"\n"
+"--- Options ---"
+msgstr ""
+"\n"
+"--- Mo¾nosti ---"
+
+msgid "E356: get_varp ERROR"
+msgstr "E356: get_varp CHYBA"
+
+#, c-format
+msgid "E357: 'langmap': Matching character missing for %s"
+msgstr "E357: 'langmap': pre %s chýba vyhovujúci znak"
+
+#, c-format
+msgid "E358: 'langmap': Extra characters after semicolon: %s"
+msgstr "E358: 'langmap': nadbytoèné znaky po bodkoèiarke: %s"
+
+msgid "cannot open "
+msgstr "nedá sa otvori» "
+
+msgid "VIM: Can't open window!\n"
+msgstr "VIM: Nedá sa otvori» okno!\n"
+
+msgid "Need Amigados version 2.04 or later\n"
+msgstr "Je potrebná Amigados verzia 2.04 alebo nov¹ia\n"
+
+#, c-format
+msgid "Need %s version %ld\n"
+msgstr "Potrebná %s verzia %ld\n"
+
+msgid "Cannot open NIL:\n"
+msgstr "Nedá sa otvori» NIL:\n"
+
+msgid "Cannot create "
+msgstr "Nedá sa vytvori» "
+
+#, c-format
+msgid "Vim exiting with %d\n"
+msgstr "Vim ukonèený s %d\n"
+
+msgid "cannot change console mode ?!\n"
+msgstr "nemô¾em zmeni» konzolový mód ?!\n"
+
+msgid "mch_get_shellsize: not a console??\n"
+msgstr "mch_get_shellsize: nie je konzolou??\n"
+
+#. if Vim opened a window: Executing a shell may cause crashes
+msgid "E360: Cannot execute shell with -f option"
+msgstr "E360: Nedá sa spusti» shell s -f voµbou"
+
+msgid "Cannot execute "
+msgstr "Nedá sa spusti» "
+
+msgid "shell "
+msgstr "shell "
+
+msgid " returned\n"
+msgstr " vrátené\n"
+
+msgid "ANCHOR_BUF_SIZE too small."
+msgstr "ANCHOR_BUF_SIZE príli¹ malá."
+
+msgid "I/O ERROR"
+msgstr "I/O CHYBA"
+
+msgid "...(truncated)"
+msgstr "...(skrátené)"
+
+msgid "'columns' is not 80, cannot execute external commands"
+msgstr "'ståpce' nie je 80, nemô¾em spusti» externý príkaz"
+
+msgid "E237: Printer selection failed"
+msgstr "E237: Zlyhal výber tlaèiarne"
+
+#, c-format
+msgid "to %s on %s"
+msgstr "%s na %s"
+
+#, c-format
+msgid "E613: Unknown printer font: %s"
+msgstr "E613: Neznámy font tlaèiarne: %s"
+
+#, c-format
+msgid "E238: Print error: %s"
+msgstr "E238: Chyba tlaèe: %s"
+
+#, c-format
+msgid "Printing '%s'"
+msgstr "Tlaèím '%s'"
+
+#, c-format
+msgid "E244: Illegal charset name \"%s\" in font name \"%s\""
+msgstr "E244: Chybný názov znakovej sady \"%s\" v názve písma \"%s\""
+
+#, c-format
+msgid "E245: Illegal char '%c' in font name \"%s\""
+msgstr "E245: Chybný znak '%c' v názve písma \"%s\""
+
+msgid "Vim: Double signal, exiting\n"
+msgstr "Vim: dvojitý signál, konèím\n"
+
+#, c-format
+msgid "Vim: Caught deadly signal %s\n"
+msgstr "Vim: Zachytený smrtiaci signál %s\n"
+
+#, c-format
+msgid "Vim: Caught deadly signal\n"
+msgstr "Vim: Zachytený smrtiaci signál\n"
+
+#, c-format
+msgid "Opening the X display took %ld msec"
+msgstr "Otvorenie X displej zabralo %ld msec"
+
+#. KDE sometimes produces X error that we want to ignore
+msgid ""
+"\n"
+"Vim: Got X error but we continue...\n"
+msgstr ""
+"\n"
+"Vim: Chyba X ale pokraèujem ...\n"
+
+msgid ""
+"\n"
+"Vim: Got X error\n"
+msgstr ""
+"\n"
+"Vim: Chyba X\n"
+
+msgid "Testing the X display failed"
+msgstr "Testovanie X displeja zlyhalo"
+
+msgid "Opening the X display timed out"
+msgstr "Uplynul èas otvorenia X displeja"
+
+msgid ""
+"\n"
+"Cannot execute shell "
+msgstr ""
+"\n"
+"Nedá sa spusti» shell "
+
+msgid ""
+"\n"
+"Cannot execute shell sh\n"
+msgstr ""
+"\n"
+"Nedá sa spusti» sh shell\n"
+
+msgid ""
+"\n"
+"shell returned "
+msgstr ""
+"\n"
+" návratová hodnota shellu "
+
+msgid ""
+"\n"
+"Cannot create pipes\n"
+msgstr ""
+"\n"
+"Nedjú sa vytvori» rúry\n"
+
+msgid ""
+"\n"
+"Cannot fork\n"
+msgstr ""
+"\n"
+"Vyvolanie fork zlyhalo\n"
+
+msgid ""
+"\n"
+"Command terminated\n"
+msgstr ""
+"\n"
+"Príkaz ukonèený\n"
+
+msgid "XSMP lost ICE connection"
+msgstr "XSMP stratilo ICE spojenie"
+
+#, c-format
+msgid "dlerror = \"%s\""
+msgstr "dlerror = \"%s\""
+
+msgid "Opening the X display failed"
+msgstr "Otvorenie X displeja zlyhalo"
+
+msgid "XSMP handling save-yourself request"
+msgstr "XSMP spracuváva po¾iadavku na samoulo¾enie"
+
+msgid "XSMP opening connection"
+msgstr "XSMP otvára spojenie"
+
+msgid "XSMP ICE connection watch failed"
+msgstr "XSMP kontrola spojenia ICE zlyhala"
+
+#, c-format
+msgid "XSMP SmcOpenConnection failed: %s"
+msgstr "XSMP SmcOpenConnection zlyhalo: %s"
+
+msgid "At line"
+msgstr "Na riadku"
+
+msgid "Could not load vim32.dll!"
+msgstr "Nemô¾em nahra» vim32.dll!"
+
+msgid "VIM Error"
+msgstr "VIM Chyba"
+
+msgid "Could not fix up function pointers to the DLL!"
+msgstr "Nemô¾em opravi» odkazy funkcií na DLL!"
+
+#, c-format
+msgid "shell returned %d"
+msgstr "návratová hodnota shellu %d"
+
+#, c-format
+msgid "Vim: Caught %s event\n"
+msgstr "Vim: Zachytená udalos» %s\n"
+
+msgid "close"
+msgstr "zavrie»"
+
+msgid "logoff"
+msgstr "odhlási»"
+
+msgid "shutdown"
+msgstr "vypnú»"
+
+msgid "E371: Command not found"
+msgstr "E371: Príkaz nenájdený"
+
+msgid ""
+"VIMRUN.EXE not found in your $PATH.\n"
+"External commands will not pause after completion.\n"
+"See :help win32-vimrun for more information."
+msgstr ""
+"VIMRUN.EXE nenájdený v $PATH.\n"
+"Po dokonèení externých príkazov nebude výstup pozastavený.\n"
+"Pozrite :help win32-vimrun pre viac informácií."
+
+msgid "Vim Warning"
+msgstr "Vim Varovanie"
+
+#, c-format
+msgid "E372: Too many %%%c in format string"
+msgstr "E372: Príli¹ mnoho %%%c vo formátovacom re»azci"
+
+#, c-format
+msgid "E373: Unexpected %%%c in format string"
+msgstr "E373: Neoèakávaný výskyt %%%c vo formátovacom re»azci"
+
+msgid "E374: Missing ] in format string"
+msgstr "E374: Vo formátovacom re»azci chýba ]"
+
+#, c-format
+msgid "E375: Unsupported %%%c in format string"
+msgstr ""
+"E375: Nepodporovaná formátová ¹pecifikácia %%%c vo formátovacom re»azci"
+
+#, c-format
+msgid "E376: Invalid %%%c in format string prefix"
+msgstr "E376: Neprístupné %%%c v prefixe formátovacieho re»azca"
+
+#, c-format
+msgid "E377: Invalid %%%c in format string"
+msgstr "E377: Neprístupné %%%c vo formátovacom re»azci"
+
+msgid "E378: 'errorformat' contains no pattern"
+msgstr "E378: 'errorformat' neobsahuje ¾iadny vzor"
+
+msgid "E379: Missing or empty directory name"
+msgstr "E379: Chýbajúci alebo prázdny názov adresára"
+
+msgid "E553: No more items"
+msgstr "E553: ®iadne ïal¹ie polo¾ky"
+
+#, c-format
+msgid "(%d of %d)%s%s: "
+msgstr "(%d z %d)%s%s: "
+
+msgid " (line deleted)"
+msgstr " (riadok vymazaný)"
+
+msgid "E380: At bottom of quickfix stack"
+msgstr "E380: Koniec quickfix zoznamu"
+
+msgid "E381: At top of quickfix stack"
+msgstr "E381: Zaèiatok quickfix zoznamu"
+
+#, c-format
+msgid "error list %d of %d; %d errors"
+msgstr "zoznam chýb %d z %d; %d chýb"
+
+msgid "E382: Cannot write, 'buftype' option is set"
+msgstr "E382: Nedá sa ulo¾i», je nastavená voµba 'buftype'"
+
+msgid "E683: File name missing or invalid pattern"
+msgstr "E683: Chýba meno súboru alebo chybný vzor"
+
+msgid "Cannot open file \"%s\""
+msgstr "Nedá sa otvori» súbor \"%s\""
+
+msgid "E681: Buffer is not loaded"
+msgstr "E681: Buffer nie je naèítaný"
+
+#, c-format
+msgid "E369: invalid item in %s%%[]"
+msgstr "E369: chybná polo¾ka v %s%%[]"
+
+msgid "E339: Pattern too long"
+msgstr "E339: Vzor je príli¹ dlhý"
+
+msgid "E50: Too many \\z("
+msgstr "E50: Príli¹ mnoho \\z("
+
+#, c-format
+msgid "E51: Too many %s("
+msgstr "E51: Príli¹ mnoho %s("
+
+msgid "E52: Unmatched \\z("
+msgstr "E52: Nespárované \\z("
+
+#, c-format
+msgid "E53: Unmatched %s%%("
+msgstr "E53: Nespárované %s%%("
+
+#, c-format
+msgid "E54: Unmatched %s("
+msgstr "E54: Nespárované %s("
+
+#, c-format
+msgid "E55: Unmatched %s)"
+msgstr "E55: Nespárované %s)"
+
+#, c-format
+msgid "E59: invalid character after %s@"
+msgstr "E59: Neprípustný znak po %s@"
+
+#, c-format
+msgid "E60: Too many complex %s{...}s"
+msgstr "E60: Príli¹ komplexné %s{...}"
+
+#, c-format
+msgid "E61: Nested %s*"
+msgstr "E61: Vnorený %s*"
+
+#, c-format
+msgid "E62: Nested %s%c"
+msgstr "E62: Vnorený %s%c"
+
+msgid "E63: invalid use of \\_"
+msgstr "E63: Chybne pou¾ité \\_"
+
+#, c-format
+msgid "E64: %s%c follows nothing"
+msgstr "E64: %s%c niè nenasleduje"
+
+msgid "E65: Illegal back reference"
+msgstr "E65: Chybná spätná referencia"
+
+msgid "E66: \\z( not allowed here"
+msgstr "E66: \\z( tu nie je povolené"
+
+msgid "E67: \\z1 - \\z9 not allowed here"
+msgstr "E67: \\z1 a spol. tu nie je povolené"
+
+msgid "E68: Invalid character after \\z"
+msgstr "E68: Neprípustný znak po \\z"
+
+#, c-format
+msgid "E69: Missing ] after %s%%["
+msgstr "E69: Chýbajúca ] po %s%%["
+
+#, c-format
+msgid "E70: Empty %s%%[]"
+msgstr "E70: Prázdny %s%%[]"
+
+#, c-format
+msgid "E678: Invalid character after %s%%[dxouU]"
+msgstr "E678: Neprípustný znak po %s%%[dxouU]"
+
+#, c-format
+msgid "E71: Invalid character after %s%%"
+msgstr "E71: Neprípustný znak po %s%%"
+
+#, c-format
+msgid "E769: Missing ] after %s["
+msgstr "E769: Chýbajúca ] po %s["
+
+#, c-format
+msgid "E554: Syntax error in %s{...}"
+msgstr "E554: Chyba syntaxe v %s{...}"
+
+msgid "External submatches:\n"
+msgstr "Vnútorné podradené zhody:\n"
+
+msgid " VREPLACE"
+msgstr " NAHRADI« VERTIKÁLNE"
+
+msgid " REPLACE"
+msgstr " NAHRADI«"
+
+msgid " REVERSE"
+msgstr " OBRÁTI«"
+
+msgid " INSERT"
+msgstr " VLO®I«"
+
+msgid " (insert)"
+msgstr " (vlo¾i»)"
+
+msgid " (replace)"
+msgstr " (nahradi»)"
+
+msgid " (vreplace)"
+msgstr " (nahradi» vertikálne)"
+
+msgid " Hebrew"
+msgstr " Hebrejský"
+
+msgid " Arabic"
+msgstr " Arabský"
+
+msgid " (lang)"
+msgstr " (jazyk)"
+
+msgid " (paste)"
+msgstr " (vlo¾i»)"
+
+msgid " VISUAL"
+msgstr " VIZUÁLNE"
+
+msgid " VISUAL LINE"
+msgstr " VIZUÁLNY RIADOK"
+
+msgid " VISUAL BLOCK"
+msgstr " VIZUÁLNY BLOK"
+
+msgid " SELECT"
+msgstr " ZHODY"
+
+msgid " SELECT LINE"
+msgstr " OZNAÈ RIADOK"
+
+msgid " SELECT BLOCK"
+msgstr " OZNAÈ BLOK"
+
+msgid "recording"
+msgstr "nahrávam"
+
+#, c-format
+msgid "E383: Invalid search string: %s"
+msgstr "E383: Neprípustný hµadaný re»azec: %s"
+
+#, c-format
+msgid "E384: search hit TOP without match for: %s"
+msgstr "E384: hµadanie dosiahlo zaèiatok bez nájdenia %s"
+
+#, c-format
+msgid "E385: search hit BOTTOM without match for: %s"
+msgstr "E385: hµadanie dosiahlo koniec bez nájdenia %s"
+
+msgid "E386: Expected '?' or '/' after ';'"
+msgstr "E386: Po ';' oèakávam '?' alebo '/'"
+
+msgid " (includes previously listed match)"
+msgstr " (vrátane u¾ vypísaných zhôd)"
+
+#. cursor at status line
+msgid "--- Included files "
+msgstr "--- Vlo¾ené súbory"
+
+msgid "not found "
+msgstr "nenájdené "
+
+msgid "in path ---\n"
+msgstr "v ceste ---\n"
+
+msgid " (Already listed)"
+msgstr " (U¾ vypísané)"
+
+msgid " NOT FOUND"
+msgstr " NENÁJDENÉ"
+
+#, c-format
+msgid "Scanning included file: %s"
+msgstr "Prehµadávam vlo¾ené súbory: %s"
+
+msgid "E387: Match is on current line"
+msgstr "E387: Zhoda je na aktuálnom riadku"
+
+msgid "All included files were found"
+msgstr "V¹etky vlo¾ené súbory boli nájdené"
+
+msgid "No included files"
+msgstr "®iadne vlo¾ené súbory"
+
+msgid "E388: Couldn't find definition"
+msgstr "E388: Nedá sa nájs» definícia"
+
+msgid "E389: Couldn't find pattern"
+msgstr "E389: Nedá sa nájs» vzor"
+
+msgid "E759: Format error in spell file"
+msgstr "E759: Chyba formátovania v spell súbore (kontrola pravopisu)"
+
+msgid "E758: Truncated spell file"
+msgstr "E758: Odseknutý spell súbor (kontrola pravopisu)"
+
+#, c-format
+msgid "Trailing text in %s line %d: %s"
+msgstr "Prebytoèný text v %s na riadku %d: %s"
+
+#, c-format
+msgid "Affix name too long in %s line %d: %s"
+msgstr "Prípona príli¶ dlhá v %s riadok %d: %s"
+
+msgid "E761: Format error in affix file FOL, LOW or UPP"
+msgstr "E761: Chyba formátovania v súbore prípon FOL, LOW alebo UPP (NASLEDUJE, MALÉ alebo VE¥KÉ)"
+
+msgid "E762: Character in FOL, LOW or UPP is out of range"
+msgstr "E762: Znak v FOL, LOW alebo UPP (NASLEDUJE, MALÉ alebo VE¥KÉ) je mimo rozsah"
+
+msgid "Compressing word tree..."
+msgstr "Robím kompresiu stromu slov..."
+
+msgid "E756: Spell checking is not enabled"
+msgstr "E756: Kontrola pravopisu nie je zapnutá"
+
+#, c-format
+msgid "Warning: Cannot find word list \"%s.%s.spl\" or \"%s.ascii.spl\""
+msgstr "Varovanie: Nemo¾no nájs» zoznam slov \"%s.%s.spl\" alebo \"%s.ascii.spl\""
+
+#, c-format
+msgid "Reading spell file \"%s\""
+msgstr "Èítam slovníkový súbor \"%s\""
+
+msgid "E757: This does not look like a spell file"
+msgstr "E757: Toto sa nezdá by» slovníkovým súborom"
+
+msgid "E771: Old spell file, needs to be updated"
+msgstr "E771: Starý slovníkový súbor, potrebuje by» zaktualizovaný"
+
+msgid "E772: Spell file is for newer version of Vim"
+msgstr "E772: Slovníkový súbor je pre nov¹iu verziu Vim"
+
+msgid "E770: Unsupported section in spell file"
+msgstr "E770: Nepodporovaná sekcia v slovníkovom súbore"
+
+#, c-format
+msgid "Warning: region %s not supported"
+msgstr "Varovanie: región %s nie je podporovaný"
+
+#, c-format
+msgid "Reading affix file %s..."
+msgstr "Naèítavam súbor s príponami %s..."
+
+#, c-format
+msgid "Conversion failure for word in %s line %d: %s"
+msgstr "Konverzia slova zlyhala v %s riadok %d: %s"
+
+#, c-format
+msgid "Conversion in %s not supported: from %s to %s"
+msgstr "Konverzia v %s nie je podporovaná: z %s do %s"
+
+#, c-format
+msgid "Conversion in %s not supported"
+msgstr "Konverzia v %s nie je podporovaná"
+
+#, c-format
+msgid "Invalid value for FLAG in %s line %d: %s"
+msgstr "Neplatná hodnota pre príznak (FLAG) v %s riadok %d: %s"
+
+#, c-format
+msgid "FLAG after using flags in %s line %d: %s"
+msgstr "Príznak (FLAG) po pou¾ití príznakov v %s riadok %d: %s"
+
+#, c-format
+msgid "Character used for SLASH must be ASCII; in %s line %d: %s"
+msgstr "Znak pou¾itý pre SLASH musí by» ASCII; v %s riadok %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDMAX value in %s line %d: %s"
+msgstr "Zlá hodnota COMPOUNDMAX v %s riadok %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDMIN value in %s line %d: %s"
+msgstr "Zlá hodnota COMPOUNDMIN v %s riadok %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDSYLMAX value in %s line %d: %s"
+msgstr "Zlá hodnota COMPOUNDSYLMAX v %s riadok %d: %s"
+
+#, c-format
+msgid "Different combining flag in continued affix block in %s line %d: %s"
+msgstr "Rozdielna kombinácia príznakov v nasledujúcom bloku prípon v %s riadok %d: %s"
+
+#, c-format
+msgid "Duplicate affix in %s line %d: %s"
+msgstr "Duplicitná prípona v %s riadok %d: %s"
+
+#, c-format
+msgid ""
+"Affix also used for BAD/RAR/KEP/NEEDAFFIX/NEEDCOMPOUND in %s line %d: %s"
+msgstr ""
+"Prípona pou¾itá aj pre BAD/RAR/KEP/NEEDAFFIX/NEEDCOMPOUND in %s line %d: %s"
+
+#, c-format
+msgid "Expected Y or N in %s line %d: %s"
+msgstr "Oèakávane Y alebo N v %s riadok %d: %s"
+
+#, c-format
+msgid "Broken condition in %s line %d: %s"
+msgstr "Naru¹ená podmienka v %s riadok %d: %s"
+
+#, c-format
+msgid "Expected REP count in %s line %d"
+msgstr "Oèakávam poèet REP v %s riadok %d"
+
+#, c-format
+msgid "Expected MAP count in %s line %d"
+msgstr "Oèakávam poèet MAP v %s riadok %d"
+
+#, c-format
+msgid "Duplicate character in MAP in %s line %d"
+msgstr "Opakovaný znak v MAP v %s riadok %d"
+
+#, c-format
+msgid "Unrecognized or duplicate item in %s line %d: %s"
+msgstr "Nerozpoznaná alebo opakujúca sa polo¾ka v %s riadok %d: %s"
+
+#, c-format
+msgid "Missing FOL/LOW/UPP line in %s"
+msgstr "Chýbajúci riadok FOL/LOW/UPP v %s"
+
+msgid "COMPOUNDSYLMAX used without SYLLABLE"
+msgstr "COMPOUNDSYLMAX pou¾itý bez SYLLABLE"
+
+msgid "Too many postponed prefixes"
+msgstr "Príli¹ mnoho odlo¾ených prípon"
+
+msgid "Too many compound flags"
+msgstr "Príli¹ mnoho upravovacích príznakov"
+
+msgid "Too many postponed prefixes and/or compound flags"
+msgstr "Príli¹ mnoho odlo¾ených prípon a/alebo upravovacích príznakov"
+
+#, c-format
+msgid "Missing SOFO%s line in %s"
+msgstr "Chýba SOFO%s riadok v %s"
+
+#, c-format
+msgid "Both SAL and SOFO lines in %s"
+msgstr "SAL a SOFO riadky zároveò v %s"
+
+#, c-format
+msgid "Flag is not a number in %s line %d: %s"
+msgstr "Príznak nie je èíslo v %s na riadku %d: %s"
+
+#, c-format
+msgid "Illegal flag in %s line %d: %s"
+msgstr "Neprípustný príznak v %s riadok %d: %s"
+
+#, c-format
+msgid "%s value differs from what is used in another .aff file"
+msgstr "Hodnota %s sa odli¹uje od hodnoty pou¾itej v inom .aff súbore"
+
+#, c-format
+msgid "Reading dictionary file %s..."
+msgstr "Naèítavam slovník %s..."
+
+#, c-format
+msgid "E760: No word count in %s"
+msgstr "E760: Chýajúci poèet slov v %s"
+
+#, c-format
+msgid "line %6d, word %6d - %s"
+msgstr "riadok %6d, slovo %6d - %s"
+
+#, c-format
+msgid "Duplicate word in %s line %d: %s"
+msgstr "Opakujúce sa slovo v %s riadok %d: %s"
+
+#, c-format
+msgid "First duplicate word in %s line %d: %s"
+msgstr "Prvé duplicitné slovo v %s riadok %d: %s"
+
+#, c-format
+msgid "%d duplicate word(s) in %s"
+msgstr "%d duplicitné slovo(á) v %s"
+
+#, c-format
+msgid "Ignored %d word(s) with non-ASCII characters in %s"
+msgstr "Ignorovaných %d slov s nepísmennými znakmi v %s"
+
+#, c-format
+msgid "Reading word file %s..."
+msgstr "Naèítavam súbor so slovami %s..."
+
+#, c-format
+msgid "Duplicate /encoding= line ignored in %s line %d: %s"
+msgstr "Duplicitný riadok /encoding= v %s riadok %d ignorovaný: %s "
+
+#, c-format
+msgid "/encoding= line after word ignored in %s line %d: %s"
+msgstr "/encoding= riadok nasledujúci po slove v %s riadok %d ignorovaný: %s"
+
+#, c-format
+msgid "Duplicate /regions= line ignored in %s line %d: %s"
+msgstr "Duplicitný riadok /regions= v %s riadok %d ignorovaný: %s"
+
+#, c-format
+msgid "Too many regions in %s line %d: %s"
+msgstr "Príli¹ mnoho regiónov v %s riadok %d: %s"
+
+#, c-format
+msgid "/ line ignored in %s line %d: %s"
+msgstr "Riadok / v %s riadok %d ignorovaný: %s"
+
+#, c-format
+msgid "Invalid region nr in %s line %d: %s"
+msgstr "Pou¾íté chybné èíslo regiónu v %s riadok %d: %s"
+
+#, c-format
+msgid "Unrecognized flags in %s line %d: %s"
+msgstr "Nerozpoznaný príznak v %s riadok %d: %s"
+
+#, c-format
+msgid "Ignored %d words with non-ASCII characters"
+msgstr "Ignorovaných %d slov s nepísmennými znakmi"
+
+#, c-format
+msgid "Compressed %d of %d nodes; %d%% remaining"
+msgstr "Skomprimovaných %d z %d uzlov; %d%% zostáva"
+
+msgid "E751: Output file name must not have region name"
+msgstr "E751: Výstupné meno súboru nesmie ma» názov regiónu"
+
+msgid "E754: Only up to 8 regions supported"
+msgstr "E754: Podporovaných max. 8 regiónov"
+
+#, c-format
+msgid "E755: Invalid region in %s"
+msgstr "E755: Chybný región v %s"
+
+msgid "Warning: both compounding and NOBREAK specified"
+msgstr "Varovanie: ¹pecifikované spájanie a nezalamovanie"
+
+#, c-format
+msgid "Writing spell file %s..."
+msgstr "Ukládám slovníkový súbor %s..."
+
+msgid "Done!"
+msgstr "Hotovo!"
+
+#, c-format
+msgid "Estimated runtime memory use: %d bytes"
+msgstr "Veµkos» pou¾ívanej pamäte: %d bajtov"
+
+#, c-format
+msgid "E765: 'spellfile' does not have %ld entries"
+msgstr "E765: 'spellfile' nemá %ld polo¾iek"
+
+msgid "E763: Word characters differ between spell files"
+msgstr "E763: Znaky slov sa odli¹ujú medzi slovníkovými súbormi"
+
+msgid "Sorry, no suggestions"
+msgstr "Prepáète, ¾iadne návrhy"
+
+#, c-format
+msgid "Sorry, only %ld suggestions"
+msgstr "Prepáète, iba %ld návrhov"
+
+#. avoid more prompt
+#, c-format
+msgid "Change \"%.*s\" to:"
+msgstr "Zmeni» \"%.*s\" na:"
+
+#, c-format
+msgid " < \"%.*s\""
+msgstr " < \"%.*s\""
+
+msgid "E752: No previous spell replacement"
+msgstr "E752: ®iadny predchádzajúce nahradenie podµa slovníka"
+
+#, c-format
+msgid "E753: Not found: %s"
+msgstr "E753: Nenájdené: %s"
+
+#. This should have been checked when generating the .spl
+#. * file.
+msgid "E783: duplicate char in MAP entry"
+msgstr "E783: duplicitný znak v MAP polo¾ke"
+
+#, c-format
+msgid "E390: Illegal argument: %s"
+msgstr "E390: Neprípustný argument: %s"
+
+#, c-format
+msgid "E391: No such syntax cluster: %s"
+msgstr "E391: Syntaktická zostava %s neexistuje"
+
+msgid "No Syntax items defined for this buffer"
+msgstr "Pre tento buffer nie sú definované ¾iadne polo¾ky syntaxe"
+
+msgid "syncing on C-style comments"
+msgstr "synchronizujem podµa komentárov jazyka C"
+
+msgid "no syncing"
+msgstr "¾iadne synchronizácie"
+
+msgid "syncing starts "
+msgstr "synchronizácia zaèína "
+
+msgid " lines before top line"
+msgstr " riadkov pred zaèiatkom"
+
+msgid ""
+"\n"
+"--- Syntax sync items ---"
+msgstr ""
+"\n"
+"--- Polo¾ky synchronizácie syntaxe ---"
+
+msgid ""
+"\n"
+"syncing on items"
+msgstr ""
+"\n"
+"synchronizujem polo¾ky"
+
+msgid ""
+"\n"
+"--- Syntax items ---"
+msgstr ""
+"\n"
+"--- Polo¾ky syntaxe ---"
+
+#, c-format
+msgid "E392: No such syntax cluster: %s"
+msgstr "E392: Syntaktická zostava %s neexistuje"
+
+msgid "minimal "
+msgstr "minimálne "
+
+msgid "maximal "
+msgstr "maximálne "
+
+msgid "; match "
+msgstr "; zhoda "
+
+msgid " line breaks"
+msgstr " zalomení riadkov"
+
+msgid "E395: contains argument not accepted here"
+msgstr "E395: obsahuje argumenty, ktoré tu nie sú povolené"
+
+msgid "E396: containedin argument not accepted here"
+msgstr "E396: obsahuje argumenty, ktoré tu nie sú povolené"
+
+msgid "E393: group[t]here not accepted here"
+msgstr "E393: group[t]here nesmie by» na tomto mieste"
+
+#, c-format
+msgid "E394: Didn't find region item for %s"
+msgstr "E394: Pre %s chýba polo¾ka regiónu"
+
+msgid "E397: Filename required"
+msgstr "E397: Vy¾adovaný názov súboru"
+
+#, c-format
+msgid "E789: Missing ']': %s"
+msgstr "E789: Chýba ']': %s"
+
+#, c-format
+msgid "E398: Missing '=': %s"
+msgstr "E398: Chýba '=': %s"
+
+#, c-format
+msgid "E399: Not enough arguments: syntax region %s"
+msgstr "E399: Príli¹ málo argumentov: oblas» syntaxe %s"
+
+msgid "E400: No cluster specified"
+msgstr "E400: Nebola zadaná ¾iadna zostava"
+
+#, c-format
+msgid "E401: Pattern delimiter not found: %s"
+msgstr "E401: Oddeµovaè vzoru %s nenájdený"
+
+#, c-format
+msgid "E402: Garbage after pattern: %s"
+msgstr "E402: Chyba za vzorom: %s"
+
+msgid "E403: syntax sync: line continuations pattern specified twice"
+msgstr "E403: synchronizácia syntaxe: vzor pokraèovania riadkov zadaný dvakrát"
+
+#, c-format
+msgid "E404: Illegal arguments: %s"
+msgstr "E404: Chybné argumenty: %s"
+
+#, c-format
+msgid "E405: Missing equal sign: %s"
+msgstr "E405: Chýba znamienko rovná sa: %s"
+
+#, c-format
+msgid "E406: Empty argument: %s"
+msgstr "E406: Prázdny argument: %s"
+
+#, c-format
+msgid "E407: %s not allowed here"
+msgstr "E407: %s tu nie je povolené"
+
+#, c-format
+msgid "E408: %s must be first in contains list"
+msgstr "E408: %s musí by» prvý v 'contains' zozname"
+
+#, c-format
+msgid "E409: Unknown group name: %s"
+msgstr "E409: Neznámy názov skupiny: %s"
+
+#, c-format
+msgid "E410: Invalid :syntax subcommand: %s"
+msgstr "E410: Chybný podradený príkaz :syntax : %s "
+
+msgid "E679: recursive loop loading syncolor.vim"
+msgstr "E679: rekurzívna sluèka pri naèítavaní syncolor.vim"
+
+#, c-format
+msgid "E411: highlight group not found: %s"
+msgstr "E411: skupina zvýraznenia %s nebola nájdená"
+
+#, c-format
+msgid "E412: Not enough arguments: \":highlight link %s\""
+msgstr "E412: Príli¹ málo argumentov: \":highlight link %s\""
+
+#, c-format
+msgid "E413: Too many arguments: \":highlight link %s\""
+msgstr "E413: Príli¹ mnoho argumentov: \":highlight link %s\""
+
+msgid "E414: group has settings, highlight link ignored"
+msgstr "E414: skupina je nastavená, odkaz na zvýrazòovaciu skupinu ignorovaný"
+
+#, c-format
+msgid "E415: unexpected equal sign: %s"
+msgstr "E415: neoèakávané znamienko rovná sa: %s"
+
+#, c-format
+msgid "E416: missing equal sign: %s"
+msgstr "E416: chýba znamienko rovná sa: %s"
+
+#, c-format
+msgid "E417: missing argument: %s"
+msgstr "E417: chýba argument: %s"
+
+#, c-format
+msgid "E418: Illegal value: %s"
+msgstr "E418: Neprípustná hodnota: %s"
+
+msgid "E419: FG color unknown"
+msgstr "E419: farba popredia nie je známa"
+
+msgid "E420: BG color unknown"
+msgstr "E420: farba pozadia nie je známa"
+
+#, c-format
+msgid "E421: Color name or number not recognized: %s"
+msgstr "E421: Názov alebo èíslo farby nebolo rozpoznané: %s"
+
+#, c-format
+msgid "E422: terminal code too long: %s"
+msgstr "E422: terminálový kód je príli¹ dlhý: %s"
+
+#, c-format
+msgid "E423: Illegal argument: %s"
+msgstr "E423: Neprípustný argument: %s"
+
+msgid "E424: Too many different highlighting attributes in use"
+msgstr "E424: Pou¾ívaných príli¹ veµa odli¹ných zvýrazòovacích vlastností"
+
+msgid "E669: Unprintable character in group name"
+msgstr "E669: Netlaèitelný znak v mene skupiny"
+
+msgid "W18: Invalid character in group name"
+msgstr "W18: Chybný znak v mene skupiny"
+
+msgid "E555: at bottom of tag stack"
+msgstr "E555: na konci zoznamu tagov"
+
+msgid "E556: at top of tag stack"
+msgstr "E556: na zaèiatku zoznamu tagov"
+
+msgid "E425: Cannot go before first matching tag"
+msgstr "E425: Nedá sa skoèi» pred prvý vyhovujúci tag"
+
+#, c-format
+msgid "E426: tag not found: %s"
+msgstr "E426: tag %s nenájdený"
+
+msgid " # pri kind tag"
+msgstr " # pri typ tag"
+
+msgid "file\n"
+msgstr "súbor\n"
+
+msgid "E427: There is only one matching tag"
+msgstr "E427: Vyhovuje iba jeden tag"
+
+msgid "E428: Cannot go beyond last matching tag"
+msgstr "E428: Za posledný vyhovujúci tag sa nedá preskoèi»"
+
+#, c-format
+msgid "File \"%s\" does not exist"
+msgstr "Súbor \"%s\" neexistuje"
+
+#. Give an indication of the number of matching tags
+#, c-format
+msgid "tag %d of %d%s"
+msgstr "tag %d z %d%s"
+
+msgid " or more"
+msgstr " alebo viac"
+
+msgid " Using tag with different case!"
+msgstr " Pou¾ívam tag s písmom inej veµkosti!"
+
+#, c-format
+msgid "E429: File \"%s\" does not exist"
+msgstr "E429: Súbor \"%s\" neexistuje"
+
+#. Highlight title
+msgid ""
+"\n"
+" # TO tag FROM line in file/text"
+msgstr ""
+"\n"
+" # CIE¥ tag ©TART riadok v súbore/texte"
+
+#, c-format
+msgid "Searching tags file %s"
+msgstr "Prehµadávam súbor tagov %s"
+
+#, c-format
+msgid "E430: Tag file path truncated for %s\n"
+msgstr "E430: Cesta k súboru tagov %s bola orezaná\n"
+
+#, c-format
+msgid "E431: Format error in tags file \"%s\""
+msgstr "E431: Chyba formátovania v súbore tagov \"%s\""
+
+#, c-format
+msgid "Before byte %ld"
+msgstr "Pred bajtom %ld"
+
+#, c-format
+msgid "E432: Tags file not sorted: %s"
+msgstr "E432: Obsah súboru tagov %s nie je zoradený"
+
+#. never opened any tags file
+msgid "E433: No tags file"
+msgstr "E433: ®iadny súbor tagov"
+
+msgid "E434: Can't find tag pattern"
+msgstr "E434: Nedá sa nájs» vzor tagov"
+
+msgid "E435: Couldn't find tag, just guessing!"
+msgstr "E435: Tag sa nedá nájs», iba hádam!"
+
+msgid "' not known. Available builtin terminals are:"
+msgstr "' nie je známy. Dostupné vstavané terminály:"
+
+msgid "defaulting to '"
+msgstr "nastavujem na '"
+
+msgid "E557: Cannot open termcap file"
+msgstr "E557: Nedá sa otvori» termcap súbor"
+
+msgid "E558: Terminal entry not found in terminfo"
+msgstr "E558: Terminfo neobsahuje polo¾ku pre tento terminál"
+
+msgid "E559: Terminal entry not found in termcap"
+msgstr "E559: Termcap neobsahuje polo¾ku pre tento terminál"
+
+#, c-format
+msgid "E436: No \"%s\" entry in termcap"
+msgstr "E436: Termcap neobsahuje polo¾ku \"%s\""
+
+msgid "E437: terminal capability \"cm\" required"
+msgstr "E437: Terminál musí ma» schopnos» \"cm\" (schopnos» pohybu kurzora)"
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Terminal keys ---"
+msgstr ""
+"\n"
+"--- Klávesy terminálu ---"
+
+msgid "new shell started\n"
+msgstr "spustený nový shell\n"
+
+msgid "Vim: Error reading input, exiting...\n"
+msgstr "Vim: Chyba pri èítaní vstupu, konèím...\n"
+
+#. must display the prompt
+msgid "No undo possible; continue anyway"
+msgstr "Odstránenie zmien nie je mo¾né; chcete napriek tomu pokraèova»"
+
+msgid "E438: u_undo: line numbers wrong"
+msgstr "E438: u_undo: èísla riadkov sú chybné"
+
+msgid "1 change"
+msgstr "1 zmena"
+
+#, c-format
+msgid "%ld changes"
+msgstr "%ld zmien"
+
+msgid "E439: undo list corrupt"
+msgstr "E439: záznam o zmenách po¹kodený"
+
+msgid "E440: undo line missing"
+msgstr "E440: chýba opravný riadok"
+
+#. Only MS VC 4.1 and earlier can do Win32s
+msgid ""
+"\n"
+"MS-Windows 16/32-bit GUI version"
+msgstr ""
+"\n"
+"16/32 bitová GUI verzia pre MS Windows"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit GUI version"
+msgstr ""
+"\n"
+"32 bitová GUI verzia pre MS Windows"
+
+msgid " in Win32s mode"
+msgstr " vo Win32 re¾ime"
+
+msgid " with OLE support"
+msgstr " s OLE podporou"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit console version"
+msgstr ""
+"\n"
+"32 bitová verzia pre MS Windows konzolu"
+
+msgid ""
+"\n"
+"MS-Windows 16-bit version"
+msgstr ""
+"\n"
+"16 bitová verzia pre MS Windows"
+
+msgid ""
+"\n"
+"32-bit MS-DOS version"
+msgstr ""
+"\n"
+"32 bitová verzia pre MS-DOS"
+
+msgid ""
+"\n"
+"16-bit MS-DOS version"
+msgstr ""
+"\n"
+"16 bitová MS-DOS verzia"
+
+msgid ""
+"\n"
+"MacOS X (unix) version"
+msgstr ""
+"\n"
+"MacOS X (unix) verzia"
+
+msgid ""
+"\n"
+"MacOS X version"
+msgstr ""
+"\n"
+"MacOS X verzia"
+
+msgid ""
+"\n"
+"MacOS version"
+msgstr ""
+"\n"
+"MacOS verzia"
+
+msgid ""
+"\n"
+"RISC OS version"
+msgstr ""
+"\n"
+"RISC OS verzia"
+
+msgid ""
+"\n"
+"Included patches: "
+msgstr ""
+"\n"
+"Pou¾ité záplaty: "
+
+msgid "Modified by "
+msgstr "Zmenil "
+
+msgid ""
+"\n"
+"Compiled "
+msgstr ""
+"\n"
+"Prelo¾ená "
+
+msgid "by "
+msgstr " "
+
+msgid ""
+"\n"
+"Huge version "
+msgstr ""
+"\n"
+"Maximálna verzia"
+
+msgid ""
+"\n"
+"Big version "
+msgstr ""
+"\n"
+"Veµká verzia "
+
+msgid ""
+"\n"
+"Normal version "
+msgstr ""
+"\n"
+"Normálna verzia"
+
+msgid ""
+"\n"
+"Small version "
+msgstr ""
+"\n"
+"Malá verzia "
+
+msgid ""
+"\n"
+"Tiny version "
+msgstr ""
+"\n"
+"Minimálna verzia "
+
+msgid "without GUI."
+msgstr "bez grafického rozhrania."
+
+msgid "with GTK2-GNOME GUI."
+msgstr "s grafickým rozhraním GTK2-GNOME."
+
+msgid "with GTK-GNOME GUI."
+msgstr "s grafickým rozhraním GTK-GNOME."
+
+msgid "with GTK2 GUI."
+msgstr "s grafickým rozhraním GTK2."
+
+msgid "with GTK GUI."
+msgstr "s grafickým rozhraním GTK."
+
+msgid "with X11-Motif GUI."
+msgstr "s grafickým rozhraním X11-Motif."
+
+msgid "with X11-neXtaw GUI."
+msgstr "s grafickým rozhraním X11-neXtaw."
+
+msgid "with X11-Athena GUI."
+msgstr "s grafickým rozhraním X11-Athena."
+
+msgid "with Photon GUI."
+msgstr "s grafickým rozhraním Photon."
+
+msgid "with GUI."
+msgstr "s grafickým rozhraním."
+
+msgid "with Carbon GUI."
+msgstr "s grafickým rozhraním Carbon."
+
+msgid "with Cocoa GUI."
+msgstr "s grafickým rozhraním Cocoa."
+
+msgid "with (classic) GUI."
+msgstr "s klasickým grafickým rozhraním."
+
+msgid "with KDE GUI."
+msgstr "s grafickým rozhraním KDE."
+
+msgid " Features included (+) or not (-):\n"
+msgstr " Vlastnosti zahrnuté (+) a nezahrnuté (-):\n"
+
+msgid " system vimrc file: \""
+msgstr " systémový vimrc súbor: \""
+
+msgid " user vimrc file: \""
+msgstr " u¾ívateµský vimrc súbor: \""
+
+msgid " 2nd user vimrc file: \""
+msgstr " druhý u¾ívateµský vimrc súbor: \""
+
+msgid " 3rd user vimrc file: \""
+msgstr " tretí u¾ívateµský vimrc súbor: \""
+
+msgid " user exrc file: \""
+msgstr " u¾ívateµský exrc súbor: \""
+
+msgid " 2nd user exrc file: \""
+msgstr " druhý u¾ívateµský exrc súbor: \""
+
+msgid " system gvimrc file: \""
+msgstr " systémový gvimrc súbor: \""
+
+msgid " user gvimrc file: \""
+msgstr " u¾ívateµský gvimrc súbor: \""
+
+msgid "2nd user gvimrc file: \""
+msgstr "druhý u¾ívateµský gvimrc súbor: \""
+
+msgid "3rd user gvimrc file: \""
+msgstr "tretí u¾ívateµský gvimrc súbor: \""
+
+msgid " system menu file: \""
+msgstr " systémový súbor s ponukou: \""
+
+msgid " fall-back for $VIM: \""
+msgstr " implicitná hodnota $VIM:\""
+
+msgid " f-b for $VIMRUNTIME: \""
+msgstr " f-b pre $VIMRUNTIME: \""
+
+msgid "Compilation: "
+msgstr "Preklad: "
+
+msgid "Compiler: "
+msgstr "Prekladaè: "
+
+msgid "Linking: "
+msgstr "Zlinkované: "
+
+msgid " DEBUG BUILD"
+msgstr " PODPORA LADENIA"
+
+msgid "VIM - Vi IMproved"
+msgstr "VIM - Vi IMproved"
+
+msgid "version "
+msgstr "verzia "
+
+msgid "by Bram Moolenaar et al."
+msgstr "od Brama Moolenaara a ïal¹ích"
+
+msgid "Vim is open source and freely distributable"
+msgstr "Vim je voµne ¹íriteµný program s otvoreným kódom"
+
+msgid "Help poor children in Uganda!"
+msgstr "Pomô¾te chudobným de»om v Ugande!"
+
+msgid "type :help iccf<Enter> for information "
+msgstr "zadajte :help iccf<Enter> pre informácie "
+
+msgid "type :q<Enter> to exit "
+msgstr "zadajte :q<Enter> pre ukonèenie programu "
+
+msgid "type :help<Enter> or <F1> for on-line help"
+msgstr "zadajte :help<Enter> alebo <F1> pre pomocníka "
+
+msgid "type :help version8<Enter> for version info"
+msgstr "zadajte :help version8<Enter> pre informácie o verzii"
+
+msgid "Running in Vi compatible mode"
+msgstr "Pracujem v re¾ime kompatibility s Vi"
+
+msgid "type :set nocp<Enter> for Vim defaults"
+msgstr "zadajte :set nocp<Enter> pre implicitné nastavenie Vim"
+
+msgid "type :help cp-default<Enter> for info on this"
+msgstr "podrobnej¹ie informácie získate pomocou :help cp-default<Enter>"
+
+msgid "menu Help->Orphans for information "
+msgstr "bli¾¹ie informácie v ponuke Pomocník->Samostatné"
+
+msgid "Running modeless, typed text is inserted"
+msgstr "Spú¹»am v bezmódovom re¾ime, písaný text je vlo¾ený"
+
+msgid "menu Edit->Global Settings->Toggle Insert Mode "
+msgstr "ponuka Úpravy->Globálne mo¾nosti->Prepnú» re¾im vlo¾enia "
+
+msgid " for two modes "
+msgstr " pre dva re¾imy "
+
+msgid "menu Edit->Global Settings->Toggle Vi Compatible"
+msgstr "ponuka Úpravy->Globálne mo¾nostt->Prepnú» Vi kompatibilný re¾im"
+
+msgid " for Vim defaults "
+msgstr " pre predvolené vlastnosti Vim "
+
+msgid "Sponsor Vim development!"
+msgstr "Zasponzorujte vývoj Vimu!"
+
+msgid "Become a registered Vim user!"
+msgstr "Staòte sa registrovaným u¾ívateµom Vimu!"
+
+msgid "type :help sponsor<Enter> for information "
+msgstr "zadajte :help sponsor<Enter> pre informácie "
+
+msgid "type :help register<Enter> for information "
+msgstr "zadajte :help register<Enter> pre informácie "
+
+msgid "menu Help->Sponsor/Register for information "
+msgstr "bli¾¹ie informácie v ponuke Pomocník->Sponzor/Registrácia"
+
+msgid "WARNING: Windows 95/98/ME detected"
+msgstr "VAROVANIE: detekované Windows 95/98/ME"
+
+msgid "type :help windows95<Enter> for info on this"
+msgstr "zadajte :help windows95<Enter> pre podrobnej¹ie informácie"
+
+msgid "E441: There is no preview window"
+msgstr "E441: Nenájdené ¾iadne okno náhµadu"
+
+msgid "E442: Can't split topleft and botright at the same time"
+msgstr ""
+"E442: Okno sa nedá rozdeli» zároveò v móde 'vrchný-µavý' a 'spodný-"
+"pravý' ('topleft' a 'botright')"
+
+msgid "E443: Cannot rotate when another window is split"
+msgstr "E443: Nedá sa rotova», ak je iné okno rozdelené"
+
+msgid "E444: Cannot close last window"
+msgstr "E444: Posledné okno sa nedá zatvori»"
+
+msgid "Already only one window"
+msgstr "Existuje u¾ iba jedno okno"
+
+msgid "E445: Other window contains changes"
+msgstr "E445: Iné okno obsahuje zmeny"
+
+msgid "E446: No file name under cursor"
+msgstr "E446: Pod kurzorom sa nenachádza názov súboru"
+
+#, c-format
+msgid "E447: Can't find file \"%s\" in path"
+msgstr "E447: Súbor \"%s\" sa nedá nájs» v ceste"
+
+#, c-format
+msgid "E370: Could not load library %s"
+msgstr "E370: Nepodarilo sa nahra» kni¾nicu %s"
+
+msgid "Sorry, this command is disabled: the Perl library could not be loaded."
+msgstr "Prepáète, tento príkaz je vypnutý, Perl kni¾nica nemô¾e by» naèítaná."
+
+msgid "E299: Perl evaluation forbidden in sandbox without the Safe module"
+msgstr "E299: Vykonanie kódu v jazyku Perl nie je mo¾né v bezpeènostnej schránke bez bezpeènostného modulu"
+
+msgid "Edit with &multiple Vims"
+msgstr "Upravi» s viacerý&mi Vimmi"
+
+msgid "Edit with single &Vim"
+msgstr "Upravi» s jedným &Vimom"
+
+msgid "Diff with Vim"
+msgstr "Porovna» &Vimom"
+
+msgid "Edit with &Vim"
+msgstr "Upravi» s &Vimom"
+
+#. Now concatenate
+msgid "Edit with existing Vim - "
+msgstr "Upravi» s existujúcim Vimom - "
+
+msgid "Edits the selected file(s) with Vim"
+msgstr "Upravi» vybrané súbory s Vimom"
+
+msgid "Error creating process: Check if gvim is in your path!"
+msgstr "Chyba vytvárania procesu: Skontrolujte, èi je gvim vo va¹ej ceste!"
+
+msgid "gvimext.dll error"
+msgstr "chyba gvimext.dll"
+
+msgid "Path length too long!"
+msgstr "Príli¹ dlhá cesta!"
+
+msgid "--No lines in buffer--"
+msgstr "--Buffer neobsahuje ¾iadne riadky--"
+
+#.
+#. * The error messages that can be shared are included here.
+#. * Excluded are errors that are only used once and debugging messages.
+#.
+msgid "E470: Command aborted"
+msgstr "E470: Príkaz preru¹ený"
+
+msgid "E471: Argument required"
+msgstr "E471: Je vy¾adovaný argument"
+
+msgid "E10: \\ should be followed by /, ? or &"
+msgstr "E10: po \\ by malo nasledova» /, ? alebo &"
+
+msgid "E11: Invalid in command-line window; <CR> executes, CTRL-C quits"
+msgstr ""
+"E11: Chybný príkaz v okne príkazového riadku; <Enter> spú¹»a, CTRL-C ukonèuje"
+
+msgid "E12: Command not allowed from exrc/vimrc in current dir or tag search"
+msgstr ""
+"E12: Príkaz nie je z exrc/vimrc v aktuálnom adresári alebo pri hµadaní tagu "
+"povolený."
+
+msgid "E171: Missing :endif"
+msgstr "E171: Chýba :endif"
+
+msgid "E600: Missing :endtry"
+msgstr "E600: Chýba :endtry"
+
+msgid "E170: Missing :endwhile"
+msgstr "E170: Chýba :endwhile"
+
+msgid "E170: Missing :endfor"
+msgstr "E170: Chýba :endfor"
+
+msgid "E588: :endwhile without :while"
+msgstr "E588: :endwhile bez zodpovedajúceho :while"
+
+msgid "E588: :endfor without :for"
+msgstr "E588: :endfor bez zodpovedajúceho :for"
+
+msgid "E13: File exists (add ! to override)"
+msgstr "E13: Súbor existuje (pou¾ite ! pre prepísanie)"
+
+msgid "E472: Command failed"
+msgstr "E472: Príkaz zlyhal"
+
+#, c-format
+msgid "E234: Unknown fontset: %s"
+msgstr "E234: Neznáma sada písiem: %s"
+
+#, c-format
+msgid "E235: Unknown font: %s"
+msgstr "E235: Neznáme písmo: %s"
+
+#, c-format
+msgid "E236: Font \"%s\" is not fixed-width"
+msgstr "E236: Písmo \"%s\" nemá pevnú ¹írku"
+
+msgid "E473: Internal error"
+msgstr "E473: Vnútorná chyba"
+
+msgid "Interrupted"
+msgstr "Preru¹ené"
+
+msgid "E14: Invalid address"
+msgstr "E14: Chybná adresa"
+
+msgid "E474: Invalid argument"
+msgstr "E474: Chybný argument"
+
+#, c-format
+msgid "E475: Invalid argument: %s"
+msgstr "E475: Chybný argument: %s"
+
+#, c-format
+msgid "E15: Invalid expression: %s"
+msgstr "E15: Chybný výraz: %s"
+
+msgid "E16: Invalid range"
+msgstr "E16: Chybný rozsah"
+
+msgid "E476: Invalid command"
+msgstr "E476: Chybný príkaz"
+
+#, c-format
+msgid "E17: \"%s\" is a directory"
+msgstr "E17: \"%s\" je adresárom"
+
+#, c-format
+msgid "E364: Library call failed for \"%s()\""
+msgstr "E364: Vyvolanie kni¾niènej funkcia zlyhalo pre \"%s()\""
+
+#, c-format
+msgid "E448: Could not load library function %s"
+msgstr "E448: Nepodarilo sa nahra» funkciu kni¾nice %s"
+
+msgid "E19: Mark has invalid line number"
+msgstr "E19: Znaèka má chybné èíslo riadku"
+
+msgid "E20: Mark not set"
+msgstr "E20: Znaèka nie je nastavená"
+
+msgid "E21: Cannot make changes, 'modifiable' is off"
+msgstr "E21: Nemo¾no robi» zmeny, voµba 'modifiable' je vypnutá"
+
+msgid "E22: Scripts nested too deep"
+msgstr "E22: Skripty vnorené príli¹ hlboko"
+
+msgid "E23: No alternate file"
+msgstr "E23: ®iadny alternatívny súbor"
+
+msgid "E24: No such abbreviation"
+msgstr "E24: Taká skratka neexistuje"
+
+msgid "E477: No ! allowed"
+msgstr "E477: ! nie je povolený"
+
+msgid "E25: GUI cannot be used: Not enabled at compile time"
+msgstr "E25: Nedá sa pou¾í» GUI: nebolo zapnuté pri preklade programu"
+
+msgid "E26: Hebrew cannot be used: Not enabled at compile time\n"
+msgstr ""
+"E26: Nedá sa pou¾í» hebrejský re¾im: nebol zapnutý pri preklade programu\n"
+
+msgid "E27: Farsi cannot be used: Not enabled at compile time\n"
+msgstr "E27: Nedá sa pou¾í» farsi re¾im: nebol zapnutý pri preklade programu\n"
+
+msgid "E800: Arabic cannot be used: Not enabled at compile time\n"
+msgstr "E800: Nedá sa pou¾í» arabic re¾im: nebol zapnutý pri preklade programu\n"
+
+#, c-format
+msgid "E28: No such highlight group name: %s"
+msgstr "E28: Skupina zvýraznenia %s neexistuje"
+
+msgid "E29: No inserted text yet"
+msgstr "E29: Zatiaµ nie je vlo¾ený ¾iaden text"
+
+msgid "E30: No previous command line"
+msgstr "E30: ®iadny predchádzajúci príkazový riadok"
+
+msgid "E31: No such mapping"
+msgstr "E31: Mapovanie nenájdené"
+
+msgid "E479: No match"
+msgstr "E479: ®iadna zhoda"
+
+#, c-format
+msgid "E480: No match: %s"
+msgstr "E480: ®iadna zhoda: %s"
+
+msgid "E32: No file name"
+msgstr "E32: ®iadny názov súboru"
+
+msgid "E33: No previous substitute regular expression"
+msgstr "E33: ®iadny predchádzajúci prislúchajúci správny výraz"
+
+msgid "E34: No previous command"
+msgstr "E34: ®iadny predchádzajúci príkaz"
+
+msgid "E35: No previous regular expression"
+msgstr "E35: ®iadny predchádzajúci regulárny výraz"
+
+msgid "E481: No range allowed"
+msgstr "E481: Rozsah nie je povolený"
+
+msgid "E36: Not enough room"
+msgstr "E36: Nedostatok miesta"
+
+#, c-format
+msgid "E247: no registered server named \"%s\""
+msgstr "E247: ¾iaden registrovaný server pomenovaný \"%s\""
+
+#, c-format
+msgid "E482: Can't create file %s"
+msgstr "E482: Nedá sa vytvori» súbor %s"
+
+msgid "E483: Can't get temp file name"
+msgstr "E483: Nedá sa získa» názov doèasného súboru"
+
+#, c-format
+msgid "E484: Can't open file %s"
+msgstr "E484: Nedá sa otvori» súbor %s"
+
+#, c-format
+msgid "E485: Can't read file %s"
+msgstr "E485: Nedá sa èíta» súbor %s"
+
+msgid "E37: No write since last change (add ! to override)"
+msgstr "E37: Neulo¾ené zmeny (pou¾ite ! pre vynútenie)"
+
+msgid "E38: Null argument"
+msgstr "E38: Nulový argument"
+
+msgid "E39: Number expected"
+msgstr "E39: Oèakávané èíslo"
+
+#, c-format
+msgid "E40: Can't open errorfile %s"
+msgstr "E40: Nedá sa otvori» chybový súbor %s"
+
+msgid "E233: cannot open display"
+msgstr "E233: nedá sa otvori» displej"
+
+msgid "E41: Out of memory!"
+msgstr "E41: Nedostatok pamäti!"
+
+msgid "Pattern not found"
+msgstr "Vzor nenájdený"
+
+#, c-format
+msgid "E486: Pattern not found: %s"
+msgstr "E486: Vzor nenájdený: %s"
+
+msgid "E487: Argument must be positive"
+msgstr "E487: Argument musí by» kladný"
+
+msgid "E459: Cannot go back to previous directory"
+msgstr "E459: ®iadny predchádzajúci adresár"
+
+msgid "E42: No Errors"
+msgstr "E42: ®iadne chyby"
+
+msgid "E43: Damaged match string"
+msgstr "E43: Po¹kodený re»azac pre vyhµadávanie"
+
+msgid "E44: Corrupted regexp program"
+msgstr "E44: Po¹kodený regexp program"
+
+msgid "E45: 'readonly' option is set (add ! to override)"
+msgstr ""
+"E45: voµba 'readonly' (iba na èítanie) je nastavená (pou¾ite ! pre "
+"prepísanie)"
+
+#, c-format
+msgid "E46: Cannot change read-only variable \"%s\""
+msgstr "E46: Nedá sa nastavi» premenná len na èítanie \"%s\""
+
+#, c-format
+msgid "E46: Cannot set variable in the sandbox: \"%s\""
+msgstr "E46: Nedá sa nastavi» premenná v bezpeènostnej schránke: \"%s\""
+
+msgid "E47: Error while reading errorfile"
+msgstr "E47: Chyba pri èítaní chybového súboru"
+
+msgid "E48: Not allowed in sandbox"
+msgstr "E48: Nie je dovolené v bezpeènostnej schránke"
+
+msgid "E523: Not allowed here"
+msgstr "E523: Nie je na povolené na tomto mieste"
+
+msgid "E359: Screen mode setting not supported"
+msgstr "E359: Nastavovanie re¾imu obrazovky nie je podporované"
+
+msgid "E49: Invalid scroll size"
+msgstr "E49: Chybná hodnota veµkosti rolovania"
+
+msgid "E91: 'shell' option is empty"
+msgstr "E91: voµba 'shell' je prázdna"
+
+msgid "E255: Couldn't read in sign data!"
+msgstr "E255: Chyba -- nedájú sa preèíta» oznaèovacie dáta!"
+
+msgid "E72: Close error on swap file"
+msgstr "E72: Chyba pri uzatváraní odkladacieho súboru"
+
+msgid "E73: tag stack empty"
+msgstr "E73: zoznam tagov je prázdny"
+
+msgid "E74: Command too complex"
+msgstr "E74: Príkaz je príli¹ zlo¾itý"
+
+msgid "E75: Name too long"
+msgstr "E75: Názov je príli¹ dlhý"
+
+msgid "E76: Too many ["
+msgstr "E76: Príli¹ mnoho ["
+
+msgid "E77: Too many file names"
+msgstr "E77: Príli¹ mnoho názvov súborov"
+
+msgid "E488: Trailing characters"
+msgstr "E488: Nadbytoèné znaky na konci"
+
+msgid "E78: Unknown mark"
+msgstr "E78: Neznáma znaèka"
+
+msgid "E79: Cannot expand wildcards"
+msgstr "E79: Nemo¾no expandova» ¾olíkové znaky (wildcards)"
+
+msgid "E591: 'winheight' cannot be smaller than 'winminheight'"
+msgstr ""
+"E591: hodnota voµby 'winheight' (vý¹ka okna) nesmie by» men¹ia ne¾ hodnota voµby 'winminheight' (minimálna vý¹ka okna)"
+
+msgid "E592: 'winwidth' cannot be smaller than 'winminwidth'"
+msgstr ""
+"E592: hodnota voµby 'winwidth' (¹írka okna) nesmie by» men¹ia ne¾ hodnota volµy 'winminwidth' (minimálna ¹írka okna)"
+
+msgid "E80: Error while writing"
+msgstr "E80: Chyba pri ukladaní"
+
+msgid "Zero count"
+msgstr "Nulový poèet"
+
+msgid "E81: Using <SID> not in a script context"
+msgstr "E81: Pou¾itie <SID> mimo kontext skriptu"
+
+msgid "E449: Invalid expression received"
+msgstr "E449: Bol prijatý chybný výraz"
+
+msgid "E463: Region is guarded, cannot modify"
+msgstr "E463: Región je uzamknutý, nemo¾no modifikova»"
+
+msgid "E744: NetBeans does not allow changes in read-only files"
+msgstr "E744: NetBeans nepovoµuje zmeny v súboroch len na èítanie"
+
+#, c-format
+msgid "E685: Internal error: %s"
+msgstr "E685: Vnútorná chyba: %s"
+
+msgid "E363: pattern uses more memory than 'maxmempattern'"
+msgstr "E363: vzor pou¾íva viac pamäte ako 'maxmempattern'"
+
+msgid "E749: empty buffer"
+msgstr "E749: prázdny buffer"
+
+msgid "E682: Invalid search pattern or delimiter"
+msgstr "E682: Neprípustný hµadaný re»azec alebo oddeµovaè"
+
+msgid "E139: File is loaded in another buffer"
+msgstr "E139: Súbor je naèítaný v inom buffere"
+
+#, c-format
+msgid "E764: Option '%s' is not set"
+msgstr "E764: Voµba \"%s\" nie je nastavená"
+
+msgid "search hit TOP, continuing at BOTTOM"
+msgstr "hµadanie dosiahlo zaèiatok, pokraèovanie od konca"
+
+msgid "search hit BOTTOM, continuing at TOP"
+msgstr "hµadanie dosiahlo koniec, pokraèovanie od zaèiatku"
+
diff --git a/src/po/sr.po b/src/po/sr.po
new file mode 100644
index 0000000..88c5d18
--- /dev/null
+++ b/src/po/sr.po
@@ -0,0 +1,7115 @@
+# Serbian Cyrillic translation for Vim
+#
+# Do ":help uganda" in Vim to read copying and usage conditions.
+# Do ":help credits" in Vim to see a list of people who contributed.
+# Copyright (C) 2017
+# This file is distributed under the same license as the Vim package.
+# FIRST AUTHOR Ivan Pešić <ivan.pesic@gmail.com>, 2017.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Vim(Serbian)\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2018-05-15 11:55+0400\n"
+"PO-Revision-Date: 2018-05-15 10:50+0400\n"
+"Last-Translator: Ivan Pešić <ivan.pesic@gmail.com>\n"
+"Language-Team: Serbian\n"
+"Language: sr\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\n"
+
+msgid "E831: bf_key_init() called with empty password"
+msgstr "E831: bf_key_init() је позвана Ñа празном лозинком"
+
+msgid "E820: sizeof(uint32_t) != 4"
+msgstr "E820: sizeof(uint32_t) != 4"
+
+msgid "E817: Blowfish big/little endian use wrong"
+msgstr "E817: Blowfish употреба big/little endian је погрешна"
+
+msgid "E818: sha256 test failed"
+msgstr "E818: sha256 теÑÑ‚ није уÑпео"
+
+msgid "E819: Blowfish test failed"
+msgstr "E819: Blowfish теÑÑ‚ није уÑпео"
+
+msgid "[Location List]"
+msgstr "[ЛиÑта локација]"
+
+msgid "[Quickfix List]"
+msgstr "[Quickfix лиÑта]"
+
+msgid "E855: Autocommands caused command to abort"
+msgstr "E855: Ðутокоманде Ñу изазвале прекид команде"
+
+msgid "E82: Cannot allocate any buffer, exiting..."
+msgstr "E82: Ðе може да Ñе резервише меморија ни за један бафер, излазак..."
+
+msgid "E83: Cannot allocate buffer, using other one..."
+msgstr "E83: Ðе може да Ñе резервише меморија за бафер, кориÑти Ñе други..."
+
+msgid "E931: Buffer cannot be registered"
+msgstr "E931: Бафер не може да Ñе региÑтрује"
+
+msgid "E937: Attempt to delete a buffer that is in use"
+msgstr "E937: Покушај бриÑања бафера који је у употреби"
+
+msgid "E515: No buffers were unloaded"
+msgstr "E515: Ðиједан бафер није уклоњен из меморије"
+
+msgid "E516: No buffers were deleted"
+msgstr "E516: Ðиједан бафер није обриÑан"
+
+msgid "E517: No buffers were wiped out"
+msgstr "E517: Ðиједан бафер није очишћен"
+
+msgid "1 buffer unloaded"
+msgstr "1 бафер је уклоњен из меморије"
+
+#, c-format
+msgid "%d buffers unloaded"
+msgstr "%d бафера је уклоњено из меморије"
+
+msgid "1 buffer deleted"
+msgstr "1 бафер је обриÑан"
+
+#, c-format
+msgid "%d buffers deleted"
+msgstr "%d бафера је обриÑано"
+
+msgid "1 buffer wiped out"
+msgstr "1 бафер је очишћен"
+
+#, c-format
+msgid "%d buffers wiped out"
+msgstr "%d бафера је очишћено"
+
+msgid "E90: Cannot unload last buffer"
+msgstr "E90: ПоÑледњи бафер не може да Ñе уклони из меморије"
+
+msgid "E84: No modified buffer found"
+msgstr "E84: Ðије пронађен измењени бафер"
+
+msgid "E85: There is no listed buffer"
+msgstr "E85: Ðема бафера на лиÑти"
+
+msgid "E87: Cannot go beyond last buffer"
+msgstr "E87: Ðе може да Ñе иде иза поÑледњег бафера"
+
+msgid "E88: Cannot go before first buffer"
+msgstr "E88: Ðе може да Ñе иде иÑпред првог бафера"
+
+#, c-format
+msgid "E89: No write since last change for buffer %ld (add ! to override)"
+msgstr ""
+"E89: Од поÑледње измене није било упиÑа за бафер %ld (додајте ! да "
+"премоÑтите)"
+
+msgid "E948: Job still running (add ! to end the job)"
+msgstr "E948: Задатак Ñе још извршава (додајте ! да зауÑтавите задатак)"
+
+msgid "E37: No write since last change (add ! to override)"
+msgstr "E37: Ðије било упиÑа од поÑледње промене (додајте ! да премоÑтите)"
+
+msgid "E948: Job still running"
+msgstr "E948: Задатак Ñе и даље извршава"
+
+msgid "E37: No write since last change"
+msgstr "E37: Ðије било упиÑа од поÑледње промене"
+
+msgid "W14: Warning: List of file names overflow"
+msgstr ""
+"W14: Упозорење: Прекорачена је макÑимална величина лиÑте имена датотека"
+
+#, c-format
+msgid "E92: Buffer %ld not found"
+msgstr "E92: Бафер %ld није пронађен"
+
+#, c-format
+msgid "E93: More than one match for %s"
+msgstr "E93: Више од једног подударања Ñа %s"
+
+#, c-format
+msgid "E94: No matching buffer for %s"
+msgstr "E94: Ðиједан бафер Ñе не подудара Ñа %s"
+
+#, c-format
+msgid "line %ld"
+msgstr "линија %ld"
+
+msgid "E95: Buffer with this name already exists"
+msgstr "E95: Бафер Ñа овим именом већ поÑтоји"
+
+msgid " [Modified]"
+msgstr "[Измењено]"
+
+msgid "[Not edited]"
+msgstr "[Ðије уређивано]"
+
+msgid "[New file]"
+msgstr "[Ðова датотека]"
+
+msgid "[Read errors]"
+msgstr "[Грешке при читању]"
+
+msgid "[RO]"
+msgstr "[СЧ]"
+
+msgid "[readonly]"
+msgstr "[Ñамо за читање]"
+
+#, c-format
+msgid "1 line --%d%%--"
+msgstr "1 линија --%d%%--"
+
+#, c-format
+msgid "%ld lines --%d%%--"
+msgstr "%ld линија --%d%%--"
+
+#, c-format
+msgid "line %ld of %ld --%d%%-- col "
+msgstr "линија %ld од %ld --%d%%-- кол "
+
+msgid "[No Name]"
+msgstr "[Без имена]"
+
+msgid "help"
+msgstr "помоћ"
+
+msgid "[Help]"
+msgstr "[Помоћ]"
+
+msgid "[Preview]"
+msgstr "[Преглед]"
+
+msgid "All"
+msgstr "Све"
+
+msgid "Bot"
+msgstr "Дно"
+
+msgid "Top"
+msgstr "Врх"
+
+msgid ""
+"\n"
+"# Buffer list:\n"
+msgstr ""
+"\n"
+"# ЛиÑта бафера:\n"
+
+msgid "E382: Cannot write, 'buftype' option is set"
+msgstr "E382: Ð£Ð¿Ð¸Ñ Ð½Ð¸Ñ˜Ðµ могућ, поÑтављена је 'buftype' опција"
+
+msgid "[Scratch]"
+msgstr "[Празно]"
+
+msgid ""
+"\n"
+"--- Signs ---"
+msgstr ""
+"\n"
+"--- Знаци ---"
+
+#, c-format
+msgid "Signs for %s:"
+msgstr "Знаци за %s:"
+
+#, c-format
+msgid " line=%ld id=%d name=%s"
+msgstr " линија=%ld ид=%d име=%s"
+
+msgid "E902: Cannot connect to port"
+msgstr "E902: Повезивање на порт није могуће"
+
+msgid "E901: gethostbyname() in channel_open()"
+msgstr "E901: gethostbyname() у channel_open()"
+
+msgid "E898: socket() in channel_open()"
+msgstr "E898: socket() у channel_open()"
+
+msgid "E903: received command with non-string argument"
+msgstr "E903: примњена команда Ñа аргуменом који није Ñтринг"
+
+msgid "E904: last argument for expr/call must be a number"
+msgstr "E904: поÑледњи аргумент за expr/call мора бити број"
+
+msgid "E904: third argument for call must be a list"
+msgstr "E904: трећи аргумент за call мора бити лиÑта"
+
+#, c-format
+msgid "E905: received unknown command: %s"
+msgstr "E905: примљена непозната команда: %s"
+
+#, c-format
+msgid "E630: %s(): write while not connected"
+msgstr "E630: %s(): ÑƒÐ¿Ð¸Ñ Ð´Ð¾Ðº није уÑпоÑтављена веза"
+
+#, c-format
+msgid "E631: %s(): write failed"
+msgstr "E631: %s(): ÑƒÐ¿Ð¸Ñ Ð½Ð¸Ñ˜Ðµ уÑпео"
+
+#, c-format
+msgid "E917: Cannot use a callback with %s()"
+msgstr "E917: Callback не може да Ñе кориÑти Ñа %s()"
+
+msgid "E912: cannot use ch_evalexpr()/ch_sendexpr() with a raw or nl channel"
+msgstr ""
+"E912: ch_evalexpr()/ch_sendexpr() не може да Ñе кориÑти Ñа raw или nl каналом"
+
+msgid "E906: not an open channel"
+msgstr "E906: није отворен канал"
+
+msgid "E920: _io file requires _name to be set"
+msgstr "E920: _io датотека захтева да _name буде поÑтављено"
+
+msgid "E915: in_io buffer requires in_buf or in_name to be set"
+msgstr "E915: in_io бафер захтева да in_buf или in_name буде поÑтављено"
+
+#, c-format
+msgid "E918: buffer must be loaded: %s"
+msgstr "E918: бафер мора бити учитан: %s"
+
+msgid "E821: File is encrypted with unknown method"
+msgstr "E821: Датотека је шифрована непознатом методом"
+
+msgid "Warning: Using a weak encryption method; see :help 'cm'"
+msgstr "Упозорење: КориÑти Ñе Ñлаба метода шифрирања; погледајте :help 'cm'"
+
+msgid "Enter encryption key: "
+msgstr "УнеÑите кључ за шифрирање: "
+
+msgid "Enter same key again: "
+msgstr "УнеÑите иÑти кључ поново: "
+
+msgid "Keys don't match!"
+msgstr "Кључеви ниÑу иÑти!"
+
+msgid "[crypted]"
+msgstr "[шифровано]"
+
+#, c-format
+msgid "E720: Missing colon in Dictionary: %s"
+msgstr "E720: ÐедоÑтаје тачка-зарез у Речнику: %s"
+
+#, c-format
+msgid "E721: Duplicate key in Dictionary: \"%s\""
+msgstr "E721: Дупликат кључа у Речнику: \"%s\""
+
+#, c-format
+msgid "E722: Missing comma in Dictionary: %s"
+msgstr "E722: ÐедоÑтаје зарез у Речнику: %s"
+
+#, c-format
+msgid "E723: Missing end of Dictionary '}': %s"
+msgstr "E723: ÐедоÑтаје крај Речника '}': %s"
+
+msgid "extend() argument"
+msgstr "extend() аргумент"
+
+#, c-format
+msgid "E737: Key already exists: %s"
+msgstr "E737: Кључ већ поÑтоји: %s"
+
+#, c-format
+msgid "E96: Cannot diff more than %ld buffers"
+msgstr "E96: Ðе може да Ñе упоређује више од %ld бафера"
+
+msgid "E810: Cannot read or write temp files"
+msgstr "E810: Ðије могуће читање или ÑƒÐ¿Ð¸Ñ Ñƒ привремене датотеке"
+
+msgid "E97: Cannot create diffs"
+msgstr "E97: Ðије могуће креирање diff-ова"
+
+msgid "Patch file"
+msgstr "Patch датотека"
+
+msgid "E816: Cannot read patch output"
+msgstr "E816: Ðије могуће читање patch излаза"
+
+msgid "E98: Cannot read diff output"
+msgstr "E98: Ðије могуће читање diff излаза"
+
+msgid "E99: Current buffer is not in diff mode"
+msgstr "E99: Текући бафер није у diff режиму"
+
+msgid "E793: No other buffer in diff mode is modifiable"
+msgstr "E793: Ðиједан други бафер у diff режиму није измењив"
+
+msgid "E100: No other buffer in diff mode"
+msgstr "E100: ниједан други бафер није у diff режиму"
+
+msgid "E101: More than two buffers in diff mode, don't know which one to use"
+msgstr "E101: Више од два бафера Ñу у diff режиму, не знам који да кориÑтим"
+
+#, c-format
+msgid "E102: Can't find buffer \"%s\""
+msgstr "E102: Бафер \"%s\" не може да Ñе пронађе"
+
+#, c-format
+msgid "E103: Buffer \"%s\" is not in diff mode"
+msgstr "E103: Бафер \"%s\" није у diff режиму"
+
+msgid "E787: Buffer changed unexpectedly"
+msgstr "E787: Бафер је неочекивано измењен"
+
+msgid "E104: Escape not allowed in digraph"
+msgstr "E104: Escape није дозвољен у digraph"
+
+msgid "E544: Keymap file not found"
+msgstr "E544: Keymap датотека није пронађена"
+
+msgid "E105: Using :loadkeymap not in a sourced file"
+msgstr "E105: Коришћење :loadkeymap ван датотеке која Ñе учитава као Ñкрипта"
+
+msgid "E791: Empty keymap entry"
+msgstr "E791: Празна keymap Ñтавка"
+
+msgid " Keyword completion (^N^P)"
+msgstr " Довршавање кључне речи (^N^P)"
+
+msgid " ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+msgstr " ^X режим (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+
+msgid " Whole line completion (^L^N^P)"
+msgstr " Довршавање целе линије (^L^N^P)"
+
+msgid " File name completion (^F^N^P)"
+msgstr " Довршавање имена датотеке (^F^N^P)"
+
+msgid " Tag completion (^]^N^P)"
+msgstr " Довршавање ознаке (^]^N^P)"
+
+msgid " Path pattern completion (^N^P)"
+msgstr " Довршавање шаблона путање (^N^P)"
+
+msgid " Definition completion (^D^N^P)"
+msgstr " Довршавање дефиниције (^D^N^P)"
+
+msgid " Dictionary completion (^K^N^P)"
+msgstr " Довршавање речника (^K^N^P)"
+
+msgid " Thesaurus completion (^T^N^P)"
+msgstr " Довршавање речника Ñинонима (^T^N^P)"
+
+msgid " Command-line completion (^V^N^P)"
+msgstr " Довршавање командне линије (^V^N^P)"
+
+msgid " User defined completion (^U^N^P)"
+msgstr " КориÑнички дефиниÑано довршавање (^U^N^P)"
+
+msgid " Omni completion (^O^N^P)"
+msgstr " Omni довршавање (^O^N^P)"
+
+msgid " Spelling suggestion (s^N^P)"
+msgstr " ПравопиÑни предлог (s^N^P)"
+
+msgid " Keyword Local completion (^N^P)"
+msgstr " Довршавање локалне кључне речи (^N^P)"
+
+msgid "Hit end of paragraph"
+msgstr "ДоÑтигнут крај паÑуÑа"
+
+msgid "E839: Completion function changed window"
+msgstr "E839: Функција довршавања је променила прозор"
+
+msgid "E840: Completion function deleted text"
+msgstr "E840: Функција довршавања је обриÑала текÑÑ‚"
+
+msgid "'dictionary' option is empty"
+msgstr "Опција 'dictionary' је празна"
+
+msgid "'thesaurus' option is empty"
+msgstr "Опција 'thesaurus' је празна"
+
+#, c-format
+msgid "Scanning dictionary: %s"
+msgstr "Скенирање речника: %s"
+
+msgid " (insert) Scroll (^E/^Y)"
+msgstr " (уметање) Скроловање (^E/^Y)"
+
+msgid " (replace) Scroll (^E/^Y)"
+msgstr " (замена) Скроловање (^E/^Y)"
+
+#, c-format
+msgid "Scanning: %s"
+msgstr "Скенирање: %s"
+
+msgid "Scanning tags."
+msgstr "Скенирање ознака."
+
+msgid "match in file"
+msgstr "подударање у датотеци"
+
+msgid " Adding"
+msgstr " Додавање"
+
+msgid "-- Searching..."
+msgstr "-- Претрага..."
+
+msgid "Back at original"
+msgstr "Ðазад на оригинал"
+
+msgid "Word from other line"
+msgstr "Реч из друге линије"
+
+msgid "The only match"
+msgstr "Једино подударање"
+
+#, c-format
+msgid "match %d of %d"
+msgstr "подударање %d од %d"
+
+#, c-format
+msgid "match %d"
+msgstr "подударање %d"
+
+msgid "E18: Unexpected characters in :let"
+msgstr "E18: Ðеочекивани карактери у :let"
+
+#, c-format
+msgid "E121: Undefined variable: %s"
+msgstr "E121: ÐедефиниÑана променљива: %s"
+
+msgid "E111: Missing ']'"
+msgstr "E111: ÐедоÑтаје ']'"
+
+msgid "E719: Cannot use [:] with a Dictionary"
+msgstr "E719: Ðе може да Ñе кориÑти [:] Ñа Речником"
+
+#, c-format
+msgid "E734: Wrong variable type for %s="
+msgstr "E734: Погрешан тип променљиве за %s="
+
+#, c-format
+msgid "E461: Illegal variable name: %s"
+msgstr "E461: Ðедозвољено име променљиве: %s"
+
+msgid "E806: using Float as a String"
+msgstr "E806: коришћење Float као String"
+
+msgid "E687: Less targets than List items"
+msgstr "E687: Мање одредишта него Ñтавки ЛиÑте"
+
+msgid "E688: More targets than List items"
+msgstr "E688: Више одредишта него Ñтавки ЛиÑте"
+
+msgid "Double ; in list of variables"
+msgstr "Дупле ; у лиÑти променљивих"
+
+#, c-format
+msgid "E738: Can't list variables for %s"
+msgstr "E738: Ðе може да Ñе прикаже лиÑта променљивих за %s"
+
+msgid "E689: Can only index a List or Dictionary"
+msgstr "E689: Само ЛиÑта или Речник могу да Ñе индекÑирају"
+
+msgid "E708: [:] must come last"
+msgstr "E708: [:] мора да буде поÑледња"
+
+msgid "E709: [:] requires a List value"
+msgstr "E709: [:] захтева вредноÑÑ‚ типа List"
+
+msgid "E710: List value has more items than target"
+msgstr "E710: ВредноÑÑ‚ типа List има више Ñтавки него одредиште"
+
+msgid "E711: List value has not enough items"
+msgstr "E711: ВредноÑÑ‚ типа List нема довољно Ñтавки"
+
+msgid "E690: Missing \"in\" after :for"
+msgstr "E690: ÐедоÑтаје \"in\" након :for"
+
+#, c-format
+msgid "E108: No such variable: \"%s\""
+msgstr "E108: Ðе поÑтоји таква променљива: \"%s\""
+
+#, c-format
+msgid "E940: Cannot lock or unlock variable %s"
+msgstr "E940: Ðе може да Ñе откључа или закључа променљива %s"
+
+msgid "E743: variable nested too deep for (un)lock"
+msgstr "E743: променљива је угњеждена Ñувише дубоко да би Ñе за(от)кључала"
+
+msgid "E109: Missing ':' after '?'"
+msgstr "E109: ÐедоÑтаје ':' након '?'"
+
+msgid "E804: Cannot use '%' with Float"
+msgstr "E804: '%' не може да Ñе кориÑти Ñа Float"
+
+msgid "E110: Missing ')'"
+msgstr "E110: ÐедоÑтаје ')'"
+
+msgid "E695: Cannot index a Funcref"
+msgstr "E695: Funcref не може да Ñе индекÑира"
+
+msgid "E909: Cannot index a special variable"
+msgstr "E909: Специјална променљива не може да Ñе индекÑира"
+
+#, c-format
+msgid "E112: Option name missing: %s"
+msgstr "E112: ÐедоÑтаје име опције: %s"
+
+#, c-format
+msgid "E113: Unknown option: %s"
+msgstr "E113: Ðепозната опција: %s"
+
+#, c-format
+msgid "E114: Missing quote: %s"
+msgstr "E114: ÐедоÑтаје наводник: %s"
+
+#, c-format
+msgid "E115: Missing quote: %s"
+msgstr "E115: ÐедоÑтаје наводник: %s"
+
+msgid "Not enough memory to set references, garbage collection aborted!"
+msgstr ""
+"Ðема довољно меморије за поÑтављање референци, прекинуто је Ñкупљање отпада"
+
+msgid "E724: variable nested too deep for displaying"
+msgstr "E724: променљива је угњеждена предубоко да би Ñе приказала"
+
+msgid "E805: Using a Float as a Number"
+msgstr "E805: КориÑти Ñе Float као Number"
+
+msgid "E703: Using a Funcref as a Number"
+msgstr "E703: КориÑти Ñе Funcref као Number"
+
+msgid "E745: Using a List as a Number"
+msgstr "E745: КориÑти Ñе List као Number"
+
+msgid "E728: Using a Dictionary as a Number"
+msgstr "E728: КориÑти Ñе Dictionary као Number"
+
+msgid "E910: Using a Job as a Number"
+msgstr "E910: КориÑти Ñе Job као Number"
+
+msgid "E913: Using a Channel as a Number"
+msgstr "E913: КориÑти Ñе Channel као Number"
+
+msgid "E891: Using a Funcref as a Float"
+msgstr "E891: КориÑти Ñе Funcref као Float"
+
+msgid "E892: Using a String as a Float"
+msgstr "E892: КориÑти Ñе String као Float"
+
+msgid "E893: Using a List as a Float"
+msgstr "E893: КориÑти Ñе List као Float"
+
+msgid "E894: Using a Dictionary as a Float"
+msgstr "E894: КориÑти Ñе Dictionary као Float"
+
+msgid "E907: Using a special value as a Float"
+msgstr "E907: КориÑти Ñе Ñпецијална вредноÑÑ‚ као Float"
+
+msgid "E911: Using a Job as a Float"
+msgstr "E911: КориÑти Ñе Job као Float"
+
+msgid "E914: Using a Channel as a Float"
+msgstr "E914: КориÑти Ñе Channel као Float"
+
+msgid "E729: using Funcref as a String"
+msgstr "E729: кориÑти Ñе Funcref као String"
+
+msgid "E730: using List as a String"
+msgstr "E730: кориÑти Ñе List као String"
+
+msgid "E731: using Dictionary as a String"
+msgstr "E731: кориÑти Ñе Dictionary као String"
+
+msgid "E908: using an invalid value as a String"
+msgstr "E908: кориÑти Ñе недозвољена вредноÑÑ‚ као String"
+
+#, c-format
+msgid "E795: Cannot delete variable %s"
+msgstr "E795: Променљива %s не може да Ñе обрише"
+
+#, c-format
+msgid "E704: Funcref variable name must start with a capital: %s"
+msgstr "E704: Име Funcref мора да почне великим Ñловом: %s"
+
+#, c-format
+msgid "E705: Variable name conflicts with existing function: %s"
+msgstr "E705: Име променљиве је у конфликту Ñа поÑтојећом функцијом: %s"
+
+#, c-format
+msgid "E741: Value is locked: %s"
+msgstr "E741: ВредноÑÑ‚ је закључана: %s"
+
+msgid "Unknown"
+msgstr "Ðепознато"
+
+#, c-format
+msgid "E742: Cannot change value of %s"
+msgstr "E742: ВредноÑÑ‚ %s не може да Ñе промени"
+
+msgid "E698: variable nested too deep for making a copy"
+msgstr "E698: променљива је предубоко угњеждена да би Ñе направила копија"
+
+msgid ""
+"\n"
+"# global variables:\n"
+msgstr ""
+"\n"
+"# глобалне променљиве:\n"
+
+msgid ""
+"\n"
+"\tLast set from "
+msgstr ""
+"\n"
+"\tПоÑледњи Ñет од "
+
+msgid "E691: Can only compare List with List"
+msgstr "E691: List може да Ñе пореди Ñамо Ñа List"
+
+msgid "E692: Invalid operation for List"
+msgstr "E692: ÐеиÑправна операција за List"
+
+msgid "E735: Can only compare Dictionary with Dictionary"
+msgstr "E735: Dictionary може да Ñе пореди Ñамо Ñа Dictionary"
+
+msgid "E736: Invalid operation for Dictionary"
+msgstr "E736: ÐеиÑправна операција за Dictionary"
+
+msgid "E694: Invalid operation for Funcrefs"
+msgstr "E694: ÐеиÑправна операција за Funcrefs"
+
+msgid "map() argument"
+msgstr "map() аргумент"
+
+msgid "filter() argument"
+msgstr "filter() аргумент"
+
+#, c-format
+msgid "E686: Argument of %s must be a List"
+msgstr "E686: Ðргумент за %s мора бити List"
+
+msgid "E928: String required"
+msgstr "E928: Захтева Ñе String"
+
+msgid "E808: Number or Float required"
+msgstr "E808: Захтева Ñе Number или Float"
+
+msgid "add() argument"
+msgstr "add() аргумент"
+
+msgid "E785: complete() can only be used in Insert mode"
+msgstr "E785: complete() може да Ñе кориÑти Ñамо у режиму Уметање"
+
+msgid "&Ok"
+msgstr "&Ок"
+
+#, c-format
+msgid "+-%s%3ld line: "
+msgid_plural "+-%s%3ld lines: "
+msgstr[0] "+-%s%3ld линија: "
+msgstr[1] "+-%s%3ld линија: "
+
+#, c-format
+msgid "E700: Unknown function: %s"
+msgstr "E700: Ðепозната функција: %s"
+
+msgid "E922: expected a dict"
+msgstr "E922: очекивао Ñе dict"
+
+msgid "E923: Second argument of function() must be a list or a dict"
+msgstr "E923: Други аргумент function() мора бити list или dict"
+
+msgid ""
+"&OK\n"
+"&Cancel"
+msgstr ""
+"&OK\n"
+"О&ткажи"
+
+msgid "called inputrestore() more often than inputsave()"
+msgstr "inputrestore() је позвана више пута него inputsave()"
+
+msgid "insert() argument"
+msgstr "insert() аргумент"
+
+msgid "E786: Range not allowed"
+msgstr "E786: ОпÑег није дозвољен"
+
+msgid "E916: not a valid job"
+msgstr "E916: није валидан job"
+
+msgid "E701: Invalid type for len()"
+msgstr "E701: ÐеиÑправан тип за len()"
+
+#, c-format
+msgid "E798: ID is reserved for \":match\": %ld"
+msgstr "E798: ИД је резервиÑан за \":match\": %ld"
+
+msgid "E726: Stride is zero"
+msgstr "E726: Корак је нула"
+
+msgid "E727: Start past end"
+msgstr "E727: Почетак иза краја"
+
+msgid "<empty>"
+msgstr "<празно>"
+
+msgid "E240: No connection to the X server"
+msgstr "E240: Ðема везе Ñа X Ñервером"
+
+#, c-format
+msgid "E241: Unable to send to %s"
+msgstr "E241: Слање ка %s није могуће"
+
+msgid "E277: Unable to read a server reply"
+msgstr "E277: Ðе може да Ñе прочита одговор Ñервера"
+
+msgid "E941: already started a server"
+msgstr "E941: Ñервер је већ покренут"
+
+msgid "E942: +clientserver feature not available"
+msgstr "E942: МогућноÑÑ‚ +clientserver није доÑтупна"
+
+msgid "remove() argument"
+msgstr "remove() аргумент"
+
+msgid "E655: Too many symbolic links (cycle?)"
+msgstr "E655: Превише Ñимболичких веза (циклуÑ?)"
+
+msgid "reverse() argument"
+msgstr "reverse() аргумент"
+
+msgid "E258: Unable to send to client"
+msgstr "E258: Слање ка клијенту није могуће"
+
+#, c-format
+msgid "E927: Invalid action: '%s'"
+msgstr "E927: ÐеиÑправна акција: '%s'"
+
+msgid "sort() argument"
+msgstr "sort() аргумент"
+
+msgid "uniq() argument"
+msgstr "uniq() аргумент"
+
+msgid "E702: Sort compare function failed"
+msgstr "E702: Sort функција поређења није уÑпела"
+
+msgid "E882: Uniq compare function failed"
+msgstr "E882: Uniq функција поређења није уÑпела"
+
+msgid "(Invalid)"
+msgstr "(ÐеиÑправно)"
+
+#, c-format
+msgid "E935: invalid submatch number: %d"
+msgstr "E935: неиÑправан број подпоклапања: %d"
+
+msgid "E677: Error writing temp file"
+msgstr "E677: Грешка при упиÑу temp датотеке"
+
+msgid "E921: Invalid callback argument"
+msgstr "E921: ÐеиÑправан callback аргумент"
+
+#, c-format
+msgid "<%s>%s%s %d, Hex %02x, Oct %03o, Digr %s"
+msgstr "<%s>%s%s %d, Ð¥ÐµÐºÑ %02x, Окт %03o, Дигр %s"
+
+#, c-format
+msgid "<%s>%s%s %d, Hex %02x, Octal %03o"
+msgstr "<%s>%s%s %d, Ð¥ÐµÐºÑ %02x, Октално %03o"
+
+#, c-format
+msgid "> %d, Hex %04x, Oct %o, Digr %s"
+msgstr "> %d, Ð¥ÐµÐºÑ %04x, Окт %o, Дигр %s"
+
+#, c-format
+msgid "> %d, Hex %08x, Oct %o, Digr %s"
+msgstr "> %d, Ð¥ÐµÐºÑ %08x, Окт %o, Дигр %s"
+
+#, c-format
+msgid "> %d, Hex %04x, Octal %o"
+msgstr "> %d, Ð¥ÐµÐºÑ %04x, Октално %o"
+
+#, c-format
+msgid "> %d, Hex %08x, Octal %o"
+msgstr "> %d, Ð¥ÐµÐºÑ %08x, Октално %o"
+
+msgid "E134: Move lines into themselves"
+msgstr "E134: Премештање линија у Ñаме Ñебе"
+
+msgid "1 line moved"
+msgstr "1 линија премештена"
+
+#, c-format
+msgid "%ld lines moved"
+msgstr "%ld линија премештено"
+
+#, c-format
+msgid "%ld lines filtered"
+msgstr "%ld линија филтрирано"
+
+msgid "E135: *Filter* Autocommands must not change current buffer"
+msgstr "E135: *Филтер* Ðутокоманде не Ñмеју да мењају текући бафер"
+
+msgid "[No write since last change]\n"
+msgstr "[Ðема упиÑа од поÑледње промене]\n"
+
+#, c-format
+msgid "%sviminfo: %s in line: "
+msgstr "%sviminfo: %s у линији: "
+
+msgid "E136: viminfo: Too many errors, skipping rest of file"
+msgstr "E136: viminfo: Превише грешака, оÑтатак датотеке Ñе преÑкаче"
+
+#, c-format
+msgid "Reading viminfo file \"%s\"%s%s%s"
+msgstr "Читање viminfo датотеке \"%s\"%s%s%s"
+
+msgid " info"
+msgstr " инфо"
+
+msgid " marks"
+msgstr " маркера"
+
+msgid " oldfiles"
+msgstr " Ñтарихдатотека"
+
+msgid " FAILED"
+msgstr " ÐЕУСПЕЛО"
+
+#, c-format
+msgid "E137: Viminfo file is not writable: %s"
+msgstr "E137: Viminfo датотека није упиÑива: %s"
+
+#, c-format
+msgid "E929: Too many viminfo temp files, like %s!"
+msgstr "E929: Превише viminfo temp датотека, као %s!"
+
+#, c-format
+msgid "E138: Can't write viminfo file %s!"
+msgstr "E138: Viminfo датотека %s не може да Ñе упише!"
+
+#, c-format
+msgid "Writing viminfo file \"%s\""
+msgstr "УпиÑивање viminfo датотеке \"%s\""
+
+#, c-format
+msgid "E886: Can't rename viminfo file to %s!"
+msgstr "E886: Viminfo датотека не може да Ñе преименује у %s!"
+
+#, c-format
+msgid "# This viminfo file was generated by Vim %s.\n"
+msgstr "# Ову viminfo датотеку је генериÑао Vim %s.\n"
+
+msgid ""
+"# You may edit it if you're careful!\n"
+"\n"
+msgstr ""
+"# Можете да је уређујете ако Ñте опрезни!\n"
+"\n"
+
+msgid "# Value of 'encoding' when this file was written\n"
+msgstr "# ВредноÑÑ‚ опције 'encoding' када је ова датотека напиÑана\n"
+
+msgid "Illegal starting char"
+msgstr "ÐеиÑправан почетни карактер"
+
+msgid ""
+"\n"
+"# Bar lines, copied verbatim:\n"
+msgstr ""
+"\n"
+"# Преградне линије, копиране доÑловно:\n"
+
+msgid "Save As"
+msgstr "Сачувај као"
+
+msgid "Write partial file?"
+msgstr "Да упишем парцијалну датотеку?"
+
+msgid "E140: Use ! to write partial buffer"
+msgstr "E140: КориÑтите ! да биÑте упиÑали парцијални бафер"
+
+#, c-format
+msgid "Overwrite existing file \"%s\"?"
+msgstr "Да препишем поÑтојећи датотеку \"%s\"?"
+
+#, c-format
+msgid "Swap file \"%s\" exists, overwrite anyway?"
+msgstr "Swap датотека \"%s\" поÑтоји, да је препишем у Ñваком Ñлучају?"
+
+#, c-format
+msgid "E768: Swap file exists: %s (:silent! overrides)"
+msgstr "E768: Swap датотека поÑтоји: %s (:silent! премошћава)"
+
+#, c-format
+msgid "E141: No file name for buffer %ld"
+msgstr "E141: Ðема имена датотеке за бафер %ld"
+
+msgid "E142: File not written: Writing is disabled by 'write' option"
+msgstr "E142: Датотека није упиÑана: УпиÑивање је онемогућено опцијом 'write'"
+
+#, c-format
+msgid ""
+"'readonly' option is set for \"%s\".\n"
+"Do you wish to write anyway?"
+msgstr ""
+"'readonly' опција је поÑтављена за \"%s\".\n"
+"Да ли ипак желите да упишете?"
+
+#, c-format
+msgid ""
+"File permissions of \"%s\" are read-only.\n"
+"It may still be possible to write it.\n"
+"Do you wish to try?"
+msgstr ""
+"Дозволе датотеке \"%s\" омогућавају Ñамо читање.\n"
+"Можда је ипак могуће да Ñе упише.\n"
+"Да ли желите да покушате?"
+
+#, c-format
+msgid "E505: \"%s\" is read-only (add ! to override)"
+msgstr "E505: \"%s\" је Ñамо за читање (додајте ! за премошћавање)"
+
+msgid "Edit File"
+msgstr "Уреди датотеку"
+
+#, c-format
+msgid "E143: Autocommands unexpectedly deleted new buffer %s"
+msgstr "E143: Ðутокоманде Ñу неочекивано обриÑале нов бафер %s"
+
+msgid "E144: non-numeric argument to :z"
+msgstr "E144: ненумерички аргумент за :z"
+
+msgid "E145: Shell commands not allowed in rvim"
+msgstr "E145: Shell команде ниÑу дозвољене у rvim"
+
+msgid "E146: Regular expressions can't be delimited by letters"
+msgstr "E146: Регуларни изрази не могу да Ñе раздвајају Ñловима"
+
+#, c-format
+msgid "replace with %s (y/n/a/q/l/^E/^Y)?"
+msgstr "заменити Ñа %s (y/n/a/q/l/^E/^Y)?"
+
+msgid "(Interrupted) "
+msgstr "(Прекинуто)"
+
+msgid "1 match"
+msgstr "1 подударање"
+
+msgid "1 substitution"
+msgstr "1 замена"
+
+#, c-format
+msgid "%ld matches"
+msgstr "%ld подударања"
+
+#, c-format
+msgid "%ld substitutions"
+msgstr "%ld замена"
+
+msgid " on 1 line"
+msgstr " у 1 линији"
+
+#, c-format
+msgid " on %ld lines"
+msgstr " у %ld линија"
+
+msgid "E147: Cannot do :global recursive with a range"
+msgstr "E147: :global не може да Ñе изврши рекурзивно Ñа опÑегом"
+
+msgid "E148: Regular expression missing from global"
+msgstr "E148: У global недоÑтаје регуларни израз"
+
+#, c-format
+msgid "Pattern found in every line: %s"
+msgstr "Шаблон је пронаћен у Ñвакој линији: %s"
+
+#, c-format
+msgid "Pattern not found: %s"
+msgstr "Шаблон није пронађен: %s"
+
+msgid ""
+"\n"
+"# Last Substitute String:\n"
+"$"
+msgstr ""
+"\n"
+"# ПоÑледњи Стринг за замену:\n"
+"$"
+
+msgid "E478: Don't panic!"
+msgstr "E478: Ðе паничите!"
+
+#, c-format
+msgid "E661: Sorry, no '%s' help for %s"
+msgstr "E661: Жао нам је, нема '%s' помоћи за %s"
+
+#, c-format
+msgid "E149: Sorry, no help for %s"
+msgstr "E149: Жао нам је, нема помоћи за %s"
+
+#, c-format
+msgid "Sorry, help file \"%s\" not found"
+msgstr "Жао нам је, датотека помоћи \"%s\" није пронађена"
+
+#, c-format
+msgid "E151: No match: %s"
+msgstr "E151: Ðема подударања: %s"
+
+#, c-format
+msgid "E152: Cannot open %s for writing"
+msgstr "E152: %s не може да Ñе отвори за упиÑ"
+
+#, c-format
+msgid "E153: Unable to open %s for reading"
+msgstr "E153: %s не може да Ñе отвори за читање"
+
+#, c-format
+msgid "E670: Mix of help file encodings within a language: %s"
+msgstr "E670: Помешано је више кодирања фајлова помоћи за језик: %s"
+
+#, c-format
+msgid "E154: Duplicate tag \"%s\" in file %s/%s"
+msgstr "E154: Дуплирана ознака \"%s\" у датотеци %s/%s"
+
+#, c-format
+msgid "E150: Not a directory: %s"
+msgstr "E150: Ðије директоријум: %s"
+
+#, c-format
+msgid "E160: Unknown sign command: %s"
+msgstr "E160: Ðепозната знак команда: %s"
+
+msgid "E156: Missing sign name"
+msgstr "E156: ÐедоÑтаје име знака"
+
+msgid "E612: Too many signs defined"
+msgstr "E612: ДефиниÑано је превише знакова"
+
+#, c-format
+msgid "E239: Invalid sign text: %s"
+msgstr "E239: ÐеиÑправан текÑÑ‚ знака: %s"
+
+#, c-format
+msgid "E155: Unknown sign: %s"
+msgstr "E155: Ðепознат знак: %s"
+
+msgid "E159: Missing sign number"
+msgstr "E159: ÐедоÑтаје број знака"
+
+#, c-format
+msgid "E158: Invalid buffer name: %s"
+msgstr "E158: ÐеиÑправно име бафера: %s"
+
+msgid "E934: Cannot jump to a buffer that does not have a name"
+msgstr "E934: Ðе може да Ñе Ñкочи на бафер који нема име`"
+
+#, c-format
+msgid "E157: Invalid sign ID: %ld"
+msgstr "E157: ÐеиÑправан ИД знака: %ld"
+
+#, c-format
+msgid "E885: Not possible to change sign %s"
+msgstr "E885: Знак %s не може да Ñе промени"
+
+msgid " (NOT FOUND)"
+msgstr " (ÐИЈЕ ПРОÐÐЂЕÐО)"
+
+msgid " (not supported)"
+msgstr " (није подржано)"
+
+msgid "[Deleted]"
+msgstr "[ОбриÑано]"
+
+msgid "No old files"
+msgstr "Ðема Ñтарих датотека"
+
+msgid "Entering Debug mode. Type \"cont\" to continue."
+msgstr "Улазак у Debug режим. Откуцајте \"cont\" за наÑтавак."
+
+#, c-format
+msgid "Oldval = \"%s\""
+msgstr "Старавред = \"%s\""
+
+#, c-format
+msgid "Newval = \"%s\""
+msgstr "Ðоваавред = \"%s\""
+
+#, c-format
+msgid "line %ld: %s"
+msgstr "линија %ld: %s"
+
+#, c-format
+msgid "cmd: %s"
+msgstr "ком: %s"
+
+msgid "frame is zero"
+msgstr "оквир је нула"
+
+#, c-format
+msgid "frame at highest level: %d"
+msgstr "оквир је на највишем нивоу: %d"
+
+#, c-format
+msgid "Breakpoint in \"%s%s\" line %ld"
+msgstr "Прекидна тачка у \"%s%s\" линија %ld"
+
+#, c-format
+msgid "E161: Breakpoint not found: %s"
+msgstr "E161: Прекидна тачка није пронађена: %s"
+
+msgid "No breakpoints defined"
+msgstr "Ðије дефиниÑана ниједна прекидна тачка"
+
+#, c-format
+msgid "%3d %s %s line %ld"
+msgstr "%3d %s %s линија %ld"
+
+#, c-format
+msgid "%3d expr %s"
+msgstr "%3d израз %s"
+
+msgid "E750: First use \":profile start {fname}\""
+msgstr "E750: Ðајпре кориÑтите \":profile start {fname}\""
+
+#, c-format
+msgid "Save changes to \"%s\"?"
+msgstr "Да Ñачувам промене у \"%s\"?"
+
+#, c-format
+msgid "E947: Job still running in buffer \"%s\""
+msgstr "E947: Задатак Ñе и даље извршава у баферу \"%s\""
+
+#, c-format
+msgid "E162: No write since last change for buffer \"%s\""
+msgstr "E162: Ðије било упиÑа од поÑледње промене за бафер \"%s\""
+
+msgid "Warning: Entered other buffer unexpectedly (check autocommands)"
+msgstr "Упозорење: Ðеочекивано Ñе прешло у други бафер (проверите аутокоманде)"
+
+msgid "E163: There is only one file to edit"
+msgstr "E163: ПоÑтоји Ñамо једна датотека за уређивање"
+
+msgid "E164: Cannot go before first file"
+msgstr "E164: Ðе може да Ñе иде иÑпред прве датотеке"
+
+msgid "E165: Cannot go beyond last file"
+msgstr "E165: Ðе може да Ñе иде иÑпред прве датотеке"
+
+#, c-format
+msgid "E666: compiler not supported: %s"
+msgstr "E666: компајлер није подржан: %s"
+
+#, c-format
+msgid "Searching for \"%s\" in \"%s\""
+msgstr "Тражи Ñе \"%s\" у \"%s\""
+
+#, c-format
+msgid "Searching for \"%s\""
+msgstr "Тражи Ñе\"%s\""
+
+#, c-format
+msgid "not found in '%s': \"%s\""
+msgstr "није пронађено у '%s': \"%s\""
+
+#, c-format
+msgid "W20: Required python version 2.x not supported, ignoring file: %s"
+msgstr ""
+"W20: Захтевани python version 2.x није подржан, датотека: %s Ñе игнорише"
+
+#, c-format
+msgid "W21: Required python version 3.x not supported, ignoring file: %s"
+msgstr ""
+"W21: Захтевани python version 3.x није подржан, датотека: %s Ñе игнорише"
+
+msgid "Source Vim script"
+msgstr "Изворна Vim Ñкрипта"
+
+#, c-format
+msgid "Cannot source a directory: \"%s\""
+msgstr "Директоријум не може да буде извор: \"%s\""
+
+#, c-format
+msgid "could not source \"%s\""
+msgstr "не може бити извор \"%s\""
+
+#, c-format
+msgid "line %ld: could not source \"%s\""
+msgstr "линија %ld: не може бити извор \"%s\""
+
+#, c-format
+msgid "sourcing \"%s\""
+msgstr "прибављање \"%s\""
+
+#, c-format
+msgid "line %ld: sourcing \"%s\""
+msgstr "линија %ld: прибављање \"%s\""
+
+#, c-format
+msgid "finished sourcing %s"
+msgstr "завршено прибављање %s"
+
+#, c-format
+msgid "continuing in %s"
+msgstr "наÑтавља Ñе у %s"
+
+msgid "modeline"
+msgstr "режимÑка линија (modeline)"
+
+msgid "--cmd argument"
+msgstr "--cmd аргумент"
+
+msgid "-c argument"
+msgstr "-c аргумент"
+
+msgid "environment variable"
+msgstr "променљива окружења"
+
+msgid "error handler"
+msgstr "процедура за обраду грешке"
+
+msgid "W15: Warning: Wrong line separator, ^M may be missing"
+msgstr "W15: Упозорење: Погрешан Ñепаратор линије, можда недоÑтаје ^M"
+
+msgid "E167: :scriptencoding used outside of a sourced file"
+msgstr "E167: :scriptencoding Ñе кориÑти ван изворишне датотеке"
+
+msgid "E168: :finish used outside of a sourced file"
+msgstr "E168: :finish Ñе кориÑти ван изворишне датотеке"
+
+#, c-format
+msgid "Current %slanguage: \"%s\""
+msgstr "Текући %sјезик: \"%s\""
+
+#, c-format
+msgid "E197: Cannot set language to \"%s\""
+msgstr "E197: Језик не може да Ñе поÑтави на \"%s\""
+
+msgid "Entering Ex mode. Type \"visual\" to go to Normal mode."
+msgstr ""
+"Улазак у Ex режим. Откуцајте \"visual\" да биÑте прешли у Ðормални режим."
+
+msgid "E501: At end-of-file"
+msgstr "E501: Ðа крају-датотеке"
+
+msgid "E169: Command too recursive"
+msgstr "E169: Команда је Ñувише рекурзивна"
+
+#, c-format
+msgid "E605: Exception not caught: %s"
+msgstr "E605: Изузетак није ухваћен: %s"
+
+msgid "End of sourced file"
+msgstr "Крај изворишне датотеке"
+
+msgid "End of function"
+msgstr "Крај функције"
+
+msgid "E464: Ambiguous use of user-defined command"
+msgstr "E464: ДвоÑмиÑлена употреба кориÑнички дефиниÑане команде"
+
+msgid "E492: Not an editor command"
+msgstr "E492: Ðије команда едитора"
+
+msgid "E493: Backwards range given"
+msgstr "E493: Задат је опÑег уназад"
+
+msgid "Backwards range given, OK to swap"
+msgstr "Задат је опÑег уназад, ОК да Ñе замени"
+
+msgid "E494: Use w or w>>"
+msgstr "E494: КориÑтите w или w>>"
+
+msgid "E943: Command table needs to be updated, run 'make cmdidxs'"
+msgstr "E943: Табела команди мора да Ñе оÑвежи, покрените 'make cmdidxs'"
+
+msgid "E319: Sorry, the command is not available in this version"
+msgstr "E319: Жао нам је, та команда није доÑтупна у овој верзији"
+
+msgid "1 more file to edit. Quit anyway?"
+msgstr "Још 1 датотека за уређивање. Ипак желите да напуÑтите програм?"
+
+#, c-format
+msgid "%d more files to edit. Quit anyway?"
+msgstr "Још %d датотека за уређивање. Ипак желите да напуÑтите програм?"
+
+msgid "E173: 1 more file to edit"
+msgstr "E173: Још 1 датотека за уређивање"
+
+#, c-format
+msgid "E173: %ld more files to edit"
+msgstr "E173: Још %ld датотека за уређивање"
+
+msgid "E174: Command already exists: add ! to replace it"
+msgstr "E174: Команда већ поÑтоји: додајте ! да је замените"
+
+msgid ""
+"\n"
+" Name Args Address Complete Definition"
+msgstr ""
+"\n"
+" Име Ðргум ÐдреÑа Довршење Дефиниција"
+
+msgid "No user-defined commands found"
+msgstr "ÐиÑу пронађене кориÑнички дефиниÑане команде"
+
+msgid "E175: No attribute specified"
+msgstr "E175: Ðије наведен ни један атрибут"
+
+msgid "E176: Invalid number of arguments"
+msgstr "E176: ÐеиÑправан број аргумената"
+
+msgid "E177: Count cannot be specified twice"
+msgstr "E177: Бројач не може да Ñе наведе два пута"
+
+msgid "E178: Invalid default value for count"
+msgstr "E178: ÐеÑправна подразумевана вредноÑÑ‚ за бројач"
+
+msgid "E179: argument required for -complete"
+msgstr "E179: потребан је аргумент за -complete"
+
+msgid "E179: argument required for -addr"
+msgstr "E179: потребан је аргумент за -addr"
+
+#, c-format
+msgid "E181: Invalid attribute: %s"
+msgstr "E181: ÐеиÑправан атрибут: %s"
+
+msgid "E182: Invalid command name"
+msgstr "E182: ÐеиÑправно име команде"
+
+msgid "E183: User defined commands must start with an uppercase letter"
+msgstr "E183: КориÑнички дефиниÑане команде морају да почну великим Ñловом"
+
+msgid "E841: Reserved name, cannot be used for user defined command"
+msgstr ""
+"E841: РезервиÑано име, не може да Ñе кориÑти за кориÑнички дефиниÑану команду"
+
+#, c-format
+msgid "E184: No such user-defined command: %s"
+msgstr "E184: Ðе поÑтоји таква кориÑнички дефиниÑана команда: %s"
+
+#, c-format
+msgid "E180: Invalid address type value: %s"
+msgstr "E180: ÐеиÑправна вредноÑÑ‚ адреÑног типа: %s"
+
+#, c-format
+msgid "E180: Invalid complete value: %s"
+msgstr "E180: ÐеиÑправна вредноÑÑ‚ довршавања: %s"
+
+msgid "E468: Completion argument only allowed for custom completion"
+msgstr "E468: Ðргумент довршавања је дозвољен Ñамо за прилагођена довршавања"
+
+msgid "E467: Custom completion requires a function argument"
+msgstr "E467: Прилагођено довршавање захтева аргумент функције"
+
+msgid "unknown"
+msgstr "непознато"
+
+#, c-format
+msgid "E185: Cannot find color scheme '%s'"
+msgstr "E185: Шема боја '%s' не може да Ñе пронађе"
+
+msgid "Greetings, Vim user!"
+msgstr "Поздрав, кориÑниче Vim-a"
+
+msgid "E784: Cannot close last tab page"
+msgstr "E784: ПоÑледња картица не може да Ñе затвори"
+
+msgid "Already only one tab page"
+msgstr "Већ Ñте на Ñамо једној картици"
+
+msgid "Edit File in new window"
+msgstr "Уређивање Датотеке у новом прозору"
+
+#, c-format
+msgid "Tab page %d"
+msgstr "Картица %d"
+
+msgid "No swap file"
+msgstr "Ðема swap датотеке"
+
+msgid "Append File"
+msgstr "Додавање на крај Датотеке"
+
+msgid "E747: Cannot change directory, buffer is modified (add ! to override)"
+msgstr ""
+"E747: Директоријум не може да Ñе промени, бафер је измењен (додајте ! за "
+"премошћавање)"
+
+msgid "E186: No previous directory"
+msgstr "E186: Ðема претгодног директоријума"
+
+msgid "E187: Unknown"
+msgstr "E187: Ðепознато"
+
+msgid "E465: :winsize requires two number arguments"
+msgstr "E465: :winsize захтева два бројчана аргумента"
+
+#, c-format
+msgid "Window position: X %d, Y %d"
+msgstr "Позиција прозора: X %d, Y %d"
+
+msgid "E188: Obtaining window position not implemented for this platform"
+msgstr "E188: Добављање позиције прозора није имплементирано за ову платформу"
+
+msgid "E466: :winpos requires two number arguments"
+msgstr "E466: :winpos захтева два бројчана аргумента"
+
+msgid "E930: Cannot use :redir inside execute()"
+msgstr "E930: :redir не може да Ñе кориÑти унутар execute()"
+
+msgid "Save Redirection"
+msgstr "Сачувај Редирекцију"
+
+msgid "Save View"
+msgstr "Сачувај Поглед"
+
+msgid "Save Session"
+msgstr "Сачувај СеÑију"
+
+msgid "Save Setup"
+msgstr "Сачувај Подешавање"
+
+#, c-format
+msgid "E739: Cannot create directory: %s"
+msgstr "E739: Директоријум не може да Ñе креира: %s"
+
+#, c-format
+msgid "E189: \"%s\" exists (add ! to override)"
+msgstr "E189: \"%s\" поÑтоји (додајте ! за премошћавање)"
+
+#, c-format
+msgid "E190: Cannot open \"%s\" for writing"
+msgstr "E190: \"%s\" не може да Ñе отвори за упиÑ"
+
+msgid "E191: Argument must be a letter or forward/backward quote"
+msgstr "E191: Ðргумент мора бити Ñлово или апоÑтроф/обрнути апоÑтроф"
+
+msgid "E192: Recursive use of :normal too deep"
+msgstr "E192: Рекурзивно коришћење :normal је Ñувише дубоко"
+
+msgid "E809: #< is not available without the +eval feature"
+msgstr "E809: #< није доÑтупно без +eval могућноÑти"
+
+msgid "E194: No alternate file name to substitute for '#'"
+msgstr "E194: Ðема алтернативног имена које би заменило '#'"
+
+msgid "E495: no autocommand file name to substitute for \"<afile>\""
+msgstr "E495: нема имена датотеке за аутокоманде које би заменило \"<afile>\""
+
+msgid "E496: no autocommand buffer number to substitute for \"<abuf>\""
+msgstr "E496: нема броја бафера за аутокоманду који би заменио \"<abuf>\""
+
+msgid "E497: no autocommand match name to substitute for \"<amatch>\""
+msgstr "E497: нема имена подударања аутокоманде које би заменило \"<amatch>\""
+
+msgid "E498: no :source file name to substitute for \"<sfile>\""
+msgstr "E498: нема имена :source датотеке које би заменило \"<sfile>\""
+
+msgid "E842: no line number to use for \"<slnum>\""
+msgstr "E842: нема броја линије који би Ñе кориÑтио за \"<slnum>\""
+
+#, no-c-format
+msgid "E499: Empty file name for '%' or '#', only works with \":p:h\""
+msgstr "E499: Празно име датотеке за'%' or '#', функционише Ñамо Ñа \":p:h\""
+
+msgid "E500: Evaluates to an empty string"
+msgstr "E500: Резултат израчунавања је празан Ñтринг"
+
+msgid "E195: Cannot open viminfo file for reading"
+msgstr "E195: viminfo датотека не може да Ñе отвори за читање"
+
+msgid "Untitled"
+msgstr "Без наÑлова"
+
+msgid "E196: No digraphs in this version"
+msgstr "E196: У овој верзији нема диграфа"
+
+msgid "E608: Cannot :throw exceptions with 'Vim' prefix"
+msgstr "E608: :throw изузетка Ñа 'Vim' префикÑом није дозвољен"
+
+#, c-format
+msgid "Exception thrown: %s"
+msgstr "Бачен је изузетак: %s"
+
+#, c-format
+msgid "Exception finished: %s"
+msgstr "Изузетак је завршен: %s"
+
+#, c-format
+msgid "Exception discarded: %s"
+msgstr "Изузетак је одбачен: %s"
+
+#, c-format
+msgid "%s, line %ld"
+msgstr "%s, линија %ld"
+
+#, c-format
+msgid "Exception caught: %s"
+msgstr "Изузетак је ухваћен: %s"
+
+#, c-format
+msgid "%s made pending"
+msgstr "%s је Ñтављен на чекање"
+
+#, c-format
+msgid "%s resumed"
+msgstr "%s је поново активан"
+
+#, c-format
+msgid "%s discarded"
+msgstr "%s је одбачен"
+
+msgid "Exception"
+msgstr "Изузетак"
+
+msgid "Error and interrupt"
+msgstr "Грешка и прекид"
+
+msgid "Error"
+msgstr "Грешка"
+
+msgid "Interrupt"
+msgstr "Прекид"
+
+msgid "E579: :if nesting too deep"
+msgstr "E579: :if угњеждавање је Ñувише дубоко"
+
+msgid "E580: :endif without :if"
+msgstr "E580: :endif без :if"
+
+msgid "E581: :else without :if"
+msgstr "E581: :else без :if"
+
+msgid "E582: :elseif without :if"
+msgstr "E582: :elseif без :if"
+
+msgid "E583: multiple :else"
+msgstr "E583: вишеÑтруко :else"
+
+msgid "E584: :elseif after :else"
+msgstr "E584: :elseif након :else"
+
+msgid "E585: :while/:for nesting too deep"
+msgstr "E585: :while/:for угњеждавање је Ñувише дубоко"
+
+msgid "E586: :continue without :while or :for"
+msgstr "E586: :continue без :while или :for"
+
+msgid "E587: :break without :while or :for"
+msgstr "E587: :break без :while или :for"
+
+msgid "E732: Using :endfor with :while"
+msgstr "E732: Коришћење :endfor Ñа :while"
+
+msgid "E733: Using :endwhile with :for"
+msgstr "E733: Коришћење :endwhile Ñа :for"
+
+msgid "E601: :try nesting too deep"
+msgstr "E601: :try угњеждавање је Ñувише дубоко"
+
+msgid "E603: :catch without :try"
+msgstr "E603: :catch без :try"
+
+msgid "E604: :catch after :finally"
+msgstr "E604: :catch након :finally"
+
+msgid "E606: :finally without :try"
+msgstr "E606: :finally без :try"
+
+msgid "E607: multiple :finally"
+msgstr "E607: вишеÑтруко :finally"
+
+msgid "E602: :endtry without :try"
+msgstr "E602: :endtry без :try"
+
+msgid "E193: :endfunction not inside a function"
+msgstr "E193: :endfunction није унутар функције"
+
+msgid "E788: Not allowed to edit another buffer now"
+msgstr "E788: Уређивање другог бафера тренутно није дозвољено"
+
+msgid "E811: Not allowed to change buffer information now"
+msgstr "E811: Мењање информација о баферу тренутно није дозвољено"
+
+msgid "tagname"
+msgstr "ознака"
+
+msgid " kind file\n"
+msgstr " врÑта датотеке\n"
+
+msgid "'history' option is zero"
+msgstr "опција 'history' је нула"
+
+#, c-format
+msgid ""
+"\n"
+"# %s History (newest to oldest):\n"
+msgstr ""
+"\n"
+"# %s ИÑторија (од најновијег ка најÑтаријем):\n"
+
+msgid "Command Line"
+msgstr "Командна линија"
+
+msgid "Search String"
+msgstr "Стринг за претрагу"
+
+msgid "Expression"
+msgstr "Израз"
+
+msgid "Input Line"
+msgstr "Линија за уноÑ"
+
+msgid "Debug Line"
+msgstr "Debug линија"
+
+msgid "E198: cmd_pchar beyond the command length"
+msgstr "E198: cmd_pchar је иза дужине команде"
+
+msgid "E199: Active window or buffer deleted"
+msgstr "E199: Active window or buffer deleted"
+
+msgid "E812: Autocommands changed buffer or buffer name"
+msgstr "E812: Ðутокоманде Ñу промениле багер или име бафера"
+
+msgid "Illegal file name"
+msgstr "Ðедозвољено име датотеке"
+
+msgid "is a directory"
+msgstr "је директоријум"
+
+msgid "is not a file"
+msgstr "није датотека"
+
+msgid "is a device (disabled with 'opendevice' option)"
+msgstr "је уређај (онемогућен опцијом 'opendevice')"
+
+msgid "[New File]"
+msgstr "[Ðова датотека]"
+
+msgid "[New DIRECTORY]"
+msgstr "[Ðов ДИРЕКТОРИЈУМ]"
+
+msgid "[File too big]"
+msgstr "[Датотека је Ñувише велика]"
+
+msgid "[Permission Denied]"
+msgstr "[Дозвола одбијена]"
+
+msgid "E200: *ReadPre autocommands made the file unreadable"
+msgstr "E200: *ReadPre аутокоманде Ñу учиниле датотеку нечитљивом"
+
+msgid "E201: *ReadPre autocommands must not change current buffer"
+msgstr "E201: *ReadPre аутокоманде не Ñмеју да измене текући бафер"
+
+msgid "Vim: Reading from stdin...\n"
+msgstr "Vim: Читање Ñа stdin...\n"
+
+msgid "Reading from stdin..."
+msgstr "Читање Ñа stdin..."
+
+msgid "E202: Conversion made file unreadable!"
+msgstr "E202: Конверзија је учинила датотеку нечитљивом!"
+
+msgid "[fifo/socket]"
+msgstr "[fifo/утичница]"
+
+msgid "[fifo]"
+msgstr "[fifo]"
+
+msgid "[socket]"
+msgstr "[утичница]"
+
+msgid "[character special]"
+msgstr "[Ñпецијални карактер]"
+
+msgid "[CR missing]"
+msgstr "[недоÑтаје CR]"
+
+msgid "[long lines split]"
+msgstr "[дуге линије преломљене]"
+
+msgid "[NOT converted]"
+msgstr "[ÐИЈЕ конвертовано]"
+
+msgid "[converted]"
+msgstr "[конвертовано]"
+
+#, c-format
+msgid "[CONVERSION ERROR in line %ld]"
+msgstr "[ГРЕШКРКОÐВЕРЗИЈЕ у линији %ld]"
+
+#, c-format
+msgid "[ILLEGAL BYTE in line %ld]"
+msgstr "[ÐЕДОЗВОЉЕРБÐЈТ у линији %ld]"
+
+msgid "[READ ERRORS]"
+msgstr "[ГРЕШКЕ ПРИ ЧИТÐЊУ]"
+
+msgid "Can't find temp file for conversion"
+msgstr "Привремена датотека за конверзију не може да Ñе пронађе"
+
+msgid "Conversion with 'charconvert' failed"
+msgstr "Конверзија Ñа 'charconvert' није уÑпела"
+
+msgid "can't read output of 'charconvert'"
+msgstr "излаз 'charconvert' не може да Ñе прочита"
+
+msgid "E676: No matching autocommands for acwrite buffer"
+msgstr "E676: Ðема одговарајућих аутокоманди за acwrite бафер"
+
+msgid "E203: Autocommands deleted or unloaded buffer to be written"
+msgstr ""
+"E203: Ðутокоманде Ñу обриÑале или уклониле из меморије бафер који требало да "
+"буде упиÑан"
+
+msgid "E204: Autocommand changed number of lines in unexpected way"
+msgstr "E204: Ðутокоманде Ñу на неочекиван начин промениле број линија"
+
+msgid "NetBeans disallows writes of unmodified buffers"
+msgstr "NetBeans не дозвољава ÑƒÐ¿Ð¸Ñ Ð½ÐµÐ¸Ð·Ð¼ÐµÑšÐµÐ½Ð¸Ñ… бафера"
+
+msgid "Partial writes disallowed for NetBeans buffers"
+msgstr "Парцијални упиÑи ниÑу дозвољени за NetBeans бафере"
+
+msgid "is not a file or writable device"
+msgstr "није датотека или уређај на који може да Ñе упиÑује"
+
+msgid "writing to device disabled with 'opendevice' option"
+msgstr "ÑƒÐ¿Ð¸Ñ Ð½Ð° уређај је онемогућен опцијом 'opendevice'"
+
+msgid "is read-only (add ! to override)"
+msgstr "је Ñамо за читање (додајте ! за премошћавање)"
+
+msgid "E506: Can't write to backup file (add ! to override)"
+msgstr ""
+"E506: Ðе може да Ñе упише у резервну датотеку (додајте ! за премошћавање)"
+
+msgid "E507: Close error for backup file (add ! to override)"
+msgstr ""
+"E507: Грешка код затварања за резервну датотеку (додајте ! за премошћавање)"
+
+msgid "E508: Can't read file for backup (add ! to override)"
+msgstr ""
+"E508: Резервна датотека не може да Ñе прочита (додајте ! за премошћавање)"
+
+msgid "E509: Cannot create backup file (add ! to override)"
+msgstr ""
+"E509: Резервна датотека не може да Ñе креира (додајте ! за премошћавање)"
+
+msgid "E510: Can't make backup file (add ! to override)"
+msgstr ""
+"E510: Резервна датотека не може да Ñе направи (додајте ! за премошћавање)"
+
+msgid "E214: Can't find temp file for writing"
+msgstr "E214: Привремена датотека за ÑƒÐ¿Ð¸Ñ Ð½Ðµ може да Ñе пронађе"
+
+msgid "E213: Cannot convert (add ! to write without conversion)"
+msgstr "E213: Конверзија није могућа (додајте ! за ÑƒÐ¿Ð¸Ñ Ð±ÐµÐ· конверзије)"
+
+msgid "E166: Can't open linked file for writing"
+msgstr "E166: Повезана датотека не може да Ñе отвори за упиÑ"
+
+msgid "E212: Can't open file for writing"
+msgstr "E212: Датотека не може да Ñе отвори за упиÑ"
+
+msgid "E949: File changed while writing"
+msgstr "E949: Датотека је промењена током упиÑа"
+
+msgid "E512: Close failed"
+msgstr "E512: Затварање није уÑпело"
+
+msgid "E513: write error, conversion failed (make 'fenc' empty to override)"
+msgstr ""
+"E513: грешка при упиÑу, конверзија није уÑпела (оÑтавите 'fenc' празно да "
+"премоÑтите)"
+
+#, c-format
+msgid ""
+"E513: write error, conversion failed in line %ld (make 'fenc' empty to "
+"override)"
+msgstr ""
+"E513: грешка при упиÑу, конверзија није уÑпела у линији %ld (оÑтавите 'fenc' "
+"празно да премоÑтите)"
+
+msgid "E514: write error (file system full?)"
+msgstr "E514: грешка при упиÑу (ÑиÑтем датотека је пун?)"
+
+msgid " CONVERSION ERROR"
+msgstr " ГРЕШКРКОÐВЕРЗИЈЕ"
+
+#, c-format
+msgid " in line %ld;"
+msgstr " у линији %ld;"
+
+msgid "[Device]"
+msgstr "[Уређај]"
+
+msgid "[New]"
+msgstr "[Ðово]"
+
+msgid " [a]"
+msgstr " [н]"
+
+msgid " appended"
+msgstr " наÑтављено"
+
+msgid " [w]"
+msgstr " [у]"
+
+msgid " written"
+msgstr " упиÑано"
+
+msgid "E205: Patchmode: can't save original file"
+msgstr "E205: Patch режим: оригинална датотека не може да Ñе Ñачува"
+
+msgid "E206: patchmode: can't touch empty original file"
+msgstr "E206: Patch режим: не може да Ñе креира празна оригинална датотека"
+
+msgid "E207: Can't delete backup file"
+msgstr "E207: Резервна датотека не може да Ñе обрише"
+
+msgid ""
+"\n"
+"WARNING: Original file may be lost or damaged\n"
+msgstr ""
+"\n"
+"УПОЗОРЕЊЕ: Оригинална датотека је можда изгубљена или оштећена\n"
+
+msgid "don't quit the editor until the file is successfully written!"
+msgstr "не напуштајте едитор док Ñе датотека уÑпешно не упише!"
+
+msgid "[dos]"
+msgstr "[dos]"
+
+msgid "[dos format]"
+msgstr "[dos формат]"
+
+msgid "[mac]"
+msgstr "[mac]"
+
+msgid "[mac format]"
+msgstr "[mac формат]"
+
+msgid "[unix]"
+msgstr "[unix]"
+
+msgid "[unix format]"
+msgstr "[unix формат]"
+
+msgid "1 line, "
+msgstr "1 линија, "
+
+#, c-format
+msgid "%ld lines, "
+msgstr "%ld линија, "
+
+msgid "1 character"
+msgstr "1 карактер"
+
+#, c-format
+msgid "%lld characters"
+msgstr "%lld карактера"
+
+msgid "[noeol]"
+msgstr "[noeol]"
+
+msgid "[Incomplete last line]"
+msgstr "[ПоÑледња линија није комплетна]"
+
+msgid "WARNING: The file has been changed since reading it!!!"
+msgstr "УПОЗОРЕЊЕ: Ова датотека је промењена од кад је прочитана!!!"
+
+msgid "Do you really want to write to it"
+msgstr "Да ли заиÑта желите да пишете у њу"
+
+#, c-format
+msgid "E208: Error writing to \"%s\""
+msgstr "E208: Грешка при упиÑу у \"%s\""
+
+#, c-format
+msgid "E209: Error closing \"%s\""
+msgstr "E209: Грешка при затварању \"%s\""
+
+#, c-format
+msgid "E210: Error reading \"%s\""
+msgstr "E210: Грешка при читању \"%s\""
+
+msgid "E246: FileChangedShell autocommand deleted buffer"
+msgstr "E246: FileChangedShell аутокоманда је обриÑала бафер"
+
+#, c-format
+msgid "E211: File \"%s\" no longer available"
+msgstr "E211: Датотека \"%s\" више није доÑтупна"
+
+#, c-format
+msgid ""
+"W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as "
+"well"
+msgstr ""
+"W12: Упозорење: Датотека \"%s\" је измењена и бафер у програму Vim је такође "
+"измењен"
+
+msgid "See \":help W12\" for more info."
+msgstr "Погледајте \":help W12\" за више информација."
+
+#, c-format
+msgid "W11: Warning: File \"%s\" has changed since editing started"
+msgstr ""
+"W11: Упозорење: Датотека \"%s\" је измењена откад је започето уређивање"
+
+msgid "See \":help W11\" for more info."
+msgstr "Погледајте \":help W11\" за више информација."
+
+#, c-format
+msgid "W16: Warning: Mode of file \"%s\" has changed since editing started"
+msgstr ""
+"W16: Упозорење: Режим датотеке \"%s\" је измењен откад је започето уређивање"
+
+msgid "See \":help W16\" for more info."
+msgstr "Погледајте \":help W16\" за више информација."
+
+#, c-format
+msgid "W13: Warning: File \"%s\" has been created after editing started"
+msgstr "W13: Упозорење: Датотека \"%s\" је креирана након почетка уређивања"
+
+msgid "Warning"
+msgstr "Упозорење"
+
+msgid ""
+"&OK\n"
+"&Load File"
+msgstr ""
+"&OK\n"
+"&Учитај датотеку"
+
+#, c-format
+msgid "E462: Could not prepare for reloading \"%s\""
+msgstr "E462: Припрема за поновно учитавање \"%s\" није била могућа"
+
+#, c-format
+msgid "E321: Could not reload \"%s\""
+msgstr "E321: \"%s\" не може поново да Ñе учита"
+
+msgid "--Deleted--"
+msgstr "--ОбриÑано--"
+
+#, c-format
+msgid "auto-removing autocommand: %s <buffer=%d>"
+msgstr "ауто-уклањајућа аутокоманда: %s <бафер=%d>"
+
+#, c-format
+msgid "E367: No such group: \"%s\""
+msgstr "E367: Ðема такве групе: \"%s\""
+
+msgid "E936: Cannot delete the current group"
+msgstr "E936: Текућа група не може да Ñе обрише"
+
+msgid "W19: Deleting augroup that is still in use"
+msgstr "W19: БриÑање augroup која је још у употреби"
+
+#, c-format
+msgid "E215: Illegal character after *: %s"
+msgstr "E215: Ðедозвољени карактер након *: %s"
+
+#, c-format
+msgid "E216: No such event: %s"
+msgstr "E216: Ðема таквог догађаја: %s"
+
+#, c-format
+msgid "E216: No such group or event: %s"
+msgstr "E216: Ðема такве групе или догађаја: %s"
+
+msgid ""
+"\n"
+"--- Autocommands ---"
+msgstr ""
+"\n"
+"--- Ðутокоманде ---"
+
+#, c-format
+msgid "E680: <buffer=%d>: invalid buffer number "
+msgstr "E680: <бафер=%d>: неиÑправан број бафера "
+
+msgid "E217: Can't execute autocommands for ALL events"
+msgstr "E217: Ðутокоманде за СВЕ догађаје не могу да Ñе изврше"
+
+msgid "No matching autocommands"
+msgstr "Ðема подударајућих аутокоманди"
+
+msgid "E218: autocommand nesting too deep"
+msgstr "E218: Угњеждавање аутокоманде је Ñувише дубоко"
+
+#, c-format
+msgid "%s Autocommands for \"%s\""
+msgstr "%s Ðутокоманде за \"%s\""
+
+#, c-format
+msgid "Executing %s"
+msgstr "Извршавање %s"
+
+#, c-format
+msgid "autocommand %s"
+msgstr "аутокоманда %s"
+
+msgid "E219: Missing {."
+msgstr "E219: ÐедоÑтаје {."
+
+msgid "E220: Missing }."
+msgstr "E220: ÐедоÑтаје }."
+
+msgid "E490: No fold found"
+msgstr "E490: Ðије пронађено ниједно Ñклапање"
+
+msgid "E350: Cannot create fold with current 'foldmethod'"
+msgstr "E350: Склапање не може да Ñе креира Ñа текућим 'foldmethod'"
+
+msgid "E351: Cannot delete fold with current 'foldmethod'"
+msgstr "E351: Склапање не може да Ñе обрише Ñа текћим 'foldmethod'"
+
+#, c-format
+msgid "+--%3ld line folded "
+msgid_plural "+--%3ld lines folded "
+msgstr[0] "+--%3ld линија подвијена"
+msgstr[1] "+--%3ld линија подвијено"
+
+msgid "E222: Add to read buffer"
+msgstr "E222: Додавање у бафер читања"
+
+msgid "E223: recursive mapping"
+msgstr "E223: рекурзивно мапирање"
+
+#, c-format
+msgid "E224: global abbreviation already exists for %s"
+msgstr "E224: глобална Ñкраћеница за %s већ поÑтоји"
+
+#, c-format
+msgid "E225: global mapping already exists for %s"
+msgstr "E225: глобално мапирање за %s већ поÑтоји"
+
+#, c-format
+msgid "E226: abbreviation already exists for %s"
+msgstr "E226: Ñкраћеница за %s већ поÑтоји"
+
+#, c-format
+msgid "E227: mapping already exists for %s"
+msgstr "E227: мапирање за %s већ поÑтоји"
+
+msgid "No abbreviation found"
+msgstr "Скраћеница није пронађена"
+
+msgid "No mapping found"
+msgstr "Мапирање није пронађено"
+
+msgid "E228: makemap: Illegal mode"
+msgstr "E228: makemap: Ðедозвољен режим"
+
+msgid "E851: Failed to create a new process for the GUI"
+msgstr "E851: Креирање новог процеÑа за GUI није уÑпело"
+
+msgid "E852: The child process failed to start the GUI"
+msgstr "E852: ÐŸÑ€Ð¾Ñ†ÐµÑ Ð¿Ð¾Ñ‚Ð¾Ð¼Ð°Ðº није уÑпео да покрене GUI"
+
+msgid "E229: Cannot start the GUI"
+msgstr "E229: GUI не може да Ñе покрене"
+
+#, c-format
+msgid "E230: Cannot read from \"%s\""
+msgstr "E230: Из \"%s\" не може да Ñе чита"
+
+msgid "E665: Cannot start GUI, no valid font found"
+msgstr "E665: GUI не може да Ñе покрене, није пронађен валидан фонт"
+
+msgid "E231: 'guifontwide' invalid"
+msgstr "E231: 'guifontwide' неиÑправан"
+
+msgid "E599: Value of 'imactivatekey' is invalid"
+msgstr "E599: ВредноÑÑ‚ 'imactivatekey' није иÑправна"
+
+#, c-format
+msgid "E254: Cannot allocate color %s"
+msgstr "E254: Боја %s не може да Ñе алоцира"
+
+msgid "No match at cursor, finding next"
+msgstr "Ðема подударања на меÑту курÑора, тражи Ñе даље"
+
+msgid "<cannot open> "
+msgstr "<не може да Ñе отвори> "
+
+#, c-format
+msgid "E616: vim_SelFile: can't get font %s"
+msgstr "E616: vim_SelFile: не може да Ñе добије фонт %s"
+
+msgid "E614: vim_SelFile: can't return to current directory"
+msgstr "E614: vim_SelFile: повратак у текући директоријум није могућ"
+
+msgid "Pathname:"
+msgstr "Име путање:"
+
+msgid "E615: vim_SelFile: can't get current directory"
+msgstr "E615: vim_SelFile: не може да Ñе добије текући директоријум"
+
+msgid "OK"
+msgstr "ОК"
+
+msgid "Cancel"
+msgstr "Откажи"
+
+msgid "Scrollbar Widget: Could not get geometry of thumb pixmap."
+msgstr "Scrollbar Widget: Ðе може да Ñе добије геометрија thumb pixmap."
+
+msgid "Vim dialog"
+msgstr "Vim дијалог"
+
+msgid "E232: Cannot create BalloonEval with both message and callback"
+msgstr ""
+"E232: Ðе може да Ñе креира BalloonEval и Ñа поруком и Ñа повратним позивом"
+
+msgid "_Cancel"
+msgstr "_Откажи"
+
+msgid "_Save"
+msgstr "_Сачувај"
+
+msgid "_Open"
+msgstr "_Отвори"
+
+msgid "_OK"
+msgstr "_OK"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"&Cancel"
+msgstr ""
+"&Да\n"
+"&Ðе\n"
+"&Откажи"
+
+msgid "Yes"
+msgstr "Да"
+
+msgid "No"
+msgstr "Ðе"
+
+msgid "Input _Methods"
+msgstr "_Методе уноÑа"
+
+msgid "VIM - Search and Replace..."
+msgstr "VIM - Претрага and Замена..."
+
+msgid "VIM - Search..."
+msgstr "VIM - Претрага..."
+
+msgid "Find what:"
+msgstr "Пронађи:"
+
+msgid "Replace with:"
+msgstr "Замени Ñа:"
+
+msgid "Match whole word only"
+msgstr "Само целе речи подударају"
+
+msgid "Match case"
+msgstr "Мала/велика Ñлова"
+
+msgid "Direction"
+msgstr "Смер"
+
+msgid "Up"
+msgstr "Горе"
+
+msgid "Down"
+msgstr "Доле"
+
+msgid "Find Next"
+msgstr "Пронађи наредно"
+
+msgid "Replace"
+msgstr "Замени"
+
+msgid "Replace All"
+msgstr "Замени Ñве"
+
+msgid "_Close"
+msgstr "_Затвори"
+
+msgid "Vim: Received \"die\" request from session manager\n"
+msgstr "Vim: Примљен је \"die\" захтев од менаџера ÑеÑије\n"
+
+msgid "Close tab"
+msgstr "Затвори картицу"
+
+msgid "New tab"
+msgstr "Ðова картица"
+
+msgid "Open Tab..."
+msgstr "Отвори картицу..."
+
+msgid "Vim: Main window unexpectedly destroyed\n"
+msgstr "Vim: Главни прозор је неочекивано уништен\n"
+
+msgid "&Filter"
+msgstr "&Филтер"
+
+msgid "&Cancel"
+msgstr "&Откажи"
+
+msgid "Directories"
+msgstr "Директоријуми"
+
+msgid "Filter"
+msgstr "Филтер"
+
+msgid "&Help"
+msgstr "&Помоћ"
+
+msgid "Files"
+msgstr "Датотеке"
+
+msgid "&OK"
+msgstr "&ОК"
+
+msgid "Selection"
+msgstr "Селекција"
+
+msgid "Find &Next"
+msgstr "Пронађи &Следеће"
+
+msgid "&Replace"
+msgstr "&Замени"
+
+msgid "Replace &All"
+msgstr "Замени Ñ&Ве"
+
+msgid "&Undo"
+msgstr "О&позови"
+
+msgid "Open tab..."
+msgstr "Отвори картицу"
+
+msgid "Find string (use '\\\\' to find a '\\')"
+msgstr "Пронађи Ñтринг (кориÑтите '\\\\' да пронађете '\\')"
+
+msgid "Find & Replace (use '\\\\' to find a '\\')"
+msgstr "Пронађи & Замени (кориÑтите '\\\\' да пронађете '\\')"
+
+msgid "Not Used"
+msgstr "Ðе кориÑти Ñе"
+
+msgid "Directory\t*.nothing\n"
+msgstr "Директоријум\t*.ништа\n"
+
+#, c-format
+msgid "E671: Cannot find window title \"%s\""
+msgstr "E671: ÐаÑлов прозора \"%s\" не може да Ñе пронађе"
+
+#, c-format
+msgid "E243: Argument not supported: \"-%s\"; Use the OLE version."
+msgstr "E243: Ðргумент није подржан: \"-%s\"; КориÑтите OLE верзију."
+
+msgid "E672: Unable to open window inside MDI application"
+msgstr "E672: Ðије могуће отварање прозора унутар MDI апликације"
+
+msgid "Vim E458: Cannot allocate colormap entry, some colors may be incorrect"
+msgstr ""
+"Vim E458: colormap ÑƒÐ½Ð¾Ñ Ð½Ðµ може да Ñе алоцира, неке боје Ñу можда неиÑправне"
+
+#, c-format
+msgid "E250: Fonts for the following charsets are missing in fontset %s:"
+msgstr "E250: Фонтови за Ñледеће Ñетове карактера недоÑтају у фонтÑету %s:"
+
+#, c-format
+msgid "E252: Fontset name: %s"
+msgstr "E252: Име фонтÑета: %s"
+
+#, c-format
+msgid "Font '%s' is not fixed-width"
+msgstr "Фонт %s' није фикÑне ширине"
+
+#, c-format
+msgid "E253: Fontset name: %s"
+msgstr "E253: Име фонтÑета: %s"
+
+#, c-format
+msgid "Font0: %s"
+msgstr "Фонт0: %s"
+
+#, c-format
+msgid "Font1: %s"
+msgstr "Фонт1: %s"
+
+#, c-format
+msgid "Font%ld width is not twice that of font0"
+msgstr "Ширина фонт%ld није двоÑтрука од ширине фонт0"
+
+#, c-format
+msgid "Font0 width: %ld"
+msgstr "Фонт0 ширина: %ld"
+
+#, c-format
+msgid "Font1 width: %ld"
+msgstr "Фонт1 ширина: %ld"
+
+msgid "Invalid font specification"
+msgstr "ÐеиÑправна Ñпецификација фонта"
+
+msgid "&Dismiss"
+msgstr "О&дбаци"
+
+msgid "no specific match"
+msgstr "нема поÑебног подударања"
+
+msgid "Vim - Font Selector"
+msgstr "Vim - Фонт Ñелектор"
+
+msgid "Name:"
+msgstr "Име:"
+
+msgid "Show size in Points"
+msgstr "Прикажи величину у Тачкама"
+
+msgid "Encoding:"
+msgstr "Кодирање:"
+
+msgid "Font:"
+msgstr "Фонт:"
+
+msgid "Style:"
+msgstr "Стил:"
+
+msgid "Size:"
+msgstr "Величина:"
+
+msgid "E256: Hangul automata ERROR"
+msgstr "E256: ГРЕШКРHangul аутомата"
+
+msgid "E550: Missing colon"
+msgstr "E550: ÐедоÑтаје двотачка"
+
+msgid "E551: Illegal component"
+msgstr "E551: ÐеиÑправна компонента"
+
+msgid "E552: digit expected"
+msgstr "E552: очекује Ñе цифра"
+
+#, c-format
+msgid "Page %d"
+msgstr "Страна %d"
+
+msgid "No text to be printed"
+msgstr "Ðема текÑта за штампу"
+
+#, c-format
+msgid "Printing page %d (%d%%)"
+msgstr "Штампање Ñтране %d (%d%%)"
+
+#, c-format
+msgid " Copy %d of %d"
+msgstr " Копија %d од %d"
+
+#, c-format
+msgid "Printed: %s"
+msgstr "Одштампано: %s"
+
+msgid "Printing aborted"
+msgstr "Штампање прекинуто"
+
+msgid "E455: Error writing to PostScript output file"
+msgstr "E455: Грешка приликом упиÑа у PostScript излазну датотеку"
+
+#, c-format
+msgid "E624: Can't open file \"%s\""
+msgstr "E624: Датотека \"%s\" не може да Ñе отвори"
+
+#, c-format
+msgid "E457: Can't read PostScript resource file \"%s\""
+msgstr "E457: PostScript resource датотека \"%s\" не може да Ñе чита"
+
+#, c-format
+msgid "E618: file \"%s\" is not a PostScript resource file"
+msgstr "E618: датотека \"%s\" није PostScript resource датотека"
+
+#, c-format
+msgid "E619: file \"%s\" is not a supported PostScript resource file"
+msgstr "E619: датотека \"%s\" није подржана PostScript resource датотека"
+
+#, c-format
+msgid "E621: \"%s\" resource file has wrong version"
+msgstr "E621: \"%s\" resource датотека је погрешне верзије"
+
+msgid "E673: Incompatible multi-byte encoding and character set."
+msgstr "E673: Вишебајтно кодирање и Ñкуп карактера ниÑу компатибилни."
+
+msgid "E674: printmbcharset cannot be empty with multi-byte encoding."
+msgstr "E674: printmbcharset не може бити празно Ñа вишебајтним кодирањем."
+
+msgid "E675: No default font specified for multi-byte printing."
+msgstr "E675: Ðије наведен подразумевани фонт за вишебајтно штампање."
+
+msgid "E324: Can't open PostScript output file"
+msgstr "E324: PostScript излазна датотека не може да Ñе отвори"
+
+#, c-format
+msgid "E456: Can't open file \"%s\""
+msgstr "E456: Датотека \"%s\" не може да Ñе отвори"
+
+msgid "E456: Can't find PostScript resource file \"prolog.ps\""
+msgstr "E456: PostScript resource датотека \"prolog.ps\" не може да Ñе пронађе"
+
+msgid "E456: Can't find PostScript resource file \"cidfont.ps\""
+msgstr ""
+"E456: PostScript resource датотека \"cidfont.ps\" не може да Ñе пронађе"
+
+#, c-format
+msgid "E456: Can't find PostScript resource file \"%s.ps\""
+msgstr "E456: PostScript resource датотека \"%s.ps\" не може да Ñе пронађе"
+
+#, c-format
+msgid "E620: Unable to convert to print encoding \"%s\""
+msgstr "E620: Ðије могућа конверзија у кодирање за штампу \"%s\""
+
+msgid "Sending to printer..."
+msgstr "Слање штампачу..."
+
+msgid "E365: Failed to print PostScript file"
+msgstr "E365: PostScript датотека није уÑпела да Ñе одштампа"
+
+msgid "Print job sent."
+msgstr "Задатак штампе је поÑлат"
+
+msgid "Add a new database"
+msgstr "Додај нову базу"
+
+msgid "Query for a pattern"
+msgstr "Упит за шаблон"
+
+msgid "Show this message"
+msgstr "Прикажи ову поруку"
+
+msgid "Kill a connection"
+msgstr "Затвори везу"
+
+msgid "Reinit all connections"
+msgstr "Поново иницијализуј Ñве везе"
+
+msgid "Show connections"
+msgstr "Прикажи везе"
+
+#, c-format
+msgid "E560: Usage: cs[cope] %s"
+msgstr "E560: Употреба: cs[cope] %s"
+
+msgid "This cscope command does not support splitting the window.\n"
+msgstr "Ова cscope команда не подржава поделу прозора.\n"
+
+msgid "E562: Usage: cstag <ident>"
+msgstr "E562: Употреба: cstag <ident>"
+
+msgid "E257: cstag: tag not found"
+msgstr "E257: cstag: ознака није пронађена"
+
+#, c-format
+msgid "E563: stat(%s) error: %d"
+msgstr "E563: stat(%s) грешка: %d"
+
+msgid "E563: stat error"
+msgstr "E563: stat грешка"
+
+#, c-format
+msgid "E564: %s is not a directory or a valid cscope database"
+msgstr "E564: %s није директоријум или валидна cscope база података"
+
+#, c-format
+msgid "Added cscope database %s"
+msgstr "cscope база података %s је додата"
+
+#, c-format
+msgid "E262: error reading cscope connection %ld"
+msgstr "E262: грешка код читања cscope везе %ld"
+
+msgid "E561: unknown cscope search type"
+msgstr "E561: непознат cscope тип претраге"
+
+msgid "E566: Could not create cscope pipes"
+msgstr "E566: cscope процеÑни токови ниÑу могли да Ñе креирају"
+
+msgid "E622: Could not fork for cscope"
+msgstr "E622: Рачвање за cscope није уÑпело"
+
+msgid "cs_create_connection setpgid failed"
+msgstr "cs_create_connection setpgid није уÑпео"
+
+msgid "cs_create_connection exec failed"
+msgstr "cs_create_connection exec није уÑпео"
+
+msgid "cs_create_connection: fdopen for to_fp failed"
+msgstr "cs_create_connection: fdopen за to_fp није уÑпео"
+
+msgid "cs_create_connection: fdopen for fr_fp failed"
+msgstr "cs_create_connection: fdopen за fr_fp није уÑпео"
+
+msgid "E623: Could not spawn cscope process"
+msgstr "E623: Мрешћење cscope процеÑа није уÑпело"
+
+msgid "E567: no cscope connections"
+msgstr "E567: нема cscope веза"
+
+#, c-format
+msgid "E469: invalid cscopequickfix flag %c for %c"
+msgstr "E469: неиÑправан cscopequickfix индикатор %c за %c"
+
+#, c-format
+msgid "E259: no matches found for cscope query %s of %s"
+msgstr "E259: ниÑу пронађена подударања за cscope упит %s на %s"
+
+msgid "cscope commands:\n"
+msgstr "cscope команде:\n"
+
+#, c-format
+msgid "%-5s: %s%*s (Usage: %s)"
+msgstr "%-5s: %s%*s (Употреба: %s)"
+
+msgid ""
+"\n"
+" a: Find assignments to this symbol\n"
+" c: Find functions calling this function\n"
+" d: Find functions called by this function\n"
+" e: Find this egrep pattern\n"
+" f: Find this file\n"
+" g: Find this definition\n"
+" i: Find files #including this file\n"
+" s: Find this C symbol\n"
+" t: Find this text string\n"
+msgstr ""
+"\n"
+" a: Пронађи доделе овом Ñимболу\n"
+" c: Пронађи функције које позивају ову функцију\n"
+" d: Пронађи функције које зове ова функција\n"
+" e: Пронађи овај egrep шаблон\n"
+" f: Пронађи ову датотеку\n"
+" g: Пронађи ову дефиницију\n"
+" i: Пронађи датотеке које #includе ову датотеку\n"
+" s: Пронађи овај C Ñимбол\n"
+" t: Пронађи овај текÑÑ‚ Ñтринг\n"
+
+#, c-format
+msgid "E625: cannot open cscope database: %s"
+msgstr "E625: cscope database: %s не може да Ñе отвори"
+
+msgid "E626: cannot get cscope database information"
+msgstr "E626: Инфорамције о cscope бази података не могу да Ñе добију"
+
+msgid "E568: duplicate cscope database not added"
+msgstr "E568: Дупликат cscope база података није додата"
+
+#, c-format
+msgid "E261: cscope connection %s not found"
+msgstr "E261: cscope веза %s није пронађена"
+
+#, c-format
+msgid "cscope connection %s closed"
+msgstr "cscope веза %s је затворена"
+
+msgid "E570: fatal error in cs_manage_matches"
+msgstr "E570: фатална грешка у cs_manage_matches"
+
+#, c-format
+msgid "Cscope tag: %s"
+msgstr "Cscope ознака: %s"
+
+msgid ""
+"\n"
+" # line"
+msgstr ""
+"\n"
+" # линија"
+
+msgid "filename / context / line\n"
+msgstr "датотека / контекÑÑ‚ / линија\n"
+
+#, c-format
+msgid "E609: Cscope error: %s"
+msgstr "E609: Cscope грешка: %s"
+
+msgid "All cscope databases reset"
+msgstr "Све cscope базе података реÑетоване"
+
+msgid "no cscope connections\n"
+msgstr "нема cscope веза\n"
+
+msgid " # pid database name prepend path\n"
+msgstr " # pid име базе података додај путању иÑпред\n"
+
+msgid "Lua library cannot be loaded."
+msgstr "Lua библиотека не може да Ñе учита"
+
+msgid "cannot save undo information"
+msgstr "инфорамције за опозив не могу да Ñе Ñачувају"
+
+msgid ""
+"E815: Sorry, this command is disabled, the MzScheme libraries could not be "
+"loaded."
+msgstr ""
+"E815: Жао нам је, ова команда је онемогућена, MzScheme библиотеке ниÑу могле "
+"да Ñе учитају."
+
+msgid ""
+"E895: Sorry, this command is disabled, the MzScheme's racket/base module "
+"could not be loaded."
+msgstr ""
+"E895: Жао нам је, ова команда је онемогућена, MzScheme-ов racket/base модул "
+"није могао да Ñе учита."
+
+msgid "invalid expression"
+msgstr "неиÑправан израз"
+
+msgid "expressions disabled at compile time"
+msgstr "изрази Ñу онемогућени у време компилације"
+
+msgid "hidden option"
+msgstr "Ñкривена опција"
+
+msgid "unknown option"
+msgstr "непозната опција"
+
+msgid "window index is out of range"
+msgstr "Ð¸Ð½Ð´ÐµÐºÑ Ð¿Ñ€Ð¾Ð·Ð¾Ñ€Ð° је ван опÑега"
+
+msgid "couldn't open buffer"
+msgstr "бафер не може да Ñе отвори"
+
+msgid "cannot delete line"
+msgstr "линија не може да Ñе обрише"
+
+msgid "cannot replace line"
+msgstr "линија не може да Ñе замени"
+
+msgid "cannot insert line"
+msgstr "линија не може да Ñе уметне"
+
+msgid "string cannot contain newlines"
+msgstr "Ñтринг не може да Ñадржи нове редове"
+
+msgid "error converting Scheme values to Vim"
+msgstr "грешка при конверзији Scheme вредноÑти у Vim"
+
+msgid "Vim error: ~a"
+msgstr "Vim грешка: ~a"
+
+msgid "Vim error"
+msgstr "Vim грешка"
+
+msgid "buffer is invalid"
+msgstr "бафер је неважећи"
+
+msgid "window is invalid"
+msgstr "прозор је неважећи"
+
+msgid "linenr out of range"
+msgstr "linenr је ван опÑега"
+
+msgid "not allowed in the Vim sandbox"
+msgstr "није дозвољено у Vim sandbox-у"
+
+#, c-format
+msgid "E370: Could not load library %s"
+msgstr "E370: Библиотека %s није могла да Ñе учита"
+
+msgid "Sorry, this command is disabled: the Perl library could not be loaded."
+msgstr ""
+"Жао нам је, ова команда је онемогућена: Perl библиотека није могла да "
+"Ñе учита."
+
+msgid "E299: Perl evaluation forbidden in sandbox without the Safe module"
+msgstr "E299: Perl одређивање вредноÑти у sandbox-у је забрањено без Safe модула"
+
+msgid "E836: This Vim cannot execute :python after using :py3"
+msgstr "E836: Овај Vim не може да изврши :python након коришћења :py3"
+
+msgid ""
+"E263: Sorry, this command is disabled, the Python library could not be "
+"loaded."
+msgstr ""
+"E263: Жао нам је, ова команда је онемогућена, Python библиотека није могла "
+"да Ñе учита."
+
+msgid ""
+"E887: Sorry, this command is disabled, the Python's site module could not be "
+"loaded."
+msgstr ""
+"E887: Жао нам је, ова команда је онемогућена, Python-ов site модул није "
+"могао да Ñе учита."
+
+msgid "E659: Cannot invoke Python recursively"
+msgstr "E659: Python не може да Ñе позива рекурзивно"
+
+msgid "E837: This Vim cannot execute :py3 after using :python"
+msgstr "E837: Овај Vim не може да изврши :py3 након коришћења :python"
+
+msgid "E265: $_ must be an instance of String"
+msgstr "E265: $_ мора да буде инÑтанца String-а"
+
+msgid ""
+"E266: Sorry, this command is disabled, the Ruby library could not be loaded."
+msgstr ""
+"E266: Жао нам је, ова команда је онемогућена, Ruby библиотека није могла да "
+"Ñе учита."
+
+msgid "E267: unexpected return"
+msgstr "E267: неочекиван return"
+
+msgid "E268: unexpected next"
+msgstr "E268: неочекивано next"
+
+msgid "E269: unexpected break"
+msgstr "E269: неочекивано break"
+
+msgid "E270: unexpected redo"
+msgstr "E270: неочекивано redo"
+
+msgid "E271: retry outside of rescue clause"
+msgstr "E271: retry ван rescue клаузуле"
+
+msgid "E272: unhandled exception"
+msgstr "E272: необрађени изузетак"
+
+#, c-format
+msgid "E273: unknown longjmp status %d"
+msgstr "E273: непознат longjmp ÑÑ‚Ð°Ñ‚ÑƒÑ %d"
+
+msgid "invalid buffer number"
+msgstr "неиÑправан број бафера"
+
+msgid "not implemented yet"
+msgstr "још није имплементирано"
+
+msgid "cannot set line(s)"
+msgstr "линија(е) не може да Ñе поÑтави"
+
+msgid "invalid mark name"
+msgstr "неиÑправно име маркера"
+
+msgid "mark not set"
+msgstr "маркер није поÑтављен"
+
+#, c-format
+msgid "row %d column %d"
+msgstr "ред %d колона %d"
+
+msgid "cannot insert/append line"
+msgstr "линија не може да Ñе уметне/дода на крај"
+
+msgid "line number out of range"
+msgstr "број линије је ван опÑега"
+
+msgid "unknown flag: "
+msgstr "непознат индикатор"
+
+msgid "unknown vimOption"
+msgstr "непозната vimОпција"
+
+msgid "keyboard interrupt"
+msgstr "прекид таÑтатуре"
+
+msgid "vim error"
+msgstr "vim грешка"
+
+msgid "cannot create buffer/window command: object is being deleted"
+msgstr "бафер/прозор команда не може да Ñе креира: објекат Ñе брише"
+
+msgid ""
+"cannot register callback command: buffer/window is already being deleted"
+msgstr ""
+"команда повратног позива не може да Ñе региÑтрује: бафер/прозор је већ "
+"обриÑан"
+
+msgid ""
+"E280: TCL FATAL ERROR: reflist corrupt!? Please report this to vim-dev@vim."
+"org"
+msgstr ""
+"E280: TCL ФÐТÐЛÐРГРЕШКÐ: reflist је оштећена!? Молимо пријавите ово на "
+"vim-dev@vim.org"
+
+msgid "cannot register callback command: buffer/window reference not found"
+msgstr ""
+"команда повратног позива не може да Ñе региÑтрује: референца бафера/прозора "
+"није пронађена"
+
+msgid ""
+"E571: Sorry, this command is disabled: the Tcl library could not be loaded."
+msgstr ""
+"E571: Жао нам је, ова команда је онемогућена: Tcl библиотека није могла да "
+"Ñе учита."
+
+#, c-format
+msgid "E572: exit code %d"
+msgstr "E572: излазни код %d"
+
+msgid "cannot get line"
+msgstr "линија не може да Ñе добије"
+
+msgid "Unable to register a command server name"
+msgstr "Име Ñервера команди није могло да Ñе региÑтрује"
+
+msgid "E248: Failed to send command to the destination program"
+msgstr "E248: Слање команде циљном програму није уÑпело"
+
+#, c-format
+msgid "E573: Invalid server id used: %s"
+msgstr "E573: КориÑти Ñе неÑправан ид Ñервера: %s"
+
+msgid "E251: VIM instance registry property is badly formed. Deleted!"
+msgstr "E251: registry ÑвојÑтво VIM инÑтанце је лоше формирано. ОбриÑано!"
+
+#, c-format
+msgid "E938: Duplicate key in JSON: \"%s\""
+msgstr "E938: Дупли кључ у JSON: \"%s\""
+
+#, c-format
+msgid "E696: Missing comma in List: %s"
+msgstr "E696: У ЛиÑти недоÑтаје зарез: %s"
+
+#, c-format
+msgid "E697: Missing end of List ']': %s"
+msgstr "E697: ÐедоÑтаје крај ЛиÑте ']': %s"
+
+msgid "Unknown option argument"
+msgstr "Ðепознат аргумент опције"
+
+msgid "Too many edit arguments"
+msgstr "Сувише аргумента уређивања"
+
+msgid "Argument missing after"
+msgstr "Ðргумент недоÑтаје након"
+
+msgid "Garbage after option argument"
+msgstr "Смеће након аргумента опције"
+
+msgid "Too many \"+command\", \"-c command\" or \"--cmd command\" arguments"
+msgstr "Сувише \"+command\", \"-c command\" или \"--cmd command\" аргумената"
+
+msgid "Invalid argument for"
+msgstr "ÐеиÑправан аргумент for"
+
+#, c-format
+msgid "%d files to edit\n"
+msgstr "%d датотека за уређивање\n"
+
+msgid "netbeans is not supported with this GUI\n"
+msgstr "NetBeans није подржан Ñа овим GUI\n"
+
+msgid "'-nb' cannot be used: not enabled at compile time\n"
+msgstr "'-nb' не може да Ñе кориÑти: није омогућено у време компилације\n"
+
+msgid "This Vim was not compiled with the diff feature."
+msgstr "Овај Vim није компајлиран Ñа diff могућношћу."
+
+msgid "Attempt to open script file again: \""
+msgstr "Покушај да Ñе поново отвори Ñкрипт датотека: \""
+
+msgid "Cannot open for reading: \""
+msgstr "Ðе може да Ñе отвори за читање: \""
+
+msgid "Cannot open for script output: \""
+msgstr "Ðе може да Ñе отвори за излаз Ñкрипте: \""
+
+msgid "Vim: Error: Failure to start gvim from NetBeans\n"
+msgstr "Vim: Грешка: Покретање gvim из NetBeans није уÑпело\n"
+
+msgid "Vim: Error: This version of Vim does not run in a Cygwin terminal\n"
+msgstr ""
+"Vim: Грешка: Ова верзија Vim не може да Ñе покрене из Cygwin терминала\n"
+
+msgid "Vim: Warning: Output is not to a terminal\n"
+msgstr "Vim: Упозорење: Излаз није у терминал\n"
+
+msgid "Vim: Warning: Input is not from a terminal\n"
+msgstr "Vim: Упозорење: Улаз није из терминала\n"
+
+msgid "pre-vimrc command line"
+msgstr "pre-vimrc командна линија"
+
+#, c-format
+msgid "E282: Cannot read from \"%s\""
+msgstr "E282: Ðе може да Ñе чита из \"%s\""
+
+msgid ""
+"\n"
+"More info with: \"vim -h\"\n"
+msgstr ""
+"\n"
+"Више инфо Ñа: \"vim -h\"\n"
+
+msgid "[file ..] edit specified file(s)"
+msgstr "[датотека ..] уређуј наведену(е) датотеку(е)"
+
+msgid "- read text from stdin"
+msgstr "- читај текÑÑ‚ Ñа stdin"
+
+msgid "-t tag edit file where tag is defined"
+msgstr "-t tag уређуј датотеку где је дефиниÑана ознака"
+
+msgid "-q [errorfile] edit file with first error"
+msgstr "-q [дат.грешке] уређуј датотеку Ñа првом грешком"
+
+msgid ""
+"\n"
+"\n"
+"Usage:"
+msgstr ""
+"\n"
+"\n"
+"Употреба:"
+
+msgid " vim [arguments] "
+msgstr " vim [аргументи] "
+
+msgid ""
+"\n"
+" or:"
+msgstr ""
+"\n"
+" или:"
+
+msgid ""
+"\n"
+"Where case is ignored prepend / to make flag upper case"
+msgstr ""
+"\n"
+"Где Ñе мала/велика Ñлова игноришу Ñтавите иÑпред / како би претворили "
+"индикатор у велика Ñлова"
+
+msgid ""
+"\n"
+"\n"
+"Arguments:\n"
+msgstr ""
+"\n"
+"\n"
+"Ðргументи:\n"
+
+msgid "--\t\t\tOnly file names after this"
+msgstr "--\t\t\tСамо имена датотека након овога"
+
+msgid "--literal\t\tDon't expand wildcards"
+msgstr "--literal\t\tÐе развијај џокере"
+
+msgid "-register\t\tRegister this gvim for OLE"
+msgstr "-register\t\tРегиÑтруј овај gvim за OLE"
+
+msgid "-unregister\t\tUnregister gvim for OLE"
+msgstr "-unregister\t\tУклони региÑтрацију gvim за OLE"
+
+msgid "-g\t\t\tRun using GUI (like \"gvim\")"
+msgstr "-g\t\t\tПокрени кориÑтећи GUI (као \"gvim\")"
+
+msgid "-f or --nofork\tForeground: Don't fork when starting GUI"
+msgstr "-f или --nofork\tУ предњем плану: немој да рачваш кад Ñе покреће GUI"
+
+msgid "-v\t\t\tVi mode (like \"vi\")"
+msgstr "-v\t\t\tVi режим (као \"vi\")"
+
+msgid "-e\t\t\tEx mode (like \"ex\")"
+msgstr "-e\t\t\tEx режим (као \"ex\")"
+
+msgid "-E\t\t\tImproved Ex mode"
+msgstr "-E\t\t\tУнапређен Ex режим"
+
+msgid "-s\t\t\tSilent (batch) mode (only for \"ex\")"
+msgstr "-s\t\t\tÐечујни (batch) режим (Ñамо за \"ex\")"
+
+msgid "-d\t\t\tDiff mode (like \"vimdiff\")"
+msgstr "-d\t\t\tDiff режим (као \"vimdiff\")"
+
+msgid "-y\t\t\tEasy mode (like \"evim\", modeless)"
+msgstr "-y\t\t\tEasy режим (као \"evim\", безрежимни)"
+
+msgid "-R\t\t\tReadonly mode (like \"view\")"
+msgstr "-R\t\t\tReadonly режим (као \"view\")"
+
+msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
+msgstr "-Z\t\t\tRestricted режим (као \"rvim\")"
+
+msgid "-m\t\t\tModifications (writing files) not allowed"
+msgstr "-m\t\t\tИзмене (упиÑивање датотека) ниÑу дозвољене"
+
+msgid "-M\t\t\tModifications in text not allowed"
+msgstr "-M\t\t\tИзмене у текÑту ниÑу дозвољене"
+
+msgid "-b\t\t\tBinary mode"
+msgstr "-b\t\t\tБинарни режим"
+
+msgid "-l\t\t\tLisp mode"
+msgstr "-l\t\t\tLisp режим"
+
+msgid "-C\t\t\tCompatible with Vi: 'compatible'"
+msgstr "-C\t\t\tКомпатибилан Ñа Vi: 'compatible'"
+
+msgid "-N\t\t\tNot fully Vi compatible: 'nocompatible'"
+msgstr "-N\t\t\tÐе потпуно Vi компатибилан: 'nocompatible'"
+
+msgid "-V[N][fname]\t\tBe verbose [level N] [log messages to fname]"
+msgstr "-V[N][fname]\t\tБуди опширан [ниво N] [бележи поруке у fname]"
+
+msgid "-D\t\t\tDebugging mode"
+msgstr "-D\t\t\tDebugging режим"
+
+msgid "-n\t\t\tNo swap file, use memory only"
+msgstr "-n\t\t\tБез swap датотеке, кориÑти Ñамо меморију"
+
+msgid "-r\t\t\tList swap files and exit"
+msgstr "-r\t\t\tИзлиÑтај swap датотеке и изађи"
+
+msgid "-r (with file name)\tRecover crashed session"
+msgstr "-r (Ñа именом датотеке)\tОбнови Ñрушену ÑеÑију"
+
+msgid "-L\t\t\tSame as -r"
+msgstr "-L\t\t\tИÑто као -r"
+
+msgid "-f\t\t\tDon't use newcli to open window"
+msgstr "-f\t\t\tÐемој да кориÑтиш нов cli да отвориш прозор"
+
+msgid "-dev <device>\t\tUse <device> for I/O"
+msgstr "-dev <уређај>\t\tКориÑти <уређај> за У/И"
+
+msgid "-A\t\t\tStart in Arabic mode"
+msgstr "-A\t\t\tПокрени у ÐрапÑком режиму"
+
+msgid "-H\t\t\tStart in Hebrew mode"
+msgstr "-H\t\t\tПокрени у ХебрејÑком режиму"
+
+msgid "-F\t\t\tStart in Farsi mode"
+msgstr "-F\t\t\tПокрени у ФарÑи режиму"
+
+msgid "-T <terminal>\tSet terminal type to <terminal>"
+msgstr "-T <терминал>\tПоÑтави тип терминала на <терминал>"
+
+msgid "--not-a-term\t\tSkip warning for input/output not being a terminal"
+msgstr "--not-a-term\t\tПреÑкочи упозорење да улаз/излаз није терминал"
+
+msgid "--ttyfail\t\tExit if input or output is not a terminal"
+msgstr "--ttyfail\t\tИзађи ако улаз или излаз ниÑу терминал"
+
+msgid "-u <vimrc>\t\tUse <vimrc> instead of any .vimrc"
+msgstr "-u <vimrc>\t\tКориÑти <vimrc> умеÑто било ког .vimrc"
+
+msgid "-U <gvimrc>\t\tUse <gvimrc> instead of any .gvimrc"
+msgstr "-U <gvimrc>\t\tКориÑти <gvimrc> умеÑто било ког .gvimrc"
+
+msgid "--noplugin\t\tDon't load plugin scripts"
+msgstr "--noplugin\t\tÐе учитавај Ñкрипте додатака"
+
+msgid "-p[N]\t\tOpen N tab pages (default: one for each file)"
+msgstr "-p[N]\t\tОтвори N картица (подразумевано: по једну за Ñваку датотеку)"
+
+msgid "-o[N]\t\tOpen N windows (default: one for each file)"
+msgstr "-o[N]\t\tОтвори N прозора (подразумевано: по један за Ñваку датотеку)"
+
+msgid "-O[N]\t\tLike -o but split vertically"
+msgstr "-O[N]\t\tКао -o али подели по вертикали"
+
+msgid "+\t\t\tStart at end of file"
+msgstr "+\t\t\tПочни на крају датотеке"
+
+msgid "+<lnum>\t\tStart at line <lnum>"
+msgstr "+<бројл>\t\tПочни на линији <бројл>"
+
+msgid "--cmd <command>\tExecute <command> before loading any vimrc file"
+msgstr ""
+"--cmd <команда>\tИзврши <команда> пре учитавања било које vimrc датотеке"
+
+msgid "-c <command>\t\tExecute <command> after loading the first file"
+msgstr "-c <команда>\t\tИзврши <команда> након учитавања прве датотеке"
+
+msgid "-S <session>\t\tSource file <session> after loading the first file"
+msgstr ""
+"-S <ÑеÑија>\t\tИзворна датотека <ÑеÑија> након учитавања прве "
+"датотеке"
+
+msgid "-s <scriptin>\tRead Normal mode commands from file <scriptin>"
+msgstr ""
+"-s <Ñкриптулаз>\tЧитај команде Ðормалног режима из датотеке <Ñкриптулаз>"
+
+msgid "-w <scriptout>\tAppend all typed commands to file <scriptout>"
+msgstr ""
+"-w <Ñкриптизлаз>\tÐадовежи Ñве откуцане команде на крај датотеке "
+"<Ñкриптизлаз>"
+
+msgid "-W <scriptout>\tWrite all typed commands to file <scriptout>"
+msgstr "-W <Ñкриптизлаз>\tУпиÑуј Ñве откуцане команде у датотеку <Ñкриптизлаз>"
+
+msgid "-x\t\t\tEdit encrypted files"
+msgstr "-x\t\t\tУређуј шифроване датотеке"
+
+msgid "-display <display>\tConnect vim to this particular X-server"
+msgstr "-display <диÑплеј>\tПовежи vim на овај X-Ñервер"
+
+msgid "-X\t\t\tDo not connect to X server"
+msgstr "-X\t\t\tÐе повезуј Ñе на X Ñервер"
+
+msgid "--remote <files>\tEdit <files> in a Vim server if possible"
+msgstr "--remote <датотеке>\tУређуј <датотеке> у Vim Ñерверу ако је могуће"
+
+msgid "--remote-silent <files> Same, don't complain if there is no server"
+msgstr "--remote-silent <датотеке> ИÑто, не буни Ñе ако нема Ñервера"
+
+msgid ""
+"--remote-wait <files> As --remote but wait for files to have been edited"
+msgstr ""
+"--remote-wait <датотеке> Као --remote али чекај да датотеке буду уређене"
+
+msgid ""
+"--remote-wait-silent <files> Same, don't complain if there is no server"
+msgstr "--remote-wait-silent <датотеке> ИÑто, не буни Ñе ако нема Ñервера"
+
+msgid ""
+"--remote-tab[-wait][-silent] <files> As --remote but use tab page per file"
+msgstr ""
+"--remote-tab[-wait][-silent] <датотеке> Као --remote али кориÑти једну "
+"картицу по датотеци"
+
+msgid "--remote-send <keys>\tSend <keys> to a Vim server and exit"
+msgstr "--remote-send <таÑтери>\tПошаљи <таÑтери> Vim Ñерверу и изађи"
+
+msgid "--remote-expr <expr>\tEvaluate <expr> in a Vim server and print result"
+msgstr ""
+"--remote-expr <израз>\tИзрачунај <израз> у Vim Ñерверу и одштампај резултат"
+
+msgid "--serverlist\t\tList available Vim server names and exit"
+msgstr "--serverlist\t\tИзлиÑтај имена доÑтупних Vim Ñервера и изађи"
+
+msgid "--servername <name>\tSend to/become the Vim server <name>"
+msgstr "--servername <име>\tПошаљи/поÑтани Vim Ñервер <име>"
+
+msgid "--startuptime <file>\tWrite startup timing messages to <file>"
+msgstr "--startuptime <датотека>\tУпиши поруке о дужини покретања у <датотеку>"
+
+msgid "-i <viminfo>\t\tUse <viminfo> instead of .viminfo"
+msgstr "-i <viminfo>\t\tКориÑти <viminfo> умеÑто .viminfo"
+
+msgid "--clean\t\t'nocompatible', Vim defaults, no plugins, no viminfo"
+msgstr ""
+"--clean\t\t'nocompatible', Vim подразумеване вредноÑти, без додатака, без "
+"viminfo"
+
+msgid "-h or --help\tPrint Help (this message) and exit"
+msgstr "-h or --help\tИÑпиши Помоћ (ову поруку) и изађи"
+
+msgid "--version\t\tPrint version information and exit"
+msgstr "--version\t\tИÑпиши информације о верзији и изађи"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Motif version):\n"
+msgstr ""
+"\n"
+"Ðргументи које препознаје gvim (Motif верзија):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (neXtaw version):\n"
+msgstr ""
+"\n"
+"Ðргументи које препознаје gvim (neXtaw верзија):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Athena version):\n"
+msgstr ""
+"\n"
+"Ðргументи које препознаје gvim (Athena верзија):\n"
+
+msgid "-display <display>\tRun vim on <display>"
+msgstr "-display <диÑплеј>\tПокрени vim на <диÑплеј>"
+
+msgid "-iconic\t\tStart vim iconified"
+msgstr "-iconic\t\tПокрени vim као икону"
+
+msgid "-background <color>\tUse <color> for the background (also: -bg)"
+msgstr "-background <боја>\tКориÑти <боја> за позадину (такође: -bg)"
+
+msgid "-foreground <color>\tUse <color> for normal text (also: -fg)"
+msgstr "-foreground <боја>\tКориÑти <боја> за нормални текÑÑ‚ (такође: -fg)"
+
+msgid "-font <font>\t\tUse <font> for normal text (also: -fn)"
+msgstr "-font <фонт>\t\tКориÑти <фонт> за нормални текÑÑ‚ (такође: -fn)"
+
+msgid "-boldfont <font>\tUse <font> for bold text"
+msgstr "-boldfont <фонт>\tКориÑти <фонт> за подебљани текÑÑ‚"
+
+msgid "-italicfont <font>\tUse <font> for italic text"
+msgstr "-italicfont <фонт>\tКориÑти <фонт> за курзивни текÑÑ‚"
+
+msgid "-geometry <geom>\tUse <geom> for initial geometry (also: -geom)"
+msgstr "-geometry <геом>\tКориÑти <геом> за почетну геометрију (такође: -geom)"
+
+msgid "-borderwidth <width>\tUse a border width of <width> (also: -bw)"
+msgstr "-borderwidth <ширина>\tКориÑти оквир ширине <ширина> (такође: -bw)"
+
+msgid "-scrollbarwidth <width> Use a scrollbar width of <width> (also: -sw)"
+msgstr ""
+"-scrollbarwidth <ширина> КориÑти Линију за Ñкроловање ширине <ширина> "
+"(такође: -sw)"
+
+msgid "-menuheight <height>\tUse a menu bar height of <height> (also: -mh)"
+msgstr ""
+"-menuheight <ширина>\tКориÑти линију менија виÑине <виÑина> (такође: -mh)"
+
+msgid "-reverse\t\tUse reverse video (also: -rv)"
+msgstr "-reverse\t\tКориÑти обрнути видео (такође: -rv)"
+
+msgid "+reverse\t\tDon't use reverse video (also: +rv)"
+msgstr "+reverse\t\tÐемој да кориÑтиш обрнути видео (такође: +rv)"
+
+msgid "-xrm <resource>\tSet the specified resource"
+msgstr "-xrm <реÑурÑ>\tПоÑтави наведени реÑурÑ"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (GTK+ version):\n"
+msgstr ""
+"\n"
+"Ðргументи које препознаје gvim (GTK+ верзија):\n"
+
+msgid "-display <display>\tRun vim on <display> (also: --display)"
+msgstr "-display <диÑплеј>\tПокрени vim на <диÑплеј> (такође: --display)"
+
+msgid "--role <role>\tSet a unique role to identify the main window"
+msgstr ""
+"--role <улога>\tПоÑтави јединÑтвену улогу да би Ñе идентификовао главни "
+"прозор"
+
+msgid "--socketid <xid>\tOpen Vim inside another GTK widget"
+msgstr "--socketid <xid>\tОтвори Vim унутар другог GTK виџета"
+
+msgid "--echo-wid\t\tMake gvim echo the Window ID on stdout"
+msgstr "--echo-wid\t\tÐека gvim иÑпише Window ID на stdout"
+
+msgid "-P <parent title>\tOpen Vim inside parent application"
+msgstr "-P <назив родитеља>\tОтвори Vim унутар родитељÑке апликације"
+
+msgid "--windowid <HWND>\tOpen Vim inside another win32 widget"
+msgstr "--windowid <HWND>\tОтвори Vim унутар другог win32 виџета"
+
+msgid "No display"
+msgstr "Ðема приказа"
+
+msgid ": Send failed.\n"
+msgstr ": Слање није уÑпело.\n"
+
+msgid ": Send failed. Trying to execute locally\n"
+msgstr ": Слање није уÑпело. Покушава Ñе локално извршавање\n"
+
+#, c-format
+msgid "%d of %d edited"
+msgstr "%d од %d уређено"
+
+msgid "No display: Send expression failed.\n"
+msgstr "Ðема приказа: Израз Ñлања није уÑпео.\n"
+
+msgid ": Send expression failed.\n"
+msgstr ": Израз Ñлања није уÑпео.\n"
+
+msgid "No marks set"
+msgstr "Ðема поÑтављених маркера"
+
+#, c-format
+msgid "E283: No marks matching \"%s\""
+msgstr "E283: Ðема маркера који Ñе подударају Ñа \"%s\""
+
+msgid ""
+"\n"
+"mark line col file/text"
+msgstr ""
+"\n"
+"линија маркера кол датотека/текÑÑ‚"
+
+msgid ""
+"\n"
+" jump line col file/text"
+msgstr ""
+"\n"
+" линија Ñкока кол датотека/текÑÑ‚"
+
+msgid ""
+"\n"
+"change line col text"
+msgstr ""
+"\n"
+"линија промене кол текÑÑ‚"
+
+msgid ""
+"\n"
+"# File marks:\n"
+msgstr ""
+"\n"
+"# Маркери датотеке:\n"
+
+msgid ""
+"\n"
+"# Jumplist (newest first):\n"
+msgstr ""
+"\n"
+"# Скок-лиÑта (прво најновији):\n"
+
+msgid ""
+"\n"
+"# History of marks within files (newest to oldest):\n"
+msgstr ""
+"\n"
+"# ИÑторија маркера унутар датотека (ок најновијег до најÑтаријег):\n"
+
+msgid "Missing '>'"
+msgstr "ÐедоÑтаје '>'"
+
+msgid "E543: Not a valid codepage"
+msgstr "E543: Ðеважећа кодна Ñтрана"
+
+msgid "E284: Cannot set IC values"
+msgstr "E284: IC вредноÑти не могу да Ñе поÑтаве"
+
+msgid "E285: Failed to create input context"
+msgstr "E285: Креирање контекÑта уноÑа није уÑпело"
+
+msgid "E286: Failed to open input method"
+msgstr "E286: Отварање методе уноÑа није уÑпело"
+
+msgid "E287: Warning: Could not set destroy callback to IM"
+msgstr ""
+"E287: Упозорење: ПоÑтављање повратне функције за уништење IM није уÑпело"
+
+msgid "E288: input method doesn't support any style"
+msgstr "E288: метод уноÑа не подржава ниједан Ñтил"
+
+msgid "E289: input method doesn't support my preedit type"
+msgstr "E289: метод уноÑа не подржава мој preedit тип"
+
+msgid "E293: block was not locked"
+msgstr "E293: блок није закључан"
+
+msgid "E294: Seek error in swap file read"
+msgstr "E294: Грешка код поÑтављања показивача за читање swap датотеке"
+
+msgid "E295: Read error in swap file"
+msgstr "E295: Грешка при читању swap датотеке"
+
+msgid "E296: Seek error in swap file write"
+msgstr "E296: Грешка код поÑтављања показивача за ÑƒÐ¿Ð¸Ñ swap датотеке"
+
+msgid "E297: Write error in swap file"
+msgstr "E297: Грешка при упиÑу swap датотеке"
+
+msgid "E300: Swap file already exists (symlink attack?)"
+msgstr "E300: Swap датотека већ поÑтоји (symlink напад?)"
+
+msgid "E298: Didn't get block nr 0?"
+msgstr "E298: Блок бр 0 није добављен?"
+
+msgid "E298: Didn't get block nr 1?"
+msgstr "E298: Блок бр 1 није добављен?"
+
+msgid "E298: Didn't get block nr 2?"
+msgstr "E298: Блок бр 2 није добављен?"
+
+msgid "E843: Error while updating swap file crypt"
+msgstr "E843: Грешка приликом оÑважавања криптовања swap датотеке"
+
+msgid "E301: Oops, lost the swap file!!!"
+msgstr "E301: УупÑ, swap датотека је изгубљена!!!"
+
+msgid "E302: Could not rename swap file"
+msgstr "E302: Промена имена swap датотеке није уÑпела"
+
+#, c-format
+msgid "E303: Unable to open swap file for \"%s\", recovery impossible"
+msgstr ""
+"E303: Отварање swap датотеке за \"%s\" није уÑпело, опоравак је немогућ"
+
+msgid "E304: ml_upd_block0(): Didn't get block 0??"
+msgstr "E304: ml_upd_block0(): Блок бр 0 није добављен??"
+
+#, c-format
+msgid "E305: No swap file found for %s"
+msgstr "E305: За %s није пронађена swap датотека"
+
+msgid "Enter number of swap file to use (0 to quit): "
+msgstr "УнеÑите број swap датотеке која ће да Ñе кориÑти (0 за отказивање): "
+
+#, c-format
+msgid "E306: Cannot open %s"
+msgstr "E306: %s не може да Ñе отвори"
+
+msgid "Unable to read block 0 from "
+msgstr "Ðије могуће литање блока 0 из "
+
+msgid ""
+"\n"
+"Maybe no changes were made or Vim did not update the swap file."
+msgstr ""
+"\n"
+"Можда ниÑу направљене никакве измене или Vim није оÑвежио swap датотеку."
+
+msgid " cannot be used with this version of Vim.\n"
+msgstr " не може да Ñе кориÑти Ñа овом верзијом Vim-а.\n"
+
+msgid "Use Vim version 3.0.\n"
+msgstr "КориÑтите Vim верзијe 3.0.\n"
+
+#, c-format
+msgid "E307: %s does not look like a Vim swap file"
+msgstr "E307: %s не изгледа као Vim swap датотека"
+
+msgid " cannot be used on this computer.\n"
+msgstr " не може да Ñе кориÑти на овом компјутеру.\n"
+
+msgid "The file was created on "
+msgstr "Ова датотека је креирана Ñа "
+
+msgid ""
+",\n"
+"or the file has been damaged."
+msgstr ""
+",\n"
+"или је датотека оштећена."
+
+#, c-format
+msgid ""
+"E833: %s is encrypted and this version of Vim does not support encryption"
+msgstr "E833: %s је шифрована и ова верзија Vim-а не подржава шифровање"
+
+msgid " has been damaged (page size is smaller than minimum value).\n"
+msgstr " је оштећена (величина Ñтранице је маља од минималне вредноÑти).\n"
+
+#, c-format
+msgid "Using swap file \"%s\""
+msgstr "КориÑти Ñе swap датотека \"%s\""
+
+#, c-format
+msgid "Original file \"%s\""
+msgstr "Оригинална датотека \"%s\""
+
+msgid "E308: Warning: Original file may have been changed"
+msgstr "E308: Упозорење: Можда је промењена оригинална датотека"
+
+#, c-format
+msgid "Swap file is encrypted: \"%s\""
+msgstr "Swap датотека је шифрована: \"%s\""
+
+msgid ""
+"\n"
+"If you entered a new crypt key but did not write the text file,"
+msgstr ""
+"\n"
+"Ðко Ñте унели нов кључ за шифрирање али ниÑте упиÑали текÑÑ‚ датотеку,"
+
+msgid ""
+"\n"
+"enter the new crypt key."
+msgstr ""
+"\n"
+"унеÑите нови кључ за шифрирање."
+
+msgid ""
+"\n"
+"If you wrote the text file after changing the crypt key press enter"
+msgstr ""
+"\n"
+"Ðко Ñте упиÑали текÑÑ‚ датотеку на диÑк након промене кључа за шифрирање "
+"притиÑните ентер"
+
+msgid ""
+"\n"
+"to use the same key for text file and swap file"
+msgstr ""
+"\n"
+"да биÑте кориÑтили иÑти кључ за текÑÑ‚ датотеку и swap датотеку"
+
+#, c-format
+msgid "E309: Unable to read block 1 from %s"
+msgstr "E309: Блок 1 из %s не може да Ñе прочита"
+
+msgid "???MANY LINES MISSING"
+msgstr "??ÐЕДОСТÐЈЕ ÐœÐОГО ЛИÐИЈÐ"
+
+msgid "???LINE COUNT WRONG"
+msgstr "???БРОЈ ЛИÐИЈРЈЕ ПОГРЕШÐÐ"
+
+msgid "???EMPTY BLOCK"
+msgstr "???ПРÐЗÐРБЛОК"
+
+msgid "???LINES MISSING"
+msgstr "???ÐЕДОСТÐЈУ ЛИÐИЈЕ"
+
+#, c-format
+msgid "E310: Block 1 ID wrong (%s not a .swp file?)"
+msgstr "E310: ID блока 1 је погрешан (%s није .swp датотека?)"
+
+msgid "???BLOCK MISSING"
+msgstr "???ÐЕДОСТÐЈЕ БЛОК"
+
+msgid "??? from here until ???END lines may be messed up"
+msgstr "??? одавде па до ???КРÐЈ линије Ñу можда забрљане"
+
+msgid "??? from here until ???END lines may have been inserted/deleted"
+msgstr "??? одавде па до ???КРÐЈ линије Ñу можда уметане/бриÑане"
+
+msgid "???END"
+msgstr "???КРÐЈ"
+
+msgid "E311: Recovery Interrupted"
+msgstr "E311: Опоравак је прекинут"
+
+msgid ""
+"E312: Errors detected while recovering; look for lines starting with ???"
+msgstr ""
+"E312: Откривене Ñу грешке приликом опоравка; потражите линије које почињу "
+"Ñа ???"
+
+msgid "See \":help E312\" for more information."
+msgstr "Погледајте \":help E312\" за више информација."
+
+msgid "Recovery completed. You should check if everything is OK."
+msgstr "Опоравак је завршен. Требало би да проверите да ли је Ñве OK."
+
+msgid ""
+"\n"
+"(You might want to write out this file under another name\n"
+msgstr ""
+"\n"
+"(Можда биÑте хтели да запишете ову датотеку под другим именом\n"
+
+msgid "and run diff with the original file to check for changes)"
+msgstr "и покренете diff Ñа оригиналном датотеком да провелите има ли измена)"
+
+msgid "Recovery completed. Buffer contents equals file contents."
+msgstr "Опоравак је завршен. Садржај бафера је иÑтоветан Ñадржају датотеке."
+
+msgid ""
+"\n"
+"You may want to delete the .swp file now.\n"
+"\n"
+msgstr ""
+"\n"
+"Сада можда желите да обришете .swp датотеку.\n"
+"\n"
+
+msgid "Using crypt key from swap file for the text file.\n"
+msgstr "За текÑÑ‚ датотеку Ñе кориÑти кључ за шифрирање из swap датотеке.\n"
+
+msgid "Swap files found:"
+msgstr "Пронађене Ñу swap датотеке:"
+
+msgid " In current directory:\n"
+msgstr " У текућем директоријуму:\n"
+
+msgid " Using specified name:\n"
+msgstr " КориÑтећи наведено име:\n"
+
+msgid " In directory "
+msgstr " У директоријуму "
+
+msgid " -- none --\n"
+msgstr " -- ниједна --\n"
+
+msgid " owned by: "
+msgstr " које поÑедује: "
+
+msgid " dated: "
+msgstr " датиране: "
+
+msgid " dated: "
+msgstr " датиране: "
+
+msgid " [from Vim version 3.0]"
+msgstr " [од Vim верзије 3.0]"
+
+msgid " [does not look like a Vim swap file]"
+msgstr " [не изгледа као Vim swap датотека]"
+
+msgid " file name: "
+msgstr " име датотеке: "
+
+msgid ""
+"\n"
+" modified: "
+msgstr ""
+"\n"
+" измењено: "
+
+msgid "YES"
+msgstr "ДÐ"
+
+msgid "no"
+msgstr "не"
+
+msgid ""
+"\n"
+" user name: "
+msgstr ""
+"\n"
+" кориÑничко име: "
+
+msgid " host name: "
+msgstr " име хоÑта: "
+
+msgid ""
+"\n"
+" host name: "
+msgstr ""
+"\n"
+" име хоÑта: "
+
+msgid ""
+"\n"
+" process ID: "
+msgstr ""
+"\n"
+" ИД процеÑа: "
+
+msgid " (still running)"
+msgstr " (још Ñе извршава)"
+
+msgid ""
+"\n"
+" [not usable with this version of Vim]"
+msgstr ""
+"\n"
+" [није употребљива Ñа овом верзијом Vim-а]"
+
+msgid ""
+"\n"
+" [not usable on this computer]"
+msgstr ""
+"\n"
+" [није употребљива на овом компјутеру]"
+
+msgid " [cannot be read]"
+msgstr " [не може да Ñе прочита]"
+
+msgid " [cannot be opened]"
+msgstr " [не може да Ñе отвори]"
+
+msgid "E313: Cannot preserve, there is no swap file"
+msgstr "E313: Ðе може да Ñе презервира, нема swap датотеке"
+
+msgid "File preserved"
+msgstr "Датотека је презервирана"
+
+msgid "E314: Preserve failed"
+msgstr "E314: Презервација није уÑпела"
+
+#, c-format
+msgid "E315: ml_get: invalid lnum: %ld"
+msgstr "E315: ml_get: неиÑправан lnum: %ld"
+
+#, c-format
+msgid "E316: ml_get: cannot find line %ld"
+msgstr "E316: ml_get: линија %ld не може да Ñе пронађе"
+
+msgid "E317: pointer block id wrong 3"
+msgstr "E317: ид показивача блока је погрешан 3"
+
+msgid "stack_idx should be 0"
+msgstr "stack_idx би требало да је 0"
+
+msgid "E318: Updated too many blocks?"
+msgstr "E318: ОÑвежено превише блокова?"
+
+msgid "E317: pointer block id wrong 4"
+msgstr "E317: ид показивача блока је погрешан 4"
+
+msgid "deleted block 1?"
+msgstr "блок 1 обриÑан?"
+
+#, c-format
+msgid "E320: Cannot find line %ld"
+msgstr "E320: Линија %ld не може да Ñе пронађе"
+
+msgid "E317: pointer block id wrong"
+msgstr "E317: ид показивача блока је погрешан"
+
+msgid "pe_line_count is zero"
+msgstr "pe_line_count је нула"
+
+#, c-format
+msgid "E322: line number out of range: %ld past the end"
+msgstr "E322: број линије је ван опÑега: %ld иза краја"
+
+#, c-format
+msgid "E323: line count wrong in block %ld"
+msgstr "E323: број линија је погрешан у блоку %ld"
+
+msgid "Stack size increases"
+msgstr "Величина Ñтека Ñе повећава"
+
+msgid "E317: pointer block id wrong 2"
+msgstr "E317: ид показивача блока је погрешан 2"
+
+#, c-format
+msgid "E773: Symlink loop for \"%s\""
+msgstr "E773: Symlink петља за \"%s\""
+
+msgid "E325: ATTENTION"
+msgstr "E325: ПÐЖЊÐ"
+
+msgid ""
+"\n"
+"Found a swap file by the name \""
+msgstr ""
+"\n"
+"Пронађена је swap датотека под именом \""
+
+msgid "While opening file \""
+msgstr "Док Ñе отварала датотекa \""
+
+msgid " NEWER than swap file!\n"
+msgstr " ÐОВИЈРод swap датотеке!\n"
+
+msgid ""
+"\n"
+"(1) Another program may be editing the same file. If this is the case,\n"
+" be careful not to end up with two different instances of the same\n"
+" file when making changes. Quit, or continue with caution.\n"
+msgstr ""
+"\n"
+"(1) Можда други програм уређује иÑту датотеку. Ðко је ово Ñлучај,\n"
+" кад правите измене, пазите да не завршите Ñа две различите\n"
+" инÑтанце иÑте датотеке. Изађите, или опрезно наÑтавите.\n"
+
+msgid "(2) An edit session for this file crashed.\n"
+msgstr "(2) СеÑија уређивања ове датотеке Ñе Ñрушила.\n"
+
+msgid " If this is the case, use \":recover\" or \"vim -r "
+msgstr " Ðко је ово Ñлучај, кориÑтите \":recover\" или \"vim -r "
+
+msgid ""
+"\"\n"
+" to recover the changes (see \":help recovery\").\n"
+msgstr ""
+"\"\n"
+" да опоравите измене (погледајте \":help recovery\").\n"
+
+msgid " If you did this already, delete the swap file \""
+msgstr " Ðко Ñте ово већ учинили, обришите swap датотеку \""
+
+msgid ""
+"\"\n"
+" to avoid this message.\n"
+msgstr ""
+"\"\n"
+" како би избегли ову поруку.\n"
+
+msgid "Swap file \""
+msgstr "Swap датотека \""
+
+msgid "\" already exists!"
+msgstr "\" већ поÑтоји!"
+
+msgid "VIM - ATTENTION"
+msgstr "VIM - ПÐЖЊÐ"
+
+msgid "Swap file already exists!"
+msgstr "Swap датотека већ поÑтоји!"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"Отвори &Само за читање\n"
+"Ипак &Уређуј\n"
+"&Опорави\n"
+"&Изађи\n"
+"&Прекини"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Delete it\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"Отвори &Само за читање\n"
+"Ипак &Уређуј\n"
+"&Опорави\n"
+"&Изађи\n"
+"&Прекини"
+
+msgid "E326: Too many swap files found"
+msgstr "E326: Пронађено је превише swap датотека"
+
+msgid "E327: Part of menu-item path is not sub-menu"
+msgstr "E327: Део путање Ñтавке менија није подмени"
+
+msgid "E328: Menu only exists in another mode"
+msgstr "E328: Мени поÑтоји Ñамо у другом режиму"
+
+#, c-format
+msgid "E329: No menu \"%s\""
+msgstr "E329: Ðема менија \"%s\""
+
+msgid "E792: Empty menu name"
+msgstr "E792: Празно име менија"
+
+msgid "E330: Menu path must not lead to a sub-menu"
+msgstr "E330: Путања менија не Ñме да води у подмени"
+
+msgid "E331: Must not add menu items directly to menu bar"
+msgstr "E331: Ставке менија не Ñмеју да Ñе додају директно у линију менија"
+
+msgid "E332: Separator cannot be part of a menu path"
+msgstr "E332: Сепаратор не може да буде део путање менија"
+
+msgid ""
+"\n"
+"--- Menus ---"
+msgstr ""
+"\n"
+"--- Менији ---"
+
+msgid "Tear off this menu"
+msgstr "Отцепи овај мени"
+
+#, c-format
+msgid "E335: Menu not defined for %s mode"
+msgstr "E335: Мени није дефиниÑан за %s Ñ€eжим"
+
+msgid "E333: Menu path must lead to a menu item"
+msgstr "E333: Путања менија мора да води у Ñтавку менија"
+
+#, c-format
+msgid "E334: Menu not found: %s"
+msgstr "E334: Мени није пронађен: %s"
+
+msgid "E336: Menu path must lead to a sub-menu"
+msgstr "E336: Путања менија мора да води у подмени"
+
+msgid "E337: Menu not found - check menu names"
+msgstr "E337: Мени није пронађен - проверите имена менија"
+
+#, c-format
+msgid "Error detected while processing %s:"
+msgstr "Откривена је грешка током обраде %s:"
+
+#, c-format
+msgid "line %4ld:"
+msgstr "линија %4ld:"
+
+#, c-format
+msgid "E354: Invalid register name: '%s'"
+msgstr "E354: ÐеиÑправно име региÑтра: '%s'"
+
+msgid "Messages maintainer: Bram Moolenaar <Bram@vim.org>"
+msgstr "Поруке одржава: Иван Пешић <ivan.pesic@gmail.com>"
+
+msgid "Interrupt: "
+msgstr "Прекид: "
+
+msgid "Press ENTER or type command to continue"
+msgstr "Да биÑте наÑтавили, притиÑните ЕÐТЕР или откуцајте команду"
+
+#, c-format
+msgid "%s line %ld"
+msgstr "%s линија %ld"
+
+msgid "-- More --"
+msgstr "-- Још --"
+
+msgid " SPACE/d/j: screen/page/line down, b/u/k: up, q: quit "
+msgstr " РÐЗМÐКÐИЦÐ/d/j: екран/Ñтрана/линија наниже, b/u/k: навише, q: излаз "
+
+msgid "Question"
+msgstr "Питање"
+
+msgid ""
+"&Yes\n"
+"&No"
+msgstr ""
+"&Да\n"
+"&Ðе"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"Save &All\n"
+"&Discard All\n"
+"&Cancel"
+msgstr ""
+"&Да\n"
+"&Ðе\n"
+"Сачувај &Све\n"
+"о&Дбаци Ñве\n"
+"&Откажи"
+
+msgid "Select Directory dialog"
+msgstr "Дијалог избора директоријума"
+
+msgid "Save File dialog"
+msgstr "Дијалог чувања датотеке"
+
+msgid "Open File dialog"
+msgstr "Дијалог отварања датотеке"
+
+msgid "E338: Sorry, no file browser in console mode"
+msgstr "E338: Жао нам је, нема претраживача датотека у конзолном режиму"
+
+msgid "E766: Insufficient arguments for printf()"
+msgstr "E766: Ðедовољно аргумената за printf()"
+
+msgid "E807: Expected Float argument for printf()"
+msgstr "E807: Очекује Ñе Float аргумент за printf()"
+
+msgid "E767: Too many arguments to printf()"
+msgstr "E767: Сувише аргумената за printf()"
+
+msgid "W10: Warning: Changing a readonly file"
+msgstr "W10: Упозорење: Мења Ñе датотека која може Ñамо да Ñе чита"
+
+msgid "Type number and <Enter> or click with mouse (empty cancels): "
+msgstr "УнеÑите број и <Enter> или кликните мишем (ништа за отказ): "
+
+msgid "Type number and <Enter> (empty cancels): "
+msgstr "УнеÑите број и <Enter> (ништа за отказ): "
+
+msgid "1 more line"
+msgstr "1 линија више"
+
+msgid "1 line less"
+msgstr "1 линија мање"
+
+#, c-format
+msgid "%ld more lines"
+msgstr "%ld линија више"
+
+#, c-format
+msgid "%ld fewer lines"
+msgstr "%ld линија мање"
+
+msgid " (Interrupted)"
+msgstr " (Прекинуто)"
+
+msgid "Beep!"
+msgstr "Биип!"
+
+msgid "ERROR: "
+msgstr "ГРЕШКÐ: "
+
+#, c-format
+msgid ""
+"\n"
+"[bytes] total alloc-freed %lu-%lu, in use %lu, peak use %lu\n"
+msgstr ""
+"\n"
+"[бајтова] укупно алоц-оÑлоб %lu-%lu, у употр %lu, вршна употр %lu\n"
+
+#, c-format
+msgid ""
+"[calls] total re/malloc()'s %lu, total free()'s %lu\n"
+"\n"
+msgstr ""
+"[позива] укупно re/malloc()-а %lu, укупно free()-ова %lu\n"
+"\n"
+
+msgid "E340: Line is becoming too long"
+msgstr "E340: Линија поÑтаје предугачка"
+
+#, c-format
+msgid "E341: Internal error: lalloc(%ld, )"
+msgstr "E341: Интерна грешка: lalloc(%ld, )"
+
+#, c-format
+msgid "E342: Out of memory! (allocating %lu bytes)"
+msgstr "E342: Ðема више меморије! (код алокације %lu бајтова)"
+
+#, c-format
+msgid "Calling shell to execute: \"%s\""
+msgstr "Позива Ñе командно окружење да изврши: \"%s\""
+
+msgid "E545: Missing colon"
+msgstr "E545: ÐедоÑтаје двотачка"
+
+msgid "E546: Illegal mode"
+msgstr "E546: Ðедозвољени режим"
+
+msgid "E547: Illegal mouseshape"
+msgstr "E547: Ðедозвољени mouseshape"
+
+msgid "E548: digit expected"
+msgstr "E548: очекује Ñе цифра"
+
+msgid "E549: Illegal percentage"
+msgstr "E549: Ðедозвољени проценат"
+
+msgid "E854: path too long for completion"
+msgstr "E854: путања је Ñувише дугачка да би Ñе довршила"
+
+#, c-format
+msgid ""
+"E343: Invalid path: '**[number]' must be at the end of the path or be "
+"followed by '%s'."
+msgstr ""
+"E343: ÐеиÑправна путања: '**[број]' мора бити на крају путање или да иза "
+"њега Ñледи '%s'."
+
+#, c-format
+msgid "E344: Can't find directory \"%s\" in cdpath"
+msgstr "E344: Директоријум \"%s\" не може да Ñе пронађе у cdpath"
+
+#, c-format
+msgid "E345: Can't find file \"%s\" in path"
+msgstr "E345: Датотека \"%s\" не може да Ñе пронађе у path"
+
+#, c-format
+msgid "E346: No more directory \"%s\" found in cdpath"
+msgstr "E346: Директоријум \"%s\" више не може да Ñе пронађе у cdpath"
+
+#, c-format
+msgid "E347: No more file \"%s\" found in path"
+msgstr "E347: Датотека \"%s\" више не може да Ñе пронађе у path"
+
+#, c-format
+msgid "E668: Wrong access mode for NetBeans connection info file: \"%s\""
+msgstr "E668: Погрешан режим приÑтупа за инфо датотеку NetBeans везе: \"%s\""
+
+#, c-format
+msgid "E658: NetBeans connection lost for buffer %ld"
+msgstr "E658: NetBeans веза је изгубљена за бафер %ld"
+
+msgid "E838: netbeans is not supported with this GUI"
+msgstr "E838: netbeans није подржан Ñа овим GUI"
+
+msgid "E511: netbeans already connected"
+msgstr "E511: netbeans је већ повезан"
+
+#, c-format
+msgid "E505: %s is read-only (add ! to override)"
+msgstr "E505: %s је Ñамо за читање (додајте ! за премошћавање)"
+
+msgid "E349: No identifier under cursor"
+msgstr "E349: Под курÑором није идентификатор"
+
+msgid "E774: 'operatorfunc' is empty"
+msgstr "E774: 'operatorfunc' је празна"
+
+msgid "E775: Eval feature not available"
+msgstr "E775: Eval могућноÑÑ‚ није доÑтупна"
+
+msgid "Warning: terminal cannot highlight"
+msgstr "Упозорење: терминал не може да иÑтакне текÑÑ‚"
+
+msgid "E348: No string under cursor"
+msgstr "E348: Под курÑором нема Ñтринга"
+
+msgid "E352: Cannot erase folds with current 'foldmethod'"
+msgstr "E352: Са текућим 'foldmethod' не могу да Ñе обришу Ñклапања"
+
+msgid "E664: changelist is empty"
+msgstr "E664: лиÑта промена је празна"
+
+msgid "E662: At start of changelist"
+msgstr "E662: Ðа почетку лиÑте промена"
+
+msgid "E663: At end of changelist"
+msgstr "E663: Ðа крају лиÑте промена"
+
+msgid "Type :qa! and press <Enter> to abandon all changes and exit Vim"
+msgstr ""
+"Откуцајте :qa! и притиÑните <Ентер> да одбаците Ñве измене и напуÑтите Vim"
+
+#, c-format
+msgid "1 line %sed 1 time"
+msgstr "1 линија %sрана 1 пут"
+
+#, c-format
+msgid "1 line %sed %d times"
+msgstr "1 линија %sрана %d пута"
+
+#, c-format
+msgid "%ld lines %sed 1 time"
+msgstr "%ld линија %sрано 1 пут"
+
+#, c-format
+msgid "%ld lines %sed %d times"
+msgstr "%ld линија %sрано %d пута"
+
+#, c-format
+msgid "%ld lines to indent... "
+msgstr "%ld за увлачење... "
+
+msgid "1 line indented "
+msgstr "1 линија увучена "
+
+#, c-format
+msgid "%ld lines indented "
+msgstr "%ld инија увучено "
+
+msgid "E748: No previously used register"
+msgstr "E748: Ðема претходно коришћеног региÑтра"
+
+msgid "cannot yank; delete anyway"
+msgstr "не може да Ñе тргне; ипак обриÑати"
+
+msgid "1 line changed"
+msgstr "1 линија је промењена"
+
+#, c-format
+msgid "%ld lines changed"
+msgstr "%ld линија је промењено"
+
+#, c-format
+msgid "freeing %ld lines"
+msgstr "оÑлобађа Ñе %ld линија"
+
+#, c-format
+msgid " into \"%c"
+msgstr " у \"%c"
+
+#, c-format
+msgid "block of 1 line yanked%s"
+msgstr "блок од 1 линије је тргнут%s"
+
+#, c-format
+msgid "1 line yanked%s"
+msgstr "1 линија је тргнута%s"
+
+#, c-format
+msgid "block of %ld lines yanked%s"
+msgstr "блок од %ld линија је тргнут%s"
+
+#, c-format
+msgid "%ld lines yanked%s"
+msgstr "%ld линија је тргнуто%s"
+
+#, c-format
+msgid "E353: Nothing in register %s"
+msgstr "E353: РегиÑтар %s је празан"
+
+msgid ""
+"\n"
+"--- Registers ---"
+msgstr ""
+"\n"
+"--- РегиÑтри ---"
+
+msgid "Illegal register name"
+msgstr "Ðеважеће име региÑтра"
+
+msgid ""
+"\n"
+"# Registers:\n"
+msgstr ""
+"\n"
+"# РегиÑтри:\n"
+
+#, c-format
+msgid "E574: Unknown register type %d"
+msgstr "E574: Ðепознат тип региÑтра %d"
+
+msgid ""
+"E883: search pattern and expression register may not contain two or more "
+"lines"
+msgstr ""
+"E883: региÑтар за шаблон претраге и израз не може да Ñадржи две или више "
+"линија"
+
+#, c-format
+msgid "%ld Cols; "
+msgstr "%ld Кол; "
+
+#, c-format
+msgid "Selected %s%ld of %ld Lines; %lld of %lld Words; %lld of %lld Bytes"
+msgstr "Изабрано %s%ld од %ld Линија; %lld од %lld Речи; %lld од %lld Бајтова"
+
+#, c-format
+msgid ""
+"Selected %s%ld of %ld Lines; %lld of %lld Words; %lld of %lld Chars; %lld of "
+"%lld Bytes"
+msgstr ""
+"Изабрано %s%ld од %ld Линија; %lld од %lld Речи; %lld од %lld Знака; %lld од "
+"%lld Бајтова"
+
+#, c-format
+msgid "Col %s of %s; Line %ld of %ld; Word %lld of %lld; Byte %lld of %lld"
+msgstr "Кол %s од %s; Линија %ld од %ld; Реч %lld од %lld; Бајт %lld од %lld"
+
+#, c-format
+msgid ""
+"Col %s of %s; Line %ld of %ld; Word %lld of %lld; Char %lld of %lld; Byte %"
+"lld of %lld"
+msgstr ""
+"Кол %s од %s; Линија %ld од %ld; Реч %lld од %lld; Знак %lld од %lld; Бајт %"
+"lld од %lld"
+
+#, c-format
+msgid "(+%lld for BOM)"
+msgstr "(+%lld за BOM)"
+
+msgid "Thanks for flying Vim"
+msgstr "Хвала што летите Ñа Vim"
+
+msgid "E518: Unknown option"
+msgstr "E518: Ðепозната опција"
+
+msgid "E519: Option not supported"
+msgstr "E519: Опција није подржана"
+
+msgid "E520: Not allowed in a modeline"
+msgstr "E520: Ðије довољено у режимÑкој линији"
+
+msgid "E846: Key code not set"
+msgstr "E846: Ðије поÑтављрн код таÑтера"
+
+msgid "E521: Number required after ="
+msgstr "E521: Потребан је број након ="
+
+msgid "E522: Not found in termcap"
+msgstr "E522: Ðије пронађено у termcap"
+
+#, c-format
+msgid "E539: Illegal character <%s>"
+msgstr "E539: Ðедозвољен карактер <%s>"
+
+#, c-format
+msgid "For option %s"
+msgstr "За опцију %s"
+
+msgid "E529: Cannot set 'term' to empty string"
+msgstr "E529: 'term' не може да Ñе поÑтави на празан Ñтринг"
+
+msgid "E530: Cannot change term in GUI"
+msgstr "E530: term не може да Ñе промени из GUI"
+
+msgid "E531: Use \":gui\" to start the GUI"
+msgstr "E531: КориÑтите \":gui\" да покренете GUI"
+
+msgid "E589: 'backupext' and 'patchmode' are equal"
+msgstr "E589: 'backupext' и 'patchmode' Ñу иÑтоветни"
+
+msgid "E834: Conflicts with value of 'listchars'"
+msgstr "E834: У конфликту Ñа вредношћу 'listchars'"
+
+msgid "E835: Conflicts with value of 'fillchars'"
+msgstr "E835: У конфликту Ñа вредношћу 'fillchars'"
+
+msgid "E617: Cannot be changed in the GTK+ 2 GUI"
+msgstr "E617: Ðе може да Ñе промени у GTK+ 2 GUI"
+
+#, c-format
+msgid "E950: Cannot convert between %s and %s"
+msgstr "E950: Ðе може да Ñе конвертује између %s и %s"
+
+msgid "E524: Missing colon"
+msgstr "E524: ÐедоÑтаје двотачка"
+
+msgid "E525: Zero length string"
+msgstr "E525: Стринг дужине нула"
+
+#, c-format
+msgid "E526: Missing number after <%s>"
+msgstr "E526: ÐедоÑтаје број након <%s>"
+
+msgid "E527: Missing comma"
+msgstr "E527: ÐедоÑтаје зарез"
+
+msgid "E528: Must specify a ' value"
+msgstr "E528: Мора да Ñе наведе ' вредноÑÑ‚"
+
+msgid "E595: contains unprintable or wide character"
+msgstr "E595: Ñадржи карактер који не може да Ñе одштампа, или широки карактер"
+
+msgid "E596: Invalid font(s)"
+msgstr "E596: ÐеиÑправни фонт(ови)"
+
+msgid "E597: can't select fontset"
+msgstr "E597: fontset не може да Ñе изабере"
+
+msgid "E598: Invalid fontset"
+msgstr "E598: ÐеиÑправан fontset"
+
+msgid "E533: can't select wide font"
+msgstr "E533: широки фонт не може да Ñе изабере"
+
+msgid "E534: Invalid wide font"
+msgstr "E534: ÐеиÑправан широки фонт"
+
+#, c-format
+msgid "E535: Illegal character after <%c>"
+msgstr "E535: Ðеважећи карактер након <%c>"
+
+msgid "E536: comma required"
+msgstr "E536: потребан зарез"
+
+#, c-format
+msgid "E537: 'commentstring' must be empty or contain %s"
+msgstr "E537: 'commentstring' мора бити празно или да Ñадржи %s"
+
+msgid "E538: No mouse support"
+msgstr "E538: Ðема подршке за миша"
+
+msgid "E540: Unclosed expression sequence"
+msgstr "E540: Ðиз израза није затворен"
+
+msgid "E541: too many items"
+msgstr "E541: превише Ñтавки"
+
+msgid "E542: unbalanced groups"
+msgstr "E542: неуравнотежене групе"
+
+msgid "E946: Cannot make a terminal with running job modifiable"
+msgstr ""
+"E946: Терминал Ñа задатком који Ñе извршава не може да Ñе учини измењивим"
+
+msgid "E590: A preview window already exists"
+msgstr "E590: Прозор за преглед већ поÑтоји"
+
+msgid "W17: Arabic requires UTF-8, do ':set encoding=utf-8'"
+msgstr "W17: ÐрапÑки захтева UTF-8, извршите ':set encoding=utf-8'"
+
+msgid "E954: 24-bit colors are not supported on this environment"
+msgstr "E954: Ово окружење не подржава 24-битне боје"
+
+#, c-format
+msgid "E593: Need at least %d lines"
+msgstr "E593: Потребно је најмање %d линија"
+
+#, c-format
+msgid "E594: Need at least %d columns"
+msgstr "E594: Потребно је најмање %d колона"
+
+#, c-format
+msgid "E355: Unknown option: %s"
+msgstr "E355: Ðепозната опција: %s"
+
+#, c-format
+msgid "E521: Number required: &%s = '%s'"
+msgstr "E521: Захтева Ñе број: &%s = '%s'"
+
+msgid ""
+"\n"
+"--- Terminal codes ---"
+msgstr ""
+"\n"
+"--- Кодови терминала ---"
+
+msgid ""
+"\n"
+"--- Global option values ---"
+msgstr ""
+"\n"
+"--- ВредноÑти глобалних опција ---"
+
+msgid ""
+"\n"
+"--- Local option values ---"
+msgstr ""
+"\n"
+"--- ВредноÑти локалних опција ---"
+
+msgid ""
+"\n"
+"--- Options ---"
+msgstr ""
+"\n"
+"--- Опције ---"
+
+msgid "E356: get_varp ERROR"
+msgstr "E356: get_varp ГРЕШКÐ"
+
+#, c-format
+msgid "E357: 'langmap': Matching character missing for %s"
+msgstr "E357: 'langmap': ÐедоÑтаје одговарајући карактер за %s"
+
+#, c-format
+msgid "E358: 'langmap': Extra characters after semicolon: %s"
+msgstr "E358: 'langmap': Има још карактера након тачказареза: %s"
+
+msgid "cannot open "
+msgstr "не може да Ñе отвори "
+
+msgid "VIM: Can't open window!\n"
+msgstr "VIM: Прозор не може да Ñе отвори!\n"
+
+msgid "Need Amigados version 2.04 or later\n"
+msgstr "Потребан је Amigados верзија 2.04 или каÑнији\n"
+
+#, c-format
+msgid "Need %s version %ld\n"
+msgstr "Потребан је %s верзија %ld\n"
+
+msgid "Cannot open NIL:\n"
+msgstr "Ðе може да Ñе отвори NIL:\n"
+
+msgid "Cannot create "
+msgstr "Ðе може да Ñе креира "
+
+#, c-format
+msgid "Vim exiting with %d\n"
+msgstr "Vim излази Ñа %d\n"
+
+msgid "cannot change console mode ?!\n"
+msgstr "конзолни режим не може да Ñе промени ?!\n"
+
+msgid "mch_get_shellsize: not a console??\n"
+msgstr "mch_get_shellsize: није конзола??\n"
+
+msgid "E360: Cannot execute shell with -f option"
+msgstr "E360: Командно окружење не може да Ñе изврши Ñа -f опцијом"
+
+msgid "Cannot execute "
+msgstr "Ðе може да Ñе изврши "
+
+msgid "shell "
+msgstr "командно окружење "
+
+msgid " returned\n"
+msgstr " вратило\n"
+
+msgid "ANCHOR_BUF_SIZE too small."
+msgstr "ANCHOR_BUF_SIZE Ñувише мали."
+
+msgid "I/O ERROR"
+msgstr "У/И ГРЕШКÐ"
+
+msgid "Message"
+msgstr "Порука"
+
+msgid "E237: Printer selection failed"
+msgstr "E237: Избор штампача није уÑпео"
+
+#, c-format
+msgid "to %s on %s"
+msgstr "у %s на %s"
+
+#, c-format
+msgid "E613: Unknown printer font: %s"
+msgstr "E613: Ðепознат фонт штампача: %s"
+
+#, c-format
+msgid "E238: Print error: %s"
+msgstr "E238: Грешка код штампања: %s"
+
+#, c-format
+msgid "Printing '%s'"
+msgstr "Штампа Ñе '%s'"
+
+#, c-format
+msgid "E244: Illegal charset name \"%s\" in font name \"%s\""
+msgstr "E244: Ðедозвољено име Ñета карактера \"%s\" у имену фонту \"%s\""
+
+#, c-format
+msgid "E244: Illegal quality name \"%s\" in font name \"%s\""
+msgstr "E244: Ðедозвољено име варијанте \"%s\" у имену фонту \"%s\""
+
+#, c-format
+msgid "E245: Illegal char '%c' in font name \"%s\""
+msgstr "E245: ÐеиÑправан карактер '%c' у имену фонта \"%s\""
+
+#, c-format
+msgid "Opening the X display took %ld msec"
+msgstr "Отварање X приказа је трајало %ld мÑек"
+
+msgid ""
+"\n"
+"Vim: Got X error\n"
+msgstr ""
+"\n"
+"Vim: Дошло је до X грешке\n"
+
+msgid "Testing the X display failed"
+msgstr "ТеÑтирање X приказа није уÑпело"
+
+msgid "Opening the X display timed out"
+msgstr "ИÑтекло је макÑимално време за отварање X приказа"
+
+msgid ""
+"\n"
+"Could not get security context for "
+msgstr ""
+"\n"
+"Ðије могао да Ñе очита безбедноÑни контекÑÑ‚ за "
+
+msgid ""
+"\n"
+"Could not set security context for "
+msgstr ""
+"\n"
+"Ðије могао да Ñе поÑтави безбедноÑни контекÑÑ‚ за "
+
+#, c-format
+msgid "Could not set security context %s for %s"
+msgstr "БезбедноÑни контекÑÑ‚ %s за %s није могао да Ñе поÑтави"
+
+#, c-format
+msgid "Could not get security context %s for %s. Removing it!"
+msgstr "БезбедноÑни контекÑÑ‚ %s за %s није могао да Ñе очита. Уклања Ñе!"
+
+msgid ""
+"\n"
+"Cannot execute shell sh\n"
+msgstr ""
+"\n"
+"Командно окружење sh не може да Ñе изврши\n"
+
+msgid ""
+"\n"
+"shell returned "
+msgstr ""
+"\n"
+"командно окружење је вратило "
+
+msgid ""
+"\n"
+"Cannot create pipes\n"
+msgstr ""
+"\n"
+"Токови података не могу да Ñе креирају\n"
+
+msgid ""
+"\n"
+"Cannot fork\n"
+msgstr ""
+"\n"
+"Рачвање није могуће\n"
+
+msgid ""
+"\n"
+"Cannot execute shell "
+msgstr ""
+"\n"
+"Командно окружење не може да Ñе изврши "
+
+msgid ""
+"\n"
+"Command terminated\n"
+msgstr ""
+"\n"
+"Команда је прекинута\n"
+
+msgid "XSMP lost ICE connection"
+msgstr "XSMP је изгубио ICE везу"
+
+#, c-format
+msgid "dlerror = \"%s\""
+msgstr "dlerror = \"%s\""
+
+msgid "Opening the X display failed"
+msgstr "Отварање X приказа није уÑпело"
+
+msgid "XSMP handling save-yourself request"
+msgstr "XSMP опÑлужује Ñачувај-Ñе захтев"
+
+msgid "XSMP opening connection"
+msgstr "XSMP отвара везу"
+
+msgid "XSMP ICE connection watch failed"
+msgstr "XSMP ICE надгледање везе није уÑпело"
+
+#, c-format
+msgid "XSMP SmcOpenConnection failed: %s"
+msgstr "XSMP SmcOpenConnection није уÑпело: %s"
+
+msgid "At line"
+msgstr "Код линије"
+
+msgid "Could not load vim32.dll!"
+msgstr "vim32.dll није могла да Ñе учита!"
+
+msgid "VIM Error"
+msgstr "VIM Грешка"
+
+msgid "Could not fix up function pointers to the DLL!"
+msgstr "Показивачи на функције у DLL-у ниÑу могли да Ñе поправе!"
+
+#, c-format
+msgid "Vim: Caught %s event\n"
+msgstr "Vim: Ухваћен је %s догађај\n"
+
+msgid "close"
+msgstr "затварање"
+
+msgid "logoff"
+msgstr "одјављивање"
+
+msgid "shutdown"
+msgstr "иÑкључивање"
+
+msgid "E371: Command not found"
+msgstr "E371: Команда није пронађена"
+
+msgid ""
+"VIMRUN.EXE not found in your $PATH.\n"
+"External commands will not pause after completion.\n"
+"See :help win32-vimrun for more information."
+msgstr ""
+"VIMRUN.EXE није пронађен у вашем $PATH.\n"
+"ЕкÑтерне команде неће моћи да Ñе паузирају након завршетка.\n"
+"Погледајте :help win32-vimrun за више информација."
+
+msgid "Vim Warning"
+msgstr "Vim Упозорење"
+
+#, c-format
+msgid "shell returned %d"
+msgstr "командно окружење је вратило %d"
+
+msgid "E926: Current location list was changed"
+msgstr "E926: Текућа лиÑта локација је промењена"
+
+#, c-format
+msgid "E372: Too many %%%c in format string"
+msgstr "E372: Превише %%%c Ñтрингу формата"
+
+#, c-format
+msgid "E373: Unexpected %%%c in format string"
+msgstr "E373: Ðеочекивано %%%c Ñтрингу формата"
+
+msgid "E374: Missing ] in format string"
+msgstr "E374: ÐедоÑтаје ] у Ñтрингу формата"
+
+#, c-format
+msgid "E375: Unsupported %%%c in format string"
+msgstr "E375: Ðеподржано %%%c у Ñтрингу формата"
+
+#, c-format
+msgid "E376: Invalid %%%c in format string prefix"
+msgstr "E376: Ðеважеће %%%c у префикÑу Ñтринга формата"
+
+#, c-format
+msgid "E377: Invalid %%%c in format string"
+msgstr "E377: Ðеважеће %%%c у Ñтрингу формата"
+
+msgid "E378: 'errorformat' contains no pattern"
+msgstr "E378: 'errorformat' не Ñадржи шаблон"
+
+msgid "E379: Missing or empty directory name"
+msgstr "E379: Име директоријума недоÑтаје или је празно"
+
+msgid "E553: No more items"
+msgstr "E553: Ðема више Ñтавки"
+
+msgid "E924: Current window was closed"
+msgstr "E924: Текући прозор је затворен"
+
+msgid "E925: Current quickfix was changed"
+msgstr "E925: Текући quickfix је промењен"
+
+#, c-format
+msgid "(%d of %d)%s%s: "
+msgstr "(%d од %d)%s%s: "
+
+msgid " (line deleted)"
+msgstr " (линија обриÑана)"
+
+#, c-format
+msgid "%serror list %d of %d; %d errors "
+msgstr "%sлиÑта грешака %d од %d; %d грешака "
+
+msgid "E380: At bottom of quickfix stack"
+msgstr "E380: Ðа дну quickfix Ñтека"
+
+msgid "E381: At top of quickfix stack"
+msgstr "E381: Ðа врху quickfix Ñтека"
+
+msgid "No entries"
+msgstr "Ðема уноÑа"
+
+msgid "Error file"
+msgstr "Датотека грешака"
+
+msgid "E683: File name missing or invalid pattern"
+msgstr "E683: ÐедоÑтаје име датотеке или неважећи шаблон"
+
+#, c-format
+msgid "Cannot open file \"%s\""
+msgstr "Датотека \"%s\" не може да Ñе отвори"
+
+msgid "E681: Buffer is not loaded"
+msgstr "E681: Бафер није учитан"
+
+msgid "E777: String or List expected"
+msgstr "E777: Очекује Ñе String или List"
+
+#, c-format
+msgid "E369: invalid item in %s%%[]"
+msgstr "E369: неважећа Ñтавка у %s%%[]"
+
+#, c-format
+msgid "E769: Missing ] after %s["
+msgstr "E769: ÐедоÑтаје ] након %s["
+
+msgid "E944: Reverse range in character class"
+msgstr "E944: Обрнути опÑег у карактер клаÑи"
+
+msgid "E945: Range too large in character class"
+msgstr "E945: Превелики опÑег у карактер клаÑи"
+
+#, c-format
+msgid "E53: Unmatched %s%%("
+msgstr "E53: Ðеупарена %s%%("
+
+#, c-format
+msgid "E54: Unmatched %s("
+msgstr "E54: Ðеупарена %s("
+
+#, c-format
+msgid "E55: Unmatched %s)"
+msgstr "E55: Ðеупарена %s)"
+
+msgid "E66: \\z( not allowed here"
+msgstr "E66: \\z( овде није дозвољено"
+
+msgid "E67: \\z1 - \\z9 not allowed here"
+msgstr "E67: \\z1 - \\z9 овде ниÑу дозвољени"
+
+#, c-format
+msgid "E69: Missing ] after %s%%["
+msgstr "E69: ÐедоÑтаје ] након %s%%["
+
+#, c-format
+msgid "E70: Empty %s%%[]"
+msgstr "E70: Празан %s%%[]"
+
+msgid "E65: Illegal back reference"
+msgstr "E65: Ðеважећа повратна референца"
+
+msgid "E339: Pattern too long"
+msgstr "E339: Шаблон је предугачак"
+
+msgid "E50: Too many \\z("
+msgstr "E50: Превише \\z("
+
+#, c-format
+msgid "E51: Too many %s("
+msgstr "E51: Превише %s("
+
+msgid "E52: Unmatched \\z("
+msgstr "E52: Ðеупарено \\z("
+
+#, c-format
+msgid "E59: invalid character after %s@"
+msgstr "E59: неважећи карактер након %s@"
+
+#, c-format
+msgid "E60: Too many complex %s{...}s"
+msgstr "E60: Превише комплекÑних %s{...}s"
+
+#, c-format
+msgid "E61: Nested %s*"
+msgstr "E61: Угњеждено %s*"
+
+#, c-format
+msgid "E62: Nested %s%c"
+msgstr "E62: Угњеждено %s%c"
+
+msgid "E63: invalid use of \\_"
+msgstr "E63: неиÑправна употреба \\_"
+
+#, c-format
+msgid "E64: %s%c follows nothing"
+msgstr "E64: %s%c je иза ничега"
+
+msgid "E68: Invalid character after \\z"
+msgstr "E68: Ðеважећи карактер након \\z"
+
+#, c-format
+msgid "E678: Invalid character after %s%%[dxouU]"
+msgstr "E678: Ðеважећи карактер након %s%%[dxouU]"
+
+#, c-format
+msgid "E71: Invalid character after %s%%"
+msgstr "E71: Ðеважећи карактер након %s%%"
+
+#, c-format
+msgid "E554: Syntax error in %s{...}"
+msgstr "E554: СинтакÑна грешка у %s{...}"
+
+msgid "External submatches:\n"
+msgstr "Спољна подпоклапања:\n"
+
+#, c-format
+msgid "E888: (NFA regexp) cannot repeat %s"
+msgstr "E888: (NFA regexp) не може да Ñе понови %s"
+
+msgid ""
+"E864: \\%#= can only be followed by 0, 1, or 2. The automatic engine will be "
+"used "
+msgstr ""
+"E864: Иза \\%#= може да Ñледи једино 0, 1, или 2. КориÑтиће Ñе аутоматÑки "
+"енџин "
+
+msgid "Switching to backtracking RE engine for pattern: "
+msgstr "Пребацивање на backtracking RE енџин за шаблон: "
+
+msgid "E865: (NFA) Regexp end encountered prematurely"
+msgstr "E865: Крај (NFA) Regexp израза је доÑтигнут прерано"
+
+#, c-format
+msgid "E866: (NFA regexp) Misplaced %c"
+msgstr "E866: (NFA regexp) %c је на погрешном меÑту"
+
+#, c-format
+msgid "E877: (NFA regexp) Invalid character class: %ld"
+msgstr "E877: (NFA regexp) Ðеважећа карактер клаÑа: %ld"
+
+#, c-format
+msgid "E867: (NFA) Unknown operator '\\z%c'"
+msgstr "E867: (NFA) Ðепознати оператор '\\z%c'"
+
+msgid "E951: \\% value too large"
+msgstr "E951: ВредноÑÑ‚ \\% је предугачка"
+
+#, c-format
+msgid "E867: (NFA) Unknown operator '\\%%%c'"
+msgstr "E867: (NFA) Ðепознати оператор '\\%%%c'"
+
+msgid "E868: Error building NFA with equivalence class!"
+msgstr "E868: Грешка при грађењу NFA Ñа клаÑом еквиваленције!"
+
+#, c-format
+msgid "E869: (NFA) Unknown operator '\\@%c'"
+msgstr "E869: (NFA) Ðепознати оператор '\\@%c'"
+
+msgid "E870: (NFA regexp) Error reading repetition limits"
+msgstr "E870: (NFA regexp) Грешка при читању граница понављања"
+
+msgid "E871: (NFA regexp) Can't have a multi follow a multi"
+msgstr "E871: (NFA regexp) Мулти не може Ñледи иза мулти"
+
+msgid "E872: (NFA regexp) Too many '('"
+msgstr "E872: (NFA regexp) Превише '('"
+
+msgid "E879: (NFA regexp) Too many \\z("
+msgstr "E879: (NFA regexp) Превише \\z("
+
+msgid "E873: (NFA regexp) proper termination error"
+msgstr "E873: (NFA regexp) грешка правилне терминације"
+
+msgid "E874: (NFA) Could not pop the stack!"
+msgstr "E874: (NFA) Скидање Ñа Ñтека није уÑпело!"
+
+msgid ""
+"E875: (NFA regexp) (While converting from postfix to NFA), too many states "
+"left on stack"
+msgstr ""
+"E875: (NFA regexp) (Док је вршена конверзија из postfix у NFA), превише "
+"Ñтања је оÑтало на Ñтеку"
+
+msgid "E876: (NFA regexp) Not enough space to store the whole NFA "
+msgstr ""
+"E876: (NFA regexp) Ðема довољно проÑтора да Ñе уÑкладишти комплетан NFA "
+
+msgid "E878: (NFA) Could not allocate memory for branch traversal!"
+msgstr "E878: (NFA) Ðије могла да Ñе алоцира меморија за обилазак грана!"
+
+msgid ""
+"Could not open temporary log file for writing, displaying on stderr... "
+msgstr ""
+"Привремена лог датотека није могла да Ñе отвори за упиÑ, приказује Ñе на "
+"stderr... "
+
+#, c-format
+msgid "(NFA) COULD NOT OPEN %s !"
+msgstr "(NFA) %s ÐЕ МОЖЕ ДРСЕ ОТВОРИ !"
+
+msgid "Could not open temporary log file for writing "
+msgstr "Привремена лог датотека није могла да Ñе отвори за ÑƒÐ¿Ð¸Ñ "
+
+msgid " VREPLACE"
+msgstr "ВЗÐМЕÐÐ"
+
+msgid " REPLACE"
+msgstr " ЗÐМЕÐÐ"
+
+msgid " REVERSE"
+msgstr " ОБРÐУТО"
+
+msgid " INSERT"
+msgstr " УМЕТÐЊЕ"
+
+msgid " (insert)"
+msgstr " (уметање)"
+
+msgid " (replace)"
+msgstr " (замена)"
+
+msgid " (vreplace)"
+msgstr " (взамена)"
+
+msgid " Hebrew"
+msgstr " хебрејÑки"
+
+msgid " Arabic"
+msgstr " арапÑки"
+
+msgid " (paste)"
+msgstr " (налепи)"
+
+msgid " VISUAL"
+msgstr " ВИЗУЕЛÐО"
+
+msgid " VISUAL LINE"
+msgstr " ВИЗУЕЛÐРЛИÐИЈÐ"
+
+msgid " VISUAL BLOCK"
+msgstr " ВИЗУЕЛÐИ БЛОК"
+
+msgid " SELECT"
+msgstr " ИЗБОР"
+
+msgid " SELECT LINE"
+msgstr " ИЗБОР ЛИÐИЈÐ"
+
+msgid " SELECT BLOCK"
+msgstr " ИЗБОР БЛОКÐ"
+
+msgid "recording"
+msgstr "Ñнимање"
+
+#, c-format
+msgid "E383: Invalid search string: %s"
+msgstr "E383: ÐеиÑправан Ñтринг за претрагу: %s"
+
+#, c-format
+msgid "E384: search hit TOP without match for: %s"
+msgstr "E384: претрага је доÑтигла ВРХ без подударања за: %s"
+
+#, c-format
+msgid "E385: search hit BOTTOM without match for: %s"
+msgstr "E385: претрага је доÑтигла ДÐО без подударања за: %s"
+
+msgid "E386: Expected '?' or '/' after ';'"
+msgstr "E386: Ðакон ';' Ñе очекује '?' или '/'"
+
+msgid " (includes previously listed match)"
+msgstr " (укључује претходно наведена подударања)"
+
+msgid "--- Included files "
+msgstr "--- Прикључене датотеке "
+
+msgid "not found "
+msgstr "ниÑу пронађене "
+
+msgid "in path ---\n"
+msgstr "у путањи ---\n"
+
+msgid " (Already listed)"
+msgstr " (Већ наведено)"
+
+msgid " NOT FOUND"
+msgstr " ÐИЈЕ ПРОÐÐЂЕÐО"
+
+#, c-format
+msgid "Scanning included file: %s"
+msgstr "Прегледање уметнуте датотеке: %s"
+
+#, c-format
+msgid "Searching included file %s"
+msgstr "Претраживање уметнуте датотеке %s"
+
+msgid "E387: Match is on current line"
+msgstr "E387: Подударање је у текућој линији"
+
+msgid "All included files were found"
+msgstr "Све уметнуте датотеке Ñу пронађене"
+
+msgid "No included files"
+msgstr "Ðема уметнутих датотека"
+
+msgid "E388: Couldn't find definition"
+msgstr "E388: Дефиниција не може да Ñе пронађе"
+
+msgid "E389: Couldn't find pattern"
+msgstr "E389: Шаблон за претрагу није пронађен"
+
+msgid "Substitute "
+msgstr "Замена "
+
+#, c-format
+msgid ""
+"\n"
+"# Last %sSearch Pattern:\n"
+"~"
+msgstr ""
+"\n"
+"# ПоÑледњи %sШаблон Претраге:\n"
+"~"
+
+msgid "E756: Spell checking is not enabled"
+msgstr "E756: Провера правопиÑа није омогућена"
+
+#, c-format
+msgid "Warning: Cannot find word list \"%s_%s.spl\" or \"%s_ascii.spl\""
+msgstr ""
+"Упозорење: ЛиÑта речи \"%s_%s.spl\" или \"%s_ascii.spl\" не може да Ñе "
+"пронађе"
+
+#, c-format
+msgid "Warning: Cannot find word list \"%s.%s.spl\" or \"%s.ascii.spl\""
+msgstr ""
+"Упозорење: ЛиÑта речи \"%s.%s.spl\" или \"%s.ascii.spl\" не може да Ñе "
+"пронађе"
+
+msgid "E797: SpellFileMissing autocommand deleted buffer"
+msgstr "E797: SpellFileMissing аутокоманда је обриÑала бафер"
+
+#, c-format
+msgid "Warning: region %s not supported"
+msgstr "Упозорење: регион %s није подржан"
+
+msgid "Sorry, no suggestions"
+msgstr "Жао нам је, нема ÑугеÑтија"
+
+#, c-format
+msgid "Sorry, only %ld suggestions"
+msgstr "Жао нам је, Ñамо %ld ÑугеÑтија"
+
+#, c-format
+msgid "Change \"%.*s\" to:"
+msgstr "Променити \"%.*s\" у:"
+
+#, c-format
+msgid " < \"%.*s\""
+msgstr " < \"%.*s\""
+
+msgid "E752: No previous spell replacement"
+msgstr "E752: Ðема претходне правопиÑне замене"
+
+#, c-format
+msgid "E753: Not found: %s"
+msgstr "E753: Ðије пронађено: %s"
+
+msgid "E758: Truncated spell file"
+msgstr "E758: ПравопиÑна датотека је прекраћена"
+
+#, c-format
+msgid "Trailing text in %s line %d: %s"
+msgstr "ТекÑÑ‚ вишак у %s линија %d: %s"
+
+#, c-format
+msgid "Affix name too long in %s line %d: %s"
+msgstr "Име наÑтавка је предугачко у %s линија %d: %s"
+
+msgid "E761: Format error in affix file FOL, LOW or UPP"
+msgstr "E761: Грешка формата у датотеци наÑтавака FOL, LOW или UPP"
+
+msgid "E762: Character in FOL, LOW or UPP is out of range"
+msgstr "E762: Карактер у FOL, LOW или UPP је ван опÑега"
+
+msgid "Compressing word tree..."
+msgstr "Стабло речи Ñе компреÑује..."
+
+#, c-format
+msgid "Reading spell file \"%s\""
+msgstr "Читање правопиÑне датотеке \"%s\""
+
+msgid "E757: This does not look like a spell file"
+msgstr "E757: Ово не изгледа као правопиÑна датотека"
+
+msgid "E771: Old spell file, needs to be updated"
+msgstr "E771: Стара правопиÑна датотека, потребно је да Ñе оÑвежи"
+
+msgid "E772: Spell file is for newer version of Vim"
+msgstr "E772: ПравопиÑна датотека је за новију верзију Vim-а"
+
+msgid "E770: Unsupported section in spell file"
+msgstr "E770: Ðеподржана Ñекција у правопиÑној датотеци"
+
+#, c-format
+msgid "E778: This does not look like a .sug file: %s"
+msgstr "E778: Ово не изгледа као .sug датотека: %s"
+
+#, c-format
+msgid "E779: Old .sug file, needs to be updated: %s"
+msgstr "E779: Стара .sug датотека, потребно је да Ñе оÑвежи: %s"
+
+#, c-format
+msgid "E780: .sug file is for newer version of Vim: %s"
+msgstr "E780: .sug датотека је за новију верзију Vim-а: %s"
+
+#, c-format
+msgid "E781: .sug file doesn't match .spl file: %s"
+msgstr "E781: .sug датотека не одговара .spl датотеци: %s"
+
+#, c-format
+msgid "E782: error while reading .sug file: %s"
+msgstr "E782: грешка приликом читања .sug датотеке: %s"
+
+#, c-format
+msgid "Reading affix file %s..."
+msgstr "Читање датотеке наÑтавака %s..."
+
+#, c-format
+msgid "Conversion failure for word in %s line %d: %s"
+msgstr "ÐеуÑпешна конверзија за реч у %s линија %d: %s"
+
+#, c-format
+msgid "Conversion in %s not supported: from %s to %s"
+msgstr "Конверзија у %s није подржана: из %s у %s"
+
+#, c-format
+msgid "Conversion in %s not supported"
+msgstr "Конверзија у %s није подржана"
+
+#, c-format
+msgid "Invalid value for FLAG in %s line %d: %s"
+msgstr "Ðеважећа вредноÑÑ‚ за FLAG у %s линија %d: %s"
+
+#, c-format
+msgid "FLAG after using flags in %s line %d: %s"
+msgstr "FLAG након коришћења индикатора у %s линија %d: %s"
+
+#, c-format
+msgid ""
+"Defining COMPOUNDFORBIDFLAG after PFX item may give wrong results in %s line "
+"%d"
+msgstr ""
+"ДефиниÑање COMPOUNDFORBIDFLAG након PFX Ñтавке може да дâ погрешне резултате "
+"у %s line %d"
+
+#, c-format
+msgid ""
+"Defining COMPOUNDPERMITFLAG after PFX item may give wrong results in %s line "
+"%d"
+msgstr ""
+"ДефиниÑање COMPOUNDPERMITFLAG након PFX Ñтавке може да дâ погрешне резултате "
+"у %s line %d"
+
+#, c-format
+msgid "Wrong COMPOUNDRULES value in %s line %d: %s"
+msgstr "Погрешна COMPOUNDRULES вредноÑÑ‚ у %s линија %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDWORDMAX value in %s line %d: %s"
+msgstr "Погрешна COMPOUNDWORDMAX вредноÑÑ‚ у %s линија %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDMIN value in %s line %d: %s"
+msgstr "Погрешна COMPOUNDMIN вредноÑÑ‚ у %s линија %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDSYLMAX value in %s line %d: %s"
+msgstr "Погрешна COMPOUNDSYLMAX вредноÑÑ‚ у %s линија %d: %s"
+
+#, c-format
+msgid "Wrong CHECKCOMPOUNDPATTERN value in %s line %d: %s"
+msgstr "Погрешна CHECKCOMPOUNDPATTERN вредноÑÑ‚ у %s линија %d: %s"
+
+#, c-format
+msgid "Different combining flag in continued affix block in %s line %d: %s"
+msgstr ""
+"Различит индикатор комбиновања у наÑтављеном блоку наÑтавака у %s линија %d: "
+"%s"
+
+#, c-format
+msgid "Duplicate affix in %s line %d: %s"
+msgstr "Дупликат наÑтавка у %s линија %d: %s"
+
+#, c-format
+msgid ""
+"Affix also used for BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST in %s "
+"line %d: %s"
+msgstr ""
+"ÐаÑтавак Ñе такође кориÑти за BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST у %s"
+"линија %d: %s"
+
+#, c-format
+msgid "Expected Y or N in %s line %d: %s"
+msgstr "Очекује Ñе Y или N у %s линија %d: %s"
+
+#, c-format
+msgid "Broken condition in %s line %d: %s"
+msgstr "Ðеправилан уÑлов у %s линија %d: %s"
+
+#, c-format
+msgid "Expected REP(SAL) count in %s line %d"
+msgstr "Очекује Ñе број REP(SAL) у %s линија %d"
+
+#, c-format
+msgid "Expected MAP count in %s line %d"
+msgstr "Очекује Ñе број MAP у %s линија %d"
+
+#, c-format
+msgid "Duplicate character in MAP in %s line %d"
+msgstr "Дупликат карактера у MAP у %s линија %d"
+
+#, c-format
+msgid "Unrecognized or duplicate item in %s line %d: %s"
+msgstr "ÐепрепоÑната или дупла Ñтавка у %s линија %d: %s"
+
+#, c-format
+msgid "Missing FOL/LOW/UPP line in %s"
+msgstr "ÐедоÑтаје FOL/LOW/UPP линија у %s"
+
+msgid "COMPOUNDSYLMAX used without SYLLABLE"
+msgstr "COMPOUNDSYLMAX Ñе кориÑти без SYLLABLE"
+
+msgid "Too many postponed prefixes"
+msgstr "Превише закашњених префикÑа"
+
+msgid "Too many compound flags"
+msgstr "Превише индикатора Ñложеница"
+
+msgid "Too many postponed prefixes and/or compound flags"
+msgstr "Превише закашњених префикÑа и/или индикатора Ñложеница"
+
+#, c-format
+msgid "Missing SOFO%s line in %s"
+msgstr "ÐедоÑтаје SOFO%s линија у %s"
+
+#, c-format
+msgid "Both SAL and SOFO lines in %s"
+msgstr "И SAL и SOFO линије у %s"
+
+#, c-format
+msgid "Flag is not a number in %s line %d: %s"
+msgstr "Индикатор није број у %s линија %d: %s"
+
+#, c-format
+msgid "Illegal flag in %s line %d: %s"
+msgstr "Ðеважећи индикатор у %s линија %d: %s"
+
+#, c-format
+msgid "%s value differs from what is used in another .aff file"
+msgstr ""
+"%s вредноÑÑ‚ Ñе разликује од онога што је коришћено у другој .aff датотеци"
+
+#, c-format
+msgid "Reading dictionary file %s..."
+msgstr "Читање датотеке речника %s..."
+
+#, c-format
+msgid "E760: No word count in %s"
+msgstr "E760: Ðема броја речи у %s"
+
+#, c-format
+msgid "line %6d, word %6ld - %s"
+msgstr "линија %6d, реч %6ld - %s"
+
+#, c-format
+msgid "Duplicate word in %s line %d: %s"
+msgstr "Дупликат речи у %s линија %d: %s"
+
+#, c-format
+msgid "First duplicate word in %s line %d: %s"
+msgstr "Прва реч дупликат у %s линија %d: %s"
+
+#, c-format
+msgid "%d duplicate word(s) in %s"
+msgstr "%d реч(и) дупликат(а) у %s"
+
+#, c-format
+msgid "Ignored %d word(s) with non-ASCII characters in %s"
+msgstr "ИгнориÑана/о %d реч(и) Ñа не-ASCII карактерима у %s"
+
+#, c-format
+msgid "Reading word file %s..."
+msgstr "Читање датотеке речи %s..."
+
+#, c-format
+msgid "Duplicate /encoding= line ignored in %s line %d: %s"
+msgstr "Дупликат /encoding= линија је игнориÑана у %s линија %d: %s"
+
+#, c-format
+msgid "/encoding= line after word ignored in %s line %d: %s"
+msgstr "/encoding= линија након речи је игнориÑана у %s линија %d: %s"
+
+#, c-format
+msgid "Duplicate /regions= line ignored in %s line %d: %s"
+msgstr "Дупликат /regions= линија је игнориÑана у %s линија %d: %s"
+
+#, c-format
+msgid "Too many regions in %s line %d: %s"
+msgstr "Превише региона у %s линија %d: %s"
+
+#, c-format
+msgid "/ line ignored in %s line %d: %s"
+msgstr "/ линија игнориÑана у %s линија %d: %s"
+
+#, c-format
+msgid "Invalid region nr in %s line %d: %s"
+msgstr "Ðеважећи број региона у %s линија %d: %s"
+
+#, c-format
+msgid "Unrecognized flags in %s line %d: %s"
+msgstr "Ðепрепознати индикатори у %s линија %d: %s"
+
+#, c-format
+msgid "Ignored %d words with non-ASCII characters"
+msgstr "ИгнориÑано је %d рћи Ñа не-ASCII карактерима"
+
+msgid "E845: Insufficient memory, word list will be incomplete"
+msgstr "E845: Ðедовољно меморије, лиÑта речи неће бити комплетна"
+
+#, c-format
+msgid "Compressed %d of %d nodes; %d (%d%%) remaining"
+msgstr "КомпреÑовано је %d од %d чворова; преоÑтало је још %d (%d%%)"
+
+msgid "Reading back spell file..."
+msgstr "Читање правопиÑне датотеке..."
+
+msgid "Performing soundfolding..."
+msgstr "Извођење Ñклапања по звучноÑти..."
+
+#, c-format
+msgid "Number of words after soundfolding: %ld"
+msgstr "Број речи након Ñклапања по звучноÑти: %ld"
+
+#, c-format
+msgid "Total number of words: %d"
+msgstr "Укупан број речи: %d"
+
+#, c-format
+msgid "Writing suggestion file %s..."
+msgstr "УпиÑивање датотеке предлога %s..."
+
+#, c-format
+msgid "Estimated runtime memory use: %d bytes"
+msgstr "Процењена потребна величина меморије у време извршавања: %d бајтова"
+
+msgid "E751: Output file name must not have region name"
+msgstr "E751: Име излазне датотеке не Ñме да има име региона"
+
+#, c-format
+msgid "E754: Only up to %ld regions supported"
+msgstr "E754: Подржано је Ñамо до %ld региона"
+
+#, c-format
+msgid "E755: Invalid region in %s"
+msgstr "E755: Ðеважећи регион у %s"
+
+msgid "Warning: both compounding and NOBREAK specified"
+msgstr "Упозорење: наведени Ñу и Ñлагање и NOBREAK"
+
+#, c-format
+msgid "Writing spell file %s..."
+msgstr "УпиÑивање правопиÑне датотеке %s..."
+
+msgid "Done!"
+msgstr "Завршено!"
+
+#, c-format
+msgid "E765: 'spellfile' does not have %ld entries"
+msgstr "E765: 'spellfile' не Ñадржи %ld Ñтавке"
+
+#, c-format
+msgid "Word '%.*s' removed from %s"
+msgstr "Реч '%.*s' је уклоњена из %s"
+
+#, c-format
+msgid "Word '%.*s' added to %s"
+msgstr "Реч '%.*s' је додата у %s"
+
+msgid "E763: Word characters differ between spell files"
+msgstr "E763: Карактери у речи Ñе разликују између правопиÑних датотека"
+
+msgid "E783: duplicate char in MAP entry"
+msgstr "E783: карактер дупликат у MAP Ñтавци"
+
+msgid "No Syntax items defined for this buffer"
+msgstr "За оба јбафер ниÑу дефиниÑане ÑинтакÑне Ñтавке"
+
+msgid "syntax conceal on"
+msgstr "Ñкривање ÑинтакÑе укључено"
+
+msgid "syntax conceal off"
+msgstr "Ñкривање ÑинтакÑе иÑкључено"
+
+#, c-format
+msgid "E390: Illegal argument: %s"
+msgstr "E390: Ðеважећи аргумент: %s"
+
+msgid "syntax case ignore"
+msgstr "мала/велика Ñлова Ñе не разликују у ÑинтакÑи"
+
+msgid "syntax case match"
+msgstr "мала/велика Ñлова Ñе разликују у ÑинтакÑи"
+
+msgid "syntax spell toplevel"
+msgstr "ÑинтакÑа правопиÑа toplevel"
+
+msgid "syntax spell notoplevel"
+msgstr "ÑинтакÑа правопиÑа notoplevel"
+
+msgid "syntax spell default"
+msgstr "ÑинтакÑа правопиÑа подразумевано"
+
+msgid "syntax iskeyword "
+msgstr "ÑинтакÑа iskeyword "
+
+#, c-format
+msgid "E391: No such syntax cluster: %s"
+msgstr "E391: Ðе поÑтоји такав ÑинтакÑни клаÑтер: %s"
+
+msgid "syncing on C-style comments"
+msgstr "Ñинхронизација на коментарима C-Ñтила"
+
+msgid "no syncing"
+msgstr "без Ñинхронизације"
+
+msgid "syncing starts "
+msgstr "Ñинхронизација почиње "
+
+msgid " lines before top line"
+msgstr " линија пре линије на врху"
+
+msgid ""
+"\n"
+"--- Syntax sync items ---"
+msgstr ""
+"\n"
+"--- Ставке Ñинхро ÑинтакÑе ---"
+
+msgid ""
+"\n"
+"syncing on items"
+msgstr ""
+"\n"
+"Ñинхро на Ñтавкама"
+
+msgid ""
+"\n"
+"--- Syntax items ---"
+msgstr ""
+"\n"
+"--- Ставке ÑинтакÑе ---"
+
+#, c-format
+msgid "E392: No such syntax cluster: %s"
+msgstr "E392: не поÑтоји такав ÑинтакÑни клаÑтер: %s"
+
+msgid "minimal "
+msgstr "минимално "
+
+msgid "maximal "
+msgstr "макÑимално "
+
+msgid "; match "
+msgstr "; подударања "
+
+msgid " line breaks"
+msgstr " прелома линије"
+
+msgid "E395: contains argument not accepted here"
+msgstr "E395: Ñадржи аргумент који Ñе овде не прихвата"
+
+msgid "E844: invalid cchar value"
+msgstr "E844: неважећа cchar вредноÑÑ‚"
+
+msgid "E393: group[t]here not accepted here"
+msgstr "E393: group[t]here Ñе овде не прихвата"
+
+#, c-format
+msgid "E394: Didn't find region item for %s"
+msgstr "E394: Ставка региона није пронађена за %s"
+
+msgid "E397: Filename required"
+msgstr "E397: Потребно име датотеке"
+
+msgid "E847: Too many syntax includes"
+msgstr "E847: Превише ÑинтакÑних уметања"
+
+#, c-format
+msgid "E789: Missing ']': %s"
+msgstr "E789: ÐедоÑтаје ']': %s"
+
+#, c-format
+msgid "E890: trailing char after ']': %s]%s"
+msgstr "E890: карактер вишка након ']': %s]%s"
+
+#, c-format
+msgid "E398: Missing '=': %s"
+msgstr "E398: ÐедоÑтаје '=': %s"
+
+#, c-format
+msgid "E399: Not enough arguments: syntax region %s"
+msgstr "E399: Ðема довољно аргумената: ÑинтакÑни регион %s"
+
+msgid "E848: Too many syntax clusters"
+msgstr "E848: Превише ÑинтакÑних клаÑтера"
+
+msgid "E400: No cluster specified"
+msgstr "E400: Ðије наведен ниједан клаÑтер"
+
+#, c-format
+msgid "E401: Pattern delimiter not found: %s"
+msgstr "E401: Ðије пронађен граничник шаблона: %s"
+
+#, c-format
+msgid "E402: Garbage after pattern: %s"
+msgstr "E402: Смеће након шаблона: %s"
+
+msgid "E403: syntax sync: line continuations pattern specified twice"
+msgstr "E403: ÑинтакÑна Ñинхро: шаблон наÑтављања линије је наведен двапут"
+
+#, c-format
+msgid "E404: Illegal arguments: %s"
+msgstr "E404: Ðеважећи аргументи: %s"
+
+#, c-format
+msgid "E405: Missing equal sign: %s"
+msgstr "E405: недоÑтаје знак једнакоÑти: %s"
+
+#, c-format
+msgid "E406: Empty argument: %s"
+msgstr "E406: Празан аргумент: %s"
+
+#, c-format
+msgid "E407: %s not allowed here"
+msgstr "E407: %s овде није дозвољено"
+
+#, c-format
+msgid "E408: %s must be first in contains list"
+msgstr "E408: %s мора да буде прво у contains лиÑти"
+
+#, c-format
+msgid "E409: Unknown group name: %s"
+msgstr "E409: Ðепознато име групе: %s"
+
+#, c-format
+msgid "E410: Invalid :syntax subcommand: %s"
+msgstr "E410: Ðеважећа :syntax подкоманда: %s"
+
+msgid ""
+" TOTAL COUNT MATCH SLOWEST AVERAGE NAME PATTERN"
+msgstr ""
+" УКУПÐО БРОЈ ПОДУД ÐÐЈСПОРИЈЕ ПРОСЕК ИМЕ ШÐБЛОÐ"
+
+msgid "E679: recursive loop loading syncolor.vim"
+msgstr "E679: Рекурзивна петља код учитавања syncolor.vim"
+
+#, c-format
+msgid "E411: highlight group not found: %s"
+msgstr "E411: група иÑтицања није пронађена: %s"
+
+#, c-format
+msgid "E412: Not enough arguments: \":highlight link %s\""
+msgstr "E412: Ðема довољно аргумената: \":highlight link %s\""
+
+#, c-format
+msgid "E413: Too many arguments: \":highlight link %s\""
+msgstr "E413: Сувише аргумената: \":highlight link %s\""
+
+msgid "E414: group has settings, highlight link ignored"
+msgstr "E414: група има поÑтавке, highlight link Ñе игнорише"
+
+#, c-format
+msgid "E415: unexpected equal sign: %s"
+msgstr "E415: неочкиван знак једнакоÑти: %s"
+
+#, c-format
+msgid "E416: missing equal sign: %s"
+msgstr "E416: недоÑтаје знак једнакоÑти: %s"
+
+#, c-format
+msgid "E417: missing argument: %s"
+msgstr "E417: недоÑтаје аргумент: %s"
+
+#, c-format
+msgid "E418: Illegal value: %s"
+msgstr "E418: Ðеважећа вредноÑÑ‚: %s"
+
+msgid "E419: FG color unknown"
+msgstr "E419: Ðепозната FG боја"
+
+msgid "E420: BG color unknown"
+msgstr "E420: Ðепозната BG боја"
+
+#, c-format
+msgid "E421: Color name or number not recognized: %s"
+msgstr "E421: Име боје или број ниÑу препознати: %s"
+
+#, c-format
+msgid "E422: terminal code too long: %s"
+msgstr "E422: код терминала је предугачак: %s"
+
+#, c-format
+msgid "E423: Illegal argument: %s"
+msgstr "E423: Ðеважећи аргумент: %s"
+
+msgid "E424: Too many different highlighting attributes in use"
+msgstr "E424: У употреби је превише различитих атрибута иÑтицања"
+
+msgid "E669: Unprintable character in group name"
+msgstr "E669: У имену групе је карактер који не може да Ñе штампа"
+
+msgid "W18: Invalid character in group name"
+msgstr "W18: Ðеважећи карактер у имену групе"
+
+msgid "E849: Too many highlight and syntax groups"
+msgstr "E849: Превише ÑинтакÑних и група иÑтицања"
+
+msgid "E555: at bottom of tag stack"
+msgstr "E555: на дну Ñтека ознака"
+
+msgid "E556: at top of tag stack"
+msgstr "E556: на врху Ñтека ознака"
+
+msgid "E425: Cannot go before first matching tag"
+msgstr "E425: Ðе може да Ñе иде иÑпред прве подударајуће ознаке"
+
+#, c-format
+msgid "E426: tag not found: %s"
+msgstr "E426: ознака није пронађена: %s"
+
+msgid " # pri kind tag"
+msgstr " # ознака pri врÑте"
+
+msgid "file\n"
+msgstr "датотека\n"
+
+msgid "E427: There is only one matching tag"
+msgstr "E427: ПоÑтоји Ñамо једна подударајућа ознака"
+
+msgid "E428: Cannot go beyond last matching tag"
+msgstr "E428: Ðе може да Ñе иде иза поÑледње подударајуће ознаке"
+
+#, c-format
+msgid "File \"%s\" does not exist"
+msgstr "Датотека \"%s\" не поÑтоји"
+
+#, c-format
+msgid "tag %d of %d%s"
+msgstr "ознака %d од %d%s"
+
+msgid " or more"
+msgstr " или више"
+
+msgid " Using tag with different case!"
+msgstr " КориÑти Ñе ознака за другом врÑтом Ñлова (мала/велика)!"
+
+#, c-format
+msgid "E429: File \"%s\" does not exist"
+msgstr "E429: Датотека \"%s\" не поÑтоји"
+
+msgid ""
+"\n"
+" # TO tag FROM line in file/text"
+msgstr ""
+"\n"
+" # ÐРознака ОД линије у датот/текÑÑ‚"
+
+#, c-format
+msgid "Searching tags file %s"
+msgstr "Претраживање датотеке ознака %s"
+
+#, c-format
+msgid "E430: Tag file path truncated for %s\n"
+msgstr "E430: Путања датотеке ознака је прекинута за %s\n"
+
+msgid "Ignoring long line in tags file"
+msgstr "Дугачка линија у датотеци ознака Ñе игнорише"
+
+#, c-format
+msgid "E431: Format error in tags file \"%s\""
+msgstr "E431: Грешка формата у датотеци ознака \"%s\""
+
+#, c-format
+msgid "Before byte %ld"
+msgstr "Пре бајта %ld"
+
+#, c-format
+msgid "E432: Tags file not sorted: %s"
+msgstr "E432: Датотека ознака није Ñортирана: %s"
+
+msgid "E433: No tags file"
+msgstr "E433: Ðема датотеке ознака"
+
+msgid "E434: Can't find tag pattern"
+msgstr "E434: Ðе може да Ñе пронађе шаблон ознаке"
+
+msgid "E435: Couldn't find tag, just guessing!"
+msgstr "E435: Ознака није могла да Ñе пронађе, Ñамо нагађам!"
+
+#, c-format
+msgid "Duplicate field name: %s"
+msgstr "Дупло име поља: %s"
+
+msgid "' not known. Available builtin terminals are:"
+msgstr "' није познат. ДоÑтупни уграђени терминали Ñу:"
+
+msgid "defaulting to '"
+msgstr "подразумева Ñе '"
+
+msgid "E557: Cannot open termcap file"
+msgstr "E557: termcap датотека не може да Ñе отвори"
+
+msgid "E558: Terminal entry not found in terminfo"
+msgstr "E558: У terminfo није пронађена Ñтавка за терминал"
+
+msgid "E559: Terminal entry not found in termcap"
+msgstr "E559: У termcap није пронађена Ñтавка терминала"
+
+#, c-format
+msgid "E436: No \"%s\" entry in termcap"
+msgstr "E436: Ðема \"%s\" Ñтавке у termcap"
+
+msgid "E437: terminal capability \"cm\" required"
+msgstr "E437: потребна је могућноÑÑ‚ терминала \"cm\""
+
+msgid ""
+"\n"
+"--- Terminal keys ---"
+msgstr ""
+"\n"
+"--- ТаÑтери терминала ---"
+
+msgid "Cannot open $VIMRUNTIME/rgb.txt"
+msgstr "Ðе може да Ñе отвори $VIMRUNTIME/rgb.txt"
+
+#, c-format
+msgid "Kill job in \"%s\"?"
+msgstr "Да ли да Ñе уништи задатак у \"%s\"?"
+
+msgid "Terminal"
+msgstr "Терминал"
+
+msgid "Terminal-finished"
+msgstr "Терминал-завршен"
+
+msgid "active"
+msgstr "aktivan"
+
+msgid "running"
+msgstr "ради"
+
+msgid "finished"
+msgstr "завршен"
+
+#, c-format
+msgid "E953: File exists: %s"
+msgstr "E953: Датотека већ поÑтоји: %s"
+
+msgid "E955: Not a terminal buffer"
+msgstr "E955: Ðије терминалÑки бафер"
+
+msgid "new shell started\n"
+msgstr "покренуто ново командно окружење\n"
+
+msgid "Vim: Error reading input, exiting...\n"
+msgstr "Vim: Грешка при читању улаза, излазак...\n"
+
+msgid "Used CUT_BUFFER0 instead of empty selection"
+msgstr "УмеÑто празне Ñелекције корићен је CUT_BUFFER0"
+
+msgid "E881: Line count changed unexpectedly"
+msgstr "E881: Број линија Ñе неочекивано променио"
+
+msgid "No undo possible; continue anyway"
+msgstr "Ðије могућ опозив; ипак наÑтави"
+
+#, c-format
+msgid "E828: Cannot open undo file for writing: %s"
+msgstr "E828: Датотека опозива не може да Ñе отвори за упиÑ: %s"
+
+#, c-format
+msgid "E825: Corrupted undo file (%s): %s"
+msgstr "E825: ИÑкварена датотека за опозив (%s): %s"
+
+msgid "Cannot write undo file in any directory in 'undodir'"
+msgstr ""
+"Датотека за опозив не може да Ñе упише ни у један директоријум из 'undodir'"
+
+#, c-format
+msgid "Will not overwrite with undo file, cannot read: %s"
+msgstr ""
+"Ðеће Ñе вршити препиÑивање Ñа датотеком опозива, читање није могуће: %s"
+
+#, c-format
+msgid "Will not overwrite, this is not an undo file: %s"
+msgstr "Ðеће Ñе цршити препиÑивање, ово није датотека за опозив: %s"
+
+msgid "Skipping undo file write, nothing to undo"
+msgstr "ПреÑкакање упиÑа у датотеку за опозив, нема шта да Ñе опозове"
+
+#, c-format
+msgid "Writing undo file: %s"
+msgstr "Ð£Ð¿Ð¸Ñ Ð´Ð°Ñ‚Ð¾Ñ‚ÐµÐºÐµ за опозив: %s"
+
+#, c-format
+msgid "E829: write error in undo file: %s"
+msgstr "E829: грешка код упиÑа у датотеку за опозив: %s"
+
+#, c-format
+msgid "Not reading undo file, owner differs: %s"
+msgstr "Датотека за опозив Ñе не чита, влаÑник Ñе разликује: %s"
+
+#, c-format
+msgid "Reading undo file: %s"
+msgstr "Читање датотеке за опозив: %s"
+
+#, c-format
+msgid "E822: Cannot open undo file for reading: %s"
+msgstr "E822: Датотека за опозив не може да Ñе отвори за читање: %s"
+
+#, c-format
+msgid "E823: Not an undo file: %s"
+msgstr "E823: Ðије датотека за опозив: %s"
+
+#, c-format
+msgid "E832: Non-encrypted file has encrypted undo file: %s"
+msgstr ""
+"E832: Датотека која није шифрована има шифровану датотеку за опозив: %s"
+
+#, c-format
+msgid "E826: Undo file decryption failed: %s"
+msgstr "E826: Дешифровање датотеке за опозив није уÑпело: %s"
+
+#, c-format
+msgid "E827: Undo file is encrypted: %s"
+msgstr "E827: Датотека за опозив је шифрована: %s"
+
+#, c-format
+msgid "E824: Incompatible undo file: %s"
+msgstr "E824: Ðекомпатибилна датотека за опозив: %s"
+
+msgid "File contents changed, cannot use undo info"
+msgstr ""
+"Садржај датотеке је промењен, информације за опозив не могу да Ñе кориÑте"
+
+#, c-format
+msgid "Finished reading undo file %s"
+msgstr "Тавршено је читање датотеке за опозив %s"
+
+msgid "Already at oldest change"
+msgstr "Већ Ñте на најÑтаријој измени"
+
+msgid "Already at newest change"
+msgstr "Већ Ñте на најновијој измени"
+
+#, c-format
+msgid "E830: Undo number %ld not found"
+msgstr "E830: Број опозива %ld није пронађен"
+
+msgid "E438: u_undo: line numbers wrong"
+msgstr "E438: u_undo: погрешни бројеви линије"
+
+msgid "more line"
+msgstr "линија више"
+
+msgid "more lines"
+msgstr "линија више"
+
+msgid "line less"
+msgstr "линија мање"
+
+msgid "fewer lines"
+msgstr "линија мање"
+
+msgid "change"
+msgstr "измена"
+
+msgid "changes"
+msgstr "измена"
+
+#, c-format
+msgid "%ld %s; %s #%ld %s"
+msgstr "%ld %s; %s #%ld %s"
+
+msgid "before"
+msgstr "пре"
+
+msgid "after"
+msgstr "након"
+
+msgid "Nothing to undo"
+msgstr "Ðишта за опозив"
+
+msgid "number changes when saved"
+msgstr "број измене када Ñачувано"
+
+#, c-format
+msgid "%ld seconds ago"
+msgstr "пре %ld Ñекунди"
+
+msgid "E790: undojoin is not allowed after undo"
+msgstr "E790: undojoin ије дозвољен након undo"
+
+msgid "E439: undo list corrupt"
+msgstr "E439: лиÑта опозива је иÑкварена"
+
+msgid "E440: undo line missing"
+msgstr "E440: недоÑтаје линија опозива"
+
+#, c-format
+msgid "E122: Function %s already exists, add ! to replace it"
+msgstr "E122: Функција %s већ поÑтоји, додајте ! да је замените"
+
+msgid "E717: Dictionary entry already exists"
+msgstr "E717: Ð£Ð½Ð¾Ñ Ð²ÐµÑ› поÑтоји у речнику"
+
+msgid "E718: Funcref required"
+msgstr "E718: Потребна funcref"
+
+#, c-format
+msgid "E130: Unknown function: %s"
+msgstr "E130: Ðепозната функција: %s"
+
+#, c-format
+msgid "E125: Illegal argument: %s"
+msgstr "E125: Ðеважећи аргумент: %s"
+
+#, c-format
+msgid "E853: Duplicate argument name: %s"
+msgstr "E853: Име аргумента је дуплирано: %s"
+
+#, c-format
+msgid "E740: Too many arguments for function %s"
+msgstr "E740: Превише аргумената за функцију %s"
+
+#, c-format
+msgid "E116: Invalid arguments for function %s"
+msgstr "E116: Ðеважећи аргументи за функцију %s"
+
+msgid "E132: Function call depth is higher than 'maxfuncdepth'"
+msgstr "E132: Дубина позива функције је већа од 'maxfuncdepth'"
+
+#, c-format
+msgid "calling %s"
+msgstr "позива Ñе %s"
+
+#, c-format
+msgid "%s aborted"
+msgstr "%s је прекинута"
+
+#, c-format
+msgid "%s returning #%ld"
+msgstr "%s враћа #%ld"
+
+#, c-format
+msgid "%s returning %s"
+msgstr "%s враћа %s"
+
+msgid "E699: Too many arguments"
+msgstr "E699: Сувише аргумената"
+
+#, c-format
+msgid "E117: Unknown function: %s"
+msgstr "E117: Ðепозната функција: %s"
+
+#, c-format
+msgid "E933: Function was deleted: %s"
+msgstr "E933: Функција је обриÑана: %s"
+
+#, c-format
+msgid "E119: Not enough arguments for function: %s"
+msgstr "E119: Ðема довољно аргумената за функцију: %s"
+
+#, c-format
+msgid "E120: Using <SID> not in a script context: %s"
+msgstr "E120: Коришћење <SID> ван Ñкрипт контекÑта: %s"
+
+#, c-format
+msgid "E725: Calling dict function without Dictionary: %s"
+msgstr "E725: Позивање dict функције без Речника: %s"
+
+msgid "E129: Function name required"
+msgstr "E129: Потребно је име функције"
+
+#, c-format
+msgid "E128: Function name must start with a capital or \"s:\": %s"
+msgstr "E128: Име функције мора да почне великим Ñловом или \"s:\": %s"
+
+#, c-format
+msgid "E884: Function name cannot contain a colon: %s"
+msgstr "E884: Име функције не може да Ñадржи двотачку: %s"
+
+#, c-format
+msgid "E123: Undefined function: %s"
+msgstr "E123: ÐедефиниÑана функција: %s"
+
+#, c-format
+msgid "E124: Missing '(': %s"
+msgstr "E124: ÐедоÑтаје '(': %s"
+
+msgid "E862: Cannot use g: here"
+msgstr "E862: g: не може овде да Ñе кориÑти"
+
+#, c-format
+msgid "E932: Closure function should not be at top level: %s"
+msgstr "E932: Затварајућа функција не би требало да буде на највишем нивоу: %s"
+
+msgid "E126: Missing :endfunction"
+msgstr "E126: ÐедоÑтаје :endfunction"
+
+#, c-format
+msgid "W22: Text found after :endfunction: %s"
+msgstr "W22: Пронађен текÑÑ‚ након :endfunction: %s"
+
+#, c-format
+msgid "E707: Function name conflicts with variable: %s"
+msgstr "E707: Име функције је у конфликту Ñа променљивом: %s"
+
+#, c-format
+msgid "E127: Cannot redefine function %s: It is in use"
+msgstr "E127: Функција %s не може да Ñе редефинише: Тренутно Ñе кориÑти"
+
+#, c-format
+msgid "E746: Function name does not match script file name: %s"
+msgstr "E746: Име функције Ñе не поклапа Ñа именом Ñкрипт датотеке: %s"
+
+#, c-format
+msgid "E131: Cannot delete function %s: It is in use"
+msgstr "E131: Функција %s не може да Ñе обрише: Тренутно Ñе кориÑти"
+
+msgid "E133: :return not inside a function"
+msgstr "E133: :return није унутар функције"
+
+#, c-format
+msgid "E107: Missing parentheses: %s"
+msgstr "E107: ÐедоÑтају заграде: %s"
+
+msgid ""
+"\n"
+"MS-Windows 64-bit GUI version"
+msgstr ""
+"\n"
+"MS-Windows 64-битна GUI верзија"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit GUI version"
+msgstr ""
+"\n"
+"MS-Windows 32-битна GUI верзија"
+
+msgid " with OLE support"
+msgstr " Ñа OLE подршком"
+
+msgid ""
+"\n"
+"MS-Windows 64-bit console version"
+msgstr ""
+"\n"
+"MS-Windows 64-битна конзолна верзија"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit console version"
+msgstr ""
+"\n"
+"MS-Windows 32-битна конзолна верзија"
+
+msgid ""
+"\n"
+"macOS version"
+msgstr ""
+"\n"
+"macOS верзија"
+
+msgid ""
+"\n"
+"macOS version w/o darwin feat."
+msgstr ""
+"\n"
+"macOS верзија без darwin могућ."
+
+msgid ""
+"\n"
+"OpenVMS version"
+msgstr ""
+"\n"
+"OpenVMS верзија"
+
+msgid ""
+"\n"
+"Included patches: "
+msgstr ""
+"\n"
+"Укључене иÑправке: "
+
+msgid ""
+"\n"
+"Extra patches: "
+msgstr ""
+"\n"
+"ЕкÑтра иÑправке: "
+
+msgid "Modified by "
+msgstr "Модификовао "
+
+msgid ""
+"\n"
+"Compiled "
+msgstr ""
+"\n"
+"Компајлирао"
+
+msgid "by "
+msgstr " "
+
+msgid ""
+"\n"
+"Huge version "
+msgstr ""
+"\n"
+"Огромна верзија "
+
+msgid ""
+"\n"
+"Big version "
+msgstr ""
+"\n"
+"Велика верзија "
+
+msgid ""
+"\n"
+"Normal version "
+msgstr ""
+"\n"
+"Ðормална верзија "
+
+msgid ""
+"\n"
+"Small version "
+msgstr ""
+"\n"
+"Мала верзија "
+
+msgid ""
+"\n"
+"Tiny version "
+msgstr ""
+"\n"
+"Сићушна верзија "
+
+msgid "without GUI."
+msgstr "без GUI."
+
+msgid "with GTK3 GUI."
+msgstr "Ñа GTK3 GUI."
+
+msgid "with GTK2-GNOME GUI."
+msgstr "Ñа GTK2-GNOME GUI."
+
+msgid "with GTK2 GUI."
+msgstr "Ñа GTK2 GUI."
+
+msgid "with X11-Motif GUI."
+msgstr "Ñа X11-Motif GUI."
+
+msgid "with X11-neXtaw GUI."
+msgstr "Ñа X11-neXtaw GUI."
+
+msgid "with X11-Athena GUI."
+msgstr "Ñа X11-Athena GUI."
+
+msgid "with Photon GUI."
+msgstr "Ñа Photon GUI."
+
+msgid "with GUI."
+msgstr "Ñа GUI."
+
+msgid "with Carbon GUI."
+msgstr "Ñа Carbon GUI."
+
+msgid "with Cocoa GUI."
+msgstr "Ñа Cocoa GUI."
+
+msgid " Features included (+) or not (-):\n"
+msgstr " МогућноÑти укључене (+) или не (-):\n"
+
+msgid " system vimrc file: \""
+msgstr " ÑиÑтемÑкa vimrc датотека: \""
+
+msgid " user vimrc file: \""
+msgstr " кориÑничка vimrc датотека: \""
+
+msgid " 2nd user vimrc file: \""
+msgstr " 2га кориÑничка vimrc датотека: \""
+
+msgid " 3rd user vimrc file: \""
+msgstr " 3ћа кориÑничка vimrc датотека: \""
+
+msgid " user exrc file: \""
+msgstr " кориÑничка exrc датотека: \""
+
+msgid " 2nd user exrc file: \""
+msgstr " 2га кориÑничка exrc датотека: \""
+
+msgid " system gvimrc file: \""
+msgstr " ÑиÑтемÑка gvimrc датотека: \""
+
+msgid " user gvimrc file: \""
+msgstr " кориÑничка gvimrc датотека: \""
+
+msgid "2nd user gvimrc file: \""
+msgstr "2га кориÑничка gvimrc датотека: \""
+
+msgid "3rd user gvimrc file: \""
+msgstr "3ћа кориÑничка gvimrc датотека: \""
+
+msgid " defaults file: \""
+msgstr " датотека Ñа подраз. опцијама: \""
+
+msgid " system menu file: \""
+msgstr " ÑиÑтемÑка датотека менија: \""
+
+msgid " fall-back for $VIM: \""
+msgstr " резервна вредноÑÑ‚ за $VIM: \""
+
+msgid " f-b for $VIMRUNTIME: \""
+msgstr "резервна вредн. за $VIMRUNTIME: \""
+
+msgid "Compilation: "
+msgstr "Компилација: "
+
+msgid "Compiler: "
+msgstr "Компајлер: "
+
+msgid "Linking: "
+msgstr "Повезивање: "
+
+msgid " DEBUG BUILD"
+msgstr " DEBUG ИЗДÐЊЕ"
+
+msgid "VIM - Vi IMproved"
+msgstr "VIM - Vi IMproved"
+
+msgid "version "
+msgstr "верзија "
+
+msgid "by Bram Moolenaar et al."
+msgstr "напиÑали Bram Moolenaar et al."
+
+msgid "Vim is open source and freely distributable"
+msgstr "Vim је отвореног кода и може Ñлободно да Ñе диÑтрибуира"
+
+msgid "Help poor children in Uganda!"
+msgstr "Помозите Ñиромашној деци у Уганди!"
+
+msgid "type :help iccf<Enter> for information "
+msgstr "откуцајте :help iccf<Enter> за информације "
+
+msgid "type :q<Enter> to exit "
+msgstr "откуцајте :q<Enter> за излаз "
+
+msgid "type :help<Enter> or <F1> for on-line help"
+msgstr "откуцајте :help<Enter> или <F1> за on-line помоћ "
+
+msgid "type :help version8<Enter> for version info"
+msgstr "откуцајте :help version8<Enter> за инфо о верзији"
+
+msgid "Running in Vi compatible mode"
+msgstr "Рад у Vi компатибилном режиму"
+
+msgid "type :set nocp<Enter> for Vim defaults"
+msgstr "откуцајте :set nocp<Enter> за Vim подразумевано"
+
+msgid "type :help cp-default<Enter> for info on this"
+msgstr "откуцајте :help cp-default<Enter> за инфо о овоме"
+
+msgid "menu Help->Orphans for information "
+msgstr "мени Помоћ->Сирочићи за информације "
+
+msgid "Running modeless, typed text is inserted"
+msgstr "БезрежимÑки рад, умеће Ñе откуцани текÑÑ‚"
+
+msgid "menu Edit->Global Settings->Toggle Insert Mode "
+msgstr "мени Уређивање->Глобална подешавања->Преклапај режим Уметање "
+
+msgid " for two modes "
+msgstr " за два режима "
+
+msgid "menu Edit->Global Settings->Toggle Vi Compatible"
+msgstr "мени Уређивање->Глобална подешавања->Преклапај Vi Компатибилно"
+
+msgid " for Vim defaults "
+msgstr " за Vim подразумевано "
+
+msgid "Sponsor Vim development!"
+msgstr "Спонзоришите Vim развој!"
+
+msgid "Become a registered Vim user!"
+msgstr "ПоÑтаните региÑтровани Vim кориÑник!"
+
+msgid "type :help sponsor<Enter> for information "
+msgstr "откуцајте :help sponsor<Enter> за информације "
+
+msgid "type :help register<Enter> for information "
+msgstr "откуцајте :help register<Enter> за информације "
+
+msgid "menu Help->Sponsor/Register for information "
+msgstr "мени Помоћ->Спонзор/РегиÑтруј Ñе за информације "
+
+msgid "Already only one window"
+msgstr "Већ поÑтоји Ñамо један прозор"
+
+msgid "E441: There is no preview window"
+msgstr "E441: Ðема прозора за преглед"
+
+msgid "E442: Can't split topleft and botright at the same time"
+msgstr "E442: topleft и botright не могу да Ñе поделе у иÑто време"
+
+msgid "E443: Cannot rotate when another window is split"
+msgstr "E443: Ðе може да Ñе ротира када је подељен други прозор"
+
+msgid "E444: Cannot close last window"
+msgstr "E444: ПоÑледњи прозор не може да Ñе затвори"
+
+msgid "E813: Cannot close autocmd window"
+msgstr "E813: autocmd прозор не може да Ñе затвори"
+
+msgid "E814: Cannot close window, only autocmd window would remain"
+msgstr "E814: Прозор не може да Ñе затвори, преоÑтао би једино autocmd прозор"
+
+msgid "E445: Other window contains changes"
+msgstr "E445: Други прозори Ñадрже измене"
+
+msgid "E446: No file name under cursor"
+msgstr "E446: Под курÑором Ñе не налази име датотеке"
+
+#, c-format
+msgid "E447: Can't find file \"%s\" in path"
+msgstr "E447: Датотека \"%s\" не може да Ñе пронађе у путањи"
+
+#, c-format
+msgid "E799: Invalid ID: %ld (must be greater than or equal to 1)"
+msgstr "E799: Ðеважећи ИД: %ld (мора бити већи од или једнак 1)"
+
+#, c-format
+msgid "E801: ID already taken: %ld"
+msgstr "E801: ИД је већ заузет: %ld"
+
+msgid "List or number required"
+msgstr "Захтева Ñе лиÑта или број"
+
+#, c-format
+msgid "E802: Invalid ID: %ld (must be greater than or equal to 1)"
+msgstr "E802: Ðеважећи ИД: %ld (мора бити већи од или једнак 1)"
+
+#, c-format
+msgid "E803: ID not found: %ld"
+msgstr "E803: ИД није пронађен: %ld"
+
+msgid "Edit with &multiple Vims"
+msgstr "Уређуј Ñа &више Vim-ова"
+
+msgid "Edit with single &Vim"
+msgstr "Уређуј Ñа једним &Vim-ом"
+
+msgid "Diff with Vim"
+msgstr "Diff Ñа Vim"
+
+msgid "Edit with &Vim"
+msgstr "Уређуј Ñа &Vim-ом"
+
+msgid "Edit with existing Vim - "
+msgstr "Уређуј Ñа поÑтојећим Vim - "
+
+msgid "Edits the selected file(s) with Vim"
+msgstr "Уређује Ñелектовауе датотеку(е) Ñа Vim-ом"
+
+msgid "Error creating process: Check if gvim is in your path!"
+msgstr ""
+"Грешка приликом креирања процеÑа: Проверите да ли је gvim у вашој путањи!"
+
+msgid "gvimext.dll error"
+msgstr "gvimext.dll грешка"
+
+msgid "Path length too long!"
+msgstr "Путања је предугачка!"
+
+msgid "--No lines in buffer--"
+msgstr "--У баферу нема линија--"
+
+msgid "E470: Command aborted"
+msgstr "E470: Команда прекинута"
+
+msgid "E471: Argument required"
+msgstr "E471: Потребан је аргумент"
+
+msgid "E10: \\ should be followed by /, ? or &"
+msgstr "E10: Иза \\ треба да је /, ? или &"
+
+msgid "E11: Invalid in command-line window; <CR> executes, CTRL-C quits"
+msgstr ""
+"E11: Ðеважеће у прозору командне линије; <CR> извршава, CTRL-C отказује"
+
+msgid "E12: Command not allowed from exrc/vimrc in current dir or tag search"
+msgstr ""
+"E12: ПоÑтоји забрана за команду у exrc/vimrc у текућој претрази "
+"директоријума или ознаке"
+
+msgid "E171: Missing :endif"
+msgstr "E171: ÐедоÑтаје :endif"
+
+msgid "E600: Missing :endtry"
+msgstr "E600: ÐедоÑтаје :endtry"
+
+msgid "E170: Missing :endwhile"
+msgstr "E170: ÐедоÑтаје :endwhile"
+
+msgid "E170: Missing :endfor"
+msgstr "E170: ÐедоÑтаје :endfor"
+
+msgid "E588: :endwhile without :while"
+msgstr "E588: :endwhile без :while"
+
+msgid "E588: :endfor without :for"
+msgstr "E588: :endfor без :for"
+
+msgid "E13: File exists (add ! to override)"
+msgstr "E13: Датотека поÑтоји (додајте ! за премошћавање)"
+
+msgid "E472: Command failed"
+msgstr "E472: Команда није уÑпела"
+
+#, c-format
+msgid "E234: Unknown fontset: %s"
+msgstr "E234: Ðепознат fontset: %s"
+
+#, c-format
+msgid "E235: Unknown font: %s"
+msgstr "E235: Ðепознат фонт: %s"
+
+#, c-format
+msgid "E236: Font \"%s\" is not fixed-width"
+msgstr "E236: Фонт \"%s\" није фикÑне ширине"
+
+msgid "E473: Internal error"
+msgstr "E473: Интерна грешка"
+
+#, c-format
+msgid "E685: Internal error: %s"
+msgstr "E685: Интерна грешка: %s"
+
+msgid "Interrupted"
+msgstr "Прекинуто"
+
+msgid "E14: Invalid address"
+msgstr "E14: Ðеважећа адреÑа"
+
+msgid "E474: Invalid argument"
+msgstr "E474: Ðеважећи аргумент"
+
+#, c-format
+msgid "E475: Invalid argument: %s"
+msgstr "E475: Ðеважећи аргумент: %s"
+
+#, c-format
+msgid "E475: Invalid value for argument %s"
+msgstr "E475: Ðеважећa вредноÑÑ‚ за аргумент: %s"
+
+#, c-format
+msgid "E475: Invalid value for argument %s: %s"
+msgstr "E475: Ðеважећa вредноÑÑ‚ за аргумент %s: %s"
+
+#, c-format
+msgid "E15: Invalid expression: %s"
+msgstr "E15: Ðеважећи израз: %s"
+
+msgid "E16: Invalid range"
+msgstr "E16: Ðеважећи опÑег"
+
+msgid "E476: Invalid command"
+msgstr "E476: Ðеважећа команда"
+
+#, c-format
+msgid "E17: \"%s\" is a directory"
+msgstr "E17: \"%s\" је директоријум"
+
+#, c-format
+msgid "E364: Library call failed for \"%s()\""
+msgstr "E364: Позив библиотеке није уÑпео за \"%s()\""
+
+msgid "E667: Fsync failed"
+msgstr "E667: Fsync није уÑпео"
+
+#, c-format
+msgid "E448: Could not load library function %s"
+msgstr "E448: Библиотечка функција %s није могла да Ñе учита"
+
+msgid "E19: Mark has invalid line number"
+msgstr "E19: Маркер Ñадржи неиÑправан број линије"
+
+msgid "E20: Mark not set"
+msgstr "E20: Маркер није поÑтављен"
+
+msgid "E21: Cannot make changes, 'modifiable' is off"
+msgstr "E21: Измене не могу да Ñе учине, опција 'modifiable' је иÑкључена"
+
+msgid "E22: Scripts nested too deep"
+msgstr "E22: Скрипте Ñу предубоко угњеждене"
+
+msgid "E23: No alternate file"
+msgstr "E23: Ðема алтернативне датотеке"
+
+msgid "E24: No such abbreviation"
+msgstr "E24: Таква Ñкраћеница не поÑтоји"
+
+msgid "E477: No ! allowed"
+msgstr "E477: ! није дозвољен"
+
+msgid "E25: GUI cannot be used: Not enabled at compile time"
+msgstr "E25: GUI не може да Ñе кориÑти: Ðије омогућен у време компилације"
+
+msgid "E26: Hebrew cannot be used: Not enabled at compile time\n"
+msgstr ""
+"E26: хебрејÑки не може да Ñе кориÑти: Ðије омогућен у време компилације\n"
+
+msgid "E27: Farsi cannot be used: Not enabled at compile time\n"
+msgstr "E27: фарÑи не може да Ñе кориÑти: Ðије омогућен у време компилације\n"
+
+msgid "E800: Arabic cannot be used: Not enabled at compile time\n"
+msgstr ""
+"E800: арапÑки не може да Ñе кориÑти: Ðије омогућен у време компилације\n"
+
+#, c-format
+msgid "E28: No such highlight group name: %s"
+msgstr "E28: Ðема групе иÑтицања Ñа таквим именом: %s"
+
+msgid "E29: No inserted text yet"
+msgstr "E29: ТекÑÑ‚ још није унет"
+
+msgid "E30: No previous command line"
+msgstr "E30: Ðема претходне командне линије"
+
+msgid "E31: No such mapping"
+msgstr "E31: Такво мапирање не поÑтоји"
+
+msgid "E479: No match"
+msgstr "E479: Ðема подударања"
+
+#, c-format
+msgid "E480: No match: %s"
+msgstr "E480: Ðема подударања: %s"
+
+msgid "E32: No file name"
+msgstr "E32: Ðема имена датотеке"
+
+msgid "E33: No previous substitute regular expression"
+msgstr "E33: Ðема претходног регуларног израза за замену"
+
+msgid "E34: No previous command"
+msgstr "E34: Ðема претходне команде"
+
+msgid "E35: No previous regular expression"
+msgstr "E35: Ðема претходног регуларног израза"
+
+msgid "E481: No range allowed"
+msgstr "E481: ОпÑег није дозвољен"
+
+msgid "E36: Not enough room"
+msgstr "E36: Ðема довољно проÑтора"
+
+#, c-format
+msgid "E247: no registered server named \"%s\""
+msgstr "E247: нема региÑтованог Ñервера под именом \"%s\""
+
+#, c-format
+msgid "E482: Can't create file %s"
+msgstr "E482: Датотека %s не може да Ñе креира"
+
+msgid "E483: Can't get temp file name"
+msgstr "E483: Име привремене датотке не може да Ñе добије"
+
+#, c-format
+msgid "E484: Can't open file %s"
+msgstr "E484: Датотека %s не може да Ñе отвори"
+
+#, c-format
+msgid "E485: Can't read file %s"
+msgstr "E485: Датотека %s не може да Ñе прочита"
+
+msgid "E38: Null argument"
+msgstr "E38: Празан аргумент"
+
+msgid "E39: Number expected"
+msgstr "E39: Очекује Ñе број"
+
+#, c-format
+msgid "E40: Can't open errorfile %s"
+msgstr "E40: Датотека грешке %s не може да Ñе отвори"
+
+msgid "E233: cannot open display"
+msgstr "E233: проказ не може да Ñе отвори"
+
+msgid "E41: Out of memory!"
+msgstr "E41: Ðема више меморије!"
+
+msgid "Pattern not found"
+msgstr "Шаблон није пронађен"
+
+#, c-format
+msgid "E486: Pattern not found: %s"
+msgstr "E486: Шаблон није пронађен: %s"
+
+msgid "E487: Argument must be positive"
+msgstr "E487: Ðргумент мора бити позитиван"
+
+msgid "E459: Cannot go back to previous directory"
+msgstr "E459: Ðе може да Ñе оде назад на претходни директоријум"
+
+msgid "E42: No Errors"
+msgstr "E42: Ðема грешака"
+
+msgid "E776: No location list"
+msgstr "E776: Ðема лиÑте локација"
+
+msgid "E43: Damaged match string"
+msgstr "E43: Оштећен Ñтринг за подударање"
+
+msgid "E44: Corrupted regexp program"
+msgstr "E44: regexp програм је покварен"
+
+msgid "E45: 'readonly' option is set (add ! to override)"
+msgstr "E45: ПоÑтављена је 'readonly' опција (додајте ! за премошћавање)"
+
+#, c-format
+msgid "E46: Cannot change read-only variable \"%s\""
+msgstr "E46: Променљива Ñамо за читање \"%s\" не може да Ñе измени"
+
+#, c-format
+msgid "E794: Cannot set variable in the sandbox: \"%s\""
+msgstr "E794: Ðе може да Ñе поÑтави променљива у sandbox-у: \"%s\""
+
+msgid "E713: Cannot use empty key for Dictionary"
+msgstr "E713: Ðе може да Ñе кориÑти празан кључ за Речник"
+
+msgid "E715: Dictionary required"
+msgstr "E715: Потребан Речник"
+
+#, c-format
+msgid "E684: list index out of range: %ld"
+msgstr "E684: Ð¸Ð½Ð´ÐµÐºÑ Ð»Ð¸Ñте је ван опÑега: %ld"
+
+#, c-format
+msgid "E118: Too many arguments for function: %s"
+msgstr "E118: Превише аргумената за функцију: %s"
+
+#, c-format
+msgid "E716: Key not present in Dictionary: %s"
+msgstr "E716: У Речнику нема кључа: %s"
+
+msgid "E714: List required"
+msgstr "E714: Потребна ЛиÑта"
+
+#, c-format
+msgid "E712: Argument of %s must be a List or Dictionary"
+msgstr "E712: Ðргумент за %s мора бити ЛиÑта или Речник"
+
+msgid "E47: Error while reading errorfile"
+msgstr "E47: Грешка приликом читаља датотеке грешке"
+
+msgid "E48: Not allowed in sandbox"
+msgstr "E48: Ðије дозвољено у sandbox-у"
+
+msgid "E523: Not allowed here"
+msgstr "E523: Ðије дозвољено овде"
+
+msgid "E359: Screen mode setting not supported"
+msgstr "E359: Подешавање режима екрана није подржано"
+
+msgid "E49: Invalid scroll size"
+msgstr "E49: Ðеважећа величина линије за Ñкроловање"
+
+msgid "E91: 'shell' option is empty"
+msgstr "E91: Опција 'shell' је празна"
+
+msgid "E255: Couldn't read in sign data!"
+msgstr "E255: Подаци за знак ниÑу могли да Ñе прочитају!"
+
+msgid "E72: Close error on swap file"
+msgstr "E72: Грешка код затвањара swap датотеке"
+
+msgid "E73: tag stack empty"
+msgstr "E73: Ñтек ознака је празан"
+
+msgid "E74: Command too complex"
+msgstr "E74: Команда је Ñувише комплекÑна"
+
+msgid "E75: Name too long"
+msgstr "E75: Име је предугачко"
+
+msgid "E76: Too many ["
+msgstr "E76: Превише ["
+
+msgid "E77: Too many file names"
+msgstr "E77: Превише имена датотека"
+
+msgid "E488: Trailing characters"
+msgstr "E488: Карактери вишка на крају"
+
+msgid "E78: Unknown mark"
+msgstr "E78: Ðепознат маркер"
+
+msgid "E79: Cannot expand wildcards"
+msgstr "E79: Ðокери не могу да Ñе развију"
+
+msgid "E591: 'winheight' cannot be smaller than 'winminheight'"
+msgstr "E591: 'winheight' не може да буде мање од 'winminheight'"
+
+msgid "E592: 'winwidth' cannot be smaller than 'winminwidth'"
+msgstr "E592: 'winwidth' не може да буде мање од 'winminwidth'"
+
+msgid "E80: Error while writing"
+msgstr "E80: Грешка приликом упиÑа"
+
+msgid "E939: Positive count required"
+msgstr "E939: Потребан је позитиван број"
+
+msgid "E81: Using <SID> not in a script context"
+msgstr "E81: <SID> Ñе кориÑти ван Ñкрипт контекÑта"
+
+msgid "E449: Invalid expression received"
+msgstr "E449: Примљен је неважећи израз"
+
+msgid "E463: Region is guarded, cannot modify"
+msgstr "E463: Регион је чуван, измена није могућа"
+
+msgid "E744: NetBeans does not allow changes in read-only files"
+msgstr ""
+"E744: NetBeans не дозвољава измене датотека које Ñмеју Ñамо да Ñе читају"
+
+msgid "E363: pattern uses more memory than 'maxmempattern'"
+msgstr "E363: шаблон кориÑти више меморије од 'maxmempattern'"
+
+msgid "E749: empty buffer"
+msgstr "E749: празан бафер"
+
+#, c-format
+msgid "E86: Buffer %ld does not exist"
+msgstr "E86: Бафер %ld не поÑтоји"
+
+msgid "E682: Invalid search pattern or delimiter"
+msgstr "E682: Ðеважећи шаблон претраге или раздвојни карактер"
+
+msgid "E139: File is loaded in another buffer"
+msgstr "E139: Датотека је учитана у други бафер"
+
+#, c-format
+msgid "E764: Option '%s' is not set"
+msgstr "E764: Опција '%s' није поÑтављена"
+
+msgid "E850: Invalid register name"
+msgstr "E850: Ðеважеће име региÑтра"
+
+#, c-format
+msgid "E919: Directory not found in '%s': \"%s\""
+msgstr "E919: Ðије пронађен директоријум у '%s': \"%s\""
+
+msgid "E952: Autocommand caused recursive behavior"
+msgstr "E952: Ðутокомандa je изазвала рекурзивно понашање"
+
+msgid "search hit TOP, continuing at BOTTOM"
+msgstr "претрага је доÑтигла ВРХ, наÑтавља Ñе на ДÐУ"
+
+msgid "search hit BOTTOM, continuing at TOP"
+msgstr "претрага је доÑтигла ДÐО, наÑтавља Ñе на ВРХУ"
+
+#, c-format
+msgid "Need encryption key for \"%s\""
+msgstr "Потребан је кључ за шифровање \"%s\""
+
+msgid "empty keys are not allowed"
+msgstr "празни кључеви ниÑу дозвољени"
+
+msgid "dictionary is locked"
+msgstr "речник је закључан"
+
+msgid "list is locked"
+msgstr "лиÑта је закључана"
+
+#, c-format
+msgid "failed to add key '%s' to dictionary"
+msgstr "кључ '%s' није могао да Ñе дода у речник"
+
+#, c-format
+msgid "index must be int or slice, not %s"
+msgstr "index мора бити типа int или slice, не %s"
+
+#, c-format
+msgid "expected str() or unicode() instance, but got %s"
+msgstr "очекивала Ñе инÑтанца str() или unicode(), али је добијена %s"
+
+#, c-format
+msgid "expected bytes() or str() instance, but got %s"
+msgstr "очекивала Ñе инÑтанца bytes() или str(), али је добијена %s"
+
+#, c-format
+msgid ""
+"expected int(), long() or something supporting coercing to long(), but got %s"
+msgstr ""
+"очекивало Ñе int(), long() или нешто што подржава Ñпајање Ñа long(), али је "
+"добијено %s"
+
+#, c-format
+msgid "expected int() or something supporting coercing to int(), but got %s"
+msgstr ""
+"очекивало Ñе int() или нешто што подржава Ñпајање Ñа int(), али је добијено %"
+"s"
+
+msgid "value is too large to fit into C int type"
+msgstr "вредноÑÑ‚ је Ñувише велика да Ñе ÑмеÑти у C int тип"
+
+msgid "value is too small to fit into C int type"
+msgstr "вредноÑÑ‚ је Ñувише мала да Ñе ÑмеÑти у C int тип"
+
+msgid "number must be greater than zero"
+msgstr "број мора бити већи од нуле"
+
+msgid "number must be greater or equal to zero"
+msgstr "број мора бити већи од или једнак нули"
+
+msgid "can't delete OutputObject attributes"
+msgstr "атрибути OutputObject не могу да Ñе обришу"
+
+#, c-format
+msgid "invalid attribute: %s"
+msgstr "неважећи атрибут: %s"
+
+msgid "E264: Python: Error initialising I/O objects"
+msgstr "E264: Python: Грешка код иницијализације У/И објеката"
+
+msgid "failed to change directory"
+msgstr "не може да Ñе промени директоријум"
+
+#, c-format
+msgid "expected 3-tuple as imp.find_module() result, but got %s"
+msgstr "Као резултат imp.find_module() очекује Ñе триплет, али је добијено %s"
+
+#, c-format
+msgid "expected 3-tuple as imp.find_module() result, but got tuple of size %d"
+msgstr ""
+"Као резултат imp.find_module() очекује Ñе триплет, али је добијена н-торка "
+"величине %d"
+
+msgid "internal error: imp.find_module returned tuple with NULL"
+msgstr "интерна грешка: imp.find_module је вратио н-торку Ñа NULL"
+
+msgid "cannot delete vim.Dictionary attributes"
+msgstr "vim.Dictionary атрибути не могу да Ñе обришу"
+
+msgid "cannot modify fixed dictionary"
+msgstr "фикÑни речник не може да Ñе измени"
+
+#, c-format
+msgid "cannot set attribute %s"
+msgstr "атрибут %s не може да Ñе поÑтави"
+
+msgid "hashtab changed during iteration"
+msgstr "hashtab је промењен током итерације"
+
+#, c-format
+msgid "expected sequence element of size 2, but got sequence of size %d"
+msgstr ""
+"очекивао Ñе елемент Ñеквенце величине 2, али је добијена Ñеквенца "
+"величине %d"
+
+msgid "list constructor does not accept keyword arguments"
+msgstr "конÑтруктор лиÑте не прихвата кључне речи за аргументе"
+
+msgid "list index out of range"
+msgstr "Ð¸Ð½Ð´ÐµÐºÑ Ð»Ð¸Ñте је ван опÑега"
+
+#, c-format
+msgid "internal error: failed to get vim list item %d"
+msgstr "интерна грешка: Ñтавка %d vim лиÑте није могла да Ñе добије"
+
+msgid "slice step cannot be zero"
+msgstr "slice корак не може да буде нула"
+
+#, c-format
+msgid "attempt to assign sequence of size greater than %d to extended slice"
+msgstr "покушај доделе Ñеквенце величине веће од %d како би Ñе продужио slice"
+
+#, c-format
+msgid "internal error: no vim list item %d"
+msgstr "интерна грешка: нема Ñтавке %d у vim лиÑти"
+
+msgid "internal error: not enough list items"
+msgstr "интерна грешка: нема довољно Ñтавки лиÑте"
+
+msgid "internal error: failed to add item to list"
+msgstr "интерна грешка: Ñтавка није могла да Ñе дода лиÑти"
+
+#, c-format
+msgid "attempt to assign sequence of size %d to extended slice of size %d"
+msgstr ""
+"покушај доделе Ñеквенце величине %d како би Ñе продужио slice величине %d"
+
+msgid "failed to add item to list"
+msgstr "Ñтавка није могла да Ñе дода лиÑти"
+
+msgid "cannot delete vim.List attributes"
+msgstr "vim.List атрибути не могу да Ñе обришу"
+
+msgid "cannot modify fixed list"
+msgstr "фикÑна лиÑта не може да Ñе измени"
+
+#, c-format
+msgid "unnamed function %s does not exist"
+msgstr "неименована функција %s не поÑтоји"
+
+#, c-format
+msgid "function %s does not exist"
+msgstr "функција %s не поÑтоји"
+
+#, c-format
+msgid "failed to run function %s"
+msgstr "функција %s није могла да Ñе покрене"
+
+msgid "unable to get option value"
+msgstr "вредноÑÑ‚ опције није могла да Ñе добије"
+
+msgid "internal error: unknown option type"
+msgstr "интерна грешка: непознат тип опције"
+
+msgid "problem while switching windows"
+msgstr "проблем код пребацивања прозора"
+
+#, c-format
+msgid "unable to unset global option %s"
+msgstr "глобална опција %s није могла да Ñе иÑкључи"
+
+#, c-format
+msgid "unable to unset option %s which does not have global value"
+msgstr "опција %s која нема глобалну вредноÑÑ‚ није могла да Ñе иÑкључи"
+
+msgid "attempt to refer to deleted tab page"
+msgstr "покушај рефериÑања на обриÑану картицу"
+
+msgid "no such tab page"
+msgstr "не поÑтоји таква картица"
+
+msgid "attempt to refer to deleted window"
+msgstr "покушај рефериÑања на обриÑан прозор"
+
+msgid "readonly attribute: buffer"
+msgstr "атрибут Ñамо за читање: бафер"
+
+msgid "cursor position outside buffer"
+msgstr "позиција курÑора је ван бафера"
+
+msgid "no such window"
+msgstr "нема таквог прозора"
+
+msgid "attempt to refer to deleted buffer"
+msgstr "покушај рефериÑања на обриÑан бафер"
+
+msgid "failed to rename buffer"
+msgstr "име бафера није могло да Ñе промени"
+
+msgid "mark name must be a single character"
+msgstr "име маркера мора бити Ñамо један карактер"
+
+#, c-format
+msgid "expected vim.Buffer object, but got %s"
+msgstr "очекивао Ñе vim.Buffer објекат, али је добијен %s"
+
+#, c-format
+msgid "failed to switch to buffer %d"
+msgstr "прелазак на бафер %d није био могућ"
+
+#, c-format
+msgid "expected vim.Window object, but got %s"
+msgstr "очекивао Ñе vim.Window објекат, али је добијен %s"
+
+msgid "failed to find window in the current tab page"
+msgstr "прозор није пронађен у текућој картици"
+
+msgid "did not switch to the specified window"
+msgstr "није Ñе прешло у наведени прозор"
+
+#, c-format
+msgid "expected vim.TabPage object, but got %s"
+msgstr "очекивао Ñе vim.TabPage објекат, али је добијен %s"
+
+msgid "did not switch to the specified tab page"
+msgstr "није Ñе прешло у наведену картицу"
+
+msgid "failed to run the code"
+msgstr "кôд није могао да Ñе покрене"
+
+msgid "E858: Eval did not return a valid python object"
+msgstr "E858: Eval није вратио важећи python објекат"
+
+msgid "E859: Failed to convert returned python object to vim value"
+msgstr "E859: Конверзија враћеног python објекта у vim вредноÑÑ‚ није уÑпела"
+
+#, c-format
+msgid "unable to convert %s to vim dictionary"
+msgstr "%s не може да Ñе конвертује у vim речник"
+
+#, c-format
+msgid "unable to convert %s to vim list"
+msgstr "%s не може да Ñе конвертује у vim лиÑту"
+
+#, c-format
+msgid "unable to convert %s to vim structure"
+msgstr "%s не може да Ñе конвертује у vim Ñтруктуру"
+
+msgid "internal error: NULL reference passed"
+msgstr "интерна грешка: проÑлеђена је NULL референца"
+
+msgid "internal error: invalid value type"
+msgstr "интерна грешка: вредноÑÑ‚ неважећег типа"
+
+msgid ""
+"Failed to set path hook: sys.path_hooks is not a list\n"
+"You should now do the following:\n"
+"- append vim.path_hook to sys.path_hooks\n"
+"- append vim.VIM_SPECIAL_PATH to sys.path\n"
+msgstr ""
+"Кука за путању није могла да Ñе поÑтави: sys.path_hooks није у лиÑти\n"
+"Сада би требало да урадите Ñледеће:\n"
+"- додајте vim.path_hook на крај sys.path_hooks\n"
+"- додајте vim.VIM_SPECIAL_PATH на крај sys.path\n"
+
+msgid ""
+"Failed to set path: sys.path is not a list\n"
+"You should now append vim.VIM_SPECIAL_PATH to sys.path"
+msgstr ""
+"Путања није могла да Ñе поÑтави: sys.path није у лиÑти\n"
+"Сада би требало да додате vim.VIM_SPECIAL_PATH на крај sys.path"
+
+msgid ""
+"Vim macro files (*.vim)\t*.vim\n"
+"All Files (*.*)\t*.*\n"
+msgstr ""
+"Vim макро датотеке (*.vim)\t*.vim\n"
+"Све датотеке (*.*)\t*.*\n"
+
+msgid "All Files (*.*)\t*.*\n"
+msgstr "Све датотеке (*.*)\t*.*\n"
+
+msgid ""
+"All Files (*.*)\t*.*\n"
+"C source (*.c, *.h)\t*.c;*.h\n"
+"C++ source (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"VB code (*.bas, *.frm)\t*.bas;*.frm\n"
+"Vim files (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
+msgstr ""
+"Све датотеке (*.*)\t*.*\n"
+"C изворни код (*.c, *.h)\t*.c;*.h\n"
+"C++ изворни код (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"VB код (*.bas, *.frm)\t*.bas;*.frm\n"
+"Vim датотеке (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
+
+msgid ""
+"Vim macro files (*.vim)\t*.vim\n"
+"All Files (*)\t*\n"
+msgstr ""
+"Vim макро датотеке (*.vim)\t*.vim\n"
+"Све датотеке (*)\t*\n"
+
+msgid "All Files (*)\t*\n"
+msgstr "Све датотеке (*)\t*\n"
+
+msgid ""
+"All Files (*)\t*\n"
+"C source (*.c, *.h)\t*.c;*.h\n"
+"C++ source (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"Vim files (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
+msgstr ""
+"Све датотеке (*)\t*\n"
+"C изворни код (*.c, *.h)\t*.c;*.h\n"
+"C++ изворни код (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"Vim датотеке (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
diff --git a/src/po/sv.po b/src/po/sv.po
new file mode 100644
index 0000000..25533cd
--- /dev/null
+++ b/src/po/sv.po
@@ -0,0 +1,6148 @@
+# Swedish translation for Vim.
+# Copyright (C) 2003-2007 Free Software Foundation, Inc.
+# Johan Svedberg <johan@svedberg.com>, 2003-2007.
+msgid ""
+msgstr ""
+"Project-Id-Version: Vim 7.1\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2007-05-09 14:27+0200\n"
+"PO-Revision-Date: 2007-05-09 14:52\n"
+"Last-Translator: Johan Svedberg <johan@svedberg.com>\n"
+"Language-Team: Swedish <tp-sv@listor.tp-sv.se>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-1\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "E82: Cannot allocate any buffer, exiting..."
+msgstr "E82: Kan inte allokera någon buffert, avslutar..."
+
+msgid "E83: Cannot allocate buffer, using other one..."
+msgstr "E83: Kan inte allokera buffert, använder en annan..."
+
+msgid "E515: No buffers were unloaded"
+msgstr "E515: Inga buffertar blev urladdade"
+
+msgid "E516: No buffers were deleted"
+msgstr "E516: Inga buffertar blev borttagna"
+
+msgid "E517: No buffers were wiped out"
+msgstr "E517: Inga buffertar blev utraderade"
+
+msgid "1 buffer unloaded"
+msgstr "1 buffert laddades ur"
+
+#, c-format
+msgid "%d buffers unloaded"
+msgstr "%d buffertar laddades ur"
+
+msgid "1 buffer deleted"
+msgstr "1 buffert borttagen"
+
+#, c-format
+msgid "%d buffers deleted"
+msgstr "%d buffertar borttagna"
+
+msgid "1 buffer wiped out"
+msgstr "1 buffert utraderad"
+
+#, c-format
+msgid "%d buffers wiped out"
+msgstr "%d buffertar utraderade"
+
+msgid "E84: No modified buffer found"
+msgstr "E84: Ingen modifierad buffert hittad"
+
+#. back where we started, didn't find anything.
+msgid "E85: There is no listed buffer"
+msgstr "E85: Det finns inga listade buffertar"
+
+#, c-format
+msgid "E86: Buffer %ld does not exist"
+msgstr "E86: Buffert %ld existerar inte"
+
+msgid "E87: Cannot go beyond last buffer"
+msgstr "E87: Kan inte gå bortom sista buffert"
+
+msgid "E88: Cannot go before first buffer"
+msgstr "E88: Kan inte gå före första buffert"
+
+#, c-format
+msgid "E89: No write since last change for buffer %ld (add ! to override)"
+msgstr ""
+"E89: Ingen skrivning sedan senaste ändring för buffert %ld (lägg till ! för "
+"att tvinga)"
+
+msgid "E90: Cannot unload last buffer"
+msgstr "E90: Kan inte ladda ur senaste buffert"
+
+msgid "W14: Warning: List of file names overflow"
+msgstr "W14: Varning: Lista över filnamn flödar över"
+
+#, c-format
+msgid "E92: Buffer %ld not found"
+msgstr "E92: Buffer %ld hittades inte"
+
+#, c-format
+msgid "E93: More than one match for %s"
+msgstr "E93: Fler än en träff för %s"
+
+#, c-format
+msgid "E94: No matching buffer for %s"
+msgstr "E94: Ingen matchande buffert för %s"
+
+#, c-format
+msgid "line %ld"
+msgstr "rad %ld"
+
+msgid "E95: Buffer with this name already exists"
+msgstr "E95: Buffer med det här namnet existerar redan"
+
+msgid " [Modified]"
+msgstr " [Modifierad]"
+
+msgid "[Not edited]"
+msgstr "[Inte redigerad]"
+
+msgid "[New file]"
+msgstr "[Ny fil]"
+
+msgid "[Read errors]"
+msgstr "[Läsfel]"
+
+msgid "[readonly]"
+msgstr "[skrivskyddad]"
+
+#, c-format
+msgid "1 line --%d%%--"
+msgstr "1 rad --%d%%--"
+
+#, c-format
+msgid "%ld lines --%d%%--"
+msgstr "%ld rader --%d%%--"
+
+#, c-format
+msgid "line %ld of %ld --%d%%-- col "
+msgstr "rad %ld av %ld --%d%%-- kol "
+
+msgid "[No Name]"
+msgstr "[Inget Namn]"
+
+#. must be a help buffer
+msgid "help"
+msgstr "hjälp"
+
+msgid "[Help]"
+msgstr "[Hjälp]"
+
+msgid "[Preview]"
+msgstr "[Förhandsvisning]"
+
+msgid "All"
+msgstr "Alla"
+
+msgid "Bot"
+msgstr "Bott"
+
+msgid "Top"
+msgstr "Topp"
+
+#, c-format
+msgid ""
+"\n"
+"# Buffer list:\n"
+msgstr ""
+"\n"
+"# Buffertlista:\n"
+
+msgid "[Location List]"
+msgstr "[Positionslista]"
+
+msgid "[Quickfix List]"
+msgstr "[Quickfix-lista]"
+
+msgid ""
+"\n"
+"--- Signs ---"
+msgstr ""
+"\n"
+"--- Tecken ---"
+
+#, c-format
+msgid "Signs for %s:"
+msgstr "Tecken för %s:"
+
+#, c-format
+msgid " line=%ld id=%d name=%s"
+msgstr " line=%ld id=%d namn=%s"
+
+#, c-format
+msgid "E96: Can not diff more than %ld buffers"
+msgstr "E96: Kan inte skilja fler än %ld buffertar"
+
+msgid "E97: Cannot create diffs"
+msgstr "E97: Kan inte skapa skiljare"
+
+msgid "Patch file"
+msgstr "Patchfil"
+
+msgid "E98: Cannot read diff output"
+msgstr "E98: Kan inte läsa skiljeutdata"
+
+msgid "E99: Current buffer is not in diff mode"
+msgstr "E99: Aktuell buffert är inte i skiljeläge"
+
+msgid "E793: No other buffer in diff mode is modifiable"
+msgstr "E793: Ingen annan buffert i skiljeläge är ändringsbar"
+
+msgid "E100: No other buffer in diff mode"
+msgstr "E100: Ingen annan buffert i skiljeläge"
+
+msgid "E101: More than two buffers in diff mode, don't know which one to use"
+msgstr ""
+"E101: Fler än två buffertar i skiljeläge, vet inte vilken som ska användas"
+
+#, c-format
+msgid "E102: Can't find buffer \"%s\""
+msgstr "E102: Kan inte hitta buffert \"%s\""
+
+#, c-format
+msgid "E103: Buffer \"%s\" is not in diff mode"
+msgstr "E103: Buffert \"%s\" är inte i skiljeläge"
+
+msgid "E787: Buffer changed unexpectedly"
+msgstr "E787: Buffert ändrades oväntat"
+
+msgid "E104: Escape not allowed in digraph"
+msgstr "E104: Escape inte tillåtet i digraf"
+
+msgid "E544: Keymap file not found"
+msgstr "E544: Keymap-fil hittades inte"
+
+msgid "E105: Using :loadkeymap not in a sourced file"
+msgstr "E105: Användning av :loadkeymap utanför en körd fil"
+
+msgid "E791: Empty keymap entry"
+msgstr "E791: Tomt tangentbords-post"
+
+msgid " Keyword completion (^N^P)"
+msgstr " Nyckelordskomplettering (^N^P)"
+
+#. ctrl_x_mode == 0, ^P/^N compl.
+msgid " ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+msgstr " ^X-läge (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+
+msgid " Whole line completion (^L^N^P)"
+msgstr " Helradskomplettering (^L^N^P)"
+
+msgid " File name completion (^F^N^P)"
+msgstr " Filnamnskomplettering (^F^N^P)"
+
+msgid " Tag completion (^]^N^P)"
+msgstr " Taggkomplettering (^]^N^P)"
+
+msgid " Path pattern completion (^N^P)"
+msgstr " Sökvägsmönsterkomplettering (^N^P)"
+
+msgid " Definition completion (^D^N^P)"
+msgstr " Definitionskomplettering (^D^N^P)"
+
+msgid " Dictionary completion (^K^N^P)"
+msgstr " Ordbokskomplettering (^K^N^P)"
+
+msgid " Thesaurus completion (^T^N^P)"
+msgstr " Tesaurkomplettering (^T^N^P)"
+
+msgid " Command-line completion (^V^N^P)"
+msgstr " Kommandoradskomplettering (^V^N^P)"
+
+msgid " User defined completion (^U^N^P)"
+msgstr " Användardefinierad komplettering (^U^N^P)"
+
+msgid " Omni completion (^O^N^P)"
+msgstr " Omnikomplettering (^O^N^P)"
+
+msgid " Spelling suggestion (s^N^P)"
+msgstr " Stavningsförslag (s^N^P)"
+
+msgid " Keyword Local completion (^N^P)"
+msgstr " Lokal nyckelordskomplettering (^N^P)"
+
+msgid "Hit end of paragraph"
+msgstr "Stötte på slutet på stycket"
+
+msgid "'dictionary' option is empty"
+msgstr "'dictionary'-flagga är tom"
+
+msgid "'thesaurus' option is empty"
+msgstr "'thesaurus'-flagga är tom"
+
+#, c-format
+msgid "Scanning dictionary: %s"
+msgstr "Söker igenom ordbok: %s"
+
+msgid " (insert) Scroll (^E/^Y)"
+msgstr " (infoga) Rulla (^E/^Y)"
+
+msgid " (replace) Scroll (^E/^Y)"
+msgstr " (ersätt) Rulla (^E/^Y)"
+
+#, c-format
+msgid "Scanning: %s"
+msgstr "Söker igenom: %s"
+
+#, c-format
+msgid "Scanning tags."
+msgstr "Söker igenom taggar."
+
+msgid " Adding"
+msgstr " Lägger till"
+
+#. showmode might reset the internal line pointers, so it must
+#. * be called before line = ml_get(), or when this address is no
+#. * longer needed. -- Acevedo.
+#.
+msgid "-- Searching..."
+msgstr "-- Söker..."
+
+msgid "Back at original"
+msgstr "Tillbaka på orginalet"
+
+msgid "Word from other line"
+msgstr "Ord från annan rad"
+
+msgid "The only match"
+msgstr "Den enda träffen"
+
+#, c-format
+msgid "match %d of %d"
+msgstr "träff %d av %d"
+
+#, c-format
+msgid "match %d"
+msgstr "träff %d"
+
+msgid "E18: Unexpected characters in :let"
+msgstr "E18: Oväntade tecken i :let"
+
+#, c-format
+msgid "E684: list index out of range: %ld"
+msgstr "E684: listindex utanför område: %ld"
+
+#, c-format
+msgid "E121: Undefined variable: %s"
+msgstr "E121: Odefinierad variabel: %s"
+
+msgid "E111: Missing ']'"
+msgstr "E111: Saknar ']'"
+
+#, c-format
+msgid "E686: Argument of %s must be a List"
+msgstr "E686: Argument av %s måste vara en List"
+
+#, c-format
+msgid "E712: Argument of %s must be a List or Dictionary"
+msgstr "E712: Argument av %s måste vara en Lista eller Tabell"
+
+msgid "E713: Cannot use empty key for Dictionary"
+msgstr "E713: Kan inte använda tom nyckel för Tabell"
+
+msgid "E714: List required"
+msgstr "E714: Lista krävs"
+
+msgid "E715: Dictionary required"
+msgstr "E715: Tabell krävs"
+
+#, c-format
+msgid "E118: Too many arguments for function: %s"
+msgstr "E118: För många argument till funktion: %s"
+
+#, c-format
+msgid "E716: Key not present in Dictionary: %s"
+msgstr "E716: Tangent finns inte i Tabell: %s"
+
+#, c-format
+msgid "E122: Function %s already exists, add ! to replace it"
+msgstr "E122: Funktionen %s existerar redan, lägg till ! för att ersätta den"
+
+msgid "E717: Dictionary entry already exists"
+msgstr "E717: Tabell-post existerar redan"
+
+msgid "E718: Funcref required"
+msgstr "E718: Funcref krävs"
+
+msgid "E719: Cannot use [:] with a Dictionary"
+msgstr "E719: Kan inte använda [:] med en Tabell"
+
+#, c-format
+msgid "E734: Wrong variable type for %s="
+msgstr "E734: Fel variabeltyp för %s="
+
+#, c-format
+msgid "E130: Unknown function: %s"
+msgstr "E130: Okänd funktion: %s"
+
+#, c-format
+msgid "E461: Illegal variable name: %s"
+msgstr "E461: Otillåtet variabelnamn: %s"
+
+msgid "E687: Less targets than List items"
+msgstr "E687: Färre mål än List-poster"
+
+msgid "E688: More targets than List items"
+msgstr "E688: Fler mål än List-poster"
+
+msgid "Double ; in list of variables"
+msgstr "Double ; i listan med variabler"
+
+#, c-format
+msgid "E738: Can't list variables for %s"
+msgstr "E738: Kan inte lista variabler för %s"
+
+msgid "E689: Can only index a List or Dictionary"
+msgstr "E689: Kan bara indexera en Lista eller Tabell"
+
+msgid "E708: [:] must come last"
+msgstr "E708: [:] måste komma sist"
+
+msgid "E709: [:] requires a List value"
+msgstr "E709: [:] kräver ett List-värde"
+
+msgid "E710: List value has more items than target"
+msgstr "E710: List-värde har mer föremål än mål"
+
+msgid "E711: List value has not enough items"
+msgstr "E711: List-värde har inte tillräckligt med föremål"
+
+msgid "E690: Missing \"in\" after :for"
+msgstr "E690: Saknar \"in\" efter :for"
+
+#, c-format
+msgid "E107: Missing parentheses: %s"
+msgstr "E107: Saknar hakparantes: %s"
+
+#, c-format
+msgid "E108: No such variable: \"%s\""
+msgstr "E108: Ingen sådan variabel: \"%s\""
+
+msgid "E743: variable nested too deep for (un)lock"
+msgstr "E743: variabel nästlade för djupt för (un)lock"
+
+msgid "E109: Missing ':' after '?'"
+msgstr "E109: Saknar ':' efter '?'"
+
+msgid "E691: Can only compare List with List"
+msgstr "E691: Kan bara jämföra Lista med Lista"
+
+msgid "E692: Invalid operation for List"
+msgstr "E692: Ogiltig operation för Lista"
+
+msgid "E735: Can only compare Dictionary with Dictionary"
+msgstr "E735: Kan bara jämföra Tabell med Tabell"
+
+msgid "E736: Invalid operation for Dictionary"
+msgstr "E736: Ogiltig operation för Tabell"
+
+msgid "E693: Can only compare Funcref with Funcref"
+msgstr "E693: Kan bara jämföra Funcref med Funcref"
+
+msgid "E694: Invalid operation for Funcrefs"
+msgstr "E694: Ogiltig operation för Funcrefs"
+
+msgid "E110: Missing ')'"
+msgstr "E110: Saknar ')'"
+
+msgid "E695: Cannot index a Funcref"
+msgstr "E695: Kan inte indexera en Funcref"
+
+#, c-format
+msgid "E112: Option name missing: %s"
+msgstr "E112: Flaggnamn saknas: %s"
+
+#, c-format
+msgid "E113: Unknown option: %s"
+msgstr "E113: Okänd flagga: %s"
+
+#, c-format
+msgid "E114: Missing quote: %s"
+msgstr "E114: Saknar citattecken: %s"
+
+#, c-format
+msgid "E115: Missing quote: %s"
+msgstr "E115: Saknar citattecken: %s"
+
+#, c-format
+msgid "E696: Missing comma in List: %s"
+msgstr "E696: Saknar komma i Lista: %s"
+
+#, c-format
+msgid "E697: Missing end of List ']': %s"
+msgstr "E697: Saknar slut på Lista ']': %s"
+
+#, c-format
+msgid "E720: Missing colon in Dictionary: %s"
+msgstr "E720: Saknar kolon i Tabell: %s"
+
+#, c-format
+msgid "E721: Duplicate key in Dictionary: \"%s\""
+msgstr "E721: Duplicerad nyckel i Tabell: \"%s\""
+
+#, c-format
+msgid "E722: Missing comma in Dictionary: %s"
+msgstr "E722: Saknar komma i Tabell: %s"
+
+#, c-format
+msgid "E723: Missing end of Dictionary '}': %s"
+msgstr "E723: Saknar slut på Tabell '}': %s"
+
+msgid "E724: variable nested too deep for displaying"
+msgstr "E724: variabel nästlad för djupt för att visas"
+
+#, c-format
+msgid "E117: Unknown function: %s"
+msgstr "E117: Okänd funktion: %s"
+
+#, c-format
+msgid "E119: Not enough arguments for function: %s"
+msgstr "E119: För få argument till funktion: %s"
+
+#, c-format
+msgid "E120: Using <SID> not in a script context: %s"
+msgstr "E120: Använder inte <SID> i ett skriptsammanhang: %s"
+
+#, c-format
+msgid "E725: Calling dict function without Dictionary: %s"
+msgstr "E725: Anropar tabell-funktion utan Tabell: %s"
+
+msgid "E699: Too many arguments"
+msgstr "E699: För många argument"
+
+msgid "E785: complete() can only be used in Insert mode"
+msgstr "E785: complete() kan bara användas i infogningsläge"
+
+#.
+#. * Yes this is ugly, I don't particularly like it either. But doing it
+#. * this way has the compelling advantage that translations need not to
+#. * be touched at all. See below what 'ok' and 'ync' are used for.
+#.
+msgid "&Ok"
+msgstr "&Ok"
+
+#, c-format
+msgid "E737: Key already exists: %s"
+msgstr "E737: Tangenten finns redan: %s"
+
+#, c-format
+msgid "+-%s%3ld lines: "
+msgstr "+-%s%3ld rader: "
+
+#, c-format
+msgid "E700: Unknown function: %s"
+msgstr "E700: Okänd funktion: %s"
+
+msgid ""
+"&OK\n"
+"&Cancel"
+msgstr ""
+"&OK\n"
+"&Avbryt"
+
+msgid "called inputrestore() more often than inputsave()"
+msgstr "anropade inputrestore() oftare än inputsave()"
+
+msgid "E786: Range not allowed"
+msgstr "E786: Område otillåtet"
+
+msgid "E701: Invalid type for len()"
+msgstr "E701: Ogiltig typ för len()"
+
+msgid "E726: Stride is zero"
+msgstr "E726: Kliv är noll"
+
+msgid "E727: Start past end"
+msgstr "E727: Start efter slut"
+
+msgid "<empty>"
+msgstr "<tom>"
+
+msgid "E240: No connection to Vim server"
+msgstr "E240: Ingen anslutning till Vim-server"
+
+#, c-format
+msgid "E241: Unable to send to %s"
+msgstr "E241: Kunde inte sända till %s"
+
+msgid "E277: Unable to read a server reply"
+msgstr "E277: Kunde inte läsa ett serversvar"
+
+msgid "E655: Too many symbolic links (cycle?)"
+msgstr "E655: För många symboliska länkar (slinga?)"
+
+msgid "E258: Unable to send to client"
+msgstr "E258: Kunde inte sända till klient"
+
+msgid "E702: Sort compare function failed"
+msgstr "E702: Jämförelsefunktionen för sortering misslyckades"
+
+msgid "(Invalid)"
+msgstr "(Ogiltig)"
+
+msgid "E677: Error writing temp file"
+msgstr "E677: Fel vid skrivning av temporär fil"
+
+msgid "E703: Using a Funcref as a Number"
+msgstr "E703: Använder en Funcref som en siffra"
+
+msgid "E745: Using a List as a Number"
+msgstr "E745: Använder en Lista som en siffra"
+
+msgid "E728: Using a Dictionary as a Number"
+msgstr "E728: Använder en Tabell som en siffra"
+
+msgid "E729: using Funcref as a String"
+msgstr "E729: använder Funcref som en Sträng"
+
+msgid "E730: using List as a String"
+msgstr "E730: använder Lista som en Sträng"
+
+msgid "E731: using Dictionary as a String"
+msgstr "E731: använder Tabell som en Sträng"
+
+#, c-format
+msgid "E704: Funcref variable name must start with a capital: %s"
+msgstr "E704: Variabelnamn för Funcref måste börja med en versal: %s"
+
+#, c-format
+msgid "E705: Variable name conflicts with existing function: %s"
+msgstr "E705: Variabelnamn konflikterar med existerande funktion %s"
+
+#, c-format
+msgid "E706: Variable type mismatch for: %s"
+msgstr "E706: Variabeltyp matchar inte för: %s"
+
+#, c-format
+msgid "E795: Cannot delete variable %s"
+msgstr "E795: Kan inte ta bort variabel %s"
+
+#, c-format
+msgid "E741: Value is locked: %s"
+msgstr "E741: Värde är låst: %s"
+
+msgid "Unknown"
+msgstr "Okänd"
+
+#, c-format
+msgid "E742: Cannot change value of %s"
+msgstr "E742: Kan inte ändra värde av %s"
+
+msgid "E698: variable nested too deep for making a copy"
+msgstr "E698: variabel nästlad för djupt för att skapa en kopia"
+
+#, c-format
+msgid "E124: Missing '(': %s"
+msgstr "E124: Saknar '(': %s"
+
+#, c-format
+msgid "E125: Illegal argument: %s"
+msgstr "E125: Otillåtet argument: %s"
+
+msgid "E126: Missing :endfunction"
+msgstr "E126: Saknar :endfunction"
+
+#, c-format
+msgid "E746: Function name does not match script file name: %s"
+msgstr "E746: Funktionsnamn matchar inte skriptfilnamn: %s"
+
+msgid "E129: Function name required"
+msgstr "E129: Funktionsnamn krävs"
+
+#, c-format
+msgid "E128: Function name must start with a capital or contain a colon: %s"
+msgstr ""
+"E128: Funktionsnamn måste börja med en versal eller innehålla ett kolon: %s"
+
+#, c-format
+msgid "E131: Cannot delete function %s: It is in use"
+msgstr "E131: Kan inte ta bort funktion %s: Den används"
+
+msgid "E132: Function call depth is higher than 'maxfuncdepth'"
+msgstr "E132: Djupet på funktionsanropet är högre än 'maxfuncdepth'"
+
+#, c-format
+msgid "calling %s"
+msgstr "anropar %s"
+
+#, c-format
+msgid "%s aborted"
+msgstr "%s avbröts"
+
+#, c-format
+msgid "%s returning #%ld"
+msgstr "%s returnerar #%ld"
+
+#, c-format
+msgid "%s returning %s"
+msgstr "%s returnerar %s"
+
+#, c-format
+msgid "continuing in %s"
+msgstr "fortsätter i %s"
+
+msgid "E133: :return not inside a function"
+msgstr "E133: :return inte inom en funktion"
+
+#, c-format
+msgid ""
+"\n"
+"# global variables:\n"
+msgstr ""
+"\n"
+"# globala variabler:\n"
+
+msgid ""
+"\n"
+"\tLast set from "
+msgstr ""
+"\n"
+"\tSenast satt från "
+
+msgid "Entering Debug mode. Type \"cont\" to continue."
+msgstr "Går in i felsökningsläge. Skriv \"cont\" för att fortsätta."
+
+#, c-format
+msgid "line %ld: %s"
+msgstr "rad %ld: %s"
+
+#, c-format
+msgid "cmd: %s"
+msgstr "kommando: %s"
+
+#, c-format
+msgid "Breakpoint in \"%s%s\" line %ld"
+msgstr "Brytpunkt i \"%s%s\" rad %ld"
+
+#, c-format
+msgid "E161: Breakpoint not found: %s"
+msgstr "E161: Brytpunkt hittades inte: %s"
+
+msgid "No breakpoints defined"
+msgstr "Inga brytpunkter definierade"
+
+#, c-format
+msgid "%3d %s %s line %ld"
+msgstr "%3d %s %s rad %ld"
+
+msgid "E750: First use :profile start <fname>"
+msgstr "E750: Använd :profile start <fnamn> först"
+
+msgid "Save As"
+msgstr "Spara som"
+
+#, c-format
+msgid "Save changes to \"%s\"?"
+msgstr "Spara ändringar till \"%s\"?"
+
+msgid "Untitled"
+msgstr "Namnlös"
+
+#, c-format
+msgid "E162: No write since last change for buffer \"%s\""
+msgstr "E162: Ingen skrivning sedan senaste ändring för buffert \"%s\""
+
+msgid "Warning: Entered other buffer unexpectedly (check autocommands)"
+msgstr "Varning: Gick in i andra buffertar oväntat (kontrollera autokommandon)"
+
+msgid "E163: There is only one file to edit"
+msgstr "E163: Det finns bara en fil att redigera"
+
+msgid "E164: Cannot go before first file"
+msgstr "E164: Kan inte gå före första filen"
+
+msgid "E165: Cannot go beyond last file"
+msgstr "E165: Kan inte gå bortom sista filen"
+
+#, c-format
+msgid "E666: compiler not supported: %s"
+msgstr "E666: kompilator stöds inte: %s"
+
+#, c-format
+msgid "Searching for \"%s\" in \"%s\""
+msgstr "Söker efter \"%s\" i \"%s\""
+
+#, c-format
+msgid "Searching for \"%s\""
+msgstr "Söker efter \"%s\""
+
+#, c-format
+msgid "not found in 'runtimepath': \"%s\""
+msgstr "hittades inte i 'runtimepath': \"%s\""
+
+msgid "Source Vim script"
+msgstr "Läs Vim-skript"
+
+#, c-format
+msgid "Cannot source a directory: \"%s\""
+msgstr "Kan inte läsa en katalog: \"%s\""
+
+#, c-format
+msgid "could not source \"%s\""
+msgstr "kunde inte läsa \"%s\""
+
+#, c-format
+msgid "line %ld: could not source \"%s\""
+msgstr "rad %ld: kunde inte läsa \"%s\""
+
+#, c-format
+msgid "sourcing \"%s\""
+msgstr "läser \"%s\""
+
+#, c-format
+msgid "line %ld: sourcing \"%s\""
+msgstr "rad %ld: läser \"%s\""
+
+#, c-format
+msgid "finished sourcing %s"
+msgstr "läste klart %s"
+
+msgid "modeline"
+msgstr "lägesrad"
+
+msgid "--cmd argument"
+msgstr "--cmd argument"
+
+msgid "-c argument"
+msgstr "-c argument"
+
+msgid "environment variable"
+msgstr "miljövariabel"
+
+msgid "error handler"
+msgstr "felhanterare"
+
+msgid "W15: Warning: Wrong line separator, ^M may be missing"
+msgstr "W15: Varning: Fel radavskiljare, ^M kan saknas"
+
+msgid "E167: :scriptencoding used outside of a sourced file"
+msgstr "E167: :scriptencoding används utanför en körd fil"
+
+msgid "E168: :finish used outside of a sourced file"
+msgstr "E168: :finish används utanför en körd fil"
+
+#, c-format
+msgid "Current %slanguage: \"%s\""
+msgstr "Aktuellt %sspråk: \"%s\""
+
+#, c-format
+msgid "E197: Cannot set language to \"%s\""
+msgstr "E197: Kan inte sätta språk till \"%s\""
+
+#, c-format
+msgid "<%s>%s%s %d, Hex %02x, Octal %03o"
+msgstr "<%s>%s%s %d, Hex %02x, Oktalt %03o"
+
+#, c-format
+msgid "> %d, Hex %04x, Octal %o"
+msgstr "> %d, Hex %04x, Oktalt %o"
+
+#, c-format
+msgid "> %d, Hex %08x, Octal %o"
+msgstr "> %d, Hex %08x, Oktalt %o"
+
+msgid "E134: Move lines into themselves"
+msgstr "E134: Flytta rader in i dem själva"
+
+msgid "1 line moved"
+msgstr "1 rad flyttad"
+
+#, c-format
+msgid "%ld lines moved"
+msgstr "%ld rader flyttade"
+
+#, c-format
+msgid "%ld lines filtered"
+msgstr "%ld rader filtrerade"
+
+msgid "E135: *Filter* Autocommands must not change current buffer"
+msgstr "E135: *Filter*-Autokommandon får inte ändra aktuell buffert"
+
+msgid "[No write since last change]\n"
+msgstr "[Ingen skrivning sedan senaste ändring]\n"
+
+#, c-format
+msgid "%sviminfo: %s in line: "
+msgstr "%sviminfo: %s på rad: "
+
+msgid "E136: viminfo: Too many errors, skipping rest of file"
+msgstr "E136: viminfo: För många fel, hoppar över resten av filen"
+
+#, c-format
+msgid "Reading viminfo file \"%s\"%s%s%s"
+msgstr "Läser viminfo-fil \"%s\"%s%s%s"
+
+msgid " info"
+msgstr " info"
+
+msgid " marks"
+msgstr " märken"
+
+msgid " FAILED"
+msgstr " MISSLYCKADES"
+
+#. avoid a wait_return for this message, it's annoying
+#, c-format
+msgid "E137: Viminfo file is not writable: %s"
+msgstr "E137: Viminfo-fil är inte skrivbar: %s"
+
+#, c-format
+msgid "E138: Can't write viminfo file %s!"
+msgstr "E138: Kan inte skriva viminfo-fil %s!"
+
+#, c-format
+msgid "Writing viminfo file \"%s\""
+msgstr "Skriver viminfo-fil \"%s\""
+
+#. Write the info:
+#, c-format
+msgid "# This viminfo file was generated by Vim %s.\n"
+msgstr "# Den här viminfo-filen genererades av Vim %s.\n"
+
+#, c-format
+msgid ""
+"# You may edit it if you're careful!\n"
+"\n"
+msgstr ""
+"# Du får redigera den om du är försiktig!\n"
+"\n"
+
+#, c-format
+msgid "# Value of 'encoding' when this file was written\n"
+msgstr "# Värde av 'encoding' när den här filen blev skriven\n"
+
+msgid "Illegal starting char"
+msgstr "Otillåtet starttecken"
+
+msgid "Write partial file?"
+msgstr "Skriv ofullständig fil?"
+
+msgid "E140: Use ! to write partial buffer"
+msgstr "E140: Använd ! för att skriva ofullständig buffert"
+
+#, c-format
+msgid "Overwrite existing file \"%s\"?"
+msgstr "Skriv över befintlig fil \"%s\"?"
+
+#, c-format
+msgid "Swap file \"%s\" exists, overwrite anyway?"
+msgstr "Växlingsfil \"%s\" existerar, skriv över ändå?"
+
+#, c-format
+msgid "E768: Swap file exists: %s (:silent! overrides)"
+msgstr "E768: Växlingsfil existerar: %s (:silent! tvingar)"
+
+#, c-format
+msgid "E141: No file name for buffer %ld"
+msgstr "E141: Inget filnamn för buffert %ld"
+
+msgid "E142: File not written: Writing is disabled by 'write' option"
+msgstr "E142: Filen skrevs inte: Skrivning är inaktiverat med 'write'-flaggan"
+
+#, c-format
+msgid ""
+"'readonly' option is set for \"%s\".\n"
+"Do you wish to write anyway?"
+msgstr ""
+"'readonly' flaggan är satt för \"%s\".\n"
+"Önskar du att skriva ändå?"
+
+msgid "Edit File"
+msgstr "Redigera fil"
+
+#, c-format
+msgid "E143: Autocommands unexpectedly deleted new buffer %s"
+msgstr "E143: Autokommandon tog oväntat bort ny buffert %s"
+
+msgid "E144: non-numeric argument to :z"
+msgstr "E144: ickenumeriskt argument till :z"
+
+msgid "E145: Shell commands not allowed in rvim"
+msgstr "E145: Skalkommandon inte tillåtna i rvim"
+
+msgid "E146: Regular expressions can't be delimited by letters"
+msgstr "E146: Reguljära uttryck kan inte vara åtskilda av bokstäver"
+
+#, c-format
+msgid "replace with %s (y/n/a/q/l/^E/^Y)?"
+msgstr "ersätt med %s (y/n/a/q/l/^E/^Y)?"
+
+msgid "(Interrupted) "
+msgstr "(Avbruten) "
+
+msgid "1 match"
+msgstr "1 träff"
+
+msgid "1 substitution"
+msgstr "1 ersättning"
+
+#, c-format
+msgid "%ld matches"
+msgstr "%ld träffar"
+
+#, c-format
+msgid "%ld substitutions"
+msgstr "%ld ersättningar"
+
+msgid " on 1 line"
+msgstr " på 1 rad"
+
+#, c-format
+msgid " on %ld lines"
+msgstr " på %ld rader"
+
+msgid "E147: Cannot do :global recursive"
+msgstr "E147: Kan inte göra :global rekursivt"
+
+msgid "E148: Regular expression missing from global"
+msgstr "E148: Reguljärt uttryck saknas från global"
+
+#, c-format
+msgid "Pattern found in every line: %s"
+msgstr "Mönster funnet i varje rad: %s"
+
+#, c-format
+msgid ""
+"\n"
+"# Last Substitute String:\n"
+"$"
+msgstr ""
+"\n"
+"# Senaste ersättningssträng:\n"
+"$"
+
+msgid "E478: Don't panic!"
+msgstr "E478: Få inte panik!"
+
+#, c-format
+msgid "E661: Sorry, no '%s' help for %s"
+msgstr "E661: Tyvärr, ingen \"%s\"-hjälp för %s"
+
+#, c-format
+msgid "E149: Sorry, no help for %s"
+msgstr "E149: Tyvärr, ingen hjälp för %s"
+
+#, c-format
+msgid "Sorry, help file \"%s\" not found"
+msgstr "Tyvärr, hjälpfil \"%s\" hittades inte"
+
+#, c-format
+msgid "E150: Not a directory: %s"
+msgstr "E150: Inte en katalog: %s"
+
+#, c-format
+msgid "E152: Cannot open %s for writing"
+msgstr "E152: Kan inte öppna %s för skrivning"
+
+#, c-format
+msgid "E153: Unable to open %s for reading"
+msgstr "E153: Kunde inte öppna %s för läsning"
+
+#, c-format
+msgid "E670: Mix of help file encodings within a language: %s"
+msgstr "E670: Blandning av hjälpfilskodning inom ett språk: %s"
+
+#, c-format
+msgid "E154: Duplicate tag \"%s\" in file %s/%s"
+msgstr "E154: Duplicerad tagg \"%s\" i fil %s/%s"
+
+#, c-format
+msgid "E160: Unknown sign command: %s"
+msgstr "E160: Okänt signaturkommando: %s"
+
+msgid "E156: Missing sign name"
+msgstr "E156: Saknar signaturnamn"
+
+msgid "E612: Too many signs defined"
+msgstr "E612: För många signaturer definierade"
+
+#, c-format
+msgid "E239: Invalid sign text: %s"
+msgstr "E239: Ogiltig signaturtext: %s"
+
+#, c-format
+msgid "E155: Unknown sign: %s"
+msgstr "E155: Okänd signatur: %s"
+
+msgid "E159: Missing sign number"
+msgstr "E159: Saknar signaturnummer"
+
+#, c-format
+msgid "E158: Invalid buffer name: %s"
+msgstr "E158: Ogiltigt buffertnamn: %s"
+
+#, c-format
+msgid "E157: Invalid sign ID: %ld"
+msgstr "E157: Ogiltigt signatur-ID: %ld"
+
+msgid " (NOT FOUND)"
+msgstr " (INTE HITTADE)"
+
+msgid " (not supported)"
+msgstr " (stöds inte)"
+
+msgid "[Deleted]"
+msgstr "[Borttagen]"
+
+msgid "Entering Ex mode. Type \"visual\" to go to Normal mode."
+msgstr "Går in i Ex-läge. Skriv \"visual\" för att gå till Normal-läge."
+
+msgid "E501: At end-of-file"
+msgstr "E501: Vid filslut"
+
+msgid "E169: Command too recursive"
+msgstr "E169: Kommando för rekursivt"
+
+#, c-format
+msgid "E605: Exception not caught: %s"
+msgstr "E605: Undantag inte fångat: %s"
+
+msgid "End of sourced file"
+msgstr "Slut på läst fil"
+
+msgid "End of function"
+msgstr "Slut på funktion"
+
+msgid "E464: Ambiguous use of user-defined command"
+msgstr "E464: Otydlig användning av användardefinierat kommando"
+
+msgid "E492: Not an editor command"
+msgstr "E492: Inte ett redigerarkommando"
+
+msgid "E493: Backwards range given"
+msgstr "E493: Bakåtområde givet"
+
+msgid "Backwards range given, OK to swap"
+msgstr "Bakåtområde givet, OK att växla"
+
+msgid "E494: Use w or w>>"
+msgstr "E494: Använd w eller w>>"
+
+msgid "E319: Sorry, the command is not available in this version"
+msgstr "E319: Tyvärr, kommandot är inte tillgängligt i den här versionen"
+
+msgid "E172: Only one file name allowed"
+msgstr "E172: Bara ett filnamn tillåtet"
+
+msgid "1 more file to edit. Quit anyway?"
+msgstr "1 fil till att redigera. Avsluta ändå?"
+
+#, c-format
+msgid "%d more files to edit. Quit anyway?"
+msgstr "%d filer till att redigera. Avsluta ändå?"
+
+msgid "E173: 1 more file to edit"
+msgstr "E173: 1 fil till att redigera"
+
+#, c-format
+msgid "E173: %ld more files to edit"
+msgstr "E173: %ld filer till att redigera"
+
+msgid "E174: Command already exists: add ! to replace it"
+msgstr "E174: Kommando existerar redan: lägg till ! för att ersätta det"
+
+msgid ""
+"\n"
+" Name Args Range Complete Definition"
+msgstr ""
+"\n"
+" Namn Arg Område Färdigt Definition"
+
+msgid "No user-defined commands found"
+msgstr "Inga användardefinierade kommandon hittade"
+
+msgid "E175: No attribute specified"
+msgstr "E175: Inga attribut angivna"
+
+msgid "E176: Invalid number of arguments"
+msgstr "E176: Ogiltigt antal argument"
+
+msgid "E177: Count cannot be specified twice"
+msgstr "E177: Antal kan inte anges två gånger"
+
+msgid "E178: Invalid default value for count"
+msgstr "E178: Ogiltigt standardvärde för antal"
+
+msgid "E179: argument required for -complete"
+msgstr "E179: argument krävs för -complete"
+
+#, c-format
+msgid "E181: Invalid attribute: %s"
+msgstr "E181: Ogiltigt attribut: %s"
+
+msgid "E182: Invalid command name"
+msgstr "E182: Ogiltigt kommandonamn"
+
+msgid "E183: User defined commands must start with an uppercase letter"
+msgstr "E183: Användardefinierade kommandon måste börja med en stor bokstav"
+
+#, c-format
+msgid "E184: No such user-defined command: %s"
+msgstr "E184: Inget sådant användardefinierat kommando: %s"
+
+#, c-format
+msgid "E180: Invalid complete value: %s"
+msgstr "E180: Ogiltigt kompletteringsvärde: %s"
+
+msgid "E468: Completion argument only allowed for custom completion"
+msgstr "E468: Kompletteringsargument bara tillåtet för specialkomplettering"
+
+msgid "E467: Custom completion requires a function argument"
+msgstr "E467: Specialkomplettering kräver ett funktionsargument"
+
+#, c-format
+msgid "E185: Cannot find color scheme %s"
+msgstr "E185: Kan inte hitta färgschema %s"
+
+msgid "Greetings, Vim user!"
+msgstr "Välkommen, Vim-användare!"
+
+msgid "E784: Cannot close last tab page"
+msgstr "E784: Kan inte stänga senaste flik"
+
+msgid "Already only one tab page"
+msgstr "Redan bara en flik"
+
+msgid "Edit File in new window"
+msgstr "Redigera fil i nytt fönster"
+
+#, c-format
+msgid "Tab page %d"
+msgstr "Flik %d"
+
+msgid "No swap file"
+msgstr "Ingen växlingsfil"
+
+msgid "Append File"
+msgstr "Lägg till fil"
+
+msgid "E747: Cannot change directory, buffer is modified (add ! to override)"
+msgstr ""
+"E747: Kan inte ändra katalog, buffert är ändrad (lägg till ! för att tvinga)"
+
+msgid "E186: No previous directory"
+msgstr "E186: Ingen tidigare katalog"
+
+msgid "E187: Unknown"
+msgstr "E187: Okänt"
+
+msgid "E465: :winsize requires two number arguments"
+msgstr "E465: :winsize kräver två sifferargument"
+
+#, c-format
+msgid "Window position: X %d, Y %d"
+msgstr "Fönsterposition: X %d, Y %d"
+
+msgid "E188: Obtaining window position not implemented for this platform"
+msgstr ""
+"E188: Förskaffa fönsterposition inte implementerat för den här plattformen"
+
+msgid "E466: :winpos requires two number arguments"
+msgstr "E466: :winpos kräver två sifferargument"
+
+msgid "Save Redirection"
+msgstr "Spara omdirigering"
+
+msgid "Save View"
+msgstr "Spara vy"
+
+msgid "Save Session"
+msgstr "Spara session"
+
+msgid "Save Setup"
+msgstr "Spara konfiguration"
+
+#, c-format
+msgid "E739: Cannot create directory: %s"
+msgstr "E739: Kan inte skapa katalog: %s"
+
+#, c-format
+msgid "E189: \"%s\" exists (add ! to override)"
+msgstr "E189: \"%s\" existerar (lägg till ! för att tvinga)"
+
+#, c-format
+msgid "E190: Cannot open \"%s\" for writing"
+msgstr "E190: Kan inte öppna \"%s\" för skrivning"
+
+#. set mark
+msgid "E191: Argument must be a letter or forward/backward quote"
+msgstr ""
+"E191: Argument måste vara en bokstav eller framåt-/bakåtvänt citattecken"
+
+msgid "E192: Recursive use of :normal too deep"
+msgstr "E192: Rekursiv användning av :normal för djup"
+
+msgid "E194: No alternate file name to substitute for '#'"
+msgstr "E194: Inget alternativt filnamn att byta ut '#' med"
+
+msgid "E495: no autocommand file name to substitute for \"<afile>\""
+msgstr "E495: inget autokommando-filnamn att ersätta \"<afile>\" med"
+
+msgid "E496: no autocommand buffer number to substitute for \"<abuf>\""
+msgstr "E496: inget autokommando-buffernummer att ersätta \"<abuf>\" med"
+
+msgid "E497: no autocommand match name to substitute for \"<amatch>\""
+msgstr "E497: inget autokommando-träffnamn att byta ut \"<amatch>\" med"
+
+msgid "E498: no :source file name to substitute for \"<sfile>\""
+msgstr "E498: inget :source-filnamn att byta ut \"<sfile>\" med"
+
+#, no-c-format
+msgid "E499: Empty file name for '%' or '#', only works with \":p:h\""
+msgstr "E499: Tomt filnamn för '%' or '#', fungerar bara med \":p:h\""
+
+msgid "E500: Evaluates to an empty string"
+msgstr "E500: Evaluerar till en tom sträng"
+
+msgid "E195: Cannot open viminfo file for reading"
+msgstr "E195: Kan inte öppna viminfo-fil för läsning"
+
+msgid "E196: No digraphs in this version"
+msgstr "E196: Inga digrafer i den här versionen"
+
+msgid "E608: Cannot :throw exceptions with 'Vim' prefix"
+msgstr "E608: Kan inte :throw undantag med 'Vim'-prefix"
+
+#. always scroll up, don't overwrite
+#, c-format
+msgid "Exception thrown: %s"
+msgstr "Undantag kastade: %s"
+
+#, c-format
+msgid "Exception finished: %s"
+msgstr "Undantag färdiga: %s"
+
+#, c-format
+msgid "Exception discarded: %s"
+msgstr "Undantag förkastade: %s"
+
+#, c-format
+msgid "%s, line %ld"
+msgstr "%s, rad %ld"
+
+#. always scroll up, don't overwrite
+#, c-format
+msgid "Exception caught: %s"
+msgstr "Undantag fångade: %s"
+
+#, c-format
+msgid "%s made pending"
+msgstr "%s gjordes avvaktande"
+
+#, c-format
+msgid "%s resumed"
+msgstr "%s återupptagen"
+
+#, c-format
+msgid "%s discarded"
+msgstr "%s förkastad"
+
+msgid "Exception"
+msgstr "Undantag"
+
+msgid "Error and interrupt"
+msgstr "Fel och avbrytet"
+
+msgid "Error"
+msgstr "Fel"
+
+#. if (pending & CSTP_INTERRUPT)
+msgid "Interrupt"
+msgstr "Avbryt"
+
+msgid "E579: :if nesting too deep"
+msgstr "E579: :if nästlad för djupt"
+
+msgid "E580: :endif without :if"
+msgstr "E580: :endif utan :if"
+
+msgid "E581: :else without :if"
+msgstr "E581: :else utan :if"
+
+msgid "E582: :elseif without :if"
+msgstr "E582: :elseif utan :if"
+
+msgid "E583: multiple :else"
+msgstr "E583: flera :else"
+
+msgid "E584: :elseif after :else"
+msgstr "E584: :elseif efter :else"
+
+msgid "E585: :while/:for nesting too deep"
+msgstr "E585: :while/:for nästlad för djupt"
+
+msgid "E586: :continue without :while or :for"
+msgstr "E586: :continue utan :while eller :for"
+
+msgid "E587: :break without :while or :for"
+msgstr "E587: :break utan :while eller :for"
+
+msgid "E732: Using :endfor with :while"
+msgstr "E732: Använder :endfor med :while"
+
+msgid "E733: Using :endwhile with :for"
+msgstr "E733: Använder :endwhile med :for"
+
+msgid "E601: :try nesting too deep"
+msgstr "E601: :try nästlad för djupt"
+
+msgid "E603: :catch without :try"
+msgstr "E603: :catch utan :try"
+
+#. Give up for a ":catch" after ":finally" and ignore it.
+#. * Just parse.
+msgid "E604: :catch after :finally"
+msgstr "E604: :catch efter :finally"
+
+msgid "E606: :finally without :try"
+msgstr "E606: :finally utan :try"
+
+#. Give up for a multiple ":finally" and ignore it.
+msgid "E607: multiple :finally"
+msgstr "E607: flera :finally"
+
+msgid "E602: :endtry without :try"
+msgstr "E602: :endtry utan :try"
+
+msgid "E193: :endfunction not inside a function"
+msgstr "E193: :endfunction inte inom en funktion"
+
+msgid "E788: Not allowed to edit another buffer now"
+msgstr "E788: Inte tillåtet att redigera en annan buffert nu"
+
+msgid "tagname"
+msgstr "taggnamn"
+
+msgid " kind file\n"
+msgstr " snäll fil\n"
+
+msgid "'history' option is zero"
+msgstr "'history'-flagga är noll"
+
+#, c-format
+msgid ""
+"\n"
+"# %s History (newest to oldest):\n"
+msgstr ""
+"\n"
+"# %s Historia (nyaste till äldsta):\n"
+
+msgid "Command Line"
+msgstr "Kommandorad"
+
+msgid "Search String"
+msgstr "Söksträng"
+
+msgid "Expression"
+msgstr "Uttryck"
+
+msgid "Input Line"
+msgstr "Inmatningsrad"
+
+msgid "E198: cmd_pchar beyond the command length"
+msgstr "E198: cmd_pchar bortom kommandolängden"
+
+msgid "E199: Active window or buffer deleted"
+msgstr "E199: Aktivt fönster eller buffert borttagen"
+
+msgid "Illegal file name"
+msgstr "Otillåtet filnamn"
+
+msgid "is a directory"
+msgstr "är en katalog"
+
+msgid "is not a file"
+msgstr "är inte en fil"
+
+msgid "is a device (disabled with 'opendevice' option)"
+msgstr "är en enhet (inaktiverad med 'opendevice'-flagga)"
+
+msgid "[New File]"
+msgstr "[Ny fil]"
+
+msgid "[New DIRECTORY]"
+msgstr "[Ny KATALOG]"
+
+msgid "[File too big]"
+msgstr "[Fil för stor]"
+
+msgid "[Permission Denied]"
+msgstr "[Tillåtelse nekas]"
+
+msgid "E200: *ReadPre autocommands made the file unreadable"
+msgstr "E200: *ReadPre autokommandon gjorde filen oläsbar"
+
+msgid "E201: *ReadPre autocommands must not change current buffer"
+msgstr "E201: *ReadPre autokommandon får inte ändra nuvarande buffert"
+
+msgid "Vim: Reading from stdin...\n"
+msgstr "Vim: Läser från standard in...\n"
+
+msgid "Reading from stdin..."
+msgstr "Läser från standard in..."
+
+#. Re-opening the original file failed!
+msgid "E202: Conversion made file unreadable!"
+msgstr "E202: Konvertering gjorde filen oläsbar!"
+
+msgid "[fifo/socket]"
+msgstr "[fifo/uttag]"
+
+msgid "[fifo]"
+msgstr "[fifo]"
+
+msgid "[socket]"
+msgstr "[uttag]"
+
+msgid "[RO]"
+msgstr "[EL]"
+
+msgid "[CR missing]"
+msgstr "[CR saknas]"
+
+msgid "[NL found]"
+msgstr "[NL hittat]"
+
+msgid "[long lines split]"
+msgstr "[långa rader delade]"
+
+msgid "[NOT converted]"
+msgstr "[INTE konverterad]"
+
+msgid "[converted]"
+msgstr "[konverterad]"
+
+msgid "[crypted]"
+msgstr "[krypterad]"
+
+#, c-format
+msgid "[CONVERSION ERROR in line %ld]"
+msgstr "[KONVERTERINGSFEL på rad %ld]"
+
+#, c-format
+msgid "[ILLEGAL BYTE in line %ld]"
+msgstr "[OTILLÅTEN BIT på rad %ld]"
+
+msgid "[READ ERRORS]"
+msgstr "[LÄSFEL]"
+
+msgid "Can't find temp file for conversion"
+msgstr "Kan inte hitta temporär fil för konvertering"
+
+msgid "Conversion with 'charconvert' failed"
+msgstr "Konvertering med 'charconvert' misslyckades"
+
+msgid "can't read output of 'charconvert'"
+msgstr "kan inte läsa utdata av 'charconvert'"
+
+msgid "E676: No matching autocommands for acwrite buffer"
+msgstr "E676: Inga matchande autokommandon för acwrite buffert"
+
+msgid "E203: Autocommands deleted or unloaded buffer to be written"
+msgstr ""
+"E203: Autokommandon tog bort eller laddade ur buffert som skulle skrivas"
+
+msgid "E204: Autocommand changed number of lines in unexpected way"
+msgstr "E204: Autokommado ändrade antal rader på ett oväntat sätt"
+
+msgid "NetBeans disallows writes of unmodified buffers"
+msgstr "NetBeans tillåter inte skrivning av omodifierade buffertar"
+
+msgid "Partial writes disallowed for NetBeans buffers"
+msgstr "Delvisa skrivningar tillåts inte i NetBeans-buffertar"
+
+msgid "is not a file or writable device"
+msgstr "är inte en fil eller skrivbar enhet"
+
+msgid "writing to device disabled with 'opendevice' option"
+msgstr "skriver till en enhet inaktiverad med 'opendevice'-flagga"
+
+msgid "is read-only (add ! to override)"
+msgstr "är skrivskyddad (lägg till ! för att tvinga)"
+
+msgid "E506: Can't write to backup file (add ! to override)"
+msgstr "E506: Kan inte skriva till säkerhetskopia (lägg till ! för att tvinga)"
+
+msgid "E507: Close error for backup file (add ! to override)"
+msgstr "E507: Stängningsfel för säkerhetskopia (lägg till ! för att tvinga)"
+
+msgid "E508: Can't read file for backup (add ! to override)"
+msgstr ""
+"E508: Kan inte läsa fil för säkerhetskopia (lägg till ! för att tvinga)"
+
+msgid "E509: Cannot create backup file (add ! to override)"
+msgstr "E509: Kan inte skapa säkerhetskopia (lägg till ! för att tvinga)"
+
+msgid "E510: Can't make backup file (add ! to override)"
+msgstr "E510: Kan inte göra säkerhetskopia (lägg till ! för att tvinga)"
+
+msgid "E460: The resource fork would be lost (add ! to override)"
+msgstr "E460: Resursgrenen skulle tappas bort (lägg till ! för att tvinga)"
+
+msgid "E214: Can't find temp file for writing"
+msgstr "E214: Kan inte hitta temporär fil för skrivning"
+
+msgid "E213: Cannot convert (add ! to write without conversion)"
+msgstr ""
+"E213: Kan inte konvertera (lägg till ! för att skriva utan konvertering)"
+
+msgid "E166: Can't open linked file for writing"
+msgstr "E166: Kan inte öppna länkad fil för skrivning"
+
+msgid "E212: Can't open file for writing"
+msgstr "E212: Kan inte öppna fil för skrivning"
+
+msgid "E667: Fsync failed"
+msgstr "E667: Fsync misslyckades"
+
+msgid "E512: Close failed"
+msgstr "E512: Stängning misslyckades"
+
+msgid "E513: write error, conversion failed (make 'fenc' empty to override)"
+msgstr ""
+"E513: skrivfel, konvertering misslyckades (gör 'fenc' tom för att tvinga)"
+
+msgid "E514: write error (file system full?)"
+msgstr "E514: skrivfel (filsystem fullt?)"
+
+msgid " CONVERSION ERROR"
+msgstr " KONVERTERINGSFEL"
+
+msgid "[Device]"
+msgstr "[Enhet]"
+
+msgid "[New]"
+msgstr "[Ny]"
+
+msgid " [a]"
+msgstr " [l]"
+
+msgid " appended"
+msgstr " lade till"
+
+msgid " [w]"
+msgstr " [s]"
+
+msgid " written"
+msgstr " skriven"
+
+msgid "E205: Patchmode: can't save original file"
+msgstr "E205: Patchläge: kan inte spara orginalfil"
+
+msgid "E206: patchmode: can't touch empty original file"
+msgstr "E206: patchläge: kan inte skapa tom orginalfil"
+
+msgid "E207: Can't delete backup file"
+msgstr "E207: Kan inte ta bort säkerhetskopia"
+
+msgid ""
+"\n"
+"WARNING: Original file may be lost or damaged\n"
+msgstr ""
+"\n"
+"VARNING: Orginalfilen kan vara förlorad eller skadad\n"
+
+msgid "don't quit the editor until the file is successfully written!"
+msgstr "avsluta inte redigeraren innan filen är framgångsrikt skriven"
+
+msgid "[dos]"
+msgstr "[dos]"
+
+msgid "[dos format]"
+msgstr "[dos-format]"
+
+msgid "[mac]"
+msgstr "[mac]"
+
+msgid "[mac format]"
+msgstr "[mac-format]"
+
+msgid "[unix]"
+msgstr "[unix]"
+
+msgid "[unix format]"
+msgstr "[unix-format]"
+
+msgid "1 line, "
+msgstr "1 rad, "
+
+#, c-format
+msgid "%ld lines, "
+msgstr "%ld rader, "
+
+msgid "1 character"
+msgstr "1 tecken"
+
+#, c-format
+msgid "%ld characters"
+msgstr "%ld tecken"
+
+msgid "[noeol]"
+msgstr "[inget radslut]"
+
+msgid "[Incomplete last line]"
+msgstr "[Ofullständig sistarad]"
+
+#. don't overwrite messages here
+#. must give this prompt
+#. don't use emsg() here, don't want to flush the buffers
+msgid "WARNING: The file has been changed since reading it!!!"
+msgstr "VARNING: Filen har ändrats sedan den lästes in!!!"
+
+msgid "Do you really want to write to it"
+msgstr "Vill du verkligen skriva till den"
+
+#, c-format
+msgid "E208: Error writing to \"%s\""
+msgstr "E208: Fel vid skrivning till \"%s\""
+
+#, c-format
+msgid "E209: Error closing \"%s\""
+msgstr "E209: Fel vid stängning av \"%s\""
+
+#, c-format
+msgid "E210: Error reading \"%s\""
+msgstr "E210: Fel vid läsning av \"%s\""
+
+msgid "E246: FileChangedShell autocommand deleted buffer"
+msgstr "E246: FileChangedShell-autokommandot tog bort buffert"
+
+#, c-format
+msgid "E211: File \"%s\" no longer available"
+msgstr "E211: Filen \"%s\" är inte längre tillgänglig"
+
+#, c-format
+msgid ""
+"W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as "
+"well"
+msgstr ""
+"W12: Varning: Filen \"%s\" har ändrats och bufferten ändrades i Vim också"
+
+msgid "See \":help W12\" for more info."
+msgstr "Se \":help W12\" för mer info."
+
+#, c-format
+msgid "W11: Warning: File \"%s\" has changed since editing started"
+msgstr "W11: Varning: Filen \"%s\" har ändrats sedan redigeringen började"
+
+msgid "See \":help W11\" for more info."
+msgstr "Se \":help W11\" för mer info."
+
+#, c-format
+msgid "W16: Warning: Mode of file \"%s\" has changed since editing started"
+msgstr ""
+"W16: Varning: Rättigheterna på filen \"%s\" har ändrats sedan redigeringen "
+"började"
+
+msgid "See \":help W16\" for more info."
+msgstr "Se \":help W16\" för mer info."
+
+#, c-format
+msgid "W13: Warning: File \"%s\" has been created after editing started"
+msgstr "W13: Varning: Filen \"%s\" har skapats efter redigeringen började"
+
+msgid "Warning"
+msgstr "Varning"
+
+msgid ""
+"&OK\n"
+"&Load File"
+msgstr ""
+"&OK\n"
+"&Läs in filen"
+
+#, c-format
+msgid "E462: Could not prepare for reloading \"%s\""
+msgstr "E462: Kunde inte förbereda för att läsa om \"%s\""
+
+#, c-format
+msgid "E321: Could not reload \"%s\""
+msgstr "E321: Kunde inte läsa om \"%s\""
+
+msgid "--Deleted--"
+msgstr "--Borttagen--"
+
+#, c-format
+msgid "auto-removing autocommand: %s <buffer=%d>"
+msgstr "tar bort autokommando automatiskt: %s <buffert=%d>"
+
+#. the group doesn't exist
+#, c-format
+msgid "E367: No such group: \"%s\""
+msgstr "E367: Ingen sådan grupp: \"%s\""
+
+#, c-format
+msgid "E215: Illegal character after *: %s"
+msgstr "E215: Otillåtet tecken efter *: %s"
+
+#, c-format
+msgid "E216: No such event: %s"
+msgstr "E216: Ingen sådan händelse: %s"
+
+#, c-format
+msgid "E216: No such group or event: %s"
+msgstr "E216: Ingen sådan grupp eller händelse: %s"
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Autocommands ---"
+msgstr ""
+"\n"
+"--- Autokommandon ---"
+
+#, c-format
+msgid "E680: <buffer=%d>: invalid buffer number "
+msgstr "E680: <buffert=%d>: ogiltigt buffertnummer "
+
+msgid "E217: Can't execute autocommands for ALL events"
+msgstr "E217: Kan inte köra autokommandon för ALLA händelser"
+
+msgid "No matching autocommands"
+msgstr "Inga matchande autokommandon"
+
+msgid "E218: autocommand nesting too deep"
+msgstr "E218: autokommando nästlad för djupt"
+
+#, c-format
+msgid "%s Autocommands for \"%s\""
+msgstr "%s Autokommandon för \"%s\""
+
+#, c-format
+msgid "Executing %s"
+msgstr "Kör %s"
+
+#, c-format
+msgid "autocommand %s"
+msgstr "autokommando %s"
+
+msgid "E219: Missing {."
+msgstr "E219: Saknar {."
+
+msgid "E220: Missing }."
+msgstr "E220: Saknar }."
+
+msgid "E490: No fold found"
+msgstr "E490: Inget veck funnet"
+
+msgid "E350: Cannot create fold with current 'foldmethod'"
+msgstr "E350: Kan inte skapa veck med nuvarande 'foldmethod'"
+
+msgid "E351: Cannot delete fold with current 'foldmethod'"
+msgstr "E351: Kan inte ta bort veck med nuvarande 'foldmethod'"
+
+#, c-format
+msgid "+--%3ld lines folded "
+msgstr "+--%3ld rader vikta "
+
+msgid "E222: Add to read buffer"
+msgstr "E222: Lägg till i läsbuffert"
+
+msgid "E223: recursive mapping"
+msgstr "E223: rekursiv mappning"
+
+#, c-format
+msgid "E224: global abbreviation already exists for %s"
+msgstr "E224: global förkortning existerar redan för %s"
+
+#, c-format
+msgid "E225: global mapping already exists for %s"
+msgstr "E225: global mappning existerar redan för %s"
+
+#, c-format
+msgid "E226: abbreviation already exists for %s"
+msgstr "E226: förkortning existerar redan för %s"
+
+#, c-format
+msgid "E227: mapping already exists for %s"
+msgstr "E227: mappning existerar redan för %s"
+
+msgid "No abbreviation found"
+msgstr "Ingen förkortning hittades"
+
+msgid "No mapping found"
+msgstr "Ingen mappning hittades"
+
+msgid "E228: makemap: Illegal mode"
+msgstr "E228: makemap: Otillåtet läge"
+
+msgid "<cannot open> "
+msgstr "<kan inte öppna> "
+
+#, c-format
+msgid "E616: vim_SelFile: can't get font %s"
+msgstr "E616: vim_SelFile: kan inte hämta typsnitt %s"
+
+msgid "E614: vim_SelFile: can't return to current directory"
+msgstr "E614: vim_SelFile: Kan inte återvända till aktuell katalog"
+
+msgid "Pathname:"
+msgstr "Sökväg:"
+
+msgid "E615: vim_SelFile: can't get current directory"
+msgstr "E615: vim_SelFile: kan inte hämta aktuell katalog"
+
+msgid "OK"
+msgstr "OK"
+
+msgid "Cancel"
+msgstr "Avbryt"
+
+msgid "Vim dialog"
+msgstr "Vim-dialog"
+
+msgid "Scrollbar Widget: Could not get geometry of thumb pixmap."
+msgstr "Rullningslist: Kunde inte hämta geometrin på miniatyrbild."
+
+msgid "E232: Cannot create BalloonEval with both message and callback"
+msgstr "E232: Kan inte skapa BalloonEval med både meddelande och återkallning"
+
+msgid "E229: Cannot start the GUI"
+msgstr "E229: Kan inte starta GUI"
+
+#, c-format
+msgid "E230: Cannot read from \"%s\""
+msgstr "E230: Kan inte läsa från \"%s\""
+
+msgid "E665: Cannot start GUI, no valid font found"
+msgstr "E665: Kan inte starta GUI, ingen giltig font hittad"
+
+msgid "E231: 'guifontwide' invalid"
+msgstr "E231: 'guifontwide' ogiltig"
+
+msgid "E599: Value of 'imactivatekey' is invalid"
+msgstr "E599: Värdet av 'imactivatekey' är ogiltigt"
+
+#, c-format
+msgid "E254: Cannot allocate color %s"
+msgstr "E254: Kan inte allokera färg %s"
+
+msgid "No match at cursor, finding next"
+msgstr "Ingen matchning vid markör, söker nästa"
+
+msgid "Vim dialog..."
+msgstr "Vim-dialog..."
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"&Cancel"
+msgstr ""
+"&Ja\n"
+"&Nej\n"
+"&Avbryt"
+
+msgid "Input _Methods"
+msgstr "Inmatnings_metoder"
+
+msgid "VIM - Search and Replace..."
+msgstr "VIM - Sök och ersätt..."
+
+msgid "VIM - Search..."
+msgstr "VIM - Sök..."
+
+msgid "Find what:"
+msgstr "Hitta vad:"
+
+msgid "Replace with:"
+msgstr "Ersätt med:"
+
+#. whole word only button
+msgid "Match whole word only"
+msgstr "Matcha endast hela ord"
+
+#. match case button
+msgid "Match case"
+msgstr "Skilj på stora/små bokstäver"
+
+msgid "Direction"
+msgstr "Riktning"
+
+#. 'Up' and 'Down' buttons
+msgid "Up"
+msgstr "Upp"
+
+msgid "Down"
+msgstr "Ned"
+
+msgid "Find Next"
+msgstr "Hitta nästa"
+
+msgid "Replace"
+msgstr "Ersätt"
+
+msgid "Replace All"
+msgstr "Ersätt alla"
+
+msgid "Vim: Received \"die\" request from session manager\n"
+msgstr "Vim: Tog emot \"die\"-begäran från sessionshanteraren\n"
+
+msgid "Close"
+msgstr "Stäng"
+
+msgid "New tab"
+msgstr "Ny flik"
+
+msgid "Open Tab..."
+msgstr "Öppna flik..."
+
+msgid "Vim: Main window unexpectedly destroyed\n"
+msgstr "Vim: Huvudfönster oväntat förstört\n"
+
+msgid "Font Selection"
+msgstr "Typsnittsval"
+
+msgid "Used CUT_BUFFER0 instead of empty selection"
+msgstr "Använd CUT_BUFFER0 istället för tomt val"
+
+msgid "&Filter"
+msgstr "&Filter"
+
+msgid "&Cancel"
+msgstr "&Avbryt"
+
+msgid "Directories"
+msgstr "Kataloger"
+
+msgid "Filter"
+msgstr "Filter"
+
+msgid "&Help"
+msgstr "&Hjälp"
+
+msgid "Files"
+msgstr "Filer"
+
+msgid "&OK"
+msgstr "&OK"
+
+msgid "Selection"
+msgstr "Val"
+
+msgid "Find &Next"
+msgstr "Hitta &nästa"
+
+msgid "&Replace"
+msgstr "&Ersätt"
+
+msgid "Replace &All"
+msgstr "Ersätt &alla"
+
+msgid "&Undo"
+msgstr "&Ångra"
+
+#, c-format
+msgid "E671: Cannot find window title \"%s\""
+msgstr "E671: Kan inte hitta fönstertitel \"%s\""
+
+#, c-format
+msgid "E243: Argument not supported: \"-%s\"; Use the OLE version."
+msgstr "E243: Argument stöds inte: \"-%s\"; Används OLE-versionen."
+
+msgid "E672: Unable to open window inside MDI application"
+msgstr "E672: Kunde inte öppna fönster inuti MDI-applikation"
+
+msgid "Close tab"
+msgstr "Stäng flik"
+
+msgid "Open tab..."
+msgstr "Öppna flik..."
+
+msgid "Find string (use '\\\\' to find a '\\')"
+msgstr "Sök sträng (använd '\\\\' för att hitta '\\')"
+
+msgid "Find & Replace (use '\\\\' to find a '\\')"
+msgstr "Sök & ersätt (använd '\\\\' för att hitta '\\')"
+
+#. We fake this: Use a filter that doesn't select anything and a default
+#. * file name that won't be used.
+msgid "Not Used"
+msgstr "Inte använd"
+
+msgid "Directory\t*.nothing\n"
+msgstr "Katalog\t*.nothing\n"
+
+msgid "Vim E458: Cannot allocate colormap entry, some colors may be incorrect"
+msgstr ""
+"Vim E458: Kan inte allokera post i färgkarta, några färger kan bli felaktiga"
+
+#, c-format
+msgid "E250: Fonts for the following charsets are missing in fontset %s:"
+msgstr ""
+"E250: Typsnitt för följande teckenkoder saknas i typsnittsuppsättningen %s:"
+
+#, c-format
+msgid "E252: Fontset name: %s"
+msgstr "E252: Typsnittsuppsättningsnamn: %s"
+
+#, c-format
+msgid "Font '%s' is not fixed-width"
+msgstr "Font '%s' är inte fast bredd"
+
+#, c-format
+msgid "E253: Fontset name: %s\n"
+msgstr "E253: Typsnittsuppsättningsnamn: %s\n"
+
+#, c-format
+msgid "Font0: %s\n"
+msgstr "Typsnitt0: %s\n"
+
+#, c-format
+msgid "Font1: %s\n"
+msgstr "Typsnitt1: %s\n"
+
+#, c-format
+msgid "Font%ld width is not twice that of font0\n"
+msgstr "Typsnitt%ld är inte dubbelt så bred som font0\n"
+
+#, c-format
+msgid "Font0 width: %ld\n"
+msgstr "Typsnitt0 bredd: %ld\n"
+
+#, c-format
+msgid ""
+"Font1 width: %ld\n"
+"\n"
+msgstr ""
+"Typsnitt1 bredd: %ld\n"
+"\n"
+
+msgid "Invalid font specification"
+msgstr "Ogiltig typsnittsuppsättning"
+
+msgid "&Dismiss"
+msgstr "&Förkasta"
+
+msgid "no specific match"
+msgstr "ingen specifik matchning"
+
+msgid "Vim - Font Selector"
+msgstr "Vim - Typsnittsväljare"
+
+msgid "Name:"
+msgstr "Namn:"
+
+#. create toggle button
+msgid "Show size in Points"
+msgstr "Visa storlek i punkter"
+
+msgid "Encoding:"
+msgstr "Teckenkodning:"
+
+msgid "Font:"
+msgstr "Typsnitt:"
+
+msgid "Style:"
+msgstr "Stil:"
+
+msgid "Size:"
+msgstr "Storlek:"
+
+msgid "E256: Hangul automata ERROR"
+msgstr "E256: Hangul automata FEL"
+
+msgid "E550: Missing colon"
+msgstr "E550: Saknar kolon"
+
+msgid "E551: Illegal component"
+msgstr "E551: Otillåten komponent"
+
+msgid "E552: digit expected"
+msgstr "E552: siffra förväntades"
+
+#, c-format
+msgid "Page %d"
+msgstr "Sida %d"
+
+msgid "No text to be printed"
+msgstr "Ingen text att skriva ut"
+
+#, c-format
+msgid "Printing page %d (%d%%)"
+msgstr "Skriver ut sida %d (%d%%)"
+
+#, c-format
+msgid " Copy %d of %d"
+msgstr " Kopia %d av %d"
+
+#, c-format
+msgid "Printed: %s"
+msgstr "Skrev ut: %s"
+
+msgid "Printing aborted"
+msgstr "Utskrift avbruten"
+
+msgid "E455: Error writing to PostScript output file"
+msgstr "E455: Fel vid skrivning av utdata till PostScript-fil"
+
+#, c-format
+msgid "E624: Can't open file \"%s\""
+msgstr "E624: Kan inte öppna fil \"%s\""
+
+#, c-format
+msgid "E457: Can't read PostScript resource file \"%s\""
+msgstr "E457: Kan inte läsa PostScript-resursfil \"%s\""
+
+#, c-format
+msgid "E618: file \"%s\" is not a PostScript resource file"
+msgstr "E618: fil \"%s\" är inte en PostScript-resursfil"
+
+#, c-format
+msgid "E619: file \"%s\" is not a supported PostScript resource file"
+msgstr "E619: fil \"%s\" är inte en PostScript-resursfil som stöds"
+
+#, c-format
+msgid "E621: \"%s\" resource file has wrong version"
+msgstr "E621: \"%s\"-källfilen har fel version"
+
+msgid "E673: Incompatible multi-byte encoding and character set."
+msgstr "E673: Inkompatibel flerbitskodning och teckenuppsättning."
+
+msgid "E674: printmbcharset cannot be empty with multi-byte encoding."
+msgstr "E674: printmbcharset kan inte vara tom med flerbitskodning."
+
+msgid "E675: No default font specified for multi-byte printing."
+msgstr "E675: Ingen standardfont angiven för flerbitsutskrifter."
+
+msgid "E324: Can't open PostScript output file"
+msgstr "E324: Kan inte öppna PostScript-utfil"
+
+#, c-format
+msgid "E456: Can't open file \"%s\""
+msgstr "E456: Kan inte öppna fil \"%s\""
+
+msgid "E456: Can't find PostScript resource file \"prolog.ps\""
+msgstr "E456: Kan inte hitta PostScript-källfilen \"prolog.ps\""
+
+msgid "E456: Can't find PostScript resource file \"cidfont.ps\""
+msgstr "E456: Kan inte hitta PostScript-källfilen \"cidfont.ps\""
+
+#, c-format
+msgid "E456: Can't find PostScript resource file \"%s.ps\""
+msgstr "E456: Kan inte hitta PostScript-källfilen \"%s.ps\""
+
+#, c-format
+msgid "E620: Unable to convert to print encoding \"%s\""
+msgstr "E620: Kunde inte konvertera från utskriftkodning \"%s\""
+
+msgid "Sending to printer..."
+msgstr "Skickar till skrivare..."
+
+msgid "E365: Failed to print PostScript file"
+msgstr "E365: Misslyckades med att skriva ut PostScript-fil"
+
+msgid "Print job sent."
+msgstr "Skrivarjobb skickat."
+
+msgid "Add a new database"
+msgstr "Lägg till en ny databas"
+
+msgid "Query for a pattern"
+msgstr "Fråga efter ett mönster"
+
+msgid "Show this message"
+msgstr "Visa detta meddelande"
+
+msgid "Kill a connection"
+msgstr "Döda en anslutning"
+
+msgid "Reinit all connections"
+msgstr "Ominitiera alla anslutningar"
+
+msgid "Show connections"
+msgstr "Visa anslutningar"
+
+#, c-format
+msgid "E560: Usage: cs[cope] %s"
+msgstr "E560: Användning: cs[cope] %s"
+
+msgid "This cscope command does not support splitting the window.\n"
+msgstr "Det här scope-kommandot stöder inte delning av fönstret.\n"
+
+msgid "E562: Usage: cstag <ident>"
+msgstr "E562: Användning: cstag <identifierare>"
+
+msgid "E257: cstag: tag not found"
+msgstr "E257: cstag: tagg hittades inte"
+
+#, c-format
+msgid "E563: stat(%s) error: %d"
+msgstr "E563: stat(%s)-fel: %d"
+
+msgid "E563: stat error"
+msgstr "E563: stat-fel"
+
+#, c-format
+msgid "E564: %s is not a directory or a valid cscope database"
+msgstr "E564: %s är inte en katalog eller en godkänd cscope-databas"
+
+#, c-format
+msgid "Added cscope database %s"
+msgstr "Lade till cscope-databas %s"
+
+#, c-format
+msgid "E262: error reading cscope connection %ld"
+msgstr "E262: fel vid läsning av cscope-anslutning %ld"
+
+msgid "E561: unknown cscope search type"
+msgstr "E561: okänd cscope-söktyp"
+
+msgid "E566: Could not create cscope pipes"
+msgstr "E566: Kunde inte skapa cscope-rör"
+
+msgid "E622: Could not fork for cscope"
+msgstr "E622: Kunde inte grena för cscope"
+
+msgid "cs_create_connection exec failed"
+msgstr "cs_create_connection-exekvering misslyckades"
+
+msgid "E623: Could not spawn cscope process"
+msgstr "E623: Kunde inte starta cscope-process"
+
+msgid "cs_create_connection: fdopen for to_fp failed"
+msgstr "cs_create_connection: fdopen för to_fp misslyckades"
+
+msgid "cs_create_connection: fdopen for fr_fp failed"
+msgstr "cs_create_connection: fdopen för fr_fp misslyckades"
+
+msgid "E567: no cscope connections"
+msgstr "E567: inga cscope-anslutningar"
+
+#, c-format
+msgid "E259: no matches found for cscope query %s of %s"
+msgstr "E259: inga träffar funna för cscope-förfrågan %s av %s"
+
+#, c-format
+msgid "E469: invalid cscopequickfix flag %c for %c"
+msgstr "E469: ogiltig cscopequickfix flagga %c för %c"
+
+msgid "cscope commands:\n"
+msgstr "cscope-kommandon:\n"
+
+#, c-format
+msgid "%-5s: %-30s (Usage: %s)"
+msgstr "%-5s: %-30s (Användning: %s)"
+
+#, c-format
+msgid "E625: cannot open cscope database: %s"
+msgstr "E625: kan inte öppna cscope-databas: %s"
+
+msgid "E626: cannot get cscope database information"
+msgstr "E626: kan inte hämta cscope-databasinformation"
+
+msgid "E568: duplicate cscope database not added"
+msgstr "E568: dubblerad cscope-databas inte lagd till"
+
+msgid "E569: maximum number of cscope connections reached"
+msgstr "E569: maximalt antal av cscope-anslutningar nått"
+
+#, c-format
+msgid "E261: cscope connection %s not found"
+msgstr "E261: cscope-anslutning %s hittades inte"
+
+#, c-format
+msgid "cscope connection %s closed"
+msgstr "cscope-anslutning %s stängd"
+
+#. should not reach here
+msgid "E570: fatal error in cs_manage_matches"
+msgstr "E570: ödesdigert fel i cs_manage_matches"
+
+#, c-format
+msgid "Cscope tag: %s"
+msgstr "Cscope-tagg: %s"
+
+msgid ""
+"\n"
+" # line"
+msgstr ""
+"\n"
+" # rad"
+
+msgid "filename / context / line\n"
+msgstr "filnamn / sammanhang / rad\n"
+
+#, c-format
+msgid "E609: Cscope error: %s"
+msgstr "E609: Cscope-fel: %s"
+
+msgid "All cscope databases reset"
+msgstr "Alla cscope-databaser återställda"
+
+msgid "no cscope connections\n"
+msgstr "inga cscope-anslutningar\n"
+
+msgid " # pid database name prepend path\n"
+msgstr " # pid databasnamn först i sökväg\n"
+
+msgid ""
+"???: Sorry, this command is disabled, the MzScheme library could not be "
+"loaded."
+msgstr ""
+"???: Tyvärr, det här kommandot är inaktiverat: MzScheme-biblioteket kunde "
+"inte läsas in."
+
+msgid "invalid expression"
+msgstr "ogiltigt uttryck"
+
+msgid "expressions disabled at compile time"
+msgstr "uttryck inaktiverat vid kompilering"
+
+msgid "hidden option"
+msgstr "gömd flagga"
+
+msgid "unknown option"
+msgstr "okänd flagga"
+
+msgid "window index is out of range"
+msgstr "fönsterindex är utanför område"
+
+msgid "couldn't open buffer"
+msgstr "kunde inte öppna buffert"
+
+msgid "cannot save undo information"
+msgstr "kan inte spara ångra-information"
+
+msgid "cannot delete line"
+msgstr "kan inte ta bort rad"
+
+msgid "cannot replace line"
+msgstr "kan inte ersätta rad"
+
+msgid "cannot insert line"
+msgstr "kan inte infoga rad"
+
+msgid "string cannot contain newlines"
+msgstr "sträng kan inte innehålla nyrader"
+
+msgid "Vim error: ~a"
+msgstr "Vim-fel: ~a"
+
+msgid "Vim error"
+msgstr "Vim-fel"
+
+msgid "buffer is invalid"
+msgstr "buffert är ogiltig"
+
+msgid "window is invalid"
+msgstr "fönster är ogiltigt"
+
+msgid "linenr out of range"
+msgstr "radnummer utanför område"
+
+msgid "not allowed in the Vim sandbox"
+msgstr "inte tillåtet i Vim-sandlådan"
+
+msgid ""
+"E263: Sorry, this command is disabled, the Python library could not be "
+"loaded."
+msgstr ""
+"E263: Tyvärr, detta kommandot är inaktiverat, Python-biblioteket kunde inte "
+"läsas in."
+
+msgid "E659: Cannot invoke Python recursively"
+msgstr "E659: Kan inte anropa Python rekursivt"
+
+msgid "can't delete OutputObject attributes"
+msgstr "kan inte ta bort OutputObject-attribut"
+
+msgid "softspace must be an integer"
+msgstr "softspace måste vara ett heltal"
+
+msgid "invalid attribute"
+msgstr "ogiltigt attribut"
+
+msgid "writelines() requires list of strings"
+msgstr "writelines() kräver lista av strängar"
+
+msgid "E264: Python: Error initialising I/O objects"
+msgstr "E264: Python: Fel vid initiering av I/O-objekt"
+
+msgid "attempt to refer to deleted buffer"
+msgstr "försök att referera till borttagen buffert"
+
+msgid "line number out of range"
+msgstr "radnummer utanför område"
+
+#, c-format
+msgid "<buffer object (deleted) at %8lX>"
+msgstr "<buffertobjekt (borttaget) vid %8lX>"
+
+msgid "invalid mark name"
+msgstr "ogiltigt märknamn"
+
+msgid "no such buffer"
+msgstr "ingen sådan buffert"
+
+msgid "attempt to refer to deleted window"
+msgstr "försök att referera till borttaget fönster"
+
+msgid "readonly attribute"
+msgstr "skrivskyddad attribut"
+
+msgid "cursor position outside buffer"
+msgstr "markörposition utanför buffert"
+
+#, c-format
+msgid "<window object (deleted) at %.8lX>"
+msgstr "<fönsterobjekt (borttaget) vid %.8lX>"
+
+#, c-format
+msgid "<window object (unknown) at %.8lX>"
+msgstr "<fönsterobjekt (okänt) vid %.8lX>"
+
+#, c-format
+msgid "<window %d>"
+msgstr "<fönster %d>"
+
+msgid "no such window"
+msgstr "inget sådant fönster"
+
+msgid "E265: $_ must be an instance of String"
+msgstr "E265: $_ måste vara en instans av String"
+
+msgid ""
+"E266: Sorry, this command is disabled, the Ruby library could not be loaded."
+msgstr ""
+"E266: Tyvärr, detta kommandot är inaktiverat, Ruby-biblioteket kunde inte "
+"läsas in."
+
+msgid "E267: unexpected return"
+msgstr "E267: oväntad returnering"
+
+msgid "E268: unexpected next"
+msgstr "E268: oväntad next"
+
+msgid "E269: unexpected break"
+msgstr "E269: oväntad break"
+
+msgid "E270: unexpected redo"
+msgstr "E270: oväntad redo"
+
+msgid "E271: retry outside of rescue clause"
+msgstr "E271: retry utanför rescue-block"
+
+msgid "E272: unhandled exception"
+msgstr "E272: ohanterat undantag"
+
+#, c-format
+msgid "E273: unknown longjmp status %d"
+msgstr "E273: okänt longjmp-status %d"
+
+msgid "Toggle implementation/definition"
+msgstr "Växla mellan implementation/definition"
+
+msgid "Show base class of"
+msgstr "Visa basklass av"
+
+msgid "Show overridden member function"
+msgstr "Visa åsidosatt medlemsfunktion"
+
+msgid "Retrieve from file"
+msgstr "Hämta från fil"
+
+msgid "Retrieve from project"
+msgstr "Hämta från projekt"
+
+msgid "Retrieve from all projects"
+msgstr "Hämta från alla projekt"
+
+msgid "Retrieve"
+msgstr "Hämta"
+
+msgid "Show source of"
+msgstr "Visa källa för"
+
+msgid "Find symbol"
+msgstr "Hitta symbol"
+
+msgid "Browse class"
+msgstr "Bläddra i klass"
+
+msgid "Show class in hierarchy"
+msgstr "Visa klass i hierarki"
+
+msgid "Show class in restricted hierarchy"
+msgstr "Visa klass i begränsad hierarki"
+
+msgid "Xref refers to"
+msgstr "Xref refererar till"
+
+msgid "Xref referred by"
+msgstr "Xref refereras av"
+
+msgid "Xref has a"
+msgstr "Xref har en"
+
+msgid "Xref used by"
+msgstr "Xref används av"
+
+msgid "Show docu of"
+msgstr "Visa docu av"
+
+msgid "Generate docu for"
+msgstr "Generera docu för"
+
+msgid ""
+"Cannot connect to SNiFF+. Check environment (sniffemacs must be found in "
+"$PATH).\n"
+msgstr ""
+"Kan inte ansluta till SNiFF+. Kontrollera miljö (sniffemacs måste kunna "
+"hittas i $PATH).\n"
+
+msgid "E274: Sniff: Error during read. Disconnected"
+msgstr "E274: Sniff: Fel vid läsning. Frånkopplad"
+
+msgid "SNiFF+ is currently "
+msgstr "SNiFF+ är för närvarande "
+
+msgid "not "
+msgstr "inte "
+
+msgid "connected"
+msgstr "ansluten"
+
+#, c-format
+msgid "E275: Unknown SNiFF+ request: %s"
+msgstr "E275: Okänd SNiFF+-begäran: %s"
+
+msgid "E276: Error connecting to SNiFF+"
+msgstr "E276: Fel vid anslutning till SNiFF+"
+
+msgid "E278: SNiFF+ not connected"
+msgstr "E278: SNiFF+ inte ansluten"
+
+msgid "E279: Not a SNiFF+ buffer"
+msgstr "E279: Inte en SNiFF+-buffert"
+
+msgid "Sniff: Error during write. Disconnected"
+msgstr "Sniff: Fel vid skrivning. Frånkopplad"
+
+msgid "invalid buffer number"
+msgstr "ogiltigt buffertnummer"
+
+msgid "not implemented yet"
+msgstr "inte implementerat än"
+
+#. ???
+msgid "cannot set line(s)"
+msgstr "kan inte ställa in rad(er)"
+
+msgid "mark not set"
+msgstr "märke inte satt"
+
+#, c-format
+msgid "row %d column %d"
+msgstr "rad %d kolumn %d"
+
+msgid "cannot insert/append line"
+msgstr "kan inte infoga/lägga till rad"
+
+msgid "unknown flag: "
+msgstr "okänd flagga: "
+
+msgid "unknown vimOption"
+msgstr "okänd vimOption"
+
+msgid "keyboard interrupt"
+msgstr "tangentbordsavbrott"
+
+msgid "vim error"
+msgstr "vim-fel"
+
+msgid "cannot create buffer/window command: object is being deleted"
+msgstr "kan inte skapa buffert/fönster-kommando: objekt håller på att tas bort"
+
+msgid ""
+"cannot register callback command: buffer/window is already being deleted"
+msgstr ""
+"kan inte registera återkallningskommando: buffert/fönster håller redan på "
+"att tas bort"
+
+#. This should never happen. Famous last word?
+msgid ""
+"E280: TCL FATAL ERROR: reflist corrupt!? Please report this to vim-dev@vim."
+"org"
+msgstr ""
+"E280: TCL ÖDESDIGERT FEL: reflist trasig!? Var snäll och rapportera detta "
+"till vim-dev@vim.org"
+
+msgid "cannot register callback command: buffer/window reference not found"
+msgstr ""
+"kan inte registrera återkallningskommando: buffert-/fönsterreferens hittades "
+"inte"
+
+msgid ""
+"E571: Sorry, this command is disabled: the Tcl library could not be loaded."
+msgstr ""
+"E571: Tyvärr, detta kommando är inaktiverat: Tcl-biblioteket kunde inte "
+"läsas in."
+
+msgid ""
+"E281: TCL ERROR: exit code is not int!? Please report this to vim-dev@vim.org"
+msgstr ""
+"E281: TCL-FEL: Avslutningskoden är inte int!? Var snäll och rapportera detta "
+"till vim-dev@vim.org"
+
+#, c-format
+msgid "E572: exit code %d"
+msgstr "E572: avslutningskod %d"
+
+msgid "cannot get line"
+msgstr "kan inte hämta rad"
+
+msgid "Unable to register a command server name"
+msgstr "Kunde inte registrera ett kommandoservernamn"
+
+msgid "E248: Failed to send command to the destination program"
+msgstr "E248: Misslyckades att skicka kommando till målprogrammet"
+
+#, c-format
+msgid "E573: Invalid server id used: %s"
+msgstr "E573: Ogiltigt server-id använt: %s"
+
+msgid "E251: VIM instance registry property is badly formed. Deleted!"
+msgstr "E251: VIM instansregisteregenskap är dåligt format. Borttaget!"
+
+msgid "Unknown option argument"
+msgstr "Okänt flaggargument"
+
+msgid "Too many edit arguments"
+msgstr "För många redigeringsargument"
+
+msgid "Argument missing after"
+msgstr "Argument saknas efter"
+
+msgid "Garbage after option argument"
+msgstr "Skräp efter flaggargument"
+
+msgid "Too many \"+command\", \"-c command\" or \"--cmd command\" arguments"
+msgstr ""
+"För många \"+kommando\"-, \"-c kommando\"- eller \"--cmd kommando\"-argument"
+
+msgid "Invalid argument for"
+msgstr "Ogiltigt argument för"
+
+#, c-format
+msgid "%d files to edit\n"
+msgstr "%d filer att redigera\n"
+
+msgid "This Vim was not compiled with the diff feature."
+msgstr "Denna Vim blev inte kompilerad med diff-funktionen."
+
+msgid "Attempt to open script file again: \""
+msgstr "Försök att öppna skriptfil igen: \""
+
+msgid "Cannot open for reading: \""
+msgstr "Kan inte öppna för läsning: \""
+
+msgid "Cannot open for script output: \""
+msgstr "Kan inte öppna för skriptutmatning: \""
+
+msgid "Vim: Error: Failure to start gvim from NetBeans\n"
+msgstr "Vim: Fel: Misslyckades att starta gvim från NetBeans\n"
+
+msgid "Vim: Warning: Output is not to a terminal\n"
+msgstr "Vim: Varning: Utmatning är inte till en terminal\n"
+
+msgid "Vim: Warning: Input is not from a terminal\n"
+msgstr "Vim: Varning: Inmatning är inte från en terminal\n"
+
+#. just in case..
+msgid "pre-vimrc command line"
+msgstr "pre-vimrc kommandorad"
+
+#, c-format
+msgid "E282: Cannot read from \"%s\""
+msgstr "E282: Kan inte läsa från \"%s\""
+
+msgid ""
+"\n"
+"More info with: \"vim -h\"\n"
+msgstr ""
+"\n"
+"Mer info med: \"vim -h\"\n"
+
+msgid "[file ..] edit specified file(s)"
+msgstr "[fil ..] redigera angivna fil(er)"
+
+msgid "- read text from stdin"
+msgstr "- läs text från standard in"
+
+msgid "-t tag edit file where tag is defined"
+msgstr "-t tagg redigera fil där tagg är definierad"
+
+msgid "-q [errorfile] edit file with first error"
+msgstr "-q [felfil] redigera fil med första fel"
+
+msgid ""
+"\n"
+"\n"
+"Usage:"
+msgstr ""
+"\n"
+"\n"
+"användning:"
+
+msgid " vim [arguments] "
+msgstr " vim [argument] "
+
+msgid ""
+"\n"
+" or:"
+msgstr ""
+"\n"
+" eller:"
+
+msgid ""
+"\n"
+"Where case is ignored prepend / to make flag upper case"
+msgstr ""
+"\n"
+"Där storlek ignoreras börja med / för att göra flagga versal"
+
+msgid ""
+"\n"
+"\n"
+"Arguments:\n"
+msgstr ""
+"\n"
+"\n"
+"Argument:\n"
+
+msgid "--\t\t\tOnly file names after this"
+msgstr "--\t\t\tBara filnamn efter det här"
+
+msgid "--literal\t\tDon't expand wildcards"
+msgstr "--literal\t\tExpandera inte jokertecken"
+
+msgid "-register\t\tRegister this gvim for OLE"
+msgstr "-register\t\tRegistrera gvim för OLE"
+
+msgid "-unregister\t\tUnregister gvim for OLE"
+msgstr "-unregister\t\tAvregistrera gvim för OLE"
+
+msgid "-g\t\t\tRun using GUI (like \"gvim\")"
+msgstr "-g\t\t\tKör som GUI (som \"gvim\")"
+
+msgid "-f or --nofork\tForeground: Don't fork when starting GUI"
+msgstr "-f eller --nofork\tFörgrund: Grena inte vid start av GUI"
+
+msgid "-v\t\t\tVi mode (like \"vi\")"
+msgstr "-v\t\t\tVi-läge (som \"vi\")"
+
+msgid "-e\t\t\tEx mode (like \"ex\")"
+msgstr "-e\t\t\tEx-läge (som \"ex\")"
+
+msgid "-s\t\t\tSilent (batch) mode (only for \"ex\")"
+msgstr "-s\t\t\tTyst (batch) läge (bara för \"ex\")"
+
+msgid "-d\t\t\tDiff mode (like \"vimdiff\")"
+msgstr "-d\t\t\tDiff-läge (som \"vimdiff\")"
+
+msgid "-y\t\t\tEasy mode (like \"evim\", modeless)"
+msgstr "-y\t\t\tLätt läge (som \"evim\", lägeslös)"
+
+msgid "-R\t\t\tReadonly mode (like \"view\")"
+msgstr "-R\t\t\tSkrivskyddat läge (som \"view\")"
+
+msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
+msgstr "-Z\t\t\tBegränsat läge (som \"rvim\")"
+
+msgid "-m\t\t\tModifications (writing files) not allowed"
+msgstr "-m\t\t\tModifieringar (skriva filer) inte tillåtet"
+
+msgid "-M\t\t\tModifications in text not allowed"
+msgstr "-M\t\t\tModifieringar i text inte tillåtet"
+
+msgid "-b\t\t\tBinary mode"
+msgstr "-b\t\t\tBinärläge"
+
+msgid "-l\t\t\tLisp mode"
+msgstr "-l\t\t\tLisp-läge"
+
+msgid "-C\t\t\tCompatible with Vi: 'compatible'"
+msgstr "-C\t\t\tKompatibelt med Vi: 'compatible'"
+
+msgid "-N\t\t\tNot fully Vi compatible: 'nocompatible'"
+msgstr "-N\t\t\tInte fullt Vi-kompatibel: 'nocompatible'"
+
+msgid "-V[N][fname]\t\tBe verbose [level N] [log messages to fname]"
+msgstr "-V[N][fnamn]\t\tVar mångordig [nivå N] [logga meddelanden till fnamn]"
+
+msgid "-D\t\t\tDebugging mode"
+msgstr "-D\t\t\tFelsökningsläge"
+
+msgid "-n\t\t\tNo swap file, use memory only"
+msgstr "-n\t\t\tIngen växlingsfil, använd endast minnet"
+
+msgid "-r\t\t\tList swap files and exit"
+msgstr "-r\t\t\tLista växlingsfiler och avsluta"
+
+msgid "-r (with file name)\tRecover crashed session"
+msgstr "-r (med filnamn)\tÅterskapa kraschad session"
+
+msgid "-L\t\t\tSame as -r"
+msgstr "-L\t\t\tSamma som -r"
+
+msgid "-f\t\t\tDon't use newcli to open window"
+msgstr "-f\t\t\tAnvända inte newcli för att öppna fönster"
+
+msgid "-dev <device>\t\tUse <device> for I/O"
+msgstr "-dev <enhet>\t\tAnvänd <enhet> för I/O"
+
+msgid "-A\t\t\tStart in Arabic mode"
+msgstr "-A\t\t\tStarta i arabiskt läge"
+
+msgid "-H\t\t\tStart in Hebrew mode"
+msgstr "-H\t\t\tStarta i hebreiskt läge"
+
+msgid "-F\t\t\tStart in Farsi mode"
+msgstr "-F\t\t\tStarta i persiskt läge (Farsi)"
+
+msgid "-T <terminal>\tSet terminal type to <terminal>"
+msgstr "-T <terminal>\tStäll in terminaltyp till <terminal>"
+
+msgid "-u <vimrc>\t\tUse <vimrc> instead of any .vimrc"
+msgstr "-u <vimrc>\t\tAnvänd <vimrc> istället för någon .vimrc"
+
+msgid "-U <gvimrc>\t\tUse <gvimrc> instead of any .gvimrc"
+msgstr "-U <gvimrc>\t\tAnvänd <gvimrc> istället för någon .gvimrc"
+
+msgid "--noplugin\t\tDon't load plugin scripts"
+msgstr "--noplugin\t\tLäs inte in insticksskript"
+
+msgid "-p[N]\t\tOpen N tab pages (default: one for each file)"
+msgstr "-p[N]\t\tÖppna N flikar (standard: en för varje fil)"
+
+msgid "-o[N]\t\tOpen N windows (default: one for each file)"
+msgstr "-o[N]\t\tÖppna N fönster (standard: ett för varje fil)"
+
+msgid "-O[N]\t\tLike -o but split vertically"
+msgstr "-O[N]\t\tSom -o men dela vertikalt"
+
+msgid "+\t\t\tStart at end of file"
+msgstr "+\t\t\tStarta vid slut av fil"
+
+msgid "+<lnum>\t\tStart at line <lnum>"
+msgstr "+<lnr>\t\tStarta på rad <rnr>"
+
+msgid "--cmd <command>\tExecute <command> before loading any vimrc file"
+msgstr "--cmd <kommando>\tKör <kommando> före inläsning av någon vimrc fil"
+
+msgid "-c <command>\t\tExecute <command> after loading the first file"
+msgstr "-c <kommando>\tKör <kommando> efter inläsning av den första filen"
+
+msgid "-S <session>\t\tSource file <session> after loading the first file"
+msgstr "-S <session>\t\tKör fil <session> efter inläsning av den första filen"
+
+msgid "-s <scriptin>\tRead Normal mode commands from file <scriptin>"
+msgstr "-s <inskript>\tLäs Normallägeskommandon från fil <inskript>"
+
+msgid "-w <scriptout>\tAppend all typed commands to file <scriptout>"
+msgstr "-w <utskript>\tLägg till alla skrivna kommandon till fil <utskript>"
+
+msgid "-W <scriptout>\tWrite all typed commands to file <scriptout>"
+msgstr "-W <utskript>\tSkriv alla skrivna kommandon till fil <utskript>"
+
+msgid "-x\t\t\tEdit encrypted files"
+msgstr "-x\t\t\tRedigera krypterade filer"
+
+msgid "-display <display>\tConnect vim to this particular X-server"
+msgstr "-display <display>\tAnslut vim till just denna X-server"
+
+msgid "-X\t\t\tDo not connect to X server"
+msgstr "-X\t\t\tAnslut inte till X server"
+
+msgid "--remote <files>\tEdit <files> in a Vim server if possible"
+msgstr "--remote <filer>\tRedigera <filer> i en Vim-server om möjligt"
+
+msgid "--remote-silent <files> Same, don't complain if there is no server"
+msgstr ""
+"--remote-silent <filer>\tSamma, klaga inte om det inte finns någon server"
+
+msgid ""
+"--remote-wait <files> As --remote but wait for files to have been edited"
+msgstr ""
+"--remote-wait <filer>\tSom --remote men vänta på att filer har blivit "
+"redigerade"
+
+msgid ""
+"--remote-wait-silent <files> Same, don't complain if there is no server"
+msgstr ""
+"--remote-wait-silent <filer>\tSamma, klaga inte om det inte finns någon "
+"server"
+
+msgid "--remote-tab <files> As --remote but open tab page for each file"
+msgstr "--remote-tab <filer> Som --remote men öppna flik för varje fil"
+
+msgid "--remote-send <keys>\tSend <keys> to a Vim server and exit"
+msgstr ""
+"--remote-send <nycklar>\tSkicka <nycklar> till en Vim-server och avsluta"
+
+msgid "--remote-expr <expr>\tEvaluate <expr> in a Vim server and print result"
+msgstr ""
+"--remote-expr <uttryck>\tEvaluera <uttryck> i en Vim-server och skriv ut "
+"resultatet"
+
+msgid "--serverlist\t\tList available Vim server names and exit"
+msgstr "--serverlist\t\tLista tillgängliga Vim-servernamn och avsluta"
+
+msgid "--servername <name>\tSend to/become the Vim server <name>"
+msgstr "--servername <namn>\tSkicka till/för att bli Vim-servern <namn>"
+
+msgid "-i <viminfo>\t\tUse <viminfo> instead of .viminfo"
+msgstr "-i <viminfo>\t\tAnvänd <viminfo> istället för .viminfo"
+
+msgid "-h or --help\tPrint Help (this message) and exit"
+msgstr "-h eller --help\tSkriv ut Hjälp (det här meddelandet) och avsluta"
+
+msgid "--version\t\tPrint version information and exit"
+msgstr "--version\t\tSkriv ut versionsinformation och avsluta"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Motif version):\n"
+msgstr ""
+"\n"
+"Argument som stöds av gvim (Motif-version):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (neXtaw version):\n"
+msgstr ""
+"\n"
+"Argument som stöds av gvim (neXtaw-version):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Athena version):\n"
+msgstr ""
+"\n"
+"Argument som stöds av gvim (Athena-version):\n"
+
+msgid "-display <display>\tRun vim on <display>"
+msgstr "-display <display>\tKör vim på <display>"
+
+msgid "-iconic\t\tStart vim iconified"
+msgstr "-iconic\t\tStarta vim som ikon"
+
+msgid "-name <name>\t\tUse resource as if vim was <name>"
+msgstr "-name <namn>\t\tAnvänd resurs som om vim var <namn>"
+
+msgid "\t\t\t (Unimplemented)\n"
+msgstr "\t\t\t (Oimplementerat)\n"
+
+msgid "-background <color>\tUse <color> for the background (also: -bg)"
+msgstr "-background <färg>\tAnvänd <färg> för bakgrunden (även: -bg)"
+
+msgid "-foreground <color>\tUse <color> for normal text (also: -fg)"
+msgstr "-foreground <färg>\tAnvänd <färg> för vanlig text (även: -fg)"
+
+msgid "-font <font>\t\tUse <font> for normal text (also: -fn)"
+msgstr "-font <typsnitt>\t\tAnvänd <typsnitt> för vanlig text (även: -fn)"
+
+msgid "-boldfont <font>\tUse <font> for bold text"
+msgstr "­boldfont <typsnitt>\tAnvänd <typsnitt> för fet text"
+
+msgid "-italicfont <font>\tUse <font> for italic text"
+msgstr "-italicfont <typsnitt>\tAnvänd <typsnitt> för kursiv text"
+
+msgid "-geometry <geom>\tUse <geom> for initial geometry (also: -geom)"
+msgstr ""
+"-geometry <geom>\tAnvänd <geom> för inledande fönsterplacering (även: -geom)"
+
+msgid "-borderwidth <width>\tUse a border width of <width> (also: -bw)"
+msgstr "-borderwidth <bredd>\tAnvänd en rambredd med <bredd> (även: -bw)"
+
+msgid "-scrollbarwidth <width> Use a scrollbar width of <width> (also: -sw)"
+msgstr ""
+"-scrollbarwidth <bredd> Använd en rullningslistbredd på <bredd> (även: -sw)"
+
+msgid "-menuheight <height>\tUse a menu bar height of <height> (also: -mh)"
+msgstr "-menuheight <höjd>\tAnvänd en menyradshöjd med <höjd> (även: -mh)"
+
+msgid "-reverse\t\tUse reverse video (also: -rv)"
+msgstr "-reverse\t\tAnvänd omvänd video (även: -rv)"
+
+msgid "+reverse\t\tDon't use reverse video (also: +rv)"
+msgstr "+reverse\t\tAnvänd inte omvänd video (även: +rv)"
+
+msgid "-xrm <resource>\tSet the specified resource"
+msgstr "-xrm <tillgång>\tStäll in den angivna tillgången"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (RISC OS version):\n"
+msgstr ""
+"\n"
+"Argument igenkända av gvim (RISC OS-version):\n"
+
+msgid "--columns <number>\tInitial width of window in columns"
+msgstr "--columns <antal>\tInledande bredd på fönster i kolumner"
+
+msgid "--rows <number>\tInitial height of window in rows"
+msgstr "--rows <antal>\tInledande höjd på fönster i rader"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (GTK+ version):\n"
+msgstr ""
+"\n"
+"Argument igenkända av gvim (GTK+-version):\n"
+
+msgid "-display <display>\tRun vim on <display> (also: --display)"
+msgstr "-display <display>\tKör vim på <display> (även: --display)"
+
+msgid "--role <role>\tSet a unique role to identify the main window"
+msgstr "--role <roll>\tStäll in en unik roll för att identifiera huvudfönstret"
+
+msgid "--socketid <xid>\tOpen Vim inside another GTK widget"
+msgstr "--socketid <xid>\tÖppna Vim innanför en annan GTK-widget"
+
+msgid "-P <parent title>\tOpen Vim inside parent application"
+msgstr "-P <förälder fönster>\tÖppna Vim inuti förälderapplikation"
+
+msgid "No display"
+msgstr "Ingen display"
+
+#. Failed to send, abort.
+msgid ": Send failed.\n"
+msgstr ": Överföring misslyckades.\n"
+
+#. Let vim start normally.
+msgid ": Send failed. Trying to execute locally\n"
+msgstr ": Överföring misslyckades. Försöker att köra lokalt\n"
+
+#, c-format
+msgid "%d of %d edited"
+msgstr "%d av %d redigerade"
+
+msgid "No display: Send expression failed.\n"
+msgstr "Ingen display: Överföringsuttryck misslyckades.\n"
+
+msgid ": Send expression failed.\n"
+msgstr ": Överföringsuttryck misslyckades.\n"
+
+msgid "No marks set"
+msgstr "Inga märken satta"
+
+#, c-format
+msgid "E283: No marks matching \"%s\""
+msgstr "E283: Inga märken matchade \"%s\""
+
+#. Highlight title
+msgid ""
+"\n"
+"mark line col file/text"
+msgstr ""
+"\n"
+"märke rad kol fil/text"
+
+#. Highlight title
+msgid ""
+"\n"
+" jump line col file/text"
+msgstr ""
+"\n"
+" hopp rad kol fil/text"
+
+#. Highlight title
+msgid ""
+"\n"
+"change line col text"
+msgstr ""
+"\n"
+"ändring rad kol text"
+
+#, c-format
+msgid ""
+"\n"
+"# File marks:\n"
+msgstr ""
+"\n"
+"# Filmärken:\n"
+
+#. Write the jumplist with -'
+#, c-format
+msgid ""
+"\n"
+"# Jumplist (newest first):\n"
+msgstr ""
+"\n"
+"# Hopplista (nyaste först):\n"
+
+#, c-format
+msgid ""
+"\n"
+"# History of marks within files (newest to oldest):\n"
+msgstr ""
+"\n"
+"# Historia för märken inne i filer (nyaste till äldsta):\n"
+
+msgid "Missing '>'"
+msgstr "Saknar '>'"
+
+msgid "E543: Not a valid codepage"
+msgstr "E543: Inte en godkänd teckentabell"
+
+msgid "E284: Cannot set IC values"
+msgstr "E284: Kan inte ställa in IC-värden"
+
+msgid "E285: Failed to create input context"
+msgstr "E285: Misslyckades att skapa inmatningsmiljö"
+
+msgid "E286: Failed to open input method"
+msgstr "E286: Misslyckades att öppna inmatningsmetod"
+
+msgid "E287: Warning: Could not set destroy callback to IM"
+msgstr "E287: Varning: Kunde inte ställa in förstörningsåterkallning till IM"
+
+msgid "E288: input method doesn't support any style"
+msgstr "E288: inmatningsmetod stöder inte någon stil"
+
+msgid "E289: input method doesn't support my preedit type"
+msgstr "E289: inmatningsmetod stöder inte min förredigeringstyp"
+
+msgid "E290: over-the-spot style requires fontset"
+msgstr "E290: över-pricken-stil kräver typsnittsuppsättning"
+
+msgid "E291: Your GTK+ is older than 1.2.3. Status area disabled"
+msgstr "E291: Din GTK+ är äldre än 1.2.3. Statusområde inaktiverat"
+
+msgid "E292: Input Method Server is not running"
+msgstr "E292: Inmatningsmetodserver körs inte"
+
+msgid "E293: block was not locked"
+msgstr "E293: block låstes inte"
+
+msgid "E294: Seek error in swap file read"
+msgstr "E294: Sökfel i växelfilsläsning"
+
+msgid "E295: Read error in swap file"
+msgstr "E295: Läsfel i växelfil"
+
+msgid "E296: Seek error in swap file write"
+msgstr "E296: Sökfel i växelfilskrivning"
+
+msgid "E297: Write error in swap file"
+msgstr "E297: Skrivfel i växelfil"
+
+msgid "E300: Swap file already exists (symlink attack?)"
+msgstr "E300: Växelfil existerar redan (symlänksattack?)"
+
+msgid "E298: Didn't get block nr 0?"
+msgstr "E298: Tog inte emot block nr 0?"
+
+msgid "E298: Didn't get block nr 1?"
+msgstr "E298: Tog inte emot block nr 1?"
+
+msgid "E298: Didn't get block nr 2?"
+msgstr "E298: Tog inte emot block nr 2?"
+
+#. could not (re)open the swap file, what can we do????
+msgid "E301: Oops, lost the swap file!!!"
+msgstr "E301: Hoppsan, tappat bort växelfilen!!!"
+
+msgid "E302: Could not rename swap file"
+msgstr "E302: Kunde inte döpa om växelfil"
+
+#, c-format
+msgid "E303: Unable to open swap file for \"%s\", recovery impossible"
+msgstr "E303: Kunde inte öppna växelfil för \"%s\", återskapning omöjlig"
+
+msgid "E304: ml_upd_block0(): Didn't get block 0??"
+msgstr "E304: ml_upd_block0(): Tog inte emot block 0??"
+
+#, c-format
+msgid "E305: No swap file found for %s"
+msgstr "E305: Ingen växelfil hittad för %s"
+
+msgid "Enter number of swap file to use (0 to quit): "
+msgstr "Ange nummer på växelfil att använda (0 för att avsluta): "
+
+#, c-format
+msgid "E306: Cannot open %s"
+msgstr "E306: Kan inte öppna %s"
+
+msgid "Unable to read block 0 from "
+msgstr "Kunde inte läsa block 0 från "
+
+msgid ""
+"\n"
+"Maybe no changes were made or Vim did not update the swap file."
+msgstr ""
+"\n"
+"Kanske gjordes inte några förändringar eller så uppdaterade inte Vim "
+"växlingsfilen."
+
+msgid " cannot be used with this version of Vim.\n"
+msgstr " kan inte användas med den här versionen av Vim.\n"
+
+msgid "Use Vim version 3.0.\n"
+msgstr "Använd Vim version 3.0.\n"
+
+#, c-format
+msgid "E307: %s does not look like a Vim swap file"
+msgstr "E307: %s ser inte ut som en Vim-växlingsfil"
+
+msgid " cannot be used on this computer.\n"
+msgstr " kan inte användas på den här datorn.\n"
+
+msgid "The file was created on "
+msgstr "Filen skapades på "
+
+msgid ""
+",\n"
+"or the file has been damaged."
+msgstr ""
+",\n"
+"eller så har filen blivit skadad."
+
+msgid " has been damaged (page size is smaller than minimum value).\n"
+msgstr " har skadats (sid-storlek är mindre än minimumvärdet).\n"
+
+#, c-format
+msgid "Using swap file \"%s\""
+msgstr "Använder växlingsfil \"%s\""
+
+#, c-format
+msgid "Original file \"%s\""
+msgstr "Orginalfil \"%s\""
+
+msgid "E308: Warning: Original file may have been changed"
+msgstr "E308: Varning: Orginalfilen kan ha blivit skadad"
+
+#, c-format
+msgid "E309: Unable to read block 1 from %s"
+msgstr "E309: Kunde inte läsa block 1 från %s"
+
+msgid "???MANY LINES MISSING"
+msgstr "???MÅNGA RADER SAKNAS"
+
+msgid "???LINE COUNT WRONG"
+msgstr "???RADANTAL FEL"
+
+msgid "???EMPTY BLOCK"
+msgstr "???TOMT BLOCK"
+
+msgid "???LINES MISSING"
+msgstr "???RADER SAKNAS"
+
+#, c-format
+msgid "E310: Block 1 ID wrong (%s not a .swp file?)"
+msgstr "E310: Block 1 ID fel (%s inte en .swp-fil?)"
+
+msgid "???BLOCK MISSING"
+msgstr "???BLOCK SAKNAS"
+
+msgid "??? from here until ???END lines may be messed up"
+msgstr "??? från här till ???SLUT kan rader vara tillstökade"
+
+msgid "??? from here until ???END lines may have been inserted/deleted"
+msgstr "??? från här till ???SLUT kan rader ha blivit infogade/borttagna"
+
+msgid "???END"
+msgstr "??SLUT"
+
+msgid "E311: Recovery Interrupted"
+msgstr "E311: Återskapning avbruten"
+
+msgid ""
+"E312: Errors detected while recovering; look for lines starting with ???"
+msgstr ""
+"E312: Fel upptäckt vid återskapning; titta efter rader som börjar med ???"
+
+msgid "See \":help E312\" for more information."
+msgstr "Se \":help E312\" för mer information."
+
+msgid "Recovery completed. You should check if everything is OK."
+msgstr "Återskapning klar. Du borde kontrollera om allting är OK."
+
+msgid ""
+"\n"
+"(You might want to write out this file under another name\n"
+msgstr ""
+"\n"
+"(Du kanske vill spara den här filen under ett annat namn\n"
+
+msgid "and run diff with the original file to check for changes)\n"
+msgstr ""
+"och kör diff med orginalfilen för att kontrollera efter förändringar)\n"
+
+msgid ""
+"Delete the .swp file afterwards.\n"
+"\n"
+msgstr ""
+"Ta bort .swp-filen efteråt.\n"
+"\n"
+
+#. use msg() to start the scrolling properly
+msgid "Swap files found:"
+msgstr "Växlingsfiler hittade:"
+
+msgid " In current directory:\n"
+msgstr " I aktuell katalog:\n"
+
+msgid " Using specified name:\n"
+msgstr " Använder angivet namn:\n"
+
+msgid " In directory "
+msgstr " I katalog "
+
+msgid " -- none --\n"
+msgstr " -- inget --\n"
+
+msgid " owned by: "
+msgstr " ägd av: "
+
+msgid " dated: "
+msgstr " daterad: "
+
+msgid " dated: "
+msgstr " daterad: "
+
+msgid " [from Vim version 3.0]"
+msgstr " [från Vim version 3.0]"
+
+msgid " [does not look like a Vim swap file]"
+msgstr " [ser inte ut som en Vim-växlingsfil]"
+
+msgid " file name: "
+msgstr " filnamn: "
+
+msgid ""
+"\n"
+" modified: "
+msgstr ""
+"\n"
+" modifierad: "
+
+msgid "YES"
+msgstr "JA"
+
+msgid "no"
+msgstr "nej"
+
+msgid ""
+"\n"
+" user name: "
+msgstr ""
+"\n"
+" användarnamn: "
+
+msgid " host name: "
+msgstr " värdnamn: "
+
+msgid ""
+"\n"
+" host name: "
+msgstr ""
+"\n"
+" värdnamn: "
+
+msgid ""
+"\n"
+" process ID: "
+msgstr ""
+"\n"
+" process-ID: "
+
+msgid " (still running)"
+msgstr " (körs fortfarande)"
+
+msgid ""
+"\n"
+" [not usable with this version of Vim]"
+msgstr ""
+"\n"
+" [inte användbar med den här versionen av Vim]"
+
+msgid ""
+"\n"
+" [not usable on this computer]"
+msgstr ""
+"\n"
+" [inte användbar på den här datorn]"
+
+msgid " [cannot be read]"
+msgstr " [kan inte läsas]"
+
+msgid " [cannot be opened]"
+msgstr " [kan inte öppnas]"
+
+msgid "E313: Cannot preserve, there is no swap file"
+msgstr "E313: Kan inte bevara, det finns ingen växlingsfil"
+
+msgid "File preserved"
+msgstr "Fil bevarad"
+
+msgid "E314: Preserve failed"
+msgstr "E314: Bevaring misslyckades"
+
+#, c-format
+msgid "E315: ml_get: invalid lnum: %ld"
+msgstr "E315: ml_get: ogiltigt lnum: %ld"
+
+#, c-format
+msgid "E316: ml_get: cannot find line %ld"
+msgstr "E316: ml_get: kan inte hitta rad %ld"
+
+msgid "E317: pointer block id wrong 3"
+msgstr "E317: pekarblock-id fel 3"
+
+msgid "stack_idx should be 0"
+msgstr "stack_idx ska vara 0"
+
+msgid "E318: Updated too many blocks?"
+msgstr "E318: Uppdaterade för många block?"
+
+msgid "E317: pointer block id wrong 4"
+msgstr "E317: pekarblock-id fel 4"
+
+msgid "deleted block 1?"
+msgstr "tagit bort block 1?"
+
+#, c-format
+msgid "E320: Cannot find line %ld"
+msgstr "E320: Kan inte hitta rad %ld"
+
+msgid "E317: pointer block id wrong"
+msgstr "E317: pekarblock-id fel"
+
+msgid "pe_line_count is zero"
+msgstr "pe_line_count är noll"
+
+#, c-format
+msgid "E322: line number out of range: %ld past the end"
+msgstr "E322: radnummer utanför område: %ld bakom slutet"
+
+#, c-format
+msgid "E323: line count wrong in block %ld"
+msgstr "E323: radantal fel i block %ld"
+
+msgid "Stack size increases"
+msgstr "Stackstorlek ökar"
+
+msgid "E317: pointer block id wrong 2"
+msgstr "E317: pekarblock-id fel 2"
+
+#, c-format
+msgid "E773: Symlink loop for \"%s\""
+msgstr "E773: Symbolisk länk-loop för \"%s\""
+
+msgid "E325: ATTENTION"
+msgstr "E325: LYSTRING"
+
+msgid ""
+"\n"
+"Found a swap file by the name \""
+msgstr ""
+"\n"
+"Hittade en växlingsfil med namnet \""
+
+msgid "While opening file \""
+msgstr "Vid öppning av fil \""
+
+msgid " NEWER than swap file!\n"
+msgstr " NYARE än växelfil!\n"
+
+#. Some of these messages are long to allow translation to
+#. * other languages.
+msgid ""
+"\n"
+"(1) Another program may be editing the same file.\n"
+" If this is the case, be careful not to end up with two\n"
+" different instances of the same file when making changes.\n"
+msgstr ""
+"\n"
+"(1) Ett annat program kan redigera samma fil.\n"
+" Om så är fallet, var försiktig så att det inte slutar med två\n"
+" versioner av samma fil vid förändringar.\n"
+
+msgid " Quit, or continue with caution.\n"
+msgstr " Avsluta, eller fortsätt på egen risk.\n"
+
+msgid ""
+"\n"
+"(2) An edit session for this file crashed.\n"
+msgstr ""
+"\n"
+"(2) En redigeringssession för den här filen kraschade.\n"
+
+msgid " If this is the case, use \":recover\" or \"vim -r "
+msgstr " Om så är fallet, använd \":recover\" eller \"vim -r "
+
+msgid ""
+"\"\n"
+" to recover the changes (see \":help recovery\").\n"
+msgstr ""
+"\"\n"
+" för att återskapa förändringarna (se \":help recovery\").\n"
+
+msgid " If you did this already, delete the swap file \""
+msgstr " Om du redan har gjort det, ta bort växlingsfilen \""
+
+msgid ""
+"\"\n"
+" to avoid this message.\n"
+msgstr ""
+"\"\n"
+" för att undvika det här meddelandet.\n"
+
+msgid "Swap file \""
+msgstr "Växlingsfil \""
+
+msgid "\" already exists!"
+msgstr "\" existerar redan!"
+
+msgid "VIM - ATTENTION"
+msgstr "VIM - LYSTRING"
+
+msgid "Swap file already exists!"
+msgstr "Växlingsfil existerar redan!"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"&Öppna skrivskyddad\n"
+"&Redigera ändå\n"
+"&Återskapa\n"
+"&Avsluta\n"
+"A&vbryt"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Delete it\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"&Öppna skrivskyddad\n"
+"&Redigera ändå\n"
+"&Återskapa\n"
+"&Ta bort den\n"
+"&Avsluta\n"
+"A&vbryt"
+
+msgid "E326: Too many swap files found"
+msgstr "E326: För många växlingsfiler hittade"
+
+msgid "E327: Part of menu-item path is not sub-menu"
+msgstr "E327: Del av menyföremål sökväg är inte undermeny"
+
+msgid "E328: Menu only exists in another mode"
+msgstr "E328: Meny existerar bara i ett annat läge"
+
+#, c-format
+msgid "E329: No menu \"%s\""
+msgstr "E329: Ingen meny \"%s\""
+
+#. Only a mnemonic or accelerator is not valid.
+msgid "E792: Empty menu name"
+msgstr "E792: Tomt menynamn"
+
+msgid "E330: Menu path must not lead to a sub-menu"
+msgstr "E330: Menysökväg får inte leda till en undermeny"
+
+msgid "E331: Must not add menu items directly to menu bar"
+msgstr "E331: Får inte lägga till menyföremål direkt till menyrad"
+
+msgid "E332: Separator cannot be part of a menu path"
+msgstr "E332: Avskiljare kam inte vara en del av en menysökväg"
+
+#. Now we have found the matching menu, and we list the mappings
+#. Highlight title
+msgid ""
+"\n"
+"--- Menus ---"
+msgstr ""
+"\n"
+"--- Menyer ---"
+
+msgid "Tear off this menu"
+msgstr "Ta loss den här menyn"
+
+msgid "E333: Menu path must lead to a menu item"
+msgstr "E333: Menysökväg måste leda till ett menyföremål"
+
+#, c-format
+msgid "E334: Menu not found: %s"
+msgstr "E334: Meny hittades inte: %s"
+
+#, c-format
+msgid "E335: Menu not defined for %s mode"
+msgstr "E335: Meny inte definierad för %s läge"
+
+msgid "E336: Menu path must lead to a sub-menu"
+msgstr "E336: Menysökväg måste leda till en undermeny"
+
+msgid "E337: Menu not found - check menu names"
+msgstr "E337: Meny hittades inte - kontrollera menynamn"
+
+#, c-format
+msgid "Error detected while processing %s:"
+msgstr "Fel upptäcktes vid bearbetning av %s:"
+
+#, c-format
+msgid "line %4ld:"
+msgstr "rad %4ld:"
+
+#, c-format
+msgid "E354: Invalid register name: '%s'"
+msgstr "E354: Otillåtet registernamn: '%s'"
+
+msgid "Messages maintainer: Bram Moolenaar <Bram@vim.org>"
+msgstr "Meddelandeansvarig: Johan Svedberg <johan@svedberg.com>"
+
+msgid "Interrupt: "
+msgstr "Avbrott: "
+
+msgid "Press ENTER or type command to continue"
+msgstr "Tryck RETUR eller skriv kommando för att fortsätta"
+
+#, c-format
+msgid "%s line %ld"
+msgstr "%s rad %ld"
+
+msgid "-- More --"
+msgstr "-- Mer --"
+
+msgid " SPACE/d/j: screen/page/line down, b/u/k: up, q: quit "
+msgstr " BLANKSTEG/d/j: skärm/sida/rad ned, b/u/k: upp, q: quit "
+
+msgid "Question"
+msgstr "Fråga"
+
+msgid ""
+"&Yes\n"
+"&No"
+msgstr ""
+"&Ja\n"
+"&Nej"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"Save &All\n"
+"&Discard All\n"
+"&Cancel"
+msgstr ""
+"&Ja\n"
+"&Nej\n"
+"&Spara &alla\n"
+"&Kasta bort alla\n"
+"&Avbryt"
+
+msgid "Select Directory dialog"
+msgstr "Välj katalog-dialog"
+
+msgid "Save File dialog"
+msgstr "Spara fil-dialog"
+
+msgid "Open File dialog"
+msgstr "Öppna fil-dialog"
+
+#. TODO: non-GUI file selector here
+msgid "E338: Sorry, no file browser in console mode"
+msgstr "E338: Tyvärr, ingen filbläddrare i konsoll-läge"
+
+msgid "E766: Insufficient arguments for printf()"
+msgstr "E766: Otillräckliga argument för printf()"
+
+msgid "E767: Too many arguments to printf()"
+msgstr "E767: För många argument till printf()"
+
+msgid "W10: Warning: Changing a readonly file"
+msgstr "W10: Varning: Ändrar en skrivskyddad fil"
+
+msgid "Type number or click with mouse (<Enter> cancels): "
+msgstr "Skriv siffra eller klicka med musen (<Retur> avbryter): "
+
+msgid "Choice number (<Enter> cancels): "
+msgstr "Välj siffra (<Retur> avbryter): "
+
+msgid "1 more line"
+msgstr "1 rad till"
+
+msgid "1 line less"
+msgstr "1 rad mindre"
+
+#, c-format
+msgid "%ld more lines"
+msgstr "%ld rad till"
+
+#, c-format
+msgid "%ld fewer lines"
+msgstr "%ld färre rader"
+
+msgid " (Interrupted)"
+msgstr " (Avbruten)"
+
+msgid "Beep!"
+msgstr "Piip!"
+
+msgid "Vim: preserving files...\n"
+msgstr "Vim: bevarar filer...\n"
+
+#. close all memfiles, without deleting
+msgid "Vim: Finished.\n"
+msgstr "Vim: Färdig.\n"
+
+#, c-format
+msgid "ERROR: "
+msgstr "FEL: "
+
+#, c-format
+msgid ""
+"\n"
+"[bytes] total alloc-freed %lu-%lu, in use %lu, peak use %lu\n"
+msgstr ""
+"\n"
+"[byte] sammanlagd allok-frigjord %lu-%lu, i användning %lu, toppanvändning %"
+"lu\n"
+
+#, c-format
+msgid ""
+"[calls] total re/malloc()'s %lu, total free()'s %lu\n"
+"\n"
+msgstr ""
+"[anrop] sammanlagda om/malloc()'s %lu, sammanlagda free()'s %lu\n"
+"\n"
+
+msgid "E340: Line is becoming too long"
+msgstr "E340: Rad börjar bli för lång"
+
+#, c-format
+msgid "E341: Internal error: lalloc(%ld, )"
+msgstr "E341: Internt fel: lalloc(%ld, )"
+
+#, c-format
+msgid "E342: Out of memory! (allocating %lu bytes)"
+msgstr "E342: Slut på minne! (allokerar %lu byte)"
+
+#, c-format
+msgid "Calling shell to execute: \"%s\""
+msgstr "Anropar skal att köra: \"%s\""
+
+msgid "E545: Missing colon"
+msgstr "E545: Saknar kolon"
+
+msgid "E546: Illegal mode"
+msgstr "E546: Otillåtet läge"
+
+msgid "E547: Illegal mouseshape"
+msgstr "E547: Otillåten musform"
+
+msgid "E548: digit expected"
+msgstr "E548: siffra förväntades"
+
+msgid "E549: Illegal percentage"
+msgstr "E549: Otillåten procentsats"
+
+msgid "Enter encryption key: "
+msgstr "Ange krypteringsnyckel: "
+
+msgid "Enter same key again: "
+msgstr "Ange samma nyckel igen: "
+
+msgid "Keys don't match!"
+msgstr "Nycklar matchar inte!"
+
+#, c-format
+msgid ""
+"E343: Invalid path: '**[number]' must be at the end of the path or be "
+"followed by '%s'."
+msgstr ""
+"E343: Ogiltig sökväg: '**[nummer]' måste vara i slutet på sökvägen eller "
+"följas av '%s'."
+
+#, c-format
+msgid "E344: Can't find directory \"%s\" in cdpath"
+msgstr "E344: Kan inte hitta katalog \"%s\" i cdpath"
+
+#, c-format
+msgid "E345: Can't find file \"%s\" in path"
+msgstr "E345: Kan inte hitta fil \"%s\" i sökväg"
+
+#, c-format
+msgid "E346: No more directory \"%s\" found in cdpath"
+msgstr "E346: Ingen katalog \"%s\" hittades i cdpath"
+
+#, c-format
+msgid "E347: No more file \"%s\" found in path"
+msgstr "E347: Ingen fil \"%s\" hittades i sökvägen"
+
+#. Get here when the server can't be found.
+msgid "Cannot connect to Netbeans #2"
+msgstr "Kan inte ansluta till Netbeans #2"
+
+msgid "Cannot connect to Netbeans"
+msgstr "Kan inte ansluta till Netbeans"
+
+#, c-format
+msgid "E668: Wrong access mode for NetBeans connection info file: \"%s\""
+msgstr "E668: Fel rättighetsläge för NetBeans-anslutningens info fil: \"%s\""
+
+msgid "read from Netbeans socket"
+msgstr "läs från Netbeans-uttag"
+
+#, c-format
+msgid "E658: NetBeans connection lost for buffer %ld"
+msgstr "E658: NetBeans-anslutning tappad för buffert %ld"
+
+msgid "E505: "
+msgstr "E505: "
+
+msgid "E774: 'operatorfunc' is empty"
+msgstr "E774: 'operatorfunc' är tom"
+
+msgid "E775: Eval feature not available"
+msgstr "E775: Eval-funktionen inte tillgänglig"
+
+msgid "Warning: terminal cannot highlight"
+msgstr "Varning: terminal kan inte framhäva"
+
+msgid "E348: No string under cursor"
+msgstr "E348: Ingen sträng under markör"
+
+msgid "E349: No identifier under cursor"
+msgstr "E349: Ingen identifierare under markör"
+
+msgid "E352: Cannot erase folds with current 'foldmethod'"
+msgstr "E352: Kan inte ta bort veck med aktuell 'foldmethod'"
+
+msgid "E664: changelist is empty"
+msgstr "E664: ändringslista är tom"
+
+msgid "E662: At start of changelist"
+msgstr "E662: Vid början av ändringslista"
+
+msgid "E663: At end of changelist"
+msgstr "E663: Vid slutet av ändringslista"
+
+msgid "Type :quit<Enter> to exit Vim"
+msgstr "skriv :q<Enter> för att avsluta Vim "
+
+#, c-format
+msgid "1 line %sed 1 time"
+msgstr "1 rad %sad 1 gång"
+
+#, c-format
+msgid "1 line %sed %d times"
+msgstr "1 rad %sade %d gånger"
+
+#, c-format
+msgid "%ld lines %sed 1 time"
+msgstr "%ld rader %sad 1 gång"
+
+#, c-format
+msgid "%ld lines %sed %d times"
+msgstr "%ld rader %sade %d gånger"
+
+#, c-format
+msgid "%ld lines to indent... "
+msgstr "%ld rader att indentera... "
+
+msgid "1 line indented "
+msgstr "1 rad indenterad "
+
+#, c-format
+msgid "%ld lines indented "
+msgstr "%ld rader indenterade "
+
+msgid "E748: No previously used register"
+msgstr "E748: Inget tidigare använt register"
+
+#. must display the prompt
+msgid "cannot yank; delete anyway"
+msgstr "kan inte kopiera; ta bort ändå"
+
+msgid "1 line changed"
+msgstr "1 rad ändrad"
+
+#, c-format
+msgid "%ld lines changed"
+msgstr "%ld rader ändrade"
+
+#, c-format
+msgid "freeing %ld lines"
+msgstr "frigör %ld rader"
+
+msgid "block of 1 line yanked"
+msgstr "block om 1 rad kopierat"
+
+msgid "1 line yanked"
+msgstr "1 rad kopierad"
+
+#, c-format
+msgid "block of %ld lines yanked"
+msgstr "block om %ld rader kopierade"
+
+#, c-format
+msgid "%ld lines yanked"
+msgstr "%ld rader kopierade"
+
+#, c-format
+msgid "E353: Nothing in register %s"
+msgstr "E353: Ingenting i register %s"
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Registers ---"
+msgstr ""
+"\n"
+"--- Register ---"
+
+msgid "Illegal register name"
+msgstr "Otillåtet registernamn"
+
+#, c-format
+msgid ""
+"\n"
+"# Registers:\n"
+msgstr ""
+"\n"
+"# Register:\n"
+
+#, c-format
+msgid "E574: Unknown register type %d"
+msgstr "E574: Okänd registertyp %d"
+
+#, c-format
+msgid "%ld Cols; "
+msgstr "%ld kolumner; "
+
+#, c-format
+msgid "Selected %s%ld of %ld Lines; %ld of %ld Words; %ld of %ld Bytes"
+msgstr "Markerade %s%ld av %ld rader; %ld av %ld ord; %ld av %ld bitar"
+
+#, c-format
+msgid ""
+"Selected %s%ld of %ld Lines; %ld of %ld Words; %ld of %ld Chars; %ld of %ld "
+"Bytes"
+msgstr ""
+"Markerade %s%ld av %ld rader; %ld av %ld ord; %ld av %ld tecken; %ld av %ld "
+"bitar"
+
+#, c-format
+msgid "Col %s of %s; Line %ld of %ld; Word %ld of %ld; Byte %ld of %ld"
+msgstr "Kol %s av %s; rad %ld av %ld; ord %ld av %ld; bit %ld av %ld"
+
+#, c-format
+msgid ""
+"Col %s of %s; Line %ld of %ld; Word %ld of %ld; Char %ld of %ld; Byte %ld of "
+"%ld"
+msgstr ""
+"Kol %s av %s; rad %ld av %ld; ord %ld av %ld; tecken %ld av %ld; bit %ld av %"
+"ld"
+
+#, c-format
+msgid "(+%ld for BOM)"
+msgstr "(+%ld för BOM)"
+
+msgid "%<%f%h%m%=Page %N"
+msgstr "%<%f%h%m%=Sida %N"
+
+msgid "Thanks for flying Vim"
+msgstr "Tack för att du flyger med Vim"
+
+msgid "E518: Unknown option"
+msgstr "E518: Okänd flagga"
+
+msgid "E519: Option not supported"
+msgstr "E519: Flagga stöds inte"
+
+msgid "E520: Not allowed in a modeline"
+msgstr "E520: Inte tillåtet i en lägesrad"
+
+msgid "E521: Number required after ="
+msgstr "E521: Nummer krävs efter ="
+
+msgid "E522: Not found in termcap"
+msgstr "E522: Inte hittat i termcap"
+
+#, c-format
+msgid "E539: Illegal character <%s>"
+msgstr "E539: Otillåtet tecken <%s>"
+
+msgid "E529: Cannot set 'term' to empty string"
+msgstr "E529: Kan inte sätta 'term' till tom sträng"
+
+msgid "E530: Cannot change term in GUI"
+msgstr "E530: Kan inte ändra term i GUI"
+
+msgid "E531: Use \":gui\" to start the GUI"
+msgstr "E531: Använd \":gui\" för att starta GUI"
+
+msgid "E589: 'backupext' and 'patchmode' are equal"
+msgstr "E589: 'backuptext' och 'patchmode' är lika"
+
+msgid "E617: Cannot be changed in the GTK+ 2 GUI"
+msgstr "E617: Kan inte bli ändrat i GTK+ 2-GUI"
+
+msgid "E524: Missing colon"
+msgstr "E524: Saknar kolon"
+
+msgid "E525: Zero length string"
+msgstr "E525: Nollängdssträng"
+
+#, c-format
+msgid "E526: Missing number after <%s>"
+msgstr "E526: Saknar nummer efter <%s>"
+
+msgid "E527: Missing comma"
+msgstr "E527: Saknar komma"
+
+msgid "E528: Must specify a ' value"
+msgstr "E528: Måste ange ett '-värde"
+
+msgid "E595: contains unprintable or wide character"
+msgstr "E595: innehåller outskrivbara eller breda tecken"
+
+msgid "E596: Invalid font(s)"
+msgstr "E596: Ogiltig(a) typsnitt"
+
+msgid "E597: can't select fontset"
+msgstr "E597: kan inte välja typsnittsuppsättning"
+
+msgid "E598: Invalid fontset"
+msgstr "E598: Ogiltig typsnittsuppsättning"
+
+msgid "E533: can't select wide font"
+msgstr "E533: kan inte välja brett typsnitt"
+
+msgid "E534: Invalid wide font"
+msgstr "E534: Ogiltigt brett typsnitt"
+
+#, c-format
+msgid "E535: Illegal character after <%c>"
+msgstr "E535: Otillåtet tecken efter <%c>"
+
+msgid "E536: comma required"
+msgstr "E536: komma krävs"
+
+#, c-format
+msgid "E537: 'commentstring' must be empty or contain %s"
+msgstr "E537: 'commentstring' måste vara tom eller innehålla %s"
+
+msgid "E538: No mouse support"
+msgstr "E538: Inget musstöd"
+
+msgid "E540: Unclosed expression sequence"
+msgstr "E540: Ostängd uttryckssekvens"
+
+msgid "E541: too many items"
+msgstr "E541: för många föremål"
+
+msgid "E542: unbalanced groups"
+msgstr "E542: obalanserade grupper"
+
+msgid "E590: A preview window already exists"
+msgstr "E590: Ett förhandsvisningsfönster existerar redan"
+
+msgid "W17: Arabic requires UTF-8, do ':set encoding=utf-8'"
+msgstr "W17: Arabiska kräver UTF-8, gör ':set encoding=utf-8'"
+
+#, c-format
+msgid "E593: Need at least %d lines"
+msgstr "E593: Behöver åtminstone %d rader"
+
+#, c-format
+msgid "E594: Need at least %d columns"
+msgstr "E594: Behöver åtminstone %d kolumner"
+
+#, c-format
+msgid "E355: Unknown option: %s"
+msgstr "E355: Okänd flagga: %s"
+
+msgid ""
+"\n"
+"--- Terminal codes ---"
+msgstr ""
+"\n"
+"--- Terminalkoder ---"
+
+msgid ""
+"\n"
+"--- Global option values ---"
+msgstr ""
+"\n"
+"--- Globala flaggvärden ---"
+
+msgid ""
+"\n"
+"--- Local option values ---"
+msgstr ""
+"\n"
+"--- Lokala flaggvärden ---"
+
+msgid ""
+"\n"
+"--- Options ---"
+msgstr ""
+"\n"
+"--- Flaggor ---"
+
+msgid "E356: get_varp ERROR"
+msgstr "E356: get_varp-FEL"
+
+#, c-format
+msgid "E357: 'langmap': Matching character missing for %s"
+msgstr "E357: 'langmap': Matchande tecken saknas för %s"
+
+#, c-format
+msgid "E358: 'langmap': Extra characters after semicolon: %s"
+msgstr "E358: 'langmap': Extra tecken efter semikolon: %s"
+
+msgid "cannot open "
+msgstr "kan inte öppna "
+
+msgid "VIM: Can't open window!\n"
+msgstr "VIM: Kan inte öppna fönster!\n"
+
+msgid "Need Amigados version 2.04 or later\n"
+msgstr "Behöver Amigados version 2.04 eller senare\n"
+
+#, c-format
+msgid "Need %s version %ld\n"
+msgstr "Behöver %s version %ld\n"
+
+msgid "Cannot open NIL:\n"
+msgstr "Kan inte öppna NIL:\n"
+
+msgid "Cannot create "
+msgstr "Kan inte skapa "
+
+#, c-format
+msgid "Vim exiting with %d\n"
+msgstr "Vim avslutar med %d\n"
+
+msgid "cannot change console mode ?!\n"
+msgstr "kan inte ändra konsoll-läge ?!\n"
+
+msgid "mch_get_shellsize: not a console??\n"
+msgstr "mch_get_shellsize: inte en konsoll??\n"
+
+#. if Vim opened a window: Executing a shell may cause crashes
+msgid "E360: Cannot execute shell with -f option"
+msgstr "E360: Kan inte köra skal med -f-flagga"
+
+msgid "Cannot execute "
+msgstr "Kan inte köra "
+
+msgid "shell "
+msgstr "skal "
+
+msgid " returned\n"
+msgstr " returnerade\n"
+
+msgid "ANCHOR_BUF_SIZE too small."
+msgstr "ANCHOR_BUF_SIZE för liten."
+
+msgid "I/O ERROR"
+msgstr "I/O-FEL"
+
+msgid "Message"
+msgstr "Meddelande"
+
+msgid "'columns' is not 80, cannot execute external commands"
+msgstr "'columns' är inte 80, kan inte köra externa kommandon"
+
+msgid "E237: Printer selection failed"
+msgstr "E237: Skrivarval misslyckades"
+
+#, c-format
+msgid "to %s on %s"
+msgstr "till %s på %s"
+
+#, c-format
+msgid "E613: Unknown printer font: %s"
+msgstr "E613: Okänt skrivartypsnitt: %s"
+
+#, c-format
+msgid "E238: Print error: %s"
+msgstr "E238: Skrivarfel: %s"
+
+#, c-format
+msgid "Printing '%s'"
+msgstr "Skriver ut '%s'"
+
+#, c-format
+msgid "E244: Illegal charset name \"%s\" in font name \"%s\""
+msgstr "E244: Otillåtet teckenkodsnamn \"%s\" i typsnittsnamn \"%s\""
+
+#, c-format
+msgid "E245: Illegal char '%c' in font name \"%s\""
+msgstr "E245: Otillåtet tecken '%c' i typsnittsnamn \"%s\""
+
+msgid "Vim: Double signal, exiting\n"
+msgstr "Vim: Dubbelsignal, avslutar\n"
+
+#, c-format
+msgid "Vim: Caught deadly signal %s\n"
+msgstr "Vim: Fångade dödlig signal %s\n"
+
+#, c-format
+msgid "Vim: Caught deadly signal\n"
+msgstr "Vim: Fångade dödlig signal\n"
+
+#, c-format
+msgid "Opening the X display took %ld msec"
+msgstr "Öppning av X-display tog %ld ms"
+
+msgid ""
+"\n"
+"Vim: Got X error\n"
+msgstr ""
+"\n"
+"Vim: Fick X-error\n"
+
+msgid "Testing the X display failed"
+msgstr "Testning av X-displayen misslyckades"
+
+msgid "Opening the X display timed out"
+msgstr "Öppning av X-displayen tog för lång tid"
+
+msgid ""
+"\n"
+"Cannot execute shell "
+msgstr ""
+"\n"
+"Kan inte köra skal "
+
+msgid ""
+"\n"
+"Cannot execute shell sh\n"
+msgstr ""
+"\n"
+"Kan inte köra skal sh\n"
+
+msgid ""
+"\n"
+"shell returned "
+msgstr ""
+"\n"
+"skal returnerade "
+
+msgid ""
+"\n"
+"Cannot create pipes\n"
+msgstr ""
+"\n"
+"Kan inte skapa rör\n"
+
+msgid ""
+"\n"
+"Cannot fork\n"
+msgstr ""
+"\n"
+"Kan inte grena\n"
+
+msgid ""
+"\n"
+"Command terminated\n"
+msgstr ""
+"\n"
+"Kommando avslutades\n"
+
+msgid "XSMP lost ICE connection"
+msgstr "XSMP tappade ICE-anslutning"
+
+#, c-format
+msgid "dlerror = \"%s\""
+msgstr "dlfel = \"%s\""
+
+msgid "Opening the X display failed"
+msgstr "Öppning av X-displayen misslyckades"
+
+msgid "XSMP handling save-yourself request"
+msgstr "XSMP hanterar spara-själv-förfrågan"
+
+msgid "XSMP opening connection"
+msgstr "XSMP öppnar anslutning"
+
+msgid "XSMP ICE connection watch failed"
+msgstr "XSMP ICE-anslutning övervakning misslyckades"
+
+#, c-format
+msgid "XSMP SmcOpenConnection failed: %s"
+msgstr "XSMP SmcOpenConnection misslyckades: %s"
+
+msgid "Could not load vim32.dll!"
+msgstr "Kunde inte läsa in vim32.dll!"
+
+msgid "VIM Error"
+msgstr "VIM-fel"
+
+msgid "Could not fix up function pointers to the DLL!"
+msgstr "Kunde inte ordna upp funktionspekare till DLL:en!"
+
+#, c-format
+msgid "shell returned %d"
+msgstr "skal returnerade %d"
+
+#, c-format
+msgid "Vim: Caught %s event\n"
+msgstr "Vim: Fångade %s-händelse\n"
+
+msgid "close"
+msgstr "stäng"
+
+msgid "logoff"
+msgstr "logga ut"
+
+msgid "shutdown"
+msgstr "stäng av"
+
+msgid "E371: Command not found"
+msgstr "E371: Kommando hittades inte"
+
+msgid ""
+"VIMRUN.EXE not found in your $PATH.\n"
+"External commands will not pause after completion.\n"
+"See :help win32-vimrun for more information."
+msgstr ""
+"VIMRUN.EXE hittades inte i din $PATH.\n"
+"Externa kommandon vill inte stå stilla efter färdigställning.\n"
+"Se :help win32-vimrun för mer information."
+
+msgid "Vim Warning"
+msgstr "Vim-varning"
+
+msgid "At line"
+msgstr "På rad"
+
+#, c-format
+msgid "E372: Too many %%%c in format string"
+msgstr "E372: För många %%%c i formatsträng"
+
+#, c-format
+msgid "E373: Unexpected %%%c in format string"
+msgstr "E373: Oväntad %%%c i formatsträng"
+
+msgid "E374: Missing ] in format string"
+msgstr "E374: Saknar ] i formatsträng"
+
+#, c-format
+msgid "E375: Unsupported %%%c in format string"
+msgstr "E375: Ostödd %%%c i formatsträng"
+
+#, c-format
+msgid "E376: Invalid %%%c in format string prefix"
+msgstr "E376: Ogiltig %%%c i formatsträngprefix"
+
+#, c-format
+msgid "E377: Invalid %%%c in format string"
+msgstr "E377: Ogiltig %%%c i formatsträng"
+
+msgid "E378: 'errorformat' contains no pattern"
+msgstr "E378: 'errorformat' innehåller inga mönster"
+
+msgid "E379: Missing or empty directory name"
+msgstr "E379: Saknar eller tomt katalognamn"
+
+msgid "E553: No more items"
+msgstr "E553: Inga fler föremål"
+
+#, c-format
+msgid "(%d of %d)%s%s: "
+msgstr "(%d av %d)%s%s: "
+
+msgid " (line deleted)"
+msgstr " (rad borttagen)"
+
+msgid "E380: At bottom of quickfix stack"
+msgstr "E380: På botten av quickfix-stack"
+
+msgid "E381: At top of quickfix stack"
+msgstr "E381: På toppen av quickfix-stack"
+
+#, c-format
+msgid "error list %d of %d; %d errors"
+msgstr "fellista %d av %d; %d fel"
+
+msgid "E382: Cannot write, 'buftype' option is set"
+msgstr "E382: Kan inte skriva, 'buftype'-flagga är satt"
+
+msgid "E683: File name missing or invalid pattern"
+msgstr "E683: Filnamn saknas eller ogiltigt mönster"
+
+#, c-format
+msgid "Cannot open file \"%s\""
+msgstr "Kan inte öppna fil \"%s\""
+
+msgid "E681: Buffer is not loaded"
+msgstr "E681: Buffert är inte laddad"
+
+msgid "E777: String or List expected"
+msgstr "E777: Sträng eller Lista förväntades"
+
+#, c-format
+msgid "E369: invalid item in %s%%[]"
+msgstr "E369: ogiltigt föremål i %s%%[]"
+
+msgid "E339: Pattern too long"
+msgstr "E339: Mönster för långt"
+
+msgid "E50: Too many \\z("
+msgstr "E50: För många \\z("
+
+#, c-format
+msgid "E51: Too many %s("
+msgstr "E51: För många %s("
+
+msgid "E52: Unmatched \\z("
+msgstr "E52: Omatchade \\z("
+
+#, c-format
+msgid "E53: Unmatched %s%%("
+msgstr "E53: Omatchade %s%%("
+
+#, c-format
+msgid "E54: Unmatched %s("
+msgstr "E54: Omatchade %s("
+
+#, c-format
+msgid "E55: Unmatched %s)"
+msgstr "E55: Omatchade %s)"
+
+#, c-format
+msgid "E59: invalid character after %s@"
+msgstr "E59: ogiltigt tecken efter %s@"
+
+#, c-format
+msgid "E60: Too many complex %s{...}s"
+msgstr "E60: För många komplexa %s{...}s"
+
+#, c-format
+msgid "E61: Nested %s*"
+msgstr "E61: Nästlade %s*"
+
+#, c-format
+msgid "E62: Nested %s%c"
+msgstr "E62: Nästlade %s%c"
+
+msgid "E63: invalid use of \\_"
+msgstr "E63: ogiltig användning av \\_"
+
+#, c-format
+msgid "E64: %s%c follows nothing"
+msgstr "E64: %s%c följer ingenting"
+
+msgid "E65: Illegal back reference"
+msgstr "E65: Otillåten bakåtreferens"
+
+msgid "E66: \\z( not allowed here"
+msgstr "E66: \\z{ inte tillåtet här"
+
+msgid "E67: \\z1 - \\z9 not allowed here"
+msgstr "E67: \\z1 m.fl. inte tillåtet här"
+
+msgid "E68: Invalid character after \\z"
+msgstr "E68: Ogiltigt tecken efter \\z"
+
+#, c-format
+msgid "E69: Missing ] after %s%%["
+msgstr "E69: Saknar ] efter %s%%["
+
+#, c-format
+msgid "E70: Empty %s%%[]"
+msgstr "E70: Tom %s%%[]"
+
+#, c-format
+msgid "E678: Invalid character after %s%%[dxouU]"
+msgstr "E678: Ogiltigt tecken efter %s%%[dxouU]"
+
+#, c-format
+msgid "E71: Invalid character after %s%%"
+msgstr "E71: Ogiltigt tecken efter %s%%"
+
+#, c-format
+msgid "E769: Missing ] after %s["
+msgstr "E769: Saknar ] efter %s["
+
+#, c-format
+msgid "E554: Syntax error in %s{...}"
+msgstr "E554: Syntaxfel i %s{...}"
+
+msgid "External submatches:\n"
+msgstr "Externa underträffar:\n"
+
+msgid " VREPLACE"
+msgstr " VERSÄTT"
+
+msgid " REPLACE"
+msgstr " ERSÄTT"
+
+msgid " REVERSE"
+msgstr " OMVÄND"
+
+msgid " INSERT"
+msgstr " INFOGA"
+
+msgid " (insert)"
+msgstr " (infoga)"
+
+msgid " (replace)"
+msgstr " (ersätt)"
+
+msgid " (vreplace)"
+msgstr " (versätt)"
+
+msgid " Hebrew"
+msgstr " Hebreiska"
+
+msgid " Arabic"
+msgstr " Arabiska"
+
+msgid " (lang)"
+msgstr " (språk)"
+
+msgid " (paste)"
+msgstr " (klistra in)"
+
+msgid " VISUAL"
+msgstr " VISUELL"
+
+msgid " VISUAL LINE"
+msgstr " VISUELL RAD"
+
+msgid " VISUAL BLOCK"
+msgstr " VISUELLT BLOCK"
+
+msgid " SELECT"
+msgstr " MARKERA"
+
+msgid " SELECT LINE"
+msgstr " MARKERA RAD"
+
+msgid " SELECT BLOCK"
+msgstr " MARKERA BLOCK"
+
+msgid "recording"
+msgstr "spelar in"
+
+#, c-format
+msgid "E383: Invalid search string: %s"
+msgstr "E383: Ogiltig söksträng: %s"
+
+#, c-format
+msgid "E384: search hit TOP without match for: %s"
+msgstr "E384: sökning nådde TOPPEN utan träff av: %s"
+
+#, c-format
+msgid "E385: search hit BOTTOM without match for: %s"
+msgstr "E385: sökning nådde BOTTEN utan träff av: %s"
+
+msgid "E386: Expected '?' or '/' after ';'"
+msgstr "E386: Förväntade '?' eller '/' efter ';'"
+
+msgid " (includes previously listed match)"
+msgstr " (inkluderar tidigare listad träff)"
+
+#. cursor at status line
+msgid "--- Included files "
+msgstr "--- Inkluderade filer "
+
+msgid "not found "
+msgstr "hittades inte "
+
+msgid "in path ---\n"
+msgstr "i sökväg ---\n"
+
+msgid " (Already listed)"
+msgstr " (Redan listade)"
+
+msgid " NOT FOUND"
+msgstr " INTE HITTADE"
+
+#, c-format
+msgid "Scanning included file: %s"
+msgstr "Söker igenom inkluderad fil: %s"
+
+#, c-format
+msgid "Searching included file %s"
+msgstr "Söker igenom inkluderad fil %s"
+
+msgid "E387: Match is on current line"
+msgstr "E387: Matchning är på aktuell rad"
+
+msgid "All included files were found"
+msgstr "Alla inkluderade filer hittades"
+
+msgid "No included files"
+msgstr "Inga inkluderade filer"
+
+msgid "E388: Couldn't find definition"
+msgstr "E388: Kunde inte hitta definition"
+
+msgid "E389: Couldn't find pattern"
+msgstr "E389: Kunde inte hitta mönster"
+
+#, c-format
+msgid ""
+"\n"
+"# Last %sSearch Pattern:\n"
+"~"
+msgstr ""
+"\n"
+"# Senaste %sSökmönster:\n"
+"~"
+
+msgid "E759: Format error in spell file"
+msgstr "E759: Formateringsfel i stavningsfil"
+
+msgid "E758: Truncated spell file"
+msgstr "E758: Trunkerad stavningsfil"
+
+#, c-format
+msgid "Trailing text in %s line %d: %s"
+msgstr "Eftersläpande text i %s rad %d: %s"
+
+#, c-format
+msgid "Affix name too long in %s line %d: %s"
+msgstr "Affix-namn för långt i %s rad %d: %s"
+
+msgid "E761: Format error in affix file FOL, LOW or UPP"
+msgstr "E761: Formateringsfel i affix-fil FOL, LOW eller UPP"
+
+msgid "E762: Character in FOL, LOW or UPP is out of range"
+msgstr "E762: Tecken i FOL, LOW eller UPP är utanför område"
+
+msgid "Compressing word tree..."
+msgstr "Komprimerar ordträd..."
+
+msgid "E756: Spell checking is not enabled"
+msgstr "E756: Stavningskontroll är inte aktiverat"
+
+#, c-format
+msgid "Warning: Cannot find word list \"%s.%s.spl\" or \"%s.ascii.spl\""
+msgstr "Varning: Kan inte hitta ordlista \"%s.%s.spl\" eller \"%s.ascii.spl\""
+
+#, c-format
+msgid "Reading spell file \"%s\""
+msgstr "Läser stavningsfil \"%s\""
+
+msgid "E757: This does not look like a spell file"
+msgstr "E757: Det här ser inte ut som en stavningsfil"
+
+msgid "E771: Old spell file, needs to be updated"
+msgstr "E771: Gammal stavningsfil, behöver bli uppdaterad"
+
+msgid "E772: Spell file is for newer version of Vim"
+msgstr "E772: Stavningsfil är för nyare version av Vim"
+
+msgid "E770: Unsupported section in spell file"
+msgstr "E770: Ostödd sektion i stavningsfil"
+
+#, c-format
+msgid "Warning: region %s not supported"
+msgstr "Varning: region %s stöds inte"
+
+#, c-format
+msgid "Reading affix file %s..."
+msgstr "Läser affix-fil %s..."
+
+#, c-format
+msgid "Conversion failure for word in %s line %d: %s"
+msgstr "Konvertering misslyckades för ord i %s rad %d: %s"
+
+#, c-format
+msgid "Conversion in %s not supported: from %s to %s"
+msgstr "Konvertering i %s stöds inte: från %s till %s"
+
+#, c-format
+msgid "Conversion in %s not supported"
+msgstr "Konvertering i %s stöds inte"
+
+#, c-format
+msgid "Invalid value for FLAG in %s line %d: %s"
+msgstr "Ogiltigt värde för FLAG i %s rad %d: %s"
+
+#, c-format
+msgid "FLAG after using flags in %s line %d: %s"
+msgstr "FLAG efter användning av flags i %s rad %d: %s"
+
+#, c-format
+msgid ""
+"Defining COMPOUNDFORBIDFLAG after PFX item may give wrong results in %s line "
+"%d"
+msgstr ""
+"Definiera COMPOUNDFORBIDFLAG efter PFX-post kan ge fel resultat i %s rad %d"
+
+#, c-format
+msgid ""
+"Defining COMPOUNDPERMITFLAG after PFX item may give wrong results in %s line "
+"%d"
+msgstr "Definiera COMPOUNDPERMITFLAG efter PFX-post kan ge fel resultat i %s "
+"rad %d"
+
+#, c-format
+msgid "Wrong COMPOUNDWORDMAX value in %s line %d: %s"
+msgstr "Fel COMPOUNDWORDMAX-värde i %s rad %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDMIN value in %s line %d: %s"
+msgstr "Fel COMPOUNDMIN-värde i %s rad %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDSYLMAX value in %s line %d: %s"
+msgstr "Fel COMPOUNDSYLMAX-värde i %s rad %d: %s"
+
+#, c-format
+msgid "Wrong CHECKCOMPOUNDPATTERN value in %s line %d: %s"
+msgstr "Fel CHECKCOMPOUNDPATTERN-värde i %s rad %d: %s"
+
+#, c-format
+msgid "Different combining flag in continued affix block in %s line %d: %s"
+msgstr "Annan kombinerande flagga i efterföljande affix-block i %s rad %d: %s"
+
+#, c-format
+msgid "Duplicate affix in %s line %d: %s"
+msgstr "Duplicerad affix i %s rad %d: %s"
+
+#, c-format
+msgid ""
+"Affix also used for BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST in %s "
+"line %d: %s"
+msgstr ""
+"Affix också använd för BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST i %"
+"s rad %d: %s"
+
+#, c-format
+msgid "Expected Y or N in %s line %d: %s"
+msgstr "Förväntade Y eller N i %s rad %d: %s"
+
+#, c-format
+msgid "Broken condition in %s line %d: %s"
+msgstr "Trasigt villkor i %s rad %d: %s"
+
+#, c-format
+msgid "Expected REP(SAL) count in %s line %d"
+msgstr "Förväntade REP(SAL)-antal i %s rad %d"
+
+#, c-format
+msgid "Expected MAP count in %s line %d"
+msgstr "Förväntade MAP-antal i %s rad %d"
+
+#, c-format
+msgid "Duplicate character in MAP in %s line %d"
+msgstr "Duplicerat tecken i MAP i %s rad %d"
+
+#, c-format
+msgid "Unrecognized or duplicate item in %s line %d: %s"
+msgstr "Okänd eller duplicerad post i %s rad %d: %s"
+
+#, c-format
+msgid "Missing FOL/LOW/UPP line in %s"
+msgstr "Saknar FOL/LOW/UPP rad i %s"
+
+msgid "COMPOUNDSYLMAX used without SYLLABLE"
+msgstr "COMPOUNDSYLMAX använd utan SYLLABLE"
+
+msgid "Too many postponed prefixes"
+msgstr "För många uppskjutna prefix"
+
+msgid "Too many compound flags"
+msgstr "För många sammansatta flaggor"
+
+msgid "Too many postponed prefixes and/or compound flags"
+msgstr "För många uppskjutna prefix och/eller sammansatta flaggor"
+
+#, c-format
+msgid "Missing SOFO%s line in %s"
+msgstr "Saknar SOFO%s rad i %s"
+
+#, c-format
+msgid "Both SAL and SOFO lines in %s"
+msgstr "Både SAL och SOFO rader i %s"
+
+#, c-format
+msgid "Flag is not a number in %s line %d: %s"
+msgstr "Flagga är inte ett nummer i %s rad %d: %s"
+
+#, c-format
+msgid "Illegal flag in %s line %d: %s"
+msgstr "Ogiltig flagga i %s rad %d: %s"
+
+#, c-format
+msgid "%s value differs from what is used in another .aff file"
+msgstr "%s värde skiljer sig från vad som används i en annan .aff-fil."
+
+#, c-format
+msgid "Reading dictionary file %s..."
+msgstr "Läser ordboksfil %s..."
+
+#, c-format
+msgid "E760: No word count in %s"
+msgstr "E760: Inget ordantal i %s"
+
+#, c-format
+msgid "line %6d, word %6d - %s"
+msgstr "rad %6d, ord %6d - %s"
+
+#, c-format
+msgid "Duplicate word in %s line %d: %s"
+msgstr "Duplicerat ord i %s rad %d: %s"
+
+#, c-format
+msgid "First duplicate word in %s line %d: %s"
+msgstr "Första duplicerade ordet i %s rad %d: %s"
+
+#, c-format
+msgid "%d duplicate word(s) in %s"
+msgstr "%d duplicerade ord i %s"
+
+#, c-format
+msgid "Ignored %d word(s) with non-ASCII characters in %s"
+msgstr "Ignorerade %d ord med icke-ASCII tecken i %s"
+
+#, c-format
+msgid "Reading word file %s..."
+msgstr "Läser ordfil %s..."
+
+#, c-format
+msgid "Duplicate /encoding= line ignored in %s line %d: %s"
+msgstr "Duplicerad /encoding=-rad ignorerad i %s rad %d: %s"
+
+#, c-format
+msgid "/encoding= line after word ignored in %s line %d: %s"
+msgstr "/encoding=-rad efter ord ignorerad i %s rad %d: %s"
+
+#, c-format
+msgid "Duplicate /regions= line ignored in %s line %d: %s"
+msgstr "Duplicerad /regions=-rad ignorerad i %s rad %d: %s"
+
+#, c-format
+msgid "Too many regions in %s line %d: %s"
+msgstr "För många regioner i %s rad %d: %s"
+
+#, c-format
+msgid "/ line ignored in %s line %d: %s"
+msgstr "/-rad ignorerad i %s rad %d: %s"
+
+#, c-format
+msgid "Invalid region nr in %s line %d: %s"
+msgstr "Ogiltigt regionsnr i %s rad %d: %s"
+
+#, c-format
+msgid "Unrecognized flags in %s line %d: %s"
+msgstr "Okända flaggot i %s rad %d: %s"
+
+#, c-format
+msgid "Ignored %d words with non-ASCII characters"
+msgstr "Ignorerade %d ord med icke-ASCII tecken"
+
+#, c-format
+msgid "Compressed %d of %d nodes; %d (%d%%) remaining"
+msgstr "Komprimerade %d av %d noder; %d (%d%%) återstår"
+
+msgid "Reading back spell file..."
+msgstr "Läser tillbaka stavningsfil..."
+
+#.
+#. * Go through the trie of good words, soundfold each word and add it to
+#. * the soundfold trie.
+#.
+msgid "Performing soundfolding..."
+msgstr "Utför ljudvikning..."
+
+#, c-format
+msgid "Number of words after soundfolding: %ld"
+msgstr "Antal ord efter ljudvikning: %ld"
+
+#, c-format
+msgid "Total number of words: %d"
+msgstr "Totalt antal ord: %d"
+
+#, c-format
+msgid "Writing suggestion file %s..."
+msgstr "Skriver förslagsfil %s..."
+
+#, c-format
+msgid "Estimated runtime memory use: %d bytes"
+msgstr "Beräknat körtidsminne använt: %d byte"
+
+msgid "E751: Output file name must not have region name"
+msgstr "E751: Utmatningsfilnamn får inte ha regionnamn"
+
+msgid "E754: Only up to 8 regions supported"
+msgstr "E754: Bara upp till 8 regioner stöds"
+
+#, c-format
+msgid "E755: Invalid region in %s"
+msgstr "E755: Ogiltig region i %s"
+
+msgid "Warning: both compounding and NOBREAK specified"
+msgstr "Varning: både sammansättning och NOBREAK specifierad"
+
+#, c-format
+msgid "Writing spell file %s..."
+msgstr "Skriver stavningsfil %s..."
+
+msgid "Done!"
+msgstr "Klar!"
+
+#, c-format
+msgid "E765: 'spellfile' does not have %ld entries"
+msgstr "E765: 'spellfile' har inte %ld poster"
+
+#, c-format
+msgid "Word removed from %s"
+msgstr "Ord borttaget från %s"
+
+#, c-format
+msgid "Word added to %s"
+msgstr "Ord lagd till %s"
+
+msgid "E763: Word characters differ between spell files"
+msgstr "E763: Ordtecken skiljer sig mellan stavningsfiler"
+
+msgid "Sorry, no suggestions"
+msgstr "Tyvärr, inga föreslag"
+
+#, c-format
+msgid "Sorry, only %ld suggestions"
+msgstr "Tyvärr, bara %ld föreslag"
+
+#. for when 'cmdheight' > 1
+#. avoid more prompt
+#, c-format
+msgid "Change \"%.*s\" to:"
+msgstr "Ändra \"%.*s\" till:"
+
+#, c-format
+msgid " < \"%.*s\""
+msgstr " < \"%.*s\""
+
+msgid "E752: No previous spell replacement"
+msgstr "E752: Ingen tidigare stavningsersättning"
+
+#, c-format
+msgid "E753: Not found: %s"
+msgstr "E753: Hittades inte: %s"
+
+#, c-format
+msgid "E778: This does not look like a .sug file: %s"
+msgstr "E778: Det här ser inte ut som en .sug-fil: %s"
+
+#, c-format
+msgid "E779: Old .sug file, needs to be updated: %s"
+msgstr "E779: Gammal .sug-fil, behöver bli uppdaterad: %s"
+
+#, c-format
+msgid "E780: .sug file is for newer version of Vim: %s"
+msgstr "E780: .sug-fil är för nyare version av Vim: %s"
+
+#, c-format
+msgid "E781: .sug file doesn't match .spl file: %s"
+msgstr "E781: .sug-fil matchar inte .spl-fil: %s"
+
+#, c-format
+msgid "E782: error while reading .sug file: %s"
+msgstr "E782: fel vid läsning av .sug-fil: %s"
+
+#. This should have been checked when generating the .spl
+#. * file.
+msgid "E783: duplicate char in MAP entry"
+msgstr "E783: dubblerat tecken i MAP-post"
+
+#, c-format
+msgid "E390: Illegal argument: %s"
+msgstr "E390: Otillåtet argument: %s"
+
+#, c-format
+msgid "E391: No such syntax cluster: %s"
+msgstr "E391: Inget sådant syntax-kluster: %s"
+
+msgid "No Syntax items defined for this buffer"
+msgstr "Inga syntax-föremål definierade för den här bufferten"
+
+msgid "syncing on C-style comments"
+msgstr "synkning av C-stil-kommentarer"
+
+msgid "no syncing"
+msgstr "ingen synkning"
+
+msgid "syncing starts "
+msgstr "synkning startar"
+
+msgid " lines before top line"
+msgstr " rader före topprad"
+
+msgid ""
+"\n"
+"--- Syntax sync items ---"
+msgstr ""
+"\n"
+"--- Syntax-synkföremål ---"
+
+msgid ""
+"\n"
+"syncing on items"
+msgstr ""
+"\n"
+"synkning av föremål"
+
+msgid ""
+"\n"
+"--- Syntax items ---"
+msgstr ""
+"\n"
+"--- Syntax föremål ---"
+
+#, c-format
+msgid "E392: No such syntax cluster: %s"
+msgstr "E392: Inga sådana syntaxkluster: %s"
+
+msgid "minimal "
+msgstr "minimal "
+
+msgid "maximal "
+msgstr "maximal "
+
+msgid "; match "
+msgstr "; träff "
+
+msgid " line breaks"
+msgstr " radbrytningar"
+
+msgid "E395: contains argument not accepted here"
+msgstr "E395: innehåller argument som inte är tillåtna här"
+
+msgid "E396: containedin argument not accepted here"
+msgstr "E396: innehöll argument som inte är tillåtna här"
+
+msgid "E393: group[t]here not accepted here"
+msgstr "E393: grupper inte tillåtna här"
+
+#, c-format
+msgid "E394: Didn't find region item for %s"
+msgstr "E394: Hittade inte regionföremål för %s"
+
+msgid "E397: Filename required"
+msgstr "E397: Filnamn krävs"
+
+#, c-format
+msgid "E789: Missing ']': %s"
+msgstr "E789: Saknar ']': %s"
+
+#, c-format
+msgid "E398: Missing '=': %s"
+msgstr "E398: Saknar '=': %s"
+
+#, c-format
+msgid "E399: Not enough arguments: syntax region %s"
+msgstr "E399: Inte tillräckliga argument: syntaxregion %s"
+
+msgid "E400: No cluster specified"
+msgstr "E400: Inget kluster angivet"
+
+#, c-format
+msgid "E401: Pattern delimiter not found: %s"
+msgstr "E401: Mönsteravgränsare hittades inte: %s"
+
+#, c-format
+msgid "E402: Garbage after pattern: %s"
+msgstr "E402: Skräp efter mönster: %s"
+
+msgid "E403: syntax sync: line continuations pattern specified twice"
+msgstr "E403: syntax-synk: radfortsättningsmönster angivet två gånger"
+
+#, c-format
+msgid "E404: Illegal arguments: %s"
+msgstr "E404: Otillåtna argument: %s"
+
+#, c-format
+msgid "E405: Missing equal sign: %s"
+msgstr "E405: Saknar likamed-tecken: %s"
+
+#, c-format
+msgid "E406: Empty argument: %s"
+msgstr "E406: Tomt argument: %s"
+
+#, c-format
+msgid "E407: %s not allowed here"
+msgstr "E407: %s inte tillåtet här"
+
+#, c-format
+msgid "E408: %s must be first in contains list"
+msgstr "E408: %s måste vara först i innehållslista"
+
+#, c-format
+msgid "E409: Unknown group name: %s"
+msgstr "E409: Okänt gruppnamn: %s"
+
+#, c-format
+msgid "E410: Invalid :syntax subcommand: %s"
+msgstr "E410: Ogiltigt :syntax-underkommando: %s"
+
+msgid "E679: recursive loop loading syncolor.vim"
+msgstr "E679: rekursiv loop laddar syncolor.vim"
+
+#, c-format
+msgid "E411: highlight group not found: %s"
+msgstr "E411: framhävningsgrupp hittades inte: %s"
+
+#, c-format
+msgid "E412: Not enough arguments: \":highlight link %s\""
+msgstr "E412: Inte tillräckliga argument: \":highlight länk %s\""
+
+#, c-format
+msgid "E413: Too many arguments: \":highlight link %s\""
+msgstr "E413: För många argument: \":highlight länk %s\""
+
+msgid "E414: group has settings, highlight link ignored"
+msgstr "E414: grupp har inställningar, framhävningslänk ignorerad"
+
+#, c-format
+msgid "E415: unexpected equal sign: %s"
+msgstr "E415: oväntat likamed-tecken: %s"
+
+#, c-format
+msgid "E416: missing equal sign: %s"
+msgstr "E416: saknar likamed-tecken: %s"
+
+#, c-format
+msgid "E417: missing argument: %s"
+msgstr "E417: saknar argument: %s"
+
+#, c-format
+msgid "E418: Illegal value: %s"
+msgstr "E418: Otillåtet värde: %s"
+
+msgid "E419: FG color unknown"
+msgstr "E419: FG-färg okänd"
+
+msgid "E420: BG color unknown"
+msgstr "E420: BG-färg okänd"
+
+#, c-format
+msgid "E421: Color name or number not recognized: %s"
+msgstr "E421: Färgnamn eller nummer inte igenkänt: %s"
+
+#, c-format
+msgid "E422: terminal code too long: %s"
+msgstr "E422: terminalkod för lång: %s"
+
+#, c-format
+msgid "E423: Illegal argument: %s"
+msgstr "E423: Otillåtet argument: %s"
+
+msgid "E424: Too many different highlighting attributes in use"
+msgstr "E424: För många olika framhävningsattribut i användning"
+
+msgid "E669: Unprintable character in group name"
+msgstr "E669: Outskrivbart tecken i gruppnamn"
+
+msgid "W18: Invalid character in group name"
+msgstr "W18: Ogiltigt tecken i gruppnamn"
+
+msgid "E555: at bottom of tag stack"
+msgstr "E555: på botten av taggstack"
+
+msgid "E556: at top of tag stack"
+msgstr "E556: på toppen av taggstack"
+
+msgid "E425: Cannot go before first matching tag"
+msgstr "E425: Kan inte gå före första matchande tagg"
+
+#, c-format
+msgid "E426: tag not found: %s"
+msgstr "E426: tagg hittades inte: %s"
+
+msgid " # pri kind tag"
+msgstr " # pri-typ-tagg"
+
+msgid "file\n"
+msgstr "fil\n"
+
+msgid "E427: There is only one matching tag"
+msgstr "E427: Det finns bara en matchande tagg"
+
+msgid "E428: Cannot go beyond last matching tag"
+msgstr "E428: Kan inte gå bortom sista matchande tagg"
+
+#, c-format
+msgid "File \"%s\" does not exist"
+msgstr "Fil \"%s\" existerar inte"
+
+#. Give an indication of the number of matching tags
+#, c-format
+msgid "tag %d of %d%s"
+msgstr "tagg %d av %d%s"
+
+msgid " or more"
+msgstr " eller fler"
+
+msgid " Using tag with different case!"
+msgstr " Använder tagg med annan storlek!"
+
+#, c-format
+msgid "E429: File \"%s\" does not exist"
+msgstr "E429: Fil \"%s\" existerar inte"
+
+#. Highlight title
+msgid ""
+"\n"
+" # TO tag FROM line in file/text"
+msgstr ""
+"\n"
+" # TILL tagg FRÅN LINJE i fil/text"
+
+#, c-format
+msgid "Searching tags file %s"
+msgstr "Söker tagg-fil %s"
+
+#, c-format
+msgid "E430: Tag file path truncated for %s\n"
+msgstr "E430: Taggfilsökväg trunkerades för %s\n"
+
+#, c-format
+msgid "E431: Format error in tags file \"%s\""
+msgstr "E431: Formateringsfel i tagg-fil \"%s\""
+
+#, c-format
+msgid "Before byte %ld"
+msgstr "Före byte %ld"
+
+#, c-format
+msgid "E432: Tags file not sorted: %s"
+msgstr "E432: Tagg-fil inte sorterad: %s"
+
+#. never opened any tags file
+msgid "E433: No tags file"
+msgstr "E433: Ingen tagg-fil"
+
+msgid "E434: Can't find tag pattern"
+msgstr "E434: Kan inte hitta taggmönster"
+
+msgid "E435: Couldn't find tag, just guessing!"
+msgstr "E435: Kunde inte hitta tagg, gissar bara!"
+
+msgid "' not known. Available builtin terminals are:"
+msgstr "' inte känd. Tillgängliga inbyggda terminaler är:"
+
+msgid "defaulting to '"
+msgstr "använder standard '"
+
+msgid "E557: Cannot open termcap file"
+msgstr "E557: Kan inte öppna termcap-fil"
+
+msgid "E558: Terminal entry not found in terminfo"
+msgstr "E558: Terminalnotering hittades inte i terminfo"
+
+msgid "E559: Terminal entry not found in termcap"
+msgstr "E559: Terminalnotering hittades inte i termcap"
+
+#, c-format
+msgid "E436: No \"%s\" entry in termcap"
+msgstr "E436: Ingen \"%s\"-notering i termcap"
+
+msgid "E437: terminal capability \"cm\" required"
+msgstr "E437: terminalkapacitet \"cm\" krävs"
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Terminal keys ---"
+msgstr ""
+"\n"
+"--- Terminalnycklar ---"
+
+msgid "new shell started\n"
+msgstr "nytt skal startat\n"
+
+msgid "Vim: Error reading input, exiting...\n"
+msgstr "Vim: Fel vid läsning av inmatning, avslutar...\n"
+
+#. must display the prompt
+msgid "No undo possible; continue anyway"
+msgstr "Ingen ångring möjlig; fortsätter ändå"
+
+msgid "Already at oldest change"
+msgstr "Redan vid äldsta ändring"
+
+msgid "Already at newest change"
+msgstr "Redan vid nyaste ändring"
+
+#, c-format
+msgid "Undo number %ld not found"
+msgstr "Ångra-nummer %ld hittades inte"
+
+msgid "E438: u_undo: line numbers wrong"
+msgstr "E438: u_undo: radnummer fel"
+
+msgid "more line"
+msgstr "en rad till"
+
+msgid "more lines"
+msgstr "fler rader"
+
+msgid "line less"
+msgstr "en rad mindre"
+
+msgid "fewer lines"
+msgstr "färre rader"
+
+msgid "change"
+msgstr "ändring"
+
+msgid "changes"
+msgstr "ändringar"
+
+#, c-format
+msgid "%ld %s; %s #%ld %s"
+msgstr "%ld %s; %s #%ld %s"
+
+msgid "before"
+msgstr "före"
+
+msgid "after"
+msgstr "efter"
+
+msgid "Nothing to undo"
+msgstr "Inget att ångra"
+
+msgid "number changes time"
+msgstr "antal ändringar tid"
+
+#, c-format
+msgid "%ld seconds ago"
+msgstr "%ld sekunder sedan"
+
+msgid "E790: undojoin is not allowed after undo"
+msgstr "E790: undojoin är inte tillåtet efter undo"
+
+msgid "E439: undo list corrupt"
+msgstr "E439: ångra-lista trasig"
+
+msgid "E440: undo line missing"
+msgstr "E440: ångra-rad saknas"
+
+#. Only MS VC 4.1 and earlier can do Win32s
+msgid ""
+"\n"
+"MS-Windows 16/32-bit GUI version"
+msgstr ""
+"\n"
+"MS-Windows 16/32-bitars GUI-version"
+
+msgid ""
+"\n"
+"MS-Windows 64-bit GUI version"
+msgstr ""
+"\n"
+"MS-Windows 64-bitars GUI-version"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit GUI version"
+msgstr ""
+"\n"
+"MS-Windows 32-bitars GUI-version"
+
+msgid " in Win32s mode"
+msgstr " i Win32s-läge"
+
+msgid " with OLE support"
+msgstr " med OLE-stöd"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit console version"
+msgstr ""
+"\n"
+"MS-Windows 32-bitars konsollversion"
+
+msgid ""
+"\n"
+"MS-Windows 16-bit version"
+msgstr ""
+"\n"
+"MS-Windows 16-bitars version"
+
+msgid ""
+"\n"
+"32-bit MS-DOS version"
+msgstr ""
+"\n"
+"32-bitars MS-DOS-version"
+
+msgid ""
+"\n"
+"16-bit MS-DOS version"
+msgstr ""
+"\n"
+"16-bitars MS-DOS-version"
+
+msgid ""
+"\n"
+"MacOS X (unix) version"
+msgstr ""
+"\n"
+"MacOS X-version (unix)"
+
+msgid ""
+"\n"
+"MacOS X version"
+msgstr ""
+"\n"
+"MacOS X-version"
+
+msgid ""
+"\n"
+"MacOS version"
+msgstr ""
+"\n"
+"MacOS-version"
+
+msgid ""
+"\n"
+"RISC OS version"
+msgstr ""
+"\n"
+"RISC OS-version"
+
+msgid ""
+"\n"
+"Included patches: "
+msgstr ""
+"\n"
+"Inkluderade patchar: "
+
+msgid "Modified by "
+msgstr "Modifierad av "
+
+msgid ""
+"\n"
+"Compiled "
+msgstr ""
+"\n"
+"Kompilerad "
+
+msgid "by "
+msgstr "av "
+
+msgid ""
+"\n"
+"Huge version "
+msgstr ""
+"\n"
+"Enorm version "
+
+msgid ""
+"\n"
+"Big version "
+msgstr ""
+"\n"
+"Stor version "
+
+msgid ""
+"\n"
+"Normal version "
+msgstr ""
+"\n"
+"Normal version "
+
+msgid ""
+"\n"
+"Small version "
+msgstr ""
+"\n"
+"Liten version "
+
+msgid ""
+"\n"
+"Tiny version "
+msgstr ""
+"\n"
+"Jätteliten version "
+
+msgid "without GUI."
+msgstr "utan GUI."
+
+msgid "with GTK2-GNOME GUI."
+msgstr "med GTK2-GNOME-GUI."
+
+msgid "with GTK-GNOME GUI."
+msgstr "med GTK-GNOME-GUI."
+
+msgid "with GTK2 GUI."
+msgstr "med GTK2-GUI."
+
+msgid "with GTK GUI."
+msgstr "med GTK-GUI."
+
+msgid "with X11-Motif GUI."
+msgstr "med X11-Motif-GUI."
+
+msgid "with X11-neXtaw GUI."
+msgstr "med X11-neXtaw-GUI."
+
+msgid "with X11-Athena GUI."
+msgstr "med X11-Athena-GUI."
+
+msgid "with Photon GUI."
+msgstr "med Photon-GUI."
+
+msgid "with GUI."
+msgstr "med GUI."
+
+msgid "with Carbon GUI."
+msgstr "med Carbon-GUI."
+
+msgid "with Cocoa GUI."
+msgstr "med Cocoa-GUI."
+
+msgid "with (classic) GUI."
+msgstr "med (klassiskt) GUI."
+
+msgid " Features included (+) or not (-):\n"
+msgstr " Funktioner inkluderade (+) eller inte (-):\n"
+
+msgid " system vimrc file: \""
+msgstr " system-vimrc-fil: \""
+
+msgid " user vimrc file: \""
+msgstr " användar-vimrc-fil: \""
+
+msgid " 2nd user vimrc file: \""
+msgstr " Andra användar-vimrc-fil: \""
+
+msgid " 3rd user vimrc file: \""
+msgstr " Tredje användar-vimrc-fil: \""
+
+msgid " user exrc file: \""
+msgstr " användar-exrc-fil: \""
+
+msgid " 2nd user exrc file: \""
+msgstr " Andra användar-exrc-fil: \""
+
+msgid " system gvimrc file: \""
+msgstr " system-gvimrc-fil: \""
+
+msgid " user gvimrc file: \""
+msgstr " användar-gvimrc-fil: \""
+
+msgid "2nd user gvimrc file: \""
+msgstr "Andra användar-gvimrc-fil: \""
+
+msgid "3rd user gvimrc file: \""
+msgstr "Tredje användar-gvimrc-fil: \""
+
+msgid " system menu file: \""
+msgstr " systemmenyfil: \""
+
+msgid " fall-back for $VIM: \""
+msgstr " reserv för $VIM: \""
+
+msgid " f-b for $VIMRUNTIME: \""
+msgstr " reserv för $VIMRUNTIME: \""
+
+msgid "Compilation: "
+msgstr "Kompilering: "
+
+msgid "Compiler: "
+msgstr "Kompilator: "
+
+msgid "Linking: "
+msgstr "Länkning: "
+
+msgid " DEBUG BUILD"
+msgstr " FELSÖKNINGSBYGGD"
+
+msgid "VIM - Vi IMproved"
+msgstr "VIM - Vi IMproved"
+
+msgid "version "
+msgstr "version "
+
+msgid "by Bram Moolenaar et al."
+msgstr "av Bram Moolenaar m.fl."
+
+msgid "Vim is open source and freely distributable"
+msgstr "Vim är öppen källkod och fri att distribuera"
+
+msgid "Help poor children in Uganda!"
+msgstr "Hjälp fattiga barn i Uganda!"
+
+msgid "type :help iccf<Enter> for information "
+msgstr "skriv :help iccf<Enter> för information "
+
+msgid "type :q<Enter> to exit "
+msgstr "skriv :q<Enter> för att avsluta "
+
+msgid "type :help<Enter> or <F1> for on-line help"
+msgstr "skriv :help<Enter> eller <F1> för online-hjälp "
+
+msgid "type :help version8<Enter> for version info"
+msgstr "skriv :help version8<Enter> för versioninformation "
+
+msgid "Running in Vi compatible mode"
+msgstr "Kör i Vi-kompatibelt läge"
+
+msgid "type :set nocp<Enter> for Vim defaults"
+msgstr "skriv :set nocp<Enter> för Vim- standarder "
+
+msgid "type :help cp-default<Enter> for info on this"
+msgstr "skriv :help cp-default<Enter> för information om det här"
+
+msgid "menu Help->Orphans for information "
+msgstr "meny Hjälp->Föräldralösa för information "
+
+msgid "Running modeless, typed text is inserted"
+msgstr "Kör lägeslöst, skriven text blir infogad"
+
+msgid "menu Edit->Global Settings->Toggle Insert Mode "
+msgstr "meny Redigera->Globala inställningar->Växla infogningsläge "
+
+msgid " for two modes "
+msgstr " för två lägen "
+
+msgid "menu Edit->Global Settings->Toggle Vi Compatible"
+msgstr "meny Redigera->Globala Inställningar->Växla Vi Komptaibel"
+
+msgid " for Vim defaults "
+msgstr " för vim-standardalternativ "
+
+msgid "Sponsor Vim development!"
+msgstr "Stöd utvecklingen av Vim!"
+
+msgid "Become a registered Vim user!"
+msgstr "Bli en registrerad Vim-användare!"
+
+msgid "type :help sponsor<Enter> for information "
+msgstr "skriv :help sponsor<Enter> för information "
+
+msgid "type :help register<Enter> for information "
+msgstr "skriv :help register<Enter> för information "
+
+msgid "menu Help->Sponsor/Register for information "
+msgstr "meny Hjälp->Stöd/Registrera för information "
+
+msgid "WARNING: Windows 95/98/ME detected"
+msgstr "VARNING: Windows 95/98/ME upptäckt"
+
+msgid "type :help windows95<Enter> for info on this"
+msgstr "skriv :help windows95<Enter> för info om det här"
+
+msgid "Already only one window"
+msgstr "Redan bara ett fönster"
+
+msgid "E441: There is no preview window"
+msgstr "E441: Det finns inget förhandsvisningsfönster"
+
+msgid "E442: Can't split topleft and botright at the same time"
+msgstr "E442: Kan inte dela toppvänster och bottenhöger samtidigt"
+
+msgid "E443: Cannot rotate when another window is split"
+msgstr "E443: Kan inte rotera när ett annat fönster är delat"
+
+msgid "E444: Cannot close last window"
+msgstr "E444: Kan inte stänga senaste fönstret"
+
+msgid "E445: Other window contains changes"
+msgstr "E445: Andra fönster innehåller ändringar"
+
+msgid "E446: No file name under cursor"
+msgstr "E446: Inget filnamn under markör"
+
+#, c-format
+msgid "E447: Can't find file \"%s\" in path"
+msgstr "E447: Kan inte hitta fil \"%s\" i sökväg"
+
+#, c-format
+msgid "E370: Could not load library %s"
+msgstr "E370: Kunde inte läsa in bibliotek %s"
+
+msgid "Sorry, this command is disabled: the Perl library could not be loaded."
+msgstr ""
+"Tyvärr, det här kommandot är inaktiverat: Perl-biblioteket kunde inte läsas "
+"in."
+
+msgid "E299: Perl evaluation forbidden in sandbox without the Safe module"
+msgstr "E299: Perl-evaluering förbjuden i sandlåda utan Safe-modulen"
+
+msgid "Edit with &multiple Vims"
+msgstr "Redigera med &flera Vims"
+
+msgid "Edit with single &Vim"
+msgstr "Redigera med en &Vim"
+
+msgid "Diff with Vim"
+msgstr "Diff med Vim"
+
+msgid "Edit with &Vim"
+msgstr "Redigera med &Vim"
+
+#. Now concatenate
+msgid "Edit with existing Vim - "
+msgstr "Redigera med befintlig Vim - "
+
+msgid "Edits the selected file(s) with Vim"
+msgstr "Redigerar markerade fil(erna) med Vim"
+
+msgid "Error creating process: Check if gvim is in your path!"
+msgstr "Felskapande process: Kontrollera om gvim är i din sökväg!"
+
+msgid "gvimext.dll error"
+msgstr "gvimext.dll-fel"
+
+msgid "Path length too long!"
+msgstr "Sökvägslängd för lång!"
+
+msgid "--No lines in buffer--"
+msgstr "--Inga rader i buffert--"
+
+#.
+#. * The error messages that can be shared are included here.
+#. * Excluded are errors that are only used once and debugging messages.
+#.
+msgid "E470: Command aborted"
+msgstr "E470: Kommando avbrutet"
+
+msgid "E471: Argument required"
+msgstr "E471: Argument krävs"
+
+msgid "E10: \\ should be followed by /, ? or &"
+msgstr "E10: \\ borde följas av /, ? eller &"
+
+msgid "E11: Invalid in command-line window; <CR> executes, CTRL-C quits"
+msgstr "E11: Felaktighet i kommandoradsfönster; <CR> kör, CTRL-C avslutar"
+
+msgid "E12: Command not allowed from exrc/vimrc in current dir or tag search"
+msgstr ""
+"E12: Kommando inte tillåtet från exrc/vimrc i aktuell katalog eller "
+"taggsökning"
+
+msgid "E171: Missing :endif"
+msgstr "E171: Saknar :endif"
+
+msgid "E600: Missing :endtry"
+msgstr "E600: Saknar :endtry"
+
+msgid "E170: Missing :endwhile"
+msgstr "E170: Saknar :endwhile"
+
+msgid "E170: Missing :endfor"
+msgstr "E170: Saknar :endfor"
+
+msgid "E588: :endwhile without :while"
+msgstr "E588: :endwhile utan :while"
+
+msgid "E588: :endfor without :for"
+msgstr "E588: :endfor utan :for"
+
+msgid "E13: File exists (add ! to override)"
+msgstr "E13: Fil existerar (lägg till ! för att tvinga)"
+
+msgid "E472: Command failed"
+msgstr "E472: Kommando misslyckades"
+
+#, c-format
+msgid "E234: Unknown fontset: %s"
+msgstr "E234: Okänd typsnittsuppsättning: %s"
+
+#, c-format
+msgid "E235: Unknown font: %s"
+msgstr "E235: Okänt typsnitt: %s"
+
+#, c-format
+msgid "E236: Font \"%s\" is not fixed-width"
+msgstr "E236: Typsnitt \"%s\" är inte bredd-fixerad"
+
+msgid "E473: Internal error"
+msgstr "E473: Internt fel"
+
+msgid "Interrupted"
+msgstr "Avbruten"
+
+msgid "E14: Invalid address"
+msgstr "E14: Ogiltig address"
+
+msgid "E474: Invalid argument"
+msgstr "E474: Ogiltigt argument"
+
+#, c-format
+msgid "E475: Invalid argument: %s"
+msgstr "E475: Ogiltigt argument: %s"
+
+#, c-format
+msgid "E15: Invalid expression: %s"
+msgstr "E15: Ogiltigt uttryck: %s"
+
+msgid "E16: Invalid range"
+msgstr "E16: Ogiltigt område"
+
+msgid "E476: Invalid command"
+msgstr "E476: Ogiltigt kommando"
+
+#, c-format
+msgid "E17: \"%s\" is a directory"
+msgstr "E17: \"%s\" är en katalog"
+
+#, c-format
+msgid "E364: Library call failed for \"%s()\""
+msgstr "E364: Biblioteksanrop misslyckades för \"%s()\""
+
+#, c-format
+msgid "E448: Could not load library function %s"
+msgstr "E448: Kunde inte läsa in biblioteksfunktion %s"
+
+msgid "E19: Mark has invalid line number"
+msgstr "E19: Markering har ogiltigt radnummer"
+
+msgid "E20: Mark not set"
+msgstr "E20: Markering inte satt"
+
+msgid "E21: Cannot make changes, 'modifiable' is off"
+msgstr "E21: Kan inte göra ändringar, 'modifiable' är av"
+
+msgid "E22: Scripts nested too deep"
+msgstr "E22: Skript nästlade för djupt"
+
+msgid "E23: No alternate file"
+msgstr "E23: Ingen alternativ fil"
+
+msgid "E24: No such abbreviation"
+msgstr "E24: Ingen sådan förkortning"
+
+msgid "E477: No ! allowed"
+msgstr "E477: Inget ! tillåtet"
+
+msgid "E25: GUI cannot be used: Not enabled at compile time"
+msgstr "E25: GUI kan inte användas: Inte aktiverat vid kompilering"
+
+msgid "E26: Hebrew cannot be used: Not enabled at compile time\n"
+msgstr "E26: Hebreiska kan inte användas: Inte aktiverat vid kompilering\n"
+
+msgid "E27: Farsi cannot be used: Not enabled at compile time\n"
+msgstr "E27: Persiska kan inte användas: Inte aktiverat vid kompilering\n"
+
+msgid "E800: Arabic cannot be used: Not enabled at compile time\n"
+msgstr "E800: Arabiska kan inte användas: Inte aktiverat vid kompilering\n"
+
+#, c-format
+msgid "E28: No such highlight group name: %s"
+msgstr "E28: Inget sådant framhävningsgruppnamn: %s"
+
+msgid "E29: No inserted text yet"
+msgstr "E29: Ingen infogad text än"
+
+msgid "E30: No previous command line"
+msgstr "E30: Ingen tidigare kommandorad"
+
+msgid "E31: No such mapping"
+msgstr "E31: Ingen sådan mappning"
+
+msgid "E479: No match"
+msgstr "E479: Ingen träff"
+
+#, c-format
+msgid "E480: No match: %s"
+msgstr "E480: Ingen träff: %s"
+
+msgid "E32: No file name"
+msgstr "E32: Inget filnamn"
+
+msgid "E33: No previous substitute regular expression"
+msgstr "E33: Inget tidigare utbytningsreguljäruttryck"
+
+msgid "E34: No previous command"
+msgstr "E34: Inget tidigare kommando"
+
+msgid "E35: No previous regular expression"
+msgstr "E35: Inget tidigare reguljärt uttryck"
+
+msgid "E481: No range allowed"
+msgstr "E481: Inget område tillåtet"
+
+msgid "E36: Not enough room"
+msgstr "E36: Inte tillräckligt med utrymme"
+
+#, c-format
+msgid "E247: no registered server named \"%s\""
+msgstr "E247: ingen registrerad server med namnet \"%s\""
+
+#, c-format
+msgid "E482: Can't create file %s"
+msgstr "E482: Kan inte skapa fil %s"
+
+msgid "E483: Can't get temp file name"
+msgstr "E483: Kan inte hämta temporärt filnamn"
+
+#, c-format
+msgid "E484: Can't open file %s"
+msgstr "E484: Kan inte öppna fil %s"
+
+#, c-format
+msgid "E485: Can't read file %s"
+msgstr "E485: Kan inte läsa fil %s"
+
+msgid "E37: No write since last change (add ! to override)"
+msgstr ""
+"E37: Ingen skrivning sedan senaste ändring (lägg till ! för att tvinga)"
+
+msgid "E38: Null argument"
+msgstr "E38: Null-argument"
+
+msgid "E39: Number expected"
+msgstr "E39: Nummer väntat"
+
+#, c-format
+msgid "E40: Can't open errorfile %s"
+msgstr "E40: Kan inte öppna felfil %s"
+
+msgid "E233: cannot open display"
+msgstr "E233: kan inte öppna display"
+
+msgid "E41: Out of memory!"
+msgstr "E41: Slut på minne!"
+
+msgid "Pattern not found"
+msgstr "Mönster hittades inte"
+
+#, c-format
+msgid "E486: Pattern not found: %s"
+msgstr "E486: Mönster hittades inte: %s"
+
+msgid "E487: Argument must be positive"
+msgstr "E487: Argument måste vara positivt"
+
+msgid "E459: Cannot go back to previous directory"
+msgstr "E459: Kan inte gå tillbaka till tidigare katalog"
+
+msgid "E42: No Errors"
+msgstr "E42: Inga fel"
+
+msgid "E776: No location list"
+msgstr "E776: Ingen positionslista"
+
+msgid "E43: Damaged match string"
+msgstr "E43: Skadad träffsträng"
+
+msgid "E44: Corrupted regexp program"
+msgstr "E44: Trasigt program för reguljära uttryck"
+
+msgid "E45: 'readonly' option is set (add ! to override)"
+msgstr "E45: 'readonly' flagga är satt (lägg till ! för att tvinga)"
+
+#, c-format
+msgid "E46: Cannot change read-only variable \"%s\""
+msgstr "E46: Kan inte ändra skrivskyddad variabel \"%s\""
+
+#, c-format
+msgid "E794: Cannot set variable in the sandbox: \"%s\""
+msgstr "E794: Kan inte sätta variabel i sandlådan: \"%s\""
+
+msgid "E47: Error while reading errorfile"
+msgstr "E47: Fel vid läsning av felfil"
+
+msgid "E48: Not allowed in sandbox"
+msgstr "E48: Inte tillåtet i sandlåda"
+
+msgid "E523: Not allowed here"
+msgstr "E523: Inte tillåtet här"
+
+msgid "E359: Screen mode setting not supported"
+msgstr "E359: Skärmläge inställning stöds inte"
+
+msgid "E49: Invalid scroll size"
+msgstr "E49: Ogiltig rullningsstorlek"
+
+msgid "E91: 'shell' option is empty"
+msgstr "E91: 'shell' flagga är tom"
+
+msgid "E255: Couldn't read in sign data!"
+msgstr "E255: Kunde inte läsa in teckendata!"
+
+msgid "E72: Close error on swap file"
+msgstr "E72: Stängningsfel på växlingsfil"
+
+msgid "E73: tag stack empty"
+msgstr "E73: taggstack tom"
+
+msgid "E74: Command too complex"
+msgstr "E74: Kommando för komplext"
+
+msgid "E75: Name too long"
+msgstr "E75: Namn för långt"
+
+msgid "E76: Too many ["
+msgstr "E76: För många ["
+
+msgid "E77: Too many file names"
+msgstr "E77: För många filnamn"
+
+msgid "E488: Trailing characters"
+msgstr "E488: Eftersläpande tecken"
+
+msgid "E78: Unknown mark"
+msgstr "E78: Okänt märke"
+
+msgid "E79: Cannot expand wildcards"
+msgstr "E79: Kan inte expandera jokertecken"
+
+msgid "E591: 'winheight' cannot be smaller than 'winminheight'"
+msgstr "E591: 'winheight' kan inte vara mindre än 'winminheight'"
+
+msgid "E592: 'winwidth' cannot be smaller than 'winminwidth'"
+msgstr "E592: 'winwidth' kan inte vara mindre än 'winminwidth'"
+
+msgid "E80: Error while writing"
+msgstr "E80: Fel vid skrivning"
+
+msgid "Zero count"
+msgstr "Noll-längd"
+
+msgid "E81: Using <SID> not in a script context"
+msgstr "E81: Använder inte <SID> i ett skriptsammanhang"
+
+msgid "E449: Invalid expression received"
+msgstr "E449: Ogiltigt uttryck mottaget"
+
+msgid "E463: Region is guarded, cannot modify"
+msgstr "E463: Region är vaktad, kan inte modifiera"
+
+msgid "E744: NetBeans does not allow changes in read-only files"
+msgstr "E744: NetBeans tillåter inte ändringar i skrivskyddade filer"
+
+#, c-format
+msgid "E685: Internal error: %s"
+msgstr "E685: Internt fel: %s"
+
+msgid "E363: pattern uses more memory than 'maxmempattern'"
+msgstr "E363: mönster använder mer minne än 'maxmempattern'"
+
+msgid "E749: empty buffer"
+msgstr "E749: tom buffert"
+
+msgid "E682: Invalid search pattern or delimiter"
+msgstr "E682: Ogiltigt sökmönster eller delimiter"
+
+msgid "E139: File is loaded in another buffer"
+msgstr "E139: Filen är inläst i en annan buffert"
+
+#, c-format
+msgid "E764: Option '%s' is not set"
+msgstr "E764: Flagga '%s' är inte satt"
+
+msgid "search hit TOP, continuing at BOTTOM"
+msgstr "sökning nådde TOPPEN, fortsätter vid BOTTEN"
+
+msgid "search hit BOTTOM, continuing at TOP"
+msgstr "sökning nådde BOTTEN, forsätter vid TOPPEN"
diff --git a/src/po/uk.cp1251.po b/src/po/uk.cp1251.po
new file mode 100644
index 0000000..a36ec7a
--- /dev/null
+++ b/src/po/uk.cp1251.po
@@ -0,0 +1,7333 @@
+#
+# Ukrainian translation for Vim
+#
+# Generated from uk.po, DO NOT EDIT
+#
+# Copyright (C) 2001 Bohdan Vlasyuk <bohdan@vstu.edu.ua>
+# Bohdan donated this work to be distributed with Vim under the Vim license.
+#
+# Thanks to:
+# Dmytro Kovalov <dmytro.kovalov@nssmb.com> for useful suggestions
+# Dmytro O. Redchuk <dor@kiev-online.net> for viminfo bug
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: vim 8.1\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2018-06-20 06:30+0300\n"
+"PO-Revision-Date: 2010-06-18 21:53+0300\n"
+"Last-Translator: Àíàòîë³é Ñàõí³ê <sakhnik@gmail.com>\n"
+"Language-Team: Ukrainian\n"
+"Language: uk\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=cp1251\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+msgid "E831: bf_key_init() called with empty password"
+msgstr "E831: Âèêëèêàíî bf_key_init() ç ïîðîæí³ì ïàðîëåì"
+
+msgid "E820: sizeof(uint32_t) != 4"
+msgstr "E820: sizeof(uint32_t) != 4"
+
+msgid "E817: Blowfish big/little endian use wrong"
+msgstr "E817: Íåïðàâèëüíå âèêîðèñòàííÿ ïîðÿäêó áàéò³â Blowfish (BE/LE)"
+
+msgid "E818: sha256 test failed"
+msgstr "E818: Íå ïðîéøëà ïåðåâ³ðêà sha256"
+
+msgid "E819: Blowfish test failed"
+msgstr "E819: Íå ïðîéøëà ïåðåâ³ðêà Blowfish"
+
+msgid "[Location List]"
+msgstr "[Ñïèñîê ì³ñöü]"
+
+msgid "[Quickfix List]"
+msgstr "[Ñïèñîê âèïðàâëåíü]"
+
+msgid "E855: Autocommands caused command to abort"
+msgstr "E855: Àâòîêîìàíäè ïðèçâåëè äî ñêàñóâàííÿ êîìàíäè"
+
+msgid "E82: Cannot allocate any buffer, exiting..."
+msgstr "E82: Íåìຠìîæëèâîñò³ ðîçì³ñòèòè õî÷ îäèí áóôåð, çàâåðøåííÿ ðîáîòè..."
+
+msgid "E83: Cannot allocate buffer, using other one..."
+msgstr "E83: Íåìຠìîæëèâîñò³ ðîçì³ñòèòè áóôåð, áóäå âèêîðèñòàíî ³íøèé..."
+
+msgid "E931: Buffer cannot be registered"
+msgstr "E931: Íåìîæëèâî çàðåºñòðóâàòè áóôåð"
+
+msgid "E937: Attempt to delete a buffer that is in use"
+msgstr "E937: Ñïðîáà âèäàëèòè áóôåð, ùî âèêîðèñòîâóºòüñÿ"
+
+msgid "E515: No buffers were unloaded"
+msgstr "E515: Æîäåí ç áóôåð³â íå áóâ âèâàíòàæåíèé"
+
+msgid "E516: No buffers were deleted"
+msgstr "E516: Æîäåí ç áóôåð³â íå çíèùåíî"
+
+msgid "E517: No buffers were wiped out"
+msgstr "E517: Æîäåí ç áóôåð³â íå âèòåðòî"
+
+msgid "1 buffer unloaded"
+msgstr "Âèâàíòàæåíî îäèí áóôåð"
+
+#, c-format
+msgid "%d buffers unloaded"
+msgstr "Âèâàíòàæåíî %d áóôåðè(³â)"
+
+msgid "1 buffer deleted"
+msgstr "Çíèùåíî îäèí áóôåð"
+
+#, c-format
+msgid "%d buffers deleted"
+msgstr "Çíèùåíî %d áóôåðè(³â)"
+
+msgid "1 buffer wiped out"
+msgstr "Âèòåðòî îäèí áóôåð"
+
+#, c-format
+msgid "%d buffers wiped out"
+msgstr "Âèòåðòî %d áóôåðè(³â)"
+
+msgid "E90: Cannot unload last buffer"
+msgstr "E90: Íå ìîæó âèâàíòàæèòè îñòàíí³é áóôåð"
+
+msgid "E84: No modified buffer found"
+msgstr "E84: Æîäåí áóôåð íå çì³íåíî"
+
+msgid "E85: There is no listed buffer"
+msgstr "E85: Ó ñïèñêó íåìຠáóôåð³â"
+
+msgid "E87: Cannot go beyond last buffer"
+msgstr "E87: Öå âæå îñòàíí³é áóôåð"
+
+msgid "E88: Cannot go before first buffer"
+msgstr "E88: Öå âæå íàéïåðøèé áóôåð"
+
+#, c-format
+msgid "E89: No write since last change for buffer %ld (add ! to override)"
+msgstr "E89: Áóôåð %ld ìຠçì³íè (! ùîá íå çâàæàòè)"
+
+msgid "E948: Job still running (add ! to end the job)"
+msgstr "E948: Çàâäàííÿ âñå ùå âèêîíóºòüñÿ (äîäàéòå ! ùîá çàê³í÷èòè)"
+
+msgid "E37: No write since last change (add ! to override)"
+msgstr "E37: Çì³íè íå áóëî çàïèñàíî (! ùîá íå çâàæàòè)"
+
+msgid "E948: Job still running"
+msgstr "E948: Çàâäàííÿ âæå ùå âèêîíóºòüñÿ"
+
+msgid "E37: No write since last change"
+msgstr "E37: Íå çàïèñàíî ïîïåðåäí³ çì³íè"
+
+msgid "W14: Warning: List of file names overflow"
+msgstr "W14: Îáåðåæíî: Ñïèñîê íàçâ ôàéë³â ïåðåïîâíåíî"
+
+#, c-format
+msgid "E92: Buffer %ld not found"
+msgstr "E92: Áóôåð %ld íå çíàéäåíî"
+
+#, c-format
+msgid "E93: More than one match for %s"
+msgstr "E93: Çíàéäåíî ê³ëüêà çá³ã³â ç %s"
+
+#, c-format
+msgid "E94: No matching buffer for %s"
+msgstr "E94: Íå çíàéäåíî áóôåð, ñõîæèé íà %s"
+
+#, c-format
+msgid "line %ld"
+msgstr "ðÿäîê %ld"
+
+msgid "E95: Buffer with this name already exists"
+msgstr "E95: Áóôåð ç òàêîþ íàçâîþ âæå ³ñíóº"
+
+msgid " [Modified]"
+msgstr " [Çì³íåíî]"
+
+msgid "[Not edited]"
+msgstr "[Íå ðåäàãîâàíî]"
+
+msgid "[New file]"
+msgstr "[Íîâèé ôàéë]"
+
+msgid "[Read errors]"
+msgstr "[Ïîìèëêè ÷èòàííÿ]"
+
+msgid "[RO]"
+msgstr "[RO]"
+
+msgid "[readonly]"
+msgstr "[ëèøå ÷èòàòè]"
+
+#, c-format
+msgid "1 line --%d%%--"
+msgstr "îäèí ðÿäîê --%d%%--"
+
+#, c-format
+msgid "%ld lines --%d%%--"
+msgstr "%ld ðÿäêè(³â) --%d%%--"
+
+#, c-format
+msgid "line %ld of %ld --%d%%-- col "
+msgstr "ðÿäîê %ld ç %ld --%d%%-- êîëîíêà "
+
+msgid "[No Name]"
+msgstr "[Áåç íàçâè]"
+
+msgid "help"
+msgstr "äîïîìîãà"
+
+msgid "[Help]"
+msgstr "[Äîïîìîãà]"
+
+msgid "[Preview]"
+msgstr "[Ïåðåãëÿä]"
+
+msgid "All"
+msgstr "Óñå"
+
+msgid "Bot"
+msgstr "Çíèçó"
+
+msgid "Top"
+msgstr "Âãîð³"
+
+msgid ""
+"\n"
+"# Buffer list:\n"
+msgstr ""
+"\n"
+"# Ñïèñîê áóôåð³â:\n"
+
+msgid "E382: Cannot write, 'buftype' option is set"
+msgstr "E382: Íå ìîæó çàïèñàòè, âêàçàíà îïö³ÿ 'buftype'"
+
+msgid "[Prompt]"
+msgstr "[ϳäêàçêà]"
+
+msgid "[Scratch]"
+msgstr "[Ç íóëÿ]"
+
+msgid ""
+"\n"
+"--- Signs ---"
+msgstr ""
+"\n"
+"--- Ïîçíà÷êè ---"
+
+#, c-format
+msgid "Signs for %s:"
+msgstr "Ïîçíà÷êè äëÿ %s:"
+
+#, c-format
+msgid " line=%ld id=%d name=%s"
+msgstr " ðÿäîê=%ld id=%d íàçâà=%s"
+
+msgid "E902: Cannot connect to port"
+msgstr "E902: Íå âäàëîñÿ ç'ºäíàòèñÿ ç ïîðòîì"
+
+msgid "E901: gethostbyname() in channel_open()"
+msgstr "E901: gethostbyname() ó channel_open()"
+
+msgid "E898: socket() in channel_open()"
+msgstr "E898: socket() ó channel_open()"
+
+msgid "E903: received command with non-string argument"
+msgstr "E903: îòðèìàíî êîìàíäó ç íåòåêñòîâèì àðãóìåíòîì"
+
+msgid "E904: last argument for expr/call must be a number"
+msgstr "E904: îñòàíí³é àðãóìåíò ó âèðàç³/âèêëèêó ìຠáóòè ÷èñëîì"
+
+msgid "E904: third argument for call must be a list"
+msgstr "E904: òðåò³é àðãóìåíò ó âèêëèêó ìຠáóòè ñïèñêîì"
+
+#, c-format
+msgid "E905: received unknown command: %s"
+msgstr "E905: îòðèìàíî íåâ³äîìó êîìàíäó: %s"
+
+#, c-format
+msgid "E630: %s(): write while not connected"
+msgstr "E630: %s(): çàïèñ äî ï³ä’ºäíàííÿ"
+
+#, c-format
+msgid "E631: %s(): write failed"
+msgstr "E631: %s(): çáåðåæåííÿ íå âäàëîñÿ"
+
+#, c-format
+msgid "E917: Cannot use a callback with %s()"
+msgstr "E917: Íå ìîæíà âèêîðèñòàòè çâîðîòí³é âèêëèê ó %s()"
+
+msgid "E912: cannot use ch_evalexpr()/ch_sendexpr() with a raw or nl channel"
+msgstr ""
+"E912: íå ìîæíà âèêîðèñòàòè ch_evalexpr()/ch_sendexpr() ç raw ÷è nl êàíàëîì"
+
+msgid "E906: not an open channel"
+msgstr "E906: íå â³äêðèòèé êàíàë"
+
+msgid "E920: _io file requires _name to be set"
+msgstr "E920: ôàéë _io ïîòðåáóº âñòàíîâëåíîãî _name"
+
+msgid "E915: in_io buffer requires in_buf or in_name to be set"
+msgstr "E915: áóôåð in_io ïîòðåáóº âñòàíîâëåíîãî in_buf ÷è in_name"
+
+#, c-format
+msgid "E918: buffer must be loaded: %s"
+msgstr "E918: áóôåð ìຠáóòè çàâàíòàæåíèé: %s"
+
+msgid "E821: File is encrypted with unknown method"
+msgstr "E821: Ôàéë çàøèôðîâàíî íåâ³äîìèì ìåòîäîì"
+
+msgid "Warning: Using a weak encryption method; see :help 'cm'"
+msgstr "Óâàãà: Âèêîðèñòîâóºòüñÿ ñëàáêèé ìåòîä øèôðóâàííÿ; äèâ. :help 'cm'"
+
+msgid "Enter encryption key: "
+msgstr "Âêàæ³òü êëþ÷ øèôðó: "
+
+msgid "Enter same key again: "
+msgstr "Ïîâòîð³òü êëþ÷: "
+
+msgid "Keys don't match!"
+msgstr "Êëþ÷³ íå îäíàêîâ³!"
+
+msgid "[crypted]"
+msgstr "[çàøèôðîâàíî]"
+
+# msgstr "E235: "
+#, c-format
+msgid "E720: Missing colon in Dictionary: %s"
+msgstr "E720: Áðàêóº äâîêðàïêè ó ñëîâíèêó: %s"
+
+#, c-format
+msgid "E721: Duplicate key in Dictionary: \"%s\""
+msgstr "E721: Ïîâòîðåííÿ êëþ÷à â ñëîâíèêó: «%s»"
+
+# msgstr "E235: "
+#, c-format
+msgid "E722: Missing comma in Dictionary: %s"
+msgstr "E722: Áðàêóº êîìè ó ñëîâíèêó: %s"
+
+#, c-format
+msgid "E723: Missing end of Dictionary '}': %s"
+msgstr "E723: Íåìຠê³íö³âêè ñëîâíèêà '}': %s"
+
+# msgstr "E14: "
+msgid "extend() argument"
+msgstr "àðãóìåíò extend()"
+
+# msgstr "E226: "
+#, c-format
+msgid "E737: Key already exists: %s"
+msgstr "E737: Êëþ÷ âæå ³ñíóº: %s"
+
+#, c-format
+msgid "E96: Cannot diff more than %ld buffers"
+msgstr "E96: Íå ìîæíà ïîð³âíþâàòè ïîíàä %ld áóôåðè(³â)"
+
+msgid "E810: Cannot read or write temp files"
+msgstr "E810: Íå ìîæíà ÷èòàòè ÷è çàïèñóâàòè òèì÷àñîâ³ ôàéëè"
+
+msgid "E97: Cannot create diffs"
+msgstr "E97: Íå âäàëîñÿ ñòâîðèòè ïîð³âíÿííÿ"
+
+msgid "Patch file"
+msgstr "Ëàòêà"
+
+msgid "E816: Cannot read patch output"
+msgstr "E816: Íå âäàëîñÿ ïðî÷èòàòè ðåçóëüòàò patch"
+
+msgid "E98: Cannot read diff output"
+msgstr "E98: Íå âäàëîñÿ ïðî÷èòàòè ðåçóëüòàò diff"
+
+msgid "E99: Current buffer is not in diff mode"
+msgstr "E99: Öåé áóôåð íå â ðåæèì³ ïîð³âíÿííÿ"
+
+msgid "E793: No other buffer in diff mode is modifiable"
+msgstr "E793: Íåìຠá³ëüøå ìîäèô³êîâíèõ áóôåð³â â ðåæèì³ ïîð³âíÿííÿ"
+
+msgid "E100: No other buffer in diff mode"
+msgstr "E100: Íåìຠ³íøèõ áóôåð³â â ðåæèì³ ïîð³âíÿííÿ"
+
+msgid "E101: More than two buffers in diff mode, don't know which one to use"
+msgstr ""
+"E101: Ïîíàä äâà áóôåðè ó ðåæèì³ ïîð³âíÿííÿ, íå çðîçóì³ëî, êîòðèé ³ç íèõ "
+"âèêîðèñòàòè"
+
+#, c-format
+msgid "E102: Can't find buffer \"%s\""
+msgstr "E102: Íå âäàëîñÿ çíàéòè áóôåð «%s»"
+
+#, c-format
+msgid "E103: Buffer \"%s\" is not in diff mode"
+msgstr "E103: Áóôåð «%s» íå â ðåæèì³ ïîð³âíÿííÿ"
+
+msgid "E787: Buffer changed unexpectedly"
+msgstr "E787: Áóôåð íåñïîä³âàíî çì³íèâñÿ"
+
+msgid "E104: Escape not allowed in digraph"
+msgstr "E104: Ó äèãðàôàõ íå ìîæå ì³ñòèòèñÿ escape"
+
+msgid "E544: Keymap file not found"
+msgstr "E544: Íå çíàéäåíî ôàéë ðîçêëàäêè"
+
+msgid "E105: Using :loadkeymap not in a sourced file"
+msgstr "E105: :loadkeymap âèêîðèñòàíî íå ó ôàéë³ êîìàíä"
+
+msgid "E791: Empty keymap entry"
+msgstr "E791: Åëåìåíò ðîçêëàäêè ïîðîæí³é"
+
+msgid " Keyword completion (^N^P)"
+msgstr " Äîïîâíåííÿ êëþ÷îâèõ ñë³â (^N^P)"
+
+msgid " ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+msgstr " Ðåæèì ^X (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+
+msgid " Whole line completion (^L^N^P)"
+msgstr " Äîïîâíåííÿ óñüîãî ðÿäêà (^L^N^P)"
+
+msgid " File name completion (^F^N^P)"
+msgstr " Äîïîâíåííÿ íàçâè ôàéëó (^F^N^P)"
+
+msgid " Tag completion (^]^N^P)"
+msgstr " Äîïîâíåííÿ ì³òîê (^]^N^P)"
+
+msgid " Path pattern completion (^N^P)"
+msgstr " Äîïîâíåííÿ øëÿõó çà çðàçêîì (^N^P)"
+
+msgid " Definition completion (^D^N^P)"
+msgstr " Äîïîâíåííÿ âèçíà÷åííÿ (^D^N^P)"
+
+msgid " Dictionary completion (^K^N^P)"
+msgstr " Äîïîâíåííÿ ç³ ñëîâíèêà (^K^N^P)"
+
+msgid " Thesaurus completion (^T^N^P)"
+msgstr " Äîïîâíåííÿ ç òåçàóðóñó (^T^N^P)"
+
+msgid " Command-line completion (^V^N^P)"
+msgstr " Äîïîâíåííÿ êîìàíä (^V^N^P)"
+
+msgid " User defined completion (^U^N^P)"
+msgstr " Êîðèñòóâàöüêå äîïîâíåííÿ (^U^N^P)"
+
+msgid " Omni completion (^O^N^P)"
+msgstr " Êì³òëèâå äîïîâíåííÿ (^O^N^P)"
+
+msgid " Spelling suggestion (s^N^P)"
+msgstr " Îðôîãðàô³÷íà ï³äêàçêà (s^N^P)"
+
+msgid " Keyword Local completion (^N^P)"
+msgstr " Äîïîâíåííÿ ì³ñöåâèõ êëþ÷îâèõ ñë³â (^N^P)"
+
+msgid "Hit end of paragraph"
+msgstr "Òðàïèâñÿ ê³íåöü ïàðàãðàôà"
+
+# msgstr "E443: "
+msgid "E839: Completion function changed window"
+msgstr "E839: Ôóíêö³ÿ äîïîâíåííÿ çì³íèëà â³êíî"
+
+msgid "E840: Completion function deleted text"
+msgstr "E840: Ôóíêö³ÿ äîïîâíåííÿ çíèùèëà òåêñò"
+
+msgid "'dictionary' option is empty"
+msgstr "Îïö³ÿ 'dictionary' ïîðîæíÿ"
+
+msgid "'thesaurus' option is empty"
+msgstr "Îïö³ÿ 'thesaurus' ïîðîæíÿ"
+
+#, c-format
+msgid "Scanning dictionary: %s"
+msgstr "Ñêàíóºòüñÿ ñëîâíèê: %s"
+
+msgid " (insert) Scroll (^E/^Y)"
+msgstr " (âñòàâêà) Ïðîãîðíóòè (^E/^Y)"
+
+msgid " (replace) Scroll (^E/^Y)"
+msgstr " (çàì³íà) Ïðîãîðíóòè (^E/^Y)"
+
+#, c-format
+msgid "Scanning: %s"
+msgstr "Ïîøóê ó: %s"
+
+msgid "Scanning tags."
+msgstr "Ïîøóê ñåðåä ì³òîê."
+
+msgid "match in file"
+msgstr "çá³ã ó ôàéë³"
+
+msgid " Adding"
+msgstr " Äîäàºòüñÿ"
+
+msgid "-- Searching..."
+msgstr "-- Ïîøóê..."
+
+msgid "Back at original"
+msgstr "Ïî÷àòêîâèé âàð³àíò"
+
+msgid "Word from other line"
+msgstr "Ñëîâî ç ³íøîãî ðÿäêà"
+
+msgid "The only match"
+msgstr "ªäèíèé çá³ã"
+
+#, c-format
+msgid "match %d of %d"
+msgstr "çá³ã %d ç %d"
+
+#, c-format
+msgid "match %d"
+msgstr "çá³ã %d"
+
+# msgstr "E17: "
+msgid "E18: Unexpected characters in :let"
+msgstr "E18: Íåî÷³êóâàí³ ñèìâîëè ó :let"
+
+#, c-format
+msgid "E121: Undefined variable: %s"
+msgstr "E121: Íåâèçíà÷åíà çì³ííà: %s"
+
+msgid "E111: Missing ']'"
+msgstr "E111: Áðàêóº ']'"
+
+msgid "E719: Cannot use [:] with a Dictionary"
+msgstr "E719: Íå ìîæíà âèêîðèñòàòè [:] ç³ ñëîâíèêîì"
+
+#, c-format
+msgid "E734: Wrong variable type for %s="
+msgstr "E734: Íåïðàâèëüíèé òèï çì³ííî¿ äëÿ %s="
+
+#, c-format
+msgid "E461: Illegal variable name: %s"
+msgstr "E461: Íåïðèïóñòèìà íàçâà çì³ííî¿: %s"
+
+# msgstr "E373: "
+msgid "E806: using Float as a String"
+msgstr "E806: Float âæèòî ÿê String"
+
+msgid "E687: Less targets than List items"
+msgstr "E687: Ö³ëåé ìåíøå, í³æ åëåìåíò³â ñïèñêó"
+
+msgid "E688: More targets than List items"
+msgstr "E688: Ö³ëåé á³ëüøå, í³æ åëåìåíò³â ñïèñêó"
+
+msgid "Double ; in list of variables"
+msgstr "Äðóãà ; ó ñïèñêó çì³ííèõ"
+
+# msgstr "E235: "
+#, c-format
+msgid "E738: Can't list variables for %s"
+msgstr "E738: Íå ìîæíà ïåðåðàõóâàòè çì³íí³ ó %s"
+
+msgid "E689: Can only index a List or Dictionary"
+msgstr "E689: ²íäåêñíèé äîñòóï ìîæå áóòè ò³ëüêè äî ñïèñêó ÷è ñëîâíèêà"
+
+msgid "E708: [:] must come last"
+msgstr "E708: [:] ìຠáóòè îñòàííüîþ"
+
+msgid "E709: [:] requires a List value"
+msgstr "E709: [:] âèìàãຠñïèñîê"
+
+msgid "E710: List value has more items than target"
+msgstr "E710: Ñïèñîê ìຠá³ëüøå åëåìåíò³â, í³æ ö³ëü"
+
+msgid "E711: List value has not enough items"
+msgstr "E711: Ñïèñîê ìຠíåäîñòàòíüî åëåìåíò³â"
+
+msgid "E690: Missing \"in\" after :for"
+msgstr "E690: Ïðîïóùåíî «in» ï³ñëÿ :for"
+
+#, c-format
+msgid "E108: No such variable: \"%s\""
+msgstr "E108: Çì³ííî¿ íåìàº: «%s»"
+
+#, c-format
+msgid "E940: Cannot lock or unlock variable %s"
+msgstr "E940: Íåìîæëèâî çàáëîêóâàòè ÷è ðîçáëîêóâàòè çì³ííó %s"
+
+msgid "E743: variable nested too deep for (un)lock"
+msgstr "E743: Çì³ííà ìຠçàáàãàòî âêëàäåíü ùîá áóòè çà-/â³äêðèòîþ."
+
+msgid "E109: Missing ':' after '?'"
+msgstr "E109: Áðàêóº ':' ï³ñëÿ '?'"
+
+msgid "E804: Cannot use '%' with Float"
+msgstr "E804: Íå ìîæíà âèêîíàòè '%' íàä Float"
+
+msgid "E110: Missing ')'"
+msgstr "E110: Ïðîïóùåíî ')'"
+
+msgid "E695: Cannot index a Funcref"
+msgstr "E695: Ôóíêö³ÿ íå ìຠ³íäåêñàö³¿"
+
+msgid "E909: Cannot index a special variable"
+msgstr "E909: Íå ìîæíà ³íäåêñóâàòè ñïåö³àëüíó çì³ííó"
+
+#, c-format
+msgid "E112: Option name missing: %s"
+msgstr "E112: Áðàêóº íàçâè îïö³¿: %s"
+
+#, c-format
+msgid "E113: Unknown option: %s"
+msgstr "E113: Íåâ³äîìà îïö³ÿ: %s"
+
+#, c-format
+msgid "E114: Missing quote: %s"
+msgstr "E114: Áðàêóº ëàïêè: %s"
+
+#, c-format
+msgid "E115: Missing quote: %s"
+msgstr "E115: Áðàêóº ëàïêè: %s"
+
+msgid "Not enough memory to set references, garbage collection aborted!"
+msgstr "Íåäîñòàòíüî ïàì’ÿò³, ùîá âñòàíîâèòè ïîñèëàííÿ, çá³ð ñì³òòÿ ñêàñîâàíî!"
+
+# msgstr "E21: "
+msgid "E724: variable nested too deep for displaying"
+msgstr "E724: Ó çì³íí³é çàáàãàòî âêëàäåíü ùîá ¿¿ ïîêàçàòè"
+
+msgid "E805: Using a Float as a Number"
+msgstr "E805: Float âæèòî ÿê Number"
+
+msgid "E703: Using a Funcref as a Number"
+msgstr "E703: Funcref âæèòî ÿê Number"
+
+msgid "E745: Using a List as a Number"
+msgstr "E745: List âæèòî ÿê Number"
+
+msgid "E728: Using a Dictionary as a Number"
+msgstr "E728: Dictionary âæèòî ÿê Number"
+
+msgid "E910: Using a Job as a Number"
+msgstr "E910: Job âæèòî ÿê Number"
+
+msgid "E913: Using a Channel as a Number"
+msgstr "E913: Channel âæèòî ÿê Number"
+
+msgid "E891: Using a Funcref as a Float"
+msgstr "E891: Funcref âæèòî ÿê Float"
+
+msgid "E892: Using a String as a Float"
+msgstr "E892: String âæèòî ÿê Float"
+
+msgid "E893: Using a List as a Float"
+msgstr "E893: List âæèòî ÿê Float"
+
+msgid "E894: Using a Dictionary as a Float"
+msgstr "E894: Dictionary âæèòî ÿê Float"
+
+msgid "E907: Using a special value as a Float"
+msgstr "E907: Ñïåö³àëüíå çíà÷åííÿ âæèòî ÿê Float"
+
+msgid "E911: Using a Job as a Float"
+msgstr "E911: Job âæèòî ÿê Float"
+
+msgid "E914: Using a Channel as a Float"
+msgstr "E914: Channel âæèòî ÿê Float"
+
+msgid "E729: using Funcref as a String"
+msgstr "E729: Funcref âæèòî ÿê String"
+
+# msgstr "E373: "
+msgid "E730: using List as a String"
+msgstr "E730: List âæèòî ÿê String"
+
+msgid "E731: using Dictionary as a String"
+msgstr "E731: Dictionary âæèòî ÿê String"
+
+# msgstr "E373: "
+msgid "E908: using an invalid value as a String"
+msgstr "E908: íåïðàâèëüíå çíà÷åííÿ âæèòî ÿê String"
+
+#, c-format
+msgid "E795: Cannot delete variable %s"
+msgstr "E795: Íå ìîæíà çíèùèòè çì³ííó %s"
+
+#, c-format
+msgid "E704: Funcref variable name must start with a capital: %s"
+msgstr "E704: Íàçâà çì³ííî¿ Funcref ìຠïî÷èíàòèñÿ ç âåëèêî¿ ë³òåðè: %s"
+
+#, c-format
+msgid "E705: Variable name conflicts with existing function: %s"
+msgstr "E705: Íàçâà çì³ííî¿ ñï³âïàäàº ç ³ñíóþ÷îþ ôóíêö³ºþ: %s"
+
+#, c-format
+msgid "E741: Value is locked: %s"
+msgstr "E741: Çíà÷åííÿ çàõèùåíå: %s"
+
+msgid "Unknown"
+msgstr "Íåâ³äîìî"
+
+#, c-format
+msgid "E742: Cannot change value of %s"
+msgstr "E742: Íå ìîæíà çì³íèòè çíà÷åííÿ %s"
+
+msgid "E698: variable nested too deep for making a copy"
+msgstr "E698: Çì³ííà âêëàäåíà çàíàäòî ãëèáîêî ùîá çðîáèòè ¿¿ êîï³þ"
+
+msgid ""
+"\n"
+"# global variables:\n"
+msgstr ""
+"\n"
+"# ãëîáàëüí³ çì³íí³:\n"
+
+msgid ""
+"\n"
+"\tLast set from "
+msgstr ""
+"\n"
+"\tÂîñòàííº çì³íåíà ó "
+
+msgid "E691: Can only compare List with List"
+msgstr "E691: Ñïèñîê ìîæíà ïîð³âíÿòè ò³ëüêè ç³ ñïèñêîì"
+
+msgid "E692: Invalid operation for List"
+msgstr "E692: Íåêîðåêòíà îïåðàö³ÿ íàä ñïèñêîì"
+
+msgid "E735: Can only compare Dictionary with Dictionary"
+msgstr "E735: Ñëîâíèê ìîæíà ïîð³âíÿòè ò³ëüêè ³ç ñëîâíèêîì"
+
+msgid "E736: Invalid operation for Dictionary"
+msgstr "E736: Íåêîðåêòíà îïåðàö³ÿ íàä ñëîâíèêîì"
+
+msgid "E694: Invalid operation for Funcrefs"
+msgstr "E694: Íåêîðåêòíà îïåðàö³ÿ íàä ôóíêö³ºþ"
+
+# msgstr "E14: "
+msgid "map() argument"
+msgstr "àðãóìåíò map()"
+
+# msgstr "E14: "
+msgid "filter() argument"
+msgstr "àðãóìåíò filter()"
+
+#, c-format
+msgid "E686: Argument of %s must be a List"
+msgstr "E686: Àðãóìåíò ó %s ìຠáóòè ñïèñêîì"
+
+# msgstr "E396: "
+msgid "E928: String required"
+msgstr "E928: Ïîòð³áíî String"
+
+msgid "E808: Number or Float required"
+msgstr "E808: Òðåáà âêàçàòè Number ÷è Float"
+
+# msgstr "E14: "
+msgid "add() argument"
+msgstr "àðãóìåíò add()"
+
+# msgstr "E327: "
+msgid "E785: complete() can only be used in Insert mode"
+msgstr "E785: complete() ìîæíà âæèâàòè ò³ëüêè â ðåæèì³ âñòàâêè"
+
+msgid "&Ok"
+msgstr "&O:Ãàðàçä"
+
+#, c-format
+msgid "+-%s%3ld line: "
+msgid_plural "+-%s%3ld lines: "
+msgstr[0] "+-%s%3ld ðÿäîê: "
+msgstr[1] "+-%s%3ld ðÿäê³â: "
+
+#, c-format
+msgid "E700: Unknown function: %s"
+msgstr "E700: Íåâ³äîìà ôóíêö³ÿ: %s"
+
+msgid "E922: expected a dict"
+msgstr "E922: î÷³êóºòüñÿ dict"
+
+msgid "E923: Second argument of function() must be a list or a dict"
+msgstr "E923: Äðóãèé àðãóìåíò function() ìຠáóòè ñïèñêîì ÷è ñëîâíèêîì"
+
+msgid ""
+"&OK\n"
+"&Cancel"
+msgstr ""
+"&O:Ãàðàçä\n"
+"&C:Ñêàñóâàòè"
+
+msgid "called inputrestore() more often than inputsave()"
+msgstr "Âèêëèêè äî inputrestore() ÷àñò³øå, í³æ äî inputsave()"
+
+# msgstr "E14: "
+msgid "insert() argument"
+msgstr "àðãóìåíò insert()"
+
+# msgstr "E406: "
+msgid "E786: Range not allowed"
+msgstr "E786: ²íòåðâàë íå äîçâîëåíî"
+
+msgid "E916: not a valid job"
+msgstr "E916: íåêîðåêòíå çàâäàííÿ"
+
+# msgstr "E177: "
+msgid "E701: Invalid type for len()"
+msgstr "E701: Íåêîðåêòíèé òèï äëÿ len()"
+
+#, c-format
+msgid "E798: ID is reserved for \":match\": %ld"
+msgstr "E798: ID çàðåçåðâîâàíî äëÿ «:match»: %ld"
+
+msgid "E726: Stride is zero"
+msgstr "E726: Êðîê íóëüîâèé"
+
+msgid "E727: Start past end"
+msgstr "E727: Ïî÷àòîê çà ê³íöåì"
+
+msgid "<empty>"
+msgstr "<í³÷îãî>"
+
+msgid "E240: No connection to the X server"
+msgstr "E240: Íåìຠç'ºäíàííÿ ³ç ñåðâåðîì X"
+
+#, c-format
+msgid "E241: Unable to send to %s"
+msgstr "E241: Íå âäàëîñÿ â³ä³ñëàòè äî %s"
+
+msgid "E277: Unable to read a server reply"
+msgstr "E277: Íå âäàëîñÿ ïðî÷èòàòè â³äïîâ³äü ñåðâåðà"
+
+msgid "E941: already started a server"
+msgstr "E941: ñåðâåð âæå çàïóùåíî"
+
+msgid "E942: +clientserver feature not available"
+msgstr "E942: ìîæëèâ³ñòü +clientserver â³äñóòíÿ"
+
+# msgstr "E14: "
+msgid "remove() argument"
+msgstr "àðãóìåíò remove()"
+
+msgid "E655: Too many symbolic links (cycle?)"
+msgstr "E655: Çàáàãàòî ñèìâîëüíèõ ïîñèëàíü (öèêë?)"
+
+# msgstr "E14: "
+msgid "reverse() argument"
+msgstr "àðãóìåíò reverse()"
+
+msgid "E258: Unable to send to client"
+msgstr "E258: Íå âäàëîñÿ íàä³ñëàòè ê볺íòó"
+
+#, c-format
+msgid "E927: Invalid action: '%s'"
+msgstr "E927: Íåïðàâèëüíà ä³ÿ: '%s'"
+
+# msgstr "E14: "
+msgid "sort() argument"
+msgstr "àðãóìåíò sort()"
+
+# msgstr "E14: "
+msgid "uniq() argument"
+msgstr "àðãóìåíò unique()"
+
+# msgstr "E364: "
+msgid "E702: Sort compare function failed"
+msgstr "E702: Ïîìèëêà ó ôóíêö³¿ ïîð³âíÿííÿ sort"
+
+# msgstr "E364: "
+msgid "E882: Uniq compare function failed"
+msgstr "E882: Ïîìèëêà ó ôóíêö³¿ ïîð³âíÿííÿ uniq"
+
+msgid "(Invalid)"
+msgstr "(Íåìîæëèâî)"
+
+#, c-format
+msgid "E935: invalid submatch number: %d"
+msgstr "E935: íåïðàâèëüíèé íîìåð ï³ä-çá³ãó: %d"
+
+msgid "E677: Error writing temp file"
+msgstr "E677: Íå âäàëîñÿ çàïèñàòè òèì÷àñîâèé ôàéë"
+
+# msgstr "E14: "
+msgid "E921: Invalid callback argument"
+msgstr "E921: Íåêîðåêòíèé àðãóìåíò çâîðîòíîãî âèêëèêó"
+
+msgid "Entering Debug mode. Type \"cont\" to continue."
+msgstr "Ðåæèì íàëàãîäæåííÿ. Ùîá ïðîäîâæèòè ââåä³òü «cont»."
+
+#, c-format
+msgid "Oldval = \"%s\""
+msgstr "Oldval = «%s»"
+
+#, c-format
+msgid "Newval = \"%s\""
+msgstr "Newval = «%s»"
+
+#, c-format
+msgid "line %ld: %s"
+msgstr "ðÿäîê %ld: %s"
+
+#, c-format
+msgid "cmd: %s"
+msgstr "êîìàíäà: %s"
+
+msgid "frame is zero"
+msgstr "êàäð ñòåêó íóëüîâèé"
+
+#, c-format
+msgid "frame at highest level: %d"
+msgstr "êàäð ñòåêó íà íàéâèùîìó ð³âí³: %d"
+
+#, c-format
+msgid "Breakpoint in \"%s%s\" line %ld"
+msgstr "Òî÷êà çóïèíêè â «%s%s» ðÿäîê %ld"
+
+#, c-format
+msgid "E161: Breakpoint not found: %s"
+msgstr "E161: Òî÷êó çóïèíêè íå çíàéäåíî: %s"
+
+msgid "No breakpoints defined"
+msgstr "Íå âèçíà÷åíî æîäíî¿ òî÷êè çóïèíêè"
+
+#, c-format
+msgid "%3d %s %s line %ld"
+msgstr "%3d %s %s ðÿäîê %ld"
+
+#, c-format
+msgid "%3d expr %s"
+msgstr "%3d âèðàç %s"
+
+msgid "E750: First use \":profile start {fname}\""
+msgstr "E750: Ñïî÷àòêó çðîá³òü «:profile start {ôàéë}»"
+
+msgid "Save As"
+msgstr "Çáåðåãòè ÿê"
+
+#, c-format
+msgid "Save changes to \"%s\"?"
+msgstr "Çáåðåãòè çì³íè â «%s»?"
+
+#, c-format
+msgid "E947: Job still running in buffer \"%s\""
+msgstr "E947: Çàâäàííÿ âæå ùå âèêîíóºòüñÿ ó áóôåð³ «%s»"
+
+#, c-format
+msgid "E162: No write since last change for buffer \"%s\""
+msgstr "E162: Áóôåð «%s» ìຠíå çáåðåæåí³ çì³íè"
+
+msgid "Warning: Entered other buffer unexpectedly (check autocommands)"
+msgstr ""
+"Îáåðåæíî: Íåñïîä³âàíî îïèíèëèñÿ ó ³íøîìó áóôåð³ (ïåðåâ³ðòå àâòîêîìàíäè)"
+
+msgid "E163: There is only one file to edit"
+msgstr "E163: Ðåäàãóºòüñÿ ëèøå îäèí ôàéë"
+
+msgid "E164: Cannot go before first file"
+msgstr "E164: Öå âæå íàéïåðøèé ôàéë"
+
+msgid "E165: Cannot go beyond last file"
+msgstr "E165: Öå âæå îñòàíí³é ôàéë"
+
+#, c-format
+msgid "E666: compiler not supported: %s"
+msgstr "E666: Êîìï³ëÿòîð íå ï³äòðèìóºòüñÿ: %s"
+
+# msgstr "E195: "
+#, c-format
+msgid "Searching for \"%s\" in \"%s\""
+msgstr "Ïîøóê «%s» â «%s»"
+
+#, c-format
+msgid "Searching for \"%s\""
+msgstr "Ïîøóê «%s»"
+
+#, c-format
+msgid "not found in '%s': \"%s\""
+msgstr "íå çíàéäåíî ó '%s': «%s»"
+
+#, c-format
+msgid "W20: Required python version 2.x not supported, ignoring file: %s"
+msgstr "W20: Ïîòð³áíà âåðñ³ÿ python 2.x íå ï³äòðèìóºòüñÿ, ³ãíîðóºòüñÿ ôàéë: %s"
+
+#, c-format
+msgid "W21: Required python version 3.x not supported, ignoring file: %s"
+msgstr "W21: Ïîòð³áíà âåðñ³ÿ python 3.x íå ï³äòðèìóºòüñÿ, ³ãíîðóºòüñÿ ôàéë: %s"
+
+msgid "Source Vim script"
+msgstr "Ïðî÷èòàòè ñêðèïò Vim"
+
+#, c-format
+msgid "Cannot source a directory: \"%s\""
+msgstr "Íå âäàëîñÿ ïðî÷èòàòè êàòàëîã: «%s»"
+
+#, c-format
+msgid "could not source \"%s\""
+msgstr "Íå âäàëîñÿ âèêîíàòè «%s»"
+
+#, c-format
+msgid "line %ld: could not source \"%s\""
+msgstr "ðÿäîê %ld: íå âäàëîñÿ âèêîíàòè «%s»"
+
+#, c-format
+msgid "sourcing \"%s\""
+msgstr "âèêîíóºòüñÿ «%s»"
+
+#, c-format
+msgid "line %ld: sourcing \"%s\""
+msgstr "ðÿäîê %ld: âèêîíóºòüñÿ «%s»"
+
+#, c-format
+msgid "finished sourcing %s"
+msgstr "çàê³í÷åíî âèêîíàííÿ %s"
+
+#, c-format
+msgid "continuing in %s"
+msgstr "ïðîäîâæåííÿ â %s"
+
+msgid "modeline"
+msgstr "modeline"
+
+# msgstr "E14: "
+msgid "--cmd argument"
+msgstr "--cmd àðãóìåíò"
+
+# msgstr "E14: "
+msgid "-c argument"
+msgstr "-c àðãóìåíò"
+
+msgid "environment variable"
+msgstr "çì³ííà îòî÷åííÿ"
+
+msgid "error handler"
+msgstr "îáðîáíèê ïîìèëêè"
+
+msgid "W15: Warning: Wrong line separator, ^M may be missing"
+msgstr "W15: Çàñòåðåæåííÿ: Íåïðàâèëüíèé ðîçä³ëüíèê ðÿäê³â, ìîæëèâî, áðàêóº ^M"
+
+msgid "E167: :scriptencoding used outside of a sourced file"
+msgstr "E167: :scriptencoding âèêîðèñòàíî ïîçà âèêîíóâàíèì ôàéëîì"
+
+msgid "E168: :finish used outside of a sourced file"
+msgstr "E168: :finish âèêîðèñòàíî ïîçà âèêîíóâàíèì ôàéëîì"
+
+#, c-format
+msgid "Current %slanguage: \"%s\""
+msgstr "Ìîâà (%s): «%s»"
+
+#, c-format
+msgid "E197: Cannot set language to \"%s\""
+msgstr "E197: Íå âäàëîñÿ âñòàíîâèòè ìîâó «%s»"
+
+#, c-format
+msgid "<%s>%s%s %d, Hex %02x, Oct %03o, Digr %s"
+msgstr "<%s>%s%s %d, ø³ñò %02x, â³ñ %03o, äèãð %s"
+
+#, c-format
+msgid "<%s>%s%s %d, Hex %02x, Octal %03o"
+msgstr "<%s>%s%s %d, ø³ñò %02x, â³ñ %03o"
+
+#, c-format
+msgid "> %d, Hex %04x, Oct %o, Digr %s"
+msgstr "> %d, ø³ñò %04x, â³ñ %o, äèãð %s"
+
+#, c-format
+msgid "> %d, Hex %08x, Oct %o, Digr %s"
+msgstr "> %d, ø³ñò %08x, â³ñ %o, äèãð %s"
+
+#, c-format
+msgid "> %d, Hex %04x, Octal %o"
+msgstr "> %d, ø³ñò %04x, â³ñ %o"
+
+#, c-format
+msgid "> %d, Hex %08x, Octal %o"
+msgstr "> %d, ø³ñò %08x, â³ñ %o"
+
+msgid "E134: Move lines into themselves"
+msgstr "E134: Íåìîæëèâî ïåðåì³ñòèòè ðÿäêè ñàì³ â ñåáå"
+
+msgid "1 line moved"
+msgstr "Ïåðåì³ùåíî îäèí ðÿäîê"
+
+#, c-format
+msgid "%ld lines moved"
+msgstr "Ïåðåì³ùåíî %ld ðÿäêè(³â)"
+
+#, c-format
+msgid "%ld lines filtered"
+msgstr "³äô³ëüòðîâàíî %ld ðÿäêè(³â)"
+
+msgid "E135: *Filter* Autocommands must not change current buffer"
+msgstr "E135: Àâòîêîìàíäè *Filter* íå ïîâèíí³ çì³íþâàòè ïîòî÷íèé áóôåð"
+
+msgid "[No write since last change]\n"
+msgstr "[Çì³íè íå çàïèñàíî]\n"
+
+#, c-format
+msgid "%sviminfo: %s in line: "
+msgstr "%sviminfo: %s â ðÿäêó: "
+
+msgid "E136: viminfo: Too many errors, skipping rest of file"
+msgstr "E136: viminfo: Çàáàãàòî ïîìèëîê, ðåøòà ôàéëó áóäå ïðîïóùåíî"
+
+#, c-format
+msgid "Reading viminfo file \"%s\"%s%s%s"
+msgstr "Ç÷èòóºòüñÿ ôàéë viminfo: «%s»%s%s%s"
+
+msgid " info"
+msgstr " ³íôîðìàö³ÿ"
+
+msgid " marks"
+msgstr " ïîçíà÷êè"
+
+msgid " oldfiles"
+msgstr " ñòàð³ ôàéëè"
+
+msgid " FAILED"
+msgstr " ÍÅ ÂÄÀËÎÑß"
+
+#, c-format
+msgid "E137: Viminfo file is not writable: %s"
+msgstr "E137: Íå äîçâîëåíî çàïèñ ó ôàéë viminfo: %s"
+
+#, c-format
+msgid "E929: Too many viminfo temp files, like %s!"
+msgstr "E929: Çàáàãàòî òèì÷àñîâèõ ôàéë³â viminfo, ÿê %s!"
+
+#, c-format
+msgid "E138: Can't write viminfo file %s!"
+msgstr "E138: Íå âäàëîñÿ çàïèñàòè ôàéë viminfo %s!"
+
+#, c-format
+msgid "Writing viminfo file \"%s\""
+msgstr "Çàïèñóºòüñÿ ôàéë viminfo «%s»"
+
+#, c-format
+msgid "E886: Can't rename viminfo file to %s!"
+msgstr "E886: Íå âäàëîñÿ ïåðåéìåíóâàòè ôàéë viminfo ó %s!"
+
+#, c-format
+msgid "# This viminfo file was generated by Vim %s.\n"
+msgstr "# Öåé ôàéë àâòîìàòè÷íî ñòâîðåíèé Vim %s.\n"
+
+msgid ""
+"# You may edit it if you're careful!\n"
+"\n"
+msgstr ""
+"# Ìîæåòå ðåäàãóâàòè, àëå ÎÁÅÐÅÆÍÎ!\n"
+"\n"
+
+msgid "# Value of 'encoding' when this file was written\n"
+msgstr "# Çíà÷åííÿ 'encoding' ï³ä ÷àñ ñòâîðåííÿ öüîãî ôàéëó\n"
+
+msgid "Illegal starting char"
+msgstr "Íåäîçâîëåíèé ñèìâîë íà ïî÷àòêó ðÿäêà"
+
+msgid ""
+"\n"
+"# Bar lines, copied verbatim:\n"
+msgstr ""
+"\n"
+"# Ðÿäêè bar, ñêîï³éîâàíî ïîñèìâîëüíî:\n"
+
+msgid "Write partial file?"
+msgstr "Çàïèñàòè ÷àñòèíó ôàéëó?"
+
+msgid "E140: Use ! to write partial buffer"
+msgstr "E140: Âèêîðèñòàéòå ! äëÿ çàïèñó ÷àñòèíè áóôåðà"
+
+#, c-format
+msgid "Overwrite existing file \"%s\"?"
+msgstr "Ïåðåïèñàòè ³ñíóþ÷èé ôàéë «%s»?"
+
+#, c-format
+msgid "Swap file \"%s\" exists, overwrite anyway?"
+msgstr "Ôàéë îáì³íó «%s» ³ñíóº, ïåðåçàïèñàòè?"
+
+#, c-format
+msgid "E768: Swap file exists: %s (:silent! overrides)"
+msgstr "E768: Ôàéë îáì³íó ³ñíóº: %s (:silent! ïåðåâàæóº)"
+
+#, c-format
+msgid "E141: No file name for buffer %ld"
+msgstr "E141: Íåìຠâõ³äíîãî ôàéëó äëÿ áóôåðà %ld"
+
+msgid "E142: File not written: Writing is disabled by 'write' option"
+msgstr "E142: Ôàéë íå çàïèñàíî: çàïèñ çàáîðîíåíî îïö³ºþ 'write'"
+
+#, c-format
+msgid ""
+"'readonly' option is set for \"%s\".\n"
+"Do you wish to write anyway?"
+msgstr ""
+"Äëÿ «%s» âñòàíîâëåíî 'readonly'.\n"
+"Áàæàºòå âñå îäíî ïðîäîâæèòè çàïèñ?"
+
+#, c-format
+msgid ""
+"File permissions of \"%s\" are read-only.\n"
+"It may still be possible to write it.\n"
+"Do you wish to try?"
+msgstr ""
+"Ôàéë «%s» äîçâîëåíî ò³ëüêè ÷èòàòè.\n"
+"Ïðîòå, ìîæëèâî, éîãî ìîæíà çàïèñàòè.\n"
+"Õî÷åòå ñïðîáóâàòè?"
+
+#, c-format
+msgid "E505: \"%s\" is read-only (add ! to override)"
+msgstr "E505: «%s» ò³ëüêè äëÿ ÷èòàííÿ (! ùîá íå çâàæàòè)"
+
+msgid "Edit File"
+msgstr "Ðåäàãóâàòè Ôàéë"
+
+#, c-format
+msgid "E143: Autocommands unexpectedly deleted new buffer %s"
+msgstr "E143: Àâòîêîìàíäè íåñïîä³âàíî çíèùèëè íîâèé áóôåð %s"
+
+msgid "E144: non-numeric argument to :z"
+msgstr "E144: íå ÷èñëîâèé àðãóìåíò äëÿ :z"
+
+msgid "E145: Shell commands not allowed in rvim"
+msgstr "E145: Ó rvim íå äîçâîëåí³ êîìàíäè îáîëîíêè"
+
+msgid "E146: Regular expressions can't be delimited by letters"
+msgstr "E146: Ðåãóëÿðí³ âèðàçè íå ìîæíà ðîçä³ëÿòè ë³òåðàìè"
+
+#, c-format
+msgid "replace with %s (y/n/a/q/l/^E/^Y)?"
+msgstr "Çàì³íèòè íà %s (y/n/a/q/l/^E/^Y)?"
+
+msgid "(Interrupted) "
+msgstr "(Ïåðåðâàíî) "
+
+# msgstr "E31: "
+msgid "1 match"
+msgstr "Îäèí çá³ã"
+
+msgid "1 substitution"
+msgstr "Îäíà çàì³íà"
+
+#, c-format
+msgid "%ld matches"
+msgstr "%ld çá³ãè(³â)"
+
+#, c-format
+msgid "%ld substitutions"
+msgstr "%ld çàì³í(è)"
+
+msgid " on 1 line"
+msgstr " â îäíîìó ðÿäêó"
+
+#, c-format
+msgid " on %ld lines"
+msgstr " â %ld ðÿäêàõ"
+
+msgid "E147: Cannot do :global recursive with a range"
+msgstr "E147: :global íå ìîæíà âæèâàòè ðåêóðñèâíî ç ä³àïàçîíîì"
+
+msgid "E148: Regular expression missing from global"
+msgstr "E148: Ó global áðàêóº çðàçêà"
+
+#, c-format
+msgid "Pattern found in every line: %s"
+msgstr "Çðàçîê çíàéäåíî ó êîæíîìó ðÿäêó: %s"
+
+#, c-format
+msgid "Pattern not found: %s"
+msgstr "Çðàçîê íå çíàéäåíî: %s"
+
+msgid ""
+"\n"
+"# Last Substitute String:\n"
+"$"
+msgstr ""
+"\n"
+"# Îñòàííÿ çàì³íà:\n"
+"$"
+
+msgid "E478: Don't panic!"
+msgstr "E478: Áåç ïàí³êè!"
+
+#, c-format
+msgid "E661: Sorry, no '%s' help for %s"
+msgstr "E661: Âèáà÷òå, íåìຠäîïîìîãè '%s' äëÿ %s"
+
+#, c-format
+msgid "E149: Sorry, no help for %s"
+msgstr "E149: Âèáà÷òå, íåìຠäîïîìîãè äëÿ %s"
+
+#, c-format
+msgid "Sorry, help file \"%s\" not found"
+msgstr "Âèáà÷òå, ôàéë äîïîìîãè «%s» íå çíàéäåíî"
+
+#, c-format
+msgid "E151: No match: %s"
+msgstr "E151: Æîäíîãî çá³ãó: %s"
+
+#, c-format
+msgid "E152: Cannot open %s for writing"
+msgstr "E152: Íå âäàëîñÿ â³äêðèòè %s äëÿ çàïèñó"
+
+#, c-format
+msgid "E153: Unable to open %s for reading"
+msgstr "E153: Íå âäàëîñÿ â³äêðèòè %s äëÿ ÷èòàííÿ"
+
+#, c-format
+msgid "E670: Mix of help file encodings within a language: %s"
+msgstr "E670: ̳øàíèíà êîäóâàíü ôàéëó äîïîìîãè äëÿ ìîâè %s"
+
+#, c-format
+msgid "E154: Duplicate tag \"%s\" in file %s/%s"
+msgstr "E154: Ïîâòîðåííÿ ì³òêè «%s» ó ôàéë³ %s/%s"
+
+#, c-format
+msgid "E150: Not a directory: %s"
+msgstr "E150: Íå º êàòàëîãîì: %s"
+
+#, c-format
+msgid "E160: Unknown sign command: %s"
+msgstr "E160: Íåâ³äîìà êîìàíäà íàäïèñó: %s"
+
+msgid "E156: Missing sign name"
+msgstr "E156: Ïðîïóùåíî íàçâó íàäïèñó"
+
+msgid "E612: Too many signs defined"
+msgstr "E612: Âèçíà÷åíî çàáàãàòî íàäïèñ³â"
+
+#, c-format
+msgid "E239: Invalid sign text: %s"
+msgstr "E239: Íåêîðåêòíèé íàäïèñ: %s"
+
+#, c-format
+msgid "E155: Unknown sign: %s"
+msgstr "E155: Íåâ³äîìèé íàäïèñ: %s"
+
+msgid "E159: Missing sign number"
+msgstr "E159: Ïðîïóùåíî íîìåð íàäïèñó"
+
+#, c-format
+msgid "E158: Invalid buffer name: %s"
+msgstr "E158: Íåêîðåêòíà íàçâà áóôåðà: %s"
+
+msgid "E934: Cannot jump to a buffer that does not have a name"
+msgstr "E934: Íå ìîæíà ïåðåéòè äî áóôåðà, ÿêèé íå ìຠíàçâè"
+
+#, c-format
+msgid "E157: Invalid sign ID: %ld"
+msgstr "E157: Íåïðàâèëüíèé ID íàäïèñó: %ld"
+
+#, c-format
+msgid "E885: Not possible to change sign %s"
+msgstr "E885: Íåìîæëèâî çì³íèòè çíàê %s"
+
+msgid " (NOT FOUND)"
+msgstr " (ÍÅ ÇÍÀÉÄÅÍÎ)"
+
+msgid " (not supported)"
+msgstr " (íå ï³äòðèìóºòüñÿ)"
+
+msgid "[Deleted]"
+msgstr "[Çíèùåíî]"
+
+msgid "No old files"
+msgstr "Æîäíîãî ñòàðîãî ôàéëó"
+
+msgid "Entering Ex mode. Type \"visual\" to go to Normal mode."
+msgstr "Ðåæèì Ex. Äëÿ ïîâåðíåííÿ äî íîðìàëüíîãî ðåæèìó âèêîíàéòå «visual»"
+
+msgid "E501: At end-of-file"
+msgstr "E501: ʳíåöü ôàéëó"
+
+msgid "E169: Command too recursive"
+msgstr "E169: Êîìàíäà çàíàäòî ðåêóðñèâíà"
+
+#, c-format
+msgid "E605: Exception not caught: %s"
+msgstr "E605: Âèíÿòêîâà ñèòóàö³ÿ íå îáðîáëåíà: %s"
+
+msgid "End of sourced file"
+msgstr "ʳíåöü âèêîíóâàíîãî ôàéëó"
+
+msgid "End of function"
+msgstr "ʳíåöü ôóíêö³¿"
+
+msgid "E464: Ambiguous use of user-defined command"
+msgstr "E464: Íåîäíîçíà÷íèé âæèòîê êîìàíäè êîðèñòóâà÷à"
+
+msgid "E492: Not an editor command"
+msgstr "E492: Öå íå êîìàíäà ðåäàêòîðà"
+
+msgid "E493: Backwards range given"
+msgstr "E493: ²íòåðâàë çàäàíî íàâèâîð³ò"
+
+msgid "Backwards range given, OK to swap"
+msgstr "²íòåðâàë çàäàíî íàâèâîð³ò, ùîá ïîì³íÿòè ì³ñöÿìè — ÃÀÐÀÇÄ"
+
+msgid "E494: Use w or w>>"
+msgstr "E494: Ñïðîáóéòå w àáî w>>"
+
+msgid "E943: Command table needs to be updated, run 'make cmdidxs'"
+msgstr "E943: Òàáëèöþ êîìàíä ïîòð³áíî ïîíîâèòè, çàïóñò³òü 'make cmdidxs'"
+
+msgid "E319: Sorry, the command is not available in this version"
+msgstr "E319: Âèáà÷òå, ö³º¿ êîìàíäè íåìຠó ö³é âåðñ³¿"
+
+msgid "1 more file to edit. Quit anyway?"
+msgstr "Çàëèøèëîñÿ â³äðåäàãóâàòè ùå îäèí ôàéë. Âñå îäíî âèéòè?"
+
+#, c-format
+msgid "%d more files to edit. Quit anyway?"
+msgstr "Ùå º %d íå ðåäàãîâàíèõ ôàéë³â. Âñå îäíî âèéòè?"
+
+msgid "E173: 1 more file to edit"
+msgstr "E173: Çàëèøèëîñÿ â³äðåäàãóâàòè ùå îäèí ôàéë"
+
+#, c-format
+msgid "E173: %ld more files to edit"
+msgstr "E173: Çàëèøèëîñÿ %ld íå ðåäàãîâàíèõ ôàéë³â"
+
+msgid "E174: Command already exists: add ! to replace it"
+msgstr "E174: Êîìàíäà âæå ³ñíóº, ! ùîá çàì³íèòè ¿¿"
+
+msgid ""
+"\n"
+" Name Args Address Complete Definition"
+msgstr ""
+"\n"
+" Íàçâà Àðã. Àäðåñà Äîïîâíåííÿ Âèçíà÷åííÿ"
+
+msgid "No user-defined commands found"
+msgstr "Íå çíàéäåíî êîìàíä êîðèñòóâà÷à"
+
+msgid "E175: No attribute specified"
+msgstr "E175: Íå âêàçàíî àòðèáóò³â"
+
+msgid "E176: Invalid number of arguments"
+msgstr "E176: Íåïðàâèëüíà ê³ëüê³ñòü àðãóìåíò³â"
+
+msgid "E177: Count cannot be specified twice"
+msgstr "E177: ˳÷èëüíèê íå ìîæå áóòè âêàçàíî äâ³÷³"
+
+# msgstr "E177: "
+msgid "E178: Invalid default value for count"
+msgstr "E178: Íåïðàâèëüíå ïî÷àòêîâå çíà÷åííÿ ë³÷èëüíèêà"
+
+# msgstr "E178: "
+msgid "E179: argument required for -complete"
+msgstr "E179: äëÿ -complete ïîòð³áíèé àðãóìåíò"
+
+# msgstr "E178: "
+msgid "E179: argument required for -addr"
+msgstr "E179: äëÿ -addr ïîòð³áíèé àðãóìåíò"
+
+# msgstr "E180: "
+#, c-format
+msgid "E181: Invalid attribute: %s"
+msgstr "E181: Íåïðàâèëüíèé àòðèáóò: %s"
+
+# msgstr "E181: "
+msgid "E182: Invalid command name"
+msgstr "E182: Íåïðàâèëüíà íàçâà êîìàíäè"
+
+# msgstr "E182: "
+msgid "E183: User defined commands must start with an uppercase letter"
+msgstr "E183: Êîìàíäè êîðèñòóâà÷à ïîâèíí³ ïî÷èíàòèñÿ ç âåëèêî¿ ë³òåðè"
+
+msgid "E841: Reserved name, cannot be used for user defined command"
+msgstr ""
+"E841: Çàðåçåðâîâàíà íàçâà, íå ìîæíà âèêîðèñòàòè äëÿ êîìàíäè êîðèñòóâà÷à"
+
+# msgstr "E183: "
+#, c-format
+msgid "E184: No such user-defined command: %s"
+msgstr "E184: Êîìàíäó êîðèñòóâà÷à íå çíàéäåíî: %s"
+
+# msgstr "E179: "
+#, c-format
+msgid "E180: Invalid address type value: %s"
+msgstr "E180: Íåïðàâèëüíå çíà÷åííÿ òèïó àäðåñè: %s"
+
+# msgstr "E179: "
+#, c-format
+msgid "E180: Invalid complete value: %s"
+msgstr "E180: Íåïðàâèëüíå äîïîâíåííÿ: %s"
+
+msgid "E468: Completion argument only allowed for custom completion"
+msgstr "E468: Àðãóìåíò äîçâîëåíèé ò³ëüêè äëÿ äîïîâíåííÿ êîðèñòóâà÷à"
+
+msgid "E467: Custom completion requires a function argument"
+msgstr "E467: Êîðèñòóâàöüêå äîïîâíåííÿ âèìàãຠàðãóìåíò-ôóíêö³þ"
+
+msgid "unknown"
+msgstr "Íåâ³äîìî"
+
+# msgstr "E184: "
+#, c-format
+msgid "E185: Cannot find color scheme '%s'"
+msgstr "E185: Íå âäàëîñÿ çíàéòè ñõåìó êîëüîð³â «%s»"
+
+msgid "Greetings, Vim user!"
+msgstr "³òàííÿ, êîðèñòóâà÷ó Vim!"
+
+# msgstr "E443: "
+msgid "E784: Cannot close last tab page"
+msgstr "E784: Íå ìîæíà çàêðèòè îñòàííþ âêëàäêó"
+
+# msgstr "E444: "
+msgid "Already only one tab page"
+msgstr "Âæå é òàê ëèøå îäíà âêëàäêà"
+
+# msgstr "E185: "
+msgid "Edit File in new window"
+msgstr "Ðåäàãóâàòè ôàéë ó íîâîìó â³êí³"
+
+#, c-format
+msgid "Tab page %d"
+msgstr "Âêëàäêà %d"
+
+msgid "No swap file"
+msgstr "Íåìຠôàéëó îáì³íó"
+
+msgid "Append File"
+msgstr "Äîïèñàòè ôàéë"
+
+msgid "E747: Cannot change directory, buffer is modified (add ! to override)"
+msgstr "E747: Íå âäàëîñÿ çì³íèòè êàòàëîã, áóôåð ìຠçì³íè (! ùîá íå çâàæàòè)"
+
+msgid "E186: No previous directory"
+msgstr "E186: Öå âæå íàéïåðøèé êàòàëîã"
+
+# msgstr "E186: "
+msgid "E187: Unknown"
+msgstr "E187: Íåâ³äîìî"
+
+msgid "E465: :winsize requires two number arguments"
+msgstr "E465: :winsize âèìàãຠäâà ÷èñëîâèõ àðãóìåíòè"
+
+# msgstr "E187: "
+#, c-format
+msgid "Window position: X %d, Y %d"
+msgstr "Ïîçèö³ÿ â³êíà: X %d, Y %d"
+
+msgid "E188: Obtaining window position not implemented for this platform"
+msgstr "E188: Íå ìîæíà îòðèìàòè ïîçèö³þ â³êíà íà ö³é ïëàòôîðì³"
+
+msgid "E466: :winpos requires two number arguments"
+msgstr "E466: :winpos âèìàãຠäâà ÷èñëîâèõ àðãóìåíòè"
+
+msgid "E930: Cannot use :redir inside execute()"
+msgstr "E930: Íå ìîæíà âèêîðèñòàòè :redir âñåðåäèí³ execute()"
+
+# msgstr "E188: "
+msgid "Save Redirection"
+msgstr "Çáåðåãòè ïåðåàäðåñîâàíèé âèâ³ä"
+
+msgid "Save View"
+msgstr "Çáåðåãòè âèãëÿä"
+
+msgid "Save Session"
+msgstr "Çáåðåãòè ñåàíñ"
+
+msgid "Save Setup"
+msgstr "Çáåðåãòè íàëàøòóâàííÿ"
+
+#, c-format
+msgid "E739: Cannot create directory: %s"
+msgstr "E739: Íå âäàëîñÿ ñòâîðèòè êàòàëîã: %s"
+
+#, c-format
+msgid "E189: \"%s\" exists (add ! to override)"
+msgstr "E189: Ôàéë «%s» ³ñíóº (! ùîá íå çâàæàòè)"
+
+# msgstr "E189: "
+#, c-format
+msgid "E190: Cannot open \"%s\" for writing"
+msgstr "E190: Íå âäàëîñÿ â³äêðèòè «%s» äëÿ çàïèñó"
+
+# msgstr "E190: "
+msgid "E191: Argument must be a letter or forward/backward quote"
+msgstr "E191: Àðãóìåíò ìຠáóòè ë³òåðîþ, ` àáî '"
+
+# msgstr "E191: "
+msgid "E192: Recursive use of :normal too deep"
+msgstr "E192: Çàáàãàòî âêëàäåíèõ :normal"
+
+msgid "E809: #< is not available without the +eval feature"
+msgstr "E809: #< íå äîñòóïíà áåç ìîæëèâîñò³ +eval"
+
+# msgstr "E193: "
+msgid "E194: No alternate file name to substitute for '#'"
+msgstr "E194: Íåìຠíàçâè âòîðèííîãî ôàéëó äëÿ çàì³íè '#'"
+
+msgid "E495: no autocommand file name to substitute for \"<afile>\""
+msgstr "E495: Íåìຠíàçâè ôàéëó àâòîêîìàíäè äëÿ çàì³íè «<afile>»"
+
+msgid "E496: no autocommand buffer number to substitute for \"<abuf>\""
+msgstr "E496: Íåìຠíîìåðà áóôåðà àâòîêîìàíäè äëÿ çàì³íè «<abuf>»"
+
+msgid "E497: no autocommand match name to substitute for \"<amatch>\""
+msgstr "E497: Íåìຠíàçâè çá³ãó àâòîêîìàíäè äëÿ çàì³íè «<amatch>»"
+
+msgid "E498: no :source file name to substitute for \"<sfile>\""
+msgstr "E498: Íåìຠíàçâè ôàéëó :source äëÿ çàì³íè «<sfile>»"
+
+msgid "E842: no line number to use for \"<slnum>\""
+msgstr "E842: íåìຠíîìåðà ðÿäêà, ùîá âèêîðèñòàòè ç «<sfile>»"
+
+#, no-c-format
+msgid "E499: Empty file name for '%' or '#', only works with \":p:h\""
+msgstr "E499: Íàçâà ôàéëó äëÿ '%' ÷è '#' ïîðîæíÿ, ïðàöþº ëèøå ç «:p:h»"
+
+msgid "E500: Evaluates to an empty string"
+msgstr "E500: Ðåçóëüòàò — ïîðîæí³é ðÿäîê"
+
+msgid "E195: Cannot open viminfo file for reading"
+msgstr "E195: Íå âäàëîñÿ ïðî÷èòàòè ôàéë viminfo"
+
+msgid "Untitled"
+msgstr "Íåíàçâàíèé"
+
+msgid "E196: No digraphs in this version"
+msgstr "E196: Ó ö³é âåðñ³¿ íåìຠäèãðàô³â"
+
+msgid "E608: Cannot :throw exceptions with 'Vim' prefix"
+msgstr "E608: Íå ìîæíà âèêèäàòè (:throw) âèíÿòêè ç ïðåô³êñîì 'Vim'"
+
+#, c-format
+msgid "Exception thrown: %s"
+msgstr "Âèíÿòêîâà ñèòóàö³ÿ: %s"
+
+#, c-format
+msgid "Exception finished: %s"
+msgstr "Âèíÿòîê çàê³í÷åíî: %s"
+
+#, c-format
+msgid "Exception discarded: %s"
+msgstr "Âèíÿòîê ñêèíóòî: %s"
+
+#, c-format
+msgid "%s, line %ld"
+msgstr "%s, ðÿäîê %ld"
+
+#, c-format
+msgid "Exception caught: %s"
+msgstr "Ñï³éìàíî âèíÿòêîâó ñèòóàö³þ: %s"
+
+#, c-format
+msgid "%s made pending"
+msgstr "Î÷³êóºòüñÿ %s"
+
+#, c-format
+msgid "%s resumed"
+msgstr "³äíîâëåíî %s"
+
+#, c-format
+msgid "%s discarded"
+msgstr "Ñêèíóòî %s"
+
+msgid "Exception"
+msgstr "Âèíÿòîê"
+
+msgid "Error and interrupt"
+msgstr "Ïîìèëêà, ïåðåðâàíî"
+
+# msgstr "E231: "
+msgid "Error"
+msgstr "Ïîìèëêà"
+
+msgid "Interrupt"
+msgstr "Ïåðåðâàíî"
+
+msgid "E579: :if nesting too deep"
+msgstr "E579: Çàíàäòî áàãàòî âêëàäåíèõ :if"
+
+msgid "E580: :endif without :if"
+msgstr "E580: :endif áåç :if"
+
+msgid "E581: :else without :if"
+msgstr "E581: :else áåç :if"
+
+msgid "E582: :elseif without :if"
+msgstr "E582: :elseif áåç :if"
+
+msgid "E583: multiple :else"
+msgstr "E583: Íå îäíå :else"
+
+msgid "E584: :elseif after :else"
+msgstr "E584: :elseif ï³ñëÿ :else"
+
+msgid "E585: :while/:for nesting too deep"
+msgstr "E585: Çàáàãàòî âêëàäåíèõ :while/:for"
+
+msgid "E586: :continue without :while or :for"
+msgstr "E586: :continue áåç :while ÷è :for"
+
+msgid "E587: :break without :while or :for"
+msgstr "E587: :break áåç :while ÷è :for"
+
+msgid "E732: Using :endfor with :while"
+msgstr "E732: Âæèòî :endfor ³ç :while"
+
+msgid "E733: Using :endwhile with :for"
+msgstr "E733: Âæèòî :endwhile ³ç :for"
+
+msgid "E601: :try nesting too deep"
+msgstr "E601: Çàáàãàòî âêëàäåíèõ :try"
+
+msgid "E603: :catch without :try"
+msgstr "E603: :catch áåç :try"
+
+msgid "E604: :catch after :finally"
+msgstr "E604: :catch ï³ñëÿ :finally"
+
+msgid "E606: :finally without :try"
+msgstr "E606: :finally áåç :try"
+
+msgid "E607: multiple :finally"
+msgstr "E607: Íå îäíå :finally"
+
+msgid "E602: :endtry without :try"
+msgstr "E602: :entry áåç :try"
+
+msgid "E193: :endfunction not inside a function"
+msgstr "E193: :endfunction ïîçà ìåæàìè ôóíêö³¿"
+
+msgid "E788: Not allowed to edit another buffer now"
+msgstr "E788: Çàðàç íå ìîæíà ðåäàãóâàòè ³íøèé áóôåð"
+
+msgid "E811: Not allowed to change buffer information now"
+msgstr "E811: Çàðàç íå ìîæíà çì³íþâàòè ³íôîðìàö³þ áóôåðà"
+
+# msgstr "E197: "
+msgid "tagname"
+msgstr "íàçâà ì³òêè"
+
+msgid " kind file\n"
+msgstr " òèï ôàéëó\n"
+
+msgid "'history' option is zero"
+msgstr "Îïö³ÿ 'history' ïîðîæíÿ"
+
+#, c-format
+msgid ""
+"\n"
+"# %s History (newest to oldest):\n"
+msgstr ""
+"\n"
+"# Ïîïåðåäí³ %s (â³ä íàéíîâ³øèõ):\n"
+
+msgid "Command Line"
+msgstr "êîìàíäè"
+
+msgid "Search String"
+msgstr "øóêàí³ ðÿäêè"
+
+msgid "Expression"
+msgstr "âèðàçè"
+
+msgid "Input Line"
+msgstr "ââåäåí³ ðÿäêè"
+
+msgid "Debug Line"
+msgstr "Ðÿäîê íàëàãîäæåííÿ"
+
+msgid "E198: cmd_pchar beyond the command length"
+msgstr "E198: cmd_pchar ïîçà ìåæàìè êîìàíäè"
+
+msgid "E199: Active window or buffer deleted"
+msgstr "E199: Àêòèâíå â³êíî àáî áóôåð áóëî çíèùåíî"
+
+msgid "E812: Autocommands changed buffer or buffer name"
+msgstr "E812: Àâòîêîìàíäè çì³íèëè áóôåð ÷è éîãî íàçâó"
+
+# msgstr "E199: "
+msgid "Illegal file name"
+msgstr "Íåäîçâîëåíà íàçâà ôàéëó"
+
+msgid "is a directory"
+msgstr "êàòàëîã"
+
+msgid "is not a file"
+msgstr "íå ôàéë"
+
+msgid "is a device (disabled with 'opendevice' option)"
+msgstr "º ïðèñòðîºì (âèìêíåíî îïö³ºþ 'opendevice')"
+
+msgid "[New File]"
+msgstr "[Íîâèé ôàéë]"
+
+msgid "[New DIRECTORY]"
+msgstr "[Íîâèé êàòàëîã]"
+
+msgid "[File too big]"
+msgstr "[Ôàéë çàâåëèêèé]"
+
+msgid "[Permission Denied]"
+msgstr "[³äìîâëåíî]"
+
+msgid "E200: *ReadPre autocommands made the file unreadable"
+msgstr "E200: Àâòîêîìàíäè *ReadPre óíåìîæëèâèëè ÷èòàííÿ ôàéëó"
+
+# msgstr "E200: "
+msgid "E201: *ReadPre autocommands must not change current buffer"
+msgstr "E201: Àâòîêîìàíäè *ReadPre íå ïîâèíí³ çì³íþâàòè öåé áóôåð"
+
+# msgstr "E201: "
+msgid "Vim: Reading from stdin...\n"
+msgstr "Vim: ×èòàºòüñÿ ç stdin...\n"
+
+msgid "Reading from stdin..."
+msgstr "×èòàºòüñÿ ç stdin..."
+
+msgid "E202: Conversion made file unreadable!"
+msgstr "E202: Êîíâåðòàö³ÿ óíåìîæëèâèëà ÷èòàííÿ ôàéëó!"
+
+# msgstr "E202: "
+msgid "[fifo/socket]"
+msgstr "[êàíàë/ãí³çäî]"
+
+msgid "[fifo]"
+msgstr "[êàíàë]"
+
+msgid "[socket]"
+msgstr "[ãí³çäî]"
+
+msgid "[character special]"
+msgstr "[ñïåö. ñèìâîëüíèé]"
+
+msgid "[CR missing]"
+msgstr "[Áðàêóº CR]"
+
+msgid "[long lines split]"
+msgstr "[Ðîçáèòî äîâã³ ðÿäêè]"
+
+msgid "[NOT converted]"
+msgstr "[ÍÅ êîíâåðòîâàíî]"
+
+msgid "[converted]"
+msgstr "[êîíâåðòîâàíî]"
+
+#, c-format
+msgid "[CONVERSION ERROR in line %ld]"
+msgstr "[ÏÎÌÈËÊÀ ÊÎÍÂÅÐÒÀÖ²¯ ó ðÿäêó %ld]"
+
+#, c-format
+msgid "[ILLEGAL BYTE in line %ld]"
+msgstr "[ÍÅÊÎÐÅÊÒÍÈÉ ÁÀÉÒ ó ðÿäêó %ld]"
+
+msgid "[READ ERRORS]"
+msgstr "[ÏÎÌÈËÊÀ ×ÈÒÀÍÍß]"
+
+msgid "Can't find temp file for conversion"
+msgstr "Íå âäàëîñÿ ï³äøóêàòè òèì÷àñîâèé ôàéë äëÿ êîíâåðòàö³¿"
+
+msgid "Conversion with 'charconvert' failed"
+msgstr "Êîíâåðòàö³ÿ ç 'charconvert' íå âäàëàñÿ"
+
+msgid "can't read output of 'charconvert'"
+msgstr "íå âäàëîñÿ ïðî÷èòàòè âèâ³ä 'charconvert'"
+
+# msgstr "E217: "
+msgid "E676: No matching autocommands for acwrite buffer"
+msgstr "E676: Íåìຠâ³äïîâ³äíèõ àâòîêîìàíä"
+
+msgid "E203: Autocommands deleted or unloaded buffer to be written"
+msgstr "E203: Àâòîêîìàíäà çíèùèëà àáî âèâàíòàæèëà áóôåð, ùî ìàâ áóòè çàïèñàíèé"
+
+msgid "E204: Autocommand changed number of lines in unexpected way"
+msgstr "E204: Àâòîêîìàíäà íåñïîä³âàíèì ÷èíîì çì³íèëà ê³ëüê³ñòü ðÿäê³â"
+
+msgid "NetBeans disallows writes of unmodified buffers"
+msgstr "NetBeans íå äîçâîëÿº çàïèñóâàòè ó íåçì³íåí³ áóôåðè"
+
+# msgstr "E391: "
+msgid "Partial writes disallowed for NetBeans buffers"
+msgstr "×àñòêîâ³ çàïèñè çàáîðîíåí³ äëÿ áóôåð³â NetBeans"
+
+msgid "is not a file or writable device"
+msgstr "Íå ïðèäàòíèé äëÿ çàïèñó"
+
+msgid "writing to device disabled with 'opendevice' option"
+msgstr "Çàïèñ äî ïðèñòðîþ çàáîðîíåíî îïö³ºþ 'opendevice'"
+
+msgid "is read-only (add ! to override)"
+msgstr "ëèøå äëÿ ÷èòàííÿ (! ùîá íå çâàæàòè)"
+
+msgid "E506: Can't write to backup file (add ! to override)"
+msgstr "E506: Íå âäàëîñÿ çàïèñàòè ðåçåðâíèé ôàéë (! ùîá íå çâàæàòè)"
+
+msgid "E507: Close error for backup file (add ! to override)"
+msgstr "E507: Ïîìèëêà çàêðèòòÿ ðåçåðâíîãî ôàéëó (! ùîá íå çâàæàòè)"
+
+msgid "E508: Can't read file for backup (add ! to override)"
+msgstr ""
+"E508: Íå âäàëîñÿ ïðî÷èòàòè ôàéë ùîá ñòâîðèòè ðåçåðâíó êîï³þ (! ùîá íå "
+"çâàæàòè)"
+
+msgid "E509: Cannot create backup file (add ! to override)"
+msgstr "E509: Íå âäàëîñÿ ñòâîðèòè ðåçåðâíó êîï³þ (! ùîá íå çâàæàòè)"
+
+msgid "E510: Can't make backup file (add ! to override)"
+msgstr "E510: Íå âäàëîñÿ çðîáèòè ðåçåðâíó êîï³þ (! ùîá íå çâàæàòè)"
+
+msgid "E214: Can't find temp file for writing"
+msgstr "E214: Íå âäàëîñÿ ï³äøóêàòè òèì÷àñîâèé ôàéë äëÿ çàïèñó"
+
+msgid "E213: Cannot convert (add ! to write without conversion)"
+msgstr "E213: Íå âäàëîñÿ ïåðåòâîðèòè (! ùîá çàïèñàòè áåç êîíâåðòàö³¿)"
+
+msgid "E166: Can't open linked file for writing"
+msgstr "E166: Íå âäàëîñÿ â³äêðèòè äëÿ çàïèñó çâ'ÿçàíèé ôàéë"
+
+msgid "E212: Can't open file for writing"
+msgstr "E212: Íå âäàëîñÿ â³äêðèòè ôàéë äëÿ çàïèñó"
+
+# msgstr "E79: "
+msgid "E949: File changed while writing"
+msgstr "E949: Ôàéë çì³íèâëÿ ï³ä ÷àñ çàïèñó"
+
+msgid "E512: Close failed"
+msgstr "E512: Íå âäàëîñÿ çàêðèòè"
+
+msgid "E513: write error, conversion failed (make 'fenc' empty to override)"
+msgstr "E513: Ïîìèëêà çàïèñó, êîíâåðòàö³ÿ íå âäàëàñÿ (ñêèíüòå 'fenc')"
+
+#, c-format
+msgid ""
+"E513: write error, conversion failed in line %ld (make 'fenc' empty to "
+"override)"
+msgstr ""
+"E513: Ïîìèëêà çàïèñó, êîíâåðòàö³ÿ íå âäàëàñÿ ó ðÿäêó %ld (ñêèíüòå 'fenc')"
+
+msgid "E514: write error (file system full?)"
+msgstr "E514: Ïîìèëêà çàïèñó (ñê³í÷èëîñü â³ëüíå ì³ñöå?)"
+
+msgid " CONVERSION ERROR"
+msgstr " ÏÎÌÈËÊÀ ÊÎÍÂÅÐÒÀÖ²¯"
+
+#, c-format
+msgid " in line %ld;"
+msgstr " ó ðÿäêó %ld;"
+
+msgid "[Device]"
+msgstr "[Ïðèñòð³é]"
+
+msgid "[New]"
+msgstr "[Íîâèé]"
+
+msgid " [a]"
+msgstr "[ä]"
+
+msgid " appended"
+msgstr " äîïèñàíèé"
+
+msgid " [w]"
+msgstr "[ç]"
+
+msgid " written"
+msgstr " çàïèñàíèé"
+
+msgid "E205: Patchmode: can't save original file"
+msgstr "E205: Ëàòàííÿ: íå âäàëîñÿ çáåðåãòè îðèã³íàë"
+
+msgid "E206: patchmode: can't touch empty original file"
+msgstr "E206: Ëàòàííÿ: íå âäàëîñÿ ñòâîðèòè îðèã³íàë"
+
+msgid "E207: Can't delete backup file"
+msgstr "E207: Íå âäàëîñÿ çíèùèòè ðåçåðâíèé ôàéë"
+
+msgid ""
+"\n"
+"WARNING: Original file may be lost or damaged\n"
+msgstr ""
+"\n"
+"ÇÀÑÒÅÐÅÆÅÍÍß: Îðèã³íàë, ìàáóòü, âòðà÷åíèé ÷è ïîøêîäæåíèé\n"
+
+msgid "don't quit the editor until the file is successfully written!"
+msgstr "Íå âèõîäüòå ç ðåäàêòîðà, äîêè ôàéë íå çàïèñàíî!"
+
+msgid "[dos]"
+msgstr "[dos]"
+
+msgid "[dos format]"
+msgstr "[ôîðìàò dos]"
+
+msgid "[mac]"
+msgstr "[mac]"
+
+msgid "[mac format]"
+msgstr "[ôîðìàò mac]"
+
+msgid "[unix]"
+msgstr "[unix]"
+
+msgid "[unix format]"
+msgstr "[ôîðìàò unix]"
+
+msgid "1 line, "
+msgstr "îäèí ðÿäîê, "
+
+#, c-format
+msgid "%ld lines, "
+msgstr "%ld ðÿäê³â, "
+
+msgid "1 character"
+msgstr "îäèí ñèìâîë"
+
+#, c-format
+msgid "%lld characters"
+msgstr "%lld ñèìâîë³â"
+
+msgid "[noeol]"
+msgstr "[noeol]"
+
+msgid "[Incomplete last line]"
+msgstr "[Íåïîâíèé îñòàíí³é ðÿäîê]"
+
+msgid "WARNING: The file has been changed since reading it!!!"
+msgstr "ÇÀÑÒÅÐÅÆÅÍÍß: Ôàéë çì³íèâñÿ ç ÷àñó îñòàííüîãî ÷èòàííÿ!!!"
+
+msgid "Do you really want to write to it"
+msgstr "Âè ñïðàâä³ õî÷åòå éîãî ïåðåïèñàòè??"
+
+#, c-format
+msgid "E208: Error writing to \"%s\""
+msgstr "E208: Ïîìèëêà çàïèñó ó «%s»"
+
+#, c-format
+msgid "E209: Error closing \"%s\""
+msgstr "E209: Ïîìèëêà çàêðèòòÿ «%s»"
+
+#, c-format
+msgid "E210: Error reading \"%s\""
+msgstr "E210: Ïîìèëêà ÷èòàííÿ «%s»"
+
+msgid "E246: FileChangedShell autocommand deleted buffer"
+msgstr "E246: Àâòîêîìàíäà FileChangedShell çíèùèëà áóôåð"
+
+#, c-format
+msgid "E211: File \"%s\" no longer available"
+msgstr "E211: Ôàéë «%s» á³ëüøå íå äîñÿæíèé"
+
+#, c-format
+msgid ""
+"W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as "
+"well"
+msgstr "W12: Çàñòåðåæåííÿ: Ôàéë «%s» çì³íèâñÿ, àëå é áóôåð ó Vim òàêîæ"
+
+msgid "See \":help W12\" for more info."
+msgstr "Äèâ. «:help W12» äëÿ óòî÷íåííÿ."
+
+#, c-format
+msgid "W11: Warning: File \"%s\" has changed since editing started"
+msgstr "W11: Çàñòåðåæåííÿ: Ôàéë «%s» çì³íèâñÿ ï³ñëÿ ïî÷àòêó ðåäàãóâàííÿ"
+
+msgid "See \":help W11\" for more info."
+msgstr "Äèâ. «:help W11» äëÿ óòî÷íåííÿ."
+
+#, c-format
+msgid "W16: Warning: Mode of file \"%s\" has changed since editing started"
+msgstr "W16: Çàñòåðåæåííÿ: Ðåæèì ôàéëó «%s» çì³íèâñÿ ï³ñëÿ ïî÷àòêó ðåäàãóâàííÿ"
+
+msgid "See \":help W16\" for more info."
+msgstr "Äèâ. «:help W16» äëÿ óòî÷íåííÿ."
+
+#, c-format
+msgid "W13: Warning: File \"%s\" has been created after editing started"
+msgstr "W13: Çàñòåðåæåííÿ: Ôàéë «%s» áóëî ñòâîðåíî ï³ñëÿ ïî÷àòêó ðåäàãóâàííÿ"
+
+msgid "Warning"
+msgstr "Çàñòåðåæåííÿ"
+
+msgid ""
+"&OK\n"
+"&Load File"
+msgstr ""
+"&O:Ãàðàçä\n"
+"&L:Çàâàíòàæèòè"
+
+#, c-format
+msgid "E462: Could not prepare for reloading \"%s\""
+msgstr "E462: Íå âäàëîñÿ ï³äãîòóâàòè «%s», ùîá ïåðå÷èòàòè"
+
+#, c-format
+msgid "E321: Could not reload \"%s\""
+msgstr "E321: Íå âäàëîñÿ ïåðå÷èòàòè «%s»"
+
+msgid "--Deleted--"
+msgstr "--Çíèùåíî--"
+
+#, c-format
+msgid "auto-removing autocommand: %s <buffer=%d>"
+msgstr "Àâòîìàòè÷íå çíèùåííÿ àâòîêîìàíäè: %s <áóôåð=%d>"
+
+#, c-format
+msgid "E367: No such group: \"%s\""
+msgstr "E367: Íåìຠòàêî¿ ãðóïè: «%s»"
+
+msgid "E936: Cannot delete the current group"
+msgstr "E936: Íå âäàëîñÿ çíèùèòè öþ ãðóïó"
+
+msgid "W19: Deleting augroup that is still in use"
+msgstr "W19: Çíèùóºòüñÿ àâòîãðóïà âñå ùå ó âæèòêó"
+
+#, c-format
+msgid "E215: Illegal character after *: %s"
+msgstr "E215: Íåäîçâîëåíèé ñèìâîë ï³ñëÿ *: %s"
+
+# msgstr "E215: "
+#, c-format
+msgid "E216: No such event: %s"
+msgstr "E216: Íåìຠòàêî¿ ïî䳿: %s"
+
+# msgstr "E215: "
+#, c-format
+msgid "E216: No such group or event: %s"
+msgstr "E216: Íåìຠòàêî¿ ãðóïè ÷è ïî䳿: %s"
+
+# msgstr "E216: "
+msgid ""
+"\n"
+"--- Autocommands ---"
+msgstr ""
+"\n"
+"--- Àâòîêîìàíäè ---"
+
+#, c-format
+msgid "E680: <buffer=%d>: invalid buffer number "
+msgstr "E680: <áóôåð=%d>: íåêîðåêòíèé íîìåð áóôåðà "
+
+msgid "E217: Can't execute autocommands for ALL events"
+msgstr "E217: Íå ìîæó âèêîíóâàòè àâòîêîìàíäè äëÿ ÓÑ²Õ ïîä³é"
+
+# msgstr "E217: "
+msgid "No matching autocommands"
+msgstr "Íåìຠâ³äïîâ³äíèõ àâòîêîìàíä"
+
+msgid "E218: autocommand nesting too deep"
+msgstr "E218: Çàáàãàòî âêëàäåíèõ àâòîêîìàíä"
+
+# msgstr "E218: "
+#, c-format
+msgid "%s Autocommands for \"%s\""
+msgstr "Àâòîêîìàíäè %s äëÿ «%s»"
+
+#, c-format
+msgid "Executing %s"
+msgstr "Âèêîíóºòüñÿ %s"
+
+#, c-format
+msgid "autocommand %s"
+msgstr "àâòîêîìàíäà %s"
+
+msgid "E219: Missing {."
+msgstr "E219: Áðàêóº {."
+
+# msgstr "E219: "
+msgid "E220: Missing }."
+msgstr "E220: Áðàêóº }."
+
+# msgstr "E220: "
+msgid "E490: No fold found"
+msgstr "E490: Çãîðòîê íå çíàéäåíî"
+
+# msgstr "E349: "
+msgid "E350: Cannot create fold with current 'foldmethod'"
+msgstr "E350: Íå âäàëîñÿ ñòâîðèòè çãîðòêó ìåòîäîì 'foldmethod'"
+
+msgid "E351: Cannot delete fold with current 'foldmethod'"
+msgstr "E351: Íå âäàëîñÿ çíèùèòè çãîðòêó ìåòîäîì 'foldmethod'"
+
+#, c-format
+msgid "+--%3ld line folded "
+msgid_plural "+--%3ld lines folded "
+msgstr[0] "+--%3ld ðÿäîê çãîðíóòî "
+msgstr[1] "+--%3ld ðÿäê³â çãîðíóòî "
+
+msgid "E222: Add to read buffer"
+msgstr "E222: Äîäàòè äî áóôåðà ÷èòàííÿ"
+
+msgid "E223: recursive mapping"
+msgstr "E223: Çàì³íà ðåêóðñèâíà"
+
+# msgstr "E223: "
+#, c-format
+msgid "E224: global abbreviation already exists for %s"
+msgstr "E224: Çàãàëüíå ñêîðî÷åííÿ äëÿ %s âæå ³ñíóº"
+
+# msgstr "E224: "
+#, c-format
+msgid "E225: global mapping already exists for %s"
+msgstr "E225: Çàãàëüíà çàì³íà äëÿ %s âæå ³ñíóº"
+
+# msgstr "E225: "
+#, c-format
+msgid "E226: abbreviation already exists for %s"
+msgstr "E226: Âæå º ñêîðî÷åííÿ äëÿ %s"
+
+# msgstr "E226: "
+#, c-format
+msgid "E227: mapping already exists for %s"
+msgstr "E227: Âæå º çàì³íà äëÿ %s"
+
+# msgstr "E227: "
+msgid "No abbreviation found"
+msgstr "Ñêîðî÷åííÿ íå çíàéäåíî"
+
+msgid "No mapping found"
+msgstr "Çàì³íè íå çíàéäåíî"
+
+msgid "E228: makemap: Illegal mode"
+msgstr "E228: makemap: Íåïðèïóñòèìèé ðåæèì"
+
+msgid "<cannot open> "
+msgstr "<íå â³äêðèâàºòüñÿ> "
+
+#, c-format
+msgid "E616: vim_SelFile: can't get font %s"
+msgstr "E616: vim_SelFile: íå âäàëîñÿ îòðèìàòè øðèôò %s"
+
+msgid "E614: vim_SelFile: can't return to current directory"
+msgstr "E614: vim_SelFile: íå âäàëîñÿ ïîâåðíóòèñÿ â ïîòî÷íèé êàòàëîã"
+
+msgid "Pathname:"
+msgstr "Øëÿõ:"
+
+msgid "E615: vim_SelFile: can't get current directory"
+msgstr "E615: vim_SelFile: íå âäàëîñÿ îòðèìàòè ïîòî÷íèé êàòàëîã"
+
+msgid "OK"
+msgstr "Ãàðàçä"
+
+msgid "Cancel"
+msgstr "Ñêàñóâàòè"
+
+msgid "Vim dialog"
+msgstr "ijàëîã Vim"
+
+msgid "Scrollbar Widget: Could not get geometry of thumb pixmap."
+msgstr "Scrollbar Widget: Íå âäàëîñÿ âèçíà÷èòè ðîçì³ð ñêîðî÷åíî¿ êàðòèíêè."
+
+msgid "E232: Cannot create BalloonEval with both message and callback"
+msgstr "E232: Íå âäàëîñÿ ñòâîðèòè BalloonEval ç ïîâ³äîìëåííÿì ³ ôóíêö³ºþ"
+
+msgid "E851: Failed to create a new process for the GUI"
+msgstr "E851: Íå âäàëîñÿ ñòâîðèòè íîâèé ïðîöåñ äëÿ GUI"
+
+msgid "E852: The child process failed to start the GUI"
+msgstr "E852: Äî÷³ðí³é ïðîöåñ íå çì³ã çàïóñòèòè GUI"
+
+# msgstr "E228: "
+msgid "E229: Cannot start the GUI"
+msgstr "E229: Íå âäàëîñÿ çàïóñòèòè GUI"
+
+# msgstr "E229: "
+#, c-format
+msgid "E230: Cannot read from \"%s\""
+msgstr "E230: Íå âäàëîñÿ ïðî÷èòàòè ç «%s»"
+
+msgid "E665: Cannot start GUI, no valid font found"
+msgstr "E665: Íå âäàëîñÿ çàïóñòèòè GUI, íå çíàéäåíî øðèôò"
+
+# msgstr "E230: "
+msgid "E231: 'guifontwide' invalid"
+msgstr "E231: Íåêîðåêòíèé 'guifontwide'"
+
+msgid "E599: Value of 'imactivatekey' is invalid"
+msgstr "E599: Çíà÷åííÿ 'imactivatekey' íåêîðåêòíå"
+
+#, c-format
+msgid "E254: Cannot allocate color %s"
+msgstr "E254: Íå âäàëîñÿ îòðèìàòè êîë³ð %s"
+
+msgid "No match at cursor, finding next"
+msgstr "Íåìຠíàä êóðñîðîì, ïîøóê òðèâàº"
+
+msgid "_Cancel"
+msgstr "Ñêàñóâàòè"
+
+msgid "_Save"
+msgstr "Çáåðåãòè"
+
+msgid "_Open"
+msgstr "³äêðèòè"
+
+msgid "_OK"
+msgstr "Ãàðàçä"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"&Cancel"
+msgstr ""
+"&Y:Òàê\n"
+"&N:ͳ\n"
+"&C:Ñêàñóâàòè"
+
+msgid "Yes"
+msgstr "Òàê"
+
+msgid "No"
+msgstr "ͳ"
+
+msgid "Input _Methods"
+msgstr "Ìåòîäè ââåäåííÿ"
+
+msgid "VIM - Search and Replace..."
+msgstr "VIM - Çíàéòè é çàì³íèòè..."
+
+msgid "VIM - Search..."
+msgstr "VIM - Ïîøóê..."
+
+msgid "Find what:"
+msgstr "Çíàéòè:"
+
+msgid "Replace with:"
+msgstr "Çàì³íèòè íà:"
+
+msgid "Match whole word only"
+msgstr "Ëèøå ïîâíå ñëîâî"
+
+msgid "Match case"
+msgstr "Çâàæàòè íà ðåã³ñòð"
+
+msgid "Direction"
+msgstr "Íàïðÿì"
+
+msgid "Up"
+msgstr "Âãîðó"
+
+msgid "Down"
+msgstr "Óíèç"
+
+msgid "Find Next"
+msgstr "Íàñòóïíå"
+
+msgid "Replace"
+msgstr "Çàì³íèòè"
+
+msgid "Replace All"
+msgstr "Çàì³íèòè óñ³"
+
+msgid "_Close"
+msgstr "Çàêðèòè"
+
+msgid "Vim: Received \"die\" request from session manager\n"
+msgstr "Vim: Îòðèìàâ çàïèò «die» â³ä ìåíåäæåðà ñåñ³é\n"
+
+msgid "Close tab"
+msgstr "Çàêðèòè âêëàäêó"
+
+msgid "New tab"
+msgstr "Íîâà âêëàäêà"
+
+msgid "Open Tab..."
+msgstr "³äêðèòè âêëàäêó..."
+
+msgid "Vim: Main window unexpectedly destroyed\n"
+msgstr "Vim: Íåñïîä³âàíî çíèùèëîñÿ ãîëîâíå â³êíî\n"
+
+msgid "&Filter"
+msgstr "&F:Ô³ëüòðóâàòè"
+
+msgid "&Cancel"
+msgstr "&C:Ñêàñóâàòè"
+
+msgid "Directories"
+msgstr "Êàòàëîãè"
+
+msgid "Filter"
+msgstr "Ô³ëüòð"
+
+msgid "&Help"
+msgstr "&H:Äîïîìîãà"
+
+msgid "Files"
+msgstr "Ôàéëè"
+
+msgid "&OK"
+msgstr "&O:Ãàðàçä"
+
+msgid "Selection"
+msgstr "Âèä³ëåííÿ"
+
+msgid "Find &Next"
+msgstr "&N:Çíàéòè äàë³"
+
+msgid "&Replace"
+msgstr "&R:Çàì³íèòè"
+
+msgid "Replace &All"
+msgstr "&A:Çàì³íèòè óñ³"
+
+msgid "&Undo"
+msgstr "&U:Ñêàñóâàòè"
+
+msgid "Open tab..."
+msgstr "³äêðèòè âêëàäêó..."
+
+# msgstr "E245: "
+msgid "Find string (use '\\\\' to find a '\\')"
+msgstr "Çíàéòè ðÿäîê ('\\\\' ùîá çíàéòè '\\')"
+
+msgid "Find & Replace (use '\\\\' to find a '\\')"
+msgstr "Çíàéòè ³ çàì³íèòè ('\\\\' ùîá çíàéòè '\\')"
+
+msgid "Not Used"
+msgstr "Íåìàº"
+
+msgid "Directory\t*.nothing\n"
+msgstr "Êàòàëîã\t*.í³÷îãî\n"
+
+#, c-format
+msgid "E671: Cannot find window title \"%s\""
+msgstr "E671: Íå âäàëîñÿ çíàéòè â³êíî «%s»"
+
+#, c-format
+msgid "E243: Argument not supported: \"-%s\"; Use the OLE version."
+msgstr "E243: Àðãóìåíò íå ï³äòðèìóºòüñÿ: «-%s»; êîðèñòóéòåñü âåðñ³ºþ ç OLE."
+
+msgid "E672: Unable to open window inside MDI application"
+msgstr "E672: Íå âäàëîñÿ â³äêðèòè â³êíî âñåðåäèí³ ïðîãðàìè MDI"
+
+msgid "Vim E458: Cannot allocate colormap entry, some colors may be incorrect"
+msgstr ""
+"Vim E458: Íåìຠâ³ëüíèõ êîì³ðîê ó ïàë³òð³, äåÿê³ êîëüîðè ìîæóòü áóòè "
+"íåïðàâèëüí³"
+
+#, c-format
+msgid "E250: Fonts for the following charsets are missing in fontset %s:"
+msgstr "E250: Øðèôòè äëÿ öèõ ñèìâîë³â â³äñóòí³ ó íàáîð³ %s:"
+
+# msgstr "E250: "
+#, c-format
+msgid "E252: Fontset name: %s"
+msgstr "E252: Íàçâà íàáîðó øðèôò³â: %s"
+
+# msgstr "E252: "
+#, c-format
+msgid "Font '%s' is not fixed-width"
+msgstr "Øðèôò '%s' íå º ìîíîøèðèííèì"
+
+#, c-format
+msgid "E253: Fontset name: %s"
+msgstr "E253: Íàçâà íàáîðó øðèôò³â: %s"
+
+#, c-format
+msgid "Font0: %s"
+msgstr "Øðèôò0: %s"
+
+#, c-format
+msgid "Font1: %s"
+msgstr "Øðèôò1: %s"
+
+#, c-format
+msgid "Font%ld width is not twice that of font0"
+msgstr "Øèðèíà øðèôòó%ld íå á³ëüøà óäâ³÷³ çà øèðèíó øðèôòó0"
+
+#, c-format
+msgid "Font0 width: %ld"
+msgstr "Øèðèíà øðèôòó0: %ld"
+
+#, c-format
+msgid "Font1 width: %ld"
+msgstr "Øèðèíà øðèôòó1: %ld"
+
+msgid "Invalid font specification"
+msgstr "Íåêîðåêòíà ñïåöèô³êàö³ÿ øðèôòó"
+
+msgid "&Dismiss"
+msgstr "&D:Ïðèïèíèòè"
+
+msgid "no specific match"
+msgstr "íåìຠêîíêðåòíîãî çá³ãó"
+
+# msgstr "E234: "
+msgid "Vim - Font Selector"
+msgstr "Vim - Âèá³ð øðèôòó"
+
+msgid "Name:"
+msgstr "Íàçâà:"
+
+msgid "Show size in Points"
+msgstr "Ïîêàçàòè ðîçì³ð ó ïóíêòàõ"
+
+msgid "Encoding:"
+msgstr "Êîäóâàííÿ:"
+
+msgid "Font:"
+msgstr "Øðèôò:"
+
+msgid "Style:"
+msgstr "Ñòèëü:"
+
+msgid "Size:"
+msgstr "Ðîçì³ð:"
+
+msgid "E256: Hangul automata ERROR"
+msgstr "E256: Ïîìèëêà àâòîìàòó Hangul"
+
+msgid "E550: Missing colon"
+msgstr "E550: Ïðîïóùåíî äâîêðàïêó"
+
+# msgstr "E347: "
+msgid "E551: Illegal component"
+msgstr "E551: Íåêîðåêòíèé êîìïîíåíò"
+
+msgid "E552: digit expected"
+msgstr "E552: î÷³êóºòüñÿ öèôðà"
+
+#, c-format
+msgid "Page %d"
+msgstr "Ñòîð³íêà %d"
+
+msgid "No text to be printed"
+msgstr "ͳ÷îãî äðóêóâàòè"
+
+#, c-format
+msgid "Printing page %d (%d%%)"
+msgstr "Äðóêóºòüñÿ ñòîð³íêà %d (%d%%)"
+
+#, c-format
+msgid " Copy %d of %d"
+msgstr " Êîï³ÿ %d ç %d"
+
+#, c-format
+msgid "Printed: %s"
+msgstr "Íàäðóêîâàíî: %s"
+
+msgid "Printing aborted"
+msgstr "Äðóê ïåðåðâàíî"
+
+msgid "E455: Error writing to PostScript output file"
+msgstr "E455: Íå âäàëîñÿ çàïèñàòè âèõ³äíèé ôàéë PostScript"
+
+#, c-format
+msgid "E624: Can't open file \"%s\""
+msgstr "E624: Íå âäàëîñÿ â³äêðèòè ôàéë «%s»"
+
+#, c-format
+msgid "E457: Can't read PostScript resource file \"%s\""
+msgstr "E457: Íå âäàëîñÿ ïðî÷èòàòè ôàéë ðåñóðñ³â PostScript «%s»"
+
+#, c-format
+msgid "E618: file \"%s\" is not a PostScript resource file"
+msgstr "E618: «%s» íå º ôàéëîì ðåñóðñ³â PostScript"
+
+#, c-format
+msgid "E619: file \"%s\" is not a supported PostScript resource file"
+msgstr "E619: «%s» íå º ï³äòðèìóâàíèì ôàéëîì ðåñóðñ³â PostScript"
+
+#, c-format
+msgid "E621: \"%s\" resource file has wrong version"
+msgstr "E621: Íåïðàâèëüíà âåðñ³ÿ ôàéëó ðåñóðñ³â «%s»"
+
+msgid "E673: Incompatible multi-byte encoding and character set."
+msgstr "E673: Íåñóì³ñí³ áàãàòîáàéòîâå êîäóâàííÿ é íàá³ð ñèìâîë³â."
+
+msgid "E674: printmbcharset cannot be empty with multi-byte encoding."
+msgstr ""
+"E674: printmbcharset íå ìîæå áóòè ïîðîæí³ì ç áàãàòîáàéòîâèì êîäóâàííÿì."
+
+msgid "E675: No default font specified for multi-byte printing."
+msgstr "E675: Íå çàçíà÷åíî øðèôò äëÿ áàãàòîáàéòîâîãî äðóêó."
+
+msgid "E324: Can't open PostScript output file"
+msgstr "E324: Íå âäàëîñÿ â³äêðèòè ôàéë PostScript äëÿ âèâîäó"
+
+#, c-format
+msgid "E456: Can't open file \"%s\""
+msgstr "E456: Íå âäàëîñÿ â³äêðèòè ôàéë «%s»"
+
+msgid "E456: Can't find PostScript resource file \"prolog.ps\""
+msgstr "E456: Íå âäàëîñÿ çíàéòè ôàéë ðåñóðñ³â PostScript «prolog.ps»"
+
+msgid "E456: Can't find PostScript resource file \"cidfont.ps\""
+msgstr "E456: Íå âäàëîñÿ çíàéòè ôàéë ðåñóðñ³â PostScript «cidfont.ps»"
+
+#, c-format
+msgid "E456: Can't find PostScript resource file \"%s.ps\""
+msgstr "E456: Íå âäàëîñÿ çíàéòè ôàéë ðåñóðñ³â PostScript «%s.ps»"
+
+#, c-format
+msgid "E620: Unable to convert to print encoding \"%s\""
+msgstr "E620: Íå âäàëîñÿ ïåðåòâîðèòè äî êîäóâàííÿ äðóêó «%s»"
+
+msgid "Sending to printer..."
+msgstr "³äñèëàºòüñÿ íà ïðèíòåð..."
+
+msgid "E365: Failed to print PostScript file"
+msgstr "E365: Íå âäàëîñÿ íàäðóêóâàòè ôàéë PostScript"
+
+msgid "Print job sent."
+msgstr "Çàâäàííÿ äðóêó â³ä³ñëàíî."
+
+# msgstr "E255: "
+msgid "Add a new database"
+msgstr "Äîäàòè íîâó áàçó äàíèõ"
+
+msgid "Query for a pattern"
+msgstr "Çàïèò çà çðàçêîì"
+
+msgid "Show this message"
+msgstr "Ïîêàçàòè öå ïîâ³äîìëåííÿ"
+
+msgid "Kill a connection"
+msgstr "Çíèùèòè ç'ºäíàííÿ"
+
+msgid "Reinit all connections"
+msgstr "Ïåðåçàïóñòèòè óñ³ ç'ºäíàííÿ"
+
+msgid "Show connections"
+msgstr "Ïîêàçàòè ç'ºäíàííÿ"
+
+#, c-format
+msgid "E560: Usage: cs[cope] %s"
+msgstr "E560: Âèêîðèñòàííÿ: cs[cope] %s"
+
+msgid "This cscope command does not support splitting the window.\n"
+msgstr "Öÿ êîìàíäà cscope íå â쳺 ä³ëèòè â³êíî.\n"
+
+msgid "E562: Usage: cstag <ident>"
+msgstr "E562: Âèêîðèñòàííÿ: cstag <³äåíòèô-îð>"
+
+msgid "E257: cstag: tag not found"
+msgstr "E257: cstag: ì³òêó íå çíàéäåíî"
+
+# msgstr "E257: "
+#, c-format
+msgid "E563: stat(%s) error: %d"
+msgstr "E563: stat(%s) ïîìèëêà: %d"
+
+msgid "E563: stat error"
+msgstr "E563: ïîìèëêà stat"
+
+#, c-format
+msgid "E564: %s is not a directory or a valid cscope database"
+msgstr "E564: %s íå º í³ êàòàëîãîì, í³ áàçîþ äàíèõ cscope"
+
+#, c-format
+msgid "Added cscope database %s"
+msgstr "Äîäàíî áàçó äàíèõ cscope %s"
+
+#, c-format
+msgid "E262: error reading cscope connection %ld"
+msgstr "E262: Ïîìèëêà ÷èòàííÿ ç³ ç'ºäíàííÿ cscope %ld"
+
+msgid "E561: unknown cscope search type"
+msgstr "E561: Íåâ³äîìèé òèï ïîøóêó cscope"
+
+msgid "E566: Could not create cscope pipes"
+msgstr "E566: Íå âäàëîñÿ ñòâîðèòè êàíàëè äî cscope"
+
+msgid "E622: Could not fork for cscope"
+msgstr "E622: Íå âäàëîñÿ ðîçä³ëèòè ïðîöåñ äëÿ cscope"
+
+msgid "cs_create_connection setpgid failed"
+msgstr "cs_create_connection: ïîìèëêà setpgid"
+
+msgid "cs_create_connection exec failed"
+msgstr "cs_create_connection: ïîìèëêà ï³ä ÷àñ âèêîíàííÿ"
+
+msgid "cs_create_connection: fdopen for to_fp failed"
+msgstr "cs_create_connection: fdopen äëÿ to_fp íå âäàâñÿ"
+
+msgid "cs_create_connection: fdopen for fr_fp failed"
+msgstr "cs_create_connection: fdopen äëÿ fr_fp íå âäàâñÿ"
+
+msgid "E623: Could not spawn cscope process"
+msgstr "E623: Íå âäàëîñÿ ñòâîðèòè ïðîöåñ cscope"
+
+msgid "E567: no cscope connections"
+msgstr "E567: æîäíîãî ç'ºäíàííÿ ³ç cscope"
+
+#, c-format
+msgid "E469: invalid cscopequickfix flag %c for %c"
+msgstr "E469: Íåêîðåêòíèé ïðàïîðåöü cscopequickfix %c äëÿ %c"
+
+# msgstr "E258: "
+#, c-format
+msgid "E259: no matches found for cscope query %s of %s"
+msgstr "E259: Äëÿ çàïèòó cscope %s ç %s í³÷îãî íå çíàéäåíî"
+
+# msgstr "E259: "
+msgid "cscope commands:\n"
+msgstr "Êîìàíäè cscope:\n"
+
+#, c-format
+msgid "%-5s: %s%*s (Usage: %s)"
+msgstr "%-5s: %s%*s (Âèêîðèñòàííÿ: %s)"
+
+msgid ""
+"\n"
+" a: Find assignments to this symbol\n"
+" c: Find functions calling this function\n"
+" d: Find functions called by this function\n"
+" e: Find this egrep pattern\n"
+" f: Find this file\n"
+" g: Find this definition\n"
+" i: Find files #including this file\n"
+" s: Find this C symbol\n"
+" t: Find this text string\n"
+msgstr ""
+"\n"
+" a: Çíàéòè ïðèñâîºííÿ öüîãî ñèìâîëó\n"
+" c: Çíàéòè ôóíêö³¿, ùî âèêëèêàþòü öþ ôóíêö³þ\n"
+" d: Çíàéòè ôóíêö³¿, ùî âèêëèêàþòüñÿ ö³ºþ ôóíêö³ºþ\n"
+" e: Çíàéòè öåé øàáëîí egrep\n"
+" f: Çíàéòè öåé ôàéë\n"
+" g: Çíàéòè öå âèçíà÷åííÿ\n"
+" i: Çíàéòè ôàéëè, ÿê³ âêëþ÷àþòü â ñåáå öåé ôàéë\n"
+" s: Çíàéòè öåé ñèìâîë C\n"
+" t: Çíàéòè öåé òåêñò\n"
+
+#, c-format
+msgid "E625: cannot open cscope database: %s"
+msgstr "E625: Íå âäàëîñÿ â³äêðèòè áàçó äàíèõ cscope: %s"
+
+msgid "E626: cannot get cscope database information"
+msgstr "E626: Íå âäàëîñÿ îòðèìàòè ³íôîðìàö³þ ç áàçè äàíèõ cscope"
+
+msgid "E568: duplicate cscope database not added"
+msgstr "E568: Ïîâòîðíà áàçà äàíèõ cscope íå äîäàíà"
+
+# msgstr "E260: "
+#, c-format
+msgid "E261: cscope connection %s not found"
+msgstr "E261: Ç'ºäíàííÿ ç cscope %s íå çíàéäåíî"
+
+#, c-format
+msgid "cscope connection %s closed"
+msgstr "Ç'ºäíàííÿ ç cscope %s çàê³í÷åíî"
+
+msgid "E570: fatal error in cs_manage_matches"
+msgstr "E570: Ôàòàëüíà ïîìèëêà â cs_manage_matches"
+
+#, c-format
+msgid "Cscope tag: %s"
+msgstr "Òå´ cscope: %s"
+
+msgid ""
+"\n"
+" # line"
+msgstr ""
+"\n"
+" # ðÿäîê"
+
+msgid "filename / context / line\n"
+msgstr "ôàéë / êîíòåêñò / ðÿäîê\n"
+
+#, c-format
+msgid "E609: Cscope error: %s"
+msgstr "E609: Ïîìèëêà cscope: %s"
+
+msgid "All cscope databases reset"
+msgstr "Óñ³ áàçè äàíèõ cscope ïåðåçàâàíòàæåíî"
+
+msgid "no cscope connections\n"
+msgstr "Æîäíîãî ç'ºäíàííÿ ç cscope\n"
+
+msgid " # pid database name prepend path\n"
+msgstr " # pid íàçâà áàçè äàíèõ øëÿõ\n"
+
+msgid "Lua library cannot be loaded."
+msgstr "Íå âäàëîñÿ çàâàíòàæèòè á³áë³îòåêó Lua"
+
+msgid "cannot save undo information"
+msgstr "íå âäàëîñÿ çáåðåãòè ³íôîðìàö³þ äëÿ ñêàñóâàííÿ"
+
+msgid ""
+"E815: Sorry, this command is disabled, the MzScheme libraries could not be "
+"loaded."
+msgstr ""
+"E815: Âèáà÷òå, öÿ êîìàíäà âèìêíåíà, á³áë³îòåêè MzScheme íå ìîæóòü áóòè "
+"çàâàíòàæåí³."
+
+msgid ""
+"E895: Sorry, this command is disabled, the MzScheme's racket/base module "
+"could not be loaded."
+msgstr ""
+"E895: Âèáà÷òå, öÿ êîìàíäà âèìêíåíà, á³áë³îòåêè MzScheme íå ìîæóòü áóòè "
+"çàâàíòàæåí³."
+
+msgid "invalid expression"
+msgstr "íåêîðåêòíèé âèðàç"
+
+msgid "expressions disabled at compile time"
+msgstr "îáðîáêó âèðàç³â âèìêíåíî ï³ä ÷àñ êîìï³ëÿö³¿"
+
+msgid "hidden option"
+msgstr "ïðèõîâàíà îïö³ÿ"
+
+msgid "unknown option"
+msgstr "íåâ³äîìà îïö³ÿ"
+
+msgid "window index is out of range"
+msgstr "íåêîðåêòíèé íîìåð â³êíà"
+
+msgid "couldn't open buffer"
+msgstr "íå âäàëîñÿ â³äêðèòè áóôåð"
+
+msgid "cannot delete line"
+msgstr "íåìîæëèâî çíèùèòè ðÿäîê"
+
+msgid "cannot replace line"
+msgstr "íåìîæëèâî çàì³íèòè ðÿäîê"
+
+msgid "cannot insert line"
+msgstr "íå âäàëîñÿ âñòàâèòè ðÿäîê"
+
+msgid "string cannot contain newlines"
+msgstr "á³ëüøå í³æ îäèí ðÿäîê"
+
+msgid "error converting Scheme values to Vim"
+msgstr "íå âäàëîñÿ ïåðåòâîðèòè çíà÷åííÿ Scheme ó Vim"
+
+msgid "Vim error: ~a"
+msgstr "Ïîìèëêà Vim: ~a"
+
+msgid "Vim error"
+msgstr "Ïîìèëêà Vim"
+
+msgid "buffer is invalid"
+msgstr "áóôåð íåïðèäàòíèé"
+
+msgid "window is invalid"
+msgstr "â³êíî íåïðèäàòíå"
+
+msgid "linenr out of range"
+msgstr "íîìåð ðÿäêà çà ìåæàìè ôàéëó"
+
+msgid "not allowed in the Vim sandbox"
+msgstr "íå äîçâîëåíî ó ï³ñî÷íèö³ Vim"
+
+msgid "E837: This Vim cannot execute :py3 after using :python"
+msgstr "E837: Python: Íå ìîæíà âèêîðèñòàòè :py ³ :py3 â îäíîìó ñåàíñ³"
+
+msgid ""
+"E263: Sorry, this command is disabled, the Python library could not be "
+"loaded."
+msgstr ""
+"E263: Âèáà÷òå, öÿ êîìàíäà âèìêíåíà, á³áë³îòåêà Python íå ìîæå áóòè "
+"çàâàíòàæåíà."
+
+msgid "E836: This Vim cannot execute :python after using :py3"
+msgstr "E836: Python: Íå ìîæíà âèêîðèñòàòè :py ³ :py3 â îäíîìó ñåàíñ³"
+
+msgid ""
+"E887: Sorry, this command is disabled, the Python's site module could not be "
+"loaded."
+msgstr ""
+"E887: Âèáà÷òå, öÿ êîìàíäà âèìêíåíà, ì³ñöåâà á³áë³îòåêà Python íå ìîæå áóòè "
+"çàâàíòàæåíà."
+
+msgid "E659: Cannot invoke Python recursively"
+msgstr "E659: Íå ìîæíà ðåêóðñèâíî âèêëèêàòè Python"
+
+msgid "E265: $_ must be an instance of String"
+msgstr "E265: $_ ìຠáóòè åêçåìïëÿðîì String"
+
+msgid ""
+"E266: Sorry, this command is disabled, the Ruby library could not be loaded."
+msgstr ""
+"E266: Âèáà÷òå, öÿ êîìàíäà âèìêíåíà, á³áë³îòåêà Ruby íå ìîæå áóòè çàâàíòàæåíà."
+
+# msgstr "E414: "
+msgid "E267: unexpected return"
+msgstr "E267: íåñïîä³âàíèé return"
+
+msgid "E268: unexpected next"
+msgstr "E268: íåñïîä³âàíèé next"
+
+msgid "E269: unexpected break"
+msgstr "E269: íåñïîä³âàíèé break"
+
+msgid "E270: unexpected redo"
+msgstr "E270: íåñïîä³âàíèé redo"
+
+msgid "E271: retry outside of rescue clause"
+msgstr "E271: retry ïîçà rescue"
+
+msgid "E272: unhandled exception"
+msgstr "E272: Íåîáðîáëåíèé âèíÿòîê"
+
+# msgstr "E233: "
+#, c-format
+msgid "E273: unknown longjmp status %d"
+msgstr "E273: Íåâ³äîìèé ñòàòóñ longjmp: %d"
+
+msgid "invalid buffer number"
+msgstr "íåïðàâèëüíà íàçâà áóôåðà"
+
+msgid "not implemented yet"
+msgstr "ùå íå ðåàë³çîâàíî"
+
+msgid "cannot set line(s)"
+msgstr "íå âäàëîñÿ âñòàíîâèòè ðÿäêè"
+
+msgid "invalid mark name"
+msgstr "íåïðàâèëüíà íàçâà ïîçíà÷êè"
+
+# msgstr "E19: "
+msgid "mark not set"
+msgstr "ïîì³òêó íå âêàçàíî"
+
+#, c-format
+msgid "row %d column %d"
+msgstr "ðÿäîê %d êîëîíêà %d"
+
+msgid "cannot insert/append line"
+msgstr "Íå âäàëîñÿ âñòàâèòè/äîäàòè ðÿäîê"
+
+msgid "line number out of range"
+msgstr "íîìåð ðÿäêà çà ìåæàìè ôàéëó"
+
+msgid "unknown flag: "
+msgstr "íåâ³äîìèé ïðàïîðåöü: "
+
+msgid "unknown vimOption"
+msgstr "Íåâ³äîìà vimOption"
+
+msgid "keyboard interrupt"
+msgstr "ïåðåðâàíî ç êëàâ³àòóðè"
+
+msgid "vim error"
+msgstr "ïîìèëêà Vim"
+
+msgid "cannot create buffer/window command: object is being deleted"
+msgstr "íå âäàëîñÿ ñòâîðèòè êîìàíäó â³êíà/áóôåðà: îá'ºêò çíèùóºòüñÿ"
+
+msgid ""
+"cannot register callback command: buffer/window is already being deleted"
+msgstr "Íå âäàëîñÿ çàðåºñòðóâàòè ïîä³þ: áóôåð/â³êíî óæå çíèùóºòüñÿ"
+
+msgid ""
+"E280: TCL FATAL ERROR: reflist corrupt!? Please report this to vim-dev@vim."
+"org"
+msgstr ""
+"E280: ÔÀÒÀËÜÍÀ ÏÎÌÈËÊÀ TCL: ìîæëèâî ïîøêîäæåíî ñïèñîê ïîñèëàíü!? Áóäü ëàñêà, "
+"ïîâ³äîìòå ó vim-dev@vim.org"
+
+msgid "cannot register callback command: buffer/window reference not found"
+msgstr ""
+"Íå âäàëîñÿ çàðåºñòðóâàòè êîìàíäó ïî䳿: ïîñèëàííÿ íà áóôåð/â³êíî íå çíàéäåíî"
+
+msgid ""
+"E571: Sorry, this command is disabled: the Tcl library could not be loaded."
+msgstr ""
+"E571: Âèáà÷òå, öÿ êîìàíäà âèìêíåíà, á³áë³îòåêà Tcl íå ìîæå áóòè çàâàíòàæåíà."
+
+#, c-format
+msgid "E572: exit code %d"
+msgstr "E572: Êîä âèõîäó %d"
+
+msgid "cannot get line"
+msgstr "íå âäàëîñÿ ä³ñòàòè ðÿäîê"
+
+msgid "Unable to register a command server name"
+msgstr "Íå âäàëîñÿ çàðåºñòðóâàòè íàçâó ñåðâåðà êîìàíä"
+
+msgid "E248: Failed to send command to the destination program"
+msgstr "E248: Íå âäàëîñÿ â³ä³ñëàòè êîìàíäó äî ïðîãðàìè-ö³ë³"
+
+#, c-format
+msgid "E573: Invalid server id used: %s"
+msgstr "E573: Âèêîðèñòàíî íåêîðåêòíèé ³äåíòèô³êàòîð ñåðâåðà: %s"
+
+msgid "E251: VIM instance registry property is badly formed. Deleted!"
+msgstr "E251: Ðåêâ³çèò ðåºñòðó çðàçêó VIM ñôîðìîâàíèé íåïðàâèëüíî. Çíèùåíî!"
+
+#, c-format
+msgid "E938: Duplicate key in JSON: \"%s\""
+msgstr "E938: Ïîâòîðåííÿ êëþ÷à â JSON: «%s»"
+
+# msgstr "E404: "
+#, c-format
+msgid "E696: Missing comma in List: %s"
+msgstr "E696: Áðàêóº êîìè ó ñïèñêó: %s"
+
+#, c-format
+msgid "E697: Missing end of List ']': %s"
+msgstr "E697: Íåìຠê³íö³âêè ñïèñêó ']': %s"
+
+msgid "Unknown option argument"
+msgstr "Íåâ³äîìèé àðãóìåíò îïö³¿"
+
+msgid "Too many edit arguments"
+msgstr "Çàáàãàòî àðãóìåíò³â"
+
+msgid "Argument missing after"
+msgstr "Ïðîïóùåíî àðãóìåíò ï³ñëÿ"
+
+msgid "Garbage after option argument"
+msgstr "Ñì³òòÿ ï³ñëÿ àðãóìåíòó îïö³¿"
+
+msgid "Too many \"+command\", \"-c command\" or \"--cmd command\" arguments"
+msgstr "Çàáàãàòî àðãóìåíò³â ó «+êîìàíäà», «-c êîìàíäà» àáî «--cmd êîìàíäà»"
+
+# msgstr "E14: "
+msgid "Invalid argument for"
+msgstr "Íåïðàâèëüíèé àðãóìåíò ó"
+
+#, c-format
+msgid "%d files to edit\n"
+msgstr "%d ôàéëè(³â)\n"
+
+msgid "netbeans is not supported with this GUI\n"
+msgstr "netbeans íå ï³äòðèìóºòüñÿ ç öèì GUI\n"
+
+msgid "'-nb' cannot be used: not enabled at compile time\n"
+msgstr "Íå ìîæíà âèêîðèñòàòè '-nb': íå äîçâîëåíî ï³ä ÷àñ êîìï³ëÿö³¿\n"
+
+msgid "This Vim was not compiled with the diff feature."
+msgstr "Öÿ âåðñ³ÿ Vim íå áóëà ñêîìï³ëüîâàíà ç ï³äòðèìêîþ ïîð³âíÿííÿ."
+
+msgid "Attempt to open script file again: \""
+msgstr "Ñïðîáà ïîâòîðíî â³äêðèòè ñêðèïò: \""
+
+msgid "Cannot open for reading: \""
+msgstr "Íå âäàëîñÿ ïðî÷èòàòè: \""
+
+msgid "Cannot open for script output: \""
+msgstr "Íå âäàëîñÿ â³äêðèòè ÿê âèõ³äíèé ôàéë: \""
+
+msgid "Vim: Error: Failure to start gvim from NetBeans\n"
+msgstr "Vim: Ïîìèëêà: Íå âäàëîñÿ çàïóñòèòè gvim äëÿ NetBeans\n"
+
+msgid "Vim: Error: This version of Vim does not run in a Cygwin terminal\n"
+msgstr "Vim: Ïîìèëêà: Öÿ âåðñ³ÿ Vim íå ïðàöþº ó òåðì³íàë³ Cygwin\n"
+
+msgid "Vim: Warning: Output is not to a terminal\n"
+msgstr "Vim: Çàñòåðåæåííÿ: Âèâ³ä íå ó òåðì³íàë\n"
+
+msgid "Vim: Warning: Input is not from a terminal\n"
+msgstr "Vim: Çàñòåðåæåííÿ: Óâåäåííÿ íå ç òåðì³íàëó\n"
+
+msgid "pre-vimrc command line"
+msgstr "êîìàíäè ïåðåä vimrc"
+
+#, c-format
+msgid "E282: Cannot read from \"%s\""
+msgstr "E282: Íå âäàëîñÿ ïðî÷èòàòè ç «%s»"
+
+# msgstr "E282: "
+msgid ""
+"\n"
+"More info with: \"vim -h\"\n"
+msgstr ""
+"\n"
+"ijçíàéòåñÿ á³ëüøå: «vim -h»\n"
+
+msgid "[file ..] edit specified file(s)"
+msgstr "[ôàéë ..] ðåäàãóâàòè âêàçàí³ ôàéëè"
+
+msgid "- read text from stdin"
+msgstr "- ÷èòàòè òåêñò ç stdin"
+
+msgid "-t tag edit file where tag is defined"
+msgstr "-t ïîì³òêà ïåðåéòè äî ì³òêè"
+
+msgid "-q [errorfile] edit file with first error"
+msgstr "-q [ôàéë] ïåðåéòè äî ïåðøî¿ ïîìèëêè"
+
+msgid ""
+"\n"
+"\n"
+"Usage:"
+msgstr ""
+"\n"
+"\n"
+"Âæèòîê:"
+
+msgid " vim [arguments] "
+msgstr " vim [àðãóìåíòè] "
+
+msgid ""
+"\n"
+" or:"
+msgstr ""
+"\n"
+" àáî:"
+
+msgid ""
+"\n"
+"Where case is ignored prepend / to make flag upper case"
+msgstr ""
+"\n"
+"ßêùî ðåã³ñòð ³ãíîðóºòüñÿ, äîäàéòå / ñïåðåäó ùîá ïðàïîðåöü áóâ ó âåðõíüîìó "
+"ðåã³ñòð³."
+
+msgid ""
+"\n"
+"\n"
+"Arguments:\n"
+msgstr ""
+"\n"
+"\n"
+"Àðãóìåíòè:\n"
+
+msgid "--\t\t\tOnly file names after this"
+msgstr "--\t\t\tËèøå íàçâè ôàéë³â ï³ñëÿ öüîãî"
+
+msgid "--literal\t\tDon't expand wildcards"
+msgstr "--literal\t\tÍå ðîçêðèâàòè øàáëîíè"
+
+msgid "-register\t\tRegister this gvim for OLE"
+msgstr "-register\t\tÇàðåºñòðóâàòè öåé gvim äëÿ OLE"
+
+msgid "-unregister\t\tUnregister gvim for OLE"
+msgstr "-unregister\t\tÑêàñóâàòè ðåºñòðàö³þ öüîãî gvim äëÿ OLE"
+
+msgid "-g\t\t\tRun using GUI (like \"gvim\")"
+msgstr "-g\t\t\tÇàïóñòèòè GUI (í³áè «gvim»)"
+
+msgid "-f or --nofork\tForeground: Don't fork when starting GUI"
+msgstr "-f ÷è --nofork\tÏåðåäí³é ïëàí: òðèìàòè òåðì³íàë ï³ñëÿ çàïóñêó GUI"
+
+msgid "-v\t\t\tVi mode (like \"vi\")"
+msgstr "-v\t\t\tÐåæèì Vi (í³áè «vi»)"
+
+msgid "-e\t\t\tEx mode (like \"ex\")"
+msgstr "-e\t\t\tÐåæèì Ex (í³áè «ex»)"
+
+msgid "-E\t\t\tImproved Ex mode"
+msgstr "-E\t\t\tÏîêðàùåíèé ðåæèì Ex"
+
+msgid "-s\t\t\tSilent (batch) mode (only for \"ex\")"
+msgstr "-s\t\t\tÌîâ÷àçíèé (ïàêåòíèé) ðåæèì (ëèøå äëÿ «ex»)"
+
+msgid "-d\t\t\tDiff mode (like \"vimdiff\")"
+msgstr "-d\t\t\tÐåæèì ïîð³âíÿííÿ (í³áè «vimdiff»)"
+
+msgid "-y\t\t\tEasy mode (like \"evim\", modeless)"
+msgstr "-y\t\t\tÏðîñòèé ðåæèì (í³áè «evim», áåç ðåæèì³â)"
+
+msgid "-R\t\t\tReadonly mode (like \"view\")"
+msgstr "-R\t\t\tÐåæèì ïåðåãëÿäó (í³áè «view»)"
+
+msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
+msgstr "-Z\t\t\tÎáìåæåíèé ðåæèì (í³áè «rvim»)"
+
+msgid "-m\t\t\tModifications (writing files) not allowed"
+msgstr "-m\t\t\tÇì³íè (çàïèñ ôàéë³â) íå äîçâîëåíî"
+
+msgid "-M\t\t\tModifications in text not allowed"
+msgstr "-M\t\t\tÇì³íè â òåêñò³ ôàéë³â íå äîçâîëåíî"
+
+msgid "-b\t\t\tBinary mode"
+msgstr "-b\t\t\tÄâ³éêîâèé ðåæèì"
+
+msgid "-l\t\t\tLisp mode"
+msgstr "-l\t\t\tÐåæèì lisp"
+
+msgid "-C\t\t\tCompatible with Vi: 'compatible'"
+msgstr "-C\t\t\tÑóì³ñíèé ç Vi ðåæèì: 'compatible'"
+
+msgid "-N\t\t\tNot fully Vi compatible: 'nocompatible'"
+msgstr "-N\t\t\tÍå çîâñ³ì ñóì³ñíèé ç Vi ðåæèì: 'nocompatible'"
+
+msgid "-V[N][fname]\t\tBe verbose [level N] [log messages to fname]"
+msgstr "-V[N][ôàéë]\t\tÁ³ëüøå ïîâ³äîìëåíü [ð³âåíü N] [ôàéë æóðí. ïîâ³äîìëåíü]"
+
+msgid "-D\t\t\tDebugging mode"
+msgstr "-D\t\t\tÐåæèì íàëàãîäæåííÿ"
+
+msgid "-n\t\t\tNo swap file, use memory only"
+msgstr "-n\t\t\tÍå âèêîðèñòîâóâàòè ôàéë îáì³íó, òðèìàòè óñå â ïàì'ÿò³"
+
+msgid "-r\t\t\tList swap files and exit"
+msgstr "-r\t\t\tÏîêàçàòè ôàéëè îáì³íó ³ âèéòè"
+
+msgid "-r (with file name)\tRecover crashed session"
+msgstr "-r (íàçâà ôàéëó)\t³äíîâèòè àâàð³éíî çàê³í÷åíèé ñåàíñ"
+
+msgid "-L\t\t\tSame as -r"
+msgstr "-L\t\t\tÒå ñàìå, ùî é -r"
+
+msgid "-f\t\t\tDon't use newcli to open window"
+msgstr "-f\t\t\tÍå âèêîðèñòîâóâàòè newcli äëÿ â³äêðèòòÿ â³êíà"
+
+msgid "-dev <device>\t\tUse <device> for I/O"
+msgstr "-dev <ïðèñòð³é>\t\t\tÂèêîðèñòîâóâàòè <ïðèñòð³é> äëÿ ââîäó/âèâîäó"
+
+msgid "-A\t\t\tStart in Arabic mode"
+msgstr "-A\t\t\tÇàïóñòèòè â ðåæèì³ àðàáñüêî¿ ìîâè"
+
+msgid "-H\t\t\tStart in Hebrew mode"
+msgstr "-H\t\t\tÇàïóñòèòè â ðåæèì³ ³âðèòó"
+
+msgid "-F\t\t\tStart in Farsi mode"
+msgstr "-F\t\t\tÇàïóñòèòè â ðåæèì³ ïåðñüêî¿ ìîâè"
+
+msgid "-T <terminal>\tSet terminal type to <terminal>"
+msgstr "-T <òåðì³íàë>\tÂñòàíîâèòè òèï òåðì³íàëó ó <òåðì³íàë>"
+
+msgid "--not-a-term\t\tSkip warning for input/output not being a terminal"
+msgstr "--not-a-term\t\tÏðîïóñòèòè ïîïåðåäæåííÿ ââîäó/âèâîäó íå â òåðì³íàë"
+
+msgid "--ttyfail\t\tExit if input or output is not a terminal"
+msgstr "--ttyfail\t\tÂèéòè, ÿêùî ââåäåííÿ/âèâåäåííÿ íå â òåðì³íàë"
+
+msgid "-u <vimrc>\t\tUse <vimrc> instead of any .vimrc"
+msgstr "-u <vimrc>\t\tÂèêîðèñòàòè ïîäàíèé ôàéë çàì³ñòü .vimrc"
+
+msgid "-U <gvimrc>\t\tUse <gvimrc> instead of any .gvimrc"
+msgstr "-u <gvimrc>\t\tÂèêîðèñòàòè ïîäàíèé ôàéë çàì³ñòü .gvimrc"
+
+msgid "--noplugin\t\tDon't load plugin scripts"
+msgstr "--noplugin\t\tÍå âàíòàæèòè ñêðèïòè äîïîâíåííÿ"
+
+msgid "-p[N]\t\tOpen N tab pages (default: one for each file)"
+msgstr "-p[N]\t\t³äêðèòè N âêëàäîê (àáî ïî îäí³é äëÿ êîæíîãî ôàéëó)"
+
+msgid "-o[N]\t\tOpen N windows (default: one for each file)"
+msgstr "-o[N]\t\t³äêðèòè N â³êîí (àáî ïî îäíîìó äëÿ êîæíîãî ôàéëó)"
+
+msgid "-O[N]\t\tLike -o but split vertically"
+msgstr "-O[N]\t\tͳáè -o, àëå ïîä³ëèòè â³êíà âåðòèêàëüíî"
+
+msgid "+\t\t\tStart at end of file"
+msgstr "+\t\t\tÐîçïî÷àòè â ê³íö³ ôàéëó"
+
+msgid "+<lnum>\t\tStart at line <lnum>"
+msgstr "+<ðÿäîê>\t\tÐîçïî÷àòè ó âêàçàíîìó <ðÿäêó>"
+
+msgid "--cmd <command>\tExecute <command> before loading any vimrc file"
+msgstr "--cmd <êîìàíäà>\tÂèêîíàòè <êîìàíäó> ïåðåä çàâàíòàæåííÿì vimrc"
+
+msgid "-c <command>\t\tExecute <command> after loading the first file"
+msgstr "-c <êîìàíäà>\t\tÂèêîíàòè <êîìàíäó> ï³ñëÿ çàâàíòàæåííÿ ïåðøîãî ôàéëó"
+
+msgid "-S <session>\t\tSource file <session> after loading the first file"
+msgstr "-S <ñåàíñ>\t\tÂèêîíàòè ïîäàíèé ôàéë ï³ñëÿ ïåðøîãî çàâàíòàæåíîãî ôàéëó"
+
+msgid "-s <scriptin>\tRead Normal mode commands from file <scriptin>"
+msgstr "-s <ñêðèïò>\t\tÇ÷èòàòè êîìàíäè íîðìàëüíîãî ðåæèìó ç ôàéëó <ñêðèïò>"
+
+msgid "-w <scriptout>\tAppend all typed commands to file <scriptout>"
+msgstr "-w <ñêðèïò>\t\tÄîïèñàòè óñ³ íàáðàí³ êîìàíäè äî ôàéëó <ñêðèïò>"
+
+msgid "-W <scriptout>\tWrite all typed commands to file <scriptout>"
+msgstr "-w <ñêðèïò>\t\tÇàïèñàòè óñ³ íàáðàí³ êîìàíäè ó ôàéë <ñêðèïò>"
+
+msgid "-x\t\t\tEdit encrypted files"
+msgstr "-x\t\t\tÐåäàãóâàòè çàøèôðîâàí³ ôàéëè"
+
+msgid "-display <display>\tConnect vim to this particular X-server"
+msgstr "-display <äèñïëåé>\tϳä'ºäíàòè vim äî çàäàíîãî äèñïëåþ ñåðâåðà X"
+
+msgid "-X\t\t\tDo not connect to X server"
+msgstr "-X\t\t\tÍå ç'ºäíóâàòèñÿ ç X ñåðâåðîì"
+
+msgid "--remote <files>\tEdit <files> in a Vim server if possible"
+msgstr "--remote <ôàéëè>\tÐåäàãóâàòè <ôàéëè> íà ñåðâåð³ Vim, ÿêùî öå ìîæëèâî"
+
+msgid "--remote-silent <files> Same, don't complain if there is no server"
+msgstr ""
+"--remote-silent <ôàéëè> Òå ñàìå, ò³ëüêè íå ñêàðæèòèñÿ íà â³äñóòí³ñòü ñåðâåðà"
+
+msgid ""
+"--remote-wait <files> As --remote but wait for files to have been edited"
+msgstr ""
+"--remote-wait <ôàéëè> ..., àëå çà÷åêàòè ïîêè óñ³ ôàéëè áóäóòü â³äðåäàãîâàí³"
+
+msgid ""
+"--remote-wait-silent <files> Same, don't complain if there is no server"
+msgstr ""
+"--remote-wait-silent <ôàéëè> Òå ñàìå, ò³ëüêè íå ñêàðæèòèñÿ, ÿêùî ñåðâåðà "
+"íåìàº"
+
+msgid ""
+"--remote-tab[-wait][-silent] <files> As --remote but use tab page per file"
+msgstr ""
+"--remote-tab[-wait][-silent] <ôàéëè> Òàê ñàìî, ÿê --remote, àëå ïî âêëàäö³ "
+"íà ôàéë"
+
+msgid "--remote-send <keys>\tSend <keys> to a Vim server and exit"
+msgstr "--remote-send <ñèìâîëè> ³ä³ñëàòè <ñèìâîëè> ñåðâåðó ³ çàâåðøèòè ðîáîòó"
+
+msgid "--remote-expr <expr>\tEvaluate <expr> in a Vim server and print result"
+msgstr ""
+"--remote-expr <âèðàç> Âèêîíàòè <âèðàç> ó ñåðâåð³ Vim ³ íàäðóêóâàòè ðåçóëüòàò"
+
+msgid "--serverlist\t\tList available Vim server names and exit"
+msgstr ""
+"--serverlist\t\tÏîêàçàòè ñïèñîê íàÿâíèõ ñåðâåð³â Vim ³ çàâåðøèòè ðîáîòó"
+
+msgid "--servername <name>\tSend to/become the Vim server <name>"
+msgstr "--servername <íàçâà>\tÍàä³ñëàòè äî/ñòàòè Vim ñåðâåðîì ç <íàçâîþ>"
+
+msgid "--startuptime <file>\tWrite startup timing messages to <file>"
+msgstr ""
+"--startuptime <ôàéë>\tÇàïèñàòè çàïóñêí³ ïîâ³äîìëåííÿ ç ÷àñîâèìè â³äì³òêàìè "
+"äî <ôàéëó>"
+
+msgid "-i <viminfo>\t\tUse <viminfo> instead of .viminfo"
+msgstr "-i <viminfo>\t\tÂèêîðèñòàòè <viminfo> çàì³ñòü .viminfo"
+
+msgid "--clean\t\t'nocompatible', Vim defaults, no plugins, no viminfo"
+msgstr "--clean\t\t'nocompatible', Vim ïî÷àòêîâî, áåç ðîçøèðåíü, áåç viminfo"
+
+msgid "-h or --help\tPrint Help (this message) and exit"
+msgstr "-h ÷è --help\tÍàäðóêóâàòè öå ïîâ³äîìëåííÿ ³ âèéòè"
+
+msgid "--version\t\tPrint version information and exit"
+msgstr "--version\t\tÍàäðóêóâàòè ³íôîðìàö³þ ïðî âåðñ³þ ïðîãðàìè ³ âèéòè"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Motif version):\n"
+msgstr ""
+"\n"
+"Àðãóìåíòè äëÿ gvim (âåðñ³ÿ Motif)\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (neXtaw version):\n"
+msgstr ""
+"\n"
+"Àðãóìåíòè äëÿ gvim (âåðñ³ÿ neXtaw):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Athena version):\n"
+msgstr ""
+"\n"
+"Àðãóìåíòè äëÿ gvim (âåðñ³ÿ Athena)\n"
+
+msgid "-display <display>\tRun vim on <display>"
+msgstr "-display <äèñïëåé>\tÂèêîíàòè vim íà çàäàíîìó <äèñïëå¿>"
+
+msgid "-iconic\t\tStart vim iconified"
+msgstr "-iconic\t\tÇàïóñòèòè Vim ³ çãîðíóòè éîãî â³êíî"
+
+msgid "-background <color>\tUse <color> for the background (also: -bg)"
+msgstr "-background <êîë³ð>\tÂèêîðèñòàòè <êîë³ð> äëÿ ôîíó (òàêîæ: -bg)"
+
+msgid "-foreground <color>\tUse <color> for normal text (also: -fg)"
+msgstr ""
+"-foreground <êîë³ð>\tÂèêîðèñòàòè <êîë³ð> äëÿ çâè÷àéíîãî òåêñòó (òàêîæ: -fg)"
+
+msgid "-font <font>\t\tUse <font> for normal text (also: -fn)"
+msgstr "-font <øðèôò>\tÂèêîðèñòàòè <øðèôò> äëÿ çâè÷àéíîãî òåêñòó (òàêîæ: -fn)"
+
+msgid "-boldfont <font>\tUse <font> for bold text"
+msgstr "-boldfont <øðèôò>\tÂèêîðèñòàòè <øðèôò> äëÿ æèðíîãî òåêñòó"
+
+msgid "-italicfont <font>\tUse <font> for italic text"
+msgstr "-italicfont <øðèôò>\tÂèêîðèñòàòè <øðèôò> äëÿ ïîõèëîãî òåêñòó"
+
+msgid "-geometry <geom>\tUse <geom> for initial geometry (also: -geom)"
+msgstr "-geometry <ãåîì>\tÇàäàòè ðîçì³ðè é ïîëîæåííÿ (òàêîæ: -geom)"
+
+msgid "-borderwidth <width>\tUse a border width of <width> (also: -bw)"
+msgstr "-borderwidth <òîâù>\tÂñòàíîâèòè òîâùèíó ìåæ <òîâù> (òàêîæ: -bw)"
+
+msgid "-scrollbarwidth <width> Use a scrollbar width of <width> (also: -sw)"
+msgstr "-scrollbarwidth <òîâù> Âñòàíîâèòè òîâùèíó ë³í³éêè çñóâó (òàêîæ: -sw)"
+
+msgid "-menuheight <height>\tUse a menu bar height of <height> (also: -mh)"
+msgstr "-menuheight <âèñîòà>\tÂñòàíîâèòè âèñîòó ìåíþ <âèñîòà> (òàêîæ: -mh)"
+
+msgid "-reverse\t\tUse reverse video (also: -rv)"
+msgstr "-reverse\t\tÎáåðíóòè êîëüîðè (òàêîæ: -rv)"
+
+msgid "+reverse\t\tDon't use reverse video (also: +rv)"
+msgstr "+reverse\t\tÍå îáåðòàòè êîëüîðè (òàêîæ: +rv)"
+
+msgid "-xrm <resource>\tSet the specified resource"
+msgstr "-xrm <ðåñóðñ>\t\tÂñòàíîâèòè çàçíà÷åíèé ðåñóðñ"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (GTK+ version):\n"
+msgstr ""
+"\n"
+"Àðãóìåíòè gvim (âåðñ³ÿ GTK+)\n"
+
+msgid "-display <display>\tRun vim on <display> (also: --display)"
+msgstr "-display <äèñïëåé>\tÂèêîíàòè vim íà <äèñïëå¿> (òàêîæ: --display)"
+
+msgid "--role <role>\tSet a unique role to identify the main window"
+msgstr ""
+"--role <ðîëü>\tÂñòàíîâèòè óí³êàëüíó ðîëü äëÿ ³äåíòèô³êàö³¿ ãîëîâíîãî â³êíà"
+
+msgid "--socketid <xid>\tOpen Vim inside another GTK widget"
+msgstr "--socketid <xid>\t³äêðèòè Vim â ³íøîìó åëåìåíò³ ³íòåðôåéñó GTK"
+
+msgid "--echo-wid\t\tMake gvim echo the Window ID on stdout"
+msgstr "--echo-wid\t\tÕàé gvim íàäðóêóº ³äåíòèô³êàòîð â³êíà íà stdout"
+
+msgid "-P <parent title>\tOpen Vim inside parent application"
+msgstr "-P <çàãîëîâîê áàòüêà>\t³äêðèòè Vim âñåðåäèí³ áàòüê³âñüêîãî â³êíà"
+
+msgid "--windowid <HWND>\tOpen Vim inside another win32 widget"
+msgstr "--windowid <HWND>\t³äêðèòè Vim âñåðåäèí³ ³íøîãî åëåìåíòó win32"
+
+msgid "No display"
+msgstr "Íåìຠäèñïëåþ"
+
+msgid ": Send failed.\n"
+msgstr ": Íå âäàëîñÿ â³ä³ñëàòè.\n"
+
+msgid ": Send failed. Trying to execute locally\n"
+msgstr ": Íå âäàëîñÿ â³ä³ñëàòè. Ñïðîáà âèêîíàòè íà ì³ñö³\n"
+
+#, c-format
+msgid "%d of %d edited"
+msgstr "â³äðåäàãîâàíî %d ç %d"
+
+msgid "No display: Send expression failed.\n"
+msgstr "Íåìຠäèñïëåþ: ³ä³ñëàòè âèðàç íå âäàëîñÿ.\n"
+
+msgid ": Send expression failed.\n"
+msgstr ": ³ä³ñëàòè âèðàç íå âäàëîñÿ.\n"
+
+msgid "No marks set"
+msgstr "Íå âñòàíîâëåíî æîäíî¿ ïîì³òêè"
+
+#, c-format
+msgid "E283: No marks matching \"%s\""
+msgstr "E283: Ïîì³òêó «%s» íå çíàéäåíî"
+
+# msgstr "E283: "
+msgid ""
+"\n"
+"mark line col file/text"
+msgstr ""
+"\n"
+"ïîì. ðÿä. êîë. ôàéë/òåêñò"
+
+msgid ""
+"\n"
+" jump line col file/text"
+msgstr ""
+"\n"
+" òî÷êà ðÿä. ñòîâï. ôàéë/òåêñò"
+
+# msgstr "E283: "
+msgid ""
+"\n"
+"change line col text"
+msgstr ""
+"\n"
+"çì³íèòè ðÿä. ñòîâï. òåêñò"
+
+# TODO
+msgid ""
+"\n"
+"# File marks:\n"
+msgstr ""
+"\n"
+"# Ïîì³òêè:\n"
+
+msgid ""
+"\n"
+"# Jumplist (newest first):\n"
+msgstr ""
+"\n"
+"# Ñïèñîê ïåðåõîä³â (â³ä íàéíîâ³øèõ):\n"
+
+# TODO
+msgid ""
+"\n"
+"# History of marks within files (newest to oldest):\n"
+msgstr ""
+"\n"
+"# Ïîïåðåäí³ ïîì³òêè â ôàéëàõ (â³ä íàéíîâ³øèõ):\n"
+
+msgid "Missing '>'"
+msgstr "Ïðîïóùåíî '>'"
+
+msgid "E543: Not a valid codepage"
+msgstr "E543: Íåêîðåêòíà êîäîâà ñòîð³íêà"
+
+msgid "E284: Cannot set IC values"
+msgstr "E284: Íå âäàëîñÿ âñòàíîâèòè çíà÷åííÿ êîíòåêñòó ââîäó"
+
+msgid "E285: Failed to create input context"
+msgstr "E285: Íå âäàëîñÿ ñòâîðèòè êîíòåêñò ââîäó"
+
+msgid "E286: Failed to open input method"
+msgstr "E286: Íå âäàëîñÿ ñòâîðèòè ìåòîä ââîäó"
+
+# msgstr "E286: "
+msgid "E287: Warning: Could not set destroy callback to IM"
+msgstr ""
+"E287: Çàñòåðåæåííÿ: Íå âäàëîñÿ âñòàíîâèòè â ìåòîä³ ââîäó ïîä³þ çíèùåííÿ"
+
+# msgstr "E287: "
+msgid "E288: input method doesn't support any style"
+msgstr "E288: Ìåòîä ââîäó íå ï³äòðèìóº ñòèë³"
+
+# msgstr "E288: "
+msgid "E289: input method doesn't support my preedit type"
+msgstr "E289: Ìåòîä ââîäó íå ï³äòðèìóº â³äðåäàãîâàí³ òèïè"
+
+# msgstr "E292: "
+msgid "E293: block was not locked"
+msgstr "E293: Áëîê íå áóëî çàô³êñîâàíî"
+
+# msgstr "E293: "
+msgid "E294: Seek error in swap file read"
+msgstr "E294: Ïîìèëêà çì³íè ïîçèö³¿ ó ôàéë³ îáì³íó"
+
+msgid "E295: Read error in swap file"
+msgstr "E295: Ïîìèëêà ç÷èòóâàííÿ ôàéëó îáì³íó"
+
+msgid "E296: Seek error in swap file write"
+msgstr "E296: Ïîìèëêà çì³íè ïîçèö³¿ ï³ä ÷àñ çàïèñó ó ôàéë îáì³íó"
+
+msgid "E297: Write error in swap file"
+msgstr "E297: Ïîìèëêà çàïèñó ôàéëó îáì³íó"
+
+msgid "E300: Swap file already exists (symlink attack?)"
+msgstr "E300: Ôàéë îáì³íó âæå ³ñíóº (àòàêà ñèìâîëüíèì ïîñèëàííÿì?)"
+
+msgid "E298: Didn't get block nr 0?"
+msgstr "E298: Íåìຠáëîêó 0?"
+
+msgid "E298: Didn't get block nr 1?"
+msgstr "E298: Íåìຠáëîêó 1?"
+
+# msgstr "E298: "
+msgid "E298: Didn't get block nr 2?"
+msgstr "E298: Íåìຠáëîêó 2?"
+
+msgid "E843: Error while updating swap file crypt"
+msgstr "E843: Ïîìèëêà ïîíîâëåííÿ øèôðóâàííÿ ôàéëó îáì³íó"
+
+msgid "E301: Oops, lost the swap file!!!"
+msgstr "E301: Îé, âòðà÷åíî ôàéë îáì³íó!!!"
+
+# msgstr "E301: "
+msgid "E302: Could not rename swap file"
+msgstr "E302: Íå âäàëîñÿ ïåðåéìåíóâàòè ôàéëó îáì³íó"
+
+# msgstr "E302: "
+#, c-format
+msgid "E303: Unable to open swap file for \"%s\", recovery impossible"
+msgstr "E303: Íå âäàëîñÿ ïðî÷èòàòè ôàéë îáì³íó äëÿ «%s», â³äíîâëåííÿ íåìîæëèâå"
+
+msgid "E304: ml_upd_block0(): Didn't get block 0??"
+msgstr "E304: ml_upd_block0(): Íåìຠáëîêó 0??"
+
+#, c-format
+msgid "E305: No swap file found for %s"
+msgstr "E305: Íå çíàéäåíî ôàéëó îáì³íó äëÿ %s"
+
+# msgstr "E305: "
+msgid "Enter number of swap file to use (0 to quit): "
+msgstr "Ââåä³òü íîìåð ôàéëó îáì³íó, êîòðèé âèêîðèñòàòè, (0 äëÿ âèõîäó):"
+
+#, c-format
+msgid "E306: Cannot open %s"
+msgstr "E306: Íå âäàëîñÿ â³äêðèòè %s"
+
+msgid "Unable to read block 0 from "
+msgstr "Íå âäàëîñÿ ïðî÷èòàòè áëîê 0 ç "
+
+msgid ""
+"\n"
+"Maybe no changes were made or Vim did not update the swap file."
+msgstr ""
+"\n"
+"Íàïåâíî, çì³í íå áóëî, àáî Vim íå ïîíîâèâ ôàéë îáì³íó."
+
+msgid " cannot be used with this version of Vim.\n"
+msgstr " íå ìîæíà âèêîðèñòàòè ç ö³ºþ âåðñ³ºþ Vim.\n"
+
+msgid "Use Vim version 3.0.\n"
+msgstr "Çíàéä³òü Vim 3.0\n"
+
+#, c-format
+msgid "E307: %s does not look like a Vim swap file"
+msgstr "E307: %s íå ñõîæå íà ôàéë îáì³íó Vim"
+
+msgid " cannot be used on this computer.\n"
+msgstr " íå ìîæíà âèêîðèñòàòè íà öüîìó êîìï'þòåð³.\n"
+
+msgid "The file was created on "
+msgstr "Ôàéë áóëî ñòâîðåíî íà "
+
+msgid ""
+",\n"
+"or the file has been damaged."
+msgstr ""
+",\n"
+"àáî ôàéë áóëî ïîøêîäæåíî."
+
+#, c-format
+msgid ""
+"E833: %s is encrypted and this version of Vim does not support encryption"
+msgstr "E833: %s çàøèôðîâàíî, à öÿ âåðñ³ÿ Vim íå ï³äòðèìóº øèôðóâàííÿ"
+
+msgid " has been damaged (page size is smaller than minimum value).\n"
+msgstr " ïîøêîäæåíèé (ðîçì³ð ñòîð³íêè ìåíøèé ì³í³ìàëüíîãî çíà÷åííÿ).\n"
+
+#, c-format
+msgid "Using swap file \"%s\""
+msgstr "Âèêîðèñòîâóºòüñÿ ôàéë îáì³íó «%s»"
+
+#, c-format
+msgid "Original file \"%s\""
+msgstr "Ïî÷àòêîâèé ôàéë «%s»"
+
+msgid "E308: Warning: Original file may have been changed"
+msgstr "E308: Çàñòåðåæåííÿ: Ìîæëèâî, ïî÷àòêîâèé ôàéë áóëî çì³íåíî"
+
+#, c-format
+msgid "Swap file is encrypted: \"%s\""
+msgstr "Ôàéë îáì³íó çàøèôðîâàíèé: «%s»"
+
+msgid ""
+"\n"
+"If you entered a new crypt key but did not write the text file,"
+msgstr ""
+"\n"
+"ßêùî âè çàäàëè íîâèé êëþ÷ øèôðó, àëå íå çàïèñàëè òåêñòîâèé ôàéë,"
+
+msgid ""
+"\n"
+"enter the new crypt key."
+msgstr ""
+"\n"
+"ââåä³òü íîâèé êëþ÷ øèôðó."
+
+msgid ""
+"\n"
+"If you wrote the text file after changing the crypt key press enter"
+msgstr ""
+"\n"
+"ßêùî âè çàïèñàëè òåêñòîâèé ôàéë ï³ñëÿ çì³íè êëþ÷à øèôðó, íàòèñí³òü enter"
+
+msgid ""
+"\n"
+"to use the same key for text file and swap file"
+msgstr ""
+"\n"
+"ùîá âèêîðèñòàòè îäíàêîâèé êëþ÷ äëÿ òåêñòîâîãî ôàéëó òà ôàéëó îáì³íó"
+
+# msgstr "E308: "
+#, c-format
+msgid "E309: Unable to read block 1 from %s"
+msgstr "E309: Íå âäàëîñÿ ïðî÷èòàòè áëîê 1 ç %s"
+
+# msgstr "E309: "
+msgid "???MANY LINES MISSING"
+msgstr "??? ÁÐÀÊÓª ÁÀÃÀÒÜÎÕ ÐßÄʲÂ"
+
+msgid "???LINE COUNT WRONG"
+msgstr "??? ÍÅÏÐÀÂÈËÜÍÀ ʲËÜʲÑÒÜ ÐßÄʲÂ"
+
+msgid "???EMPTY BLOCK"
+msgstr "??? ÏÎÐÎÆÍ²É ÁËÎÊ"
+
+msgid "???LINES MISSING"
+msgstr "??? ÏÐÎÏÓÙÅͲ ÐßÄÊÈ"
+
+#, c-format
+msgid "E310: Block 1 ID wrong (%s not a .swp file?)"
+msgstr "E310: ²äåíòèô³êàòîð áëîêó 1 íåïðàâèëüíèé (%s íå º ôàéëîì îáì³íó?)"
+
+# msgstr "E310: "
+msgid "???BLOCK MISSING"
+msgstr "??? ÏÐÎÏÓÙÅÍÎ ÁËÎÊ"
+
+msgid "??? from here until ???END lines may be messed up"
+msgstr "??? çâ³äñè ³ äî `??? ʲÍÅÖÜ' ðÿäêè, ìîæëèâî, ñïëóòàí³"
+
+msgid "??? from here until ???END lines may have been inserted/deleted"
+msgstr "??? çâ³äñè ³ äî `??? ʲÍÅÖÜ' ðÿäêè, ìîæëèâî, áóëè äîäàí³/çíèùåí³"
+
+msgid "???END"
+msgstr "??? ʲÍÅÖÜ"
+
+msgid "E311: Recovery Interrupted"
+msgstr "E311: ³äíîâëåííÿ ïåðåðâàíî"
+
+msgid ""
+"E312: Errors detected while recovering; look for lines starting with ???"
+msgstr ""
+"E312: ϳä ÷àñ â³äíîâëåííÿ çíàéäåíî ïîìèëêè. Ïåðåãëÿíüòå ðÿäêè, ùî "
+"ïî÷èíàþòüñÿ ç ???"
+
+msgid "See \":help E312\" for more information."
+msgstr "Äèâ. «:help E312» äëÿ óòî÷íåííÿ."
+
+msgid "Recovery completed. You should check if everything is OK."
+msgstr "³äíîâëåííÿ çàê³í÷åíî, ïåðåâ³ðòå ÷è âñå ãàðàçä."
+
+msgid ""
+"\n"
+"(You might want to write out this file under another name\n"
+msgstr ""
+"\n"
+"(Ìîæëèâî, ïîòð³áíî çàïèñàòè öåé ôàéë ï³ä ³íøîþ íàçâîþ\n"
+
+msgid "and run diff with the original file to check for changes)"
+msgstr "³ çàïóñòèòè diff ç îðèã³íàëîì ùîá ïåðåâ³ðèòè çì³íè)"
+
+msgid "Recovery completed. Buffer contents equals file contents."
+msgstr "³äíîâëåííÿ çàê³í÷åíî. Âì³ñò áóôåðà ñï³âïàäàº ç³ âì³ñòîì ôàéëó."
+
+msgid ""
+"\n"
+"You may want to delete the .swp file now.\n"
+"\n"
+msgstr ""
+"\n"
+"Ìîæëèâî, òåïåð âè õî÷åòå çíèùèòè ôàéë îáì³íó .swp.\n"
+"\n"
+
+msgid "Using crypt key from swap file for the text file.\n"
+msgstr "Äëÿ òåêñòîâîãî ôàéëó âèêîðèñòîâóºòüñÿ êëþ÷ øèôðó ç ôàéëó îáì³íó.\n"
+
+msgid "Swap files found:"
+msgstr "Çíàéäåíî ôàéëè îáì³íó:"
+
+msgid " In current directory:\n"
+msgstr "  ïîòî÷íîìó êàòàëîç³:\n"
+
+msgid " Using specified name:\n"
+msgstr " Âèêîðèñòîâóþ÷è âêàçàíó íàçâó:\n"
+
+msgid " In directory "
+msgstr " Ó êàòàëîç³ "
+
+msgid " -- none --\n"
+msgstr " -- æîäíîãî --\n"
+
+msgid " owned by: "
+msgstr " âëàñíèê: "
+
+msgid " dated: "
+msgstr " äàòà: "
+
+msgid " dated: "
+msgstr " äàòà: "
+
+msgid " [from Vim version 3.0]"
+msgstr " [â³ä Vim 3.0]"
+
+msgid " [does not look like a Vim swap file]"
+msgstr " [íå ñõîæå íà ôàéë îáì³íó]"
+
+msgid " file name: "
+msgstr " íàçâà ôàéëó: "
+
+msgid ""
+"\n"
+" modified: "
+msgstr ""
+"\n"
+" çì³íåíî: "
+
+msgid "YES"
+msgstr "ÒÀÊ"
+
+msgid "no"
+msgstr "í³"
+
+msgid ""
+"\n"
+" user name: "
+msgstr ""
+"\n"
+" êîðèñòóâà÷: "
+
+msgid " host name: "
+msgstr " íàçâà âóçëà: "
+
+msgid ""
+"\n"
+" host name: "
+msgstr ""
+"\n"
+" íàçâà âóçëà: "
+
+msgid ""
+"\n"
+" process ID: "
+msgstr ""
+"\n"
+" ID ïðîöåñó: "
+
+msgid " (still running)"
+msgstr " (âèêîíóºòüñÿ)"
+
+msgid ""
+"\n"
+" [not usable with this version of Vim]"
+msgstr ""
+"\n"
+" [íå ïðèäàòíèé äëÿ ö³º¿ âåðñ³¿ Vim]"
+
+msgid ""
+"\n"
+" [not usable on this computer]"
+msgstr ""
+"\n"
+" [íåïðèäàòíèé íà öüîìó êîìï'þòåð³]"
+
+msgid " [cannot be read]"
+msgstr " [íå ìîæíà ïðî÷èòàòè]"
+
+msgid " [cannot be opened]"
+msgstr " [íå ìîæíà â³äêðèòè]"
+
+msgid "E313: Cannot preserve, there is no swap file"
+msgstr "E313: Íå âäàëîñÿ çàãîòîâèòè, íåìຠôàéëó îáì³íó"
+
+# msgstr "E313: "
+msgid "File preserved"
+msgstr "Ôàéë çáåðåæåíî"
+
+msgid "E314: Preserve failed"
+msgstr "E314: Çáåðåæåííÿ íå âäàëîñÿ"
+
+# msgstr "E314: "
+#, c-format
+msgid "E315: ml_get: invalid lnum: %ld"
+msgstr "E315: ml_get: íåïðàâèëüíèé lnum: %ld"
+
+# msgstr "E315: "
+#, c-format
+msgid "E316: ml_get: cannot find line %ld"
+msgstr "E316: ml_get: íå çíàéøîâ ðÿäîê %ld"
+
+# msgstr "E316: "
+msgid "E317: pointer block id wrong 3"
+msgstr "E317: Âêàç³âíèê áëîêó ïîìèëêîâèé 3"
+
+# msgstr "E317: "
+msgid "stack_idx should be 0"
+msgstr "stack_idx ìຠáóòè ð³âíèì 0"
+
+msgid "E318: Updated too many blocks?"
+msgstr "E318: Ïîíîâëåíî çàáàãàòî áëîê³â?"
+
+msgid "E317: pointer block id wrong 4"
+msgstr "E317: Âêàç³âíèê áëîêó ïîìèëêîâèé 4"
+
+msgid "deleted block 1?"
+msgstr "áëîê 1 çíèùåíî?"
+
+#, c-format
+msgid "E320: Cannot find line %ld"
+msgstr "E320: Íå âäàëîñÿ çíàéòè ðÿäîê %ld"
+
+msgid "E317: pointer block id wrong"
+msgstr "E317: Âêàç³âíèê áëîêó ïîìèëêîâèé"
+
+# msgstr "E317: "
+msgid "pe_line_count is zero"
+msgstr "pe_line_count äîð³âíþº 0"
+
+#, c-format
+msgid "E322: line number out of range: %ld past the end"
+msgstr "E322: Íîìåð ðÿäêà âèéøîâ çà ìåæ³: %ld çà ê³íöåì"
+
+# msgstr "E322: "
+#, c-format
+msgid "E323: line count wrong in block %ld"
+msgstr "E323: ʳëüê³ñòü ðÿäê³â ó áëîö³ %ld"
+
+# msgstr "E323: "
+msgid "Stack size increases"
+msgstr "Ðîçì³ð ñòåêó çá³ëüøóºòüñÿ"
+
+msgid "E317: pointer block id wrong 2"
+msgstr "E317: Âêàç³âíèê áëîêó ïîìèëêîâèé 2"
+
+#, c-format
+msgid "E773: Symlink loop for \"%s\""
+msgstr "E773: Öèêë³÷í³ ñèìâîëüí³ ïîñèëàííÿ «%s»"
+
+# msgstr "E317: "
+msgid "E325: ATTENTION"
+msgstr "E325: ÓÂÀÃÀ"
+
+msgid ""
+"\n"
+"Found a swap file by the name \""
+msgstr ""
+"\n"
+"Çíàéäåíî ôàéë îáì³íó ç íàçâîþ \""
+
+msgid "While opening file \""
+msgstr "Ïðè â³äêðèòò³ ôàéëó \""
+
+msgid " NEWER than swap file!\n"
+msgstr " ÍβØÈÉ çà ôàéë îáì³íó!\n"
+
+msgid ""
+"\n"
+"(1) Another program may be editing the same file. If this is the case,\n"
+" be careful not to end up with two different instances of the same\n"
+" file when making changes. Quit, or continue with caution.\n"
+msgstr ""
+"\n"
+"(1) Ìîæëèâî, ³íøà ïðîãðàìà âæå ðåäàãóº öåé ñàìèé ôàéë. ßêùî öå òàê,\n"
+" áóäüòå îáåðåæí³, ùîá íå çàëèøèëèñÿ äâà ð³çí³ åêçåìïëÿðè\n"
+" îäíîãî é òîãî ñàìîãî ôàéëó ï³ñëÿ çì³í. Âèéä³òü ÷è ïðîäîâæóéòå ç "
+"îáåðåæí³ñòþ.\n"
+
+msgid "(2) An edit session for this file crashed.\n"
+msgstr "(2) Ñåàíñ ðåäàãóâàííÿ öüîãî ôàéëó çàçíàâ êðàõó.\n"
+
+msgid " If this is the case, use \":recover\" or \"vim -r "
+msgstr " ßêùî öå ñïðàâä³ òðàïèëîñÿ, ñïðîáóéòå «:recover» àáî «vim -r "
+
+msgid ""
+"\"\n"
+" to recover the changes (see \":help recovery\").\n"
+msgstr ""
+"»\n"
+" ùîá â³äíîâèòè çì³íè (äèâ. «:help recovery»).\n"
+
+msgid " If you did this already, delete the swap file \""
+msgstr " ßêùî âè âæå öå çðîáèëè, çíèù³òü ôàéë îáì³íó «"
+
+msgid ""
+"\"\n"
+" to avoid this message.\n"
+msgstr ""
+"»,\n"
+" ùîá ïîçáóòèñÿ öüîãî ïîâ³äîìëåííÿ.\n"
+
+msgid "Swap file \""
+msgstr "Ôàéë îáì³íó «"
+
+msgid "\" already exists!"
+msgstr "» âæå ³ñíóº!"
+
+msgid "VIM - ATTENTION"
+msgstr "VIM — ÓÂÀÃÀ"
+
+msgid "Swap file already exists!"
+msgstr "Ôàéë îáì³íó âæå ³ñíóº!"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"&O:³äêðèòè ëèøå äëÿ ÷èòàííÿ\n"
+"&E:Âñå îäíî ðåäàãóâàòè\n"
+"&R:³äíîâèòè\n"
+"&Q:Âèéòè\n"
+"&A:Ïåðåðâàòè"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Delete it\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"&O:³äêðèòè ëèøå äëÿ ÷èòàííÿ\n"
+"&E:Óñå îäíî ðåäàãóâàòè\n"
+"&R:³äíîâèòè\n"
+"&D:Çíèùèòè éîãî\n"
+"&Q:Âèéòè\n"
+"&A:Ïåðåðâàòè"
+
+msgid "E326: Too many swap files found"
+msgstr "E326: Çíàéäåíî çàáàãàòî ôàéë³â îáì³íó"
+
+# msgstr "E326: "
+msgid "E327: Part of menu-item path is not sub-menu"
+msgstr "E327: ×àñòèíà øëÿõó äî åëåìåíòà ìåíþ íå º ï³äìåíþ"
+
+# msgstr "E327: "
+msgid "E328: Menu only exists in another mode"
+msgstr "E328: Ìåíþ ìîæå áóòè ò³ëüêè â ³íøîìó ðåæèì³"
+
+# msgstr "E328: "
+#, c-format
+msgid "E329: No menu \"%s\""
+msgstr "E329: Íåìຠìåíþ «%s»"
+
+msgid "E792: Empty menu name"
+msgstr "E792: Ïîðîæíÿ íàçâà ìåíþ"
+
+# msgstr "E329: "
+msgid "E330: Menu path must not lead to a sub-menu"
+msgstr "E330: Øëÿõ äî ìåíþ íå ïîâèíåí âåñòè äî ï³äìåíþ"
+
+# msgstr "E330: "
+msgid "E331: Must not add menu items directly to menu bar"
+msgstr "E331: Íå ìîæíà äîäàâàòè åëåìåíòè ìåíþ ïðîñòî äî âåðõíüîãî ìåíþ"
+
+# msgstr "E331: "
+msgid "E332: Separator cannot be part of a menu path"
+msgstr "E332: Ðîçä³ëüíèê íå ìîæå áóòè ÷àñòèíîþ øëÿõó ìåíþ"
+
+# msgstr "E332: "
+msgid ""
+"\n"
+"--- Menus ---"
+msgstr ""
+"\n"
+"--- Ìåíþ ---"
+
+msgid "Tear off this menu"
+msgstr "³ä³ðâàòè öå ìåíþ"
+
+# msgstr "E334: "
+#, c-format
+msgid "E335: Menu not defined for %s mode"
+msgstr "E335: Äëÿ ðåæèìó %s ìåíþ íå âèçíà÷åíî"
+
+msgid "E333: Menu path must lead to a menu item"
+msgstr "E333: Øëÿõ ïîâèíåí âåñòè äî åëåìåíòà ìåíþ"
+
+# msgstr "E333: "
+#, c-format
+msgid "E334: Menu not found: %s"
+msgstr "E334: Ìåíþ íå çíàéäåíî: %s"
+
+# msgstr "E335: "
+msgid "E336: Menu path must lead to a sub-menu"
+msgstr "E336: Øëÿõ ïîâèíåí âåñòè äî ï³äìåíþ"
+
+# msgstr "E336: "
+msgid "E337: Menu not found - check menu names"
+msgstr "E337: Ìåíþ íå çíàéäåíî — ïåðåâ³ðòå íàçâó"
+
+# msgstr "E337: "
+#, c-format
+msgid "Error detected while processing %s:"
+msgstr "Âèÿâëåíî ïîìèëêó ï³ä ÷àñ âèêîíàííÿ %s:"
+
+#, c-format
+msgid "line %4ld:"
+msgstr "ðÿäîê %4ld:"
+
+#, c-format
+msgid "E354: Invalid register name: '%s'"
+msgstr "E354: Íåïðàâèëüíà íàçâà ðåã³ñòðó: '%s'"
+
+msgid "Messages maintainer: Bram Moolenaar <Bram@vim.org>"
+msgstr "Óêðà¿í³çàö³ÿ: Àíàòîë³é Ñàõí³ê <sakhnik@gmail.com>"
+
+msgid "Interrupt: "
+msgstr "Ïåðåðâàíî: "
+
+msgid "Press ENTER or type command to continue"
+msgstr "Íàòèñí³òü ENTER àáî ââåä³òü êîìàíäó äëÿ ïðîäîâæåííÿ"
+
+#, c-format
+msgid "%s line %ld"
+msgstr "%s ðÿäîê %ld"
+
+msgid "-- More --"
+msgstr "-- Ùå --"
+
+msgid " SPACE/d/j: screen/page/line down, b/u/k: up, q: quit "
+msgstr " ÏÐÎÁ²Ë/d/j: âíèç íà åêðàí/ñòîð³íêó/ðÿäîê, b/u/k: âãîðó, q: âèéòè "
+
+msgid "Question"
+msgstr "Çàïèòàííÿ"
+
+msgid ""
+"&Yes\n"
+"&No"
+msgstr ""
+"&Y:Òàê\n"
+"&N:ͳ"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"Save &All\n"
+"&Discard All\n"
+"&Cancel"
+msgstr ""
+"&Y:Òàê\n"
+"&N:ͳ\n"
+"&A:Óñ³\n"
+"&D:Æîäíîãî\n"
+"&C:Ñêàñóâàòè"
+
+msgid "Select Directory dialog"
+msgstr "Âèáðàòè êàòàëîã"
+
+msgid "Save File dialog"
+msgstr "Çàïàì'ÿòàòè ôàéë"
+
+msgid "Open File dialog"
+msgstr "³äêðèòè ôàéë"
+
+msgid "E338: Sorry, no file browser in console mode"
+msgstr "E338: Âèáà÷òå, àëå â êîíñîë³ íåìຠä³àëîãó âèáîðó ôàéëó"
+
+msgid "E766: Insufficient arguments for printf()"
+msgstr "E766: Íåäîñòàòíüî àðãóìåíò³â äëÿ printf()"
+
+msgid "E807: Expected Float argument for printf()"
+msgstr "E807: Î÷³êóºòüñÿ àðãóìåíò Float äëÿ printf()"
+
+msgid "E767: Too many arguments to printf()"
+msgstr "E767: Çàáàãàòî àðãóìåíò³â äëÿ printf()"
+
+# msgstr "E338: "
+msgid "W10: Warning: Changing a readonly file"
+msgstr "W10: Çàñòåðåæåííÿ: Çì³íþºòüñÿ ôàéë ïðèçíà÷åíèé ëèøå äëÿ ÷èòàííÿ"
+
+msgid "Type number and <Enter> or click with mouse (empty cancels): "
+msgstr "Íàáåð³òü ÷èñëî é <Enter> ÷è êëàöí³òü ìèøêîþ (ïîðîæíº ñêàñîâóº): "
+
+msgid "Type number and <Enter> (empty cancels): "
+msgstr "Íàáåð³òü ÷èñëî é <Enter> (ïîðîæíº ñêàñîâóº): "
+
+msgid "1 more line"
+msgstr "äîäàíî îäèí ðÿäîê"
+
+msgid "1 line less"
+msgstr "çíèùåíî îäèí ðÿäîê"
+
+#, c-format
+msgid "%ld more lines"
+msgstr "äîäàíî ðÿäê³â: %ld"
+
+#, c-format
+msgid "%ld fewer lines"
+msgstr "çíèùåíî ðÿäê³â: %ld"
+
+msgid " (Interrupted)"
+msgstr " (Ïåðåðâàíî)"
+
+msgid "Beep!"
+msgstr "Äçåíü!"
+
+msgid "ERROR: "
+msgstr "ÏÎÌÈËÊÀ: "
+
+#, c-format
+msgid ""
+"\n"
+"[bytes] total alloc-freed %lu-%lu, in use %lu, peak use %lu\n"
+msgstr ""
+"\n"
+"[áàéò] âñüîãî ðîçì/çíèù. %lu/%lu, âèêîð. %lu, ìàêñ. %lu\n"
+
+#, c-format
+msgid ""
+"[calls] total re/malloc()'s %lu, total free()'s %lu\n"
+"\n"
+msgstr ""
+"[âèêëèêè] óñüîãî re/malloc() - %lu, óñüîãî free() - %lu\n"
+"\n"
+
+msgid "E340: Line is becoming too long"
+msgstr "E340: Ðÿäîê ñòຠçàíàäòî äîâãèì"
+
+# msgstr "E340: "
+#, c-format
+msgid "E341: Internal error: lalloc(%ld, )"
+msgstr "E341: Âíóòð³øíÿ ïîìèëêà: lalloc(%ld, )"
+
+# msgstr "E341: "
+#, c-format
+msgid "E342: Out of memory! (allocating %lu bytes)"
+msgstr "E342: Çàáðàêëî ïàì'ÿò³! (ïîòð³áíî áóëî %lu áàéò³â)"
+
+# msgstr "E342: "
+#, c-format
+msgid "Calling shell to execute: \"%s\""
+msgstr "Âèêëèêàºòüñÿ îáîëîíêà ùîá âèêîíàòè: «%s»"
+
+msgid "E545: Missing colon"
+msgstr "E545: Ïðîïóùåíî äâîêðàïêó"
+
+msgid "E546: Illegal mode"
+msgstr "E546: Íåïðàâèëüíèé ðåæèì"
+
+msgid "E547: Illegal mouseshape"
+msgstr "E547: Íåïðàâèëüíèé âèãëÿä ìèø³"
+
+msgid "E548: digit expected"
+msgstr "E548: Ïîòð³áíà öèôðà"
+
+msgid "E549: Illegal percentage"
+msgstr "E549: Íåïðàâèëüíèé â³äñîòîê"
+
+msgid "E854: path too long for completion"
+msgstr "E854: øëÿõ çàíàäòî äîâãèé äëÿ äîïîâíåííÿ"
+
+#, c-format
+msgid ""
+"E343: Invalid path: '**[number]' must be at the end of the path or be "
+"followed by '%s'."
+msgstr ""
+"E343: Íåêîðåêòíèé øëÿõ: `**[÷èñëî]' ïîâèííå áóòè íàïðèê³íö³ øëÿõó àáî ïåðåä "
+"'%s'."
+
+# msgstr "E343: "
+#, c-format
+msgid "E344: Can't find directory \"%s\" in cdpath"
+msgstr "E344: Íå âäàëîñÿ çíàéòè êàòàëîã «%s» ó cdpath"
+
+# msgstr "E344: "
+#, c-format
+msgid "E345: Can't find file \"%s\" in path"
+msgstr "E345: Íå âäàëîñÿ çíàéòè ôàéë «%s» ó path"
+
+# msgstr "E345: "
+#, c-format
+msgid "E346: No more directory \"%s\" found in cdpath"
+msgstr "E346: Ó cdpath íåìຠá³ëüøå êàòàëîãó «%s»"
+
+# msgstr "E346: "
+#, c-format
+msgid "E347: No more file \"%s\" found in path"
+msgstr "E347: Ó øëÿõó ïîøóêó á³ëüøå íåìຠôàéë³â «%s»"
+
+#, c-format
+msgid "E668: Wrong access mode for NetBeans connection info file: \"%s\""
+msgstr ""
+"E668: Íåïðàâèëüíèé ðåæèì äîñòóïó äî ôàéëó ³íôîðìàö³¿ ïðî ç'ºäíàííÿ ç "
+"NetBenans: «%s»"
+
+#, c-format
+msgid "E658: NetBeans connection lost for buffer %ld"
+msgstr "E658: Âòðà÷åíî çâ'ÿçîê ³ç NetBeans äëÿ áóôåðà %ld"
+
+msgid "E838: netbeans is not supported with this GUI"
+msgstr "E838: netbeans íå ï³äòðèìóºòüñÿ ç öèì GUI"
+
+msgid "E511: netbeans already connected"
+msgstr "E511: netbeans âæå ï³ä'ºäíàíî"
+
+#, c-format
+msgid "E505: %s is read-only (add ! to override)"
+msgstr "E505: %s ò³ëüêè äëÿ ÷èòàííÿ (! ùîá íå çâàæàòè)"
+
+# msgstr "E348: "
+msgid "E349: No identifier under cursor"
+msgstr "E349: Íåìຠ³äåíòèô³êàòîðà íàä êóðñîðîì"
+
+msgid "E774: 'operatorfunc' is empty"
+msgstr "E774: 'operatorfunc' ïîðîæíÿ"
+
+msgid "E775: Eval feature not available"
+msgstr "E775: Ìîæëèâ³ñòü eval íåäîñòóïíà"
+
+msgid "Warning: terminal cannot highlight"
+msgstr "Çàñòåðåæåííÿ: Òåðì³íàë íå ï³äòðèìóº êîëüîðè"
+
+msgid "E348: No string under cursor"
+msgstr "E348: Íåìຠðÿäêà íà êóðñîð³"
+
+msgid "E352: Cannot erase folds with current 'foldmethod'"
+msgstr "E352: Íå âäàëîñÿ çíèùèòè çãîðòêè ïîòî÷íèì ìåòîäîì 'foldmethod'"
+
+msgid "E664: changelist is empty"
+msgstr "E664: Ñïèñîê çì³í ïîðîæí³é"
+
+msgid "E662: At start of changelist"
+msgstr "E662: Ïî÷àòîê ñïèñêó çì³í"
+
+msgid "E663: At end of changelist"
+msgstr "E663: ʳíåöü ñïèñêó çì³í"
+
+msgid "Type :qa! and press <Enter> to abandon all changes and exit Vim"
+msgstr ""
+"Óâåä³òü :qa! ³ íàòèñí³òü <Enter>, ùîá â³äêèíóòè âñ³ çì³íè ³ âèéòè ç Vim"
+
+#, c-format
+msgid "1 line %sed 1 time"
+msgstr "Îäèí ðÿäîê %s-íî"
+
+#, c-format
+msgid "1 line %sed %d times"
+msgstr "Îäèí ðÿäîê %s-íî %d ðàç³â"
+
+#, c-format
+msgid "%ld lines %sed 1 time"
+msgstr "%ld ðÿäê³â %s-íî"
+
+#, c-format
+msgid "%ld lines %sed %d times"
+msgstr "%ld ðÿäê³â %s-íî %d ðàç³â"
+
+#, c-format
+msgid "%ld lines to indent... "
+msgstr "Çàëèøèëîñÿ âèð³âíÿòè %ld ðÿäê³â..."
+
+msgid "1 line indented "
+msgstr "Âèð³âíÿíî îäèí ðÿäîê"
+
+#, c-format
+msgid "%ld lines indented "
+msgstr "Âèð³âíÿíî ðÿäê³â: %ld"
+
+msgid "E748: No previously used register"
+msgstr "E748: Ðåã³ñòðè ïåðåä öèì íå âæèâàëèñü"
+
+msgid "cannot yank; delete anyway"
+msgstr "íå âäàëîñÿ çàïàì'ÿòàòè; âñå îäíî çíèùèòè?"
+
+msgid "1 line changed"
+msgstr "Îäèí ðÿäîê çì³íåíî"
+
+#, c-format
+msgid "%ld lines changed"
+msgstr "Çì³íåíî ðÿäê³â: %ld"
+
+#, c-format
+msgid "freeing %ld lines"
+msgstr "Çâ³ëüíåíî ðÿäê³â: %ld"
+
+#, c-format
+msgid " into \"%c"
+msgstr " ó \"%c"
+
+#, c-format
+msgid "block of 1 line yanked%s"
+msgstr "áëîê ç 1 ðÿäêà âèñìèêíóòî%s"
+
+#, c-format
+msgid "1 line yanked%s"
+msgstr "1 ðÿäîê âèñìèêíóòî%s"
+
+#, c-format
+msgid "block of %ld lines yanked%s"
+msgstr "áëîê ³ç %ld ðÿäê³â âèñìèêíóòî%s"
+
+#, c-format
+msgid "%ld lines yanked%s"
+msgstr "%ld ðÿäê³â âèñìèêíóòî%s"
+
+#, c-format
+msgid "E353: Nothing in register %s"
+msgstr "E353: Ó ðåã³ñòð³ %s í³÷îãî íåìàº"
+
+# msgstr "E353: "
+msgid ""
+"\n"
+"--- Registers ---"
+msgstr ""
+"\n"
+"--- Ðåã³ñòðè ---"
+
+msgid "Illegal register name"
+msgstr "Íåïðàâèëüíà íàçâà ðåã³ñòðó"
+
+msgid ""
+"\n"
+"# Registers:\n"
+msgstr ""
+"\n"
+"# Ðåã³ñòðè:\n"
+
+#, c-format
+msgid "E574: Unknown register type %d"
+msgstr "E574: Íåâ³äîìèé òèï ðåã³ñòðó %d"
+
+msgid ""
+"E883: search pattern and expression register may not contain two or more "
+"lines"
+msgstr ""
+"E883: øàáëîí ïîøóêó ³ ðåã³ñòðîâèé âèðàç íå ìîæóòü ì³ñòèòè äâà ÷è á³ëüøå "
+"ðÿäê³â"
+
+#, c-format
+msgid "%ld Cols; "
+msgstr "äîâæ.: %ld; "
+
+#, c-format
+msgid "Selected %s%ld of %ld Lines; %lld of %lld Words; %lld of %lld Bytes"
+msgstr "Âèáðàíî %s%ld ç %ld ðÿäê³â; %lld ç %lld ñë³â; %lld ç %lld áàéò³â"
+
+#, c-format
+msgid ""
+"Selected %s%ld of %ld Lines; %lld of %lld Words; %lld of %lld Chars; %lld of "
+"%lld Bytes"
+msgstr ""
+"Âèáðàíî %s%ld ç %ld ðÿäê³â; %lld ç %lld ñë³â; %lld of %lld ñèìâîë³â; %lld ç "
+"%lld áàéò³â"
+
+#, c-format
+msgid "Col %s of %s; Line %ld of %ld; Word %lld of %lld; Byte %lld of %lld"
+msgstr "Êîëîíêà %s ç %s; ðÿäîê %ld ç %ld; ñëîâî %lld ç %lld; áàéò %lld ç %lld"
+
+#, c-format
+msgid ""
+"Col %s of %s; Line %ld of %ld; Word %lld of %lld; Char %lld of %lld; Byte "
+"%lld of %lld"
+msgstr ""
+"Êîëîíêà %s ç %s; ðÿäîê %ld ç %ld; ñëîâî %lld ç %lld; ñèìâîë %lld of %lld; "
+"áàéò %lld ç %lld"
+
+#, c-format
+msgid "(+%lld for BOM)"
+msgstr "(+%lld äëÿ BOM)"
+
+msgid "Thanks for flying Vim"
+msgstr "Äÿêóºìî çà âèá³ð Vim"
+
+msgid "E518: Unknown option"
+msgstr "E518: Íåâ³äîìà îïö³ÿ"
+
+msgid "E519: Option not supported"
+msgstr "E519: Îïö³ÿ íå ï³äòðèìóºòüñÿ"
+
+msgid "E520: Not allowed in a modeline"
+msgstr "E520: Íå äîçâîëåíî ó modeline"
+
+msgid "E846: Key code not set"
+msgstr "E846: Êîä êëþ÷à íå âñòàíîâëåíî"
+
+msgid "E521: Number required after ="
+msgstr "E521: ϳñëÿ = ïîòð³áíî âêàçàòè ÷èñëî"
+
+msgid "E522: Not found in termcap"
+msgstr "E522: Íå çíàéäåíî ñåðåä ìîæëèâîñòåé òåðì³íàë³â"
+
+#, c-format
+msgid "E539: Illegal character <%s>"
+msgstr "E539: Íåäîçâîëåíèé ñèìâîë <%s>"
+
+#, c-format
+msgid "For option %s"
+msgstr "Äëÿ îïö³¿ %s"
+
+msgid "E529: Cannot set 'term' to empty string"
+msgstr "E529: Íå âäàëîñÿ ñïîðîæíèòè 'term'"
+
+msgid "E530: Cannot change term in GUI"
+msgstr "E530: Íå âäàëîñÿ çì³íèòè term â GUI"
+
+msgid "E531: Use \":gui\" to start the GUI"
+msgstr "E531: Çàñòîñóéòå «:gui» äëÿ çàïóñêó GUI"
+
+msgid "E589: 'backupext' and 'patchmode' are equal"
+msgstr "E589: Îïö³¿ 'backupext' ³ 'patchmode' îäíàêîâ³"
+
+msgid "E834: Conflicts with value of 'listchars'"
+msgstr "E834: Êîíôë³êòóº ³ç çíà÷åííÿì 'listchars'"
+
+msgid "E835: Conflicts with value of 'fillchars'"
+msgstr "E835: Êîíôë³êòóº ³ç çíà÷åííÿì 'fillchars'"
+
+msgid "E617: Cannot be changed in the GTK+ 2 GUI"
+msgstr "E617: Íå ìîæíà çì³íèòè â GUI GTK+ 2"
+
+#, c-format
+msgid "E950: Cannot convert between %s and %s"
+msgstr "E950: Íå ìîæíà ïåðåòâîðèòè ì³æ %s ³ %s"
+
+msgid "E524: Missing colon"
+msgstr "E524: Áðàêóº äâîêðàïêè"
+
+msgid "E525: Zero length string"
+msgstr "E525: Ðÿäîê ïîðîæí³é"
+
+#, c-format
+msgid "E526: Missing number after <%s>"
+msgstr "E526: ϳñëÿ <%s> áðàêóº ÷èñëà"
+
+msgid "E527: Missing comma"
+msgstr "E527: Áðàêóº êîìè"
+
+msgid "E528: Must specify a ' value"
+msgstr "E528: Ïîòð³áíî âêàçàòè çíà÷åííÿ '"
+
+msgid "E595: contains unprintable or wide character"
+msgstr "E595: ̳ñòèòü íåäðóêîâí³ àáî ðîçøèðåí³ ñèìâîëè"
+
+msgid "E596: Invalid font(s)"
+msgstr "E596: Íåêîðåêòíèé(³) øðèôò(è)"
+
+msgid "E597: can't select fontset"
+msgstr "E597: Íå âäàëîñÿ âèáðàòè íàá³ð øðèôò³â"
+
+msgid "E598: Invalid fontset"
+msgstr "E598: Íåïðàâèëüíèé íàá³ð øðèôò³â"
+
+msgid "E533: can't select wide font"
+msgstr "E533: Íå âäàëîñÿ âèêîðèñòàòè ðîçøèðåíèé øðèôò"
+
+msgid "E534: Invalid wide font"
+msgstr "E534: Íåêîðåêòíèé ðîçøèðåíèé øðèôò"
+
+#, c-format
+msgid "E535: Illegal character after <%c>"
+msgstr "E535: Íåäîçâîëåíèé ñèìâîë ï³ñëÿ <%c>"
+
+msgid "E536: comma required"
+msgstr "E536: Ïîòð³áíà êîìà"
+
+#, c-format
+msgid "E537: 'commentstring' must be empty or contain %s"
+msgstr "E537: 'commentstring' ìຠáóòè ïîðîæíüîþ ÷è ì³ñòèòè %s"
+
+msgid "E538: No mouse support"
+msgstr "E538: Ìèøà íå ï³äòðèìóºòüñÿ"
+
+msgid "E540: Unclosed expression sequence"
+msgstr "E540: Ïîñë³äîâí³ñòü âèðàç³â íå çàâåðøåíî"
+
+msgid "E541: too many items"
+msgstr "E541: Çàáàãàòî åëåìåíò³â"
+
+msgid "E542: unbalanced groups"
+msgstr "E542: Ãðóïè íå çáàëàíñîâàíî"
+
+msgid "E946: Cannot make a terminal with running job modifiable"
+msgstr "E946: Íå ìîæíà çðîáèòè ìîäèô³êîâíèì òåðì³íàë ³ç çàïóùåíèì çàâäàííÿì"
+
+msgid "E590: A preview window already exists"
+msgstr "E590: ³êíî ïåðåãëÿäó âæå ³ñíóº"
+
+msgid "W17: Arabic requires UTF-8, do ':set encoding=utf-8'"
+msgstr ""
+"W17: Äëÿ àðàáñüêî¿ ìîâè ïîòð³áíå UTF-8, âèêîíàéòå ':set encoding=utf-8'"
+
+msgid "E954: 24-bit colors are not supported on this environment"
+msgstr "E954: 24-ðîçðÿäí³ êîëüîðè íå ï³äòðèìóþòüñÿ ó öüîìó îòî÷åíí³"
+
+#, c-format
+msgid "E593: Need at least %d lines"
+msgstr "E593: Ïîòð³áíî ùîíàéìåíøå %d ðÿäê³â"
+
+#, c-format
+msgid "E594: Need at least %d columns"
+msgstr "E594: Ïîòð³áíî ùîíàéìåíøå %d ñòîâïö³â"
+
+#, c-format
+msgid "E355: Unknown option: %s"
+msgstr "E355: Íåâ³äîìà îïö³ÿ: %s"
+
+#, c-format
+msgid "E521: Number required: &%s = '%s'"
+msgstr "E521: Ïîòð³áíî âêàçàòè Number: &%s = '%s'"
+
+# msgstr "E355: "
+msgid ""
+"\n"
+"--- Terminal codes ---"
+msgstr ""
+"\n"
+"--- Êîäè òåðì³íàëó ---"
+
+msgid ""
+"\n"
+"--- Global option values ---"
+msgstr ""
+"\n"
+"--- Çíà÷åííÿ çàãàëüíèõ îïö³é ---"
+
+msgid ""
+"\n"
+"--- Local option values ---"
+msgstr ""
+"\n"
+"--- Çíà÷åííÿ ëîêàëüíèõ îïö³é ---"
+
+msgid ""
+"\n"
+"--- Options ---"
+msgstr ""
+"\n"
+"--- Îïö³¿ ---"
+
+msgid "E356: get_varp ERROR"
+msgstr "E356: Ïîìèëêà get_varp"
+
+# msgstr "E356: "
+#, c-format
+msgid "E357: 'langmap': Matching character missing for %s"
+msgstr "E357: 'langmap': Äëÿ ñèìâîëó %s íåìຠïàðè"
+
+# msgstr "E357: "
+#, c-format
+msgid "E358: 'langmap': Extra characters after semicolon: %s"
+msgstr "E358: 'langmap': Çàéâ³ ñèìâîëè ï³ñëÿ `;': %s"
+
+# msgstr "E358: "
+msgid "cannot open "
+msgstr "íå âäàëîñÿ â³äêðèòè "
+
+msgid "VIM: Can't open window!\n"
+msgstr "VIM: Íå âäàëîñÿ â³äêðèòè â³êíî!\n"
+
+msgid "Need Amigados version 2.04 or later\n"
+msgstr "Ïîòð³áíà Amigados 2.04 àáî ï³çí³øà\n"
+
+#, c-format
+msgid "Need %s version %ld\n"
+msgstr "Ïîòð³áíî %s âåðñ³¿ %ld\n"
+
+msgid "Cannot open NIL:\n"
+msgstr "Íå âäàëîñÿ â³äêðèòè NIL:\n"
+
+msgid "Cannot create "
+msgstr "Íå âäàëîñÿ ñòâîðèòè "
+
+#, c-format
+msgid "Vim exiting with %d\n"
+msgstr "Vim çàâåðøóº ðîáîòó ç %d\n"
+
+msgid "cannot change console mode ?!\n"
+msgstr "íå ìîæó çì³íèòè ðåæèì êîíñîë³ ?!\n"
+
+# msgstr "E359: "
+msgid "mch_get_shellsize: not a console??\n"
+msgstr "mch_get_shellsize: íå êîíñîëü??\n"
+
+msgid "E360: Cannot execute shell with -f option"
+msgstr "E360: Íå âäàëîñÿ çàïóñòèòè îáîëîíêó ç îïö³ºþ -f"
+
+# msgstr "E360: "
+msgid "Cannot execute "
+msgstr "Íå âäàëîñÿ âèêîíàòè "
+
+msgid "shell "
+msgstr "îáîëîíêó "
+
+msgid " returned\n"
+msgstr " ïîâåðíóòî\n"
+
+msgid "ANCHOR_BUF_SIZE too small."
+msgstr "ANCHOR_BUF_SIZE çàìàëèé"
+
+msgid "I/O ERROR"
+msgstr "Ïîìèëêà ââîäó/âèâîäó"
+
+msgid "Message"
+msgstr "Ïîâ³äîìëåííÿ"
+
+# msgstr "E364: "
+msgid "E237: Printer selection failed"
+msgstr "E237: Íå âäàëîñÿ âèáðàòè ïðèíòåð"
+
+#, c-format
+msgid "to %s on %s"
+msgstr "íà %s ç %s"
+
+#, c-format
+msgid "E613: Unknown printer font: %s"
+msgstr "E613: Íåâ³äîìèé øðèôò ïðèíòåðà: %s"
+
+#, c-format
+msgid "E238: Print error: %s"
+msgstr "E238: Ïîìèëêà äðóêó: %s"
+
+#, c-format
+msgid "Printing '%s'"
+msgstr "Äðóêóºòüñÿ '%s'"
+
+#, c-format
+msgid "E244: Illegal charset name \"%s\" in font name \"%s\""
+msgstr "E244: Íåêîðåêòíà íàçâà íàáîðó ñèìâîë³â «%s» ó íàçâ³ øðèôòó «%s»"
+
+#, c-format
+msgid "E244: Illegal quality name \"%s\" in font name \"%s\""
+msgstr "E244: Íåêîðåêòíà íàçâà ÿêîñò³ «%s» ó íàçâ³ øðèôòó «%s»"
+
+#, c-format
+msgid "E245: Illegal char '%c' in font name \"%s\""
+msgstr "E245: Ïîìèëêîâèé ñèìâîë %c â íàçâ³ øðèôòó «%s»"
+
+#, c-format
+msgid "Opening the X display took %ld msec"
+msgstr "Íà â³äêðèòòÿ äèñïëåþ X ï³øëî %ld ì³ë³ñåêóíä"
+
+msgid ""
+"\n"
+"Vim: Got X error\n"
+msgstr ""
+"\n"
+"Vim: Ïîìèëêà X\n"
+
+msgid "Testing the X display failed"
+msgstr "Äèñïëåé Õ íå ïðîéøîâ ïåðåâ³ðêó"
+
+msgid "Opening the X display timed out"
+msgstr "Ñïëèâ ÷àñ î÷³êóâàííÿ â³äêðèòòÿ äèñïëåþ Õ"
+
+msgid ""
+"\n"
+"Could not get security context for "
+msgstr ""
+"\n"
+"Íå âäàëîñÿ îòðèìàòè êîíòåêñò áåçïåêè äëÿ "
+
+msgid ""
+"\n"
+"Could not set security context for "
+msgstr ""
+"\n"
+"Íå âäàëîñÿ âñòàíîâèòè êîíòåêñò áåçïåêè äëÿ "
+
+#, c-format
+msgid "Could not set security context %s for %s"
+msgstr "Íå âäàëîñÿ âñòàíîâèòè êîíòåêñò áåçïåêè %s äëÿ %s"
+
+#, c-format
+msgid "Could not get security context %s for %s. Removing it!"
+msgstr "Íå âäàëîñÿ îòðèìàòè êîíòåêñò áåçïåêè %s äëÿ %s. Âèäàëÿºìî!"
+
+msgid ""
+"\n"
+"Cannot execute shell sh\n"
+msgstr ""
+"\n"
+"Íå âäàëîñÿ çàïóñòèòè îáîëîíêó `sh'\n"
+
+# msgstr "E362: "
+msgid ""
+"\n"
+"shell returned "
+msgstr ""
+"\n"
+"îáîëîíêà ïîâåðíóëà: "
+
+msgid ""
+"\n"
+"Cannot create pipes\n"
+msgstr ""
+"\n"
+"Íå ìîæíà ñòâîðèòè êàíàëè\n"
+
+msgid ""
+"\n"
+"Cannot fork\n"
+msgstr ""
+"\n"
+"Íå âäàëîñÿ ðîçäâî¿òèñÿ\n"
+
+msgid ""
+"\n"
+"Cannot execute shell "
+msgstr ""
+"\n"
+"Íå âäàëîñÿ çàïóñòèòè îáîëîíêó"
+
+msgid ""
+"\n"
+"Command terminated\n"
+msgstr ""
+"\n"
+"Êîìàíäà çàê³í÷èëà âèêîíàííÿ\n"
+
+msgid "XSMP lost ICE connection"
+msgstr "XSMP âòðàòèâ ç'ºäíàííÿ ICE"
+
+#, c-format
+msgid "dlerror = \"%s\""
+msgstr "dlerror = «%s»"
+
+msgid "Opening the X display failed"
+msgstr "Íå âäàëîñÿ â³äêðèòè äèñïëåé X"
+
+msgid "XSMP handling save-yourself request"
+msgstr "XSMP îáðîáëÿºòüñÿ çàïèò 'çáåðåæè ñåáå'"
+
+msgid "XSMP opening connection"
+msgstr "XSMP â³äêðèâàºòüñÿ ç'ºäíàííÿ"
+
+msgid "XSMP ICE connection watch failed"
+msgstr "XSMP ñïîñòåðåæåííÿ çà ç'ºäíàííÿì ç ICE íå âäàëîñÿ"
+
+#, c-format
+msgid "XSMP SmcOpenConnection failed: %s"
+msgstr "XSMP íå âäàëîñÿ SmcOpenConnection: %s"
+
+msgid "At line"
+msgstr "Ðÿäîê:"
+
+msgid "Could not load vim32.dll!"
+msgstr "Íå âäàëîñÿ çàâàíòàæèòè vim32.dll"
+
+msgid "VIM Error"
+msgstr "Ïîìèëêà VIM"
+
+msgid "Could not fix up function pointers to the DLL!"
+msgstr "Íå âäàëîñÿ âèïðàâèòè âêàç³âíèêè íà ôóíêö³¿ DLL!"
+
+#, c-format
+msgid "Vim: Caught %s event\n"
+msgstr "Vim: Âèÿâëåíî ïîä³þ %s\n"
+
+msgid "close"
+msgstr "close"
+
+msgid "logoff"
+msgstr "logoff"
+
+msgid "shutdown"
+msgstr "shutdown"
+
+msgid "E371: Command not found"
+msgstr "E371: Êîìàíäó íå çíàéäåíî"
+
+msgid ""
+"VIMRUN.EXE not found in your $PATH.\n"
+"External commands will not pause after completion.\n"
+"See :help win32-vimrun for more information."
+msgstr ""
+"Ôàéë VIMRUN.EXE íå çíàéäåíî ó øëÿõó ïîøóêó.\n"
+"Çîâí³øí³ êîìàíäè íå áóäóòü ïðèçóïèíåí³ ï³ñëÿ âèêîíàííÿ.\n"
+"Ãëÿíüòå :help win32-vimrun ùîá îòðèìàòè ïîäðîáèö³."
+
+msgid "Vim Warning"
+msgstr "Çàñòåðåæåííÿ Vim"
+
+#, c-format
+msgid "shell returned %d"
+msgstr "îáîëîíêà ïîâåðíóëà %d"
+
+msgid "E926: Current location list was changed"
+msgstr "E926: Ïîòî÷íèé ñïèñîê ì³ñöü çì³íèâñÿ"
+
+# msgstr "E371: "
+#, c-format
+msgid "E372: Too many %%%c in format string"
+msgstr "E372: Çàáàãàòî %%%c ó ðÿäêó ôîðìàòó"
+
+# msgstr "E372: "
+#, c-format
+msgid "E373: Unexpected %%%c in format string"
+msgstr "E373: Íåî÷³êóâàíèé `%%%c' ó ðÿäêó ôîðìàòó"
+
+# msgstr "E373: "
+msgid "E374: Missing ] in format string"
+msgstr "E374: Ïðîïóùåíî ] ó ðÿäêó ôîðìàòó"
+
+# msgstr "E374: "
+#, c-format
+msgid "E375: Unsupported %%%c in format string"
+msgstr "E375: %%%c ó ðÿäêó ôîðìàòó íå ï³äòðèìóºòüñÿ"
+
+# msgstr "E375: "
+#, c-format
+msgid "E376: Invalid %%%c in format string prefix"
+msgstr "E376: Ïîìèëêîâèé `%%%c' ó ïðåô³êñ³ ðÿäêó ôîðìàòó"
+
+# msgstr "E376: "
+#, c-format
+msgid "E377: Invalid %%%c in format string"
+msgstr "E377: Ïîìèëêîâèé `%%%c' ó ðÿäêó ôîðìàòó"
+
+# msgstr "E377: "
+msgid "E378: 'errorformat' contains no pattern"
+msgstr "E378: 'errorformat' íå ì³ñòèòü çðàçîê"
+
+# msgstr "E378: "
+msgid "E379: Missing or empty directory name"
+msgstr "E379: Ïðîïóùåíà ÷è ïîðîæíÿ íàçâà êàòàëîãó"
+
+msgid "E553: No more items"
+msgstr "E553: Íåìຠá³ëüøå åëåìåíò³â"
+
+msgid "E924: Current window was closed"
+msgstr "E924: Ïîòî÷íå â³êíî áóëî çàêðèòî"
+
+msgid "E925: Current quickfix was changed"
+msgstr "E925: Ïîòî÷íèé quickfix çì³íèâñÿ"
+
+#, c-format
+msgid "(%d of %d)%s%s: "
+msgstr "(%d ç %d)%s%s: "
+
+msgid " (line deleted)"
+msgstr " (ðÿäîê çíèùåíî)"
+
+#, c-format
+msgid "%serror list %d of %d; %d errors "
+msgstr "%sñïèñîê ïîìèëîê %d ç %d; %d ïîìèëîê"
+
+msgid "E380: At bottom of quickfix stack"
+msgstr "E380: Äíî ñòåêó âèïðàâëåíü"
+
+msgid "E381: At top of quickfix stack"
+msgstr "E381: Âåðøèíà ñòåêó âèïðàâëåíü"
+
+msgid "No entries"
+msgstr "ͳ÷îãî"
+
+# msgstr "E231: "
+msgid "Error file"
+msgstr "Ôàéë ïîìèëîê"
+
+msgid "E683: File name missing or invalid pattern"
+msgstr "E683: Ïðîïóùåíî íàçâó ôàéëó ÷è íåêîðåêòíèé øàáëîí"
+
+#, c-format
+msgid "Cannot open file \"%s\""
+msgstr "Íå âäàëîñÿ â³äêðèòè ôàéë «%s»"
+
+msgid "E681: Buffer is not loaded"
+msgstr "E681: Áóôåð íå çàâàíòàæåíî"
+
+msgid "E777: String or List expected"
+msgstr "E777: Î÷³êóºòüñÿ String ÷è List"
+
+#, c-format
+msgid "E369: invalid item in %s%%[]"
+msgstr "E369: Íåêîðåêòíèé åëåìåíò ó %s%%[]"
+
+#, c-format
+msgid "E769: Missing ] after %s["
+msgstr "E769: Áðàêóº ] ï³ñëÿ %s["
+
+msgid "E944: Reverse range in character class"
+msgstr "E944: Çâîðîòí³é ä³àïàçîí ó êëàñ³ ñèìâîë³â"
+
+msgid "E945: Range too large in character class"
+msgstr "E945: Çàâåëèêèé ä³àïàçîí ó êëàñ³ ñèìâîë³â"
+
+#, c-format
+msgid "E53: Unmatched %s%%("
+msgstr "E53: Íåìຠïàðè %s%%("
+
+#, c-format
+msgid "E54: Unmatched %s("
+msgstr "E54: Íåìຠïàðè %s("
+
+#, c-format
+msgid "E55: Unmatched %s)"
+msgstr "E55: Íåìຠïàðè %s)"
+
+# msgstr "E406: "
+msgid "E66: \\z( not allowed here"
+msgstr "E66: \\z( òóò íå äîçâîëåíî"
+
+# msgstr "E406: "
+msgid "E67: \\z1 - \\z9 not allowed here"
+msgstr "E67: \\z1 òà ³í. òóò íå äîçâîëåíî"
+
+#, c-format
+msgid "E69: Missing ] after %s%%["
+msgstr "E69: Ïðîïóùåíî ] ï³ñëÿ %s%%["
+
+#, c-format
+msgid "E70: Empty %s%%[]"
+msgstr "E70: %s%%[] ïîðîæí³é"
+
+msgid "E65: Illegal back reference"
+msgstr "E65: Íåêîðåêòíå çâîðîòíå ïîñèëàííÿ"
+
+# msgstr "E382: "
+msgid "E339: Pattern too long"
+msgstr "E339: Çðàçîê çàíàäòî äîâãèé"
+
+msgid "E50: Too many \\z("
+msgstr "E50: Çàáàãàòî \\z("
+
+#, c-format
+msgid "E51: Too many %s("
+msgstr "E51: Çàáàãàòî %s("
+
+msgid "E52: Unmatched \\z("
+msgstr "E52: Íåìຠïàðè \\z("
+
+#, c-format
+msgid "E59: invalid character after %s@"
+msgstr "E59: Íåäîçâîëåíèé ñèìâîë ï³ñëÿ %s@"
+
+#, c-format
+msgid "E60: Too many complex %s{...}s"
+msgstr "E60: Çàáàãàòî ñêëàäíèõ %s{...}"
+
+# msgstr "E339: "
+#, c-format
+msgid "E61: Nested %s*"
+msgstr "E61: Âêëàäåí³ %s*"
+
+# msgstr "E61: "
+#, c-format
+msgid "E62: Nested %s%c"
+msgstr "E62: Âêëàäåí³ %s%c"
+
+msgid "E63: invalid use of \\_"
+msgstr "E63: Íåêîðåêòíî âæèòî \\_"
+
+# msgstr "E62: "
+#, c-format
+msgid "E64: %s%c follows nothing"
+msgstr "E64: ϳñëÿ %s%c í³÷îãî íåìàº"
+
+msgid "E68: Invalid character after \\z"
+msgstr "E68: Íåïðàâèëüíèé ñèìâîë ï³ñëÿ \\z"
+
+#, c-format
+msgid "E678: Invalid character after %s%%[dxouU]"
+msgstr "E678: Íåäîçâîëåíèé ñèìâîë ï³ñëÿ %s%%[dxouU]"
+
+#, c-format
+msgid "E71: Invalid character after %s%%"
+msgstr "E71: Íåäîçâîëåíèé ñèìâîë ï³ñëÿ %s%%"
+
+# msgstr "E64: "
+#, c-format
+msgid "E554: Syntax error in %s{...}"
+msgstr "E554: Ñèíòàêñè÷íà ïîìèëêà â %s{...}"
+
+msgid "External submatches:\n"
+msgstr "Çîâí³øí³ ï³ä-çá³ãè:\n"
+
+#, c-format
+msgid "E888: (NFA regexp) cannot repeat %s"
+msgstr "E888: (NFA regexp) íå ìîæíà ïîâòîðèòè %s"
+
+msgid ""
+"E864: \\%#= can only be followed by 0, 1, or 2. The automatic engine will be "
+"used "
+msgstr ""
+"E864: ï³ñëÿ \\%#= ìîæå áóòè ò³ëüêè 0, 1, or 2. Áóäå âèêîðèñòàíî àâòîìàòè÷íèé "
+"ìåõàí³çì "
+
+msgid "Switching to backtracking RE engine for pattern: "
+msgstr "Ïåðåìèêàºìîñÿ äî ïîøóêó ç ïîâåðíåííÿì äëÿ øàáëîíà: "
+
+msgid "E865: (NFA) Regexp end encountered prematurely"
+msgstr "E865: (NFA) Çàðàíî òðàïèâñÿ ê³íåöü ðåãóëÿðíîãî âèðàçó"
+
+#, c-format
+msgid "E866: (NFA regexp) Misplaced %c"
+msgstr "E866: (NFA regexp) Íå íà ì³ñö³ %c"
+
+#, c-format
+msgid "E877: (NFA regexp) Invalid character class: %ld"
+msgstr "E877: (NFA regexp) Íåïðàâèëüíèé êëàñ ñèìâîëó: %ld"
+
+#, c-format
+msgid "E867: (NFA) Unknown operator '\\z%c'"
+msgstr "E867: (NFA) Íåâ³äîìèé îïåðàòîð '\\z%c'"
+
+msgid "E951: \\% value too large"
+msgstr "E951: çíà÷åííÿ \\% çàâåëèêå"
+
+#, c-format
+msgid "E867: (NFA) Unknown operator '\\%%%c'"
+msgstr "E867: (NFA) Íåâ³äîìèé îïåðàòîð '\\%%%c'"
+
+msgid "E868: Error building NFA with equivalence class!"
+msgstr "E868: Íå âäàëîñÿ ïîáóäóâàòè NFA ç êëàñîì åêâ³âàëåíòíîñò³!"
+
+#, c-format
+msgid "E869: (NFA) Unknown operator '\\@%c'"
+msgstr "E869: (NFA) Íåâ³äîìèé îïåðàòîð '\\@%c'"
+
+msgid "E870: (NFA regexp) Error reading repetition limits"
+msgstr "E870: (NFA regexp) Íå âäàëîñÿ ïðî÷èòàòè ìåæ³ ïîâòîðåííÿ"
+
+msgid "E871: (NFA regexp) Can't have a multi follow a multi"
+msgstr "E871: (NFA regexp) Ìóëüòè íå ìîæå áóòè çà ìóëüòè"
+
+msgid "E872: (NFA regexp) Too many '('"
+msgstr "E872: (NFA regexp) Çàáàãàòî '('"
+
+msgid "E879: (NFA regexp) Too many \\z("
+msgstr "E879: (NFA regexp) Çàáàãàòî \\z("
+
+msgid "E873: (NFA regexp) proper termination error"
+msgstr "E873: (NFA regexp) ïîìèëêà íàëåæíîãî ïðèïèíåííÿ"
+
+msgid "E874: (NFA) Could not pop the stack!"
+msgstr "E874: (NFA) Ñòåê ïîðîæí³é!"
+
+msgid ""
+"E875: (NFA regexp) (While converting from postfix to NFA), too many states "
+"left on stack"
+msgstr ""
+"E875: (NFA regexp) (ϳä ÷àñ ïåðåòâîðåííÿ ç ïîñòô³êñ ó NFA) çàëèøèëîñÿ "
+"çàáàãàòî ñòàí³â ó ñòåêó"
+
+msgid "E876: (NFA regexp) Not enough space to store the whole NFA "
+msgstr "E876: (NFA regexp) Íåäîñòàòíüî ïàì’ÿò³, ùîá çáåðåãòè âåñü NFA "
+
+msgid "E878: (NFA) Could not allocate memory for branch traversal!"
+msgstr "E878: (NFA) Íå âäàëîñÿ îòðèìàòè ïàì’ÿòü äëÿ îáõîäó ã³ëîê!"
+
+msgid "Could not open temporary log file for writing, displaying on stderr... "
+msgstr ""
+"Íå âäàëîñÿ â³äêðèòè òèì÷àñîâèé ôàéë æóðíàëó äëÿ çàïèñó, ïîêàçóºòüñÿ íà "
+"stderr... "
+
+#, c-format
+msgid "(NFA) COULD NOT OPEN %s !"
+msgstr "(NFA) ÍÅ ÂÄÀËÎÑß Â²ÄÊÐÈÒÈ %s!"
+
+msgid ""
+"Could not open temporary log file for writing, displaying on stderr ... "
+msgstr ""
+"Íå âäàëîñÿ â³äêðèòè òèì÷àñîâèé ôàéë æóðíàëó äëÿ çàïèñó, ïîêàçóºòüñÿ íà "
+"stderr ... "
+
+msgid "Could not open temporary log file for writing "
+msgstr "Íå âäàëîñÿ â³äêðèòè òèì÷àñîâèé ôàéë æóðíàëó äëÿ çàïèñó "
+
+msgid " VREPLACE"
+msgstr " ²ÐÒ ÇÀ̲ÍÀ"
+
+msgid " REPLACE"
+msgstr " ÇÀ̲ÍÀ"
+
+msgid " REVERSE"
+msgstr " ÍÀÂÈÂÎвÒ"
+
+msgid " INSERT"
+msgstr " ÂÑÒÀÂÊÀ"
+
+msgid " (insert)"
+msgstr " (âñòàâêà)"
+
+msgid " (replace)"
+msgstr " (çàì³íà)"
+
+msgid " (vreplace)"
+msgstr " (â³ðò çàì³íà)"
+
+msgid " Hebrew"
+msgstr " ²âðèò"
+
+msgid " Arabic"
+msgstr " Àðàáñüêà"
+
+msgid " (paste)"
+msgstr " (êëåé)"
+
+msgid " VISUAL"
+msgstr " ÂÈÁ²Ð"
+
+msgid " VISUAL LINE"
+msgstr " ÂÈÁ²Ð ÐßÄʲÂ"
+
+msgid " VISUAL BLOCK"
+msgstr " ÂÈÁ²Ð ÁËÎÊÓ"
+
+msgid " SELECT"
+msgstr " ÂÈIJËÅÍÍß"
+
+msgid " SELECT LINE"
+msgstr " ÂÈIJËÅÍÍß ÐßÄʲÂ"
+
+msgid " SELECT BLOCK"
+msgstr " ÂÈIJËÅÍÍß ÁËÎÊÓ"
+
+msgid "recording"
+msgstr "éäå çàïèñ"
+
+#, c-format
+msgid "E383: Invalid search string: %s"
+msgstr "E383: Íåïðàâèëüíèé çðàçîê äëÿ ïîøóêó: %s"
+
+#, c-format
+msgid "E384: search hit TOP without match for: %s"
+msgstr "E384: Ïîøóê ä³éøîâ äî ÏÎ×ÀÒÊÓ áåç çá³ã³â ç %s"
+
+#, c-format
+msgid "E385: search hit BOTTOM without match for: %s"
+msgstr "E385: Ïîøóê ä³éøîâ äî ʲÍÖß áåç çá³ã³â ç %s"
+
+msgid "E386: Expected '?' or '/' after ';'"
+msgstr "E386: ϳñëÿ `;' ìຠáóòè `?' àáî `/'"
+
+# msgstr "E386: "
+msgid " (includes previously listed match)"
+msgstr " (ðàçîì ç ïîïåðåäí³ìè çá³ãàìè)"
+
+msgid "--- Included files "
+msgstr "--- Âêëþ÷åí³ ôàéëè "
+
+msgid "not found "
+msgstr "íå çíàéäåíî "
+
+msgid "in path ---\n"
+msgstr "ó øëÿõó ïîøóêó ---\n"
+
+msgid " (Already listed)"
+msgstr " (Óæå ó ñïèñêó)"
+
+msgid " NOT FOUND"
+msgstr " ÍÅ ÇÍÀÉÄÅÍÎ"
+
+#, c-format
+msgid "Scanning included file: %s"
+msgstr "Ïîøóê ó âêëþ÷åíîìó ôàéë³: %s"
+
+#, c-format
+msgid "Searching included file %s"
+msgstr "Øóêàºòüñÿ ó âêëþ÷åíîìó ôàéë³ %s"
+
+msgid "E387: Match is on current line"
+msgstr "E387: Çá³ã ó ïîòî÷íîìó ðÿäêó"
+
+msgid "All included files were found"
+msgstr "Áóëè çíàéäåí³ âñ³ âêëþ÷åí³ ôàéëè"
+
+msgid "No included files"
+msgstr "Æîäíîãî âêëþ÷åíîãî ôàéëó"
+
+msgid "E388: Couldn't find definition"
+msgstr "E388: Âèçíà÷åííÿ íå çíàéäåíî"
+
+msgid "E389: Couldn't find pattern"
+msgstr "E389: Çðàçîê íå çíàéäåíî"
+
+msgid "Substitute "
+msgstr "Çàì³íà "
+
+#, c-format
+msgid ""
+"\n"
+"# Last %sSearch Pattern:\n"
+"~"
+msgstr ""
+"\n"
+"# Îñò. %sÇðàçîê ïîøóêó:\n"
+"~"
+
+msgid "E756: Spell checking is not enabled"
+msgstr "E756: Ïåðåâ³ðêà îðôîãðàô³¿ íå äîçâîëåíà"
+
+#, c-format
+msgid "Warning: Cannot find word list \"%s_%s.spl\" or \"%s_ascii.spl\""
+msgstr ""
+"Çàñòåðåæåííÿ: Íå âäàëîñÿ çíàéòè ñïèñîê ñë³â «%s_%s.spl» ÷è «%s_ascii.spl»"
+
+#, c-format
+msgid "Warning: Cannot find word list \"%s.%s.spl\" or \"%s.ascii.spl\""
+msgstr ""
+"Çàñòåðåæåííÿ: Íå âäàëîñÿ çíàéòè ñïèñîê ñë³â «%s.%s.spl» ÷è «%s.ascii.spl»"
+
+msgid "E797: SpellFileMissing autocommand deleted buffer"
+msgstr "E797: Àâòîêîìàíäà SpellFileMissing çíèùèëà áóôåð"
+
+#, c-format
+msgid "Warning: region %s not supported"
+msgstr "Çàñòåðåæåííÿ: ðåã³îí %s íå ï³äòðèìóºòüñÿ"
+
+msgid "Sorry, no suggestions"
+msgstr "Ïðîáà÷òå, íåìຠïðîïîçèö³é"
+
+#, c-format
+msgid "Sorry, only %ld suggestions"
+msgstr "Ïðîáà÷òå, ò³ëüêè %ld ïðîïîçèö³é"
+
+#, c-format
+msgid "Change \"%.*s\" to:"
+msgstr "Çàì³íèòè «%.*s» íà:"
+
+#, c-format
+msgid " < \"%.*s\""
+msgstr " < «%.*s»"
+
+# msgstr "E34: "
+msgid "E752: No previous spell replacement"
+msgstr "E752: Íåìຠïîïåðåäíüî¿ çàì³íè"
+
+# msgstr "E333: "
+#, c-format
+msgid "E753: Not found: %s"
+msgstr "E753: Íå çíàéäåíî: %s"
+
+# msgstr "E364: "
+msgid "E758: Truncated spell file"
+msgstr "E758: Îá³ðâàíèé ôàéë îðôîãðàô³¿"
+
+#, c-format
+msgid "Trailing text in %s line %d: %s"
+msgstr "Çàéâèé òåêñò ó %s ó ðÿäêó %d: %s"
+
+#, c-format
+msgid "Affix name too long in %s line %d: %s"
+msgstr "Íàçâà àô³êñó çàâåëèêà ó %s ó ðÿäêó %d: %s"
+
+# msgstr "E430: "
+msgid "E761: Format error in affix file FOL, LOW or UPP"
+msgstr "E761: Ïîìèëêà ôîðìàòó ó ôàéë³ àô³êñ³â FOL, LOW ÷è UPP"
+
+msgid "E762: Character in FOL, LOW or UPP is out of range"
+msgstr "E762: Ñèìâîë ó FOL, LOW ÷è UPP ïîçà ìåæàìè"
+
+msgid "Compressing word tree..."
+msgstr "Ñòèñêóºòüñÿ äåðåâî ñë³â..."
+
+#, c-format
+msgid "Reading spell file \"%s\""
+msgstr "×èòàºòüñÿ ôàéë îðôîãðàô³¿ «%s»"
+
+msgid "E757: This does not look like a spell file"
+msgstr "E757: Íå ñõîæå íà ôàéë îðôîãðàô³¿"
+
+msgid "E771: Old spell file, needs to be updated"
+msgstr "E771: Ôàéë îðôîãðàô³¿ ñòàðèé, òðåáà ïîíîâèòè"
+
+msgid "E772: Spell file is for newer version of Vim"
+msgstr "E772: Ôàéë îðôîãðàô³¿ ïðèçíà÷åíèé äëÿ á³ëüø íîâî¿ âåðñ³¿ Vim"
+
+msgid "E770: Unsupported section in spell file"
+msgstr "E770: Íåäîçâîëåíà ñåêö³ÿ ó ôàéë³ îðôîãðàô³¿"
+
+#, c-format
+msgid "E778: This does not look like a .sug file: %s"
+msgstr "E778: Íå ñõîæå íà ôàéë .sug: %s"
+
+#, c-format
+msgid "E779: Old .sug file, needs to be updated: %s"
+msgstr "E779: Çàñòàð³ëèé ôàéë .sug, òðåáà ïîíîâèòè: %s"
+
+#, c-format
+msgid "E780: .sug file is for newer version of Vim: %s"
+msgstr "E780: Ôàéë .sug äëÿ á³ëüø íîâî¿ âåðñ³¿ Vim: %s"
+
+#, c-format
+msgid "E781: .sug file doesn't match .spl file: %s"
+msgstr "E781: Ôàéë .sug íå â³äïîâ³äຠôàéëó .spl: %s"
+
+#, c-format
+msgid "E782: error while reading .sug file: %s"
+msgstr "E782: Ïîìèëêà ÷èòàííÿ ôàéëó .sug: %s"
+
+#, c-format
+msgid "Reading affix file %s..."
+msgstr "×èòàºòüñÿ ôàéë àô³êñ³â %s..."
+
+#, c-format
+msgid "Conversion failure for word in %s line %d: %s"
+msgstr "Ïîìèëêà ïåðåòâîðåííÿ ñëîâà ó %s ó ðÿäêó %d: %s"
+
+#, c-format
+msgid "Conversion in %s not supported: from %s to %s"
+msgstr "Ïåðåòâîðåííÿ ó %s íå ï³äòðèìóºòüñÿ: ç %s äî %s"
+
+#, c-format
+msgid "Conversion in %s not supported"
+msgstr "Ïåðåòâîðåííÿ ó %s íå ï³äòðèìóºòüñÿ"
+
+#, c-format
+msgid "Invalid value for FLAG in %s line %d: %s"
+msgstr "Íåêîðåêòíå çíà÷åííÿ FLAG ó %s ó ðÿäêó %d: %s"
+
+#, c-format
+msgid "FLAG after using flags in %s line %d: %s"
+msgstr "FLAG ï³ñëÿ âèêîðèñòàííÿ ïðàïîðö³â ó %s ó ðÿäêó %d: %s"
+
+#, c-format
+msgid ""
+"Defining COMPOUNDFORBIDFLAG after PFX item may give wrong results in %s line "
+"%d"
+msgstr ""
+"Âèçíà÷åííÿ COMPOUNDFORBIDFLAG ï³ñëÿ åëåìåíòó PFX ìîæå äàòè íåïðàâèëüíèé "
+"ðåçóëüòàò ó %s ó ðÿäêó %d"
+
+#, c-format
+msgid ""
+"Defining COMPOUNDPERMITFLAG after PFX item may give wrong results in %s line "
+"%d"
+msgstr ""
+"Âèçíà÷åííÿ COMPOUNDPERMITFLAG ï³ñëÿ åëåìåíòó PFX ìîæó äàòè íåïðàâèëüíèé "
+"ðåçóëüòàò ó %s ó ðÿäêó %d"
+
+#, c-format
+msgid "Wrong COMPOUNDRULES value in %s line %d: %s"
+msgstr "Íåïðàâèëüíå çíà÷åííÿ COMPOUNDRULES ó %s ó ðÿäêó %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDWORDMAX value in %s line %d: %s"
+msgstr "Íåïðàâèëüíå çíà÷åííÿ COMPOUNDWORDMAX ó %s ó ðÿäêó %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDMIN value in %s line %d: %s"
+msgstr "Íåïðàâèëüíå çíà÷åííÿ COMPOUNDMIN ó %s ó ðÿäêó %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDSYLMAX value in %s line %d: %s"
+msgstr "Íåïðàâèëüíå çíà÷åííÿ COMPOUNDSYLMAX ó %s ó ðÿäêó %d: %s"
+
+#, c-format
+msgid "Wrong CHECKCOMPOUNDPATTERN value in %s line %d: %s"
+msgstr "Íåïðàâèëüíå çíà÷åííÿ CHECKCOMPOUNDPATTERN ó %s ó ðÿäêó %d: %s"
+
+#, c-format
+msgid "Different combining flag in continued affix block in %s line %d: %s"
+msgstr ""
+"²íøèé ïðàïîðåöü êîìá³íàö³¿ ó ïðîäîâæåíí³ áëîêó àô³êñ³â ó %s ó ðÿäêó %d: %s"
+
+#, c-format
+msgid "Duplicate affix in %s line %d: %s"
+msgstr "Ïîäâ³éíèé àô³êñ ó %s ó ðÿäêó %d: %s"
+
+#, c-format
+msgid ""
+"Affix also used for BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST in %s "
+"line %d: %s"
+msgstr ""
+"Àô³êñ òàêîæ âèêîðèñòîâóºòüñÿ äëÿ BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/"
+"NOSUGGEST ó %s ó ðÿäêó %d: %s"
+
+#, c-format
+msgid "Expected Y or N in %s line %d: %s"
+msgstr "Òðåáà Y ÷è N ó %s ó ðÿäêó %d: %s"
+
+#, c-format
+msgid "Broken condition in %s line %d: %s"
+msgstr "Íåïðèäàòíà óìîâà ó %s ó ðÿäêó %d: %s"
+
+#, c-format
+msgid "Expected REP(SAL) count in %s line %d"
+msgstr "Òðåáà ê³ëüê³ñòü REP(SAL) ó %s ó ðÿäêó %d"
+
+#, c-format
+msgid "Expected MAP count in %s line %d"
+msgstr "Òðåáà ê³ëüê³ñòü MAP ó %s ó ðÿäêó %d"
+
+#, c-format
+msgid "Duplicate character in MAP in %s line %d"
+msgstr "Ïîâòîðåííÿ ñèìâîëó ó MAP ó %s ó ðÿäêó %d"
+
+#, c-format
+msgid "Unrecognized or duplicate item in %s line %d: %s"
+msgstr "Íåðîçï³çíàíèé ÷è ïîâòîðíèé åëåìåíò ó %s ó ðÿäêó %d: %s"
+
+#, c-format
+msgid "Missing FOL/LOW/UPP line in %s"
+msgstr "Ïðîïóùåíî ðÿäîê FOL/LOW/UPP ó %s"
+
+msgid "COMPOUNDSYLMAX used without SYLLABLE"
+msgstr "Âæèòî COMPOUNDSYLMAX áåç SYLLABLE"
+
+msgid "Too many postponed prefixes"
+msgstr "Çàáàãàòî â³äêëàäåíèõ ïðåô³êñ³â"
+
+msgid "Too many compound flags"
+msgstr "Çàáàãàòî ñêëàäíèõ ïðàïîðö³â"
+
+msgid "Too many postponed prefixes and/or compound flags"
+msgstr "Çàáàãàòî â³äêëàäåíèõ ïðåô³êñ³â ³/àáî ñêëàäíèõ ïðàïîðö³â"
+
+#, c-format
+msgid "Missing SOFO%s line in %s"
+msgstr "Ïðîïóùåíî ðÿäîê SOFO%s ó %s"
+
+#, c-format
+msgid "Both SAL and SOFO lines in %s"
+msgstr "Îáèäâà ðÿäêè SAL ³ SOFO ó %s"
+
+#, c-format
+msgid "Flag is not a number in %s line %d: %s"
+msgstr "Ïðàïîðåöü íå º ÷èñëîì ó %s ó ðÿäêó %d: %s"
+
+#, c-format
+msgid "Illegal flag in %s line %d: %s"
+msgstr "Íåïðàâèëüíèé ïðàïîðåöü ó %s ó ðÿäêó %d: %s"
+
+#, c-format
+msgid "%s value differs from what is used in another .aff file"
+msgstr "Çíà÷åííÿ %s â³äð³çíÿºòüñÿ â³ä òîãî, ùî âæèòî ó ³íøîìó ôàéë³ .aff"
+
+#, c-format
+msgid "Reading dictionary file %s..."
+msgstr "Ç÷èòóºòüñÿ ñëîâíèêîâèé ôàéë %s..."
+
+#, c-format
+msgid "E760: No word count in %s"
+msgstr "E760: Íåìຠê³ëüêîñò³ ñë³â ó %s"
+
+#, c-format
+msgid "line %6d, word %6ld - %s"
+msgstr "ðÿäîê %6d, ñëîâî %6ld - %s"
+
+#, c-format
+msgid "Duplicate word in %s line %d: %s"
+msgstr "Ïîâòîðåííÿ ñëîâà ó %s ó ðÿäêó %d: %s"
+
+#, c-format
+msgid "First duplicate word in %s line %d: %s"
+msgstr "Ïåðøå ïîâòîðåííÿ ñëîâà ó %s ó ðÿäêó %d: %s"
+
+#, c-format
+msgid "%d duplicate word(s) in %s"
+msgstr "%d ïîâòîðþâàíèõ ñë³â ó %s"
+
+#, c-format
+msgid "Ignored %d word(s) with non-ASCII characters in %s"
+msgstr "Ïðîïóùåíî %d ñë³â(~) ³ç íå-ASCII ñèìâîëàìè ó %s"
+
+#, c-format
+msgid "Reading word file %s..."
+msgstr "×èòàºòüñÿ ôàéë ñë³â %s..."
+
+#, c-format
+msgid "Duplicate /encoding= line ignored in %s line %d: %s"
+msgstr "Ïîâòîðåííÿ ðÿäêà /encoding= ïðî³ãíîðîâàíî ó %s ó ðÿäêó %d: %s"
+
+#, c-format
+msgid "/encoding= line after word ignored in %s line %d: %s"
+msgstr "Ðÿäîê /encoding= ï³ñëÿ ñëîâà ïðî³ãíîðîâàíî ó %s ó ðÿäêó %d: %s"
+
+#, c-format
+msgid "Duplicate /regions= line ignored in %s line %d: %s"
+msgstr "Ïîâòîðåííÿ ðÿäêà /regions= ïðî³ãíîðîâàíî ó %s ó ðÿäêó %d: %s"
+
+#, c-format
+msgid "Too many regions in %s line %d: %s"
+msgstr "Çàáàãàòî ðåã³îí³â ó %s ó ðÿäêó %d: %s"
+
+#, c-format
+msgid "/ line ignored in %s line %d: %s"
+msgstr "Ðÿäîê / ïðî³ãíîðîâàíî ó %s ó ðÿäêó %d: %s"
+
+#, c-format
+msgid "Invalid region nr in %s line %d: %s"
+msgstr "Íåêîðåêòíèé íîìåð ðåã³îíó ó %s ó ðÿäêó %d: %s"
+
+#, c-format
+msgid "Unrecognized flags in %s line %d: %s"
+msgstr "Íåðîçï³çíàí³ ïðàïîðö³ ó %s ó ðÿäêó %d: %s"
+
+#, c-format
+msgid "Ignored %d words with non-ASCII characters"
+msgstr "Ïðî³ãíîðîâàíî %d ñë³â ³ç íå-ASCII ñèìâîëàìè"
+
+msgid "E845: Insufficient memory, word list will be incomplete"
+msgstr "E845: Íåäîñòàòíüî ïàì’ÿò³, ñïèñîê ñë³â áóäå íåïîâíèì"
+
+#, c-format
+msgid "Compressed %d of %d nodes; %d (%d%%) remaining"
+msgstr "Ñòèñíåíî %d ç %d âóçë³â; çàëèøèëîñÿ %d (%d%%)"
+
+msgid "Reading back spell file..."
+msgstr "Ïåðå÷èòóºòüñÿ ôàéë îðôîãðàô³¿..."
+
+msgid "Performing soundfolding..."
+msgstr "Âèêîíóºòüñÿ çãîðòàííÿ çâóê³â..."
+
+#, c-format
+msgid "Number of words after soundfolding: %ld"
+msgstr "ʳëüê³ñòü ñë³â ï³ñëÿ çãîðòàííÿ çâóê³â: %ld"
+
+#, c-format
+msgid "Total number of words: %d"
+msgstr "Ïîâíà ê³ëüê³ñòü ñë³â: %d"
+
+#, c-format
+msgid "Writing suggestion file %s..."
+msgstr "Çàïèñóºòüñÿ ôàéë ïðèïóùåíü %s..."
+
+#, c-format
+msgid "Estimated runtime memory use: %d bytes"
+msgstr "Îö³íêà ñïîæèâàííÿ ïàì'ÿò³: %d áàéò"
+
+msgid "E751: Output file name must not have region name"
+msgstr "E751: Âèõ³äíèé ôàéë íå ïîâèíåí ìàòè íàçâó ðåã³îíó"
+
+#, c-format
+msgid "E754: Only up to %ld regions supported"
+msgstr "E754: ϳäòðèìóºòüñÿ ò³ëüêè äî %ld ðåã³îí³â"
+
+#, c-format
+msgid "E755: Invalid region in %s"
+msgstr "E755: Íåêîðåêòíèé ðåã³îí ó %s"
+
+msgid "Warning: both compounding and NOBREAK specified"
+msgstr "Çàñòåðåæåííÿ: çàçíà÷åíî îáèäâà `ñêëàäí³ ñëîâà' ³ NOBREAK"
+
+#, c-format
+msgid "Writing spell file %s..."
+msgstr "Çàïèñóºòüñÿ ôàéë îðôîãðàô³¿ %s..."
+
+msgid "Done!"
+msgstr "Çðîáëåíî!"
+
+#, c-format
+msgid "E765: 'spellfile' does not have %ld entries"
+msgstr "E765: 'spellfile' íå ì³ñòèòü %ld åëåìåíò³â"
+
+#, c-format
+msgid "Word '%.*s' removed from %s"
+msgstr "Ñëîâî '%.*s' çíèùåíî ç %s"
+
+#, c-format
+msgid "Word '%.*s' added to %s"
+msgstr "Ñëîâî '%.*s' äîäàíî äî %s"
+
+msgid "E763: Word characters differ between spell files"
+msgstr "E763: Ñèìâîëè ó ñëîâ³ â³äð³çíÿþòüñÿ ó ôàéëàõ îðôîãðàô³¿"
+
+msgid "E783: duplicate char in MAP entry"
+msgstr "E783: Ïîâòîðåíî ñèìâîë ó åëåìåíò³ MAP"
+
+# msgstr "E391: "
+msgid "No Syntax items defined for this buffer"
+msgstr "Äëÿ áóôåðà íå âèçíà÷åíî åëåìåíò³â ñèíòàêñèñó"
+
+msgid "syntax conceal on"
+msgstr "ìàñêóâàííÿ ñèíòàêñèñó óâ³ìê"
+
+msgid "syntax conceal off"
+msgstr "ìàñêóâàííÿ ñèíòàêñèñó âèìê"
+
+#, c-format
+msgid "E390: Illegal argument: %s"
+msgstr "E390: Íåïðàâèëüíèé àðãóìåíò: %s"
+
+msgid "syntax case ignore"
+msgstr "ñèíòàêñèñ ³ãíîðóâàòè ðåã³ñòð"
+
+msgid "syntax case match"
+msgstr "ñèíòàêñèñ äîòðèìóâàòèñÿ ðåã³ñòðó"
+
+msgid "syntax spell toplevel"
+msgstr "ñèíòàêñèñ ïåðåâ³ðÿòè âñþäè"
+
+msgid "syntax spell notoplevel"
+msgstr "ñèíòàêñèñ íå ïåðåâ³ðÿòè"
+
+msgid "syntax spell default"
+msgstr "ñèíòàêñèñ ïî÷àòêîâî"
+
+msgid "syntax iskeyword "
+msgstr "ñèíòàêñèñ iskeyword "
+
+#, c-format
+msgid "E391: No such syntax cluster: %s"
+msgstr "E391: Íåìຠòàêîãî ñèíòàêñè÷íîãî êëàñòåðà: %s"
+
+msgid "syncing on C-style comments"
+msgstr "ñèíõðîí³çóºòüñÿ ïî êîìåíòàðÿõ ñòèëþ Ñ"
+
+msgid "no syncing"
+msgstr "áåç ñèíõðîí³çàö³¿"
+
+msgid "syncing starts "
+msgstr "ïî÷èíàºòüñÿ ñèíõðîí³çàö³ÿ çà "
+
+msgid " lines before top line"
+msgstr " ðÿäê³â ïåðåä ïåðøèì ðÿäêîì"
+
+msgid ""
+"\n"
+"--- Syntax sync items ---"
+msgstr ""
+"\n"
+"--- Åëåìåíòè ñèíõðîí³çàö³¿ ñèíòàêñèñó ---"
+
+msgid ""
+"\n"
+"syncing on items"
+msgstr ""
+"\n"
+"ñèíõðîí³çàö³ÿ ïî åëåìåíòàõ"
+
+msgid ""
+"\n"
+"--- Syntax items ---"
+msgstr ""
+"\n"
+"--- Åëåìåíòè ñèíòàêñèñó ---"
+
+#, c-format
+msgid "E392: No such syntax cluster: %s"
+msgstr "E392: Íåìຠòàêîãî ñèíòàêñè÷íîãî êëàñòåðà: %s"
+
+msgid "minimal "
+msgstr "ì³í³ìàëüíèé "
+
+msgid "maximal "
+msgstr "ìàêñèìàëüíèé "
+
+msgid "; match "
+msgstr "; çá³ã "
+
+msgid " line breaks"
+msgstr " ðîçðèâè ðÿäê³â"
+
+msgid "E395: contains argument not accepted here"
+msgstr "E395: ̳ñòèòü íåïðèéíÿòí³ òóò àðãóìåíòè"
+
+# msgstr "E14: "
+msgid "E844: invalid cchar value"
+msgstr "E844: Íåêîðåêòíå çíà÷åííÿ cchar"
+
+msgid "E393: group[t]here not accepted here"
+msgstr "E393: group[t]here òóò íåïðèéíÿòíèé"
+
+#, c-format
+msgid "E394: Didn't find region item for %s"
+msgstr "E394: Íå çíàéäåíî åëåìåíò ðåã³îíó äëÿ %s"
+
+# msgstr "E396: "
+msgid "E397: Filename required"
+msgstr "E397: Ïîòð³áíà íàçâà ôàéëó"
+
+msgid "E847: Too many syntax includes"
+msgstr "E847: Çàáàãàòî ñèíòàêñè÷íèõ âêëþ÷åíü"
+
+#, c-format
+msgid "E789: Missing ']': %s"
+msgstr "E789: Ïðîïóùåíî ']': %s"
+
+#, c-format
+msgid "E890: trailing char after ']': %s]%s"
+msgstr "E890: íàäëèøêîâ³ ñèìâîëè ï³ñëÿ ']': %s]%s"
+
+#, c-format
+msgid "E398: Missing '=': %s"
+msgstr "E398: Ïðîïóùåíî `=': %s"
+
+# ---------------------------------------
+#, c-format
+msgid "E399: Not enough arguments: syntax region %s"
+msgstr "E399: Áðàêóº àðãóìåíò³â: ñèíòàêñè÷íèé ðåã³îí %s"
+
+msgid "E848: Too many syntax clusters"
+msgstr "E848: Çàáàãàòî ñèíòàêñè÷íèõ êëàñòåð³â"
+
+msgid "E400: No cluster specified"
+msgstr "E400: Êëàñòåð íå âêàçàíî"
+
+#, c-format
+msgid "E401: Pattern delimiter not found: %s"
+msgstr "E401: ʳíåöü çðàçêó íå çíàéäåíî: %s"
+
+#, c-format
+msgid "E402: Garbage after pattern: %s"
+msgstr "E402: Ñì³òòÿ ï³ñëÿ çðàçêó: %s"
+
+# msgstr "E402: "
+msgid "E403: syntax sync: line continuations pattern specified twice"
+msgstr ""
+"E403: Ñèíòàêñè÷íà ñèíõðîí³çàö³ÿ: çðàçîê äëÿ ïðîäîâæåííÿ ðÿäêà âêàçàíî äâ³÷³"
+
+#, c-format
+msgid "E404: Illegal arguments: %s"
+msgstr "E404: Íåïðàâèëüí³ àðãóìåíòè: %s"
+
+# msgstr "E404: "
+#, c-format
+msgid "E405: Missing equal sign: %s"
+msgstr "E405: Ïðîïóùåíî çíàê ð³âíîñò³: %s"
+
+# msgstr "E405: "
+#, c-format
+msgid "E406: Empty argument: %s"
+msgstr "E406: Ïîðîæí³é àðãóìåíò: %s"
+
+# msgstr "E406: "
+#, c-format
+msgid "E407: %s not allowed here"
+msgstr "E407: %s òóò íå äîçâîëåíî"
+
+#, c-format
+msgid "E408: %s must be first in contains list"
+msgstr "E408: %s ìຠáóòè ïåðøèì ðÿäêîì ó ñïèñêó contains"
+
+#, c-format
+msgid "E409: Unknown group name: %s"
+msgstr "E409: Íåâ³äîìà íàçâà ãðóïè: %s"
+
+# msgstr "E409: "
+#, c-format
+msgid "E410: Invalid :syntax subcommand: %s"
+msgstr "E410: Íåïðàâèëüíà ï³äêîìàíäà :syntax: %s"
+
+msgid ""
+" TOTAL COUNT MATCH SLOWEST AVERAGE NAME PATTERN"
+msgstr ""
+" ÂÑÜÎÃÎ Ê-ÒÜ ÑϲÂÏ. ÍÀÉÏβË. ÑÅÐÅÄÍ. ÍÀÇÂÀ ØÀÁËÎÍ"
+
+msgid "E679: recursive loop loading syncolor.vim"
+msgstr "E679: Ðåêóðñèâíèé öèêë ÷èòàííÿ syncolor.vim"
+
+# msgstr "E410: "
+#, c-format
+msgid "E411: highlight group not found: %s"
+msgstr "E411: Ãðóïó ï³äñâ³÷óâàííÿ íå çíàéäåíî: %s"
+
+# msgstr "E411: "
+#, c-format
+msgid "E412: Not enough arguments: \":highlight link %s\""
+msgstr "E412: Íåäîñòàòíüî àðãóìåíò³â: «:highlight link %s»"
+
+# msgstr "E412: "
+#, c-format
+msgid "E413: Too many arguments: \":highlight link %s\""
+msgstr "E413: Çàáàãàòî àðãóìåíò³â: «:highlight link %s»"
+
+# msgstr "E413: "
+msgid "E414: group has settings, highlight link ignored"
+msgstr "E414: Ãðóìà ìຠsettings, highlight link ïðî³ãíîðîâàíî"
+
+# msgstr "E414: "
+#, c-format
+msgid "E415: unexpected equal sign: %s"
+msgstr "E415: Íåñïîä³âàíèé çíàê ð³âíîñò³: %s"
+
+# msgstr "E415: "
+#, c-format
+msgid "E416: missing equal sign: %s"
+msgstr "E416: Ïðîïóùåíî çíàê ð³âíîñò³: %s"
+
+#, c-format
+msgid "E417: missing argument: %s"
+msgstr "E417: Ïðîïóùåíî àðãóìåíò: %s"
+
+#, c-format
+msgid "E418: Illegal value: %s"
+msgstr "E418: Íåïðàâèëüíå çíà÷åííÿ: %s"
+
+# msgstr "E418: "
+msgid "E419: FG color unknown"
+msgstr "E419: Íåâ³äîìèé êîë³ð òåêñòó"
+
+# msgstr "E419: "
+msgid "E420: BG color unknown"
+msgstr "E420: Íåâ³äîìèé êîë³ð ôîíó"
+
+# msgstr "E420: "
+#, c-format
+msgid "E421: Color name or number not recognized: %s"
+msgstr "E421: Íåðîçï³çíàíà íàçâà àáî íîìåð êîëüîðó: %s"
+
+# msgstr "E421: "
+#, c-format
+msgid "E422: terminal code too long: %s"
+msgstr "E422: Çàíàäòî äîâãèé êîä òåðì³íàëó: %s"
+
+# msgstr "E422: "
+#, c-format
+msgid "E423: Illegal argument: %s"
+msgstr "E423: Íåïðàâèëüíèé àðãóìåíò: %s"
+
+# msgstr "E423: "
+msgid "E424: Too many different highlighting attributes in use"
+msgstr "E424: Âèêîðèñòàíî çàáàãàòî ð³çíèõ àòðèáóò³â êîëüîðó"
+
+msgid "E669: Unprintable character in group name"
+msgstr "E669: Íåäðóêîâíèé ñèìâîë ó íàçâ³ ãðóïè"
+
+# msgstr "E181: "
+msgid "W18: Invalid character in group name"
+msgstr "W18: Íåêîðåêòíèé ñèìâîë ó íàçâ³ ãðóïè"
+
+msgid "E849: Too many highlight and syntax groups"
+msgstr "E849: Çàáàãàòî ãðóï ï³äñâ³÷óâàííÿ ³ ñèíòàêñèñó"
+
+# msgstr "E424: "
+msgid "E555: at bottom of tag stack"
+msgstr "E555: ʳíåöü ñòåêó ì³òîê"
+
+msgid "E556: at top of tag stack"
+msgstr "E556: Âåðøèíà ñòåêó ì³òîê"
+
+msgid "E425: Cannot go before first matching tag"
+msgstr "E425: Öå âæå íàéïåðøà â³äïîâ³äíà ì³òêà"
+
+# msgstr "E425: "
+#, c-format
+msgid "E426: tag not found: %s"
+msgstr "E426: ̳òêó íå çíàéäåíî: %s"
+
+# msgstr "E426: "
+msgid " # pri kind tag"
+msgstr " # ïð³ òèï ì³òêà"
+
+msgid "file\n"
+msgstr "ôàéë\n"
+
+msgid "E427: There is only one matching tag"
+msgstr "E427: Ëèøå îäíà â³äïîâ³äíà ì³òêà"
+
+# msgstr "E427: "
+msgid "E428: Cannot go beyond last matching tag"
+msgstr "E428: Öå âæå îñòàííÿ â³äïîâ³äíà ì³òêà"
+
+# msgstr "E428: "
+#, c-format
+msgid "File \"%s\" does not exist"
+msgstr "Ôàéë «%s» íå ³ñíóº"
+
+#, c-format
+msgid "tag %d of %d%s"
+msgstr "ì³òêà %d ç %d%s"
+
+msgid " or more"
+msgstr " àáî á³ëüøå"
+
+msgid " Using tag with different case!"
+msgstr " Âèêîðèñòàíî ì³òêó, íå ðîçð³çíÿþ÷è âåëèê³ é ìàë³ ë³òåðè"
+
+#, c-format
+msgid "E429: File \"%s\" does not exist"
+msgstr "E429: Ôàéë «%s» íå ³ñíóº"
+
+# msgstr "E429: "
+msgid ""
+"\n"
+" # TO tag FROM line in file/text"
+msgstr ""
+"\n"
+" # ÄÎ ì³òêè Ç ðÿäêà ó ôàéë³/òåêñò³"
+
+#, c-format
+msgid "Searching tags file %s"
+msgstr "Øóêàºòüñÿ ó ôàéë³ ì³òîê %s"
+
+#, c-format
+msgid "E430: Tag file path truncated for %s\n"
+msgstr "E430: Øëÿõ ôàéëó ì³òîê ñêîðî÷åíî äî %s\n"
+
+msgid "Ignoring long line in tags file"
+msgstr "²ãíîðóºòüñÿ äîâãèé ðÿäîê ó ôàéë³ ç ïîçíà÷êàìè"
+
+# msgstr "E430: "
+#, c-format
+msgid "E431: Format error in tags file \"%s\""
+msgstr "E431: Ïîìèëêà ôîðìàòó ó ôàéë³ ì³òîê «%s»"
+
+# msgstr "E431: "
+#, c-format
+msgid "Before byte %ld"
+msgstr "Ïåðåä áàéòîì %ld"
+
+#, c-format
+msgid "E432: Tags file not sorted: %s"
+msgstr "E432: Ôàéë ì³òîê íå âïîðÿäêîâàíèé: %s"
+
+# msgstr "E432: "
+msgid "E433: No tags file"
+msgstr "E433: Íåìຠôàéëó ì³òîê"
+
+# msgstr "E433: "
+msgid "E434: Can't find tag pattern"
+msgstr "E434: Íå âäàëîñÿ çíàéòè çðàçîê ì³òêè"
+
+# msgstr "E434: "
+msgid "E435: Couldn't find tag, just guessing!"
+msgstr "E435: Íå âäàëîñÿ çíàéòè ì³òêó, ò³ëüêè ïðèïóùåííÿ!"
+
+#, c-format
+msgid "Duplicate field name: %s"
+msgstr "Íàçâà ïîëÿ ïîâòîðþºòüñÿ: %s"
+
+# msgstr "E435: "
+msgid "' not known. Available builtin terminals are:"
+msgstr "' íå â³äîìèé. Âáóäîâàí³ òåðì³íàëè:"
+
+msgid "defaulting to '"
+msgstr "ïî÷àòêîâî '"
+
+msgid "E557: Cannot open termcap file"
+msgstr "E557: Íå âäàëîñÿ â³äêðèòè ôàéë ìîæëèâîñòåé òåðì³íàë³â"
+
+msgid "E558: Terminal entry not found in terminfo"
+msgstr "E558: Íåìຠ³íôîðìàö³¿ ïðî òåðì³íàë"
+
+msgid "E559: Terminal entry not found in termcap"
+msgstr "E559: Íåìຠ³íôîðìàö³¿ ïðî ìîæëèâîñò³ òåðì³íàëó"
+
+#, c-format
+msgid "E436: No \"%s\" entry in termcap"
+msgstr "E436: Íåìຠçàïèñó «%s» ïðî ìîæëèâîñò³ òåðì³íàëó"
+
+msgid "E437: terminal capability \"cm\" required"
+msgstr "E437: Ïîòð³áíà ìîæëèâ³ñòü òåðì³íàëó «cm»"
+
+msgid ""
+"\n"
+"--- Terminal keys ---"
+msgstr ""
+"\n"
+"--- Êëàâ³ø³ òåðì³íàëó ---"
+
+msgid "Cannot open $VIMRUNTIME/rgb.txt"
+msgstr "Íåìîæëèâî â³äêðèòè $VIMRUNTIME/rgb.txt"
+
+#, c-format
+msgid "Kill job in \"%s\"?"
+msgstr "Çóïèíèòè çàâäàííÿ ó «%s»?"
+
+msgid "Terminal"
+msgstr "Òåðì³íàë"
+
+msgid "Terminal-finished"
+msgstr "Òåðì³íàë-çàê³í÷åíî"
+
+msgid "active"
+msgstr "àêòèâíèé"
+
+msgid "running"
+msgstr "âèêîíóºòüñÿ"
+
+msgid "finished"
+msgstr "çàê³í÷åíî"
+
+# msgstr "E226: "
+#, c-format
+msgid "E953: File exists: %s"
+msgstr "E953: Ôàéë âæå ³ñíóº: %s"
+
+msgid "E955: Not a terminal buffer"
+msgstr "E955: Íå áóôåð òåðì³íàëó"
+
+msgid "new shell started\n"
+msgstr "çàïóùåíî íîâó îáîëîíêó\n"
+
+msgid "Vim: Error reading input, exiting...\n"
+msgstr "Vim: Ïîìèëêà ÷èòàííÿ ââîäó, ðîáîòà çàâåðøóºòüñÿ...\n"
+
+# msgstr "E242: "
+msgid "Used CUT_BUFFER0 instead of empty selection"
+msgstr "Âèêîðèñòàíî CUT_BUFFER0 çàì³ñòü ïîðîæíüîãî âèä³ëåííÿ"
+
+msgid "E881: Line count changed unexpectedly"
+msgstr "E881: ʳëüê³ñòü ðÿäê³â íåñïîä³âàíî çì³íèëàñÿ"
+
+msgid "No undo possible; continue anyway"
+msgstr "Ñêàñóâàííÿ áóäå íåìîæëèâå, âñå îäíî ïðîäîâæèòè"
+
+#, c-format
+msgid "E828: Cannot open undo file for writing: %s"
+msgstr "E828: Íå âäàëîñÿ â³äêðèòè ôàéë ³ñòî𳿠äëÿ çàïèñó: %s"
+
+#, c-format
+msgid "E825: Corrupted undo file (%s): %s"
+msgstr "E825: Ôàéë ³ñòî𳿠ïîøêîäæåíî (%s): %s"
+
+msgid "Cannot write undo file in any directory in 'undodir'"
+msgstr "Íå âäàëîñÿ çàïèñàòè ôàéë ³ñòî𳿠ó æîäíó ç äèðåêòîð³é ó 'undodir'"
+
+#, c-format
+msgid "Will not overwrite with undo file, cannot read: %s"
+msgstr "Íå ìîæíà ïåðåçàïèñàòè ç ôàéëó ñêàñóâàíü, íå ìîæíà ïðî÷èòàòè: %s"
+
+#, c-format
+msgid "Will not overwrite, this is not an undo file: %s"
+msgstr "Íå ìîæíà ïåðåçàïèñàòè, öå íå ôàéë ³ñòîð³¿: %s"
+
+msgid "Skipping undo file write, nothing to undo"
+msgstr "Ôàéë ³ñòî𳿠íå çàïèñóºòüñÿ, í³÷îãî ïîâåðòàòè"
+
+#, c-format
+msgid "Writing undo file: %s"
+msgstr "Çàïèñóºòüñÿ ôàéë ³ñòîð³¿: %s"
+
+#, c-format
+msgid "E829: write error in undo file: %s"
+msgstr "E829: Ïîìèëêà çàïèñó ó ôàéë³ ³ñòîð³¿: %s"
+
+#, c-format
+msgid "Not reading undo file, owner differs: %s"
+msgstr "Ôàéë ³ñòî𳿠ïðî÷èòàíî íå áóäå, âëàñíèê ³íøèé: %s"
+
+#, c-format
+msgid "Reading undo file: %s"
+msgstr "×èòàºòüñÿ ôàéë ³ñòîð³¿: %s"
+
+#, c-format
+msgid "E822: Cannot open undo file for reading: %s"
+msgstr "E822: Íå âäàëîñÿ â³äêðèòè ôàéë äëÿ ÷èòàííÿ: %s"
+
+# msgstr "E333: "
+#, c-format
+msgid "E823: Not an undo file: %s"
+msgstr "E823: Íå ôàéë ³ñòîð³¿: %s"
+
+#, c-format
+msgid "E832: Non-encrypted file has encrypted undo file: %s"
+msgstr "E832: Íå çàøèôðîâàíèé ôàéë ìຠçàøèôðîâàíèé ôàéë ³ñòîð³¿: %s"
+
+#, c-format
+msgid "E826: Undo file decryption failed: %s"
+msgstr "E826: Íå âäàëîñÿ ðîçøèôðóâàòè ôàéë ³ñòîð³¿: %s"
+
+#, c-format
+msgid "E827: Undo file is encrypted: %s"
+msgstr "E827: Ôàéë ³ñòî𳿠çàøèôðîâàíèé: %s"
+
+#, c-format
+msgid "E824: Incompatible undo file: %s"
+msgstr "E824: Íåñóì³ñíèé ôàéë ³ñòîð³¿: %s"
+
+msgid "File contents changed, cannot use undo info"
+msgstr "Âì³ñò ôàéëó çì³íèâñÿ, íå ìîæíà âèêîðèñòàòè ³íôîðìàö³þ ïðî ³ñòîð³þ"
+
+#, c-format
+msgid "Finished reading undo file %s"
+msgstr "Çàê³í÷åíî ÷èòàííÿ ôàéëó ³ñòî𳿠%s"
+
+msgid "Already at oldest change"
+msgstr "Âæå íà íàéñòàðø³é çì³í³"
+
+msgid "Already at newest change"
+msgstr "Âæå íà íàéíîâ³ø³é çì³í³"
+
+#, c-format
+msgid "E830: Undo number %ld not found"
+msgstr "E830: Çì³íó %ld íå çíàéäåíî â ³ñòîð³¿"
+
+msgid "E438: u_undo: line numbers wrong"
+msgstr "E438: u_undo: íåïðàâèëüí³ íîìåðè ðÿäê³â"
+
+msgid "more line"
+msgstr "äîäàíî ðÿäîê"
+
+msgid "more lines"
+msgstr "ðÿäê³â äîäàíî"
+
+msgid "line less"
+msgstr "çíèùåíî ðÿäîê"
+
+msgid "fewer lines"
+msgstr "ðÿäê³â çíèùåíî"
+
+# msgstr "E438: "
+msgid "change"
+msgstr "çì³íà"
+
+# msgstr "E438: "
+msgid "changes"
+msgstr "çì³í"
+
+#, c-format
+msgid "%ld %s; %s #%ld %s"
+msgstr "%ld %s; %s #%ld %s"
+
+msgid "before"
+msgstr "ïåðåä"
+
+msgid "after"
+msgstr "ï³ñëÿ"
+
+msgid "Nothing to undo"
+msgstr "Íåìຠí³÷îãî ñêàñîâóâàòè"
+
+msgid "number changes when saved"
+msgstr "íîìåð çì³íè ÷àñ çáåðåæåíî"
+
+#, c-format
+msgid "%ld seconds ago"
+msgstr "%ld ñåêóíä òîìó"
+
+# msgstr "E406: "
+msgid "E790: undojoin is not allowed after undo"
+msgstr "E790: Íå ìîæíà âèêîíàòè undojoin ï³ñëÿ undo"
+
+msgid "E439: undo list corrupt"
+msgstr "E439: Ñïèñîê ñêàñóâàííÿ ïîøêîäæåíî"
+
+# msgstr "E439: "
+msgid "E440: undo line missing"
+msgstr "E440: ³äñóòí³é ðÿäîê ñêàñóâàííÿ"
+
+#, c-format
+msgid "E122: Function %s already exists, add ! to replace it"
+msgstr "E122: Ôóíêö³ÿ %s óæå ³ñíóº, ! ùîá çàì³íèòè"
+
+msgid "E717: Dictionary entry already exists"
+msgstr "E717: Çàïèñ ó ñëîâíèêó âæå ³ñíóº"
+
+msgid "E718: Funcref required"
+msgstr "E718: Òðåáà ïîñèëàííÿ íà ôóíêö³þ"
+
+#, c-format
+msgid "E130: Unknown function: %s"
+msgstr "E130: Íåâ³äîìà ôóíêö³ÿ: %s"
+
+#, c-format
+msgid "E125: Illegal argument: %s"
+msgstr "E125: Íåäîçâîëåíèé àðãóìåíò: %s"
+
+#, c-format
+msgid "E853: Duplicate argument name: %s"
+msgstr "E853: Íàçâà àðãóìåíòó ïîâòîðþºòüñÿ: %s"
+
+#, c-format
+msgid "E740: Too many arguments for function %s"
+msgstr "E740: Çàáàãàòî àðãóìåíò³â äëÿ ôóíêö³¿ %s"
+
+#, c-format
+msgid "E116: Invalid arguments for function %s"
+msgstr "E116: Íåïðàâèëüí³ àðãóìåíòè ôóíêö³¿ %s"
+
+msgid "E132: Function call depth is higher than 'maxfuncdepth'"
+msgstr "E132: Ãëèáèíà âèêëèê³â ôóíêö³¿ ïåðåâèùóº 'maxfuncdepth'"
+
+#, c-format
+msgid "calling %s"
+msgstr "âèêëèêàºòüñÿ %s"
+
+#, c-format
+msgid "%s aborted"
+msgstr "%s ïðèïèíåíî"
+
+#, c-format
+msgid "%s returning #%ld"
+msgstr "%s ïîâåðòຠ#%ld"
+
+#, c-format
+msgid "%s returning %s"
+msgstr "%s ïîâåðòຠ%s"
+
+msgid "E699: Too many arguments"
+msgstr "E699: Çàáàãàòî àðãóìåíò³â"
+
+#, c-format
+msgid "E117: Unknown function: %s"
+msgstr "E117: Íåâ³äîìà ôóíêö³ÿ: %s"
+
+#, c-format
+msgid "E933: Function was deleted: %s"
+msgstr "E933: Ôóíêö³þ âèäàëåíî: %s"
+
+#, c-format
+msgid "E119: Not enough arguments for function: %s"
+msgstr "E119: Çàìàëî àðãóìåíò³â äëÿ ôóíêö³¿ %s"
+
+#, c-format
+msgid "E120: Using <SID> not in a script context: %s"
+msgstr "E120: <SID> âèêîðèñòîâóºòüñÿ íå ó êîíòåêñò³ ñêðèïòó: %s"
+
+#, c-format
+msgid "E725: Calling dict function without Dictionary: %s"
+msgstr "E725: Âèêëèê dict-ôóíêö³¿ áåç ñëîâíèêà: %s"
+
+msgid "E129: Function name required"
+msgstr "E129: Íå âêàçàíî íàçâó ôóíêö³¿"
+
+#, c-format
+msgid "E128: Function name must start with a capital or \"s:\": %s"
+msgstr "E128: Íàçâà ôóíêö³¿ ìຠïî÷èíàòèñÿ ç âåëèêî¿ ë³òåðè àáî «s:»: %s"
+
+#, c-format
+msgid "E884: Function name cannot contain a colon: %s"
+msgstr "E884: Íàçâà ôóíêö³¿ íå ìîæå ìàòè äâîêðàïêó: %s"
+
+#, c-format
+msgid "E123: Undefined function: %s"
+msgstr "E123: Íåâèçíà÷åíà ôóíêö³ÿ: %s"
+
+#, c-format
+msgid "E124: Missing '(': %s"
+msgstr "E124: Áðàêóº '(': %s"
+
+msgid "E862: Cannot use g: here"
+msgstr "E862: Òóò íå ìîæíà âèêîðèñòàòè g:"
+
+#, c-format
+msgid "E932: Closure function should not be at top level: %s"
+msgstr "E932: Ôóíêö³ÿ çàìèêàííÿ íå ïîâèííà áóòè íà âåðõíüîìó ð³âí³: %s"
+
+msgid "E126: Missing :endfunction"
+msgstr "E126: Áðàêóº :endfunction"
+
+#, c-format
+msgid "W22: Text found after :endfunction: %s"
+msgstr "W22: Òðàïèâñÿ òåêñò ï³ñëÿ :endfunction: %s"
+
+#, c-format
+msgid "E707: Function name conflicts with variable: %s"
+msgstr "E707: Íàçâà ôóíêö³¿ ñï³âïàäàº ç³ çì³ííîþ: %s"
+
+#, c-format
+msgid "E127: Cannot redefine function %s: It is in use"
+msgstr "E127: Íå âäàëîñÿ ïåðåâèçíà÷èòè ôóíêö³þ %s: âîíà âèêîðèñòîâóºòüñÿ"
+
+#, c-format
+msgid "E746: Function name does not match script file name: %s"
+msgstr "E746: Íàçâà ôóíêö³¿ íå çá³ãàºòüñÿ ç íàçâîþ ôàéëó ñêðèïòó: %s"
+
+#, c-format
+msgid "E131: Cannot delete function %s: It is in use"
+msgstr "E131: Íå âäàëîñÿ çíèùèòè ôóíêö³þ %s: Âîíà âèêîðèñòîâóºòüñÿ"
+
+msgid "E133: :return not inside a function"
+msgstr "E133: :return ïîçà ìåæàìè ôóíêö³¿"
+
+#, c-format
+msgid "E107: Missing parentheses: %s"
+msgstr "E107: Ïðîïóùåíî äóæêè: %s"
+
+msgid ""
+"\n"
+"MS-Windows 64-bit GUI version"
+msgstr ""
+"\n"
+"Âåðñ³ÿ ç GUI äëÿ 64-ðîçðÿäíî¿ MS-Windows"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit GUI version"
+msgstr ""
+"\n"
+"Âåðñ³ÿ ç GUI äëÿ 32-ðîçðÿäíî¿ Windows"
+
+msgid " with OLE support"
+msgstr " ç ï³äòðèìêîþ OLE"
+
+msgid ""
+"\n"
+"MS-Windows 64-bit console version"
+msgstr ""
+"\n"
+"Êîíñîëüíà âåðñ³ÿ äëÿ 64-ðîçðÿäíî¿ Windows"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit console version"
+msgstr ""
+"\n"
+"Êîíñîëüíà âåðñ³ÿ äëÿ 32-ðîçðÿäíî¿ Windows"
+
+msgid ""
+"\n"
+"macOS version"
+msgstr ""
+"\n"
+"Âåðñ³ÿ macOS"
+
+msgid ""
+"\n"
+"macOS version w/o darwin feat."
+msgstr ""
+"\n"
+"Âåðñ³ÿ macOS áåç darwin."
+
+msgid ""
+"\n"
+"OpenVMS version"
+msgstr ""
+"\n"
+"Âåðñ³ÿ äëÿ OpenVMS"
+
+msgid ""
+"\n"
+"Included patches: "
+msgstr ""
+"\n"
+"Âêëþ÷åí³ ëàòêè: "
+
+msgid ""
+"\n"
+"Extra patches: "
+msgstr ""
+"\n"
+"Äîäàòêîâ³ ëàòêè: "
+
+msgid "Modified by "
+msgstr "Çì³íèâ "
+
+msgid ""
+"\n"
+"Compiled "
+msgstr ""
+"\n"
+"Ñêîìï³ëþâàâ "
+
+msgid "by "
+msgstr " "
+
+msgid ""
+"\n"
+"Huge version "
+msgstr ""
+"\n"
+"óãàíòñüêà âåðñ³ÿ "
+
+msgid ""
+"\n"
+"Big version "
+msgstr ""
+"\n"
+"Âåëèêà âåðñ³ÿ "
+
+msgid ""
+"\n"
+"Normal version "
+msgstr ""
+"\n"
+"Íîðìàëüíà âåðñ³ÿ "
+
+msgid ""
+"\n"
+"Small version "
+msgstr ""
+"\n"
+"Ìàëà âåðñ³ÿ "
+
+msgid ""
+"\n"
+"Tiny version "
+msgstr ""
+"\n"
+"Êðèõ³òíà âåðñ³ÿ "
+
+msgid "without GUI."
+msgstr "áåç GUI."
+
+msgid "with GTK3 GUI."
+msgstr "ç GUI GTK3."
+
+msgid "with GTK2-GNOME GUI."
+msgstr "ç GUI GTK2-GNOME."
+
+msgid "with GTK2 GUI."
+msgstr "ç GUI GTK2."
+
+msgid "with X11-Motif GUI."
+msgstr "ç GUI X11-Motif."
+
+msgid "with X11-neXtaw GUI."
+msgstr "ç GUI X11-neXtaw."
+
+msgid "with X11-Athena GUI."
+msgstr "ç GUI X11-Athena."
+
+msgid "with Photon GUI."
+msgstr "ç GUI Photon."
+
+msgid "with GUI."
+msgstr "ç GUI."
+
+msgid "with Carbon GUI."
+msgstr "ç GUI Carbon."
+
+msgid "with Cocoa GUI."
+msgstr "ç GUI Cocoa."
+
+msgid " Features included (+) or not (-):\n"
+msgstr " Âêëþ÷åí³ (+) àáî íå âêëþ÷åí³ (-) êîìïîíåíòè:\n"
+
+msgid " system vimrc file: \""
+msgstr " ñèñòåìíèé vimrc: \""
+
+msgid " user vimrc file: \""
+msgstr " vimrc êîðèñòóâà÷à: \""
+
+msgid " 2nd user vimrc file: \""
+msgstr " äðóãèé vimrc êîðèñòóâà÷à: \""
+
+msgid " 3rd user vimrc file: \""
+msgstr " òðåò³é vimrc êîðèñòóâà÷à: \""
+
+msgid " user exrc file: \""
+msgstr " exrc êîðèñòóâà÷à: \""
+
+msgid " 2nd user exrc file: \""
+msgstr " äðóãèé exrc êîðèñòóâà÷à: \""
+
+msgid " system gvimrc file: \""
+msgstr " ñèñòåìíèé gvimrc: \""
+
+msgid " user gvimrc file: \""
+msgstr " gvimrc êîðèñòóâà÷à: \""
+
+msgid "2nd user gvimrc file: \""
+msgstr "äðóãèé gvimrc êîðèñòóâà÷à: \""
+
+msgid "3rd user gvimrc file: \""
+msgstr "òðåò³é gvimrc êîðèñòóâà÷à: \""
+
+msgid " defaults file: \""
+msgstr " ôàéë defaults: \""
+
+msgid " system menu file: \""
+msgstr " ñèñòåìíå ìåíþ: \""
+
+msgid " fall-back for $VIM: \""
+msgstr " çàì³íà äëÿ $VIM: \""
+
+msgid " f-b for $VIMRUNTIME: \""
+msgstr " çàì³íà äëÿ $VIMRUNTIME: \""
+
+msgid "Compilation: "
+msgstr "Ñêîìï³ëüîâàíî: "
+
+msgid "Compiler: "
+msgstr "Êîìï³ëÿòîð: "
+
+msgid "Linking: "
+msgstr "Ñêîìïîíîâàíî: "
+
+msgid " DEBUG BUILD"
+msgstr " ÂÅÐÑ²ß ÄËß ÍÀËÀÃÎÄÆÅÍÍß"
+
+msgid "VIM - Vi IMproved"
+msgstr "VIM - Ïîêðàùåíèé Vi"
+
+msgid "version "
+msgstr "âåðñ³ÿ "
+
+msgid "by Bram Moolenaar et al."
+msgstr "àâòîð: Bram Moolenaar òà ³í."
+
+msgid "Vim is open source and freely distributable"
+msgstr "Vim — öå â³äêðèòà é â³ëüíî ðîçïîâñþäæóâàíà ïðîãðàìà"
+
+msgid "Help poor children in Uganda!"
+msgstr "Äîïîìîæ³òü ñèðîòàì ç Óãàíäè!"
+
+msgid "type :help iccf<Enter> for information "
+msgstr ":help iccf<Enter> ïîäðîáèö³ "
+
+msgid "type :q<Enter> to exit "
+msgstr ":q<Enter> âèõ³ä ç Vim "
+
+msgid "type :help<Enter> or <F1> for on-line help"
+msgstr ":help<Enter> àáî <F1> ïåðåãëÿä äîïîìîãè "
+
+msgid "type :help version8<Enter> for version info"
+msgstr ":help version8<Enter> ³íôîðìàö³ÿ ïðî âåðñ³þ "
+
+msgid "Running in Vi compatible mode"
+msgstr "Âè ïðàöþºòå â ðåæèì³ ñóì³ñíîìó ç Vi"
+
+msgid "type :set nocp<Enter> for Vim defaults"
+msgstr ":set nocp<Enter> ðåæèì íåñóì³ñíèé ç Vi "
+
+msgid "type :help cp-default<Enter> for info on this"
+msgstr ":help cp-default<Enter> ³íôîðìàö³ÿ ïðî ñóì³ñí³ñòü"
+
+msgid "menu Help->Orphans for information "
+msgstr "ìåíþ Help->Orphans ïîäàëüøà ³íôîðìàö³ÿ "
+
+msgid "Running modeless, typed text is inserted"
+msgstr "Áåç ðåæèì³â, òåêñò ùî íàáðàíî âñòàâëÿºòüñÿ"
+
+msgid "menu Edit->Global Settings->Toggle Insert Mode "
+msgstr "ìåíþ Edit->Global Settings->Toggle Insert Mode "
+
+msgid " for two modes "
+msgstr " äëÿ äâîõ ðåæèì³â "
+
+msgid "menu Edit->Global Settings->Toggle Vi Compatible"
+msgstr "ìåíþ Edit->Global Settings->Toggle Vi Compatible "
+
+msgid " for Vim defaults "
+msgstr " ùîá ïî÷èíàòè â ðåæèì³ ñóì³ñíîñò³ ç Vi"
+
+msgid "Sponsor Vim development!"
+msgstr "ϳäòðèìàéòå ðîçðîáêó ðåäàêòîðà Vim!"
+
+msgid "Become a registered Vim user!"
+msgstr "Ñòàíüòå çàðåºñòðîâàíèì êîðèñòóâà÷åì Vim!"
+
+msgid "type :help sponsor<Enter> for information "
+msgstr ":help sponsor<Enter> ïîäàëüøà ³íôîðìàö³ÿ "
+
+msgid "type :help register<Enter> for information "
+msgstr ":help register<Enter> ïîäàëüøà ³íôîðìàö³ÿ "
+
+msgid "menu Help->Sponsor/Register for information "
+msgstr "ìåíþ Äîïîìîãà->Ñïîíñîð/Ðåºñòðàö³ÿ ïîäðîáèö³ "
+
+# msgstr "E444: "
+msgid "Already only one window"
+msgstr "Öå âæå ºäèíå â³êíî"
+
+msgid "E441: There is no preview window"
+msgstr "E441: Íåìຠâ³êíà ïåðåãëÿäó"
+
+# msgstr "E441: "
+msgid "E442: Can't split topleft and botright at the same time"
+msgstr "E442: Íå âäàëîñÿ îäíî÷àñíî ðîçáèòè topleft ³ botright"
+
+# msgstr "E442: "
+msgid "E443: Cannot rotate when another window is split"
+msgstr "E443: Íå âäàëîñÿ ïåðåì³ñòèòè â³êíî, çàâàæàþòü ³íø³"
+
+# msgstr "E443: "
+msgid "E444: Cannot close last window"
+msgstr "E444: Íå âäàëîñÿ çàêðèòè îñòàííº â³êíî"
+
+# msgstr "E443: "
+msgid "E813: Cannot close autocmd window"
+msgstr "E813: Íå âäàëîñÿ çàêðèòè â³êíî autocmd"
+
+# msgstr "E443: "
+msgid "E814: Cannot close window, only autocmd window would remain"
+msgstr "E814: Íå âäàëîñÿ çàêðèòè â³êíî, çàëèøèëîñÿ á ò³ëüêè â³êíî autocmd"
+
+msgid "E445: Other window contains changes"
+msgstr "E445: Ó ³íøîìó â³êí³ º çì³íè"
+
+# msgstr "E445: "
+msgid "E446: No file name under cursor"
+msgstr "E446: Íåìຠíàçâè ôàéëó íàä êóðñîðîì"
+
+# msgstr "E446: "
+#, c-format
+msgid "E447: Can't find file \"%s\" in path"
+msgstr "E447: Ôàéë «%s» íå çíàéäåíî ó øëÿõó ïîøóêó"
+
+#, c-format
+msgid "E799: Invalid ID: %ld (must be greater than or equal to 1)"
+msgstr "E799: Íåïðàâèëüíèé ID: %ld (ìຠáóòè íå ìåíøèé, í³æ 1)"
+
+#, c-format
+msgid "E801: ID already taken: %ld"
+msgstr "E801: ID âæå çàéíÿòî: %ld"
+
+# msgstr "E396: "
+msgid "List or number required"
+msgstr "Ïîòð³áåí ñïèñîê ÷è ÷èñëî"
+
+#, c-format
+msgid "E802: Invalid ID: %ld (must be greater than or equal to 1)"
+msgstr "E802: Íåïðàâèëüíèé ID: %ld (ìຠáóòè íå ìåíøèé, í³æ 1)"
+
+# msgstr "E333: "
+#, c-format
+msgid "E803: ID not found: %ld"
+msgstr "E803: ID íå çíàéäåíî: %ld"
+
+#, c-format
+msgid "E370: Could not load library %s"
+msgstr "E370: Íå âäàëîñÿ çàâàíòàæèòè á³áë³îòåêó %s"
+
+msgid "Sorry, this command is disabled: the Perl library could not be loaded."
+msgstr ""
+"Âèáà÷òå, öÿ êîìàíäà âèìêíåíà, á³áë³îòåêà Perl íå ìîæå áóòè çàâàíòàæåíà."
+
+msgid "E299: Perl evaluation forbidden in sandbox without the Safe module"
+msgstr "E299: Îá÷èñëåííÿ âèðàç³â Perl çàáîðîíåíå ó ï³ñî÷íèö³ áåç ìîäóëÿ Safe"
+
+msgid "Edit with &multiple Vims"
+msgstr "Ðåäàãóâàòè ó (&m)ð³çíèõ Vim"
+
+msgid "Edit with single &Vim"
+msgstr "Ðåäàãóâàòè ó îäíîìó &Vim"
+
+msgid "Diff with Vim"
+msgstr "Ïîð³âíÿòè ç äîïîìîãîþ Vim"
+
+msgid "Edit with &Vim"
+msgstr "Ðåäàãóâàòè çà äîïîìîãîþ &Vim"
+
+msgid "Edit with existing Vim - "
+msgstr "Ðåäàãóâàòè ó âæå çàïóùåíîìó Vim - "
+
+msgid "Edits the selected file(s) with Vim"
+msgstr "Ðåäàãóº âèáðàí³ ôàéëè ç äîïîìîãîþ Vim"
+
+msgid "Error creating process: Check if gvim is in your path!"
+msgstr "Ïîìèëêà ñòâîðåííÿ ïðîöåñó, ïåðåâ³ðòå ÷è º gvim ó øëÿõó ïîøóêó!"
+
+msgid "gvimext.dll error"
+msgstr "ïîìèëêà gvimext.dll"
+
+msgid "Path length too long!"
+msgstr "Øëÿõ çàíàäòî äîâãèé!"
+
+# msgstr "E447: "
+msgid "--No lines in buffer--"
+msgstr "--Æîäíîãî ðÿäêà--"
+
+msgid "E470: Command aborted"
+msgstr "E470: Êîìàíäó ïåðåðâàíî"
+
+msgid "E471: Argument required"
+msgstr "E471: Íåîáõ³äíî âêàçàòè àðãóìåíò"
+
+msgid "E10: \\ should be followed by /, ? or &"
+msgstr "E10: Çà \\ ìຠéòè /, ? àáî &"
+
+# msgstr "E10: "
+msgid "E11: Invalid in command-line window; <CR> executes, CTRL-C quits"
+msgstr "E11: Íåïðèïóñòèìî ó â³êí³ êîìàíä, <CR> âèêîíóº, CTRL-C âèõîäèòü"
+
+msgid "E12: Command not allowed from exrc/vimrc in current dir or tag search"
+msgstr ""
+"E12: Êîìàíäà íå äîçâîëåíà ó exrc/vimrc ó ïîøóêó ïîòî÷íîãî êàòàëîãó ÷è òå´ó"
+
+msgid "E171: Missing :endif"
+msgstr "E171: Áðàêóº :endif"
+
+msgid "E600: Missing :endtry"
+msgstr "E600: Áðàêóº :endtry"
+
+msgid "E170: Missing :endwhile"
+msgstr "E170: Áðàêóº :endwhile"
+
+msgid "E170: Missing :endfor"
+msgstr "E170: Áðàêóº :endfor"
+
+msgid "E588: :endwhile without :while"
+msgstr "E588: :endwhile áåç :while"
+
+msgid "E588: :endfor without :for"
+msgstr "E588: :endfor áåç :for"
+
+msgid "E13: File exists (add ! to override)"
+msgstr "E13: Ôàéë ³ñíóº (! ùîá íå çâàæàòè)"
+
+msgid "E472: Command failed"
+msgstr "E472: Êîìàíäà íà âäàëàñü"
+
+# msgstr "E233: "
+#, c-format
+msgid "E234: Unknown fontset: %s"
+msgstr "E234: Íåâ³äîìèé íàá³ð øðèôò³â: %s"
+
+#, c-format
+msgid "E235: Unknown font: %s"
+msgstr "E235: Íåâ³äîìèé øðèôò: %s"
+
+# msgstr "E235: "
+#, c-format
+msgid "E236: Font \"%s\" is not fixed-width"
+msgstr "E236: Øðèôò «%s» íå ìîíîøèðèííèé"
+
+msgid "E473: Internal error"
+msgstr "E473: Âíóòð³øíÿ ïîìèëêà"
+
+#, c-format
+msgid "E685: Internal error: %s"
+msgstr "E685: Âíóòð³øíÿ ïîìèëêà: %s"
+
+msgid "Interrupted"
+msgstr "Ïåðåðâàíî"
+
+msgid "E14: Invalid address"
+msgstr "E14: Íåïðàâèëüíà àäðåñà"
+
+# msgstr "E14: "
+msgid "E474: Invalid argument"
+msgstr "E474: Íåêîðåêòíèé àðãóìåíò"
+
+#, c-format
+msgid "E475: Invalid argument: %s"
+msgstr "E475: Íåêîðåêòíèé àðãóìåíò: %s"
+
+#, c-format
+msgid "E475: Invalid value for argument %s"
+msgstr "E475: Íåêîðåêòíå çíà÷åííÿ äëÿ àðãóìåíòó %s"
+
+#, c-format
+msgid "E475: Invalid value for argument %s: %s"
+msgstr "E475: Íåêîðåêòíå çíà÷åííÿ äëÿ àðãóìåíòó %s: %s"
+
+#, c-format
+msgid "E15: Invalid expression: %s"
+msgstr "E15: Íåïðàâèëüíèé âèðàç: %s"
+
+# msgstr "E15: "
+msgid "E16: Invalid range"
+msgstr "E16: Íåïðàâèëüí³ ìåæ³"
+
+# msgstr "E16: "
+msgid "E476: Invalid command"
+msgstr "E476: Íåêîðåêòíà êîìàíäà"
+
+#, c-format
+msgid "E17: \"%s\" is a directory"
+msgstr "E17: «%s» — öå êàòàëîã"
+
+#, c-format
+msgid "E364: Library call failed for \"%s()\""
+msgstr "E364: Á³áë³îòå÷íèé âèêëèê äî «%s()» íå âäàâñÿ"
+
+msgid "E667: Fsync failed"
+msgstr "E667: Íå âäàëîñÿ âèêîíàòè fsync"
+
+#, c-format
+msgid "E448: Could not load library function %s"
+msgstr "E448: Íå âäàëîñÿ çàâàíòàæèòè á³áë³îòå÷íó ôóíêö³þ %s"
+
+# msgstr "E18: "
+msgid "E19: Mark has invalid line number"
+msgstr "E19: Ó ïîì³òêè íåêîðåêòíèé íîìåð ðÿäêà"
+
+# msgstr "E19: "
+msgid "E20: Mark not set"
+msgstr "E20: Ïîì³òêó íå âñòàíîâëåíî"
+
+# msgstr "E20: "
+msgid "E21: Cannot make changes, 'modifiable' is off"
+msgstr "E21: Çì³íè íå äîçâîëåí³: âèìêíåíî 'modifiable'"
+
+# msgstr "E21: "
+msgid "E22: Scripts nested too deep"
+msgstr "E22: Çàáàãàòî âêëàäåíèõ ñêðèïò³â"
+
+# msgstr "E22: "
+msgid "E23: No alternate file"
+msgstr "E23: Íåìຠâòîðèííîãî ôàéëó"
+
+# msgstr "E23: "
+msgid "E24: No such abbreviation"
+msgstr "E24: Òàêîãî ñêîðî÷åííÿ íåìàº"
+
+# msgstr "E24: "
+msgid "E477: No ! allowed"
+msgstr "E477: ! íå äîçâîëåíî"
+
+msgid "E25: GUI cannot be used: Not enabled at compile time"
+msgstr "E25: Íå ìîæíà âèêîðèñòàòè GUI: Íå ââ³ìêíåíî ï³ä ÷àñ êîìï³ëÿö³¿"
+
+msgid "E26: Hebrew cannot be used: Not enabled at compile time\n"
+msgstr "E26: Íå ìîæíà âèêîðèñòàòè ³âðèò: Íå ââ³ìêíåíî ï³ä ÷àñ êîìï³ëÿö³¿\n"
+
+msgid "E27: Farsi cannot be used: Not enabled at compile time\n"
+msgstr "E27: Íå ìîæíà âèêîðèñòàòè ôàðñ³: Íå ââ³ìêíåíî ï³ä ÷àñ êîìï³ëÿö³¿\n"
+
+msgid "E800: Arabic cannot be used: Not enabled at compile time\n"
+msgstr ""
+"E800: Íå ìîæíà âèêîðèñòàòè àðàáñüêó ìîâó: Íå ââ³ìêíåíî ï³ä ÷àñ êîìï³ëÿö³¿\n"
+
+# msgstr "E25: "
+#, c-format
+msgid "E28: No such highlight group name: %s"
+msgstr "E28: Íåìຠòàêî¿ ãðóïè ï³äñâ³÷óâàííÿ: %s"
+
+# msgstr "E28: "
+msgid "E29: No inserted text yet"
+msgstr "E29: Òåêñò ùå íå áóëî äîäàíî"
+
+# msgstr "E29: "
+msgid "E30: No previous command line"
+msgstr "E30: Ùå íå áóëî êîìàíä"
+
+# msgstr "E30: "
+msgid "E31: No such mapping"
+msgstr "E31: Íåìຠòàêî¿ çàì³íè"
+
+# msgstr "E31: "
+msgid "E479: No match"
+msgstr "E479: Æîäíîãî çá³ãó"
+
+#, c-format
+msgid "E480: No match: %s"
+msgstr "E480: Æîäíîãî çá³ãó: %s"
+
+msgid "E32: No file name"
+msgstr "E32: Áðàêóº íàçâè ôàéëó"
+
+# msgstr "E32: "
+msgid "E33: No previous substitute regular expression"
+msgstr "E33: Çàì³íà çðàçê³â ùå íå âèêîðèñòîâóâàëàñü"
+
+# msgstr "E33: "
+msgid "E34: No previous command"
+msgstr "E34: Êîìàíä ùå íå áóëî"
+
+# msgstr "E34: "
+msgid "E35: No previous regular expression"
+msgstr "E35: Çðàçê³â ïîøóêó ùå íå áóëî"
+
+# msgstr "E35: "
+msgid "E481: No range allowed"
+msgstr "E481: Íå äîçâîëåíî âêàçóâàòè ìåæ³"
+
+msgid "E36: Not enough room"
+msgstr "E36: ̳ñöÿ íå âèñòà÷èòü"
+
+#, c-format
+msgid "E247: no registered server named \"%s\""
+msgstr "E247: Íåìຠçàðåºñòðîâàíèõ ñåðâåð³â ç íàçâîþ «%s»"
+
+# msgstr "E36: "
+#, c-format
+msgid "E482: Can't create file %s"
+msgstr "E482: Íå âäàëîñÿ ñòâîðèòè ôàéë %s"
+
+msgid "E483: Can't get temp file name"
+msgstr "E483: Íå âäàëîñÿ ñôîðìóâàòè íàçâó òèì÷àñîâîãî ôàéëó"
+
+#, c-format
+msgid "E484: Can't open file %s"
+msgstr "E484: Íå âäàëîñÿ â³äêðèòè ôàéë %s"
+
+#, c-format
+msgid "E485: Can't read file %s"
+msgstr "E485: Íå âäàëîñÿ ïðî÷èòàòè ôàéë %s"
+
+msgid "E38: Null argument"
+msgstr "E38: ³äñóòí³é àðãóìåíò"
+
+msgid "E39: Number expected"
+msgstr "E39: Î÷³êóºòüñÿ ÷èñëî"
+
+#, c-format
+msgid "E40: Can't open errorfile %s"
+msgstr "E40: Íå âäàëîñÿ â³äêðèòè ôàéë ïîìèëîê %s"
+
+msgid "E233: cannot open display"
+msgstr "E233: Íå âäàëîñÿ â³äêðèòè äèñïëåé"
+
+msgid "E41: Out of memory!"
+msgstr "E41: Çàáðàêëî ïàì'ÿò³!"
+
+msgid "Pattern not found"
+msgstr "Çðàçîê íå çíàéäåíî"
+
+#, c-format
+msgid "E486: Pattern not found: %s"
+msgstr "E486: Çðàçîê íå çíàéäåíî: %s"
+
+msgid "E487: Argument must be positive"
+msgstr "E487: Àðãóìåíò ìຠáóòè äîäàòíèé"
+
+msgid "E459: Cannot go back to previous directory"
+msgstr "E459: Íå âäàëîñÿ ïåðåéòè äî ïîïåðåäíüîãî êàòàëîãó"
+
+msgid "E42: No Errors"
+msgstr "E42: Æîäíî¿ ïîìèëêè"
+
+msgid "E776: No location list"
+msgstr "E776: Íåìຠñïèñêó ì³ñöü"
+
+msgid "E43: Damaged match string"
+msgstr "E43: Òåêñò çá³ãó ïîøêîäæåíî"
+
+msgid "E44: Corrupted regexp program"
+msgstr "E44: dzïñîâàíà ïðîãðàìà ðåãóëÿðíèõ âèðàç³â"
+
+msgid "E45: 'readonly' option is set (add ! to override)"
+msgstr "E45: Âñòàíîâëåíî îïö³þ 'readonly' (! ùîá íå çâàæàòè)"
+
+#, c-format
+msgid "E46: Cannot change read-only variable \"%s\""
+msgstr "E46: Çì³ííà ò³ëüêè äëÿ ÷èòàííÿ: «%s»"
+
+#, c-format
+msgid "E794: Cannot set variable in the sandbox: \"%s\""
+msgstr "E794: Íå ìîæíà âñòàíîâèòè çì³ííó ó ï³ñî÷íèö³: «%s»"
+
+msgid "E713: Cannot use empty key for Dictionary"
+msgstr "E713: Êëþ÷ ñëîâíèêà íå ìîæå áóòè ïîðîæí³ì"
+
+msgid "E715: Dictionary required"
+msgstr "E715: Ïîòð³áåí ñëîâíèê"
+
+#, c-format
+msgid "E684: list index out of range: %ld"
+msgstr "E684: ²íäåêñ ñïèñêó ïîçà ìåæàìè: %ld"
+
+#, c-format
+msgid "E118: Too many arguments for function: %s"
+msgstr "E118: Çàáàãàòî àðãóìåíò³â äëÿ ôóíêö³¿: %s"
+
+#, c-format
+msgid "E716: Key not present in Dictionary: %s"
+msgstr "E716: Íåìຠòàêîãî êëþ÷à ó ñëîâíèêó: %s"
+
+# msgstr "E396: "
+msgid "E714: List required"
+msgstr "E714: Ïîòð³áåí ñïèñîê"
+
+#, c-format
+msgid "E712: Argument of %s must be a List or Dictionary"
+msgstr "E712: Àðãóìåíò ó %s ìຠáóòè ñïèñêîì ÷è ñëîâíèêîì"
+
+msgid "E47: Error while reading errorfile"
+msgstr "E47: Ïîìèëêà ÷èòàííÿ ôàéëó ïîìèëîê"
+
+msgid "E48: Not allowed in sandbox"
+msgstr "E48: Íà äîçâîëåíî ó ï³ñî÷íèö³"
+
+msgid "E523: Not allowed here"
+msgstr "E523: Íå äîçâîëåíî òóò"
+
+msgid "E359: Screen mode setting not supported"
+msgstr "E359: Ðåæèì åêðàíó íå ï³äòðèìóºòüñÿ"
+
+msgid "E49: Invalid scroll size"
+msgstr "E49: Íåêîðåêòíèé ðîçì³ð çñóâó"
+
+msgid "E91: 'shell' option is empty"
+msgstr "E91: Îïö³ÿ 'shell' ïîðîæíÿ"
+
+# msgstr "E254: "
+msgid "E255: Couldn't read in sign data!"
+msgstr "E255: Íå ìîæíà ç÷èòàòè äàí³ íàïèñó!"
+
+msgid "E72: Close error on swap file"
+msgstr "E72: Ïîìèëêà ï³ä ÷àñ çàêðèòòÿ ôàéëó îáì³íó"
+
+msgid "E73: tag stack empty"
+msgstr "E73: Ñòåê ì³òîê ïîðîæí³é"
+
+msgid "E74: Command too complex"
+msgstr "E74: Çàíàäòî ñêëàäíà êîìàíäà"
+
+msgid "E75: Name too long"
+msgstr "E75: Çàäîâãå ³ì'ÿ"
+
+msgid "E76: Too many ["
+msgstr "E76: Çàáàãàòî '['"
+
+msgid "E77: Too many file names"
+msgstr "E77: Çàáàãàòî íàçâ ôàéë³â"
+
+msgid "E488: Trailing characters"
+msgstr "E488: Íàäëèøêîâ³ ñèìâîëè"
+
+msgid "E78: Unknown mark"
+msgstr "E78: Íåâ³äîìà ïîì³òêà"
+
+msgid "E79: Cannot expand wildcards"
+msgstr "E79: Íå âäàëîñÿ ðîçêðèòè øàáëîí"
+
+msgid "E591: 'winheight' cannot be smaller than 'winminheight'"
+msgstr "E591: 'winheight' íå ìîæå áóòè ìåíøèì çà 'winminheight'"
+
+msgid "E592: 'winwidth' cannot be smaller than 'winminwidth'"
+msgstr "E592: 'winwidth' íå ìîæå áóòè ìåíøèì çà 'winminwidth'"
+
+# msgstr "E79: "
+msgid "E80: Error while writing"
+msgstr "E80: Ïîìèëêà ï³ä ÷àñ çàïèñó"
+
+# msgstr "E396: "
+msgid "E939: Positive count required"
+msgstr "E939: Ïîòð³áíà äîäàòíà ê³ëüê³ñòü"
+
+msgid "E81: Using <SID> not in a script context"
+msgstr "E81: <SID> âèêîðèñòîâóºòüñÿ íå â êîíòåêñò³ ñêðèïòó"
+
+msgid "E449: Invalid expression received"
+msgstr "E449: Îòðèìàíî íåêîðåêòíèé âèðàç"
+
+msgid "E463: Region is guarded, cannot modify"
+msgstr "E463: Íå ìîæíà çì³íèòè çàõèùåíèé ðåã³îí"
+
+msgid "E744: NetBeans does not allow changes in read-only files"
+msgstr "E744: NetBeans íå äîçâîëÿº çì³íþâàòè çàõèùåí³ â³ä çàïèñó ôàéëè"
+
+msgid "E363: pattern uses more memory than 'maxmempattern'"
+msgstr "E363: Çðàçîê âèêîðèñòîâóº á³ëüøå, í³æ 'maxmempattern', ïàì'ÿò³"
+
+msgid "E749: empty buffer"
+msgstr "E749: Ïîðîæí³é áóôåð"
+
+#, c-format
+msgid "E86: Buffer %ld does not exist"
+msgstr "E86: Áóôåðà %ld íåìàº"
+
+msgid "E682: Invalid search pattern or delimiter"
+msgstr "E682: Íåêîðåêòíèé çðàçîê äëÿ ïîøóêó ÷è ðîçä³ëüíèê"
+
+msgid "E139: File is loaded in another buffer"
+msgstr "E139: Ôàéë óæå çàâàíòàæåíî â ³íøèé áóôåð"
+
+# msgstr "E235: "
+#, c-format
+msgid "E764: Option '%s' is not set"
+msgstr "E764: Îïö³ÿ '%s' íå âñòàíîâëåíà"
+
+msgid "E850: Invalid register name"
+msgstr "E850: Íåïðàâèëüíà íàçâà ðåã³ñòðó"
+
+#, c-format
+msgid "E919: Directory not found in '%s': \"%s\""
+msgstr "E919: Òåêó íå çíàéäåíî: '%s': «%s»"
+
+msgid "E952: Autocommand caused recursive behavior"
+msgstr "E952: Àâòîêîìàíäè ïðèçâåëè äî ðåêóðñ³¿"
+
+msgid "search hit TOP, continuing at BOTTOM"
+msgstr "Ïîøóê ä³éøîâ äî ÏÎ×ÀÒÊÓ, ïðîäîâæóºòüñÿ ç ʲÍÖß"
+
+msgid "search hit BOTTOM, continuing at TOP"
+msgstr "Ïîøóê ä³éøîâ äî ʲÍÖß, ïðîäîâæóºòüñÿ ç ÏÎ×ÀÒÊÓ"
+
+#, c-format
+msgid "Need encryption key for \"%s\""
+msgstr "Äëÿ «%s» ïîòð³áåí êëþ÷: "
+
+# msgstr "E406: "
+msgid "empty keys are not allowed"
+msgstr "ïîðîæí³ êëþ÷³ íå äîçâîëåí³"
+
+msgid "dictionary is locked"
+msgstr "ñëîâíèê çàáëîêîâàíî"
+
+msgid "list is locked"
+msgstr "ñïèñîê çàáëîêîâàíî"
+
+#, c-format
+msgid "failed to add key '%s' to dictionary"
+msgstr "íå âäàëîñÿ äîäàòè êëþ÷ '%s' äî ñëîâíèêà"
+
+#, c-format
+msgid "index must be int or slice, not %s"
+msgstr "³íäåêñ ìຠáóòè ö³ëèé ÷è çð³ç, íå %s"
+
+#, c-format
+msgid "expected str() or unicode() instance, but got %s"
+msgstr "î÷³êóâàâñÿ åêçåìïëÿð str() ÷è unicode(), àëå îòðèìàíî %s"
+
+#, c-format
+msgid "expected bytes() or str() instance, but got %s"
+msgstr "î÷³êóâàâñÿ åêçåìïëÿð bytes() ÷è str(), àëå îòðèìàíî %s"
+
+#, c-format
+msgid ""
+"expected int(), long() or something supporting coercing to long(), but got %s"
+msgstr ""
+"î÷³êóâàâñÿ int(), long() ÷è ùîñü, ùî ìîæå áóòè âì³ùåíå long(), àëå îòðèìàíî "
+"%s"
+
+#, c-format
+msgid "expected int() or something supporting coercing to int(), but got %s"
+msgstr "î÷³êóâàâñÿ int() ÷è ùîñü, ùî ìîæå áóòè âì³ùåíå int(), àëå îòðèìàíî %s"
+
+msgid "value is too large to fit into C int type"
+msgstr "çíà÷åííÿ çàâåëèêå, ùîá âì³ñòèòèñÿ ó òèï C int"
+
+msgid "value is too small to fit into C int type"
+msgstr "çíà÷åííÿ çàìàëå, ùîá âì³ñòèòèñÿ ó òèï C int"
+
+msgid "number must be greater than zero"
+msgstr "÷èñëî ìຠáóòè á³ëüøå, í³æ íóëü"
+
+msgid "number must be greater or equal to zero"
+msgstr "÷èñëî ìຠáóòè íå ìåíøå, í³æ íóëü"
+
+msgid "can't delete OutputObject attributes"
+msgstr "íå âäàëîñÿ çíèùèòè àòðèáóòè OutputObject"
+
+# msgstr "E180: "
+#, c-format
+msgid "invalid attribute: %s"
+msgstr "íåïðàâèëüíèé àòðèáóò: %s"
+
+msgid "E264: Python: Error initialising I/O objects"
+msgstr "E264: Python: Ïîìèëêà ³í³ö³àë³çàö³¿ îá'ºêò³â ââîäó/âèâîäó"
+
+msgid "failed to change directory"
+msgstr "íå âäàëîñÿ çì³íèòè äèðåêòîð³þ"
+
+#, c-format
+msgid "expected 3-tuple as imp.find_module() result, but got %s"
+msgstr "î÷³êóâàâñÿ 3-êîðòåæ ÿê ðåçóëüòàò imp.find_module(), àëå îòðèìàíî %s"
+
+#, c-format
+msgid "expected 3-tuple as imp.find_module() result, but got tuple of size %d"
+msgstr "î÷³êóâàâñÿ 3-êîðòåæ ÿê ðåçóëüòàò imp.find_module(), àëå îòðèìàíî %d"
+
+msgid "internal error: imp.find_module returned tuple with NULL"
+msgstr "âíóòð³øíÿ ïîìèëêà: imp.find_module ïîâåðíóëà êîðòåæ ç NULL"
+
+msgid "cannot delete vim.Dictionary attributes"
+msgstr "íå âäàëîñÿ çíèùèòè àòðèáóòè vim.Dictionary"
+
+msgid "cannot modify fixed dictionary"
+msgstr "íå ìîæíà çì³íèòè ô³êñîâàíèé ñëîâíèê"
+
+#, c-format
+msgid "cannot set attribute %s"
+msgstr "íå ìîæíà âñòàíîâèòè àòðèáóò %s"
+
+msgid "hashtab changed during iteration"
+msgstr "õåø-òàáëèöÿ çì³íèëàñÿ ï³ä ÷àñ ïåðåáèðàííÿ"
+
+#, c-format
+msgid "expected sequence element of size 2, but got sequence of size %d"
+msgstr ""
+"î÷³êóâàëàñü ïîñë³äîâí³ñòü ðîçì³ðîì 2, àëå îòðèìàíî ïîñë³äîâí³ñòü ðîçì³ðó %d"
+
+msgid "list constructor does not accept keyword arguments"
+msgstr "ñïèñêîâèé êîíñòðóêòîð íå ïðèéìຠ³ìåíîâàí³ àðãóìåíòè"
+
+msgid "list index out of range"
+msgstr "³íäåêñ ñïèñêó çà ìåæàìè"
+
+#, c-format
+msgid "internal error: failed to get vim list item %d"
+msgstr "âíóòð³øíÿ ïîìèëêà: íå âäàëîñÿ îòðèìàòè åëåìåíò ñïèñêó vim %d"
+
+msgid "slice step cannot be zero"
+msgstr "êðîê çð³çó íå ìîæå áóòè íóëü"
+
+#, c-format
+msgid "attempt to assign sequence of size greater than %d to extended slice"
+msgstr ""
+"ñïðîáà ïðèçíà÷èòè ïîñë³äîâí³ñòü ðîçì³ðó á³ëüøå, í³æ %d, ó ðîçøèðåíèé çð³ç"
+
+#, c-format
+msgid "internal error: no vim list item %d"
+msgstr "âíóòð³øíÿ ïîìèëêà: íåìຠåëåìåíòà ñïèñêó vim %d"
+
+msgid "internal error: not enough list items"
+msgstr "âíóòð³øíÿ ïîìèëêà: áðàêóº åëåìåíò³â ó ñïèñêó"
+
+msgid "internal error: failed to add item to list"
+msgstr "âíóòð³øíÿ ïîìèëêà: íå âäàëîñÿ äîäàòè åëåìåíò äî ñïèñêó"
+
+#, c-format
+msgid "attempt to assign sequence of size %d to extended slice of size %d"
+msgstr ""
+"ñïðîáà ïðèçíà÷èòè ïîñë³äîâí³ñòü ðîçì³ðîì %d ó ðîçøèðåíèé çð³ç ðîçì³ðó %d"
+
+msgid "failed to add item to list"
+msgstr "íå âäàëîñÿ äîäàòè åëåìåíò äî ñïèñêó"
+
+msgid "cannot delete vim.List attributes"
+msgstr "íå âäàëîñÿ çíèùèòè àòðèáóòè vim.List"
+
+msgid "cannot modify fixed list"
+msgstr "íå ìîæíà çì³íèòè ô³êñîâàíèé ñïèñîê"
+
+# msgstr "E428: "
+#, c-format
+msgid "unnamed function %s does not exist"
+msgstr "áåç³ìåííî¿ ôóíêö³¿ %s íå ³ñíóº"
+
+# msgstr "E428: "
+#, c-format
+msgid "function %s does not exist"
+msgstr "ôóíêö³¿ %s íå ³ñíóº"
+
+#, c-format
+msgid "failed to run function %s"
+msgstr "íå âäàëîñÿ âèêîíàòè ôóíêö³þ %s"
+
+msgid "unable to get option value"
+msgstr "íå âäàëîñÿ îòðèìàòè çíà÷åííÿ îïö³¿"
+
+msgid "internal error: unknown option type"
+msgstr "âíóòð³øíÿ ïîìèëêà: íåâ³äîìèé òèï îïö³¿"
+
+msgid "problem while switching windows"
+msgstr "íå âäàëîñÿ ïåðåìêíóòè â³êíà"
+
+#, c-format
+msgid "unable to unset global option %s"
+msgstr "íå âäàëîñÿ ñêèíóòè ãëîáàëüíó îïö³þ %s"
+
+#, c-format
+msgid "unable to unset option %s which does not have global value"
+msgstr "íå âäàëîñÿ ñêèíóòè îïö³þ %s, ÿêà íå ìຠãëîáàëüíîãî çíà÷åííÿ"
+
+msgid "attempt to refer to deleted tab page"
+msgstr "ñïðîáà çâåðíåííÿ äî çíèùåíî¿ âêëàäêè"
+
+msgid "no such tab page"
+msgstr "òàêî¿ âêëàäêè íåìàº"
+
+msgid "attempt to refer to deleted window"
+msgstr "ñïðîáà çâåðíóòèñÿ äî çíèùåíîãî â³êíà"
+
+msgid "readonly attribute: buffer"
+msgstr "àòðèáóò ëèøå äëÿ ÷èòàííÿ: áóôåð"
+
+msgid "cursor position outside buffer"
+msgstr "êóðñîð çà ìåæàìè áóôåðà"
+
+msgid "no such window"
+msgstr "òàêîãî â³êíà íåìàº"
+
+msgid "attempt to refer to deleted buffer"
+msgstr "ñïðîáà çâåðíåííÿ äî çíèùåíîãî áóôåðà"
+
+msgid "failed to rename buffer"
+msgstr "íå âäàëîñÿ ïåðåéìåíóâàòè áóôåð"
+
+msgid "mark name must be a single character"
+msgstr "íàçâîþ ì³òêè ìຠáóòè îäèí ñèìâîë"
+
+#, c-format
+msgid "expected vim.Buffer object, but got %s"
+msgstr "î÷³êóâàâñÿ îá’ºêò vim.Buffer, àëå îòðèìàíî %s"
+
+#, c-format
+msgid "failed to switch to buffer %d"
+msgstr "íå âäàëîñÿ ïåðåìêíóòèñÿ äî áóôåðà %d"
+
+#, c-format
+msgid "expected vim.Window object, but got %s"
+msgstr "î÷³êóâàâñÿ îá’ºêò vim.Window, àëå îòðèìàíî %s"
+
+msgid "failed to find window in the current tab page"
+msgstr "íå âäàëîñÿ çíàéòè â³êíî ó ïîòî÷í³é âêëàäö³"
+
+msgid "did not switch to the specified window"
+msgstr "íå ïåðåìêíóâñÿ äî âêàçàíîãî â³êíà"
+
+#, c-format
+msgid "expected vim.TabPage object, but got %s"
+msgstr "î÷³êóâàâñÿ îá’ºêò vim.TabPage, àëå îòðèìàíî %s"
+
+msgid "did not switch to the specified tab page"
+msgstr "íå ïåðåìêíóâñÿ äî âêàçàíî¿ âêëàäêè"
+
+msgid "failed to run the code"
+msgstr "íå âäàëîñÿ âèêîíàòè êîä"
+
+msgid "E858: Eval did not return a valid python object"
+msgstr "E858: Eval íå ïîâåðíóâ ä³éñíèé îá’ºêò python"
+
+msgid "E859: Failed to convert returned python object to vim value"
+msgstr "E859: Íå âäàëîñÿ ïåðåòâîðèòè îá’ºêò python ó çíà÷åííÿ vim"
+
+#, c-format
+msgid "unable to convert %s to vim dictionary"
+msgstr "íå âäàëîñÿ ïåðåòâîðèòè %s ó ñëîâíèê vim"
+
+#, c-format
+msgid "unable to convert %s to vim list"
+msgstr "íå âäàëîñÿ ïåðåòâîðèòè %s ó ñïèñîê vim"
+
+#, c-format
+msgid "unable to convert %s to vim structure"
+msgstr "íå âäàëîñÿ ïåðåòâîðèòè %s ó ñòðóêòóðó vim"
+
+msgid "internal error: NULL reference passed"
+msgstr "âíóòð³øíÿ ïîìèëêà: ïåðåäàíî ïîñèëàííÿ NULL"
+
+msgid "internal error: invalid value type"
+msgstr "âíóòð³øíÿ ïîìèëêà: íåïðàâèëüíèé òèï çíà÷åííÿ"
+
+msgid ""
+"Failed to set path hook: sys.path_hooks is not a list\n"
+"You should now do the following:\n"
+"- append vim.path_hook to sys.path_hooks\n"
+"- append vim.VIM_SPECIAL_PATH to sys.path\n"
+msgstr ""
+"Íå âäàëîñÿ âñòàíîâèòè îáðîáíèê øëÿõó: sys.path_hooks íå ñïèñîê\n"
+"Âàì ñë³ä â÷èíèòè òàê:\n"
+"- äîäàéòå vim.path_hook äî sys.path_hooks\n"
+"- äîäàéòå vim.VIM_SPECIAL_PATH äî sys.path\n"
+
+msgid ""
+"Failed to set path: sys.path is not a list\n"
+"You should now append vim.VIM_SPECIAL_PATH to sys.path"
+msgstr ""
+"Íå âäàëîñÿ âñòàíîâèòè øëÿõ: sys.path íå ñïèñîê\n"
+"Âàñ ñë³ä äîäàòè vim.VIM_SPECIAL_PATH äî sys.path"
+
+msgid ""
+"Vim macro files (*.vim)\t*.vim\n"
+"All Files (*.*)\t*.*\n"
+msgstr ""
+"Ìàêðîñè Vim (*.vim)\t*.vim\n"
+"Âñ³ ôàéëè (*.*)\t*.*\n"
+
+msgid "All Files (*.*)\t*.*\n"
+msgstr "Âñ³ ôàéëè (*.*)\t*.*\n"
+
+msgid ""
+"All Files (*.*)\t*.*\n"
+"C source (*.c, *.h)\t*.c;*.h\n"
+"C++ source (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"VB code (*.bas, *.frm)\t*.bas;*.frm\n"
+"Vim files (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
+msgstr ""
+"Âñ³ ôàéëè (*.*)\t*.*\n"
+"Ïåðøîêîä C (*.c, *.h)\t*.c;*.h\n"
+"Ïåðøîêîä C++ (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"Êîä VB (*.bas, *.frm)\t*.bas;*.frm\n"
+"Ôàéëè Vim (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
+
+msgid ""
+"Vim macro files (*.vim)\t*.vim\n"
+"All Files (*)\t*\n"
+msgstr ""
+"Ìàêðîñè Vim (*.vim)\t*.vim\n"
+"Âñ³ ôàéëè (*)\t*\n"
+
+msgid "All Files (*)\t*\n"
+msgstr "Âñ³ ôàéëè (*)\t*\n"
+
+msgid ""
+"All Files (*)\t*\n"
+"C source (*.c, *.h)\t*.c;*.h\n"
+"C++ source (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"Vim files (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
+msgstr ""
+"Âñ³ ôàéëè (*)\t*\n"
+"Ïåðøîêîä C (*.c, *.h)\t*.c;*.h\n"
+"Ïåðøîêîä C++ (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"Ôàéëè Vim (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
diff --git a/src/po/uk.po b/src/po/uk.po
new file mode 100644
index 0000000..ba291ef
--- /dev/null
+++ b/src/po/uk.po
@@ -0,0 +1,7333 @@
+#
+# Ukrainian translation for Vim
+#
+# Original translations
+#
+# Copyright (C) 2001 Bohdan Vlasyuk <bohdan@vstu.edu.ua>
+# Bohdan donated this work to be distributed with Vim under the Vim license.
+#
+# Thanks to:
+# Dmytro Kovalov <dmytro.kovalov@nssmb.com> for useful suggestions
+# Dmytro O. Redchuk <dor@kiev-online.net> for viminfo bug
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: vim 8.1\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2018-06-20 06:30+0300\n"
+"PO-Revision-Date: 2010-06-18 21:53+0300\n"
+"Last-Translator: Ðнатолій Сахнік <sakhnik@gmail.com>\n"
+"Language-Team: Ukrainian\n"
+"Language: uk\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+msgid "E831: bf_key_init() called with empty password"
+msgstr "E831: Викликано bf_key_init() з порожнім паролем"
+
+msgid "E820: sizeof(uint32_t) != 4"
+msgstr "E820: sizeof(uint32_t) != 4"
+
+msgid "E817: Blowfish big/little endian use wrong"
+msgstr "E817: Ðеправильне викориÑÑ‚Ð°Ð½Ð½Ñ Ð¿Ð¾Ñ€Ñдку байтів Blowfish (BE/LE)"
+
+msgid "E818: sha256 test failed"
+msgstr "E818: Ðе пройшла перевірка sha256"
+
+msgid "E819: Blowfish test failed"
+msgstr "E819: Ðе пройшла перевірка Blowfish"
+
+msgid "[Location List]"
+msgstr "[СпиÑок міÑць]"
+
+msgid "[Quickfix List]"
+msgstr "[СпиÑок виправлень]"
+
+msgid "E855: Autocommands caused command to abort"
+msgstr "E855: Ðвтокоманди призвели до ÑкаÑÑƒÐ²Ð°Ð½Ð½Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð¸"
+
+msgid "E82: Cannot allocate any buffer, exiting..."
+msgstr "E82: Ðемає можливоÑÑ‚Ñ– розміÑтити хоч один буфер, Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð½Ñ Ñ€Ð¾Ð±Ð¾Ñ‚Ð¸..."
+
+msgid "E83: Cannot allocate buffer, using other one..."
+msgstr "E83: Ðемає можливоÑÑ‚Ñ– розміÑтити буфер, буде викориÑтано інший..."
+
+msgid "E931: Buffer cannot be registered"
+msgstr "E931: Ðеможливо зареєÑтрувати буфер"
+
+msgid "E937: Attempt to delete a buffer that is in use"
+msgstr "E937: Спроба видалити буфер, що викориÑтовуєтьÑÑ"
+
+msgid "E515: No buffers were unloaded"
+msgstr "E515: Жоден з буферів не був вивантажений"
+
+msgid "E516: No buffers were deleted"
+msgstr "E516: Жоден з буферів не знищено"
+
+msgid "E517: No buffers were wiped out"
+msgstr "E517: Жоден з буферів не витерто"
+
+msgid "1 buffer unloaded"
+msgstr "Вивантажено один буфер"
+
+#, c-format
+msgid "%d buffers unloaded"
+msgstr "Вивантажено %d буфери(ів)"
+
+msgid "1 buffer deleted"
+msgstr "Знищено один буфер"
+
+#, c-format
+msgid "%d buffers deleted"
+msgstr "Знищено %d буфери(ів)"
+
+msgid "1 buffer wiped out"
+msgstr "Витерто один буфер"
+
+#, c-format
+msgid "%d buffers wiped out"
+msgstr "Витерто %d буфери(ів)"
+
+msgid "E90: Cannot unload last buffer"
+msgstr "E90: Ðе можу вивантажити оÑтанній буфер"
+
+msgid "E84: No modified buffer found"
+msgstr "E84: Жоден буфер не змінено"
+
+msgid "E85: There is no listed buffer"
+msgstr "E85: У ÑпиÑку немає буферів"
+
+msgid "E87: Cannot go beyond last buffer"
+msgstr "E87: Це вже оÑтанній буфер"
+
+msgid "E88: Cannot go before first buffer"
+msgstr "E88: Це вже найперший буфер"
+
+#, c-format
+msgid "E89: No write since last change for buffer %ld (add ! to override)"
+msgstr "E89: Буфер %ld має зміни (! щоб не зважати)"
+
+msgid "E948: Job still running (add ! to end the job)"
+msgstr "E948: Ð—Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð²Ñе ще виконуєтьÑÑ (додайте ! щоб закінчити)"
+
+msgid "E37: No write since last change (add ! to override)"
+msgstr "E37: Зміни не було запиÑано (! щоб не зважати)"
+
+msgid "E948: Job still running"
+msgstr "E948: Ð—Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð²Ð¶Ðµ ще виконуєтьÑÑ"
+
+msgid "E37: No write since last change"
+msgstr "E37: Ðе запиÑано попередні зміни"
+
+msgid "W14: Warning: List of file names overflow"
+msgstr "W14: Обережно: СпиÑок назв файлів переповнено"
+
+#, c-format
+msgid "E92: Buffer %ld not found"
+msgstr "E92: Буфер %ld не знайдено"
+
+#, c-format
+msgid "E93: More than one match for %s"
+msgstr "E93: Знайдено кілька збігів з %s"
+
+#, c-format
+msgid "E94: No matching buffer for %s"
+msgstr "E94: Ðе знайдено буфер, Ñхожий на %s"
+
+#, c-format
+msgid "line %ld"
+msgstr "Ñ€Ñдок %ld"
+
+msgid "E95: Buffer with this name already exists"
+msgstr "E95: Буфер з такою назвою вже Ñ–Ñнує"
+
+msgid " [Modified]"
+msgstr " [Змінено]"
+
+msgid "[Not edited]"
+msgstr "[Ðе редаговано]"
+
+msgid "[New file]"
+msgstr "[Ðовий файл]"
+
+msgid "[Read errors]"
+msgstr "[Помилки читаннÑ]"
+
+msgid "[RO]"
+msgstr "[RO]"
+
+msgid "[readonly]"
+msgstr "[лише читати]"
+
+#, c-format
+msgid "1 line --%d%%--"
+msgstr "один Ñ€Ñдок --%d%%--"
+
+#, c-format
+msgid "%ld lines --%d%%--"
+msgstr "%ld Ñ€Ñдки(ів) --%d%%--"
+
+#, c-format
+msgid "line %ld of %ld --%d%%-- col "
+msgstr "Ñ€Ñдок %ld з %ld --%d%%-- колонка "
+
+msgid "[No Name]"
+msgstr "[Без назви]"
+
+msgid "help"
+msgstr "допомога"
+
+msgid "[Help]"
+msgstr "[Допомога]"
+
+msgid "[Preview]"
+msgstr "[ПереглÑд]"
+
+msgid "All"
+msgstr "УÑе"
+
+msgid "Bot"
+msgstr "Знизу"
+
+msgid "Top"
+msgstr "Вгорі"
+
+msgid ""
+"\n"
+"# Buffer list:\n"
+msgstr ""
+"\n"
+"# СпиÑок буферів:\n"
+
+msgid "E382: Cannot write, 'buftype' option is set"
+msgstr "E382: Ðе можу запиÑати, вказана Ð¾Ð¿Ñ†Ñ–Ñ 'buftype'"
+
+msgid "[Prompt]"
+msgstr "[Підказка]"
+
+msgid "[Scratch]"
+msgstr "[З нулÑ]"
+
+msgid ""
+"\n"
+"--- Signs ---"
+msgstr ""
+"\n"
+"--- Позначки ---"
+
+#, c-format
+msgid "Signs for %s:"
+msgstr "Позначки Ð´Ð»Ñ %s:"
+
+#, c-format
+msgid " line=%ld id=%d name=%s"
+msgstr " Ñ€Ñдок=%ld id=%d назва=%s"
+
+msgid "E902: Cannot connect to port"
+msgstr "E902: Ðе вдалоÑÑ Ð·'єднатиÑÑ Ð· портом"
+
+msgid "E901: gethostbyname() in channel_open()"
+msgstr "E901: gethostbyname() у channel_open()"
+
+msgid "E898: socket() in channel_open()"
+msgstr "E898: socket() у channel_open()"
+
+msgid "E903: received command with non-string argument"
+msgstr "E903: отримано команду з нетекÑтовим аргументом"
+
+msgid "E904: last argument for expr/call must be a number"
+msgstr "E904: оÑтанній аргумент у виразі/виклику має бути чиÑлом"
+
+msgid "E904: third argument for call must be a list"
+msgstr "E904: третій аргумент у виклику має бути ÑпиÑком"
+
+#, c-format
+msgid "E905: received unknown command: %s"
+msgstr "E905: отримано невідому команду: %s"
+
+#, c-format
+msgid "E630: %s(): write while not connected"
+msgstr "E630: %s(): Ð·Ð°Ð¿Ð¸Ñ Ð´Ð¾ під’єднаннÑ"
+
+#, c-format
+msgid "E631: %s(): write failed"
+msgstr "E631: %s(): Ð·Ð±ÐµÑ€ÐµÐ¶ÐµÐ½Ð½Ñ Ð½Ðµ вдалоÑÑ"
+
+#, c-format
+msgid "E917: Cannot use a callback with %s()"
+msgstr "E917: Ðе можна викориÑтати зворотній виклик у %s()"
+
+msgid "E912: cannot use ch_evalexpr()/ch_sendexpr() with a raw or nl channel"
+msgstr ""
+"E912: не можна викориÑтати ch_evalexpr()/ch_sendexpr() з raw чи nl каналом"
+
+msgid "E906: not an open channel"
+msgstr "E906: не відкритий канал"
+
+msgid "E920: _io file requires _name to be set"
+msgstr "E920: файл _io потребує вÑтановленого _name"
+
+msgid "E915: in_io buffer requires in_buf or in_name to be set"
+msgstr "E915: буфер in_io потребує вÑтановленого in_buf чи in_name"
+
+#, c-format
+msgid "E918: buffer must be loaded: %s"
+msgstr "E918: буфер має бути завантажений: %s"
+
+msgid "E821: File is encrypted with unknown method"
+msgstr "E821: Файл зашифровано невідомим методом"
+
+msgid "Warning: Using a weak encryption method; see :help 'cm'"
+msgstr "Увага: ВикориÑтовуєтьÑÑ Ñлабкий метод шифруваннÑ; див. :help 'cm'"
+
+msgid "Enter encryption key: "
+msgstr "Вкажіть ключ шифру: "
+
+msgid "Enter same key again: "
+msgstr "Повторіть ключ: "
+
+msgid "Keys don't match!"
+msgstr "Ключі не однакові!"
+
+msgid "[crypted]"
+msgstr "[зашифровано]"
+
+# msgstr "E235: "
+#, c-format
+msgid "E720: Missing colon in Dictionary: %s"
+msgstr "E720: Бракує двокрапки у Ñловнику: %s"
+
+#, c-format
+msgid "E721: Duplicate key in Dictionary: \"%s\""
+msgstr "E721: ÐŸÐ¾Ð²Ñ‚Ð¾Ñ€ÐµÐ½Ð½Ñ ÐºÐ»ÑŽÑ‡Ð° в Ñловнику: «%s»"
+
+# msgstr "E235: "
+#, c-format
+msgid "E722: Missing comma in Dictionary: %s"
+msgstr "E722: Бракує коми у Ñловнику: %s"
+
+#, c-format
+msgid "E723: Missing end of Dictionary '}': %s"
+msgstr "E723: Ðемає кінцівки Ñловника '}': %s"
+
+# msgstr "E14: "
+msgid "extend() argument"
+msgstr "аргумент extend()"
+
+# msgstr "E226: "
+#, c-format
+msgid "E737: Key already exists: %s"
+msgstr "E737: Ключ вже Ñ–Ñнує: %s"
+
+#, c-format
+msgid "E96: Cannot diff more than %ld buffers"
+msgstr "E96: Ðе можна порівнювати понад %ld буфери(ів)"
+
+msgid "E810: Cannot read or write temp files"
+msgstr "E810: Ðе можна читати чи запиÑувати тимчаÑові файли"
+
+msgid "E97: Cannot create diffs"
+msgstr "E97: Ðе вдалоÑÑ Ñтворити порівнÑннÑ"
+
+msgid "Patch file"
+msgstr "Латка"
+
+msgid "E816: Cannot read patch output"
+msgstr "E816: Ðе вдалоÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ результат patch"
+
+msgid "E98: Cannot read diff output"
+msgstr "E98: Ðе вдалоÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ результат diff"
+
+msgid "E99: Current buffer is not in diff mode"
+msgstr "E99: Цей буфер не в режимі порівнÑннÑ"
+
+msgid "E793: No other buffer in diff mode is modifiable"
+msgstr "E793: Ðемає більше модифіковних буферів в режимі порівнÑннÑ"
+
+msgid "E100: No other buffer in diff mode"
+msgstr "E100: Ðемає інших буферів в режимі порівнÑннÑ"
+
+msgid "E101: More than two buffers in diff mode, don't know which one to use"
+msgstr ""
+"E101: Понад два буфери у режимі порівнÑннÑ, не зрозуміло, котрий із них "
+"викориÑтати"
+
+#, c-format
+msgid "E102: Can't find buffer \"%s\""
+msgstr "E102: Ðе вдалоÑÑ Ð·Ð½Ð°Ð¹Ñ‚Ð¸ буфер «%s»"
+
+#, c-format
+msgid "E103: Buffer \"%s\" is not in diff mode"
+msgstr "E103: Буфер «%s» не в режимі порівнÑннÑ"
+
+msgid "E787: Buffer changed unexpectedly"
+msgstr "E787: Буфер неÑподівано змінивÑÑ"
+
+msgid "E104: Escape not allowed in digraph"
+msgstr "E104: У диграфах не може міÑтитиÑÑ escape"
+
+msgid "E544: Keymap file not found"
+msgstr "E544: Ðе знайдено файл розкладки"
+
+msgid "E105: Using :loadkeymap not in a sourced file"
+msgstr "E105: :loadkeymap викориÑтано не у файлі команд"
+
+msgid "E791: Empty keymap entry"
+msgstr "E791: Елемент розкладки порожній"
+
+msgid " Keyword completion (^N^P)"
+msgstr " Ð”Ð¾Ð¿Ð¾Ð²Ð½ÐµÐ½Ð½Ñ ÐºÐ»ÑŽÑ‡Ð¾Ð²Ð¸Ñ… Ñлів (^N^P)"
+
+msgid " ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+msgstr " Режим ^X (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+
+msgid " Whole line completion (^L^N^P)"
+msgstr " Ð”Ð¾Ð¿Ð¾Ð²Ð½ÐµÐ½Ð½Ñ ÑƒÑього Ñ€Ñдка (^L^N^P)"
+
+msgid " File name completion (^F^N^P)"
+msgstr " Ð”Ð¾Ð¿Ð¾Ð²Ð½ÐµÐ½Ð½Ñ Ð½Ð°Ð·Ð²Ð¸ файлу (^F^N^P)"
+
+msgid " Tag completion (^]^N^P)"
+msgstr " Ð”Ð¾Ð¿Ð¾Ð²Ð½ÐµÐ½Ð½Ñ Ð¼Ñ–Ñ‚Ð¾Ðº (^]^N^P)"
+
+msgid " Path pattern completion (^N^P)"
+msgstr " Ð”Ð¾Ð¿Ð¾Ð²Ð½ÐµÐ½Ð½Ñ ÑˆÐ»Ñху за зразком (^N^P)"
+
+msgid " Definition completion (^D^N^P)"
+msgstr " Ð”Ð¾Ð¿Ð¾Ð²Ð½ÐµÐ½Ð½Ñ Ð²Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ (^D^N^P)"
+
+msgid " Dictionary completion (^K^N^P)"
+msgstr " Ð”Ð¾Ð¿Ð¾Ð²Ð½ÐµÐ½Ð½Ñ Ð·Ñ– Ñловника (^K^N^P)"
+
+msgid " Thesaurus completion (^T^N^P)"
+msgstr " Ð”Ð¾Ð¿Ð¾Ð²Ð½ÐµÐ½Ð½Ñ Ð· тезауруÑу (^T^N^P)"
+
+msgid " Command-line completion (^V^N^P)"
+msgstr " Ð”Ð¾Ð¿Ð¾Ð²Ð½ÐµÐ½Ð½Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´ (^V^N^P)"
+
+msgid " User defined completion (^U^N^P)"
+msgstr " КориÑтувацьке Ð´Ð¾Ð¿Ð¾Ð²Ð½ÐµÐ½Ð½Ñ (^U^N^P)"
+
+msgid " Omni completion (^O^N^P)"
+msgstr " Кмітливе Ð´Ð¾Ð¿Ð¾Ð²Ð½ÐµÐ½Ð½Ñ (^O^N^P)"
+
+msgid " Spelling suggestion (s^N^P)"
+msgstr " Орфографічна підказка (s^N^P)"
+
+msgid " Keyword Local completion (^N^P)"
+msgstr " Ð”Ð¾Ð¿Ð¾Ð²Ð½ÐµÐ½Ð½Ñ Ð¼Ñ–Ñцевих ключових Ñлів (^N^P)"
+
+msgid "Hit end of paragraph"
+msgstr "ТрапивÑÑ ÐºÑ–Ð½ÐµÑ†ÑŒ параграфа"
+
+# msgstr "E443: "
+msgid "E839: Completion function changed window"
+msgstr "E839: Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ Ð´Ð¾Ð¿Ð¾Ð²Ð½ÐµÐ½Ð½Ñ Ð·Ð¼Ñ–Ð½Ð¸Ð»Ð° вікно"
+
+msgid "E840: Completion function deleted text"
+msgstr "E840: Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ Ð´Ð¾Ð¿Ð¾Ð²Ð½ÐµÐ½Ð½Ñ Ð·Ð½Ð¸Ñ‰Ð¸Ð»Ð° текÑÑ‚"
+
+msgid "'dictionary' option is empty"
+msgstr "ÐžÐ¿Ñ†Ñ–Ñ 'dictionary' порожнÑ"
+
+msgid "'thesaurus' option is empty"
+msgstr "ÐžÐ¿Ñ†Ñ–Ñ 'thesaurus' порожнÑ"
+
+#, c-format
+msgid "Scanning dictionary: %s"
+msgstr "СкануєтьÑÑ Ñловник: %s"
+
+msgid " (insert) Scroll (^E/^Y)"
+msgstr " (вÑтавка) Прогорнути (^E/^Y)"
+
+msgid " (replace) Scroll (^E/^Y)"
+msgstr " (заміна) Прогорнути (^E/^Y)"
+
+#, c-format
+msgid "Scanning: %s"
+msgstr "Пошук у: %s"
+
+msgid "Scanning tags."
+msgstr "Пошук Ñеред міток."
+
+msgid "match in file"
+msgstr "збіг у файлі"
+
+msgid " Adding"
+msgstr " ДодаєтьÑÑ"
+
+msgid "-- Searching..."
+msgstr "-- Пошук..."
+
+msgid "Back at original"
+msgstr "Початковий варіант"
+
+msgid "Word from other line"
+msgstr "Слово з іншого Ñ€Ñдка"
+
+msgid "The only match"
+msgstr "Єдиний збіг"
+
+#, c-format
+msgid "match %d of %d"
+msgstr "збіг %d з %d"
+
+#, c-format
+msgid "match %d"
+msgstr "збіг %d"
+
+# msgstr "E17: "
+msgid "E18: Unexpected characters in :let"
+msgstr "E18: Ðеочікувані Ñимволи у :let"
+
+#, c-format
+msgid "E121: Undefined variable: %s"
+msgstr "E121: Ðевизначена змінна: %s"
+
+msgid "E111: Missing ']'"
+msgstr "E111: Бракує ']'"
+
+msgid "E719: Cannot use [:] with a Dictionary"
+msgstr "E719: Ðе можна викориÑтати [:] зі Ñловником"
+
+#, c-format
+msgid "E734: Wrong variable type for %s="
+msgstr "E734: Ðеправильний тип змінної Ð´Ð»Ñ %s="
+
+#, c-format
+msgid "E461: Illegal variable name: %s"
+msgstr "E461: ÐеприпуÑтима назва змінної: %s"
+
+# msgstr "E373: "
+msgid "E806: using Float as a String"
+msgstr "E806: Float вжито Ñк String"
+
+msgid "E687: Less targets than List items"
+msgstr "E687: Цілей менше, ніж елементів ÑпиÑку"
+
+msgid "E688: More targets than List items"
+msgstr "E688: Цілей більше, ніж елементів ÑпиÑку"
+
+msgid "Double ; in list of variables"
+msgstr "Друга ; у ÑпиÑку змінних"
+
+# msgstr "E235: "
+#, c-format
+msgid "E738: Can't list variables for %s"
+msgstr "E738: Ðе можна перерахувати змінні у %s"
+
+msgid "E689: Can only index a List or Dictionary"
+msgstr "E689: ІндекÑний доÑтуп може бути тільки до ÑпиÑку чи Ñловника"
+
+msgid "E708: [:] must come last"
+msgstr "E708: [:] має бути оÑтанньою"
+
+msgid "E709: [:] requires a List value"
+msgstr "E709: [:] вимагає ÑпиÑок"
+
+msgid "E710: List value has more items than target"
+msgstr "E710: СпиÑок має більше елементів, ніж ціль"
+
+msgid "E711: List value has not enough items"
+msgstr "E711: СпиÑок має недоÑтатньо елементів"
+
+msgid "E690: Missing \"in\" after :for"
+msgstr "E690: Пропущено «in» піÑÐ»Ñ :for"
+
+#, c-format
+msgid "E108: No such variable: \"%s\""
+msgstr "E108: Змінної немає: «%s»"
+
+#, c-format
+msgid "E940: Cannot lock or unlock variable %s"
+msgstr "E940: Ðеможливо заблокувати чи розблокувати змінну %s"
+
+msgid "E743: variable nested too deep for (un)lock"
+msgstr "E743: Змінна має забагато вкладень щоб бути за-/відкритою."
+
+msgid "E109: Missing ':' after '?'"
+msgstr "E109: Бракує ':' піÑÐ»Ñ '?'"
+
+msgid "E804: Cannot use '%' with Float"
+msgstr "E804: Ðе можна виконати '%' над Float"
+
+msgid "E110: Missing ')'"
+msgstr "E110: Пропущено ')'"
+
+msgid "E695: Cannot index a Funcref"
+msgstr "E695: Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ Ð½Ðµ має індекÑації"
+
+msgid "E909: Cannot index a special variable"
+msgstr "E909: Ðе можна індекÑувати Ñпеціальну змінну"
+
+#, c-format
+msgid "E112: Option name missing: %s"
+msgstr "E112: Бракує назви опції: %s"
+
+#, c-format
+msgid "E113: Unknown option: %s"
+msgstr "E113: Ðевідома опціÑ: %s"
+
+#, c-format
+msgid "E114: Missing quote: %s"
+msgstr "E114: Бракує лапки: %s"
+
+#, c-format
+msgid "E115: Missing quote: %s"
+msgstr "E115: Бракує лапки: %s"
+
+msgid "Not enough memory to set references, garbage collection aborted!"
+msgstr "ÐедоÑтатньо пам’ÑÑ‚Ñ–, щоб вÑтановити поÑиланнÑ, збір ÑÐ¼Ñ–Ñ‚Ñ‚Ñ ÑкаÑовано!"
+
+# msgstr "E21: "
+msgid "E724: variable nested too deep for displaying"
+msgstr "E724: У змінній забагато вкладень щоб її показати"
+
+msgid "E805: Using a Float as a Number"
+msgstr "E805: Float вжито Ñк Number"
+
+msgid "E703: Using a Funcref as a Number"
+msgstr "E703: Funcref вжито Ñк Number"
+
+msgid "E745: Using a List as a Number"
+msgstr "E745: List вжито Ñк Number"
+
+msgid "E728: Using a Dictionary as a Number"
+msgstr "E728: Dictionary вжито Ñк Number"
+
+msgid "E910: Using a Job as a Number"
+msgstr "E910: Job вжито Ñк Number"
+
+msgid "E913: Using a Channel as a Number"
+msgstr "E913: Channel вжито Ñк Number"
+
+msgid "E891: Using a Funcref as a Float"
+msgstr "E891: Funcref вжито Ñк Float"
+
+msgid "E892: Using a String as a Float"
+msgstr "E892: String вжито Ñк Float"
+
+msgid "E893: Using a List as a Float"
+msgstr "E893: List вжито Ñк Float"
+
+msgid "E894: Using a Dictionary as a Float"
+msgstr "E894: Dictionary вжито Ñк Float"
+
+msgid "E907: Using a special value as a Float"
+msgstr "E907: Спеціальне Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð²Ð¶Ð¸Ñ‚Ð¾ Ñк Float"
+
+msgid "E911: Using a Job as a Float"
+msgstr "E911: Job вжито Ñк Float"
+
+msgid "E914: Using a Channel as a Float"
+msgstr "E914: Channel вжито Ñк Float"
+
+msgid "E729: using Funcref as a String"
+msgstr "E729: Funcref вжито Ñк String"
+
+# msgstr "E373: "
+msgid "E730: using List as a String"
+msgstr "E730: List вжито Ñк String"
+
+msgid "E731: using Dictionary as a String"
+msgstr "E731: Dictionary вжито Ñк String"
+
+# msgstr "E373: "
+msgid "E908: using an invalid value as a String"
+msgstr "E908: неправильне Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð²Ð¶Ð¸Ñ‚Ð¾ Ñк String"
+
+#, c-format
+msgid "E795: Cannot delete variable %s"
+msgstr "E795: Ðе можна знищити змінну %s"
+
+#, c-format
+msgid "E704: Funcref variable name must start with a capital: %s"
+msgstr "E704: Ðазва змінної Funcref має починатиÑÑ Ð· великої літери: %s"
+
+#, c-format
+msgid "E705: Variable name conflicts with existing function: %s"
+msgstr "E705: Ðазва змінної Ñпівпадає з Ñ–Ñнуючою функцією: %s"
+
+#, c-format
+msgid "E741: Value is locked: %s"
+msgstr "E741: Ð—Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð·Ð°Ñ…Ð¸Ñ‰ÐµÐ½Ðµ: %s"
+
+msgid "Unknown"
+msgstr "Ðевідомо"
+
+#, c-format
+msgid "E742: Cannot change value of %s"
+msgstr "E742: Ðе можна змінити Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ %s"
+
+msgid "E698: variable nested too deep for making a copy"
+msgstr "E698: Змінна вкладена занадто глибоко щоб зробити її копію"
+
+msgid ""
+"\n"
+"# global variables:\n"
+msgstr ""
+"\n"
+"# глобальні змінні:\n"
+
+msgid ""
+"\n"
+"\tLast set from "
+msgstr ""
+"\n"
+"\tВоÑтаннє змінена у "
+
+msgid "E691: Can only compare List with List"
+msgstr "E691: СпиÑок можна порівнÑти тільки зі ÑпиÑком"
+
+msgid "E692: Invalid operation for List"
+msgstr "E692: Ðекоректна Ð¾Ð¿ÐµÑ€Ð°Ñ†Ñ–Ñ Ð½Ð°Ð´ ÑпиÑком"
+
+msgid "E735: Can only compare Dictionary with Dictionary"
+msgstr "E735: Словник можна порівнÑти тільки із Ñловником"
+
+msgid "E736: Invalid operation for Dictionary"
+msgstr "E736: Ðекоректна Ð¾Ð¿ÐµÑ€Ð°Ñ†Ñ–Ñ Ð½Ð°Ð´ Ñловником"
+
+msgid "E694: Invalid operation for Funcrefs"
+msgstr "E694: Ðекоректна Ð¾Ð¿ÐµÑ€Ð°Ñ†Ñ–Ñ Ð½Ð°Ð´ функцією"
+
+# msgstr "E14: "
+msgid "map() argument"
+msgstr "аргумент map()"
+
+# msgstr "E14: "
+msgid "filter() argument"
+msgstr "аргумент filter()"
+
+#, c-format
+msgid "E686: Argument of %s must be a List"
+msgstr "E686: Ðргумент у %s має бути ÑпиÑком"
+
+# msgstr "E396: "
+msgid "E928: String required"
+msgstr "E928: Потрібно String"
+
+msgid "E808: Number or Float required"
+msgstr "E808: Треба вказати Number чи Float"
+
+# msgstr "E14: "
+msgid "add() argument"
+msgstr "аргумент add()"
+
+# msgstr "E327: "
+msgid "E785: complete() can only be used in Insert mode"
+msgstr "E785: complete() можна вживати тільки в режимі вÑтавки"
+
+msgid "&Ok"
+msgstr "&O:Гаразд"
+
+#, c-format
+msgid "+-%s%3ld line: "
+msgid_plural "+-%s%3ld lines: "
+msgstr[0] "+-%s%3ld Ñ€Ñдок: "
+msgstr[1] "+-%s%3ld Ñ€Ñдків: "
+
+#, c-format
+msgid "E700: Unknown function: %s"
+msgstr "E700: Ðевідома функціÑ: %s"
+
+msgid "E922: expected a dict"
+msgstr "E922: очікуєтьÑÑ dict"
+
+msgid "E923: Second argument of function() must be a list or a dict"
+msgstr "E923: Другий аргумент function() має бути ÑпиÑком чи Ñловником"
+
+msgid ""
+"&OK\n"
+"&Cancel"
+msgstr ""
+"&O:Гаразд\n"
+"&C:СкаÑувати"
+
+msgid "called inputrestore() more often than inputsave()"
+msgstr "Виклики до inputrestore() чаÑтіше, ніж до inputsave()"
+
+# msgstr "E14: "
+msgid "insert() argument"
+msgstr "аргумент insert()"
+
+# msgstr "E406: "
+msgid "E786: Range not allowed"
+msgstr "E786: Інтервал не дозволено"
+
+msgid "E916: not a valid job"
+msgstr "E916: некоректне завданнÑ"
+
+# msgstr "E177: "
+msgid "E701: Invalid type for len()"
+msgstr "E701: Ðекоректний тип Ð´Ð»Ñ len()"
+
+#, c-format
+msgid "E798: ID is reserved for \":match\": %ld"
+msgstr "E798: ID зарезервовано Ð´Ð»Ñ Â«:match»: %ld"
+
+msgid "E726: Stride is zero"
+msgstr "E726: Крок нульовий"
+
+msgid "E727: Start past end"
+msgstr "E727: Початок за кінцем"
+
+msgid "<empty>"
+msgstr "<нічого>"
+
+msgid "E240: No connection to the X server"
+msgstr "E240: Ðемає з'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ñ–Ð· Ñервером X"
+
+#, c-format
+msgid "E241: Unable to send to %s"
+msgstr "E241: Ðе вдалоÑÑ Ð²Ñ–Ð´Ñ–Ñлати до %s"
+
+msgid "E277: Unable to read a server reply"
+msgstr "E277: Ðе вдалоÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ відповідь Ñервера"
+
+msgid "E941: already started a server"
+msgstr "E941: Ñервер вже запущено"
+
+msgid "E942: +clientserver feature not available"
+msgstr "E942: можливіÑÑ‚ÑŒ +clientserver відÑутнÑ"
+
+# msgstr "E14: "
+msgid "remove() argument"
+msgstr "аргумент remove()"
+
+msgid "E655: Too many symbolic links (cycle?)"
+msgstr "E655: Забагато Ñимвольних поÑилань (цикл?)"
+
+# msgstr "E14: "
+msgid "reverse() argument"
+msgstr "аргумент reverse()"
+
+msgid "E258: Unable to send to client"
+msgstr "E258: Ðе вдалоÑÑ Ð½Ð°Ð´Ñ–Ñлати клієнту"
+
+#, c-format
+msgid "E927: Invalid action: '%s'"
+msgstr "E927: Ðеправильна діÑ: '%s'"
+
+# msgstr "E14: "
+msgid "sort() argument"
+msgstr "аргумент sort()"
+
+# msgstr "E14: "
+msgid "uniq() argument"
+msgstr "аргумент unique()"
+
+# msgstr "E364: "
+msgid "E702: Sort compare function failed"
+msgstr "E702: Помилка у функції порівнÑÐ½Ð½Ñ sort"
+
+# msgstr "E364: "
+msgid "E882: Uniq compare function failed"
+msgstr "E882: Помилка у функції порівнÑÐ½Ð½Ñ uniq"
+
+msgid "(Invalid)"
+msgstr "(Ðеможливо)"
+
+#, c-format
+msgid "E935: invalid submatch number: %d"
+msgstr "E935: неправильний номер під-збігу: %d"
+
+msgid "E677: Error writing temp file"
+msgstr "E677: Ðе вдалоÑÑ Ð·Ð°Ð¿Ð¸Ñати тимчаÑовий файл"
+
+# msgstr "E14: "
+msgid "E921: Invalid callback argument"
+msgstr "E921: Ðекоректний аргумент зворотного виклику"
+
+msgid "Entering Debug mode. Type \"cont\" to continue."
+msgstr "Режим налагодженнÑ. Щоб продовжити введіть «cont»."
+
+#, c-format
+msgid "Oldval = \"%s\""
+msgstr "Oldval = «%s»"
+
+#, c-format
+msgid "Newval = \"%s\""
+msgstr "Newval = «%s»"
+
+#, c-format
+msgid "line %ld: %s"
+msgstr "Ñ€Ñдок %ld: %s"
+
+#, c-format
+msgid "cmd: %s"
+msgstr "команда: %s"
+
+msgid "frame is zero"
+msgstr "кадр Ñтеку нульовий"
+
+#, c-format
+msgid "frame at highest level: %d"
+msgstr "кадр Ñтеку на найвищому рівні: %d"
+
+#, c-format
+msgid "Breakpoint in \"%s%s\" line %ld"
+msgstr "Точка зупинки в «%s%s» Ñ€Ñдок %ld"
+
+#, c-format
+msgid "E161: Breakpoint not found: %s"
+msgstr "E161: Точку зупинки не знайдено: %s"
+
+msgid "No breakpoints defined"
+msgstr "Ðе визначено жодної точки зупинки"
+
+#, c-format
+msgid "%3d %s %s line %ld"
+msgstr "%3d %s %s Ñ€Ñдок %ld"
+
+#, c-format
+msgid "%3d expr %s"
+msgstr "%3d вираз %s"
+
+msgid "E750: First use \":profile start {fname}\""
+msgstr "E750: Спочатку зробіть «:profile start {файл}»"
+
+msgid "Save As"
+msgstr "Зберегти Ñк"
+
+#, c-format
+msgid "Save changes to \"%s\"?"
+msgstr "Зберегти зміни в «%s»?"
+
+#, c-format
+msgid "E947: Job still running in buffer \"%s\""
+msgstr "E947: Ð—Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð²Ð¶Ðµ ще виконуєтьÑÑ Ñƒ буфері «%s»"
+
+#, c-format
+msgid "E162: No write since last change for buffer \"%s\""
+msgstr "E162: Буфер «%s» має не збережені зміни"
+
+msgid "Warning: Entered other buffer unexpectedly (check autocommands)"
+msgstr ""
+"Обережно: ÐеÑподівано опинилиÑÑ Ñƒ іншому буфері (перевірте автокоманди)"
+
+msgid "E163: There is only one file to edit"
+msgstr "E163: РедагуєтьÑÑ Ð»Ð¸ÑˆÐµ один файл"
+
+msgid "E164: Cannot go before first file"
+msgstr "E164: Це вже найперший файл"
+
+msgid "E165: Cannot go beyond last file"
+msgstr "E165: Це вже оÑтанній файл"
+
+#, c-format
+msgid "E666: compiler not supported: %s"
+msgstr "E666: КомпілÑтор не підтримуєтьÑÑ: %s"
+
+# msgstr "E195: "
+#, c-format
+msgid "Searching for \"%s\" in \"%s\""
+msgstr "Пошук «%s» в «%s»"
+
+#, c-format
+msgid "Searching for \"%s\""
+msgstr "Пошук «%s»"
+
+#, c-format
+msgid "not found in '%s': \"%s\""
+msgstr "не знайдено у '%s': «%s»"
+
+#, c-format
+msgid "W20: Required python version 2.x not supported, ignoring file: %s"
+msgstr "W20: Потрібна верÑÑ–Ñ python 2.x не підтримуєтьÑÑ, ігноруєтьÑÑ Ñ„Ð°Ð¹Ð»: %s"
+
+#, c-format
+msgid "W21: Required python version 3.x not supported, ignoring file: %s"
+msgstr "W21: Потрібна верÑÑ–Ñ python 3.x не підтримуєтьÑÑ, ігноруєтьÑÑ Ñ„Ð°Ð¹Ð»: %s"
+
+msgid "Source Vim script"
+msgstr "Прочитати Ñкрипт Vim"
+
+#, c-format
+msgid "Cannot source a directory: \"%s\""
+msgstr "Ðе вдалоÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ каталог: «%s»"
+
+#, c-format
+msgid "could not source \"%s\""
+msgstr "Ðе вдалоÑÑ Ð²Ð¸ÐºÐ¾Ð½Ð°Ñ‚Ð¸ «%s»"
+
+#, c-format
+msgid "line %ld: could not source \"%s\""
+msgstr "Ñ€Ñдок %ld: не вдалоÑÑ Ð²Ð¸ÐºÐ¾Ð½Ð°Ñ‚Ð¸ «%s»"
+
+#, c-format
+msgid "sourcing \"%s\""
+msgstr "виконуєтьÑÑ Â«%s»"
+
+#, c-format
+msgid "line %ld: sourcing \"%s\""
+msgstr "Ñ€Ñдок %ld: виконуєтьÑÑ Â«%s»"
+
+#, c-format
+msgid "finished sourcing %s"
+msgstr "закінчено Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ %s"
+
+#, c-format
+msgid "continuing in %s"
+msgstr "Ð¿Ñ€Ð¾Ð´Ð¾Ð²Ð¶ÐµÐ½Ð½Ñ Ð² %s"
+
+msgid "modeline"
+msgstr "modeline"
+
+# msgstr "E14: "
+msgid "--cmd argument"
+msgstr "--cmd аргумент"
+
+# msgstr "E14: "
+msgid "-c argument"
+msgstr "-c аргумент"
+
+msgid "environment variable"
+msgstr "змінна оточеннÑ"
+
+msgid "error handler"
+msgstr "обробник помилки"
+
+msgid "W15: Warning: Wrong line separator, ^M may be missing"
+msgstr "W15: ЗаÑтереженнÑ: Ðеправильний роздільник Ñ€Ñдків, можливо, бракує ^M"
+
+msgid "E167: :scriptencoding used outside of a sourced file"
+msgstr "E167: :scriptencoding викориÑтано поза виконуваним файлом"
+
+msgid "E168: :finish used outside of a sourced file"
+msgstr "E168: :finish викориÑтано поза виконуваним файлом"
+
+#, c-format
+msgid "Current %slanguage: \"%s\""
+msgstr "Мова (%s): «%s»"
+
+#, c-format
+msgid "E197: Cannot set language to \"%s\""
+msgstr "E197: Ðе вдалоÑÑ Ð²Ñтановити мову «%s»"
+
+#, c-format
+msgid "<%s>%s%s %d, Hex %02x, Oct %03o, Digr %s"
+msgstr "<%s>%s%s %d, шіÑÑ‚ %02x, Ð²Ñ–Ñ %03o, дигр %s"
+
+#, c-format
+msgid "<%s>%s%s %d, Hex %02x, Octal %03o"
+msgstr "<%s>%s%s %d, шіÑÑ‚ %02x, Ð²Ñ–Ñ %03o"
+
+#, c-format
+msgid "> %d, Hex %04x, Oct %o, Digr %s"
+msgstr "> %d, шіÑÑ‚ %04x, Ð²Ñ–Ñ %o, дигр %s"
+
+#, c-format
+msgid "> %d, Hex %08x, Oct %o, Digr %s"
+msgstr "> %d, шіÑÑ‚ %08x, Ð²Ñ–Ñ %o, дигр %s"
+
+#, c-format
+msgid "> %d, Hex %04x, Octal %o"
+msgstr "> %d, шіÑÑ‚ %04x, Ð²Ñ–Ñ %o"
+
+#, c-format
+msgid "> %d, Hex %08x, Octal %o"
+msgstr "> %d, шіÑÑ‚ %08x, Ð²Ñ–Ñ %o"
+
+msgid "E134: Move lines into themselves"
+msgstr "E134: Ðеможливо переміÑтити Ñ€Ñдки Ñамі в Ñебе"
+
+msgid "1 line moved"
+msgstr "Переміщено один Ñ€Ñдок"
+
+#, c-format
+msgid "%ld lines moved"
+msgstr "Переміщено %ld Ñ€Ñдки(ів)"
+
+#, c-format
+msgid "%ld lines filtered"
+msgstr "Відфільтровано %ld Ñ€Ñдки(ів)"
+
+msgid "E135: *Filter* Autocommands must not change current buffer"
+msgstr "E135: Ðвтокоманди *Filter* не повинні змінювати поточний буфер"
+
+msgid "[No write since last change]\n"
+msgstr "[Зміни не запиÑано]\n"
+
+#, c-format
+msgid "%sviminfo: %s in line: "
+msgstr "%sviminfo: %s в Ñ€Ñдку: "
+
+msgid "E136: viminfo: Too many errors, skipping rest of file"
+msgstr "E136: viminfo: Забагато помилок, решта файлу буде пропущено"
+
+#, c-format
+msgid "Reading viminfo file \"%s\"%s%s%s"
+msgstr "ЗчитуєтьÑÑ Ñ„Ð°Ð¹Ð» viminfo: «%s»%s%s%s"
+
+msgid " info"
+msgstr " інформаціÑ"
+
+msgid " marks"
+msgstr " позначки"
+
+msgid " oldfiles"
+msgstr " Ñтарі файли"
+
+msgid " FAILED"
+msgstr " ÐЕ ВДÐЛОСЯ"
+
+#, c-format
+msgid "E137: Viminfo file is not writable: %s"
+msgstr "E137: Ðе дозволено Ð·Ð°Ð¿Ð¸Ñ Ñƒ файл viminfo: %s"
+
+#, c-format
+msgid "E929: Too many viminfo temp files, like %s!"
+msgstr "E929: Забагато тимчаÑових файлів viminfo, Ñк %s!"
+
+#, c-format
+msgid "E138: Can't write viminfo file %s!"
+msgstr "E138: Ðе вдалоÑÑ Ð·Ð°Ð¿Ð¸Ñати файл viminfo %s!"
+
+#, c-format
+msgid "Writing viminfo file \"%s\""
+msgstr "ЗапиÑуєтьÑÑ Ñ„Ð°Ð¹Ð» viminfo «%s»"
+
+#, c-format
+msgid "E886: Can't rename viminfo file to %s!"
+msgstr "E886: Ðе вдалоÑÑ Ð¿ÐµÑ€ÐµÐ¹Ð¼ÐµÐ½ÑƒÐ²Ð°Ñ‚Ð¸ файл viminfo у %s!"
+
+#, c-format
+msgid "# This viminfo file was generated by Vim %s.\n"
+msgstr "# Цей файл автоматично Ñтворений Vim %s.\n"
+
+msgid ""
+"# You may edit it if you're careful!\n"
+"\n"
+msgstr ""
+"# Можете редагувати, але ОБЕРЕЖÐО!\n"
+"\n"
+
+msgid "# Value of 'encoding' when this file was written\n"
+msgstr "# Ð—Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ 'encoding' під Ñ‡Ð°Ñ ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ñ†ÑŒÐ¾Ð³Ð¾ файлу\n"
+
+msgid "Illegal starting char"
+msgstr "Ðедозволений Ñимвол на початку Ñ€Ñдка"
+
+msgid ""
+"\n"
+"# Bar lines, copied verbatim:\n"
+msgstr ""
+"\n"
+"# РÑдки bar, Ñкопійовано поÑимвольно:\n"
+
+msgid "Write partial file?"
+msgstr "ЗапиÑати чаÑтину файлу?"
+
+msgid "E140: Use ! to write partial buffer"
+msgstr "E140: ВикориÑтайте ! Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñу чаÑтини буфера"
+
+#, c-format
+msgid "Overwrite existing file \"%s\"?"
+msgstr "ПерепиÑати Ñ–Ñнуючий файл «%s»?"
+
+#, c-format
+msgid "Swap file \"%s\" exists, overwrite anyway?"
+msgstr "Файл обміну «%s» Ñ–Ñнує, перезапиÑати?"
+
+#, c-format
+msgid "E768: Swap file exists: %s (:silent! overrides)"
+msgstr "E768: Файл обміну Ñ–Ñнує: %s (:silent! переважує)"
+
+#, c-format
+msgid "E141: No file name for buffer %ld"
+msgstr "E141: Ðемає вхідного файлу Ð´Ð»Ñ Ð±ÑƒÑ„ÐµÑ€Ð° %ld"
+
+msgid "E142: File not written: Writing is disabled by 'write' option"
+msgstr "E142: Файл не запиÑано: Ð·Ð°Ð¿Ð¸Ñ Ð·Ð°Ð±Ð¾Ñ€Ð¾Ð½ÐµÐ½Ð¾ опцією 'write'"
+
+#, c-format
+msgid ""
+"'readonly' option is set for \"%s\".\n"
+"Do you wish to write anyway?"
+msgstr ""
+"Ð”Ð»Ñ Â«%s» вÑтановлено 'readonly'.\n"
+"Бажаєте вÑе одно продовжити запиÑ?"
+
+#, c-format
+msgid ""
+"File permissions of \"%s\" are read-only.\n"
+"It may still be possible to write it.\n"
+"Do you wish to try?"
+msgstr ""
+"Файл «%s» дозволено тільки читати.\n"
+"Проте, можливо, його можна запиÑати.\n"
+"Хочете Ñпробувати?"
+
+#, c-format
+msgid "E505: \"%s\" is read-only (add ! to override)"
+msgstr "E505: «%s» тільки Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ (! щоб не зважати)"
+
+msgid "Edit File"
+msgstr "Редагувати Файл"
+
+#, c-format
+msgid "E143: Autocommands unexpectedly deleted new buffer %s"
+msgstr "E143: Ðвтокоманди неÑподівано знищили новий буфер %s"
+
+msgid "E144: non-numeric argument to :z"
+msgstr "E144: не чиÑловий аргумент Ð´Ð»Ñ :z"
+
+msgid "E145: Shell commands not allowed in rvim"
+msgstr "E145: У rvim не дозволені команди оболонки"
+
+msgid "E146: Regular expressions can't be delimited by letters"
+msgstr "E146: РегулÑрні вирази не можна розділÑти літерами"
+
+#, c-format
+msgid "replace with %s (y/n/a/q/l/^E/^Y)?"
+msgstr "Замінити на %s (y/n/a/q/l/^E/^Y)?"
+
+msgid "(Interrupted) "
+msgstr "(Перервано) "
+
+# msgstr "E31: "
+msgid "1 match"
+msgstr "Один збіг"
+
+msgid "1 substitution"
+msgstr "Одна заміна"
+
+#, c-format
+msgid "%ld matches"
+msgstr "%ld збіги(ів)"
+
+#, c-format
+msgid "%ld substitutions"
+msgstr "%ld замін(и)"
+
+msgid " on 1 line"
+msgstr " в одному Ñ€Ñдку"
+
+#, c-format
+msgid " on %ld lines"
+msgstr " в %ld Ñ€Ñдках"
+
+msgid "E147: Cannot do :global recursive with a range"
+msgstr "E147: :global не можна вживати рекурÑивно з діапазоном"
+
+msgid "E148: Regular expression missing from global"
+msgstr "E148: У global бракує зразка"
+
+#, c-format
+msgid "Pattern found in every line: %s"
+msgstr "Зразок знайдено у кожному Ñ€Ñдку: %s"
+
+#, c-format
+msgid "Pattern not found: %s"
+msgstr "Зразок не знайдено: %s"
+
+msgid ""
+"\n"
+"# Last Substitute String:\n"
+"$"
+msgstr ""
+"\n"
+"# ОÑÑ‚Ð°Ð½Ð½Ñ Ð·Ð°Ð¼Ñ–Ð½Ð°:\n"
+"$"
+
+msgid "E478: Don't panic!"
+msgstr "E478: Без паніки!"
+
+#, c-format
+msgid "E661: Sorry, no '%s' help for %s"
+msgstr "E661: Вибачте, немає допомоги '%s' Ð´Ð»Ñ %s"
+
+#, c-format
+msgid "E149: Sorry, no help for %s"
+msgstr "E149: Вибачте, немає допомоги Ð´Ð»Ñ %s"
+
+#, c-format
+msgid "Sorry, help file \"%s\" not found"
+msgstr "Вибачте, файл допомоги «%s» не знайдено"
+
+#, c-format
+msgid "E151: No match: %s"
+msgstr "E151: Жодного збігу: %s"
+
+#, c-format
+msgid "E152: Cannot open %s for writing"
+msgstr "E152: Ðе вдалоÑÑ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸ %s Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñу"
+
+#, c-format
+msgid "E153: Unable to open %s for reading"
+msgstr "E153: Ðе вдалоÑÑ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸ %s Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ"
+
+#, c-format
+msgid "E670: Mix of help file encodings within a language: %s"
+msgstr "E670: Мішанина кодувань файлу допомоги Ð´Ð»Ñ Ð¼Ð¾Ð²Ð¸ %s"
+
+#, c-format
+msgid "E154: Duplicate tag \"%s\" in file %s/%s"
+msgstr "E154: ÐŸÐ¾Ð²Ñ‚Ð¾Ñ€ÐµÐ½Ð½Ñ Ð¼Ñ–Ñ‚ÐºÐ¸ «%s» у файлі %s/%s"
+
+#, c-format
+msgid "E150: Not a directory: %s"
+msgstr "E150: Ðе Ñ” каталогом: %s"
+
+#, c-format
+msgid "E160: Unknown sign command: %s"
+msgstr "E160: Ðевідома команда надпиÑу: %s"
+
+msgid "E156: Missing sign name"
+msgstr "E156: Пропущено назву надпиÑу"
+
+msgid "E612: Too many signs defined"
+msgstr "E612: Визначено забагато надпиÑів"
+
+#, c-format
+msgid "E239: Invalid sign text: %s"
+msgstr "E239: Ðекоректний надпиÑ: %s"
+
+#, c-format
+msgid "E155: Unknown sign: %s"
+msgstr "E155: Ðевідомий надпиÑ: %s"
+
+msgid "E159: Missing sign number"
+msgstr "E159: Пропущено номер надпиÑу"
+
+#, c-format
+msgid "E158: Invalid buffer name: %s"
+msgstr "E158: Ðекоректна назва буфера: %s"
+
+msgid "E934: Cannot jump to a buffer that does not have a name"
+msgstr "E934: Ðе можна перейти до буфера, Ñкий не має назви"
+
+#, c-format
+msgid "E157: Invalid sign ID: %ld"
+msgstr "E157: Ðеправильний ID надпиÑу: %ld"
+
+#, c-format
+msgid "E885: Not possible to change sign %s"
+msgstr "E885: Ðеможливо змінити знак %s"
+
+msgid " (NOT FOUND)"
+msgstr " (ÐЕ ЗÐÐЙДЕÐО)"
+
+msgid " (not supported)"
+msgstr " (не підтримуєтьÑÑ)"
+
+msgid "[Deleted]"
+msgstr "[Знищено]"
+
+msgid "No old files"
+msgstr "Жодного Ñтарого файлу"
+
+msgid "Entering Ex mode. Type \"visual\" to go to Normal mode."
+msgstr "Режим Ex. Ð”Ð»Ñ Ð¿Ð¾Ð²ÐµÑ€Ð½ÐµÐ½Ð½Ñ Ð´Ð¾ нормального режиму виконайте «visual»"
+
+msgid "E501: At end-of-file"
+msgstr "E501: Кінець файлу"
+
+msgid "E169: Command too recursive"
+msgstr "E169: Команда занадто рекурÑивна"
+
+#, c-format
+msgid "E605: Exception not caught: %s"
+msgstr "E605: ВинÑткова ÑÐ¸Ñ‚ÑƒÐ°Ñ†Ñ–Ñ Ð½Ðµ оброблена: %s"
+
+msgid "End of sourced file"
+msgstr "Кінець виконуваного файлу"
+
+msgid "End of function"
+msgstr "Кінець функції"
+
+msgid "E464: Ambiguous use of user-defined command"
+msgstr "E464: Ðеоднозначний вжиток команди кориÑтувача"
+
+msgid "E492: Not an editor command"
+msgstr "E492: Це не команда редактора"
+
+msgid "E493: Backwards range given"
+msgstr "E493: Інтервал задано навиворіт"
+
+msgid "Backwards range given, OK to swap"
+msgstr "Інтервал задано навиворіт, щоб помінÑти міÑцÑми — ГÐРÐЗД"
+
+msgid "E494: Use w or w>>"
+msgstr "E494: Спробуйте w або w>>"
+
+msgid "E943: Command table needs to be updated, run 'make cmdidxs'"
+msgstr "E943: Таблицю команд потрібно поновити, запуÑÑ‚Ñ–Ñ‚ÑŒ 'make cmdidxs'"
+
+msgid "E319: Sorry, the command is not available in this version"
+msgstr "E319: Вибачте, цієї команди немає у цій верÑÑ–Ñ—"
+
+msgid "1 more file to edit. Quit anyway?"
+msgstr "ЗалишилоÑÑ Ð²Ñ–Ð´Ñ€ÐµÐ´Ð°Ð³ÑƒÐ²Ð°Ñ‚Ð¸ ще один файл. Ð’Ñе одно вийти?"
+
+#, c-format
+msgid "%d more files to edit. Quit anyway?"
+msgstr "Ще Ñ” %d не редагованих файлів. Ð’Ñе одно вийти?"
+
+msgid "E173: 1 more file to edit"
+msgstr "E173: ЗалишилоÑÑ Ð²Ñ–Ð´Ñ€ÐµÐ´Ð°Ð³ÑƒÐ²Ð°Ñ‚Ð¸ ще один файл"
+
+#, c-format
+msgid "E173: %ld more files to edit"
+msgstr "E173: ЗалишилоÑÑ %ld не редагованих файлів"
+
+msgid "E174: Command already exists: add ! to replace it"
+msgstr "E174: Команда вже Ñ–Ñнує, ! щоб замінити Ñ—Ñ—"
+
+msgid ""
+"\n"
+" Name Args Address Complete Definition"
+msgstr ""
+"\n"
+" Ðазва Ðрг. ÐдреÑа Ð”Ð¾Ð¿Ð¾Ð²Ð½ÐµÐ½Ð½Ñ Ð’Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ"
+
+msgid "No user-defined commands found"
+msgstr "Ðе знайдено команд кориÑтувача"
+
+msgid "E175: No attribute specified"
+msgstr "E175: Ðе вказано атрибутів"
+
+msgid "E176: Invalid number of arguments"
+msgstr "E176: Ðеправильна кількіÑÑ‚ÑŒ аргументів"
+
+msgid "E177: Count cannot be specified twice"
+msgstr "E177: Лічильник не може бути вказано двічі"
+
+# msgstr "E177: "
+msgid "E178: Invalid default value for count"
+msgstr "E178: Ðеправильне початкове Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð»Ñ–Ñ‡Ð¸Ð»ÑŒÐ½Ð¸ÐºÐ°"
+
+# msgstr "E178: "
+msgid "E179: argument required for -complete"
+msgstr "E179: Ð´Ð»Ñ -complete потрібний аргумент"
+
+# msgstr "E178: "
+msgid "E179: argument required for -addr"
+msgstr "E179: Ð´Ð»Ñ -addr потрібний аргумент"
+
+# msgstr "E180: "
+#, c-format
+msgid "E181: Invalid attribute: %s"
+msgstr "E181: Ðеправильний атрибут: %s"
+
+# msgstr "E181: "
+msgid "E182: Invalid command name"
+msgstr "E182: Ðеправильна назва команди"
+
+# msgstr "E182: "
+msgid "E183: User defined commands must start with an uppercase letter"
+msgstr "E183: Команди кориÑтувача повинні починатиÑÑ Ð· великої літери"
+
+msgid "E841: Reserved name, cannot be used for user defined command"
+msgstr ""
+"E841: Зарезервована назва, не можна викориÑтати Ð´Ð»Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð¸ кориÑтувача"
+
+# msgstr "E183: "
+#, c-format
+msgid "E184: No such user-defined command: %s"
+msgstr "E184: Команду кориÑтувача не знайдено: %s"
+
+# msgstr "E179: "
+#, c-format
+msgid "E180: Invalid address type value: %s"
+msgstr "E180: Ðеправильне Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ñ‚Ð¸Ð¿Ñƒ адреÑи: %s"
+
+# msgstr "E179: "
+#, c-format
+msgid "E180: Invalid complete value: %s"
+msgstr "E180: Ðеправильне доповненнÑ: %s"
+
+msgid "E468: Completion argument only allowed for custom completion"
+msgstr "E468: Ðргумент дозволений тільки Ð´Ð»Ñ Ð´Ð¾Ð¿Ð¾Ð²Ð½ÐµÐ½Ð½Ñ ÐºÐ¾Ñ€Ð¸Ñтувача"
+
+msgid "E467: Custom completion requires a function argument"
+msgstr "E467: КориÑтувацьке Ð´Ð¾Ð¿Ð¾Ð²Ð½ÐµÐ½Ð½Ñ Ð²Ð¸Ð¼Ð°Ð³Ð°Ñ” аргумент-функцію"
+
+msgid "unknown"
+msgstr "Ðевідомо"
+
+# msgstr "E184: "
+#, c-format
+msgid "E185: Cannot find color scheme '%s'"
+msgstr "E185: Ðе вдалоÑÑ Ð·Ð½Ð°Ð¹Ñ‚Ð¸ Ñхему кольорів «%s»"
+
+msgid "Greetings, Vim user!"
+msgstr "ВітаннÑ, кориÑтувачу Vim!"
+
+# msgstr "E443: "
+msgid "E784: Cannot close last tab page"
+msgstr "E784: Ðе можна закрити оÑтанню вкладку"
+
+# msgstr "E444: "
+msgid "Already only one tab page"
+msgstr "Вже й так лише одна вкладка"
+
+# msgstr "E185: "
+msgid "Edit File in new window"
+msgstr "Редагувати файл у новому вікні"
+
+#, c-format
+msgid "Tab page %d"
+msgstr "Вкладка %d"
+
+msgid "No swap file"
+msgstr "Ðемає файлу обміну"
+
+msgid "Append File"
+msgstr "ДопиÑати файл"
+
+msgid "E747: Cannot change directory, buffer is modified (add ! to override)"
+msgstr "E747: Ðе вдалоÑÑ Ð·Ð¼Ñ–Ð½Ð¸Ñ‚Ð¸ каталог, буфер має зміни (! щоб не зважати)"
+
+msgid "E186: No previous directory"
+msgstr "E186: Це вже найперший каталог"
+
+# msgstr "E186: "
+msgid "E187: Unknown"
+msgstr "E187: Ðевідомо"
+
+msgid "E465: :winsize requires two number arguments"
+msgstr "E465: :winsize вимагає два чиÑлових аргументи"
+
+# msgstr "E187: "
+#, c-format
+msgid "Window position: X %d, Y %d"
+msgstr "ÐŸÐ¾Ð·Ð¸Ñ†Ñ–Ñ Ð²Ñ–ÐºÐ½Ð°: X %d, Y %d"
+
+msgid "E188: Obtaining window position not implemented for this platform"
+msgstr "E188: Ðе можна отримати позицію вікна на цій платформі"
+
+msgid "E466: :winpos requires two number arguments"
+msgstr "E466: :winpos вимагає два чиÑлових аргументи"
+
+msgid "E930: Cannot use :redir inside execute()"
+msgstr "E930: Ðе можна викориÑтати :redir вÑередині execute()"
+
+# msgstr "E188: "
+msgid "Save Redirection"
+msgstr "Зберегти переадреÑований вивід"
+
+msgid "Save View"
+msgstr "Зберегти виглÑд"
+
+msgid "Save Session"
+msgstr "Зберегти ÑеанÑ"
+
+msgid "Save Setup"
+msgstr "Зберегти налаштуваннÑ"
+
+#, c-format
+msgid "E739: Cannot create directory: %s"
+msgstr "E739: Ðе вдалоÑÑ Ñтворити каталог: %s"
+
+#, c-format
+msgid "E189: \"%s\" exists (add ! to override)"
+msgstr "E189: Файл «%s» Ñ–Ñнує (! щоб не зважати)"
+
+# msgstr "E189: "
+#, c-format
+msgid "E190: Cannot open \"%s\" for writing"
+msgstr "E190: Ðе вдалоÑÑ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸ «%s» Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñу"
+
+# msgstr "E190: "
+msgid "E191: Argument must be a letter or forward/backward quote"
+msgstr "E191: Ðргумент має бути літерою, ` або '"
+
+# msgstr "E191: "
+msgid "E192: Recursive use of :normal too deep"
+msgstr "E192: Забагато вкладених :normal"
+
+msgid "E809: #< is not available without the +eval feature"
+msgstr "E809: #< не доÑтупна без можливоÑÑ‚Ñ– +eval"
+
+# msgstr "E193: "
+msgid "E194: No alternate file name to substitute for '#'"
+msgstr "E194: Ðемає назви вторинного файлу Ð´Ð»Ñ Ð·Ð°Ð¼Ñ–Ð½Ð¸ '#'"
+
+msgid "E495: no autocommand file name to substitute for \"<afile>\""
+msgstr "E495: Ðемає назви файлу автокоманди Ð´Ð»Ñ Ð·Ð°Ð¼Ñ–Ð½Ð¸ «<afile>»"
+
+msgid "E496: no autocommand buffer number to substitute for \"<abuf>\""
+msgstr "E496: Ðемає номера буфера автокоманди Ð´Ð»Ñ Ð·Ð°Ð¼Ñ–Ð½Ð¸ «<abuf>»"
+
+msgid "E497: no autocommand match name to substitute for \"<amatch>\""
+msgstr "E497: Ðемає назви збігу автокоманди Ð´Ð»Ñ Ð·Ð°Ð¼Ñ–Ð½Ð¸ «<amatch>»"
+
+msgid "E498: no :source file name to substitute for \"<sfile>\""
+msgstr "E498: Ðемає назви файлу :source Ð´Ð»Ñ Ð·Ð°Ð¼Ñ–Ð½Ð¸ «<sfile>»"
+
+msgid "E842: no line number to use for \"<slnum>\""
+msgstr "E842: немає номера Ñ€Ñдка, щоб викориÑтати з «<sfile>»"
+
+#, no-c-format
+msgid "E499: Empty file name for '%' or '#', only works with \":p:h\""
+msgstr "E499: Ðазва файлу Ð´Ð»Ñ '%' чи '#' порожнÑ, працює лише з «:p:h»"
+
+msgid "E500: Evaluates to an empty string"
+msgstr "E500: Результат — порожній Ñ€Ñдок"
+
+msgid "E195: Cannot open viminfo file for reading"
+msgstr "E195: Ðе вдалоÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ файл viminfo"
+
+msgid "Untitled"
+msgstr "Ðеназваний"
+
+msgid "E196: No digraphs in this version"
+msgstr "E196: У цій верÑÑ–Ñ— немає диграфів"
+
+msgid "E608: Cannot :throw exceptions with 'Vim' prefix"
+msgstr "E608: Ðе можна викидати (:throw) винÑтки з префікÑом 'Vim'"
+
+#, c-format
+msgid "Exception thrown: %s"
+msgstr "ВинÑткова ÑитуаціÑ: %s"
+
+#, c-format
+msgid "Exception finished: %s"
+msgstr "ВинÑток закінчено: %s"
+
+#, c-format
+msgid "Exception discarded: %s"
+msgstr "ВинÑток Ñкинуто: %s"
+
+#, c-format
+msgid "%s, line %ld"
+msgstr "%s, Ñ€Ñдок %ld"
+
+#, c-format
+msgid "Exception caught: %s"
+msgstr "Спіймано винÑткову Ñитуацію: %s"
+
+#, c-format
+msgid "%s made pending"
+msgstr "ОчікуєтьÑÑ %s"
+
+#, c-format
+msgid "%s resumed"
+msgstr "Відновлено %s"
+
+#, c-format
+msgid "%s discarded"
+msgstr "Скинуто %s"
+
+msgid "Exception"
+msgstr "ВинÑток"
+
+msgid "Error and interrupt"
+msgstr "Помилка, перервано"
+
+# msgstr "E231: "
+msgid "Error"
+msgstr "Помилка"
+
+msgid "Interrupt"
+msgstr "Перервано"
+
+msgid "E579: :if nesting too deep"
+msgstr "E579: Занадто багато вкладених :if"
+
+msgid "E580: :endif without :if"
+msgstr "E580: :endif без :if"
+
+msgid "E581: :else without :if"
+msgstr "E581: :else без :if"
+
+msgid "E582: :elseif without :if"
+msgstr "E582: :elseif без :if"
+
+msgid "E583: multiple :else"
+msgstr "E583: Ðе одне :else"
+
+msgid "E584: :elseif after :else"
+msgstr "E584: :elseif піÑÐ»Ñ :else"
+
+msgid "E585: :while/:for nesting too deep"
+msgstr "E585: Забагато вкладених :while/:for"
+
+msgid "E586: :continue without :while or :for"
+msgstr "E586: :continue без :while чи :for"
+
+msgid "E587: :break without :while or :for"
+msgstr "E587: :break без :while чи :for"
+
+msgid "E732: Using :endfor with :while"
+msgstr "E732: Вжито :endfor із :while"
+
+msgid "E733: Using :endwhile with :for"
+msgstr "E733: Вжито :endwhile із :for"
+
+msgid "E601: :try nesting too deep"
+msgstr "E601: Забагато вкладених :try"
+
+msgid "E603: :catch without :try"
+msgstr "E603: :catch без :try"
+
+msgid "E604: :catch after :finally"
+msgstr "E604: :catch піÑÐ»Ñ :finally"
+
+msgid "E606: :finally without :try"
+msgstr "E606: :finally без :try"
+
+msgid "E607: multiple :finally"
+msgstr "E607: Ðе одне :finally"
+
+msgid "E602: :endtry without :try"
+msgstr "E602: :entry без :try"
+
+msgid "E193: :endfunction not inside a function"
+msgstr "E193: :endfunction поза межами функції"
+
+msgid "E788: Not allowed to edit another buffer now"
+msgstr "E788: Зараз не можна редагувати інший буфер"
+
+msgid "E811: Not allowed to change buffer information now"
+msgstr "E811: Зараз не можна змінювати інформацію буфера"
+
+# msgstr "E197: "
+msgid "tagname"
+msgstr "назва мітки"
+
+msgid " kind file\n"
+msgstr " тип файлу\n"
+
+msgid "'history' option is zero"
+msgstr "ÐžÐ¿Ñ†Ñ–Ñ 'history' порожнÑ"
+
+#, c-format
+msgid ""
+"\n"
+"# %s History (newest to oldest):\n"
+msgstr ""
+"\n"
+"# Попередні %s (від найновіших):\n"
+
+msgid "Command Line"
+msgstr "команди"
+
+msgid "Search String"
+msgstr "шукані Ñ€Ñдки"
+
+msgid "Expression"
+msgstr "вирази"
+
+msgid "Input Line"
+msgstr "введені Ñ€Ñдки"
+
+msgid "Debug Line"
+msgstr "РÑдок налагодженнÑ"
+
+msgid "E198: cmd_pchar beyond the command length"
+msgstr "E198: cmd_pchar поза межами команди"
+
+msgid "E199: Active window or buffer deleted"
+msgstr "E199: Ðктивне вікно або буфер було знищено"
+
+msgid "E812: Autocommands changed buffer or buffer name"
+msgstr "E812: Ðвтокоманди змінили буфер чи його назву"
+
+# msgstr "E199: "
+msgid "Illegal file name"
+msgstr "Ðедозволена назва файлу"
+
+msgid "is a directory"
+msgstr "каталог"
+
+msgid "is not a file"
+msgstr "не файл"
+
+msgid "is a device (disabled with 'opendevice' option)"
+msgstr "Ñ” приÑтроєм (вимкнено опцією 'opendevice')"
+
+msgid "[New File]"
+msgstr "[Ðовий файл]"
+
+msgid "[New DIRECTORY]"
+msgstr "[Ðовий каталог]"
+
+msgid "[File too big]"
+msgstr "[Файл завеликий]"
+
+msgid "[Permission Denied]"
+msgstr "[Відмовлено]"
+
+msgid "E200: *ReadPre autocommands made the file unreadable"
+msgstr "E200: Ðвтокоманди *ReadPre унеможливили Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ Ñ„Ð°Ð¹Ð»Ñƒ"
+
+# msgstr "E200: "
+msgid "E201: *ReadPre autocommands must not change current buffer"
+msgstr "E201: Ðвтокоманди *ReadPre не повинні змінювати цей буфер"
+
+# msgstr "E201: "
+msgid "Vim: Reading from stdin...\n"
+msgstr "Vim: ЧитаєтьÑÑ Ð· stdin...\n"
+
+msgid "Reading from stdin..."
+msgstr "ЧитаєтьÑÑ Ð· stdin..."
+
+msgid "E202: Conversion made file unreadable!"
+msgstr "E202: ÐšÐ¾Ð½Ð²ÐµÑ€Ñ‚Ð°Ñ†Ñ–Ñ ÑƒÐ½ÐµÐ¼Ð¾Ð¶Ð»Ð¸Ð²Ð¸Ð»Ð° Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ Ñ„Ð°Ð¹Ð»Ñƒ!"
+
+# msgstr "E202: "
+msgid "[fifo/socket]"
+msgstr "[канал/гніздо]"
+
+msgid "[fifo]"
+msgstr "[канал]"
+
+msgid "[socket]"
+msgstr "[гніздо]"
+
+msgid "[character special]"
+msgstr "[Ñпец. Ñимвольний]"
+
+msgid "[CR missing]"
+msgstr "[Бракує CR]"
+
+msgid "[long lines split]"
+msgstr "[Розбито довгі Ñ€Ñдки]"
+
+msgid "[NOT converted]"
+msgstr "[ÐЕ конвертовано]"
+
+msgid "[converted]"
+msgstr "[конвертовано]"
+
+#, c-format
+msgid "[CONVERSION ERROR in line %ld]"
+msgstr "[ПОМИЛКРКОÐВЕРТÐЦІЇ у Ñ€Ñдку %ld]"
+
+#, c-format
+msgid "[ILLEGAL BYTE in line %ld]"
+msgstr "[ÐЕКОРЕКТÐИЙ БÐЙТ у Ñ€Ñдку %ld]"
+
+msgid "[READ ERRORS]"
+msgstr "[ПОМИЛКРЧИТÐÐÐЯ]"
+
+msgid "Can't find temp file for conversion"
+msgstr "Ðе вдалоÑÑ Ð¿Ñ–Ð´ÑˆÑƒÐºÐ°Ñ‚Ð¸ тимчаÑовий файл Ð´Ð»Ñ ÐºÐ¾Ð½Ð²ÐµÑ€Ñ‚Ð°Ñ†Ñ–Ñ—"
+
+msgid "Conversion with 'charconvert' failed"
+msgstr "ÐšÐ¾Ð½Ð²ÐµÑ€Ñ‚Ð°Ñ†Ñ–Ñ Ð· 'charconvert' не вдалаÑÑ"
+
+msgid "can't read output of 'charconvert'"
+msgstr "не вдалоÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ вивід 'charconvert'"
+
+# msgstr "E217: "
+msgid "E676: No matching autocommands for acwrite buffer"
+msgstr "E676: Ðемає відповідних автокоманд"
+
+msgid "E203: Autocommands deleted or unloaded buffer to be written"
+msgstr "E203: Ðвтокоманда знищила або вивантажила буфер, що мав бути запиÑаний"
+
+msgid "E204: Autocommand changed number of lines in unexpected way"
+msgstr "E204: Ðвтокоманда неÑподіваним чином змінила кількіÑÑ‚ÑŒ Ñ€Ñдків"
+
+msgid "NetBeans disallows writes of unmodified buffers"
+msgstr "NetBeans не дозволÑÑ” запиÑувати у незмінені буфери"
+
+# msgstr "E391: "
+msgid "Partial writes disallowed for NetBeans buffers"
+msgstr "ЧаÑткові запиÑи заборонені Ð´Ð»Ñ Ð±ÑƒÑ„ÐµÑ€Ñ–Ð² NetBeans"
+
+msgid "is not a file or writable device"
+msgstr "Ðе придатний Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñу"
+
+msgid "writing to device disabled with 'opendevice' option"
+msgstr "Ð—Ð°Ð¿Ð¸Ñ Ð´Ð¾ приÑтрою заборонено опцією 'opendevice'"
+
+msgid "is read-only (add ! to override)"
+msgstr "лише Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ (! щоб не зважати)"
+
+msgid "E506: Can't write to backup file (add ! to override)"
+msgstr "E506: Ðе вдалоÑÑ Ð·Ð°Ð¿Ð¸Ñати резервний файл (! щоб не зважати)"
+
+msgid "E507: Close error for backup file (add ! to override)"
+msgstr "E507: Помилка Ð·Ð°ÐºÑ€Ð¸Ñ‚Ñ‚Ñ Ñ€ÐµÐ·ÐµÑ€Ð²Ð½Ð¾Ð³Ð¾ файлу (! щоб не зважати)"
+
+msgid "E508: Can't read file for backup (add ! to override)"
+msgstr ""
+"E508: Ðе вдалоÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ файл щоб Ñтворити резервну копію (! щоб не "
+"зважати)"
+
+msgid "E509: Cannot create backup file (add ! to override)"
+msgstr "E509: Ðе вдалоÑÑ Ñтворити резервну копію (! щоб не зважати)"
+
+msgid "E510: Can't make backup file (add ! to override)"
+msgstr "E510: Ðе вдалоÑÑ Ð·Ñ€Ð¾Ð±Ð¸Ñ‚Ð¸ резервну копію (! щоб не зважати)"
+
+msgid "E214: Can't find temp file for writing"
+msgstr "E214: Ðе вдалоÑÑ Ð¿Ñ–Ð´ÑˆÑƒÐºÐ°Ñ‚Ð¸ тимчаÑовий файл Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñу"
+
+msgid "E213: Cannot convert (add ! to write without conversion)"
+msgstr "E213: Ðе вдалоÑÑ Ð¿ÐµÑ€ÐµÑ‚Ð²Ð¾Ñ€Ð¸Ñ‚Ð¸ (! щоб запиÑати без конвертації)"
+
+msgid "E166: Can't open linked file for writing"
+msgstr "E166: Ðе вдалоÑÑ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸ Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñу зв'Ñзаний файл"
+
+msgid "E212: Can't open file for writing"
+msgstr "E212: Ðе вдалоÑÑ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸ файл Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñу"
+
+# msgstr "E79: "
+msgid "E949: File changed while writing"
+msgstr "E949: Файл Ð·Ð¼Ñ–Ð½Ð¸Ð²Ð»Ñ Ð¿Ñ–Ð´ Ñ‡Ð°Ñ Ð·Ð°Ð¿Ð¸Ñу"
+
+msgid "E512: Close failed"
+msgstr "E512: Ðе вдалоÑÑ Ð·Ð°ÐºÑ€Ð¸Ñ‚Ð¸"
+
+msgid "E513: write error, conversion failed (make 'fenc' empty to override)"
+msgstr "E513: Помилка запиÑу, ÐºÐ¾Ð½Ð²ÐµÑ€Ñ‚Ð°Ñ†Ñ–Ñ Ð½Ðµ вдалаÑÑ (Ñкиньте 'fenc')"
+
+#, c-format
+msgid ""
+"E513: write error, conversion failed in line %ld (make 'fenc' empty to "
+"override)"
+msgstr ""
+"E513: Помилка запиÑу, ÐºÐ¾Ð½Ð²ÐµÑ€Ñ‚Ð°Ñ†Ñ–Ñ Ð½Ðµ вдалаÑÑ Ñƒ Ñ€Ñдку %ld (Ñкиньте 'fenc')"
+
+msgid "E514: write error (file system full?)"
+msgstr "E514: Помилка запиÑу (ÑкінчилоÑÑŒ вільне міÑце?)"
+
+msgid " CONVERSION ERROR"
+msgstr " ПОМИЛКРКОÐВЕРТÐЦІЇ"
+
+#, c-format
+msgid " in line %ld;"
+msgstr " у Ñ€Ñдку %ld;"
+
+msgid "[Device]"
+msgstr "[ПриÑтрій]"
+
+msgid "[New]"
+msgstr "[Ðовий]"
+
+msgid " [a]"
+msgstr "[д]"
+
+msgid " appended"
+msgstr " допиÑаний"
+
+msgid " [w]"
+msgstr "[з]"
+
+msgid " written"
+msgstr " запиÑаний"
+
+msgid "E205: Patchmode: can't save original file"
+msgstr "E205: ЛатаннÑ: не вдалоÑÑ Ð·Ð±ÐµÑ€ÐµÐ³Ñ‚Ð¸ оригінал"
+
+msgid "E206: patchmode: can't touch empty original file"
+msgstr "E206: ЛатаннÑ: не вдалоÑÑ Ñтворити оригінал"
+
+msgid "E207: Can't delete backup file"
+msgstr "E207: Ðе вдалоÑÑ Ð·Ð½Ð¸Ñ‰Ð¸Ñ‚Ð¸ резервний файл"
+
+msgid ""
+"\n"
+"WARNING: Original file may be lost or damaged\n"
+msgstr ""
+"\n"
+"ЗÐСТЕРЕЖЕÐÐЯ: Оригінал, мабуть, втрачений чи пошкоджений\n"
+
+msgid "don't quit the editor until the file is successfully written!"
+msgstr "Ðе виходьте з редактора, доки файл не запиÑано!"
+
+msgid "[dos]"
+msgstr "[dos]"
+
+msgid "[dos format]"
+msgstr "[формат dos]"
+
+msgid "[mac]"
+msgstr "[mac]"
+
+msgid "[mac format]"
+msgstr "[формат mac]"
+
+msgid "[unix]"
+msgstr "[unix]"
+
+msgid "[unix format]"
+msgstr "[формат unix]"
+
+msgid "1 line, "
+msgstr "один Ñ€Ñдок, "
+
+#, c-format
+msgid "%ld lines, "
+msgstr "%ld Ñ€Ñдків, "
+
+msgid "1 character"
+msgstr "один Ñимвол"
+
+#, c-format
+msgid "%lld characters"
+msgstr "%lld Ñимволів"
+
+msgid "[noeol]"
+msgstr "[noeol]"
+
+msgid "[Incomplete last line]"
+msgstr "[Ðеповний оÑтанній Ñ€Ñдок]"
+
+msgid "WARNING: The file has been changed since reading it!!!"
+msgstr "ЗÐСТЕРЕЖЕÐÐЯ: Файл змінивÑÑ Ð· чаÑу оÑтаннього читаннÑ!!!"
+
+msgid "Do you really want to write to it"
+msgstr "Ви Ñправді хочете його перепиÑати??"
+
+#, c-format
+msgid "E208: Error writing to \"%s\""
+msgstr "E208: Помилка запиÑу у «%s»"
+
+#, c-format
+msgid "E209: Error closing \"%s\""
+msgstr "E209: Помилка Ð·Ð°ÐºÑ€Ð¸Ñ‚Ñ‚Ñ Â«%s»"
+
+#, c-format
+msgid "E210: Error reading \"%s\""
+msgstr "E210: Помилка Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ Â«%s»"
+
+msgid "E246: FileChangedShell autocommand deleted buffer"
+msgstr "E246: Ðвтокоманда FileChangedShell знищила буфер"
+
+#, c-format
+msgid "E211: File \"%s\" no longer available"
+msgstr "E211: Файл «%s» більше не доÑÑжний"
+
+#, c-format
+msgid ""
+"W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as "
+"well"
+msgstr "W12: ЗаÑтереженнÑ: Файл «%s» змінивÑÑ, але й буфер у Vim також"
+
+msgid "See \":help W12\" for more info."
+msgstr "Див. «:help W12» Ð´Ð»Ñ ÑƒÑ‚Ð¾Ñ‡Ð½ÐµÐ½Ð½Ñ."
+
+#, c-format
+msgid "W11: Warning: File \"%s\" has changed since editing started"
+msgstr "W11: ЗаÑтереженнÑ: Файл «%s» змінивÑÑ Ð¿Ñ–ÑÐ»Ñ Ð¿Ð¾Ñ‡Ð°Ñ‚ÐºÑƒ редагуваннÑ"
+
+msgid "See \":help W11\" for more info."
+msgstr "Див. «:help W11» Ð´Ð»Ñ ÑƒÑ‚Ð¾Ñ‡Ð½ÐµÐ½Ð½Ñ."
+
+#, c-format
+msgid "W16: Warning: Mode of file \"%s\" has changed since editing started"
+msgstr "W16: ЗаÑтереженнÑ: Режим файлу «%s» змінивÑÑ Ð¿Ñ–ÑÐ»Ñ Ð¿Ð¾Ñ‡Ð°Ñ‚ÐºÑƒ редагуваннÑ"
+
+msgid "See \":help W16\" for more info."
+msgstr "Див. «:help W16» Ð´Ð»Ñ ÑƒÑ‚Ð¾Ñ‡Ð½ÐµÐ½Ð½Ñ."
+
+#, c-format
+msgid "W13: Warning: File \"%s\" has been created after editing started"
+msgstr "W13: ЗаÑтереженнÑ: Файл «%s» було Ñтворено піÑÐ»Ñ Ð¿Ð¾Ñ‡Ð°Ñ‚ÐºÑƒ редагуваннÑ"
+
+msgid "Warning"
+msgstr "ЗаÑтереженнÑ"
+
+msgid ""
+"&OK\n"
+"&Load File"
+msgstr ""
+"&O:Гаразд\n"
+"&L:Завантажити"
+
+#, c-format
+msgid "E462: Could not prepare for reloading \"%s\""
+msgstr "E462: Ðе вдалоÑÑ Ð¿Ñ–Ð´Ð³Ð¾Ñ‚ÑƒÐ²Ð°Ñ‚Ð¸ «%s», щоб перечитати"
+
+#, c-format
+msgid "E321: Could not reload \"%s\""
+msgstr "E321: Ðе вдалоÑÑ Ð¿ÐµÑ€ÐµÑ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ «%s»"
+
+msgid "--Deleted--"
+msgstr "--Знищено--"
+
+#, c-format
+msgid "auto-removing autocommand: %s <buffer=%d>"
+msgstr "Ðвтоматичне Ð·Ð½Ð¸Ñ‰ÐµÐ½Ð½Ñ Ð°Ð²Ñ‚Ð¾ÐºÐ¾Ð¼Ð°Ð½Ð´Ð¸: %s <буфер=%d>"
+
+#, c-format
+msgid "E367: No such group: \"%s\""
+msgstr "E367: Ðемає такої групи: «%s»"
+
+msgid "E936: Cannot delete the current group"
+msgstr "E936: Ðе вдалоÑÑ Ð·Ð½Ð¸Ñ‰Ð¸Ñ‚Ð¸ цю групу"
+
+msgid "W19: Deleting augroup that is still in use"
+msgstr "W19: ЗнищуєтьÑÑ Ð°Ð²Ñ‚Ð¾Ð³Ñ€ÑƒÐ¿Ð° вÑе ще у вжитку"
+
+#, c-format
+msgid "E215: Illegal character after *: %s"
+msgstr "E215: Ðедозволений Ñимвол піÑÐ»Ñ *: %s"
+
+# msgstr "E215: "
+#, c-format
+msgid "E216: No such event: %s"
+msgstr "E216: Ðемає такої події: %s"
+
+# msgstr "E215: "
+#, c-format
+msgid "E216: No such group or event: %s"
+msgstr "E216: Ðемає такої групи чи події: %s"
+
+# msgstr "E216: "
+msgid ""
+"\n"
+"--- Autocommands ---"
+msgstr ""
+"\n"
+"--- Ðвтокоманди ---"
+
+#, c-format
+msgid "E680: <buffer=%d>: invalid buffer number "
+msgstr "E680: <буфер=%d>: некоректний номер буфера "
+
+msgid "E217: Can't execute autocommands for ALL events"
+msgstr "E217: Ðе можу виконувати автокоманди Ð´Ð»Ñ Ð£Ð¡Ð†Ð¥ подій"
+
+# msgstr "E217: "
+msgid "No matching autocommands"
+msgstr "Ðемає відповідних автокоманд"
+
+msgid "E218: autocommand nesting too deep"
+msgstr "E218: Забагато вкладених автокоманд"
+
+# msgstr "E218: "
+#, c-format
+msgid "%s Autocommands for \"%s\""
+msgstr "Ðвтокоманди %s Ð´Ð»Ñ Â«%s»"
+
+#, c-format
+msgid "Executing %s"
+msgstr "ВиконуєтьÑÑ %s"
+
+#, c-format
+msgid "autocommand %s"
+msgstr "автокоманда %s"
+
+msgid "E219: Missing {."
+msgstr "E219: Бракує {."
+
+# msgstr "E219: "
+msgid "E220: Missing }."
+msgstr "E220: Бракує }."
+
+# msgstr "E220: "
+msgid "E490: No fold found"
+msgstr "E490: Згорток не знайдено"
+
+# msgstr "E349: "
+msgid "E350: Cannot create fold with current 'foldmethod'"
+msgstr "E350: Ðе вдалоÑÑ Ñтворити згортку методом 'foldmethod'"
+
+msgid "E351: Cannot delete fold with current 'foldmethod'"
+msgstr "E351: Ðе вдалоÑÑ Ð·Ð½Ð¸Ñ‰Ð¸Ñ‚Ð¸ згортку методом 'foldmethod'"
+
+#, c-format
+msgid "+--%3ld line folded "
+msgid_plural "+--%3ld lines folded "
+msgstr[0] "+--%3ld Ñ€Ñдок згорнуто "
+msgstr[1] "+--%3ld Ñ€Ñдків згорнуто "
+
+msgid "E222: Add to read buffer"
+msgstr "E222: Додати до буфера читаннÑ"
+
+msgid "E223: recursive mapping"
+msgstr "E223: Заміна рекурÑивна"
+
+# msgstr "E223: "
+#, c-format
+msgid "E224: global abbreviation already exists for %s"
+msgstr "E224: Загальне ÑÐºÐ¾Ñ€Ð¾Ñ‡ÐµÐ½Ð½Ñ Ð´Ð»Ñ %s вже Ñ–Ñнує"
+
+# msgstr "E224: "
+#, c-format
+msgid "E225: global mapping already exists for %s"
+msgstr "E225: Загальна заміна Ð´Ð»Ñ %s вже Ñ–Ñнує"
+
+# msgstr "E225: "
+#, c-format
+msgid "E226: abbreviation already exists for %s"
+msgstr "E226: Вже Ñ” ÑÐºÐ¾Ñ€Ð¾Ñ‡ÐµÐ½Ð½Ñ Ð´Ð»Ñ %s"
+
+# msgstr "E226: "
+#, c-format
+msgid "E227: mapping already exists for %s"
+msgstr "E227: Вже Ñ” заміна Ð´Ð»Ñ %s"
+
+# msgstr "E227: "
+msgid "No abbreviation found"
+msgstr "Ð¡ÐºÐ¾Ñ€Ð¾Ñ‡ÐµÐ½Ð½Ñ Ð½Ðµ знайдено"
+
+msgid "No mapping found"
+msgstr "Заміни не знайдено"
+
+msgid "E228: makemap: Illegal mode"
+msgstr "E228: makemap: ÐеприпуÑтимий режим"
+
+msgid "<cannot open> "
+msgstr "<не відкриваєтьÑÑ> "
+
+#, c-format
+msgid "E616: vim_SelFile: can't get font %s"
+msgstr "E616: vim_SelFile: не вдалоÑÑ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ñ‚Ð¸ шрифт %s"
+
+msgid "E614: vim_SelFile: can't return to current directory"
+msgstr "E614: vim_SelFile: не вдалоÑÑ Ð¿Ð¾Ð²ÐµÑ€Ð½ÑƒÑ‚Ð¸ÑÑ Ð² поточний каталог"
+
+msgid "Pathname:"
+msgstr "ШлÑÑ…:"
+
+msgid "E615: vim_SelFile: can't get current directory"
+msgstr "E615: vim_SelFile: не вдалоÑÑ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ñ‚Ð¸ поточний каталог"
+
+msgid "OK"
+msgstr "Гаразд"
+
+msgid "Cancel"
+msgstr "СкаÑувати"
+
+msgid "Vim dialog"
+msgstr "Діалог Vim"
+
+msgid "Scrollbar Widget: Could not get geometry of thumb pixmap."
+msgstr "Scrollbar Widget: Ðе вдалоÑÑ Ð²Ð¸Ð·Ð½Ð°Ñ‡Ð¸Ñ‚Ð¸ розмір Ñкороченої картинки."
+
+msgid "E232: Cannot create BalloonEval with both message and callback"
+msgstr "E232: Ðе вдалоÑÑ Ñтворити BalloonEval з повідомленнÑм Ñ– функцією"
+
+msgid "E851: Failed to create a new process for the GUI"
+msgstr "E851: Ðе вдалоÑÑ Ñтворити новий Ð¿Ñ€Ð¾Ñ†ÐµÑ Ð´Ð»Ñ GUI"
+
+msgid "E852: The child process failed to start the GUI"
+msgstr "E852: Дочірній Ð¿Ñ€Ð¾Ñ†ÐµÑ Ð½Ðµ зміг запуÑтити GUI"
+
+# msgstr "E228: "
+msgid "E229: Cannot start the GUI"
+msgstr "E229: Ðе вдалоÑÑ Ð·Ð°Ð¿ÑƒÑтити GUI"
+
+# msgstr "E229: "
+#, c-format
+msgid "E230: Cannot read from \"%s\""
+msgstr "E230: Ðе вдалоÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ з «%s»"
+
+msgid "E665: Cannot start GUI, no valid font found"
+msgstr "E665: Ðе вдалоÑÑ Ð·Ð°Ð¿ÑƒÑтити GUI, не знайдено шрифт"
+
+# msgstr "E230: "
+msgid "E231: 'guifontwide' invalid"
+msgstr "E231: Ðекоректний 'guifontwide'"
+
+msgid "E599: Value of 'imactivatekey' is invalid"
+msgstr "E599: Ð—Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ 'imactivatekey' некоректне"
+
+#, c-format
+msgid "E254: Cannot allocate color %s"
+msgstr "E254: Ðе вдалоÑÑ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ñ‚Ð¸ колір %s"
+
+msgid "No match at cursor, finding next"
+msgstr "Ðемає над курÑором, пошук триває"
+
+msgid "_Cancel"
+msgstr "СкаÑувати"
+
+msgid "_Save"
+msgstr "Зберегти"
+
+msgid "_Open"
+msgstr "Відкрити"
+
+msgid "_OK"
+msgstr "Гаразд"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"&Cancel"
+msgstr ""
+"&Y:Так\n"
+"&N:ÐÑ–\n"
+"&C:СкаÑувати"
+
+msgid "Yes"
+msgstr "Так"
+
+msgid "No"
+msgstr "ÐÑ–"
+
+msgid "Input _Methods"
+msgstr "Методи введеннÑ"
+
+msgid "VIM - Search and Replace..."
+msgstr "VIM - Знайти й замінити..."
+
+msgid "VIM - Search..."
+msgstr "VIM - Пошук..."
+
+msgid "Find what:"
+msgstr "Знайти:"
+
+msgid "Replace with:"
+msgstr "Замінити на:"
+
+msgid "Match whole word only"
+msgstr "Лише повне Ñлово"
+
+msgid "Match case"
+msgstr "Зважати на регіÑÑ‚Ñ€"
+
+msgid "Direction"
+msgstr "ÐапрÑм"
+
+msgid "Up"
+msgstr "Вгору"
+
+msgid "Down"
+msgstr "Униз"
+
+msgid "Find Next"
+msgstr "ÐаÑтупне"
+
+msgid "Replace"
+msgstr "Замінити"
+
+msgid "Replace All"
+msgstr "Замінити уÑÑ–"
+
+msgid "_Close"
+msgstr "Закрити"
+
+msgid "Vim: Received \"die\" request from session manager\n"
+msgstr "Vim: Отримав запит «die» від менеджера ÑеÑій\n"
+
+msgid "Close tab"
+msgstr "Закрити вкладку"
+
+msgid "New tab"
+msgstr "Ðова вкладка"
+
+msgid "Open Tab..."
+msgstr "Відкрити вкладку..."
+
+msgid "Vim: Main window unexpectedly destroyed\n"
+msgstr "Vim: ÐеÑподівано знищилоÑÑ Ð³Ð¾Ð»Ð¾Ð²Ð½Ðµ вікно\n"
+
+msgid "&Filter"
+msgstr "&F:Фільтрувати"
+
+msgid "&Cancel"
+msgstr "&C:СкаÑувати"
+
+msgid "Directories"
+msgstr "Каталоги"
+
+msgid "Filter"
+msgstr "Фільтр"
+
+msgid "&Help"
+msgstr "&H:Допомога"
+
+msgid "Files"
+msgstr "Файли"
+
+msgid "&OK"
+msgstr "&O:Гаразд"
+
+msgid "Selection"
+msgstr "ВиділеннÑ"
+
+msgid "Find &Next"
+msgstr "&N:Знайти далі"
+
+msgid "&Replace"
+msgstr "&R:Замінити"
+
+msgid "Replace &All"
+msgstr "&A:Замінити уÑÑ–"
+
+msgid "&Undo"
+msgstr "&U:СкаÑувати"
+
+msgid "Open tab..."
+msgstr "Відкрити вкладку..."
+
+# msgstr "E245: "
+msgid "Find string (use '\\\\' to find a '\\')"
+msgstr "Знайти Ñ€Ñдок ('\\\\' щоб знайти '\\')"
+
+msgid "Find & Replace (use '\\\\' to find a '\\')"
+msgstr "Знайти і замінити ('\\\\' щоб знайти '\\')"
+
+msgid "Not Used"
+msgstr "Ðемає"
+
+msgid "Directory\t*.nothing\n"
+msgstr "Каталог\t*.нічого\n"
+
+#, c-format
+msgid "E671: Cannot find window title \"%s\""
+msgstr "E671: Ðе вдалоÑÑ Ð·Ð½Ð°Ð¹Ñ‚Ð¸ вікно «%s»"
+
+#, c-format
+msgid "E243: Argument not supported: \"-%s\"; Use the OLE version."
+msgstr "E243: Ðргумент не підтримуєтьÑÑ: «-%s»; кориÑтуйтеÑÑŒ верÑією з OLE."
+
+msgid "E672: Unable to open window inside MDI application"
+msgstr "E672: Ðе вдалоÑÑ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸ вікно вÑередині програми MDI"
+
+msgid "Vim E458: Cannot allocate colormap entry, some colors may be incorrect"
+msgstr ""
+"Vim E458: Ðемає вільних комірок у палітрі, деÑкі кольори можуть бути "
+"неправильні"
+
+#, c-format
+msgid "E250: Fonts for the following charsets are missing in fontset %s:"
+msgstr "E250: Шрифти Ð´Ð»Ñ Ñ†Ð¸Ñ… Ñимволів відÑутні у наборі %s:"
+
+# msgstr "E250: "
+#, c-format
+msgid "E252: Fontset name: %s"
+msgstr "E252: Ðазва набору шрифтів: %s"
+
+# msgstr "E252: "
+#, c-format
+msgid "Font '%s' is not fixed-width"
+msgstr "Шрифт '%s' не є моноширинним"
+
+#, c-format
+msgid "E253: Fontset name: %s"
+msgstr "E253: Ðазва набору шрифтів: %s"
+
+#, c-format
+msgid "Font0: %s"
+msgstr "Шрифт0: %s"
+
+#, c-format
+msgid "Font1: %s"
+msgstr "Шрифт1: %s"
+
+#, c-format
+msgid "Font%ld width is not twice that of font0"
+msgstr "Ширина шрифту%ld не більша удвічі за ширину шрифту0"
+
+#, c-format
+msgid "Font0 width: %ld"
+msgstr "Ширина шрифту0: %ld"
+
+#, c-format
+msgid "Font1 width: %ld"
+msgstr "Ширина шрифту1: %ld"
+
+msgid "Invalid font specification"
+msgstr "Ðекоректна ÑÐ¿ÐµÑ†Ð¸Ñ„Ñ–ÐºÐ°Ñ†Ñ–Ñ ÑˆÑ€Ð¸Ñ„Ñ‚Ñƒ"
+
+msgid "&Dismiss"
+msgstr "&D:Припинити"
+
+msgid "no specific match"
+msgstr "немає конкретного збігу"
+
+# msgstr "E234: "
+msgid "Vim - Font Selector"
+msgstr "Vim - Вибір шрифту"
+
+msgid "Name:"
+msgstr "Ðазва:"
+
+msgid "Show size in Points"
+msgstr "Показати розмір у пунктах"
+
+msgid "Encoding:"
+msgstr "КодуваннÑ:"
+
+msgid "Font:"
+msgstr "Шрифт:"
+
+msgid "Style:"
+msgstr "Стиль:"
+
+msgid "Size:"
+msgstr "Розмір:"
+
+msgid "E256: Hangul automata ERROR"
+msgstr "E256: Помилка автомату Hangul"
+
+msgid "E550: Missing colon"
+msgstr "E550: Пропущено двокрапку"
+
+# msgstr "E347: "
+msgid "E551: Illegal component"
+msgstr "E551: Ðекоректний компонент"
+
+msgid "E552: digit expected"
+msgstr "E552: очікуєтьÑÑ Ñ†Ð¸Ñ„Ñ€Ð°"
+
+#, c-format
+msgid "Page %d"
+msgstr "Сторінка %d"
+
+msgid "No text to be printed"
+msgstr "Ðічого друкувати"
+
+#, c-format
+msgid "Printing page %d (%d%%)"
+msgstr "ДрукуєтьÑÑ Ñторінка %d (%d%%)"
+
+#, c-format
+msgid " Copy %d of %d"
+msgstr " ÐšÐ¾Ð¿Ñ–Ñ %d з %d"
+
+#, c-format
+msgid "Printed: %s"
+msgstr "Ðадруковано: %s"
+
+msgid "Printing aborted"
+msgstr "Друк перервано"
+
+msgid "E455: Error writing to PostScript output file"
+msgstr "E455: Ðе вдалоÑÑ Ð·Ð°Ð¿Ð¸Ñати вихідний файл PostScript"
+
+#, c-format
+msgid "E624: Can't open file \"%s\""
+msgstr "E624: Ðе вдалоÑÑ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸ файл «%s»"
+
+#, c-format
+msgid "E457: Can't read PostScript resource file \"%s\""
+msgstr "E457: Ðе вдалоÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ файл реÑурÑів PostScript «%s»"
+
+#, c-format
+msgid "E618: file \"%s\" is not a PostScript resource file"
+msgstr "E618: «%s» не Ñ” файлом реÑурÑів PostScript"
+
+#, c-format
+msgid "E619: file \"%s\" is not a supported PostScript resource file"
+msgstr "E619: «%s» не Ñ” підтримуваним файлом реÑурÑів PostScript"
+
+#, c-format
+msgid "E621: \"%s\" resource file has wrong version"
+msgstr "E621: Ðеправильна верÑÑ–Ñ Ñ„Ð°Ð¹Ð»Ñƒ реÑурÑів «%s»"
+
+msgid "E673: Incompatible multi-byte encoding and character set."
+msgstr "E673: ÐеÑуміÑні багатобайтове ÐºÐ¾Ð´ÑƒÐ²Ð°Ð½Ð½Ñ Ð¹ набір Ñимволів."
+
+msgid "E674: printmbcharset cannot be empty with multi-byte encoding."
+msgstr ""
+"E674: printmbcharset не може бути порожнім з багатобайтовим кодуваннÑм."
+
+msgid "E675: No default font specified for multi-byte printing."
+msgstr "E675: Ðе зазначено шрифт Ð´Ð»Ñ Ð±Ð°Ð³Ð°Ñ‚Ð¾Ð±Ð°Ð¹Ñ‚Ð¾Ð²Ð¾Ð³Ð¾ друку."
+
+msgid "E324: Can't open PostScript output file"
+msgstr "E324: Ðе вдалоÑÑ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸ файл PostScript Ð´Ð»Ñ Ð²Ð¸Ð²Ð¾Ð´Ñƒ"
+
+#, c-format
+msgid "E456: Can't open file \"%s\""
+msgstr "E456: Ðе вдалоÑÑ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸ файл «%s»"
+
+msgid "E456: Can't find PostScript resource file \"prolog.ps\""
+msgstr "E456: Ðе вдалоÑÑ Ð·Ð½Ð°Ð¹Ñ‚Ð¸ файл реÑурÑів PostScript «prolog.ps»"
+
+msgid "E456: Can't find PostScript resource file \"cidfont.ps\""
+msgstr "E456: Ðе вдалоÑÑ Ð·Ð½Ð°Ð¹Ñ‚Ð¸ файл реÑурÑів PostScript «cidfont.ps»"
+
+#, c-format
+msgid "E456: Can't find PostScript resource file \"%s.ps\""
+msgstr "E456: Ðе вдалоÑÑ Ð·Ð½Ð°Ð¹Ñ‚Ð¸ файл реÑурÑів PostScript «%s.ps»"
+
+#, c-format
+msgid "E620: Unable to convert to print encoding \"%s\""
+msgstr "E620: Ðе вдалоÑÑ Ð¿ÐµÑ€ÐµÑ‚Ð²Ð¾Ñ€Ð¸Ñ‚Ð¸ до ÐºÐ¾Ð´ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ñ€ÑƒÐºÑƒ «%s»"
+
+msgid "Sending to printer..."
+msgstr "ВідÑилаєтьÑÑ Ð½Ð° принтер..."
+
+msgid "E365: Failed to print PostScript file"
+msgstr "E365: Ðе вдалоÑÑ Ð½Ð°Ð´Ñ€ÑƒÐºÑƒÐ²Ð°Ñ‚Ð¸ файл PostScript"
+
+msgid "Print job sent."
+msgstr "Ð—Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð´Ñ€ÑƒÐºÑƒ відіÑлано."
+
+# msgstr "E255: "
+msgid "Add a new database"
+msgstr "Додати нову базу даних"
+
+msgid "Query for a pattern"
+msgstr "Запит за зразком"
+
+msgid "Show this message"
+msgstr "Показати це повідомленнÑ"
+
+msgid "Kill a connection"
+msgstr "Знищити з'єднаннÑ"
+
+msgid "Reinit all connections"
+msgstr "ПерезапуÑтити уÑÑ– з'єднаннÑ"
+
+msgid "Show connections"
+msgstr "Показати з'єднаннÑ"
+
+#, c-format
+msgid "E560: Usage: cs[cope] %s"
+msgstr "E560: ВикориÑтаннÑ: cs[cope] %s"
+
+msgid "This cscope command does not support splitting the window.\n"
+msgstr "Ð¦Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð° cscope не вміє ділити вікно.\n"
+
+msgid "E562: Usage: cstag <ident>"
+msgstr "E562: ВикориÑтаннÑ: cstag <ідентиф-ор>"
+
+msgid "E257: cstag: tag not found"
+msgstr "E257: cstag: мітку не знайдено"
+
+# msgstr "E257: "
+#, c-format
+msgid "E563: stat(%s) error: %d"
+msgstr "E563: stat(%s) помилка: %d"
+
+msgid "E563: stat error"
+msgstr "E563: помилка stat"
+
+#, c-format
+msgid "E564: %s is not a directory or a valid cscope database"
+msgstr "E564: %s не є ні каталогом, ні базою даних cscope"
+
+#, c-format
+msgid "Added cscope database %s"
+msgstr "Додано базу даних cscope %s"
+
+#, c-format
+msgid "E262: error reading cscope connection %ld"
+msgstr "E262: Помилка Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ Ð·Ñ– з'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ cscope %ld"
+
+msgid "E561: unknown cscope search type"
+msgstr "E561: Ðевідомий тип пошуку cscope"
+
+msgid "E566: Could not create cscope pipes"
+msgstr "E566: Ðе вдалоÑÑ Ñтворити канали до cscope"
+
+msgid "E622: Could not fork for cscope"
+msgstr "E622: Ðе вдалоÑÑ Ñ€Ð¾Ð·Ð´Ñ–Ð»Ð¸Ñ‚Ð¸ Ð¿Ñ€Ð¾Ñ†ÐµÑ Ð´Ð»Ñ cscope"
+
+msgid "cs_create_connection setpgid failed"
+msgstr "cs_create_connection: помилка setpgid"
+
+msgid "cs_create_connection exec failed"
+msgstr "cs_create_connection: помилка під Ñ‡Ð°Ñ Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ"
+
+msgid "cs_create_connection: fdopen for to_fp failed"
+msgstr "cs_create_connection: fdopen Ð´Ð»Ñ to_fp не вдавÑÑ"
+
+msgid "cs_create_connection: fdopen for fr_fp failed"
+msgstr "cs_create_connection: fdopen Ð´Ð»Ñ fr_fp не вдавÑÑ"
+
+msgid "E623: Could not spawn cscope process"
+msgstr "E623: Ðе вдалоÑÑ Ñтворити Ð¿Ñ€Ð¾Ñ†ÐµÑ cscope"
+
+msgid "E567: no cscope connections"
+msgstr "E567: жодного з'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ñ–Ð· cscope"
+
+#, c-format
+msgid "E469: invalid cscopequickfix flag %c for %c"
+msgstr "E469: Ðекоректний прапорець cscopequickfix %c Ð´Ð»Ñ %c"
+
+# msgstr "E258: "
+#, c-format
+msgid "E259: no matches found for cscope query %s of %s"
+msgstr "E259: Ð”Ð»Ñ Ð·Ð°Ð¿Ð¸Ñ‚Ñƒ cscope %s з %s нічого не знайдено"
+
+# msgstr "E259: "
+msgid "cscope commands:\n"
+msgstr "Команди cscope:\n"
+
+#, c-format
+msgid "%-5s: %s%*s (Usage: %s)"
+msgstr "%-5s: %s%*s (ВикориÑтаннÑ: %s)"
+
+msgid ""
+"\n"
+" a: Find assignments to this symbol\n"
+" c: Find functions calling this function\n"
+" d: Find functions called by this function\n"
+" e: Find this egrep pattern\n"
+" f: Find this file\n"
+" g: Find this definition\n"
+" i: Find files #including this file\n"
+" s: Find this C symbol\n"
+" t: Find this text string\n"
+msgstr ""
+"\n"
+" a: Знайти приÑÐ²Ð¾Ñ”Ð½Ð½Ñ Ñ†ÑŒÐ¾Ð³Ð¾ Ñимволу\n"
+" c: Знайти функції, що викликають цю функцію\n"
+" d: Знайти функції, що викликаютьÑÑ Ñ†Ñ–Ñ”ÑŽ функцією\n"
+" e: Знайти цей шаблон egrep\n"
+" f: Знайти цей файл\n"
+" g: Знайти це визначеннÑ\n"
+" i: Знайти файли, Ñкі включають в Ñебе цей файл\n"
+" s: Знайти цей Ñимвол C\n"
+" t: Знайти цей текÑÑ‚\n"
+
+#, c-format
+msgid "E625: cannot open cscope database: %s"
+msgstr "E625: Ðе вдалоÑÑ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸ базу даних cscope: %s"
+
+msgid "E626: cannot get cscope database information"
+msgstr "E626: Ðе вдалоÑÑ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ñ‚Ð¸ інформацію з бази даних cscope"
+
+msgid "E568: duplicate cscope database not added"
+msgstr "E568: Повторна база даних cscope не додана"
+
+# msgstr "E260: "
+#, c-format
+msgid "E261: cscope connection %s not found"
+msgstr "E261: З'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð· cscope %s не знайдено"
+
+#, c-format
+msgid "cscope connection %s closed"
+msgstr "З'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð· cscope %s закінчено"
+
+msgid "E570: fatal error in cs_manage_matches"
+msgstr "E570: Фатальна помилка в cs_manage_matches"
+
+#, c-format
+msgid "Cscope tag: %s"
+msgstr "Теґ cscope: %s"
+
+msgid ""
+"\n"
+" # line"
+msgstr ""
+"\n"
+" # Ñ€Ñдок"
+
+msgid "filename / context / line\n"
+msgstr "файл / контекÑÑ‚ / Ñ€Ñдок\n"
+
+#, c-format
+msgid "E609: Cscope error: %s"
+msgstr "E609: Помилка cscope: %s"
+
+msgid "All cscope databases reset"
+msgstr "УÑÑ– бази даних cscope перезавантажено"
+
+msgid "no cscope connections\n"
+msgstr "Жодного з'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð· cscope\n"
+
+msgid " # pid database name prepend path\n"
+msgstr " # pid назва бази даних шлÑÑ…\n"
+
+msgid "Lua library cannot be loaded."
+msgstr "Ðе вдалоÑÑ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶Ð¸Ñ‚Ð¸ бібліотеку Lua"
+
+msgid "cannot save undo information"
+msgstr "не вдалоÑÑ Ð·Ð±ÐµÑ€ÐµÐ³Ñ‚Ð¸ інформацію Ð´Ð»Ñ ÑкаÑуваннÑ"
+
+msgid ""
+"E815: Sorry, this command is disabled, the MzScheme libraries could not be "
+"loaded."
+msgstr ""
+"E815: Вибачте, Ñ†Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð° вимкнена, бібліотеки MzScheme не можуть бути "
+"завантажені."
+
+msgid ""
+"E895: Sorry, this command is disabled, the MzScheme's racket/base module "
+"could not be loaded."
+msgstr ""
+"E895: Вибачте, Ñ†Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð° вимкнена, бібліотеки MzScheme не можуть бути "
+"завантажені."
+
+msgid "invalid expression"
+msgstr "некоректний вираз"
+
+msgid "expressions disabled at compile time"
+msgstr "обробку виразів вимкнено під Ñ‡Ð°Ñ ÐºÐ¾Ð¼Ð¿Ñ–Ð»Ñції"
+
+msgid "hidden option"
+msgstr "прихована опціÑ"
+
+msgid "unknown option"
+msgstr "невідома опціÑ"
+
+msgid "window index is out of range"
+msgstr "некоректний номер вікна"
+
+msgid "couldn't open buffer"
+msgstr "не вдалоÑÑ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸ буфер"
+
+msgid "cannot delete line"
+msgstr "неможливо знищити Ñ€Ñдок"
+
+msgid "cannot replace line"
+msgstr "неможливо замінити Ñ€Ñдок"
+
+msgid "cannot insert line"
+msgstr "не вдалоÑÑ Ð²Ñтавити Ñ€Ñдок"
+
+msgid "string cannot contain newlines"
+msgstr "більше ніж один Ñ€Ñдок"
+
+msgid "error converting Scheme values to Vim"
+msgstr "не вдалоÑÑ Ð¿ÐµÑ€ÐµÑ‚Ð²Ð¾Ñ€Ð¸Ñ‚Ð¸ Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Scheme у Vim"
+
+msgid "Vim error: ~a"
+msgstr "Помилка Vim: ~a"
+
+msgid "Vim error"
+msgstr "Помилка Vim"
+
+msgid "buffer is invalid"
+msgstr "буфер непридатний"
+
+msgid "window is invalid"
+msgstr "вікно непридатне"
+
+msgid "linenr out of range"
+msgstr "номер Ñ€Ñдка за межами файлу"
+
+msgid "not allowed in the Vim sandbox"
+msgstr "не дозволено у піÑочниці Vim"
+
+msgid "E837: This Vim cannot execute :py3 after using :python"
+msgstr "E837: Python: Ðе можна викориÑтати :py Ñ– :py3 в одному ÑеанÑÑ–"
+
+msgid ""
+"E263: Sorry, this command is disabled, the Python library could not be "
+"loaded."
+msgstr ""
+"E263: Вибачте, Ñ†Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð° вимкнена, бібліотека Python не може бути "
+"завантажена."
+
+msgid "E836: This Vim cannot execute :python after using :py3"
+msgstr "E836: Python: Ðе можна викориÑтати :py Ñ– :py3 в одному ÑеанÑÑ–"
+
+msgid ""
+"E887: Sorry, this command is disabled, the Python's site module could not be "
+"loaded."
+msgstr ""
+"E887: Вибачте, Ñ†Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð° вимкнена, міÑцева бібліотека Python не може бути "
+"завантажена."
+
+msgid "E659: Cannot invoke Python recursively"
+msgstr "E659: Ðе можна рекурÑивно викликати Python"
+
+msgid "E265: $_ must be an instance of String"
+msgstr "E265: $_ має бути екземплÑром String"
+
+msgid ""
+"E266: Sorry, this command is disabled, the Ruby library could not be loaded."
+msgstr ""
+"E266: Вибачте, Ñ†Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð° вимкнена, бібліотека Ruby не може бути завантажена."
+
+# msgstr "E414: "
+msgid "E267: unexpected return"
+msgstr "E267: неÑподіваний return"
+
+msgid "E268: unexpected next"
+msgstr "E268: неÑподіваний next"
+
+msgid "E269: unexpected break"
+msgstr "E269: неÑподіваний break"
+
+msgid "E270: unexpected redo"
+msgstr "E270: неÑподіваний redo"
+
+msgid "E271: retry outside of rescue clause"
+msgstr "E271: retry поза rescue"
+
+msgid "E272: unhandled exception"
+msgstr "E272: Ðеоброблений винÑток"
+
+# msgstr "E233: "
+#, c-format
+msgid "E273: unknown longjmp status %d"
+msgstr "E273: Ðевідомий ÑÑ‚Ð°Ñ‚ÑƒÑ longjmp: %d"
+
+msgid "invalid buffer number"
+msgstr "неправильна назва буфера"
+
+msgid "not implemented yet"
+msgstr "ще не реалізовано"
+
+msgid "cannot set line(s)"
+msgstr "не вдалоÑÑ Ð²Ñтановити Ñ€Ñдки"
+
+msgid "invalid mark name"
+msgstr "неправильна назва позначки"
+
+# msgstr "E19: "
+msgid "mark not set"
+msgstr "помітку не вказано"
+
+#, c-format
+msgid "row %d column %d"
+msgstr "Ñ€Ñдок %d колонка %d"
+
+msgid "cannot insert/append line"
+msgstr "Ðе вдалоÑÑ Ð²Ñтавити/додати Ñ€Ñдок"
+
+msgid "line number out of range"
+msgstr "номер Ñ€Ñдка за межами файлу"
+
+msgid "unknown flag: "
+msgstr "невідомий прапорець: "
+
+msgid "unknown vimOption"
+msgstr "Ðевідома vimOption"
+
+msgid "keyboard interrupt"
+msgstr "перервано з клавіатури"
+
+msgid "vim error"
+msgstr "помилка Vim"
+
+msgid "cannot create buffer/window command: object is being deleted"
+msgstr "не вдалоÑÑ Ñтворити команду вікна/буфера: об'єкт знищуєтьÑÑ"
+
+msgid ""
+"cannot register callback command: buffer/window is already being deleted"
+msgstr "Ðе вдалоÑÑ Ð·Ð°Ñ€ÐµÑ”Ñтрувати подію: буфер/вікно уже знищуєтьÑÑ"
+
+msgid ""
+"E280: TCL FATAL ERROR: reflist corrupt!? Please report this to vim-dev@vim."
+"org"
+msgstr ""
+"E280: ФÐТÐЛЬÐРПОМИЛКРTCL: можливо пошкоджено ÑпиÑок поÑилань!? Будь лаÑка, "
+"повідомте у vim-dev@vim.org"
+
+msgid "cannot register callback command: buffer/window reference not found"
+msgstr ""
+"Ðе вдалоÑÑ Ð·Ð°Ñ€ÐµÑ”Ñтрувати команду події: поÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð½Ð° буфер/вікно не знайдено"
+
+msgid ""
+"E571: Sorry, this command is disabled: the Tcl library could not be loaded."
+msgstr ""
+"E571: Вибачте, Ñ†Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð° вимкнена, бібліотека Tcl не може бути завантажена."
+
+#, c-format
+msgid "E572: exit code %d"
+msgstr "E572: Код виходу %d"
+
+msgid "cannot get line"
+msgstr "не вдалоÑÑ Ð´Ñ–Ñтати Ñ€Ñдок"
+
+msgid "Unable to register a command server name"
+msgstr "Ðе вдалоÑÑ Ð·Ð°Ñ€ÐµÑ”Ñтрувати назву Ñервера команд"
+
+msgid "E248: Failed to send command to the destination program"
+msgstr "E248: Ðе вдалоÑÑ Ð²Ñ–Ð´Ñ–Ñлати команду до програми-цілі"
+
+#, c-format
+msgid "E573: Invalid server id used: %s"
+msgstr "E573: ВикориÑтано некоректний ідентифікатор Ñервера: %s"
+
+msgid "E251: VIM instance registry property is badly formed. Deleted!"
+msgstr "E251: Реквізит реєÑтру зразку VIM Ñформований неправильно. Знищено!"
+
+#, c-format
+msgid "E938: Duplicate key in JSON: \"%s\""
+msgstr "E938: ÐŸÐ¾Ð²Ñ‚Ð¾Ñ€ÐµÐ½Ð½Ñ ÐºÐ»ÑŽÑ‡Ð° в JSON: «%s»"
+
+# msgstr "E404: "
+#, c-format
+msgid "E696: Missing comma in List: %s"
+msgstr "E696: Бракує коми у ÑпиÑку: %s"
+
+#, c-format
+msgid "E697: Missing end of List ']': %s"
+msgstr "E697: Ðемає кінцівки ÑпиÑку ']': %s"
+
+msgid "Unknown option argument"
+msgstr "Ðевідомий аргумент опції"
+
+msgid "Too many edit arguments"
+msgstr "Забагато аргументів"
+
+msgid "Argument missing after"
+msgstr "Пропущено аргумент піÑлÑ"
+
+msgid "Garbage after option argument"
+msgstr "Ð¡Ð¼Ñ–Ñ‚Ñ‚Ñ Ð¿Ñ–ÑÐ»Ñ Ð°Ñ€Ð³ÑƒÐ¼ÐµÐ½Ñ‚Ñƒ опції"
+
+msgid "Too many \"+command\", \"-c command\" or \"--cmd command\" arguments"
+msgstr "Забагато аргументів у «+команда», «-c команда» або «--cmd команда»"
+
+# msgstr "E14: "
+msgid "Invalid argument for"
+msgstr "Ðеправильний аргумент у"
+
+#, c-format
+msgid "%d files to edit\n"
+msgstr "%d файли(ів)\n"
+
+msgid "netbeans is not supported with this GUI\n"
+msgstr "netbeans не підтримуєтьÑÑ Ð· цим GUI\n"
+
+msgid "'-nb' cannot be used: not enabled at compile time\n"
+msgstr "Ðе можна викориÑтати '-nb': не дозволено під Ñ‡Ð°Ñ ÐºÐ¾Ð¼Ð¿Ñ–Ð»Ñції\n"
+
+msgid "This Vim was not compiled with the diff feature."
+msgstr "Ð¦Ñ Ð²ÐµÑ€ÑÑ–Ñ Vim не була Ñкомпільована з підтримкою порівнÑннÑ."
+
+msgid "Attempt to open script file again: \""
+msgstr "Спроба повторно відкрити Ñкрипт: \""
+
+msgid "Cannot open for reading: \""
+msgstr "Ðе вдалоÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸: \""
+
+msgid "Cannot open for script output: \""
+msgstr "Ðе вдалоÑÑ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸ Ñк вихідний файл: \""
+
+msgid "Vim: Error: Failure to start gvim from NetBeans\n"
+msgstr "Vim: Помилка: Ðе вдалоÑÑ Ð·Ð°Ð¿ÑƒÑтити gvim Ð´Ð»Ñ NetBeans\n"
+
+msgid "Vim: Error: This version of Vim does not run in a Cygwin terminal\n"
+msgstr "Vim: Помилка: Ð¦Ñ Ð²ÐµÑ€ÑÑ–Ñ Vim не працює у терміналі Cygwin\n"
+
+msgid "Vim: Warning: Output is not to a terminal\n"
+msgstr "Vim: ЗаÑтереженнÑ: Вивід не у термінал\n"
+
+msgid "Vim: Warning: Input is not from a terminal\n"
+msgstr "Vim: ЗаÑтереженнÑ: Ð£Ð²ÐµÐ´ÐµÐ½Ð½Ñ Ð½Ðµ з терміналу\n"
+
+msgid "pre-vimrc command line"
+msgstr "команди перед vimrc"
+
+#, c-format
+msgid "E282: Cannot read from \"%s\""
+msgstr "E282: Ðе вдалоÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ з «%s»"
+
+# msgstr "E282: "
+msgid ""
+"\n"
+"More info with: \"vim -h\"\n"
+msgstr ""
+"\n"
+"ДізнайтеÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ: «vim -h»\n"
+
+msgid "[file ..] edit specified file(s)"
+msgstr "[файл ..] редагувати вказані файли"
+
+msgid "- read text from stdin"
+msgstr "- читати текÑÑ‚ з stdin"
+
+msgid "-t tag edit file where tag is defined"
+msgstr "-t помітка перейти до мітки"
+
+msgid "-q [errorfile] edit file with first error"
+msgstr "-q [файл] перейти до першої помилки"
+
+msgid ""
+"\n"
+"\n"
+"Usage:"
+msgstr ""
+"\n"
+"\n"
+"Вжиток:"
+
+msgid " vim [arguments] "
+msgstr " vim [аргументи] "
+
+msgid ""
+"\n"
+" or:"
+msgstr ""
+"\n"
+" або:"
+
+msgid ""
+"\n"
+"Where case is ignored prepend / to make flag upper case"
+msgstr ""
+"\n"
+"Якщо регіÑÑ‚Ñ€ ігноруєтьÑÑ, додайте / Ñпереду щоб прапорець був у верхньому "
+"регіÑтрі."
+
+msgid ""
+"\n"
+"\n"
+"Arguments:\n"
+msgstr ""
+"\n"
+"\n"
+"Ðргументи:\n"
+
+msgid "--\t\t\tOnly file names after this"
+msgstr "--\t\t\tЛише назви файлів піÑÐ»Ñ Ñ†ÑŒÐ¾Ð³Ð¾"
+
+msgid "--literal\t\tDon't expand wildcards"
+msgstr "--literal\t\tÐе розкривати шаблони"
+
+msgid "-register\t\tRegister this gvim for OLE"
+msgstr "-register\t\tЗареєÑтрувати цей gvim Ð´Ð»Ñ OLE"
+
+msgid "-unregister\t\tUnregister gvim for OLE"
+msgstr "-unregister\t\tСкаÑувати реєÑтрацію цього gvim Ð´Ð»Ñ OLE"
+
+msgid "-g\t\t\tRun using GUI (like \"gvim\")"
+msgstr "-g\t\t\tЗапуÑтити GUI (ніби «gvim»)"
+
+msgid "-f or --nofork\tForeground: Don't fork when starting GUI"
+msgstr "-f чи --nofork\tПередній план: тримати термінал піÑÐ»Ñ Ð·Ð°Ð¿ÑƒÑку GUI"
+
+msgid "-v\t\t\tVi mode (like \"vi\")"
+msgstr "-v\t\t\tРежим Vi (ніби «vi»)"
+
+msgid "-e\t\t\tEx mode (like \"ex\")"
+msgstr "-e\t\t\tРежим Ex (ніби «ex»)"
+
+msgid "-E\t\t\tImproved Ex mode"
+msgstr "-E\t\t\tПокращений режим Ex"
+
+msgid "-s\t\t\tSilent (batch) mode (only for \"ex\")"
+msgstr "-s\t\t\tМовчазний (пакетний) режим (лише Ð´Ð»Ñ Â«ex»)"
+
+msgid "-d\t\t\tDiff mode (like \"vimdiff\")"
+msgstr "-d\t\t\tРежим порівнÑÐ½Ð½Ñ (ніби «vimdiff»)"
+
+msgid "-y\t\t\tEasy mode (like \"evim\", modeless)"
+msgstr "-y\t\t\tПроÑтий режим (ніби «evim», без режимів)"
+
+msgid "-R\t\t\tReadonly mode (like \"view\")"
+msgstr "-R\t\t\tРежим переглÑду (ніби «view»)"
+
+msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
+msgstr "-Z\t\t\tОбмежений режим (ніби «rvim»)"
+
+msgid "-m\t\t\tModifications (writing files) not allowed"
+msgstr "-m\t\t\tЗміни (Ð·Ð°Ð¿Ð¸Ñ Ñ„Ð°Ð¹Ð»Ñ–Ð²) не дозволено"
+
+msgid "-M\t\t\tModifications in text not allowed"
+msgstr "-M\t\t\tЗміни в текÑÑ‚Ñ– файлів не дозволено"
+
+msgid "-b\t\t\tBinary mode"
+msgstr "-b\t\t\tДвійковий режим"
+
+msgid "-l\t\t\tLisp mode"
+msgstr "-l\t\t\tРежим lisp"
+
+msgid "-C\t\t\tCompatible with Vi: 'compatible'"
+msgstr "-C\t\t\tСуміÑний з Vi режим: 'compatible'"
+
+msgid "-N\t\t\tNot fully Vi compatible: 'nocompatible'"
+msgstr "-N\t\t\tÐе зовÑім ÑуміÑний з Vi режим: 'nocompatible'"
+
+msgid "-V[N][fname]\t\tBe verbose [level N] [log messages to fname]"
+msgstr "-V[N][файл]\t\tБільше повідомлень [рівень N] [файл журн. повідомлень]"
+
+msgid "-D\t\t\tDebugging mode"
+msgstr "-D\t\t\tРежим налагодженнÑ"
+
+msgid "-n\t\t\tNo swap file, use memory only"
+msgstr "-n\t\t\tÐе викориÑтовувати файл обміну, тримати уÑе в пам'ÑÑ‚Ñ–"
+
+msgid "-r\t\t\tList swap files and exit"
+msgstr "-r\t\t\tПоказати файли обміну і вийти"
+
+msgid "-r (with file name)\tRecover crashed session"
+msgstr "-r (назва файлу)\tВідновити аварійно закінчений ÑеанÑ"
+
+msgid "-L\t\t\tSame as -r"
+msgstr "-L\t\t\tТе Ñаме, що й -r"
+
+msgid "-f\t\t\tDon't use newcli to open window"
+msgstr "-f\t\t\tÐе викориÑтовувати newcli Ð´Ð»Ñ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ñ‚Ñ Ð²Ñ–ÐºÐ½Ð°"
+
+msgid "-dev <device>\t\tUse <device> for I/O"
+msgstr "-dev <приÑтрій>\t\t\tВикориÑтовувати <приÑтрій> Ð´Ð»Ñ Ð²Ð²Ð¾Ð´Ñƒ/виводу"
+
+msgid "-A\t\t\tStart in Arabic mode"
+msgstr "-A\t\t\tЗапуÑтити в режимі арабÑької мови"
+
+msgid "-H\t\t\tStart in Hebrew mode"
+msgstr "-H\t\t\tЗапуÑтити в режимі івриту"
+
+msgid "-F\t\t\tStart in Farsi mode"
+msgstr "-F\t\t\tЗапуÑтити в режимі перÑької мови"
+
+msgid "-T <terminal>\tSet terminal type to <terminal>"
+msgstr "-T <термінал>\tÐ’Ñтановити тип терміналу у <термінал>"
+
+msgid "--not-a-term\t\tSkip warning for input/output not being a terminal"
+msgstr "--not-a-term\t\tПропуÑтити Ð¿Ð¾Ð¿ÐµÑ€ÐµÐ´Ð¶ÐµÐ½Ð½Ñ Ð²Ð²Ð¾Ð´Ñƒ/виводу не в термінал"
+
+msgid "--ttyfail\t\tExit if input or output is not a terminal"
+msgstr "--ttyfail\t\tВийти, Ñкщо введеннÑ/Ð²Ð¸Ð²ÐµÐ´ÐµÐ½Ð½Ñ Ð½Ðµ в термінал"
+
+msgid "-u <vimrc>\t\tUse <vimrc> instead of any .vimrc"
+msgstr "-u <vimrc>\t\tВикориÑтати поданий файл заміÑÑ‚ÑŒ .vimrc"
+
+msgid "-U <gvimrc>\t\tUse <gvimrc> instead of any .gvimrc"
+msgstr "-u <gvimrc>\t\tВикориÑтати поданий файл заміÑÑ‚ÑŒ .gvimrc"
+
+msgid "--noplugin\t\tDon't load plugin scripts"
+msgstr "--noplugin\t\tÐе вантажити Ñкрипти доповненнÑ"
+
+msgid "-p[N]\t\tOpen N tab pages (default: one for each file)"
+msgstr "-p[N]\t\tВідкрити N вкладок (або по одній Ð´Ð»Ñ ÐºÐ¾Ð¶Ð½Ð¾Ð³Ð¾ файлу)"
+
+msgid "-o[N]\t\tOpen N windows (default: one for each file)"
+msgstr "-o[N]\t\tВідкрити N вікон (або по одному Ð´Ð»Ñ ÐºÐ¾Ð¶Ð½Ð¾Ð³Ð¾ файлу)"
+
+msgid "-O[N]\t\tLike -o but split vertically"
+msgstr "-O[N]\t\tÐіби -o, але поділити вікна вертикально"
+
+msgid "+\t\t\tStart at end of file"
+msgstr "+\t\t\tРозпочати в кінці файлу"
+
+msgid "+<lnum>\t\tStart at line <lnum>"
+msgstr "+<Ñ€Ñдок>\t\tРозпочати у вказаному <Ñ€Ñдку>"
+
+msgid "--cmd <command>\tExecute <command> before loading any vimrc file"
+msgstr "--cmd <команда>\tВиконати <команду> перед завантаженнÑм vimrc"
+
+msgid "-c <command>\t\tExecute <command> after loading the first file"
+msgstr "-c <команда>\t\tВиконати <команду> піÑÐ»Ñ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð¿ÐµÑ€ÑˆÐ¾Ð³Ð¾ файлу"
+
+msgid "-S <session>\t\tSource file <session> after loading the first file"
+msgstr "-S <ÑеанÑ>\t\tВиконати поданий файл піÑÐ»Ñ Ð¿ÐµÑ€ÑˆÐ¾Ð³Ð¾ завантаженого файлу"
+
+msgid "-s <scriptin>\tRead Normal mode commands from file <scriptin>"
+msgstr "-s <Ñкрипт>\t\tЗчитати команди нормального режиму з файлу <Ñкрипт>"
+
+msgid "-w <scriptout>\tAppend all typed commands to file <scriptout>"
+msgstr "-w <Ñкрипт>\t\tДопиÑати уÑÑ– набрані команди до файлу <Ñкрипт>"
+
+msgid "-W <scriptout>\tWrite all typed commands to file <scriptout>"
+msgstr "-w <Ñкрипт>\t\tЗапиÑати уÑÑ– набрані команди у файл <Ñкрипт>"
+
+msgid "-x\t\t\tEdit encrypted files"
+msgstr "-x\t\t\tРедагувати зашифровані файли"
+
+msgid "-display <display>\tConnect vim to this particular X-server"
+msgstr "-display <диÑплей>\tПід'єднати vim до заданого диÑплею Ñервера X"
+
+msgid "-X\t\t\tDo not connect to X server"
+msgstr "-X\t\t\tÐе з'єднуватиÑÑ Ð· X Ñервером"
+
+msgid "--remote <files>\tEdit <files> in a Vim server if possible"
+msgstr "--remote <файли>\tРедагувати <файли> на Ñервері Vim, Ñкщо це можливо"
+
+msgid "--remote-silent <files> Same, don't complain if there is no server"
+msgstr ""
+"--remote-silent <файли> Те Ñаме, тільки не ÑкаржитиÑÑ Ð½Ð° відÑутніÑÑ‚ÑŒ Ñервера"
+
+msgid ""
+"--remote-wait <files> As --remote but wait for files to have been edited"
+msgstr ""
+"--remote-wait <файли> ..., але зачекати поки уÑÑ– файли будуть відредаговані"
+
+msgid ""
+"--remote-wait-silent <files> Same, don't complain if there is no server"
+msgstr ""
+"--remote-wait-silent <файли> Те Ñаме, тільки не ÑкаржитиÑÑ, Ñкщо Ñервера "
+"немає"
+
+msgid ""
+"--remote-tab[-wait][-silent] <files> As --remote but use tab page per file"
+msgstr ""
+"--remote-tab[-wait][-silent] <файли> Так Ñамо, Ñк --remote, але по вкладці "
+"на файл"
+
+msgid "--remote-send <keys>\tSend <keys> to a Vim server and exit"
+msgstr "--remote-send <Ñимволи> ВідіÑлати <Ñимволи> Ñерверу Ñ– завершити роботу"
+
+msgid "--remote-expr <expr>\tEvaluate <expr> in a Vim server and print result"
+msgstr ""
+"--remote-expr <вираз> Виконати <вираз> у Ñервері Vim Ñ– надрукувати результат"
+
+msgid "--serverlist\t\tList available Vim server names and exit"
+msgstr ""
+"--serverlist\t\tПоказати ÑпиÑок наÑвних Ñерверів Vim Ñ– завершити роботу"
+
+msgid "--servername <name>\tSend to/become the Vim server <name>"
+msgstr "--servername <назва>\tÐадіÑлати до/Ñтати Vim Ñервером з <назвою>"
+
+msgid "--startuptime <file>\tWrite startup timing messages to <file>"
+msgstr ""
+"--startuptime <файл>\tЗапиÑати запуÑкні Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð· чаÑовими відмітками "
+"до <файлу>"
+
+msgid "-i <viminfo>\t\tUse <viminfo> instead of .viminfo"
+msgstr "-i <viminfo>\t\tВикориÑтати <viminfo> заміÑÑ‚ÑŒ .viminfo"
+
+msgid "--clean\t\t'nocompatible', Vim defaults, no plugins, no viminfo"
+msgstr "--clean\t\t'nocompatible', Vim початково, без розширень, без viminfo"
+
+msgid "-h or --help\tPrint Help (this message) and exit"
+msgstr "-h чи --help\tÐадрукувати це Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ñ– вийти"
+
+msgid "--version\t\tPrint version information and exit"
+msgstr "--version\t\tÐадрукувати інформацію про верÑÑ–ÑŽ програми Ñ– вийти"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Motif version):\n"
+msgstr ""
+"\n"
+"Ðргументи Ð´Ð»Ñ gvim (верÑÑ–Ñ Motif)\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (neXtaw version):\n"
+msgstr ""
+"\n"
+"Ðргументи Ð´Ð»Ñ gvim (верÑÑ–Ñ neXtaw):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Athena version):\n"
+msgstr ""
+"\n"
+"Ðргументи Ð´Ð»Ñ gvim (верÑÑ–Ñ Athena)\n"
+
+msgid "-display <display>\tRun vim on <display>"
+msgstr "-display <диÑплей>\tВиконати vim на заданому <диÑплеї>"
+
+msgid "-iconic\t\tStart vim iconified"
+msgstr "-iconic\t\tЗапуÑтити Vim Ñ– згорнути його вікно"
+
+msgid "-background <color>\tUse <color> for the background (also: -bg)"
+msgstr "-background <колір>\tВикориÑтати <колір> Ð´Ð»Ñ Ñ„Ð¾Ð½Ñƒ (також: -bg)"
+
+msgid "-foreground <color>\tUse <color> for normal text (also: -fg)"
+msgstr ""
+"-foreground <колір>\tВикориÑтати <колір> Ð´Ð»Ñ Ð·Ð²Ð¸Ñ‡Ð°Ð¹Ð½Ð¾Ð³Ð¾ текÑту (також: -fg)"
+
+msgid "-font <font>\t\tUse <font> for normal text (also: -fn)"
+msgstr "-font <шрифт>\tВикориÑтати <шрифт> Ð´Ð»Ñ Ð·Ð²Ð¸Ñ‡Ð°Ð¹Ð½Ð¾Ð³Ð¾ текÑту (також: -fn)"
+
+msgid "-boldfont <font>\tUse <font> for bold text"
+msgstr "-boldfont <шрифт>\tВикориÑтати <шрифт> Ð´Ð»Ñ Ð¶Ð¸Ñ€Ð½Ð¾Ð³Ð¾ текÑту"
+
+msgid "-italicfont <font>\tUse <font> for italic text"
+msgstr "-italicfont <шрифт>\tВикориÑтати <шрифт> Ð´Ð»Ñ Ð¿Ð¾Ñ…Ð¸Ð»Ð¾Ð³Ð¾ текÑту"
+
+msgid "-geometry <geom>\tUse <geom> for initial geometry (also: -geom)"
+msgstr "-geometry <геом>\tЗадати розміри й Ð¿Ð¾Ð»Ð¾Ð¶ÐµÐ½Ð½Ñ (також: -geom)"
+
+msgid "-borderwidth <width>\tUse a border width of <width> (also: -bw)"
+msgstr "-borderwidth <товщ>\tÐ’Ñтановити товщину меж <товщ> (також: -bw)"
+
+msgid "-scrollbarwidth <width> Use a scrollbar width of <width> (also: -sw)"
+msgstr "-scrollbarwidth <товщ> Ð’Ñтановити товщину лінійки зÑуву (також: -sw)"
+
+msgid "-menuheight <height>\tUse a menu bar height of <height> (also: -mh)"
+msgstr "-menuheight <виÑота>\tÐ’Ñтановити виÑоту меню <виÑота> (також: -mh)"
+
+msgid "-reverse\t\tUse reverse video (also: -rv)"
+msgstr "-reverse\t\tОбернути кольори (також: -rv)"
+
+msgid "+reverse\t\tDon't use reverse video (also: +rv)"
+msgstr "+reverse\t\tÐе обертати кольори (також: +rv)"
+
+msgid "-xrm <resource>\tSet the specified resource"
+msgstr "-xrm <реÑурÑ>\t\tÐ’Ñтановити зазначений реÑурÑ"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (GTK+ version):\n"
+msgstr ""
+"\n"
+"Ðргументи gvim (верÑÑ–Ñ GTK+)\n"
+
+msgid "-display <display>\tRun vim on <display> (also: --display)"
+msgstr "-display <диÑплей>\tВиконати vim на <диÑплеї> (також: --display)"
+
+msgid "--role <role>\tSet a unique role to identify the main window"
+msgstr ""
+"--role <роль>\tÐ’Ñтановити унікальну роль Ð´Ð»Ñ Ñ–Ð´ÐµÐ½Ñ‚Ð¸Ñ„Ñ–ÐºÐ°Ñ†Ñ–Ñ— головного вікна"
+
+msgid "--socketid <xid>\tOpen Vim inside another GTK widget"
+msgstr "--socketid <xid>\tВідкрити Vim в іншому елементі інтерфейÑу GTK"
+
+msgid "--echo-wid\t\tMake gvim echo the Window ID on stdout"
+msgstr "--echo-wid\t\tХай gvim надрукує ідентифікатор вікна на stdout"
+
+msgid "-P <parent title>\tOpen Vim inside parent application"
+msgstr "-P <заголовок батька>\tВідкрити Vim вÑередині батьківÑького вікна"
+
+msgid "--windowid <HWND>\tOpen Vim inside another win32 widget"
+msgstr "--windowid <HWND>\tВідкрити Vim вÑередині іншого елементу win32"
+
+msgid "No display"
+msgstr "Ðемає диÑплею"
+
+msgid ": Send failed.\n"
+msgstr ": Ðе вдалоÑÑ Ð²Ñ–Ð´Ñ–Ñлати.\n"
+
+msgid ": Send failed. Trying to execute locally\n"
+msgstr ": Ðе вдалоÑÑ Ð²Ñ–Ð´Ñ–Ñлати. Спроба виконати на міÑці\n"
+
+#, c-format
+msgid "%d of %d edited"
+msgstr "відредаговано %d з %d"
+
+msgid "No display: Send expression failed.\n"
+msgstr "Ðемає диÑплею: ВідіÑлати вираз не вдалоÑÑ.\n"
+
+msgid ": Send expression failed.\n"
+msgstr ": ВідіÑлати вираз не вдалоÑÑ.\n"
+
+msgid "No marks set"
+msgstr "Ðе вÑтановлено жодної помітки"
+
+#, c-format
+msgid "E283: No marks matching \"%s\""
+msgstr "E283: Помітку «%s» не знайдено"
+
+# msgstr "E283: "
+msgid ""
+"\n"
+"mark line col file/text"
+msgstr ""
+"\n"
+"пом. Ñ€Ñд. кол. файл/текÑÑ‚"
+
+msgid ""
+"\n"
+" jump line col file/text"
+msgstr ""
+"\n"
+" точка Ñ€Ñд. Ñтовп. файл/текÑÑ‚"
+
+# msgstr "E283: "
+msgid ""
+"\n"
+"change line col text"
+msgstr ""
+"\n"
+"змінити Ñ€Ñд. Ñтовп. текÑÑ‚"
+
+# TODO
+msgid ""
+"\n"
+"# File marks:\n"
+msgstr ""
+"\n"
+"# Помітки:\n"
+
+msgid ""
+"\n"
+"# Jumplist (newest first):\n"
+msgstr ""
+"\n"
+"# СпиÑок переходів (від найновіших):\n"
+
+# TODO
+msgid ""
+"\n"
+"# History of marks within files (newest to oldest):\n"
+msgstr ""
+"\n"
+"# Попередні помітки в файлах (від найновіших):\n"
+
+msgid "Missing '>'"
+msgstr "Пропущено '>'"
+
+msgid "E543: Not a valid codepage"
+msgstr "E543: Ðекоректна кодова Ñторінка"
+
+msgid "E284: Cannot set IC values"
+msgstr "E284: Ðе вдалоÑÑ Ð²Ñтановити Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ ÐºÐ¾Ð½Ñ‚ÐµÐºÑту вводу"
+
+msgid "E285: Failed to create input context"
+msgstr "E285: Ðе вдалоÑÑ Ñтворити контекÑÑ‚ вводу"
+
+msgid "E286: Failed to open input method"
+msgstr "E286: Ðе вдалоÑÑ Ñтворити метод вводу"
+
+# msgstr "E286: "
+msgid "E287: Warning: Could not set destroy callback to IM"
+msgstr ""
+"E287: ЗаÑтереженнÑ: Ðе вдалоÑÑ Ð²Ñтановити в методі вводу подію знищеннÑ"
+
+# msgstr "E287: "
+msgid "E288: input method doesn't support any style"
+msgstr "E288: Метод вводу не підтримує Ñтилі"
+
+# msgstr "E288: "
+msgid "E289: input method doesn't support my preedit type"
+msgstr "E289: Метод вводу не підтримує відредаговані типи"
+
+# msgstr "E292: "
+msgid "E293: block was not locked"
+msgstr "E293: Блок не було зафікÑовано"
+
+# msgstr "E293: "
+msgid "E294: Seek error in swap file read"
+msgstr "E294: Помилка зміни позиції у файлі обміну"
+
+msgid "E295: Read error in swap file"
+msgstr "E295: Помилка Ð·Ñ‡Ð¸Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ñ„Ð°Ð¹Ð»Ñƒ обміну"
+
+msgid "E296: Seek error in swap file write"
+msgstr "E296: Помилка зміни позиції під Ñ‡Ð°Ñ Ð·Ð°Ð¿Ð¸Ñу у файл обміну"
+
+msgid "E297: Write error in swap file"
+msgstr "E297: Помилка запиÑу файлу обміну"
+
+msgid "E300: Swap file already exists (symlink attack?)"
+msgstr "E300: Файл обміну вже Ñ–Ñнує (атака Ñимвольним поÑиланнÑм?)"
+
+msgid "E298: Didn't get block nr 0?"
+msgstr "E298: Ðемає блоку 0?"
+
+msgid "E298: Didn't get block nr 1?"
+msgstr "E298: Ðемає блоку 1?"
+
+# msgstr "E298: "
+msgid "E298: Didn't get block nr 2?"
+msgstr "E298: Ðемає блоку 2?"
+
+msgid "E843: Error while updating swap file crypt"
+msgstr "E843: Помилка Ð¿Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ ÑˆÐ¸Ñ„Ñ€ÑƒÐ²Ð°Ð½Ð½Ñ Ñ„Ð°Ð¹Ð»Ñƒ обміну"
+
+msgid "E301: Oops, lost the swap file!!!"
+msgstr "E301: Ой, втрачено файл обміну!!!"
+
+# msgstr "E301: "
+msgid "E302: Could not rename swap file"
+msgstr "E302: Ðе вдалоÑÑ Ð¿ÐµÑ€ÐµÐ¹Ð¼ÐµÐ½ÑƒÐ²Ð°Ñ‚Ð¸ файлу обміну"
+
+# msgstr "E302: "
+#, c-format
+msgid "E303: Unable to open swap file for \"%s\", recovery impossible"
+msgstr "E303: Ðе вдалоÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ файл обміну Ð´Ð»Ñ Â«%s», Ð²Ñ–Ð´Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð½ÐµÐ¼Ð¾Ð¶Ð»Ð¸Ð²Ðµ"
+
+msgid "E304: ml_upd_block0(): Didn't get block 0??"
+msgstr "E304: ml_upd_block0(): Ðемає блоку 0??"
+
+#, c-format
+msgid "E305: No swap file found for %s"
+msgstr "E305: Ðе знайдено файлу обміну Ð´Ð»Ñ %s"
+
+# msgstr "E305: "
+msgid "Enter number of swap file to use (0 to quit): "
+msgstr "Введіть номер файлу обміну, котрий викориÑтати, (0 Ð´Ð»Ñ Ð²Ð¸Ñ…Ð¾Ð´Ñƒ):"
+
+#, c-format
+msgid "E306: Cannot open %s"
+msgstr "E306: Ðе вдалоÑÑ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸ %s"
+
+msgid "Unable to read block 0 from "
+msgstr "Ðе вдалоÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ блок 0 з "
+
+msgid ""
+"\n"
+"Maybe no changes were made or Vim did not update the swap file."
+msgstr ""
+"\n"
+"Ðапевно, змін не було, або Vim не поновив файл обміну."
+
+msgid " cannot be used with this version of Vim.\n"
+msgstr " не можна викориÑтати з цією верÑією Vim.\n"
+
+msgid "Use Vim version 3.0.\n"
+msgstr "Знайдіть Vim 3.0\n"
+
+#, c-format
+msgid "E307: %s does not look like a Vim swap file"
+msgstr "E307: %s не Ñхоже на файл обміну Vim"
+
+msgid " cannot be used on this computer.\n"
+msgstr " не можна викориÑтати на цьому комп'ютері.\n"
+
+msgid "The file was created on "
+msgstr "Файл було Ñтворено на "
+
+msgid ""
+",\n"
+"or the file has been damaged."
+msgstr ""
+",\n"
+"або файл було пошкоджено."
+
+#, c-format
+msgid ""
+"E833: %s is encrypted and this version of Vim does not support encryption"
+msgstr "E833: %s зашифровано, а Ñ†Ñ Ð²ÐµÑ€ÑÑ–Ñ Vim не підтримує шифруваннÑ"
+
+msgid " has been damaged (page size is smaller than minimum value).\n"
+msgstr " пошкоджений (розмір Ñторінки менший мінімального значеннÑ).\n"
+
+#, c-format
+msgid "Using swap file \"%s\""
+msgstr "ВикориÑтовуєтьÑÑ Ñ„Ð°Ð¹Ð» обміну «%s»"
+
+#, c-format
+msgid "Original file \"%s\""
+msgstr "Початковий файл «%s»"
+
+msgid "E308: Warning: Original file may have been changed"
+msgstr "E308: ЗаÑтереженнÑ: Можливо, початковий файл було змінено"
+
+#, c-format
+msgid "Swap file is encrypted: \"%s\""
+msgstr "Файл обміну зашифрований: «%s»"
+
+msgid ""
+"\n"
+"If you entered a new crypt key but did not write the text file,"
+msgstr ""
+"\n"
+"Якщо ви задали новий ключ шифру, але не запиÑали текÑтовий файл,"
+
+msgid ""
+"\n"
+"enter the new crypt key."
+msgstr ""
+"\n"
+"введіть новий ключ шифру."
+
+msgid ""
+"\n"
+"If you wrote the text file after changing the crypt key press enter"
+msgstr ""
+"\n"
+"Якщо ви запиÑали текÑтовий файл піÑÐ»Ñ Ð·Ð¼Ñ–Ð½Ð¸ ключа шифру, натиÑніть enter"
+
+msgid ""
+"\n"
+"to use the same key for text file and swap file"
+msgstr ""
+"\n"
+"щоб викориÑтати однаковий ключ Ð´Ð»Ñ Ñ‚ÐµÐºÑтового файлу та файлу обміну"
+
+# msgstr "E308: "
+#, c-format
+msgid "E309: Unable to read block 1 from %s"
+msgstr "E309: Ðе вдалоÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ блок 1 з %s"
+
+# msgstr "E309: "
+msgid "???MANY LINES MISSING"
+msgstr "??? БРÐКУЄ БÐГÐТЬОХ РЯДКІВ"
+
+msgid "???LINE COUNT WRONG"
+msgstr "??? ÐЕПРÐВИЛЬÐРКІЛЬКІСТЬ РЯДКІВ"
+
+msgid "???EMPTY BLOCK"
+msgstr "??? ПОРОЖÐІЙ БЛОК"
+
+msgid "???LINES MISSING"
+msgstr "??? ПРОПУЩЕÐІ РЯДКИ"
+
+#, c-format
+msgid "E310: Block 1 ID wrong (%s not a .swp file?)"
+msgstr "E310: Ідентифікатор блоку 1 неправильний (%s не є файлом обміну?)"
+
+# msgstr "E310: "
+msgid "???BLOCK MISSING"
+msgstr "??? ПРОПУЩЕÐО БЛОК"
+
+msgid "??? from here until ???END lines may be messed up"
+msgstr "??? звідÑи Ñ– до `??? КІÐЕЦЬ' Ñ€Ñдки, можливо, Ñплутані"
+
+msgid "??? from here until ???END lines may have been inserted/deleted"
+msgstr "??? звідÑи Ñ– до `??? КІÐЕЦЬ' Ñ€Ñдки, можливо, були додані/знищені"
+
+msgid "???END"
+msgstr "??? КІÐЕЦЬ"
+
+msgid "E311: Recovery Interrupted"
+msgstr "E311: Ð’Ñ–Ð´Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð¿ÐµÑ€ÐµÑ€Ð²Ð°Ð½Ð¾"
+
+msgid ""
+"E312: Errors detected while recovering; look for lines starting with ???"
+msgstr ""
+"E312: Під Ñ‡Ð°Ñ Ð²Ñ–Ð´Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð·Ð½Ð°Ð¹Ð´ÐµÐ½Ð¾ помилки. ПереглÑньте Ñ€Ñдки, що "
+"починаютьÑÑ Ð· ???"
+
+msgid "See \":help E312\" for more information."
+msgstr "Див. «:help E312» Ð´Ð»Ñ ÑƒÑ‚Ð¾Ñ‡Ð½ÐµÐ½Ð½Ñ."
+
+msgid "Recovery completed. You should check if everything is OK."
+msgstr "Ð’Ñ–Ð´Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð·Ð°ÐºÑ–Ð½Ñ‡ÐµÐ½Ð¾, перевірте чи вÑе гаразд."
+
+msgid ""
+"\n"
+"(You might want to write out this file under another name\n"
+msgstr ""
+"\n"
+"(Можливо, потрібно запиÑати цей файл під іншою назвою\n"
+
+msgid "and run diff with the original file to check for changes)"
+msgstr "Ñ– запуÑтити diff з оригіналом щоб перевірити зміни)"
+
+msgid "Recovery completed. Buffer contents equals file contents."
+msgstr "Ð’Ñ–Ð´Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð·Ð°ÐºÑ–Ð½Ñ‡ÐµÐ½Ð¾. ВміÑÑ‚ буфера Ñпівпадає зі вміÑтом файлу."
+
+msgid ""
+"\n"
+"You may want to delete the .swp file now.\n"
+"\n"
+msgstr ""
+"\n"
+"Можливо, тепер ви хочете знищити файл обміну .swp.\n"
+"\n"
+
+msgid "Using crypt key from swap file for the text file.\n"
+msgstr "Ð”Ð»Ñ Ñ‚ÐµÐºÑтового файлу викориÑтовуєтьÑÑ ÐºÐ»ÑŽÑ‡ шифру з файлу обміну.\n"
+
+msgid "Swap files found:"
+msgstr "Знайдено файли обміну:"
+
+msgid " In current directory:\n"
+msgstr " В поточному каталозі:\n"
+
+msgid " Using specified name:\n"
+msgstr " ВикориÑтовуючи вказану назву:\n"
+
+msgid " In directory "
+msgstr " У каталозі "
+
+msgid " -- none --\n"
+msgstr " -- жодного --\n"
+
+msgid " owned by: "
+msgstr " влаÑник: "
+
+msgid " dated: "
+msgstr " дата: "
+
+msgid " dated: "
+msgstr " дата: "
+
+msgid " [from Vim version 3.0]"
+msgstr " [від Vim 3.0]"
+
+msgid " [does not look like a Vim swap file]"
+msgstr " [не Ñхоже на файл обміну]"
+
+msgid " file name: "
+msgstr " назва файлу: "
+
+msgid ""
+"\n"
+" modified: "
+msgstr ""
+"\n"
+" змінено: "
+
+msgid "YES"
+msgstr "ТÐК"
+
+msgid "no"
+msgstr "ні"
+
+msgid ""
+"\n"
+" user name: "
+msgstr ""
+"\n"
+" кориÑтувач: "
+
+msgid " host name: "
+msgstr " назва вузла: "
+
+msgid ""
+"\n"
+" host name: "
+msgstr ""
+"\n"
+" назва вузла: "
+
+msgid ""
+"\n"
+" process ID: "
+msgstr ""
+"\n"
+" ID процеÑу: "
+
+msgid " (still running)"
+msgstr " (виконуєтьÑÑ)"
+
+msgid ""
+"\n"
+" [not usable with this version of Vim]"
+msgstr ""
+"\n"
+" [не придатний Ð´Ð»Ñ Ñ†Ñ–Ñ”Ñ— верÑÑ–Ñ— Vim]"
+
+msgid ""
+"\n"
+" [not usable on this computer]"
+msgstr ""
+"\n"
+" [непридатний на цьому комп'ютері]"
+
+msgid " [cannot be read]"
+msgstr " [не можна прочитати]"
+
+msgid " [cannot be opened]"
+msgstr " [не можна відкрити]"
+
+msgid "E313: Cannot preserve, there is no swap file"
+msgstr "E313: Ðе вдалоÑÑ Ð·Ð°Ð³Ð¾Ñ‚Ð¾Ð²Ð¸Ñ‚Ð¸, немає файлу обміну"
+
+# msgstr "E313: "
+msgid "File preserved"
+msgstr "Файл збережено"
+
+msgid "E314: Preserve failed"
+msgstr "E314: Ð—Ð±ÐµÑ€ÐµÐ¶ÐµÐ½Ð½Ñ Ð½Ðµ вдалоÑÑ"
+
+# msgstr "E314: "
+#, c-format
+msgid "E315: ml_get: invalid lnum: %ld"
+msgstr "E315: ml_get: неправильний lnum: %ld"
+
+# msgstr "E315: "
+#, c-format
+msgid "E316: ml_get: cannot find line %ld"
+msgstr "E316: ml_get: не знайшов Ñ€Ñдок %ld"
+
+# msgstr "E316: "
+msgid "E317: pointer block id wrong 3"
+msgstr "E317: Вказівник блоку помилковий 3"
+
+# msgstr "E317: "
+msgid "stack_idx should be 0"
+msgstr "stack_idx має бути рівним 0"
+
+msgid "E318: Updated too many blocks?"
+msgstr "E318: Поновлено забагато блоків?"
+
+msgid "E317: pointer block id wrong 4"
+msgstr "E317: Вказівник блоку помилковий 4"
+
+msgid "deleted block 1?"
+msgstr "блок 1 знищено?"
+
+#, c-format
+msgid "E320: Cannot find line %ld"
+msgstr "E320: Ðе вдалоÑÑ Ð·Ð½Ð°Ð¹Ñ‚Ð¸ Ñ€Ñдок %ld"
+
+msgid "E317: pointer block id wrong"
+msgstr "E317: Вказівник блоку помилковий"
+
+# msgstr "E317: "
+msgid "pe_line_count is zero"
+msgstr "pe_line_count дорівнює 0"
+
+#, c-format
+msgid "E322: line number out of range: %ld past the end"
+msgstr "E322: Ðомер Ñ€Ñдка вийшов за межі: %ld за кінцем"
+
+# msgstr "E322: "
+#, c-format
+msgid "E323: line count wrong in block %ld"
+msgstr "E323: КількіÑÑ‚ÑŒ Ñ€Ñдків у блоці %ld"
+
+# msgstr "E323: "
+msgid "Stack size increases"
+msgstr "Розмір Ñтеку збільшуєтьÑÑ"
+
+msgid "E317: pointer block id wrong 2"
+msgstr "E317: Вказівник блоку помилковий 2"
+
+#, c-format
+msgid "E773: Symlink loop for \"%s\""
+msgstr "E773: Циклічні Ñимвольні поÑÐ¸Ð»Ð°Ð½Ð½Ñ Â«%s»"
+
+# msgstr "E317: "
+msgid "E325: ATTENTION"
+msgstr "E325: УВÐГÐ"
+
+msgid ""
+"\n"
+"Found a swap file by the name \""
+msgstr ""
+"\n"
+"Знайдено файл обміну з назвою \""
+
+msgid "While opening file \""
+msgstr "При відкритті файлу \""
+
+msgid " NEWER than swap file!\n"
+msgstr " ÐОВІШИЙ за файл обміну!\n"
+
+msgid ""
+"\n"
+"(1) Another program may be editing the same file. If this is the case,\n"
+" be careful not to end up with two different instances of the same\n"
+" file when making changes. Quit, or continue with caution.\n"
+msgstr ""
+"\n"
+"(1) Можливо, інша програма вже редагує цей Ñамий файл. Якщо це так,\n"
+" будьте обережні, щоб не залишилиÑÑ Ð´Ð²Ð° різні екземплÑри\n"
+" одного й того Ñамого файлу піÑÐ»Ñ Ð·Ð¼Ñ–Ð½. Вийдіть чи продовжуйте з "
+"обережніÑÑ‚ÑŽ.\n"
+
+msgid "(2) An edit session for this file crashed.\n"
+msgstr "(2) Ð¡ÐµÐ°Ð½Ñ Ñ€ÐµÐ´Ð°Ð³ÑƒÐ²Ð°Ð½Ð½Ñ Ñ†ÑŒÐ¾Ð³Ð¾ файлу зазнав краху.\n"
+
+msgid " If this is the case, use \":recover\" or \"vim -r "
+msgstr " Якщо це Ñправді трапилоÑÑ, Ñпробуйте «:recover» або «vim -r "
+
+msgid ""
+"\"\n"
+" to recover the changes (see \":help recovery\").\n"
+msgstr ""
+"»\n"
+" щоб відновити зміни (див. «:help recovery»).\n"
+
+msgid " If you did this already, delete the swap file \""
+msgstr " Якщо ви вже це зробили, знищіть файл обміну «"
+
+msgid ""
+"\"\n"
+" to avoid this message.\n"
+msgstr ""
+"»,\n"
+" щоб позбутиÑÑ Ñ†ÑŒÐ¾Ð³Ð¾ повідомленнÑ.\n"
+
+msgid "Swap file \""
+msgstr "Файл обміну «"
+
+msgid "\" already exists!"
+msgstr "» вже Ñ–Ñнує!"
+
+msgid "VIM - ATTENTION"
+msgstr "VIM — УВÐГÐ"
+
+msgid "Swap file already exists!"
+msgstr "Файл обміну вже Ñ–Ñнує!"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"&O:Відкрити лише Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ\n"
+"&E:Ð’Ñе одно редагувати\n"
+"&R:Відновити\n"
+"&Q:Вийти\n"
+"&A:Перервати"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Delete it\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"&O:Відкрити лише Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ\n"
+"&E:УÑе одно редагувати\n"
+"&R:Відновити\n"
+"&D:Знищити його\n"
+"&Q:Вийти\n"
+"&A:Перервати"
+
+msgid "E326: Too many swap files found"
+msgstr "E326: Знайдено забагато файлів обміну"
+
+# msgstr "E326: "
+msgid "E327: Part of menu-item path is not sub-menu"
+msgstr "E327: ЧаÑтина шлÑху до елемента меню не Ñ” підменю"
+
+# msgstr "E327: "
+msgid "E328: Menu only exists in another mode"
+msgstr "E328: Меню може бути тільки в іншому режимі"
+
+# msgstr "E328: "
+#, c-format
+msgid "E329: No menu \"%s\""
+msgstr "E329: Ðемає меню «%s»"
+
+msgid "E792: Empty menu name"
+msgstr "E792: ÐŸÐ¾Ñ€Ð¾Ð¶Ð½Ñ Ð½Ð°Ð·Ð²Ð° меню"
+
+# msgstr "E329: "
+msgid "E330: Menu path must not lead to a sub-menu"
+msgstr "E330: ШлÑÑ… до меню не повинен веÑти до підменю"
+
+# msgstr "E330: "
+msgid "E331: Must not add menu items directly to menu bar"
+msgstr "E331: Ðе можна додавати елементи меню проÑто до верхнього меню"
+
+# msgstr "E331: "
+msgid "E332: Separator cannot be part of a menu path"
+msgstr "E332: Роздільник не може бути чаÑтиною шлÑху меню"
+
+# msgstr "E332: "
+msgid ""
+"\n"
+"--- Menus ---"
+msgstr ""
+"\n"
+"--- Меню ---"
+
+msgid "Tear off this menu"
+msgstr "Відірвати це меню"
+
+# msgstr "E334: "
+#, c-format
+msgid "E335: Menu not defined for %s mode"
+msgstr "E335: Ð”Ð»Ñ Ñ€ÐµÐ¶Ð¸Ð¼Ñƒ %s меню не визначено"
+
+msgid "E333: Menu path must lead to a menu item"
+msgstr "E333: ШлÑÑ… повинен веÑти до елемента меню"
+
+# msgstr "E333: "
+#, c-format
+msgid "E334: Menu not found: %s"
+msgstr "E334: Меню не знайдено: %s"
+
+# msgstr "E335: "
+msgid "E336: Menu path must lead to a sub-menu"
+msgstr "E336: ШлÑÑ… повинен веÑти до підменю"
+
+# msgstr "E336: "
+msgid "E337: Menu not found - check menu names"
+msgstr "E337: Меню не знайдено — перевірте назву"
+
+# msgstr "E337: "
+#, c-format
+msgid "Error detected while processing %s:"
+msgstr "ВиÑвлено помилку під Ñ‡Ð°Ñ Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ %s:"
+
+#, c-format
+msgid "line %4ld:"
+msgstr "Ñ€Ñдок %4ld:"
+
+#, c-format
+msgid "E354: Invalid register name: '%s'"
+msgstr "E354: Ðеправильна назва регіÑтру: '%s'"
+
+msgid "Messages maintainer: Bram Moolenaar <Bram@vim.org>"
+msgstr "УкраїнізаціÑ: Ðнатолій Сахнік <sakhnik@gmail.com>"
+
+msgid "Interrupt: "
+msgstr "Перервано: "
+
+msgid "Press ENTER or type command to continue"
+msgstr "ÐатиÑніть ENTER або введіть команду Ð´Ð»Ñ Ð¿Ñ€Ð¾Ð´Ð¾Ð²Ð¶ÐµÐ½Ð½Ñ"
+
+#, c-format
+msgid "%s line %ld"
+msgstr "%s Ñ€Ñдок %ld"
+
+msgid "-- More --"
+msgstr "-- Ще --"
+
+msgid " SPACE/d/j: screen/page/line down, b/u/k: up, q: quit "
+msgstr " ПРОБІЛ/d/j: вниз на екран/Ñторінку/Ñ€Ñдок, b/u/k: вгору, q: вийти "
+
+msgid "Question"
+msgstr "ЗапитаннÑ"
+
+msgid ""
+"&Yes\n"
+"&No"
+msgstr ""
+"&Y:Так\n"
+"&N:ÐÑ–"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"Save &All\n"
+"&Discard All\n"
+"&Cancel"
+msgstr ""
+"&Y:Так\n"
+"&N:ÐÑ–\n"
+"&A:УÑÑ–\n"
+"&D:Жодного\n"
+"&C:СкаÑувати"
+
+msgid "Select Directory dialog"
+msgstr "Вибрати каталог"
+
+msgid "Save File dialog"
+msgstr "Запам'Ñтати файл"
+
+msgid "Open File dialog"
+msgstr "Відкрити файл"
+
+msgid "E338: Sorry, no file browser in console mode"
+msgstr "E338: Вибачте, але в конÑолі немає діалогу вибору файлу"
+
+msgid "E766: Insufficient arguments for printf()"
+msgstr "E766: ÐедоÑтатньо аргументів Ð´Ð»Ñ printf()"
+
+msgid "E807: Expected Float argument for printf()"
+msgstr "E807: ОчікуєтьÑÑ Ð°Ñ€Ð³ÑƒÐ¼ÐµÐ½Ñ‚ Float Ð´Ð»Ñ printf()"
+
+msgid "E767: Too many arguments to printf()"
+msgstr "E767: Забагато аргументів Ð´Ð»Ñ printf()"
+
+# msgstr "E338: "
+msgid "W10: Warning: Changing a readonly file"
+msgstr "W10: ЗаÑтереженнÑ: ЗмінюєтьÑÑ Ñ„Ð°Ð¹Ð» призначений лише Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ"
+
+msgid "Type number and <Enter> or click with mouse (empty cancels): "
+msgstr "Ðаберіть чиÑло й <Enter> чи клацніть мишкою (порожнє ÑкаÑовує): "
+
+msgid "Type number and <Enter> (empty cancels): "
+msgstr "Ðаберіть чиÑло й <Enter> (порожнє ÑкаÑовує): "
+
+msgid "1 more line"
+msgstr "додано один Ñ€Ñдок"
+
+msgid "1 line less"
+msgstr "знищено один Ñ€Ñдок"
+
+#, c-format
+msgid "%ld more lines"
+msgstr "додано Ñ€Ñдків: %ld"
+
+#, c-format
+msgid "%ld fewer lines"
+msgstr "знищено Ñ€Ñдків: %ld"
+
+msgid " (Interrupted)"
+msgstr " (Перервано)"
+
+msgid "Beep!"
+msgstr "Дзень!"
+
+msgid "ERROR: "
+msgstr "ПОМИЛКÐ: "
+
+#, c-format
+msgid ""
+"\n"
+"[bytes] total alloc-freed %lu-%lu, in use %lu, peak use %lu\n"
+msgstr ""
+"\n"
+"[байт] вÑього розм/знищ. %lu/%lu, викор. %lu, макÑ. %lu\n"
+
+#, c-format
+msgid ""
+"[calls] total re/malloc()'s %lu, total free()'s %lu\n"
+"\n"
+msgstr ""
+"[виклики] уÑього re/malloc() - %lu, уÑього free() - %lu\n"
+"\n"
+
+msgid "E340: Line is becoming too long"
+msgstr "E340: РÑдок Ñтає занадто довгим"
+
+# msgstr "E340: "
+#, c-format
+msgid "E341: Internal error: lalloc(%ld, )"
+msgstr "E341: Ð’Ð½ÑƒÑ‚Ñ€Ñ–ÑˆÐ½Ñ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ°: lalloc(%ld, )"
+
+# msgstr "E341: "
+#, c-format
+msgid "E342: Out of memory! (allocating %lu bytes)"
+msgstr "E342: Забракло пам'ÑÑ‚Ñ–! (потрібно було %lu байтів)"
+
+# msgstr "E342: "
+#, c-format
+msgid "Calling shell to execute: \"%s\""
+msgstr "ВикликаєтьÑÑ Ð¾Ð±Ð¾Ð»Ð¾Ð½ÐºÐ° щоб виконати: «%s»"
+
+msgid "E545: Missing colon"
+msgstr "E545: Пропущено двокрапку"
+
+msgid "E546: Illegal mode"
+msgstr "E546: Ðеправильний режим"
+
+msgid "E547: Illegal mouseshape"
+msgstr "E547: Ðеправильний виглÑд миші"
+
+msgid "E548: digit expected"
+msgstr "E548: Потрібна цифра"
+
+msgid "E549: Illegal percentage"
+msgstr "E549: Ðеправильний відÑоток"
+
+msgid "E854: path too long for completion"
+msgstr "E854: шлÑÑ… занадто довгий Ð´Ð»Ñ Ð´Ð¾Ð¿Ð¾Ð²Ð½ÐµÐ½Ð½Ñ"
+
+#, c-format
+msgid ""
+"E343: Invalid path: '**[number]' must be at the end of the path or be "
+"followed by '%s'."
+msgstr ""
+"E343: Ðекоректний шлÑÑ…: `**[чиÑло]' повинне бути наприкінці шлÑху або перед "
+"'%s'."
+
+# msgstr "E343: "
+#, c-format
+msgid "E344: Can't find directory \"%s\" in cdpath"
+msgstr "E344: Ðе вдалоÑÑ Ð·Ð½Ð°Ð¹Ñ‚Ð¸ каталог «%s» у cdpath"
+
+# msgstr "E344: "
+#, c-format
+msgid "E345: Can't find file \"%s\" in path"
+msgstr "E345: Ðе вдалоÑÑ Ð·Ð½Ð°Ð¹Ñ‚Ð¸ файл «%s» у path"
+
+# msgstr "E345: "
+#, c-format
+msgid "E346: No more directory \"%s\" found in cdpath"
+msgstr "E346: У cdpath немає більше каталогу «%s»"
+
+# msgstr "E346: "
+#, c-format
+msgid "E347: No more file \"%s\" found in path"
+msgstr "E347: У шлÑху пошуку більше немає файлів «%s»"
+
+#, c-format
+msgid "E668: Wrong access mode for NetBeans connection info file: \"%s\""
+msgstr ""
+"E668: Ðеправильний режим доÑтупу до файлу інформації про з'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð· "
+"NetBenans: «%s»"
+
+#, c-format
+msgid "E658: NetBeans connection lost for buffer %ld"
+msgstr "E658: Втрачено зв'Ñзок із NetBeans Ð´Ð»Ñ Ð±ÑƒÑ„ÐµÑ€Ð° %ld"
+
+msgid "E838: netbeans is not supported with this GUI"
+msgstr "E838: netbeans не підтримуєтьÑÑ Ð· цим GUI"
+
+msgid "E511: netbeans already connected"
+msgstr "E511: netbeans вже під'єднано"
+
+#, c-format
+msgid "E505: %s is read-only (add ! to override)"
+msgstr "E505: %s тільки Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ (! щоб не зважати)"
+
+# msgstr "E348: "
+msgid "E349: No identifier under cursor"
+msgstr "E349: Ðемає ідентифікатора над курÑором"
+
+msgid "E774: 'operatorfunc' is empty"
+msgstr "E774: 'operatorfunc' порожнÑ"
+
+msgid "E775: Eval feature not available"
+msgstr "E775: МожливіÑÑ‚ÑŒ eval недоÑтупна"
+
+msgid "Warning: terminal cannot highlight"
+msgstr "ЗаÑтереженнÑ: Термінал не підтримує кольори"
+
+msgid "E348: No string under cursor"
+msgstr "E348: Ðемає Ñ€Ñдка на курÑорі"
+
+msgid "E352: Cannot erase folds with current 'foldmethod'"
+msgstr "E352: Ðе вдалоÑÑ Ð·Ð½Ð¸Ñ‰Ð¸Ñ‚Ð¸ згортки поточним методом 'foldmethod'"
+
+msgid "E664: changelist is empty"
+msgstr "E664: СпиÑок змін порожній"
+
+msgid "E662: At start of changelist"
+msgstr "E662: Початок ÑпиÑку змін"
+
+msgid "E663: At end of changelist"
+msgstr "E663: Кінець ÑпиÑку змін"
+
+msgid "Type :qa! and press <Enter> to abandon all changes and exit Vim"
+msgstr ""
+"Уведіть :qa! Ñ– натиÑніть <Enter>, щоб відкинути вÑÑ– зміни Ñ– вийти з Vim"
+
+#, c-format
+msgid "1 line %sed 1 time"
+msgstr "Один Ñ€Ñдок %s-но"
+
+#, c-format
+msgid "1 line %sed %d times"
+msgstr "Один Ñ€Ñдок %s-но %d разів"
+
+#, c-format
+msgid "%ld lines %sed 1 time"
+msgstr "%ld Ñ€Ñдків %s-но"
+
+#, c-format
+msgid "%ld lines %sed %d times"
+msgstr "%ld Ñ€Ñдків %s-но %d разів"
+
+#, c-format
+msgid "%ld lines to indent... "
+msgstr "ЗалишилоÑÑ Ð²Ð¸Ñ€Ñ–Ð²Ð½Ñти %ld Ñ€Ñдків..."
+
+msgid "1 line indented "
+msgstr "ВирівнÑно один Ñ€Ñдок"
+
+#, c-format
+msgid "%ld lines indented "
+msgstr "ВирівнÑно Ñ€Ñдків: %ld"
+
+msgid "E748: No previously used register"
+msgstr "E748: РегіÑтри перед цим не вживалиÑÑŒ"
+
+msgid "cannot yank; delete anyway"
+msgstr "не вдалоÑÑ Ð·Ð°Ð¿Ð°Ð¼'Ñтати; вÑе одно знищити?"
+
+msgid "1 line changed"
+msgstr "Один Ñ€Ñдок змінено"
+
+#, c-format
+msgid "%ld lines changed"
+msgstr "Змінено Ñ€Ñдків: %ld"
+
+#, c-format
+msgid "freeing %ld lines"
+msgstr "Звільнено Ñ€Ñдків: %ld"
+
+#, c-format
+msgid " into \"%c"
+msgstr " у \"%c"
+
+#, c-format
+msgid "block of 1 line yanked%s"
+msgstr "блок з 1 Ñ€Ñдка виÑмикнуто%s"
+
+#, c-format
+msgid "1 line yanked%s"
+msgstr "1 Ñ€Ñдок виÑмикнуто%s"
+
+#, c-format
+msgid "block of %ld lines yanked%s"
+msgstr "блок із %ld Ñ€Ñдків виÑмикнуто%s"
+
+#, c-format
+msgid "%ld lines yanked%s"
+msgstr "%ld Ñ€Ñдків виÑмикнуто%s"
+
+#, c-format
+msgid "E353: Nothing in register %s"
+msgstr "E353: У регіÑтрі %s нічого немає"
+
+# msgstr "E353: "
+msgid ""
+"\n"
+"--- Registers ---"
+msgstr ""
+"\n"
+"--- РегіÑтри ---"
+
+msgid "Illegal register name"
+msgstr "Ðеправильна назва регіÑтру"
+
+msgid ""
+"\n"
+"# Registers:\n"
+msgstr ""
+"\n"
+"# РегіÑтри:\n"
+
+#, c-format
+msgid "E574: Unknown register type %d"
+msgstr "E574: Ðевідомий тип регіÑтру %d"
+
+msgid ""
+"E883: search pattern and expression register may not contain two or more "
+"lines"
+msgstr ""
+"E883: шаблон пошуку Ñ– регіÑтровий вираз не можуть міÑтити два чи більше "
+"Ñ€Ñдків"
+
+#, c-format
+msgid "%ld Cols; "
+msgstr "довж.: %ld; "
+
+#, c-format
+msgid "Selected %s%ld of %ld Lines; %lld of %lld Words; %lld of %lld Bytes"
+msgstr "Вибрано %s%ld з %ld Ñ€Ñдків; %lld з %lld Ñлів; %lld з %lld байтів"
+
+#, c-format
+msgid ""
+"Selected %s%ld of %ld Lines; %lld of %lld Words; %lld of %lld Chars; %lld of "
+"%lld Bytes"
+msgstr ""
+"Вибрано %s%ld з %ld Ñ€Ñдків; %lld з %lld Ñлів; %lld of %lld Ñимволів; %lld з "
+"%lld байтів"
+
+#, c-format
+msgid "Col %s of %s; Line %ld of %ld; Word %lld of %lld; Byte %lld of %lld"
+msgstr "Колонка %s з %s; Ñ€Ñдок %ld з %ld; Ñлово %lld з %lld; байт %lld з %lld"
+
+#, c-format
+msgid ""
+"Col %s of %s; Line %ld of %ld; Word %lld of %lld; Char %lld of %lld; Byte "
+"%lld of %lld"
+msgstr ""
+"Колонка %s з %s; Ñ€Ñдок %ld з %ld; Ñлово %lld з %lld; Ñимвол %lld of %lld; "
+"байт %lld з %lld"
+
+#, c-format
+msgid "(+%lld for BOM)"
+msgstr "(+%lld Ð´Ð»Ñ BOM)"
+
+msgid "Thanks for flying Vim"
+msgstr "ДÑкуємо за вибір Vim"
+
+msgid "E518: Unknown option"
+msgstr "E518: Ðевідома опціÑ"
+
+msgid "E519: Option not supported"
+msgstr "E519: ÐžÐ¿Ñ†Ñ–Ñ Ð½Ðµ підтримуєтьÑÑ"
+
+msgid "E520: Not allowed in a modeline"
+msgstr "E520: Ðе дозволено у modeline"
+
+msgid "E846: Key code not set"
+msgstr "E846: Код ключа не вÑтановлено"
+
+msgid "E521: Number required after ="
+msgstr "E521: ПіÑÐ»Ñ = потрібно вказати чиÑло"
+
+msgid "E522: Not found in termcap"
+msgstr "E522: Ðе знайдено Ñеред можливоÑтей терміналів"
+
+#, c-format
+msgid "E539: Illegal character <%s>"
+msgstr "E539: Ðедозволений Ñимвол <%s>"
+
+#, c-format
+msgid "For option %s"
+msgstr "Ð”Ð»Ñ Ð¾Ð¿Ñ†Ñ–Ñ— %s"
+
+msgid "E529: Cannot set 'term' to empty string"
+msgstr "E529: Ðе вдалоÑÑ Ñпорожнити 'term'"
+
+msgid "E530: Cannot change term in GUI"
+msgstr "E530: Ðе вдалоÑÑ Ð·Ð¼Ñ–Ð½Ð¸Ñ‚Ð¸ term в GUI"
+
+msgid "E531: Use \":gui\" to start the GUI"
+msgstr "E531: ЗаÑтоÑуйте «:gui» Ð´Ð»Ñ Ð·Ð°Ð¿ÑƒÑку GUI"
+
+msgid "E589: 'backupext' and 'patchmode' are equal"
+msgstr "E589: Опції 'backupext' і 'patchmode' однакові"
+
+msgid "E834: Conflicts with value of 'listchars'"
+msgstr "E834: Конфліктує із значеннÑм 'listchars'"
+
+msgid "E835: Conflicts with value of 'fillchars'"
+msgstr "E835: Конфліктує із значеннÑм 'fillchars'"
+
+msgid "E617: Cannot be changed in the GTK+ 2 GUI"
+msgstr "E617: Ðе можна змінити в GUI GTK+ 2"
+
+#, c-format
+msgid "E950: Cannot convert between %s and %s"
+msgstr "E950: Ðе можна перетворити між %s Ñ– %s"
+
+msgid "E524: Missing colon"
+msgstr "E524: Бракує двокрапки"
+
+msgid "E525: Zero length string"
+msgstr "E525: РÑдок порожній"
+
+#, c-format
+msgid "E526: Missing number after <%s>"
+msgstr "E526: ПіÑÐ»Ñ <%s> бракує чиÑла"
+
+msgid "E527: Missing comma"
+msgstr "E527: Бракує коми"
+
+msgid "E528: Must specify a ' value"
+msgstr "E528: Потрібно вказати Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ '"
+
+msgid "E595: contains unprintable or wide character"
+msgstr "E595: МіÑтить недруковні або розширені Ñимволи"
+
+msgid "E596: Invalid font(s)"
+msgstr "E596: Ðекоректний(Ñ–) шрифт(и)"
+
+msgid "E597: can't select fontset"
+msgstr "E597: Ðе вдалоÑÑ Ð²Ð¸Ð±Ñ€Ð°Ñ‚Ð¸ набір шрифтів"
+
+msgid "E598: Invalid fontset"
+msgstr "E598: Ðеправильний набір шрифтів"
+
+msgid "E533: can't select wide font"
+msgstr "E533: Ðе вдалоÑÑ Ð²Ð¸ÐºÐ¾Ñ€Ð¸Ñтати розширений шрифт"
+
+msgid "E534: Invalid wide font"
+msgstr "E534: Ðекоректний розширений шрифт"
+
+#, c-format
+msgid "E535: Illegal character after <%c>"
+msgstr "E535: Ðедозволений Ñимвол піÑÐ»Ñ <%c>"
+
+msgid "E536: comma required"
+msgstr "E536: Потрібна кома"
+
+#, c-format
+msgid "E537: 'commentstring' must be empty or contain %s"
+msgstr "E537: 'commentstring' має бути порожньою чи міÑтити %s"
+
+msgid "E538: No mouse support"
+msgstr "E538: Миша не підтримуєтьÑÑ"
+
+msgid "E540: Unclosed expression sequence"
+msgstr "E540: ПоÑлідовніÑÑ‚ÑŒ виразів не завершено"
+
+msgid "E541: too many items"
+msgstr "E541: Забагато елементів"
+
+msgid "E542: unbalanced groups"
+msgstr "E542: Групи не збаланÑовано"
+
+msgid "E946: Cannot make a terminal with running job modifiable"
+msgstr "E946: Ðе можна зробити модифіковним термінал із запущеним завданнÑм"
+
+msgid "E590: A preview window already exists"
+msgstr "E590: Вікно переглÑду вже Ñ–Ñнує"
+
+msgid "W17: Arabic requires UTF-8, do ':set encoding=utf-8'"
+msgstr ""
+"W17: Ð”Ð»Ñ Ð°Ñ€Ð°Ð±Ñької мови потрібне UTF-8, виконайте ':set encoding=utf-8'"
+
+msgid "E954: 24-bit colors are not supported on this environment"
+msgstr "E954: 24-розрÑдні кольори не підтримуютьÑÑ Ñƒ цьому оточенні"
+
+#, c-format
+msgid "E593: Need at least %d lines"
+msgstr "E593: Потрібно щонайменше %d Ñ€Ñдків"
+
+#, c-format
+msgid "E594: Need at least %d columns"
+msgstr "E594: Потрібно щонайменше %d Ñтовпців"
+
+#, c-format
+msgid "E355: Unknown option: %s"
+msgstr "E355: Ðевідома опціÑ: %s"
+
+#, c-format
+msgid "E521: Number required: &%s = '%s'"
+msgstr "E521: Потрібно вказати Number: &%s = '%s'"
+
+# msgstr "E355: "
+msgid ""
+"\n"
+"--- Terminal codes ---"
+msgstr ""
+"\n"
+"--- Коди терміналу ---"
+
+msgid ""
+"\n"
+"--- Global option values ---"
+msgstr ""
+"\n"
+"--- Ð—Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð·Ð°Ð³Ð°Ð»ÑŒÐ½Ð¸Ñ… опцій ---"
+
+msgid ""
+"\n"
+"--- Local option values ---"
+msgstr ""
+"\n"
+"--- Ð—Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð»Ð¾ÐºÐ°Ð»ÑŒÐ½Ð¸Ñ… опцій ---"
+
+msgid ""
+"\n"
+"--- Options ---"
+msgstr ""
+"\n"
+"--- Опції ---"
+
+msgid "E356: get_varp ERROR"
+msgstr "E356: Помилка get_varp"
+
+# msgstr "E356: "
+#, c-format
+msgid "E357: 'langmap': Matching character missing for %s"
+msgstr "E357: 'langmap': Ð”Ð»Ñ Ñимволу %s немає пари"
+
+# msgstr "E357: "
+#, c-format
+msgid "E358: 'langmap': Extra characters after semicolon: %s"
+msgstr "E358: 'langmap': Зайві Ñимволи піÑÐ»Ñ `;': %s"
+
+# msgstr "E358: "
+msgid "cannot open "
+msgstr "не вдалоÑÑ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸ "
+
+msgid "VIM: Can't open window!\n"
+msgstr "VIM: Ðе вдалоÑÑ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸ вікно!\n"
+
+msgid "Need Amigados version 2.04 or later\n"
+msgstr "Потрібна Amigados 2.04 або пізніша\n"
+
+#, c-format
+msgid "Need %s version %ld\n"
+msgstr "Потрібно %s верÑÑ–Ñ— %ld\n"
+
+msgid "Cannot open NIL:\n"
+msgstr "Ðе вдалоÑÑ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸ NIL:\n"
+
+msgid "Cannot create "
+msgstr "Ðе вдалоÑÑ Ñтворити "
+
+#, c-format
+msgid "Vim exiting with %d\n"
+msgstr "Vim завершує роботу з %d\n"
+
+msgid "cannot change console mode ?!\n"
+msgstr "не можу змінити режим конÑолі ?!\n"
+
+# msgstr "E359: "
+msgid "mch_get_shellsize: not a console??\n"
+msgstr "mch_get_shellsize: не конÑоль??\n"
+
+msgid "E360: Cannot execute shell with -f option"
+msgstr "E360: Ðе вдалоÑÑ Ð·Ð°Ð¿ÑƒÑтити оболонку з опцією -f"
+
+# msgstr "E360: "
+msgid "Cannot execute "
+msgstr "Ðе вдалоÑÑ Ð²Ð¸ÐºÐ¾Ð½Ð°Ñ‚Ð¸ "
+
+msgid "shell "
+msgstr "оболонку "
+
+msgid " returned\n"
+msgstr " повернуто\n"
+
+msgid "ANCHOR_BUF_SIZE too small."
+msgstr "ANCHOR_BUF_SIZE замалий"
+
+msgid "I/O ERROR"
+msgstr "Помилка вводу/виводу"
+
+msgid "Message"
+msgstr "ПовідомленнÑ"
+
+# msgstr "E364: "
+msgid "E237: Printer selection failed"
+msgstr "E237: Ðе вдалоÑÑ Ð²Ð¸Ð±Ñ€Ð°Ñ‚Ð¸ принтер"
+
+#, c-format
+msgid "to %s on %s"
+msgstr "на %s з %s"
+
+#, c-format
+msgid "E613: Unknown printer font: %s"
+msgstr "E613: Ðевідомий шрифт принтера: %s"
+
+#, c-format
+msgid "E238: Print error: %s"
+msgstr "E238: Помилка друку: %s"
+
+#, c-format
+msgid "Printing '%s'"
+msgstr "ДрукуєтьÑÑ '%s'"
+
+#, c-format
+msgid "E244: Illegal charset name \"%s\" in font name \"%s\""
+msgstr "E244: Ðекоректна назва набору Ñимволів «%s» у назві шрифту «%s»"
+
+#, c-format
+msgid "E244: Illegal quality name \"%s\" in font name \"%s\""
+msgstr "E244: Ðекоректна назва ÑкоÑÑ‚Ñ– «%s» у назві шрифту «%s»"
+
+#, c-format
+msgid "E245: Illegal char '%c' in font name \"%s\""
+msgstr "E245: Помилковий Ñимвол %c в назві шрифту «%s»"
+
+#, c-format
+msgid "Opening the X display took %ld msec"
+msgstr "Ðа Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ñ‚Ñ Ð´Ð¸Ñплею X пішло %ld міліÑекунд"
+
+msgid ""
+"\n"
+"Vim: Got X error\n"
+msgstr ""
+"\n"
+"Vim: Помилка X\n"
+
+msgid "Testing the X display failed"
+msgstr "ДиÑплей Ð¥ не пройшов перевірку"
+
+msgid "Opening the X display timed out"
+msgstr "Сплив Ñ‡Ð°Ñ Ð¾Ñ‡Ñ–ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ñ‚Ñ Ð´Ð¸Ñплею Ð¥"
+
+msgid ""
+"\n"
+"Could not get security context for "
+msgstr ""
+"\n"
+"Ðе вдалоÑÑ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ñ‚Ð¸ контекÑÑ‚ безпеки Ð´Ð»Ñ "
+
+msgid ""
+"\n"
+"Could not set security context for "
+msgstr ""
+"\n"
+"Ðе вдалоÑÑ Ð²Ñтановити контекÑÑ‚ безпеки Ð´Ð»Ñ "
+
+#, c-format
+msgid "Could not set security context %s for %s"
+msgstr "Ðе вдалоÑÑ Ð²Ñтановити контекÑÑ‚ безпеки %s Ð´Ð»Ñ %s"
+
+#, c-format
+msgid "Could not get security context %s for %s. Removing it!"
+msgstr "Ðе вдалоÑÑ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ñ‚Ð¸ контекÑÑ‚ безпеки %s Ð´Ð»Ñ %s. ВидалÑємо!"
+
+msgid ""
+"\n"
+"Cannot execute shell sh\n"
+msgstr ""
+"\n"
+"Ðе вдалоÑÑ Ð·Ð°Ð¿ÑƒÑтити оболонку `sh'\n"
+
+# msgstr "E362: "
+msgid ""
+"\n"
+"shell returned "
+msgstr ""
+"\n"
+"оболонка повернула: "
+
+msgid ""
+"\n"
+"Cannot create pipes\n"
+msgstr ""
+"\n"
+"Ðе можна Ñтворити канали\n"
+
+msgid ""
+"\n"
+"Cannot fork\n"
+msgstr ""
+"\n"
+"Ðе вдалоÑÑ Ñ€Ð¾Ð·Ð´Ð²Ð¾Ñ—Ñ‚Ð¸ÑÑ\n"
+
+msgid ""
+"\n"
+"Cannot execute shell "
+msgstr ""
+"\n"
+"Ðе вдалоÑÑ Ð·Ð°Ð¿ÑƒÑтити оболонку"
+
+msgid ""
+"\n"
+"Command terminated\n"
+msgstr ""
+"\n"
+"Команда закінчила виконаннÑ\n"
+
+msgid "XSMP lost ICE connection"
+msgstr "XSMP втратив з'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ ICE"
+
+#, c-format
+msgid "dlerror = \"%s\""
+msgstr "dlerror = «%s»"
+
+msgid "Opening the X display failed"
+msgstr "Ðе вдалоÑÑ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸ диÑплей X"
+
+msgid "XSMP handling save-yourself request"
+msgstr "XSMP оброблÑєтьÑÑ Ð·Ð°Ð¿Ð¸Ñ‚ 'збережи Ñебе'"
+
+msgid "XSMP opening connection"
+msgstr "XSMP відкриваєтьÑÑ Ð·'єднаннÑ"
+
+msgid "XSMP ICE connection watch failed"
+msgstr "XSMP ÑпоÑÑ‚ÐµÑ€ÐµÐ¶ÐµÐ½Ð½Ñ Ð·Ð° з'єднаннÑм з ICE не вдалоÑÑ"
+
+#, c-format
+msgid "XSMP SmcOpenConnection failed: %s"
+msgstr "XSMP не вдалоÑÑ SmcOpenConnection: %s"
+
+msgid "At line"
+msgstr "РÑдок:"
+
+msgid "Could not load vim32.dll!"
+msgstr "Ðе вдалоÑÑ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶Ð¸Ñ‚Ð¸ vim32.dll"
+
+msgid "VIM Error"
+msgstr "Помилка VIM"
+
+msgid "Could not fix up function pointers to the DLL!"
+msgstr "Ðе вдалоÑÑ Ð²Ð¸Ð¿Ñ€Ð°Ð²Ð¸Ñ‚Ð¸ вказівники на функції DLL!"
+
+#, c-format
+msgid "Vim: Caught %s event\n"
+msgstr "Vim: ВиÑвлено подію %s\n"
+
+msgid "close"
+msgstr "close"
+
+msgid "logoff"
+msgstr "logoff"
+
+msgid "shutdown"
+msgstr "shutdown"
+
+msgid "E371: Command not found"
+msgstr "E371: Команду не знайдено"
+
+msgid ""
+"VIMRUN.EXE not found in your $PATH.\n"
+"External commands will not pause after completion.\n"
+"See :help win32-vimrun for more information."
+msgstr ""
+"Файл VIMRUN.EXE не знайдено у шлÑху пошуку.\n"
+"Зовнішні команди не будуть призупинені піÑÐ»Ñ Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ.\n"
+"ГлÑньте :help win32-vimrun щоб отримати подробиці."
+
+msgid "Vim Warning"
+msgstr "ЗаÑÑ‚ÐµÑ€ÐµÐ¶ÐµÐ½Ð½Ñ Vim"
+
+#, c-format
+msgid "shell returned %d"
+msgstr "оболонка повернула %d"
+
+msgid "E926: Current location list was changed"
+msgstr "E926: Поточний ÑпиÑок міÑць змінивÑÑ"
+
+# msgstr "E371: "
+#, c-format
+msgid "E372: Too many %%%c in format string"
+msgstr "E372: Забагато %%%c у Ñ€Ñдку формату"
+
+# msgstr "E372: "
+#, c-format
+msgid "E373: Unexpected %%%c in format string"
+msgstr "E373: Ðеочікуваний `%%%c' у Ñ€Ñдку формату"
+
+# msgstr "E373: "
+msgid "E374: Missing ] in format string"
+msgstr "E374: Пропущено ] у Ñ€Ñдку формату"
+
+# msgstr "E374: "
+#, c-format
+msgid "E375: Unsupported %%%c in format string"
+msgstr "E375: %%%c у Ñ€Ñдку формату не підтримуєтьÑÑ"
+
+# msgstr "E375: "
+#, c-format
+msgid "E376: Invalid %%%c in format string prefix"
+msgstr "E376: Помилковий `%%%c' у префікÑÑ– Ñ€Ñдку формату"
+
+# msgstr "E376: "
+#, c-format
+msgid "E377: Invalid %%%c in format string"
+msgstr "E377: Помилковий `%%%c' у Ñ€Ñдку формату"
+
+# msgstr "E377: "
+msgid "E378: 'errorformat' contains no pattern"
+msgstr "E378: 'errorformat' не міÑтить зразок"
+
+# msgstr "E378: "
+msgid "E379: Missing or empty directory name"
+msgstr "E379: Пропущена чи Ð¿Ð¾Ñ€Ð¾Ð¶Ð½Ñ Ð½Ð°Ð·Ð²Ð° каталогу"
+
+msgid "E553: No more items"
+msgstr "E553: Ðемає більше елементів"
+
+msgid "E924: Current window was closed"
+msgstr "E924: Поточне вікно було закрито"
+
+msgid "E925: Current quickfix was changed"
+msgstr "E925: Поточний quickfix змінивÑÑ"
+
+#, c-format
+msgid "(%d of %d)%s%s: "
+msgstr "(%d з %d)%s%s: "
+
+msgid " (line deleted)"
+msgstr " (Ñ€Ñдок знищено)"
+
+#, c-format
+msgid "%serror list %d of %d; %d errors "
+msgstr "%sÑпиÑок помилок %d з %d; %d помилок"
+
+msgid "E380: At bottom of quickfix stack"
+msgstr "E380: Дно Ñтеку виправлень"
+
+msgid "E381: At top of quickfix stack"
+msgstr "E381: Вершина Ñтеку виправлень"
+
+msgid "No entries"
+msgstr "Ðічого"
+
+# msgstr "E231: "
+msgid "Error file"
+msgstr "Файл помилок"
+
+msgid "E683: File name missing or invalid pattern"
+msgstr "E683: Пропущено назву файлу чи некоректний шаблон"
+
+#, c-format
+msgid "Cannot open file \"%s\""
+msgstr "Ðе вдалоÑÑ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸ файл «%s»"
+
+msgid "E681: Buffer is not loaded"
+msgstr "E681: Буфер не завантажено"
+
+msgid "E777: String or List expected"
+msgstr "E777: ОчікуєтьÑÑ String чи List"
+
+#, c-format
+msgid "E369: invalid item in %s%%[]"
+msgstr "E369: Ðекоректний елемент у %s%%[]"
+
+#, c-format
+msgid "E769: Missing ] after %s["
+msgstr "E769: Бракує ] піÑÐ»Ñ %s["
+
+msgid "E944: Reverse range in character class"
+msgstr "E944: Зворотній діапазон у клаÑÑ– Ñимволів"
+
+msgid "E945: Range too large in character class"
+msgstr "E945: Завеликий діапазон у клаÑÑ– Ñимволів"
+
+#, c-format
+msgid "E53: Unmatched %s%%("
+msgstr "E53: Ðемає пари %s%%("
+
+#, c-format
+msgid "E54: Unmatched %s("
+msgstr "E54: Ðемає пари %s("
+
+#, c-format
+msgid "E55: Unmatched %s)"
+msgstr "E55: Ðемає пари %s)"
+
+# msgstr "E406: "
+msgid "E66: \\z( not allowed here"
+msgstr "E66: \\z( тут не дозволено"
+
+# msgstr "E406: "
+msgid "E67: \\z1 - \\z9 not allowed here"
+msgstr "E67: \\z1 та ін. тут не дозволено"
+
+#, c-format
+msgid "E69: Missing ] after %s%%["
+msgstr "E69: Пропущено ] піÑÐ»Ñ %s%%["
+
+#, c-format
+msgid "E70: Empty %s%%[]"
+msgstr "E70: %s%%[] порожній"
+
+msgid "E65: Illegal back reference"
+msgstr "E65: Ðекоректне зворотне поÑиланнÑ"
+
+# msgstr "E382: "
+msgid "E339: Pattern too long"
+msgstr "E339: Зразок занадто довгий"
+
+msgid "E50: Too many \\z("
+msgstr "E50: Забагато \\z("
+
+#, c-format
+msgid "E51: Too many %s("
+msgstr "E51: Забагато %s("
+
+msgid "E52: Unmatched \\z("
+msgstr "E52: Ðемає пари \\z("
+
+#, c-format
+msgid "E59: invalid character after %s@"
+msgstr "E59: Ðедозволений Ñимвол піÑÐ»Ñ %s@"
+
+#, c-format
+msgid "E60: Too many complex %s{...}s"
+msgstr "E60: Забагато Ñкладних %s{...}"
+
+# msgstr "E339: "
+#, c-format
+msgid "E61: Nested %s*"
+msgstr "E61: Вкладені %s*"
+
+# msgstr "E61: "
+#, c-format
+msgid "E62: Nested %s%c"
+msgstr "E62: Вкладені %s%c"
+
+msgid "E63: invalid use of \\_"
+msgstr "E63: Ðекоректно вжито \\_"
+
+# msgstr "E62: "
+#, c-format
+msgid "E64: %s%c follows nothing"
+msgstr "E64: ПіÑÐ»Ñ %s%c нічого немає"
+
+msgid "E68: Invalid character after \\z"
+msgstr "E68: Ðеправильний Ñимвол піÑÐ»Ñ \\z"
+
+#, c-format
+msgid "E678: Invalid character after %s%%[dxouU]"
+msgstr "E678: Ðедозволений Ñимвол піÑÐ»Ñ %s%%[dxouU]"
+
+#, c-format
+msgid "E71: Invalid character after %s%%"
+msgstr "E71: Ðедозволений Ñимвол піÑÐ»Ñ %s%%"
+
+# msgstr "E64: "
+#, c-format
+msgid "E554: Syntax error in %s{...}"
+msgstr "E554: СинтакÑична помилка в %s{...}"
+
+msgid "External submatches:\n"
+msgstr "Зовнішні під-збіги:\n"
+
+#, c-format
+msgid "E888: (NFA regexp) cannot repeat %s"
+msgstr "E888: (NFA regexp) не можна повторити %s"
+
+msgid ""
+"E864: \\%#= can only be followed by 0, 1, or 2. The automatic engine will be "
+"used "
+msgstr ""
+"E864: піÑÐ»Ñ \\%#= може бути тільки 0, 1, or 2. Буде викориÑтано автоматичний "
+"механізм "
+
+msgid "Switching to backtracking RE engine for pattern: "
+msgstr "ПеремикаємоÑÑ Ð´Ð¾ пошуку з поверненнÑм Ð´Ð»Ñ ÑˆÐ°Ð±Ð»Ð¾Ð½Ð°: "
+
+msgid "E865: (NFA) Regexp end encountered prematurely"
+msgstr "E865: (NFA) Зарано трапивÑÑ ÐºÑ–Ð½ÐµÑ†ÑŒ регулÑрного виразу"
+
+#, c-format
+msgid "E866: (NFA regexp) Misplaced %c"
+msgstr "E866: (NFA regexp) Ðе на міÑці %c"
+
+#, c-format
+msgid "E877: (NFA regexp) Invalid character class: %ld"
+msgstr "E877: (NFA regexp) Ðеправильний ÐºÐ»Ð°Ñ Ñимволу: %ld"
+
+#, c-format
+msgid "E867: (NFA) Unknown operator '\\z%c'"
+msgstr "E867: (NFA) Ðевідомий оператор '\\z%c'"
+
+msgid "E951: \\% value too large"
+msgstr "E951: Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ \\% завелике"
+
+#, c-format
+msgid "E867: (NFA) Unknown operator '\\%%%c'"
+msgstr "E867: (NFA) Ðевідомий оператор '\\%%%c'"
+
+msgid "E868: Error building NFA with equivalence class!"
+msgstr "E868: Ðе вдалоÑÑ Ð¿Ð¾Ð±ÑƒÐ´ÑƒÐ²Ð°Ñ‚Ð¸ NFA з клаÑом еквівалентноÑÑ‚Ñ–!"
+
+#, c-format
+msgid "E869: (NFA) Unknown operator '\\@%c'"
+msgstr "E869: (NFA) Ðевідомий оператор '\\@%c'"
+
+msgid "E870: (NFA regexp) Error reading repetition limits"
+msgstr "E870: (NFA regexp) Ðе вдалоÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ межі повтореннÑ"
+
+msgid "E871: (NFA regexp) Can't have a multi follow a multi"
+msgstr "E871: (NFA regexp) Мульти не може бути за мульти"
+
+msgid "E872: (NFA regexp) Too many '('"
+msgstr "E872: (NFA regexp) Забагато '('"
+
+msgid "E879: (NFA regexp) Too many \\z("
+msgstr "E879: (NFA regexp) Забагато \\z("
+
+msgid "E873: (NFA regexp) proper termination error"
+msgstr "E873: (NFA regexp) помилка належного припиненнÑ"
+
+msgid "E874: (NFA) Could not pop the stack!"
+msgstr "E874: (NFA) Стек порожній!"
+
+msgid ""
+"E875: (NFA regexp) (While converting from postfix to NFA), too many states "
+"left on stack"
+msgstr ""
+"E875: (NFA regexp) (Під Ñ‡Ð°Ñ Ð¿ÐµÑ€ÐµÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð· поÑÑ‚Ñ„Ñ–ÐºÑ Ñƒ NFA) залишилоÑÑ "
+"забагато Ñтанів у Ñтеку"
+
+msgid "E876: (NFA regexp) Not enough space to store the whole NFA "
+msgstr "E876: (NFA regexp) ÐедоÑтатньо пам’ÑÑ‚Ñ–, щоб зберегти веÑÑŒ NFA "
+
+msgid "E878: (NFA) Could not allocate memory for branch traversal!"
+msgstr "E878: (NFA) Ðе вдалоÑÑ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ñ‚Ð¸ пам’ÑÑ‚ÑŒ Ð´Ð»Ñ Ð¾Ð±Ñ…Ð¾Ð´Ñƒ гілок!"
+
+msgid "Could not open temporary log file for writing, displaying on stderr... "
+msgstr ""
+"Ðе вдалоÑÑ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸ тимчаÑовий файл журналу Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñу, показуєтьÑÑ Ð½Ð° "
+"stderr... "
+
+#, c-format
+msgid "(NFA) COULD NOT OPEN %s !"
+msgstr "(NFA) ÐЕ ВДÐЛОСЯ ВІДКРИТИ %s!"
+
+msgid ""
+"Could not open temporary log file for writing, displaying on stderr ... "
+msgstr ""
+"Ðе вдалоÑÑ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸ тимчаÑовий файл журналу Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñу, показуєтьÑÑ Ð½Ð° "
+"stderr ... "
+
+msgid "Could not open temporary log file for writing "
+msgstr "Ðе вдалоÑÑ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸ тимчаÑовий файл журналу Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñу "
+
+msgid " VREPLACE"
+msgstr " ВІРТ ЗÐМІÐÐ"
+
+msgid " REPLACE"
+msgstr " ЗÐМІÐÐ"
+
+msgid " REVERSE"
+msgstr " ÐÐВИВОРІТ"
+
+msgid " INSERT"
+msgstr " ВСТÐВКÐ"
+
+msgid " (insert)"
+msgstr " (вÑтавка)"
+
+msgid " (replace)"
+msgstr " (заміна)"
+
+msgid " (vreplace)"
+msgstr " (вірт заміна)"
+
+msgid " Hebrew"
+msgstr " Іврит"
+
+msgid " Arabic"
+msgstr " ÐрабÑька"
+
+msgid " (paste)"
+msgstr " (клей)"
+
+msgid " VISUAL"
+msgstr " ВИБІР"
+
+msgid " VISUAL LINE"
+msgstr " ВИБІР РЯДКІВ"
+
+msgid " VISUAL BLOCK"
+msgstr " ВИБІР БЛОКУ"
+
+msgid " SELECT"
+msgstr " ВИДІЛЕÐÐЯ"
+
+msgid " SELECT LINE"
+msgstr " ВИДІЛЕÐÐЯ РЯДКІВ"
+
+msgid " SELECT BLOCK"
+msgstr " ВИДІЛЕÐÐЯ БЛОКУ"
+
+msgid "recording"
+msgstr "йде запиÑ"
+
+#, c-format
+msgid "E383: Invalid search string: %s"
+msgstr "E383: Ðеправильний зразок Ð´Ð»Ñ Ð¿Ð¾ÑˆÑƒÐºÑƒ: %s"
+
+#, c-format
+msgid "E384: search hit TOP without match for: %s"
+msgstr "E384: Пошук дійшов до ПОЧÐТКУ без збігів з %s"
+
+#, c-format
+msgid "E385: search hit BOTTOM without match for: %s"
+msgstr "E385: Пошук дійшов до КІÐЦЯ без збігів з %s"
+
+msgid "E386: Expected '?' or '/' after ';'"
+msgstr "E386: ПіÑÐ»Ñ `;' має бути `?' або `/'"
+
+# msgstr "E386: "
+msgid " (includes previously listed match)"
+msgstr " (разом з попередніми збігами)"
+
+msgid "--- Included files "
+msgstr "--- Включені файли "
+
+msgid "not found "
+msgstr "не знайдено "
+
+msgid "in path ---\n"
+msgstr "у шлÑху пошуку ---\n"
+
+msgid " (Already listed)"
+msgstr " (Уже у ÑпиÑку)"
+
+msgid " NOT FOUND"
+msgstr " ÐЕ ЗÐÐЙДЕÐО"
+
+#, c-format
+msgid "Scanning included file: %s"
+msgstr "Пошук у включеному файлі: %s"
+
+#, c-format
+msgid "Searching included file %s"
+msgstr "ШукаєтьÑÑ Ñƒ включеному файлі %s"
+
+msgid "E387: Match is on current line"
+msgstr "E387: Збіг у поточному Ñ€Ñдку"
+
+msgid "All included files were found"
+msgstr "Були знайдені вÑÑ– включені файли"
+
+msgid "No included files"
+msgstr "Жодного включеного файлу"
+
+msgid "E388: Couldn't find definition"
+msgstr "E388: Ð’Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð½Ðµ знайдено"
+
+msgid "E389: Couldn't find pattern"
+msgstr "E389: Зразок не знайдено"
+
+msgid "Substitute "
+msgstr "Заміна "
+
+#, c-format
+msgid ""
+"\n"
+"# Last %sSearch Pattern:\n"
+"~"
+msgstr ""
+"\n"
+"# ОÑÑ‚. %sЗразок пошуку:\n"
+"~"
+
+msgid "E756: Spell checking is not enabled"
+msgstr "E756: Перевірка орфографії не дозволена"
+
+#, c-format
+msgid "Warning: Cannot find word list \"%s_%s.spl\" or \"%s_ascii.spl\""
+msgstr ""
+"ЗаÑтереженнÑ: Ðе вдалоÑÑ Ð·Ð½Ð°Ð¹Ñ‚Ð¸ ÑпиÑок Ñлів «%s_%s.spl» чи «%s_ascii.spl»"
+
+#, c-format
+msgid "Warning: Cannot find word list \"%s.%s.spl\" or \"%s.ascii.spl\""
+msgstr ""
+"ЗаÑтереженнÑ: Ðе вдалоÑÑ Ð·Ð½Ð°Ð¹Ñ‚Ð¸ ÑпиÑок Ñлів «%s.%s.spl» чи «%s.ascii.spl»"
+
+msgid "E797: SpellFileMissing autocommand deleted buffer"
+msgstr "E797: Ðвтокоманда SpellFileMissing знищила буфер"
+
+#, c-format
+msgid "Warning: region %s not supported"
+msgstr "ЗаÑтереженнÑ: регіон %s не підтримуєтьÑÑ"
+
+msgid "Sorry, no suggestions"
+msgstr "Пробачте, немає пропозицій"
+
+#, c-format
+msgid "Sorry, only %ld suggestions"
+msgstr "Пробачте, тільки %ld пропозицій"
+
+#, c-format
+msgid "Change \"%.*s\" to:"
+msgstr "Замінити «%.*s» на:"
+
+#, c-format
+msgid " < \"%.*s\""
+msgstr " < «%.*s»"
+
+# msgstr "E34: "
+msgid "E752: No previous spell replacement"
+msgstr "E752: Ðемає попередньої заміни"
+
+# msgstr "E333: "
+#, c-format
+msgid "E753: Not found: %s"
+msgstr "E753: Ðе знайдено: %s"
+
+# msgstr "E364: "
+msgid "E758: Truncated spell file"
+msgstr "E758: Обірваний файл орфографії"
+
+#, c-format
+msgid "Trailing text in %s line %d: %s"
+msgstr "Зайвий текÑÑ‚ у %s у Ñ€Ñдку %d: %s"
+
+#, c-format
+msgid "Affix name too long in %s line %d: %s"
+msgstr "Ðазва афікÑу завелика у %s у Ñ€Ñдку %d: %s"
+
+# msgstr "E430: "
+msgid "E761: Format error in affix file FOL, LOW or UPP"
+msgstr "E761: Помилка формату у файлі афікÑів FOL, LOW чи UPP"
+
+msgid "E762: Character in FOL, LOW or UPP is out of range"
+msgstr "E762: Символ у FOL, LOW чи UPP поза межами"
+
+msgid "Compressing word tree..."
+msgstr "СтиÑкуєтьÑÑ Ð´ÐµÑ€ÐµÐ²Ð¾ Ñлів..."
+
+#, c-format
+msgid "Reading spell file \"%s\""
+msgstr "ЧитаєтьÑÑ Ñ„Ð°Ð¹Ð» орфографії «%s»"
+
+msgid "E757: This does not look like a spell file"
+msgstr "E757: Ðе Ñхоже на файл орфографії"
+
+msgid "E771: Old spell file, needs to be updated"
+msgstr "E771: Файл орфографії Ñтарий, треба поновити"
+
+msgid "E772: Spell file is for newer version of Vim"
+msgstr "E772: Файл орфографії призначений Ð´Ð»Ñ Ð±Ñ–Ð»ÑŒÑˆ нової верÑÑ–Ñ— Vim"
+
+msgid "E770: Unsupported section in spell file"
+msgstr "E770: Ðедозволена ÑÐµÐºÑ†Ñ–Ñ Ñƒ файлі орфографії"
+
+#, c-format
+msgid "E778: This does not look like a .sug file: %s"
+msgstr "E778: Ðе Ñхоже на файл .sug: %s"
+
+#, c-format
+msgid "E779: Old .sug file, needs to be updated: %s"
+msgstr "E779: ЗаÑтарілий файл .sug, треба поновити: %s"
+
+#, c-format
+msgid "E780: .sug file is for newer version of Vim: %s"
+msgstr "E780: Файл .sug Ð´Ð»Ñ Ð±Ñ–Ð»ÑŒÑˆ нової верÑÑ–Ñ— Vim: %s"
+
+#, c-format
+msgid "E781: .sug file doesn't match .spl file: %s"
+msgstr "E781: Файл .sug не відповідає файлу .spl: %s"
+
+#, c-format
+msgid "E782: error while reading .sug file: %s"
+msgstr "E782: Помилка Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ Ñ„Ð°Ð¹Ð»Ñƒ .sug: %s"
+
+#, c-format
+msgid "Reading affix file %s..."
+msgstr "ЧитаєтьÑÑ Ñ„Ð°Ð¹Ð» афікÑів %s..."
+
+#, c-format
+msgid "Conversion failure for word in %s line %d: %s"
+msgstr "Помилка Ð¿ÐµÑ€ÐµÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ñлова у %s у Ñ€Ñдку %d: %s"
+
+#, c-format
+msgid "Conversion in %s not supported: from %s to %s"
+msgstr "ÐŸÐµÑ€ÐµÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ñƒ %s не підтримуєтьÑÑ: з %s до %s"
+
+#, c-format
+msgid "Conversion in %s not supported"
+msgstr "ÐŸÐµÑ€ÐµÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ñƒ %s не підтримуєтьÑÑ"
+
+#, c-format
+msgid "Invalid value for FLAG in %s line %d: %s"
+msgstr "Ðекоректне Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ FLAG у %s у Ñ€Ñдку %d: %s"
+
+#, c-format
+msgid "FLAG after using flags in %s line %d: %s"
+msgstr "FLAG піÑÐ»Ñ Ð²Ð¸ÐºÐ¾Ñ€Ð¸ÑÑ‚Ð°Ð½Ð½Ñ Ð¿Ñ€Ð°Ð¿Ð¾Ñ€Ñ†Ñ–Ð² у %s у Ñ€Ñдку %d: %s"
+
+#, c-format
+msgid ""
+"Defining COMPOUNDFORBIDFLAG after PFX item may give wrong results in %s line "
+"%d"
+msgstr ""
+"Ð’Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ COMPOUNDFORBIDFLAG піÑÐ»Ñ ÐµÐ»ÐµÐ¼ÐµÐ½Ñ‚Ñƒ PFX може дати неправильний "
+"результат у %s у Ñ€Ñдку %d"
+
+#, c-format
+msgid ""
+"Defining COMPOUNDPERMITFLAG after PFX item may give wrong results in %s line "
+"%d"
+msgstr ""
+"Ð’Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ COMPOUNDPERMITFLAG піÑÐ»Ñ ÐµÐ»ÐµÐ¼ÐµÐ½Ñ‚Ñƒ PFX можу дати неправильний "
+"результат у %s у Ñ€Ñдку %d"
+
+#, c-format
+msgid "Wrong COMPOUNDRULES value in %s line %d: %s"
+msgstr "Ðеправильне Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ COMPOUNDRULES у %s у Ñ€Ñдку %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDWORDMAX value in %s line %d: %s"
+msgstr "Ðеправильне Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ COMPOUNDWORDMAX у %s у Ñ€Ñдку %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDMIN value in %s line %d: %s"
+msgstr "Ðеправильне Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ COMPOUNDMIN у %s у Ñ€Ñдку %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDSYLMAX value in %s line %d: %s"
+msgstr "Ðеправильне Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ COMPOUNDSYLMAX у %s у Ñ€Ñдку %d: %s"
+
+#, c-format
+msgid "Wrong CHECKCOMPOUNDPATTERN value in %s line %d: %s"
+msgstr "Ðеправильне Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ CHECKCOMPOUNDPATTERN у %s у Ñ€Ñдку %d: %s"
+
+#, c-format
+msgid "Different combining flag in continued affix block in %s line %d: %s"
+msgstr ""
+"Інший прапорець комбінації у продовженні блоку афікÑів у %s у Ñ€Ñдку %d: %s"
+
+#, c-format
+msgid "Duplicate affix in %s line %d: %s"
+msgstr "Подвійний Ð°Ñ„Ñ–ÐºÑ Ñƒ %s у Ñ€Ñдку %d: %s"
+
+#, c-format
+msgid ""
+"Affix also used for BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST in %s "
+"line %d: %s"
+msgstr ""
+"ÐÑ„Ñ–ÐºÑ Ñ‚Ð°ÐºÐ¾Ð¶ викориÑтовуєтьÑÑ Ð´Ð»Ñ BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/"
+"NOSUGGEST у %s у Ñ€Ñдку %d: %s"
+
+#, c-format
+msgid "Expected Y or N in %s line %d: %s"
+msgstr "Треба Y чи N у %s у Ñ€Ñдку %d: %s"
+
+#, c-format
+msgid "Broken condition in %s line %d: %s"
+msgstr "Ðепридатна умова у %s у Ñ€Ñдку %d: %s"
+
+#, c-format
+msgid "Expected REP(SAL) count in %s line %d"
+msgstr "Треба кількіÑÑ‚ÑŒ REP(SAL) у %s у Ñ€Ñдку %d"
+
+#, c-format
+msgid "Expected MAP count in %s line %d"
+msgstr "Треба кількіÑÑ‚ÑŒ MAP у %s у Ñ€Ñдку %d"
+
+#, c-format
+msgid "Duplicate character in MAP in %s line %d"
+msgstr "ÐŸÐ¾Ð²Ñ‚Ð¾Ñ€ÐµÐ½Ð½Ñ Ñимволу у MAP у %s у Ñ€Ñдку %d"
+
+#, c-format
+msgid "Unrecognized or duplicate item in %s line %d: %s"
+msgstr "Ðерозпізнаний чи повторний елемент у %s у Ñ€Ñдку %d: %s"
+
+#, c-format
+msgid "Missing FOL/LOW/UPP line in %s"
+msgstr "Пропущено Ñ€Ñдок FOL/LOW/UPP у %s"
+
+msgid "COMPOUNDSYLMAX used without SYLLABLE"
+msgstr "Вжито COMPOUNDSYLMAX без SYLLABLE"
+
+msgid "Too many postponed prefixes"
+msgstr "Забагато відкладених префікÑів"
+
+msgid "Too many compound flags"
+msgstr "Забагато Ñкладних прапорців"
+
+msgid "Too many postponed prefixes and/or compound flags"
+msgstr "Забагато відкладених префікÑів Ñ–/або Ñкладних прапорців"
+
+#, c-format
+msgid "Missing SOFO%s line in %s"
+msgstr "Пропущено Ñ€Ñдок SOFO%s у %s"
+
+#, c-format
+msgid "Both SAL and SOFO lines in %s"
+msgstr "Обидва Ñ€Ñдки SAL Ñ– SOFO у %s"
+
+#, c-format
+msgid "Flag is not a number in %s line %d: %s"
+msgstr "Прапорець не Ñ” чиÑлом у %s у Ñ€Ñдку %d: %s"
+
+#, c-format
+msgid "Illegal flag in %s line %d: %s"
+msgstr "Ðеправильний прапорець у %s у Ñ€Ñдку %d: %s"
+
+#, c-format
+msgid "%s value differs from what is used in another .aff file"
+msgstr "Ð—Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ %s відрізнÑєтьÑÑ Ð²Ñ–Ð´ того, що вжито у іншому файлі .aff"
+
+#, c-format
+msgid "Reading dictionary file %s..."
+msgstr "ЗчитуєтьÑÑ Ñловниковий файл %s..."
+
+#, c-format
+msgid "E760: No word count in %s"
+msgstr "E760: Ðемає кількоÑÑ‚Ñ– Ñлів у %s"
+
+#, c-format
+msgid "line %6d, word %6ld - %s"
+msgstr "Ñ€Ñдок %6d, Ñлово %6ld - %s"
+
+#, c-format
+msgid "Duplicate word in %s line %d: %s"
+msgstr "ÐŸÐ¾Ð²Ñ‚Ð¾Ñ€ÐµÐ½Ð½Ñ Ñлова у %s у Ñ€Ñдку %d: %s"
+
+#, c-format
+msgid "First duplicate word in %s line %d: %s"
+msgstr "Перше Ð¿Ð¾Ð²Ñ‚Ð¾Ñ€ÐµÐ½Ð½Ñ Ñлова у %s у Ñ€Ñдку %d: %s"
+
+#, c-format
+msgid "%d duplicate word(s) in %s"
+msgstr "%d повторюваних Ñлів у %s"
+
+#, c-format
+msgid "Ignored %d word(s) with non-ASCII characters in %s"
+msgstr "Пропущено %d Ñлів(~) із не-ASCII Ñимволами у %s"
+
+#, c-format
+msgid "Reading word file %s..."
+msgstr "ЧитаєтьÑÑ Ñ„Ð°Ð¹Ð» Ñлів %s..."
+
+#, c-format
+msgid "Duplicate /encoding= line ignored in %s line %d: %s"
+msgstr "ÐŸÐ¾Ð²Ñ‚Ð¾Ñ€ÐµÐ½Ð½Ñ Ñ€Ñдка /encoding= проігноровано у %s у Ñ€Ñдку %d: %s"
+
+#, c-format
+msgid "/encoding= line after word ignored in %s line %d: %s"
+msgstr "РÑдок /encoding= піÑÐ»Ñ Ñлова проігноровано у %s у Ñ€Ñдку %d: %s"
+
+#, c-format
+msgid "Duplicate /regions= line ignored in %s line %d: %s"
+msgstr "ÐŸÐ¾Ð²Ñ‚Ð¾Ñ€ÐµÐ½Ð½Ñ Ñ€Ñдка /regions= проігноровано у %s у Ñ€Ñдку %d: %s"
+
+#, c-format
+msgid "Too many regions in %s line %d: %s"
+msgstr "Забагато регіонів у %s у Ñ€Ñдку %d: %s"
+
+#, c-format
+msgid "/ line ignored in %s line %d: %s"
+msgstr "РÑдок / проігноровано у %s у Ñ€Ñдку %d: %s"
+
+#, c-format
+msgid "Invalid region nr in %s line %d: %s"
+msgstr "Ðекоректний номер регіону у %s у Ñ€Ñдку %d: %s"
+
+#, c-format
+msgid "Unrecognized flags in %s line %d: %s"
+msgstr "Ðерозпізнані прапорці у %s у Ñ€Ñдку %d: %s"
+
+#, c-format
+msgid "Ignored %d words with non-ASCII characters"
+msgstr "Проігноровано %d Ñлів із не-ASCII Ñимволами"
+
+msgid "E845: Insufficient memory, word list will be incomplete"
+msgstr "E845: ÐедоÑтатньо пам’ÑÑ‚Ñ–, ÑпиÑок Ñлів буде неповним"
+
+#, c-format
+msgid "Compressed %d of %d nodes; %d (%d%%) remaining"
+msgstr "СтиÑнено %d з %d вузлів; залишилоÑÑ %d (%d%%)"
+
+msgid "Reading back spell file..."
+msgstr "ПеречитуєтьÑÑ Ñ„Ð°Ð¹Ð» орфографії..."
+
+msgid "Performing soundfolding..."
+msgstr "ВиконуєтьÑÑ Ð·Ð³Ð¾Ñ€Ñ‚Ð°Ð½Ð½Ñ Ð·Ð²ÑƒÐºÑ–Ð²..."
+
+#, c-format
+msgid "Number of words after soundfolding: %ld"
+msgstr "КількіÑÑ‚ÑŒ Ñлів піÑÐ»Ñ Ð·Ð³Ð¾Ñ€Ñ‚Ð°Ð½Ð½Ñ Ð·Ð²ÑƒÐºÑ–Ð²: %ld"
+
+#, c-format
+msgid "Total number of words: %d"
+msgstr "Повна кількіÑÑ‚ÑŒ Ñлів: %d"
+
+#, c-format
+msgid "Writing suggestion file %s..."
+msgstr "ЗапиÑуєтьÑÑ Ñ„Ð°Ð¹Ð» припущень %s..."
+
+#, c-format
+msgid "Estimated runtime memory use: %d bytes"
+msgstr "Оцінка ÑÐ¿Ð¾Ð¶Ð¸Ð²Ð°Ð½Ð½Ñ Ð¿Ð°Ð¼'ÑÑ‚Ñ–: %d байт"
+
+msgid "E751: Output file name must not have region name"
+msgstr "E751: Вихідний файл не повинен мати назву регіону"
+
+#, c-format
+msgid "E754: Only up to %ld regions supported"
+msgstr "E754: ПідтримуєтьÑÑ Ñ‚Ñ–Ð»ÑŒÐºÐ¸ до %ld регіонів"
+
+#, c-format
+msgid "E755: Invalid region in %s"
+msgstr "E755: Ðекоректний регіон у %s"
+
+msgid "Warning: both compounding and NOBREAK specified"
+msgstr "ЗаÑтереженнÑ: зазначено обидва `Ñкладні Ñлова' Ñ– NOBREAK"
+
+#, c-format
+msgid "Writing spell file %s..."
+msgstr "ЗапиÑуєтьÑÑ Ñ„Ð°Ð¹Ð» орфографії %s..."
+
+msgid "Done!"
+msgstr "Зроблено!"
+
+#, c-format
+msgid "E765: 'spellfile' does not have %ld entries"
+msgstr "E765: 'spellfile' не міÑтить %ld елементів"
+
+#, c-format
+msgid "Word '%.*s' removed from %s"
+msgstr "Слово '%.*s' знищено з %s"
+
+#, c-format
+msgid "Word '%.*s' added to %s"
+msgstr "Слово '%.*s' додано до %s"
+
+msgid "E763: Word characters differ between spell files"
+msgstr "E763: Символи у Ñлові відрізнÑÑŽÑ‚ÑŒÑÑ Ñƒ файлах орфографії"
+
+msgid "E783: duplicate char in MAP entry"
+msgstr "E783: Повторено Ñимвол у елементі MAP"
+
+# msgstr "E391: "
+msgid "No Syntax items defined for this buffer"
+msgstr "Ð”Ð»Ñ Ð±ÑƒÑ„ÐµÑ€Ð° не визначено елементів ÑинтакÑиÑу"
+
+msgid "syntax conceal on"
+msgstr "маÑÐºÑƒÐ²Ð°Ð½Ð½Ñ ÑинтакÑиÑу увімк"
+
+msgid "syntax conceal off"
+msgstr "маÑÐºÑƒÐ²Ð°Ð½Ð½Ñ ÑинтакÑиÑу вимк"
+
+#, c-format
+msgid "E390: Illegal argument: %s"
+msgstr "E390: Ðеправильний аргумент: %s"
+
+msgid "syntax case ignore"
+msgstr "ÑинтакÑÐ¸Ñ Ñ–Ð³Ð½Ð¾Ñ€ÑƒÐ²Ð°Ñ‚Ð¸ регіÑÑ‚Ñ€"
+
+msgid "syntax case match"
+msgstr "ÑинтакÑÐ¸Ñ Ð´Ð¾Ñ‚Ñ€Ð¸Ð¼ÑƒÐ²Ð°Ñ‚Ð¸ÑÑ Ñ€ÐµÐ³Ñ–Ñтру"
+
+msgid "syntax spell toplevel"
+msgstr "ÑинтакÑÐ¸Ñ Ð¿ÐµÑ€ÐµÐ²Ñ–Ñ€Ñти вÑюди"
+
+msgid "syntax spell notoplevel"
+msgstr "ÑинтакÑÐ¸Ñ Ð½Ðµ перевірÑти"
+
+msgid "syntax spell default"
+msgstr "ÑинтакÑÐ¸Ñ Ð¿Ð¾Ñ‡Ð°Ñ‚ÐºÐ¾Ð²Ð¾"
+
+msgid "syntax iskeyword "
+msgstr "ÑинтакÑÐ¸Ñ iskeyword "
+
+#, c-format
+msgid "E391: No such syntax cluster: %s"
+msgstr "E391: Ðемає такого ÑинтакÑичного клаÑтера: %s"
+
+msgid "syncing on C-style comments"
+msgstr "ÑинхронізуєтьÑÑ Ð¿Ð¾ коментарÑÑ… Ñтилю С"
+
+msgid "no syncing"
+msgstr "без Ñинхронізації"
+
+msgid "syncing starts "
+msgstr "починаєтьÑÑ ÑÐ¸Ð½Ñ…Ñ€Ð¾Ð½Ñ–Ð·Ð°Ñ†Ñ–Ñ Ð·Ð° "
+
+msgid " lines before top line"
+msgstr " Ñ€Ñдків перед першим Ñ€Ñдком"
+
+msgid ""
+"\n"
+"--- Syntax sync items ---"
+msgstr ""
+"\n"
+"--- Елементи Ñинхронізації ÑинтакÑиÑу ---"
+
+msgid ""
+"\n"
+"syncing on items"
+msgstr ""
+"\n"
+"ÑÐ¸Ð½Ñ…Ñ€Ð¾Ð½Ñ–Ð·Ð°Ñ†Ñ–Ñ Ð¿Ð¾ елементах"
+
+msgid ""
+"\n"
+"--- Syntax items ---"
+msgstr ""
+"\n"
+"--- Елементи ÑинтакÑиÑу ---"
+
+#, c-format
+msgid "E392: No such syntax cluster: %s"
+msgstr "E392: Ðемає такого ÑинтакÑичного клаÑтера: %s"
+
+msgid "minimal "
+msgstr "мінімальний "
+
+msgid "maximal "
+msgstr "макÑимальний "
+
+msgid "; match "
+msgstr "; збіг "
+
+msgid " line breaks"
+msgstr " розриви Ñ€Ñдків"
+
+msgid "E395: contains argument not accepted here"
+msgstr "E395: МіÑтить неприйнÑтні тут аргументи"
+
+# msgstr "E14: "
+msgid "E844: invalid cchar value"
+msgstr "E844: Ðекоректне Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ cchar"
+
+msgid "E393: group[t]here not accepted here"
+msgstr "E393: group[t]here тут неприйнÑтний"
+
+#, c-format
+msgid "E394: Didn't find region item for %s"
+msgstr "E394: Ðе знайдено елемент регіону Ð´Ð»Ñ %s"
+
+# msgstr "E396: "
+msgid "E397: Filename required"
+msgstr "E397: Потрібна назва файлу"
+
+msgid "E847: Too many syntax includes"
+msgstr "E847: Забагато ÑинтакÑичних включень"
+
+#, c-format
+msgid "E789: Missing ']': %s"
+msgstr "E789: Пропущено ']': %s"
+
+#, c-format
+msgid "E890: trailing char after ']': %s]%s"
+msgstr "E890: надлишкові Ñимволи піÑÐ»Ñ ']': %s]%s"
+
+#, c-format
+msgid "E398: Missing '=': %s"
+msgstr "E398: Пропущено `=': %s"
+
+# ---------------------------------------
+#, c-format
+msgid "E399: Not enough arguments: syntax region %s"
+msgstr "E399: Бракує аргументів: ÑинтакÑичний регіон %s"
+
+msgid "E848: Too many syntax clusters"
+msgstr "E848: Забагато ÑинтакÑичних клаÑтерів"
+
+msgid "E400: No cluster specified"
+msgstr "E400: КлаÑтер не вказано"
+
+#, c-format
+msgid "E401: Pattern delimiter not found: %s"
+msgstr "E401: Кінець зразку не знайдено: %s"
+
+#, c-format
+msgid "E402: Garbage after pattern: %s"
+msgstr "E402: Ð¡Ð¼Ñ–Ñ‚Ñ‚Ñ Ð¿Ñ–ÑÐ»Ñ Ð·Ñ€Ð°Ð·ÐºÑƒ: %s"
+
+# msgstr "E402: "
+msgid "E403: syntax sync: line continuations pattern specified twice"
+msgstr ""
+"E403: СинтакÑична ÑинхронізаціÑ: зразок Ð´Ð»Ñ Ð¿Ñ€Ð¾Ð´Ð¾Ð²Ð¶ÐµÐ½Ð½Ñ Ñ€Ñдка вказано двічі"
+
+#, c-format
+msgid "E404: Illegal arguments: %s"
+msgstr "E404: Ðеправильні аргументи: %s"
+
+# msgstr "E404: "
+#, c-format
+msgid "E405: Missing equal sign: %s"
+msgstr "E405: Пропущено знак рівноÑÑ‚Ñ–: %s"
+
+# msgstr "E405: "
+#, c-format
+msgid "E406: Empty argument: %s"
+msgstr "E406: Порожній аргумент: %s"
+
+# msgstr "E406: "
+#, c-format
+msgid "E407: %s not allowed here"
+msgstr "E407: %s тут не дозволено"
+
+#, c-format
+msgid "E408: %s must be first in contains list"
+msgstr "E408: %s має бути першим Ñ€Ñдком у ÑпиÑку contains"
+
+#, c-format
+msgid "E409: Unknown group name: %s"
+msgstr "E409: Ðевідома назва групи: %s"
+
+# msgstr "E409: "
+#, c-format
+msgid "E410: Invalid :syntax subcommand: %s"
+msgstr "E410: Ðеправильна підкоманда :syntax: %s"
+
+msgid ""
+" TOTAL COUNT MATCH SLOWEST AVERAGE NAME PATTERN"
+msgstr ""
+" ВСЬОГО К-ТЬ СПІВП. ÐÐЙПОВІЛ. СЕРЕДÐ. ÐÐЗВРШÐБЛОÐ"
+
+msgid "E679: recursive loop loading syncolor.vim"
+msgstr "E679: РекурÑивний цикл Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ syncolor.vim"
+
+# msgstr "E410: "
+#, c-format
+msgid "E411: highlight group not found: %s"
+msgstr "E411: Групу підÑÐ²Ñ–Ñ‡ÑƒÐ²Ð°Ð½Ð½Ñ Ð½Ðµ знайдено: %s"
+
+# msgstr "E411: "
+#, c-format
+msgid "E412: Not enough arguments: \":highlight link %s\""
+msgstr "E412: ÐедоÑтатньо аргументів: «:highlight link %s»"
+
+# msgstr "E412: "
+#, c-format
+msgid "E413: Too many arguments: \":highlight link %s\""
+msgstr "E413: Забагато аргументів: «:highlight link %s»"
+
+# msgstr "E413: "
+msgid "E414: group has settings, highlight link ignored"
+msgstr "E414: Грума має settings, highlight link проігноровано"
+
+# msgstr "E414: "
+#, c-format
+msgid "E415: unexpected equal sign: %s"
+msgstr "E415: ÐеÑподіваний знак рівноÑÑ‚Ñ–: %s"
+
+# msgstr "E415: "
+#, c-format
+msgid "E416: missing equal sign: %s"
+msgstr "E416: Пропущено знак рівноÑÑ‚Ñ–: %s"
+
+#, c-format
+msgid "E417: missing argument: %s"
+msgstr "E417: Пропущено аргумент: %s"
+
+#, c-format
+msgid "E418: Illegal value: %s"
+msgstr "E418: Ðеправильне значеннÑ: %s"
+
+# msgstr "E418: "
+msgid "E419: FG color unknown"
+msgstr "E419: Ðевідомий колір текÑту"
+
+# msgstr "E419: "
+msgid "E420: BG color unknown"
+msgstr "E420: Ðевідомий колір фону"
+
+# msgstr "E420: "
+#, c-format
+msgid "E421: Color name or number not recognized: %s"
+msgstr "E421: Ðерозпізнана назва або номер кольору: %s"
+
+# msgstr "E421: "
+#, c-format
+msgid "E422: terminal code too long: %s"
+msgstr "E422: Занадто довгий код терміналу: %s"
+
+# msgstr "E422: "
+#, c-format
+msgid "E423: Illegal argument: %s"
+msgstr "E423: Ðеправильний аргумент: %s"
+
+# msgstr "E423: "
+msgid "E424: Too many different highlighting attributes in use"
+msgstr "E424: ВикориÑтано забагато різних атрибутів кольору"
+
+msgid "E669: Unprintable character in group name"
+msgstr "E669: Ðедруковний Ñимвол у назві групи"
+
+# msgstr "E181: "
+msgid "W18: Invalid character in group name"
+msgstr "W18: Ðекоректний Ñимвол у назві групи"
+
+msgid "E849: Too many highlight and syntax groups"
+msgstr "E849: Забагато груп підÑÐ²Ñ–Ñ‡ÑƒÐ²Ð°Ð½Ð½Ñ Ñ– ÑинтакÑиÑу"
+
+# msgstr "E424: "
+msgid "E555: at bottom of tag stack"
+msgstr "E555: Кінець Ñтеку міток"
+
+msgid "E556: at top of tag stack"
+msgstr "E556: Вершина Ñтеку міток"
+
+msgid "E425: Cannot go before first matching tag"
+msgstr "E425: Це вже найперша відповідна мітка"
+
+# msgstr "E425: "
+#, c-format
+msgid "E426: tag not found: %s"
+msgstr "E426: Мітку не знайдено: %s"
+
+# msgstr "E426: "
+msgid " # pri kind tag"
+msgstr " # прі тип мітка"
+
+msgid "file\n"
+msgstr "файл\n"
+
+msgid "E427: There is only one matching tag"
+msgstr "E427: Лише одна відповідна мітка"
+
+# msgstr "E427: "
+msgid "E428: Cannot go beyond last matching tag"
+msgstr "E428: Це вже оÑÑ‚Ð°Ð½Ð½Ñ Ð²Ñ–Ð´Ð¿Ð¾Ð²Ñ–Ð´Ð½Ð° мітка"
+
+# msgstr "E428: "
+#, c-format
+msgid "File \"%s\" does not exist"
+msgstr "Файл «%s» не Ñ–Ñнує"
+
+#, c-format
+msgid "tag %d of %d%s"
+msgstr "мітка %d з %d%s"
+
+msgid " or more"
+msgstr " або більше"
+
+msgid " Using tag with different case!"
+msgstr " ВикориÑтано мітку, не розрізнÑючи великі й малі літери"
+
+#, c-format
+msgid "E429: File \"%s\" does not exist"
+msgstr "E429: Файл «%s» не Ñ–Ñнує"
+
+# msgstr "E429: "
+msgid ""
+"\n"
+" # TO tag FROM line in file/text"
+msgstr ""
+"\n"
+" # ДО мітки З Ñ€Ñдка у файлі/текÑÑ‚Ñ–"
+
+#, c-format
+msgid "Searching tags file %s"
+msgstr "ШукаєтьÑÑ Ñƒ файлі міток %s"
+
+#, c-format
+msgid "E430: Tag file path truncated for %s\n"
+msgstr "E430: ШлÑÑ… файлу міток Ñкорочено до %s\n"
+
+msgid "Ignoring long line in tags file"
+msgstr "ІгноруєтьÑÑ Ð´Ð¾Ð²Ð³Ð¸Ð¹ Ñ€Ñдок у файлі з позначками"
+
+# msgstr "E430: "
+#, c-format
+msgid "E431: Format error in tags file \"%s\""
+msgstr "E431: Помилка формату у файлі міток «%s»"
+
+# msgstr "E431: "
+#, c-format
+msgid "Before byte %ld"
+msgstr "Перед байтом %ld"
+
+#, c-format
+msgid "E432: Tags file not sorted: %s"
+msgstr "E432: Файл міток не впорÑдкований: %s"
+
+# msgstr "E432: "
+msgid "E433: No tags file"
+msgstr "E433: Ðемає файлу міток"
+
+# msgstr "E433: "
+msgid "E434: Can't find tag pattern"
+msgstr "E434: Ðе вдалоÑÑ Ð·Ð½Ð°Ð¹Ñ‚Ð¸ зразок мітки"
+
+# msgstr "E434: "
+msgid "E435: Couldn't find tag, just guessing!"
+msgstr "E435: Ðе вдалоÑÑ Ð·Ð½Ð°Ð¹Ñ‚Ð¸ мітку, тільки припущеннÑ!"
+
+#, c-format
+msgid "Duplicate field name: %s"
+msgstr "Ðазва Ð¿Ð¾Ð»Ñ Ð¿Ð¾Ð²Ñ‚Ð¾Ñ€ÑŽÑ”Ñ‚ÑŒÑÑ: %s"
+
+# msgstr "E435: "
+msgid "' not known. Available builtin terminals are:"
+msgstr "' не відомий. Вбудовані термінали:"
+
+msgid "defaulting to '"
+msgstr "початково '"
+
+msgid "E557: Cannot open termcap file"
+msgstr "E557: Ðе вдалоÑÑ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸ файл можливоÑтей терміналів"
+
+msgid "E558: Terminal entry not found in terminfo"
+msgstr "E558: Ðемає інформації про термінал"
+
+msgid "E559: Terminal entry not found in termcap"
+msgstr "E559: Ðемає інформації про можливоÑÑ‚Ñ– терміналу"
+
+#, c-format
+msgid "E436: No \"%s\" entry in termcap"
+msgstr "E436: Ðемає запиÑу «%s» про можливоÑÑ‚Ñ– терміналу"
+
+msgid "E437: terminal capability \"cm\" required"
+msgstr "E437: Потрібна можливіÑÑ‚ÑŒ терміналу «cm»"
+
+msgid ""
+"\n"
+"--- Terminal keys ---"
+msgstr ""
+"\n"
+"--- Клавіші терміналу ---"
+
+msgid "Cannot open $VIMRUNTIME/rgb.txt"
+msgstr "Ðеможливо відкрити $VIMRUNTIME/rgb.txt"
+
+#, c-format
+msgid "Kill job in \"%s\"?"
+msgstr "Зупинити Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ñƒ «%s»?"
+
+msgid "Terminal"
+msgstr "Термінал"
+
+msgid "Terminal-finished"
+msgstr "Термінал-закінчено"
+
+msgid "active"
+msgstr "активний"
+
+msgid "running"
+msgstr "виконуєтьÑÑ"
+
+msgid "finished"
+msgstr "закінчено"
+
+# msgstr "E226: "
+#, c-format
+msgid "E953: File exists: %s"
+msgstr "E953: Файл вже Ñ–Ñнує: %s"
+
+msgid "E955: Not a terminal buffer"
+msgstr "E955: Ðе буфер терміналу"
+
+msgid "new shell started\n"
+msgstr "запущено нову оболонку\n"
+
+msgid "Vim: Error reading input, exiting...\n"
+msgstr "Vim: Помилка Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ Ð²Ð²Ð¾Ð´Ñƒ, робота завершуєтьÑÑ...\n"
+
+# msgstr "E242: "
+msgid "Used CUT_BUFFER0 instead of empty selection"
+msgstr "ВикориÑтано CUT_BUFFER0 заміÑÑ‚ÑŒ порожнього виділеннÑ"
+
+msgid "E881: Line count changed unexpectedly"
+msgstr "E881: КількіÑÑ‚ÑŒ Ñ€Ñдків неÑподівано змінилаÑÑ"
+
+msgid "No undo possible; continue anyway"
+msgstr "СкаÑÑƒÐ²Ð°Ð½Ð½Ñ Ð±ÑƒÐ´Ðµ неможливе, вÑе одно продовжити"
+
+#, c-format
+msgid "E828: Cannot open undo file for writing: %s"
+msgstr "E828: Ðе вдалоÑÑ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸ файл Ñ–Ñторії Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñу: %s"
+
+#, c-format
+msgid "E825: Corrupted undo file (%s): %s"
+msgstr "E825: Файл Ñ–Ñторії пошкоджено (%s): %s"
+
+msgid "Cannot write undo file in any directory in 'undodir'"
+msgstr "Ðе вдалоÑÑ Ð·Ð°Ð¿Ð¸Ñати файл Ñ–Ñторії у жодну з директорій у 'undodir'"
+
+#, c-format
+msgid "Will not overwrite with undo file, cannot read: %s"
+msgstr "Ðе можна перезапиÑати з файлу ÑкаÑувань, не можна прочитати: %s"
+
+#, c-format
+msgid "Will not overwrite, this is not an undo file: %s"
+msgstr "Ðе можна перезапиÑати, це не файл Ñ–Ñторії: %s"
+
+msgid "Skipping undo file write, nothing to undo"
+msgstr "Файл Ñ–Ñторії не запиÑуєтьÑÑ, нічого повертати"
+
+#, c-format
+msgid "Writing undo file: %s"
+msgstr "ЗапиÑуєтьÑÑ Ñ„Ð°Ð¹Ð» Ñ–Ñторії: %s"
+
+#, c-format
+msgid "E829: write error in undo file: %s"
+msgstr "E829: Помилка запиÑу у файлі Ñ–Ñторії: %s"
+
+#, c-format
+msgid "Not reading undo file, owner differs: %s"
+msgstr "Файл Ñ–Ñторії прочитано не буде, влаÑник інший: %s"
+
+#, c-format
+msgid "Reading undo file: %s"
+msgstr "ЧитаєтьÑÑ Ñ„Ð°Ð¹Ð» Ñ–Ñторії: %s"
+
+#, c-format
+msgid "E822: Cannot open undo file for reading: %s"
+msgstr "E822: Ðе вдалоÑÑ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸ файл Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ: %s"
+
+# msgstr "E333: "
+#, c-format
+msgid "E823: Not an undo file: %s"
+msgstr "E823: Ðе файл Ñ–Ñторії: %s"
+
+#, c-format
+msgid "E832: Non-encrypted file has encrypted undo file: %s"
+msgstr "E832: Ðе зашифрований файл має зашифрований файл Ñ–Ñторії: %s"
+
+#, c-format
+msgid "E826: Undo file decryption failed: %s"
+msgstr "E826: Ðе вдалоÑÑ Ñ€Ð¾Ð·ÑˆÐ¸Ñ„Ñ€ÑƒÐ²Ð°Ñ‚Ð¸ файл Ñ–Ñторії: %s"
+
+#, c-format
+msgid "E827: Undo file is encrypted: %s"
+msgstr "E827: Файл Ñ–Ñторії зашифрований: %s"
+
+#, c-format
+msgid "E824: Incompatible undo file: %s"
+msgstr "E824: ÐеÑуміÑний файл Ñ–Ñторії: %s"
+
+msgid "File contents changed, cannot use undo info"
+msgstr "ВміÑÑ‚ файлу змінивÑÑ, не можна викориÑтати інформацію про Ñ–Ñторію"
+
+#, c-format
+msgid "Finished reading undo file %s"
+msgstr "Закінчено Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ Ñ„Ð°Ð¹Ð»Ñƒ Ñ–Ñторії %s"
+
+msgid "Already at oldest change"
+msgstr "Вже на найÑтаршій зміні"
+
+msgid "Already at newest change"
+msgstr "Вже на найновішій зміні"
+
+#, c-format
+msgid "E830: Undo number %ld not found"
+msgstr "E830: Зміну %ld не знайдено в Ñ–Ñторії"
+
+msgid "E438: u_undo: line numbers wrong"
+msgstr "E438: u_undo: неправильні номери Ñ€Ñдків"
+
+msgid "more line"
+msgstr "додано Ñ€Ñдок"
+
+msgid "more lines"
+msgstr "Ñ€Ñдків додано"
+
+msgid "line less"
+msgstr "знищено Ñ€Ñдок"
+
+msgid "fewer lines"
+msgstr "Ñ€Ñдків знищено"
+
+# msgstr "E438: "
+msgid "change"
+msgstr "зміна"
+
+# msgstr "E438: "
+msgid "changes"
+msgstr "змін"
+
+#, c-format
+msgid "%ld %s; %s #%ld %s"
+msgstr "%ld %s; %s #%ld %s"
+
+msgid "before"
+msgstr "перед"
+
+msgid "after"
+msgstr "піÑлÑ"
+
+msgid "Nothing to undo"
+msgstr "Ðемає нічого ÑкаÑовувати"
+
+msgid "number changes when saved"
+msgstr "номер зміни Ñ‡Ð°Ñ Ð·Ð±ÐµÑ€ÐµÐ¶ÐµÐ½Ð¾"
+
+#, c-format
+msgid "%ld seconds ago"
+msgstr "%ld Ñекунд тому"
+
+# msgstr "E406: "
+msgid "E790: undojoin is not allowed after undo"
+msgstr "E790: Ðе можна виконати undojoin піÑÐ»Ñ undo"
+
+msgid "E439: undo list corrupt"
+msgstr "E439: СпиÑок ÑкаÑÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ð¾ÑˆÐºÐ¾Ð´Ð¶ÐµÐ½Ð¾"
+
+# msgstr "E439: "
+msgid "E440: undo line missing"
+msgstr "E440: ВідÑутній Ñ€Ñдок ÑкаÑуваннÑ"
+
+#, c-format
+msgid "E122: Function %s already exists, add ! to replace it"
+msgstr "E122: Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ %s уже Ñ–Ñнує, ! щоб замінити"
+
+msgid "E717: Dictionary entry already exists"
+msgstr "E717: Ð—Ð°Ð¿Ð¸Ñ Ñƒ Ñловнику вже Ñ–Ñнує"
+
+msgid "E718: Funcref required"
+msgstr "E718: Треба поÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð½Ð° функцію"
+
+#, c-format
+msgid "E130: Unknown function: %s"
+msgstr "E130: Ðевідома функціÑ: %s"
+
+#, c-format
+msgid "E125: Illegal argument: %s"
+msgstr "E125: Ðедозволений аргумент: %s"
+
+#, c-format
+msgid "E853: Duplicate argument name: %s"
+msgstr "E853: Ðазва аргументу повторюєтьÑÑ: %s"
+
+#, c-format
+msgid "E740: Too many arguments for function %s"
+msgstr "E740: Забагато аргументів Ð´Ð»Ñ Ñ„ÑƒÐ½ÐºÑ†Ñ–Ñ— %s"
+
+#, c-format
+msgid "E116: Invalid arguments for function %s"
+msgstr "E116: Ðеправильні аргументи функції %s"
+
+msgid "E132: Function call depth is higher than 'maxfuncdepth'"
+msgstr "E132: Глибина викликів функції перевищує 'maxfuncdepth'"
+
+#, c-format
+msgid "calling %s"
+msgstr "викликаєтьÑÑ %s"
+
+#, c-format
+msgid "%s aborted"
+msgstr "%s припинено"
+
+#, c-format
+msgid "%s returning #%ld"
+msgstr "%s повертає #%ld"
+
+#, c-format
+msgid "%s returning %s"
+msgstr "%s повертає %s"
+
+msgid "E699: Too many arguments"
+msgstr "E699: Забагато аргументів"
+
+#, c-format
+msgid "E117: Unknown function: %s"
+msgstr "E117: Ðевідома функціÑ: %s"
+
+#, c-format
+msgid "E933: Function was deleted: %s"
+msgstr "E933: Функцію видалено: %s"
+
+#, c-format
+msgid "E119: Not enough arguments for function: %s"
+msgstr "E119: Замало аргументів Ð´Ð»Ñ Ñ„ÑƒÐ½ÐºÑ†Ñ–Ñ— %s"
+
+#, c-format
+msgid "E120: Using <SID> not in a script context: %s"
+msgstr "E120: <SID> викориÑтовуєтьÑÑ Ð½Ðµ у контекÑÑ‚Ñ– Ñкрипту: %s"
+
+#, c-format
+msgid "E725: Calling dict function without Dictionary: %s"
+msgstr "E725: Виклик dict-функції без Ñловника: %s"
+
+msgid "E129: Function name required"
+msgstr "E129: Ðе вказано назву функції"
+
+#, c-format
+msgid "E128: Function name must start with a capital or \"s:\": %s"
+msgstr "E128: Ðазва функції має починатиÑÑ Ð· великої літери або «s:»: %s"
+
+#, c-format
+msgid "E884: Function name cannot contain a colon: %s"
+msgstr "E884: Ðазва функції не може мати двокрапку: %s"
+
+#, c-format
+msgid "E123: Undefined function: %s"
+msgstr "E123: Ðевизначена функціÑ: %s"
+
+#, c-format
+msgid "E124: Missing '(': %s"
+msgstr "E124: Бракує '(': %s"
+
+msgid "E862: Cannot use g: here"
+msgstr "E862: Тут не можна викориÑтати g:"
+
+#, c-format
+msgid "E932: Closure function should not be at top level: %s"
+msgstr "E932: Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ Ð·Ð°Ð¼Ð¸ÐºÐ°Ð½Ð½Ñ Ð½Ðµ повинна бути на верхньому рівні: %s"
+
+msgid "E126: Missing :endfunction"
+msgstr "E126: Бракує :endfunction"
+
+#, c-format
+msgid "W22: Text found after :endfunction: %s"
+msgstr "W22: ТрапивÑÑ Ñ‚ÐµÐºÑÑ‚ піÑÐ»Ñ :endfunction: %s"
+
+#, c-format
+msgid "E707: Function name conflicts with variable: %s"
+msgstr "E707: Ðазва функції Ñпівпадає зі змінною: %s"
+
+#, c-format
+msgid "E127: Cannot redefine function %s: It is in use"
+msgstr "E127: Ðе вдалоÑÑ Ð¿ÐµÑ€ÐµÐ²Ð¸Ð·Ð½Ð°Ñ‡Ð¸Ñ‚Ð¸ функцію %s: вона викориÑтовуєтьÑÑ"
+
+#, c-format
+msgid "E746: Function name does not match script file name: %s"
+msgstr "E746: Ðазва функції не збігаєтьÑÑ Ð· назвою файлу Ñкрипту: %s"
+
+#, c-format
+msgid "E131: Cannot delete function %s: It is in use"
+msgstr "E131: Ðе вдалоÑÑ Ð·Ð½Ð¸Ñ‰Ð¸Ñ‚Ð¸ функцію %s: Вона викориÑтовуєтьÑÑ"
+
+msgid "E133: :return not inside a function"
+msgstr "E133: :return поза межами функції"
+
+#, c-format
+msgid "E107: Missing parentheses: %s"
+msgstr "E107: Пропущено дужки: %s"
+
+msgid ""
+"\n"
+"MS-Windows 64-bit GUI version"
+msgstr ""
+"\n"
+"ВерÑÑ–Ñ Ð· GUI Ð´Ð»Ñ 64-розрÑдної MS-Windows"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit GUI version"
+msgstr ""
+"\n"
+"ВерÑÑ–Ñ Ð· GUI Ð´Ð»Ñ 32-розрÑдної Windows"
+
+msgid " with OLE support"
+msgstr " з підтримкою OLE"
+
+msgid ""
+"\n"
+"MS-Windows 64-bit console version"
+msgstr ""
+"\n"
+"КонÑольна верÑÑ–Ñ Ð´Ð»Ñ 64-розрÑдної Windows"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit console version"
+msgstr ""
+"\n"
+"КонÑольна верÑÑ–Ñ Ð´Ð»Ñ 32-розрÑдної Windows"
+
+msgid ""
+"\n"
+"macOS version"
+msgstr ""
+"\n"
+"ВерÑÑ–Ñ macOS"
+
+msgid ""
+"\n"
+"macOS version w/o darwin feat."
+msgstr ""
+"\n"
+"ВерÑÑ–Ñ macOS без darwin."
+
+msgid ""
+"\n"
+"OpenVMS version"
+msgstr ""
+"\n"
+"ВерÑÑ–Ñ Ð´Ð»Ñ OpenVMS"
+
+msgid ""
+"\n"
+"Included patches: "
+msgstr ""
+"\n"
+"Включені латки: "
+
+msgid ""
+"\n"
+"Extra patches: "
+msgstr ""
+"\n"
+"Додаткові латки: "
+
+msgid "Modified by "
+msgstr "Змінив "
+
+msgid ""
+"\n"
+"Compiled "
+msgstr ""
+"\n"
+"Скомпілював "
+
+msgid "by "
+msgstr " "
+
+msgid ""
+"\n"
+"Huge version "
+msgstr ""
+"\n"
+"ГігантÑька верÑÑ–Ñ "
+
+msgid ""
+"\n"
+"Big version "
+msgstr ""
+"\n"
+"Велика верÑÑ–Ñ "
+
+msgid ""
+"\n"
+"Normal version "
+msgstr ""
+"\n"
+"Ðормальна верÑÑ–Ñ "
+
+msgid ""
+"\n"
+"Small version "
+msgstr ""
+"\n"
+"Мала верÑÑ–Ñ "
+
+msgid ""
+"\n"
+"Tiny version "
+msgstr ""
+"\n"
+"Крихітна верÑÑ–Ñ "
+
+msgid "without GUI."
+msgstr "без GUI."
+
+msgid "with GTK3 GUI."
+msgstr "з GUI GTK3."
+
+msgid "with GTK2-GNOME GUI."
+msgstr "з GUI GTK2-GNOME."
+
+msgid "with GTK2 GUI."
+msgstr "з GUI GTK2."
+
+msgid "with X11-Motif GUI."
+msgstr "з GUI X11-Motif."
+
+msgid "with X11-neXtaw GUI."
+msgstr "з GUI X11-neXtaw."
+
+msgid "with X11-Athena GUI."
+msgstr "з GUI X11-Athena."
+
+msgid "with Photon GUI."
+msgstr "з GUI Photon."
+
+msgid "with GUI."
+msgstr "з GUI."
+
+msgid "with Carbon GUI."
+msgstr "з GUI Carbon."
+
+msgid "with Cocoa GUI."
+msgstr "з GUI Cocoa."
+
+msgid " Features included (+) or not (-):\n"
+msgstr " Включені (+) або не включені (-) компоненти:\n"
+
+msgid " system vimrc file: \""
+msgstr " ÑиÑтемний vimrc: \""
+
+msgid " user vimrc file: \""
+msgstr " vimrc кориÑтувача: \""
+
+msgid " 2nd user vimrc file: \""
+msgstr " другий vimrc кориÑтувача: \""
+
+msgid " 3rd user vimrc file: \""
+msgstr " третій vimrc кориÑтувача: \""
+
+msgid " user exrc file: \""
+msgstr " exrc кориÑтувача: \""
+
+msgid " 2nd user exrc file: \""
+msgstr " другий exrc кориÑтувача: \""
+
+msgid " system gvimrc file: \""
+msgstr " ÑиÑтемний gvimrc: \""
+
+msgid " user gvimrc file: \""
+msgstr " gvimrc кориÑтувача: \""
+
+msgid "2nd user gvimrc file: \""
+msgstr "другий gvimrc кориÑтувача: \""
+
+msgid "3rd user gvimrc file: \""
+msgstr "третій gvimrc кориÑтувача: \""
+
+msgid " defaults file: \""
+msgstr " файл defaults: \""
+
+msgid " system menu file: \""
+msgstr " ÑиÑтемне меню: \""
+
+msgid " fall-back for $VIM: \""
+msgstr " заміна Ð´Ð»Ñ $VIM: \""
+
+msgid " f-b for $VIMRUNTIME: \""
+msgstr " заміна Ð´Ð»Ñ $VIMRUNTIME: \""
+
+msgid "Compilation: "
+msgstr "Скомпільовано: "
+
+msgid "Compiler: "
+msgstr "КомпілÑтор: "
+
+msgid "Linking: "
+msgstr "Скомпоновано: "
+
+msgid " DEBUG BUILD"
+msgstr " ВЕРСІЯ ДЛЯ ÐÐЛÐГОДЖЕÐÐЯ"
+
+msgid "VIM - Vi IMproved"
+msgstr "VIM - Покращений Vi"
+
+msgid "version "
+msgstr "верÑÑ–Ñ "
+
+msgid "by Bram Moolenaar et al."
+msgstr "автор: Bram Moolenaar та ін."
+
+msgid "Vim is open source and freely distributable"
+msgstr "Vim — це відкрита й вільно розповÑюджувана програма"
+
+msgid "Help poor children in Uganda!"
+msgstr "Допоможіть Ñиротам з Уганди!"
+
+msgid "type :help iccf<Enter> for information "
+msgstr ":help iccf<Enter> подробиці "
+
+msgid "type :q<Enter> to exit "
+msgstr ":q<Enter> вихід з Vim "
+
+msgid "type :help<Enter> or <F1> for on-line help"
+msgstr ":help<Enter> або <F1> переглÑд допомоги "
+
+msgid "type :help version8<Enter> for version info"
+msgstr ":help version8<Enter> Ñ–Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ñ–Ñ Ð¿Ñ€Ð¾ верÑÑ–ÑŽ "
+
+msgid "Running in Vi compatible mode"
+msgstr "Ви працюєте в режимі ÑуміÑному з Vi"
+
+msgid "type :set nocp<Enter> for Vim defaults"
+msgstr ":set nocp<Enter> режим неÑуміÑний з Vi "
+
+msgid "type :help cp-default<Enter> for info on this"
+msgstr ":help cp-default<Enter> Ñ–Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ñ–Ñ Ð¿Ñ€Ð¾ ÑуміÑніÑÑ‚ÑŒ"
+
+msgid "menu Help->Orphans for information "
+msgstr "меню Help->Orphans подальша Ñ–Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ñ–Ñ "
+
+msgid "Running modeless, typed text is inserted"
+msgstr "Без режимів, текÑÑ‚ що набрано вÑтавлÑєтьÑÑ"
+
+msgid "menu Edit->Global Settings->Toggle Insert Mode "
+msgstr "меню Edit->Global Settings->Toggle Insert Mode "
+
+msgid " for two modes "
+msgstr " Ð´Ð»Ñ Ð´Ð²Ð¾Ñ… режимів "
+
+msgid "menu Edit->Global Settings->Toggle Vi Compatible"
+msgstr "меню Edit->Global Settings->Toggle Vi Compatible "
+
+msgid " for Vim defaults "
+msgstr " щоб починати в режимі ÑуміÑноÑÑ‚Ñ– з Vi"
+
+msgid "Sponsor Vim development!"
+msgstr "Підтримайте розробку редактора Vim!"
+
+msgid "Become a registered Vim user!"
+msgstr "Станьте зареєÑтрованим кориÑтувачем Vim!"
+
+msgid "type :help sponsor<Enter> for information "
+msgstr ":help sponsor<Enter> подальша Ñ–Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ñ–Ñ "
+
+msgid "type :help register<Enter> for information "
+msgstr ":help register<Enter> подальша Ñ–Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ñ–Ñ "
+
+msgid "menu Help->Sponsor/Register for information "
+msgstr "меню Допомога->СпонÑор/РеєÑÑ‚Ñ€Ð°Ñ†Ñ–Ñ Ð¿Ð¾Ð´Ñ€Ð¾Ð±Ð¸Ñ†Ñ– "
+
+# msgstr "E444: "
+msgid "Already only one window"
+msgstr "Це вже єдине вікно"
+
+msgid "E441: There is no preview window"
+msgstr "E441: Ðемає вікна переглÑду"
+
+# msgstr "E441: "
+msgid "E442: Can't split topleft and botright at the same time"
+msgstr "E442: Ðе вдалоÑÑ Ð¾Ð´Ð½Ð¾Ñ‡Ð°Ñно розбити topleft Ñ– botright"
+
+# msgstr "E442: "
+msgid "E443: Cannot rotate when another window is split"
+msgstr "E443: Ðе вдалоÑÑ Ð¿ÐµÑ€ÐµÐ¼Ñ–Ñтити вікно, заважають інші"
+
+# msgstr "E443: "
+msgid "E444: Cannot close last window"
+msgstr "E444: Ðе вдалоÑÑ Ð·Ð°ÐºÑ€Ð¸Ñ‚Ð¸ оÑтаннє вікно"
+
+# msgstr "E443: "
+msgid "E813: Cannot close autocmd window"
+msgstr "E813: Ðе вдалоÑÑ Ð·Ð°ÐºÑ€Ð¸Ñ‚Ð¸ вікно autocmd"
+
+# msgstr "E443: "
+msgid "E814: Cannot close window, only autocmd window would remain"
+msgstr "E814: Ðе вдалоÑÑ Ð·Ð°ÐºÑ€Ð¸Ñ‚Ð¸ вікно, залишилоÑÑ Ð± тільки вікно autocmd"
+
+msgid "E445: Other window contains changes"
+msgstr "E445: У іншому вікні є зміни"
+
+# msgstr "E445: "
+msgid "E446: No file name under cursor"
+msgstr "E446: Ðемає назви файлу над курÑором"
+
+# msgstr "E446: "
+#, c-format
+msgid "E447: Can't find file \"%s\" in path"
+msgstr "E447: Файл «%s» не знайдено у шлÑху пошуку"
+
+#, c-format
+msgid "E799: Invalid ID: %ld (must be greater than or equal to 1)"
+msgstr "E799: Ðеправильний ID: %ld (має бути не менший, ніж 1)"
+
+#, c-format
+msgid "E801: ID already taken: %ld"
+msgstr "E801: ID вже зайнÑто: %ld"
+
+# msgstr "E396: "
+msgid "List or number required"
+msgstr "Потрібен ÑпиÑок чи чиÑло"
+
+#, c-format
+msgid "E802: Invalid ID: %ld (must be greater than or equal to 1)"
+msgstr "E802: Ðеправильний ID: %ld (має бути не менший, ніж 1)"
+
+# msgstr "E333: "
+#, c-format
+msgid "E803: ID not found: %ld"
+msgstr "E803: ID не знайдено: %ld"
+
+#, c-format
+msgid "E370: Could not load library %s"
+msgstr "E370: Ðе вдалоÑÑ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶Ð¸Ñ‚Ð¸ бібліотеку %s"
+
+msgid "Sorry, this command is disabled: the Perl library could not be loaded."
+msgstr ""
+"Вибачте, Ñ†Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð° вимкнена, бібліотека Perl не може бути завантажена."
+
+msgid "E299: Perl evaluation forbidden in sandbox without the Safe module"
+msgstr "E299: ОбчиÑÐ»ÐµÐ½Ð½Ñ Ð²Ð¸Ñ€Ð°Ð·Ñ–Ð² Perl заборонене у піÑочниці без Ð¼Ð¾Ð´ÑƒÐ»Ñ Safe"
+
+msgid "Edit with &multiple Vims"
+msgstr "Редагувати у (&m)різних Vim"
+
+msgid "Edit with single &Vim"
+msgstr "Редагувати у одному &Vim"
+
+msgid "Diff with Vim"
+msgstr "ПорівнÑти з допомогою Vim"
+
+msgid "Edit with &Vim"
+msgstr "Редагувати за допомогою &Vim"
+
+msgid "Edit with existing Vim - "
+msgstr "Редагувати у вже запущеному Vim - "
+
+msgid "Edits the selected file(s) with Vim"
+msgstr "Редагує вибрані файли з допомогою Vim"
+
+msgid "Error creating process: Check if gvim is in your path!"
+msgstr "Помилка ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾Ñ†ÐµÑу, перевірте чи Ñ” gvim у шлÑху пошуку!"
+
+msgid "gvimext.dll error"
+msgstr "помилка gvimext.dll"
+
+msgid "Path length too long!"
+msgstr "ШлÑÑ… занадто довгий!"
+
+# msgstr "E447: "
+msgid "--No lines in buffer--"
+msgstr "--Жодного Ñ€Ñдка--"
+
+msgid "E470: Command aborted"
+msgstr "E470: Команду перервано"
+
+msgid "E471: Argument required"
+msgstr "E471: Ðеобхідно вказати аргумент"
+
+msgid "E10: \\ should be followed by /, ? or &"
+msgstr "E10: За \\ має йти /, ? або &"
+
+# msgstr "E10: "
+msgid "E11: Invalid in command-line window; <CR> executes, CTRL-C quits"
+msgstr "E11: ÐеприпуÑтимо у вікні команд, <CR> виконує, CTRL-C виходить"
+
+msgid "E12: Command not allowed from exrc/vimrc in current dir or tag search"
+msgstr ""
+"E12: Команда не дозволена у exrc/vimrc у пошуку поточного каталогу чи теґу"
+
+msgid "E171: Missing :endif"
+msgstr "E171: Бракує :endif"
+
+msgid "E600: Missing :endtry"
+msgstr "E600: Бракує :endtry"
+
+msgid "E170: Missing :endwhile"
+msgstr "E170: Бракує :endwhile"
+
+msgid "E170: Missing :endfor"
+msgstr "E170: Бракує :endfor"
+
+msgid "E588: :endwhile without :while"
+msgstr "E588: :endwhile без :while"
+
+msgid "E588: :endfor without :for"
+msgstr "E588: :endfor без :for"
+
+msgid "E13: File exists (add ! to override)"
+msgstr "E13: Файл Ñ–Ñнує (! щоб не зважати)"
+
+msgid "E472: Command failed"
+msgstr "E472: Команда на вдалаÑÑŒ"
+
+# msgstr "E233: "
+#, c-format
+msgid "E234: Unknown fontset: %s"
+msgstr "E234: Ðевідомий набір шрифтів: %s"
+
+#, c-format
+msgid "E235: Unknown font: %s"
+msgstr "E235: Ðевідомий шрифт: %s"
+
+# msgstr "E235: "
+#, c-format
+msgid "E236: Font \"%s\" is not fixed-width"
+msgstr "E236: Шрифт «%s» не моноширинний"
+
+msgid "E473: Internal error"
+msgstr "E473: Ð’Ð½ÑƒÑ‚Ñ€Ñ–ÑˆÐ½Ñ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ°"
+
+#, c-format
+msgid "E685: Internal error: %s"
+msgstr "E685: Ð’Ð½ÑƒÑ‚Ñ€Ñ–ÑˆÐ½Ñ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ°: %s"
+
+msgid "Interrupted"
+msgstr "Перервано"
+
+msgid "E14: Invalid address"
+msgstr "E14: Ðеправильна адреÑа"
+
+# msgstr "E14: "
+msgid "E474: Invalid argument"
+msgstr "E474: Ðекоректний аргумент"
+
+#, c-format
+msgid "E475: Invalid argument: %s"
+msgstr "E475: Ðекоректний аргумент: %s"
+
+#, c-format
+msgid "E475: Invalid value for argument %s"
+msgstr "E475: Ðекоректне Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð´Ð»Ñ Ð°Ñ€Ð³ÑƒÐ¼ÐµÐ½Ñ‚Ñƒ %s"
+
+#, c-format
+msgid "E475: Invalid value for argument %s: %s"
+msgstr "E475: Ðекоректне Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð´Ð»Ñ Ð°Ñ€Ð³ÑƒÐ¼ÐµÐ½Ñ‚Ñƒ %s: %s"
+
+#, c-format
+msgid "E15: Invalid expression: %s"
+msgstr "E15: Ðеправильний вираз: %s"
+
+# msgstr "E15: "
+msgid "E16: Invalid range"
+msgstr "E16: Ðеправильні межі"
+
+# msgstr "E16: "
+msgid "E476: Invalid command"
+msgstr "E476: Ðекоректна команда"
+
+#, c-format
+msgid "E17: \"%s\" is a directory"
+msgstr "E17: «%s» — це каталог"
+
+#, c-format
+msgid "E364: Library call failed for \"%s()\""
+msgstr "E364: Бібліотечний виклик до «%s()» не вдавÑÑ"
+
+msgid "E667: Fsync failed"
+msgstr "E667: Ðе вдалоÑÑ Ð²Ð¸ÐºÐ¾Ð½Ð°Ñ‚Ð¸ fsync"
+
+#, c-format
+msgid "E448: Could not load library function %s"
+msgstr "E448: Ðе вдалоÑÑ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶Ð¸Ñ‚Ð¸ бібліотечну функцію %s"
+
+# msgstr "E18: "
+msgid "E19: Mark has invalid line number"
+msgstr "E19: У помітки некоректний номер Ñ€Ñдка"
+
+# msgstr "E19: "
+msgid "E20: Mark not set"
+msgstr "E20: Помітку не вÑтановлено"
+
+# msgstr "E20: "
+msgid "E21: Cannot make changes, 'modifiable' is off"
+msgstr "E21: Зміни не дозволені: вимкнено 'modifiable'"
+
+# msgstr "E21: "
+msgid "E22: Scripts nested too deep"
+msgstr "E22: Забагато вкладених Ñкриптів"
+
+# msgstr "E22: "
+msgid "E23: No alternate file"
+msgstr "E23: Ðемає вторинного файлу"
+
+# msgstr "E23: "
+msgid "E24: No such abbreviation"
+msgstr "E24: Такого ÑÐºÐ¾Ñ€Ð¾Ñ‡ÐµÐ½Ð½Ñ Ð½ÐµÐ¼Ð°Ñ”"
+
+# msgstr "E24: "
+msgid "E477: No ! allowed"
+msgstr "E477: ! не дозволено"
+
+msgid "E25: GUI cannot be used: Not enabled at compile time"
+msgstr "E25: Ðе можна викориÑтати GUI: Ðе ввімкнено під Ñ‡Ð°Ñ ÐºÐ¾Ð¼Ð¿Ñ–Ð»Ñції"
+
+msgid "E26: Hebrew cannot be used: Not enabled at compile time\n"
+msgstr "E26: Ðе можна викориÑтати іврит: Ðе ввімкнено під Ñ‡Ð°Ñ ÐºÐ¾Ð¼Ð¿Ñ–Ð»Ñції\n"
+
+msgid "E27: Farsi cannot be used: Not enabled at compile time\n"
+msgstr "E27: Ðе можна викориÑтати фарÑÑ–: Ðе ввімкнено під Ñ‡Ð°Ñ ÐºÐ¾Ð¼Ð¿Ñ–Ð»Ñції\n"
+
+msgid "E800: Arabic cannot be used: Not enabled at compile time\n"
+msgstr ""
+"E800: Ðе можна викориÑтати арабÑьку мову: Ðе ввімкнено під Ñ‡Ð°Ñ ÐºÐ¾Ð¼Ð¿Ñ–Ð»Ñції\n"
+
+# msgstr "E25: "
+#, c-format
+msgid "E28: No such highlight group name: %s"
+msgstr "E28: Ðемає такої групи підÑвічуваннÑ: %s"
+
+# msgstr "E28: "
+msgid "E29: No inserted text yet"
+msgstr "E29: ТекÑÑ‚ ще не було додано"
+
+# msgstr "E29: "
+msgid "E30: No previous command line"
+msgstr "E30: Ще не було команд"
+
+# msgstr "E30: "
+msgid "E31: No such mapping"
+msgstr "E31: Ðемає такої заміни"
+
+# msgstr "E31: "
+msgid "E479: No match"
+msgstr "E479: Жодного збігу"
+
+#, c-format
+msgid "E480: No match: %s"
+msgstr "E480: Жодного збігу: %s"
+
+msgid "E32: No file name"
+msgstr "E32: Бракує назви файлу"
+
+# msgstr "E32: "
+msgid "E33: No previous substitute regular expression"
+msgstr "E33: Заміна зразків ще не викориÑтовувалаÑÑŒ"
+
+# msgstr "E33: "
+msgid "E34: No previous command"
+msgstr "E34: Команд ще не було"
+
+# msgstr "E34: "
+msgid "E35: No previous regular expression"
+msgstr "E35: Зразків пошуку ще не було"
+
+# msgstr "E35: "
+msgid "E481: No range allowed"
+msgstr "E481: Ðе дозволено вказувати межі"
+
+msgid "E36: Not enough room"
+msgstr "E36: МіÑÑ†Ñ Ð½Ðµ виÑтачить"
+
+#, c-format
+msgid "E247: no registered server named \"%s\""
+msgstr "E247: Ðемає зареєÑтрованих Ñерверів з назвою «%s»"
+
+# msgstr "E36: "
+#, c-format
+msgid "E482: Can't create file %s"
+msgstr "E482: Ðе вдалоÑÑ Ñтворити файл %s"
+
+msgid "E483: Can't get temp file name"
+msgstr "E483: Ðе вдалоÑÑ Ñформувати назву тимчаÑового файлу"
+
+#, c-format
+msgid "E484: Can't open file %s"
+msgstr "E484: Ðе вдалоÑÑ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸ файл %s"
+
+#, c-format
+msgid "E485: Can't read file %s"
+msgstr "E485: Ðе вдалоÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ файл %s"
+
+msgid "E38: Null argument"
+msgstr "E38: ВідÑутній аргумент"
+
+msgid "E39: Number expected"
+msgstr "E39: ОчікуєтьÑÑ Ñ‡Ð¸Ñло"
+
+#, c-format
+msgid "E40: Can't open errorfile %s"
+msgstr "E40: Ðе вдалоÑÑ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸ файл помилок %s"
+
+msgid "E233: cannot open display"
+msgstr "E233: Ðе вдалоÑÑ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸ диÑплей"
+
+msgid "E41: Out of memory!"
+msgstr "E41: Забракло пам'ÑÑ‚Ñ–!"
+
+msgid "Pattern not found"
+msgstr "Зразок не знайдено"
+
+#, c-format
+msgid "E486: Pattern not found: %s"
+msgstr "E486: Зразок не знайдено: %s"
+
+msgid "E487: Argument must be positive"
+msgstr "E487: Ðргумент має бути додатний"
+
+msgid "E459: Cannot go back to previous directory"
+msgstr "E459: Ðе вдалоÑÑ Ð¿ÐµÑ€ÐµÐ¹Ñ‚Ð¸ до попереднього каталогу"
+
+msgid "E42: No Errors"
+msgstr "E42: Жодної помилки"
+
+msgid "E776: No location list"
+msgstr "E776: Ðемає ÑпиÑку міÑць"
+
+msgid "E43: Damaged match string"
+msgstr "E43: ТекÑÑ‚ збігу пошкоджено"
+
+msgid "E44: Corrupted regexp program"
+msgstr "E44: ЗіпÑована програма регулÑрних виразів"
+
+msgid "E45: 'readonly' option is set (add ! to override)"
+msgstr "E45: Ð’Ñтановлено опцію 'readonly' (! щоб не зважати)"
+
+#, c-format
+msgid "E46: Cannot change read-only variable \"%s\""
+msgstr "E46: Змінна тільки Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ: «%s»"
+
+#, c-format
+msgid "E794: Cannot set variable in the sandbox: \"%s\""
+msgstr "E794: Ðе можна вÑтановити змінну у піÑочниці: «%s»"
+
+msgid "E713: Cannot use empty key for Dictionary"
+msgstr "E713: Ключ Ñловника не може бути порожнім"
+
+msgid "E715: Dictionary required"
+msgstr "E715: Потрібен Ñловник"
+
+#, c-format
+msgid "E684: list index out of range: %ld"
+msgstr "E684: Ð†Ð½Ð´ÐµÐºÑ ÑпиÑку поза межами: %ld"
+
+#, c-format
+msgid "E118: Too many arguments for function: %s"
+msgstr "E118: Забагато аргументів Ð´Ð»Ñ Ñ„ÑƒÐ½ÐºÑ†Ñ–Ñ—: %s"
+
+#, c-format
+msgid "E716: Key not present in Dictionary: %s"
+msgstr "E716: Ðемає такого ключа у Ñловнику: %s"
+
+# msgstr "E396: "
+msgid "E714: List required"
+msgstr "E714: Потрібен ÑпиÑок"
+
+#, c-format
+msgid "E712: Argument of %s must be a List or Dictionary"
+msgstr "E712: Ðргумент у %s має бути ÑпиÑком чи Ñловником"
+
+msgid "E47: Error while reading errorfile"
+msgstr "E47: Помилка Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ Ñ„Ð°Ð¹Ð»Ñƒ помилок"
+
+msgid "E48: Not allowed in sandbox"
+msgstr "E48: Ðа дозволено у піÑочниці"
+
+msgid "E523: Not allowed here"
+msgstr "E523: Ðе дозволено тут"
+
+msgid "E359: Screen mode setting not supported"
+msgstr "E359: Режим екрану не підтримуєтьÑÑ"
+
+msgid "E49: Invalid scroll size"
+msgstr "E49: Ðекоректний розмір зÑуву"
+
+msgid "E91: 'shell' option is empty"
+msgstr "E91: ÐžÐ¿Ñ†Ñ–Ñ 'shell' порожнÑ"
+
+# msgstr "E254: "
+msgid "E255: Couldn't read in sign data!"
+msgstr "E255: Ðе можна зчитати дані напиÑу!"
+
+msgid "E72: Close error on swap file"
+msgstr "E72: Помилка під Ñ‡Ð°Ñ Ð·Ð°ÐºÑ€Ð¸Ñ‚Ñ‚Ñ Ñ„Ð°Ð¹Ð»Ñƒ обміну"
+
+msgid "E73: tag stack empty"
+msgstr "E73: Стек міток порожній"
+
+msgid "E74: Command too complex"
+msgstr "E74: Занадто Ñкладна команда"
+
+msgid "E75: Name too long"
+msgstr "E75: Задовге ім'Ñ"
+
+msgid "E76: Too many ["
+msgstr "E76: Забагато '['"
+
+msgid "E77: Too many file names"
+msgstr "E77: Забагато назв файлів"
+
+msgid "E488: Trailing characters"
+msgstr "E488: Ðадлишкові Ñимволи"
+
+msgid "E78: Unknown mark"
+msgstr "E78: Ðевідома помітка"
+
+msgid "E79: Cannot expand wildcards"
+msgstr "E79: Ðе вдалоÑÑ Ñ€Ð¾Ð·ÐºÑ€Ð¸Ñ‚Ð¸ шаблон"
+
+msgid "E591: 'winheight' cannot be smaller than 'winminheight'"
+msgstr "E591: 'winheight' не може бути меншим за 'winminheight'"
+
+msgid "E592: 'winwidth' cannot be smaller than 'winminwidth'"
+msgstr "E592: 'winwidth' не може бути меншим за 'winminwidth'"
+
+# msgstr "E79: "
+msgid "E80: Error while writing"
+msgstr "E80: Помилка під Ñ‡Ð°Ñ Ð·Ð°Ð¿Ð¸Ñу"
+
+# msgstr "E396: "
+msgid "E939: Positive count required"
+msgstr "E939: Потрібна додатна кількіÑÑ‚ÑŒ"
+
+msgid "E81: Using <SID> not in a script context"
+msgstr "E81: <SID> викориÑтовуєтьÑÑ Ð½Ðµ в контекÑÑ‚Ñ– Ñкрипту"
+
+msgid "E449: Invalid expression received"
+msgstr "E449: Отримано некоректний вираз"
+
+msgid "E463: Region is guarded, cannot modify"
+msgstr "E463: Ðе можна змінити захищений регіон"
+
+msgid "E744: NetBeans does not allow changes in read-only files"
+msgstr "E744: NetBeans не дозволÑÑ” змінювати захищені від запиÑу файли"
+
+msgid "E363: pattern uses more memory than 'maxmempattern'"
+msgstr "E363: Зразок викориÑтовує більше, ніж 'maxmempattern', пам'ÑÑ‚Ñ–"
+
+msgid "E749: empty buffer"
+msgstr "E749: Порожній буфер"
+
+#, c-format
+msgid "E86: Buffer %ld does not exist"
+msgstr "E86: Буфера %ld немає"
+
+msgid "E682: Invalid search pattern or delimiter"
+msgstr "E682: Ðекоректний зразок Ð´Ð»Ñ Ð¿Ð¾ÑˆÑƒÐºÑƒ чи роздільник"
+
+msgid "E139: File is loaded in another buffer"
+msgstr "E139: Файл уже завантажено в інший буфер"
+
+# msgstr "E235: "
+#, c-format
+msgid "E764: Option '%s' is not set"
+msgstr "E764: ÐžÐ¿Ñ†Ñ–Ñ '%s' не вÑтановлена"
+
+msgid "E850: Invalid register name"
+msgstr "E850: Ðеправильна назва регіÑтру"
+
+#, c-format
+msgid "E919: Directory not found in '%s': \"%s\""
+msgstr "E919: Теку не знайдено: '%s': «%s»"
+
+msgid "E952: Autocommand caused recursive behavior"
+msgstr "E952: Ðвтокоманди призвели до рекурÑÑ–Ñ—"
+
+msgid "search hit TOP, continuing at BOTTOM"
+msgstr "Пошук дійшов до ПОЧÐТКУ, продовжуєтьÑÑ Ð· КІÐЦЯ"
+
+msgid "search hit BOTTOM, continuing at TOP"
+msgstr "Пошук дійшов до КІÐЦЯ, продовжуєтьÑÑ Ð· ПОЧÐТКУ"
+
+#, c-format
+msgid "Need encryption key for \"%s\""
+msgstr "Ð”Ð»Ñ Â«%s» потрібен ключ: "
+
+# msgstr "E406: "
+msgid "empty keys are not allowed"
+msgstr "порожні ключі не дозволені"
+
+msgid "dictionary is locked"
+msgstr "Ñловник заблоковано"
+
+msgid "list is locked"
+msgstr "ÑпиÑок заблоковано"
+
+#, c-format
+msgid "failed to add key '%s' to dictionary"
+msgstr "не вдалоÑÑ Ð´Ð¾Ð´Ð°Ñ‚Ð¸ ключ '%s' до Ñловника"
+
+#, c-format
+msgid "index must be int or slice, not %s"
+msgstr "Ñ–Ð½Ð´ÐµÐºÑ Ð¼Ð°Ñ” бути цілий чи зріз, не %s"
+
+#, c-format
+msgid "expected str() or unicode() instance, but got %s"
+msgstr "очікувавÑÑ ÐµÐºÐ·ÐµÐ¼Ð¿Ð»ÑÑ€ str() чи unicode(), але отримано %s"
+
+#, c-format
+msgid "expected bytes() or str() instance, but got %s"
+msgstr "очікувавÑÑ ÐµÐºÐ·ÐµÐ¼Ð¿Ð»ÑÑ€ bytes() чи str(), але отримано %s"
+
+#, c-format
+msgid ""
+"expected int(), long() or something supporting coercing to long(), but got %s"
+msgstr ""
+"очікувавÑÑ int(), long() чи щоÑÑŒ, що може бути вміщене long(), але отримано "
+"%s"
+
+#, c-format
+msgid "expected int() or something supporting coercing to int(), but got %s"
+msgstr "очікувавÑÑ int() чи щоÑÑŒ, що може бути вміщене int(), але отримано %s"
+
+msgid "value is too large to fit into C int type"
+msgstr "Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð·Ð°Ð²ÐµÐ»Ð¸ÐºÐµ, щоб вміÑтитиÑÑ Ñƒ тип C int"
+
+msgid "value is too small to fit into C int type"
+msgstr "Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð·Ð°Ð¼Ð°Ð»Ðµ, щоб вміÑтитиÑÑ Ñƒ тип C int"
+
+msgid "number must be greater than zero"
+msgstr "чиÑло має бути більше, ніж нуль"
+
+msgid "number must be greater or equal to zero"
+msgstr "чиÑло має бути не менше, ніж нуль"
+
+msgid "can't delete OutputObject attributes"
+msgstr "не вдалоÑÑ Ð·Ð½Ð¸Ñ‰Ð¸Ñ‚Ð¸ атрибути OutputObject"
+
+# msgstr "E180: "
+#, c-format
+msgid "invalid attribute: %s"
+msgstr "неправильний атрибут: %s"
+
+msgid "E264: Python: Error initialising I/O objects"
+msgstr "E264: Python: Помилка ініціалізації об'єктів вводу/виводу"
+
+msgid "failed to change directory"
+msgstr "не вдалоÑÑ Ð·Ð¼Ñ–Ð½Ð¸Ñ‚Ð¸ директорію"
+
+#, c-format
+msgid "expected 3-tuple as imp.find_module() result, but got %s"
+msgstr "очікувавÑÑ 3-кортеж Ñк результат imp.find_module(), але отримано %s"
+
+#, c-format
+msgid "expected 3-tuple as imp.find_module() result, but got tuple of size %d"
+msgstr "очікувавÑÑ 3-кортеж Ñк результат imp.find_module(), але отримано %d"
+
+msgid "internal error: imp.find_module returned tuple with NULL"
+msgstr "Ð²Ð½ÑƒÑ‚Ñ€Ñ–ÑˆÐ½Ñ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ°: imp.find_module повернула кортеж з NULL"
+
+msgid "cannot delete vim.Dictionary attributes"
+msgstr "не вдалоÑÑ Ð·Ð½Ð¸Ñ‰Ð¸Ñ‚Ð¸ атрибути vim.Dictionary"
+
+msgid "cannot modify fixed dictionary"
+msgstr "не можна змінити фікÑований Ñловник"
+
+#, c-format
+msgid "cannot set attribute %s"
+msgstr "не можна вÑтановити атрибут %s"
+
+msgid "hashtab changed during iteration"
+msgstr "хеш-Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ Ð·Ð¼Ñ–Ð½Ð¸Ð»Ð°ÑÑ Ð¿Ñ–Ð´ Ñ‡Ð°Ñ Ð¿ÐµÑ€ÐµÐ±Ð¸Ñ€Ð°Ð½Ð½Ñ"
+
+#, c-format
+msgid "expected sequence element of size 2, but got sequence of size %d"
+msgstr ""
+"очікувалаÑÑŒ поÑлідовніÑÑ‚ÑŒ розміром 2, але отримано поÑлідовніÑÑ‚ÑŒ розміру %d"
+
+msgid "list constructor does not accept keyword arguments"
+msgstr "ÑпиÑковий конÑтруктор не приймає іменовані аргументи"
+
+msgid "list index out of range"
+msgstr "Ñ–Ð½Ð´ÐµÐºÑ ÑпиÑку за межами"
+
+#, c-format
+msgid "internal error: failed to get vim list item %d"
+msgstr "Ð²Ð½ÑƒÑ‚Ñ€Ñ–ÑˆÐ½Ñ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ°: не вдалоÑÑ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ñ‚Ð¸ елемент ÑпиÑку vim %d"
+
+msgid "slice step cannot be zero"
+msgstr "крок зрізу не може бути нуль"
+
+#, c-format
+msgid "attempt to assign sequence of size greater than %d to extended slice"
+msgstr ""
+"Ñпроба призначити поÑлідовніÑÑ‚ÑŒ розміру більше, ніж %d, у розширений зріз"
+
+#, c-format
+msgid "internal error: no vim list item %d"
+msgstr "Ð²Ð½ÑƒÑ‚Ñ€Ñ–ÑˆÐ½Ñ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ°: немає елемента ÑпиÑку vim %d"
+
+msgid "internal error: not enough list items"
+msgstr "Ð²Ð½ÑƒÑ‚Ñ€Ñ–ÑˆÐ½Ñ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ°: бракує елементів у ÑпиÑку"
+
+msgid "internal error: failed to add item to list"
+msgstr "Ð²Ð½ÑƒÑ‚Ñ€Ñ–ÑˆÐ½Ñ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ°: не вдалоÑÑ Ð´Ð¾Ð´Ð°Ñ‚Ð¸ елемент до ÑпиÑку"
+
+#, c-format
+msgid "attempt to assign sequence of size %d to extended slice of size %d"
+msgstr ""
+"Ñпроба призначити поÑлідовніÑÑ‚ÑŒ розміром %d у розширений зріз розміру %d"
+
+msgid "failed to add item to list"
+msgstr "не вдалоÑÑ Ð´Ð¾Ð´Ð°Ñ‚Ð¸ елемент до ÑпиÑку"
+
+msgid "cannot delete vim.List attributes"
+msgstr "не вдалоÑÑ Ð·Ð½Ð¸Ñ‰Ð¸Ñ‚Ð¸ атрибути vim.List"
+
+msgid "cannot modify fixed list"
+msgstr "не можна змінити фікÑований ÑпиÑок"
+
+# msgstr "E428: "
+#, c-format
+msgid "unnamed function %s does not exist"
+msgstr "безіменної функції %s не Ñ–Ñнує"
+
+# msgstr "E428: "
+#, c-format
+msgid "function %s does not exist"
+msgstr "функції %s не Ñ–Ñнує"
+
+#, c-format
+msgid "failed to run function %s"
+msgstr "не вдалоÑÑ Ð²Ð¸ÐºÐ¾Ð½Ð°Ñ‚Ð¸ функцію %s"
+
+msgid "unable to get option value"
+msgstr "не вдалоÑÑ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ñ‚Ð¸ Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð¾Ð¿Ñ†Ñ–Ñ—"
+
+msgid "internal error: unknown option type"
+msgstr "Ð²Ð½ÑƒÑ‚Ñ€Ñ–ÑˆÐ½Ñ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ°: невідомий тип опції"
+
+msgid "problem while switching windows"
+msgstr "не вдалоÑÑ Ð¿ÐµÑ€ÐµÐ¼ÐºÐ½ÑƒÑ‚Ð¸ вікна"
+
+#, c-format
+msgid "unable to unset global option %s"
+msgstr "не вдалоÑÑ Ñкинути глобальну опцію %s"
+
+#, c-format
+msgid "unable to unset option %s which does not have global value"
+msgstr "не вдалоÑÑ Ñкинути опцію %s, Ñка не має глобального значеннÑ"
+
+msgid "attempt to refer to deleted tab page"
+msgstr "Ñпроба Ð·Ð²ÐµÑ€Ð½ÐµÐ½Ð½Ñ Ð´Ð¾ знищеної вкладки"
+
+msgid "no such tab page"
+msgstr "такої вкладки немає"
+
+msgid "attempt to refer to deleted window"
+msgstr "Ñпроба звернутиÑÑ Ð´Ð¾ знищеного вікна"
+
+msgid "readonly attribute: buffer"
+msgstr "атрибут лише Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ: буфер"
+
+msgid "cursor position outside buffer"
+msgstr "курÑор за межами буфера"
+
+msgid "no such window"
+msgstr "такого вікна немає"
+
+msgid "attempt to refer to deleted buffer"
+msgstr "Ñпроба Ð·Ð²ÐµÑ€Ð½ÐµÐ½Ð½Ñ Ð´Ð¾ знищеного буфера"
+
+msgid "failed to rename buffer"
+msgstr "не вдалоÑÑ Ð¿ÐµÑ€ÐµÐ¹Ð¼ÐµÐ½ÑƒÐ²Ð°Ñ‚Ð¸ буфер"
+
+msgid "mark name must be a single character"
+msgstr "назвою мітки має бути один Ñимвол"
+
+#, c-format
+msgid "expected vim.Buffer object, but got %s"
+msgstr "очікувавÑÑ Ð¾Ð±â€™Ñ”ÐºÑ‚ vim.Buffer, але отримано %s"
+
+#, c-format
+msgid "failed to switch to buffer %d"
+msgstr "не вдалоÑÑ Ð¿ÐµÑ€ÐµÐ¼ÐºÐ½ÑƒÑ‚Ð¸ÑÑ Ð´Ð¾ буфера %d"
+
+#, c-format
+msgid "expected vim.Window object, but got %s"
+msgstr "очікувавÑÑ Ð¾Ð±â€™Ñ”ÐºÑ‚ vim.Window, але отримано %s"
+
+msgid "failed to find window in the current tab page"
+msgstr "не вдалоÑÑ Ð·Ð½Ð°Ð¹Ñ‚Ð¸ вікно у поточній вкладці"
+
+msgid "did not switch to the specified window"
+msgstr "не перемкнувÑÑ Ð´Ð¾ вказаного вікна"
+
+#, c-format
+msgid "expected vim.TabPage object, but got %s"
+msgstr "очікувавÑÑ Ð¾Ð±â€™Ñ”ÐºÑ‚ vim.TabPage, але отримано %s"
+
+msgid "did not switch to the specified tab page"
+msgstr "не перемкнувÑÑ Ð´Ð¾ вказаної вкладки"
+
+msgid "failed to run the code"
+msgstr "не вдалоÑÑ Ð²Ð¸ÐºÐ¾Ð½Ð°Ñ‚Ð¸ код"
+
+msgid "E858: Eval did not return a valid python object"
+msgstr "E858: Eval не повернув дійÑний об’єкт python"
+
+msgid "E859: Failed to convert returned python object to vim value"
+msgstr "E859: Ðе вдалоÑÑ Ð¿ÐµÑ€ÐµÑ‚Ð²Ð¾Ñ€Ð¸Ñ‚Ð¸ об’єкт python у Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ vim"
+
+#, c-format
+msgid "unable to convert %s to vim dictionary"
+msgstr "не вдалоÑÑ Ð¿ÐµÑ€ÐµÑ‚Ð²Ð¾Ñ€Ð¸Ñ‚Ð¸ %s у Ñловник vim"
+
+#, c-format
+msgid "unable to convert %s to vim list"
+msgstr "не вдалоÑÑ Ð¿ÐµÑ€ÐµÑ‚Ð²Ð¾Ñ€Ð¸Ñ‚Ð¸ %s у ÑпиÑок vim"
+
+#, c-format
+msgid "unable to convert %s to vim structure"
+msgstr "не вдалоÑÑ Ð¿ÐµÑ€ÐµÑ‚Ð²Ð¾Ñ€Ð¸Ñ‚Ð¸ %s у Ñтруктуру vim"
+
+msgid "internal error: NULL reference passed"
+msgstr "Ð²Ð½ÑƒÑ‚Ñ€Ñ–ÑˆÐ½Ñ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ°: передано поÑÐ¸Ð»Ð°Ð½Ð½Ñ NULL"
+
+msgid "internal error: invalid value type"
+msgstr "Ð²Ð½ÑƒÑ‚Ñ€Ñ–ÑˆÐ½Ñ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ°: неправильний тип значеннÑ"
+
+msgid ""
+"Failed to set path hook: sys.path_hooks is not a list\n"
+"You should now do the following:\n"
+"- append vim.path_hook to sys.path_hooks\n"
+"- append vim.VIM_SPECIAL_PATH to sys.path\n"
+msgstr ""
+"Ðе вдалоÑÑ Ð²Ñтановити обробник шлÑху: sys.path_hooks не ÑпиÑок\n"
+"Вам Ñлід вчинити так:\n"
+"- додайте vim.path_hook до sys.path_hooks\n"
+"- додайте vim.VIM_SPECIAL_PATH до sys.path\n"
+
+msgid ""
+"Failed to set path: sys.path is not a list\n"
+"You should now append vim.VIM_SPECIAL_PATH to sys.path"
+msgstr ""
+"Ðе вдалоÑÑ Ð²Ñтановити шлÑÑ…: sys.path не ÑпиÑок\n"
+"Ð’Ð°Ñ Ñлід додати vim.VIM_SPECIAL_PATH до sys.path"
+
+msgid ""
+"Vim macro files (*.vim)\t*.vim\n"
+"All Files (*.*)\t*.*\n"
+msgstr ""
+"МакроÑи Vim (*.vim)\t*.vim\n"
+"Ð’ÑÑ– файли (*.*)\t*.*\n"
+
+msgid "All Files (*.*)\t*.*\n"
+msgstr "Ð’ÑÑ– файли (*.*)\t*.*\n"
+
+msgid ""
+"All Files (*.*)\t*.*\n"
+"C source (*.c, *.h)\t*.c;*.h\n"
+"C++ source (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"VB code (*.bas, *.frm)\t*.bas;*.frm\n"
+"Vim files (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
+msgstr ""
+"Ð’ÑÑ– файли (*.*)\t*.*\n"
+"Першокод C (*.c, *.h)\t*.c;*.h\n"
+"Першокод C++ (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"Код VB (*.bas, *.frm)\t*.bas;*.frm\n"
+"Файли Vim (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
+
+msgid ""
+"Vim macro files (*.vim)\t*.vim\n"
+"All Files (*)\t*\n"
+msgstr ""
+"МакроÑи Vim (*.vim)\t*.vim\n"
+"Ð’ÑÑ– файли (*)\t*\n"
+
+msgid "All Files (*)\t*\n"
+msgstr "Ð’ÑÑ– файли (*)\t*\n"
+
+msgid ""
+"All Files (*)\t*\n"
+"C source (*.c, *.h)\t*.c;*.h\n"
+"C++ source (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"Vim files (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
+msgstr ""
+"Ð’ÑÑ– файли (*)\t*\n"
+"Першокод C (*.c, *.h)\t*.c;*.h\n"
+"Першокод C++ (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"Файли Vim (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
diff --git a/src/po/vi.po b/src/po/vi.po
new file mode 100644
index 0000000..a222137
--- /dev/null
+++ b/src/po/vi.po
@@ -0,0 +1,5196 @@
+# Vietnamese translation for Vim
+# first translator(s): Phan Vinh Thinh <teppi@vnlinux.org>, 2005
+# Original translations.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Vim 6.3 \n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2005-02-25 22:51+0300\n"
+"PO-Revision-Date: 2005-02-30 21:37+0400\n"
+"Last-Translator: Phan Vinh Thinh <teppi@vnlinux.org>\n"
+"Language-Team: Phan Vinh Thinh <teppi@vnlinux.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "E82: Cannot allocate any buffer, exiting..."
+msgstr "E82: Không thể phân chia bộ nhớ thậm chí cho một bộ đệm, thoát..."
+
+msgid "E83: Cannot allocate buffer, using other one..."
+msgstr "E83: Không thể phân chia bộ nhớ cho bộ đệm, sử dụng bộ đệm khác..."
+
+msgid "E515: No buffers were unloaded"
+msgstr "E515: Không có bộ đệm nào được bỠnạp từ bộ nhớ"
+
+msgid "E516: No buffers were deleted"
+msgstr "E516: Không có bộ đệm nào bị xóa"
+
+msgid "E517: No buffers were wiped out"
+msgstr "E517: Không có bộ đệm nào được làm sạch"
+
+msgid "1 buffer unloaded"
+msgstr "1 bộ đệm được bỠnạp từ bộ nhớ"
+
+#, c-format
+msgid "%d buffers unloaded"
+msgstr "%d bộ đệm được bỠnạp từ bộ nhớ"
+
+msgid "1 buffer deleted"
+msgstr "1 bộ đệm bị xóa"
+
+#, c-format
+msgid "%d buffers deleted"
+msgstr "%d bộ đệm được bỠnạp"
+
+msgid "1 buffer wiped out"
+msgstr "1 bộ đệm được làm sạch"
+
+#, c-format
+msgid "%d buffers wiped out"
+msgstr "%d bộ đệm được làm sạch"
+
+msgid "E84: No modified buffer found"
+msgstr "E84: Không tìm thấy bộ đệm có thay đổi"
+
+#. back where we started, didn't find anything.
+msgid "E85: There is no listed buffer"
+msgstr "E85: Không có bộ đệm được liệt kê"
+
+#, c-format
+msgid "E86: Buffer %ld does not exist"
+msgstr "E86: Bộ đệm %ld không tồn tại"
+
+msgid "E87: Cannot go beyond last buffer"
+msgstr "E87: Äây là bá»™ đệm cuối cùng"
+
+msgid "E88: Cannot go before first buffer"
+msgstr "E88: Äây là bá»™ đệm đầu tiên"
+
+#, c-format
+msgid "E89: No write since last change for buffer %ld (add ! to override)"
+msgstr ""
+"E89: Thay đổi trong bộ đệm %ld chưa được ghi lại (thêm ! để thoát ra bằng "
+"má»i giá)"
+
+msgid "E90: Cannot unload last buffer"
+msgstr "E90: Không thể bỠnạp từ bộ nhớ bộ đệm cuối cùng"
+
+msgid "W14: Warning: List of file names overflow"
+msgstr "W14: Cảnh báo: Danh sách tên tập tin quá đầy"
+
+#, c-format
+msgid "E92: Buffer %ld not found"
+msgstr "E92: Bộ đệm %ld không được tìm thấy"
+
+#, c-format
+msgid "E93: More than one match for %s"
+msgstr "E93: Tìm thấy vài tương ứng với %s"
+
+#, c-format
+msgid "E94: No matching buffer for %s"
+msgstr "E94: Không có bộ đệm tương ứng với %s"
+
+#, c-format
+msgid "line %ld"
+msgstr "dòng %ld"
+
+msgid "E95: Buffer with this name already exists"
+msgstr "E95: Äã có bá»™ đệm vá»›i tên nhÆ° vậy"
+
+msgid " [Modified]"
+msgstr " [Äã thay đổi]"
+
+msgid "[Not edited]"
+msgstr "[Chưa soạn thảo]"
+
+msgid "[New file]"
+msgstr "[Tập tin mới]"
+
+msgid "[Read errors]"
+msgstr "[Lá»—i Ä‘á»c]"
+
+msgid "[readonly]"
+msgstr "[chỉ Ä‘á»c]"
+
+#, c-format
+msgid "1 line --%d%%--"
+msgstr "1 dòng --%d%%--"
+
+#, c-format
+msgid "%ld lines --%d%%--"
+msgstr "%ld dòng --%d%%--"
+
+#, c-format
+msgid "line %ld of %ld --%d%%-- col "
+msgstr "dòng %ld của %ld --%d%%-- cột "
+
+msgid "[No file]"
+msgstr "[Không có tập tin]"
+
+#. must be a help buffer
+msgid "help"
+msgstr "trợ giúp"
+
+msgid "[help]"
+msgstr "[trợ giúp]"
+
+msgid "[Preview]"
+msgstr "[Xem trÆ°á»›c]"
+
+msgid "All"
+msgstr "Tất cả"
+
+msgid "Bot"
+msgstr "Cuối"
+
+msgid "Top"
+msgstr "Äầu"
+
+msgid ""
+"\n"
+"# Buffer list:\n"
+msgstr ""
+"\n"
+"# Danh sách bộ đệm:\n"
+
+msgid "[Error List]"
+msgstr "[Danh sách lỗi]"
+
+msgid "[No File]"
+msgstr "[Không có tập tin]"
+
+msgid ""
+"\n"
+"--- Signs ---"
+msgstr ""
+"\n"
+"--- Ký hiệu ---"
+
+#, c-format
+msgid "Signs for %s:"
+msgstr "Ký hiệu cho %s:"
+
+#, c-format
+msgid " line=%ld id=%d name=%s"
+msgstr " dòng=%ld id=%d tên=%s"
+
+#, c-format
+msgid "E96: Can not diff more than %ld buffers"
+msgstr "E96: Chỉ có thể theo dõi sá»± khác nhau trong nhiá»u nhất %ld bá»™ đệm"
+
+msgid "E97: Cannot create diffs"
+msgstr "E97: Không thể tạo tập tin khác biệt (diff)"
+
+msgid "Patch file"
+msgstr "Tập tin vá lỗi (patch)"
+
+msgid "E98: Cannot read diff output"
+msgstr "E98: Không thể Ä‘á»c dữ liệu ra của lệnh diff"
+
+msgid "E99: Current buffer is not in diff mode"
+msgstr "E99: Bá»™ đệm hiện thá»i không nằm trong chế Ä‘á»™ khác biệt (diff)"
+
+msgid "E100: No other buffer in diff mode"
+msgstr "E100: Không còn bộ đệm trong chế độ khác biệt (diff) nào nữa"
+
+msgid "E101: More than two buffers in diff mode, don't know which one to use"
+msgstr ""
+"E101: Có nhiá»u hÆ¡n hai bá»™ đệm trong chế Ä‘á»™ khác biệt (diff), không biết chá»n"
+
+#, c-format
+msgid "E102: Can't find buffer \"%s\""
+msgstr "E102: Không tìm thấy bộ đệm \"%s\""
+
+#, c-format
+msgid "E103: Buffer \"%s\" is not in diff mode"
+msgstr "E103: Bộ đệm \"%s\" không nằm trong chế độ khác biệt (diff)"
+
+msgid "E104: Escape not allowed in digraph"
+msgstr "E104: Không cho phép dùng ký tự thoát Escape trong chữ ghép"
+
+msgid "E544: Keymap file not found"
+msgstr "E544: Không tìm thấy tập tin sơ đồ bàn phím"
+
+msgid "E105: Using :loadkeymap not in a sourced file"
+msgstr "E105: Câu lệnh :loadkeymap được sử dụng ngoài tập tin script"
+
+msgid " Keyword completion (^N^P)"
+msgstr " Tự động kết thúc cho từ khóa (^N^P)"
+
+#. ctrl_x_mode == 0, ^P/^N compl.
+msgid " ^X mode (^E^Y^L^]^F^I^K^D^V^N^P)"
+msgstr " Chế độ ^X (^E^Y^L^]^F^I^K^D^V^N^P)"
+
+#. Scroll has it's own msgs, in it's place there is the msg for local
+#. * ctrl_x_mode = 0 (eg continue_status & CONT_LOCAL) -- Acevedo
+msgid " Keyword Local completion (^N^P)"
+msgstr " Tự động kết thúc nội bộ cho từ khóa (^N^P)"
+
+msgid " Whole line completion (^L^N^P)"
+msgstr " Tự động kết thúc cho cả dòng (^L^N^P)"
+
+msgid " File name completion (^F^N^P)"
+msgstr " Tự động kết thúc tên tập tin (^F^N^P)"
+
+msgid " Tag completion (^]^N^P)"
+msgstr " Tự động kết thúc thẻ đánh dấu (^]^N^P)"
+
+msgid " Path pattern completion (^N^P)"
+msgstr " Tá»± Ä‘á»™ng kết thúc mẫu Ä‘Æ°á»ng dẫn (^N^P)"
+
+msgid " Definition completion (^D^N^P)"
+msgstr " Tự động kết thúc định nghĩa (^D^N^P)"
+
+msgid " Dictionary completion (^K^N^P)"
+msgstr " Tự động kết thúc theo từ điển (^K^N^P)"
+
+msgid " Thesaurus completion (^T^N^P)"
+msgstr " Tự động kết thúc từ đồng âm (^T^N^P)"
+
+msgid " Command-line completion (^V^N^P)"
+msgstr " Tự động kết thúc dòng lệnh (^V^N^P)"
+
+msgid "Hit end of paragraph"
+msgstr "Kết thúc của đoạn văn"
+
+msgid "'thesaurus' option is empty"
+msgstr "Không Ä‘Æ°a ra giá trị của tùy chá»n 'thesaurus'"
+
+msgid "'dictionary' option is empty"
+msgstr "Không Ä‘Æ°a ra giá trị của tùy chá»n 'dictionary'"
+
+#, c-format
+msgid "Scanning dictionary: %s"
+msgstr "Quét từ điển: %s"
+
+msgid " (insert) Scroll (^E/^Y)"
+msgstr " (chèn) Cuộn (^E/^Y)"
+
+msgid " (replace) Scroll (^E/^Y)"
+msgstr " (thay thế) Cuộn (^E/^Y)"
+
+#, c-format
+msgid "Scanning: %s"
+msgstr "Quét: %s"
+
+msgid "Scanning tags."
+msgstr "Tìm kiếm trong số thẻ đánh dấu."
+
+msgid " Adding"
+msgstr " Thêm"
+
+#. showmode might reset the internal line pointers, so it must
+#. * be called before line = ml_get(), or when this address is no
+#. * longer needed. -- Acevedo.
+#.
+msgid "-- Searching..."
+msgstr "-- Tìm kiếm..."
+
+msgid "Back at original"
+msgstr "Từ ban đầu"
+
+msgid "Word from other line"
+msgstr "Từ của dòng khác"
+
+msgid "The only match"
+msgstr "Tương ứng duy nhất"
+
+#, c-format
+msgid "match %d of %d"
+msgstr "Tương ứng %d của %d"
+
+#, c-format
+msgid "match %d"
+msgstr "Tương ứng %d"
+
+#. Skip further arguments but do continue to
+#. * search for a trailing command.
+#, c-format
+msgid "E106: Unknown variable: \"%s\""
+msgstr "E106: Biến không biết: \"%s\""
+
+#, c-format
+msgid "E107: Missing parentheses: %s"
+msgstr "E107: Thiếu dấu ngoặc: %s"
+
+#, c-format
+msgid "E108: No such variable: \"%s\""
+msgstr "E108: Không có biến như vậy: \"%s\""
+
+msgid "E109: Missing ':' after '?'"
+msgstr "E109: Thiếu ':' sau '?'"
+
+msgid "E110: Missing ')'"
+msgstr "E110: Thiếu ')'"
+
+msgid "E111: Missing ']'"
+msgstr "E111: Thiếu ']'"
+
+#, c-format
+msgid "E112: Option name missing: %s"
+msgstr "E112: Không Ä‘Æ°a ra tên tùy chá»n: %s"
+
+#, c-format
+msgid "E113: Unknown option: %s"
+msgstr "E113: Tùy chá»n không biết: %s"
+
+#, c-format
+msgid "E114: Missing quote: %s"
+msgstr "E114: Thiếu ngoặc kép: %s"
+
+#, c-format
+msgid "E115: Missing quote: %s"
+msgstr "E115: Thiếu ngoặc kép: %s"
+
+#, c-format
+msgid "E116: Invalid arguments for function %s"
+msgstr "E116: Tham số cho hàm %s đưa ra không đúng"
+
+#, c-format
+msgid "E117: Unknown function: %s"
+msgstr "E117: Hàm số không biết: %s"
+
+#, c-format
+msgid "E118: Too many arguments for function: %s"
+msgstr "E118: Quá nhiá»u tham số cho hàm: %s"
+
+#, c-format
+msgid "E119: Not enough arguments for function: %s"
+msgstr "E119: Không đủ tham số cho hàm: %s"
+
+#, c-format
+msgid "E120: Using <SID> not in a script context: %s"
+msgstr "E120: Sử dụng <SID> ngoài script: %s"
+
+#.
+#. * Yes this is ugly, I don't particularly like it either. But doing it
+#. * this way has the compelling advantage that translations need not to
+#. * be touched at all. See below what 'ok' and 'ync' are used for.
+#.
+msgid "&Ok"
+msgstr "&Ok"
+
+#, c-format
+msgid "+-%s%3ld lines: "
+msgstr "+-%s%3ld dòng: "
+
+msgid ""
+"&OK\n"
+"&Cancel"
+msgstr ""
+"&OK\n"
+"&Hủy bá»"
+
+msgid "called inputrestore() more often than inputsave()"
+msgstr "Hàm số inputrestore() được gá»i nhiá»u hÆ¡n hàm inputsave()"
+
+msgid "E655: Too many symbolic links (cycle?)"
+msgstr "E655: Quá nhiá»u liên kết tượng trÆ°ng (vòng lặp?)"
+
+msgid "E240: No connection to Vim server"
+msgstr "E240: Không có kết nối với máy chủ Vim"
+
+msgid "E277: Unable to read a server reply"
+msgstr "E277: Máy chủ không trả lá»i"
+
+msgid "E258: Unable to send to client"
+msgstr "E258: Không thể trả lá»i cho máy con"
+
+#, c-format
+msgid "E241: Unable to send to %s"
+msgstr "E241: Không thể gửi tin nhắn tới %s"
+
+msgid "(Invalid)"
+msgstr "(Không đúng)"
+
+#, c-format
+msgid "E121: Undefined variable: %s"
+msgstr "E121: Biến không xác định: %s"
+
+#, c-format
+msgid "E461: Illegal variable name: %s"
+msgstr "E461: Tên biến không cho phép: %s"
+
+#, c-format
+msgid "E122: Function %s already exists, add ! to replace it"
+msgstr "E122: Hàm số %s đã có, hãy thêm ! để thay thế nó."
+
+#, c-format
+msgid "E123: Undefined function: %s"
+msgstr "E123: Hàm số không xác định: %s"
+
+#, c-format
+msgid "E124: Missing '(': %s"
+msgstr "E124: Thiếu '(': %s"
+
+#, c-format
+msgid "E125: Illegal argument: %s"
+msgstr "E125: Tham số không cho phép: %s"
+
+msgid "E126: Missing :endfunction"
+msgstr "E126: Thiếu lệnh :endfunction"
+
+#, c-format
+msgid "E127: Cannot redefine function %s: It is in use"
+msgstr "E127: Không thể định nghĩa lại hàm số %s: hàm đang được sử dụng"
+
+msgid "E129: Function name required"
+msgstr "E129: Cần tên hàm số"
+
+#, c-format
+msgid "E128: Function name must start with a capital: %s"
+msgstr "E128: Tên hàm số phải bắt đầu với một chữ cái hoa: %s"
+
+#, c-format
+msgid "E130: Undefined function: %s"
+msgstr "E130: Hàm số %s chưa xác định"
+
+#, c-format
+msgid "E131: Cannot delete function %s: It is in use"
+msgstr "E131: Không thể xóa hàm số %s: Hàm đang được sử dụng"
+
+msgid "E132: Function call depth is higher than 'maxfuncdepth'"
+msgstr "E132: Äá»™ sâu của lá»i gá»i hàm số lá»›n hÆ¡n giá trị 'maxfuncdepth'"
+
+#. always scroll up, don't overwrite
+#, c-format
+msgid "calling %s"
+msgstr "lá»i gá»i %s"
+
+#, c-format
+msgid "%s aborted"
+msgstr "%s dừng"
+
+#, c-format
+msgid "%s returning #%ld"
+msgstr "%s trả lại #%ld"
+
+#, c-format
+msgid "%s returning \"%s\""
+msgstr "%s trả lại \"%s\""
+
+#. always scroll up, don't overwrite
+#, c-format
+msgid "continuing in %s"
+msgstr "tiếp tục trong %s"
+
+msgid "E133: :return not inside a function"
+msgstr "E133: lệnh :return ở ngoài một hàm"
+
+msgid ""
+"\n"
+"# global variables:\n"
+msgstr ""
+"\n"
+"# biến toàn cầu:\n"
+
+msgid "Entering Debug mode. Type \"cont\" to continue."
+msgstr "Bật chế độ sửa lỗi (Debug). Gõ \"cont\" để tiếp tục."
+
+#, c-format
+msgid "line %ld: %s"
+msgstr "dòng %ld: %s"
+
+#, c-format
+msgid "cmd: %s"
+msgstr "câu lệnh: %s"
+
+#, c-format
+msgid "Breakpoint in \"%s%s\" line %ld"
+msgstr "Äiểm dừng trên \"%s%s\" dòng %ld"
+
+#, c-format
+msgid "E161: Breakpoint not found: %s"
+msgstr "E161: Không tìm thấy điểm dừng: %s"
+
+msgid "No breakpoints defined"
+msgstr "Äiểm dừng không được xác định"
+
+#, c-format
+msgid "%3d %s %s line %ld"
+msgstr "%3d %s %s dòng %ld"
+
+msgid "Save As"
+msgstr "Ghi nhá»› nhÆ°"
+
+#, c-format
+msgid "Save changes to \"%.*s\"?"
+msgstr "Ghi nhớ thay đổi vào \"%.*s\"?"
+
+msgid "Untitled"
+msgstr "Chưa đặt tên"
+
+#, c-format
+msgid "E162: No write since last change for buffer \"%s\""
+msgstr "E162: Thay đổi chưa được ghi nhớ trong bộ đệm \"%s\""
+
+msgid "Warning: Entered other buffer unexpectedly (check autocommands)"
+msgstr ""
+"Cảnh báo: Chuyển tới bộ đệm khác không theo ý muốn (hãy kiểm tra câu lệnh tự "
+"Ä‘á»™ng)"
+
+msgid "E163: There is only one file to edit"
+msgstr "E163: Chỉ có một tập tin để soạn thảo"
+
+msgid "E164: Cannot go before first file"
+msgstr "E164: Äây là tập tin đầu tiên"
+
+msgid "E165: Cannot go beyond last file"
+msgstr "E165: Äây là tập tin cuối cùng"
+
+#, c-format
+msgid "E666: compiler not supported: %s"
+msgstr "E666: trình biên dịch không được hỗ trợ: %s"
+
+#, c-format
+msgid "Searching for \"%s\" in \"%s\""
+msgstr "Tìm kiếm \"%s\" trong \"%s\""
+
+#, c-format
+msgid "Searching for \"%s\""
+msgstr "Tìm kiếm \"%s\""
+
+#, c-format
+msgid "not found in 'runtimepath': \"%s\""
+msgstr "không tìm thấy trong 'runtimepath': \"%s\""
+
+msgid "Source Vim script"
+msgstr "Thực hiện script của Vim"
+
+#, c-format
+msgid "Cannot source a directory: \"%s\""
+msgstr "Không thể thực hiện một thư mục: \"%s\""
+
+#, c-format
+msgid "could not source \"%s\""
+msgstr "không thực hiện được \"%s\""
+
+#, c-format
+msgid "line %ld: could not source \"%s\""
+msgstr "dòng %ld: không thực hiện được \"%s\""
+
+#, c-format
+msgid "sourcing \"%s\""
+msgstr "thực hiện \"%s\""
+
+#, c-format
+msgid "line %ld: sourcing \"%s\""
+msgstr "dòng %ld: thực hiện \"%s\""
+
+#, c-format
+msgid "finished sourcing %s"
+msgstr "thực hiện xong %s"
+
+msgid "W15: Warning: Wrong line separator, ^M may be missing"
+msgstr "W15: Cảnh báo: Ký tự phân cách dòng không đúng. Rất có thể thiếu ^M"
+
+msgid "E167: :scriptencoding used outside of a sourced file"
+msgstr "E167: Lệnh :scriptencoding sử dụng ngoài tập tin script"
+
+msgid "E168: :finish used outside of a sourced file"
+msgstr "E168: Lệnh :finish sử dụng ngoài tập tin script"
+
+#, c-format
+msgid "Page %d"
+msgstr "Trang %d"
+
+msgid "No text to be printed"
+msgstr "Không có gì để in"
+
+#, c-format
+msgid "Printing page %d (%d%%)"
+msgstr "In trang %d (%d%%)"
+
+#, c-format
+msgid " Copy %d of %d"
+msgstr " Sao chép %d của %d"
+
+#, c-format
+msgid "Printed: %s"
+msgstr "Äã in: %s"
+
+msgid "Printing aborted"
+msgstr "In bị dừng"
+
+msgid "E455: Error writing to PostScript output file"
+msgstr "E455: Lỗi ghi nhớ vào tập tin PostScript"
+
+#, c-format
+msgid "E624: Can't open file \"%s\""
+msgstr "E624: Không thể mở tập tin \"%s\""
+
+#, c-format
+msgid "E457: Can't read PostScript resource file \"%s\""
+msgstr "E457: Không thể Ä‘á»c tập tin tài nguyên PostScript \"%s\""
+
+#, c-format
+msgid "E618: file \"%s\" is not a PostScript resource file"
+msgstr "E618: \"%s\" không phải là tập tin tài nguyên PostScript"
+
+#, c-format
+msgid "E619: file \"%s\" is not a supported PostScript resource file"
+msgstr "E619: \"%s\" không phải là tập tin tài nguyên PostScript được hỗ trợ"
+
+#, c-format
+msgid "E621: \"%s\" resource file has wrong version"
+msgstr "E621: tập tin tài nguyên \"%s\" có phiên bản không đúng"
+
+msgid "E324: Can't open PostScript output file"
+msgstr "E324: Không thể mở tập tin PostScript"
+
+#, c-format
+msgid "E456: Can't open file \"%s\""
+msgstr "E456: Không thể mở tập tin \"%s\""
+
+msgid "E456: Can't find PostScript resource file \"prolog.ps\""
+msgstr "E456: Không tìm thấy tập tin tài nguyên PostScript \"prolog.ps\""
+
+#, c-format
+msgid "E456: Can't find PostScript resource file \"%s.ps\""
+msgstr "E456: Không tìm thấy tập tin tài nguyên PostScript \"%s.ps\""
+
+#, c-format
+msgid "E620: Unable to convert from multi-byte to \"%s\" encoding"
+msgstr "E620: Không thể chuyển từ các ký tá»± nhiá»u byte thành bảng mã \"%s\""
+
+msgid "Sending to printer..."
+msgstr "Gửi tới máy in..."
+
+msgid "E365: Failed to print PostScript file"
+msgstr "E365: In tập tin PostScript không thành công"
+
+msgid "Print job sent."
+msgstr "Äã gá»­i công việc in."
+
+#, c-format
+msgid "Current %slanguage: \"%s\""
+msgstr "Ngôn ngữ %shiện thá»i: \"%s\""
+
+#, c-format
+msgid "E197: Cannot set language to \"%s\""
+msgstr "E197: Không thể thay đổi ngôn ngữ thành \"%s\""
+
+#, c-format
+msgid "<%s>%s%s %d, Hex %02x, Octal %03o"
+msgstr "<%s>%s%s %d, Hex %02x, Octal %03o"
+
+#, c-format
+msgid "> %d, Hex %04x, Octal %o"
+msgstr "> %d, Hex %04x, Octal %o"
+
+#, c-format
+msgid "> %d, Hex %08x, Octal %o"
+msgstr "> %d, Hex %08x, Octal %o"
+
+msgid "E134: Move lines into themselves"
+msgstr "E134: Di chuyển các dòng lên chính chúng"
+
+msgid "1 line moved"
+msgstr "Äã di chuyển 1 dòng"
+
+#, c-format
+msgid "%ld lines moved"
+msgstr "Äã di chuyển %ld dòng"
+
+#, c-format
+msgid "%ld lines filtered"
+msgstr "Äã lá»c %ld dòng"
+
+msgid "E135: *Filter* Autocommands must not change current buffer"
+msgstr "E135: Các lệnh tá»± Ä‘á»™ng *Filter* không được thay đổi bá»™ đệm hiện thá»i"
+
+msgid "[No write since last change]\n"
+msgstr "[Thay đổi chưa được ghi nhớ]\n"
+
+#, c-format
+msgid "%sviminfo: %s in line: "
+msgstr "%sviminfo: %s trên dòng: "
+
+msgid "E136: viminfo: Too many errors, skipping rest of file"
+msgstr "E136: viminfo: Quá nhiá»u lá»—i, phần còn lại của tập tin sẽ được bá» qua"
+
+#, c-format
+msgid "Reading viminfo file \"%s\"%s%s%s"
+msgstr "Äá»c tập tin viminfo \"%s\"%s%s%s"
+
+msgid " info"
+msgstr " thông tin"
+
+msgid " marks"
+msgstr " dấu hiệu"
+
+msgid " FAILED"
+msgstr " KHÔNG THÀNH CÔNG"
+
+#, c-format
+msgid "E137: Viminfo file is not writable: %s"
+msgstr "E137: Thiếu quyá»n ghi lên tập tin viminfo: %s"
+
+#, c-format
+msgid "E138: Can't write viminfo file %s!"
+msgstr "E138: Không thể ghi tập tin viminfo %s!"
+
+#, c-format
+msgid "Writing viminfo file \"%s\""
+msgstr "Ghi tập tin viminfo \"%s\""
+
+#. Write the info:
+#, c-format
+msgid "# This viminfo file was generated by Vim %s.\n"
+msgstr "# Tập tin viminfo này được tự động tạo bởi Vim %s.\n"
+
+msgid ""
+"# You may edit it if you're careful!\n"
+"\n"
+msgstr ""
+"# Bạn có thể sá»­a tập tin này, nhÆ°ng hãy thận trá»ng!\n"
+"\n"
+
+msgid "# Value of 'encoding' when this file was written\n"
+msgstr "# Giá trị của tùy chá»n 'encoding' vào thá»i Ä‘iểm ghi tập tin\n"
+
+msgid "Illegal starting char"
+msgstr "Ký tự đầu tiên không cho phép"
+
+#. Overwriting a file that is loaded in another buffer is not a
+#. * good idea.
+msgid "E139: File is loaded in another buffer"
+msgstr "E139: Tập tin được nạp trong bộ đệm khác"
+
+msgid "Write partial file?"
+msgstr "Ghi nhớ một phần tập tin?"
+
+msgid "E140: Use ! to write partial buffer"
+msgstr "E140: Sử dụng ! để ghi nhớ một phần bộ đệm"
+
+#, c-format
+msgid "Overwrite existing file \"%.*s\"?"
+msgstr "Ghi đè lên tập tin đã có \"%.*s\"?"
+
+#, c-format
+msgid "E141: No file name for buffer %ld"
+msgstr "E141: Không có tên tập tin cho bộ đệm %ld"
+
+msgid "E142: File not written: Writing is disabled by 'write' option"
+msgstr "E142: Tập tin chÆ°a được ghi nhá»›: Ghi nhá»› bị tắt bởi tùy chá»n 'write'"
+
+#, c-format
+msgid ""
+"'readonly' option is set for \"%.*s\".\n"
+"Do you wish to write anyway?"
+msgstr ""
+"Tùy chá»n 'readonly' được đặt cho \"%.*s\".\n"
+"Ghi nhá»› bằng má»i giá?"
+
+msgid "Edit File"
+msgstr "Soạn thảo tập tin"
+
+#, c-format
+msgid "E143: Autocommands unexpectedly deleted new buffer %s"
+msgstr "E143: Các lệnh tự động xóa bộ đệm mới ngoài ý muốn %s"
+
+msgid "E144: non-numeric argument to :z"
+msgstr "E144: Tham số của lệnh :z phải là số"
+
+msgid "E145: Shell commands not allowed in rvim"
+msgstr "E145: Không cho phép sử dụng lệnh shell trong rvim."
+
+msgid "E146: Regular expressions can't be delimited by letters"
+msgstr "E146: Không thể phân cách biểu thức chính quy bằng chữ cái"
+
+#, c-format
+msgid "replace with %s (y/n/a/q/l/^E/^Y)?"
+msgstr "thay thế bằng %s? (y/n/a/q/l/^E/^Y)"
+
+msgid "(Interrupted) "
+msgstr "(bị dừng)"
+
+msgid "1 substitution"
+msgstr "1 thay thế"
+
+#, c-format
+msgid "%ld substitutions"
+msgstr "%ld thay thế"
+
+msgid " on 1 line"
+msgstr " trên 1 dòng"
+
+#, c-format
+msgid " on %ld lines"
+msgstr " trên %ld dòng"
+
+msgid "E147: Cannot do :global recursive"
+msgstr "E147: Không thực hiện được lệnh :global đệ qui"
+
+msgid "E148: Regular expression missing from global"
+msgstr "E148: Thiếu biểu thức chính quy trong lệnh :global"
+
+#, c-format
+msgid "Pattern found in every line: %s"
+msgstr "Tìm thấy tÆ°Æ¡ng ứng trên má»i dòng: %s"
+
+msgid ""
+"\n"
+"# Last Substitute String:\n"
+"$"
+msgstr ""
+"\n"
+"# Chuỗi thay thế cuối cùng:\n"
+"$"
+
+msgid "E478: Don't panic!"
+msgstr "E478: Hãy bình tĩnh, đừng hoảng hốt!"
+
+#, c-format
+msgid "E661: Sorry, no '%s' help for %s"
+msgstr "E661: Rất tiếc, không có trợ giúp '%s' cho %s"
+
+#, c-format
+msgid "E149: Sorry, no help for %s"
+msgstr "E149: Rất tiếc không có trợ giúp cho %s"
+
+#, c-format
+msgid "Sorry, help file \"%s\" not found"
+msgstr "Xin lỗi, không tìm thấy tập tin trợ giúp \"%s\""
+
+#, c-format
+msgid "E150: Not a directory: %s"
+msgstr "E150: %s không phải là một thư mục"
+
+#, c-format
+msgid "E152: Cannot open %s for writing"
+msgstr "E152: Không thể mở %s để ghi"
+
+#, c-format
+msgid "E153: Unable to open %s for reading"
+msgstr "E153: Không thể mở %s để Ä‘á»c"
+
+#, c-format
+msgid "E670: Mix of help file encodings within a language: %s"
+msgstr ""
+"E670: Tập tin trợ giúp sá»­ dụng nhiá»u bảng mã khác nhau cho má»™t ngôn ngữ: %s"
+
+#, c-format
+msgid "E154: Duplicate tag \"%s\" in file %s"
+msgstr "E154: Thẻ ghi lặp lại \"%s\" trong tập tin %s"
+
+#, c-format
+msgid "E160: Unknown sign command: %s"
+msgstr "E160: Câu lệnh ký hiệu không biết: %s"
+
+msgid "E156: Missing sign name"
+msgstr "E156: Thiếu tên ký hiệu"
+
+msgid "E612: Too many signs defined"
+msgstr "E612: Äịnh nghÄ©a quá nhiá»u ký hiệu"
+
+#, c-format
+msgid "E239: Invalid sign text: %s"
+msgstr "E239: Văn bản ký hiệu không thích hợp: %s"
+
+#, c-format
+msgid "E155: Unknown sign: %s"
+msgstr "E155: Ký hiệu không biết: %s"
+
+msgid "E159: Missing sign number"
+msgstr "E159: Thiếu số của ký hiệu"
+
+#, c-format
+msgid "E158: Invalid buffer name: %s"
+msgstr "E158: Tên bộ đệm không đúng: %s"
+
+#, c-format
+msgid "E157: Invalid sign ID: %ld"
+msgstr "E157: ID của ký hiệu không đúng: %ld"
+
+msgid " (NOT FOUND)"
+msgstr " (KHÔNG TÌM THẤY)"
+
+msgid " (not supported)"
+msgstr " (không được hỗ trợ)"
+
+msgid "[Deleted]"
+msgstr "[bị xóa]"
+
+msgid "Entering Ex mode. Type \"visual\" to go to Normal mode."
+msgstr ""
+"Chuyển vào chế Ä‘á»™ Ex. Äể chuyển vá» chế Ä‘á»™ Thông thÆ°á»ng hãy gõ \"visual\""
+
+#. must be at EOF
+msgid "E501: At end-of-file"
+msgstr "E501: Ở cuối tập tin"
+
+msgid "E169: Command too recursive"
+msgstr "E169: Câu lệnh quá đệ quy"
+
+#, c-format
+msgid "E605: Exception not caught: %s"
+msgstr "E605: TrÆ°á»ng hợp đặc biệt không được xá»­ lý: %s"
+
+msgid "End of sourced file"
+msgstr "Kết thúc tập tin script"
+
+msgid "End of function"
+msgstr "Kết thúc của hàm số"
+
+msgid "E464: Ambiguous use of user-defined command"
+msgstr "E464: Sá»± sá»­ dụng không rõ ràng câu lệnh do ngÆ°á»i dùng định nghÄ©a"
+
+msgid "E492: Not an editor command"
+msgstr "E492: Không phải là câu lệnh của trình soạn thảo"
+
+msgid "E493: Backwards range given"
+msgstr "E493: ÄÆ°a ra phạm vi ngược lại"
+
+msgid "Backwards range given, OK to swap"
+msgstr "ÄÆ°a ra phạm vi ngược lại, thay đổi vị trí hai giá»›i hạn"
+
+msgid "E494: Use w or w>>"
+msgstr "E494: Hãy sử dụng w hoặc w>>"
+
+msgid "E319: Sorry, the command is not available in this version"
+msgstr "E319: Xin lỗi, câu lệnh này không có trong phiên bản này"
+
+msgid "E172: Only one file name allowed"
+msgstr "E172: Chỉ cho phép sử dụng một tên tập tin"
+
+msgid "1 more file to edit. Quit anyway?"
+msgstr "Còn 1 tập tin nữa cần soạn thảo. Thoát?"
+
+#, c-format
+msgid "%d more files to edit. Quit anyway?"
+msgstr "Còn %d tập tin nữa chưa soạn thảo. Thoát?"
+
+msgid "E173: 1 more file to edit"
+msgstr "E173: 1 tập tin nữa chỠsoạn thảo."
+
+#, c-format
+msgid "E173: %ld more files to edit"
+msgstr "E173: %ld tập tin nữa chưa soạn thảo."
+
+msgid "E174: Command already exists: add ! to replace it"
+msgstr "E174: Äã có câu lệnh: Thêm ! để thay thế"
+
+msgid ""
+"\n"
+" Name Args Range Complete Definition"
+msgstr ""
+"\n"
+" Tên\t\tTham_số Phạm_vi Phần_phụ Äịnh_nghÄ©a"
+
+msgid "No user-defined commands found"
+msgstr "Không tìm thấy câu lệnh do ngÆ°á»i dùng định nghÄ©a"
+
+msgid "E175: No attribute specified"
+msgstr "E175: Không có tham số được chỉ ra"
+
+msgid "E176: Invalid number of arguments"
+msgstr "E176: Số lượng tham số không đúng"
+
+msgid "E177: Count cannot be specified twice"
+msgstr "E177: Số đếm không thể được chỉ ra hai lần"
+
+msgid "E178: Invalid default value for count"
+msgstr "E178: Giá trị của số đếm theo mặc định không đúng"
+
+msgid "E179: argument required for complete"
+msgstr "E179: yêu cầu đưa ra tham số để kết thúc"
+
+#, c-format
+msgid "E180: Invalid complete value: %s"
+msgstr "E180: Giá trị phần phụ không đúng: %s"
+
+msgid "E468: Completion argument only allowed for custom completion"
+msgstr ""
+"E468: Tham số tự động kết thúc chỉ cho phép sử dụng với phần phụ đặc biệt"
+
+msgid "E467: Custom completion requires a function argument"
+msgstr "E467: Phần phục đặc biệt yêu cầu một tham số của hàm"
+
+#, c-format
+msgid "E181: Invalid attribute: %s"
+msgstr "E181: Thuộc tính không đúng: %s"
+
+msgid "E182: Invalid command name"
+msgstr "E182: Tên câu lệnh không đúng"
+
+msgid "E183: User defined commands must start with an uppercase letter"
+msgstr "E183: Câu lệnh ngÆ°á»i dùng định nghÄ©a phải bắt đầu vá»›i má»™t ký tá»± hoa"
+
+#, c-format
+msgid "E184: No such user-defined command: %s"
+msgstr "E184: Không có câu lệnh ngÆ°á»i dùng định nghÄ©a nhÆ° vậy: %s"
+
+#, c-format
+msgid "E185: Cannot find color scheme %s"
+msgstr "E185: Không tin thấy sơ đồ màu sắc %s"
+
+msgid "Greetings, Vim user!"
+msgstr "Xin chào ngÆ°á»i dùng Vim!"
+
+msgid "Edit File in new window"
+msgstr "Soạn thảo tập tin trong cửa sổ mới"
+
+msgid "No swap file"
+msgstr "Không có tập tin swap"
+
+msgid "Append File"
+msgstr "Thêm tập tin"
+
+msgid "E186: No previous directory"
+msgstr "E186: Không có thư mục trước"
+
+msgid "E187: Unknown"
+msgstr "E187: Không rõ"
+
+msgid "E465: :winsize requires two number arguments"
+msgstr "E465: câu lệnh :winsize yêu cầu hai tham số bằng số"
+
+#, c-format
+msgid "Window position: X %d, Y %d"
+msgstr "Vị trí cửa sổ: X %d, Y %d"
+
+msgid "E188: Obtaining window position not implemented for this platform"
+msgstr "E188: Trên hệ thống này việc xác định vị trí cửa sổ không làm việc"
+
+msgid "E466: :winpos requires two number arguments"
+msgstr "E466: câu lệnh :winpos yêu câu hai tham số bằng số"
+
+msgid "Save Redirection"
+msgstr "Chuyển hướng ghi nhớ"
+
+msgid "Save View"
+msgstr "Ghi nhớ vẻ ngoài"
+
+msgid "Save Session"
+msgstr "Ghi nhớ buổi làm việc"
+
+msgid "Save Setup"
+msgstr "Ghi nhớ cấu hình"
+
+#, c-format
+msgid "E189: \"%s\" exists (add ! to override)"
+msgstr "E189: \"%s\" đã có (thêm !, để ghi đè)"
+
+#, c-format
+msgid "E190: Cannot open \"%s\" for writing"
+msgstr "E190: Không mở được \"%s\" để ghi nhớ"
+
+#. set mark
+msgid "E191: Argument must be a letter or forward/backward quote"
+msgstr "E191: Tham số phải là một chữ cái hoặc dấu ngoặc thẳng/ngược"
+
+msgid "E192: Recursive use of :normal too deep"
+msgstr "E192: Sử dụng đệ quy lệnh :normal quá sâu"
+
+msgid "E194: No alternate file name to substitute for '#'"
+msgstr "E194: Không có tên tập tin tương đương để thay thế '#'"
+
+msgid "E495: no autocommand file name to substitute for \"<afile>\""
+msgstr "E495: Không có tên tập tin câu lệnh tự động để thay thế \"<afile>\""
+
+msgid "E496: no autocommand buffer number to substitute for \"<abuf>\""
+msgstr ""
+"E496: Không có số thứ tự bộ đệm câu lệnh tự động để thay thế \"<abuf>\""
+
+msgid "E497: no autocommand match name to substitute for \"<amatch>\""
+msgstr "E497: Không có tên tương ứng câu lệnh tự động để thay thế \"<amatch>\""
+
+msgid "E498: no :source file name to substitute for \"<sfile>\""
+msgstr "E498: không có tên tập tin :source để thay thế \"<sfile>\""
+
+#, no-c-format
+msgid "E499: Empty file name for '%' or '#', only works with \":p:h\""
+msgstr "E499: Tên tập tin rỗng cho '%' hoặc '#', chỉ làm việc với \":p:h\""
+
+msgid "E500: Evaluates to an empty string"
+msgstr "E500: Kết quả của biểu thức là một chuỗi rỗng"
+
+msgid "E195: Cannot open viminfo file for reading"
+msgstr "E195: Không thể mở tập tin viminfo để Ä‘á»c"
+
+msgid "E196: No digraphs in this version"
+msgstr "E196: Trong phiên bản này chữ ghép không được hỗ trợ"
+
+msgid "E608: Cannot :throw exceptions with 'Vim' prefix"
+msgstr ""
+"E608: Không thể thá»±c hiện lệnh :throw cho những ngoại lệ vá»›i tiá»n tố 'Vim'"
+
+#. always scroll up, don't overwrite
+#, c-format
+msgid "Exception thrown: %s"
+msgstr "TrÆ°á»ng hợp ngoại lệ: %s"
+
+#, c-format
+msgid "Exception finished: %s"
+msgstr "Kết thúc việc xá»­ lý trÆ°á»ng hợp ngoại lệ: %s"
+
+#, c-format
+msgid "Exception discarded: %s"
+msgstr "TrÆ°á»ng hợp ngoại lệ bị bá» qua: %s"
+
+#, c-format
+msgid "%s, line %ld"
+msgstr "%s, dòng %ld"
+
+#. always scroll up, don't overwrite
+#, c-format
+msgid "Exception caught: %s"
+msgstr "Xá»­ lý trÆ°á»ng hợp ngoại lệ: %s"
+
+#, c-format
+msgid "%s made pending"
+msgstr "%s thực hiện việc chỠđợi"
+
+#, c-format
+msgid "%s resumed"
+msgstr "%s được phục hồi lại"
+
+#, c-format
+msgid "%s discarded"
+msgstr "%s bị bỠqua"
+
+msgid "Exception"
+msgstr "TrÆ°á»ng hợp ngoại lệ"
+
+msgid "Error and interrupt"
+msgstr "Lỗi và sự gián đoạn"
+
+msgid "Error"
+msgstr "Lá»—i"
+
+#. if (pending & CSTP_INTERRUPT)
+msgid "Interrupt"
+msgstr "Sự gián đoạn"
+
+msgid "E579: :if nesting too deep"
+msgstr "E579: :if xếp lồng vào nhau quá sâu"
+
+msgid "E580: :endif without :if"
+msgstr "E580: :endif không có :if"
+
+msgid "E581: :else without :if"
+msgstr "E581: :else không có :if"
+
+msgid "E582: :elseif without :if"
+msgstr "E582: :elseif không có :if"
+
+msgid "E583: multiple :else"
+msgstr "E583: phát hiện vài :else"
+
+msgid "E584: :elseif after :else"
+msgstr "E584: :elseif sau :else"
+
+msgid "E585: :while nesting too deep"
+msgstr "E585: :while xếp lồng vào nhau quá sâu"
+
+msgid "E586: :continue without :while"
+msgstr "E586: :continue không có :while"
+
+msgid "E587: :break without :while"
+msgstr "E587: :break không có :while"
+
+msgid "E601: :try nesting too deep"
+msgstr "E601: :try xếp lồng vào nhau quá sâu"
+
+msgid "E603: :catch without :try"
+msgstr "E603: :catch không có :try"
+
+#. Give up for a ":catch" after ":finally" and ignore it.
+#. * Just parse.
+msgid "E604: :catch after :finally"
+msgstr "E604: :catch đứng sau :finally"
+
+msgid "E606: :finally without :try"
+msgstr "E606: :finally không có :try"
+
+#. Give up for a multiple ":finally" and ignore it.
+msgid "E607: multiple :finally"
+msgstr "E607: phát hiện vài :finally"
+
+msgid "E602: :endtry without :try"
+msgstr "E602: :endtry không có :try"
+
+msgid "E193: :endfunction not inside a function"
+msgstr "E193: lệnh :endfunction chỉ được sử dụng trong một hàm số"
+
+msgid "tagname"
+msgstr "tên thẻ ghi"
+
+msgid " kind file\n"
+msgstr " loại tập tin\n"
+
+msgid "'history' option is zero"
+msgstr "giá trị của tùy chá»n 'history' bằng không"
+
+#, c-format
+msgid ""
+"\n"
+"# %s History (newest to oldest):\n"
+msgstr ""
+"\n"
+"# %s, Lịch sử (bắt đầu từ mới nhất tới cũ nhất):\n"
+
+msgid "Command Line"
+msgstr "Dòng lệnh"
+
+msgid "Search String"
+msgstr "Chuỗi tìm kiếm"
+
+msgid "Expression"
+msgstr "Biểu thức"
+
+msgid "Input Line"
+msgstr "Dòng nhập"
+
+msgid "E198: cmd_pchar beyond the command length"
+msgstr "E198: cmd_pchar lá»›n hÆ¡n chiá»u dài câu lệnh"
+
+msgid "E199: Active window or buffer deleted"
+msgstr "E199: Cửa sổ hoặc bộ đệm hoạt động bị xóa"
+
+msgid "Illegal file name"
+msgstr "Tên tập tin không cho phép"
+
+msgid "is a directory"
+msgstr "là một thư mục"
+
+msgid "is not a file"
+msgstr "không phải là một tập tin"
+
+msgid "[New File]"
+msgstr "[Tập tin mới]"
+
+msgid "[Permission Denied]"
+msgstr "[Truy cập bị từ chối]"
+
+msgid "E200: *ReadPre autocommands made the file unreadable"
+msgstr ""
+"E200: Câu lệnh tá»± Ä‘á»™ng *ReadPre làm cho tập tin trở thành không thể Ä‘á»c"
+
+msgid "E201: *ReadPre autocommands must not change current buffer"
+msgstr "E201: Câu lệnh tự động *ReadPre không được thay đổi bộ đệm hoạt động"
+
+msgid "Vim: Reading from stdin...\n"
+msgstr "Vim: Äá»c từ đầu vào tiêu chuẩn stdin...\n"
+
+msgid "Reading from stdin..."
+msgstr "Äá»c từ đầu vào tiêu chuẩn stdin..."
+
+#. Re-opening the original file failed!
+msgid "E202: Conversion made file unreadable!"
+msgstr "E202: Sá»± biến đổi làm cho tập tin trở thành không thể Ä‘á»c!"
+
+msgid "[fifo/socket]"
+msgstr "[fifo/socket]"
+
+msgid "[fifo]"
+msgstr "[fifo]"
+
+msgid "[socket]"
+msgstr "[socket]"
+
+msgid "[RO]"
+msgstr "[Chỉ Ä‘á»c]"
+
+msgid "[CR missing]"
+msgstr "[thiếu ký tự CR]"
+
+msgid "[NL found]"
+msgstr "[tìm thấy ký tự NL]"
+
+msgid "[long lines split]"
+msgstr "[dòng dài được chia nhá»]"
+
+msgid "[NOT converted]"
+msgstr "[KHÔNG được chuyển đổi]"
+
+msgid "[converted]"
+msgstr "[đã chuyển bảng mã]"
+
+msgid "[crypted]"
+msgstr "[đã mã hóa]"
+
+msgid "[CONVERSION ERROR]"
+msgstr "[LỖI CHUYỂN BẢNG MÃ]"
+
+#, c-format
+msgid "[ILLEGAL BYTE in line %ld]"
+msgstr "[BYTE KHÔNG CHO PHÉP trên dòng %ld]"
+
+msgid "[READ ERRORS]"
+msgstr "[Lá»–I ÄỌC]"
+
+msgid "Can't find temp file for conversion"
+msgstr "Không tìm thấy tập tin tạm thá»i (temp) để chuyển bảng mã"
+
+msgid "Conversion with 'charconvert' failed"
+msgstr "Chuyển đổi nhỠ'charconvert' không được thực hiện"
+
+msgid "can't read output of 'charconvert'"
+msgstr "không Ä‘á»c được đầu ra của 'charconvert'"
+
+msgid "E203: Autocommands deleted or unloaded buffer to be written"
+msgstr "E203: Câu lệnh tự động đã xóa hoặc bỠnạp bộ đệm cần ghi nhớ"
+
+msgid "E204: Autocommand changed number of lines in unexpected way"
+msgstr "E204: Câu lệnh tự động đã thay đổ số dòng theo cách không mong muốn"
+
+msgid "NetBeans disallows writes of unmodified buffers"
+msgstr "NetBeans không cho phép ghi nhớ bộ đệm chưa có thay đổi nào"
+
+msgid "Partial writes disallowed for NetBeans buffers"
+msgstr "Ghi nhớ một phần bộ đệm NetBeans không được cho phép"
+
+msgid "is not a file or writable device"
+msgstr "không phải là một tập tin thay một thiết bị có thể ghi nhớ"
+
+msgid "is read-only (add ! to override)"
+msgstr "là tập tin chỉ Ä‘á»c (thêm ! để ghi nhá»› bằng má»i giá)"
+
+msgid "E506: Can't write to backup file (add ! to override)"
+msgstr ""
+"E506: Không thể ghi nhá»› vào tập tin lÆ°u trữ (thêm ! để ghi nhá»› bằng má»i giá"
+
+msgid "E507: Close error for backup file (add ! to override)"
+msgstr "E507: Lỗi đóng tập tin lưu trữ (thêm ! để bỠqua việc kiểm tra lại)"
+
+msgid "E508: Can't read file for backup (add ! to override)"
+msgstr ""
+"E508: Không Ä‘á»c được tập tin lÆ°u trữ (thêm ! để bá» qua việc kiểm tra lại)"
+
+msgid "E509: Cannot create backup file (add ! to override)"
+msgstr ""
+"E509: Không tạo được tập tin lưu trữ (thêm ! để bỠqua việc kiểm tra lại)"
+
+msgid "E510: Can't make backup file (add ! to override)"
+msgstr ""
+"E510: Không tạo được tập tin lưu trữ (thêm ! để bỠqua việc kiểm tra lại)"
+
+msgid "E460: The resource fork would be lost (add ! to override)"
+msgstr "E460: Nhánh tài nguyên sẽ bị mất (thêm ! để bỠqua việc kiểm tra lại)"
+
+msgid "E214: Can't find temp file for writing"
+msgstr "E214: Không tìm thấy tập tin tạm thá»i (temp) để ghi nhá»›"
+
+msgid "E213: Cannot convert (add ! to write without conversion)"
+msgstr ""
+"E213: Không thể chuyển đổi bảng mã (thêm ! để ghi nhớ mà không chuyển đổi)"
+
+msgid "E166: Can't open linked file for writing"
+msgstr "E166: Không thể mở tập tin liên kết để ghi nhớ"
+
+msgid "E212: Can't open file for writing"
+msgstr "E212: Không thể mở tập tin để ghi nhớ"
+
+msgid "E667: Fsync failed"
+msgstr "E667: Không thực hiện thành công hàm số fsync()"
+
+msgid "E512: Close failed"
+msgstr "E512: Thao tác đóng không thành công"
+
+msgid "E513: write error, conversion failed"
+msgstr "E513: Lỗi ghi nhớ, biến đổi không thành công"
+
+msgid "E514: write error (file system full?)"
+msgstr "E514: lỗi ghi nhớ (không còn chỗ trống?)"
+
+msgid " CONVERSION ERROR"
+msgstr " Lá»–I BIẾN Äá»”I"
+
+msgid "[Device]"
+msgstr "[Thiết bị]"
+
+msgid "[New]"
+msgstr "[Má»›i]"
+
+msgid " [a]"
+msgstr " [a]"
+
+msgid " appended"
+msgstr " đã thêm"
+
+msgid " [w]"
+msgstr " [w]"
+
+msgid " written"
+msgstr " đã ghi"
+
+msgid "E205: Patchmode: can't save original file"
+msgstr "E205: Chế độ vá lỗi (patch): không thể ghi nhớ tập tin gốc"
+
+msgid "E206: patchmode: can't touch empty original file"
+msgstr ""
+"E206: Chế độ vá lỗi (patch): không thể thay đổi tham số của tập tin gốc "
+"trống rỗng"
+
+msgid "E207: Can't delete backup file"
+msgstr "E207: Không thể xóa tập tin lưu trữ (backup)"
+
+msgid ""
+"\n"
+"WARNING: Original file may be lost or damaged\n"
+msgstr ""
+"\n"
+"CẢNH BÃO: Tập tin gốc có thể bị mất hoặc bị há»ng\n"
+
+msgid "don't quit the editor until the file is successfully written!"
+msgstr ""
+"đừng thoát khởi trình soạn thảo, khi tập tin còn chưa được ghi nhớ thành cồng"
+
+msgid "[dos]"
+msgstr "[dos]"
+
+msgid "[dos format]"
+msgstr "[định dạng dos]"
+
+msgid "[mac]"
+msgstr "[mac]"
+
+msgid "[mac format]"
+msgstr "[định dạng mac]"
+
+msgid "[unix]"
+msgstr "[unix]"
+
+msgid "[unix format]"
+msgstr "[định dạng unix]"
+
+msgid "1 line, "
+msgstr "1 dòng, "
+
+#, c-format
+msgid "%ld lines, "
+msgstr "%ld dòng, "
+
+msgid "1 character"
+msgstr "1 ký tự"
+
+#, c-format
+msgid "%ld characters"
+msgstr "%ld ký tự"
+
+msgid "[noeol]"
+msgstr "[noeol]"
+
+msgid "[Incomplete last line]"
+msgstr "[Dòng cuối cùng không đầy đủ]"
+
+#. don't overwrite messages here
+#. must give this prompt
+#. don't use emsg() here, don't want to flush the buffers
+msgid "WARNING: The file has been changed since reading it!!!"
+msgstr "CẢNH BÃO: Tập tin đã thay đổi so vá»›i thá»i Ä‘iểm Ä‘á»c!!!"
+
+msgid "Do you really want to write to it"
+msgstr "Bạn có chắc muốn ghi nhớ vào tập tin này"
+
+#, c-format
+msgid "E208: Error writing to \"%s\""
+msgstr "E208: Lỗi ghi nhớ vào \"%s\""
+
+#, c-format
+msgid "E209: Error closing \"%s\""
+msgstr "E209: Lỗi đóng \"%s\""
+
+#, c-format
+msgid "E210: Error reading \"%s\""
+msgstr "E210: Lá»—i Ä‘á»c \"%s\""
+
+msgid "E246: FileChangedShell autocommand deleted buffer"
+msgstr "E246: Bộ đệm bị xóa khi thực hiện câu lệnh tự động FileChangedShell"
+
+#, c-format
+msgid "E211: Warning: File \"%s\" no longer available"
+msgstr "E211: Cảnh báo: Tập tin \"%s\" không còn truy cập được nữa"
+
+#, c-format
+msgid ""
+"W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as "
+"well"
+msgstr ""
+"W12: Cảnh báo: Tập tin \"%s\" và bộ đệm Vim đã thay đổi không phụ thuộc vào "
+"nhau"
+
+#, c-format
+msgid "W11: Warning: File \"%s\" has changed since editing started"
+msgstr ""
+"W11: Cảnh báo: Tập tin \"%s\" đã thay đổi sau khi việc soạn thảo bắt đầu"
+
+#, c-format
+msgid "W16: Warning: Mode of file \"%s\" has changed since editing started"
+msgstr ""
+"W16: Cảnh báo: chế độ truy cập tới tập tin \"%s\" đã thay đổi sau khi bắt "
+"đầu soạn thảo"
+
+#, c-format
+msgid "W13: Warning: File \"%s\" has been created after editing started"
+msgstr ""
+"W13: Cảnh báo: tập tin \"%s\" được tạo ra sau khi việc soạn thảo bắt đầu"
+
+msgid "See \":help W11\" for more info."
+msgstr "Hãy xem thông tin chi tiết trong \":help W11\"."
+
+msgid "Warning"
+msgstr "Cảnh báo"
+
+msgid ""
+"&OK\n"
+"&Load File"
+msgstr ""
+"&OK\n"
+"&Nạp tập tin"
+
+#, c-format
+msgid "E462: Could not prepare for reloading \"%s\""
+msgstr "E462: Không thể chuẩn bị để nạp lại \"%s\""
+
+#, c-format
+msgid "E321: Could not reload \"%s\""
+msgstr "E321: Không thể nạp lại \"%s\""
+
+msgid "--Deleted--"
+msgstr "--Bị xóa--"
+
+#. the group doesn't exist
+#, c-format
+msgid "E367: No such group: \"%s\""
+msgstr "E367: Nhóm \"%s\" không tồn tại"
+
+#, c-format
+msgid "E215: Illegal character after *: %s"
+msgstr "E215: Ký tự không cho phép sau *: %s"
+
+#, c-format
+msgid "E216: No such event: %s"
+msgstr "E216: Sự kiện không có thật: %s"
+
+#, c-format
+msgid "E216: No such group or event: %s"
+msgstr "E216: Nhóm hoặc sự kiện không có thật: %s"
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Autocommands ---"
+msgstr ""
+"\n"
+"--- Câu lệnh tự động ---"
+
+msgid "E217: Can't execute autocommands for ALL events"
+msgstr "E217: Không thể thực hiện câu lệnh tự động cho MỌI sự kiện"
+
+msgid "No matching autocommands"
+msgstr "Không có câu lệnh tự động tương ứng"
+
+msgid "E218: autocommand nesting too deep"
+msgstr "E218: câu lệnh tự động xếp lồng vào nhau quá xâu"
+
+#, c-format
+msgid "%s Autocommands for \"%s\""
+msgstr "%s câu lệnh tự động cho \"%s\""
+
+#, c-format
+msgid "Executing %s"
+msgstr "Thực hiện %s"
+
+#. always scroll up, don't overwrite
+#, c-format
+msgid "autocommand %s"
+msgstr "câu lệnh tự động %s"
+
+msgid "E219: Missing {."
+msgstr "E219: Thiếu {."
+
+msgid "E220: Missing }."
+msgstr "E220: Thiếu }."
+
+msgid "E490: No fold found"
+msgstr "E490: Không tìm thấy nếp gấp"
+
+msgid "E350: Cannot create fold with current 'foldmethod'"
+msgstr ""
+"E350: Không thể tạo nếp gấp vá»›i giá trị hiện thá»i của tùy chá»n 'foldmethod'"
+
+msgid "E351: Cannot delete fold with current 'foldmethod'"
+msgstr ""
+"E351: Không thể xóa nếp gấp vá»›i giá trị hiện thá»i của tùy chá»n 'foldmethod'"
+
+msgid "E222: Add to read buffer"
+msgstr "E222: Thêm vào bá»™ đệm Ä‘ang Ä‘á»c"
+
+msgid "E223: recursive mapping"
+msgstr "E223: ánh xạ đệ quy"
+
+#, c-format
+msgid "E224: global abbreviation already exists for %s"
+msgstr "E224: đã có sự viết tắt toàn cầu cho %s"
+
+#, c-format
+msgid "E225: global mapping already exists for %s"
+msgstr "E225: đã có ánh xạ toàn cầu cho %s"
+
+#, c-format
+msgid "E226: abbreviation already exists for %s"
+msgstr "E226: đã có sự viết tắt cho %s"
+
+#, c-format
+msgid "E227: mapping already exists for %s"
+msgstr "E227: đã có ánh xạ cho %s"
+
+msgid "No abbreviation found"
+msgstr "Không tìm thấy viết tắt"
+
+msgid "No mapping found"
+msgstr "Không tìm thấy ánh xạ"
+
+msgid "E228: makemap: Illegal mode"
+msgstr "E228: makemap: Chế độ không cho phép"
+
+msgid "<cannot open> "
+msgstr "<không thể mở> "
+
+#, c-format
+msgid "E616: vim_SelFile: can't get font %s"
+msgstr "E616: vim_SelFile: không tìm thấy phông chữ %s"
+
+msgid "E614: vim_SelFile: can't return to current directory"
+msgstr "E614: vim_SelFile: không trở lại được thÆ° mục hiện thá»i"
+
+msgid "Pathname:"
+msgstr "ÄÆ°á»ng dẫn tá»›i tập tin:"
+
+msgid "E615: vim_SelFile: can't get current directory"
+msgstr "E615: vim_SelFile: không tìm thấy thÆ° mục hiện thá»i"
+
+msgid "OK"
+msgstr "Äồng ý"
+
+msgid "Cancel"
+msgstr "Hủy bá»"
+
+msgid "Vim dialog"
+msgstr "Hộp thoại Vim"
+
+msgid "Scrollbar Widget: Could not get geometry of thumb pixmap."
+msgstr "Thanh cuá»™n: Không thể xác định hình há»c của thanh cuá»™n."
+
+msgid "E232: Cannot create BalloonEval with both message and callback"
+msgstr "E232: Không tạo được BalloonEval vá»›i cả thông báo và lá»i gá»i ngược lại"
+
+msgid "E229: Cannot start the GUI"
+msgstr "E229: Không chạy được giao diện đồ há»a GUI"
+
+#, c-format
+msgid "E230: Cannot read from \"%s\""
+msgstr "E230: Không Ä‘á»c được từ \"%s\""
+
+msgid "E665: Cannot start GUI, no valid font found"
+msgstr ""
+"E665: Không chạy được giao diện đồ há»a GUI, Ä‘Æ°a ra phông chữ không đúng"
+
+msgid "E231: 'guifontwide' invalid"
+msgstr "E231: 'guifontwide' có giá trị không đúng"
+
+msgid "E599: Value of 'imactivatekey' is invalid"
+msgstr "E599: Giá trị của 'imactivatekey' không đúng"
+
+#, c-format
+msgid "E254: Cannot allocate color %s"
+msgstr "E254: Không chỉ định được màu %s"
+
+msgid "Vim dialog..."
+msgstr "Hộp thoại Vim..."
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"&Cancel"
+msgstr ""
+"&Có\n"
+"&Không\n"
+"&Dừng"
+
+msgid "Input _Methods"
+msgstr "Phương pháp _nhập liệu"
+
+msgid "VIM - Search and Replace..."
+msgstr "VIM - Tìm kiếm và thay thế..."
+
+msgid "VIM - Search..."
+msgstr "VIM - Tìm kiếm..."
+
+msgid "Find what:"
+msgstr "Tìm kiếm gì:"
+
+msgid "Replace with:"
+msgstr "Thay thế bởi:"
+
+#. whole word only button
+msgid "Match whole word only"
+msgstr "Chỉ tìm tương ứng hoàn toàn với từ"
+
+#. match case button
+msgid "Match case"
+msgstr "Có tính kiểu chữ"
+
+msgid "Direction"
+msgstr "HÆ°á»›ng"
+
+#. 'Up' and 'Down' buttons
+msgid "Up"
+msgstr "Lên"
+
+msgid "Down"
+msgstr "Xuống"
+
+msgid "Find Next"
+msgstr "Tìm tiếp"
+
+msgid "Replace"
+msgstr "Thay thế"
+
+msgid "Replace All"
+msgstr "Thay thế tất cả"
+
+msgid "Vim: Received \"die\" request from session manager\n"
+msgstr "Vim: Nhận được yêu cầu \"chết\" (dừng) từ trình quản lý màn hình\n"
+
+msgid "Vim: Main window unexpectedly destroyed\n"
+msgstr "Vim: Cửa sổ chính đã bị đóng đột ngột\n"
+
+msgid "Font Selection"
+msgstr "Chá»n phông chữ"
+
+msgid "Used CUT_BUFFER0 instead of empty selection"
+msgstr "Sá»­ dụng CUT_BUFFER0 thay cho lá»±a chá»n trống rá»—ng"
+
+msgid "Filter"
+msgstr "Äầu lá»c"
+
+msgid "Directories"
+msgstr "Thư mục"
+
+msgid "Help"
+msgstr "Trợ giúp"
+
+msgid "Files"
+msgstr "Tập tin"
+
+msgid "Selection"
+msgstr "Lá»±a chá»n"
+
+msgid "Undo"
+msgstr "Hủy thao tác"
+
+#, c-format
+msgid "E671: Cannot find window title \"%s\""
+msgstr "E671: Không tìm được tiêu đỠcửa sổ \"%s\""
+
+#, c-format
+msgid "E243: Argument not supported: \"-%s\"; Use the OLE version."
+msgstr "E243: Tham số không được hỗ trợ: \"-%s\"; Hãy sử dụng phiên bản OLE."
+
+msgid "E672: Unable to open window inside MDI application"
+msgstr "E672: Không mở được cửa sổ bên trong ứng dụng MDI"
+
+msgid "Find string (use '\\\\' to find a '\\')"
+msgstr "Tìm kiếm chuỗi (hãy sử dụng '\\\\' để tìm kiếm dấu '\\')"
+
+msgid "Find & Replace (use '\\\\' to find a '\\')"
+msgstr "Tìm kiếm và Thay thế (hãy sử dụng '\\\\' để tìm kiếm dấu '\\')"
+
+msgid "Vim E458: Cannot allocate colormap entry, some colors may be incorrect"
+msgstr ""
+"Vim E458: Không chỉ định được bản ghi trong bảng màu, một vài màu có thể "
+"hiển thị không chính xác"
+
+#, c-format
+msgid "E250: Fonts for the following charsets are missing in fontset %s:"
+msgstr "E250: Trong bộ phông chữ %s thiếu phông cho các bảng mã sau:"
+
+#, c-format
+msgid "E252: Fontset name: %s"
+msgstr "E252: Bộ phông chữ: %s"
+
+#, c-format
+msgid "Font '%s' is not fixed-width"
+msgstr "Phông chữ '%s' không phải là phông có độ rộng cố định (fixed-width)"
+
+#, c-format
+msgid "E253: Fontset name: %s\n"
+msgstr "E253: Bộ phông chữ: %s\n"
+
+#, c-format
+msgid "Font0: %s\n"
+msgstr "Font0: %s\n"
+
+#, c-format
+msgid "Font1: %s\n"
+msgstr "Font1: %s\n"
+
+#, c-format
+msgid "Font%ld width is not twice that of font0\n"
+msgstr ""
+"Chiá»u rá»™ng phông chữ font%ld phải lá»›n hÆ¡n hai lần so vá»›i chiá»u rá»™ng font0\n"
+
+#, c-format
+msgid "Font0 width: %ld\n"
+msgstr "Chiá»u rá»™ng font0: %ld\n"
+
+#, c-format
+msgid ""
+"Font1 width: %ld\n"
+"\n"
+msgstr ""
+"Chiá»u rá»™ng font1: %ld\n"
+"\n"
+
+msgid "E256: Hangul automata ERROR"
+msgstr "E256: LỖI máy tự động Hangual (tiếng Hàn)"
+
+msgid "Add a new database"
+msgstr "Thêm một cơ sở dữ liệu mới"
+
+msgid "Query for a pattern"
+msgstr "Yêu cầu theo một mẫu"
+
+msgid "Show this message"
+msgstr "Hiển thị thông báo này"
+
+msgid "Kill a connection"
+msgstr "Hủy kết nối"
+
+msgid "Reinit all connections"
+msgstr "Khởi đầu lại tất cả các kết nối"
+
+msgid "Show connections"
+msgstr "Hiển thị kết nối"
+
+#, c-format
+msgid "E560: Usage: cs[cope] %s"
+msgstr "E560: Sử dụng: cs[cope] %s"
+
+msgid "This cscope command does not support splitting the window.\n"
+msgstr "Câu lệnh cscope này không hỗ trợ việc chia (split) cửa sổ.\n"
+
+msgid "E562: Usage: cstag <ident>"
+msgstr "E562: Sử dụng: cstag <tên>"
+
+msgid "E257: cstag: tag not found"
+msgstr "E257: cstag: không tìm thấy thẻ ghi"
+
+#, c-format
+msgid "E563: stat(%s) error: %d"
+msgstr "E563: lá»—i stat(%s): %d"
+
+msgid "E563: stat error"
+msgstr "E563: lá»—i stat"
+
+#, c-format
+msgid "E564: %s is not a directory or a valid cscope database"
+msgstr ""
+"E564: %s không phải là một thư mục hoặc một cơ sở dữ liệu cscope thích hợp"
+
+#, c-format
+msgid "Added cscope database %s"
+msgstr "Äã thêm cÆ¡ sở dữ liệu cscope %s"
+
+#, c-format
+msgid "E262: error reading cscope connection %ld"
+msgstr "E262: lỗi lấy thông tin từ kết nối cscope %ld"
+
+msgid "E561: unknown cscope search type"
+msgstr "E561: không rõ loại tìm kiếm cscope"
+
+msgid "E566: Could not create cscope pipes"
+msgstr "E566: Không tạo được Ä‘Æ°á»ng ống (pipe) cho cscope"
+
+msgid "E622: Could not fork for cscope"
+msgstr "E622: Không thực hiện được fork() cho cscope"
+
+msgid "cs_create_connection exec failed"
+msgstr "thực hiện cs_create_connection không thành công"
+
+msgid "E623: Could not spawn cscope process"
+msgstr "E623: Chạy tiến trình cscope không thành công"
+
+msgid "cs_create_connection: fdopen for to_fp failed"
+msgstr "cs_create_connection: thực hiện fdopen cho to_fp không thành công"
+
+msgid "cs_create_connection: fdopen for fr_fp failed"
+msgstr "cs_create_connection: thực hiện fdopen cho fr_fp không thành công"
+
+msgid "E567: no cscope connections"
+msgstr "E567: không có kết nối với cscope"
+
+#, c-format
+msgid "E259: no matches found for cscope query %s of %s"
+msgstr "E259: không tìm thấy tương ứng với yêu cầu cscope %s cho %s"
+
+#, c-format
+msgid "E469: invalid cscopequickfix flag %c for %c"
+msgstr "E469: cỠcscopequickfix %c cho %c không chính xác"
+
+msgid "cscope commands:\n"
+msgstr "các lệnh cscope:\n"
+
+#, c-format
+msgid "%-5s: %-30s (Usage: %s)"
+msgstr "%-5s: %-30s (Sử dụng: %s)"
+
+#, c-format
+msgid "E625: cannot open cscope database: %s"
+msgstr "E625: không mở được cơ sở dữ liệu cscope: %s"
+
+msgid "E626: cannot get cscope database information"
+msgstr "E626: không lấy được thông tin vỠcơ sở dữ liệu cscope"
+
+msgid "E568: duplicate cscope database not added"
+msgstr "E568: cơ sở dữ liệu này của cscope đã được gắn vào từ trước"
+
+msgid "E569: maximum number of cscope connections reached"
+msgstr "E569: đã đạt tới số kết nối lớn nhất cho phép với cscope"
+
+#, c-format
+msgid "E261: cscope connection %s not found"
+msgstr "E261: kết nối với cscope %s không được tìm thấy"
+
+#, c-format
+msgid "cscope connection %s closed"
+msgstr "kết nối %s với cscope đã bị đóng"
+
+#. should not reach here
+msgid "E570: fatal error in cs_manage_matches"
+msgstr "E570: lỗi nặng trong cs_manage_matches"
+
+#, c-format
+msgid "Cscope tag: %s"
+msgstr "Thẻ ghi cscope: %s"
+
+msgid ""
+"\n"
+" # line"
+msgstr ""
+"\n"
+" # dòng"
+
+msgid "filename / context / line\n"
+msgstr "tên tập tin / nội dung / dòng\n"
+
+#, c-format
+msgid "E609: Cscope error: %s"
+msgstr "E609: Lá»—i cscope: %s"
+
+msgid "All cscope databases reset"
+msgstr "Khởi động lại tất cả cơ sở dữ liệu cscope"
+
+msgid "no cscope connections\n"
+msgstr "không có kết nối với cscope\n"
+
+msgid " # pid database name prepend path\n"
+msgstr " # pid tên cÆ¡ sở dữ liệu Ä‘Æ°á»ng dẫn ban đầu\n"
+
+msgid ""
+"E263: Sorry, this command is disabled, the Python library could not be "
+"loaded."
+msgstr ""
+"E263: Rất tiếc câu lệnh này không làm việc, vì thư viện Python chưa được nạp."
+
+msgid "E659: Cannot invoke Python recursively"
+msgstr "E659: Không thể gá»i Python má»™t cách đệ quy"
+
+msgid "can't delete OutputObject attributes"
+msgstr "Không xóa được thuộc tính OutputObject"
+
+msgid "softspace must be an integer"
+msgstr "giá trị softspace phải là một số nguyên"
+
+msgid "invalid attribute"
+msgstr "thuộc tính không đúng"
+
+msgid "writelines() requires list of strings"
+msgstr "writelines() yêu cầu một danh sách các chuỗi"
+
+msgid "E264: Python: Error initialising I/O objects"
+msgstr "E264: Python: Lỗi khi bắt đầu sử dụng vật thể I/O"
+
+msgid "invalid expression"
+msgstr "biểu thức không đúng"
+
+msgid "expressions disabled at compile time"
+msgstr "biểu thức bị tắt khi biên dịch"
+
+msgid "attempt to refer to deleted buffer"
+msgstr "cố chỉ đến bộ đệm đã bị xóa"
+
+msgid "line number out of range"
+msgstr "số thứ tự của dòng vượt quá giới hạn"
+
+#, c-format
+msgid "<buffer object (deleted) at %8lX>"
+msgstr "<vật thể của bộ đệm (bị xóa) tại %8lX>"
+
+msgid "invalid mark name"
+msgstr "tên dấu hiệu không đúng"
+
+msgid "no such buffer"
+msgstr "không có bộ đệm như vậy"
+
+msgid "attempt to refer to deleted window"
+msgstr "cố chỉ đến cửa sổ đã bị đóng"
+
+msgid "readonly attribute"
+msgstr "thuá»™c tính chỉ Ä‘á»c"
+
+msgid "cursor position outside buffer"
+msgstr "vị trí con trỠnằm ngoài bộ đệm"
+
+#, c-format
+msgid "<window object (deleted) at %.8lX>"
+msgstr "<vật thể của cửa sổ (bị xóa) tại %.8lX>"
+
+#, c-format
+msgid "<window object (unknown) at %.8lX>"
+msgstr "<vật thể của cửa sổ (không rõ) tại %.8lX>"
+
+#, c-format
+msgid "<window %d>"
+msgstr "<cửa sổ %d>"
+
+msgid "no such window"
+msgstr "không có cửa sổ như vậy"
+
+msgid "cannot save undo information"
+msgstr "không ghi được thông tin vỠviệc hủy thao tác"
+
+msgid "cannot delete line"
+msgstr "không xóa được dòng"
+
+msgid "cannot replace line"
+msgstr "không thay thế được dòng"
+
+msgid "cannot insert line"
+msgstr "không chèn được dòng"
+
+msgid "string cannot contain newlines"
+msgstr "chuỗi không thể chứa ký tự dòng mới"
+
+msgid ""
+"E266: Sorry, this command is disabled, the Ruby library could not be loaded."
+msgstr ""
+"E266: Rất tiếc câu lệnh này không làm việc, vì thư viện Ruby chưa đượcnạp."
+
+#, c-format
+msgid "E273: unknown longjmp status %d"
+msgstr "E273: không rõ trạng thái của longjmp %d"
+
+msgid "Toggle implementation/definition"
+msgstr "Bật tắt giữa thi hành/định nghĩa"
+
+msgid "Show base class of"
+msgstr "Hiển thị hạng cơ bản của"
+
+msgid "Show overridden member function"
+msgstr "Hiển thị hàm số bị nạp đè lên"
+
+msgid "Retrieve from file"
+msgstr "Nhận từ tập tin"
+
+msgid "Retrieve from project"
+msgstr "Nhận từ dự án"
+
+msgid "Retrieve from all projects"
+msgstr "Nhận từ tất cả các dự án"
+
+msgid "Retrieve"
+msgstr "Nhận"
+
+msgid "Show source of"
+msgstr "Hiển thị mã nguồn"
+
+msgid "Find symbol"
+msgstr "Tìm ký hiệu"
+
+msgid "Browse class"
+msgstr "Duyệt hạng"
+
+msgid "Show class in hierarchy"
+msgstr "Hiển thị hạng trong hệ thống cấp bậc"
+
+msgid "Show class in restricted hierarchy"
+msgstr "Hiển thị hạng trong hệ thống cấp bậc giới hạn"
+
+msgid "Xref refers to"
+msgstr "Xref chỉ đến"
+
+msgid "Xref referred by"
+msgstr "Liên kết đến xref từ"
+
+msgid "Xref has a"
+msgstr "Xref có một"
+
+msgid "Xref used by"
+msgstr "Xref được sử dụng bởi"
+
+msgid "Show docu of"
+msgstr "Hiển thị docu của"
+
+msgid "Generate docu for"
+msgstr "Tạo docu cho"
+
+msgid ""
+"Cannot connect to SNiFF+. Check environment (sniffemacs must be found in "
+"$PATH).\n"
+msgstr ""
+"Không kết nối được tá»›i SNiFF+. Hãy kiểm tra cấu hình môi trÆ°á»ng.(sniffemacs "
+"phải được chỉ ra trong biến $PATH).\n"
+
+msgid "E274: Sniff: Error during read. Disconnected"
+msgstr "E274: Sniff: Lá»—i trong thá»i gian Ä‘á»c. Ngắt kết nối"
+
+msgid "SNiFF+ is currently "
+msgstr "Trong thá»i Ä‘iểm hiện nay SNiFF+ "
+
+msgid "not "
+msgstr "không "
+
+msgid "connected"
+msgstr "được kết nối"
+
+#, c-format
+msgid "E275: Unknown SNiFF+ request: %s"
+msgstr "E275: không rõ yêu cầu của SNiFF+: %s"
+
+msgid "E276: Error connecting to SNiFF+"
+msgstr "E276: Lỗi kết nối với SNiFF+"
+
+msgid "E278: SNiFF+ not connected"
+msgstr "E278: SNiFF+ chưa được kết nối"
+
+msgid "E279: Not a SNiFF+ buffer"
+msgstr "E279: Äây không phải là bá»™ đệm SNiFF+"
+
+msgid "Sniff: Error during write. Disconnected"
+msgstr "Sniff: Lá»—i trong thá»i gian ghi nhá»›. Ngắt kết nối"
+
+msgid "invalid buffer number"
+msgstr "số của bộ đệm không đúng"
+
+msgid "not implemented yet"
+msgstr "tạm thá»i chÆ°a được thá»±c thi"
+
+msgid "unknown option"
+msgstr "tùy chá»n không rõ"
+
+#. ???
+msgid "cannot set line(s)"
+msgstr "không thể đặt (các) dòng"
+
+msgid "mark not set"
+msgstr "dấu hiệu chưa được đặt"
+
+#, c-format
+msgid "row %d column %d"
+msgstr "hàng %d cột %d"
+
+msgid "cannot insert/append line"
+msgstr "không thể chèn hoặc thêm dòng"
+
+msgid "unknown flag: "
+msgstr "cỠkhông biết: "
+
+msgid "unknown vimOption"
+msgstr "không rõ tùy chá»n vimOption"
+
+msgid "keyboard interrupt"
+msgstr "sự gián đoạn của bàn phím"
+
+msgid "vim error"
+msgstr "lỗi của vim"
+
+msgid "cannot create buffer/window command: object is being deleted"
+msgstr "không tạo được câu lệnh của bộ đệm hay của cửa sổ: vật thể đang bị xóa"
+
+msgid ""
+"cannot register callback command: buffer/window is already being deleted"
+msgstr "không đăng ký được câu lệnh gá»i ngược: bá»™ đệm hoặc cá»­a sổ Ä‘ang bị xóa"
+
+#. This should never happen. Famous last word?
+msgid ""
+"E280: TCL FATAL ERROR: reflist corrupt!? Please report this to vim-dev@vim."
+"org"
+msgstr ""
+"E280: Lá»–I NẶNG CỦA TCL: bị há»ng danh sách liên kết!? Hãy thông báo việc "
+"nàyđến danh sách thư (mailing list) vim-dev@vim.org"
+
+msgid "cannot register callback command: buffer/window reference not found"
+msgstr ""
+"không đăng ký được câu lệnh gá»i ngược: không tìm thấy liên kết đến bá»™ đệm "
+"hoặc cửa sổ"
+
+msgid ""
+"E571: Sorry, this command is disabled: the Tcl library could not be loaded."
+msgstr ""
+"E571: Rất tiếc là câu lệnh này không làm việc, vì thư viện Tcl chưa được nạp"
+
+msgid ""
+"E281: TCL ERROR: exit code is not int!? Please report this to vim-dev@vim.org"
+msgstr ""
+"E281: Lá»–I TCL: mã thoát ra không phải là má»™t số nguyên!? Hãy thông báo Ä‘iá»u "
+"này đến danh sách thư (mailing list) vim-dev@vim.org"
+
+msgid "cannot get line"
+msgstr "không nhận được dòng"
+
+msgid "Unable to register a command server name"
+msgstr "Không đăng ký được một tên cho máy chủ câu lệnh"
+
+msgid "E248: Failed to send command to the destination program"
+msgstr "E248: Gửi câu lệnh vào chương trình khác không thành công"
+
+#, c-format
+msgid "E573: Invalid server id used: %s"
+msgstr "E573: Sử dụng id máy chủ không đúng: %s"
+
+msgid "E251: VIM instance registry property is badly formed. Deleted!"
+msgstr "E251: Thuộc tính đăng ký của Vim được định dạng không đúng. Xóa!"
+
+msgid "Unknown option"
+msgstr "Tùy chá»n không biết"
+
+msgid "Too many edit arguments"
+msgstr "Có quá nhiá»u tham số soạn thảo"
+
+msgid "Argument missing after"
+msgstr "Thiếu tham số sau"
+
+msgid "Garbage after option"
+msgstr "Rác sau tùy chá»n"
+
+msgid "Too many \"+command\", \"-c command\" or \"--cmd command\" arguments"
+msgstr ""
+"Quá nhiá»u tham số \"+câu lệnh\", \"-c câu lệnh\" hoặc \"--cmd câu lệnh\""
+
+msgid "Invalid argument for"
+msgstr "Tham số không được phép cho"
+
+msgid "This Vim was not compiled with the diff feature."
+msgstr "Vim không được biên dịch với tính năng hỗ trợ xem khác biệt (diff)."
+
+msgid "Attempt to open script file again: \""
+msgstr "Thử mở tập tin script một lần nữa: \""
+
+msgid "Cannot open for reading: \""
+msgstr "Không mở để Ä‘á»c được: \""
+
+msgid "Cannot open for script output: \""
+msgstr "Không mở cho đầu ra script được: \""
+
+#, c-format
+msgid "%d files to edit\n"
+msgstr "%d tập tin để soạn thảo\n"
+
+msgid "Vim: Warning: Output is not to a terminal\n"
+msgstr "Vim: Cảnh báo: Äầu ra không hÆ°á»›ng tá»›i má»™t terminal\n"
+
+msgid "Vim: Warning: Input is not from a terminal\n"
+msgstr "Vim: Cảnh báo: Äầu vào không phải đến từ má»™t terminal\n"
+
+#. just in case..
+msgid "pre-vimrc command line"
+msgstr "dòng lệnh chạy trước khi thực hiện vimrc"
+
+#, c-format
+msgid "E282: Cannot read from \"%s\""
+msgstr "E282: Không Ä‘á»c được từ \"%s\""
+
+msgid ""
+"\n"
+"More info with: \"vim -h\"\n"
+msgstr ""
+"\n"
+"Xem thông tin chi tiết với: \"vim -h\"\n"
+
+msgid "[file ..] edit specified file(s)"
+msgstr "[tập tin ..] soạn thảo (các) tập tin chỉ ra"
+
+msgid "- read text from stdin"
+msgstr "- Ä‘á»c văn bản từ đầu vào stdin"
+
+msgid "-t tag edit file where tag is defined"
+msgstr "-t thẻ ghi soạn thảo tập tin từ chỗ thẻ ghi chỉ ra"
+
+msgid "-q [errorfile] edit file with first error"
+msgstr "-q [tập tin lỗi] soạn thảo tập tin với lỗi đầu tiên"
+
+msgid ""
+"\n"
+"\n"
+"Usage:"
+msgstr ""
+"\n"
+"\n"
+"Sử dụng:"
+
+msgid " vim [arguments] "
+msgstr " vim [các tham số] "
+
+msgid ""
+"\n"
+" or:"
+msgstr ""
+"\n"
+" hoặc:"
+
+msgid ""
+"\n"
+"\n"
+"Arguments:\n"
+msgstr ""
+"\n"
+"\n"
+"Tham số:\n"
+
+msgid "--\t\t\tOnly file names after this"
+msgstr "--\t\t\tSau tham số chỉ đưa ra tên tập tin"
+
+msgid "--literal\t\tDon't expand wildcards"
+msgstr "--literal\t\tKhông thực hiện việc mở rộng wildcard"
+
+msgid "-register\t\tRegister this gvim for OLE"
+msgstr "-register\t\tÄăng ký gvim này cho OLE"
+
+msgid "-unregister\t\tUnregister gvim for OLE"
+msgstr "-unregister\t\tBỠđăng ký gvim này cho OLE"
+
+msgid "-g\t\t\tRun using GUI (like \"gvim\")"
+msgstr "-g\t\t\tSá»­ dụng giao diện đồ há»a GUI (giống \"gvim\")"
+
+msgid "-f or --nofork\tForeground: Don't fork when starting GUI"
+msgstr ""
+"-f hoặc --nofork\tTrong chương trình hoạt động: Không thực hiện fork khi "
+"chạy GUI"
+
+msgid "-v\t\t\tVi mode (like \"vi\")"
+msgstr "-v\t\t\tChế độ Vi (giống \"vi\")"
+
+msgid "-e\t\t\tEx mode (like \"ex\")"
+msgstr "-e\t\t\tChế độ Ex (giống \"ex\")"
+
+msgid "-s\t\t\tSilent (batch) mode (only for \"ex\")"
+msgstr "-s\t\t\tChế độ ít đưa thông báo (gói) (chỉ dành cho \"ex\")"
+
+msgid "-d\t\t\tDiff mode (like \"vimdiff\")"
+msgstr "-d\t\t\tChế độ khác biệt, diff (giống \"vimdiff\")"
+
+msgid "-y\t\t\tEasy mode (like \"evim\", modeless)"
+msgstr "-y\t\t\tChế độ đơn giản (giống \"evim\", không có chế độ)"
+
+msgid "-R\t\t\tReadonly mode (like \"view\")"
+msgstr "-R\t\t\tChế Ä‘á»™ chỉ Ä‘á»c (giống \"view\")"
+
+msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
+msgstr "-Z\t\t\tChế độ hạn chế (giống \"rvim\")"
+
+msgid "-m\t\t\tModifications (writing files) not allowed"
+msgstr "-m\t\t\tKhông có khả năng ghi nhớ thay đổi (ghi nhớ tập tin)"
+
+msgid "-M\t\t\tModifications in text not allowed"
+msgstr "-M\t\t\tKhông có khả năng thay đổi văn bản"
+
+msgid "-b\t\t\tBinary mode"
+msgstr "-b\t\t\tChế độ nhị phân (binary)"
+
+msgid "-l\t\t\tLisp mode"
+msgstr "-l\t\t\tChế độ Lisp"
+
+msgid "-C\t\t\tCompatible with Vi: 'compatible'"
+msgstr "-C\t\t\tChế độ tương thích với Vi: 'compatible'"
+
+msgid "-N\t\t\tNot fully Vi compatible: 'nocompatible'"
+msgstr "-N\t\t\tChế độ không tương thích hoàn toàn với Vi: 'nocompatible'"
+
+msgid "-V[N]\t\tVerbose level"
+msgstr "-V[N]\t\tMức độ chi tiết của thông báo"
+
+msgid "-D\t\t\tDebugging mode"
+msgstr "-D\t\t\tChế độ sửa lỗi (debug)"
+
+msgid "-n\t\t\tNo swap file, use memory only"
+msgstr "-n\t\t\tKhông sử dụng tập tin swap, chỉ sử dụng bộ nhớ"
+
+msgid "-r\t\t\tList swap files and exit"
+msgstr "-r\t\t\tLiệt kê các tập tin swap rồi thoát"
+
+msgid "-r (with file name)\tRecover crashed session"
+msgstr "-r (với tên tập tin)\tPhục hồi lần soạn thảo gặp sự cố"
+
+msgid "-L\t\t\tSame as -r"
+msgstr "-L\t\t\tGiống với -r"
+
+msgid "-f\t\t\tDon't use newcli to open window"
+msgstr "-f\t\t\tKhông sử dụng newcli để mở cửa sổ"
+
+msgid "-dev <device>\t\tUse <device> for I/O"
+msgstr "-dev <thiết bị>\t\tSử dụng <thiết bị> cho I/O"
+
+msgid "-A\t\t\tStart in Arabic mode"
+msgstr "-A\t\t\tKhởi động vào chế độ Ả Rập"
+
+msgid "-H\t\t\tStart in Hebrew mode"
+msgstr "-H\t\t\tKhởi động vào chế độ Do thái"
+
+msgid "-F\t\t\tStart in Farsi mode"
+msgstr "-F\t\t\tKhởi động vào chế độ Farsi"
+
+msgid "-T <terminal>\tSet terminal type to <terminal>"
+msgstr "-T <terminal>\tÄặt loại terminal thành <terminal>"
+
+msgid "-u <vimrc>\t\tUse <vimrc> instead of any .vimrc"
+msgstr "-u <vimrc>\t\tSá»­ dụng <vimrc> thay thế cho má»i .vimrc"
+
+msgid "-U <gvimrc>\t\tUse <gvimrc> instead of any .gvimrc"
+msgstr "-U <gvimrc>\t\tSá»­ dụng <gvimrc> thay thế cho má»i .gvimrc"
+
+msgid "--noplugin\t\tDon't load plugin scripts"
+msgstr "--noplugin\t\tKhông nạp bất kỳ script môđun nào"
+
+msgid "-o[N]\t\tOpen N windows (default: one for each file)"
+msgstr "-o[N]\t\tMở N cửa sổ (theo mặc định: mỗi cửa sổ cho một tập tin)"
+
+msgid "-O[N]\t\tLike -o but split vertically"
+msgstr "-O[N]\t\tGiống vá»›i -o nhÆ°ng phân chia theo Ä‘Æ°á»ng thẳng đứng"
+
+msgid "+\t\t\tStart at end of file"
+msgstr "+\t\t\tBắt đầu soạn thảo từ cuối tập tin"
+
+msgid "+<lnum>\t\tStart at line <lnum>"
+msgstr "+<lnum>\t\tBắt đầu soạn thảo từ dòng thứ <lnum> (số thứ tự của dòng)"
+
+msgid "--cmd <command>\tExecute <command> before loading any vimrc file"
+msgstr "--cmd <câu lệnh>\tThực hiện <câu lệnh> trước khi nạp tập tin vimrc"
+
+msgid "-c <command>\t\tExecute <command> after loading the first file"
+msgstr "-c <câu lệnh>\t\tThực hiện <câu lệnh> sau khi nạp tập tin đầu tiên"
+
+msgid "-S <session>\t\tSource file <session> after loading the first file"
+msgstr "-S <session>\t\tThực hiện <session> sau khi nạp tập tin đầu tiên"
+
+msgid "-s <scriptin>\tRead Normal mode commands from file <scriptin>"
+msgstr ""
+"-s <scriptin>\tÄá»c các lệnh của chế Ä‘á»™ Thông thÆ°á»ng từ tập tin <scriptin>"
+
+msgid "-w <scriptout>\tAppend all typed commands to file <scriptout>"
+msgstr "-w <scriptout>\tThêm tất cả các lệnh đã gõ vào tập tin <scriptout>"
+
+msgid "-W <scriptout>\tWrite all typed commands to file <scriptout>"
+msgstr "-W <scriptout>\tGhi nhớ tất cả các lệnh đã gõ vào tập tin <scriptout>"
+
+msgid "-x\t\t\tEdit encrypted files"
+msgstr "-x\t\t\tSoạn thảo tập tin đã mã hóa"
+
+msgid "-display <display>\tConnect vim to this particular X-server"
+msgstr "-display <màn hình>\tKết nối vim tới máy chủ X đã chỉ ra"
+
+msgid "-X\t\t\tDo not connect to X server"
+msgstr "-X\t\t\tKhông thực hiện việc kết nối tới máy chủ X"
+
+msgid "--remote <files>\tEdit <files> in a Vim server if possible"
+msgstr "--remote <tập tin>\tSoạn thảo <tập tin> trên máy chủ Vim nếu có thể"
+
+msgid "--remote-silent <files> Same, don't complain if there is no server"
+msgstr ""
+"--remote-silent <tập tin> Cũng vậy, nhưng không kêu ca dù không có máy chủ"
+
+msgid ""
+"--remote-wait <files> As --remote but wait for files to have been edited"
+msgstr "--remote-wait <tập tin> Cũng như --remote, nhưng chỠsự kết thúc"
+
+msgid ""
+"--remote-wait-silent <files> Same, don't complain if there is no server"
+msgstr ""
+"--remote-wait-silent <tập tin> Cũng vậy, nhưng không kêu ca dù không có máy "
+"chủ"
+
+msgid "--remote-send <keys>\tSend <keys> to a Vim server and exit"
+msgstr "--remote-send <phím>\tGửi <phím> lên máy chủ Vim và thoát"
+
+msgid "--remote-expr <expr>\tEvaluate <expr> in a Vim server and print result"
+msgstr ""
+"--remote-expr <biểu thức>\tTính <biểu thức> trên máy chủ Vim và in ra kết quả"
+
+msgid "--serverlist\t\tList available Vim server names and exit"
+msgstr "--serverlist\t\tHiển thị danh sách máy chủ Vim và thoát"
+
+msgid "--servername <name>\tSend to/become the Vim server <name>"
+msgstr "--servername <tên>\tGửi lên (hoặc trở thành) máy chủ Vim với <tên>"
+
+msgid "-i <viminfo>\t\tUse <viminfo> instead of .viminfo"
+msgstr "-i <viminfo>\t\tSử dụng tập tin <viminfo> thay cho .viminfo"
+
+msgid "-h or --help\tPrint Help (this message) and exit"
+msgstr "-h hoặc --help\tHiển thị Trợ giúp (thông tin này) và thoát"
+
+msgid "--version\t\tPrint version information and exit"
+msgstr "--version\t\tÄÆ°a ra thông tin vá» phiên bản Vim và thoát"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Motif version):\n"
+msgstr ""
+"\n"
+"Tham số cho gvim (phiên bản Motif):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (neXtaw version):\n"
+msgstr ""
+"\n"
+"Tham số cho gvim (phiên bản neXtaw):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Athena version):\n"
+msgstr ""
+"\n"
+"Tham số cho gvim (phiên bản Athena):\n"
+
+msgid "-display <display>\tRun vim on <display>"
+msgstr "-display <màn hình>\tChạy vim trong <màn hình> đã chỉ ra"
+
+msgid "-iconic\t\tStart vim iconified"
+msgstr "-iconic\t\tChạy vim ở dạng thu nhá»"
+
+msgid "-name <name>\t\tUse resource as if vim was <name>"
+msgstr "-name <tên>\t\tSử dụng tài nguyên giống như khi vim có <tên>"
+
+msgid "\t\t\t (Unimplemented)\n"
+msgstr "\t\t\t (Chưa được thực thi)\n"
+
+msgid "-background <color>\tUse <color> for the background (also: -bg)"
+msgstr "-background <màu>\tSá»­ dụng <màu> chỉ ra cho ná»n (cÅ©ng nhÆ°: -bg)"
+
+msgid "-foreground <color>\tUse <color> for normal text (also: -fg)"
+msgstr ""
+"-foreground <màu>\tSá»­ dụng <màu> cho văn bản thông thÆ°á»ng (cÅ©ng nhÆ°: -fg)"
+
+msgid "-font <font>\t\tUse <font> for normal text (also: -fn)"
+msgstr ""
+"-font <phông>\t\tSá»­ dụng <phông> chữ cho văn bản thông thÆ°á»ng (cÅ©ng nhÆ°: -fn)"
+
+msgid "-boldfont <font>\tUse <font> for bold text"
+msgstr "-boldfont <phông>\tSử dụng <phông> chữ cho văn bản in đậm"
+
+msgid "-italicfont <font>\tUse <font> for italic text"
+msgstr "-italicfont <phông>\tSử dụng <phông> chữ cho văn bản in nghiêng"
+
+msgid "-geometry <geom>\tUse <geom> for initial geometry (also: -geom)"
+msgstr "-geometry <kích thước>\tSử dụng <kích thước> ban đầu (cũng như: -geom)"
+
+msgid "-borderwidth <width>\tUse a border width of <width> (also: -bw)"
+msgstr ""
+"-borderwidth <rá»™ng>\tSá»­ dụng Ä‘Æ°á»ng viá»n có chiá»u <rá»™ng> (cÅ©ng nhÆ°: -bw)"
+
+msgid "-scrollbarwidth <width> Use a scrollbar width of <width> (also: -sw)"
+msgstr ""
+"-scrollbarwidth <rá»™ng> Sá»­ dụng thanh cuá»™n vá»›i chiá»u <rá»™ng> (cÅ©ng nhÆ°: -sw)"
+
+msgid "-menuheight <height>\tUse a menu bar height of <height> (also: -mh)"
+msgstr ""
+"-menuheight <cao>\tSá»­ dụng thanh trình Ä‘Æ¡n vá»›i chiá»u <cao> (cÅ©ng nhÆ°: -mh)"
+
+msgid "-reverse\t\tUse reverse video (also: -rv)"
+msgstr "-reverse\t\tSử dụng chế độ video đảo ngược (cũng như: -rv)"
+
+msgid "+reverse\t\tDon't use reverse video (also: +rv)"
+msgstr "+reverse\t\tKhông sử dụng chế độ video đảo ngược (cũng như: +rv)"
+
+msgid "-xrm <resource>\tSet the specified resource"
+msgstr "-xrm <tài nguyên>\tÄặt <tài nguyên> chỉ ra"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (RISC OS version):\n"
+msgstr ""
+"\n"
+"Tham số cho gvim (phiên bản RISC OS):\n"
+
+msgid "--columns <number>\tInitial width of window in columns"
+msgstr "--columns <số>\tChiá»u rá»™ng ban đầu của cá»­a sổ tính theo số cá»™t"
+
+msgid "--rows <number>\tInitial height of window in rows"
+msgstr "--rows <số>\tChiá»u cao ban đầu của cá»­a sổ tính theo số dòng"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (GTK+ version):\n"
+msgstr ""
+"\n"
+"Tham số cho gvim (phiên bản GTK+):\n"
+
+msgid "-display <display>\tRun vim on <display> (also: --display)"
+msgstr ""
+"-display <màn hình>\tChạy vim trên <màn hình> chỉ ra (cũng như: --display)"
+
+msgid "--role <role>\tSet a unique role to identify the main window"
+msgstr "--role <vai trò>\tÄặt <vai trò> duy nhất để nhận diện cá»­a sổ chính"
+
+msgid "--socketid <xid>\tOpen Vim inside another GTK widget"
+msgstr "--socketid <xid>\tMở Vim bên trong thành phần GTK khác"
+
+msgid "-P <parent title>\tOpen Vim inside parent application"
+msgstr "-P <tiêu đỠcủa mẹ>\tMở Vim bên trong ứng dụng mẹ"
+
+msgid "No display"
+msgstr "Không có màn hình"
+
+#. Failed to send, abort.
+msgid ": Send failed.\n"
+msgstr ": Gửi không thành công.\n"
+
+#. Let vim start normally.
+msgid ": Send failed. Trying to execute locally\n"
+msgstr ": Gửi không thành công. Thử thực hiện nội bộ\n"
+
+#, c-format
+msgid "%d of %d edited"
+msgstr "đã soạn thảo %d từ %d"
+
+msgid "No display: Send expression failed.\n"
+msgstr "Không có màn hình: gửi biểu thức không thành công.\n"
+
+msgid ": Send expression failed.\n"
+msgstr ": Gửi biểu thức không thành công.\n"
+
+msgid "No marks set"
+msgstr "Không có dấu hiệu nào được đặt."
+
+#, c-format
+msgid "E283: No marks matching \"%s\""
+msgstr "E283: Không có dấu hiệu tương ứng với \"%s\""
+
+#. Highlight title
+msgid ""
+"\n"
+"mark line col file/text"
+msgstr ""
+"\n"
+"nhãn dòng cột tập tin/văn bản"
+
+#. Highlight title
+msgid ""
+"\n"
+" jump line col file/text"
+msgstr ""
+"\n"
+" bước_nhảy dòng cột tập tin/văn bản"
+
+#. Highlight title
+msgid ""
+"\n"
+"change line col text"
+msgstr ""
+"\n"
+"thay_đổi dòng cột văn_bản"
+
+msgid ""
+"\n"
+"# File marks:\n"
+msgstr ""
+"\n"
+"# Nhãn của tập tin:\n"
+
+#. Write the jumplist with -'
+msgid ""
+"\n"
+"# Jumplist (newest first):\n"
+msgstr ""
+"\n"
+"# Danh sách bước nhảy (mới hơn đứng trước):\n"
+
+msgid ""
+"\n"
+"# History of marks within files (newest to oldest):\n"
+msgstr ""
+"\n"
+"# Lịch sử các nhãn trong tập tin (từ mới nhất đến cũ nhất):\n"
+
+msgid "Missing '>'"
+msgstr "Thiếu '>'"
+
+msgid "E543: Not a valid codepage"
+msgstr "E543: Bảng mã không cho phép"
+
+msgid "E284: Cannot set IC values"
+msgstr "E284: Không đặt được giá trị nội dung nhập vào (IC)"
+
+msgid "E285: Failed to create input context"
+msgstr "E285: Không tạo được nội dung nhập vào"
+
+msgid "E286: Failed to open input method"
+msgstr "E286: Việc thử mở phương pháp nhập không thành công"
+
+msgid "E287: Warning: Could not set destroy callback to IM"
+msgstr ""
+"E287: Cảnh báo: không đặt được sá»± gá»i ngược hủy diệt thành phÆ°Æ¡ng pháp nhập"
+
+msgid "E288: input method doesn't support any style"
+msgstr "E288: phương pháp nhập không hỗ trợ bất kỳ phong cách (style) nào"
+
+msgid "E289: input method doesn't support my preedit type"
+msgstr "E289: phương pháp nhập không hỗ trợ loại soạn thảo trước của Vim"
+
+msgid "E290: over-the-spot style requires fontset"
+msgstr "E290: phong cách over-the-spot yêu cầu một bộ phông chữ"
+
+msgid "E291: Your GTK+ is older than 1.2.3. Status area disabled"
+msgstr "E291: GTK+ cũ hơn 1.2.3. Vùng chỉ trạng thái không làm việc"
+
+msgid "E292: Input Method Server is not running"
+msgstr "E292: Máy chủ phương pháp nhập liệu chưa được chạy"
+
+msgid "E293: block was not locked"
+msgstr "E293: khối chưa bị khóa"
+
+msgid "E294: Seek error in swap file read"
+msgstr "E294: Lá»—i tìm kiếm khi Ä‘á»c tập tin trao đổi (swap)"
+
+msgid "E295: Read error in swap file"
+msgstr "E295: Lá»—i Ä‘á»c tập tin trao đổi (swap)"
+
+msgid "E296: Seek error in swap file write"
+msgstr "E296: Lỗi tìm kiếm khi ghi nhớ tập tin trao đổi (swap)"
+
+msgid "E297: Write error in swap file"
+msgstr "E297: Lỗi ghi nhớ tập tin trao đổi (swap)"
+
+msgid "E300: Swap file already exists (symlink attack?)"
+msgstr ""
+"E300: Tập tin trao đổi (swap) đã tồn tại (sá»­ dụng liên kết má»m tấn công?)"
+
+msgid "E298: Didn't get block nr 0?"
+msgstr "E298: Chưa lấy khối số 0?"
+
+msgid "E298: Didn't get block nr 1?"
+msgstr "E298: Chưa lấy khối số 12?"
+
+msgid "E298: Didn't get block nr 2?"
+msgstr "E298: Chưa lấy khối số 2?"
+
+#. could not (re)open the swap file, what can we do????
+msgid "E301: Oops, lost the swap file!!!"
+msgstr "E301: á»i, mất tập tin trao đổi (swap)!!!"
+
+msgid "E302: Could not rename swap file"
+msgstr "E302: Không đổi được tên tập tin trao đổi (swap)"
+
+#, c-format
+msgid "E303: Unable to open swap file for \"%s\", recovery impossible"
+msgstr ""
+"E303: Không mở được tập tin trao đổi (swap) cho \"%s\", nên không thể phục "
+"hồi"
+
+msgid "E304: ml_timestamp: Didn't get block 0??"
+msgstr "E304: ml_timestamp: Chưa lấy khối số 0??"
+
+#, c-format
+msgid "E305: No swap file found for %s"
+msgstr "E305: Không tìm thấy tập tin trao đổi (swap) cho %s"
+
+msgid "Enter number of swap file to use (0 to quit): "
+msgstr "Hãy nhập số của tập tin trao đổi (swap) muốn sử dụng (0 để thoát): "
+
+#, c-format
+msgid "E306: Cannot open %s"
+msgstr "E306: Không mở được %s"
+
+msgid "Unable to read block 0 from "
+msgstr "Không thể Ä‘á»c khối số 0 từ "
+
+msgid ""
+"\n"
+"Maybe no changes were made or Vim did not update the swap file."
+msgstr ""
+"\n"
+"Chưa có thay đổi nào hoặc Vim không thể cập nhật tập tin trao đổi (swap)"
+
+msgid " cannot be used with this version of Vim.\n"
+msgstr " không thể sử dụng trong phiên bản Vim này.\n"
+
+msgid "Use Vim version 3.0.\n"
+msgstr "Hãy sử dụng Vim phiên bản 3.0.\n"
+
+#, c-format
+msgid "E307: %s does not look like a Vim swap file"
+msgstr "E307: %s không phải là tập tin trao đổi (swap) của Vim"
+
+msgid " cannot be used on this computer.\n"
+msgstr " không thể sử dụng trên máy tính này.\n"
+
+msgid "The file was created on "
+msgstr "Tập tin đã được tạo trên "
+
+msgid ""
+",\n"
+"or the file has been damaged."
+msgstr ""
+",\n"
+"hoặc tập tin đã bị há»ng."
+
+#, c-format
+msgid "Using swap file \"%s\""
+msgstr "Äang sá»­ dụng tập tin trao đổi (swap) \"%s\""
+
+#, c-format
+msgid "Original file \"%s\""
+msgstr "Tập tin gốc \"%s\""
+
+msgid "E308: Warning: Original file may have been changed"
+msgstr "E308: Cảnh báo: Tập tin gốc có thể đã bị thay đổi"
+
+#, c-format
+msgid "E309: Unable to read block 1 from %s"
+msgstr "E309: Không Ä‘á»c được khối số 1 từ %s"
+
+msgid "???MANY LINES MISSING"
+msgstr "???THIẾU NHIỀU DÒNG"
+
+msgid "???LINE COUNT WRONG"
+msgstr "???GIà TRỊ CỦA Sá» ÄẾM DÃ’NG BỊ SAI"
+
+msgid "???EMPTY BLOCK"
+msgstr "???KHá»I Rá»–NG"
+
+msgid "???LINES MISSING"
+msgstr "???THIẾU DÒNG"
+
+#, c-format
+msgid "E310: Block 1 ID wrong (%s not a .swp file?)"
+msgstr "E310: Khối 1 ID sai (%s không phải là tập tin .swp?)"
+
+msgid "???BLOCK MISSING"
+msgstr "???THIẾU KHá»I"
+
+msgid "??? from here until ???END lines may be messed up"
+msgstr "??? từ đây tá»›i ???CUá»I, các dòng có thể đã bị há»ng"
+
+msgid "??? from here until ???END lines may have been inserted/deleted"
+msgstr "??? từ đây tá»›i ???CUá»I, các dòng có thể đã bị chèn hoặc xóa"
+
+msgid "???END"
+msgstr "???CUá»I"
+
+msgid "E311: Recovery Interrupted"
+msgstr "E311: Việc phục hồi bị gián đoạn"
+
+msgid ""
+"E312: Errors detected while recovering; look for lines starting with ???"
+msgstr ""
+"E312: Phát hiện ra lỗi trong khi phục hồi; hãy xem những dòng bắt đầu với ???"
+
+msgid "See \":help E312\" for more information."
+msgstr "Hãy xem thông tin bổ sung trong trợ giúp \":help E312\""
+
+msgid "Recovery completed. You should check if everything is OK."
+msgstr "Việc phục hồi đã hoàn thành. Nên kiểm tra xem má»i thứ có ổn không."
+
+msgid ""
+"\n"
+"(You might want to write out this file under another name\n"
+msgstr ""
+"\n"
+"(Có thể ghi nhớ tập tin với tên khác và so sánh với tập\n"
+
+msgid "and run diff with the original file to check for changes)\n"
+msgstr "gốc bằng chương trình diff).\n"
+
+msgid ""
+"Delete the .swp file afterwards.\n"
+"\n"
+msgstr ""
+"Sau đó hãy xóa tập tin .swp.\n"
+"\n"
+
+#. use msg() to start the scrolling properly
+msgid "Swap files found:"
+msgstr "Tìm thấy tập tin trao đổi (swap):"
+
+msgid " In current directory:\n"
+msgstr " Trong thÆ° mục hiện thá»i:\n"
+
+msgid " Using specified name:\n"
+msgstr " Với tên chỉ ra:\n"
+
+msgid " In directory "
+msgstr " Trong thư mục "
+
+msgid " -- none --\n"
+msgstr " -- không --\n"
+
+msgid " owned by: "
+msgstr " ngÆ°á»i sở hữu: "
+
+msgid " dated: "
+msgstr " ngày: "
+
+msgid " dated: "
+msgstr " ngày: "
+
+msgid " [from Vim version 3.0]"
+msgstr " [từ Vim phiên bản 3.0]"
+
+msgid " [does not look like a Vim swap file]"
+msgstr " [không phải là tập tin trao đổi (swap) của Vim]"
+
+msgid " file name: "
+msgstr " tên tập tin: "
+
+msgid ""
+"\n"
+" modified: "
+msgstr ""
+"\n"
+" thay đổi: "
+
+msgid "YES"
+msgstr "CÓ"
+
+msgid "no"
+msgstr "không"
+
+msgid ""
+"\n"
+" user name: "
+msgstr ""
+"\n"
+" tên ngÆ°á»i dùng: "
+
+msgid " host name: "
+msgstr " tên máy: "
+
+msgid ""
+"\n"
+" host name: "
+msgstr ""
+"\n"
+" tên máy: "
+
+msgid ""
+"\n"
+" process ID: "
+msgstr ""
+"\n"
+" ID tiến trình: "
+
+msgid " (still running)"
+msgstr " (vẫn đang chạy)"
+
+msgid ""
+"\n"
+" [not usable with this version of Vim]"
+msgstr ""
+"\n"
+" [không sử dụng được với phiên bản này của Vim]"
+
+msgid ""
+"\n"
+" [not usable on this computer]"
+msgstr ""
+"\n"
+" [không sử dụng được trên máy tính này]"
+
+msgid " [cannot be read]"
+msgstr " [không Ä‘á»c được]"
+
+msgid " [cannot be opened]"
+msgstr " [không mở được]"
+
+msgid "E313: Cannot preserve, there is no swap file"
+msgstr "E313: Không cập nhật được tập tin trao đổi (swap) vì không tìm thấy nó"
+
+msgid "File preserved"
+msgstr "Äã cập nhật tập tin trao đổi (swap)"
+
+msgid "E314: Preserve failed"
+msgstr "E314: Cập nhật không thành công"
+
+#, c-format
+msgid "E315: ml_get: invalid lnum: %ld"
+msgstr "E315: ml_get: giá trị lnum không đúng: %ld"
+
+#, c-format
+msgid "E316: ml_get: cannot find line %ld"
+msgstr "E316: ml_get: không tìm được dòng %ld"
+
+msgid "E317: pointer block id wrong 3"
+msgstr "E317: Giá trị của pointer khối số 3 không đúng"
+
+msgid "stack_idx should be 0"
+msgstr "giá trị stack_idx phải bằng 0"
+
+msgid "E318: Updated too many blocks?"
+msgstr "E318: Äã cập nhật quá nhiá»u khối?"
+
+msgid "E317: pointer block id wrong 4"
+msgstr "E317: Giá trị của pointer khối số 4 không đúng"
+
+msgid "deleted block 1?"
+msgstr "đã xóa khối số 1?"
+
+#, c-format
+msgid "E320: Cannot find line %ld"
+msgstr "E320: Không tìm được dòng %ld"
+
+msgid "E317: pointer block id wrong"
+msgstr "E317: giá trị của pointer khối không đúng"
+
+msgid "pe_line_count is zero"
+msgstr "giá trị pe_line_count bằng không"
+
+#, c-format
+msgid "E322: line number out of range: %ld past the end"
+msgstr "E322: số thứ tự dòng vượt quá giới hạn : %ld"
+
+#, c-format
+msgid "E323: line count wrong in block %ld"
+msgstr "E323: giá trị đếm dòng không đúng trong khối %ld"
+
+msgid "Stack size increases"
+msgstr "Kích thước của đống tăng lên"
+
+msgid "E317: pointer block id wrong 2"
+msgstr "E317: Giá trị của cái chỉ (pointer) khối số 2 không đúng"
+
+msgid "E325: ATTENTION"
+msgstr "E325: CHÚ Ã"
+
+msgid ""
+"\n"
+"Found a swap file by the name \""
+msgstr ""
+"\n"
+"Tìm thấy một tập tin trao đổi (swap) với tên \""
+
+msgid "While opening file \""
+msgstr "Khi mở tập tin: \""
+
+msgid " NEWER than swap file!\n"
+msgstr " MỚI hơn so với tập tin trao đổi (swap)\n"
+
+#. Some of these messages are long to allow translation to
+#. * other languages.
+msgid ""
+"\n"
+"(1) Another program may be editing the same file.\n"
+" If this is the case, be careful not to end up with two\n"
+" different instances of the same file when making changes.\n"
+msgstr ""
+"\n"
+"(1) Rất có thể một chương trình khác đang soạn thảo tập tin.\n"
+" Nếu như vậy, hãy cẩn thận khi thay đổi, làm sao để không thu\n"
+" được hai phương án khác nhau của cùng một tập tin.\n"
+
+msgid " Quit, or continue with caution.\n"
+msgstr " Thoát hoặc tiếp tục với sự cẩn thận.\n"
+
+msgid ""
+"\n"
+"(2) An edit session for this file crashed.\n"
+msgstr ""
+"\n"
+"(2) Lần soạn thảo trước của tập tin này gặp sự cố.\n"
+
+msgid " If this is the case, use \":recover\" or \"vim -r "
+msgstr ""
+" Trong trÆ°á»ng hợp này, hãy sá»­ dụng câu lệnh \":recover\" hoặc \"vim -r "
+
+msgid ""
+"\"\n"
+" to recover the changes (see \":help recovery\").\n"
+msgstr ""
+"\"\n"
+" để phục hồi những thay đổi (hãy xem \":help recovery\").\n"
+
+msgid " If you did this already, delete the swap file \""
+msgstr ""
+" Nếu đã thực hiện thao tác này rồi, thì hãy xóa tập tin trao đổi (swap) \""
+
+msgid ""
+"\"\n"
+" to avoid this message.\n"
+msgstr ""
+"\"\n"
+" để tránh sự xuất hiện của thông báo này trong tương lai.\n"
+
+msgid "Swap file \""
+msgstr "Tập tin trao đổi (swap) \""
+
+msgid "\" already exists!"
+msgstr "\" đã có rồi!"
+
+msgid "VIM - ATTENTION"
+msgstr "VIM - CHÚ Ã"
+
+msgid "Swap file already exists!"
+msgstr "Tập tin trao đổi (swap) đã rồi!"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"&O Mở chỉ để Ä‘á»c\n"
+"&E Vẫn soạn thảo\n"
+"&R Phục hồi\n"
+"&Q Thoát\n"
+"&A Gián đoạn"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Quit\n"
+"&Abort\n"
+"&Delete it"
+msgstr ""
+"&O Mở chỉ để Ä‘á»c\n"
+"&E Vẫn soạn thảo\n"
+"&R Phục hồi\n"
+"&Q Thoát\n"
+"&A Gián đoạn&D Xóa nó"
+
+msgid "E326: Too many swap files found"
+msgstr "E326: Tìm thấy quá nhiá»u tập tin trao đổi (swap)"
+
+msgid "E327: Part of menu-item path is not sub-menu"
+msgstr ""
+"E327: Má»™t phần của Ä‘Æ°á»ng dẫn tá»›i phần tá»­ của trình Ä‘Æ¡n không phải là trình "
+"Ä‘Æ¡n con"
+
+msgid "E328: Menu only exists in another mode"
+msgstr "E328: Trình đơn chỉ có trong chế độ khác"
+
+msgid "E329: No menu of that name"
+msgstr "E329: Không có trình đơn với tên như vậy"
+
+msgid "E330: Menu path must not lead to a sub-menu"
+msgstr "E330: ÄÆ°á»ng dẫn tá»›i trình Ä‘Æ¡n không được Ä‘Æ°a tá»›i trình Ä‘Æ¡n con"
+
+msgid "E331: Must not add menu items directly to menu bar"
+msgstr ""
+"E331: Các phần tử của trình đơn không thể thêm trực tiếp vào thanh trình đơn"
+
+msgid "E332: Separator cannot be part of a menu path"
+msgstr "E332: Cái phân chia không thể là má»™t phần của Ä‘Æ°á»ng dẫn tá»›i trình Ä‘Æ¡n"
+
+#. Now we have found the matching menu, and we list the mappings
+#. Highlight title
+msgid ""
+"\n"
+"--- Menus ---"
+msgstr ""
+"\n"
+"--- Trình đơn ---"
+
+msgid "Tear off this menu"
+msgstr "Chia cắt trình đơn này"
+
+msgid "E333: Menu path must lead to a menu item"
+msgstr "E333: ÄÆ°á»ng dẫn tá»›i trình Ä‘Æ¡n phải Ä‘Æ°a tá»›i má»™t phần tá»­ cuả trình Ä‘Æ¡n"
+
+#, c-format
+msgid "E334: Menu not found: %s"
+msgstr "E334: Không tìm thấy trình đơn: %s"
+
+#, c-format
+msgid "E335: Menu not defined for %s mode"
+msgstr "E335: Trình đơn không được định nghĩa cho chế độ %s"
+
+msgid "E336: Menu path must lead to a sub-menu"
+msgstr "E336: ÄÆ°á»ng dẫn tá»›i trình Ä‘Æ¡n phải Ä‘Æ°a tá»›i má»™t trình Ä‘Æ¡n con"
+
+msgid "E337: Menu not found - check menu names"
+msgstr "E337: Không tìm thấy trình đơn - hãy kiểm tra tên trình đơn"
+
+#, c-format
+msgid "Error detected while processing %s:"
+msgstr "Phát hiện lỗi khi xử lý %s:"
+
+#, c-format
+msgid "line %4ld:"
+msgstr "dòng %4ld:"
+
+msgid "[string too long]"
+msgstr "[chuỗi quá dài]"
+
+msgid "Messages maintainer: Bram Moolenaar <Bram@vim.org>"
+msgstr ""
+"Bản dịch các thông báo sang tiếng Việt: Phan Vĩnh Thịnh <teppi@vnlinux.org>"
+
+msgid "Interrupt: "
+msgstr "Gián đoạn: "
+
+msgid "Hit ENTER to continue"
+msgstr "Nhấn phím ENTER để tiếp tục"
+
+msgid "Hit ENTER or type command to continue"
+msgstr "Nhấn phím ENTER hoặc nhập câu lệnh để tiếp tục"
+
+msgid "-- More --"
+msgstr "-- Còn nữa --"
+
+msgid " (RET/BS: line, SPACE/b: page, d/u: half page, q: quit)"
+msgstr " (RET/BS: dòng, SPACE/b: trang, d/u: nửa trang, q: thoát)"
+
+msgid " (RET: line, SPACE: page, d: half page, q: quit)"
+msgstr " (RET: dòng, SPACE: trang, d: nửa trang, q: thoát)"
+
+msgid "Question"
+msgstr "Câu há»i"
+
+msgid ""
+"&Yes\n"
+"&No"
+msgstr ""
+"&Có\n"
+"&Không"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"Save &All\n"
+"&Discard All\n"
+"&Cancel"
+msgstr ""
+"&Có\n"
+"&Không&Ghi nhớ tất cả\n"
+"&Vứt bỠtất cả\n"
+"&Dừng lại"
+
+msgid "Save File dialog"
+msgstr "Ghi nhớ tập tin"
+
+msgid "Open File dialog"
+msgstr "Mở tập tin"
+
+#. TODO: non-GUI file selector here
+msgid "E338: Sorry, no file browser in console mode"
+msgstr ""
+"E338: Xin lỗi nhưng không có trình duyệt tập tin trong chế độ kênh giao tác "
+"(console)"
+
+msgid "W10: Warning: Changing a readonly file"
+msgstr "W10: Cảnh báo: Thay đổi má»™t tập tin chỉ có quyá»n Ä‘á»c"
+
+msgid "1 more line"
+msgstr "Thêm 1 dòng"
+
+msgid "1 line less"
+msgstr "Bớt 1 dòng"
+
+#, c-format
+msgid "%ld more lines"
+msgstr "Thêm %ld dòng"
+
+#, c-format
+msgid "%ld fewer lines"
+msgstr "Bớt %ld dòng"
+
+msgid " (Interrupted)"
+msgstr " (Bị gián đoạn)"
+
+msgid "Vim: preserving files...\n"
+msgstr "Vim: ghi nhớ các tập tin...\n"
+
+#. close all memfiles, without deleting
+msgid "Vim: Finished.\n"
+msgstr "Vim: Äã xong.\n"
+
+msgid "ERROR: "
+msgstr "Lá»–I: "
+
+#, c-format
+msgid ""
+"\n"
+"[bytes] total alloc-freed %lu-%lu, in use %lu, peak use %lu\n"
+msgstr ""
+"\n"
+"[byte] tổng phân phối-còn trống %lu-%lu, sử dụng %lu, píc sử dụng %lu\n"
+
+#, c-format
+msgid ""
+"[calls] total re/malloc()'s %lu, total free()'s %lu\n"
+"\n"
+msgstr ""
+"[gá»i] tổng re/malloc() %lu, tổng free() %lu\n"
+"\n"
+
+msgid "E340: Line is becoming too long"
+msgstr "E340: Dòng đang trở thành quá dài"
+
+#, c-format
+msgid "E341: Internal error: lalloc(%ld, )"
+msgstr "E341: Lá»—i ná»™i bá»™: lalloc(%ld, )"
+
+#, c-format
+msgid "E342: Out of memory! (allocating %lu bytes)"
+msgstr "E342: Không đủ bộ nhớ! (phân chia %lu byte)"
+
+#, c-format
+msgid "Calling shell to execute: \"%s\""
+msgstr "Gá»i shell để thá»±c hiện: \"%s\""
+
+msgid "E545: Missing colon"
+msgstr "E545: Thiếu dấu hai chấm"
+
+msgid "E546: Illegal mode"
+msgstr "E546: Chế độ không cho phép"
+
+msgid "E547: Illegal mouseshape"
+msgstr "E547: Dạng trỠchuột không cho phép"
+
+msgid "E548: digit expected"
+msgstr "E548: yêu cầu một số"
+
+msgid "E549: Illegal percentage"
+msgstr "E549: Tỷ lệ phần trăm không cho phép"
+
+msgid "Enter encryption key: "
+msgstr "Nhập mật khẩu để mã hóa: "
+
+msgid "Enter same key again: "
+msgstr " Nhập lại mật khẩu:"
+
+msgid "Keys don't match!"
+msgstr "Hai mật khẩu không trùng nhau!"
+
+#, c-format
+msgid ""
+"E343: Invalid path: '**[number]' must be at the end of the path or be "
+"followed by '%s'."
+msgstr ""
+"E343: ÄÆ°á»ng dẫn Ä‘Æ°a ra không đúng: '**[số]' phải ở cuối Ä‘Æ°á»ng dẫn hoặc theo "
+"sau bởi '%s'"
+
+#, c-format
+msgid "E344: Can't find directory \"%s\" in cdpath"
+msgstr "E344: Không tìm thấy thư mục \"%s\" để chuyển thư mục"
+
+#, c-format
+msgid "E345: Can't find file \"%s\" in path"
+msgstr "E345: Không tìm thấy tập tin \"%s\" trong Ä‘Æ°á»ng dẫn"
+
+#, c-format
+msgid "E346: No more directory \"%s\" found in cdpath"
+msgstr "E346: Trong Ä‘Æ°á»ng dẫn thay đổi thÆ° mục không còn có thÆ° mục \"%s\" nữa"
+
+#, c-format
+msgid "E347: No more file \"%s\" found in path"
+msgstr "E347: Trong Ä‘Æ°á»ng dẫn path không còn có tập tin \"%s\" nữa"
+
+msgid "E550: Missing colon"
+msgstr "E550: Thiếu dấu hai chấm"
+
+msgid "E551: Illegal component"
+msgstr "E551: Thành phần không cho phép"
+
+msgid "E552: digit expected"
+msgstr "E552: Cần chỉ ra một số"
+
+#. Get here when the server can't be found.
+msgid "Cannot connect to Netbeans #2"
+msgstr "Không kết nối được với Netbeans #2"
+
+msgid "Cannot connect to Netbeans"
+msgstr "Không kết nối được với NetBeans"
+
+#, c-format
+msgid "E668: Wrong access mode for NetBeans connection info file: \"%s\""
+msgstr ""
+"E668: Chế độ truy cập thông tin vỠliên kết với NetBeans không đúng: \"%s\""
+
+msgid "read from Netbeans socket"
+msgstr "Ä‘á»c từ socket NetBeans"
+
+#, c-format
+msgid "E658: NetBeans connection lost for buffer %ld"
+msgstr "E658: Bị mất liên kết với NetBeans cho bộ đệm %ld"
+
+msgid "Warning: terminal cannot highlight"
+msgstr "Cảnh báo: terminal không thực hiện được sự chiếu sáng"
+
+msgid "E348: No string under cursor"
+msgstr "E348: Không có chuá»—i ở vị trí con trá»"
+
+msgid "E349: No identifier under cursor"
+msgstr "E349: Không có tên ở vị trí con trá»"
+
+msgid "E352: Cannot erase folds with current 'foldmethod'"
+msgstr ""
+"E352: Không thể tẩy xóa nếp gấp vá»›i giá trị hiện thá»i của tùy chá»n "
+"'foldmethod'"
+
+msgid "E664: changelist is empty"
+msgstr "E664: danh sách những thay đổi trống rỗng"
+
+msgid "E662: At start of changelist"
+msgstr "E662: Ở đầu danh sách những thay đổi"
+
+msgid "E663: At end of changelist"
+msgstr "E663: Ở cuối danh sách những thay đổi"
+
+msgid "Type :quit<Enter> to exit Vim"
+msgstr "Gõ :quit<Enter> để thoát khá»i Vim"
+
+#, c-format
+msgid "1 line %sed 1 time"
+msgstr "Trên 1 dòng %s 1 lần"
+
+#, c-format
+msgid "1 line %sed %d times"
+msgstr "Trên 1 dòng %s %d lần"
+
+#, c-format
+msgid "%ld lines %sed 1 time"
+msgstr "Trên %ld dòng %s 1 lần"
+
+#, c-format
+msgid "%ld lines %sed %d times"
+msgstr "Trên %ld dòng %s %d lần"
+
+#, c-format
+msgid "%ld lines to indent... "
+msgstr "Thụt đầu %ld dòng..."
+
+msgid "1 line indented "
+msgstr "Äã thụt đầu 1 dòng"
+
+#, c-format
+msgid "%ld lines indented "
+msgstr "%ld dòng đã thụt đầu"
+
+#. must display the prompt
+msgid "cannot yank; delete anyway"
+msgstr "sao chép không thành công; đã xóa"
+
+msgid "1 line changed"
+msgstr "1 dòng đã thay đổi"
+
+#, c-format
+msgid "%ld lines changed"
+msgstr "%ld đã thay đổi"
+
+#, c-format
+msgid "freeing %ld lines"
+msgstr "đã làm sạch %ld dòng"
+
+msgid "1 line yanked"
+msgstr "đã sao chép 1 dòng"
+
+#, c-format
+msgid "%ld lines yanked"
+msgstr "đã sao chép %ld dòng"
+
+#, c-format
+msgid "E353: Nothing in register %s"
+msgstr "E353: Trong sổ đăng ký %s không có gì hết"
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Registers ---"
+msgstr ""
+"\n"
+"--- Sổ đăng ký ---"
+
+msgid "Illegal register name"
+msgstr "Tên sổ đăng ký không cho phép"
+
+msgid ""
+"\n"
+"# Registers:\n"
+msgstr ""
+"\n"
+"# Sổ đăng ký:\n"
+
+#, c-format
+msgid "E574: Unknown register type %d"
+msgstr "E574: Loại sổ đăng ký không biết %d"
+
+#, c-format
+msgid "E354: Invalid register name: '%s'"
+msgstr "E354: Tên sổ đăng ký không cho phép: '%s'"
+
+#, c-format
+msgid "%ld Cols; "
+msgstr "%ld Cá»™t; "
+
+#, c-format
+msgid "Selected %s%ld of %ld Lines; %ld of %ld Words; %ld of %ld Bytes"
+msgstr "Chá»n %s%ld của %ld Dòng; %ld của %ld Từ; %ld của %ld Byte"
+
+#, c-format
+msgid "Col %s of %s; Line %ld of %ld; Word %ld of %ld; Byte %ld of %ld"
+msgstr "Cột %s của %s; Dòng %ld của %ld; Từ %ld của %ld; Byte %ld của %ld"
+
+#, c-format
+msgid "(+%ld for BOM)"
+msgstr "(+%ld cho BOM)"
+
+msgid "%<%f%h%m%=Page %N"
+msgstr "%<%f%h%m%=Trang %N"
+
+msgid "Thanks for flying Vim"
+msgstr "Xin cảm ơn đã sử dụng Vim"
+
+msgid "E518: Unknown option"
+msgstr "E518: Tùy chá»n không biết"
+
+msgid "E519: Option not supported"
+msgstr "E519: Tùy chá»n không được há»— trợ"
+
+msgid "E520: Not allowed in a modeline"
+msgstr "E520: Không cho phép trên dòng chế độ (modeline)"
+
+msgid ""
+"\n"
+"\tLast set from "
+msgstr ""
+"\n"
+"\tLần cuối cùng tùy chá»n thay đổi vào "
+
+msgid "E521: Number required after ="
+msgstr "E521: Sau dấu = cần đưa ra một số"
+
+msgid "E522: Not found in termcap"
+msgstr "E522: Không tìm thấy trong termcap"
+
+#, c-format
+msgid "E539: Illegal character <%s>"
+msgstr "E539: Ký tự không cho phép <%s>"
+
+msgid "E529: Cannot set 'term' to empty string"
+msgstr "E529: Giá trị của tùy chá»n 'term' không thể là má»™t chuá»—i trống rá»—ng"
+
+msgid "E530: Cannot change term in GUI"
+msgstr "E530: Không thể thay đổi terminal trong giao diện đồ há»a GUI"
+
+msgid "E531: Use \":gui\" to start the GUI"
+msgstr "E531: Hãy sá»­ dụng \":gui\" để chạy giao diện đồ há»a GUI"
+
+msgid "E589: 'backupext' and 'patchmode' are equal"
+msgstr "E589: giá trị của tùy chá»n 'backupext' và 'patchmode' bằng nhau"
+
+msgid "E617: Cannot be changed in the GTK+ 2 GUI"
+msgstr "E617: Không thể thay đổi trong giao diện đồ há»a GTK+ 2"
+
+msgid "E524: Missing colon"
+msgstr "E524: Thiếu dấu hai chấm"
+
+msgid "E525: Zero length string"
+msgstr "E525: Chuỗi có độ dài bằng không"
+
+#, c-format
+msgid "E526: Missing number after <%s>"
+msgstr "E526: Thiếu một số sau <%s>"
+
+msgid "E527: Missing comma"
+msgstr "E527: Thiếu dấu phẩy"
+
+msgid "E528: Must specify a ' value"
+msgstr "E528: Cần đưa ra một giá trị cho '"
+
+msgid "E595: contains unprintable or wide character"
+msgstr "E595: chứa ký tá»± không in ra hoặc ký tá»± vá»›i chiá»u rá»™ng gấp đôi"
+
+msgid "E596: Invalid font(s)"
+msgstr "E596: Phông chữ không đúng"
+
+msgid "E597: can't select fontset"
+msgstr "E597: không chá»n được bá»™ phông chữ"
+
+msgid "E598: Invalid fontset"
+msgstr "E598: Bộ phông chữ không đúng"
+
+msgid "E533: can't select wide font"
+msgstr "E533: không chá»n được phông chữ vá»›i các ký tá»± có chiá»u rá»™ng gấp đôi"
+
+msgid "E534: Invalid wide font"
+msgstr "E534: Phông chữ, vá»›i ký tá»± có chiá»u rá»™ng gấp đôi, không đúng"
+
+#, c-format
+msgid "E535: Illegal character after <%c>"
+msgstr "E535: Ký tự sau <%c> không chính xác"
+
+msgid "E536: comma required"
+msgstr "E536: cầu có dấu phẩy"
+
+#, c-format
+msgid "E537: 'commentstring' must be empty or contain %s"
+msgstr "E537: Giá trị của tùy chá»n 'commentstring' phải rá»—ng hoặc chứa %s"
+
+msgid "E538: No mouse support"
+msgstr "E538: Chuột không được hỗ trợ"
+
+msgid "E540: Unclosed expression sequence"
+msgstr "E540: Dãy các biểu thức không đóng"
+
+msgid "E541: too many items"
+msgstr "E541: quá nhiá»u phần tá»­"
+
+msgid "E542: unbalanced groups"
+msgstr "E542: các nhóm không cân bằng"
+
+msgid "E590: A preview window already exists"
+msgstr "E590: Cửa sổ xem trước đã có"
+
+msgid "W17: Arabic requires UTF-8, do ':set encoding=utf-8'"
+msgstr "W17: Tiếng Ả Rập yêu cầu sử dụng UTF-8, hãy nhập ':set encoding=utf-8'"
+
+#, c-format
+msgid "E593: Need at least %d lines"
+msgstr "E593: Cần ít nhất %d dòng"
+
+#, c-format
+msgid "E594: Need at least %d columns"
+msgstr "E594: Cần ít nhất %d cột"
+
+#, c-format
+msgid "E355: Unknown option: %s"
+msgstr "E355: Tùy chá»n không biết: %s"
+
+msgid ""
+"\n"
+"--- Terminal codes ---"
+msgstr ""
+"\n"
+"--- Mã terminal ---"
+
+msgid ""
+"\n"
+"--- Global option values ---"
+msgstr ""
+"\n"
+"--- Giá trị tùy chá»n toàn cầu ---"
+
+msgid ""
+"\n"
+"--- Local option values ---"
+msgstr ""
+"\n"
+"--- Giá trị tùy chá»n ná»™i bá»™ ---"
+
+msgid ""
+"\n"
+"--- Options ---"
+msgstr ""
+"\n"
+"--- Tùy chá»n ---"
+
+msgid "E356: get_varp ERROR"
+msgstr "E356: Lá»–I get_varp"
+
+#, c-format
+msgid "E357: 'langmap': Matching character missing for %s"
+msgstr "E357: 'langmap': Thiếu ký tự tương ứng cho %s"
+
+#, c-format
+msgid "E358: 'langmap': Extra characters after semicolon: %s"
+msgstr "E358: 'langmap': Thừa ký tự sau dấu chấm phẩy: %s"
+
+msgid "cannot open "
+msgstr "không mở được "
+
+msgid "VIM: Can't open window!\n"
+msgstr "VIM: Không mở được cửa sổ!\n"
+
+msgid "Need Amigados version 2.04 or later\n"
+msgstr "Cần Amigados phiên bản 2.04 hoặc mới hơn\n"
+
+#, c-format
+msgid "Need %s version %ld\n"
+msgstr "Cần %s phiên bản %ld\n"
+
+msgid "Cannot open NIL:\n"
+msgstr "Không mở được NIL:\n"
+
+msgid "Cannot create "
+msgstr "Không tạo được "
+
+#, c-format
+msgid "Vim exiting with %d\n"
+msgstr "Thoát Vim với mã %d\n"
+
+msgid "cannot change console mode ?!\n"
+msgstr "không thay đổi được chế độ kênh giao tác (console)?!\n"
+
+msgid "mch_get_shellsize: not a console??\n"
+msgstr "mch_get_shellsize: không phải là kênh giao tác (console)??\n"
+
+#. if Vim opened a window: Executing a shell may cause crashes
+msgid "E360: Cannot execute shell with -f option"
+msgstr "E360: Không chạy được shell vá»›i tùy chá»n -f"
+
+msgid "Cannot execute "
+msgstr "Không chạy được "
+
+msgid "shell "
+msgstr "shell "
+
+msgid " returned\n"
+msgstr " thoát\n"
+
+msgid "ANCHOR_BUF_SIZE too small."
+msgstr "Giá trị ANCHOR_BUF_SIZE quá nhá»."
+
+msgid "I/O ERROR"
+msgstr "LỖI I/O (NHẬP/XUẤT)"
+
+msgid "...(truncated)"
+msgstr "...(bị cắt bớt)"
+
+msgid "'columns' is not 80, cannot execute external commands"
+msgstr "Tùy chá»n 'columns' khác 80, chÆ°Æ¡ng trình ngoại trú không thể thá»±c hiện"
+
+msgid "E237: Printer selection failed"
+msgstr "E237: Chá»n máy in không thành công"
+
+#, c-format
+msgid "to %s on %s"
+msgstr "tới %s trên %s"
+
+#, c-format
+msgid "E613: Unknown printer font: %s"
+msgstr "E613: Không rõ phông chữ của máy in: %s"
+
+#, c-format
+msgid "E238: Print error: %s"
+msgstr "E238: Lá»—i in: %s"
+
+msgid "Unknown"
+msgstr "Không rõ"
+
+#, c-format
+msgid "Printing '%s'"
+msgstr "Äang in '%s'"
+
+#, c-format
+msgid "E244: Illegal charset name \"%s\" in font name \"%s\""
+msgstr "E244: Tên bảng mã không cho phép \"%s\" trong tên phông chữ \"%s\""
+
+#, c-format
+msgid "E245: Illegal char '%c' in font name \"%s\""
+msgstr "E245: Ký tự không cho phép '%c' trong tên phông chữ \"%s\""
+
+msgid "Vim: Double signal, exiting\n"
+msgstr "Vim: Tín hiệu đôi, thoát\n"
+
+#, c-format
+msgid "Vim: Caught deadly signal %s\n"
+msgstr "Vim: Nhận được tín hiệu chết %s\n"
+
+msgid "Vim: Caught deadly signal\n"
+msgstr "Vim: Nhận được tín hiệu chết\n"
+
+#, c-format
+msgid "Opening the X display took %ld msec"
+msgstr "Mở màn hình X mất %ld mili giây"
+
+msgid ""
+"\n"
+"Vim: Got X error\n"
+msgstr ""
+"\n"
+"Vim: Lá»—i X\n"
+
+msgid "Testing the X display failed"
+msgstr "Kiểm tra màn hình X không thành công"
+
+msgid "Opening the X display timed out"
+msgstr "Không mở được màn hình X trong thá»i gian cho phép (time out)"
+
+msgid ""
+"\n"
+"Cannot execute shell "
+msgstr ""
+"\n"
+"Không chạy được shell "
+
+msgid ""
+"\n"
+"Cannot execute shell sh\n"
+msgstr ""
+"\n"
+"Không chạy được shell sh\n"
+
+msgid ""
+"\n"
+"shell returned "
+msgstr ""
+"\n"
+"shell dừng làm việc "
+
+msgid ""
+"\n"
+"Cannot create pipes\n"
+msgstr ""
+"\n"
+"Không tạo được Ä‘Æ°á»ng ống (pipe)\n"
+
+msgid ""
+"\n"
+"Cannot fork\n"
+msgstr ""
+"\n"
+"Không thực hiện được fork()\n"
+
+msgid ""
+"\n"
+"Command terminated\n"
+msgstr ""
+"\n"
+"Câu lệnh bị gián đoạn\n"
+
+msgid "XSMP lost ICE connection"
+msgstr "XSMP mất kết nối ICE"
+
+msgid "Opening the X display failed"
+msgstr "Mở màn hình X không thành công"
+
+msgid "XSMP handling save-yourself request"
+msgstr "XSMP xử lý yêu cầu tự động ghi nhớ"
+
+msgid "XSMP opening connection"
+msgstr "XSMP mở kết nối"
+
+msgid "XSMP ICE connection watch failed"
+msgstr "XSMP mất theo dõi kết nối ICE"
+
+#, c-format
+msgid "XSMP SmcOpenConnection failed: %s"
+msgstr "XSMP thực hiện SmcOpenConnection không thành công: %s"
+
+msgid "At line"
+msgstr "Tại dòng"
+
+msgid "Could not allocate memory for command line."
+msgstr "Không phân chia được bộ nhớ cho dòng lệnh."
+
+msgid "VIM Error"
+msgstr "Lá»—i VIM"
+
+msgid "Could not load vim32.dll!"
+msgstr "Không nạp được vim32.dll!"
+
+msgid "Could not fix up function pointers to the DLL!"
+msgstr "Không sửa được cái chỉ (pointer) hàm số tới DLL!"
+
+#, c-format
+msgid "shell returned %d"
+msgstr "thoát shell với mã %d"
+
+#, c-format
+msgid "Vim: Caught %s event\n"
+msgstr "Vim: Nhận được sự kiện %s\n"
+
+msgid "close"
+msgstr "đóng"
+
+msgid "logoff"
+msgstr "thoát"
+
+msgid "shutdown"
+msgstr "tắt máy"
+
+msgid "E371: Command not found"
+msgstr "E371: Câu lệnh không tìm thấy"
+
+msgid ""
+"VIMRUN.EXE not found in your $PATH.\n"
+"External commands will not pause after completion.\n"
+"See :help win32-vimrun for more information."
+msgstr ""
+"Không tìm thấy VIMRUN.EXE trong $PATH.\n"
+"Lệnh ngoại trú sẽ không dừng lại sau khi hoàn thành.\n"
+"Thông tin chi tiết xem trong :help win32-vimrun"
+
+msgid "Vim Warning"
+msgstr "Cảnh báo Vim"
+
+#, c-format
+msgid "E372: Too many %%%c in format string"
+msgstr "E372: Quá nhiá»u %%%c trong chuá»—i định dạng"
+
+#, c-format
+msgid "E373: Unexpected %%%c in format string"
+msgstr "E373: Không mong đợi %%%c trong chuỗi định dạng"
+
+msgid "E374: Missing ] in format string"
+msgstr "E374: Thiếu ] trong chuỗi định dạng"
+
+#, c-format
+msgid "E375: Unsupported %%%c in format string"
+msgstr "E375: %%%c không được hỗ trợ trong chuỗi định dạng"
+
+#, c-format
+msgid "E376: Invalid %%%c in format string prefix"
+msgstr "E376: Không cho phép %%%c trong tiá»n tố của chuá»—i định dạng"
+
+#, c-format
+msgid "E377: Invalid %%%c in format string"
+msgstr "E377: Không cho phép %%%c trong chuỗi định dạng"
+
+msgid "E378: 'errorformat' contains no pattern"
+msgstr "E378: Trong giá trị 'errorformat' thiếu mẫu (pattern)"
+
+msgid "E379: Missing or empty directory name"
+msgstr "E379: Tên thư mục không được đưa ra hoặc bằng một chuỗi rỗng"
+
+msgid "E553: No more items"
+msgstr "E553: Không còn phần tử nào nữa"
+
+#, c-format
+msgid "(%d of %d)%s%s: "
+msgstr "(%d của %d)%s%s: "
+
+msgid " (line deleted)"
+msgstr " (dòng bị xóa)"
+
+msgid "E380: At bottom of quickfix stack"
+msgstr "E380: Ở dưới của đống sửa nhanh"
+
+msgid "E381: At top of quickfix stack"
+msgstr "E381: Ở đầu của đống sửa nhanh"
+
+#, c-format
+msgid "error list %d of %d; %d errors"
+msgstr "danh sách lỗi %d của %d; %d lỗi"
+
+msgid "E382: Cannot write, 'buftype' option is set"
+msgstr "E382: Không ghi nhớ được, giá trị 'buftype' không phải là chuỗi rỗng"
+
+#, c-format
+msgid "E369: invalid item in %s%%[]"
+msgstr "E369: phần tử không cho phép trong %s%%[]"
+
+msgid "E339: Pattern too long"
+msgstr "E339: Mẫu (pattern) quá dài"
+
+msgid "E50: Too many \\z("
+msgstr "E50: Quá nhiá»u \\z("
+
+#, c-format
+msgid "E51: Too many %s("
+msgstr "E51: Quá nhiá»u %s("
+
+msgid "E52: Unmatched \\z("
+msgstr "E52: Không có cặp cho \\z("
+
+#, c-format
+msgid "E53: Unmatched %s%%("
+msgstr "E53: Không có cặp cho %s%%("
+
+#, c-format
+msgid "E54: Unmatched %s("
+msgstr "E54: Không có cặp cho %s("
+
+#, c-format
+msgid "E55: Unmatched %s)"
+msgstr "E55: Không có cặp cho %s)"
+
+#, c-format
+msgid "E56: %s* operand could be empty"
+msgstr "E56: operand %s* không thể rỗng"
+
+#, c-format
+msgid "E57: %s+ operand could be empty"
+msgstr "E57: operand %s+ không thể rỗng"
+
+#, c-format
+msgid "E59: invalid character after %s@"
+msgstr "E59: ký tự không cho phép sau %s@"
+
+#, c-format
+msgid "E58: %s{ operand could be empty"
+msgstr "E58: operand %s{ không thể rỗng"
+
+#, c-format
+msgid "E60: Too many complex %s{...}s"
+msgstr "E60: Quá nhiá»u cấu trúc phức tạp %s{...}"
+
+#, c-format
+msgid "E61: Nested %s*"
+msgstr "E61: %s* lồng vào"
+
+#, c-format
+msgid "E62: Nested %s%c"
+msgstr "E62: %s%c lồng vào"
+
+msgid "E63: invalid use of \\_"
+msgstr "E63: không cho phép sử dụng \\_"
+
+#, c-format
+msgid "E64: %s%c follows nothing"
+msgstr "E64: %s%c không theo sau gì cả"
+
+msgid "E65: Illegal back reference"
+msgstr "E65: Không cho phép liên kết ngược lại"
+
+msgid "E66: \\z( not allowed here"
+msgstr "E66: \\z( không thể sử dụng ở đây"
+
+msgid "E67: \\z1 - \\z9 not allowed here"
+msgstr "E67: \\z1 và tương tự không được sử dụng ở đây"
+
+msgid "E68: Invalid character after \\z"
+msgstr "E68: Ký tự không cho phép sau \\z"
+
+#, c-format
+msgid "E69: Missing ] after %s%%["
+msgstr "E69: Thiếu ] sau %s%%["
+
+#, c-format
+msgid "E70: Empty %s%%[]"
+msgstr "E70: %s%%[] rá»—ng"
+
+#, c-format
+msgid "E71: Invalid character after %s%%"
+msgstr "E71: Ký tự không cho phép sau %s%%"
+
+#, c-format
+msgid "E554: Syntax error in %s{...}"
+msgstr "E554: Lỗi cú pháp trong %s{...}"
+
+msgid "E361: Crash intercepted; regexp too complex?"
+msgstr "E361: Sự cố được ngăn chặn; biểu thức chính quy quá phức tạp?"
+
+msgid "E363: pattern caused out-of-stack error"
+msgstr "E363: sử dụng mẫu (pattern) gây ra lỗi out-of-stack"
+
+msgid "External submatches:\n"
+msgstr "Sự tương ứng con ngoài:\n"
+
+#, c-format
+msgid "+--%3ld lines folded "
+msgstr "+--%3ld dòng được gấp"
+
+msgid " VREPLACE"
+msgstr " THAY THẾ ẢO"
+
+msgid " REPLACE"
+msgstr " THAY THẾ"
+
+msgid " REVERSE"
+msgstr " NGƯỢC LẠI"
+
+msgid " INSERT"
+msgstr " CHÈN"
+
+msgid " (insert)"
+msgstr " (chèn)"
+
+msgid " (replace)"
+msgstr " (thay thế)"
+
+msgid " (vreplace)"
+msgstr " (thay thế ảo)"
+
+msgid " Hebrew"
+msgstr " Do thái"
+
+msgid " Arabic"
+msgstr " Ả rập"
+
+msgid " (lang)"
+msgstr " (ngôn ngữ)"
+
+msgid " (paste)"
+msgstr " (dán)"
+
+msgid " VISUAL"
+msgstr " CHẾ ÄỘ VISUAL"
+
+msgid " VISUAL LINE"
+msgstr " DÃ’NG VISUAL"
+
+msgid " VISUAL BLOCK"
+msgstr " KHá»I VISUAL"
+
+msgid " SELECT"
+msgstr " LỰA CHỌN"
+
+msgid " SELECT LINE"
+msgstr " LỰA CHỌN DÒNG"
+
+msgid " SELECT BLOCK"
+msgstr " Lá»°A CHỌN KHá»I"
+
+msgid "recording"
+msgstr "Ä‘ang ghi"
+
+msgid "search hit TOP, continuing at BOTTOM"
+msgstr "tìm kiếm sẽ được tiếp tục từ CUá»I tài liệu"
+
+msgid "search hit BOTTOM, continuing at TOP"
+msgstr "tìm kiếm sẽ được tiếp tục từ ÄẦU tài liệu"
+
+#, c-format
+msgid "E383: Invalid search string: %s"
+msgstr "E383: Chuỗi tìm kiếm không đúng: %s"
+
+#, c-format
+msgid "E384: search hit TOP without match for: %s"
+msgstr "E384: tìm kiếm kết thúc ở ÄẦU tập tin; không tìm thấy %s"
+
+#, c-format
+msgid "E385: search hit BOTTOM without match for: %s"
+msgstr "E385: tìm kiếm kết thúc ở CUá»I tập tin; không tìm thấy %s"
+
+msgid "E386: Expected '?' or '/' after ';'"
+msgstr "E386: Mong đợi nhập '?' hoặc '/' sau ';'"
+
+msgid " (includes previously listed match)"
+msgstr " (gồm cả những tương ứng đã liệt kê trước đây)"
+
+#. cursor at status line
+msgid "--- Included files "
+msgstr "--- Tập tin tính đến "
+
+msgid "not found "
+msgstr "không tìm thấy "
+
+msgid "in path ---\n"
+msgstr "trong Ä‘Æ°á»ng dẫn ---\n"
+
+msgid " (Already listed)"
+msgstr " (Äã liệt kê)"
+
+msgid " NOT FOUND"
+msgstr " KHÔNG TÌM THẤY"
+
+#, c-format
+msgid "Scanning included file: %s"
+msgstr "Quét trong tập tin được tính đến: %s"
+
+msgid "E387: Match is on current line"
+msgstr "E387: Tương ứng nằm trên dòng hiện tại"
+
+msgid "All included files were found"
+msgstr "Tìm thấy tất cả các tập tin được tính đến"
+
+msgid "No included files"
+msgstr "Không có tập tin được tính đến"
+
+msgid "E388: Couldn't find definition"
+msgstr "E388: Không tìm thấy định nghĩa"
+
+msgid "E389: Couldn't find pattern"
+msgstr "E389: Không tìm thấy mẫu (pattern)"
+
+#, c-format
+msgid "E390: Illegal argument: %s"
+msgstr "E390: Tham số không cho phép: %s"
+
+#, c-format
+msgid "E391: No such syntax cluster: %s"
+msgstr "E391: Không có cụm cú pháp như vậy: %s"
+
+msgid "No Syntax items defined for this buffer"
+msgstr "Không có phần tử cú pháp nào được định nghĩa cho bộ đệm này"
+
+msgid "syncing on C-style comments"
+msgstr "Äồng bá»™ hóa theo chú thích kiểu C"
+
+msgid "no syncing"
+msgstr "không đồng bộ hóa"
+
+msgid "syncing starts "
+msgstr "đồng bộ hóa bắt đầu "
+
+msgid " lines before top line"
+msgstr " dòng trước dòng đầu tiên"
+
+msgid ""
+"\n"
+"--- Syntax sync items ---"
+msgstr ""
+"\n"
+"--- Phần tử đồng bộ hóa cú pháp ---"
+
+msgid ""
+"\n"
+"syncing on items"
+msgstr ""
+"\n"
+"đồng bộ hóa theo phần tử"
+
+msgid ""
+"\n"
+"--- Syntax items ---"
+msgstr ""
+"\n"
+"--- Phần tử cú pháp ---"
+
+#, c-format
+msgid "E392: No such syntax cluster: %s"
+msgstr "E392: Không có cụm cú pháp như vậy: %s"
+
+msgid "minimal "
+msgstr "nhỠnhất "
+
+msgid "maximal "
+msgstr "lớn nhất "
+
+msgid "; match "
+msgstr "; tương ứng "
+
+msgid " line breaks"
+msgstr " chuyển dòng"
+
+msgid "E393: group[t]here not accepted here"
+msgstr "E393: không được sử dụng group[t]here ở đây"
+
+#, c-format
+msgid "E394: Didn't find region item for %s"
+msgstr "E394: Phần tử vùng cho %s không tìm thấy"
+
+msgid "E395: contains argument not accepted here"
+msgstr "E395: không được sử dụng tham số contains ở đây"
+
+msgid "E396: containedin argument not accepted here"
+msgstr "E396: không được sử dụng tham số containedin ở đây"
+
+msgid "E397: Filename required"
+msgstr "E397: Yêu cầu tên tập tin"
+
+#, c-format
+msgid "E398: Missing '=': %s"
+msgstr "E398: Thiếu '=': %s"
+
+#, c-format
+msgid "E399: Not enough arguments: syntax region %s"
+msgstr "E399: Không đủ tham số: vùng cú pháp %s"
+
+msgid "E400: No cluster specified"
+msgstr "E400: Chưa chỉ ra cụm"
+
+#, c-format
+msgid "E401: Pattern delimiter not found: %s"
+msgstr "E401: Không tìm thấy ký tự phân chia mẫu (pattern): %s"
+
+#, c-format
+msgid "E402: Garbage after pattern: %s"
+msgstr "E402: Rác ở sau mẫu (pattern): %s"
+
+msgid "E403: syntax sync: line continuations pattern specified twice"
+msgstr "E403: đồng bộ hóa cú pháp: mẫu tiếp tục của dòng chỉ ra hai lần"
+
+#, c-format
+msgid "E404: Illegal arguments: %s"
+msgstr "E404: Tham số không cho phép: %s"
+
+#, c-format
+msgid "E405: Missing equal sign: %s"
+msgstr "E405: Thiếu dấu bằng: %s"
+
+#, c-format
+msgid "E406: Empty argument: %s"
+msgstr "E406: Tham số trống rỗng: %s"
+
+#, c-format
+msgid "E407: %s not allowed here"
+msgstr "E407: %s không được cho phép ở đây"
+
+#, c-format
+msgid "E408: %s must be first in contains list"
+msgstr "E408: %s phải là đầu tiên trong danh sách contains"
+
+#, c-format
+msgid "E409: Unknown group name: %s"
+msgstr "E409: Tên nhóm không biết: %s"
+
+#, c-format
+msgid "E410: Invalid :syntax subcommand: %s"
+msgstr "E410: Câu lệnh con :syntax không đúng: %s"
+
+#, c-format
+msgid "E411: highlight group not found: %s"
+msgstr "E411: không tìm thấy nhóm chiếu sáng cú pháp: %s"
+
+#, c-format
+msgid "E412: Not enough arguments: \":highlight link %s\""
+msgstr "E412: Không đủ tham số: \":highlight link %s\""
+
+#, c-format
+msgid "E413: Too many arguments: \":highlight link %s\""
+msgstr "E413: Quá nhiá»u tham số: \":highlight link %s\""
+
+msgid "E414: group has settings, highlight link ignored"
+msgstr "E414: nhóm có thiết lập riêng, chiếu sáng liên kết bị bỠqua"
+
+#, c-format
+msgid "E415: unexpected equal sign: %s"
+msgstr "E415: dấu bằng không được mong đợi: %s"
+
+#, c-format
+msgid "E416: missing equal sign: %s"
+msgstr "E416: thiếu dấu bằng: %s"
+
+#, c-format
+msgid "E417: missing argument: %s"
+msgstr "E417: thiếu tham số: %s"
+
+#, c-format
+msgid "E418: Illegal value: %s"
+msgstr "E418: Giá trị không cho phép: %s"
+
+msgid "E419: FG color unknown"
+msgstr "E419: Không rõ màu văn bản (FG)"
+
+msgid "E420: BG color unknown"
+msgstr "E420: Không rõ màu ná»n sau (BG)"
+
+#, c-format
+msgid "E421: Color name or number not recognized: %s"
+msgstr "E421: Tên hoặc số của màu không được nhận ra: %s"
+
+#, c-format
+msgid "E422: terminal code too long: %s"
+msgstr "E422: mã terminal quá dài: %s"
+
+#, c-format
+msgid "E423: Illegal argument: %s"
+msgstr "E423: Tham số không cho phép: %s"
+
+msgid "E424: Too many different highlighting attributes in use"
+msgstr "E424: Sá»­ dụng quá nhiá»u thuá»™c tính chiếu sáng cú pháp"
+
+msgid "E669: Unprintable character in group name"
+msgstr "E669: Ký tự không thể tin ra trong tên nhóm"
+
+#. This is an error, but since there previously was no check only
+#. * give a warning.
+msgid "W18: Invalid character in group name"
+msgstr "W18: Ký tự không cho phép trong tên nhóm"
+
+msgid "E555: at bottom of tag stack"
+msgstr "E555: ở cuối đống thẻ ghi"
+
+msgid "E556: at top of tag stack"
+msgstr "E556: ở đầu đống thẻ ghi"
+
+msgid "E425: Cannot go before first matching tag"
+msgstr "E425: Không chuyển được tới vị trí ở trước thẻ ghi tương ứng đầu tiên"
+
+#, c-format
+msgid "E426: tag not found: %s"
+msgstr "E426: không tìm thấy thẻ ghi: %s"
+
+msgid " # pri kind tag"
+msgstr " # pri loại thẻ ghi"
+
+msgid "file\n"
+msgstr "tập tin\n"
+
+#.
+#. * Ask to select a tag from the list.
+#. * When using ":silent" assume that <CR> was entered.
+#.
+msgid "Enter nr of choice (<CR> to abort): "
+msgstr "Hãy chá»n số cần thiết (<CR> để dừng):"
+
+msgid "E427: There is only one matching tag"
+msgstr "E427: Chỉ có một thẻ ghi tương ứng"
+
+msgid "E428: Cannot go beyond last matching tag"
+msgstr "E428: Không chuyển được tới vị trí ở sau thẻ ghi tương ứng cuối cùng"
+
+#, c-format
+msgid "File \"%s\" does not exist"
+msgstr "Tập tin \"%s\" không tồn tại"
+
+#. Give an indication of the number of matching tags
+#, c-format
+msgid "tag %d of %d%s"
+msgstr "thẻ ghi %d của %d%s"
+
+msgid " or more"
+msgstr " và hơn nữa"
+
+msgid " Using tag with different case!"
+msgstr " Äang sá»­ dụng thẻ ghi vá»›i kiểu chữ khác!"
+
+#, c-format
+msgid "E429: File \"%s\" does not exist"
+msgstr "E429: Tập tin \"%s\" không tồn tại"
+
+#. Highlight title
+msgid ""
+"\n"
+" # TO tag FROM line in file/text"
+msgstr ""
+"\n"
+" # TỚI thẻ ghi TỪ dòng trong tập tin/văn bản"
+
+#, c-format
+msgid "Searching tags file %s"
+msgstr "Tìm kiếm tập tin thẻ ghi %s"
+
+#, c-format
+msgid "E430: Tag file path truncated for %s\n"
+msgstr "E430: ÄÆ°á»ng dẫn tá»›i tập tin thẻ ghi bị cắt bá»›t cho %s\n"
+
+#, c-format
+msgid "E431: Format error in tags file \"%s\""
+msgstr "E431: Lỗi định dạng trong tập tin thẻ ghi \"%s\""
+
+#, c-format
+msgid "Before byte %ld"
+msgstr "TrÆ°á»›c byte %ld"
+
+#, c-format
+msgid "E432: Tags file not sorted: %s"
+msgstr "E432: Tập tin thẻ ghi chưa được sắp xếp: %s"
+
+#. never opened any tags file
+msgid "E433: No tags file"
+msgstr "E433: Không có tập tin thẻ ghi"
+
+msgid "E434: Can't find tag pattern"
+msgstr "E434: Không tìm thấy mẫu thẻ ghi"
+
+msgid "E435: Couldn't find tag, just guessing!"
+msgstr "E435: Không tìm thấy thẻ ghi, đang thử đoán!"
+
+msgid "' not known. Available builtin terminals are:"
+msgstr "' không rõ. Có các terminal gắn sẵn (builtin) sau:"
+
+msgid "defaulting to '"
+msgstr "theo mặc định '"
+
+msgid "E557: Cannot open termcap file"
+msgstr "E557: Không thể mở tập tin termcap"
+
+msgid "E558: Terminal entry not found in terminfo"
+msgstr "E558: Trong terminfo không có bản ghi nào vỠterminal này"
+
+msgid "E559: Terminal entry not found in termcap"
+msgstr "E559: Trong termcap không có bản ghi nào vỠterminal này"
+
+#, c-format
+msgid "E436: No \"%s\" entry in termcap"
+msgstr "E436: Trong termcap không có bản ghi \"%s\""
+
+msgid "E437: terminal capability \"cm\" required"
+msgstr "E437: cần khả năng của terminal \"cm\""
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Terminal keys ---"
+msgstr ""
+"\n"
+"--- Phím terminal ---"
+
+msgid "new shell started\n"
+msgstr "đã chạy shell mới\n"
+
+msgid "Vim: Error reading input, exiting...\n"
+msgstr "Vim: Lá»—i Ä‘á»c dữ liệu nhập, thoát...\n"
+
+#. must display the prompt
+msgid "No undo possible; continue anyway"
+msgstr "Không thể hủy thao tác; tiếp tục thực hiện"
+
+msgid "E438: u_undo: line numbers wrong"
+msgstr "E438: u_undo: số thứ tự dòng không đúng"
+
+msgid "1 change"
+msgstr "duy nhất 1 thay đổi"
+
+#, c-format
+msgid "%ld changes"
+msgstr "%ld thay đổi"
+
+msgid "E439: undo list corrupt"
+msgstr "E439: danh sách hủy thao tác (undo) bị há»ng"
+
+msgid "E440: undo line missing"
+msgstr "E440: bị mất dòng hủy thao tác"
+
+#. Only MS VC 4.1 and earlier can do Win32s
+msgid ""
+"\n"
+"MS-Windows 16/32-bit GUI version"
+msgstr ""
+"\n"
+"Phiên bản vá»›i giao diện đồ há»a GUI cho MS-Windows 16/32 bit"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit GUI version"
+msgstr ""
+"\n"
+"Phiên bản vá»›i giao diện đồ há»a GUI cho MS-Windows 32 bit"
+
+msgid " in Win32s mode"
+msgstr " trong chế độ Win32"
+
+msgid " with OLE support"
+msgstr " với hỗ trợ OLE"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit console version"
+msgstr ""
+"\n"
+"Phiên bản console cho MS-Windows 32 bit"
+
+msgid ""
+"\n"
+"MS-Windows 16-bit version"
+msgstr ""
+"\n"
+"Phiên bản cho MS-Windows 16 bit"
+
+msgid ""
+"\n"
+"32-bit MS-DOS version"
+msgstr ""
+"\n"
+"Phiên bản cho MS-DOS 32 bit"
+
+msgid ""
+"\n"
+"16-bit MS-DOS version"
+msgstr ""
+"\n"
+"Phiên bản cho MS-DOS 16 bit"
+
+msgid ""
+"\n"
+"MacOS X (unix) version"
+msgstr ""
+"\n"
+"Phiên bản cho MacOS X (unix)"
+
+msgid ""
+"\n"
+"MacOS X version"
+msgstr ""
+"\n"
+"Phiên bản cho MacOS X"
+
+msgid ""
+"\n"
+"MacOS version"
+msgstr ""
+"\n"
+"Phiên bản cho MacOS"
+
+msgid ""
+"\n"
+"RISC OS version"
+msgstr ""
+"\n"
+"Phiên bản cho RISC OS"
+
+msgid ""
+"\n"
+"Included patches: "
+msgstr ""
+"\n"
+"Bao gồm các bản vá lỗi: "
+
+msgid "Modified by "
+msgstr "Với các thay đổi bởi "
+
+msgid ""
+"\n"
+"Compiled "
+msgstr ""
+"\n"
+"Äược biên dịch "
+
+msgid "by "
+msgstr "bởi "
+
+msgid ""
+"\n"
+"Huge version "
+msgstr ""
+"\n"
+"Phiên bản khổng lồ "
+
+msgid ""
+"\n"
+"Big version "
+msgstr ""
+"\n"
+"Phiên bản lớn "
+
+msgid ""
+"\n"
+"Normal version "
+msgstr ""
+"\n"
+"Phiên bản thông thÆ°á»ng "
+
+msgid ""
+"\n"
+"Small version "
+msgstr ""
+"\n"
+"Phiên bản nhỠ"
+
+msgid ""
+"\n"
+"Tiny version "
+msgstr ""
+"\n"
+"Phiên bản \"tí hon\" "
+
+msgid "without GUI."
+msgstr "không có giao diện đồ há»a GUI."
+
+msgid "with GTK2-GNOME GUI."
+msgstr "vá»›i giao diện đồ há»a GUI GTK2-GNOME."
+
+msgid "with GTK-GNOME GUI."
+msgstr "vá»›i giao diện đồ há»a GUI GTK-GNOME."
+
+msgid "with GTK2 GUI."
+msgstr "vá»›i giao diện đồ há»a GUI GTK2."
+
+msgid "with GTK GUI."
+msgstr "vá»›i giao diện đồ há»a GUI GTK."
+
+msgid "with X11-Motif GUI."
+msgstr "vá»›i giao diện đồ há»a GUI X11-Motif."
+
+msgid "with X11-neXtaw GUI."
+msgstr "vá»›i giao diện đồ há»a GUI X11-neXtaw."
+
+msgid "with X11-Athena GUI."
+msgstr "vá»›i giao diện đồ há»a GUI X11-Athena."
+
+msgid "with BeOS GUI."
+msgstr "vá»›i giao diện đồ há»a GUI BeOS."
+
+msgid "with Photon GUI."
+msgstr "vá»›i giao diện đồ há»a GUI Photon."
+
+msgid "with GUI."
+msgstr "vá»›i giao diện đồ há»a GUI."
+
+msgid "with Carbon GUI."
+msgstr "vá»›i giao diện đồ há»a GUI Carbon."
+
+msgid "with Cocoa GUI."
+msgstr "vá»›i giao diện đồ há»a GUI Cocoa."
+
+msgid "with (classic) GUI."
+msgstr "vá»›i giao diện đồ há»a (cổ Ä‘iển) GUI."
+
+msgid " Features included (+) or not (-):\n"
+msgstr " Tính năng có (+) hoặc không (-):\n"
+
+msgid " system vimrc file: \""
+msgstr " tập tin vimrc chung cho hệ thống: \""
+
+msgid " user vimrc file: \""
+msgstr " tập tin vimrc của ngÆ°á»i dùng: \""
+
+msgid " 2nd user vimrc file: \""
+msgstr " tập tin vimrc thứ hai của ngÆ°á»i dùng: \""
+
+msgid " 3rd user vimrc file: \""
+msgstr " tập tin vimrc thứ ba của ngÆ°á»i dùng: \""
+
+msgid " user exrc file: \""
+msgstr " tập tin exrc của ngÆ°á»i dùng: \""
+
+msgid " 2nd user exrc file: \""
+msgstr " tập tin exrc thứ hai của ngÆ°á»i dùng: \""
+
+msgid " system gvimrc file: \""
+msgstr " tập tin gvimrc chung cho hệ thống: \""
+
+msgid " user gvimrc file: \""
+msgstr " tập tin gvimrc của ngÆ°á»i dùng: \""
+
+msgid "2nd user gvimrc file: \""
+msgstr " tập tin gvimrc thứ hai của ngÆ°á»i dùng: \""
+
+msgid "3rd user gvimrc file: \""
+msgstr " tập tin gvimrc thứ ba của ngÆ°á»i dùng: \""
+
+msgid " system menu file: \""
+msgstr " tập tin trình đơn chung cho hệ thống: \""
+
+msgid " fall-back for $VIM: \""
+msgstr " giá trị $VIM theo mặc định: \""
+
+msgid " f-b for $VIMRUNTIME: \""
+msgstr " giá trị $VIMRUNTIME theo mặc định: \""
+
+msgid "Compilation: "
+msgstr "Tham số biên dịch: "
+
+msgid "Compiler: "
+msgstr "Trình biên dịch: "
+
+msgid "Linking: "
+msgstr "Liên kết: "
+
+msgid " DEBUG BUILD"
+msgstr " BIÊN DỊCH SỬA LỖI (DEBUG)"
+
+msgid "VIM - Vi IMproved"
+msgstr "VIM ::: Vi IMproved (Vi cải tiến) ::: Phiên bản tiếng Việt"
+
+msgid "version "
+msgstr "phiên bản "
+
+msgid "by Bram Moolenaar et al."
+msgstr "Do Bram Moolenaar và những ngÆ°á»i khác thá»±c hiện"
+
+msgid "Vim is open source and freely distributable"
+msgstr "Vim là chương trình mã nguồn mở và phân phối tự do"
+
+msgid "Help poor children in Uganda!"
+msgstr "Hãy giúp đỡ trẻ em nghèo Uganda!"
+
+msgid "type :help iccf<Enter> for information "
+msgstr "hãy gõ :help iccf<Enter> để biết thêm thông tin"
+
+msgid "type :q<Enter> to exit "
+msgstr " hãy gõ :q<Enter> để thoát khá»i chÆ°Æ¡ng trình "
+
+msgid "type :help<Enter> or <F1> for on-line help"
+msgstr " hãy gõ :help<Enter> hoặc <F1> để có được trợ giúp "
+
+msgid "type :help version8<Enter> for version info"
+msgstr "hãy gõ :help version8<Enter> để biết vỠphiên bản này "
+
+msgid "Running in Vi compatible mode"
+msgstr "Làm việc trong chế độ tương thích với Vi"
+
+msgid "type :set nocp<Enter> for Vim defaults"
+msgstr "hãy gõ :set nocp<Enter> để chuyển vào chế độ Vim "
+
+msgid "type :help cp-default<Enter> for info on this"
+msgstr "hãy gõ :help cp-default<Enter> để có thêm thông tin vá» Ä‘iá»u này"
+
+msgid "menu Help->Orphans for information "
+msgstr "trình đơn Trợ giúp->Mồ côi để có thêm thông tin "
+
+msgid "Running modeless, typed text is inserted"
+msgstr "Không chế độ, văn bản nhập vào sẽ được chèn"
+
+msgid "menu Edit->Global Settings->Toggle Insert Mode "
+msgstr "trình đơn Soạn thảo->Thiết lập chung->Chế độ chèn "
+
+msgid " for two modes "
+msgstr " cho hai chế độ "
+
+msgid "menu Edit->Global Settings->Toggle Vi Compatible"
+msgstr ""
+"trình đơn Soạn thảo->Thiết lập chung->Tương thích với Vi "
+
+msgid " for Vim defaults "
+msgstr ""
+" để chuyển vào chế độ Vim mặc định "
+
+msgid "Sponsor Vim development!"
+msgstr "Hãy giúp đỡ phát triển Vim!"
+
+msgid "Become a registered Vim user!"
+msgstr "Hãy trở thành ngÆ°á»i dùng đăng ký của Vim!"
+
+msgid "type :help sponsor<Enter> for information "
+msgstr "hãy gõ :help sponsor<Enter> để biết thêm thông tin "
+
+msgid "type :help register<Enter> for information "
+msgstr "hãy gõ :help register<Enter> để biết thêm thông tin "
+
+msgid "menu Help->Sponsor/Register for information "
+msgstr "trình Ä‘Æ¡n Trợ giúp->Giúp đỡ/Äăng ký để biết thêm thông tin "
+
+msgid "WARNING: Windows 95/98/ME detected"
+msgstr "CẢNH BÃO: nhận ra Windows 95/98/ME"
+
+msgid "type :help windows95<Enter> for info on this"
+msgstr "hãy gõ :help windows95<Enter> để biết thêm thông tin "
+
+msgid "E441: There is no preview window"
+msgstr "E441: Không có cửa sổ xem trước"
+
+msgid "E442: Can't split topleft and botright at the same time"
+msgstr ""
+"E442: Cá»­a sổ không thể đồng thá»i ở bên trái phía trên và bên phải phía dÆ°á»›i"
+
+msgid "E443: Cannot rotate when another window is split"
+msgstr "E443: Không đổi được chỗ khi cửa sổ khác được chia"
+
+msgid "E444: Cannot close last window"
+msgstr "E444: Không được đóng cửa sổ cuối cùng"
+
+msgid "Already only one window"
+msgstr "Chỉ có một cửa sổ"
+
+msgid "E445: Other window contains changes"
+msgstr "E445: Cửa sổ khác có thay đổi chưa được ghi nhớ"
+
+msgid "E446: No file name under cursor"
+msgstr "E446: Không có tên tập tin tại vị trí con trá»"
+
+#, c-format
+msgid "E447: Can't find file \"%s\" in path"
+msgstr "E447: Không tìm thấy tập tin \"%s\" trong Ä‘Æ°á»ng dẫn"
+
+#, c-format
+msgid "E370: Could not load library %s"
+msgstr "E370: Không nạp được thư viện %s"
+
+msgid "Sorry, this command is disabled: the Perl library could not be loaded."
+msgstr "Xin lỗi, câu lệnh này bị tắt: không nạp được thư viện Perl."
+
+msgid "E299: Perl evaluation forbidden in sandbox without the Safe module"
+msgstr ""
+"E299: Không cho phép sự tính toán Perl trong hộp cát mà không có môđun An "
+"toàn"
+
+msgid "Edit with &multiple Vims"
+msgstr "Soạn thảo trong nhiá»u Vi&m"
+
+msgid "Edit with single &Vim"
+msgstr "Soạn thảo trong một &Vim"
+
+msgid "&Diff with Vim"
+msgstr "&So sánh (diff) qua Vim"
+
+msgid "Edit with &Vim"
+msgstr "Soạn thảo trong &Vim"
+
+#. Now concatenate
+msgid "Edit with existing Vim - &"
+msgstr "Soạn thảo trong Vim đã chạy - &"
+
+msgid "Edits the selected file(s) with Vim"
+msgstr "Soạn thảo (các) tập tin đã chá»n trong Vim"
+
+msgid "Error creating process: Check if gvim is in your path!"
+msgstr "Lá»—i tạo tiến trình: Hãy kiểm tra xem gvim có trong Ä‘Æ°á»ng dẫn không!"
+
+msgid "gvimext.dll error"
+msgstr "lá»—i gvimext.dll"
+
+msgid "Path length too long!"
+msgstr "ÄÆ°á»ng dẫn quá dài!"
+
+msgid "--No lines in buffer--"
+msgstr "-- Không có dòng nào trong bộ đệm --"
+
+#.
+#. * The error messages that can be shared are included here.
+#. * Excluded are errors that are only used once and debugging messages.
+#.
+msgid "E470: Command aborted"
+msgstr "E470: Câu lệnh bị dừng"
+
+msgid "E471: Argument required"
+msgstr "E471: Cần chỉ ra tham số"
+
+msgid "E10: \\ should be followed by /, ? or &"
+msgstr "E10: Sau \\ phải là các ký tự /, ? hoặc &"
+
+msgid "E11: Invalid in command-line window; <CR> executes, CTRL-C quits"
+msgstr "E11: Lỗi trong cửa sổ dòng lệnh; <CR> thực hiện, CTRL-C thoát"
+
+msgid "E12: Command not allowed from exrc/vimrc in current dir or tag search"
+msgstr ""
+"E12: Câu lệnh không cho phép từ exrc/vimrc trong thÆ° mục hiện thá»i hoặc "
+"trong tìm kiếm thẻ ghi"
+
+msgid "E171: Missing :endif"
+msgstr "E171: Thiếu câu lệnh :endif"
+
+msgid "E600: Missing :endtry"
+msgstr "E600: Thiếu câu lệnh :endtry"
+
+msgid "E170: Missing :endwhile"
+msgstr "E170: Thiếu câu lệnh :endwhile"
+
+msgid "E588: :endwhile without :while"
+msgstr "E588: Câu lệnh :endwhile không có lệnh :while (1 cặp)"
+
+msgid "E13: File exists (add ! to override)"
+msgstr "E13: Tập tin đã tồn tại (thêm ! để ghi chèn)"
+
+msgid "E472: Command failed"
+msgstr "E472: Không thực hiện thành công câu lệnh"
+
+#, c-format
+msgid "E234: Unknown fontset: %s"
+msgstr "E234: Không rõ bộ phông chữ: %s"
+
+#, c-format
+msgid "E235: Unknown font: %s"
+msgstr "E235: Không rõ phông chữ: %s"
+
+#, c-format
+msgid "E236: Font \"%s\" is not fixed-width"
+msgstr "E236: Phông chữ \"%s\" không có độ rộng cố định (fixed-width)"
+
+msgid "E473: Internal error"
+msgstr "E473: Lá»—i ná»™i bá»™"
+
+msgid "Interrupted"
+msgstr "Bị gián đoạn"
+
+msgid "E14: Invalid address"
+msgstr "E14: Äịa chỉ không cho phép"
+
+msgid "E474: Invalid argument"
+msgstr "E474: Tham số không cho phép"
+
+#, c-format
+msgid "E475: Invalid argument: %s"
+msgstr "E475: Tham số không cho phép: %s"
+
+#, c-format
+msgid "E15: Invalid expression: %s"
+msgstr "E15: Biểu thức không cho phép: %s"
+
+msgid "E16: Invalid range"
+msgstr "E16: Vùng không cho phép"
+
+msgid "E476: Invalid command"
+msgstr "E476: Câu lệnh không cho phép"
+
+#, c-format
+msgid "E17: \"%s\" is a directory"
+msgstr "E17: \"%s\" là mộ thư mục"
+
+msgid "E18: Unexpected characters before '='"
+msgstr "E18: Ở trước '=' có các ký tự không mong đợi"
+
+#, c-format
+msgid "E364: Library call failed for \"%s()\""
+msgstr "E364: Gá»i hàm số \"%s()\" của thÆ° viện không thành công"
+
+#, c-format
+msgid "E448: Could not load library function %s"
+msgstr "E448: Nạp hàm số %s của thư viện không thành công"
+
+msgid "E19: Mark has invalid line number"
+msgstr "E19: Dấu hiệu chỉ đến một số thứ tự dòng không đúng"
+
+msgid "E20: Mark not set"
+msgstr "E20: Dấu hiệu không được xác định"
+
+msgid "E21: Cannot make changes, 'modifiable' is off"
+msgstr "E21: Không thể thay đổi, vì tùy chá»n 'modifiable' bị tắt"
+
+msgid "E22: Scripts nested too deep"
+msgstr "E22: Các script lồng vào nhau quá sâu"
+
+msgid "E23: No alternate file"
+msgstr "E23: Không có tập tin xen kẽ"
+
+msgid "E24: No such abbreviation"
+msgstr "E24: Không có chữ viết tắt như vậy"
+
+msgid "E477: No ! allowed"
+msgstr "E477: Không cho phép !"
+
+msgid "E25: GUI cannot be used: Not enabled at compile time"
+msgstr "E25: Không sá»­ dụng được giao diện đồ há»a vì không chá»n khi biên dịch"
+
+msgid "E26: Hebrew cannot be used: Not enabled at compile time\n"
+msgstr "E26: Tiếng Do thái không được chá»n khi biên dịch\n"
+
+msgid "E27: Farsi cannot be used: Not enabled at compile time\n"
+msgstr "E27: Tiếng Farsi không được chá»n khi biên dịch\n"
+
+msgid "E800: Arabic cannot be used: Not enabled at compile time\n"
+msgstr "E800: Tiếng Ả Rập không được chá»n khi biên dịch\n"
+
+#, c-format
+msgid "E28: No such highlight group name: %s"
+msgstr "E28: Nhóm chiếu sáng cú pháp %s không tồn tại"
+
+msgid "E29: No inserted text yet"
+msgstr "E29: Tạm thá»i chÆ°a có văn bản được chèn"
+
+msgid "E30: No previous command line"
+msgstr "E30: Không có dòng lệnh trước"
+
+msgid "E31: No such mapping"
+msgstr "E31: Không có ánh xạ (mapping) như vậy"
+
+msgid "E479: No match"
+msgstr "E479: Không có tương ứng"
+
+#, c-format
+msgid "E480: No match: %s"
+msgstr "E480: Không có tương ứng: %s"
+
+msgid "E32: No file name"
+msgstr "E32: Không có tên tập tin"
+
+msgid "E33: No previous substitute regular expression"
+msgstr "E33: Không có biểu thức chính quy trước để thay thế"
+
+msgid "E34: No previous command"
+msgstr "E34: Không có câu lệnh trước"
+
+msgid "E35: No previous regular expression"
+msgstr "E35: Không có biểu thức chính quy trước"
+
+msgid "E481: No range allowed"
+msgstr "E481: Không cho phép sử dụng phạm vi"
+
+msgid "E36: Not enough room"
+msgstr "E36: Không đủ chỗ trống"
+
+#, c-format
+msgid "E247: no registered server named \"%s\""
+msgstr "E247: máy chủ \"%s\" chưa đăng ký"
+
+#, c-format
+msgid "E482: Can't create file %s"
+msgstr "E482: Không tạo được tập tin %s"
+
+msgid "E483: Can't get temp file name"
+msgstr "E483: Không nhận được tên tập tin tạm thá»i (temp)"
+
+#, c-format
+msgid "E484: Can't open file %s"
+msgstr "E484: Không mở được tập tin %s"
+
+#, c-format
+msgid "E485: Can't read file %s"
+msgstr "E485: Không Ä‘á»c được tập tin %s"
+
+msgid "E37: No write since last change (add ! to override)"
+msgstr "E37: Thay đổi chưa được ghi nhớ (thêm ! để bỠqua ghi nhớ)"
+
+msgid "E38: Null argument"
+msgstr "E38: Tham sô bằng 0"
+
+msgid "E39: Number expected"
+msgstr "E39: Yêu cầu một số"
+
+#, c-format
+msgid "E40: Can't open errorfile %s"
+msgstr "E40: Không mở được tập tin lỗi %s"
+
+msgid "E233: cannot open display"
+msgstr "E233: không mở được màn hình"
+
+msgid "E41: Out of memory!"
+msgstr "E41: Không đủ bộ nhớ!"
+
+msgid "Pattern not found"
+msgstr "Không tìm thấy mẫu (pattern)"
+
+#, c-format
+msgid "E486: Pattern not found: %s"
+msgstr "E486: Không tìm thấy mẫu (pattern): %s"
+
+msgid "E487: Argument must be positive"
+msgstr "E487: Tham số phải là một số dương"
+
+msgid "E459: Cannot go back to previous directory"
+msgstr "E459: Không quay lại được thư mục trước đó"
+
+msgid "E42: No Errors"
+msgstr "E42: Không có lỗi"
+
+msgid "E43: Damaged match string"
+msgstr "E43: Chuá»—i tÆ°Æ¡ng ứng bị há»ng"
+
+msgid "E44: Corrupted regexp program"
+msgstr "E44: ChÆ°Æ¡ng trình xá»­ lý biểu thức chính quy bị há»ng"
+
+msgid "E45: 'readonly' option is set (add ! to override)"
+msgstr "E45: Tùy chá»n 'readonly' được bật (Hãy thêm ! để lá» Ä‘i)"
+
+#, c-format
+msgid "E46: Cannot set read-only variable \"%s\""
+msgstr "E46: Không thay đổi được biến chỉ Ä‘á»c \"%s\""
+
+msgid "E47: Error while reading errorfile"
+msgstr "E47: Lá»—i khi Ä‘á»c tập tin lá»—i"
+
+msgid "E48: Not allowed in sandbox"
+msgstr "E48: Không cho phép trong hộp cát (sandbox)"
+
+msgid "E523: Not allowed here"
+msgstr "E523: Không cho phép ở đây"
+
+msgid "E359: Screen mode setting not supported"
+msgstr "E359: Chế độ màn hình không được hỗ trợ"
+
+msgid "E49: Invalid scroll size"
+msgstr "E49: Kích thước thanh cuộn không cho phép"
+
+msgid "E91: 'shell' option is empty"
+msgstr "E91: Tùy chá»n 'shell' là má»™t chuá»—i rá»—ng"
+
+msgid "E255: Couldn't read in sign data!"
+msgstr "E255: Không Ä‘á»c được dữ liệu vá» ký tá»±!"
+
+msgid "E72: Close error on swap file"
+msgstr "E72: Lỗi đóng tập tin trao đổi (swap)"
+
+msgid "E73: tag stack empty"
+msgstr "E73: đống thẻ ghi rỗng"
+
+msgid "E74: Command too complex"
+msgstr "E74: Câu lệnh quá phức tạp"
+
+msgid "E75: Name too long"
+msgstr "E75: Tên quá dài"
+
+msgid "E76: Too many ["
+msgstr "E76: Quá nhiá»u ký tá»± ["
+
+msgid "E77: Too many file names"
+msgstr "E77: Quá nhiá»u tên tập tin"
+
+msgid "E488: Trailing characters"
+msgstr "E488: Ký tự thừa ở đuôi"
+
+msgid "E78: Unknown mark"
+msgstr "E78: Dấu hiệu không biết"
+
+msgid "E79: Cannot expand wildcards"
+msgstr "E79: Không thực hiện được phép thế theo wildcard"
+
+msgid "E591: 'winheight' cannot be smaller than 'winminheight'"
+msgstr "E591: giá trị của 'winheight' không thể nhỠhơn 'winminheight'"
+
+msgid "E592: 'winwidth' cannot be smaller than 'winminwidth'"
+msgstr "E592: giá trị của 'winwidth' không thể nhỠhơn 'winminwidth'"
+
+msgid "E80: Error while writing"
+msgstr "E80: Lá»—i khi ghi nhá»›"
+
+msgid "Zero count"
+msgstr "Giá trị của bộ đếm bằng 0"
+
+msgid "E81: Using <SID> not in a script context"
+msgstr "E81: Sử dụng <SID> ngoài phạm vi script"
+
+msgid "E449: Invalid expression received"
+msgstr "E449: Nhận được một biểu thức không cho phép"
+
+msgid "E463: Region is guarded, cannot modify"
+msgstr "E463: Không thể thay đổi vùng đã được bảo vệ"
diff --git a/src/po/zh_CN.UTF-8.po b/src/po/zh_CN.UTF-8.po
new file mode 100644
index 0000000..7c7d453
--- /dev/null
+++ b/src/po/zh_CN.UTF-8.po
@@ -0,0 +1,6140 @@
+# Chinese (simplified) Translation for Vim
+#
+# Do ":help uganda" in Vim to read copying and usage conditions.
+# Do ":help credits" in Vim to see a list of people who contributed.
+#
+# FIRST AUTHOR Wang Jun <junw@turbolinux.com.cn>
+#
+# TRANSLATORS
+# Edyfox <edyfox@gmail.com>
+# Yuheng Xie <elephant@linux.net.cn>
+#
+# Original translations.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Vim(Simplified Chinese)\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2006-04-21 15:16+0800\n"
+"PO-Revision-Date: 2006-04-21 14:00+0800\n"
+"Last-Translator: Yuheng Xie\n"
+"Language-Team: Simplified Chinese\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8-bit\n"
+
+msgid "E82: Cannot allocate any buffer, exiting..."
+msgstr "E82: 无法分é…任何缓冲区,退出程åº..."
+
+msgid "E83: Cannot allocate buffer, using other one..."
+msgstr "E83: 无法分é…缓冲区,使用å¦ä¸€ä¸ªç¼“冲区..."
+
+msgid "E515: No buffers were unloaded"
+msgstr "E515: 没有释放任何缓冲区"
+
+msgid "E516: No buffers were deleted"
+msgstr "E516: 没有删除任何缓冲区"
+
+msgid "E517: No buffers were wiped out"
+msgstr "E517: 没有清除任何缓冲区"
+
+msgid "1 buffer unloaded"
+msgstr "释放了 1 个缓冲区"
+
+#, c-format
+msgid "%d buffers unloaded"
+msgstr "释放了 %d 个缓冲区"
+
+msgid "1 buffer deleted"
+msgstr "删除了 1 个缓冲区"
+
+#, c-format
+msgid "%d buffers deleted"
+msgstr "删除了 %d 个缓冲区"
+
+msgid "1 buffer wiped out"
+msgstr "清除了 1 个缓冲区"
+
+#, c-format
+msgid "%d buffers wiped out"
+msgstr "清除了 %d 个缓冲区"
+
+msgid "E84: No modified buffer found"
+msgstr "E84: 没有修改过的缓冲区"
+
+#. back where we started, didn't find anything.
+msgid "E85: There is no listed buffer"
+msgstr "E85: 没有å¯åˆ—出的缓冲区"
+
+#, c-format
+msgid "E86: Buffer %ld does not exist"
+msgstr "E86: 缓冲区 %ld ä¸å­˜åœ¨"
+
+msgid "E87: Cannot go beyond last buffer"
+msgstr "E87: 无法切æ¢ï¼Œå·²æ˜¯æœ€åŽä¸€ä¸ªç¼“冲区"
+
+msgid "E88: Cannot go before first buffer"
+msgstr "E88: 无法切æ¢ï¼Œå·²æ˜¯ç¬¬ä¸€ä¸ªç¼“冲区"
+
+#, c-format
+msgid "E89: No write since last change for buffer %ld (add ! to override)"
+msgstr "E89: 缓冲区 %ld 已修改但尚未ä¿å­˜ (请加 ! 强制执行)"
+
+msgid "E90: Cannot unload last buffer"
+msgstr "E90: 无法释放最åŽä¸€ä¸ªç¼“冲区"
+
+msgid "W14: Warning: List of file names overflow"
+msgstr "W14: 警告: 文件å过多"
+
+#, c-format
+msgid "E92: Buffer %ld not found"
+msgstr "E92: 找ä¸åˆ°ç¼“冲区 %ld"
+
+#, c-format
+msgid "E93: More than one match for %s"
+msgstr "E93: 找到ä¸æ­¢ä¸€ä¸ª %s"
+
+#, c-format
+msgid "E94: No matching buffer for %s"
+msgstr "E94: 没有匹é…的缓冲区 %s"
+
+#, c-format
+msgid "line %ld"
+msgstr "第 %ld 行"
+
+msgid "E95: Buffer with this name already exists"
+msgstr "E95: 已有缓冲区使用该å称"
+
+msgid " [Modified]"
+msgstr " [已修改]"
+
+msgid "[Not edited]"
+msgstr "[未编辑]"
+
+msgid "[New file]"
+msgstr "[新文件]"
+
+msgid "[Read errors]"
+msgstr "[读错误]"
+
+msgid "[readonly]"
+msgstr "[åªè¯»]"
+
+#, c-format
+msgid "1 line --%d%%--"
+msgstr "1 行 --%d%%--"
+
+#, c-format
+msgid "%ld lines --%d%%--"
+msgstr "%ld 行 --%d%%--"
+
+#, c-format
+msgid "line %ld of %ld --%d%%-- col "
+msgstr "行 %ld / %ld --%d%%-- 列 "
+
+msgid "[No Name]"
+msgstr "[未命å]"
+
+#. must be a help buffer
+msgid "help"
+msgstr "帮助"
+
+msgid "[Help]"
+msgstr "[帮助]"
+
+msgid "[Preview]"
+msgstr "[预览]"
+
+msgid "All"
+msgstr "全部"
+
+msgid "Bot"
+msgstr "底端"
+
+msgid "Top"
+msgstr "顶端"
+
+#, c-format
+msgid ""
+"\n"
+"# Buffer list:\n"
+msgstr ""
+"\n"
+"# 缓冲区列表:\n"
+
+msgid "[Location List]"
+msgstr "[Location 列表]"
+
+msgid "[Quickfix List]"
+msgstr "[Quickfix 列表]"
+
+msgid ""
+"\n"
+"--- Signs ---"
+msgstr ""
+"\n"
+"--- Signs ---"
+
+#, c-format
+msgid "Signs for %s:"
+msgstr "%s çš„ Signs:"
+
+#, c-format
+msgid " line=%ld id=%d name=%s"
+msgstr " è¡Œ=%ld id=%d å称=%s"
+
+#, c-format
+msgid "E96: Can not diff more than %ld buffers"
+msgstr "E96: ä¸èƒ½æ¯”较(diff) %ld 个以上的缓冲区"
+
+msgid "E97: Cannot create diffs"
+msgstr "E97: 无法创建 diff"
+
+msgid "Patch file"
+msgstr "Patch 文件"
+
+msgid "E98: Cannot read diff output"
+msgstr "E98: æ— æ³•è¯»å– diff 的输出"
+
+msgid "E99: Current buffer is not in diff mode"
+msgstr "E99: 当å‰ç¼“冲区ä¸åœ¨ diff 模å¼"
+
+msgid "E100: No other buffer in diff mode"
+msgstr "E100: 没有其它处于 diff 模å¼çš„缓冲区"
+
+msgid "E101: More than two buffers in diff mode, don't know which one to use"
+msgstr "E101: 有两个以上的缓冲区处于 diff 模å¼ï¼Œä¸èƒ½å†³å®šç”¨å“ªä¸€ä¸ª"
+
+#, c-format
+msgid "E102: Can't find buffer \"%s\""
+msgstr "E102: 找ä¸åˆ°ç¼“冲区 \"%s\""
+
+#, c-format
+msgid "E103: Buffer \"%s\" is not in diff mode"
+msgstr "E103: 缓冲区 \"%s\" ä¸åœ¨ diff 模å¼"
+
+msgid "E787: Buffer changed unexpectedly"
+msgstr "E787: æ„外地改å˜äº†ç¼“冲区"
+
+msgid "E104: Escape not allowed in digraph"
+msgstr "E104: å¤åˆå­—符(digraph)中ä¸èƒ½ä½¿ç”¨ Escape"
+
+msgid "E544: Keymap file not found"
+msgstr "E544: 找ä¸åˆ° Keymap 文件"
+
+msgid "E105: Using :loadkeymap not in a sourced file"
+msgstr "E105: ä¸æ˜¯åœ¨è„šæœ¬æ–‡ä»¶ä¸­ä½¿ç”¨ :loadkeymap "
+
+msgid " Keyword completion (^N^P)"
+msgstr " 关键字补全 (^N^P)"
+
+#. ctrl_x_mode == 0, ^P/^N compl.
+msgid " ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+msgstr " ^X æ¨¡å¼ (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+
+msgid " Whole line completion (^L^N^P)"
+msgstr " 整行补全 (^L^N^P)"
+
+msgid " File name completion (^F^N^P)"
+msgstr " 文件å补全 (^F^N^P)"
+
+msgid " Tag completion (^]^N^P)"
+msgstr " Tag 补全 (^]^N^P)"
+
+msgid " Path pattern completion (^N^P)"
+msgstr " 头文件模å¼è¡¥å…¨ (^N^P)"
+
+msgid " Definition completion (^D^N^P)"
+msgstr " 定义补全 (^D^N^P)"
+
+msgid " Dictionary completion (^K^N^P)"
+msgstr " Dictionary 补全 (^K^N^P)"
+
+msgid " Thesaurus completion (^T^N^P)"
+msgstr " Thesaurus 补全 (^T^N^P)"
+
+msgid " Command-line completion (^V^N^P)"
+msgstr " 命令行补全 (^V^N^P)"
+
+msgid " User defined completion (^U^N^P)"
+msgstr " 用户自定义补全 (^U^N^P)"
+
+msgid " Omni completion (^O^N^P)"
+msgstr " 全能补全 (^O^N^P)"
+
+msgid " Spelling suggestion (s^N^P)"
+msgstr " 拼写建议 (s^N^P)"
+
+msgid " Keyword Local completion (^N^P)"
+msgstr " 关键字局部补全 (^N^P)"
+
+msgid "Hit end of paragraph"
+msgstr "已到段è½ç»“å°¾"
+
+msgid "'dictionary' option is empty"
+msgstr "选项 'dictionary' 为空"
+
+msgid "'thesaurus' option is empty"
+msgstr "选项 'thesaurus' 为空"
+
+#, c-format
+msgid "Scanning dictionary: %s"
+msgstr "正在扫æ dictionary: %s"
+
+msgid " (insert) Scroll (^E/^Y)"
+msgstr " (æ’å…¥) Scroll (^E/^Y)"
+
+msgid " (replace) Scroll (^E/^Y)"
+msgstr " (替æ¢) Scroll (^E/^Y)"
+
+#, c-format
+msgid "Scanning: %s"
+msgstr "正在扫æ: %s"
+
+#, c-format
+msgid "Scanning tags."
+msgstr "扫æ标签."
+
+msgid " Adding"
+msgstr " 增加"
+
+#. showmode might reset the internal line pointers, so it must
+#. * be called before line = ml_get(), or when this address is no
+#. * longer needed. -- Acevedo.
+#.
+msgid "-- Searching..."
+msgstr "-- 查找中..."
+
+msgid "Back at original"
+msgstr "回到起点"
+
+msgid "Word from other line"
+msgstr "å¦ä¸€è¡Œçš„è¯"
+
+msgid "The only match"
+msgstr "唯一匹é…"
+
+#, c-format
+msgid "match %d of %d"
+msgstr "åŒ¹é… %d / %d"
+
+#, c-format
+msgid "match %d"
+msgstr "åŒ¹é… %d"
+
+msgid "E18: Unexpected characters in :let"
+msgstr "E18: :let 中出现异常字符"
+
+#, c-format
+msgid "E684: list index out of range: %ld"
+msgstr "E684: List 索引超出范围: %ld"
+
+#, c-format
+msgid "E121: Undefined variable: %s"
+msgstr "E121: 未定义的å˜é‡: %s"
+
+msgid "E111: Missing ']'"
+msgstr "E111: 缺少 ']'"
+
+#, c-format
+msgid "E686: Argument of %s must be a List"
+msgstr "E686: %s çš„å‚数必须是 List"
+
+#, c-format
+msgid "E712: Argument of %s must be a List or Dictionary"
+msgstr "E712: %s çš„å‚数必须是 List 或者 Dictionary"
+
+msgid "E713: Cannot use empty key for Dictionary"
+msgstr "E713: Dictionary çš„é”®ä¸èƒ½ä¸ºç©º"
+
+msgid "E714: List required"
+msgstr "E714: éœ€è¦ List"
+
+msgid "E715: Dictionary required"
+msgstr "E715: éœ€è¦ Dictionary"
+
+#, c-format
+msgid "E118: Too many arguments for function: %s"
+msgstr "E118: 函数的å‚数过多: %s"
+
+#, c-format
+msgid "E716: Key not present in Dictionary: %s"
+msgstr "E716: Dictionary 中ä¸å­˜åœ¨é”®: %s"
+
+#, c-format
+msgid "E122: Function %s already exists, add ! to replace it"
+msgstr "E122: 函数 %s 已存在,请加 ! 强制替æ¢"
+
+msgid "E717: Dictionary entry already exists"
+msgstr "E717: Dictionary 项已存在"
+
+msgid "E718: Funcref required"
+msgstr "E718: éœ€è¦ Funcref"
+
+msgid "E719: Cannot use [:] with a Dictionary"
+msgstr "E719: ä¸èƒ½å¯¹ Dictionary 使用 [:]"
+
+#, c-format
+msgid "E734: Wrong variable type for %s="
+msgstr "E734: %s= çš„å˜é‡ç±»åž‹ä¸æ­£ç¡®"
+
+#, c-format
+msgid "E130: Unknown function: %s"
+msgstr "E130: 未知的函数: %s"
+
+#, c-format
+msgid "E461: Illegal variable name: %s"
+msgstr "E461: 无效的å˜é‡å: %s"
+
+msgid "E687: Less targets than List items"
+msgstr "E687: 目标比 List 项数少"
+
+msgid "E688: More targets than List items"
+msgstr "E688: 目标比 List 项数多"
+
+msgid "Double ; in list of variables"
+msgstr "å˜é‡åˆ—表中出现两个 ;"
+
+#, c-format
+msgid "E738: Can't list variables for %s"
+msgstr "E738: 无法列出 %s çš„å˜é‡"
+
+msgid "E689: Can only index a List or Dictionary"
+msgstr "E689: åªèƒ½ç´¢å¼• List 或 Dictionary"
+
+msgid "E708: [:] must come last"
+msgstr "E708: [:] 必须在最åŽ"
+
+msgid "E709: [:] requires a List value"
+msgstr "E709: [:] 需è¦ä¸€ä¸ª List 值"
+
+msgid "E710: List value has more items than target"
+msgstr "E710: List 值的项比目标多"
+
+msgid "E711: List value has not enough items"
+msgstr "E711: List 值没有足够多的项"
+
+msgid "E690: Missing \"in\" after :for"
+msgstr "E690: :for åŽç¼ºå°‘ \"in\""
+
+#, c-format
+msgid "E107: Missing parentheses: %s"
+msgstr "E107: 缺少括å·: %s"
+
+#, c-format
+msgid "E108: No such variable: \"%s\""
+msgstr "E108: æ— æ­¤å˜é‡: \"%s\""
+
+msgid "E743: variable nested too deep for (un)lock"
+msgstr "E743: (un)lock çš„å˜é‡åµŒå¥—过深"
+
+msgid "E109: Missing ':' after '?'"
+msgstr "E109: '?' åŽç¼ºå°‘ ':'"
+
+msgid "E691: Can only compare List with List"
+msgstr "E691: åªèƒ½æ¯”较 List å’Œ List"
+
+msgid "E692: Invalid operation for List"
+msgstr "E692: 对 List 无效的æ“作"
+
+msgid "E735: Can only compare Dictionary with Dictionary"
+msgstr "E735: åªèƒ½æ¯”较 Dictionary å’Œ Dictionary"
+
+msgid "E736: Invalid operation for Dictionary"
+msgstr "E736: 对 Dictionary 无效的æ“作"
+
+msgid "E693: Can only compare Funcref with Funcref"
+msgstr "E693: åªèƒ½æ¯”较 Funcref å’Œ Funcref"
+
+msgid "E694: Invalid operation for Funcrefs"
+msgstr "E694: 对 Funcrefs 无效的æ“作"
+
+msgid "E110: Missing ')'"
+msgstr "E110: 缺少 ')'"
+
+msgid "E695: Cannot index a Funcref"
+msgstr "E695: ä¸èƒ½ç´¢å¼•ä¸€ä¸ª Funcref"
+
+#, c-format
+msgid "E112: Option name missing: %s"
+msgstr "E112: 缺少选项å称: %s"
+
+#, c-format
+msgid "E113: Unknown option: %s"
+msgstr "E113: 未知的选项: %s"
+
+#, c-format
+msgid "E114: Missing quote: %s"
+msgstr "E114: 缺少引å·: %s"
+
+#, c-format
+msgid "E115: Missing quote: %s"
+msgstr "E115: 缺少引å·: %s"
+
+#, c-format
+msgid "E696: Missing comma in List: %s"
+msgstr "E696: List 中缺少逗å·: %s"
+
+#, c-format
+msgid "E697: Missing end of List ']': %s"
+msgstr "E697: List 缺少结æŸç¬¦ ']': %s"
+
+#, c-format
+msgid "E720: Missing colon in Dictionary: %s"
+msgstr "E720: Dictionary 中缺少冒å·: %s"
+
+#, c-format
+msgid "E721: Duplicate key in Dictionary: \"%s\""
+msgstr "E721: Dictionary 中出现é‡å¤çš„é”®: \"%s\""
+
+#, c-format
+msgid "E722: Missing comma in Dictionary: %s"
+msgstr "E722: Dictionary 中缺少逗å·: %s"
+
+#, c-format
+msgid "E723: Missing end of Dictionary '}': %s"
+msgstr "E723: Dictionary 缺少结æŸç¬¦ '}': %s"
+
+msgid "E724: variable nested too deep for displaying"
+msgstr "E724: å˜é‡åµŒå¥—过深无法显示"
+
+msgid "E699: Too many arguments"
+msgstr "E699: å‚数过多"
+
+msgid "E785: complete() can only be used in Insert mode"
+msgstr "E785: complete() åªèƒ½åœ¨æ’入模å¼ä¸­ä½¿ç”¨"
+
+#.
+#. * Yes this is ugly, I don't particularly like it either. But doing it
+#. * this way has the compelling advantage that translations need not to
+#. * be touched at all. See below what 'ok' and 'ync' are used for.
+#.
+msgid "&Ok"
+msgstr "确定(&O)"
+
+#, c-format
+msgid "E737: Key already exists: %s"
+msgstr "E737: 键已存在: %s"
+
+#, c-format
+msgid "+-%s%3ld lines: "
+msgstr "+-%s%3ld 行: "
+
+#, c-format
+msgid "E700: Unknown function: %s"
+msgstr "E700: 未知的函数: %s"
+
+msgid ""
+"&OK\n"
+"&Cancel"
+msgstr ""
+"确定(&O)\n"
+"å–消(&C)"
+
+msgid "called inputrestore() more often than inputsave()"
+msgstr "inputrestore() 的调用次数多于 inputsave()"
+
+msgid "E786: Range not allowed"
+msgstr "E786: ä¸å…许的范围"
+
+msgid "E701: Invalid type for len()"
+msgstr "E701: len() 的类型无效"
+
+msgid "E726: Stride is zero"
+msgstr "E726: 步长为零"
+
+msgid "E727: Start past end"
+msgstr "E727: 起始值在终止值åŽ"
+
+msgid "<empty>"
+msgstr "<空>"
+
+msgid "E240: No connection to Vim server"
+msgstr "E240: 没有到 Vim æœåŠ¡å™¨çš„连接"
+
+#, c-format
+msgid "E241: Unable to send to %s"
+msgstr "E241: 无法å‘é€åˆ° %s"
+
+msgid "E277: Unable to read a server reply"
+msgstr "E277: 无法读å–æœåŠ¡å™¨å“应"
+
+msgid "E655: Too many symbolic links (cycle?)"
+msgstr "E655: 符å·è¿žæŽ¥è¿‡å¤š(循环?)"
+
+msgid "E258: Unable to send to client"
+msgstr "E258: 无法å‘é€åˆ°å®¢æˆ·ç«¯"
+
+msgid "E702: Sort compare function failed"
+msgstr "E702: Sort 比较函数失败"
+
+msgid "(Invalid)"
+msgstr "(无效)"
+
+msgid "E677: Error writing temp file"
+msgstr "E677: 写临时文件出错"
+
+msgid "E703: Using a Funcref as a Number"
+msgstr "E703: 将 Funcref 作数字使用"
+
+msgid "E745: Using a List as a Number"
+msgstr "E745: 将 List 作数字使用"
+
+msgid "E728: Using a Dictionary as a Number"
+msgstr "E728: 将 Dictionary 作数字使用"
+
+msgid "E729: using Funcref as a String"
+msgstr "E729: 将 Funcref 作 String 使用"
+
+msgid "E730: using List as a String"
+msgstr "E730: 将 List 作 String 使用"
+
+msgid "E731: using Dictionary as a String"
+msgstr "E731: 将 Dictionary 作 String 使用"
+
+#, c-format
+msgid "E704: Funcref variable name must start with a capital: %s"
+msgstr "E704: Funcref å˜é‡å必须以大写字æ¯å¼€å¤´: %s"
+
+#, c-format
+msgid "E705: Variable name conflicts with existing function: %s"
+msgstr "E705: å˜é‡å与已有函数å冲çª: %s"
+
+#, c-format
+msgid "E706: Variable type mismatch for: %s"
+msgstr "E706: å˜é‡ç±»åž‹ä¸åŒ¹é…: %s"
+
+#, c-format
+msgid "E741: Value is locked: %s"
+msgstr "E741: 值已é”定: %s"
+
+msgid "Unknown"
+msgstr "未知"
+
+#, c-format
+msgid "E742: Cannot change value of %s"
+msgstr "E742: æ— æ³•æ”¹å˜ %s 的值"
+
+msgid "E698: variable nested too deep for making a copy"
+msgstr "E698: å˜é‡åµŒå¥—过深无法å¤åˆ¶"
+
+#, c-format
+msgid "E124: Missing '(': %s"
+msgstr "E124: 缺少 '(': %s"
+
+#, c-format
+msgid "E125: Illegal argument: %s"
+msgstr "E125: 无效的å‚æ•°: %s"
+
+msgid "E126: Missing :endfunction"
+msgstr "E126: 缺少 :endfunction"
+
+#, c-format
+msgid "E746: Function name does not match script file name: %s"
+msgstr "E746: 函数å与脚本文件åä¸åŒ¹é…: %s"
+
+msgid "E129: Function name required"
+msgstr "E129: 需è¦å‡½æ•°å"
+
+#, c-format
+msgid "E128: Function name must start with a capital or contain a colon: %s"
+msgstr "E128: 函数å必须以大写字æ¯å¼€å¤´æˆ–者包å«å†’å·: %s"
+
+#, c-format
+msgid "E131: Cannot delete function %s: It is in use"
+msgstr "E131: 无法删除函数 %s: 正在使用中"
+
+msgid "E132: Function call depth is higher than 'maxfuncdepth'"
+msgstr "E132: 函数调用深度超出 'maxfuncdepth'"
+
+#, c-format
+msgid "calling %s"
+msgstr "调用 %s"
+
+#, c-format
+msgid "%s aborted"
+msgstr "%s 已中止"
+
+#, c-format
+msgid "%s returning #%ld"
+msgstr "%s 返回 #%ld "
+
+#, c-format
+msgid "%s returning %s"
+msgstr "%s 返回 %s"
+
+#, c-format
+msgid "continuing in %s"
+msgstr "在 %s 中继续"
+
+msgid "E133: :return not inside a function"
+msgstr "E133: :return ä¸åœ¨å‡½æ•°ä¸­"
+
+#, c-format
+msgid ""
+"\n"
+"# global variables:\n"
+msgstr ""
+"\n"
+"# 全局å˜é‡:\n"
+
+msgid ""
+"\n"
+"\tLast set from "
+msgstr ""
+"\n"
+"\t最近修改于 "
+
+#, c-format
+msgid "<%s>%s%s %d, Hex %02x, Octal %03o"
+msgstr "<%s>%s%s %d, å六进制 %02x, 八进制 %03o"
+
+#, c-format
+msgid "> %d, Hex %04x, Octal %o"
+msgstr "> %d, å六进制 %04x, 八进制 %o"
+
+#, c-format
+msgid "> %d, Hex %08x, Octal %o"
+msgstr "> %d, å六进制 %08x, 八进制 %o"
+
+msgid "E134: Move lines into themselves"
+msgstr "E134: 把行移动到自已中"
+
+msgid "1 line moved"
+msgstr "移动了 1 行"
+
+#, c-format
+msgid "%ld lines moved"
+msgstr "移动了 %ld 行"
+
+#, c-format
+msgid "%ld lines filtered"
+msgstr "过滤了 %ld 行"
+
+msgid "E135: *Filter* Autocommands must not change current buffer"
+msgstr "E135: *Filter* 自动命令ä¸å¯ä»¥æ”¹å˜å½“å‰ç¼“冲区"
+
+msgid "[No write since last change]\n"
+msgstr "[已修改但尚未ä¿å­˜]\n"
+
+# bad to translate
+#, c-format
+msgid "%sviminfo: %s in line: "
+msgstr "%sviminfo: %s ä½äºŽè¡Œ: "
+
+msgid "E136: viminfo: Too many errors, skipping rest of file"
+msgstr "E136: viminfo: 错误过多,忽略文件的剩余部分"
+
+#, c-format
+msgid "Reading viminfo file \"%s\"%s%s%s"
+msgstr "è¯»å– viminfo 文件 \"%s\"%s%s%s"
+
+msgid " info"
+msgstr " ä¿¡æ¯"
+
+msgid " marks"
+msgstr " 标记"
+
+msgid " FAILED"
+msgstr " 失败"
+
+#, c-format
+msgid "E137: Viminfo file is not writable: %s"
+msgstr "E137: Viminfo 文件ä¸å¯å†™å…¥: %s"
+
+#, c-format
+msgid "E138: Can't write viminfo file %s!"
+msgstr "E138: 无法写入 viminfo 文件 %sï¼"
+
+#, c-format
+msgid "Writing viminfo file \"%s\""
+msgstr "写入 viminfo 文件 \"%s\""
+
+# do not translate to avoid writing Chinese in files
+#. Write the info:
+#, fuzzy, c-format
+#~ msgid "# This viminfo file was generated by Vim %s.\n"
+#~ msgstr "# 这个 viminfo 文件是由 Vim %s 生æˆçš„。\n"
+
+# do not translate to avoid writing Chinese in files
+#, fuzzy, c-format
+msgid ""
+"# You may edit it if you're careful!\n"
+"\n"
+msgstr ""
+"# 如果è¦è‡ªè¡Œä¿®æ”¹è¯·ç‰¹åˆ«å°å¿ƒï¼\n"
+"\n"
+
+# do not translate to avoid writing Chinese in files
+#, fuzzy, c-format
+#~ msgid "# Value of 'encoding' when this file was written\n"
+#~ msgstr "# 'encoding' 在此文件建立时的值\n"
+
+msgid "Illegal starting char"
+msgstr "无效的å¯åŠ¨å­—符"
+
+msgid "Save As"
+msgstr "å¦å­˜ä¸º"
+
+msgid "Write partial file?"
+msgstr "è¦å†™å…¥éƒ¨åˆ†æ–‡ä»¶å—?"
+
+msgid "E140: Use ! to write partial buffer"
+msgstr "E140: 请使用 ! æ¥å†™å…¥éƒ¨åˆ†ç¼“冲区"
+
+#, c-format
+msgid "Overwrite existing file \"%s\"?"
+msgstr "覆盖已存在的文件 \"%s\" å—?"
+
+#, c-format
+msgid "Swap file \"%s\" exists, overwrite anyway?"
+msgstr "交æ¢æ–‡ä»¶ \"%s\" 已存在,确实è¦è¦†ç›–å—?"
+
+#, c-format
+msgid "E768: Swap file exists: %s (:silent! overrides)"
+msgstr "E768: 交æ¢æ–‡ä»¶å·²å­˜åœ¨: %s (:silent! 强制执行)"
+
+#, c-format
+msgid "E141: No file name for buffer %ld"
+msgstr "E141: 缓冲区 %ld 没有文件å"
+
+msgid "E142: File not written: Writing is disabled by 'write' option"
+msgstr "E142: 文件未写入: 写入被 'write' 选项ç¦ç”¨"
+
+#, c-format
+msgid ""
+"'readonly' option is set for \"%s\".\n"
+"Do you wish to write anyway?"
+msgstr ""
+"\"%s\" 已设定 'readonly' 选项。\n"
+"确实è¦è¦†ç›–å—?"
+
+msgid "Edit File"
+msgstr "编辑文件"
+
+#, c-format
+msgid "E143: Autocommands unexpectedly deleted new buffer %s"
+msgstr "E143: 自动命令æ„外地删除了新缓冲区 %s"
+
+msgid "E144: non-numeric argument to :z"
+msgstr "E144: :z ä¸æŽ¥å—éžæ•°å­—çš„å‚æ•°"
+
+msgid "E145: Shell commands not allowed in rvim"
+msgstr "E145: rvim 中ç¦æ­¢ä½¿ç”¨ shell 命令"
+
+msgid "E146: Regular expressions can't be delimited by letters"
+msgstr "E146: 正则表达å¼ä¸èƒ½ç”¨å­—æ¯ä½œåˆ†ç•Œ"
+
+#, c-format
+msgid "replace with %s (y/n/a/q/l/^E/^Y)?"
+msgstr "替æ¢ä¸º %s (y/n/a/q/l/^E/^Y)?"
+
+msgid "(Interrupted) "
+msgstr "(已中断) "
+
+msgid "1 match"
+msgstr "1 个匹é…,"
+
+msgid "1 substitution"
+msgstr "1 次替æ¢ï¼Œ"
+
+#, c-format
+msgid "%ld matches"
+msgstr "%ld 个匹é…,"
+
+#, c-format
+msgid "%ld substitutions"
+msgstr "%ld 次替æ¢ï¼Œ"
+
+msgid " on 1 line"
+msgstr "共 1 行"
+
+#, c-format
+msgid " on %ld lines"
+msgstr "共 %ld 行"
+
+msgid "E147: Cannot do :global recursive"
+msgstr "E147: :global ä¸èƒ½é€’归执行"
+
+msgid "E148: Regular expression missing from global"
+msgstr "E148: global 缺少正则表达å¼"
+
+#, c-format
+msgid "Pattern found in every line: %s"
+msgstr "æ¯è¡Œéƒ½åŒ¹é…表达å¼: %s"
+
+# do not translate to avoid writing Chinese in files
+#, fuzzy, c-format
+msgid ""
+"\n"
+"# Last Substitute String:\n"
+"$"
+msgstr ""
+"\n"
+"# 最近的替æ¢å­—符串:\n"
+"$"
+
+msgid "E478: Don't panic!"
+msgstr "E478: ä¸è¦æ…Œï¼"
+
+#, c-format
+msgid "E661: Sorry, no '%s' help for %s"
+msgstr "E661: 抱歉,没有 '%s' 的 %s 的说明"
+
+#, c-format
+msgid "E149: Sorry, no help for %s"
+msgstr "E149: 抱歉,没有 %s 的说明"
+
+#, c-format
+msgid "Sorry, help file \"%s\" not found"
+msgstr "抱歉,找ä¸åˆ°å¸®åŠ©æ–‡ä»¶ \"%s\""
+
+#, c-format
+msgid "E150: Not a directory: %s"
+msgstr "E150: ä¸æ˜¯ç›®å½•: %s"
+
+#, c-format
+msgid "E152: Cannot open %s for writing"
+msgstr "E152: 无法打开并写入 %s"
+
+#, c-format
+msgid "E153: Unable to open %s for reading"
+msgstr "E153: æ— æ³•æ‰“å¼€å¹¶è¯»å– %s"
+
+#, c-format
+msgid "E670: Mix of help file encodings within a language: %s"
+msgstr "E670: 在一ç§è¯­è¨€ä¸­æ··åˆäº†å¤šç§å¸®åŠ©æ–‡ä»¶ç¼–ç : %s"
+
+#, c-format
+msgid "E154: Duplicate tag \"%s\" in file %s/%s"
+msgstr "E154: Tag \"%s\" 在文件 %s/%s 中é‡å¤å‡ºçŽ°"
+
+#, c-format
+msgid "E160: Unknown sign command: %s"
+msgstr "E160: 未知的 sign 命令: %s"
+
+msgid "E156: Missing sign name"
+msgstr "E156: 缺少 sign å称"
+
+msgid "E612: Too many signs defined"
+msgstr "E612: Signs 定义过多"
+
+#, c-format
+msgid "E239: Invalid sign text: %s"
+msgstr "E239: 无效的 sign 文字: %s"
+
+#, c-format
+msgid "E155: Unknown sign: %s"
+msgstr "E155: 未知的 sign: %s"
+
+msgid "E159: Missing sign number"
+msgstr "E159: 缺少 sign å·"
+
+#, c-format
+msgid "E158: Invalid buffer name: %s"
+msgstr "E158: 无效的缓冲区å: %s"
+
+#, c-format
+msgid "E157: Invalid sign ID: %ld"
+msgstr "E157: 无效的 sign ID: %ld"
+
+msgid " (NOT FOUND)"
+msgstr " (找ä¸åˆ°)"
+
+msgid " (not supported)"
+msgstr " (ä¸æ”¯æŒ)"
+
+msgid "[Deleted]"
+msgstr "[已删除]"
+
+msgid "Entering Debug mode. Type \"cont\" to continue."
+msgstr "进入调试模å¼ã€‚输入 \"cont\" 继续è¿è¡Œã€‚"
+
+#, c-format
+msgid "line %ld: %s"
+msgstr "第 %ld 行: %s"
+
+#, c-format
+msgid "cmd: %s"
+msgstr "命令: %s"
+
+#, c-format
+msgid "Breakpoint in \"%s%s\" line %ld"
+msgstr "断点 \"%s%s\" 第 %ld 行"
+
+#, c-format
+msgid "E161: Breakpoint not found: %s"
+msgstr "E161: 找ä¸åˆ°æ–­ç‚¹: %s"
+
+msgid "No breakpoints defined"
+msgstr "没有定义断点"
+
+#, c-format
+msgid "%3d %s %s line %ld"
+msgstr "%3d %s %s 第 %ld 行"
+
+msgid "E750: First use :profile start <fname>"
+msgstr "E750: 请先使用 :profile start <fname>"
+
+#, c-format
+msgid "Save changes to \"%s\"?"
+msgstr "将改å˜ä¿å­˜åˆ° \"%s\" å—?"
+
+msgid "Untitled"
+msgstr "未命å"
+
+#, c-format
+msgid "E162: No write since last change for buffer \"%s\""
+msgstr "E162: 缓冲区 \"%s\" 已修改但尚未ä¿å­˜"
+
+msgid "Warning: Entered other buffer unexpectedly (check autocommands)"
+msgstr "警告: æ„外地进入了其它缓冲区 (请检查自动命令)"
+
+msgid "E163: There is only one file to edit"
+msgstr "E163: åªæœ‰ä¸€ä¸ªæ–‡ä»¶å¯ç¼–辑"
+
+msgid "E164: Cannot go before first file"
+msgstr "E164: 无法切æ¢ï¼Œå·²æ˜¯ç¬¬ä¸€ä¸ªæ–‡ä»¶"
+
+msgid "E165: Cannot go beyond last file"
+msgstr "E165: 无法切æ¢ï¼Œå·²æ˜¯æœ€åŽä¸€ä¸ªæ–‡ä»¶"
+
+#, c-format
+msgid "E666: compiler not supported: %s"
+msgstr "E666: ä¸æ”¯æŒç¼–译器: %s"
+
+#, c-format
+msgid "Searching for \"%s\" in \"%s\""
+msgstr "正在查找 \"%s\",在 \"%s\" 中"
+
+#, c-format
+msgid "Searching for \"%s\""
+msgstr "正在查找 \"%s\""
+
+#, c-format
+msgid "not found in 'runtimepath': \"%s\""
+msgstr "在 'runtimepath' 中找ä¸åˆ° \"%s\""
+
+msgid "Source Vim script"
+msgstr "执行 Vim 脚本"
+
+#, c-format
+msgid "Cannot source a directory: \"%s\""
+msgstr "ä¸èƒ½æ‰§è¡Œç›®å½•: \"%s\""
+
+#, c-format
+msgid "could not source \"%s\""
+msgstr "ä¸èƒ½æ‰§è¡Œ \"%s\""
+
+#, c-format
+msgid "line %ld: could not source \"%s\""
+msgstr "第 %ld è¡Œ: ä¸èƒ½æ‰§è¡Œ \"%s\""
+
+#, c-format
+msgid "sourcing \"%s\""
+msgstr "执行 \"%s\""
+
+#, c-format
+msgid "line %ld: sourcing \"%s\""
+msgstr "第 %ld 行: 执行 \"%s\""
+
+#, c-format
+msgid "finished sourcing %s"
+msgstr "结æŸæ‰§è¡Œ %s"
+
+msgid "modeline"
+msgstr "modeline"
+
+msgid "--cmd argument"
+msgstr "--cmd å‚æ•°"
+
+msgid "-c argument"
+msgstr "-c å‚æ•°"
+
+msgid "environment variable"
+msgstr "环境å˜é‡"
+
+#~ msgid "error handler"
+#~ msgstr ""
+
+msgid "W15: Warning: Wrong line separator, ^M may be missing"
+msgstr "W15: 警告: 错误的行分隔符,å¯èƒ½æ˜¯å°‘了 ^M"
+
+msgid "E167: :scriptencoding used outside of a sourced file"
+msgstr "E167: 在脚本文件外使用了 :scriptencoding"
+
+msgid "E168: :finish used outside of a sourced file"
+msgstr "E168: 在脚本文件外使用了 :finish"
+
+#, c-format
+msgid "Current %slanguage: \"%s\""
+msgstr "当å‰çš„ %s语言: \"%s\""
+
+#, c-format
+msgid "E197: Cannot set language to \"%s\""
+msgstr "E197: ä¸èƒ½è®¾å®šè¯­è¨€ä¸º \"%s\""
+
+msgid "Entering Ex mode. Type \"visual\" to go to Normal mode."
+msgstr "进入 Ex 模å¼ã€‚输入 \"visual\" 回到正常模å¼ã€‚"
+
+msgid "E501: At end-of-file"
+msgstr "E501: 已到文件末尾"
+
+msgid "E169: Command too recursive"
+msgstr "E169: 命令递归层数过多"
+
+#, c-format
+msgid "E605: Exception not caught: %s"
+msgstr "E605: 异常没有被æ•èŽ·: %s"
+
+msgid "End of sourced file"
+msgstr "脚本文件结æŸ"
+
+msgid "End of function"
+msgstr "函数结æŸ"
+
+msgid "E464: Ambiguous use of user-defined command"
+msgstr "E464: ä¸ç¡®å®šçš„用户自定义命令"
+
+msgid "E492: Not an editor command"
+msgstr "E492: ä¸æ˜¯ç¼–辑器的命令"
+
+msgid "E493: Backwards range given"
+msgstr "E493: 使用了逆å‘的范围"
+
+msgid "Backwards range given, OK to swap"
+msgstr "使用了逆å‘的范围,确定交æ¢å—"
+
+msgid "E494: Use w or w>>"
+msgstr "E494: 请使用 w 或 w>>"
+
+msgid "E319: Sorry, the command is not available in this version"
+msgstr "E319: 抱歉,命令在此版本中ä¸å¯ç”¨"
+
+msgid "E172: Only one file name allowed"
+msgstr "E172: åªå…许一个文件å"
+
+msgid "1 more file to edit. Quit anyway?"
+msgstr "还有 1 个文件未编辑。确实è¦é€€å‡ºå—?"
+
+#, c-format
+msgid "%d more files to edit. Quit anyway?"
+msgstr "还有 %d 个文件未编辑。确实è¦é€€å‡ºå—?"
+
+msgid "E173: 1 more file to edit"
+msgstr "E173: 还有 1 个文件未编辑"
+
+#, c-format
+msgid "E173: %ld more files to edit"
+msgstr "E173: 还有 %ld 个文件未编辑"
+
+msgid "E174: Command already exists: add ! to replace it"
+msgstr "E174: 命令已存在: 请加 ! 强制替æ¢"
+
+msgid ""
+"\n"
+" Name Args Range Complete Definition"
+msgstr ""
+"\n"
+" å称 å‚æ•° 范围 补全 定义 "
+
+msgid "No user-defined commands found"
+msgstr "找ä¸åˆ°ç”¨æˆ·è‡ªå®šä¹‰å‘½ä»¤"
+
+msgid "E175: No attribute specified"
+msgstr "E175: 没有指定属性"
+
+msgid "E176: Invalid number of arguments"
+msgstr "E176: 无效的å‚数个数"
+
+msgid "E177: Count cannot be specified twice"
+msgstr "E177: ä¸èƒ½æŒ‡å®šä¸¤æ¬¡è®¡æ•°"
+
+msgid "E178: Invalid default value for count"
+msgstr "E178: 无效的计数默认值"
+
+msgid "E179: argument required for -complete"
+msgstr "E179: -complete 需è¦å‚æ•°"
+
+#, c-format
+msgid "E181: Invalid attribute: %s"
+msgstr "E181: 无效的属性: %s"
+
+msgid "E182: Invalid command name"
+msgstr "E182: 无效的命令å"
+
+msgid "E183: User defined commands must start with an uppercase letter"
+msgstr "E183: 用户自定义命令必须以大写字æ¯å¼€å¤´"
+
+#, c-format
+msgid "E184: No such user-defined command: %s"
+msgstr "E184: 没有这个用户自定义命令: %s"
+
+#, c-format
+msgid "E180: Invalid complete value: %s"
+msgstr "E180: 无效的补全类型: %s"
+
+msgid "E468: Completion argument only allowed for custom completion"
+msgstr "E468: åªæœ‰ custom 补全æ‰å…许å‚æ•°"
+
+msgid "E467: Custom completion requires a function argument"
+msgstr "E467: Custom 补全需è¦ä¸€ä¸ªå‡½æ•°å‚æ•°"
+
+#, c-format
+msgid "E185: Cannot find color scheme %s"
+msgstr "E185: 找ä¸åˆ°é…色方案 %s"
+
+msgid "Greetings, Vim user!"
+msgstr "您好,Vim 用户ï¼"
+
+msgid "E784: Cannot close last tab page"
+msgstr "E784: ä¸èƒ½å…³é—­æœ€åŽä¸€ä¸ª tab 页"
+
+msgid "Already only one tab page"
+msgstr "å·²ç»åªå‰©ä¸€ä¸ª tab 页了"
+
+msgid "Edit File in new window"
+msgstr "在新窗å£ç¼–辑文件"
+
+#, c-format
+msgid "Tab page %d"
+msgstr "Tab 页 %d"
+
+msgid "No swap file"
+msgstr "无交æ¢æ–‡ä»¶"
+
+msgid "Append File"
+msgstr "追加文件"
+
+msgid "E747: Cannot change directory, buffer is modified (add ! to override)"
+msgstr "E747: ä¸èƒ½æ”¹å˜ç›®å½•ï¼Œç¼“冲区已修改 (请加 ! 强制执行)"
+
+msgid "E186: No previous directory"
+msgstr "E186: å‰ä¸€ä¸ªç›®å½•ä¸å­˜åœ¨"
+
+msgid "E187: Unknown"
+msgstr "E187: 未知"
+
+msgid "E465: :winsize requires two number arguments"
+msgstr "E465: :winsize 需è¦ä¸¤ä¸ªæ•°å­—å‚æ•°"
+
+#, c-format
+msgid "Window position: X %d, Y %d"
+msgstr "窗å£ä½ç½®: X %d, Y %d"
+
+msgid "E188: Obtaining window position not implemented for this platform"
+msgstr "E188: 在此平å°ä¸Šä¸èƒ½èŽ·å¾—窗å£ä½ç½®"
+
+msgid "E466: :winpos requires two number arguments"
+msgstr "E466: :winpos 需è¦ä¸¤ä¸ªæ•°å­—å‚æ•°"
+
+msgid "Save Redirection"
+msgstr "ä¿å­˜é‡å®šå‘"
+
+msgid "Save View"
+msgstr "ä¿å­˜è§†å›¾"
+
+msgid "Save Session"
+msgstr "ä¿å­˜ä¼šè¯"
+
+msgid "Save Setup"
+msgstr "ä¿å­˜è®¾å®š"
+
+#, c-format
+msgid "E739: Cannot create directory: %s"
+msgstr "E739: 无法创建目录: %s"
+
+#, c-format
+msgid "E189: \"%s\" exists (add ! to override)"
+msgstr "E189: \"%s\" 已存在 (请加 ! 强制执行)"
+
+#, c-format
+msgid "E190: Cannot open \"%s\" for writing"
+msgstr "E190: 无法打开并写入 \"%s\""
+
+#. set mark
+msgid "E191: Argument must be a letter or forward/backward quote"
+msgstr "E191: å‚数必须是一个字æ¯æˆ–者正/å引å·"
+
+msgid "E192: Recursive use of :normal too deep"
+msgstr "E192: :normal 递归层数过深"
+
+msgid "E194: No alternate file name to substitute for '#'"
+msgstr "E194: æ²¡æœ‰ç”¨äºŽæ›¿æ¢ '#' 的交替文件å"
+
+msgid "E495: no autocommand file name to substitute for \"<afile>\""
+msgstr "E495: æ²¡æœ‰ç”¨äºŽæ›¿æ¢ \"<afile>\" 的自动命令文件å"
+
+msgid "E496: no autocommand buffer number to substitute for \"<abuf>\""
+msgstr "E496: æ²¡æœ‰ç”¨äºŽæ›¿æ¢ \"<abuf>\" 的自动命令缓冲区å·"
+
+msgid "E497: no autocommand match name to substitute for \"<amatch>\""
+msgstr "E497: æ²¡æœ‰ç”¨äºŽæ›¿æ¢ \"<amatch>\" 的自动命令匹é…å"
+
+msgid "E498: no :source file name to substitute for \"<sfile>\""
+msgstr "E498: æ²¡æœ‰ç”¨äºŽæ›¿æ¢ \"<sfile>\" çš„ :source 文件å"
+
+#, no-c-format
+msgid "E499: Empty file name for '%' or '#', only works with \":p:h\""
+msgstr "E499: '%' 或 '#' 为空文件å,åªèƒ½ç”¨äºŽ \":p:h\""
+
+msgid "E500: Evaluates to an empty string"
+msgstr "E500: 结果为空字符串"
+
+msgid "E195: Cannot open viminfo file for reading"
+msgstr "E195: æ— æ³•æ‰“å¼€å¹¶è¯»å– viminfo 文件"
+
+msgid "E196: No digraphs in this version"
+msgstr "E196: 此版本无å¤åˆå­—符(digraph)"
+
+msgid "E608: Cannot :throw exceptions with 'Vim' prefix"
+msgstr "E608: ä¸èƒ½ :throw å‰ç¼€ä¸º 'Vim' 的异常"
+
+#. always scroll up, don't overwrite
+#, c-format
+msgid "Exception thrown: %s"
+msgstr "抛出异常: %s"
+
+#, c-format
+msgid "Exception finished: %s"
+msgstr "完æˆå¼‚常: %s"
+
+#, c-format
+msgid "Exception discarded: %s"
+msgstr "丢弃异常: %s"
+
+#, c-format
+msgid "%s, line %ld"
+msgstr "%s,第 %ld 行"
+
+#. always scroll up, don't overwrite
+#, c-format
+msgid "Exception caught: %s"
+msgstr "æ•èŽ·å¼‚常: %s"
+
+#, c-format
+#~ msgid "%s made pending"
+#~ msgstr ""
+
+#, fuzzy, c-format
+#~ msgid "%s resumed"
+#~ msgstr " 已返回\n"
+
+#, c-format
+#~ msgid "%s discarded"
+#~ msgstr ""
+
+msgid "Exception"
+msgstr "异常"
+
+msgid "Error and interrupt"
+msgstr "错误和中断"
+
+msgid "Error"
+msgstr "错误"
+
+#. if (pending & CSTP_INTERRUPT)
+msgid "Interrupt"
+msgstr "中断"
+
+msgid "E579: :if nesting too deep"
+msgstr "E579: :if 嵌套层数过深"
+
+msgid "E580: :endif without :if"
+msgstr "E580: :endif 缺少对应的 :if"
+
+msgid "E581: :else without :if"
+msgstr "E581: :else 缺少对应的 :if"
+
+msgid "E582: :elseif without :if"
+msgstr "E582: :elseif 缺少对应的 :if"
+
+msgid "E583: multiple :else"
+msgstr "E583: 多个 :else"
+
+msgid "E584: :elseif after :else"
+msgstr "E584: :elseif 在 :else åŽé¢"
+
+msgid "E585: :while/:for nesting too deep"
+msgstr "E585: :while/:for 嵌套层数过深"
+
+msgid "E586: :continue without :while or :for"
+msgstr "E586: :continue 缺少对应的 :while 或 :for"
+
+msgid "E587: :break without :while or :for"
+msgstr "E587: :break 缺少对应的 :while 或 :for"
+
+msgid "E732: Using :endfor with :while"
+msgstr "E732: :while 以 :endfor 结尾"
+
+msgid "E733: Using :endwhile with :for"
+msgstr "E733: :for 以 :endwhile 结尾"
+
+msgid "E601: :try nesting too deep"
+msgstr "E601: :try 嵌套层数过深"
+
+msgid "E603: :catch without :try"
+msgstr "E603: :catch 缺少对应的 :try"
+
+#. Give up for a ":catch" after ":finally" and ignore it.
+#. * Just parse.
+msgid "E604: :catch after :finally"
+msgstr "E604: :catch 在 :finally åŽé¢"
+
+msgid "E606: :finally without :try"
+msgstr "E606: :finally 缺少对应的 :try"
+
+#. Give up for a multiple ":finally" and ignore it.
+msgid "E607: multiple :finally"
+msgstr "E607: 多个 :finally"
+
+msgid "E602: :endtry without :try"
+msgstr "E602: :endtry 缺少对应的 :try"
+
+msgid "E193: :endfunction not inside a function"
+msgstr "E193: :endfunction ä¸åœ¨å‡½æ•°å†…"
+
+msgid "E788: Not allowed to edit another buffer now"
+msgstr "E788: ç›®å‰ä¸å…许编辑别的缓冲区"
+
+msgid "tagname"
+msgstr "tag å"
+
+msgid " kind file\n"
+msgstr " 类型 文件\n"
+
+msgid "'history' option is zero"
+msgstr "选项 'history' 为零"
+
+# do not translate to avoid writing Chinese in files
+#, fuzzy, c-format
+msgid ""
+"\n"
+"# %s History (newest to oldest):\n"
+msgstr ""
+"\n"
+"# %s 历å²è®°å½• (从新到旧):\n"
+
+# do not translate to avoid writing Chinese in files
+#, fuzzy
+#~ msgid "Command Line"
+#~ msgstr "命令行"
+
+# do not translate to avoid writing Chinese in files
+#, fuzzy
+#~ msgid "Search String"
+#~ msgstr "查找字符串"
+
+# do not translate to avoid writing Chinese in files
+#, fuzzy
+#~ msgid "Expression"
+#~ msgstr "表达å¼"
+
+# do not translate to avoid writing Chinese in files
+#, fuzzy
+#~ msgid "Input Line"
+#~ msgstr "输入行"
+
+msgid "E198: cmd_pchar beyond the command length"
+msgstr "E198: cmd_pchar 超过命令长度"
+
+msgid "E199: Active window or buffer deleted"
+msgstr "E199: 活动窗å£æˆ–缓冲区已被删除"
+
+msgid "Illegal file name"
+msgstr "无效的文件å"
+
+msgid "is a directory"
+msgstr "是目录"
+
+msgid "is not a file"
+msgstr "ä¸æ˜¯æ–‡ä»¶"
+
+msgid "[New File]"
+msgstr "[新文件]"
+
+msgid "[New DIRECTORY]"
+msgstr "[新目录]"
+
+msgid "[File too big]"
+msgstr "[文件过大]"
+
+msgid "[Permission Denied]"
+msgstr "[æƒé™ä¸è¶³]"
+
+msgid "E200: *ReadPre autocommands made the file unreadable"
+msgstr "E200: *ReadPre 自动命令导致文件ä¸å¯è¯»"
+
+msgid "E201: *ReadPre autocommands must not change current buffer"
+msgstr "E201: *ReadPre 自动命令ä¸å…许改å˜å½“å‰ç¼“冲区"
+
+msgid "Vim: Reading from stdin...\n"
+msgstr "Vim: 从标准输入读å–...\n"
+
+msgid "Reading from stdin..."
+msgstr "从标准输入读å–..."
+
+#. Re-opening the original file failed!
+msgid "E202: Conversion made file unreadable!"
+msgstr "E202: 转æ¢å¯¼è‡´æ–‡ä»¶ä¸å¯è¯»"
+
+msgid "[fifo/socket]"
+msgstr "[fifo/socket]"
+
+msgid "[fifo]"
+msgstr "[fifo]"
+
+msgid "[socket]"
+msgstr "[socket]"
+
+msgid "[RO]"
+msgstr "[åªè¯»]"
+
+msgid "[CR missing]"
+msgstr "[缺少 CR]'"
+
+msgid "[NL found]"
+msgstr "[找到 NL]"
+
+msgid "[long lines split]"
+msgstr "[长行分割]"
+
+msgid "[NOT converted]"
+msgstr "[未转æ¢]"
+
+msgid "[converted]"
+msgstr "[已转æ¢]"
+
+msgid "[crypted]"
+msgstr "[已加密]"
+
+#, c-format
+msgid "[CONVERSION ERROR in line %ld]"
+msgstr "[第 %ld 行转æ¢é”™è¯¯]"
+
+#, c-format
+msgid "[ILLEGAL BYTE in line %ld]"
+msgstr "[第 %ld 行无效字符]"
+
+msgid "[READ ERRORS]"
+msgstr "[读错误]"
+
+msgid "Can't find temp file for conversion"
+msgstr "找ä¸åˆ°ç”¨äºŽè½¬æ¢çš„临时文件"
+
+msgid "Conversion with 'charconvert' failed"
+msgstr "'charconvert' 转æ¢å¤±è´¥"
+
+msgid "can't read output of 'charconvert'"
+msgstr "æ— æ³•è¯»å– 'charconvert' 的输出"
+
+msgid "E676: No matching autocommands for acwrite buffer"
+msgstr "E676: 找ä¸åˆ° acwrite 缓冲区对应的自动命令"
+
+msgid "E203: Autocommands deleted or unloaded buffer to be written"
+msgstr "E203: 自动命令删除或释放了è¦å†™å…¥çš„缓冲区"
+
+msgid "E204: Autocommand changed number of lines in unexpected way"
+msgstr "E204: 自动命令æ„外地改å˜äº†è¡Œæ•°"
+
+msgid "NetBeans disallows writes of unmodified buffers"
+msgstr "NetBeans ä¸å…许未修改的缓冲区写入"
+
+msgid "Partial writes disallowed for NetBeans buffers"
+msgstr "NetBeans ä¸å…许缓冲区部分写入"
+
+msgid "is not a file or writable device"
+msgstr "ä¸æ˜¯æ–‡ä»¶æˆ–å¯å†™çš„设备"
+
+msgid "is read-only (add ! to override)"
+msgstr "åªè¯» (请加 ! 强制执行)"
+
+msgid "E506: Can't write to backup file (add ! to override)"
+msgstr "E506: 无法写入备份文件 (请加 ! 强制执行)"
+
+msgid "E507: Close error for backup file (add ! to override)"
+msgstr "E507: 关闭备份文件出错 (请加 ! 强制执行)"
+
+msgid "E508: Can't read file for backup (add ! to override)"
+msgstr "E508: 无法读å–文件以供备份 (请加 ! 强制执行)"
+
+msgid "E509: Cannot create backup file (add ! to override)"
+msgstr "E509: 无法创建备份文件 (请加 ! 强制执行)"
+
+msgid "E510: Can't make backup file (add ! to override)"
+msgstr "E510: 无法生æˆå¤‡ä»½æ–‡ä»¶ (请加 ! 强制执行)"
+
+msgid "E460: The resource fork would be lost (add ! to override)"
+msgstr "E460: Resource fork 会丢失 (请加 ! 强制执行)"
+
+msgid "E214: Can't find temp file for writing"
+msgstr "E214: 找ä¸åˆ°ç”¨äºŽå†™å…¥çš„临时文件"
+
+msgid "E213: Cannot convert (add ! to write without conversion)"
+msgstr "E213: æ— æ³•è½¬æ¢ (请加 ! 强制ä¸è½¬æ¢å†™å…¥)"
+
+msgid "E166: Can't open linked file for writing"
+msgstr "E166: 无法打开并写入链接文件"
+
+msgid "E212: Can't open file for writing"
+msgstr "E212: 无法打开并写入文件"
+
+msgid "E667: Fsync failed"
+msgstr "E667: åŒæ­¥å¤±è´¥"
+
+msgid "E512: Close failed"
+msgstr "E512: 关闭失败"
+
+msgid "E513: write error, conversion failed (make 'fenc' empty to override)"
+msgstr "E513: 写入错误,转æ¢å¤±è´¥ (请将 'fenc' 置空以强制执行)"
+
+msgid "E514: write error (file system full?)"
+msgstr "E514: 写入错误 (文件系统已满?)"
+
+msgid " CONVERSION ERROR"
+msgstr " 转æ¢é”™è¯¯"
+
+msgid "[Device]"
+msgstr "[设备]"
+
+msgid "[New]"
+msgstr "[æ–°]"
+
+msgid " [a]"
+msgstr " [a]"
+
+msgid " appended"
+msgstr " 已追加"
+
+msgid " [w]"
+msgstr " [w]"
+
+msgid " written"
+msgstr " 已写入"
+
+msgid "E205: Patchmode: can't save original file"
+msgstr "E205: Patchmode: 无法ä¿å­˜åŽŸå§‹æ–‡ä»¶"
+
+msgid "E206: patchmode: can't touch empty original file"
+msgstr "E206: Patchmode: 无法生æˆç©ºçš„原始文件"
+
+msgid "E207: Can't delete backup file"
+msgstr "E207: 无法删除备份文件"
+
+msgid ""
+"\n"
+"WARNING: Original file may be lost or damaged\n"
+msgstr ""
+"\n"
+"警告: 原始文件å¯èƒ½å·²ä¸¢å¤±æˆ–æŸå\n"
+
+msgid "don't quit the editor until the file is successfully written!"
+msgstr "在文件正确写入å‰è¯·å‹¿é€€å‡ºç¼–辑器ï¼"
+
+msgid "[dos]"
+msgstr "[dos]"
+
+msgid "[dos format]"
+msgstr "[dos æ ¼å¼]"
+
+msgid "[mac]"
+msgstr "[mac]"
+
+msgid "[mac format]"
+msgstr "[mac æ ¼å¼]"
+
+msgid "[unix]"
+msgstr "[unix]"
+
+msgid "[unix format]"
+msgstr "[unix æ ¼å¼]"
+
+msgid "1 line, "
+msgstr "1 行,"
+
+#, c-format
+msgid "%ld lines, "
+msgstr "%ld 行,"
+
+msgid "1 character"
+msgstr "1 个字符"
+
+#, c-format
+msgid "%ld characters"
+msgstr "%ld 个字符"
+
+msgid "[noeol]"
+msgstr "[noeol]"
+
+msgid "[Incomplete last line]"
+msgstr "[最åŽä¸€è¡Œä¸å®Œæ•´]"
+
+#. don't overwrite messages here
+#. must give this prompt
+#. don't use emsg() here, don't want to flush the buffers
+msgid "WARNING: The file has been changed since reading it!!!"
+msgstr "警告: 此文件自读入åŽå·²å‘生å˜åŠ¨ï¼ï¼ï¼"
+
+msgid "Do you really want to write to it"
+msgstr "确实è¦å†™å…¥å—"
+
+#, c-format
+msgid "E208: Error writing to \"%s\""
+msgstr "E208: 写入文件 \"%s\" 出错"
+
+#, c-format
+msgid "E209: Error closing \"%s\""
+msgstr "E209: 关闭文件 \"%s\" 出错"
+
+#, c-format
+msgid "E210: Error reading \"%s\""
+msgstr "E210: 读å–文件 \"%s\" 出错"
+
+msgid "E246: FileChangedShell autocommand deleted buffer"
+msgstr "E246: FileChangedShell 自动命令删除了缓冲区"
+
+#, c-format
+msgid "E211: File \"%s\" no longer available"
+msgstr "E211: 文件 \"%s\" å·²ç»ä¸å­˜åœ¨"
+
+#, c-format
+msgid ""
+"W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as "
+"well"
+msgstr "W12: 警告: 文件 \"%s\" å·²å˜åŠ¨ï¼Œå¹¶ä¸”在 Vim 中的缓冲区也已å˜åŠ¨"
+
+msgid "See \":help W12\" for more info."
+msgstr "è¿›ä¸€æ­¥è¯´æ˜Žè¯·è§ \":help W12\""
+
+#, c-format
+msgid "W11: Warning: File \"%s\" has changed since editing started"
+msgstr "W11: 警告: 编辑开始åŽï¼Œæ–‡ä»¶ \"%s\" å·²å˜åŠ¨"
+
+msgid "See \":help W11\" for more info."
+msgstr "è¿›ä¸€æ­¥è¯´æ˜Žè¯·è§ \":help W11\""
+
+#, c-format
+msgid "W16: Warning: Mode of file \"%s\" has changed since editing started"
+msgstr "W16: 警告: 编辑开始åŽï¼Œæ–‡ä»¶ \"%s\" 的模å¼å·²å˜åŠ¨"
+
+msgid "See \":help W16\" for more info."
+msgstr "è¿›ä¸€æ­¥è¯´æ˜Žè¯·è§ \":help W16\""
+
+#, c-format
+msgid "W13: Warning: File \"%s\" has been created after editing started"
+msgstr "W13: 警告: 编辑开始åŽï¼Œæ–‡ä»¶ \"%s\" 已被创建"
+
+msgid "Warning"
+msgstr "警告"
+
+msgid ""
+"&OK\n"
+"&Load File"
+msgstr ""
+"确定(&O)\n"
+"加载文件(&L)"
+
+#, c-format
+msgid "E462: Could not prepare for reloading \"%s\""
+msgstr "E462: 无法为é‡æ–°åŠ è½½ \"%s\" åšå‡†å¤‡"
+
+#, c-format
+msgid "E321: Could not reload \"%s\""
+msgstr "E321: 无法é‡æ–°åŠ è½½ \"%s\""
+
+msgid "--Deleted--"
+msgstr "--已删除--"
+
+#, c-format
+#~ msgid "auto-removing autocommand: %s <buffer=%d>"
+#~ msgstr ""
+
+#. the group doesn't exist
+#, c-format
+msgid "E367: No such group: \"%s\""
+msgstr "E367: 无此组: \"%s\""
+
+#, c-format
+msgid "E215: Illegal character after *: %s"
+msgstr "E215: * åŽé¢æœ‰æ— æ•ˆå­—符: %s"
+
+#, c-format
+msgid "E216: No such event: %s"
+msgstr "E216: 无此事件: %s"
+
+#, c-format
+msgid "E216: No such group or event: %s"
+msgstr "E216: 无此组或事件: %s"
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Autocommands ---"
+msgstr ""
+"\n"
+"--- 自动命令 ---"
+
+#, c-format
+msgid "E680: <buffer=%d>: invalid buffer number "
+msgstr "E680: <buffer=%d>: æ— æ•ˆçš„ç¼“å†²åŒºå· "
+
+msgid "E217: Can't execute autocommands for ALL events"
+msgstr "E217: ä¸èƒ½å¯¹æ‰€æœ‰äº‹ä»¶æ‰§è¡Œè‡ªåŠ¨å‘½ä»¤"
+
+msgid "No matching autocommands"
+msgstr "没有匹é…的自动命令"
+
+msgid "E218: autocommand nesting too deep"
+msgstr "E218: 自动命令嵌套层数过深"
+
+#, c-format
+msgid "%s Autocommands for \"%s\""
+msgstr "%s 自动命令 \"%s\""
+
+#, c-format
+msgid "Executing %s"
+msgstr "执行 %s"
+
+#, c-format
+msgid "autocommand %s"
+msgstr "自动命令 %s"
+
+msgid "E219: Missing {."
+msgstr "E219: 缺少 {。"
+
+msgid "E220: Missing }."
+msgstr "E220: 缺少 }。"
+
+msgid "E490: No fold found"
+msgstr "E490: 找ä¸åˆ°æŠ˜å "
+
+msgid "E350: Cannot create fold with current 'foldmethod'"
+msgstr "E350: ä¸èƒ½åœ¨å½“å‰çš„ 'foldmethod' 下创建折å "
+
+msgid "E351: Cannot delete fold with current 'foldmethod'"
+msgstr "E351: ä¸èƒ½åœ¨å½“å‰çš„ 'foldmethod' 下删除折å "
+
+#, c-format
+msgid "+--%3ld lines folded "
+msgstr "+--å·²æŠ˜å  %3ld è¡Œ"
+
+msgid "E222: Add to read buffer"
+msgstr "E222: 添加到已读缓冲区中"
+
+msgid "E223: recursive mapping"
+msgstr "E223: 递归映射"
+
+#, c-format
+msgid "E224: global abbreviation already exists for %s"
+msgstr "E224: 全局缩写 %s 已存在"
+
+#, c-format
+msgid "E225: global mapping already exists for %s"
+msgstr "E225: 全局映射 %s 已存在"
+
+#, c-format
+msgid "E226: abbreviation already exists for %s"
+msgstr "E226: 缩写 %s 已存在"
+
+#, c-format
+msgid "E227: mapping already exists for %s"
+msgstr "E227: 映射 %s 已存在"
+
+msgid "No abbreviation found"
+msgstr "找ä¸åˆ°ç¼©å†™"
+
+msgid "No mapping found"
+msgstr "找ä¸åˆ°æ˜ å°„"
+
+msgid "E228: makemap: Illegal mode"
+msgstr "E228: makemap: 无效的模å¼"
+
+msgid "E229: Cannot start the GUI"
+msgstr "E229: 无法å¯åŠ¨å›¾å½¢ç•Œé¢"
+
+#, c-format
+msgid "E230: Cannot read from \"%s\""
+msgstr "E230: 无法读å–文件 \"%s\""
+
+msgid "E665: Cannot start GUI, no valid font found"
+msgstr "E665: 无法å¯åŠ¨å›¾å½¢ç•Œé¢ï¼Œæ‰¾ä¸åˆ°æœ‰æ•ˆçš„字体"
+
+msgid "E231: 'guifontwide' invalid"
+msgstr "E231: 无效的 'guifontwide'"
+
+msgid "E599: Value of 'imactivatekey' is invalid"
+msgstr "E599: 'imactivatekey' 的值无效"
+
+#, c-format
+msgid "E254: Cannot allocate color %s"
+msgstr "E254: 无法分é…颜色 %s"
+
+msgid "No match at cursor, finding next"
+msgstr "在光标处没有匹é…,查找下一个"
+
+msgid "<cannot open> "
+msgstr "<无法打开>"
+
+#, c-format
+msgid "E616: vim_SelFile: can't get font %s"
+msgstr "E616: vim_SelFile: 无法获å–字体 %s"
+
+msgid "E614: vim_SelFile: can't return to current directory"
+msgstr "E614: vim_SelFile: 无法返回当å‰ç›®å½•"
+
+msgid "Pathname:"
+msgstr "路径:"
+
+msgid "E615: vim_SelFile: can't get current directory"
+msgstr "E615: vim_SelFile: 无法获å–当å‰ç›®å½•"
+
+msgid "OK"
+msgstr "确定"
+
+msgid "Cancel"
+msgstr "å–消"
+
+msgid "Scrollbar Widget: Could not get geometry of thumb pixmap."
+msgstr "滚动æ¡éƒ¨ä»¶: 无法获å–滑å—图åƒçš„几何大å°"
+
+msgid "Vim dialog"
+msgstr "Vim 对è¯æ¡†"
+
+msgid "E232: Cannot create BalloonEval with both message and callback"
+msgstr "E232: ä¸èƒ½åŒæ—¶ä½¿ç”¨æ¶ˆæ¯å’Œå›žè°ƒå‡½æ•°æ¥åˆ›å»º BalloonEval"
+
+msgid "Vim dialog..."
+msgstr "Vim 对è¯æ¡†..."
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"&Cancel"
+msgstr ""
+"是(&Y)\n"
+"å¦(&N)\n"
+"å–消(&C)"
+
+msgid "Input _Methods"
+msgstr "输入法(_M)"
+
+msgid "VIM - Search and Replace..."
+msgstr "VIM - 查找和替æ¢..."
+
+msgid "VIM - Search..."
+msgstr "VIM - 查找..."
+
+msgid "Find what:"
+msgstr "查找内容:"
+
+msgid "Replace with:"
+msgstr "替æ¢ä¸º:"
+
+#. whole word only button
+msgid "Match whole word only"
+msgstr "匹é…完整的è¯"
+
+#. match case button
+msgid "Match case"
+msgstr "匹é…大å°å†™"
+
+msgid "Direction"
+msgstr "æ–¹å‘"
+
+#. 'Up' and 'Down' buttons
+msgid "Up"
+msgstr "å‘上"
+
+msgid "Down"
+msgstr "å‘下"
+
+msgid "Find Next"
+msgstr "查找下一个"
+
+msgid "Replace"
+msgstr "替æ¢"
+
+msgid "Replace All"
+msgstr "全部替æ¢"
+
+msgid "Vim: Received \"die\" request from session manager\n"
+msgstr "Vim: 从会è¯ç®¡ç†å™¨æ”¶åˆ° \"die\" 请求\n"
+
+msgid "Close"
+msgstr "关闭"
+
+msgid "New tab"
+msgstr "新建标签"
+
+msgid "Open Tab..."
+msgstr "打开标签..."
+
+msgid "Vim: Main window unexpectedly destroyed\n"
+msgstr "Vim: 主窗å£è¢«æ„外地摧æ¯\n"
+
+msgid "Font Selection"
+msgstr "选择字体"
+
+msgid "Used CUT_BUFFER0 instead of empty selection"
+msgstr "使用 CUT_BUFFER0 æ¥å–代空选择"
+
+msgid "&Filter"
+msgstr "过滤(&F)"
+
+msgid "&Cancel"
+msgstr "å–消(&C)"
+
+msgid "Directories"
+msgstr "目录"
+
+msgid "Filter"
+msgstr "过滤器"
+
+msgid "&Help"
+msgstr "帮助(&H)"
+
+msgid "Files"
+msgstr "文件"
+
+msgid "&OK"
+msgstr "确定(&O)"
+
+msgid "Selection"
+msgstr "选择"
+
+msgid "Find &Next"
+msgstr "查找下一个(&N)"
+
+msgid "&Replace"
+msgstr "替æ¢(&R)"
+
+msgid "Replace &All"
+msgstr "全部替æ¢(&A)"
+
+msgid "&Undo"
+msgstr "撤销(&U)"
+
+#, c-format
+msgid "E671: Cannot find window title \"%s\""
+msgstr "E671: 找ä¸åˆ°çª—å£æ ‡é¢˜ \"%s\""
+
+#, c-format
+msgid "E243: Argument not supported: \"-%s\"; Use the OLE version."
+msgstr "E243: ä¸æ”¯æŒçš„å‚æ•°: \"-%s\";请使用 OLE 版本。"
+
+msgid "E672: Unable to open window inside MDI application"
+msgstr "E672: 无法在 MDI 应用程åºä¸­æ‰“开窗å£"
+
+msgid "Close tab"
+msgstr "关闭标签"
+
+msgid "Open tab..."
+msgstr "打开标签..."
+
+msgid "Find string (use '\\\\' to find a '\\')"
+msgstr "查找字符串 (使用 '\\\\' æ¥æŸ¥æ‰¾ '\\')"
+
+msgid "Find & Replace (use '\\\\' to find a '\\')"
+msgstr "查找和替æ¢å­—符串 (使用 '\\\\' æ¥æŸ¥æ‰¾ '\\')"
+
+#. We fake this: Use a filter that doesn't select anything and a default
+#. * file name that won't be used.
+msgid "Not Used"
+msgstr "未使用"
+
+msgid "Directory\t*.nothing\n"
+msgstr "目录\t*.nothing\n"
+
+msgid "Vim E458: Cannot allocate colormap entry, some colors may be incorrect"
+msgstr "Vim E458: 无法分é…颜色表项,æŸäº›é¢œè‰²å¯èƒ½ä¸æ­£ç¡®"
+
+#, c-format
+msgid "E250: Fonts for the following charsets are missing in fontset %s:"
+msgstr "E250: Fontset %s 缺少下列字符集的字体:"
+
+#, c-format
+msgid "E252: Fontset name: %s"
+msgstr "E252: Fontset å称: %s"
+
+#, c-format
+msgid "Font '%s' is not fixed-width"
+msgstr "'%s' ä¸æ˜¯å›ºå®šå®½åº¦çš„字体"
+
+#, c-format
+msgid "E253: Fontset name: %s\n"
+msgstr "E253: Fontset å称: %s\n"
+
+#, c-format
+msgid "Font0: %s\n"
+msgstr "字体0: %s\n"
+
+#, c-format
+msgid "Font1: %s\n"
+msgstr "字体1: %s\n"
+
+#, c-format
+msgid "Font%ld width is not twice that of font0\n"
+msgstr "字体%ld的宽度ä¸æ˜¯å­—体0的两å€\n"
+
+#, c-format
+msgid "Font0 width: %ld\n"
+msgstr "字体0的宽度:%ld\n"
+
+#, c-format
+msgid ""
+"Font1 width: %ld\n"
+"\n"
+msgstr ""
+"字体1的宽度: %ld\n"
+"\n"
+
+msgid "Invalid font specification"
+msgstr "指定了无效的字体"
+
+msgid "&Dismiss"
+msgstr "å–消(&D)"
+
+msgid "no specific match"
+msgstr "找ä¸åˆ°åŒ¹é…的项"
+
+msgid "Vim - Font Selector"
+msgstr "Vim - 字体选择器"
+
+msgid "Name:"
+msgstr "å称:"
+
+#. create toggle button
+#~ msgid "Show size in Points"
+#~ msgstr ""
+
+msgid "Encoding:"
+msgstr "ç¼–ç :"
+
+msgid "Font:"
+msgstr "字体:"
+
+msgid "Style:"
+msgstr "风格:"
+
+msgid "Size:"
+msgstr "尺寸:"
+
+msgid "E256: Hangul automata ERROR"
+msgstr "E256: Hangul automata 错误"
+
+msgid "E550: Missing colon"
+msgstr "E550: 缺少冒å·"
+
+msgid "E551: Illegal component"
+msgstr "E551: 无效的部分"
+
+msgid "E552: digit expected"
+msgstr "E552: 应该è¦æœ‰æ•°å­—"
+
+#, c-format
+msgid "Page %d"
+msgstr "第 %d 页"
+
+msgid "No text to be printed"
+msgstr "没有è¦æ‰“å°çš„文字"
+
+#, c-format
+msgid "Printing page %d (%d%%)"
+msgstr "正在打å°ç¬¬ %d 页 (%d%%)"
+
+#, c-format
+msgid " Copy %d of %d"
+msgstr "å¤åˆ¶ %d / %d"
+
+#, c-format
+msgid "Printed: %s"
+msgstr "已打å°: %s"
+
+msgid "Printing aborted"
+msgstr "打å°ä¸­æ­¢"
+
+msgid "E455: Error writing to PostScript output file"
+msgstr "E455: 写入 PostScript 输出文件出错"
+
+#, c-format
+msgid "E624: Can't open file \"%s\""
+msgstr "E624: 无法打开文件 \"%s\""
+
+#, c-format
+msgid "E457: Can't read PostScript resource file \"%s\""
+msgstr "E457: æ— æ³•è¯»å– PostScript 资æºæ–‡ä»¶ \"%s\""
+
+#, c-format
+msgid "E618: file \"%s\" is not a PostScript resource file"
+msgstr "E618: 文件 \"%s\" ä¸æ˜¯ PostScript 资æºæ–‡ä»¶"
+
+#, c-format
+msgid "E619: file \"%s\" is not a supported PostScript resource file"
+msgstr "E619: 文件 \"%s\" ä¸æ˜¯å·²æ”¯æŒçš„ PostScript 资æºæ–‡ä»¶"
+
+#, c-format
+msgid "E621: \"%s\" resource file has wrong version"
+msgstr "E621: \"%s\" 资æºæ–‡ä»¶ç‰ˆæœ¬ä¸æ­£ç¡®"
+
+msgid "E673: Incompatible multi-byte encoding and character set."
+msgstr "E673: ä¸å…¼å®¹çš„多字节编ç å’Œå­—符集。"
+
+msgid "E674: printmbcharset cannot be empty with multi-byte encoding."
+msgstr "E674: printmbcharset 在多字节编ç ä¸‹ä¸èƒ½ä¸ºç©ºã€‚"
+
+msgid "E675: No default font specified for multi-byte printing."
+msgstr "E675: 没有指定多字节打å°çš„默认字体。"
+
+msgid "E324: Can't open PostScript output file"
+msgstr "E324: 无法打开 PostScript 输出文件"
+
+#, c-format
+msgid "E456: Can't open file \"%s\""
+msgstr "E456: 无法打开文件 \"%s\""
+
+msgid "E456: Can't find PostScript resource file \"prolog.ps\""
+msgstr "E456: 找ä¸åˆ° PostScript 资æºæ–‡ä»¶ \"prolog.ps\""
+
+msgid "E456: Can't find PostScript resource file \"cidfont.ps\""
+msgstr "E456: 找ä¸åˆ° PostScript 资æºæ–‡ä»¶ \"cidfont.ps\""
+
+#, c-format
+msgid "E456: Can't find PostScript resource file \"%s.ps\""
+msgstr "E456: 找ä¸åˆ° PostScript 资æºæ–‡ä»¶ \"%s.ps\""
+
+#, c-format
+msgid "E620: Unable to convert to print encoding \"%s\""
+msgstr "E620: 无法转æ¢è‡³æ‰“å°ç¼–ç  \"%s\""
+
+msgid "Sending to printer..."
+msgstr "å‘é€åˆ°æ‰“å°æœºâ€¦â€¦"
+
+msgid "E365: Failed to print PostScript file"
+msgstr "E365: æ— æ³•æ‰“å° PostScript 文件"
+
+msgid "Print job sent."
+msgstr "打å°ä»»åŠ¡å·²è¢«å‘é€ã€‚"
+
+msgid "Add a new database"
+msgstr "添加一个新的数æ®åº“"
+
+msgid "Query for a pattern"
+msgstr "查询一个模å¼"
+
+msgid "Show this message"
+msgstr "显示此信æ¯"
+
+msgid "Kill a connection"
+msgstr "结æŸä¸€ä¸ªè¿žæŽ¥"
+
+msgid "Reinit all connections"
+msgstr "é‡ç½®æ‰€æœ‰è¿žæŽ¥"
+
+msgid "Show connections"
+msgstr "显示连接"
+
+#, c-format
+msgid "E560: Usage: cs[cope] %s"
+msgstr "E560: 用法: cs[cope] %s"
+
+msgid "This cscope command does not support splitting the window.\n"
+msgstr "这个 cscope 命令ä¸æ”¯æŒåˆ†å‰²çª—å£ã€‚\n"
+
+msgid "E562: Usage: cstag <ident>"
+msgstr "E562: 用法: cstag <ident>"
+
+msgid "E257: cstag: tag not found"
+msgstr "E257: cstag: 找ä¸åˆ° tag"
+
+#, c-format
+msgid "E563: stat(%s) error: %d"
+msgstr "E563: stat(%s) 错误: %d"
+
+msgid "E563: stat error"
+msgstr "E563: stat 错误"
+
+#, c-format
+msgid "E564: %s is not a directory or a valid cscope database"
+msgstr "E564: %s ä¸æ˜¯ç›®å½•æˆ–有效的 cscope æ•°æ®åº“"
+
+#, c-format
+msgid "Added cscope database %s"
+msgstr "添加了 cscope æ•°æ®åº“ %s"
+
+#, c-format
+msgid "E262: error reading cscope connection %ld"
+msgstr "E262: è¯»å– cscope 连接 %ld 出错"
+
+msgid "E561: unknown cscope search type"
+msgstr "E561: 未知的 cscope 查找类型"
+
+msgid "E566: Could not create cscope pipes"
+msgstr "E566: 无法创建 cscope 管é“"
+
+msgid "E622: Could not fork for cscope"
+msgstr "E622: 无法对 cscope 进行 fork"
+
+msgid "cs_create_connection exec failed"
+msgstr "cs_create_connection 执行失败"
+
+msgid "E623: Could not spawn cscope process"
+msgstr "E623: æ— æ³•ç”Ÿæˆ cscope 进程"
+
+msgid "cs_create_connection: fdopen for to_fp failed"
+msgstr "cs_create_connection: fdopen to_fp 失败"
+
+msgid "cs_create_connection: fdopen for fr_fp failed"
+msgstr "cs_create_connection: fdopen fr_fp 失败"
+
+msgid "E567: no cscope connections"
+msgstr "E567: 没有 cscope 连接"
+
+#, c-format
+msgid "E259: no matches found for cscope query %s of %s"
+msgstr "E259: cscope 查询 %s %s 没有找到匹é…的结果"
+
+#, c-format
+msgid "E469: invalid cscopequickfix flag %c for %c"
+msgstr "E469: cscopequickfix 标志 %c 对 %c 无效"
+
+msgid "cscope commands:\n"
+msgstr "cscope 命令:\n"
+
+#, c-format
+msgid "%-5s: %-30s (Usage: %s)"
+msgstr "%-5s: %-30s (用法: %s)"
+
+#, c-format
+msgid "E625: cannot open cscope database: %s"
+msgstr "E625: 无法打开 cscope æ•°æ®åº“: %s"
+
+msgid "E626: cannot get cscope database information"
+msgstr "E626: æ— æ³•èŽ·å– cscope æ•°æ®åº“ä¿¡æ¯"
+
+msgid "E568: duplicate cscope database not added"
+msgstr "E568: é‡å¤çš„ cscope æ•°æ®åº“未被加入"
+
+msgid "E569: maximum number of cscope connections reached"
+msgstr "E569: 已达到 cscope 的最大连接数"
+
+#, c-format
+msgid "E261: cscope connection %s not found"
+msgstr "E261: 找ä¸åˆ° cscope 连接 %s"
+
+#, c-format
+msgid "cscope connection %s closed"
+msgstr "cscope 连接 %s 已关闭"
+
+#. should not reach here
+msgid "E570: fatal error in cs_manage_matches"
+msgstr "E570: cs_manage_matches 严é‡é”™è¯¯"
+
+#, c-format
+msgid "Cscope tag: %s"
+msgstr "Cscope tag: %s"
+
+msgid ""
+"\n"
+" # line"
+msgstr ""
+"\n"
+" # 行 "
+
+msgid "filename / context / line\n"
+msgstr "文件å / 上下文 / è¡Œ\n"
+
+#, c-format
+msgid "E609: Cscope error: %s"
+msgstr "E609: Cscope 错误: %s"
+
+msgid "All cscope databases reset"
+msgstr "所有 cscope æ•°æ®åº“已被é‡ç½®"
+
+msgid "no cscope connections\n"
+msgstr "没有 cscope 连接\n"
+
+msgid " # pid database name prepend path\n"
+msgstr " # pid æ•°æ®åº“å prepend path\n"
+
+msgid ""
+"???: Sorry, this command is disabled, the MzScheme library could not be "
+"loaded."
+msgstr "???: 抱歉,此命令ä¸å¯ç”¨ï¼Œæ— æ³•åŠ è½½ MzScheme 库"
+
+msgid "invalid expression"
+msgstr "无效的表达å¼"
+
+msgid "expressions disabled at compile time"
+msgstr "编译时没有å¯ç”¨è¡¨è¾¾å¼"
+
+msgid "hidden option"
+msgstr "éšè—的选项"
+
+msgid "unknown option"
+msgstr "未知的选项"
+
+msgid "window index is out of range"
+msgstr "窗å£ç´¢å¼•è¶…出范围"
+
+msgid "couldn't open buffer"
+msgstr "无法打开缓冲区"
+
+msgid "cannot save undo information"
+msgstr "无法ä¿å­˜æ’¤é”€ä¿¡æ¯"
+
+msgid "cannot delete line"
+msgstr "无法删除行"
+
+msgid "cannot replace line"
+msgstr "无法替æ¢è¡Œ"
+
+msgid "cannot insert line"
+msgstr "无法æ’入行"
+
+msgid "string cannot contain newlines"
+msgstr "字符串ä¸èƒ½åŒ…å«æ¢è¡Œ(NL)"
+
+msgid "Vim error: ~a"
+msgstr "Vim 错误: ~a"
+
+msgid "Vim error"
+msgstr "Vim 错误"
+
+msgid "buffer is invalid"
+msgstr "缓冲区无效"
+
+msgid "window is invalid"
+msgstr "窗å£æ— æ•ˆ"
+
+msgid "linenr out of range"
+msgstr "è¡Œå·è¶…出范围"
+
+msgid "not allowed in the Vim sandbox"
+msgstr "ä¸å…许在 sandbox 中使用"
+
+msgid ""
+"E263: Sorry, this command is disabled, the Python library could not be "
+"loaded."
+msgstr "E263: 抱歉,此命令ä¸å¯ç”¨ï¼Œæ— æ³•åŠ è½½ Python 库。"
+
+msgid "E659: Cannot invoke Python recursively"
+msgstr "E659: ä¸èƒ½é€’归调用 Python"
+
+msgid "can't delete OutputObject attributes"
+msgstr "ä¸èƒ½åˆ é™¤ OutputObject 属性"
+
+msgid "softspace must be an integer"
+msgstr "softspace 必须是整数"
+
+msgid "invalid attribute"
+msgstr "无效的属性"
+
+msgid "writelines() requires list of strings"
+msgstr "writelines() 需è¦å­—符串列表作å‚æ•°"
+
+msgid "E264: Python: Error initialising I/O objects"
+msgstr "E264: Python: åˆå§‹åŒ– I/O 对象出错"
+
+msgid "attempt to refer to deleted buffer"
+msgstr "试图引用已被删除的缓冲区"
+
+msgid "line number out of range"
+msgstr "è¡Œå·è¶…出范围"
+
+#, c-format
+msgid "<buffer object (deleted) at %8lX>"
+msgstr "<缓冲区对象(已删除): %8lX>"
+
+msgid "invalid mark name"
+msgstr "无效的标记å称"
+
+msgid "no such buffer"
+msgstr "无此缓冲区"
+
+msgid "attempt to refer to deleted window"
+msgstr "试图引用已被删除的窗å£"
+
+msgid "readonly attribute"
+msgstr "åªè¯»å±žæ€§"
+
+msgid "cursor position outside buffer"
+msgstr "光标ä½ç½®åœ¨ç¼“冲区外"
+
+#, c-format
+msgid "<window object (deleted) at %.8lX>"
+msgstr "<窗å£å¯¹è±¡(已删除): %.8lX>"
+
+#, c-format
+msgid "<window object (unknown) at %.8lX>"
+msgstr "<窗å£å¯¹è±¡(未知): %.8lX>"
+
+#, c-format
+msgid "<window %d>"
+msgstr "<çª—å£ %d>"
+
+msgid "no such window"
+msgstr "无此窗å£"
+
+msgid ""
+"E266: Sorry, this command is disabled, the Ruby library could not be loaded."
+msgstr "E266: 抱歉,此命令ä¸å¯ç”¨ï¼Œæ— æ³•åŠ è½½ Ruby 库"
+
+#, c-format
+msgid "E273: unknown longjmp status %d"
+msgstr "E273: 未知的 longjmp çŠ¶æ€ %d"
+
+msgid "Toggle implementation/definition"
+msgstr "切æ¢å®žçŽ°/定义"
+
+msgid "Show base class of"
+msgstr "显示 base class of:"
+
+msgid "Show overridden member function"
+msgstr "显示被覆盖的æˆå‘˜å‡½æ•°"
+
+msgid "Retrieve from file"
+msgstr "æ¢å¤: 从文件"
+
+msgid "Retrieve from project"
+msgstr "æ¢å¤: 从对象"
+
+msgid "Retrieve from all projects"
+msgstr "æ¢å¤: 从所有项目"
+
+msgid "Retrieve"
+msgstr "æ¢å¤"
+
+msgid "Show source of"
+msgstr "显示æºä»£ç : "
+
+msgid "Find symbol"
+msgstr "查找 symbol"
+
+msgid "Browse class"
+msgstr "æµè§ˆ class"
+
+msgid "Show class in hierarchy"
+msgstr "显示层次关系的类"
+
+msgid "Show class in restricted hierarchy"
+msgstr "显示 restricted 层次关系的 class"
+
+msgid "Xref refers to"
+msgstr "Xref å‚考到"
+
+msgid "Xref referred by"
+msgstr "Xref 被è°å‚考:"
+
+msgid "Xref has a"
+msgstr "Xref 有"
+
+msgid "Xref used by"
+msgstr "Xref 被è°ä½¿ç”¨:"
+
+msgid "Show docu of"
+msgstr "显示文件: "
+
+msgid "Generate docu for"
+msgstr "产生文件: "
+
+msgid ""
+"Cannot connect to SNiFF+. Check environment (sniffemacs must be found in "
+"$PATH).\n"
+msgstr "ä¸èƒ½è¿žæŽ¥åˆ° SNiFF+。请检查环境å˜é‡ ($PATH 里必需å¯ä»¥æ‰¾åˆ° sniffemacs)\n"
+
+msgid "E274: Sniff: Error during read. Disconnected"
+msgstr "E274: Sniff: 读å–错误. å–消连接"
+
+msgid "SNiFF+ is currently "
+msgstr "SNiFF+ ç›®å‰"
+
+msgid "not "
+msgstr "未"
+
+msgid "connected"
+msgstr "连接中"
+
+#, c-format
+msgid "E275: Unknown SNiFF+ request: %s"
+msgstr "E275: ä¸æ­£ç¡®çš„ SNiff+ 调用: %s"
+
+msgid "E276: Error connecting to SNiFF+"
+msgstr "E276: 连接到 SNiFF+ 失败"
+
+msgid "E278: SNiFF+ not connected"
+msgstr "E278: 未连接到 SNiFF+"
+
+msgid "E279: Not a SNiFF+ buffer"
+msgstr "E279: ä¸æ˜¯ SNiFF+ 的缓冲区"
+
+msgid "Sniff: Error during write. Disconnected"
+msgstr "Sniff: 写入错误。结æŸè¿žæŽ¥"
+
+msgid "invalid buffer number"
+msgstr "无效的缓冲区å·"
+
+msgid "not implemented yet"
+msgstr "尚未实现"
+
+#. ???
+msgid "cannot set line(s)"
+msgstr "无法设定行"
+
+msgid "mark not set"
+msgstr "没有设定标记"
+
+#, c-format
+msgid "row %d column %d"
+msgstr "第 %d 行 第 %d 列"
+
+msgid "cannot insert/append line"
+msgstr "无法æ’å…¥/追加行"
+
+msgid "unknown flag: "
+msgstr "未知的标志: "
+
+msgid "unknown vimOption"
+msgstr "未知的 vim 选项"
+
+msgid "keyboard interrupt"
+msgstr "键盘中断"
+
+msgid "vim error"
+msgstr "vim 错误"
+
+msgid "cannot create buffer/window command: object is being deleted"
+msgstr "无法创建缓冲区/窗å£å‘½ä»¤: 对象将被删除"
+
+msgid ""
+"cannot register callback command: buffer/window is already being deleted"
+msgstr "无法注册回调命令: 缓冲区/窗å£å·²è¢«åˆ é™¤"
+
+#. This should never happen. Famous last word?
+msgid ""
+"E280: TCL FATAL ERROR: reflist corrupt!? Please report this to vim-dev@vim."
+"org"
+msgstr "E280: TCL 严é‡é”™è¯¯: reflist æŸåï¼ï¼Ÿè¯·æŠ¥å‘Šç»™ vim-dev@vim.org"
+
+msgid "cannot register callback command: buffer/window reference not found"
+msgstr "无法注册回调命令: 找ä¸åˆ°ç¼“冲区/窗å£å¼•ç”¨"
+
+msgid ""
+"E571: Sorry, this command is disabled: the Tcl library could not be loaded."
+msgstr "E571: 抱歉,此命令ä¸å¯ç”¨ï¼Œæ— æ³•åŠ è½½ Tcl 库"
+
+msgid ""
+"E281: TCL ERROR: exit code is not int!? Please report this to vim-dev@vim.org"
+msgstr "E281: TCL 错误: 退出返回值ä¸æ˜¯æ•´æ•°ï¼ï¼Ÿè¯·æŠ¥å‘Šç»™ vim-dev@vim.org"
+
+#, c-format
+msgid "E572: exit code %d"
+msgstr "E572: 退出返回值 %d"
+
+msgid "cannot get line"
+msgstr "无法获å–è¡Œ"
+
+msgid "Unable to register a command server name"
+msgstr "无法注册命令æœåŠ¡å™¨å"
+
+msgid "E248: Failed to send command to the destination program"
+msgstr "E248: 无法å‘é€å‘½ä»¤åˆ°ç›®çš„程åº"
+
+#, c-format
+msgid "E573: Invalid server id used: %s"
+msgstr "E573: 使用了无效的æœåŠ¡å™¨ id: %s"
+
+msgid "E251: VIM instance registry property is badly formed. Deleted!"
+msgstr "E251: VIM 实例注册属性有误。已删除ï¼"
+
+msgid "Unknown option argument"
+msgstr "未知的选项å‚æ•°"
+
+msgid "Too many edit arguments"
+msgstr "编辑å‚数过多"
+
+msgid "Argument missing after"
+msgstr "缺少必è¦çš„å‚æ•°"
+
+msgid "Garbage after option argument"
+msgstr "选项å‚æ•°åŽçš„内容无效"
+
+msgid "Too many \"+command\", \"-c command\" or \"--cmd command\" arguments"
+msgstr "\"+command\"ã€\"-c command\" 或 \"--cmd command\" å‚数过多"
+
+msgid "Invalid argument for"
+msgstr "无效的å‚æ•°"
+
+#, c-format
+msgid "%d files to edit\n"
+msgstr "还有 %d 个文件等待编辑\n"
+
+msgid "This Vim was not compiled with the diff feature."
+msgstr "此 Vim 编译时没有加入 diff 功能"
+
+msgid "Attempt to open script file again: \""
+msgstr "试图å†æ¬¡æ‰“开脚本文件: \""
+
+msgid "Cannot open for reading: \""
+msgstr "无法打开并读å–: \""
+
+msgid "Cannot open for script output: \""
+msgstr "无法打开并输出脚本: \""
+
+msgid "Vim: Error: Failure to start gvim from NetBeans\n"
+msgstr "Vim: 错误: 无法从 NetBeans 中å¯åŠ¨ gvim\n"
+
+msgid "Vim: Warning: Output is not to a terminal\n"
+msgstr "Vim: 警告: 输出ä¸æ˜¯åˆ°ç»ˆç«¯(å±å¹•)\n"
+
+msgid "Vim: Warning: Input is not from a terminal\n"
+msgstr "Vim: 警告: 输入ä¸æ˜¯æ¥è‡ªç»ˆç«¯(键盘)\n"
+
+#. just in case..
+msgid "pre-vimrc command line"
+msgstr "pre-vimrc 命令行"
+
+#, c-format
+msgid "E282: Cannot read from \"%s\""
+msgstr "E282: æ— æ³•è¯»å– \"%s\""
+
+msgid ""
+"\n"
+"More info with: \"vim -h\"\n"
+msgstr ""
+"\n"
+"更多信æ¯è¯·è§: \"vim -h\"\n"
+
+msgid "[file ..] edit specified file(s)"
+msgstr "[文件 ..] 编辑指定的文件"
+
+msgid "- read text from stdin"
+msgstr "- 从标准输入(stdin)读å–文本"
+
+msgid "-t tag edit file where tag is defined"
+msgstr "-t tag 编辑 tag 定义处的文件"
+
+msgid "-q [errorfile] edit file with first error"
+msgstr "-q [errorfile] 编辑第一个出错处的文件"
+
+msgid ""
+"\n"
+"\n"
+"Usage:"
+msgstr ""
+"\n"
+"\n"
+"用法:"
+
+msgid " vim [arguments] "
+msgstr " vim [å‚æ•°] "
+
+msgid ""
+"\n"
+" or:"
+msgstr ""
+"\n"
+" 或:"
+
+#~ msgid "where case is ignored prepend / to make flag upper case"
+#~ msgstr ""
+
+msgid ""
+"\n"
+"\n"
+"Arguments:\n"
+msgstr ""
+"\n"
+"\n"
+"å‚æ•°:\n"
+
+msgid "--\t\t\tOnly file names after this"
+msgstr "--\t\t\t在这以åŽåªæœ‰æ–‡ä»¶å"
+
+msgid "--literal\t\tDon't expand wildcards"
+msgstr "--literal\t\tä¸æ‰©å±•é€šé…符"
+
+msgid "-register\t\tRegister this gvim for OLE"
+msgstr "-register\t\t注册此 gvim 到 OLE"
+
+msgid "-unregister\t\tUnregister gvim for OLE"
+msgstr "-unregister\t\tå–消 OLE 中的 gvim 注册"
+
+msgid "-g\t\t\tRun using GUI (like \"gvim\")"
+msgstr "-g\t\t\tä½¿ç”¨å›¾å½¢ç•Œé¢ (åŒ \"gvim\")"
+
+msgid "-f or --nofork\tForeground: Don't fork when starting GUI"
+msgstr "-f 或 --nofork\tå‰å°: å¯åŠ¨å›¾å½¢ç•Œé¢æ—¶ä¸ fork"
+
+msgid "-v\t\t\tVi mode (like \"vi\")"
+msgstr "-v\t\t\tVi æ¨¡å¼ (åŒ \"vi\")"
+
+msgid "-e\t\t\tEx mode (like \"ex\")"
+msgstr "-e\t\t\tEx æ¨¡å¼ (åŒ \"ex\")"
+
+msgid "-s\t\t\tSilent (batch) mode (only for \"ex\")"
+msgstr "-s\t\t\t安é™(批处ç†)æ¨¡å¼ (åªèƒ½ä¸Ž \"ex\" 一起使用)"
+
+msgid "-d\t\t\tDiff mode (like \"vimdiff\")"
+msgstr "-d\t\t\tDiff æ¨¡å¼ (åŒ \"vimdiff\")"
+
+msgid "-y\t\t\tEasy mode (like \"evim\", modeless)"
+msgstr "-y\t\t\tå®¹æ˜“æ¨¡å¼ (åŒ \"evim\",无模å¼)"
+
+msgid "-R\t\t\tReadonly mode (like \"view\")"
+msgstr "-R\t\t\tåªè¯»æ¨¡å¼ (åŒ \"view\")"
+
+msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
+msgstr "-Z\t\t\té™åˆ¶æ¨¡å¼ (åŒ \"rvim\")"
+
+msgid "-m\t\t\tModifications (writing files) not allowed"
+msgstr "-m\t\t\tä¸å¯ä¿®æ”¹(写入文件)"
+
+msgid "-M\t\t\tModifications in text not allowed"
+msgstr "-M\t\t\t文本ä¸å¯ä¿®æ”¹"
+
+msgid "-b\t\t\tBinary mode"
+msgstr "-b\t\t\t二进制模å¼"
+
+msgid "-l\t\t\tLisp mode"
+msgstr "-l\t\t\tLisp 模å¼"
+
+msgid "-C\t\t\tCompatible with Vi: 'compatible'"
+msgstr "-C\t\t\t兼容传统的 Vi: 'compatible'"
+
+msgid "-N\t\t\tNot fully Vi compatible: 'nocompatible'"
+msgstr "-N\t\t\tä¸å®Œå…¨å…¼å®¹ä¼ ç»Ÿçš„ Vi: 'nocompatible'"
+
+msgid "-V[N]\t\tVerbose level"
+msgstr "-V[N]\t\tVerbose 等级"
+
+msgid "-D\t\t\tDebugging mode"
+msgstr "-D\t\t\t调试模å¼"
+
+msgid "-n\t\t\tNo swap file, use memory only"
+msgstr "-n\t\t\tä¸ä½¿ç”¨äº¤æ¢æ–‡ä»¶ï¼Œåªä½¿ç”¨å†…å­˜"
+
+msgid "-r\t\t\tList swap files and exit"
+msgstr "-r\t\t\t列出交æ¢æ–‡ä»¶å¹¶é€€å‡º"
+
+msgid "-r (with file name)\tRecover crashed session"
+msgstr "-r (跟文件å)\t\tæ¢å¤å´©æºƒçš„会è¯"
+
+msgid "-L\t\t\tSame as -r"
+msgstr "-L\t\t\tåŒ -r"
+
+msgid "-f\t\t\tDon't use newcli to open window"
+msgstr "-f\t\t\tä¸ä½¿ç”¨ newcli æ¥æ‰“开窗å£"
+
+msgid "-dev <device>\t\tUse <device> for I/O"
+msgstr "-dev <device>\t\t使用 <device> 进行输入输出"
+
+msgid "-A\t\t\tStart in Arabic mode"
+msgstr "-A\t\t\t以 Arabic 模å¼å¯åŠ¨"
+
+msgid "-H\t\t\tStart in Hebrew mode"
+msgstr "-H\t\t\t以 Hebrew 模å¼å¯åŠ¨"
+
+msgid "-F\t\t\tStart in Farsi mode"
+msgstr "-F\t\t\t以 Farsi 模å¼å¯åŠ¨"
+
+msgid "-T <terminal>\tSet terminal type to <terminal>"
+msgstr "-T <terminal>\t设定终端类型为 <terminal>"
+
+msgid "-u <vimrc>\t\tUse <vimrc> instead of any .vimrc"
+msgstr "-u <vimrc>\t\t使用 <vimrc> 替代任何 .vimrc"
+
+msgid "-U <gvimrc>\t\tUse <gvimrc> instead of any .gvimrc"
+msgstr "-U <gvimrc>\t\t使用 <gvimrc> 替代任何 .gvimrc"
+
+msgid "--noplugin\t\tDon't load plugin scripts"
+msgstr "--noplugin\t\tä¸åŠ è½½ plugin 脚本"
+
+msgid "-p[N]\t\tOpen N tab pages (default: one for each file)"
+msgstr "-P[N]\t\t打开 N 个标签页 (默认值: æ¯ä¸ªæ–‡ä»¶ä¸€ä¸ª)"
+
+msgid "-o[N]\t\tOpen N windows (default: one for each file)"
+msgstr "-o[N]\t\t打开 N ä¸ªçª—å£ (默认值: æ¯ä¸ªæ–‡ä»¶ä¸€ä¸ª)"
+
+msgid "-O[N]\t\tLike -o but split vertically"
+msgstr "-O[N]\t\tåŒ -o 但垂直分割"
+
+msgid "+\t\t\tStart at end of file"
+msgstr "+\t\t\tå¯åŠ¨åŽè·³åˆ°æ–‡ä»¶æœ«å°¾"
+
+msgid "+<lnum>\t\tStart at line <lnum>"
+msgstr "+<lnum>\t\tå¯åŠ¨åŽè·³åˆ°ç¬¬ <lnum> è¡Œ"
+
+msgid "--cmd <command>\tExecute <command> before loading any vimrc file"
+msgstr "--cmd <command>\t加载任何 vimrc 文件å‰æ‰§è¡Œ <command>"
+
+msgid "-c <command>\t\tExecute <command> after loading the first file"
+msgstr "-c <command>\t\t加载第一个文件åŽæ‰§è¡Œ <command>"
+
+msgid "-S <session>\t\tSource file <session> after loading the first file"
+msgstr "-S <session>\t\t加载第一个文件åŽæ‰§è¡Œæ–‡ä»¶ <session>"
+
+msgid "-s <scriptin>\tRead Normal mode commands from file <scriptin>"
+msgstr "-s <scriptin>\t从文件 <scriptin> 读入正常模å¼çš„命令"
+
+msgid "-w <scriptout>\tAppend all typed commands to file <scriptout>"
+msgstr "-w <scriptout>\t将所有输入的命令追加到文件 <scriptout>"
+
+msgid "-W <scriptout>\tWrite all typed commands to file <scriptout>"
+msgstr "-W <scriptout>\t将所有输入的命令写入到文件 <scriptout>"
+
+msgid "-x\t\t\tEdit encrypted files"
+msgstr "-x\t\t\t编辑加密的文件"
+
+msgid "-display <display>\tConnect vim to this particular X-server"
+msgstr "-display <display>\t将 vim 与指定的 X-server 连接"
+
+msgid "-X\t\t\tDo not connect to X server"
+msgstr "-X\t\t\tä¸è¿žæŽ¥åˆ° X Server"
+
+msgid "--remote <files>\tEdit <files> in a Vim server if possible"
+msgstr "--remote <files>\t如有å¯èƒ½ï¼Œåœ¨ Vim æœåŠ¡å™¨ä¸Šç¼–辑文件 <files>"
+
+msgid ""
+"--remote-silent <files> Same, don't complain if there is no server"
+msgstr "--remote-silent <files> åŒä¸Šï¼Œæ‰¾ä¸åˆ°æœåŠ¡å™¨æ—¶ä¸æŠ±æ€¨"
+
+msgid ""
+"--remote-wait <files> As --remote but wait for files to have been edited"
+msgstr "--remote-wait <files> åŒ --remote 但会等待文件完æˆç¼–辑"
+
+msgid ""
+"--remote-wait-silent <files> Same, don't complain if there is no server"
+msgstr "--remote-wait-silent <files> åŒä¸Šï¼Œæ‰¾ä¸åˆ°æœåŠ¡å™¨æ—¶ä¸æŠ±æ€¨"
+
+msgid "--remote-tab <files> As --remote but open tab page for each file"
+msgstr "--remote-tab <files> åŒ --remote 但对æ¯ä¸ªæ–‡ä»¶æ‰“开一个标签页"
+
+msgid "--remote-send <keys>\tSend <keys> to a Vim server and exit"
+msgstr "--remote-send <keys>\té€å‡º <keys> 到 Vim æœåŠ¡å™¨å¹¶é€€å‡º"
+
+msgid "--remote-expr <expr>\tEvaluate <expr> in a Vim server and print result"
+msgstr "--remote-expr <expr>\t在 Vim æœåŠ¡å™¨ä¸Šæ±‚ <expr> 的值并打å°ç»“æžœ"
+
+msgid "--serverlist\t\tList available Vim server names and exit"
+msgstr "--serverlist\t\t列出å¯ç”¨çš„ Vim æœåŠ¡å™¨å称并退出"
+
+msgid "--servername <name>\tSend to/become the Vim server <name>"
+msgstr "--servername <name>\tå‘é€åˆ°æˆ–æˆä¸º Vim æœåŠ¡å™¨ <name>"
+
+msgid "-i <viminfo>\t\tUse <viminfo> instead of .viminfo"
+msgstr "-i <viminfo>\t\t使用 <viminfo> å–代 .viminfo"
+
+msgid "-h or --help\tPrint Help (this message) and exit"
+msgstr "-h 或 --help\t打å°å¸®åŠ©(本信æ¯)并退出"
+
+msgid "--version\t\tPrint version information and exit"
+msgstr "--version\t\t打å°ç‰ˆæœ¬ä¿¡æ¯å¹¶é€€å‡º"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Motif version):\n"
+msgstr ""
+"\n"
+"gvim (Motif 版本) å¯è¯†åˆ«çš„å‚æ•°:\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (neXtaw version):\n"
+msgstr ""
+"\n"
+"gvim (neXtaw 版本) å¯è¯†åˆ«çš„å‚æ•°:\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Athena version):\n"
+msgstr ""
+"\n"
+"gvim (Athena 版本) å¯è¯†åˆ«çš„å‚æ•°:\n"
+
+msgid "-display <display>\tRun vim on <display>"
+msgstr "-display <display>\t在 <display> 上è¿è¡Œ vim"
+
+msgid "-iconic\t\tStart vim iconified"
+msgstr "-iconic\t\tå¯åŠ¨åŽæœ€å°åŒ–"
+
+msgid "-name <name>\t\tUse resource as if vim was <name>"
+msgstr "-name <name>\t\tè¯»å– Resource 时把 vim 视为 <name>"
+
+msgid "\t\t\t (Unimplemented)\n"
+msgstr "\t\t\t (尚未实现)\n"
+
+msgid "-background <color>\tUse <color> for the background (also: -bg)"
+msgstr "-background <color>\t使用 <color> 作为背景色 (也å¯ç”¨ -bg)"
+
+msgid "-foreground <color>\tUse <color> for normal text (also: -fg)"
+msgstr "-foreground <color>\t使用 <color> 作为一般文字颜色 (也å¯ç”¨ -fg)"
+
+msgid "-font <font>\t\tUse <font> for normal text (also: -fn)"
+msgstr "-font <font>\t使用 <font> 作为一般字体 (也å¯ç”¨ -fn)"
+
+msgid "-boldfont <font>\tUse <font> for bold text"
+msgstr "-boldfont <font>\t使用 <font> 作为粗体字体"
+
+msgid "-italicfont <font>\tUse <font> for italic text"
+msgstr "-italicfont <font>\t使用 <font> 作为斜体字体"
+
+msgid "-geometry <geom>\tUse <geom> for initial geometry (also: -geom)"
+msgstr "-geometry <geom>\t使用 <geom> 作为åˆå§‹ä½ç½® (也å¯ç”¨ -geom)"
+
+msgid "-borderwidth <width>\tUse a border width of <width> (also: -bw)"
+msgstr "-borderwidth <width>\t设定边框宽度为 <width> (也å¯ç”¨ -bw)"
+
+msgid "-scrollbarwidth <width> Use a scrollbar width of <width> (also: -sw)"
+msgstr "-scrollbarwidth <width> 设定滚动æ¡å®½åº¦ä¸º <width> (也å¯ç”¨ -sw)"
+
+msgid "-menuheight <height>\tUse a menu bar height of <height> (also: -mh)"
+msgstr "-menuheight <height>\t设定èœå•æ é«˜åº¦ä¸º <height> (也å¯ç”¨ -mh)"
+
+msgid "-reverse\t\tUse reverse video (also: -rv)"
+msgstr "-reverse\t\t使用å显 (也å¯ç”¨ -rv)"
+
+msgid "+reverse\t\tDon't use reverse video (also: +rv)"
+msgstr "+reverse\t\tä¸ä½¿ç”¨å显 (也å¯ç”¨ +rv)"
+
+msgid "-xrm <resource>\tSet the specified resource"
+msgstr "-xrm <resource>\t设定指定的资æº"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (RISC OS version):\n"
+msgstr ""
+"\n"
+"gvim (RISC OS 版本) å¯è¯†åˆ«çš„å‚æ•°:\n"
+
+msgid "--columns <number>\tInitial width of window in columns"
+msgstr "--columns <number>\t窗å£åˆå§‹å®½åº¦"
+
+msgid "--rows <number>\tInitial height of window in rows"
+msgstr "--rows <number>\t窗å£åˆå§‹é«˜åº¦"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (GTK+ version):\n"
+msgstr ""
+"\n"
+"gvim (GTK+ 版本) å¯è¯†åˆ«çš„å‚æ•°:\n"
+
+msgid "-display <display>\tRun vim on <display> (also: --display)"
+msgstr "-display <display>\t在 <display> 上è¿è¡Œ vim (也å¯ç”¨ --display)"
+
+msgid "--role <role>\tSet a unique role to identify the main window"
+msgstr "--role <role>\t设置用于区分主窗å£çš„窗å£è§’色å"
+
+msgid "--socketid <xid>\tOpen Vim inside another GTK widget"
+msgstr "--socketid <xid>\t在å¦ä¸€ä¸ª GTK 部件中打开 Vim"
+
+msgid "-P <parent title>\tOpen Vim inside parent application"
+msgstr "-P <parent title>\t在父应用程åºä¸­æ‰“å¼€ Vim"
+
+msgid "No display"
+msgstr "没有 display"
+
+#. Failed to send, abort.
+msgid ": Send failed.\n"
+msgstr ": å‘é€å¤±è´¥ã€‚\n"
+
+#. Let vim start normally.
+msgid ": Send failed. Trying to execute locally\n"
+msgstr ": å‘é€å¤±è´¥ã€‚å°è¯•æœ¬åœ°æ‰§è¡Œ\n"
+
+#, c-format
+msgid "%d of %d edited"
+msgstr "%d 中 %d 已编辑"
+
+msgid "No display: Send expression failed.\n"
+msgstr "没有 display: å‘é€è¡¨è¾¾å¼å¤±è´¥ã€‚\n"
+
+msgid ": Send expression failed.\n"
+msgstr ": å‘é€è¡¨è¾¾å¼å¤±è´¥ã€‚\n"
+
+msgid "No marks set"
+msgstr "没有设定标记"
+
+#, c-format
+msgid "E283: No marks matching \"%s\""
+msgstr "E283: æ²¡æœ‰åŒ¹é… \"%s\" 的标记"
+
+#. Highlight title
+msgid ""
+"\n"
+"mark line col file/text"
+msgstr ""
+"\n"
+"标记 行 列 文件/文本"
+
+#. Highlight title
+msgid ""
+"\n"
+" jump line col file/text"
+msgstr ""
+"\n"
+" 跳转 行 列 文件/文本"
+
+#. Highlight title
+msgid ""
+"\n"
+"change line col text"
+msgstr ""
+"\n"
+" æ”¹å˜ è¡Œ 列 文本"
+
+#, c-format
+msgid ""
+"\n"
+"# File marks:\n"
+msgstr ""
+"\n"
+"# 文件标记:\n"
+
+#. Write the jumplist with -'
+#, c-format
+msgid ""
+"\n"
+"# Jumplist (newest first):\n"
+msgstr ""
+"\n"
+"# 跳转列表 (从新到旧):\n"
+
+#, c-format
+msgid ""
+"\n"
+"# History of marks within files (newest to oldest):\n"
+msgstr ""
+"\n"
+"# 文件内的标记历å²è®°å½• (从新到旧):\n"
+
+msgid "Missing '>'"
+msgstr "缺少 '>'"
+
+msgid "E543: Not a valid codepage"
+msgstr "E543: 无效的代ç é¡µ"
+
+msgid "E284: Cannot set IC values"
+msgstr "E284: ä¸èƒ½è®¾å®š IC 值"
+
+msgid "E285: Failed to create input context"
+msgstr "E285: 无法创建输入上下文"
+
+msgid "E286: Failed to open input method"
+msgstr "E286: 无法打开输入法"
+
+msgid "E287: Warning: Could not set destroy callback to IM"
+msgstr "E287: 警告: 无法设定输入法的释放回调函数"
+
+msgid "E288: input method doesn't support any style"
+msgstr "E288: 输入法ä¸æ”¯æŒä»»ä½•é£Žæ ¼"
+
+msgid "E289: input method doesn't support my preedit type"
+msgstr "E289: 输入法ä¸æ”¯æŒæˆ‘的预编辑类型"
+
+msgid "E290: over-the-spot style requires fontset"
+msgstr "E290: over-the-spot é£Žæ ¼éœ€è¦ Fontset"
+
+msgid "E291: Your GTK+ is older than 1.2.3. Status area disabled"
+msgstr "E291: ä½ çš„ GTK+ 比 1.2.3 旧。状æ€åŒºä¸å¯ç”¨ã€‚"
+
+msgid "E292: Input Method Server is not running"
+msgstr "E292: 输入法æœåŠ¡å™¨æœªè¿è¡Œ"
+
+msgid "E293: block was not locked"
+msgstr "E293: å—未被é”定"
+
+msgid "E294: Seek error in swap file read"
+msgstr "E294: 交æ¢æ–‡ä»¶è¯»å–定ä½é”™è¯¯"
+
+msgid "E295: Read error in swap file"
+msgstr "E295: 交æ¢æ–‡ä»¶è¯»å–错误"
+
+msgid "E296: Seek error in swap file write"
+msgstr "E296: 交æ¢æ–‡ä»¶å†™å…¥å®šä½é”™è¯¯"
+
+msgid "E297: Write error in swap file"
+msgstr "E297: 交æ¢æ–‡ä»¶å†™å…¥é”™è¯¯"
+
+msgid "E300: Swap file already exists (symlink attack?)"
+msgstr "E300: 交æ¢æ–‡ä»¶å·²å­˜åœ¨ (符å·è¿žæŽ¥æ”»å‡»ï¼Ÿ)"
+
+msgid "E298: Didn't get block nr 0?"
+msgstr "E298: 找ä¸åˆ°å— 0?"
+
+msgid "E298: Didn't get block nr 1?"
+msgstr "E298: 找ä¸åˆ°å— 1?"
+
+msgid "E298: Didn't get block nr 2?"
+msgstr "E298: 找ä¸åˆ°å— 2?"
+
+#. could not (re)open the swap file, what can we do????
+msgid "E301: Oops, lost the swap file!!!"
+msgstr "E301: 噢,交æ¢æ–‡ä»¶ä¸è§äº†ï¼ï¼ï¼"
+
+msgid "E302: Could not rename swap file"
+msgstr "E302: 无法é‡å‘½å交æ¢æ–‡ä»¶"
+
+#, c-format
+msgid "E303: Unable to open swap file for \"%s\", recovery impossible"
+msgstr "E303: 无法打开 \"%s\" 的交æ¢æ–‡ä»¶ï¼Œæ¢å¤å°†ä¸å¯èƒ½"
+
+msgid "E304: ml_upd_block0(): Didn't get block 0??"
+msgstr "E304: ml_upd_block0(): 找ä¸åˆ°å— 0?"
+
+#, c-format
+msgid "E305: No swap file found for %s"
+msgstr "E305: 找ä¸åˆ° %s 的交æ¢æ–‡ä»¶"
+
+msgid "Enter number of swap file to use (0 to quit): "
+msgstr "请输入è¦ä½¿ç”¨çš„交æ¢æ–‡ä»¶ç¼–å· (0 退出): "
+
+#, c-format
+msgid "E306: Cannot open %s"
+msgstr "E306: 无法打开 %s"
+
+msgid "Unable to read block 0 from "
+msgstr "无法读å–å— 0: "
+
+msgid ""
+"\n"
+"Maybe no changes were made or Vim did not update the swap file."
+msgstr ""
+"\n"
+"å¯èƒ½ä½ æ²¡åšè¿‡ä»»ä½•ä¿®æ”¹æˆ–是 Vim 还æ¥ä¸åŠæ›´æ–°äº¤æ¢æ–‡ä»¶ã€‚"
+
+msgid " cannot be used with this version of Vim.\n"
+msgstr " ä¸èƒ½åœ¨è¯¥ç‰ˆæœ¬çš„ Vim 中使用。\n"
+
+msgid "Use Vim version 3.0.\n"
+msgstr "使用 Vim 3.0。\n"
+
+#, c-format
+msgid "E307: %s does not look like a Vim swap file"
+msgstr "E307: %s 看起æ¥ä¸åƒæ˜¯ Vim 交æ¢æ–‡ä»¶"
+
+msgid " cannot be used on this computer.\n"
+msgstr " ä¸èƒ½åœ¨è¿™å°ç”µè„‘上使用。\n"
+
+msgid "The file was created on "
+msgstr "此文件创建于 "
+
+msgid ""
+",\n"
+"or the file has been damaged."
+msgstr ""
+",\n"
+"或是此文件已æŸå。"
+
+#, c-format
+msgid "Using swap file \"%s\""
+msgstr "使用交æ¢æ–‡ä»¶ \"%s\""
+
+#, c-format
+msgid "Original file \"%s\""
+msgstr "原始文件 \"%s\""
+
+msgid "E308: Warning: Original file may have been changed"
+msgstr "E308: 警告: 原始文件å¯èƒ½å·²è¢«ä¿®æ”¹"
+
+#, c-format
+msgid "E309: Unable to read block 1 from %s"
+msgstr "E309: 无法从 %s 读å–å— 1"
+
+# do not translate to avoid writing Chinese in files
+#, fuzzy
+#~ msgid "???MANY LINES MISSING"
+#~ msgstr "???缺少了太多行"
+
+# do not translate to avoid writing Chinese in files
+#, fuzzy
+#~ msgid "???LINE COUNT WRONG"
+#~ msgstr "???行数错误"
+
+# do not translate to avoid writing Chinese in files
+#, fuzzy
+#~ msgid "???EMPTY BLOCK"
+#~ msgstr "???空的å—"
+
+# do not translate to avoid writing Chinese in files
+#, fuzzy
+#~ msgid "???LINES MISSING"
+#~ msgstr "???缺少了一些行"
+
+#, c-format
+msgid "E310: Block 1 ID wrong (%s not a .swp file?)"
+msgstr "E310: å— 1 ID 错误 (%s ä¸æ˜¯äº¤æ¢æ–‡ä»¶ï¼Ÿ)"
+
+# do not translate to avoid writing Chinese in files
+#, fuzzy
+#~ msgid "???BLOCK MISSING"
+#~ msgstr "???缺少å—"
+
+# do not translate to avoid writing Chinese in files
+#, fuzzy
+#~ msgid "??? from here until ???END lines may be messed up"
+#~ msgstr "??? 从这里到 ???END çš„è¡Œå¯èƒ½å·²æ··ä¹±"
+
+# do not translate to avoid writing Chinese in files
+#, fuzzy
+#~ msgid "??? from here until ???END lines may have been inserted/deleted"
+#~ msgstr "??? 从这里到 ???END çš„è¡Œå¯èƒ½å·²è¢«æ’å…¥/删除过"
+
+# do not translate to avoid writing Chinese in files
+#, fuzzy
+#~ msgid "???END"
+#~ msgstr "???END"
+
+msgid "E311: Recovery Interrupted"
+msgstr "E311: æ¢å¤å·²è¢«ä¸­æ–­"
+
+msgid ""
+"E312: Errors detected while recovering; look for lines starting with ???"
+msgstr "E312: æ¢å¤æ—¶å‘生错误;请注æ„开头为 ??? çš„è¡Œ"
+
+msgid "See \":help E312\" for more information."
+msgstr "更多信æ¯è¯·è§ \":help E312\""
+
+msgid "Recovery completed. You should check if everything is OK."
+msgstr "æ¢å¤å®Œæ¯•ã€‚请确定一切正常。"
+
+msgid ""
+"\n"
+"(You might want to write out this file under another name\n"
+msgstr ""
+"\n"
+"(ä½ å¯èƒ½æƒ³è¦å°†è¿™ä¸ªæ–‡ä»¶å¦å­˜ä¸ºåˆ«çš„文件å\n"
+
+msgid "and run diff with the original file to check for changes)\n"
+msgstr "å†è¿è¡Œ diff 与原文件比较以检查是å¦æœ‰æ”¹å˜)\n"
+
+msgid ""
+"Delete the .swp file afterwards.\n"
+"\n"
+msgstr ""
+"然åŽæŠŠ .swp 文件删掉。\n"
+"\n"
+
+#. use msg() to start the scrolling properly
+msgid "Swap files found:"
+msgstr "找到交æ¢æ–‡ä»¶:"
+
+msgid " In current directory:\n"
+msgstr " ä½äºŽå½“å‰ç›®å½•:\n"
+
+msgid " Using specified name:\n"
+msgstr " 使用指定的åå­—:\n"
+
+msgid " In directory "
+msgstr " ä½äºŽç›®å½• "
+
+msgid " -- none --\n"
+msgstr " -- æ—  --\n"
+
+msgid " owned by: "
+msgstr " 所有者: "
+
+msgid " dated: "
+msgstr " 日期: "
+
+msgid " dated: "
+msgstr " 日期: "
+
+msgid " [from Vim version 3.0]"
+msgstr " [æ¥è‡ª Vim 版本 3.0]"
+
+msgid " [does not look like a Vim swap file]"
+msgstr " [ä¸åƒæ˜¯ Vim 交æ¢æ–‡ä»¶]"
+
+msgid " file name: "
+msgstr " 文件å: "
+
+msgid ""
+"\n"
+" modified: "
+msgstr ""
+"\n"
+" 修改过: "
+
+msgid "YES"
+msgstr "是"
+
+msgid "no"
+msgstr "å¦"
+
+msgid ""
+"\n"
+" user name: "
+msgstr ""
+"\n"
+" 用户å: "
+
+msgid " host name: "
+msgstr " 主机å: "
+
+msgid ""
+"\n"
+" host name: "
+msgstr ""
+"\n"
+" 主机å: "
+
+msgid ""
+"\n"
+" process ID: "
+msgstr ""
+"\n"
+" 进程 ID: "
+
+msgid " (still running)"
+msgstr " (ä»åœ¨è¿è¡Œ)"
+
+msgid ""
+"\n"
+" [not usable with this version of Vim]"
+msgstr ""
+"\n"
+" [ä¸èƒ½åœ¨è¯¥ç‰ˆæœ¬çš„ Vim 上使用]"
+
+msgid ""
+"\n"
+" [not usable on this computer]"
+msgstr ""
+"\n"
+" [ä¸èƒ½åœ¨æœ¬æœºä¸Šä½¿ç”¨]"
+
+msgid " [cannot be read]"
+msgstr " [无法读å–]"
+
+msgid " [cannot be opened]"
+msgstr " [无法打开]"
+
+msgid "E313: Cannot preserve, there is no swap file"
+msgstr "E313: 无法ä¿ç•™ï¼Œæ²¡æœ‰äº¤æ¢æ–‡ä»¶"
+
+msgid "File preserved"
+msgstr "文件已ä¿ç•™"
+
+msgid "E314: Preserve failed"
+msgstr "E314: ä¿ç•™å¤±è´¥"
+
+#, c-format
+msgid "E315: ml_get: invalid lnum: %ld"
+msgstr "E315: ml_get: 无效的 lnum: %ld"
+
+#, c-format
+msgid "E316: ml_get: cannot find line %ld"
+msgstr "E316: ml_get: 找ä¸åˆ°ç¬¬ %ld è¡Œ"
+
+msgid "E317: pointer block id wrong 3"
+msgstr "E317: æŒ‡é’ˆå— id 错误 3"
+
+msgid "stack_idx should be 0"
+msgstr "stack_idx 应该是 0"
+
+msgid "E318: Updated too many blocks?"
+msgstr "E318: 更新了太多的å—?"
+
+msgid "E317: pointer block id wrong 4"
+msgstr "E317: æŒ‡é’ˆå— id 错误 4"
+
+msgid "deleted block 1?"
+msgstr "åˆ é™¤äº†å— 1?"
+
+#, c-format
+msgid "E320: Cannot find line %ld"
+msgstr "E320: 找ä¸åˆ°ç¬¬ %ld è¡Œ"
+
+msgid "E317: pointer block id wrong"
+msgstr "E317: æŒ‡é’ˆå— id 错误"
+
+msgid "pe_line_count is zero"
+msgstr "pe_line_count 为零"
+
+#, c-format
+msgid "E322: line number out of range: %ld past the end"
+msgstr "E322: è¡Œå·è¶…出范围: %ld 超出结尾"
+
+#, c-format
+msgid "E323: line count wrong in block %ld"
+msgstr "E323: å— %ld 行数错误"
+
+msgid "Stack size increases"
+msgstr "堆栈大å°å¢žåŠ "
+
+msgid "E317: pointer block id wrong 2"
+msgstr "E317: æŒ‡é’ˆå— id 错误 2"
+
+#, c-format
+msgid "E773: Symlink loop for \"%s\""
+msgstr "E773: \"%s\" 符å·è¿žæŽ¥å‡ºçŽ°å¾ªçŽ¯"
+
+msgid "E325: ATTENTION"
+msgstr "E325: 注æ„"
+
+msgid ""
+"\n"
+"Found a swap file by the name \""
+msgstr ""
+"\n"
+"å‘现交æ¢æ–‡ä»¶ \""
+
+msgid "While opening file \""
+msgstr "正在打开文件 \""
+
+msgid " NEWER than swap file!\n"
+msgstr " 比交æ¢æ–‡ä»¶æ–°ï¼\n"
+
+#. Some of these messages are long to allow translation to
+#. * other languages.
+msgid ""
+"\n"
+"(1) Another program may be editing the same file.\n"
+" If this is the case, be careful not to end up with two\n"
+" different instances of the same file when making changes.\n"
+msgstr ""
+"\n"
+"(1) å¦ä¸€ä¸ªç¨‹åºå¯èƒ½ä¹Ÿåœ¨ç¼–辑åŒä¸€ä¸ªæ–‡ä»¶ã€‚\n"
+" 如果是这样,修改时请注æ„é¿å…åŒä¸€ä¸ªæ–‡ä»¶äº§ç”Ÿä¸¤ä¸ªä¸åŒçš„版本。\n"
+"\n"
+
+msgid " Quit, or continue with caution.\n"
+msgstr " 退出,或å°å¿ƒåœ°ç»§ç»­ã€‚\n"
+
+msgid ""
+"\n"
+"(2) An edit session for this file crashed.\n"
+msgstr ""
+"\n"
+"(2) 上次编辑此文件时崩溃。\n"
+
+msgid " If this is the case, use \":recover\" or \"vim -r "
+msgstr " 如果是这样,请用 \":recover\" 或 \"vim -r "
+
+msgid ""
+"\"\n"
+" to recover the changes (see \":help recovery\").\n"
+msgstr ""
+"\"\n"
+" æ¢å¤ä¿®æ”¹çš„内容 (è¯·è§ \":help recovery\")。\n"
+
+msgid " If you did this already, delete the swap file \""
+msgstr " 如果你已ç»è¿›è¡Œäº†æ¢å¤ï¼Œè¯·åˆ é™¤äº¤æ¢æ–‡ä»¶ \""
+
+msgid ""
+"\"\n"
+" to avoid this message.\n"
+msgstr ""
+"\"\n"
+" 以é¿å…å†çœ‹åˆ°æ­¤æ¶ˆæ¯ã€‚\n"
+
+msgid "Swap file \""
+msgstr "交æ¢æ–‡ä»¶ \""
+
+msgid "\" already exists!"
+msgstr "\" 已存在ï¼"
+
+msgid "VIM - ATTENTION"
+msgstr "VIM - 注æ„"
+
+msgid "Swap file already exists!"
+msgstr "交æ¢æ–‡ä»¶å·²å­˜åœ¨ï¼"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"以åªè¯»æ–¹å¼æ‰“å¼€(&O)\n"
+"直接编辑(&E)\n"
+"æ¢å¤(&R)\n"
+"退出(&Q)\n"
+"中止(&A)"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Delete it\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"以åªè¯»æ–¹å¼æ‰“å¼€(&O)\n"
+"直接编辑(&E)\n"
+"æ¢å¤(&R)\n"
+"删除交æ¢æ–‡ä»¶(&D)\n"
+"退出(&Q)\n"
+"中止(&A)"
+
+msgid "E326: Too many swap files found"
+msgstr "E326: 找到太多交æ¢æ–‡ä»¶"
+
+msgid "E327: Part of menu-item path is not sub-menu"
+msgstr "E327: èœå•é¡¹çš„æŸéƒ¨åˆ†è·¯å¾„ä¸æ˜¯å­èœå•"
+
+msgid "E328: Menu only exists in another mode"
+msgstr "E328: èœå•åªåœ¨å…¶å®ƒæ¨¡å¼ä¸­å­˜åœ¨"
+
+#, c-format
+msgid "E329: No menu \"%s\""
+msgstr "E329: 没有èœå• \"%s\""
+
+msgid "E330: Menu path must not lead to a sub-menu"
+msgstr "E330: èœå•è·¯å¾„ä¸èƒ½æŒ‡å‘å­èœå•"
+
+msgid "E331: Must not add menu items directly to menu bar"
+msgstr "E331: ä¸èƒ½æŠŠèœå•é¡¹ç›´æŽ¥åŠ åˆ°èœå•æ ä¸­"
+
+msgid "E332: Separator cannot be part of a menu path"
+msgstr "E332: 分隔线ä¸èƒ½æ˜¯èœå•è·¯å¾„的一部分"
+
+#. Now we have found the matching menu, and we list the mappings
+#. Highlight title
+msgid ""
+"\n"
+"--- Menus ---"
+msgstr ""
+"\n"
+"--- èœå• ---"
+
+msgid "Tear off this menu"
+msgstr "撕下此èœå•"
+
+msgid "E333: Menu path must lead to a menu item"
+msgstr "E333: èœå•è·¯å¾„必须指å‘èœå•é¡¹"
+
+#, c-format
+msgid "E334: Menu not found: %s"
+msgstr "E334: 找ä¸åˆ°èœå•: %s"
+
+#, c-format
+msgid "E335: Menu not defined for %s mode"
+msgstr "E335: %s 模å¼ä¸­èœå•æœªå®šä¹‰"
+
+msgid "E336: Menu path must lead to a sub-menu"
+msgstr "E336: èœå•è·¯å¾„必须指å‘å­èœå•"
+
+msgid "E337: Menu not found - check menu names"
+msgstr "E337: 找ä¸åˆ°èœå• - 请检查èœå•å称"
+
+#, c-format
+msgid "Error detected while processing %s:"
+msgstr "å¤„ç† %s æ—¶å‘生错误:"
+
+#, c-format
+msgid "line %4ld:"
+msgstr "第 %4ld 行:"
+
+#, c-format
+msgid "E354: Invalid register name: '%s'"
+msgstr "E354: 无效的寄存器å: '%s'"
+
+msgid "Messages maintainer: Bram Moolenaar <Bram@vim.org>"
+msgstr "简体中文消æ¯ç»´æŠ¤è€…: Yuheng Xie <elephant@linux.net.cn>"
+
+msgid "Interrupt: "
+msgstr "已中断: "
+
+msgid "Press ENTER or type command to continue"
+msgstr "请按 ENTER 或其它命令继续"
+
+#, c-format
+msgid "%s line %ld"
+msgstr "%s 第 %ld 行"
+
+msgid "-- More --"
+msgstr "-- 更多 --"
+
+msgid " SPACE/d/j: screen/page/line down, b/u/k: up, q: quit "
+msgstr " 空格/d/j: å±å¹•/页/è¡Œ 下翻,b/u/k: 上翻,q: 退出 "
+
+msgid "Question"
+msgstr "问题"
+
+msgid ""
+"&Yes\n"
+"&No"
+msgstr ""
+"是(&Y)\n"
+"å¦(&N)"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"Save &All\n"
+"&Discard All\n"
+"&Cancel"
+msgstr ""
+"是(&Y)\n"
+"å¦(&N)\n"
+"全部ä¿å­˜(&A)\n"
+"全部丢弃(&D)\n"
+"å–消(&C)"
+
+msgid "Select Directory dialog"
+msgstr "选择目录对è¯æ¡†"
+
+msgid "Save File dialog"
+msgstr "ä¿å­˜æ–‡ä»¶å¯¹è¯æ¡†"
+
+msgid "Open File dialog"
+msgstr "打开文件对è¯æ¡†"
+
+#. TODO: non-GUI file selector here
+msgid "E338: Sorry, no file browser in console mode"
+msgstr "E338: 抱歉,控制å°æ¨¡å¼ä¸‹æ²¡æœ‰æ–‡ä»¶æµè§ˆå™¨"
+
+msgid "E766: Insufficient arguments for printf()"
+msgstr "E766: printf() çš„å‚æ•°ä¸è¶³"
+
+msgid "E767: Too many arguments to printf()"
+msgstr "E767: printf() çš„å‚数过多"
+
+msgid "W10: Warning: Changing a readonly file"
+msgstr "W10: 警告: 正在修改一个åªè¯»æ–‡ä»¶"
+
+msgid "Type number or click with mouse (<Enter> cancels): "
+msgstr "请输入数字或点击鼠标 (<Enter> å–消): "
+
+msgid "Choice number (<Enter> cancels): "
+msgstr "请选择数字 (<Enter> å–消): "
+
+msgid "1 more line"
+msgstr "多了 1 行"
+
+msgid "1 line less"
+msgstr "少了 1 行"
+
+#, c-format
+msgid "%ld more lines"
+msgstr "多了 %ld 行"
+
+#, c-format
+msgid "%ld fewer lines"
+msgstr "少了 %ld 行"
+
+msgid " (Interrupted)"
+msgstr " (已中断)"
+
+msgid "Beep!"
+msgstr "Beep!"
+
+msgid "Vim: preserving files...\n"
+msgstr "Vim: 正在ä¿ç•™æ–‡ä»¶â€¦â€¦\n"
+
+#. close all memfiles, without deleting
+msgid "Vim: Finished.\n"
+msgstr "Vim: 结æŸã€‚\n"
+
+#, c-format
+msgid "ERROR: "
+msgstr "错误: "
+
+#, c-format
+msgid ""
+"\n"
+"[bytes] total alloc-freed %lu-%lu, in use %lu, peak use %lu\n"
+msgstr ""
+"\n"
+"[字节] 总共 alloc-free %lu-%lu,使用中 %lu,高峰使用 %lu\n"
+
+#, c-format
+msgid ""
+"[calls] total re/malloc()'s %lu, total free()'s %lu\n"
+"\n"
+msgstr ""
+"[调用] 总共 re/malloc(): %lu,总共 free()': %lu\n"
+"\n"
+
+msgid "E340: Line is becoming too long"
+msgstr "E340: 此行过长"
+
+#, c-format
+msgid "E341: Internal error: lalloc(%ld, )"
+msgstr "E341: 内部错误: lalloc(%ld, )"
+
+#, c-format
+msgid "E342: Out of memory! (allocating %lu bytes)"
+msgstr "E342: 内存ä¸è¶³ï¼(åˆ†é… %lu 字节)"
+
+#, c-format
+msgid "Calling shell to execute: \"%s\""
+msgstr "调用 shell 执行: \"%s\""
+
+msgid "E545: Missing colon"
+msgstr "E545: 缺少冒å·"
+
+msgid "E546: Illegal mode"
+msgstr "E546: 无效的模å¼"
+
+msgid "E547: Illegal mouseshape"
+msgstr "E547: 无效的鼠标形状"
+
+msgid "E548: digit expected"
+msgstr "E548: 此处需è¦æ•°å­—"
+
+msgid "E549: Illegal percentage"
+msgstr "E549: 无效的百分比"
+
+msgid "Enter encryption key: "
+msgstr "输入密ç : "
+
+msgid "Enter same key again: "
+msgstr "请å†è¾“入一次: "
+
+msgid "Keys don't match!"
+msgstr "两次密ç ä¸åŒ¹é…ï¼"
+
+#, c-format
+msgid ""
+"E343: Invalid path: '**[number]' must be at the end of the path or be "
+"followed by '%s'."
+msgstr "E343: 无效的路径: '**[number]' 必须在路径末尾或者åŽé¢æŽ¥ '%s'。"
+
+#, c-format
+msgid "E344: Can't find directory \"%s\" in cdpath"
+msgstr "E344: cdpath 中找ä¸åˆ°ç›®å½• \"%s\""
+
+#, c-format
+msgid "E345: Can't find file \"%s\" in path"
+msgstr "E345: 在路径中找ä¸åˆ°æ–‡ä»¶ \"%s\""
+
+#, c-format
+msgid "E346: No more directory \"%s\" found in cdpath"
+msgstr "E346: 在路径中找ä¸åˆ°æ›´å¤šçš„文件 \"%s\""
+
+#, c-format
+msgid "E347: No more file \"%s\" found in path"
+msgstr "E347: 在路径中找ä¸åˆ°æ›´å¤šçš„文件 \"%s\""
+
+#. Get here when the server can't be found.
+msgid "Cannot connect to Netbeans #2"
+msgstr "无法连接到 Netbeans #2"
+
+msgid "Cannot connect to Netbeans"
+msgstr "无法连接到 Netbeans"
+
+#, c-format
+msgid "E668: Wrong access mode for NetBeans connection info file: \"%s\""
+msgstr "E668: NetBeans 连接信æ¯æ–‡ä»¶ä¸­é”™è¯¯çš„访问模å¼: \"%s\""
+
+msgid "read from Netbeans socket"
+msgstr "从 Netbeans 套接字读å–"
+
+#, c-format
+msgid "E658: NetBeans connection lost for buffer %ld"
+msgstr "E658: 缓冲区 %ld 丢失 NetBeans 连接"
+
+msgid "E505: "
+msgstr "E505: "
+
+msgid "E774: 'operatorfunc' is empty"
+msgstr "E774: 'operatorfunc' 为空"
+
+msgid "E775: Eval feature not available"
+msgstr "E775: 求值功能ä¸å¯ç”¨"
+
+msgid "Warning: terminal cannot highlight"
+msgstr "警告: 你的终端ä¸èƒ½æ˜¾ç¤ºé«˜äº®"
+
+msgid "E348: No string under cursor"
+msgstr "E348: 光标处没有字符串"
+
+msgid "E349: No identifier under cursor"
+msgstr "E349: 光标处没有识别字"
+
+msgid "E352: Cannot erase folds with current 'foldmethod'"
+msgstr "E352: ä¸èƒ½åœ¨å½“å‰çš„ 'foldmethod' 下删除 fold"
+
+msgid "E664: changelist is empty"
+msgstr "E664: 改å˜åˆ—表为空"
+
+msgid "E662: At start of changelist"
+msgstr "E662: 已在改å˜åˆ—表的开始处"
+
+msgid "E663: At end of changelist"
+msgstr "E663: 已在改å˜åˆ—表的末尾处"
+
+msgid "Type :quit<Enter> to exit Vim"
+msgstr "输入 :quit<Enter> 退出 Vim"
+
+#, c-format
+msgid "1 line %sed 1 time"
+msgstr "1 行 %s 了 1 次"
+
+#, c-format
+msgid "1 line %sed %d times"
+msgstr "1 行 %s 了 %d 次"
+
+#, c-format
+msgid "%ld lines %sed 1 time"
+msgstr "%ld 行 %s 了 1 次"
+
+#, c-format
+msgid "%ld lines %sed %d times"
+msgstr "%ld 行 %s 了 %d 次"
+
+#, c-format
+msgid "%ld lines to indent... "
+msgstr "缩进 %ld 行…… "
+
+msgid "1 line indented "
+msgstr "缩进了 1 行 "
+
+#, c-format
+msgid "%ld lines indented "
+msgstr "缩进了 %ld 行 "
+
+msgid "E748: No previously used register"
+msgstr "E748: 没有å‰ä¸€ä¸ªä½¿ç”¨çš„寄存器"
+
+#. must display the prompt
+msgid "cannot yank; delete anyway"
+msgstr "无法å¤åˆ¶ï¼›æ”¹ä¸ºåˆ é™¤"
+
+msgid "1 line changed"
+msgstr "改å˜äº† 1 è¡Œ"
+
+#, c-format
+msgid "%ld lines changed"
+msgstr "改å˜äº† %ld è¡Œ"
+
+#, c-format
+msgid "freeing %ld lines"
+msgstr "释放了 %ld 行"
+
+msgid "block of 1 line yanked"
+msgstr "å¤åˆ¶äº† 1 行的å—"
+
+msgid "1 line yanked"
+msgstr "å¤åˆ¶äº† 1 è¡Œ"
+
+#, c-format
+msgid "block of %ld lines yanked"
+msgstr "å¤åˆ¶äº† %ld 行的å—"
+
+#, c-format
+msgid "%ld lines yanked"
+msgstr "å¤åˆ¶äº† %ld è¡Œ"
+
+#, c-format
+msgid "E353: Nothing in register %s"
+msgstr "E353: 寄存器 %s 里没有东西"
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Registers ---"
+msgstr ""
+"\n"
+"--- 寄存器 ---"
+
+msgid "Illegal register name"
+msgstr "无效的寄存器å"
+
+#, c-format
+msgid ""
+"\n"
+"# Registers:\n"
+msgstr ""
+"\n"
+"# 寄存器:\n"
+
+#, c-format
+msgid "E574: Unknown register type %d"
+msgstr "E574: 未知的寄存器类型 %d"
+
+#, c-format
+msgid "%ld Cols; "
+msgstr "%ld 列; "
+
+#, c-format
+msgid "Selected %s%ld of %ld Lines; %ld of %ld Words; %ld of %ld Bytes"
+msgstr "选择了 %s%ld/%ld è¡Œ; %ld/%ld 个è¯; %ld/%ld 个字节"
+
+#, c-format
+msgid ""
+"Selected %s%ld of %ld Lines; %ld of %ld Words; %ld of %ld Chars; %ld of %ld "
+"Bytes"
+msgstr "选择了 %s%ld/%ld è¡Œ; %ld/%ld 个è¯; %ld/%ld 个字符; %ld/%ld 个字节"
+
+#, c-format
+msgid "Col %s of %s; Line %ld of %ld; Word %ld of %ld; Byte %ld of %ld"
+msgstr "第 %s/%s 列; 第 %ld/%ld è¡Œ; 第 %ld/%ld 个è¯; 第 %ld/%ld 个字节"
+
+#, c-format
+msgid ""
+"Col %s of %s; Line %ld of %ld; Word %ld of %ld; Char %ld of %ld; Byte %ld of "
+"%ld"
+msgstr ""
+"第 %s/%s 列; 第 %ld/%ld è¡Œ; 第 %ld/%ld 个è¯; 第 %ld/%ld 个字符; 第 %ld/%ld 个"
+"字节"
+
+#, c-format
+#~ msgid "(+%ld for BOM)"
+#~ msgstr ""
+
+#~ msgid "%<%f%h%m%=Page %N"
+#~ msgstr ""
+
+msgid "Thanks for flying Vim"
+msgstr "感谢您选择 Vim"
+
+msgid "E518: Unknown option"
+msgstr "E518: 未知的选项"
+
+msgid "E519: Option not supported"
+msgstr "E519: ä¸æ”¯æŒè¯¥é€‰é¡¹"
+
+msgid "E520: Not allowed in a modeline"
+msgstr "E520: ä¸å…许在 modeline 中使用"
+
+msgid "E521: Number required after ="
+msgstr "E521: = åŽé¢éœ€è¦æ•°å­—"
+
+msgid "E522: Not found in termcap"
+msgstr "E522: Termcap 里é¢æ‰¾ä¸åˆ°"
+
+#, c-format
+msgid "E539: Illegal character <%s>"
+msgstr "E539: 无效的字符 <%s>"
+
+msgid "E529: Cannot set 'term' to empty string"
+msgstr "E529: ä¸èƒ½è®¾å®š 'term' 为空字符串"
+
+msgid "E530: Cannot change term in GUI"
+msgstr "E530: 在图形界é¢ä¸­ä¸èƒ½æ”¹å˜ç»ˆç«¯"
+
+msgid "E531: Use \":gui\" to start the GUI"
+msgstr "E531: 请用 \":gui\" å¯åŠ¨å›¾å½¢ç•Œé¢"
+
+msgid "E589: 'backupext' and 'patchmode' are equal"
+msgstr "E589: 'backupext' 和 'patchmode' 相等"
+
+msgid "E617: Cannot be changed in the GTK+ 2 GUI"
+msgstr "E617: 在 GTK+ 2 图形界é¢ä¸­ä¸èƒ½æ›´æ”¹"
+
+msgid "E524: Missing colon"
+msgstr "E524: 缺少冒å·"
+
+msgid "E525: Zero length string"
+msgstr "E525: 字符串长度为零"
+
+#, c-format
+msgid "E526: Missing number after <%s>"
+msgstr "E526: <%s> åŽé¢ç¼ºå°‘æ•°å­—"
+
+msgid "E527: Missing comma"
+msgstr "E527: 缺少逗å·"
+
+msgid "E528: Must specify a ' value"
+msgstr "E528: 必须指定一个 ' 值"
+
+msgid "E595: contains unprintable or wide character"
+msgstr "E595: 包å«ä¸å¯æ˜¾ç¤ºå­—符或宽字符"
+
+msgid "E596: Invalid font(s)"
+msgstr "E596: 无效的字体"
+
+msgid "E597: can't select fontset"
+msgstr "E597: 无法选择 Fontset"
+
+msgid "E598: Invalid fontset"
+msgstr "E598: 无效的 Fontset"
+
+msgid "E533: can't select wide font"
+msgstr "E533: 无法选择宽字体"
+
+msgid "E534: Invalid wide font"
+msgstr "E534: 无效的宽字体"
+
+#, c-format
+msgid "E535: Illegal character after <%c>"
+msgstr "E535: <%c> åŽé¢æœ‰æ— æ•ˆçš„字符"
+
+msgid "E536: comma required"
+msgstr "E536: 需è¦é€—å·"
+
+#, c-format
+msgid "E537: 'commentstring' must be empty or contain %s"
+msgstr "E537: 'commentstring' å¿…é¡»ä¸ºç©ºæˆ–åŒ…å« %s"
+
+msgid "E538: No mouse support"
+msgstr "E538: ä¸æ”¯æŒé¼ æ ‡"
+
+msgid "E540: Unclosed expression sequence"
+msgstr "E540: 没有结æŸçš„表达å¼åºåˆ—"
+
+msgid "E541: too many items"
+msgstr "E541: 项目过多"
+
+msgid "E542: unbalanced groups"
+msgstr "E542: 错乱的组"
+
+msgid "E590: A preview window already exists"
+msgstr "E590: 预览窗å£å·²å­˜åœ¨"
+
+msgid "W17: Arabic requires UTF-8, do ':set encoding=utf-8'"
+msgstr "W17: Arabic éœ€è¦ UTF-8,请执行 ':set encoding=utf-8'"
+
+#, c-format
+msgid "E593: Need at least %d lines"
+msgstr "E593: è‡³å°‘éœ€è¦ %d è¡Œ"
+
+#, c-format
+msgid "E594: Need at least %d columns"
+msgstr "E594: è‡³å°‘éœ€è¦ %d 列"
+
+#, c-format
+msgid "E355: Unknown option: %s"
+msgstr "E355: 未知的选项: %s"
+
+msgid ""
+"\n"
+"--- Terminal codes ---"
+msgstr ""
+"\n"
+"--- ç»ˆç«¯ç¼–ç  ---"
+
+msgid ""
+"\n"
+"--- Global option values ---"
+msgstr ""
+"\n"
+"--- 全局选项值 ---"
+
+msgid ""
+"\n"
+"--- Local option values ---"
+msgstr ""
+"\n"
+"--- 局部选项值 ---"
+
+msgid ""
+"\n"
+"--- Options ---"
+msgstr ""
+"\n"
+"--- 选项 ---"
+
+msgid "E356: get_varp ERROR"
+msgstr "E356: get_varp 错误"
+
+#, c-format
+msgid "E357: 'langmap': Matching character missing for %s"
+msgstr "E357: 'langmap': 找ä¸åˆ° %s 对应的字符"
+
+#, c-format
+msgid "E358: 'langmap': Extra characters after semicolon: %s"
+msgstr "E358: 'langmap': 分å·åŽæœ‰å¤šä½™çš„字符: %s"
+
+msgid "cannot open "
+msgstr "ä¸èƒ½æ‰“å¼€"
+
+msgid "VIM: Can't open window!\n"
+msgstr "VIM: ä¸èƒ½æ‰“开窗å£!\n"
+
+msgid "Need Amigados version 2.04 or later\n"
+msgstr "éœ€è¦ Amigados 版本 2.04 以上\n"
+
+#, c-format
+msgid "Need %s version %ld\n"
+msgstr "éœ€è¦ %s 版本 %ld\n"
+
+msgid "Cannot open NIL:\n"
+msgstr "ä¸èƒ½æ‰“å¼€ NIL:\n"
+
+msgid "Cannot create "
+msgstr "ä¸èƒ½åˆ›å»º "
+
+#, c-format
+msgid "Vim exiting with %d\n"
+msgstr "Vim 返回值: %d\n"
+
+msgid "cannot change console mode ?!\n"
+msgstr "ä¸èƒ½åˆ‡æ¢ä¸»æŽ§å°(console)æ¨¡å¼ !?\n"
+
+msgid "mch_get_shellsize: not a console??\n"
+msgstr "mch_get_shellsize: ä¸æ˜¯ä¸»æŽ§å°(console)??\n"
+
+#. if Vim opened a window: Executing a shell may cause crashes
+msgid "E360: Cannot execute shell with -f option"
+msgstr "E360: ä¸èƒ½ç”¨ -f 选项执行 shell"
+
+msgid "Cannot execute "
+msgstr "ä¸èƒ½æ‰§è¡Œ "
+
+msgid "shell "
+msgstr "shell "
+
+msgid " returned\n"
+msgstr " 已返回\n"
+
+msgid "ANCHOR_BUF_SIZE too small."
+msgstr "ANCHOR_BUF_SIZE 太å°"
+
+msgid "I/O ERROR"
+msgstr "I/O 错误"
+
+msgid "Message"
+msgstr "消æ¯"
+
+msgid "'columns' is not 80, cannot execute external commands"
+msgstr "'columns' ä¸æ˜¯ 80, ä¸èƒ½æ‰§è¡Œå¤–部命令"
+
+msgid "E237: Printer selection failed"
+msgstr "E237: 选择打å°æœºå¤±è´¥"
+
+#, c-format
+msgid "to %s on %s"
+msgstr "从 %s 到 %s"
+
+#, c-format
+msgid "E613: Unknown printer font: %s"
+msgstr "E613: 未知的打å°æœºå­—体: %s"
+
+#, c-format
+msgid "E238: Print error: %s"
+msgstr "E238: 打å°é”™è¯¯: %s"
+
+#, c-format
+msgid "Printing '%s'"
+msgstr "æ‰“å° '%s'"
+
+#, c-format
+msgid "E244: Illegal charset name \"%s\" in font name \"%s\""
+msgstr "E244: 字符集 \"%s\" ä¸èƒ½å¯¹åº”字体\"%s\""
+
+#, c-format
+msgid "E245: Illegal char '%c' in font name \"%s\""
+msgstr "E245: ä¸æ­£ç¡®çš„字符 '%c' 出现在字体å称 \"%s\" 内"
+
+msgid "Vim: Double signal, exiting\n"
+msgstr "Vim: åŒé‡ä¿¡å·ï¼Œé€€å‡ºä¸­\n"
+
+#, c-format
+msgid "Vim: Caught deadly signal %s\n"
+msgstr "Vim: 拦截到致命信å·(deadly signal) %s\n"
+
+#, c-format
+msgid "Vim: Caught deadly signal\n"
+msgstr "Vim: 拦截到致命信å·(deadly signal)\n"
+
+#, c-format
+msgid "Opening the X display took %ld msec"
+msgstr "打开 X display 用时 %ld 秒"
+
+msgid ""
+"\n"
+"Vim: Got X error\n"
+msgstr ""
+"\n"
+"Vim: X 错误\n"
+
+msgid "Testing the X display failed"
+msgstr "测试 X display 失败"
+
+msgid "Opening the X display timed out"
+msgstr "打开 X display 超时"
+
+msgid ""
+"\n"
+"Cannot execute shell "
+msgstr ""
+"\n"
+"无法执行 shell"
+
+msgid ""
+"\n"
+"Cannot execute shell sh\n"
+msgstr ""
+"\n"
+"无法执行 shell sh\n"
+
+msgid ""
+"\n"
+"shell returned "
+msgstr ""
+"\n"
+"Shell 已返回"
+
+msgid ""
+"\n"
+"Cannot create pipes\n"
+msgstr ""
+"\n"
+"无法建立管é“\n"
+
+msgid ""
+"\n"
+"Cannot fork\n"
+msgstr ""
+"\n"
+"无法 fork\n"
+
+msgid ""
+"\n"
+"Command terminated\n"
+msgstr ""
+"\n"
+"命令已结æŸ\n"
+
+msgid "XSMP lost ICE connection"
+msgstr "XSMP 丢失了到 ICE 的连接"
+
+# do not translate
+#, c-format
+msgid "dlerror = \"%s\""
+msgstr "dlerror = \"%s\""
+
+msgid "Opening the X display failed"
+msgstr "打开 X display 失败"
+
+msgid "XSMP handling save-yourself request"
+msgstr "XSMP å¤„ç† save-yourself 请求"
+
+msgid "XSMP opening connection"
+msgstr "XSMP 打开连接"
+
+msgid "XSMP ICE connection watch failed"
+msgstr "XSMP ICE 连接监视失败"
+
+#, c-format
+msgid "XSMP SmcOpenConnection failed: %s"
+msgstr "XSMP SmcOpenConnection 调用失败: %s"
+
+msgid "At line"
+msgstr "åœ¨è¡Œå· "
+
+msgid "Could not load vim32.dll!"
+msgstr "无法加载 vim32.dllï¼"
+
+msgid "VIM Error"
+msgstr "VIM 错误"
+
+msgid "Could not fix up function pointers to the DLL!"
+msgstr "无法修正到 DLL 的函数指针!"
+
+#, c-format
+msgid "shell returned %d"
+msgstr "Shell 返回 %d"
+
+#, c-format
+msgid "Vim: Caught %s event\n"
+msgstr "Vim: 拦截到 %s 事件\n"
+
+msgid "close"
+msgstr "关闭"
+
+msgid "logoff"
+msgstr "注消"
+
+msgid "shutdown"
+msgstr "关机"
+
+msgid "E371: Command not found"
+msgstr "E371: 找ä¸åˆ°å‘½ä»¤"
+
+msgid ""
+"VIMRUN.EXE not found in your $PATH.\n"
+"External commands will not pause after completion.\n"
+"See :help win32-vimrun for more information."
+msgstr ""
+"在你的 $PATH 中找ä¸åˆ° VIMRUN.EXE。\n"
+"外部命令执行完毕åŽå°†ä¸ä¼šæš‚åœã€‚\n"
+"è¿›ä¸€æ­¥è¯´æ˜Žè¯·è§ :help win32-vimrun"
+
+msgid "Vim Warning"
+msgstr "Vim 警告"
+
+#, c-format
+msgid "E372: Too many %%%c in format string"
+msgstr "E372: æ ¼å¼åŒ–字符串里有太多 %%%c "
+
+#, c-format
+msgid "E373: Unexpected %%%c in format string"
+msgstr "E373: æ ¼å¼åŒ–字符串ä¸åº”该出现 %%%c "
+
+msgid "E374: Missing ] in format string"
+msgstr "E374: æ ¼å¼åŒ–字符串里少了 ]"
+
+#, c-format
+msgid "E375: Unsupported %%%c in format string"
+msgstr "E375: æ ¼å¼åŒ–字符串里有ä¸æ”¯æŒçš„ %%%c "
+
+#, c-format
+msgid "E376: Invalid %%%c in format string prefix"
+msgstr "E376: æ ¼å¼åŒ–字符串开头里有ä¸æ­£ç¡®çš„ %%%c "
+
+#, c-format
+msgid "E377: Invalid %%%c in format string"
+msgstr "E377: æ ¼å¼åŒ–字符串里有ä¸æ­£ç¡®çš„ %%%c "
+
+msgid "E378: 'errorformat' contains no pattern"
+msgstr "E378: 'errorformat' 未设定"
+
+msgid "E379: Missing or empty directory name"
+msgstr "E379: 找ä¸åˆ°ç›®å½•å称或是空的目录å称"
+
+msgid "E553: No more items"
+msgstr "E553: 没有更多的项"
+
+#, c-format
+msgid "(%d of %d)%s%s: "
+msgstr "(%d / %d)%s%s: "
+
+msgid " (line deleted)"
+msgstr " (行已删除)"
+
+msgid "E380: At bottom of quickfix stack"
+msgstr "E380: Quickfix 堆栈底端"
+
+msgid "E381: At top of quickfix stack"
+msgstr "E381: Quickfix 堆栈顶端"
+
+#, c-format
+msgid "error list %d of %d; %d errors"
+msgstr "错误列表 %d / %d;共 %d 个错误"
+
+msgid "E382: Cannot write, 'buftype' option is set"
+msgstr "E382: 无法写入,已设定选项 'buftype'"
+
+msgid "E683: File name missing or invalid pattern"
+msgstr "E683: 缺少文件å或模å¼æ— æ•ˆ"
+
+#, c-format
+msgid "Cannot open file \"%s\""
+msgstr "无法打开文件 \"%s\""
+
+msgid "E681: Buffer is not loaded"
+msgstr "E681: 缓冲区未加载"
+
+msgid "E777: String or List expected"
+msgstr "E777: æ­¤å¤„éœ€è¦ String 或者 List"
+
+#, c-format
+msgid "E369: invalid item in %s%%[]"
+msgstr "E369: %s%%[] 中有无效的项"
+
+msgid "E339: Pattern too long"
+msgstr "E339: 模å¼å¤ªé•¿"
+
+msgid "E50: Too many \\z("
+msgstr "E50: 太多 \\z("
+
+#, c-format
+msgid "E51: Too many %s("
+msgstr "E51: 太多 %s("
+
+msgid "E52: Unmatched \\z("
+msgstr "E52: ä¸åŒ¹é…çš„ \\z("
+
+#, c-format
+msgid "E53: Unmatched %s%%("
+msgstr "E53: ä¸åŒ¹é…çš„ %s%%("
+
+#, c-format
+msgid "E54: Unmatched %s("
+msgstr "E54: ä¸åŒ¹é…çš„ %s("
+
+#, c-format
+msgid "E55: Unmatched %s)"
+msgstr "E55: ä¸åŒ¹é…çš„ %s)"
+
+#, c-format
+msgid "E59: invalid character after %s@"
+msgstr "E59: %s@ åŽé¢æœ‰æ— æ•ˆçš„字符"
+
+#, c-format
+msgid "E60: Too many complex %s{...}s"
+msgstr "E60: 太多å¤æ‚çš„ %s{...}s"
+
+#, c-format
+msgid "E61: Nested %s*"
+msgstr "E61: 嵌套的 %s*"
+
+#, c-format
+msgid "E62: Nested %s%c"
+msgstr "E62: 嵌套的 %s%c"
+
+msgid "E63: invalid use of \\_"
+msgstr "E63: ä¸æ­£ç¡®åœ°ä½¿ç”¨ \\_"
+
+#, c-format
+msgid "E64: %s%c follows nothing"
+msgstr "E64: %s%c å‰é¢æ— å†…容"
+
+msgid "E65: Illegal back reference"
+msgstr "E65: 无效的回引"
+
+msgid "E66: \\z( not allowed here"
+msgstr "E66: 此处ä¸å…许 \\z("
+
+msgid "E67: \\z1 - \\z9 not allowed here"
+msgstr "E67: 此处ä¸å…许 \\z1 ç­‰"
+
+msgid "E68: Invalid character after \\z"
+msgstr "E68: \\z åŽé¢æœ‰æ— æ•ˆçš„字符"
+
+#, c-format
+msgid "E69: Missing ] after %s%%["
+msgstr "E69: %s%%[ åŽç¼ºå°‘ ]"
+
+#, c-format
+msgid "E70: Empty %s%%[]"
+msgstr "E70: 空的 %s%%[]"
+
+#, c-format
+msgid "E678: Invalid character after %s%%[dxouU]"
+msgstr "E678: %s%%[dxouU] åŽé¢æœ‰æ— æ•ˆçš„字符"
+
+#, c-format
+msgid "E71: Invalid character after %s%%"
+msgstr "E71: %s%% åŽé¢æœ‰æ— æ•ˆçš„字符"
+
+#, c-format
+msgid "E769: Missing ] after %s["
+msgstr "E769: %s[ åŽç¼ºå°‘ ]"
+
+#, c-format
+msgid "E554: Syntax error in %s{...}"
+msgstr "E554: %s{...} 中语法错误"
+
+msgid "External submatches:\n"
+msgstr "外部符åˆ:\n"
+
+msgid " VREPLACE"
+msgstr " V-替æ¢"
+
+msgid " REPLACE"
+msgstr " 替æ¢"
+
+msgid " REVERSE"
+msgstr " åå‘"
+
+msgid " INSERT"
+msgstr " æ’å…¥"
+
+msgid " (insert)"
+msgstr " (æ’å…¥)"
+
+msgid " (replace)"
+msgstr " (替æ¢)"
+
+msgid " (vreplace)"
+msgstr " (V-替æ¢)"
+
+msgid " Hebrew"
+msgstr " Hebrew"
+
+msgid " Arabic"
+msgstr " Arabic"
+
+msgid " (lang)"
+msgstr " (语言)"
+
+msgid " (paste)"
+msgstr " (粘帖)"
+
+msgid " VISUAL"
+msgstr " å¯è§†"
+
+msgid " VISUAL LINE"
+msgstr " å¯è§† è¡Œ"
+
+msgid " VISUAL BLOCK"
+msgstr " å¯è§† å—"
+
+msgid " SELECT"
+msgstr " 选择"
+
+msgid " SELECT LINE"
+msgstr " 选择 行"
+
+msgid " SELECT BLOCK"
+msgstr " 选择 å—"
+
+msgid "recording"
+msgstr "记录中"
+
+#, c-format
+msgid "E383: Invalid search string: %s"
+msgstr "E383: 无效的查找字符串: %s"
+
+#, c-format
+msgid "E384: search hit TOP without match for: %s"
+msgstr "E384: 已查找到文件开头ä»æ‰¾ä¸åˆ° %s"
+
+#, c-format
+msgid "E385: search hit BOTTOM without match for: %s"
+msgstr "E385: 已查找到文件结尾ä»æ‰¾ä¸åˆ° %s"
+
+msgid "E386: Expected '?' or '/' after ';'"
+msgstr "E386: 在 ';' åŽé¢åº”该有 '?' 或 '/'"
+
+msgid " (includes previously listed match)"
+msgstr " (包括上次列出符åˆé¡¹)"
+
+#. cursor at status line
+msgid "--- Included files "
+msgstr "--- 包å«æ–‡ä»¶ "
+
+msgid "not found "
+msgstr "找ä¸åˆ° "
+
+msgid "in path ---\n"
+msgstr "在路径 ---\n"
+
+msgid " (Already listed)"
+msgstr " (已列出)"
+
+msgid " NOT FOUND"
+msgstr " 找ä¸åˆ°"
+
+#, c-format
+msgid "Scanning included file: %s"
+msgstr "查找包å«æ–‡ä»¶: %s"
+
+#, c-format
+msgid "Searching included file %s"
+msgstr "查找包å«çš„文件 %s"
+
+msgid "E387: Match is on current line"
+msgstr "E387: 当å‰è¡ŒåŒ¹é…"
+
+msgid "All included files were found"
+msgstr "所有包å«æ–‡ä»¶éƒ½å·²æ‰¾åˆ°"
+
+msgid "No included files"
+msgstr "没有包å«æ–‡ä»¶"
+
+msgid "E388: Couldn't find definition"
+msgstr "E388: 找ä¸åˆ°å®šä¹‰"
+
+msgid "E389: Couldn't find pattern"
+msgstr "E389: 找ä¸åˆ° pattern"
+
+msgid "E759: Format error in spell file"
+msgstr "E759: 拼写文件格å¼é”™è¯¯"
+
+msgid "E758: Truncated spell file"
+msgstr "E758: 已截断的拼写文件"
+
+#, c-format
+msgid "Trailing text in %s line %d: %s"
+msgstr "%s 第 %d 行,多余的åŽç»­å­—符: %s"
+
+#, c-format
+msgid "Affix name too long in %s line %d: %s"
+msgstr "%s 第 %d 行,附加项å字太长: %s"
+
+msgid "E761: Format error in affix file FOL, LOW or UPP"
+msgstr "E761: 附加文件 FOLã€LOW 或 UPP 中格å¼é”™è¯¯"
+
+msgid "E762: Character in FOL, LOW or UPP is out of range"
+msgstr "E762: FOLã€LOW 或 UPP 中字符超出范围"
+
+msgid "Compressing word tree..."
+msgstr "压缩å•è¯æ ‘……"
+
+msgid "E756: Spell checking is not enabled"
+msgstr "E756: 拼写检查未å¯ç”¨"
+
+#, c-format
+msgid "Warning: Cannot find word list \"%s.%s.spl\" or \"%s.ascii.spl\""
+msgstr "警告: 找ä¸åˆ°å•è¯åˆ—表 \"%s.%s.spl\" or \"%s.ascii.spl\""
+
+#, c-format
+msgid "Reading spell file \"%s\""
+msgstr "读å–拼写文件 \"%s\""
+
+msgid "E757: This does not look like a spell file"
+msgstr "E757: 这看起æ¥ä¸åƒæ˜¯æ‹¼å†™æ–‡ä»¶"
+
+msgid "E771: Old spell file, needs to be updated"
+msgstr "E771: 旧版本的拼写文件,需è¦æ›´æ–°"
+
+msgid "E772: Spell file is for newer version of Vim"
+msgstr "E772: 为更高版本的 Vim 所用的拼写文件"
+
+msgid "E770: Unsupported section in spell file"
+msgstr "E770: 拼写文件中存在ä¸æ”¯æŒçš„节"
+
+#, c-format
+msgid "Warning: region %s not supported"
+msgstr "警告: 区域 %s ä¸æ”¯æŒ"
+
+#, c-format
+msgid "Reading affix file %s..."
+msgstr "读å–附加文件 %s ……"
+
+#, c-format
+msgid "Conversion failure for word in %s line %d: %s"
+msgstr "å•è¯ %s 转æ¢å¤±è´¥ï¼Œç¬¬ %d è¡Œ: %s"
+
+#, c-format
+msgid "Conversion in %s not supported: from %s to %s"
+msgstr "ä¸æ”¯æŒ %s 中的转æ¢: 从 %s 到 %s"
+
+#, c-format
+msgid "Conversion in %s not supported"
+msgstr "ä¸æ”¯æŒ %s 中的转æ¢"
+
+#, c-format
+msgid "Invalid value for FLAG in %s line %d: %s"
+msgstr "%s 第 %d 行,FLAG 的值无效: %s"
+
+#, c-format
+msgid "FLAG after using flags in %s line %d: %s"
+msgstr "%s 第 %d 行,在使用标志åŽå‡ºçŽ° FLAG: %s"
+
+#, c-format
+#~ msgid ""
+#~ "Defining COMPOUNDFORBIDFLAG after PFX item may give wrong results in %s line "
+#~ "%d"
+#~ msgstr ""
+
+#, c-format
+#~ msgid ""
+#~ "Defining COMPOUNDPERMITFLAG after PFX item may give wrong results in %s line "
+#~ "%d"
+#~ msgstr ""
+
+#, c-format
+msgid "Wrong COMPOUNDWORDMAX value in %s line %d: %s"
+msgstr "%s 第 %d 行,错误的 COMPOUNDWORDMAX 值: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDMIN value in %s line %d: %s"
+msgstr "%s 第 %d 行,错误的 COMPOUNDMIN 值: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDSYLMAX value in %s line %d: %s"
+msgstr "%s 第 %d 行,错误的 COMPOUNDSYLMAX 值: %s"
+
+#, c-format
+msgid "Wrong CHECKCOMPOUNDPATTERN value in %s line %d: %s"
+msgstr "%s 第 %d 行,错误的 CHECKCOMPOUNDPATTERN 值: %s"
+
+#, c-format
+msgid "Different combining flag in continued affix block in %s line %d: %s"
+msgstr "%s 第 %d 行,在连续的附加å—中出现ä¸åŒçš„组åˆæ ‡å¿—: %s"
+
+#, c-format
+msgid "Duplicate affix in %s line %d: %s"
+msgstr "%s 第 %d 行,é‡å¤çš„附加项: %s"
+
+#, c-format
+msgid ""
+"Affix also used for BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST in %s "
+"line %d: %s"
+msgstr ""
+"%s 第 %d 行,附加项被 BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST 使"
+"用: %s"
+
+#, c-format
+msgid "Expected Y or N in %s line %d: %s"
+msgstr "%s 第 %d è¡Œï¼Œæ­¤å¤„éœ€è¦ Y 或 N: %s"
+
+#, c-format
+msgid "Broken condition in %s line %d: %s"
+msgstr "%s 第 %d 行,错误的æ¡ä»¶: %s"
+
+#, c-format
+msgid "Expected REP(SAL) count in %s line %d"
+msgstr "%s 第 %d è¡Œï¼Œæ­¤å¤„éœ€è¦ REP(SAL) 计数"
+
+#, c-format
+msgid "Expected MAP count in %s line %d"
+msgstr "%s 第 %d è¡Œï¼Œæ­¤å¤„éœ€è¦ MAP 计数"
+
+#, c-format
+msgid "Duplicate character in MAP in %s line %d"
+msgstr "%s 第 %d 行,MAP 中存在é‡å¤çš„字符"
+
+#, c-format
+msgid "Unrecognized or duplicate item in %s line %d: %s"
+msgstr "%s 第 %d 行,无法识别或é‡å¤çš„项: %s"
+
+#, c-format
+msgid "Missing FOL/LOW/UPP line in %s"
+msgstr "%s 中缺少 FOL/LOW/UPP 行"
+
+msgid "COMPOUNDSYLMAX used without SYLLABLE"
+msgstr "在没有 SYLLABLE 的情况下使用了 COMPOUNDSYLMAX"
+
+msgid "Too many postponed prefixes"
+msgstr "太多延迟å‰ç¼€"
+
+msgid "Too many compound flags"
+msgstr "太多组åˆæ ‡å¿—"
+
+msgid "Too many postponed prefixes and/or compound flags"
+msgstr "太多延迟å‰ç¼€å’Œ/或组åˆæ ‡å¿—"
+
+#, c-format
+msgid "Missing SOFO%s line in %s"
+msgstr "%s 中缺少 SOFO%s 行"
+
+#, c-format
+msgid "Both SAL and SOFO lines in %s"
+msgstr "%s åŒæ—¶å‡ºçŽ° SQL å’Œ SOFO è¡Œ"
+
+#, c-format
+msgid "Flag is not a number in %s line %d: %s"
+msgstr "%s 第 %d 行,标志ä¸æ˜¯æ•°å­—: %s"
+
+#, c-format
+msgid "Illegal flag in %s line %d: %s"
+msgstr "%s 第 %d 行,无效的标志: %s"
+
+#, c-format
+msgid "%s value differs from what is used in another .aff file"
+msgstr "%s 的值与å¦ä¸€ä¸ª .aff 文件中使用的值ä¸ç›¸åŒ"
+
+#, c-format
+msgid "Reading dictionary file %s..."
+msgstr "读å–字典文件 %s ……"
+
+#, c-format
+msgid "E760: No word count in %s"
+msgstr "E760: %s 中没有å•è¯è®¡æ•°"
+
+#, c-format
+msgid "line %6d, word %6d - %s"
+msgstr "第 %6d 行,第 %6d 个å•è¯ - %s"
+
+#, c-format
+msgid "Duplicate word in %s line %d: %s"
+msgstr "%s 第 %d 行,é‡å¤çš„å•è¯: %s"
+
+#, c-format
+msgid "First duplicate word in %s line %d: %s"
+msgstr "%s 第 %d 行,首次é‡å¤çš„å•è¯: %s"
+
+#, c-format
+msgid "%d duplicate word(s) in %s"
+msgstr "存在 %d 个é‡å¤çš„å•è¯ï¼Œåœ¨ %s 中"
+
+#, c-format
+msgid "Ignored %d word(s) with non-ASCII characters in %s"
+msgstr "忽略了å«æœ‰éž ASCII 字符的 %d 个å•è¯ï¼Œåœ¨ %s 中"
+
+#, c-format
+msgid "Reading word file %s..."
+msgstr "读å–å•è¯æ–‡ä»¶ %s ……"
+
+#, c-format
+#~ msgid "Duplicate /encoding= line ignored in %s line %d: %s"
+#~ msgstr ""
+
+#, c-format
+msgid "/encoding= line after word ignored in %s line %d: %s"
+msgstr "%s 第 %d 行,å•è¯åŽçš„ /encoding= 行已被忽略: %s"
+
+#, c-format
+msgid "Duplicate /regions= line ignored in %s line %d: %s"
+msgstr "%s 第 %d 行,é‡å¤çš„ /regions= 行已被忽略: %s"
+
+#, c-format
+msgid "Too many regions in %s line %d: %s"
+msgstr "%s 第 %d 行,太多区域: %s"
+
+#, c-format
+msgid "/ line ignored in %s line %d: %s"
+msgstr "%s 第 %d 行,/ 行已被忽略: %s"
+
+#, c-format
+msgid "Invalid region nr in %s line %d: %s"
+msgstr "%s 第 %d 行,无效的区域å·: %s"
+
+#, c-format
+msgid "Unrecognized flags in %s line %d: %s"
+msgstr "%s 第 %d 行,ä¸å¯è¯†åˆ«çš„标志: %s"
+
+#, c-format
+msgid "Ignored %d words with non-ASCII characters"
+msgstr "忽略了å«æœ‰éž ASCII 字符的 %d 个å•è¯"
+
+#, c-format
+msgid "Compressed %d of %d nodes; %d (%d%%) remaining"
+msgstr "压缩了 %d/%d 个节点;剩余 %d (%d%%)"
+
+msgid "Reading back spell file..."
+msgstr "读å–拼写文件……"
+
+#.
+#. * Go through the trie of good words, soundfold each word and add it to
+#. * the soundfold trie.
+#.
+msgid "Performing soundfolding..."
+msgstr "正在 soundfolding……"
+
+#, c-format
+msgid "Number of words after soundfolding: %ld"
+msgstr "soundfolding åŽçš„å•è¯æ•°: %ld"
+
+#, c-format
+msgid "Total number of words: %d"
+msgstr "å•è¯æ€»æ•°: %d"
+
+#, c-format
+msgid "Writing suggestion file %s..."
+msgstr "写入建议文件 %s ……"
+
+#, c-format
+msgid "Estimated runtime memory use: %d bytes"
+msgstr "估计è¿è¡Œæ—¶å†…存用é‡: %d 字节"
+
+msgid "E751: Output file name must not have region name"
+msgstr "E751: 输出文件åä¸èƒ½å«æœ‰åŒºåŸŸå"
+
+msgid "E754: Only up to 8 regions supported"
+msgstr "E754: 最多åªæ”¯æŒ 8 个区域"
+
+#, c-format
+msgid "E755: Invalid region in %s"
+msgstr "E755: %s 出现无效的范围"
+
+msgid "Warning: both compounding and NOBREAK specified"
+msgstr "警告: åŒæ—¶æŒ‡å®šäº† compounding å’Œ NOBREAK"
+
+#, c-format
+msgid "Writing spell file %s..."
+msgstr "写入拼写文件 %s ……"
+
+msgid "Done!"
+msgstr "完æˆï¼"
+
+#, c-format
+msgid "E765: 'spellfile' does not have %ld entries"
+msgstr "E765: 'spellfile' 没有 %ld 项"
+
+#, c-format
+msgid "Word removed from %s"
+msgstr "从 %s 中删除了å•è¯"
+
+#, c-format
+msgid "Word added to %s"
+msgstr "å‘ %s 中添加了å•è¯"
+
+msgid "E763: Word characters differ between spell files"
+msgstr "E763: 拼写文件之间的字符ä¸ç›¸åŒ"
+
+msgid "Sorry, no suggestions"
+msgstr "抱歉,没有建议"
+
+#, c-format
+msgid "Sorry, only %ld suggestions"
+msgstr "抱歉,åªæœ‰ %ld æ¡å»ºè®®"
+
+#. avoid more prompt
+#, c-format
+msgid "Change \"%.*s\" to:"
+msgstr "将 \"%.*s\" 改为:"
+
+#, c-format
+msgid " < \"%.*s\""
+msgstr " < \"%.*s\""
+
+msgid "E752: No previous spell replacement"
+msgstr "E752: 之å‰æ²¡æœ‰æ‹¼å†™æ›¿æ¢"
+
+#, c-format
+msgid "E753: Not found: %s"
+msgstr "E753: 找ä¸åˆ°: %s"
+
+#, c-format
+msgid "E778: This does not look like a .sug file: %s"
+msgstr "E778: 看起æ¥ä¸åƒæ˜¯ .sug 文件: %s"
+
+#, c-format
+#~ msgid "E779: Old .sug file, needs to be updated: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E780: .sug file is for newer version of Vim: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E781: .sug file doesn't match .spl file: %s"
+#~ msgstr ""
+
+#, fuzzy, c-format
+#~ msgid "E782: error while reading .sug file: %s"
+#~ msgstr "E47: 读å–错误文件失败"
+
+#. This should have been checked when generating the .spl
+#. * file.
+#~ msgid "E783: duplicate char in MAP entry"
+#~ msgstr ""
+
+#, c-format
+msgid "E390: Illegal argument: %s"
+msgstr "E390: 无效的å‚æ•°: %s"
+
+#, c-format
+msgid "E391: No such syntax cluster: %s"
+msgstr "E391: 无此语法 cluster: \"%s\""
+
+msgid "No Syntax items defined for this buffer"
+msgstr "这个缓冲区没有定义任何语法项"
+
+msgid "syncing on C-style comments"
+msgstr "C风格注释åŒæ­¥ä¸­"
+
+msgid "no syncing"
+msgstr "没有åŒæ­¥"
+
+msgid "syncing starts "
+msgstr "åŒæ­¥å¼€å§‹"
+
+msgid " lines before top line"
+msgstr "è¡Œå·è¶…出范围"
+
+msgid ""
+"\n"
+"--- Syntax sync items ---"
+msgstr ""
+"\n"
+"--- 语法åŒæ­¥é¡¹ç›® (Syntax sync items) ---"
+
+msgid ""
+"\n"
+"syncing on items"
+msgstr ""
+"\n"
+"åŒæ­¥ä¸­:"
+
+msgid ""
+"\n"
+"--- Syntax items ---"
+msgstr ""
+"\n"
+"--- 语法项目 ---"
+
+#, c-format
+msgid "E392: No such syntax cluster: %s"
+msgstr "E392: 无此语法 cluster: \"%s\""
+
+msgid "minimal "
+msgstr "最å°"
+
+msgid "maximal "
+msgstr "最大"
+
+#, fuzzy
+#~ msgid "; match "
+#~ msgstr "åŒ¹é… %d"
+
+#, fuzzy
+#~ msgid " line breaks"
+#~ msgstr "少于一行"
+
+msgid "E395: contains argument not accepted here"
+msgstr "E395: 使用了ä¸æ­£ç¡®çš„å‚æ•°"
+
+msgid "E396: containedin argument not accepted here"
+msgstr "E396: 使用了ä¸æ­£ç¡®çš„å‚æ•°"
+
+msgid "E393: group[t]here not accepted here"
+msgstr "E393: 使用了ä¸æ­£ç¡®çš„å‚æ•°"
+
+#, c-format
+msgid "E394: Didn't find region item for %s"
+msgstr "E394: 找ä¸åˆ° %s çš„ region item"
+
+msgid "E397: Filename required"
+msgstr "E397: 需è¦æ–‡ä»¶å称"
+
+#, c-format
+msgid "E747: Missing ']': %s"
+msgstr "E747: 缺少 ']': %s"
+
+#, c-format
+msgid "E398: Missing '=': %s"
+msgstr "E398: 缺少 '=': %s"
+
+#, c-format
+msgid "E399: Not enough arguments: syntax region %s"
+msgstr "E399: syntax region %s çš„å‚数太少"
+
+msgid "E400: No cluster specified"
+msgstr "E400: 没有指定的属性"
+
+#, c-format
+msgid "E401: Pattern delimiter not found: %s"
+msgstr "E401: 找ä¸åˆ°åˆ†éš”符å·: %s"
+
+#, c-format
+msgid "E402: Garbage after pattern: %s"
+msgstr "E402: '%s' åŽé¢çš„东西ä¸èƒ½è¯†åˆ«"
+
+msgid "E403: syntax sync: line continuations pattern specified twice"
+msgstr "E403: 语法åŒæ­¥: 连接行符å·æŒ‡å®šäº†ä¸¤æ¬¡"
+
+#, c-format
+msgid "E404: Illegal arguments: %s"
+msgstr "E404: 无效的å‚æ•°: %s"
+
+#, c-format
+msgid "E405: Missing equal sign: %s"
+msgstr "E405: 缺少等å·: %s"
+
+#, c-format
+msgid "E406: Empty argument: %s"
+msgstr "E406: 空的å‚æ•°: %s"
+
+#, c-format
+msgid "E407: %s not allowed here"
+msgstr "E407: %s ä¸èƒ½åœ¨æ­¤å‡ºçŽ°"
+
+#, c-format
+msgid "E408: %s must be first in contains list"
+msgstr "E408: %s 必须是列表里的第一个"
+
+#, c-format
+msgid "E409: Unknown group name: %s"
+msgstr "E409: ä¸æ­£ç¡®çš„组å: %s"
+
+#, c-format
+msgid "E410: Invalid :syntax subcommand: %s"
+msgstr "E410: ä¸æ­£ç¡®çš„ :syntax å­å‘½ä»¤: %s"
+
+msgid "E679: recursive loop loading syncolor.vim"
+msgstr "E679: 加载 syncolor.vim 时出现嵌套循环"
+
+#, c-format
+msgid "E411: highlight group not found: %s"
+msgstr "E411: 找ä¸åˆ° highlight group: %s"
+
+#, c-format
+msgid "E412: Not enough arguments: \":highlight link %s\""
+msgstr "E412: å‚数太少: \":highlight link %s\""
+
+#, c-format
+msgid "E413: Too many arguments: \":highlight link %s\""
+msgstr "E413: å‚数过多: \":highlight link %s\""
+
+msgid "E414: group has settings, highlight link ignored"
+msgstr "E414: 已设定组, 忽略 highlight link"
+
+#, c-format
+msgid "E415: unexpected equal sign: %s"
+msgstr "E415: ä¸è¯¥æœ‰çš„ç­‰å·: %s"
+
+#, c-format
+msgid "E416: missing equal sign: %s"
+msgstr "E416: 缺少等å·: %s"
+
+#, c-format
+msgid "E417: missing argument: %s"
+msgstr "E417: 缺少å‚æ•°: %s"
+
+#, c-format
+msgid "E418: Illegal value: %s"
+msgstr "E418: ä¸åˆæ³•çš„值: %s"
+
+msgid "E419: FG color unknown"
+msgstr "E419: 错误的å‰æ™¯é¢œè‰²"
+
+msgid "E420: BG color unknown"
+msgstr "E420: 错误的背景颜色"
+
+#, c-format
+msgid "E421: Color name or number not recognized: %s"
+msgstr "E421: 错误的颜色å称或数值: %s"
+
+#, c-format
+msgid "E422: terminal code too long: %s"
+msgstr "E422: 终端编ç å¤ªé•¿: %s"
+
+#, c-format
+msgid "E423: Illegal argument: %s"
+msgstr "E423: 无效的å‚æ•°: %s"
+
+msgid "E424: Too many different highlighting attributes in use"
+msgstr "E424: 使用了太多ä¸åŒçš„高亮度属性"
+
+msgid "E669: Unprintable character in group name"
+msgstr "E669: 组å中存在ä¸å¯æ˜¾ç¤ºå­—符"
+
+msgid "W18: Invalid character in group name"
+msgstr "W18: 组å中å«æœ‰æ— æ•ˆå­—符"
+
+msgid "E555: at bottom of tag stack"
+msgstr "E555: 已在 tag 堆栈底部"
+
+msgid "E556: at top of tag stack"
+msgstr "E556: 已在 tag 堆栈顶部"
+
+msgid "E425: Cannot go before first matching tag"
+msgstr "E425: 已到第一个匹é…çš„ tag"
+
+#, c-format
+msgid "E426: tag not found: %s"
+msgstr "E426: 找ä¸åˆ° tag: %s"
+
+msgid " # pri kind tag"
+msgstr " # pri kind tag"
+
+msgid "file\n"
+msgstr "文件\n"
+
+msgid "E427: There is only one matching tag"
+msgstr "E427: åªæœ‰ä¸€ä¸ªåŒ¹é…çš„ tag"
+
+msgid "E428: Cannot go beyond last matching tag"
+msgstr "E428: 己到最åŽä¸€ä¸ªåŒ¹é…çš„ tag"
+
+#, c-format
+msgid "File \"%s\" does not exist"
+msgstr "文件 \"%s\" ä¸å­˜åœ¨"
+
+#. Give an indication of the number of matching tags
+#, c-format
+msgid "tag %d of %d%s"
+msgstr "找到 tag: %d / %d%s"
+
+msgid " or more"
+msgstr " 或更多"
+
+msgid " Using tag with different case!"
+msgstr " 以ä¸åŒå¤§å°å†™æ¥ä½¿ç”¨ tagï¼"
+
+#, c-format
+msgid "E429: File \"%s\" does not exist"
+msgstr "E429: 文件 \"%s\" ä¸å­˜åœ¨"
+
+#. Highlight title
+msgid ""
+"\n"
+" # TO tag FROM line in file/text"
+msgstr ""
+"\n"
+" # 到 tag 从 行 在 文件/文本"
+
+#, c-format
+msgid "Searching tags file %s"
+msgstr "查找 tag 文件 %s"
+
+#, c-format
+msgid "E430: Tag file path truncated for %s\n"
+msgstr "E430: Tag 文件路径被截断为 %s\n"
+
+#, c-format
+msgid "E431: Format error in tags file \"%s\""
+msgstr "E431: Tag 文件 \"%s\" æ ¼å¼é”™è¯¯"
+
+#, c-format
+msgid "Before byte %ld"
+msgstr "在第 %ld 字节之å‰"
+
+#, c-format
+msgid "E432: Tags file not sorted: %s"
+msgstr "E432: Tag 文件未排åº: %s"
+
+#. never opened any tags file
+msgid "E433: No tags file"
+msgstr "E433: 没有 tag 文件"
+
+msgid "E434: Can't find tag pattern"
+msgstr "E434: 找ä¸åˆ° tag 模å¼"
+
+msgid "E435: Couldn't find tag, just guessing!"
+msgstr "E435: 找ä¸åˆ° tag,试ç€çŒœï¼"
+
+msgid "' not known. Available builtin terminals are:"
+msgstr "' 未知。å¯ç”¨çš„内建终端有:"
+
+msgid "defaulting to '"
+msgstr "默认值为: '"
+
+msgid "E557: Cannot open termcap file"
+msgstr "E557: 无法打开 termcap 文件"
+
+msgid "E558: Terminal entry not found in terminfo"
+msgstr "E558: 在 terminfo 中找ä¸åˆ°ç»ˆç«¯é¡¹"
+
+msgid "E559: Terminal entry not found in termcap"
+msgstr "E559: 在 termcap 中找ä¸åˆ°ç»ˆç«¯é¡¹"
+
+#, c-format
+msgid "E436: No \"%s\" entry in termcap"
+msgstr "E436: termcap 中没有 \"%s\" 项"
+
+msgid "E437: terminal capability \"cm\" required"
+msgstr "E437: 终端需è¦èƒ½åŠ› \"cm\""
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Terminal keys ---"
+msgstr ""
+"\n"
+"--- 终端按键 ---"
+
+msgid "new shell started\n"
+msgstr "å¯åŠ¨æ–° shell\n"
+
+msgid "Vim: Error reading input, exiting...\n"
+msgstr "Vim: 读错误,退出中...\n"
+
+#. must display the prompt
+msgid "No undo possible; continue anyway"
+msgstr "无法撤销;ä»ç„¶ç»§ç»­"
+
+msgid "Already at oldest change"
+msgstr "å·²ä½äºŽæœ€æ—§çš„改å˜"
+
+msgid "Already at newest change"
+msgstr "å·²ä½äºŽæœ€æ–°çš„改å˜"
+
+#, c-format
+msgid "Undo number %ld not found"
+msgstr "找ä¸åˆ°æ’¤é”€å· %ld"
+
+msgid "E438: u_undo: line numbers wrong"
+msgstr "E438: u_undo: è¡Œå·é”™è¯¯"
+
+msgid "more line"
+msgstr "行被加入"
+
+msgid "more lines"
+msgstr "行被加入"
+
+msgid "line less"
+msgstr "行被去掉"
+
+msgid "fewer lines"
+msgstr "行被去掉"
+
+msgid "change"
+msgstr "è¡Œå‘生改å˜"
+
+msgid "changes"
+msgstr "è¡Œå‘生改å˜"
+
+#, c-format
+msgid "%ld %s; %s #%ld %s"
+msgstr "%ld %sï¼›%s #%ld %s"
+
+msgid "before"
+msgstr "before"
+
+msgid "after"
+msgstr "after"
+
+msgid "Nothing to undo"
+msgstr "æ— å¯æ’¤é”€"
+
+msgid "number changes time"
+msgstr " ç¼–å· æ”¹å˜ æ—¶é—´"
+
+msgid "E439: undo list corrupt"
+msgstr "E439: 撤销列表æŸå"
+
+msgid "E440: undo line missing"
+msgstr "E440: 找ä¸åˆ°è¦æ’¤é”€çš„è¡Œ"
+
+#. Only MS VC 4.1 and earlier can do Win32s
+msgid ""
+"\n"
+"MS-Windows 16/32-bit GUI version"
+msgstr ""
+"\n"
+"MS-Windows 16/32 ä½å›¾å½¢ç•Œé¢ç‰ˆæœ¬"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit GUI version"
+msgstr ""
+"\n"
+"MS-Windows 32 ä½å›¾å½¢ç•Œé¢ç‰ˆæœ¬"
+
+msgid " in Win32s mode"
+msgstr " Win32s 模å¼"
+
+msgid " with OLE support"
+msgstr " 带 OLE 支æŒ"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit console version"
+msgstr ""
+"\n"
+"MS-Windows 32 ä½æŽ§åˆ¶å°ç‰ˆæœ¬"
+
+msgid ""
+"\n"
+"MS-Windows 16-bit version"
+msgstr ""
+"\n"
+"MS-Windows 16 ä½æŽ§åˆ¶å°ç‰ˆæœ¬"
+
+msgid ""
+"\n"
+"32-bit MS-DOS version"
+msgstr ""
+"\n"
+"32 ä½ MS-DOS 版本"
+
+msgid ""
+"\n"
+"16-bit MS-DOS version"
+msgstr ""
+"\n"
+"16 ä½ MS-DOS 版本"
+
+msgid ""
+"\n"
+"MacOS X (unix) version"
+msgstr ""
+"\n"
+"MacOS X (unix) 版本"
+
+msgid ""
+"\n"
+"MacOS X version"
+msgstr ""
+"\n"
+"MacOS X 版本"
+
+msgid ""
+"\n"
+"MacOS version"
+msgstr ""
+"\n"
+"MacOS 版本"
+
+msgid ""
+"\n"
+"RISC OS version"
+msgstr ""
+"\n"
+"RISC OS 版本"
+
+msgid ""
+"\n"
+"Included patches: "
+msgstr ""
+"\n"
+"包å«è¡¥ä¸: "
+
+msgid "Modified by "
+msgstr "修改者 "
+
+msgid ""
+"\n"
+"Compiled "
+msgstr ""
+"\n"
+"编译"
+
+msgid "by "
+msgstr "者 "
+
+msgid ""
+"\n"
+"Huge version "
+msgstr ""
+"\n"
+"巨型版本 "
+
+msgid ""
+"\n"
+"Big version "
+msgstr ""
+"\n"
+"大型版本 "
+
+msgid ""
+"\n"
+"Normal version "
+msgstr ""
+"\n"
+"正常版本 "
+
+msgid ""
+"\n"
+"Small version "
+msgstr ""
+"\n"
+"å°åž‹ç‰ˆæœ¬ "
+
+msgid ""
+"\n"
+"Tiny version "
+msgstr ""
+"\n"
+"微型版本 "
+
+msgid "without GUI."
+msgstr "无图形界é¢ã€‚"
+
+msgid "with GTK2-GNOME GUI."
+msgstr "带 GTK2-GNOME 图形界é¢ã€‚"
+
+msgid "with GTK-GNOME GUI."
+msgstr "带 GTK-GNOME 图形界é¢ã€‚"
+
+msgid "with GTK2 GUI."
+msgstr "带 GTK2 图形界é¢ã€‚"
+
+msgid "with GTK GUI."
+msgstr "带 GTK 图形界é¢ã€‚"
+
+msgid "with X11-Motif GUI."
+msgstr "带 X11-Motif 图形界é¢ã€‚"
+
+msgid "with X11-neXtaw GUI."
+msgstr "带 X11-neXtaw 图形界é¢ã€‚"
+
+msgid "with X11-Athena GUI."
+msgstr "带 X11-Athena 图形界é¢ã€‚"
+
+msgid "with Photon GUI."
+msgstr "带 Photon 图形界é¢ã€‚"
+
+msgid "with GUI."
+msgstr "带图形界é¢ã€‚"
+
+msgid "with Carbon GUI."
+msgstr "带 Carbon 图形界é¢ã€‚"
+
+msgid "with Cocoa GUI."
+msgstr "带 Cocoa 图形界é¢ã€‚"
+
+msgid "with (classic) GUI."
+msgstr "带(传统)图形界é¢ã€‚"
+
+msgid " Features included (+) or not (-):\n"
+msgstr " å¯ä½¿ç”¨(+)与ä¸å¯ä½¿ç”¨(-)的功能:\n"
+
+msgid " system vimrc file: \""
+msgstr " 系统 vimrc 文件: \""
+
+msgid " user vimrc file: \""
+msgstr " 用户 vimrc 文件: \""
+
+msgid " 2nd user vimrc file: \""
+msgstr " 第二用户 vimrc 文件: \""
+
+msgid " 3rd user vimrc file: \""
+msgstr " 第三用户 vimrc 文件: \""
+
+msgid " user exrc file: \""
+msgstr " 用户 exrc 文件: \""
+
+msgid " 2nd user exrc file: \""
+msgstr " 第二用户 exrc 文件: \""
+
+msgid " system gvimrc file: \""
+msgstr " 系统 gvimrc 文件: \""
+
+msgid " user gvimrc file: \""
+msgstr " 用户 gvimrc 文件: \""
+
+msgid "2nd user gvimrc file: \""
+msgstr "第二用户 gvimrc 文件: \""
+
+msgid "3rd user gvimrc file: \""
+msgstr "第三用户 gvimrc 文件: \""
+
+msgid " system menu file: \""
+msgstr " 系统èœå•æ–‡ä»¶: \""
+
+msgid " fall-back for $VIM: \""
+msgstr " $VIM 预设值: \""
+
+msgid " f-b for $VIMRUNTIME: \""
+msgstr " $VIMRUNTIME 预设值: \""
+
+msgid "Compilation: "
+msgstr "编译方å¼: "
+
+msgid "Compiler: "
+msgstr "编译器: "
+
+msgid "Linking: "
+msgstr "链接方å¼: "
+
+msgid " DEBUG BUILD"
+msgstr " 调试版本"
+
+msgid "VIM - Vi IMproved"
+msgstr "VIM - Vi IMproved"
+
+msgid "version "
+msgstr "版本 "
+
+msgid "by Bram Moolenaar et al."
+msgstr "维护人 Bram Moolenaar 等"
+
+msgid "Vim is open source and freely distributable"
+msgstr "Vim 是å¯è‡ªç”±åˆ†å‘的开放æºä»£ç è½¯ä»¶"
+
+msgid "Help poor children in Uganda!"
+msgstr "帮助乌干达的å¯æ€œå„¿ç«¥ï¼"
+
+msgid "type :help iccf<Enter> for information "
+msgstr "输入 :help iccf<Enter> 查看说明 "
+
+msgid "type :q<Enter> to exit "
+msgstr "输入 :q<Enter> 退出 "
+
+msgid "type :help<Enter> or <F1> for on-line help"
+msgstr "输入 :help<Enter> 或 <F1> 查看在线帮助 "
+
+msgid "type :help version8<Enter> for version info"
+msgstr "输入 :help version8<Enter> æŸ¥çœ‹ç‰ˆæœ¬ä¿¡æ¯ "
+
+msgid "Running in Vi compatible mode"
+msgstr "è¿è¡ŒäºŽ Vi 兼容模å¼"
+
+msgid "type :set nocp<Enter> for Vim defaults"
+msgstr "输入 :set nocp<Enter> æ¢å¤é»˜è®¤çš„ Vim "
+
+msgid "type :help cp-default<Enter> for info on this"
+msgstr "输入 :help cp-default<Enter> 查看相关说明 "
+
+msgid "menu Help->Orphans for information "
+msgstr "èœå• 帮助->孤儿 查看说明 "
+
+msgid "Running modeless, typed text is inserted"
+msgstr "无模å¼è¿è¡Œï¼Œè¾“入文字å³æ’å…¥"
+
+msgid "menu Edit->Global Settings->Toggle Insert Mode "
+msgstr "èœå• 编辑->全局设定->å¼€/å…³æ’å…¥æ¨¡å¼ "
+
+#, fuzzy
+#~ msgid " for two modes "
+#~ msgstr " # pid æ•°æ®åº“å称 prepend path\n"
+
+#~ msgid "menu Edit->Global Settings->Toggle Vi Compatible"
+#~ msgstr ""
+
+#, fuzzy
+#~ msgid " for Vim defaults "
+#~ msgstr " # pid æ•°æ®åº“å称 prepend path\n"
+
+msgid "Sponsor Vim development!"
+msgstr "赞助 Vim çš„å¼€å‘ï¼"
+
+msgid "Become a registered Vim user!"
+msgstr "æˆä¸º Vim 的注册用户ï¼"
+
+msgid "type :help sponsor<Enter> for information "
+msgstr "输入 :help sponsor<Enter> 查看说明 "
+
+msgid "type :help register<Enter> for information "
+msgstr "输入 :help register<Enter> 查看说明 "
+
+msgid "menu Help->Sponsor/Register for information "
+msgstr "èœå• Help->Sponsor/Register 查看说明 "
+
+msgid "WARNING: Windows 95/98/ME detected"
+msgstr "警告: 检测到 Windows 95/98/ME"
+
+msgid "type :help windows95<Enter> for info on this"
+msgstr "输入 :help windows95<Enter> 查看相关说明 "
+
+msgid "Already only one window"
+msgstr "å·²ç»åªå‰©ä¸€ä¸ªçª—å£äº†"
+
+msgid "E441: There is no preview window"
+msgstr "E441: 没有预览窗å£"
+
+msgid "E442: Can't split topleft and botright at the same time"
+msgstr "E442: ä¸èƒ½åŒæ—¶è¿›è¡Œ topleft å’Œ botright 分割"
+
+msgid "E443: Cannot rotate when another window is split"
+msgstr "E443: 有其它分割窗å£æ—¶ä¸èƒ½æ—‹è½¬"
+
+msgid "E444: Cannot close last window"
+msgstr "E444: ä¸èƒ½å…³é—­æœ€åŽä¸€ä¸ªçª—å£"
+
+msgid "E445: Other window contains changes"
+msgstr "E445: 其它窗å£æœ‰æ”¹å˜çš„内容"
+
+msgid "E446: No file name under cursor"
+msgstr "E446: 光标处没有文件å"
+
+#, c-format
+msgid "E447: Can't find file \"%s\" in path"
+msgstr "E447: 在路径中找ä¸åˆ°æ–‡ä»¶ \"%s\""
+
+#, c-format
+msgid "E370: Could not load library %s"
+msgstr "E370: 无法加载库 %s"
+
+msgid "Sorry, this command is disabled: the Perl library could not be loaded."
+msgstr "抱歉,此命令ä¸å¯ç”¨: 无法加载 Perl 库。"
+
+#~ msgid "E299: Perl evaluation forbidden in sandbox without the Safe module"
+#~ msgstr ""
+
+msgid "Edit with &multiple Vims"
+msgstr "用多个 Vim 编辑(&M)"
+
+msgid "Edit with single &Vim"
+msgstr "用å•ä¸ª Vim 编辑(&V)"
+
+msgid "Diff with Vim"
+msgstr "用 Vim 比较(diff)"
+
+msgid "Edit with &Vim"
+msgstr "用 Vim 编辑(&V)"
+
+#. Now concatenate
+msgid "Edit with existing Vim - "
+msgstr "用当å‰çš„ Vim 编辑 - "
+
+msgid "Edits the selected file(s) with Vim"
+msgstr "用 Vim 编辑选中的文件"
+
+msgid "Error creating process: Check if gvim is in your path!"
+msgstr "创建进程失败: 请检查 gvim 是å¦åœ¨è·¯å¾„中ï¼"
+
+msgid "gvimext.dll error"
+msgstr "gvimext.dll 错误"
+
+msgid "Path length too long!"
+msgstr "路径太长ï¼"
+
+msgid "--No lines in buffer--"
+msgstr "--缓冲区无内容--"
+
+#.
+#. * The error messages that can be shared are included here.
+#. * Excluded are errors that are only used once and debugging messages.
+#.
+msgid "E470: Command aborted"
+msgstr "E470: 命令被中止"
+
+msgid "E471: Argument required"
+msgstr "E471: 需è¦å‚æ•°"
+
+msgid "E10: \\ should be followed by /, ? or &"
+msgstr "E10: \\ åŽé¢åº”该跟有 /ã€? 或 &"
+
+msgid "E11: Invalid in command-line window; <CR> executes, CTRL-C quits"
+msgstr "E11: 在命令行窗å£ä¸­æ— æ•ˆï¼›<CR> 执行,CTRL-C 退出"
+
+msgid "E12: Command not allowed from exrc/vimrc in current dir or tag search"
+msgstr "E12: 当å‰ç›®å½•ä¸­çš„ exrc/vimrc 或 tag 查找中ä¸å…许此命令"
+
+msgid "E171: Missing :endif"
+msgstr "E171: 缺少 :endif"
+
+msgid "E600: Missing :endtry"
+msgstr "E600: 缺少 :endtry"
+
+msgid "E170: Missing :endwhile"
+msgstr "E170: 缺少 :endwhile"
+
+msgid "E170: Missing :endfor"
+msgstr "E170: 缺少 :endfor"
+
+msgid "E588: :endwhile without :while"
+msgstr "E588: :endwhile 缺少对应的 :while"
+
+msgid "E588: :endfor without :for"
+msgstr "E588: :endfor 缺少对应的 :for"
+
+msgid "E13: File exists (add ! to override)"
+msgstr "E13: 文件已存在 (请加 ! 强制执行)"
+
+msgid "E472: Command failed"
+msgstr "E472: 命令执行失败"
+
+#, c-format
+msgid "E234: Unknown fontset: %s"
+msgstr "E234: 未知的 Fontset: %s"
+
+#, c-format
+msgid "E235: Unknown font: %s"
+msgstr "E235: 未知的字体: %s"
+
+#, c-format
+msgid "E236: Font \"%s\" is not fixed-width"
+msgstr "E236: 字体 \"%s\" ä¸æ˜¯ç­‰å®½å­—体"
+
+msgid "E473: Internal error"
+msgstr "E473: 内部错误"
+
+msgid "Interrupted"
+msgstr "已中断"
+
+msgid "E14: Invalid address"
+msgstr "E14: 无效的地å€"
+
+msgid "E474: Invalid argument"
+msgstr "E474: 无效的å‚æ•°"
+
+#, c-format
+msgid "E475: Invalid argument: %s"
+msgstr "E475: 无效的å‚æ•°: %s"
+
+#, c-format
+msgid "E15: Invalid expression: %s"
+msgstr "E15: 无效的表达å¼: %s"
+
+msgid "E16: Invalid range"
+msgstr "E16: 无效的范围"
+
+msgid "E476: Invalid command"
+msgstr "E476: 无效的命令"
+
+#, c-format
+msgid "E17: \"%s\" is a directory"
+msgstr "E17: \"%s\" 是目录"
+
+#, c-format
+msgid "E364: Library call failed for \"%s()\""
+msgstr "E364: 调用函数库 \"%s()\" 失败"
+
+#, c-format
+msgid "E448: Could not load library function %s"
+msgstr "E448: 无法加载库函数 %s"
+
+msgid "E19: Mark has invalid line number"
+msgstr "E19: 标记的行å·æ— æ•ˆ"
+
+msgid "E20: Mark not set"
+msgstr "E20: 没有设定标记"
+
+msgid "E21: Cannot make changes, 'modifiable' is off"
+msgstr "E21: ä¸èƒ½ä¿®æ”¹ï¼Œå› ä¸ºé€‰é¡¹ 'modifiable' 是关的"
+
+msgid "E22: Scripts nested too deep"
+msgstr "E22: 脚本嵌套过深"
+
+msgid "E23: No alternate file"
+msgstr "E23: 没有交替文件"
+
+msgid "E24: No such abbreviation"
+msgstr "E24: 没有这个缩写"
+
+msgid "E477: No ! allowed"
+msgstr "E477: ä¸èƒ½ä½¿ç”¨ \"!\""
+
+msgid "E25: GUI cannot be used: Not enabled at compile time"
+msgstr "E25: 无法使用图形界é¢: 编译时没有å¯ç”¨"
+
+msgid "E26: Hebrew cannot be used: Not enabled at compile time\n"
+msgstr "E26: 无法使用 Hebrew: 编译时没有å¯ç”¨\n"
+
+msgid "E27: Farsi cannot be used: Not enabled at compile time\n"
+msgstr "E27: 无法使用 Farsi: 编译时没有å¯ç”¨\n"
+
+msgid "E800: Arabic cannot be used: Not enabled at compile time\n"
+msgstr "E800: 无法使用 Arabic: 编译时没有å¯ç”¨\n"
+
+#, c-format
+msgid "E28: No such highlight group name: %s"
+msgstr "E28: 没有这个高亮群组å: %s"
+
+msgid "E29: No inserted text yet"
+msgstr "E29: 没有æ’入过文字"
+
+msgid "E30: No previous command line"
+msgstr "E30: 没有å‰ä¸€ä¸ªå‘½ä»¤è¡Œ"
+
+msgid "E31: No such mapping"
+msgstr "E31: 没有这个映射"
+
+msgid "E479: No match"
+msgstr "E479: 没有匹é…"
+
+#, c-format
+msgid "E480: No match: %s"
+msgstr "E480: 没有匹é…: %s"
+
+msgid "E32: No file name"
+msgstr "E32: 没有文件å"
+
+msgid "E33: No previous substitute regular expression"
+msgstr "E33: 没有å‰ä¸€ä¸ªæ›¿æ¢æ­£åˆ™è¡¨è¾¾å¼"
+
+msgid "E34: No previous command"
+msgstr "E34: 没有å‰ä¸€ä¸ªå‘½ä»¤"
+
+msgid "E35: No previous regular expression"
+msgstr "E35: 没有å‰ä¸€ä¸ªæ­£åˆ™è¡¨è¾¾å¼"
+
+msgid "E481: No range allowed"
+msgstr "E481: ä¸èƒ½ä½¿ç”¨èŒƒå›´"
+
+msgid "E36: Not enough room"
+msgstr "E36: 没有足够的空间"
+
+#, c-format
+msgid "E247: no registered server named \"%s\""
+msgstr "E247: 没有åå« \"%s\" 的已注册的æœåŠ¡å™¨"
+
+#, c-format
+msgid "E482: Can't create file %s"
+msgstr "E482: 无法创建文件 %s"
+
+msgid "E483: Can't get temp file name"
+msgstr "E483: 无法获å–临时文件å"
+
+#, c-format
+msgid "E484: Can't open file %s"
+msgstr "E484: 无法打开文件 %s"
+
+#, c-format
+msgid "E485: Can't read file %s"
+msgstr "E485: 无法读å–文件 %s"
+
+msgid "E37: No write since last change (add ! to override)"
+msgstr "E37: 已修改但尚未ä¿å­˜ (å¯ç”¨ ! 强制执行)"
+
+msgid "E38: Null argument"
+msgstr "E38: 空的å‚æ•°"
+
+msgid "E39: Number expected"
+msgstr "E39: 此处需è¦æ•°å­—"
+
+#, c-format
+msgid "E40: Can't open errorfile %s"
+msgstr "E40: 无法打开错误文件 %s"
+
+msgid "E233: cannot open display"
+msgstr "E233: 无法打开 display"
+
+msgid "E41: Out of memory!"
+msgstr "E41: 内存ä¸è¶³ï¼"
+
+msgid "Pattern not found"
+msgstr "找ä¸åˆ°æ¨¡å¼"
+
+#, c-format
+msgid "E486: Pattern not found: %s"
+msgstr "E486: 找ä¸åˆ°æ¨¡å¼: %s"
+
+msgid "E487: Argument must be positive"
+msgstr "E487: å‚数必须是正数"
+
+msgid "E459: Cannot go back to previous directory"
+msgstr "E459: 无法回到å‰ä¸€ä¸ªç›®å½•"
+
+msgid "E42: No Errors"
+msgstr "E42: 没有错误"
+
+msgid "E776: No location list"
+msgstr "E776: 没有 location 列表"
+
+msgid "E43: Damaged match string"
+msgstr "E43: å·²æŸå的匹é…字符串"
+
+msgid "E44: Corrupted regexp program"
+msgstr "E44: å·²æŸå的正则表达å¼ç¨‹åº"
+
+msgid "E45: 'readonly' option is set (add ! to override)"
+msgstr "E45: 已设定选项 'readonly' (请加 ! 强制执行)"
+
+#, c-format
+msgid "E46: Cannot change read-only variable \"%s\""
+msgstr "E46: ä¸èƒ½æ”¹å˜åªè¯»å˜é‡ \"%s\""
+
+#, c-format
+msgid "E46: Cannot set variable in the sandbox: \"%s\""
+msgstr "E46: ä¸èƒ½åœ¨ sandbox 中设定å˜é‡: \"%s\""
+
+msgid "E47: Error while reading errorfile"
+msgstr "E47: 读å–错误文件失败"
+
+msgid "E48: Not allowed in sandbox"
+msgstr "E48: ä¸å…许在 sandbox 中使用"
+
+msgid "E523: Not allowed here"
+msgstr "E523: ä¸å…许在此使用"
+
+msgid "E359: Screen mode setting not supported"
+msgstr "E359: ä¸æ”¯æŒè®¾å®šå±å¹•æ¨¡å¼"
+
+msgid "E49: Invalid scroll size"
+msgstr "E49: 无效的滚动大å°"
+
+msgid "E91: 'shell' option is empty"
+msgstr "E91: 选项 'shell' 为空"
+
+msgid "E255: Couldn't read in sign data!"
+msgstr "E255: æ— æ³•è¯»å– sign æ•°æ®ï¼"
+
+msgid "E72: Close error on swap file"
+msgstr "E72: 交æ¢æ–‡ä»¶å…³é—­é”™è¯¯"
+
+msgid "E73: tag stack empty"
+msgstr "E73: tag 堆栈为空"
+
+msgid "E74: Command too complex"
+msgstr "E74: 命令过å¤æ‚"
+
+msgid "E75: Name too long"
+msgstr "E75: å字过长"
+
+msgid "E76: Too many ["
+msgstr "E76: [ 过多"
+
+msgid "E77: Too many file names"
+msgstr "E77: 文件å过多"
+
+msgid "E488: Trailing characters"
+msgstr "E488: 多余的尾部字符"
+
+msgid "E78: Unknown mark"
+msgstr "E78: 未知的标记"
+
+msgid "E79: Cannot expand wildcards"
+msgstr "E79: 无法扩展通é…符"
+
+msgid "E591: 'winheight' cannot be smaller than 'winminheight'"
+msgstr "E591: 'winheight' ä¸èƒ½å°äºŽ 'winminheight'"
+
+msgid "E592: 'winwidth' cannot be smaller than 'winminwidth'"
+msgstr "E592: 'winwidth' ä¸èƒ½å°äºŽ 'winminwidth'"
+
+msgid "E80: Error while writing"
+msgstr "E80: 写入出错"
+
+msgid "Zero count"
+msgstr "计数为零"
+
+msgid "E81: Using <SID> not in a script context"
+msgstr "E81: 在脚本环境外使用了 <SID>"
+
+msgid "E449: Invalid expression received"
+msgstr "E449: 收到无效的表达å¼"
+
+#~ msgid "E463: Region is guarded, cannot modify"
+#~ msgstr ""
+
+msgid "E744: NetBeans does not allow changes in read-only files"
+msgstr "E744: NetBeans ä¸å…许改å˜åªè¯»æ–‡ä»¶"
+
+#, c-format
+msgid "E685: Internal error: %s"
+msgstr "E685: 内部错误: %s"
+
+msgid "E363: pattern uses more memory than 'maxmempattern'"
+msgstr "E363: 表达å¼çš„内存使用超出 'maxmempattern'"
+
+msgid "E749: empty buffer"
+msgstr "E749: 空的缓冲区"
+
+msgid "E682: Invalid search pattern or delimiter"
+msgstr "E682: 无效的æœç´¢è¡¨è¾¾å¼æˆ–分隔符"
+
+msgid "E139: File is loaded in another buffer"
+msgstr "E139: 文件已在å¦ä¸€ä¸ªç¼“冲区中被加载"
+
+#, c-format
+msgid "E764: Option '%s' is not set"
+msgstr "E764: 没有设定选项 '%s'"
+
+msgid "search hit TOP, continuing at BOTTOM"
+msgstr "已查找到文件开头,å†ä»Žç»“尾继续查找"
+
+msgid "search hit BOTTOM, continuing at TOP"
+msgstr "已查找到文件结尾,å†ä»Žå¼€å¤´ç»§ç»­æŸ¥æ‰¾"
+
+#~ msgid "Affix flags ignored when PFXPOSTPONE used in %s line %d: %s"
+#~ msgstr "%s 第 %d 行,使用 PFXPOSTPONE 时附加标志被忽略: %s"
+
+#~ msgid "[No file]"
+#~ msgstr "[未命å]"
+
+#~ msgid "[Error List]"
+#~ msgstr "[错误列表]"
+
+#~ msgid "E106: Unknown variable: \"%s\""
+#~ msgstr "E106: 未定义的å˜é‡: \"%s\""
+
+#~ msgid "E119: Not enough arguments for function: %s"
+#~ msgstr "E119: 函数 %s çš„å‚数太少"
+
+#~ msgid "E120: Using <SID> not in a script context: %s"
+#~ msgstr "E120: <SID> ä¸èƒ½åœ¨ script 上下文外使用: %s"
+
+#~ msgid "E123: Undefined function: %s"
+#~ msgstr "E123: 函数 %s 尚未定义"
+
+#~ msgid "E127: Cannot redefine function %s: It is in use"
+#~ msgstr "E127: 函数 %s 正在使用中,ä¸èƒ½é‡æ–°å®šä¹‰"
+
+#~ msgid "function "
+#~ msgstr "函数 "
+
+#~ msgid "E130: Undefined function: %s"
+#~ msgstr "E130: 函数 %s 尚未定义"
+
+#~ msgid "Run Macro"
+#~ msgstr "执行å®"
+
+#~ msgid "E242: Color name not recognized: %s"
+#~ msgstr "E242: %s 为ä¸èƒ½è¯†åˆ«çš„颜色å称"
+
+#~ msgid "error reading cscope connection %d"
+#~ msgstr "è¯»å– cscope 连接 %d 时错误"
+
+#~ msgid "E260: cscope connection not found"
+#~ msgstr "E260: 找ä¸åˆ° cscope 连接"
+
+#~ msgid "cscope connection closed"
+#~ msgstr "cscope 连接已关闭"
+
+#~ msgid "couldn't malloc\n"
+#~ msgstr "ä¸èƒ½ä½¿ç”¨ malloc\n"
+
+#~ msgid "%2d %-5ld %-34s <none>\n"
+#~ msgstr "%2d %-5ld %-34s <æ— >\n"
+
+#~ msgid "E249: couldn't read VIM instance registry property"
+#~ msgstr "E249: ä¸èƒ½è¯»å– VIM çš„ 注册表属性"
+
+#~ msgid "\"\n"
+#~ msgstr "\"\n"
+
+#~ msgid "--help\t\tShow Gnome arguments"
+#~ msgstr "--help\t\t显示 Gnome 相关å‚æ•°"
+
+#~ msgid "[string too long]"
+#~ msgstr "[字符串太长]"
+
+#~ msgid "Hit ENTER to continue"
+#~ msgstr "请按 ENTER 继续"
+
+#~ msgid " (RET/BS: line, SPACE/b: page, d/u: half page, q: quit)"
+#~ msgstr " (RET/BS: å‘下/å‘上一行, 空格/b: 一页, d/u: åŠé¡µ, q: 退出)"
+
+#~ msgid " (RET: line, SPACE: page, d: half page, q: quit)"
+#~ msgstr " (RET: å‘下一行, 空白键: 一页, d: åŠé¡µ, q: 退出)"
+
+#~ msgid "E361: Crash intercepted; regexp too complex?"
+#~ msgstr "E361: ä¸èƒ½æ‰§è¡Œ; regular expression 太å¤æ‚?"
+
+#~ msgid "E363: pattern caused out-of-stack error"
+#~ msgstr "E363: regular expression 造æˆå †æ ˆç”¨å…‰çš„错误"
+
+#~ msgid " BLOCK"
+#~ msgstr " å—"
+
+#~ msgid " LINE"
+#~ msgstr " 行"
+
+#~ msgid "Enter nr of choice (<CR> to abort): "
+#~ msgstr "输入 nr 或选择 (<CR> 退出): "
+
+#~ msgid "Linear tag search"
+#~ msgstr "线性查找标签 (Tags)"
+
+#~ msgid "Binary tag search"
+#~ msgstr "二进制查找(Binary search) 标签(Tags)"
+
+#~ msgid "with BeOS GUI."
+#~ msgstr "使用 BeOS 图形界é¢ã€‚"
diff --git a/src/po/zh_CN.cp936.po b/src/po/zh_CN.cp936.po
new file mode 100644
index 0000000..6647d23
--- /dev/null
+++ b/src/po/zh_CN.cp936.po
@@ -0,0 +1,6140 @@
+# Chinese (simplified) Translation for Vim
+#
+# Do ":help uganda" in Vim to read copying and usage conditions.
+# Do ":help credits" in Vim to see a list of people who contributed.
+#
+# FIRST AUTHOR Wang Jun <junw@turbolinux.com.cn>
+#
+# TRANSLATORS
+# Edyfox <edyfox@gmail.com>
+# Yuheng Xie <elephant@linux.net.cn>
+#
+# Generated from zh_CN.UTF-8.po, DO NOT EDIT.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Vim(Simplified Chinese)\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2006-04-21 15:16+0800\n"
+"PO-Revision-Date: 2006-04-21 14:00+0800\n"
+"Last-Translator: Yuheng Xie\n"
+"Language-Team: Simplified Chinese\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=gbk\n"
+"Content-Transfer-Encoding: 8-bit\n"
+
+msgid "E82: Cannot allocate any buffer, exiting..."
+msgstr "E82: ÎÞ·¨·ÖÅäÈκλº³åÇø£¬Í˳ö³ÌÐò..."
+
+msgid "E83: Cannot allocate buffer, using other one..."
+msgstr "E83: ÎÞ·¨·ÖÅ仺³åÇø£¬Ê¹ÓÃÁíÒ»¸ö»º³åÇø..."
+
+msgid "E515: No buffers were unloaded"
+msgstr "E515: ûÓÐÊÍ·ÅÈκλº³åÇø"
+
+msgid "E516: No buffers were deleted"
+msgstr "E516: ûÓÐɾ³ýÈκλº³åÇø"
+
+msgid "E517: No buffers were wiped out"
+msgstr "E517: ûÓÐÇå³ýÈκλº³åÇø"
+
+msgid "1 buffer unloaded"
+msgstr "ÊÍ·ÅÁË 1 ¸ö»º³åÇø"
+
+#, c-format
+msgid "%d buffers unloaded"
+msgstr "ÊÍ·ÅÁË %d ¸ö»º³åÇø"
+
+msgid "1 buffer deleted"
+msgstr "ɾ³ýÁË 1 ¸ö»º³åÇø"
+
+#, c-format
+msgid "%d buffers deleted"
+msgstr "ɾ³ýÁË %d ¸ö»º³åÇø"
+
+msgid "1 buffer wiped out"
+msgstr "Çå³ýÁË 1 ¸ö»º³åÇø"
+
+#, c-format
+msgid "%d buffers wiped out"
+msgstr "Çå³ýÁË %d ¸ö»º³åÇø"
+
+msgid "E84: No modified buffer found"
+msgstr "E84: ûÓÐÐ޸ĹýµÄ»º³åÇø"
+
+#. back where we started, didn't find anything.
+msgid "E85: There is no listed buffer"
+msgstr "E85: ûÓпÉÁгöµÄ»º³åÇø"
+
+#, c-format
+msgid "E86: Buffer %ld does not exist"
+msgstr "E86: »º³åÇø %ld ²»´æÔÚ"
+
+msgid "E87: Cannot go beyond last buffer"
+msgstr "E87: ÎÞ·¨Çл»£¬ÒÑÊÇ×îºóÒ»¸ö»º³åÇø"
+
+msgid "E88: Cannot go before first buffer"
+msgstr "E88: ÎÞ·¨Çл»£¬ÒÑÊǵÚÒ»¸ö»º³åÇø"
+
+#, c-format
+msgid "E89: No write since last change for buffer %ld (add ! to override)"
+msgstr "E89: »º³åÇø %ld ÒÑÐ޸ĵ«ÉÐδ±£´æ (Çë¼Ó ! Ç¿ÖÆÖ´ÐÐ)"
+
+msgid "E90: Cannot unload last buffer"
+msgstr "E90: ÎÞ·¨ÊÍ·Å×îºóÒ»¸ö»º³åÇø"
+
+msgid "W14: Warning: List of file names overflow"
+msgstr "W14: ¾¯¸æ: ÎļþÃû¹ý¶à"
+
+#, c-format
+msgid "E92: Buffer %ld not found"
+msgstr "E92: ÕÒ²»µ½»º³åÇø %ld"
+
+#, c-format
+msgid "E93: More than one match for %s"
+msgstr "E93: ÕÒµ½²»Ö¹Ò»¸ö %s"
+
+#, c-format
+msgid "E94: No matching buffer for %s"
+msgstr "E94: ûÓÐÆ¥ÅäµÄ»º³åÇø %s"
+
+#, c-format
+msgid "line %ld"
+msgstr "µÚ %ld ÐÐ"
+
+msgid "E95: Buffer with this name already exists"
+msgstr "E95: ÒÑÓлº³åÇøʹÓøÃÃû³Æ"
+
+msgid " [Modified]"
+msgstr " [ÒÑÐÞ¸Ä]"
+
+msgid "[Not edited]"
+msgstr "[δ±à¼­]"
+
+msgid "[New file]"
+msgstr "[ÐÂÎļþ]"
+
+msgid "[Read errors]"
+msgstr "[¶Á´íÎó]"
+
+msgid "[readonly]"
+msgstr "[Ö»¶Á]"
+
+#, c-format
+msgid "1 line --%d%%--"
+msgstr "1 ÐÐ --%d%%--"
+
+#, c-format
+msgid "%ld lines --%d%%--"
+msgstr "%ld ÐÐ --%d%%--"
+
+#, c-format
+msgid "line %ld of %ld --%d%%-- col "
+msgstr "ÐÐ %ld / %ld --%d%%-- ÁÐ "
+
+msgid "[No Name]"
+msgstr "[δÃüÃû]"
+
+#. must be a help buffer
+msgid "help"
+msgstr "°ïÖú"
+
+msgid "[Help]"
+msgstr "[°ïÖú]"
+
+msgid "[Preview]"
+msgstr "[Ô¤ÀÀ]"
+
+msgid "All"
+msgstr "È«²¿"
+
+msgid "Bot"
+msgstr "µ×¶Ë"
+
+msgid "Top"
+msgstr "¶¥¶Ë"
+
+#, c-format
+msgid ""
+"\n"
+"# Buffer list:\n"
+msgstr ""
+"\n"
+"# »º³åÇøÁбí:\n"
+
+msgid "[Location List]"
+msgstr "[Location Áбí]"
+
+msgid "[Quickfix List]"
+msgstr "[Quickfix Áбí]"
+
+msgid ""
+"\n"
+"--- Signs ---"
+msgstr ""
+"\n"
+"--- Signs ---"
+
+#, c-format
+msgid "Signs for %s:"
+msgstr "%s µÄ Signs:"
+
+#, c-format
+msgid " line=%ld id=%d name=%s"
+msgstr " ÐÐ=%ld id=%d Ãû³Æ=%s"
+
+#, c-format
+msgid "E96: Can not diff more than %ld buffers"
+msgstr "E96: ²»ÄܱȽÏ(diff) %ld ¸öÒÔÉϵĻº³åÇø"
+
+msgid "E97: Cannot create diffs"
+msgstr "E97: ÎÞ·¨´´½¨ diff"
+
+msgid "Patch file"
+msgstr "Patch Îļþ"
+
+msgid "E98: Cannot read diff output"
+msgstr "E98: ÎÞ·¨¶ÁÈ¡ diff µÄÊä³ö"
+
+msgid "E99: Current buffer is not in diff mode"
+msgstr "E99: µ±Ç°»º³åÇø²»ÔÚ diff ģʽ"
+
+msgid "E100: No other buffer in diff mode"
+msgstr "E100: ûÓÐÆäËü´¦ÓÚ diff ģʽµÄ»º³åÇø"
+
+msgid "E101: More than two buffers in diff mode, don't know which one to use"
+msgstr "E101: ÓÐÁ½¸öÒÔÉϵĻº³åÇø´¦ÓÚ diff ģʽ£¬²»Äܾö¶¨ÓÃÄÄÒ»¸ö"
+
+#, c-format
+msgid "E102: Can't find buffer \"%s\""
+msgstr "E102: ÕÒ²»µ½»º³åÇø \"%s\""
+
+#, c-format
+msgid "E103: Buffer \"%s\" is not in diff mode"
+msgstr "E103: »º³åÇø \"%s\" ²»ÔÚ diff ģʽ"
+
+msgid "E787: Buffer changed unexpectedly"
+msgstr "E787: ÒâÍâµØ¸Ä±äÁË»º³åÇø"
+
+msgid "E104: Escape not allowed in digraph"
+msgstr "E104: ¸´ºÏ×Ö·û(digraph)Öв»ÄÜʹÓà Escape"
+
+msgid "E544: Keymap file not found"
+msgstr "E544: ÕÒ²»µ½ Keymap Îļþ"
+
+msgid "E105: Using :loadkeymap not in a sourced file"
+msgstr "E105: ²»ÊÇÔڽű¾ÎļþÖÐʹÓà :loadkeymap "
+
+msgid " Keyword completion (^N^P)"
+msgstr " ¹Ø¼ü×Ö²¹È« (^N^P)"
+
+#. ctrl_x_mode == 0, ^P/^N compl.
+msgid " ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+msgstr " ^X ģʽ (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+
+msgid " Whole line completion (^L^N^P)"
+msgstr " ÕûÐв¹È« (^L^N^P)"
+
+msgid " File name completion (^F^N^P)"
+msgstr " ÎļþÃû²¹È« (^F^N^P)"
+
+msgid " Tag completion (^]^N^P)"
+msgstr " Tag ²¹È« (^]^N^P)"
+
+msgid " Path pattern completion (^N^P)"
+msgstr " Í·Îļþģʽ²¹È« (^N^P)"
+
+msgid " Definition completion (^D^N^P)"
+msgstr " ¶¨Ò岹ȫ (^D^N^P)"
+
+msgid " Dictionary completion (^K^N^P)"
+msgstr " Dictionary ²¹È« (^K^N^P)"
+
+msgid " Thesaurus completion (^T^N^P)"
+msgstr " Thesaurus ²¹È« (^T^N^P)"
+
+msgid " Command-line completion (^V^N^P)"
+msgstr " ÃüÁîÐв¹È« (^V^N^P)"
+
+msgid " User defined completion (^U^N^P)"
+msgstr " Óû§×Ô¶¨Ò岹ȫ (^U^N^P)"
+
+msgid " Omni completion (^O^N^P)"
+msgstr " È«Äܲ¹È« (^O^N^P)"
+
+msgid " Spelling suggestion (s^N^P)"
+msgstr " ƴд½¨Òé (s^N^P)"
+
+msgid " Keyword Local completion (^N^P)"
+msgstr " ¹Ø¼ü×Ö¾Ö²¿²¹È« (^N^P)"
+
+msgid "Hit end of paragraph"
+msgstr "Òѵ½¶ÎÂä½áβ"
+
+msgid "'dictionary' option is empty"
+msgstr "Ñ¡Ïî 'dictionary' Ϊ¿Õ"
+
+msgid "'thesaurus' option is empty"
+msgstr "Ñ¡Ïî 'thesaurus' Ϊ¿Õ"
+
+#, c-format
+msgid "Scanning dictionary: %s"
+msgstr "ÕýÔÚɨÃè dictionary: %s"
+
+msgid " (insert) Scroll (^E/^Y)"
+msgstr " (²åÈë) Scroll (^E/^Y)"
+
+msgid " (replace) Scroll (^E/^Y)"
+msgstr " (Ìæ»») Scroll (^E/^Y)"
+
+#, c-format
+msgid "Scanning: %s"
+msgstr "ÕýÔÚɨÃè: %s"
+
+#, c-format
+msgid "Scanning tags."
+msgstr "ɨÃè±êÇ©."
+
+msgid " Adding"
+msgstr " Ôö¼Ó"
+
+#. showmode might reset the internal line pointers, so it must
+#. * be called before line = ml_get(), or when this address is no
+#. * longer needed. -- Acevedo.
+#.
+msgid "-- Searching..."
+msgstr "-- ²éÕÒÖÐ..."
+
+msgid "Back at original"
+msgstr "»Øµ½Æðµã"
+
+msgid "Word from other line"
+msgstr "ÁíÒ»ÐеĴÊ"
+
+msgid "The only match"
+msgstr "ΨһƥÅä"
+
+#, c-format
+msgid "match %d of %d"
+msgstr "Æ¥Åä %d / %d"
+
+#, c-format
+msgid "match %d"
+msgstr "Æ¥Åä %d"
+
+msgid "E18: Unexpected characters in :let"
+msgstr "E18: :let ÖгöÏÖÒì³£×Ö·û"
+
+#, c-format
+msgid "E684: list index out of range: %ld"
+msgstr "E684: List Ë÷Òý³¬³ö·¶Î§: %ld"
+
+#, c-format
+msgid "E121: Undefined variable: %s"
+msgstr "E121: 䶨ÒåµÄ±äÁ¿: %s"
+
+msgid "E111: Missing ']'"
+msgstr "E111: ȱÉÙ ']'"
+
+#, c-format
+msgid "E686: Argument of %s must be a List"
+msgstr "E686: %s µÄ²ÎÊý±ØÐëÊÇ List"
+
+#, c-format
+msgid "E712: Argument of %s must be a List or Dictionary"
+msgstr "E712: %s µÄ²ÎÊý±ØÐëÊÇ List »òÕß Dictionary"
+
+msgid "E713: Cannot use empty key for Dictionary"
+msgstr "E713: Dictionary µÄ¼ü²»ÄÜΪ¿Õ"
+
+msgid "E714: List required"
+msgstr "E714: ÐèÒª List"
+
+msgid "E715: Dictionary required"
+msgstr "E715: ÐèÒª Dictionary"
+
+#, c-format
+msgid "E118: Too many arguments for function: %s"
+msgstr "E118: º¯ÊýµÄ²ÎÊý¹ý¶à: %s"
+
+#, c-format
+msgid "E716: Key not present in Dictionary: %s"
+msgstr "E716: Dictionary Öв»´æÔÚ¼ü: %s"
+
+#, c-format
+msgid "E122: Function %s already exists, add ! to replace it"
+msgstr "E122: º¯Êý %s ÒÑ´æÔÚ£¬Çë¼Ó ! Ç¿ÖÆÌæ»»"
+
+msgid "E717: Dictionary entry already exists"
+msgstr "E717: Dictionary ÏîÒÑ´æÔÚ"
+
+msgid "E718: Funcref required"
+msgstr "E718: ÐèÒª Funcref"
+
+msgid "E719: Cannot use [:] with a Dictionary"
+msgstr "E719: ²»ÄÜ¶Ô Dictionary ʹÓà [:]"
+
+#, c-format
+msgid "E734: Wrong variable type for %s="
+msgstr "E734: %s= µÄ±äÁ¿ÀàÐͲ»ÕýÈ·"
+
+#, c-format
+msgid "E130: Unknown function: %s"
+msgstr "E130: δ֪µÄº¯Êý: %s"
+
+#, c-format
+msgid "E461: Illegal variable name: %s"
+msgstr "E461: ÎÞЧµÄ±äÁ¿Ãû: %s"
+
+msgid "E687: Less targets than List items"
+msgstr "E687: Ä¿±ê±È List ÏîÊýÉÙ"
+
+msgid "E688: More targets than List items"
+msgstr "E688: Ä¿±ê±È List ÏîÊý¶à"
+
+msgid "Double ; in list of variables"
+msgstr "±äÁ¿ÁбíÖгöÏÖÁ½¸ö ;"
+
+#, c-format
+msgid "E738: Can't list variables for %s"
+msgstr "E738: ÎÞ·¨Áгö %s µÄ±äÁ¿"
+
+msgid "E689: Can only index a List or Dictionary"
+msgstr "E689: Ö»ÄÜË÷Òý List »ò Dictionary"
+
+msgid "E708: [:] must come last"
+msgstr "E708: [:] ±ØÐëÔÚ×îºó"
+
+msgid "E709: [:] requires a List value"
+msgstr "E709: [:] ÐèÒªÒ»¸ö List Öµ"
+
+msgid "E710: List value has more items than target"
+msgstr "E710: List ÖµµÄÏî±ÈÄ¿±ê¶à"
+
+msgid "E711: List value has not enough items"
+msgstr "E711: List ֵûÓÐ×ã¹»¶àµÄÏî"
+
+msgid "E690: Missing \"in\" after :for"
+msgstr "E690: :for ºóȱÉÙ \"in\""
+
+#, c-format
+msgid "E107: Missing parentheses: %s"
+msgstr "E107: ȱÉÙÀ¨ºÅ: %s"
+
+#, c-format
+msgid "E108: No such variable: \"%s\""
+msgstr "E108: Î޴˱äÁ¿: \"%s\""
+
+msgid "E743: variable nested too deep for (un)lock"
+msgstr "E743: (un)lock µÄ±äÁ¿Ç¶Ì×¹ýÉî"
+
+msgid "E109: Missing ':' after '?'"
+msgstr "E109: '?' ºóȱÉÙ ':'"
+
+msgid "E691: Can only compare List with List"
+msgstr "E691: Ö»ÄÜ±È½Ï List ºÍ List"
+
+msgid "E692: Invalid operation for List"
+msgstr "E692: ¶Ô List ÎÞЧµÄ²Ù×÷"
+
+msgid "E735: Can only compare Dictionary with Dictionary"
+msgstr "E735: Ö»ÄÜ±È½Ï Dictionary ºÍ Dictionary"
+
+msgid "E736: Invalid operation for Dictionary"
+msgstr "E736: ¶Ô Dictionary ÎÞЧµÄ²Ù×÷"
+
+msgid "E693: Can only compare Funcref with Funcref"
+msgstr "E693: Ö»ÄÜ±È½Ï Funcref ºÍ Funcref"
+
+msgid "E694: Invalid operation for Funcrefs"
+msgstr "E694: ¶Ô Funcrefs ÎÞЧµÄ²Ù×÷"
+
+msgid "E110: Missing ')'"
+msgstr "E110: ȱÉÙ ')'"
+
+msgid "E695: Cannot index a Funcref"
+msgstr "E695: ²»ÄÜË÷ÒýÒ»¸ö Funcref"
+
+#, c-format
+msgid "E112: Option name missing: %s"
+msgstr "E112: ȱÉÙÑ¡ÏîÃû³Æ: %s"
+
+#, c-format
+msgid "E113: Unknown option: %s"
+msgstr "E113: δ֪µÄÑ¡Ïî: %s"
+
+#, c-format
+msgid "E114: Missing quote: %s"
+msgstr "E114: ȱÉÙÒýºÅ: %s"
+
+#, c-format
+msgid "E115: Missing quote: %s"
+msgstr "E115: ȱÉÙÒýºÅ: %s"
+
+#, c-format
+msgid "E696: Missing comma in List: %s"
+msgstr "E696: List ÖÐȱÉÙ¶ººÅ: %s"
+
+#, c-format
+msgid "E697: Missing end of List ']': %s"
+msgstr "E697: List ȱÉÙ½áÊø·û ']': %s"
+
+#, c-format
+msgid "E720: Missing colon in Dictionary: %s"
+msgstr "E720: Dictionary ÖÐȱÉÙðºÅ: %s"
+
+#, c-format
+msgid "E721: Duplicate key in Dictionary: \"%s\""
+msgstr "E721: Dictionary ÖгöÏÖÖظ´µÄ¼ü: \"%s\""
+
+#, c-format
+msgid "E722: Missing comma in Dictionary: %s"
+msgstr "E722: Dictionary ÖÐȱÉÙ¶ººÅ: %s"
+
+#, c-format
+msgid "E723: Missing end of Dictionary '}': %s"
+msgstr "E723: Dictionary ȱÉÙ½áÊø·û '}': %s"
+
+msgid "E724: variable nested too deep for displaying"
+msgstr "E724: ±äÁ¿Ç¶Ì×¹ýÉîÎÞ·¨ÏÔʾ"
+
+msgid "E699: Too many arguments"
+msgstr "E699: ²ÎÊý¹ý¶à"
+
+msgid "E785: complete() can only be used in Insert mode"
+msgstr "E785: complete() Ö»ÄÜÔÚ²åÈëģʽÖÐʹÓÃ"
+
+#.
+#. * Yes this is ugly, I don't particularly like it either. But doing it
+#. * this way has the compelling advantage that translations need not to
+#. * be touched at all. See below what 'ok' and 'ync' are used for.
+#.
+msgid "&Ok"
+msgstr "È·¶¨(&O)"
+
+#, c-format
+msgid "E737: Key already exists: %s"
+msgstr "E737: ¼üÒÑ´æÔÚ: %s"
+
+#, c-format
+msgid "+-%s%3ld lines: "
+msgstr "+-%s%3ld ÐÐ: "
+
+#, c-format
+msgid "E700: Unknown function: %s"
+msgstr "E700: δ֪µÄº¯Êý: %s"
+
+msgid ""
+"&OK\n"
+"&Cancel"
+msgstr ""
+"È·¶¨(&O)\n"
+"È¡Ïû(&C)"
+
+msgid "called inputrestore() more often than inputsave()"
+msgstr "inputrestore() µÄµ÷ÓôÎÊý¶àÓÚ inputsave()"
+
+msgid "E786: Range not allowed"
+msgstr "E786: ²»ÔÊÐíµÄ·¶Î§"
+
+msgid "E701: Invalid type for len()"
+msgstr "E701: len() µÄÀàÐÍÎÞЧ"
+
+msgid "E726: Stride is zero"
+msgstr "E726: ²½³¤ÎªÁã"
+
+msgid "E727: Start past end"
+msgstr "E727: ÆðʼֵÔÚÖÕÖ¹Öµºó"
+
+msgid "<empty>"
+msgstr "<¿Õ>"
+
+msgid "E240: No connection to Vim server"
+msgstr "E240: ûÓе½ Vim ·þÎñÆ÷µÄÁ¬½Ó"
+
+#, c-format
+msgid "E241: Unable to send to %s"
+msgstr "E241: ÎÞ·¨·¢Ë͵½ %s"
+
+msgid "E277: Unable to read a server reply"
+msgstr "E277: ÎÞ·¨¶ÁÈ¡·þÎñÆ÷ÏìÓ¦"
+
+msgid "E655: Too many symbolic links (cycle?)"
+msgstr "E655: ·ûºÅÁ¬½Ó¹ý¶à(Ñ­»·£¿)"
+
+msgid "E258: Unable to send to client"
+msgstr "E258: ÎÞ·¨·¢Ë͵½¿Í»§¶Ë"
+
+msgid "E702: Sort compare function failed"
+msgstr "E702: Sort ±È½Ïº¯Êýʧ°Ü"
+
+msgid "(Invalid)"
+msgstr "(ÎÞЧ)"
+
+msgid "E677: Error writing temp file"
+msgstr "E677: дÁÙʱÎļþ³ö´í"
+
+msgid "E703: Using a Funcref as a Number"
+msgstr "E703: ½« Funcref ×÷Êý×ÖʹÓÃ"
+
+msgid "E745: Using a List as a Number"
+msgstr "E745: ½« List ×÷Êý×ÖʹÓÃ"
+
+msgid "E728: Using a Dictionary as a Number"
+msgstr "E728: ½« Dictionary ×÷Êý×ÖʹÓÃ"
+
+msgid "E729: using Funcref as a String"
+msgstr "E729: ½« Funcref ×÷ String ʹÓÃ"
+
+msgid "E730: using List as a String"
+msgstr "E730: ½« List ×÷ String ʹÓÃ"
+
+msgid "E731: using Dictionary as a String"
+msgstr "E731: ½« Dictionary ×÷ String ʹÓÃ"
+
+#, c-format
+msgid "E704: Funcref variable name must start with a capital: %s"
+msgstr "E704: Funcref ±äÁ¿Ãû±ØÐëÒÔ´óд×Öĸ¿ªÍ·: %s"
+
+#, c-format
+msgid "E705: Variable name conflicts with existing function: %s"
+msgstr "E705: ±äÁ¿ÃûÓëÒÑÓк¯ÊýÃû³åÍ»: %s"
+
+#, c-format
+msgid "E706: Variable type mismatch for: %s"
+msgstr "E706: ±äÁ¿ÀàÐͲ»Æ¥Åä: %s"
+
+#, c-format
+msgid "E741: Value is locked: %s"
+msgstr "E741: ÖµÒÑËø¶¨: %s"
+
+msgid "Unknown"
+msgstr "δ֪"
+
+#, c-format
+msgid "E742: Cannot change value of %s"
+msgstr "E742: ÎÞ·¨¸Ä±ä %s µÄÖµ"
+
+msgid "E698: variable nested too deep for making a copy"
+msgstr "E698: ±äÁ¿Ç¶Ì×¹ýÉîÎÞ·¨¸´ÖÆ"
+
+#, c-format
+msgid "E124: Missing '(': %s"
+msgstr "E124: ȱÉÙ '(': %s"
+
+#, c-format
+msgid "E125: Illegal argument: %s"
+msgstr "E125: ÎÞЧµÄ²ÎÊý: %s"
+
+msgid "E126: Missing :endfunction"
+msgstr "E126: ȱÉÙ :endfunction"
+
+#, c-format
+msgid "E746: Function name does not match script file name: %s"
+msgstr "E746: º¯ÊýÃûÓë½Å±¾ÎļþÃû²»Æ¥Åä: %s"
+
+msgid "E129: Function name required"
+msgstr "E129: ÐèÒªº¯ÊýÃû"
+
+#, c-format
+msgid "E128: Function name must start with a capital or contain a colon: %s"
+msgstr "E128: º¯ÊýÃû±ØÐëÒÔ´óд×Öĸ¿ªÍ·»òÕß°üº¬Ã°ºÅ: %s"
+
+#, c-format
+msgid "E131: Cannot delete function %s: It is in use"
+msgstr "E131: ÎÞ·¨É¾³ýº¯Êý %s: ÕýÔÚʹÓÃÖÐ"
+
+msgid "E132: Function call depth is higher than 'maxfuncdepth'"
+msgstr "E132: º¯Êýµ÷ÓÃÉî¶È³¬³ö 'maxfuncdepth'"
+
+#, c-format
+msgid "calling %s"
+msgstr "µ÷ÓÃ %s"
+
+#, c-format
+msgid "%s aborted"
+msgstr "%s ÒÑÖÐÖ¹"
+
+#, c-format
+msgid "%s returning #%ld"
+msgstr "%s ·µ»Ø #%ld "
+
+#, c-format
+msgid "%s returning %s"
+msgstr "%s ·µ»Ø %s"
+
+#, c-format
+msgid "continuing in %s"
+msgstr "ÔÚ %s ÖмÌÐø"
+
+msgid "E133: :return not inside a function"
+msgstr "E133: :return ²»ÔÚº¯ÊýÖÐ"
+
+#, c-format
+msgid ""
+"\n"
+"# global variables:\n"
+msgstr ""
+"\n"
+"# È«¾Ö±äÁ¿:\n"
+
+msgid ""
+"\n"
+"\tLast set from "
+msgstr ""
+"\n"
+"\t×î½üÐÞ¸ÄÓÚ "
+
+#, c-format
+msgid "<%s>%s%s %d, Hex %02x, Octal %03o"
+msgstr "<%s>%s%s %d, Ê®Áù½øÖÆ %02x, °Ë½øÖÆ %03o"
+
+#, c-format
+msgid "> %d, Hex %04x, Octal %o"
+msgstr "> %d, Ê®Áù½øÖÆ %04x, °Ë½øÖÆ %o"
+
+#, c-format
+msgid "> %d, Hex %08x, Octal %o"
+msgstr "> %d, Ê®Áù½øÖÆ %08x, °Ë½øÖÆ %o"
+
+msgid "E134: Move lines into themselves"
+msgstr "E134: °ÑÐÐÒƶ¯µ½×ÔÒÑÖÐ"
+
+msgid "1 line moved"
+msgstr "Òƶ¯ÁË 1 ÐÐ"
+
+#, c-format
+msgid "%ld lines moved"
+msgstr "Òƶ¯ÁË %ld ÐÐ"
+
+#, c-format
+msgid "%ld lines filtered"
+msgstr "¹ýÂËÁË %ld ÐÐ"
+
+msgid "E135: *Filter* Autocommands must not change current buffer"
+msgstr "E135: *Filter* ×Ô¶¯ÃüÁî²»¿ÉÒԸı䵱ǰ»º³åÇø"
+
+msgid "[No write since last change]\n"
+msgstr "[ÒÑÐ޸ĵ«ÉÐδ±£´æ]\n"
+
+# bad to translate
+#, c-format
+msgid "%sviminfo: %s in line: "
+msgstr "%sviminfo: %s λÓÚÐÐ: "
+
+msgid "E136: viminfo: Too many errors, skipping rest of file"
+msgstr "E136: viminfo: ´íÎó¹ý¶à£¬ºöÂÔÎļþµÄÊ£Óಿ·Ö"
+
+#, c-format
+msgid "Reading viminfo file \"%s\"%s%s%s"
+msgstr "¶ÁÈ¡ viminfo Îļþ \"%s\"%s%s%s"
+
+msgid " info"
+msgstr " ÐÅÏ¢"
+
+msgid " marks"
+msgstr " 񈬀"
+
+msgid " FAILED"
+msgstr " ʧ°Ü"
+
+#, c-format
+msgid "E137: Viminfo file is not writable: %s"
+msgstr "E137: Viminfo Îļþ²»¿ÉдÈë: %s"
+
+#, c-format
+msgid "E138: Can't write viminfo file %s!"
+msgstr "E138: ÎÞ·¨Ð´Èë viminfo Îļþ %s£¡"
+
+#, c-format
+msgid "Writing viminfo file \"%s\""
+msgstr "дÈë viminfo Îļþ \"%s\""
+
+# do not translate to avoid writing Chinese in files
+#. Write the info:
+#, fuzzy, c-format
+#~ msgid "# This viminfo file was generated by Vim %s.\n"
+#~ msgstr "# Õâ¸ö viminfo ÎļþÊÇÓÉ Vim %s Éú³ÉµÄ¡£\n"
+
+# do not translate to avoid writing Chinese in files
+#, fuzzy, c-format
+msgid ""
+"# You may edit it if you're careful!\n"
+"\n"
+msgstr ""
+"# Èç¹ûÒª×ÔÐÐÐÞ¸ÄÇëÌرðСÐÄ£¡\n"
+"\n"
+
+# do not translate to avoid writing Chinese in files
+#, fuzzy, c-format
+#~ msgid "# Value of 'encoding' when this file was written\n"
+#~ msgstr "# 'encoding' ÔÚ´ËÎļþ½¨Á¢Ê±µÄÖµ\n"
+
+msgid "Illegal starting char"
+msgstr "ÎÞЧµÄÆô¶¯×Ö·û"
+
+msgid "Save As"
+msgstr "Áí´æΪ"
+
+msgid "Write partial file?"
+msgstr "ҪдÈ벿·ÖÎļþÂð£¿"
+
+msgid "E140: Use ! to write partial buffer"
+msgstr "E140: ÇëʹÓà ! À´Ð´È벿·Ö»º³åÇø"
+
+#, c-format
+msgid "Overwrite existing file \"%s\"?"
+msgstr "¸²¸ÇÒÑ´æÔÚµÄÎļþ \"%s\" Âð£¿"
+
+#, c-format
+msgid "Swap file \"%s\" exists, overwrite anyway?"
+msgstr "½»»»Îļþ \"%s\" ÒÑ´æÔÚ£¬È·ÊµÒª¸²¸ÇÂð£¿"
+
+#, c-format
+msgid "E768: Swap file exists: %s (:silent! overrides)"
+msgstr "E768: ½»»»ÎļþÒÑ´æÔÚ: %s (:silent! Ç¿ÖÆÖ´ÐÐ)"
+
+#, c-format
+msgid "E141: No file name for buffer %ld"
+msgstr "E141: »º³åÇø %ld ûÓÐÎļþÃû"
+
+msgid "E142: File not written: Writing is disabled by 'write' option"
+msgstr "E142: ÎļþδдÈë: дÈë±» 'write' Ñ¡Ïî½ûÓÃ"
+
+#, c-format
+msgid ""
+"'readonly' option is set for \"%s\".\n"
+"Do you wish to write anyway?"
+msgstr ""
+"\"%s\" ÒÑÉ趨 'readonly' Ñ¡Ïî¡£\n"
+"ȷʵҪ¸²¸ÇÂð£¿"
+
+msgid "Edit File"
+msgstr "±à¼­Îļþ"
+
+#, c-format
+msgid "E143: Autocommands unexpectedly deleted new buffer %s"
+msgstr "E143: ×Ô¶¯ÃüÁîÒâÍâµØɾ³ýÁËлº³åÇø %s"
+
+msgid "E144: non-numeric argument to :z"
+msgstr "E144: :z ²»½ÓÊÜ·ÇÊý×ֵIJÎÊý"
+
+msgid "E145: Shell commands not allowed in rvim"
+msgstr "E145: rvim ÖнûֹʹÓà shell ÃüÁî"
+
+msgid "E146: Regular expressions can't be delimited by letters"
+msgstr "E146: ÕýÔò±í´ïʽ²»ÄÜÓÃ×Öĸ×÷·Ö½ç"
+
+#, c-format
+msgid "replace with %s (y/n/a/q/l/^E/^Y)?"
+msgstr "Ì滻Ϊ %s (y/n/a/q/l/^E/^Y)£¿"
+
+msgid "(Interrupted) "
+msgstr "(ÒÑÖжÏ) "
+
+msgid "1 match"
+msgstr "1 ¸öÆ¥Å䣬"
+
+msgid "1 substitution"
+msgstr "1 ´ÎÌæ»»£¬"
+
+#, c-format
+msgid "%ld matches"
+msgstr "%ld ¸öÆ¥Å䣬"
+
+#, c-format
+msgid "%ld substitutions"
+msgstr "%ld ´ÎÌæ»»£¬"
+
+msgid " on 1 line"
+msgstr "¹² 1 ÐÐ"
+
+#, c-format
+msgid " on %ld lines"
+msgstr "¹² %ld ÐÐ"
+
+msgid "E147: Cannot do :global recursive"
+msgstr "E147: :global ²»ÄܵݹéÖ´ÐÐ"
+
+msgid "E148: Regular expression missing from global"
+msgstr "E148: global ȱÉÙÕýÔò±í´ïʽ"
+
+#, c-format
+msgid "Pattern found in every line: %s"
+msgstr "ÿÐж¼Æ¥Åä±í´ïʽ: %s"
+
+# do not translate to avoid writing Chinese in files
+#, fuzzy, c-format
+msgid ""
+"\n"
+"# Last Substitute String:\n"
+"$"
+msgstr ""
+"\n"
+"# ×î½üµÄÌæ»»×Ö·û´®:\n"
+"$"
+
+msgid "E478: Don't panic!"
+msgstr "E478: ²»Òª»Å£¡"
+
+#, c-format
+msgid "E661: Sorry, no '%s' help for %s"
+msgstr "E661: ±§Ç¸£¬Ã»ÓÐ '%s' µÄ %s µÄ˵Ã÷"
+
+#, c-format
+msgid "E149: Sorry, no help for %s"
+msgstr "E149: ±§Ç¸£¬Ã»ÓÐ %s µÄ˵Ã÷"
+
+#, c-format
+msgid "Sorry, help file \"%s\" not found"
+msgstr "±§Ç¸£¬ÕÒ²»µ½°ïÖúÎļþ \"%s\""
+
+#, c-format
+msgid "E150: Not a directory: %s"
+msgstr "E150: ²»ÊÇĿ¼: %s"
+
+#, c-format
+msgid "E152: Cannot open %s for writing"
+msgstr "E152: ÎÞ·¨´ò¿ª²¢Ð´Èë %s"
+
+#, c-format
+msgid "E153: Unable to open %s for reading"
+msgstr "E153: ÎÞ·¨´ò¿ª²¢¶ÁÈ¡ %s"
+
+#, c-format
+msgid "E670: Mix of help file encodings within a language: %s"
+msgstr "E670: ÔÚÒ»ÖÖÓïÑÔÖлìºÏÁ˶àÖÖ°ïÖúÎļþ±àÂë: %s"
+
+#, c-format
+msgid "E154: Duplicate tag \"%s\" in file %s/%s"
+msgstr "E154: Tag \"%s\" ÔÚÎļþ %s/%s ÖÐÖظ´³öÏÖ"
+
+#, c-format
+msgid "E160: Unknown sign command: %s"
+msgstr "E160: δ֪µÄ sign ÃüÁî: %s"
+
+msgid "E156: Missing sign name"
+msgstr "E156: ȱÉÙ sign Ãû³Æ"
+
+msgid "E612: Too many signs defined"
+msgstr "E612: Signs ¶¨Òå¹ý¶à"
+
+#, c-format
+msgid "E239: Invalid sign text: %s"
+msgstr "E239: ÎÞЧµÄ sign ÎÄ×Ö: %s"
+
+#, c-format
+msgid "E155: Unknown sign: %s"
+msgstr "E155: δ֪µÄ sign: %s"
+
+msgid "E159: Missing sign number"
+msgstr "E159: ȱÉÙ sign ºÅ"
+
+#, c-format
+msgid "E158: Invalid buffer name: %s"
+msgstr "E158: ÎÞЧµÄ»º³åÇøÃû: %s"
+
+#, c-format
+msgid "E157: Invalid sign ID: %ld"
+msgstr "E157: ÎÞЧµÄ sign ID: %ld"
+
+msgid " (NOT FOUND)"
+msgstr " (ÕÒ²»µ½)"
+
+msgid " (not supported)"
+msgstr " (²»Ö§³Ö)"
+
+msgid "[Deleted]"
+msgstr "[ÒÑɾ³ý]"
+
+msgid "Entering Debug mode. Type \"cont\" to continue."
+msgstr "½øÈëµ÷ÊÔģʽ¡£ÊäÈë \"cont\" ¼ÌÐøÔËÐС£"
+
+#, c-format
+msgid "line %ld: %s"
+msgstr "µÚ %ld ÐÐ: %s"
+
+#, c-format
+msgid "cmd: %s"
+msgstr "ÃüÁî: %s"
+
+#, c-format
+msgid "Breakpoint in \"%s%s\" line %ld"
+msgstr "¶Ïµã \"%s%s\" µÚ %ld ÐÐ"
+
+#, c-format
+msgid "E161: Breakpoint not found: %s"
+msgstr "E161: ÕÒ²»µ½¶Ïµã: %s"
+
+msgid "No breakpoints defined"
+msgstr "ûÓж¨Òå¶Ïµã"
+
+#, c-format
+msgid "%3d %s %s line %ld"
+msgstr "%3d %s %s µÚ %ld ÐÐ"
+
+msgid "E750: First use :profile start <fname>"
+msgstr "E750: ÇëÏÈʹÓà :profile start <fname>"
+
+#, c-format
+msgid "Save changes to \"%s\"?"
+msgstr "½«¸Ä±ä±£´æµ½ \"%s\" Âð£¿"
+
+msgid "Untitled"
+msgstr "δÃüÃû"
+
+#, c-format
+msgid "E162: No write since last change for buffer \"%s\""
+msgstr "E162: »º³åÇø \"%s\" ÒÑÐ޸ĵ«ÉÐδ±£´æ"
+
+msgid "Warning: Entered other buffer unexpectedly (check autocommands)"
+msgstr "¾¯¸æ: ÒâÍâµØ½øÈëÁËÆäËü»º³åÇø (Çë¼ì²é×Ô¶¯ÃüÁî)"
+
+msgid "E163: There is only one file to edit"
+msgstr "E163: Ö»ÓÐÒ»¸öÎļþ¿É±à¼­"
+
+msgid "E164: Cannot go before first file"
+msgstr "E164: ÎÞ·¨Çл»£¬ÒÑÊǵÚÒ»¸öÎļþ"
+
+msgid "E165: Cannot go beyond last file"
+msgstr "E165: ÎÞ·¨Çл»£¬ÒÑÊÇ×îºóÒ»¸öÎļþ"
+
+#, c-format
+msgid "E666: compiler not supported: %s"
+msgstr "E666: ²»Ö§³Ö±àÒëÆ÷: %s"
+
+#, c-format
+msgid "Searching for \"%s\" in \"%s\""
+msgstr "ÕýÔÚ²éÕÒ \"%s\"£¬ÔÚ \"%s\" ÖÐ"
+
+#, c-format
+msgid "Searching for \"%s\""
+msgstr "ÕýÔÚ²éÕÒ \"%s\""
+
+#, c-format
+msgid "not found in 'runtimepath': \"%s\""
+msgstr "ÔÚ 'runtimepath' ÖÐÕÒ²»µ½ \"%s\""
+
+msgid "Source Vim script"
+msgstr "Ö´ÐÐ Vim ½Å±¾"
+
+#, c-format
+msgid "Cannot source a directory: \"%s\""
+msgstr "²»ÄÜÖ´ÐÐĿ¼: \"%s\""
+
+#, c-format
+msgid "could not source \"%s\""
+msgstr "²»ÄÜÖ´ÐÐ \"%s\""
+
+#, c-format
+msgid "line %ld: could not source \"%s\""
+msgstr "µÚ %ld ÐÐ: ²»ÄÜÖ´ÐÐ \"%s\""
+
+#, c-format
+msgid "sourcing \"%s\""
+msgstr "Ö´ÐÐ \"%s\""
+
+#, c-format
+msgid "line %ld: sourcing \"%s\""
+msgstr "µÚ %ld ÐÐ: Ö´ÐÐ \"%s\""
+
+#, c-format
+msgid "finished sourcing %s"
+msgstr "½áÊøÖ´ÐÐ %s"
+
+msgid "modeline"
+msgstr "modeline"
+
+msgid "--cmd argument"
+msgstr "--cmd ²ÎÊý"
+
+msgid "-c argument"
+msgstr "-c ²ÎÊý"
+
+msgid "environment variable"
+msgstr "»·¾³±äÁ¿"
+
+#~ msgid "error handler"
+#~ msgstr ""
+
+msgid "W15: Warning: Wrong line separator, ^M may be missing"
+msgstr "W15: ¾¯¸æ: ´íÎóµÄÐзָô·û£¬¿ÉÄÜÊÇÉÙÁË ^M"
+
+msgid "E167: :scriptencoding used outside of a sourced file"
+msgstr "E167: Ôڽű¾ÎļþÍâʹÓÃÁË :scriptencoding"
+
+msgid "E168: :finish used outside of a sourced file"
+msgstr "E168: Ôڽű¾ÎļþÍâʹÓÃÁË :finish"
+
+#, c-format
+msgid "Current %slanguage: \"%s\""
+msgstr "µ±Ç°µÄ %sÓïÑÔ: \"%s\""
+
+#, c-format
+msgid "E197: Cannot set language to \"%s\""
+msgstr "E197: ²»ÄÜÉ趨ÓïÑÔΪ \"%s\""
+
+msgid "Entering Ex mode. Type \"visual\" to go to Normal mode."
+msgstr "½øÈë Ex ģʽ¡£ÊäÈë \"visual\" »Øµ½Õý³£Ä£Ê½¡£"
+
+msgid "E501: At end-of-file"
+msgstr "E501: Òѵ½Îļþĩβ"
+
+msgid "E169: Command too recursive"
+msgstr "E169: ÃüÁîµÝ¹é²ãÊý¹ý¶à"
+
+#, c-format
+msgid "E605: Exception not caught: %s"
+msgstr "E605: Ò쳣ûÓб»²¶»ñ: %s"
+
+msgid "End of sourced file"
+msgstr "½Å±¾Îļþ½áÊø"
+
+msgid "End of function"
+msgstr "º¯Êý½áÊø"
+
+msgid "E464: Ambiguous use of user-defined command"
+msgstr "E464: ²»È·¶¨µÄÓû§×Ô¶¨ÒåÃüÁî"
+
+msgid "E492: Not an editor command"
+msgstr "E492: ²»ÊDZ༭Æ÷µÄÃüÁî"
+
+msgid "E493: Backwards range given"
+msgstr "E493: ʹÓÃÁËÄæÏòµÄ·¶Î§"
+
+msgid "Backwards range given, OK to swap"
+msgstr "ʹÓÃÁËÄæÏòµÄ·¶Î§£¬È·¶¨½»»»Âð"
+
+msgid "E494: Use w or w>>"
+msgstr "E494: ÇëʹÓà w »ò w>>"
+
+msgid "E319: Sorry, the command is not available in this version"
+msgstr "E319: ±§Ç¸£¬ÃüÁîÔÚ´Ë°æ±¾Öв»¿ÉÓÃ"
+
+msgid "E172: Only one file name allowed"
+msgstr "E172: Ö»ÔÊÐíÒ»¸öÎļþÃû"
+
+msgid "1 more file to edit. Quit anyway?"
+msgstr "»¹ÓÐ 1 ¸öÎļþδ±à¼­¡£È·ÊµÒªÍ˳öÂð£¿"
+
+#, c-format
+msgid "%d more files to edit. Quit anyway?"
+msgstr "»¹ÓÐ %d ¸öÎļþδ±à¼­¡£È·ÊµÒªÍ˳öÂð£¿"
+
+msgid "E173: 1 more file to edit"
+msgstr "E173: »¹ÓÐ 1 ¸öÎļþδ±à¼­"
+
+#, c-format
+msgid "E173: %ld more files to edit"
+msgstr "E173: »¹ÓÐ %ld ¸öÎļþδ±à¼­"
+
+msgid "E174: Command already exists: add ! to replace it"
+msgstr "E174: ÃüÁîÒÑ´æÔÚ: Çë¼Ó ! Ç¿ÖÆÌæ»»"
+
+msgid ""
+"\n"
+" Name Args Range Complete Definition"
+msgstr ""
+"\n"
+" Ãû³Æ ²ÎÊý ·¶Î§ ²¹È« ¶¨Òå "
+
+msgid "No user-defined commands found"
+msgstr "ÕÒ²»µ½Óû§×Ô¶¨ÒåÃüÁî"
+
+msgid "E175: No attribute specified"
+msgstr "E175: ûÓÐÖ¸¶¨ÊôÐÔ"
+
+msgid "E176: Invalid number of arguments"
+msgstr "E176: ÎÞЧµÄ²ÎÊý¸öÊý"
+
+msgid "E177: Count cannot be specified twice"
+msgstr "E177: ²»ÄÜÖ¸¶¨Á½´Î¼ÆÊý"
+
+msgid "E178: Invalid default value for count"
+msgstr "E178: ÎÞЧµÄ¼ÆÊýĬÈÏÖµ"
+
+msgid "E179: argument required for -complete"
+msgstr "E179: -complete ÐèÒª²ÎÊý"
+
+#, c-format
+msgid "E181: Invalid attribute: %s"
+msgstr "E181: ÎÞЧµÄÊôÐÔ: %s"
+
+msgid "E182: Invalid command name"
+msgstr "E182: ÎÞЧµÄÃüÁîÃû"
+
+msgid "E183: User defined commands must start with an uppercase letter"
+msgstr "E183: Óû§×Ô¶¨ÒåÃüÁî±ØÐëÒÔ´óд×Öĸ¿ªÍ·"
+
+#, c-format
+msgid "E184: No such user-defined command: %s"
+msgstr "E184: ûÓÐÕâ¸öÓû§×Ô¶¨ÒåÃüÁî: %s"
+
+#, c-format
+msgid "E180: Invalid complete value: %s"
+msgstr "E180: ÎÞЧµÄ²¹È«ÀàÐÍ: %s"
+
+msgid "E468: Completion argument only allowed for custom completion"
+msgstr "E468: Ö»ÓÐ custom ²¹È«²ÅÔÊÐí²ÎÊý"
+
+msgid "E467: Custom completion requires a function argument"
+msgstr "E467: Custom ²¹È«ÐèÒªÒ»¸öº¯Êý²ÎÊý"
+
+#, c-format
+msgid "E185: Cannot find color scheme %s"
+msgstr "E185: ÕÒ²»µ½ÅäÉ«·½°¸ %s"
+
+msgid "Greetings, Vim user!"
+msgstr "ÄúºÃ£¬Vim Óû§£¡"
+
+msgid "E784: Cannot close last tab page"
+msgstr "E784: ²»ÄܹرÕ×îºóÒ»¸ö tab Ò³"
+
+msgid "Already only one tab page"
+msgstr "ÒѾ­Ö»Ê£Ò»¸ö tab Ò³ÁË"
+
+msgid "Edit File in new window"
+msgstr "ÔÚд°¿Ú±à¼­Îļþ"
+
+#, c-format
+msgid "Tab page %d"
+msgstr "Tab Ò³ %d"
+
+msgid "No swap file"
+msgstr "ÎÞ½»»»Îļþ"
+
+msgid "Append File"
+msgstr "×·¼ÓÎļþ"
+
+msgid "E747: Cannot change directory, buffer is modified (add ! to override)"
+msgstr "E747: ²»ÄܸıäĿ¼£¬»º³åÇøÒÑÐÞ¸Ä (Çë¼Ó ! Ç¿ÖÆÖ´ÐÐ)"
+
+msgid "E186: No previous directory"
+msgstr "E186: Ç°Ò»¸öĿ¼²»´æÔÚ"
+
+msgid "E187: Unknown"
+msgstr "E187: δ֪"
+
+msgid "E465: :winsize requires two number arguments"
+msgstr "E465: :winsize ÐèÒªÁ½¸öÊý×Ö²ÎÊý"
+
+#, c-format
+msgid "Window position: X %d, Y %d"
+msgstr "´°¿ÚλÖÃ: X %d, Y %d"
+
+msgid "E188: Obtaining window position not implemented for this platform"
+msgstr "E188: ÔÚ´Ëƽ̨Éϲ»ÄÜ»ñµÃ´°¿ÚλÖÃ"
+
+msgid "E466: :winpos requires two number arguments"
+msgstr "E466: :winpos ÐèÒªÁ½¸öÊý×Ö²ÎÊý"
+
+msgid "Save Redirection"
+msgstr "±£´æÖض¨Ïò"
+
+msgid "Save View"
+msgstr "±£´æÊÓͼ"
+
+msgid "Save Session"
+msgstr "±£´æ»á»°"
+
+msgid "Save Setup"
+msgstr "±£´æÉ趨"
+
+#, c-format
+msgid "E739: Cannot create directory: %s"
+msgstr "E739: ÎÞ·¨´´½¨Ä¿Â¼: %s"
+
+#, c-format
+msgid "E189: \"%s\" exists (add ! to override)"
+msgstr "E189: \"%s\" ÒÑ´æÔÚ (Çë¼Ó ! Ç¿ÖÆÖ´ÐÐ)"
+
+#, c-format
+msgid "E190: Cannot open \"%s\" for writing"
+msgstr "E190: ÎÞ·¨´ò¿ª²¢Ð´Èë \"%s\""
+
+#. set mark
+msgid "E191: Argument must be a letter or forward/backward quote"
+msgstr "E191: ²ÎÊý±ØÐëÊÇÒ»¸ö×Öĸ»òÕßÕý/·´ÒýºÅ"
+
+msgid "E192: Recursive use of :normal too deep"
+msgstr "E192: :normal µÝ¹é²ãÊý¹ýÉî"
+
+msgid "E194: No alternate file name to substitute for '#'"
+msgstr "E194: ûÓÐÓÃÓÚÌæ»» '#' µÄ½»ÌæÎļþÃû"
+
+msgid "E495: no autocommand file name to substitute for \"<afile>\""
+msgstr "E495: ûÓÐÓÃÓÚÌæ»» \"<afile>\" µÄ×Ô¶¯ÃüÁîÎļþÃû"
+
+msgid "E496: no autocommand buffer number to substitute for \"<abuf>\""
+msgstr "E496: ûÓÐÓÃÓÚÌæ»» \"<abuf>\" µÄ×Ô¶¯ÃüÁ³åÇøºÅ"
+
+msgid "E497: no autocommand match name to substitute for \"<amatch>\""
+msgstr "E497: ûÓÐÓÃÓÚÌæ»» \"<amatch>\" µÄ×Ô¶¯ÃüÁîÆ¥ÅäÃû"
+
+msgid "E498: no :source file name to substitute for \"<sfile>\""
+msgstr "E498: ûÓÐÓÃÓÚÌæ»» \"<sfile>\" µÄ :source ÎļþÃû"
+
+#, no-c-format
+msgid "E499: Empty file name for '%' or '#', only works with \":p:h\""
+msgstr "E499: '%' »ò '#' Ϊ¿ÕÎļþÃû£¬Ö»ÄÜÓÃÓÚ \":p:h\""
+
+msgid "E500: Evaluates to an empty string"
+msgstr "E500: ½á¹ûΪ¿Õ×Ö·û´®"
+
+msgid "E195: Cannot open viminfo file for reading"
+msgstr "E195: ÎÞ·¨´ò¿ª²¢¶ÁÈ¡ viminfo Îļþ"
+
+msgid "E196: No digraphs in this version"
+msgstr "E196: ´Ë°æ±¾ÎÞ¸´ºÏ×Ö·û(digraph)"
+
+msgid "E608: Cannot :throw exceptions with 'Vim' prefix"
+msgstr "E608: ²»ÄÜ :throw ǰ׺Ϊ 'Vim' µÄÒì³£"
+
+#. always scroll up, don't overwrite
+#, c-format
+msgid "Exception thrown: %s"
+msgstr "Å׳öÒì³£: %s"
+
+#, c-format
+msgid "Exception finished: %s"
+msgstr "Íê³ÉÒì³£: %s"
+
+#, c-format
+msgid "Exception discarded: %s"
+msgstr "¶ªÆúÒì³£: %s"
+
+#, c-format
+msgid "%s, line %ld"
+msgstr "%s£¬µÚ %ld ÐÐ"
+
+#. always scroll up, don't overwrite
+#, c-format
+msgid "Exception caught: %s"
+msgstr "²¶»ñÒì³£: %s"
+
+#, c-format
+#~ msgid "%s made pending"
+#~ msgstr ""
+
+#, fuzzy, c-format
+#~ msgid "%s resumed"
+#~ msgstr " ÒÑ·µ»Ø\n"
+
+#, c-format
+#~ msgid "%s discarded"
+#~ msgstr ""
+
+msgid "Exception"
+msgstr "Òì³£"
+
+msgid "Error and interrupt"
+msgstr "´íÎóºÍÖжÏ"
+
+msgid "Error"
+msgstr "´íÎó"
+
+#. if (pending & CSTP_INTERRUPT)
+msgid "Interrupt"
+msgstr "ÖжÏ"
+
+msgid "E579: :if nesting too deep"
+msgstr "E579: :if ǶÌײãÊý¹ýÉî"
+
+msgid "E580: :endif without :if"
+msgstr "E580: :endif ȱÉÙ¶ÔÓ¦µÄ :if"
+
+msgid "E581: :else without :if"
+msgstr "E581: :else ȱÉÙ¶ÔÓ¦µÄ :if"
+
+msgid "E582: :elseif without :if"
+msgstr "E582: :elseif ȱÉÙ¶ÔÓ¦µÄ :if"
+
+msgid "E583: multiple :else"
+msgstr "E583: ¶à¸ö :else"
+
+msgid "E584: :elseif after :else"
+msgstr "E584: :elseif ÔÚ :else ºóÃæ"
+
+msgid "E585: :while/:for nesting too deep"
+msgstr "E585: :while/:for ǶÌײãÊý¹ýÉî"
+
+msgid "E586: :continue without :while or :for"
+msgstr "E586: :continue ȱÉÙ¶ÔÓ¦µÄ :while »ò :for"
+
+msgid "E587: :break without :while or :for"
+msgstr "E587: :break ȱÉÙ¶ÔÓ¦µÄ :while »ò :for"
+
+msgid "E732: Using :endfor with :while"
+msgstr "E732: :while ÒÔ :endfor ½áβ"
+
+msgid "E733: Using :endwhile with :for"
+msgstr "E733: :for ÒÔ :endwhile ½áβ"
+
+msgid "E601: :try nesting too deep"
+msgstr "E601: :try ǶÌײãÊý¹ýÉî"
+
+msgid "E603: :catch without :try"
+msgstr "E603: :catch ȱÉÙ¶ÔÓ¦µÄ :try"
+
+#. Give up for a ":catch" after ":finally" and ignore it.
+#. * Just parse.
+msgid "E604: :catch after :finally"
+msgstr "E604: :catch ÔÚ :finally ºóÃæ"
+
+msgid "E606: :finally without :try"
+msgstr "E606: :finally ȱÉÙ¶ÔÓ¦µÄ :try"
+
+#. Give up for a multiple ":finally" and ignore it.
+msgid "E607: multiple :finally"
+msgstr "E607: ¶à¸ö :finally"
+
+msgid "E602: :endtry without :try"
+msgstr "E602: :endtry ȱÉÙ¶ÔÓ¦µÄ :try"
+
+msgid "E193: :endfunction not inside a function"
+msgstr "E193: :endfunction ²»ÔÚº¯ÊýÄÚ"
+
+msgid "E788: Not allowed to edit another buffer now"
+msgstr "E788: Ä¿Ç°²»ÔÊÐí±à¼­±ðµÄ»º³åÇø"
+
+msgid "tagname"
+msgstr "tag Ãû"
+
+msgid " kind file\n"
+msgstr " ÀàÐÍ Îļþ\n"
+
+msgid "'history' option is zero"
+msgstr "Ñ¡Ïî 'history' ΪÁã"
+
+# do not translate to avoid writing Chinese in files
+#, fuzzy, c-format
+msgid ""
+"\n"
+"# %s History (newest to oldest):\n"
+msgstr ""
+"\n"
+"# %s ÀúÊ·¼Ç¼ (´Óе½¾É):\n"
+
+# do not translate to avoid writing Chinese in files
+#, fuzzy
+#~ msgid "Command Line"
+#~ msgstr "ÃüÁîÐÐ"
+
+# do not translate to avoid writing Chinese in files
+#, fuzzy
+#~ msgid "Search String"
+#~ msgstr "²éÕÒ×Ö·û´®"
+
+# do not translate to avoid writing Chinese in files
+#, fuzzy
+#~ msgid "Expression"
+#~ msgstr "±í´ïʽ"
+
+# do not translate to avoid writing Chinese in files
+#, fuzzy
+#~ msgid "Input Line"
+#~ msgstr "ÊäÈëÐÐ"
+
+msgid "E198: cmd_pchar beyond the command length"
+msgstr "E198: cmd_pchar ³¬¹ýÃüÁ¶È"
+
+msgid "E199: Active window or buffer deleted"
+msgstr "E199: »î¶¯´°¿Ú»ò»º³åÇøÒѱ»É¾³ý"
+
+msgid "Illegal file name"
+msgstr "ÎÞЧµÄÎļþÃû"
+
+msgid "is a directory"
+msgstr "ÊÇĿ¼"
+
+msgid "is not a file"
+msgstr "²»ÊÇÎļþ"
+
+msgid "[New File]"
+msgstr "[ÐÂÎļþ]"
+
+msgid "[New DIRECTORY]"
+msgstr "[ÐÂĿ¼]"
+
+msgid "[File too big]"
+msgstr "[Îļþ¹ý´ó]"
+
+msgid "[Permission Denied]"
+msgstr "[ȨÏÞ²»×ã]"
+
+msgid "E200: *ReadPre autocommands made the file unreadable"
+msgstr "E200: *ReadPre ×Ô¶¯ÃüÁîµ¼ÖÂÎļþ²»¿É¶Á"
+
+msgid "E201: *ReadPre autocommands must not change current buffer"
+msgstr "E201: *ReadPre ×Ô¶¯ÃüÁî²»ÔÊÐí¸Ä±äµ±Ç°»º³åÇø"
+
+msgid "Vim: Reading from stdin...\n"
+msgstr "Vim: ´Ó±ê×¼ÊäÈë¶ÁÈ¡...\n"
+
+msgid "Reading from stdin..."
+msgstr "´Ó±ê×¼ÊäÈë¶ÁÈ¡..."
+
+#. Re-opening the original file failed!
+msgid "E202: Conversion made file unreadable!"
+msgstr "E202: ת»»µ¼ÖÂÎļþ²»¿É¶Á"
+
+msgid "[fifo/socket]"
+msgstr "[fifo/socket]"
+
+msgid "[fifo]"
+msgstr "[fifo]"
+
+msgid "[socket]"
+msgstr "[socket]"
+
+msgid "[RO]"
+msgstr "[Ö»¶Á]"
+
+msgid "[CR missing]"
+msgstr "[ȱÉÙ CR]'"
+
+msgid "[NL found]"
+msgstr "[ÕÒµ½ NL]"
+
+msgid "[long lines split]"
+msgstr "[³¤Ðзָî]"
+
+msgid "[NOT converted]"
+msgstr "[δת»»]"
+
+msgid "[converted]"
+msgstr "[ÒÑת»»]"
+
+msgid "[crypted]"
+msgstr "[ÒѼÓÃÜ]"
+
+#, c-format
+msgid "[CONVERSION ERROR in line %ld]"
+msgstr "[µÚ %ld ÐÐת»»´íÎó]"
+
+#, c-format
+msgid "[ILLEGAL BYTE in line %ld]"
+msgstr "[µÚ %ld ÐÐÎÞЧ×Ö·û]"
+
+msgid "[READ ERRORS]"
+msgstr "[¶Á´íÎó]"
+
+msgid "Can't find temp file for conversion"
+msgstr "ÕÒ²»µ½ÓÃÓÚת»»µÄÁÙʱÎļþ"
+
+msgid "Conversion with 'charconvert' failed"
+msgstr "'charconvert' ת»»Ê§°Ü"
+
+msgid "can't read output of 'charconvert'"
+msgstr "ÎÞ·¨¶ÁÈ¡ 'charconvert' µÄÊä³ö"
+
+msgid "E676: No matching autocommands for acwrite buffer"
+msgstr "E676: ÕÒ²»µ½ acwrite »º³åÇø¶ÔÓ¦µÄ×Ô¶¯ÃüÁî"
+
+msgid "E203: Autocommands deleted or unloaded buffer to be written"
+msgstr "E203: ×Ô¶¯ÃüÁîɾ³ý»òÊÍ·ÅÁËҪдÈëµÄ»º³åÇø"
+
+msgid "E204: Autocommand changed number of lines in unexpected way"
+msgstr "E204: ×Ô¶¯ÃüÁîÒâÍâµØ¸Ä±äÁËÐÐÊý"
+
+msgid "NetBeans disallows writes of unmodified buffers"
+msgstr "NetBeans ²»ÔÊÐíδÐ޸ĵĻº³åÇøдÈë"
+
+msgid "Partial writes disallowed for NetBeans buffers"
+msgstr "NetBeans ²»ÔÊÐí»º³åÇø²¿·ÖдÈë"
+
+msgid "is not a file or writable device"
+msgstr "²»ÊÇÎļþ»ò¿ÉдµÄÉ豸"
+
+msgid "is read-only (add ! to override)"
+msgstr "Ö»¶Á (Çë¼Ó ! Ç¿ÖÆÖ´ÐÐ)"
+
+msgid "E506: Can't write to backup file (add ! to override)"
+msgstr "E506: ÎÞ·¨Ð´È뱸·ÝÎļþ (Çë¼Ó ! Ç¿ÖÆÖ´ÐÐ)"
+
+msgid "E507: Close error for backup file (add ! to override)"
+msgstr "E507: ¹Ø±Õ±¸·ÝÎļþ³ö´í (Çë¼Ó ! Ç¿ÖÆÖ´ÐÐ)"
+
+msgid "E508: Can't read file for backup (add ! to override)"
+msgstr "E508: ÎÞ·¨¶ÁÈ¡ÎļþÒÔ¹©±¸·Ý (Çë¼Ó ! Ç¿ÖÆÖ´ÐÐ)"
+
+msgid "E509: Cannot create backup file (add ! to override)"
+msgstr "E509: ÎÞ·¨´´½¨±¸·ÝÎļþ (Çë¼Ó ! Ç¿ÖÆÖ´ÐÐ)"
+
+msgid "E510: Can't make backup file (add ! to override)"
+msgstr "E510: ÎÞ·¨Éú³É±¸·ÝÎļþ (Çë¼Ó ! Ç¿ÖÆÖ´ÐÐ)"
+
+msgid "E460: The resource fork would be lost (add ! to override)"
+msgstr "E460: Resource fork »á¶ªÊ§ (Çë¼Ó ! Ç¿ÖÆÖ´ÐÐ)"
+
+msgid "E214: Can't find temp file for writing"
+msgstr "E214: ÕÒ²»µ½ÓÃÓÚдÈëµÄÁÙʱÎļþ"
+
+msgid "E213: Cannot convert (add ! to write without conversion)"
+msgstr "E213: ÎÞ·¨×ª»» (Çë¼Ó ! Ç¿ÖƲ»×ª»»Ð´Èë)"
+
+msgid "E166: Can't open linked file for writing"
+msgstr "E166: ÎÞ·¨´ò¿ª²¢Ð´ÈëÁ´½ÓÎļþ"
+
+msgid "E212: Can't open file for writing"
+msgstr "E212: ÎÞ·¨´ò¿ª²¢Ð´ÈëÎļþ"
+
+msgid "E667: Fsync failed"
+msgstr "E667: ͬ²½Ê§°Ü"
+
+msgid "E512: Close failed"
+msgstr "E512: ¹Ø±Õʧ°Ü"
+
+msgid "E513: write error, conversion failed (make 'fenc' empty to override)"
+msgstr "E513: дÈë´íÎó£¬×ª»»Ê§°Ü (Ç뽫 'fenc' ÖÿÕÒÔÇ¿ÖÆÖ´ÐÐ)"
+
+msgid "E514: write error (file system full?)"
+msgstr "E514: дÈë´íÎó (ÎļþϵͳÒÑÂú£¿)"
+
+msgid " CONVERSION ERROR"
+msgstr " ת»»´íÎó"
+
+msgid "[Device]"
+msgstr "[É豸]"
+
+msgid "[New]"
+msgstr "[ÐÂ]"
+
+msgid " [a]"
+msgstr " [a]"
+
+msgid " appended"
+msgstr " ÒÑ×·¼Ó"
+
+msgid " [w]"
+msgstr " [w]"
+
+msgid " written"
+msgstr " ÒÑдÈë"
+
+msgid "E205: Patchmode: can't save original file"
+msgstr "E205: Patchmode: ÎÞ·¨±£´æԭʼÎļþ"
+
+msgid "E206: patchmode: can't touch empty original file"
+msgstr "E206: Patchmode: ÎÞ·¨Éú³É¿ÕµÄԭʼÎļþ"
+
+msgid "E207: Can't delete backup file"
+msgstr "E207: ÎÞ·¨É¾³ý±¸·ÝÎļþ"
+
+msgid ""
+"\n"
+"WARNING: Original file may be lost or damaged\n"
+msgstr ""
+"\n"
+"¾¯¸æ: ԭʼÎļþ¿ÉÄÜÒѶªÊ§»òËð»µ\n"
+
+msgid "don't quit the editor until the file is successfully written!"
+msgstr "ÔÚÎļþÕýȷдÈëÇ°ÇëÎðÍ˳ö±à¼­Æ÷£¡"
+
+msgid "[dos]"
+msgstr "[dos]"
+
+msgid "[dos format]"
+msgstr "[dos ¸ñʽ]"
+
+msgid "[mac]"
+msgstr "[mac]"
+
+msgid "[mac format]"
+msgstr "[mac ¸ñʽ]"
+
+msgid "[unix]"
+msgstr "[unix]"
+
+msgid "[unix format]"
+msgstr "[unix ¸ñʽ]"
+
+msgid "1 line, "
+msgstr "1 ÐУ¬"
+
+#, c-format
+msgid "%ld lines, "
+msgstr "%ld ÐУ¬"
+
+msgid "1 character"
+msgstr "1 ¸ö×Ö·û"
+
+#, c-format
+msgid "%ld characters"
+msgstr "%ld ¸ö×Ö·û"
+
+msgid "[noeol]"
+msgstr "[noeol]"
+
+msgid "[Incomplete last line]"
+msgstr "[×îºóÒ»Ðв»ÍêÕû]"
+
+#. don't overwrite messages here
+#. must give this prompt
+#. don't use emsg() here, don't want to flush the buffers
+msgid "WARNING: The file has been changed since reading it!!!"
+msgstr "¾¯¸æ: ´ËÎļþ×Ô¶ÁÈëºóÒÑ·¢Éú±ä¶¯£¡£¡£¡"
+
+msgid "Do you really want to write to it"
+msgstr "ȷʵҪдÈëÂð"
+
+#, c-format
+msgid "E208: Error writing to \"%s\""
+msgstr "E208: дÈëÎļþ \"%s\" ³ö´í"
+
+#, c-format
+msgid "E209: Error closing \"%s\""
+msgstr "E209: ¹Ø±ÕÎļþ \"%s\" ³ö´í"
+
+#, c-format
+msgid "E210: Error reading \"%s\""
+msgstr "E210: ¶ÁÈ¡Îļþ \"%s\" ³ö´í"
+
+msgid "E246: FileChangedShell autocommand deleted buffer"
+msgstr "E246: FileChangedShell ×Ô¶¯ÃüÁîɾ³ýÁË»º³åÇø"
+
+#, c-format
+msgid "E211: File \"%s\" no longer available"
+msgstr "E211: Îļþ \"%s\" ÒѾ­²»´æÔÚ"
+
+#, c-format
+msgid ""
+"W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as "
+"well"
+msgstr "W12: ¾¯¸æ: Îļþ \"%s\" Òѱ䶯£¬²¢ÇÒÔÚ Vim ÖеĻº³åÇøÒ²Òѱ䶯"
+
+msgid "See \":help W12\" for more info."
+msgstr "½øÒ»²½ËµÃ÷Çë¼û \":help W12\""
+
+#, c-format
+msgid "W11: Warning: File \"%s\" has changed since editing started"
+msgstr "W11: ¾¯¸æ: ±à¼­¿ªÊ¼ºó£¬Îļþ \"%s\" Òѱ䶯"
+
+msgid "See \":help W11\" for more info."
+msgstr "½øÒ»²½ËµÃ÷Çë¼û \":help W11\""
+
+#, c-format
+msgid "W16: Warning: Mode of file \"%s\" has changed since editing started"
+msgstr "W16: ¾¯¸æ: ±à¼­¿ªÊ¼ºó£¬Îļþ \"%s\" µÄģʽÒѱ䶯"
+
+msgid "See \":help W16\" for more info."
+msgstr "½øÒ»²½ËµÃ÷Çë¼û \":help W16\""
+
+#, c-format
+msgid "W13: Warning: File \"%s\" has been created after editing started"
+msgstr "W13: ¾¯¸æ: ±à¼­¿ªÊ¼ºó£¬Îļþ \"%s\" Òѱ»´´½¨"
+
+msgid "Warning"
+msgstr "¾¯¸æ"
+
+msgid ""
+"&OK\n"
+"&Load File"
+msgstr ""
+"È·¶¨(&O)\n"
+"¼ÓÔØÎļþ(&L)"
+
+#, c-format
+msgid "E462: Could not prepare for reloading \"%s\""
+msgstr "E462: ÎÞ·¨ÎªÖØмÓÔØ \"%s\" ×ö×¼±¸"
+
+#, c-format
+msgid "E321: Could not reload \"%s\""
+msgstr "E321: ÎÞ·¨ÖØмÓÔØ \"%s\""
+
+msgid "--Deleted--"
+msgstr "--ÒÑɾ³ý--"
+
+#, c-format
+#~ msgid "auto-removing autocommand: %s <buffer=%d>"
+#~ msgstr ""
+
+#. the group doesn't exist
+#, c-format
+msgid "E367: No such group: \"%s\""
+msgstr "E367: ÎÞ´Ë×é: \"%s\""
+
+#, c-format
+msgid "E215: Illegal character after *: %s"
+msgstr "E215: * ºóÃæÓÐÎÞЧ×Ö·û: %s"
+
+#, c-format
+msgid "E216: No such event: %s"
+msgstr "E216: ÎÞ´Ëʼþ: %s"
+
+#, c-format
+msgid "E216: No such group or event: %s"
+msgstr "E216: ÎÞ´Ë×é»òʼþ: %s"
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Autocommands ---"
+msgstr ""
+"\n"
+"--- ×Ô¶¯ÃüÁî ---"
+
+#, c-format
+msgid "E680: <buffer=%d>: invalid buffer number "
+msgstr "E680: <buffer=%d>: ÎÞЧµÄ»º³åÇøºÅ "
+
+msgid "E217: Can't execute autocommands for ALL events"
+msgstr "E217: ²»ÄܶÔËùÓÐʼþÖ´ÐÐ×Ô¶¯ÃüÁî"
+
+msgid "No matching autocommands"
+msgstr "ûÓÐÆ¥ÅäµÄ×Ô¶¯ÃüÁî"
+
+msgid "E218: autocommand nesting too deep"
+msgstr "E218: ×Ô¶¯ÃüÁîǶÌײãÊý¹ýÉî"
+
+#, c-format
+msgid "%s Autocommands for \"%s\""
+msgstr "%s ×Ô¶¯ÃüÁî \"%s\""
+
+#, c-format
+msgid "Executing %s"
+msgstr "Ö´ÐÐ %s"
+
+#, c-format
+msgid "autocommand %s"
+msgstr "×Ô¶¯ÃüÁî %s"
+
+msgid "E219: Missing {."
+msgstr "E219: ȱÉÙ {¡£"
+
+msgid "E220: Missing }."
+msgstr "E220: ȱÉÙ }¡£"
+
+msgid "E490: No fold found"
+msgstr "E490: ÕÒ²»µ½ÕÛµþ"
+
+msgid "E350: Cannot create fold with current 'foldmethod'"
+msgstr "E350: ²»ÄÜÔÚµ±Ç°µÄ 'foldmethod' Ï´´½¨ÕÛµþ"
+
+msgid "E351: Cannot delete fold with current 'foldmethod'"
+msgstr "E351: ²»ÄÜÔÚµ±Ç°µÄ 'foldmethod' ÏÂɾ³ýÕÛµþ"
+
+#, c-format
+msgid "+--%3ld lines folded "
+msgstr "+--ÒÑÕÛµþ %3ld ÐÐ"
+
+msgid "E222: Add to read buffer"
+msgstr "E222: Ìí¼Óµ½ÒѶÁ»º³åÇøÖÐ"
+
+msgid "E223: recursive mapping"
+msgstr "E223: µÝ¹éÓ³Éä"
+
+#, c-format
+msgid "E224: global abbreviation already exists for %s"
+msgstr "E224: È«¾ÖËõд %s ÒÑ´æÔÚ"
+
+#, c-format
+msgid "E225: global mapping already exists for %s"
+msgstr "E225: È«¾ÖÓ³Éä %s ÒÑ´æÔÚ"
+
+#, c-format
+msgid "E226: abbreviation already exists for %s"
+msgstr "E226: Ëõд %s ÒÑ´æÔÚ"
+
+#, c-format
+msgid "E227: mapping already exists for %s"
+msgstr "E227: Ó³Éä %s ÒÑ´æÔÚ"
+
+msgid "No abbreviation found"
+msgstr "ÕÒ²»µ½Ëõд"
+
+msgid "No mapping found"
+msgstr "ÕÒ²»µ½Ó³Éä"
+
+msgid "E228: makemap: Illegal mode"
+msgstr "E228: makemap: ÎÞЧµÄģʽ"
+
+msgid "E229: Cannot start the GUI"
+msgstr "E229: ÎÞ·¨Æô¶¯Í¼ÐνçÃæ"
+
+#, c-format
+msgid "E230: Cannot read from \"%s\""
+msgstr "E230: ÎÞ·¨¶ÁÈ¡Îļþ \"%s\""
+
+msgid "E665: Cannot start GUI, no valid font found"
+msgstr "E665: ÎÞ·¨Æô¶¯Í¼ÐνçÃ棬ÕÒ²»µ½ÓÐЧµÄ×ÖÌå"
+
+msgid "E231: 'guifontwide' invalid"
+msgstr "E231: ÎÞЧµÄ 'guifontwide'"
+
+msgid "E599: Value of 'imactivatekey' is invalid"
+msgstr "E599: 'imactivatekey' µÄÖµÎÞЧ"
+
+#, c-format
+msgid "E254: Cannot allocate color %s"
+msgstr "E254: ÎÞ·¨·ÖÅäÑÕÉ« %s"
+
+msgid "No match at cursor, finding next"
+msgstr "ÔÚ¹â±ê´¦Ã»ÓÐÆ¥Å䣬²éÕÒÏÂÒ»¸ö"
+
+msgid "<cannot open> "
+msgstr "<ÎÞ·¨´ò¿ª>"
+
+#, c-format
+msgid "E616: vim_SelFile: can't get font %s"
+msgstr "E616: vim_SelFile: ÎÞ·¨»ñÈ¡×ÖÌå %s"
+
+msgid "E614: vim_SelFile: can't return to current directory"
+msgstr "E614: vim_SelFile: ÎÞ·¨·µ»Øµ±Ç°Ä¿Â¼"
+
+msgid "Pathname:"
+msgstr "·¾¶:"
+
+msgid "E615: vim_SelFile: can't get current directory"
+msgstr "E615: vim_SelFile: ÎÞ·¨»ñÈ¡µ±Ç°Ä¿Â¼"
+
+msgid "OK"
+msgstr "È·¶¨"
+
+msgid "Cancel"
+msgstr "È¡Ïû"
+
+msgid "Scrollbar Widget: Could not get geometry of thumb pixmap."
+msgstr "¹ö¶¯Ìõ²¿¼þ: ÎÞ·¨»ñÈ¡»¬¿éͼÏñµÄ¼¸ºÎ´óС"
+
+msgid "Vim dialog"
+msgstr "Vim ¶Ô»°¿ò"
+
+msgid "E232: Cannot create BalloonEval with both message and callback"
+msgstr "E232: ²»ÄÜͬʱʹÓÃÏûÏ¢ºÍ»Øµ÷º¯ÊýÀ´´´½¨ BalloonEval"
+
+msgid "Vim dialog..."
+msgstr "Vim ¶Ô»°¿ò..."
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"&Cancel"
+msgstr ""
+"ÊÇ(&Y)\n"
+"·ñ(&N)\n"
+"È¡Ïû(&C)"
+
+msgid "Input _Methods"
+msgstr "ÊäÈë·¨(_M)"
+
+msgid "VIM - Search and Replace..."
+msgstr "VIM - ²éÕÒºÍÌæ»»..."
+
+msgid "VIM - Search..."
+msgstr "VIM - ²éÕÒ..."
+
+msgid "Find what:"
+msgstr "²éÕÒÄÚÈÝ:"
+
+msgid "Replace with:"
+msgstr "Ì滻Ϊ:"
+
+#. whole word only button
+msgid "Match whole word only"
+msgstr "Æ¥ÅäÍêÕûµÄ´Ê"
+
+#. match case button
+msgid "Match case"
+msgstr "Æ¥Åä´óСд"
+
+msgid "Direction"
+msgstr "·½Ïò"
+
+#. 'Up' and 'Down' buttons
+msgid "Up"
+msgstr "ÏòÉÏ"
+
+msgid "Down"
+msgstr "ÏòÏÂ"
+
+msgid "Find Next"
+msgstr "²éÕÒÏÂÒ»¸ö"
+
+msgid "Replace"
+msgstr "Ìæ»»"
+
+msgid "Replace All"
+msgstr "È«²¿Ìæ»»"
+
+msgid "Vim: Received \"die\" request from session manager\n"
+msgstr "Vim: ´Ó»á»°¹ÜÀíÆ÷ÊÕµ½ \"die\" ÇëÇó\n"
+
+msgid "Close"
+msgstr "¹Ø±Õ"
+
+msgid "New tab"
+msgstr "н¨±êÇ©"
+
+msgid "Open Tab..."
+msgstr "´ò¿ª±êÇ©..."
+
+msgid "Vim: Main window unexpectedly destroyed\n"
+msgstr "Vim: Ö÷´°¿Ú±»ÒâÍâµØ´Ý»Ù\n"
+
+msgid "Font Selection"
+msgstr "Ñ¡Ôñ×ÖÌå"
+
+msgid "Used CUT_BUFFER0 instead of empty selection"
+msgstr "ʹÓà CUT_BUFFER0 À´È¡´ú¿ÕÑ¡Ôñ"
+
+msgid "&Filter"
+msgstr "¹ýÂË(&F)"
+
+msgid "&Cancel"
+msgstr "È¡Ïû(&C)"
+
+msgid "Directories"
+msgstr "Ŀ¼"
+
+msgid "Filter"
+msgstr "¹ýÂËÆ÷"
+
+msgid "&Help"
+msgstr "°ïÖú(&H)"
+
+msgid "Files"
+msgstr "Îļþ"
+
+msgid "&OK"
+msgstr "È·¶¨(&O)"
+
+msgid "Selection"
+msgstr "Ñ¡Ôñ"
+
+msgid "Find &Next"
+msgstr "²éÕÒÏÂÒ»¸ö(&N)"
+
+msgid "&Replace"
+msgstr "Ìæ»»(&R)"
+
+msgid "Replace &All"
+msgstr "È«²¿Ìæ»»(&A)"
+
+msgid "&Undo"
+msgstr "³·Ïú(&U)"
+
+#, c-format
+msgid "E671: Cannot find window title \"%s\""
+msgstr "E671: ÕÒ²»µ½´°¿Ú±êÌâ \"%s\""
+
+#, c-format
+msgid "E243: Argument not supported: \"-%s\"; Use the OLE version."
+msgstr "E243: ²»Ö§³ÖµÄ²ÎÊý: \"-%s\"£»ÇëʹÓà OLE °æ±¾¡£"
+
+msgid "E672: Unable to open window inside MDI application"
+msgstr "E672: ÎÞ·¨ÔÚ MDI Ó¦ÓóÌÐòÖдò¿ª´°¿Ú"
+
+msgid "Close tab"
+msgstr "¹Ø±Õ±êÇ©"
+
+msgid "Open tab..."
+msgstr "´ò¿ª±êÇ©..."
+
+msgid "Find string (use '\\\\' to find a '\\')"
+msgstr "²éÕÒ×Ö·û´® (ʹÓà '\\\\' À´²éÕÒ '\\')"
+
+msgid "Find & Replace (use '\\\\' to find a '\\')"
+msgstr "²éÕÒºÍÌæ»»×Ö·û´® (ʹÓà '\\\\' À´²éÕÒ '\\')"
+
+#. We fake this: Use a filter that doesn't select anything and a default
+#. * file name that won't be used.
+msgid "Not Used"
+msgstr "δʹÓÃ"
+
+msgid "Directory\t*.nothing\n"
+msgstr "Ŀ¼\t*.nothing\n"
+
+msgid "Vim E458: Cannot allocate colormap entry, some colors may be incorrect"
+msgstr "Vim E458: ÎÞ·¨·ÖÅäÑÕÉ«±íÏijЩÑÕÉ«¿ÉÄܲ»ÕýÈ·"
+
+#, c-format
+msgid "E250: Fonts for the following charsets are missing in fontset %s:"
+msgstr "E250: Fontset %s ȱÉÙÏÂÁÐ×Ö·û¼¯µÄ×ÖÌå:"
+
+#, c-format
+msgid "E252: Fontset name: %s"
+msgstr "E252: Fontset Ãû³Æ: %s"
+
+#, c-format
+msgid "Font '%s' is not fixed-width"
+msgstr "'%s' ²»Êǹ̶¨¿í¶ÈµÄ×ÖÌå"
+
+#, c-format
+msgid "E253: Fontset name: %s\n"
+msgstr "E253: Fontset Ãû³Æ: %s\n"
+
+#, c-format
+msgid "Font0: %s\n"
+msgstr "×ÖÌå0: %s\n"
+
+#, c-format
+msgid "Font1: %s\n"
+msgstr "×ÖÌå1: %s\n"
+
+#, c-format
+msgid "Font%ld width is not twice that of font0\n"
+msgstr "×ÖÌå%ldµÄ¿í¶È²»ÊÇ×ÖÌå0µÄÁ½±¶\n"
+
+#, c-format
+msgid "Font0 width: %ld\n"
+msgstr "×ÖÌå0µÄ¿í¶È£º%ld\n"
+
+#, c-format
+msgid ""
+"Font1 width: %ld\n"
+"\n"
+msgstr ""
+"×ÖÌå1µÄ¿í¶È: %ld\n"
+"\n"
+
+msgid "Invalid font specification"
+msgstr "Ö¸¶¨ÁËÎÞЧµÄ×ÖÌå"
+
+msgid "&Dismiss"
+msgstr "È¡Ïû(&D)"
+
+msgid "no specific match"
+msgstr "ÕÒ²»µ½Æ¥ÅäµÄÏî"
+
+msgid "Vim - Font Selector"
+msgstr "Vim - ×ÖÌåÑ¡ÔñÆ÷"
+
+msgid "Name:"
+msgstr "Ãû³Æ:"
+
+#. create toggle button
+#~ msgid "Show size in Points"
+#~ msgstr ""
+
+msgid "Encoding:"
+msgstr "±àÂë:"
+
+msgid "Font:"
+msgstr "×ÖÌå:"
+
+msgid "Style:"
+msgstr "·ç¸ñ:"
+
+msgid "Size:"
+msgstr "³ß´ç:"
+
+msgid "E256: Hangul automata ERROR"
+msgstr "E256: Hangul automata ´íÎó"
+
+msgid "E550: Missing colon"
+msgstr "E550: ȱÉÙðºÅ"
+
+msgid "E551: Illegal component"
+msgstr "E551: ÎÞЧµÄ²¿·Ö"
+
+msgid "E552: digit expected"
+msgstr "E552: Ó¦¸ÃÒªÓÐÊý×Ö"
+
+#, c-format
+msgid "Page %d"
+msgstr "µÚ %d Ò³"
+
+msgid "No text to be printed"
+msgstr "ûÓÐÒª´òÓ¡µÄÎÄ×Ö"
+
+#, c-format
+msgid "Printing page %d (%d%%)"
+msgstr "ÕýÔÚ´òÓ¡µÚ %d Ò³ (%d%%)"
+
+#, c-format
+msgid " Copy %d of %d"
+msgstr "¸´ÖÆ %d / %d"
+
+#, c-format
+msgid "Printed: %s"
+msgstr "ÒÑ´òÓ¡: %s"
+
+msgid "Printing aborted"
+msgstr "´òÓ¡ÖÐÖ¹"
+
+msgid "E455: Error writing to PostScript output file"
+msgstr "E455: дÈë PostScript Êä³öÎļþ³ö´í"
+
+#, c-format
+msgid "E624: Can't open file \"%s\""
+msgstr "E624: ÎÞ·¨´ò¿ªÎļþ \"%s\""
+
+#, c-format
+msgid "E457: Can't read PostScript resource file \"%s\""
+msgstr "E457: ÎÞ·¨¶ÁÈ¡ PostScript ×ÊÔ´Îļþ \"%s\""
+
+#, c-format
+msgid "E618: file \"%s\" is not a PostScript resource file"
+msgstr "E618: Îļþ \"%s\" ²»ÊÇ PostScript ×ÊÔ´Îļþ"
+
+#, c-format
+msgid "E619: file \"%s\" is not a supported PostScript resource file"
+msgstr "E619: Îļþ \"%s\" ²»ÊÇÒÑÖ§³ÖµÄ PostScript ×ÊÔ´Îļþ"
+
+#, c-format
+msgid "E621: \"%s\" resource file has wrong version"
+msgstr "E621: \"%s\" ×ÊÔ´Îļþ°æ±¾²»ÕýÈ·"
+
+msgid "E673: Incompatible multi-byte encoding and character set."
+msgstr "E673: ²»¼æÈݵĶà×Ö½Ú±àÂëºÍ×Ö·û¼¯¡£"
+
+msgid "E674: printmbcharset cannot be empty with multi-byte encoding."
+msgstr "E674: printmbcharset ÔÚ¶à×Ö½Ú±àÂëϲ»ÄÜΪ¿Õ¡£"
+
+msgid "E675: No default font specified for multi-byte printing."
+msgstr "E675: ûÓÐÖ¸¶¨¶à×Ö½Ú´òÓ¡µÄĬÈÏ×ÖÌå¡£"
+
+msgid "E324: Can't open PostScript output file"
+msgstr "E324: ÎÞ·¨´ò¿ª PostScript Êä³öÎļþ"
+
+#, c-format
+msgid "E456: Can't open file \"%s\""
+msgstr "E456: ÎÞ·¨´ò¿ªÎļþ \"%s\""
+
+msgid "E456: Can't find PostScript resource file \"prolog.ps\""
+msgstr "E456: ÕÒ²»µ½ PostScript ×ÊÔ´Îļþ \"prolog.ps\""
+
+msgid "E456: Can't find PostScript resource file \"cidfont.ps\""
+msgstr "E456: ÕÒ²»µ½ PostScript ×ÊÔ´Îļþ \"cidfont.ps\""
+
+#, c-format
+msgid "E456: Can't find PostScript resource file \"%s.ps\""
+msgstr "E456: ÕÒ²»µ½ PostScript ×ÊÔ´Îļþ \"%s.ps\""
+
+#, c-format
+msgid "E620: Unable to convert to print encoding \"%s\""
+msgstr "E620: ÎÞ·¨×ª»»ÖÁ´òÓ¡±àÂë \"%s\""
+
+msgid "Sending to printer..."
+msgstr "·¢Ë͵½´òÓ¡»ú¡­¡­"
+
+msgid "E365: Failed to print PostScript file"
+msgstr "E365: ÎÞ·¨´òÓ¡ PostScript Îļþ"
+
+msgid "Print job sent."
+msgstr "´òÓ¡ÈÎÎñÒѱ»·¢ËÍ¡£"
+
+msgid "Add a new database"
+msgstr "Ìí¼ÓÒ»¸öеÄÊý¾Ý¿â"
+
+msgid "Query for a pattern"
+msgstr "²éѯһ¸öģʽ"
+
+msgid "Show this message"
+msgstr "ÏÔʾ´ËÐÅÏ¢"
+
+msgid "Kill a connection"
+msgstr "½áÊøÒ»¸öÁ¬½Ó"
+
+msgid "Reinit all connections"
+msgstr "ÖØÖÃËùÓÐÁ¬½Ó"
+
+msgid "Show connections"
+msgstr "ÏÔʾÁ¬½Ó"
+
+#, c-format
+msgid "E560: Usage: cs[cope] %s"
+msgstr "E560: Ó÷¨: cs[cope] %s"
+
+msgid "This cscope command does not support splitting the window.\n"
+msgstr "Õâ¸ö cscope ÃüÁî²»Ö§³Ö·Ö¸î´°¿Ú¡£\n"
+
+msgid "E562: Usage: cstag <ident>"
+msgstr "E562: Ó÷¨: cstag <ident>"
+
+msgid "E257: cstag: tag not found"
+msgstr "E257: cstag: ÕÒ²»µ½ tag"
+
+#, c-format
+msgid "E563: stat(%s) error: %d"
+msgstr "E563: stat(%s) ´íÎó: %d"
+
+msgid "E563: stat error"
+msgstr "E563: stat ´íÎó"
+
+#, c-format
+msgid "E564: %s is not a directory or a valid cscope database"
+msgstr "E564: %s ²»ÊÇĿ¼»òÓÐЧµÄ cscope Êý¾Ý¿â"
+
+#, c-format
+msgid "Added cscope database %s"
+msgstr "Ìí¼ÓÁË cscope Êý¾Ý¿â %s"
+
+#, c-format
+msgid "E262: error reading cscope connection %ld"
+msgstr "E262: ¶ÁÈ¡ cscope Á¬½Ó %ld ³ö´í"
+
+msgid "E561: unknown cscope search type"
+msgstr "E561: δ֪µÄ cscope ²éÕÒÀàÐÍ"
+
+msgid "E566: Could not create cscope pipes"
+msgstr "E566: ÎÞ·¨´´½¨ cscope ¹ÜµÀ"
+
+msgid "E622: Could not fork for cscope"
+msgstr "E622: ÎÞ·¨¶Ô cscope ½øÐÐ fork"
+
+msgid "cs_create_connection exec failed"
+msgstr "cs_create_connection Ö´ÐÐʧ°Ü"
+
+msgid "E623: Could not spawn cscope process"
+msgstr "E623: ÎÞ·¨Éú³É cscope ½ø³Ì"
+
+msgid "cs_create_connection: fdopen for to_fp failed"
+msgstr "cs_create_connection: fdopen to_fp ʧ°Ü"
+
+msgid "cs_create_connection: fdopen for fr_fp failed"
+msgstr "cs_create_connection: fdopen fr_fp ʧ°Ü"
+
+msgid "E567: no cscope connections"
+msgstr "E567: ûÓÐ cscope Á¬½Ó"
+
+#, c-format
+msgid "E259: no matches found for cscope query %s of %s"
+msgstr "E259: cscope ²éѯ %s %s ûÓÐÕÒµ½Æ¥ÅäµÄ½á¹û"
+
+#, c-format
+msgid "E469: invalid cscopequickfix flag %c for %c"
+msgstr "E469: cscopequickfix ±êÖ¾ %c ¶Ô %c ÎÞЧ"
+
+msgid "cscope commands:\n"
+msgstr "cscope ÃüÁî:\n"
+
+#, c-format
+msgid "%-5s: %-30s (Usage: %s)"
+msgstr "%-5s: %-30s (Ó÷¨: %s)"
+
+#, c-format
+msgid "E625: cannot open cscope database: %s"
+msgstr "E625: ÎÞ·¨´ò¿ª cscope Êý¾Ý¿â: %s"
+
+msgid "E626: cannot get cscope database information"
+msgstr "E626: ÎÞ·¨»ñÈ¡ cscope Êý¾Ý¿âÐÅÏ¢"
+
+msgid "E568: duplicate cscope database not added"
+msgstr "E568: Öظ´µÄ cscope Êý¾Ý¿âδ±»¼ÓÈë"
+
+msgid "E569: maximum number of cscope connections reached"
+msgstr "E569: ÒÑ´ïµ½ cscope µÄ×î´óÁ¬½ÓÊý"
+
+#, c-format
+msgid "E261: cscope connection %s not found"
+msgstr "E261: ÕÒ²»µ½ cscope Á¬½Ó %s"
+
+#, c-format
+msgid "cscope connection %s closed"
+msgstr "cscope Á¬½Ó %s ÒѹرÕ"
+
+#. should not reach here
+msgid "E570: fatal error in cs_manage_matches"
+msgstr "E570: cs_manage_matches ÑÏÖØ´íÎó"
+
+#, c-format
+msgid "Cscope tag: %s"
+msgstr "Cscope tag: %s"
+
+msgid ""
+"\n"
+" # line"
+msgstr ""
+"\n"
+" # ÐÐ "
+
+msgid "filename / context / line\n"
+msgstr "ÎļþÃû / ÉÏÏÂÎÄ / ÐÐ\n"
+
+#, c-format
+msgid "E609: Cscope error: %s"
+msgstr "E609: Cscope ´íÎó: %s"
+
+msgid "All cscope databases reset"
+msgstr "ËùÓÐ cscope Êý¾Ý¿âÒѱ»ÖØÖÃ"
+
+msgid "no cscope connections\n"
+msgstr "ûÓÐ cscope Á¬½Ó\n"
+
+msgid " # pid database name prepend path\n"
+msgstr " # pid Êý¾Ý¿âÃû prepend path\n"
+
+msgid ""
+"???: Sorry, this command is disabled, the MzScheme library could not be "
+"loaded."
+msgstr "???: ±§Ç¸£¬´ËÃüÁî²»¿ÉÓã¬ÎÞ·¨¼ÓÔØ MzScheme ¿â"
+
+msgid "invalid expression"
+msgstr "ÎÞЧµÄ±í´ïʽ"
+
+msgid "expressions disabled at compile time"
+msgstr "±àÒëʱûÓÐÆôÓñí´ïʽ"
+
+msgid "hidden option"
+msgstr "Òþ²ØµÄÑ¡Ïî"
+
+msgid "unknown option"
+msgstr "δ֪µÄÑ¡Ïî"
+
+msgid "window index is out of range"
+msgstr "´°¿ÚË÷Òý³¬³ö·¶Î§"
+
+msgid "couldn't open buffer"
+msgstr "ÎÞ·¨´ò¿ª»º³åÇø"
+
+msgid "cannot save undo information"
+msgstr "ÎÞ·¨±£´æ³·ÏúÐÅÏ¢"
+
+msgid "cannot delete line"
+msgstr "ÎÞ·¨É¾³ýÐÐ"
+
+msgid "cannot replace line"
+msgstr "ÎÞ·¨Ìæ»»ÐÐ"
+
+msgid "cannot insert line"
+msgstr "ÎÞ·¨²åÈëÐÐ"
+
+msgid "string cannot contain newlines"
+msgstr "×Ö·û´®²»ÄÜ°üº¬»»ÐÐ(NL)"
+
+msgid "Vim error: ~a"
+msgstr "Vim ´íÎó: ~a"
+
+msgid "Vim error"
+msgstr "Vim ´íÎó"
+
+msgid "buffer is invalid"
+msgstr "»º³åÇøÎÞЧ"
+
+msgid "window is invalid"
+msgstr "´°¿ÚÎÞЧ"
+
+msgid "linenr out of range"
+msgstr "Ðкų¬³ö·¶Î§"
+
+msgid "not allowed in the Vim sandbox"
+msgstr "²»ÔÊÐíÔÚ sandbox ÖÐʹÓÃ"
+
+msgid ""
+"E263: Sorry, this command is disabled, the Python library could not be "
+"loaded."
+msgstr "E263: ±§Ç¸£¬´ËÃüÁî²»¿ÉÓã¬ÎÞ·¨¼ÓÔØ Python ¿â¡£"
+
+msgid "E659: Cannot invoke Python recursively"
+msgstr "E659: ²»Äܵݹéµ÷Óà Python"
+
+msgid "can't delete OutputObject attributes"
+msgstr "²»ÄÜɾ³ý OutputObject ÊôÐÔ"
+
+msgid "softspace must be an integer"
+msgstr "softspace ±ØÐëÊÇÕûÊý"
+
+msgid "invalid attribute"
+msgstr "ÎÞЧµÄÊôÐÔ"
+
+msgid "writelines() requires list of strings"
+msgstr "writelines() ÐèÒª×Ö·û´®Áбí×÷²ÎÊý"
+
+msgid "E264: Python: Error initialising I/O objects"
+msgstr "E264: Python: ³õʼ»¯ I/O ¶ÔÏó³ö´í"
+
+msgid "attempt to refer to deleted buffer"
+msgstr "ÊÔͼÒýÓÃÒѱ»É¾³ýµÄ»º³åÇø"
+
+msgid "line number out of range"
+msgstr "Ðкų¬³ö·¶Î§"
+
+#, c-format
+msgid "<buffer object (deleted) at %8lX>"
+msgstr "<»º³åÇø¶ÔÏó(ÒÑɾ³ý): %8lX>"
+
+msgid "invalid mark name"
+msgstr "ÎÞЧµÄ±ê¼ÇÃû³Æ"
+
+msgid "no such buffer"
+msgstr "ÎÞ´Ë»º³åÇø"
+
+msgid "attempt to refer to deleted window"
+msgstr "ÊÔͼÒýÓÃÒѱ»É¾³ýµÄ´°¿Ú"
+
+msgid "readonly attribute"
+msgstr "Ö»¶ÁÊôÐÔ"
+
+msgid "cursor position outside buffer"
+msgstr "¹â±êλÖÃÔÚ»º³åÇøÍâ"
+
+#, c-format
+msgid "<window object (deleted) at %.8lX>"
+msgstr "<´°¿Ú¶ÔÏó(ÒÑɾ³ý): %.8lX>"
+
+#, c-format
+msgid "<window object (unknown) at %.8lX>"
+msgstr "<´°¿Ú¶ÔÏó(δ֪): %.8lX>"
+
+#, c-format
+msgid "<window %d>"
+msgstr "<´°¿Ú %d>"
+
+msgid "no such window"
+msgstr "ÎÞ´Ë´°¿Ú"
+
+msgid ""
+"E266: Sorry, this command is disabled, the Ruby library could not be loaded."
+msgstr "E266: ±§Ç¸£¬´ËÃüÁî²»¿ÉÓã¬ÎÞ·¨¼ÓÔØ Ruby ¿â"
+
+#, c-format
+msgid "E273: unknown longjmp status %d"
+msgstr "E273: δ֪µÄ longjmp ״̬ %d"
+
+msgid "Toggle implementation/definition"
+msgstr "Çл»ÊµÏÖ/¶¨Òå"
+
+msgid "Show base class of"
+msgstr "ÏÔʾ base class of:"
+
+msgid "Show overridden member function"
+msgstr "ÏÔʾ±»¸²¸ÇµÄ³ÉÔ±º¯Êý"
+
+msgid "Retrieve from file"
+msgstr "»Ö¸´: ´ÓÎļþ"
+
+msgid "Retrieve from project"
+msgstr "»Ö¸´: ´Ó¶ÔÏó"
+
+msgid "Retrieve from all projects"
+msgstr "»Ö¸´: ´ÓËùÓÐÏîÄ¿"
+
+msgid "Retrieve"
+msgstr "»Ö¸´"
+
+msgid "Show source of"
+msgstr "ÏÔʾԴ´úÂë: "
+
+msgid "Find symbol"
+msgstr "²éÕÒ symbol"
+
+msgid "Browse class"
+msgstr "ä¯ÀÀ class"
+
+msgid "Show class in hierarchy"
+msgstr "ÏÔʾ²ã´Î¹ØϵµÄÀà"
+
+msgid "Show class in restricted hierarchy"
+msgstr "ÏÔʾ restricted ²ã´Î¹ØϵµÄ class"
+
+msgid "Xref refers to"
+msgstr "Xref ²Î¿¼µ½"
+
+msgid "Xref referred by"
+msgstr "Xref ±»Ë­²Î¿¼:"
+
+msgid "Xref has a"
+msgstr "Xref ÓÐ"
+
+msgid "Xref used by"
+msgstr "Xref ±»Ë­Ê¹ÓÃ:"
+
+msgid "Show docu of"
+msgstr "ÏÔʾÎļþ: "
+
+msgid "Generate docu for"
+msgstr "²úÉúÎļþ: "
+
+msgid ""
+"Cannot connect to SNiFF+. Check environment (sniffemacs must be found in "
+"$PATH).\n"
+msgstr "²»ÄÜÁ¬½Óµ½ SNiFF+¡£Çë¼ì²é»·¾³±äÁ¿ ($PATH Àï±ØÐè¿ÉÒÔÕÒµ½ sniffemacs)\n"
+
+msgid "E274: Sniff: Error during read. Disconnected"
+msgstr "E274: Sniff: ¶ÁÈ¡´íÎó. È¡ÏûÁ¬½Ó"
+
+msgid "SNiFF+ is currently "
+msgstr "SNiFF+ Ä¿Ç°"
+
+msgid "not "
+msgstr "δ"
+
+msgid "connected"
+msgstr "Á¬½ÓÖÐ"
+
+#, c-format
+msgid "E275: Unknown SNiFF+ request: %s"
+msgstr "E275: ²»ÕýÈ·µÄ SNiff+ µ÷ÓÃ: %s"
+
+msgid "E276: Error connecting to SNiFF+"
+msgstr "E276: Á¬½Óµ½ SNiFF+ ʧ°Ü"
+
+msgid "E278: SNiFF+ not connected"
+msgstr "E278: δÁ¬½Óµ½ SNiFF+"
+
+msgid "E279: Not a SNiFF+ buffer"
+msgstr "E279: ²»ÊÇ SNiFF+ µÄ»º³åÇø"
+
+msgid "Sniff: Error during write. Disconnected"
+msgstr "Sniff: дÈë´íÎó¡£½áÊøÁ¬½Ó"
+
+msgid "invalid buffer number"
+msgstr "ÎÞЧµÄ»º³åÇøºÅ"
+
+msgid "not implemented yet"
+msgstr "ÉÐδʵÏÖ"
+
+#. ???
+msgid "cannot set line(s)"
+msgstr "ÎÞ·¨É趨ÐÐ"
+
+msgid "mark not set"
+msgstr "ûÓÐÉ趨±ê¼Ç"
+
+#, c-format
+msgid "row %d column %d"
+msgstr "µÚ %d ÐÐ µÚ %d ÁÐ"
+
+msgid "cannot insert/append line"
+msgstr "ÎÞ·¨²åÈë/×·¼ÓÐÐ"
+
+msgid "unknown flag: "
+msgstr "δ֪µÄ±êÖ¾: "
+
+msgid "unknown vimOption"
+msgstr "δ֪µÄ vim Ñ¡Ïî"
+
+msgid "keyboard interrupt"
+msgstr "¼üÅÌÖжÏ"
+
+msgid "vim error"
+msgstr "vim ´íÎó"
+
+msgid "cannot create buffer/window command: object is being deleted"
+msgstr "ÎÞ·¨´´½¨»º³åÇø/´°¿ÚÃüÁî: ¶ÔÏ󽫱»É¾³ý"
+
+msgid ""
+"cannot register callback command: buffer/window is already being deleted"
+msgstr "ÎÞ·¨×¢²á»Øµ÷ÃüÁî: »º³åÇø/´°¿ÚÒѱ»É¾³ý"
+
+#. This should never happen. Famous last word?
+msgid ""
+"E280: TCL FATAL ERROR: reflist corrupt!? Please report this to vim-dev@vim."
+"org"
+msgstr "E280: TCL ÑÏÖØ´íÎó: reflist Ë𻵣¡£¿Ç뱨¸æ¸ø vim-dev@vim.org"
+
+msgid "cannot register callback command: buffer/window reference not found"
+msgstr "ÎÞ·¨×¢²á»Øµ÷ÃüÁî: ÕÒ²»µ½»º³åÇø/´°¿ÚÒýÓÃ"
+
+msgid ""
+"E571: Sorry, this command is disabled: the Tcl library could not be loaded."
+msgstr "E571: ±§Ç¸£¬´ËÃüÁî²»¿ÉÓã¬ÎÞ·¨¼ÓÔØ Tcl ¿â"
+
+msgid ""
+"E281: TCL ERROR: exit code is not int!? Please report this to vim-dev@vim.org"
+msgstr "E281: TCL ´íÎó: Í˳ö·µ»ØÖµ²»ÊÇÕûÊý£¡£¿Ç뱨¸æ¸ø vim-dev@vim.org"
+
+#, c-format
+msgid "E572: exit code %d"
+msgstr "E572: Í˳ö·µ»ØÖµ %d"
+
+msgid "cannot get line"
+msgstr "ÎÞ·¨»ñÈ¡ÐÐ"
+
+msgid "Unable to register a command server name"
+msgstr "ÎÞ·¨×¢²áÃüÁî·þÎñÆ÷Ãû"
+
+msgid "E248: Failed to send command to the destination program"
+msgstr "E248: ÎÞ·¨·¢ËÍÃüÁĿµÄ³ÌÐò"
+
+#, c-format
+msgid "E573: Invalid server id used: %s"
+msgstr "E573: ʹÓÃÁËÎÞЧµÄ·þÎñÆ÷ id: %s"
+
+msgid "E251: VIM instance registry property is badly formed. Deleted!"
+msgstr "E251: VIM ʵÀý×¢²áÊôÐÔÓÐÎó¡£ÒÑɾ³ý£¡"
+
+msgid "Unknown option argument"
+msgstr "δ֪µÄÑ¡Ïî²ÎÊý"
+
+msgid "Too many edit arguments"
+msgstr "±à¼­²ÎÊý¹ý¶à"
+
+msgid "Argument missing after"
+msgstr "ȱÉÙ±ØÒªµÄ²ÎÊý"
+
+msgid "Garbage after option argument"
+msgstr "Ñ¡Ïî²ÎÊýºóµÄÄÚÈÝÎÞЧ"
+
+msgid "Too many \"+command\", \"-c command\" or \"--cmd command\" arguments"
+msgstr "\"+command\"¡¢\"-c command\" »ò \"--cmd command\" ²ÎÊý¹ý¶à"
+
+msgid "Invalid argument for"
+msgstr "ÎÞЧµÄ²ÎÊý"
+
+#, c-format
+msgid "%d files to edit\n"
+msgstr "»¹ÓÐ %d ¸öÎļþµÈ´ý±à¼­\n"
+
+msgid "This Vim was not compiled with the diff feature."
+msgstr "´Ë Vim ±àÒëʱûÓмÓÈë diff ¹¦ÄÜ"
+
+msgid "Attempt to open script file again: \""
+msgstr "ÊÔͼÔٴδò¿ª½Å±¾Îļþ: \""
+
+msgid "Cannot open for reading: \""
+msgstr "ÎÞ·¨´ò¿ª²¢¶ÁÈ¡: \""
+
+msgid "Cannot open for script output: \""
+msgstr "ÎÞ·¨´ò¿ª²¢Êä³ö½Å±¾: \""
+
+msgid "Vim: Error: Failure to start gvim from NetBeans\n"
+msgstr "Vim: ´íÎó: ÎÞ·¨´Ó NetBeans ÖÐÆô¶¯ gvim\n"
+
+msgid "Vim: Warning: Output is not to a terminal\n"
+msgstr "Vim: ¾¯¸æ: Êä³ö²»Êǵ½ÖÕ¶Ë(ÆÁÄ»)\n"
+
+msgid "Vim: Warning: Input is not from a terminal\n"
+msgstr "Vim: ¾¯¸æ: ÊäÈë²»ÊÇÀ´×ÔÖÕ¶Ë(¼üÅÌ)\n"
+
+#. just in case..
+msgid "pre-vimrc command line"
+msgstr "pre-vimrc ÃüÁîÐÐ"
+
+#, c-format
+msgid "E282: Cannot read from \"%s\""
+msgstr "E282: ÎÞ·¨¶ÁÈ¡ \"%s\""
+
+msgid ""
+"\n"
+"More info with: \"vim -h\"\n"
+msgstr ""
+"\n"
+"¸ü¶àÐÅÏ¢Çë¼û: \"vim -h\"\n"
+
+msgid "[file ..] edit specified file(s)"
+msgstr "[Îļþ ..] ±à¼­Ö¸¶¨µÄÎļþ"
+
+msgid "- read text from stdin"
+msgstr "- ´Ó±ê×¼ÊäÈë(stdin)¶ÁÈ¡Îı¾"
+
+msgid "-t tag edit file where tag is defined"
+msgstr "-t tag ±à¼­ tag ¶¨Òå´¦µÄÎļþ"
+
+msgid "-q [errorfile] edit file with first error"
+msgstr "-q [errorfile] ±à¼­µÚÒ»¸ö³ö´í´¦µÄÎļþ"
+
+msgid ""
+"\n"
+"\n"
+"Usage:"
+msgstr ""
+"\n"
+"\n"
+"Ó÷¨:"
+
+msgid " vim [arguments] "
+msgstr " vim [²ÎÊý] "
+
+msgid ""
+"\n"
+" or:"
+msgstr ""
+"\n"
+" »ò:"
+
+#~ msgid "where case is ignored prepend / to make flag upper case"
+#~ msgstr ""
+
+msgid ""
+"\n"
+"\n"
+"Arguments:\n"
+msgstr ""
+"\n"
+"\n"
+"²ÎÊý:\n"
+
+msgid "--\t\t\tOnly file names after this"
+msgstr "--\t\t\tÔÚÕâÒÔºóÖ»ÓÐÎļþÃû"
+
+msgid "--literal\t\tDon't expand wildcards"
+msgstr "--literal\t\t²»À©Õ¹Í¨Åä·û"
+
+msgid "-register\t\tRegister this gvim for OLE"
+msgstr "-register\t\t×¢²á´Ë gvim µ½ OLE"
+
+msgid "-unregister\t\tUnregister gvim for OLE"
+msgstr "-unregister\t\tÈ¡Ïû OLE ÖÐµÄ gvim ×¢²á"
+
+msgid "-g\t\t\tRun using GUI (like \"gvim\")"
+msgstr "-g\t\t\tʹÓÃͼÐνçÃæ (ͬ \"gvim\")"
+
+msgid "-f or --nofork\tForeground: Don't fork when starting GUI"
+msgstr "-f »ò --nofork\tǰ̨: Æô¶¯Í¼ÐνçÃæʱ²» fork"
+
+msgid "-v\t\t\tVi mode (like \"vi\")"
+msgstr "-v\t\t\tVi ģʽ (ͬ \"vi\")"
+
+msgid "-e\t\t\tEx mode (like \"ex\")"
+msgstr "-e\t\t\tEx ģʽ (ͬ \"ex\")"
+
+msgid "-s\t\t\tSilent (batch) mode (only for \"ex\")"
+msgstr "-s\t\t\t°²¾²(Åú´¦Àí)ģʽ (Ö»ÄÜÓë \"ex\" Ò»ÆðʹÓÃ)"
+
+msgid "-d\t\t\tDiff mode (like \"vimdiff\")"
+msgstr "-d\t\t\tDiff ģʽ (ͬ \"vimdiff\")"
+
+msgid "-y\t\t\tEasy mode (like \"evim\", modeless)"
+msgstr "-y\t\t\tÈÝÒ×ģʽ (ͬ \"evim\"£¬ÎÞģʽ)"
+
+msgid "-R\t\t\tReadonly mode (like \"view\")"
+msgstr "-R\t\t\tÖ»¶Áģʽ (ͬ \"view\")"
+
+msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
+msgstr "-Z\t\t\tÏÞÖÆģʽ (ͬ \"rvim\")"
+
+msgid "-m\t\t\tModifications (writing files) not allowed"
+msgstr "-m\t\t\t²»¿ÉÐÞ¸Ä(дÈëÎļþ)"
+
+msgid "-M\t\t\tModifications in text not allowed"
+msgstr "-M\t\t\tÎı¾²»¿ÉÐÞ¸Ä"
+
+msgid "-b\t\t\tBinary mode"
+msgstr "-b\t\t\t¶þ½øÖÆģʽ"
+
+msgid "-l\t\t\tLisp mode"
+msgstr "-l\t\t\tLisp ģʽ"
+
+msgid "-C\t\t\tCompatible with Vi: 'compatible'"
+msgstr "-C\t\t\t¼æÈÝ´«Í³µÄ Vi: 'compatible'"
+
+msgid "-N\t\t\tNot fully Vi compatible: 'nocompatible'"
+msgstr "-N\t\t\t²»ÍêÈ«¼æÈÝ´«Í³µÄ Vi: 'nocompatible'"
+
+msgid "-V[N]\t\tVerbose level"
+msgstr "-V[N]\t\tVerbose µÈ¼¶"
+
+msgid "-D\t\t\tDebugging mode"
+msgstr "-D\t\t\tµ÷ÊÔģʽ"
+
+msgid "-n\t\t\tNo swap file, use memory only"
+msgstr "-n\t\t\t²»Ê¹Óý»»»Îļþ£¬Ö»Ê¹ÓÃÄÚ´æ"
+
+msgid "-r\t\t\tList swap files and exit"
+msgstr "-r\t\t\tÁгö½»»»Îļþ²¢Í˳ö"
+
+msgid "-r (with file name)\tRecover crashed session"
+msgstr "-r (¸úÎļþÃû)\t\t»Ö¸´±ÀÀ£µÄ»á»°"
+
+msgid "-L\t\t\tSame as -r"
+msgstr "-L\t\t\tͬ -r"
+
+msgid "-f\t\t\tDon't use newcli to open window"
+msgstr "-f\t\t\t²»Ê¹Óà newcli À´´ò¿ª´°¿Ú"
+
+msgid "-dev <device>\t\tUse <device> for I/O"
+msgstr "-dev <device>\t\tʹÓà <device> ½øÐÐÊäÈëÊä³ö"
+
+msgid "-A\t\t\tStart in Arabic mode"
+msgstr "-A\t\t\tÒÔ Arabic ģʽÆô¶¯"
+
+msgid "-H\t\t\tStart in Hebrew mode"
+msgstr "-H\t\t\tÒÔ Hebrew ģʽÆô¶¯"
+
+msgid "-F\t\t\tStart in Farsi mode"
+msgstr "-F\t\t\tÒÔ Farsi ģʽÆô¶¯"
+
+msgid "-T <terminal>\tSet terminal type to <terminal>"
+msgstr "-T <terminal>\tÉ趨ÖÕ¶ËÀàÐÍΪ <terminal>"
+
+msgid "-u <vimrc>\t\tUse <vimrc> instead of any .vimrc"
+msgstr "-u <vimrc>\t\tʹÓà <vimrc> Ìæ´úÈκΠ.vimrc"
+
+msgid "-U <gvimrc>\t\tUse <gvimrc> instead of any .gvimrc"
+msgstr "-U <gvimrc>\t\tʹÓà <gvimrc> Ìæ´úÈκΠ.gvimrc"
+
+msgid "--noplugin\t\tDon't load plugin scripts"
+msgstr "--noplugin\t\t²»¼ÓÔØ plugin ½Å±¾"
+
+msgid "-p[N]\t\tOpen N tab pages (default: one for each file)"
+msgstr "-P[N]\t\t´ò¿ª N ¸ö±êÇ©Ò³ (ĬÈÏÖµ: ÿ¸öÎļþÒ»¸ö)"
+
+msgid "-o[N]\t\tOpen N windows (default: one for each file)"
+msgstr "-o[N]\t\t´ò¿ª N ¸ö´°¿Ú (ĬÈÏÖµ: ÿ¸öÎļþÒ»¸ö)"
+
+msgid "-O[N]\t\tLike -o but split vertically"
+msgstr "-O[N]\t\tͬ -o µ«´¹Ö±·Ö¸î"
+
+msgid "+\t\t\tStart at end of file"
+msgstr "+\t\t\tÆô¶¯ºóÌøµ½Îļþĩβ"
+
+msgid "+<lnum>\t\tStart at line <lnum>"
+msgstr "+<lnum>\t\tÆô¶¯ºóÌøµ½µÚ <lnum> ÐÐ"
+
+msgid "--cmd <command>\tExecute <command> before loading any vimrc file"
+msgstr "--cmd <command>\t¼ÓÔØÈκΠvimrc ÎļþÇ°Ö´ÐÐ <command>"
+
+msgid "-c <command>\t\tExecute <command> after loading the first file"
+msgstr "-c <command>\t\t¼ÓÔصÚÒ»¸öÎļþºóÖ´ÐÐ <command>"
+
+msgid "-S <session>\t\tSource file <session> after loading the first file"
+msgstr "-S <session>\t\t¼ÓÔصÚÒ»¸öÎļþºóÖ´ÐÐÎļþ <session>"
+
+msgid "-s <scriptin>\tRead Normal mode commands from file <scriptin>"
+msgstr "-s <scriptin>\t´ÓÎļþ <scriptin> ¶ÁÈëÕý³£Ä£Ê½µÄÃüÁî"
+
+msgid "-w <scriptout>\tAppend all typed commands to file <scriptout>"
+msgstr "-w <scriptout>\t½«ËùÓÐÊäÈëµÄÃüÁî×·¼Óµ½Îļþ <scriptout>"
+
+msgid "-W <scriptout>\tWrite all typed commands to file <scriptout>"
+msgstr "-W <scriptout>\t½«ËùÓÐÊäÈëµÄÃüÁîдÈëµ½Îļþ <scriptout>"
+
+msgid "-x\t\t\tEdit encrypted files"
+msgstr "-x\t\t\t±à¼­¼ÓÃܵÄÎļþ"
+
+msgid "-display <display>\tConnect vim to this particular X-server"
+msgstr "-display <display>\t½« vim ÓëÖ¸¶¨µÄ X-server Á¬½Ó"
+
+msgid "-X\t\t\tDo not connect to X server"
+msgstr "-X\t\t\t²»Á¬½Óµ½ X Server"
+
+msgid "--remote <files>\tEdit <files> in a Vim server if possible"
+msgstr "--remote <files>\tÈçÓпÉÄÜ£¬ÔÚ Vim ·þÎñÆ÷Éϱ༭Îļþ <files>"
+
+msgid ""
+"--remote-silent <files> Same, don't complain if there is no server"
+msgstr "--remote-silent <files> ͬÉÏ£¬ÕÒ²»µ½·þÎñÆ÷ʱ²»±§Ô¹"
+
+msgid ""
+"--remote-wait <files> As --remote but wait for files to have been edited"
+msgstr "--remote-wait <files> ͬ --remote µ«»áµÈ´ýÎļþÍê³É±à¼­"
+
+msgid ""
+"--remote-wait-silent <files> Same, don't complain if there is no server"
+msgstr "--remote-wait-silent <files> ͬÉÏ£¬ÕÒ²»µ½·þÎñÆ÷ʱ²»±§Ô¹"
+
+msgid "--remote-tab <files> As --remote but open tab page for each file"
+msgstr "--remote-tab <files> ͬ --remote µ«¶Ôÿ¸öÎļþ´ò¿ªÒ»¸ö±êÇ©Ò³"
+
+msgid "--remote-send <keys>\tSend <keys> to a Vim server and exit"
+msgstr "--remote-send <keys>\tËͳö <keys> µ½ Vim ·þÎñÆ÷²¢Í˳ö"
+
+msgid "--remote-expr <expr>\tEvaluate <expr> in a Vim server and print result"
+msgstr "--remote-expr <expr>\tÔÚ Vim ·þÎñÆ÷ÉÏÇó <expr> µÄÖµ²¢´òÓ¡½á¹û"
+
+msgid "--serverlist\t\tList available Vim server names and exit"
+msgstr "--serverlist\t\tÁгö¿ÉÓÃµÄ Vim ·þÎñÆ÷Ãû³Æ²¢Í˳ö"
+
+msgid "--servername <name>\tSend to/become the Vim server <name>"
+msgstr "--servername <name>\t·¢Ë͵½»ò³ÉΪ Vim ·þÎñÆ÷ <name>"
+
+msgid "-i <viminfo>\t\tUse <viminfo> instead of .viminfo"
+msgstr "-i <viminfo>\t\tʹÓà <viminfo> È¡´ú .viminfo"
+
+msgid "-h or --help\tPrint Help (this message) and exit"
+msgstr "-h »ò --help\t´òÓ¡°ïÖú(±¾ÐÅÏ¢)²¢Í˳ö"
+
+msgid "--version\t\tPrint version information and exit"
+msgstr "--version\t\t´òÓ¡°æ±¾ÐÅÏ¢²¢Í˳ö"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Motif version):\n"
+msgstr ""
+"\n"
+"gvim (Motif °æ±¾) ¿Éʶ±ðµÄ²ÎÊý:\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (neXtaw version):\n"
+msgstr ""
+"\n"
+"gvim (neXtaw °æ±¾) ¿Éʶ±ðµÄ²ÎÊý:\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Athena version):\n"
+msgstr ""
+"\n"
+"gvim (Athena °æ±¾) ¿Éʶ±ðµÄ²ÎÊý:\n"
+
+msgid "-display <display>\tRun vim on <display>"
+msgstr "-display <display>\tÔÚ <display> ÉÏÔËÐÐ vim"
+
+msgid "-iconic\t\tStart vim iconified"
+msgstr "-iconic\t\tÆô¶¯ºó×îС»¯"
+
+msgid "-name <name>\t\tUse resource as if vim was <name>"
+msgstr "-name <name>\t\t¶ÁÈ¡ Resource ʱ°Ñ vim ÊÓΪ <name>"
+
+msgid "\t\t\t (Unimplemented)\n"
+msgstr "\t\t\t (ÉÐδʵÏÖ)\n"
+
+msgid "-background <color>\tUse <color> for the background (also: -bg)"
+msgstr "-background <color>\tʹÓà <color> ×÷Ϊ±³¾°É« (Ò²¿ÉÓà -bg)"
+
+msgid "-foreground <color>\tUse <color> for normal text (also: -fg)"
+msgstr "-foreground <color>\tʹÓà <color> ×÷Ϊһ°ãÎÄ×ÖÑÕÉ« (Ò²¿ÉÓà -fg)"
+
+msgid "-font <font>\t\tUse <font> for normal text (also: -fn)"
+msgstr "-font <font>\tʹÓà <font> ×÷Ϊһ°ã×ÖÌå (Ò²¿ÉÓà -fn)"
+
+msgid "-boldfont <font>\tUse <font> for bold text"
+msgstr "-boldfont <font>\tʹÓà <font> ×÷Ϊ´ÖÌå×ÖÌå"
+
+msgid "-italicfont <font>\tUse <font> for italic text"
+msgstr "-italicfont <font>\tʹÓà <font> ×÷ΪбÌå×ÖÌå"
+
+msgid "-geometry <geom>\tUse <geom> for initial geometry (also: -geom)"
+msgstr "-geometry <geom>\tʹÓà <geom> ×÷Ϊ³õʼλÖà (Ò²¿ÉÓà -geom)"
+
+msgid "-borderwidth <width>\tUse a border width of <width> (also: -bw)"
+msgstr "-borderwidth <width>\tÉ趨±ß¿ò¿í¶ÈΪ <width> (Ò²¿ÉÓà -bw)"
+
+msgid "-scrollbarwidth <width> Use a scrollbar width of <width> (also: -sw)"
+msgstr "-scrollbarwidth <width> É趨¹ö¶¯Ìõ¿í¶ÈΪ <width> (Ò²¿ÉÓà -sw)"
+
+msgid "-menuheight <height>\tUse a menu bar height of <height> (also: -mh)"
+msgstr "-menuheight <height>\tÉ趨²Ëµ¥À¸¸ß¶ÈΪ <height> (Ò²¿ÉÓà -mh)"
+
+msgid "-reverse\t\tUse reverse video (also: -rv)"
+msgstr "-reverse\t\tʹÓ÷´ÏÔ (Ò²¿ÉÓà -rv)"
+
+msgid "+reverse\t\tDon't use reverse video (also: +rv)"
+msgstr "+reverse\t\t²»Ê¹Ó÷´ÏÔ (Ò²¿ÉÓà +rv)"
+
+msgid "-xrm <resource>\tSet the specified resource"
+msgstr "-xrm <resource>\tÉ趨ָ¶¨µÄ×ÊÔ´"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (RISC OS version):\n"
+msgstr ""
+"\n"
+"gvim (RISC OS °æ±¾) ¿Éʶ±ðµÄ²ÎÊý:\n"
+
+msgid "--columns <number>\tInitial width of window in columns"
+msgstr "--columns <number>\t´°¿Ú³õʼ¿í¶È"
+
+msgid "--rows <number>\tInitial height of window in rows"
+msgstr "--rows <number>\t´°¿Ú³õʼ¸ß¶È"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (GTK+ version):\n"
+msgstr ""
+"\n"
+"gvim (GTK+ °æ±¾) ¿Éʶ±ðµÄ²ÎÊý:\n"
+
+msgid "-display <display>\tRun vim on <display> (also: --display)"
+msgstr "-display <display>\tÔÚ <display> ÉÏÔËÐÐ vim (Ò²¿ÉÓà --display)"
+
+msgid "--role <role>\tSet a unique role to identify the main window"
+msgstr "--role <role>\tÉèÖÃÓÃÓÚÇø·ÖÖ÷´°¿ÚµÄ´°¿Ú½ÇÉ«Ãû"
+
+msgid "--socketid <xid>\tOpen Vim inside another GTK widget"
+msgstr "--socketid <xid>\tÔÚÁíÒ»¸ö GTK ²¿¼þÖдò¿ª Vim"
+
+msgid "-P <parent title>\tOpen Vim inside parent application"
+msgstr "-P <parent title>\tÔÚ¸¸Ó¦ÓóÌÐòÖдò¿ª Vim"
+
+msgid "No display"
+msgstr "ûÓÐ display"
+
+#. Failed to send, abort.
+msgid ": Send failed.\n"
+msgstr ": ·¢ËÍʧ°Ü¡£\n"
+
+#. Let vim start normally.
+msgid ": Send failed. Trying to execute locally\n"
+msgstr ": ·¢ËÍʧ°Ü¡£³¢ÊÔ±¾µØÖ´ÐÐ\n"
+
+#, c-format
+msgid "%d of %d edited"
+msgstr "%d ÖÐ %d Òѱ༭"
+
+msgid "No display: Send expression failed.\n"
+msgstr "ûÓÐ display: ·¢Ëͱí´ïʽʧ°Ü¡£\n"
+
+msgid ": Send expression failed.\n"
+msgstr ": ·¢Ëͱí´ïʽʧ°Ü¡£\n"
+
+msgid "No marks set"
+msgstr "ûÓÐÉ趨±ê¼Ç"
+
+#, c-format
+msgid "E283: No marks matching \"%s\""
+msgstr "E283: ûÓÐÆ¥Åä \"%s\" µÄ±ê¼Ç"
+
+#. Highlight title
+msgid ""
+"\n"
+"mark line col file/text"
+msgstr ""
+"\n"
+"±ê¼Ç ÐÐ ÁÐ Îļþ/Îı¾"
+
+#. Highlight title
+msgid ""
+"\n"
+" jump line col file/text"
+msgstr ""
+"\n"
+" Ìøת ÐÐ ÁÐ Îļþ/Îı¾"
+
+#. Highlight title
+msgid ""
+"\n"
+"change line col text"
+msgstr ""
+"\n"
+" ¸Ä±ä ÐÐ ÁÐ Îı¾"
+
+#, c-format
+msgid ""
+"\n"
+"# File marks:\n"
+msgstr ""
+"\n"
+"# Îļþ±ê¼Ç:\n"
+
+#. Write the jumplist with -'
+#, c-format
+msgid ""
+"\n"
+"# Jumplist (newest first):\n"
+msgstr ""
+"\n"
+"# ÌøתÁбí (´Óе½¾É):\n"
+
+#, c-format
+msgid ""
+"\n"
+"# History of marks within files (newest to oldest):\n"
+msgstr ""
+"\n"
+"# ÎļþÄڵıê¼ÇÀúÊ·¼Ç¼ (´Óе½¾É):\n"
+
+msgid "Missing '>'"
+msgstr "ȱÉÙ '>'"
+
+msgid "E543: Not a valid codepage"
+msgstr "E543: ÎÞЧµÄ´úÂëÒ³"
+
+msgid "E284: Cannot set IC values"
+msgstr "E284: ²»ÄÜÉ趨 IC Öµ"
+
+msgid "E285: Failed to create input context"
+msgstr "E285: ÎÞ·¨´´½¨ÊäÈëÉÏÏÂÎÄ"
+
+msgid "E286: Failed to open input method"
+msgstr "E286: ÎÞ·¨´ò¿ªÊäÈë·¨"
+
+msgid "E287: Warning: Could not set destroy callback to IM"
+msgstr "E287: ¾¯¸æ: ÎÞ·¨É趨ÊäÈë·¨µÄÊͷŻص÷º¯Êý"
+
+msgid "E288: input method doesn't support any style"
+msgstr "E288: ÊäÈë·¨²»Ö§³ÖÈκηç¸ñ"
+
+msgid "E289: input method doesn't support my preedit type"
+msgstr "E289: ÊäÈë·¨²»Ö§³ÖÎÒµÄÔ¤±à¼­ÀàÐÍ"
+
+msgid "E290: over-the-spot style requires fontset"
+msgstr "E290: over-the-spot ·ç¸ñÐèÒª Fontset"
+
+msgid "E291: Your GTK+ is older than 1.2.3. Status area disabled"
+msgstr "E291: ÄãµÄ GTK+ ±È 1.2.3 ¾É¡£×´Ì¬Çø²»¿ÉÓá£"
+
+msgid "E292: Input Method Server is not running"
+msgstr "E292: ÊäÈë·¨·þÎñÆ÷δÔËÐÐ"
+
+msgid "E293: block was not locked"
+msgstr "E293: ¿éδ±»Ëø¶¨"
+
+msgid "E294: Seek error in swap file read"
+msgstr "E294: ½»»»Îļþ¶ÁÈ¡¶¨Î»´íÎó"
+
+msgid "E295: Read error in swap file"
+msgstr "E295: ½»»»Îļþ¶ÁÈ¡´íÎó"
+
+msgid "E296: Seek error in swap file write"
+msgstr "E296: ½»»»ÎļþдÈ붨λ´íÎó"
+
+msgid "E297: Write error in swap file"
+msgstr "E297: ½»»»ÎļþдÈë´íÎó"
+
+msgid "E300: Swap file already exists (symlink attack?)"
+msgstr "E300: ½»»»ÎļþÒÑ´æÔÚ (·ûºÅÁ¬½Ó¹¥»÷£¿)"
+
+msgid "E298: Didn't get block nr 0?"
+msgstr "E298: ÕÒ²»µ½¿é 0£¿"
+
+msgid "E298: Didn't get block nr 1?"
+msgstr "E298: ÕÒ²»µ½¿é 1£¿"
+
+msgid "E298: Didn't get block nr 2?"
+msgstr "E298: ÕÒ²»µ½¿é 2£¿"
+
+#. could not (re)open the swap file, what can we do????
+msgid "E301: Oops, lost the swap file!!!"
+msgstr "E301: àÞ£¬½»»»Îļþ²»¼ûÁË£¡£¡£¡"
+
+msgid "E302: Could not rename swap file"
+msgstr "E302: ÎÞ·¨ÖØÃüÃû½»»»Îļþ"
+
+#, c-format
+msgid "E303: Unable to open swap file for \"%s\", recovery impossible"
+msgstr "E303: ÎÞ·¨´ò¿ª \"%s\" µÄ½»»»Îļþ£¬»Ö¸´½«²»¿ÉÄÜ"
+
+msgid "E304: ml_upd_block0(): Didn't get block 0??"
+msgstr "E304: ml_upd_block0(): ÕÒ²»µ½¿é 0£¿"
+
+#, c-format
+msgid "E305: No swap file found for %s"
+msgstr "E305: ÕÒ²»µ½ %s µÄ½»»»Îļþ"
+
+msgid "Enter number of swap file to use (0 to quit): "
+msgstr "ÇëÊäÈëҪʹÓõĽ»»»Îļþ±àºÅ (0 Í˳ö): "
+
+#, c-format
+msgid "E306: Cannot open %s"
+msgstr "E306: ÎÞ·¨´ò¿ª %s"
+
+msgid "Unable to read block 0 from "
+msgstr "ÎÞ·¨¶ÁÈ¡¿é 0: "
+
+msgid ""
+"\n"
+"Maybe no changes were made or Vim did not update the swap file."
+msgstr ""
+"\n"
+"¿ÉÄÜÄãû×ö¹ýÈκÎÐ޸ĻòÊÇ Vim »¹À´²»¼°¸üн»»»Îļþ¡£"
+
+msgid " cannot be used with this version of Vim.\n"
+msgstr " ²»ÄÜÔڸð汾µÄ Vim ÖÐʹÓá£\n"
+
+msgid "Use Vim version 3.0.\n"
+msgstr "ʹÓà Vim 3.0¡£\n"
+
+#, c-format
+msgid "E307: %s does not look like a Vim swap file"
+msgstr "E307: %s ¿´ÆðÀ´²»ÏñÊÇ Vim ½»»»Îļþ"
+
+msgid " cannot be used on this computer.\n"
+msgstr " ²»ÄÜÔÚÕą̂µçÄÔÉÏʹÓá£\n"
+
+msgid "The file was created on "
+msgstr "´ËÎļþ´´½¨ÓÚ "
+
+msgid ""
+",\n"
+"or the file has been damaged."
+msgstr ""
+"£¬\n"
+"»òÊÇ´ËÎļþÒÑË𻵡£"
+
+#, c-format
+msgid "Using swap file \"%s\""
+msgstr "ʹÓý»»»Îļþ \"%s\""
+
+#, c-format
+msgid "Original file \"%s\""
+msgstr "ԭʼÎļþ \"%s\""
+
+msgid "E308: Warning: Original file may have been changed"
+msgstr "E308: ¾¯¸æ: ԭʼÎļþ¿ÉÄÜÒѱ»ÐÞ¸Ä"
+
+#, c-format
+msgid "E309: Unable to read block 1 from %s"
+msgstr "E309: ÎÞ·¨´Ó %s ¶ÁÈ¡¿é 1"
+
+# do not translate to avoid writing Chinese in files
+#, fuzzy
+#~ msgid "???MANY LINES MISSING"
+#~ msgstr "???ȱÉÙÁËÌ«¶àÐÐ"
+
+# do not translate to avoid writing Chinese in files
+#, fuzzy
+#~ msgid "???LINE COUNT WRONG"
+#~ msgstr "???ÐÐÊý´íÎó"
+
+# do not translate to avoid writing Chinese in files
+#, fuzzy
+#~ msgid "???EMPTY BLOCK"
+#~ msgstr "???¿ÕµÄ¿é"
+
+# do not translate to avoid writing Chinese in files
+#, fuzzy
+#~ msgid "???LINES MISSING"
+#~ msgstr "???ȱÉÙÁËһЩÐÐ"
+
+#, c-format
+msgid "E310: Block 1 ID wrong (%s not a .swp file?)"
+msgstr "E310: ¿é 1 ID ´íÎó (%s ²»Êǽ»»»Îļþ£¿)"
+
+# do not translate to avoid writing Chinese in files
+#, fuzzy
+#~ msgid "???BLOCK MISSING"
+#~ msgstr "???ȱÉÙ¿é"
+
+# do not translate to avoid writing Chinese in files
+#, fuzzy
+#~ msgid "??? from here until ???END lines may be messed up"
+#~ msgstr "??? ´ÓÕâÀïµ½ ???END µÄÐпÉÄÜÒÑ»ìÂÒ"
+
+# do not translate to avoid writing Chinese in files
+#, fuzzy
+#~ msgid "??? from here until ???END lines may have been inserted/deleted"
+#~ msgstr "??? ´ÓÕâÀïµ½ ???END µÄÐпÉÄÜÒѱ»²åÈë/ɾ³ý¹ý"
+
+# do not translate to avoid writing Chinese in files
+#, fuzzy
+#~ msgid "???END"
+#~ msgstr "???END"
+
+msgid "E311: Recovery Interrupted"
+msgstr "E311: »Ö¸´Òѱ»ÖжÏ"
+
+msgid ""
+"E312: Errors detected while recovering; look for lines starting with ???"
+msgstr "E312: »Ö¸´Ê±·¢Éú´íÎó£»Çë×¢Ò⿪ͷΪ ??? µÄÐÐ"
+
+msgid "See \":help E312\" for more information."
+msgstr "¸ü¶àÐÅÏ¢Çë¼û \":help E312\""
+
+msgid "Recovery completed. You should check if everything is OK."
+msgstr "»Ö¸´Íê±Ï¡£ÇëÈ·¶¨Ò»ÇÐÕý³£¡£"
+
+msgid ""
+"\n"
+"(You might want to write out this file under another name\n"
+msgstr ""
+"\n"
+"(Äã¿ÉÄÜÏëÒª½«Õâ¸öÎļþÁí´æΪ±ðµÄÎļþÃû\n"
+
+msgid "and run diff with the original file to check for changes)\n"
+msgstr "ÔÙÔËÐÐ diff ÓëÔ­Îļþ±È½ÏÒÔ¼ì²éÊÇ·ñÓиıä)\n"
+
+msgid ""
+"Delete the .swp file afterwards.\n"
+"\n"
+msgstr ""
+"È»ºó°Ñ .swp Îļþɾµô¡£\n"
+"\n"
+
+#. use msg() to start the scrolling properly
+msgid "Swap files found:"
+msgstr "ÕÒµ½½»»»Îļþ:"
+
+msgid " In current directory:\n"
+msgstr " λÓÚµ±Ç°Ä¿Â¼:\n"
+
+msgid " Using specified name:\n"
+msgstr " ʹÓÃÖ¸¶¨µÄÃû×Ö:\n"
+
+msgid " In directory "
+msgstr " λÓÚĿ¼ "
+
+msgid " -- none --\n"
+msgstr " -- ÎÞ --\n"
+
+msgid " owned by: "
+msgstr " ËùÓÐÕß: "
+
+msgid " dated: "
+msgstr " ÈÕÆÚ: "
+
+msgid " dated: "
+msgstr " ÈÕÆÚ: "
+
+msgid " [from Vim version 3.0]"
+msgstr " [À´×Ô Vim °æ±¾ 3.0]"
+
+msgid " [does not look like a Vim swap file]"
+msgstr " [²»ÏñÊÇ Vim ½»»»Îļþ]"
+
+msgid " file name: "
+msgstr " ÎļþÃû: "
+
+msgid ""
+"\n"
+" modified: "
+msgstr ""
+"\n"
+" Ð޸Ĺý: "
+
+msgid "YES"
+msgstr "ÊÇ"
+
+msgid "no"
+msgstr "·ñ"
+
+msgid ""
+"\n"
+" user name: "
+msgstr ""
+"\n"
+" ̞: "
+
+msgid " host name: "
+msgstr " Ö÷»úÃû: "
+
+msgid ""
+"\n"
+" host name: "
+msgstr ""
+"\n"
+" Ö÷»úÃû: "
+
+msgid ""
+"\n"
+" process ID: "
+msgstr ""
+"\n"
+" ½ø³Ì ID: "
+
+msgid " (still running)"
+msgstr " (ÈÔÔÚÔËÐÐ)"
+
+msgid ""
+"\n"
+" [not usable with this version of Vim]"
+msgstr ""
+"\n"
+" [²»ÄÜÔڸð汾µÄ Vim ÉÏʹÓÃ]"
+
+msgid ""
+"\n"
+" [not usable on this computer]"
+msgstr ""
+"\n"
+" [²»ÄÜÔÚ±¾»úÉÏʹÓÃ]"
+
+msgid " [cannot be read]"
+msgstr " [ÎÞ·¨¶ÁÈ¡]"
+
+msgid " [cannot be opened]"
+msgstr " [ÎÞ·¨´ò¿ª]"
+
+msgid "E313: Cannot preserve, there is no swap file"
+msgstr "E313: ÎÞ·¨±£Áô£¬Ã»Óн»»»Îļþ"
+
+msgid "File preserved"
+msgstr "ÎļþÒѱ£Áô"
+
+msgid "E314: Preserve failed"
+msgstr "E314: ±£Áôʧ°Ü"
+
+#, c-format
+msgid "E315: ml_get: invalid lnum: %ld"
+msgstr "E315: ml_get: ÎÞЧµÄ lnum: %ld"
+
+#, c-format
+msgid "E316: ml_get: cannot find line %ld"
+msgstr "E316: ml_get: ÕÒ²»µ½µÚ %ld ÐÐ"
+
+msgid "E317: pointer block id wrong 3"
+msgstr "E317: Ö¸Õë¿é id ´íÎó 3"
+
+msgid "stack_idx should be 0"
+msgstr "stack_idx Ó¦¸ÃÊÇ 0"
+
+msgid "E318: Updated too many blocks?"
+msgstr "E318: ¸üÐÂÁËÌ«¶àµÄ¿é£¿"
+
+msgid "E317: pointer block id wrong 4"
+msgstr "E317: Ö¸Õë¿é id ´íÎó 4"
+
+msgid "deleted block 1?"
+msgstr "ɾ³ýÁË¿é 1£¿"
+
+#, c-format
+msgid "E320: Cannot find line %ld"
+msgstr "E320: ÕÒ²»µ½µÚ %ld ÐÐ"
+
+msgid "E317: pointer block id wrong"
+msgstr "E317: Ö¸Õë¿é id ´íÎó"
+
+msgid "pe_line_count is zero"
+msgstr "pe_line_count ΪÁã"
+
+#, c-format
+msgid "E322: line number out of range: %ld past the end"
+msgstr "E322: Ðкų¬³ö·¶Î§: %ld ³¬³ö½áβ"
+
+#, c-format
+msgid "E323: line count wrong in block %ld"
+msgstr "E323: ¿é %ld ÐÐÊý´íÎó"
+
+msgid "Stack size increases"
+msgstr "¶ÑÕ»´óСÔö¼Ó"
+
+msgid "E317: pointer block id wrong 2"
+msgstr "E317: Ö¸Õë¿é id ´íÎó 2"
+
+#, c-format
+msgid "E773: Symlink loop for \"%s\""
+msgstr "E773: \"%s\" ·ûºÅÁ¬½Ó³öÏÖÑ­»·"
+
+msgid "E325: ATTENTION"
+msgstr "E325: ×¢Òâ"
+
+msgid ""
+"\n"
+"Found a swap file by the name \""
+msgstr ""
+"\n"
+"·¢ÏÖ½»»»Îļþ \""
+
+msgid "While opening file \""
+msgstr "ÕýÔÚ´ò¿ªÎļþ \""
+
+msgid " NEWER than swap file!\n"
+msgstr " ±È½»»»ÎļþУ¡\n"
+
+#. Some of these messages are long to allow translation to
+#. * other languages.
+msgid ""
+"\n"
+"(1) Another program may be editing the same file.\n"
+" If this is the case, be careful not to end up with two\n"
+" different instances of the same file when making changes.\n"
+msgstr ""
+"\n"
+"(1) ÁíÒ»¸ö³ÌÐò¿ÉÄÜÒ²Ôڱ༭ͬһ¸öÎļþ¡£\n"
+" Èç¹ûÊÇÕâÑù£¬ÐÞ¸ÄʱÇë×¢Òâ±ÜÃâͬһ¸öÎļþ²úÉúÁ½¸ö²»Í¬µÄ°æ±¾¡£\n"
+"\n"
+
+msgid " Quit, or continue with caution.\n"
+msgstr " Í˳ö£¬»òСÐĵؼÌÐø¡£\n"
+
+msgid ""
+"\n"
+"(2) An edit session for this file crashed.\n"
+msgstr ""
+"\n"
+"(2) Éϴα༭´ËÎļþʱ±ÀÀ£¡£\n"
+
+msgid " If this is the case, use \":recover\" or \"vim -r "
+msgstr " Èç¹ûÊÇÕâÑù£¬ÇëÓà \":recover\" »ò \"vim -r "
+
+msgid ""
+"\"\n"
+" to recover the changes (see \":help recovery\").\n"
+msgstr ""
+"\"\n"
+" »Ö¸´Ð޸ĵÄÄÚÈÝ (Çë¼û \":help recovery\")¡£\n"
+
+msgid " If you did this already, delete the swap file \""
+msgstr " Èç¹ûÄãÒѾ­½øÐÐÁ˻ָ´£¬Çëɾ³ý½»»»Îļþ \""
+
+msgid ""
+"\"\n"
+" to avoid this message.\n"
+msgstr ""
+"\"\n"
+" ÒÔ±ÜÃâÔÙ¿´µ½´ËÏûÏ¢¡£\n"
+
+msgid "Swap file \""
+msgstr "½»»»Îļþ \""
+
+msgid "\" already exists!"
+msgstr "\" ÒÑ´æÔÚ£¡"
+
+msgid "VIM - ATTENTION"
+msgstr "VIM - ×¢Òâ"
+
+msgid "Swap file already exists!"
+msgstr "½»»»ÎļþÒÑ´æÔÚ£¡"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"ÒÔÖ»¶Á·½Ê½´ò¿ª(&O)\n"
+"Ö±½Ó±à¼­(&E)\n"
+"»Ö¸´(&R)\n"
+"Í˳ö(&Q)\n"
+"ÖÐÖ¹(&A)"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Delete it\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"ÒÔÖ»¶Á·½Ê½´ò¿ª(&O)\n"
+"Ö±½Ó±à¼­(&E)\n"
+"»Ö¸´(&R)\n"
+"ɾ³ý½»»»Îļþ(&D)\n"
+"Í˳ö(&Q)\n"
+"ÖÐÖ¹(&A)"
+
+msgid "E326: Too many swap files found"
+msgstr "E326: ÕÒµ½Ì«¶à½»»»Îļþ"
+
+msgid "E327: Part of menu-item path is not sub-menu"
+msgstr "E327: ²Ëµ¥ÏîµÄij²¿·Ö·¾¶²»ÊÇ×Ӳ˵¥"
+
+msgid "E328: Menu only exists in another mode"
+msgstr "E328: ²Ëµ¥Ö»ÔÚÆäËüģʽÖдæÔÚ"
+
+#, c-format
+msgid "E329: No menu \"%s\""
+msgstr "E329: ûÓв˵¥ \"%s\""
+
+msgid "E330: Menu path must not lead to a sub-menu"
+msgstr "E330: ²Ëµ¥Â·¾¶²»ÄÜÖ¸Ïò×Ӳ˵¥"
+
+msgid "E331: Must not add menu items directly to menu bar"
+msgstr "E331: ²»ÄܰѲ˵¥ÏîÖ±½Ó¼Óµ½²Ëµ¥À¸ÖÐ"
+
+msgid "E332: Separator cannot be part of a menu path"
+msgstr "E332: ·Ö¸ôÏß²»ÄÜÊDz˵¥Â·¾¶µÄÒ»²¿·Ö"
+
+#. Now we have found the matching menu, and we list the mappings
+#. Highlight title
+msgid ""
+"\n"
+"--- Menus ---"
+msgstr ""
+"\n"
+"--- ²Ëµ¥ ---"
+
+msgid "Tear off this menu"
+msgstr "˺Ï´˲˵¥"
+
+msgid "E333: Menu path must lead to a menu item"
+msgstr "E333: ²Ëµ¥Â·¾¶±ØÐëÖ¸Ïò²Ëµ¥Ïî"
+
+#, c-format
+msgid "E334: Menu not found: %s"
+msgstr "E334: ÕÒ²»µ½²Ëµ¥: %s"
+
+#, c-format
+msgid "E335: Menu not defined for %s mode"
+msgstr "E335: %s ģʽÖв˵¥Î´¶¨Òå"
+
+msgid "E336: Menu path must lead to a sub-menu"
+msgstr "E336: ²Ëµ¥Â·¾¶±ØÐëÖ¸Ïò×Ӳ˵¥"
+
+msgid "E337: Menu not found - check menu names"
+msgstr "E337: ÕÒ²»µ½²Ëµ¥ - Çë¼ì²é²Ëµ¥Ãû³Æ"
+
+#, c-format
+msgid "Error detected while processing %s:"
+msgstr "´¦Àí %s ʱ·¢Éú´íÎó:"
+
+#, c-format
+msgid "line %4ld:"
+msgstr "µÚ %4ld ÐÐ:"
+
+#, c-format
+msgid "E354: Invalid register name: '%s'"
+msgstr "E354: ÎÞЧµÄ¼Ä´æÆ÷Ãû: '%s'"
+
+msgid "Messages maintainer: Bram Moolenaar <Bram@vim.org>"
+msgstr "¼òÌåÖÐÎÄÏûϢά»¤Õß: Yuheng Xie <elephant@linux.net.cn>"
+
+msgid "Interrupt: "
+msgstr "ÒÑÖжÏ: "
+
+msgid "Press ENTER or type command to continue"
+msgstr "Çë°´ ENTER »òÆäËüÃüÁî¼ÌÐø"
+
+#, c-format
+msgid "%s line %ld"
+msgstr "%s µÚ %ld ÐÐ"
+
+msgid "-- More --"
+msgstr "-- ¸ü¶à --"
+
+msgid " SPACE/d/j: screen/page/line down, b/u/k: up, q: quit "
+msgstr " ¿Õ¸ñ/d/j: ÆÁÄ»/Ò³/ÐÐ Ï·­£¬b/u/k: ÉÏ·­£¬q: Í˳ö "
+
+msgid "Question"
+msgstr "ÎÊÌâ"
+
+msgid ""
+"&Yes\n"
+"&No"
+msgstr ""
+"ÊÇ(&Y)\n"
+"·ñ(&N)"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"Save &All\n"
+"&Discard All\n"
+"&Cancel"
+msgstr ""
+"ÊÇ(&Y)\n"
+"·ñ(&N)\n"
+"È«²¿±£´æ(&A)\n"
+"È«²¿¶ªÆú(&D)\n"
+"È¡Ïû(&C)"
+
+msgid "Select Directory dialog"
+msgstr "Ñ¡ÔñĿ¼¶Ô»°¿ò"
+
+msgid "Save File dialog"
+msgstr "±£´æÎļþ¶Ô»°¿ò"
+
+msgid "Open File dialog"
+msgstr "´ò¿ªÎļþ¶Ô»°¿ò"
+
+#. TODO: non-GUI file selector here
+msgid "E338: Sorry, no file browser in console mode"
+msgstr "E338: ±§Ç¸£¬¿ØÖÆ̨ģʽÏÂûÓÐÎļþä¯ÀÀÆ÷"
+
+msgid "E766: Insufficient arguments for printf()"
+msgstr "E766: printf() µÄ²ÎÊý²»×ã"
+
+msgid "E767: Too many arguments to printf()"
+msgstr "E767: printf() µÄ²ÎÊý¹ý¶à"
+
+msgid "W10: Warning: Changing a readonly file"
+msgstr "W10: ¾¯¸æ: ÕýÔÚÐÞ¸ÄÒ»¸öÖ»¶ÁÎļþ"
+
+msgid "Type number or click with mouse (<Enter> cancels): "
+msgstr "ÇëÊäÈëÊý×Ö»òµã»÷Êó±ê (<Enter> È¡Ïû): "
+
+msgid "Choice number (<Enter> cancels): "
+msgstr "ÇëÑ¡ÔñÊý×Ö (<Enter> È¡Ïû): "
+
+msgid "1 more line"
+msgstr "¶àÁË 1 ÐÐ"
+
+msgid "1 line less"
+msgstr "ÉÙÁË 1 ÐÐ"
+
+#, c-format
+msgid "%ld more lines"
+msgstr "¶àÁË %ld ÐÐ"
+
+#, c-format
+msgid "%ld fewer lines"
+msgstr "ÉÙÁË %ld ÐÐ"
+
+msgid " (Interrupted)"
+msgstr " (ÒÑÖжÏ)"
+
+msgid "Beep!"
+msgstr "Beep!"
+
+msgid "Vim: preserving files...\n"
+msgstr "Vim: ÕýÔÚ±£ÁôÎļþ¡­¡­\n"
+
+#. close all memfiles, without deleting
+msgid "Vim: Finished.\n"
+msgstr "Vim: ½áÊø¡£\n"
+
+#, c-format
+msgid "ERROR: "
+msgstr "´íÎó: "
+
+#, c-format
+msgid ""
+"\n"
+"[bytes] total alloc-freed %lu-%lu, in use %lu, peak use %lu\n"
+msgstr ""
+"\n"
+"[×Ö½Ú] ×ܹ² alloc-free %lu-%lu£¬Ê¹ÓÃÖÐ %lu£¬¸ß·åʹÓà %lu\n"
+
+#, c-format
+msgid ""
+"[calls] total re/malloc()'s %lu, total free()'s %lu\n"
+"\n"
+msgstr ""
+"[µ÷ÓÃ] ×ܹ² re/malloc(): %lu£¬×ܹ² free()': %lu\n"
+"\n"
+
+msgid "E340: Line is becoming too long"
+msgstr "E340: ´ËÐйý³¤"
+
+#, c-format
+msgid "E341: Internal error: lalloc(%ld, )"
+msgstr "E341: ÄÚ²¿´íÎó: lalloc(%ld, )"
+
+#, c-format
+msgid "E342: Out of memory! (allocating %lu bytes)"
+msgstr "E342: ÄÚ´æ²»×㣡(·ÖÅä %lu ×Ö½Ú)"
+
+#, c-format
+msgid "Calling shell to execute: \"%s\""
+msgstr "µ÷ÓÃ shell Ö´ÐÐ: \"%s\""
+
+msgid "E545: Missing colon"
+msgstr "E545: ȱÉÙðºÅ"
+
+msgid "E546: Illegal mode"
+msgstr "E546: ÎÞЧµÄģʽ"
+
+msgid "E547: Illegal mouseshape"
+msgstr "E547: ÎÞЧµÄÊó±êÐÎ×´"
+
+msgid "E548: digit expected"
+msgstr "E548: ´Ë´¦ÐèÒªÊý×Ö"
+
+msgid "E549: Illegal percentage"
+msgstr "E549: ÎÞЧµÄ°Ù·Ö±È"
+
+msgid "Enter encryption key: "
+msgstr "ÊäÈëÃÜÂë: "
+
+msgid "Enter same key again: "
+msgstr "ÇëÔÙÊäÈëÒ»´Î: "
+
+msgid "Keys don't match!"
+msgstr "Á½´ÎÃÜÂ벻ƥÅ䣡"
+
+#, c-format
+msgid ""
+"E343: Invalid path: '**[number]' must be at the end of the path or be "
+"followed by '%s'."
+msgstr "E343: ÎÞЧµÄ·¾¶: '**[number]' ±ØÐëÔÚ·¾¶Ä©Î²»òÕߺóÃæ½Ó '%s'¡£"
+
+#, c-format
+msgid "E344: Can't find directory \"%s\" in cdpath"
+msgstr "E344: cdpath ÖÐÕÒ²»µ½Ä¿Â¼ \"%s\""
+
+#, c-format
+msgid "E345: Can't find file \"%s\" in path"
+msgstr "E345: ÔÚ·¾¶ÖÐÕÒ²»µ½Îļþ \"%s\""
+
+#, c-format
+msgid "E346: No more directory \"%s\" found in cdpath"
+msgstr "E346: ÔÚ·¾¶ÖÐÕÒ²»µ½¸ü¶àµÄÎļþ \"%s\""
+
+#, c-format
+msgid "E347: No more file \"%s\" found in path"
+msgstr "E347: ÔÚ·¾¶ÖÐÕÒ²»µ½¸ü¶àµÄÎļþ \"%s\""
+
+#. Get here when the server can't be found.
+msgid "Cannot connect to Netbeans #2"
+msgstr "ÎÞ·¨Á¬½Óµ½ Netbeans #2"
+
+msgid "Cannot connect to Netbeans"
+msgstr "ÎÞ·¨Á¬½Óµ½ Netbeans"
+
+#, c-format
+msgid "E668: Wrong access mode for NetBeans connection info file: \"%s\""
+msgstr "E668: NetBeans Á¬½ÓÐÅÏ¢ÎļþÖдíÎóµÄ·ÃÎÊģʽ: \"%s\""
+
+msgid "read from Netbeans socket"
+msgstr "´Ó Netbeans Ì×½Ó×Ö¶ÁÈ¡"
+
+#, c-format
+msgid "E658: NetBeans connection lost for buffer %ld"
+msgstr "E658: »º³åÇø %ld ¶ªÊ§ NetBeans Á¬½Ó"
+
+msgid "E505: "
+msgstr "E505: "
+
+msgid "E774: 'operatorfunc' is empty"
+msgstr "E774: 'operatorfunc' Ϊ¿Õ"
+
+msgid "E775: Eval feature not available"
+msgstr "E775: ÇóÖµ¹¦Äܲ»¿ÉÓÃ"
+
+msgid "Warning: terminal cannot highlight"
+msgstr "¾¯¸æ: ÄãµÄÖն˲»ÄÜÏÔʾ¸ßÁÁ"
+
+msgid "E348: No string under cursor"
+msgstr "E348: ¹â±ê´¦Ã»ÓÐ×Ö·û´®"
+
+msgid "E349: No identifier under cursor"
+msgstr "E349: ¹â±ê´¦Ã»ÓÐʶ±ð×Ö"
+
+msgid "E352: Cannot erase folds with current 'foldmethod'"
+msgstr "E352: ²»ÄÜÔÚµ±Ç°µÄ 'foldmethod' ÏÂɾ³ý fold"
+
+msgid "E664: changelist is empty"
+msgstr "E664: ¸Ä±äÁбíΪ¿Õ"
+
+msgid "E662: At start of changelist"
+msgstr "E662: ÒÑÔڸıäÁбíµÄ¿ªÊ¼´¦"
+
+msgid "E663: At end of changelist"
+msgstr "E663: ÒÑÔڸıäÁбíµÄĩβ´¦"
+
+msgid "Type :quit<Enter> to exit Vim"
+msgstr "ÊäÈë :quit<Enter> Í˳ö Vim"
+
+#, c-format
+msgid "1 line %sed 1 time"
+msgstr "1 ÐÐ %s ÁË 1 ´Î"
+
+#, c-format
+msgid "1 line %sed %d times"
+msgstr "1 ÐÐ %s ÁË %d ´Î"
+
+#, c-format
+msgid "%ld lines %sed 1 time"
+msgstr "%ld ÐÐ %s ÁË 1 ´Î"
+
+#, c-format
+msgid "%ld lines %sed %d times"
+msgstr "%ld ÐÐ %s ÁË %d ´Î"
+
+#, c-format
+msgid "%ld lines to indent... "
+msgstr "Ëõ½ø %ld ÐС­¡­ "
+
+msgid "1 line indented "
+msgstr "Ëõ½øÁË 1 ÐÐ "
+
+#, c-format
+msgid "%ld lines indented "
+msgstr "Ëõ½øÁË %ld ÐÐ "
+
+msgid "E748: No previously used register"
+msgstr "E748: ûÓÐÇ°Ò»¸öʹÓõļĴæÆ÷"
+
+#. must display the prompt
+msgid "cannot yank; delete anyway"
+msgstr "ÎÞ·¨¸´ÖÆ£»¸ÄΪɾ³ý"
+
+msgid "1 line changed"
+msgstr "¸Ä±äÁË 1 ÐÐ"
+
+#, c-format
+msgid "%ld lines changed"
+msgstr "¸Ä±äÁË %ld ÐÐ"
+
+#, c-format
+msgid "freeing %ld lines"
+msgstr "ÊÍ·ÅÁË %ld ÐÐ"
+
+msgid "block of 1 line yanked"
+msgstr "¸´ÖÆÁË 1 ÐеĿé"
+
+msgid "1 line yanked"
+msgstr "¸´ÖÆÁË 1 ÐÐ"
+
+#, c-format
+msgid "block of %ld lines yanked"
+msgstr "¸´ÖÆÁË %ld ÐеĿé"
+
+#, c-format
+msgid "%ld lines yanked"
+msgstr "¸´ÖÆÁË %ld ÐÐ"
+
+#, c-format
+msgid "E353: Nothing in register %s"
+msgstr "E353: ¼Ä´æÆ÷ %s ÀïûÓж«Î÷"
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Registers ---"
+msgstr ""
+"\n"
+"--- ¼Ä´æÆ÷ ---"
+
+msgid "Illegal register name"
+msgstr "ÎÞЧµÄ¼Ä´æÆ÷Ãû"
+
+#, c-format
+msgid ""
+"\n"
+"# Registers:\n"
+msgstr ""
+"\n"
+"# ¼Ä´æÆ÷:\n"
+
+#, c-format
+msgid "E574: Unknown register type %d"
+msgstr "E574: δ֪µÄ¼Ä´æÆ÷ÀàÐÍ %d"
+
+#, c-format
+msgid "%ld Cols; "
+msgstr "%ld ÁÐ; "
+
+#, c-format
+msgid "Selected %s%ld of %ld Lines; %ld of %ld Words; %ld of %ld Bytes"
+msgstr "Ñ¡ÔñÁË %s%ld/%ld ÐÐ; %ld/%ld ¸ö´Ê; %ld/%ld ¸ö×Ö½Ú"
+
+#, c-format
+msgid ""
+"Selected %s%ld of %ld Lines; %ld of %ld Words; %ld of %ld Chars; %ld of %ld "
+"Bytes"
+msgstr "Ñ¡ÔñÁË %s%ld/%ld ÐÐ; %ld/%ld ¸ö´Ê; %ld/%ld ¸ö×Ö·û; %ld/%ld ¸ö×Ö½Ú"
+
+#, c-format
+msgid "Col %s of %s; Line %ld of %ld; Word %ld of %ld; Byte %ld of %ld"
+msgstr "µÚ %s/%s ÁÐ; µÚ %ld/%ld ÐÐ; µÚ %ld/%ld ¸ö´Ê; µÚ %ld/%ld ¸ö×Ö½Ú"
+
+#, c-format
+msgid ""
+"Col %s of %s; Line %ld of %ld; Word %ld of %ld; Char %ld of %ld; Byte %ld of "
+"%ld"
+msgstr ""
+"µÚ %s/%s ÁÐ; µÚ %ld/%ld ÐÐ; µÚ %ld/%ld ¸ö´Ê; µÚ %ld/%ld ¸ö×Ö·û; µÚ %ld/%ld ¸ö"
+"×Ö½Ú"
+
+#, c-format
+#~ msgid "(+%ld for BOM)"
+#~ msgstr ""
+
+#~ msgid "%<%f%h%m%=Page %N"
+#~ msgstr ""
+
+msgid "Thanks for flying Vim"
+msgstr "¸ÐлÄúÑ¡Ôñ Vim"
+
+msgid "E518: Unknown option"
+msgstr "E518: δ֪µÄÑ¡Ïî"
+
+msgid "E519: Option not supported"
+msgstr "E519: ²»Ö§³Ö¸ÃÑ¡Ïî"
+
+msgid "E520: Not allowed in a modeline"
+msgstr "E520: ²»ÔÊÐíÔÚ modeline ÖÐʹÓÃ"
+
+msgid "E521: Number required after ="
+msgstr "E521: = ºóÃæÐèÒªÊý×Ö"
+
+msgid "E522: Not found in termcap"
+msgstr "E522: Termcap ÀïÃæÕÒ²»µ½"
+
+#, c-format
+msgid "E539: Illegal character <%s>"
+msgstr "E539: ÎÞЧµÄ×Ö·û <%s>"
+
+msgid "E529: Cannot set 'term' to empty string"
+msgstr "E529: ²»ÄÜÉ趨 'term' Ϊ¿Õ×Ö·û´®"
+
+msgid "E530: Cannot change term in GUI"
+msgstr "E530: ÔÚͼÐνçÃæÖв»ÄܸıäÖÕ¶Ë"
+
+msgid "E531: Use \":gui\" to start the GUI"
+msgstr "E531: ÇëÓà \":gui\" Æô¶¯Í¼ÐνçÃæ"
+
+msgid "E589: 'backupext' and 'patchmode' are equal"
+msgstr "E589: 'backupext' ºÍ 'patchmode' ÏàµÈ"
+
+msgid "E617: Cannot be changed in the GTK+ 2 GUI"
+msgstr "E617: ÔÚ GTK+ 2 ͼÐνçÃæÖв»Äܸü¸Ä"
+
+msgid "E524: Missing colon"
+msgstr "E524: ȱÉÙðºÅ"
+
+msgid "E525: Zero length string"
+msgstr "E525: ×Ö·û´®³¤¶ÈΪÁã"
+
+#, c-format
+msgid "E526: Missing number after <%s>"
+msgstr "E526: <%s> ºóÃæȱÉÙÊý×Ö"
+
+msgid "E527: Missing comma"
+msgstr "E527: ȱÉÙ¶ººÅ"
+
+msgid "E528: Must specify a ' value"
+msgstr "E528: ±ØÐëÖ¸¶¨Ò»¸ö ' Öµ"
+
+msgid "E595: contains unprintable or wide character"
+msgstr "E595: °üº¬²»¿ÉÏÔʾ×Ö·û»ò¿í×Ö·û"
+
+msgid "E596: Invalid font(s)"
+msgstr "E596: ÎÞЧµÄ×ÖÌå"
+
+msgid "E597: can't select fontset"
+msgstr "E597: ÎÞ·¨Ñ¡Ôñ Fontset"
+
+msgid "E598: Invalid fontset"
+msgstr "E598: ÎÞЧµÄ Fontset"
+
+msgid "E533: can't select wide font"
+msgstr "E533: ÎÞ·¨Ñ¡Ôñ¿í×ÖÌå"
+
+msgid "E534: Invalid wide font"
+msgstr "E534: ÎÞЧµÄ¿í×ÖÌå"
+
+#, c-format
+msgid "E535: Illegal character after <%c>"
+msgstr "E535: <%c> ºóÃæÓÐÎÞЧµÄ×Ö·û"
+
+msgid "E536: comma required"
+msgstr "E536: ÐèÒª¶ººÅ"
+
+#, c-format
+msgid "E537: 'commentstring' must be empty or contain %s"
+msgstr "E537: 'commentstring' ±ØÐëΪ¿Õ»ò°üº¬ %s"
+
+msgid "E538: No mouse support"
+msgstr "E538: ²»Ö§³ÖÊó±ê"
+
+msgid "E540: Unclosed expression sequence"
+msgstr "E540: ûÓнáÊøµÄ±í´ïʽÐòÁÐ"
+
+msgid "E541: too many items"
+msgstr "E541: ÏîÄ¿¹ý¶à"
+
+msgid "E542: unbalanced groups"
+msgstr "E542: ´íÂÒµÄ×é"
+
+msgid "E590: A preview window already exists"
+msgstr "E590: Ô¤ÀÀ´°¿ÚÒÑ´æÔÚ"
+
+msgid "W17: Arabic requires UTF-8, do ':set encoding=utf-8'"
+msgstr "W17: Arabic ÐèÒª UTF-8£¬ÇëÖ´ÐÐ ':set encoding=utf-8'"
+
+#, c-format
+msgid "E593: Need at least %d lines"
+msgstr "E593: ÖÁÉÙÐèÒª %d ÐÐ"
+
+#, c-format
+msgid "E594: Need at least %d columns"
+msgstr "E594: ÖÁÉÙÐèÒª %d ÁÐ"
+
+#, c-format
+msgid "E355: Unknown option: %s"
+msgstr "E355: δ֪µÄÑ¡Ïî: %s"
+
+msgid ""
+"\n"
+"--- Terminal codes ---"
+msgstr ""
+"\n"
+"--- Öն˱àÂë ---"
+
+msgid ""
+"\n"
+"--- Global option values ---"
+msgstr ""
+"\n"
+"--- È«¾ÖÑ¡ÏîÖµ ---"
+
+msgid ""
+"\n"
+"--- Local option values ---"
+msgstr ""
+"\n"
+"--- ¾Ö²¿Ñ¡ÏîÖµ ---"
+
+msgid ""
+"\n"
+"--- Options ---"
+msgstr ""
+"\n"
+"--- Ñ¡Ïî ---"
+
+msgid "E356: get_varp ERROR"
+msgstr "E356: get_varp ´íÎó"
+
+#, c-format
+msgid "E357: 'langmap': Matching character missing for %s"
+msgstr "E357: 'langmap': ÕÒ²»µ½ %s ¶ÔÓ¦µÄ×Ö·û"
+
+#, c-format
+msgid "E358: 'langmap': Extra characters after semicolon: %s"
+msgstr "E358: 'langmap': ·ÖºÅºóÓжàÓàµÄ×Ö·û: %s"
+
+msgid "cannot open "
+msgstr "²»ÄÜ´ò¿ª"
+
+msgid "VIM: Can't open window!\n"
+msgstr "VIM: ²»ÄÜ´ò¿ª´°¿Ú!\n"
+
+msgid "Need Amigados version 2.04 or later\n"
+msgstr "ÐèÒª Amigados °æ±¾ 2.04 ÒÔÉÏ\n"
+
+#, c-format
+msgid "Need %s version %ld\n"
+msgstr "ÐèÒª %s °æ±¾ %ld\n"
+
+msgid "Cannot open NIL:\n"
+msgstr "²»ÄÜ´ò¿ª NIL:\n"
+
+msgid "Cannot create "
+msgstr "²»ÄÜ´´½¨ "
+
+#, c-format
+msgid "Vim exiting with %d\n"
+msgstr "Vim ·µ»ØÖµ: %d\n"
+
+msgid "cannot change console mode ?!\n"
+msgstr "²»ÄÜÇл»Ö÷¿Ø̨(console)ģʽ !?\n"
+
+msgid "mch_get_shellsize: not a console??\n"
+msgstr "mch_get_shellsize: ²»ÊÇÖ÷¿Ø̨(console)??\n"
+
+#. if Vim opened a window: Executing a shell may cause crashes
+msgid "E360: Cannot execute shell with -f option"
+msgstr "E360: ²»ÄÜÓà -f Ñ¡ÏîÖ´ÐÐ shell"
+
+msgid "Cannot execute "
+msgstr "²»ÄÜÖ´ÐÐ "
+
+msgid "shell "
+msgstr "shell "
+
+msgid " returned\n"
+msgstr " ÒÑ·µ»Ø\n"
+
+msgid "ANCHOR_BUF_SIZE too small."
+msgstr "ANCHOR_BUF_SIZE ̫С"
+
+msgid "I/O ERROR"
+msgstr "I/O ´íÎó"
+
+msgid "Message"
+msgstr "ÏûÏ¢"
+
+msgid "'columns' is not 80, cannot execute external commands"
+msgstr "'columns' ²»ÊÇ 80, ²»ÄÜÖ´ÐÐÍⲿÃüÁî"
+
+msgid "E237: Printer selection failed"
+msgstr "E237: Ñ¡Ôñ´òÓ¡»úʧ°Ü"
+
+#, c-format
+msgid "to %s on %s"
+msgstr "´Ó %s µ½ %s"
+
+#, c-format
+msgid "E613: Unknown printer font: %s"
+msgstr "E613: δ֪µÄ´òÓ¡»ú×ÖÌå: %s"
+
+#, c-format
+msgid "E238: Print error: %s"
+msgstr "E238: ´òÓ¡´íÎó: %s"
+
+#, c-format
+msgid "Printing '%s'"
+msgstr "´òÓ¡ '%s'"
+
+#, c-format
+msgid "E244: Illegal charset name \"%s\" in font name \"%s\""
+msgstr "E244: ×Ö·û¼¯ \"%s\" ²»ÄܶÔÓ¦×ÖÌå\"%s\""
+
+#, c-format
+msgid "E245: Illegal char '%c' in font name \"%s\""
+msgstr "E245: ²»ÕýÈ·µÄ×Ö·û '%c' ³öÏÖÔÚ×ÖÌåÃû³Æ \"%s\" ÄÚ"
+
+msgid "Vim: Double signal, exiting\n"
+msgstr "Vim: Ë«ÖØÐźţ¬Í˳öÖÐ\n"
+
+#, c-format
+msgid "Vim: Caught deadly signal %s\n"
+msgstr "Vim: À¹½Øµ½ÖÂÃüÐźÅ(deadly signal) %s\n"
+
+#, c-format
+msgid "Vim: Caught deadly signal\n"
+msgstr "Vim: À¹½Øµ½ÖÂÃüÐźÅ(deadly signal)\n"
+
+#, c-format
+msgid "Opening the X display took %ld msec"
+msgstr "´ò¿ª X display ÓÃʱ %ld Ãë"
+
+msgid ""
+"\n"
+"Vim: Got X error\n"
+msgstr ""
+"\n"
+"Vim: X ´íÎó\n"
+
+msgid "Testing the X display failed"
+msgstr "²âÊÔ X display ʧ°Ü"
+
+msgid "Opening the X display timed out"
+msgstr "´ò¿ª X display ³¬Ê±"
+
+msgid ""
+"\n"
+"Cannot execute shell "
+msgstr ""
+"\n"
+"ÎÞ·¨Ö´ÐÐ shell"
+
+msgid ""
+"\n"
+"Cannot execute shell sh\n"
+msgstr ""
+"\n"
+"ÎÞ·¨Ö´ÐÐ shell sh\n"
+
+msgid ""
+"\n"
+"shell returned "
+msgstr ""
+"\n"
+"Shell ÒÑ·µ»Ø"
+
+msgid ""
+"\n"
+"Cannot create pipes\n"
+msgstr ""
+"\n"
+"ÎÞ·¨½¨Á¢¹ÜµÀ\n"
+
+msgid ""
+"\n"
+"Cannot fork\n"
+msgstr ""
+"\n"
+"ÎÞ·¨ fork\n"
+
+msgid ""
+"\n"
+"Command terminated\n"
+msgstr ""
+"\n"
+"ÃüÁîÒѽáÊø\n"
+
+msgid "XSMP lost ICE connection"
+msgstr "XSMP ¶ªÊ§Á˵½ ICE µÄÁ¬½Ó"
+
+# do not translate
+#, c-format
+msgid "dlerror = \"%s\""
+msgstr "dlerror = \"%s\""
+
+msgid "Opening the X display failed"
+msgstr "´ò¿ª X display ʧ°Ü"
+
+msgid "XSMP handling save-yourself request"
+msgstr "XSMP ´¦Àí save-yourself ÇëÇó"
+
+msgid "XSMP opening connection"
+msgstr "XSMP ´ò¿ªÁ¬½Ó"
+
+msgid "XSMP ICE connection watch failed"
+msgstr "XSMP ICE Á¬½Ó¼àÊÓʧ°Ü"
+
+#, c-format
+msgid "XSMP SmcOpenConnection failed: %s"
+msgstr "XSMP SmcOpenConnection µ÷ÓÃʧ°Ü: %s"
+
+msgid "At line"
+msgstr "ÔÚÐкŠ"
+
+msgid "Could not load vim32.dll!"
+msgstr "ÎÞ·¨¼ÓÔØ vim32.dll£¡"
+
+msgid "VIM Error"
+msgstr "VIM ´íÎó"
+
+msgid "Could not fix up function pointers to the DLL!"
+msgstr "ÎÞ·¨ÐÞÕýµ½ DLL µÄº¯ÊýÖ¸Õë!"
+
+#, c-format
+msgid "shell returned %d"
+msgstr "Shell ·µ»Ø %d"
+
+#, c-format
+msgid "Vim: Caught %s event\n"
+msgstr "Vim: À¹½Øµ½ %s ʼþ\n"
+
+msgid "close"
+msgstr "¹Ø±Õ"
+
+msgid "logoff"
+msgstr "×¢Ïû"
+
+msgid "shutdown"
+msgstr "¹Ø»ú"
+
+msgid "E371: Command not found"
+msgstr "E371: ÕÒ²»µ½ÃüÁî"
+
+msgid ""
+"VIMRUN.EXE not found in your $PATH.\n"
+"External commands will not pause after completion.\n"
+"See :help win32-vimrun for more information."
+msgstr ""
+"ÔÚÄãµÄ $PATH ÖÐÕÒ²»µ½ VIMRUN.EXE¡£\n"
+"ÍⲿÃüÁîÖ´ÐÐÍê±Ïºó½«²»»áÔÝÍ£¡£\n"
+"½øÒ»²½ËµÃ÷Çë¼û :help win32-vimrun"
+
+msgid "Vim Warning"
+msgstr "Vim ¾¯¸æ"
+
+#, c-format
+msgid "E372: Too many %%%c in format string"
+msgstr "E372: ¸ñʽ»¯×Ö·û´®ÀïÓÐÌ«¶à %%%c "
+
+#, c-format
+msgid "E373: Unexpected %%%c in format string"
+msgstr "E373: ¸ñʽ»¯×Ö·û´®²»Ó¦¸Ã³öÏÖ %%%c "
+
+msgid "E374: Missing ] in format string"
+msgstr "E374: ¸ñʽ»¯×Ö·û´®ÀïÉÙÁË ]"
+
+#, c-format
+msgid "E375: Unsupported %%%c in format string"
+msgstr "E375: ¸ñʽ»¯×Ö·û´®ÀïÓв»Ö§³ÖµÄ %%%c "
+
+#, c-format
+msgid "E376: Invalid %%%c in format string prefix"
+msgstr "E376: ¸ñʽ»¯×Ö·û´®¿ªÍ·ÀïÓв»ÕýÈ·µÄ %%%c "
+
+#, c-format
+msgid "E377: Invalid %%%c in format string"
+msgstr "E377: ¸ñʽ»¯×Ö·û´®ÀïÓв»ÕýÈ·µÄ %%%c "
+
+msgid "E378: 'errorformat' contains no pattern"
+msgstr "E378: 'errorformat' δÉ趨"
+
+msgid "E379: Missing or empty directory name"
+msgstr "E379: ÕÒ²»µ½Ä¿Â¼Ãû³Æ»òÊÇ¿ÕµÄĿ¼Ãû³Æ"
+
+msgid "E553: No more items"
+msgstr "E553: ûÓиü¶àµÄÏî"
+
+#, c-format
+msgid "(%d of %d)%s%s: "
+msgstr "(%d / %d)%s%s: "
+
+msgid " (line deleted)"
+msgstr " (ÐÐÒÑɾ³ý)"
+
+msgid "E380: At bottom of quickfix stack"
+msgstr "E380: Quickfix ¶ÑÕ»µ×¶Ë"
+
+msgid "E381: At top of quickfix stack"
+msgstr "E381: Quickfix ¶ÑÕ»¶¥¶Ë"
+
+#, c-format
+msgid "error list %d of %d; %d errors"
+msgstr "´íÎóÁбí %d / %d£»¹² %d ¸ö´íÎó"
+
+msgid "E382: Cannot write, 'buftype' option is set"
+msgstr "E382: ÎÞ·¨Ð´È룬ÒÑÉ趨ѡÏî 'buftype'"
+
+msgid "E683: File name missing or invalid pattern"
+msgstr "E683: ȱÉÙÎļþÃû»òģʽÎÞЧ"
+
+#, c-format
+msgid "Cannot open file \"%s\""
+msgstr "ÎÞ·¨´ò¿ªÎļþ \"%s\""
+
+msgid "E681: Buffer is not loaded"
+msgstr "E681: »º³åÇøδ¼ÓÔØ"
+
+msgid "E777: String or List expected"
+msgstr "E777: ´Ë´¦ÐèÒª String »òÕß List"
+
+#, c-format
+msgid "E369: invalid item in %s%%[]"
+msgstr "E369: %s%%[] ÖÐÓÐÎÞЧµÄÏî"
+
+msgid "E339: Pattern too long"
+msgstr "E339: ģʽ̫³¤"
+
+msgid "E50: Too many \\z("
+msgstr "E50: Ì«¶à \\z("
+
+#, c-format
+msgid "E51: Too many %s("
+msgstr "E51: Ì«¶à %s("
+
+msgid "E52: Unmatched \\z("
+msgstr "E52: ²»Æ¥ÅäµÄ \\z("
+
+#, c-format
+msgid "E53: Unmatched %s%%("
+msgstr "E53: ²»Æ¥ÅäµÄ %s%%("
+
+#, c-format
+msgid "E54: Unmatched %s("
+msgstr "E54: ²»Æ¥ÅäµÄ %s("
+
+#, c-format
+msgid "E55: Unmatched %s)"
+msgstr "E55: ²»Æ¥ÅäµÄ %s)"
+
+#, c-format
+msgid "E59: invalid character after %s@"
+msgstr "E59: %s@ ºóÃæÓÐÎÞЧµÄ×Ö·û"
+
+#, c-format
+msgid "E60: Too many complex %s{...}s"
+msgstr "E60: Ì«¶à¸´Ô %s{...}s"
+
+#, c-format
+msgid "E61: Nested %s*"
+msgstr "E61: ǶÌ×µÄ %s*"
+
+#, c-format
+msgid "E62: Nested %s%c"
+msgstr "E62: ǶÌ×µÄ %s%c"
+
+msgid "E63: invalid use of \\_"
+msgstr "E63: ²»ÕýÈ·µØʹÓà \\_"
+
+#, c-format
+msgid "E64: %s%c follows nothing"
+msgstr "E64: %s%c Ç°ÃæÎÞÄÚÈÝ"
+
+msgid "E65: Illegal back reference"
+msgstr "E65: ÎÞЧµÄ»ØÒý"
+
+msgid "E66: \\z( not allowed here"
+msgstr "E66: ´Ë´¦²»ÔÊÐí \\z("
+
+msgid "E67: \\z1 - \\z9 not allowed here"
+msgstr "E67: ´Ë´¦²»ÔÊÐí \\z1 µÈ"
+
+msgid "E68: Invalid character after \\z"
+msgstr "E68: \\z ºóÃæÓÐÎÞЧµÄ×Ö·û"
+
+#, c-format
+msgid "E69: Missing ] after %s%%["
+msgstr "E69: %s%%[ ºóȱÉÙ ]"
+
+#, c-format
+msgid "E70: Empty %s%%[]"
+msgstr "E70: ¿ÕµÄ %s%%[]"
+
+#, c-format
+msgid "E678: Invalid character after %s%%[dxouU]"
+msgstr "E678: %s%%[dxouU] ºóÃæÓÐÎÞЧµÄ×Ö·û"
+
+#, c-format
+msgid "E71: Invalid character after %s%%"
+msgstr "E71: %s%% ºóÃæÓÐÎÞЧµÄ×Ö·û"
+
+#, c-format
+msgid "E769: Missing ] after %s["
+msgstr "E769: %s[ ºóȱÉÙ ]"
+
+#, c-format
+msgid "E554: Syntax error in %s{...}"
+msgstr "E554: %s{...} ÖÐÓï·¨´íÎó"
+
+msgid "External submatches:\n"
+msgstr "Íⲿ·ûºÏ:\n"
+
+msgid " VREPLACE"
+msgstr " V-Ìæ»»"
+
+msgid " REPLACE"
+msgstr " Ìæ»»"
+
+msgid " REVERSE"
+msgstr " ·´Ïò"
+
+msgid " INSERT"
+msgstr " ²åÈë"
+
+msgid " (insert)"
+msgstr " (²åÈë)"
+
+msgid " (replace)"
+msgstr " (Ìæ»»)"
+
+msgid " (vreplace)"
+msgstr " (V-Ìæ»»)"
+
+msgid " Hebrew"
+msgstr " Hebrew"
+
+msgid " Arabic"
+msgstr " Arabic"
+
+msgid " (lang)"
+msgstr " (ÓïÑÔ)"
+
+msgid " (paste)"
+msgstr " (Õ³Ìû)"
+
+msgid " VISUAL"
+msgstr " ¿ÉÊÓ"
+
+msgid " VISUAL LINE"
+msgstr " ¿ÉÊÓ ÐÐ"
+
+msgid " VISUAL BLOCK"
+msgstr " ¿ÉÊÓ ¿é"
+
+msgid " SELECT"
+msgstr " Ñ¡Ôñ"
+
+msgid " SELECT LINE"
+msgstr " Ñ¡Ôñ ÐÐ"
+
+msgid " SELECT BLOCK"
+msgstr " Ñ¡Ôñ ¿é"
+
+msgid "recording"
+msgstr "¼Ç¼ÖÐ"
+
+#, c-format
+msgid "E383: Invalid search string: %s"
+msgstr "E383: ÎÞЧµÄ²éÕÒ×Ö·û´®: %s"
+
+#, c-format
+msgid "E384: search hit TOP without match for: %s"
+msgstr "E384: ÒѲéÕÒµ½Îļþ¿ªÍ·ÈÔÕÒ²»µ½ %s"
+
+#, c-format
+msgid "E385: search hit BOTTOM without match for: %s"
+msgstr "E385: ÒѲéÕÒµ½Îļþ½áβÈÔÕÒ²»µ½ %s"
+
+msgid "E386: Expected '?' or '/' after ';'"
+msgstr "E386: ÔÚ ';' ºóÃæÓ¦¸ÃÓÐ '?' »ò '/'"
+
+msgid " (includes previously listed match)"
+msgstr " (°üÀ¨ÉÏ´ÎÁгö·ûºÏÏî)"
+
+#. cursor at status line
+msgid "--- Included files "
+msgstr "--- °üº¬Îļþ "
+
+msgid "not found "
+msgstr "ÕÒ²»µ½ "
+
+msgid "in path ---\n"
+msgstr "ÔÚ·¾¶ ---\n"
+
+msgid " (Already listed)"
+msgstr " (ÒÑÁгö)"
+
+msgid " NOT FOUND"
+msgstr " ÕÒ²»µ½"
+
+#, c-format
+msgid "Scanning included file: %s"
+msgstr "²éÕÒ°üº¬Îļþ: %s"
+
+#, c-format
+msgid "Searching included file %s"
+msgstr "²éÕÒ°üº¬µÄÎļþ %s"
+
+msgid "E387: Match is on current line"
+msgstr "E387: µ±Ç°ÐÐÆ¥Åä"
+
+msgid "All included files were found"
+msgstr "ËùÓаüº¬Îļþ¶¼ÒÑÕÒµ½"
+
+msgid "No included files"
+msgstr "ûÓаüº¬Îļþ"
+
+msgid "E388: Couldn't find definition"
+msgstr "E388: ÕÒ²»µ½¶¨Òå"
+
+msgid "E389: Couldn't find pattern"
+msgstr "E389: ÕÒ²»µ½ pattern"
+
+msgid "E759: Format error in spell file"
+msgstr "E759: ƴдÎļþ¸ñʽ´íÎó"
+
+msgid "E758: Truncated spell file"
+msgstr "E758: ÒѽضϵÄƴдÎļþ"
+
+#, c-format
+msgid "Trailing text in %s line %d: %s"
+msgstr "%s µÚ %d ÐУ¬¶àÓàµÄºóÐø×Ö·û: %s"
+
+#, c-format
+msgid "Affix name too long in %s line %d: %s"
+msgstr "%s µÚ %d ÐУ¬¸½¼ÓÏîÃû×ÖÌ«³¤: %s"
+
+msgid "E761: Format error in affix file FOL, LOW or UPP"
+msgstr "E761: ¸½¼ÓÎļþ FOL¡¢LOW »ò UPP Öиñʽ´íÎó"
+
+msgid "E762: Character in FOL, LOW or UPP is out of range"
+msgstr "E762: FOL¡¢LOW »ò UPP ÖÐ×Ö·û³¬³ö·¶Î§"
+
+msgid "Compressing word tree..."
+msgstr "ѹËõµ¥´ÊÊ÷¡­¡­"
+
+msgid "E756: Spell checking is not enabled"
+msgstr "E756: ƴд¼ì²éδÆôÓÃ"
+
+#, c-format
+msgid "Warning: Cannot find word list \"%s.%s.spl\" or \"%s.ascii.spl\""
+msgstr "¾¯¸æ: ÕÒ²»µ½µ¥´ÊÁбí \"%s.%s.spl\" or \"%s.ascii.spl\""
+
+#, c-format
+msgid "Reading spell file \"%s\""
+msgstr "¶ÁȡƴдÎļþ \"%s\""
+
+msgid "E757: This does not look like a spell file"
+msgstr "E757: Õâ¿´ÆðÀ´²»ÏñÊÇƴдÎļþ"
+
+msgid "E771: Old spell file, needs to be updated"
+msgstr "E771: ¾É°æ±¾µÄƴдÎļþ£¬ÐèÒª¸üÐÂ"
+
+msgid "E772: Spell file is for newer version of Vim"
+msgstr "E772: Ϊ¸ü¸ß°æ±¾µÄ Vim ËùÓõÄƴдÎļþ"
+
+msgid "E770: Unsupported section in spell file"
+msgstr "E770: ƴдÎļþÖдæÔÚ²»Ö§³ÖµÄ½Ú"
+
+#, c-format
+msgid "Warning: region %s not supported"
+msgstr "¾¯¸æ: ÇøÓò %s ²»Ö§³Ö"
+
+#, c-format
+msgid "Reading affix file %s..."
+msgstr "¶ÁÈ¡¸½¼ÓÎļþ %s ¡­¡­"
+
+#, c-format
+msgid "Conversion failure for word in %s line %d: %s"
+msgstr "µ¥´Ê %s ת»»Ê§°Ü£¬µÚ %d ÐÐ: %s"
+
+#, c-format
+msgid "Conversion in %s not supported: from %s to %s"
+msgstr "²»Ö§³Ö %s ÖеÄת»»: ´Ó %s µ½ %s"
+
+#, c-format
+msgid "Conversion in %s not supported"
+msgstr "²»Ö§³Ö %s ÖеÄת»»"
+
+#, c-format
+msgid "Invalid value for FLAG in %s line %d: %s"
+msgstr "%s µÚ %d ÐУ¬FLAG µÄÖµÎÞЧ: %s"
+
+#, c-format
+msgid "FLAG after using flags in %s line %d: %s"
+msgstr "%s µÚ %d ÐУ¬ÔÚʹÓñêÖ¾ºó³öÏÖ FLAG: %s"
+
+#, c-format
+#~ msgid ""
+#~ "Defining COMPOUNDFORBIDFLAG after PFX item may give wrong results in %s line "
+#~ "%d"
+#~ msgstr ""
+
+#, c-format
+#~ msgid ""
+#~ "Defining COMPOUNDPERMITFLAG after PFX item may give wrong results in %s line "
+#~ "%d"
+#~ msgstr ""
+
+#, c-format
+msgid "Wrong COMPOUNDWORDMAX value in %s line %d: %s"
+msgstr "%s µÚ %d ÐУ¬´íÎóµÄ COMPOUNDWORDMAX Öµ: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDMIN value in %s line %d: %s"
+msgstr "%s µÚ %d ÐУ¬´íÎóµÄ COMPOUNDMIN Öµ: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDSYLMAX value in %s line %d: %s"
+msgstr "%s µÚ %d ÐУ¬´íÎóµÄ COMPOUNDSYLMAX Öµ: %s"
+
+#, c-format
+msgid "Wrong CHECKCOMPOUNDPATTERN value in %s line %d: %s"
+msgstr "%s µÚ %d ÐУ¬´íÎóµÄ CHECKCOMPOUNDPATTERN Öµ: %s"
+
+#, c-format
+msgid "Different combining flag in continued affix block in %s line %d: %s"
+msgstr "%s µÚ %d ÐУ¬ÔÚÁ¬ÐøµÄ¸½¼Ó¿éÖгöÏÖ²»Í¬µÄ×éºÏ±êÖ¾: %s"
+
+#, c-format
+msgid "Duplicate affix in %s line %d: %s"
+msgstr "%s µÚ %d ÐУ¬Öظ´µÄ¸½¼ÓÏî: %s"
+
+#, c-format
+msgid ""
+"Affix also used for BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST in %s "
+"line %d: %s"
+msgstr ""
+"%s µÚ %d ÐУ¬¸½¼ÓÏî±» BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST ʹ"
+"ÓÃ: %s"
+
+#, c-format
+msgid "Expected Y or N in %s line %d: %s"
+msgstr "%s µÚ %d ÐУ¬´Ë´¦ÐèÒª Y »ò N: %s"
+
+#, c-format
+msgid "Broken condition in %s line %d: %s"
+msgstr "%s µÚ %d ÐУ¬´íÎóµÄÌõ¼þ: %s"
+
+#, c-format
+msgid "Expected REP(SAL) count in %s line %d"
+msgstr "%s µÚ %d ÐУ¬´Ë´¦ÐèÒª REP(SAL) ¼ÆÊý"
+
+#, c-format
+msgid "Expected MAP count in %s line %d"
+msgstr "%s µÚ %d ÐУ¬´Ë´¦ÐèÒª MAP ¼ÆÊý"
+
+#, c-format
+msgid "Duplicate character in MAP in %s line %d"
+msgstr "%s µÚ %d ÐУ¬MAP ÖдæÔÚÖظ´µÄ×Ö·û"
+
+#, c-format
+msgid "Unrecognized or duplicate item in %s line %d: %s"
+msgstr "%s µÚ %d ÐУ¬ÎÞ·¨Ê¶±ð»òÖظ´µÄÏî: %s"
+
+#, c-format
+msgid "Missing FOL/LOW/UPP line in %s"
+msgstr "%s ÖÐȱÉÙ FOL/LOW/UPP ÐÐ"
+
+msgid "COMPOUNDSYLMAX used without SYLLABLE"
+msgstr "ÔÚûÓÐ SYLLABLE µÄÇé¿öÏÂʹÓÃÁË COMPOUNDSYLMAX"
+
+msgid "Too many postponed prefixes"
+msgstr "Ì«¶àÑÓ³Ùǰ׺"
+
+msgid "Too many compound flags"
+msgstr "Ì«¶à×éºÏ±êÖ¾"
+
+msgid "Too many postponed prefixes and/or compound flags"
+msgstr "Ì«¶àÑÓ³Ùǰ׺ºÍ/»ò×éºÏ±êÖ¾"
+
+#, c-format
+msgid "Missing SOFO%s line in %s"
+msgstr "%s ÖÐȱÉÙ SOFO%s ÐÐ"
+
+#, c-format
+msgid "Both SAL and SOFO lines in %s"
+msgstr "%s ͬʱ³öÏÖ SQL ºÍ SOFO ÐÐ"
+
+#, c-format
+msgid "Flag is not a number in %s line %d: %s"
+msgstr "%s µÚ %d ÐУ¬±êÖ¾²»ÊÇÊý×Ö: %s"
+
+#, c-format
+msgid "Illegal flag in %s line %d: %s"
+msgstr "%s µÚ %d ÐУ¬ÎÞЧµÄ±êÖ¾: %s"
+
+#, c-format
+msgid "%s value differs from what is used in another .aff file"
+msgstr "%s µÄÖµÓëÁíÒ»¸ö .aff ÎļþÖÐʹÓõÄÖµ²»Ïàͬ"
+
+#, c-format
+msgid "Reading dictionary file %s..."
+msgstr "¶ÁÈ¡×ÖµäÎļþ %s ¡­¡­"
+
+#, c-format
+msgid "E760: No word count in %s"
+msgstr "E760: %s ÖÐûÓе¥´Ê¼ÆÊý"
+
+#, c-format
+msgid "line %6d, word %6d - %s"
+msgstr "µÚ %6d ÐУ¬µÚ %6d ¸öµ¥´Ê - %s"
+
+#, c-format
+msgid "Duplicate word in %s line %d: %s"
+msgstr "%s µÚ %d ÐУ¬Öظ´µÄµ¥´Ê: %s"
+
+#, c-format
+msgid "First duplicate word in %s line %d: %s"
+msgstr "%s µÚ %d ÐУ¬Ê×´ÎÖظ´µÄµ¥´Ê: %s"
+
+#, c-format
+msgid "%d duplicate word(s) in %s"
+msgstr "´æÔÚ %d ¸öÖظ´µÄµ¥´Ê£¬ÔÚ %s ÖÐ"
+
+#, c-format
+msgid "Ignored %d word(s) with non-ASCII characters in %s"
+msgstr "ºöÂÔÁ˺¬ÓÐ·Ç ASCII ×Ö·ûµÄ %d ¸öµ¥´Ê£¬ÔÚ %s ÖÐ"
+
+#, c-format
+msgid "Reading word file %s..."
+msgstr "¶ÁÈ¡µ¥´ÊÎļþ %s ¡­¡­"
+
+#, c-format
+#~ msgid "Duplicate /encoding= line ignored in %s line %d: %s"
+#~ msgstr ""
+
+#, c-format
+msgid "/encoding= line after word ignored in %s line %d: %s"
+msgstr "%s µÚ %d ÐУ¬µ¥´ÊºóµÄ /encoding= ÐÐÒѱ»ºöÂÔ: %s"
+
+#, c-format
+msgid "Duplicate /regions= line ignored in %s line %d: %s"
+msgstr "%s µÚ %d ÐУ¬Öظ´µÄ /regions= ÐÐÒѱ»ºöÂÔ: %s"
+
+#, c-format
+msgid "Too many regions in %s line %d: %s"
+msgstr "%s µÚ %d ÐУ¬Ì«¶àÇøÓò: %s"
+
+#, c-format
+msgid "/ line ignored in %s line %d: %s"
+msgstr "%s µÚ %d ÐУ¬/ ÐÐÒѱ»ºöÂÔ: %s"
+
+#, c-format
+msgid "Invalid region nr in %s line %d: %s"
+msgstr "%s µÚ %d ÐУ¬ÎÞЧµÄÇøÓòºÅ: %s"
+
+#, c-format
+msgid "Unrecognized flags in %s line %d: %s"
+msgstr "%s µÚ %d ÐУ¬²»¿Éʶ±ðµÄ±êÖ¾: %s"
+
+#, c-format
+msgid "Ignored %d words with non-ASCII characters"
+msgstr "ºöÂÔÁ˺¬ÓÐ·Ç ASCII ×Ö·ûµÄ %d ¸öµ¥´Ê"
+
+#, c-format
+msgid "Compressed %d of %d nodes; %d (%d%%) remaining"
+msgstr "ѹËõÁË %d/%d ¸ö½Úµã£»Ê£Óà %d (%d%%)"
+
+msgid "Reading back spell file..."
+msgstr "¶ÁȡƴдÎļþ¡­¡­"
+
+#.
+#. * Go through the trie of good words, soundfold each word and add it to
+#. * the soundfold trie.
+#.
+msgid "Performing soundfolding..."
+msgstr "ÕýÔÚ soundfolding¡­¡­"
+
+#, c-format
+msgid "Number of words after soundfolding: %ld"
+msgstr "soundfolding ºóµÄµ¥´ÊÊý: %ld"
+
+#, c-format
+msgid "Total number of words: %d"
+msgstr "µ¥´Ê×ÜÊý: %d"
+
+#, c-format
+msgid "Writing suggestion file %s..."
+msgstr "дÈ뽨ÒéÎļþ %s ¡­¡­"
+
+#, c-format
+msgid "Estimated runtime memory use: %d bytes"
+msgstr "¹À¼ÆÔËÐÐʱÄÚ´æÓÃÁ¿: %d ×Ö½Ú"
+
+msgid "E751: Output file name must not have region name"
+msgstr "E751: Êä³öÎļþÃû²»Äܺ¬ÓÐÇøÓòÃû"
+
+msgid "E754: Only up to 8 regions supported"
+msgstr "E754: ×î¶àÖ»Ö§³Ö 8 ¸öÇøÓò"
+
+#, c-format
+msgid "E755: Invalid region in %s"
+msgstr "E755: %s ³öÏÖÎÞЧµÄ·¶Î§"
+
+msgid "Warning: both compounding and NOBREAK specified"
+msgstr "¾¯¸æ: ͬʱָ¶¨ÁË compounding ºÍ NOBREAK"
+
+#, c-format
+msgid "Writing spell file %s..."
+msgstr "дÈëƴдÎļþ %s ¡­¡­"
+
+msgid "Done!"
+msgstr "Íê³É£¡"
+
+#, c-format
+msgid "E765: 'spellfile' does not have %ld entries"
+msgstr "E765: 'spellfile' ûÓÐ %ld Ïî"
+
+#, c-format
+msgid "Word removed from %s"
+msgstr "´Ó %s ÖÐɾ³ýÁ˵¥´Ê"
+
+#, c-format
+msgid "Word added to %s"
+msgstr "Ïò %s ÖÐÌí¼ÓÁ˵¥´Ê"
+
+msgid "E763: Word characters differ between spell files"
+msgstr "E763: ƴдÎļþÖ®¼äµÄ×Ö·û²»Ïàͬ"
+
+msgid "Sorry, no suggestions"
+msgstr "±§Ç¸£¬Ã»Óн¨Òé"
+
+#, c-format
+msgid "Sorry, only %ld suggestions"
+msgstr "±§Ç¸£¬Ö»ÓÐ %ld Ìõ½¨Òé"
+
+#. avoid more prompt
+#, c-format
+msgid "Change \"%.*s\" to:"
+msgstr "½« \"%.*s\" ¸ÄΪ£º"
+
+#, c-format
+msgid " < \"%.*s\""
+msgstr " < \"%.*s\""
+
+msgid "E752: No previous spell replacement"
+msgstr "E752: ֮ǰûÓÐƴдÌæ»»"
+
+#, c-format
+msgid "E753: Not found: %s"
+msgstr "E753: ÕÒ²»µ½: %s"
+
+#, c-format
+msgid "E778: This does not look like a .sug file: %s"
+msgstr "E778: ¿´ÆðÀ´²»ÏñÊÇ .sug Îļþ: %s"
+
+#, c-format
+#~ msgid "E779: Old .sug file, needs to be updated: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E780: .sug file is for newer version of Vim: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E781: .sug file doesn't match .spl file: %s"
+#~ msgstr ""
+
+#, fuzzy, c-format
+#~ msgid "E782: error while reading .sug file: %s"
+#~ msgstr "E47: ¶ÁÈ¡´íÎóÎļþʧ°Ü"
+
+#. This should have been checked when generating the .spl
+#. * file.
+#~ msgid "E783: duplicate char in MAP entry"
+#~ msgstr ""
+
+#, c-format
+msgid "E390: Illegal argument: %s"
+msgstr "E390: ÎÞЧµÄ²ÎÊý: %s"
+
+#, c-format
+msgid "E391: No such syntax cluster: %s"
+msgstr "E391: ÎÞ´ËÓï·¨ cluster: \"%s\""
+
+msgid "No Syntax items defined for this buffer"
+msgstr "Õâ¸ö»º³åÇøûÓж¨ÒåÈκÎÓï·¨Ïî"
+
+msgid "syncing on C-style comments"
+msgstr "C·ç¸ñ×¢ÊÍͬ²½ÖÐ"
+
+msgid "no syncing"
+msgstr "ûÓÐͬ²½"
+
+msgid "syncing starts "
+msgstr "ͬ²½¿ªÊ¼"
+
+msgid " lines before top line"
+msgstr "Ðкų¬³ö·¶Î§"
+
+msgid ""
+"\n"
+"--- Syntax sync items ---"
+msgstr ""
+"\n"
+"--- Ó﷨ͬ²½ÏîÄ¿ (Syntax sync items) ---"
+
+msgid ""
+"\n"
+"syncing on items"
+msgstr ""
+"\n"
+"ͬ²½ÖÐ:"
+
+msgid ""
+"\n"
+"--- Syntax items ---"
+msgstr ""
+"\n"
+"--- Óï·¨ÏîÄ¿ ---"
+
+#, c-format
+msgid "E392: No such syntax cluster: %s"
+msgstr "E392: ÎÞ´ËÓï·¨ cluster: \"%s\""
+
+msgid "minimal "
+msgstr "×îС"
+
+msgid "maximal "
+msgstr "×î´ó"
+
+#, fuzzy
+#~ msgid "; match "
+#~ msgstr "Æ¥Åä %d"
+
+#, fuzzy
+#~ msgid " line breaks"
+#~ msgstr "ÉÙÓÚÒ»ÐÐ"
+
+msgid "E395: contains argument not accepted here"
+msgstr "E395: ʹÓÃÁ˲»ÕýÈ·µÄ²ÎÊý"
+
+msgid "E396: containedin argument not accepted here"
+msgstr "E396: ʹÓÃÁ˲»ÕýÈ·µÄ²ÎÊý"
+
+msgid "E393: group[t]here not accepted here"
+msgstr "E393: ʹÓÃÁ˲»ÕýÈ·µÄ²ÎÊý"
+
+#, c-format
+msgid "E394: Didn't find region item for %s"
+msgstr "E394: ÕÒ²»µ½ %s µÄ region item"
+
+msgid "E397: Filename required"
+msgstr "E397: ÐèÒªÎļþÃû³Æ"
+
+#, c-format
+msgid "E747: Missing ']': %s"
+msgstr "E747: ȱÉÙ ']': %s"
+
+#, c-format
+msgid "E398: Missing '=': %s"
+msgstr "E398: ȱÉÙ '=': %s"
+
+#, c-format
+msgid "E399: Not enough arguments: syntax region %s"
+msgstr "E399: syntax region %s µÄ²ÎÊýÌ«ÉÙ"
+
+msgid "E400: No cluster specified"
+msgstr "E400: ûÓÐÖ¸¶¨µÄÊôÐÔ"
+
+#, c-format
+msgid "E401: Pattern delimiter not found: %s"
+msgstr "E401: ÕÒ²»µ½·Ö¸ô·ûºÅ: %s"
+
+#, c-format
+msgid "E402: Garbage after pattern: %s"
+msgstr "E402: '%s' ºóÃæµÄ¶«Î÷²»ÄÜʶ±ð"
+
+msgid "E403: syntax sync: line continuations pattern specified twice"
+msgstr "E403: Ó﷨ͬ²½: Á¬½ÓÐзûºÅÖ¸¶¨ÁËÁ½´Î"
+
+#, c-format
+msgid "E404: Illegal arguments: %s"
+msgstr "E404: ÎÞЧµÄ²ÎÊý: %s"
+
+#, c-format
+msgid "E405: Missing equal sign: %s"
+msgstr "E405: ȱÉٵȺÅ: %s"
+
+#, c-format
+msgid "E406: Empty argument: %s"
+msgstr "E406: ¿ÕµÄ²ÎÊý: %s"
+
+#, c-format
+msgid "E407: %s not allowed here"
+msgstr "E407: %s ²»ÄÜÔڴ˳öÏÖ"
+
+#, c-format
+msgid "E408: %s must be first in contains list"
+msgstr "E408: %s ±ØÐëÊÇÁбíÀïµÄµÚÒ»¸ö"
+
+#, c-format
+msgid "E409: Unknown group name: %s"
+msgstr "E409: ²»ÕýÈ·µÄ×éÃû: %s"
+
+#, c-format
+msgid "E410: Invalid :syntax subcommand: %s"
+msgstr "E410: ²»ÕýÈ·µÄ :syntax ×ÓÃüÁî: %s"
+
+msgid "E679: recursive loop loading syncolor.vim"
+msgstr "E679: ¼ÓÔØ syncolor.vim ʱ³öÏÖǶÌ×Ñ­»·"
+
+#, c-format
+msgid "E411: highlight group not found: %s"
+msgstr "E411: ÕÒ²»µ½ highlight group: %s"
+
+#, c-format
+msgid "E412: Not enough arguments: \":highlight link %s\""
+msgstr "E412: ²ÎÊýÌ«ÉÙ: \":highlight link %s\""
+
+#, c-format
+msgid "E413: Too many arguments: \":highlight link %s\""
+msgstr "E413: ²ÎÊý¹ý¶à: \":highlight link %s\""
+
+msgid "E414: group has settings, highlight link ignored"
+msgstr "E414: ÒÑÉ趨×é, ºöÂÔ highlight link"
+
+#, c-format
+msgid "E415: unexpected equal sign: %s"
+msgstr "E415: ²»¸ÃÓеĵȺÅ: %s"
+
+#, c-format
+msgid "E416: missing equal sign: %s"
+msgstr "E416: ȱÉٵȺÅ: %s"
+
+#, c-format
+msgid "E417: missing argument: %s"
+msgstr "E417: ȱÉÙ²ÎÊý: %s"
+
+#, c-format
+msgid "E418: Illegal value: %s"
+msgstr "E418: ²»ºÏ·¨µÄÖµ: %s"
+
+msgid "E419: FG color unknown"
+msgstr "E419: ´íÎóµÄÇ°¾°ÑÕÉ«"
+
+msgid "E420: BG color unknown"
+msgstr "E420: ´íÎóµÄ±³¾°ÑÕÉ«"
+
+#, c-format
+msgid "E421: Color name or number not recognized: %s"
+msgstr "E421: ´íÎóµÄÑÕÉ«Ãû³Æ»òÊýÖµ: %s"
+
+#, c-format
+msgid "E422: terminal code too long: %s"
+msgstr "E422: Öն˱àÂëÌ«³¤: %s"
+
+#, c-format
+msgid "E423: Illegal argument: %s"
+msgstr "E423: ÎÞЧµÄ²ÎÊý: %s"
+
+msgid "E424: Too many different highlighting attributes in use"
+msgstr "E424: ʹÓÃÁËÌ«¶à²»Í¬µÄ¸ßÁÁ¶ÈÊôÐÔ"
+
+msgid "E669: Unprintable character in group name"
+msgstr "E669: ×éÃûÖдæÔÚ²»¿ÉÏÔʾ×Ö·û"
+
+msgid "W18: Invalid character in group name"
+msgstr "W18: ×éÃûÖк¬ÓÐÎÞЧ×Ö·û"
+
+msgid "E555: at bottom of tag stack"
+msgstr "E555: ÒÑÔÚ tag ¶ÑÕ»µ×²¿"
+
+msgid "E556: at top of tag stack"
+msgstr "E556: ÒÑÔÚ tag ¶ÑÕ»¶¥²¿"
+
+msgid "E425: Cannot go before first matching tag"
+msgstr "E425: Òѵ½µÚÒ»¸öÆ¥ÅäµÄ tag"
+
+#, c-format
+msgid "E426: tag not found: %s"
+msgstr "E426: ÕÒ²»µ½ tag: %s"
+
+msgid " # pri kind tag"
+msgstr " # pri kind tag"
+
+msgid "file\n"
+msgstr "Îļþ\n"
+
+msgid "E427: There is only one matching tag"
+msgstr "E427: Ö»ÓÐÒ»¸öÆ¥ÅäµÄ tag"
+
+msgid "E428: Cannot go beyond last matching tag"
+msgstr "E428: ¼ºµ½×îºóÒ»¸öÆ¥ÅäµÄ tag"
+
+#, c-format
+msgid "File \"%s\" does not exist"
+msgstr "Îļþ \"%s\" ²»´æÔÚ"
+
+#. Give an indication of the number of matching tags
+#, c-format
+msgid "tag %d of %d%s"
+msgstr "ÕÒµ½ tag: %d / %d%s"
+
+msgid " or more"
+msgstr " »ò¸ü¶à"
+
+msgid " Using tag with different case!"
+msgstr " ÒÔ²»Í¬´óСдÀ´Ê¹Óà tag£¡"
+
+#, c-format
+msgid "E429: File \"%s\" does not exist"
+msgstr "E429: Îļþ \"%s\" ²»´æÔÚ"
+
+#. Highlight title
+msgid ""
+"\n"
+" # TO tag FROM line in file/text"
+msgstr ""
+"\n"
+" # µ½ tag ´Ó ÐÐ ÔÚ Îļþ/Îı¾"
+
+#, c-format
+msgid "Searching tags file %s"
+msgstr "²éÕÒ tag Îļþ %s"
+
+#, c-format
+msgid "E430: Tag file path truncated for %s\n"
+msgstr "E430: Tag Îļþ·¾¶±»½Ø¶ÏΪ %s\n"
+
+#, c-format
+msgid "E431: Format error in tags file \"%s\""
+msgstr "E431: Tag Îļþ \"%s\" ¸ñʽ´íÎó"
+
+#, c-format
+msgid "Before byte %ld"
+msgstr "ÔÚµÚ %ld ×Ö½Ú֮ǰ"
+
+#, c-format
+msgid "E432: Tags file not sorted: %s"
+msgstr "E432: Tag ÎļþδÅÅÐò: %s"
+
+#. never opened any tags file
+msgid "E433: No tags file"
+msgstr "E433: ûÓÐ tag Îļþ"
+
+msgid "E434: Can't find tag pattern"
+msgstr "E434: ÕÒ²»µ½ tag ģʽ"
+
+msgid "E435: Couldn't find tag, just guessing!"
+msgstr "E435: ÕÒ²»µ½ tag£¬ÊÔ×Ų£¡"
+
+msgid "' not known. Available builtin terminals are:"
+msgstr "' δ֪¡£¿ÉÓõÄÄÚ½¨ÖÕ¶ËÓÐ:"
+
+msgid "defaulting to '"
+msgstr "ĬÈÏֵΪ: '"
+
+msgid "E557: Cannot open termcap file"
+msgstr "E557: ÎÞ·¨´ò¿ª termcap Îļþ"
+
+msgid "E558: Terminal entry not found in terminfo"
+msgstr "E558: ÔÚ terminfo ÖÐÕÒ²»µ½ÖÕ¶ËÏî"
+
+msgid "E559: Terminal entry not found in termcap"
+msgstr "E559: ÔÚ termcap ÖÐÕÒ²»µ½ÖÕ¶ËÏî"
+
+#, c-format
+msgid "E436: No \"%s\" entry in termcap"
+msgstr "E436: termcap ÖÐûÓÐ \"%s\" Ïî"
+
+msgid "E437: terminal capability \"cm\" required"
+msgstr "E437: ÖÕ¶ËÐèÒªÄÜÁ¦ \"cm\""
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Terminal keys ---"
+msgstr ""
+"\n"
+"--- Öն˰´¼ü ---"
+
+msgid "new shell started\n"
+msgstr "Æô¶¯Ð shell\n"
+
+msgid "Vim: Error reading input, exiting...\n"
+msgstr "Vim: ¶Á´íÎó£¬Í˳öÖÐ...\n"
+
+#. must display the prompt
+msgid "No undo possible; continue anyway"
+msgstr "ÎÞ·¨³·Ïú£»ÈÔÈ»¼ÌÐø"
+
+msgid "Already at oldest change"
+msgstr "ÒÑλÓÚ×î¾ÉµÄ¸Ä±ä"
+
+msgid "Already at newest change"
+msgstr "ÒÑλÓÚ×îеĸıä"
+
+#, c-format
+msgid "Undo number %ld not found"
+msgstr "ÕÒ²»µ½³·ÏúºÅ %ld"
+
+msgid "E438: u_undo: line numbers wrong"
+msgstr "E438: u_undo: ÐкŴíÎó"
+
+msgid "more line"
+msgstr "Ðб»¼ÓÈë"
+
+msgid "more lines"
+msgstr "Ðб»¼ÓÈë"
+
+msgid "line less"
+msgstr "Ðб»È¥µô"
+
+msgid "fewer lines"
+msgstr "Ðб»È¥µô"
+
+msgid "change"
+msgstr "Ðз¢Éú¸Ä±ä"
+
+msgid "changes"
+msgstr "Ðз¢Éú¸Ä±ä"
+
+#, c-format
+msgid "%ld %s; %s #%ld %s"
+msgstr "%ld %s£»%s #%ld %s"
+
+msgid "before"
+msgstr "before"
+
+msgid "after"
+msgstr "after"
+
+msgid "Nothing to undo"
+msgstr "Î޿ɳ·Ïú"
+
+msgid "number changes time"
+msgstr " ±àºÅ ¸Ä±ä ʱ¼ä"
+
+msgid "E439: undo list corrupt"
+msgstr "E439: ³·ÏúÁбíËð»µ"
+
+msgid "E440: undo line missing"
+msgstr "E440: ÕÒ²»µ½Òª³·ÏúµÄÐÐ"
+
+#. Only MS VC 4.1 and earlier can do Win32s
+msgid ""
+"\n"
+"MS-Windows 16/32-bit GUI version"
+msgstr ""
+"\n"
+"MS-Windows 16/32 λͼÐνçÃæ°æ±¾"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit GUI version"
+msgstr ""
+"\n"
+"MS-Windows 32 λͼÐνçÃæ°æ±¾"
+
+msgid " in Win32s mode"
+msgstr " Win32s ģʽ"
+
+msgid " with OLE support"
+msgstr " ´ø OLE Ö§³Ö"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit console version"
+msgstr ""
+"\n"
+"MS-Windows 32 λ¿ØÖÆ̨°æ±¾"
+
+msgid ""
+"\n"
+"MS-Windows 16-bit version"
+msgstr ""
+"\n"
+"MS-Windows 16 λ¿ØÖÆ̨°æ±¾"
+
+msgid ""
+"\n"
+"32-bit MS-DOS version"
+msgstr ""
+"\n"
+"32 λ MS-DOS °æ±¾"
+
+msgid ""
+"\n"
+"16-bit MS-DOS version"
+msgstr ""
+"\n"
+"16 λ MS-DOS °æ±¾"
+
+msgid ""
+"\n"
+"MacOS X (unix) version"
+msgstr ""
+"\n"
+"MacOS X (unix) °æ±¾"
+
+msgid ""
+"\n"
+"MacOS X version"
+msgstr ""
+"\n"
+"MacOS X °æ±¾"
+
+msgid ""
+"\n"
+"MacOS version"
+msgstr ""
+"\n"
+"MacOS °æ±¾"
+
+msgid ""
+"\n"
+"RISC OS version"
+msgstr ""
+"\n"
+"RISC OS °æ±¾"
+
+msgid ""
+"\n"
+"Included patches: "
+msgstr ""
+"\n"
+"°üº¬²¹¶¡: "
+
+msgid "Modified by "
+msgstr "ÐÞ¸ÄÕß "
+
+msgid ""
+"\n"
+"Compiled "
+msgstr ""
+"\n"
+"±àÒë"
+
+msgid "by "
+msgstr "Õß "
+
+msgid ""
+"\n"
+"Huge version "
+msgstr ""
+"\n"
+"¾ÞÐÍ°æ±¾ "
+
+msgid ""
+"\n"
+"Big version "
+msgstr ""
+"\n"
+"´óÐÍ°æ±¾ "
+
+msgid ""
+"\n"
+"Normal version "
+msgstr ""
+"\n"
+"Õý³£°æ±¾ "
+
+msgid ""
+"\n"
+"Small version "
+msgstr ""
+"\n"
+"СÐÍ°æ±¾ "
+
+msgid ""
+"\n"
+"Tiny version "
+msgstr ""
+"\n"
+"΢ÐÍ°æ±¾ "
+
+msgid "without GUI."
+msgstr "ÎÞͼÐνçÃæ¡£"
+
+msgid "with GTK2-GNOME GUI."
+msgstr "´ø GTK2-GNOME ͼÐνçÃæ¡£"
+
+msgid "with GTK-GNOME GUI."
+msgstr "´ø GTK-GNOME ͼÐνçÃæ¡£"
+
+msgid "with GTK2 GUI."
+msgstr "´ø GTK2 ͼÐνçÃæ¡£"
+
+msgid "with GTK GUI."
+msgstr "´ø GTK ͼÐνçÃæ¡£"
+
+msgid "with X11-Motif GUI."
+msgstr "´ø X11-Motif ͼÐνçÃæ¡£"
+
+msgid "with X11-neXtaw GUI."
+msgstr "´ø X11-neXtaw ͼÐνçÃæ¡£"
+
+msgid "with X11-Athena GUI."
+msgstr "´ø X11-Athena ͼÐνçÃæ¡£"
+
+msgid "with Photon GUI."
+msgstr "´ø Photon ͼÐνçÃæ¡£"
+
+msgid "with GUI."
+msgstr "´øͼÐνçÃæ¡£"
+
+msgid "with Carbon GUI."
+msgstr "´ø Carbon ͼÐνçÃæ¡£"
+
+msgid "with Cocoa GUI."
+msgstr "´ø Cocoa ͼÐνçÃæ¡£"
+
+msgid "with (classic) GUI."
+msgstr "´ø(´«Í³)ͼÐνçÃæ¡£"
+
+msgid " Features included (+) or not (-):\n"
+msgstr " ¿ÉʹÓÃ(+)Óë²»¿ÉʹÓÃ(-)µÄ¹¦ÄÜ:\n"
+
+msgid " system vimrc file: \""
+msgstr " ϵͳ vimrc Îļþ: \""
+
+msgid " user vimrc file: \""
+msgstr " Óû§ vimrc Îļþ: \""
+
+msgid " 2nd user vimrc file: \""
+msgstr " µÚ¶þÓû§ vimrc Îļþ: \""
+
+msgid " 3rd user vimrc file: \""
+msgstr " µÚÈýÓû§ vimrc Îļþ: \""
+
+msgid " user exrc file: \""
+msgstr " Óû§ exrc Îļþ: \""
+
+msgid " 2nd user exrc file: \""
+msgstr " µÚ¶þÓû§ exrc Îļþ: \""
+
+msgid " system gvimrc file: \""
+msgstr " ϵͳ gvimrc Îļþ: \""
+
+msgid " user gvimrc file: \""
+msgstr " Óû§ gvimrc Îļþ: \""
+
+msgid "2nd user gvimrc file: \""
+msgstr "µÚ¶þÓû§ gvimrc Îļþ: \""
+
+msgid "3rd user gvimrc file: \""
+msgstr "µÚÈýÓû§ gvimrc Îļþ: \""
+
+msgid " system menu file: \""
+msgstr " ϵͳ²Ëµ¥Îļþ: \""
+
+msgid " fall-back for $VIM: \""
+msgstr " $VIM Ô¤ÉèÖµ: \""
+
+msgid " f-b for $VIMRUNTIME: \""
+msgstr " $VIMRUNTIME Ô¤ÉèÖµ: \""
+
+msgid "Compilation: "
+msgstr "±àÒ뷽ʽ: "
+
+msgid "Compiler: "
+msgstr "±àÒëÆ÷: "
+
+msgid "Linking: "
+msgstr "Á´½Ó·½Ê½: "
+
+msgid " DEBUG BUILD"
+msgstr " µ÷ÊÔ°æ±¾"
+
+msgid "VIM - Vi IMproved"
+msgstr "VIM - Vi IMproved"
+
+msgid "version "
+msgstr "°æ±¾ "
+
+msgid "by Bram Moolenaar et al."
+msgstr "ά»¤ÈË Bram Moolenaar µÈ"
+
+msgid "Vim is open source and freely distributable"
+msgstr "Vim ÊÇ¿É×ÔÓÉ·Ö·¢µÄ¿ª·ÅÔ´´úÂëÈí¼þ"
+
+msgid "Help poor children in Uganda!"
+msgstr "°ïÖúÎڸɴïµÄ¿ÉÁ¯¶ùͯ£¡"
+
+msgid "type :help iccf<Enter> for information "
+msgstr "ÊäÈë :help iccf<Enter> ²é¿´ËµÃ÷ "
+
+msgid "type :q<Enter> to exit "
+msgstr "ÊäÈë :q<Enter> Í˳ö "
+
+msgid "type :help<Enter> or <F1> for on-line help"
+msgstr "ÊäÈë :help<Enter> »ò <F1> ²é¿´ÔÚÏß°ïÖú "
+
+msgid "type :help version8<Enter> for version info"
+msgstr "ÊäÈë :help version8<Enter> ²é¿´°æ±¾ÐÅÏ¢ "
+
+msgid "Running in Vi compatible mode"
+msgstr "ÔËÐÐÓÚ Vi ¼æÈÝģʽ"
+
+msgid "type :set nocp<Enter> for Vim defaults"
+msgstr "ÊäÈë :set nocp<Enter> »Ö¸´Ä¬È쵀 Vim "
+
+msgid "type :help cp-default<Enter> for info on this"
+msgstr "ÊäÈë :help cp-default<Enter> ²é¿´Ïà¹Ø˵Ã÷ "
+
+msgid "menu Help->Orphans for information "
+msgstr "²Ëµ¥ °ïÖú->¹Â¶ù ²é¿´ËµÃ÷ "
+
+msgid "Running modeless, typed text is inserted"
+msgstr "ÎÞģʽÔËÐУ¬ÊäÈëÎÄ×Ö¼´²åÈë"
+
+msgid "menu Edit->Global Settings->Toggle Insert Mode "
+msgstr "²Ëµ¥ ±à¼­->È«¾ÖÉ趨->¿ª/¹Ø²åÈëģʽ "
+
+#, fuzzy
+#~ msgid " for two modes "
+#~ msgstr " # pid Êý¾Ý¿âÃû³Æ prepend path\n"
+
+#~ msgid "menu Edit->Global Settings->Toggle Vi Compatible"
+#~ msgstr ""
+
+#, fuzzy
+#~ msgid " for Vim defaults "
+#~ msgstr " # pid Êý¾Ý¿âÃû³Æ prepend path\n"
+
+msgid "Sponsor Vim development!"
+msgstr "ÔÞÖú Vim µÄ¿ª·¢£¡"
+
+msgid "Become a registered Vim user!"
+msgstr "³ÉΪ Vim µÄ×¢²áÓû§£¡"
+
+msgid "type :help sponsor<Enter> for information "
+msgstr "ÊäÈë :help sponsor<Enter> ²é¿´ËµÃ÷ "
+
+msgid "type :help register<Enter> for information "
+msgstr "ÊäÈë :help register<Enter> ²é¿´ËµÃ÷ "
+
+msgid "menu Help->Sponsor/Register for information "
+msgstr "²Ëµ¥ Help->Sponsor/Register ²é¿´ËµÃ÷ "
+
+msgid "WARNING: Windows 95/98/ME detected"
+msgstr "¾¯¸æ: ¼ì²âµ½ Windows 95/98/ME"
+
+msgid "type :help windows95<Enter> for info on this"
+msgstr "ÊäÈë :help windows95<Enter> ²é¿´Ïà¹Ø˵Ã÷ "
+
+msgid "Already only one window"
+msgstr "ÒѾ­Ö»Ê£Ò»¸ö´°¿ÚÁË"
+
+msgid "E441: There is no preview window"
+msgstr "E441: ûÓÐÔ¤ÀÀ´°¿Ú"
+
+msgid "E442: Can't split topleft and botright at the same time"
+msgstr "E442: ²»ÄÜͬʱ½øÐÐ topleft ºÍ botright ·Ö¸î"
+
+msgid "E443: Cannot rotate when another window is split"
+msgstr "E443: ÓÐÆäËü·Ö¸î´°¿Úʱ²»ÄÜÐýת"
+
+msgid "E444: Cannot close last window"
+msgstr "E444: ²»ÄܹرÕ×îºóÒ»¸ö´°¿Ú"
+
+msgid "E445: Other window contains changes"
+msgstr "E445: ÆäËü´°¿ÚÓиıäµÄÄÚÈÝ"
+
+msgid "E446: No file name under cursor"
+msgstr "E446: ¹â±ê´¦Ã»ÓÐÎļþÃû"
+
+#, c-format
+msgid "E447: Can't find file \"%s\" in path"
+msgstr "E447: ÔÚ·¾¶ÖÐÕÒ²»µ½Îļþ \"%s\""
+
+#, c-format
+msgid "E370: Could not load library %s"
+msgstr "E370: ÎÞ·¨¼ÓÔØ¿â %s"
+
+msgid "Sorry, this command is disabled: the Perl library could not be loaded."
+msgstr "±§Ç¸£¬´ËÃüÁî²»¿ÉÓÃ: ÎÞ·¨¼ÓÔØ Perl ¿â¡£"
+
+#~ msgid "E299: Perl evaluation forbidden in sandbox without the Safe module"
+#~ msgstr ""
+
+msgid "Edit with &multiple Vims"
+msgstr "Óöà¸ö Vim ±à¼­(&M)"
+
+msgid "Edit with single &Vim"
+msgstr "Óõ¥¸ö Vim ±à¼­(&V)"
+
+msgid "Diff with Vim"
+msgstr "Óà Vim ±È½Ï(diff)"
+
+msgid "Edit with &Vim"
+msgstr "Óà Vim ±à¼­(&V)"
+
+#. Now concatenate
+msgid "Edit with existing Vim - "
+msgstr "Óõ±Ç°µÄ Vim ±à¼­ - "
+
+msgid "Edits the selected file(s) with Vim"
+msgstr "Óà Vim ±à¼­Ñ¡ÖеÄÎļþ"
+
+msgid "Error creating process: Check if gvim is in your path!"
+msgstr "´´½¨½ø³Ìʧ°Ü: Çë¼ì²é gvim ÊÇ·ñÔÚ·¾¶ÖУ¡"
+
+msgid "gvimext.dll error"
+msgstr "gvimext.dll ´íÎó"
+
+msgid "Path length too long!"
+msgstr "·¾¶Ì«³¤£¡"
+
+msgid "--No lines in buffer--"
+msgstr "--»º³åÇøÎÞÄÚÈÝ--"
+
+#.
+#. * The error messages that can be shared are included here.
+#. * Excluded are errors that are only used once and debugging messages.
+#.
+msgid "E470: Command aborted"
+msgstr "E470: ÃüÁî±»ÖÐÖ¹"
+
+msgid "E471: Argument required"
+msgstr "E471: ÐèÒª²ÎÊý"
+
+msgid "E10: \\ should be followed by /, ? or &"
+msgstr "E10: \\ ºóÃæÓ¦¸Ã¸úÓÐ /¡¢? »ò &"
+
+msgid "E11: Invalid in command-line window; <CR> executes, CTRL-C quits"
+msgstr "E11: ÔÚÃüÁîÐд°¿ÚÖÐÎÞЧ£»<CR> Ö´ÐУ¬CTRL-C Í˳ö"
+
+msgid "E12: Command not allowed from exrc/vimrc in current dir or tag search"
+msgstr "E12: µ±Ç°Ä¿Â¼ÖÐµÄ exrc/vimrc »ò tag ²éÕÒÖв»ÔÊÐí´ËÃüÁî"
+
+msgid "E171: Missing :endif"
+msgstr "E171: ȱÉÙ :endif"
+
+msgid "E600: Missing :endtry"
+msgstr "E600: ȱÉÙ :endtry"
+
+msgid "E170: Missing :endwhile"
+msgstr "E170: ȱÉÙ :endwhile"
+
+msgid "E170: Missing :endfor"
+msgstr "E170: ȱÉÙ :endfor"
+
+msgid "E588: :endwhile without :while"
+msgstr "E588: :endwhile ȱÉÙ¶ÔÓ¦µÄ :while"
+
+msgid "E588: :endfor without :for"
+msgstr "E588: :endfor ȱÉÙ¶ÔÓ¦µÄ :for"
+
+msgid "E13: File exists (add ! to override)"
+msgstr "E13: ÎļþÒÑ´æÔÚ (Çë¼Ó ! Ç¿ÖÆÖ´ÐÐ)"
+
+msgid "E472: Command failed"
+msgstr "E472: ÃüÁîÖ´ÐÐʧ°Ü"
+
+#, c-format
+msgid "E234: Unknown fontset: %s"
+msgstr "E234: δ֪µÄ Fontset: %s"
+
+#, c-format
+msgid "E235: Unknown font: %s"
+msgstr "E235: δ֪µÄ×ÖÌå: %s"
+
+#, c-format
+msgid "E236: Font \"%s\" is not fixed-width"
+msgstr "E236: ×ÖÌå \"%s\" ²»Êǵȿí×ÖÌå"
+
+msgid "E473: Internal error"
+msgstr "E473: ÄÚ²¿´íÎó"
+
+msgid "Interrupted"
+msgstr "ÒÑÖжÏ"
+
+msgid "E14: Invalid address"
+msgstr "E14: ÎÞЧµÄµØÖ·"
+
+msgid "E474: Invalid argument"
+msgstr "E474: ÎÞЧµÄ²ÎÊý"
+
+#, c-format
+msgid "E475: Invalid argument: %s"
+msgstr "E475: ÎÞЧµÄ²ÎÊý: %s"
+
+#, c-format
+msgid "E15: Invalid expression: %s"
+msgstr "E15: ÎÞЧµÄ±í´ïʽ: %s"
+
+msgid "E16: Invalid range"
+msgstr "E16: ÎÞЧµÄ·¶Î§"
+
+msgid "E476: Invalid command"
+msgstr "E476: ÎÞЧµÄÃüÁî"
+
+#, c-format
+msgid "E17: \"%s\" is a directory"
+msgstr "E17: \"%s\" ÊÇĿ¼"
+
+#, c-format
+msgid "E364: Library call failed for \"%s()\""
+msgstr "E364: µ÷Óú¯Êý¿â \"%s()\" ʧ°Ü"
+
+#, c-format
+msgid "E448: Could not load library function %s"
+msgstr "E448: ÎÞ·¨¼ÓÔؿ⺯Êý %s"
+
+msgid "E19: Mark has invalid line number"
+msgstr "E19: ±ê¼ÇµÄÐкÅÎÞЧ"
+
+msgid "E20: Mark not set"
+msgstr "E20: ûÓÐÉ趨±ê¼Ç"
+
+msgid "E21: Cannot make changes, 'modifiable' is off"
+msgstr "E21: ²»ÄÜÐ޸ģ¬ÒòΪѡÏî 'modifiable' ÊǹصÄ"
+
+msgid "E22: Scripts nested too deep"
+msgstr "E22: ½Å±¾Ç¶Ì×¹ýÉî"
+
+msgid "E23: No alternate file"
+msgstr "E23: ûÓн»ÌæÎļþ"
+
+msgid "E24: No such abbreviation"
+msgstr "E24: ûÓÐÕâ¸öËõд"
+
+msgid "E477: No ! allowed"
+msgstr "E477: ²»ÄÜʹÓà \"!\""
+
+msgid "E25: GUI cannot be used: Not enabled at compile time"
+msgstr "E25: ÎÞ·¨Ê¹ÓÃͼÐνçÃæ: ±àÒëʱûÓÐÆôÓÃ"
+
+msgid "E26: Hebrew cannot be used: Not enabled at compile time\n"
+msgstr "E26: ÎÞ·¨Ê¹Óà Hebrew: ±àÒëʱûÓÐÆôÓÃ\n"
+
+msgid "E27: Farsi cannot be used: Not enabled at compile time\n"
+msgstr "E27: ÎÞ·¨Ê¹Óà Farsi: ±àÒëʱûÓÐÆôÓÃ\n"
+
+msgid "E800: Arabic cannot be used: Not enabled at compile time\n"
+msgstr "E800: ÎÞ·¨Ê¹Óà Arabic: ±àÒëʱûÓÐÆôÓÃ\n"
+
+#, c-format
+msgid "E28: No such highlight group name: %s"
+msgstr "E28: ûÓÐÕâ¸ö¸ßÁÁȺ×éÃû: %s"
+
+msgid "E29: No inserted text yet"
+msgstr "E29: ûÓвåÈë¹ýÎÄ×Ö"
+
+msgid "E30: No previous command line"
+msgstr "E30: ûÓÐÇ°Ò»¸öÃüÁîÐÐ"
+
+msgid "E31: No such mapping"
+msgstr "E31: ûÓÐÕâ¸öÓ³Éä"
+
+msgid "E479: No match"
+msgstr "E479: ûÓÐÆ¥Åä"
+
+#, c-format
+msgid "E480: No match: %s"
+msgstr "E480: ûÓÐÆ¥Åä: %s"
+
+msgid "E32: No file name"
+msgstr "E32: ûÓÐÎļþÃû"
+
+msgid "E33: No previous substitute regular expression"
+msgstr "E33: ûÓÐÇ°Ò»¸öÌæ»»ÕýÔò±í´ïʽ"
+
+msgid "E34: No previous command"
+msgstr "E34: ûÓÐÇ°Ò»¸öÃüÁî"
+
+msgid "E35: No previous regular expression"
+msgstr "E35: ûÓÐÇ°Ò»¸öÕýÔò±í´ïʽ"
+
+msgid "E481: No range allowed"
+msgstr "E481: ²»ÄÜʹÓ÷¶Î§"
+
+msgid "E36: Not enough room"
+msgstr "E36: ûÓÐ×ã¹»µÄ¿Õ¼ä"
+
+#, c-format
+msgid "E247: no registered server named \"%s\""
+msgstr "E247: ûÓÐÃû½Ð \"%s\" µÄÒÑ×¢²áµÄ·þÎñÆ÷"
+
+#, c-format
+msgid "E482: Can't create file %s"
+msgstr "E482: ÎÞ·¨´´½¨Îļþ %s"
+
+msgid "E483: Can't get temp file name"
+msgstr "E483: ÎÞ·¨»ñÈ¡ÁÙʱÎļþÃû"
+
+#, c-format
+msgid "E484: Can't open file %s"
+msgstr "E484: ÎÞ·¨´ò¿ªÎļþ %s"
+
+#, c-format
+msgid "E485: Can't read file %s"
+msgstr "E485: ÎÞ·¨¶ÁÈ¡Îļþ %s"
+
+msgid "E37: No write since last change (add ! to override)"
+msgstr "E37: ÒÑÐ޸ĵ«ÉÐδ±£´æ (¿ÉÓà ! Ç¿ÖÆÖ´ÐÐ)"
+
+msgid "E38: Null argument"
+msgstr "E38: ¿ÕµÄ²ÎÊý"
+
+msgid "E39: Number expected"
+msgstr "E39: ´Ë´¦ÐèÒªÊý×Ö"
+
+#, c-format
+msgid "E40: Can't open errorfile %s"
+msgstr "E40: ÎÞ·¨´ò¿ª´íÎóÎļþ %s"
+
+msgid "E233: cannot open display"
+msgstr "E233: ÎÞ·¨´ò¿ª display"
+
+msgid "E41: Out of memory!"
+msgstr "E41: ÄÚ´æ²»×㣡"
+
+msgid "Pattern not found"
+msgstr "ÕÒ²»µ½Ä£Ê½"
+
+#, c-format
+msgid "E486: Pattern not found: %s"
+msgstr "E486: ÕÒ²»µ½Ä£Ê½: %s"
+
+msgid "E487: Argument must be positive"
+msgstr "E487: ²ÎÊý±ØÐëÊÇÕýÊý"
+
+msgid "E459: Cannot go back to previous directory"
+msgstr "E459: ÎÞ·¨»Øµ½Ç°Ò»¸öĿ¼"
+
+msgid "E42: No Errors"
+msgstr "E42: ûÓдíÎó"
+
+msgid "E776: No location list"
+msgstr "E776: ûÓÐ location Áбí"
+
+msgid "E43: Damaged match string"
+msgstr "E43: ÒÑË𻵵ÄÆ¥Åä×Ö·û´®"
+
+msgid "E44: Corrupted regexp program"
+msgstr "E44: ÒÑË𻵵ÄÕýÔò±í´ïʽ³ÌÐò"
+
+msgid "E45: 'readonly' option is set (add ! to override)"
+msgstr "E45: ÒÑÉ趨ѡÏî 'readonly' (Çë¼Ó ! Ç¿ÖÆÖ´ÐÐ)"
+
+#, c-format
+msgid "E46: Cannot change read-only variable \"%s\""
+msgstr "E46: ²»ÄܸıäÖ»¶Á±äÁ¿ \"%s\""
+
+#, c-format
+msgid "E46: Cannot set variable in the sandbox: \"%s\""
+msgstr "E46: ²»ÄÜÔÚ sandbox ÖÐÉ趨±äÁ¿: \"%s\""
+
+msgid "E47: Error while reading errorfile"
+msgstr "E47: ¶ÁÈ¡´íÎóÎļþʧ°Ü"
+
+msgid "E48: Not allowed in sandbox"
+msgstr "E48: ²»ÔÊÐíÔÚ sandbox ÖÐʹÓÃ"
+
+msgid "E523: Not allowed here"
+msgstr "E523: ²»ÔÊÐíÔÚ´ËʹÓÃ"
+
+msgid "E359: Screen mode setting not supported"
+msgstr "E359: ²»Ö§³ÖÉ趨ÆÁĻģʽ"
+
+msgid "E49: Invalid scroll size"
+msgstr "E49: ÎÞЧµÄ¹ö¶¯´óС"
+
+msgid "E91: 'shell' option is empty"
+msgstr "E91: Ñ¡Ïî 'shell' Ϊ¿Õ"
+
+msgid "E255: Couldn't read in sign data!"
+msgstr "E255: ÎÞ·¨¶ÁÈ¡ sign Êý¾Ý£¡"
+
+msgid "E72: Close error on swap file"
+msgstr "E72: ½»»»Îļþ¹Ø±Õ´íÎó"
+
+msgid "E73: tag stack empty"
+msgstr "E73: tag ¶ÑջΪ¿Õ"
+
+msgid "E74: Command too complex"
+msgstr "E74: ÃüÁî¹ý¸´ÔÓ"
+
+msgid "E75: Name too long"
+msgstr "E75: Ãû×Ö¹ý³¤"
+
+msgid "E76: Too many ["
+msgstr "E76: [ ¹ý¶à"
+
+msgid "E77: Too many file names"
+msgstr "E77: ÎļþÃû¹ý¶à"
+
+msgid "E488: Trailing characters"
+msgstr "E488: ¶àÓàµÄβ²¿×Ö·û"
+
+msgid "E78: Unknown mark"
+msgstr "E78: δ֪µÄ±ê¼Ç"
+
+msgid "E79: Cannot expand wildcards"
+msgstr "E79: ÎÞ·¨À©Õ¹Í¨Åä·û"
+
+msgid "E591: 'winheight' cannot be smaller than 'winminheight'"
+msgstr "E591: 'winheight' ²»ÄÜСÓÚ 'winminheight'"
+
+msgid "E592: 'winwidth' cannot be smaller than 'winminwidth'"
+msgstr "E592: 'winwidth' ²»ÄÜСÓÚ 'winminwidth'"
+
+msgid "E80: Error while writing"
+msgstr "E80: дÈë³ö´í"
+
+msgid "Zero count"
+msgstr "¼ÆÊýΪÁã"
+
+msgid "E81: Using <SID> not in a script context"
+msgstr "E81: Ôڽű¾»·¾³ÍâʹÓÃÁË <SID>"
+
+msgid "E449: Invalid expression received"
+msgstr "E449: ÊÕµ½ÎÞЧµÄ±í´ïʽ"
+
+#~ msgid "E463: Region is guarded, cannot modify"
+#~ msgstr ""
+
+msgid "E744: NetBeans does not allow changes in read-only files"
+msgstr "E744: NetBeans ²»ÔÊÐí¸Ä±äÖ»¶ÁÎļþ"
+
+#, c-format
+msgid "E685: Internal error: %s"
+msgstr "E685: ÄÚ²¿´íÎó: %s"
+
+msgid "E363: pattern uses more memory than 'maxmempattern'"
+msgstr "E363: ±í´ïʽµÄÄÚ´æʹÓó¬³ö 'maxmempattern'"
+
+msgid "E749: empty buffer"
+msgstr "E749: ¿ÕµÄ»º³åÇø"
+
+msgid "E682: Invalid search pattern or delimiter"
+msgstr "E682: ÎÞЧµÄËÑË÷±í´ïʽ»ò·Ö¸ô·û"
+
+msgid "E139: File is loaded in another buffer"
+msgstr "E139: ÎļþÒÑÔÚÁíÒ»¸ö»º³åÇøÖб»¼ÓÔØ"
+
+#, c-format
+msgid "E764: Option '%s' is not set"
+msgstr "E764: ûÓÐÉ趨ѡÏî '%s'"
+
+msgid "search hit TOP, continuing at BOTTOM"
+msgstr "ÒѲéÕÒµ½Îļþ¿ªÍ·£¬ÔÙ´Ó½áβ¼ÌÐø²éÕÒ"
+
+msgid "search hit BOTTOM, continuing at TOP"
+msgstr "ÒѲéÕÒµ½Îļþ½á⣬ÔÙ´Ó¿ªÍ·¼ÌÐø²éÕÒ"
+
+#~ msgid "Affix flags ignored when PFXPOSTPONE used in %s line %d: %s"
+#~ msgstr "%s µÚ %d ÐУ¬Ê¹Óà PFXPOSTPONE ʱ¸½¼Ó±êÖ¾±»ºöÂÔ: %s"
+
+#~ msgid "[No file]"
+#~ msgstr "[δÃüÃû]"
+
+#~ msgid "[Error List]"
+#~ msgstr "[´íÎóÁбí]"
+
+#~ msgid "E106: Unknown variable: \"%s\""
+#~ msgstr "E106: 䶨ÒåµÄ±äÁ¿: \"%s\""
+
+#~ msgid "E119: Not enough arguments for function: %s"
+#~ msgstr "E119: º¯Êý %s µÄ²ÎÊýÌ«ÉÙ"
+
+#~ msgid "E120: Using <SID> not in a script context: %s"
+#~ msgstr "E120: <SID> ²»ÄÜÔÚ script ÉÏÏÂÎÄÍâʹÓÃ: %s"
+
+#~ msgid "E123: Undefined function: %s"
+#~ msgstr "E123: º¯Êý %s ÉÐ䶨Òå"
+
+#~ msgid "E127: Cannot redefine function %s: It is in use"
+#~ msgstr "E127: º¯Êý %s ÕýÔÚʹÓÃÖУ¬²»ÄÜÖØж¨Òå"
+
+#~ msgid "function "
+#~ msgstr "º¯Êý "
+
+#~ msgid "E130: Undefined function: %s"
+#~ msgstr "E130: º¯Êý %s ÉÐ䶨Òå"
+
+#~ msgid "Run Macro"
+#~ msgstr "Ö´Ðкê"
+
+#~ msgid "E242: Color name not recognized: %s"
+#~ msgstr "E242: %s Ϊ²»ÄÜʶ±ðµÄÑÕÉ«Ãû³Æ"
+
+#~ msgid "error reading cscope connection %d"
+#~ msgstr "¶ÁÈ¡ cscope Á¬½Ó %d ʱ´íÎó"
+
+#~ msgid "E260: cscope connection not found"
+#~ msgstr "E260: ÕÒ²»µ½ cscope Á¬½Ó"
+
+#~ msgid "cscope connection closed"
+#~ msgstr "cscope Á¬½ÓÒѹرÕ"
+
+#~ msgid "couldn't malloc\n"
+#~ msgstr "²»ÄÜʹÓà malloc\n"
+
+#~ msgid "%2d %-5ld %-34s <none>\n"
+#~ msgstr "%2d %-5ld %-34s <ÎÞ>\n"
+
+#~ msgid "E249: couldn't read VIM instance registry property"
+#~ msgstr "E249: ²»ÄܶÁÈ¡ VIM µÄ ×¢²á±íÊôÐÔ"
+
+#~ msgid "\"\n"
+#~ msgstr "\"\n"
+
+#~ msgid "--help\t\tShow Gnome arguments"
+#~ msgstr "--help\t\tÏÔʾ Gnome Ïà¹Ø²ÎÊý"
+
+#~ msgid "[string too long]"
+#~ msgstr "[×Ö·û´®Ì«³¤]"
+
+#~ msgid "Hit ENTER to continue"
+#~ msgstr "Çë°´ ENTER ¼ÌÐø"
+
+#~ msgid " (RET/BS: line, SPACE/b: page, d/u: half page, q: quit)"
+#~ msgstr " (RET/BS: ÏòÏÂ/ÏòÉÏÒ»ÐÐ, ¿Õ¸ñ/b: Ò»Ò³, d/u: °ëÒ³, q: Í˳ö)"
+
+#~ msgid " (RET: line, SPACE: page, d: half page, q: quit)"
+#~ msgstr " (RET: ÏòÏÂÒ»ÐÐ, ¿Õ°×¼ü: Ò»Ò³, d: °ëÒ³, q: Í˳ö)"
+
+#~ msgid "E361: Crash intercepted; regexp too complex?"
+#~ msgstr "E361: ²»ÄÜÖ´ÐÐ; regular expression Ì«¸´ÔÓ?"
+
+#~ msgid "E363: pattern caused out-of-stack error"
+#~ msgstr "E363: regular expression Ôì³É¶ÑÕ»ÓùâµÄ´íÎó"
+
+#~ msgid " BLOCK"
+#~ msgstr " ¿é"
+
+#~ msgid " LINE"
+#~ msgstr " ÐÐ"
+
+#~ msgid "Enter nr of choice (<CR> to abort): "
+#~ msgstr "ÊäÈë nr »òÑ¡Ôñ (<CR> Í˳ö): "
+
+#~ msgid "Linear tag search"
+#~ msgstr "ÏßÐÔ²éÕÒ±êÇ© (Tags)"
+
+#~ msgid "Binary tag search"
+#~ msgstr "¶þ½øÖƲéÕÒ(Binary search) ±êÇ©(Tags)"
+
+#~ msgid "with BeOS GUI."
+#~ msgstr "ʹÓà BeOS ͼÐνçÃæ¡£"
diff --git a/src/po/zh_CN.po b/src/po/zh_CN.po
new file mode 100644
index 0000000..2ec047d
--- /dev/null
+++ b/src/po/zh_CN.po
@@ -0,0 +1,6140 @@
+# Chinese (simplified) Translation for Vim
+#
+# Do ":help uganda" in Vim to read copying and usage conditions.
+# Do ":help credits" in Vim to see a list of people who contributed.
+#
+# FIRST AUTHOR Wang Jun <junw@turbolinux.com.cn>
+#
+# TRANSLATORS
+# Edyfox <edyfox@gmail.com>
+# Yuheng Xie <elephant@linux.net.cn>
+#
+# Original translations.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Vim(Simplified Chinese)\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2006-04-21 15:16+0800\n"
+"PO-Revision-Date: 2006-04-21 14:00+0800\n"
+"Last-Translator: Yuheng Xie <elephant@linux.net.cn>\n"
+"Language-Team: Simplified Chinese <i18n-translation@lists.linux.net.cn>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=gb2312\n"
+"Content-Transfer-Encoding: 8-bit\n"
+
+msgid "E82: Cannot allocate any buffer, exiting..."
+msgstr "E82: ÎÞ·¨·ÖÅäÈκλº³åÇø£¬Í˳ö³ÌÐò..."
+
+msgid "E83: Cannot allocate buffer, using other one..."
+msgstr "E83: ÎÞ·¨·ÖÅ仺³åÇø£¬Ê¹ÓÃÁíÒ»¸ö»º³åÇø..."
+
+msgid "E515: No buffers were unloaded"
+msgstr "E515: ûÓÐÊÍ·ÅÈκλº³åÇø"
+
+msgid "E516: No buffers were deleted"
+msgstr "E516: ûÓÐɾ³ýÈκλº³åÇø"
+
+msgid "E517: No buffers were wiped out"
+msgstr "E517: ûÓÐÇå³ýÈκλº³åÇø"
+
+msgid "1 buffer unloaded"
+msgstr "ÊÍ·ÅÁË 1 ¸ö»º³åÇø"
+
+#, c-format
+msgid "%d buffers unloaded"
+msgstr "ÊÍ·ÅÁË %d ¸ö»º³åÇø"
+
+msgid "1 buffer deleted"
+msgstr "ɾ³ýÁË 1 ¸ö»º³åÇø"
+
+#, c-format
+msgid "%d buffers deleted"
+msgstr "ɾ³ýÁË %d ¸ö»º³åÇø"
+
+msgid "1 buffer wiped out"
+msgstr "Çå³ýÁË 1 ¸ö»º³åÇø"
+
+#, c-format
+msgid "%d buffers wiped out"
+msgstr "Çå³ýÁË %d ¸ö»º³åÇø"
+
+msgid "E84: No modified buffer found"
+msgstr "E84: ûÓÐÐ޸ĹýµÄ»º³åÇø"
+
+#. back where we started, didn't find anything.
+msgid "E85: There is no listed buffer"
+msgstr "E85: ûÓпÉÁгöµÄ»º³åÇø"
+
+#, c-format
+msgid "E86: Buffer %ld does not exist"
+msgstr "E86: »º³åÇø %ld ²»´æÔÚ"
+
+msgid "E87: Cannot go beyond last buffer"
+msgstr "E87: ÎÞ·¨Çл»£¬ÒÑÊÇ×îºóÒ»¸ö»º³åÇø"
+
+msgid "E88: Cannot go before first buffer"
+msgstr "E88: ÎÞ·¨Çл»£¬ÒÑÊǵÚÒ»¸ö»º³åÇø"
+
+#, c-format
+msgid "E89: No write since last change for buffer %ld (add ! to override)"
+msgstr "E89: »º³åÇø %ld ÒÑÐ޸ĵ«ÉÐδ±£´æ (Çë¼Ó ! Ç¿ÖÆÖ´ÐÐ)"
+
+msgid "E90: Cannot unload last buffer"
+msgstr "E90: ÎÞ·¨ÊÍ·Å×îºóÒ»¸ö»º³åÇø"
+
+msgid "W14: Warning: List of file names overflow"
+msgstr "W14: ¾¯¸æ: ÎļþÃû¹ý¶à"
+
+#, c-format
+msgid "E92: Buffer %ld not found"
+msgstr "E92: ÕÒ²»µ½»º³åÇø %ld"
+
+#, c-format
+msgid "E93: More than one match for %s"
+msgstr "E93: ÕÒµ½²»Ö¹Ò»¸ö %s"
+
+#, c-format
+msgid "E94: No matching buffer for %s"
+msgstr "E94: ûÓÐÆ¥ÅäµÄ»º³åÇø %s"
+
+#, c-format
+msgid "line %ld"
+msgstr "µÚ %ld ÐÐ"
+
+msgid "E95: Buffer with this name already exists"
+msgstr "E95: ÒÑÓлº³åÇøʹÓøÃÃû³Æ"
+
+msgid " [Modified]"
+msgstr " [ÒÑÐÞ¸Ä]"
+
+msgid "[Not edited]"
+msgstr "[δ±à¼­]"
+
+msgid "[New file]"
+msgstr "[ÐÂÎļþ]"
+
+msgid "[Read errors]"
+msgstr "[¶Á´íÎó]"
+
+msgid "[readonly]"
+msgstr "[Ö»¶Á]"
+
+#, c-format
+msgid "1 line --%d%%--"
+msgstr "1 ÐÐ --%d%%--"
+
+#, c-format
+msgid "%ld lines --%d%%--"
+msgstr "%ld ÐÐ --%d%%--"
+
+#, c-format
+msgid "line %ld of %ld --%d%%-- col "
+msgstr "ÐÐ %ld / %ld --%d%%-- ÁÐ "
+
+msgid "[No Name]"
+msgstr "[δÃüÃû]"
+
+#. must be a help buffer
+msgid "help"
+msgstr "°ïÖú"
+
+msgid "[Help]"
+msgstr "[°ïÖú]"
+
+msgid "[Preview]"
+msgstr "[Ô¤ÀÀ]"
+
+msgid "All"
+msgstr "È«²¿"
+
+msgid "Bot"
+msgstr "µ×¶Ë"
+
+msgid "Top"
+msgstr "¶¥¶Ë"
+
+#, c-format
+msgid ""
+"\n"
+"# Buffer list:\n"
+msgstr ""
+"\n"
+"# »º³åÇøÁбí:\n"
+
+msgid "[Location List]"
+msgstr "[Location Áбí]"
+
+msgid "[Quickfix List]"
+msgstr "[Quickfix Áбí]"
+
+msgid ""
+"\n"
+"--- Signs ---"
+msgstr ""
+"\n"
+"--- Signs ---"
+
+#, c-format
+msgid "Signs for %s:"
+msgstr "%s µÄ Signs:"
+
+#, c-format
+msgid " line=%ld id=%d name=%s"
+msgstr " ÐÐ=%ld id=%d Ãû³Æ=%s"
+
+#, c-format
+msgid "E96: Can not diff more than %ld buffers"
+msgstr "E96: ²»ÄܱȽÏ(diff) %ld ¸öÒÔÉϵĻº³åÇø"
+
+msgid "E97: Cannot create diffs"
+msgstr "E97: ÎÞ·¨´´½¨ diff"
+
+msgid "Patch file"
+msgstr "Patch Îļþ"
+
+msgid "E98: Cannot read diff output"
+msgstr "E98: ÎÞ·¨¶ÁÈ¡ diff µÄÊä³ö"
+
+msgid "E99: Current buffer is not in diff mode"
+msgstr "E99: µ±Ç°»º³åÇø²»ÔÚ diff ģʽ"
+
+msgid "E100: No other buffer in diff mode"
+msgstr "E100: ûÓÐÆäËü´¦ÓÚ diff ģʽµÄ»º³åÇø"
+
+msgid "E101: More than two buffers in diff mode, don't know which one to use"
+msgstr "E101: ÓÐÁ½¸öÒÔÉϵĻº³åÇø´¦ÓÚ diff ģʽ£¬²»Äܾö¶¨ÓÃÄÄÒ»¸ö"
+
+#, c-format
+msgid "E102: Can't find buffer \"%s\""
+msgstr "E102: ÕÒ²»µ½»º³åÇø \"%s\""
+
+#, c-format
+msgid "E103: Buffer \"%s\" is not in diff mode"
+msgstr "E103: »º³åÇø \"%s\" ²»ÔÚ diff ģʽ"
+
+msgid "E787: Buffer changed unexpectedly"
+msgstr "E787: ÒâÍâµØ¸Ä±äÁË»º³åÇø"
+
+msgid "E104: Escape not allowed in digraph"
+msgstr "E104: ¸´ºÏ×Ö·û(digraph)Öв»ÄÜʹÓà Escape"
+
+msgid "E544: Keymap file not found"
+msgstr "E544: ÕÒ²»µ½ Keymap Îļþ"
+
+msgid "E105: Using :loadkeymap not in a sourced file"
+msgstr "E105: ²»ÊÇÔڽű¾ÎļþÖÐʹÓà :loadkeymap "
+
+msgid " Keyword completion (^N^P)"
+msgstr " ¹Ø¼ü×Ö²¹È« (^N^P)"
+
+#. ctrl_x_mode == 0, ^P/^N compl.
+msgid " ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+msgstr " ^X ģʽ (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+
+msgid " Whole line completion (^L^N^P)"
+msgstr " ÕûÐв¹È« (^L^N^P)"
+
+msgid " File name completion (^F^N^P)"
+msgstr " ÎļþÃû²¹È« (^F^N^P)"
+
+msgid " Tag completion (^]^N^P)"
+msgstr " Tag ²¹È« (^]^N^P)"
+
+#, fuzzy
+#~ msgid " Path pattern completion (^N^P)"
+#~ msgstr " ·¾¶Ä£Ê½²¹È« (^N^P)"
+
+msgid " Definition completion (^D^N^P)"
+msgstr " ¶¨Ò岹ȫ (^D^N^P)"
+
+msgid " Dictionary completion (^K^N^P)"
+msgstr " Dictionary ²¹È« (^K^N^P)"
+
+msgid " Thesaurus completion (^T^N^P)"
+msgstr " Thesaurus ²¹È« (^T^N^P)"
+
+msgid " Command-line completion (^V^N^P)"
+msgstr " ÃüÁîÐв¹È« (^V^N^P)"
+
+msgid " User defined completion (^U^N^P)"
+msgstr " Óû§×Ô¶¨Ò岹ȫ (^U^N^P)"
+
+msgid " Omni completion (^O^N^P)"
+msgstr " È«Äܲ¹È« (^O^N^P)"
+
+msgid " Spelling suggestion (s^N^P)"
+msgstr " ƴд½¨Òé (s^N^P)"
+
+msgid " Keyword Local completion (^N^P)"
+msgstr " ¹Ø¼ü×Ö¾Ö²¿²¹È« (^N^P)"
+
+msgid "Hit end of paragraph"
+msgstr "Òѵ½¶ÎÂä½áβ"
+
+msgid "'dictionary' option is empty"
+msgstr "Ñ¡Ïî 'dictionary' Ϊ¿Õ"
+
+msgid "'thesaurus' option is empty"
+msgstr "Ñ¡Ïî 'thesaurus' Ϊ¿Õ"
+
+#, c-format
+msgid "Scanning dictionary: %s"
+msgstr "ÕýÔÚɨÃè dictionary: %s"
+
+msgid " (insert) Scroll (^E/^Y)"
+msgstr " (²åÈë) Scroll (^E/^Y)"
+
+msgid " (replace) Scroll (^E/^Y)"
+msgstr " (Ìæ»») Scroll (^E/^Y)"
+
+#, c-format
+msgid "Scanning: %s"
+msgstr "ÕýÔÚɨÃè: %s"
+
+#, c-format
+msgid "Scanning tags."
+msgstr "ɨÃè±êÇ©."
+
+msgid " Adding"
+msgstr " Ôö¼Ó"
+
+#. showmode might reset the internal line pointers, so it must
+#. * be called before line = ml_get(), or when this address is no
+#. * longer needed. -- Acevedo.
+#.
+msgid "-- Searching..."
+msgstr "-- ²éÕÒÖÐ..."
+
+msgid "Back at original"
+msgstr "»Øµ½Æðµã"
+
+msgid "Word from other line"
+msgstr "ÁíÒ»ÐеĴÊ"
+
+msgid "The only match"
+msgstr "ΨһƥÅä"
+
+#, c-format
+msgid "match %d of %d"
+msgstr "Æ¥Åä %d / %d"
+
+#, c-format
+msgid "match %d"
+msgstr "Æ¥Åä %d"
+
+msgid "E18: Unexpected characters in :let"
+msgstr "E18: :let ÖгöÏÖÒì³£×Ö·û"
+
+#, c-format
+msgid "E684: list index out of range: %ld"
+msgstr "E684: List Ë÷Òý³¬³ö·¶Î§: %ld"
+
+#, c-format
+msgid "E121: Undefined variable: %s"
+msgstr "E121: 䶨ÒåµÄ±äÁ¿: %s"
+
+msgid "E111: Missing ']'"
+msgstr "E111: ȱÉÙ ']'"
+
+#, c-format
+msgid "E686: Argument of %s must be a List"
+msgstr "E686: %s µÄ²ÎÊý±ØÐëÊÇ List"
+
+#, c-format
+msgid "E712: Argument of %s must be a List or Dictionary"
+msgstr "E712: %s µÄ²ÎÊý±ØÐëÊÇ List »òÕß Dictionary"
+
+msgid "E713: Cannot use empty key for Dictionary"
+msgstr "E713: Dictionary µÄ¼ü²»ÄÜΪ¿Õ"
+
+msgid "E714: List required"
+msgstr "E714: ÐèÒª List"
+
+msgid "E715: Dictionary required"
+msgstr "E715: ÐèÒª Dictionary"
+
+#, c-format
+msgid "E118: Too many arguments for function: %s"
+msgstr "E118: º¯ÊýµÄ²ÎÊý¹ý¶à: %s"
+
+#, c-format
+msgid "E716: Key not present in Dictionary: %s"
+msgstr "E716: Dictionary Öв»´æÔÚ¼ü: %s"
+
+#, c-format
+msgid "E122: Function %s already exists, add ! to replace it"
+msgstr "E122: º¯Êý %s ÒÑ´æÔÚ£¬Çë¼Ó ! Ç¿ÖÆÌæ»»"
+
+msgid "E717: Dictionary entry already exists"
+msgstr "E717: Dictionary ÏîÒÑ´æÔÚ"
+
+msgid "E718: Funcref required"
+msgstr "E718: ÐèÒª Funcref"
+
+msgid "E719: Cannot use [:] with a Dictionary"
+msgstr "E719: ²»ÄÜ¶Ô Dictionary ʹÓà [:]"
+
+#, c-format
+msgid "E734: Wrong variable type for %s="
+msgstr "E734: %s= µÄ±äÁ¿ÀàÐͲ»ÕýÈ·"
+
+#, c-format
+msgid "E130: Unknown function: %s"
+msgstr "E130: δ֪µÄº¯Êý: %s"
+
+#, c-format
+msgid "E461: Illegal variable name: %s"
+msgstr "E461: ÎÞЧµÄ±äÁ¿Ãû: %s"
+
+msgid "E687: Less targets than List items"
+msgstr "E687: Ä¿±ê±È List ÏîÊýÉÙ"
+
+msgid "E688: More targets than List items"
+msgstr "E688: Ä¿±ê±È List ÏîÊý¶à"
+
+msgid "Double ; in list of variables"
+msgstr "±äÁ¿ÁбíÖгöÏÖÁ½¸ö ;"
+
+#, c-format
+msgid "E738: Can't list variables for %s"
+msgstr "E738: ÎÞ·¨Áгö %s µÄ±äÁ¿"
+
+msgid "E689: Can only index a List or Dictionary"
+msgstr "E689: Ö»ÄÜË÷Òý List »ò Dictionary"
+
+msgid "E708: [:] must come last"
+msgstr "E708: [:] ±ØÐëÔÚ×îºó"
+
+msgid "E709: [:] requires a List value"
+msgstr "E709: [:] ÐèÒªÒ»¸ö List Öµ"
+
+msgid "E710: List value has more items than target"
+msgstr "E710: List ÖµµÄÏî±ÈÄ¿±ê¶à"
+
+msgid "E711: List value has not enough items"
+msgstr "E711: List ֵûÓÐ×ã¹»¶àµÄÏî"
+
+msgid "E690: Missing \"in\" after :for"
+msgstr "E690: :for ºóȱÉÙ \"in\""
+
+#, c-format
+msgid "E107: Missing parentheses: %s"
+msgstr "E107: ȱÉÙÀ¨ºÅ: %s"
+
+#, c-format
+msgid "E108: No such variable: \"%s\""
+msgstr "E108: Î޴˱äÁ¿: \"%s\""
+
+msgid "E743: variable nested too deep for (un)lock"
+msgstr "E743: (un)lock µÄ±äÁ¿Ç¶Ì×¹ýÉî"
+
+msgid "E109: Missing ':' after '?'"
+msgstr "E109: '?' ºóȱÉÙ ':'"
+
+msgid "E691: Can only compare List with List"
+msgstr "E691: Ö»ÄÜ±È½Ï List ºÍ List"
+
+msgid "E692: Invalid operation for List"
+msgstr "E692: ¶Ô List ÎÞЧµÄ²Ù×÷"
+
+msgid "E735: Can only compare Dictionary with Dictionary"
+msgstr "E735: Ö»ÄÜ±È½Ï Dictionary ºÍ Dictionary"
+
+msgid "E736: Invalid operation for Dictionary"
+msgstr "E736: ¶Ô Dictionary ÎÞЧµÄ²Ù×÷"
+
+msgid "E693: Can only compare Funcref with Funcref"
+msgstr "E693: Ö»ÄÜ±È½Ï Funcref ºÍ Funcref"
+
+msgid "E694: Invalid operation for Funcrefs"
+msgstr "E694: ¶Ô Funcrefs ÎÞЧµÄ²Ù×÷"
+
+msgid "E110: Missing ')'"
+msgstr "E110: ȱÉÙ ')'"
+
+msgid "E695: Cannot index a Funcref"
+msgstr "E695: ²»ÄÜË÷ÒýÒ»¸ö Funcref"
+
+#, c-format
+msgid "E112: Option name missing: %s"
+msgstr "E112: ȱÉÙÑ¡ÏîÃû³Æ: %s"
+
+#, c-format
+msgid "E113: Unknown option: %s"
+msgstr "E113: δ֪µÄÑ¡Ïî: %s"
+
+#, c-format
+msgid "E114: Missing quote: %s"
+msgstr "E114: ȱÉÙÒýºÅ: %s"
+
+#, c-format
+msgid "E115: Missing quote: %s"
+msgstr "E115: ȱÉÙÒýºÅ: %s"
+
+#, c-format
+msgid "E696: Missing comma in List: %s"
+msgstr "E696: List ÖÐȱÉÙ¶ººÅ: %s"
+
+#, c-format
+msgid "E697: Missing end of List ']': %s"
+msgstr "E697: List ȱÉÙ½áÊø·û ']': %s"
+
+#, c-format
+msgid "E720: Missing colon in Dictionary: %s"
+msgstr "E720: Dictionary ÖÐȱÉÙðºÅ: %s"
+
+#, c-format
+msgid "E721: Duplicate key in Dictionary: \"%s\""
+msgstr "E721: Dictionary ÖгöÏÖÖظ´µÄ¼ü: \"%s\""
+
+#, c-format
+msgid "E722: Missing comma in Dictionary: %s"
+msgstr "E722: Dictionary ÖÐȱÉÙ¶ººÅ: %s"
+
+#, c-format
+msgid "E723: Missing end of Dictionary '}': %s"
+msgstr "E723: Dictionary ȱÉÙ½áÊø·û '}': %s"
+
+msgid "E724: variable nested too deep for displaying"
+msgstr "E724: ±äÁ¿Ç¶Ì×¹ýÉîÎÞ·¨ÏÔʾ"
+
+msgid "E699: Too many arguments"
+msgstr "E699: ²ÎÊý¹ý¶à"
+
+msgid "E785: complete() can only be used in Insert mode"
+msgstr "E785: complete() Ö»ÄÜÔÚ²åÈëģʽÖÐʹÓÃ"
+
+#.
+#. * Yes this is ugly, I don't particularly like it either. But doing it
+#. * this way has the compelling advantage that translations need not to
+#. * be touched at all. See below what 'ok' and 'ync' are used for.
+#.
+msgid "&Ok"
+msgstr "È·¶¨(&O)"
+
+#, c-format
+msgid "E737: Key already exists: %s"
+msgstr "E737: ¼üÒÑ´æÔÚ: %s"
+
+#, c-format
+msgid "+-%s%3ld lines: "
+msgstr "+-%s%3ld ÐÐ: "
+
+#, c-format
+msgid "E700: Unknown function: %s"
+msgstr "E700: δ֪µÄº¯Êý: %s"
+
+msgid ""
+"&OK\n"
+"&Cancel"
+msgstr ""
+"È·¶¨(&O)\n"
+"È¡Ïû(&C)"
+
+msgid "called inputrestore() more often than inputsave()"
+msgstr "inputrestore() µÄµ÷ÓôÎÊý¶àÓÚ inputsave()"
+
+msgid "E786: Range not allowed"
+msgstr "E786: ²»ÔÊÐíµÄ·¶Î§"
+
+msgid "E701: Invalid type for len()"
+msgstr "E701: len() µÄÀàÐÍÎÞЧ"
+
+msgid "E726: Stride is zero"
+msgstr "E726: ²½³¤ÎªÁã"
+
+msgid "E727: Start past end"
+msgstr "E727: ÆðʼֵÔÚÖÕÖ¹Öµºó"
+
+msgid "<empty>"
+msgstr "<¿Õ>"
+
+msgid "E240: No connection to Vim server"
+msgstr "E240: ûÓе½ Vim ·þÎñÆ÷µÄÁ¬½Ó"
+
+#, c-format
+msgid "E241: Unable to send to %s"
+msgstr "E241: ÎÞ·¨·¢Ë͵½ %s"
+
+msgid "E277: Unable to read a server reply"
+msgstr "E277: ÎÞ·¨¶ÁÈ¡·þÎñÆ÷ÏìÓ¦"
+
+msgid "E655: Too many symbolic links (cycle?)"
+msgstr "E655: ·ûºÅÁ¬½Ó¹ý¶à(Ñ­»·£¿)"
+
+msgid "E258: Unable to send to client"
+msgstr "E258: ÎÞ·¨·¢Ë͵½¿Í»§¶Ë"
+
+msgid "E702: Sort compare function failed"
+msgstr "E702: Sort ±È½Ïº¯Êýʧ°Ü"
+
+msgid "(Invalid)"
+msgstr "(ÎÞЧ)"
+
+msgid "E677: Error writing temp file"
+msgstr "E677: дÁÙʱÎļþ³ö´í"
+
+msgid "E703: Using a Funcref as a Number"
+msgstr "E703: ½« Funcref ×÷Êý×ÖʹÓÃ"
+
+msgid "E745: Using a List as a Number"
+msgstr "E745: ½« List ×÷Êý×ÖʹÓÃ"
+
+msgid "E728: Using a Dictionary as a Number"
+msgstr "E728: ½« Dictionary ×÷Êý×ÖʹÓÃ"
+
+msgid "E729: using Funcref as a String"
+msgstr "E729: ½« Funcref ×÷ String ʹÓÃ"
+
+msgid "E730: using List as a String"
+msgstr "E730: ½« List ×÷ String ʹÓÃ"
+
+msgid "E731: using Dictionary as a String"
+msgstr "E731: ½« Dictionary ×÷ String ʹÓÃ"
+
+#, c-format
+msgid "E704: Funcref variable name must start with a capital: %s"
+msgstr "E704: Funcref ±äÁ¿Ãû±ØÐëÒÔ´óд×Öĸ¿ªÍ·: %s"
+
+#, c-format
+msgid "E705: Variable name conflicts with existing function: %s"
+msgstr "E705: ±äÁ¿ÃûÓëÒÑÓк¯ÊýÃû³åÍ»: %s"
+
+#, c-format
+msgid "E706: Variable type mismatch for: %s"
+msgstr "E706: ±äÁ¿ÀàÐͲ»Æ¥Åä: %s"
+
+#, c-format
+msgid "E741: Value is locked: %s"
+msgstr "E741: ÖµÒÑËø¶¨: %s"
+
+msgid "Unknown"
+msgstr "δ֪"
+
+#, c-format
+msgid "E742: Cannot change value of %s"
+msgstr "E742: ÎÞ·¨¸Ä±ä %s µÄÖµ"
+
+msgid "E698: variable nested too deep for making a copy"
+msgstr "E698: ±äÁ¿Ç¶Ì×¹ýÉîÎÞ·¨¸´ÖÆ"
+
+#, c-format
+msgid "E124: Missing '(': %s"
+msgstr "E124: ȱÉÙ '(': %s"
+
+#, c-format
+msgid "E125: Illegal argument: %s"
+msgstr "E125: ÎÞЧµÄ²ÎÊý: %s"
+
+msgid "E126: Missing :endfunction"
+msgstr "E126: ȱÉÙ :endfunction"
+
+#, c-format
+msgid "E746: Function name does not match script file name: %s"
+msgstr "E746: º¯ÊýÃûÓë½Å±¾ÎļþÃû²»Æ¥Åä: %s"
+
+msgid "E129: Function name required"
+msgstr "E129: ÐèÒªº¯ÊýÃû"
+
+#, c-format
+msgid "E128: Function name must start with a capital or contain a colon: %s"
+msgstr "E128: º¯ÊýÃû±ØÐëÒÔ´óд×Öĸ¿ªÍ·»òÕß°üº¬Ã°ºÅ: %s"
+
+#, c-format
+msgid "E131: Cannot delete function %s: It is in use"
+msgstr "E131: ÎÞ·¨É¾³ýº¯Êý %s: ÕýÔÚʹÓÃÖÐ"
+
+msgid "E132: Function call depth is higher than 'maxfuncdepth'"
+msgstr "E132: º¯Êýµ÷ÓÃÉî¶È³¬³ö 'maxfuncdepth'"
+
+#, c-format
+msgid "calling %s"
+msgstr "µ÷ÓÃ %s"
+
+#, c-format
+msgid "%s aborted"
+msgstr "%s ÒÑÖÐÖ¹"
+
+#, c-format
+msgid "%s returning #%ld"
+msgstr "%s ·µ»Ø #%ld "
+
+#, c-format
+msgid "%s returning %s"
+msgstr "%s ·µ»Ø %s"
+
+#, c-format
+msgid "continuing in %s"
+msgstr "ÔÚ %s ÖмÌÐø"
+
+msgid "E133: :return not inside a function"
+msgstr "E133: :return ²»ÔÚº¯ÊýÖÐ"
+
+#, c-format
+msgid ""
+"\n"
+"# global variables:\n"
+msgstr ""
+"\n"
+"# È«¾Ö±äÁ¿:\n"
+
+msgid ""
+"\n"
+"\tLast set from "
+msgstr ""
+"\n"
+"\t×î½üÐÞ¸ÄÓÚ "
+
+#, c-format
+msgid "<%s>%s%s %d, Hex %02x, Octal %03o"
+msgstr "<%s>%s%s %d, Ê®Áù½øÖÆ %02x, °Ë½øÖÆ %03o"
+
+#, c-format
+msgid "> %d, Hex %04x, Octal %o"
+msgstr "> %d, Ê®Áù½øÖÆ %04x, °Ë½øÖÆ %o"
+
+#, c-format
+msgid "> %d, Hex %08x, Octal %o"
+msgstr "> %d, Ê®Áù½øÖÆ %08x, °Ë½øÖÆ %o"
+
+msgid "E134: Move lines into themselves"
+msgstr "E134: °ÑÐÐÒƶ¯µ½×ÔÒÑÖÐ"
+
+msgid "1 line moved"
+msgstr "Òƶ¯ÁË 1 ÐÐ"
+
+#, c-format
+msgid "%ld lines moved"
+msgstr "Òƶ¯ÁË %ld ÐÐ"
+
+#, c-format
+msgid "%ld lines filtered"
+msgstr "¹ýÂËÁË %ld ÐÐ"
+
+msgid "E135: *Filter* Autocommands must not change current buffer"
+msgstr "E135: *Filter* ×Ô¶¯ÃüÁî²»¿ÉÒԸı䵱ǰ»º³åÇø"
+
+msgid "[No write since last change]\n"
+msgstr "[ÒÑÐ޸ĵ«ÉÐδ±£´æ]\n"
+
+# bad to translate
+#, c-format
+msgid "%sviminfo: %s in line: "
+msgstr "%sviminfo: %s λÓÚÐÐ: "
+
+msgid "E136: viminfo: Too many errors, skipping rest of file"
+msgstr "E136: viminfo: ´íÎó¹ý¶à£¬ºöÂÔÎļþµÄÊ£Óಿ·Ö"
+
+#, c-format
+msgid "Reading viminfo file \"%s\"%s%s%s"
+msgstr "¶ÁÈ¡ viminfo Îļþ \"%s\"%s%s%s"
+
+msgid " info"
+msgstr " ÐÅÏ¢"
+
+msgid " marks"
+msgstr " 񈬀"
+
+msgid " FAILED"
+msgstr " ʧ°Ü"
+
+#, c-format
+msgid "E137: Viminfo file is not writable: %s"
+msgstr "E137: Viminfo Îļþ²»¿ÉдÈë: %s"
+
+#, c-format
+msgid "E138: Can't write viminfo file %s!"
+msgstr "E138: ÎÞ·¨Ð´Èë viminfo Îļþ %s£¡"
+
+#, c-format
+msgid "Writing viminfo file \"%s\""
+msgstr "дÈë viminfo Îļþ \"%s\""
+
+# do not translate to avoid writing Chinese in files
+#. Write the info:
+#, fuzzy, c-format
+#~ msgid "# This viminfo file was generated by Vim %s.\n"
+#~ msgstr "# Õâ¸ö viminfo ÎļþÊÇÓÉ Vim %s Éú³ÉµÄ¡£\n"
+
+# do not translate to avoid writing Chinese in files
+#, fuzzy, c-format
+msgid ""
+"# You may edit it if you're careful!\n"
+"\n"
+msgstr ""
+"# Èç¹ûÒª×ÔÐÐÐÞ¸ÄÇëÌرðСÐÄ£¡\n"
+"\n"
+
+# do not translate to avoid writing Chinese in files
+#, fuzzy, c-format
+#~ msgid "# Value of 'encoding' when this file was written\n"
+#~ msgstr "# 'encoding' ÔÚ´ËÎļþ½¨Á¢Ê±µÄÖµ\n"
+
+msgid "Illegal starting char"
+msgstr "ÎÞЧµÄÆô¶¯×Ö·û"
+
+msgid "Save As"
+msgstr "Áí´æΪ"
+
+msgid "Write partial file?"
+msgstr "ҪдÈ벿·ÖÎļþÂð£¿"
+
+msgid "E140: Use ! to write partial buffer"
+msgstr "E140: ÇëʹÓà ! À´Ð´È벿·Ö»º³åÇø"
+
+#, c-format
+msgid "Overwrite existing file \"%s\"?"
+msgstr "¸²¸ÇÒÑ´æÔÚµÄÎļþ \"%s\" Âð£¿"
+
+#, c-format
+msgid "Swap file \"%s\" exists, overwrite anyway?"
+msgstr "½»»»Îļþ \"%s\" ÒÑ´æÔÚ£¬È·ÊµÒª¸²¸ÇÂð£¿"
+
+#, c-format
+msgid "E768: Swap file exists: %s (:silent! overrides)"
+msgstr "E768: ½»»»ÎļþÒÑ´æÔÚ: %s (:silent! Ç¿ÖÆÖ´ÐÐ)"
+
+#, c-format
+msgid "E141: No file name for buffer %ld"
+msgstr "E141: »º³åÇø %ld ûÓÐÎļþÃû"
+
+msgid "E142: File not written: Writing is disabled by 'write' option"
+msgstr "E142: ÎļþδдÈë: дÈë±» 'write' Ñ¡Ïî½ûÓÃ"
+
+#, c-format
+msgid ""
+"'readonly' option is set for \"%s\".\n"
+"Do you wish to write anyway?"
+msgstr ""
+"\"%s\" ÒÑÉ趨 'readonly' Ñ¡Ïî¡£\n"
+"ȷʵҪ¸²¸ÇÂð£¿"
+
+msgid "Edit File"
+msgstr "±à¼­Îļþ"
+
+#, c-format
+msgid "E143: Autocommands unexpectedly deleted new buffer %s"
+msgstr "E143: ×Ô¶¯ÃüÁîÒâÍâµØɾ³ýÁËлº³åÇø %s"
+
+msgid "E144: non-numeric argument to :z"
+msgstr "E144: :z ²»½ÓÊÜ·ÇÊý×ֵIJÎÊý"
+
+msgid "E145: Shell commands not allowed in rvim"
+msgstr "E145: rvim ÖнûֹʹÓà shell ÃüÁî"
+
+msgid "E146: Regular expressions can't be delimited by letters"
+msgstr "E146: ÕýÔò±í´ïʽ²»ÄÜÓÃ×Öĸ×÷·Ö½ç"
+
+#, c-format
+msgid "replace with %s (y/n/a/q/l/^E/^Y)?"
+msgstr "Ì滻Ϊ %s (y/n/a/q/l/^E/^Y)£¿"
+
+msgid "(Interrupted) "
+msgstr "(ÒÑÖжÏ) "
+
+msgid "1 match"
+msgstr "1 ¸öÆ¥Å䣬"
+
+msgid "1 substitution"
+msgstr "1 ´ÎÌæ»»£¬"
+
+#, c-format
+msgid "%ld matches"
+msgstr "%ld ¸öÆ¥Å䣬"
+
+#, c-format
+msgid "%ld substitutions"
+msgstr "%ld ´ÎÌæ»»£¬"
+
+msgid " on 1 line"
+msgstr "¹² 1 ÐÐ"
+
+#, c-format
+msgid " on %ld lines"
+msgstr "¹² %ld ÐÐ"
+
+msgid "E147: Cannot do :global recursive"
+msgstr "E147: :global ²»ÄܵݹéÖ´ÐÐ"
+
+msgid "E148: Regular expression missing from global"
+msgstr "E148: global ȱÉÙÕýÔò±í´ïʽ"
+
+#, c-format
+msgid "Pattern found in every line: %s"
+msgstr "ÿÐж¼Æ¥Åä±í´ïʽ: %s"
+
+# do not translate to avoid writing Chinese in files
+#, fuzzy, c-format
+msgid ""
+"\n"
+"# Last Substitute String:\n"
+"$"
+msgstr ""
+"\n"
+"# ×î½üµÄÌæ»»×Ö·û´®:\n"
+"$"
+
+msgid "E478: Don't panic!"
+msgstr "E478: ²»Òª»Å£¡"
+
+#, c-format
+msgid "E661: Sorry, no '%s' help for %s"
+msgstr "E661: ±§Ç¸£¬Ã»ÓÐ '%s' µÄ %s µÄ˵Ã÷"
+
+#, c-format
+msgid "E149: Sorry, no help for %s"
+msgstr "E149: ±§Ç¸£¬Ã»ÓÐ %s µÄ˵Ã÷"
+
+#, c-format
+msgid "Sorry, help file \"%s\" not found"
+msgstr "±§Ç¸£¬ÕÒ²»µ½°ïÖúÎļþ \"%s\""
+
+#, c-format
+msgid "E150: Not a directory: %s"
+msgstr "E150: ²»ÊÇĿ¼: %s"
+
+#, c-format
+msgid "E152: Cannot open %s for writing"
+msgstr "E152: ÎÞ·¨´ò¿ª²¢Ð´Èë %s"
+
+#, c-format
+msgid "E153: Unable to open %s for reading"
+msgstr "E153: ÎÞ·¨´ò¿ª²¢¶ÁÈ¡ %s"
+
+#, c-format
+msgid "E670: Mix of help file encodings within a language: %s"
+msgstr "E670: ÔÚÒ»ÖÖÓïÑÔÖлìºÏÁ˶àÖÖ°ïÖúÎļþ±àÂë: %s"
+
+#, c-format
+msgid "E154: Duplicate tag \"%s\" in file %s/%s"
+msgstr "E154: Tag \"%s\" ÔÚÎļþ %s/%s ÖÐÖظ´³öÏÖ"
+
+#, c-format
+msgid "E160: Unknown sign command: %s"
+msgstr "E160: δ֪µÄ sign ÃüÁî: %s"
+
+msgid "E156: Missing sign name"
+msgstr "E156: ȱÉÙ sign Ãû³Æ"
+
+msgid "E612: Too many signs defined"
+msgstr "E612: Signs ¶¨Òå¹ý¶à"
+
+#, c-format
+msgid "E239: Invalid sign text: %s"
+msgstr "E239: ÎÞЧµÄ sign ÎÄ×Ö: %s"
+
+#, c-format
+msgid "E155: Unknown sign: %s"
+msgstr "E155: δ֪µÄ sign: %s"
+
+msgid "E159: Missing sign number"
+msgstr "E159: ȱÉÙ sign ºÅ"
+
+#, c-format
+msgid "E158: Invalid buffer name: %s"
+msgstr "E158: ÎÞЧµÄ»º³åÇøÃû: %s"
+
+#, c-format
+msgid "E157: Invalid sign ID: %ld"
+msgstr "E157: ÎÞЧµÄ sign ID: %ld"
+
+msgid " (NOT FOUND)"
+msgstr " (ÕÒ²»µ½)"
+
+msgid " (not supported)"
+msgstr " (²»Ö§³Ö)"
+
+msgid "[Deleted]"
+msgstr "[ÒÑɾ³ý]"
+
+msgid "Entering Debug mode. Type \"cont\" to continue."
+msgstr "½øÈëµ÷ÊÔģʽ¡£ÊäÈë \"cont\" ¼ÌÐøÔËÐС£"
+
+#, c-format
+msgid "line %ld: %s"
+msgstr "µÚ %ld ÐÐ: %s"
+
+#, c-format
+msgid "cmd: %s"
+msgstr "ÃüÁî: %s"
+
+#, c-format
+msgid "Breakpoint in \"%s%s\" line %ld"
+msgstr "¶Ïµã \"%s%s\" µÚ %ld ÐÐ"
+
+#, c-format
+msgid "E161: Breakpoint not found: %s"
+msgstr "E161: ÕÒ²»µ½¶Ïµã: %s"
+
+msgid "No breakpoints defined"
+msgstr "ûÓж¨Òå¶Ïµã"
+
+#, c-format
+msgid "%3d %s %s line %ld"
+msgstr "%3d %s %s µÚ %ld ÐÐ"
+
+msgid "E750: First use :profile start <fname>"
+msgstr "E750: ÇëÏÈʹÓà :profile start <fname>"
+
+#, c-format
+msgid "Save changes to \"%s\"?"
+msgstr "½«¸Ä±ä±£´æµ½ \"%s\" Âð£¿"
+
+msgid "Untitled"
+msgstr "δÃüÃû"
+
+#, c-format
+msgid "E162: No write since last change for buffer \"%s\""
+msgstr "E162: »º³åÇø \"%s\" ÒÑÐ޸ĵ«ÉÐδ±£´æ"
+
+msgid "Warning: Entered other buffer unexpectedly (check autocommands)"
+msgstr "¾¯¸æ: ÒâÍâµØ½øÈëÁËÆäËü»º³åÇø (Çë¼ì²é×Ô¶¯ÃüÁî)"
+
+msgid "E163: There is only one file to edit"
+msgstr "E163: Ö»ÓÐÒ»¸öÎļþ¿É±à¼­"
+
+msgid "E164: Cannot go before first file"
+msgstr "E164: ÎÞ·¨Çл»£¬ÒÑÊǵÚÒ»¸öÎļþ"
+
+msgid "E165: Cannot go beyond last file"
+msgstr "E165: ÎÞ·¨Çл»£¬ÒÑÊÇ×îºóÒ»¸öÎļþ"
+
+#, c-format
+msgid "E666: compiler not supported: %s"
+msgstr "E666: ²»Ö§³Ö±àÒëÆ÷: %s"
+
+#, c-format
+msgid "Searching for \"%s\" in \"%s\""
+msgstr "ÕýÔÚ²éÕÒ \"%s\"£¬ÔÚ \"%s\" ÖÐ"
+
+#, c-format
+msgid "Searching for \"%s\""
+msgstr "ÕýÔÚ²éÕÒ \"%s\""
+
+#, c-format
+msgid "not found in 'runtimepath': \"%s\""
+msgstr "ÔÚ 'runtimepath' ÖÐÕÒ²»µ½ \"%s\""
+
+msgid "Source Vim script"
+msgstr "Ö´ÐÐ Vim ½Å±¾"
+
+#, c-format
+msgid "Cannot source a directory: \"%s\""
+msgstr "²»ÄÜÖ´ÐÐĿ¼: \"%s\""
+
+#, c-format
+msgid "could not source \"%s\""
+msgstr "²»ÄÜÖ´ÐÐ \"%s\""
+
+#, c-format
+msgid "line %ld: could not source \"%s\""
+msgstr "µÚ %ld ÐÐ: ²»ÄÜÖ´ÐÐ \"%s\""
+
+#, c-format
+msgid "sourcing \"%s\""
+msgstr "Ö´ÐÐ \"%s\""
+
+#, c-format
+msgid "line %ld: sourcing \"%s\""
+msgstr "µÚ %ld ÐÐ: Ö´ÐÐ \"%s\""
+
+#, c-format
+msgid "finished sourcing %s"
+msgstr "½áÊøÖ´ÐÐ %s"
+
+msgid "modeline"
+msgstr "modeline"
+
+msgid "--cmd argument"
+msgstr "--cmd ²ÎÊý"
+
+msgid "-c argument"
+msgstr "-c ²ÎÊý"
+
+msgid "environment variable"
+msgstr "»·¾³±äÁ¿"
+
+#~ msgid "error handler"
+#~ msgstr ""
+
+msgid "W15: Warning: Wrong line separator, ^M may be missing"
+msgstr "W15: ¾¯¸æ: ´íÎóµÄÐзָô·û£¬¿ÉÄÜÊÇÉÙÁË ^M"
+
+msgid "E167: :scriptencoding used outside of a sourced file"
+msgstr "E167: Ôڽű¾ÎļþÍâʹÓÃÁË :scriptencoding"
+
+msgid "E168: :finish used outside of a sourced file"
+msgstr "E168: Ôڽű¾ÎļþÍâʹÓÃÁË :finish"
+
+#, c-format
+msgid "Current %slanguage: \"%s\""
+msgstr "µ±Ç°µÄ %sÓïÑÔ: \"%s\""
+
+#, c-format
+msgid "E197: Cannot set language to \"%s\""
+msgstr "E197: ²»ÄÜÉ趨ÓïÑÔΪ \"%s\""
+
+msgid "Entering Ex mode. Type \"visual\" to go to Normal mode."
+msgstr "½øÈë Ex ģʽ¡£ÊäÈë \"visual\" »Øµ½Õý³£Ä£Ê½¡£"
+
+msgid "E501: At end-of-file"
+msgstr "E501: Òѵ½Îļþĩβ"
+
+msgid "E169: Command too recursive"
+msgstr "E169: ÃüÁîµÝ¹é²ãÊý¹ý¶à"
+
+#, c-format
+msgid "E605: Exception not caught: %s"
+msgstr "E605: Ò쳣ûÓб»²¶»ñ: %s"
+
+msgid "End of sourced file"
+msgstr "½Å±¾Îļþ½áÊø"
+
+msgid "End of function"
+msgstr "º¯Êý½áÊø"
+
+msgid "E464: Ambiguous use of user-defined command"
+msgstr "E464: ²»È·¶¨µÄÓû§×Ô¶¨ÒåÃüÁî"
+
+msgid "E492: Not an editor command"
+msgstr "E492: ²»ÊDZ༭Æ÷µÄÃüÁî"
+
+msgid "E493: Backwards range given"
+msgstr "E493: ʹÓÃÁËÄæÏòµÄ·¶Î§"
+
+msgid "Backwards range given, OK to swap"
+msgstr "ʹÓÃÁËÄæÏòµÄ·¶Î§£¬È·¶¨½»»»Âð"
+
+msgid "E494: Use w or w>>"
+msgstr "E494: ÇëʹÓà w »ò w>>"
+
+msgid "E319: Sorry, the command is not available in this version"
+msgstr "E319: ±§Ç¸£¬ÃüÁîÔÚ´Ë°æ±¾Öв»¿ÉÓÃ"
+
+msgid "E172: Only one file name allowed"
+msgstr "E172: Ö»ÔÊÐíÒ»¸öÎļþÃû"
+
+msgid "1 more file to edit. Quit anyway?"
+msgstr "»¹ÓÐ 1 ¸öÎļþδ±à¼­¡£È·ÊµÒªÍ˳öÂð£¿"
+
+#, c-format
+msgid "%d more files to edit. Quit anyway?"
+msgstr "»¹ÓÐ %d ¸öÎļþδ±à¼­¡£È·ÊµÒªÍ˳öÂð£¿"
+
+msgid "E173: 1 more file to edit"
+msgstr "E173: »¹ÓÐ 1 ¸öÎļþδ±à¼­"
+
+#, c-format
+msgid "E173: %ld more files to edit"
+msgstr "E173: »¹ÓÐ %ld ¸öÎļþδ±à¼­"
+
+msgid "E174: Command already exists: add ! to replace it"
+msgstr "E174: ÃüÁîÒÑ´æÔÚ: Çë¼Ó ! Ç¿ÖÆÌæ»»"
+
+msgid ""
+"\n"
+" Name Args Range Complete Definition"
+msgstr ""
+"\n"
+" Ãû³Æ ²ÎÊý ·¶Î§ ²¹È« ¶¨Òå "
+
+msgid "No user-defined commands found"
+msgstr "ÕÒ²»µ½Óû§×Ô¶¨ÒåÃüÁî"
+
+msgid "E175: No attribute specified"
+msgstr "E175: ûÓÐÖ¸¶¨ÊôÐÔ"
+
+msgid "E176: Invalid number of arguments"
+msgstr "E176: ÎÞЧµÄ²ÎÊý¸öÊý"
+
+msgid "E177: Count cannot be specified twice"
+msgstr "E177: ²»ÄÜÖ¸¶¨Á½´Î¼ÆÊý"
+
+msgid "E178: Invalid default value for count"
+msgstr "E178: ÎÞЧµÄ¼ÆÊýĬÈÏÖµ"
+
+msgid "E179: argument required for -complete"
+msgstr "E179: -complete ÐèÒª²ÎÊý"
+
+#, c-format
+msgid "E181: Invalid attribute: %s"
+msgstr "E181: ÎÞЧµÄÊôÐÔ: %s"
+
+msgid "E182: Invalid command name"
+msgstr "E182: ÎÞЧµÄÃüÁîÃû"
+
+msgid "E183: User defined commands must start with an uppercase letter"
+msgstr "E183: Óû§×Ô¶¨ÒåÃüÁî±ØÐëÒÔ´óд×Öĸ¿ªÍ·"
+
+#, c-format
+msgid "E184: No such user-defined command: %s"
+msgstr "E184: ûÓÐÕâ¸öÓû§×Ô¶¨ÒåÃüÁî: %s"
+
+#, c-format
+msgid "E180: Invalid complete value: %s"
+msgstr "E180: ÎÞЧµÄ²¹È«ÀàÐÍ: %s"
+
+msgid "E468: Completion argument only allowed for custom completion"
+msgstr "E468: Ö»ÓÐ custom ²¹È«²ÅÔÊÐí²ÎÊý"
+
+msgid "E467: Custom completion requires a function argument"
+msgstr "E467: Custom ²¹È«ÐèÒªÒ»¸öº¯Êý²ÎÊý"
+
+#, c-format
+msgid "E185: Cannot find color scheme %s"
+msgstr "E185: ÕÒ²»µ½ÅäÉ«·½°¸ %s"
+
+msgid "Greetings, Vim user!"
+msgstr "ÄúºÃ£¬Vim Óû§£¡"
+
+msgid "E784: Cannot close last tab page"
+msgstr "E784: ²»ÄܹرÕ×îºóÒ»¸ö tab Ò³"
+
+msgid "Already only one tab page"
+msgstr "ÒѾ­Ö»Ê£Ò»¸ö tab Ò³ÁË"
+
+msgid "Edit File in new window"
+msgstr "ÔÚд°¿Ú±à¼­Îļþ"
+
+#, c-format
+msgid "Tab page %d"
+msgstr "Tab Ò³ %d"
+
+msgid "No swap file"
+msgstr "ÎÞ½»»»Îļþ"
+
+msgid "Append File"
+msgstr "×·¼ÓÎļþ"
+
+msgid "E747: Cannot change directory, buffer is modified (add ! to override)"
+msgstr "E747: ²»ÄܸıäĿ¼£¬»º³åÇøÒÑÐÞ¸Ä (Çë¼Ó ! Ç¿ÖÆÖ´ÐÐ)"
+
+msgid "E186: No previous directory"
+msgstr "E186: Ç°Ò»¸öĿ¼²»´æÔÚ"
+
+msgid "E187: Unknown"
+msgstr "E187: δ֪"
+
+msgid "E465: :winsize requires two number arguments"
+msgstr "E465: :winsize ÐèÒªÁ½¸öÊý×Ö²ÎÊý"
+
+#, c-format
+msgid "Window position: X %d, Y %d"
+msgstr "´°¿ÚλÖÃ: X %d, Y %d"
+
+msgid "E188: Obtaining window position not implemented for this platform"
+msgstr "E188: ÔÚ´Ëƽ̨Éϲ»ÄÜ»ñµÃ´°¿ÚλÖÃ"
+
+msgid "E466: :winpos requires two number arguments"
+msgstr "E466: :winpos ÐèÒªÁ½¸öÊý×Ö²ÎÊý"
+
+msgid "Save Redirection"
+msgstr "±£´æÖض¨Ïò"
+
+msgid "Save View"
+msgstr "±£´æÊÓͼ"
+
+msgid "Save Session"
+msgstr "±£´æ»á»°"
+
+msgid "Save Setup"
+msgstr "±£´æÉ趨"
+
+#, c-format
+msgid "E739: Cannot create directory: %s"
+msgstr "E739: ÎÞ·¨´´½¨Ä¿Â¼: %s"
+
+#, c-format
+msgid "E189: \"%s\" exists (add ! to override)"
+msgstr "E189: \"%s\" ÒÑ´æÔÚ (Çë¼Ó ! Ç¿ÖÆÖ´ÐÐ)"
+
+#, c-format
+msgid "E190: Cannot open \"%s\" for writing"
+msgstr "E190: ÎÞ·¨´ò¿ª²¢Ð´Èë \"%s\""
+
+#. set mark
+msgid "E191: Argument must be a letter or forward/backward quote"
+msgstr "E191: ²ÎÊý±ØÐëÊÇÒ»¸ö×Öĸ»òÕßÕý/·´ÒýºÅ"
+
+msgid "E192: Recursive use of :normal too deep"
+msgstr "E192: :normal µÝ¹é²ãÊý¹ýÉî"
+
+msgid "E194: No alternate file name to substitute for '#'"
+msgstr "E194: ûÓÐÓÃÓÚÌæ»» '#' µÄ½»ÌæÎļþÃû"
+
+msgid "E495: no autocommand file name to substitute for \"<afile>\""
+msgstr "E495: ûÓÐÓÃÓÚÌæ»» \"<afile>\" µÄ×Ô¶¯ÃüÁîÎļþÃû"
+
+msgid "E496: no autocommand buffer number to substitute for \"<abuf>\""
+msgstr "E496: ûÓÐÓÃÓÚÌæ»» \"<abuf>\" µÄ×Ô¶¯ÃüÁ³åÇøºÅ"
+
+msgid "E497: no autocommand match name to substitute for \"<amatch>\""
+msgstr "E497: ûÓÐÓÃÓÚÌæ»» \"<amatch>\" µÄ×Ô¶¯ÃüÁîÆ¥ÅäÃû"
+
+msgid "E498: no :source file name to substitute for \"<sfile>\""
+msgstr "E498: ûÓÐÓÃÓÚÌæ»» \"<sfile>\" µÄ :source ÎļþÃû"
+
+#, no-c-format
+msgid "E499: Empty file name for '%' or '#', only works with \":p:h\""
+msgstr "E499: '%' »ò '#' Ϊ¿ÕÎļþÃû£¬Ö»ÄÜÓÃÓÚ \":p:h\""
+
+msgid "E500: Evaluates to an empty string"
+msgstr "E500: ½á¹ûΪ¿Õ×Ö·û´®"
+
+msgid "E195: Cannot open viminfo file for reading"
+msgstr "E195: ÎÞ·¨´ò¿ª²¢¶ÁÈ¡ viminfo Îļþ"
+
+msgid "E196: No digraphs in this version"
+msgstr "E196: ´Ë°æ±¾ÎÞ¸´ºÏ×Ö·û(digraph)"
+
+msgid "E608: Cannot :throw exceptions with 'Vim' prefix"
+msgstr "E608: ²»ÄÜ :throw ǰ׺Ϊ 'Vim' µÄÒì³£"
+
+#. always scroll up, don't overwrite
+#, c-format
+msgid "Exception thrown: %s"
+msgstr "Å׳öÒì³£: %s"
+
+#, c-format
+msgid "Exception finished: %s"
+msgstr "Íê³ÉÒì³£: %s"
+
+#, c-format
+msgid "Exception discarded: %s"
+msgstr "¶ªÆúÒì³£: %s"
+
+#, c-format
+msgid "%s, line %ld"
+msgstr "%s£¬µÚ %ld ÐÐ"
+
+#. always scroll up, don't overwrite
+#, c-format
+msgid "Exception caught: %s"
+msgstr "²¶»ñÒì³£: %s"
+
+#, c-format
+#~ msgid "%s made pending"
+#~ msgstr ""
+
+#, fuzzy, c-format
+#~ msgid "%s resumed"
+#~ msgstr " ÒÑ·µ»Ø\n"
+
+#, c-format
+#~ msgid "%s discarded"
+#~ msgstr ""
+
+msgid "Exception"
+msgstr "Òì³£"
+
+msgid "Error and interrupt"
+msgstr "´íÎóºÍÖжÏ"
+
+msgid "Error"
+msgstr "´íÎó"
+
+#. if (pending & CSTP_INTERRUPT)
+msgid "Interrupt"
+msgstr "ÖжÏ"
+
+msgid "E579: :if nesting too deep"
+msgstr "E579: :if ǶÌײãÊý¹ýÉî"
+
+msgid "E580: :endif without :if"
+msgstr "E580: :endif ȱÉÙ¶ÔÓ¦µÄ :if"
+
+msgid "E581: :else without :if"
+msgstr "E581: :else ȱÉÙ¶ÔÓ¦µÄ :if"
+
+msgid "E582: :elseif without :if"
+msgstr "E582: :elseif ȱÉÙ¶ÔÓ¦µÄ :if"
+
+msgid "E583: multiple :else"
+msgstr "E583: ¶à¸ö :else"
+
+msgid "E584: :elseif after :else"
+msgstr "E584: :elseif ÔÚ :else ºóÃæ"
+
+msgid "E585: :while/:for nesting too deep"
+msgstr "E585: :while/:for ǶÌײãÊý¹ýÉî"
+
+msgid "E586: :continue without :while or :for"
+msgstr "E586: :continue ȱÉÙ¶ÔÓ¦µÄ :while »ò :for"
+
+msgid "E587: :break without :while or :for"
+msgstr "E587: :break ȱÉÙ¶ÔÓ¦µÄ :while »ò :for"
+
+msgid "E732: Using :endfor with :while"
+msgstr "E732: :while ÒÔ :endfor ½áβ"
+
+msgid "E733: Using :endwhile with :for"
+msgstr "E733: :for ÒÔ :endwhile ½áβ"
+
+msgid "E601: :try nesting too deep"
+msgstr "E601: :try ǶÌײãÊý¹ýÉî"
+
+msgid "E603: :catch without :try"
+msgstr "E603: :catch ȱÉÙ¶ÔÓ¦µÄ :try"
+
+#. Give up for a ":catch" after ":finally" and ignore it.
+#. * Just parse.
+msgid "E604: :catch after :finally"
+msgstr "E604: :catch ÔÚ :finally ºóÃæ"
+
+msgid "E606: :finally without :try"
+msgstr "E606: :finally ȱÉÙ¶ÔÓ¦µÄ :try"
+
+#. Give up for a multiple ":finally" and ignore it.
+msgid "E607: multiple :finally"
+msgstr "E607: ¶à¸ö :finally"
+
+msgid "E602: :endtry without :try"
+msgstr "E602: :endtry ȱÉÙ¶ÔÓ¦µÄ :try"
+
+msgid "E193: :endfunction not inside a function"
+msgstr "E193: :endfunction ²»ÔÚº¯ÊýÄÚ"
+
+msgid "E788: Not allowed to edit another buffer now"
+msgstr "E788: Ä¿Ç°²»ÔÊÐí±à¼­±ðµÄ»º³åÇø"
+
+msgid "tagname"
+msgstr "tag Ãû"
+
+msgid " kind file\n"
+msgstr " ÀàÐÍ Îļþ\n"
+
+msgid "'history' option is zero"
+msgstr "Ñ¡Ïî 'history' ΪÁã"
+
+# do not translate to avoid writing Chinese in files
+#, fuzzy, c-format
+msgid ""
+"\n"
+"# %s History (newest to oldest):\n"
+msgstr ""
+"\n"
+"# %s ÀúÊ·¼Ç¼ (´Óе½¾É):\n"
+
+# do not translate to avoid writing Chinese in files
+#, fuzzy
+#~ msgid "Command Line"
+#~ msgstr "ÃüÁîÐÐ"
+
+# do not translate to avoid writing Chinese in files
+#, fuzzy
+#~ msgid "Search String"
+#~ msgstr "²éÕÒ×Ö·û´®"
+
+# do not translate to avoid writing Chinese in files
+#, fuzzy
+#~ msgid "Expression"
+#~ msgstr "±í´ïʽ"
+
+# do not translate to avoid writing Chinese in files
+#, fuzzy
+#~ msgid "Input Line"
+#~ msgstr "ÊäÈëÐÐ"
+
+msgid "E198: cmd_pchar beyond the command length"
+msgstr "E198: cmd_pchar ³¬¹ýÃüÁ¶È"
+
+msgid "E199: Active window or buffer deleted"
+msgstr "E199: »î¶¯´°¿Ú»ò»º³åÇøÒѱ»É¾³ý"
+
+msgid "Illegal file name"
+msgstr "ÎÞЧµÄÎļþÃû"
+
+msgid "is a directory"
+msgstr "ÊÇĿ¼"
+
+msgid "is not a file"
+msgstr "²»ÊÇÎļþ"
+
+msgid "[New File]"
+msgstr "[ÐÂÎļþ]"
+
+msgid "[New DIRECTORY]"
+msgstr "[ÐÂĿ¼]"
+
+msgid "[File too big]"
+msgstr "[Îļþ¹ý´ó]"
+
+msgid "[Permission Denied]"
+msgstr "[ȨÏÞ²»×ã]"
+
+msgid "E200: *ReadPre autocommands made the file unreadable"
+msgstr "E200: *ReadPre ×Ô¶¯ÃüÁîµ¼ÖÂÎļþ²»¿É¶Á"
+
+msgid "E201: *ReadPre autocommands must not change current buffer"
+msgstr "E201: *ReadPre ×Ô¶¯ÃüÁî²»ÔÊÐí¸Ä±äµ±Ç°»º³åÇø"
+
+msgid "Vim: Reading from stdin...\n"
+msgstr "Vim: ´Ó±ê×¼ÊäÈë¶ÁÈ¡...\n"
+
+msgid "Reading from stdin..."
+msgstr "´Ó±ê×¼ÊäÈë¶ÁÈ¡..."
+
+#. Re-opening the original file failed!
+msgid "E202: Conversion made file unreadable!"
+msgstr "E202: ת»»µ¼ÖÂÎļþ²»¿É¶Á"
+
+msgid "[fifo/socket]"
+msgstr "[fifo/socket]"
+
+msgid "[fifo]"
+msgstr "[fifo]"
+
+msgid "[socket]"
+msgstr "[socket]"
+
+msgid "[RO]"
+msgstr "[Ö»¶Á]"
+
+msgid "[CR missing]"
+msgstr "[ȱÉÙ CR]'"
+
+msgid "[NL found]"
+msgstr "[ÕÒµ½ NL]"
+
+msgid "[long lines split]"
+msgstr "[³¤Ðзָî]"
+
+msgid "[NOT converted]"
+msgstr "[δת»»]"
+
+msgid "[converted]"
+msgstr "[ÒÑת»»]"
+
+msgid "[crypted]"
+msgstr "[ÒѼÓÃÜ]"
+
+#, c-format
+msgid "[CONVERSION ERROR in line %ld]"
+msgstr "[µÚ %ld ÐÐת»»´íÎó]"
+
+#, c-format
+msgid "[ILLEGAL BYTE in line %ld]"
+msgstr "[µÚ %ld ÐÐÎÞЧ×Ö·û]"
+
+msgid "[READ ERRORS]"
+msgstr "[¶Á´íÎó]"
+
+msgid "Can't find temp file for conversion"
+msgstr "ÕÒ²»µ½ÓÃÓÚת»»µÄÁÙʱÎļþ"
+
+msgid "Conversion with 'charconvert' failed"
+msgstr "'charconvert' ת»»Ê§°Ü"
+
+msgid "can't read output of 'charconvert'"
+msgstr "ÎÞ·¨¶ÁÈ¡ 'charconvert' µÄÊä³ö"
+
+msgid "E676: No matching autocommands for acwrite buffer"
+msgstr "E676: ÕÒ²»µ½ acwrite »º³åÇø¶ÔÓ¦µÄ×Ô¶¯ÃüÁî"
+
+msgid "E203: Autocommands deleted or unloaded buffer to be written"
+msgstr "E203: ×Ô¶¯ÃüÁîɾ³ý»òÊÍ·ÅÁËҪдÈëµÄ»º³åÇø"
+
+msgid "E204: Autocommand changed number of lines in unexpected way"
+msgstr "E204: ×Ô¶¯ÃüÁîÒâÍâµØ¸Ä±äÁËÐÐÊý"
+
+msgid "NetBeans disallows writes of unmodified buffers"
+msgstr "NetBeans ²»ÔÊÐíδÐ޸ĵĻº³åÇøдÈë"
+
+msgid "Partial writes disallowed for NetBeans buffers"
+msgstr "NetBeans ²»ÔÊÐí»º³åÇø²¿·ÖдÈë"
+
+msgid "is not a file or writable device"
+msgstr "²»ÊÇÎļþ»ò¿ÉдµÄÉ豸"
+
+msgid "is read-only (add ! to override)"
+msgstr "Ö»¶Á (Çë¼Ó ! Ç¿ÖÆÖ´ÐÐ)"
+
+msgid "E506: Can't write to backup file (add ! to override)"
+msgstr "E506: ÎÞ·¨Ð´È뱸·ÝÎļþ (Çë¼Ó ! Ç¿ÖÆÖ´ÐÐ)"
+
+msgid "E507: Close error for backup file (add ! to override)"
+msgstr "E507: ¹Ø±Õ±¸·ÝÎļþ³ö´í (Çë¼Ó ! Ç¿ÖÆÖ´ÐÐ)"
+
+msgid "E508: Can't read file for backup (add ! to override)"
+msgstr "E508: ÎÞ·¨¶ÁÈ¡ÎļþÒÔ¹©±¸·Ý (Çë¼Ó ! Ç¿ÖÆÖ´ÐÐ)"
+
+msgid "E509: Cannot create backup file (add ! to override)"
+msgstr "E509: ÎÞ·¨´´½¨±¸·ÝÎļþ (Çë¼Ó ! Ç¿ÖÆÖ´ÐÐ)"
+
+msgid "E510: Can't make backup file (add ! to override)"
+msgstr "E510: ÎÞ·¨Éú³É±¸·ÝÎļþ (Çë¼Ó ! Ç¿ÖÆÖ´ÐÐ)"
+
+msgid "E460: The resource fork would be lost (add ! to override)"
+msgstr "E460: Resource fork »á¶ªÊ§ (Çë¼Ó ! Ç¿ÖÆÖ´ÐÐ)"
+
+msgid "E214: Can't find temp file for writing"
+msgstr "E214: ÕÒ²»µ½ÓÃÓÚдÈëµÄÁÙʱÎļþ"
+
+msgid "E213: Cannot convert (add ! to write without conversion)"
+msgstr "E213: ÎÞ·¨×ª»» (Çë¼Ó ! Ç¿ÖƲ»×ª»»Ð´Èë)"
+
+msgid "E166: Can't open linked file for writing"
+msgstr "E166: ÎÞ·¨´ò¿ª²¢Ð´ÈëÁ´½ÓÎļþ"
+
+msgid "E212: Can't open file for writing"
+msgstr "E212: ÎÞ·¨´ò¿ª²¢Ð´ÈëÎļþ"
+
+msgid "E667: Fsync failed"
+msgstr "E667: ͬ²½Ê§°Ü"
+
+msgid "E512: Close failed"
+msgstr "E512: ¹Ø±Õʧ°Ü"
+
+msgid "E513: write error, conversion failed (make 'fenc' empty to override)"
+msgstr "E513: дÈë´íÎó£¬×ª»»Ê§°Ü (Ç뽫 'fenc' ÖÿÕÒÔÇ¿ÖÆÖ´ÐÐ)"
+
+msgid "E514: write error (file system full?)"
+msgstr "E514: дÈë´íÎó (ÎļþϵͳÒÑÂú£¿)"
+
+msgid " CONVERSION ERROR"
+msgstr " ת»»´íÎó"
+
+msgid "[Device]"
+msgstr "[É豸]"
+
+msgid "[New]"
+msgstr "[ÐÂ]"
+
+msgid " [a]"
+msgstr " [a]"
+
+msgid " appended"
+msgstr " ÒÑ×·¼Ó"
+
+msgid " [w]"
+msgstr " [w]"
+
+msgid " written"
+msgstr " ÒÑдÈë"
+
+msgid "E205: Patchmode: can't save original file"
+msgstr "E205: Patchmode: ÎÞ·¨±£´æԭʼÎļþ"
+
+msgid "E206: patchmode: can't touch empty original file"
+msgstr "E206: Patchmode: ÎÞ·¨Éú³É¿ÕµÄԭʼÎļþ"
+
+msgid "E207: Can't delete backup file"
+msgstr "E207: ÎÞ·¨É¾³ý±¸·ÝÎļþ"
+
+msgid ""
+"\n"
+"WARNING: Original file may be lost or damaged\n"
+msgstr ""
+"\n"
+"¾¯¸æ: ԭʼÎļþ¿ÉÄÜÒѶªÊ§»òËð»µ\n"
+
+msgid "don't quit the editor until the file is successfully written!"
+msgstr "ÔÚÎļþÕýȷдÈëÇ°ÇëÎðÍ˳ö±à¼­Æ÷£¡"
+
+msgid "[dos]"
+msgstr "[dos]"
+
+msgid "[dos format]"
+msgstr "[dos ¸ñʽ]"
+
+msgid "[mac]"
+msgstr "[mac]"
+
+msgid "[mac format]"
+msgstr "[mac ¸ñʽ]"
+
+msgid "[unix]"
+msgstr "[unix]"
+
+msgid "[unix format]"
+msgstr "[unix ¸ñʽ]"
+
+msgid "1 line, "
+msgstr "1 ÐУ¬"
+
+#, c-format
+msgid "%ld lines, "
+msgstr "%ld ÐУ¬"
+
+msgid "1 character"
+msgstr "1 ¸ö×Ö·û"
+
+#, c-format
+msgid "%ld characters"
+msgstr "%ld ¸ö×Ö·û"
+
+msgid "[noeol]"
+msgstr "[noeol]"
+
+msgid "[Incomplete last line]"
+msgstr "[×îºóÒ»Ðв»ÍêÕû]"
+
+#. don't overwrite messages here
+#. must give this prompt
+#. don't use emsg() here, don't want to flush the buffers
+msgid "WARNING: The file has been changed since reading it!!!"
+msgstr "¾¯¸æ: ´ËÎļþ×Ô¶ÁÈëºóÒÑ·¢Éú±ä¶¯£¡£¡£¡"
+
+msgid "Do you really want to write to it"
+msgstr "ȷʵҪдÈëÂð"
+
+#, c-format
+msgid "E208: Error writing to \"%s\""
+msgstr "E208: дÈëÎļþ \"%s\" ³ö´í"
+
+#, c-format
+msgid "E209: Error closing \"%s\""
+msgstr "E209: ¹Ø±ÕÎļþ \"%s\" ³ö´í"
+
+#, c-format
+msgid "E210: Error reading \"%s\""
+msgstr "E210: ¶ÁÈ¡Îļþ \"%s\" ³ö´í"
+
+msgid "E246: FileChangedShell autocommand deleted buffer"
+msgstr "E246: FileChangedShell ×Ô¶¯ÃüÁîɾ³ýÁË»º³åÇø"
+
+#, c-format
+msgid "E211: File \"%s\" no longer available"
+msgstr "E211: Îļþ \"%s\" ÒѾ­²»´æÔÚ"
+
+#, c-format
+msgid ""
+"W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as "
+"well"
+msgstr "W12: ¾¯¸æ: Îļþ \"%s\" Òѱ䶯£¬²¢ÇÒÔÚ Vim ÖеĻº³åÇøÒ²Òѱ䶯"
+
+msgid "See \":help W12\" for more info."
+msgstr "½øÒ»²½ËµÃ÷Çë¼û \":help W12\""
+
+#, c-format
+msgid "W11: Warning: File \"%s\" has changed since editing started"
+msgstr "W11: ¾¯¸æ: ±à¼­¿ªÊ¼ºó£¬Îļþ \"%s\" Òѱ䶯"
+
+msgid "See \":help W11\" for more info."
+msgstr "½øÒ»²½ËµÃ÷Çë¼û \":help W11\""
+
+#, c-format
+msgid "W16: Warning: Mode of file \"%s\" has changed since editing started"
+msgstr "W16: ¾¯¸æ: ±à¼­¿ªÊ¼ºó£¬Îļþ \"%s\" µÄģʽÒѱ䶯"
+
+msgid "See \":help W16\" for more info."
+msgstr "½øÒ»²½ËµÃ÷Çë¼û \":help W16\""
+
+#, c-format
+msgid "W13: Warning: File \"%s\" has been created after editing started"
+msgstr "W13: ¾¯¸æ: ±à¼­¿ªÊ¼ºó£¬Îļþ \"%s\" Òѱ»´´½¨"
+
+msgid "Warning"
+msgstr "¾¯¸æ"
+
+msgid ""
+"&OK\n"
+"&Load File"
+msgstr ""
+"È·¶¨(&O)\n"
+"¼ÓÔØÎļþ(&L)"
+
+#, c-format
+msgid "E462: Could not prepare for reloading \"%s\""
+msgstr "E462: ÎÞ·¨ÎªÖØмÓÔØ \"%s\" ×ö×¼±¸"
+
+#, c-format
+msgid "E321: Could not reload \"%s\""
+msgstr "E321: ÎÞ·¨ÖØмÓÔØ \"%s\""
+
+msgid "--Deleted--"
+msgstr "--ÒÑɾ³ý--"
+
+#, c-format
+#~ msgid "auto-removing autocommand: %s <buffer=%d>"
+#~ msgstr ""
+
+#. the group doesn't exist
+#, c-format
+msgid "E367: No such group: \"%s\""
+msgstr "E367: ÎÞ´Ë×é: \"%s\""
+
+#, c-format
+msgid "E215: Illegal character after *: %s"
+msgstr "E215: * ºóÃæÓÐÎÞЧ×Ö·û: %s"
+
+#, c-format
+msgid "E216: No such event: %s"
+msgstr "E216: ÎÞ´Ëʼþ: %s"
+
+#, c-format
+msgid "E216: No such group or event: %s"
+msgstr "E216: ÎÞ´Ë×é»òʼþ: %s"
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Autocommands ---"
+msgstr ""
+"\n"
+"--- ×Ô¶¯ÃüÁî ---"
+
+#, c-format
+msgid "E680: <buffer=%d>: invalid buffer number "
+msgstr "E680: <buffer=%d>: ÎÞЧµÄ»º³åÇøºÅ "
+
+msgid "E217: Can't execute autocommands for ALL events"
+msgstr "E217: ²»ÄܶÔËùÓÐʼþÖ´ÐÐ×Ô¶¯ÃüÁî"
+
+msgid "No matching autocommands"
+msgstr "ûÓÐÆ¥ÅäµÄ×Ô¶¯ÃüÁî"
+
+msgid "E218: autocommand nesting too deep"
+msgstr "E218: ×Ô¶¯ÃüÁîǶÌײãÊý¹ýÉî"
+
+#, c-format
+msgid "%s Autocommands for \"%s\""
+msgstr "%s ×Ô¶¯ÃüÁî \"%s\""
+
+#, c-format
+msgid "Executing %s"
+msgstr "Ö´ÐÐ %s"
+
+#, c-format
+msgid "autocommand %s"
+msgstr "×Ô¶¯ÃüÁî %s"
+
+msgid "E219: Missing {."
+msgstr "E219: ȱÉÙ {¡£"
+
+msgid "E220: Missing }."
+msgstr "E220: ȱÉÙ }¡£"
+
+msgid "E490: No fold found"
+msgstr "E490: ÕÒ²»µ½ÕÛµþ"
+
+msgid "E350: Cannot create fold with current 'foldmethod'"
+msgstr "E350: ²»ÄÜÔÚµ±Ç°µÄ 'foldmethod' Ï´´½¨ÕÛµþ"
+
+msgid "E351: Cannot delete fold with current 'foldmethod'"
+msgstr "E351: ²»ÄÜÔÚµ±Ç°µÄ 'foldmethod' ÏÂɾ³ýÕÛµþ"
+
+#, c-format
+msgid "+--%3ld lines folded "
+msgstr "+--ÒÑÕÛµþ %3ld ÐÐ"
+
+msgid "E222: Add to read buffer"
+msgstr "E222: Ìí¼Óµ½ÒѶÁ»º³åÇøÖÐ"
+
+msgid "E223: recursive mapping"
+msgstr "E223: µÝ¹éÓ³Éä"
+
+#, c-format
+msgid "E224: global abbreviation already exists for %s"
+msgstr "E224: È«¾ÖËõд %s ÒÑ´æÔÚ"
+
+#, c-format
+msgid "E225: global mapping already exists for %s"
+msgstr "E225: È«¾ÖÓ³Éä %s ÒÑ´æÔÚ"
+
+#, c-format
+msgid "E226: abbreviation already exists for %s"
+msgstr "E226: Ëõд %s ÒÑ´æÔÚ"
+
+#, c-format
+msgid "E227: mapping already exists for %s"
+msgstr "E227: Ó³Éä %s ÒÑ´æÔÚ"
+
+msgid "No abbreviation found"
+msgstr "ÕÒ²»µ½Ëõд"
+
+msgid "No mapping found"
+msgstr "ÕÒ²»µ½Ó³Éä"
+
+msgid "E228: makemap: Illegal mode"
+msgstr "E228: makemap: ÎÞЧµÄģʽ"
+
+msgid "E229: Cannot start the GUI"
+msgstr "E229: ÎÞ·¨Æô¶¯Í¼ÐνçÃæ"
+
+#, c-format
+msgid "E230: Cannot read from \"%s\""
+msgstr "E230: ÎÞ·¨¶ÁÈ¡Îļþ \"%s\""
+
+msgid "E665: Cannot start GUI, no valid font found"
+msgstr "E665: ÎÞ·¨Æô¶¯Í¼ÐνçÃ棬ÕÒ²»µ½ÓÐЧµÄ×ÖÌå"
+
+msgid "E231: 'guifontwide' invalid"
+msgstr "E231: ÎÞЧµÄ 'guifontwide'"
+
+msgid "E599: Value of 'imactivatekey' is invalid"
+msgstr "E599: 'imactivatekey' µÄÖµÎÞЧ"
+
+#, c-format
+msgid "E254: Cannot allocate color %s"
+msgstr "E254: ÎÞ·¨·ÖÅäÑÕÉ« %s"
+
+msgid "No match at cursor, finding next"
+msgstr "ÔÚ¹â±ê´¦Ã»ÓÐÆ¥Å䣬²éÕÒÏÂÒ»¸ö"
+
+msgid "<cannot open> "
+msgstr "<ÎÞ·¨´ò¿ª>"
+
+#, c-format
+msgid "E616: vim_SelFile: can't get font %s"
+msgstr "E616: vim_SelFile: ÎÞ·¨»ñÈ¡×ÖÌå %s"
+
+msgid "E614: vim_SelFile: can't return to current directory"
+msgstr "E614: vim_SelFile: ÎÞ·¨·µ»Øµ±Ç°Ä¿Â¼"
+
+msgid "Pathname:"
+msgstr "·¾¶:"
+
+msgid "E615: vim_SelFile: can't get current directory"
+msgstr "E615: vim_SelFile: ÎÞ·¨»ñÈ¡µ±Ç°Ä¿Â¼"
+
+msgid "OK"
+msgstr "È·¶¨"
+
+msgid "Cancel"
+msgstr "È¡Ïû"
+
+msgid "Scrollbar Widget: Could not get geometry of thumb pixmap."
+msgstr "¹ö¶¯Ìõ²¿¼þ: ÎÞ·¨»ñÈ¡»¬¿éͼÏñµÄ¼¸ºÎ´óС"
+
+msgid "Vim dialog"
+msgstr "Vim ¶Ô»°¿ò"
+
+msgid "E232: Cannot create BalloonEval with both message and callback"
+msgstr "E232: ²»ÄÜͬʱʹÓÃÏûÏ¢ºÍ»Øµ÷º¯ÊýÀ´´´½¨ BalloonEval"
+
+msgid "Vim dialog..."
+msgstr "Vim ¶Ô»°¿ò..."
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"&Cancel"
+msgstr ""
+"ÊÇ(&Y)\n"
+"·ñ(&N)\n"
+"È¡Ïû(&C)"
+
+msgid "Input _Methods"
+msgstr "ÊäÈë·¨(_M)"
+
+msgid "VIM - Search and Replace..."
+msgstr "VIM - ²éÕÒºÍÌæ»»..."
+
+msgid "VIM - Search..."
+msgstr "VIM - ²éÕÒ..."
+
+msgid "Find what:"
+msgstr "²éÕÒÄÚÈÝ:"
+
+msgid "Replace with:"
+msgstr "Ì滻Ϊ:"
+
+#. whole word only button
+msgid "Match whole word only"
+msgstr "Æ¥ÅäÍêÕûµÄ´Ê"
+
+#. match case button
+msgid "Match case"
+msgstr "Æ¥Åä´óСд"
+
+msgid "Direction"
+msgstr "·½Ïò"
+
+#. 'Up' and 'Down' buttons
+msgid "Up"
+msgstr "ÏòÉÏ"
+
+msgid "Down"
+msgstr "ÏòÏÂ"
+
+msgid "Find Next"
+msgstr "²éÕÒÏÂÒ»¸ö"
+
+msgid "Replace"
+msgstr "Ìæ»»"
+
+msgid "Replace All"
+msgstr "È«²¿Ìæ»»"
+
+msgid "Vim: Received \"die\" request from session manager\n"
+msgstr "Vim: ´Ó»á»°¹ÜÀíÆ÷ÊÕµ½ \"die\" ÇëÇó\n"
+
+msgid "Close"
+msgstr "¹Ø±Õ"
+
+msgid "New tab"
+msgstr "н¨±êÇ©"
+
+msgid "Open Tab..."
+msgstr "´ò¿ª±êÇ©..."
+
+msgid "Vim: Main window unexpectedly destroyed\n"
+msgstr "Vim: Ö÷´°¿Ú±»ÒâÍâµØ´Ý»Ù\n"
+
+msgid "Font Selection"
+msgstr "Ñ¡Ôñ×ÖÌå"
+
+msgid "Used CUT_BUFFER0 instead of empty selection"
+msgstr "ʹÓà CUT_BUFFER0 À´È¡´ú¿ÕÑ¡Ôñ"
+
+msgid "&Filter"
+msgstr "¹ýÂË(&F)"
+
+msgid "&Cancel"
+msgstr "È¡Ïû(&C)"
+
+msgid "Directories"
+msgstr "Ŀ¼"
+
+msgid "Filter"
+msgstr "¹ýÂËÆ÷"
+
+msgid "&Help"
+msgstr "°ïÖú(&H)"
+
+msgid "Files"
+msgstr "Îļþ"
+
+msgid "&OK"
+msgstr "È·¶¨(&O)"
+
+msgid "Selection"
+msgstr "Ñ¡Ôñ"
+
+msgid "Find &Next"
+msgstr "²éÕÒÏÂÒ»¸ö(&N)"
+
+msgid "&Replace"
+msgstr "Ìæ»»(&R)"
+
+msgid "Replace &All"
+msgstr "È«²¿Ìæ»»(&A)"
+
+msgid "&Undo"
+msgstr "³·Ïú(&U)"
+
+#, c-format
+msgid "E671: Cannot find window title \"%s\""
+msgstr "E671: ÕÒ²»µ½´°¿Ú±êÌâ \"%s\""
+
+#, c-format
+msgid "E243: Argument not supported: \"-%s\"; Use the OLE version."
+msgstr "E243: ²»Ö§³ÖµÄ²ÎÊý: \"-%s\"£»ÇëʹÓà OLE °æ±¾¡£"
+
+msgid "E672: Unable to open window inside MDI application"
+msgstr "E672: ÎÞ·¨ÔÚ MDI Ó¦ÓóÌÐòÖдò¿ª´°¿Ú"
+
+msgid "Close tab"
+msgstr "¹Ø±Õ±êÇ©"
+
+msgid "Open tab..."
+msgstr "´ò¿ª±êÇ©..."
+
+msgid "Find string (use '\\\\' to find a '\\')"
+msgstr "²éÕÒ×Ö·û´® (ʹÓà '\\\\' À´²éÕÒ '\\')"
+
+msgid "Find & Replace (use '\\\\' to find a '\\')"
+msgstr "²éÕÒºÍÌæ»»×Ö·û´® (ʹÓà '\\\\' À´²éÕÒ '\\')"
+
+#. We fake this: Use a filter that doesn't select anything and a default
+#. * file name that won't be used.
+msgid "Not Used"
+msgstr "δʹÓÃ"
+
+msgid "Directory\t*.nothing\n"
+msgstr "Ŀ¼\t*.nothing\n"
+
+msgid "Vim E458: Cannot allocate colormap entry, some colors may be incorrect"
+msgstr "Vim E458: ÎÞ·¨·ÖÅäÑÕÉ«±íÏijЩÑÕÉ«¿ÉÄܲ»ÕýÈ·"
+
+#, c-format
+msgid "E250: Fonts for the following charsets are missing in fontset %s:"
+msgstr "E250: Fontset %s ȱÉÙÏÂÁÐ×Ö·û¼¯µÄ×ÖÌå:"
+
+#, c-format
+msgid "E252: Fontset name: %s"
+msgstr "E252: Fontset Ãû³Æ: %s"
+
+#, c-format
+msgid "Font '%s' is not fixed-width"
+msgstr "'%s' ²»Êǹ̶¨¿í¶ÈµÄ×ÖÌå"
+
+#, c-format
+msgid "E253: Fontset name: %s\n"
+msgstr "E253: Fontset Ãû³Æ: %s\n"
+
+#, c-format
+msgid "Font0: %s\n"
+msgstr "×ÖÌå0: %s\n"
+
+#, c-format
+msgid "Font1: %s\n"
+msgstr "×ÖÌå1: %s\n"
+
+#, c-format
+msgid "Font%ld width is not twice that of font0\n"
+msgstr "×ÖÌå%ldµÄ¿í¶È²»ÊÇ×ÖÌå0µÄÁ½±¶\n"
+
+#, c-format
+msgid "Font0 width: %ld\n"
+msgstr "×ÖÌå0µÄ¿í¶È£º%ld\n"
+
+#, c-format
+msgid ""
+"Font1 width: %ld\n"
+"\n"
+msgstr ""
+"×ÖÌå1µÄ¿í¶È: %ld\n"
+"\n"
+
+msgid "Invalid font specification"
+msgstr "Ö¸¶¨ÁËÎÞЧµÄ×ÖÌå"
+
+msgid "&Dismiss"
+msgstr "È¡Ïû(&D)"
+
+msgid "no specific match"
+msgstr "ÕÒ²»µ½Æ¥ÅäµÄÏî"
+
+msgid "Vim - Font Selector"
+msgstr "Vim - ×ÖÌåÑ¡ÔñÆ÷"
+
+msgid "Name:"
+msgstr "Ãû³Æ:"
+
+#. create toggle button
+#~ msgid "Show size in Points"
+#~ msgstr ""
+
+msgid "Encoding:"
+msgstr "±àÂë:"
+
+msgid "Font:"
+msgstr "×ÖÌå:"
+
+msgid "Style:"
+msgstr "·ç¸ñ:"
+
+msgid "Size:"
+msgstr "³ß´ç:"
+
+msgid "E256: Hangul automata ERROR"
+msgstr "E256: Hangul automata ´íÎó"
+
+msgid "E550: Missing colon"
+msgstr "E550: ȱÉÙðºÅ"
+
+msgid "E551: Illegal component"
+msgstr "E551: ÎÞЧµÄ²¿·Ö"
+
+msgid "E552: digit expected"
+msgstr "E552: Ó¦¸ÃÒªÓÐÊý×Ö"
+
+#, c-format
+msgid "Page %d"
+msgstr "µÚ %d Ò³"
+
+msgid "No text to be printed"
+msgstr "ûÓÐÒª´òÓ¡µÄÎÄ×Ö"
+
+#, c-format
+msgid "Printing page %d (%d%%)"
+msgstr "ÕýÔÚ´òÓ¡µÚ %d Ò³ (%d%%)"
+
+#, c-format
+msgid " Copy %d of %d"
+msgstr "¸´ÖÆ %d / %d"
+
+#, c-format
+msgid "Printed: %s"
+msgstr "ÒÑ´òÓ¡: %s"
+
+msgid "Printing aborted"
+msgstr "´òÓ¡ÖÐÖ¹"
+
+msgid "E455: Error writing to PostScript output file"
+msgstr "E455: дÈë PostScript Êä³öÎļþ³ö´í"
+
+#, c-format
+msgid "E624: Can't open file \"%s\""
+msgstr "E624: ÎÞ·¨´ò¿ªÎļþ \"%s\""
+
+#, c-format
+msgid "E457: Can't read PostScript resource file \"%s\""
+msgstr "E457: ÎÞ·¨¶ÁÈ¡ PostScript ×ÊÔ´Îļþ \"%s\""
+
+#, c-format
+msgid "E618: file \"%s\" is not a PostScript resource file"
+msgstr "E618: Îļþ \"%s\" ²»ÊÇ PostScript ×ÊÔ´Îļþ"
+
+#, c-format
+msgid "E619: file \"%s\" is not a supported PostScript resource file"
+msgstr "E619: Îļþ \"%s\" ²»ÊÇÒÑÖ§³ÖµÄ PostScript ×ÊÔ´Îļþ"
+
+#, c-format
+msgid "E621: \"%s\" resource file has wrong version"
+msgstr "E621: \"%s\" ×ÊÔ´Îļþ°æ±¾²»ÕýÈ·"
+
+msgid "E673: Incompatible multi-byte encoding and character set."
+msgstr "E673: ²»¼æÈݵĶà×Ö½Ú±àÂëºÍ×Ö·û¼¯¡£"
+
+msgid "E674: printmbcharset cannot be empty with multi-byte encoding."
+msgstr "E674: printmbcharset ÔÚ¶à×Ö½Ú±àÂëϲ»ÄÜΪ¿Õ¡£"
+
+msgid "E675: No default font specified for multi-byte printing."
+msgstr "E675: ûÓÐÖ¸¶¨¶à×Ö½Ú´òÓ¡µÄĬÈÏ×ÖÌå¡£"
+
+msgid "E324: Can't open PostScript output file"
+msgstr "E324: ÎÞ·¨´ò¿ª PostScript Êä³öÎļþ"
+
+#, c-format
+msgid "E456: Can't open file \"%s\""
+msgstr "E456: ÎÞ·¨´ò¿ªÎļþ \"%s\""
+
+msgid "E456: Can't find PostScript resource file \"prolog.ps\""
+msgstr "E456: ÕÒ²»µ½ PostScript ×ÊÔ´Îļþ \"prolog.ps\""
+
+msgid "E456: Can't find PostScript resource file \"cidfont.ps\""
+msgstr "E456: ÕÒ²»µ½ PostScript ×ÊÔ´Îļþ \"cidfont.ps\""
+
+#, c-format
+msgid "E456: Can't find PostScript resource file \"%s.ps\""
+msgstr "E456: ÕÒ²»µ½ PostScript ×ÊÔ´Îļþ \"%s.ps\""
+
+#, c-format
+msgid "E620: Unable to convert to print encoding \"%s\""
+msgstr "E620: ÎÞ·¨×ª»»ÖÁ´òÓ¡±àÂë \"%s\""
+
+msgid "Sending to printer..."
+msgstr "·¢Ë͵½´òÓ¡»ú¡­¡­"
+
+msgid "E365: Failed to print PostScript file"
+msgstr "E365: ÎÞ·¨´òÓ¡ PostScript Îļþ"
+
+msgid "Print job sent."
+msgstr "´òÓ¡ÈÎÎñÒѱ»·¢ËÍ¡£"
+
+msgid "Add a new database"
+msgstr "Ìí¼ÓÒ»¸öеÄÊý¾Ý¿â"
+
+msgid "Query for a pattern"
+msgstr "²éѯһ¸öģʽ"
+
+msgid "Show this message"
+msgstr "ÏÔʾ´ËÐÅÏ¢"
+
+msgid "Kill a connection"
+msgstr "½áÊøÒ»¸öÁ¬½Ó"
+
+msgid "Reinit all connections"
+msgstr "ÖØÖÃËùÓÐÁ¬½Ó"
+
+msgid "Show connections"
+msgstr "ÏÔʾÁ¬½Ó"
+
+#, c-format
+msgid "E560: Usage: cs[cope] %s"
+msgstr "E560: Ó÷¨: cs[cope] %s"
+
+msgid "This cscope command does not support splitting the window.\n"
+msgstr "Õâ¸ö cscope ÃüÁî²»Ö§³Ö·Ö¸î´°¿Ú¡£\n"
+
+msgid "E562: Usage: cstag <ident>"
+msgstr "E562: Ó÷¨: cstag <ident>"
+
+msgid "E257: cstag: tag not found"
+msgstr "E257: cstag: ÕÒ²»µ½ tag"
+
+#, c-format
+msgid "E563: stat(%s) error: %d"
+msgstr "E563: stat(%s) ´íÎó: %d"
+
+msgid "E563: stat error"
+msgstr "E563: stat ´íÎó"
+
+#, c-format
+msgid "E564: %s is not a directory or a valid cscope database"
+msgstr "E564: %s ²»ÊÇĿ¼»òÓÐЧµÄ cscope Êý¾Ý¿â"
+
+#, c-format
+msgid "Added cscope database %s"
+msgstr "Ìí¼ÓÁË cscope Êý¾Ý¿â %s"
+
+#, c-format
+msgid "E262: error reading cscope connection %ld"
+msgstr "E262: ¶ÁÈ¡ cscope Á¬½Ó %ld ³ö´í"
+
+msgid "E561: unknown cscope search type"
+msgstr "E561: δ֪µÄ cscope ²éÕÒÀàÐÍ"
+
+msgid "E566: Could not create cscope pipes"
+msgstr "E566: ÎÞ·¨´´½¨ cscope ¹ÜµÀ"
+
+msgid "E622: Could not fork for cscope"
+msgstr "E622: ÎÞ·¨¶Ô cscope ½øÐÐ fork"
+
+msgid "cs_create_connection exec failed"
+msgstr "cs_create_connection Ö´ÐÐʧ°Ü"
+
+msgid "E623: Could not spawn cscope process"
+msgstr "E623: ÎÞ·¨Éú³É cscope ½ø³Ì"
+
+msgid "cs_create_connection: fdopen for to_fp failed"
+msgstr "cs_create_connection: fdopen to_fp ʧ°Ü"
+
+msgid "cs_create_connection: fdopen for fr_fp failed"
+msgstr "cs_create_connection: fdopen fr_fp ʧ°Ü"
+
+msgid "E567: no cscope connections"
+msgstr "E567: ûÓÐ cscope Á¬½Ó"
+
+#, c-format
+msgid "E259: no matches found for cscope query %s of %s"
+msgstr "E259: cscope ²éѯ %s %s ûÓÐÕÒµ½Æ¥ÅäµÄ½á¹û"
+
+#, c-format
+msgid "E469: invalid cscopequickfix flag %c for %c"
+msgstr "E469: cscopequickfix ±êÖ¾ %c ¶Ô %c ÎÞЧ"
+
+msgid "cscope commands:\n"
+msgstr "cscope ÃüÁî:\n"
+
+#, c-format
+msgid "%-5s: %-30s (Usage: %s)"
+msgstr "%-5s: %-30s (Ó÷¨: %s)"
+
+#, c-format
+msgid "E625: cannot open cscope database: %s"
+msgstr "E625: ÎÞ·¨´ò¿ª cscope Êý¾Ý¿â: %s"
+
+msgid "E626: cannot get cscope database information"
+msgstr "E626: ÎÞ·¨»ñÈ¡ cscope Êý¾Ý¿âÐÅÏ¢"
+
+msgid "E568: duplicate cscope database not added"
+msgstr "E568: Öظ´µÄ cscope Êý¾Ý¿âδ±»¼ÓÈë"
+
+msgid "E569: maximum number of cscope connections reached"
+msgstr "E569: ÒÑ´ïµ½ cscope µÄ×î´óÁ¬½ÓÊý"
+
+#, c-format
+msgid "E261: cscope connection %s not found"
+msgstr "E261: ÕÒ²»µ½ cscope Á¬½Ó %s"
+
+#, c-format
+msgid "cscope connection %s closed"
+msgstr "cscope Á¬½Ó %s ÒѹرÕ"
+
+#. should not reach here
+msgid "E570: fatal error in cs_manage_matches"
+msgstr "E570: cs_manage_matches ÑÏÖØ´íÎó"
+
+#, c-format
+msgid "Cscope tag: %s"
+msgstr "Cscope tag: %s"
+
+msgid ""
+"\n"
+" # line"
+msgstr ""
+"\n"
+" # ÐÐ "
+
+msgid "filename / context / line\n"
+msgstr "ÎļþÃû / ÉÏÏÂÎÄ / ÐÐ\n"
+
+#, c-format
+msgid "E609: Cscope error: %s"
+msgstr "E609: Cscope ´íÎó: %s"
+
+msgid "All cscope databases reset"
+msgstr "ËùÓÐ cscope Êý¾Ý¿âÒѱ»ÖØÖÃ"
+
+msgid "no cscope connections\n"
+msgstr "ûÓÐ cscope Á¬½Ó\n"
+
+msgid " # pid database name prepend path\n"
+msgstr " # pid Êý¾Ý¿âÃû prepend path\n"
+
+msgid ""
+"???: Sorry, this command is disabled, the MzScheme library could not be "
+"loaded."
+msgstr "???: ±§Ç¸£¬´ËÃüÁî²»¿ÉÓã¬ÎÞ·¨¼ÓÔØ MzScheme ¿â"
+
+msgid "invalid expression"
+msgstr "ÎÞЧµÄ±í´ïʽ"
+
+msgid "expressions disabled at compile time"
+msgstr "±àÒëʱûÓÐÆôÓñí´ïʽ"
+
+msgid "hidden option"
+msgstr "Òþ²ØµÄÑ¡Ïî"
+
+msgid "unknown option"
+msgstr "δ֪µÄÑ¡Ïî"
+
+msgid "window index is out of range"
+msgstr "´°¿ÚË÷Òý³¬³ö·¶Î§"
+
+msgid "couldn't open buffer"
+msgstr "ÎÞ·¨´ò¿ª»º³åÇø"
+
+msgid "cannot save undo information"
+msgstr "ÎÞ·¨±£´æ³·ÏúÐÅÏ¢"
+
+msgid "cannot delete line"
+msgstr "ÎÞ·¨É¾³ýÐÐ"
+
+msgid "cannot replace line"
+msgstr "ÎÞ·¨Ìæ»»ÐÐ"
+
+msgid "cannot insert line"
+msgstr "ÎÞ·¨²åÈëÐÐ"
+
+msgid "string cannot contain newlines"
+msgstr "×Ö·û´®²»ÄÜ°üº¬»»ÐÐ(NL)"
+
+msgid "Vim error: ~a"
+msgstr "Vim ´íÎó: ~a"
+
+msgid "Vim error"
+msgstr "Vim ´íÎó"
+
+msgid "buffer is invalid"
+msgstr "»º³åÇøÎÞЧ"
+
+msgid "window is invalid"
+msgstr "´°¿ÚÎÞЧ"
+
+msgid "linenr out of range"
+msgstr "Ðкų¬³ö·¶Î§"
+
+msgid "not allowed in the Vim sandbox"
+msgstr "²»ÔÊÐíÔÚ sandbox ÖÐʹÓÃ"
+
+msgid ""
+"E263: Sorry, this command is disabled, the Python library could not be "
+"loaded."
+msgstr "E263: ±§Ç¸£¬´ËÃüÁî²»¿ÉÓã¬ÎÞ·¨¼ÓÔØ Python ¿â¡£"
+
+msgid "E659: Cannot invoke Python recursively"
+msgstr "E659: ²»Äܵݹéµ÷Óà Python"
+
+msgid "can't delete OutputObject attributes"
+msgstr "²»ÄÜɾ³ý OutputObject ÊôÐÔ"
+
+msgid "softspace must be an integer"
+msgstr "softspace ±ØÐëÊÇÕûÊý"
+
+msgid "invalid attribute"
+msgstr "ÎÞЧµÄÊôÐÔ"
+
+msgid "writelines() requires list of strings"
+msgstr "writelines() ÐèÒª×Ö·û´®Áбí×÷²ÎÊý"
+
+msgid "E264: Python: Error initialising I/O objects"
+msgstr "E264: Python: ³õʼ»¯ I/O ¶ÔÏó³ö´í"
+
+msgid "attempt to refer to deleted buffer"
+msgstr "ÊÔͼÒýÓÃÒѱ»É¾³ýµÄ»º³åÇø"
+
+msgid "line number out of range"
+msgstr "Ðкų¬³ö·¶Î§"
+
+#, c-format
+msgid "<buffer object (deleted) at %8lX>"
+msgstr "<»º³åÇø¶ÔÏó(ÒÑɾ³ý): %8lX>"
+
+msgid "invalid mark name"
+msgstr "ÎÞЧµÄ±ê¼ÇÃû³Æ"
+
+msgid "no such buffer"
+msgstr "ÎÞ´Ë»º³åÇø"
+
+msgid "attempt to refer to deleted window"
+msgstr "ÊÔͼÒýÓÃÒѱ»É¾³ýµÄ´°¿Ú"
+
+msgid "readonly attribute"
+msgstr "Ö»¶ÁÊôÐÔ"
+
+msgid "cursor position outside buffer"
+msgstr "¹â±êλÖÃÔÚ»º³åÇøÍâ"
+
+#, c-format
+msgid "<window object (deleted) at %.8lX>"
+msgstr "<´°¿Ú¶ÔÏó(ÒÑɾ³ý): %.8lX>"
+
+#, c-format
+msgid "<window object (unknown) at %.8lX>"
+msgstr "<´°¿Ú¶ÔÏó(δ֪): %.8lX>"
+
+#, c-format
+msgid "<window %d>"
+msgstr "<´°¿Ú %d>"
+
+msgid "no such window"
+msgstr "ÎÞ´Ë´°¿Ú"
+
+msgid ""
+"E266: Sorry, this command is disabled, the Ruby library could not be loaded."
+msgstr "E266: ±§Ç¸£¬´ËÃüÁî²»¿ÉÓã¬ÎÞ·¨¼ÓÔØ Ruby ¿â"
+
+#, c-format
+msgid "E273: unknown longjmp status %d"
+msgstr "E273: δ֪µÄ longjmp ״̬ %d"
+
+msgid "Toggle implementation/definition"
+msgstr "Çл»ÊµÏÖ/¶¨Òå"
+
+msgid "Show base class of"
+msgstr "ÏÔʾ base class of:"
+
+msgid "Show overridden member function"
+msgstr "ÏÔʾ±»¸²¸ÇµÄ³ÉÔ±º¯Êý"
+
+msgid "Retrieve from file"
+msgstr "»Ö¸´: ´ÓÎļþ"
+
+msgid "Retrieve from project"
+msgstr "»Ö¸´: ´Ó¶ÔÏó"
+
+msgid "Retrieve from all projects"
+msgstr "»Ö¸´: ´ÓËùÓÐÏîÄ¿"
+
+msgid "Retrieve"
+msgstr "»Ö¸´"
+
+msgid "Show source of"
+msgstr "ÏÔʾԴ´úÂë: "
+
+msgid "Find symbol"
+msgstr "²éÕÒ symbol"
+
+msgid "Browse class"
+msgstr "ä¯ÀÀ class"
+
+msgid "Show class in hierarchy"
+msgstr "ÏÔʾ²ã´Î¹ØϵµÄÀà"
+
+msgid "Show class in restricted hierarchy"
+msgstr "ÏÔʾ restricted ²ã´Î¹ØϵµÄ class"
+
+msgid "Xref refers to"
+msgstr "Xref ²Î¿¼µ½"
+
+msgid "Xref referred by"
+msgstr "Xref ±»Ë­²Î¿¼:"
+
+msgid "Xref has a"
+msgstr "Xref ÓÐ"
+
+msgid "Xref used by"
+msgstr "Xref ±»Ë­Ê¹ÓÃ:"
+
+msgid "Show docu of"
+msgstr "ÏÔʾÎļþ: "
+
+msgid "Generate docu for"
+msgstr "²úÉúÎļþ: "
+
+msgid ""
+"Cannot connect to SNiFF+. Check environment (sniffemacs must be found in "
+"$PATH).\n"
+msgstr "²»ÄÜÁ¬½Óµ½ SNiFF+¡£Çë¼ì²é»·¾³±äÁ¿ ($PATH Àï±ØÐè¿ÉÒÔÕÒµ½ sniffemacs)\n"
+
+msgid "E274: Sniff: Error during read. Disconnected"
+msgstr "E274: Sniff: ¶ÁÈ¡´íÎó. È¡ÏûÁ¬½Ó"
+
+msgid "SNiFF+ is currently "
+msgstr "SNiFF+ Ä¿Ç°"
+
+msgid "not "
+msgstr "δ"
+
+msgid "connected"
+msgstr "Á¬½ÓÖÐ"
+
+#, c-format
+msgid "E275: Unknown SNiFF+ request: %s"
+msgstr "E275: ²»ÕýÈ·µÄ SNiff+ µ÷ÓÃ: %s"
+
+msgid "E276: Error connecting to SNiFF+"
+msgstr "E276: Á¬½Óµ½ SNiFF+ ʧ°Ü"
+
+msgid "E278: SNiFF+ not connected"
+msgstr "E278: δÁ¬½Óµ½ SNiFF+"
+
+msgid "E279: Not a SNiFF+ buffer"
+msgstr "E279: ²»ÊÇ SNiFF+ µÄ»º³åÇø"
+
+msgid "Sniff: Error during write. Disconnected"
+msgstr "Sniff: дÈë´íÎó¡£½áÊøÁ¬½Ó"
+
+msgid "invalid buffer number"
+msgstr "ÎÞЧµÄ»º³åÇøºÅ"
+
+msgid "not implemented yet"
+msgstr "ÉÐδʵÏÖ"
+
+#. ???
+msgid "cannot set line(s)"
+msgstr "ÎÞ·¨É趨ÐÐ"
+
+msgid "mark not set"
+msgstr "ûÓÐÉ趨±ê¼Ç"
+
+#, c-format
+msgid "row %d column %d"
+msgstr "µÚ %d ÐÐ µÚ %d ÁÐ"
+
+msgid "cannot insert/append line"
+msgstr "ÎÞ·¨²åÈë/×·¼ÓÐÐ"
+
+msgid "unknown flag: "
+msgstr "δ֪µÄ±êÖ¾: "
+
+msgid "unknown vimOption"
+msgstr "δ֪µÄ vim Ñ¡Ïî"
+
+msgid "keyboard interrupt"
+msgstr "¼üÅÌÖжÏ"
+
+msgid "vim error"
+msgstr "vim ´íÎó"
+
+msgid "cannot create buffer/window command: object is being deleted"
+msgstr "ÎÞ·¨´´½¨»º³åÇø/´°¿ÚÃüÁî: ¶ÔÏ󽫱»É¾³ý"
+
+msgid ""
+"cannot register callback command: buffer/window is already being deleted"
+msgstr "ÎÞ·¨×¢²á»Øµ÷ÃüÁî: »º³åÇø/´°¿ÚÒѱ»É¾³ý"
+
+#. This should never happen. Famous last word?
+msgid ""
+"E280: TCL FATAL ERROR: reflist corrupt!? Please report this to vim-dev@vim."
+"org"
+msgstr "E280: TCL ÑÏÖØ´íÎó: reflist Ë𻵣¡£¿Ç뱨¸æ¸ø vim-dev@vim.org"
+
+msgid "cannot register callback command: buffer/window reference not found"
+msgstr "ÎÞ·¨×¢²á»Øµ÷ÃüÁî: ÕÒ²»µ½»º³åÇø/´°¿ÚÒýÓÃ"
+
+msgid ""
+"E571: Sorry, this command is disabled: the Tcl library could not be loaded."
+msgstr "E571: ±§Ç¸£¬´ËÃüÁî²»¿ÉÓã¬ÎÞ·¨¼ÓÔØ Tcl ¿â"
+
+msgid ""
+"E281: TCL ERROR: exit code is not int!? Please report this to vim-dev@vim.org"
+msgstr "E281: TCL ´íÎó: Í˳ö·µ»ØÖµ²»ÊÇÕûÊý£¡£¿Ç뱨¸æ¸ø vim-dev@vim.org"
+
+#, c-format
+msgid "E572: exit code %d"
+msgstr "E572: Í˳ö·µ»ØÖµ %d"
+
+msgid "cannot get line"
+msgstr "ÎÞ·¨»ñÈ¡ÐÐ"
+
+msgid "Unable to register a command server name"
+msgstr "ÎÞ·¨×¢²áÃüÁî·þÎñÆ÷Ãû"
+
+msgid "E248: Failed to send command to the destination program"
+msgstr "E248: ÎÞ·¨·¢ËÍÃüÁĿµÄ³ÌÐò"
+
+#, c-format
+msgid "E573: Invalid server id used: %s"
+msgstr "E573: ʹÓÃÁËÎÞЧµÄ·þÎñÆ÷ id: %s"
+
+msgid "E251: VIM instance registry property is badly formed. Deleted!"
+msgstr "E251: VIM ʵÀý×¢²áÊôÐÔÓÐÎó¡£ÒÑɾ³ý£¡"
+
+msgid "Unknown option argument"
+msgstr "δ֪µÄÑ¡Ïî²ÎÊý"
+
+msgid "Too many edit arguments"
+msgstr "±à¼­²ÎÊý¹ý¶à"
+
+msgid "Argument missing after"
+msgstr "ȱÉÙ±ØÒªµÄ²ÎÊý"
+
+msgid "Garbage after option argument"
+msgstr "Ñ¡Ïî²ÎÊýºóµÄÄÚÈÝÎÞЧ"
+
+msgid "Too many \"+command\", \"-c command\" or \"--cmd command\" arguments"
+msgstr "\"+command\"¡¢\"-c command\" »ò \"--cmd command\" ²ÎÊý¹ý¶à"
+
+msgid "Invalid argument for"
+msgstr "ÎÞЧµÄ²ÎÊý"
+
+#, c-format
+msgid "%d files to edit\n"
+msgstr "»¹ÓÐ %d ¸öÎļþµÈ´ý±à¼­\n"
+
+msgid "This Vim was not compiled with the diff feature."
+msgstr "´Ë Vim ±àÒëʱûÓмÓÈë diff ¹¦ÄÜ"
+
+msgid "Attempt to open script file again: \""
+msgstr "ÊÔͼÔٴδò¿ª½Å±¾Îļþ: \""
+
+msgid "Cannot open for reading: \""
+msgstr "ÎÞ·¨´ò¿ª²¢¶ÁÈ¡: \""
+
+msgid "Cannot open for script output: \""
+msgstr "ÎÞ·¨´ò¿ª²¢Êä³ö½Å±¾: \""
+
+msgid "Vim: Error: Failure to start gvim from NetBeans\n"
+msgstr "Vim: ´íÎó: ÎÞ·¨´Ó NetBeans ÖÐÆô¶¯ gvim\n"
+
+msgid "Vim: Warning: Output is not to a terminal\n"
+msgstr "Vim: ¾¯¸æ: Êä³ö²»Êǵ½ÖÕ¶Ë(ÆÁÄ»)\n"
+
+msgid "Vim: Warning: Input is not from a terminal\n"
+msgstr "Vim: ¾¯¸æ: ÊäÈë²»ÊÇÀ´×ÔÖÕ¶Ë(¼üÅÌ)\n"
+
+#. just in case..
+msgid "pre-vimrc command line"
+msgstr "pre-vimrc ÃüÁîÐÐ"
+
+#, c-format
+msgid "E282: Cannot read from \"%s\""
+msgstr "E282: ÎÞ·¨¶ÁÈ¡ \"%s\""
+
+msgid ""
+"\n"
+"More info with: \"vim -h\"\n"
+msgstr ""
+"\n"
+"¸ü¶àÐÅÏ¢Çë¼û: \"vim -h\"\n"
+
+msgid "[file ..] edit specified file(s)"
+msgstr "[Îļþ ..] ±à¼­Ö¸¶¨µÄÎļþ"
+
+msgid "- read text from stdin"
+msgstr "- ´Ó±ê×¼ÊäÈë(stdin)¶ÁÈ¡Îı¾"
+
+msgid "-t tag edit file where tag is defined"
+msgstr "-t tag ±à¼­ tag ¶¨Òå´¦µÄÎļþ"
+
+msgid "-q [errorfile] edit file with first error"
+msgstr "-q [errorfile] ±à¼­µÚÒ»¸ö³ö´í´¦µÄÎļþ"
+
+msgid ""
+"\n"
+"\n"
+"Usage:"
+msgstr ""
+"\n"
+"\n"
+"Ó÷¨:"
+
+msgid " vim [arguments] "
+msgstr " vim [²ÎÊý] "
+
+msgid ""
+"\n"
+" or:"
+msgstr ""
+"\n"
+" »ò:"
+
+#~ msgid "where case is ignored prepend / to make flag upper case"
+#~ msgstr ""
+
+msgid ""
+"\n"
+"\n"
+"Arguments:\n"
+msgstr ""
+"\n"
+"\n"
+"²ÎÊý:\n"
+
+msgid "--\t\t\tOnly file names after this"
+msgstr "--\t\t\tÔÚÕâÒÔºóÖ»ÓÐÎļþÃû"
+
+msgid "--literal\t\tDon't expand wildcards"
+msgstr "--literal\t\t²»À©Õ¹Í¨Åä·û"
+
+msgid "-register\t\tRegister this gvim for OLE"
+msgstr "-register\t\t×¢²á´Ë gvim µ½ OLE"
+
+msgid "-unregister\t\tUnregister gvim for OLE"
+msgstr "-unregister\t\tÈ¡Ïû OLE ÖÐµÄ gvim ×¢²á"
+
+msgid "-g\t\t\tRun using GUI (like \"gvim\")"
+msgstr "-g\t\t\tʹÓÃͼÐνçÃæ (ͬ \"gvim\")"
+
+msgid "-f or --nofork\tForeground: Don't fork when starting GUI"
+msgstr "-f »ò --nofork\tǰ̨: Æô¶¯Í¼ÐνçÃæʱ²» fork"
+
+msgid "-v\t\t\tVi mode (like \"vi\")"
+msgstr "-v\t\t\tVi ģʽ (ͬ \"vi\")"
+
+msgid "-e\t\t\tEx mode (like \"ex\")"
+msgstr "-e\t\t\tEx ģʽ (ͬ \"ex\")"
+
+msgid "-s\t\t\tSilent (batch) mode (only for \"ex\")"
+msgstr "-s\t\t\t°²¾²(Åú´¦Àí)ģʽ (Ö»ÄÜÓë \"ex\" Ò»ÆðʹÓÃ)"
+
+msgid "-d\t\t\tDiff mode (like \"vimdiff\")"
+msgstr "-d\t\t\tDiff ģʽ (ͬ \"vimdiff\")"
+
+msgid "-y\t\t\tEasy mode (like \"evim\", modeless)"
+msgstr "-y\t\t\tÈÝÒ×ģʽ (ͬ \"evim\"£¬ÎÞģʽ)"
+
+msgid "-R\t\t\tReadonly mode (like \"view\")"
+msgstr "-R\t\t\tÖ»¶Áģʽ (ͬ \"view\")"
+
+msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
+msgstr "-Z\t\t\tÏÞÖÆģʽ (ͬ \"rvim\")"
+
+msgid "-m\t\t\tModifications (writing files) not allowed"
+msgstr "-m\t\t\t²»¿ÉÐÞ¸Ä(дÈëÎļþ)"
+
+msgid "-M\t\t\tModifications in text not allowed"
+msgstr "-M\t\t\tÎı¾²»¿ÉÐÞ¸Ä"
+
+msgid "-b\t\t\tBinary mode"
+msgstr "-b\t\t\t¶þ½øÖÆģʽ"
+
+msgid "-l\t\t\tLisp mode"
+msgstr "-l\t\t\tLisp ģʽ"
+
+msgid "-C\t\t\tCompatible with Vi: 'compatible'"
+msgstr "-C\t\t\t¼æÈÝ´«Í³µÄ Vi: 'compatible'"
+
+msgid "-N\t\t\tNot fully Vi compatible: 'nocompatible'"
+msgstr "-N\t\t\t²»ÍêÈ«¼æÈÝ´«Í³µÄ Vi: 'nocompatible'"
+
+msgid "-V[N]\t\tVerbose level"
+msgstr "-V[N]\t\tVerbose µÈ¼¶"
+
+msgid "-D\t\t\tDebugging mode"
+msgstr "-D\t\t\tµ÷ÊÔģʽ"
+
+msgid "-n\t\t\tNo swap file, use memory only"
+msgstr "-n\t\t\t²»Ê¹Óý»»»Îļþ£¬Ö»Ê¹ÓÃÄÚ´æ"
+
+msgid "-r\t\t\tList swap files and exit"
+msgstr "-r\t\t\tÁгö½»»»Îļþ²¢Í˳ö"
+
+msgid "-r (with file name)\tRecover crashed session"
+msgstr "-r (¸úÎļþÃû)\t\t»Ö¸´±ÀÀ£µÄ»á»°"
+
+msgid "-L\t\t\tSame as -r"
+msgstr "-L\t\t\tͬ -r"
+
+msgid "-f\t\t\tDon't use newcli to open window"
+msgstr "-f\t\t\t²»Ê¹Óà newcli À´´ò¿ª´°¿Ú"
+
+msgid "-dev <device>\t\tUse <device> for I/O"
+msgstr "-dev <device>\t\tʹÓà <device> ½øÐÐÊäÈëÊä³ö"
+
+msgid "-A\t\t\tStart in Arabic mode"
+msgstr "-A\t\t\tÒÔ Arabic ģʽÆô¶¯"
+
+msgid "-H\t\t\tStart in Hebrew mode"
+msgstr "-H\t\t\tÒÔ Hebrew ģʽÆô¶¯"
+
+msgid "-F\t\t\tStart in Farsi mode"
+msgstr "-F\t\t\tÒÔ Farsi ģʽÆô¶¯"
+
+msgid "-T <terminal>\tSet terminal type to <terminal>"
+msgstr "-T <terminal>\tÉ趨ÖÕ¶ËÀàÐÍΪ <terminal>"
+
+msgid "-u <vimrc>\t\tUse <vimrc> instead of any .vimrc"
+msgstr "-u <vimrc>\t\tʹÓà <vimrc> Ìæ´úÈκΠ.vimrc"
+
+msgid "-U <gvimrc>\t\tUse <gvimrc> instead of any .gvimrc"
+msgstr "-U <gvimrc>\t\tʹÓà <gvimrc> Ìæ´úÈκΠ.gvimrc"
+
+msgid "--noplugin\t\tDon't load plugin scripts"
+msgstr "--noplugin\t\t²»¼ÓÔØ plugin ½Å±¾"
+
+msgid "-p[N]\t\tOpen N tab pages (default: one for each file)"
+msgstr "-P[N]\t\t´ò¿ª N ¸ö±êÇ©Ò³ (ĬÈÏÖµ: ÿ¸öÎļþÒ»¸ö)"
+
+msgid "-o[N]\t\tOpen N windows (default: one for each file)"
+msgstr "-o[N]\t\t´ò¿ª N ¸ö´°¿Ú (ĬÈÏÖµ: ÿ¸öÎļþÒ»¸ö)"
+
+msgid "-O[N]\t\tLike -o but split vertically"
+msgstr "-O[N]\t\tͬ -o µ«´¹Ö±·Ö¸î"
+
+msgid "+\t\t\tStart at end of file"
+msgstr "+\t\t\tÆô¶¯ºóÌøµ½Îļþĩβ"
+
+msgid "+<lnum>\t\tStart at line <lnum>"
+msgstr "+<lnum>\t\tÆô¶¯ºóÌøµ½µÚ <lnum> ÐÐ"
+
+msgid "--cmd <command>\tExecute <command> before loading any vimrc file"
+msgstr "--cmd <command>\t¼ÓÔØÈκΠvimrc ÎļþÇ°Ö´ÐÐ <command>"
+
+msgid "-c <command>\t\tExecute <command> after loading the first file"
+msgstr "-c <command>\t\t¼ÓÔصÚÒ»¸öÎļþºóÖ´ÐÐ <command>"
+
+msgid "-S <session>\t\tSource file <session> after loading the first file"
+msgstr "-S <session>\t\t¼ÓÔصÚÒ»¸öÎļþºóÖ´ÐÐÎļþ <session>"
+
+msgid "-s <scriptin>\tRead Normal mode commands from file <scriptin>"
+msgstr "-s <scriptin>\t´ÓÎļþ <scriptin> ¶ÁÈëÕý³£Ä£Ê½µÄÃüÁî"
+
+msgid "-w <scriptout>\tAppend all typed commands to file <scriptout>"
+msgstr "-w <scriptout>\t½«ËùÓÐÊäÈëµÄÃüÁî×·¼Óµ½Îļþ <scriptout>"
+
+msgid "-W <scriptout>\tWrite all typed commands to file <scriptout>"
+msgstr "-W <scriptout>\t½«ËùÓÐÊäÈëµÄÃüÁîдÈëµ½Îļþ <scriptout>"
+
+msgid "-x\t\t\tEdit encrypted files"
+msgstr "-x\t\t\t±à¼­¼ÓÃܵÄÎļþ"
+
+msgid "-display <display>\tConnect vim to this particular X-server"
+msgstr "-display <display>\t½« vim ÓëÖ¸¶¨µÄ X-server Á¬½Ó"
+
+msgid "-X\t\t\tDo not connect to X server"
+msgstr "-X\t\t\t²»Á¬½Óµ½ X Server"
+
+msgid "--remote <files>\tEdit <files> in a Vim server if possible"
+msgstr "--remote <files>\tÈçÓпÉÄÜ£¬ÔÚ Vim ·þÎñÆ÷Éϱ༭Îļþ <files>"
+
+msgid "--remote-silent <files> Same, don't complain if there is no server"
+msgstr "--remote-silent <files> ͬÉÏ£¬ÕÒ²»µ½·þÎñÆ÷ʱ²»±§Ô¹"
+
+msgid ""
+"--remote-wait <files> As --remote but wait for files to have been edited"
+msgstr "--remote-wait <files> ͬ --remote µ«»áµÈ´ýÎļþÍê³É±à¼­"
+
+msgid ""
+"--remote-wait-silent <files> Same, don't complain if there is no server"
+msgstr "--remote-wait-silent <files> ͬÉÏ£¬ÕÒ²»µ½·þÎñÆ÷ʱ²»±§Ô¹"
+
+msgid "--remote-tab <files> As --remote but open tab page for each file"
+msgstr "--remote-tab <files> ͬ --remote µ«¶Ôÿ¸öÎļþ´ò¿ªÒ»¸ö±êÇ©Ò³"
+
+msgid "--remote-send <keys>\tSend <keys> to a Vim server and exit"
+msgstr "--remote-send <keys>\tËͳö <keys> µ½ Vim ·þÎñÆ÷²¢Í˳ö"
+
+msgid "--remote-expr <expr>\tEvaluate <expr> in a Vim server and print result"
+msgstr "--remote-expr <expr>\tÔÚ Vim ·þÎñÆ÷ÉÏÇó <expr> µÄÖµ²¢´òÓ¡½á¹û"
+
+msgid "--serverlist\t\tList available Vim server names and exit"
+msgstr "--serverlist\t\tÁгö¿ÉÓÃµÄ Vim ·þÎñÆ÷Ãû³Æ²¢Í˳ö"
+
+msgid "--servername <name>\tSend to/become the Vim server <name>"
+msgstr "--servername <name>\t·¢Ë͵½»ò³ÉΪ Vim ·þÎñÆ÷ <name>"
+
+msgid "-i <viminfo>\t\tUse <viminfo> instead of .viminfo"
+msgstr "-i <viminfo>\t\tʹÓà <viminfo> È¡´ú .viminfo"
+
+msgid "-h or --help\tPrint Help (this message) and exit"
+msgstr "-h »ò --help\t´òÓ¡°ïÖú(±¾ÐÅÏ¢)²¢Í˳ö"
+
+msgid "--version\t\tPrint version information and exit"
+msgstr "--version\t\t´òÓ¡°æ±¾ÐÅÏ¢²¢Í˳ö"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Motif version):\n"
+msgstr ""
+"\n"
+"gvim (Motif °æ±¾) ¿Éʶ±ðµÄ²ÎÊý:\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (neXtaw version):\n"
+msgstr ""
+"\n"
+"gvim (neXtaw °æ±¾) ¿Éʶ±ðµÄ²ÎÊý:\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Athena version):\n"
+msgstr ""
+"\n"
+"gvim (Athena °æ±¾) ¿Éʶ±ðµÄ²ÎÊý:\n"
+
+msgid "-display <display>\tRun vim on <display>"
+msgstr "-display <display>\tÔÚ <display> ÉÏÔËÐÐ vim"
+
+msgid "-iconic\t\tStart vim iconified"
+msgstr "-iconic\t\tÆô¶¯ºó×îС»¯"
+
+msgid "-name <name>\t\tUse resource as if vim was <name>"
+msgstr "-name <name>\t\t¶ÁÈ¡ Resource ʱ°Ñ vim ÊÓΪ <name>"
+
+msgid "\t\t\t (Unimplemented)\n"
+msgstr "\t\t\t (ÉÐδʵÏÖ)\n"
+
+msgid "-background <color>\tUse <color> for the background (also: -bg)"
+msgstr "-background <color>\tʹÓà <color> ×÷Ϊ±³¾°É« (Ò²¿ÉÓà -bg)"
+
+msgid "-foreground <color>\tUse <color> for normal text (also: -fg)"
+msgstr "-foreground <color>\tʹÓà <color> ×÷Ϊһ°ãÎÄ×ÖÑÕÉ« (Ò²¿ÉÓà -fg)"
+
+msgid "-font <font>\t\tUse <font> for normal text (also: -fn)"
+msgstr "-font <font>\tʹÓà <font> ×÷Ϊһ°ã×ÖÌå (Ò²¿ÉÓà -fn)"
+
+msgid "-boldfont <font>\tUse <font> for bold text"
+msgstr "-boldfont <font>\tʹÓà <font> ×÷Ϊ´ÖÌå×ÖÌå"
+
+msgid "-italicfont <font>\tUse <font> for italic text"
+msgstr "-italicfont <font>\tʹÓà <font> ×÷ΪбÌå×ÖÌå"
+
+msgid "-geometry <geom>\tUse <geom> for initial geometry (also: -geom)"
+msgstr "-geometry <geom>\tʹÓà <geom> ×÷Ϊ³õʼλÖà (Ò²¿ÉÓà -geom)"
+
+msgid "-borderwidth <width>\tUse a border width of <width> (also: -bw)"
+msgstr "-borderwidth <width>\tÉ趨±ß¿ò¿í¶ÈΪ <width> (Ò²¿ÉÓà -bw)"
+
+msgid "-scrollbarwidth <width> Use a scrollbar width of <width> (also: -sw)"
+msgstr "-scrollbarwidth <width> É趨¹ö¶¯Ìõ¿í¶ÈΪ <width> (Ò²¿ÉÓà -sw)"
+
+msgid "-menuheight <height>\tUse a menu bar height of <height> (also: -mh)"
+msgstr "-menuheight <height>\tÉ趨²Ëµ¥À¸¸ß¶ÈΪ <height> (Ò²¿ÉÓà -mh)"
+
+msgid "-reverse\t\tUse reverse video (also: -rv)"
+msgstr "-reverse\t\tʹÓ÷´ÏÔ (Ò²¿ÉÓà -rv)"
+
+msgid "+reverse\t\tDon't use reverse video (also: +rv)"
+msgstr "+reverse\t\t²»Ê¹Ó÷´ÏÔ (Ò²¿ÉÓà +rv)"
+
+msgid "-xrm <resource>\tSet the specified resource"
+msgstr "-xrm <resource>\tÉ趨ָ¶¨µÄ×ÊÔ´"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (RISC OS version):\n"
+msgstr ""
+"\n"
+"gvim (RISC OS °æ±¾) ¿Éʶ±ðµÄ²ÎÊý:\n"
+
+msgid "--columns <number>\tInitial width of window in columns"
+msgstr "--columns <number>\t´°¿Ú³õʼ¿í¶È"
+
+msgid "--rows <number>\tInitial height of window in rows"
+msgstr "--rows <number>\t´°¿Ú³õʼ¸ß¶È"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (GTK+ version):\n"
+msgstr ""
+"\n"
+"gvim (GTK+ °æ±¾) ¿Éʶ±ðµÄ²ÎÊý:\n"
+
+msgid "-display <display>\tRun vim on <display> (also: --display)"
+msgstr "-display <display>\tÔÚ <display> ÉÏÔËÐÐ vim (Ò²¿ÉÓà --display)"
+
+msgid "--role <role>\tSet a unique role to identify the main window"
+msgstr "--role <role>\tÉèÖÃÓÃÓÚÇø·ÖÖ÷´°¿ÚµÄ´°¿Ú½ÇÉ«Ãû"
+
+msgid "--socketid <xid>\tOpen Vim inside another GTK widget"
+msgstr "--socketid <xid>\tÔÚÁíÒ»¸ö GTK ²¿¼þÖдò¿ª Vim"
+
+msgid "-P <parent title>\tOpen Vim inside parent application"
+msgstr "-P <parent title>\tÔÚ¸¸Ó¦ÓóÌÐòÖдò¿ª Vim"
+
+msgid "No display"
+msgstr "ûÓÐ display"
+
+#. Failed to send, abort.
+msgid ": Send failed.\n"
+msgstr ": ·¢ËÍʧ°Ü¡£\n"
+
+#. Let vim start normally.
+msgid ": Send failed. Trying to execute locally\n"
+msgstr ": ·¢ËÍʧ°Ü¡£³¢ÊÔ±¾µØÖ´ÐÐ\n"
+
+#, c-format
+msgid "%d of %d edited"
+msgstr "%d ÖÐ %d Òѱ༭"
+
+msgid "No display: Send expression failed.\n"
+msgstr "ûÓÐ display: ·¢Ëͱí´ïʽʧ°Ü¡£\n"
+
+msgid ": Send expression failed.\n"
+msgstr ": ·¢Ëͱí´ïʽʧ°Ü¡£\n"
+
+msgid "No marks set"
+msgstr "ûÓÐÉ趨±ê¼Ç"
+
+#, c-format
+msgid "E283: No marks matching \"%s\""
+msgstr "E283: ûÓÐÆ¥Åä \"%s\" µÄ±ê¼Ç"
+
+#. Highlight title
+msgid ""
+"\n"
+"mark line col file/text"
+msgstr ""
+"\n"
+"±ê¼Ç ÐÐ ÁÐ Îļþ/Îı¾"
+
+#. Highlight title
+msgid ""
+"\n"
+" jump line col file/text"
+msgstr ""
+"\n"
+" Ìøת ÐÐ ÁÐ Îļþ/Îı¾"
+
+#. Highlight title
+msgid ""
+"\n"
+"change line col text"
+msgstr ""
+"\n"
+" ¸Ä±ä ÐÐ ÁÐ Îı¾"
+
+#, c-format
+msgid ""
+"\n"
+"# File marks:\n"
+msgstr ""
+"\n"
+"# Îļþ±ê¼Ç:\n"
+
+#. Write the jumplist with -'
+#, c-format
+msgid ""
+"\n"
+"# Jumplist (newest first):\n"
+msgstr ""
+"\n"
+"# ÌøתÁбí (´Óе½¾É):\n"
+
+#, c-format
+msgid ""
+"\n"
+"# History of marks within files (newest to oldest):\n"
+msgstr ""
+"\n"
+"# ÎļþÄڵıê¼ÇÀúÊ·¼Ç¼ (´Óе½¾É):\n"
+
+msgid "Missing '>'"
+msgstr "ȱÉÙ '>'"
+
+msgid "E543: Not a valid codepage"
+msgstr "E543: ÎÞЧµÄ´úÂëÒ³"
+
+msgid "E284: Cannot set IC values"
+msgstr "E284: ²»ÄÜÉ趨 IC Öµ"
+
+msgid "E285: Failed to create input context"
+msgstr "E285: ÎÞ·¨´´½¨ÊäÈëÉÏÏÂÎÄ"
+
+msgid "E286: Failed to open input method"
+msgstr "E286: ÎÞ·¨´ò¿ªÊäÈë·¨"
+
+msgid "E287: Warning: Could not set destroy callback to IM"
+msgstr "E287: ¾¯¸æ: ÎÞ·¨É趨ÊäÈë·¨µÄÊͷŻص÷º¯Êý"
+
+msgid "E288: input method doesn't support any style"
+msgstr "E288: ÊäÈë·¨²»Ö§³ÖÈκηç¸ñ"
+
+msgid "E289: input method doesn't support my preedit type"
+msgstr "E289: ÊäÈë·¨²»Ö§³ÖÎÒµÄÔ¤±à¼­ÀàÐÍ"
+
+msgid "E290: over-the-spot style requires fontset"
+msgstr "E290: over-the-spot ·ç¸ñÐèÒª Fontset"
+
+msgid "E291: Your GTK+ is older than 1.2.3. Status area disabled"
+msgstr "E291: ÄãµÄ GTK+ ±È 1.2.3 ¾É¡£×´Ì¬Çø²»¿ÉÓá£"
+
+msgid "E292: Input Method Server is not running"
+msgstr "E292: ÊäÈë·¨·þÎñÆ÷δÔËÐÐ"
+
+msgid "E293: block was not locked"
+msgstr "E293: ¿éδ±»Ëø¶¨"
+
+msgid "E294: Seek error in swap file read"
+msgstr "E294: ½»»»Îļþ¶ÁÈ¡¶¨Î»´íÎó"
+
+msgid "E295: Read error in swap file"
+msgstr "E295: ½»»»Îļþ¶ÁÈ¡´íÎó"
+
+msgid "E296: Seek error in swap file write"
+msgstr "E296: ½»»»ÎļþдÈ붨λ´íÎó"
+
+msgid "E297: Write error in swap file"
+msgstr "E297: ½»»»ÎļþдÈë´íÎó"
+
+msgid "E300: Swap file already exists (symlink attack?)"
+msgstr "E300: ½»»»ÎļþÒÑ´æÔÚ (·ûºÅÁ¬½Ó¹¥»÷£¿)"
+
+msgid "E298: Didn't get block nr 0?"
+msgstr "E298: ÕÒ²»µ½¿é 0£¿"
+
+msgid "E298: Didn't get block nr 1?"
+msgstr "E298: ÕÒ²»µ½¿é 1£¿"
+
+msgid "E298: Didn't get block nr 2?"
+msgstr "E298: ÕÒ²»µ½¿é 2£¿"
+
+#. could not (re)open the swap file, what can we do????
+msgid "E301: Oops, lost the swap file!!!"
+msgstr "E301: àÞ£¬½»»»Îļþ²»¼ûÁË£¡£¡£¡"
+
+msgid "E302: Could not rename swap file"
+msgstr "E302: ÎÞ·¨ÖØÃüÃû½»»»Îļþ"
+
+#, c-format
+msgid "E303: Unable to open swap file for \"%s\", recovery impossible"
+msgstr "E303: ÎÞ·¨´ò¿ª \"%s\" µÄ½»»»Îļþ£¬»Ö¸´½«²»¿ÉÄÜ"
+
+msgid "E304: ml_upd_block0(): Didn't get block 0??"
+msgstr "E304: ml_upd_block0(): ÕÒ²»µ½¿é 0£¿"
+
+#, c-format
+msgid "E305: No swap file found for %s"
+msgstr "E305: ÕÒ²»µ½ %s µÄ½»»»Îļþ"
+
+msgid "Enter number of swap file to use (0 to quit): "
+msgstr "ÇëÊäÈëҪʹÓõĽ»»»Îļþ±àºÅ (0 Í˳ö): "
+
+#, c-format
+msgid "E306: Cannot open %s"
+msgstr "E306: ÎÞ·¨´ò¿ª %s"
+
+msgid "Unable to read block 0 from "
+msgstr "ÎÞ·¨¶ÁÈ¡¿é 0: "
+
+msgid ""
+"\n"
+"Maybe no changes were made or Vim did not update the swap file."
+msgstr ""
+"\n"
+"¿ÉÄÜÄãû×ö¹ýÈκÎÐ޸ĻòÊÇ Vim »¹À´²»¼°¸üн»»»Îļþ¡£"
+
+msgid " cannot be used with this version of Vim.\n"
+msgstr " ²»ÄÜÔڸð汾µÄ Vim ÖÐʹÓá£\n"
+
+msgid "Use Vim version 3.0.\n"
+msgstr "ʹÓà Vim 3.0¡£\n"
+
+#, c-format
+msgid "E307: %s does not look like a Vim swap file"
+msgstr "E307: %s ¿´ÆðÀ´²»ÏñÊÇ Vim ½»»»Îļþ"
+
+msgid " cannot be used on this computer.\n"
+msgstr " ²»ÄÜÔÚÕą̂µçÄÔÉÏʹÓá£\n"
+
+msgid "The file was created on "
+msgstr "´ËÎļþ´´½¨ÓÚ "
+
+msgid ""
+",\n"
+"or the file has been damaged."
+msgstr ""
+"£¬\n"
+"»òÊÇ´ËÎļþÒÑË𻵡£"
+
+#, c-format
+msgid "Using swap file \"%s\""
+msgstr "ʹÓý»»»Îļþ \"%s\""
+
+#, c-format
+msgid "Original file \"%s\""
+msgstr "ԭʼÎļþ \"%s\""
+
+msgid "E308: Warning: Original file may have been changed"
+msgstr "E308: ¾¯¸æ: ԭʼÎļþ¿ÉÄÜÒѱ»ÐÞ¸Ä"
+
+#, c-format
+msgid "E309: Unable to read block 1 from %s"
+msgstr "E309: ÎÞ·¨´Ó %s ¶ÁÈ¡¿é 1"
+
+# do not translate to avoid writing Chinese in files
+#, fuzzy
+#~ msgid "???MANY LINES MISSING"
+#~ msgstr "???ȱÉÙÁËÌ«¶àÐÐ"
+
+# do not translate to avoid writing Chinese in files
+#, fuzzy
+#~ msgid "???LINE COUNT WRONG"
+#~ msgstr "???ÐÐÊý´íÎó"
+
+# do not translate to avoid writing Chinese in files
+#, fuzzy
+#~ msgid "???EMPTY BLOCK"
+#~ msgstr "???¿ÕµÄ¿é"
+
+# do not translate to avoid writing Chinese in files
+#, fuzzy
+#~ msgid "???LINES MISSING"
+#~ msgstr "???ȱÉÙÁËһЩÐÐ"
+
+#, c-format
+msgid "E310: Block 1 ID wrong (%s not a .swp file?)"
+msgstr "E310: ¿é 1 ID ´íÎó (%s ²»Êǽ»»»Îļþ£¿)"
+
+# do not translate to avoid writing Chinese in files
+#, fuzzy
+#~ msgid "???BLOCK MISSING"
+#~ msgstr "???ȱÉÙ¿é"
+
+# do not translate to avoid writing Chinese in files
+#, fuzzy
+#~ msgid "??? from here until ???END lines may be messed up"
+#~ msgstr "??? ´ÓÕâÀïµ½ ???END µÄÐпÉÄÜÒÑ»ìÂÒ"
+
+# do not translate to avoid writing Chinese in files
+#, fuzzy
+#~ msgid "??? from here until ???END lines may have been inserted/deleted"
+#~ msgstr "??? ´ÓÕâÀïµ½ ???END µÄÐпÉÄÜÒѱ»²åÈë/ɾ³ý¹ý"
+
+# do not translate to avoid writing Chinese in files
+#, fuzzy
+#~ msgid "???END"
+#~ msgstr "???END"
+
+msgid "E311: Recovery Interrupted"
+msgstr "E311: »Ö¸´Òѱ»ÖжÏ"
+
+msgid ""
+"E312: Errors detected while recovering; look for lines starting with ???"
+msgstr "E312: »Ö¸´Ê±·¢Éú´íÎó£»Çë×¢Ò⿪ͷΪ ??? µÄÐÐ"
+
+msgid "See \":help E312\" for more information."
+msgstr "¸ü¶àÐÅÏ¢Çë¼û \":help E312\""
+
+msgid "Recovery completed. You should check if everything is OK."
+msgstr "»Ö¸´Íê±Ï¡£ÇëÈ·¶¨Ò»ÇÐÕý³£¡£"
+
+msgid ""
+"\n"
+"(You might want to write out this file under another name\n"
+msgstr ""
+"\n"
+"(Äã¿ÉÄÜÏëÒª½«Õâ¸öÎļþÁí´æΪ±ðµÄÎļþÃû\n"
+
+msgid "and run diff with the original file to check for changes)\n"
+msgstr "ÔÙÔËÐÐ diff ÓëÔ­Îļþ±È½ÏÒÔ¼ì²éÊÇ·ñÓиıä)\n"
+
+msgid ""
+"Delete the .swp file afterwards.\n"
+"\n"
+msgstr ""
+"È»ºó°Ñ .swp Îļþɾµô¡£\n"
+"\n"
+
+#. use msg() to start the scrolling properly
+msgid "Swap files found:"
+msgstr "ÕÒµ½½»»»Îļþ:"
+
+msgid " In current directory:\n"
+msgstr " λÓÚµ±Ç°Ä¿Â¼:\n"
+
+msgid " Using specified name:\n"
+msgstr " ʹÓÃÖ¸¶¨µÄÃû×Ö:\n"
+
+msgid " In directory "
+msgstr " λÓÚĿ¼ "
+
+msgid " -- none --\n"
+msgstr " -- ÎÞ --\n"
+
+msgid " owned by: "
+msgstr " ËùÓÐÕß: "
+
+msgid " dated: "
+msgstr " ÈÕÆÚ: "
+
+msgid " dated: "
+msgstr " ÈÕÆÚ: "
+
+msgid " [from Vim version 3.0]"
+msgstr " [À´×Ô Vim °æ±¾ 3.0]"
+
+msgid " [does not look like a Vim swap file]"
+msgstr " [²»ÏñÊÇ Vim ½»»»Îļþ]"
+
+msgid " file name: "
+msgstr " ÎļþÃû: "
+
+msgid ""
+"\n"
+" modified: "
+msgstr ""
+"\n"
+" Ð޸Ĺý: "
+
+msgid "YES"
+msgstr "ÊÇ"
+
+msgid "no"
+msgstr "·ñ"
+
+msgid ""
+"\n"
+" user name: "
+msgstr ""
+"\n"
+" ̞: "
+
+msgid " host name: "
+msgstr " Ö÷»úÃû: "
+
+msgid ""
+"\n"
+" host name: "
+msgstr ""
+"\n"
+" Ö÷»úÃû: "
+
+msgid ""
+"\n"
+" process ID: "
+msgstr ""
+"\n"
+" ½ø³Ì ID: "
+
+msgid " (still running)"
+msgstr " (ÈÔÔÚÔËÐÐ)"
+
+msgid ""
+"\n"
+" [not usable with this version of Vim]"
+msgstr ""
+"\n"
+" [²»ÄÜÔڸð汾µÄ Vim ÉÏʹÓÃ]"
+
+msgid ""
+"\n"
+" [not usable on this computer]"
+msgstr ""
+"\n"
+" [²»ÄÜÔÚ±¾»úÉÏʹÓÃ]"
+
+msgid " [cannot be read]"
+msgstr " [ÎÞ·¨¶ÁÈ¡]"
+
+msgid " [cannot be opened]"
+msgstr " [ÎÞ·¨´ò¿ª]"
+
+msgid "E313: Cannot preserve, there is no swap file"
+msgstr "E313: ÎÞ·¨±£Áô£¬Ã»Óн»»»Îļþ"
+
+msgid "File preserved"
+msgstr "ÎļþÒѱ£Áô"
+
+msgid "E314: Preserve failed"
+msgstr "E314: ±£Áôʧ°Ü"
+
+#, c-format
+msgid "E315: ml_get: invalid lnum: %ld"
+msgstr "E315: ml_get: ÎÞЧµÄ lnum: %ld"
+
+#, c-format
+msgid "E316: ml_get: cannot find line %ld"
+msgstr "E316: ml_get: ÕÒ²»µ½µÚ %ld ÐÐ"
+
+msgid "E317: pointer block id wrong 3"
+msgstr "E317: Ö¸Õë¿é id ´íÎó 3"
+
+msgid "stack_idx should be 0"
+msgstr "stack_idx Ó¦¸ÃÊÇ 0"
+
+msgid "E318: Updated too many blocks?"
+msgstr "E318: ¸üÐÂÁËÌ«¶àµÄ¿é£¿"
+
+msgid "E317: pointer block id wrong 4"
+msgstr "E317: Ö¸Õë¿é id ´íÎó 4"
+
+msgid "deleted block 1?"
+msgstr "ɾ³ýÁË¿é 1£¿"
+
+#, c-format
+msgid "E320: Cannot find line %ld"
+msgstr "E320: ÕÒ²»µ½µÚ %ld ÐÐ"
+
+msgid "E317: pointer block id wrong"
+msgstr "E317: Ö¸Õë¿é id ´íÎó"
+
+msgid "pe_line_count is zero"
+msgstr "pe_line_count ΪÁã"
+
+#, c-format
+msgid "E322: line number out of range: %ld past the end"
+msgstr "E322: Ðкų¬³ö·¶Î§: %ld ³¬³ö½áβ"
+
+#, c-format
+msgid "E323: line count wrong in block %ld"
+msgstr "E323: ¿é %ld ÐÐÊý´íÎó"
+
+msgid "Stack size increases"
+msgstr "¶ÑÕ»´óСÔö¼Ó"
+
+msgid "E317: pointer block id wrong 2"
+msgstr "E317: Ö¸Õë¿é id ´íÎó 2"
+
+#, c-format
+msgid "E773: Symlink loop for \"%s\""
+msgstr "E773: \"%s\" ·ûºÅÁ¬½Ó³öÏÖÑ­»·"
+
+msgid "E325: ATTENTION"
+msgstr "E325: ×¢Òâ"
+
+msgid ""
+"\n"
+"Found a swap file by the name \""
+msgstr ""
+"\n"
+"·¢ÏÖ½»»»Îļþ \""
+
+msgid "While opening file \""
+msgstr "ÕýÔÚ´ò¿ªÎļþ \""
+
+msgid " NEWER than swap file!\n"
+msgstr " ±È½»»»ÎļþУ¡\n"
+
+#. Some of these messages are long to allow translation to
+#. * other languages.
+msgid ""
+"\n"
+"(1) Another program may be editing the same file.\n"
+" If this is the case, be careful not to end up with two\n"
+" different instances of the same file when making changes.\n"
+msgstr ""
+"\n"
+"(1) ÁíÒ»¸ö³ÌÐò¿ÉÄÜÒ²Ôڱ༭ͬһ¸öÎļþ¡£\n"
+" Èç¹ûÊÇÕâÑù£¬ÐÞ¸ÄʱÇë×¢Òâ±ÜÃâͬһ¸öÎļþ²úÉúÁ½¸ö²»Í¬µÄ°æ±¾¡£\n"
+"\n"
+
+msgid " Quit, or continue with caution.\n"
+msgstr " Í˳ö£¬»òСÐĵؼÌÐø¡£\n"
+
+msgid ""
+"\n"
+"(2) An edit session for this file crashed.\n"
+msgstr ""
+"\n"
+"(2) Éϴα༭´ËÎļþʱ±ÀÀ£¡£\n"
+
+msgid " If this is the case, use \":recover\" or \"vim -r "
+msgstr " Èç¹ûÊÇÕâÑù£¬ÇëÓà \":recover\" »ò \"vim -r "
+
+msgid ""
+"\"\n"
+" to recover the changes (see \":help recovery\").\n"
+msgstr ""
+"\"\n"
+" »Ö¸´Ð޸ĵÄÄÚÈÝ (Çë¼û \":help recovery\")¡£\n"
+
+msgid " If you did this already, delete the swap file \""
+msgstr " Èç¹ûÄãÒѾ­½øÐÐÁ˻ָ´£¬Çëɾ³ý½»»»Îļþ \""
+
+msgid ""
+"\"\n"
+" to avoid this message.\n"
+msgstr ""
+"\"\n"
+" ÒÔ±ÜÃâÔÙ¿´µ½´ËÏûÏ¢¡£\n"
+
+msgid "Swap file \""
+msgstr "½»»»Îļþ \""
+
+msgid "\" already exists!"
+msgstr "\" ÒÑ´æÔÚ£¡"
+
+msgid "VIM - ATTENTION"
+msgstr "VIM - ×¢Òâ"
+
+msgid "Swap file already exists!"
+msgstr "½»»»ÎļþÒÑ´æÔÚ£¡"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"ÒÔÖ»¶Á·½Ê½´ò¿ª(&O)\n"
+"Ö±½Ó±à¼­(&E)\n"
+"»Ö¸´(&R)\n"
+"Í˳ö(&Q)\n"
+"ÖÐÖ¹(&A)"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Delete it\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"ÒÔÖ»¶Á·½Ê½´ò¿ª(&O)\n"
+"Ö±½Ó±à¼­(&E)\n"
+"»Ö¸´(&R)\n"
+"ɾ³ý½»»»Îļþ(&D)\n"
+"Í˳ö(&Q)\n"
+"ÖÐÖ¹(&A)"
+
+msgid "E326: Too many swap files found"
+msgstr "E326: ÕÒµ½Ì«¶à½»»»Îļþ"
+
+msgid "E327: Part of menu-item path is not sub-menu"
+msgstr "E327: ²Ëµ¥ÏîµÄij²¿·Ö·¾¶²»ÊÇ×Ӳ˵¥"
+
+msgid "E328: Menu only exists in another mode"
+msgstr "E328: ²Ëµ¥Ö»ÔÚÆäËüģʽÖдæÔÚ"
+
+#, c-format
+msgid "E329: No menu \"%s\""
+msgstr "E329: ûÓв˵¥ \"%s\""
+
+msgid "E330: Menu path must not lead to a sub-menu"
+msgstr "E330: ²Ëµ¥Â·¾¶²»ÄÜÖ¸Ïò×Ӳ˵¥"
+
+msgid "E331: Must not add menu items directly to menu bar"
+msgstr "E331: ²»ÄܰѲ˵¥ÏîÖ±½Ó¼Óµ½²Ëµ¥À¸ÖÐ"
+
+msgid "E332: Separator cannot be part of a menu path"
+msgstr "E332: ·Ö¸ôÏß²»ÄÜÊDz˵¥Â·¾¶µÄÒ»²¿·Ö"
+
+#. Now we have found the matching menu, and we list the mappings
+#. Highlight title
+msgid ""
+"\n"
+"--- Menus ---"
+msgstr ""
+"\n"
+"--- ²Ëµ¥ ---"
+
+msgid "Tear off this menu"
+msgstr "˺Ï´˲˵¥"
+
+msgid "E333: Menu path must lead to a menu item"
+msgstr "E333: ²Ëµ¥Â·¾¶±ØÐëÖ¸Ïò²Ëµ¥Ïî"
+
+#, c-format
+msgid "E334: Menu not found: %s"
+msgstr "E334: ÕÒ²»µ½²Ëµ¥: %s"
+
+#, c-format
+msgid "E335: Menu not defined for %s mode"
+msgstr "E335: %s ģʽÖв˵¥Î´¶¨Òå"
+
+msgid "E336: Menu path must lead to a sub-menu"
+msgstr "E336: ²Ëµ¥Â·¾¶±ØÐëÖ¸Ïò×Ӳ˵¥"
+
+msgid "E337: Menu not found - check menu names"
+msgstr "E337: ÕÒ²»µ½²Ëµ¥ - Çë¼ì²é²Ëµ¥Ãû³Æ"
+
+#, c-format
+msgid "Error detected while processing %s:"
+msgstr "´¦Àí %s ʱ·¢Éú´íÎó:"
+
+#, c-format
+msgid "line %4ld:"
+msgstr "µÚ %4ld ÐÐ:"
+
+#, c-format
+msgid "E354: Invalid register name: '%s'"
+msgstr "E354: ÎÞЧµÄ¼Ä´æÆ÷Ãû: '%s'"
+
+msgid "Messages maintainer: Bram Moolenaar <Bram@vim.org>"
+msgstr "¼òÌåÖÐÎÄÏûϢά»¤Õß: Yuheng Xie <elephant@linux.net.cn>"
+
+msgid "Interrupt: "
+msgstr "ÒÑÖжÏ: "
+
+msgid "Press ENTER or type command to continue"
+msgstr "Çë°´ ENTER »òÆäËüÃüÁî¼ÌÐø"
+
+#, c-format
+msgid "%s line %ld"
+msgstr "%s µÚ %ld ÐÐ"
+
+msgid "-- More --"
+msgstr "-- ¸ü¶à --"
+
+msgid " SPACE/d/j: screen/page/line down, b/u/k: up, q: quit "
+msgstr " ¿Õ¸ñ/d/j: ÆÁÄ»/Ò³/ÐÐ Ï·­£¬b/u/k: ÉÏ·­£¬q: Í˳ö "
+
+msgid "Question"
+msgstr "ÎÊÌâ"
+
+msgid ""
+"&Yes\n"
+"&No"
+msgstr ""
+"ÊÇ(&Y)\n"
+"·ñ(&N)"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"Save &All\n"
+"&Discard All\n"
+"&Cancel"
+msgstr ""
+"ÊÇ(&Y)\n"
+"·ñ(&N)\n"
+"È«²¿±£´æ(&A)\n"
+"È«²¿¶ªÆú(&D)\n"
+"È¡Ïû(&C)"
+
+msgid "Select Directory dialog"
+msgstr "Ñ¡ÔñĿ¼¶Ô»°¿ò"
+
+msgid "Save File dialog"
+msgstr "±£´æÎļþ¶Ô»°¿ò"
+
+msgid "Open File dialog"
+msgstr "´ò¿ªÎļþ¶Ô»°¿ò"
+
+#. TODO: non-GUI file selector here
+msgid "E338: Sorry, no file browser in console mode"
+msgstr "E338: ±§Ç¸£¬¿ØÖÆ̨ģʽÏÂûÓÐÎļþä¯ÀÀÆ÷"
+
+msgid "E766: Insufficient arguments for printf()"
+msgstr "E766: printf() µÄ²ÎÊý²»×ã"
+
+msgid "E767: Too many arguments to printf()"
+msgstr "E767: printf() µÄ²ÎÊý¹ý¶à"
+
+msgid "W10: Warning: Changing a readonly file"
+msgstr "W10: ¾¯¸æ: ÕýÔÚÐÞ¸ÄÒ»¸öÖ»¶ÁÎļþ"
+
+msgid "Type number or click with mouse (<Enter> cancels): "
+msgstr "ÇëÊäÈëÊý×Ö»òµã»÷Êó±ê (<Enter> È¡Ïû): "
+
+msgid "Choice number (<Enter> cancels): "
+msgstr "ÇëÑ¡ÔñÊý×Ö (<Enter> È¡Ïû): "
+
+msgid "1 more line"
+msgstr "¶àÁË 1 ÐÐ"
+
+msgid "1 line less"
+msgstr "ÉÙÁË 1 ÐÐ"
+
+#, c-format
+msgid "%ld more lines"
+msgstr "¶àÁË %ld ÐÐ"
+
+#, c-format
+msgid "%ld fewer lines"
+msgstr "ÉÙÁË %ld ÐÐ"
+
+msgid " (Interrupted)"
+msgstr " (ÒÑÖжÏ)"
+
+msgid "Beep!"
+msgstr "Beep!"
+
+msgid "Vim: preserving files...\n"
+msgstr "Vim: ÕýÔÚ±£ÁôÎļþ¡­¡­\n"
+
+#. close all memfiles, without deleting
+msgid "Vim: Finished.\n"
+msgstr "Vim: ½áÊø¡£\n"
+
+#, c-format
+msgid "ERROR: "
+msgstr "´íÎó: "
+
+#, c-format
+msgid ""
+"\n"
+"[bytes] total alloc-freed %lu-%lu, in use %lu, peak use %lu\n"
+msgstr ""
+"\n"
+"[×Ö½Ú] ×ܹ² alloc-free %lu-%lu£¬Ê¹ÓÃÖÐ %lu£¬¸ß·åʹÓà %lu\n"
+
+#, c-format
+msgid ""
+"[calls] total re/malloc()'s %lu, total free()'s %lu\n"
+"\n"
+msgstr ""
+"[µ÷ÓÃ] ×ܹ² re/malloc(): %lu£¬×ܹ² free()': %lu\n"
+"\n"
+
+msgid "E340: Line is becoming too long"
+msgstr "E340: ´ËÐйý³¤"
+
+#, c-format
+msgid "E341: Internal error: lalloc(%ld, )"
+msgstr "E341: ÄÚ²¿´íÎó: lalloc(%ld, )"
+
+#, c-format
+msgid "E342: Out of memory! (allocating %lu bytes)"
+msgstr "E342: ÄÚ´æ²»×㣡(·ÖÅä %lu ×Ö½Ú)"
+
+#, c-format
+msgid "Calling shell to execute: \"%s\""
+msgstr "µ÷ÓÃ shell Ö´ÐÐ: \"%s\""
+
+msgid "E545: Missing colon"
+msgstr "E545: ȱÉÙðºÅ"
+
+msgid "E546: Illegal mode"
+msgstr "E546: ÎÞЧµÄģʽ"
+
+msgid "E547: Illegal mouseshape"
+msgstr "E547: ÎÞЧµÄÊó±êÐÎ×´"
+
+msgid "E548: digit expected"
+msgstr "E548: ´Ë´¦ÐèÒªÊý×Ö"
+
+msgid "E549: Illegal percentage"
+msgstr "E549: ÎÞЧµÄ°Ù·Ö±È"
+
+msgid "Enter encryption key: "
+msgstr "ÊäÈëÃÜÂë: "
+
+msgid "Enter same key again: "
+msgstr "ÇëÔÙÊäÈëÒ»´Î: "
+
+msgid "Keys don't match!"
+msgstr "Á½´ÎÃÜÂ벻ƥÅ䣡"
+
+#, c-format
+msgid ""
+"E343: Invalid path: '**[number]' must be at the end of the path or be "
+"followed by '%s'."
+msgstr "E343: ÎÞЧµÄ·¾¶: '**[number]' ±ØÐëÔÚ·¾¶Ä©Î²»òÕߺóÃæ½Ó '%s'¡£"
+
+#, c-format
+msgid "E344: Can't find directory \"%s\" in cdpath"
+msgstr "E344: cdpath ÖÐÕÒ²»µ½Ä¿Â¼ \"%s\""
+
+#, c-format
+msgid "E345: Can't find file \"%s\" in path"
+msgstr "E345: ÔÚ·¾¶ÖÐÕÒ²»µ½Îļþ \"%s\""
+
+#, c-format
+msgid "E346: No more directory \"%s\" found in cdpath"
+msgstr "E346: ÔÚ·¾¶ÖÐÕÒ²»µ½¸ü¶àµÄÎļþ \"%s\""
+
+#, c-format
+msgid "E347: No more file \"%s\" found in path"
+msgstr "E347: ÔÚ·¾¶ÖÐÕÒ²»µ½¸ü¶àµÄÎļþ \"%s\""
+
+#. Get here when the server can't be found.
+msgid "Cannot connect to Netbeans #2"
+msgstr "ÎÞ·¨Á¬½Óµ½ Netbeans #2"
+
+msgid "Cannot connect to Netbeans"
+msgstr "ÎÞ·¨Á¬½Óµ½ Netbeans"
+
+#, c-format
+msgid "E668: Wrong access mode for NetBeans connection info file: \"%s\""
+msgstr "E668: NetBeans Á¬½ÓÐÅÏ¢ÎļþÖдíÎóµÄ·ÃÎÊģʽ: \"%s\""
+
+msgid "read from Netbeans socket"
+msgstr "´Ó Netbeans Ì×½Ó×Ö¶ÁÈ¡"
+
+#, c-format
+msgid "E658: NetBeans connection lost for buffer %ld"
+msgstr "E658: »º³åÇø %ld ¶ªÊ§ NetBeans Á¬½Ó"
+
+msgid "E505: "
+msgstr "E505: "
+
+msgid "E774: 'operatorfunc' is empty"
+msgstr "E774: 'operatorfunc' Ϊ¿Õ"
+
+msgid "E775: Eval feature not available"
+msgstr "E775: ÇóÖµ¹¦Äܲ»¿ÉÓÃ"
+
+msgid "Warning: terminal cannot highlight"
+msgstr "¾¯¸æ: ÄãµÄÖն˲»ÄÜÏÔʾ¸ßÁÁ"
+
+msgid "E348: No string under cursor"
+msgstr "E348: ¹â±ê´¦Ã»ÓÐ×Ö·û´®"
+
+msgid "E349: No identifier under cursor"
+msgstr "E349: ¹â±ê´¦Ã»ÓÐʶ±ð×Ö"
+
+msgid "E352: Cannot erase folds with current 'foldmethod'"
+msgstr "E352: ²»ÄÜÔÚµ±Ç°µÄ 'foldmethod' ÏÂɾ³ý fold"
+
+msgid "E664: changelist is empty"
+msgstr "E664: ¸Ä±äÁбíΪ¿Õ"
+
+msgid "E662: At start of changelist"
+msgstr "E662: ÒÑÔڸıäÁбíµÄ¿ªÊ¼´¦"
+
+msgid "E663: At end of changelist"
+msgstr "E663: ÒÑÔڸıäÁбíµÄĩβ´¦"
+
+msgid "Type :quit<Enter> to exit Vim"
+msgstr "ÊäÈë :quit<Enter> Í˳ö Vim"
+
+#, c-format
+msgid "1 line %sed 1 time"
+msgstr "1 ÐÐ %s ÁË 1 ´Î"
+
+#, c-format
+msgid "1 line %sed %d times"
+msgstr "1 ÐÐ %s ÁË %d ´Î"
+
+#, c-format
+msgid "%ld lines %sed 1 time"
+msgstr "%ld ÐÐ %s ÁË 1 ´Î"
+
+#, c-format
+msgid "%ld lines %sed %d times"
+msgstr "%ld ÐÐ %s ÁË %d ´Î"
+
+#, c-format
+msgid "%ld lines to indent... "
+msgstr "Ëõ½ø %ld ÐС­¡­ "
+
+msgid "1 line indented "
+msgstr "Ëõ½øÁË 1 ÐÐ "
+
+#, c-format
+msgid "%ld lines indented "
+msgstr "Ëõ½øÁË %ld ÐÐ "
+
+msgid "E748: No previously used register"
+msgstr "E748: ûÓÐÇ°Ò»¸öʹÓõļĴæÆ÷"
+
+#. must display the prompt
+msgid "cannot yank; delete anyway"
+msgstr "ÎÞ·¨¸´ÖÆ£»¸ÄΪɾ³ý"
+
+msgid "1 line changed"
+msgstr "¸Ä±äÁË 1 ÐÐ"
+
+#, c-format
+msgid "%ld lines changed"
+msgstr "¸Ä±äÁË %ld ÐÐ"
+
+#, c-format
+msgid "freeing %ld lines"
+msgstr "ÊÍ·ÅÁË %ld ÐÐ"
+
+msgid "block of 1 line yanked"
+msgstr "¸´ÖÆÁË 1 ÐеĿé"
+
+msgid "1 line yanked"
+msgstr "¸´ÖÆÁË 1 ÐÐ"
+
+#, c-format
+msgid "block of %ld lines yanked"
+msgstr "¸´ÖÆÁË %ld ÐеĿé"
+
+#, c-format
+msgid "%ld lines yanked"
+msgstr "¸´ÖÆÁË %ld ÐÐ"
+
+#, c-format
+msgid "E353: Nothing in register %s"
+msgstr "E353: ¼Ä´æÆ÷ %s ÀïûÓж«Î÷"
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Registers ---"
+msgstr ""
+"\n"
+"--- ¼Ä´æÆ÷ ---"
+
+msgid "Illegal register name"
+msgstr "ÎÞЧµÄ¼Ä´æÆ÷Ãû"
+
+#, c-format
+msgid ""
+"\n"
+"# Registers:\n"
+msgstr ""
+"\n"
+"# ¼Ä´æÆ÷:\n"
+
+#, c-format
+msgid "E574: Unknown register type %d"
+msgstr "E574: δ֪µÄ¼Ä´æÆ÷ÀàÐÍ %d"
+
+#, c-format
+msgid "%ld Cols; "
+msgstr "%ld ÁÐ; "
+
+#, c-format
+msgid "Selected %s%ld of %ld Lines; %ld of %ld Words; %ld of %ld Bytes"
+msgstr "Ñ¡ÔñÁË %s%ld/%ld ÐÐ; %ld/%ld ¸ö´Ê; %ld/%ld ¸ö×Ö½Ú"
+
+#, c-format
+msgid ""
+"Selected %s%ld of %ld Lines; %ld of %ld Words; %ld of %ld Chars; %ld of %ld "
+"Bytes"
+msgstr "Ñ¡ÔñÁË %s%ld/%ld ÐÐ; %ld/%ld ¸ö´Ê; %ld/%ld ¸ö×Ö·û; %ld/%ld ¸ö×Ö½Ú"
+
+#, c-format
+msgid "Col %s of %s; Line %ld of %ld; Word %ld of %ld; Byte %ld of %ld"
+msgstr "µÚ %s/%s ÁÐ; µÚ %ld/%ld ÐÐ; µÚ %ld/%ld ¸ö´Ê; µÚ %ld/%ld ¸ö×Ö½Ú"
+
+#, c-format
+msgid ""
+"Col %s of %s; Line %ld of %ld; Word %ld of %ld; Char %ld of %ld; Byte %ld of "
+"%ld"
+msgstr ""
+"µÚ %s/%s ÁÐ; µÚ %ld/%ld ÐÐ; µÚ %ld/%ld ¸ö´Ê; µÚ %ld/%ld ¸ö×Ö·û; µÚ %ld/%ld ¸ö"
+"×Ö½Ú"
+
+#, c-format
+#~ msgid "(+%ld for BOM)"
+#~ msgstr ""
+
+#~ msgid "%<%f%h%m%=Page %N"
+#~ msgstr ""
+
+msgid "Thanks for flying Vim"
+msgstr "¸ÐлÄúÑ¡Ôñ Vim"
+
+msgid "E518: Unknown option"
+msgstr "E518: δ֪µÄÑ¡Ïî"
+
+msgid "E519: Option not supported"
+msgstr "E519: ²»Ö§³Ö¸ÃÑ¡Ïî"
+
+msgid "E520: Not allowed in a modeline"
+msgstr "E520: ²»ÔÊÐíÔÚ modeline ÖÐʹÓÃ"
+
+msgid "E521: Number required after ="
+msgstr "E521: = ºóÃæÐèÒªÊý×Ö"
+
+msgid "E522: Not found in termcap"
+msgstr "E522: Termcap ÀïÃæÕÒ²»µ½"
+
+#, c-format
+msgid "E539: Illegal character <%s>"
+msgstr "E539: ÎÞЧµÄ×Ö·û <%s>"
+
+msgid "E529: Cannot set 'term' to empty string"
+msgstr "E529: ²»ÄÜÉ趨 'term' Ϊ¿Õ×Ö·û´®"
+
+msgid "E530: Cannot change term in GUI"
+msgstr "E530: ÔÚͼÐνçÃæÖв»ÄܸıäÖÕ¶Ë"
+
+msgid "E531: Use \":gui\" to start the GUI"
+msgstr "E531: ÇëÓà \":gui\" Æô¶¯Í¼ÐνçÃæ"
+
+msgid "E589: 'backupext' and 'patchmode' are equal"
+msgstr "E589: 'backupext' ºÍ 'patchmode' ÏàµÈ"
+
+msgid "E617: Cannot be changed in the GTK+ 2 GUI"
+msgstr "E617: ÔÚ GTK+ 2 ͼÐνçÃæÖв»Äܸü¸Ä"
+
+msgid "E524: Missing colon"
+msgstr "E524: ȱÉÙðºÅ"
+
+msgid "E525: Zero length string"
+msgstr "E525: ×Ö·û´®³¤¶ÈΪÁã"
+
+#, c-format
+msgid "E526: Missing number after <%s>"
+msgstr "E526: <%s> ºóÃæȱÉÙÊý×Ö"
+
+msgid "E527: Missing comma"
+msgstr "E527: ȱÉÙ¶ººÅ"
+
+msgid "E528: Must specify a ' value"
+msgstr "E528: ±ØÐëÖ¸¶¨Ò»¸ö ' Öµ"
+
+msgid "E595: contains unprintable or wide character"
+msgstr "E595: °üº¬²»¿ÉÏÔʾ×Ö·û»ò¿í×Ö·û"
+
+msgid "E596: Invalid font(s)"
+msgstr "E596: ÎÞЧµÄ×ÖÌå"
+
+msgid "E597: can't select fontset"
+msgstr "E597: ÎÞ·¨Ñ¡Ôñ Fontset"
+
+msgid "E598: Invalid fontset"
+msgstr "E598: ÎÞЧµÄ Fontset"
+
+msgid "E533: can't select wide font"
+msgstr "E533: ÎÞ·¨Ñ¡Ôñ¿í×ÖÌå"
+
+msgid "E534: Invalid wide font"
+msgstr "E534: ÎÞЧµÄ¿í×ÖÌå"
+
+#, c-format
+msgid "E535: Illegal character after <%c>"
+msgstr "E535: <%c> ºóÃæÓÐÎÞЧµÄ×Ö·û"
+
+msgid "E536: comma required"
+msgstr "E536: ÐèÒª¶ººÅ"
+
+#, c-format
+msgid "E537: 'commentstring' must be empty or contain %s"
+msgstr "E537: 'commentstring' ±ØÐëΪ¿Õ»ò°üº¬ %s"
+
+msgid "E538: No mouse support"
+msgstr "E538: ²»Ö§³ÖÊó±ê"
+
+msgid "E540: Unclosed expression sequence"
+msgstr "E540: ûÓнáÊøµÄ±í´ïʽÐòÁÐ"
+
+msgid "E541: too many items"
+msgstr "E541: ÏîÄ¿¹ý¶à"
+
+msgid "E542: unbalanced groups"
+msgstr "E542: ´íÂÒµÄ×é"
+
+msgid "E590: A preview window already exists"
+msgstr "E590: Ô¤ÀÀ´°¿ÚÒÑ´æÔÚ"
+
+msgid "W17: Arabic requires UTF-8, do ':set encoding=utf-8'"
+msgstr "W17: Arabic ÐèÒª UTF-8£¬ÇëÖ´ÐÐ ':set encoding=utf-8'"
+
+#, c-format
+msgid "E593: Need at least %d lines"
+msgstr "E593: ÖÁÉÙÐèÒª %d ÐÐ"
+
+#, c-format
+msgid "E594: Need at least %d columns"
+msgstr "E594: ÖÁÉÙÐèÒª %d ÁÐ"
+
+#, c-format
+msgid "E355: Unknown option: %s"
+msgstr "E355: δ֪µÄÑ¡Ïî: %s"
+
+msgid ""
+"\n"
+"--- Terminal codes ---"
+msgstr ""
+"\n"
+"--- Öն˱àÂë ---"
+
+msgid ""
+"\n"
+"--- Global option values ---"
+msgstr ""
+"\n"
+"--- È«¾ÖÑ¡ÏîÖµ ---"
+
+msgid ""
+"\n"
+"--- Local option values ---"
+msgstr ""
+"\n"
+"--- ¾Ö²¿Ñ¡ÏîÖµ ---"
+
+msgid ""
+"\n"
+"--- Options ---"
+msgstr ""
+"\n"
+"--- Ñ¡Ïî ---"
+
+msgid "E356: get_varp ERROR"
+msgstr "E356: get_varp ´íÎó"
+
+#, c-format
+msgid "E357: 'langmap': Matching character missing for %s"
+msgstr "E357: 'langmap': ÕÒ²»µ½ %s ¶ÔÓ¦µÄ×Ö·û"
+
+#, c-format
+msgid "E358: 'langmap': Extra characters after semicolon: %s"
+msgstr "E358: 'langmap': ·ÖºÅºóÓжàÓàµÄ×Ö·û: %s"
+
+msgid "cannot open "
+msgstr "²»ÄÜ´ò¿ª"
+
+msgid "VIM: Can't open window!\n"
+msgstr "VIM: ²»ÄÜ´ò¿ª´°¿Ú!\n"
+
+msgid "Need Amigados version 2.04 or later\n"
+msgstr "ÐèÒª Amigados °æ±¾ 2.04 ÒÔÉÏ\n"
+
+#, c-format
+msgid "Need %s version %ld\n"
+msgstr "ÐèÒª %s °æ±¾ %ld\n"
+
+msgid "Cannot open NIL:\n"
+msgstr "²»ÄÜ´ò¿ª NIL:\n"
+
+msgid "Cannot create "
+msgstr "²»ÄÜ´´½¨ "
+
+#, c-format
+msgid "Vim exiting with %d\n"
+msgstr "Vim ·µ»ØÖµ: %d\n"
+
+msgid "cannot change console mode ?!\n"
+msgstr "²»ÄÜÇл»Ö÷¿Ø̨(console)ģʽ !?\n"
+
+msgid "mch_get_shellsize: not a console??\n"
+msgstr "mch_get_shellsize: ²»ÊÇÖ÷¿Ø̨(console)??\n"
+
+#. if Vim opened a window: Executing a shell may cause crashes
+msgid "E360: Cannot execute shell with -f option"
+msgstr "E360: ²»ÄÜÓà -f Ñ¡ÏîÖ´ÐÐ shell"
+
+msgid "Cannot execute "
+msgstr "²»ÄÜÖ´ÐÐ "
+
+msgid "shell "
+msgstr "shell "
+
+msgid " returned\n"
+msgstr " ÒÑ·µ»Ø\n"
+
+msgid "ANCHOR_BUF_SIZE too small."
+msgstr "ANCHOR_BUF_SIZE ̫С"
+
+msgid "I/O ERROR"
+msgstr "I/O ´íÎó"
+
+msgid "Message"
+msgstr "ÏûÏ¢"
+
+msgid "'columns' is not 80, cannot execute external commands"
+msgstr "'columns' ²»ÊÇ 80, ²»ÄÜÖ´ÐÐÍⲿÃüÁî"
+
+msgid "E237: Printer selection failed"
+msgstr "E237: Ñ¡Ôñ´òÓ¡»úʧ°Ü"
+
+#, c-format
+msgid "to %s on %s"
+msgstr "´Ó %s µ½ %s"
+
+#, c-format
+msgid "E613: Unknown printer font: %s"
+msgstr "E613: δ֪µÄ´òÓ¡»ú×ÖÌå: %s"
+
+#, c-format
+msgid "E238: Print error: %s"
+msgstr "E238: ´òÓ¡´íÎó: %s"
+
+#, c-format
+msgid "Printing '%s'"
+msgstr "´òÓ¡ '%s'"
+
+#, c-format
+msgid "E244: Illegal charset name \"%s\" in font name \"%s\""
+msgstr "E244: ×Ö·û¼¯ \"%s\" ²»ÄܶÔÓ¦×ÖÌå\"%s\""
+
+#, c-format
+msgid "E245: Illegal char '%c' in font name \"%s\""
+msgstr "E245: ²»ÕýÈ·µÄ×Ö·û '%c' ³öÏÖÔÚ×ÖÌåÃû³Æ \"%s\" ÄÚ"
+
+msgid "Vim: Double signal, exiting\n"
+msgstr "Vim: Ë«ÖØÐźţ¬Í˳öÖÐ\n"
+
+#, c-format
+msgid "Vim: Caught deadly signal %s\n"
+msgstr "Vim: À¹½Øµ½ÖÂÃüÐźÅ(deadly signal) %s\n"
+
+#, c-format
+msgid "Vim: Caught deadly signal\n"
+msgstr "Vim: À¹½Øµ½ÖÂÃüÐźÅ(deadly signal)\n"
+
+#, c-format
+msgid "Opening the X display took %ld msec"
+msgstr "´ò¿ª X display ÓÃʱ %ld Ãë"
+
+msgid ""
+"\n"
+"Vim: Got X error\n"
+msgstr ""
+"\n"
+"Vim: X ´íÎó\n"
+
+msgid "Testing the X display failed"
+msgstr "²âÊÔ X display ʧ°Ü"
+
+msgid "Opening the X display timed out"
+msgstr "´ò¿ª X display ³¬Ê±"
+
+msgid ""
+"\n"
+"Cannot execute shell "
+msgstr ""
+"\n"
+"ÎÞ·¨Ö´ÐÐ shell"
+
+msgid ""
+"\n"
+"Cannot execute shell sh\n"
+msgstr ""
+"\n"
+"ÎÞ·¨Ö´ÐÐ shell sh\n"
+
+msgid ""
+"\n"
+"shell returned "
+msgstr ""
+"\n"
+"Shell ÒÑ·µ»Ø"
+
+msgid ""
+"\n"
+"Cannot create pipes\n"
+msgstr ""
+"\n"
+"ÎÞ·¨½¨Á¢¹ÜµÀ\n"
+
+msgid ""
+"\n"
+"Cannot fork\n"
+msgstr ""
+"\n"
+"ÎÞ·¨ fork\n"
+
+msgid ""
+"\n"
+"Command terminated\n"
+msgstr ""
+"\n"
+"ÃüÁîÒѽáÊø\n"
+
+msgid "XSMP lost ICE connection"
+msgstr "XSMP ¶ªÊ§Á˵½ ICE µÄÁ¬½Ó"
+
+# do not translate
+#, c-format
+msgid "dlerror = \"%s\""
+msgstr "dlerror = \"%s\""
+
+msgid "Opening the X display failed"
+msgstr "´ò¿ª X display ʧ°Ü"
+
+msgid "XSMP handling save-yourself request"
+msgstr "XSMP ´¦Àí save-yourself ÇëÇó"
+
+msgid "XSMP opening connection"
+msgstr "XSMP ´ò¿ªÁ¬½Ó"
+
+msgid "XSMP ICE connection watch failed"
+msgstr "XSMP ICE Á¬½Ó¼àÊÓʧ°Ü"
+
+#, c-format
+msgid "XSMP SmcOpenConnection failed: %s"
+msgstr "XSMP SmcOpenConnection µ÷ÓÃʧ°Ü: %s"
+
+msgid "At line"
+msgstr "ÔÚÐкŠ"
+
+msgid "Could not load vim32.dll!"
+msgstr "ÎÞ·¨¼ÓÔØ vim32.dll£¡"
+
+msgid "VIM Error"
+msgstr "VIM ´íÎó"
+
+msgid "Could not fix up function pointers to the DLL!"
+msgstr "ÎÞ·¨ÐÞÕýµ½ DLL µÄº¯ÊýÖ¸Õë!"
+
+#, c-format
+msgid "shell returned %d"
+msgstr "Shell ·µ»Ø %d"
+
+#, c-format
+msgid "Vim: Caught %s event\n"
+msgstr "Vim: À¹½Øµ½ %s ʼþ\n"
+
+msgid "close"
+msgstr "¹Ø±Õ"
+
+msgid "logoff"
+msgstr "×¢Ïû"
+
+msgid "shutdown"
+msgstr "¹Ø»ú"
+
+msgid "E371: Command not found"
+msgstr "E371: ÕÒ²»µ½ÃüÁî"
+
+msgid ""
+"VIMRUN.EXE not found in your $PATH.\n"
+"External commands will not pause after completion.\n"
+"See :help win32-vimrun for more information."
+msgstr ""
+"ÔÚÄãµÄ $PATH ÖÐÕÒ²»µ½ VIMRUN.EXE¡£\n"
+"ÍⲿÃüÁîÖ´ÐÐÍê±Ïºó½«²»»áÔÝÍ£¡£\n"
+"½øÒ»²½ËµÃ÷Çë¼û :help win32-vimrun"
+
+msgid "Vim Warning"
+msgstr "Vim ¾¯¸æ"
+
+#, c-format
+msgid "E372: Too many %%%c in format string"
+msgstr "E372: ¸ñʽ»¯×Ö·û´®ÀïÓÐÌ«¶à %%%c "
+
+#, c-format
+msgid "E373: Unexpected %%%c in format string"
+msgstr "E373: ¸ñʽ»¯×Ö·û´®²»Ó¦¸Ã³öÏÖ %%%c "
+
+msgid "E374: Missing ] in format string"
+msgstr "E374: ¸ñʽ»¯×Ö·û´®ÀïÉÙÁË ]"
+
+#, c-format
+msgid "E375: Unsupported %%%c in format string"
+msgstr "E375: ¸ñʽ»¯×Ö·û´®ÀïÓв»Ö§³ÖµÄ %%%c "
+
+#, c-format
+msgid "E376: Invalid %%%c in format string prefix"
+msgstr "E376: ¸ñʽ»¯×Ö·û´®¿ªÍ·ÀïÓв»ÕýÈ·µÄ %%%c "
+
+#, c-format
+msgid "E377: Invalid %%%c in format string"
+msgstr "E377: ¸ñʽ»¯×Ö·û´®ÀïÓв»ÕýÈ·µÄ %%%c "
+
+msgid "E378: 'errorformat' contains no pattern"
+msgstr "E378: 'errorformat' δÉ趨"
+
+msgid "E379: Missing or empty directory name"
+msgstr "E379: ÕÒ²»µ½Ä¿Â¼Ãû³Æ»òÊÇ¿ÕµÄĿ¼Ãû³Æ"
+
+msgid "E553: No more items"
+msgstr "E553: ûÓиü¶àµÄÏî"
+
+#, c-format
+msgid "(%d of %d)%s%s: "
+msgstr "(%d / %d)%s%s: "
+
+msgid " (line deleted)"
+msgstr " (ÐÐÒÑɾ³ý)"
+
+msgid "E380: At bottom of quickfix stack"
+msgstr "E380: Quickfix ¶ÑÕ»µ×¶Ë"
+
+msgid "E381: At top of quickfix stack"
+msgstr "E381: Quickfix ¶ÑÕ»¶¥¶Ë"
+
+#, c-format
+msgid "error list %d of %d; %d errors"
+msgstr "´íÎóÁбí %d / %d£»¹² %d ¸ö´íÎó"
+
+msgid "E382: Cannot write, 'buftype' option is set"
+msgstr "E382: ÎÞ·¨Ð´È룬ÒÑÉ趨ѡÏî 'buftype'"
+
+msgid "E683: File name missing or invalid pattern"
+msgstr "E683: ȱÉÙÎļþÃû»òģʽÎÞЧ"
+
+#, c-format
+msgid "Cannot open file \"%s\""
+msgstr "ÎÞ·¨´ò¿ªÎļþ \"%s\""
+
+msgid "E681: Buffer is not loaded"
+msgstr "E681: »º³åÇøδ¼ÓÔØ"
+
+msgid "E777: String or List expected"
+msgstr "E777: ´Ë´¦ÐèÒª String »òÕß List"
+
+#, c-format
+msgid "E369: invalid item in %s%%[]"
+msgstr "E369: %s%%[] ÖÐÓÐÎÞЧµÄÏî"
+
+msgid "E339: Pattern too long"
+msgstr "E339: ģʽ̫³¤"
+
+msgid "E50: Too many \\z("
+msgstr "E50: Ì«¶à \\z("
+
+#, c-format
+msgid "E51: Too many %s("
+msgstr "E51: Ì«¶à %s("
+
+msgid "E52: Unmatched \\z("
+msgstr "E52: ²»Æ¥ÅäµÄ \\z("
+
+#, c-format
+msgid "E53: Unmatched %s%%("
+msgstr "E53: ²»Æ¥ÅäµÄ %s%%("
+
+#, c-format
+msgid "E54: Unmatched %s("
+msgstr "E54: ²»Æ¥ÅäµÄ %s("
+
+#, c-format
+msgid "E55: Unmatched %s)"
+msgstr "E55: ²»Æ¥ÅäµÄ %s)"
+
+#, c-format
+msgid "E59: invalid character after %s@"
+msgstr "E59: %s@ ºóÃæÓÐÎÞЧµÄ×Ö·û"
+
+#, c-format
+msgid "E60: Too many complex %s{...}s"
+msgstr "E60: Ì«¶à¸´Ô %s{...}s"
+
+#, c-format
+msgid "E61: Nested %s*"
+msgstr "E61: ǶÌ×µÄ %s*"
+
+#, c-format
+msgid "E62: Nested %s%c"
+msgstr "E62: ǶÌ×µÄ %s%c"
+
+msgid "E63: invalid use of \\_"
+msgstr "E63: ²»ÕýÈ·µØʹÓà \\_"
+
+#, c-format
+msgid "E64: %s%c follows nothing"
+msgstr "E64: %s%c Ç°ÃæÎÞÄÚÈÝ"
+
+msgid "E65: Illegal back reference"
+msgstr "E65: ÎÞЧµÄ»ØÒý"
+
+msgid "E66: \\z( not allowed here"
+msgstr "E66: ´Ë´¦²»ÔÊÐí \\z("
+
+msgid "E67: \\z1 - \\z9 not allowed here"
+msgstr "E67: ´Ë´¦²»ÔÊÐí \\z1 µÈ"
+
+msgid "E68: Invalid character after \\z"
+msgstr "E68: \\z ºóÃæÓÐÎÞЧµÄ×Ö·û"
+
+#, c-format
+msgid "E69: Missing ] after %s%%["
+msgstr "E69: %s%%[ ºóȱÉÙ ]"
+
+#, c-format
+msgid "E70: Empty %s%%[]"
+msgstr "E70: ¿ÕµÄ %s%%[]"
+
+#, c-format
+msgid "E678: Invalid character after %s%%[dxouU]"
+msgstr "E678: %s%%[dxouU] ºóÃæÓÐÎÞЧµÄ×Ö·û"
+
+#, c-format
+msgid "E71: Invalid character after %s%%"
+msgstr "E71: %s%% ºóÃæÓÐÎÞЧµÄ×Ö·û"
+
+#, c-format
+msgid "E769: Missing ] after %s["
+msgstr "E769: %s[ ºóȱÉÙ ]"
+
+#, c-format
+msgid "E554: Syntax error in %s{...}"
+msgstr "E554: %s{...} ÖÐÓï·¨´íÎó"
+
+msgid "External submatches:\n"
+msgstr "Íⲿ·ûºÏ:\n"
+
+msgid " VREPLACE"
+msgstr " V-Ìæ»»"
+
+msgid " REPLACE"
+msgstr " Ìæ»»"
+
+msgid " REVERSE"
+msgstr " ·´Ïò"
+
+msgid " INSERT"
+msgstr " ²åÈë"
+
+msgid " (insert)"
+msgstr " (²åÈë)"
+
+msgid " (replace)"
+msgstr " (Ìæ»»)"
+
+msgid " (vreplace)"
+msgstr " (V-Ìæ»»)"
+
+msgid " Hebrew"
+msgstr " Hebrew"
+
+msgid " Arabic"
+msgstr " Arabic"
+
+msgid " (lang)"
+msgstr " (ÓïÑÔ)"
+
+msgid " (paste)"
+msgstr " (Õ³Ìû)"
+
+msgid " VISUAL"
+msgstr " ¿ÉÊÓ"
+
+msgid " VISUAL LINE"
+msgstr " ¿ÉÊÓ ÐÐ"
+
+msgid " VISUAL BLOCK"
+msgstr " ¿ÉÊÓ ¿é"
+
+msgid " SELECT"
+msgstr " Ñ¡Ôñ"
+
+msgid " SELECT LINE"
+msgstr " Ñ¡Ôñ ÐÐ"
+
+msgid " SELECT BLOCK"
+msgstr " Ñ¡Ôñ ¿é"
+
+msgid "recording"
+msgstr "¼Ç¼ÖÐ"
+
+#, c-format
+msgid "E383: Invalid search string: %s"
+msgstr "E383: ÎÞЧµÄ²éÕÒ×Ö·û´®: %s"
+
+#, c-format
+msgid "E384: search hit TOP without match for: %s"
+msgstr "E384: ÒѲéÕÒµ½Îļþ¿ªÍ·ÈÔÕÒ²»µ½ %s"
+
+#, c-format
+msgid "E385: search hit BOTTOM without match for: %s"
+msgstr "E385: ÒѲéÕÒµ½Îļþ½áβÈÔÕÒ²»µ½ %s"
+
+msgid "E386: Expected '?' or '/' after ';'"
+msgstr "E386: ÔÚ ';' ºóÃæÓ¦¸ÃÓÐ '?' »ò '/'"
+
+msgid " (includes previously listed match)"
+msgstr " (°üÀ¨ÉÏ´ÎÁгö·ûºÏÏî)"
+
+#. cursor at status line
+msgid "--- Included files "
+msgstr "--- °üº¬Îļþ "
+
+msgid "not found "
+msgstr "ÕÒ²»µ½ "
+
+msgid "in path ---\n"
+msgstr "ÔÚ·¾¶ ---\n"
+
+msgid " (Already listed)"
+msgstr " (ÒÑÁгö)"
+
+msgid " NOT FOUND"
+msgstr " ÕÒ²»µ½"
+
+#, c-format
+msgid "Scanning included file: %s"
+msgstr "²éÕÒ°üº¬Îļþ: %s"
+
+#, c-format
+msgid "Searching included file %s"
+msgstr "²éÕÒ°üº¬µÄÎļþ %s"
+
+msgid "E387: Match is on current line"
+msgstr "E387: µ±Ç°ÐÐÆ¥Åä"
+
+msgid "All included files were found"
+msgstr "ËùÓаüº¬Îļþ¶¼ÒÑÕÒµ½"
+
+msgid "No included files"
+msgstr "ûÓаüº¬Îļþ"
+
+msgid "E388: Couldn't find definition"
+msgstr "E388: ÕÒ²»µ½¶¨Òå"
+
+msgid "E389: Couldn't find pattern"
+msgstr "E389: ÕÒ²»µ½ pattern"
+
+msgid "E759: Format error in spell file"
+msgstr "E759: ƴдÎļþ¸ñʽ´íÎó"
+
+msgid "E758: Truncated spell file"
+msgstr "E758: ÒѽضϵÄƴдÎļþ"
+
+#, c-format
+msgid "Trailing text in %s line %d: %s"
+msgstr "%s µÚ %d ÐУ¬¶àÓàµÄºóÐø×Ö·û: %s"
+
+#, c-format
+msgid "Affix name too long in %s line %d: %s"
+msgstr "%s µÚ %d ÐУ¬¸½¼ÓÏîÃû×ÖÌ«³¤: %s"
+
+msgid "E761: Format error in affix file FOL, LOW or UPP"
+msgstr "E761: ¸½¼ÓÎļþ FOL¡¢LOW »ò UPP Öиñʽ´íÎó"
+
+msgid "E762: Character in FOL, LOW or UPP is out of range"
+msgstr "E762: FOL¡¢LOW »ò UPP ÖÐ×Ö·û³¬³ö·¶Î§"
+
+msgid "Compressing word tree..."
+msgstr "ѹËõµ¥´ÊÊ÷¡­¡­"
+
+msgid "E756: Spell checking is not enabled"
+msgstr "E756: ƴд¼ì²éδÆôÓÃ"
+
+#, c-format
+msgid "Warning: Cannot find word list \"%s.%s.spl\" or \"%s.ascii.spl\""
+msgstr "¾¯¸æ: ÕÒ²»µ½µ¥´ÊÁбí \"%s.%s.spl\" or \"%s.ascii.spl\""
+
+#, c-format
+msgid "Reading spell file \"%s\""
+msgstr "¶ÁȡƴдÎļþ \"%s\""
+
+msgid "E757: This does not look like a spell file"
+msgstr "E757: Õâ¿´ÆðÀ´²»ÏñÊÇƴдÎļþ"
+
+msgid "E771: Old spell file, needs to be updated"
+msgstr "E771: ¾É°æ±¾µÄƴдÎļþ£¬ÐèÒª¸üÐÂ"
+
+msgid "E772: Spell file is for newer version of Vim"
+msgstr "E772: Ϊ¸ü¸ß°æ±¾µÄ Vim ËùÓõÄƴдÎļþ"
+
+msgid "E770: Unsupported section in spell file"
+msgstr "E770: ƴдÎļþÖдæÔÚ²»Ö§³ÖµÄ½Ú"
+
+#, c-format
+msgid "Warning: region %s not supported"
+msgstr "¾¯¸æ: ÇøÓò %s ²»Ö§³Ö"
+
+#, c-format
+msgid "Reading affix file %s..."
+msgstr "¶ÁÈ¡¸½¼ÓÎļþ %s ¡­¡­"
+
+#, c-format
+msgid "Conversion failure for word in %s line %d: %s"
+msgstr "µ¥´Ê %s ת»»Ê§°Ü£¬µÚ %d ÐÐ: %s"
+
+#, c-format
+msgid "Conversion in %s not supported: from %s to %s"
+msgstr "²»Ö§³Ö %s ÖеÄת»»: ´Ó %s µ½ %s"
+
+#, c-format
+msgid "Conversion in %s not supported"
+msgstr "²»Ö§³Ö %s ÖеÄת»»"
+
+#, c-format
+msgid "Invalid value for FLAG in %s line %d: %s"
+msgstr "%s µÚ %d ÐУ¬FLAG µÄÖµÎÞЧ: %s"
+
+#, c-format
+msgid "FLAG after using flags in %s line %d: %s"
+msgstr "%s µÚ %d ÐУ¬ÔÚʹÓñêÖ¾ºó³öÏÖ FLAG: %s"
+
+#, c-format
+#~ msgid ""
+#~ "Defining COMPOUNDFORBIDFLAG after PFX item may give wrong results in %s line "
+#~ "%d"
+#~ msgstr ""
+
+#, c-format
+#~ msgid ""
+#~ "Defining COMPOUNDPERMITFLAG after PFX item may give wrong results in %s line "
+#~ "%d"
+#~ msgstr ""
+
+#, c-format
+msgid "Wrong COMPOUNDWORDMAX value in %s line %d: %s"
+msgstr "%s µÚ %d ÐУ¬´íÎóµÄ COMPOUNDWORDMAX Öµ: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDMIN value in %s line %d: %s"
+msgstr "%s µÚ %d ÐУ¬´íÎóµÄ COMPOUNDMIN Öµ: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDSYLMAX value in %s line %d: %s"
+msgstr "%s µÚ %d ÐУ¬´íÎóµÄ COMPOUNDSYLMAX Öµ: %s"
+
+#, c-format
+msgid "Wrong CHECKCOMPOUNDPATTERN value in %s line %d: %s"
+msgstr "%s µÚ %d ÐУ¬´íÎóµÄ CHECKCOMPOUNDPATTERN Öµ: %s"
+
+#, c-format
+msgid "Different combining flag in continued affix block in %s line %d: %s"
+msgstr "%s µÚ %d ÐУ¬ÔÚÁ¬ÐøµÄ¸½¼Ó¿éÖгöÏÖ²»Í¬µÄ×éºÏ±êÖ¾: %s"
+
+#, c-format
+msgid "Duplicate affix in %s line %d: %s"
+msgstr "%s µÚ %d ÐУ¬Öظ´µÄ¸½¼ÓÏî: %s"
+
+#, c-format
+msgid ""
+"Affix also used for BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST in %s "
+"line %d: %s"
+msgstr ""
+"%s µÚ %d ÐУ¬¸½¼ÓÏî±» BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST ʹ"
+"ÓÃ: %s"
+
+#, c-format
+msgid "Expected Y or N in %s line %d: %s"
+msgstr "%s µÚ %d ÐУ¬´Ë´¦ÐèÒª Y »ò N: %s"
+
+#, c-format
+msgid "Broken condition in %s line %d: %s"
+msgstr "%s µÚ %d ÐУ¬´íÎóµÄÌõ¼þ: %s"
+
+#, c-format
+msgid "Expected REP(SAL) count in %s line %d"
+msgstr "%s µÚ %d ÐУ¬´Ë´¦ÐèÒª REP(SAL) ¼ÆÊý"
+
+#, c-format
+msgid "Expected MAP count in %s line %d"
+msgstr "%s µÚ %d ÐУ¬´Ë´¦ÐèÒª MAP ¼ÆÊý"
+
+#, c-format
+msgid "Duplicate character in MAP in %s line %d"
+msgstr "%s µÚ %d ÐУ¬MAP ÖдæÔÚÖظ´µÄ×Ö·û"
+
+#, c-format
+msgid "Unrecognized or duplicate item in %s line %d: %s"
+msgstr "%s µÚ %d ÐУ¬ÎÞ·¨Ê¶±ð»òÖظ´µÄÏî: %s"
+
+#, c-format
+msgid "Missing FOL/LOW/UPP line in %s"
+msgstr "%s ÖÐȱÉÙ FOL/LOW/UPP ÐÐ"
+
+msgid "COMPOUNDSYLMAX used without SYLLABLE"
+msgstr "ÔÚûÓÐ SYLLABLE µÄÇé¿öÏÂʹÓÃÁË COMPOUNDSYLMAX"
+
+msgid "Too many postponed prefixes"
+msgstr "Ì«¶àÑÓ³Ùǰ׺"
+
+msgid "Too many compound flags"
+msgstr "Ì«¶à×éºÏ±êÖ¾"
+
+msgid "Too many postponed prefixes and/or compound flags"
+msgstr "Ì«¶àÑÓ³Ùǰ׺ºÍ/»ò×éºÏ±êÖ¾"
+
+#, c-format
+msgid "Missing SOFO%s line in %s"
+msgstr "%s ÖÐȱÉÙ SOFO%s ÐÐ"
+
+#, c-format
+msgid "Both SAL and SOFO lines in %s"
+msgstr "%s ͬʱ³öÏÖ SQL ºÍ SOFO ÐÐ"
+
+#, c-format
+msgid "Flag is not a number in %s line %d: %s"
+msgstr "%s µÚ %d ÐУ¬±êÖ¾²»ÊÇÊý×Ö: %s"
+
+#, c-format
+msgid "Illegal flag in %s line %d: %s"
+msgstr "%s µÚ %d ÐУ¬ÎÞЧµÄ±êÖ¾: %s"
+
+#, c-format
+msgid "%s value differs from what is used in another .aff file"
+msgstr "%s µÄÖµÓëÁíÒ»¸ö .aff ÎļþÖÐʹÓõÄÖµ²»Ïàͬ"
+
+#, c-format
+msgid "Reading dictionary file %s..."
+msgstr "¶ÁÈ¡×ÖµäÎļþ %s ¡­¡­"
+
+#, c-format
+msgid "E760: No word count in %s"
+msgstr "E760: %s ÖÐûÓе¥´Ê¼ÆÊý"
+
+#, c-format
+msgid "line %6d, word %6d - %s"
+msgstr "µÚ %6d ÐУ¬µÚ %6d ¸öµ¥´Ê - %s"
+
+#, c-format
+msgid "Duplicate word in %s line %d: %s"
+msgstr "%s µÚ %d ÐУ¬Öظ´µÄµ¥´Ê: %s"
+
+#, c-format
+msgid "First duplicate word in %s line %d: %s"
+msgstr "%s µÚ %d ÐУ¬Ê×´ÎÖظ´µÄµ¥´Ê: %s"
+
+#, c-format
+msgid "%d duplicate word(s) in %s"
+msgstr "´æÔÚ %d ¸öÖظ´µÄµ¥´Ê£¬ÔÚ %s ÖÐ"
+
+#, c-format
+msgid "Ignored %d word(s) with non-ASCII characters in %s"
+msgstr "ºöÂÔÁ˺¬ÓÐ·Ç ASCII ×Ö·ûµÄ %d ¸öµ¥´Ê£¬ÔÚ %s ÖÐ"
+
+#, c-format
+msgid "Reading word file %s..."
+msgstr "¶ÁÈ¡µ¥´ÊÎļþ %s ¡­¡­"
+
+#, c-format
+#~ msgid "Duplicate /encoding= line ignored in %s line %d: %s"
+#~ msgstr ""
+
+#, c-format
+msgid "/encoding= line after word ignored in %s line %d: %s"
+msgstr "%s µÚ %d ÐУ¬µ¥´ÊºóµÄ /encoding= ÐÐÒѱ»ºöÂÔ: %s"
+
+#, c-format
+msgid "Duplicate /regions= line ignored in %s line %d: %s"
+msgstr "%s µÚ %d ÐУ¬Öظ´µÄ /regions= ÐÐÒѱ»ºöÂÔ: %s"
+
+#, c-format
+msgid "Too many regions in %s line %d: %s"
+msgstr "%s µÚ %d ÐУ¬Ì«¶àÇøÓò: %s"
+
+#, c-format
+msgid "/ line ignored in %s line %d: %s"
+msgstr "%s µÚ %d ÐУ¬/ ÐÐÒѱ»ºöÂÔ: %s"
+
+#, c-format
+msgid "Invalid region nr in %s line %d: %s"
+msgstr "%s µÚ %d ÐУ¬ÎÞЧµÄÇøÓòºÅ: %s"
+
+#, c-format
+msgid "Unrecognized flags in %s line %d: %s"
+msgstr "%s µÚ %d ÐУ¬²»¿Éʶ±ðµÄ±êÖ¾: %s"
+
+#, c-format
+msgid "Ignored %d words with non-ASCII characters"
+msgstr "ºöÂÔÁ˺¬ÓÐ·Ç ASCII ×Ö·ûµÄ %d ¸öµ¥´Ê"
+
+#, c-format
+msgid "Compressed %d of %d nodes; %d (%d%%) remaining"
+msgstr "ѹËõÁË %d/%d ¸ö½Úµã£»Ê£Óà %d (%d%%)"
+
+msgid "Reading back spell file..."
+msgstr "¶ÁȡƴдÎļþ¡­¡­"
+
+#.
+#. * Go through the trie of good words, soundfold each word and add it to
+#. * the soundfold trie.
+#.
+msgid "Performing soundfolding..."
+msgstr "ÕýÔÚ soundfolding¡­¡­"
+
+#, c-format
+msgid "Number of words after soundfolding: %ld"
+msgstr "soundfolding ºóµÄµ¥´ÊÊý: %ld"
+
+#, c-format
+msgid "Total number of words: %d"
+msgstr "µ¥´Ê×ÜÊý: %d"
+
+#, c-format
+msgid "Writing suggestion file %s..."
+msgstr "дÈ뽨ÒéÎļþ %s ¡­¡­"
+
+#, c-format
+msgid "Estimated runtime memory use: %d bytes"
+msgstr "¹À¼ÆÔËÐÐʱÄÚ´æÓÃÁ¿: %d ×Ö½Ú"
+
+msgid "E751: Output file name must not have region name"
+msgstr "E751: Êä³öÎļþÃû²»Äܺ¬ÓÐÇøÓòÃû"
+
+msgid "E754: Only up to 8 regions supported"
+msgstr "E754: ×î¶àÖ»Ö§³Ö 8 ¸öÇøÓò"
+
+#, c-format
+msgid "E755: Invalid region in %s"
+msgstr "E755: %s ³öÏÖÎÞЧµÄ·¶Î§"
+
+msgid "Warning: both compounding and NOBREAK specified"
+msgstr "¾¯¸æ: ͬʱָ¶¨ÁË compounding ºÍ NOBREAK"
+
+#, c-format
+msgid "Writing spell file %s..."
+msgstr "дÈëƴдÎļþ %s ¡­¡­"
+
+msgid "Done!"
+msgstr "Íê³É£¡"
+
+#, c-format
+msgid "E765: 'spellfile' does not have %ld entries"
+msgstr "E765: 'spellfile' ûÓÐ %ld Ïî"
+
+#, c-format
+msgid "Word removed from %s"
+msgstr "´Ó %s ÖÐɾ³ýÁ˵¥´Ê"
+
+#, c-format
+msgid "Word added to %s"
+msgstr "Ïò %s ÖÐÌí¼ÓÁ˵¥´Ê"
+
+msgid "E763: Word characters differ between spell files"
+msgstr "E763: ƴдÎļþÖ®¼äµÄ×Ö·û²»Ïàͬ"
+
+msgid "Sorry, no suggestions"
+msgstr "±§Ç¸£¬Ã»Óн¨Òé"
+
+#, c-format
+msgid "Sorry, only %ld suggestions"
+msgstr "±§Ç¸£¬Ö»ÓÐ %ld Ìõ½¨Òé"
+
+#. avoid more prompt
+#, c-format
+msgid "Change \"%.*s\" to:"
+msgstr "½« \"%.*s\" ¸ÄΪ£º"
+
+#, c-format
+msgid " < \"%.*s\""
+msgstr " < \"%.*s\""
+
+msgid "E752: No previous spell replacement"
+msgstr "E752: ֮ǰûÓÐƴдÌæ»»"
+
+#, c-format
+msgid "E753: Not found: %s"
+msgstr "E753: ÕÒ²»µ½: %s"
+
+#, c-format
+msgid "E778: This does not look like a .sug file: %s"
+msgstr "E778: ¿´ÆðÀ´²»ÏñÊÇ .sug Îļþ: %s"
+
+#, c-format
+#~ msgid "E779: Old .sug file, needs to be updated: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E780: .sug file is for newer version of Vim: %s"
+#~ msgstr ""
+
+#, c-format
+#~ msgid "E781: .sug file doesn't match .spl file: %s"
+#~ msgstr ""
+
+#, fuzzy, c-format
+#~ msgid "E782: error while reading .sug file: %s"
+#~ msgstr "E47: ¶ÁÈ¡´íÎóÎļþʧ°Ü"
+
+#. This should have been checked when generating the .spl
+#. * file.
+#~ msgid "E783: duplicate char in MAP entry"
+#~ msgstr ""
+
+#, c-format
+msgid "E390: Illegal argument: %s"
+msgstr "E390: ÎÞЧµÄ²ÎÊý: %s"
+
+#, c-format
+msgid "E391: No such syntax cluster: %s"
+msgstr "E391: ÎÞ´ËÓï·¨ cluster: \"%s\""
+
+msgid "No Syntax items defined for this buffer"
+msgstr "Õâ¸ö»º³åÇøûÓж¨ÒåÈκÎÓï·¨Ïî"
+
+msgid "syncing on C-style comments"
+msgstr "C·ç¸ñ×¢ÊÍͬ²½ÖÐ"
+
+msgid "no syncing"
+msgstr "ûÓÐͬ²½"
+
+msgid "syncing starts "
+msgstr "ͬ²½¿ªÊ¼"
+
+msgid " lines before top line"
+msgstr "Ðкų¬³ö·¶Î§"
+
+msgid ""
+"\n"
+"--- Syntax sync items ---"
+msgstr ""
+"\n"
+"--- Ó﷨ͬ²½ÏîÄ¿ (Syntax sync items) ---"
+
+msgid ""
+"\n"
+"syncing on items"
+msgstr ""
+"\n"
+"ͬ²½ÖÐ:"
+
+msgid ""
+"\n"
+"--- Syntax items ---"
+msgstr ""
+"\n"
+"--- Óï·¨ÏîÄ¿ ---"
+
+#, c-format
+msgid "E392: No such syntax cluster: %s"
+msgstr "E392: ÎÞ´ËÓï·¨ cluster: \"%s\""
+
+msgid "minimal "
+msgstr "×îС"
+
+msgid "maximal "
+msgstr "×î´ó"
+
+#, fuzzy
+#~ msgid "; match "
+#~ msgstr "Æ¥Åä %d"
+
+#, fuzzy
+#~ msgid " line breaks"
+#~ msgstr "ÉÙÓÚÒ»ÐÐ"
+
+msgid "E395: contains argument not accepted here"
+msgstr "E395: ʹÓÃÁ˲»ÕýÈ·µÄ²ÎÊý"
+
+msgid "E396: containedin argument not accepted here"
+msgstr "E396: ʹÓÃÁ˲»ÕýÈ·µÄ²ÎÊý"
+
+msgid "E393: group[t]here not accepted here"
+msgstr "E393: ʹÓÃÁ˲»ÕýÈ·µÄ²ÎÊý"
+
+#, c-format
+msgid "E394: Didn't find region item for %s"
+msgstr "E394: ÕÒ²»µ½ %s µÄ region item"
+
+msgid "E397: Filename required"
+msgstr "E397: ÐèÒªÎļþÃû³Æ"
+
+#, c-format
+msgid "E747: Missing ']': %s"
+msgstr "E747: ȱÉÙ ']': %s"
+
+#, c-format
+msgid "E398: Missing '=': %s"
+msgstr "E398: ȱÉÙ '=': %s"
+
+#, c-format
+msgid "E399: Not enough arguments: syntax region %s"
+msgstr "E399: syntax region %s µÄ²ÎÊýÌ«ÉÙ"
+
+msgid "E400: No cluster specified"
+msgstr "E400: ûÓÐÖ¸¶¨µÄÊôÐÔ"
+
+#, c-format
+msgid "E401: Pattern delimiter not found: %s"
+msgstr "E401: ÕÒ²»µ½·Ö¸ô·ûºÅ: %s"
+
+#, c-format
+msgid "E402: Garbage after pattern: %s"
+msgstr "E402: '%s' ºóÃæµÄ¶«Î÷²»ÄÜʶ±ð"
+
+msgid "E403: syntax sync: line continuations pattern specified twice"
+msgstr "E403: Ó﷨ͬ²½: Á¬½ÓÐзûºÅÖ¸¶¨ÁËÁ½´Î"
+
+#, c-format
+msgid "E404: Illegal arguments: %s"
+msgstr "E404: ÎÞЧµÄ²ÎÊý: %s"
+
+#, c-format
+msgid "E405: Missing equal sign: %s"
+msgstr "E405: ȱÉٵȺÅ: %s"
+
+#, c-format
+msgid "E406: Empty argument: %s"
+msgstr "E406: ¿ÕµÄ²ÎÊý: %s"
+
+#, c-format
+msgid "E407: %s not allowed here"
+msgstr "E407: %s ²»ÄÜÔڴ˳öÏÖ"
+
+#, c-format
+msgid "E408: %s must be first in contains list"
+msgstr "E408: %s ±ØÐëÊÇÁбíÀïµÄµÚÒ»¸ö"
+
+#, c-format
+msgid "E409: Unknown group name: %s"
+msgstr "E409: ²»ÕýÈ·µÄ×éÃû: %s"
+
+#, c-format
+msgid "E410: Invalid :syntax subcommand: %s"
+msgstr "E410: ²»ÕýÈ·µÄ :syntax ×ÓÃüÁî: %s"
+
+msgid "E679: recursive loop loading syncolor.vim"
+msgstr "E679: ¼ÓÔØ syncolor.vim ʱ³öÏÖǶÌ×Ñ­»·"
+
+#, c-format
+msgid "E411: highlight group not found: %s"
+msgstr "E411: ÕÒ²»µ½ highlight group: %s"
+
+#, c-format
+msgid "E412: Not enough arguments: \":highlight link %s\""
+msgstr "E412: ²ÎÊýÌ«ÉÙ: \":highlight link %s\""
+
+#, c-format
+msgid "E413: Too many arguments: \":highlight link %s\""
+msgstr "E413: ²ÎÊý¹ý¶à: \":highlight link %s\""
+
+msgid "E414: group has settings, highlight link ignored"
+msgstr "E414: ÒÑÉ趨×é, ºöÂÔ highlight link"
+
+#, c-format
+msgid "E415: unexpected equal sign: %s"
+msgstr "E415: ²»¸ÃÓеĵȺÅ: %s"
+
+#, c-format
+msgid "E416: missing equal sign: %s"
+msgstr "E416: ȱÉٵȺÅ: %s"
+
+#, c-format
+msgid "E417: missing argument: %s"
+msgstr "E417: ȱÉÙ²ÎÊý: %s"
+
+#, c-format
+msgid "E418: Illegal value: %s"
+msgstr "E418: ²»ºÏ·¨µÄÖµ: %s"
+
+msgid "E419: FG color unknown"
+msgstr "E419: ´íÎóµÄÇ°¾°ÑÕÉ«"
+
+msgid "E420: BG color unknown"
+msgstr "E420: ´íÎóµÄ±³¾°ÑÕÉ«"
+
+#, c-format
+msgid "E421: Color name or number not recognized: %s"
+msgstr "E421: ´íÎóµÄÑÕÉ«Ãû³Æ»òÊýÖµ: %s"
+
+#, c-format
+msgid "E422: terminal code too long: %s"
+msgstr "E422: Öն˱àÂëÌ«³¤: %s"
+
+#, c-format
+msgid "E423: Illegal argument: %s"
+msgstr "E423: ÎÞЧµÄ²ÎÊý: %s"
+
+msgid "E424: Too many different highlighting attributes in use"
+msgstr "E424: ʹÓÃÁËÌ«¶à²»Í¬µÄ¸ßÁÁ¶ÈÊôÐÔ"
+
+msgid "E669: Unprintable character in group name"
+msgstr "E669: ×éÃûÖдæÔÚ²»¿ÉÏÔʾ×Ö·û"
+
+msgid "W18: Invalid character in group name"
+msgstr "W18: ×éÃûÖк¬ÓÐÎÞЧ×Ö·û"
+
+msgid "E555: at bottom of tag stack"
+msgstr "E555: ÒÑÔÚ tag ¶ÑÕ»µ×²¿"
+
+msgid "E556: at top of tag stack"
+msgstr "E556: ÒÑÔÚ tag ¶ÑÕ»¶¥²¿"
+
+msgid "E425: Cannot go before first matching tag"
+msgstr "E425: Òѵ½µÚÒ»¸öÆ¥ÅäµÄ tag"
+
+#, c-format
+msgid "E426: tag not found: %s"
+msgstr "E426: ÕÒ²»µ½ tag: %s"
+
+msgid " # pri kind tag"
+msgstr " # pri kind tag"
+
+msgid "file\n"
+msgstr "Îļþ\n"
+
+msgid "E427: There is only one matching tag"
+msgstr "E427: Ö»ÓÐÒ»¸öÆ¥ÅäµÄ tag"
+
+msgid "E428: Cannot go beyond last matching tag"
+msgstr "E428: ¼ºµ½×îºóÒ»¸öÆ¥ÅäµÄ tag"
+
+#, c-format
+msgid "File \"%s\" does not exist"
+msgstr "Îļþ \"%s\" ²»´æÔÚ"
+
+#. Give an indication of the number of matching tags
+#, c-format
+msgid "tag %d of %d%s"
+msgstr "ÕÒµ½ tag: %d / %d%s"
+
+msgid " or more"
+msgstr " »ò¸ü¶à"
+
+msgid " Using tag with different case!"
+msgstr " ÒÔ²»Í¬´óСдÀ´Ê¹Óà tag£¡"
+
+#, c-format
+msgid "E429: File \"%s\" does not exist"
+msgstr "E429: Îļþ \"%s\" ²»´æÔÚ"
+
+#. Highlight title
+msgid ""
+"\n"
+" # TO tag FROM line in file/text"
+msgstr ""
+"\n"
+" # µ½ tag ´Ó ÐÐ ÔÚ Îļþ/Îı¾"
+
+#, c-format
+msgid "Searching tags file %s"
+msgstr "²éÕÒ tag Îļþ %s"
+
+#, c-format
+msgid "E430: Tag file path truncated for %s\n"
+msgstr "E430: Tag Îļþ·¾¶±»½Ø¶ÏΪ %s\n"
+
+#, c-format
+msgid "E431: Format error in tags file \"%s\""
+msgstr "E431: Tag Îļþ \"%s\" ¸ñʽ´íÎó"
+
+#, c-format
+msgid "Before byte %ld"
+msgstr "ÔÚµÚ %ld ×Ö½Ú֮ǰ"
+
+#, c-format
+msgid "E432: Tags file not sorted: %s"
+msgstr "E432: Tag ÎļþδÅÅÐò: %s"
+
+#. never opened any tags file
+msgid "E433: No tags file"
+msgstr "E433: ûÓÐ tag Îļþ"
+
+msgid "E434: Can't find tag pattern"
+msgstr "E434: ÕÒ²»µ½ tag ģʽ"
+
+msgid "E435: Couldn't find tag, just guessing!"
+msgstr "E435: ÕÒ²»µ½ tag£¬ÊÔ×Ų£¡"
+
+msgid "' not known. Available builtin terminals are:"
+msgstr "' δ֪¡£¿ÉÓõÄÄÚ½¨ÖÕ¶ËÓÐ:"
+
+msgid "defaulting to '"
+msgstr "ĬÈÏֵΪ: '"
+
+msgid "E557: Cannot open termcap file"
+msgstr "E557: ÎÞ·¨´ò¿ª termcap Îļþ"
+
+msgid "E558: Terminal entry not found in terminfo"
+msgstr "E558: ÔÚ terminfo ÖÐÕÒ²»µ½ÖÕ¶ËÏî"
+
+msgid "E559: Terminal entry not found in termcap"
+msgstr "E559: ÔÚ termcap ÖÐÕÒ²»µ½ÖÕ¶ËÏî"
+
+#, c-format
+msgid "E436: No \"%s\" entry in termcap"
+msgstr "E436: termcap ÖÐûÓÐ \"%s\" Ïî"
+
+msgid "E437: terminal capability \"cm\" required"
+msgstr "E437: ÖÕ¶ËÐèÒªÄÜÁ¦ \"cm\""
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Terminal keys ---"
+msgstr ""
+"\n"
+"--- Öն˰´¼ü ---"
+
+msgid "new shell started\n"
+msgstr "Æô¶¯Ð shell\n"
+
+msgid "Vim: Error reading input, exiting...\n"
+msgstr "Vim: ¶Á´íÎó£¬Í˳öÖÐ...\n"
+
+#. must display the prompt
+msgid "No undo possible; continue anyway"
+msgstr "ÎÞ·¨³·Ïú£»Çë¼ÌÐø"
+
+msgid "Already at oldest change"
+msgstr "ÒÑλÓÚ×î¾ÉµÄ¸Ä±ä"
+
+msgid "Already at newest change"
+msgstr "ÒÑλÓÚ×îеĸıä"
+
+#, c-format
+msgid "Undo number %ld not found"
+msgstr "ÕÒ²»µ½³·ÏúºÅ %ld"
+
+msgid "E438: u_undo: line numbers wrong"
+msgstr "E438: u_undo: ÐкŴíÎó"
+
+msgid "more line"
+msgstr "Ðб»¼ÓÈë"
+
+msgid "more lines"
+msgstr "Ðб»¼ÓÈë"
+
+msgid "line less"
+msgstr "Ðб»È¥µô"
+
+msgid "fewer lines"
+msgstr "Ðб»È¥µô"
+
+msgid "change"
+msgstr "Ðз¢Éú¸Ä±ä"
+
+msgid "changes"
+msgstr "Ðз¢Éú¸Ä±ä"
+
+#, c-format
+msgid "%ld %s; %s #%ld %s"
+msgstr "%ld %s£»%s #%ld %s"
+
+msgid "before"
+msgstr "before"
+
+msgid "after"
+msgstr "after"
+
+msgid "Nothing to undo"
+msgstr "Î޿ɳ·Ïú"
+
+msgid "number changes time"
+msgstr " ±àºÅ ¸Ä±ä ʱ¼ä"
+
+msgid "E439: undo list corrupt"
+msgstr "E439: ³·ÏúÁбíËð»µ"
+
+msgid "E440: undo line missing"
+msgstr "E440: ÕÒ²»µ½Òª³·ÏúµÄÐÐ"
+
+#. Only MS VC 4.1 and earlier can do Win32s
+msgid ""
+"\n"
+"MS-Windows 16/32-bit GUI version"
+msgstr ""
+"\n"
+"MS-Windows 16/32 λͼÐνçÃæ°æ±¾"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit GUI version"
+msgstr ""
+"\n"
+"MS-Windows 32 λͼÐνçÃæ°æ±¾"
+
+msgid " in Win32s mode"
+msgstr " Win32s ģʽ"
+
+msgid " with OLE support"
+msgstr " ´ø OLE Ö§³Ö"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit console version"
+msgstr ""
+"\n"
+"MS-Windows 32 λ¿ØÖÆ̨°æ±¾"
+
+msgid ""
+"\n"
+"MS-Windows 16-bit version"
+msgstr ""
+"\n"
+"MS-Windows 16 λ¿ØÖÆ̨°æ±¾"
+
+msgid ""
+"\n"
+"32-bit MS-DOS version"
+msgstr ""
+"\n"
+"32 λ MS-DOS °æ±¾"
+
+msgid ""
+"\n"
+"16-bit MS-DOS version"
+msgstr ""
+"\n"
+"16 λ MS-DOS °æ±¾"
+
+msgid ""
+"\n"
+"MacOS X (unix) version"
+msgstr ""
+"\n"
+"MacOS X (unix) °æ±¾"
+
+msgid ""
+"\n"
+"MacOS X version"
+msgstr ""
+"\n"
+"MacOS X °æ±¾"
+
+msgid ""
+"\n"
+"MacOS version"
+msgstr ""
+"\n"
+"MacOS °æ±¾"
+
+msgid ""
+"\n"
+"RISC OS version"
+msgstr ""
+"\n"
+"RISC OS °æ±¾"
+
+msgid ""
+"\n"
+"Included patches: "
+msgstr ""
+"\n"
+"°üº¬²¹¶¡: "
+
+msgid "Modified by "
+msgstr "ÐÞ¸ÄÕß "
+
+msgid ""
+"\n"
+"Compiled "
+msgstr ""
+"\n"
+"±àÒë"
+
+msgid "by "
+msgstr "Õß "
+
+msgid ""
+"\n"
+"Huge version "
+msgstr ""
+"\n"
+"¾ÞÐÍ°æ±¾ "
+
+msgid ""
+"\n"
+"Big version "
+msgstr ""
+"\n"
+"´óÐÍ°æ±¾ "
+
+msgid ""
+"\n"
+"Normal version "
+msgstr ""
+"\n"
+"Õý³£°æ±¾ "
+
+msgid ""
+"\n"
+"Small version "
+msgstr ""
+"\n"
+"СÐÍ°æ±¾ "
+
+msgid ""
+"\n"
+"Tiny version "
+msgstr ""
+"\n"
+"΢ÐÍ°æ±¾ "
+
+msgid "without GUI."
+msgstr "ÎÞͼÐνçÃæ¡£"
+
+msgid "with GTK2-GNOME GUI."
+msgstr "´ø GTK2-GNOME ͼÐνçÃæ¡£"
+
+msgid "with GTK-GNOME GUI."
+msgstr "´ø GTK-GNOME ͼÐνçÃæ¡£"
+
+msgid "with GTK2 GUI."
+msgstr "´ø GTK2 ͼÐνçÃæ¡£"
+
+msgid "with GTK GUI."
+msgstr "´ø GTK ͼÐνçÃæ¡£"
+
+msgid "with X11-Motif GUI."
+msgstr "´ø X11-Motif ͼÐνçÃæ¡£"
+
+msgid "with X11-neXtaw GUI."
+msgstr "´ø X11-neXtaw ͼÐνçÃæ¡£"
+
+msgid "with X11-Athena GUI."
+msgstr "´ø X11-Athena ͼÐνçÃæ¡£"
+
+msgid "with Photon GUI."
+msgstr "´ø Photon ͼÐνçÃæ¡£"
+
+msgid "with GUI."
+msgstr "´øͼÐνçÃæ¡£"
+
+msgid "with Carbon GUI."
+msgstr "´ø Carbon ͼÐνçÃæ¡£"
+
+msgid "with Cocoa GUI."
+msgstr "´ø Cocoa ͼÐνçÃæ¡£"
+
+msgid "with (classic) GUI."
+msgstr "´ø(´«Í³)ͼÐνçÃæ¡£"
+
+msgid " Features included (+) or not (-):\n"
+msgstr " ¿ÉʹÓÃ(+)Óë²»¿ÉʹÓÃ(-)µÄ¹¦ÄÜ:\n"
+
+msgid " system vimrc file: \""
+msgstr " ϵͳ vimrc Îļþ: \""
+
+msgid " user vimrc file: \""
+msgstr " Óû§ vimrc Îļþ: \""
+
+msgid " 2nd user vimrc file: \""
+msgstr " µÚ¶þÓû§ vimrc Îļþ: \""
+
+msgid " 3rd user vimrc file: \""
+msgstr " µÚÈýÓû§ vimrc Îļþ: \""
+
+msgid " user exrc file: \""
+msgstr " Óû§ exrc Îļþ: \""
+
+msgid " 2nd user exrc file: \""
+msgstr " µÚ¶þÓû§ exrc Îļþ: \""
+
+msgid " system gvimrc file: \""
+msgstr " ϵͳ gvimrc Îļþ: \""
+
+msgid " user gvimrc file: \""
+msgstr " Óû§ gvimrc Îļþ: \""
+
+msgid "2nd user gvimrc file: \""
+msgstr "µÚ¶þÓû§ gvimrc Îļþ: \""
+
+msgid "3rd user gvimrc file: \""
+msgstr "µÚÈýÓû§ gvimrc Îļþ: \""
+
+msgid " system menu file: \""
+msgstr " ϵͳ²Ëµ¥Îļþ: \""
+
+msgid " fall-back for $VIM: \""
+msgstr " $VIM Ô¤ÉèÖµ: \""
+
+msgid " f-b for $VIMRUNTIME: \""
+msgstr " $VIMRUNTIME Ô¤ÉèÖµ: \""
+
+msgid "Compilation: "
+msgstr "±àÒ뷽ʽ: "
+
+msgid "Compiler: "
+msgstr "±àÒëÆ÷: "
+
+msgid "Linking: "
+msgstr "Á´½Ó·½Ê½: "
+
+msgid " DEBUG BUILD"
+msgstr " µ÷ÊÔ°æ±¾"
+
+msgid "VIM - Vi IMproved"
+msgstr "VIM - Vi IMproved"
+
+msgid "version "
+msgstr "°æ±¾ "
+
+msgid "by Bram Moolenaar et al."
+msgstr "ά»¤ÈË Bram Moolenaar µÈ"
+
+msgid "Vim is open source and freely distributable"
+msgstr "Vim ÊÇ¿É×ÔÓÉ·Ö·¢µÄ¿ª·ÅÔ´´úÂëÈí¼þ"
+
+msgid "Help poor children in Uganda!"
+msgstr "°ïÖúÎڸɴïµÄ¿ÉÁ¯¶ùͯ£¡"
+
+msgid "type :help iccf<Enter> for information "
+msgstr "ÊäÈë :help iccf<Enter> ²é¿´ËµÃ÷ "
+
+msgid "type :q<Enter> to exit "
+msgstr "ÊäÈë :q<Enter> Í˳ö "
+
+msgid "type :help<Enter> or <F1> for on-line help"
+msgstr "ÊäÈë :help<Enter> »ò <F1> ²é¿´ÔÚÏß°ïÖú "
+
+msgid "type :help version8<Enter> for version info"
+msgstr "ÊäÈë :help version8<Enter> ²é¿´°æ±¾ÐÅÏ¢ "
+
+msgid "Running in Vi compatible mode"
+msgstr "ÔËÐÐÓÚ Vi ¼æÈÝģʽ"
+
+msgid "type :set nocp<Enter> for Vim defaults"
+msgstr "ÊäÈë :set nocp<Enter> »Ö¸´Ä¬È쵀 Vim "
+
+msgid "type :help cp-default<Enter> for info on this"
+msgstr "ÊäÈë :help cp-default<Enter> ²é¿´Ïà¹Ø˵Ã÷ "
+
+msgid "menu Help->Orphans for information "
+msgstr "²Ëµ¥ Help->Orphans ²é¿´ËµÃ÷ "
+
+msgid "Running modeless, typed text is inserted"
+msgstr "ÎÞģʽÔËÐУ¬ÊäÈëÎÄ×Ö¼´²åÈë"
+
+msgid "menu Edit->Global Settings->Toggle Insert Mode "
+msgstr "²Ëµ¥ Edit->Global Settings->Toggle Insert Mode "
+
+#, fuzzy
+#~ msgid " for two modes "
+#~ msgstr " # pid Êý¾Ý¿âÃû³Æ prepend path\n"
+
+#~ msgid "menu Edit->Global Settings->Toggle Vi Compatible"
+#~ msgstr ""
+
+#, fuzzy
+#~ msgid " for Vim defaults "
+#~ msgstr " # pid Êý¾Ý¿âÃû³Æ prepend path\n"
+
+msgid "Sponsor Vim development!"
+msgstr "ÔÞÖú Vim µÄ¿ª·¢£¡"
+
+msgid "Become a registered Vim user!"
+msgstr "³ÉΪ Vim µÄ×¢²áÓû§£¡"
+
+msgid "type :help sponsor<Enter> for information "
+msgstr "ÊäÈë :help sponsor<Enter> ²é¿´ËµÃ÷ "
+
+msgid "type :help register<Enter> for information "
+msgstr "ÊäÈë :help register<Enter> ²é¿´ËµÃ÷ "
+
+msgid "menu Help->Sponsor/Register for information "
+msgstr "²Ëµ¥ Help->Sponsor/Register ²é¿´ËµÃ÷ "
+
+msgid "WARNING: Windows 95/98/ME detected"
+msgstr "¾¯¸æ: ¼ì²âµ½ Windows 95/98/ME"
+
+msgid "type :help windows95<Enter> for info on this"
+msgstr "ÊäÈë :help windows95<Enter> ²é¿´Ïà¹Ø˵Ã÷ "
+
+msgid "Already only one window"
+msgstr "ÒѾ­Ö»Ê£Ò»¸ö´°¿ÚÁË"
+
+msgid "E441: There is no preview window"
+msgstr "E441: ûÓÐÔ¤ÀÀ´°¿Ú"
+
+msgid "E442: Can't split topleft and botright at the same time"
+msgstr "E442: ²»ÄÜͬʱ½øÐÐ topleft ºÍ botright ·Ö¸î"
+
+msgid "E443: Cannot rotate when another window is split"
+msgstr "E443: ÓÐÆäËü·Ö¸î´°¿Úʱ²»ÄÜÐýת"
+
+msgid "E444: Cannot close last window"
+msgstr "E444: ²»ÄܹرÕ×îºóÒ»¸ö´°¿Ú"
+
+msgid "E445: Other window contains changes"
+msgstr "E445: ÆäËü´°¿ÚÓиıäµÄÄÚÈÝ"
+
+msgid "E446: No file name under cursor"
+msgstr "E446: ¹â±ê´¦Ã»ÓÐÎļþÃû"
+
+#, c-format
+msgid "E447: Can't find file \"%s\" in path"
+msgstr "E447: ÔÚ·¾¶ÖÐÕÒ²»µ½Îļþ \"%s\""
+
+#, c-format
+msgid "E370: Could not load library %s"
+msgstr "E370: ÎÞ·¨¼ÓÔØ¿â %s"
+
+msgid "Sorry, this command is disabled: the Perl library could not be loaded."
+msgstr "±§Ç¸£¬´ËÃüÁî²»¿ÉÓÃ: ÎÞ·¨¼ÓÔØ Perl ¿â¡£"
+
+#~ msgid "E299: Perl evaluation forbidden in sandbox without the Safe module"
+#~ msgstr ""
+
+msgid "Edit with &multiple Vims"
+msgstr "Óöà¸ö Vim ±à¼­(&M)"
+
+msgid "Edit with single &Vim"
+msgstr "Óõ¥¸ö Vim ±à¼­(&V)"
+
+msgid "Diff with Vim"
+msgstr "Óà Vim ±È½Ï(diff)"
+
+msgid "Edit with &Vim"
+msgstr "Óà Vim ±à¼­(&V)"
+
+#. Now concatenate
+msgid "Edit with existing Vim - "
+msgstr "Óõ±Ç°µÄ Vim ±à¼­ - "
+
+msgid "Edits the selected file(s) with Vim"
+msgstr "Óà Vim ±à¼­Ñ¡ÖеÄÎļþ"
+
+msgid "Error creating process: Check if gvim is in your path!"
+msgstr "´´½¨½ø³Ìʧ°Ü: Çë¼ì²é gvim ÊÇ·ñÔÚ·¾¶ÖУ¡"
+
+msgid "gvimext.dll error"
+msgstr "gvimext.dll ´íÎó"
+
+msgid "Path length too long!"
+msgstr "·¾¶Ì«³¤£¡"
+
+msgid "--No lines in buffer--"
+msgstr "--»º³åÇøÎÞÄÚÈÝ--"
+
+#.
+#. * The error messages that can be shared are included here.
+#. * Excluded are errors that are only used once and debugging messages.
+#.
+msgid "E470: Command aborted"
+msgstr "E470: ÃüÁî±»ÖÐÖ¹"
+
+msgid "E471: Argument required"
+msgstr "E471: ÐèÒª²ÎÊý"
+
+msgid "E10: \\ should be followed by /, ? or &"
+msgstr "E10: \\ ºóÃæÓ¦¸Ã¸úÓÐ /¡¢? »ò &"
+
+msgid "E11: Invalid in command-line window; <CR> executes, CTRL-C quits"
+msgstr "E11: ÔÚÃüÁîÐд°¿ÚÖÐÎÞЧ£»<CR> Ö´ÐУ¬CTRL-C Í˳ö"
+
+msgid "E12: Command not allowed from exrc/vimrc in current dir or tag search"
+msgstr "E12: µ±Ç°Ä¿Â¼ÖÐµÄ exrc/vimrc »ò tag ²éÕÒÖв»ÔÊÐí´ËÃüÁî"
+
+msgid "E171: Missing :endif"
+msgstr "E171: ȱÉÙ :endif"
+
+msgid "E600: Missing :endtry"
+msgstr "E600: ȱÉÙ :endtry"
+
+msgid "E170: Missing :endwhile"
+msgstr "E170: ȱÉÙ :endwhile"
+
+msgid "E170: Missing :endfor"
+msgstr "E170: ȱÉÙ :endfor"
+
+msgid "E588: :endwhile without :while"
+msgstr "E588: :endwhile ȱÉÙ¶ÔÓ¦µÄ :while"
+
+msgid "E588: :endfor without :for"
+msgstr "E588: :endfor ȱÉÙ¶ÔÓ¦µÄ :for"
+
+msgid "E13: File exists (add ! to override)"
+msgstr "E13: ÎļþÒÑ´æÔÚ (Çë¼Ó ! Ç¿ÖÆÖ´ÐÐ)"
+
+msgid "E472: Command failed"
+msgstr "E472: ÃüÁîÖ´ÐÐʧ°Ü"
+
+#, c-format
+msgid "E234: Unknown fontset: %s"
+msgstr "E234: δ֪µÄ Fontset: %s"
+
+#, c-format
+msgid "E235: Unknown font: %s"
+msgstr "E235: δ֪µÄ×ÖÌå: %s"
+
+#, c-format
+msgid "E236: Font \"%s\" is not fixed-width"
+msgstr "E236: ×ÖÌå \"%s\" ²»Êǵȿí×ÖÌå"
+
+msgid "E473: Internal error"
+msgstr "E473: ÄÚ²¿´íÎó"
+
+msgid "Interrupted"
+msgstr "ÒÑÖжÏ"
+
+msgid "E14: Invalid address"
+msgstr "E14: ÎÞЧµÄµØÖ·"
+
+msgid "E474: Invalid argument"
+msgstr "E474: ÎÞЧµÄ²ÎÊý"
+
+#, c-format
+msgid "E475: Invalid argument: %s"
+msgstr "E475: ÎÞЧµÄ²ÎÊý: %s"
+
+#, c-format
+msgid "E15: Invalid expression: %s"
+msgstr "E15: ÎÞЧµÄ±í´ïʽ: %s"
+
+msgid "E16: Invalid range"
+msgstr "E16: ÎÞЧµÄ·¶Î§"
+
+msgid "E476: Invalid command"
+msgstr "E476: ÎÞЧµÄÃüÁî"
+
+#, c-format
+msgid "E17: \"%s\" is a directory"
+msgstr "E17: \"%s\" ÊÇĿ¼"
+
+#, c-format
+msgid "E364: Library call failed for \"%s()\""
+msgstr "E364: µ÷Óú¯Êý¿â \"%s()\" ʧ°Ü"
+
+#, c-format
+msgid "E448: Could not load library function %s"
+msgstr "E448: ÎÞ·¨¼ÓÔؿ⺯Êý %s"
+
+msgid "E19: Mark has invalid line number"
+msgstr "E19: ±ê¼ÇµÄÐкÅÎÞЧ"
+
+msgid "E20: Mark not set"
+msgstr "E20: ûÓÐÉ趨±ê¼Ç"
+
+msgid "E21: Cannot make changes, 'modifiable' is off"
+msgstr "E21: ²»ÄÜÐ޸ģ¬ÒòΪѡÏî 'modifiable' ÊǹصÄ"
+
+msgid "E22: Scripts nested too deep"
+msgstr "E22: ½Å±¾Ç¶Ì×¹ýÉî"
+
+msgid "E23: No alternate file"
+msgstr "E23: ûÓн»ÌæÎļþ"
+
+msgid "E24: No such abbreviation"
+msgstr "E24: ûÓÐÕâ¸öËõд"
+
+msgid "E477: No ! allowed"
+msgstr "E477: ²»ÄÜʹÓà \"!\""
+
+msgid "E25: GUI cannot be used: Not enabled at compile time"
+msgstr "E25: ÎÞ·¨Ê¹ÓÃͼÐνçÃæ: ±àÒëʱûÓÐÆôÓÃ"
+
+msgid "E26: Hebrew cannot be used: Not enabled at compile time\n"
+msgstr "E26: ÎÞ·¨Ê¹Óà Hebrew: ±àÒëʱûÓÐÆôÓÃ\n"
+
+msgid "E27: Farsi cannot be used: Not enabled at compile time\n"
+msgstr "E27: ÎÞ·¨Ê¹Óà Farsi: ±àÒëʱûÓÐÆôÓÃ\n"
+
+msgid "E800: Arabic cannot be used: Not enabled at compile time\n"
+msgstr "E800: ÎÞ·¨Ê¹Óà Arabic: ±àÒëʱûÓÐÆôÓÃ\n"
+
+#, c-format
+msgid "E28: No such highlight group name: %s"
+msgstr "E28: ûÓÐÕâ¸ö¸ßÁÁȺ×éÃû: %s"
+
+msgid "E29: No inserted text yet"
+msgstr "E29: ûÓвåÈë¹ýÎÄ×Ö"
+
+msgid "E30: No previous command line"
+msgstr "E30: ûÓÐÇ°Ò»¸öÃüÁîÐÐ"
+
+msgid "E31: No such mapping"
+msgstr "E31: ûÓÐÕâ¸öÓ³Éä"
+
+msgid "E479: No match"
+msgstr "E479: ûÓÐÆ¥Åä"
+
+#, c-format
+msgid "E480: No match: %s"
+msgstr "E480: ûÓÐÆ¥Åä: %s"
+
+msgid "E32: No file name"
+msgstr "E32: ûÓÐÎļþÃû"
+
+msgid "E33: No previous substitute regular expression"
+msgstr "E33: ûÓÐÇ°Ò»¸öÌæ»»ÕýÔò±í´ïʽ"
+
+msgid "E34: No previous command"
+msgstr "E34: ûÓÐÇ°Ò»¸öÃüÁî"
+
+msgid "E35: No previous regular expression"
+msgstr "E35: ûÓÐÇ°Ò»¸öÕýÔò±í´ïʽ"
+
+msgid "E481: No range allowed"
+msgstr "E481: ²»ÄÜʹÓ÷¶Î§"
+
+msgid "E36: Not enough room"
+msgstr "E36: ûÓÐ×ã¹»µÄ¿Õ¼ä"
+
+#, c-format
+msgid "E247: no registered server named \"%s\""
+msgstr "E247: ûÓÐÃû½Ð \"%s\" µÄÒÑ×¢²áµÄ·þÎñÆ÷"
+
+#, c-format
+msgid "E482: Can't create file %s"
+msgstr "E482: ÎÞ·¨´´½¨Îļþ %s"
+
+msgid "E483: Can't get temp file name"
+msgstr "E483: ÎÞ·¨»ñÈ¡ÁÙʱÎļþÃû"
+
+#, c-format
+msgid "E484: Can't open file %s"
+msgstr "E484: ÎÞ·¨´ò¿ªÎļþ %s"
+
+#, c-format
+msgid "E485: Can't read file %s"
+msgstr "E485: ÎÞ·¨¶ÁÈ¡Îļþ %s"
+
+msgid "E37: No write since last change (add ! to override)"
+msgstr "E37: ÒÑÐ޸ĵ«ÉÐδ±£´æ (¿ÉÓà ! Ç¿ÖÆÖ´ÐÐ)"
+
+msgid "E38: Null argument"
+msgstr "E38: ¿ÕµÄ²ÎÊý"
+
+msgid "E39: Number expected"
+msgstr "E39: ´Ë´¦ÐèÒªÊý×Ö"
+
+#, c-format
+msgid "E40: Can't open errorfile %s"
+msgstr "E40: ÎÞ·¨´ò¿ª´íÎóÎļþ %s"
+
+msgid "E233: cannot open display"
+msgstr "E233: ÎÞ·¨´ò¿ª display"
+
+msgid "E41: Out of memory!"
+msgstr "E41: ÄÚ´æ²»×㣡"
+
+msgid "Pattern not found"
+msgstr "ÕÒ²»µ½Ä£Ê½"
+
+#, c-format
+msgid "E486: Pattern not found: %s"
+msgstr "E486: ÕÒ²»µ½Ä£Ê½: %s"
+
+msgid "E487: Argument must be positive"
+msgstr "E487: ²ÎÊý±ØÐëÊÇÕýÊý"
+
+msgid "E459: Cannot go back to previous directory"
+msgstr "E459: ÎÞ·¨»Øµ½Ç°Ò»¸öĿ¼"
+
+msgid "E42: No Errors"
+msgstr "E42: ûÓдíÎó"
+
+msgid "E776: No location list"
+msgstr "E776: ûÓÐ location Áбí"
+
+msgid "E43: Damaged match string"
+msgstr "E43: ÒÑË𻵵ÄÆ¥Åä×Ö·û´®"
+
+msgid "E44: Corrupted regexp program"
+msgstr "E44: ÒÑË𻵵ÄÕýÔò±í´ïʽ³ÌÐò"
+
+msgid "E45: 'readonly' option is set (add ! to override)"
+msgstr "E45: ÒÑÉ趨ѡÏî 'readonly' (Çë¼Ó ! Ç¿ÖÆÖ´ÐÐ)"
+
+#, c-format
+msgid "E46: Cannot change read-only variable \"%s\""
+msgstr "E46: ²»ÄܸıäÖ»¶Á±äÁ¿ \"%s\""
+
+#, c-format
+msgid "E46: Cannot set variable in the sandbox: \"%s\""
+msgstr "E46: ²»ÄÜÔÚ sandbox ÖÐÉ趨±äÁ¿: \"%s\""
+
+msgid "E47: Error while reading errorfile"
+msgstr "E47: ¶ÁÈ¡´íÎóÎļþʧ°Ü"
+
+msgid "E48: Not allowed in sandbox"
+msgstr "E48: ²»ÔÊÐíÔÚ sandbox ÖÐʹÓÃ"
+
+msgid "E523: Not allowed here"
+msgstr "E523: ²»ÔÊÐíÔÚ´ËʹÓÃ"
+
+msgid "E359: Screen mode setting not supported"
+msgstr "E359: ²»Ö§³ÖÉ趨ÆÁĻģʽ"
+
+msgid "E49: Invalid scroll size"
+msgstr "E49: ÎÞЧµÄ¹ö¶¯´óС"
+
+msgid "E91: 'shell' option is empty"
+msgstr "E91: Ñ¡Ïî 'shell' Ϊ¿Õ"
+
+msgid "E255: Couldn't read in sign data!"
+msgstr "E255: ÎÞ·¨¶ÁÈ¡ sign Êý¾Ý£¡"
+
+msgid "E72: Close error on swap file"
+msgstr "E72: ½»»»Îļþ¹Ø±Õ´íÎó"
+
+msgid "E73: tag stack empty"
+msgstr "E73: tag ¶ÑջΪ¿Õ"
+
+msgid "E74: Command too complex"
+msgstr "E74: ÃüÁî¹ý¸´ÔÓ"
+
+msgid "E75: Name too long"
+msgstr "E75: Ãû×Ö¹ý³¤"
+
+msgid "E76: Too many ["
+msgstr "E76: [ ¹ý¶à"
+
+msgid "E77: Too many file names"
+msgstr "E77: ÎļþÃû¹ý¶à"
+
+msgid "E488: Trailing characters"
+msgstr "E488: ¶àÓàµÄβ²¿×Ö·û"
+
+msgid "E78: Unknown mark"
+msgstr "E78: δ֪µÄ±ê¼Ç"
+
+msgid "E79: Cannot expand wildcards"
+msgstr "E79: ÎÞ·¨À©Õ¹Í¨Åä·û"
+
+msgid "E591: 'winheight' cannot be smaller than 'winminheight'"
+msgstr "E591: 'winheight' ²»ÄÜСÓÚ 'winminheight'"
+
+msgid "E592: 'winwidth' cannot be smaller than 'winminwidth'"
+msgstr "E592: 'winwidth' ²»ÄÜСÓÚ 'winminwidth'"
+
+msgid "E80: Error while writing"
+msgstr "E80: дÈë³ö´í"
+
+msgid "Zero count"
+msgstr "¼ÆÊýΪÁã"
+
+msgid "E81: Using <SID> not in a script context"
+msgstr "E81: Ôڽű¾»·¾³ÍâʹÓÃÁË <SID>"
+
+msgid "E449: Invalid expression received"
+msgstr "E449: ÊÕµ½ÎÞЧµÄ±í´ïʽ"
+
+#~ msgid "E463: Region is guarded, cannot modify"
+#~ msgstr ""
+
+msgid "E744: NetBeans does not allow changes in read-only files"
+msgstr "E744: NetBeans ²»ÔÊÐí¸Ä±äÖ»¶ÁÎļþ"
+
+#, c-format
+msgid "E685: Internal error: %s"
+msgstr "E685: ÄÚ²¿´íÎó: %s"
+
+msgid "E363: pattern uses more memory than 'maxmempattern'"
+msgstr "E363: ±í´ïʽµÄÄÚ´æʹÓó¬³ö 'maxmempattern'"
+
+msgid "E749: empty buffer"
+msgstr "E749: ¿ÕµÄ»º³åÇø"
+
+msgid "E682: Invalid search pattern or delimiter"
+msgstr "E682: ÎÞЧµÄËÑË÷±í´ïʽ»ò·Ö¸ô·û"
+
+msgid "E139: File is loaded in another buffer"
+msgstr "E139: ÎļþÒÑÔÚÁíÒ»¸ö»º³åÇøÖб»¼ÓÔØ"
+
+#, c-format
+msgid "E764: Option '%s' is not set"
+msgstr "E764: ûÓÐÉ趨ѡÏî '%s'"
+
+msgid "search hit TOP, continuing at BOTTOM"
+msgstr "ÒѲéÕÒµ½Îļþ¿ªÍ·£¬ÔÙ´Ó½áβ¼ÌÐø²éÕÒ"
+
+msgid "search hit BOTTOM, continuing at TOP"
+msgstr "ÒѲéÕÒµ½Îļþ½á⣬ÔÙ´Ó¿ªÍ·¼ÌÐø²éÕÒ"
+
+#~ msgid "Affix flags ignored when PFXPOSTPONE used in %s line %d: %s"
+#~ msgstr "%s µÚ %d ÐУ¬Ê¹Óà PFXPOSTPONE ʱ¸½¼Ó±êÖ¾±»ºöÂÔ: %s"
+
+#~ msgid "[No file]"
+#~ msgstr "[δÃüÃû]"
+
+#~ msgid "[Error List]"
+#~ msgstr "[´íÎóÁбí]"
+
+#~ msgid "E106: Unknown variable: \"%s\""
+#~ msgstr "E106: 䶨ÒåµÄ±äÁ¿: \"%s\""
+
+#~ msgid "E119: Not enough arguments for function: %s"
+#~ msgstr "E119: º¯Êý %s µÄ²ÎÊýÌ«ÉÙ"
+
+#~ msgid "E120: Using <SID> not in a script context: %s"
+#~ msgstr "E120: <SID> ²»ÄÜÔÚ script ÉÏÏÂÎÄÍâʹÓÃ: %s"
+
+#~ msgid "E123: Undefined function: %s"
+#~ msgstr "E123: º¯Êý %s ÉÐ䶨Òå"
+
+#~ msgid "E127: Cannot redefine function %s: It is in use"
+#~ msgstr "E127: º¯Êý %s ÕýÔÚʹÓÃÖУ¬²»ÄÜÖØж¨Òå"
+
+#~ msgid "function "
+#~ msgstr "º¯Êý "
+
+#~ msgid "E130: Undefined function: %s"
+#~ msgstr "E130: º¯Êý %s ÉÐ䶨Òå"
+
+#~ msgid "Run Macro"
+#~ msgstr "Ö´Ðкê"
+
+#~ msgid "E242: Color name not recognized: %s"
+#~ msgstr "E242: %s Ϊ²»ÄÜʶ±ðµÄÑÕÉ«Ãû³Æ"
+
+#~ msgid "error reading cscope connection %d"
+#~ msgstr "¶ÁÈ¡ cscope Á¬½Ó %d ʱ´íÎó"
+
+#~ msgid "E260: cscope connection not found"
+#~ msgstr "E260: ÕÒ²»µ½ cscope Á¬½Ó"
+
+#~ msgid "cscope connection closed"
+#~ msgstr "cscope Á¬½ÓÒѹرÕ"
+
+#~ msgid "couldn't malloc\n"
+#~ msgstr "²»ÄÜʹÓà malloc\n"
+
+#~ msgid "%2d %-5ld %-34s <none>\n"
+#~ msgstr "%2d %-5ld %-34s <ÎÞ>\n"
+
+#~ msgid "E249: couldn't read VIM instance registry property"
+#~ msgstr "E249: ²»ÄܶÁÈ¡ VIM µÄ ×¢²á±íÊôÐÔ"
+
+#~ msgid "\"\n"
+#~ msgstr "\"\n"
+
+#~ msgid "--help\t\tShow Gnome arguments"
+#~ msgstr "--help\t\tÏÔʾ Gnome Ïà¹Ø²ÎÊý"
+
+#~ msgid "[string too long]"
+#~ msgstr "[×Ö·û´®Ì«³¤]"
+
+#~ msgid "Hit ENTER to continue"
+#~ msgstr "Çë°´ ENTER ¼ÌÐø"
+
+#~ msgid " (RET/BS: line, SPACE/b: page, d/u: half page, q: quit)"
+#~ msgstr " (RET/BS: ÏòÏÂ/ÏòÉÏÒ»ÐÐ, ¿Õ¸ñ/b: Ò»Ò³, d/u: °ëÒ³, q: Í˳ö)"
+
+#~ msgid " (RET: line, SPACE: page, d: half page, q: quit)"
+#~ msgstr " (RET: ÏòÏÂÒ»ÐÐ, ¿Õ°×¼ü: Ò»Ò³, d: °ëÒ³, q: Í˳ö)"
+
+#~ msgid "E361: Crash intercepted; regexp too complex?"
+#~ msgstr "E361: ²»ÄÜÖ´ÐÐ; regular expression Ì«¸´ÔÓ?"
+
+#~ msgid "E363: pattern caused out-of-stack error"
+#~ msgstr "E363: regular expression Ôì³É¶ÑÕ»ÓùâµÄ´íÎó"
+
+#~ msgid " BLOCK"
+#~ msgstr " ¿é"
+
+#~ msgid " LINE"
+#~ msgstr " ÐÐ"
+
+#~ msgid "Enter nr of choice (<CR> to abort): "
+#~ msgstr "ÊäÈë nr »òÑ¡Ôñ (<CR> Í˳ö): "
+
+#~ msgid "Linear tag search"
+#~ msgstr "ÏßÐÔ²éÕÒ±êÇ© (Tags)"
+
+#~ msgid "Binary tag search"
+#~ msgstr "¶þ½øÖƲéÕÒ(Binary search) ±êÇ©(Tags)"
+
+#~ msgid "with BeOS GUI."
+#~ msgstr "ʹÓà BeOS ͼÐνçÃæ¡£"
diff --git a/src/po/zh_TW.UTF-8.po b/src/po/zh_TW.UTF-8.po
new file mode 100644
index 0000000..8b3656c
--- /dev/null
+++ b/src/po/zh_TW.UTF-8.po
@@ -0,0 +1,5282 @@
+# Traditional Chinese Translation for Vim vim:set foldmethod=marker:
+#
+# Do ":help uganda" in Vim to read copying and usage conditions.
+# Do ":help credits" in Vim to see a list of people who contributed.
+#
+# FIRST AUTHOR Francis S.Lin <piaip@csie.ntu.edu.tw>, 2000
+# FIRST RELEASE Thu Jun 14 14:24:17 CST 2001
+# MAINTAINER: Debian VIM Maintainers <pkg-vim-maintainers@lists.alioth.debian.org>
+#
+# Last update: $LastChangedDate: 2006-04-16 22:06:40 -0400 (dom, 16 apr 2006) $
+#
+# XXX This file is in need of a new maintainer, Debian VIM Maintainers maintain
+# it only because patches have been submitted for it by Debian users and the
+# former maintainer was MIA (Missing In Action), taking over its
+# maintenance was thus the only way to include those patches.
+# If you care about this file, and have time to maintain it please do so!
+#
+# To update, search pattern: /fuzzy\|^msgstr ""\(\n"\)\@!
+#
+# DO NOT USE WORDS WITH BACKSLASH ('\') AS SECOND BYTE OF BIG5 CHARS
+# EG: '功', # 許功蓋
+# [blacklist: é¤æž¯é–±ç®ç©€è·šæ·šèº¡è±¹æ“ºç’žç¸·é«å­æ­¿ä¿ž]
+# [blacklist: 娉崤黠孀廄çµæ„§éˆ¾æšä¹ˆå’苒塿踊]
+# you can replace these characters with alternative words.
+# THIS WILL CAUSE INCOMPATIBLE ON gettext 0.10.36+
+#
+# Note (2005.01.27):
+# A bug was found for UTF8 mode.
+# > msgid "%ld fewer lines" "on %ld lines"
+# If you don't put more (at least 2) spaces after %ld
+# gvim/win32 will crash (no reason).
+# So please change [行"] to [行 "]
+#
+# Q. How to use UTF8 mode on Win32?
+# A. A simple configuration:
+# set encoding=utf-8; let $LANG='zh_TW.UTF-8';
+# (set langmenu=none or ..)
+# set termencoding=utf-8
+# set fileencodings=ucs-bom,utf-8,japan,taiwan,prc
+# set fileencoding=taiwan (or utf-8)
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Vim(Traditional Chinese)\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2005-01-27 19:00+0800\n"
+"PO-Revision-Date: Mon Feb 19 22:49:21 CST 2001\n"
+"Last-Translator: Hung-Te Lin <piaip@csie.ntu.edu.tw>\n"
+"Language-Team: Hung-Te Lin <piaip@csie.ntu.edu.tw>, Cecil Sheng "
+"<b7506022@csie.ntu.edu.tw>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8-bit\n"
+
+msgid "E82: Cannot allocate any buffer, exiting..."
+msgstr "E82: 無法é…置任何緩è¡å€ï¼Œé›¢é–‹ç¨‹å¼..."
+
+msgid "E83: Cannot allocate buffer, using other one..."
+msgstr "E83: 無法é…置緩è¡å€ï¼Œä½¿ç”¨å¦ä¸€å€‹ç·©è¡å€...."
+
+#, c-format
+msgid "E515: No buffers were unloaded"
+msgstr "E515: 沒有釋放任何緩è¡å€"
+
+#, c-format
+msgid "E516: No buffers were deleted"
+msgstr "E516: 沒有刪除任何緩è¡å€"
+
+#, c-format
+msgid "E517: No buffers were wiped out"
+msgstr "E517: 沒有清除任何緩è¡å€"
+
+msgid "1 buffer unloaded"
+msgstr "已釋放一個緩è¡å€"
+
+#, c-format
+msgid "%d buffers unloaded"
+msgstr "已釋放 %d 個緩è¡å€"
+
+msgid "1 buffer deleted"
+msgstr "已刪除一個緩è¡å€"
+
+#, c-format
+msgid "%d buffers deleted"
+msgstr "已刪除 %d 個緩è¡å€"
+
+msgid "1 buffer wiped out"
+msgstr "已刪除一個緩è¡å€"
+
+#, c-format
+msgid "%d buffers wiped out"
+msgstr "已刪除 %d 個緩è¡å€"
+
+msgid "E84: No modified buffer found"
+msgstr "E84: 沒有修改éŽçš„ç·©è¡å€"
+
+#. back where we started, didn't find anything.
+msgid "E85: There is no listed buffer"
+msgstr "E85: 沒有列出的緩è¡å€"
+
+#, c-format
+msgid "E86: Buffer %ld does not exist"
+msgstr "E86: ç·©è¡å€ %ld ä¸å­˜åœ¨"
+
+msgid "E87: Cannot go beyond last buffer"
+msgstr "E87: 無法切æ›åˆ°æ›´å¾Œé¢çš„ç·©è¡å€"
+
+msgid "E88: Cannot go before first buffer"
+msgstr "E88: 無法切æ›åˆ°æ›´å‰é¢çš„ç·©è¡å€"
+
+#, c-format
+msgid "E89: No write since last change for buffer %ld (add ! to override)"
+msgstr "E89: 已更改éŽç·©è¡å€ %ld 但尚未存檔 (å¯ç”¨ ! 強制執行)"
+
+msgid "E90: Cannot unload last buffer"
+msgstr "E90: 無法釋放最後一個緩è¡å€"
+
+msgid "W14: Warning: List of file names overflow"
+msgstr "W14: 警告: 檔åéŽå¤š"
+
+#, c-format
+msgid "E92: Buffer %ld not found"
+msgstr "E92: 找ä¸åˆ°ç¬¬ %ld 個緩è¡å€"
+
+#, c-format
+msgid "E93: More than one match for %s"
+msgstr "E93: 找到一個以上的 %s"
+
+#, c-format
+msgid "E94: No matching buffer for %s"
+msgstr "E94: 找ä¸åˆ° %s"
+
+#, c-format
+msgid "line %ld"
+msgstr "行 %ld"
+
+msgid "E95: Buffer with this name already exists"
+msgstr "E95: 已有緩è¡å€ä½¿ç”¨é€™å€‹åå­—"
+
+msgid " [Modified]"
+msgstr " [已修改]"
+
+msgid "[Not edited]"
+msgstr "[未編輯]"
+
+msgid "[New file]"
+msgstr "[新檔案]"
+
+msgid "[Read errors]"
+msgstr "[讀å–錯誤]"
+
+msgid "[readonly]"
+msgstr "[唯讀]"
+
+#, c-format
+msgid "1 line --%d%%--"
+msgstr "行數 1 --%d%%--"
+
+#, c-format
+msgid "%ld lines --%d%%--"
+msgstr "行數 %ld --%d%%--"
+
+#, c-format
+msgid "line %ld of %ld --%d%%-- col "
+msgstr "行 %ld/%ld --%d%%-- 欄 "
+
+msgid "[No file]"
+msgstr "[未命å]"
+
+#. must be a help buffer
+msgid "help"
+msgstr "[輔助說明]"
+
+msgid "[help]"
+msgstr "[輔助說明]"
+
+msgid "[Preview]"
+msgstr "[é è¦½]"
+
+msgid "All"
+msgstr "全部"
+
+msgid "Bot"
+msgstr "底端"
+
+msgid "Top"
+msgstr "頂端"
+
+#, c-format
+msgid ""
+"\n"
+"# Buffer list:\n"
+msgstr ""
+"\n"
+"# ç·©è¡å€åˆ—表:\n"
+
+msgid "[Error List]"
+msgstr "[錯誤列表]"
+
+msgid "[No File]"
+msgstr "[未命å]"
+
+msgid ""
+"\n"
+"--- Signs ---"
+msgstr ""
+"\n"
+"--- 符號 ---"
+
+#, c-format
+msgid "Signs for %s:"
+msgstr "%s 的符號:"
+
+#, c-format
+msgid " line=%ld id=%d name=%s"
+msgstr " è¡Œ=%ld id=%d å稱=%s"
+
+#, c-format
+msgid "E96: Can not diff more than %ld buffers"
+msgstr "E96: 無法比較(diff) %ld個以上的緩è¡å€"
+
+msgid "E97: Cannot create diffs"
+msgstr "E97: ä¸èƒ½å»ºç«‹ "
+
+msgid "Patch file"
+msgstr "Patch 檔案"
+
+msgid "E98: Cannot read diff output"
+msgstr "E98: ç„¡æ³•è®€å– diff 的輸出"
+
+msgid "E99: Current buffer is not in diff mode"
+msgstr "E99: ç›®å‰çš„ç·©è¡å€ä¸æ˜¯åœ¨ diff 模å¼"
+
+msgid "E100: No other buffer in diff mode"
+msgstr "E100: 沒有緩è¡å€åœ¨ diff 模å¼"
+
+msgid "E101: More than two buffers in diff mode, don't know which one to use"
+msgstr "E101: 有兩個以上的緩è¡å€åœ¨ diff 模å¼ï¼Œç„¡æ³•æ±ºå®šè¦ç”¨å“ªä¸€å€‹"
+
+#, c-format
+msgid "E102: Can't find buffer \"%s\""
+msgstr "E102: 找ä¸åˆ°ç·©è¡å€: \"%s\""
+
+#, c-format
+msgid "E103: Buffer \"%s\" is not in diff mode"
+msgstr "E103: ç·©è¡å€ \"%s\" ä¸æ˜¯åœ¨ diff 模å¼"
+
+msgid "E104: Escape not allowed in digraph"
+msgstr "E104: 複åˆå­—å…ƒ(digraph)中ä¸èƒ½ä½¿ç”¨ Escape"
+
+msgid "E544: Keymap file not found"
+msgstr "E544: 找ä¸åˆ° keymap 檔"
+
+msgid "E105: Using :loadkeymap not in a sourced file"
+msgstr "E105: 使用 :loadkeymap "
+
+msgid " Keyword completion (^N^P)"
+msgstr " é—œéµå­—è‡ªå‹•å®Œæˆ (^N^P)"
+
+#. ctrl_x_mode == 0, ^P/^N compl.
+msgid " ^X mode (^E^Y^L^]^F^I^K^D^V^N^P)"
+msgstr " ^X æ¨¡å¼ (^E^Y^L^]^F^I^K^D^N^P)"
+
+#. Scroll has it's own msgs, in it's place there is the msg for local
+#. * ctrl_x_mode = 0 (eg continue_status & CONT_LOCAL) -- Acevedo
+msgid " Keyword Local completion (^N^P)"
+msgstr " å€åŸŸé—œéµå­—è‡ªå‹•å®Œæˆ (^N^P)"
+
+msgid " Whole line completion (^L^N^P)"
+msgstr " æ•´è¡Œè‡ªå‹•å®Œæˆ (^L^N^P)"
+
+msgid " File name completion (^F^N^P)"
+msgstr " 檔åè‡ªå‹•å®Œæˆ (^F^N^P)"
+
+msgid " Tag completion (^]^N^P)"
+msgstr " æ¨™ç±¤è‡ªå‹•å®Œæˆ (^]^N^P)"
+
+msgid " Path pattern completion (^N^P)"
+msgstr " è·¯å¾‘è‡ªå‹•å®Œæˆ (^N^P)"
+
+msgid " Definition completion (^D^N^P)"
+msgstr " å®šç¾©è‡ªå‹•å®Œæˆ (^D^N^P)"
+
+msgid " Dictionary completion (^K^N^P)"
+msgstr " å­—å…¸è‡ªå‹•å®Œæˆ (^K^N^P)"
+
+msgid " Thesaurus completion (^T^N^P)"
+msgstr " Thesaurus è‡ªå‹•å®Œæˆ (^T^N^P)"
+
+msgid " Command-line completion (^V^N^P)"
+msgstr " å‘½ä»¤åˆ—è‡ªå‹•å®Œæˆ (^V^N^P)"
+
+msgid "Hit end of paragraph"
+msgstr "已到段è½çµå°¾"
+
+msgid "'thesaurus' option is empty"
+msgstr "é¸é … 'thesaurus' 未設定"
+
+msgid "'dictionary' option is empty"
+msgstr "é¸é … 'dictionary' 未設定"
+
+#, c-format
+msgid "Scanning dictionary: %s"
+msgstr "掃瞄字典: %s"
+
+msgid " (insert) Scroll (^E/^Y)"
+msgstr " (æ’å…¥) Scroll (^E/^Y)"
+
+msgid " (replace) Scroll (^E/^Y)"
+msgstr " (å–代) Scroll (^E/^Y)"
+
+#, c-format
+msgid "Scanning: %s"
+msgstr "掃瞄中: %s"
+
+#, c-format
+msgid "Scanning tags."
+msgstr "掃瞄標籤."
+
+msgid " Adding"
+msgstr " 增加"
+
+#. showmode might reset the internal line pointers, so it must
+#. * be called before line = ml_get(), or when this address is no
+#. * longer needed. -- Acevedo.
+#.
+msgid "-- Searching..."
+msgstr "-- æœå°‹ä¸­..."
+
+msgid "Back at original"
+msgstr "回到起點"
+
+msgid "Word from other line"
+msgstr "從別行開始的字 (?)"
+
+msgid "The only match"
+msgstr "åªæœ‰æ­¤é …符åˆ"
+
+#, c-format
+msgid "match %d of %d"
+msgstr "找到 %d / %d"
+
+#, c-format
+msgid "match %d"
+msgstr "ç¬¦åˆ %d"
+
+#. Skip further arguments but do continue to
+#. * search for a trailing command.
+#, c-format
+msgid "E106: Unknown variable: \"%s\""
+msgstr "E106: 未定義的變數: \"%s\""
+
+#, c-format
+msgid "E107: Missing parentheses: %s"
+msgstr "E107: 缺少å°æ‡‰çš„括號: %s"
+
+#, c-format
+msgid "E108: No such variable: \"%s\""
+msgstr "E108: 無此變數: \"%s\""
+
+msgid "E109: Missing ':' after '?'"
+msgstr "E109: '?' 後缺少 ':'"
+
+msgid "E110: Missing ')'"
+msgstr "E110: 缺少å°æ‡‰çš„ \")\""
+
+msgid "E111: Missing ']'"
+msgstr "E111: 缺少å°æ‡‰çš„ \"]\""
+
+#, c-format
+msgid "E112: Option name missing: %s"
+msgstr "E112: 缺少é¸é …å稱: %s"
+
+#, c-format
+msgid "E113: Unknown option: %s"
+msgstr "E113: ä¸æ­£ç¢ºçš„é¸é …: %s"
+
+#, c-format
+msgid "E114: Missing quote: %s"
+msgstr "E114: 缺少引號: %s"
+
+#, c-format
+msgid "E115: Missing quote: %s"
+msgstr "E115: 缺少引號: %s"
+
+#, c-format
+msgid "E116: Invalid arguments for function %s"
+msgstr "E116: å‡½å¼ %s 的引數ä¸æ­£ç¢º"
+
+#, c-format
+msgid "E117: Unknown function: %s"
+msgstr "E117: 未定義的函å¼: %s"
+
+#, c-format
+msgid "E118: Too many arguments for function: %s"
+msgstr "E118: å‡½å¼ %s 的引數éŽå¤š"
+
+#, c-format
+msgid "E119: Not enough arguments for function: %s"
+msgstr "E119: å‡½å¼ %s 的引數太少"
+
+#, c-format
+msgid "E120: Using <SID> not in a script context: %s"
+msgstr "E120: <SID> ä¸èƒ½åœ¨ script 本文外使用: %s"
+
+#.
+#. * Yes this is ugly, I don't particularly like it either. But doing it
+#. * this way has the compelling advantage that translations need not to
+#. * be touched at all. See below what 'ok' and 'ync' are used for.
+#.
+msgid "&Ok"
+msgstr "確定(&O)"
+
+#, c-format
+msgid "+-%s%3ld lines: "
+msgstr "+-%s%3ld 行: "
+
+msgid ""
+"&OK\n"
+"&Cancel"
+msgstr ""
+"確定(&O)\n"
+"å–消(&C)"
+
+msgid "called inputrestore() more often than inputsave()"
+msgstr "å‘¼å« inputrestore() 的次數比 inputsave() 還多"
+
+msgid "E655: Too many symbolic links (cycle?)"
+msgstr "E655: 太多層的符號éˆçµ(symlink) (循環?)"
+
+msgid "E240: No connection to Vim server"
+msgstr "E240: 沒有與 Vim Server 建立連線"
+
+msgid "E277: Unable to read a server reply"
+msgstr "E277: 無法讀å–伺æœå™¨çš„回應"
+
+msgid "E258: Unable to send to client"
+msgstr "E258: 無法傳é€åˆ° client"
+
+#, c-format
+msgid "E241: Unable to send to %s"
+msgstr "E241: 無法傳é€åˆ° %s"
+
+msgid "(Invalid)"
+msgstr "(ä¸æ­£ç¢º)"
+
+#, c-format
+msgid "E121: Undefined variable: %s"
+msgstr "E121: 變數 %s 尚未定義"
+
+#, c-format
+msgid "E461: Illegal variable name: %s"
+msgstr "E461: ä¸åˆæ³•çš„變數å稱: %s"
+
+#, c-format
+msgid "E122: Function %s already exists, add ! to replace it"
+msgstr "E122: å‡½å¼ %s 已經存在, 請使用 ! 強制å–代"
+
+#, c-format
+msgid "E123: Undefined function: %s"
+msgstr "E123: å‡½å¼ %s 尚未定義"
+
+#, c-format
+msgid "E124: Missing '(': %s"
+msgstr "E124: 缺少 \"(\": %s"
+
+#, c-format
+msgid "E125: Illegal argument: %s"
+msgstr "E125: åƒæ•¸ä¸æ­£ç¢º: %s"
+
+msgid "E126: Missing :endfunction"
+msgstr "E126: 缺少 :endfunction"
+
+#, c-format
+msgid "E127: Cannot redefine function %s: It is in use"
+msgstr "E127: å‡½å¼ %s 正在使用中,無法é‡æ–°å®šç¾©"
+
+msgid "E129: Function name required"
+msgstr "E129: 需è¦å‡½å¼å稱"
+
+#, c-format
+msgid "E128: Function name must start with a capital: %s"
+msgstr "E128: 函å¼å稱第一個字æ¯å¿…須大寫: %s"
+
+#, c-format
+msgid "E130: Undefined function: %s"
+msgstr "E130: å‡½å¼ %s 尚未定義"
+
+#, c-format
+msgid "E131: Cannot delete function %s: It is in use"
+msgstr "E131: å‡½å¼ %s 正在使用中,無法刪除"
+
+msgid "E132: Function call depth is higher than 'maxfuncdepth'"
+msgstr "E132: 函å¼éžè¿´å‘¼å«å±¤æ•¸è¶…éŽ 'maxfuncdepth'"
+
+#. always scroll up, don't overwrite
+#, c-format
+msgid "calling %s"
+msgstr "å‘¼å« %s"
+
+#, c-format
+msgid "%s aborted"
+msgstr "%s 被強制中斷執行 "
+
+#, c-format
+msgid "%s returning #%ld"
+msgstr "%s 傳回值 #%ld "
+
+#, c-format
+msgid "%s returning \"%s\""
+msgstr "%s 傳回值 \"%s\""
+
+#. always scroll up, don't overwrite
+#, c-format
+msgid "continuing in %s"
+msgstr "繼續: %s"
+
+msgid "E133: :return not inside a function"
+msgstr "E133: :return 必須在函å¼è£¡ä½¿ç”¨"
+
+#, c-format
+msgid ""
+"\n"
+"# global variables:\n"
+msgstr ""
+"\n"
+"# 全域變數:\n"
+
+#, c-format
+msgid "<%s>%s%s %d, Hex %02x, Octal %03o"
+msgstr "<%s>%s%s %d, åå…­é€²ä½ %02x, å…«é€²ä½ %03o"
+
+#, c-format
+msgid "> %d, Hex %04x, Octal %o"
+msgstr "> %d, åå…­é€²ä½ %04x, å…«é€²ä½ %o"
+
+#, c-format
+msgid "> %d, Hex %08x, Octal %o"
+msgstr "> %d, åå…­é€²ä½ %08x, å…«é€²ä½ %o"
+
+msgid "E134: Move lines into themselves"
+msgstr "E134: 無法把行移到它自已內"
+
+msgid "1 line moved"
+msgstr "å·²æ¬ç§» 1 è¡Œ "
+
+#, c-format
+msgid "%ld lines moved"
+msgstr "å·²æ¬ç§» %ld è¡Œ "
+
+#, c-format
+msgid "%ld lines filtered"
+msgstr "å·²è™•ç† %ld è¡Œ "
+
+msgid "E135: *Filter* Autocommands must not change current buffer"
+msgstr "E135: *Filter* Autocommand ä¸å¯ä»¥æ›´æ”¹ç·©è¡å€çš„內容"
+
+msgid "[No write since last change]\n"
+msgstr "[更新後尚未儲存]\n"
+
+#, c-format
+msgid "%sviminfo: %s in line: "
+msgstr "%sviminfo: %s 在行中: "
+
+msgid "E136: viminfo: Too many errors, skipping rest of file"
+msgstr "E136: viminfo: éŽå¤šéŒ¯èª¤, 忽略檔案其餘部分"
+
+#, c-format
+msgid "Reading viminfo file \"%s\"%s%s%s"
+msgstr "è®€å– viminfo 檔案 \"%s\"%s%s%s"
+
+msgid " info"
+msgstr " 訊æ¯"
+
+msgid " marks"
+msgstr " 標記"
+
+msgid " FAILED"
+msgstr " 失敗"
+
+#, c-format
+msgid "E137: Viminfo file is not writable: %s"
+msgstr "E137: Viminfo 檔案無法寫入: %s"
+
+#, c-format
+msgid "E138: Can't write viminfo file %s!"
+msgstr "E138: 無法寫入 viminfo 檔案 %s !"
+
+#, c-format
+msgid "Writing viminfo file \"%s\""
+msgstr "寫入 viminfo 檔案 \"%s\" 中"
+
+#. Write the info:
+#, c-format
+msgid "# This viminfo file was generated by Vim %s.\n"
+msgstr "# 本 viminfo 檔案是由 Vim %s 所產生.\n"
+
+#, c-format
+msgid ""
+"# You may edit it if you're careful!\n"
+"\n"
+msgstr ""
+"# 如果想è¦è‡ªè¡Œä¿®æ”¹è«‹ç‰¹åˆ¥å°å¿ƒï¼\n"
+"\n"
+
+#, c-format
+msgid "# Value of 'encoding' when this file was written\n"
+msgstr "# 'encoding' 在此檔建立時的值\n"
+
+msgid "Illegal starting char"
+msgstr "無效的起始字元"
+
+msgid "Save As"
+msgstr "å¦å­˜æ–°æª”"
+
+#. Overwriting a file that is loaded in another buffer is not a
+#. * good idea.
+msgid "E139: File is loaded in another buffer"
+msgstr "E139: 您在å¦ä¸€å€‹ç·©è¡å€ä¹Ÿè¼‰å…¥äº†é€™å€‹æª”案"
+
+msgid "Write partial file?"
+msgstr "è¦å¯«å…¥éƒ¨åˆ†æª”案嗎?"
+
+msgid "E140: Use ! to write partial buffer"
+msgstr "E140: 請使用 ! 以寫入部分緩è¡å€"
+
+#, c-format
+msgid "Overwrite existing file \"%.*s\"?"
+msgstr "è¦è¦†å¯«å·²å­˜åœ¨çš„檔案 \"%.*s\"?"
+
+#, c-format
+msgid "E141: No file name for buffer %ld"
+msgstr "E141: ç·©è¡å€ %ld 沒有檔案å稱"
+
+msgid "E142: File not written: Writing is disabled by 'write' option"
+msgstr "E142: 檔案未寫入,因為 'write' é¸é …被關閉"
+
+#, c-format
+msgid ""
+"'readonly' option is set for \"%.*s\".\n"
+"Do you wish to write anyway?"
+msgstr ""
+"\"%.*s\" 已設定 'readonly' é¸é ….\n"
+"確定è¦è¦†å¯«å—Žï¼Ÿ"
+
+msgid "Edit File"
+msgstr "編輯檔案"
+
+#, c-format
+msgid "E143: Autocommands unexpectedly deleted new buffer %s"
+msgstr "E143: Autocommands æ„外地刪除新緩è¡å€ %s"
+
+msgid "E144: non-numeric argument to :z"
+msgstr "E144: :z ä¸æŽ¥å—éžæ•¸å­—çš„åƒæ•¸"
+
+msgid "E145: Shell commands not allowed in rvim"
+msgstr "E145: rvim 中ç¦æ­¢ä½¿ç”¨ shell 命令"
+
+msgid "E146: Regular expressions can't be delimited by letters"
+msgstr "E146: Regular expression 無法用字æ¯åˆ†éš” (?)"
+
+#, c-format
+msgid "replace with %s (y/n/a/q/l/^E/^Y)?"
+msgstr "å–代為 %s (y/n/a/q/^E/^Y)?"
+
+msgid "(Interrupted) "
+msgstr "(已中斷) "
+
+msgid "1 substitution"
+msgstr "å–代一組 "
+
+#, c-format
+msgid "%ld substitutions"
+msgstr "å–代 %ld 組 "
+
+msgid " on 1 line"
+msgstr ",範åœï¼šä¸€è¡Œ "
+
+#, c-format
+msgid " on %ld lines"
+msgstr ",範åœï¼š %ld è¡Œ "
+
+msgid "E147: Cannot do :global recursive"
+msgstr "E147: :global 無法éžè¿´åŸ·è¡Œ "
+
+msgid "E148: Regular expression missing from global"
+msgstr "E148: æ²’æœ‰ä½¿ç”¨éŽ Regular expression (?)"
+
+#, c-format
+msgid "Pattern found in every line: %s"
+msgstr "æ¯ä¸€è¡Œéƒ½æ‰¾ä¸åˆ°: %s"
+
+#, c-format
+msgid ""
+"\n"
+"# Last Substitute String:\n"
+"$"
+msgstr ""
+"\n"
+"# å‰ä¸€çµ„替代字串:\n"
+"$"
+
+msgid "E478: Don't panic!"
+msgstr "E478: ä¸è¦é©šæ…Œ!"
+
+#, c-format
+msgid "E661: Sorry, no '%s' help for %s"
+msgstr "E661: 抱歉, 沒有關於 %s-%s 的說明"
+
+#, c-format
+msgid "E149: Sorry, no help for %s"
+msgstr "E149: 抱歉, 沒有 %s 的說明"
+
+#, c-format
+msgid "Sorry, help file \"%s\" not found"
+msgstr "抱歉, 找ä¸åˆ°èªªæ˜Žæª” \"%s\""
+
+#, c-format
+msgid "E150: Not a directory: %s"
+msgstr "E150: %s ä¸æ˜¯ç›®éŒ„"
+
+#, c-format
+msgid "E152: Cannot open %s for writing"
+msgstr "E152: 無法以寫入模å¼é–‹å•Ÿ \"%s\""
+
+#, c-format
+msgid "E153: Unable to open %s for reading"
+msgstr "E153: 無法讀å–檔案: %s"
+
+#, c-format
+msgid "E670: Mix of help file encodings within a language: %s"
+msgstr "E670: åŒä¸€èªžè¨€ (%s) 中有混åˆä¸åŒå­—元編碼的說明檔"
+
+#, c-format
+msgid "E154: Duplicate tag \"%s\" in file %s"
+msgstr "E154: 標籤(tag) \"%s\" 在檔案 %s 裡é‡è¤‡å‡ºç¾å¤šæ¬¡"
+
+#, c-format
+msgid "E160: Unknown sign command: %s"
+msgstr "E160: 未定義的 sign command: %s"
+
+msgid "E156: Missing sign name"
+msgstr "E156: 缺少 sign å稱"
+
+msgid "E612: Too many signs defined"
+msgstr "E612: 已定義太多 signs"
+
+#, c-format
+msgid "E239: Invalid sign text: %s"
+msgstr "E239: ä¸æ­£ç¢ºçš„ sign 文字: %s"
+
+#, c-format
+msgid "E155: Unknown sign: %s"
+msgstr "E155: ä¸æ­£ç¢ºçš„ sign: %s"
+
+msgid "E159: Missing sign number"
+msgstr "E159: 缺少 sign number"
+
+#, c-format
+msgid "E158: Invalid buffer name: %s"
+msgstr "E158: ç·©è¡å€å稱錯誤: %s"
+
+#, c-format
+msgid "E157: Invalid sign ID: %ld"
+msgstr "E157: Sign ID 錯誤: %ld"
+
+msgid " (NOT FOUND)"
+msgstr " (找ä¸åˆ°) "
+
+msgid " (not supported)"
+msgstr " (ä¸æ”¯æ´) "
+
+msgid "[Deleted]"
+msgstr "[已刪除]"
+
+msgid "Entering Debug mode. Type \"cont\" to continue."
+msgstr "進入除錯模å¼. 輸入 \"cont\" 以回到正常模å¼."
+
+#, c-format
+msgid "line %ld: %s"
+msgstr "行 %ld: %s"
+
+#, c-format
+msgid "cmd: %s"
+msgstr "cmd: %s"
+
+#, c-format
+msgid "Breakpoint in \"%s%s\" line %ld"
+msgstr "\"%s%s\" 中斷點: 第 %ld 行 "
+
+#, c-format
+msgid "E161: Breakpoint not found: %s"
+msgstr "E161: 找ä¸åˆ°ä¸­æ–·é»ž: %s"
+
+msgid "No breakpoints defined"
+msgstr "沒有定義中斷點"
+
+#, c-format
+msgid "%3d %s %s line %ld"
+msgstr "%3d %s %s 第 %ld 行 "
+
+#, c-format
+msgid "Save changes to \"%.*s\"?"
+msgstr "將變動存儲至 \"%.*s\"?"
+
+msgid "Untitled"
+msgstr "未命å"
+
+#, c-format
+msgid "E162: No write since last change for buffer \"%s\""
+msgstr "E162: 已更改éŽç·©è¡å€ \"%s\" 但尚未存檔 (å¯ç”¨ ! 強制執行)"
+
+msgid "Warning: Entered other buffer unexpectedly (check autocommands)"
+msgstr "注æ„: 已切æ›åˆ°å…¶å®ƒç·©è¡å€ (請檢查 Autocommands 有無錯誤)"
+
+msgid "E163: There is only one file to edit"
+msgstr "E163: åªæœ‰ä¸€å€‹æª”案å¯ç·¨è¼¯"
+
+msgid "E164: Cannot go before first file"
+msgstr "E164: 已經在第一個檔案了"
+
+msgid "E165: Cannot go beyond last file"
+msgstr "E165: 已經在最後一個檔案了"
+
+#, c-format
+msgid "E666: compiler not supported: %s"
+msgstr "E666: 編譯器ä¸æ”¯æ´: %s"
+
+#, c-format
+msgid "Searching for \"%s\" in \"%s\""
+msgstr "æœå°‹ä¸­: \"%s\" -- \"%s\""
+
+#, c-format
+msgid "Searching for \"%s\""
+msgstr "æœå°‹ä¸­: \"%s\""
+
+#, c-format
+msgid "not found in 'runtimepath': \"%s\""
+msgstr "在 'runtimepath' 裡找ä¸åˆ° \"%s\""
+
+msgid "Source Vim script"
+msgstr "執行 Vim script"
+
+#, c-format
+msgid "Cannot source a directory: \"%s\""
+msgstr "無法執行目錄: \"%s\""
+
+#, c-format
+msgid "could not source \"%s\""
+msgstr "無法執行 \"%s\""
+
+#, c-format
+msgid "line %ld: could not source \"%s\""
+msgstr "第 %ld 行: 無法執行 \"%s\""
+
+#, c-format
+msgid "sourcing \"%s\""
+msgstr "執行 \"%s\" 中"
+
+#, c-format
+msgid "line %ld: sourcing \"%s\""
+msgstr "第 %ld è¡Œ: çµæŸåŸ·è¡Œ %s"
+
+#, c-format
+msgid "finished sourcing %s"
+msgstr "çµæŸåŸ·è¡Œ %s"
+
+msgid "W15: Warning: Wrong line separator, ^M may be missing"
+msgstr "W15: 注æ„: 錯誤的行分隔字元,å¯èƒ½æ˜¯å°‘了 ^M"
+
+msgid "E167: :scriptencoding used outside of a sourced file"
+msgstr "E167: 在執行 script 檔案外ä¸å¯ä½¿ç”¨ :scriptencoding"
+
+msgid "E168: :finish used outside of a sourced file"
+msgstr "E168: 在執行 script 檔案外ä¸å¯ä½¿ç”¨ :finish"
+
+#, c-format
+msgid "Page %d"
+msgstr "第 %d é "
+
+msgid "No text to be printed"
+msgstr "沒有è¦åˆ—å°çš„文字"
+
+#, c-format
+msgid "Printing page %d (%d%%)"
+msgstr "列å°ä¸­: 第 %d é  (%d%%)"
+
+#, c-format
+msgid " Copy %d of %d"
+msgstr "複製 %d / %d"
+
+#, c-format
+msgid "Printed: %s"
+msgstr "已列å°: %s"
+
+#, c-format
+msgid "Printing aborted"
+msgstr "å·²å–消列å°"
+
+msgid "E455: Error writing to PostScript output file"
+msgstr "E455: 無法寫入 PostScript 輸出檔"
+
+#, c-format
+msgid "E624: Can't open file \"%s\""
+msgstr "E624: 無法開啟檔案 \"%s\""
+
+#, c-format
+msgid "E457: Can't read PostScript resource file \"%s\""
+msgstr "E457: ç„¡æ³•è®€å– PostScript 資æºæª” \"%s\""
+
+#, c-format
+msgid "E618: file \"%s\" is not a PostScript resource file"
+msgstr "E618: 檔案 \"%s\" ä¸æ˜¯ PostScript 資æºæª” "
+
+#, c-format
+msgid "E619: file \"%s\" is not a supported PostScript resource file"
+msgstr "E619: ä¸æ”¯æ´ PostScript 資æºæª” \"%s\""
+
+#, c-format
+msgid "E621: \"%s\" resource file has wrong version"
+msgstr "E621: \"%s\" 資æºæª”版本錯誤"
+
+msgid "E324: Can't open PostScript output file"
+msgstr "E324: 無法開啟 PostScript 輸出檔"
+
+#, c-format
+msgid "E456: Can't open file \"%s\""
+msgstr "E456: 無法開啟檔案 \"%s\""
+
+msgid "E456: Can't find PostScript resource file \"prolog.ps\""
+msgstr "E456: ç„¡æ³•è®€å– PostScript 資æºæª” \"prolog.ps\""
+
+#, c-format
+msgid "E456: Can't find PostScript resource file \"%s.ps\""
+msgstr "E456: ç„¡æ³•è®€å– PostScript 資æºæª” \"%s.ps\""
+
+#, c-format
+msgid "E620: Unable to convert from multi-byte to \"%s\" encoding"
+msgstr "E620:無法轉æ›è‡³ \"%s\" 字元編碼"
+
+msgid "Sending to printer..."
+msgstr "傳é€è³‡æ–™åˆ°å°è¡¨æ©Ÿ..."
+
+msgid "E365: Failed to print PostScript file"
+msgstr "E365: ç„¡æ³•åˆ—å° PostScript 檔案"
+
+msgid "Print job sent."
+msgstr "å·²é€å‡ºåˆ—å°å·¥ä½œã€‚"
+
+#, c-format
+msgid "Current %slanguage: \"%s\""
+msgstr "ç›®å‰çš„ %s語言: \"%s\""
+
+#, c-format
+msgid "E197: Cannot set language to \"%s\""
+msgstr "E197: ä¸èƒ½è¨­å®šèªžè¨€æˆ \"%s\""
+
+msgid "Entering Ex mode. Type \"visual\" to go to Normal mode."
+msgstr "進入 Ex 模å¼. 輸入 \"visua\" 以回到正常模å¼."
+
+#. must be at EOF
+msgid "E501: At end-of-file"
+msgstr "E501: 已到檔案çµå°¾"
+
+msgid "E169: Command too recursive"
+msgstr "E169: 命令éžè¿´å±¤æ•¸éŽå¤š"
+
+#, c-format
+msgid "E605: Exception not caught: %s"
+msgstr "E605: 未攔截的例外: %s"
+
+msgid "End of sourced file"
+msgstr "命令檔çµæŸ"
+
+msgid "End of function"
+msgstr "函å¼çµå°¾"
+
+msgid "E464: Ambiguous use of user-defined command"
+msgstr "E464: 使用者定義的命令會混淆"
+
+msgid "E492: Not an editor command"
+msgstr "E492: ä¸æ˜¯ç·¨è¼¯å™¨çš„命令"
+
+msgid "E493: Backwards range given"
+msgstr "E493: 指定了å‘å‰åƒè€ƒçš„範åœ"
+
+msgid "Backwards range given, OK to swap"
+msgstr "指定了å‘å‰åƒè€ƒçš„範åœï¼ŒOK to swap"
+
+msgid "E494: Use w or w>>"
+msgstr "E494: 請使用 w 或 w>>"
+
+msgid "E319: Sorry, the command is not available in this version"
+msgstr "E319: 抱歉, 本命令在此版本中沒有實作"
+
+msgid "E172: Only one file name allowed"
+msgstr "E172: åªèƒ½æœ‰ä¸€å€‹æª”"
+
+msgid "1 more file to edit. Quit anyway?"
+msgstr "還有一個檔案未編輯. 確定è¦é›¢é–‹ï¼Ÿ"
+
+#, c-format
+msgid "%d more files to edit. Quit anyway?"
+msgstr "還有 %d 個檔案未編輯. 確定è¦é›¢é–‹ï¼Ÿ"
+
+msgid "E173: 1 more file to edit"
+msgstr "E173: 還有一個檔案未編輯 "
+
+#, c-format
+msgid "E173: %ld more files to edit"
+msgstr "E173: 還有 %ld 個檔案未編輯"
+
+msgid "E174: Command already exists: add ! to replace it"
+msgstr "E174: 命令已經存在, 請使用 ! 強制é‡æ–°å®šç¾©"
+
+msgid ""
+"\n"
+" Name Args Range Complete Definition"
+msgstr ""
+"\n"
+" å稱 åƒæ•¸ ç¯„åœ å®Œæ•´ 定義 "
+
+msgid "No user-defined commands found"
+msgstr "找ä¸åˆ°ä½¿ç”¨è€…定義的命令"
+
+msgid "E175: No attribute specified"
+msgstr "E175: 沒有指定的屬性"
+
+msgid "E176: Invalid number of arguments"
+msgstr "E176: ä¸æ­£ç¢ºçš„åƒæ•¸æ•¸ç›®"
+
+msgid "E177: Count cannot be specified twice"
+msgstr "E177: ä¸èƒ½æŒ‡å®šå…©æ¬¡æ•¸ç›®"
+
+msgid "E178: Invalid default value for count"
+msgstr "E178: 數目的é è¨­åƒæ•¸ä¸æ­£ç¢º"
+
+msgid "E179: argument required for complete"
+msgstr "E179: 指令需è¦åƒæ•¸æ‰èƒ½å®Œæˆ"
+
+#, c-format
+msgid "E180: Invalid complete value: %s"
+msgstr "E180: ä¸å®Œæ•´çš„值: '%s'"
+
+msgid "E468: Completion argument only allowed for custom completion"
+msgstr "E468: 自訂補完時æ‰å¯è£œå®Œåƒæ•¸"
+
+msgid "E467: Custom completion requires a function argument"
+msgstr "E467: 自訂補完需è¦å‡½å¼ç‚ºåƒæ•¸"
+
+#, c-format
+msgid "E181: Invalid attribute: %s"
+msgstr "E181: ä¸æ­£ç¢ºçš„屬性: %s"
+
+msgid "E182: Invalid command name"
+msgstr "E182: 指令å稱ä¸æ­£ç¢º"
+
+msgid "E183: User defined commands must start with an uppercase letter"
+msgstr "E183: 使用者自定指令必須以大寫字æ¯é–‹å§‹"
+
+#, c-format
+msgid "E184: No such user-defined command: %s"
+msgstr "E184: 沒有使用者自定的命令: %s"
+
+#, c-format
+msgid "E185: Cannot find color scheme %s"
+msgstr "E185: 找ä¸åˆ°é¡è‰²æ¨£å¼ %s"
+
+msgid "Greetings, Vim user!"
+msgstr "å—¨, Vim 使用者ï¼"
+
+msgid "Edit File in new window"
+msgstr "在新視窗編輯檔案"
+
+msgid "No swap file"
+msgstr "無暫存檔"
+
+msgid "Append File"
+msgstr "附加檔案"
+
+msgid "E186: No previous directory"
+msgstr "E186: 沒有å‰ä¸€å€‹ç›®éŒ„"
+
+msgid "E187: Unknown"
+msgstr "E187: 無法辦識的標記"
+
+msgid "E465: :winsize requires two number arguments"
+msgstr "E465: :winsize 需è¦å…©å€‹åƒæ•¸"
+
+#, c-format
+msgid "Window position: X %d, Y %d"
+msgstr "視窗ä½ç½®: X %d, Y %d"
+
+msgid "E188: Obtaining window position not implemented for this platform"
+msgstr "E188: 在您的平å°ä¸Šç„¡æ³•ç²å¾—視窗ä½ç½®"
+
+msgid "E466: :winpos requires two number arguments"
+msgstr "E466: :winpos 需è¦å…©å€‹åƒæ•¸"
+
+msgid "Save Redirection"
+msgstr "儲存 Redirection"
+
+msgid "Save View"
+msgstr "儲存 View"
+
+msgid "Save Session"
+msgstr "儲存 Session"
+
+msgid "Save Setup"
+msgstr "儲存設定"
+
+#, c-format
+msgid "E189: \"%s\" exists (add ! to override)"
+msgstr "E189: \"%s\" 已存在 (請用 ! 強制執行)"
+
+#, c-format
+msgid "E190: Cannot open \"%s\" for writing"
+msgstr "E190: 無法以寫入模å¼é–‹å•Ÿ \"%s\""
+
+#. set mark
+msgid "E191: Argument must be a letter or forward/backward quote"
+msgstr "E191: åƒæ•¸å¿…須是英文字æ¯æˆ–å‘å‰/後的引號"
+
+msgid "E192: Recursive use of :normal too deep"
+msgstr "E192: :normal éžè¿´å±¤æ•¸éŽæ·±"
+
+msgid "E194: No alternate file name to substitute for '#'"
+msgstr "E194: 沒有 '#' å¯æ›¿ä»£çš„檔å"
+
+msgid "E495: no autocommand file name to substitute for \"<afile>\""
+msgstr "E495: 沒有 Autocommand 檔å以å–代 \"<afile>\""
+
+msgid "E496: no autocommand buffer number to substitute for \"<abuf>\""
+msgstr "E496: 沒有 Autocommand ç·©è¡å€å稱以å–代 \"<abuf>\""
+
+msgid "E497: no autocommand match name to substitute for \"<amatch>\""
+msgstr "E497: 沒有 Autocommand 符åˆå稱以å–代 \"<amatch>\""
+
+msgid "E498: no :source file name to substitute for \"<sfile>\""
+msgstr "E498: 沒有 :source 檔å以å–代 \"<sfile>\""
+
+#, no-c-format
+msgid "E499: Empty file name for '%' or '#', only works with \":p:h\""
+msgstr "E499: '%' 或 '#' 指å‘空檔å,åªèƒ½ç”¨æ–¼ \":p:h\""
+
+msgid "E500: Evaluates to an empty string"
+msgstr "E500: 輸入為空字串"
+
+msgid "E195: Cannot open viminfo file for reading"
+msgstr "E195: ç„¡æ³•è®€å– viminfo"
+
+msgid "E196: No digraphs in this version"
+msgstr "E196: 本版本無複åˆå­—å…ƒ(digraph)"
+
+msgid "E608: Cannot :throw exceptions with 'Vim' prefix"
+msgstr "E608: ä¸èƒ½ :throw 用 'Vim' 開頭的例外"
+
+#. always scroll up, don't overwrite
+#, c-format
+msgid "Exception thrown: %s"
+msgstr "丟出例外: %s"
+
+#, c-format
+msgid "Exception finished: %s"
+msgstr "例外çµæŸï¼š %s"
+
+#, c-format
+msgid "Exception discarded: %s"
+msgstr "已丟棄例外: %s"
+
+#, c-format
+msgid "%s, line %ld"
+msgstr "%s, 行 %ld"
+
+#. always scroll up, don't overwrite
+#, c-format
+msgid "Exception caught: %s"
+msgstr "發生例外:%s"
+
+#, c-format
+msgid "%s made pending"
+msgstr "%s é€ æˆ pending"
+
+#, c-format
+msgid "%s resumed"
+msgstr "%s 已回復"
+
+#, c-format
+msgid "%s discarded"
+msgstr "%s 已丟棄"
+
+msgid "Exception"
+msgstr "例外"
+
+msgid "Error and interrupt"
+msgstr "錯誤與中斷"
+
+msgid "Error"
+msgstr "錯誤"
+
+#. if (pending & CSTP_INTERRUPT)
+msgid "Interrupt"
+msgstr "中斷"
+
+msgid "E579: :if nesting too deep"
+msgstr "E579: :if 層數éŽæ·±"
+
+msgid "E580: :endif without :if"
+msgstr "E580: :endif 缺少å°æ‡‰çš„ :if"
+
+msgid "E581: :else without :if"
+msgstr "E581: :else 缺少å°æ‡‰çš„ :if"
+
+msgid "E582: :elseif without :if"
+msgstr "E582: :elseif 缺少å°æ‡‰çš„ :if"
+
+msgid "E583: multiple :else"
+msgstr "E583: å¤šé‡ :else"
+
+msgid "E584: :elseif after :else"
+msgstr "E584: :elseif 在 :else 之後"
+
+msgid "E585: :while nesting too deep"
+msgstr "E585: :while 層數éŽæ·±"
+
+msgid "E586: :continue without :while"
+msgstr "E586: :continue 缺少å°æ‡‰çš„ :while"
+
+msgid "E587: :break without :while"
+msgstr "E587: :break 缺少å°æ‡‰çš„ :while"
+
+msgid "E601: :try nesting too deep"
+msgstr "E601: :if 層數éŽæ·±"
+
+msgid "E603: :catch without :try"
+msgstr "E603: :catch 沒有 :try"
+
+#. Give up for a ":catch" after ":finally" and ignore it.
+#. * Just parse.
+msgid "E604: :catch after :finally"
+msgstr "E604: :catch 在 :finally 之後"
+
+msgid "E606: :finally without :try"
+msgstr "E606: :finally 沒有 :try"
+
+#. Give up for a multiple ":finally" and ignore it.
+msgid "E607: multiple :finally"
+msgstr "E607: å¤šé‡ :finally"
+
+msgid "E602: :endtry without :try"
+msgstr "E602: :endif 缺少å°æ‡‰çš„ :if"
+
+msgid "E193: :endfunction not inside a function"
+msgstr "E193: :endfunction 必須在函å¼å…§éƒ¨ä½¿ç”¨"
+
+msgid "tagname"
+msgstr "標籤å稱"
+
+msgid " kind file\n"
+msgstr "類檔案\n"
+
+msgid "'history' option is zero"
+msgstr "é¸é … 'history' 是零"
+
+#, c-format
+msgid ""
+"\n"
+"# %s History (newest to oldest):\n"
+msgstr ""
+"\n"
+"# %s æ­·å²è¨˜éŒ„ (新到舊):\n"
+
+msgid "Command Line"
+msgstr "命令列"
+
+msgid "Search String"
+msgstr "æœå°‹å­—串"
+
+msgid "Expression"
+msgstr "é‹ç®—å¼"
+
+msgid "Input Line"
+msgstr "輸入行 "
+
+msgid "E198: cmd_pchar beyond the command length"
+msgstr "E198: cmd_pchar 超éŽå‘½ä»¤é•·åº¦"
+
+msgid "E199: Active window or buffer deleted"
+msgstr "E199: 已刪除掉作用中的視窗或暫存å€"
+
+msgid "Illegal file name"
+msgstr "ä¸æ­£ç¢ºçš„檔å"
+
+msgid "is a directory"
+msgstr "是目錄"
+
+msgid "is not a file"
+msgstr "ä¸æ˜¯æª”案"
+
+msgid "[New File]"
+msgstr "[未命å]"
+
+msgid "[Permission Denied]"
+msgstr "[權é™ä¸è¶³]"
+
+msgid "E200: *ReadPre autocommands made the file unreadable"
+msgstr "E200: *ReadPre Autocommand 使程å¼ç„¡æ³•è®€å–此檔"
+
+msgid "E201: *ReadPre autocommands must not change current buffer"
+msgstr "E201: *Filter* Autocommand ä¸å¯ä»¥æ›´æ”¹ç·©è¡å€çš„內容"
+
+msgid "Vim: Reading from stdin...\n"
+msgstr "Vim: 從標準輸入讀å–...\n"
+
+msgid "Reading from stdin..."
+msgstr "從標準輸入讀å–..."
+
+#. Re-opening the original file failed!
+msgid "E202: Conversion made file unreadable!"
+msgstr "E202: 轉æ›éŒ¯èª¤"
+
+msgid "[fifo/socket]"
+msgstr "[fifo/socket]"
+
+msgid "[fifo]"
+msgstr "[fifo]"
+
+msgid "[socket]"
+msgstr "[socket]"
+
+msgid "[RO]"
+msgstr "[唯讀]"
+
+msgid "[CR missing]"
+msgstr "[缺少CR]'"
+
+msgid "[NL found]"
+msgstr "[找到NL]"
+
+msgid "[long lines split]"
+msgstr "[分割éŽé•·è¡Œ]"
+
+msgid "[NOT converted]"
+msgstr "[未轉æ›]"
+
+msgid "[converted]"
+msgstr "[已轉æ›]"
+
+msgid "[crypted]"
+msgstr "[已加密]"
+
+msgid "[CONVERSION ERROR]"
+msgstr "轉æ›éŒ¯èª¤"
+
+#, c-format
+msgid "[ILLEGAL BYTE in line %ld]"
+msgstr "[è¡Œ %ld 有ä¸æ­£ç¢ºçš„ä½å…ƒ]"
+
+msgid "[READ ERRORS]"
+msgstr "[讀å–錯誤]"
+
+msgid "Can't find temp file for conversion"
+msgstr "找ä¸åˆ°è½‰æ›ç”¨çš„暫存檔"
+
+msgid "Conversion with 'charconvert' failed"
+msgstr "字元集轉æ›éŒ¯èª¤"
+
+msgid "can't read output of 'charconvert'"
+msgstr "ç„¡æ³•è®€å– 'charconvert' 的輸出"
+
+msgid "E203: Autocommands deleted or unloaded buffer to be written"
+msgstr "E203: Autocommand 刪除或釋放了è¦å¯«å…¥çš„ç·©è¡å€"
+
+msgid "E204: Autocommand changed number of lines in unexpected way"
+msgstr "E204: Autocommand æ„外地改變了行號"
+
+msgid "NetBeans disallows writes of unmodified buffers"
+msgstr "NetBeans ä¸èƒ½å¯«å‡ºæœªä¿®æ”¹çš„ç·©è¡å€"
+
+msgid "Partial writes disallowed for NetBeans buffers"
+msgstr "部份內容無法寫入 Netbeans ç·©è¡å€"
+
+msgid "is not a file or writable device"
+msgstr "ä¸æ˜¯æª”案或å¯å¯«å…¥çš„è£ç½®"
+
+msgid "is read-only (add ! to override)"
+msgstr "是唯讀檔 (請使用 ! 強制執行)"
+
+msgid "E506: Can't write to backup file (add ! to override)"
+msgstr "E506: 無法寫入備份檔 (請使用 ! 強制執行)"
+
+msgid "E507: Close error for backup file (add ! to override)"
+msgstr "E507: 無法關閉備份檔 (請使用 ! 強制執行)"
+
+msgid "E508: Can't read file for backup (add ! to override)"
+msgstr "E508: 無法讀å–檔案以供備份 (請使用 ! 強制執行)"
+
+msgid "E509: Cannot create backup file (add ! to override)"
+msgstr "E509: 無法建立備份檔 (請使用 ! 強制執行)"
+
+msgid "E510: Can't make backup file (add ! to override)"
+msgstr "E510: 無法製作備份檔 (請使用 ! 強制執行)"
+
+msgid "E460: The resource fork would be lost (add ! to override)"
+msgstr "E460: Resource fork 會消失 (請使用 ! 強制執行)"
+
+msgid "E214: Can't find temp file for writing"
+msgstr "E214: 找ä¸åˆ°å¯«å…¥ç”¨çš„暫存檔"
+
+msgid "E213: Cannot convert (add ! to write without conversion)"
+msgstr "E213: ç„¡æ³•è½‰æ› (請使用 ! 強制ä¸è½‰æ›å¯«å…¥)"
+
+msgid "E166: Can't open linked file for writing"
+msgstr "E166: 無法以寫入模å¼é–‹å•Ÿé€£çµæª”案"
+
+msgid "E212: Can't open file for writing"
+msgstr "E212: 無法以寫入模å¼é–‹å•Ÿ"
+
+msgid "E667: Fsync failed"
+msgstr "E667: Fsync 命令執行失敗"
+
+msgid "E512: Close failed"
+msgstr "E512: 關閉失敗"
+
+msgid "E513: write error, conversion failed"
+msgstr "E513: 無法寫入 -- 轉æ›å¤±æ•—"
+
+msgid "E514: write error (file system full?)"
+msgstr "E514: 寫入錯誤 (檔案系統已滿?)"
+
+msgid " CONVERSION ERROR"
+msgstr "轉æ›éŒ¯èª¤"
+
+msgid "[Device]"
+msgstr "[è£ç½®]"
+
+msgid "[New]"
+msgstr "[æ–°]"
+
+msgid " [a]"
+msgstr "[a]"
+
+msgid " appended"
+msgstr " 已附加"
+
+msgid " [w]"
+msgstr "[w]"
+
+msgid " written"
+msgstr " 已寫入"
+
+msgid "E205: Patchmode: can't save original file"
+msgstr "E205: Patch 模å¼: 無法儲存原始檔案"
+
+msgid "E206: patchmode: can't touch empty original file"
+msgstr "E206: Patch 模å¼: 無法變更空的原始檔案"
+
+msgid "E207: Can't delete backup file"
+msgstr "E207: 無法刪除備份檔"
+
+msgid ""
+"\n"
+"WARNING: Original file may be lost or damaged\n"
+msgstr ""
+"\n"
+"警告: 原始檔案æµå¤±æˆ–æ壞\n"
+
+msgid "don't quit the editor until the file is successfully written!"
+msgstr "在檔案正確寫入å‰è«‹å‹¿é›¢é–‹ç·¨è¼¯å™¨!"
+
+msgid "[dos]"
+msgstr "[dos]"
+
+msgid "[dos format]"
+msgstr "[dos æ ¼å¼]"
+
+msgid "[mac]"
+msgstr "[mac]"
+
+msgid "[mac format]"
+msgstr "[mac æ ¼å¼]"
+
+msgid "[unix]"
+msgstr "[unix]"
+
+msgid "[unix format]"
+msgstr "[unix æ ¼å¼]"
+
+msgid "1 line, "
+msgstr "1 行, "
+
+#, c-format
+msgid "%ld lines, "
+msgstr "%ld 行, "
+
+msgid "1 character"
+msgstr "一個字元"
+
+#, c-format
+msgid "%ld characters"
+msgstr "%ld個字元"
+
+msgid "[noeol]"
+msgstr "[noeol]"
+
+msgid "[Incomplete last line]"
+msgstr "[çµå°¾è¡Œä¸å®Œæ•´]"
+
+#. don't overwrite messages here
+#. must give this prompt
+#. don't use emsg() here, don't want to flush the buffers
+msgid "WARNING: The file has been changed since reading it!!!"
+msgstr "警告: 本檔案自上次讀入後已變動!!!"
+
+msgid "Do you really want to write to it"
+msgstr "確定è¦å¯«å…¥å—Ž"
+
+#, c-format
+msgid "E208: Error writing to \"%s\""
+msgstr "E208: 寫入檔案 \"%s\" 錯誤"
+
+#, c-format
+msgid "E209: Error closing \"%s\""
+msgstr "E209: 關閉檔案 \"%s\" 錯誤"
+
+#, c-format
+msgid "E210: Error reading \"%s\""
+msgstr "E210: 讀å–檔案 \"%s\" 錯誤"
+
+msgid "E246: FileChangedShell autocommand deleted buffer"
+msgstr "E246: FileChangedShell autocommand 刪除緩è¡å€"
+
+#, c-format
+msgid "E211: Warning: File \"%s\" no longer available"
+msgstr "E211: 警告: 檔案 \"%s\" 已經ä¸å­˜åœ¨"
+
+#, c-format
+msgid ""
+"W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as "
+"well"
+msgstr "W12: 警告: 檔案 \"%s\" 自上次讀入後已變動, 而且編輯中的緩è¡å€ä¹Ÿæ›´å‹•äº†"
+
+#, c-format
+msgid "W11: Warning: File \"%s\" has changed since editing started"
+msgstr "W11: 警告: 檔案 \"%s\" 自上次讀入後已變動"
+
+#, c-format
+msgid "W16: Warning: Mode of file \"%s\" has changed since editing started"
+msgstr "W16: 警告: 檔案 \"%s\" 的權é™èˆ‡ä¸Šæ¬¡è®€å…¥æ™‚ä¸ä¸€æ¨£ (有變動éŽ)"
+
+# 'mode' seems better as translated to 'permission'?
+#, c-format
+msgid "W13: Warning: File \"%s\" has been created after editing started"
+msgstr "W13: 警告: 檔案 \"%s\" 在開始編輯後åˆè¢«å»ºç«‹äº†"
+
+msgid "See \":help W11\" for more info."
+msgstr "進一步說明請見 \":help W11\"。"
+
+msgid "Warning"
+msgstr "警告"
+
+msgid ""
+"&OK\n"
+"&Load File"
+msgstr ""
+"確定(&O)\n"
+"載入檔案(&L)"
+
+#, c-format
+msgid "E462: Could not prepare for reloading \"%s\""
+msgstr "E462: 無法準備é‡æ–°è¼‰å…¥ \"%s\""
+
+#, c-format
+msgid "E321: Could not reload \"%s\""
+msgstr "E321: 無法é‡æ–°è¼‰å…¥ \"%s\""
+
+msgid "--Deleted--"
+msgstr "--已刪除--"
+
+#. the group doesn't exist
+#, c-format
+msgid "E367: No such group: \"%s\""
+msgstr "E367: 無此群組: \"%s\""
+
+#, c-format
+msgid "E215: Illegal character after *: %s"
+msgstr "E215: * 後é¢æœ‰ä¸æ­£ç¢ºçš„å­—å…ƒ: %s"
+
+#, c-format
+msgid "E216: No such event: %s"
+msgstr "E216: 無此事件: %s"
+
+#, c-format
+msgid "E216: No such group or event: %s"
+msgstr "E216: 無此群組或事件: %s"
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Autocommands ---"
+msgstr ""
+"\n"
+"--- Autocommands ---"
+
+msgid "E217: Can't execute autocommands for ALL events"
+msgstr "E217: 無法å°æ‰€æœ‰äº‹ä»¶åŸ·è¡Œ autocommand"
+
+msgid "No matching autocommands"
+msgstr "找ä¸åˆ°å°æ‡‰çš„ autocommand"
+
+msgid "E218: autocommand nesting too deep"
+msgstr "E218: autocommand 層數éŽæ·±"
+
+#, c-format
+msgid "%s Autocommands for \"%s\""
+msgstr "%s Autocommands: \"%s\""
+
+#, c-format
+msgid "Executing %s"
+msgstr "執行 %s"
+
+#. always scroll up, don't overwrite
+#, c-format
+msgid "autocommand %s"
+msgstr "autocommand %s"
+
+msgid "E219: Missing {."
+msgstr "E219: 缺少 {."
+
+msgid "E220: Missing }."
+msgstr "E220: 缺少 }."
+
+msgid "E490: No fold found"
+msgstr "E490: 找ä¸åˆ°ä»»ä½• fold"
+
+msgid "E350: Cannot create fold with current 'foldmethod'"
+msgstr "E350: 無法在目å‰çš„ 'foldmethod' 下建立 fold"
+
+msgid "E351: Cannot delete fold with current 'foldmethod'"
+msgstr "E351: 無法在目å‰çš„ 'foldmethod' 下刪除 fold"
+
+msgid "E222: Add to read buffer"
+msgstr "E222: 加入讀å–ç·©è¡å€ä¸­"
+
+msgid "E223: recursive mapping"
+msgstr "E223: éžè¿´ mapping"
+
+#, c-format
+msgid "E224: global abbreviation already exists for %s"
+msgstr "E224: %s 已經有全域 abbreviation 了"
+
+#, c-format
+msgid "E225: global mapping already exists for %s"
+msgstr "E225: %s 已經有全域 mapping 了"
+
+#, c-format
+msgid "E226: abbreviation already exists for %s"
+msgstr "E226: %s 已經有 abbreviation 了"
+
+#, c-format
+msgid "E227: mapping already exists for %s"
+msgstr "E227: %s 的 mapping 已經存在"
+
+msgid "No abbreviation found"
+msgstr "找ä¸åˆ° abbreviation"
+
+msgid "No mapping found"
+msgstr "沒有這個 mapping å°æ‡‰"
+
+msgid "E228: makemap: Illegal mode"
+msgstr "E228: makemap: ä¸æ­£ç¢ºçš„模å¼"
+
+msgid "E229: Cannot start the GUI"
+msgstr "E229: 無法啟動圖型界é¢"
+
+#, c-format
+msgid "E230: Cannot read from \"%s\""
+msgstr "E230: 無法讀å–檔案 \"%s\""
+
+msgid "E665: Cannot start GUI, no valid font found"
+msgstr "E665: 無法啟動圖型界é¢ï¼Œæ‰¾ä¸åˆ°å¯ç”¨çš„å­—åž‹"
+
+msgid "E231: 'guifontwide' invalid"
+msgstr "E231: ä¸æ­£ç¢ºçš„ 'guifontwide'"
+
+msgid "E599: Value of 'imactivatekey' is invalid"
+msgstr "E599: 'imactivatekey' 的值ä¸æ­£ç¢º"
+
+#, c-format
+msgid "E254: Cannot allocate color %s"
+msgstr "E254: ä¸èƒ½é…ç½®é¡è‰² %s"
+
+msgid "<cannot open> "
+msgstr "<ä¸èƒ½é–‹å•Ÿ>"
+
+#, c-format
+msgid "E616: vim_SelFile: can't get font %s"
+msgstr "E616: vim_SelFile: ä¸èƒ½ä½¿ç”¨ %s å­—åž‹"
+
+msgid "E614: vim_SelFile: can't return to current directory"
+msgstr "E614: vim_SelFile: 無法回到目å‰ç›®éŒ„"
+
+msgid "Pathname:"
+msgstr "路徑:"
+
+msgid "E615: vim_SelFile: can't get current directory"
+msgstr "E615: vim_SelFile: 無法å–å¾—ç›®å‰ç›®éŒ„"
+
+msgid "OK"
+msgstr "確定"
+
+msgid "Cancel"
+msgstr "å–消"
+
+msgid "Scrollbar Widget: Could not get geometry of thumb pixmap."
+msgstr "æ²å‹•è»¸: ä¸èƒ½è¨­å®š thumb pixmap çš„ä½ç½®"
+
+msgid "Vim dialog"
+msgstr "Vim å°è©±ç›’"
+
+msgid "E232: Cannot create BalloonEval with both message and callback"
+msgstr "E232: ä¸èƒ½å°è¨Šæ¯èˆ‡ callback 建立 BallonEval"
+
+msgid "Vim dialog..."
+msgstr "Vim å°è©±ç›’..."
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"&Cancel"
+msgstr ""
+"&Y是\n"
+"&Nå¦\n"
+"&Cå–消"
+
+msgid "Input _Methods"
+msgstr "輸入法"
+
+msgid "VIM - Search and Replace..."
+msgstr "VIM - 尋找與å–代..."
+
+msgid "VIM - Search..."
+msgstr "VIM - 尋找..."
+
+msgid "Find what:"
+msgstr "æœå°‹:"
+
+msgid "Replace with:"
+msgstr "å–代為:"
+
+#. whole word only button
+msgid "Match whole word only"
+msgstr "åªæœå°‹å®Œå…¨ç›¸åŒçš„å­—"
+
+#. match case button
+msgid "Match case"
+msgstr "符åˆå¤§å°å¯«"
+
+msgid "Direction"
+msgstr "æ–¹å‘"
+
+#. 'Up' and 'Down' buttons
+msgid "Up"
+msgstr "å‘上"
+
+msgid "Down"
+msgstr "å‘下"
+
+msgid "Find Next"
+msgstr "找下一個"
+
+msgid "Replace"
+msgstr "å–代"
+
+msgid "Replace All"
+msgstr "å–代全部"
+
+msgid "Vim: Received \"die\" request from session manager\n"
+msgstr "Vim: ç”± Session 管ç†å“¡æ”¶åˆ° \"die\" è¦æ±‚\n"
+
+msgid "Vim: Main window unexpectedly destroyed\n"
+msgstr "Vim: 主視窗爛掉\n"
+
+msgid "Font Selection"
+msgstr "å­—åž‹é¸æ“‡"
+
+msgid "Used CUT_BUFFER0 instead of empty selection"
+msgstr "使用 CUT_BUFFER0 來å–代空é¸æ“‡"
+
+msgid "Filter"
+msgstr "éŽæ¿¾å™¨"
+
+msgid "Directories"
+msgstr "目錄"
+
+msgid "Help"
+msgstr "輔助說明"
+
+msgid "Files"
+msgstr "檔案"
+
+msgid "Selection"
+msgstr "é¸æ“‡"
+
+msgid "Undo"
+msgstr "復原"
+
+#, c-format
+msgid "E671: Cannot find window title \"%s\""
+msgstr "E671: 找ä¸åˆ°æ¨™é¡Œç‚º \"%s\" 的視窗"
+
+#, c-format
+msgid "E243: Argument not supported: \"-%s\"; Use the OLE version."
+msgstr "E243: ä¸æ”¯æ´åƒæ•¸ \"-%s\"。請用 OLE 版本。"
+
+msgid "E672: Unable to open window inside MDI application"
+msgstr "E672: 無法在 MDI 程å¼ä¸­é–‹å•Ÿè¦–窗"
+
+msgid "Find string (use '\\\\' to find a '\\')"
+msgstr "æœå°‹å­—串 (使用 '\\\\' 來表示 '\\')"
+
+msgid "Find & Replace (use '\\\\' to find a '\\')"
+msgstr "æœå°‹åŠå–代字串 (使用 '\\\\' 來表示 '\\')"
+
+msgid "Vim E458: Cannot allocate colormap entry, some colors may be incorrect"
+msgstr "Vim E458: 無法é…ç½® color map 項目,有些é¡è‰²çœ‹èµ·ä¾†æœƒæ€ªæ€ªçš„"
+
+#, c-format
+msgid "E250: Fonts for the following charsets are missing in fontset %s:"
+msgstr "E250: Fontset %s 沒有設定正確的字型以供顯示這些字元集:"
+
+#, c-format
+msgid "E252: Fontset name: %s"
+msgstr "E252: 字型集(Fontset)å稱: %s"
+
+#, c-format
+msgid "Font '%s' is not fixed-width"
+msgstr "'%s' ä¸æ˜¯å›ºå®šå¯¬åº¦å­—åž‹"
+
+#, c-format
+msgid "E253: Fontset name: %s\n"
+msgstr "E253: 字型集(Fontset)å稱: %s\n"
+
+#, c-format
+msgid "Font0: %s\n"
+msgstr "Font0: %s\n"
+
+#, c-format
+msgid "Font1: %s\n"
+msgstr "Font1: %s\n"
+
+#, c-format
+msgid "Font%ld width is not twice that of font0\n"
+msgstr "å­—åž‹%ld 寬度ä¸æ˜¯ å­—åž‹0 çš„å…©å€\n"
+
+#, c-format
+msgid "Font0 width: %ld\n"
+msgstr "字型0的寬度:%ld\n"
+
+#, c-format
+msgid ""
+"Font1 width: %ld\n"
+"\n"
+msgstr ""
+"字型1寬度: %ld\n"
+"\n"
+
+msgid "E256: Hangul automata ERROR"
+msgstr "E256: Hangul automata 錯誤"
+
+msgid "Add a new database"
+msgstr "新增資料庫"
+
+msgid "Query for a pattern"
+msgstr "輸入 pattern"
+
+msgid "Show this message"
+msgstr "顯示此訊æ¯"
+
+msgid "Kill a connection"
+msgstr "çµæŸé€£ç·š"
+
+msgid "Reinit all connections"
+msgstr "é‡è¨­æ‰€æœ‰é€£ç·š"
+
+msgid "Show connections"
+msgstr "顯示連線"
+
+#, c-format
+msgid "E560: Usage: cs[cope] %s"
+msgstr "E560: 用法: cs[cope] %s"
+
+msgid "This cscope command does not support splitting the window.\n"
+msgstr "這個 cscope 命令ä¸æ”¯æ´åˆ†å‰²èž¢å¹•\n"
+
+msgid "E562: Usage: cstag <ident>"
+msgstr "E562: 用法: cstag <識別字ident>"
+
+msgid "E257: cstag: tag not found"
+msgstr "E257: cstag: 找ä¸åˆ° tag"
+
+#, c-format
+msgid "E563: stat(%s) error: %d"
+msgstr "E563: stat(%s) 錯誤: %d"
+
+msgid "E563: stat error"
+msgstr "E563: stat 錯誤"
+
+#, c-format
+msgid "E564: %s is not a directory or a valid cscope database"
+msgstr "E564: %s ä¸æ˜¯ç›®éŒ„或 cscope 資料庫"
+
+#, c-format
+msgid "Added cscope database %s"
+msgstr "新增 cscope 資料庫 %s"
+
+#, c-format
+msgid "E262: error reading cscope connection %ld"
+msgstr "E262: è®€å– cscope 連線 %ld 錯誤"
+
+msgid "E561: unknown cscope search type"
+msgstr "E561: 未知的 cscope æœå°‹å½¢æ…‹"
+
+msgid "E566: Could not create cscope pipes"
+msgstr "E566: 無法建立與 cscope 的 pipe 連線"
+
+msgid "E622: Could not fork for cscope"
+msgstr "E622: 無法 fork 以執行 cscope "
+
+msgid "cs_create_connection exec failed"
+msgstr "cs_create_connection 執行失敗"
+
+msgid "E623: Could not spawn cscope process"
+msgstr "E623: 無法執行 cscope "
+
+msgid "cs_create_connection: fdopen for to_fp failed"
+msgstr "cs_create_connection: fdopen 失敗 (to_fp)"
+
+msgid "cs_create_connection: fdopen for fr_fp failed"
+msgstr "cs_create_connection: fdopen 失敗 (fr_fp)"
+
+msgid "E567: no cscope connections"
+msgstr "E567: 沒有 cscope 連線"
+
+#, c-format
+msgid "E259: no matches found for cscope query %s of %s"
+msgstr "E259: 找ä¸åˆ°ç¬¦åˆ cscope çš„æœå°‹ %s / %s"
+
+#, c-format
+msgid "E469: invalid cscopequickfix flag %c for %c"
+msgstr "E469: cscopequickfix çš„ flac %c (%c) ä¸æ­£ç¢º"
+
+msgid "cscope commands:\n"
+msgstr "cscope 命令:\n"
+
+#, c-format
+msgid "%-5s: %-30s (Usage: %s)"
+msgstr "%-5s: %-30s (用法: %s)"
+
+#, c-format
+msgid "E625: cannot open cscope database: %s"
+msgstr "E625: 無法開啟 cscope 資料庫 %s"
+
+msgid "E626: cannot get cscope database information"
+msgstr "E626: 無法å–å¾— cscope 資料庫資訊"
+
+msgid "E568: duplicate cscope database not added"
+msgstr "E568: é‡è¤‡çš„ cscope 資料庫未被加入"
+
+msgid "E569: maximum number of cscope connections reached"
+msgstr "E569: å·²é”到 cscope 最大連線數目"
+
+#, c-format
+msgid "E261: cscope connection %s not found"
+msgstr "E261: 找ä¸åˆ° cscope 連線 %s"
+
+#, c-format
+msgid "cscope connection %s closed"
+msgstr "cscope 連線 %s 已關閉"
+
+#. should not reach here
+msgid "E570: fatal error in cs_manage_matches"
+msgstr "E570: cs_manage_matches åš´é‡éŒ¯èª¤"
+
+#, c-format
+msgid "Cscope tag: %s"
+msgstr "Cscope 標籤(tag): %s"
+
+msgid ""
+"\n"
+" # line"
+msgstr ""
+"\n"
+" # 行 "
+
+msgid "filename / context / line\n"
+msgstr "檔å / 內文 / 行號\n"
+
+#, c-format
+msgid "E609: Cscope error: %s"
+msgstr "E609: Csope 錯誤: %s"
+
+msgid "All cscope databases reset"
+msgstr "é‡è¨­æ‰€æœ‰ cscope 資料庫"
+
+msgid "no cscope connections\n"
+msgstr "沒有 cscope 連線\n"
+
+msgid " # pid database name prepend path\n"
+msgstr " # pid 資料庫å稱 prepend path\n"
+
+msgid ""
+"E263: Sorry, this command is disabled, the Python library could not be "
+"loaded."
+msgstr "E263: 抱歉,這個命令無法使用,Python 程å¼åº«æ²’有載入。"
+
+msgid "E659: Cannot invoke Python recursively"
+msgstr "E659: 無法éžè¿´åŸ·è¡Œ Python "
+
+msgid "can't delete OutputObject attributes"
+msgstr "無法刪除 OutputObject 屬性"
+
+msgid "softspace must be an integer"
+msgstr "softspace 必需是整數"
+
+msgid "invalid attribute"
+msgstr "ä¸æ­£ç¢ºçš„屬性"
+
+msgid "writelines() requires list of strings"
+msgstr "writelines() éœ€è¦ string list 當åƒæ•¸"
+
+msgid "E264: Python: Error initialising I/O objects"
+msgstr "E264: Python: 無法åˆå§‹ I/O 物件"
+
+msgid "invalid expression"
+msgstr "ä¸æ­£ç¢ºçš„é‹ç®—å¼"
+
+msgid "expressions disabled at compile time"
+msgstr "因為編譯時沒有加入é‹ç®—å¼(expression)的程å¼ç¢¼ï¼Œæ‰€ä»¥ç„¡æ³•ä½¿ç”¨é‹ç®—å¼"
+
+msgid "attempt to refer to deleted buffer"
+msgstr "試圖使用已被刪除的 buffer"
+
+msgid "line number out of range"
+msgstr "行號超出範åœ"
+
+#, c-format
+msgid "<buffer object (deleted) at %8lX>"
+msgstr "<buffer 物件 (已刪除): %8lX>"
+
+msgid "invalid mark name"
+msgstr "標記å稱ä¸æ­£ç¢º"
+
+msgid "no such buffer"
+msgstr "ç„¡æ­¤ buffer"
+
+msgid "attempt to refer to deleted window"
+msgstr "試圖使用已被刪除的視窗"
+
+msgid "readonly attribute"
+msgstr "唯讀屬性"
+
+msgid "cursor position outside buffer"
+msgstr "游標定ä½åœ¨ç·©è¡å€ä¹‹å¤–"
+
+#, c-format
+msgid "<window object (deleted) at %.8lX>"
+msgstr "<視窗物件(已刪除): %.8lX>"
+
+#, c-format
+msgid "<window object (unknown) at %.8lX>"
+msgstr "<視窗物件(未知): %.8lX>"
+
+#, c-format
+msgid "<window %d>"
+msgstr "<視窗 %d>"
+
+msgid "no such window"
+msgstr "無此視窗"
+
+msgid "cannot save undo information"
+msgstr "無法儲存復原資訊"
+
+msgid "cannot delete line"
+msgstr "ä¸èƒ½åˆªé™¤æ­¤è¡Œ "
+
+msgid "cannot replace line"
+msgstr "ä¸èƒ½æ›¿ä»£æ­¤è¡Œ "
+
+msgid "cannot insert line"
+msgstr "ä¸èƒ½æ›¿ä»£æ’入此行 "
+
+msgid "string cannot contain newlines"
+msgstr "字串無法包å«æ–°è¡Œ "
+
+msgid ""
+"E266: Sorry, this command is disabled, the Ruby library could not be loaded."
+msgstr "E266: 此命令無法使用,無法載入 Ruby 程å¼åº«(Library)"
+
+#, c-format
+msgid "E273: unknown longjmp status %d"
+msgstr "E273: 未知的 longjmp status %d"
+
+msgid "Toggle implementation/definition"
+msgstr "切æ›å¯¦ä½œ/定義"
+
+msgid "Show base class of"
+msgstr "顯示 base class of:"
+
+msgid "Show overridden member function"
+msgstr "顯示被 override 的 member function"
+
+msgid "Retrieve from file"
+msgstr "讀å–: 從檔案"
+
+msgid "Retrieve from project"
+msgstr "讀å–: 從物件"
+
+msgid "Retrieve from all projects"
+msgstr "讀å–: 從所有 project"
+
+msgid "Retrieve"
+msgstr "讀å–"
+
+msgid "Show source of"
+msgstr "顯示原始碼: "
+
+msgid "Find symbol"
+msgstr "æœå°‹ symbol"
+
+msgid "Browse class"
+msgstr "ç€è¦½ class"
+
+msgid "Show class in hierarchy"
+msgstr "顯示階層å¼çš„ class"
+
+msgid "Show class in restricted hierarchy"
+msgstr "顯示 restricted 階層å¼çš„ class"
+
+msgid "Xref refers to"
+msgstr "Xref åƒè€ƒåˆ°"
+
+msgid "Xref referred by"
+msgstr "Xref 被誰åƒè€ƒ:"
+
+msgid "Xref has a"
+msgstr "Xref 有"
+
+msgid "Xref used by"
+msgstr "Xref 被誰使用:"
+
+msgid "Show docu of"
+msgstr "顯示文件: "
+
+msgid "Generate docu for"
+msgstr "產生文件: "
+
+msgid ""
+"Cannot connect to SNiFF+. Check environment (sniffemacs must be found in "
+"$PATH).\n"
+msgstr "無法連線到 SNiFF+。請檢查環境變數 ($PATH 裡必需å¯ä»¥æ‰¾åˆ° sniffemacs)\n"
+
+msgid "E274: Sniff: Error during read. Disconnected"
+msgstr "E274: Sniff: 讀å–錯誤. å–消連線"
+
+msgid "SNiFF+ is currently "
+msgstr "SNiFF+ ç›®å‰"
+
+msgid "not "
+msgstr "未"
+
+msgid "connected"
+msgstr "連線中"
+
+#, c-format
+msgid "E275: Unknown SNiFF+ request: %s"
+msgstr "E275: ä¸æ­£ç¢ºçš„ SNiff+ 呼å«: %s"
+
+msgid "E276: Error connecting to SNiFF+"
+msgstr "E276: 連線到 SNiFF+ 失敗"
+
+msgid "E278: SNiFF+ not connected"
+msgstr "E278: 未連線到 SNiFF+"
+
+msgid "E279: Not a SNiFF+ buffer"
+msgstr "E279: ä¸æ˜¯ SNiFF+ çš„ç·©è¡å€"
+
+msgid "Sniff: Error during write. Disconnected"
+msgstr "Sniff: 寫入錯誤。çµæŸé€£ç·š"
+
+msgid "invalid buffer number"
+msgstr "ç·©è¡å€è™Ÿç¢¼éŒ¯èª¤"
+
+msgid "not implemented yet"
+msgstr "尚未實作"
+
+msgid "unknown option"
+msgstr "ä¸æ­£ç¢ºçš„é¸é …"
+
+#. ???
+msgid "cannot set line(s)"
+msgstr "ä¸èƒ½è¨­å®šè¡Œ "
+
+msgid "mark not set"
+msgstr "沒有設定標記"
+
+#, c-format
+msgid "row %d column %d"
+msgstr "列 %d 行 %d"
+
+msgid "cannot insert/append line"
+msgstr "ä¸èƒ½æ’入或附加此行 "
+
+msgid "unknown flag: "
+msgstr "錯誤的旗標: "
+
+msgid "unknown vimOption"
+msgstr "ä¸æ­£ç¢ºçš„ VIM é¸é …"
+
+msgid "keyboard interrupt"
+msgstr "éµç›¤ä¸­æ–·"
+
+msgid "vim error"
+msgstr "vim 錯誤"
+
+msgid "cannot create buffer/window command: object is being deleted"
+msgstr "無法建立緩è¡å€/視窗命令: 物件將會被刪除"
+
+msgid ""
+"cannot register callback command: buffer/window is already being deleted"
+msgstr "無法註冊 callback 命令: ç·©è¡å€/視窗已經被刪除了"
+
+#. This should never happen. Famous last word?
+msgid ""
+"E280: TCL FATAL ERROR: reflist corrupt!? Please report this to vim-dev@vim."
+"org"
+msgstr "E280: TCL åš´é‡éŒ¯èª¤: reflist 爛掉了!? 請報告給 to vim-dev@vim.org"
+
+msgid "cannot register callback command: buffer/window reference not found"
+msgstr "無法註冊 callback 命令: 找ä¸åˆ°ç·©è¡å€/視窗"
+
+msgid ""
+"E571: Sorry, this command is disabled: the Tcl library could not be loaded."
+msgstr "E571: 此命令無法使用, 因為無法載入 Tcl 程å¼åº«(Library)"
+
+msgid ""
+"E281: TCL ERROR: exit code is not int!? Please report this to vim-dev@vim.org"
+msgstr "E281: TCL 錯誤: çµæŸç¢¼ä¸æ˜¯æ•´æ•¸!? 請報告給 to vim-dev@vim.org"
+
+msgid "cannot get line"
+msgstr "ä¸èƒ½å–得此行 "
+
+msgid "Unable to register a command server name"
+msgstr "無法註冊命令伺æœå™¨å稱"
+
+msgid "E248: Failed to send command to the destination program"
+msgstr "E248: 無法é€å‡ºå‘½ä»¤åˆ°ç›®çš„地程å¼"
+
+#, c-format
+msgid "E573: Invalid server id used: %s"
+msgstr "E573: ä¸æ­£ç¢ºçš„伺æœå™¨ id : %s"
+
+msgid "E251: VIM instance registry property is badly formed. Deleted!"
+msgstr "E251: VIM 的 registry 設定項有誤。已刪除。"
+
+msgid "Unknown option"
+msgstr "ä¸æ­£ç¢ºçš„é¸é …"
+
+msgid "Too many edit arguments"
+msgstr "太多編輯åƒæ•¸"
+
+msgid "Argument missing after"
+msgstr "缺少必è¦çš„åƒæ•¸:"
+
+msgid "Garbage after option"
+msgstr "無法辨èªæ­¤é¸é …後的命令: "
+
+msgid "Too many \"+command\", \"-c command\" or \"--cmd command\" arguments"
+msgstr "太多 \"+command\" 〠\"-c command\" 或 \"--cmd command\" åƒæ•¸"
+
+msgid "Invalid argument for"
+msgstr "ä¸æ­£ç¢ºçš„åƒæ•¸: "
+
+msgid "This Vim was not compiled with the diff feature."
+msgstr "您的 Vim 編譯時沒有加入 diff 的能力"
+
+msgid "Attempt to open script file again: \""
+msgstr "試圖å†æ¬¡é–‹å•Ÿ script 檔: \""
+
+msgid "Cannot open for reading: \""
+msgstr "無法開啟以讀å–: \""
+
+msgid "Cannot open for script output: \""
+msgstr "無法開啟為 script 輸出: \""
+
+#, c-format
+msgid "%d files to edit\n"
+msgstr "還有 %d 個檔案等待編輯\n"
+
+msgid "Vim: Warning: Output is not to a terminal\n"
+msgstr "Vim: 注æ„: 輸出ä¸æ˜¯çµ‚端機(螢幕)\n"
+
+msgid "Vim: Warning: Input is not from a terminal\n"
+msgstr "Vim: 注æ„: 輸入ä¸æ˜¯çµ‚端機(éµç›¤)\n"
+
+#. just in case..
+msgid "pre-vimrc command line"
+msgstr "vimrc å‰å‘½ä»¤åˆ—"
+
+#, c-format
+msgid "E282: Cannot read from \"%s\""
+msgstr "E282: 無法讀å–檔案 \"%s\""
+
+msgid ""
+"\n"
+"More info with: \"vim -h\"\n"
+msgstr ""
+"\n"
+"查詢更多資訊請執行: \"vim -h\"\n"
+
+msgid "[file ..] edit specified file(s)"
+msgstr "[檔案 ..] 編輯指定的檔案"
+
+msgid "- read text from stdin"
+msgstr "- 從標準輸入(stdin)讀å–檔案"
+
+msgid "-t tag edit file where tag is defined"
+msgstr "-t tag 編輯時使用指定的 tag"
+
+msgid "-q [errorfile] edit file with first error"
+msgstr "-q [errorfile] 編輯時載入第一個錯誤"
+
+msgid ""
+"\n"
+"\n"
+"Usage:"
+msgstr ""
+"\n"
+"\n"
+" 用法:"
+
+msgid " vim [arguments] "
+msgstr "vim [åƒæ•¸] "
+
+msgid ""
+"\n"
+" or:"
+msgstr ""
+"\n"
+" 或:"
+
+msgid ""
+"\n"
+"\n"
+"Arguments:\n"
+msgstr ""
+"\n"
+"\n"
+"åƒæ•¸:\n"
+
+msgid "--\t\t\tOnly file names after this"
+msgstr "--\t\t\tåªæœ‰åœ¨é€™ä¹‹å¾Œçš„檔案"
+
+msgid "--literal\t\tDon't expand wildcards"
+msgstr "--literal\t\tä¸å±•é–‹è¬ç”¨å­—å…ƒ"
+
+msgid "-register\t\tRegister this gvim for OLE"
+msgstr "-register\t\t註冊 gvim 到 OLE"
+
+msgid "-unregister\t\tUnregister gvim for OLE"
+msgstr "-unregister\t\tå–消 OLE 中的 gvim 註冊"
+
+msgid "-g\t\t\tRun using GUI (like \"gvim\")"
+msgstr "-g\t\t\tä½¿ç”¨åœ–å½¢ç•Œé¢ (åŒ \"gvim\")"
+
+msgid "-f or --nofork\tForeground: Don't fork when starting GUI"
+msgstr "-f 或 --nofork\tå‰æ™¯: 起始圖形界é¢æ™‚ä¸ fork"
+
+msgid "-v\t\t\tVi mode (like \"vi\")"
+msgstr "-v\t\t\tVi æ¨¡å¼ (åŒ \"vi\")"
+
+msgid "-e\t\t\tEx mode (like \"ex\")"
+msgstr "-e\t\t\tEx æ¨¡å¼ (åŒ \"ex\")"
+
+msgid "-s\t\t\tSilent (batch) mode (only for \"ex\")"
+msgstr "-s\t\t\tå®‰éœ (batch) æ¨¡å¼ (åªèƒ½èˆ‡ \"ex\" 一起使用)"
+
+msgid "-d\t\t\tDiff mode (like \"vimdiff\")"
+msgstr "-d\t\t\tDiff æ¨¡å¼ (åŒ \"vimdiff\", å¯è¿…速比較兩檔案ä¸åŒè™•)"
+
+msgid "-y\t\t\tEasy mode (like \"evim\", modeless)"
+msgstr "-y\t\t\tç°¡æ˜“æ¨¡å¼ (åŒ \"evim\", modeless)"
+
+msgid "-R\t\t\tReadonly mode (like \"view\")"
+msgstr "-R\t\t\tå”¯è®€æ¨¡å¼ (åŒ \"view\")"
+
+msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
+msgstr "-Z\t\t\té™åˆ¶æ¨¡å¼ (åŒ \"rvim\")"
+
+msgid "-m\t\t\tModifications (writing files) not allowed"
+msgstr "-m\t\t\tä¸å¯ä¿®æ”¹ (寫入檔案)"
+
+msgid "-M\t\t\tModifications in text not allowed"
+msgstr "-M\t\t\tä¸å¯ä¿®æ”¹æ–‡å­—"
+
+msgid "-b\t\t\tBinary mode"
+msgstr "-b\t\t\t二進ä½æ¨¡å¼"
+
+msgid "-l\t\t\tLisp mode"
+msgstr "-l\t\t\tLisp 模å¼"
+
+msgid "-C\t\t\tCompatible with Vi: 'compatible'"
+msgstr "-C\t\t\t'compatible' 傳統 Vi 相容模å¼"
+
+msgid "-N\t\t\tNot fully Vi compatible: 'nocompatible'"
+msgstr "-N\t\t\t'nocompatible' ä¸å®Œå…¨èˆ‡å‚³çµ± Vi 相容,å¯ä½¿ç”¨ Vim 加強能力"
+
+msgid "-V[N]\t\tVerbose level"
+msgstr "-V[N]\t\tVerbose 等級"
+
+msgid "-D\t\t\tDebugging mode"
+msgstr "-D\t\t\t除錯模å¼"
+
+msgid "-n\t\t\tNo swap file, use memory only"
+msgstr "-n\t\t\tä¸ä½¿ç”¨æš«å­˜æª”, åªä½¿ç”¨è¨˜æ†¶é«”"
+
+msgid "-r\t\t\tList swap files and exit"
+msgstr "-r\t\t\t列出暫存檔後離開"
+
+msgid "-r (with file name)\tRecover crashed session"
+msgstr "-r (加檔å) \t修復上次æ毀的資料(Recover crashed session)"
+
+msgid "-L\t\t\tSame as -r"
+msgstr "-L\t\t\tåŒ -r"
+
+msgid "-f\t\t\tDon't use newcli to open window"
+msgstr "-f\t\t\tä¸ä½¿ç”¨ newcli 來開啟視窗"
+
+msgid "-dev <device>\t\tUse <device> for I/O"
+msgstr "-dev <device>\t\t使用 <device> åšè¼¸å‡ºå…¥"
+
+msgid "-A\t\t\tStart in Arabic mode"
+msgstr "-A\t\t\t啟動為 Arabic 模å¼"
+
+msgid "-H\t\t\tStart in Hebrew mode"
+msgstr "-H\t\t\t啟動為 Hebrew 模å¼"
+
+msgid "-F\t\t\tStart in Farsi mode"
+msgstr "-F\t\t\t啟動為 Farsi 模å¼"
+
+msgid "-T <terminal>\tSet terminal type to <terminal>"
+msgstr "-T <terminal>\t設定終端機為 <terminal>"
+
+msgid "-u <vimrc>\t\tUse <vimrc> instead of any .vimrc"
+msgstr "-u <vimrc>\t\t使用 <vimrc> å–代任何 .vimrc"
+
+msgid "-U <gvimrc>\t\tUse <gvimrc> instead of any .gvimrc"
+msgstr "-U <gvimrc>\t\t使用 <gvimrc> å–代任何 .gvimrc"
+
+msgid "--noplugin\t\tDon't load plugin scripts"
+msgstr "--noplugin\t\tä¸è¼‰å…¥ä»»ä½• plugin"
+
+msgid "-o[N]\t\tOpen N windows (default: one for each file)"
+msgstr "-o[N]\t\té–‹å•Ÿ N 個視窗 (é è¨­æ˜¯æ¯å€‹æª”案一個)"
+
+msgid "-O[N]\t\tLike -o but split vertically"
+msgstr "-O[N]\t\tåŒ -o 但使用垂直分割"
+
+msgid "+\t\t\tStart at end of file"
+msgstr "+\t\t\t啟動後跳到檔案çµå°¾"
+
+msgid "+<lnum>\t\tStart at line <lnum>"
+msgstr "+<lnum>\t\t啟動後跳到第 <lnum> 行 "
+
+msgid "--cmd <command>\tExecute <command> before loading any vimrc file"
+msgstr "--cmd <command>\t載入任何 vimrc å‰åŸ·è¡Œ <command>"
+
+msgid "-c <command>\t\tExecute <command> after loading the first file"
+msgstr "-c <command>\t\t載入第一個檔案後執行 <command>"
+
+msgid "-S <session>\t\tSource file <session> after loading the first file"
+msgstr "-S <session>\t\t載入第一個檔案後載入 Session 檔 <session>"
+
+msgid "-s <scriptin>\tRead Normal mode commands from file <scriptin>"
+msgstr "-s <scriptin>\t從 <scriptin> 讀入一般模å¼å‘½ä»¤"
+
+msgid "-w <scriptout>\tAppend all typed commands to file <scriptout>"
+msgstr "-w <scriptout>\tå°æª”案 <scriptout> 附加(append)所有輸入的命令"
+
+msgid "-W <scriptout>\tWrite all typed commands to file <scriptout>"
+msgstr "-W <scriptout>\tå°æª”案 <scriptout> 寫入所有輸入的命令"
+
+msgid "-x\t\t\tEdit encrypted files"
+msgstr "-x\t\t\t編輯編碼éŽçš„檔案"
+
+msgid "-display <display>\tConnect vim to this particular X-server"
+msgstr "-display <display>\t將 vim 與指定的 X-server 連線"
+
+msgid "-X\t\t\tDo not connect to X server"
+msgstr "-X\t\t\tä¸è¦é€£ç·šåˆ° X Server"
+
+msgid "--remote <files>\tEdit <files> in a Vim server if possible"
+msgstr "--remote <files>\t編輯 Vim 伺æœå™¨ä¸Šçš„ <files> 後離開"
+
+msgid "--remote-silent <files> Same, don't complain if there is no server"
+msgstr "--remote-silent <files> 相åŒï¼Œä½†æ²’有伺æœå™¨æ™‚ä¸è­¦å‘Š"
+
+msgid ""
+"--remote-wait <files> As --remote but wait for files to have been edited"
+msgstr "--remote-wait <files> åŒ --remote, 但會等候檔案完æˆç·¨è¼¯"
+
+msgid ""
+"--remote-wait-silent <files> Same, don't complain if there is no server"
+msgstr "--remote-wait-silent <files> 相åŒï¼Œä½†æ²’伺æœå™¨æ™‚ä¸è­¦å‘Š"
+
+msgid "--remote-send <keys>\tSend <keys> to a Vim server and exit"
+msgstr "--remote-send <keys>\té€å‡º <keys> 到 Vim 伺æœå™¨ä¸¦é›¢é–‹"
+
+msgid "--remote-expr <expr>\tEvaluate <expr> in a Vim server and print result"
+msgstr "--remote-expr <expr>\t在伺æœå™¨ä¸ŠåŸ·è¡Œ <expr> 並å°å‡ºçµæžœ"
+
+msgid "--serverlist\t\tList available Vim server names and exit"
+msgstr "--serverlist\t\t列出å¯ç”¨çš„ Vim 伺æœå™¨å稱並離開"
+
+msgid "--servername <name>\tSend to/become the Vim server <name>"
+msgstr "--servername <name>\té€è‡³/æˆç‚º Vim 伺æœå™¨ <name>"
+
+msgid "-i <viminfo>\t\tUse <viminfo> instead of .viminfo"
+msgstr "-i <viminfo>\t\t使用 <viminfo> è€Œéž .viminfo"
+
+msgid "-h or --help\tPrint Help (this message) and exit"
+msgstr "-h 或 --help\tå°å‡ºèªªæ˜Ž(也就是本訊æ¯)後離開"
+
+msgid "--version\t\tPrint version information and exit"
+msgstr "--version\t\tå°å‡ºç‰ˆæœ¬è³‡è¨Šå¾Œé›¢é–‹"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Motif version):\n"
+msgstr ""
+"\n"
+"gvim èªå¾—çš„åƒæ•¸ (Motif 版):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (neXtaw version):\n"
+msgstr ""
+"\n"
+"gvim èªå¾—çš„åƒæ•¸ (neXtaw 版):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Athena version):\n"
+msgstr ""
+"\n"
+"gvim èªå¾—çš„åƒæ•¸ (Athena 版):\n"
+
+msgid "-display <display>\tRun vim on <display>"
+msgstr "-display <display>\t在視窗 <display> 執行 vim"
+
+msgid "-iconic\t\tStart vim iconified"
+msgstr "-iconic\t\t啟動後圖示化(iconified)"
+
+msgid "-name <name>\t\tUse resource as if vim was <name>"
+msgstr "-name <name>\t\tè®€å– Resource 時把 vim çš„å稱視為 <name>"
+
+msgid "\t\t\t (Unimplemented)\n"
+msgstr "\t\t\t (尚未實作)\n"
+
+msgid "-background <color>\tUse <color> for the background (also: -bg)"
+msgstr "-background <color>\t設定 <color> 為背景色 (也å¯ç”¨ -bg)"
+
+msgid "-foreground <color>\tUse <color> for normal text (also: -fg)"
+msgstr "-foreground <color>\t設定 <color> 為一般文字é¡è‰² (也å¯ç”¨ -fg)"
+
+msgid "-font <font>\t\tUse <font> for normal text (also: -fn)"
+msgstr "-font <font>\t使用 <font> 為一般字型 (也å¯ç”¨ -fn)"
+
+msgid "-boldfont <font>\tUse <font> for bold text"
+msgstr "-boldfont <font>\t使用 <font> 為粗體字型"
+
+msgid "-italicfont <font>\tUse <font> for italic text"
+msgstr "-italicfont <font>\t使用 <font> 為斜體字型"
+
+msgid "-geometry <geom>\tUse <geom> for initial geometry (also: -geom)"
+msgstr "-geometry <geom>\t使用<geom>為起始ä½ç½® (也å¯ç”¨ -geom)"
+
+msgid "-borderwidth <width>\tUse a border width of <width> (also: -bw)"
+msgstr "-borderwidth <width>\t使用寬度為 <width> 的邊框 (也å¯ç”¨ -bw)"
+
+msgid "-scrollbarwidth <width> Use a scrollbar width of <width> (also: -sw)"
+msgstr "-scrollbarwidth <width> 設定æ²å‹•è»¸å¯¬åº¦ç‚º <width> (也å¯ç”¨ -sw)"
+
+msgid "-menuheight <height>\tUse a menu bar height of <height> (also: -mh)"
+msgstr "-menuheight <height>\t設定é¸å–®åˆ—的高度為 <height> (也å¯ç”¨ -mh)"
+
+msgid "-reverse\t\tUse reverse video (also: -rv)"
+msgstr "-reverse\t\t使用å相顯示 (也å¯ç”¨ -rv)"
+
+msgid "+reverse\t\tDon't use reverse video (also: +rv)"
+msgstr "+reverse\t\tä¸ä½¿ç”¨å相顯示 (也å¯ç”¨ +rv)"
+
+msgid "-xrm <resource>\tSet the specified resource"
+msgstr "-xrm <resource>\t設定指定的 resource"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (RISC OS version):\n"
+msgstr ""
+"\n"
+"gvim èªå¾—çš„åƒæ•¸ (RISC OS 版):\n"
+
+msgid "--columns <number>\tInitial width of window in columns"
+msgstr "--columns <number>\t視窗åˆå§‹åŒ–寬度"
+
+msgid "--rows <number>\tInitial height of window in rows"
+msgstr "--rows <number>\t視窗åˆå§‹åŒ–高度"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (GTK+ version):\n"
+msgstr ""
+"\n"
+"gvim èªå¾—çš„åƒæ•¸ (GTK+ 版):\n"
+
+msgid "-display <display>\tRun vim on <display> (also: --display)"
+msgstr "-display <display>\t在 <display> 執行 vim (也å¯ç”¨ --display)"
+
+msgid "--role <role>\tSet a unique role to identify the main window"
+msgstr "--role <role>\t設定ç¨ç‰¹çš„角色(role)以å€åˆ†ä¸»è¦–窗"
+
+msgid "--socketid <xid>\tOpen Vim inside another GTK widget"
+msgstr "--socketid <xid>\t在å¦ä¸€å€‹ GTK widget 內開啟 Vim"
+
+msgid "-P <parent title>\tOpen Vim inside parent application"
+msgstr "-P <parent title>\t在父程å¼ä¸­é–‹å•Ÿ Vim"
+
+msgid "No display"
+msgstr "無顯示"
+
+#. Failed to send, abort.
+msgid ": Send failed.\n"
+msgstr ": 傳é€å¤±æ•—。\n"
+
+#. Let vim start normally.
+msgid ": Send failed. Trying to execute locally\n"
+msgstr ": é€å‡ºå¤±æ•—。試圖在本地執行\n"
+
+#, c-format
+msgid "%d of %d edited"
+msgstr "已編輯 %d/%d 個檔案"
+
+msgid "No display: Send expression failed.\n"
+msgstr "ç„¡ Display: 無法傳é€é‹ç®—å¼ã€‚\n"
+
+msgid ": Send expression failed.\n"
+msgstr ": 無法傳é€é‹ç®—å¼ã€‚\n"
+
+msgid "No marks set"
+msgstr "沒有設定標記 (mark)"
+
+#, c-format
+msgid "E283: No marks matching \"%s\""
+msgstr "E283: 找ä¸åˆ°ç¬¦åˆ \"%s\" 的標記(mark)"
+
+#. Highlight title
+msgid ""
+"\n"
+"mark line col file/text"
+msgstr ""
+"\n"
+"標記 行號 欄 檔案/文字"
+
+#. Highlight title
+msgid ""
+"\n"
+" jump line col file/text"
+msgstr ""
+"\n"
+" jump 行號 欄 檔案/文字"
+
+#. Highlight title
+msgid ""
+"\n"
+"change line col text"
+msgstr ""
+"\n"
+"改變 行號 欄 文字"
+
+#, c-format
+msgid ""
+"\n"
+"# File marks:\n"
+msgstr ""
+"\n"
+"# 檔案標記:\n"
+
+#. Write the jumplist with -'
+#, c-format
+msgid ""
+"\n"
+"# Jumplist (newest first):\n"
+msgstr ""
+"\n"
+"# Jumplist (由新到舊):\n"
+
+#, c-format
+msgid ""
+"\n"
+"# History of marks within files (newest to oldest):\n"
+msgstr ""
+"\n"
+"# 檔案內 Mark 記錄 (由新到舊):\n"
+
+msgid "Missing '>'"
+msgstr "缺少å°æ‡‰çš„ '>'"
+
+msgid "E543: Not a valid codepage"
+msgstr "E543: ä¸æ­£ç¢ºçš„ codepage"
+
+msgid "E284: Cannot set IC values"
+msgstr "E284: ä¸èƒ½è¨­å®š IC 數值"
+
+msgid "E285: Failed to create input context"
+msgstr "E285: 無法建立 input context"
+
+msgid "E286: Failed to open input method"
+msgstr "E286: 無法開啟輸入法"
+
+msgid "E287: Warning: Could not set destroy callback to IM"
+msgstr "E287: 警告: 無法移除 IM 的 callback"
+
+msgid "E288: input method doesn't support any style"
+msgstr "E288: 輸入法ä¸æ”¯æ´ä»»ä½• style"
+
+msgid "E289: input method doesn't support my preedit type"
+msgstr "E289: 輸入法ä¸æ”¯æ´ä»»ä½• style"
+
+msgid "E290: over-the-spot style requires fontset"
+msgstr "E290: over-the-spot 需è¦å­—型集(Fontset)"
+
+msgid "E291: Your GTK+ is older than 1.2.3. Status area disabled"
+msgstr "E291: ä½ çš„ GTK+ 比 1.2.3 還舊。無法使用狀態å€ã€‚"
+
+msgid "E292: Input Method Server is not running"
+msgstr "E292: 沒有執行中的輸入法管ç†ç¨‹å¼(Input Method Server)"
+
+msgid "E293: block was not locked"
+msgstr "E293: å€å¡Šæœªè¢«éŽ–定"
+
+msgid "E294: Seek error in swap file read"
+msgstr "E294: 暫存檔讀å–錯誤"
+
+msgid "E295: Read error in swap file"
+msgstr "E295: 暫存檔讀å–錯誤"
+
+msgid "E296: Seek error in swap file write"
+msgstr "E296: 暫存檔寫入錯誤"
+
+msgid "E297: Write error in swap file"
+msgstr "E297: 暫存檔寫入錯誤"
+
+msgid "E300: Swap file already exists (symlink attack?)"
+msgstr "E300: 暫存檔已經存在! (å°å¿ƒç¬¦è™Ÿé€£çµçš„安全æ¼æ´ž!?)"
+
+msgid "E298: Didn't get block nr 0?"
+msgstr "E298: 找ä¸åˆ°å€å¡Š 0?"
+
+msgid "E298: Didn't get block nr 1?"
+msgstr "E298: 找ä¸åˆ°å€å¡Š 1?"
+
+msgid "E298: Didn't get block nr 2?"
+msgstr "E298: 找ä¸åˆ°å€å¡Š 2?"
+
+#. could not (re)open the swap file, what can we do????
+msgid "E301: Oops, lost the swap file!!!"
+msgstr "E301: 噢噢, 暫存檔ä¸è¦‹äº†!!!"
+
+msgid "E302: Could not rename swap file"
+msgstr "E302: 無法改變暫存檔的å稱"
+
+#, c-format
+msgid "E303: Unable to open swap file for \"%s\", recovery impossible"
+msgstr "E303: 無法開啟暫存檔 \"%s\", ä¸å¯èƒ½ä¿®å¾©äº†"
+
+msgid "E304: ml_timestamp: Didn't get block 0??"
+msgstr "E304: ml_timestamp: 找ä¸åˆ°å€å¡Š 0??"
+
+#, c-format
+msgid "E305: No swap file found for %s"
+msgstr "E305: 找ä¸åˆ° %s 的暫存檔"
+
+msgid "Enter number of swap file to use (0 to quit): "
+msgstr "è«‹é¸æ“‡ä½ è¦ä½¿ç”¨çš„暫存檔 (按0 離開): "
+
+#, c-format
+msgid "E306: Cannot open %s"
+msgstr "E306: 無法開啟 %s"
+
+msgid "Unable to read block 0 from "
+msgstr "無法讀å–å€å¡Š 0:"
+
+msgid ""
+"\n"
+"Maybe no changes were made or Vim did not update the swap file."
+msgstr ""
+"\n"
+"å¯èƒ½æ˜¯ä½ æ²’åšéŽä»»ä½•ä¿®æ”¹æˆ–是 Vim 還來ä¸åŠæ›´æ–°æš«å­˜æª”."
+
+msgid " cannot be used with this version of Vim.\n"
+msgstr " 無法在本版本的 Vim 中使用.\n"
+
+msgid "Use Vim version 3.0.\n"
+msgstr "使用 Vim 3.0。\n"
+
+#, c-format
+msgid "E307: %s does not look like a Vim swap file"
+msgstr "E307: %s 看起來ä¸åƒæ˜¯ Vim 暫存檔"
+
+msgid " cannot be used on this computer.\n"
+msgstr " 無法在這臺電腦上使用.\n"
+
+msgid "The file was created on "
+msgstr "本檔案建立於 "
+
+msgid ""
+",\n"
+"or the file has been damaged."
+msgstr ""
+",\n"
+"或是這檔案已經æ毀。"
+
+#, c-format
+msgid "Using swap file \"%s\""
+msgstr "使用暫存檔 \"%s\""
+
+#, c-format
+msgid "Original file \"%s\""
+msgstr "原始檔 \"%s\""
+
+msgid "E308: Warning: Original file may have been changed"
+msgstr "E308: 警告: 原始檔案å¯èƒ½å·²ç¶“修改éŽäº†"
+
+#, c-format
+msgid "E309: Unable to read block 1 from %s"
+msgstr "E309: 無法從 %s 讀å–å€å¡Š 1"
+
+msgid "???MANY LINES MISSING"
+msgstr "???缺少太多行 "
+
+msgid "???LINE COUNT WRONG"
+msgstr "???行號錯誤"
+
+msgid "???EMPTY BLOCK"
+msgstr "???空的 BLOCK"
+
+msgid "???LINES MISSING"
+msgstr "???找ä¸åˆ°ä¸€äº›è¡Œ "
+
+#, c-format
+msgid "E310: Block 1 ID wrong (%s not a .swp file?)"
+msgstr "E310: å€å¡Š 1 ID 錯誤 (%s ä¸æ˜¯æš«å­˜æª”?)"
+
+msgid "???BLOCK MISSING"
+msgstr "???找ä¸åˆ°BLOCK"
+
+msgid "??? from here until ???END lines may be messed up"
+msgstr "??? 從這裡到 ???END 的內容å¯èƒ½æœ‰å•é¡Œ"
+
+msgid "??? from here until ???END lines may have been inserted/deleted"
+msgstr "??? 從這裡到 ???END 的內容å¯èƒ½è¢«åˆªé™¤/æ’å…¥éŽ"
+
+# do not translate
+msgid "???END"
+msgstr "???END"
+
+msgid "E311: Recovery Interrupted"
+msgstr "E311: 修復已中斷"
+
+msgid ""
+"E312: Errors detected while recovering; look for lines starting with ???"
+msgstr "E312: 修復時發生錯誤; 請注æ„開頭為 ??? çš„è¡Œ "
+
+msgid "See \":help E312\" for more information."
+msgstr "詳細說明請見 \":help E312\""
+
+msgid "Recovery completed. You should check if everything is OK."
+msgstr "復原完æˆ. 請確定一切正常."
+
+msgid ""
+"\n"
+"(You might want to write out this file under another name\n"
+msgstr ""
+"\n"
+"(ä½ å¯èƒ½æœƒæƒ³è¦æŠŠé€™å€‹æª”案å¦å­˜åˆ¥çš„檔å,\n"
+
+msgid "and run diff with the original file to check for changes)\n"
+msgstr "å†åŸ·è¡Œ diff 與原檔案比較以檢查是å¦æœ‰æ”¹è®Š)\n"
+
+msgid ""
+"Delete the .swp file afterwards.\n"
+"\n"
+msgstr ""
+"(D)直接刪除 .swp 暫存檔\n"
+"\n"
+
+#. use msg() to start the scrolling properly
+msgid "Swap files found:"
+msgstr "找到以下的暫存檔:"
+
+msgid " In current directory:\n"
+msgstr " 在目å‰çš„目錄:\n"
+
+msgid " Using specified name:\n"
+msgstr " Using specified name:\n"
+
+msgid " In directory "
+msgstr " 在目錄 "
+
+msgid " -- none --\n"
+msgstr " -- ç„¡ --\n"
+
+msgid " owned by: "
+msgstr " æ“有者: "
+
+msgid " dated: "
+msgstr " 日期: "
+
+msgid " dated: "
+msgstr " 日期: "
+
+msgid " [from Vim version 3.0]"
+msgstr " [從 Vim 版本 3.0]"
+
+msgid " [does not look like a Vim swap file]"
+msgstr " [ä¸åƒ Vim 的暫存檔]"
+
+msgid " file name: "
+msgstr " 檔å: "
+
+msgid ""
+"\n"
+" modified: "
+msgstr ""
+"\n"
+" 修改éŽ: "
+
+msgid "YES"
+msgstr "是"
+
+msgid "no"
+msgstr "å¦"
+
+msgid ""
+"\n"
+" user name: "
+msgstr ""
+"\n"
+" 使用者: "
+
+msgid " host name: "
+msgstr " 主機å稱: "
+
+msgid ""
+"\n"
+" host name: "
+msgstr ""
+"\n"
+" 主機å稱: "
+
+msgid ""
+"\n"
+" process ID: "
+msgstr ""
+"\n"
+" process ID: "
+
+msgid " (still running)"
+msgstr " (執行中)"
+
+msgid ""
+"\n"
+" [not usable with this version of Vim]"
+msgstr ""
+"\n"
+" [無法在本版本的 Vim 上使用]"
+
+msgid ""
+"\n"
+" [not usable on this computer]"
+msgstr ""
+"\n"
+" [無法在本電腦上使用]"
+
+msgid " [cannot be read]"
+msgstr " [無法讀å–]"
+
+msgid " [cannot be opened]"
+msgstr " [無法開啟]"
+
+msgid "E313: Cannot preserve, there is no swap file"
+msgstr "E313: 無法ä¿ç•™, ä¸ä½¿ç”¨æš«å­˜æª”"
+
+msgid "File preserved"
+msgstr "檔案已ä¿ç•™"
+
+msgid "E314: Preserve failed"
+msgstr "E314: ä¿ç•™å¤±æ•—"
+
+#, c-format
+msgid "E315: ml_get: invalid lnum: %ld"
+msgstr "E315: ml_get: 錯誤的 lnum: %ld"
+
+#, c-format
+msgid "E316: ml_get: cannot find line %ld"
+msgstr "E316: ml_get: 找ä¸åˆ°ç¬¬ %ld è¡Œ "
+
+msgid "E317: pointer block id wrong 3"
+msgstr "E317: 指標å€å¡Š id 錯誤 3"
+
+msgid "stack_idx should be 0"
+msgstr "stack_idx 應該是 0"
+
+msgid "E318: Updated too many blocks?"
+msgstr "E318: 更新太多å€å¡Š?"
+
+msgid "E317: pointer block id wrong 4"
+msgstr "E317: 指標å€å¡Š id 錯誤 4"
+
+msgid "deleted block 1?"
+msgstr "刪除å€å¡Š 1?"
+
+#, c-format
+msgid "E320: Cannot find line %ld"
+msgstr "E320: 找ä¸åˆ°ç¬¬ %ld è¡Œ "
+
+msgid "E317: pointer block id wrong"
+msgstr "E317: 指標å€å¡Š id 錯誤"
+
+msgid "pe_line_count is zero"
+msgstr "pe_line_count 為零"
+
+#, c-format
+msgid "E322: line number out of range: %ld past the end"
+msgstr "E322: 行號超出範åœ: %ld 超éŽçµå°¾"
+
+#, c-format
+msgid "E323: line count wrong in block %ld"
+msgstr "E323: å€å¡Š %ld 行數錯誤"
+
+msgid "Stack size increases"
+msgstr "堆疊大å°å¢žåŠ "
+
+msgid "E317: pointer block id wrong 2"
+msgstr "E317: 指標å€å¡Š id 錯 2"
+
+msgid "E325: ATTENTION"
+msgstr "E325: 注æ„"
+
+msgid ""
+"\n"
+"Found a swap file by the name \""
+msgstr ""
+"\n"
+"找到暫存檔 \""
+
+msgid "While opening file \""
+msgstr "在開啟檔案 \""
+
+msgid " NEWER than swap file!\n"
+msgstr " 比暫存檔更新!\n"
+
+#. Some of these messages are long to allow translation to
+#. * other languages.
+msgid ""
+"\n"
+"(1) Another program may be editing the same file.\n"
+" If this is the case, be careful not to end up with two\n"
+" different instances of the same file when making changes.\n"
+msgstr ""
+"\n"
+"(1) å¯èƒ½æœ‰å¦ä¸€å€‹ç¨‹å¼ä¹Ÿåœ¨ç·¨è¼¯åŒä¸€å€‹æª”案.\n"
+" 如果是這樣,請å°å¿ƒä¸è¦å…©é‚Šä¸€èµ·å¯«å…¥ï¼Œä¸ç„¶ä½ çš„努力都會負諸æµæ°´ã€‚\n"
+
+msgid " Quit, or continue with caution.\n"
+msgstr " 離開,或是繼續編輯。\n"
+
+msgid ""
+"\n"
+"(2) An edit session for this file crashed.\n"
+msgstr ""
+"\n"
+"(2) å‰æ¬¡ç·¨è¼¯æ­¤æª”時當機\n"
+
+msgid " If this is the case, use \":recover\" or \"vim -r "
+msgstr " 如果是這樣, 請用 \":recover\" 或 \"vim -r"
+
+msgid ""
+"\"\n"
+" to recover the changes (see \":help recovery\").\n"
+msgstr ""
+"\"\n"
+" 來救回修改資料 (詳細說明請看 \":help recovery\").\n"
+
+msgid " If you did this already, delete the swap file \""
+msgstr " 如果該救的都已經救了, 請直接刪除此暫存檔 \""
+
+msgid ""
+"\"\n"
+" to avoid this message.\n"
+msgstr ""
+"\"\n"
+" 以é¿å…å†çœ‹åˆ°æ­¤è¨Šæ¯.\n"
+
+msgid "Swap file \""
+msgstr "暫存檔 \""
+
+msgid "\" already exists!"
+msgstr "\" 已經存在了!"
+
+msgid "VIM - ATTENTION"
+msgstr "VIM - 注æ„"
+
+msgid "Swap file already exists!"
+msgstr "暫存檔已經存在!"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"以唯讀方å¼é–‹å•Ÿ(&O)\n"
+"直接編輯(&E)\n"
+"修復(&R)\n"
+"離開(&Q)\n"
+"跳出(&A)"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Quit\n"
+"&Abort\n"
+"&Delete it"
+msgstr ""
+"以唯讀方å¼é–‹å•Ÿ(&O)\n"
+"直接編輯(&E)\n"
+"修復(&R)\n"
+"離開(&Q)\n"
+"跳出(&A)\n"
+"刪除暫存檔(&D)"
+
+msgid "E326: Too many swap files found"
+msgstr "E326: 找到太多暫存檔"
+
+msgid "E327: Part of menu-item path is not sub-menu"
+msgstr "E327: 部份é¸é …路徑ä¸æ˜¯å­é¸å–®"
+
+msgid "E328: Menu only exists in another mode"
+msgstr "E328: é¸å–®åªèƒ½åœ¨å…¶å®ƒæ¨¡å¼ä¸­ä½¿ç”¨"
+
+msgid "E329: No menu of that name"
+msgstr "E329: 沒有那樣的é¸å–®"
+
+msgid "E330: Menu path must not lead to a sub-menu"
+msgstr "E330: é¸å–®è·¯å¾‘ä¸èƒ½æŒ‡å‘å­é¸å–®"
+
+msgid "E331: Must not add menu items directly to menu bar"
+msgstr "E331: ä¸èƒ½ç›´æŽ¥æŠŠé¸é …加到é¸å–®åˆ—中"
+
+msgid "E332: Separator cannot be part of a menu path"
+msgstr "E332: 分隔線ä¸èƒ½æ˜¯é¸å–®è·¯å¾‘的一部份"
+
+#. Now we have found the matching menu, and we list the mappings
+#. Highlight title
+msgid ""
+"\n"
+"--- Menus ---"
+msgstr ""
+"\n"
+"--- é¸å–® ---"
+
+msgid "Tear off this menu"
+msgstr "切下此é¸å–®"
+
+msgid "E333: Menu path must lead to a menu item"
+msgstr "E333: é¸å–®è·¯å¾‘必需指å‘一個é¸é …"
+
+#, c-format
+msgid "E334: Menu not found: %s"
+msgstr "E334: [é¸å–®] 找ä¸åˆ° %s"
+
+#, c-format
+msgid "E335: Menu not defined for %s mode"
+msgstr "E335: %s 模å¼æœªå®šç¾©é¸å–®"
+
+msgid "E336: Menu path must lead to a sub-menu"
+msgstr "E336: é¸å–®è·¯å¾‘必需指å‘å­é¸å–®"
+
+msgid "E337: Menu not found - check menu names"
+msgstr "E337: 找ä¸åˆ°é¸å–® - 請檢查é¸å–®å稱"
+
+#, c-format
+msgid "Error detected while processing %s:"
+msgstr "è™•ç† %s 時發生錯誤:"
+
+#, c-format
+msgid "line %4ld:"
+msgstr "行 %4ld:"
+
+msgid "[string too long]"
+msgstr "[此行éŽé•·]"
+
+msgid "Messages maintainer: Bram Moolenaar <Bram@vim.org>"
+msgstr ""
+"正體中文訊æ¯ç¶­è­·è€…: Francis S.Lin <piaip@csie.ntu.edu."
+"tw>, Cecil Sheng <b7506022@csie.ntu.edu.tw>"
+
+msgid "Interrupt: "
+msgstr "已中斷: "
+
+msgid "Hit ENTER to continue"
+msgstr "請按 ENTER 繼續"
+
+msgid "Hit ENTER or type command to continue"
+msgstr "請按 ENTER 或其它命令以繼續"
+
+msgid "-- More --"
+msgstr "-- 尚有 --"
+
+msgid " (RET/BS: line, SPACE/b: page, d/u: half page, q: quit)"
+msgstr " (RET/BS: å‘下/å‘上一行, 空白éµ/b: 一é , d/u: åŠé , q: 離開)"
+
+msgid " (RET: line, SPACE: page, d: half page, q: quit)"
+msgstr " (RET: å‘下一行, 空白éµ: 一é , d: åŠé , q: 離開)"
+
+msgid "Question"
+msgstr "å•é¡Œ"
+
+msgid ""
+"&Yes\n"
+"&No"
+msgstr ""
+"&Y是\n"
+"&Nå¦"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"Save &All\n"
+"&Discard All\n"
+"&Cancel"
+msgstr ""
+"&Y是\n"
+"&Nå¦\n"
+"&A全部存檔\n"
+"&D全部ä¸å­˜\n"
+"&Cå–消"
+
+msgid "Save File dialog"
+msgstr "存檔"
+
+msgid "Open File dialog"
+msgstr "開檔"
+
+#. TODO: non-GUI file selector here
+msgid "E338: Sorry, no file browser in console mode"
+msgstr "E338: 主控å°(Console)模å¼æ™‚沒有檔案ç€è¦½å™¨(file browser)"
+
+msgid "W10: Warning: Changing a readonly file"
+msgstr "W10: 注æ„: 你正在修改一個唯讀檔"
+
+msgid "1 more line"
+msgstr "還有一行 "
+
+msgid "1 line less"
+msgstr "少於一行 "
+
+#, c-format
+msgid "%ld more lines"
+msgstr "多了 %ld 行 "
+
+#, c-format
+msgid "%ld fewer lines"
+msgstr "少了 %ld 行 "
+
+msgid " (Interrupted)"
+msgstr " (已中斷)"
+
+msgid "Vim: preserving files...\n"
+msgstr "Vim: ä¿ç•™æª”案中...\n"
+
+#. close all memfiles, without deleting
+msgid "Vim: Finished.\n"
+msgstr "Vim: çµæŸ.\n"
+
+#, c-format
+msgid "ERROR: "
+msgstr "錯誤: "
+
+#, c-format
+msgid ""
+"\n"
+"[bytes] total alloc-freed %lu-%lu, in use %lu, peak use %lu\n"
+msgstr ""
+"\n"
+"[bytes] 全部 alloc-freed %lu-%lu, 使用中 %lu, peak 使用 %lu\n"
+
+#, c-format
+msgid ""
+"[calls] total re/malloc()'s %lu, total free()'s %lu\n"
+"\n"
+msgstr ""
+"[呼å«] 全部 re/malloc(): %lu, 全部 free()': %lu\n"
+"\n"
+
+msgid "E340: Line is becoming too long"
+msgstr "E340: 此行éŽé•·"
+
+#, c-format
+msgid "E341: Internal error: lalloc(%ld, )"
+msgstr "E341: 內部錯誤: lalloc(%ld, )"
+
+#, c-format
+msgid "E342: Out of memory! (allocating %lu bytes)"
+msgstr "E342: 記憶體ä¸è¶³! (嘗試é…ç½® %lu ä½å…ƒçµ„)"
+
+#, c-format
+msgid "Calling shell to execute: \"%s\""
+msgstr "å‘¼å« shell 執行: \"%s\""
+
+msgid "E545: Missing colon"
+msgstr "E545: 缺少 colon"
+
+msgid "E546: Illegal mode"
+msgstr "E546: ä¸æ­£ç¢ºçš„模å¼"
+
+msgid "E547: Illegal mouseshape"
+msgstr "E547: ä¸æ­£ç¢ºçš„滑鼠形狀"
+
+msgid "E548: digit expected"
+msgstr "E548: 應該è¦æœ‰æ•¸å­—"
+
+msgid "E549: Illegal percentage"
+msgstr "E549: ä¸æ­£ç¢ºçš„百分比"
+
+msgid "Enter encryption key: "
+msgstr "輸入密碼: "
+
+msgid "Enter same key again: "
+msgstr "è«‹å†è¼¸å…¥ä¸€æ¬¡: "
+
+msgid "Keys don't match!"
+msgstr "兩次輸入密碼ä¸ç›¸åŒ!"
+
+#, c-format
+msgid ""
+"E343: Invalid path: '**[number]' must be at the end of the path or be "
+"followed by '%s'."
+msgstr "E343: ä¸æ­£ç¢ºçš„路徑: '**[number]' 必需è¦åœ¨è·¯å¾‘çµå°¾æˆ–è¦æŽ¥è‘— '%s'"
+
+#, c-format
+msgid "E344: Can't find directory \"%s\" in cdpath"
+msgstr "E344: cdpath 中沒有目錄 \"%s\""
+
+#, c-format
+msgid "E345: Can't find file \"%s\" in path"
+msgstr "E345: 在路徑中找ä¸åˆ°æª”案 \"%s\""
+
+#, c-format
+msgid "E346: No more directory \"%s\" found in cdpath"
+msgstr "E346: 在路徑中找ä¸åˆ°æ›´å¤šçš„檔案 \"%s\""
+
+#, c-format
+msgid "E347: No more file \"%s\" found in path"
+msgstr "E347: 在路徑中找ä¸åˆ°æ›´å¤šçš„檔案 \"%s\""
+
+msgid "E550: Missing colon"
+msgstr "E550: 缺少 colon"
+
+msgid "E551: Illegal component"
+msgstr "E551: ä¸æ­£ç¢ºçš„模å¼"
+
+msgid "E552: digit expected"
+msgstr "E552: 應該è¦æœ‰æ•¸å­—"
+
+#. Get here when the server can't be found.
+msgid "Cannot connect to Netbeans #2"
+msgstr "無法連接到 Netbeans #2"
+
+msgid "Cannot connect to Netbeans"
+msgstr "無法連接到 Netbeans"
+
+#, c-format
+msgid "E668: Wrong access mode for NetBeans connection info file: \"%s\""
+msgstr "E668: NetBeans 連線資訊檔案: \"%s\" å­˜å–模å¼ä¸æ­£ç¢º"
+
+msgid "read from Netbeans socket"
+msgstr "ç”± Netbeans socket 讀å–"
+
+#, c-format
+msgid "E658: NetBeans connection lost for buffer %ld"
+msgstr "E658: ç·©è¡å€ %ld 與 NetBeans 的連線已中斷"
+
+msgid "Warning: terminal cannot highlight"
+msgstr "注æ„: 你的終端機無法顯示高亮度"
+
+msgid "E348: No string under cursor"
+msgstr "E348: 游標處沒有字串"
+
+msgid "E349: No identifier under cursor"
+msgstr "E349: 游標處沒有識別字"
+
+msgid "E352: Cannot erase folds with current 'foldmethod'"
+msgstr "E352: 無法在目å‰çš„ 'foldmethod' 下刪除 fold"
+
+msgid "E664: changelist is empty"
+msgstr "E664: 變更列表是空的"
+
+msgid "E662: At start of changelist"
+msgstr "E662: 已在變更列表的開頭"
+
+msgid "E663: At end of changelist"
+msgstr "E663: 已在變更列表的çµå°¾"
+
+msgid "Type :quit<Enter> to exit Vim"
+msgstr "è¦é›¢é–‹ Vim 請輸入 :quit<Enter> "
+
+#, c-format
+msgid "1 line %sed 1 time"
+msgstr "一行 %s éŽ ä¸€æ¬¡"
+
+#, c-format
+msgid "1 line %sed %d times"
+msgstr "一行 %s éŽ %d 次"
+
+#, c-format
+msgid "%ld lines %sed 1 time"
+msgstr "%ld è¡Œ %s éŽ ä¸€æ¬¡"
+
+#, c-format
+msgid "%ld lines %sed %d times"
+msgstr "%ld è¡Œ %s éŽ %d 次"
+
+#, c-format
+msgid "%ld lines to indent... "
+msgstr "縮排 %ld 行... "
+
+msgid "1 line indented "
+msgstr "一行已縮排"
+
+#, c-format
+msgid "%ld lines indented "
+msgstr "已縮排 %ld 行 "
+
+#. must display the prompt
+msgid "cannot yank; delete anyway"
+msgstr "無法剪下; 直接刪除"
+
+msgid "1 line changed"
+msgstr " 1 行 ~ed"
+
+#, c-format
+msgid "%ld lines changed"
+msgstr "已改變 %ld 行 "
+
+#, c-format
+msgid "freeing %ld lines"
+msgstr "釋放 %ld 行中 "
+
+msgid "1 line yanked"
+msgstr "已複製 1 行 "
+
+#, c-format
+msgid "%ld lines yanked"
+msgstr "已複製 %ld 行 "
+
+#, c-format
+msgid "E353: Nothing in register %s"
+msgstr "E353: 暫存器 %s 裡沒有æ±è¥¿"
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Registers ---"
+msgstr ""
+"\n"
+"--- 暫存器 ---"
+
+msgid "Illegal register name"
+msgstr "ä¸æ­£ç¢ºçš„暫存器å稱"
+
+#, c-format
+msgid ""
+"\n"
+"# Registers:\n"
+msgstr ""
+"\n"
+"# 暫存器:\n"
+
+#, c-format
+msgid "E574: Unknown register type %d"
+msgstr "E574: 未知的註冊型態: %d"
+
+#, c-format
+msgid "E354: Invalid register name: '%s'"
+msgstr "E354: 暫存器å稱錯誤: '%s'"
+
+#, c-format
+msgid "%ld Cols; "
+msgstr "%ld 欄; "
+
+#, c-format
+msgid "Selected %s%ld of %ld Lines; %ld of %ld Words; %ld of %ld Bytes"
+msgstr "é¸æ“‡äº† %s%ld/%ld è¡Œ; %ld/%ld å­—(Word); %ld/%ld å­—å…ƒ(Bytes)"
+
+#, c-format
+msgid "Col %s of %s; Line %ld of %ld; Word %ld of %ld; Byte %ld of %ld"
+msgstr "欄 %s/%s; 行 %ld/%ld; 字(Word) %ld/%ld; 字元(Byte) %ld/%ld"
+
+#, c-format
+msgid "(+%ld for BOM)"
+msgstr "(+%ld for BOM)"
+
+msgid "%<%f%h%m%=Page %N"
+msgstr "%<%f%h%m%=第 %N é "
+
+# ? what's this for?
+msgid "Thanks for flying Vim"
+msgstr "æ„Ÿè¬æ‚¨æ„›ç”¨ Vim"
+
+msgid "E518: Unknown option"
+msgstr "E518: ä¸æ­£ç¢ºçš„é¸é …"
+
+msgid "E519: Option not supported"
+msgstr "E519: ä¸æ”¯æ´è©²é¸é …"
+
+msgid "E520: Not allowed in a modeline"
+msgstr "E520: ä¸èƒ½åœ¨ Modeline 裡出ç¾"
+
+msgid ""
+"\n"
+"\tLast set from "
+msgstr ""
+"\n"
+"\t上次設定: "
+
+msgid "E521: Number required after ="
+msgstr "E521: = 後需è¦æœ‰æ•¸å­—"
+
+msgid "E522: Not found in termcap"
+msgstr "E522: Termcap 裡é¢æ‰¾ä¸åˆ°"
+
+#, c-format
+msgid "E539: Illegal character <%s>"
+msgstr "E539: ä¸æ­£ç¢ºçš„å­—å…ƒ <%s>"
+
+msgid "E529: Cannot set 'term' to empty string"
+msgstr "E529: 無法設定 'term' 為空字串"
+
+msgid "E530: Cannot change term in GUI"
+msgstr "E530: 在圖型界é¢ä¸­ç„¡æ³•åˆ‡æ› term"
+
+msgid "E531: Use \":gui\" to start the GUI"
+msgstr "E531: 輸入 \":gui\" 來啟動圖形界é¢"
+
+msgid "E589: 'backupext' and 'patchmode' are equal"
+msgstr "E589: 'backupext' 跟 'patchmode' 是一樣的"
+
+msgid "E617: Cannot be changed in the GTK+ 2 GUI"
+msgstr "E617: 在圖型界é¢ä¸­ç„¡æ³•åˆ‡æ› term"
+
+msgid "E524: Missing colon"
+msgstr "E524: 缺少 colon"
+
+msgid "E525: Zero length string"
+msgstr "E525: 零長度字串"
+
+#, c-format
+msgid "E526: Missing number after <%s>"
+msgstr "E526: <%s> 後缺少數字"
+
+msgid "E527: Missing comma"
+msgstr "E527: 缺少逗號"
+
+msgid "E528: Must specify a ' value"
+msgstr "E528: 必需指定一個 ' 值"
+
+msgid "E595: contains unprintable or wide character"
+msgstr "E595: å…§å«ç„¡æ³•é¡¯ç¤ºçš„å­—å…ƒ"
+
+msgid "E596: Invalid font(s)"
+msgstr "E596: ä¸æ­£ç¢ºçš„å­—åž‹"
+
+msgid "E597: can't select fontset"
+msgstr "E597: 無法使用字型集(Fontset)"
+
+msgid "E598: Invalid fontset"
+msgstr "E598: ä¸æ­£ç¢ºçš„字型集(Fontset)"
+
+msgid "E533: can't select wide font"
+msgstr "E533: 無法使用設定的中文字型(Widefont)"
+
+msgid "E534: Invalid wide font"
+msgstr "E534: ä¸æ­£ç¢ºçš„å­—åž‹(Widefont)"
+
+#, c-format
+msgid "E535: Illegal character after <%c>"
+msgstr "E535: <%c> 後有ä¸æ­£ç¢ºçš„å­—å…ƒ"
+
+msgid "E536: comma required"
+msgstr "E536: 需è¦é€—號"
+
+#, c-format
+msgid "E537: 'commentstring' must be empty or contain %s"
+msgstr "E537: 'commentstring' å¿…éœ€æ˜¯ç©ºç™½æˆ–åŒ…å« %s"
+
+msgid "E538: No mouse support"
+msgstr "E538: ä¸æ”¯æ´æ»‘é¼ "
+
+msgid "E540: Unclosed expression sequence"
+msgstr "E540: 沒有çµæŸçš„é‹ç®—å¼: "
+
+msgid "E541: too many items"
+msgstr "E541: 太多項目"
+
+msgid "E542: unbalanced groups"
+msgstr "E542: ä¸å°ç¨±çš„ group"
+
+msgid "E590: A preview window already exists"
+msgstr "E590: é è¦–的視窗已經存在了"
+
+msgid "W17: Arabic requires UTF-8, do ':set encoding=utf-8'"
+msgstr "W17: Arabic éœ€è¦ UTF-8, 請執行 ':set encoding=utf-8'"
+
+#, c-format
+msgid "E593: Need at least %d lines"
+msgstr "E593: è‡³å°‘éœ€è¦ %d è¡Œ "
+
+#, c-format
+msgid "E594: Need at least %d columns"
+msgstr "E594: è‡³å°‘éœ€è¦ %d 欄"
+
+#, c-format
+msgid "E355: Unknown option: %s"
+msgstr "E355: ä¸æ­£ç¢ºçš„é¸é …: %s"
+
+msgid ""
+"\n"
+"--- Terminal codes ---"
+msgstr ""
+"\n"
+"--- 終端機碼 ---"
+
+msgid ""
+"\n"
+"--- Global option values ---"
+msgstr ""
+"\n"
+"--- Global é¸é …值 ---"
+
+msgid ""
+"\n"
+"--- Local option values ---"
+msgstr ""
+"\n"
+"--- Local é¸é …值 ---"
+
+msgid ""
+"\n"
+"--- Options ---"
+msgstr ""
+"\n"
+"--- é¸é … ---"
+
+msgid "E356: get_varp ERROR"
+msgstr "E356: get_varp 錯誤"
+
+#, c-format
+msgid "E357: 'langmap': Matching character missing for %s"
+msgstr "E357: 'langmap': 找ä¸åˆ° %s å°æ‡‰çš„å­—å…ƒ"
+
+#, c-format
+msgid "E358: 'langmap': Extra characters after semicolon: %s"
+msgstr "E358: 'langmap': 分號後有多餘的字元: %s"
+
+msgid "cannot open "
+msgstr "ä¸èƒ½é–‹å•Ÿ"
+
+msgid "VIM: Can't open window!\n"
+msgstr "VIM: 無法開啟視窗!\n"
+
+msgid "Need Amigados version 2.04 or later\n"
+msgstr "éœ€è¦ Amigados 版本 2.04 以上\n"
+
+#, c-format
+msgid "Need %s version %ld\n"
+msgstr "éœ€è¦ %s 版本 %ld\n"
+
+msgid "Cannot open NIL:\n"
+msgstr "無法開啟 NIL:\n"
+
+msgid "Cannot create "
+msgstr "ä¸èƒ½å»ºç«‹ "
+
+#, c-format
+msgid "Vim exiting with %d\n"
+msgstr "Vim çµæŸå‚³å›žå€¼: %d\n"
+
+msgid "cannot change console mode ?!\n"
+msgstr "無法切æ›ä¸»æŽ§å°(console)æ¨¡å¼ !?\n"
+
+msgid "mch_get_shellsize: not a console??\n"
+msgstr "mch_get_shellsize: ä¸æ˜¯ä¸»æŽ§å°(console)??\n"
+
+#. if Vim opened a window: Executing a shell may cause crashes
+msgid "E360: Cannot execute shell with -f option"
+msgstr "E360: ä¸èƒ½ç”¨ -f é¸é …執行 shell"
+
+msgid "Cannot execute "
+msgstr "ä¸èƒ½åŸ·è¡Œ "
+
+msgid "shell "
+msgstr "shell "
+
+msgid " returned\n"
+msgstr " 已返回\n"
+
+msgid "ANCHOR_BUF_SIZE too small."
+msgstr "ANCHOR_BUF_SIZE 太å°"
+
+msgid "I/O ERROR"
+msgstr "I/O 錯誤"
+
+msgid "...(truncated)"
+msgstr "...(已切掉)"
+
+msgid "'columns' is not 80, cannot execute external commands"
+msgstr "'columns' ä¸æ˜¯ 80, 無法執行外部命令"
+
+msgid "E237: Printer selection failed"
+msgstr "E237: 無法é¸æ“‡æ­¤å°è¡¨æ©Ÿ"
+
+#, c-format
+msgid "to %s on %s"
+msgstr "到 %s on %s"
+
+#, c-format
+msgid "E613: Unknown printer font: %s"
+msgstr "E613: ä¸æ­£ç¢ºçš„å°è¡¨æ©Ÿå­—åž‹: %s"
+
+#, c-format
+msgid "E238: Print error: %s"
+msgstr "E238: 列å°éŒ¯èª¤: %s"
+
+msgid "Unknown"
+msgstr "未知"
+
+#, c-format
+msgid "Printing '%s'"
+msgstr "列å°ä¸­: '%s'"
+
+#, c-format
+msgid "E244: Illegal charset name \"%s\" in font name \"%s\""
+msgstr "E244: 字元集 \"%s\" 無法å°æ‡‰å­—åž‹\"%s\""
+
+#, c-format
+msgid "E245: Illegal char '%c' in font name \"%s\""
+msgstr "E245: ä¸æ­£ç¢ºçš„å­—å…ƒ '%c' 出ç¾åœ¨å­—åž‹å稱 \"%s\" å…§"
+
+msgid "Vim: Double signal, exiting\n"
+msgstr "Vim: é›™é‡signal, 離開中\n"
+
+#, c-format
+msgid "Vim: Caught deadly signal %s\n"
+msgstr "Vim: CVim: 攔截到信號(signal) %s\n"
+
+#, c-format
+msgid "Vim: Caught deadly signal\n"
+msgstr "Vim: 攔截到致命的信號(deadly signale)\n"
+
+#, c-format
+msgid "Opening the X display took %ld msec"
+msgstr "開啟 X Window 耗時 %ld msec"
+
+msgid ""
+"\n"
+"Vim: Got X error\n"
+msgstr ""
+"\n"
+"Vim: X 錯誤\n"
+
+msgid "Testing the X display failed"
+msgstr "測試 X Window 失敗"
+
+msgid "Opening the X display timed out"
+msgstr "開啟 X Window 逾時"
+
+msgid ""
+"\n"
+"Cannot execute shell "
+msgstr ""
+"\n"
+"ä¸èƒ½åŸ·è¡Œ shell"
+
+msgid ""
+"\n"
+"Cannot execute shell sh\n"
+msgstr ""
+"\n"
+"ä¸èƒ½åŸ·è¡Œ shell sh\n"
+
+msgid ""
+"\n"
+"shell returned "
+msgstr ""
+"\n"
+"Shell 已返回"
+
+msgid ""
+"\n"
+"Cannot create pipes\n"
+msgstr ""
+"\n"
+"ä¸èƒ½å»ºç«‹ pipe 管線\n"
+
+msgid ""
+"\n"
+"Cannot fork\n"
+msgstr ""
+"\n"
+"ä¸èƒ½ fork\n"
+
+msgid ""
+"\n"
+"Command terminated\n"
+msgstr ""
+"\n"
+"命令已終çµ\n"
+
+msgid "XSMP lost ICE connection"
+msgstr "XSMP 失去 ICE 連線"
+
+msgid "Opening the X display failed"
+msgstr "開啟 X Window 失敗"
+
+msgid "XSMP handling save-yourself request"
+msgstr "XSMP 正在處ç†è‡ªæˆ‘儲存è¦æ±‚"
+
+msgid "XSMP opening connection"
+msgstr "開啟 XSMP 連線中"
+
+msgid "XSMP ICE connection watch failed"
+msgstr "XSMP ICE 連線監看失敗"
+
+#, c-format
+msgid "XSMP SmcOpenConnection failed: %s"
+msgstr "XSMP SmcOpenConnection 失敗: %s"
+
+msgid "At line"
+msgstr "在行號 "
+
+msgid "Could not allocate memory for command line."
+msgstr "無法為命令列é…置記憶體。"
+
+msgid "VIM Error"
+msgstr "VIM 錯誤"
+
+msgid "Could not load vim32.dll!"
+msgstr "無法載入 vim32.dllï¼"
+
+msgid "Could not fix up function pointers to the DLL!"
+msgstr "ä¸èƒ½ä¿®æ­£å‡½å¼æŒ‡æ¨™åˆ° DLL!"
+
+#, c-format
+msgid "shell returned %d"
+msgstr "Shell 傳回值 %d"
+
+#, c-format
+msgid "Vim: Caught %s event\n"
+msgstr "Vim: 攔截到 %s \n"
+
+msgid "close"
+msgstr "關閉"
+
+msgid "logoff"
+msgstr "登出"
+
+msgid "shutdown"
+msgstr "關機"
+
+msgid "E371: Command not found"
+msgstr "E371: 找ä¸åˆ°å‘½ä»¤"
+
+msgid ""
+"VIMRUN.EXE not found in your $PATH.\n"
+"External commands will not pause after completion.\n"
+"See :help win32-vimrun for more information."
+msgstr ""
+"在你的 $PATH 中找ä¸åˆ° VIMRUN.EXE.\n"
+"外部命令執行完畢後將ä¸æœƒæš«åœ.\n"
+"進一步說明請執行 :help win32-vimrun "
+
+msgid "Vim Warning"
+msgstr "Vim 警告"
+
+#, c-format
+msgid "E372: Too many %%%c in format string"
+msgstr "E372: æ ¼å¼åŒ–字串裡有太多 %%%c "
+
+#, c-format
+msgid "E373: Unexpected %%%c in format string"
+msgstr "E373: æ ¼å¼åŒ–字串ä¸æ‡‰è©²å‡ºç¾ %%%c "
+
+msgid "E374: Missing ] in format string"
+msgstr "E374: æ ¼å¼åŒ–字串裡少了 ]"
+
+#, c-format
+msgid "E375: Unsupported %%%c in format string"
+msgstr "E375: æ ¼å¼åŒ–字串裡有ä¸æ”¯æ´çš„ %%%c "
+
+#, c-format
+msgid "E376: Invalid %%%c in format string prefix"
+msgstr "E376: æ ¼å¼åŒ–字串開頭裡有ä¸æ­£ç¢ºçš„ %%%c "
+
+#, c-format
+msgid "E377: Invalid %%%c in format string"
+msgstr "E377: æ ¼å¼åŒ–字串裡有ä¸æ­£ç¢ºçš„ %%%c "
+
+msgid "E378: 'errorformat' contains no pattern"
+msgstr "E378: 'errorformat' 未設定"
+
+msgid "E379: Missing or empty directory name"
+msgstr "E379: 找ä¸åˆ°ç›®éŒ„å稱或是空的目錄å稱"
+
+msgid "E553: No more items"
+msgstr "E553: 沒有其它項目"
+
+#, c-format
+msgid "(%d of %d)%s%s: "
+msgstr "(%d / %d)%s%s: "
+
+msgid " (line deleted)"
+msgstr " (行已刪除)"
+
+msgid "E380: At bottom of quickfix stack"
+msgstr "E380: Quickfix 堆疊çµå°¾"
+
+msgid "E381: At top of quickfix stack"
+msgstr "E381: Quickfix 堆疊頂端"
+
+#, c-format
+msgid "error list %d of %d; %d errors"
+msgstr "錯誤列表 %d/%d; 共有 %d 項錯誤"
+
+msgid "E382: Cannot write, 'buftype' option is set"
+msgstr "E382: 無法寫入,'buftype' é¸é …已設定"
+
+#, c-format
+msgid "E369: invalid item in %s%%[]"
+msgstr "E369: ä¸æ­£ç¢ºçš„項目: %s%%[]"
+
+msgid "E339: Pattern too long"
+msgstr "E339: å字太長"
+
+msgid "E50: Too many \\z("
+msgstr "E50: 太多 \\z("
+
+#, c-format
+msgid "E51: Too many %s("
+msgstr "E51: 太多 %s("
+
+msgid "E52: Unmatched \\z("
+msgstr "E52: ç„¡å°æ‡‰çš„ \\z("
+
+#, c-format
+msgid "E53: Unmatched %s%%("
+msgstr "E53: ç„¡å°æ‡‰çš„ %s%%("
+
+#, c-format
+msgid "E54: Unmatched %s("
+msgstr "E54: ç„¡å°æ‡‰çš„ %s("
+
+#, c-format
+msgid "E55: Unmatched %s)"
+msgstr "E55: ç„¡å°æ‡‰çš„ %s)"
+
+#, c-format
+msgid "E56: %s* operand could be empty"
+msgstr "E56: %s* é‹ç®—å…ƒå¯ä»¥æ˜¯ç©ºçš„"
+
+#, c-format
+msgid "E57: %s+ operand could be empty"
+msgstr "E57: %s+ é‹ç®—å…ƒå¯ä»¥æ˜¯ç©ºçš„"
+
+#, c-format
+msgid "E59: invalid character after %s@"
+msgstr "E59: 後é¢æœ‰ä¸æ­£ç¢ºçš„å­—å…ƒ: %s@"
+
+#, c-format
+msgid "E58: %s{ operand could be empty"
+msgstr "E58: %s{ é‹ç®—å…ƒå¯ä»¥æ˜¯ç©ºçš„"
+
+#, c-format
+msgid "E60: Too many complex %s{...}s"
+msgstr "E60: 太多複雜的 %s{...}s"
+
+#, c-format
+msgid "E61: Nested %s*"
+msgstr "E61: 巢狀 %s*"
+
+#, c-format
+msgid "E62: Nested %s%c"
+msgstr "E62: 巢狀 %s%c"
+
+msgid "E63: invalid use of \\_"
+msgstr "E63: ä¸æ­£ç¢ºçš„使用 \\_"
+
+#, c-format
+msgid "E64: %s%c follows nothing"
+msgstr "E64: %s%c 沒有接æ±è¥¿"
+
+msgid "E65: Illegal back reference"
+msgstr "E65: ä¸æ­£ç¢ºçš„åå‘åƒè€ƒ"
+
+msgid "E66: \\z( not allowed here"
+msgstr "E66: \\z( ä¸èƒ½åœ¨æ­¤å‡ºç¾"
+
+msgid "E67: \\z1 - \\z9 not allowed here"
+msgstr "E67: \\z1 - \\z9 ä¸èƒ½åœ¨æ­¤å‡ºç¾"
+
+msgid "E68: Invalid character after \\z"
+msgstr "E68: 後é¢æœ‰ä¸æ­£ç¢ºçš„å­—å…ƒ: \\z"
+
+#, c-format
+msgid "E69: Missing ] after %s%%["
+msgstr "E69: %s%%[ 後缺少 ]"
+
+#, c-format
+msgid "E70: Empty %s%%[]"
+msgstr "E70: 空的 %s%%[]"
+
+#, c-format
+msgid "E71: Invalid character after %s%%"
+msgstr "E71: 後é¢æœ‰ä¸æ­£ç¢ºçš„å­—å…ƒ: %s%%"
+
+#, c-format
+msgid "E554: Syntax error in %s{...}"
+msgstr "E554: 語法錯誤: %s{...}"
+
+msgid "E361: Crash intercepted; regexp too complex?"
+msgstr "E361: 無法執行; regular expression 太複雜?"
+
+msgid "E363: pattern caused out-of-stack error"
+msgstr "E363: regular expression 造æˆå †ç–Šç”¨å…‰çš„錯誤"
+
+msgid "External submatches:\n"
+msgstr "外部符åˆ:\n"
+
+#, c-format
+msgid "+--%3ld lines folded "
+msgstr "+--已 fold %3ld 行 "
+
+msgid " VREPLACE"
+msgstr " V-å–代"
+
+msgid " REPLACE"
+msgstr " å–代"
+
+msgid " REVERSE"
+msgstr " å轉"
+
+msgid " INSERT"
+msgstr " æ’å…¥"
+
+msgid " (insert)"
+msgstr " (æ’å…¥)"
+
+msgid " (replace)"
+msgstr " (å–代)"
+
+msgid " (vreplace)"
+msgstr " (v-å–代)"
+
+msgid " Hebrew"
+msgstr " Hebrew"
+
+msgid " Arabic"
+msgstr " Arabic"
+
+msgid " (lang)"
+msgstr " (語言)"
+
+msgid " (paste)"
+msgstr " (貼上)"
+
+msgid " VISUAL"
+msgstr " é¸å–"
+
+msgid " VISUAL LINE"
+msgstr " [行] "
+
+msgid " VISUAL BLOCK"
+msgstr " [å€å¡Š] "
+
+msgid " SELECT"
+msgstr " é¸å–"
+
+msgid " SELECT LINE"
+msgstr " é¸å–è¡Œ "
+
+msgid " SELECT BLOCK"
+msgstr " é¸å–å€å¡Š"
+
+msgid "recording"
+msgstr "記錄中"
+
+msgid "search hit TOP, continuing at BOTTOM"
+msgstr "å·²æœå°‹åˆ°æª”案開頭;å†å¾žçµå°¾ç¹¼çºŒæœå°‹"
+
+msgid "search hit BOTTOM, continuing at TOP"
+msgstr "å·²æœå°‹åˆ°æª”案çµå°¾ï¼›å†å¾žé–‹é ­ç¹¼çºŒæœå°‹"
+
+#, c-format
+msgid "E383: Invalid search string: %s"
+msgstr "E383: 錯誤的æœå°‹å­—串: %s"
+
+#, c-format
+msgid "E384: search hit TOP without match for: %s"
+msgstr "E384: å·²æœå°‹åˆ°æª”案開頭ä»æ‰¾ä¸åˆ° %s"
+
+#, c-format
+msgid "E385: search hit BOTTOM without match for: %s"
+msgstr "E385: å·²æœå°‹åˆ°æª”案çµå°¾ä»æ‰¾ä¸åˆ° %s"
+
+msgid "E386: Expected '?' or '/' after ';'"
+msgstr "E386: 在 ';' 後é¢æ‡‰è©²æœ‰ '?' 或 '/'"
+
+msgid " (includes previously listed match)"
+msgstr " (包括å‰æ¬¡åˆ—出符åˆé …)"
+
+#. cursor at status line
+msgid "--- Included files "
+msgstr "--- 引入檔案 "
+
+msgid "not found "
+msgstr "找ä¸åˆ° "
+
+msgid "in path ---\n"
+msgstr "---\n"
+
+msgid " (Already listed)"
+msgstr " (已列出)"
+
+msgid " NOT FOUND"
+msgstr " 找ä¸åˆ°"
+
+#, c-format
+msgid "Scanning included file: %s"
+msgstr "æœå°‹å¼•å…¥æª”案: %s"
+
+msgid "E387: Match is on current line"
+msgstr "E387: ç›®å‰æ‰€åœ¨è¡Œä¸­æœ‰ä¸€åŒ¹é…"
+
+msgid "All included files were found"
+msgstr "所有引入檔案都已找到"
+
+msgid "No included files"
+msgstr "沒有引入檔案"
+
+msgid "E388: Couldn't find definition"
+msgstr "E388: 找ä¸åˆ°å®šç¾©"
+
+msgid "E389: Couldn't find pattern"
+msgstr "E389: 找ä¸åˆ° pattern"
+
+#, c-format
+msgid "E390: Illegal argument: %s"
+msgstr "E390: åƒæ•¸ä¸æ­£ç¢º: %s"
+
+#, c-format
+msgid "E391: No such syntax cluster: %s"
+msgstr "E391: ç„¡æ­¤ syntax cluster: \"%s\""
+
+msgid "No Syntax items defined for this buffer"
+msgstr "這個緩è¡å€æ²’有定義任何語法"
+
+msgid "syncing on C-style comments"
+msgstr "C語言å¼è¨»è§£åŒæ­¥åŒ–中"
+
+msgid "no syncing"
+msgstr "沒有åŒæ­¥åŒ–"
+
+msgid "syncing starts "
+msgstr "åŒæ­¥åŒ–開始"
+
+msgid " lines before top line"
+msgstr "行號超出範åœ"
+
+msgid ""
+"\n"
+"--- Syntax sync items ---"
+msgstr ""
+"\n"
+"--- 語法åŒæ­¥ç‰©ä»¶ (Syntax sync items) ---"
+
+msgid ""
+"\n"
+"syncing on items"
+msgstr ""
+"\n"
+"åŒæ­¥åŒ–中:"
+
+msgid ""
+"\n"
+"--- Syntax items ---"
+msgstr ""
+"\n"
+"--- 語法項目 ---"
+
+#, c-format
+msgid "E392: No such syntax cluster: %s"
+msgstr "E392: ç„¡æ­¤ syntax cluster: \"%s\""
+
+msgid "minimal "
+msgstr "最å°"
+
+msgid "maximal "
+msgstr "最大"
+
+msgid "; match "
+msgstr "; ç¬¦åˆ "
+
+msgid " line breaks"
+msgstr "斷行 "
+
+msgid "E393: group[t]here not accepted here"
+msgstr "E393: 使用了ä¸æ­£ç¢ºçš„åƒæ•¸"
+
+#, c-format
+msgid "E394: Didn't find region item for %s"
+msgstr "E394: 找ä¸åˆ° %s çš„ region item"
+
+msgid "E395: contains argument not accepted here"
+msgstr "E395: 使用了ä¸æ­£ç¢ºçš„åƒæ•¸"
+
+msgid "E396: containedin argument not accepted here"
+msgstr "E396: 使用了ä¸æ­£ç¢ºçš„åƒæ•¸"
+
+msgid "E397: Filename required"
+msgstr "E397: 需è¦æª”案å稱"
+
+#, c-format
+msgid "E398: Missing '=': %s"
+msgstr "E398: 缺少 \"=\": %s"
+
+#, c-format
+msgid "E399: Not enough arguments: syntax region %s"
+msgstr "E399: syntax region %s 的引數太少"
+
+msgid "E400: No cluster specified"
+msgstr "E400: 沒有指定的屬性"
+
+#, c-format
+msgid "E401: Pattern delimiter not found: %s"
+msgstr "E401: 找ä¸åˆ°åˆ†éš”符號: %s"
+
+#, c-format
+msgid "E402: Garbage after pattern: %s"
+msgstr "E402: '%s' 後é¢çš„æ±è¥¿ç„¡æ³•è¾¨è­˜"
+
+msgid "E403: syntax sync: line continuations pattern specified twice"
+msgstr "E403: 語法åŒæ­¥: 連接行符號被指定了兩次"
+
+#, c-format
+msgid "E404: Illegal arguments: %s"
+msgstr "E404: åƒæ•¸ä¸æ­£ç¢º: %s"
+
+#, c-format
+msgid "E405: Missing equal sign: %s"
+msgstr "E405: 缺少相等符號: %s"
+
+#, c-format
+msgid "E406: Empty argument: %s"
+msgstr "E406: 空白åƒæ•¸: %s"
+
+#, c-format
+msgid "E407: %s not allowed here"
+msgstr "E407: %s ä¸èƒ½åœ¨æ­¤å‡ºç¾"
+
+#, c-format
+msgid "E408: %s must be first in contains list"
+msgstr "E408: %s 必須是列表裡的第一個"
+
+#, c-format
+msgid "E409: Unknown group name: %s"
+msgstr "E409: ä¸æ­£ç¢ºçš„群組å稱: %s"
+
+#, c-format
+msgid "E410: Invalid :syntax subcommand: %s"
+msgstr "E410: ä¸æ­£ç¢ºçš„ :syntax å­å‘½ä»¤: %s"
+
+#, c-format
+msgid "E411: highlight group not found: %s"
+msgstr "E411: 找ä¸åˆ° highlight group: %s"
+
+#, c-format
+msgid "E412: Not enough arguments: \":highlight link %s\""
+msgstr "E412: åƒæ•¸å¤ªå°‘: \":highlight link %s\""
+
+#, c-format
+msgid "E413: Too many arguments: \":highlight link %s\""
+msgstr "E413: åƒæ•¸éŽå¤š: \":highlight link %s\""
+
+msgid "E414: group has settings, highlight link ignored"
+msgstr "E414: 已設定群組, 忽略 highlight link"
+
+#, c-format
+msgid "E415: unexpected equal sign: %s"
+msgstr "E415: ä¸è©²æœ‰çš„等號: %s"
+
+#, c-format
+msgid "E416: missing equal sign: %s"
+msgstr "E416: 缺少相等符號: %s"
+
+#, c-format
+msgid "E417: missing argument: %s"
+msgstr "E417: 缺少åƒæ•¸: %s"
+
+#, c-format
+msgid "E418: Illegal value: %s"
+msgstr "E418: ä¸åˆæ³•çš„值: %s"
+
+msgid "E419: FG color unknown"
+msgstr "E419: 錯誤的å‰æ™¯é¡è‰²"
+
+msgid "E420: BG color unknown"
+msgstr "E420: 錯誤的背景é¡è‰²"
+
+#, c-format
+msgid "E421: Color name or number not recognized: %s"
+msgstr "E421: 錯誤的é¡è‰²å稱或數值: %s"
+
+#, c-format
+msgid "E422: terminal code too long: %s"
+msgstr "E422: 終端機碼太長: %s"
+
+#, c-format
+msgid "E423: Illegal argument: %s"
+msgstr "E423: åƒæ•¸ä¸æ­£ç¢º: %s"
+
+msgid "E424: Too many different highlighting attributes in use"
+msgstr "E424: 使用了éŽå¤šç›¸ç•°çš„高亮度屬性"
+
+msgid "E669: Unprintable character in group name"
+msgstr "E669: 群組å稱中有無法列å°çš„å­—å…ƒ"
+
+#. This is an error, but since there previously was no check only
+#. * give a warning.
+msgid "W18: Invalid character in group name"
+msgstr "W18: 群組å稱中有ä¸æ­£ç¢ºçš„å­—å…ƒ"
+
+msgid "E555: at bottom of tag stack"
+msgstr "E555: 標籤(tag)堆疊çµå°¾"
+
+msgid "E556: at top of tag stack"
+msgstr "E556: 標籤(tag)堆疊開頭"
+
+msgid "E425: Cannot go before first matching tag"
+msgstr "E425: 已經在最å‰é¢çš„標籤(tag)了"
+
+#, c-format
+msgid "E426: tag not found: %s"
+msgstr "E426: 找ä¸åˆ°æ¨™ç±¤(tag): %s"
+
+msgid " # pri kind tag"
+msgstr " # pri kind tag"
+
+msgid "file\n"
+msgstr "檔案\n"
+
+#.
+#. * Ask to select a tag from the list.
+#. * When using ":silent" assume that <CR> was entered.
+#.
+msgid "Enter nr of choice (<CR> to abort): "
+msgstr "輸入 nr 或é¸æ“‡ (<CR> 離開): "
+
+msgid "E427: There is only one matching tag"
+msgstr "E427: åªæœ‰æ­¤é …符åˆ"
+
+msgid "E428: Cannot go beyond last matching tag"
+msgstr "E428: 己經在最後一個符åˆçš„ tag 了"
+
+#, c-format
+msgid "File \"%s\" does not exist"
+msgstr "檔案 \"%s\" ä¸å­˜åœ¨"
+
+#. Give an indication of the number of matching tags
+#, c-format
+msgid "tag %d of %d%s"
+msgstr "找到 tag: %d/%d%s"
+
+msgid " or more"
+msgstr " 或更多"
+
+msgid " Using tag with different case!"
+msgstr " 以ä¸åŒå¤§å°å¯«ä¾†ä½¿ç”¨ tag!"
+
+#, c-format
+msgid "E429: File \"%s\" does not exist"
+msgstr "E429: 檔案 \"%s\" ä¸å­˜åœ¨"
+
+#. Highlight title
+msgid ""
+"\n"
+" # TO tag FROM line in file/text"
+msgstr ""
+"\n"
+" # 到 tag 從 行 在 檔案/文字"
+
+#, c-format
+msgid "Searching tags file %s"
+msgstr "æœå°‹ tag 檔案 \"%s\""
+
+#, c-format
+msgid "E430: Tag file path truncated for %s\n"
+msgstr "E430: Tag 檔案路徑被截斷為 %s\n"
+
+#, c-format
+msgid "E431: Format error in tags file \"%s\""
+msgstr "E431: Tag 檔 \"%s\" æ ¼å¼éŒ¯èª¤"
+
+#, c-format
+msgid "Before byte %ld"
+msgstr "在 %ld ä½å…ƒä¹‹å‰"
+
+#, c-format
+msgid "E432: Tags file not sorted: %s"
+msgstr "E432: Tag 檔案未排åº: %s"
+
+#. never opened any tags file
+msgid "E433: No tags file"
+msgstr "E433: 沒有 tag 檔"
+
+msgid "E434: Can't find tag pattern"
+msgstr "E434: 找ä¸åˆ° tag"
+
+msgid "E435: Couldn't find tag, just guessing!"
+msgstr "E435: 找ä¸åˆ° tag, 用猜的!"
+
+msgid "' not known. Available builtin terminals are:"
+msgstr "' 無法載入。å¯ç”¨çš„內建終端機形å¼æœ‰:"
+
+msgid "defaulting to '"
+msgstr "é è¨­: '"
+
+msgid "E557: Cannot open termcap file"
+msgstr "E557: 無法開啟 termcap 檔案"
+
+msgid "E558: Terminal entry not found in terminfo"
+msgstr "E558: terminfo 中沒有終端機資料項"
+
+msgid "E559: Terminal entry not found in termcap"
+msgstr "E559: termcap 中沒有終端機資料項"
+
+#, c-format
+msgid "E436: No \"%s\" entry in termcap"
+msgstr "E436: termcap 沒有 \"%s\" entry"
+
+msgid "E437: terminal capability \"cm\" required"
+msgstr "E437: çµ‚ç«¯æ©Ÿéœ€è¦ \"cm\" 的能力"
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Terminal keys ---"
+msgstr ""
+"\n"
+"--- çµ‚ç«¯æ©ŸæŒ‰éµ ---"
+
+msgid "new shell started\n"
+msgstr "èµ·å‹•æ–° shell\n"
+
+msgid "Vim: Error reading input, exiting...\n"
+msgstr "Vim: 讀å–輸入錯誤,離開中...\n"
+
+#. must display the prompt
+msgid "No undo possible; continue anyway"
+msgstr "無法還原;請繼續努力"
+
+msgid "E438: u_undo: line numbers wrong"
+msgstr "E438: u_undo: 行號錯誤"
+
+msgid "1 change"
+msgstr "一項改變"
+
+#, c-format
+msgid "%ld changes"
+msgstr "%ld 項改變"
+
+msgid "E439: undo list corrupt"
+msgstr "E439: 復原列表æ壞"
+
+msgid "E440: undo line missing"
+msgstr "E440: 找ä¸åˆ°è¦ undo çš„è¡Œ "
+
+#. Only MS VC 4.1 and earlier can do Win32s
+msgid ""
+"\n"
+"MS-Windows 16/32-bit GUI version"
+msgstr ""
+"\n"
+"MS-Windows 16/32 Bit 圖型界é¢ç‰ˆæœ¬"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit GUI version"
+msgstr ""
+"\n"
+"MS-Windows 32 Bit 圖型界é¢ç‰ˆæœ¬"
+
+msgid " in Win32s mode"
+msgstr "Win32s 模å¼"
+
+msgid " with OLE support"
+msgstr "æ”¯æ´ OLE"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit console version"
+msgstr ""
+"\n"
+"MS-Windows 32 Bit console 版本"
+
+msgid ""
+"\n"
+"MS-Windows 16-bit version"
+msgstr ""
+"\n"
+"MS-Windows 32 Bit console 版本"
+
+msgid ""
+"\n"
+"32-bit MS-DOS version"
+msgstr ""
+"\n"
+"32 Bit MS-DOS 版本"
+
+msgid ""
+"\n"
+"16-bit MS-DOS version"
+msgstr ""
+"\n"
+"16 Bit MS-DOS 版本"
+
+msgid ""
+"\n"
+"MacOS X (unix) version"
+msgstr ""
+"\n"
+"MacOS X (unix) 版本"
+
+msgid ""
+"\n"
+"MacOS X version"
+msgstr ""
+"\n"
+"MacOS X 版本"
+
+msgid ""
+"\n"
+"MacOS version"
+msgstr ""
+"\n"
+"MacOS 版本"
+
+msgid ""
+"\n"
+"RISC OS version"
+msgstr ""
+"\n"
+"RISC OS 版本"
+
+msgid ""
+"\n"
+"Included patches: "
+msgstr ""
+"\n"
+"引入修正: "
+
+msgid "Modified by "
+msgstr "修改者為"
+
+msgid ""
+"\n"
+"Compiled "
+msgstr ""
+"\n"
+"編譯"
+
+msgid "by "
+msgstr "者:"
+
+msgid ""
+"\n"
+"Huge version "
+msgstr ""
+"\n"
+"超強版本 "
+
+msgid ""
+"\n"
+"Big version "
+msgstr ""
+"\n"
+"大型版本 "
+
+msgid ""
+"\n"
+"Normal version "
+msgstr ""
+"\n"
+"一般版本 "
+
+msgid ""
+"\n"
+"Small version "
+msgstr ""
+"\n"
+"簡易版本 "
+
+msgid ""
+"\n"
+"Tiny version "
+msgstr ""
+"\n"
+"精簡版本 "
+
+msgid "without GUI."
+msgstr "ä¸ä½¿ç”¨åœ–åž‹ç•Œé¢ã€‚"
+
+msgid "with GTK2-GNOME GUI."
+msgstr "使用 GTK2-GNOME 圖型界é¢ã€‚"
+
+msgid "with GTK-GNOME GUI."
+msgstr "使用 GTK-GNOME 圖型界é¢ã€‚"
+
+msgid "with GTK2 GUI."
+msgstr "使用 GTK2 圖型界é¢ã€‚"
+
+msgid "with GTK GUI."
+msgstr "使用 GTK 圖型界é¢ã€‚"
+
+msgid "with X11-Motif GUI."
+msgstr "使用 X11-Motif 圖型界é¢ã€‚"
+
+msgid "with X11-neXtaw GUI."
+msgstr "使用 X11-neXtaw 圖型界é¢ã€‚"
+
+msgid "with X11-Athena GUI."
+msgstr "使用 X11-Athena 圖型界é¢ã€‚"
+
+msgid "with BeOS GUI."
+msgstr "使用 BeOS 圖型界é¢ã€‚"
+
+msgid "with Photon GUI."
+msgstr "使用Photon圖型界é¢ã€‚"
+
+msgid "with GUI."
+msgstr "使用圖型界é¢ã€‚"
+
+msgid "with Carbon GUI."
+msgstr "使用 Carbon 圖型界é¢ã€‚"
+
+msgid "with Cocoa GUI."
+msgstr "使用 Cocoa 圖型界é¢ã€‚"
+
+msgid "with (classic) GUI."
+msgstr "使用 (傳統) 圖型界é¢ã€‚"
+
+msgid " Features included (+) or not (-):\n"
+msgstr " ç›®å‰å¯ä½¿ç”¨(+)與ä¸å¯ä½¿ç”¨(-)的模組列表:\n"
+
+msgid " system vimrc file: \""
+msgstr " 系統 vimrc 設定檔: \""
+
+msgid " user vimrc file: \""
+msgstr " 使用者個人 vimrc 設定檔: \""
+
+msgid " 2nd user vimrc file: \""
+msgstr " 第二組個人 vimrc 檔案: \""
+
+msgid " 3rd user vimrc file: \""
+msgstr " 第三組個人 vimrc 檔案: \""
+
+msgid " user exrc file: \""
+msgstr " 使用者個人 exrc 設定檔: \""
+
+msgid " 2nd user exrc file: \""
+msgstr " 第二組使用者 exrc 檔案: \""
+
+msgid " system gvimrc file: \""
+msgstr " 系統 gvimrc 檔案: \""
+
+msgid " user gvimrc file: \""
+msgstr " 使用者個人 gvimrc 檔: \""
+
+msgid "2nd user gvimrc file: \""
+msgstr " 第二組個人 gvimrc 檔案: \""
+
+msgid "3rd user gvimrc file: \""
+msgstr " 第三組個人 gvimrc 檔案: \""
+
+msgid " system menu file: \""
+msgstr " 系統é¸å–®è¨­å®šæª”: \""
+
+msgid " fall-back for $VIM: \""
+msgstr " $VIM é è¨­å€¼: \""
+
+msgid " f-b for $VIMRUNTIME: \""
+msgstr " $VIMRUNTIME é è¨­å€¼: \""
+
+msgid "Compilation: "
+msgstr "編譯方å¼: "
+
+msgid "Compiler: "
+msgstr "編譯器: "
+
+msgid "Linking: "
+msgstr "éˆçµæ–¹å¼: "
+
+msgid " DEBUG BUILD"
+msgstr " 除錯版本"
+
+msgid "VIM - Vi IMproved"
+msgstr "VIM - Vi IMproved"
+
+msgid "version "
+msgstr "版本 "
+
+msgid "by Bram Moolenaar et al."
+msgstr "維護者: Bram Moolenaar et al."
+
+msgid "Vim is open source and freely distributable"
+msgstr "Vim 為å¯è‡ªç”±æ•£ä½ˆçš„開放原始碼軟體"
+
+msgid "Help poor children in Uganda!"
+msgstr "請幫助çƒå¹²é”çš„å¯æ†å­©ç«¥!"
+
+msgid "type :help iccf<Enter> for information "
+msgstr "進一步說明請輸入 :help iccf<Enter>"
+
+msgid "type :q<Enter> to exit "
+msgstr "è¦é›¢é–‹è«‹è¼¸å…¥ :q<Enter> "
+
+msgid "type :help<Enter> or <F1> for on-line help"
+msgstr "線上說明請輸入 :help<Enter> "
+
+msgid "type :help version8<Enter> for version info"
+msgstr "新版本資訊請輸入 :help version8<Enter>"
+
+msgid "Running in Vi compatible mode"
+msgstr "Vi 相容模å¼"
+
+msgid "type :set nocp<Enter> for Vim defaults"
+msgstr "如果è¦å®Œå…¨æ¨¡æ“¬å‚³çµ± Vi 請輸入 :set nocp<Enter>"
+
+msgid "type :help cp-default<Enter> for info on this"
+msgstr "如果需è¦å° Vi 相容模å¼çš„進一步說明請輸入 :help cp-default<Enter>"
+
+msgid "menu Help->Orphans for information "
+msgstr "進一步說明請é¸å–é¸å–®çš„ 輔助說明->拯救孤兒"
+
+msgid "Running modeless, typed text is inserted"
+msgstr "執行 Modeless 模å¼ï¼Œè¼¸å…¥çš„文字會自動æ’å…¥"
+
+msgid "menu Edit->Global Settings->Toggle Insert Mode "
+msgstr "é¸å–é¸å–®çš„「編輯ã€ã€Œå…¨åŸŸè¨­å®šã€ã€Œåˆ‡æ›æ’入模å¼ã€"
+
+msgid " for two modes "
+msgstr " å…©ç¨®æ¨¡å¼ "
+
+msgid "menu Edit->Global Settings->Toggle Vi Compatible"
+msgstr "é¸å–é¸å–®çš„「編輯ã€ã€Œå…¨åŸŸè¨­å®šã€ã€Œåˆ‡æ›å‚³çµ±Vi相容模å¼ã€"
+
+msgid " for Vim defaults "
+msgstr " 以得 Vim é è¨­å€¼ "
+
+msgid "Sponsor Vim development!"
+msgstr "贊助 Vim 的開發與æˆé•·ï¼"
+
+msgid "Become a registered Vim user!"
+msgstr "æˆç‚º Vim 的註冊使用者ï¼"
+
+msgid "type :help sponsor<Enter> for information "
+msgstr "詳細說明請輸入 :help sponsor<Enter>"
+
+msgid "type :help register<Enter> for information "
+msgstr "詳細說明請輸入 :help register<Enter> "
+
+msgid "menu Help->Sponsor/Register for information "
+msgstr "詳細說明請é¸å–é¸å–®çš„ 輔助說明->贊助/註冊 "
+
+msgid "WARNING: Windows 95/98/ME detected"
+msgstr "注æ„: åµæ¸¬åˆ° Windows 95/98/ME"
+
+msgid "type :help windows95<Enter> for info on this"
+msgstr "如果需è¦å° Windows 95 支æ´çš„更多資訊請輸入 :help windows95<Enter>"
+
+msgid "E441: There is no preview window"
+msgstr "E441: 沒有é è¦½è¦–窗"
+
+msgid "E442: Can't split topleft and botright at the same time"
+msgstr "E442: ä¸èƒ½åŒæ™‚分割視窗為左上和å³ä¸‹è§’"
+
+msgid "E443: Cannot rotate when another window is split"
+msgstr "E443: 有其它分割視窗時無法旋轉"
+
+msgid "E444: Cannot close last window"
+msgstr "E444: ä¸èƒ½é—œé–‰æœ€å¾Œä¸€å€‹è¦–窗"
+
+msgid "Already only one window"
+msgstr "已經åªå‰©ä¸€å€‹è¦–窗了"
+
+msgid "E445: Other window contains changes"
+msgstr "E445: 其它視窗有更動資料"
+
+msgid "E446: No file name under cursor"
+msgstr "E446: 游標處沒有檔å"
+
+#, c-format
+msgid "E447: Can't find file \"%s\" in path"
+msgstr "E447: 在路徑中找ä¸åˆ°æª”案 \"%s\""
+
+#, c-format
+msgid "E370: Could not load library %s"
+msgstr "E370: 無法é‡æ–°è¼‰å…¥ç¨‹å¼åº« %s"
+
+msgid "Sorry, this command is disabled: the Perl library could not be loaded."
+msgstr "抱歉, 此命令無法使用. 原因: 無法載入 Perl 程å¼åº«(Library)"
+
+msgid "E299: Perl evaluation forbidden in sandbox without the Safe module"
+msgstr "E299: 在 sandbox 中無 Safe 模組時無法執行 Perl"
+
+msgid "Edit with &multiple Vims"
+msgstr "使用多個 Vim session 編輯(&M)"
+
+msgid "Edit with single &Vim"
+msgstr "åªä½¿ç”¨åŒä¸€å€‹ Vim session 編輯(&V)"
+
+msgid "&Diff with Vim"
+msgstr "使用 Vim 來比較(&Diff)"
+
+msgid "Edit with &Vim"
+msgstr "使用 Vim 編輯此檔(&V)"
+
+#. Now concatenate
+msgid "Edit with existing Vim - &"
+msgstr "使用執行中的 Vim session 編輯 - &"
+
+msgid "Edits the selected file(s) with Vim"
+msgstr "使用 Vim 編輯已é¸å–的檔案"
+
+msgid "Error creating process: Check if gvim is in your path!"
+msgstr "無法執行程å¼: 請檢查 gvim 有沒有在你的 PATH 變數裡!"
+
+msgid "gvimext.dll error"
+msgstr "gvimext.dll 錯誤"
+
+msgid "Path length too long!"
+msgstr "路徑長度太長!"
+
+msgid "--No lines in buffer--"
+msgstr "--ç·©è¡å€ç„¡è³‡æ–™--"
+
+#.
+#. * The error messages that can be shared are included here.
+#. * Excluded are errors that are only used once and debugging messages.
+#.
+msgid "E470: Command aborted"
+msgstr "E470: 命令被強制中斷執行 "
+
+msgid "E471: Argument required"
+msgstr "E471: 需è¦æŒ‡ä»¤åƒæ•¸"
+
+msgid "E10: \\ should be followed by /, ? or &"
+msgstr "E10: \\ 後é¢æ‡‰è©²æœ‰ / ? 或 &"
+
+msgid "E11: Invalid in command-line window; <CR> executes, CTRL-C quits"
+msgstr "E11: ä¸èƒ½åœ¨å‘½ä»¤åˆ—視窗中使用。<CR>執行,CTRL-C 離開"
+
+msgid "E12: Command not allowed from exrc/vimrc in current dir or tag search"
+msgstr "E12: exrc/vimrc 裡的指令無法執行 "
+
+msgid "E171: Missing :endif"
+msgstr "E171: 缺少 :endif"
+
+msgid "E600: Missing :endtry"
+msgstr "E600: 缺少 :endtry"
+
+msgid "E170: Missing :endwhile"
+msgstr "E170: 缺少 :endwhile"
+
+msgid "E588: :endwhile without :while"
+msgstr "E588: :endwhile 缺少å°æ‡‰çš„ :while"
+
+msgid "E13: File exists (add ! to override)"
+msgstr "E13: 檔案已經存在 (å¯ç”¨ ! 強制å–代)"
+
+msgid "E472: Command failed"
+msgstr "E472: 命令執行失敗"
+
+#, c-format
+msgid "E234: Unknown fontset: %s"
+msgstr "E234: ä¸æ­£ç¢ºçš„字元集 (Fontset): %s"
+
+#, c-format
+msgid "E235: Unknown font: %s"
+msgstr "E235: ä¸æ­£ç¢ºçš„å­—åž‹å稱: %s"
+
+#, c-format
+msgid "E236: Font \"%s\" is not fixed-width"
+msgstr "E236: \"%s\" ä¸æ˜¯å›ºå®šå¯¬åº¦å­—åž‹"
+
+msgid "E473: Internal error"
+msgstr "E473: 內部錯誤"
+
+msgid "Interrupted"
+msgstr "已中斷"
+
+msgid "E14: Invalid address"
+msgstr "E14: ä¸æ­£ç¢ºçš„ä½å€"
+
+msgid "E474: Invalid argument"
+msgstr "E474: ä¸æ­£ç¢ºçš„åƒæ•¸"
+
+#, c-format
+msgid "E475: Invalid argument: %s"
+msgstr "E475: ä¸æ­£ç¢ºçš„åƒæ•¸: %s"
+
+#, c-format
+msgid "E15: Invalid expression: %s"
+msgstr "E15: ä¸æ­£ç¢ºçš„é‹ç®—å¼: %s"
+
+msgid "E16: Invalid range"
+msgstr "E16: ä¸æ­£ç¢ºçš„範åœ"
+
+msgid "E476: Invalid command"
+msgstr "E476: ä¸æ­£ç¢ºçš„命令"
+
+#, c-format
+msgid "E17: \"%s\" is a directory"
+msgstr "E17: \"%s\" 是目錄"
+
+msgid "E18: Unexpected characters before '='"
+msgstr "E18: '=' å‰é¢å‡ºç¾äº†éŒ¯èª¤çš„å­—å…ƒ"
+
+#, c-format
+msgid "E364: Library call failed for \"%s()\""
+msgstr "E364: 呼å«å‡½å¼åº« \"%s\"() 失敗"
+
+#, c-format
+msgid "E448: Could not load library function %s"
+msgstr "E448: 無法載入程å¼åº«çš„å‡½å¼ %s"
+
+msgid "E19: Mark has invalid line number"
+msgstr "E19: 標記的行號錯誤"
+
+msgid "E20: Mark not set"
+msgstr "E20: 沒有設定標記"
+
+msgid "E21: Cannot make changes, 'modifiable' is off"
+msgstr "E21: 因為 'modifiable' é¸é …是關閉的,所以ä¸èƒ½ä¿®æ”¹"
+
+msgid "E22: Scripts nested too deep"
+msgstr "E22: 巢狀éžè¿´å‘¼å«å¤ªå¤šå±¤"
+
+msgid "E23: No alternate file"
+msgstr "E23: 沒有替代的檔案"
+
+msgid "E24: No such abbreviation"
+msgstr "E24: 沒有這個 abbreviation å°æ‡‰"
+
+msgid "E477: No ! allowed"
+msgstr "E477: ä¸å¯ä½¿ç”¨ '!'"
+
+msgid "E25: GUI cannot be used: Not enabled at compile time"
+msgstr "E25: 因為編譯時沒有加入圖型界é¢çš„程å¼ç¢¼ï¼Œæ‰€ä»¥ç„¡æ³•ä½¿ç”¨åœ–åž‹ç•Œé¢"
+
+msgid "E26: Hebrew cannot be used: Not enabled at compile time\n"
+msgstr "E26: 因為編譯時沒有加入 Hebrew 的程å¼ç¢¼ï¼Œæ‰€ä»¥ç„¡æ³•ä½¿ç”¨ Hebrew\n"
+
+msgid "E27: Farsi cannot be used: Not enabled at compile time\n"
+msgstr "E27: 因為編譯時沒有加入 Farsi 的程å¼ç¢¼ï¼Œæ‰€ä»¥ç„¡æ³•ä½¿ç”¨ Farsi\n"
+
+msgid "E800: Arabic cannot be used: Not enabled at compile time\n"
+msgstr "E800: 因為編譯時沒有加入 Arabic 的程å¼ç¢¼ï¼Œæ‰€ä»¥ç„¡æ³•ä½¿ç”¨\n"
+
+#, c-format
+msgid "E28: No such highlight group name: %s"
+msgstr "E28: 沒有å為 '%s' çš„ highlight group"
+
+msgid "E29: No inserted text yet"
+msgstr "E29: 還沒有æ’入文字éŽ"
+
+msgid "E30: No previous command line"
+msgstr "E30: 沒有å‰ä¸€é …命令"
+
+msgid "E31: No such mapping"
+msgstr "E31: 沒有這個 mapping å°æ‡‰"
+
+msgid "E479: No match"
+msgstr "E479: 找ä¸åˆ°"
+
+#, c-format
+msgid "E480: No match: %s"
+msgstr "E480: 找ä¸åˆ°: %s"
+
+msgid "E32: No file name"
+msgstr "E32: 沒有檔å"
+
+msgid "E33: No previous substitute regular expression"
+msgstr "E33: 沒有å‰ä¸€å€‹æœå°‹/å–代的命令"
+
+msgid "E34: No previous command"
+msgstr "E34: 沒有å‰ä¸€å€‹å‘½ä»¤"
+
+msgid "E35: No previous regular expression"
+msgstr "E35: 沒有å‰ä¸€å€‹æœå°‹æŒ‡ä»¤"
+
+msgid "E481: No range allowed"
+msgstr "E481: ä¸å¯ä½¿ç”¨ç¯„åœæŒ‡ä»¤"
+
+msgid "E36: Not enough room"
+msgstr "E36: 沒有足夠的空間"
+
+#, c-format
+msgid "E247: no registered server named \"%s\""
+msgstr "E247: 沒有註冊為 \"%s\" 的伺æœå™¨"
+
+#, c-format
+msgid "E482: Can't create file %s"
+msgstr "E482: ä¸èƒ½å»ºç«‹æª”案 %s"
+
+msgid "E483: Can't get temp file name"
+msgstr "E483: 無法得知暫存檔å"
+
+#, c-format
+msgid "E484: Can't open file %s"
+msgstr "E484: 無法開啟檔案 %s"
+
+#, c-format
+msgid "E485: Can't read file %s"
+msgstr "E485: 無法讀å–檔案 %s"
+
+msgid "E37: No write since last change (add ! to override)"
+msgstr "E37: 已更改éŽæª”案但尚未存檔 (å¯ç”¨ ! 強制執行)"
+
+msgid "E38: Null argument"
+msgstr "E38: 空的 (Null) åƒæ•¸"
+
+msgid "E39: Number expected"
+msgstr "E39: 應該è¦æœ‰æ•¸å­—"
+
+#, c-format
+msgid "E40: Can't open errorfile %s"
+msgstr "E40: 無法開啟錯誤檔案 %s"
+
+msgid "E233: cannot open display"
+msgstr "E233: <ä¸èƒ½é–‹å•Ÿ X Server DISPLAY>"
+
+msgid "E41: Out of memory!"
+msgstr "E41: 記憶體ä¸è¶³!"
+
+msgid "Pattern not found"
+msgstr "找ä¸åˆ°"
+
+#, c-format
+msgid "E486: Pattern not found: %s"
+msgstr "E486: 找ä¸åˆ° %s"
+
+msgid "E487: Argument must be positive"
+msgstr "E487: åƒæ•¸æ‡‰è©²æ˜¯æ­£æ•¸"
+
+msgid "E459: Cannot go back to previous directory"
+msgstr "E459: 無法回到å‰ä¸€å€‹ç›®éŒ„"
+
+msgid "E42: No Errors"
+msgstr "E42: 沒有錯誤"
+
+msgid "E43: Damaged match string"
+msgstr "E43: 符åˆå­—串有å•é¡Œ"
+
+msgid "E44: Corrupted regexp program"
+msgstr "E44: regexp 有å•é¡Œ"
+
+msgid "E45: 'readonly' option is set (add ! to override)"
+msgstr "E45: 有設定 'readonly' é¸é …(唯讀) (å¯ç”¨ ! 強制執行)"
+
+#, c-format
+msgid "E46: Cannot set read-only variable \"%s\""
+msgstr "E46: 無法設定唯讀變數 \"%s\""
+
+msgid "E47: Error while reading errorfile"
+msgstr "E47: 讀å–錯誤檔案失敗"
+
+msgid "E48: Not allowed in sandbox"
+msgstr "E48: ä¸èƒ½åœ¨ sandbox 裡出ç¾"
+
+msgid "E523: Not allowed here"
+msgstr "E523: 這裡ä¸å¯ä½¿ç”¨"
+
+msgid "E359: Screen mode setting not supported"
+msgstr "E359: ä¸æ”¯æ´è¨­å®šèž¢å¹•æ¨¡å¼"
+
+msgid "E49: Invalid scroll size"
+msgstr "E49: 錯誤的æ²å‹•å¤§å°"
+
+msgid "E91: 'shell' option is empty"
+msgstr "E91: 'E71: é¸é … 'shell' 未設定"
+
+msgid "E255: Couldn't read in sign data!"
+msgstr "E255: ç„¡æ³•è®€å– sign data!"
+
+msgid "E72: Close error on swap file"
+msgstr "E72: 暫存檔關閉錯誤"
+
+msgid "E73: tag stack empty"
+msgstr "E73: 標籤堆疊已空"
+
+msgid "E74: Command too complex"
+msgstr "E74: 命令太複雜"
+
+msgid "E75: Name too long"
+msgstr "E75: å字太長"
+
+msgid "E76: Too many ["
+msgstr "E76: 太多 ["
+
+msgid "E77: Too many file names"
+msgstr "E77: 太多檔å"
+
+msgid "E488: Trailing characters"
+msgstr "E488: 你輸入了多餘的字元"
+
+msgid "E78: Unknown mark"
+msgstr "E78: 無法辦識的標記"
+
+msgid "E79: Cannot expand wildcards"
+msgstr "E79: 無法展開è¬ç”¨å­—å…ƒ"
+
+msgid "E591: 'winheight' cannot be smaller than 'winminheight'"
+msgstr "E591: 'winheight' ä¸èƒ½æ¯” 'winminheight' æ›´å°‘"
+
+msgid "E592: 'winwidth' cannot be smaller than 'winminwidth'"
+msgstr "E592: 'winwidth' ä¸èƒ½æ¯” 'winminwidth' æ›´å°‘"
+
+msgid "E80: Error while writing"
+msgstr "E80: 寫入錯誤"
+
+msgid "Zero count"
+msgstr "數到零 (?)"
+
+msgid "E81: Using <SID> not in a script context"
+msgstr "E81: <SID> ä¸èƒ½åœ¨ script 本文外使用."
+
+msgid "E449: Invalid expression received"
+msgstr "E449: 收到ä¸æ­£ç¢ºçš„é‹ç®—å¼"
+
+msgid "E463: Region is guarded, cannot modify"
+msgstr "E463: å€åŸŸè¢«ä¿è­·ï¼Œç„¡æ³•ä¿®æ”¹"
+
+#~ msgid "E565: error reading cscope connection %d"
+#~ msgstr "E565: è®€å– cscope 連線 %d 錯誤"
+
+#~ msgid "E260: cscope connection not found"
+#~ msgstr "E260: 找ä¸åˆ° cscope 連線"
+
+#~ msgid "cscope connection closed"
+#~ msgstr "cscope 連線已關閉"
+
+#~ msgid "couldn't malloc\n"
+#~ msgstr "無法使用 malloc\n"
+
+#~ msgid "%2d %-5ld %-34s <none>\n"
+#~ msgstr "%2d %-5ld %-34s <ç„¡>\n"
+
+#~ msgid "\"\n"
+#~ msgstr "\"\n"
+
+#~ msgid "--help\t\tShow Gnome arguments"
+#~ msgstr "--help\t\t顯示 Gnome 相關åƒæ•¸"
+
+#~ msgid " BLOCK"
+#~ msgstr " å€å¡Š"
+
+#~ msgid " LINE"
+#~ msgstr " è¡Œé¸å–"
+
+#~ msgid "Linear tag search"
+#~ msgstr "線性æœå°‹æ¨™ç±¤ (Tags)"
+
+#~ msgid "Binary tag search"
+#~ msgstr "二分æœå°‹(Binary search) 標籤(Tags)"
+
+#~ msgid "function "
+#~ msgstr "å‡½å¼ "
+
+#~ msgid "Run Macro"
+#~ msgstr "執行巨集"
+
+#~ msgid "E221: 'commentstring' is empty"
+#~ msgstr "E221: é¸é … 'commentstring' 未設定"
+
+#~ msgid "E242: Color name not recognized: %s"
+#~ msgstr "E242: %s 為無法識別的é¡è‰²å稱"
+
+#~ msgid "E242: Missing color: %s"
+#~ msgstr "E242: 找ä¸åˆ°é¡è‰²: %s"
+
+#~ msgid "error reading cscope connection %d"
+#~ msgstr "è®€å– cscope 連線 %d 時錯誤"
+
+#~ msgid "E249: couldn't read VIM instance registry property"
+#~ msgstr "E249: ç„¡æ³•è®€å– VIM çš„ registry 設定項"
+
+#~ msgid "Can't open file %s"
+#~ msgstr "無法開啟檔案 %s"
+
+#~ msgid "Unable to send reply"
+#~ msgstr "無法傳é€å›žæ‡‰è¨Šæ¯"
+
+#~ msgid "E241: Unable to send to Vim server"
+#~ msgstr "E241: 無法傳é€åˆ° Vim 伺æœå™¨"
+
+#~ msgid ""
+#~ "\n"
+#~ "Send failed. No command server present ?\n"
+#~ msgstr ""
+#~ "\n"
+#~ "傳é€å¤±æ•—。沒有命令伺æœå™¨å­˜åœ¨ ?\n"
+
+#~ msgid "PC (32 bits Vim)"
+#~ msgstr "PC (32 ä½å…ƒ Vim)"
+
+#~ msgid "PC (16 bits Vim)"
+#~ msgstr "PC (16 ä½å…ƒ Vim)"
+
+#~ msgid "E362: Unsupported screen mode"
+#~ msgstr "E362: 螢幕模å¼ä¸æ”¯æ´"
+
+#~ msgid "No servers found for this display"
+#~ msgstr "æ­¤Display沒有伺æœå™¨(Servers)"
+
+#~ msgid "E258: no matches found in cscope connections"
+#~ msgstr "E258: cscope 連線找ä¸åˆ°ç¬¦åˆçš„"
+
+#~ msgid ""
+#~ "\n"
+#~ "MacOS Carbon"
+#~ msgstr ""
+#~ "\n"
+#~ "MacOS Carbon"
+
+#~ msgid ""
+#~ "\n"
+#~ "MacOS 8"
+#~ msgstr ""
+#~ "\n"
+#~ "MacOS 8"
+
+#~ msgid "Retrieve next symbol"
+#~ msgstr "讀å–: 從下個 symbol"
+
+#~ msgid "-- SNiFF+ commands --"
+#~ msgstr "-- SNiFF+ 命令 --"
+
+#~ msgid "E277: Unrecognized sniff request [%s]"
+#~ msgstr "E277: 無法辨識 sniff 命令 [%s]"
diff --git a/src/po/zh_TW.po b/src/po/zh_TW.po
new file mode 100644
index 0000000..f29700f
--- /dev/null
+++ b/src/po/zh_TW.po
@@ -0,0 +1,5275 @@
+# Traditional Chinese Translation for Vim vim:set foldmethod=marker:
+#
+# Do ":help uganda" in Vim to read copying and usage conditions.
+# Do ":help credits" in Vim to see a list of people who contributed.
+#
+# FIRST AUTHOR Francis S.Lin <piaip@csie.ntu.edu.tw>, 2000
+# FIRST RELEASE Thu Jun 14 14:24:17 CST 2001
+#
+# Last update: 2005/01/27 07:03 (6.3)
+#
+# To update, search pattern: /fuzzy\|^msgstr ""\(\n"\)\@!
+#
+# DO NOT USE WORDS WITH BACKSLASH ('\') AS SECOND BYTE OF BIG5 CHARS
+# EG: '¥\', # ³\¥\»\
+# [blacklist: À\¬\¾\¯\½\¶\²\Æ\°\Â\¿\Á\Å\§\ª\«\]
+# [blacklist: ®\±\Ã\Ä\´\µ\·\¹\º\¤\¦\­\á\ä\]
+# you can replace these characters with alternative words.
+# THIS WILL CAUSE INCOMPATIBLE ON gettext 0.10.36+
+#
+# Note (2005.01.27):
+# A bug was found for UTF8 mode.
+# > msgid "%ld fewer lines" "on %ld lines"
+# If you don't put more (at least 2) spaces after %ld
+# gvim/win32 will crash (no reason).
+# So please change [¦æ"] to [¦æ "]
+#
+# Q. How to use UTF8 mode on Win32?
+# A. A simple configuration:
+# set encoding=utf-8; let $LANG='zh_TW.UTF-8';
+# (set langmenu=none or ..)
+# set termencoding=utf-8
+# set fileencodings=ucs-bom,utf-8,japan,taiwan,prc
+# set fileencoding=taiwan (or utf-8)
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Vim(Traditional Chinese)\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2005-01-27 19:00+0800\n"
+"PO-Revision-Date: Mon Feb 19 22:49:21 CST 2001\n"
+"Last-Translator: Hung-Te Lin <piaip@csie.ntu.edu.tw>\n"
+"Language-Team: Hung-Te Lin <piaip@csie.ntu.edu.tw>, Cecil Sheng "
+"<b7506022@csie.ntu.edu.tw>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=big5\n"
+"Content-Transfer-Encoding: 8-bit\n"
+
+msgid "E82: Cannot allocate any buffer, exiting..."
+msgstr "E82: µLªk°t¸m¥ô¦ó½w½Ä°Ï¡AÂ÷¶}µ{¦¡..."
+
+msgid "E83: Cannot allocate buffer, using other one..."
+msgstr "E83: µLªk°t¸m½w½Ä°Ï¡A¨Ï¥Î¥t¤@­Ó½w½Ä°Ï...."
+
+#, c-format
+msgid "E515: No buffers were unloaded"
+msgstr "E515: ¨S¦³ÄÀ©ñ¥ô¦ó½w½Ä°Ï"
+
+#, c-format
+msgid "E516: No buffers were deleted"
+msgstr "E516: ¨S¦³§R°£¥ô¦ó½w½Ä°Ï"
+
+#, c-format
+msgid "E517: No buffers were wiped out"
+msgstr "E517: ¨S¦³²M°£¥ô¦ó½w½Ä°Ï"
+
+msgid "1 buffer unloaded"
+msgstr "¤wÄÀ©ñ¤@­Ó½w½Ä°Ï"
+
+#, c-format
+msgid "%d buffers unloaded"
+msgstr "¤wÄÀ©ñ %d ­Ó½w½Ä°Ï"
+
+msgid "1 buffer deleted"
+msgstr "¤w§R°£¤@­Ó½w½Ä°Ï"
+
+#, c-format
+msgid "%d buffers deleted"
+msgstr "¤w§R°£ %d ­Ó½w½Ä°Ï"
+
+msgid "1 buffer wiped out"
+msgstr "¤w§R°£¤@­Ó½w½Ä°Ï"
+
+#, c-format
+msgid "%d buffers wiped out"
+msgstr "¤w§R°£ %d ­Ó½w½Ä°Ï"
+
+msgid "E84: No modified buffer found"
+msgstr "E84: ¨S¦³­×§ï¹Lªº½w½Ä°Ï"
+
+#. back where we started, didn't find anything.
+msgid "E85: There is no listed buffer"
+msgstr "E85: ¨S¦³¦C¥Xªº½w½Ä°Ï"
+
+#, c-format
+msgid "E86: Buffer %ld does not exist"
+msgstr "E86: ½w½Ä°Ï %ld ¤£¦s¦b"
+
+msgid "E87: Cannot go beyond last buffer"
+msgstr "E87: µLªk¤Á´«¨ì§ó«á­±ªº½w½Ä°Ï"
+
+msgid "E88: Cannot go before first buffer"
+msgstr "E88: µLªk¤Á´«¨ì§ó«e­±ªº½w½Ä°Ï"
+
+#, c-format
+msgid "E89: No write since last change for buffer %ld (add ! to override)"
+msgstr "E89: ¤w§ó§ï¹L½w½Ä°Ï %ld ¦ý©|¥¼¦sÀÉ (¥i¥Î ! ±j¨î°õ¦æ)"
+
+msgid "E90: Cannot unload last buffer"
+msgstr "E90: µLªkÄÀ©ñ³Ì«á¤@­Ó½w½Ä°Ï"
+
+msgid "W14: Warning: List of file names overflow"
+msgstr "W14: ĵ§i: ÀɦW¹L¦h"
+
+#, c-format
+msgid "E92: Buffer %ld not found"
+msgstr "E92: §ä¤£¨ì²Ä %ld ­Ó½w½Ä°Ï"
+
+#, c-format
+msgid "E93: More than one match for %s"
+msgstr "E93: §ä¨ì¤@­Ó¥H¤Wªº %s"
+
+#, c-format
+msgid "E94: No matching buffer for %s"
+msgstr "E94: §ä¤£¨ì %s"
+
+#, c-format
+msgid "line %ld"
+msgstr "¦æ %ld"
+
+msgid "E95: Buffer with this name already exists"
+msgstr "E95: ¤w¦³½w½Ä°Ï¨Ï¥Î³o­Ó¦W¦r"
+
+msgid " [Modified]"
+msgstr " [¤w­×§ï]"
+
+msgid "[Not edited]"
+msgstr "[¥¼½s¿è]"
+
+msgid "[New file]"
+msgstr "[·sÀÉ®×]"
+
+msgid "[Read errors]"
+msgstr "[Ū¨ú¿ù»~]"
+
+msgid "[readonly]"
+msgstr "[°ßŪ]"
+
+#, c-format
+msgid "1 line --%d%%--"
+msgstr "¦æ¼Æ 1 --%d%%--"
+
+#, c-format
+msgid "%ld lines --%d%%--"
+msgstr "¦æ¼Æ %ld --%d%%--"
+
+#, c-format
+msgid "line %ld of %ld --%d%%-- col "
+msgstr "¦æ %ld/%ld --%d%%-- Äæ "
+
+msgid "[No file]"
+msgstr "[¥¼©R¦W]"
+
+#. must be a help buffer
+msgid "help"
+msgstr "[»²§U»¡©ú]"
+
+msgid "[help]"
+msgstr "[»²§U»¡©ú]"
+
+msgid "[Preview]"
+msgstr "[¹wÄý]"
+
+msgid "All"
+msgstr "¥þ³¡"
+
+msgid "Bot"
+msgstr "©³ºÝ"
+
+msgid "Top"
+msgstr "³»ºÝ"
+
+#, c-format
+msgid ""
+"\n"
+"# Buffer list:\n"
+msgstr ""
+"\n"
+"# ½w½Ä°Ï¦Cªí:\n"
+
+msgid "[Error List]"
+msgstr "[¿ù»~¦Cªí]"
+
+msgid "[No File]"
+msgstr "[¥¼©R¦W]"
+
+msgid ""
+"\n"
+"--- Signs ---"
+msgstr ""
+"\n"
+"--- ²Å¸¹ ---"
+
+#, c-format
+msgid "Signs for %s:"
+msgstr "%s ªº²Å¸¹:"
+
+#, c-format
+msgid " line=%ld id=%d name=%s"
+msgstr " ¦æ=%ld id=%d ¦WºÙ=%s"
+
+#, c-format
+msgid "E96: Can not diff more than %ld buffers"
+msgstr "E96: µLªk¤ñ¸û(diff) %ld­Ó¥H¤Wªº½w½Ä°Ï"
+
+msgid "E97: Cannot create diffs"
+msgstr "E97: ¤£¯à«Ø¥ß "
+
+msgid "Patch file"
+msgstr "Patch ÀÉ®×"
+
+msgid "E98: Cannot read diff output"
+msgstr "E98: µLªkŪ¨ú diff ªº¿é¥X"
+
+msgid "E99: Current buffer is not in diff mode"
+msgstr "E99: ¥Ø«eªº½w½Ä°Ï¤£¬O¦b diff ¼Ò¦¡"
+
+msgid "E100: No other buffer in diff mode"
+msgstr "E100: ¨S¦³½w½Ä°Ï¦b diff ¼Ò¦¡"
+
+msgid "E101: More than two buffers in diff mode, don't know which one to use"
+msgstr "E101: ¦³¨â­Ó¥H¤Wªº½w½Ä°Ï¦b diff ¼Ò¦¡¡AµLªk¨M©w­n¥Î­þ¤@­Ó"
+
+#, c-format
+msgid "E102: Can't find buffer \"%s\""
+msgstr "E102: §ä¤£¨ì½w½Ä°Ï: \"%s\""
+
+#, c-format
+msgid "E103: Buffer \"%s\" is not in diff mode"
+msgstr "E103: ½w½Ä°Ï \"%s\" ¤£¬O¦b diff ¼Ò¦¡"
+
+msgid "E104: Escape not allowed in digraph"
+msgstr "E104: ½Æ¦X¦r¤¸(digraph)¤¤¤£¯à¨Ï¥Î Escape"
+
+msgid "E544: Keymap file not found"
+msgstr "E544: §ä¤£¨ì keymap ÀÉ"
+
+msgid "E105: Using :loadkeymap not in a sourced file"
+msgstr "E105: ¨Ï¥Î :loadkeymap "
+
+msgid " Keyword completion (^N^P)"
+msgstr " ÃöÁä¦r¦Û°Ê§¹¦¨ (^N^P)"
+
+#. ctrl_x_mode == 0, ^P/^N compl.
+msgid " ^X mode (^E^Y^L^]^F^I^K^D^V^N^P)"
+msgstr " ^X ¼Ò¦¡ (^E^Y^L^]^F^I^K^D^N^P)"
+
+#. Scroll has it's own msgs, in it's place there is the msg for local
+#. * ctrl_x_mode = 0 (eg continue_status & CONT_LOCAL) -- Acevedo
+msgid " Keyword Local completion (^N^P)"
+msgstr " °Ï°ìÃöÁä¦r¦Û°Ê§¹¦¨ (^N^P)"
+
+msgid " Whole line completion (^L^N^P)"
+msgstr " ¾ã¦æ¦Û°Ê§¹¦¨ (^L^N^P)"
+
+msgid " File name completion (^F^N^P)"
+msgstr " ÀɦW¦Û°Ê§¹¦¨ (^F^N^P)"
+
+msgid " Tag completion (^]^N^P)"
+msgstr " ¼ÐÅҦ۰ʧ¹¦¨ (^]^N^P)"
+
+msgid " Path pattern completion (^N^P)"
+msgstr " ¸ô®|¦Û°Ê§¹¦¨ (^N^P)"
+
+msgid " Definition completion (^D^N^P)"
+msgstr " ©w¸q¦Û°Ê§¹¦¨ (^D^N^P)"
+
+msgid " Dictionary completion (^K^N^P)"
+msgstr " ¦r¨å¦Û°Ê§¹¦¨ (^K^N^P)"
+
+msgid " Thesaurus completion (^T^N^P)"
+msgstr " Thesaurus ¦Û°Ê§¹¦¨ (^T^N^P)"
+
+msgid " Command-line completion (^V^N^P)"
+msgstr " ©R¥O¦C¦Û°Ê§¹¦¨ (^V^N^P)"
+
+msgid "Hit end of paragraph"
+msgstr "¤w¨ì¬q¸¨µ²§À"
+
+msgid "'thesaurus' option is empty"
+msgstr "¿ï¶µ 'thesaurus' ¥¼³]©w"
+
+msgid "'dictionary' option is empty"
+msgstr "¿ï¶µ 'dictionary' ¥¼³]©w"
+
+#, c-format
+msgid "Scanning dictionary: %s"
+msgstr "±½ºË¦r¨å: %s"
+
+msgid " (insert) Scroll (^E/^Y)"
+msgstr " (´¡¤J) Scroll (^E/^Y)"
+
+msgid " (replace) Scroll (^E/^Y)"
+msgstr " (¨ú¥N) Scroll (^E/^Y)"
+
+#, c-format
+msgid "Scanning: %s"
+msgstr "±½ºË¤¤: %s"
+
+#, c-format
+msgid "Scanning tags."
+msgstr "±½ºË¼ÐÅÒ."
+
+msgid " Adding"
+msgstr " ¼W¥["
+
+#. showmode might reset the internal line pointers, so it must
+#. * be called before line = ml_get(), or when this address is no
+#. * longer needed. -- Acevedo.
+#.
+msgid "-- Searching..."
+msgstr "-- ·j´M¤¤..."
+
+msgid "Back at original"
+msgstr "¦^¨ì°_ÂI"
+
+msgid "Word from other line"
+msgstr "±q§O¦æ¶}©lªº¦r (?)"
+
+msgid "The only match"
+msgstr "¥u¦³¦¹¶µ²Å¦X"
+
+#, c-format
+msgid "match %d of %d"
+msgstr "§ä¨ì %d / %d"
+
+#, c-format
+msgid "match %d"
+msgstr "²Å¦X %d"
+
+#. Skip further arguments but do continue to
+#. * search for a trailing command.
+#, c-format
+msgid "E106: Unknown variable: \"%s\""
+msgstr "E106: ¥¼©w¸qªºÅܼÆ: \"%s\""
+
+#, c-format
+msgid "E107: Missing parentheses: %s"
+msgstr "E107: ¯Ê¤Ö¹ïÀ³ªº¬A¸¹: %s"
+
+#, c-format
+msgid "E108: No such variable: \"%s\""
+msgstr "E108: µL¦¹ÅܼÆ: \"%s\""
+
+msgid "E109: Missing ':' after '?'"
+msgstr "E109: '?' «á¯Ê¤Ö ':'"
+
+msgid "E110: Missing ')'"
+msgstr "E110: ¯Ê¤Ö¹ïÀ³ªº \")\""
+
+msgid "E111: Missing ']'"
+msgstr "E111: ¯Ê¤Ö¹ïÀ³ªº \"]\""
+
+#, c-format
+msgid "E112: Option name missing: %s"
+msgstr "E112: ¯Ê¤Ö¿ï¶µ¦WºÙ: %s"
+
+#, c-format
+msgid "E113: Unknown option: %s"
+msgstr "E113: ¤£¥¿½Tªº¿ï¶µ: %s"
+
+#, c-format
+msgid "E114: Missing quote: %s"
+msgstr "E114: ¯Ê¤Ö¤Þ¸¹: %s"
+
+#, c-format
+msgid "E115: Missing quote: %s"
+msgstr "E115: ¯Ê¤Ö¤Þ¸¹: %s"
+
+#, c-format
+msgid "E116: Invalid arguments for function %s"
+msgstr "E116: ¨ç¦¡ %s ªº¤Þ¼Æ¤£¥¿½T"
+
+#, c-format
+msgid "E117: Unknown function: %s"
+msgstr "E117: ¥¼©w¸qªº¨ç¦¡: %s"
+
+#, c-format
+msgid "E118: Too many arguments for function: %s"
+msgstr "E118: ¨ç¦¡ %s ªº¤Þ¼Æ¹L¦h"
+
+#, c-format
+msgid "E119: Not enough arguments for function: %s"
+msgstr "E119: ¨ç¦¡ %s ªº¤Þ¼Æ¤Ó¤Ö"
+
+#, c-format
+msgid "E120: Using <SID> not in a script context: %s"
+msgstr "E120: <SID> ¤£¯à¦b script ¥»¤å¥~¨Ï¥Î: %s"
+
+#.
+#. * Yes this is ugly, I don't particularly like it either. But doing it
+#. * this way has the compelling advantage that translations need not to
+#. * be touched at all. See below what 'ok' and 'ync' are used for.
+#.
+msgid "&Ok"
+msgstr "½T©w(&O)"
+
+#, c-format
+msgid "+-%s%3ld lines: "
+msgstr "+-%s%3ld ¦æ: "
+
+msgid ""
+"&OK\n"
+"&Cancel"
+msgstr ""
+"½T©w(&O)\n"
+"¨ú®ø(&C)"
+
+msgid "called inputrestore() more often than inputsave()"
+msgstr "©I¥s inputrestore() ªº¦¸¼Æ¤ñ inputsave() ÁÙ¦h"
+
+msgid "E655: Too many symbolic links (cycle?)"
+msgstr "E655: ¤Ó¦h¼hªº²Å¸¹Ãìµ²(symlink) (´`Àô?)"
+
+msgid "E240: No connection to Vim server"
+msgstr "E240: ¨S¦³»P Vim Server «Ø¥ß³s½u"
+
+msgid "E277: Unable to read a server reply"
+msgstr "E277: µLªkŪ¨ú¦øªA¾¹ªº¦^À³"
+
+msgid "E258: Unable to send to client"
+msgstr "E258: µLªk¶Ç°e¨ì client"
+
+#, c-format
+msgid "E241: Unable to send to %s"
+msgstr "E241: µLªk¶Ç°e¨ì %s"
+
+msgid "(Invalid)"
+msgstr "(¤£¥¿½T)"
+
+#, c-format
+msgid "E121: Undefined variable: %s"
+msgstr "E121: ÅÜ¼Æ %s ©|¥¼©w¸q"
+
+#, c-format
+msgid "E461: Illegal variable name: %s"
+msgstr "E461: ¤£¦XªkªºÅܼƦWºÙ: %s"
+
+#, c-format
+msgid "E122: Function %s already exists, add ! to replace it"
+msgstr "E122: ¨ç¦¡ %s ¤w¸g¦s¦b, ½Ð¨Ï¥Î ! ±j¨î¨ú¥N"
+
+#, c-format
+msgid "E123: Undefined function: %s"
+msgstr "E123: ¨ç¦¡ %s ©|¥¼©w¸q"
+
+#, c-format
+msgid "E124: Missing '(': %s"
+msgstr "E124: ¯Ê¤Ö \"(\": %s"
+
+#, c-format
+msgid "E125: Illegal argument: %s"
+msgstr "E125: °Ñ¼Æ¤£¥¿½T: %s"
+
+msgid "E126: Missing :endfunction"
+msgstr "E126: ¯Ê¤Ö :endfunction"
+
+#, c-format
+msgid "E127: Cannot redefine function %s: It is in use"
+msgstr "E127: ¨ç¦¡ %s ¥¿¦b¨Ï¥Î¤¤¡AµLªk­«·s©w¸q"
+
+msgid "E129: Function name required"
+msgstr "E129: »Ý­n¨ç¦¡¦WºÙ"
+
+#, c-format
+msgid "E128: Function name must start with a capital: %s"
+msgstr "E128: ¨ç¦¡¦WºÙ²Ä¤@­Ó¦r¥À¥²¶·¤j¼g: %s"
+
+#, c-format
+msgid "E130: Undefined function: %s"
+msgstr "E130: ¨ç¦¡ %s ©|¥¼©w¸q"
+
+#, c-format
+msgid "E131: Cannot delete function %s: It is in use"
+msgstr "E131: ¨ç¦¡ %s ¥¿¦b¨Ï¥Î¤¤¡AµLªk§R°£"
+
+msgid "E132: Function call depth is higher than 'maxfuncdepth'"
+msgstr "E132: ¨ç¦¡»¼°j©I¥s¼h¼Æ¶W¹L 'maxfuncdepth'"
+
+#. always scroll up, don't overwrite
+#, c-format
+msgid "calling %s"
+msgstr "©I¥s %s"
+
+#, c-format
+msgid "%s aborted"
+msgstr "%s ³Q±j¨î¤¤Â_°õ¦æ "
+
+#, c-format
+msgid "%s returning #%ld"
+msgstr "%s ¶Ç¦^­È #%ld "
+
+#, c-format
+msgid "%s returning \"%s\""
+msgstr "%s ¶Ç¦^­È \"%s\""
+
+#. always scroll up, don't overwrite
+#, c-format
+msgid "continuing in %s"
+msgstr "Ä~Äò: %s"
+
+msgid "E133: :return not inside a function"
+msgstr "E133: :return ¥²¶·¦b¨ç¦¡¸Ì¨Ï¥Î"
+
+#, c-format
+msgid ""
+"\n"
+"# global variables:\n"
+msgstr ""
+"\n"
+"# ¥þ°ìÅܼÆ:\n"
+
+#, c-format
+msgid "<%s>%s%s %d, Hex %02x, Octal %03o"
+msgstr "<%s>%s%s %d, ¤Q¤»¶i¦ì %02x, ¤K¶i¦ì %03o"
+
+#, c-format
+msgid "> %d, Hex %04x, Octal %o"
+msgstr "> %d, ¤Q¤»¶i¦ì %04x, ¤K¶i¦ì %o"
+
+#, c-format
+msgid "> %d, Hex %08x, Octal %o"
+msgstr "> %d, ¤Q¤»¶i¦ì %08x, ¤K¶i¦ì %o"
+
+msgid "E134: Move lines into themselves"
+msgstr "E134: µLªk§â¦æ²¾¨ì¥¦¦Û¤w¤º"
+
+msgid "1 line moved"
+msgstr "¤w·h²¾ 1 ¦æ "
+
+#, c-format
+msgid "%ld lines moved"
+msgstr "¤w·h²¾ %ld ¦æ "
+
+#, c-format
+msgid "%ld lines filtered"
+msgstr "¤w³B²z %ld ¦æ "
+
+msgid "E135: *Filter* Autocommands must not change current buffer"
+msgstr "E135: *Filter* Autocommand ¤£¥i¥H§ó§ï½w½Ä°Ïªº¤º®e"
+
+msgid "[No write since last change]\n"
+msgstr "[§ó·s«á©|¥¼Àx¦s]\n"
+
+#, c-format
+msgid "%sviminfo: %s in line: "
+msgstr "%sviminfo: %s ¦b¦æ¤¤: "
+
+msgid "E136: viminfo: Too many errors, skipping rest of file"
+msgstr "E136: viminfo: ¹L¦h¿ù»~, ©¿²¤Àɮרä¾l³¡¤À"
+
+#, c-format
+msgid "Reading viminfo file \"%s\"%s%s%s"
+msgstr "Ū¨ú viminfo ÀÉ®× \"%s\"%s%s%s"
+
+msgid " info"
+msgstr " °T®§"
+
+msgid " marks"
+msgstr " ¼Ð°O"
+
+msgid " FAILED"
+msgstr " ¥¢±Ñ"
+
+#, c-format
+msgid "E137: Viminfo file is not writable: %s"
+msgstr "E137: Viminfo ÀÉ®×µLªk¼g¤J: %s"
+
+#, c-format
+msgid "E138: Can't write viminfo file %s!"
+msgstr "E138: µLªk¼g¤J viminfo ÀÉ®× %s !"
+
+#, c-format
+msgid "Writing viminfo file \"%s\""
+msgstr "¼g¤J viminfo ÀÉ®× \"%s\" ¤¤"
+
+#. Write the info:
+#, c-format
+msgid "# This viminfo file was generated by Vim %s.\n"
+msgstr "# ¥» viminfo Àɮ׬O¥Ñ Vim %s ©Ò²£¥Í.\n"
+
+#, c-format
+msgid ""
+"# You may edit it if you're careful!\n"
+"\n"
+msgstr ""
+"# ¦pªG·Q­n¦Û¦æ­×§ï½Ð¯S§O¤p¤ß¡I\n"
+"\n"
+
+#, c-format
+msgid "# Value of 'encoding' when this file was written\n"
+msgstr "# 'encoding' ¦b¦¹Àɫإ߮ɪº­È\n"
+
+msgid "Illegal starting char"
+msgstr "µL®Äªº°_©l¦r¤¸"
+
+msgid "Save As"
+msgstr "¥t¦s·sÀÉ"
+
+#. Overwriting a file that is loaded in another buffer is not a
+#. * good idea.
+msgid "E139: File is loaded in another buffer"
+msgstr "E139: ±z¦b¥t¤@­Ó½w½Ä°Ï¤]¸ü¤J¤F³o­ÓÀÉ®×"
+
+msgid "Write partial file?"
+msgstr "­n¼g¤J³¡¤ÀÀɮ׶ܡH"
+
+msgid "E140: Use ! to write partial buffer"
+msgstr "E140: ½Ð¨Ï¥Î ! ¥H¼g¤J³¡¤À½w½Ä°Ï"
+
+#, c-format
+msgid "Overwrite existing file \"%.*s\"?"
+msgstr "­nÂмg¤w¦s¦bªºÀÉ®× \"%.*s\"¡H"
+
+#, c-format
+msgid "E141: No file name for buffer %ld"
+msgstr "E141: ½w½Ä°Ï %ld ¨S¦³ÀɮצWºÙ"
+
+msgid "E142: File not written: Writing is disabled by 'write' option"
+msgstr "E142: ÀÉ®×¥¼¼g¤J¡A¦]¬° 'write' ¿ï¶µ³QÃö³¬"
+
+#, c-format
+msgid ""
+"'readonly' option is set for \"%.*s\".\n"
+"Do you wish to write anyway?"
+msgstr ""
+"\"%.*s\" ¤w³]©w 'readonly' ¿ï¶µ.\n"
+"½T©w­nÂмg¶Ü¡H"
+
+msgid "Edit File"
+msgstr "½s¿èÀÉ®×"
+
+#, c-format
+msgid "E143: Autocommands unexpectedly deleted new buffer %s"
+msgstr "E143: Autocommands ·N¥~¦a§R°£·s½w½Ä°Ï %s"
+
+msgid "E144: non-numeric argument to :z"
+msgstr "E144: :z ¤£±µ¨ü«D¼Æ¦rªº°Ñ¼Æ"
+
+msgid "E145: Shell commands not allowed in rvim"
+msgstr "E145: rvim ¤¤¸T¤î¨Ï¥Î shell ©R¥O"
+
+msgid "E146: Regular expressions can't be delimited by letters"
+msgstr "E146: Regular expression µLªk¥Î¦r¥À¤À¹j (?)"
+
+#, c-format
+msgid "replace with %s (y/n/a/q/l/^E/^Y)?"
+msgstr "¨ú¥N¬° %s (y/n/a/q/^E/^Y)?"
+
+msgid "(Interrupted) "
+msgstr "(¤w¤¤Â_) "
+
+msgid "1 substitution"
+msgstr "¨ú¥N¤@²Õ "
+
+#, c-format
+msgid "%ld substitutions"
+msgstr "¨ú¥N %ld ²Õ "
+
+msgid " on 1 line"
+msgstr "¡A½d³ò¡G¤@¦æ "
+
+#, c-format
+msgid " on %ld lines"
+msgstr "¡A½d³ò¡G %ld ¦æ "
+
+msgid "E147: Cannot do :global recursive"
+msgstr "E147: :global µLªk»¼°j°õ¦æ "
+
+msgid "E148: Regular expression missing from global"
+msgstr "E148: ¨S¦³¨Ï¥Î¹L Regular expression (?)"
+
+#, c-format
+msgid "Pattern found in every line: %s"
+msgstr "¨C¤@¦æ³£§ä¤£¨ì: %s"
+
+#, c-format
+msgid ""
+"\n"
+"# Last Substitute String:\n"
+"$"
+msgstr ""
+"\n"
+"# «e¤@²Õ´À¥N¦r¦ê:\n"
+"$"
+
+msgid "E478: Don't panic!"
+msgstr "E478: ¤£­nÅå·W!"
+
+#, c-format
+msgid "E661: Sorry, no '%s' help for %s"
+msgstr "E661: ©êºp, ¨S¦³Ãö©ó %s-%s ªº»¡©ú"
+
+#, c-format
+msgid "E149: Sorry, no help for %s"
+msgstr "E149: ©êºp, ¨S¦³ %s ªº»¡©ú"
+
+#, c-format
+msgid "Sorry, help file \"%s\" not found"
+msgstr "©êºp, §ä¤£¨ì»¡©úÀÉ \"%s\""
+
+#, c-format
+msgid "E150: Not a directory: %s"
+msgstr "E150: %s ¤£¬O¥Ø¿ý"
+
+#, c-format
+msgid "E152: Cannot open %s for writing"
+msgstr "E152: µLªk¥H¼g¤J¼Ò¦¡¶}±Ò \"%s\""
+
+#, c-format
+msgid "E153: Unable to open %s for reading"
+msgstr "E153: µLªkŪ¨úÀÉ®×: %s"
+
+#, c-format
+msgid "E670: Mix of help file encodings within a language: %s"
+msgstr "E670: ¦P¤@»y¨¥ (%s) ¤¤¦³²V¦X¤£¦P¦r¤¸½s½Xªº»¡©úÀÉ"
+
+#, c-format
+msgid "E154: Duplicate tag \"%s\" in file %s"
+msgstr "E154: ¼ÐÅÒ(tag) \"%s\" ¦bÀÉ®× %s ¸Ì­«½Æ¥X²{¦h¦¸"
+
+#, c-format
+msgid "E160: Unknown sign command: %s"
+msgstr "E160: ¥¼©w¸qªº sign command: %s"
+
+msgid "E156: Missing sign name"
+msgstr "E156: ¯Ê¤Ö sign ¦WºÙ"
+
+msgid "E612: Too many signs defined"
+msgstr "E612: ¤w©w¸q¤Ó¦h signs"
+
+#, c-format
+msgid "E239: Invalid sign text: %s"
+msgstr "E239: ¤£¥¿½Tªº sign ¤å¦r: %s"
+
+#, c-format
+msgid "E155: Unknown sign: %s"
+msgstr "E155: ¤£¥¿½Tªº sign: %s"
+
+msgid "E159: Missing sign number"
+msgstr "E159: ¯Ê¤Ö sign number"
+
+#, c-format
+msgid "E158: Invalid buffer name: %s"
+msgstr "E158: ½w½Ä°Ï¦WºÙ¿ù»~: %s"
+
+#, c-format
+msgid "E157: Invalid sign ID: %ld"
+msgstr "E157: Sign ID ¿ù»~: %ld"
+
+msgid " (NOT FOUND)"
+msgstr " (§ä¤£¨ì) "
+
+msgid " (not supported)"
+msgstr " (¤£¤ä´©) "
+
+msgid "[Deleted]"
+msgstr "[¤w§R°£]"
+
+msgid "Entering Debug mode. Type \"cont\" to continue."
+msgstr "¶i¤J°£¿ù¼Ò¦¡. ¿é¤J \"cont\" ¥H¦^¨ì¥¿±`¼Ò¦¡."
+
+#, c-format
+msgid "line %ld: %s"
+msgstr "¦æ %ld: %s"
+
+#, c-format
+msgid "cmd: %s"
+msgstr "cmd: %s"
+
+#, c-format
+msgid "Breakpoint in \"%s%s\" line %ld"
+msgstr "\"%s%s\" ¤¤Â_ÂI: ²Ä %ld ¦æ "
+
+#, c-format
+msgid "E161: Breakpoint not found: %s"
+msgstr "E161: §ä¤£¨ì¤¤Â_ÂI: %s"
+
+msgid "No breakpoints defined"
+msgstr "¨S¦³©w¸q¤¤Â_ÂI"
+
+#, c-format
+msgid "%3d %s %s line %ld"
+msgstr "%3d %s %s ²Ä %ld ¦æ "
+
+#, c-format
+msgid "Save changes to \"%.*s\"?"
+msgstr "±NÅܰʦsÀx¦Ü \"%.*s\"?"
+
+msgid "Untitled"
+msgstr "¥¼©R¦W"
+
+#, c-format
+msgid "E162: No write since last change for buffer \"%s\""
+msgstr "E162: ¤w§ó§ï¹L½w½Ä°Ï \"%s\" ¦ý©|¥¼¦sÀÉ (¥i¥Î ! ±j¨î°õ¦æ)"
+
+msgid "Warning: Entered other buffer unexpectedly (check autocommands)"
+msgstr "ª`·N: ¤w¤Á´«¨ì¨ä¥¦½w½Ä°Ï (½ÐÀˬd Autocommands ¦³µL¿ù»~)"
+
+msgid "E163: There is only one file to edit"
+msgstr "E163: ¥u¦³¤@­ÓÀÉ®×¥i½s¿è"
+
+msgid "E164: Cannot go before first file"
+msgstr "E164: ¤w¸g¦b²Ä¤@­ÓÀɮפF"
+
+msgid "E165: Cannot go beyond last file"
+msgstr "E165: ¤w¸g¦b³Ì«á¤@­ÓÀɮפF"
+
+#, c-format
+msgid "E666: compiler not supported: %s"
+msgstr "E666: ½sĶ¾¹¤£¤ä´©: %s"
+
+#, c-format
+msgid "Searching for \"%s\" in \"%s\""
+msgstr "·j´M¤¤: \"%s\" -- \"%s\""
+
+#, c-format
+msgid "Searching for \"%s\""
+msgstr "·j´M¤¤: \"%s\""
+
+#, c-format
+msgid "not found in 'runtimepath': \"%s\""
+msgstr "¦b 'runtimepath' ¸Ì§ä¤£¨ì \"%s\""
+
+msgid "Source Vim script"
+msgstr "°õ¦æ Vim script"
+
+#, c-format
+msgid "Cannot source a directory: \"%s\""
+msgstr "µLªk°õ¦æ¥Ø¿ý¡G \"%s\""
+
+#, c-format
+msgid "could not source \"%s\""
+msgstr "µLªk°õ¦æ \"%s\""
+
+#, c-format
+msgid "line %ld: could not source \"%s\""
+msgstr "²Ä %ld ¦æ: µLªk°õ¦æ \"%s\""
+
+#, c-format
+msgid "sourcing \"%s\""
+msgstr "°õ¦æ \"%s\" ¤¤"
+
+#, c-format
+msgid "line %ld: sourcing \"%s\""
+msgstr "²Ä %ld ¦æ: µ²§ô°õ¦æ %s"
+
+#, c-format
+msgid "finished sourcing %s"
+msgstr "µ²§ô°õ¦æ %s"
+
+msgid "W15: Warning: Wrong line separator, ^M may be missing"
+msgstr "W15: ª`·N: ¿ù»~ªº¦æ¤À¹j¦r¤¸¡A¥i¯à¬O¤Ö¤F ^M"
+
+msgid "E167: :scriptencoding used outside of a sourced file"
+msgstr "E167: ¦b°õ¦æ script ÀÉ®×¥~¤£¥i¨Ï¥Î :scriptencoding"
+
+msgid "E168: :finish used outside of a sourced file"
+msgstr "E168: ¦b°õ¦æ script ÀÉ®×¥~¤£¥i¨Ï¥Î :finish"
+
+#, c-format
+msgid "Page %d"
+msgstr "²Ä %d ­¶"
+
+msgid "No text to be printed"
+msgstr "¨S¦³­n¦C¦Lªº¤å¦r"
+
+#, c-format
+msgid "Printing page %d (%d%%)"
+msgstr "¦C¦L¤¤: ²Ä %d ­¶ (%d%%)"
+
+#, c-format
+msgid " Copy %d of %d"
+msgstr "½Æ»s %d / %d"
+
+#, c-format
+msgid "Printed: %s"
+msgstr "¤w¦C¦L: %s"
+
+#, c-format
+msgid "Printing aborted"
+msgstr "¤w¨ú®ø¦C¦L"
+
+msgid "E455: Error writing to PostScript output file"
+msgstr "E455: µLªk¼g¤J PostScript ¿é¥XÀÉ"
+
+#, c-format
+msgid "E624: Can't open file \"%s\""
+msgstr "E624: µLªk¶}±ÒÀÉ®× \"%s\""
+
+#, c-format
+msgid "E457: Can't read PostScript resource file \"%s\""
+msgstr "E457: µLªkŪ¨ú PostScript ¸ê·½ÀÉ \"%s\""
+
+#, c-format
+msgid "E618: file \"%s\" is not a PostScript resource file"
+msgstr "E618: ÀÉ®× \"%s\" ¤£¬O PostScript ¸ê·½ÀÉ "
+
+#, c-format
+msgid "E619: file \"%s\" is not a supported PostScript resource file"
+msgstr "E619: ¤£¤ä´© PostScript ¸ê·½ÀÉ \"%s\""
+
+#, c-format
+msgid "E621: \"%s\" resource file has wrong version"
+msgstr "E621: \"%s\" ¸ê·½Àɪ©¥»¿ù»~"
+
+msgid "E324: Can't open PostScript output file"
+msgstr "E324: µLªk¶}±Ò PostScript ¿é¥XÀÉ"
+
+#, c-format
+msgid "E456: Can't open file \"%s\""
+msgstr "E456: µLªk¶}±ÒÀÉ®× \"%s\""
+
+msgid "E456: Can't find PostScript resource file \"prolog.ps\""
+msgstr "E456: µLªkŪ¨ú PostScript ¸ê·½ÀÉ \"prolog.ps\""
+
+#, c-format
+msgid "E456: Can't find PostScript resource file \"%s.ps\""
+msgstr "E456: µLªkŪ¨ú PostScript ¸ê·½ÀÉ \"%s.ps\""
+
+#, c-format
+msgid "E620: Unable to convert from multi-byte to \"%s\" encoding"
+msgstr "E620:µLªkÂà´«¦Ü \"%s\" ¦r¤¸½s½X"
+
+msgid "Sending to printer..."
+msgstr "¶Ç°e¸ê®Æ¨ì¦Lªí¾÷..."
+
+msgid "E365: Failed to print PostScript file"
+msgstr "E365: µLªk¦C¦L PostScript ÀÉ®×"
+
+msgid "Print job sent."
+msgstr "¤w°e¥X¦C¦L¤u§@¡C"
+
+#, c-format
+msgid "Current %slanguage: \"%s\""
+msgstr "¥Ø«eªº %s»y¨¥: \"%s\""
+
+#, c-format
+msgid "E197: Cannot set language to \"%s\""
+msgstr "E197: ¤£¯à³]©w»y¨¥¦¨ \"%s\""
+
+msgid "Entering Ex mode. Type \"visual\" to go to Normal mode."
+msgstr "¶i¤J Ex ¼Ò¦¡. ¿é¤J \"visua\" ¥H¦^¨ì¥¿±`¼Ò¦¡."
+
+#. must be at EOF
+msgid "E501: At end-of-file"
+msgstr "E501: ¤w¨ìÀÉ®×µ²§À"
+
+msgid "E169: Command too recursive"
+msgstr "E169: ©R¥O»¼°j¼h¼Æ¹L¦h"
+
+#, c-format
+msgid "E605: Exception not caught: %s"
+msgstr "E605: ¥¼ÄdºIªº¨Ò¥~¡G %s"
+
+msgid "End of sourced file"
+msgstr "©R¥OÀɵ²§ô"
+
+msgid "End of function"
+msgstr "¨ç¦¡µ²§À"
+
+msgid "E464: Ambiguous use of user-defined command"
+msgstr "E464: ¨Ï¥ÎªÌ©w¸qªº©R¥O·|²V²c"
+
+msgid "E492: Not an editor command"
+msgstr "E492: ¤£¬O½s¿è¾¹ªº©R¥O"
+
+msgid "E493: Backwards range given"
+msgstr "E493: «ü©w¤F¦V«e°Ñ¦Òªº½d³ò"
+
+msgid "Backwards range given, OK to swap"
+msgstr "«ü©w¤F¦V«e°Ñ¦Òªº½d³ò¡AOK to swap"
+
+msgid "E494: Use w or w>>"
+msgstr "E494: ½Ð¨Ï¥Î w ©Î w>>"
+
+msgid "E319: Sorry, the command is not available in this version"
+msgstr "E319: ©êºp, ¥»©R¥O¦b¦¹ª©¥»¤¤¨S¦³¹ê§@"
+
+msgid "E172: Only one file name allowed"
+msgstr "E172: ¥u¯à¦³¤@­ÓÀÉ"
+
+msgid "1 more file to edit. Quit anyway?"
+msgstr "ÁÙ¦³¤@­ÓÀÉ®×¥¼½s¿è. ½T©w­nÂ÷¶}¡H"
+
+#, c-format
+msgid "%d more files to edit. Quit anyway?"
+msgstr "ÁÙ¦³ %d ­ÓÀÉ®×¥¼½s¿è. ½T©w­nÂ÷¶}¡H"
+
+msgid "E173: 1 more file to edit"
+msgstr "E173: ÁÙ¦³¤@­ÓÀÉ®×¥¼½s¿è "
+
+#, c-format
+msgid "E173: %ld more files to edit"
+msgstr "E173: ÁÙ¦³ %ld ­ÓÀÉ®×¥¼½s¿è"
+
+msgid "E174: Command already exists: add ! to replace it"
+msgstr "E174: ©R¥O¤w¸g¦s¦b, ½Ð¨Ï¥Î ! ±j¨î­«·s©w¸q"
+
+msgid ""
+"\n"
+" Name Args Range Complete Definition"
+msgstr ""
+"\n"
+" ¦WºÙ °Ñ¼Æ ½d³ò §¹¾ã ©w¸q "
+
+msgid "No user-defined commands found"
+msgstr "§ä¤£¨ì¨Ï¥ÎªÌ©w¸qªº©R¥O"
+
+msgid "E175: No attribute specified"
+msgstr "E175: ¨S¦³«ü©wªºÄÝ©Ê"
+
+msgid "E176: Invalid number of arguments"
+msgstr "E176: ¤£¥¿½Tªº°Ñ¼Æ¼Æ¥Ø"
+
+msgid "E177: Count cannot be specified twice"
+msgstr "E177: ¤£¯à«ü©w¨â¦¸¼Æ¥Ø"
+
+msgid "E178: Invalid default value for count"
+msgstr "E178: ¼Æ¥Øªº¹w³]°Ñ¼Æ¤£¥¿½T"
+
+msgid "E179: argument required for complete"
+msgstr "E179: «ü¥O»Ý­n°Ñ¼Æ¤~¯à§¹¦¨"
+
+#, c-format
+msgid "E180: Invalid complete value: %s"
+msgstr "E180: ¤£§¹¾ãªº­È: '%s'"
+
+msgid "E468: Completion argument only allowed for custom completion"
+msgstr "E468: ¦Û­q¸É§¹®É¤~¥i¸É§¹°Ñ¼Æ"
+
+msgid "E467: Custom completion requires a function argument"
+msgstr "E467: ¦Û­q¸É§¹»Ý­n¨ç¦¡¬°°Ñ¼Æ"
+
+#, c-format
+msgid "E181: Invalid attribute: %s"
+msgstr "E181: ¤£¥¿½TªºÄÝ©Ê: %s"
+
+msgid "E182: Invalid command name"
+msgstr "E182: «ü¥O¦WºÙ¤£¥¿½T"
+
+msgid "E183: User defined commands must start with an uppercase letter"
+msgstr "E183: ¨Ï¥ÎªÌ¦Û©w«ü¥O¥²¶·¥H¤j¼g¦r¥À¶}©l"
+
+#, c-format
+msgid "E184: No such user-defined command: %s"
+msgstr "E184: ¨S¦³¨Ï¥ÎªÌ¦Û©wªº©R¥O¡G %s"
+
+#, c-format
+msgid "E185: Cannot find color scheme %s"
+msgstr "E185: §ä¤£¨ìÃC¦â¼Ë¦¡ %s"
+
+msgid "Greetings, Vim user!"
+msgstr "¶Ù, Vim ¨Ï¥ÎªÌ¡I"
+
+msgid "Edit File in new window"
+msgstr "¦b·sµøµ¡½s¿èÀÉ®×"
+
+msgid "No swap file"
+msgstr "µL¼È¦sÀÉ"
+
+msgid "Append File"
+msgstr "ªþ¥[ÀÉ®×"
+
+msgid "E186: No previous directory"
+msgstr "E186: ¨S¦³«e¤@­Ó¥Ø¿ý"
+
+msgid "E187: Unknown"
+msgstr "E187: µLªk¿ìÃѪº¼Ð°O"
+
+msgid "E465: :winsize requires two number arguments"
+msgstr "E465: :winsize »Ý­n¨â­Ó°Ñ¼Æ"
+
+#, c-format
+msgid "Window position: X %d, Y %d"
+msgstr "µøµ¡¦ì¸m: X %d, Y %d"
+
+msgid "E188: Obtaining window position not implemented for this platform"
+msgstr "E188: ¦b±zªº¥­¥x¤WµLªkÀò±oµøµ¡¦ì¸m"
+
+msgid "E466: :winpos requires two number arguments"
+msgstr "E466: :winpos »Ý­n¨â­Ó°Ñ¼Æ"
+
+msgid "Save Redirection"
+msgstr "Àx¦s Redirection"
+
+msgid "Save View"
+msgstr "Àx¦s View"
+
+msgid "Save Session"
+msgstr "Àx¦s Session"
+
+msgid "Save Setup"
+msgstr "Àx¦s³]©w"
+
+#, c-format
+msgid "E189: \"%s\" exists (add ! to override)"
+msgstr "E189: \"%s\" ¤w¦s¦b (½Ð¥Î ! ±j¨î°õ¦æ)"
+
+#, c-format
+msgid "E190: Cannot open \"%s\" for writing"
+msgstr "E190: µLªk¥H¼g¤J¼Ò¦¡¶}±Ò \"%s\""
+
+#. set mark
+msgid "E191: Argument must be a letter or forward/backward quote"
+msgstr "E191: °Ñ¼Æ¥²¶·¬O­^¤å¦r¥À©Î¦V«e/«áªº¤Þ¸¹"
+
+msgid "E192: Recursive use of :normal too deep"
+msgstr "E192: :normal »¼°j¼h¼Æ¹L²`"
+
+msgid "E194: No alternate file name to substitute for '#'"
+msgstr "E194: ¨S¦³ '#' ¥i´À¥NªºÀɦW"
+
+msgid "E495: no autocommand file name to substitute for \"<afile>\""
+msgstr "E495: ¨S¦³ Autocommand ÀɦW¥H¨ú¥N \"<afile>\""
+
+msgid "E496: no autocommand buffer number to substitute for \"<abuf>\""
+msgstr "E496: ¨S¦³ Autocommand ½w½Ä°Ï¦WºÙ¥H¨ú¥N \"<abuf>\""
+
+msgid "E497: no autocommand match name to substitute for \"<amatch>\""
+msgstr "E497: ¨S¦³ Autocommand ²Å¦X¦WºÙ¥H¨ú¥N \"<amatch>\""
+
+msgid "E498: no :source file name to substitute for \"<sfile>\""
+msgstr "E498: ¨S¦³ :source ÀɦW¥H¨ú¥N \"<sfile>\""
+
+#, no-c-format
+msgid "E499: Empty file name for '%' or '#', only works with \":p:h\""
+msgstr "E499: '%' ©Î '#' «ü¦VªÅÀɦW¡A¥u¯à¥Î©ó \":p:h\""
+
+msgid "E500: Evaluates to an empty string"
+msgstr "E500: ¿é¤J¬°ªÅ¦r¦ê"
+
+msgid "E195: Cannot open viminfo file for reading"
+msgstr "E195: µLªkŪ¨ú viminfo"
+
+msgid "E196: No digraphs in this version"
+msgstr "E196: ¥»ª©¥»µL½Æ¦X¦r¤¸(digraph)"
+
+msgid "E608: Cannot :throw exceptions with 'Vim' prefix"
+msgstr "E608: ¤£¯à :throw ¥Î 'Vim' ¶}ÀYªº¨Ò¥~"
+
+#. always scroll up, don't overwrite
+#, c-format
+msgid "Exception thrown: %s"
+msgstr "¥á¥X¨Ò¥~¡G %s"
+
+#, c-format
+msgid "Exception finished: %s"
+msgstr "¨Ò¥~µ²§ô¡G %s"
+
+#, c-format
+msgid "Exception discarded: %s"
+msgstr "¤w¥á±ó¨Ò¥~¡G %s"
+
+#, c-format
+msgid "%s, line %ld"
+msgstr "%s, ¦æ %ld"
+
+#. always scroll up, don't overwrite
+#, c-format
+msgid "Exception caught: %s"
+msgstr "µo¥Í¨Ò¥~¡G%s"
+
+#, c-format
+msgid "%s made pending"
+msgstr "%s ³y¦¨ pending"
+
+#, c-format
+msgid "%s resumed"
+msgstr "%s ¤w¦^´_"
+
+#, c-format
+msgid "%s discarded"
+msgstr "%s ¤w¥á±ó"
+
+msgid "Exception"
+msgstr "¨Ò¥~"
+
+msgid "Error and interrupt"
+msgstr "¿ù»~»P¤¤Â_"
+
+msgid "Error"
+msgstr "¿ù»~"
+
+#. if (pending & CSTP_INTERRUPT)
+msgid "Interrupt"
+msgstr "¤¤Â_"
+
+msgid "E579: :if nesting too deep"
+msgstr "E579: :if ¼h¼Æ¹L²`"
+
+msgid "E580: :endif without :if"
+msgstr "E580: :endif ¯Ê¤Ö¹ïÀ³ªº :if"
+
+msgid "E581: :else without :if"
+msgstr "E581: :else ¯Ê¤Ö¹ïÀ³ªº :if"
+
+msgid "E582: :elseif without :if"
+msgstr "E582: :elseif ¯Ê¤Ö¹ïÀ³ªº :if"
+
+msgid "E583: multiple :else"
+msgstr "E583: ¦h­« :else"
+
+msgid "E584: :elseif after :else"
+msgstr "E584: :elseif ¦b :else ¤§«á"
+
+msgid "E585: :while nesting too deep"
+msgstr "E585: :while ¼h¼Æ¹L²`"
+
+msgid "E586: :continue without :while"
+msgstr "E586: :continue ¯Ê¤Ö¹ïÀ³ªº :while"
+
+msgid "E587: :break without :while"
+msgstr "E587: :break ¯Ê¤Ö¹ïÀ³ªº :while"
+
+msgid "E601: :try nesting too deep"
+msgstr "E601: :if ¼h¼Æ¹L²`"
+
+msgid "E603: :catch without :try"
+msgstr "E603: :catch ¨S¦³ :try"
+
+#. Give up for a ":catch" after ":finally" and ignore it.
+#. * Just parse.
+msgid "E604: :catch after :finally"
+msgstr "E604: :catch ¦b :finally ¤§«á"
+
+msgid "E606: :finally without :try"
+msgstr "E606: :finally ¨S¦³ :try"
+
+#. Give up for a multiple ":finally" and ignore it.
+msgid "E607: multiple :finally"
+msgstr "E607: ¦h­« :finally"
+
+msgid "E602: :endtry without :try"
+msgstr "E602: :endif ¯Ê¤Ö¹ïÀ³ªº :if"
+
+msgid "E193: :endfunction not inside a function"
+msgstr "E193: :endfunction ¥²¶·¦b¨ç¦¡¤º³¡¨Ï¥Î"
+
+msgid "tagname"
+msgstr "¼ÐÅÒ¦WºÙ"
+
+msgid " kind file\n"
+msgstr "ÃþÀÉ®×\n"
+
+msgid "'history' option is zero"
+msgstr "¿ï¶µ 'history' ¬O¹s"
+
+#, c-format
+msgid ""
+"\n"
+"# %s History (newest to oldest):\n"
+msgstr ""
+"\n"
+"# %s ¾ú¥v°O¿ý (·s¨ìÂÂ):\n"
+
+msgid "Command Line"
+msgstr "©R¥O¦C"
+
+msgid "Search String"
+msgstr "·j´M¦r¦ê"
+
+msgid "Expression"
+msgstr "¹Bºâ¦¡"
+
+msgid "Input Line"
+msgstr "¿é¤J¦æ "
+
+msgid "E198: cmd_pchar beyond the command length"
+msgstr "E198: cmd_pchar ¶W¹L©R¥Oªø«×"
+
+msgid "E199: Active window or buffer deleted"
+msgstr "E199: ¤w§R°£±¼§@¥Î¤¤ªºµøµ¡©Î¼È¦s°Ï"
+
+msgid "Illegal file name"
+msgstr "¤£¥¿½TªºÀɦW"
+
+msgid "is a directory"
+msgstr "¬O¥Ø¿ý"
+
+msgid "is not a file"
+msgstr "¤£¬OÀÉ®×"
+
+msgid "[New File]"
+msgstr "[¥¼©R¦W]"
+
+msgid "[Permission Denied]"
+msgstr "[Åv­­¤£¨¬]"
+
+msgid "E200: *ReadPre autocommands made the file unreadable"
+msgstr "E200: *ReadPre Autocommand ¨Ïµ{¦¡µLªkŪ¨ú¦¹ÀÉ"
+
+msgid "E201: *ReadPre autocommands must not change current buffer"
+msgstr "E201: *Filter* Autocommand ¤£¥i¥H§ó§ï½w½Ä°Ïªº¤º®e"
+
+msgid "Vim: Reading from stdin...\n"
+msgstr "Vim: ±q¼Ð·Ç¿é¤JŪ¨ú...\n"
+
+msgid "Reading from stdin..."
+msgstr "±q¼Ð·Ç¿é¤JŪ¨ú..."
+
+#. Re-opening the original file failed!
+msgid "E202: Conversion made file unreadable!"
+msgstr "E202: Âà´«¿ù»~"
+
+msgid "[fifo/socket]"
+msgstr "[fifo/socket]"
+
+msgid "[fifo]"
+msgstr "[fifo]"
+
+msgid "[socket]"
+msgstr "[socket]"
+
+msgid "[RO]"
+msgstr "[°ßŪ]"
+
+msgid "[CR missing]"
+msgstr "[¯Ê¤ÖCR]'"
+
+msgid "[NL found]"
+msgstr "[§ä¨ìNL]"
+
+msgid "[long lines split]"
+msgstr "[¤À³Î¹Lªø¦æ]"
+
+msgid "[NOT converted]"
+msgstr "[¥¼Âà´«]"
+
+msgid "[converted]"
+msgstr "[¤wÂà´«]"
+
+msgid "[crypted]"
+msgstr "[¤w¥[±K]"
+
+msgid "[CONVERSION ERROR]"
+msgstr "Âà´«¿ù»~"
+
+#, c-format
+msgid "[ILLEGAL BYTE in line %ld]"
+msgstr "[¦æ %ld ¦³¤£¥¿½Tªº¦ì¤¸]"
+
+msgid "[READ ERRORS]"
+msgstr "[Ū¨ú¿ù»~]"
+
+msgid "Can't find temp file for conversion"
+msgstr "§ä¤£¨ìÂà´«¥Îªº¼È¦sÀÉ"
+
+msgid "Conversion with 'charconvert' failed"
+msgstr "¦r¤¸¶°Âà´«¿ù»~"
+
+msgid "can't read output of 'charconvert'"
+msgstr "µLªkŪ¨ú 'charconvert' ªº¿é¥X"
+
+msgid "E203: Autocommands deleted or unloaded buffer to be written"
+msgstr "E203: Autocommand §R°£©ÎÄÀ©ñ¤F­n¼g¤Jªº½w½Ä°Ï"
+
+msgid "E204: Autocommand changed number of lines in unexpected way"
+msgstr "E204: Autocommand ·N¥~¦a§ïÅܤF¦æ¸¹"
+
+msgid "NetBeans disallows writes of unmodified buffers"
+msgstr "NetBeans ¤£¯à¼g¥X¥¼­×§ïªº½w½Ä°Ï"
+
+msgid "Partial writes disallowed for NetBeans buffers"
+msgstr "³¡¥÷¤º®eµLªk¼g¤J Netbeans ½w½Ä°Ï"
+
+msgid "is not a file or writable device"
+msgstr "¤£¬OÀɮשΥi¼g¤Jªº¸Ë¸m"
+
+msgid "is read-only (add ! to override)"
+msgstr "¬O°ßŪÀÉ (½Ð¨Ï¥Î ! ±j¨î°õ¦æ)"
+
+msgid "E506: Can't write to backup file (add ! to override)"
+msgstr "E506: µLªk¼g¤J³Æ¥÷ÀÉ (½Ð¨Ï¥Î ! ±j¨î°õ¦æ)"
+
+msgid "E507: Close error for backup file (add ! to override)"
+msgstr "E507: µLªkÃö³¬³Æ¥÷ÀÉ (½Ð¨Ï¥Î ! ±j¨î°õ¦æ)"
+
+msgid "E508: Can't read file for backup (add ! to override)"
+msgstr "E508: µLªkŪ¨úÀÉ®×¥H¨Ñ³Æ¥÷ (½Ð¨Ï¥Î ! ±j¨î°õ¦æ)"
+
+msgid "E509: Cannot create backup file (add ! to override)"
+msgstr "E509: µLªk«Ø¥ß³Æ¥÷ÀÉ (½Ð¨Ï¥Î ! ±j¨î°õ¦æ)"
+
+msgid "E510: Can't make backup file (add ! to override)"
+msgstr "E510: µLªk»s§@³Æ¥÷ÀÉ (½Ð¨Ï¥Î ! ±j¨î°õ¦æ)"
+
+msgid "E460: The resource fork would be lost (add ! to override)"
+msgstr "E460: Resource fork ·|®ø¥¢ (½Ð¨Ï¥Î ! ±j¨î°õ¦æ)"
+
+msgid "E214: Can't find temp file for writing"
+msgstr "E214: §ä¤£¨ì¼g¤J¥Îªº¼È¦sÀÉ"
+
+msgid "E213: Cannot convert (add ! to write without conversion)"
+msgstr "E213: µLªkÂà´« (½Ð¨Ï¥Î ! ±j¨î¤£Âà´«¼g¤J)"
+
+msgid "E166: Can't open linked file for writing"
+msgstr "E166: µLªk¥H¼g¤J¼Ò¦¡¶}±Ò³sµ²ÀÉ®×"
+
+msgid "E212: Can't open file for writing"
+msgstr "E212: µLªk¥H¼g¤J¼Ò¦¡¶}±Ò"
+
+msgid "E667: Fsync failed"
+msgstr "E667: Fsync ©R¥O°õ¦æ¥¢±Ñ"
+
+msgid "E512: Close failed"
+msgstr "E512: Ãö³¬¥¢±Ñ"
+
+msgid "E513: write error, conversion failed"
+msgstr "E513: µLªk¼g¤J -- Âà´«¥¢±Ñ"
+
+msgid "E514: write error (file system full?)"
+msgstr "E514: ¼g¤J¿ù»~ (Àɮרt²Î¤wº¡¡H)"
+
+msgid " CONVERSION ERROR"
+msgstr "Âà´«¿ù»~"
+
+msgid "[Device]"
+msgstr "[¸Ë¸m]"
+
+msgid "[New]"
+msgstr "[·s]"
+
+msgid " [a]"
+msgstr "[a]"
+
+msgid " appended"
+msgstr " ¤wªþ¥["
+
+msgid " [w]"
+msgstr "[w]"
+
+msgid " written"
+msgstr " ¤w¼g¤J"
+
+msgid "E205: Patchmode: can't save original file"
+msgstr "E205: Patch ¼Ò¦¡: µLªkÀx¦s­ì©lÀÉ®×"
+
+msgid "E206: patchmode: can't touch empty original file"
+msgstr "E206: Patch ¼Ò¦¡: µLªkÅܧóªÅªº­ì©lÀÉ®×"
+
+msgid "E207: Can't delete backup file"
+msgstr "E207: µLªk§R°£³Æ¥÷ÀÉ"
+
+msgid ""
+"\n"
+"WARNING: Original file may be lost or damaged\n"
+msgstr ""
+"\n"
+"ĵ§i: ­ì©lÀɮ׬y¥¢©Î·lÃa\n"
+
+msgid "don't quit the editor until the file is successfully written!"
+msgstr "¦bÀÉ®×¥¿½T¼g¤J«e½Ð¤ÅÂ÷¶}½s¿è¾¹!"
+
+msgid "[dos]"
+msgstr "[dos]"
+
+msgid "[dos format]"
+msgstr "[dos ®æ¦¡]"
+
+msgid "[mac]"
+msgstr "[mac]"
+
+msgid "[mac format]"
+msgstr "[mac ®æ¦¡]"
+
+msgid "[unix]"
+msgstr "[unix]"
+
+msgid "[unix format]"
+msgstr "[unix ®æ¦¡]"
+
+msgid "1 line, "
+msgstr "1 ¦æ, "
+
+#, c-format
+msgid "%ld lines, "
+msgstr "%ld ¦æ, "
+
+msgid "1 character"
+msgstr "¤@­Ó¦r¤¸"
+
+#, c-format
+msgid "%ld characters"
+msgstr "%ld­Ó¦r¤¸"
+
+msgid "[noeol]"
+msgstr "[noeol]"
+
+msgid "[Incomplete last line]"
+msgstr "[µ²§À¦æ¤£§¹¾ã]"
+
+#. don't overwrite messages here
+#. must give this prompt
+#. don't use emsg() here, don't want to flush the buffers
+msgid "WARNING: The file has been changed since reading it!!!"
+msgstr "ĵ§i: ¥»ÀɮצۤW¦¸Åª¤J«á¤wÅÜ°Ê!!!"
+
+msgid "Do you really want to write to it"
+msgstr "½T©w­n¼g¤J¶Ü"
+
+#, c-format
+msgid "E208: Error writing to \"%s\""
+msgstr "E208: ¼g¤JÀÉ®× \"%s\" ¿ù»~"
+
+#, c-format
+msgid "E209: Error closing \"%s\""
+msgstr "E209: Ãö³¬ÀÉ®× \"%s\" ¿ù»~"
+
+#, c-format
+msgid "E210: Error reading \"%s\""
+msgstr "E210: Ū¨úÀÉ®× \"%s\" ¿ù»~"
+
+msgid "E246: FileChangedShell autocommand deleted buffer"
+msgstr "E246: FileChangedShell autocommand §R°£½w½Ä°Ï"
+
+#, c-format
+msgid "E211: Warning: File \"%s\" no longer available"
+msgstr "E211: ĵ§i: ÀÉ®× \"%s\" ¤w¸g¤£¦s¦b"
+
+#, c-format
+msgid ""
+"W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as "
+"well"
+msgstr "W12: ĵ§i: ÀÉ®× \"%s\" ¦Û¤W¦¸Åª¤J«á¤wÅÜ°Ê, ¦Ó¥B½s¿è¤¤ªº½w½Ä°Ï¤]§ó°Ê¤F"
+
+#, c-format
+msgid "W11: Warning: File \"%s\" has changed since editing started"
+msgstr "W11: ĵ§i: ÀÉ®× \"%s\" ¦Û¤W¦¸Åª¤J«á¤wÅÜ°Ê"
+
+#, c-format
+msgid "W16: Warning: Mode of file \"%s\" has changed since editing started"
+msgstr "W16: ĵ§i: ÀÉ®× \"%s\" ªºÅv­­»P¤W¦¸Åª¤J®É¤£¤@¼Ë (¦³ÅܰʹL)"
+
+# 'mode' seems better as translated to 'permission'?
+#, c-format
+msgid "W13: Warning: File \"%s\" has been created after editing started"
+msgstr "W13: ĵ§i: ÀÉ®× \"%s\" ¦b¶}©l½s¿è«á¤S³Q«Ø¥ß¤F"
+
+msgid "See \":help W11\" for more info."
+msgstr "¶i¤@¨B»¡©ú½Ð¨£ \":help W11\"¡C"
+
+msgid "Warning"
+msgstr "ĵ§i"
+
+msgid ""
+"&OK\n"
+"&Load File"
+msgstr ""
+"½T©w(&O)\n"
+"¸ü¤JÀÉ®×(&L)"
+
+#, c-format
+msgid "E462: Could not prepare for reloading \"%s\""
+msgstr "E462: µLªk·Ç³Æ­«·s¸ü¤J \"%s\""
+
+#, c-format
+msgid "E321: Could not reload \"%s\""
+msgstr "E321: µLªk­«·s¸ü¤J \"%s\""
+
+msgid "--Deleted--"
+msgstr "--¤w§R°£--"
+
+#. the group doesn't exist
+#, c-format
+msgid "E367: No such group: \"%s\""
+msgstr "E367: µL¦¹¸s²Õ: \"%s\""
+
+#, c-format
+msgid "E215: Illegal character after *: %s"
+msgstr "E215: * «á­±¦³¤£¥¿½Tªº¦r¤¸: %s"
+
+#, c-format
+msgid "E216: No such event: %s"
+msgstr "E216: µL¦¹¨Æ¥ó: %s"
+
+#, c-format
+msgid "E216: No such group or event: %s"
+msgstr "E216: µL¦¹¸s²Õ©Î¨Æ¥ó: %s"
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Autocommands ---"
+msgstr ""
+"\n"
+"--- Autocommands ---"
+
+msgid "E217: Can't execute autocommands for ALL events"
+msgstr "E217: µLªk¹ï©Ò¦³¨Æ¥ó°õ¦æ autocommand"
+
+msgid "No matching autocommands"
+msgstr "§ä¤£¨ì¹ïÀ³ªº autocommand"
+
+msgid "E218: autocommand nesting too deep"
+msgstr "E218: autocommand ¼h¼Æ¹L²`"
+
+#, c-format
+msgid "%s Autocommands for \"%s\""
+msgstr "%s Autocommands: \"%s\""
+
+#, c-format
+msgid "Executing %s"
+msgstr "°õ¦æ %s"
+
+#. always scroll up, don't overwrite
+#, c-format
+msgid "autocommand %s"
+msgstr "autocommand %s"
+
+msgid "E219: Missing {."
+msgstr "E219: ¯Ê¤Ö {."
+
+msgid "E220: Missing }."
+msgstr "E220: ¯Ê¤Ö }."
+
+msgid "E490: No fold found"
+msgstr "E490: §ä¤£¨ì¥ô¦ó fold"
+
+msgid "E350: Cannot create fold with current 'foldmethod'"
+msgstr "E350: µLªk¦b¥Ø«eªº 'foldmethod' ¤U«Ø¥ß fold"
+
+msgid "E351: Cannot delete fold with current 'foldmethod'"
+msgstr "E351: µLªk¦b¥Ø«eªº 'foldmethod' ¤U§R°£ fold"
+
+msgid "E222: Add to read buffer"
+msgstr "E222: ¥[¤JŪ¨ú½w½Ä°Ï¤¤"
+
+msgid "E223: recursive mapping"
+msgstr "E223: »¼°j mapping"
+
+#, c-format
+msgid "E224: global abbreviation already exists for %s"
+msgstr "E224: %s ¤w¸g¦³¥þ°ì abbreviation ¤F"
+
+#, c-format
+msgid "E225: global mapping already exists for %s"
+msgstr "E225: %s ¤w¸g¦³¥þ°ì mapping ¤F"
+
+#, c-format
+msgid "E226: abbreviation already exists for %s"
+msgstr "E226: %s ¤w¸g¦³ abbreviation ¤F"
+
+#, c-format
+msgid "E227: mapping already exists for %s"
+msgstr "E227: %s ªº mapping ¤w¸g¦s¦b"
+
+msgid "No abbreviation found"
+msgstr "§ä¤£¨ì abbreviation"
+
+msgid "No mapping found"
+msgstr "¨S¦³³o­Ó mapping ¹ïÀ³"
+
+msgid "E228: makemap: Illegal mode"
+msgstr "E228: makemap: ¤£¥¿½Tªº¼Ò¦¡"
+
+msgid "E229: Cannot start the GUI"
+msgstr "E229: µLªk±Ò°Ê¹Ï«¬¬É­±"
+
+#, c-format
+msgid "E230: Cannot read from \"%s\""
+msgstr "E230: µLªkŪ¨úÀÉ®× \"%s\""
+
+msgid "E665: Cannot start GUI, no valid font found"
+msgstr "E665: µLªk±Ò°Ê¹Ï«¬¬É­±¡A§ä¤£¨ì¥i¥Îªº¦r«¬"
+
+msgid "E231: 'guifontwide' invalid"
+msgstr "E231: ¤£¥¿½Tªº 'guifontwide'"
+
+msgid "E599: Value of 'imactivatekey' is invalid"
+msgstr "E599: 'imactivatekey' ªº­È¤£¥¿½T"
+
+#, c-format
+msgid "E254: Cannot allocate color %s"
+msgstr "E254: ¤£¯à°t¸mÃC¦â %s"
+
+msgid "<cannot open> "
+msgstr "<¤£¯à¶}±Ò>"
+
+#, c-format
+msgid "E616: vim_SelFile: can't get font %s"
+msgstr "E616: vim_SelFile: ¤£¯à¨Ï¥Î %s ¦r«¬"
+
+msgid "E614: vim_SelFile: can't return to current directory"
+msgstr "E614: vim_SelFile: µLªk¦^¨ì¥Ø«e¥Ø¿ý"
+
+msgid "Pathname:"
+msgstr "¸ô®|:"
+
+msgid "E615: vim_SelFile: can't get current directory"
+msgstr "E615: vim_SelFile: µLªk¨ú±o¥Ø«e¥Ø¿ý"
+
+msgid "OK"
+msgstr "½T©w"
+
+msgid "Cancel"
+msgstr "¨ú®ø"
+
+msgid "Scrollbar Widget: Could not get geometry of thumb pixmap."
+msgstr "±²°Ê¶b: ¤£¯à³]©w thumb pixmap ªº¦ì¸m"
+
+msgid "Vim dialog"
+msgstr "Vim ¹ï¸Ü²°"
+
+msgid "E232: Cannot create BalloonEval with both message and callback"
+msgstr "E232: ¤£¯à¹ï°T®§»P callback «Ø¥ß BallonEval"
+
+msgid "Vim dialog..."
+msgstr "Vim ¹ï¸Ü²°..."
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"&Cancel"
+msgstr ""
+"&Y¬O\n"
+"&N§_\n"
+"&C¨ú®ø"
+
+msgid "Input _Methods"
+msgstr "¿é¤Jªk"
+
+msgid "VIM - Search and Replace..."
+msgstr "VIM - ´M§ä»P¨ú¥N..."
+
+msgid "VIM - Search..."
+msgstr "VIM - ´M§ä..."
+
+msgid "Find what:"
+msgstr "·j´M:"
+
+msgid "Replace with:"
+msgstr "¨ú¥N¬°:"
+
+#. whole word only button
+msgid "Match whole word only"
+msgstr "¥u·j´M§¹¥þ¬Û¦Pªº¦r"
+
+#. match case button
+msgid "Match case"
+msgstr "²Å¦X¤j¤p¼g"
+
+msgid "Direction"
+msgstr "¤è¦V"
+
+#. 'Up' and 'Down' buttons
+msgid "Up"
+msgstr "¦V¤W"
+
+msgid "Down"
+msgstr "¦V¤U"
+
+msgid "Find Next"
+msgstr "§ä¤U¤@­Ó"
+
+msgid "Replace"
+msgstr "¨ú¥N"
+
+msgid "Replace All"
+msgstr "¨ú¥N¥þ³¡"
+
+msgid "Vim: Received \"die\" request from session manager\n"
+msgstr "Vim: ¥Ñ Session ºÞ²z­û¦¬¨ì \"die\" ­n¨D\n"
+
+msgid "Vim: Main window unexpectedly destroyed\n"
+msgstr "Vim: ¥Dµøµ¡Äê±¼\n"
+
+msgid "Font Selection"
+msgstr "¦r«¬¿ï¾Ü"
+
+msgid "Used CUT_BUFFER0 instead of empty selection"
+msgstr "¨Ï¥Î CUT_BUFFER0 ¨Ó¨ú¥NªÅ¿ï¾Ü"
+
+msgid "Filter"
+msgstr "¹LÂo¾¹"
+
+msgid "Directories"
+msgstr "¥Ø¿ý"
+
+msgid "Help"
+msgstr "»²§U»¡©ú"
+
+msgid "Files"
+msgstr "ÀÉ®×"
+
+msgid "Selection"
+msgstr "¿ï¾Ü"
+
+msgid "Undo"
+msgstr "´_­ì"
+
+#, c-format
+msgid "E671: Cannot find window title \"%s\""
+msgstr "E671: §ä¤£¨ì¼ÐÃD¬° \"%s\" ªºµøµ¡"
+
+#, c-format
+msgid "E243: Argument not supported: \"-%s\"; Use the OLE version."
+msgstr "E243: ¤£¤ä´©°Ñ¼Æ \"-%s\"¡C½Ð¥Î OLE ª©¥»¡C"
+
+msgid "E672: Unable to open window inside MDI application"
+msgstr "E672: µLªk¦b MDI µ{¦¡¤¤¶}±Òµøµ¡"
+
+msgid "Find string (use '\\\\' to find a '\\')"
+msgstr "·j´M¦r¦ê (¨Ï¥Î '\\\\' ¨Óªí¥Ü '\\')"
+
+msgid "Find & Replace (use '\\\\' to find a '\\')"
+msgstr "·j´M¤Î¨ú¥N¦r¦ê (¨Ï¥Î '\\\\' ¨Óªí¥Ü '\\')"
+
+msgid "Vim E458: Cannot allocate colormap entry, some colors may be incorrect"
+msgstr "Vim E458: µLªk°t¸m color map ¶µ¥Ø¡A¦³¨ÇÃC¦â¬Ý°_¨Ó·|©Ç©Çªº"
+
+#, c-format
+msgid "E250: Fonts for the following charsets are missing in fontset %s:"
+msgstr "E250: Fontset %s ¨S¦³³]©w¥¿½Tªº¦r«¬¥H¨ÑÅã¥Ü³o¨Ç¦r¤¸¶°:"
+
+#, c-format
+msgid "E252: Fontset name: %s"
+msgstr "E252: ¦r«¬¶°(Fontset)¦WºÙ: %s"
+
+#, c-format
+msgid "Font '%s' is not fixed-width"
+msgstr "'%s' ¤£¬O©T©w¼e«×¦r«¬"
+
+#, c-format
+msgid "E253: Fontset name: %s\n"
+msgstr "E253: ¦r«¬¶°(Fontset)¦WºÙ: %s\n"
+
+#, c-format
+msgid "Font0: %s\n"
+msgstr "Font0: %s\n"
+
+#, c-format
+msgid "Font1: %s\n"
+msgstr "Font1: %s\n"
+
+#, c-format
+msgid "Font%ld width is not twice that of font0\n"
+msgstr "¦r«¬%ld ¼e«×¤£¬O ¦r«¬0 ªº¨â­¿\n"
+
+#, c-format
+msgid "Font0 width: %ld\n"
+msgstr "¦r«¬0ªº¼e«×¡G%ld\n"
+
+#, c-format
+msgid ""
+"Font1 width: %ld\n"
+"\n"
+msgstr ""
+"¦r«¬1¼e«×: %ld\n"
+"\n"
+
+msgid "E256: Hangul automata ERROR"
+msgstr "E256: Hangul automata ¿ù»~"
+
+msgid "Add a new database"
+msgstr "·s¼W¸ê®Æ®w"
+
+msgid "Query for a pattern"
+msgstr "¿é¤J pattern"
+
+msgid "Show this message"
+msgstr "Åã¥Ü¦¹°T®§"
+
+msgid "Kill a connection"
+msgstr "µ²§ô³s½u"
+
+msgid "Reinit all connections"
+msgstr "­«³]©Ò¦³³s½u"
+
+msgid "Show connections"
+msgstr "Åã¥Ü³s½u"
+
+#, c-format
+msgid "E560: Usage: cs[cope] %s"
+msgstr "E560: ¥Îªk: cs[cope] %s"
+
+msgid "This cscope command does not support splitting the window.\n"
+msgstr "³o­Ó cscope ©R¥O¤£¤ä´©¤À³Î¿Ã¹õ\n"
+
+msgid "E562: Usage: cstag <ident>"
+msgstr "E562: ¥Îªk: cstag <ÃѧO¦rident>"
+
+msgid "E257: cstag: tag not found"
+msgstr "E257: cstag: §ä¤£¨ì tag"
+
+#, c-format
+msgid "E563: stat(%s) error: %d"
+msgstr "E563: stat(%s) ¿ù»~: %d"
+
+msgid "E563: stat error"
+msgstr "E563: stat ¿ù»~"
+
+#, c-format
+msgid "E564: %s is not a directory or a valid cscope database"
+msgstr "E564: %s ¤£¬O¥Ø¿ý©Î cscope ¸ê®Æ®w"
+
+#, c-format
+msgid "Added cscope database %s"
+msgstr "·s¼W cscope ¸ê®Æ®w %s"
+
+#, c-format
+msgid "E262: error reading cscope connection %ld"
+msgstr "E262: Ū¨ú cscope ³s½u %ld ¿ù»~"
+
+msgid "E561: unknown cscope search type"
+msgstr "E561: ¥¼ª¾ªº cscope ·j´M§ÎºA"
+
+msgid "E566: Could not create cscope pipes"
+msgstr "E566: µLªk«Ø¥ß»P cscope ªº pipe ³s½u"
+
+msgid "E622: Could not fork for cscope"
+msgstr "E622: µLªk fork ¥H°õ¦æ cscope "
+
+msgid "cs_create_connection exec failed"
+msgstr "cs_create_connection °õ¦æ¥¢±Ñ"
+
+msgid "E623: Could not spawn cscope process"
+msgstr "E623: µLªk°õ¦æ cscope "
+
+msgid "cs_create_connection: fdopen for to_fp failed"
+msgstr "cs_create_connection: fdopen ¥¢±Ñ (to_fp)"
+
+msgid "cs_create_connection: fdopen for fr_fp failed"
+msgstr "cs_create_connection: fdopen ¥¢±Ñ (fr_fp)"
+
+msgid "E567: no cscope connections"
+msgstr "E567: ¨S¦³ cscope ³s½u"
+
+#, c-format
+msgid "E259: no matches found for cscope query %s of %s"
+msgstr "E259: §ä¤£¨ì²Å¦X cscope ªº·j´M %s / %s"
+
+#, c-format
+msgid "E469: invalid cscopequickfix flag %c for %c"
+msgstr "E469: cscopequickfix ªº flac %c (%c) ¤£¥¿½T"
+
+msgid "cscope commands:\n"
+msgstr "cscope ©R¥O:\n"
+
+#, c-format
+msgid "%-5s: %-30s (Usage: %s)"
+msgstr "%-5s: %-30s (¥Îªk: %s)"
+
+#, c-format
+msgid "E625: cannot open cscope database: %s"
+msgstr "E625: µLªk¶}±Ò cscope ¸ê®Æ®w %s"
+
+msgid "E626: cannot get cscope database information"
+msgstr "E626: µLªk¨ú±o cscope ¸ê®Æ®w¸ê°T"
+
+msgid "E568: duplicate cscope database not added"
+msgstr "E568: ­«½Æªº cscope ¸ê®Æ®w¥¼³Q¥[¤J"
+
+msgid "E569: maximum number of cscope connections reached"
+msgstr "E569: ¤w¹F¨ì cscope ³Ì¤j³s½u¼Æ¥Ø"
+
+#, c-format
+msgid "E261: cscope connection %s not found"
+msgstr "E261: §ä¤£¨ì cscope ³s½u %s"
+
+#, c-format
+msgid "cscope connection %s closed"
+msgstr "cscope ³s½u %s ¤wÃö³¬"
+
+#. should not reach here
+msgid "E570: fatal error in cs_manage_matches"
+msgstr "E570: cs_manage_matches ÄY­«¿ù»~"
+
+#, c-format
+msgid "Cscope tag: %s"
+msgstr "Cscope ¼ÐÅÒ(tag): %s"
+
+msgid ""
+"\n"
+" # line"
+msgstr ""
+"\n"
+" # ¦æ "
+
+msgid "filename / context / line\n"
+msgstr "ÀɦW / ¤º¤å / ¦æ¸¹\n"
+
+#, c-format
+msgid "E609: Cscope error: %s"
+msgstr "E609: Csope ¿ù»~: %s"
+
+msgid "All cscope databases reset"
+msgstr "­«³]©Ò¦³ cscope ¸ê®Æ®w"
+
+msgid "no cscope connections\n"
+msgstr "¨S¦³ cscope ³s½u\n"
+
+msgid " # pid database name prepend path\n"
+msgstr " # pid ¸ê®Æ®w¦WºÙ prepend path\n"
+
+msgid ""
+"E263: Sorry, this command is disabled, the Python library could not be "
+"loaded."
+msgstr "E263: ©êºp¡A³o­Ó©R¥OµLªk¨Ï¥Î¡APython µ{¦¡®w¨S¦³¸ü¤J¡C"
+
+msgid "E659: Cannot invoke Python recursively"
+msgstr "E659: µLªk»¼°j°õ¦æ Python "
+
+msgid "can't delete OutputObject attributes"
+msgstr "µLªk§R°£ OutputObject ÄÝ©Ê"
+
+msgid "softspace must be an integer"
+msgstr "softspace ¥²»Ý¬O¾ã¼Æ"
+
+msgid "invalid attribute"
+msgstr "¤£¥¿½TªºÄÝ©Ê"
+
+msgid "writelines() requires list of strings"
+msgstr "writelines() »Ý­n string list ·í°Ñ¼Æ"
+
+msgid "E264: Python: Error initialising I/O objects"
+msgstr "E264: Python: µLªkªì©l I/O ª«¥ó"
+
+msgid "invalid expression"
+msgstr "¤£¥¿½Tªº¹Bºâ¦¡"
+
+msgid "expressions disabled at compile time"
+msgstr "¦]¬°½sĶ®É¨S¦³¥[¤J¹Bºâ¦¡(expression)ªºµ{¦¡½X¡A©Ò¥HµLªk¨Ï¥Î¹Bºâ¦¡"
+
+msgid "attempt to refer to deleted buffer"
+msgstr "¸Õ¹Ï¨Ï¥Î¤w³Q§R°£ªº buffer"
+
+msgid "line number out of range"
+msgstr "¦æ¸¹¶W¥X½d³ò"
+
+#, c-format
+msgid "<buffer object (deleted) at %8lX>"
+msgstr "<buffer ª«¥ó (¤w§R°£): %8lX>"
+
+msgid "invalid mark name"
+msgstr "¼Ð°O¦WºÙ¤£¥¿½T"
+
+msgid "no such buffer"
+msgstr "µL¦¹ buffer"
+
+msgid "attempt to refer to deleted window"
+msgstr "¸Õ¹Ï¨Ï¥Î¤w³Q§R°£ªºµøµ¡"
+
+msgid "readonly attribute"
+msgstr "°ßŪÄÝ©Ê"
+
+msgid "cursor position outside buffer"
+msgstr "´å¼Ð©w¦ì¦b½w½Ä°Ï¤§¥~"
+
+#, c-format
+msgid "<window object (deleted) at %.8lX>"
+msgstr "<µøµ¡ª«¥ó(¤w§R°£): %.8lX>"
+
+#, c-format
+msgid "<window object (unknown) at %.8lX>"
+msgstr "<µøµ¡ª«¥ó(¥¼ª¾): %.8lX>"
+
+#, c-format
+msgid "<window %d>"
+msgstr "<µøµ¡ %d>"
+
+msgid "no such window"
+msgstr "µL¦¹µøµ¡"
+
+msgid "cannot save undo information"
+msgstr "µLªkÀx¦s´_­ì¸ê°T"
+
+msgid "cannot delete line"
+msgstr "¤£¯à§R°£¦¹¦æ "
+
+msgid "cannot replace line"
+msgstr "¤£¯à´À¥N¦¹¦æ "
+
+msgid "cannot insert line"
+msgstr "¤£¯à´À¥N´¡¤J¦¹¦æ "
+
+msgid "string cannot contain newlines"
+msgstr "¦r¦êµLªk¥]§t·s¦æ "
+
+msgid ""
+"E266: Sorry, this command is disabled, the Ruby library could not be loaded."
+msgstr "E266: ¦¹©R¥OµLªk¨Ï¥Î¡AµLªk¸ü¤J Ruby µ{¦¡®w(Library)"
+
+#, c-format
+msgid "E273: unknown longjmp status %d"
+msgstr "E273: ¥¼ª¾ªº longjmp status %d"
+
+msgid "Toggle implementation/definition"
+msgstr "¤Á´«¹ê§@/©w¸q"
+
+msgid "Show base class of"
+msgstr "Åã¥Ü base class of:"
+
+msgid "Show overridden member function"
+msgstr "Åã¥Ü³Q override ªº member function"
+
+msgid "Retrieve from file"
+msgstr "Ū¨ú: ±qÀÉ®×"
+
+msgid "Retrieve from project"
+msgstr "Ū¨ú: ±qª«¥ó"
+
+msgid "Retrieve from all projects"
+msgstr "Ū¨ú: ±q©Ò¦³ project"
+
+msgid "Retrieve"
+msgstr "Ū¨ú"
+
+msgid "Show source of"
+msgstr "Åã¥Ü­ì©l½X: "
+
+msgid "Find symbol"
+msgstr "·j´M symbol"
+
+msgid "Browse class"
+msgstr "ÂsÄý class"
+
+msgid "Show class in hierarchy"
+msgstr "Åã¥Ü¶¥¼h¦¡ªº class"
+
+msgid "Show class in restricted hierarchy"
+msgstr "Åã¥Ü restricted ¶¥¼h¦¡ªº class"
+
+msgid "Xref refers to"
+msgstr "Xref °Ñ¦Ò¨ì"
+
+msgid "Xref referred by"
+msgstr "Xref ³Q½Ö°Ñ¦Ò:"
+
+msgid "Xref has a"
+msgstr "Xref ¦³"
+
+msgid "Xref used by"
+msgstr "Xref ³Q½Ö¨Ï¥Î:"
+
+msgid "Show docu of"
+msgstr "Åã¥Ü¤å¥ó: "
+
+msgid "Generate docu for"
+msgstr "²£¥Í¤å¥ó: "
+
+msgid ""
+"Cannot connect to SNiFF+. Check environment (sniffemacs must be found in "
+"$PATH).\n"
+msgstr "µLªk³s½u¨ì SNiFF+¡C½ÐÀˬdÀô¹ÒÅÜ¼Æ ($PATH ¸Ì¥²»Ý¥i¥H§ä¨ì sniffemacs)\n"
+
+msgid "E274: Sniff: Error during read. Disconnected"
+msgstr "E274: Sniff: Ū¨ú¿ù»~. ¨ú®ø³s½u"
+
+msgid "SNiFF+ is currently "
+msgstr "SNiFF+ ¥Ø«e"
+
+msgid "not "
+msgstr "¥¼"
+
+msgid "connected"
+msgstr "³s½u¤¤"
+
+#, c-format
+msgid "E275: Unknown SNiFF+ request: %s"
+msgstr "E275: ¤£¥¿½Tªº SNiff+ ©I¥s: %s"
+
+msgid "E276: Error connecting to SNiFF+"
+msgstr "E276: ³s½u¨ì SNiFF+ ¥¢±Ñ"
+
+msgid "E278: SNiFF+ not connected"
+msgstr "E278: ¥¼³s½u¨ì SNiFF+"
+
+msgid "E279: Not a SNiFF+ buffer"
+msgstr "E279: ¤£¬O SNiFF+ ªº½w½Ä°Ï"
+
+msgid "Sniff: Error during write. Disconnected"
+msgstr "Sniff: ¼g¤J¿ù»~¡Cµ²§ô³s½u"
+
+msgid "invalid buffer number"
+msgstr "½w½Ä°Ï¸¹½X¿ù»~"
+
+msgid "not implemented yet"
+msgstr "©|¥¼¹ê§@"
+
+msgid "unknown option"
+msgstr "¤£¥¿½Tªº¿ï¶µ"
+
+#. ???
+msgid "cannot set line(s)"
+msgstr "¤£¯à³]©w¦æ "
+
+msgid "mark not set"
+msgstr "¨S¦³³]©w¼Ð°O"
+
+#, c-format
+msgid "row %d column %d"
+msgstr "¦C %d ¦æ %d"
+
+msgid "cannot insert/append line"
+msgstr "¤£¯à´¡¤J©Îªþ¥[¦¹¦æ "
+
+msgid "unknown flag: "
+msgstr "¿ù»~ªººX¼Ð: "
+
+msgid "unknown vimOption"
+msgstr "¤£¥¿½Tªº VIM ¿ï¶µ"
+
+msgid "keyboard interrupt"
+msgstr "Áä½L¤¤Â_"
+
+msgid "vim error"
+msgstr "vim ¿ù»~"
+
+msgid "cannot create buffer/window command: object is being deleted"
+msgstr "µLªk«Ø¥ß½w½Ä°Ï/µøµ¡©R¥O: ª«¥ó±N·|³Q§R°£"
+
+msgid ""
+"cannot register callback command: buffer/window is already being deleted"
+msgstr "µLªkµù¥U callback ©R¥O: ½w½Ä°Ï/µøµ¡¤w¸g³Q§R°£¤F"
+
+#. This should never happen. Famous last word?
+msgid ""
+"E280: TCL FATAL ERROR: reflist corrupt!? Please report this to vim-dev@vim."
+"org"
+msgstr "E280: TCL ÄY­«¿ù»~: reflist Äê±¼¤F!? ½Ð³ø§iµ¹ to vim-dev@vim.org"
+
+msgid "cannot register callback command: buffer/window reference not found"
+msgstr "µLªkµù¥U callback ©R¥O: §ä¤£¨ì½w½Ä°Ï/µøµ¡"
+
+msgid ""
+"E571: Sorry, this command is disabled: the Tcl library could not be loaded."
+msgstr "E571: ¦¹©R¥OµLªk¨Ï¥Î, ¦]¬°µLªk¸ü¤J Tcl µ{¦¡®w(Library)"
+
+msgid ""
+"E281: TCL ERROR: exit code is not int!? Please report this to vim-dev@vim.org"
+msgstr "E281: TCL ¿ù»~: µ²§ô½X¤£¬O¾ã¼Æ!? ½Ð³ø§iµ¹ to vim-dev@vim.org"
+
+msgid "cannot get line"
+msgstr "¤£¯à¨ú±o¦¹¦æ "
+
+msgid "Unable to register a command server name"
+msgstr "µLªkµù¥U©R¥O¦øªA¾¹¦WºÙ"
+
+msgid "E248: Failed to send command to the destination program"
+msgstr "E248: µLªk°e¥X©R¥O¨ì¥Øªº¦aµ{¦¡"
+
+#, c-format
+msgid "E573: Invalid server id used: %s"
+msgstr "E573: ¤£¥¿½Tªº¦øªA¾¹ id : %s"
+
+msgid "E251: VIM instance registry property is badly formed. Deleted!"
+msgstr "E251: VIM ªº registry ³]©w¶µ¦³»~¡C¤w§R°£¡C"
+
+msgid "Unknown option"
+msgstr "¤£¥¿½Tªº¿ï¶µ"
+
+msgid "Too many edit arguments"
+msgstr "¤Ó¦h½s¿è°Ñ¼Æ"
+
+msgid "Argument missing after"
+msgstr "¯Ê¤Ö¥²­nªº°Ñ¼Æ:"
+
+msgid "Garbage after option"
+msgstr "µLªk¿ë»{¦¹¿ï¶µ«áªº©R¥O: "
+
+msgid "Too many \"+command\", \"-c command\" or \"--cmd command\" arguments"
+msgstr "¤Ó¦h \"+command\" ¡B \"-c command\" ©Î \"--cmd command\" °Ñ¼Æ"
+
+msgid "Invalid argument for"
+msgstr "¤£¥¿½Tªº°Ñ¼Æ: "
+
+msgid "This Vim was not compiled with the diff feature."
+msgstr "±zªº Vim ½sĶ®É¨S¦³¥[¤J diff ªº¯à¤O"
+
+msgid "Attempt to open script file again: \""
+msgstr "¸Õ¹Ï¦A¦¸¶}±Ò script ÀÉ: \""
+
+msgid "Cannot open for reading: \""
+msgstr "µLªk¶}±Ò¥HŪ¨ú: \""
+
+msgid "Cannot open for script output: \""
+msgstr "µLªk¶}±Ò¬° script ¿é¥X: \""
+
+#, c-format
+msgid "%d files to edit\n"
+msgstr "ÁÙ¦³ %d ­ÓÀÉ®×µ¥«Ý½s¿è\n"
+
+msgid "Vim: Warning: Output is not to a terminal\n"
+msgstr "Vim: ª`·N: ¿é¥X¤£¬O²×ºÝ¾÷(¿Ã¹õ)\n"
+
+msgid "Vim: Warning: Input is not from a terminal\n"
+msgstr "Vim: ª`·N: ¿é¤J¤£¬O²×ºÝ¾÷(Áä½L)\n"
+
+#. just in case..
+msgid "pre-vimrc command line"
+msgstr "vimrc «e©R¥O¦C"
+
+#, c-format
+msgid "E282: Cannot read from \"%s\""
+msgstr "E282: µLªkŪ¨úÀÉ®× \"%s\""
+
+msgid ""
+"\n"
+"More info with: \"vim -h\"\n"
+msgstr ""
+"\n"
+"¬d¸ß§ó¦h¸ê°T½Ð°õ¦æ: \"vim -h\"\n"
+
+msgid "[file ..] edit specified file(s)"
+msgstr "[ÀÉ®× ..] ½s¿è«ü©wªºÀÉ®×"
+
+msgid "- read text from stdin"
+msgstr "- ±q¼Ð·Ç¿é¤J(stdin)Ū¨úÀÉ®×"
+
+msgid "-t tag edit file where tag is defined"
+msgstr "-t tag ½s¿è®É¨Ï¥Î«ü©wªº tag"
+
+msgid "-q [errorfile] edit file with first error"
+msgstr "-q [errorfile] ½s¿è®É¸ü¤J²Ä¤@­Ó¿ù»~"
+
+msgid ""
+"\n"
+"\n"
+"Usage:"
+msgstr ""
+"\n"
+"\n"
+" ¥Îªk:"
+
+msgid " vim [arguments] "
+msgstr "vim [°Ñ¼Æ] "
+
+msgid ""
+"\n"
+" or:"
+msgstr ""
+"\n"
+" ©Î:"
+
+msgid ""
+"\n"
+"\n"
+"Arguments:\n"
+msgstr ""
+"\n"
+"\n"
+"°Ñ¼Æ:\n"
+
+msgid "--\t\t\tOnly file names after this"
+msgstr "--\t\t\t¥u¦³¦b³o¤§«áªºÀÉ®×"
+
+msgid "--literal\t\tDon't expand wildcards"
+msgstr "--literal\t\t¤£®i¶}¸U¥Î¦r¤¸"
+
+msgid "-register\t\tRegister this gvim for OLE"
+msgstr "-register\t\tµù¥U gvim ¨ì OLE"
+
+msgid "-unregister\t\tUnregister gvim for OLE"
+msgstr "-unregister\t\t¨ú®ø OLE ¤¤ªº gvim µù¥U"
+
+msgid "-g\t\t\tRun using GUI (like \"gvim\")"
+msgstr "-g\t\t\t¨Ï¥Î¹Ï§Î¬É­± (¦P \"gvim\")"
+
+msgid "-f or --nofork\tForeground: Don't fork when starting GUI"
+msgstr "-f ©Î --nofork\t«e´º: °_©l¹Ï§Î¬É­±®É¤£ fork"
+
+msgid "-v\t\t\tVi mode (like \"vi\")"
+msgstr "-v\t\t\tVi ¼Ò¦¡ (¦P \"vi\")"
+
+msgid "-e\t\t\tEx mode (like \"ex\")"
+msgstr "-e\t\t\tEx ¼Ò¦¡ (¦P \"ex\")"
+
+msgid "-s\t\t\tSilent (batch) mode (only for \"ex\")"
+msgstr "-s\t\t\t¦wÀR (batch) ¼Ò¦¡ (¥u¯à»P \"ex\" ¤@°_¨Ï¥Î)"
+
+msgid "-d\t\t\tDiff mode (like \"vimdiff\")"
+msgstr "-d\t\t\tDiff ¼Ò¦¡ (¦P \"vimdiff\", ¥i¨³³t¤ñ¸û¨âÀɮפ£¦P³B)"
+
+msgid "-y\t\t\tEasy mode (like \"evim\", modeless)"
+msgstr "-y\t\t\t²©ö¼Ò¦¡ (¦P \"evim\", modeless)"
+
+msgid "-R\t\t\tReadonly mode (like \"view\")"
+msgstr "-R\t\t\t°ßŪ¼Ò¦¡ (¦P \"view\")"
+
+msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
+msgstr "-Z\t\t\t­­¨î¼Ò¦¡ (¦P \"rvim\")"
+
+msgid "-m\t\t\tModifications (writing files) not allowed"
+msgstr "-m\t\t\t¤£¥i­×§ï (¼g¤JÀÉ®×)"
+
+msgid "-M\t\t\tModifications in text not allowed"
+msgstr "-M\t\t\t¤£¥i­×§ï¤å¦r"
+
+msgid "-b\t\t\tBinary mode"
+msgstr "-b\t\t\t¤G¶i¦ì¼Ò¦¡"
+
+msgid "-l\t\t\tLisp mode"
+msgstr "-l\t\t\tLisp ¼Ò¦¡"
+
+msgid "-C\t\t\tCompatible with Vi: 'compatible'"
+msgstr "-C\t\t\t'compatible' ¶Ç²Î Vi ¬Û®e¼Ò¦¡"
+
+msgid "-N\t\t\tNot fully Vi compatible: 'nocompatible'"
+msgstr "-N\t\t\t'nocompatible' ¤£§¹¥þ»P¶Ç²Î Vi ¬Û®e¡A¥i¨Ï¥Î Vim ¥[±j¯à¤O"
+
+msgid "-V[N]\t\tVerbose level"
+msgstr "-V[N]\t\tVerbose µ¥¯Å"
+
+msgid "-D\t\t\tDebugging mode"
+msgstr "-D\t\t\t°£¿ù¼Ò¦¡"
+
+msgid "-n\t\t\tNo swap file, use memory only"
+msgstr "-n\t\t\t¤£¨Ï¥Î¼È¦sÀÉ, ¥u¨Ï¥Î°O¾ÐÅé"
+
+msgid "-r\t\t\tList swap files and exit"
+msgstr "-r\t\t\t¦C¥X¼È¦sÀÉ«áÂ÷¶}"
+
+msgid "-r (with file name)\tRecover crashed session"
+msgstr "-r (¥[ÀɦW) \t­×´_¤W¦¸·l·´ªº¸ê®Æ(Recover crashed session)"
+
+msgid "-L\t\t\tSame as -r"
+msgstr "-L\t\t\t¦P -r"
+
+msgid "-f\t\t\tDon't use newcli to open window"
+msgstr "-f\t\t\t¤£¨Ï¥Î newcli ¨Ó¶}±Òµøµ¡"
+
+msgid "-dev <device>\t\tUse <device> for I/O"
+msgstr "-dev <device>\t\t¨Ï¥Î <device> °µ¿é¥X¤J"
+
+msgid "-A\t\t\tStart in Arabic mode"
+msgstr "-A\t\t\t±Ò°Ê¬° Arabic ¼Ò¦¡"
+
+msgid "-H\t\t\tStart in Hebrew mode"
+msgstr "-H\t\t\t±Ò°Ê¬° Hebrew ¼Ò¦¡"
+
+msgid "-F\t\t\tStart in Farsi mode"
+msgstr "-F\t\t\t±Ò°Ê¬° Farsi ¼Ò¦¡"
+
+msgid "-T <terminal>\tSet terminal type to <terminal>"
+msgstr "-T <terminal>\t³]©w²×ºÝ¾÷¬° <terminal>"
+
+msgid "-u <vimrc>\t\tUse <vimrc> instead of any .vimrc"
+msgstr "-u <vimrc>\t\t¨Ï¥Î <vimrc> ¨ú¥N¥ô¦ó .vimrc"
+
+msgid "-U <gvimrc>\t\tUse <gvimrc> instead of any .gvimrc"
+msgstr "-U <gvimrc>\t\t¨Ï¥Î <gvimrc> ¨ú¥N¥ô¦ó .gvimrc"
+
+msgid "--noplugin\t\tDon't load plugin scripts"
+msgstr "--noplugin\t\t¤£¸ü¤J¥ô¦ó plugin"
+
+msgid "-o[N]\t\tOpen N windows (default: one for each file)"
+msgstr "-o[N]\t\t¶}±Ò N ­Óµøµ¡ (¹w³]¬O¨C­ÓÀɮפ@­Ó)"
+
+msgid "-O[N]\t\tLike -o but split vertically"
+msgstr "-O[N]\t\t¦P -o ¦ý¨Ï¥Î««ª½¤À³Î"
+
+msgid "+\t\t\tStart at end of file"
+msgstr "+\t\t\t±Ò°Ê«á¸õ¨ìÀÉ®×µ²§À"
+
+msgid "+<lnum>\t\tStart at line <lnum>"
+msgstr "+<lnum>\t\t±Ò°Ê«á¸õ¨ì²Ä <lnum> ¦æ "
+
+msgid "--cmd <command>\tExecute <command> before loading any vimrc file"
+msgstr "--cmd <command>\t¸ü¤J¥ô¦ó vimrc «e°õ¦æ <command>"
+
+msgid "-c <command>\t\tExecute <command> after loading the first file"
+msgstr "-c <command>\t\t¸ü¤J²Ä¤@­ÓÀɮ׫á°õ¦æ <command>"
+
+msgid "-S <session>\t\tSource file <session> after loading the first file"
+msgstr "-S <session>\t\t¸ü¤J²Ä¤@­ÓÀɮ׫á¸ü¤J Session ÀÉ <session>"
+
+msgid "-s <scriptin>\tRead Normal mode commands from file <scriptin>"
+msgstr "-s <scriptin>\t±q <scriptin> Ū¤J¤@¯ë¼Ò¦¡©R¥O"
+
+msgid "-w <scriptout>\tAppend all typed commands to file <scriptout>"
+msgstr "-w <scriptout>\t¹ïÀÉ®× <scriptout> ªþ¥[(append)©Ò¦³¿é¤Jªº©R¥O"
+
+msgid "-W <scriptout>\tWrite all typed commands to file <scriptout>"
+msgstr "-W <scriptout>\t¹ïÀÉ®× <scriptout> ¼g¤J©Ò¦³¿é¤Jªº©R¥O"
+
+msgid "-x\t\t\tEdit encrypted files"
+msgstr "-x\t\t\t½s¿è½s½X¹LªºÀÉ®×"
+
+msgid "-display <display>\tConnect vim to this particular X-server"
+msgstr "-display <display>\t±N vim »P«ü©wªº X-server ³s½u"
+
+msgid "-X\t\t\tDo not connect to X server"
+msgstr "-X\t\t\t¤£­n³s½u¨ì X Server"
+
+msgid "--remote <files>\tEdit <files> in a Vim server if possible"
+msgstr "--remote <files>\t½s¿è Vim ¦øªA¾¹¤Wªº <files> «áÂ÷¶}"
+
+msgid "--remote-silent <files> Same, don't complain if there is no server"
+msgstr "--remote-silent <files> ¬Û¦P¡A¦ý¨S¦³¦øªA¾¹®É¤£Äµ§i"
+
+msgid ""
+"--remote-wait <files> As --remote but wait for files to have been edited"
+msgstr "--remote-wait <files> ¦P --remote, ¦ý·|µ¥­ÔÀɮק¹¦¨½s¿è"
+
+msgid ""
+"--remote-wait-silent <files> Same, don't complain if there is no server"
+msgstr "--remote-wait-silent <files> ¬Û¦P¡A¦ý¨S¦øªA¾¹®É¤£Äµ§i"
+
+msgid "--remote-send <keys>\tSend <keys> to a Vim server and exit"
+msgstr "--remote-send <keys>\t°e¥X <keys> ¨ì Vim ¦øªA¾¹¨ÃÂ÷¶}"
+
+msgid "--remote-expr <expr>\tEvaluate <expr> in a Vim server and print result"
+msgstr "--remote-expr <expr>\t¦b¦øªA¾¹¤W°õ¦æ <expr> ¨Ã¦L¥Xµ²ªG"
+
+msgid "--serverlist\t\tList available Vim server names and exit"
+msgstr "--serverlist\t\t¦C¥X¥i¥Îªº Vim ¦øªA¾¹¦WºÙ¨ÃÂ÷¶}"
+
+msgid "--servername <name>\tSend to/become the Vim server <name>"
+msgstr "--servername <name>\t°e¦Ü/¦¨¬° Vim ¦øªA¾¹ <name>"
+
+msgid "-i <viminfo>\t\tUse <viminfo> instead of .viminfo"
+msgstr "-i <viminfo>\t\t¨Ï¥Î <viminfo> ¦Ó«D .viminfo"
+
+msgid "-h or --help\tPrint Help (this message) and exit"
+msgstr "-h ©Î --help\t¦L¥X»¡©ú(¤]´N¬O¥»°T®§)«áÂ÷¶}"
+
+msgid "--version\t\tPrint version information and exit"
+msgstr "--version\t\t¦L¥Xª©¥»¸ê°T«áÂ÷¶}"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Motif version):\n"
+msgstr ""
+"\n"
+"gvim »{±oªº°Ñ¼Æ (Motif ª©):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (neXtaw version):\n"
+msgstr ""
+"\n"
+"gvim »{±oªº°Ñ¼Æ (neXtaw ª©):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Athena version):\n"
+msgstr ""
+"\n"
+"gvim »{±oªº°Ñ¼Æ (Athena ª©):\n"
+
+msgid "-display <display>\tRun vim on <display>"
+msgstr "-display <display>\t¦bµøµ¡ <display> °õ¦æ vim"
+
+msgid "-iconic\t\tStart vim iconified"
+msgstr "-iconic\t\t±Ò°Ê«á¹Ï¥Ü¤Æ(iconified)"
+
+msgid "-name <name>\t\tUse resource as if vim was <name>"
+msgstr "-name <name>\t\tŪ¨ú Resource ®É§â vim ªº¦WºÙµø¬° <name>"
+
+msgid "\t\t\t (Unimplemented)\n"
+msgstr "\t\t\t (©|¥¼¹ê§@)\n"
+
+msgid "-background <color>\tUse <color> for the background (also: -bg)"
+msgstr "-background <color>\t³]©w <color> ¬°­I´º¦â (¤]¥i¥Î -bg)"
+
+msgid "-foreground <color>\tUse <color> for normal text (also: -fg)"
+msgstr "-foreground <color>\t³]©w <color> ¬°¤@¯ë¤å¦rÃC¦â (¤]¥i¥Î -fg)"
+
+msgid "-font <font>\t\tUse <font> for normal text (also: -fn)"
+msgstr "-font <font>\t¨Ï¥Î <font> ¬°¤@¯ë¦r«¬ (¤]¥i¥Î -fn)"
+
+msgid "-boldfont <font>\tUse <font> for bold text"
+msgstr "-boldfont <font>\t¨Ï¥Î <font> ¬°²ÊÅé¦r«¬"
+
+msgid "-italicfont <font>\tUse <font> for italic text"
+msgstr "-italicfont <font>\t¨Ï¥Î <font> ¬°±×Åé¦r«¬"
+
+msgid "-geometry <geom>\tUse <geom> for initial geometry (also: -geom)"
+msgstr "-geometry <geom>\t¨Ï¥Î<geom>¬°°_©l¦ì¸m (¤]¥i¥Î -geom)"
+
+msgid "-borderwidth <width>\tUse a border width of <width> (also: -bw)"
+msgstr "-borderwidth <width>\t¨Ï¥Î¼e«×¬° <width> ªºÃä®Ø (¤]¥i¥Î -bw)"
+
+msgid "-scrollbarwidth <width> Use a scrollbar width of <width> (also: -sw)"
+msgstr "-scrollbarwidth <width> ³]©w±²°Ê¶b¼e«×¬° <width> (¤]¥i¥Î -sw)"
+
+msgid "-menuheight <height>\tUse a menu bar height of <height> (also: -mh)"
+msgstr "-menuheight <height>\t³]©w¿ï³æ¦Cªº°ª«×¬° <height> (¤]¥i¥Î -mh)"
+
+msgid "-reverse\t\tUse reverse video (also: -rv)"
+msgstr "-reverse\t\t¨Ï¥Î¤Ï¬ÛÅã¥Ü (¤]¥i¥Î -rv)"
+
+msgid "+reverse\t\tDon't use reverse video (also: +rv)"
+msgstr "+reverse\t\t¤£¨Ï¥Î¤Ï¬ÛÅã¥Ü (¤]¥i¥Î +rv)"
+
+msgid "-xrm <resource>\tSet the specified resource"
+msgstr "-xrm <resource>\t³]©w«ü©wªº resource"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (RISC OS version):\n"
+msgstr ""
+"\n"
+"gvim »{±oªº°Ñ¼Æ (RISC OS ª©):\n"
+
+msgid "--columns <number>\tInitial width of window in columns"
+msgstr "--columns <number>\tµøµ¡ªì©l¤Æ¼e«×"
+
+msgid "--rows <number>\tInitial height of window in rows"
+msgstr "--rows <number>\tµøµ¡ªì©l¤Æ°ª«×"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (GTK+ version):\n"
+msgstr ""
+"\n"
+"gvim »{±oªº°Ñ¼Æ (GTK+ ª©):\n"
+
+msgid "-display <display>\tRun vim on <display> (also: --display)"
+msgstr "-display <display>\t¦b <display> °õ¦æ vim (¤]¥i¥Î --display)"
+
+msgid "--role <role>\tSet a unique role to identify the main window"
+msgstr "--role <role>\t³]©w¿W¯Sªº¨¤¦â(role)¥H°Ï¤À¥Dµøµ¡"
+
+msgid "--socketid <xid>\tOpen Vim inside another GTK widget"
+msgstr "--socketid <xid>\t¦b¥t¤@­Ó GTK widget ¤º¶}±Ò Vim"
+
+msgid "-P <parent title>\tOpen Vim inside parent application"
+msgstr "-P <parent title>\t¦b¤÷µ{¦¡¤¤¶}±Ò Vim"
+
+msgid "No display"
+msgstr "µLÅã¥Ü"
+
+#. Failed to send, abort.
+msgid ": Send failed.\n"
+msgstr ": ¶Ç°e¥¢±Ñ¡C\n"
+
+#. Let vim start normally.
+msgid ": Send failed. Trying to execute locally\n"
+msgstr ": °e¥X¥¢±Ñ¡C¸Õ¹Ï¦b¥»¦a°õ¦æ\n"
+
+#, c-format
+msgid "%d of %d edited"
+msgstr "¤w½s¿è %d/%d ­ÓÀÉ®×"
+
+msgid "No display: Send expression failed.\n"
+msgstr "µL Display: µLªk¶Ç°e¹Bºâ¦¡¡C\n"
+
+msgid ": Send expression failed.\n"
+msgstr ": µLªk¶Ç°e¹Bºâ¦¡¡C\n"
+
+msgid "No marks set"
+msgstr "¨S¦³³]©w¼Ð°O (mark)"
+
+#, c-format
+msgid "E283: No marks matching \"%s\""
+msgstr "E283: §ä¤£¨ì²Å¦X \"%s\" ªº¼Ð°O(mark)"
+
+#. Highlight title
+msgid ""
+"\n"
+"mark line col file/text"
+msgstr ""
+"\n"
+"¼Ð°O ¦æ¸¹ Äæ ÀÉ®×/¤å¦r"
+
+#. Highlight title
+msgid ""
+"\n"
+" jump line col file/text"
+msgstr ""
+"\n"
+" jump ¦æ¸¹ Äæ ÀÉ®×/¤å¦r"
+
+#. Highlight title
+msgid ""
+"\n"
+"change line col text"
+msgstr ""
+"\n"
+"§ïÅÜ ¦æ¸¹ Äæ ¤å¦r"
+
+#, c-format
+msgid ""
+"\n"
+"# File marks:\n"
+msgstr ""
+"\n"
+"# Àɮ׼аO:\n"
+
+#. Write the jumplist with -'
+#, c-format
+msgid ""
+"\n"
+"# Jumplist (newest first):\n"
+msgstr ""
+"\n"
+"# Jumplist (¥Ñ·s¨ìÂÂ):\n"
+
+#, c-format
+msgid ""
+"\n"
+"# History of marks within files (newest to oldest):\n"
+msgstr ""
+"\n"
+"# Àɮפº Mark °O¿ý (¥Ñ·s¨ìÂÂ):\n"
+
+msgid "Missing '>'"
+msgstr "¯Ê¤Ö¹ïÀ³ªº '>'"
+
+msgid "E543: Not a valid codepage"
+msgstr "E543: ¤£¥¿½Tªº codepage"
+
+msgid "E284: Cannot set IC values"
+msgstr "E284: ¤£¯à³]©w IC ¼Æ­È"
+
+msgid "E285: Failed to create input context"
+msgstr "E285: µLªk«Ø¥ß input context"
+
+msgid "E286: Failed to open input method"
+msgstr "E286: µLªk¶}±Ò¿é¤Jªk"
+
+msgid "E287: Warning: Could not set destroy callback to IM"
+msgstr "E287: ĵ§i: µLªk²¾°£ IM ªº callback"
+
+msgid "E288: input method doesn't support any style"
+msgstr "E288: ¿é¤Jªk¤£¤ä´©¥ô¦ó style"
+
+msgid "E289: input method doesn't support my preedit type"
+msgstr "E289: ¿é¤Jªk¤£¤ä´©¥ô¦ó style"
+
+msgid "E290: over-the-spot style requires fontset"
+msgstr "E290: over-the-spot »Ý­n¦r«¬¶°(Fontset)"
+
+msgid "E291: Your GTK+ is older than 1.2.3. Status area disabled"
+msgstr "E291: §Aªº GTK+ ¤ñ 1.2.3 ÁÙ¡CµLªk¨Ï¥Îª¬ºA°Ï¡C"
+
+msgid "E292: Input Method Server is not running"
+msgstr "E292: ¨S¦³°õ¦æ¤¤ªº¿é¤JªkºÞ²zµ{¦¡(Input Method Server)"
+
+msgid "E293: block was not locked"
+msgstr "E293: °Ï¶ô¥¼³QÂê©w"
+
+msgid "E294: Seek error in swap file read"
+msgstr "E294: ¼È¦sÀÉŪ¨ú¿ù»~"
+
+msgid "E295: Read error in swap file"
+msgstr "E295: ¼È¦sÀÉŪ¨ú¿ù»~"
+
+msgid "E296: Seek error in swap file write"
+msgstr "E296: ¼È¦sÀɼg¤J¿ù»~"
+
+msgid "E297: Write error in swap file"
+msgstr "E297: ¼È¦sÀɼg¤J¿ù»~"
+
+msgid "E300: Swap file already exists (symlink attack?)"
+msgstr "E300: ¼È¦sÀɤw¸g¦s¦b! (¤p¤ß²Å¸¹³sµ²ªº¦w¥þº|¬}!?)"
+
+msgid "E298: Didn't get block nr 0?"
+msgstr "E298: §ä¤£¨ì°Ï¶ô 0?"
+
+msgid "E298: Didn't get block nr 1?"
+msgstr "E298: §ä¤£¨ì°Ï¶ô 1?"
+
+msgid "E298: Didn't get block nr 2?"
+msgstr "E298: §ä¤£¨ì°Ï¶ô 2?"
+
+#. could not (re)open the swap file, what can we do????
+msgid "E301: Oops, lost the swap file!!!"
+msgstr "E301: ¾¾¾¾, ¼È¦sÀɤ£¨£¤F!!!"
+
+msgid "E302: Could not rename swap file"
+msgstr "E302: µLªk§ïÅܼȦsÀɪº¦WºÙ"
+
+#, c-format
+msgid "E303: Unable to open swap file for \"%s\", recovery impossible"
+msgstr "E303: µLªk¶}±Ò¼È¦sÀÉ \"%s\", ¤£¥i¯à­×´_¤F"
+
+msgid "E304: ml_timestamp: Didn't get block 0??"
+msgstr "E304: ml_timestamp: §ä¤£¨ì°Ï¶ô 0??"
+
+#, c-format
+msgid "E305: No swap file found for %s"
+msgstr "E305: §ä¤£¨ì %s ªº¼È¦sÀÉ"
+
+msgid "Enter number of swap file to use (0 to quit): "
+msgstr "½Ð¿ï¾Ü§A­n¨Ï¥Îªº¼È¦sÀÉ («ö0 Â÷¶}): "
+
+#, c-format
+msgid "E306: Cannot open %s"
+msgstr "E306: µLªk¶}±Ò %s"
+
+msgid "Unable to read block 0 from "
+msgstr "µLªkŪ¨ú°Ï¶ô 0:"
+
+msgid ""
+"\n"
+"Maybe no changes were made or Vim did not update the swap file."
+msgstr ""
+"\n"
+"¥i¯à¬O§A¨S°µ¹L¥ô¦ó­×§ï©Î¬O Vim ÁÙ¨Ó¤£¤Î§ó·s¼È¦sÀÉ."
+
+msgid " cannot be used with this version of Vim.\n"
+msgstr " µLªk¦b¥»ª©¥»ªº Vim ¤¤¨Ï¥Î.\n"
+
+msgid "Use Vim version 3.0.\n"
+msgstr "¨Ï¥Î Vim 3.0¡C\n"
+
+#, c-format
+msgid "E307: %s does not look like a Vim swap file"
+msgstr "E307: %s ¬Ý°_¨Ó¤£¹³¬O Vim ¼È¦sÀÉ"
+
+msgid " cannot be used on this computer.\n"
+msgstr " µLªk¦b³o»O¹q¸£¤W¨Ï¥Î.\n"
+
+msgid "The file was created on "
+msgstr "¥»Àɮ׫إߩó "
+
+msgid ""
+",\n"
+"or the file has been damaged."
+msgstr ""
+",\n"
+"©Î¬O³oÀɮפw¸g·l·´¡C"
+
+#, c-format
+msgid "Using swap file \"%s\""
+msgstr "¨Ï¥Î¼È¦sÀÉ \"%s\""
+
+#, c-format
+msgid "Original file \"%s\""
+msgstr "­ì©lÀÉ \"%s\""
+
+msgid "E308: Warning: Original file may have been changed"
+msgstr "E308: ĵ§i: ­ì©lÀÉ®×¥i¯à¤w¸g­×§ï¹L¤F"
+
+#, c-format
+msgid "E309: Unable to read block 1 from %s"
+msgstr "E309: µLªk±q %s Ū¨ú°Ï¶ô 1"
+
+msgid "???MANY LINES MISSING"
+msgstr "???¯Ê¤Ö¤Ó¦h¦æ "
+
+msgid "???LINE COUNT WRONG"
+msgstr "???¦æ¸¹¿ù»~"
+
+msgid "???EMPTY BLOCK"
+msgstr "???ªÅªº BLOCK"
+
+msgid "???LINES MISSING"
+msgstr "???§ä¤£¨ì¤@¨Ç¦æ "
+
+#, c-format
+msgid "E310: Block 1 ID wrong (%s not a .swp file?)"
+msgstr "E310: °Ï¶ô 1 ID ¿ù»~ (%s ¤£¬O¼È¦sÀÉ?)"
+
+msgid "???BLOCK MISSING"
+msgstr "???§ä¤£¨ìBLOCK"
+
+msgid "??? from here until ???END lines may be messed up"
+msgstr "??? ±q³o¸Ì¨ì ???END ªº¤º®e¥i¯à¦³°ÝÃD"
+
+msgid "??? from here until ???END lines may have been inserted/deleted"
+msgstr "??? ±q³o¸Ì¨ì ???END ªº¤º®e¥i¯à³Q§R°£/´¡¤J¹L"
+
+# do not translate
+msgid "???END"
+msgstr "???END"
+
+msgid "E311: Recovery Interrupted"
+msgstr "E311: ­×´_¤w¤¤Â_"
+
+msgid ""
+"E312: Errors detected while recovering; look for lines starting with ???"
+msgstr "E312: ­×´_®Éµo¥Í¿ù»~; ½Ðª`·N¶}ÀY¬° ??? ªº¦æ "
+
+msgid "See \":help E312\" for more information."
+msgstr "¸Ô²Ó»¡©ú½Ð¨£ \":help E312\""
+
+msgid "Recovery completed. You should check if everything is OK."
+msgstr "´_­ì§¹¦¨. ½Ð½T©w¤@¤Á¥¿±`."
+
+msgid ""
+"\n"
+"(You might want to write out this file under another name\n"
+msgstr ""
+"\n"
+"(§A¥i¯à·|·Q­n§â³o­ÓÀÉ®×¥t¦s§OªºÀɦW¡A\n"
+
+msgid "and run diff with the original file to check for changes)\n"
+msgstr "¦A°õ¦æ diff »P­ìÀɮפñ¸û¥HÀˬd¬O§_¦³§ïÅÜ)\n"
+
+msgid ""
+"Delete the .swp file afterwards.\n"
+"\n"
+msgstr ""
+"(D)ª½±µ§R°£ .swp ¼È¦sÀÉ\n"
+"\n"
+
+#. use msg() to start the scrolling properly
+msgid "Swap files found:"
+msgstr "§ä¨ì¥H¤Uªº¼È¦sÀÉ:"
+
+msgid " In current directory:\n"
+msgstr " ¦b¥Ø«eªº¥Ø¿ý:\n"
+
+msgid " Using specified name:\n"
+msgstr " Using specified name:\n"
+
+msgid " In directory "
+msgstr " ¦b¥Ø¿ý "
+
+msgid " -- none --\n"
+msgstr " -- µL --\n"
+
+msgid " owned by: "
+msgstr " ¾Ö¦³ªÌ: "
+
+msgid " dated: "
+msgstr " ¤é´Á: "
+
+msgid " dated: "
+msgstr " ¤é´Á: "
+
+msgid " [from Vim version 3.0]"
+msgstr " [±q Vim ª©¥» 3.0]"
+
+msgid " [does not look like a Vim swap file]"
+msgstr " [¤£¹³ Vim ªº¼È¦sÀÉ]"
+
+msgid " file name: "
+msgstr " ÀɦW: "
+
+msgid ""
+"\n"
+" modified: "
+msgstr ""
+"\n"
+" ­×§ï¹L: "
+
+msgid "YES"
+msgstr "¬O"
+
+msgid "no"
+msgstr "§_"
+
+msgid ""
+"\n"
+" user name: "
+msgstr ""
+"\n"
+" ¨Ï¥ÎªÌ: "
+
+msgid " host name: "
+msgstr " ¥D¾÷¦WºÙ: "
+
+msgid ""
+"\n"
+" host name: "
+msgstr ""
+"\n"
+" ¥D¾÷¦WºÙ: "
+
+msgid ""
+"\n"
+" process ID: "
+msgstr ""
+"\n"
+" process ID: "
+
+msgid " (still running)"
+msgstr " (°õ¦æ¤¤)"
+
+msgid ""
+"\n"
+" [not usable with this version of Vim]"
+msgstr ""
+"\n"
+" [µLªk¦b¥»ª©¥»ªº Vim ¤W¨Ï¥Î]"
+
+msgid ""
+"\n"
+" [not usable on this computer]"
+msgstr ""
+"\n"
+" [µLªk¦b¥»¹q¸£¤W¨Ï¥Î]"
+
+msgid " [cannot be read]"
+msgstr " [µLªkŪ¨ú]"
+
+msgid " [cannot be opened]"
+msgstr " [µLªk¶}±Ò]"
+
+msgid "E313: Cannot preserve, there is no swap file"
+msgstr "E313: µLªk«O¯d, ¤£¨Ï¥Î¼È¦sÀÉ"
+
+msgid "File preserved"
+msgstr "Àɮפw«O¯d"
+
+msgid "E314: Preserve failed"
+msgstr "E314: «O¯d¥¢±Ñ"
+
+#, c-format
+msgid "E315: ml_get: invalid lnum: %ld"
+msgstr "E315: ml_get: ¿ù»~ªº lnum: %ld"
+
+#, c-format
+msgid "E316: ml_get: cannot find line %ld"
+msgstr "E316: ml_get: §ä¤£¨ì²Ä %ld ¦æ "
+
+msgid "E317: pointer block id wrong 3"
+msgstr "E317: «ü¼Ð°Ï¶ô id ¿ù»~ 3"
+
+msgid "stack_idx should be 0"
+msgstr "stack_idx À³¸Ó¬O 0"
+
+msgid "E318: Updated too many blocks?"
+msgstr "E318: §ó·s¤Ó¦h°Ï¶ô?"
+
+msgid "E317: pointer block id wrong 4"
+msgstr "E317: «ü¼Ð°Ï¶ô id ¿ù»~ 4"
+
+msgid "deleted block 1?"
+msgstr "§R°£°Ï¶ô 1?"
+
+#, c-format
+msgid "E320: Cannot find line %ld"
+msgstr "E320: §ä¤£¨ì²Ä %ld ¦æ "
+
+msgid "E317: pointer block id wrong"
+msgstr "E317: «ü¼Ð°Ï¶ô id ¿ù»~"
+
+msgid "pe_line_count is zero"
+msgstr "pe_line_count ¬°¹s"
+
+#, c-format
+msgid "E322: line number out of range: %ld past the end"
+msgstr "E322: ¦æ¸¹¶W¥X½d³ò: %ld ¶W¹Lµ²§À"
+
+#, c-format
+msgid "E323: line count wrong in block %ld"
+msgstr "E323: °Ï¶ô %ld ¦æ¼Æ¿ù»~"
+
+msgid "Stack size increases"
+msgstr "°ïÅ|¤j¤p¼W¥["
+
+msgid "E317: pointer block id wrong 2"
+msgstr "E317: «ü¼Ð°Ï¶ô id ¿ù 2"
+
+msgid "E325: ATTENTION"
+msgstr "E325: ª`·N"
+
+msgid ""
+"\n"
+"Found a swap file by the name \""
+msgstr ""
+"\n"
+"§ä¨ì¼È¦sÀÉ \""
+
+msgid "While opening file \""
+msgstr "¦b¶}±ÒÀÉ®× \""
+
+msgid " NEWER than swap file!\n"
+msgstr " ¤ñ¼È¦sÀɧó·s!\n"
+
+#. Some of these messages are long to allow translation to
+#. * other languages.
+msgid ""
+"\n"
+"(1) Another program may be editing the same file.\n"
+" If this is the case, be careful not to end up with two\n"
+" different instances of the same file when making changes.\n"
+msgstr ""
+"\n"
+"(1) ¥i¯à¦³¥t¤@­Óµ{¦¡¤]¦b½s¿è¦P¤@­ÓÀÉ®×.\n"
+" ¦pªG¬O³o¼Ë¡A½Ð¤p¤ß¤£­n¨âÃä¤@°_¼g¤J¡A¤£µM§Aªº§V¤O³£·|­t½Ñ¬y¤ô¡C\n"
+
+msgid " Quit, or continue with caution.\n"
+msgstr " Â÷¶}¡A©Î¬OÄ~Äò½s¿è¡C\n"
+
+msgid ""
+"\n"
+"(2) An edit session for this file crashed.\n"
+msgstr ""
+"\n"
+"(2) «e¦¸½s¿è¦¹Àɮɷí¾÷\n"
+
+msgid " If this is the case, use \":recover\" or \"vim -r "
+msgstr " ¦pªG¬O³o¼Ë, ½Ð¥Î \":recover\" ©Î \"vim -r"
+
+msgid ""
+"\"\n"
+" to recover the changes (see \":help recovery\").\n"
+msgstr ""
+"\"\n"
+" ¨Ó±Ï¦^­×§ï¸ê®Æ (¸Ô²Ó»¡©ú½Ð¬Ý \":help recovery\").\n"
+
+msgid " If you did this already, delete the swap file \""
+msgstr " ¦pªG¸Ó±Ïªº³£¤w¸g±Ï¤F, ½Ðª½±µ§R°£¦¹¼È¦sÀÉ \""
+
+msgid ""
+"\"\n"
+" to avoid this message.\n"
+msgstr ""
+"\"\n"
+" ¥HÁקK¦A¬Ý¨ì¦¹°T®§.\n"
+
+msgid "Swap file \""
+msgstr "¼È¦sÀÉ \""
+
+msgid "\" already exists!"
+msgstr "\" ¤w¸g¦s¦b¤F!"
+
+msgid "VIM - ATTENTION"
+msgstr "VIM - ª`·N"
+
+msgid "Swap file already exists!"
+msgstr "¼È¦sÀɤw¸g¦s¦b!"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"¥H°ßŪ¤è¦¡¶}±Ò(&O)\n"
+"ª½±µ½s¿è(&E)\n"
+"­×´_(&R)\n"
+"Â÷¶}(&Q)\n"
+"¸õ¥X(&A)"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Quit\n"
+"&Abort\n"
+"&Delete it"
+msgstr ""
+"¥H°ßŪ¤è¦¡¶}±Ò(&O)\n"
+"ª½±µ½s¿è(&E)\n"
+"­×´_(&R)\n"
+"Â÷¶}(&Q)\n"
+"¸õ¥X(&A)\n"
+"§R°£¼È¦sÀÉ(&D)"
+
+msgid "E326: Too many swap files found"
+msgstr "E326: §ä¨ì¤Ó¦h¼È¦sÀÉ"
+
+msgid "E327: Part of menu-item path is not sub-menu"
+msgstr "E327: ³¡¥÷¿ï¶µ¸ô®|¤£¬O¤l¿ï³æ"
+
+msgid "E328: Menu only exists in another mode"
+msgstr "E328: ¿ï³æ¥u¯à¦b¨ä¥¦¼Ò¦¡¤¤¨Ï¥Î"
+
+msgid "E329: No menu of that name"
+msgstr "E329: ¨S¦³¨º¼Ëªº¿ï³æ"
+
+msgid "E330: Menu path must not lead to a sub-menu"
+msgstr "E330: ¿ï³æ¸ô®|¤£¯à«ü¦V¤l¿ï³æ"
+
+msgid "E331: Must not add menu items directly to menu bar"
+msgstr "E331: ¤£¯àª½±µ§â¿ï¶µ¥[¨ì¿ï³æ¦C¤¤"
+
+msgid "E332: Separator cannot be part of a menu path"
+msgstr "E332: ¤À¹j½u¤£¯à¬O¿ï³æ¸ô®|ªº¤@³¡¥÷"
+
+#. Now we have found the matching menu, and we list the mappings
+#. Highlight title
+msgid ""
+"\n"
+"--- Menus ---"
+msgstr ""
+"\n"
+"--- ¿ï³æ ---"
+
+msgid "Tear off this menu"
+msgstr "¤Á¤U¦¹¿ï³æ"
+
+msgid "E333: Menu path must lead to a menu item"
+msgstr "E333: ¿ï³æ¸ô®|¥²»Ý«ü¦V¤@­Ó¿ï¶µ"
+
+#, c-format
+msgid "E334: Menu not found: %s"
+msgstr "E334: [¿ï³æ] §ä¤£¨ì %s"
+
+#, c-format
+msgid "E335: Menu not defined for %s mode"
+msgstr "E335: %s ¼Ò¦¡¥¼©w¸q¿ï³æ"
+
+msgid "E336: Menu path must lead to a sub-menu"
+msgstr "E336: ¿ï³æ¸ô®|¥²»Ý«ü¦V¤l¿ï³æ"
+
+msgid "E337: Menu not found - check menu names"
+msgstr "E337: §ä¤£¨ì¿ï³æ - ½ÐÀˬd¿ï³æ¦WºÙ"
+
+#, c-format
+msgid "Error detected while processing %s:"
+msgstr "³B²z %s ®Éµo¥Í¿ù»~:"
+
+#, c-format
+msgid "line %4ld:"
+msgstr "¦æ %4ld:"
+
+msgid "[string too long]"
+msgstr "[¦¹¦æ¹Lªø]"
+
+msgid "Messages maintainer: Bram Moolenaar <Bram@vim.org>"
+msgstr ""
+"¥¿Å餤¤å°T®§ºûÅ@ªÌ: Francis S.Lin <piaip@csie.ntu.edu."
+"tw>, Cecil Sheng <b7506022@csie.ntu.edu.tw>"
+
+msgid "Interrupt: "
+msgstr "¤w¤¤Â_: "
+
+msgid "Hit ENTER to continue"
+msgstr "½Ð«ö ENTER Ä~Äò"
+
+msgid "Hit ENTER or type command to continue"
+msgstr "½Ð«ö ENTER ©Î¨ä¥¦©R¥O¥HÄ~Äò"
+
+msgid "-- More --"
+msgstr "-- ©|¦³ --"
+
+msgid " (RET/BS: line, SPACE/b: page, d/u: half page, q: quit)"
+msgstr " (RET/BS: ¦V¤U/¦V¤W¤@¦æ, ªÅ¥ÕÁä/b: ¤@­¶, d/u: ¥b­¶, q: Â÷¶})"
+
+msgid " (RET: line, SPACE: page, d: half page, q: quit)"
+msgstr " (RET: ¦V¤U¤@¦æ, ªÅ¥ÕÁä: ¤@­¶, d: ¥b­¶, q: Â÷¶})"
+
+msgid "Question"
+msgstr "°ÝÃD"
+
+msgid ""
+"&Yes\n"
+"&No"
+msgstr ""
+"&Y¬O\n"
+"&N§_"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"Save &All\n"
+"&Discard All\n"
+"&Cancel"
+msgstr ""
+"&Y¬O\n"
+"&N§_\n"
+"&A¥þ³¡¦sÀÉ\n"
+"&D¥þ³¡¤£¦s\n"
+"&C¨ú®ø"
+
+msgid "Save File dialog"
+msgstr "¦sÀÉ"
+
+msgid "Open File dialog"
+msgstr "¶}ÀÉ"
+
+#. TODO: non-GUI file selector here
+msgid "E338: Sorry, no file browser in console mode"
+msgstr "E338: ¥D±±¥x(Console)¼Ò¦¡®É¨S¦³ÀÉ®×ÂsÄý¾¹(file browser)"
+
+msgid "W10: Warning: Changing a readonly file"
+msgstr "W10: ª`·N: §A¥¿¦b­×§ï¤@­Ó°ßŪÀÉ"
+
+msgid "1 more line"
+msgstr "ÁÙ¦³¤@¦æ "
+
+msgid "1 line less"
+msgstr "¤Ö©ó¤@¦æ "
+
+#, c-format
+msgid "%ld more lines"
+msgstr "ÁÙ¦³ %ld ¦æ "
+
+#, c-format
+msgid "%ld fewer lines"
+msgstr "¥u³Ñ %ld ¦æ "
+
+msgid " (Interrupted)"
+msgstr " (¤w¤¤Â_)"
+
+msgid "Vim: preserving files...\n"
+msgstr "Vim: «O¯dÀɮפ¤...\n"
+
+#. close all memfiles, without deleting
+msgid "Vim: Finished.\n"
+msgstr "Vim: µ²§ô.\n"
+
+#, c-format
+msgid "ERROR: "
+msgstr "¿ù»~: "
+
+#, c-format
+msgid ""
+"\n"
+"[bytes] total alloc-freed %lu-%lu, in use %lu, peak use %lu\n"
+msgstr ""
+"\n"
+"[bytes] ¥þ³¡ alloc-freed %lu-%lu, ¨Ï¥Î¤¤ %lu, peak ¨Ï¥Î %lu\n"
+
+#, c-format
+msgid ""
+"[calls] total re/malloc()'s %lu, total free()'s %lu\n"
+"\n"
+msgstr ""
+"[©I¥s] ¥þ³¡ re/malloc(): %lu, ¥þ³¡ free()': %lu\n"
+"\n"
+
+msgid "E340: Line is becoming too long"
+msgstr "E340: ¦¹¦æ¹Lªø"
+
+#, c-format
+msgid "E341: Internal error: lalloc(%ld, )"
+msgstr "E341: ¤º³¡¿ù»~: lalloc(%ld, )"
+
+#, c-format
+msgid "E342: Out of memory! (allocating %lu bytes)"
+msgstr "E342: °O¾ÐÅ餣¨¬! (¹Á¸Õ°t¸m %lu ¦ì¤¸²Õ)"
+
+#, c-format
+msgid "Calling shell to execute: \"%s\""
+msgstr "©I¥s shell °õ¦æ: \"%s\""
+
+msgid "E545: Missing colon"
+msgstr "E545: ¯Ê¤Ö colon"
+
+msgid "E546: Illegal mode"
+msgstr "E546: ¤£¥¿½Tªº¼Ò¦¡"
+
+msgid "E547: Illegal mouseshape"
+msgstr "E547: ¤£¥¿½Tªº·Æ¹«§Îª¬"
+
+msgid "E548: digit expected"
+msgstr "E548: À³¸Ó­n¦³¼Æ¦r"
+
+msgid "E549: Illegal percentage"
+msgstr "E549: ¤£¥¿½Tªº¦Ê¤À¤ñ"
+
+msgid "Enter encryption key: "
+msgstr "¿é¤J±K½X: "
+
+msgid "Enter same key again: "
+msgstr "½Ð¦A¿é¤J¤@¦¸: "
+
+msgid "Keys don't match!"
+msgstr "¨â¦¸¿é¤J±K½X¤£¬Û¦P!"
+
+#, c-format
+msgid ""
+"E343: Invalid path: '**[number]' must be at the end of the path or be "
+"followed by '%s'."
+msgstr "E343: ¤£¥¿½Tªº¸ô®|: '**[number]' ¥²»Ý­n¦b¸ô®|µ²§À©Î­n±µµÛ '%s'"
+
+#, c-format
+msgid "E344: Can't find directory \"%s\" in cdpath"
+msgstr "E344: cdpath ¤¤¨S¦³¥Ø¿ý \"%s\""
+
+#, c-format
+msgid "E345: Can't find file \"%s\" in path"
+msgstr "E345: ¦b¸ô®|¤¤§ä¤£¨ìÀÉ®× \"%s\""
+
+#, c-format
+msgid "E346: No more directory \"%s\" found in cdpath"
+msgstr "E346: ¦b¸ô®|¤¤§ä¤£¨ì§ó¦hªºÀÉ®× \"%s\""
+
+#, c-format
+msgid "E347: No more file \"%s\" found in path"
+msgstr "E347: ¦b¸ô®|¤¤§ä¤£¨ì§ó¦hªºÀÉ®× \"%s\""
+
+msgid "E550: Missing colon"
+msgstr "E550: ¯Ê¤Ö colon"
+
+msgid "E551: Illegal component"
+msgstr "E551: ¤£¥¿½Tªº¼Ò¦¡"
+
+msgid "E552: digit expected"
+msgstr "E552: À³¸Ó­n¦³¼Æ¦r"
+
+#. Get here when the server can't be found.
+msgid "Cannot connect to Netbeans #2"
+msgstr "µLªk³s±µ¨ì Netbeans #2"
+
+msgid "Cannot connect to Netbeans"
+msgstr "µLªk³s±µ¨ì Netbeans"
+
+#, c-format
+msgid "E668: Wrong access mode for NetBeans connection info file: \"%s\""
+msgstr "E668: NetBeans ³s½u¸ê°TÀÉ®×: \"%s\" ¦s¨ú¼Ò¦¡¤£¥¿½T"
+
+msgid "read from Netbeans socket"
+msgstr "¥Ñ Netbeans socket Ū¨ú"
+
+#, c-format
+msgid "E658: NetBeans connection lost for buffer %ld"
+msgstr "E658: ½w½Ä°Ï %ld »P NetBeans ªº³s½u¤w¤¤Â_"
+
+msgid "Warning: terminal cannot highlight"
+msgstr "ª`·N: §Aªº²×ºÝ¾÷µLªkÅã¥Ü°ª«G«×"
+
+msgid "E348: No string under cursor"
+msgstr "E348: ´å¼Ð³B¨S¦³¦r¦ê"
+
+msgid "E349: No identifier under cursor"
+msgstr "E349: ´å¼Ð³B¨S¦³ÃѧO¦r"
+
+msgid "E352: Cannot erase folds with current 'foldmethod'"
+msgstr "E352: µLªk¦b¥Ø«eªº 'foldmethod' ¤U§R°£ fold"
+
+msgid "E664: changelist is empty"
+msgstr "E664: Åܧó¦Cªí¬OªÅªº"
+
+msgid "E662: At start of changelist"
+msgstr "E662: ¤w¦bÅܧó¦Cªíªº¶}ÀY"
+
+msgid "E663: At end of changelist"
+msgstr "E663: ¤w¦bÅܧó¦Cªíªºµ²§À"
+
+msgid "Type :quit<Enter> to exit Vim"
+msgstr "­nÂ÷¶} Vim ½Ð¿é¤J :quit<Enter> "
+
+#, c-format
+msgid "1 line %sed 1 time"
+msgstr "¤@¦æ %s ¹L ¤@¦¸"
+
+#, c-format
+msgid "1 line %sed %d times"
+msgstr "¤@¦æ %s ¹L %d ¦¸"
+
+#, c-format
+msgid "%ld lines %sed 1 time"
+msgstr "%ld ¦æ %s ¹L ¤@¦¸"
+
+#, c-format
+msgid "%ld lines %sed %d times"
+msgstr "%ld ¦æ %s ¹L %d ¦¸"
+
+#, c-format
+msgid "%ld lines to indent... "
+msgstr "ÁY±Æ %ld ¦æ... "
+
+msgid "1 line indented "
+msgstr "¤@¦æ¤wÁY±Æ"
+
+#, c-format
+msgid "%ld lines indented "
+msgstr "¤wÁY±Æ %ld ¦æ "
+
+#. must display the prompt
+msgid "cannot yank; delete anyway"
+msgstr "µLªk°Å¤U; ª½±µ§R°£"
+
+msgid "1 line changed"
+msgstr " 1 ¦æ ~ed"
+
+#, c-format
+msgid "%ld lines changed"
+msgstr "¤w§ïÅÜ %ld ¦æ "
+
+#, c-format
+msgid "freeing %ld lines"
+msgstr "ÄÀ©ñ %ld ¦æ¤¤ "
+
+msgid "1 line yanked"
+msgstr "¤w½Æ»s 1 ¦æ "
+
+#, c-format
+msgid "%ld lines yanked"
+msgstr "¤w½Æ»s %ld ¦æ "
+
+#, c-format
+msgid "E353: Nothing in register %s"
+msgstr "E353: ¼È¦s¾¹ %s ¸Ì¨S¦³ªF¦è"
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Registers ---"
+msgstr ""
+"\n"
+"--- ¼È¦s¾¹ ---"
+
+msgid "Illegal register name"
+msgstr "¤£¥¿½Tªº¼È¦s¾¹¦WºÙ"
+
+#, c-format
+msgid ""
+"\n"
+"# Registers:\n"
+msgstr ""
+"\n"
+"# ¼È¦s¾¹:\n"
+
+#, c-format
+msgid "E574: Unknown register type %d"
+msgstr "E574: ¥¼ª¾ªºµù¥U«¬ºA: %d"
+
+#, c-format
+msgid "E354: Invalid register name: '%s'"
+msgstr "E354: ¼È¦s¾¹¦WºÙ¿ù»~: '%s'"
+
+#, c-format
+msgid "%ld Cols; "
+msgstr "%ld Äæ; "
+
+#, c-format
+msgid "Selected %s%ld of %ld Lines; %ld of %ld Words; %ld of %ld Bytes"
+msgstr "¿ï¾Ü¤F %s%ld/%ld ¦æ; %ld/%ld ¦r(Word); %ld/%ld ¦r¤¸(Bytes)"
+
+#, c-format
+msgid "Col %s of %s; Line %ld of %ld; Word %ld of %ld; Byte %ld of %ld"
+msgstr "Äæ %s/%s; ¦æ %ld/%ld; ¦r(Word) %ld/%ld; ¦r¤¸(Byte) %ld/%ld"
+
+#, c-format
+msgid "(+%ld for BOM)"
+msgstr "(+%ld for BOM)"
+
+msgid "%<%f%h%m%=Page %N"
+msgstr "%<%f%h%m%=²Ä %N ­¶"
+
+# ? what's this for?
+msgid "Thanks for flying Vim"
+msgstr "·PÁ±z·R¥Î Vim"
+
+msgid "E518: Unknown option"
+msgstr "E518: ¤£¥¿½Tªº¿ï¶µ"
+
+msgid "E519: Option not supported"
+msgstr "E519: ¤£¤ä´©¸Ó¿ï¶µ"
+
+msgid "E520: Not allowed in a modeline"
+msgstr "E520: ¤£¯à¦b Modeline ¸Ì¥X²{"
+
+msgid ""
+"\n"
+"\tLast set from "
+msgstr ""
+"\n"
+"\t¤W¦¸³]©w: "
+
+msgid "E521: Number required after ="
+msgstr "E521: = «á»Ý­n¦³¼Æ¦r"
+
+msgid "E522: Not found in termcap"
+msgstr "E522: Termcap ¸Ì­±§ä¤£¨ì"
+
+#, c-format
+msgid "E539: Illegal character <%s>"
+msgstr "E539: ¤£¥¿½Tªº¦r¤¸ <%s>"
+
+msgid "E529: Cannot set 'term' to empty string"
+msgstr "E529: µLªk³]©w 'term' ¬°ªÅ¦r¦ê"
+
+msgid "E530: Cannot change term in GUI"
+msgstr "E530: ¦b¹Ï«¬¬É­±¤¤µLªk¤Á´« term"
+
+msgid "E531: Use \":gui\" to start the GUI"
+msgstr "E531: ¿é¤J \":gui\" ¨Ó±Ò°Ê¹Ï§Î¬É­±"
+
+msgid "E589: 'backupext' and 'patchmode' are equal"
+msgstr "E589: 'backupext' ¸ò 'patchmode' ¬O¤@¼Ëªº"
+
+msgid "E617: Cannot be changed in the GTK+ 2 GUI"
+msgstr "E617: ¦b¹Ï«¬¬É­±¤¤µLªk¤Á´« term"
+
+msgid "E524: Missing colon"
+msgstr "E524: ¯Ê¤Ö colon"
+
+msgid "E525: Zero length string"
+msgstr "E525: ¹sªø«×¦r¦ê"
+
+#, c-format
+msgid "E526: Missing number after <%s>"
+msgstr "E526: <%s> «á¯Ê¤Ö¼Æ¦r"
+
+msgid "E527: Missing comma"
+msgstr "E527: ¯Ê¤Ö³r¸¹"
+
+msgid "E528: Must specify a ' value"
+msgstr "E528: ¥²»Ý«ü©w¤@­Ó ' ­È"
+
+msgid "E595: contains unprintable or wide character"
+msgstr "E595: ¤º§tµLªkÅã¥Üªº¦r¤¸"
+
+msgid "E596: Invalid font(s)"
+msgstr "E596: ¤£¥¿½Tªº¦r«¬"
+
+msgid "E597: can't select fontset"
+msgstr "E597: µLªk¨Ï¥Î¦r«¬¶°(Fontset)"
+
+msgid "E598: Invalid fontset"
+msgstr "E598: ¤£¥¿½Tªº¦r«¬¶°(Fontset)"
+
+msgid "E533: can't select wide font"
+msgstr "E533: µLªk¨Ï¥Î³]©wªº¤¤¤å¦r«¬(Widefont)"
+
+msgid "E534: Invalid wide font"
+msgstr "E534: ¤£¥¿½Tªº¦r«¬(Widefont)"
+
+#, c-format
+msgid "E535: Illegal character after <%c>"
+msgstr "E535: <%c> «á¦³¤£¥¿½Tªº¦r¤¸"
+
+msgid "E536: comma required"
+msgstr "E536: »Ý­n³r¸¹"
+
+#, c-format
+msgid "E537: 'commentstring' must be empty or contain %s"
+msgstr "E537: 'commentstring' ¥²»Ý¬OªÅ¥Õ©Î¥]§t %s"
+
+msgid "E538: No mouse support"
+msgstr "E538: ¤£¤ä´©·Æ¹«"
+
+msgid "E540: Unclosed expression sequence"
+msgstr "E540: ¨S¦³µ²§ôªº¹Bºâ¦¡: "
+
+msgid "E541: too many items"
+msgstr "E541: ¤Ó¦h¶µ¥Ø"
+
+msgid "E542: unbalanced groups"
+msgstr "E542: ¤£¹ïºÙªº group"
+
+msgid "E590: A preview window already exists"
+msgstr "E590: ¹wµøªºµøµ¡¤w¸g¦s¦b¤F"
+
+msgid "W17: Arabic requires UTF-8, do ':set encoding=utf-8'"
+msgstr "W17: Arabic »Ý­n UTF-8, ½Ð°õ¦æ ':set encoding=utf-8'"
+
+#, c-format
+msgid "E593: Need at least %d lines"
+msgstr "E593: ¦Ü¤Ö»Ý­n %d ¦æ "
+
+#, c-format
+msgid "E594: Need at least %d columns"
+msgstr "E594: ¦Ü¤Ö»Ý­n %d Äæ"
+
+#, c-format
+msgid "E355: Unknown option: %s"
+msgstr "E355: ¤£¥¿½Tªº¿ï¶µ: %s"
+
+msgid ""
+"\n"
+"--- Terminal codes ---"
+msgstr ""
+"\n"
+"--- ²×ºÝ¾÷½X ---"
+
+msgid ""
+"\n"
+"--- Global option values ---"
+msgstr ""
+"\n"
+"--- Global ¿ï¶µ­È ---"
+
+msgid ""
+"\n"
+"--- Local option values ---"
+msgstr ""
+"\n"
+"--- Local ¿ï¶µ­È ---"
+
+msgid ""
+"\n"
+"--- Options ---"
+msgstr ""
+"\n"
+"--- ¿ï¶µ ---"
+
+msgid "E356: get_varp ERROR"
+msgstr "E356: get_varp ¿ù»~"
+
+#, c-format
+msgid "E357: 'langmap': Matching character missing for %s"
+msgstr "E357: 'langmap': §ä¤£¨ì %s ¹ïÀ³ªº¦r¤¸"
+
+#, c-format
+msgid "E358: 'langmap': Extra characters after semicolon: %s"
+msgstr "E358: 'langmap': ¤À¸¹«á¦³¦h¾lªº¦r¤¸: %s"
+
+msgid "cannot open "
+msgstr "¤£¯à¶}±Ò"
+
+msgid "VIM: Can't open window!\n"
+msgstr "VIM: µLªk¶}±Òµøµ¡!\n"
+
+msgid "Need Amigados version 2.04 or later\n"
+msgstr "»Ý­n Amigados ª©¥» 2.04 ¥H¤W\n"
+
+#, c-format
+msgid "Need %s version %ld\n"
+msgstr "»Ý­n %s ª©¥» %ld\n"
+
+msgid "Cannot open NIL:\n"
+msgstr "µLªk¶}±Ò NIL:\n"
+
+msgid "Cannot create "
+msgstr "¤£¯à«Ø¥ß "
+
+#, c-format
+msgid "Vim exiting with %d\n"
+msgstr "Vim µ²§ô¶Ç¦^­È: %d\n"
+
+msgid "cannot change console mode ?!\n"
+msgstr "µLªk¤Á´«¥D±±¥x(console)¼Ò¦¡ !?\n"
+
+msgid "mch_get_shellsize: not a console??\n"
+msgstr "mch_get_shellsize: ¤£¬O¥D±±¥x(console)??\n"
+
+#. if Vim opened a window: Executing a shell may cause crashes
+msgid "E360: Cannot execute shell with -f option"
+msgstr "E360: ¤£¯à¥Î -f ¿ï¶µ°õ¦æ shell"
+
+msgid "Cannot execute "
+msgstr "¤£¯à°õ¦æ "
+
+msgid "shell "
+msgstr "shell "
+
+msgid " returned\n"
+msgstr " ¤wªð¦^\n"
+
+msgid "ANCHOR_BUF_SIZE too small."
+msgstr "ANCHOR_BUF_SIZE ¤Ó¤p"
+
+msgid "I/O ERROR"
+msgstr "I/O ¿ù»~"
+
+msgid "...(truncated)"
+msgstr "...(¤w¤Á±¼)"
+
+msgid "'columns' is not 80, cannot execute external commands"
+msgstr "'columns' ¤£¬O 80, µLªk°õ¦æ¥~³¡©R¥O"
+
+msgid "E237: Printer selection failed"
+msgstr "E237: µLªk¿ï¾Ü¦¹¦Lªí¾÷"
+
+#, c-format
+msgid "to %s on %s"
+msgstr "¨ì %s on %s"
+
+#, c-format
+msgid "E613: Unknown printer font: %s"
+msgstr "E613: ¤£¥¿½Tªº¦Lªí¾÷¦r«¬: %s"
+
+#, c-format
+msgid "E238: Print error: %s"
+msgstr "E238: ¦C¦L¿ù»~: %s"
+
+msgid "Unknown"
+msgstr "¥¼ª¾"
+
+#, c-format
+msgid "Printing '%s'"
+msgstr "¦C¦L¤¤: '%s'"
+
+#, c-format
+msgid "E244: Illegal charset name \"%s\" in font name \"%s\""
+msgstr "E244: ¦r¤¸¶° \"%s\" µLªk¹ïÀ³¦r«¬\"%s\""
+
+#, c-format
+msgid "E245: Illegal char '%c' in font name \"%s\""
+msgstr "E245: ¤£¥¿½Tªº¦r¤¸ '%c' ¥X²{¦b¦r«¬¦WºÙ \"%s\" ¤º"
+
+msgid "Vim: Double signal, exiting\n"
+msgstr "Vim: Âù­«signal, Â÷¶}¤¤\n"
+
+#, c-format
+msgid "Vim: Caught deadly signal %s\n"
+msgstr "Vim: CVim: ÄdºI¨ì«H¸¹(signal) %s\n"
+
+#, c-format
+msgid "Vim: Caught deadly signal\n"
+msgstr "Vim: ÄdºI¨ì­P©Rªº«H¸¹(deadly signale)\n"
+
+#, c-format
+msgid "Opening the X display took %ld msec"
+msgstr "¶}±Ò X Window ¯Ó®É %ld msec"
+
+msgid ""
+"\n"
+"Vim: Got X error\n"
+msgstr ""
+"\n"
+"Vim: X ¿ù»~\n"
+
+msgid "Testing the X display failed"
+msgstr "´ú¸Õ X Window ¥¢±Ñ"
+
+msgid "Opening the X display timed out"
+msgstr "¶}±Ò X Window ¹O®É"
+
+msgid ""
+"\n"
+"Cannot execute shell "
+msgstr ""
+"\n"
+"¤£¯à°õ¦æ shell"
+
+msgid ""
+"\n"
+"Cannot execute shell sh\n"
+msgstr ""
+"\n"
+"¤£¯à°õ¦æ shell sh\n"
+
+msgid ""
+"\n"
+"shell returned "
+msgstr ""
+"\n"
+"Shell ¤wªð¦^"
+
+msgid ""
+"\n"
+"Cannot create pipes\n"
+msgstr ""
+"\n"
+"¤£¯à«Ø¥ß pipe ºÞ½u\n"
+
+msgid ""
+"\n"
+"Cannot fork\n"
+msgstr ""
+"\n"
+"¤£¯à fork\n"
+
+msgid ""
+"\n"
+"Command terminated\n"
+msgstr ""
+"\n"
+"©R¥O¤w²×µ²\n"
+
+msgid "XSMP lost ICE connection"
+msgstr "XSMP ¥¢¥h ICE ³s½u"
+
+msgid "Opening the X display failed"
+msgstr "¶}±Ò X Window ¥¢±Ñ"
+
+msgid "XSMP handling save-yourself request"
+msgstr "XSMP ¥¿¦b³B²z¦Û§ÚÀx¦s­n¨D"
+
+msgid "XSMP opening connection"
+msgstr "¶}±Ò XSMP ³s½u¤¤"
+
+msgid "XSMP ICE connection watch failed"
+msgstr "XSMP ICE ³s½uºÊ¬Ý¥¢±Ñ"
+
+#, c-format
+msgid "XSMP SmcOpenConnection failed: %s"
+msgstr "XSMP SmcOpenConnection ¥¢±Ñ: %s"
+
+msgid "At line"
+msgstr "¦b¦æ¸¹ "
+
+msgid "Could not allocate memory for command line."
+msgstr "µLªk¬°©R¥O¦C°t¸m°O¾ÐÅé¡C"
+
+msgid "VIM Error"
+msgstr "VIM ¿ù»~"
+
+msgid "Could not load vim32.dll!"
+msgstr "µLªk¸ü¤J vim32.dll¡I"
+
+msgid "Could not fix up function pointers to the DLL!"
+msgstr "¤£¯à­×¥¿¨ç¦¡«ü¼Ð¨ì DLL!"
+
+#, c-format
+msgid "shell returned %d"
+msgstr "Shell ¶Ç¦^­È %d"
+
+#, c-format
+msgid "Vim: Caught %s event\n"
+msgstr "Vim: ÄdºI¨ì %s \n"
+
+msgid "close"
+msgstr "Ãö³¬"
+
+msgid "logoff"
+msgstr "µn¥X"
+
+msgid "shutdown"
+msgstr "Ãö¾÷"
+
+msgid "E371: Command not found"
+msgstr "E371: §ä¤£¨ì©R¥O"
+
+msgid ""
+"VIMRUN.EXE not found in your $PATH.\n"
+"External commands will not pause after completion.\n"
+"See :help win32-vimrun for more information."
+msgstr ""
+"¦b§Aªº $PATH ¤¤§ä¤£¨ì VIMRUN.EXE.\n"
+"¥~³¡©R¥O°õ¦æ§¹²¦«á±N¤£·|¼È°±.\n"
+"¶i¤@¨B»¡©ú½Ð°õ¦æ :help win32-vimrun "
+
+msgid "Vim Warning"
+msgstr "Vim ĵ§i"
+
+#, c-format
+msgid "E372: Too many %%%c in format string"
+msgstr "E372: ®æ¦¡¤Æ¦r¦ê¸Ì¦³¤Ó¦h %%%c "
+
+#, c-format
+msgid "E373: Unexpected %%%c in format string"
+msgstr "E373: ®æ¦¡¤Æ¦r¦ê¤£À³¸Ó¥X²{ %%%c "
+
+msgid "E374: Missing ] in format string"
+msgstr "E374: ®æ¦¡¤Æ¦r¦ê¸Ì¤Ö¤F ]"
+
+#, c-format
+msgid "E375: Unsupported %%%c in format string"
+msgstr "E375: ®æ¦¡¤Æ¦r¦ê¸Ì¦³¤£¤ä´©ªº %%%c "
+
+#, c-format
+msgid "E376: Invalid %%%c in format string prefix"
+msgstr "E376: ®æ¦¡¤Æ¦r¦ê¶}ÀY¸Ì¦³¤£¥¿½Tªº %%%c "
+
+#, c-format
+msgid "E377: Invalid %%%c in format string"
+msgstr "E377: ®æ¦¡¤Æ¦r¦ê¸Ì¦³¤£¥¿½Tªº %%%c "
+
+msgid "E378: 'errorformat' contains no pattern"
+msgstr "E378: 'errorformat' ¥¼³]©w"
+
+msgid "E379: Missing or empty directory name"
+msgstr "E379: §ä¤£¨ì¥Ø¿ý¦WºÙ©Î¬OªÅªº¥Ø¿ý¦WºÙ"
+
+msgid "E553: No more items"
+msgstr "E553: ¨S¦³¨ä¥¦¶µ¥Ø"
+
+#, c-format
+msgid "(%d of %d)%s%s: "
+msgstr "(%d / %d)%s%s: "
+
+msgid " (line deleted)"
+msgstr " (¦æ¤w§R°£)"
+
+msgid "E380: At bottom of quickfix stack"
+msgstr "E380: Quickfix °ïÅ|µ²§À"
+
+msgid "E381: At top of quickfix stack"
+msgstr "E381: Quickfix °ïÅ|³»ºÝ"
+
+#, c-format
+msgid "error list %d of %d; %d errors"
+msgstr "¿ù»~¦Cªí %d/%d; ¦@¦³ %d ¶µ¿ù»~"
+
+msgid "E382: Cannot write, 'buftype' option is set"
+msgstr "E382: µLªk¼g¤J¡A'buftype' ¿ï¶µ¤w³]©w"
+
+#, c-format
+msgid "E369: invalid item in %s%%[]"
+msgstr "E369: ¤£¥¿½Tªº¶µ¥Ø¡G %s%%[]"
+
+msgid "E339: Pattern too long"
+msgstr "E339: ¦W¦r¤Óªø"
+
+msgid "E50: Too many \\z("
+msgstr "E50: ¤Ó¦h \\z("
+
+#, c-format
+msgid "E51: Too many %s("
+msgstr "E51: ¤Ó¦h %s("
+
+msgid "E52: Unmatched \\z("
+msgstr "E52: µL¹ïÀ³ªº \\z("
+
+#, c-format
+msgid "E53: Unmatched %s%%("
+msgstr "E53: µL¹ïÀ³ªº %s%%("
+
+#, c-format
+msgid "E54: Unmatched %s("
+msgstr "E54: µL¹ïÀ³ªº %s("
+
+#, c-format
+msgid "E55: Unmatched %s)"
+msgstr "E55: µL¹ïÀ³ªº %s)"
+
+#, c-format
+msgid "E56: %s* operand could be empty"
+msgstr "E56: %s* ¹Bºâ¤¸¥i¥H¬OªÅªº"
+
+#, c-format
+msgid "E57: %s+ operand could be empty"
+msgstr "E57: %s+ ¹Bºâ¤¸¥i¥H¬OªÅªº"
+
+#, c-format
+msgid "E59: invalid character after %s@"
+msgstr "E59: «á­±¦³¤£¥¿½Tªº¦r¤¸: %s@"
+
+#, c-format
+msgid "E58: %s{ operand could be empty"
+msgstr "E58: %s{ ¹Bºâ¤¸¥i¥H¬OªÅªº"
+
+#, c-format
+msgid "E60: Too many complex %s{...}s"
+msgstr "E60: ¤Ó¦h½ÆÂøªº %s{...}s"
+
+#, c-format
+msgid "E61: Nested %s*"
+msgstr "E61: ±_ª¬ %s*"
+
+#, c-format
+msgid "E62: Nested %s%c"
+msgstr "E62: ±_ª¬ %s%c"
+
+msgid "E63: invalid use of \\_"
+msgstr "E63: ¤£¥¿½Tªº¨Ï¥Î \\_"
+
+#, c-format
+msgid "E64: %s%c follows nothing"
+msgstr "E64: %s%c ¨S¦³±µªF¦è"
+
+msgid "E65: Illegal back reference"
+msgstr "E65: ¤£¥¿½Tªº¤Ï¦V°Ñ¦Ò"
+
+msgid "E66: \\z( not allowed here"
+msgstr "E66: \\z( ¤£¯à¦b¦¹¥X²{"
+
+msgid "E67: \\z1 - \\z9 not allowed here"
+msgstr "E67: \\z1 - \\z9 ¤£¯à¦b¦¹¥X²{"
+
+msgid "E68: Invalid character after \\z"
+msgstr "E68: «á­±¦³¤£¥¿½Tªº¦r¤¸: \\z"
+
+#, c-format
+msgid "E69: Missing ] after %s%%["
+msgstr "E69: %s%%[ «á¯Ê¤Ö ]"
+
+#, c-format
+msgid "E70: Empty %s%%[]"
+msgstr "E70: ªÅªº %s%%[]"
+
+#, c-format
+msgid "E71: Invalid character after %s%%"
+msgstr "E71: «á­±¦³¤£¥¿½Tªº¦r¤¸: %s%%"
+
+#, c-format
+msgid "E554: Syntax error in %s{...}"
+msgstr "E554: »yªk¿ù»~: %s{...}"
+
+msgid "E361: Crash intercepted; regexp too complex?"
+msgstr "E361: µLªk°õ¦æ; regular expression ¤Ó½ÆÂø?"
+
+msgid "E363: pattern caused out-of-stack error"
+msgstr "E363: regular expression ³y¦¨°ïÅ|¥Î¥úªº¿ù»~"
+
+msgid "External submatches:\n"
+msgstr "¥~³¡²Å¦X:\n"
+
+#, c-format
+msgid "+--%3ld lines folded "
+msgstr "+--¤w fold %3ld ¦æ "
+
+msgid " VREPLACE"
+msgstr " V-¨ú¥N"
+
+msgid " REPLACE"
+msgstr " ¨ú¥N"
+
+msgid " REVERSE"
+msgstr " ¤ÏÂà"
+
+msgid " INSERT"
+msgstr " ´¡¤J"
+
+msgid " (insert)"
+msgstr " (´¡¤J)"
+
+msgid " (replace)"
+msgstr " (¨ú¥N)"
+
+msgid " (vreplace)"
+msgstr " (v-¨ú¥N)"
+
+msgid " Hebrew"
+msgstr " Hebrew"
+
+msgid " Arabic"
+msgstr " Arabic"
+
+msgid " (lang)"
+msgstr " (»y¨¥)"
+
+msgid " (paste)"
+msgstr " (¶K¤W)"
+
+msgid " VISUAL"
+msgstr " ¿ï¨ú"
+
+msgid " VISUAL LINE"
+msgstr " [¦æ] "
+
+msgid " VISUAL BLOCK"
+msgstr " [°Ï¶ô] "
+
+msgid " SELECT"
+msgstr " ¿ï¨ú"
+
+msgid " SELECT LINE"
+msgstr " ¿ï¨ú¦æ "
+
+msgid " SELECT BLOCK"
+msgstr " ¿ï¨ú°Ï¶ô"
+
+msgid "recording"
+msgstr "°O¿ý¤¤"
+
+msgid "search hit TOP, continuing at BOTTOM"
+msgstr "¤w·j´M¨ìÀɮ׶}ÀY¡F¦A±qµ²§ÀÄ~Äò·j´M"
+
+msgid "search hit BOTTOM, continuing at TOP"
+msgstr "¤w·j´M¨ìÀÉ®×µ²§À¡F¦A±q¶}ÀYÄ~Äò·j´M"
+
+#, c-format
+msgid "E383: Invalid search string: %s"
+msgstr "E383: ¿ù»~ªº·j´M¦r¦ê: %s"
+
+#, c-format
+msgid "E384: search hit TOP without match for: %s"
+msgstr "E384: ¤w·j´M¨ìÀɮ׶}ÀY¤´§ä¤£¨ì %s"
+
+#, c-format
+msgid "E385: search hit BOTTOM without match for: %s"
+msgstr "E385: ¤w·j´M¨ìÀÉ®×µ²§À¤´§ä¤£¨ì %s"
+
+msgid "E386: Expected '?' or '/' after ';'"
+msgstr "E386: ¦b ';' «á­±À³¸Ó¦³ '?' ©Î '/'"
+
+msgid " (includes previously listed match)"
+msgstr " (¥]¬A«e¦¸¦C¥X²Å¦X¶µ)"
+
+#. cursor at status line
+msgid "--- Included files "
+msgstr "--- ¤Þ¤JÀÉ®× "
+
+msgid "not found "
+msgstr "§ä¤£¨ì "
+
+msgid "in path ---\n"
+msgstr "---\n"
+
+msgid " (Already listed)"
+msgstr " (¤w¦C¥X)"
+
+msgid " NOT FOUND"
+msgstr " §ä¤£¨ì"
+
+#, c-format
+msgid "Scanning included file: %s"
+msgstr "·j´M¤Þ¤JÀÉ®×: %s"
+
+msgid "E387: Match is on current line"
+msgstr "E387: ¥Ø«e©Ò¦b¦æ¤¤¦³¤@¤Ç°t"
+
+msgid "All included files were found"
+msgstr "©Ò¦³¤Þ¤JÀɮ׳£¤w§ä¨ì"
+
+msgid "No included files"
+msgstr "¨S¦³¤Þ¤JÀÉ®×"
+
+msgid "E388: Couldn't find definition"
+msgstr "E388: §ä¤£¨ì©w¸q"
+
+msgid "E389: Couldn't find pattern"
+msgstr "E389: §ä¤£¨ì pattern"
+
+#, c-format
+msgid "E390: Illegal argument: %s"
+msgstr "E390: °Ñ¼Æ¤£¥¿½T: %s"
+
+#, c-format
+msgid "E391: No such syntax cluster: %s"
+msgstr "E391: µL¦¹ syntax cluster: \"%s\""
+
+msgid "No Syntax items defined for this buffer"
+msgstr "³o­Ó½w½Ä°Ï¨S¦³©w¸q¥ô¦ó»yªk"
+
+msgid "syncing on C-style comments"
+msgstr "C»y¨¥¦¡µù¸Ñ¦P¨B¤Æ¤¤"
+
+msgid "no syncing"
+msgstr "¨S¦³¦P¨B¤Æ"
+
+msgid "syncing starts "
+msgstr "¦P¨B¤Æ¶}©l"
+
+msgid " lines before top line"
+msgstr "¦æ¸¹¶W¥X½d³ò"
+
+msgid ""
+"\n"
+"--- Syntax sync items ---"
+msgstr ""
+"\n"
+"--- »yªk¦P¨Bª«¥ó (Syntax sync items) ---"
+
+msgid ""
+"\n"
+"syncing on items"
+msgstr ""
+"\n"
+"¦P¨B¤Æ¤¤:"
+
+msgid ""
+"\n"
+"--- Syntax items ---"
+msgstr ""
+"\n"
+"--- »yªk¶µ¥Ø ---"
+
+#, c-format
+msgid "E392: No such syntax cluster: %s"
+msgstr "E392: µL¦¹ syntax cluster: \"%s\""
+
+msgid "minimal "
+msgstr "³Ì¤p"
+
+msgid "maximal "
+msgstr "³Ì¤j"
+
+msgid "; match "
+msgstr "; ²Å¦X "
+
+msgid " line breaks"
+msgstr "Â_¦æ "
+
+msgid "E393: group[t]here not accepted here"
+msgstr "E393: ¨Ï¥Î¤F¤£¥¿½Tªº°Ñ¼Æ"
+
+#, c-format
+msgid "E394: Didn't find region item for %s"
+msgstr "E394: §ä¤£¨ì %s ªº region item"
+
+msgid "E395: contains argument not accepted here"
+msgstr "E395: ¨Ï¥Î¤F¤£¥¿½Tªº°Ñ¼Æ"
+
+msgid "E396: containedin argument not accepted here"
+msgstr "E396: ¨Ï¥Î¤F¤£¥¿½Tªº°Ñ¼Æ"
+
+msgid "E397: Filename required"
+msgstr "E397: »Ý­nÀɮצWºÙ"
+
+#, c-format
+msgid "E398: Missing '=': %s"
+msgstr "E398: ¯Ê¤Ö \"=\": %s"
+
+#, c-format
+msgid "E399: Not enough arguments: syntax region %s"
+msgstr "E399: syntax region %s ªº¤Þ¼Æ¤Ó¤Ö"
+
+msgid "E400: No cluster specified"
+msgstr "E400: ¨S¦³«ü©wªºÄÝ©Ê"
+
+#, c-format
+msgid "E401: Pattern delimiter not found: %s"
+msgstr "E401: §ä¤£¨ì¤À¹j²Å¸¹: %s"
+
+#, c-format
+msgid "E402: Garbage after pattern: %s"
+msgstr "E402: '%s' «á­±ªºªF¦èµLªk¿ëÃÑ"
+
+msgid "E403: syntax sync: line continuations pattern specified twice"
+msgstr "E403: »yªk¦P¨B: ³s±µ¦æ²Å¸¹³Q«ü©w¤F¨â¦¸"
+
+#, c-format
+msgid "E404: Illegal arguments: %s"
+msgstr "E404: °Ñ¼Æ¤£¥¿½T: %s"
+
+#, c-format
+msgid "E405: Missing equal sign: %s"
+msgstr "E405: ¯Ê¤Ö¬Ûµ¥²Å¸¹: %s"
+
+#, c-format
+msgid "E406: Empty argument: %s"
+msgstr "E406: ªÅ¥Õ°Ñ¼Æ: %s"
+
+#, c-format
+msgid "E407: %s not allowed here"
+msgstr "E407: %s ¤£¯à¦b¦¹¥X²{"
+
+#, c-format
+msgid "E408: %s must be first in contains list"
+msgstr "E408: %s ¥²¶·¬O¦Cªí¸Ìªº²Ä¤@­Ó"
+
+#, c-format
+msgid "E409: Unknown group name: %s"
+msgstr "E409: ¤£¥¿½Tªº¸s²Õ¦WºÙ: %s"
+
+#, c-format
+msgid "E410: Invalid :syntax subcommand: %s"
+msgstr "E410: ¤£¥¿½Tªº :syntax ¤l©R¥O: %s"
+
+#, c-format
+msgid "E411: highlight group not found: %s"
+msgstr "E411: §ä¤£¨ì highlight group: %s"
+
+#, c-format
+msgid "E412: Not enough arguments: \":highlight link %s\""
+msgstr "E412: °Ñ¼Æ¤Ó¤Ö: \":highlight link %s\""
+
+#, c-format
+msgid "E413: Too many arguments: \":highlight link %s\""
+msgstr "E413: °Ñ¼Æ¹L¦h: \":highlight link %s\""
+
+msgid "E414: group has settings, highlight link ignored"
+msgstr "E414: ¤w³]©w¸s²Õ, ©¿²¤ highlight link"
+
+#, c-format
+msgid "E415: unexpected equal sign: %s"
+msgstr "E415: ¤£¸Ó¦³ªºµ¥¸¹: %s"
+
+#, c-format
+msgid "E416: missing equal sign: %s"
+msgstr "E416: ¯Ê¤Ö¬Ûµ¥²Å¸¹: %s"
+
+#, c-format
+msgid "E417: missing argument: %s"
+msgstr "E417: ¯Ê¤Ö°Ñ¼Æ: %s"
+
+#, c-format
+msgid "E418: Illegal value: %s"
+msgstr "E418: ¤£¦Xªkªº­È: %s"
+
+msgid "E419: FG color unknown"
+msgstr "E419: ¿ù»~ªº«e´ºÃC¦â"
+
+msgid "E420: BG color unknown"
+msgstr "E420: ¿ù»~ªº­I´ºÃC¦â"
+
+#, c-format
+msgid "E421: Color name or number not recognized: %s"
+msgstr "E421: ¿ù»~ªºÃC¦â¦WºÙ©Î¼Æ­È: %s"
+
+#, c-format
+msgid "E422: terminal code too long: %s"
+msgstr "E422: ²×ºÝ¾÷½X¤Óªø: %s"
+
+#, c-format
+msgid "E423: Illegal argument: %s"
+msgstr "E423: °Ñ¼Æ¤£¥¿½T: %s"
+
+msgid "E424: Too many different highlighting attributes in use"
+msgstr "E424: ¨Ï¥Î¤F¹L¦h¬Û²§ªº°ª«G«×ÄÝ©Ê"
+
+msgid "E669: Unprintable character in group name"
+msgstr "E669: ¸s²Õ¦WºÙ¤¤¦³µLªk¦C¦Lªº¦r¤¸"
+
+#. This is an error, but since there previously was no check only
+#. * give a warning.
+msgid "W18: Invalid character in group name"
+msgstr "W18: ¸s²Õ¦WºÙ¤¤¦³¤£¥¿½Tªº¦r¤¸"
+
+msgid "E555: at bottom of tag stack"
+msgstr "E555: ¼ÐÅÒ(tag)°ïÅ|µ²§À"
+
+msgid "E556: at top of tag stack"
+msgstr "E556: ¼ÐÅÒ(tag)°ïÅ|¶}ÀY"
+
+msgid "E425: Cannot go before first matching tag"
+msgstr "E425: ¤w¸g¦b³Ì«e­±ªº¼ÐÅÒ(tag)¤F"
+
+#, c-format
+msgid "E426: tag not found: %s"
+msgstr "E426: §ä¤£¨ì¼ÐÅÒ(tag): %s"
+
+msgid " # pri kind tag"
+msgstr " # pri kind tag"
+
+msgid "file\n"
+msgstr "ÀÉ®×\n"
+
+#.
+#. * Ask to select a tag from the list.
+#. * When using ":silent" assume that <CR> was entered.
+#.
+msgid "Enter nr of choice (<CR> to abort): "
+msgstr "¿é¤J nr ©Î¿ï¾Ü (<CR> Â÷¶}): "
+
+msgid "E427: There is only one matching tag"
+msgstr "E427: ¥u¦³¦¹¶µ²Å¦X"
+
+msgid "E428: Cannot go beyond last matching tag"
+msgstr "E428: ¤v¸g¦b³Ì«á¤@­Ó²Å¦Xªº tag ¤F"
+
+#, c-format
+msgid "File \"%s\" does not exist"
+msgstr "ÀÉ®× \"%s\" ¤£¦s¦b"
+
+#. Give an indication of the number of matching tags
+#, c-format
+msgid "tag %d of %d%s"
+msgstr "§ä¨ì tag: %d/%d%s"
+
+msgid " or more"
+msgstr " ©Î§ó¦h"
+
+msgid " Using tag with different case!"
+msgstr " ¥H¤£¦P¤j¤p¼g¨Ó¨Ï¥Î tag!"
+
+#, c-format
+msgid "E429: File \"%s\" does not exist"
+msgstr "E429: ÀÉ®× \"%s\" ¤£¦s¦b"
+
+#. Highlight title
+msgid ""
+"\n"
+" # TO tag FROM line in file/text"
+msgstr ""
+"\n"
+" # ¨ì tag ±q ¦æ ¦b ÀÉ®×/¤å¦r"
+
+#, c-format
+msgid "Searching tags file %s"
+msgstr "·j´M tag ÀÉ®× \"%s\""
+
+#, c-format
+msgid "E430: Tag file path truncated for %s\n"
+msgstr "E430: Tag Àɮ׸ô®|³QºIÂ_¬° %s\n"
+
+#, c-format
+msgid "E431: Format error in tags file \"%s\""
+msgstr "E431: Tag ÀÉ \"%s\" ®æ¦¡¿ù»~"
+
+#, c-format
+msgid "Before byte %ld"
+msgstr "¦b %ld ¦ì¤¸¤§«e"
+
+#, c-format
+msgid "E432: Tags file not sorted: %s"
+msgstr "E432: Tag ÀÉ®×¥¼±Æ§Ç: %s"
+
+#. never opened any tags file
+msgid "E433: No tags file"
+msgstr "E433: ¨S¦³ tag ÀÉ"
+
+msgid "E434: Can't find tag pattern"
+msgstr "E434: §ä¤£¨ì tag"
+
+msgid "E435: Couldn't find tag, just guessing!"
+msgstr "E435: §ä¤£¨ì tag, ¥Î²qªº!"
+
+msgid "' not known. Available builtin terminals are:"
+msgstr "' µLªk¸ü¤J¡C¥i¥Îªº¤º«Ø²×ºÝ¾÷§Î¦¡¦³:"
+
+msgid "defaulting to '"
+msgstr "¹w³]: '"
+
+msgid "E557: Cannot open termcap file"
+msgstr "E557: µLªk¶}±Ò termcap ÀÉ®×"
+
+msgid "E558: Terminal entry not found in terminfo"
+msgstr "E558: terminfo ¤¤¨S¦³²×ºÝ¾÷¸ê®Æ¶µ"
+
+msgid "E559: Terminal entry not found in termcap"
+msgstr "E559: termcap ¤¤¨S¦³²×ºÝ¾÷¸ê®Æ¶µ"
+
+#, c-format
+msgid "E436: No \"%s\" entry in termcap"
+msgstr "E436: termcap ¨S¦³ \"%s\" entry"
+
+msgid "E437: terminal capability \"cm\" required"
+msgstr "E437: ²×ºÝ¾÷»Ý­n \"cm\" ªº¯à¤O"
+
+#. Highlight title
+msgid ""
+"\n"
+"--- Terminal keys ---"
+msgstr ""
+"\n"
+"--- ²×ºÝ¾÷«öÁä ---"
+
+msgid "new shell started\n"
+msgstr "°_°Ê·s shell\n"
+
+msgid "Vim: Error reading input, exiting...\n"
+msgstr "Vim: Ū¨ú¿é¤J¿ù»~¡AÂ÷¶}¤¤...\n"
+
+#. must display the prompt
+msgid "No undo possible; continue anyway"
+msgstr "µLªkÁÙ­ì¡F½ÐÄ~Äò§V¤O"
+
+msgid "E438: u_undo: line numbers wrong"
+msgstr "E438: u_undo: ¦æ¸¹¿ù»~"
+
+msgid "1 change"
+msgstr "¤@¶µ§ïÅÜ"
+
+#, c-format
+msgid "%ld changes"
+msgstr "%ld ¶µ§ïÅÜ"
+
+msgid "E439: undo list corrupt"
+msgstr "E439: ´_­ì¦Cªí·lÃa"
+
+msgid "E440: undo line missing"
+msgstr "E440: §ä¤£¨ì­n undo ªº¦æ "
+
+#. Only MS VC 4.1 and earlier can do Win32s
+msgid ""
+"\n"
+"MS-Windows 16/32-bit GUI version"
+msgstr ""
+"\n"
+"MS-Windows 16/32 Bit ¹Ï«¬¬É­±ª©¥»"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit GUI version"
+msgstr ""
+"\n"
+"MS-Windows 32 Bit ¹Ï«¬¬É­±ª©¥»"
+
+msgid " in Win32s mode"
+msgstr "Win32s ¼Ò¦¡"
+
+msgid " with OLE support"
+msgstr "¤ä´© OLE"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit console version"
+msgstr ""
+"\n"
+"MS-Windows 32 Bit console ª©¥»"
+
+msgid ""
+"\n"
+"MS-Windows 16-bit version"
+msgstr ""
+"\n"
+"MS-Windows 32 Bit console ª©¥»"
+
+msgid ""
+"\n"
+"32-bit MS-DOS version"
+msgstr ""
+"\n"
+"32 Bit MS-DOS ª©¥»"
+
+msgid ""
+"\n"
+"16-bit MS-DOS version"
+msgstr ""
+"\n"
+"16 Bit MS-DOS ª©¥»"
+
+msgid ""
+"\n"
+"MacOS X (unix) version"
+msgstr ""
+"\n"
+"MacOS X (unix) ª©¥»"
+
+msgid ""
+"\n"
+"MacOS X version"
+msgstr ""
+"\n"
+"MacOS X ª©¥»"
+
+msgid ""
+"\n"
+"MacOS version"
+msgstr ""
+"\n"
+"MacOS ª©¥»"
+
+msgid ""
+"\n"
+"RISC OS version"
+msgstr ""
+"\n"
+"RISC OS ª©¥»"
+
+msgid ""
+"\n"
+"Included patches: "
+msgstr ""
+"\n"
+"¤Þ¤J­×¥¿: "
+
+msgid "Modified by "
+msgstr "­×§ïªÌ¬°"
+
+msgid ""
+"\n"
+"Compiled "
+msgstr ""
+"\n"
+"½sĶ"
+
+msgid "by "
+msgstr "ªÌ:"
+
+msgid ""
+"\n"
+"Huge version "
+msgstr ""
+"\n"
+"¶W±jª©¥» "
+
+msgid ""
+"\n"
+"Big version "
+msgstr ""
+"\n"
+"¤j«¬ª©¥» "
+
+msgid ""
+"\n"
+"Normal version "
+msgstr ""
+"\n"
+"¤@¯ëª©¥» "
+
+msgid ""
+"\n"
+"Small version "
+msgstr ""
+"\n"
+"²©öª©¥» "
+
+msgid ""
+"\n"
+"Tiny version "
+msgstr ""
+"\n"
+"ºë²ª©¥» "
+
+msgid "without GUI."
+msgstr "¤£¨Ï¥Î¹Ï«¬¬É­±¡C"
+
+msgid "with GTK2-GNOME GUI."
+msgstr "¨Ï¥Î GTK2-GNOME ¹Ï«¬¬É­±¡C"
+
+msgid "with GTK-GNOME GUI."
+msgstr "¨Ï¥Î GTK-GNOME ¹Ï«¬¬É­±¡C"
+
+msgid "with GTK2 GUI."
+msgstr "¨Ï¥Î GTK2 ¹Ï«¬¬É­±¡C"
+
+msgid "with GTK GUI."
+msgstr "¨Ï¥Î GTK ¹Ï«¬¬É­±¡C"
+
+msgid "with X11-Motif GUI."
+msgstr "¨Ï¥Î X11-Motif ¹Ï«¬¬É­±¡C"
+
+msgid "with X11-neXtaw GUI."
+msgstr "¨Ï¥Î X11-neXtaw ¹Ï«¬¬É­±¡C"
+
+msgid "with X11-Athena GUI."
+msgstr "¨Ï¥Î X11-Athena ¹Ï«¬¬É­±¡C"
+
+msgid "with BeOS GUI."
+msgstr "¨Ï¥Î BeOS ¹Ï«¬¬É­±¡C"
+
+msgid "with Photon GUI."
+msgstr "¨Ï¥ÎPhoton¹Ï«¬¬É­±¡C"
+
+msgid "with GUI."
+msgstr "¨Ï¥Î¹Ï«¬¬É­±¡C"
+
+msgid "with Carbon GUI."
+msgstr "¨Ï¥Î Carbon ¹Ï«¬¬É­±¡C"
+
+msgid "with Cocoa GUI."
+msgstr "¨Ï¥Î Cocoa ¹Ï«¬¬É­±¡C"
+
+msgid "with (classic) GUI."
+msgstr "¨Ï¥Î (¶Ç²Î) ¹Ï«¬¬É­±¡C"
+
+msgid " Features included (+) or not (-):\n"
+msgstr " ¥Ø«e¥i¨Ï¥Î(+)»P¤£¥i¨Ï¥Î(-)ªº¼Ò²Õ¦Cªí:\n"
+
+msgid " system vimrc file: \""
+msgstr " ¨t²Î vimrc ³]©wÀÉ: \""
+
+msgid " user vimrc file: \""
+msgstr " ¨Ï¥ÎªÌ­Ó¤H vimrc ³]©wÀÉ: \""
+
+msgid " 2nd user vimrc file: \""
+msgstr " ²Ä¤G²Õ­Ó¤H vimrc ÀÉ®×: \""
+
+msgid " 3rd user vimrc file: \""
+msgstr " ²Ä¤T²Õ­Ó¤H vimrc ÀÉ®×: \""
+
+msgid " user exrc file: \""
+msgstr " ¨Ï¥ÎªÌ­Ó¤H exrc ³]©wÀÉ: \""
+
+msgid " 2nd user exrc file: \""
+msgstr " ²Ä¤G²Õ¨Ï¥ÎªÌ exrc ÀÉ®×: \""
+
+msgid " system gvimrc file: \""
+msgstr " ¨t²Î gvimrc ÀÉ®×: \""
+
+msgid " user gvimrc file: \""
+msgstr " ¨Ï¥ÎªÌ­Ó¤H gvimrc ÀÉ: \""
+
+msgid "2nd user gvimrc file: \""
+msgstr " ²Ä¤G²Õ­Ó¤H gvimrc ÀÉ®×: \""
+
+msgid "3rd user gvimrc file: \""
+msgstr " ²Ä¤T²Õ­Ó¤H gvimrc ÀÉ®×: \""
+
+msgid " system menu file: \""
+msgstr " ¨t²Î¿ï³æ³]©wÀÉ: \""
+
+msgid " fall-back for $VIM: \""
+msgstr " $VIM ¹w³]­È: \""
+
+msgid " f-b for $VIMRUNTIME: \""
+msgstr " $VIMRUNTIME ¹w³]­È: \""
+
+msgid "Compilation: "
+msgstr "½sĶ¤è¦¡: "
+
+msgid "Compiler: "
+msgstr "½sĶ¾¹: "
+
+msgid "Linking: "
+msgstr "Ãìµ²¤è¦¡: "
+
+msgid " DEBUG BUILD"
+msgstr " °£¿ùª©¥»"
+
+msgid "VIM - Vi IMproved"
+msgstr "VIM - Vi IMproved"
+
+msgid "version "
+msgstr "ª©¥» "
+
+msgid "by Bram Moolenaar et al."
+msgstr "ºûÅ@ªÌ: Bram Moolenaar et al."
+
+msgid "Vim is open source and freely distributable"
+msgstr "Vim ¬°¥i¦Û¥Ñ´²§Gªº¶}©ñ­ì©l½X³nÅé"
+
+msgid "Help poor children in Uganda!"
+msgstr "½ÐÀ°§U¯Q¤z¹Fªº¥i¼¦«Äµ£!"
+
+msgid "type :help iccf<Enter> for information "
+msgstr "¶i¤@¨B»¡©ú½Ð¿é¤J :help iccf<Enter>"
+
+msgid "type :q<Enter> to exit "
+msgstr "­nÂ÷¶}½Ð¿é¤J :q<Enter> "
+
+msgid "type :help<Enter> or <F1> for on-line help"
+msgstr "½u¤W»¡©ú½Ð¿é¤J :help<Enter> "
+
+msgid "type :help version8<Enter> for version info"
+msgstr "·sª©¥»¸ê°T½Ð¿é¤J :help version8<Enter>"
+
+msgid "Running in Vi compatible mode"
+msgstr "Vi ¬Û®e¼Ò¦¡"
+
+msgid "type :set nocp<Enter> for Vim defaults"
+msgstr "¦pªG­n§¹¥þ¼ÒÀÀ¶Ç²Î Vi ½Ð¿é¤J :set nocp<Enter>"
+
+msgid "type :help cp-default<Enter> for info on this"
+msgstr "¦pªG»Ý­n¹ï Vi ¬Û®e¼Ò¦¡ªº¶i¤@¨B»¡©ú½Ð¿é¤J :help cp-default<Enter>"
+
+msgid "menu Help->Orphans for information "
+msgstr "¶i¤@¨B»¡©ú½Ð¿ï¨ú¿ï³æªº »²§U»¡©ú->¬@±Ï©t¨à"
+
+msgid "Running modeless, typed text is inserted"
+msgstr "°õ¦æ Modeless ¼Ò¦¡¡A¿é¤Jªº¤å¦r·|¦Û°Ê´¡¤J"
+
+msgid "menu Edit->Global Settings->Toggle Insert Mode "
+msgstr "¿ï¨ú¿ï³æªº¡u½s¿è¡v¡u¥þ°ì³]©w¡v¡u¤Á´«´¡¤J¼Ò¦¡¡v"
+
+msgid " for two modes "
+msgstr " ¨âºØ¼Ò¦¡ "
+
+msgid "menu Edit->Global Settings->Toggle Vi Compatible"
+msgstr "¿ï¨ú¿ï³æªº¡u½s¿è¡v¡u¥þ°ì³]©w¡v¡u¤Á´«¶Ç²ÎVi¬Û®e¼Ò¦¡¡v"
+
+msgid " for Vim defaults "
+msgstr " ¥H±o Vim ¹w³]­È "
+
+msgid "Sponsor Vim development!"
+msgstr "ÃÙ§U Vim ªº¶}µo»P¦¨ªø¡I"
+
+msgid "Become a registered Vim user!"
+msgstr "¦¨¬° Vim ªºµù¥U¨Ï¥ÎªÌ¡I"
+
+msgid "type :help sponsor<Enter> for information "
+msgstr "¸Ô²Ó»¡©ú½Ð¿é¤J :help sponsor<Enter>"
+
+msgid "type :help register<Enter> for information "
+msgstr "¸Ô²Ó»¡©ú½Ð¿é¤J :help register<Enter> "
+
+msgid "menu Help->Sponsor/Register for information "
+msgstr "¸Ô²Ó»¡©ú½Ð¿ï¨ú¿ï³æªº »²§U»¡©ú->ÃÙ§U/µù¥U "
+
+msgid "WARNING: Windows 95/98/ME detected"
+msgstr "ª`·N: °»´ú¨ì Windows 95/98/ME"
+
+msgid "type :help windows95<Enter> for info on this"
+msgstr "¦pªG»Ý­n¹ï Windows 95 ¤ä´©ªº§ó¦h¸ê°T½Ð¿é¤J :help windows95<Enter>"
+
+msgid "E441: There is no preview window"
+msgstr "E441: ¨S¦³¹wÄýµøµ¡"
+
+msgid "E442: Can't split topleft and botright at the same time"
+msgstr "E442: ¤£¯à¦P®É¤À³Îµøµ¡¬°¥ª¤W©M¥k¤U¨¤"
+
+msgid "E443: Cannot rotate when another window is split"
+msgstr "E443: ¦³¨ä¥¦¤À³Îµøµ¡®ÉµLªk±ÛÂà"
+
+msgid "E444: Cannot close last window"
+msgstr "E444: ¤£¯àÃö³¬³Ì«á¤@­Óµøµ¡"
+
+msgid "Already only one window"
+msgstr "¤w¸g¥u³Ñ¤@­Óµøµ¡¤F"
+
+msgid "E445: Other window contains changes"
+msgstr "E445: ¨ä¥¦µøµ¡¦³§ó°Ê¸ê®Æ"
+
+msgid "E446: No file name under cursor"
+msgstr "E446: ´å¼Ð³B¨S¦³ÀɦW"
+
+#, c-format
+msgid "E447: Can't find file \"%s\" in path"
+msgstr "E447: ¦b¸ô®|¤¤§ä¤£¨ìÀÉ®× \"%s\""
+
+#, c-format
+msgid "E370: Could not load library %s"
+msgstr "E370: µLªk­«·s¸ü¤Jµ{¦¡®w %s"
+
+msgid "Sorry, this command is disabled: the Perl library could not be loaded."
+msgstr "©êºp, ¦¹©R¥OµLªk¨Ï¥Î. ­ì¦]: µLªk¸ü¤J Perl µ{¦¡®w(Library)"
+
+msgid "E299: Perl evaluation forbidden in sandbox without the Safe module"
+msgstr "E299: ¦b sandbox ¤¤µL Safe ¼Ò²Õ®ÉµLªk°õ¦æ Perl"
+
+msgid "Edit with &multiple Vims"
+msgstr "¨Ï¥Î¦h­Ó Vim session ½s¿è(&M)"
+
+msgid "Edit with single &Vim"
+msgstr "¥u¨Ï¥Î¦P¤@­Ó Vim session ½s¿è(&V)"
+
+msgid "&Diff with Vim"
+msgstr "¨Ï¥Î Vim ¨Ó¤ñ¸û(&Diff)"
+
+msgid "Edit with &Vim"
+msgstr "¨Ï¥Î Vim ½s¿è¦¹ÀÉ(&V)"
+
+#. Now concatenate
+msgid "Edit with existing Vim - &"
+msgstr "¨Ï¥Î°õ¦æ¤¤ªº Vim session ½s¿è - &"
+
+msgid "Edits the selected file(s) with Vim"
+msgstr "¨Ï¥Î Vim ½s¿è¤w¿ï¨úªºÀÉ®×"
+
+msgid "Error creating process: Check if gvim is in your path!"
+msgstr "µLªk°õ¦æµ{¦¡: ½ÐÀˬd gvim ¦³¨S¦³¦b§Aªº PATH ÅܼƸÌ!"
+
+msgid "gvimext.dll error"
+msgstr "gvimext.dll ¿ù»~"
+
+msgid "Path length too long!"
+msgstr "¸ô®|ªø«×¤Óªø!"
+
+msgid "--No lines in buffer--"
+msgstr "--½w½Ä°ÏµL¸ê®Æ--"
+
+#.
+#. * The error messages that can be shared are included here.
+#. * Excluded are errors that are only used once and debugging messages.
+#.
+msgid "E470: Command aborted"
+msgstr "E470: ©R¥O³Q±j¨î¤¤Â_°õ¦æ "
+
+msgid "E471: Argument required"
+msgstr "E471: »Ý­n«ü¥O°Ñ¼Æ"
+
+msgid "E10: \\ should be followed by /, ? or &"
+msgstr "E10: \\ «á­±À³¸Ó¦³ / ? ©Î &"
+
+msgid "E11: Invalid in command-line window; <CR> executes, CTRL-C quits"
+msgstr "E11: ¤£¯à¦b©R¥O¦Cµøµ¡¤¤¨Ï¥Î¡C<CR>°õ¦æ¡ACTRL-C Â÷¶}"
+
+msgid "E12: Command not allowed from exrc/vimrc in current dir or tag search"
+msgstr "E12: exrc/vimrc ¸Ìªº«ü¥OµLªk°õ¦æ "
+
+msgid "E171: Missing :endif"
+msgstr "E171: ¯Ê¤Ö :endif"
+
+msgid "E600: Missing :endtry"
+msgstr "E600: ¯Ê¤Ö :endtry"
+
+msgid "E170: Missing :endwhile"
+msgstr "E170: ¯Ê¤Ö :endwhile"
+
+msgid "E588: :endwhile without :while"
+msgstr "E588: :endwhile ¯Ê¤Ö¹ïÀ³ªº :while"
+
+msgid "E13: File exists (add ! to override)"
+msgstr "E13: Àɮפw¸g¦s¦b (¥i¥Î ! ±j¨î¨ú¥N)"
+
+msgid "E472: Command failed"
+msgstr "E472: ©R¥O°õ¦æ¥¢±Ñ"
+
+#, c-format
+msgid "E234: Unknown fontset: %s"
+msgstr "E234: ¤£¥¿½Tªº¦r¤¸¶° (Fontset): %s"
+
+#, c-format
+msgid "E235: Unknown font: %s"
+msgstr "E235: ¤£¥¿½Tªº¦r«¬¦WºÙ: %s"
+
+#, c-format
+msgid "E236: Font \"%s\" is not fixed-width"
+msgstr "E236: \"%s\" ¤£¬O©T©w¼e«×¦r«¬"
+
+msgid "E473: Internal error"
+msgstr "E473: ¤º³¡¿ù»~"
+
+msgid "Interrupted"
+msgstr "¤w¤¤Â_"
+
+msgid "E14: Invalid address"
+msgstr "E14: ¤£¥¿½Tªº¦ì§}"
+
+msgid "E474: Invalid argument"
+msgstr "E474: ¤£¥¿½Tªº°Ñ¼Æ"
+
+#, c-format
+msgid "E475: Invalid argument: %s"
+msgstr "E475: ¤£¥¿½Tªº°Ñ¼Æ: %s"
+
+#, c-format
+msgid "E15: Invalid expression: %s"
+msgstr "E15: ¤£¥¿½Tªº¹Bºâ¦¡: %s"
+
+msgid "E16: Invalid range"
+msgstr "E16: ¤£¥¿½Tªº½d³ò"
+
+msgid "E476: Invalid command"
+msgstr "E476: ¤£¥¿½Tªº©R¥O"
+
+#, c-format
+msgid "E17: \"%s\" is a directory"
+msgstr "E17: \"%s\" ¬O¥Ø¿ý"
+
+msgid "E18: Unexpected characters before '='"
+msgstr "E18: '=' «e­±¥X²{¤F¿ù»~ªº¦r¤¸"
+
+#, c-format
+msgid "E364: Library call failed for \"%s()\""
+msgstr "E364: ©I¥s¨ç¦¡®w \"%s\"() ¥¢±Ñ"
+
+#, c-format
+msgid "E448: Could not load library function %s"
+msgstr "E448: µLªk¸ü¤Jµ{¦¡®wªº¨ç¦¡ %s"
+
+msgid "E19: Mark has invalid line number"
+msgstr "E19: ¼Ð°Oªº¦æ¸¹¿ù»~"
+
+msgid "E20: Mark not set"
+msgstr "E20: ¨S¦³³]©w¼Ð°O"
+
+msgid "E21: Cannot make changes, 'modifiable' is off"
+msgstr "E21: ¦]¬° 'modifiable' ¿ï¶µ¬OÃö³¬ªº¡A©Ò¥H¤£¯à­×§ï"
+
+msgid "E22: Scripts nested too deep"
+msgstr "E22: ±_ª¬»¼°j©I¥s¤Ó¦h¼h"
+
+msgid "E23: No alternate file"
+msgstr "E23: ¨S¦³´À¥NªºÀÉ®×"
+
+msgid "E24: No such abbreviation"
+msgstr "E24: ¨S¦³³o­Ó abbreviation ¹ïÀ³"
+
+msgid "E477: No ! allowed"
+msgstr "E477: ¤£¥i¨Ï¥Î '!'"
+
+msgid "E25: GUI cannot be used: Not enabled at compile time"
+msgstr "E25: ¦]¬°½sĶ®É¨S¦³¥[¤J¹Ï«¬¬É­±ªºµ{¦¡½X¡A©Ò¥HµLªk¨Ï¥Î¹Ï«¬¬É­±"
+
+msgid "E26: Hebrew cannot be used: Not enabled at compile time\n"
+msgstr "E26: ¦]¬°½sĶ®É¨S¦³¥[¤J Hebrew ªºµ{¦¡½X¡A©Ò¥HµLªk¨Ï¥Î Hebrew\n"
+
+msgid "E27: Farsi cannot be used: Not enabled at compile time\n"
+msgstr "E27: ¦]¬°½sĶ®É¨S¦³¥[¤J Farsi ªºµ{¦¡½X¡A©Ò¥HµLªk¨Ï¥Î Farsi\n"
+
+msgid "E800: Arabic cannot be used: Not enabled at compile time\n"
+msgstr "E800: ¦]¬°½sĶ®É¨S¦³¥[¤J Arabic ªºµ{¦¡½X¡A©Ò¥HµLªk¨Ï¥Î\n"
+
+#, c-format
+msgid "E28: No such highlight group name: %s"
+msgstr "E28: ¨S¦³¦W¬° '%s' ªº highlight group"
+
+msgid "E29: No inserted text yet"
+msgstr "E29: ÁÙ¨S¦³´¡¤J¤å¦r¹L"
+
+msgid "E30: No previous command line"
+msgstr "E30: ¨S¦³«e¤@¶µ©R¥O"
+
+msgid "E31: No such mapping"
+msgstr "E31: ¨S¦³³o­Ó mapping ¹ïÀ³"
+
+msgid "E479: No match"
+msgstr "E479: §ä¤£¨ì"
+
+#, c-format
+msgid "E480: No match: %s"
+msgstr "E480: §ä¤£¨ì: %s"
+
+msgid "E32: No file name"
+msgstr "E32: ¨S¦³ÀɦW"
+
+msgid "E33: No previous substitute regular expression"
+msgstr "E33: ¨S¦³«e¤@­Ó·j´M/¨ú¥Nªº©R¥O"
+
+msgid "E34: No previous command"
+msgstr "E34: ¨S¦³«e¤@­Ó©R¥O"
+
+msgid "E35: No previous regular expression"
+msgstr "E35: ¨S¦³«e¤@­Ó·j´M«ü¥O"
+
+msgid "E481: No range allowed"
+msgstr "E481: ¤£¥i¨Ï¥Î½d³ò«ü¥O"
+
+msgid "E36: Not enough room"
+msgstr "E36: ¨S¦³¨¬°÷ªºªÅ¶¡"
+
+#, c-format
+msgid "E247: no registered server named \"%s\""
+msgstr "E247: ¨S¦³µù¥U¬° \"%s\" ªº¦øªA¾¹"
+
+#, c-format
+msgid "E482: Can't create file %s"
+msgstr "E482: ¤£¯à«Ø¥ßÀÉ®× %s"
+
+msgid "E483: Can't get temp file name"
+msgstr "E483: µLªk±oª¾¼È¦sÀɦW"
+
+#, c-format
+msgid "E484: Can't open file %s"
+msgstr "E484: µLªk¶}±ÒÀÉ®× %s"
+
+#, c-format
+msgid "E485: Can't read file %s"
+msgstr "E485: µLªkŪ¨úÀÉ®× %s"
+
+msgid "E37: No write since last change (add ! to override)"
+msgstr "E37: ¤w§ó§ï¹LÀɮצý©|¥¼¦sÀÉ (¥i¥Î ! ±j¨î°õ¦æ)"
+
+msgid "E38: Null argument"
+msgstr "E38: ªÅªº (Null) °Ñ¼Æ"
+
+msgid "E39: Number expected"
+msgstr "E39: À³¸Ó­n¦³¼Æ¦r"
+
+#, c-format
+msgid "E40: Can't open errorfile %s"
+msgstr "E40: µLªk¶}±Ò¿ù»~ÀÉ®× %s"
+
+msgid "E233: cannot open display"
+msgstr "E233: <¤£¯à¶}±Ò X Server DISPLAY>"
+
+msgid "E41: Out of memory!"
+msgstr "E41: °O¾ÐÅ餣¨¬!"
+
+msgid "Pattern not found"
+msgstr "§ä¤£¨ì"
+
+#, c-format
+msgid "E486: Pattern not found: %s"
+msgstr "E486: §ä¤£¨ì %s"
+
+msgid "E487: Argument must be positive"
+msgstr "E487: °Ñ¼ÆÀ³¸Ó¬O¥¿¼Æ"
+
+msgid "E459: Cannot go back to previous directory"
+msgstr "E459: µLªk¦^¨ì«e¤@­Ó¥Ø¿ý"
+
+msgid "E42: No Errors"
+msgstr "E42: ¨S¦³¿ù»~"
+
+msgid "E43: Damaged match string"
+msgstr "E43: ²Å¦X¦r¦ê¦³°ÝÃD"
+
+msgid "E44: Corrupted regexp program"
+msgstr "E44: regexp ¦³°ÝÃD"
+
+msgid "E45: 'readonly' option is set (add ! to override)"
+msgstr "E45: ¦³³]©w 'readonly' ¿ï¶µ(°ßŪ) (¥i¥Î ! ±j¨î°õ¦æ)"
+
+#, c-format
+msgid "E46: Cannot set read-only variable \"%s\""
+msgstr "E46: µLªk³]©w°ßŪÅÜ¼Æ \"%s\""
+
+msgid "E47: Error while reading errorfile"
+msgstr "E47: Ū¨ú¿ù»~ÀÉ®×¥¢±Ñ"
+
+msgid "E48: Not allowed in sandbox"
+msgstr "E48: ¤£¯à¦b sandbox ¸Ì¥X²{"
+
+msgid "E523: Not allowed here"
+msgstr "E523: ³o¸Ì¤£¥i¨Ï¥Î"
+
+msgid "E359: Screen mode setting not supported"
+msgstr "E359: ¤£¤ä´©³]©w¿Ã¹õ¼Ò¦¡"
+
+msgid "E49: Invalid scroll size"
+msgstr "E49: ¿ù»~ªº±²°Ê¤j¤p"
+
+msgid "E91: 'shell' option is empty"
+msgstr "E91: 'E71: ¿ï¶µ 'shell' ¥¼³]©w"
+
+msgid "E255: Couldn't read in sign data!"
+msgstr "E255: µLªkŪ¨ú sign data!"
+
+msgid "E72: Close error on swap file"
+msgstr "E72: ¼È¦sÀÉÃö³¬¿ù»~"
+
+msgid "E73: tag stack empty"
+msgstr "E73: ¼ÐÅÒ°ïÅ|¤wªÅ"
+
+msgid "E74: Command too complex"
+msgstr "E74: ©R¥O¤Ó½ÆÂø"
+
+msgid "E75: Name too long"
+msgstr "E75: ¦W¦r¤Óªø"
+
+msgid "E76: Too many ["
+msgstr "E76: ¤Ó¦h ["
+
+msgid "E77: Too many file names"
+msgstr "E77: ¤Ó¦hÀɦW"
+
+msgid "E488: Trailing characters"
+msgstr "E488: §A¿é¤J¤F¦h¾lªº¦r¤¸"
+
+msgid "E78: Unknown mark"
+msgstr "E78: µLªk¿ìÃѪº¼Ð°O"
+
+msgid "E79: Cannot expand wildcards"
+msgstr "E79: µLªk®i¶}¸U¥Î¦r¤¸"
+
+msgid "E591: 'winheight' cannot be smaller than 'winminheight'"
+msgstr "E591: 'winheight' ¤£¯à¤ñ 'winminheight' §ó¤Ö"
+
+msgid "E592: 'winwidth' cannot be smaller than 'winminwidth'"
+msgstr "E592: 'winwidth' ¤£¯à¤ñ 'winminwidth' §ó¤Ö"
+
+msgid "E80: Error while writing"
+msgstr "E80: ¼g¤J¿ù»~"
+
+msgid "Zero count"
+msgstr "¼Æ¨ì¹s (?)"
+
+msgid "E81: Using <SID> not in a script context"
+msgstr "E81: <SID> ¤£¯à¦b script ¥»¤å¥~¨Ï¥Î."
+
+msgid "E449: Invalid expression received"
+msgstr "E449: ¦¬¨ì¤£¥¿½Tªº¹Bºâ¦¡"
+
+msgid "E463: Region is guarded, cannot modify"
+msgstr "E463: °Ï°ì³Q«OÅ@¡AµLªk­×§ï"
+
+#~ msgid "E565: error reading cscope connection %d"
+#~ msgstr "E565: Ū¨ú cscope ³s½u %d ¿ù»~"
+
+#~ msgid "E260: cscope connection not found"
+#~ msgstr "E260: §ä¤£¨ì cscope ³s½u"
+
+#~ msgid "cscope connection closed"
+#~ msgstr "cscope ³s½u¤wÃö³¬"
+
+#~ msgid "couldn't malloc\n"
+#~ msgstr "µLªk¨Ï¥Î malloc\n"
+
+#~ msgid "%2d %-5ld %-34s <none>\n"
+#~ msgstr "%2d %-5ld %-34s <µL>\n"
+
+#~ msgid "\"\n"
+#~ msgstr "\"\n"
+
+#~ msgid "--help\t\tShow Gnome arguments"
+#~ msgstr "--help\t\tÅã¥Ü Gnome ¬ÛÃö°Ñ¼Æ"
+
+#~ msgid " BLOCK"
+#~ msgstr " °Ï¶ô"
+
+#~ msgid " LINE"
+#~ msgstr " ¦æ¿ï¨ú"
+
+#~ msgid "Linear tag search"
+#~ msgstr "½u©Ê·j´M¼ÐÅÒ (Tags)"
+
+#~ msgid "Binary tag search"
+#~ msgstr "¤G¤À·j´M(Binary search) ¼ÐÅÒ(Tags)"
+
+#~ msgid "function "
+#~ msgstr "¨ç¦¡ "
+
+#~ msgid "Run Macro"
+#~ msgstr "°õ¦æ¥¨¶°"
+
+#~ msgid "E221: 'commentstring' is empty"
+#~ msgstr "E221: ¿ï¶µ 'commentstring' ¥¼³]©w"
+
+#~ msgid "E242: Color name not recognized: %s"
+#~ msgstr "E242: %s ¬°µLªkÃѧOªºÃC¦â¦WºÙ"
+
+#~ msgid "E242: Missing color: %s"
+#~ msgstr "E242: §ä¤£¨ìÃC¦â: %s"
+
+#~ msgid "error reading cscope connection %d"
+#~ msgstr "Ū¨ú cscope ³s½u %d ®É¿ù»~"
+
+#~ msgid "E249: couldn't read VIM instance registry property"
+#~ msgstr "E249: µLªkŪ¨ú VIM ªº registry ³]©w¶µ"
+
+#~ msgid "Can't open file %s"
+#~ msgstr "µLªk¶}±ÒÀÉ®× %s"
+
+#~ msgid "Unable to send reply"
+#~ msgstr "µLªk¶Ç°e¦^À³°T®§"
+
+#~ msgid "E241: Unable to send to Vim server"
+#~ msgstr "E241: µLªk¶Ç°e¨ì Vim ¦øªA¾¹"
+
+#~ msgid ""
+#~ "\n"
+#~ "Send failed. No command server present ?\n"
+#~ msgstr ""
+#~ "\n"
+#~ "¶Ç°e¥¢±Ñ¡C¨S¦³©R¥O¦øªA¾¹¦s¦b ?\n"
+
+#~ msgid "PC (32 bits Vim)"
+#~ msgstr "PC (32 ¦ì¤¸ Vim)"
+
+#~ msgid "PC (16 bits Vim)"
+#~ msgstr "PC (16 ¦ì¤¸ Vim)"
+
+#~ msgid "E362: Unsupported screen mode"
+#~ msgstr "E362: ¿Ã¹õ¼Ò¦¡¤£¤ä´©"
+
+#~ msgid "No servers found for this display"
+#~ msgstr "¦¹Display¨S¦³¦øªA¾¹(Servers)"
+
+#~ msgid "E258: no matches found in cscope connections"
+#~ msgstr "E258: cscope ³s½u§ä¤£¨ì²Å¦Xªº"
+
+#~ msgid ""
+#~ "\n"
+#~ "MacOS Carbon"
+#~ msgstr ""
+#~ "\n"
+#~ "MacOS Carbon"
+
+#~ msgid ""
+#~ "\n"
+#~ "MacOS 8"
+#~ msgstr ""
+#~ "\n"
+#~ "MacOS 8"
+
+#~ msgid "Retrieve next symbol"
+#~ msgstr "Ū¨ú: ±q¤U­Ó symbol"
+
+#~ msgid "-- SNiFF+ commands --"
+#~ msgstr "-- SNiFF+ ©R¥O --"
+
+#~ msgid "E277: Unrecognized sniff request [%s]"
+#~ msgstr "E277: µLªk¿ëÃÑ sniff ©R¥O [%s]"
diff --git a/src/popupmnu.c b/src/popupmnu.c
new file mode 100644
index 0000000..755dba4
--- /dev/null
+++ b/src/popupmnu.c
@@ -0,0 +1,1361 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * popupmnu.c: Popup menu (PUM)
+ */
+#include "vim.h"
+
+#if defined(FEAT_INS_EXPAND) || defined(PROTO)
+
+static pumitem_T *pum_array = NULL; /* items of displayed pum */
+static int pum_size; /* nr of items in "pum_array" */
+static int pum_selected; /* index of selected item or -1 */
+static int pum_first = 0; /* index of top item */
+
+static int call_update_screen = FALSE;
+
+static int pum_height; /* nr of displayed pum items */
+static int pum_width; /* width of displayed pum items */
+static int pum_base_width; /* width of pum items base */
+static int pum_kind_width; /* width of pum items kind column */
+static int pum_extra_width; /* width of extra stuff */
+static int pum_scrollbar; /* TRUE when scrollbar present */
+
+static int pum_row; /* top row of pum */
+static int pum_col; /* left column of pum */
+
+static win_T *pum_window = NULL;
+static int pum_win_row;
+static int pum_win_height;
+static int pum_win_col;
+static int pum_win_wcol;
+static int pum_win_width;
+
+static int pum_do_redraw = FALSE; // do redraw anyway
+static int pum_skip_redraw = FALSE; // skip redraw
+
+static int pum_set_selected(int n, int repeat);
+
+#define PUM_DEF_HEIGHT 10
+
+ static void
+pum_compute_size(void)
+{
+ int i;
+ int w;
+
+ /* Compute the width of the widest match and the widest extra. */
+ pum_base_width = 0;
+ pum_kind_width = 0;
+ pum_extra_width = 0;
+ for (i = 0; i < pum_size; ++i)
+ {
+ w = vim_strsize(pum_array[i].pum_text);
+ if (pum_base_width < w)
+ pum_base_width = w;
+ if (pum_array[i].pum_kind != NULL)
+ {
+ w = vim_strsize(pum_array[i].pum_kind) + 1;
+ if (pum_kind_width < w)
+ pum_kind_width = w;
+ }
+ if (pum_array[i].pum_extra != NULL)
+ {
+ w = vim_strsize(pum_array[i].pum_extra) + 1;
+ if (pum_extra_width < w)
+ pum_extra_width = w;
+ }
+ }
+}
+
+/*
+ * Show the popup menu with items "array[size]".
+ * "array" must remain valid until pum_undisplay() is called!
+ * When possible the leftmost character is aligned with cursor column.
+ * The menu appears above the screen line "row" or at "row" + "height" - 1.
+ */
+ void
+pum_display(
+ pumitem_T *array,
+ int size,
+ int selected) /* index of initially selected item, none if
+ out of range */
+{
+ int def_width;
+ int max_width;
+ int context_lines;
+ int cursor_col;
+ int above_row;
+ int below_row;
+ int redo_count = 0;
+#if defined(FEAT_QUICKFIX)
+ win_T *pvwin;
+#endif
+
+ do
+ {
+ def_width = p_pw;
+ above_row = 0;
+ below_row = cmdline_row;
+
+ /* Pretend the pum is already there to avoid that must_redraw is set
+ * when 'cuc' is on. */
+ pum_array = (pumitem_T *)1;
+ validate_cursor_col();
+ pum_array = NULL;
+
+ // Remember the essential parts of the window position and size, so we
+ // can decide when to reposition the popup menu.
+ pum_window = curwin;
+ pum_win_row = curwin->w_wrow + W_WINROW(curwin);
+ pum_win_height = curwin->w_height;
+ pum_win_col = curwin->w_wincol;
+ pum_win_wcol = curwin->w_wcol;
+ pum_win_width = curwin->w_width;
+
+#if defined(FEAT_QUICKFIX)
+ FOR_ALL_WINDOWS(pvwin)
+ if (pvwin->w_p_pvw)
+ break;
+ if (pvwin != NULL)
+ {
+ if (W_WINROW(pvwin) < W_WINROW(curwin))
+ above_row = W_WINROW(pvwin) + pvwin->w_height;
+ else if (W_WINROW(pvwin) > W_WINROW(curwin) + curwin->w_height)
+ below_row = W_WINROW(pvwin);
+ }
+#endif
+
+ /*
+ * Figure out the size and position of the pum.
+ */
+ if (size < PUM_DEF_HEIGHT)
+ pum_height = size;
+ else
+ pum_height = PUM_DEF_HEIGHT;
+ if (p_ph > 0 && pum_height > p_ph)
+ pum_height = p_ph;
+
+ /* Put the pum below "pum_win_row" if possible. If there are few lines
+ * decide on where there is more room. */
+ if (pum_win_row + 2 >= below_row - pum_height
+ && pum_win_row - above_row > (below_row - above_row) / 2)
+ {
+ /* pum above "pum_win_row" */
+
+ /* Leave two lines of context if possible */
+ if (curwin->w_wrow - curwin->w_cline_row >= 2)
+ context_lines = 2;
+ else
+ context_lines = curwin->w_wrow - curwin->w_cline_row;
+
+ if (pum_win_row >= size + context_lines)
+ {
+ pum_row = pum_win_row - size - context_lines;
+ pum_height = size;
+ }
+ else
+ {
+ pum_row = 0;
+ pum_height = pum_win_row - context_lines;
+ }
+ if (p_ph > 0 && pum_height > p_ph)
+ {
+ pum_row += pum_height - p_ph;
+ pum_height = p_ph;
+ }
+ }
+ else
+ {
+ /* pum below "pum_win_row" */
+
+ /* Leave two lines of context if possible */
+ if (curwin->w_cline_row
+ + curwin->w_cline_height - curwin->w_wrow >= 3)
+ context_lines = 3;
+ else
+ context_lines = curwin->w_cline_row
+ + curwin->w_cline_height - curwin->w_wrow;
+
+ pum_row = pum_win_row + context_lines;
+ if (size > below_row - pum_row)
+ pum_height = below_row - pum_row;
+ else
+ pum_height = size;
+ if (p_ph > 0 && pum_height > p_ph)
+ pum_height = p_ph;
+ }
+
+ /* don't display when we only have room for one line */
+ if (pum_height < 1 || (pum_height == 1 && size > 1))
+ return;
+
+#if defined(FEAT_QUICKFIX)
+ // If there is a preview window above avoid drawing over it.
+ if (pvwin != NULL && pum_row < above_row && pum_height > above_row)
+ {
+ pum_row = above_row;
+ pum_height = pum_win_row - above_row;
+ }
+#endif
+
+ pum_array = array;
+ pum_size = size;
+ pum_compute_size();
+ max_width = pum_base_width;
+
+ /* Calculate column */
+#ifdef FEAT_RIGHTLEFT
+ if (curwin->w_p_rl)
+ cursor_col = curwin->w_wincol + curwin->w_width
+ - curwin->w_wcol - 1;
+ else
+#endif
+ cursor_col = curwin->w_wincol + curwin->w_wcol;
+
+ /* if there are more items than room we need a scrollbar */
+ if (pum_height < size)
+ {
+ pum_scrollbar = 1;
+ ++max_width;
+ }
+ else
+ pum_scrollbar = 0;
+
+ if (def_width < max_width)
+ def_width = max_width;
+
+ if (((cursor_col < Columns - p_pw
+ || cursor_col < Columns - max_width)
+#ifdef FEAT_RIGHTLEFT
+ && !curwin->w_p_rl)
+ || (curwin->w_p_rl
+ && (cursor_col > p_pw || cursor_col > max_width)
+#endif
+ ))
+ {
+ /* align pum with "cursor_col" */
+ pum_col = cursor_col;
+
+ /* start with the maximum space available */
+#ifdef FEAT_RIGHTLEFT
+ if (curwin->w_p_rl)
+ pum_width = pum_col - pum_scrollbar + 1;
+ else
+#endif
+ pum_width = Columns - pum_col - pum_scrollbar;
+
+ if (pum_width > max_width + pum_kind_width + pum_extra_width + 1
+ && pum_width > p_pw)
+ {
+ /* the width is more than needed for the items, make it
+ * narrower */
+ pum_width = max_width + pum_kind_width + pum_extra_width + 1;
+ if (pum_width < p_pw)
+ pum_width = p_pw;
+ }
+ else if (((cursor_col > p_pw || cursor_col > max_width)
+#ifdef FEAT_RIGHTLEFT
+ && !curwin->w_p_rl)
+ || (curwin->w_p_rl && (cursor_col < Columns - p_pw
+ || cursor_col < Columns - max_width)
+#endif
+ ))
+ {
+ /* align pum edge with "cursor_col" */
+#ifdef FEAT_RIGHTLEFT
+ if (curwin->w_p_rl
+ && W_ENDCOL(curwin) < max_width + pum_scrollbar + 1)
+ {
+ pum_col = cursor_col + max_width + pum_scrollbar + 1;
+ if (pum_col >= Columns)
+ pum_col = Columns - 1;
+ }
+ else if (!curwin->w_p_rl)
+#endif
+ {
+ if (curwin->w_wincol > Columns - max_width - pum_scrollbar
+ && max_width <= p_pw)
+ {
+ /* use full width to end of the screen */
+ pum_col = Columns - max_width - pum_scrollbar;
+ if (pum_col < 0)
+ pum_col = 0;
+ }
+ }
+
+#ifdef FEAT_RIGHTLEFT
+ if (curwin->w_p_rl)
+ pum_width = pum_col - pum_scrollbar + 1;
+ else
+#endif
+ pum_width = Columns - pum_col - pum_scrollbar;
+
+ if (pum_width < p_pw)
+ {
+ pum_width = p_pw;
+#ifdef FEAT_RIGHTLEFT
+ if (curwin->w_p_rl)
+ {
+ if (pum_width > pum_col)
+ pum_width = pum_col;
+ }
+ else
+#endif
+ {
+ if (pum_width >= Columns - pum_col)
+ pum_width = Columns - pum_col - 1;
+ }
+ }
+ else if (pum_width > max_width + pum_kind_width
+ + pum_extra_width + 1
+ && pum_width > p_pw)
+ {
+ pum_width = max_width + pum_kind_width
+ + pum_extra_width + 1;
+ if (pum_width < p_pw)
+ pum_width = p_pw;
+ }
+ }
+
+ }
+ else if (Columns < def_width)
+ {
+ /* not enough room, will use what we have */
+#ifdef FEAT_RIGHTLEFT
+ if (curwin->w_p_rl)
+ pum_col = Columns - 1;
+ else
+#endif
+ pum_col = 0;
+ pum_width = Columns - 1;
+ }
+ else
+ {
+ if (max_width > p_pw)
+ max_width = p_pw; /* truncate */
+#ifdef FEAT_RIGHTLEFT
+ if (curwin->w_p_rl)
+ pum_col = max_width - 1;
+ else
+#endif
+ pum_col = Columns - max_width;
+ pum_width = max_width - pum_scrollbar;
+ }
+
+ /* Set selected item and redraw. If the window size changed need to
+ * redo the positioning. Limit this to two times, when there is not
+ * much room the window size will keep changing. */
+ } while (pum_set_selected(selected, redo_count) && ++redo_count <= 2);
+}
+
+/*
+ * Set a flag that when pum_redraw() is called it first calls update_screen().
+ * This will avoid clearing and redrawing the popup menu, prevent flicker.
+ */
+ void
+pum_call_update_screen()
+{
+ call_update_screen = TRUE;
+
+ // Update the cursor position to be able to compute the popup menu
+ // position. The cursor line length may have changed because of the
+ // inserted completion.
+ curwin->w_valid &= ~(VALID_CROW|VALID_CHEIGHT);
+ validate_cursor();
+}
+
+/*
+ * Return TRUE if we are going to redraw the popup menu and the screen position
+ * "row"/"col" is under the popup menu.
+ */
+ int
+pum_under_menu(int row, int col)
+{
+ return pum_skip_redraw
+ && row >= pum_row
+ && row < pum_row + pum_height
+ && col >= pum_col - 1
+ && col < pum_col + pum_width;
+}
+
+/*
+ * Redraw the popup menu, using "pum_first" and "pum_selected".
+ */
+ void
+pum_redraw(void)
+{
+ int row = pum_row;
+ int col;
+ int attr_norm = highlight_attr[HLF_PNI];
+ int attr_select = highlight_attr[HLF_PSI];
+ int attr_scroll = highlight_attr[HLF_PSB];
+ int attr_thumb = highlight_attr[HLF_PST];
+ int attr;
+ int i;
+ int idx;
+ char_u *s;
+ char_u *p = NULL;
+ int totwidth, width, w;
+ int thumb_pos = 0;
+ int thumb_heigth = 1;
+ int round;
+ int n;
+
+ if (call_update_screen)
+ {
+ call_update_screen = FALSE;
+ pum_skip_redraw = TRUE; // do not redraw in pum_may_redraw().
+ update_screen(0);
+ pum_skip_redraw = FALSE;
+ }
+
+ // never display more than we have
+ if (pum_first > pum_size - pum_height)
+ pum_first = pum_size - pum_height;
+
+ if (pum_scrollbar)
+ {
+ thumb_heigth = pum_height * pum_height / pum_size;
+ if (thumb_heigth == 0)
+ thumb_heigth = 1;
+ thumb_pos = (pum_first * (pum_height - thumb_heigth)
+ + (pum_size - pum_height) / 2)
+ / (pum_size - pum_height);
+ }
+
+ for (i = 0; i < pum_height; ++i)
+ {
+ idx = i + pum_first;
+ attr = (idx == pum_selected) ? attr_select : attr_norm;
+
+ /* prepend a space if there is room */
+#ifdef FEAT_RIGHTLEFT
+ if (curwin->w_p_rl)
+ {
+ if (pum_col < curwin->w_wincol + curwin->w_width - 1)
+ screen_putchar(' ', row, pum_col + 1, attr);
+ }
+ else
+#endif
+ if (pum_col > 0)
+ screen_putchar(' ', row, pum_col - 1, attr);
+
+ /* Display each entry, use two spaces for a Tab.
+ * Do this 3 times: For the main text, kind and extra info */
+ col = pum_col;
+ totwidth = 0;
+ for (round = 1; round <= 3; ++round)
+ {
+ width = 0;
+ s = NULL;
+ switch (round)
+ {
+ case 1: p = pum_array[idx].pum_text; break;
+ case 2: p = pum_array[idx].pum_kind; break;
+ case 3: p = pum_array[idx].pum_extra; break;
+ }
+ if (p != NULL)
+ for ( ; ; MB_PTR_ADV(p))
+ {
+ if (s == NULL)
+ s = p;
+ w = ptr2cells(p);
+ if (*p == NUL || *p == TAB || totwidth + w > pum_width)
+ {
+ /* Display the text that fits or comes before a Tab.
+ * First convert it to printable characters. */
+ char_u *st;
+ int saved = *p;
+
+ if (saved != NUL)
+ *p = NUL;
+ st = transstr(s);
+ if (saved != NUL)
+ *p = saved;
+#ifdef FEAT_RIGHTLEFT
+ if (curwin->w_p_rl)
+ {
+ if (st != NULL)
+ {
+ char_u *rt = reverse_text(st);
+
+ if (rt != NULL)
+ {
+ char_u *rt_start = rt;
+ int size;
+
+ size = vim_strsize(rt);
+ if (size > pum_width)
+ {
+ do
+ {
+ size -= has_mbyte
+ ? (*mb_ptr2cells)(rt) : 1;
+ MB_PTR_ADV(rt);
+ } while (size > pum_width);
+
+ if (size < pum_width)
+ {
+ /* Most left character requires
+ * 2-cells but only 1 cell is
+ * available on screen. Put a
+ * '<' on the left of the pum
+ * item */
+ *(--rt) = '<';
+ size++;
+ }
+ }
+ screen_puts_len(rt, (int)STRLEN(rt),
+ row, col - size + 1, attr);
+ vim_free(rt_start);
+ }
+ vim_free(st);
+ }
+ col -= width;
+ }
+ else
+#endif
+ {
+ if (st != NULL)
+ {
+ screen_puts_len(st, (int)STRLEN(st), row, col,
+ attr);
+ vim_free(st);
+ }
+ col += width;
+ }
+
+ if (*p != TAB)
+ break;
+
+ /* Display two spaces for a Tab. */
+#ifdef FEAT_RIGHTLEFT
+ if (curwin->w_p_rl)
+ {
+ screen_puts_len((char_u *)" ", 2, row, col - 1,
+ attr);
+ col -= 2;
+ }
+ else
+#endif
+ {
+ screen_puts_len((char_u *)" ", 2, row, col, attr);
+ col += 2;
+ }
+ totwidth += 2;
+ s = NULL; /* start text at next char */
+ width = 0;
+ }
+ else
+ width += w;
+ }
+
+ if (round > 1)
+ n = pum_kind_width + 1;
+ else
+ n = 1;
+
+ /* Stop when there is nothing more to display. */
+ if (round == 3
+ || (round == 2 && pum_array[idx].pum_extra == NULL)
+ || (round == 1 && pum_array[idx].pum_kind == NULL
+ && pum_array[idx].pum_extra == NULL)
+ || pum_base_width + n >= pum_width)
+ break;
+#ifdef FEAT_RIGHTLEFT
+ if (curwin->w_p_rl)
+ {
+ screen_fill(row, row + 1, pum_col - pum_base_width - n + 1,
+ col + 1, ' ', ' ', attr);
+ col = pum_col - pum_base_width - n + 1;
+ }
+ else
+#endif
+ {
+ screen_fill(row, row + 1, col, pum_col + pum_base_width + n,
+ ' ', ' ', attr);
+ col = pum_col + pum_base_width + n;
+ }
+ totwidth = pum_base_width + n;
+ }
+
+#ifdef FEAT_RIGHTLEFT
+ if (curwin->w_p_rl)
+ screen_fill(row, row + 1, pum_col - pum_width + 1, col + 1, ' ',
+ ' ', attr);
+ else
+#endif
+ screen_fill(row, row + 1, col, pum_col + pum_width, ' ', ' ',
+ attr);
+ if (pum_scrollbar > 0)
+ {
+#ifdef FEAT_RIGHTLEFT
+ if (curwin->w_p_rl)
+ screen_putchar(' ', row, pum_col - pum_width,
+ i >= thumb_pos && i < thumb_pos + thumb_heigth
+ ? attr_thumb : attr_scroll);
+ else
+#endif
+ screen_putchar(' ', row, pum_col + pum_width,
+ i >= thumb_pos && i < thumb_pos + thumb_heigth
+ ? attr_thumb : attr_scroll);
+ }
+
+ ++row;
+ }
+}
+
+/*
+ * Set the index of the currently selected item. The menu will scroll when
+ * necessary. When "n" is out of range don't scroll.
+ * This may be repeated when the preview window is used:
+ * "repeat" == 0: open preview window normally
+ * "repeat" == 1: open preview window but don't set the size
+ * "repeat" == 2: don't open preview window
+ * Returns TRUE when the window was resized and the location of the popup menu
+ * must be recomputed.
+ */
+ static int
+pum_set_selected(int n, int repeat)
+{
+ int resized = FALSE;
+ int context = pum_height / 2;
+
+ pum_selected = n;
+
+ if (pum_selected >= 0 && pum_selected < pum_size)
+ {
+ if (pum_first > pum_selected - 4)
+ {
+ /* scroll down; when we did a jump it's probably a PageUp then
+ * scroll a whole page */
+ if (pum_first > pum_selected - 2)
+ {
+ pum_first -= pum_height - 2;
+ if (pum_first < 0)
+ pum_first = 0;
+ else if (pum_first > pum_selected)
+ pum_first = pum_selected;
+ }
+ else
+ pum_first = pum_selected;
+ }
+ else if (pum_first < pum_selected - pum_height + 5)
+ {
+ /* scroll up; when we did a jump it's probably a PageDown then
+ * scroll a whole page */
+ if (pum_first < pum_selected - pum_height + 1 + 2)
+ {
+ pum_first += pum_height - 2;
+ if (pum_first < pum_selected - pum_height + 1)
+ pum_first = pum_selected - pum_height + 1;
+ }
+ else
+ pum_first = pum_selected - pum_height + 1;
+ }
+
+ /* Give a few lines of context when possible. */
+ if (context > 3)
+ context = 3;
+ if (pum_height > 2)
+ {
+ if (pum_first > pum_selected - context)
+ {
+ /* scroll down */
+ pum_first = pum_selected - context;
+ if (pum_first < 0)
+ pum_first = 0;
+ }
+ else if (pum_first < pum_selected + context - pum_height + 1)
+ {
+ /* scroll up */
+ pum_first = pum_selected + context - pum_height + 1;
+ }
+ }
+
+#if defined(FEAT_QUICKFIX)
+ /*
+ * Show extra info in the preview window if there is something and
+ * 'completeopt' contains "preview".
+ * Skip this when tried twice already.
+ * Skip this also when there is not much room.
+ * NOTE: Be very careful not to sync undo!
+ */
+ if (pum_array[pum_selected].pum_info != NULL
+ && Rows > 10
+ && repeat <= 1
+ && vim_strchr(p_cot, 'p') != NULL)
+ {
+ win_T *curwin_save = curwin;
+ tabpage_T *curtab_save = curtab;
+ int res = OK;
+
+ /* Open a preview window. 3 lines by default. Prefer
+ * 'previewheight' if set and smaller. */
+ g_do_tagpreview = 3;
+ if (p_pvh > 0 && p_pvh < g_do_tagpreview)
+ g_do_tagpreview = p_pvh;
+ ++RedrawingDisabled;
+ /* Prevent undo sync here, if an autocommand syncs undo weird
+ * things can happen to the undo tree. */
+ ++no_u_sync;
+ resized = prepare_tagpreview(FALSE);
+ --no_u_sync;
+ --RedrawingDisabled;
+ g_do_tagpreview = 0;
+
+ if (curwin->w_p_pvw)
+ {
+ if (!resized
+ && curbuf->b_nwindows == 1
+ && curbuf->b_fname == NULL
+ && curbuf->b_p_bt[0] == 'n' && curbuf->b_p_bt[2] == 'f'
+ && curbuf->b_p_bh[0] == 'w')
+ {
+ /* Already a "wipeout" buffer, make it empty. */
+ while (!BUFEMPTY())
+ ml_delete((linenr_T)1, FALSE);
+ }
+ else
+ {
+ /* Don't want to sync undo in the current buffer. */
+ ++no_u_sync;
+ res = do_ecmd(0, NULL, NULL, NULL, ECMD_ONE, 0, NULL);
+ --no_u_sync;
+ if (res == OK)
+ {
+ /* Edit a new, empty buffer. Set options for a "wipeout"
+ * buffer. */
+ set_option_value((char_u *)"swf", 0L, NULL, OPT_LOCAL);
+ set_option_value((char_u *)"bt", 0L,
+ (char_u *)"nofile", OPT_LOCAL);
+ set_option_value((char_u *)"bh", 0L,
+ (char_u *)"wipe", OPT_LOCAL);
+ set_option_value((char_u *)"diff", 0L,
+ NULL, OPT_LOCAL);
+ }
+ }
+ if (res == OK)
+ {
+ char_u *p, *e;
+ linenr_T lnum = 0;
+
+ for (p = pum_array[pum_selected].pum_info; *p != NUL; )
+ {
+ e = vim_strchr(p, '\n');
+ if (e == NULL)
+ {
+ ml_append(lnum++, p, 0, FALSE);
+ break;
+ }
+ else
+ {
+ *e = NUL;
+ ml_append(lnum++, p, (int)(e - p + 1), FALSE);
+ *e = '\n';
+ p = e + 1;
+ }
+ }
+
+ /* Increase the height of the preview window to show the
+ * text, but no more than 'previewheight' lines. */
+ if (repeat == 0)
+ {
+ if (lnum > p_pvh)
+ lnum = p_pvh;
+ if (curwin->w_height < lnum)
+ {
+ win_setheight((int)lnum);
+ resized = TRUE;
+ }
+ }
+
+ curbuf->b_changed = 0;
+ curbuf->b_p_ma = FALSE;
+ curwin->w_cursor.lnum = 1;
+ curwin->w_cursor.col = 0;
+
+ if ((curwin != curwin_save && win_valid(curwin_save))
+ || (curtab != curtab_save
+ && valid_tabpage(curtab_save)))
+ {
+ if (curtab != curtab_save && valid_tabpage(curtab_save))
+ goto_tabpage_tp(curtab_save, FALSE, FALSE);
+
+ /* When the first completion is done and the preview
+ * window is not resized, skip the preview window's
+ * status line redrawing. */
+ if (ins_compl_active() && !resized)
+ curwin->w_redr_status = FALSE;
+
+ /* Return cursor to where we were */
+ validate_cursor();
+ redraw_later(SOME_VALID);
+
+ /* When the preview window was resized we need to
+ * update the view on the buffer. Only go back to
+ * the window when needed, otherwise it will always be
+ * redraw. */
+ if (resized)
+ {
+ ++no_u_sync;
+ win_enter(curwin_save, TRUE);
+ --no_u_sync;
+ update_topline();
+ }
+
+ /* Update the screen before drawing the popup menu.
+ * Enable updating the status lines. */
+ pum_do_redraw = TRUE;
+ update_screen(0);
+ pum_do_redraw = FALSE;
+
+ if (!resized && win_valid(curwin_save))
+ {
+ ++no_u_sync;
+ win_enter(curwin_save, TRUE);
+ --no_u_sync;
+ }
+
+ /* May need to update the screen again when there are
+ * autocommands involved. */
+ pum_do_redraw = TRUE;
+ update_screen(0);
+ pum_do_redraw = FALSE;
+ call_update_screen = FALSE;
+ }
+ }
+ }
+ }
+#endif
+ }
+
+ if (!resized)
+ pum_redraw();
+
+ return resized;
+}
+
+/*
+ * Undisplay the popup menu (later).
+ */
+ void
+pum_undisplay(void)
+{
+ pum_array = NULL;
+ redraw_all_later(NOT_VALID);
+ redraw_tabline = TRUE;
+ status_redraw_all();
+}
+
+/*
+ * Clear the popup menu. Currently only resets the offset to the first
+ * displayed item.
+ */
+ void
+pum_clear(void)
+{
+ pum_first = 0;
+}
+
+/*
+ * Return TRUE if the popup menu is displayed.
+ * Overruled when "pum_do_redraw" is set, used to redraw the status lines.
+ */
+ int
+pum_visible(void)
+{
+ return !pum_do_redraw && pum_array != NULL;
+}
+
+/*
+ * Reposition the popup menu to adjust for window layout changes.
+ */
+ void
+pum_may_redraw(void)
+{
+ pumitem_T *array = pum_array;
+ int len = pum_size;
+ int selected = pum_selected;
+
+ if (!pum_visible() || pum_skip_redraw)
+ return; // nothing to do
+
+ if (pum_window != curwin
+ || (pum_win_row == curwin->w_wrow + W_WINROW(curwin)
+ && pum_win_height == curwin->w_height
+ && pum_win_col == curwin->w_wincol
+ && pum_win_width == curwin->w_width))
+ {
+ // window position didn't change, redraw in the same position
+ pum_redraw();
+ }
+ else
+ {
+ int wcol = curwin->w_wcol;
+
+ // Window layout changed, recompute the position.
+ // Use the remembered w_wcol value, the cursor may have moved when a
+ // completion was inserted, but we want the menu in the same position.
+ pum_undisplay();
+ curwin->w_wcol = pum_win_wcol;
+ curwin->w_valid |= VALID_WCOL;
+ pum_display(array, len, selected);
+ curwin->w_wcol = wcol;
+ }
+}
+
+/*
+ * Return the height of the popup menu, the number of entries visible.
+ * Only valid when pum_visible() returns TRUE!
+ */
+ int
+pum_get_height(void)
+{
+ return pum_height;
+}
+
+# if defined(FEAT_BEVAL_TERM) || defined(FEAT_TERM_POPUP_MENU) || defined(PROTO)
+ static void
+pum_position_at_mouse(int min_width)
+{
+ if (Rows - mouse_row > pum_size)
+ {
+ /* Enough space below the mouse row. */
+ pum_row = mouse_row + 1;
+ if (pum_height > Rows - pum_row)
+ pum_height = Rows - pum_row;
+ }
+ else
+ {
+ /* Show above the mouse row, reduce height if it does not fit. */
+ pum_row = mouse_row - pum_size;
+ if (pum_row < 0)
+ {
+ pum_height += pum_row;
+ pum_row = 0;
+ }
+ }
+ if (Columns - mouse_col >= pum_base_width
+ || Columns - mouse_col > min_width)
+ /* Enough space to show at mouse column. */
+ pum_col = mouse_col;
+ else
+ /* Not enough space, right align with window. */
+ pum_col = Columns - (pum_base_width > min_width
+ ? min_width : pum_base_width);
+
+ pum_width = Columns - pum_col;
+ if (pum_width > pum_base_width + 1)
+ pum_width = pum_base_width + 1;
+
+ // Do not redraw at cursor position.
+ pum_window = NULL;
+}
+
+# endif
+
+# if defined(FEAT_BEVAL_TERM) || defined(PROTO)
+static pumitem_T *balloon_array = NULL;
+static int balloon_arraysize;
+static int balloon_mouse_row = 0;
+static int balloon_mouse_col = 0;
+
+#define BALLOON_MIN_WIDTH 50
+#define BALLOON_MIN_HEIGHT 10
+
+typedef struct {
+ char_u *start;
+ int bytelen;
+ int cells;
+ int indent;
+} balpart_T;
+
+/*
+ * Split a string into parts to display in the balloon.
+ * Aimed at output from gdb. Attempts to split at white space, preserve quoted
+ * strings and make a struct look good.
+ * Resulting array is stored in "array" and returns the size of the array.
+ */
+ int
+split_message(char_u *mesg, pumitem_T **array)
+{
+ garray_T ga;
+ char_u *p;
+ balpart_T *item;
+ int quoted = FALSE;
+ int height;
+ int line;
+ int item_idx;
+ int indent = 0;
+ int max_cells = 0;
+ int max_height = Rows / 2 - 2;
+ int long_item_count = 0;
+ int split_long_items = FALSE;
+
+ ga_init2(&ga, sizeof(balpart_T), 20);
+ p = mesg;
+
+ while (*p != NUL)
+ {
+ if (ga_grow(&ga, 1) == FAIL)
+ goto failed;
+ item = ((balpart_T *)ga.ga_data) + ga.ga_len;
+ item->start = p;
+ item->indent = indent;
+ item->cells = indent * 2;
+ ++ga.ga_len;
+ while (*p != NUL)
+ {
+ if (*p == '"')
+ quoted = !quoted;
+ else if (*p == '\\' && p[1] != NUL)
+ ++p;
+ else if (!quoted)
+ {
+ if ((*p == ',' && p[1] == ' ') || *p == '{' || *p == '}')
+ {
+ /* Looks like a good point to break. */
+ if (*p == '{')
+ ++indent;
+ else if (*p == '}' && indent > 0)
+ --indent;
+ ++item->cells;
+ p = skipwhite(p + 1);
+ break;
+ }
+ }
+ item->cells += ptr2cells(p);
+ p += MB_PTR2LEN(p);
+ }
+ item->bytelen = p - item->start;
+ if (item->cells > max_cells)
+ max_cells = item->cells;
+ long_item_count += (item->cells - 1) / BALLOON_MIN_WIDTH;
+ }
+
+ height = 2 + ga.ga_len;
+
+ /* If there are long items and the height is below the limit: split lines */
+ if (long_item_count > 0 && height + long_item_count <= max_height)
+ {
+ split_long_items = TRUE;
+ height += long_item_count;
+ }
+
+ /* Limit to half the window height, it has to fit above or below the mouse
+ * position. */
+ if (height > max_height)
+ height = max_height;
+ *array = (pumitem_T *)alloc_clear((unsigned)sizeof(pumitem_T) * height);
+ if (*array == NULL)
+ goto failed;
+
+ /* Add an empty line above and below, looks better. */
+ (*array)->pum_text = vim_strsave((char_u *)"");
+ (*array + height - 1)->pum_text = vim_strsave((char_u *)"");
+
+ for (line = 1, item_idx = 0; line < height - 1; ++item_idx)
+ {
+ int skip;
+ int thislen;
+ int copylen;
+ int ind;
+ int cells;
+
+ item = ((balpart_T *)ga.ga_data) + item_idx;
+ for (skip = 0; skip < item->bytelen; skip += thislen)
+ {
+ if (split_long_items && item->cells >= BALLOON_MIN_WIDTH)
+ {
+ cells = item->indent * 2;
+ for (p = item->start + skip; p < item->start + item->bytelen;
+ p += MB_PTR2LEN(p))
+ if ((cells += ptr2cells(p)) > BALLOON_MIN_WIDTH)
+ break;
+ thislen = p - (item->start + skip);
+ }
+ else
+ thislen = item->bytelen;
+
+ /* put indent at the start */
+ p = alloc(thislen + item->indent * 2 + 1);
+ for (ind = 0; ind < item->indent * 2; ++ind)
+ p[ind] = ' ';
+
+ /* exclude spaces at the end of the string */
+ for (copylen = thislen; copylen > 0; --copylen)
+ if (item->start[skip + copylen - 1] != ' ')
+ break;
+
+ vim_strncpy(p + ind, item->start + skip, copylen);
+ (*array)[line].pum_text = p;
+ item->indent = 0; /* wrapped line has no indent */
+ ++line;
+ }
+ }
+ ga_clear(&ga);
+ return height;
+
+failed:
+ ga_clear(&ga);
+ return 0;
+}
+
+ void
+ui_remove_balloon(void)
+{
+ if (balloon_array != NULL)
+ {
+ pum_undisplay();
+ while (balloon_arraysize > 0)
+ vim_free(balloon_array[--balloon_arraysize].pum_text);
+ VIM_CLEAR(balloon_array);
+ }
+}
+
+/*
+ * Terminal version of a balloon, uses the popup menu code.
+ */
+ void
+ui_post_balloon(char_u *mesg, list_T *list)
+{
+ ui_remove_balloon();
+
+ if (mesg == NULL && list == NULL)
+ return;
+ if (list != NULL)
+ {
+ listitem_T *li;
+ int idx;
+
+ balloon_arraysize = list->lv_len;
+ balloon_array = (pumitem_T *)alloc_clear(
+ (unsigned)sizeof(pumitem_T) * list->lv_len);
+ if (balloon_array == NULL)
+ return;
+ for (idx = 0, li = list->lv_first; li != NULL; li = li->li_next, ++idx)
+ {
+ char_u *text = tv_get_string_chk(&li->li_tv);
+
+ balloon_array[idx].pum_text = vim_strsave(
+ text == NULL ? (char_u *)"" : text);
+ }
+ }
+ else
+ balloon_arraysize = split_message(mesg, &balloon_array);
+
+ if (balloon_arraysize > 0)
+ {
+ pum_array = balloon_array;
+ pum_size = balloon_arraysize;
+ pum_compute_size();
+ pum_scrollbar = 0;
+ pum_height = balloon_arraysize;
+
+ pum_position_at_mouse(BALLOON_MIN_WIDTH);
+ pum_selected = -1;
+ pum_first = 0;
+ pum_redraw();
+ }
+}
+
+/*
+ * Called when the mouse moved, may remove any displayed balloon.
+ */
+ void
+ui_may_remove_balloon(void)
+{
+ if (mouse_row != balloon_mouse_row || mouse_col != balloon_mouse_col)
+ ui_remove_balloon();
+}
+# endif
+
+# if defined(FEAT_TERM_POPUP_MENU) || defined(PROTO)
+/*
+ * Select the pum entry at the mouse position.
+ */
+ static void
+pum_select_mouse_pos(void)
+{
+ int idx = mouse_row - pum_row;
+
+ if (idx < 0 || idx >= pum_size)
+ pum_selected = -1;
+ else if (*pum_array[idx].pum_text != NUL)
+ pum_selected = idx;
+}
+
+/*
+ * Execute the currently selected popup menu item.
+ */
+ static void
+pum_execute_menu(vimmenu_T *menu, int mode)
+{
+ vimmenu_T *mp;
+ int idx = 0;
+ exarg_T ea;
+
+ for (mp = menu->children; mp != NULL; mp = mp->next)
+ if ((mp->modes & mp->enabled & mode) && idx++ == pum_selected)
+ {
+ vim_memset(&ea, 0, sizeof(ea));
+ execute_menu(&ea, mp, -1);
+ break;
+ }
+}
+
+/*
+ * Open the terminal version of the popup menu and don't return until it is
+ * closed.
+ */
+ void
+pum_show_popupmenu(vimmenu_T *menu)
+{
+ vimmenu_T *mp;
+ int idx = 0;
+ pumitem_T *array;
+#ifdef FEAT_BEVAL_TERM
+ int save_bevalterm = p_bevalterm;
+#endif
+ int mode;
+
+ pum_undisplay();
+ pum_size = 0;
+ mode = get_menu_mode_flag();
+
+ for (mp = menu->children; mp != NULL; mp = mp->next)
+ if (menu_is_separator(mp->dname)
+ || (mp->modes & mp->enabled & mode))
+ ++pum_size;
+
+ // When there are only Terminal mode menus, using "popup Edit" results in
+ // pum_size being zero.
+ if (pum_size <= 0)
+ {
+ emsg(e_menuothermode);
+ return;
+ }
+
+ array = (pumitem_T *)alloc_clear((unsigned)sizeof(pumitem_T) * pum_size);
+ if (array == NULL)
+ return;
+
+ for (mp = menu->children; mp != NULL; mp = mp->next)
+ if (menu_is_separator(mp->dname))
+ array[idx++].pum_text = (char_u *)"";
+ else if (mp->modes & mp->enabled & mode)
+ array[idx++].pum_text = mp->dname;
+
+ pum_array = array;
+ pum_compute_size();
+ pum_scrollbar = 0;
+ pum_height = pum_size;
+ pum_position_at_mouse(20);
+
+ pum_selected = -1;
+ pum_first = 0;
+# ifdef FEAT_BEVAL_TERM
+ p_bevalterm = TRUE; /* track mouse movement */
+ mch_setmouse(TRUE);
+# endif
+
+ for (;;)
+ {
+ int c;
+
+ pum_redraw();
+ setcursor_mayforce(TRUE);
+ out_flush();
+
+ c = vgetc();
+ if (c == ESC || c == Ctrl_C)
+ break;
+ else if (c == CAR || c == NL)
+ {
+ /* enter: select current item, if any, and close */
+ pum_execute_menu(menu, mode);
+ break;
+ }
+ else if (c == 'k' || c == K_UP || c == K_MOUSEUP)
+ {
+ /* cursor up: select previous item */
+ while (pum_selected > 0)
+ {
+ --pum_selected;
+ if (*array[pum_selected].pum_text != NUL)
+ break;
+ }
+ }
+ else if (c == 'j' || c == K_DOWN || c == K_MOUSEDOWN)
+ {
+ /* cursor down: select next item */
+ while (pum_selected < pum_size - 1)
+ {
+ ++pum_selected;
+ if (*array[pum_selected].pum_text != NUL)
+ break;
+ }
+ }
+ else if (c == K_RIGHTMOUSE)
+ {
+ /* Right mouse down: reposition the menu. */
+ vungetc(c);
+ break;
+ }
+ else if (c == K_LEFTDRAG || c == K_RIGHTDRAG || c == K_MOUSEMOVE)
+ {
+ /* mouse moved: select item in the mouse row */
+ pum_select_mouse_pos();
+ }
+ else if (c == K_LEFTMOUSE || c == K_LEFTMOUSE_NM || c == K_RIGHTRELEASE)
+ {
+ /* left mouse click: select clicked item, if any, and close;
+ * right mouse release: select clicked item, close if any */
+ pum_select_mouse_pos();
+ if (pum_selected >= 0)
+ {
+ pum_execute_menu(menu, mode);
+ break;
+ }
+ if (c == K_LEFTMOUSE || c == K_LEFTMOUSE_NM)
+ break;
+ }
+ }
+
+ vim_free(array);
+ pum_undisplay();
+# ifdef FEAT_BEVAL_TERM
+ p_bevalterm = save_bevalterm;
+ mch_setmouse(TRUE);
+# endif
+}
+
+ void
+pum_make_popup(char_u *path_name, int use_mouse_pos)
+{
+ vimmenu_T *menu;
+
+ if (!use_mouse_pos)
+ {
+ /* Hack: set mouse position at the cursor so that the menu pops up
+ * around there. */
+ mouse_row = curwin->w_winrow + curwin->w_wrow;
+ mouse_col = curwin->w_wincol + curwin->w_wcol;
+ }
+
+ menu = gui_find_menu(path_name);
+ if (menu != NULL)
+ pum_show_popupmenu(menu);
+}
+# endif
+
+#endif
diff --git a/src/proto.h b/src/proto.h
new file mode 100644
index 0000000..d7e6316
--- /dev/null
+++ b/src/proto.h
@@ -0,0 +1,339 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * Do ":help uganda" in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ */
+
+/*
+ * proto.h: include the (automatically generated) function prototypes
+ */
+
+/*
+ * Don't include these while generating prototypes. Prevents problems when
+ * files are missing.
+ */
+#if !defined(PROTO) && !defined(NOPROTO)
+
+/*
+ * Machine-dependent routines.
+ */
+/* avoid errors in function prototypes */
+# if !defined(FEAT_X11) && !defined(FEAT_GUI_GTK)
+# define Display int
+# define Widget int
+# endif
+# ifndef FEAT_GUI_GTK
+# define GdkEvent int
+# define GdkEventKey int
+# endif
+# ifndef FEAT_X11
+# define XImage int
+# endif
+
+# ifdef AMIGA
+# include "os_amiga.pro"
+# endif
+# if defined(UNIX) || defined(VMS)
+# include "os_unix.pro"
+# endif
+# ifdef WIN3264
+# include "os_win32.pro"
+# include "os_mswin.pro"
+# include "winclip.pro"
+# if (defined(__GNUC__) && !defined(__MINGW32__)) \
+ || (defined(__BORLANDC__) && __BORLANDC__ < 0x502)
+extern int _stricoll(char *a, char *b);
+# endif
+# endif
+# ifdef VMS
+# include "os_vms.pro"
+# endif
+# ifdef __BEOS__
+# include "os_beos.pro"
+# endif
+# ifdef __QNX__
+# include "os_qnx.pro"
+# endif
+
+# ifdef FEAT_CRYPT
+# include "blowfish.pro"
+# include "crypt.pro"
+# include "crypt_zip.pro"
+# endif
+# include "autocmd.pro"
+# include "buffer.pro"
+# include "charset.pro"
+# ifdef FEAT_CSCOPE
+# include "if_cscope.pro"
+# endif
+# include "dict.pro"
+# include "diff.pro"
+# include "digraph.pro"
+# include "edit.pro"
+# include "eval.pro"
+# include "evalfunc.pro"
+# include "ex_cmds.pro"
+# include "ex_cmds2.pro"
+# include "ex_docmd.pro"
+# include "ex_eval.pro"
+# include "ex_getln.pro"
+# include "fileio.pro"
+# include "fold.pro"
+# include "getchar.pro"
+# ifdef FEAT_HANGULIN
+# include "hangulin.pro"
+# endif
+# include "hardcopy.pro"
+# include "hashtab.pro"
+# include "indent.pro"
+# include "json.pro"
+# include "list.pro"
+# include "blob.pro"
+# include "main.pro"
+# include "mark.pro"
+# include "memfile.pro"
+# include "memline.pro"
+# ifdef FEAT_MENU
+# include "menu.pro"
+# endif
+# ifdef FEAT_FKMAP
+# include "farsi.pro"
+# endif
+# ifdef FEAT_ARABIC
+# include "arabic.pro"
+# endif
+
+/* These prototypes cannot be produced automatically. */
+int
+# ifdef __BORLANDC__
+_RTLENTRYF
+# endif
+smsg(const char *, ...)
+#ifdef USE_PRINTF_FORMAT_ATTRIBUTE
+ __attribute__((format(printf, 1, 0)))
+#endif
+ ;
+
+int
+# ifdef __BORLANDC__
+_RTLENTRYF
+# endif
+smsg_attr(int, const char *, ...)
+#ifdef USE_PRINTF_FORMAT_ATTRIBUTE
+ __attribute__((format(printf, 2, 3)))
+#endif
+ ;
+
+int
+# ifdef __BORLANDC__
+_RTLENTRYF
+# endif
+smsg_attr_keep(int, const char *, ...)
+#ifdef USE_PRINTF_FORMAT_ATTRIBUTE
+ __attribute__((format(printf, 2, 3)))
+#endif
+ ;
+
+int
+# ifdef __BORLANDC__
+_RTLENTRYF
+# endif
+vim_snprintf_add(char *, size_t, const char *, ...)
+#ifdef USE_PRINTF_FORMAT_ATTRIBUTE
+ __attribute__((format(printf, 3, 4)))
+#endif
+ ;
+
+int
+# ifdef __BORLANDC__
+_RTLENTRYF
+# endif
+vim_snprintf(char *, size_t, const char *, ...)
+#ifdef USE_PRINTF_FORMAT_ATTRIBUTE
+ __attribute__((format(printf, 3, 4)))
+#endif
+ ;
+
+int vim_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap);
+int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap, typval_T *tvs);
+
+# include "message.pro"
+# include "misc1.pro"
+# include "misc2.pro"
+#ifndef HAVE_STRPBRK /* not generated automatically from misc2.c */
+char_u *vim_strpbrk(char_u *s, char_u *charset);
+#endif
+#ifndef HAVE_QSORT
+/* Use our own qsort(), don't define the prototype when not used. */
+void qsort(void *base, size_t elm_count, size_t elm_size, int (*cmp)(const void *, const void *));
+#endif
+# include "move.pro"
+# include "mbyte.pro"
+# include "normal.pro"
+# include "ops.pro"
+# include "option.pro"
+# include "popupmnu.pro"
+# ifdef FEAT_QUICKFIX
+# include "quickfix.pro"
+# endif
+# include "regexp.pro"
+# include "screen.pro"
+# if defined(FEAT_CRYPT) || defined(FEAT_PERSISTENT_UNDO)
+# include "sha256.pro"
+# endif
+# include "search.pro"
+# ifdef FEAT_SIGNS
+# include "sign.pro"
+# endif
+# include "spell.pro"
+# include "spellfile.pro"
+# include "syntax.pro"
+# include "tag.pro"
+# include "term.pro"
+# ifdef FEAT_TERMINAL
+# include "terminal.pro"
+# endif
+# if defined(HAVE_TGETENT) && (defined(AMIGA) || defined(VMS))
+# include "termlib.pro"
+# endif
+# ifdef FEAT_TEXT_PROP
+# include "textprop.pro"
+# endif
+# include "ui.pro"
+# include "undo.pro"
+# include "userfunc.pro"
+# include "version.pro"
+# include "window.pro"
+
+# ifdef FEAT_LUA
+# include "if_lua.pro"
+# endif
+
+# ifdef FEAT_MZSCHEME
+# include "if_mzsch.pro"
+# endif
+
+# ifdef FEAT_PYTHON
+# include "if_python.pro"
+# endif
+
+# ifdef FEAT_PYTHON3
+# include "if_python3.pro"
+# endif
+
+# ifdef FEAT_TCL
+# include "if_tcl.pro"
+# endif
+
+# ifdef FEAT_RUBY
+# include "if_ruby.pro"
+# endif
+
+/* Ugly solution for "BalloonEval" not being defined while it's used in some
+ * .pro files. */
+# ifdef FEAT_BEVAL
+# include "beval.pro"
+# else
+# define BalloonEval int
+# endif
+
+# ifdef FEAT_NETBEANS_INTG
+# include "netbeans.pro"
+# endif
+# ifdef FEAT_JOB_CHANNEL
+# include "channel.pro"
+
+/* Not generated automatically, to add extra attribute. */
+void ch_log(channel_T *ch, const char *fmt, ...)
+#ifdef USE_PRINTF_FORMAT_ATTRIBUTE
+ __attribute__((format(printf, 2, 3)))
+#endif
+ ;
+
+# endif
+
+# if defined(FEAT_GUI) || defined(FEAT_JOB_CHANNEL)
+# if defined(UNIX) || defined(MACOS_X) || defined(VMS)
+# include "pty.pro"
+# endif
+# endif
+
+# ifdef FEAT_GUI
+# include "gui.pro"
+# if !defined(HAVE_SETENV) && !defined(HAVE_PUTENV) && !defined(VMS)
+extern int putenv(const char *string); /* in misc2.c */
+# ifdef USE_VIMPTY_GETENV
+extern char_u *vimpty_getenv(const char_u *string); /* in misc2.c */
+# endif
+# endif
+# ifdef FEAT_GUI_W32
+# include "gui_w32.pro"
+# endif
+# ifdef FEAT_GUI_GTK
+# include "gui_gtk.pro"
+# include "gui_gtk_x11.pro"
+# endif
+# ifdef FEAT_GUI_MOTIF
+# include "gui_motif.pro"
+# include "gui_xmdlg.pro"
+# endif
+# ifdef FEAT_GUI_ATHENA
+# include "gui_athena.pro"
+# ifdef FEAT_BROWSE
+extern char *vim_SelFile(Widget toplevel, char *prompt, char *init_path, int (*show_entry)(), int x, int y, guicolor_T fg, guicolor_T bg, guicolor_T scroll_fg, guicolor_T scroll_bg);
+# endif
+# endif
+# ifdef FEAT_GUI_MAC
+# include "gui_mac.pro"
+# endif
+# ifdef FEAT_GUI_X11
+# include "gui_x11.pro"
+# endif
+# ifdef FEAT_GUI_PHOTON
+# include "gui_photon.pro"
+# endif
+# endif /* FEAT_GUI */
+
+# ifdef FEAT_OLE
+# include "if_ole.pro"
+# endif
+# if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
+# include "if_xcmdsrv.pro"
+# endif
+
+/*
+ * The perl include files pollute the namespace, therefore proto.h must be
+ * included before the perl include files. But then CV is not defined, which
+ * is used in if_perl.pro. To get around this, the perl prototype files are
+ * not included here for the perl files. Use a dummy define for CV for the
+ * other files.
+ */
+#if defined(FEAT_PERL) && !defined(IN_PERL_FILE)
+# define CV void
+# ifdef __BORLANDC__
+ #pragma option -pc
+# endif
+# include "if_perl.pro"
+# ifdef __BORLANDC__
+ #pragma option -p.
+# endif
+# include "if_perlsfio.pro"
+#endif
+
+#ifdef MACOS_CONVERT
+# include "os_mac_conv.pro"
+#endif
+#if defined(MACOS_X_DARWIN) && defined(FEAT_CLIPBOARD) && !defined(FEAT_GUI)
+/* functions in os_macosx.m */
+void clip_mch_lose_selection(VimClipboard *cbd);
+int clip_mch_own_selection(VimClipboard *cbd);
+void clip_mch_request_selection(VimClipboard *cbd);
+void clip_mch_set_selection(VimClipboard *cbd);
+#endif
+
+#ifdef __BORLANDC__
+# define _PROTO_H
+#endif
+#endif /* !PROTO && !NOPROTO */
diff --git a/src/proto/arabic.pro b/src/proto/arabic.pro
new file mode 100644
index 0000000..a004ef9
--- /dev/null
+++ b/src/proto/arabic.pro
@@ -0,0 +1,3 @@
+/* arabic.c */
+int arabic_shape(int c, int *ccp, int *c1p, int prev_c, int prev_c1, int next_c);
+/* vim: set ft=c : */
diff --git a/src/proto/autocmd.pro b/src/proto/autocmd.pro
new file mode 100644
index 0000000..8c6d18f
--- /dev/null
+++ b/src/proto/autocmd.pro
@@ -0,0 +1,39 @@
+/* autocmd.c */
+void aubuflocal_remove(buf_T *buf);
+int au_has_group(char_u *name);
+void do_augroup(char_u *arg, int del_group);
+void free_all_autocmds(void);
+int check_ei(void);
+char_u *au_event_disable(char *what);
+void au_event_restore(char_u *old_ei);
+void do_autocmd(char_u *arg_in, int forceit);
+int do_doautocmd(char_u *arg, int do_msg, int *did_something);
+void ex_doautoall(exarg_T *eap);
+int check_nomodeline(char_u **argp);
+void aucmd_prepbuf(aco_save_T *aco, buf_T *buf);
+void aucmd_restbuf(aco_save_T *aco);
+int apply_autocmds(event_T event, char_u *fname, char_u *fname_io, int force, buf_T *buf);
+int apply_autocmds_exarg(event_T event, char_u *fname, char_u *fname_io, int force, buf_T *buf, exarg_T *eap);
+int apply_autocmds_retval(event_T event, char_u *fname, char_u *fname_io, int force, buf_T *buf, int *retval);
+int has_cursorhold(void);
+int trigger_cursorhold(void);
+int has_cursormoved(void);
+int has_cursormovedI(void);
+int has_textchanged(void);
+int has_textchangedI(void);
+int has_textchangedP(void);
+int has_insertcharpre(void);
+int has_cmdundefined(void);
+int has_funcundefined(void);
+int has_textyankpost(void);
+void block_autocmds(void);
+void unblock_autocmds(void);
+int is_autocmd_blocked(void);
+char_u *getnextac(int c, void *cookie, int indent);
+int has_autocmd(event_T event, char_u *sfname, buf_T *buf);
+char_u *get_augroup_name(expand_T *xp, int idx);
+char_u *set_context_in_autocmd(expand_T *xp, char_u *arg, int doautocmd);
+char_u *get_event_name(expand_T *xp, int idx);
+int autocmd_supported(char_u *name);
+int au_exists(char_u *arg);
+/* vim: set ft=c : */
diff --git a/src/proto/beval.pro b/src/proto/beval.pro
new file mode 100644
index 0000000..2be64a0
--- /dev/null
+++ b/src/proto/beval.pro
@@ -0,0 +1,6 @@
+/* beval.c */
+int get_beval_info(BalloonEval *beval, int getword, win_T **winp, linenr_T *lnump, char_u **textp, int *colp);
+void post_balloon(BalloonEval *beval, char_u *mesg, list_T *list);
+int can_use_beval(void);
+void general_beval_cb(BalloonEval *beval, int state);
+/* vim: set ft=c : */
diff --git a/src/proto/blob.pro b/src/proto/blob.pro
new file mode 100644
index 0000000..019692d
--- /dev/null
+++ b/src/proto/blob.pro
@@ -0,0 +1,16 @@
+/* blob.c */
+blob_T *blob_alloc(void);
+int rettv_blob_alloc(typval_T *rettv);
+void rettv_blob_set(typval_T *rettv, blob_T *b);
+int blob_copy(typval_T *from, typval_T *to);
+void blob_free(blob_T *b);
+void blob_unref(blob_T *b);
+long blob_len(blob_T *b);
+int blob_get(blob_T *b, int idx);
+void blob_set(blob_T *b, int idx, char_u c);
+int blob_equal(blob_T *b1, blob_T *b2);
+int read_blob(FILE *fd, blob_T *blob);
+int write_blob(FILE *fd, blob_T *blob);
+char_u *blob2string(blob_T *blob, char_u **tofree, char_u *numbuf);
+blob_T *string2blob(char_u *str);
+/* vim: set ft=c : */
diff --git a/src/proto/blowfish.pro b/src/proto/blowfish.pro
new file mode 100644
index 0000000..d959846
--- /dev/null
+++ b/src/proto/blowfish.pro
@@ -0,0 +1,6 @@
+/* blowfish.c */
+void crypt_blowfish_encode(cryptstate_T *state, char_u *from, size_t len, char_u *to);
+void crypt_blowfish_decode(cryptstate_T *state, char_u *from, size_t len, char_u *to);
+void crypt_blowfish_init(cryptstate_T *state, char_u *key, char_u *salt, int salt_len, char_u *seed, int seed_len);
+int blowfish_self_test(void);
+/* vim: set ft=c : */
diff --git a/src/proto/buffer.pro b/src/proto/buffer.pro
new file mode 100644
index 0000000..5e1aa7a
--- /dev/null
+++ b/src/proto/buffer.pro
@@ -0,0 +1,75 @@
+/* buffer.c */
+int open_buffer(int read_stdin, exarg_T *eap, int flags);
+void set_bufref(bufref_T *bufref, buf_T *buf);
+int bufref_valid(bufref_T *bufref);
+int buf_valid(buf_T *buf);
+void close_buffer(win_T *win, buf_T *buf, int action, int abort_if_last);
+void buf_clear_file(buf_T *buf);
+void buf_freeall(buf_T *buf, int flags);
+void goto_buffer(exarg_T *eap, int start, int dir, int count);
+void handle_swap_exists(bufref_T *old_curbuf);
+char *do_bufdel(int command, char_u *arg, int addr_count, int start_bnr, int end_bnr, int forceit);
+int do_buffer(int action, int start, int dir, int count, int forceit);
+void set_curbuf(buf_T *buf, int action);
+void enter_buffer(buf_T *buf);
+void do_autochdir(void);
+void no_write_message(void);
+void no_write_message_nobang(buf_T *buf);
+int curbuf_reusable(void);
+buf_T *buflist_new(char_u *ffname_arg, char_u *sfname_arg, linenr_T lnum, int flags);
+void free_buf_options(buf_T *buf, int free_p_ff);
+int buflist_getfile(int n, linenr_T lnum, int options, int forceit);
+void buflist_getfpos(void);
+buf_T *buflist_findname_exp(char_u *fname);
+buf_T *buflist_findname(char_u *ffname);
+int buflist_findpat(char_u *pattern, char_u *pattern_end, int unlisted, int diffmode, int curtab_only);
+int ExpandBufnames(char_u *pat, int *num_file, char_u ***file, int options);
+buf_T *buflist_findnr(int nr);
+char_u *buflist_nr2name(int n, int fullname, int helptail);
+void get_winopts(buf_T *buf);
+pos_T *buflist_findfpos(buf_T *buf);
+linenr_T buflist_findlnum(buf_T *buf);
+void buflist_list(exarg_T *eap);
+int buflist_name_nr(int fnum, char_u **fname, linenr_T *lnum);
+int setfname(buf_T *buf, char_u *ffname_arg, char_u *sfname_arg, int message);
+void buf_set_name(int fnum, char_u *name);
+void buf_name_changed(buf_T *buf);
+buf_T *setaltfname(char_u *ffname, char_u *sfname, linenr_T lnum);
+char_u *getaltfname(int errmsg);
+int buflist_add(char_u *fname, int flags);
+void buflist_slash_adjust(void);
+void buflist_altfpos(win_T *win);
+int otherfile(char_u *ffname);
+void buf_setino(buf_T *buf);
+void fileinfo(int fullname, int shorthelp, int dont_truncate);
+void col_print(char_u *buf, size_t buflen, int col, int vcol);
+void maketitle(void);
+void resettitle(void);
+void free_titles(void);
+int build_stl_str_hl(win_T *wp, char_u *out, size_t outlen, char_u *fmt, int use_sandbox, int fillchar, int maxwidth, struct stl_hlrec *hltab, struct stl_hlrec *tabtab);
+void get_rel_pos(win_T *wp, char_u *buf, int buflen);
+char_u *fix_fname(char_u *fname);
+void fname_expand(buf_T *buf, char_u **ffname, char_u **sfname);
+char_u *alist_name(aentry_T *aep);
+void do_arg_all(int count, int forceit, int keep_tabs);
+void ex_buffer_all(exarg_T *eap);
+void do_modelines(int flags);
+int read_viminfo_bufferlist(vir_T *virp, int writing);
+void write_viminfo_bufferlist(FILE *fp);
+int bt_normal(buf_T *buf);
+int bt_quickfix(buf_T *buf);
+int bt_terminal(buf_T *buf);
+int bt_help(buf_T *buf);
+int bt_prompt(buf_T *buf);
+int bt_nofile(buf_T *buf);
+int bt_dontwrite(buf_T *buf);
+int bt_dontwrite_msg(buf_T *buf);
+int buf_hide(buf_T *buf);
+char_u *buf_spname(buf_T *buf);
+void switch_to_win_for_buf(buf_T *buf, win_T **save_curwinp, tabpage_T **save_curtabp, bufref_T *save_curbuf);
+void restore_win_for_buf(win_T *save_curwin, tabpage_T *save_curtab, bufref_T *save_curbuf);
+int find_win_for_buf(buf_T *buf, win_T **wp, tabpage_T **tp);
+void set_buflisted(int on);
+int buf_contents_changed(buf_T *buf);
+void wipe_buffer(buf_T *buf, int aucmd);
+/* vim: set ft=c : */
diff --git a/src/proto/channel.pro b/src/proto/channel.pro
new file mode 100644
index 0000000..0f5b655
--- /dev/null
+++ b/src/proto/channel.pro
@@ -0,0 +1,76 @@
+/* channel.c */
+void ch_logfile(char_u *fname, char_u *opt);
+int ch_log_active(void);
+channel_T *add_channel(void);
+int has_any_channel(void);
+int channel_unref(channel_T *channel);
+int free_unused_channels_contents(int copyID, int mask);
+void free_unused_channels(int copyID, int mask);
+void channel_gui_register_all(void);
+channel_T *channel_open(char *hostname, int port_in, int waittime, void (*nb_close_cb)(void));
+channel_T *channel_open_func(typval_T *argvars);
+void channel_set_pipes(channel_T *channel, sock_T in, sock_T out, sock_T err);
+void channel_set_job(channel_T *channel, job_T *job, jobopt_T *options);
+void channel_set_options(channel_T *channel, jobopt_T *opt);
+void channel_set_req_callback(channel_T *channel, ch_part_T part, char_u *callback, partial_T *partial, int id);
+void channel_buffer_free(buf_T *buf);
+void channel_write_any_lines(void);
+void channel_write_new_lines(buf_T *buf);
+readq_T *channel_peek(channel_T *channel, ch_part_T part);
+char_u *channel_first_nl(readq_T *node);
+char_u *channel_get(channel_T *channel, ch_part_T part, int *outlen);
+void channel_consume(channel_T *channel, ch_part_T part, int len);
+int channel_collapse(channel_T *channel, ch_part_T part, int want_nl);
+int channel_can_write_to(channel_T *channel);
+int channel_is_open(channel_T *channel);
+int channel_has_readahead(channel_T *channel, ch_part_T part);
+char *channel_status(channel_T *channel, int req_part);
+void channel_info(channel_T *channel, dict_T *dict);
+void channel_close(channel_T *channel, int invoke_close_cb);
+void channel_close_in(channel_T *channel);
+void channel_clear(channel_T *channel);
+void channel_free_all(void);
+void common_channel_read(typval_T *argvars, typval_T *rettv, int raw, int blob);
+channel_T *channel_fd2channel(sock_T fd, ch_part_T *partp);
+void channel_handle_events(int only_keep_open);
+int channel_any_keep_open(void);
+void channel_set_nonblock(channel_T *channel, ch_part_T part);
+int channel_send(channel_T *channel, ch_part_T part, char_u *buf_arg, int len_arg, char *fun);
+void ch_expr_common(typval_T *argvars, typval_T *rettv, int eval);
+void ch_raw_common(typval_T *argvars, typval_T *rettv, int eval);
+int channel_poll_setup(int nfd_in, void *fds_in, int *towait);
+int channel_poll_check(int ret_in, void *fds_in);
+int channel_select_setup(int maxfd_in, void *rfds_in, void *wfds_in, struct timeval *tv, struct timeval **tvp);
+int channel_select_check(int ret_in, void *rfds_in, void *wfds_in);
+int channel_parse_messages(void);
+int channel_any_readahead(void);
+int set_ref_in_channel(int copyID);
+ch_part_T channel_part_send(channel_T *channel);
+ch_part_T channel_part_read(channel_T *channel);
+ch_mode_T channel_get_mode(channel_T *channel, ch_part_T part);
+int channel_get_timeout(channel_T *channel, ch_part_T part);
+void clear_job_options(jobopt_T *opt);
+void free_job_options(jobopt_T *opt);
+int get_job_options(typval_T *tv, jobopt_T *opt, int supported, int supported2);
+channel_T *get_channel_arg(typval_T *tv, int check_open, int reading, ch_part_T part);
+void job_free_all(void);
+int job_any_running(void);
+int win32_build_cmd(list_T *l, garray_T *gap);
+void job_cleanup(job_T *job);
+int set_ref_in_job(int copyID);
+void job_unref(job_T *job);
+int free_unused_jobs_contents(int copyID, int mask);
+void free_unused_jobs(int copyID, int mask);
+job_T *job_alloc(void);
+void job_set_options(job_T *job, jobopt_T *opt);
+void job_stop_on_exit(void);
+int has_pending_job(void);
+int job_check_ended(void);
+job_T *job_start(typval_T *argvars, char **argv_arg, jobopt_T *opt_arg, int is_terminal);
+char *job_status(job_T *job);
+void job_info(job_T *job, dict_T *dict);
+void job_info_all(list_T *l);
+int job_stop(job_T *job, typval_T *argvars, char *type);
+void invoke_prompt_callback(void);
+int invoke_prompt_interrupt(void);
+/* vim: set ft=c : */
diff --git a/src/proto/charset.pro b/src/proto/charset.pro
new file mode 100644
index 0000000..bb4132f
--- /dev/null
+++ b/src/proto/charset.pro
@@ -0,0 +1,64 @@
+/* charset.c */
+int init_chartab(void);
+int buf_init_chartab(buf_T *buf, int global);
+void trans_characters(char_u *buf, int bufsize);
+char_u *transstr(char_u *s);
+char_u *str_foldcase(char_u *str, int orglen, char_u *buf, int buflen);
+char_u *transchar(int c);
+char_u *transchar_byte(int c);
+void transchar_nonprint(char_u *buf, int c);
+void transchar_hex(char_u *buf, int c);
+int byte2cells(int b);
+int char2cells(int c);
+int ptr2cells(char_u *p);
+int vim_strsize(char_u *s);
+int vim_strnsize(char_u *s, int len);
+int chartabsize(char_u *p, colnr_T col);
+int linetabsize(char_u *s);
+int linetabsize_col(int startcol, char_u *s);
+int win_linetabsize(win_T *wp, char_u *line, colnr_T len);
+int vim_isIDc(int c);
+int vim_iswordc(int c);
+int vim_iswordc_buf(int c, buf_T *buf);
+int vim_iswordp(char_u *p);
+int vim_iswordp_buf(char_u *p, buf_T *buf);
+int vim_isfilec(int c);
+int vim_isfilec_or_wc(int c);
+int vim_isprintc(int c);
+int vim_isprintc_strict(int c);
+int lbr_chartabsize(char_u *line, unsigned char *s, colnr_T col);
+int lbr_chartabsize_adv(char_u *line, char_u **s, colnr_T col);
+int win_lbr_chartabsize(win_T *wp, char_u *line, char_u *s, colnr_T col, int *headp);
+int in_win_border(win_T *wp, colnr_T vcol);
+void getvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, colnr_T *end);
+colnr_T getvcol_nolist(pos_T *posp);
+void getvvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, colnr_T *end);
+void getvcols(win_T *wp, pos_T *pos1, pos_T *pos2, colnr_T *left, colnr_T *right);
+char_u *skipwhite(char_u *q);
+int getwhitecols_curline(void);
+int getwhitecols(char_u *p);
+char_u *skipdigits(char_u *q);
+char_u *skipbin(char_u *q);
+char_u *skiphex(char_u *q);
+char_u *skiptobin(char_u *q);
+char_u *skiptodigit(char_u *q);
+char_u *skiptohex(char_u *q);
+int vim_isdigit(int c);
+int vim_isxdigit(int c);
+int vim_isbdigit(int c);
+int vim_islower(int c);
+int vim_isupper(int c);
+int vim_toupper(int c);
+int vim_tolower(int c);
+char_u *skiptowhite(char_u *p);
+char_u *skiptowhite_esc(char_u *p);
+long getdigits(char_u **pp);
+int vim_isblankline(char_u *lbuf);
+void vim_str2nr(char_u *start, int *prep, int *len, int what, varnumber_T *nptr, uvarnumber_T *unptr, int maxlen);
+int hex2nr(int c);
+int hexhex2nr(char_u *p);
+int rem_backslash(char_u *str);
+void backslash_halve(char_u *p);
+char_u *backslash_halve_save(char_u *p);
+void ebcdic2ascii(char_u *buffer, int len);
+/* vim: set ft=c : */
diff --git a/src/proto/crypt.pro b/src/proto/crypt.pro
new file mode 100644
index 0000000..e8ba188
--- /dev/null
+++ b/src/proto/crypt.pro
@@ -0,0 +1,22 @@
+/* crypt.c */
+int crypt_method_nr_from_name(char_u *name);
+int crypt_method_nr_from_magic(char *ptr, int len);
+int crypt_get_method_nr(buf_T *buf);
+int crypt_whole_undofile(int method_nr);
+int crypt_get_header_len(int method_nr);
+void crypt_set_cm_option(buf_T *buf, int method_nr);
+int crypt_self_test(void);
+cryptstate_T *crypt_create(int method_nr, char_u *key, char_u *salt, int salt_len, char_u *seed, int seed_len);
+cryptstate_T *crypt_create_from_header(int method_nr, char_u *key, char_u *header);
+cryptstate_T *crypt_create_from_file(FILE *fp, char_u *key);
+cryptstate_T *crypt_create_for_writing(int method_nr, char_u *key, char_u **header, int *header_len);
+void crypt_free_state(cryptstate_T *state);
+void crypt_encode(cryptstate_T *state, char_u *from, size_t len, char_u *to);
+void crypt_encode_inplace(cryptstate_T *state, char_u *buf, size_t len);
+void crypt_decode_inplace(cryptstate_T *state, char_u *buf, size_t len);
+void crypt_free_key(char_u *key);
+void crypt_check_method(int method);
+void crypt_check_current_method(void);
+char_u *crypt_get_key(int store, int twice);
+void crypt_append_msg(buf_T *buf);
+/* vim: set ft=c : */
diff --git a/src/proto/crypt_zip.pro b/src/proto/crypt_zip.pro
new file mode 100644
index 0000000..74784e1
--- /dev/null
+++ b/src/proto/crypt_zip.pro
@@ -0,0 +1,5 @@
+/* crypt_zip.c */
+void crypt_zip_init(cryptstate_T *state, char_u *key, char_u *salt, int salt_len, char_u *seed, int seed_len);
+void crypt_zip_encode(cryptstate_T *state, char_u *from, size_t len, char_u *to);
+void crypt_zip_decode(cryptstate_T *state, char_u *from, size_t len, char_u *to);
+/* vim: set ft=c : */
diff --git a/src/proto/dict.pro b/src/proto/dict.pro
new file mode 100644
index 0000000..b09a647
--- /dev/null
+++ b/src/proto/dict.pro
@@ -0,0 +1,32 @@
+/* dict.c */
+dict_T *dict_alloc(void);
+dict_T *dict_alloc_id(alloc_id_T id);
+dict_T *dict_alloc_lock(int lock);
+int rettv_dict_alloc(typval_T *rettv);
+void rettv_dict_set(typval_T *rettv, dict_T *d);
+void dict_free_contents(dict_T *d);
+void dict_unref(dict_T *d);
+int dict_free_nonref(int copyID);
+void dict_free_items(int copyID);
+dictitem_T *dictitem_alloc(char_u *key);
+void dictitem_remove(dict_T *dict, dictitem_T *item);
+void dictitem_free(dictitem_T *item);
+dict_T *dict_copy(dict_T *orig, int deep, int copyID);
+int dict_add(dict_T *d, dictitem_T *item);
+int dict_add_number(dict_T *d, char *key, varnumber_T nr);
+int dict_add_string(dict_T *d, char *key, char_u *str);
+int dict_add_string_len(dict_T *d, char *key, char_u *str, int len);
+int dict_add_list(dict_T *d, char *key, list_T *list);
+int dict_add_dict(dict_T *d, char *key, dict_T *dict);
+long dict_len(dict_T *d);
+dictitem_T *dict_find(dict_T *d, char_u *key, int len);
+char_u *dict_get_string(dict_T *d, char_u *key, int save);
+varnumber_T dict_get_number(dict_T *d, char_u *key);
+char_u *dict2string(typval_T *tv, int copyID, int restore_copyID);
+int dict_get_tv(char_u **arg, typval_T *rettv, int evaluate);
+void dict_extend(dict_T *d1, dict_T *d2, char_u *action);
+dictitem_T *dict_lookup(hashitem_T *hi);
+int dict_equal(dict_T *d1, dict_T *d2, int ic, int recursive);
+void dict_list(typval_T *argvars, typval_T *rettv, int what);
+void dict_set_items_ro(dict_T *di);
+/* vim: set ft=c : */
diff --git a/src/proto/diff.pro b/src/proto/diff.pro
new file mode 100644
index 0000000..d6ab221
--- /dev/null
+++ b/src/proto/diff.pro
@@ -0,0 +1,29 @@
+/* diff.c */
+void diff_buf_delete(buf_T *buf);
+void diff_buf_adjust(win_T *win);
+void diff_buf_add(buf_T *buf);
+void diff_invalidate(buf_T *buf);
+void diff_mark_adjust(linenr_T line1, linenr_T line2, long amount, long amount_after);
+int diff_internal(void);
+void ex_diffupdate(exarg_T *eap);
+void ex_diffpatch(exarg_T *eap);
+void ex_diffsplit(exarg_T *eap);
+void ex_diffthis(exarg_T *eap);
+void diff_win_options(win_T *wp, int addbuf);
+void ex_diffoff(exarg_T *eap);
+void diff_clear(tabpage_T *tp);
+int diff_check(win_T *wp, linenr_T lnum);
+int diff_check_fill(win_T *wp, linenr_T lnum);
+void diff_set_topline(win_T *fromwin, win_T *towin);
+int diffopt_changed(void);
+int diffopt_horizontal(void);
+int diffopt_hiddenoff(void);
+int diff_find_change(win_T *wp, linenr_T lnum, int *startp, int *endp);
+int diff_infold(win_T *wp, linenr_T lnum);
+void nv_diffgetput(int put, long count);
+void ex_diffgetput(exarg_T *eap);
+int diff_mode_buf(buf_T *buf);
+int diff_move_to(int dir, long count);
+linenr_T diff_get_corresponding_line(buf_T *buf1, linenr_T lnum1);
+linenr_T diff_lnum_win(linenr_T lnum, win_T *wp);
+/* vim: set ft=c : */
diff --git a/src/proto/digraph.pro b/src/proto/digraph.pro
new file mode 100644
index 0000000..06b3341
--- /dev/null
+++ b/src/proto/digraph.pro
@@ -0,0 +1,11 @@
+/* digraph.c */
+int do_digraph(int c);
+char_u *get_digraph_for_char(int val_arg);
+int get_digraph(int cmdline);
+int getdigraph(int char1, int char2, int meta_char);
+void putdigraph(char_u *str);
+void listdigraphs(int use_headers);
+char *keymap_init(void);
+void ex_loadkeymap(exarg_T *eap);
+void keymap_clear(garray_T *kmap);
+/* vim: set ft=c : */
diff --git a/src/proto/edit.pro b/src/proto/edit.pro
new file mode 100644
index 0000000..3a1573f
--- /dev/null
+++ b/src/proto/edit.pro
@@ -0,0 +1,47 @@
+/* edit.c */
+int edit(int cmdchar, int startln, long count);
+void edit_putchar(int c, int highlight);
+char_u *prompt_text(void);
+int prompt_curpos_editable(void);
+void edit_unputchar(void);
+void display_dollar(colnr_T col);
+void change_indent(int type, int amount, int round, int replaced, int call_changed_bytes);
+void truncate_spaces(char_u *line);
+void backspace_until_column(int col);
+int ctrl_x_mode_not_default(void);
+int ctrl_x_mode_not_defined_yet(void);
+int vim_is_ctrl_x_key(int c);
+int ins_compl_add_infercase(char_u *str, int len, int icase, char_u *fname, int dir, int flags);
+void completeopt_was_set(void);
+void set_completion(colnr_T startcol, list_T *list);
+void ins_compl_show_pum(void);
+char_u *find_word_start(char_u *ptr);
+char_u *find_word_end(char_u *ptr);
+int ins_compl_active(void);
+int ins_compl_add_tv(typval_T *tv, int dir);
+void ins_compl_check_keys(int frequency, int in_compl_func);
+int get_literal(void);
+void insertchar(int c, int flags, int second_indent);
+void auto_format(int trailblank, int prev_line);
+int comp_textwidth(int ff);
+int stop_arrow(void);
+void set_last_insert(int c);
+void free_last_insert(void);
+char_u *add_char2buf(int c, char_u *s);
+void beginline(int flags);
+int oneright(void);
+int oneleft(void);
+int cursor_up(long n, int upd_topline);
+int cursor_down(long n, int upd_topline);
+int stuff_inserted(int c, long count, int no_esc);
+char_u *get_last_insert(void);
+char_u *get_last_insert_save(void);
+void replace_push(int c);
+int replace_push_mb(char_u *p);
+int hkmap(int c);
+int bracketed_paste(paste_mode_T mode, int drop, garray_T *gap);
+void ins_scroll(void);
+void ins_horscroll(void);
+int ins_copychar(linenr_T lnum);
+colnr_T get_nolist_virtcol(void);
+/* vim: set ft=c : */
diff --git a/src/proto/eval.pro b/src/proto/eval.pro
new file mode 100644
index 0000000..1e673e3
--- /dev/null
+++ b/src/proto/eval.pro
@@ -0,0 +1,144 @@
+/* eval.c */
+void eval_init(void);
+void eval_clear(void);
+void set_internal_string_var(char_u *name, char_u *value);
+int var_redir_start(char_u *name, int append);
+void var_redir_str(char_u *value, int value_len);
+void var_redir_stop(void);
+int eval_charconvert(char_u *enc_from, char_u *enc_to, char_u *fname_from, char_u *fname_to);
+int eval_printexpr(char_u *fname, char_u *args);
+void eval_diff(char_u *origfile, char_u *newfile, char_u *outfile);
+void eval_patch(char_u *origfile, char_u *difffile, char_u *outfile);
+int eval_to_bool(char_u *arg, int *error, char_u **nextcmd, int skip);
+int eval_expr_to_bool(typval_T *expr, int *error);
+char_u *eval_to_string_skip(char_u *arg, char_u **nextcmd, int skip);
+int skip_expr(char_u **pp);
+char_u *eval_to_string(char_u *arg, char_u **nextcmd, int convert);
+char_u *eval_to_string_safe(char_u *arg, char_u **nextcmd, int use_sandbox);
+varnumber_T eval_to_number(char_u *expr);
+list_T *eval_spell_expr(char_u *badword, char_u *expr);
+int get_spellword(list_T *list, char_u **pp);
+typval_T *eval_expr(char_u *arg, char_u **nextcmd);
+int call_vim_function(char_u *func, int argc, typval_T *argv, typval_T *rettv);
+varnumber_T call_func_retnr(char_u *func, int argc, typval_T *argv);
+void *call_func_retstr(char_u *func, int argc, typval_T *argv);
+void *call_func_retlist(char_u *func, int argc, typval_T *argv);
+int eval_foldexpr(char_u *arg, int *cp);
+void ex_let(exarg_T *eap);
+void list_hashtable_vars(hashtab_T *ht, char *prefix, int empty, int *first);
+char_u *get_lval(char_u *name, typval_T *rettv, lval_T *lp, int unlet, int skip, int flags, int fne_flags);
+void clear_lval(lval_T *lp);
+void *eval_for_line(char_u *arg, int *errp, char_u **nextcmdp, int skip);
+int next_for_item(void *fi_void, char_u *arg);
+void free_for_info(void *fi_void);
+void set_context_for_expression(expand_T *xp, char_u *arg, cmdidx_T cmdidx);
+void ex_unlet(exarg_T *eap);
+void ex_lockvar(exarg_T *eap);
+int do_unlet(char_u *name, int forceit);
+void del_menutrans_vars(void);
+char_u *get_user_var_name(expand_T *xp, int idx);
+int eval0(char_u *arg, typval_T *rettv, char_u **nextcmd, int evaluate);
+int eval1(char_u **arg, typval_T *rettv, int evaluate);
+int get_option_tv(char_u **arg, typval_T *rettv, int evaluate);
+char_u *partial_name(partial_T *pt);
+void partial_unref(partial_T *pt);
+int tv_equal(typval_T *tv1, typval_T *tv2, int ic, int recursive);
+int get_copyID(void);
+int garbage_collect(int testing);
+int set_ref_in_ht(hashtab_T *ht, int copyID, list_stack_T **list_stack);
+int set_ref_in_list(list_T *l, int copyID, ht_stack_T **ht_stack);
+int set_ref_in_item(typval_T *tv, int copyID, ht_stack_T **ht_stack, list_stack_T **list_stack);
+char_u *echo_string_core(typval_T *tv, char_u **tofree, char_u *numbuf, int copyID, int echo_style, int restore_copyID, int composite_val);
+char_u *echo_string(typval_T *tv, char_u **tofree, char_u *numbuf, int copyID);
+char_u *tv2string(typval_T *tv, char_u **tofree, char_u *numbuf, int copyID);
+char_u *string_quote(char_u *str, int function);
+int string2float(char_u *text, float_T *value);
+pos_T *var2fpos(typval_T *varp, int dollar_lnum, int *fnum);
+int list2fpos(typval_T *arg, pos_T *posp, int *fnump, colnr_T *curswantp);
+int get_id_len(char_u **arg);
+int get_name_len(char_u **arg, char_u **alias, int evaluate, int verbose);
+char_u *find_name_end(char_u *arg, char_u **expr_start, char_u **expr_end, int flags);
+int eval_isnamec(int c);
+int eval_isnamec1(int c);
+void set_vim_var_nr(int idx, varnumber_T val);
+varnumber_T get_vim_var_nr(int idx);
+char_u *get_vim_var_str(int idx);
+list_T *get_vim_var_list(int idx);
+dict_T *get_vim_var_dict(int idx);
+void set_vim_var_char(int c);
+void set_vcount(long count, long count1, int set_prevcount);
+void save_vimvars(vimvars_save_T *vvsave);
+void restore_vimvars(vimvars_save_T *vvsave);
+void set_vim_var_string(int idx, char_u *val, int len);
+void set_vim_var_list(int idx, list_T *val);
+void set_vim_var_dict(int idx, dict_T *val);
+void set_reg_var(int c);
+char_u *v_exception(char_u *oldval);
+char_u *v_throwpoint(char_u *oldval);
+char_u *set_cmdarg(exarg_T *eap, char_u *oldarg);
+int get_var_tv(char_u *name, int len, typval_T *rettv, dictitem_T **dip, int verbose, int no_autoload);
+int handle_subscript(char_u **arg, typval_T *rettv, int evaluate, int verbose);
+typval_T *alloc_tv(void);
+void free_tv(typval_T *varp);
+void clear_tv(typval_T *varp);
+void init_tv(typval_T *varp);
+varnumber_T tv_get_number(typval_T *varp);
+varnumber_T tv_get_number_chk(typval_T *varp, int *denote);
+float_T tv_get_float(typval_T *varp);
+char_u *tv_get_string(typval_T *varp);
+char_u *tv_get_string_buf(typval_T *varp, char_u *buf);
+char_u *tv_get_string_chk(typval_T *varp);
+char_u *tv_get_string_buf_chk(typval_T *varp, char_u *buf);
+char_u *tv_stringify(typval_T *varp, char_u *buf);
+dictitem_T *find_var(char_u *name, hashtab_T **htp, int no_autoload);
+dictitem_T *find_var_in_ht(hashtab_T *ht, int htname, char_u *varname, int no_autoload);
+hashtab_T *find_var_ht(char_u *name, char_u **varname);
+char_u *get_var_value(char_u *name);
+void new_script_vars(scid_T id);
+void init_var_dict(dict_T *dict, dictitem_T *dict_var, int scope);
+void unref_var_dict(dict_T *dict);
+void vars_clear(hashtab_T *ht);
+void vars_clear_ext(hashtab_T *ht, int free_val);
+void set_var(char_u *name, typval_T *tv, int copy);
+int var_check_ro(int flags, char_u *name, int use_gettext);
+int var_check_fixed(int flags, char_u *name, int use_gettext);
+int var_check_func_name(char_u *name, int new_var);
+int valid_varname(char_u *varname);
+int tv_check_lock(int lock, char_u *name, int use_gettext);
+void copy_tv(typval_T *from, typval_T *to);
+int item_copy(typval_T *from, typval_T *to, int deep, int copyID);
+void get_user_input(typval_T *argvars, typval_T *rettv, int inputdialog, int secret);
+void ex_echo(exarg_T *eap);
+void ex_echohl(exarg_T *eap);
+void ex_execute(exarg_T *eap);
+win_T *find_win_by_nr(typval_T *vp, tabpage_T *tp);
+win_T *find_win_by_nr_or_id(typval_T *vp);
+win_T *find_tabwin(typval_T *wvp, typval_T *tvp);
+void getwinvar(typval_T *argvars, typval_T *rettv, int off);
+void setwinvar(typval_T *argvars, typval_T *rettv, int off);
+char_u *autoload_name(char_u *name);
+int script_autoload(char_u *name, int reload);
+int read_viminfo_varlist(vir_T *virp, int writing);
+void write_viminfo_varlist(FILE *fp);
+int store_session_globals(FILE *fd);
+void last_set_msg(sctx_T script_ctx);
+void reset_v_option_vars(void);
+void prepare_assert_error(garray_T *gap);
+void assert_error(garray_T *gap);
+int assert_equal_common(typval_T *argvars, assert_type_T atype);
+int assert_equalfile(typval_T *argvars);
+int assert_match_common(typval_T *argvars, assert_type_T atype);
+int assert_inrange(typval_T *argvars);
+int assert_bool(typval_T *argvars, int isTrue);
+int assert_report(typval_T *argvars);
+int assert_exception(typval_T *argvars);
+int assert_beeps(typval_T *argvars);
+int assert_fails(typval_T *argvars);
+void fill_assert_error(garray_T *gap, typval_T *opt_msg_tv, char_u *exp_str, typval_T *exp_tv, typval_T *got_tv, assert_type_T atype);
+int typval_compare(typval_T *typ1, typval_T *typ2, exptype_T type, int type_is, int ic);
+char_u *typval_tostring(typval_T *arg);
+int var_exists(char_u *var);
+int modify_fname(char_u *src, int tilde_file, int *usedlen, char_u **fnamep, char_u **bufp, int *fnamelen);
+char_u *do_string_sub(char_u *str, char_u *pat, char_u *sub, typval_T *expr, char_u *flags);
+void filter_map(typval_T *argvars, typval_T *rettv, int map);
+/* vim: set ft=c : */
diff --git a/src/proto/evalfunc.pro b/src/proto/evalfunc.pro
new file mode 100644
index 0000000..c0ada9d
--- /dev/null
+++ b/src/proto/evalfunc.pro
@@ -0,0 +1,15 @@
+/* evalfunc.c */
+char_u *get_function_name(expand_T *xp, int idx);
+char_u *get_expr_name(expand_T *xp, int idx);
+int find_internal_func(char_u *name);
+int call_internal_func(char_u *name, int argcount, typval_T *argvars, typval_T *rettv);
+buf_T *buflist_find_by_name(char_u *name, int curtab_only);
+buf_T *tv_get_buf(typval_T *tv, int curtab_only);
+void execute_redir_str(char_u *value, int value_len);
+void mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv);
+float_T vim_round(float_T f);
+long do_searchpair(char_u *spat, char_u *mpat, char_u *epat, int dir, typval_T *skip, int flags, pos_T *match_pos, linenr_T lnum_stop, long time_limit);
+void f_string(typval_T *argvars, typval_T *rettv);
+char_u *get_callback(typval_T *arg, partial_T **pp);
+void free_callback(char_u *callback, partial_T *partial);
+/* vim: set ft=c : */
diff --git a/src/proto/ex_cmds.pro b/src/proto/ex_cmds.pro
new file mode 100644
index 0000000..c769b4b
--- /dev/null
+++ b/src/proto/ex_cmds.pro
@@ -0,0 +1,61 @@
+/* ex_cmds.c */
+void do_ascii(exarg_T *eap);
+void ex_align(exarg_T *eap);
+void ex_sort(exarg_T *eap);
+void ex_retab(exarg_T *eap);
+int do_move(linenr_T line1, linenr_T line2, linenr_T dest);
+void ex_copy(linenr_T line1, linenr_T line2, linenr_T n);
+void free_prev_shellcmd(void);
+void do_bang(int addr_count, exarg_T *eap, int forceit, int do_in, int do_out);
+void do_shell(char_u *cmd, int flags);
+char_u *make_filter_cmd(char_u *cmd, char_u *itmp, char_u *otmp);
+void append_redir(char_u *buf, int buflen, char_u *opt, char_u *fname);
+int viminfo_error(char *errnum, char *message, char_u *line);
+int read_viminfo(char_u *file, int flags);
+void write_viminfo(char_u *file, int forceit);
+int viminfo_readline(vir_T *virp);
+char_u *viminfo_readstring(vir_T *virp, int off, int convert);
+void viminfo_writestring(FILE *fd, char_u *p);
+int barline_writestring(FILE *fd, char_u *s, int remaining_start);
+time_T vim_time(void);
+void do_fixdel(exarg_T *eap);
+void print_line_no_prefix(linenr_T lnum, int use_number, int list);
+void print_line(linenr_T lnum, int use_number, int list);
+int rename_buffer(char_u *new_fname);
+void ex_file(exarg_T *eap);
+void ex_update(exarg_T *eap);
+void ex_write(exarg_T *eap);
+int do_write(exarg_T *eap);
+int check_overwrite(exarg_T *eap, buf_T *buf, char_u *fname, char_u *ffname, int other);
+void ex_wnext(exarg_T *eap);
+void do_wqall(exarg_T *eap);
+int not_writing(void);
+int getfile(int fnum, char_u *ffname_arg, char_u *sfname_arg, int setpm, linenr_T lnum, int forceit);
+int do_ecmd(int fnum, char_u *ffname, char_u *sfname, exarg_T *eap, linenr_T newlnum, int flags, win_T *oldwin);
+void ex_append(exarg_T *eap);
+void ex_change(exarg_T *eap);
+void ex_z(exarg_T *eap);
+int check_restricted(void);
+int check_secure(void);
+void do_sub(exarg_T *eap);
+int do_sub_msg(int count_only);
+void ex_global(exarg_T *eap);
+void global_exe(char_u *cmd);
+int read_viminfo_sub_string(vir_T *virp, int force);
+void write_viminfo_sub_string(FILE *fp);
+void free_old_sub(void);
+int prepare_tagpreview(int undo_sync);
+void ex_help(exarg_T *eap);
+void ex_helpclose(exarg_T *eap);
+char_u *check_help_lang(char_u *arg);
+int help_heuristic(char_u *matched_string, int offset, int wrong_case);
+int find_help_tags(char_u *arg, int *num_matches, char_u ***matches, int keep_lang);
+void fix_help_buffer(void);
+void ex_exusage(exarg_T *eap);
+void ex_viusage(exarg_T *eap);
+void ex_helptags(exarg_T *eap);
+void ex_smile(exarg_T *eap);
+void ex_drop(exarg_T *eap);
+char_u *skip_vimgrep_pat(char_u *p, char_u **s, int *flags);
+void ex_oldfiles(exarg_T *eap);
+/* vim: set ft=c : */
diff --git a/src/proto/ex_cmds2.pro b/src/proto/ex_cmds2.pro
new file mode 100644
index 0000000..ac9b291
--- /dev/null
+++ b/src/proto/ex_cmds2.pro
@@ -0,0 +1,112 @@
+/* ex_cmds2.c */
+int has_watchexpr(void);
+void do_debug(char_u *cmd);
+void ex_debug(exarg_T *eap);
+void dbg_check_breakpoint(exarg_T *eap);
+int dbg_check_skipped(exarg_T *eap);
+void ex_breakadd(exarg_T *eap);
+void ex_debuggreedy(exarg_T *eap);
+void ex_breakdel(exarg_T *eap);
+void ex_breaklist(exarg_T *eap);
+linenr_T dbg_find_breakpoint(int file, char_u *fname, linenr_T after);
+int has_profiling(int file, char_u *fname, int *fp);
+void dbg_breakpoint(char_u *name, linenr_T lnum);
+void profile_start(proftime_T *tm);
+void profile_end(proftime_T *tm);
+void profile_sub(proftime_T *tm, proftime_T *tm2);
+char *profile_msg(proftime_T *tm);
+float_T profile_float(proftime_T *tm);
+void profile_setlimit(long msec, proftime_T *tm);
+int profile_passed_limit(proftime_T *tm);
+void profile_zero(proftime_T *tm);
+long proftime_time_left(proftime_T *due, proftime_T *now);
+timer_T *create_timer(long msec, int repeat);
+long check_due_timer(void);
+timer_T *find_timer(long id);
+void stop_timer(timer_T *timer);
+void stop_all_timers(void);
+void add_timer_info(typval_T *rettv, timer_T *timer);
+void add_timer_info_all(typval_T *rettv);
+int set_ref_in_timer(int copyID);
+void timer_free_all(void);
+void profile_divide(proftime_T *tm, int count, proftime_T *tm2);
+void profile_add(proftime_T *tm, proftime_T *tm2);
+void profile_self(proftime_T *self, proftime_T *total, proftime_T *children);
+void profile_get_wait(proftime_T *tm);
+void profile_sub_wait(proftime_T *tm, proftime_T *tma);
+int profile_equal(proftime_T *tm1, proftime_T *tm2);
+int profile_cmp(const proftime_T *tm1, const proftime_T *tm2);
+void ex_profile(exarg_T *eap);
+char_u *get_profile_name(expand_T *xp, int idx);
+void set_context_in_profile_cmd(expand_T *xp, char_u *arg);
+void profile_dump(void);
+void script_prof_save(proftime_T *tm);
+void script_prof_restore(proftime_T *tm);
+void prof_inchar_enter(void);
+void prof_inchar_exit(void);
+int prof_def_func(void);
+int autowrite(buf_T *buf, int forceit);
+void autowrite_all(void);
+int check_changed(buf_T *buf, int flags);
+void browse_save_fname(buf_T *buf);
+void dialog_changed(buf_T *buf, int checkall);
+int can_abandon(buf_T *buf, int forceit);
+int check_changed_any(int hidden, int unload);
+int check_fname(void);
+int buf_write_all(buf_T *buf, int forceit);
+int get_arglist_exp(char_u *str, int *fcountp, char_u ***fnamesp, int wig);
+void set_arglist(char_u *str);
+void check_arg_idx(win_T *win);
+void ex_args(exarg_T *eap);
+void ex_previous(exarg_T *eap);
+void ex_rewind(exarg_T *eap);
+void ex_last(exarg_T *eap);
+void ex_argument(exarg_T *eap);
+void do_argfile(exarg_T *eap, int argn);
+void ex_next(exarg_T *eap);
+void ex_argedit(exarg_T *eap);
+void ex_argadd(exarg_T *eap);
+void ex_argdelete(exarg_T *eap);
+void ex_listdo(exarg_T *eap);
+char_u *get_arglist_name(expand_T *xp, int idx);
+void ex_compiler(exarg_T *eap);
+void ex_runtime(exarg_T *eap);
+int do_in_path(char_u *path, char_u *name, int flags, void (*callback)(char_u *fname, void *ck), void *cookie);
+int do_in_runtimepath(char_u *name, int flags, void (*callback)(char_u *fname, void *ck), void *cookie);
+int source_runtime(char_u *name, int flags);
+int source_in_path(char_u *path, char_u *name, int flags);
+void add_pack_start_dirs(void);
+void load_start_packages(void);
+void ex_packloadall(exarg_T *eap);
+void ex_packadd(exarg_T *eap);
+void ex_options(exarg_T *eap);
+void init_pyxversion(void);
+void ex_pyxfile(exarg_T *eap);
+void ex_pyx(exarg_T *eap);
+void ex_pyxdo(exarg_T *eap);
+void ex_source(exarg_T *eap);
+linenr_T *source_breakpoint(void *cookie);
+int *source_dbg_tick(void *cookie);
+int source_level(void *cookie);
+int do_source(char_u *fname, int check_other, int is_vimrc);
+void ex_scriptnames(exarg_T *eap);
+void scriptnames_slash_adjust(void);
+char_u *get_scriptname(scid_T id);
+void free_scriptnames(void);
+char *fgets_cr(char *s, int n, FILE *stream);
+char_u *getsourceline(int c, void *cookie, int indent);
+void script_line_start(void);
+void script_line_exec(void);
+void script_line_end(void);
+void ex_scriptencoding(exarg_T *eap);
+void ex_finish(exarg_T *eap);
+void do_finish(exarg_T *eap, int reanimate);
+int source_finished(char_u *(*fgetline)(int, void *, int), void *cookie);
+void ex_checktime(exarg_T *eap);
+char_u *get_mess_lang(void);
+void set_lang_var(void);
+void ex_language(exarg_T *eap);
+void free_locales(void);
+char_u *get_lang_arg(expand_T *xp, int idx);
+char_u *get_locales(expand_T *xp, int idx);
+/* vim: set ft=c : */
diff --git a/src/proto/ex_docmd.pro b/src/proto/ex_docmd.pro
new file mode 100644
index 0000000..8f3852a
--- /dev/null
+++ b/src/proto/ex_docmd.pro
@@ -0,0 +1,76 @@
+/* ex_docmd.c */
+void do_exmode(int improved);
+int do_cmdline_cmd(char_u *cmd);
+int do_cmdline(char_u *cmdline, char_u *(*fgetline)(int, void *, int), void *cookie, int flags);
+int getline_equal(char_u *(*fgetline)(int, void *, int), void *cookie, char_u *(*func)(int, void *, int));
+void *getline_cookie(char_u *(*fgetline)(int, void *, int), void *cookie);
+int parse_command_modifiers(exarg_T *eap, char **errormsg, int skip_only);
+int parse_cmd_address(exarg_T *eap, char **errormsg, int silent);
+int checkforcmd(char_u **pp, char *cmd, int len);
+int modifier_len(char_u *cmd);
+int cmd_exists(char_u *name);
+char_u *set_one_cmd_context(expand_T *xp, char_u *buff);
+char_u *skip_range(char_u *cmd, int *ctx);
+void ex_ni(exarg_T *eap);
+int expand_filename(exarg_T *eap, char_u **cmdlinep, char **errormsgp);
+void separate_nextcmd(exarg_T *eap);
+int get_bad_opt(char_u *p, exarg_T *eap);
+int ends_excmd(int c);
+char_u *find_nextcmd(char_u *p);
+char_u *check_nextcmd(char_u *p);
+char_u *get_command_name(expand_T *xp, int idx);
+void ex_comclear(exarg_T *eap);
+void uc_clear(garray_T *gap);
+char_u *get_user_commands(expand_T *xp, int idx);
+char_u *get_user_cmd_addr_type(expand_T *xp, int idx);
+char_u *get_user_cmd_flags(expand_T *xp, int idx);
+char_u *get_user_cmd_nargs(expand_T *xp, int idx);
+char_u *get_user_cmd_complete(expand_T *xp, int idx);
+int parse_addr_type_arg(char_u *value, int vallen, long *argt, int *addr_type_arg);
+int parse_compl_arg(char_u *value, int vallen, int *complp, long *argt, char_u **compl_arg);
+int cmdcomplete_str_to_type(char_u *complete_str);
+void not_exiting(void);
+void tabpage_close(int forceit);
+void tabpage_close_other(tabpage_T *tp, int forceit);
+void ex_all(exarg_T *eap);
+void handle_drop(int filec, char_u **filev, int split, void (*callback)(void *), void *cookie);
+void handle_any_postponed_drop(void);
+void alist_clear(alist_T *al);
+void alist_init(alist_T *al);
+void alist_unlink(alist_T *al);
+void alist_new(void);
+void alist_expand(int *fnum_list, int fnum_len);
+void alist_set(alist_T *al, int count, char_u **files, int use_curbuf, int *fnum_list, int fnum_len);
+void alist_add(alist_T *al, char_u *fname, int set_fnum);
+void alist_slash_adjust(void);
+void ex_splitview(exarg_T *eap);
+void tabpage_new(void);
+void do_exedit(exarg_T *eap, win_T *old_curwin);
+void free_cd_dir(void);
+void post_chdir(int local);
+void ex_cd(exarg_T *eap);
+void do_sleep(long msec);
+void ex_may_print(exarg_T *eap);
+void ex_redraw(exarg_T *eap);
+int vim_mkdir_emsg(char_u *name, int prot);
+FILE *open_exfile(char_u *fname, int forceit, char *mode);
+void update_topline_cursor(void);
+int save_current_state(save_state_T *sst);
+void restore_current_state(save_state_T *sst);
+void ex_normal(exarg_T *eap);
+void exec_normal_cmd(char_u *cmd, int remap, int silent);
+void exec_normal(int was_typed, int use_vpeekc, int may_use_terminal_loop);
+int find_cmdline_var(char_u *src, int *usedlen);
+char_u *eval_vars(char_u *src, char_u *srcstart, int *usedlen, linenr_T *lnump, char **errormsg, int *escaped);
+char_u *expand_sfile(char_u *arg);
+int put_eol(FILE *fd);
+int put_line(FILE *fd, char *s);
+void dialog_msg(char_u *buff, char *format, char_u *fname);
+char_u *get_behave_arg(expand_T *xp, int idx);
+char_u *get_messages_arg(expand_T *xp, int idx);
+char_u *get_mapclear_arg(expand_T *xp, int idx);
+void set_no_hlsearch(int flag);
+int is_loclist_cmd(int cmdidx);
+int get_pressedreturn(void);
+void set_pressedreturn(int val);
+/* vim: set ft=c : */
diff --git a/src/proto/ex_eval.pro b/src/proto/ex_eval.pro
new file mode 100644
index 0000000..34301e2
--- /dev/null
+++ b/src/proto/ex_eval.pro
@@ -0,0 +1,34 @@
+/* ex_eval.c */
+int aborting(void);
+void update_force_abort(void);
+int should_abort(int retcode);
+int aborted_in_try(void);
+int cause_errthrow(char_u *mesg, int severe, int *ignore);
+void free_global_msglist(void);
+void do_errthrow(struct condstack *cstack, char_u *cmdname);
+int do_intthrow(struct condstack *cstack);
+char *get_exception_string(void *value, except_type_T type, char_u *cmdname, int *should_free);
+void discard_current_exception(void);
+void report_make_pending(int pending, void *value);
+void report_resume_pending(int pending, void *value);
+void report_discard_pending(int pending, void *value);
+void ex_if(exarg_T *eap);
+void ex_endif(exarg_T *eap);
+void ex_else(exarg_T *eap);
+void ex_while(exarg_T *eap);
+void ex_continue(exarg_T *eap);
+void ex_break(exarg_T *eap);
+void ex_endwhile(exarg_T *eap);
+void ex_throw(exarg_T *eap);
+void do_throw(struct condstack *cstack);
+void ex_try(exarg_T *eap);
+void ex_catch(exarg_T *eap);
+void ex_finally(exarg_T *eap);
+void ex_endtry(exarg_T *eap);
+void enter_cleanup(cleanup_T *csp);
+void leave_cleanup(cleanup_T *csp);
+int cleanup_conditionals(struct condstack *cstack, int searched_cond, int inclusive);
+void rewind_conditionals(struct condstack *cstack, int idx, int cond_type, int *cond_level);
+void ex_endfunction(exarg_T *eap);
+int has_loop_cmd(char_u *p);
+/* vim: set ft=c : */
diff --git a/src/proto/ex_getln.pro b/src/proto/ex_getln.pro
new file mode 100644
index 0000000..298c630
--- /dev/null
+++ b/src/proto/ex_getln.pro
@@ -0,0 +1,60 @@
+/* ex_getln.c */
+void cmdline_init(void);
+char_u *getcmdline(int firstc, long count, int indent);
+char_u *getcmdline_prompt(int firstc, char_u *prompt, int attr, int xp_context, char_u *xp_arg);
+int text_locked(void);
+void text_locked_msg(void);
+char *get_text_locked_msg(void);
+int curbuf_locked(void);
+int allbuf_locked(void);
+char_u *getexline(int c, void *cookie, int indent);
+char_u *getexmodeline(int promptc, void *cookie, int indent);
+int cmdline_overstrike(void);
+int cmdline_at_end(void);
+colnr_T cmdline_getvcol_cursor(void);
+void free_cmdline_buf(void);
+void putcmdline(int c, int shift);
+void unputcmdline(void);
+int put_on_cmdline(char_u *str, int len, int redraw);
+void cmdline_paste_str(char_u *s, int literally);
+void redrawcmdline(void);
+void redrawcmdline_ex(int do_compute_cmdrow);
+void redrawcmd(void);
+void compute_cmdrow(void);
+void gotocmdline(int clr);
+char_u *ExpandOne(expand_T *xp, char_u *str, char_u *orig, int options, int mode);
+void ExpandInit(expand_T *xp);
+void ExpandCleanup(expand_T *xp);
+void ExpandEscape(expand_T *xp, char_u *str, int numfiles, char_u **files, int options);
+char_u *vim_strsave_fnameescape(char_u *fname, int shell);
+void tilde_replace(char_u *orig_pat, int num_files, char_u **files);
+char_u *sm_gettail(char_u *s);
+char_u *addstar(char_u *fname, int len, int context);
+void set_cmd_context(expand_T *xp, char_u *str, int len, int col, int use_ccline);
+int expand_cmdline(expand_T *xp, char_u *str, int col, int *matchcount, char_u ***matches);
+int ExpandGeneric(expand_T *xp, regmatch_T *regmatch, int *num_file, char_u ***file, char_u *((*func)(expand_T *, int)), int escaped);
+void globpath(char_u *path, char_u *file, garray_T *ga, int expand_options);
+void init_history(void);
+int get_histtype(char_u *name);
+void add_to_history(int histype, char_u *new_entry, int in_map, int sep);
+int get_history_idx(int histype);
+char_u *get_history_entry(int histype, int idx);
+int clr_history(int histype);
+int del_history_entry(int histype, char_u *str);
+int del_history_idx(int histype, int idx);
+void remove_key_from_history(void);
+char_u *get_cmdline_str(void);
+int get_cmdline_pos(void);
+int set_cmdline_pos(int pos);
+int get_cmdline_type(void);
+int get_list_range(char_u **str, int *num1, int *num2);
+void ex_history(exarg_T *eap);
+void prepare_viminfo_history(int asklen, int writing);
+int read_viminfo_history(vir_T *virp, int writing);
+void handle_viminfo_history(garray_T *values, int writing);
+void finish_viminfo_history(vir_T *virp);
+void write_viminfo_history(FILE *fp, int merge);
+void cmd_pchar(int c, int offset);
+int cmd_gchar(int offset);
+char_u *script_get(exarg_T *eap, char_u *cmd);
+/* vim: set ft=c : */
diff --git a/src/proto/farsi.pro b/src/proto/farsi.pro
new file mode 100644
index 0000000..b6e1836
--- /dev/null
+++ b/src/proto/farsi.pro
@@ -0,0 +1,12 @@
+/* farsi.c */
+int fkmap(int c);
+char_u *lrswap(char_u *ibuf);
+char_u *lrFswap(char_u *cmdbuf, int len);
+char_u *lrF_sub(char_u *ibuf);
+int cmdl_fkmap(int c);
+int F_isalpha(int c);
+int F_isdigit(int c);
+int F_ischar(int c);
+void farsi_f8(cmdarg_T *cap);
+void farsi_f9(cmdarg_T *cap);
+/* vim: set ft=c : */
diff --git a/src/proto/fileio.pro b/src/proto/fileio.pro
new file mode 100644
index 0000000..21ac55c
--- /dev/null
+++ b/src/proto/fileio.pro
@@ -0,0 +1,36 @@
+/* fileio.c */
+void filemess(buf_T *buf, char_u *name, char_u *s, int attr);
+int readfile(char_u *fname, char_u *sfname, linenr_T from, linenr_T lines_to_skip, linenr_T lines_to_read, exarg_T *eap, int flags);
+int is_dev_fd_file(char_u *fname);
+int prep_exarg(exarg_T *eap, buf_T *buf);
+void set_file_options(int set_options, exarg_T *eap);
+void set_forced_fenc(exarg_T *eap);
+int check_file_readonly(char_u *fname, int perm);
+int buf_write(buf_T *buf, char_u *fname, char_u *sfname, linenr_T start, linenr_T end, exarg_T *eap, int append, int forceit, int reset_changed, int filtering);
+void msg_add_fname(buf_T *buf, char_u *fname);
+void msg_add_lines(int insert_space, long lnum, off_T nchars);
+char_u *shorten_fname1(char_u *full_path);
+char_u *shorten_fname(char_u *full_path, char_u *dir_name);
+void shorten_buf_fname(buf_T *buf, char_u *dirname, int force);
+void shorten_fnames(int force);
+void shorten_filenames(char_u **fnames, int count);
+char_u *modname(char_u *fname, char_u *ext, int prepend_dot);
+char_u *buf_modname(int shortname, char_u *fname, char_u *ext, int prepend_dot);
+int vim_fgets(char_u *buf, int size, FILE *fp);
+int tag_fgets(char_u *buf, int size, FILE *fp);
+int vim_rename(char_u *from, char_u *to);
+int check_timestamps(int focus);
+int buf_check_timestamp(buf_T *buf, int focus);
+void buf_reload(buf_T *buf, int orig_mode);
+void buf_store_time(buf_T *buf, stat_T *st, char_u *fname);
+void write_lnum_adjust(linenr_T offset);
+int delete_recursive(char_u *name);
+void vim_deltempdir(void);
+char_u *vim_tempname(int extra_char, int keep);
+void forward_slash(char_u *fname);
+int match_file_pat(char_u *pattern, regprog_T **prog, char_u *fname, char_u *sfname, char_u *tail, int allow_dirs);
+int match_file_list(char_u *list, char_u *sfname, char_u *ffname);
+char_u *file_pat_to_reg_pat(char_u *pat, char_u *pat_end, char *allow_dirs, int no_bslash);
+long read_eintr(int fd, void *buf, size_t bufsize);
+long write_eintr(int fd, void *buf, size_t bufsize);
+/* vim: set ft=c : */
diff --git a/src/proto/fold.pro b/src/proto/fold.pro
new file mode 100644
index 0000000..d8e3494
--- /dev/null
+++ b/src/proto/fold.pro
@@ -0,0 +1,42 @@
+/* fold.c */
+void copyFoldingState(win_T *wp_from, win_T *wp_to);
+int hasAnyFolding(win_T *win);
+int hasFolding(linenr_T lnum, linenr_T *firstp, linenr_T *lastp);
+int hasFoldingWin(win_T *win, linenr_T lnum, linenr_T *firstp, linenr_T *lastp, int cache, foldinfo_T *infop);
+int foldLevel(linenr_T lnum);
+int lineFolded(win_T *win, linenr_T lnum);
+long foldedCount(win_T *win, linenr_T lnum, foldinfo_T *infop);
+int foldmethodIsManual(win_T *wp);
+int foldmethodIsIndent(win_T *wp);
+int foldmethodIsExpr(win_T *wp);
+int foldmethodIsMarker(win_T *wp);
+int foldmethodIsSyntax(win_T *wp);
+int foldmethodIsDiff(win_T *wp);
+void closeFold(linenr_T lnum, long count);
+void closeFoldRecurse(linenr_T lnum);
+void opFoldRange(linenr_T first, linenr_T last, int opening, int recurse, int had_visual);
+void openFold(linenr_T lnum, long count);
+void openFoldRecurse(linenr_T lnum);
+void foldOpenCursor(void);
+void newFoldLevel(void);
+void foldCheckClose(void);
+int foldManualAllowed(int create);
+void foldCreate(linenr_T start, linenr_T end);
+void deleteFold(linenr_T start, linenr_T end, int recursive, int had_visual);
+void clearFolding(win_T *win);
+void foldUpdate(win_T *wp, linenr_T top, linenr_T bot);
+void foldUpdateAll(win_T *win);
+int foldMoveTo(int updown, int dir, long count);
+void foldInitWin(win_T *new_win);
+int find_wl_entry(win_T *win, linenr_T lnum);
+void foldAdjustVisual(void);
+void foldAdjustCursor(void);
+void cloneFoldGrowArray(garray_T *from, garray_T *to);
+void deleteFoldRecurse(garray_T *gap);
+void foldMarkAdjust(win_T *wp, linenr_T line1, linenr_T line2, long amount, long amount_after);
+int getDeepestNesting(void);
+char_u *get_foldtext(win_T *wp, linenr_T lnum, linenr_T lnume, foldinfo_T *foldinfo, char_u *buf);
+void foldtext_cleanup(char_u *str);
+void foldMoveRange(garray_T *gap, linenr_T line1, linenr_T line2, linenr_T dest);
+int put_folds(FILE *fd, win_T *wp);
+/* vim: set ft=c : */
diff --git a/src/proto/getchar.pro b/src/proto/getchar.pro
new file mode 100644
index 0000000..0733662
--- /dev/null
+++ b/src/proto/getchar.pro
@@ -0,0 +1,70 @@
+/* getchar.c */
+void free_buff(buffheader_T *buf);
+char_u *get_recorded(void);
+char_u *get_inserted(void);
+int stuff_empty(void);
+int readbuf1_empty(void);
+void typeahead_noflush(int c);
+void flush_buffers(flush_buffers_T flush_typeahead);
+void ResetRedobuff(void);
+void CancelRedo(void);
+void saveRedobuff(save_redo_T *save_redo);
+void restoreRedobuff(save_redo_T *save_redo);
+void AppendToRedobuff(char_u *s);
+void AppendToRedobuffLit(char_u *str, int len);
+void AppendCharToRedobuff(int c);
+void AppendNumberToRedobuff(long n);
+void stuffReadbuff(char_u *s);
+void stuffRedoReadbuff(char_u *s);
+void stuffReadbuffLen(char_u *s, long len);
+void stuffReadbuffSpec(char_u *s);
+void stuffcharReadbuff(int c);
+void stuffnumReadbuff(long n);
+int start_redo(long count, int old_redo);
+int start_redo_ins(void);
+void stop_redo_ins(void);
+int ins_typebuf(char_u *str, int noremap, int offset, int nottyped, int silent);
+void ins_char_typebuf(int c);
+int typebuf_changed(int tb_change_cnt);
+int typebuf_typed(void);
+int typebuf_maplen(void);
+void del_typebuf(int len, int offset);
+int alloc_typebuf(void);
+void free_typebuf(void);
+int save_typebuf(void);
+void save_typeahead(tasave_T *tp);
+void restore_typeahead(tasave_T *tp);
+void openscript(char_u *name, int directly);
+void close_all_scripts(void);
+int using_script(void);
+void before_blocking(void);
+void updatescript(int c);
+int vgetc(void);
+int safe_vgetc(void);
+int plain_vgetc(void);
+int vpeekc(void);
+int vpeekc_nomap(void);
+int vpeekc_any(void);
+int char_avail(void);
+void vungetc(int c);
+int fix_input_buffer(char_u *buf, int len);
+int input_available(void);
+int do_map(int maptype, char_u *arg, int mode, int abbrev);
+int get_map_mode(char_u **cmdp, int forceit);
+void map_clear(char_u *cmdp, char_u *arg, int forceit, int abbr);
+void map_clear_int(buf_T *buf, int mode, int local, int abbr);
+char_u *map_mode_to_chars(int mode);
+int map_to_exists(char_u *str, char_u *modechars, int abbr);
+int map_to_exists_mode(char_u *rhs, int mode, int abbr);
+char_u *set_context_in_map_cmd(expand_T *xp, char_u *cmd, char_u *arg, int forceit, int isabbrev, int isunmap, cmdidx_T cmdidx);
+int ExpandMappings(regmatch_T *regmatch, int *num_file, char_u ***file);
+int check_abbr(int c, char_u *ptr, int col, int mincol);
+char_u *vim_strsave_escape_csi(char_u *p);
+void vim_unescape_csi(char_u *p);
+int makemap(FILE *fd, buf_T *buf);
+int put_escstr(FILE *fd, char_u *strstart, int what);
+void check_map_keycodes(void);
+char_u *check_map(char_u *keys, int mode, int exact, int ign_mod, int abbr, mapblock_T **mp_ptr, int *local_ptr);
+void init_mappings(void);
+void add_map(char_u *map, int mode);
+/* vim: set ft=c : */
diff --git a/src/proto/gui.pro b/src/proto/gui.pro
new file mode 100644
index 0000000..4004bc7
--- /dev/null
+++ b/src/proto/gui.pro
@@ -0,0 +1,70 @@
+/* gui.c */
+void gui_start(void);
+void gui_prepare(int *argc, char **argv);
+int gui_init_check(void);
+void gui_init(void);
+void gui_exit(int rc);
+void gui_shell_closed(void);
+int gui_init_font(char_u *font_list, int fontset);
+int gui_get_wide_font(void);
+void gui_set_cursor(int row, int col);
+void gui_update_cursor(int force, int clear_selection);
+void gui_position_menu(void);
+int gui_get_base_width(void);
+int gui_get_base_height(void);
+void gui_resize_shell(int pixel_width, int pixel_height);
+void gui_may_resize_shell(void);
+int gui_get_shellsize(void);
+void gui_set_shellsize(int mustset, int fit_to_display, int direction);
+void gui_new_shellsize(void);
+void gui_reset_scroll_region(void);
+void gui_start_highlight(int mask);
+void gui_stop_highlight(int mask);
+void gui_clear_block(int row1, int col1, int row2, int col2);
+void gui_update_cursor_later(void);
+void gui_write(char_u *s, int len);
+void gui_dont_update_cursor(int undraw);
+void gui_can_update_cursor(void);
+void gui_disable_flush(void);
+void gui_enable_flush(void);
+void gui_may_flush(void);
+int gui_outstr_nowrap(char_u *s, int len, int flags, guicolor_T fg, guicolor_T bg, int back);
+void gui_undraw_cursor(void);
+void gui_redraw(int x, int y, int w, int h);
+int gui_redraw_block(int row1, int col1, int row2, int col2, int flags);
+int gui_wait_for_chars(long wtime, int tb_change_cnt);
+int gui_inchar(char_u *buf, int maxlen, long wtime, int tb_change_cnt);
+void gui_send_mouse_event(int button, int x, int y, int repeated_click, int_u modifiers);
+int gui_xy2colrow(int x, int y, int *colp);
+void gui_menu_cb(vimmenu_T *menu);
+void gui_init_which_components(char_u *oldval);
+int gui_use_tabline(void);
+void gui_update_tabline(void);
+void get_tabline_label(tabpage_T *tp, int tooltip);
+int send_tabline_event(int nr);
+void send_tabline_menu_event(int tabidx, int event);
+void gui_remove_scrollbars(void);
+void gui_create_scrollbar(scrollbar_T *sb, int type, win_T *wp);
+scrollbar_T *gui_find_scrollbar(long ident);
+void gui_drag_scrollbar(scrollbar_T *sb, long value, int still_dragging);
+void gui_may_update_scrollbars(void);
+void gui_update_scrollbars(int force);
+int gui_do_scroll(void);
+int gui_do_horiz_scroll(long_u leftcol, int compute_longest_lnum);
+void gui_check_colors(void);
+guicolor_T gui_get_color(char_u *name);
+int gui_get_lightness(guicolor_T pixel);
+void gui_new_scrollbar_colors(void);
+void gui_focus_change(int in_focus);
+void gui_mouse_moved(int x, int y);
+void gui_mouse_correct(void);
+void ex_gui(exarg_T *eap);
+int gui_find_bitmap(char_u *name, char_u *buffer, char *ext);
+void gui_find_iconfile(char_u *name, char_u *buffer, char *ext);
+void display_errors(void);
+int no_console_input(void);
+void gui_update_screen(void);
+char_u *get_find_dialog_text(char_u *arg, int *wwordp, int *mcasep);
+int gui_do_findrepl(int flags, char_u *find_text, char_u *repl_text, int down);
+void gui_handle_drop(int x, int y, int_u modifiers, char_u **fnames, int count);
+/* vim: set ft=c : */
diff --git a/src/proto/gui_athena.pro b/src/proto/gui_athena.pro
new file mode 100644
index 0000000..a834dac
--- /dev/null
+++ b/src/proto/gui_athena.pro
@@ -0,0 +1,31 @@
+/* gui_athena.c */
+void gui_x11_create_widgets(void);
+void gui_x11_destroy_widgets(void);
+void gui_mch_set_toolbar_pos(int x, int y, int w, int h);
+void gui_mch_set_text_area_pos(int x, int y, int w, int h);
+void gui_x11_set_back_color(void);
+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, int idx);
+void gui_mch_new_menu_font(void);
+void gui_mch_new_tooltip_font(void);
+void gui_mch_new_tooltip_colors(void);
+void gui_mch_add_menu_item(vimmenu_T *menu, int idx);
+void gui_mch_show_toolbar(int showit);
+int gui_mch_compute_toolbar_height(void);
+void gui_mch_get_toolbar_colors(Pixel *bgp, Pixel *fgp, Pixel *bsp, Pixel *tsp, Pixel *hsp);
+void gui_mch_toggle_tearoffs(int enable);
+void gui_mch_new_menu_colors(void);
+void gui_mch_destroy_menu(vimmenu_T *menu);
+void gui_mch_show_popupmenu(vimmenu_T *menu);
+void gui_mch_def_colors(void);
+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);
+void gui_mch_enable_scrollbar(scrollbar_T *sb, int flag);
+void gui_mch_create_scrollbar(scrollbar_T *sb, int orient);
+void gui_mch_destroy_scrollbar(scrollbar_T *sb);
+void gui_mch_set_scrollbar_colors(scrollbar_T *sb);
+Window gui_x11_get_wid(void);
+char_u *gui_mch_browse(int saving, char_u *title, char_u *dflt, char_u *ext, char_u *initdir, char_u *filter);
+int gui_mch_dialog(int type, char_u *title, char_u *message, char_u *buttons, int dfltbutton, char_u *textfield, int ex_cmd);
+/* vim: set ft=c : */
diff --git a/src/proto/gui_beval.pro b/src/proto/gui_beval.pro
new file mode 100644
index 0000000..4edb45c
--- /dev/null
+++ b/src/proto/gui_beval.pro
@@ -0,0 +1,9 @@
+/* gui_beval.c */
+BalloonEval *gui_mch_create_beval_area(void *target, char_u *mesg, void (*mesgCB)(BalloonEval *, int), void *clientData);
+void gui_mch_destroy_beval_area(BalloonEval *beval);
+void gui_mch_enable_beval_area(BalloonEval *beval);
+void gui_mch_disable_beval_area(BalloonEval *beval);
+BalloonEval *gui_mch_currently_showing_beval(void);
+void gui_mch_post_balloon(BalloonEval *beval, char_u *mesg);
+void gui_mch_unpost_balloon(BalloonEval *beval);
+/* vim: set ft=c : */
diff --git a/src/proto/gui_gtk.pro b/src/proto/gui_gtk.pro
new file mode 100644
index 0000000..319e27d
--- /dev/null
+++ b/src/proto/gui_gtk.pro
@@ -0,0 +1,22 @@
+/* gui_gtk.c */
+void gui_gtk_register_stock_icons(void);
+void gui_mch_add_menu(vimmenu_T *menu, int idx);
+void gui_mch_add_menu_item(vimmenu_T *menu, int idx);
+void gui_mch_set_text_area_pos(int x, int y, int w, int h);
+void gui_gtk_set_mnemonics(int enable);
+void gui_mch_toggle_tearoffs(int enable);
+void gui_mch_menu_set_tip(vimmenu_T *menu);
+void gui_mch_destroy_menu(vimmenu_T *menu);
+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);
+void gui_mch_create_scrollbar(scrollbar_T *sb, int orient);
+void gui_mch_destroy_scrollbar(scrollbar_T *sb);
+char_u *gui_mch_browse(int saving, char_u *title, char_u *dflt, char_u *ext, char_u *initdir, char_u *filter);
+char_u *gui_mch_browsedir(char_u *title, char_u *initdir);
+int gui_mch_dialog(int type, char_u *title, char_u *message, char_u *buttons, int def_but, char_u *textfield, int ex_cmd);
+void gui_mch_show_popupmenu(vimmenu_T *menu);
+void gui_make_popup(char_u *path_name, int mouse_pos);
+void gui_mch_find_dialog(exarg_T *eap);
+void gui_mch_replace_dialog(exarg_T *eap);
+void ex_helpfind(exarg_T *eap);
+/* vim: set ft=c : */
diff --git a/src/proto/gui_gtk_gresources.pro b/src/proto/gui_gtk_gresources.pro
new file mode 100644
index 0000000..c09c793
--- /dev/null
+++ b/src/proto/gui_gtk_gresources.pro
@@ -0,0 +1,5 @@
+/* auto/gui_gtk_gresources.c */
+GResource *gui_gtk_get_resource(void);
+void gui_gtk_unregister_resource(void);
+void gui_gtk_register_resource(void);
+/* vim: set ft=c : */
diff --git a/src/proto/gui_gtk_x11.pro b/src/proto/gui_gtk_x11.pro
new file mode 100644
index 0000000..111cac7
--- /dev/null
+++ b/src/proto/gui_gtk_x11.pro
@@ -0,0 +1,79 @@
+/* gui_gtk_x11.c */
+void gui_mch_prepare(int *argc, char **argv);
+void gui_mch_free_all(void);
+int gui_mch_is_blinking(void);
+int gui_mch_is_blink_off(void);
+void gui_mch_set_blinking(long waittime, long on, long off);
+void gui_mch_stop_blink(int may_call_gui_update_cursor);
+void gui_mch_start_blink(void);
+int gui_mch_early_init_check(int give_message);
+int gui_mch_init_check(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);
+void gui_gtk_set_selection_targets(void);
+void gui_gtk_set_dnd_targets(void);
+int gui_mch_init(void);
+void gui_mch_forked(void);
+void gui_mch_new_colors(void);
+int gui_mch_open(void);
+void gui_mch_exit(int rc);
+int gui_mch_get_winpos(int *x, int *y);
+void gui_mch_set_winpos(int x, int y);
+int gui_mch_maximized(void);
+void gui_mch_unmaximize(void);
+void gui_mch_newfont(void);
+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_gtk_get_screen_geom_of_win(GtkWidget *wid, int *screen_x, int *screen_y, int *width, int *height);
+void gui_mch_get_screen_dimensions(int *screen_w, int *screen_h);
+void gui_mch_settitle(char_u *title, char_u *icon);
+void gui_mch_enable_menu(int showit);
+void gui_mch_show_toolbar(int showit);
+int gui_mch_adjust_charheight(void);
+char_u *gui_mch_font_dialog(char_u *oldval);
+int gui_mch_init_font(char_u *font_name, int fontset);
+GuiFont gui_mch_get_font(char_u *name, int report_error);
+char_u *gui_mch_get_fontname(GuiFont font, char_u *name);
+void gui_mch_free_font(GuiFont font);
+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);
+int gui_gtk2_draw_string(int row, int col, char_u *s, int len, int flags);
+int gui_mch_haskey(char_u *name);
+int gui_get_x11_windis(Window *win, Display **dis);
+Display *gui_mch_get_display(void);
+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_set_foreground(void);
+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(long wtime);
+void gui_mch_flush(void);
+void gui_mch_clear_block(int row1arg, int col1arg, int row2arg, int col2arg);
+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 clip_mch_request_selection(VimClipboard *cbd);
+void clip_mch_lose_selection(VimClipboard *cbd);
+int clip_mch_own_selection(VimClipboard *cbd);
+void clip_mch_set_selection(VimClipboard *cbd);
+int clip_gtk_owner_exists(VimClipboard *cbd);
+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);
+void gui_mch_enable_scrollbar(scrollbar_T *sb, int flag);
+guicolor_T gui_mch_get_rgb(guicolor_T pixel);
+void gui_mch_getmouse(int *x, int *y);
+void gui_mch_setmouse(int x, int y);
+void gui_mch_mousehide(int hide);
+void mch_set_mouse_shape(int shape);
+void gui_mch_drawsign(int row, int col, int typenr);
+void *gui_mch_register_sign(char_u *signfile);
+void gui_mch_destroy_sign(void *sign);
+/* vim: set ft=c : */
diff --git a/src/proto/gui_mac.pro b/src/proto/gui_mac.pro
new file mode 100644
index 0000000..011ef28
--- /dev/null
+++ b/src/proto/gui_mac.pro
@@ -0,0 +1,151 @@
+/* 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);
+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(VimClipboard *cbd);
+void clip_mch_request_selection(VimClipboard *cbd);
+void clip_mch_set_selection(VimClipboard *cbd);
+int clip_mch_own_selection(VimClipboard *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/proto/gui_motif.pro b/src/proto/gui_motif.pro
new file mode 100644
index 0000000..493f5e7
--- /dev/null
+++ b/src/proto/gui_motif.pro
@@ -0,0 +1,46 @@
+/* gui_motif.c */
+void gui_x11_create_widgets(void);
+void gui_x11_destroy_widgets(void);
+void gui_mch_set_text_area_pos(int x, int y, int w, int h);
+void gui_x11_set_back_color(void);
+void manage_centered(Widget dialog_child);
+XmFontList gui_motif_create_fontlist(XFontStruct *font);
+XmFontList gui_motif_fontset2fontlist(XFontSet *fontset);
+void gui_mch_enable_menu(int flag);
+void gui_motif_set_mnemonics(int enable);
+void gui_mch_add_menu(vimmenu_T *menu, int idx);
+void gui_mch_toggle_tearoffs(int enable);
+int gui_mch_text_area_extra_height(void);
+void gui_mch_compute_menu_height(Widget id);
+void gui_mch_add_menu_item(vimmenu_T *menu, int idx);
+void gui_motif_update_mousemodel(vimmenu_T *menu);
+void gui_mch_new_menu_colors(void);
+void gui_mch_new_menu_font(void);
+void gui_mch_new_tooltip_font(void);
+void gui_mch_new_tooltip_colors(void);
+void gui_mch_destroy_menu(vimmenu_T *menu);
+void gui_mch_show_popupmenu(vimmenu_T *menu);
+void gui_mch_def_colors(void);
+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);
+void gui_mch_enable_scrollbar(scrollbar_T *sb, int flag);
+void gui_mch_create_scrollbar(scrollbar_T *sb, int orient);
+void gui_mch_destroy_scrollbar(scrollbar_T *sb);
+void gui_mch_set_scrollbar_colors(scrollbar_T *sb);
+Window gui_x11_get_wid(void);
+char_u *gui_mch_browse(int saving, char_u *title, char_u *dflt, char_u *ext, char_u *initdir, char_u *filter);
+int gui_mch_dialog(int type, char_u *title, char_u *message, char_u *button_names, int dfltbutton, char_u *textfield, int ex_cmd);
+void gui_mch_enable_footer(int showit);
+void gui_mch_set_footer(char_u *s);
+void gui_mch_show_toolbar(int showit);
+int gui_mch_compute_toolbar_height(void);
+void motif_get_toolbar_colors(Pixel *bgp, Pixel *fgp, Pixel *bsp, Pixel *tsp, Pixel *hsp);
+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);
+void gui_motif_menu_fontlist(Widget id);
+void gui_mch_find_dialog(exarg_T *eap);
+void gui_mch_replace_dialog(exarg_T *eap);
+void gui_motif_synch_fonts(void);
+/* vim: set ft=c : */
diff --git a/src/proto/gui_photon.pro b/src/proto/gui_photon.pro
new file mode 100644
index 0000000..9fcc512
--- /dev/null
+++ b/src/proto/gui_photon.pro
@@ -0,0 +1,70 @@
+/* gui_photon.c */
+void gui_ph_encoding_changed(int new_encoding);
+void gui_mch_prepare(int *argc, char **argv);
+int gui_mch_init(void);
+int gui_mch_init_check(void);
+int gui_mch_open(void);
+void gui_mch_exit(int rc);
+void gui_mch_update(void);
+int gui_mch_wait_for_chars(int wtime);
+char_u *gui_mch_browse(int saving, char_u *title, char_u *default_name, char_u *ext, char_u *initdir, char_u *filter);
+int gui_mch_dialog(int type, char_u *title, char_u *message, char_u *buttons, int default_button, char_u *textfield, int ex_cmd);
+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_iconify(void);
+void gui_mch_set_foreground(void);
+void gui_mch_settitle(char_u *title, char_u *icon);
+void gui_mch_set_scrollbar_thumb(scrollbar_T *sb, int val, int size, int max);
+void gui_mch_set_scrollbar_pos(scrollbar_T *sb, int x, int y, int w, int h);
+void gui_mch_create_scrollbar(scrollbar_T *sb, int orient);
+void gui_mch_enable_scrollbar(scrollbar_T *sb, int flag);
+void gui_mch_destroy_scrollbar(scrollbar_T *sb);
+void mch_set_mouse_shape(int shape);
+void gui_mch_mousehide(int hide);
+void gui_mch_getmouse(int *x, int *y);
+void gui_mch_setmouse(int x, int y);
+guicolor_T gui_mch_get_rgb(guicolor_T pixel);
+void gui_mch_new_colors(void);
+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_invert_rectangle(int row, int col, int nr, int nc);
+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_draw_string(int row, int col, char_u *s, int len, int flags);
+void gui_mch_draw_hollow_cursor(guicolor_T color);
+void gui_mch_draw_part_cursor(int w, int h, guicolor_T color);
+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_start_blink(void);
+void gui_mch_stop_blink(int may_call_gui_update_cursor);
+void gui_mch_beep(void);
+void gui_mch_flash(int msec);
+void gui_mch_flush(void);
+void gui_mch_set_text_area_pos(int x, int y, int w, int h);
+int gui_mch_haskey(char_u *name);
+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, int index);
+void gui_mch_add_menu_item(vimmenu_T *menu, int index);
+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);
+void gui_mch_show_popupmenu(vimmenu_T *menu);
+void gui_mch_toggle_tearoffs(int enable);
+void gui_mch_show_toolbar(int showit);
+int gui_mch_init_font(char_u *vim_font_name, int fontset);
+int gui_mch_adjust_charheight(void);
+GuiFont gui_mch_get_font(char_u *vim_font_name, int report_error);
+char_u *gui_mch_get_fontname(GuiFont font, char_u *name);
+void gui_mch_set_font(GuiFont font);
+void gui_mch_free_font(GuiFont font);
+/* vim: set ft=c : */
diff --git a/src/proto/gui_w32.pro b/src/proto/gui_w32.pro
new file mode 100644
index 0000000..75edd4b
--- /dev/null
+++ b/src/proto/gui_w32.pro
@@ -0,0 +1,99 @@
+/* gui_w32.c */
+int gui_mch_set_rendering_options(char_u *s);
+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);
+LRESULT WINAPI vim_WindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
+void gui_mch_new_colors(void);
+void gui_mch_def_colors(void);
+int gui_mch_open(void);
+int gui_mch_get_winpos(int *x, int *y);
+void gui_mch_set_winpos(int x, int y);
+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_pos(scrollbar_T *sb, int x, int y, int w, int h);
+void gui_mch_create_scrollbar(scrollbar_T *sb, int orient);
+int gui_mch_adjust_charheight(void);
+GuiFont gui_mch_get_font(char_u *name, int giveErrorIfMissing);
+char_u *gui_mch_get_fontname(GuiFont font, char_u *name);
+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);
+int gui_mch_haskey(char_u *name);
+void gui_mch_beep(void);
+void gui_mch_invert_rectangle(int r, int c, int nr, int nc);
+void gui_mch_iconify(void);
+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_clear_block(int row1, int col1, int row2, int col2);
+void gui_mch_clear_all(void);
+void gui_mch_enable_menu(int flag);
+void gui_mch_set_menu_pos(int x, int y, int w, int h);
+void gui_mch_menu_hidden(vimmenu_T *menu, int hidden);
+void gui_mch_draw_menubar(void);
+guicolor_T gui_mch_get_rgb(guicolor_T pixel);
+void gui_mch_show_toolbar(int showit);
+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);
+void ex_simalt(exarg_T *eap);
+void gui_mch_find_dialog(exarg_T *eap);
+void gui_mch_replace_dialog(exarg_T *eap);
+void gui_mch_mousehide(int hide);
+void gui_mch_destroy_scrollbar(scrollbar_T *sb);
+void gui_mch_getmouse(int *x, int *y);
+void gui_mch_setmouse(int x, int y);
+void gui_mch_flash(int msec);
+void gui_mch_delete_lines(int row, int num_lines);
+void gui_mch_insert_lines(int row, int num_lines);
+void gui_mch_exit(int rc);
+void gui_mch_wide_font_changed(void);
+int gui_mch_init_font(char_u *font_name, int fontset);
+int gui_mch_maximized(void);
+void gui_mch_newfont(void);
+void gui_mch_settitle(char_u *title, char_u *icon);
+void mch_set_mouse_shape(int shape);
+char_u *gui_mch_browse(int saving, char_u *title, char_u *dflt, char_u *ext, char_u *initdir, char_u *filter);
+char_u *gui_mch_browsedir(char_u *title, char_u *initdir);
+int get_cmd_args(char *prog, char *cmdline, char ***argvp, char **tofree);
+void gui_mch_set_parent(char *title);
+void gui_mch_prepare(int *argc, char **argv);
+int gui_mch_init(void);
+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_set_scrollbar_thumb(scrollbar_T *sb, long val, long size, long max);
+void gui_mch_set_font(GuiFont font);
+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 im_set_font(LOGFONT *lf);
+void im_set_position(int row, int col);
+void im_set_active(int active);
+int im_get_status(void);
+void gui_mch_draw_string(int row, int col, char_u *text, int len, int flags);
+void gui_mch_flush(void);
+void gui_mch_get_screen_dimensions(int *screen_w, int *screen_h);
+void gui_mch_add_menu(vimmenu_T *menu, int pos);
+void gui_mch_show_popupmenu(vimmenu_T *menu);
+void gui_make_popup(char_u *path_name, int mouse_pos);
+void gui_make_tearoff(char_u *path_name);
+void gui_mch_add_menu_item(vimmenu_T *menu, int idx);
+void gui_mch_destroy_menu(vimmenu_T *menu);
+void gui_mch_menu_grey(vimmenu_T *menu, int grey);
+int gui_mch_dialog(int type, char_u *title, char_u *message, char_u *buttons, int dfltbutton, char_u *textfield, int ex_cmd);
+void gui_mch_set_foreground(void);
+void gui_mch_drawsign(int row, int col, int typenr);
+void *gui_mch_register_sign(char_u *signfile);
+void gui_mch_destroy_sign(void *sign);
+int multiline_balloon_available(void);
+void gui_mch_disable_beval_area(BalloonEval *beval);
+void gui_mch_enable_beval_area(BalloonEval *beval);
+void gui_mch_post_balloon(BalloonEval *beval, char_u *mesg);
+BalloonEval *gui_mch_create_beval_area(void *target, char_u *mesg, void (*mesgCB)(BalloonEval *, int), void *clientData);
+void gui_mch_destroy_beval_area(BalloonEval *beval);
+void netbeans_draw_multisign_indicator(int row);
+/* vim: set ft=c : */
diff --git a/src/proto/gui_x11.pro b/src/proto/gui_x11.pro
new file mode 100644
index 0000000..955f374
--- /dev/null
+++ b/src/proto/gui_x11.pro
@@ -0,0 +1,73 @@
+/* gui_x11.c */
+void gui_x11_key_hit_cb(Widget w, XtPointer dud, XEvent *event, Boolean *dum);
+void gui_mch_prepare(int *argc, char **argv);
+int gui_mch_init_check(void);
+int gui_mch_init(void);
+void gui_mch_uninit(void);
+void gui_mch_new_colors(void);
+int gui_mch_open(void);
+void gui_init_tooltip_font(void);
+void gui_init_menu_font(void);
+void gui_mch_exit(int rc);
+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);
+int gui_mch_init_font(char_u *font_name, int do_fontset);
+GuiFont gui_mch_get_font(char_u *name, int giveErrorIfMissing);
+char_u *gui_mch_get_fontname(GuiFont font, char_u *name);
+int gui_mch_adjust_charheight(void);
+void gui_mch_set_font(GuiFont font);
+void gui_mch_set_fontset(GuiFontset fontset);
+void gui_mch_free_font(GuiFont font);
+void gui_mch_free_fontset(GuiFontset fontset);
+GuiFontset gui_mch_get_fontset(char_u *name, int giveErrorIfMissing, int fixed_width);
+int fontset_height(XFontSet fs);
+int fontset_height2(XFontSet fs);
+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);
+int gui_get_x11_windis(Window *win, Display **dis);
+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_set_foreground(void);
+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(long 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 clip_mch_lose_selection(VimClipboard *cbd);
+int clip_mch_own_selection(VimClipboard *cbd);
+void clip_mch_request_selection(VimClipboard *cbd);
+void clip_mch_set_selection(VimClipboard *cbd);
+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);
+void gui_x11_menu_cb(Widget w, XtPointer client_data, XtPointer call_data);
+int gui_mch_is_blinking(void);
+int gui_mch_is_blink_off(void);
+void gui_mch_set_blinking(long waittime, long on, long off);
+void gui_mch_stop_blink(int may_call_gui_update_cursor);
+void gui_mch_start_blink(void);
+guicolor_T gui_mch_get_rgb(guicolor_T pixel);
+void gui_x11_callbacks(Widget textArea, Widget vimForm);
+void gui_mch_getmouse(int *x, int *y);
+void gui_mch_setmouse(int x, int y);
+XButtonPressedEvent *gui_x11_get_last_mouse_event(void);
+void gui_mch_drawsign(int row, int col, int typenr);
+void *gui_mch_register_sign(char_u *signfile);
+void gui_mch_destroy_sign(void *sign);
+void gui_mch_mousehide(int hide);
+void mch_set_mouse_shape(int shape);
+void gui_mch_menu_set_tip(vimmenu_T *menu);
+/* vim: set ft=c : */
diff --git a/src/proto/gui_xmdlg.pro b/src/proto/gui_xmdlg.pro
new file mode 100644
index 0000000..256fad7
--- /dev/null
+++ b/src/proto/gui_xmdlg.pro
@@ -0,0 +1,3 @@
+/* gui_xmdlg.c */
+char_u *gui_xm_select_font(char_u *current);
+/* vim: set ft=c : */
diff --git a/src/proto/hangulin.pro b/src/proto/hangulin.pro
new file mode 100644
index 0000000..3aef39d
--- /dev/null
+++ b/src/proto/hangulin.pro
@@ -0,0 +1,11 @@
+/* hangulin.c */
+int hangul_input_state_get(void);
+void hangul_input_state_set(int state);
+int im_get_status(void);
+void hangul_input_state_toggle(void);
+void hangul_keyboard_set(void);
+int hangul_input_process(char_u *s, int len);
+void hangul_input_clear(void);
+char_u *hangul_string_convert(char_u *buf, int *p_len);
+char_u *hangul_composing_buffer_get(int *p_len);
+/* vim: set ft=c : */
diff --git a/src/proto/hardcopy.pro b/src/proto/hardcopy.pro
new file mode 100644
index 0000000..615f088
--- /dev/null
+++ b/src/proto/hardcopy.pro
@@ -0,0 +1,20 @@
+/* hardcopy.c */
+char *parse_printoptions(void);
+char *parse_printmbfont(void);
+int prt_header_height(void);
+int prt_use_number(void);
+int prt_get_unit(int idx);
+void ex_hardcopy(exarg_T *eap);
+void mch_print_cleanup(void);
+int mch_print_init(prt_settings_T *psettings, char_u *jobname, int forceit);
+int mch_print_begin(prt_settings_T *psettings);
+void mch_print_end(prt_settings_T *psettings);
+int mch_print_end_page(void);
+int mch_print_begin_page(char_u *str);
+int mch_print_blank_page(void);
+void mch_print_start_line(int margin, int page_line);
+int mch_print_text_out(char_u *textp, int len);
+void mch_print_set_font(int iBold, int iItalic, int iUnderline);
+void mch_print_set_bg(long_u bgcol);
+void mch_print_set_fg(long_u fgcol);
+/* vim: set ft=c : */
diff --git a/src/proto/hashtab.pro b/src/proto/hashtab.pro
new file mode 100644
index 0000000..9690714
--- /dev/null
+++ b/src/proto/hashtab.pro
@@ -0,0 +1,14 @@
+/* hashtab.c */
+void hash_init(hashtab_T *ht);
+void hash_clear(hashtab_T *ht);
+void hash_clear_all(hashtab_T *ht, int off);
+hashitem_T *hash_find(hashtab_T *ht, char_u *key);
+hashitem_T *hash_lookup(hashtab_T *ht, char_u *key, hash_T hash);
+void hash_debug_results(void);
+int hash_add(hashtab_T *ht, char_u *key);
+int hash_add_item(hashtab_T *ht, hashitem_T *hi, char_u *key, hash_T hash);
+void hash_remove(hashtab_T *ht, hashitem_T *hi);
+void hash_lock(hashtab_T *ht);
+void hash_unlock(hashtab_T *ht);
+hash_T hash_hash(char_u *key);
+/* vim: set ft=c : */
diff --git a/src/proto/if_cscope.pro b/src/proto/if_cscope.pro
new file mode 100644
index 0000000..f9919c4
--- /dev/null
+++ b/src/proto/if_cscope.pro
@@ -0,0 +1,12 @@
+/* if_cscope.c */
+char_u *get_cscope_name(expand_T *xp, int idx);
+void set_context_in_cscope_cmd(expand_T *xp, char_u *arg, cmdidx_T cmdidx);
+void ex_cscope(exarg_T *eap);
+void ex_scscope(exarg_T *eap);
+void ex_cstag(exarg_T *eap);
+int cs_fgets(char_u *buf, int size);
+void cs_free_tags(void);
+void cs_print_tags(void);
+int cs_connection(int num, char_u *dbpath, char_u *ppath);
+void cs_end(void);
+/* vim: set ft=c : */
diff --git a/src/proto/if_lua.pro b/src/proto/if_lua.pro
new file mode 100644
index 0000000..c33678e
--- /dev/null
+++ b/src/proto/if_lua.pro
@@ -0,0 +1,11 @@
+/* if_lua.c */
+int lua_enabled(int verbose);
+void lua_end(void);
+void ex_lua(exarg_T *eap);
+void ex_luado(exarg_T *eap);
+void ex_luafile(exarg_T *eap);
+void lua_buffer_free(buf_T *o);
+void lua_window_free(win_T *o);
+void do_luaeval(char_u *str, typval_T *arg, typval_T *rettv);
+int set_ref_in_lua(int copyID);
+/* vim: set ft=c : */
diff --git a/src/proto/if_mzsch.pro b/src/proto/if_mzsch.pro
new file mode 100644
index 0000000..bab82ce
--- /dev/null
+++ b/src/proto/if_mzsch.pro
@@ -0,0 +1,17 @@
+/* if_mzsch.c */
+int mzscheme_enabled(int verbose);
+void mzvim_check_threads(void);
+void mzvim_reset_timer(void);
+void mzscheme_end(void);
+int mzscheme_main(void);
+void mzscheme_buffer_free(buf_T *buf);
+void mzscheme_window_free(win_T *win);
+void ex_mzscheme(exarg_T *eap);
+void ex_mzfile(exarg_T *eap);
+void do_mzeval(char_u *str, typval_T *rettv);
+void raise_vim_exn(const char *add_info);
+void raise_if_error(void);
+buf_T *get_valid_buffer(void *obj);
+win_T *get_valid_window(void *obj);
+int mzthreads_allowed(void);
+/* vim: set ft=c : */
diff --git a/src/proto/if_ole.pro b/src/proto/if_ole.pro
new file mode 100644
index 0000000..adedf6a
--- /dev/null
+++ b/src/proto/if_ole.pro
@@ -0,0 +1,5 @@
+/* if_ole.cpp */
+void InitOLE(int* pbDoRestart);
+void UninitOLE(void);
+void RegisterMe(int silent);
+void UnregisterMe(int bNotifyUser);
diff --git a/src/proto/if_perl.pro b/src/proto/if_perl.pro
new file mode 100644
index 0000000..066c0db
--- /dev/null
+++ b/src/proto/if_perl.pro
@@ -0,0 +1,9 @@
+/* auto/if_perl.c */
+int perl_enabled(int verbose);
+void perl_end(void);
+void msg_split(char_u *s, int attr);
+void perl_win_free(win_T *wp);
+void perl_buf_free(buf_T *bp);
+void ex_perl(exarg_T *eap);
+void do_perleval(char_u *str, typval_T *rettv);
+void ex_perldo(exarg_T *eap);
diff --git a/src/proto/if_perlsfio.pro b/src/proto/if_perlsfio.pro
new file mode 100644
index 0000000..df8e438
--- /dev/null
+++ b/src/proto/if_perlsfio.pro
@@ -0,0 +1,3 @@
+/* if_perlsfio.c */
+int *sfdcnewvim(void);
+/* vim: set ft=c : */
diff --git a/src/proto/if_python.pro b/src/proto/if_python.pro
new file mode 100644
index 0000000..51054ca
--- /dev/null
+++ b/src/proto/if_python.pro
@@ -0,0 +1,13 @@
+/* if_python.c */
+int python_enabled(int verbose);
+void python_end(void);
+int python_loaded(void);
+void ex_python(exarg_T *eap);
+void ex_pyfile(exarg_T *eap);
+void ex_pydo(exarg_T *eap);
+void python_buffer_free(buf_T *buf);
+void python_window_free(win_T *win);
+void python_tabpage_free(tabpage_T *tab);
+void do_pyeval(char_u *str, typval_T *rettv);
+int set_ref_in_python(int copyID);
+/* vim: set ft=c : */
diff --git a/src/proto/if_python3.pro b/src/proto/if_python3.pro
new file mode 100644
index 0000000..4e71ad2
--- /dev/null
+++ b/src/proto/if_python3.pro
@@ -0,0 +1,13 @@
+/* if_python3.c */
+int python3_enabled(int verbose);
+void python3_end(void);
+int python3_loaded(void);
+void ex_py3(exarg_T *eap);
+void ex_py3file(exarg_T *eap);
+void ex_py3do(exarg_T *eap);
+void python3_buffer_free(buf_T *buf);
+void python3_window_free(win_T *win);
+void python3_tabpage_free(tabpage_T *tab);
+void do_py3eval(char_u *str, typval_T *rettv);
+int set_ref_in_python3(int copyID);
+/* vim: set ft=c : */
diff --git a/src/proto/if_ruby.pro b/src/proto/if_ruby.pro
new file mode 100644
index 0000000..496859c
--- /dev/null
+++ b/src/proto/if_ruby.pro
@@ -0,0 +1,10 @@
+/* if_ruby.c */
+int ruby_enabled(int verbose);
+void ruby_end(void);
+void ex_ruby(exarg_T *eap);
+void ex_rubydo(exarg_T *eap);
+void ex_rubyfile(exarg_T *eap);
+void ruby_buffer_free(buf_T *buf);
+void ruby_window_free(win_T *win);
+void vim_ruby_init(void *stack_start);
+/* vim: set ft=c : */
diff --git a/src/proto/if_tcl.pro b/src/proto/if_tcl.pro
new file mode 100644
index 0000000..b572fb8
--- /dev/null
+++ b/src/proto/if_tcl.pro
@@ -0,0 +1,10 @@
+/* if_tcl.c */
+void vim_tcl_init(char *arg);
+int tcl_enabled(int verbose);
+void tcl_end(void);
+void ex_tcl(exarg_T *eap);
+void ex_tclfile(exarg_T *eap);
+void ex_tcldo(exarg_T *eap);
+void tcl_buffer_free(buf_T *buf);
+void tcl_window_free(win_T *win);
+/* vim: set ft=c : */
diff --git a/src/proto/if_xcmdsrv.pro b/src/proto/if_xcmdsrv.pro
new file mode 100644
index 0000000..801dc00
--- /dev/null
+++ b/src/proto/if_xcmdsrv.pro
@@ -0,0 +1,13 @@
+/* if_xcmdsrv.c */
+int serverRegisterName(Display *dpy, char_u *name);
+void serverChangeRegisteredWindow(Display *dpy, Window newwin);
+int serverSendToVim(Display *dpy, char_u *name, char_u *cmd, char_u **result, Window *server, int asExpr, int timeout, int localLoop, int silent);
+char_u *serverGetVimNames(Display *dpy);
+Window serverStrToWin(char_u *str);
+int serverSendReply(char_u *name, char_u *str);
+int serverReadReply(Display *dpy, Window win, char_u **str, int localLoop, int timeout);
+int serverPeekReply(Display *dpy, Window win, char_u **str);
+void serverEventProc(Display *dpy, XEvent *eventPtr, int immediate);
+void server_parse_messages(void);
+int server_waiting(void);
+/* vim: set ft=c : */
diff --git a/src/proto/indent.pro b/src/proto/indent.pro
new file mode 100644
index 0000000..277953e
--- /dev/null
+++ b/src/proto/indent.pro
@@ -0,0 +1,16 @@
+/* indent.c */
+int cin_is_cinword(char_u *line);
+pos_T *find_start_comment(int ind_maxcomment);
+int cindent_on(void);
+int cin_islabel(void);
+int cin_iscase(char_u *s, int strict);
+int cin_isscopedecl(char_u *s);
+void parse_cino(buf_T *buf);
+int get_c_indent(void);
+int get_expr_indent(void);
+int in_cinkeys(int keytyped, int when, int line_is_empty);
+int get_lisp_indent(void);
+void do_c_expr_indent(void);
+void fixthisline(int (*get_the_indent)(void));
+void fix_indent(void);
+/* vim: set ft=c : */
diff --git a/src/proto/json.pro b/src/proto/json.pro
new file mode 100644
index 0000000..b98c2c9
--- /dev/null
+++ b/src/proto/json.pro
@@ -0,0 +1,7 @@
+/* json.c */
+char_u *json_encode(typval_T *val, int options);
+char_u *json_encode_nr_expr(int nr, typval_T *val, int options);
+int json_decode_all(js_read_T *reader, typval_T *res, int options);
+int json_decode(js_read_T *reader, typval_T *res, int options);
+int json_find_end(js_read_T *reader, int options);
+/* vim: set ft=c : */
diff --git a/src/proto/list.pro b/src/proto/list.pro
new file mode 100644
index 0000000..88d9028
--- /dev/null
+++ b/src/proto/list.pro
@@ -0,0 +1,40 @@
+/* list.c */
+void list_add_watch(list_T *l, listwatch_T *lw);
+void list_rem_watch(list_T *l, listwatch_T *lwrem);
+void list_fix_watch(list_T *l, listitem_T *item);
+list_T *list_alloc(void);
+list_T *list_alloc_id(alloc_id_T id);
+int rettv_list_alloc(typval_T *rettv);
+int rettv_list_alloc_id(typval_T *rettv, alloc_id_T id);
+void rettv_list_set(typval_T *rettv, list_T *l);
+void list_unref(list_T *l);
+int list_free_nonref(int copyID);
+void list_free_items(int copyID);
+void list_free(list_T *l);
+listitem_T *listitem_alloc(void);
+void listitem_free(listitem_T *item);
+void listitem_remove(list_T *l, listitem_T *item);
+long list_len(list_T *l);
+int list_equal(list_T *l1, list_T *l2, int ic, int recursive);
+listitem_T *list_find(list_T *l, long n);
+long list_find_nr(list_T *l, long idx, int *errorp);
+char_u *list_find_str(list_T *l, long idx);
+long list_idx_of_item(list_T *l, listitem_T *item);
+void list_append(list_T *l, listitem_T *item);
+int list_append_tv(list_T *l, typval_T *tv);
+int list_append_dict(list_T *list, dict_T *dict);
+int list_append_list(list_T *list1, list_T *list2);
+int list_append_string(list_T *l, char_u *str, int len);
+int list_append_number(list_T *l, varnumber_T n);
+int list_insert_tv(list_T *l, typval_T *tv, listitem_T *item);
+void list_insert(list_T *l, listitem_T *ni, listitem_T *item);
+int list_extend(list_T *l1, list_T *l2, listitem_T *bef);
+int list_concat(list_T *l1, list_T *l2, typval_T *tv);
+list_T *list_copy(list_T *orig, int deep, int copyID);
+void vimlist_remove(list_T *l, listitem_T *item, listitem_T *item2);
+char_u *list2string(typval_T *tv, int copyID, int restore_copyID);
+int list_join(garray_T *gap, list_T *l, char_u *sep, int echo_style, int restore_copyID, int copyID);
+int get_list_tv(char_u **arg, typval_T *rettv, int evaluate);
+int write_list(FILE *fd, list_T *list, int binary);
+void init_static_list(staticList10_T *sl);
+/* vim: set ft=c : */
diff --git a/src/proto/main.pro b/src/proto/main.pro
new file mode 100644
index 0000000..278d1ad
--- /dev/null
+++ b/src/proto/main.pro
@@ -0,0 +1,17 @@
+/* main.c */
+int vim_main2(void);
+void common_init(mparm_T *paramp);
+int is_not_a_term(void);
+void main_loop(int cmdwin, int noexmode);
+void getout_preserve_modified(int exitval);
+void getout(int exitval);
+int process_env(char_u *env, int is_viminit);
+void mainerr_arg_missing(char_u *str);
+void time_push(void *tv_rel, void *tv_start);
+void time_pop(void *tp);
+void time_msg(char *mesg, void *tv_start);
+void server_to_input_buf(char_u *str);
+char_u *eval_client_expr_to_string(char_u *expr);
+int sendToLocalVim(char_u *cmd, int asExpr, char_u **result);
+char_u *serverConvert(char_u *client_enc, char_u *data, char_u **tofree);
+/* vim: set ft=c : */
diff --git a/src/proto/mark.pro b/src/proto/mark.pro
new file mode 100644
index 0000000..150e986
--- /dev/null
+++ b/src/proto/mark.pro
@@ -0,0 +1,38 @@
+/* mark.c */
+int setmark(int c);
+int setmark_pos(int c, pos_T *pos, int fnum);
+void setpcmark(void);
+void checkpcmark(void);
+pos_T *movemark(int count);
+pos_T *movechangelist(int count);
+pos_T *getmark_buf(buf_T *buf, int c, int changefile);
+pos_T *getmark(int c, int changefile);
+pos_T *getmark_buf_fnum(buf_T *buf, int c, int changefile, int *fnum);
+pos_T *getnextmark(pos_T *startpos, int dir, int begin_line);
+void fname2fnum(xfmark_T *fm);
+void fmarks_check_names(buf_T *buf);
+int check_mark(pos_T *pos);
+void clrallmarks(buf_T *buf);
+char_u *fm_getname(fmark_T *fmark, int lead_len);
+void do_marks(exarg_T *eap);
+void ex_delmarks(exarg_T *eap);
+void ex_jumps(exarg_T *eap);
+void ex_clearjumps(exarg_T *eap);
+void ex_changes(exarg_T *eap);
+void mark_adjust(linenr_T line1, linenr_T line2, long amount, long amount_after);
+void mark_adjust_nofold(linenr_T line1, linenr_T line2, long amount, long amount_after);
+void mark_col_adjust(linenr_T lnum, colnr_T mincol, long lnum_amount, long col_amount, int spaces_removed);
+void cleanup_jumplist(win_T *wp, int loadfiles);
+void copy_jumplist(win_T *from, win_T *to);
+void free_jumplist(win_T *wp);
+void set_last_cursor(win_T *win);
+void free_all_marks(void);
+int read_viminfo_filemark(vir_T *virp, int force);
+void prepare_viminfo_marks(void);
+void finish_viminfo_marks(void);
+void handle_viminfo_mark(garray_T *values, int force);
+void write_viminfo_filemarks(FILE *fp);
+int removable(char_u *name);
+void write_viminfo_marks(FILE *fp_out, garray_T *buflist);
+void copy_viminfo_marks(vir_T *virp, FILE *fp_out, garray_T *buflist, int eof, int flags);
+/* vim: set ft=c : */
diff --git a/src/proto/mbyte.pro b/src/proto/mbyte.pro
new file mode 100644
index 0000000..5b97d55
--- /dev/null
+++ b/src/proto/mbyte.pro
@@ -0,0 +1,101 @@
+/* mbyte.c */
+int enc_canon_props(char_u *name);
+char *mb_init(void);
+int bomb_size(void);
+void remove_bom(char_u *s);
+int mb_get_class(char_u *p);
+int mb_get_class_buf(char_u *p, buf_T *buf);
+int dbcs_class(unsigned lead, unsigned trail);
+int latin_char2len(int c);
+int latin_char2bytes(int c, char_u *buf);
+int latin_ptr2len(char_u *p);
+int latin_ptr2len_len(char_u *p, int size);
+int utf_uint2cells(UINT32_T c);
+int utf_char2cells(int c);
+int latin_ptr2cells(char_u *p);
+int utf_ptr2cells(char_u *p);
+int dbcs_ptr2cells(char_u *p);
+int latin_ptr2cells_len(char_u *p, int size);
+int latin_char2cells(int c);
+int mb_string2cells(char_u *p, int len);
+int latin_off2cells(unsigned off, unsigned max_off);
+int dbcs_off2cells(unsigned off, unsigned max_off);
+int utf_off2cells(unsigned off, unsigned max_off);
+int latin_ptr2char(char_u *p);
+int utf_ptr2char(char_u *p);
+int mb_ptr2char_adv(char_u **pp);
+int mb_cptr2char_adv(char_u **pp);
+int arabic_combine(int one, int two);
+int arabic_maycombine(int two);
+int utf_composinglike(char_u *p1, char_u *p2);
+int utfc_ptr2char(char_u *p, int *pcc);
+int utfc_ptr2char_len(char_u *p, int *pcc, int maxlen);
+int utfc_char2bytes(int off, char_u *buf);
+int utf_ptr2len(char_u *p);
+int utf_byte2len(int b);
+int utf_ptr2len_len(char_u *p, int size);
+int utfc_ptr2len(char_u *p);
+int utfc_ptr2len_len(char_u *p, int size);
+int utf_char2len(int c);
+int utf_char2bytes(int c, char_u *buf);
+int utf_iscomposing_uint(UINT32_T c);
+int utf_iscomposing(int c);
+int utf_printable(int c);
+int utf_class(int c);
+int utf_class_buf(int c, buf_T *buf);
+int utf_ambiguous_width(int c);
+int utf_fold(int a);
+int utf_toupper(int a);
+int utf_islower(int a);
+int utf_tolower(int a);
+int utf_isupper(int a);
+int mb_strnicmp(char_u *s1, char_u *s2, size_t nn);
+void show_utf8(void);
+int latin_head_off(char_u *base, char_u *p);
+int dbcs_head_off(char_u *base, char_u *p);
+int dbcs_screen_head_off(char_u *base, char_u *p);
+int utf_head_off(char_u *base, char_u *p);
+void mb_copy_char(char_u **fp, char_u **tp);
+int mb_off_next(char_u *base, char_u *p);
+int mb_tail_off(char_u *base, char_u *p);
+void utf_find_illegal(void);
+int utf_valid_string(char_u *s, char_u *end);
+int dbcs_screen_tail_off(char_u *base, char_u *p);
+void mb_adjust_cursor(void);
+void mb_adjustpos(buf_T *buf, pos_T *lp);
+char_u *mb_prevptr(char_u *line, char_u *p);
+int mb_charlen(char_u *str);
+int mb_charlen_len(char_u *str, int len);
+char_u *mb_unescape(char_u **pp);
+int mb_lefthalve(int row, int col);
+int mb_fix_col(int col, int row);
+char_u *enc_skip(char_u *p);
+char_u *enc_canonize(char_u *enc);
+char_u *enc_locale_env(char *locale);
+char_u *enc_locale(void);
+int encname2codepage(char_u *name);
+void *my_iconv_open(char_u *to, char_u *from);
+int iconv_enabled(int verbose);
+void iconv_end(void);
+void im_set_active(int active);
+void xim_set_focus(int focus);
+void im_set_position(int row, int col);
+void xim_set_preedit(void);
+int im_get_feedback_attr(int col);
+void xim_init(void);
+void im_shutdown(void);
+int im_xim_isvalid_imactivate(void);
+void xim_reset(void);
+int xim_queue_key_press_event(GdkEventKey *event, int down);
+int im_get_status(void);
+int preedit_get_status(void);
+int im_is_preediting(void);
+void xim_set_status_area(void);
+int xim_get_status_area_height(void);
+int convert_setup(vimconv_T *vcp, char_u *from, char_u *to);
+int convert_setup_ext(vimconv_T *vcp, char_u *from, int from_unicode_is_utf8, char_u *to, int to_unicode_is_utf8);
+int convert_input(char_u *ptr, int len, int maxlen);
+int convert_input_safe(char_u *ptr, int len, int maxlen, char_u **restp, int *restlenp);
+char_u *string_convert(vimconv_T *vcp, char_u *ptr, int *lenp);
+char_u *string_convert_ext(vimconv_T *vcp, char_u *ptr, int *lenp, int *unconvlenp);
+/* vim: set ft=c : */
diff --git a/src/proto/memfile.pro b/src/proto/memfile.pro
new file mode 100644
index 0000000..4662194
--- /dev/null
+++ b/src/proto/memfile.pro
@@ -0,0 +1,18 @@
+/* memfile.c */
+memfile_T *mf_open(char_u *fname, int flags);
+int mf_open_file(memfile_T *mfp, char_u *fname);
+void mf_close(memfile_T *mfp, int del_file);
+void mf_close_file(buf_T *buf, int getlines);
+void mf_new_page_size(memfile_T *mfp, unsigned new_size);
+bhdr_T *mf_new(memfile_T *mfp, int negative, int page_count);
+bhdr_T *mf_get(memfile_T *mfp, blocknr_T nr, int page_count);
+void mf_put(memfile_T *mfp, bhdr_T *hp, int dirty, int infile);
+void mf_free(memfile_T *mfp, bhdr_T *hp);
+int mf_sync(memfile_T *mfp, int flags);
+void mf_set_dirty(memfile_T *mfp);
+int mf_release_all(void);
+blocknr_T mf_trans_del(memfile_T *mfp, blocknr_T old_nr);
+void mf_set_ffname(memfile_T *mfp);
+void mf_fullname(memfile_T *mfp);
+int mf_need_trans(memfile_T *mfp);
+/* vim: set ft=c : */
diff --git a/src/proto/memline.pro b/src/proto/memline.pro
new file mode 100644
index 0000000..04254b0
--- /dev/null
+++ b/src/proto/memline.pro
@@ -0,0 +1,40 @@
+/* memline.c */
+int ml_open(buf_T *buf);
+void ml_set_crypt_key(buf_T *buf, char_u *old_key, char_u *old_cm);
+void ml_setname(buf_T *buf);
+void ml_open_files(void);
+void ml_open_file(buf_T *buf);
+void check_need_swap(int newfile);
+void ml_close(buf_T *buf, int del_file);
+void ml_close_all(int del_file);
+void ml_close_notmod(void);
+void ml_timestamp(buf_T *buf);
+void ml_recover(void);
+int recover_names(char_u *fname, int list, int nr, char_u **fname_out);
+char_u *make_percent_swname(char_u *dir, char_u *name);
+void get_b0_dict(char_u *fname, dict_T *d);
+void ml_sync_all(int check_file, int check_char);
+void ml_preserve(buf_T *buf, int message);
+char_u *ml_get(linenr_T lnum);
+char_u *ml_get_pos(pos_T *pos);
+char_u *ml_get_curline(void);
+char_u *ml_get_cursor(void);
+char_u *ml_get_buf(buf_T *buf, linenr_T lnum, int will_change);
+int ml_line_alloced(void);
+int ml_append(linenr_T lnum, char_u *line, colnr_T len, int newfile);
+int ml_append_buf(buf_T *buf, linenr_T lnum, char_u *line, colnr_T len, int newfile);
+int ml_replace(linenr_T lnum, char_u *line, int copy);
+int ml_replace_len(linenr_T lnum, char_u *line_arg, colnr_T len_arg, int has_props, int copy);
+int ml_delete(linenr_T lnum, int message);
+void ml_setmarked(linenr_T lnum);
+linenr_T ml_firstmarked(void);
+void ml_clearmarked(void);
+int resolve_symlink(char_u *fname, char_u *buf);
+char_u *makeswapname(char_u *fname, char_u *ffname, buf_T *buf, char_u *dir_name);
+char_u *get_file_in_dir(char_u *fname, char_u *dname);
+void ml_setflags(buf_T *buf);
+char_u *ml_encrypt_data(memfile_T *mfp, char_u *data, off_T offset, unsigned size);
+void ml_decrypt_data(memfile_T *mfp, char_u *data, off_T offset, unsigned size);
+long ml_find_line_or_offset(buf_T *buf, linenr_T lnum, long *offp);
+void goto_byte(long cnt);
+/* vim: set ft=c : */
diff --git a/src/proto/menu.pro b/src/proto/menu.pro
new file mode 100644
index 0000000..411c040
--- /dev/null
+++ b/src/proto/menu.pro
@@ -0,0 +1,27 @@
+/* menu.c */
+int winbar_height(win_T *wp);
+void ex_menu(exarg_T *eap);
+void remove_winbar(win_T *wp);
+char_u *set_context_in_menu_cmd(expand_T *xp, char_u *cmd, char_u *arg, int forceit);
+char_u *get_menu_name(expand_T *xp, int idx);
+char_u *get_menu_names(expand_T *xp, int idx);
+char_u *menu_name_skip(char_u *name);
+int get_menu_index(vimmenu_T *menu, int state);
+int menu_is_menubar(char_u *name);
+int menu_is_popup(char_u *name);
+int menu_is_child_of_popup(vimmenu_T *menu);
+int menu_is_toolbar(char_u *name);
+int menu_is_separator(char_u *name);
+int get_menu_mode_flag(void);
+void show_popupmenu(void);
+int check_menu_pointer(vimmenu_T *root, vimmenu_T *menu_to_check);
+void gui_create_initial_menus(vimmenu_T *menu);
+void gui_update_menus(int modes);
+int gui_is_menu_shortcut(int key);
+void gui_mch_toggle_tearoffs(int enable);
+void execute_menu(exarg_T *eap, vimmenu_T *menu, int mode_idx);
+void ex_emenu(exarg_T *eap);
+void winbar_click(win_T *wp, int col);
+vimmenu_T *gui_find_menu(char_u *path_name);
+void ex_menutranslate(exarg_T *eap);
+/* vim: set ft=c : */
diff --git a/src/proto/message.pro b/src/proto/message.pro
new file mode 100644
index 0000000..792ac5d
--- /dev/null
+++ b/src/proto/message.pro
@@ -0,0 +1,83 @@
+/* message.c */
+int msg(char *s);
+int verb_msg(char *s);
+int msg_attr(char *s, int attr);
+int msg_attr_keep(char *s, int attr, int keep);
+char_u *msg_strtrunc(char_u *s, int force);
+void trunc_string(char_u *s, char_u *buf, int room_in, int buflen);
+void reset_last_sourcing(void);
+void msg_source(int attr);
+int emsg_not_now(void);
+void ignore_error_for_testing(char_u *error);
+void do_perror(char *msg);
+int emsg(char *s);
+int semsg(const char *s, ...);
+void iemsg(char *s);
+void siemsg(const char *s, ...);
+void internal_error(char *where);
+void emsg_invreg(int name);
+char *msg_trunc_attr(char *s, int force, int attr);
+char_u *msg_may_trunc(int force, char_u *s);
+int delete_first_msg(void);
+void ex_messages(exarg_T *eap);
+void msg_end_prompt(void);
+void wait_return(int redraw);
+void set_keep_msg(char_u *s, int attr);
+void set_keep_msg_from_hist(void);
+void msg_start(void);
+void msg_starthere(void);
+void msg_putchar(int c);
+void msg_putchar_attr(int c, int attr);
+void msg_outnum(long n);
+void msg_home_replace(char_u *fname);
+void msg_home_replace_hl(char_u *fname);
+int msg_outtrans(char_u *str);
+int msg_outtrans_attr(char_u *str, int attr);
+int msg_outtrans_len(char_u *str, int len);
+char_u *msg_outtrans_one(char_u *p, int attr);
+int msg_outtrans_len_attr(char_u *msgstr, int len, int attr);
+void msg_make(char_u *arg);
+int msg_outtrans_special(char_u *strstart, int from);
+char_u *str2special_save(char_u *str, int is_lhs);
+char_u *str2special(char_u **sp, int from);
+void str2specialbuf(char_u *sp, char_u *buf, int len);
+void msg_prt_line(char_u *s, int list);
+void msg_puts(char *s);
+void msg_puts_title(char *s);
+void msg_outtrans_long_attr(char_u *longstr, int attr);
+void msg_outtrans_long_len_attr(char_u *longstr, int len, int attr);
+void msg_puts_attr(char *s, int attr);
+int message_filtered(char_u *msg);
+void may_clear_sb_text(void);
+void sb_text_start_cmdline(void);
+void sb_text_end_cmdline(void);
+void clear_sb_text(int all);
+void show_sb_text(void);
+void msg_sb_eol(void);
+int msg_use_printf(void);
+void mch_errmsg(char *str);
+void mch_msg(char *str);
+void msg_moremsg(int full);
+void repeat_message(void);
+void msg_clr_eos(void);
+void msg_clr_eos_force(void);
+void msg_clr_cmdline(void);
+int msg_end(void);
+void msg_check(void);
+int redirecting(void);
+void verbose_enter(void);
+void verbose_leave(void);
+void verbose_enter_scroll(void);
+void verbose_leave_scroll(void);
+void verbose_stop(void);
+int verbose_open(void);
+void give_warning(char_u *message, int hl);
+void give_warning2(char_u *message, char_u *a1, int hl);
+void msg_advance(int col);
+int do_dialog(int type, char_u *title, char_u *message, char_u *buttons, int dfltbutton, char_u *textfield, int ex_cmd);
+void display_confirm_msg(void);
+int vim_dialog_yesno(int type, char_u *title, char_u *message, int dflt);
+int vim_dialog_yesnocancel(int type, char_u *title, char_u *message, int dflt);
+int vim_dialog_yesnoallcancel(int type, char_u *title, char_u *message, int dflt);
+char_u *do_browse(int flags, char_u *title, char_u *dflt, char_u *ext, char_u *initdir, char_u *filter, buf_T *buf);
+/* vim: set ft=c : */
diff --git a/src/proto/misc1.pro b/src/proto/misc1.pro
new file mode 100644
index 0000000..1e50f8a
--- /dev/null
+++ b/src/proto/misc1.pro
@@ -0,0 +1,102 @@
+/* misc1.c */
+int get_indent(void);
+int get_indent_lnum(linenr_T lnum);
+int get_indent_buf(buf_T *buf, linenr_T lnum);
+int get_indent_str(char_u *ptr, int ts, int list);
+int get_indent_str_vtab(char_u *ptr, int ts, int *vts, int list);
+int set_indent(int size, int flags);
+int get_number_indent(linenr_T lnum);
+int get_breakindent_win(win_T *wp, char_u *line);
+int open_line(int dir, int flags, int second_line_indent);
+int get_leader_len(char_u *line, char_u **flags, int backward, int include_space);
+int get_last_leader_offset(char_u *line, char_u **flags);
+int plines(linenr_T lnum);
+int plines_win(win_T *wp, linenr_T lnum, int winheight);
+int plines_nofill(linenr_T lnum);
+int plines_win_nofill(win_T *wp, linenr_T lnum, int winheight);
+int plines_win_nofold(win_T *wp, linenr_T lnum);
+int plines_win_col(win_T *wp, linenr_T lnum, long column);
+int plines_m_win(win_T *wp, linenr_T first, linenr_T last);
+void ins_bytes(char_u *p);
+void ins_bytes_len(char_u *p, int len);
+void ins_char(int c);
+void ins_char_bytes(char_u *buf, int charlen);
+void ins_str(char_u *s);
+int del_char(int fixpos);
+int del_chars(long count, int fixpos);
+int del_bytes(long count, int fixpos_arg, int use_delcombine);
+int truncate_line(int fixpos);
+void del_lines(long nlines, int undo);
+int gchar_pos(pos_T *pos);
+int gchar_cursor(void);
+void pchar_cursor(int c);
+int inindent(int extra);
+char_u *skip_to_option_part(char_u *p);
+void changed(void);
+void changed_int(void);
+void changed_bytes(linenr_T lnum, colnr_T col);
+void inserted_bytes(linenr_T lnum, colnr_T col, int added);
+void appended_lines(linenr_T lnum, long count);
+void appended_lines_mark(linenr_T lnum, long count);
+void deleted_lines(linenr_T lnum, long count);
+void deleted_lines_mark(linenr_T lnum, long count);
+void changed_lines(linenr_T lnum, colnr_T col, linenr_T lnume, long xtra);
+void unchanged(buf_T *buf, int ff);
+void check_status(buf_T *buf);
+void change_warning(int col);
+int ask_yesno(char_u *str, int direct);
+int is_mouse_key(int c);
+int get_keystroke(void);
+int get_number(int colon, int *mouse_used);
+int prompt_for_number(int *mouse_used);
+void msgmore(long n);
+void beep_flush(void);
+void vim_beep(unsigned val);
+void init_homedir(void);
+void free_homedir(void);
+void free_users(void);
+char_u *expand_env_save(char_u *src);
+char_u *expand_env_save_opt(char_u *src, int one);
+void expand_env(char_u *src, char_u *dst, int dstlen);
+void expand_env_esc(char_u *srcp, char_u *dst, int dstlen, int esc, int one, char_u *startstr);
+char_u *vim_getenv(char_u *name, int *mustfree);
+void vim_unsetenv(char_u *var);
+void vim_setenv(char_u *name, char_u *val);
+char_u *get_env_name(expand_T *xp, int idx);
+char_u *get_users(expand_T *xp, int idx);
+int match_user(char_u *name);
+void home_replace(buf_T *buf, char_u *src, char_u *dst, int dstlen, int one);
+char_u *home_replace_save(buf_T *buf, char_u *src);
+int fullpathcmp(char_u *s1, char_u *s2, int checkname);
+char_u *gettail(char_u *fname);
+char_u *gettail_sep(char_u *fname);
+char_u *getnextcomp(char_u *fname);
+char_u *get_past_head(char_u *path);
+int vim_ispathsep(int c);
+int vim_ispathsep_nocolon(int c);
+int vim_ispathlistsep(int c);
+void shorten_dir(char_u *str);
+int dir_of_file_exists(char_u *fname);
+int vim_fnamecmp(char_u *x, char_u *y);
+int vim_fnamencmp(char_u *x, char_u *y, size_t len);
+char_u *concat_fnames(char_u *fname1, char_u *fname2, int sep);
+char_u *concat_str(char_u *str1, char_u *str2);
+void add_pathsep(char_u *p);
+char_u *FullName_save(char_u *fname, int force);
+void prepare_to_exit(void);
+void preserve_exit(void);
+int vim_fexists(char_u *fname);
+void line_breakcheck(void);
+void fast_breakcheck(void);
+int expand_wildcards_eval(char_u **pat, int *num_file, char_u ***file, int flags);
+int expand_wildcards(int num_pat, char_u **pat, int *num_files, char_u ***files, int flags);
+int match_suffix(char_u *fname);
+int unix_expandpath(garray_T *gap, char_u *path, int wildoff, int flags, int didstar);
+void remove_duplicates(garray_T *gap);
+int gen_expand_wildcards(int num_pat, char_u **pat, int *num_file, char_u ***file, int flags);
+void addfile(garray_T *gap, char_u *f, int flags);
+char_u *get_cmd_output(char_u *cmd, char_u *infile, int flags, int *ret_len);
+void FreeWild(int count, char_u **files);
+int goto_im(void);
+char_u *get_isolated_shell_name(void);
+/* vim: set ft=c : */
diff --git a/src/proto/misc2.pro b/src/proto/misc2.pro
new file mode 100644
index 0000000..7d33de8
--- /dev/null
+++ b/src/proto/misc2.pro
@@ -0,0 +1,119 @@
+/* misc2.c */
+int virtual_active(void);
+int getviscol(void);
+int coladvance_force(colnr_T wcol);
+int getviscol2(colnr_T col, colnr_T coladd);
+int coladvance(colnr_T wcol);
+int getvpos(pos_T *pos, colnr_T wcol);
+int inc_cursor(void);
+int inc(pos_T *lp);
+int incl(pos_T *lp);
+int dec_cursor(void);
+int dec(pos_T *lp);
+int decl(pos_T *lp);
+linenr_T get_cursor_rel_lnum(win_T *wp, linenr_T lnum);
+void check_pos(buf_T *buf, pos_T *pos);
+void check_cursor_lnum(void);
+void check_cursor_col(void);
+void check_cursor_col_win(win_T *win);
+void check_cursor(void);
+void adjust_cursor_col(void);
+int leftcol_changed(void);
+void vim_mem_profile_dump(void);
+int alloc_does_fail(long_u size);
+char_u *alloc(unsigned size);
+char_u *alloc_id(unsigned size, alloc_id_T id);
+char_u *alloc_clear(unsigned size);
+char_u *alloc_clear_id(unsigned size, alloc_id_T id);
+char_u *alloc_check(unsigned size);
+char_u *lalloc_clear(long_u size, int message);
+char_u *lalloc(long_u size, int message);
+char_u *lalloc_id(long_u size, int message, alloc_id_T id);
+void *mem_realloc(void *ptr, size_t size);
+void do_outofmem_msg(long_u size);
+void free_all_mem(void);
+char_u *vim_strsave(char_u *string);
+char_u *vim_strnsave(char_u *string, int len);
+char_u *vim_memsave(char_u *p, int len);
+char_u *vim_strsave_escaped(char_u *string, char_u *esc_chars);
+char_u *vim_strsave_escaped_ext(char_u *string, char_u *esc_chars, int cc, int bsl);
+int csh_like_shell(void);
+char_u *vim_strsave_shellescape(char_u *string, int do_special, int do_newline);
+char_u *vim_strsave_up(char_u *string);
+char_u *vim_strnsave_up(char_u *string, int len);
+void vim_strup(char_u *p);
+char_u *strup_save(char_u *orig);
+char_u *strlow_save(char_u *orig);
+void del_trailing_spaces(char_u *ptr);
+void vim_strncpy(char_u *to, char_u *from, size_t len);
+void vim_strcat(char_u *to, char_u *from, size_t tosize);
+int copy_option_part(char_u **option, char_u *buf, int maxlen, char *sep_chars);
+void vim_free(void *x);
+int vim_stricmp(char *s1, char *s2);
+int vim_strnicmp(char *s1, char *s2, size_t len);
+char_u *vim_strchr(char_u *string, int c);
+char_u *vim_strbyte(char_u *string, int c);
+char_u *vim_strrchr(char_u *string, int c);
+int vim_isspace(int x);
+void ga_clear(garray_T *gap);
+void ga_clear_strings(garray_T *gap);
+void ga_init(garray_T *gap);
+void ga_init2(garray_T *gap, int itemsize, int growsize);
+int ga_grow(garray_T *gap, int n);
+char_u *ga_concat_strings(garray_T *gap, char *sep);
+void ga_add_string(garray_T *gap, char_u *p);
+void ga_concat(garray_T *gap, char_u *s);
+void ga_append(garray_T *gap, int c);
+void append_ga_line(garray_T *gap);
+int name_to_mod_mask(int c);
+int simplify_key(int key, int *modifiers);
+int handle_x_keys(int key);
+char_u *get_special_key_name(int c, int modifiers);
+int trans_special(char_u **srcp, char_u *dst, int keycode, int in_string);
+int find_special_key(char_u **srcp, int *modp, int keycode, int keep_x_key, int in_string);
+int extract_modifiers(int key, int *modp);
+int find_special_key_in_table(int c);
+int get_special_key_code(char_u *name);
+char_u *get_key_name(int i);
+int get_mouse_button(int code, int *is_click, int *is_drag);
+int get_pseudo_mouse_code(int button, int is_click, int is_drag);
+int get_fileformat(buf_T *buf);
+int get_fileformat_force(buf_T *buf, exarg_T *eap);
+void set_fileformat(int t, int opt_flags);
+int default_fileformat(void);
+int call_shell(char_u *cmd, int opt);
+int get_real_state(void);
+int after_pathsep(char_u *b, char_u *p);
+int same_directory(char_u *f1, char_u *f2);
+int vim_chdirfile(char_u *fname, char *trigger_autocmd);
+int vim_stat(const char *name, stat_T *stp);
+char *parse_shape_opt(int what);
+int get_shape_idx(int mouse);
+void update_mouseshape(int shape_idx);
+void *vim_findfile_init(char_u *path, char_u *filename, char_u *stopdirs, int level, int free_visited, int find_what, void *search_ctx_arg, int tagfile, char_u *rel_fname);
+char_u *vim_findfile_stopdir(char_u *buf);
+void vim_findfile_cleanup(void *ctx);
+char_u *vim_findfile(void *search_ctx_arg);
+void vim_findfile_free_visited(void *search_ctx_arg);
+char_u *find_file_in_path(char_u *ptr, int len, int options, int first, char_u *rel_fname);
+char_u *find_directory_in_path(char_u *ptr, int len, int options, char_u *rel_fname);
+char_u *find_file_in_path_option(char_u *ptr, int len, int options, int first, char_u *path_option, int find_what, char_u *rel_fname, char_u *suffixes);
+int vim_chdir(char_u *new_dir);
+int get_user_name(char_u *buf, int len);
+void sort_strings(char_u **files, int count);
+int pathcmp(const char *p, const char *q, int maxlen);
+int filewritable(char_u *fname);
+int get2c(FILE *fd);
+int get3c(FILE *fd);
+int get4c(FILE *fd);
+time_T get8ctime(FILE *fd);
+char_u *read_string(FILE *fd, int cnt);
+int put_bytes(FILE *fd, long_u nr, int len);
+int put_time(FILE *fd, time_T the_time);
+void time_to_bytes(time_T the_time, char_u *buf);
+int has_non_ascii(char_u *s);
+void parse_queued_messages(void);
+int mch_parse_cmd(char_u *cmd, int use_shcf, char ***argv, int *argc);
+int build_argv_from_string(char_u *cmd, char ***argv, int *argc);
+int build_argv_from_list(list_T *l, char ***argv, int *argc);
+/* vim: set ft=c : */
diff --git a/src/proto/move.pro b/src/proto/move.pro
new file mode 100644
index 0000000..ed45c4d
--- /dev/null
+++ b/src/proto/move.pro
@@ -0,0 +1,43 @@
+/* move.c */
+void reset_cursorline(void);
+void redraw_for_cursorline(win_T *wp);
+void update_topline_redraw(void);
+void update_topline(void);
+void update_curswant(void);
+void check_cursor_moved(win_T *wp);
+void changed_window_setting(void);
+void changed_window_setting_win(win_T *wp);
+void set_topline(win_T *wp, linenr_T lnum);
+void changed_cline_bef_curs(void);
+void changed_cline_bef_curs_win(win_T *wp);
+void changed_line_abv_curs(void);
+void changed_line_abv_curs_win(win_T *wp);
+void validate_botline(void);
+void invalidate_botline(void);
+void invalidate_botline_win(win_T *wp);
+void approximate_botline_win(win_T *wp);
+int cursor_valid(void);
+void validate_cursor(void);
+void validate_cline_row(void);
+void validate_virtcol(void);
+void validate_virtcol_win(win_T *wp);
+void validate_cursor_col(void);
+int win_col_off(win_T *wp);
+int curwin_col_off(void);
+int win_col_off2(win_T *wp);
+int curwin_col_off2(void);
+void curs_columns(int may_scroll);
+void scrolldown(long line_count, int byfold);
+void scrollup(long line_count, int byfold);
+void check_topfill(win_T *wp, int down);
+void scrolldown_clamp(void);
+void scrollup_clamp(void);
+void scroll_cursor_top(int min_scroll, int always);
+void set_empty_rows(win_T *wp, int used);
+void scroll_cursor_bot(int min_scroll, int set_topbot);
+void scroll_cursor_halfway(int atend);
+void cursor_correct(void);
+int onepage(int dir, long count);
+void halfpage(int flag, linenr_T Prenum);
+void do_check_cursorbind(void);
+/* vim: set ft=c : */
diff --git a/src/proto/netbeans.pro b/src/proto/netbeans.pro
new file mode 100644
index 0000000..869e966
--- /dev/null
+++ b/src/proto/netbeans.pro
@@ -0,0 +1,28 @@
+/* netbeans.c */
+void netbeans_parse_messages(void);
+int isNetbeansBuffer(buf_T *bufp);
+int isNetbeansModified(buf_T *bufp);
+void netbeans_end(void);
+void ex_nbclose(exarg_T *eap);
+void ex_nbkey(exarg_T *eap);
+void ex_nbstart(exarg_T *eap);
+void netbeans_beval_cb(BalloonEval *beval, int state);
+int netbeans_active(void);
+void netbeans_open(char *params, int doabort);
+void netbeans_send_disconnect(void);
+int set_ref_in_nb_channel(int copyID);
+void netbeans_frame_moved(int new_x, int new_y);
+void netbeans_file_activated(buf_T *bufp);
+void netbeans_file_opened(buf_T *bufp);
+void netbeans_file_killed(buf_T *bufp);
+void netbeans_inserted(buf_T *bufp, linenr_T linenr, colnr_T col, char_u *txt, int newlen);
+void netbeans_removed(buf_T *bufp, linenr_T linenr, colnr_T col, long len);
+void netbeans_unmodified(buf_T *bufp);
+void netbeans_button_release(int button);
+int netbeans_keycommand(int key);
+void netbeans_save_buffer(buf_T *bufp);
+void netbeans_deleted_all_lines(buf_T *bufp);
+int netbeans_is_guarded(linenr_T top, linenr_T bot);
+void netbeans_draw_multisign_indicator(int row);
+void netbeans_gutter_click(linenr_T lnum);
+/* vim: set ft=c : */
diff --git a/src/proto/normal.pro b/src/proto/normal.pro
new file mode 100644
index 0000000..55d12bb
--- /dev/null
+++ b/src/proto/normal.pro
@@ -0,0 +1,26 @@
+/* normal.c */
+void init_normal_cmds(void);
+void normal_cmd(oparg_T *oap, int toplevel);
+void do_pending_operator(cmdarg_T *cap, int old_col, int gui_yank);
+int do_mouse(oparg_T *oap, int c, int dir, long count, int fixindent);
+void check_visual_highlight(void);
+void end_visual_mode(void);
+void reset_VIsual_and_resel(void);
+void reset_VIsual(void);
+int find_ident_under_cursor(char_u **string, int find_type);
+int find_ident_at_pos(win_T *wp, linenr_T lnum, colnr_T startcol, char_u **string, int find_type);
+void clear_showcmd(void);
+int add_to_showcmd(int c);
+void add_to_showcmd_c(int c);
+void push_showcmd(void);
+void pop_showcmd(void);
+void do_check_scrollbind(int check);
+void check_scrollbind(linenr_T topline_diff, long leftcol_diff);
+int find_decl(char_u *ptr, int len, int locally, int thisblock, int flags_arg);
+void scroll_redraw(int up, long count);
+void handle_tabmenu(void);
+void do_nv_ident(int c1, int c2);
+int get_visual_text(cmdarg_T *cap, char_u **pp, int *lenp);
+void start_selection(void);
+void may_start_select(int c);
+/* vim: set ft=c : */
diff --git a/src/proto/ops.pro b/src/proto/ops.pro
new file mode 100644
index 0000000..01df56f
--- /dev/null
+++ b/src/proto/ops.pro
@@ -0,0 +1,68 @@
+/* ops.c */
+int get_op_type(int char1, int char2);
+int op_on_lines(int op);
+int op_is_change(int op);
+int get_op_char(int optype);
+int get_extra_op_char(int optype);
+void op_shift(oparg_T *oap, int curs_top, int amount);
+void shift_line(int left, int round, int amount, int call_changed_bytes);
+void op_reindent(oparg_T *oap, int (*how)(void));
+int get_expr_register(void);
+void set_expr_line(char_u *new_line);
+char_u *get_expr_line(void);
+char_u *get_expr_line_src(void);
+int valid_yank_reg(int regname, int writing);
+int get_yank_register(int regname, int writing);
+int may_get_selection(int regname);
+void *get_register(int name, int copy);
+void put_register(int name, void *reg);
+void free_register(void *reg);
+int yank_register_mline(int regname);
+int do_record(int c);
+int do_execreg(int regname, int colon, int addcr, int silent);
+int insert_reg(int regname, int literally_arg);
+int get_spec_reg(int regname, char_u **argp, int *allocated, int errmsg);
+int cmdline_paste_reg(int regname, int literally_arg, int remcr);
+void adjust_clip_reg(int *rp);
+void shift_delete_registers(void);
+int op_delete(oparg_T *oap);
+int op_replace(oparg_T *oap, int c);
+void op_tilde(oparg_T *oap);
+int swapchar(int op_type, pos_T *pos);
+void op_insert(oparg_T *oap, long count1);
+int op_change(oparg_T *oap);
+void init_yank(void);
+void clear_registers(void);
+int op_yank(oparg_T *oap, int deleting, int mess);
+void do_put(int regname, int dir, long count, int flags);
+void adjust_cursor_eol(void);
+int preprocs_left(void);
+int get_register_name(int num);
+void ex_display(exarg_T *eap);
+char_u *skip_comment(char_u *line, int process, int include_space, int *is_comment);
+int do_join(long count, int insert_space, int save_undo, int use_formatoptions, int setmark);
+void op_format(oparg_T *oap, int keep_cursor);
+void op_formatexpr(oparg_T *oap);
+int fex_format(linenr_T lnum, long count, int c);
+void format_lines(linenr_T line_count, int avoid_fex);
+int paragraph_start(linenr_T lnum);
+void op_addsub(oparg_T *oap, linenr_T Prenum1, int g_cmd);
+void prepare_viminfo_registers(void);
+void finish_viminfo_registers(void);
+int read_viminfo_register(vir_T *virp, int force);
+void handle_viminfo_register(garray_T *values, int force);
+void write_viminfo_registers(FILE *fp);
+void x11_export_final_selection(void);
+void clip_free_selection(VimClipboard *cbd);
+void clip_get_selection(VimClipboard *cbd);
+void clip_yank_selection(int type, char_u *str, long len, VimClipboard *cbd);
+int clip_convert_selection(char_u **str, long_u *len, VimClipboard *cbd);
+void dnd_yank_drag_data(char_u *str, long len);
+char_u get_reg_type(int regname, long *reglen);
+char_u *get_reg_contents(int regname, int flags);
+void write_reg_contents(int name, char_u *str, int maxlen, int must_append);
+void write_reg_contents_lst(int name, char_u **strings, int maxlen, int must_append, int yank_type, long block_len);
+void write_reg_contents_ex(int name, char_u *str, int maxlen, int must_append, int yank_type, long block_len);
+void clear_oparg(oparg_T *oap);
+void cursor_pos_info(dict_T *dict);
+/* vim: set ft=c : */
diff --git a/src/proto/option.pro b/src/proto/option.pro
new file mode 100644
index 0000000..1027edf
--- /dev/null
+++ b/src/proto/option.pro
@@ -0,0 +1,85 @@
+/* option.c */
+void set_init_1(int clean_arg);
+void set_string_default(char *name, char_u *val);
+void set_number_default(char *name, long val);
+void free_all_options(void);
+void set_init_2(void);
+void set_init_3(void);
+void set_helplang_default(char_u *lang);
+void init_gui_options(void);
+void set_title_defaults(void);
+int do_set(char_u *arg, int opt_flags);
+int string_to_key(char_u *arg, int multi_byte);
+void set_options_bin(int oldval, int newval, int opt_flags);
+int get_viminfo_parameter(int type);
+char_u *find_viminfo_parameter(int type);
+void check_options(void);
+void check_buf_options(buf_T *buf);
+void free_string_option(char_u *p);
+void clear_string_option(char_u **pp);
+int get_term_opt_idx(char_u **p);
+int set_term_option_alloced(char_u **p);
+int was_set_insecurely(char_u *opt, int opt_flags);
+void set_string_option_direct(char_u *name, int opt_idx, char_u *val, int opt_flags, int set_sid);
+char *check_colorcolumn(win_T *wp);
+char *check_stl_option(char_u *s);
+void set_term_option_sctx_idx(char *name, int opt_idx);
+int get_option_value(char_u *name, long *numval, char_u **stringval, int opt_flags);
+int get_option_value_strict(char_u *name, long *numval, char_u **stringval, int opt_type, void *from);
+char_u *option_iter_next(void **option, int opt_type);
+char *set_option_value(char_u *name, long number, char_u *string, int opt_flags);
+char_u *get_term_code(char_u *tname);
+char_u *get_highlight_default(void);
+char_u *get_encoding_default(void);
+int makeset(FILE *fd, int opt_flags, int local_only);
+int makefoldset(FILE *fd);
+void clear_termoptions(void);
+void free_termoptions(void);
+void free_one_termoption(char_u *var);
+void set_term_defaults(void);
+void comp_col(void);
+void unset_global_local_option(char_u *name, void *from);
+char_u *get_equalprg(void);
+void win_copy_options(win_T *wp_from, win_T *wp_to);
+void copy_winopt(winopt_T *from, winopt_T *to);
+void check_win_options(win_T *win);
+void clear_winopt(winopt_T *wop);
+void buf_copy_options(buf_T *buf, int flags);
+void reset_modifiable(void);
+void set_iminsert_global(void);
+void set_imsearch_global(void);
+void set_context_in_set_cmd(expand_T *xp, char_u *arg, int opt_flags);
+int ExpandSettings(expand_T *xp, regmatch_T *regmatch, int *num_file, char_u ***file);
+int ExpandOldSetting(int *num_file, char_u ***file);
+int langmap_adjust_mb(int c);
+int has_format_option(int x);
+int shortmess(int x);
+void vimrc_found(char_u *fname, char_u *envname);
+void change_compatible(int on);
+int option_was_set(char_u *name);
+int reset_option_was_set(char_u *name);
+int can_bs(int what);
+void save_file_ff(buf_T *buf);
+int file_ff_differs(buf_T *buf, int ignore_empty);
+int check_ff_value(char_u *p);
+int tabstop_set(char_u *var, int **array);
+int tabstop_padding(colnr_T col, int ts_arg, int *vts);
+int tabstop_at(colnr_T col, int ts, int *vts);
+colnr_T tabstop_start(colnr_T col, int ts, int *vts);
+void tabstop_fromto(colnr_T start_col, colnr_T end_col, int ts_arg, int *vts, int *ntabs, int *nspcs);
+int tabstop_eq(int *ts1, int *ts2);
+int *tabstop_copy(int *oldts);
+int tabstop_count(int *ts);
+int tabstop_first(int *ts);
+long get_sw_value(buf_T *buf);
+long get_sw_value_indent(buf_T *buf);
+long get_sw_value_pos(buf_T *buf, pos_T *pos);
+long get_sw_value_col(buf_T *buf, colnr_T col);
+long get_sts_value(void);
+long get_scrolloff_value(void);
+long get_sidescrolloff_value(void);
+void find_mps_values(int *initc, int *findc, int *backwards, int switchit);
+unsigned int get_bkc_value(buf_T *buf);
+int signcolumn_on(win_T *wp);
+dict_T *get_winbuf_options(int bufopt);
+/* vim: set ft=c : */
diff --git a/src/proto/os_amiga.pro b/src/proto/os_amiga.pro
new file mode 100644
index 0000000..b781680
--- /dev/null
+++ b/src/proto/os_amiga.pro
@@ -0,0 +1,46 @@
+/* os_amiga.c */
+void win_resize_on(void);
+void win_resize_off(void);
+void mch_write(char_u *p, int len);
+int mch_inchar(char_u *buf, int maxlen, long time, int tb_change_cnt);
+int mch_char_avail(void);
+long_u mch_avail_mem(int special);
+void mch_delay(long msec, int ignoreinput);
+void mch_suspend(void);
+void mch_init(void);
+int mch_check_win(int argc, char **argv);
+int mch_input_isatty(void);
+void fname_case(char_u *name, int len);
+void mch_settitle(char_u *title, char_u *icon);
+void mch_restore_title(int which);
+int mch_can_restore_title(void);
+int mch_can_restore_icon(void);
+int mch_get_user_name(char_u *s, int len);
+void mch_get_host_name(char_u *s, int len);
+long mch_get_pid(void);
+int mch_dirname(char_u *buf, int len);
+int mch_FullName(char_u *fname, char_u *buf, int len, int force);
+int mch_isFullName(char_u *fname);
+long mch_getperm(char_u *name);
+int mch_setperm(char_u *name, long perm);
+void mch_hide(char_u *name);
+int mch_isdir(char_u *name);
+int mch_mkdir(char_u *name);
+int mch_can_exe(char_u *name, char_u **path, int use_path);
+int mch_nodetype(char_u *name);
+void mch_early_init(void);
+void mch_exit(int r);
+void mch_settmode(int tmode);
+int mch_screenmode(char_u *arg);
+int mch_get_shellsize(void);
+void mch_set_shellsize(void);
+void mch_new_shellsize(void);
+int mch_call_shell(char_u *cmd, int options);
+void mch_breakcheck(int force);
+long Chk_Abort(void);
+int mch_expandpath(garray_T *gap, char_u *pat, int flags);
+int mch_has_exp_wildcard(char_u *p);
+int mch_has_wildcard(char_u *p);
+char_u *mch_getenv(char_u *var);
+int mch_setenv(char *var, char *value, int x);
+/* vim: set ft=c : */
diff --git a/src/proto/os_beos.pro b/src/proto/os_beos.pro
new file mode 100644
index 0000000..bccf45d
--- /dev/null
+++ b/src/proto/os_beos.pro
@@ -0,0 +1,4 @@
+/* os_beos.c */
+void beos_cleanup_read_thread(void);
+int beos_select(int nbits, struct fd_set *rbits, struct fd_set *wbits, struct fd_set *ebits, struct timeval *timeout);
+/* vim: set ft=c : */
diff --git a/src/proto/os_mac_conv.pro b/src/proto/os_mac_conv.pro
new file mode 100644
index 0000000..e86e408
--- /dev/null
+++ b/src/proto/os_mac_conv.pro
@@ -0,0 +1,12 @@
+/* os_mac_conv.c */
+char_u *mac_string_convert(char_u *ptr, int len, int *lenp, int fail_on_error, int from_enc, int to_enc, int *unconvlenp);
+int macroman2enc(char_u *ptr, long *sizep, long real_size);
+int enc2macroman(char_u *from, size_t fromlen, char_u *to, int *tolenp, int maxtolen, char_u *rest, int *restlenp);
+void mac_conv_init(void);
+void mac_conv_cleanup(void);
+char_u *mac_utf16_to_enc(unsigned short *from, size_t fromLen, size_t *actualLen);
+unsigned short *mac_enc_to_utf16(char_u *from, size_t fromLen, size_t *actualLen);
+void *mac_enc_to_cfstring(char_u *from, size_t fromLen);
+char_u *mac_precompose_path(char_u *decompPath, size_t decompLen, size_t *precompLen);
+void mac_lang_init(void);
+/* vim: set ft=c : */
diff --git a/src/proto/os_mswin.pro b/src/proto/os_mswin.pro
new file mode 100644
index 0000000..cc660a6
--- /dev/null
+++ b/src/proto/os_mswin.pro
@@ -0,0 +1,54 @@
+/* os_mswin.c */
+void mch_exit(int r);
+void mch_early_init(void);
+int mch_input_isatty(void);
+void mch_settitle(char_u *title, char_u *icon);
+void mch_restore_title(int which);
+int mch_can_restore_title(void);
+int mch_can_restore_icon(void);
+int mch_FullName(char_u *fname, char_u *buf, int len, int force);
+int mch_isFullName(char_u *fname);
+void slash_adjust(char_u *p);
+int vim_stat(const char *name, stat_T *stp);
+void mch_settmode(int tmode);
+int mch_get_shellsize(void);
+void mch_set_shellsize(void);
+void mch_new_shellsize(void);
+void mch_suspend(void);
+void display_errors(void);
+int mch_has_exp_wildcard(char_u *p);
+int mch_has_wildcard(char_u *p);
+int mch_chdir(char *path);
+int mch_screenmode(char_u *arg);
+int mch_icon_load(HANDLE *iconp);
+int mch_libcall(char_u *libname, char_u *funcname, char_u *argstring, int argint, char_u **string_result, int *number_result);
+void DumpPutS(const char *psz);
+int mch_get_winpos(int *x, int *y);
+void mch_set_winpos(int x, int y);
+void mch_print_cleanup(void);
+int mch_print_init(prt_settings_T *psettings, char_u *jobname, int forceit);
+int mch_print_begin(prt_settings_T *psettings);
+void mch_print_end(prt_settings_T *psettings);
+int mch_print_end_page(void);
+int mch_print_begin_page(char_u *msg);
+int mch_print_blank_page(void);
+void mch_print_start_line(int margin, int page_line);
+int mch_print_text_out(char_u *p, int len);
+void mch_print_set_font(int iBold, int iItalic, int iUnderline);
+void mch_print_set_bg(long_u bgcol);
+void mch_print_set_fg(long_u fgcol);
+char_u *mch_resolve_shortcut(char_u *fname);
+void win32_set_foreground(void);
+void serverInitMessaging(void);
+void serverSetName(char_u *name);
+char_u *serverGetVimNames(void);
+int serverSendReply(char_u *name, char_u *reply);
+int serverSendToVim(char_u *name, char_u *cmd, char_u **result, void *ptarget, int asExpr, int timeout, int silent);
+void serverForeground(char_u *name);
+char_u *serverGetReply(HWND server, int *expr_res, int remove, int wait, int timeout);
+void serverProcessPendingMessages(void);
+char *charset_id2name(int id);
+char *quality_id2name(DWORD id);
+int get_logfont(LOGFONT *lf, char_u *name, HDC printer_dc, int verbose);
+void channel_init_winsock(void);
+/* vim: set ft=c : */
diff --git a/src/proto/os_qnx.pro b/src/proto/os_qnx.pro
new file mode 100644
index 0000000..89a250f
--- /dev/null
+++ b/src/proto/os_qnx.pro
@@ -0,0 +1,8 @@
+/* os_qnx.c */
+void qnx_init(void);
+void qnx_clip_init (void);
+int clip_mch_own_selection(VimClipboard *cbd);
+void clip_mch_lose_selection(VimClipboard *cbd);
+void clip_mch_request_selection(VimClipboard *cbd);
+void clip_mch_set_selection(VimClipboard *cbd);
+/* vim: set ft=c : */
diff --git a/src/proto/os_unix.pro b/src/proto/os_unix.pro
new file mode 100644
index 0000000..224fe98
--- /dev/null
+++ b/src/proto/os_unix.pro
@@ -0,0 +1,86 @@
+/* os_unix.c */
+int mch_chdir(char *path);
+void mch_write(char_u *s, int len);
+int mch_inchar(char_u *buf, int maxlen, long wtime, int tb_change_cnt);
+int mch_char_avail(void);
+int mch_check_messages(void);
+long_u mch_total_mem(int special);
+void mch_delay(long msec, int ignoreinput);
+int mch_stackcheck(char *p);
+void mch_suspend(void);
+void mch_init(void);
+void reset_signals(void);
+int vim_handle_signal(int sig);
+int mch_check_win(int argc, char **argv);
+int mch_input_isatty(void);
+int mch_can_restore_title(void);
+int mch_can_restore_icon(void);
+void mch_settitle(char_u *title, char_u *icon);
+void mch_restore_title(int which);
+int vim_is_xterm(char_u *name);
+int use_xterm_like_mouse(char_u *name);
+int use_xterm_mouse(void);
+int vim_is_iris(char_u *name);
+int vim_is_vt300(char_u *name);
+int vim_is_fastterm(char_u *name);
+int mch_get_user_name(char_u *s, int len);
+int mch_get_uname(uid_t uid, char_u *s, int len);
+void mch_get_host_name(char_u *s, int len);
+long mch_get_pid(void);
+int mch_dirname(char_u *buf, int len);
+int mch_FullName(char_u *fname, char_u *buf, int len, int force);
+int mch_isFullName(char_u *fname);
+void fname_case(char_u *name, int len);
+long mch_getperm(char_u *name);
+int mch_setperm(char_u *name, long perm);
+int mch_fsetperm(int fd, long perm);
+void mch_copy_sec(char_u *from_file, char_u *to_file);
+vim_acl_T mch_get_acl(char_u *fname);
+void mch_set_acl(char_u *fname, vim_acl_T aclent);
+void mch_free_acl(vim_acl_T aclent);
+void mch_hide(char_u *name);
+int mch_isdir(char_u *name);
+int mch_isrealdir(char_u *name);
+int mch_can_exe(char_u *name, char_u **path, int use_path);
+int mch_nodetype(char_u *name);
+void mch_early_init(void);
+void mch_free_mem(void);
+void mch_exit(int r);
+void mch_settmode(int tmode);
+void get_stty(void);
+int get_tty_info(int fd, ttyinfo_T *info);
+void mch_setmouse(int on);
+void mch_bevalterm_changed(void);
+void check_mouse_termcode(void);
+int mch_screenmode(char_u *arg);
+int mch_get_shellsize(void);
+int mch_report_winsize(int fd, int rows, int cols);
+void mch_set_shellsize(void);
+void mch_new_shellsize(void);
+void may_send_sigint(int c, pid_t pid, pid_t wpid);
+int mch_call_shell(char_u *cmd, int options);
+void mch_job_start(char **argv, job_T *job, jobopt_T *options, int is_terminal);
+char *mch_job_status(job_T *job);
+job_T *mch_detect_ended_job(job_T *job_list);
+int mch_signal_job(job_T *job, char_u *how);
+void mch_clear_job(job_T *job);
+int mch_create_pty_channel(job_T *job, jobopt_T *options);
+void mch_breakcheck(int force);
+int mch_expandpath(garray_T *gap, char_u *path, int flags);
+int mch_expand_wildcards(int num_pat, char_u **pat, int *num_file, char_u ***file, int flags);
+int mch_has_exp_wildcard(char_u *p);
+int mch_has_wildcard(char_u *p);
+int mch_rename(const char *src, const char *dest);
+int mch_libcall(char_u *libname, char_u *funcname, char_u *argstring, int argint, char_u **string_result, int *number_result);
+void setup_term_clip(void);
+void start_xterm_trace(int button);
+void stop_xterm_trace(void);
+void clear_xterm_clip(void);
+int clip_xterm_own_selection(VimClipboard *cbd);
+void clip_xterm_lose_selection(VimClipboard *cbd);
+void clip_xterm_request_selection(VimClipboard *cbd);
+void clip_xterm_set_selection(VimClipboard *cbd);
+int xsmp_handle_requests(void);
+void xsmp_init(void);
+void xsmp_close(void);
+/* vim: set ft=c : */
diff --git a/src/proto/os_vms.pro b/src/proto/os_vms.pro
new file mode 100644
index 0000000..c1cfd44
--- /dev/null
+++ b/src/proto/os_vms.pro
@@ -0,0 +1,16 @@
+/* os_vms.c */
+void mch_settmode(int tmode);
+int mch_get_shellsize(void);
+void mch_set_shellsize(void);
+char_u *mch_getenv(char_u *lognam);
+int mch_setenv(char *var, char *value, int x);
+int vms_sys(char *cmd, char *out, char *inp);
+char *vms_tolower(char *name);
+int vms_sys_status(int status);
+int vms_read(char *inbuf, size_t nbytes);
+int mch_expand_wildcards(int num_pat, char_u **pat, int *num_file, char_u ***file, int flags);
+int mch_expandpath(garray_T *gap, char_u *path, int flags);
+void *vms_fixfilename(void *instring);
+void vms_remove_version(void *fname);
+int RealWaitForChar(int fd, long msec, int *check_for_gpm, int *interrupted);
+/* vim: set ft=c : */
diff --git a/src/proto/os_win32.pro b/src/proto/os_win32.pro
new file mode 100644
index 0000000..7f45c5c
--- /dev/null
+++ b/src/proto/os_win32.pro
@@ -0,0 +1,76 @@
+/* os_win32.c */
+HINSTANCE vimLoadLib(char *name);
+HINSTANCE find_imported_module_by_funcname(HINSTANCE hInst, const char *funcname);
+void *get_dll_import_func(HINSTANCE hInst, const char *funcname);
+int dyn_libintl_init(void);
+void dyn_libintl_end(void);
+void PlatformId(void);
+void mch_setmouse(int on);
+void mch_bevalterm_changed(void);
+void mch_update_cursor(void);
+int mch_char_avail(void);
+int mch_check_messages(void);
+int mch_inchar(char_u *buf, int maxlen, long time, int tb_change_cnt);
+void mch_init(void);
+void mch_exit(int r);
+int mch_check_win(int argc, char **argv);
+void fname_case(char_u *name, int len);
+int mch_get_user_name(char_u *s, int len);
+void mch_get_host_name(char_u *s, int len);
+long mch_get_pid(void);
+int mch_dirname(char_u *buf, int len);
+long mch_getperm(char_u *name);
+int mch_setperm(char_u *name, long perm);
+void mch_hide(char_u *name);
+int mch_ishidden(char_u *name);
+int mch_isdir(char_u *name);
+int mch_isrealdir(char_u *name);
+int mch_mkdir(char_u *name);
+int mch_rmdir(char_u *name);
+int mch_is_hard_link(char_u *fname);
+int mch_is_symbolic_link(char_u *name);
+int mch_is_linked(char_u *fname);
+int win32_fileinfo(char_u *fname, BY_HANDLE_FILE_INFORMATION *info);
+int mch_writable(char_u *name);
+int mch_can_exe(char_u *name, char_u **path, int use_path);
+int mch_nodetype(char_u *name);
+vim_acl_T mch_get_acl(char_u *fname);
+void mch_set_acl(char_u *fname, vim_acl_T acl);
+void mch_free_acl(vim_acl_T acl);
+void mch_settmode(int tmode);
+int mch_get_shellsize(void);
+void mch_set_shellsize(void);
+void mch_new_shellsize(void);
+void mch_set_winsize_now(void);
+int mch_call_shell(char_u *cmd, int options);
+void win32_build_env(dict_T *env, garray_T *gap, int is_terminal);
+void mch_job_start(char *cmd, job_T *job, jobopt_T *options);
+char *mch_job_status(job_T *job);
+job_T *mch_detect_ended_job(job_T *job_list);
+int mch_signal_job(job_T *job, char_u *how);
+void mch_clear_job(job_T *job);
+void mch_set_normal_colors(void);
+void mch_write(char_u *s, int len);
+void mch_delay(long msec, int ignoreinput);
+int mch_remove(char_u *name);
+void mch_breakcheck(int force);
+long_u mch_total_mem(int special);
+int mch_wrename(WCHAR *wold, WCHAR *wnew);
+int mch_rename(const char *pszOldFile, const char *pszNewFile);
+char *default_shell(void);
+int mch_access(char *n, int p);
+int mch_open(const char *name, int flags, int mode);
+FILE *mch_fopen(const char *name, const char *mode);
+int mch_copy_file_attribute(char_u *from, char_u *to);
+int myresetstkoflw(void);
+int get_cmd_argsW(char ***argvp);
+void free_cmd_argsW(void);
+void used_file_arg(char *name, int literal, int full_path, int diff_mode);
+void set_alist_count(void);
+void fix_arg_enc(void);
+int mch_setenv(char *var, char *value, int x);
+void control_console_color_rgb(void);
+int has_vtp_working(void);
+int use_vtp(void);
+int is_term_win32(void);
+/* vim: set ft=c : */
diff --git a/src/proto/popupmnu.pro b/src/proto/popupmnu.pro
new file mode 100644
index 0000000..e2ae92a
--- /dev/null
+++ b/src/proto/popupmnu.pro
@@ -0,0 +1,17 @@
+/* popupmnu.c */
+void pum_display(pumitem_T *array, int size, int selected);
+void pum_call_update_screen(void);
+int pum_under_menu(int row, int col);
+void pum_redraw(void);
+void pum_undisplay(void);
+void pum_clear(void);
+int pum_visible(void);
+void pum_may_redraw(void);
+int pum_get_height(void);
+int split_message(char_u *mesg, pumitem_T **array);
+void ui_remove_balloon(void);
+void ui_post_balloon(char_u *mesg, list_T *list);
+void ui_may_remove_balloon(void);
+void pum_show_popupmenu(vimmenu_T *menu);
+void pum_make_popup(char_u *path_name, int use_mouse_pos);
+/* vim: set ft=c : */
diff --git a/src/proto/pty.pro b/src/proto/pty.pro
new file mode 100644
index 0000000..52e20ef
--- /dev/null
+++ b/src/proto/pty.pro
@@ -0,0 +1,5 @@
+/* pty.c */
+int setup_slavepty(int fd);
+int mch_openpty(char **ttyn);
+int mch_isatty(int fd);
+/* vim: set ft=c : */
diff --git a/src/proto/quickfix.pro b/src/proto/quickfix.pro
new file mode 100644
index 0000000..a71f343
--- /dev/null
+++ b/src/proto/quickfix.pro
@@ -0,0 +1,34 @@
+/* quickfix.c */
+int qf_init(win_T *wp, char_u *efile, char_u *errorformat, int newlist, char_u *qf_title, char_u *enc);
+void qf_free_all(win_T *wp);
+void check_quickfix_busy(void);
+void copy_loclist_stack(win_T *from, win_T *to);
+void qf_jump(qf_info_T *qi, int dir, int errornr, int forceit);
+void qf_jump_newwin(qf_info_T *qi, int dir, int errornr, int forceit, int newwin);
+void qf_list(exarg_T *eap);
+void qf_age(exarg_T *eap);
+void qf_history(exarg_T *eap);
+void qf_mark_adjust(win_T *wp, linenr_T line1, linenr_T line2, long amount, long amount_after);
+void qf_view_result(int split);
+void ex_cwindow(exarg_T *eap);
+void ex_cclose(exarg_T *eap);
+void ex_copen(exarg_T *eap);
+void ex_cbottom(exarg_T *eap);
+linenr_T qf_current_entry(win_T *wp);
+int grep_internal(cmdidx_T cmdidx);
+void ex_make(exarg_T *eap);
+int qf_get_size(exarg_T *eap);
+int qf_get_cur_idx(exarg_T *eap);
+int qf_get_cur_valid_idx(exarg_T *eap);
+void ex_cc(exarg_T *eap);
+void ex_cnext(exarg_T *eap);
+void ex_cfile(exarg_T *eap);
+void ex_vimgrep(exarg_T *eap);
+int get_errorlist(qf_info_T *qi_arg, win_T *wp, int qf_idx, list_T *list);
+int qf_get_properties(win_T *wp, dict_T *what, dict_T *retdict);
+int set_errorlist(win_T *wp, list_T *list, int action, char_u *title, dict_T *what);
+int set_ref_in_quickfix(int copyID);
+void ex_cbuffer(exarg_T *eap);
+void ex_cexpr(exarg_T *eap);
+void ex_helpgrep(exarg_T *eap);
+/* vim: set ft=c : */
diff --git a/src/proto/regexp.pro b/src/proto/regexp.pro
new file mode 100644
index 0000000..490bda4
--- /dev/null
+++ b/src/proto/regexp.pro
@@ -0,0 +1,20 @@
+/* regexp.c */
+int re_multiline(regprog_T *prog);
+char_u *skip_regexp(char_u *startp, int dirc, int magic, char_u **newp);
+int vim_regcomp_had_eol(void);
+void free_regexp_stuff(void);
+reg_extmatch_T *ref_extmatch(reg_extmatch_T *em);
+void unref_extmatch(reg_extmatch_T *em);
+char_u *regtilde(char_u *source, int magic);
+int vim_regsub(regmatch_T *rmp, char_u *source, typval_T *expr, char_u *dest, int copy, int magic, int backslash);
+int vim_regsub_multi(regmmatch_T *rmp, linenr_T lnum, char_u *source, char_u *dest, int copy, int magic, int backslash);
+char_u *reg_submatch(int no);
+list_T *reg_submatch_list(int no);
+regprog_T *vim_regcomp(char_u *expr_arg, int re_flags);
+void vim_regfree(regprog_T *prog);
+int regprog_in_use(regprog_T *prog);
+int vim_regexec_prog(regprog_T **prog, int ignore_case, char_u *line, colnr_T col);
+int vim_regexec(regmatch_T *rmp, char_u *line, colnr_T col);
+int vim_regexec_nl(regmatch_T *rmp, char_u *line, colnr_T col);
+long vim_regexec_multi(regmmatch_T *rmp, win_T *win, buf_T *buf, linenr_T lnum, colnr_T col, proftime_T *tm, int *timed_out);
+/* vim: set ft=c : */
diff --git a/src/proto/screen.pro b/src/proto/screen.pro
new file mode 100644
index 0000000..0657831
--- /dev/null
+++ b/src/proto/screen.pro
@@ -0,0 +1,64 @@
+/* screen.c */
+void redraw_later(int type);
+void redraw_win_later(win_T *wp, int type);
+void redraw_later_clear(void);
+void redraw_all_later(int type);
+void redraw_curbuf_later(int type);
+void redraw_buf_later(buf_T *buf, int type);
+void redraw_buf_line_later(buf_T *buf, linenr_T lnum);
+void redraw_buf_and_status_later(buf_T *buf, int type);
+int redraw_asap(int type);
+void redraw_after_callback(int call_update_screen);
+void redrawWinline(win_T *wp, linenr_T lnum);
+void reset_updating_screen(int may_resize_shell);
+void update_curbuf(int type);
+int update_screen(int type_arg);
+int conceal_cursor_line(win_T *wp);
+void conceal_check_cursor_line(void);
+void update_debug_sign(buf_T *buf, linenr_T lnum);
+void updateWindow(win_T *wp);
+int screen_get_current_line_off(void);
+void screen_line(int row, int coloff, int endcol, int clear_width, int rlflag);
+void rl_mirror(char_u *str);
+void status_redraw_all(void);
+void status_redraw_curbuf(void);
+void redraw_statuslines(void);
+void win_redraw_last_status(frame_T *frp);
+void win_redr_status_matches(expand_T *xp, int num_matches, char_u **matches, int match, int showtail);
+int stl_connected(win_T *wp);
+int get_keymap_str(win_T *wp, char_u *fmt, char_u *buf, int len);
+void screen_putchar(int c, int row, int col, int attr);
+void screen_getbytes(int row, int col, char_u *bytes, int *attrp);
+void screen_puts(char_u *text, int row, int col, int attr);
+void screen_puts_len(char_u *text, int textlen, int row, int col, int attr);
+void screen_stop_highlight(void);
+void reset_cterm_colors(void);
+void screen_draw_rectangle(int row, int col, int height, int width, int invert);
+void screen_fill(int start_row, int end_row, int start_col, int end_col, int c1, int c2, int attr);
+void check_for_delay(int check_msg_scroll);
+int screen_valid(int doclear);
+void screenalloc(int doclear);
+void free_screenlines(void);
+void screenclear(void);
+int can_clear(char_u *p);
+void screen_start(void);
+void windgoto(int row, int col);
+void setcursor(void);
+void setcursor_mayforce(int force);
+int win_ins_lines(win_T *wp, int row, int line_count, int invalid, int mayclear);
+int win_del_lines(win_T *wp, int row, int line_count, int invalid, int mayclear, int clear_attr);
+int screen_ins_lines(int off, int row, int line_count, int end, int clear_attr, win_T *wp);
+int screen_del_lines(int off, int row, int line_count, int end, int force, int clear_attr, win_T *wp);
+int skip_showmode(void);
+int showmode(void);
+void unshowmode(int force);
+void clearmode(void);
+void draw_tabline(void);
+void get_trans_bufname(buf_T *buf);
+int redrawing(void);
+int messaging(void);
+void showruler(int always);
+int number_width(win_T *wp);
+int screen_screencol(void);
+int screen_screenrow(void);
+/* vim: set ft=c : */
diff --git a/src/proto/search.pro b/src/proto/search.pro
new file mode 100644
index 0000000..eb614a1
--- /dev/null
+++ b/src/proto/search.pro
@@ -0,0 +1,51 @@
+/* search.c */
+int search_regcomp(char_u *pat, int pat_save, int pat_use, int options, regmmatch_T *regmatch);
+char_u *get_search_pat(void);
+char_u *reverse_text(char_u *s);
+void save_re_pat(int idx, char_u *pat, int magic);
+void save_search_patterns(void);
+void restore_search_patterns(void);
+void free_search_patterns(void);
+void save_last_search_pattern(void);
+void restore_last_search_pattern(void);
+char_u *last_search_pattern(void);
+int ignorecase(char_u *pat);
+int ignorecase_opt(char_u *pat, int ic_in, int scs);
+int pat_has_uppercase(char_u *pat);
+char_u *last_csearch(void);
+int last_csearch_forward(void);
+int last_csearch_until(void);
+void set_last_csearch(int c, char_u *s, int len);
+void set_csearch_direction(int cdir);
+void set_csearch_until(int t_cmd);
+char_u *last_search_pat(void);
+void reset_search_dir(void);
+void set_last_search_pat(char_u *s, int idx, int magic, int setlast);
+void last_pat_prog(regmmatch_T *regmatch);
+int searchit(win_T *win, buf_T *buf, pos_T *pos, pos_T *end_pos, int dir, char_u *pat, long count, int options, int pat_use, linenr_T stop_lnum, proftime_T *tm, int *timed_out);
+void set_search_direction(int cdir);
+int do_search(oparg_T *oap, int dirc, char_u *pat, long count, int options, proftime_T *tm, int *timed_out);
+int search_for_exact_line(buf_T *buf, pos_T *pos, int dir, char_u *pat);
+int searchc(cmdarg_T *cap, int t_cmd);
+pos_T *findmatch(oparg_T *oap, int initc);
+pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int maxtravel);
+void showmatch(int c);
+int findsent(int dir, long count);
+int findpar(int *pincl, int dir, long count, int what, int both);
+int startPS(linenr_T lnum, int para, int both);
+int fwd_word(long count, int bigword, int eol);
+int bck_word(long count, int bigword, int stop);
+int end_word(long count, int bigword, int stop, int empty);
+int bckend_word(long count, int bigword, int eol);
+int current_word(oparg_T *oap, long count, int include, int bigword);
+int current_sent(oparg_T *oap, long count, int include);
+int current_block(oparg_T *oap, long count, int include, int what, int other);
+int current_tagblock(oparg_T *oap, long count_arg, int include);
+int current_par(oparg_T *oap, long count, int include, int type);
+int current_quote(oparg_T *oap, long count, int include, int quotechar);
+int current_search(long count, int forward);
+int linewhite(linenr_T lnum);
+void find_pattern_in_path(char_u *ptr, int dir, int len, int whole, int skip_comments, int type, long count, int action, linenr_T start_lnum, linenr_T end_lnum);
+int read_viminfo_search_pattern(vir_T *virp, int force);
+void write_viminfo_search_pattern(FILE *fp);
+/* vim: set ft=c : */
diff --git a/src/proto/sha256.pro b/src/proto/sha256.pro
new file mode 100644
index 0000000..157fa73
--- /dev/null
+++ b/src/proto/sha256.pro
@@ -0,0 +1,9 @@
+/* sha256.c */
+void sha256_start(context_sha256_T *ctx);
+void sha256_update(context_sha256_T *ctx, char_u *input, UINT32_T length);
+void sha256_finish(context_sha256_T *ctx, char_u digest[32]);
+char_u *sha256_bytes(char_u *buf, int buf_len, char_u *salt, int salt_len);
+char_u *sha256_key(char_u *buf, char_u *salt, int salt_len);
+int sha256_self_test(void);
+void sha2_seed(char_u *header, int header_len, char_u *salt, int salt_len);
+/* vim: set ft=c : */
diff --git a/src/proto/sign.pro b/src/proto/sign.pro
new file mode 100644
index 0000000..d087c01
--- /dev/null
+++ b/src/proto/sign.pro
@@ -0,0 +1,27 @@
+/* sign.c */
+void init_signs(void);
+int buf_getsigntype(buf_T *buf, linenr_T lnum, int type);
+linenr_T buf_delsign(buf_T *buf, linenr_T atlnum, int id, char_u *group);
+int buf_findsign(buf_T *buf, int id, char_u *group);
+int buf_findsign_id(buf_T *buf, linenr_T lnum, char_u *groupname);
+int buf_findsigntype_id(buf_T *buf, linenr_T lnum, int typenr);
+int buf_signcount(buf_T *buf, linenr_T lnum);
+void buf_delete_signs(buf_T *buf, char_u *group);
+void sign_mark_adjust(linenr_T line1, linenr_T line2, long amount, long amount_after);
+int sign_define_by_name(char_u *name, char_u *icon, char_u *linehl, char_u *text, char_u *texthl);
+int sign_undefine_by_name(char_u *name);
+int sign_place(int *sign_id, char_u *sign_group, char_u *sign_name, buf_T *buf, linenr_T lnum, int prio);
+int sign_unplace(int sign_id, char_u *sign_group, buf_T *buf, linenr_T atlnum);
+linenr_T sign_jump(int sign_id, char_u *sign_group, buf_T *buf);
+void ex_sign(exarg_T *eap);
+void sign_getlist(char_u *name, list_T *retlist);
+void get_buffer_signs(buf_T *buf, list_T *l);
+void sign_get_placed(buf_T *buf, linenr_T lnum, int sign_id, char_u *sign_group, list_T *retlist);
+void sign_gui_started(void);
+int sign_get_attr(int typenr, int line);
+char_u *sign_get_text(int typenr);
+void *sign_get_image(int typenr);
+void free_signs(void);
+char_u *get_sign_name(expand_T *xp, int idx);
+void set_context_in_sign_cmd(expand_T *xp, char_u *arg);
+/* vim: set ft=c : */
diff --git a/src/proto/spell.pro b/src/proto/spell.pro
new file mode 100644
index 0000000..485d7d1
--- /dev/null
+++ b/src/proto/spell.pro
@@ -0,0 +1,38 @@
+/* spell.c */
+int spell_check(win_T *wp, char_u *ptr, hlf_T *attrp, int *capcol, int docount);
+int spell_move_to(win_T *wp, int dir, int allwords, int curline, hlf_T *attrp);
+void spell_cat_line(char_u *buf, char_u *line, int maxlen);
+char_u *spell_enc(void);
+slang_T *slang_alloc(char_u *lang);
+void slang_free(slang_T *lp);
+void slang_clear(slang_T *lp);
+void slang_clear_sug(slang_T *lp);
+void count_common_word(slang_T *lp, char_u *word, int len, int count);
+int byte_in_str(char_u *str, int n);
+int init_syl_tab(slang_T *slang);
+char *did_set_spelllang(win_T *wp);
+int captype(char_u *word, char_u *end);
+void spell_delete_wordlist(void);
+void spell_free_all(void);
+void spell_reload(void);
+buf_T *open_spellbuf(void);
+void close_spellbuf(buf_T *buf);
+void clear_spell_chartab(spelltab_T *sp);
+void init_spell_chartab(void);
+int spell_iswordp_nmw(char_u *p, win_T *wp);
+int spell_casefold(char_u *str, int len, char_u *buf, int buflen);
+int spell_check_sps(void);
+void spell_suggest(int count);
+void ex_spellrepall(exarg_T *eap);
+void spell_suggest_list(garray_T *gap, char_u *word, int maxcount, int need_cap, int interactive);
+void onecap_copy(char_u *word, char_u *wcopy, int upper);
+char_u *eval_soundfold(char_u *word);
+void spell_soundfold(slang_T *slang, char_u *inword, int folded, char_u *res);
+void ex_spellinfo(exarg_T *eap);
+void ex_spelldump(exarg_T *eap);
+void spell_dump_compl(char_u *pat, int ic, int *dir, int dumpflags_arg);
+char_u *spell_to_word_end(char_u *start, win_T *win);
+int spell_word_start(int startcol);
+void spell_expand_check_cap(colnr_T col);
+int expand_spelling(linenr_T lnum, char_u *pat, char_u ***matchp);
+/* vim: set ft=c : */
diff --git a/src/proto/spellfile.pro b/src/proto/spellfile.pro
new file mode 100644
index 0000000..70e993a
--- /dev/null
+++ b/src/proto/spellfile.pro
@@ -0,0 +1,9 @@
+/* spellfile.c */
+slang_T *spell_load_file(char_u *fname, char_u *lang, slang_T *old_lp, int silent);
+void suggest_load_files(void);
+int spell_check_msm(void);
+void ex_mkspell(exarg_T *eap);
+void mkspell(int fcount, char_u **fnames, int ascii, int over_write, int added_word);
+void ex_spell(exarg_T *eap);
+void spell_add_word(char_u *word, int len, int bad, int idx, int undo);
+/* vim: set ft=c : */
diff --git a/src/proto/syntax.pro b/src/proto/syntax.pro
new file mode 100644
index 0000000..966a5cb
--- /dev/null
+++ b/src/proto/syntax.pro
@@ -0,0 +1,65 @@
+/* syntax.c */
+void syn_set_timeout(proftime_T *tm);
+void syntax_start(win_T *wp, linenr_T lnum);
+void syn_stack_free_all(synblock_T *block);
+void syn_stack_apply_changes(buf_T *buf);
+void syntax_end_parsing(linenr_T lnum);
+int syntax_check_changed(linenr_T lnum);
+int get_syntax_attr(colnr_T col, int *can_spell, int keep_state);
+void syntax_clear(synblock_T *block);
+void reset_synblock(win_T *wp);
+void ex_syntax(exarg_T *eap);
+void ex_ownsyntax(exarg_T *eap);
+int syntax_present(win_T *win);
+void reset_expand_highlight(void);
+void set_context_in_echohl_cmd(expand_T *xp, char_u *arg);
+void set_context_in_syntax_cmd(expand_T *xp, char_u *arg);
+char_u *get_syntax_name(expand_T *xp, int idx);
+int syn_get_id(win_T *wp, long lnum, colnr_T col, int trans, int *spellp, int keep_state);
+int get_syntax_info(int *seqnrp);
+int syn_get_sub_char(void);
+int syn_get_stack_item(int i);
+int syn_get_foldlevel(win_T *wp, long lnum);
+void ex_syntime(exarg_T *eap);
+char_u *get_syntime_arg(expand_T *xp, int idx);
+void init_highlight(int both, int reset);
+int load_colors(char_u *name);
+int lookup_color(int idx, int foreground, int *boldp);
+void do_highlight(char_u *line, int forceit, int init);
+void free_highlight(void);
+void restore_cterm_colors(void);
+void set_normal_colors(void);
+char_u *hl_get_font_name(void);
+void hl_set_font_name(char_u *font_name);
+void hl_set_bg_color_name(char_u *name);
+void hl_set_fg_color_name(char_u *name);
+guicolor_T color_name2handle(char_u *name);
+int get_cterm_attr_idx(int attr, int fg, int bg);
+int get_tgc_attr_idx(int attr, guicolor_T fg, guicolor_T bg);
+int get_gui_attr_idx(int attr, guicolor_T fg, guicolor_T bg);
+void clear_hl_tables(void);
+int hl_combine_attr(int char_attr, int prim_attr);
+attrentry_T *syn_gui_attr2entry(int attr);
+int syn_attr2attr(int attr);
+attrentry_T *syn_term_attr2entry(int attr);
+attrentry_T *syn_cterm_attr2entry(int attr);
+char_u *highlight_has_attr(int id, int flag, int modec);
+char_u *highlight_color(int id, char_u *what, int modec);
+long_u highlight_gui_color_rgb(int id, int fg);
+int syn_name2id(char_u *name);
+int syn_name2attr(char_u *name);
+int highlight_exists(char_u *name);
+char_u *syn_id2name(int id);
+int syn_namen2id(char_u *linep, int len);
+int syn_check_group(char_u *pp, int len);
+int syn_id2attr(int hl_id);
+int syn_id2colors(int hl_id, guicolor_T *fgp, guicolor_T *bgp);
+void syn_id2cterm_bg(int hl_id, int *fgp, int *bgp);
+int syn_get_final_id(int hl_id);
+void highlight_gui_started(void);
+int highlight_changed(void);
+void set_context_in_highlight_cmd(expand_T *xp, char_u *arg);
+char_u *get_highlight_name(expand_T *xp, int idx);
+char_u *get_highlight_name_ext(expand_T *xp, int idx, int skip_cleared);
+void free_highlight_fonts(void);
+/* vim: set ft=c : */
diff --git a/src/proto/tag.pro b/src/proto/tag.pro
new file mode 100644
index 0000000..c9bcb38
--- /dev/null
+++ b/src/proto/tag.pro
@@ -0,0 +1,14 @@
+/* tag.c */
+int do_tag(char_u *tag, int type, int count, int forceit, int verbose);
+void tag_freematch(void);
+void do_tags(exarg_T *eap);
+int find_tags(char_u *pat, int *num_matches, char_u ***matchesp, int flags, int mincount, char_u *buf_ffname);
+void free_tag_stuff(void);
+int get_tagfname(tagname_T *tnp, int first, char_u *buf);
+void tagname_free(tagname_T *tnp);
+void simplify_filename(char_u *filename);
+int expand_tags(int tagnames, char_u *pat, int *num_file, char_u ***file);
+int get_tags(list_T *list, char_u *pat, char_u *buf_fname);
+void get_tagstack(win_T *wp, dict_T *retdict);
+int set_tagstack(win_T *wp, dict_T *d, int action);
+/* vim: set ft=c : */
diff --git a/src/proto/term.pro b/src/proto/term.pro
new file mode 100644
index 0000000..1b8ab5f
--- /dev/null
+++ b/src/proto/term.pro
@@ -0,0 +1,83 @@
+/* term.c */
+guicolor_T termgui_mch_get_color(char_u *name);
+guicolor_T termgui_get_color(char_u *name);
+guicolor_T termgui_mch_get_rgb(guicolor_T color);
+int set_termname(char_u *term);
+void set_mouse_termcode(int n, char_u *s);
+void del_mouse_termcode(int n);
+void getlinecol(long *cp, long *rp);
+int add_termcap_entry(char_u *name, int force);
+int term_is_8bit(char_u *name);
+int term_is_gui(char_u *name);
+char_u *tltoa(unsigned long i);
+void termcapinit(char_u *name);
+void out_flush(void);
+void out_flush_cursor(int force, int clear_selection);
+void out_flush_check(void);
+void out_trash(void);
+void out_char(unsigned c);
+void out_str_nf(char_u *s);
+void out_str_cf(char_u *s);
+void out_str(char_u *s);
+void term_windgoto(int row, int col);
+void term_cursor_right(int i);
+void term_append_lines(int line_count);
+void term_delete_lines(int line_count);
+void term_set_winpos(int x, int y);
+int term_get_winpos(int *x, int *y, varnumber_T timeout);
+void term_set_winsize(int height, int width);
+void term_fg_color(int n);
+void term_bg_color(int n);
+void term_fg_rgb_color(guicolor_T rgb);
+void term_bg_rgb_color(guicolor_T rgb);
+void term_settitle(char_u *title);
+void term_push_title(int which);
+void term_pop_title(int which);
+void ttest(int pairs);
+void add_long_to_buf(long_u val, char_u *dst);
+void check_shellsize(void);
+void limit_screen_size(void);
+void win_new_shellsize(void);
+void shell_resized(void);
+void shell_resized_check(void);
+void set_shellsize(int width, int height, int mustset);
+void settmode(int tmode);
+void starttermcap(void);
+void stoptermcap(void);
+void may_req_termresponse(void);
+void may_req_ambiguous_char_width(void);
+void may_req_bg_color(void);
+int swapping_screen(void);
+void setmouse(void);
+int mouse_has(int c);
+int mouse_model_popup(void);
+void scroll_start(void);
+void cursor_on_force(void);
+void cursor_on(void);
+void cursor_off(void);
+void term_cursor_mode(int forced);
+void term_cursor_color(char_u *color);
+int blink_state_is_inverted(void);
+void term_cursor_shape(int shape, int blink);
+void scroll_region_set(win_T *wp, int off);
+void scroll_region_reset(void);
+void clear_termcodes(void);
+void add_termcode(char_u *name, char_u *string, int flags);
+char_u *find_termcode(char_u *name);
+char_u *get_termcode(int i);
+void del_termcode(char_u *name);
+void set_mouse_topline(win_T *wp);
+int check_termcode(int max_offset, char_u *buf, int bufsize, int *buflen);
+void term_get_fg_color(char_u *r, char_u *g, char_u *b);
+void term_get_bg_color(char_u *r, char_u *g, char_u *b);
+char_u *replace_termcodes(char_u *from, char_u **bufp, int from_part, int do_lt, int special);
+int find_term_bykeys(char_u *src);
+void show_termcodes(void);
+int show_one_termcode(char_u *name, char_u *code, int printit);
+char_u *translate_mapping(char_u *str, int expmap);
+void update_tcap(int attr);
+void swap_tcap(void);
+guicolor_T gui_get_color_cmn(char_u *name);
+guicolor_T gui_get_rgb_color_cmn(int r, int g, int b);
+void cterm_color2rgb(int nr, char_u *r, char_u *g, char_u *b, char_u *ansi_idx);
+/* vim: set ft=c : */
diff --git a/src/proto/terminal.pro b/src/proto/terminal.pro
new file mode 100644
index 0000000..0fa62b7
--- /dev/null
+++ b/src/proto/terminal.pro
@@ -0,0 +1,62 @@
+/* terminal.c */
+void init_job_options(jobopt_T *opt);
+buf_T *term_start(typval_T *argvar, char **argv, jobopt_T *opt, int flags);
+void ex_terminal(exarg_T *eap);
+int term_write_session(FILE *fd, win_T *wp);
+int term_should_restore(buf_T *buf);
+void free_terminal(buf_T *buf);
+void free_unused_terminals(void);
+void write_to_term(buf_T *buffer, char_u *msg, channel_T *channel);
+int term_job_running(term_T *term);
+int term_none_open(term_T *term);
+int term_try_stop_job(buf_T *buf);
+int term_check_timers(int next_due_arg, proftime_T *now);
+int term_in_normal_mode(void);
+void term_enter_job_mode(void);
+int send_keys_to_term(term_T *term, int c, int typed);
+int terminal_is_active(void);
+cursorentry_T *term_get_cursor_shape(guicolor_T *fg, guicolor_T *bg);
+int term_use_loop(void);
+void term_win_entered(void);
+int terminal_loop(int blocking);
+void term_channel_closed(channel_T *ch);
+void term_check_channel_closed_recently(void);
+int term_do_update_window(win_T *wp);
+void term_update_window(win_T *wp);
+int term_is_finished(buf_T *buf);
+int term_show_buffer(buf_T *buf);
+void term_change_in_curbuf(void);
+int term_get_attr(buf_T *buf, linenr_T lnum, int col);
+char_u *term_get_status_text(term_T *term);
+int set_ref_in_term(int copyID);
+void set_terminal_default_colors(int cterm_fg, int cterm_bg);
+void f_term_dumpwrite(typval_T *argvars, typval_T *rettv);
+int term_swap_diff(void);
+void f_term_dumpdiff(typval_T *argvars, typval_T *rettv);
+void f_term_dumpload(typval_T *argvars, typval_T *rettv);
+void f_term_getaltscreen(typval_T *argvars, typval_T *rettv);
+void f_term_getattr(typval_T *argvars, typval_T *rettv);
+void f_term_getcursor(typval_T *argvars, typval_T *rettv);
+void f_term_getjob(typval_T *argvars, typval_T *rettv);
+void f_term_getline(typval_T *argvars, typval_T *rettv);
+void f_term_getscrolled(typval_T *argvars, typval_T *rettv);
+void f_term_getsize(typval_T *argvars, typval_T *rettv);
+void f_term_setsize(typval_T *argvars, typval_T *rettv);
+void f_term_getstatus(typval_T *argvars, typval_T *rettv);
+void f_term_gettitle(typval_T *argvars, typval_T *rettv);
+void f_term_gettty(typval_T *argvars, typval_T *rettv);
+void f_term_list(typval_T *argvars, typval_T *rettv);
+void f_term_scrape(typval_T *argvars, typval_T *rettv);
+void f_term_sendkeys(typval_T *argvars, typval_T *rettv);
+void f_term_getansicolors(typval_T *argvars, typval_T *rettv);
+void f_term_setansicolors(typval_T *argvars, typval_T *rettv);
+void f_term_setrestore(typval_T *argvars, typval_T *rettv);
+void f_term_setkill(typval_T *argvars, typval_T *rettv);
+void f_term_start(typval_T *argvars, typval_T *rettv);
+void f_term_wait(typval_T *argvars, typval_T *rettv);
+void term_send_eof(channel_T *ch);
+job_T *term_getjob(term_T *term);
+int terminal_enabled(void);
+void term_free_conpty(term_T *term);
+int use_conpty(void);
+/* vim: set ft=c : */
diff --git a/src/proto/termlib.pro b/src/proto/termlib.pro
new file mode 100644
index 0000000..3dd120f
--- /dev/null
+++ b/src/proto/termlib.pro
@@ -0,0 +1,8 @@
+/* termlib.c */
+int tgetent(char *tbuf, char *term);
+int tgetflag(char *id);
+int tgetnum(char *id);
+char *tgetstr(char *id, char **buf);
+char *tgoto(char *cm, int col, int line);
+int tputs(char *cp, int affcnt, void (*outc)(unsigned int));
+/* vim: set ft=c : */
diff --git a/src/proto/textprop.pro b/src/proto/textprop.pro
new file mode 100644
index 0000000..0eac557
--- /dev/null
+++ b/src/proto/textprop.pro
@@ -0,0 +1,18 @@
+/* textprop.c */
+void f_prop_add(typval_T *argvars, typval_T *rettv);
+int get_text_props(buf_T *buf, linenr_T lnum, char_u **props, int will_change);
+proptype_T *text_prop_type_by_id(buf_T *buf, int id);
+void f_prop_clear(typval_T *argvars, typval_T *rettv);
+void f_prop_list(typval_T *argvars, typval_T *rettv);
+void f_prop_remove(typval_T *argvars, typval_T *rettv);
+void prop_type_set(typval_T *argvars, int add);
+void f_prop_type_add(typval_T *argvars, typval_T *rettv);
+void f_prop_type_change(typval_T *argvars, typval_T *rettv);
+void f_prop_type_delete(typval_T *argvars, typval_T *rettv);
+void f_prop_type_get(typval_T *argvars, typval_T *rettv);
+void f_prop_type_list(typval_T *argvars, typval_T *rettv);
+void clear_global_prop_types(void);
+void clear_buf_prop_types(buf_T *buf);
+void adjust_prop_columns(linenr_T lnum, colnr_T col, int bytes_added);
+void adjust_props_for_split(linenr_T lnum, int kept, int deleted);
+/* vim: set ft=c : */
diff --git a/src/proto/ui.pro b/src/proto/ui.pro
new file mode 100644
index 0000000..774a308
--- /dev/null
+++ b/src/proto/ui.pro
@@ -0,0 +1,72 @@
+/* ui.c */
+void ui_write(char_u *s, int len);
+void ui_inchar_undo(char_u *s, int len);
+int ui_inchar(char_u *buf, int maxlen, long wtime, int tb_change_cnt);
+int inchar_loop(char_u *buf, int maxlen, long wtime, int tb_change_cnt, int (*wait_func)(long wtime, int *interrupted, int ignore_input), int (*resize_func)(int check_only));
+int ui_wait_for_chars_or_timer(long wtime, int (*wait_func)(long wtime, int *interrupted, int ignore_input), int *interrupted, int ignore_input);
+int ui_char_avail(void);
+void ui_delay(long msec, int ignoreinput);
+void ui_suspend(void);
+void suspend_shell(void);
+int ui_get_shellsize(void);
+void ui_set_shellsize(int mustset);
+void ui_new_shellsize(void);
+void ui_breakcheck(void);
+void ui_breakcheck_force(int force);
+void clip_init(int can_use);
+void clip_update_selection(VimClipboard *clip);
+void clip_own_selection(VimClipboard *cbd);
+void clip_lose_selection(VimClipboard *cbd);
+void start_global_changes(void);
+int is_clipboard_needs_update(void);
+void end_global_changes(void);
+void clip_auto_select(void);
+int clip_isautosel_star(void);
+int clip_isautosel_plus(void);
+void clip_modeless(int button, int is_click, int is_drag);
+void clip_start_selection(int col, int row, int repeated_click);
+void clip_process_selection(int button, int col, int row, int_u repeated_click);
+void clip_may_redraw_selection(int row, int col, int len);
+void clip_clear_selection(VimClipboard *cbd);
+void clip_may_clear_selection(int row1, int row2);
+void clip_scroll_selection(int rows);
+void clip_copy_modeless_selection(int both);
+int clip_gen_own_selection(VimClipboard *cbd);
+void clip_gen_lose_selection(VimClipboard *cbd);
+void clip_gen_set_selection(VimClipboard *cbd);
+void clip_gen_request_selection(VimClipboard *cbd);
+int clip_gen_owner_exists(VimClipboard *cbd);
+int vim_is_input_buf_full(void);
+int vim_is_input_buf_empty(void);
+int vim_free_in_input_buf(void);
+int vim_used_in_input_buf(void);
+char_u *get_input_buf(void);
+void set_input_buf(char_u *p);
+void add_to_input_buf(char_u *s, int len);
+void add_to_input_buf_csi(char_u *str, int len);
+void push_raw_key(char_u *s, int len);
+void trash_input_buf(void);
+int read_from_input_buf(char_u *buf, long maxlen);
+void fill_input_buf(int exit_on_error);
+void read_error_exit(void);
+void ui_cursor_shape_forced(int forced);
+void ui_cursor_shape(void);
+int check_col(int col);
+int check_row(int row);
+void open_app_context(void);
+void x11_setup_atoms(Display *dpy);
+void x11_setup_selection(Widget w);
+void clip_x11_request_selection(Widget myShell, Display *dpy, VimClipboard *cbd);
+void clip_x11_lose_selection(Widget myShell, VimClipboard *cbd);
+int clip_x11_own_selection(Widget myShell, VimClipboard *cbd);
+void clip_x11_set_selection(VimClipboard *cbd);
+int clip_x11_owner_exists(VimClipboard *cbd);
+void yank_cut_buffer0(Display *dpy, VimClipboard *cbd);
+int jump_to_mouse(int flags, int *inclusive, int which_button);
+int mouse_comp_pos(win_T *win, int *rowp, int *colp, linenr_T *lnump);
+win_T *mouse_find_win(int *rowp, int *colp);
+int get_fpos_of_mouse(pos_T *mpos);
+int vcol2col(win_T *wp, linenr_T lnum, int vcol);
+void ui_focus_change(int in_focus);
+void im_save_status(long *psave);
+/* vim: set ft=c : */
diff --git a/src/proto/undo.pro b/src/proto/undo.pro
new file mode 100644
index 0000000..1052d40
--- /dev/null
+++ b/src/proto/undo.pro
@@ -0,0 +1,31 @@
+/* undo.c */
+int u_save_cursor(void);
+int u_save(linenr_T top, linenr_T bot);
+int u_savesub(linenr_T lnum);
+int u_inssub(linenr_T lnum);
+int u_savedel(linenr_T lnum, long nlines);
+int undo_allowed(void);
+int u_savecommon(linenr_T top, linenr_T bot, linenr_T newbot, int reload);
+void u_compute_hash(char_u *hash);
+char_u *u_get_undo_file_name(char_u *buf_ffname, int reading);
+void u_write_undo(char_u *name, int forceit, buf_T *buf, char_u *hash);
+void u_read_undo(char_u *name, char_u *hash, char_u *orig_name);
+void u_undo(int count);
+void u_redo(int count);
+void undo_time(long step, int sec, int file, int absolute);
+void u_sync(int force);
+void ex_undolist(exarg_T *eap);
+void ex_undojoin(exarg_T *eap);
+void u_unchanged(buf_T *buf);
+void u_find_first_changed(void);
+void u_update_save_nr(buf_T *buf);
+void u_clearall(buf_T *buf);
+void u_saveline(linenr_T lnum);
+void u_clearline(void);
+void u_undoline(void);
+void u_blockfree(buf_T *buf);
+int bufIsChanged(buf_T *buf);
+int bufIsChangedNotTerm(buf_T *buf);
+int curbufIsChanged(void);
+void u_eval_tree(u_header_T *first_uhp, list_T *list);
+/* vim: set ft=c : */
diff --git a/src/proto/userfunc.pro b/src/proto/userfunc.pro
new file mode 100644
index 0000000..25f1c3c
--- /dev/null
+++ b/src/proto/userfunc.pro
@@ -0,0 +1,58 @@
+/* userfunc.c */
+void func_init(void);
+int get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate);
+char_u *deref_func_name(char_u *name, int *lenp, partial_T **partialp, int no_autoload);
+int get_func_tv(char_u *name, int len, typval_T *rettv, char_u **arg, linenr_T firstline, linenr_T lastline, int *doesrange, int evaluate, partial_T *partial, dict_T *selfdict);
+ufunc_T *find_func(char_u *name);
+void save_funccal(funccal_entry_T *entry);
+void restore_funccal(void);
+void free_all_functions(void);
+int func_call(char_u *name, typval_T *args, partial_T *partial, dict_T *selfdict, typval_T *rettv);
+int call_func(char_u *funcname, int len, typval_T *rettv, int argcount_in, typval_T *argvars_in, int (*argv_func)(int, typval_T *, int), linenr_T firstline, linenr_T lastline, int *doesrange, int evaluate, partial_T *partial, dict_T *selfdict_in);
+char_u *trans_function_name(char_u **pp, int skip, int flags, funcdict_T *fdp, partial_T **partial);
+void ex_function(exarg_T *eap);
+int eval_fname_script(char_u *p);
+int translated_function_exists(char_u *name);
+int function_exists(char_u *name, int no_deref);
+char_u *get_expanded_name(char_u *name, int check);
+void func_dump_profile(FILE *fd);
+void prof_child_enter(proftime_T *tm);
+void prof_child_exit(proftime_T *tm);
+char_u *get_user_func_name(expand_T *xp, int idx);
+void ex_delfunction(exarg_T *eap);
+void func_unref(char_u *name);
+void func_ptr_unref(ufunc_T *fp);
+void func_ref(char_u *name);
+void func_ptr_ref(ufunc_T *fp);
+void ex_return(exarg_T *eap);
+void ex_call(exarg_T *eap);
+int do_return(exarg_T *eap, int reanimate, int is_cmd, void *rettv);
+void discard_pending_return(void *rettv);
+char_u *get_return_cmd(void *rettv);
+char_u *get_func_line(int c, void *cookie, int indent);
+void func_line_start(void *cookie);
+void func_line_exec(void *cookie);
+void func_line_end(void *cookie);
+int func_has_ended(void *cookie);
+int func_has_abort(void *cookie);
+dict_T *make_partial(dict_T *selfdict_in, typval_T *rettv);
+char_u *func_name(void *cookie);
+linenr_T *func_breakpoint(void *cookie);
+int *func_dbg_tick(void *cookie);
+int func_level(void *cookie);
+int current_func_returned(void);
+int free_unref_funccal(int copyID, int testing);
+hashtab_T *get_funccal_local_ht(void);
+dictitem_T *get_funccal_local_var(void);
+hashtab_T *get_funccal_args_ht(void);
+dictitem_T *get_funccal_args_var(void);
+void list_func_vars(int *first);
+dict_T *get_current_funccal_dict(hashtab_T *ht);
+hashitem_T *find_hi_in_scoped_ht(char_u *name, hashtab_T **pht);
+dictitem_T *find_var_in_scoped_ht(char_u *name, int no_autoload);
+int set_ref_in_previous_funccal(int copyID);
+int set_ref_in_call_stack(int copyID);
+int set_ref_in_functions(int copyID);
+int set_ref_in_func_args(int copyID);
+int set_ref_in_func(char_u *name, ufunc_T *fp_in, int copyID);
+/* vim: set ft=c : */
diff --git a/src/proto/version.pro b/src/proto/version.pro
new file mode 100644
index 0000000..8139772
--- /dev/null
+++ b/src/proto/version.pro
@@ -0,0 +1,11 @@
+/* version.c */
+void init_longVersion(void);
+int highest_patch(void);
+int has_patch(int n);
+void ex_version(exarg_T *eap);
+void list_in_columns(char_u **items, int size, int current);
+void list_version(void);
+void maybe_intro_message(void);
+void intro_message(int colon);
+void ex_intro(exarg_T *eap);
+/* vim: set ft=c : */
diff --git a/src/proto/winclip.pro b/src/proto/winclip.pro
new file mode 100644
index 0000000..990c1cf
--- /dev/null
+++ b/src/proto/winclip.pro
@@ -0,0 +1,15 @@
+/* winclip.c */
+int utf8_to_utf16(char_u *instr, int inlen, short_u *outstr, int *unconvlenp);
+int utf16_to_utf8(short_u *instr, int inlen, char_u *outstr);
+void MultiByteToWideChar_alloc(UINT cp, DWORD flags, LPCSTR in, int inlen, LPWSTR *out, int *outlen);
+void WideCharToMultiByte_alloc(UINT cp, DWORD flags, LPCWSTR in, int inlen, LPSTR *out, int *outlen, LPCSTR def, LPBOOL useddef);
+void win_clip_init(void);
+int clip_mch_own_selection(VimClipboard *cbd);
+void clip_mch_lose_selection(VimClipboard *cbd);
+void clip_mch_request_selection(VimClipboard *cbd);
+void clip_mch_set_selection(VimClipboard *cbd);
+short_u *enc_to_utf16(char_u *str, int *lenp);
+char_u *utf16_to_enc(short_u *str, int *lenp);
+void acp_to_enc(char_u *str, int str_size, char_u **out, int *outlen);
+void enc_to_acp(char_u *str, int str_size, char_u **out, int *outlen);
+/* vim: set ft=c : */
diff --git a/src/proto/window.pro b/src/proto/window.pro
new file mode 100644
index 0000000..4527a37
--- /dev/null
+++ b/src/proto/window.pro
@@ -0,0 +1,98 @@
+/* window.c */
+void do_window(int nchar, long Prenum, int xchar);
+void get_wincmd_addr_type(char_u *arg, exarg_T *eap);
+int win_split(int size, int flags);
+int win_split_ins(int size, int flags, win_T *new_wp, int dir);
+int win_valid(win_T *win);
+int win_valid_any_tab(win_T *win);
+int win_count(void);
+int make_windows(int count, int vertical);
+void win_move_after(win_T *win1, win_T *win2);
+void win_equal(win_T *next_curwin, int current, int dir);
+void close_windows(buf_T *buf, int keep_curwin);
+int one_window(void);
+int win_close(win_T *win, int free_buf);
+void win_close_othertab(win_T *win, int free_buf, tabpage_T *tp);
+void win_free_all(void);
+win_T *winframe_remove(win_T *win, int *dirp, tabpage_T *tp);
+void close_others(int message, int forceit);
+void curwin_init(void);
+void win_init_empty(win_T *wp);
+int win_alloc_first(void);
+void win_alloc_aucmd_win(void);
+void win_init_size(void);
+void free_tabpage(tabpage_T *tp);
+int win_new_tabpage(int after);
+int may_open_tabpage(void);
+int make_tabpages(int maxcount);
+int valid_tabpage(tabpage_T *tpc);
+int valid_tabpage_win(tabpage_T *tpc);
+void close_tabpage(tabpage_T *tab);
+tabpage_T *find_tabpage(int n);
+int tabpage_index(tabpage_T *ftp);
+void goto_tabpage(int n);
+void goto_tabpage_tp(tabpage_T *tp, int trigger_enter_autocmds, int trigger_leave_autocmds);
+void goto_tabpage_win(tabpage_T *tp, win_T *wp);
+void tabpage_move(int nr);
+void win_goto(win_T *wp);
+win_T *win_find_nr(int winnr);
+tabpage_T *win_find_tabpage(win_T *win);
+void win_enter(win_T *wp, int undo_sync);
+win_T *buf_jump_open_win(buf_T *buf);
+win_T *buf_jump_open_tab(buf_T *buf);
+void win_append(win_T *after, win_T *wp);
+void win_remove(win_T *wp, tabpage_T *tp);
+int win_alloc_lines(win_T *wp);
+void win_free_lsize(win_T *wp);
+void shell_new_rows(void);
+void shell_new_columns(void);
+void win_size_save(garray_T *gap);
+void win_size_restore(garray_T *gap);
+int win_comp_pos(void);
+void win_setheight(int height);
+void win_setheight_win(int height, win_T *win);
+void win_setwidth(int width);
+void win_setwidth_win(int width, win_T *wp);
+void win_setminheight(void);
+void win_setminwidth(void);
+void win_drag_status_line(win_T *dragwin, int offset);
+void win_drag_vsep_line(win_T *dragwin, int offset);
+void set_fraction(win_T *wp);
+void win_new_height(win_T *wp, int height);
+void scroll_to_fraction(win_T *wp, int prev_height);
+void win_new_width(win_T *wp, int width);
+void win_comp_scroll(win_T *wp);
+void command_height(void);
+void last_status(int morewin);
+int tabline_height(void);
+char_u *grab_file_name(long count, linenr_T *file_lnum);
+char_u *file_name_at_cursor(int options, long count, linenr_T *file_lnum);
+char_u *file_name_in_line(char_u *line, int col, int options, long count, char_u *rel_fname, linenr_T *file_lnum);
+char_u *find_file_name_in_path(char_u *ptr, int len, int options, long count, char_u *rel_fname);
+int path_with_url(char_u *fname);
+int vim_isAbsName(char_u *name);
+int vim_FullName(char_u *fname, char_u *buf, int len, int force);
+int min_rows(void);
+int only_one_window(void);
+void check_lnums(int do_curwin);
+void make_snapshot(int idx);
+void restore_snapshot(int idx, int close_curwin);
+int switch_win(win_T **save_curwin, tabpage_T **save_curtab, win_T *win, tabpage_T *tp, int no_display);
+void restore_win(win_T *save_curwin, tabpage_T *save_curtab, int no_display);
+void switch_buffer(bufref_T *save_curbuf, buf_T *buf);
+void restore_buffer(bufref_T *save_curbuf);
+int win_hasvertsplit(void);
+int match_add(win_T *wp, char_u *grp, char_u *pat, int prio, int id, list_T *pos_list, char_u *conceal_char);
+int match_delete(win_T *wp, int id, int perr);
+void clear_matches(win_T *wp);
+matchitem_T *get_match(win_T *wp, int id);
+int get_win_number(win_T *wp, win_T *first_win);
+int get_tab_number(tabpage_T *tp);
+int win_getid(typval_T *argvars);
+int win_gotoid(typval_T *argvars);
+void win_id2tabwin(typval_T *argvars, list_T *list);
+win_T *win_id2wp(typval_T *argvars);
+int win_id2win(typval_T *argvars);
+void win_findbuf(typval_T *argvars, list_T *list);
+void get_framelayout(frame_T *fr, list_T *l, int outer);
+/* vim: set ft=c : */
diff --git a/src/protodef.h b/src/protodef.h
new file mode 100644
index 0000000..42a6cce
--- /dev/null
+++ b/src/protodef.h
@@ -0,0 +1,18 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * Do ":help uganda" in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ */
+
+#ifdef PROTO
+// cproto runs into trouble when these types are missing
+typedef double _Float16;
+typedef double _Float32;
+typedef double _Float64;
+typedef double _Float128;
+typedef double _Float32x;
+typedef double _Float64x;
+#endif
+
diff --git a/src/pty.c b/src/pty.c
new file mode 100644
index 0000000..23ea0c0
--- /dev/null
+++ b/src/pty.c
@@ -0,0 +1,443 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+/*
+ * The stuff in this file mostly comes from the "screen" program.
+ * Included with permission from Juergen Weigert.
+ * Copied from "pty.c". "putenv.c" was used for putenv() in misc2.c.
+ *
+ * It has been modified to work better with Vim.
+ * The parts that are not used in Vim have been deleted.
+ * See the "screen" sources for the complete stuff.
+ *
+ * This specific version is distibuted under the Vim license (attribution by
+ * Juergen Weigert), the GPL applies to the original version, see the
+ * copyright notice below.
+ */
+
+/* Copyright (c) 1993
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Copyright (c) 1987 Oliver Laumann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include "vim.h"
+
+#if defined(FEAT_GUI) || defined(FEAT_JOB_CHANNEL)
+
+#include <signal.h>
+
+#ifdef __CYGWIN32__
+# include <sys/termios.h>
+#endif
+
+#ifdef HAVE_SYS_IOCTL_H
+# include <sys/ioctl.h>
+#endif
+
+#if HAVE_STROPTS_H
+# include <sys/types.h>
+# ifdef sinix
+# define buf_T __system_buf_t__
+# endif
+# include <stropts.h>
+# ifdef sinix
+# undef buf_T
+# endif
+# ifdef SUN_SYSTEM
+# include <sys/conf.h>
+# if defined(HAVE_SYS_PTMS_H) && defined(HAVE_SVR4_PTYS)
+# include <sys/ptms.h>
+# endif
+# endif
+#endif
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#if HAVE_TERMIO_H
+# include <termio.h>
+#else
+# ifdef HAVE_TERMIOS_H
+# include <termios.h>
+# endif
+#endif
+
+#if HAVE_SYS_STREAM_H
+# include <sys/stream.h>
+#endif
+
+#if HAVE_SYS_PTEM_H
+# include <sys/ptem.h>
+#endif
+
+#if !defined(SUN_SYSTEM) && !defined(VMS)
+# include <sys/ioctl.h>
+#endif
+
+#if defined(SUN_SYSTEM) && defined(LOCKPTY) && !defined(TIOCEXCL)
+# include <sys/ttold.h>
+#endif
+
+#ifdef ISC
+# include <sys/tty.h>
+# include <sys/sioctl.h>
+# include <sys/pty.h>
+#endif
+
+#ifdef sgi
+# include <sys/sysmacros.h>
+#endif
+
+#if defined(_INCLUDE_HPUX_SOURCE) && !defined(hpux)
+# define hpux
+#endif
+
+/*
+ * if no PTYRANGE[01] is in the config file, we pick a default
+ */
+#ifndef PTYRANGE0
+# define PTYRANGE0 "qprs"
+#endif
+#ifndef PTYRANGE1
+# define PTYRANGE1 "0123456789abcdef"
+#endif
+
+/* SVR4 pseudo ttys don't seem to work with SCO-5 */
+#ifdef M_UNIX
+# undef HAVE_SVR4_PTYS
+#endif
+
+/*
+ * Open all ptys with O_NOCTTY, just to be on the safe side.
+ */
+#ifndef O_NOCTTY
+# define O_NOCTTY 0
+#endif
+
+ static void
+initmaster(int f UNUSED)
+{
+#ifndef VMS
+# ifdef POSIX
+ tcflush(f, TCIOFLUSH);
+# else
+# ifdef TIOCFLUSH
+ (void)ioctl(f, TIOCFLUSH, (char *) 0);
+# endif
+# endif
+# ifdef LOCKPTY
+ (void)ioctl(f, TIOCEXCL, (char *) 0);
+# endif
+#endif
+}
+
+/*
+ * This causes a hang on some systems, but is required for a properly working
+ * pty on others. Needs to be tuned...
+ */
+ int
+setup_slavepty(int fd)
+{
+ if (fd < 0)
+ return 0;
+#if defined(I_PUSH) && defined(HAVE_SVR4_PTYS) && !defined(sgi) \
+ && !defined(linux) && !defined(__osf__) && !defined(M_UNIX)
+# if defined(HAVE_SYS_PTEM_H) || defined(hpux)
+ if (ioctl(fd, I_PUSH, "ptem") != 0)
+ return -1;
+# endif
+ if (ioctl(fd, I_PUSH, "ldterm") != 0)
+ return -1;
+# ifdef SUN_SYSTEM
+ if (ioctl(fd, I_PUSH, "ttcompat") != 0)
+ return -1;
+# endif
+#endif
+ return 0;
+}
+
+
+#if defined(OSX) && !defined(PTY_DONE)
+#define PTY_DONE
+ int
+mch_openpty(char **ttyn)
+{
+ int f;
+ static char TtyName[32];
+
+ if ((f = open_controlling_pty(TtyName)) < 0)
+ return -1;
+ initmaster(f);
+ *ttyn = TtyName;
+ return f;
+}
+#endif
+
+#if (defined(sequent) || defined(_SEQUENT_)) && defined(HAVE_GETPSEUDOTTY) \
+ && !defined(PTY_DONE)
+#define PTY_DONE
+ int
+mch_openpty(char **ttyn)
+{
+ char *m, *s;
+ int f;
+ /* used for opening a new pty-pair: */
+ static char PtyName[32];
+ static char TtyName[32];
+
+ if ((f = getpseudotty(&s, &m)) < 0)
+ return -1;
+#ifdef _SEQUENT_
+ fvhangup(s);
+#endif
+ vim_strncpy((char_u *)PtyName, (char_u *)m, sizeof(PtyName) - 1);
+ vim_strncpy((char_u *)TtyName, (char_u *)s, sizeof(TtyName) - 1);
+ initmaster(f);
+ *ttyn = TtyName;
+ return f;
+}
+#endif
+
+#if defined(__sgi) && !defined(PTY_DONE)
+#define PTY_DONE
+ int
+mch_openpty(char **ttyn)
+{
+ int f;
+ char *name;
+ RETSIGTYPE (*sigcld) SIGPROTOARG;
+
+ /*
+ * SIGCHLD set to SIG_DFL for _getpty() because it may fork() and
+ * exec() /usr/adm/mkpts
+ */
+ sigcld = signal(SIGCHLD, SIG_DFL);
+ name = _getpty(&f, O_RDWR | O_NONBLOCK | O_EXTRA, 0600, 0);
+ signal(SIGCHLD, sigcld);
+
+ if (name == 0)
+ return -1;
+ initmaster(f);
+ *ttyn = name;
+ return f;
+}
+#endif
+
+#if defined(MIPS) && defined(HAVE_DEV_PTC) && !defined(PTY_DONE)
+#define PTY_DONE
+ int
+mch_openpty(char **ttyn)
+{
+ int f;
+ stat_T buf;
+ /* used for opening a new pty-pair: */
+ static char TtyName[32];
+
+ if ((f = open("/dev/ptc", O_RDWR | O_NOCTTY | O_NONBLOCK | O_EXTRA, 0)) < 0)
+ return -1;
+ if (mch_fstat(f, &buf) < 0)
+ {
+ close(f);
+ return -1;
+ }
+ sprintf(TtyName, "/dev/ttyq%d", minor(buf.st_rdev));
+ initmaster(f);
+ *ttyn = TtyName;
+ return f;
+}
+#endif
+
+#if defined(HAVE_SVR4_PTYS) && !defined(PTY_DONE) && !defined(hpux) \
+ && !(defined(MACOS_X) && !defined(MAC_OS_X_VERSION_10_6))
+
+/* NOTE: Even though HPUX can have /dev/ptmx, the code below doesn't work!
+ * Same for Mac OS X Leopard (10.5). */
+#define PTY_DONE
+ int
+mch_openpty(char **ttyn)
+{
+ int f;
+ char *m;
+ char *(ptsname(int));
+ int unlockpt(int);
+ int grantpt(int);
+ RETSIGTYPE (*sigcld) SIGPROTOARG;
+ /* used for opening a new pty-pair: */
+ static char TtyName[32];
+
+ if ((f = open("/dev/ptmx", O_RDWR | O_NOCTTY | O_EXTRA, 0)) == -1)
+ return -1;
+
+ /*
+ * SIGCHLD set to SIG_DFL for grantpt() because it fork()s and
+ * exec()s pt_chmod
+ */
+ sigcld = signal(SIGCHLD, SIG_DFL);
+ if ((m = ptsname(f)) == NULL || grantpt(f) || unlockpt(f))
+ {
+ signal(SIGCHLD, sigcld);
+ close(f);
+ return -1;
+ }
+ signal(SIGCHLD, sigcld);
+ vim_strncpy((char_u *)TtyName, (char_u *)m, sizeof(TtyName) - 1);
+ initmaster(f);
+ *ttyn = TtyName;
+ return f;
+}
+#endif
+
+#if defined(_AIX) && defined(HAVE_DEV_PTC) && !defined(PTY_DONE)
+#define PTY_DONE
+
+#ifdef _IBMR2
+int aixhack = -1;
+#endif
+
+ int
+mch_openpty(char **ttyn)
+{
+ int f;
+ /* used for opening a new pty-pair: */
+ static char TtyName[32];
+
+ /* a dumb looking loop replaced by mycrofts code: */
+ if ((f = open("/dev/ptc", O_RDWR | O_NOCTTY | O_EXTRA)) < 0)
+ return -1;
+ vim_strncpy((char_u *)TtyName, (char_u *)ttyname(f), sizeof(TtyName) - 1);
+ if (geteuid() != ROOT_UID && mch_access(TtyName, R_OK | W_OK))
+ {
+ close(f);
+ return -1;
+ }
+ initmaster(f);
+# ifdef _IBMR2
+ if (aixhack >= 0)
+ close(aixhack);
+ if ((aixhack = open(TtyName, O_RDWR | O_NOCTTY | O_EXTRA, 0)) < 0)
+ {
+ close(f);
+ return -1;
+ }
+# endif
+ *ttyn = TtyName;
+ return f;
+}
+#endif
+
+#ifndef PTY_DONE
+
+# ifdef hpux
+static char PtyProto[] = "/dev/ptym/ptyXY";
+static char TtyProto[] = "/dev/pty/ttyXY";
+# else
+# ifdef __BEOS__
+static char PtyProto[] = "/dev/pt/XY";
+static char TtyProto[] = "/dev/tt/XY";
+# else
+static char PtyProto[] = "/dev/ptyXY";
+static char TtyProto[] = "/dev/ttyXY";
+# endif
+# endif
+
+ int
+mch_openpty(char **ttyn)
+{
+ char *p, *q, *l, *d;
+ int f;
+ /* used for opening a new pty-pair: */
+ static char PtyName[32];
+ static char TtyName[32];
+
+ strcpy(PtyName, PtyProto);
+ strcpy(TtyName, TtyProto);
+ for (p = PtyName; *p != 'X'; p++)
+ ;
+ for (q = TtyName; *q != 'X'; q++)
+ ;
+ for (l = PTYRANGE0; (*p = *l) != '\0'; l++)
+ {
+ for (d = PTYRANGE1; (p[1] = *d) != '\0'; d++)
+ {
+ if ((f = open(PtyName, O_RDWR | O_NOCTTY | O_EXTRA, 0)) == -1)
+ continue;
+ q[0] = *l;
+ q[1] = *d;
+ if (geteuid() != ROOT_UID && mch_access(TtyName, R_OK | W_OK))
+ {
+ close(f);
+ continue;
+ }
+#if defined(SUN_SYSTEM) && defined(TIOCGPGRP) && !defined(SUNOS3)
+ /* Hack to ensure that the slave side of the pty is
+ * unused. May not work in anything other than SunOS4.1
+ */
+ {
+ int pgrp;
+
+ /* tcgetpgrp does not work (uses TIOCGETPGRP)! */
+ if (ioctl(f, TIOCGPGRP, (char *)&pgrp) != -1 || errno != EIO)
+ {
+ close(f);
+ continue;
+ }
+ }
+#endif
+ initmaster(f);
+ *ttyn = TtyName;
+ return f;
+ }
+ }
+ return -1;
+}
+#endif
+
+/*
+ * Call isatty(fd), except for SunOS where it's done differently.
+ */
+ int
+mch_isatty(int fd)
+{
+# if defined(I_STR) && defined(HAVE_SYS_PTMS_H) && defined(HAVE_SVR4_PTYS) \
+ && defined(SUN_SYSTEM)
+ // On SunOS, isatty() for /dev/ptmx returns false or sometimes can hang up
+ // in the inner ioctl(), and therefore first determine whether "fd" is a
+ // master device.
+ struct strioctl istr;
+
+ istr.ic_cmd = ISPTM;
+ istr.ic_timout = 0;
+ istr.ic_dp = NULL;
+ istr.ic_len = 0;
+
+ if (ioctl(fd, I_STR, &istr) == 0)
+ // Trick: return 2 in order to advice the caller that "fd" is a master
+ // device. cf. src/os_unix.c:get_tty_fd()
+ return 2;
+# endif
+ return isatty(fd);
+}
+
+#endif /* FEAT_GUI || FEAT_JOB_CHANNEL */
diff --git a/src/quickfix.c b/src/quickfix.c
new file mode 100644
index 0000000..3bfa027
--- /dev/null
+++ b/src/quickfix.c
@@ -0,0 +1,7252 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * quickfix.c: functions for quickfix mode, using a file with error messages
+ */
+
+#include "vim.h"
+
+#if defined(FEAT_QUICKFIX) || defined(PROTO)
+
+struct dir_stack_T
+{
+ struct dir_stack_T *next;
+ char_u *dirname;
+};
+
+/*
+ * For each error the next struct is allocated and linked in a list.
+ */
+typedef struct qfline_S qfline_T;
+struct qfline_S
+{
+ qfline_T *qf_next; // pointer to next error in the list
+ qfline_T *qf_prev; // pointer to previous error in the list
+ linenr_T qf_lnum; // line number where the error occurred
+ int qf_fnum; // file number for the line
+ int qf_col; // column where the error occurred
+ int qf_nr; // error number
+ char_u *qf_module; // module name for this error
+ char_u *qf_pattern; // search pattern for the error
+ char_u *qf_text; // description of the error
+ char_u qf_viscol; // set to TRUE if qf_col is screen column
+ char_u qf_cleared; // set to TRUE if line has been deleted
+ char_u qf_type; // type of the error (mostly 'E'); 1 for
+ // :helpgrep
+ char_u qf_valid; // valid error message detected
+};
+
+/*
+ * There is a stack of error lists.
+ */
+#define LISTCOUNT 10
+#define INVALID_QFIDX (-1)
+
+/*
+ * Quickfix list type.
+ */
+typedef enum
+{
+ QFLT_QUICKFIX, // Quickfix list - global list
+ QFLT_LOCATION, // Location list - per window list
+ QFLT_INTERNAL // Internal - Temporary list used by getqflist()/getloclist()
+} qfltype_T;
+
+/*
+ * Quickfix/Location list definition
+ * Contains a list of entries (qfline_T). qf_start points to the first entry
+ * and qf_last points to the last entry. qf_count contains the list size.
+ *
+ * Usually the list contains one or more entries. But an empty list can be
+ * created using setqflist()/setloclist() with a title and/or user context
+ * information and entries can be added later using setqflist()/setloclist().
+ */
+typedef struct qf_list_S
+{
+ int_u qf_id; // Unique identifier for this list
+ qfltype_T qfl_type;
+ qfline_T *qf_start; // pointer to the first error
+ qfline_T *qf_last; // pointer to the last error
+ qfline_T *qf_ptr; // pointer to the current error
+ int qf_count; // number of errors (0 means empty list)
+ int qf_index; // current index in the error list
+ int qf_nonevalid; // TRUE if not a single valid entry found
+ char_u *qf_title; // title derived from the command that created
+ // the error list or set by setqflist
+ typval_T *qf_ctx; // context set by setqflist/setloclist
+
+ struct dir_stack_T *qf_dir_stack;
+ char_u *qf_directory;
+ struct dir_stack_T *qf_file_stack;
+ char_u *qf_currfile;
+ int qf_multiline;
+ int qf_multiignore;
+ int qf_multiscan;
+ long qf_changedtick;
+} qf_list_T;
+
+/*
+ * Quickfix/Location list stack definition
+ * Contains a list of quickfix/location lists (qf_list_T)
+ */
+struct qf_info_S
+{
+ // Count of references to this list. Used only for location lists.
+ // When a location list window reference this list, qf_refcount
+ // will be 2. Otherwise, qf_refcount will be 1. When qf_refcount
+ // reaches 0, the list is freed.
+ int qf_refcount;
+ int qf_listcount; // current number of lists
+ int qf_curlist; // current error list
+ qf_list_T qf_lists[LISTCOUNT];
+ qfltype_T qfl_type; // type of list
+};
+
+static qf_info_T ql_info; // global quickfix list
+static int_u last_qf_id = 0; // Last used quickfix list id
+
+#define FMT_PATTERNS 11 // maximum number of % recognized
+
+/*
+ * Structure used to hold the info of one part of 'errorformat'
+ */
+typedef struct efm_S efm_T;
+struct efm_S
+{
+ regprog_T *prog; // pre-formatted part of 'errorformat'
+ efm_T *next; // pointer to next (NULL if last)
+ char_u addr[FMT_PATTERNS]; // indices of used % patterns
+ char_u prefix; // prefix of this format line:
+ // 'D' enter directory
+ // 'X' leave directory
+ // 'A' start of multi-line message
+ // 'E' error message
+ // 'W' warning message
+ // 'I' informational message
+ // 'C' continuation line
+ // 'Z' end of multi-line message
+ // 'G' general, unspecific message
+ // 'P' push file (partial) message
+ // 'Q' pop/quit file (partial) message
+ // 'O' overread (partial) message
+ char_u flags; // additional flags given in prefix
+ // '-' do not include this line
+ // '+' include whole line in message
+ int conthere; // %> used
+};
+
+// List of location lists to be deleted.
+// Used to delay the deletion of locations lists by autocmds.
+typedef struct qf_delq_S
+{
+ struct qf_delq_S *next;
+ qf_info_T *qi;
+} qf_delq_T;
+static qf_delq_T *qf_delq_head = NULL;
+
+// Counter to prevent autocmds from freeing up location lists when they are
+// still being used.
+static int quickfix_busy = 0;
+
+static efm_T *fmt_start = NULL; // cached across qf_parse_line() calls
+
+static void qf_new_list(qf_info_T *qi, char_u *qf_title);
+static int qf_add_entry(qf_info_T *qi, int qf_idx, char_u *dir, char_u *fname, char_u *module, int bufnum, char_u *mesg, long lnum, int col, int vis_col, char_u *pattern, int nr, int type, int valid);
+static void qf_free(qf_list_T *qfl);
+static char_u *qf_types(int, int);
+static int qf_get_fnum(qf_info_T *qi, int qf_idx, char_u *, char_u *);
+static char_u *qf_push_dir(char_u *, struct dir_stack_T **, int is_file_stack);
+static char_u *qf_pop_dir(struct dir_stack_T **);
+static char_u *qf_guess_filepath(qf_list_T *qfl, char_u *);
+static void qf_fmt_text(char_u *text, char_u *buf, int bufsize);
+static int qf_win_pos_update(qf_info_T *qi, int old_qf_index);
+static win_T *qf_find_win(qf_info_T *qi);
+static buf_T *qf_find_buf(qf_info_T *qi);
+static void qf_update_buffer(qf_info_T *qi, qfline_T *old_last);
+static void qf_fill_buffer(qf_info_T *qi, buf_T *buf, qfline_T *old_last);
+static buf_T *load_dummy_buffer(char_u *fname, char_u *dirname_start, char_u *resulting_dir);
+static void wipe_dummy_buffer(buf_T *buf, char_u *dirname_start);
+static void unload_dummy_buffer(buf_T *buf, char_u *dirname_start);
+static qf_info_T *ll_get_or_alloc_list(win_T *);
+
+// Quickfix window check helper macro
+#define IS_QF_WINDOW(wp) (bt_quickfix(wp->w_buffer) && wp->w_llist_ref == NULL)
+// Location list window check helper macro
+#define IS_LL_WINDOW(wp) (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL)
+
+// Quickfix and location list stack check helper macros
+#define IS_QF_STACK(qi) (qi->qfl_type == QFLT_QUICKFIX)
+#define IS_LL_STACK(qi) (qi->qfl_type == QFLT_LOCATION)
+#define IS_QF_LIST(qfl) (qfl->qfl_type == QFLT_QUICKFIX)
+#define IS_LL_LIST(qfl) (qfl->qfl_type == QFLT_LOCATION)
+
+/*
+ * Return location list for window 'wp'
+ * For location list window, return the referenced location list
+ */
+#define GET_LOC_LIST(wp) (IS_LL_WINDOW(wp) ? wp->w_llist_ref : wp->w_llist)
+
+/*
+ * Looking up a buffer can be slow if there are many. Remember the last one
+ * to make this a lot faster if there are multiple matches in the same file.
+ */
+static char_u *qf_last_bufname = NULL;
+static bufref_T qf_last_bufref = {NULL, 0, 0};
+
+static char *e_loc_list_changed =
+ N_("E926: Current location list was changed");
+
+/*
+ * Maximum number of bytes allowed per line while reading a errorfile.
+ */
+#define LINE_MAXLEN 4096
+
+static struct fmtpattern
+{
+ char_u convchar;
+ char *pattern;
+} fmt_pat[FMT_PATTERNS] =
+ {
+ {'f', ".\\+"}, // only used when at end
+ {'n', "\\d\\+"},
+ {'l', "\\d\\+"},
+ {'c', "\\d\\+"},
+ {'t', "."},
+ {'m', ".\\+"},
+ {'r', ".*"},
+ {'p', "[- .]*"},
+ {'v', "\\d\\+"},
+ {'s', ".\\+"},
+ {'o', ".\\+"}
+ };
+
+/*
+ * Convert an errorformat pattern to a regular expression pattern.
+ * See fmt_pat definition above for the list of supported patterns. The
+ * pattern specifier is supplied in "efmpat". The converted pattern is stored
+ * in "regpat". Returns a pointer to the location after the pattern.
+ */
+ static char_u *
+efmpat_to_regpat(
+ char_u *efmpat,
+ char_u *regpat,
+ efm_T *efminfo,
+ int idx,
+ int round)
+{
+ char_u *srcptr;
+
+ if (efminfo->addr[idx])
+ {
+ // Each errorformat pattern can occur only once
+ semsg(_("E372: Too many %%%c in format string"), *efmpat);
+ return NULL;
+ }
+ if ((idx && idx < 6
+ && vim_strchr((char_u *)"DXOPQ", efminfo->prefix) != NULL)
+ || (idx == 6
+ && vim_strchr((char_u *)"OPQ", efminfo->prefix) == NULL))
+ {
+ semsg(_("E373: Unexpected %%%c in format string"), *efmpat);
+ return NULL;
+ }
+ efminfo->addr[idx] = (char_u)++round;
+ *regpat++ = '\\';
+ *regpat++ = '(';
+#ifdef BACKSLASH_IN_FILENAME
+ if (*efmpat == 'f')
+ {
+ // Also match "c:" in the file name, even when
+ // checking for a colon next: "%f:".
+ // "\%(\a:\)\="
+ STRCPY(regpat, "\\%(\\a:\\)\\=");
+ regpat += 10;
+ }
+#endif
+ if (*efmpat == 'f' && efmpat[1] != NUL)
+ {
+ if (efmpat[1] != '\\' && efmpat[1] != '%')
+ {
+ // A file name may contain spaces, but this isn't
+ // in "\f". For "%f:%l:%m" there may be a ":" in
+ // the file name. Use ".\{-1,}x" instead (x is
+ // the next character), the requirement that :999:
+ // follows should work.
+ STRCPY(regpat, ".\\{-1,}");
+ regpat += 7;
+ }
+ else
+ {
+ // File name followed by '\\' or '%': include as
+ // many file name chars as possible.
+ STRCPY(regpat, "\\f\\+");
+ regpat += 4;
+ }
+ }
+ else
+ {
+ srcptr = (char_u *)fmt_pat[idx].pattern;
+ while ((*regpat = *srcptr++) != NUL)
+ ++regpat;
+ }
+ *regpat++ = '\\';
+ *regpat++ = ')';
+
+ return regpat;
+}
+
+/*
+ * Convert a scanf like format in 'errorformat' to a regular expression.
+ * Returns a pointer to the location after the pattern.
+ */
+ static char_u *
+scanf_fmt_to_regpat(
+ char_u **pefmp,
+ char_u *efm,
+ int len,
+ char_u *regpat)
+{
+ char_u *efmp = *pefmp;
+
+ if (*efmp == '[' || *efmp == '\\')
+ {
+ if ((*regpat++ = *efmp) == '[') // %*[^a-z0-9] etc.
+ {
+ if (efmp[1] == '^')
+ *regpat++ = *++efmp;
+ if (efmp < efm + len)
+ {
+ *regpat++ = *++efmp; // could be ']'
+ while (efmp < efm + len
+ && (*regpat++ = *++efmp) != ']')
+ // skip ;
+ if (efmp == efm + len)
+ {
+ emsg(_("E374: Missing ] in format string"));
+ return NULL;
+ }
+ }
+ }
+ else if (efmp < efm + len) // %*\D, %*\s etc.
+ *regpat++ = *++efmp;
+ *regpat++ = '\\';
+ *regpat++ = '+';
+ }
+ else
+ {
+ // TODO: scanf()-like: %*ud, %*3c, %*f, ... ?
+ semsg(_("E375: Unsupported %%%c in format string"), *efmp);
+ return NULL;
+ }
+
+ *pefmp = efmp;
+
+ return regpat;
+}
+
+/*
+ * Analyze/parse an errorformat prefix.
+ */
+ static char_u *
+efm_analyze_prefix(char_u *efmp, efm_T *efminfo)
+{
+ if (vim_strchr((char_u *)"+-", *efmp) != NULL)
+ efminfo->flags = *efmp++;
+ if (vim_strchr((char_u *)"DXAEWICZGOPQ", *efmp) != NULL)
+ efminfo->prefix = *efmp;
+ else
+ {
+ semsg(_("E376: Invalid %%%c in format string prefix"), *efmp);
+ return NULL;
+ }
+
+ return efmp;
+}
+
+/*
+ * Converts a 'errorformat' string part in 'efm' to a regular expression
+ * pattern. The resulting regex pattern is returned in "regpat". Additional
+ * information about the 'erroformat' pattern is returned in "fmt_ptr".
+ * Returns OK or FAIL.
+ */
+ static int
+efm_to_regpat(
+ char_u *efm,
+ int len,
+ efm_T *fmt_ptr,
+ char_u *regpat)
+{
+ char_u *ptr;
+ char_u *efmp;
+ int round;
+ int idx = 0;
+
+ // Build a regexp pattern for a 'errorformat' option part
+ ptr = regpat;
+ *ptr++ = '^';
+ round = 0;
+ for (efmp = efm; efmp < efm + len; ++efmp)
+ {
+ if (*efmp == '%')
+ {
+ ++efmp;
+ for (idx = 0; idx < FMT_PATTERNS; ++idx)
+ if (fmt_pat[idx].convchar == *efmp)
+ break;
+ if (idx < FMT_PATTERNS)
+ {
+ ptr = efmpat_to_regpat(efmp, ptr, fmt_ptr, idx, round);
+ if (ptr == NULL)
+ return FAIL;
+ round++;
+ }
+ else if (*efmp == '*')
+ {
+ ++efmp;
+ ptr = scanf_fmt_to_regpat(&efmp, efm, len, ptr);
+ if (ptr == NULL)
+ return FAIL;
+ }
+ else if (vim_strchr((char_u *)"%\\.^$~[", *efmp) != NULL)
+ *ptr++ = *efmp; // regexp magic characters
+ else if (*efmp == '#')
+ *ptr++ = '*';
+ else if (*efmp == '>')
+ fmt_ptr->conthere = TRUE;
+ else if (efmp == efm + 1) // analyse prefix
+ {
+ // prefix is allowed only at the beginning of the errorformat
+ // option part
+ efmp = efm_analyze_prefix(efmp, fmt_ptr);
+ if (efmp == NULL)
+ return FAIL;
+ }
+ else
+ {
+ semsg(_("E377: Invalid %%%c in format string"), *efmp);
+ return FAIL;
+ }
+ }
+ else // copy normal character
+ {
+ if (*efmp == '\\' && efmp + 1 < efm + len)
+ ++efmp;
+ else if (vim_strchr((char_u *)".*^$~[", *efmp) != NULL)
+ *ptr++ = '\\'; // escape regexp atoms
+ if (*efmp)
+ *ptr++ = *efmp;
+ }
+ }
+ *ptr++ = '$';
+ *ptr = NUL;
+
+ return OK;
+}
+
+/*
+ * Free the 'errorformat' information list
+ */
+ static void
+free_efm_list(efm_T **efm_first)
+{
+ efm_T *efm_ptr;
+
+ for (efm_ptr = *efm_first; efm_ptr != NULL; efm_ptr = *efm_first)
+ {
+ *efm_first = efm_ptr->next;
+ vim_regfree(efm_ptr->prog);
+ vim_free(efm_ptr);
+ }
+ fmt_start = NULL;
+}
+
+/*
+ * Compute the size of the buffer used to convert a 'errorformat' pattern into
+ * a regular expression pattern.
+ */
+ static int
+efm_regpat_bufsz(char_u *efm)
+{
+ int sz;
+ int i;
+
+ sz = (FMT_PATTERNS * 3) + ((int)STRLEN(efm) << 2);
+ for (i = FMT_PATTERNS; i > 0; )
+ sz += (int)STRLEN(fmt_pat[--i].pattern);
+#ifdef BACKSLASH_IN_FILENAME
+ sz += 12; // "%f" can become twelve chars longer (see efm_to_regpat)
+#else
+ sz += 2; // "%f" can become two chars longer
+#endif
+
+ return sz;
+}
+
+/*
+ * Return the length of a 'errorformat' option part (separated by ",").
+ */
+ static int
+efm_option_part_len(char_u *efm)
+{
+ int len;
+
+ for (len = 0; efm[len] != NUL && efm[len] != ','; ++len)
+ if (efm[len] == '\\' && efm[len + 1] != NUL)
+ ++len;
+
+ return len;
+}
+
+/*
+ * Parse the 'errorformat' option. Multiple parts in the 'errorformat' option
+ * are parsed and converted to regular expressions. Returns information about
+ * the parsed 'errorformat' option.
+ */
+ static efm_T *
+parse_efm_option(char_u *efm)
+{
+ efm_T *fmt_ptr = NULL;
+ efm_T *fmt_first = NULL;
+ efm_T *fmt_last = NULL;
+ char_u *fmtstr = NULL;
+ int len;
+ int sz;
+
+ // Each part of the format string is copied and modified from errorformat
+ // to regex prog. Only a few % characters are allowed.
+
+ // Get some space to modify the format string into.
+ sz = efm_regpat_bufsz(efm);
+ if ((fmtstr = alloc(sz)) == NULL)
+ goto parse_efm_error;
+
+ while (efm[0] != NUL)
+ {
+ // Allocate a new eformat structure and put it at the end of the list
+ fmt_ptr = (efm_T *)alloc_clear((unsigned)sizeof(efm_T));
+ if (fmt_ptr == NULL)
+ goto parse_efm_error;
+ if (fmt_first == NULL) // first one
+ fmt_first = fmt_ptr;
+ else
+ fmt_last->next = fmt_ptr;
+ fmt_last = fmt_ptr;
+
+ // Isolate one part in the 'errorformat' option
+ len = efm_option_part_len(efm);
+
+ if (efm_to_regpat(efm, len, fmt_ptr, fmtstr) == FAIL)
+ goto parse_efm_error;
+ if ((fmt_ptr->prog = vim_regcomp(fmtstr, RE_MAGIC + RE_STRING)) == NULL)
+ goto parse_efm_error;
+ // Advance to next part
+ efm = skip_to_option_part(efm + len); // skip comma and spaces
+ }
+
+ if (fmt_first == NULL) // nothing found
+ emsg(_("E378: 'errorformat' contains no pattern"));
+
+ goto parse_efm_end;
+
+parse_efm_error:
+ free_efm_list(&fmt_first);
+
+parse_efm_end:
+ vim_free(fmtstr);
+
+ return fmt_first;
+}
+
+enum {
+ QF_FAIL = 0,
+ QF_OK = 1,
+ QF_END_OF_INPUT = 2,
+ QF_NOMEM = 3,
+ QF_IGNORE_LINE = 4,
+ QF_MULTISCAN = 5,
+};
+
+/*
+ * State information used to parse lines and add entries to a quickfix/location
+ * list.
+ */
+typedef struct {
+ char_u *linebuf;
+ int linelen;
+ char_u *growbuf;
+ int growbufsiz;
+ FILE *fd;
+ typval_T *tv;
+ char_u *p_str;
+ listitem_T *p_li;
+ buf_T *buf;
+ linenr_T buflnum;
+ linenr_T lnumlast;
+ vimconv_T vc;
+} qfstate_T;
+
+/*
+ * Allocate more memory for the line buffer used for parsing lines.
+ */
+ static char_u *
+qf_grow_linebuf(qfstate_T *state, int newsz)
+{
+ char_u *p;
+
+ // If the line exceeds LINE_MAXLEN exclude the last
+ // byte since it's not a NL character.
+ state->linelen = newsz > LINE_MAXLEN ? LINE_MAXLEN - 1 : newsz;
+ if (state->growbuf == NULL)
+ {
+ state->growbuf = alloc(state->linelen + 1);
+ if (state->growbuf == NULL)
+ return NULL;
+ state->growbufsiz = state->linelen;
+ }
+ else if (state->linelen > state->growbufsiz)
+ {
+ if ((p = vim_realloc(state->growbuf, state->linelen + 1)) == NULL)
+ return NULL;
+ state->growbuf = p;
+ state->growbufsiz = state->linelen;
+ }
+ return state->growbuf;
+}
+
+/*
+ * Get the next string (separated by newline) from state->p_str.
+ */
+ static int
+qf_get_next_str_line(qfstate_T *state)
+{
+ // Get the next line from the supplied string
+ char_u *p_str = state->p_str;
+ char_u *p;
+ int len;
+
+ if (*p_str == NUL) // Reached the end of the string
+ return QF_END_OF_INPUT;
+
+ p = vim_strchr(p_str, '\n');
+ if (p != NULL)
+ len = (int)(p - p_str) + 1;
+ else
+ len = (int)STRLEN(p_str);
+
+ if (len > IOSIZE - 2)
+ {
+ state->linebuf = qf_grow_linebuf(state, len);
+ if (state->linebuf == NULL)
+ return QF_NOMEM;
+ }
+ else
+ {
+ state->linebuf = IObuff;
+ state->linelen = len;
+ }
+ vim_strncpy(state->linebuf, p_str, state->linelen);
+
+ // Increment using len in order to discard the rest of the
+ // line if it exceeds LINE_MAXLEN.
+ p_str += len;
+ state->p_str = p_str;
+
+ return QF_OK;
+}
+
+/*
+ * Get the next string from state->p_Li.
+ */
+ static int
+qf_get_next_list_line(qfstate_T *state)
+{
+ listitem_T *p_li = state->p_li;
+ int len;
+
+ while (p_li != NULL
+ && (p_li->li_tv.v_type != VAR_STRING
+ || p_li->li_tv.vval.v_string == NULL))
+ p_li = p_li->li_next; // Skip non-string items
+
+ if (p_li == NULL) // End of the list
+ {
+ state->p_li = NULL;
+ return QF_END_OF_INPUT;
+ }
+
+ len = (int)STRLEN(p_li->li_tv.vval.v_string);
+ if (len > IOSIZE - 2)
+ {
+ state->linebuf = qf_grow_linebuf(state, len);
+ if (state->linebuf == NULL)
+ return QF_NOMEM;
+ }
+ else
+ {
+ state->linebuf = IObuff;
+ state->linelen = len;
+ }
+
+ vim_strncpy(state->linebuf, p_li->li_tv.vval.v_string, state->linelen);
+
+ state->p_li = p_li->li_next; // next item
+ return QF_OK;
+}
+
+/*
+ * Get the next string from state->buf.
+ */
+ static int
+qf_get_next_buf_line(qfstate_T *state)
+{
+ char_u *p_buf = NULL;
+ int len;
+
+ // Get the next line from the supplied buffer
+ if (state->buflnum > state->lnumlast)
+ return QF_END_OF_INPUT;
+
+ p_buf = ml_get_buf(state->buf, state->buflnum, FALSE);
+ state->buflnum += 1;
+
+ len = (int)STRLEN(p_buf);
+ if (len > IOSIZE - 2)
+ {
+ state->linebuf = qf_grow_linebuf(state, len);
+ if (state->linebuf == NULL)
+ return QF_NOMEM;
+ }
+ else
+ {
+ state->linebuf = IObuff;
+ state->linelen = len;
+ }
+ vim_strncpy(state->linebuf, p_buf, state->linelen);
+
+ return QF_OK;
+}
+
+/*
+ * Get the next string from file state->fd.
+ */
+ static int
+qf_get_next_file_line(qfstate_T *state)
+{
+ int discard;
+ int growbuflen;
+
+ if (fgets((char *)IObuff, IOSIZE, state->fd) == NULL)
+ return QF_END_OF_INPUT;
+
+ discard = FALSE;
+ state->linelen = (int)STRLEN(IObuff);
+ if (state->linelen == IOSIZE - 1 && !(IObuff[state->linelen - 1] == '\n'))
+ {
+ // The current line exceeds IObuff, continue reading using
+ // growbuf until EOL or LINE_MAXLEN bytes is read.
+ if (state->growbuf == NULL)
+ {
+ state->growbufsiz = 2 * (IOSIZE - 1);
+ state->growbuf = alloc(state->growbufsiz);
+ if (state->growbuf == NULL)
+ return QF_NOMEM;
+ }
+
+ // Copy the read part of the line, excluding null-terminator
+ memcpy(state->growbuf, IObuff, IOSIZE - 1);
+ growbuflen = state->linelen;
+
+ for (;;)
+ {
+ char_u *p;
+
+ if (fgets((char *)state->growbuf + growbuflen,
+ state->growbufsiz - growbuflen, state->fd) == NULL)
+ break;
+ state->linelen = (int)STRLEN(state->growbuf + growbuflen);
+ growbuflen += state->linelen;
+ if ((state->growbuf)[growbuflen - 1] == '\n')
+ break;
+ if (state->growbufsiz == LINE_MAXLEN)
+ {
+ discard = TRUE;
+ break;
+ }
+
+ state->growbufsiz = 2 * state->growbufsiz < LINE_MAXLEN
+ ? 2 * state->growbufsiz : LINE_MAXLEN;
+ if ((p = vim_realloc(state->growbuf, state->growbufsiz)) == NULL)
+ return QF_NOMEM;
+ state->growbuf = p;
+ }
+
+ while (discard)
+ {
+ // The current line is longer than LINE_MAXLEN, continue
+ // reading but discard everything until EOL or EOF is
+ // reached.
+ if (fgets((char *)IObuff, IOSIZE, state->fd) == NULL
+ || (int)STRLEN(IObuff) < IOSIZE - 1
+ || IObuff[IOSIZE - 1] == '\n')
+ break;
+ }
+
+ state->linebuf = state->growbuf;
+ state->linelen = growbuflen;
+ }
+ else
+ state->linebuf = IObuff;
+
+ // Convert a line if it contains a non-ASCII character.
+ if (state->vc.vc_type != CONV_NONE && has_non_ascii(state->linebuf))
+ {
+ char_u *line;
+
+ line = string_convert(&state->vc, state->linebuf, &state->linelen);
+ if (line != NULL)
+ {
+ if (state->linelen < IOSIZE)
+ {
+ STRCPY(state->linebuf, line);
+ vim_free(line);
+ }
+ else
+ {
+ vim_free(state->growbuf);
+ state->linebuf = state->growbuf = line;
+ state->growbufsiz = state->linelen < LINE_MAXLEN
+ ? state->linelen : LINE_MAXLEN;
+ }
+ }
+ }
+
+ return QF_OK;
+}
+
+/*
+ * Get the next string from a file/buffer/list/string.
+ */
+ static int
+qf_get_nextline(qfstate_T *state)
+{
+ int status = QF_FAIL;
+
+ if (state->fd == NULL)
+ {
+ if (state->tv != NULL)
+ {
+ if (state->tv->v_type == VAR_STRING)
+ // Get the next line from the supplied string
+ status = qf_get_next_str_line(state);
+ else if (state->tv->v_type == VAR_LIST)
+ // Get the next line from the supplied list
+ status = qf_get_next_list_line(state);
+ }
+ else
+ // Get the next line from the supplied buffer
+ status = qf_get_next_buf_line(state);
+ }
+ else
+ // Get the next line from the supplied file
+ status = qf_get_next_file_line(state);
+
+ if (status != QF_OK)
+ return status;
+
+ // remove newline/CR from the line
+ if (state->linelen > 0 && state->linebuf[state->linelen - 1] == '\n')
+ {
+ state->linebuf[state->linelen - 1] = NUL;
+#ifdef USE_CRNL
+ if (state->linelen > 1 && state->linebuf[state->linelen - 2] == '\r')
+ state->linebuf[state->linelen - 2] = NUL;
+#endif
+ }
+
+ remove_bom(state->linebuf);
+
+ return QF_OK;
+}
+
+typedef struct {
+ char_u *namebuf;
+ char_u *module;
+ char_u *errmsg;
+ int errmsglen;
+ long lnum;
+ int col;
+ char_u use_viscol;
+ char_u *pattern;
+ int enr;
+ int type;
+ int valid;
+} qffields_T;
+
+/*
+ * Parse the match for filename ('%f') pattern in regmatch.
+ * Return the matched value in "fields->namebuf".
+ */
+ static int
+qf_parse_fmt_f(regmatch_T *rmp, int midx, qffields_T *fields, int prefix)
+{
+ int c;
+
+ if (rmp->startp[midx] == NULL || rmp->endp[midx] == NULL)
+ return QF_FAIL;
+
+ // Expand ~/file and $HOME/file to full path.
+ c = *rmp->endp[midx];
+ *rmp->endp[midx] = NUL;
+ expand_env(rmp->startp[midx], fields->namebuf, CMDBUFFSIZE);
+ *rmp->endp[midx] = c;
+
+ // For separate filename patterns (%O, %P and %Q), the specified file
+ // should exist.
+ if (vim_strchr((char_u *)"OPQ", prefix) != NULL
+ && mch_getperm(fields->namebuf) == -1)
+ return QF_FAIL;
+
+ return QF_OK;
+}
+
+/*
+ * Parse the match for error number ('%n') pattern in regmatch.
+ * Return the matched value in "fields->enr".
+ */
+ static int
+qf_parse_fmt_n(regmatch_T *rmp, int midx, qffields_T *fields)
+{
+ if (rmp->startp[midx] == NULL)
+ return QF_FAIL;
+ fields->enr = (int)atol((char *)rmp->startp[midx]);
+ return QF_OK;
+}
+
+/*
+ * Parse the match for line number (%l') pattern in regmatch.
+ * Return the matched value in "fields->lnum".
+ */
+ static int
+qf_parse_fmt_l(regmatch_T *rmp, int midx, qffields_T *fields)
+{
+ if (rmp->startp[midx] == NULL)
+ return QF_FAIL;
+ fields->lnum = atol((char *)rmp->startp[midx]);
+ return QF_OK;
+}
+
+/*
+ * Parse the match for column number ('%c') pattern in regmatch.
+ * Return the matched value in "fields->col".
+ */
+ static int
+qf_parse_fmt_c(regmatch_T *rmp, int midx, qffields_T *fields)
+{
+ if (rmp->startp[midx] == NULL)
+ return QF_FAIL;
+ fields->col = (int)atol((char *)rmp->startp[midx]);
+ return QF_OK;
+}
+
+/*
+ * Parse the match for error type ('%t') pattern in regmatch.
+ * Return the matched value in "fields->type".
+ */
+ static int
+qf_parse_fmt_t(regmatch_T *rmp, int midx, qffields_T *fields)
+{
+ if (rmp->startp[midx] == NULL)
+ return QF_FAIL;
+ fields->type = *rmp->startp[midx];
+ return QF_OK;
+}
+
+/*
+ * Parse the match for '%+' format pattern. The whole matching line is included
+ * in the error string. Return the matched line in "fields->errmsg".
+ */
+ static int
+qf_parse_fmt_plus(char_u *linebuf, int linelen, qffields_T *fields)
+{
+ char_u *p;
+
+ if (linelen >= fields->errmsglen)
+ {
+ // linelen + null terminator
+ if ((p = vim_realloc(fields->errmsg, linelen + 1)) == NULL)
+ return QF_NOMEM;
+ fields->errmsg = p;
+ fields->errmsglen = linelen + 1;
+ }
+ vim_strncpy(fields->errmsg, linebuf, linelen);
+ return QF_OK;
+}
+
+/*
+ * Parse the match for error message ('%m') pattern in regmatch.
+ * Return the matched value in "fields->errmsg".
+ */
+ static int
+qf_parse_fmt_m(regmatch_T *rmp, int midx, qffields_T *fields)
+{
+ char_u *p;
+ int len;
+
+ if (rmp->startp[midx] == NULL || rmp->endp[midx] == NULL)
+ return QF_FAIL;
+ len = (int)(rmp->endp[midx] - rmp->startp[midx]);
+ if (len >= fields->errmsglen)
+ {
+ // len + null terminator
+ if ((p = vim_realloc(fields->errmsg, len + 1)) == NULL)
+ return QF_NOMEM;
+ fields->errmsg = p;
+ fields->errmsglen = len + 1;
+ }
+ vim_strncpy(fields->errmsg, rmp->startp[midx], len);
+ return QF_OK;
+}
+
+/*
+ * Parse the match for rest of a single-line file message ('%r') pattern.
+ * Return the matched value in "tail".
+ */
+ static int
+qf_parse_fmt_r(regmatch_T *rmp, int midx, char_u **tail)
+{
+ if (rmp->startp[midx] == NULL)
+ return QF_FAIL;
+ *tail = rmp->startp[midx];
+ return QF_OK;
+}
+
+/*
+ * Parse the match for the pointer line ('%p') pattern in regmatch.
+ * Return the matched value in "fields->col".
+ */
+ static int
+qf_parse_fmt_p(regmatch_T *rmp, int midx, qffields_T *fields)
+{
+ char_u *match_ptr;
+
+ if (rmp->startp[midx] == NULL || rmp->endp[midx] == NULL)
+ return QF_FAIL;
+ fields->col = 0;
+ for (match_ptr = rmp->startp[midx]; match_ptr != rmp->endp[midx];
+ ++match_ptr)
+ {
+ ++fields->col;
+ if (*match_ptr == TAB)
+ {
+ fields->col += 7;
+ fields->col -= fields->col % 8;
+ }
+ }
+ ++fields->col;
+ fields->use_viscol = TRUE;
+ return QF_OK;
+}
+
+/*
+ * Parse the match for the virtual column number ('%v') pattern in regmatch.
+ * Return the matched value in "fields->col".
+ */
+ static int
+qf_parse_fmt_v(regmatch_T *rmp, int midx, qffields_T *fields)
+{
+ if (rmp->startp[midx] == NULL)
+ return QF_FAIL;
+ fields->col = (int)atol((char *)rmp->startp[midx]);
+ fields->use_viscol = TRUE;
+ return QF_OK;
+}
+
+/*
+ * Parse the match for the search text ('%s') pattern in regmatch.
+ * Return the matched value in "fields->pattern".
+ */
+ static int
+qf_parse_fmt_s(regmatch_T *rmp, int midx, qffields_T *fields)
+{
+ int len;
+
+ if (rmp->startp[midx] == NULL || rmp->endp[midx] == NULL)
+ return QF_FAIL;
+ len = (int)(rmp->endp[midx] - rmp->startp[midx]);
+ if (len > CMDBUFFSIZE - 5)
+ len = CMDBUFFSIZE - 5;
+ STRCPY(fields->pattern, "^\\V");
+ STRNCAT(fields->pattern, rmp->startp[midx], len);
+ fields->pattern[len + 3] = '\\';
+ fields->pattern[len + 4] = '$';
+ fields->pattern[len + 5] = NUL;
+ return QF_OK;
+}
+
+/*
+ * Parse the match for the module ('%o') pattern in regmatch.
+ * Return the matched value in "fields->module".
+ */
+ static int
+qf_parse_fmt_o(regmatch_T *rmp, int midx, qffields_T *fields)
+{
+ int len;
+
+ if (rmp->startp[midx] == NULL || rmp->endp[midx] == NULL)
+ return QF_FAIL;
+ len = (int)(rmp->endp[midx] - rmp->startp[midx]);
+ if (len > CMDBUFFSIZE)
+ len = CMDBUFFSIZE;
+ STRNCAT(fields->module, rmp->startp[midx], len);
+ return QF_OK;
+}
+
+/*
+ * 'errorformat' format pattern parser functions.
+ * The '%f' and '%r' formats are parsed differently from other formats.
+ * See qf_parse_match() for details.
+ */
+static int (*qf_parse_fmt[FMT_PATTERNS])(regmatch_T *, int, qffields_T *) =
+{
+ NULL,
+ qf_parse_fmt_n,
+ qf_parse_fmt_l,
+ qf_parse_fmt_c,
+ qf_parse_fmt_t,
+ qf_parse_fmt_m,
+ NULL,
+ qf_parse_fmt_p,
+ qf_parse_fmt_v,
+ qf_parse_fmt_s,
+ qf_parse_fmt_o
+};
+
+/*
+ * Parse the error format pattern matches in "regmatch" and set the values in
+ * "fields". fmt_ptr contains the 'efm' format specifiers/prefixes that have a
+ * match. Returns QF_OK if all the matches are successfully parsed. On
+ * failure, returns QF_FAIL or QF_NOMEM.
+ */
+ static int
+qf_parse_match(
+ char_u *linebuf,
+ int linelen,
+ efm_T *fmt_ptr,
+ regmatch_T *regmatch,
+ qffields_T *fields,
+ int qf_multiline,
+ int qf_multiscan,
+ char_u **tail)
+{
+ int idx = fmt_ptr->prefix;
+ int i;
+ int midx;
+ int status;
+
+ if ((idx == 'C' || idx == 'Z') && !qf_multiline)
+ return QF_FAIL;
+ if (vim_strchr((char_u *)"EWI", idx) != NULL)
+ fields->type = idx;
+ else
+ fields->type = 0;
+
+ // Extract error message data from matched line.
+ // We check for an actual submatch, because "\[" and "\]" in
+ // the 'errorformat' may cause the wrong submatch to be used.
+ for (i = 0; i < FMT_PATTERNS; i++)
+ {
+ status = QF_OK;
+ midx = (int)fmt_ptr->addr[i];
+ if (i == 0 && midx > 0) // %f
+ status = qf_parse_fmt_f(regmatch, midx, fields, idx);
+ else if (i == 5)
+ {
+ if (fmt_ptr->flags == '+' && !qf_multiscan) // %+
+ status = qf_parse_fmt_plus(linebuf, linelen, fields);
+ else if (midx > 0) // %m
+ status = qf_parse_fmt_m(regmatch, midx, fields);
+ }
+ else if (i == 6 && midx > 0) // %r
+ status = qf_parse_fmt_r(regmatch, midx, tail);
+ else if (midx > 0) // others
+ status = (qf_parse_fmt[i])(regmatch, midx, fields);
+
+ if (status != QF_OK)
+ return status;
+ }
+
+ return QF_OK;
+}
+
+/*
+ * Parse an error line in 'linebuf' using a single error format string in
+ * 'fmt_ptr->prog' and return the matching values in 'fields'.
+ * Returns QF_OK if the efm format matches completely and the fields are
+ * successfully copied. Otherwise returns QF_FAIL or QF_NOMEM.
+ */
+ static int
+qf_parse_get_fields(
+ char_u *linebuf,
+ int linelen,
+ efm_T *fmt_ptr,
+ qffields_T *fields,
+ int qf_multiline,
+ int qf_multiscan,
+ char_u **tail)
+{
+ regmatch_T regmatch;
+ int status = QF_FAIL;
+ int r;
+
+ if (qf_multiscan &&
+ vim_strchr((char_u *)"OPQ", fmt_ptr->prefix) == NULL)
+ return QF_FAIL;
+
+ fields->namebuf[0] = NUL;
+ fields->module[0] = NUL;
+ fields->pattern[0] = NUL;
+ if (!qf_multiscan)
+ fields->errmsg[0] = NUL;
+ fields->lnum = 0;
+ fields->col = 0;
+ fields->use_viscol = FALSE;
+ fields->enr = -1;
+ fields->type = 0;
+ *tail = NULL;
+
+ // Always ignore case when looking for a matching error.
+ regmatch.rm_ic = TRUE;
+ regmatch.regprog = fmt_ptr->prog;
+ r = vim_regexec(&regmatch, linebuf, (colnr_T)0);
+ fmt_ptr->prog = regmatch.regprog;
+ if (r)
+ status = qf_parse_match(linebuf, linelen, fmt_ptr, &regmatch,
+ fields, qf_multiline, qf_multiscan, tail);
+
+ return status;
+}
+
+/*
+ * Parse directory error format prefixes (%D and %X).
+ * Push and pop directories from the directory stack when scanning directory
+ * names.
+ */
+ static int
+qf_parse_dir_pfx(int idx, qffields_T *fields, qf_list_T *qfl)
+{
+ if (idx == 'D') // enter directory
+ {
+ if (*fields->namebuf == NUL)
+ {
+ emsg(_("E379: Missing or empty directory name"));
+ return QF_FAIL;
+ }
+ qfl->qf_directory =
+ qf_push_dir(fields->namebuf, &qfl->qf_dir_stack, FALSE);
+ if (qfl->qf_directory == NULL)
+ return QF_FAIL;
+ }
+ else if (idx == 'X') // leave directory
+ qfl->qf_directory = qf_pop_dir(&qfl->qf_dir_stack);
+
+ return QF_OK;
+}
+
+/*
+ * Parse global file name error format prefixes (%O, %P and %Q).
+ */
+ static int
+qf_parse_file_pfx(
+ int idx,
+ qffields_T *fields,
+ qf_list_T *qfl,
+ char_u *tail)
+{
+ fields->valid = FALSE;
+ if (*fields->namebuf == NUL || mch_getperm(fields->namebuf) >= 0)
+ {
+ if (*fields->namebuf && idx == 'P')
+ qfl->qf_currfile =
+ qf_push_dir(fields->namebuf, &qfl->qf_file_stack, TRUE);
+ else if (idx == 'Q')
+ qfl->qf_currfile = qf_pop_dir(&qfl->qf_file_stack);
+ *fields->namebuf = NUL;
+ if (tail && *tail)
+ {
+ STRMOVE(IObuff, skipwhite(tail));
+ qfl->qf_multiscan = TRUE;
+ return QF_MULTISCAN;
+ }
+ }
+
+ return QF_OK;
+}
+
+/*
+ * Parse a non-error line (a line which doesn't match any of the error
+ * format in 'efm').
+ */
+ static int
+qf_parse_line_nomatch(char_u *linebuf, int linelen, qffields_T *fields)
+{
+ char_u *p;
+
+ fields->namebuf[0] = NUL; // no match found, remove file name
+ fields->lnum = 0; // don't jump to this line
+ fields->valid = FALSE;
+ if (linelen >= fields->errmsglen)
+ {
+ // linelen + null terminator
+ if ((p = vim_realloc(fields->errmsg, linelen + 1)) == NULL)
+ return QF_NOMEM;
+ fields->errmsg = p;
+ fields->errmsglen = linelen + 1;
+ }
+ // copy whole line to error message
+ vim_strncpy(fields->errmsg, linebuf, linelen);
+
+ return QF_OK;
+}
+
+/*
+ * Parse multi-line error format prefixes (%C and %Z)
+ */
+ static int
+qf_parse_multiline_pfx(
+ qf_info_T *qi,
+ int qf_idx,
+ int idx,
+ qf_list_T *qfl,
+ qffields_T *fields)
+{
+ char_u *ptr;
+ int len;
+
+ if (!qfl->qf_multiignore)
+ {
+ qfline_T *qfprev = qfl->qf_last;
+
+ if (qfprev == NULL)
+ return QF_FAIL;
+ if (*fields->errmsg && !qfl->qf_multiignore)
+ {
+ len = (int)STRLEN(qfprev->qf_text);
+ if ((ptr = alloc((unsigned)(len + STRLEN(fields->errmsg) + 2)))
+ == NULL)
+ return QF_FAIL;
+ STRCPY(ptr, qfprev->qf_text);
+ vim_free(qfprev->qf_text);
+ qfprev->qf_text = ptr;
+ *(ptr += len) = '\n';
+ STRCPY(++ptr, fields->errmsg);
+ }
+ if (qfprev->qf_nr == -1)
+ qfprev->qf_nr = fields->enr;
+ if (vim_isprintc(fields->type) && !qfprev->qf_type)
+ // only printable chars allowed
+ qfprev->qf_type = fields->type;
+
+ if (!qfprev->qf_lnum)
+ qfprev->qf_lnum = fields->lnum;
+ if (!qfprev->qf_col)
+ qfprev->qf_col = fields->col;
+ qfprev->qf_viscol = fields->use_viscol;
+ if (!qfprev->qf_fnum)
+ qfprev->qf_fnum = qf_get_fnum(qi, qf_idx,
+ qfl->qf_directory,
+ *fields->namebuf || qfl->qf_directory != NULL
+ ? fields->namebuf
+ : qfl->qf_currfile != NULL && fields->valid
+ ? qfl->qf_currfile : 0);
+ }
+ if (idx == 'Z')
+ qfl->qf_multiline = qfl->qf_multiignore = FALSE;
+ line_breakcheck();
+
+ return QF_IGNORE_LINE;
+}
+
+/*
+ * Parse a line and get the quickfix fields.
+ * Return the QF_ status.
+ */
+ static int
+qf_parse_line(
+ qf_info_T *qi,
+ int qf_idx,
+ char_u *linebuf,
+ int linelen,
+ efm_T *fmt_first,
+ qffields_T *fields)
+{
+ efm_T *fmt_ptr;
+ int idx = 0;
+ char_u *tail = NULL;
+ qf_list_T *qfl = &qi->qf_lists[qf_idx];
+ int status;
+
+restofline:
+ // If there was no %> item start at the first pattern
+ if (fmt_start == NULL)
+ fmt_ptr = fmt_first;
+ else
+ {
+ // Otherwise start from the last used pattern
+ fmt_ptr = fmt_start;
+ fmt_start = NULL;
+ }
+
+ // Try to match each part of 'errorformat' until we find a complete
+ // match or no match.
+ fields->valid = TRUE;
+ for ( ; fmt_ptr != NULL; fmt_ptr = fmt_ptr->next)
+ {
+ idx = fmt_ptr->prefix;
+ status = qf_parse_get_fields(linebuf, linelen, fmt_ptr, fields,
+ qfl->qf_multiline, qfl->qf_multiscan, &tail);
+ if (status == QF_NOMEM)
+ return status;
+ if (status == QF_OK)
+ break;
+ }
+ qfl->qf_multiscan = FALSE;
+
+ if (fmt_ptr == NULL || idx == 'D' || idx == 'X')
+ {
+ if (fmt_ptr != NULL)
+ {
+ // 'D' and 'X' directory specifiers
+ status = qf_parse_dir_pfx(idx, fields, qfl);
+ if (status != QF_OK)
+ return status;
+ }
+
+ status = qf_parse_line_nomatch(linebuf, linelen, fields);
+ if (status != QF_OK)
+ return status;
+
+ if (fmt_ptr == NULL)
+ qfl->qf_multiline = qfl->qf_multiignore = FALSE;
+ }
+ else if (fmt_ptr != NULL)
+ {
+ // honor %> item
+ if (fmt_ptr->conthere)
+ fmt_start = fmt_ptr;
+
+ if (vim_strchr((char_u *)"AEWI", idx) != NULL)
+ {
+ qfl->qf_multiline = TRUE; // start of a multi-line message
+ qfl->qf_multiignore = FALSE;// reset continuation
+ }
+ else if (vim_strchr((char_u *)"CZ", idx) != NULL)
+ { // continuation of multi-line msg
+ status = qf_parse_multiline_pfx(qi, qf_idx, idx, qfl, fields);
+ if (status != QF_OK)
+ return status;
+ }
+ else if (vim_strchr((char_u *)"OPQ", idx) != NULL)
+ { // global file names
+ status = qf_parse_file_pfx(idx, fields, qfl, tail);
+ if (status == QF_MULTISCAN)
+ goto restofline;
+ }
+ if (fmt_ptr->flags == '-') // generally exclude this line
+ {
+ if (qfl->qf_multiline)
+ // also exclude continuation lines
+ qfl->qf_multiignore = TRUE;
+ return QF_IGNORE_LINE;
+ }
+ }
+
+ return QF_OK;
+}
+
+/*
+ * Returns TRUE if the specified quickfix/location stack is empty
+ */
+ static int
+qf_stack_empty(qf_info_T *qi)
+{
+ return qi == NULL || qi->qf_listcount <= 0;
+}
+
+/*
+ * Returns TRUE if the specified quickfix/location list is empty.
+ */
+ static int
+qf_list_empty(qf_info_T *qi, int qf_idx)
+{
+ if (qi == NULL || qf_idx < 0 || qf_idx >= LISTCOUNT)
+ return TRUE;
+ return qi->qf_lists[qf_idx].qf_count <= 0;
+}
+
+/*
+ * Allocate the fields used for parsing lines and populating a quickfix list.
+ */
+ static int
+qf_alloc_fields(qffields_T *pfields)
+{
+ pfields->namebuf = alloc_id(CMDBUFFSIZE + 1, aid_qf_namebuf);
+ pfields->module = alloc_id(CMDBUFFSIZE + 1, aid_qf_module);
+ pfields->errmsglen = CMDBUFFSIZE + 1;
+ pfields->errmsg = alloc_id(pfields->errmsglen, aid_qf_errmsg);
+ pfields->pattern = alloc_id(CMDBUFFSIZE + 1, aid_qf_pattern);
+ if (pfields->namebuf == NULL || pfields->errmsg == NULL
+ || pfields->pattern == NULL || pfields->module == NULL)
+ return FAIL;
+
+ return OK;
+}
+
+/*
+ * Free the fields used for parsing lines and populating a quickfix list.
+ */
+ static void
+qf_free_fields(qffields_T *pfields)
+{
+ vim_free(pfields->namebuf);
+ vim_free(pfields->module);
+ vim_free(pfields->errmsg);
+ vim_free(pfields->pattern);
+}
+
+/*
+ * Setup the state information used for parsing lines and populating a
+ * quickfix list.
+ */
+ static int
+qf_setup_state(
+ qfstate_T *pstate,
+ char_u *enc,
+ char_u *efile,
+ typval_T *tv,
+ buf_T *buf,
+ linenr_T lnumfirst,
+ linenr_T lnumlast)
+{
+ pstate->vc.vc_type = CONV_NONE;
+ if (enc != NULL && *enc != NUL)
+ convert_setup(&pstate->vc, enc, p_enc);
+
+ if (efile != NULL && (pstate->fd = mch_fopen((char *)efile, "r")) == NULL)
+ {
+ semsg(_(e_openerrf), efile);
+ return FAIL;
+ }
+
+ if (tv != NULL)
+ {
+ if (tv->v_type == VAR_STRING)
+ pstate->p_str = tv->vval.v_string;
+ else if (tv->v_type == VAR_LIST)
+ pstate->p_li = tv->vval.v_list->lv_first;
+ pstate->tv = tv;
+ }
+ pstate->buf = buf;
+ pstate->buflnum = lnumfirst;
+ pstate->lnumlast = lnumlast;
+
+ return OK;
+}
+
+/*
+ * Cleanup the state information used for parsing lines and populating a
+ * quickfix list.
+ */
+ static void
+qf_cleanup_state(qfstate_T *pstate)
+{
+ if (pstate->fd != NULL)
+ fclose(pstate->fd);
+
+ vim_free(pstate->growbuf);
+ if (pstate->vc.vc_type != CONV_NONE)
+ convert_setup(&pstate->vc, NULL, NULL);
+}
+
+/*
+ * Read the errorfile "efile" into memory, line by line, building the error
+ * list.
+ * Alternative: when "efile" is NULL read errors from buffer "buf".
+ * Alternative: when "tv" is not NULL get errors from the string or list.
+ * Always use 'errorformat' from "buf" if there is a local value.
+ * Then "lnumfirst" and "lnumlast" specify the range of lines to use.
+ * Set the title of the list to "qf_title".
+ * Return -1 for error, number of errors for success.
+ */
+ static int
+qf_init_ext(
+ qf_info_T *qi,
+ int qf_idx,
+ char_u *efile,
+ buf_T *buf,
+ typval_T *tv,
+ char_u *errorformat,
+ int newlist, // TRUE: start a new error list
+ linenr_T lnumfirst, // first line number to use
+ linenr_T lnumlast, // last line number to use
+ char_u *qf_title,
+ char_u *enc)
+{
+ qf_list_T *qfl;
+ qfstate_T state;
+ qffields_T fields;
+ qfline_T *old_last = NULL;
+ int adding = FALSE;
+ static efm_T *fmt_first = NULL;
+ char_u *efm;
+ static char_u *last_efm = NULL;
+ int retval = -1; // default: return error flag
+ int status;
+
+ // Do not used the cached buffer, it may have been wiped out.
+ VIM_CLEAR(qf_last_bufname);
+
+ vim_memset(&state, 0, sizeof(state));
+ vim_memset(&fields, 0, sizeof(fields));
+ if ((qf_alloc_fields(&fields) == FAIL) ||
+ (qf_setup_state(&state, enc, efile, tv, buf,
+ lnumfirst, lnumlast) == FAIL))
+ goto qf_init_end;
+
+ if (newlist || qf_idx == qi->qf_listcount)
+ {
+ // make place for a new list
+ qf_new_list(qi, qf_title);
+ qf_idx = qi->qf_curlist;
+ }
+ else
+ {
+ // Adding to existing list, use last entry.
+ adding = TRUE;
+ if (!qf_list_empty(qi, qf_idx))
+ old_last = qi->qf_lists[qf_idx].qf_last;
+ }
+
+ qfl = &qi->qf_lists[qf_idx];
+
+ // Use the local value of 'errorformat' if it's set.
+ if (errorformat == p_efm && tv == NULL && *buf->b_p_efm != NUL)
+ efm = buf->b_p_efm;
+ else
+ efm = errorformat;
+
+ // If the errorformat didn't change between calls, then reuse the
+ // previously parsed values.
+ if (last_efm == NULL || (STRCMP(last_efm, efm) != 0))
+ {
+ // free the previously parsed data
+ VIM_CLEAR(last_efm);
+ free_efm_list(&fmt_first);
+
+ // parse the current 'efm'
+ fmt_first = parse_efm_option(efm);
+ if (fmt_first != NULL)
+ last_efm = vim_strsave(efm);
+ }
+
+ if (fmt_first == NULL) // nothing found
+ goto error2;
+
+ // got_int is reset here, because it was probably set when killing the
+ // ":make" command, but we still want to read the errorfile then.
+ got_int = FALSE;
+
+ // Read the lines in the error file one by one.
+ // Try to recognize one of the error formats in each line.
+ while (!got_int)
+ {
+ // Get the next line from a file/buffer/list/string
+ status = qf_get_nextline(&state);
+ if (status == QF_NOMEM) // memory alloc failure
+ goto qf_init_end;
+ if (status == QF_END_OF_INPUT) // end of input
+ break;
+
+ status = qf_parse_line(qi, qf_idx, state.linebuf, state.linelen,
+ fmt_first, &fields);
+ if (status == QF_FAIL)
+ goto error2;
+ if (status == QF_NOMEM)
+ goto qf_init_end;
+ if (status == QF_IGNORE_LINE)
+ continue;
+
+ if (qf_add_entry(qi,
+ qf_idx,
+ qfl->qf_directory,
+ (*fields.namebuf || qfl->qf_directory != NULL)
+ ? fields.namebuf
+ : ((qfl->qf_currfile != NULL && fields.valid)
+ ? qfl->qf_currfile : (char_u *)NULL),
+ fields.module,
+ 0,
+ fields.errmsg,
+ fields.lnum,
+ fields.col,
+ fields.use_viscol,
+ fields.pattern,
+ fields.enr,
+ fields.type,
+ fields.valid) == FAIL)
+ goto error2;
+ line_breakcheck();
+ }
+ if (state.fd == NULL || !ferror(state.fd))
+ {
+ if (qfl->qf_index == 0)
+ {
+ // no valid entry found
+ qfl->qf_ptr = qfl->qf_start;
+ qfl->qf_index = 1;
+ qfl->qf_nonevalid = TRUE;
+ }
+ else
+ {
+ qfl->qf_nonevalid = FALSE;
+ if (qfl->qf_ptr == NULL)
+ qfl->qf_ptr = qfl->qf_start;
+ }
+ // return number of matches
+ retval = qfl->qf_count;
+ goto qf_init_end;
+ }
+ emsg(_(e_readerrf));
+error2:
+ if (!adding)
+ {
+ // Error when creating a new list. Free the new list
+ qf_free(qfl);
+ qi->qf_listcount--;
+ if (qi->qf_curlist > 0)
+ --qi->qf_curlist;
+ }
+qf_init_end:
+ if (qf_idx == qi->qf_curlist)
+ qf_update_buffer(qi, old_last);
+ qf_cleanup_state(&state);
+ qf_free_fields(&fields);
+
+ return retval;
+}
+
+/*
+ * Read the errorfile "efile" into memory, line by line, building the error
+ * list. Set the error list's title to qf_title.
+ * Return -1 for error, number of errors for success.
+ */
+ int
+qf_init(win_T *wp,
+ char_u *efile,
+ char_u *errorformat,
+ int newlist, // TRUE: start a new error list
+ char_u *qf_title,
+ char_u *enc)
+{
+ qf_info_T *qi = &ql_info;
+
+ if (wp != NULL)
+ {
+ qi = ll_get_or_alloc_list(wp);
+ if (qi == NULL)
+ return FAIL;
+ }
+
+ return qf_init_ext(qi, qi->qf_curlist, efile, curbuf, NULL, errorformat,
+ newlist, (linenr_T)0, (linenr_T)0, qf_title, enc);
+}
+
+/*
+ * Set the title of the specified quickfix list. Frees the previous title.
+ * Prepends ':' to the title.
+ */
+ static void
+qf_store_title(qf_list_T *qfl, char_u *title)
+{
+ VIM_CLEAR(qfl->qf_title);
+
+ if (title != NULL)
+ {
+ char_u *p = alloc((int)STRLEN(title) + 2);
+
+ qfl->qf_title = p;
+ if (p != NULL)
+ STRCPY(p, title);
+ }
+}
+
+/*
+ * The title of a quickfix/location list is set, by default, to the command
+ * that created the quickfix list with the ":" prefix.
+ * Create a quickfix list title string by prepending ":" to a user command.
+ * Returns a pointer to a static buffer with the title.
+ */
+ static char_u *
+qf_cmdtitle(char_u *cmd)
+{
+ static char_u qftitle_str[IOSIZE];
+
+ vim_snprintf((char *)qftitle_str, IOSIZE, ":%s", (char *)cmd);
+ return qftitle_str;
+}
+
+/*
+ * Prepare for adding a new quickfix list. If the current list is in the
+ * middle of the stack, then all the following lists are freed and then
+ * the new list is added.
+ */
+ static void
+qf_new_list(qf_info_T *qi, char_u *qf_title)
+{
+ int i;
+ qf_list_T *qfl;
+
+ // If the current entry is not the last entry, delete entries beyond
+ // the current entry. This makes it possible to browse in a tree-like
+ // way with ":grep'.
+ while (qi->qf_listcount > qi->qf_curlist + 1)
+ qf_free(&qi->qf_lists[--qi->qf_listcount]);
+
+ // When the stack is full, remove to oldest entry
+ // Otherwise, add a new entry.
+ if (qi->qf_listcount == LISTCOUNT)
+ {
+ qf_free(&qi->qf_lists[0]);
+ for (i = 1; i < LISTCOUNT; ++i)
+ qi->qf_lists[i - 1] = qi->qf_lists[i];
+ qi->qf_curlist = LISTCOUNT - 1;
+ }
+ else
+ qi->qf_curlist = qi->qf_listcount++;
+ qfl = &qi->qf_lists[qi->qf_curlist];
+ vim_memset(qfl, 0, (size_t)(sizeof(qf_list_T)));
+ qf_store_title(qfl, qf_title);
+ qfl->qfl_type = qi->qfl_type;
+ qfl->qf_id = ++last_qf_id;
+}
+
+/*
+ * Queue location list stack delete request.
+ */
+ static void
+locstack_queue_delreq(qf_info_T *qi)
+{
+ qf_delq_T *q;
+
+ q = (qf_delq_T *)alloc((unsigned)sizeof(qf_delq_T));
+ if (q != NULL)
+ {
+ q->qi = qi;
+ q->next = qf_delq_head;
+ qf_delq_head = q;
+ }
+}
+
+/*
+ * Free a location list stack
+ */
+ static void
+ll_free_all(qf_info_T **pqi)
+{
+ int i;
+ qf_info_T *qi;
+
+ qi = *pqi;
+ if (qi == NULL)
+ return;
+ *pqi = NULL; // Remove reference to this list
+
+ qi->qf_refcount--;
+ if (qi->qf_refcount < 1)
+ {
+ // No references to this location list.
+ // If the location list is still in use, then queue the delete request
+ // to be processed later.
+ if (quickfix_busy > 0)
+ locstack_queue_delreq(qi);
+ else
+ {
+ for (i = 0; i < qi->qf_listcount; ++i)
+ qf_free(&qi->qf_lists[i]);
+ vim_free(qi);
+ }
+ }
+}
+
+/*
+ * Free all the quickfix/location lists in the stack.
+ */
+ void
+qf_free_all(win_T *wp)
+{
+ int i;
+ qf_info_T *qi = &ql_info;
+
+ if (wp != NULL)
+ {
+ // location list
+ ll_free_all(&wp->w_llist);
+ ll_free_all(&wp->w_llist_ref);
+ }
+ else
+ // quickfix list
+ for (i = 0; i < qi->qf_listcount; ++i)
+ qf_free(&qi->qf_lists[i]);
+}
+
+/*
+ * Delay freeing of location list stacks when the quickfix code is running.
+ * Used to avoid problems with autocmds freeing location list stacks when the
+ * quickfix code is still referencing the stack.
+ * Must always call decr_quickfix_busy() exactly once after this.
+ */
+ static void
+incr_quickfix_busy(void)
+{
+ quickfix_busy++;
+}
+
+/*
+ * Safe to free location list stacks. Process any delayed delete requests.
+ */
+ static void
+decr_quickfix_busy(void)
+{
+ if (--quickfix_busy == 0)
+ {
+ // No longer referencing the location lists. Process all the pending
+ // delete requests.
+ while (qf_delq_head != NULL)
+ {
+ qf_delq_T *q = qf_delq_head;
+
+ qf_delq_head = q->next;
+ ll_free_all(&q->qi);
+ vim_free(q);
+ }
+ }
+#ifdef ABORT_ON_INTERNAL_ERROR
+ if (quickfix_busy < 0)
+ {
+ emsg("quickfix_busy has become negative");
+ abort();
+ }
+#endif
+}
+
+#if defined(EXITFREE) || defined(PROTO)
+ void
+check_quickfix_busy(void)
+{
+ if (quickfix_busy != 0)
+ {
+ semsg("quickfix_busy not zero on exit: %ld", (long)quickfix_busy);
+# ifdef ABORT_ON_INTERNAL_ERROR
+ abort();
+# endif
+ }
+}
+#endif
+
+/*
+ * Add an entry to the end of the list of errors.
+ * Returns OK or FAIL.
+ */
+ static int
+qf_add_entry(
+ qf_info_T *qi, // quickfix list
+ int qf_idx, // list index
+ char_u *dir, // optional directory name
+ char_u *fname, // file name or NULL
+ char_u *module, // module name or NULL
+ int bufnum, // buffer number or zero
+ char_u *mesg, // message
+ long lnum, // line number
+ int col, // column
+ int vis_col, // using visual column
+ char_u *pattern, // search pattern
+ int nr, // error number
+ int type, // type character
+ int valid) // valid entry
+{
+ qf_list_T *qfl = &qi->qf_lists[qf_idx];
+ qfline_T *qfp;
+ qfline_T **lastp; // pointer to qf_last or NULL
+
+ if ((qfp = (qfline_T *)alloc((unsigned)sizeof(qfline_T))) == NULL)
+ return FAIL;
+ if (bufnum != 0)
+ {
+ buf_T *buf = buflist_findnr(bufnum);
+
+ qfp->qf_fnum = bufnum;
+ if (buf != NULL)
+ buf->b_has_qf_entry |=
+ IS_QF_LIST(qfl) ? BUF_HAS_QF_ENTRY : BUF_HAS_LL_ENTRY;
+ }
+ else
+ qfp->qf_fnum = qf_get_fnum(qi, qf_idx, dir, fname);
+ if ((qfp->qf_text = vim_strsave(mesg)) == NULL)
+ {
+ vim_free(qfp);
+ return FAIL;
+ }
+ qfp->qf_lnum = lnum;
+ qfp->qf_col = col;
+ qfp->qf_viscol = vis_col;
+ if (pattern == NULL || *pattern == NUL)
+ qfp->qf_pattern = NULL;
+ else if ((qfp->qf_pattern = vim_strsave(pattern)) == NULL)
+ {
+ vim_free(qfp->qf_text);
+ vim_free(qfp);
+ return FAIL;
+ }
+ if (module == NULL || *module == NUL)
+ qfp->qf_module = NULL;
+ else if ((qfp->qf_module = vim_strsave(module)) == NULL)
+ {
+ vim_free(qfp->qf_text);
+ vim_free(qfp->qf_pattern);
+ vim_free(qfp);
+ return FAIL;
+ }
+ qfp->qf_nr = nr;
+ if (type != 1 && !vim_isprintc(type)) // only printable chars allowed
+ type = 0;
+ qfp->qf_type = type;
+ qfp->qf_valid = valid;
+
+ lastp = &qfl->qf_last;
+ if (qf_list_empty(qi, qf_idx)) // first element in the list
+ {
+ qfl->qf_start = qfp;
+ qfl->qf_ptr = qfp;
+ qfl->qf_index = 0;
+ qfp->qf_prev = NULL;
+ }
+ else
+ {
+ qfp->qf_prev = *lastp;
+ (*lastp)->qf_next = qfp;
+ }
+ qfp->qf_next = NULL;
+ qfp->qf_cleared = FALSE;
+ *lastp = qfp;
+ ++qfl->qf_count;
+ if (qfl->qf_index == 0 && qfp->qf_valid) // first valid entry
+ {
+ qfl->qf_index = qfl->qf_count;
+ qfl->qf_ptr = qfp;
+ }
+
+ return OK;
+}
+
+/*
+ * Allocate a new quickfix/location list stack
+ */
+ static qf_info_T *
+qf_alloc_stack(qfltype_T qfltype)
+{
+ qf_info_T *qi;
+
+ qi = (qf_info_T *)alloc_clear((unsigned)sizeof(qf_info_T));
+ if (qi != NULL)
+ {
+ qi->qf_refcount++;
+ qi->qfl_type = qfltype;
+ }
+ return qi;
+}
+
+/*
+ * Return the location list stack for window 'wp'.
+ * If not present, allocate a location list stack
+ */
+ static qf_info_T *
+ll_get_or_alloc_list(win_T *wp)
+{
+ if (IS_LL_WINDOW(wp))
+ // For a location list window, use the referenced location list
+ return wp->w_llist_ref;
+
+ // For a non-location list window, w_llist_ref should not point to a
+ // location list.
+ ll_free_all(&wp->w_llist_ref);
+
+ if (wp->w_llist == NULL)
+ wp->w_llist = qf_alloc_stack(QFLT_LOCATION); // new location list
+ return wp->w_llist;
+}
+
+/*
+ * Copy location list entries from 'from_qfl' to 'to_qfl'.
+ */
+ static int
+copy_loclist_entries(qf_list_T *from_qfl, qf_list_T *to_qfl, qf_info_T *to_qi)
+{
+ int i;
+ qfline_T *from_qfp;
+ qfline_T *prevp;
+
+ // copy all the location entries in this list
+ for (i = 0, from_qfp = from_qfl->qf_start;
+ i < from_qfl->qf_count && from_qfp != NULL;
+ ++i, from_qfp = from_qfp->qf_next)
+ {
+ if (qf_add_entry(to_qi,
+ to_qi->qf_curlist,
+ NULL,
+ NULL,
+ from_qfp->qf_module,
+ 0,
+ from_qfp->qf_text,
+ from_qfp->qf_lnum,
+ from_qfp->qf_col,
+ from_qfp->qf_viscol,
+ from_qfp->qf_pattern,
+ from_qfp->qf_nr,
+ 0,
+ from_qfp->qf_valid) == FAIL)
+ return FAIL;
+
+ // qf_add_entry() will not set the qf_num field, as the
+ // directory and file names are not supplied. So the qf_fnum
+ // field is copied here.
+ prevp = to_qfl->qf_last;
+ prevp->qf_fnum = from_qfp->qf_fnum; // file number
+ prevp->qf_type = from_qfp->qf_type; // error type
+ if (from_qfl->qf_ptr == from_qfp)
+ to_qfl->qf_ptr = prevp; // current location
+ }
+
+ return OK;
+}
+
+/*
+ * Copy the specified location list 'from_qfl' to 'to_qfl'.
+ */
+ static int
+copy_loclist(qf_list_T *from_qfl, qf_list_T *to_qfl, qf_info_T *to_qi)
+{
+ // Some of the fields are populated by qf_add_entry()
+ to_qfl->qfl_type = from_qfl->qfl_type;
+ to_qfl->qf_nonevalid = from_qfl->qf_nonevalid;
+ to_qfl->qf_count = 0;
+ to_qfl->qf_index = 0;
+ to_qfl->qf_start = NULL;
+ to_qfl->qf_last = NULL;
+ to_qfl->qf_ptr = NULL;
+ if (from_qfl->qf_title != NULL)
+ to_qfl->qf_title = vim_strsave(from_qfl->qf_title);
+ else
+ to_qfl->qf_title = NULL;
+ if (from_qfl->qf_ctx != NULL)
+ {
+ to_qfl->qf_ctx = alloc_tv();
+ if (to_qfl->qf_ctx != NULL)
+ copy_tv(from_qfl->qf_ctx, to_qfl->qf_ctx);
+ }
+ else
+ to_qfl->qf_ctx = NULL;
+
+ if (from_qfl->qf_count)
+ if (copy_loclist_entries(from_qfl, to_qfl, to_qi) == FAIL)
+ return FAIL;
+
+ to_qfl->qf_index = from_qfl->qf_index; // current index in the list
+
+ // Assign a new ID for the location list
+ to_qfl->qf_id = ++last_qf_id;
+ to_qfl->qf_changedtick = 0L;
+
+ // When no valid entries are present in the list, qf_ptr points to
+ // the first item in the list
+ if (to_qfl->qf_nonevalid)
+ {
+ to_qfl->qf_ptr = to_qfl->qf_start;
+ to_qfl->qf_index = 1;
+ }
+
+ return OK;
+}
+
+/*
+ * Copy the location list stack 'from' window to 'to' window.
+ */
+ void
+copy_loclist_stack(win_T *from, win_T *to)
+{
+ qf_info_T *qi;
+ int idx;
+
+ // When copying from a location list window, copy the referenced
+ // location list. For other windows, copy the location list for
+ // that window.
+ if (IS_LL_WINDOW(from))
+ qi = from->w_llist_ref;
+ else
+ qi = from->w_llist;
+
+ if (qi == NULL) // no location list to copy
+ return;
+
+ // allocate a new location list
+ if ((to->w_llist = qf_alloc_stack(QFLT_LOCATION)) == NULL)
+ return;
+
+ to->w_llist->qf_listcount = qi->qf_listcount;
+
+ // Copy the location lists one at a time
+ for (idx = 0; idx < qi->qf_listcount; ++idx)
+ {
+ to->w_llist->qf_curlist = idx;
+
+ if (copy_loclist(&qi->qf_lists[idx],
+ &to->w_llist->qf_lists[idx], to->w_llist) == FAIL)
+ {
+ qf_free_all(to);
+ return;
+ }
+ }
+
+ to->w_llist->qf_curlist = qi->qf_curlist; // current list
+}
+
+/*
+ * Get buffer number for file "directory/fname".
+ * Also sets the b_has_qf_entry flag.
+ */
+ static int
+qf_get_fnum(qf_info_T *qi, int qf_idx, char_u *directory, char_u *fname)
+{
+ qf_list_T *qfl = &qi->qf_lists[qf_idx];
+ char_u *ptr = NULL;
+ buf_T *buf;
+ char_u *bufname;
+
+ if (fname == NULL || *fname == NUL) // no file name
+ return 0;
+
+#ifdef VMS
+ vms_remove_version(fname);
+#endif
+#ifdef BACKSLASH_IN_FILENAME
+ if (directory != NULL)
+ slash_adjust(directory);
+ slash_adjust(fname);
+#endif
+ if (directory != NULL && !vim_isAbsName(fname)
+ && (ptr = concat_fnames(directory, fname, TRUE)) != NULL)
+ {
+ // Here we check if the file really exists.
+ // This should normally be true, but if make works without
+ // "leaving directory"-messages we might have missed a
+ // directory change.
+ if (mch_getperm(ptr) < 0)
+ {
+ vim_free(ptr);
+ directory = qf_guess_filepath(qfl, fname);
+ if (directory)
+ ptr = concat_fnames(directory, fname, TRUE);
+ else
+ ptr = vim_strsave(fname);
+ }
+ // Use concatenated directory name and file name
+ bufname = ptr;
+ }
+ else
+ bufname = fname;
+
+ if (qf_last_bufname != NULL && STRCMP(bufname, qf_last_bufname) == 0
+ && bufref_valid(&qf_last_bufref))
+ {
+ buf = qf_last_bufref.br_buf;
+ vim_free(ptr);
+ }
+ else
+ {
+ vim_free(qf_last_bufname);
+ buf = buflist_new(bufname, NULL, (linenr_T)0, BLN_NOOPT);
+ if (bufname == ptr)
+ qf_last_bufname = bufname;
+ else
+ qf_last_bufname = vim_strsave(bufname);
+ set_bufref(&qf_last_bufref, buf);
+ }
+ if (buf == NULL)
+ return 0;
+
+ buf->b_has_qf_entry =
+ IS_QF_LIST(qfl) ? BUF_HAS_QF_ENTRY : BUF_HAS_LL_ENTRY;
+ return buf->b_fnum;
+}
+
+/*
+ * Push dirbuf onto the directory stack and return pointer to actual dir or
+ * NULL on error.
+ */
+ static char_u *
+qf_push_dir(char_u *dirbuf, struct dir_stack_T **stackptr, int is_file_stack)
+{
+ struct dir_stack_T *ds_new;
+ struct dir_stack_T *ds_ptr;
+
+ // allocate new stack element and hook it in
+ ds_new = (struct dir_stack_T *)alloc((unsigned)sizeof(struct dir_stack_T));
+ if (ds_new == NULL)
+ return NULL;
+
+ ds_new->next = *stackptr;
+ *stackptr = ds_new;
+
+ // store directory on the stack
+ if (vim_isAbsName(dirbuf)
+ || (*stackptr)->next == NULL
+ || (*stackptr && is_file_stack))
+ (*stackptr)->dirname = vim_strsave(dirbuf);
+ else
+ {
+ // Okay we don't have an absolute path.
+ // dirbuf must be a subdir of one of the directories on the stack.
+ // Let's search...
+ ds_new = (*stackptr)->next;
+ (*stackptr)->dirname = NULL;
+ while (ds_new)
+ {
+ vim_free((*stackptr)->dirname);
+ (*stackptr)->dirname = concat_fnames(ds_new->dirname, dirbuf,
+ TRUE);
+ if (mch_isdir((*stackptr)->dirname) == TRUE)
+ break;
+
+ ds_new = ds_new->next;
+ }
+
+ // clean up all dirs we already left
+ while ((*stackptr)->next != ds_new)
+ {
+ ds_ptr = (*stackptr)->next;
+ (*stackptr)->next = (*stackptr)->next->next;
+ vim_free(ds_ptr->dirname);
+ vim_free(ds_ptr);
+ }
+
+ // Nothing found -> it must be on top level
+ if (ds_new == NULL)
+ {
+ vim_free((*stackptr)->dirname);
+ (*stackptr)->dirname = vim_strsave(dirbuf);
+ }
+ }
+
+ if ((*stackptr)->dirname != NULL)
+ return (*stackptr)->dirname;
+ else
+ {
+ ds_ptr = *stackptr;
+ *stackptr = (*stackptr)->next;
+ vim_free(ds_ptr);
+ return NULL;
+ }
+}
+
+/*
+ * pop dirbuf from the directory stack and return previous directory or NULL if
+ * stack is empty
+ */
+ static char_u *
+qf_pop_dir(struct dir_stack_T **stackptr)
+{
+ struct dir_stack_T *ds_ptr;
+
+ // TODO: Should we check if dirbuf is the directory on top of the stack?
+ // What to do if it isn't?
+
+ // pop top element and free it
+ if (*stackptr != NULL)
+ {
+ ds_ptr = *stackptr;
+ *stackptr = (*stackptr)->next;
+ vim_free(ds_ptr->dirname);
+ vim_free(ds_ptr);
+ }
+
+ // return NEW top element as current dir or NULL if stack is empty
+ return *stackptr ? (*stackptr)->dirname : NULL;
+}
+
+/*
+ * clean up directory stack
+ */
+ static void
+qf_clean_dir_stack(struct dir_stack_T **stackptr)
+{
+ struct dir_stack_T *ds_ptr;
+
+ while ((ds_ptr = *stackptr) != NULL)
+ {
+ *stackptr = (*stackptr)->next;
+ vim_free(ds_ptr->dirname);
+ vim_free(ds_ptr);
+ }
+}
+
+/*
+ * Check in which directory of the directory stack the given file can be
+ * found.
+ * Returns a pointer to the directory name or NULL if not found.
+ * Cleans up intermediate directory entries.
+ *
+ * TODO: How to solve the following problem?
+ * If we have this directory tree:
+ * ./
+ * ./aa
+ * ./aa/bb
+ * ./bb
+ * ./bb/x.c
+ * and make says:
+ * making all in aa
+ * making all in bb
+ * x.c:9: Error
+ * Then qf_push_dir thinks we are in ./aa/bb, but we are in ./bb.
+ * qf_guess_filepath will return NULL.
+ */
+ static char_u *
+qf_guess_filepath(qf_list_T *qfl, char_u *filename)
+{
+ struct dir_stack_T *ds_ptr;
+ struct dir_stack_T *ds_tmp;
+ char_u *fullname;
+
+ // no dirs on the stack - there's nothing we can do
+ if (qfl->qf_dir_stack == NULL)
+ return NULL;
+
+ ds_ptr = qfl->qf_dir_stack->next;
+ fullname = NULL;
+ while (ds_ptr)
+ {
+ vim_free(fullname);
+ fullname = concat_fnames(ds_ptr->dirname, filename, TRUE);
+
+ // If concat_fnames failed, just go on. The worst thing that can happen
+ // is that we delete the entire stack.
+ if ((fullname != NULL) && (mch_getperm(fullname) >= 0))
+ break;
+
+ ds_ptr = ds_ptr->next;
+ }
+
+ vim_free(fullname);
+
+ // clean up all dirs we already left
+ while (qfl->qf_dir_stack->next != ds_ptr)
+ {
+ ds_tmp = qfl->qf_dir_stack->next;
+ qfl->qf_dir_stack->next = qfl->qf_dir_stack->next->next;
+ vim_free(ds_tmp->dirname);
+ vim_free(ds_tmp);
+ }
+
+ return ds_ptr == NULL ? NULL : ds_ptr->dirname;
+}
+
+/*
+ * Returns TRUE if a quickfix/location list with the given identifier exists.
+ */
+ static int
+qflist_valid(win_T *wp, int_u qf_id)
+{
+ qf_info_T *qi = &ql_info;
+ int i;
+
+ if (wp != NULL)
+ {
+ qi = GET_LOC_LIST(wp); // Location list
+ if (qi == NULL)
+ return FALSE;
+ }
+
+ for (i = 0; i < qi->qf_listcount; ++i)
+ if (qi->qf_lists[i].qf_id == qf_id)
+ return TRUE;
+
+ return FALSE;
+}
+
+/*
+ * When loading a file from the quickfix, the autocommands may modify it.
+ * This may invalidate the current quickfix entry. This function checks
+ * whether an entry is still present in the quickfix list.
+ * Similar to location list.
+ */
+ static int
+is_qf_entry_present(qf_list_T *qfl, qfline_T *qf_ptr)
+{
+ qfline_T *qfp;
+ int i;
+
+ // Search for the entry in the current list
+ for (i = 0, qfp = qfl->qf_start; i < qfl->qf_count;
+ ++i, qfp = qfp->qf_next)
+ if (qfp == NULL || qfp == qf_ptr)
+ break;
+
+ if (i == qfl->qf_count) // Entry is not found
+ return FALSE;
+
+ return TRUE;
+}
+
+/*
+ * Get the next valid entry in the current quickfix/location list. The search
+ * starts from the current entry. Returns NULL on failure.
+ */
+ static qfline_T *
+get_next_valid_entry(
+ qf_list_T *qfl,
+ qfline_T *qf_ptr,
+ int *qf_index,
+ int dir)
+{
+ int idx;
+ int old_qf_fnum;
+
+ idx = *qf_index;
+ old_qf_fnum = qf_ptr->qf_fnum;
+
+ do
+ {
+ if (idx == qfl->qf_count || qf_ptr->qf_next == NULL)
+ return NULL;
+ ++idx;
+ qf_ptr = qf_ptr->qf_next;
+ } while ((!qfl->qf_nonevalid && !qf_ptr->qf_valid)
+ || (dir == FORWARD_FILE && qf_ptr->qf_fnum == old_qf_fnum));
+
+ *qf_index = idx;
+ return qf_ptr;
+}
+
+/*
+ * Get the previous valid entry in the current quickfix/location list. The
+ * search starts from the current entry. Returns NULL on failure.
+ */
+ static qfline_T *
+get_prev_valid_entry(
+ qf_list_T *qfl,
+ qfline_T *qf_ptr,
+ int *qf_index,
+ int dir)
+{
+ int idx;
+ int old_qf_fnum;
+
+ idx = *qf_index;
+ old_qf_fnum = qf_ptr->qf_fnum;
+
+ do
+ {
+ if (idx == 1 || qf_ptr->qf_prev == NULL)
+ return NULL;
+ --idx;
+ qf_ptr = qf_ptr->qf_prev;
+ } while ((!qfl->qf_nonevalid && !qf_ptr->qf_valid)
+ || (dir == BACKWARD_FILE && qf_ptr->qf_fnum == old_qf_fnum));
+
+ *qf_index = idx;
+ return qf_ptr;
+}
+
+/*
+ * Get the n'th (errornr) previous/next valid entry from the current entry in
+ * the quickfix list.
+ * dir == FORWARD or FORWARD_FILE: next valid entry
+ * dir == BACKWARD or BACKWARD_FILE: previous valid entry
+ */
+ static qfline_T *
+get_nth_valid_entry(
+ qf_list_T *qfl,
+ int errornr,
+ int dir,
+ int *new_qfidx)
+{
+ qfline_T *qf_ptr = qfl->qf_ptr;
+ int qf_idx = qfl->qf_index;
+ qfline_T *prev_qf_ptr;
+ int prev_index;
+ static char_u *e_no_more_items = (char_u *)N_("E553: No more items");
+ char_u *err = e_no_more_items;
+
+ while (errornr--)
+ {
+ prev_qf_ptr = qf_ptr;
+ prev_index = qf_idx;
+
+ if (dir == FORWARD || dir == FORWARD_FILE)
+ qf_ptr = get_next_valid_entry(qfl, qf_ptr, &qf_idx, dir);
+ else
+ qf_ptr = get_prev_valid_entry(qfl, qf_ptr, &qf_idx, dir);
+ if (qf_ptr == NULL)
+ {
+ qf_ptr = prev_qf_ptr;
+ qf_idx = prev_index;
+ if (err != NULL)
+ {
+ emsg(_(err));
+ return NULL;
+ }
+ break;
+ }
+
+ err = NULL;
+ }
+
+ *new_qfidx = qf_idx;
+ return qf_ptr;
+}
+
+/*
+ * Get n'th (errornr) quickfix entry from the current entry in the quickfix
+ * list 'qfl'. Returns a pointer to the new entry and the index in 'new_qfidx'
+ */
+ static qfline_T *
+get_nth_entry(qf_list_T *qfl, int errornr, int *new_qfidx)
+{
+ qfline_T *qf_ptr = qfl->qf_ptr;
+ int qf_idx = qfl->qf_index;
+
+ // New error number is less than the current error number
+ while (errornr < qf_idx && qf_idx > 1 && qf_ptr->qf_prev != NULL)
+ {
+ --qf_idx;
+ qf_ptr = qf_ptr->qf_prev;
+ }
+ // New error number is greater than the current error number
+ while (errornr > qf_idx && qf_idx < qfl->qf_count &&
+ qf_ptr->qf_next != NULL)
+ {
+ ++qf_idx;
+ qf_ptr = qf_ptr->qf_next;
+ }
+
+ *new_qfidx = qf_idx;
+ return qf_ptr;
+}
+
+/*
+ * Get a entry specied by 'errornr' and 'dir' from the current
+ * quickfix/location list. 'errornr' specifies the index of the entry and 'dir'
+ * specifies the direction (FORWARD/BACKWARD/FORWARD_FILE/BACKWARD_FILE).
+ * Returns a pointer to the entry and the index of the new entry is stored in
+ * 'new_qfidx'.
+ */
+ static qfline_T *
+qf_get_entry(
+ qf_list_T *qfl,
+ int errornr,
+ int dir,
+ int *new_qfidx)
+{
+ qfline_T *qf_ptr = qfl->qf_ptr;
+ int qfidx = qfl->qf_index;
+
+ if (dir != 0) // next/prev valid entry
+ qf_ptr = get_nth_valid_entry(qfl, errornr, dir, &qfidx);
+ else if (errornr != 0) // go to specified number
+ qf_ptr = get_nth_entry(qfl, errornr, &qfidx);
+
+ *new_qfidx = qfidx;
+ return qf_ptr;
+}
+
+/*
+ * Find a window displaying a Vim help file.
+ */
+ static win_T *
+qf_find_help_win(void)
+{
+ win_T *wp;
+
+ FOR_ALL_WINDOWS(wp)
+ if (bt_help(wp->w_buffer))
+ return wp;
+
+ return NULL;
+}
+
+/*
+ * Find a help window or open one. If 'newwin' is TRUE, then open a new help
+ * window.
+ */
+ static int
+jump_to_help_window(qf_info_T *qi, int newwin, int *opened_window)
+{
+ win_T *wp;
+ int flags;
+
+ if (cmdmod.tab != 0 || newwin)
+ wp = NULL;
+ else
+ wp = qf_find_help_win();
+ if (wp != NULL && wp->w_buffer->b_nwindows > 0)
+ win_enter(wp, TRUE);
+ else
+ {
+ // Split off help window; put it at far top if no position
+ // specified, the current window is vertically split and narrow.
+ flags = WSP_HELP;
+ if (cmdmod.split == 0 && curwin->w_width != Columns
+ && curwin->w_width < 80)
+ flags |= WSP_TOP;
+ // If the user asks to open a new window, then copy the location list.
+ // Otherwise, don't copy the location list.
+ if (IS_LL_STACK(qi) && !newwin)
+ flags |= WSP_NEWLOC;
+
+ if (win_split(0, flags) == FAIL)
+ return FAIL;
+
+ *opened_window = TRUE;
+
+ if (curwin->w_height < p_hh)
+ win_setheight((int)p_hh);
+
+ // When using location list, the new window should use the supplied
+ // location list. If the user asks to open a new window, then the new
+ // window will get a copy of the location list.
+ if (IS_LL_STACK(qi) && !newwin)
+ {
+ curwin->w_llist = qi;
+ qi->qf_refcount++;
+ }
+ }
+
+ if (!p_im)
+ restart_edit = 0; // don't want insert mode in help file
+
+ return OK;
+}
+
+/*
+ * Find a non-quickfix window using the given location list.
+ * Returns NULL if a matching window is not found.
+ */
+ static win_T *
+qf_find_win_with_loclist(qf_info_T *ll)
+{
+ win_T *wp;
+
+ FOR_ALL_WINDOWS(wp)
+ if (wp->w_llist == ll && !bt_quickfix(wp->w_buffer))
+ return wp;
+
+ return NULL;
+}
+
+/*
+ * Find a window containing a normal buffer
+ */
+ static win_T *
+qf_find_win_with_normal_buf(void)
+{
+ win_T *wp;
+
+ FOR_ALL_WINDOWS(wp)
+ if (bt_normal(wp->w_buffer))
+ return wp;
+
+ return NULL;
+}
+
+/*
+ * Go to a window in any tabpage containing the specified file. Returns TRUE
+ * if successfully jumped to the window. Otherwise returns FALSE.
+ */
+ static int
+qf_goto_tabwin_with_file(int fnum)
+{
+ tabpage_T *tp;
+ win_T *wp;
+
+ FOR_ALL_TAB_WINDOWS(tp, wp)
+ if (wp->w_buffer->b_fnum == fnum)
+ {
+ goto_tabpage_win(tp, wp);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/*
+ * Create a new window to show a file above the quickfix window. Called when
+ * only the quickfix window is present.
+ */
+ static int
+qf_open_new_file_win(qf_info_T *ll_ref)
+{
+ int flags;
+
+ flags = WSP_ABOVE;
+ if (ll_ref != NULL)
+ flags |= WSP_NEWLOC;
+ if (win_split(0, flags) == FAIL)
+ return FAIL; // not enough room for window
+ p_swb = empty_option; // don't split again
+ swb_flags = 0;
+ RESET_BINDING(curwin);
+ if (ll_ref != NULL)
+ {
+ // The new window should use the location list from the
+ // location list window
+ curwin->w_llist = ll_ref;
+ ll_ref->qf_refcount++;
+ }
+ return OK;
+}
+
+/*
+ * Go to a window that shows the right buffer. If the window is not found, go
+ * to the window just above the location list window. This is used for opening
+ * a file from a location window and not from a quickfix window. If some usable
+ * window is previously found, then it is supplied in 'use_win'.
+ */
+ static void
+qf_goto_win_with_ll_file(win_T *use_win, int qf_fnum, qf_info_T *ll_ref)
+{
+ win_T *win = use_win;
+
+ if (win == NULL)
+ {
+ // Find the window showing the selected file
+ FOR_ALL_WINDOWS(win)
+ if (win->w_buffer->b_fnum == qf_fnum)
+ break;
+ if (win == NULL)
+ {
+ // Find a previous usable window
+ win = curwin;
+ do
+ {
+ if (bt_normal(win->w_buffer))
+ break;
+ if (win->w_prev == NULL)
+ win = lastwin; // wrap around the top
+ else
+ win = win->w_prev; // go to previous window
+ } while (win != curwin);
+ }
+ }
+ win_goto(win);
+
+ // If the location list for the window is not set, then set it
+ // to the location list from the location window
+ if (win->w_llist == NULL)
+ {
+ win->w_llist = ll_ref;
+ if (ll_ref != NULL)
+ ll_ref->qf_refcount++;
+ }
+}
+
+/*
+ * Go to a window that contains the specified buffer 'qf_fnum'. If a window is
+ * not found, then go to the window just above the quickfix window. This is
+ * used for opening a file from a quickfix window and not from a location
+ * window.
+ */
+ static void
+qf_goto_win_with_qfl_file(int qf_fnum)
+{
+ win_T *win;
+ win_T *altwin;
+
+ win = curwin;
+ altwin = NULL;
+ for (;;)
+ {
+ if (win->w_buffer->b_fnum == qf_fnum)
+ break;
+ if (win->w_prev == NULL)
+ win = lastwin; // wrap around the top
+ else
+ win = win->w_prev; // go to previous window
+
+ if (IS_QF_WINDOW(win))
+ {
+ // Didn't find it, go to the window before the quickfix
+ // window.
+ if (altwin != NULL)
+ win = altwin;
+ else if (curwin->w_prev != NULL)
+ win = curwin->w_prev;
+ else
+ win = curwin->w_next;
+ break;
+ }
+
+ // Remember a usable window.
+ if (altwin == NULL && !win->w_p_pvw && bt_normal(win->w_buffer))
+ altwin = win;
+ }
+
+ win_goto(win);
+}
+
+/*
+ * Find a suitable window for opening a file (qf_fnum) from the
+ * quickfix/location list and jump to it. If the file is already opened in a
+ * window, jump to it. Otherwise open a new window to display the file. If
+ * 'newwin' is TRUE, then always open a new window. This is called from either
+ * a quickfix or a location list window.
+ */
+ static int
+qf_jump_to_usable_window(int qf_fnum, int newwin, int *opened_window)
+{
+ win_T *usable_win_ptr = NULL;
+ int usable_win;
+ qf_info_T *ll_ref = NULL;
+ win_T *win;
+
+ usable_win = 0;
+
+ // If opening a new window, then don't use the location list referred by
+ // the current window. Otherwise two windows will refer to the same
+ // location list.
+ if (!newwin)
+ ll_ref = curwin->w_llist_ref;
+
+ if (ll_ref != NULL)
+ {
+ // Find a non-quickfix window with this location list
+ usable_win_ptr = qf_find_win_with_loclist(ll_ref);
+ if (usable_win_ptr != NULL)
+ usable_win = 1;
+ }
+
+ if (!usable_win)
+ {
+ // Locate a window showing a normal buffer
+ win = qf_find_win_with_normal_buf();
+ if (win != NULL)
+ usable_win = 1;
+ }
+
+ // If no usable window is found and 'switchbuf' contains "usetab"
+ // then search in other tabs.
+ if (!usable_win && (swb_flags & SWB_USETAB))
+ usable_win = qf_goto_tabwin_with_file(qf_fnum);
+
+ // If there is only one window and it is the quickfix window, create a
+ // new one above the quickfix window.
+ if ((ONE_WINDOW && bt_quickfix(curbuf)) || !usable_win || newwin)
+ {
+ if (qf_open_new_file_win(ll_ref) != OK)
+ return FAIL;
+ *opened_window = TRUE; // close it when fail
+ }
+ else
+ {
+ if (curwin->w_llist_ref != NULL) // In a location window
+ qf_goto_win_with_ll_file(usable_win_ptr, qf_fnum, ll_ref);
+ else // In a quickfix window
+ qf_goto_win_with_qfl_file(qf_fnum);
+ }
+
+ return OK;
+}
+
+/*
+ * Edit the selected file or help file.
+ * Returns OK if successfully edited the file, FAIL on failing to open the
+ * buffer and NOTDONE if the quickfix/location list was freed by an autocmd
+ * when opening the buffer.
+ */
+ static int
+qf_jump_edit_buffer(
+ qf_info_T *qi,
+ qfline_T *qf_ptr,
+ int forceit,
+ win_T *oldwin,
+ int *opened_window)
+{
+ qf_list_T *qfl = &qi->qf_lists[qi->qf_curlist];
+ qfltype_T qfl_type = qfl->qfl_type;
+ int retval = OK;
+ int old_qf_curlist = qi->qf_curlist;
+ int save_qfid = qfl->qf_id;
+
+ if (qf_ptr->qf_type == 1)
+ {
+ // Open help file (do_ecmd() will set b_help flag, readfile() will
+ // set b_p_ro flag).
+ if (!can_abandon(curbuf, forceit))
+ {
+ no_write_message();
+ return FAIL;
+ }
+
+ retval = do_ecmd(qf_ptr->qf_fnum, NULL, NULL, NULL, (linenr_T)1,
+ ECMD_HIDE + ECMD_SET_HELP,
+ oldwin == curwin ? curwin : NULL);
+ }
+ else
+ retval = buflist_getfile(qf_ptr->qf_fnum,
+ (linenr_T)1, GETF_SETMARK | GETF_SWITCH, forceit);
+
+ // If a location list, check whether the associated window is still
+ // present.
+ if (qfl_type == QFLT_LOCATION && !win_valid_any_tab(oldwin))
+ {
+ emsg(_("E924: Current window was closed"));
+ *opened_window = FALSE;
+ return NOTDONE;
+ }
+
+ if (qfl_type == QFLT_QUICKFIX && !qflist_valid(NULL, save_qfid))
+ {
+ emsg(_("E925: Current quickfix was changed"));
+ return NOTDONE;
+ }
+
+ if (old_qf_curlist != qi->qf_curlist
+ || !is_qf_entry_present(qfl, qf_ptr))
+ {
+ if (qfl_type == QFLT_QUICKFIX)
+ emsg(_("E925: Current quickfix was changed"));
+ else
+ emsg(_(e_loc_list_changed));
+ return NOTDONE;
+ }
+
+ return retval;
+}
+
+/*
+ * Go to the error line in the current file using either line/column number or
+ * a search pattern.
+ */
+ static void
+qf_jump_goto_line(
+ linenr_T qf_lnum,
+ int qf_col,
+ char_u qf_viscol,
+ char_u *qf_pattern)
+{
+ linenr_T i;
+
+ if (qf_pattern == NULL)
+ {
+ // Go to line with error, unless qf_lnum is 0.
+ i = qf_lnum;
+ if (i > 0)
+ {
+ if (i > curbuf->b_ml.ml_line_count)
+ i = curbuf->b_ml.ml_line_count;
+ curwin->w_cursor.lnum = i;
+ }
+ if (qf_col > 0)
+ {
+ curwin->w_cursor.coladd = 0;
+ if (qf_viscol == TRUE)
+ coladvance(qf_col - 1);
+ else
+ curwin->w_cursor.col = qf_col - 1;
+ curwin->w_set_curswant = TRUE;
+ check_cursor();
+ }
+ else
+ beginline(BL_WHITE | BL_FIX);
+ }
+ else
+ {
+ pos_T save_cursor;
+
+ // Move the cursor to the first line in the buffer
+ save_cursor = curwin->w_cursor;
+ curwin->w_cursor.lnum = 0;
+ if (!do_search(NULL, '/', qf_pattern, (long)1,
+ SEARCH_KEEP, NULL, NULL))
+ curwin->w_cursor = save_cursor;
+ }
+}
+
+/*
+ * Display quickfix list index and size message
+ */
+ static void
+qf_jump_print_msg(
+ qf_info_T *qi,
+ int qf_index,
+ qfline_T *qf_ptr,
+ buf_T *old_curbuf,
+ linenr_T old_lnum)
+{
+ linenr_T i;
+ int len;
+
+ // Update the screen before showing the message, unless the screen
+ // scrolled up.
+ if (!msg_scrolled)
+ update_topline_redraw();
+ sprintf((char *)IObuff, _("(%d of %d)%s%s: "), qf_index,
+ qi->qf_lists[qi->qf_curlist].qf_count,
+ qf_ptr->qf_cleared ? _(" (line deleted)") : "",
+ (char *)qf_types(qf_ptr->qf_type, qf_ptr->qf_nr));
+ // Add the message, skipping leading whitespace and newlines.
+ len = (int)STRLEN(IObuff);
+ qf_fmt_text(skipwhite(qf_ptr->qf_text), IObuff + len, IOSIZE - len);
+
+ // Output the message. Overwrite to avoid scrolling when the 'O'
+ // flag is present in 'shortmess'; But when not jumping, print the
+ // whole message.
+ i = msg_scroll;
+ if (curbuf == old_curbuf && curwin->w_cursor.lnum == old_lnum)
+ msg_scroll = TRUE;
+ else if (!msg_scrolled && shortmess(SHM_OVERALL))
+ msg_scroll = FALSE;
+ msg_attr_keep((char *)IObuff, 0, TRUE);
+ msg_scroll = i;
+}
+
+/*
+ * Find a usable window for opening a file from the quickfix/location list. If
+ * a window is not found then open a new window. If 'newwin' is TRUE, then open
+ * a new window.
+ * Returns OK if successfully jumped or opened a window. Returns FAIL if not
+ * able to jump/open a window. Returns NOTDONE if a file is not associated
+ * with the entry.
+ */
+ static int
+qf_jump_open_window(
+ qf_info_T *qi,
+ qfline_T *qf_ptr,
+ int newwin,
+ int *opened_window)
+{
+ // For ":helpgrep" find a help window or open one.
+ if (qf_ptr->qf_type == 1 && (!bt_help(curwin->w_buffer) || cmdmod.tab != 0))
+ if (jump_to_help_window(qi, newwin, opened_window) == FAIL)
+ return FAIL;
+
+ // If currently in the quickfix window, find another window to show the
+ // file in.
+ if (bt_quickfix(curbuf) && !*opened_window)
+ {
+ // If there is no file specified, we don't know where to go.
+ // But do advance, otherwise ":cn" gets stuck.
+ if (qf_ptr->qf_fnum == 0)
+ return NOTDONE;
+
+ if (qf_jump_to_usable_window(qf_ptr->qf_fnum, newwin,
+ opened_window) == FAIL)
+ return FAIL;
+ }
+
+ return OK;
+}
+
+/*
+ * Edit a selected file from the quickfix/location list and jump to a
+ * particular line/column, adjust the folds and display a message about the
+ * jump.
+ * Returns OK on success and FAIL on failing to open the file/buffer. Returns
+ * NOTDONE if the quickfix/location list is freed by an autocmd when opening
+ * the file.
+ */
+ static int
+qf_jump_to_buffer(
+ qf_info_T *qi,
+ int qf_index,
+ qfline_T *qf_ptr,
+ int forceit,
+ win_T *oldwin,
+ int *opened_window,
+ int openfold,
+ int print_message)
+{
+ buf_T *old_curbuf;
+ linenr_T old_lnum;
+ int retval = OK;
+
+ // If there is a file name, read the wanted file if needed, and check
+ // autowrite etc.
+ old_curbuf = curbuf;
+ old_lnum = curwin->w_cursor.lnum;
+
+ if (qf_ptr->qf_fnum != 0)
+ {
+ retval = qf_jump_edit_buffer(qi, qf_ptr, forceit, oldwin,
+ opened_window);
+ if (retval != OK)
+ return retval;
+ }
+
+ // When not switched to another buffer, still need to set pc mark
+ if (curbuf == old_curbuf)
+ setpcmark();
+
+ qf_jump_goto_line(qf_ptr->qf_lnum, qf_ptr->qf_col, qf_ptr->qf_viscol,
+ qf_ptr->qf_pattern);
+
+#ifdef FEAT_FOLDING
+ if ((fdo_flags & FDO_QUICKFIX) && openfold)
+ foldOpenCursor();
+#endif
+ if (print_message)
+ qf_jump_print_msg(qi, qf_index, qf_ptr, old_curbuf, old_lnum);
+
+ return retval;
+}
+
+/*
+ * Jump to a quickfix line and try to use an existing window.
+ */
+ void
+qf_jump(qf_info_T *qi,
+ int dir,
+ int errornr,
+ int forceit)
+{
+ qf_jump_newwin(qi, dir, errornr, forceit, FALSE);
+}
+
+/*
+ * Jump to a quickfix line.
+ * If dir == 0 go to entry "errornr".
+ * If dir == FORWARD go "errornr" valid entries forward.
+ * If dir == BACKWARD go "errornr" valid entries backward.
+ * If dir == FORWARD_FILE go "errornr" valid entries files backward.
+ * If dir == BACKWARD_FILE go "errornr" valid entries files backward
+ * else if "errornr" is zero, redisplay the same line
+ * If 'forceit' is TRUE, then can discard changes to the current buffer.
+ * If 'newwin' is TRUE, then open the file in a new window.
+ */
+ void
+qf_jump_newwin(qf_info_T *qi,
+ int dir,
+ int errornr,
+ int forceit,
+ int newwin)
+{
+ qf_list_T *qfl;
+ qfline_T *qf_ptr;
+ qfline_T *old_qf_ptr;
+ int qf_index;
+ int old_qf_index;
+ char_u *old_swb = p_swb;
+ unsigned old_swb_flags = swb_flags;
+ int opened_window = FALSE;
+ win_T *oldwin = curwin;
+ int print_message = TRUE;
+#ifdef FEAT_FOLDING
+ int old_KeyTyped = KeyTyped; // getting file may reset it
+#endif
+ int retval = OK;
+
+ if (qi == NULL)
+ qi = &ql_info;
+
+ if (qf_stack_empty(qi) || qf_list_empty(qi, qi->qf_curlist))
+ {
+ emsg(_(e_quickfix));
+ return;
+ }
+
+ qfl = &qi->qf_lists[qi->qf_curlist];
+
+ qf_ptr = qfl->qf_ptr;
+ old_qf_ptr = qf_ptr;
+ qf_index = qfl->qf_index;
+ old_qf_index = qf_index;
+
+ qf_ptr = qf_get_entry(qfl, errornr, dir, &qf_index);
+ if (qf_ptr == NULL)
+ {
+ qf_ptr = old_qf_ptr;
+ qf_index = old_qf_index;
+ goto theend;
+ }
+
+ qfl->qf_index = qf_index;
+ if (qf_win_pos_update(qi, old_qf_index))
+ // No need to print the error message if it's visible in the error
+ // window
+ print_message = FALSE;
+
+ retval = qf_jump_open_window(qi, qf_ptr, newwin, &opened_window);
+ if (retval == FAIL)
+ goto failed;
+ if (retval == NOTDONE)
+ goto theend;
+
+ retval = qf_jump_to_buffer(qi, qf_index, qf_ptr, forceit, oldwin,
+ &opened_window, old_KeyTyped, print_message);
+ if (retval == NOTDONE)
+ {
+ // Quickfix/location list is freed by an autocmd
+ qi = NULL;
+ qf_ptr = NULL;
+ }
+
+ if (retval != OK)
+ {
+ if (opened_window)
+ win_close(curwin, TRUE); // Close opened window
+ if (qf_ptr != NULL && qf_ptr->qf_fnum != 0)
+ {
+ // Couldn't open file, so put index back where it was. This could
+ // happen if the file was readonly and we changed something.
+failed:
+ qf_ptr = old_qf_ptr;
+ qf_index = old_qf_index;
+ }
+ }
+theend:
+ if (qi != NULL)
+ {
+ qfl->qf_ptr = qf_ptr;
+ qfl->qf_index = qf_index;
+ }
+ if (p_swb != old_swb && opened_window)
+ {
+ // Restore old 'switchbuf' value, but not when an autocommand or
+ // modeline has changed the value.
+ if (p_swb == empty_option)
+ {
+ p_swb = old_swb;
+ swb_flags = old_swb_flags;
+ }
+ else
+ free_string_option(old_swb);
+ }
+}
+
+// Highlight attributes used for displaying entries from the quickfix list.
+static int qfFileAttr;
+static int qfSepAttr;
+static int qfLineAttr;
+
+/*
+ * Display information about a single entry from the quickfix/location list.
+ * Used by ":clist/:llist" commands.
+ * 'cursel' will be set to TRUE for the currently selected entry in the
+ * quickfix list.
+ */
+ static void
+qf_list_entry(qfline_T *qfp, int qf_idx, int cursel)
+{
+ char_u *fname;
+ buf_T *buf;
+ int filter_entry;
+
+ fname = NULL;
+ if (qfp->qf_module != NULL && *qfp->qf_module != NUL)
+ vim_snprintf((char *)IObuff, IOSIZE, "%2d %s", qf_idx,
+ (char *)qfp->qf_module);
+ else {
+ if (qfp->qf_fnum != 0
+ && (buf = buflist_findnr(qfp->qf_fnum)) != NULL)
+ {
+ fname = buf->b_fname;
+ if (qfp->qf_type == 1) // :helpgrep
+ fname = gettail(fname);
+ }
+ if (fname == NULL)
+ sprintf((char *)IObuff, "%2d", qf_idx);
+ else
+ vim_snprintf((char *)IObuff, IOSIZE, "%2d %s",
+ qf_idx, (char *)fname);
+ }
+
+ // Support for filtering entries using :filter /pat/ clist
+ // Match against the module name, file name, search pattern and
+ // text of the entry.
+ filter_entry = TRUE;
+ if (qfp->qf_module != NULL && *qfp->qf_module != NUL)
+ filter_entry &= message_filtered(qfp->qf_module);
+ if (filter_entry && fname != NULL)
+ filter_entry &= message_filtered(fname);
+ if (filter_entry && qfp->qf_pattern != NULL)
+ filter_entry &= message_filtered(qfp->qf_pattern);
+ if (filter_entry)
+ filter_entry &= message_filtered(qfp->qf_text);
+ if (filter_entry)
+ return;
+
+ msg_putchar('\n');
+ msg_outtrans_attr(IObuff, cursel ? HL_ATTR(HLF_QFL) : qfFileAttr);
+
+ if (qfp->qf_lnum != 0)
+ msg_puts_attr(":", qfSepAttr);
+ if (qfp->qf_lnum == 0)
+ IObuff[0] = NUL;
+ else if (qfp->qf_col == 0)
+ sprintf((char *)IObuff, "%ld", qfp->qf_lnum);
+ else
+ sprintf((char *)IObuff, "%ld col %d",
+ qfp->qf_lnum, qfp->qf_col);
+ sprintf((char *)IObuff + STRLEN(IObuff), "%s",
+ (char *)qf_types(qfp->qf_type, qfp->qf_nr));
+ msg_puts_attr((char *)IObuff, qfLineAttr);
+ msg_puts_attr(":", qfSepAttr);
+ if (qfp->qf_pattern != NULL)
+ {
+ qf_fmt_text(qfp->qf_pattern, IObuff, IOSIZE);
+ msg_puts((char *)IObuff);
+ msg_puts_attr(":", qfSepAttr);
+ }
+ msg_puts(" ");
+
+ // Remove newlines and leading whitespace from the text. For an
+ // unrecognized line keep the indent, the compiler may mark a word
+ // with ^^^^.
+ qf_fmt_text((fname != NULL || qfp->qf_lnum != 0)
+ ? skipwhite(qfp->qf_text) : qfp->qf_text,
+ IObuff, IOSIZE);
+ msg_prt_line(IObuff, FALSE);
+ out_flush(); // show one line at a time
+}
+
+/*
+ * ":clist": list all errors
+ * ":llist": list all locations
+ */
+ void
+qf_list(exarg_T *eap)
+{
+ qf_list_T *qfl;
+ qfline_T *qfp;
+ int i;
+ int idx1 = 1;
+ int idx2 = -1;
+ char_u *arg = eap->arg;
+ int plus = FALSE;
+ int all = eap->forceit; // if not :cl!, only show
+ // recognised errors
+ qf_info_T *qi = &ql_info;
+
+ if (is_loclist_cmd(eap->cmdidx))
+ {
+ qi = GET_LOC_LIST(curwin);
+ if (qi == NULL)
+ {
+ emsg(_(e_loclist));
+ return;
+ }
+ }
+
+ if (qf_stack_empty(qi) || qf_list_empty(qi, qi->qf_curlist))
+ {
+ emsg(_(e_quickfix));
+ return;
+ }
+ if (*arg == '+')
+ {
+ ++arg;
+ plus = TRUE;
+ }
+ if (!get_list_range(&arg, &idx1, &idx2) || *arg != NUL)
+ {
+ emsg(_(e_trailing));
+ return;
+ }
+ qfl = &qi->qf_lists[qi->qf_curlist];
+ if (plus)
+ {
+ i = qfl->qf_index;
+ idx2 = i + idx1;
+ idx1 = i;
+ }
+ else
+ {
+ i = qfl->qf_count;
+ if (idx1 < 0)
+ idx1 = (-idx1 > i) ? 0 : idx1 + i + 1;
+ if (idx2 < 0)
+ idx2 = (-idx2 > i) ? 0 : idx2 + i + 1;
+ }
+
+ // Shorten all the file names, so that it is easy to read
+ shorten_fnames(FALSE);
+
+ // Get the attributes for the different quickfix highlight items. Note
+ // that this depends on syntax items defined in the qf.vim syntax file
+ qfFileAttr = syn_name2attr((char_u *)"qfFileName");
+ if (qfFileAttr == 0)
+ qfFileAttr = HL_ATTR(HLF_D);
+ qfSepAttr = syn_name2attr((char_u *)"qfSeparator");
+ if (qfSepAttr == 0)
+ qfSepAttr = HL_ATTR(HLF_D);
+ qfLineAttr = syn_name2attr((char_u *)"qfLineNr");
+ if (qfLineAttr == 0)
+ qfLineAttr = HL_ATTR(HLF_N);
+
+ if (qfl->qf_nonevalid)
+ all = TRUE;
+ qfp = qfl->qf_start;
+ for (i = 1; !got_int && i <= qfl->qf_count; )
+ {
+ if ((qfp->qf_valid || all) && idx1 <= i && i <= idx2)
+ {
+ if (got_int)
+ break;
+
+ qf_list_entry(qfp, i, i == qfl->qf_index);
+ }
+
+ qfp = qfp->qf_next;
+ if (qfp == NULL)
+ break;
+ ++i;
+ ui_breakcheck();
+ }
+}
+
+/*
+ * Remove newlines and leading whitespace from an error message.
+ * Put the result in "buf[bufsize]".
+ */
+ static void
+qf_fmt_text(char_u *text, char_u *buf, int bufsize)
+{
+ int i;
+ char_u *p = text;
+
+ for (i = 0; *p != NUL && i < bufsize - 1; ++i)
+ {
+ if (*p == '\n')
+ {
+ buf[i] = ' ';
+ while (*++p != NUL)
+ if (!VIM_ISWHITE(*p) && *p != '\n')
+ break;
+ }
+ else
+ buf[i] = *p++;
+ }
+ buf[i] = NUL;
+}
+
+/*
+ * Display information (list number, list size and the title) about a
+ * quickfix/location list.
+ */
+ static void
+qf_msg(qf_info_T *qi, int which, char *lead)
+{
+ char *title = (char *)qi->qf_lists[which].qf_title;
+ int count = qi->qf_lists[which].qf_count;
+ char_u buf[IOSIZE];
+
+ vim_snprintf((char *)buf, IOSIZE, _("%serror list %d of %d; %d errors "),
+ lead,
+ which + 1,
+ qi->qf_listcount,
+ count);
+
+ if (title != NULL)
+ {
+ size_t len = STRLEN(buf);
+
+ if (len < 34)
+ {
+ vim_memset(buf + len, ' ', 34 - len);
+ buf[34] = NUL;
+ }
+ vim_strcat(buf, (char_u *)title, IOSIZE);
+ }
+ trunc_string(buf, buf, Columns - 1, IOSIZE);
+ msg((char *)buf);
+}
+
+/*
+ * ":colder [count]": Up in the quickfix stack.
+ * ":cnewer [count]": Down in the quickfix stack.
+ * ":lolder [count]": Up in the location list stack.
+ * ":lnewer [count]": Down in the location list stack.
+ */
+ void
+qf_age(exarg_T *eap)
+{
+ qf_info_T *qi = &ql_info;
+ int count;
+
+ if (is_loclist_cmd(eap->cmdidx))
+ {
+ qi = GET_LOC_LIST(curwin);
+ if (qi == NULL)
+ {
+ emsg(_(e_loclist));
+ return;
+ }
+ }
+
+ if (eap->addr_count != 0)
+ count = eap->line2;
+ else
+ count = 1;
+ while (count--)
+ {
+ if (eap->cmdidx == CMD_colder || eap->cmdidx == CMD_lolder)
+ {
+ if (qi->qf_curlist == 0)
+ {
+ emsg(_("E380: At bottom of quickfix stack"));
+ break;
+ }
+ --qi->qf_curlist;
+ }
+ else
+ {
+ if (qi->qf_curlist >= qi->qf_listcount - 1)
+ {
+ emsg(_("E381: At top of quickfix stack"));
+ break;
+ }
+ ++qi->qf_curlist;
+ }
+ }
+ qf_msg(qi, qi->qf_curlist, "");
+ qf_update_buffer(qi, NULL);
+}
+
+/*
+ * Display the information about all the quickfix/location lists in the stack
+ */
+ void
+qf_history(exarg_T *eap)
+{
+ qf_info_T *qi = &ql_info;
+ int i;
+
+ if (is_loclist_cmd(eap->cmdidx))
+ qi = GET_LOC_LIST(curwin);
+ if (qf_stack_empty(qi))
+ msg(_("No entries"));
+ else
+ for (i = 0; i < qi->qf_listcount; ++i)
+ qf_msg(qi, i, i == qi->qf_curlist ? "> " : " ");
+}
+
+/*
+ * Free all the entries in the error list "idx". Note that other information
+ * associated with the list like context and title are not freed.
+ */
+ static void
+qf_free_items(qf_list_T *qfl)
+{
+ qfline_T *qfp;
+ qfline_T *qfpnext;
+ int stop = FALSE;
+
+ while (qfl->qf_count && qfl->qf_start != NULL)
+ {
+ qfp = qfl->qf_start;
+ qfpnext = qfp->qf_next;
+ if (!stop)
+ {
+ vim_free(qfp->qf_module);
+ vim_free(qfp->qf_text);
+ vim_free(qfp->qf_pattern);
+ stop = (qfp == qfpnext);
+ vim_free(qfp);
+ if (stop)
+ // Somehow qf_count may have an incorrect value, set it to 1
+ // to avoid crashing when it's wrong.
+ // TODO: Avoid qf_count being incorrect.
+ qfl->qf_count = 1;
+ }
+ qfl->qf_start = qfpnext;
+ --qfl->qf_count;
+ }
+
+ qfl->qf_index = 0;
+ qfl->qf_start = NULL;
+ qfl->qf_last = NULL;
+ qfl->qf_ptr = NULL;
+ qfl->qf_nonevalid = TRUE;
+
+ qf_clean_dir_stack(&qfl->qf_dir_stack);
+ qfl->qf_directory = NULL;
+ qf_clean_dir_stack(&qfl->qf_file_stack);
+ qfl->qf_currfile = NULL;
+ qfl->qf_multiline = FALSE;
+ qfl->qf_multiignore = FALSE;
+ qfl->qf_multiscan = FALSE;
+}
+
+/*
+ * Free error list "idx". Frees all the entries in the quickfix list,
+ * associated context information and the title.
+ */
+ static void
+qf_free(qf_list_T *qfl)
+{
+ qf_free_items(qfl);
+
+ VIM_CLEAR(qfl->qf_title);
+ free_tv(qfl->qf_ctx);
+ qfl->qf_ctx = NULL;
+ qfl->qf_id = 0;
+ qfl->qf_changedtick = 0L;
+}
+
+/*
+ * qf_mark_adjust: adjust marks
+ */
+ void
+qf_mark_adjust(
+ win_T *wp,
+ linenr_T line1,
+ linenr_T line2,
+ long amount,
+ long amount_after)
+{
+ int i;
+ qfline_T *qfp;
+ int idx;
+ qf_info_T *qi = &ql_info;
+ int found_one = FALSE;
+ int buf_has_flag = wp == NULL ? BUF_HAS_QF_ENTRY : BUF_HAS_LL_ENTRY;
+
+ if (!(curbuf->b_has_qf_entry & buf_has_flag))
+ return;
+ if (wp != NULL)
+ {
+ if (wp->w_llist == NULL)
+ return;
+ qi = wp->w_llist;
+ }
+
+ for (idx = 0; idx < qi->qf_listcount; ++idx)
+ if (!qf_list_empty(qi, idx))
+ for (i = 0, qfp = qi->qf_lists[idx].qf_start;
+ i < qi->qf_lists[idx].qf_count && qfp != NULL;
+ ++i, qfp = qfp->qf_next)
+ if (qfp->qf_fnum == curbuf->b_fnum)
+ {
+ found_one = TRUE;
+ if (qfp->qf_lnum >= line1 && qfp->qf_lnum <= line2)
+ {
+ if (amount == MAXLNUM)
+ qfp->qf_cleared = TRUE;
+ else
+ qfp->qf_lnum += amount;
+ }
+ else if (amount_after && qfp->qf_lnum > line2)
+ qfp->qf_lnum += amount_after;
+ }
+
+ if (!found_one)
+ curbuf->b_has_qf_entry &= ~buf_has_flag;
+}
+
+/*
+ * Make a nice message out of the error character and the error number:
+ * char number message
+ * e or E 0 " error"
+ * w or W 0 " warning"
+ * i or I 0 " info"
+ * 0 0 ""
+ * other 0 " c"
+ * e or E n " error n"
+ * w or W n " warning n"
+ * i or I n " info n"
+ * 0 n " error n"
+ * other n " c n"
+ * 1 x "" :helpgrep
+ */
+ static char_u *
+qf_types(int c, int nr)
+{
+ static char_u buf[20];
+ static char_u cc[3];
+ char_u *p;
+
+ if (c == 'W' || c == 'w')
+ p = (char_u *)" warning";
+ else if (c == 'I' || c == 'i')
+ p = (char_u *)" info";
+ else if (c == 'E' || c == 'e' || (c == 0 && nr > 0))
+ p = (char_u *)" error";
+ else if (c == 0 || c == 1)
+ p = (char_u *)"";
+ else
+ {
+ cc[0] = ' ';
+ cc[1] = c;
+ cc[2] = NUL;
+ p = cc;
+ }
+
+ if (nr <= 0)
+ return p;
+
+ sprintf((char *)buf, "%s %3d", (char *)p, nr);
+ return buf;
+}
+
+/*
+ * When "split" is FALSE: Open the entry/result under the cursor.
+ * When "split" is TRUE: Open the entry/result under the cursor in a new window.
+ */
+ void
+qf_view_result(int split)
+{
+ qf_info_T *qi = &ql_info;
+
+ if (!bt_quickfix(curbuf))
+ return;
+
+ if (IS_LL_WINDOW(curwin))
+ qi = GET_LOC_LIST(curwin);
+
+ if (qf_list_empty(qi, qi->qf_curlist))
+ {
+ emsg(_(e_quickfix));
+ return;
+ }
+
+ if (split)
+ {
+ // Open the selected entry in a new window
+ qf_jump_newwin(qi, 0, (long)curwin->w_cursor.lnum, FALSE, TRUE);
+ do_cmdline_cmd((char_u *) "clearjumps");
+ return;
+ }
+
+ do_cmdline_cmd((char_u *)(IS_LL_WINDOW(curwin) ? ".ll" : ".cc"));
+}
+
+/*
+ * ":cwindow": open the quickfix window if we have errors to display,
+ * close it if not.
+ * ":lwindow": open the location list window if we have locations to display,
+ * close it if not.
+ */
+ void
+ex_cwindow(exarg_T *eap)
+{
+ qf_info_T *qi = &ql_info;
+ qf_list_T *qfl;
+ win_T *win;
+
+ if (is_loclist_cmd(eap->cmdidx))
+ {
+ qi = GET_LOC_LIST(curwin);
+ if (qi == NULL)
+ return;
+ }
+
+ qfl = &qi->qf_lists[qi->qf_curlist];
+
+ // Look for an existing quickfix window.
+ win = qf_find_win(qi);
+
+ // If a quickfix window is open but we have no errors to display,
+ // close the window. If a quickfix window is not open, then open
+ // it if we have errors; otherwise, leave it closed.
+ if (qf_stack_empty(qi)
+ || qfl->qf_nonevalid
+ || qf_list_empty(qi, qi->qf_curlist))
+ {
+ if (win != NULL)
+ ex_cclose(eap);
+ }
+ else if (win == NULL)
+ ex_copen(eap);
+}
+
+/*
+ * ":cclose": close the window showing the list of errors.
+ * ":lclose": close the window showing the location list
+ */
+ void
+ex_cclose(exarg_T *eap)
+{
+ win_T *win = NULL;
+ qf_info_T *qi = &ql_info;
+
+ if (is_loclist_cmd(eap->cmdidx))
+ {
+ qi = GET_LOC_LIST(curwin);
+ if (qi == NULL)
+ return;
+ }
+
+ // Find existing quickfix window and close it.
+ win = qf_find_win(qi);
+ if (win != NULL)
+ win_close(win, FALSE);
+}
+
+/*
+ * Set "w:quickfix_title" if "qi" has a title.
+ */
+ static void
+qf_set_title_var(qf_list_T *qfl)
+{
+ if (qfl->qf_title != NULL)
+ set_internal_string_var((char_u *)"w:quickfix_title", qfl->qf_title);
+}
+
+/*
+ * Goto a quickfix or location list window (if present).
+ * Returns OK if the window is found, FAIL otherwise.
+ */
+ static int
+qf_goto_cwindow(qf_info_T *qi, int resize, int sz, int vertsplit)
+{
+ win_T *win;
+
+ win = qf_find_win(qi);
+ if (win == NULL)
+ return FAIL;
+
+ win_goto(win);
+ if (resize)
+ {
+ if (vertsplit)
+ {
+ if (sz != win->w_width)
+ win_setwidth(sz);
+ }
+ else if (sz != win->w_height)
+ win_setheight(sz);
+ }
+
+ return OK;
+}
+
+/*
+ * Open a new quickfix or location list window, load the quickfix buffer and
+ * set the appropriate options for the window.
+ * Returns FAIL if the window could not be opened.
+ */
+ static int
+qf_open_new_cwindow(qf_info_T *qi, int height)
+{
+ buf_T *qf_buf;
+ win_T *oldwin = curwin;
+ tabpage_T *prevtab = curtab;
+ int flags = 0;
+ win_T *win;
+
+ qf_buf = qf_find_buf(qi);
+
+ // The current window becomes the previous window afterwards.
+ win = curwin;
+
+ if (IS_QF_STACK(qi) && cmdmod.split == 0)
+ // Create the new quickfix window at the very bottom, except when
+ // :belowright or :aboveleft is used.
+ win_goto(lastwin);
+ // Default is to open the window below the current window
+ if (cmdmod.split == 0)
+ flags = WSP_BELOW;
+ flags |= WSP_NEWLOC;
+ if (win_split(height, flags) == FAIL)
+ return FAIL; // not enough room for window
+ RESET_BINDING(curwin);
+
+ if (IS_LL_STACK(qi))
+ {
+ // For the location list window, create a reference to the
+ // location list from the window 'win'.
+ curwin->w_llist_ref = win->w_llist;
+ win->w_llist->qf_refcount++;
+ }
+
+ if (oldwin != curwin)
+ oldwin = NULL; // don't store info when in another window
+ if (qf_buf != NULL)
+ {
+ // Use the existing quickfix buffer
+ (void)do_ecmd(qf_buf->b_fnum, NULL, NULL, NULL, ECMD_ONE,
+ ECMD_HIDE + ECMD_OLDBUF, oldwin);
+ }
+ else
+ {
+ // Create a new quickfix buffer
+ (void)do_ecmd(0, NULL, NULL, NULL, ECMD_ONE, ECMD_HIDE, oldwin);
+
+ // switch off 'swapfile'
+ set_option_value((char_u *)"swf", 0L, NULL, OPT_LOCAL);
+ set_option_value((char_u *)"bt", 0L, (char_u *)"quickfix",
+ OPT_LOCAL);
+ set_option_value((char_u *)"bh", 0L, (char_u *)"wipe", OPT_LOCAL);
+ RESET_BINDING(curwin);
+#ifdef FEAT_DIFF
+ curwin->w_p_diff = FALSE;
+#endif
+#ifdef FEAT_FOLDING
+ set_option_value((char_u *)"fdm", 0L, (char_u *)"manual",
+ OPT_LOCAL);
+#endif
+ }
+
+ // Only set the height when still in the same tab page and there is no
+ // window to the side.
+ if (curtab == prevtab && curwin->w_width == Columns)
+ win_setheight(height);
+ curwin->w_p_wfh = TRUE; // set 'winfixheight'
+ if (win_valid(win))
+ prevwin = win;
+
+ return OK;
+}
+
+/*
+ * ":copen": open a window that shows the list of errors.
+ * ":lopen": open a window that shows the location list.
+ */
+ void
+ex_copen(exarg_T *eap)
+{
+ qf_info_T *qi = &ql_info;
+ qf_list_T *qfl;
+ int height;
+ int status = FAIL;
+ int lnum;
+
+ if (is_loclist_cmd(eap->cmdidx))
+ {
+ qi = GET_LOC_LIST(curwin);
+ if (qi == NULL)
+ {
+ emsg(_(e_loclist));
+ return;
+ }
+ }
+
+ incr_quickfix_busy();
+
+ if (eap->addr_count != 0)
+ height = eap->line2;
+ else
+ height = QF_WINHEIGHT;
+
+ reset_VIsual_and_resel(); // stop Visual mode
+#ifdef FEAT_GUI
+ need_mouse_correct = TRUE;
+#endif
+
+ // Find an existing quickfix window, or open a new one.
+ if (cmdmod.tab == 0)
+ status = qf_goto_cwindow(qi, eap->addr_count != 0, height,
+ cmdmod.split & WSP_VERT);
+ if (status == FAIL)
+ if (qf_open_new_cwindow(qi, height) == FAIL)
+ {
+ decr_quickfix_busy();
+ return;
+ }
+
+ qfl = &qi->qf_lists[qi->qf_curlist];
+ qf_set_title_var(qfl);
+ // Save the current index here, as updating the quickfix buffer may free
+ // the quickfix list
+ lnum = qfl->qf_index;
+
+ // Fill the buffer with the quickfix list.
+ qf_fill_buffer(qi, curbuf, NULL);
+
+ decr_quickfix_busy();
+
+ curwin->w_cursor.lnum = lnum;
+ curwin->w_cursor.col = 0;
+ check_cursor();
+ update_topline(); // scroll to show the line
+}
+
+/*
+ * Move the cursor in the quickfix window to "lnum".
+ */
+ static void
+qf_win_goto(win_T *win, linenr_T lnum)
+{
+ win_T *old_curwin = curwin;
+
+ curwin = win;
+ curbuf = win->w_buffer;
+ curwin->w_cursor.lnum = lnum;
+ curwin->w_cursor.col = 0;
+ curwin->w_cursor.coladd = 0;
+ curwin->w_curswant = 0;
+ update_topline(); // scroll to show the line
+ redraw_later(VALID);
+ curwin->w_redr_status = TRUE; // update ruler
+ curwin = old_curwin;
+ curbuf = curwin->w_buffer;
+}
+
+/*
+ * :cbottom/:lbottom commands.
+ */
+ void
+ex_cbottom(exarg_T *eap)
+{
+ qf_info_T *qi = &ql_info;
+ win_T *win;
+
+ if (is_loclist_cmd(eap->cmdidx))
+ {
+ qi = GET_LOC_LIST(curwin);
+ if (qi == NULL)
+ {
+ emsg(_(e_loclist));
+ return;
+ }
+ }
+
+ win = qf_find_win(qi);
+ if (win != NULL && win->w_cursor.lnum != win->w_buffer->b_ml.ml_line_count)
+ qf_win_goto(win, win->w_buffer->b_ml.ml_line_count);
+}
+
+/*
+ * Return the number of the current entry (line number in the quickfix
+ * window).
+ */
+ linenr_T
+qf_current_entry(win_T *wp)
+{
+ qf_info_T *qi = &ql_info;
+
+ if (IS_LL_WINDOW(wp))
+ // In the location list window, use the referenced location list
+ qi = wp->w_llist_ref;
+
+ return qi->qf_lists[qi->qf_curlist].qf_index;
+}
+
+/*
+ * Update the cursor position in the quickfix window to the current error.
+ * Return TRUE if there is a quickfix window.
+ */
+ static int
+qf_win_pos_update(
+ qf_info_T *qi,
+ int old_qf_index) // previous qf_index or zero
+{
+ win_T *win;
+ int qf_index = qi->qf_lists[qi->qf_curlist].qf_index;
+
+ // Put the cursor on the current error in the quickfix window, so that
+ // it's viewable.
+ win = qf_find_win(qi);
+ if (win != NULL
+ && qf_index <= win->w_buffer->b_ml.ml_line_count
+ && old_qf_index != qf_index)
+ {
+ if (qf_index > old_qf_index)
+ {
+ win->w_redraw_top = old_qf_index;
+ win->w_redraw_bot = qf_index;
+ }
+ else
+ {
+ win->w_redraw_top = qf_index;
+ win->w_redraw_bot = old_qf_index;
+ }
+ qf_win_goto(win, qf_index);
+ }
+ return win != NULL;
+}
+
+/*
+ * Check whether the given window is displaying the specified quickfix/location
+ * stack.
+ */
+ static int
+is_qf_win(win_T *win, qf_info_T *qi)
+{
+ // A window displaying the quickfix buffer will have the w_llist_ref field
+ // set to NULL.
+ // A window displaying a location list buffer will have the w_llist_ref
+ // pointing to the location list.
+ if (bt_quickfix(win->w_buffer))
+ if ((IS_QF_STACK(qi) && win->w_llist_ref == NULL)
+ || (IS_LL_STACK(qi) && win->w_llist_ref == qi))
+ return TRUE;
+
+ return FALSE;
+}
+
+/*
+ * Find a window displaying the quickfix/location stack 'qi'
+ * Only searches in the current tabpage.
+ */
+ static win_T *
+qf_find_win(qf_info_T *qi)
+{
+ win_T *win;
+
+ FOR_ALL_WINDOWS(win)
+ if (is_qf_win(win, qi))
+ return win;
+ return NULL;
+}
+
+/*
+ * Find a quickfix buffer.
+ * Searches in windows opened in all the tabs.
+ */
+ static buf_T *
+qf_find_buf(qf_info_T *qi)
+{
+ tabpage_T *tp;
+ win_T *win;
+
+ FOR_ALL_TAB_WINDOWS(tp, win)
+ if (is_qf_win(win, qi))
+ return win->w_buffer;
+
+ return NULL;
+}
+
+/*
+ * Update the w:quickfix_title variable in the quickfix/location list window
+ */
+ static void
+qf_update_win_titlevar(qf_info_T *qi)
+{
+ win_T *win;
+ win_T *curwin_save;
+
+ if ((win = qf_find_win(qi)) != NULL)
+ {
+ curwin_save = curwin;
+ curwin = win;
+ qf_set_title_var(&qi->qf_lists[qi->qf_curlist]);
+ curwin = curwin_save;
+ }
+}
+
+/*
+ * Find the quickfix buffer. If it exists, update the contents.
+ */
+ static void
+qf_update_buffer(qf_info_T *qi, qfline_T *old_last)
+{
+ buf_T *buf;
+ win_T *win;
+ aco_save_T aco;
+
+ // Check if a buffer for the quickfix list exists. Update it.
+ buf = qf_find_buf(qi);
+ if (buf != NULL)
+ {
+ linenr_T old_line_count = buf->b_ml.ml_line_count;
+
+ if (old_last == NULL)
+ // set curwin/curbuf to buf and save a few things
+ aucmd_prepbuf(&aco, buf);
+
+ qf_update_win_titlevar(qi);
+
+ qf_fill_buffer(qi, buf, old_last);
+ ++CHANGEDTICK(buf);
+
+ if (old_last == NULL)
+ {
+ (void)qf_win_pos_update(qi, 0);
+
+ // restore curwin/curbuf and a few other things
+ aucmd_restbuf(&aco);
+ }
+
+ // Only redraw when added lines are visible. This avoids flickering
+ // when the added lines are not visible.
+ if ((win = qf_find_win(qi)) != NULL && old_line_count < win->w_botline)
+ redraw_buf_later(buf, NOT_VALID);
+ }
+}
+
+/*
+ * Add an error line to the quickfix buffer.
+ */
+ static int
+qf_buf_add_line(buf_T *buf, linenr_T lnum, qfline_T *qfp, char_u *dirname)
+{
+ int len;
+ buf_T *errbuf;
+
+ if (qfp->qf_module != NULL)
+ {
+ STRCPY(IObuff, qfp->qf_module);
+ len = (int)STRLEN(IObuff);
+ }
+ else if (qfp->qf_fnum != 0
+ && (errbuf = buflist_findnr(qfp->qf_fnum)) != NULL
+ && errbuf->b_fname != NULL)
+ {
+ if (qfp->qf_type == 1) // :helpgrep
+ STRCPY(IObuff, gettail(errbuf->b_fname));
+ else
+ {
+ // shorten the file name if not done already
+ if (errbuf->b_sfname == NULL
+ || mch_isFullName(errbuf->b_sfname))
+ {
+ if (*dirname == NUL)
+ mch_dirname(dirname, MAXPATHL);
+ shorten_buf_fname(errbuf, dirname, FALSE);
+ }
+ STRCPY(IObuff, errbuf->b_fname);
+ }
+ len = (int)STRLEN(IObuff);
+ }
+ else
+ len = 0;
+ IObuff[len++] = '|';
+
+ if (qfp->qf_lnum > 0)
+ {
+ sprintf((char *)IObuff + len, "%ld", qfp->qf_lnum);
+ len += (int)STRLEN(IObuff + len);
+
+ if (qfp->qf_col > 0)
+ {
+ sprintf((char *)IObuff + len, " col %d", qfp->qf_col);
+ len += (int)STRLEN(IObuff + len);
+ }
+
+ sprintf((char *)IObuff + len, "%s",
+ (char *)qf_types(qfp->qf_type, qfp->qf_nr));
+ len += (int)STRLEN(IObuff + len);
+ }
+ else if (qfp->qf_pattern != NULL)
+ {
+ qf_fmt_text(qfp->qf_pattern, IObuff + len, IOSIZE - len);
+ len += (int)STRLEN(IObuff + len);
+ }
+ IObuff[len++] = '|';
+ IObuff[len++] = ' ';
+
+ // Remove newlines and leading whitespace from the text.
+ // For an unrecognized line keep the indent, the compiler may
+ // mark a word with ^^^^.
+ qf_fmt_text(len > 3 ? skipwhite(qfp->qf_text) : qfp->qf_text,
+ IObuff + len, IOSIZE - len);
+
+ if (ml_append_buf(buf, lnum, IObuff,
+ (colnr_T)STRLEN(IObuff) + 1, FALSE) == FAIL)
+ return FAIL;
+
+ return OK;
+}
+
+/*
+ * Fill current buffer with quickfix errors, replacing any previous contents.
+ * curbuf must be the quickfix buffer!
+ * If "old_last" is not NULL append the items after this one.
+ * When "old_last" is NULL then "buf" must equal "curbuf"! Because
+ * ml_delete() is used and autocommands will be triggered.
+ */
+ static void
+qf_fill_buffer(qf_info_T *qi, buf_T *buf, qfline_T *old_last)
+{
+ linenr_T lnum;
+ qfline_T *qfp;
+ int old_KeyTyped = KeyTyped;
+
+ if (old_last == NULL)
+ {
+ if (buf != curbuf)
+ {
+ internal_error("qf_fill_buffer()");
+ return;
+ }
+
+ // delete all existing lines
+ while ((curbuf->b_ml.ml_flags & ML_EMPTY) == 0)
+ (void)ml_delete((linenr_T)1, FALSE);
+ }
+
+ // Check if there is anything to display
+ if (!qf_stack_empty(qi))
+ {
+ qf_list_T *qfl = &qi->qf_lists[qi->qf_curlist];
+ char_u dirname[MAXPATHL];
+
+ *dirname = NUL;
+
+ // Add one line for each error
+ if (old_last == NULL)
+ {
+ qfp = qfl->qf_start;
+ lnum = 0;
+ }
+ else
+ {
+ qfp = old_last->qf_next;
+ lnum = buf->b_ml.ml_line_count;
+ }
+ while (lnum < qfl->qf_count)
+ {
+ if (qf_buf_add_line(buf, lnum, qfp, dirname) == FAIL)
+ break;
+
+ ++lnum;
+ qfp = qfp->qf_next;
+ if (qfp == NULL)
+ break;
+ }
+
+ if (old_last == NULL)
+ // Delete the empty line which is now at the end
+ (void)ml_delete(lnum + 1, FALSE);
+ }
+
+ // correct cursor position
+ check_lnums(TRUE);
+
+ if (old_last == NULL)
+ {
+ // Set the 'filetype' to "qf" each time after filling the buffer.
+ // This resembles reading a file into a buffer, it's more logical when
+ // using autocommands.
+ ++curbuf_lock;
+ set_option_value((char_u *)"ft", 0L, (char_u *)"qf", OPT_LOCAL);
+ curbuf->b_p_ma = FALSE;
+
+ keep_filetype = TRUE; // don't detect 'filetype'
+ apply_autocmds(EVENT_BUFREADPOST, (char_u *)"quickfix", NULL,
+ FALSE, curbuf);
+ apply_autocmds(EVENT_BUFWINENTER, (char_u *)"quickfix", NULL,
+ FALSE, curbuf);
+ keep_filetype = FALSE;
+ --curbuf_lock;
+
+ // make sure it will be redrawn
+ redraw_curbuf_later(NOT_VALID);
+ }
+
+ // Restore KeyTyped, setting 'filetype' may reset it.
+ KeyTyped = old_KeyTyped;
+}
+
+/*
+ * For every change made to the quickfix list, update the changed tick.
+ */
+ static void
+qf_list_changed(qf_list_T *qfl)
+{
+ qfl->qf_changedtick++;
+}
+
+/*
+ * Return the quickfix/location list number with the given identifier.
+ * Returns -1 if list is not found.
+ */
+ static int
+qf_id2nr(qf_info_T *qi, int_u qfid)
+{
+ int qf_idx;
+
+ for (qf_idx = 0; qf_idx < qi->qf_listcount; qf_idx++)
+ if (qi->qf_lists[qf_idx].qf_id == qfid)
+ return qf_idx;
+ return INVALID_QFIDX;
+}
+
+/*
+ * If the current list is not "save_qfid" and we can find the list with that ID
+ * then make it the current list.
+ * This is used when autocommands may have changed the current list.
+ * Returns OK if successfully restored the list. Returns FAIL if the list with
+ * the specified identifier (save_qfid) is not found in the stack.
+ */
+ static int
+qf_restore_list(qf_info_T *qi, int_u save_qfid)
+{
+ int curlist;
+
+ if (qi->qf_lists[qi->qf_curlist].qf_id != save_qfid)
+ {
+ curlist = qf_id2nr(qi, save_qfid);
+ if (curlist < 0)
+ // list is not present
+ return FAIL;
+ qi->qf_curlist = curlist;
+ }
+ return OK;
+}
+
+/*
+ * Jump to the first entry if there is one.
+ */
+ static void
+qf_jump_first(qf_info_T *qi, int_u save_qfid, int forceit)
+{
+ if (qf_restore_list(qi, save_qfid) == FAIL)
+ return;
+
+ // Autocommands might have cleared the list, check for that.
+ if (!qf_list_empty(qi, qi->qf_curlist))
+ qf_jump(qi, 0, 0, forceit);
+}
+
+/*
+ * Return TRUE when using ":vimgrep" for ":grep".
+ */
+ int
+grep_internal(cmdidx_T cmdidx)
+{
+ return ((cmdidx == CMD_grep
+ || cmdidx == CMD_lgrep
+ || cmdidx == CMD_grepadd
+ || cmdidx == CMD_lgrepadd)
+ && STRCMP("internal",
+ *curbuf->b_p_gp == NUL ? p_gp : curbuf->b_p_gp) == 0);
+}
+
+/*
+ * Return the make/grep autocmd name.
+ */
+ static char_u *
+make_get_auname(cmdidx_T cmdidx)
+{
+ switch (cmdidx)
+ {
+ case CMD_make: return (char_u *)"make";
+ case CMD_lmake: return (char_u *)"lmake";
+ case CMD_grep: return (char_u *)"grep";
+ case CMD_lgrep: return (char_u *)"lgrep";
+ case CMD_grepadd: return (char_u *)"grepadd";
+ case CMD_lgrepadd: return (char_u *)"lgrepadd";
+ default: return NULL;
+ }
+}
+
+/*
+ * Return the name for the errorfile, in allocated memory.
+ * Find a new unique name when 'makeef' contains "##".
+ * Returns NULL for error.
+ */
+ static char_u *
+get_mef_name(void)
+{
+ char_u *p;
+ char_u *name;
+ static int start = -1;
+ static int off = 0;
+#ifdef HAVE_LSTAT
+ stat_T sb;
+#endif
+
+ if (*p_mef == NUL)
+ {
+ name = vim_tempname('e', FALSE);
+ if (name == NULL)
+ emsg(_(e_notmp));
+ return name;
+ }
+
+ for (p = p_mef; *p; ++p)
+ if (p[0] == '#' && p[1] == '#')
+ break;
+
+ if (*p == NUL)
+ return vim_strsave(p_mef);
+
+ // Keep trying until the name doesn't exist yet.
+ for (;;)
+ {
+ if (start == -1)
+ start = mch_get_pid();
+ else
+ off += 19;
+
+ name = alloc((unsigned)STRLEN(p_mef) + 30);
+ if (name == NULL)
+ break;
+ STRCPY(name, p_mef);
+ sprintf((char *)name + (p - p_mef), "%d%d", start, off);
+ STRCAT(name, p + 2);
+ if (mch_getperm(name) < 0
+#ifdef HAVE_LSTAT
+ // Don't accept a symbolic link, it's a security risk.
+ && mch_lstat((char *)name, &sb) < 0
+#endif
+ )
+ break;
+ vim_free(name);
+ }
+ return name;
+}
+
+/*
+ * Form the complete command line to invoke 'make'/'grep'. Quote the command
+ * using 'shellquote' and append 'shellpipe'. Echo the fully formed command.
+ */
+ static char_u *
+make_get_fullcmd(char_u *makecmd, char_u *fname)
+{
+ char_u *cmd;
+ unsigned len;
+
+ len = (unsigned)STRLEN(p_shq) * 2 + (unsigned)STRLEN(makecmd) + 1;
+ if (*p_sp != NUL)
+ len += (unsigned)STRLEN(p_sp) + (unsigned)STRLEN(fname) + 3;
+ cmd = alloc(len);
+ if (cmd == NULL)
+ return NULL;
+ sprintf((char *)cmd, "%s%s%s", (char *)p_shq, (char *)makecmd,
+ (char *)p_shq);
+
+ // If 'shellpipe' empty: don't redirect to 'errorfile'.
+ if (*p_sp != NUL)
+ append_redir(cmd, len, p_sp, fname);
+
+ // Display the fully formed command. Output a newline if there's something
+ // else than the :make command that was typed (in which case the cursor is
+ // in column 0).
+ if (msg_col == 0)
+ msg_didout = FALSE;
+ msg_start();
+ msg_puts(":!");
+ msg_outtrans(cmd); // show what we are doing
+
+ return cmd;
+}
+
+/*
+ * Used for ":make", ":lmake", ":grep", ":lgrep", ":grepadd", and ":lgrepadd"
+ */
+ void
+ex_make(exarg_T *eap)
+{
+ char_u *fname;
+ char_u *cmd;
+ char_u *enc = NULL;
+ win_T *wp = NULL;
+ qf_info_T *qi = &ql_info;
+ int res;
+ char_u *au_name = NULL;
+ int_u save_qfid;
+
+ // Redirect ":grep" to ":vimgrep" if 'grepprg' is "internal".
+ if (grep_internal(eap->cmdidx))
+ {
+ ex_vimgrep(eap);
+ return;
+ }
+
+ au_name = make_get_auname(eap->cmdidx);
+ if (au_name != NULL && apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name,
+ curbuf->b_fname, TRUE, curbuf))
+ {
+#ifdef FEAT_EVAL
+ if (aborting())
+ return;
+#endif
+ }
+ enc = (*curbuf->b_p_menc != NUL) ? curbuf->b_p_menc : p_menc;
+
+ if (is_loclist_cmd(eap->cmdidx))
+ wp = curwin;
+
+ autowrite_all();
+ fname = get_mef_name();
+ if (fname == NULL)
+ return;
+ mch_remove(fname); // in case it's not unique
+
+ cmd = make_get_fullcmd(eap->arg, fname);
+ if (cmd == NULL)
+ return;
+
+ // let the shell know if we are redirecting output or not
+ do_shell(cmd, *p_sp != NUL ? SHELL_DOOUT : 0);
+
+#ifdef AMIGA
+ out_flush();
+ // read window status report and redraw before message
+ (void)char_avail();
+#endif
+
+ incr_quickfix_busy();
+
+ res = qf_init(wp, fname, (eap->cmdidx != CMD_make
+ && eap->cmdidx != CMD_lmake) ? p_gefm : p_efm,
+ (eap->cmdidx != CMD_grepadd
+ && eap->cmdidx != CMD_lgrepadd),
+ qf_cmdtitle(*eap->cmdlinep), enc);
+ if (wp != NULL)
+ {
+ qi = GET_LOC_LIST(wp);
+ if (qi == NULL)
+ goto cleanup;
+ }
+ if (res >= 0)
+ qf_list_changed(&qi->qf_lists[qi->qf_curlist]);
+
+ // Remember the current quickfix list identifier, so that we can
+ // check for autocommands changing the current quickfix list.
+ save_qfid = qi->qf_lists[qi->qf_curlist].qf_id;
+ if (au_name != NULL)
+ apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name,
+ curbuf->b_fname, TRUE, curbuf);
+ if (res > 0 && !eap->forceit && qflist_valid(wp, save_qfid))
+ // display the first error
+ qf_jump_first(qi, save_qfid, FALSE);
+
+cleanup:
+ decr_quickfix_busy();
+ mch_remove(fname);
+ vim_free(fname);
+ vim_free(cmd);
+}
+
+/*
+ * Returns the number of valid entries in the current quickfix/location list.
+ */
+ int
+qf_get_size(exarg_T *eap)
+{
+ qf_info_T *qi = &ql_info;
+ qf_list_T *qfl;
+ qfline_T *qfp;
+ int i, sz = 0;
+ int prev_fnum = 0;
+
+ if (is_loclist_cmd(eap->cmdidx))
+ {
+ // Location list
+ qi = GET_LOC_LIST(curwin);
+ if (qi == NULL)
+ return 0;
+ }
+
+ qfl = &qi->qf_lists[qi->qf_curlist];
+ for (i = 0, qfp = qfl->qf_start; i < qfl->qf_count && qfp != NULL;
+ ++i, qfp = qfp->qf_next)
+ {
+ if (qfp->qf_valid)
+ {
+ if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo)
+ sz++; // Count all valid entries
+ else if (qfp->qf_fnum > 0 && qfp->qf_fnum != prev_fnum)
+ {
+ // Count the number of files
+ sz++;
+ prev_fnum = qfp->qf_fnum;
+ }
+ }
+ }
+
+ return sz;
+}
+
+/*
+ * Returns the current index of the quickfix/location list.
+ * Returns 0 if there is an error.
+ */
+ int
+qf_get_cur_idx(exarg_T *eap)
+{
+ qf_info_T *qi = &ql_info;
+
+ if (is_loclist_cmd(eap->cmdidx))
+ {
+ // Location list
+ qi = GET_LOC_LIST(curwin);
+ if (qi == NULL)
+ return 0;
+ }
+
+ return qi->qf_lists[qi->qf_curlist].qf_index;
+}
+
+/*
+ * Returns the current index in the quickfix/location list (counting only valid
+ * entries). If no valid entries are in the list, then returns 1.
+ */
+ int
+qf_get_cur_valid_idx(exarg_T *eap)
+{
+ qf_info_T *qi = &ql_info;
+ qf_list_T *qfl;
+ qfline_T *qfp;
+ int i, eidx = 0;
+ int prev_fnum = 0;
+
+ if (is_loclist_cmd(eap->cmdidx))
+ {
+ // Location list
+ qi = GET_LOC_LIST(curwin);
+ if (qi == NULL)
+ return 1;
+ }
+
+ qfl = &qi->qf_lists[qi->qf_curlist];
+ qfp = qfl->qf_start;
+
+ // check if the list has valid errors
+ if (qfl->qf_count <= 0 || qfl->qf_nonevalid)
+ return 1;
+
+ for (i = 1; i <= qfl->qf_index && qfp!= NULL; i++, qfp = qfp->qf_next)
+ {
+ if (qfp->qf_valid)
+ {
+ if (eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
+ {
+ if (qfp->qf_fnum > 0 && qfp->qf_fnum != prev_fnum)
+ {
+ // Count the number of files
+ eidx++;
+ prev_fnum = qfp->qf_fnum;
+ }
+ }
+ else
+ eidx++;
+ }
+ }
+
+ return eidx ? eidx : 1;
+}
+
+/*
+ * Get the 'n'th valid error entry in the quickfix or location list.
+ * Used by :cdo, :ldo, :cfdo and :lfdo commands.
+ * For :cdo and :ldo returns the 'n'th valid error entry.
+ * For :cfdo and :lfdo returns the 'n'th valid file entry.
+ */
+ static int
+qf_get_nth_valid_entry(qf_list_T *qfl, int n, int fdo)
+{
+ qfline_T *qfp = qfl->qf_start;
+ int i, eidx;
+ int prev_fnum = 0;
+
+ // check if the list has valid errors
+ if (qfl->qf_count <= 0 || qfl->qf_nonevalid)
+ return 1;
+
+ for (i = 1, eidx = 0; i <= qfl->qf_count && qfp != NULL;
+ i++, qfp = qfp->qf_next)
+ {
+ if (qfp->qf_valid)
+ {
+ if (fdo)
+ {
+ if (qfp->qf_fnum > 0 && qfp->qf_fnum != prev_fnum)
+ {
+ // Count the number of files
+ eidx++;
+ prev_fnum = qfp->qf_fnum;
+ }
+ }
+ else
+ eidx++;
+ }
+
+ if (eidx == n)
+ break;
+ }
+
+ if (i <= qfl->qf_count)
+ return i;
+ else
+ return 1;
+}
+
+/*
+ * ":cc", ":crewind", ":cfirst" and ":clast".
+ * ":ll", ":lrewind", ":lfirst" and ":llast".
+ * ":cdo", ":ldo", ":cfdo" and ":lfdo"
+ */
+ void
+ex_cc(exarg_T *eap)
+{
+ qf_info_T *qi = &ql_info;
+ int errornr;
+
+ if (is_loclist_cmd(eap->cmdidx))
+ {
+ qi = GET_LOC_LIST(curwin);
+ if (qi == NULL)
+ {
+ emsg(_(e_loclist));
+ return;
+ }
+ }
+
+ if (eap->addr_count > 0)
+ errornr = (int)eap->line2;
+ else
+ {
+ switch (eap->cmdidx)
+ {
+ case CMD_cc: case CMD_ll:
+ errornr = 0;
+ break;
+ case CMD_crewind: case CMD_lrewind: case CMD_cfirst:
+ case CMD_lfirst:
+ errornr = 1;
+ break;
+ default:
+ errornr = 32767;
+ }
+ }
+
+ // For cdo and ldo commands, jump to the nth valid error.
+ // For cfdo and lfdo commands, jump to the nth valid file entry.
+ if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
+ || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
+ errornr = qf_get_nth_valid_entry(&qi->qf_lists[qi->qf_curlist],
+ eap->addr_count > 0 ? (int)eap->line1 : 1,
+ eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo);
+
+ qf_jump(qi, 0, errornr, eap->forceit);
+}
+
+/*
+ * ":cnext", ":cnfile", ":cNext" and ":cprevious".
+ * ":lnext", ":lNext", ":lprevious", ":lnfile", ":lNfile" and ":lpfile".
+ * Also, used by ":cdo", ":ldo", ":cfdo" and ":lfdo" commands.
+ */
+ void
+ex_cnext(exarg_T *eap)
+{
+ qf_info_T *qi = &ql_info;
+ int errornr;
+ int dir;
+
+ if (is_loclist_cmd(eap->cmdidx))
+ {
+ qi = GET_LOC_LIST(curwin);
+ if (qi == NULL)
+ {
+ emsg(_(e_loclist));
+ return;
+ }
+ }
+
+ if (eap->addr_count > 0
+ && (eap->cmdidx != CMD_cdo && eap->cmdidx != CMD_ldo
+ && eap->cmdidx != CMD_cfdo && eap->cmdidx != CMD_lfdo))
+ errornr = (int)eap->line2;
+ else
+ errornr = 1;
+
+ // Depending on the command jump to either next or previous entry/file.
+ switch (eap->cmdidx)
+ {
+ case CMD_cnext: case CMD_lnext: case CMD_cdo: case CMD_ldo:
+ dir = FORWARD;
+ break;
+ case CMD_cprevious: case CMD_lprevious: case CMD_cNext:
+ case CMD_lNext:
+ dir = BACKWARD;
+ break;
+ case CMD_cnfile: case CMD_lnfile: case CMD_cfdo: case CMD_lfdo:
+ dir = FORWARD_FILE;
+ break;
+ case CMD_cpfile: case CMD_lpfile: case CMD_cNfile: case CMD_lNfile:
+ dir = BACKWARD_FILE;
+ break;
+ default:
+ dir = FORWARD;
+ break;
+ }
+
+ qf_jump(qi, dir, errornr, eap->forceit);
+}
+
+/*
+ * ":cfile"/":cgetfile"/":caddfile" commands.
+ * ":lfile"/":lgetfile"/":laddfile" commands.
+ */
+ void
+ex_cfile(exarg_T *eap)
+{
+ char_u *enc = NULL;
+ win_T *wp = NULL;
+ qf_info_T *qi = &ql_info;
+ char_u *au_name = NULL;
+ int_u save_qfid = 0; // init for gcc
+ int res;
+
+ switch (eap->cmdidx)
+ {
+ case CMD_cfile: au_name = (char_u *)"cfile"; break;
+ case CMD_cgetfile: au_name = (char_u *)"cgetfile"; break;
+ case CMD_caddfile: au_name = (char_u *)"caddfile"; break;
+ case CMD_lfile: au_name = (char_u *)"lfile"; break;
+ case CMD_lgetfile: au_name = (char_u *)"lgetfile"; break;
+ case CMD_laddfile: au_name = (char_u *)"laddfile"; break;
+ default: break;
+ }
+ if (au_name != NULL)
+ apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name, NULL, FALSE, curbuf);
+ enc = (*curbuf->b_p_menc != NUL) ? curbuf->b_p_menc : p_menc;
+#ifdef FEAT_BROWSE
+ if (cmdmod.browse)
+ {
+ char_u *browse_file = do_browse(0, (char_u *)_("Error file"), eap->arg,
+ NULL, NULL,
+ (char_u *)_(BROWSE_FILTER_ALL_FILES), NULL);
+ if (browse_file == NULL)
+ return;
+ set_string_option_direct((char_u *)"ef", -1, browse_file, OPT_FREE, 0);
+ vim_free(browse_file);
+ }
+ else
+#endif
+ if (*eap->arg != NUL)
+ set_string_option_direct((char_u *)"ef", -1, eap->arg, OPT_FREE, 0);
+
+ if (is_loclist_cmd(eap->cmdidx))
+ wp = curwin;
+
+ incr_quickfix_busy();
+
+ // This function is used by the :cfile, :cgetfile and :caddfile
+ // commands.
+ // :cfile always creates a new quickfix list and jumps to the
+ // first error.
+ // :cgetfile creates a new quickfix list but doesn't jump to the
+ // first error.
+ // :caddfile adds to an existing quickfix list. If there is no
+ // quickfix list then a new list is created.
+ res = qf_init(wp, p_ef, p_efm, (eap->cmdidx != CMD_caddfile
+ && eap->cmdidx != CMD_laddfile),
+ qf_cmdtitle(*eap->cmdlinep), enc);
+ if (wp != NULL)
+ {
+ qi = GET_LOC_LIST(wp);
+ if (qi == NULL)
+ {
+ decr_quickfix_busy();
+ return;
+ }
+ }
+ if (res >= 0)
+ qf_list_changed(&qi->qf_lists[qi->qf_curlist]);
+ save_qfid = qi->qf_lists[qi->qf_curlist].qf_id;
+ if (au_name != NULL)
+ apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name, NULL, FALSE, curbuf);
+
+ // Jump to the first error for a new list and if autocmds didn't
+ // free the list.
+ if (res > 0 && (eap->cmdidx == CMD_cfile || eap->cmdidx == CMD_lfile)
+ && qflist_valid(wp, save_qfid))
+ // display the first error
+ qf_jump_first(qi, save_qfid, eap->forceit);
+
+ decr_quickfix_busy();
+}
+
+/*
+ * Return the vimgrep autocmd name.
+ */
+ static char_u *
+vgr_get_auname(cmdidx_T cmdidx)
+{
+ switch (cmdidx)
+ {
+ case CMD_vimgrep: return (char_u *)"vimgrep";
+ case CMD_lvimgrep: return (char_u *)"lvimgrep";
+ case CMD_vimgrepadd: return (char_u *)"vimgrepadd";
+ case CMD_lvimgrepadd: return (char_u *)"lvimgrepadd";
+ case CMD_grep: return (char_u *)"grep";
+ case CMD_lgrep: return (char_u *)"lgrep";
+ case CMD_grepadd: return (char_u *)"grepadd";
+ case CMD_lgrepadd: return (char_u *)"lgrepadd";
+ default: return NULL;
+ }
+}
+
+/*
+ * Initialize the regmatch used by vimgrep for pattern "s".
+ */
+ static void
+vgr_init_regmatch(regmmatch_T *regmatch, char_u *s)
+{
+ // Get the search pattern: either white-separated or enclosed in //
+ regmatch->regprog = NULL;
+
+ if (s == NULL || *s == NUL)
+ {
+ // Pattern is empty, use last search pattern.
+ if (last_search_pat() == NULL)
+ {
+ emsg(_(e_noprevre));
+ return;
+ }
+ regmatch->regprog = vim_regcomp(last_search_pat(), RE_MAGIC);
+ }
+ else
+ regmatch->regprog = vim_regcomp(s, RE_MAGIC);
+
+ regmatch->rmm_ic = p_ic;
+ regmatch->rmm_maxcol = 0;
+}
+
+/*
+ * Display a file name when vimgrep is running.
+ */
+ static void
+vgr_display_fname(char_u *fname)
+{
+ char_u *p;
+
+ msg_start();
+ p = msg_strtrunc(fname, TRUE);
+ if (p == NULL)
+ msg_outtrans(fname);
+ else
+ {
+ msg_outtrans(p);
+ vim_free(p);
+ }
+ msg_clr_eos();
+ msg_didout = FALSE; // overwrite this message
+ msg_nowait = TRUE; // don't wait for this message
+ msg_col = 0;
+ out_flush();
+}
+
+/*
+ * Load a dummy buffer to search for a pattern using vimgrep.
+ */
+ static buf_T *
+vgr_load_dummy_buf(
+ char_u *fname,
+ char_u *dirname_start,
+ char_u *dirname_now)
+{
+ int save_mls;
+#if defined(FEAT_SYN_HL)
+ char_u *save_ei = NULL;
+#endif
+ buf_T *buf;
+
+#if defined(FEAT_SYN_HL)
+ // Don't do Filetype autocommands to avoid loading syntax and
+ // indent scripts, a great speed improvement.
+ save_ei = au_event_disable(",Filetype");
+#endif
+ // Don't use modelines here, it's useless.
+ save_mls = p_mls;
+ p_mls = 0;
+
+ // Load file into a buffer, so that 'fileencoding' is detected,
+ // autocommands applied, etc.
+ buf = load_dummy_buffer(fname, dirname_start, dirname_now);
+
+ p_mls = save_mls;
+#if defined(FEAT_SYN_HL)
+ au_event_restore(save_ei);
+#endif
+
+ return buf;
+}
+
+/*
+ * Check whether a quickfix/location list valid. Autocmds may remove or change
+ * a quickfix list when vimgrep is running. If the list is not found, create a
+ * new list.
+ */
+ static int
+vgr_qflist_valid(
+ win_T *wp,
+ qf_info_T *qi,
+ int_u qfid,
+ char_u *title)
+{
+ // Verify that the quickfix/location list was not freed by an autocmd
+ if (!qflist_valid(wp, qfid))
+ {
+ if (wp != NULL)
+ {
+ // An autocmd has freed the location list.
+ emsg(_(e_loc_list_changed));
+ return FALSE;
+ }
+ else
+ {
+ // Quickfix list is not found, create a new one.
+ qf_new_list(qi, title);
+ return TRUE;
+ }
+ }
+
+ if (qf_restore_list(qi, qfid) == FAIL)
+ return FALSE;
+
+ return TRUE;
+}
+
+/*
+ * Search for a pattern in all the lines in a buffer and add the matching lines
+ * to a quickfix list.
+ */
+ static int
+vgr_match_buflines(
+ qf_info_T *qi,
+ char_u *fname,
+ buf_T *buf,
+ regmmatch_T *regmatch,
+ long *tomatch,
+ int duplicate_name,
+ int flags)
+{
+ int found_match = FALSE;
+ long lnum;
+ colnr_T col;
+
+ for (lnum = 1; lnum <= buf->b_ml.ml_line_count && *tomatch > 0; ++lnum)
+ {
+ col = 0;
+ while (vim_regexec_multi(regmatch, curwin, buf, lnum,
+ col, NULL, NULL) > 0)
+ {
+ // Pass the buffer number so that it gets used even for a
+ // dummy buffer, unless duplicate_name is set, then the
+ // buffer will be wiped out below.
+ if (qf_add_entry(qi,
+ qi->qf_curlist,
+ NULL, // dir
+ fname,
+ NULL,
+ duplicate_name ? 0 : buf->b_fnum,
+ ml_get_buf(buf,
+ regmatch->startpos[0].lnum + lnum, FALSE),
+ regmatch->startpos[0].lnum + lnum,
+ regmatch->startpos[0].col + 1,
+ FALSE, // vis_col
+ NULL, // search pattern
+ 0, // nr
+ 0, // type
+ TRUE // valid
+ ) == FAIL)
+ {
+ got_int = TRUE;
+ break;
+ }
+ found_match = TRUE;
+ if (--*tomatch == 0)
+ break;
+ if ((flags & VGR_GLOBAL) == 0
+ || regmatch->endpos[0].lnum > 0)
+ break;
+ col = regmatch->endpos[0].col
+ + (col == regmatch->endpos[0].col);
+ if (col > (colnr_T)STRLEN(ml_get_buf(buf, lnum, FALSE)))
+ break;
+ }
+ line_breakcheck();
+ if (got_int)
+ break;
+ }
+
+ return found_match;
+}
+
+/*
+ * Jump to the first match and update the directory.
+ */
+ static void
+vgr_jump_to_match(
+ qf_info_T *qi,
+ int forceit,
+ int *redraw_for_dummy,
+ buf_T *first_match_buf,
+ char_u *target_dir)
+{
+ buf_T *buf;
+
+ buf = curbuf;
+ qf_jump(qi, 0, 0, forceit);
+ if (buf != curbuf)
+ // If we jumped to another buffer redrawing will already be
+ // taken care of.
+ *redraw_for_dummy = FALSE;
+
+ // Jump to the directory used after loading the buffer.
+ if (curbuf == first_match_buf && target_dir != NULL)
+ {
+ exarg_T ea;
+
+ ea.arg = target_dir;
+ ea.cmdidx = CMD_lcd;
+ ex_cd(&ea);
+ }
+}
+
+/*
+ * ":vimgrep {pattern} file(s)"
+ * ":vimgrepadd {pattern} file(s)"
+ * ":lvimgrep {pattern} file(s)"
+ * ":lvimgrepadd {pattern} file(s)"
+ */
+ void
+ex_vimgrep(exarg_T *eap)
+{
+ regmmatch_T regmatch;
+ int fcount;
+ char_u **fnames;
+ char_u *fname;
+ char_u *title;
+ char_u *s;
+ char_u *p;
+ int fi;
+ qf_info_T *qi = &ql_info;
+ qf_list_T *qfl;
+ int_u save_qfid;
+ win_T *wp = NULL;
+ buf_T *buf;
+ int duplicate_name = FALSE;
+ int using_dummy;
+ int redraw_for_dummy = FALSE;
+ int found_match;
+ buf_T *first_match_buf = NULL;
+ time_t seconds = 0;
+ aco_save_T aco;
+ int flags = 0;
+ long tomatch;
+ char_u *dirname_start = NULL;
+ char_u *dirname_now = NULL;
+ char_u *target_dir = NULL;
+ char_u *au_name = NULL;
+
+ au_name = vgr_get_auname(eap->cmdidx);
+ if (au_name != NULL && apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name,
+ curbuf->b_fname, TRUE, curbuf))
+ {
+#ifdef FEAT_EVAL
+ if (aborting())
+ return;
+#endif
+ }
+
+ if (is_loclist_cmd(eap->cmdidx))
+ {
+ qi = ll_get_or_alloc_list(curwin);
+ if (qi == NULL)
+ return;
+ wp = curwin;
+ }
+
+ if (eap->addr_count > 0)
+ tomatch = eap->line2;
+ else
+ tomatch = MAXLNUM;
+
+ // Get the search pattern: either white-separated or enclosed in //
+ regmatch.regprog = NULL;
+ title = vim_strsave(qf_cmdtitle(*eap->cmdlinep));
+ p = skip_vimgrep_pat(eap->arg, &s, &flags);
+ if (p == NULL)
+ {
+ emsg(_(e_invalpat));
+ goto theend;
+ }
+
+ vgr_init_regmatch(&regmatch, s);
+ if (regmatch.regprog == NULL)
+ goto theend;
+
+ p = skipwhite(p);
+ if (*p == NUL)
+ {
+ emsg(_("E683: File name missing or invalid pattern"));
+ goto theend;
+ }
+
+ if ((eap->cmdidx != CMD_grepadd && eap->cmdidx != CMD_lgrepadd
+ && eap->cmdidx != CMD_vimgrepadd
+ && eap->cmdidx != CMD_lvimgrepadd)
+ || qf_stack_empty(qi))
+ // make place for a new list
+ qf_new_list(qi, title != NULL ? title : qf_cmdtitle(*eap->cmdlinep));
+
+ // parse the list of arguments
+ if (get_arglist_exp(p, &fcount, &fnames, TRUE) == FAIL)
+ goto theend;
+ if (fcount == 0)
+ {
+ emsg(_(e_nomatch));
+ goto theend;
+ }
+
+ dirname_start = alloc_id(MAXPATHL, aid_qf_dirname_start);
+ dirname_now = alloc_id(MAXPATHL, aid_qf_dirname_now);
+ if (dirname_start == NULL || dirname_now == NULL)
+ {
+ FreeWild(fcount, fnames);
+ goto theend;
+ }
+
+ // Remember the current directory, because a BufRead autocommand that does
+ // ":lcd %:p:h" changes the meaning of short path names.
+ mch_dirname(dirname_start, MAXPATHL);
+
+ incr_quickfix_busy();
+
+ // Remember the current quickfix list identifier, so that we can check for
+ // autocommands changing the current quickfix list.
+ save_qfid = qi->qf_lists[qi->qf_curlist].qf_id;
+
+ seconds = (time_t)0;
+ for (fi = 0; fi < fcount && !got_int && tomatch > 0; ++fi)
+ {
+ fname = shorten_fname1(fnames[fi]);
+ if (time(NULL) > seconds)
+ {
+ // Display the file name every second or so, show the user we are
+ // working on it.
+ seconds = time(NULL);
+ vgr_display_fname(fname);
+ }
+
+ buf = buflist_findname_exp(fnames[fi]);
+ if (buf == NULL || buf->b_ml.ml_mfp == NULL)
+ {
+ // Remember that a buffer with this name already exists.
+ duplicate_name = (buf != NULL);
+ using_dummy = TRUE;
+ redraw_for_dummy = TRUE;
+
+ buf = vgr_load_dummy_buf(fname, dirname_start, dirname_now);
+ }
+ else
+ // Use existing, loaded buffer.
+ using_dummy = FALSE;
+
+ // Check whether the quickfix list is still valid. When loading a
+ // buffer above, autocommands might have changed the quickfix list.
+ if (!vgr_qflist_valid(wp, qi, save_qfid, qf_cmdtitle(*eap->cmdlinep)))
+ {
+ FreeWild(fcount, fnames);
+ decr_quickfix_busy();
+ goto theend;
+ }
+ save_qfid = qi->qf_lists[qi->qf_curlist].qf_id;
+
+ if (buf == NULL)
+ {
+ if (!got_int)
+ smsg(_("Cannot open file \"%s\""), fname);
+ }
+ else
+ {
+ // Try for a match in all lines of the buffer.
+ // For ":1vimgrep" look for first match only.
+ found_match = vgr_match_buflines(qi, fname, buf, &regmatch,
+ &tomatch, duplicate_name, flags);
+
+ if (using_dummy)
+ {
+ if (found_match && first_match_buf == NULL)
+ first_match_buf = buf;
+ if (duplicate_name)
+ {
+ // Never keep a dummy buffer if there is another buffer
+ // with the same name.
+ wipe_dummy_buffer(buf, dirname_start);
+ buf = NULL;
+ }
+ else if (!cmdmod.hide
+ || buf->b_p_bh[0] == 'u' // "unload"
+ || buf->b_p_bh[0] == 'w' // "wipe"
+ || buf->b_p_bh[0] == 'd') // "delete"
+ {
+ // When no match was found we don't need to remember the
+ // buffer, wipe it out. If there was a match and it
+ // wasn't the first one or we won't jump there: only
+ // unload the buffer.
+ // Ignore 'hidden' here, because it may lead to having too
+ // many swap files.
+ if (!found_match)
+ {
+ wipe_dummy_buffer(buf, dirname_start);
+ buf = NULL;
+ }
+ else if (buf != first_match_buf || (flags & VGR_NOJUMP))
+ {
+ unload_dummy_buffer(buf, dirname_start);
+ // Keeping the buffer, remove the dummy flag.
+ buf->b_flags &= ~BF_DUMMY;
+ buf = NULL;
+ }
+ }
+
+ if (buf != NULL)
+ {
+ // Keeping the buffer, remove the dummy flag.
+ buf->b_flags &= ~BF_DUMMY;
+
+ // If the buffer is still loaded we need to use the
+ // directory we jumped to below.
+ if (buf == first_match_buf
+ && target_dir == NULL
+ && STRCMP(dirname_start, dirname_now) != 0)
+ target_dir = vim_strsave(dirname_now);
+
+ // The buffer is still loaded, the Filetype autocommands
+ // need to be done now, in that buffer. And the modelines
+ // need to be done (again). But not the window-local
+ // options!
+ aucmd_prepbuf(&aco, buf);
+#if defined(FEAT_SYN_HL)
+ apply_autocmds(EVENT_FILETYPE, buf->b_p_ft,
+ buf->b_fname, TRUE, buf);
+#endif
+ do_modelines(OPT_NOWIN);
+ aucmd_restbuf(&aco);
+ }
+ }
+ }
+ }
+
+ FreeWild(fcount, fnames);
+
+ qfl = &qi->qf_lists[qi->qf_curlist];
+ qfl->qf_nonevalid = FALSE;
+ qfl->qf_ptr = qfl->qf_start;
+ qfl->qf_index = 1;
+ qf_list_changed(qfl);
+
+ qf_update_buffer(qi, NULL);
+
+ if (au_name != NULL)
+ apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name,
+ curbuf->b_fname, TRUE, curbuf);
+ // The QuickFixCmdPost autocmd may free the quickfix list. Check the list
+ // is still valid.
+ if (!qflist_valid(wp, save_qfid)
+ || qf_restore_list(qi, save_qfid) == FAIL)
+ {
+ decr_quickfix_busy();
+ goto theend;
+ }
+
+ // Jump to first match.
+ if (!qf_list_empty(qi, qi->qf_curlist))
+ {
+ if ((flags & VGR_NOJUMP) == 0)
+ vgr_jump_to_match(qi, eap->forceit, &redraw_for_dummy,
+ first_match_buf, target_dir);
+ }
+ else
+ semsg(_(e_nomatch2), s);
+
+ decr_quickfix_busy();
+
+ // If we loaded a dummy buffer into the current window, the autocommands
+ // may have messed up things, need to redraw and recompute folds.
+ if (redraw_for_dummy)
+ {
+#ifdef FEAT_FOLDING
+ foldUpdateAll(curwin);
+#else
+ redraw_later(NOT_VALID);
+#endif
+ }
+
+theend:
+ vim_free(title);
+ vim_free(dirname_now);
+ vim_free(dirname_start);
+ vim_free(target_dir);
+ vim_regfree(regmatch.regprog);
+}
+
+/*
+ * Restore current working directory to "dirname_start" if they differ, taking
+ * into account whether it is set locally or globally.
+ */
+ static void
+restore_start_dir(char_u *dirname_start)
+{
+ char_u *dirname_now = alloc(MAXPATHL);
+
+ if (NULL != dirname_now)
+ {
+ mch_dirname(dirname_now, MAXPATHL);
+ if (STRCMP(dirname_start, dirname_now) != 0)
+ {
+ // If the directory has changed, change it back by building up an
+ // appropriate ex command and executing it.
+ exarg_T ea;
+
+ ea.arg = dirname_start;
+ ea.cmdidx = (curwin->w_localdir == NULL) ? CMD_cd : CMD_lcd;
+ ex_cd(&ea);
+ }
+ vim_free(dirname_now);
+ }
+}
+
+/*
+ * Load file "fname" into a dummy buffer and return the buffer pointer,
+ * placing the directory resulting from the buffer load into the
+ * "resulting_dir" pointer. "resulting_dir" must be allocated by the caller
+ * prior to calling this function. Restores directory to "dirname_start" prior
+ * to returning, if autocmds or the 'autochdir' option have changed it.
+ *
+ * If creating the dummy buffer does not fail, must call unload_dummy_buffer()
+ * or wipe_dummy_buffer() later!
+ *
+ * Returns NULL if it fails.
+ */
+ static buf_T *
+load_dummy_buffer(
+ char_u *fname,
+ char_u *dirname_start, // in: old directory
+ char_u *resulting_dir) // out: new directory
+{
+ buf_T *newbuf;
+ bufref_T newbufref;
+ bufref_T newbuf_to_wipe;
+ int failed = TRUE;
+ aco_save_T aco;
+ int readfile_result;
+
+ // Allocate a buffer without putting it in the buffer list.
+ newbuf = buflist_new(NULL, NULL, (linenr_T)1, BLN_DUMMY);
+ if (newbuf == NULL)
+ return NULL;
+ set_bufref(&newbufref, newbuf);
+
+ // Init the options.
+ buf_copy_options(newbuf, BCO_ENTER | BCO_NOHELP);
+
+ // need to open the memfile before putting the buffer in a window
+ if (ml_open(newbuf) == OK)
+ {
+ // Make sure this buffer isn't wiped out by autocommands.
+ ++newbuf->b_locked;
+
+ // set curwin/curbuf to buf and save a few things
+ aucmd_prepbuf(&aco, newbuf);
+
+ // Need to set the filename for autocommands.
+ (void)setfname(curbuf, fname, NULL, FALSE);
+
+ // Create swap file now to avoid the ATTENTION message.
+ check_need_swap(TRUE);
+
+ // Remove the "dummy" flag, otherwise autocommands may not
+ // work.
+ curbuf->b_flags &= ~BF_DUMMY;
+
+ newbuf_to_wipe.br_buf = NULL;
+ readfile_result = readfile(fname, NULL,
+ (linenr_T)0, (linenr_T)0, (linenr_T)MAXLNUM,
+ NULL, READ_NEW | READ_DUMMY);
+ --newbuf->b_locked;
+ if (readfile_result == OK
+ && !got_int
+ && !(curbuf->b_flags & BF_NEW))
+ {
+ failed = FALSE;
+ if (curbuf != newbuf)
+ {
+ // Bloody autocommands changed the buffer! Can happen when
+ // using netrw and editing a remote file. Use the current
+ // buffer instead, delete the dummy one after restoring the
+ // window stuff.
+ set_bufref(&newbuf_to_wipe, newbuf);
+ newbuf = curbuf;
+ }
+ }
+
+ // restore curwin/curbuf and a few other things
+ aucmd_restbuf(&aco);
+ if (newbuf_to_wipe.br_buf != NULL && bufref_valid(&newbuf_to_wipe))
+ wipe_buffer(newbuf_to_wipe.br_buf, FALSE);
+
+ // Add back the "dummy" flag, otherwise buflist_findname_stat() won't
+ // skip it.
+ newbuf->b_flags |= BF_DUMMY;
+ }
+
+ // When autocommands/'autochdir' option changed directory: go back.
+ // Let the caller know what the resulting dir was first, in case it is
+ // important.
+ mch_dirname(resulting_dir, MAXPATHL);
+ restore_start_dir(dirname_start);
+
+ if (!bufref_valid(&newbufref))
+ return NULL;
+ if (failed)
+ {
+ wipe_dummy_buffer(newbuf, dirname_start);
+ return NULL;
+ }
+ return newbuf;
+}
+
+/*
+ * Wipe out the dummy buffer that load_dummy_buffer() created. Restores
+ * directory to "dirname_start" prior to returning, if autocmds or the
+ * 'autochdir' option have changed it.
+ */
+ static void
+wipe_dummy_buffer(buf_T *buf, char_u *dirname_start)
+{
+ if (curbuf != buf) // safety check
+ {
+#if defined(FEAT_EVAL)
+ cleanup_T cs;
+
+ // Reset the error/interrupt/exception state here so that aborting()
+ // returns FALSE when wiping out the buffer. Otherwise it doesn't
+ // work when got_int is set.
+ enter_cleanup(&cs);
+#endif
+
+ wipe_buffer(buf, FALSE);
+
+#if defined(FEAT_EVAL)
+ // Restore the error/interrupt/exception state if not discarded by a
+ // new aborting error, interrupt, or uncaught exception.
+ leave_cleanup(&cs);
+#endif
+ // When autocommands/'autochdir' option changed directory: go back.
+ restore_start_dir(dirname_start);
+ }
+}
+
+/*
+ * Unload the dummy buffer that load_dummy_buffer() created. Restores
+ * directory to "dirname_start" prior to returning, if autocmds or the
+ * 'autochdir' option have changed it.
+ */
+ static void
+unload_dummy_buffer(buf_T *buf, char_u *dirname_start)
+{
+ if (curbuf != buf) // safety check
+ {
+ close_buffer(NULL, buf, DOBUF_UNLOAD, FALSE);
+
+ // When autocommands/'autochdir' option changed directory: go back.
+ restore_start_dir(dirname_start);
+ }
+}
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * Add each quickfix error to list "list" as a dictionary.
+ * If qf_idx is -1, use the current list. Otherwise, use the specified list.
+ */
+ int
+get_errorlist(qf_info_T *qi_arg, win_T *wp, int qf_idx, list_T *list)
+{
+ qf_info_T *qi = qi_arg;
+ dict_T *dict;
+ char_u buf[2];
+ qfline_T *qfp;
+ int i;
+ int bufnum;
+
+ if (qi == NULL)
+ {
+ qi = &ql_info;
+ if (wp != NULL)
+ {
+ qi = GET_LOC_LIST(wp);
+ if (qi == NULL)
+ return FAIL;
+ }
+ }
+
+ if (qf_idx == INVALID_QFIDX)
+ qf_idx = qi->qf_curlist;
+
+ if (qf_idx >= qi->qf_listcount || qf_list_empty(qi, qf_idx))
+ return FAIL;
+
+ qfp = qi->qf_lists[qf_idx].qf_start;
+ for (i = 1; !got_int && i <= qi->qf_lists[qf_idx].qf_count; ++i)
+ {
+ // Handle entries with a non-existing buffer number.
+ bufnum = qfp->qf_fnum;
+ if (bufnum != 0 && (buflist_findnr(bufnum) == NULL))
+ bufnum = 0;
+
+ if ((dict = dict_alloc()) == NULL)
+ return FAIL;
+ if (list_append_dict(list, dict) == FAIL)
+ return FAIL;
+
+ buf[0] = qfp->qf_type;
+ buf[1] = NUL;
+ if ( dict_add_number(dict, "bufnr", (long)bufnum) == FAIL
+ || dict_add_number(dict, "lnum", (long)qfp->qf_lnum) == FAIL
+ || dict_add_number(dict, "col", (long)qfp->qf_col) == FAIL
+ || dict_add_number(dict, "vcol", (long)qfp->qf_viscol) == FAIL
+ || dict_add_number(dict, "nr", (long)qfp->qf_nr) == FAIL
+ || dict_add_string(dict, "module", qfp->qf_module) == FAIL
+ || dict_add_string(dict, "pattern", qfp->qf_pattern) == FAIL
+ || dict_add_string(dict, "text", qfp->qf_text) == FAIL
+ || dict_add_string(dict, "type", buf) == FAIL
+ || dict_add_number(dict, "valid", (long)qfp->qf_valid) == FAIL)
+ return FAIL;
+
+ qfp = qfp->qf_next;
+ if (qfp == NULL)
+ break;
+ }
+ return OK;
+}
+
+// Flags used by getqflist()/getloclist() to determine which fields to return.
+enum {
+ QF_GETLIST_NONE = 0x0,
+ QF_GETLIST_TITLE = 0x1,
+ QF_GETLIST_ITEMS = 0x2,
+ QF_GETLIST_NR = 0x4,
+ QF_GETLIST_WINID = 0x8,
+ QF_GETLIST_CONTEXT = 0x10,
+ QF_GETLIST_ID = 0x20,
+ QF_GETLIST_IDX = 0x40,
+ QF_GETLIST_SIZE = 0x80,
+ QF_GETLIST_TICK = 0x100,
+ QF_GETLIST_FILEWINID = 0x200,
+ QF_GETLIST_ALL = 0x3FF,
+};
+
+/*
+ * Parse text from 'di' and return the quickfix list items.
+ * Existing quickfix lists are not modified.
+ */
+ static int
+qf_get_list_from_lines(dict_T *what, dictitem_T *di, dict_T *retdict)
+{
+ int status = FAIL;
+ qf_info_T *qi;
+ char_u *errorformat = p_efm;
+ dictitem_T *efm_di;
+ list_T *l;
+
+ // Only a List value is supported
+ if (di->di_tv.v_type == VAR_LIST && di->di_tv.vval.v_list != NULL)
+ {
+ // If errorformat is supplied then use it, otherwise use the 'efm'
+ // option setting
+ if ((efm_di = dict_find(what, (char_u *)"efm", -1)) != NULL)
+ {
+ if (efm_di->di_tv.v_type != VAR_STRING ||
+ efm_di->di_tv.vval.v_string == NULL)
+ return FAIL;
+ errorformat = efm_di->di_tv.vval.v_string;
+ }
+
+ l = list_alloc();
+ if (l == NULL)
+ return FAIL;
+
+ qi = qf_alloc_stack(QFLT_INTERNAL);
+ if (qi != NULL)
+ {
+ if (qf_init_ext(qi, 0, NULL, NULL, &di->di_tv, errorformat,
+ TRUE, (linenr_T)0, (linenr_T)0, NULL, NULL) > 0)
+ {
+ (void)get_errorlist(qi, NULL, 0, l);
+ qf_free(&qi->qf_lists[0]);
+ }
+ free(qi);
+ }
+ dict_add_list(retdict, "items", l);
+ status = OK;
+ }
+
+ return status;
+}
+
+/*
+ * Return the quickfix/location list window identifier in the current tabpage.
+ */
+ static int
+qf_winid(qf_info_T *qi)
+{
+ win_T *win;
+
+ // The quickfix window can be opened even if the quickfix list is not set
+ // using ":copen". This is not true for location lists.
+ if (qi == NULL)
+ return 0;
+ win = qf_find_win(qi);
+ if (win != NULL)
+ return win->w_id;
+ return 0;
+}
+
+/*
+ * Convert the keys in 'what' to quickfix list property flags.
+ */
+ static int
+qf_getprop_keys2flags(dict_T *what, int loclist)
+{
+ int flags = QF_GETLIST_NONE;
+
+ if (dict_find(what, (char_u *)"all", -1) != NULL)
+ {
+ flags |= QF_GETLIST_ALL;
+ if (!loclist)
+ // File window ID is applicable only to location list windows
+ flags &= ~ QF_GETLIST_FILEWINID;
+ }
+
+ if (dict_find(what, (char_u *)"title", -1) != NULL)
+ flags |= QF_GETLIST_TITLE;
+
+ if (dict_find(what, (char_u *)"nr", -1) != NULL)
+ flags |= QF_GETLIST_NR;
+
+ if (dict_find(what, (char_u *)"winid", -1) != NULL)
+ flags |= QF_GETLIST_WINID;
+
+ if (dict_find(what, (char_u *)"context", -1) != NULL)
+ flags |= QF_GETLIST_CONTEXT;
+
+ if (dict_find(what, (char_u *)"id", -1) != NULL)
+ flags |= QF_GETLIST_ID;
+
+ if (dict_find(what, (char_u *)"items", -1) != NULL)
+ flags |= QF_GETLIST_ITEMS;
+
+ if (dict_find(what, (char_u *)"idx", -1) != NULL)
+ flags |= QF_GETLIST_IDX;
+
+ if (dict_find(what, (char_u *)"size", -1) != NULL)
+ flags |= QF_GETLIST_SIZE;
+
+ if (dict_find(what, (char_u *)"changedtick", -1) != NULL)
+ flags |= QF_GETLIST_TICK;
+
+ if (loclist && dict_find(what, (char_u *)"filewinid", -1) != NULL)
+ flags |= QF_GETLIST_FILEWINID;
+
+ return flags;
+}
+
+/*
+ * Return the quickfix list index based on 'nr' or 'id' in 'what'.
+ * If 'nr' and 'id' are not present in 'what' then return the current
+ * quickfix list index.
+ * If 'nr' is zero then return the current quickfix list index.
+ * If 'nr' is '$' then return the last quickfix list index.
+ * If 'id' is present then return the index of the quickfix list with that id.
+ * If 'id' is zero then return the quickfix list index specified by 'nr'.
+ * Return -1, if quickfix list is not present or if the stack is empty.
+ */
+ static int
+qf_getprop_qfidx(qf_info_T *qi, dict_T *what)
+{
+ int qf_idx;
+ dictitem_T *di;
+
+ qf_idx = qi->qf_curlist; // default is the current list
+ if ((di = dict_find(what, (char_u *)"nr", -1)) != NULL)
+ {
+ // Use the specified quickfix/location list
+ if (di->di_tv.v_type == VAR_NUMBER)
+ {
+ // for zero use the current list
+ if (di->di_tv.vval.v_number != 0)
+ {
+ qf_idx = di->di_tv.vval.v_number - 1;
+ if (qf_idx < 0 || qf_idx >= qi->qf_listcount)
+ qf_idx = INVALID_QFIDX;
+ }
+ }
+ else if (di->di_tv.v_type == VAR_STRING
+ && di->di_tv.vval.v_string != NULL
+ && STRCMP(di->di_tv.vval.v_string, "$") == 0)
+ // Get the last quickfix list number
+ qf_idx = qi->qf_listcount - 1;
+ else
+ qf_idx = INVALID_QFIDX;
+ }
+
+ if ((di = dict_find(what, (char_u *)"id", -1)) != NULL)
+ {
+ // Look for a list with the specified id
+ if (di->di_tv.v_type == VAR_NUMBER)
+ {
+ // For zero, use the current list or the list specified by 'nr'
+ if (di->di_tv.vval.v_number != 0)
+ qf_idx = qf_id2nr(qi, di->di_tv.vval.v_number);
+ }
+ else
+ qf_idx = INVALID_QFIDX;
+ }
+
+ return qf_idx;
+}
+
+/*
+ * Return default values for quickfix list properties in retdict.
+ */
+ static int
+qf_getprop_defaults(qf_info_T *qi, int flags, int locstack, dict_T *retdict)
+{
+ int status = OK;
+
+ if (flags & QF_GETLIST_TITLE)
+ status = dict_add_string(retdict, "title", (char_u *)"");
+ if ((status == OK) && (flags & QF_GETLIST_ITEMS))
+ {
+ list_T *l = list_alloc();
+ if (l != NULL)
+ status = dict_add_list(retdict, "items", l);
+ else
+ status = FAIL;
+ }
+ if ((status == OK) && (flags & QF_GETLIST_NR))
+ status = dict_add_number(retdict, "nr", 0);
+ if ((status == OK) && (flags & QF_GETLIST_WINID))
+ status = dict_add_number(retdict, "winid", qf_winid(qi));
+ if ((status == OK) && (flags & QF_GETLIST_CONTEXT))
+ status = dict_add_string(retdict, "context", (char_u *)"");
+ if ((status == OK) && (flags & QF_GETLIST_ID))
+ status = dict_add_number(retdict, "id", 0);
+ if ((status == OK) && (flags & QF_GETLIST_IDX))
+ status = dict_add_number(retdict, "idx", 0);
+ if ((status == OK) && (flags & QF_GETLIST_SIZE))
+ status = dict_add_number(retdict, "size", 0);
+ if ((status == OK) && (flags & QF_GETLIST_TICK))
+ status = dict_add_number(retdict, "changedtick", 0);
+ if ((status == OK) && locstack && (flags & QF_GETLIST_FILEWINID))
+ status = dict_add_number(retdict, "filewinid", 0);
+
+ return status;
+}
+
+/*
+ * Return the quickfix list title as 'title' in retdict
+ */
+ static int
+qf_getprop_title(qf_list_T *qfl, dict_T *retdict)
+{
+ return dict_add_string(retdict, "title", qfl->qf_title);
+}
+
+/*
+ * Returns the identifier of the window used to display files from a location
+ * list. If there is no associated window, then returns 0. Useful only when
+ * called from a location list window.
+ */
+ static int
+qf_getprop_filewinid(win_T *wp, qf_info_T *qi, dict_T *retdict)
+{
+ int winid = 0;
+
+ if (wp != NULL && IS_LL_WINDOW(wp))
+ {
+ win_T *ll_wp = qf_find_win_with_loclist(qi);
+ if (ll_wp != NULL)
+ winid = ll_wp->w_id;
+ }
+
+ return dict_add_number(retdict, "filewinid", winid);
+}
+
+/*
+ * Return the quickfix list items/entries as 'items' in retdict
+ */
+ static int
+qf_getprop_items(qf_info_T *qi, int qf_idx, dict_T *retdict)
+{
+ int status = OK;
+ list_T *l = list_alloc();
+ if (l != NULL)
+ {
+ (void)get_errorlist(qi, NULL, qf_idx, l);
+ dict_add_list(retdict, "items", l);
+ }
+ else
+ status = FAIL;
+
+ return status;
+}
+
+/*
+ * Return the quickfix list context (if any) as 'context' in retdict.
+ */
+ static int
+qf_getprop_ctx(qf_list_T *qfl, dict_T *retdict)
+{
+ int status;
+ dictitem_T *di;
+
+ if (qfl->qf_ctx != NULL)
+ {
+ di = dictitem_alloc((char_u *)"context");
+ if (di != NULL)
+ {
+ copy_tv(qfl->qf_ctx, &di->di_tv);
+ status = dict_add(retdict, di);
+ if (status == FAIL)
+ dictitem_free(di);
+ }
+ else
+ status = FAIL;
+ }
+ else
+ status = dict_add_string(retdict, "context", (char_u *)"");
+
+ return status;
+}
+
+/*
+ * Return the current quickfix list index as 'idx' in retdict
+ */
+ static int
+qf_getprop_idx(qf_info_T *qi, int qf_idx, dict_T *retdict)
+{
+ int curidx = qi->qf_lists[qf_idx].qf_index;
+ if (qf_list_empty(qi, qf_idx))
+ // For empty lists, current index is set to 0
+ curidx = 0;
+ return dict_add_number(retdict, "idx", curidx);
+}
+
+/*
+ * Return quickfix/location list details (title) as a
+ * dictionary. 'what' contains the details to return. If 'list_idx' is -1,
+ * then current list is used. Otherwise the specified list is used.
+ */
+ int
+qf_get_properties(win_T *wp, dict_T *what, dict_T *retdict)
+{
+ qf_info_T *qi = &ql_info;
+ qf_list_T *qfl;
+ int status = OK;
+ int qf_idx = INVALID_QFIDX;
+ dictitem_T *di;
+ int flags = QF_GETLIST_NONE;
+
+ if ((di = dict_find(what, (char_u *)"lines", -1)) != NULL)
+ return qf_get_list_from_lines(what, di, retdict);
+
+ if (wp != NULL)
+ qi = GET_LOC_LIST(wp);
+
+ flags = qf_getprop_keys2flags(what, (wp != NULL));
+
+ if (!qf_stack_empty(qi))
+ qf_idx = qf_getprop_qfidx(qi, what);
+
+ // List is not present or is empty
+ if (qf_stack_empty(qi) || qf_idx == INVALID_QFIDX)
+ return qf_getprop_defaults(qi, flags, wp != NULL, retdict);
+
+ qfl = &qi->qf_lists[qf_idx];
+
+ if (flags & QF_GETLIST_TITLE)
+ status = qf_getprop_title(qfl, retdict);
+ if ((status == OK) && (flags & QF_GETLIST_NR))
+ status = dict_add_number(retdict, "nr", qf_idx + 1);
+ if ((status == OK) && (flags & QF_GETLIST_WINID))
+ status = dict_add_number(retdict, "winid", qf_winid(qi));
+ if ((status == OK) && (flags & QF_GETLIST_ITEMS))
+ status = qf_getprop_items(qi, qf_idx, retdict);
+ if ((status == OK) && (flags & QF_GETLIST_CONTEXT))
+ status = qf_getprop_ctx(qfl, retdict);
+ if ((status == OK) && (flags & QF_GETLIST_ID))
+ status = dict_add_number(retdict, "id", qfl->qf_id);
+ if ((status == OK) && (flags & QF_GETLIST_IDX))
+ status = qf_getprop_idx(qi, qf_idx, retdict);
+ if ((status == OK) && (flags & QF_GETLIST_SIZE))
+ status = dict_add_number(retdict, "size", qfl->qf_count);
+ if ((status == OK) && (flags & QF_GETLIST_TICK))
+ status = dict_add_number(retdict, "changedtick", qfl->qf_changedtick);
+ if ((status == OK) && (wp != NULL) && (flags & QF_GETLIST_FILEWINID))
+ status = qf_getprop_filewinid(wp, qi, retdict);
+
+ return status;
+}
+
+/*
+ * Add a new quickfix entry to list at 'qf_idx' in the stack 'qi' from the
+ * items in the dict 'd'. If it is a valid error entry, then set 'valid_entry'
+ * to TRUE.
+ */
+ static int
+qf_add_entry_from_dict(
+ qf_info_T *qi,
+ int qf_idx,
+ dict_T *d,
+ int first_entry,
+ int *valid_entry)
+{
+ static int did_bufnr_emsg;
+ char_u *filename, *module, *pattern, *text, *type;
+ int bufnum, valid, status, col, vcol, nr;
+ long lnum;
+
+ if (first_entry)
+ did_bufnr_emsg = FALSE;
+
+ filename = dict_get_string(d, (char_u *)"filename", TRUE);
+ module = dict_get_string(d, (char_u *)"module", TRUE);
+ bufnum = (int)dict_get_number(d, (char_u *)"bufnr");
+ lnum = (int)dict_get_number(d, (char_u *)"lnum");
+ col = (int)dict_get_number(d, (char_u *)"col");
+ vcol = (int)dict_get_number(d, (char_u *)"vcol");
+ nr = (int)dict_get_number(d, (char_u *)"nr");
+ type = dict_get_string(d, (char_u *)"type", TRUE);
+ pattern = dict_get_string(d, (char_u *)"pattern", TRUE);
+ text = dict_get_string(d, (char_u *)"text", TRUE);
+ if (text == NULL)
+ text = vim_strsave((char_u *)"");
+
+ valid = TRUE;
+ if ((filename == NULL && bufnum == 0) || (lnum == 0 && pattern == NULL))
+ valid = FALSE;
+
+ // Mark entries with non-existing buffer number as not valid. Give the
+ // error message only once.
+ if (bufnum != 0 && (buflist_findnr(bufnum) == NULL))
+ {
+ if (!did_bufnr_emsg)
+ {
+ did_bufnr_emsg = TRUE;
+ semsg(_("E92: Buffer %d not found"), bufnum);
+ }
+ valid = FALSE;
+ bufnum = 0;
+ }
+
+ // If the 'valid' field is present it overrules the detected value.
+ if ((dict_find(d, (char_u *)"valid", -1)) != NULL)
+ valid = (int)dict_get_number(d, (char_u *)"valid");
+
+ status = qf_add_entry(qi,
+ qf_idx,
+ NULL, // dir
+ filename,
+ module,
+ bufnum,
+ text,
+ lnum,
+ col,
+ vcol, // vis_col
+ pattern, // search pattern
+ nr,
+ type == NULL ? NUL : *type,
+ valid);
+
+ vim_free(filename);
+ vim_free(module);
+ vim_free(pattern);
+ vim_free(text);
+ vim_free(type);
+
+ if (valid)
+ *valid_entry = TRUE;
+
+ return status;
+}
+
+/*
+ * Add list of entries to quickfix/location list. Each list entry is
+ * a dictionary with item information.
+ */
+ static int
+qf_add_entries(
+ qf_info_T *qi,
+ int qf_idx,
+ list_T *list,
+ char_u *title,
+ int action)
+{
+ qf_list_T *qfl = &qi->qf_lists[qf_idx];
+ listitem_T *li;
+ dict_T *d;
+ qfline_T *old_last = NULL;
+ int retval = OK;
+ int valid_entry = FALSE;
+
+ if (action == ' ' || qf_idx == qi->qf_listcount)
+ {
+ // make place for a new list
+ qf_new_list(qi, title);
+ qf_idx = qi->qf_curlist;
+ qfl = &qi->qf_lists[qf_idx];
+ }
+ else if (action == 'a' && !qf_list_empty(qi, qf_idx))
+ // Adding to existing list, use last entry.
+ old_last = qfl->qf_last;
+ else if (action == 'r')
+ {
+ qf_free_items(qfl);
+ qf_store_title(qfl, title);
+ }
+
+ for (li = list->lv_first; li != NULL; li = li->li_next)
+ {
+ if (li->li_tv.v_type != VAR_DICT)
+ continue; // Skip non-dict items
+
+ d = li->li_tv.vval.v_dict;
+ if (d == NULL)
+ continue;
+
+ retval = qf_add_entry_from_dict(qi, qf_idx, d, li == list->lv_first,
+ &valid_entry);
+ if (retval == FAIL)
+ break;
+ }
+
+ // Check if any valid error entries are added to the list.
+ if (valid_entry)
+ qfl->qf_nonevalid = FALSE;
+ else if (qfl->qf_index == 0)
+ // no valid entry
+ qfl->qf_nonevalid = TRUE;
+
+ // If not appending to the list, set the current error to the first entry
+ if (action != 'a')
+ qfl->qf_ptr = qfl->qf_start;
+
+ // Update the current error index if not appending to the list or if the
+ // list was empty before and it is not empty now.
+ if ((action != 'a' || qfl->qf_index == 0) && !qf_list_empty(qi, qf_idx))
+ qfl->qf_index = 1;
+
+ // Don't update the cursor in quickfix window when appending entries
+ qf_update_buffer(qi, old_last);
+
+ return retval;
+}
+
+/*
+ * Get the quickfix list index from 'nr' or 'id'
+ */
+ static int
+qf_setprop_get_qfidx(
+ qf_info_T *qi,
+ dict_T *what,
+ int action,
+ int *newlist)
+{
+ dictitem_T *di;
+ int qf_idx = qi->qf_curlist; // default is the current list
+
+ if ((di = dict_find(what, (char_u *)"nr", -1)) != NULL)
+ {
+ // Use the specified quickfix/location list
+ if (di->di_tv.v_type == VAR_NUMBER)
+ {
+ // for zero use the current list
+ if (di->di_tv.vval.v_number != 0)
+ qf_idx = di->di_tv.vval.v_number - 1;
+
+ if ((action == ' ' || action == 'a') && qf_idx == qi->qf_listcount)
+ {
+ // When creating a new list, accept qf_idx pointing to the next
+ // non-available list and add the new list at the end of the
+ // stack.
+ *newlist = TRUE;
+ qf_idx = qf_stack_empty(qi) ? 0 : qi->qf_listcount - 1;
+ }
+ else if (qf_idx < 0 || qf_idx >= qi->qf_listcount)
+ return INVALID_QFIDX;
+ else if (action != ' ')
+ *newlist = FALSE; // use the specified list
+ }
+ else if (di->di_tv.v_type == VAR_STRING
+ && di->di_tv.vval.v_string != NULL
+ && STRCMP(di->di_tv.vval.v_string, "$") == 0)
+ {
+ if (!qf_stack_empty(qi))
+ qf_idx = qi->qf_listcount - 1;
+ else if (*newlist)
+ qf_idx = 0;
+ else
+ return INVALID_QFIDX;
+ }
+ else
+ return INVALID_QFIDX;
+ }
+
+ if (!*newlist && (di = dict_find(what, (char_u *)"id", -1)) != NULL)
+ {
+ // Use the quickfix/location list with the specified id
+ if (di->di_tv.v_type != VAR_NUMBER)
+ return INVALID_QFIDX;
+
+ return qf_id2nr(qi, di->di_tv.vval.v_number);
+ }
+
+ return qf_idx;
+}
+
+/*
+ * Set the quickfix list title.
+ */
+ static int
+qf_setprop_title(qf_info_T *qi, int qf_idx, dict_T *what, dictitem_T *di)
+{
+ qf_list_T *qfl = &qi->qf_lists[qf_idx];
+
+ if (di->di_tv.v_type != VAR_STRING)
+ return FAIL;
+
+ vim_free(qfl->qf_title);
+ qfl->qf_title = dict_get_string(what, (char_u *)"title", TRUE);
+ if (qf_idx == qi->qf_curlist)
+ qf_update_win_titlevar(qi);
+
+ return OK;
+}
+
+/*
+ * Set quickfix list items/entries.
+ */
+ static int
+qf_setprop_items(qf_info_T *qi, int qf_idx, dictitem_T *di, int action)
+{
+ int retval = FAIL;
+ char_u *title_save;
+
+ if (di->di_tv.v_type != VAR_LIST)
+ return FAIL;
+
+ title_save = vim_strsave(qi->qf_lists[qf_idx].qf_title);
+ retval = qf_add_entries(qi, qf_idx, di->di_tv.vval.v_list,
+ title_save, action == ' ' ? 'a' : action);
+ vim_free(title_save);
+
+ return retval;
+}
+
+/*
+ * Set quickfix list items/entries from a list of lines.
+ */
+ static int
+qf_setprop_items_from_lines(
+ qf_info_T *qi,
+ int qf_idx,
+ dict_T *what,
+ dictitem_T *di,
+ int action)
+{
+ char_u *errorformat = p_efm;
+ dictitem_T *efm_di;
+ int retval = FAIL;
+
+ // Use the user supplied errorformat settings (if present)
+ if ((efm_di = dict_find(what, (char_u *)"efm", -1)) != NULL)
+ {
+ if (efm_di->di_tv.v_type != VAR_STRING ||
+ efm_di->di_tv.vval.v_string == NULL)
+ return FAIL;
+ errorformat = efm_di->di_tv.vval.v_string;
+ }
+
+ // Only a List value is supported
+ if (di->di_tv.v_type != VAR_LIST || di->di_tv.vval.v_list == NULL)
+ return FAIL;
+
+ if (action == 'r')
+ qf_free_items(&qi->qf_lists[qf_idx]);
+ if (qf_init_ext(qi, qf_idx, NULL, NULL, &di->di_tv, errorformat,
+ FALSE, (linenr_T)0, (linenr_T)0, NULL, NULL) > 0)
+ retval = OK;
+
+ return retval;
+}
+
+/*
+ * Set quickfix list context.
+ */
+ static int
+qf_setprop_context(qf_list_T *qfl, dictitem_T *di)
+{
+ typval_T *ctx;
+
+ free_tv(qfl->qf_ctx);
+ ctx = alloc_tv();
+ if (ctx != NULL)
+ copy_tv(&di->di_tv, ctx);
+ qfl->qf_ctx = ctx;
+
+ return OK;
+}
+
+/*
+ * Set the current index in the specified quickfix list
+ */
+ static int
+qf_setprop_curidx(qf_info_T *qi, qf_list_T *qfl, dictitem_T *di)
+{
+ int denote = FALSE;
+ int newidx;
+ int old_qfidx;
+ qfline_T *qf_ptr;
+
+ // If the specified index is '$', then use the last entry
+ if (di->di_tv.v_type == VAR_STRING
+ && di->di_tv.vval.v_string != NULL
+ && STRCMP(di->di_tv.vval.v_string, "$") == 0)
+ newidx = qfl->qf_count;
+ else
+ {
+ // Otherwise use the specified index
+ newidx = tv_get_number_chk(&di->di_tv, &denote);
+ if (denote)
+ return FAIL;
+ }
+
+ if (newidx < 1) // sanity check
+ return FAIL;
+ if (newidx > qfl->qf_count)
+ newidx = qfl->qf_count;
+
+ old_qfidx = qfl->qf_index;
+ qf_ptr = get_nth_entry(qfl, newidx, &newidx);
+ if (qf_ptr == NULL)
+ return FAIL;
+ qfl->qf_ptr = qf_ptr;
+ qfl->qf_index = newidx;
+
+ // If the current list is modified and it is displayed in the quickfix
+ // window, then Update it.
+ if (qi->qf_lists[qi->qf_curlist].qf_id == qfl->qf_id)
+ qf_win_pos_update(qi, old_qfidx);
+
+ return OK;
+}
+
+/*
+ * Set quickfix/location list properties (title, items, context).
+ * Also used to add items from parsing a list of lines.
+ * Used by the setqflist() and setloclist() Vim script functions.
+ */
+ static int
+qf_set_properties(qf_info_T *qi, dict_T *what, int action, char_u *title)
+{
+ dictitem_T *di;
+ int retval = FAIL;
+ int qf_idx;
+ int newlist = FALSE;
+ qf_list_T *qfl;
+
+ if (action == ' ' || qf_stack_empty(qi))
+ newlist = TRUE;
+
+ qf_idx = qf_setprop_get_qfidx(qi, what, action, &newlist);
+ if (qf_idx == INVALID_QFIDX) // List not found
+ return FAIL;
+
+ if (newlist)
+ {
+ qi->qf_curlist = qf_idx;
+ qf_new_list(qi, title);
+ qf_idx = qi->qf_curlist;
+ }
+
+ qfl = &qi->qf_lists[qf_idx];
+ if ((di = dict_find(what, (char_u *)"title", -1)) != NULL)
+ retval = qf_setprop_title(qi, qf_idx, what, di);
+ if ((di = dict_find(what, (char_u *)"items", -1)) != NULL)
+ retval = qf_setprop_items(qi, qf_idx, di, action);
+ if ((di = dict_find(what, (char_u *)"lines", -1)) != NULL)
+ retval = qf_setprop_items_from_lines(qi, qf_idx, what, di, action);
+ if ((di = dict_find(what, (char_u *)"context", -1)) != NULL)
+ retval = qf_setprop_context(qfl, di);
+ if ((di = dict_find(what, (char_u *)"idx", -1)) != NULL)
+ retval = qf_setprop_curidx(qi, qfl, di);
+
+ if (retval == OK)
+ qf_list_changed(qfl);
+
+ return retval;
+}
+
+/*
+ * Find the non-location list window with the specified location list stack in
+ * the current tabpage.
+ */
+ static win_T *
+find_win_with_ll(qf_info_T *qi)
+{
+ win_T *wp = NULL;
+
+ FOR_ALL_WINDOWS(wp)
+ if ((wp->w_llist == qi) && !bt_quickfix(wp->w_buffer))
+ return wp;
+
+ return NULL;
+}
+
+/*
+ * Free the entire quickfix/location list stack.
+ * If the quickfix/location list window is open, then clear it.
+ */
+ static void
+qf_free_stack(win_T *wp, qf_info_T *qi)
+{
+ win_T *qfwin = qf_find_win(qi);
+ win_T *llwin = NULL;
+ win_T *orig_wp = wp;
+
+ if (qfwin != NULL)
+ {
+ // If the quickfix/location list window is open, then clear it
+ if (qi->qf_curlist < qi->qf_listcount)
+ qf_free(&qi->qf_lists[qi->qf_curlist]);
+ qf_update_buffer(qi, NULL);
+ }
+
+ if (wp != NULL && IS_LL_WINDOW(wp))
+ {
+ // If in the location list window, then use the non-location list
+ // window with this location list (if present)
+ llwin = find_win_with_ll(qi);
+ if (llwin != NULL)
+ wp = llwin;
+ }
+
+ qf_free_all(wp);
+ if (wp == NULL)
+ {
+ // quickfix list
+ qi->qf_curlist = 0;
+ qi->qf_listcount = 0;
+ }
+ else if (IS_LL_WINDOW(orig_wp))
+ {
+ // If the location list window is open, then create a new empty
+ // location list
+ qf_info_T *new_ll = qf_alloc_stack(QFLT_LOCATION);
+
+ // first free the list reference in the location list window
+ ll_free_all(&orig_wp->w_llist_ref);
+
+ orig_wp->w_llist_ref = new_ll;
+ if (llwin != NULL)
+ {
+ llwin->w_llist = new_ll;
+ new_ll->qf_refcount++;
+ }
+ }
+}
+
+/*
+ * Populate the quickfix list with the items supplied in the list
+ * of dictionaries. "title" will be copied to w:quickfix_title.
+ * "action" is 'a' for add, 'r' for replace. Otherwise create a new list.
+ */
+ int
+set_errorlist(
+ win_T *wp,
+ list_T *list,
+ int action,
+ char_u *title,
+ dict_T *what)
+{
+ qf_info_T *qi = &ql_info;
+ int retval = OK;
+
+ if (wp != NULL)
+ {
+ qi = ll_get_or_alloc_list(wp);
+ if (qi == NULL)
+ return FAIL;
+ }
+
+ if (action == 'f')
+ {
+ // Free the entire quickfix or location list stack
+ qf_free_stack(wp, qi);
+ return OK;
+ }
+
+ incr_quickfix_busy();
+
+ if (what != NULL)
+ retval = qf_set_properties(qi, what, action, title);
+ else
+ {
+ retval = qf_add_entries(qi, qi->qf_curlist, list, title, action);
+ if (retval == OK)
+ qf_list_changed(&qi->qf_lists[qi->qf_curlist]);
+ }
+
+ decr_quickfix_busy();
+
+ return retval;
+}
+
+/*
+ * Mark the context as in use for all the lists in a quickfix stack.
+ */
+ static int
+mark_quickfix_ctx(qf_info_T *qi, int copyID)
+{
+ int i;
+ int abort = FALSE;
+ typval_T *ctx;
+
+ for (i = 0; i < LISTCOUNT && !abort; ++i)
+ {
+ ctx = qi->qf_lists[i].qf_ctx;
+ if (ctx != NULL && ctx->v_type != VAR_NUMBER
+ && ctx->v_type != VAR_STRING && ctx->v_type != VAR_FLOAT)
+ abort = set_ref_in_item(ctx, copyID, NULL, NULL);
+ }
+
+ return abort;
+}
+
+/*
+ * Mark the context of the quickfix list and the location lists (if present) as
+ * "in use". So that garbage collection doesn't free the context.
+ */
+ int
+set_ref_in_quickfix(int copyID)
+{
+ int abort = FALSE;
+ tabpage_T *tp;
+ win_T *win;
+
+ abort = mark_quickfix_ctx(&ql_info, copyID);
+ if (abort)
+ return abort;
+
+ FOR_ALL_TAB_WINDOWS(tp, win)
+ {
+ if (win->w_llist != NULL)
+ {
+ abort = mark_quickfix_ctx(win->w_llist, copyID);
+ if (abort)
+ return abort;
+ }
+ if (IS_LL_WINDOW(win) && (win->w_llist_ref->qf_refcount == 1))
+ {
+ // In a location list window and none of the other windows is
+ // referring to this location list. Mark the location list
+ // context as still in use.
+ abort = mark_quickfix_ctx(win->w_llist_ref, copyID);
+ if (abort)
+ return abort;
+ }
+ }
+
+ return abort;
+}
+#endif
+
+/*
+ * ":[range]cbuffer [bufnr]" command.
+ * ":[range]caddbuffer [bufnr]" command.
+ * ":[range]cgetbuffer [bufnr]" command.
+ * ":[range]lbuffer [bufnr]" command.
+ * ":[range]laddbuffer [bufnr]" command.
+ * ":[range]lgetbuffer [bufnr]" command.
+ */
+ void
+ex_cbuffer(exarg_T *eap)
+{
+ buf_T *buf = NULL;
+ qf_info_T *qi = &ql_info;
+ char_u *au_name = NULL;
+ int res;
+ int_u save_qfid;
+ win_T *wp = NULL;
+
+ switch (eap->cmdidx)
+ {
+ case CMD_cbuffer: au_name = (char_u *)"cbuffer"; break;
+ case CMD_cgetbuffer: au_name = (char_u *)"cgetbuffer"; break;
+ case CMD_caddbuffer: au_name = (char_u *)"caddbuffer"; break;
+ case CMD_lbuffer: au_name = (char_u *)"lbuffer"; break;
+ case CMD_lgetbuffer: au_name = (char_u *)"lgetbuffer"; break;
+ case CMD_laddbuffer: au_name = (char_u *)"laddbuffer"; break;
+ default: break;
+ }
+ if (au_name != NULL && apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name,
+ curbuf->b_fname, TRUE, curbuf))
+ {
+#ifdef FEAT_EVAL
+ if (aborting())
+ return;
+#endif
+ }
+
+ // Must come after autocommands.
+ if (is_loclist_cmd(eap->cmdidx))
+ {
+ qi = ll_get_or_alloc_list(curwin);
+ if (qi == NULL)
+ return;
+ wp = curwin;
+ }
+
+ if (*eap->arg == NUL)
+ buf = curbuf;
+ else if (*skipwhite(skipdigits(eap->arg)) == NUL)
+ buf = buflist_findnr(atoi((char *)eap->arg));
+ if (buf == NULL)
+ emsg(_(e_invarg));
+ else if (buf->b_ml.ml_mfp == NULL)
+ emsg(_("E681: Buffer is not loaded"));
+ else
+ {
+ if (eap->addr_count == 0)
+ {
+ eap->line1 = 1;
+ eap->line2 = buf->b_ml.ml_line_count;
+ }
+ if (eap->line1 < 1 || eap->line1 > buf->b_ml.ml_line_count
+ || eap->line2 < 1 || eap->line2 > buf->b_ml.ml_line_count)
+ emsg(_(e_invrange));
+ else
+ {
+ char_u *qf_title = qf_cmdtitle(*eap->cmdlinep);
+
+ if (buf->b_sfname)
+ {
+ vim_snprintf((char *)IObuff, IOSIZE, "%s (%s)",
+ (char *)qf_title, (char *)buf->b_sfname);
+ qf_title = IObuff;
+ }
+
+ incr_quickfix_busy();
+
+ res = qf_init_ext(qi, qi->qf_curlist, NULL, buf, NULL, p_efm,
+ (eap->cmdidx != CMD_caddbuffer
+ && eap->cmdidx != CMD_laddbuffer),
+ eap->line1, eap->line2,
+ qf_title, NULL);
+ if (qf_stack_empty(qi))
+ {
+ decr_quickfix_busy();
+ return;
+ }
+ if (res >= 0)
+ qf_list_changed(&qi->qf_lists[qi->qf_curlist]);
+
+ // Remember the current quickfix list identifier, so that we can
+ // check for autocommands changing the current quickfix list.
+ save_qfid = qi->qf_lists[qi->qf_curlist].qf_id;
+ if (au_name != NULL)
+ {
+ buf_T *curbuf_old = curbuf;
+
+ apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name,
+ curbuf->b_fname, TRUE, curbuf);
+ if (curbuf != curbuf_old)
+ // Autocommands changed buffer, don't jump now, "qi" may
+ // be invalid.
+ res = 0;
+ }
+ // Jump to the first error for a new list and if autocmds didn't
+ // free the list.
+ if (res > 0 && (eap->cmdidx == CMD_cbuffer ||
+ eap->cmdidx == CMD_lbuffer)
+ && qflist_valid(wp, save_qfid))
+ // display the first error
+ qf_jump_first(qi, save_qfid, eap->forceit);
+
+ decr_quickfix_busy();
+ }
+ }
+}
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * ":cexpr {expr}", ":cgetexpr {expr}", ":caddexpr {expr}" command.
+ * ":lexpr {expr}", ":lgetexpr {expr}", ":laddexpr {expr}" command.
+ */
+ void
+ex_cexpr(exarg_T *eap)
+{
+ typval_T *tv;
+ qf_info_T *qi = &ql_info;
+ char_u *au_name = NULL;
+ int res;
+ int_u save_qfid;
+ win_T *wp = NULL;
+
+ switch (eap->cmdidx)
+ {
+ case CMD_cexpr: au_name = (char_u *)"cexpr"; break;
+ case CMD_cgetexpr: au_name = (char_u *)"cgetexpr"; break;
+ case CMD_caddexpr: au_name = (char_u *)"caddexpr"; break;
+ case CMD_lexpr: au_name = (char_u *)"lexpr"; break;
+ case CMD_lgetexpr: au_name = (char_u *)"lgetexpr"; break;
+ case CMD_laddexpr: au_name = (char_u *)"laddexpr"; break;
+ default: break;
+ }
+ if (au_name != NULL && apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name,
+ curbuf->b_fname, TRUE, curbuf))
+ {
+#ifdef FEAT_EVAL
+ if (aborting())
+ return;
+#endif
+ }
+
+ if (is_loclist_cmd(eap->cmdidx))
+ {
+ qi = ll_get_or_alloc_list(curwin);
+ if (qi == NULL)
+ return;
+ wp = curwin;
+ }
+
+ // Evaluate the expression. When the result is a string or a list we can
+ // use it to fill the errorlist.
+ tv = eval_expr(eap->arg, NULL);
+ if (tv != NULL)
+ {
+ if ((tv->v_type == VAR_STRING && tv->vval.v_string != NULL)
+ || (tv->v_type == VAR_LIST && tv->vval.v_list != NULL))
+ {
+ incr_quickfix_busy();
+ res = qf_init_ext(qi, qi->qf_curlist, NULL, NULL, tv, p_efm,
+ (eap->cmdidx != CMD_caddexpr
+ && eap->cmdidx != CMD_laddexpr),
+ (linenr_T)0, (linenr_T)0,
+ qf_cmdtitle(*eap->cmdlinep), NULL);
+ if (qf_stack_empty(qi))
+ {
+ decr_quickfix_busy();
+ goto cleanup;
+ }
+ if (res >= 0)
+ qf_list_changed(&qi->qf_lists[qi->qf_curlist]);
+
+ // Remember the current quickfix list identifier, so that we can
+ // check for autocommands changing the current quickfix list.
+ save_qfid = qi->qf_lists[qi->qf_curlist].qf_id;
+ if (au_name != NULL)
+ apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name,
+ curbuf->b_fname, TRUE, curbuf);
+
+ // Jump to the first error for a new list and if autocmds didn't
+ // free the list.
+ if (res > 0 && (eap->cmdidx == CMD_cexpr
+ || eap->cmdidx == CMD_lexpr)
+ && qflist_valid(wp, save_qfid))
+ // display the first error
+ qf_jump_first(qi, save_qfid, eap->forceit);
+ decr_quickfix_busy();
+ }
+ else
+ emsg(_("E777: String or List expected"));
+cleanup:
+ free_tv(tv);
+ }
+}
+#endif
+
+/*
+ * Get the location list for ":lhelpgrep"
+ */
+ static qf_info_T *
+hgr_get_ll(int *new_ll)
+{
+ win_T *wp;
+ qf_info_T *qi;
+
+ // If the current window is a help window, then use it
+ if (bt_help(curwin->w_buffer))
+ wp = curwin;
+ else
+ // Find an existing help window
+ wp = qf_find_help_win();
+
+ if (wp == NULL) // Help window not found
+ qi = NULL;
+ else
+ qi = wp->w_llist;
+
+ if (qi == NULL)
+ {
+ // Allocate a new location list for help text matches
+ if ((qi = qf_alloc_stack(QFLT_LOCATION)) == NULL)
+ return NULL;
+ *new_ll = TRUE;
+ }
+
+ return qi;
+}
+
+/*
+ * Search for a pattern in a help file.
+ */
+ static void
+hgr_search_file(
+ qf_info_T *qi,
+ char_u *fname,
+ vimconv_T *p_vc,
+ regmatch_T *p_regmatch)
+{
+ FILE *fd;
+ long lnum;
+
+ fd = mch_fopen((char *)fname, "r");
+ if (fd == NULL)
+ return;
+
+ lnum = 1;
+ while (!vim_fgets(IObuff, IOSIZE, fd) && !got_int)
+ {
+ char_u *line = IObuff;
+
+ // Convert a line if 'encoding' is not utf-8 and
+ // the line contains a non-ASCII character.
+ if (p_vc->vc_type != CONV_NONE
+ && has_non_ascii(IObuff))
+ {
+ line = string_convert(p_vc, IObuff, NULL);
+ if (line == NULL)
+ line = IObuff;
+ }
+
+ if (vim_regexec(p_regmatch, line, (colnr_T)0))
+ {
+ int l = (int)STRLEN(line);
+
+ // remove trailing CR, LF, spaces, etc.
+ while (l > 0 && line[l - 1] <= ' ')
+ line[--l] = NUL;
+
+ if (qf_add_entry(qi,
+ qi->qf_curlist,
+ NULL, // dir
+ fname,
+ NULL,
+ 0,
+ line,
+ lnum,
+ (int)(p_regmatch->startp[0] - line)
+ + 1, // col
+ FALSE, // vis_col
+ NULL, // search pattern
+ 0, // nr
+ 1, // type
+ TRUE // valid
+ ) == FAIL)
+ {
+ got_int = TRUE;
+ if (line != IObuff)
+ vim_free(line);
+ break;
+ }
+ }
+ if (line != IObuff)
+ vim_free(line);
+ ++lnum;
+ line_breakcheck();
+ }
+ fclose(fd);
+}
+
+/*
+ * Search for a pattern in all the help files in the doc directory under
+ * the given directory.
+ */
+ static void
+hgr_search_files_in_dir(
+ qf_info_T *qi,
+ char_u *dirname,
+ regmatch_T *p_regmatch,
+ vimconv_T *p_vc
+#ifdef FEAT_MULTI_LANG
+ , char_u *lang
+#endif
+ )
+{
+ int fcount;
+ char_u **fnames;
+ int fi;
+
+ // Find all "*.txt" and "*.??x" files in the "doc" directory.
+ add_pathsep(dirname);
+ STRCAT(dirname, "doc/*.\\(txt\\|??x\\)");
+ if (gen_expand_wildcards(1, &dirname, &fcount,
+ &fnames, EW_FILE|EW_SILENT) == OK
+ && fcount > 0)
+ {
+ for (fi = 0; fi < fcount && !got_int; ++fi)
+ {
+#ifdef FEAT_MULTI_LANG
+ // Skip files for a different language.
+ if (lang != NULL
+ && STRNICMP(lang, fnames[fi]
+ + STRLEN(fnames[fi]) - 3, 2) != 0
+ && !(STRNICMP(lang, "en", 2) == 0
+ && STRNICMP("txt", fnames[fi]
+ + STRLEN(fnames[fi]) - 3, 3) == 0))
+ continue;
+#endif
+
+ hgr_search_file(qi, fnames[fi], p_vc, p_regmatch);
+ }
+ FreeWild(fcount, fnames);
+ }
+}
+
+/*
+ * Search for a pattern in all the help files in the 'runtimepath'
+ * and add the matches to a quickfix list.
+ * 'lang' is the language specifier. If supplied, then only matches in the
+ * specified language are found.
+ */
+ static void
+hgr_search_in_rtp(qf_info_T *qi, regmatch_T *p_regmatch, char_u *lang)
+{
+ char_u *p;
+
+ vimconv_T vc;
+
+ // Help files are in utf-8 or latin1, convert lines when 'encoding'
+ // differs.
+ vc.vc_type = CONV_NONE;
+ if (!enc_utf8)
+ convert_setup(&vc, (char_u *)"utf-8", p_enc);
+
+ // Go through all the directories in 'runtimepath'
+ p = p_rtp;
+ while (*p != NUL && !got_int)
+ {
+ copy_option_part(&p, NameBuff, MAXPATHL, ",");
+
+ hgr_search_files_in_dir(qi, NameBuff, p_regmatch, &vc
+#ifdef FEAT_MULTI_LANG
+ , lang
+#endif
+ );
+ }
+
+ if (vc.vc_type != CONV_NONE)
+ convert_setup(&vc, NULL, NULL);
+}
+
+/*
+ * ":helpgrep {pattern}"
+ */
+ void
+ex_helpgrep(exarg_T *eap)
+{
+ regmatch_T regmatch;
+ char_u *save_cpo;
+ qf_info_T *qi = &ql_info;
+ int new_qi = FALSE;
+ char_u *au_name = NULL;
+ char_u *lang = NULL;
+
+ switch (eap->cmdidx)
+ {
+ case CMD_helpgrep: au_name = (char_u *)"helpgrep"; break;
+ case CMD_lhelpgrep: au_name = (char_u *)"lhelpgrep"; break;
+ default: break;
+ }
+ if (au_name != NULL && apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name,
+ curbuf->b_fname, TRUE, curbuf))
+ {
+#ifdef FEAT_EVAL
+ if (aborting())
+ return;
+#endif
+ }
+
+ // Make 'cpoptions' empty, the 'l' flag should not be used here.
+ save_cpo = p_cpo;
+ p_cpo = empty_option;
+
+ if (is_loclist_cmd(eap->cmdidx))
+ {
+ qi = hgr_get_ll(&new_qi);
+ if (qi == NULL)
+ return;
+ }
+
+ incr_quickfix_busy();
+
+#ifdef FEAT_MULTI_LANG
+ // Check for a specified language
+ lang = check_help_lang(eap->arg);
+#endif
+ regmatch.regprog = vim_regcomp(eap->arg, RE_MAGIC + RE_STRING);
+ regmatch.rm_ic = FALSE;
+ if (regmatch.regprog != NULL)
+ {
+ qf_list_T *qfl;
+
+ // create a new quickfix list
+ qf_new_list(qi, qf_cmdtitle(*eap->cmdlinep));
+
+ hgr_search_in_rtp(qi, &regmatch, lang);
+
+ vim_regfree(regmatch.regprog);
+
+ qfl = &qi->qf_lists[qi->qf_curlist];
+ qfl->qf_nonevalid = FALSE;
+ qfl->qf_ptr = qfl->qf_start;
+ qfl->qf_index = 1;
+ qf_list_changed(qfl);
+ qf_update_buffer(qi, NULL);
+ }
+
+ if (p_cpo == empty_option)
+ p_cpo = save_cpo;
+ else
+ // Darn, some plugin changed the value.
+ free_string_option(save_cpo);
+
+ if (au_name != NULL)
+ {
+ apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name,
+ curbuf->b_fname, TRUE, curbuf);
+ if (!new_qi && IS_LL_STACK(qi) && qf_find_buf(qi) == NULL)
+ {
+ // autocommands made "qi" invalid
+ decr_quickfix_busy();
+ return;
+ }
+ }
+
+ // Jump to first match.
+ if (!qf_list_empty(qi, qi->qf_curlist))
+ qf_jump(qi, 0, 0, FALSE);
+ else
+ semsg(_(e_nomatch2), eap->arg);
+
+ decr_quickfix_busy();
+
+ if (eap->cmdidx == CMD_lhelpgrep)
+ {
+ // If the help window is not opened or if it already points to the
+ // correct location list, then free the new location list.
+ if (!bt_help(curwin->w_buffer) || curwin->w_llist == qi)
+ {
+ if (new_qi)
+ ll_free_all(&qi);
+ }
+ else if (curwin->w_llist == NULL)
+ curwin->w_llist = qi;
+ }
+}
+
+#endif /* FEAT_QUICKFIX */
diff --git a/src/regexp.c b/src/regexp.c
new file mode 100644
index 0000000..9e6cf70
--- /dev/null
+++ b/src/regexp.c
@@ -0,0 +1,8291 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * Handling of regular expressions: vim_regcomp(), vim_regexec(), vim_regsub()
+ *
+ * NOTICE:
+ *
+ * This is NOT the original regular expression code as written by Henry
+ * Spencer. This code has been modified specifically for use with the VIM
+ * editor, and should not be used separately from Vim. If you want a good
+ * regular expression library, get the original code. The copyright notice
+ * that follows is from the original.
+ *
+ * END NOTICE
+ *
+ * Copyright (c) 1986 by University of Toronto.
+ * Written by Henry Spencer. Not derived from licensed software.
+ *
+ * Permission is granted to anyone to use this software for any
+ * purpose on any computer system, and to redistribute it freely,
+ * subject to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of
+ * this software, no matter how awful, even if they arise
+ * from defects in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either
+ * by explicit claim or by omission.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not
+ * be misrepresented as being the original software.
+ *
+ * Beware that some of this code is subtly aware of the way operator
+ * precedence is structured in regular expressions. Serious changes in
+ * regular-expression syntax might require a total rethink.
+ *
+ * Changes have been made by Tony Andrews, Olaf 'Rhialto' Seibert, Robert
+ * Webb, Ciaran McCreesh and Bram Moolenaar.
+ * Named character class support added by Walter Briscoe (1998 Jul 01)
+ */
+
+/* Uncomment the first if you do not want to see debugging logs or files
+ * related to regular expressions, even when compiling with -DDEBUG.
+ * Uncomment the second to get the regexp debugging. */
+/* #undef DEBUG */
+/* #define DEBUG */
+
+#include "vim.h"
+
+#ifdef DEBUG
+/* show/save debugging data when BT engine is used */
+# define BT_REGEXP_DUMP
+/* save the debugging data to a file instead of displaying it */
+# define BT_REGEXP_LOG
+# define BT_REGEXP_DEBUG_LOG
+# define BT_REGEXP_DEBUG_LOG_NAME "bt_regexp_debug.log"
+#endif
+
+/*
+ * The "internal use only" fields in regexp.h are present to pass info from
+ * compile to execute that permits the execute phase to run lots faster on
+ * simple cases. They are:
+ *
+ * regstart char that must begin a match; NUL if none obvious; Can be a
+ * multi-byte character.
+ * reganch is the match anchored (at beginning-of-line only)?
+ * regmust string (pointer into program) that match must include, or NULL
+ * regmlen length of regmust string
+ * regflags RF_ values or'ed together
+ *
+ * Regstart and reganch permit very fast decisions on suitable starting points
+ * for a match, cutting down the work a lot. Regmust permits fast rejection
+ * of lines that cannot possibly match. The regmust tests are costly enough
+ * that vim_regcomp() supplies a regmust only if the r.e. contains something
+ * potentially expensive (at present, the only such thing detected is * or +
+ * at the start of the r.e., which can involve a lot of backup). Regmlen is
+ * supplied because the test in vim_regexec() needs it and vim_regcomp() is
+ * computing it anyway.
+ */
+
+/*
+ * Structure for regexp "program". This is essentially a linear encoding
+ * of a nondeterministic finite-state machine (aka syntax charts or
+ * "railroad normal form" in parsing technology). Each node is an opcode
+ * plus a "next" pointer, possibly plus an operand. "Next" pointers of
+ * all nodes except BRANCH and BRACES_COMPLEX implement concatenation; a "next"
+ * pointer with a BRANCH on both ends of it is connecting two alternatives.
+ * (Here we have one of the subtle syntax dependencies: an individual BRANCH
+ * (as opposed to a collection of them) is never concatenated with anything
+ * because of operator precedence). The "next" pointer of a BRACES_COMPLEX
+ * node points to the node after the stuff to be repeated.
+ * The operand of some types of node is a literal string; for others, it is a
+ * node leading into a sub-FSM. In particular, the operand of a BRANCH node
+ * is the first node of the branch.
+ * (NB this is *not* a tree structure: the tail of the branch connects to the
+ * thing following the set of BRANCHes.)
+ *
+ * pattern is coded like:
+ *
+ * +-----------------+
+ * | V
+ * <aa>\|<bb> BRANCH <aa> BRANCH <bb> --> END
+ * | ^ | ^
+ * +------+ +----------+
+ *
+ *
+ * +------------------+
+ * V |
+ * <aa>* BRANCH BRANCH <aa> --> BACK BRANCH --> NOTHING --> END
+ * | | ^ ^
+ * | +---------------+ |
+ * +---------------------------------------------+
+ *
+ *
+ * +----------------------+
+ * V |
+ * <aa>\+ BRANCH <aa> --> BRANCH --> BACK BRANCH --> NOTHING --> END
+ * | | ^ ^
+ * | +-----------+ |
+ * +--------------------------------------------------+
+ *
+ *
+ * +-------------------------+
+ * V |
+ * <aa>\{} BRANCH BRACE_LIMITS --> BRACE_COMPLEX <aa> --> BACK END
+ * | | ^
+ * | +----------------+
+ * +-----------------------------------------------+
+ *
+ *
+ * <aa>\@!<bb> BRANCH NOMATCH <aa> --> END <bb> --> END
+ * | | ^ ^
+ * | +----------------+ |
+ * +--------------------------------+
+ *
+ * +---------+
+ * | V
+ * \z[abc] BRANCH BRANCH a BRANCH b BRANCH c BRANCH NOTHING --> END
+ * | | | | ^ ^
+ * | | | +-----+ |
+ * | | +----------------+ |
+ * | +---------------------------+ |
+ * +------------------------------------------------------+
+ *
+ * They all start with a BRANCH for "\|" alternatives, even when there is only
+ * one alternative.
+ */
+
+/*
+ * The opcodes are:
+ */
+
+/* definition number opnd? meaning */
+#define END 0 /* End of program or NOMATCH operand. */
+#define BOL 1 /* Match "" at beginning of line. */
+#define EOL 2 /* Match "" at end of line. */
+#define BRANCH 3 /* node Match this alternative, or the
+ * next... */
+#define BACK 4 /* Match "", "next" ptr points backward. */
+#define EXACTLY 5 /* str Match this string. */
+#define NOTHING 6 /* Match empty string. */
+#define STAR 7 /* node Match this (simple) thing 0 or more
+ * times. */
+#define PLUS 8 /* node Match this (simple) thing 1 or more
+ * times. */
+#define MATCH 9 /* node match the operand zero-width */
+#define NOMATCH 10 /* node check for no match with operand */
+#define BEHIND 11 /* node look behind for a match with operand */
+#define NOBEHIND 12 /* node look behind for no match with operand */
+#define SUBPAT 13 /* node match the operand here */
+#define BRACE_SIMPLE 14 /* node Match this (simple) thing between m and
+ * n times (\{m,n\}). */
+#define BOW 15 /* Match "" after [^a-zA-Z0-9_] */
+#define EOW 16 /* Match "" at [^a-zA-Z0-9_] */
+#define BRACE_LIMITS 17 /* nr nr define the min & max for BRACE_SIMPLE
+ * and BRACE_COMPLEX. */
+#define NEWL 18 /* Match line-break */
+#define BHPOS 19 /* End position for BEHIND or NOBEHIND */
+
+
+/* character classes: 20-48 normal, 50-78 include a line-break */
+#define ADD_NL 30
+#define FIRST_NL ANY + ADD_NL
+#define ANY 20 /* Match any one character. */
+#define ANYOF 21 /* str Match any character in this string. */
+#define ANYBUT 22 /* str Match any character not in this
+ * string. */
+#define IDENT 23 /* Match identifier char */
+#define SIDENT 24 /* Match identifier char but no digit */
+#define KWORD 25 /* Match keyword char */
+#define SKWORD 26 /* Match word char but no digit */
+#define FNAME 27 /* Match file name char */
+#define SFNAME 28 /* Match file name char but no digit */
+#define PRINT 29 /* Match printable char */
+#define SPRINT 30 /* Match printable char but no digit */
+#define WHITE 31 /* Match whitespace char */
+#define NWHITE 32 /* Match non-whitespace char */
+#define DIGIT 33 /* Match digit char */
+#define NDIGIT 34 /* Match non-digit char */
+#define HEX 35 /* Match hex char */
+#define NHEX 36 /* Match non-hex char */
+#define OCTAL 37 /* Match octal char */
+#define NOCTAL 38 /* Match non-octal char */
+#define WORD 39 /* Match word char */
+#define NWORD 40 /* Match non-word char */
+#define HEAD 41 /* Match head char */
+#define NHEAD 42 /* Match non-head char */
+#define ALPHA 43 /* Match alpha char */
+#define NALPHA 44 /* Match non-alpha char */
+#define LOWER 45 /* Match lowercase char */
+#define NLOWER 46 /* Match non-lowercase char */
+#define UPPER 47 /* Match uppercase char */
+#define NUPPER 48 /* Match non-uppercase char */
+#define LAST_NL NUPPER + ADD_NL
+#define WITH_NL(op) ((op) >= FIRST_NL && (op) <= LAST_NL)
+
+#define MOPEN 80 /* -89 Mark this point in input as start of
+ * \( subexpr. MOPEN + 0 marks start of
+ * match. */
+#define MCLOSE 90 /* -99 Analogous to MOPEN. MCLOSE + 0 marks
+ * end of match. */
+#define BACKREF 100 /* -109 node Match same string again \1-\9 */
+
+#ifdef FEAT_SYN_HL
+# define ZOPEN 110 /* -119 Mark this point in input as start of
+ * \z( subexpr. */
+# define ZCLOSE 120 /* -129 Analogous to ZOPEN. */
+# define ZREF 130 /* -139 node Match external submatch \z1-\z9 */
+#endif
+
+#define BRACE_COMPLEX 140 /* -149 node Match nodes between m & n times */
+
+#define NOPEN 150 /* Mark this point in input as start of
+ \%( subexpr. */
+#define NCLOSE 151 /* Analogous to NOPEN. */
+
+#define MULTIBYTECODE 200 /* mbc Match one multi-byte character */
+#define RE_BOF 201 /* Match "" at beginning of file. */
+#define RE_EOF 202 /* Match "" at end of file. */
+#define CURSOR 203 /* Match location of cursor. */
+
+#define RE_LNUM 204 /* nr cmp Match line number */
+#define RE_COL 205 /* nr cmp Match column number */
+#define RE_VCOL 206 /* nr cmp Match virtual column number */
+
+#define RE_MARK 207 /* mark cmp Match mark position */
+#define RE_VISUAL 208 /* Match Visual area */
+#define RE_COMPOSING 209 /* any composing characters */
+
+/*
+ * Magic characters have a special meaning, they don't match literally.
+ * Magic characters are negative. This separates them from literal characters
+ * (possibly multi-byte). Only ASCII characters can be Magic.
+ */
+#define Magic(x) ((int)(x) - 256)
+#define un_Magic(x) ((x) + 256)
+#define is_Magic(x) ((x) < 0)
+
+ static int
+no_Magic(int x)
+{
+ if (is_Magic(x))
+ return un_Magic(x);
+ return x;
+}
+
+ static int
+toggle_Magic(int x)
+{
+ if (is_Magic(x))
+ return un_Magic(x);
+ return Magic(x);
+}
+
+/*
+ * The first byte of the regexp internal "program" is actually this magic
+ * number; the start node begins in the second byte. It's used to catch the
+ * most severe mutilation of the program by the caller.
+ */
+
+#define REGMAGIC 0234
+
+/*
+ * Opcode notes:
+ *
+ * BRANCH The set of branches constituting a single choice are hooked
+ * together with their "next" pointers, since precedence prevents
+ * anything being concatenated to any individual branch. The
+ * "next" pointer of the last BRANCH in a choice points to the
+ * thing following the whole choice. This is also where the
+ * final "next" pointer of each individual branch points; each
+ * branch starts with the operand node of a BRANCH node.
+ *
+ * BACK Normal "next" pointers all implicitly point forward; BACK
+ * exists to make loop structures possible.
+ *
+ * STAR,PLUS '=', and complex '*' and '+', are implemented as circular
+ * BRANCH structures using BACK. Simple cases (one character
+ * per match) are implemented with STAR and PLUS for speed
+ * and to minimize recursive plunges.
+ *
+ * BRACE_LIMITS This is always followed by a BRACE_SIMPLE or BRACE_COMPLEX
+ * node, and defines the min and max limits to be used for that
+ * node.
+ *
+ * MOPEN,MCLOSE ...are numbered at compile time.
+ * ZOPEN,ZCLOSE ...ditto
+ */
+
+/*
+ * A node is one char of opcode followed by two chars of "next" pointer.
+ * "Next" pointers are stored as two 8-bit bytes, high order first. The
+ * value is a positive offset from the opcode of the node containing it.
+ * An operand, if any, simply follows the node. (Note that much of the
+ * code generation knows about this implicit relationship.)
+ *
+ * Using two bytes for the "next" pointer is vast overkill for most things,
+ * but allows patterns to get big without disasters.
+ */
+#define OP(p) ((int)*(p))
+#define NEXT(p) (((*((p) + 1) & 0377) << 8) + (*((p) + 2) & 0377))
+#define OPERAND(p) ((p) + 3)
+/* Obtain an operand that was stored as four bytes, MSB first. */
+#define OPERAND_MIN(p) (((long)(p)[3] << 24) + ((long)(p)[4] << 16) \
+ + ((long)(p)[5] << 8) + (long)(p)[6])
+/* Obtain a second operand stored as four bytes. */
+#define OPERAND_MAX(p) OPERAND_MIN((p) + 4)
+/* Obtain a second single-byte operand stored after a four bytes operand. */
+#define OPERAND_CMP(p) (p)[7]
+
+/*
+ * Utility definitions.
+ */
+#define UCHARAT(p) ((int)*(char_u *)(p))
+
+/* Used for an error (down from) vim_regcomp(): give the error message, set
+ * rc_did_emsg and return NULL */
+#define EMSG_RET_NULL(m) return (emsg((m)), rc_did_emsg = TRUE, (void *)NULL)
+#define IEMSG_RET_NULL(m) return (iemsg((m)), rc_did_emsg = TRUE, (void *)NULL)
+#define EMSG_RET_FAIL(m) return (emsg((m)), rc_did_emsg = TRUE, FAIL)
+#define EMSG2_RET_NULL(m, c) return (semsg((const char *)(m), (c) ? "" : "\\"), rc_did_emsg = TRUE, (void *)NULL)
+#define EMSG3_RET_NULL(m, c, a) return (semsg((const char *)(m), (c) ? "" : "\\", (a)), rc_did_emsg = TRUE, (void *)NULL)
+#define EMSG2_RET_FAIL(m, c) return (semsg((const char *)(m), (c) ? "" : "\\"), rc_did_emsg = TRUE, FAIL)
+#define EMSG_ONE_RET_NULL EMSG2_RET_NULL(_("E369: invalid item in %s%%[]"), reg_magic == MAGIC_ALL)
+
+
+#define MAX_LIMIT (32767L << 16L)
+
+static int cstrncmp(char_u *s1, char_u *s2, int *n);
+static char_u *cstrchr(char_u *, int);
+
+#ifdef BT_REGEXP_DUMP
+static void regdump(char_u *, bt_regprog_T *);
+#endif
+#ifdef DEBUG
+static char_u *regprop(char_u *);
+#endif
+
+static int re_mult_next(char *what);
+
+static char_u e_missingbracket[] = N_("E769: Missing ] after %s[");
+static char_u e_reverse_range[] = N_("E944: Reverse range in character class");
+static char_u e_large_class[] = N_("E945: Range too large in character class");
+static char_u e_unmatchedpp[] = N_("E53: Unmatched %s%%(");
+static char_u e_unmatchedp[] = N_("E54: Unmatched %s(");
+static char_u e_unmatchedpar[] = N_("E55: Unmatched %s)");
+#ifdef FEAT_SYN_HL
+static char_u e_z_not_allowed[] = N_("E66: \\z( not allowed here");
+static char_u e_z1_not_allowed[] = N_("E67: \\z1 - \\z9 not allowed here");
+#endif
+static char_u e_missing_sb[] = N_("E69: Missing ] after %s%%[");
+static char_u e_empty_sb[] = N_("E70: Empty %s%%[]");
+static char_u e_recursive[] = N_("E956: Cannot use pattern recursively");
+
+#define NOT_MULTI 0
+#define MULTI_ONE 1
+#define MULTI_MULT 2
+/*
+ * Return NOT_MULTI if c is not a "multi" operator.
+ * Return MULTI_ONE if c is a single "multi" operator.
+ * Return MULTI_MULT if c is a multi "multi" operator.
+ */
+ static int
+re_multi_type(int c)
+{
+ if (c == Magic('@') || c == Magic('=') || c == Magic('?'))
+ return MULTI_ONE;
+ if (c == Magic('*') || c == Magic('+') || c == Magic('{'))
+ return MULTI_MULT;
+ return NOT_MULTI;
+}
+
+/*
+ * Flags to be passed up and down.
+ */
+#define HASWIDTH 0x1 /* Known never to match null string. */
+#define SIMPLE 0x2 /* Simple enough to be STAR/PLUS operand. */
+#define SPSTART 0x4 /* Starts with * or +. */
+#define HASNL 0x8 /* Contains some \n. */
+#define HASLOOKBH 0x10 /* Contains "\@<=" or "\@<!". */
+#define WORST 0 /* Worst case. */
+
+/*
+ * When regcode is set to this value, code is not emitted and size is computed
+ * instead.
+ */
+#define JUST_CALC_SIZE ((char_u *) -1)
+
+static char_u *reg_prev_sub = NULL;
+
+/*
+ * REGEXP_INRANGE contains all characters which are always special in a []
+ * range after '\'.
+ * REGEXP_ABBR contains all characters which act as abbreviations after '\'.
+ * These are:
+ * \n - New line (NL).
+ * \r - Carriage Return (CR).
+ * \t - Tab (TAB).
+ * \e - Escape (ESC).
+ * \b - Backspace (Ctrl_H).
+ * \d - Character code in decimal, eg \d123
+ * \o - Character code in octal, eg \o80
+ * \x - Character code in hex, eg \x4a
+ * \u - Multibyte character code, eg \u20ac
+ * \U - Long multibyte character code, eg \U12345678
+ */
+static char_u REGEXP_INRANGE[] = "]^-n\\";
+static char_u REGEXP_ABBR[] = "nrtebdoxuU";
+
+/*
+ * Translate '\x' to its control character, except "\n", which is Magic.
+ */
+ static int
+backslash_trans(int c)
+{
+ switch (c)
+ {
+ case 'r': return CAR;
+ case 't': return TAB;
+ case 'e': return ESC;
+ case 'b': return BS;
+ }
+ return c;
+}
+
+/*
+ * Check for a character class name "[:name:]". "pp" points to the '['.
+ * Returns one of the CLASS_ items. CLASS_NONE means that no item was
+ * recognized. Otherwise "pp" is advanced to after the item.
+ */
+ static int
+get_char_class(char_u **pp)
+{
+ static const char *(class_names[]) =
+ {
+ "alnum:]",
+#define CLASS_ALNUM 0
+ "alpha:]",
+#define CLASS_ALPHA 1
+ "blank:]",
+#define CLASS_BLANK 2
+ "cntrl:]",
+#define CLASS_CNTRL 3
+ "digit:]",
+#define CLASS_DIGIT 4
+ "graph:]",
+#define CLASS_GRAPH 5
+ "lower:]",
+#define CLASS_LOWER 6
+ "print:]",
+#define CLASS_PRINT 7
+ "punct:]",
+#define CLASS_PUNCT 8
+ "space:]",
+#define CLASS_SPACE 9
+ "upper:]",
+#define CLASS_UPPER 10
+ "xdigit:]",
+#define CLASS_XDIGIT 11
+ "tab:]",
+#define CLASS_TAB 12
+ "return:]",
+#define CLASS_RETURN 13
+ "backspace:]",
+#define CLASS_BACKSPACE 14
+ "escape:]",
+#define CLASS_ESCAPE 15
+ "ident:]",
+#define CLASS_IDENT 16
+ "keyword:]",
+#define CLASS_KEYWORD 17
+ "fname:]",
+#define CLASS_FNAME 18
+ };
+#define CLASS_NONE 99
+ int i;
+
+ if ((*pp)[1] == ':')
+ {
+ for (i = 0; i < (int)(sizeof(class_names) / sizeof(*class_names)); ++i)
+ if (STRNCMP(*pp + 2, class_names[i], STRLEN(class_names[i])) == 0)
+ {
+ *pp += STRLEN(class_names[i]) + 2;
+ return i;
+ }
+ }
+ return CLASS_NONE;
+}
+
+/*
+ * Specific version of character class functions.
+ * Using a table to keep this fast.
+ */
+static short class_tab[256];
+
+#define RI_DIGIT 0x01
+#define RI_HEX 0x02
+#define RI_OCTAL 0x04
+#define RI_WORD 0x08
+#define RI_HEAD 0x10
+#define RI_ALPHA 0x20
+#define RI_LOWER 0x40
+#define RI_UPPER 0x80
+#define RI_WHITE 0x100
+
+ static void
+init_class_tab(void)
+{
+ int i;
+ static int done = FALSE;
+
+ if (done)
+ return;
+
+ for (i = 0; i < 256; ++i)
+ {
+ if (i >= '0' && i <= '7')
+ class_tab[i] = RI_DIGIT + RI_HEX + RI_OCTAL + RI_WORD;
+ else if (i >= '8' && i <= '9')
+ class_tab[i] = RI_DIGIT + RI_HEX + RI_WORD;
+ else if (i >= 'a' && i <= 'f')
+ class_tab[i] = RI_HEX + RI_WORD + RI_HEAD + RI_ALPHA + RI_LOWER;
+#ifdef EBCDIC
+ else if ((i >= 'g' && i <= 'i') || (i >= 'j' && i <= 'r')
+ || (i >= 's' && i <= 'z'))
+#else
+ else if (i >= 'g' && i <= 'z')
+#endif
+ class_tab[i] = RI_WORD + RI_HEAD + RI_ALPHA + RI_LOWER;
+ else if (i >= 'A' && i <= 'F')
+ class_tab[i] = RI_HEX + RI_WORD + RI_HEAD + RI_ALPHA + RI_UPPER;
+#ifdef EBCDIC
+ else if ((i >= 'G' && i <= 'I') || ( i >= 'J' && i <= 'R')
+ || (i >= 'S' && i <= 'Z'))
+#else
+ else if (i >= 'G' && i <= 'Z')
+#endif
+ class_tab[i] = RI_WORD + RI_HEAD + RI_ALPHA + RI_UPPER;
+ else if (i == '_')
+ class_tab[i] = RI_WORD + RI_HEAD;
+ else
+ class_tab[i] = 0;
+ }
+ class_tab[' '] |= RI_WHITE;
+ class_tab['\t'] |= RI_WHITE;
+ done = TRUE;
+}
+
+#define ri_digit(c) (c < 0x100 && (class_tab[c] & RI_DIGIT))
+#define ri_hex(c) (c < 0x100 && (class_tab[c] & RI_HEX))
+#define ri_octal(c) (c < 0x100 && (class_tab[c] & RI_OCTAL))
+#define ri_word(c) (c < 0x100 && (class_tab[c] & RI_WORD))
+#define ri_head(c) (c < 0x100 && (class_tab[c] & RI_HEAD))
+#define ri_alpha(c) (c < 0x100 && (class_tab[c] & RI_ALPHA))
+#define ri_lower(c) (c < 0x100 && (class_tab[c] & RI_LOWER))
+#define ri_upper(c) (c < 0x100 && (class_tab[c] & RI_UPPER))
+#define ri_white(c) (c < 0x100 && (class_tab[c] & RI_WHITE))
+
+/* flags for regflags */
+#define RF_ICASE 1 /* ignore case */
+#define RF_NOICASE 2 /* don't ignore case */
+#define RF_HASNL 4 /* can match a NL */
+#define RF_ICOMBINE 8 /* ignore combining characters */
+#define RF_LOOKBH 16 /* uses "\@<=" or "\@<!" */
+
+/*
+ * Global work variables for vim_regcomp().
+ */
+
+static char_u *regparse; /* Input-scan pointer. */
+static int prevchr_len; /* byte length of previous char */
+static int num_complex_braces; /* Complex \{...} count */
+static int regnpar; /* () count. */
+#ifdef FEAT_SYN_HL
+static int regnzpar; /* \z() count. */
+static int re_has_z; /* \z item detected */
+#endif
+static char_u *regcode; /* Code-emit pointer, or JUST_CALC_SIZE */
+static long regsize; /* Code size. */
+static int reg_toolong; /* TRUE when offset out of range */
+static char_u had_endbrace[NSUBEXP]; /* flags, TRUE if end of () found */
+static unsigned regflags; /* RF_ flags for prog */
+static long brace_min[10]; /* Minimums for complex brace repeats */
+static long brace_max[10]; /* Maximums for complex brace repeats */
+static int brace_count[10]; /* Current counts for complex brace repeats */
+#if defined(FEAT_SYN_HL) || defined(PROTO)
+static int had_eol; /* TRUE when EOL found by vim_regcomp() */
+#endif
+static int one_exactly = FALSE; /* only do one char for EXACTLY */
+
+static int reg_magic; /* magicness of the pattern: */
+#define MAGIC_NONE 1 /* "\V" very unmagic */
+#define MAGIC_OFF 2 /* "\M" or 'magic' off */
+#define MAGIC_ON 3 /* "\m" or 'magic' */
+#define MAGIC_ALL 4 /* "\v" very magic */
+
+static int reg_string; /* matching with a string instead of a buffer
+ line */
+static int reg_strict; /* "[abc" is illegal */
+
+/*
+ * META contains all characters that may be magic, except '^' and '$'.
+ */
+
+#ifdef EBCDIC
+static char_u META[] = "%&()*+.123456789<=>?@ACDFHIKLMOPSUVWX[_acdfhiklmnopsuvwxz{|~";
+#else
+/* META[] is used often enough to justify turning it into a table. */
+static char_u META_flags[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* % & ( ) * + . */
+ 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0,
+/* 1 2 3 4 5 6 7 8 9 < = > ? */
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1,
+/* @ A C D F H I K L M O */
+ 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1,
+/* P S U V W X Z [ _ */
+ 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1,
+/* a c d f h i k l m n o */
+ 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1,
+/* p s u v w x z { | ~ */
+ 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1
+};
+#endif
+
+static int curchr; /* currently parsed character */
+/* Previous character. Note: prevchr is sometimes -1 when we are not at the
+ * start, eg in /[ ^I]^ the pattern was never found even if it existed,
+ * because ^ was taken to be magic -- webb */
+static int prevchr;
+static int prevprevchr; /* previous-previous character */
+static int nextchr; /* used for ungetchr() */
+
+/* arguments for reg() */
+#define REG_NOPAREN 0 /* toplevel reg() */
+#define REG_PAREN 1 /* \(\) */
+#define REG_ZPAREN 2 /* \z(\) */
+#define REG_NPAREN 3 /* \%(\) */
+
+typedef struct
+{
+ char_u *regparse;
+ int prevchr_len;
+ int curchr;
+ int prevchr;
+ int prevprevchr;
+ int nextchr;
+ int at_start;
+ int prev_at_start;
+ int regnpar;
+} parse_state_T;
+
+/*
+ * Forward declarations for vim_regcomp()'s friends.
+ */
+static void initchr(char_u *);
+static int getchr(void);
+static void skipchr_keepstart(void);
+static int peekchr(void);
+static void skipchr(void);
+static void ungetchr(void);
+static long gethexchrs(int maxinputlen);
+static long getoctchrs(void);
+static long getdecchrs(void);
+static int coll_get_char(void);
+static void regcomp_start(char_u *expr, int flags);
+static char_u *reg(int, int *);
+static char_u *regbranch(int *flagp);
+static char_u *regconcat(int *flagp);
+static char_u *regpiece(int *);
+static char_u *regatom(int *);
+static char_u *regnode(int);
+static int use_multibytecode(int c);
+static int prog_magic_wrong(void);
+static char_u *regnext(char_u *);
+static void regc(int b);
+static void regmbc(int c);
+#define REGMBC(x) regmbc(x);
+#define CASEMBC(x) case x:
+static void reginsert(int, char_u *);
+static void reginsert_nr(int op, long val, char_u *opnd);
+static void reginsert_limits(int, long, long, char_u *);
+static char_u *re_put_long(char_u *pr, long_u val);
+static int read_limits(long *, long *);
+static void regtail(char_u *, char_u *);
+static void regoptail(char_u *, char_u *);
+static int reg_iswordc(int);
+
+static regengine_T bt_regengine;
+static regengine_T nfa_regengine;
+
+/*
+ * Return TRUE if compiled regular expression "prog" can match a line break.
+ */
+ int
+re_multiline(regprog_T *prog)
+{
+ return (prog->regflags & RF_HASNL);
+}
+
+/*
+ * Check for an equivalence class name "[=a=]". "pp" points to the '['.
+ * Returns a character representing the class. Zero means that no item was
+ * recognized. Otherwise "pp" is advanced to after the item.
+ */
+ static int
+get_equi_class(char_u **pp)
+{
+ int c;
+ int l = 1;
+ char_u *p = *pp;
+
+ if (p[1] == '=')
+ {
+ if (has_mbyte)
+ l = (*mb_ptr2len)(p + 2);
+ if (p[l + 2] == '=' && p[l + 3] == ']')
+ {
+ if (has_mbyte)
+ c = mb_ptr2char(p + 2);
+ else
+ c = p[2];
+ *pp += l + 4;
+ return c;
+ }
+ }
+ return 0;
+}
+
+#ifdef EBCDIC
+/*
+ * Table for equivalence class "c". (IBM-1047)
+ */
+char *EQUIVAL_CLASS_C[16] = {
+ "A\x62\x63\x64\x65\x66\x67",
+ "C\x68",
+ "E\x71\x72\x73\x74",
+ "I\x75\x76\x77\x78",
+ "N\x69",
+ "O\xEB\xEC\xED\xEE\xEF\x80",
+ "U\xFB\xFC\xFD\xFE",
+ "Y\xBA",
+ "a\x42\x43\x44\x45\x46\x47",
+ "c\x48",
+ "e\x51\x52\x53\x54",
+ "i\x55\x56\x57\x58",
+ "n\x49",
+ "o\xCB\xCC\xCD\xCE\xCF\x70",
+ "u\xDB\xDC\xDD\xDE",
+ "y\x8D\xDF",
+};
+#endif
+
+/*
+ * Produce the bytes for equivalence class "c".
+ * Currently only handles latin1, latin9 and utf-8.
+ * NOTE: When changing this function, also change nfa_emit_equi_class()
+ */
+ static void
+reg_equi_class(int c)
+{
+ if (enc_utf8 || STRCMP(p_enc, "latin1") == 0
+ || STRCMP(p_enc, "iso-8859-15") == 0)
+ {
+#ifdef EBCDIC
+ int i;
+
+ /* This might be slower than switch/case below. */
+ for (i = 0; i < 16; i++)
+ {
+ if (vim_strchr(EQUIVAL_CLASS_C[i], c) != NULL)
+ {
+ char *p = EQUIVAL_CLASS_C[i];
+
+ while (*p != 0)
+ regmbc(*p++);
+ return;
+ }
+ }
+#else
+ switch (c)
+ {
+ /* Do not use '\300' style, it results in a negative number. */
+ case 'A': case 0xc0: case 0xc1: case 0xc2:
+ case 0xc3: case 0xc4: case 0xc5:
+ CASEMBC(0x100) CASEMBC(0x102) CASEMBC(0x104) CASEMBC(0x1cd)
+ CASEMBC(0x1de) CASEMBC(0x1e0) CASEMBC(0x1ea2)
+ regmbc('A'); regmbc(0xc0); regmbc(0xc1);
+ regmbc(0xc2); regmbc(0xc3); regmbc(0xc4);
+ regmbc(0xc5);
+ REGMBC(0x100) REGMBC(0x102) REGMBC(0x104)
+ REGMBC(0x1cd) REGMBC(0x1de) REGMBC(0x1e0)
+ REGMBC(0x1ea2)
+ return;
+ case 'B': CASEMBC(0x1e02) CASEMBC(0x1e06)
+ regmbc('B'); REGMBC(0x1e02) REGMBC(0x1e06)
+ return;
+ case 'C': case 0xc7:
+ CASEMBC(0x106) CASEMBC(0x108) CASEMBC(0x10a) CASEMBC(0x10c)
+ regmbc('C'); regmbc(0xc7);
+ REGMBC(0x106) REGMBC(0x108) REGMBC(0x10a)
+ REGMBC(0x10c)
+ return;
+ case 'D': CASEMBC(0x10e) CASEMBC(0x110) CASEMBC(0x1e0a)
+ CASEMBC(0x1e0e) CASEMBC(0x1e10)
+ regmbc('D'); REGMBC(0x10e) REGMBC(0x110)
+ REGMBC(0x1e0a) REGMBC(0x1e0e) REGMBC(0x1e10)
+ return;
+ case 'E': case 0xc8: case 0xc9: case 0xca: case 0xcb:
+ CASEMBC(0x112) CASEMBC(0x114) CASEMBC(0x116) CASEMBC(0x118)
+ CASEMBC(0x11a) CASEMBC(0x1eba) CASEMBC(0x1ebc)
+ regmbc('E'); regmbc(0xc8); regmbc(0xc9);
+ regmbc(0xca); regmbc(0xcb);
+ REGMBC(0x112) REGMBC(0x114) REGMBC(0x116)
+ REGMBC(0x118) REGMBC(0x11a) REGMBC(0x1eba)
+ REGMBC(0x1ebc)
+ return;
+ case 'F': CASEMBC(0x1e1e)
+ regmbc('F'); REGMBC(0x1e1e)
+ return;
+ case 'G': CASEMBC(0x11c) CASEMBC(0x11e) CASEMBC(0x120)
+ CASEMBC(0x122) CASEMBC(0x1e4) CASEMBC(0x1e6) CASEMBC(0x1f4)
+ CASEMBC(0x1e20)
+ regmbc('G'); REGMBC(0x11c) REGMBC(0x11e)
+ REGMBC(0x120) REGMBC(0x122) REGMBC(0x1e4)
+ REGMBC(0x1e6) REGMBC(0x1f4) REGMBC(0x1e20)
+ return;
+ case 'H': CASEMBC(0x124) CASEMBC(0x126) CASEMBC(0x1e22)
+ CASEMBC(0x1e26) CASEMBC(0x1e28)
+ regmbc('H'); REGMBC(0x124) REGMBC(0x126)
+ REGMBC(0x1e22) REGMBC(0x1e26) REGMBC(0x1e28)
+ return;
+ case 'I': case 0xcc: case 0xcd: case 0xce: case 0xcf:
+ CASEMBC(0x128) CASEMBC(0x12a) CASEMBC(0x12c) CASEMBC(0x12e)
+ CASEMBC(0x130) CASEMBC(0x1cf) CASEMBC(0x1ec8)
+ regmbc('I'); regmbc(0xcc); regmbc(0xcd);
+ regmbc(0xce); regmbc(0xcf);
+ REGMBC(0x128) REGMBC(0x12a) REGMBC(0x12c)
+ REGMBC(0x12e) REGMBC(0x130) REGMBC(0x1cf)
+ REGMBC(0x1ec8)
+ return;
+ case 'J': CASEMBC(0x134)
+ regmbc('J'); REGMBC(0x134)
+ return;
+ case 'K': CASEMBC(0x136) CASEMBC(0x1e8) CASEMBC(0x1e30)
+ CASEMBC(0x1e34)
+ regmbc('K'); REGMBC(0x136) REGMBC(0x1e8)
+ REGMBC(0x1e30) REGMBC(0x1e34)
+ return;
+ case 'L': CASEMBC(0x139) CASEMBC(0x13b) CASEMBC(0x13d)
+ CASEMBC(0x13f) CASEMBC(0x141) CASEMBC(0x1e3a)
+ regmbc('L'); REGMBC(0x139) REGMBC(0x13b)
+ REGMBC(0x13d) REGMBC(0x13f) REGMBC(0x141)
+ REGMBC(0x1e3a)
+ return;
+ case 'M': CASEMBC(0x1e3e) CASEMBC(0x1e40)
+ regmbc('M'); REGMBC(0x1e3e) REGMBC(0x1e40)
+ return;
+ case 'N': case 0xd1:
+ CASEMBC(0x143) CASEMBC(0x145) CASEMBC(0x147) CASEMBC(0x1e44)
+ CASEMBC(0x1e48)
+ regmbc('N'); regmbc(0xd1);
+ REGMBC(0x143) REGMBC(0x145) REGMBC(0x147)
+ REGMBC(0x1e44) REGMBC(0x1e48)
+ return;
+ case 'O': case 0xd2: case 0xd3: case 0xd4: case 0xd5:
+ case 0xd6: case 0xd8:
+ CASEMBC(0x14c) CASEMBC(0x14e) CASEMBC(0x150) CASEMBC(0x1a0)
+ CASEMBC(0x1d1) CASEMBC(0x1ea) CASEMBC(0x1ec) CASEMBC(0x1ece)
+ regmbc('O'); regmbc(0xd2); regmbc(0xd3);
+ regmbc(0xd4); regmbc(0xd5); regmbc(0xd6);
+ regmbc(0xd8);
+ REGMBC(0x14c) REGMBC(0x14e) REGMBC(0x150)
+ REGMBC(0x1a0) REGMBC(0x1d1) REGMBC(0x1ea)
+ REGMBC(0x1ec) REGMBC(0x1ece)
+ return;
+ case 'P': case 0x1e54: case 0x1e56:
+ regmbc('P'); REGMBC(0x1e54) REGMBC(0x1e56)
+ return;
+ case 'R': CASEMBC(0x154) CASEMBC(0x156) CASEMBC(0x158)
+ CASEMBC(0x1e58) CASEMBC(0x1e5e)
+ regmbc('R'); REGMBC(0x154) REGMBC(0x156) REGMBC(0x158)
+ REGMBC(0x1e58) REGMBC(0x1e5e)
+ return;
+ case 'S': CASEMBC(0x15a) CASEMBC(0x15c) CASEMBC(0x15e)
+ CASEMBC(0x160) CASEMBC(0x1e60)
+ regmbc('S'); REGMBC(0x15a) REGMBC(0x15c)
+ REGMBC(0x15e) REGMBC(0x160) REGMBC(0x1e60)
+ return;
+ case 'T': CASEMBC(0x162) CASEMBC(0x164) CASEMBC(0x166)
+ CASEMBC(0x1e6a) CASEMBC(0x1e6e)
+ regmbc('T'); REGMBC(0x162) REGMBC(0x164)
+ REGMBC(0x166) REGMBC(0x1e6a) REGMBC(0x1e6e)
+ return;
+ case 'U': case 0xd9: case 0xda: case 0xdb: case 0xdc:
+ CASEMBC(0x168) CASEMBC(0x16a) CASEMBC(0x16c) CASEMBC(0x16e)
+ CASEMBC(0x170) CASEMBC(0x172) CASEMBC(0x1af) CASEMBC(0x1d3)
+ CASEMBC(0x1ee6)
+ regmbc('U'); regmbc(0xd9); regmbc(0xda);
+ regmbc(0xdb); regmbc(0xdc);
+ REGMBC(0x168) REGMBC(0x16a) REGMBC(0x16c)
+ REGMBC(0x16e) REGMBC(0x170) REGMBC(0x172)
+ REGMBC(0x1af) REGMBC(0x1d3) REGMBC(0x1ee6)
+ return;
+ case 'V': CASEMBC(0x1e7c)
+ regmbc('V'); REGMBC(0x1e7c)
+ return;
+ case 'W': CASEMBC(0x174) CASEMBC(0x1e80) CASEMBC(0x1e82)
+ CASEMBC(0x1e84) CASEMBC(0x1e86)
+ regmbc('W'); REGMBC(0x174) REGMBC(0x1e80)
+ REGMBC(0x1e82) REGMBC(0x1e84) REGMBC(0x1e86)
+ return;
+ case 'X': CASEMBC(0x1e8a) CASEMBC(0x1e8c)
+ regmbc('X'); REGMBC(0x1e8a) REGMBC(0x1e8c)
+ return;
+ case 'Y': case 0xdd:
+ CASEMBC(0x176) CASEMBC(0x178) CASEMBC(0x1e8e) CASEMBC(0x1ef2)
+ CASEMBC(0x1ef6) CASEMBC(0x1ef8)
+ regmbc('Y'); regmbc(0xdd);
+ REGMBC(0x176) REGMBC(0x178) REGMBC(0x1e8e)
+ REGMBC(0x1ef2) REGMBC(0x1ef6) REGMBC(0x1ef8)
+ return;
+ case 'Z': CASEMBC(0x179) CASEMBC(0x17b) CASEMBC(0x17d)
+ CASEMBC(0x1b5) CASEMBC(0x1e90) CASEMBC(0x1e94)
+ regmbc('Z'); REGMBC(0x179) REGMBC(0x17b)
+ REGMBC(0x17d) REGMBC(0x1b5) REGMBC(0x1e90)
+ REGMBC(0x1e94)
+ return;
+ case 'a': case 0xe0: case 0xe1: case 0xe2:
+ case 0xe3: case 0xe4: case 0xe5:
+ CASEMBC(0x101) CASEMBC(0x103) CASEMBC(0x105) CASEMBC(0x1ce)
+ CASEMBC(0x1df) CASEMBC(0x1e1) CASEMBC(0x1ea3)
+ regmbc('a'); regmbc(0xe0); regmbc(0xe1);
+ regmbc(0xe2); regmbc(0xe3); regmbc(0xe4);
+ regmbc(0xe5);
+ REGMBC(0x101) REGMBC(0x103) REGMBC(0x105)
+ REGMBC(0x1ce) REGMBC(0x1df) REGMBC(0x1e1)
+ REGMBC(0x1ea3)
+ return;
+ case 'b': CASEMBC(0x1e03) CASEMBC(0x1e07)
+ regmbc('b'); REGMBC(0x1e03) REGMBC(0x1e07)
+ return;
+ case 'c': case 0xe7:
+ CASEMBC(0x107) CASEMBC(0x109) CASEMBC(0x10b) CASEMBC(0x10d)
+ regmbc('c'); regmbc(0xe7);
+ REGMBC(0x107) REGMBC(0x109) REGMBC(0x10b)
+ REGMBC(0x10d)
+ return;
+ case 'd': CASEMBC(0x10f) CASEMBC(0x111) CASEMBC(0x1e0b)
+ CASEMBC(0x1e0f) CASEMBC(0x1e11)
+ regmbc('d'); REGMBC(0x10f) REGMBC(0x111)
+ REGMBC(0x1e0b) REGMBC(0x1e0f) REGMBC(0x1e11)
+ return;
+ case 'e': case 0xe8: case 0xe9: case 0xea: case 0xeb:
+ CASEMBC(0x113) CASEMBC(0x115) CASEMBC(0x117) CASEMBC(0x119)
+ CASEMBC(0x11b) CASEMBC(0x1ebb) CASEMBC(0x1ebd)
+ regmbc('e'); regmbc(0xe8); regmbc(0xe9);
+ regmbc(0xea); regmbc(0xeb);
+ REGMBC(0x113) REGMBC(0x115) REGMBC(0x117)
+ REGMBC(0x119) REGMBC(0x11b) REGMBC(0x1ebb)
+ REGMBC(0x1ebd)
+ return;
+ case 'f': CASEMBC(0x1e1f)
+ regmbc('f'); REGMBC(0x1e1f)
+ return;
+ case 'g': CASEMBC(0x11d) CASEMBC(0x11f) CASEMBC(0x121)
+ CASEMBC(0x123) CASEMBC(0x1e5) CASEMBC(0x1e7) CASEMBC(0x1f5)
+ CASEMBC(0x1e21)
+ regmbc('g'); REGMBC(0x11d) REGMBC(0x11f)
+ REGMBC(0x121) REGMBC(0x123) REGMBC(0x1e5)
+ REGMBC(0x1e7) REGMBC(0x1f5) REGMBC(0x1e21)
+ return;
+ case 'h': CASEMBC(0x125) CASEMBC(0x127) CASEMBC(0x1e23)
+ CASEMBC(0x1e27) CASEMBC(0x1e29) CASEMBC(0x1e96)
+ regmbc('h'); REGMBC(0x125) REGMBC(0x127)
+ REGMBC(0x1e23) REGMBC(0x1e27) REGMBC(0x1e29)
+ REGMBC(0x1e96)
+ return;
+ case 'i': case 0xec: case 0xed: case 0xee: case 0xef:
+ CASEMBC(0x129) CASEMBC(0x12b) CASEMBC(0x12d) CASEMBC(0x12f)
+ CASEMBC(0x1d0) CASEMBC(0x1ec9)
+ regmbc('i'); regmbc(0xec); regmbc(0xed);
+ regmbc(0xee); regmbc(0xef);
+ REGMBC(0x129) REGMBC(0x12b) REGMBC(0x12d)
+ REGMBC(0x12f) REGMBC(0x1d0) REGMBC(0x1ec9)
+ return;
+ case 'j': CASEMBC(0x135) CASEMBC(0x1f0)
+ regmbc('j'); REGMBC(0x135) REGMBC(0x1f0)
+ return;
+ case 'k': CASEMBC(0x137) CASEMBC(0x1e9) CASEMBC(0x1e31)
+ CASEMBC(0x1e35)
+ regmbc('k'); REGMBC(0x137) REGMBC(0x1e9)
+ REGMBC(0x1e31) REGMBC(0x1e35)
+ return;
+ case 'l': CASEMBC(0x13a) CASEMBC(0x13c) CASEMBC(0x13e)
+ CASEMBC(0x140) CASEMBC(0x142) CASEMBC(0x1e3b)
+ regmbc('l'); REGMBC(0x13a) REGMBC(0x13c)
+ REGMBC(0x13e) REGMBC(0x140) REGMBC(0x142)
+ REGMBC(0x1e3b)
+ return;
+ case 'm': CASEMBC(0x1e3f) CASEMBC(0x1e41)
+ regmbc('m'); REGMBC(0x1e3f) REGMBC(0x1e41)
+ return;
+ case 'n': case 0xf1:
+ CASEMBC(0x144) CASEMBC(0x146) CASEMBC(0x148) CASEMBC(0x149)
+ CASEMBC(0x1e45) CASEMBC(0x1e49)
+ regmbc('n'); regmbc(0xf1);
+ REGMBC(0x144) REGMBC(0x146) REGMBC(0x148)
+ REGMBC(0x149) REGMBC(0x1e45) REGMBC(0x1e49)
+ return;
+ case 'o': case 0xf2: case 0xf3: case 0xf4: case 0xf5:
+ case 0xf6: case 0xf8:
+ CASEMBC(0x14d) CASEMBC(0x14f) CASEMBC(0x151) CASEMBC(0x1a1)
+ CASEMBC(0x1d2) CASEMBC(0x1eb) CASEMBC(0x1ed) CASEMBC(0x1ecf)
+ regmbc('o'); regmbc(0xf2); regmbc(0xf3);
+ regmbc(0xf4); regmbc(0xf5); regmbc(0xf6);
+ regmbc(0xf8);
+ REGMBC(0x14d) REGMBC(0x14f) REGMBC(0x151)
+ REGMBC(0x1a1) REGMBC(0x1d2) REGMBC(0x1eb)
+ REGMBC(0x1ed) REGMBC(0x1ecf)
+ return;
+ case 'p': CASEMBC(0x1e55) CASEMBC(0x1e57)
+ regmbc('p'); REGMBC(0x1e55) REGMBC(0x1e57)
+ return;
+ case 'r': CASEMBC(0x155) CASEMBC(0x157) CASEMBC(0x159)
+ CASEMBC(0x1e59) CASEMBC(0x1e5f)
+ regmbc('r'); REGMBC(0x155) REGMBC(0x157) REGMBC(0x159)
+ REGMBC(0x1e59) REGMBC(0x1e5f)
+ return;
+ case 's': CASEMBC(0x15b) CASEMBC(0x15d) CASEMBC(0x15f)
+ CASEMBC(0x161) CASEMBC(0x1e61)
+ regmbc('s'); REGMBC(0x15b) REGMBC(0x15d)
+ REGMBC(0x15f) REGMBC(0x161) REGMBC(0x1e61)
+ return;
+ case 't': CASEMBC(0x163) CASEMBC(0x165) CASEMBC(0x167)
+ CASEMBC(0x1e6b) CASEMBC(0x1e6f) CASEMBC(0x1e97)
+ regmbc('t'); REGMBC(0x163) REGMBC(0x165) REGMBC(0x167)
+ REGMBC(0x1e6b) REGMBC(0x1e6f) REGMBC(0x1e97)
+ return;
+ case 'u': case 0xf9: case 0xfa: case 0xfb: case 0xfc:
+ CASEMBC(0x169) CASEMBC(0x16b) CASEMBC(0x16d) CASEMBC(0x16f)
+ CASEMBC(0x171) CASEMBC(0x173) CASEMBC(0x1b0) CASEMBC(0x1d4)
+ CASEMBC(0x1ee7)
+ regmbc('u'); regmbc(0xf9); regmbc(0xfa);
+ regmbc(0xfb); regmbc(0xfc);
+ REGMBC(0x169) REGMBC(0x16b) REGMBC(0x16d)
+ REGMBC(0x16f) REGMBC(0x171) REGMBC(0x173)
+ REGMBC(0x1b0) REGMBC(0x1d4) REGMBC(0x1ee7)
+ return;
+ case 'v': CASEMBC(0x1e7d)
+ regmbc('v'); REGMBC(0x1e7d)
+ return;
+ case 'w': CASEMBC(0x175) CASEMBC(0x1e81) CASEMBC(0x1e83)
+ CASEMBC(0x1e85) CASEMBC(0x1e87) CASEMBC(0x1e98)
+ regmbc('w'); REGMBC(0x175) REGMBC(0x1e81)
+ REGMBC(0x1e83) REGMBC(0x1e85) REGMBC(0x1e87)
+ REGMBC(0x1e98)
+ return;
+ case 'x': CASEMBC(0x1e8b) CASEMBC(0x1e8d)
+ regmbc('x'); REGMBC(0x1e8b) REGMBC(0x1e8d)
+ return;
+ case 'y': case 0xfd: case 0xff:
+ CASEMBC(0x177) CASEMBC(0x1e8f) CASEMBC(0x1e99)
+ CASEMBC(0x1ef3) CASEMBC(0x1ef7) CASEMBC(0x1ef9)
+ regmbc('y'); regmbc(0xfd); regmbc(0xff);
+ REGMBC(0x177) REGMBC(0x1e8f) REGMBC(0x1e99)
+ REGMBC(0x1ef3) REGMBC(0x1ef7) REGMBC(0x1ef9)
+ return;
+ case 'z': CASEMBC(0x17a) CASEMBC(0x17c) CASEMBC(0x17e)
+ CASEMBC(0x1b6) CASEMBC(0x1e91) CASEMBC(0x1e95)
+ regmbc('z'); REGMBC(0x17a) REGMBC(0x17c)
+ REGMBC(0x17e) REGMBC(0x1b6) REGMBC(0x1e91)
+ REGMBC(0x1e95)
+ return;
+ }
+#endif
+ }
+ regmbc(c);
+}
+
+/*
+ * Check for a collating element "[.a.]". "pp" points to the '['.
+ * Returns a character. Zero means that no item was recognized. Otherwise
+ * "pp" is advanced to after the item.
+ * Currently only single characters are recognized!
+ */
+ static int
+get_coll_element(char_u **pp)
+{
+ int c;
+ int l = 1;
+ char_u *p = *pp;
+
+ if (p[0] != NUL && p[1] == '.')
+ {
+ if (has_mbyte)
+ l = (*mb_ptr2len)(p + 2);
+ if (p[l + 2] == '.' && p[l + 3] == ']')
+ {
+ if (has_mbyte)
+ c = mb_ptr2char(p + 2);
+ else
+ c = p[2];
+ *pp += l + 4;
+ return c;
+ }
+ }
+ return 0;
+}
+
+static int reg_cpo_lit; /* 'cpoptions' contains 'l' flag */
+static int reg_cpo_bsl; /* 'cpoptions' contains '\' flag */
+
+ static void
+get_cpo_flags(void)
+{
+ reg_cpo_lit = vim_strchr(p_cpo, CPO_LITERAL) != NULL;
+ reg_cpo_bsl = vim_strchr(p_cpo, CPO_BACKSL) != NULL;
+}
+
+/*
+ * Skip over a "[]" range.
+ * "p" must point to the character after the '['.
+ * The returned pointer is on the matching ']', or the terminating NUL.
+ */
+ static char_u *
+skip_anyof(char_u *p)
+{
+ int l;
+
+ if (*p == '^') /* Complement of range. */
+ ++p;
+ if (*p == ']' || *p == '-')
+ ++p;
+ while (*p != NUL && *p != ']')
+ {
+ if (has_mbyte && (l = (*mb_ptr2len)(p)) > 1)
+ p += l;
+ else
+ if (*p == '-')
+ {
+ ++p;
+ if (*p != ']' && *p != NUL)
+ MB_PTR_ADV(p);
+ }
+ else if (*p == '\\'
+ && !reg_cpo_bsl
+ && (vim_strchr(REGEXP_INRANGE, p[1]) != NULL
+ || (!reg_cpo_lit && vim_strchr(REGEXP_ABBR, p[1]) != NULL)))
+ p += 2;
+ else if (*p == '[')
+ {
+ if (get_char_class(&p) == CLASS_NONE
+ && get_equi_class(&p) == 0
+ && get_coll_element(&p) == 0
+ && *p != NUL)
+ ++p; /* it is not a class name and not NUL */
+ }
+ else
+ ++p;
+ }
+
+ return p;
+}
+
+/*
+ * Skip past regular expression.
+ * Stop at end of "startp" or where "dirc" is found ('/', '?', etc).
+ * Take care of characters with a backslash in front of it.
+ * Skip strings inside [ and ].
+ * When "newp" is not NULL and "dirc" is '?', make an allocated copy of the
+ * expression and change "\?" to "?". If "*newp" is not NULL the expression
+ * is changed in-place.
+ */
+ char_u *
+skip_regexp(
+ char_u *startp,
+ int dirc,
+ int magic,
+ char_u **newp)
+{
+ int mymagic;
+ char_u *p = startp;
+
+ if (magic)
+ mymagic = MAGIC_ON;
+ else
+ mymagic = MAGIC_OFF;
+ get_cpo_flags();
+
+ for (; p[0] != NUL; MB_PTR_ADV(p))
+ {
+ if (p[0] == dirc) /* found end of regexp */
+ break;
+ if ((p[0] == '[' && mymagic >= MAGIC_ON)
+ || (p[0] == '\\' && p[1] == '[' && mymagic <= MAGIC_OFF))
+ {
+ p = skip_anyof(p + 1);
+ if (p[0] == NUL)
+ break;
+ }
+ else if (p[0] == '\\' && p[1] != NUL)
+ {
+ if (dirc == '?' && newp != NULL && p[1] == '?')
+ {
+ /* change "\?" to "?", make a copy first. */
+ if (*newp == NULL)
+ {
+ *newp = vim_strsave(startp);
+ if (*newp != NULL)
+ p = *newp + (p - startp);
+ }
+ if (*newp != NULL)
+ STRMOVE(p, p + 1);
+ else
+ ++p;
+ }
+ else
+ ++p; /* skip next character */
+ if (*p == 'v')
+ mymagic = MAGIC_ALL;
+ else if (*p == 'V')
+ mymagic = MAGIC_NONE;
+ }
+ }
+ return p;
+}
+
+/*
+ * Return TRUE if the back reference is legal. We must have seen the close
+ * brace.
+ * TODO: Should also check that we don't refer to something that is repeated
+ * (+*=): what instance of the repetition should we match?
+ */
+ static int
+seen_endbrace(int refnum)
+{
+ if (!had_endbrace[refnum])
+ {
+ char_u *p;
+
+ /* Trick: check if "@<=" or "@<!" follows, in which case
+ * the \1 can appear before the referenced match. */
+ for (p = regparse; *p != NUL; ++p)
+ if (p[0] == '@' && p[1] == '<' && (p[2] == '!' || p[2] == '='))
+ break;
+ if (*p == NUL)
+ {
+ emsg(_("E65: Illegal back reference"));
+ rc_did_emsg = TRUE;
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+/*
+ * bt_regcomp() - compile a regular expression into internal code for the
+ * traditional back track matcher.
+ * Returns the program in allocated space. Returns NULL for an error.
+ *
+ * We can't allocate space until we know how big the compiled form will be,
+ * but we can't compile it (and thus know how big it is) until we've got a
+ * place to put the code. So we cheat: we compile it twice, once with code
+ * generation turned off and size counting turned on, and once "for real".
+ * This also means that we don't allocate space until we are sure that the
+ * thing really will compile successfully, and we never have to move the
+ * code and thus invalidate pointers into it. (Note that it has to be in
+ * one piece because vim_free() must be able to free it all.)
+ *
+ * Whether upper/lower case is to be ignored is decided when executing the
+ * program, it does not matter here.
+ *
+ * Beware that the optimization-preparation code in here knows about some
+ * of the structure of the compiled regexp.
+ * "re_flags": RE_MAGIC and/or RE_STRING.
+ */
+ static regprog_T *
+bt_regcomp(char_u *expr, int re_flags)
+{
+ bt_regprog_T *r;
+ char_u *scan;
+ char_u *longest;
+ int len;
+ int flags;
+
+ if (expr == NULL)
+ EMSG_RET_NULL(_(e_null));
+
+ init_class_tab();
+
+ /*
+ * First pass: determine size, legality.
+ */
+ regcomp_start(expr, re_flags);
+ regcode = JUST_CALC_SIZE;
+ regc(REGMAGIC);
+ if (reg(REG_NOPAREN, &flags) == NULL)
+ return NULL;
+
+ /* Allocate space. */
+ r = (bt_regprog_T *)lalloc(sizeof(bt_regprog_T) + regsize, TRUE);
+ if (r == NULL)
+ return NULL;
+ r->re_in_use = FALSE;
+
+ /*
+ * Second pass: emit code.
+ */
+ regcomp_start(expr, re_flags);
+ regcode = r->program;
+ regc(REGMAGIC);
+ if (reg(REG_NOPAREN, &flags) == NULL || reg_toolong)
+ {
+ vim_free(r);
+ if (reg_toolong)
+ EMSG_RET_NULL(_("E339: Pattern too long"));
+ return NULL;
+ }
+
+ /* Dig out information for optimizations. */
+ r->regstart = NUL; /* Worst-case defaults. */
+ r->reganch = 0;
+ r->regmust = NULL;
+ r->regmlen = 0;
+ r->regflags = regflags;
+ if (flags & HASNL)
+ r->regflags |= RF_HASNL;
+ if (flags & HASLOOKBH)
+ r->regflags |= RF_LOOKBH;
+#ifdef FEAT_SYN_HL
+ /* Remember whether this pattern has any \z specials in it. */
+ r->reghasz = re_has_z;
+#endif
+ scan = r->program + 1; /* First BRANCH. */
+ if (OP(regnext(scan)) == END) /* Only one top-level choice. */
+ {
+ scan = OPERAND(scan);
+
+ /* Starting-point info. */
+ if (OP(scan) == BOL || OP(scan) == RE_BOF)
+ {
+ r->reganch++;
+ scan = regnext(scan);
+ }
+
+ if (OP(scan) == EXACTLY)
+ {
+ if (has_mbyte)
+ r->regstart = (*mb_ptr2char)(OPERAND(scan));
+ else
+ r->regstart = *OPERAND(scan);
+ }
+ else if ((OP(scan) == BOW
+ || OP(scan) == EOW
+ || OP(scan) == NOTHING
+ || OP(scan) == MOPEN + 0 || OP(scan) == NOPEN
+ || OP(scan) == MCLOSE + 0 || OP(scan) == NCLOSE)
+ && OP(regnext(scan)) == EXACTLY)
+ {
+ if (has_mbyte)
+ r->regstart = (*mb_ptr2char)(OPERAND(regnext(scan)));
+ else
+ r->regstart = *OPERAND(regnext(scan));
+ }
+
+ /*
+ * If there's something expensive in the r.e., find the longest
+ * literal string that must appear and make it the regmust. Resolve
+ * ties in favor of later strings, since the regstart check works
+ * with the beginning of the r.e. and avoiding duplication
+ * strengthens checking. Not a strong reason, but sufficient in the
+ * absence of others.
+ */
+ /*
+ * When the r.e. starts with BOW, it is faster to look for a regmust
+ * first. Used a lot for "#" and "*" commands. (Added by mool).
+ */
+ if ((flags & SPSTART || OP(scan) == BOW || OP(scan) == EOW)
+ && !(flags & HASNL))
+ {
+ longest = NULL;
+ len = 0;
+ for (; scan != NULL; scan = regnext(scan))
+ if (OP(scan) == EXACTLY && STRLEN(OPERAND(scan)) >= (size_t)len)
+ {
+ longest = OPERAND(scan);
+ len = (int)STRLEN(OPERAND(scan));
+ }
+ r->regmust = longest;
+ r->regmlen = len;
+ }
+ }
+#ifdef BT_REGEXP_DUMP
+ regdump(expr, r);
+#endif
+ r->engine = &bt_regengine;
+ return (regprog_T *)r;
+}
+
+/*
+ * Free a compiled regexp program, returned by bt_regcomp().
+ */
+ static void
+bt_regfree(regprog_T *prog)
+{
+ vim_free(prog);
+}
+
+/*
+ * Setup to parse the regexp. Used once to get the length and once to do it.
+ */
+ static void
+regcomp_start(
+ char_u *expr,
+ int re_flags) /* see vim_regcomp() */
+{
+ initchr(expr);
+ if (re_flags & RE_MAGIC)
+ reg_magic = MAGIC_ON;
+ else
+ reg_magic = MAGIC_OFF;
+ reg_string = (re_flags & RE_STRING);
+ reg_strict = (re_flags & RE_STRICT);
+ get_cpo_flags();
+
+ num_complex_braces = 0;
+ regnpar = 1;
+ vim_memset(had_endbrace, 0, sizeof(had_endbrace));
+#ifdef FEAT_SYN_HL
+ regnzpar = 1;
+ re_has_z = 0;
+#endif
+ regsize = 0L;
+ reg_toolong = FALSE;
+ regflags = 0;
+#if defined(FEAT_SYN_HL) || defined(PROTO)
+ had_eol = FALSE;
+#endif
+}
+
+#if defined(FEAT_SYN_HL) || defined(PROTO)
+/*
+ * Check if during the previous call to vim_regcomp the EOL item "$" has been
+ * found. This is messy, but it works fine.
+ */
+ int
+vim_regcomp_had_eol(void)
+{
+ return had_eol;
+}
+#endif
+
+// variables used for parsing
+static int at_start; // True when on the first character
+static int prev_at_start; // True when on the second character
+
+/*
+ * Parse regular expression, i.e. main body or parenthesized thing.
+ *
+ * Caller must absorb opening parenthesis.
+ *
+ * Combining parenthesis handling with the base level of regular expression
+ * is a trifle forced, but the need to tie the tails of the branches to what
+ * follows makes it hard to avoid.
+ */
+ static char_u *
+reg(
+ int paren, /* REG_NOPAREN, REG_PAREN, REG_NPAREN or REG_ZPAREN */
+ int *flagp)
+{
+ char_u *ret;
+ char_u *br;
+ char_u *ender;
+ int parno = 0;
+ int flags;
+
+ *flagp = HASWIDTH; /* Tentatively. */
+
+#ifdef FEAT_SYN_HL
+ if (paren == REG_ZPAREN)
+ {
+ /* Make a ZOPEN node. */
+ if (regnzpar >= NSUBEXP)
+ EMSG_RET_NULL(_("E50: Too many \\z("));
+ parno = regnzpar;
+ regnzpar++;
+ ret = regnode(ZOPEN + parno);
+ }
+ else
+#endif
+ if (paren == REG_PAREN)
+ {
+ /* Make a MOPEN node. */
+ if (regnpar >= NSUBEXP)
+ EMSG2_RET_NULL(_("E51: Too many %s("), reg_magic == MAGIC_ALL);
+ parno = regnpar;
+ ++regnpar;
+ ret = regnode(MOPEN + parno);
+ }
+ else if (paren == REG_NPAREN)
+ {
+ /* Make a NOPEN node. */
+ ret = regnode(NOPEN);
+ }
+ else
+ ret = NULL;
+
+ /* Pick up the branches, linking them together. */
+ br = regbranch(&flags);
+ if (br == NULL)
+ return NULL;
+ if (ret != NULL)
+ regtail(ret, br); /* [MZ]OPEN -> first. */
+ else
+ ret = br;
+ /* If one of the branches can be zero-width, the whole thing can.
+ * If one of the branches has * at start or matches a line-break, the
+ * whole thing can. */
+ if (!(flags & HASWIDTH))
+ *flagp &= ~HASWIDTH;
+ *flagp |= flags & (SPSTART | HASNL | HASLOOKBH);
+ while (peekchr() == Magic('|'))
+ {
+ skipchr();
+ br = regbranch(&flags);
+ if (br == NULL || reg_toolong)
+ return NULL;
+ regtail(ret, br); /* BRANCH -> BRANCH. */
+ if (!(flags & HASWIDTH))
+ *flagp &= ~HASWIDTH;
+ *flagp |= flags & (SPSTART | HASNL | HASLOOKBH);
+ }
+
+ /* Make a closing node, and hook it on the end. */
+ ender = regnode(
+#ifdef FEAT_SYN_HL
+ paren == REG_ZPAREN ? ZCLOSE + parno :
+#endif
+ paren == REG_PAREN ? MCLOSE + parno :
+ paren == REG_NPAREN ? NCLOSE : END);
+ regtail(ret, ender);
+
+ /* Hook the tails of the branches to the closing node. */
+ for (br = ret; br != NULL; br = regnext(br))
+ regoptail(br, ender);
+
+ /* Check for proper termination. */
+ if (paren != REG_NOPAREN && getchr() != Magic(')'))
+ {
+#ifdef FEAT_SYN_HL
+ if (paren == REG_ZPAREN)
+ EMSG_RET_NULL(_("E52: Unmatched \\z("));
+ else
+#endif
+ if (paren == REG_NPAREN)
+ EMSG2_RET_NULL(_(e_unmatchedpp), reg_magic == MAGIC_ALL);
+ else
+ EMSG2_RET_NULL(_(e_unmatchedp), reg_magic == MAGIC_ALL);
+ }
+ else if (paren == REG_NOPAREN && peekchr() != NUL)
+ {
+ if (curchr == Magic(')'))
+ EMSG2_RET_NULL(_(e_unmatchedpar), reg_magic == MAGIC_ALL);
+ else
+ EMSG_RET_NULL(_(e_trailing)); /* "Can't happen". */
+ /* NOTREACHED */
+ }
+ /*
+ * Here we set the flag allowing back references to this set of
+ * parentheses.
+ */
+ if (paren == REG_PAREN)
+ had_endbrace[parno] = TRUE; /* have seen the close paren */
+ return ret;
+}
+
+/*
+ * Parse one alternative of an | operator.
+ * Implements the & operator.
+ */
+ static char_u *
+regbranch(int *flagp)
+{
+ char_u *ret;
+ char_u *chain = NULL;
+ char_u *latest;
+ int flags;
+
+ *flagp = WORST | HASNL; /* Tentatively. */
+
+ ret = regnode(BRANCH);
+ for (;;)
+ {
+ latest = regconcat(&flags);
+ if (latest == NULL)
+ return NULL;
+ /* If one of the branches has width, the whole thing has. If one of
+ * the branches anchors at start-of-line, the whole thing does.
+ * If one of the branches uses look-behind, the whole thing does. */
+ *flagp |= flags & (HASWIDTH | SPSTART | HASLOOKBH);
+ /* If one of the branches doesn't match a line-break, the whole thing
+ * doesn't. */
+ *flagp &= ~HASNL | (flags & HASNL);
+ if (chain != NULL)
+ regtail(chain, latest);
+ if (peekchr() != Magic('&'))
+ break;
+ skipchr();
+ regtail(latest, regnode(END)); /* operand ends */
+ if (reg_toolong)
+ break;
+ reginsert(MATCH, latest);
+ chain = latest;
+ }
+
+ return ret;
+}
+
+/*
+ * Parse one alternative of an | or & operator.
+ * Implements the concatenation operator.
+ */
+ static char_u *
+regconcat(int *flagp)
+{
+ char_u *first = NULL;
+ char_u *chain = NULL;
+ char_u *latest;
+ int flags;
+ int cont = TRUE;
+
+ *flagp = WORST; /* Tentatively. */
+
+ while (cont)
+ {
+ switch (peekchr())
+ {
+ case NUL:
+ case Magic('|'):
+ case Magic('&'):
+ case Magic(')'):
+ cont = FALSE;
+ break;
+ case Magic('Z'):
+ regflags |= RF_ICOMBINE;
+ skipchr_keepstart();
+ break;
+ case Magic('c'):
+ regflags |= RF_ICASE;
+ skipchr_keepstart();
+ break;
+ case Magic('C'):
+ regflags |= RF_NOICASE;
+ skipchr_keepstart();
+ break;
+ case Magic('v'):
+ reg_magic = MAGIC_ALL;
+ skipchr_keepstart();
+ curchr = -1;
+ break;
+ case Magic('m'):
+ reg_magic = MAGIC_ON;
+ skipchr_keepstart();
+ curchr = -1;
+ break;
+ case Magic('M'):
+ reg_magic = MAGIC_OFF;
+ skipchr_keepstart();
+ curchr = -1;
+ break;
+ case Magic('V'):
+ reg_magic = MAGIC_NONE;
+ skipchr_keepstart();
+ curchr = -1;
+ break;
+ default:
+ latest = regpiece(&flags);
+ if (latest == NULL || reg_toolong)
+ return NULL;
+ *flagp |= flags & (HASWIDTH | HASNL | HASLOOKBH);
+ if (chain == NULL) /* First piece. */
+ *flagp |= flags & SPSTART;
+ else
+ regtail(chain, latest);
+ chain = latest;
+ if (first == NULL)
+ first = latest;
+ break;
+ }
+ }
+ if (first == NULL) /* Loop ran zero times. */
+ first = regnode(NOTHING);
+ return first;
+}
+
+/*
+ * Parse something followed by possible [*+=].
+ *
+ * Note that the branching code sequences used for = and the general cases
+ * of * and + are somewhat optimized: they use the same NOTHING node as
+ * both the endmarker for their branch list and the body of the last branch.
+ * It might seem that this node could be dispensed with entirely, but the
+ * endmarker role is not redundant.
+ */
+ static char_u *
+regpiece(int *flagp)
+{
+ char_u *ret;
+ int op;
+ char_u *next;
+ int flags;
+ long minval;
+ long maxval;
+
+ ret = regatom(&flags);
+ if (ret == NULL)
+ return NULL;
+
+ op = peekchr();
+ if (re_multi_type(op) == NOT_MULTI)
+ {
+ *flagp = flags;
+ return ret;
+ }
+ /* default flags */
+ *flagp = (WORST | SPSTART | (flags & (HASNL | HASLOOKBH)));
+
+ skipchr();
+ switch (op)
+ {
+ case Magic('*'):
+ if (flags & SIMPLE)
+ reginsert(STAR, ret);
+ else
+ {
+ /* Emit x* as (x&|), where & means "self". */
+ reginsert(BRANCH, ret); /* Either x */
+ regoptail(ret, regnode(BACK)); /* and loop */
+ regoptail(ret, ret); /* back */
+ regtail(ret, regnode(BRANCH)); /* or */
+ regtail(ret, regnode(NOTHING)); /* null. */
+ }
+ break;
+
+ case Magic('+'):
+ if (flags & SIMPLE)
+ reginsert(PLUS, ret);
+ else
+ {
+ /* Emit x+ as x(&|), where & means "self". */
+ next = regnode(BRANCH); /* Either */
+ regtail(ret, next);
+ regtail(regnode(BACK), ret); /* loop back */
+ regtail(next, regnode(BRANCH)); /* or */
+ regtail(ret, regnode(NOTHING)); /* null. */
+ }
+ *flagp = (WORST | HASWIDTH | (flags & (HASNL | HASLOOKBH)));
+ break;
+
+ case Magic('@'):
+ {
+ int lop = END;
+ long nr;
+
+ nr = getdecchrs();
+ switch (no_Magic(getchr()))
+ {
+ case '=': lop = MATCH; break; /* \@= */
+ case '!': lop = NOMATCH; break; /* \@! */
+ case '>': lop = SUBPAT; break; /* \@> */
+ case '<': switch (no_Magic(getchr()))
+ {
+ case '=': lop = BEHIND; break; /* \@<= */
+ case '!': lop = NOBEHIND; break; /* \@<! */
+ }
+ }
+ if (lop == END)
+ EMSG2_RET_NULL(_("E59: invalid character after %s@"),
+ reg_magic == MAGIC_ALL);
+ /* Look behind must match with behind_pos. */
+ if (lop == BEHIND || lop == NOBEHIND)
+ {
+ regtail(ret, regnode(BHPOS));
+ *flagp |= HASLOOKBH;
+ }
+ regtail(ret, regnode(END)); /* operand ends */
+ if (lop == BEHIND || lop == NOBEHIND)
+ {
+ if (nr < 0)
+ nr = 0; /* no limit is same as zero limit */
+ reginsert_nr(lop, nr, ret);
+ }
+ else
+ reginsert(lop, ret);
+ break;
+ }
+
+ case Magic('?'):
+ case Magic('='):
+ /* Emit x= as (x|) */
+ reginsert(BRANCH, ret); /* Either x */
+ regtail(ret, regnode(BRANCH)); /* or */
+ next = regnode(NOTHING); /* null. */
+ regtail(ret, next);
+ regoptail(ret, next);
+ break;
+
+ case Magic('{'):
+ if (!read_limits(&minval, &maxval))
+ return NULL;
+ if (flags & SIMPLE)
+ {
+ reginsert(BRACE_SIMPLE, ret);
+ reginsert_limits(BRACE_LIMITS, minval, maxval, ret);
+ }
+ else
+ {
+ if (num_complex_braces >= 10)
+ EMSG2_RET_NULL(_("E60: Too many complex %s{...}s"),
+ reg_magic == MAGIC_ALL);
+ reginsert(BRACE_COMPLEX + num_complex_braces, ret);
+ regoptail(ret, regnode(BACK));
+ regoptail(ret, ret);
+ reginsert_limits(BRACE_LIMITS, minval, maxval, ret);
+ ++num_complex_braces;
+ }
+ if (minval > 0 && maxval > 0)
+ *flagp = (HASWIDTH | (flags & (HASNL | HASLOOKBH)));
+ break;
+ }
+ if (re_multi_type(peekchr()) != NOT_MULTI)
+ {
+ // Can't have a multi follow a multi.
+ if (peekchr() == Magic('*'))
+ EMSG2_RET_NULL(_("E61: Nested %s*"), reg_magic >= MAGIC_ON);
+ EMSG3_RET_NULL(_("E62: Nested %s%c"), reg_magic == MAGIC_ALL,
+ no_Magic(peekchr()));
+ }
+
+ return ret;
+}
+
+/* When making changes to classchars also change nfa_classcodes. */
+static char_u *classchars = (char_u *)".iIkKfFpPsSdDxXoOwWhHaAlLuU";
+static int classcodes[] = {
+ ANY, IDENT, SIDENT, KWORD, SKWORD,
+ FNAME, SFNAME, PRINT, SPRINT,
+ WHITE, NWHITE, DIGIT, NDIGIT,
+ HEX, NHEX, OCTAL, NOCTAL,
+ WORD, NWORD, HEAD, NHEAD,
+ ALPHA, NALPHA, LOWER, NLOWER,
+ UPPER, NUPPER
+};
+
+/*
+ * Parse the lowest level.
+ *
+ * Optimization: gobbles an entire sequence of ordinary characters so that
+ * it can turn them into a single node, which is smaller to store and
+ * faster to run. Don't do this when one_exactly is set.
+ */
+ static char_u *
+regatom(int *flagp)
+{
+ char_u *ret;
+ int flags;
+ int c;
+ char_u *p;
+ int extra = 0;
+ int save_prev_at_start = prev_at_start;
+
+ *flagp = WORST; /* Tentatively. */
+
+ c = getchr();
+ switch (c)
+ {
+ case Magic('^'):
+ ret = regnode(BOL);
+ break;
+
+ case Magic('$'):
+ ret = regnode(EOL);
+#if defined(FEAT_SYN_HL) || defined(PROTO)
+ had_eol = TRUE;
+#endif
+ break;
+
+ case Magic('<'):
+ ret = regnode(BOW);
+ break;
+
+ case Magic('>'):
+ ret = regnode(EOW);
+ break;
+
+ case Magic('_'):
+ c = no_Magic(getchr());
+ if (c == '^') /* "\_^" is start-of-line */
+ {
+ ret = regnode(BOL);
+ break;
+ }
+ if (c == '$') /* "\_$" is end-of-line */
+ {
+ ret = regnode(EOL);
+#if defined(FEAT_SYN_HL) || defined(PROTO)
+ had_eol = TRUE;
+#endif
+ break;
+ }
+
+ extra = ADD_NL;
+ *flagp |= HASNL;
+
+ /* "\_[" is character range plus newline */
+ if (c == '[')
+ goto collection;
+
+ /* "\_x" is character class plus newline */
+ /* FALLTHROUGH */
+
+ /*
+ * Character classes.
+ */
+ case Magic('.'):
+ case Magic('i'):
+ case Magic('I'):
+ case Magic('k'):
+ case Magic('K'):
+ case Magic('f'):
+ case Magic('F'):
+ case Magic('p'):
+ case Magic('P'):
+ case Magic('s'):
+ case Magic('S'):
+ case Magic('d'):
+ case Magic('D'):
+ case Magic('x'):
+ case Magic('X'):
+ case Magic('o'):
+ case Magic('O'):
+ case Magic('w'):
+ case Magic('W'):
+ case Magic('h'):
+ case Magic('H'):
+ case Magic('a'):
+ case Magic('A'):
+ case Magic('l'):
+ case Magic('L'):
+ case Magic('u'):
+ case Magic('U'):
+ p = vim_strchr(classchars, no_Magic(c));
+ if (p == NULL)
+ EMSG_RET_NULL(_("E63: invalid use of \\_"));
+
+ /* When '.' is followed by a composing char ignore the dot, so that
+ * the composing char is matched here. */
+ if (enc_utf8 && c == Magic('.') && utf_iscomposing(peekchr()))
+ {
+ c = getchr();
+ goto do_multibyte;
+ }
+ ret = regnode(classcodes[p - classchars] + extra);
+ *flagp |= HASWIDTH | SIMPLE;
+ break;
+
+ case Magic('n'):
+ if (reg_string)
+ {
+ /* In a string "\n" matches a newline character. */
+ ret = regnode(EXACTLY);
+ regc(NL);
+ regc(NUL);
+ *flagp |= HASWIDTH | SIMPLE;
+ }
+ else
+ {
+ /* In buffer text "\n" matches the end of a line. */
+ ret = regnode(NEWL);
+ *flagp |= HASWIDTH | HASNL;
+ }
+ break;
+
+ case Magic('('):
+ if (one_exactly)
+ EMSG_ONE_RET_NULL;
+ ret = reg(REG_PAREN, &flags);
+ if (ret == NULL)
+ return NULL;
+ *flagp |= flags & (HASWIDTH | SPSTART | HASNL | HASLOOKBH);
+ break;
+
+ case NUL:
+ case Magic('|'):
+ case Magic('&'):
+ case Magic(')'):
+ if (one_exactly)
+ EMSG_ONE_RET_NULL;
+ IEMSG_RET_NULL(_(e_internal)); /* Supposed to be caught earlier. */
+ /* NOTREACHED */
+
+ case Magic('='):
+ case Magic('?'):
+ case Magic('+'):
+ case Magic('@'):
+ case Magic('{'):
+ case Magic('*'):
+ c = no_Magic(c);
+ EMSG3_RET_NULL(_("E64: %s%c follows nothing"),
+ (c == '*' ? reg_magic >= MAGIC_ON : reg_magic == MAGIC_ALL), c);
+ /* NOTREACHED */
+
+ case Magic('~'): /* previous substitute pattern */
+ if (reg_prev_sub != NULL)
+ {
+ char_u *lp;
+
+ ret = regnode(EXACTLY);
+ lp = reg_prev_sub;
+ while (*lp != NUL)
+ regc(*lp++);
+ regc(NUL);
+ if (*reg_prev_sub != NUL)
+ {
+ *flagp |= HASWIDTH;
+ if ((lp - reg_prev_sub) == 1)
+ *flagp |= SIMPLE;
+ }
+ }
+ else
+ EMSG_RET_NULL(_(e_nopresub));
+ break;
+
+ case Magic('1'):
+ case Magic('2'):
+ case Magic('3'):
+ case Magic('4'):
+ case Magic('5'):
+ case Magic('6'):
+ case Magic('7'):
+ case Magic('8'):
+ case Magic('9'):
+ {
+ int refnum;
+
+ refnum = c - Magic('0');
+ if (!seen_endbrace(refnum))
+ return NULL;
+ ret = regnode(BACKREF + refnum);
+ }
+ break;
+
+ case Magic('z'):
+ {
+ c = no_Magic(getchr());
+ switch (c)
+ {
+#ifdef FEAT_SYN_HL
+ case '(': if ((reg_do_extmatch & REX_SET) == 0)
+ EMSG_RET_NULL(_(e_z_not_allowed));
+ if (one_exactly)
+ EMSG_ONE_RET_NULL;
+ ret = reg(REG_ZPAREN, &flags);
+ if (ret == NULL)
+ return NULL;
+ *flagp |= flags & (HASWIDTH|SPSTART|HASNL|HASLOOKBH);
+ re_has_z = REX_SET;
+ break;
+
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': if ((reg_do_extmatch & REX_USE) == 0)
+ EMSG_RET_NULL(_(e_z1_not_allowed));
+ ret = regnode(ZREF + c - '0');
+ re_has_z = REX_USE;
+ break;
+#endif
+
+ case 's': ret = regnode(MOPEN + 0);
+ if (re_mult_next("\\zs") == FAIL)
+ return NULL;
+ break;
+
+ case 'e': ret = regnode(MCLOSE + 0);
+ if (re_mult_next("\\ze") == FAIL)
+ return NULL;
+ break;
+
+ default: EMSG_RET_NULL(_("E68: Invalid character after \\z"));
+ }
+ }
+ break;
+
+ case Magic('%'):
+ {
+ c = no_Magic(getchr());
+ switch (c)
+ {
+ /* () without a back reference */
+ case '(':
+ if (one_exactly)
+ EMSG_ONE_RET_NULL;
+ ret = reg(REG_NPAREN, &flags);
+ if (ret == NULL)
+ return NULL;
+ *flagp |= flags & (HASWIDTH | SPSTART | HASNL | HASLOOKBH);
+ break;
+
+ /* Catch \%^ and \%$ regardless of where they appear in the
+ * pattern -- regardless of whether or not it makes sense. */
+ case '^':
+ ret = regnode(RE_BOF);
+ break;
+
+ case '$':
+ ret = regnode(RE_EOF);
+ break;
+
+ case '#':
+ ret = regnode(CURSOR);
+ break;
+
+ case 'V':
+ ret = regnode(RE_VISUAL);
+ break;
+
+ case 'C':
+ ret = regnode(RE_COMPOSING);
+ break;
+
+ /* \%[abc]: Emit as a list of branches, all ending at the last
+ * branch which matches nothing. */
+ case '[':
+ if (one_exactly) /* doesn't nest */
+ EMSG_ONE_RET_NULL;
+ {
+ char_u *lastbranch;
+ char_u *lastnode = NULL;
+ char_u *br;
+
+ ret = NULL;
+ while ((c = getchr()) != ']')
+ {
+ if (c == NUL)
+ EMSG2_RET_NULL(_(e_missing_sb),
+ reg_magic == MAGIC_ALL);
+ br = regnode(BRANCH);
+ if (ret == NULL)
+ ret = br;
+ else
+ regtail(lastnode, br);
+
+ ungetchr();
+ one_exactly = TRUE;
+ lastnode = regatom(flagp);
+ one_exactly = FALSE;
+ if (lastnode == NULL)
+ return NULL;
+ }
+ if (ret == NULL)
+ EMSG2_RET_NULL(_(e_empty_sb),
+ reg_magic == MAGIC_ALL);
+ lastbranch = regnode(BRANCH);
+ br = regnode(NOTHING);
+ if (ret != JUST_CALC_SIZE)
+ {
+ regtail(lastnode, br);
+ regtail(lastbranch, br);
+ /* connect all branches to the NOTHING
+ * branch at the end */
+ for (br = ret; br != lastnode; )
+ {
+ if (OP(br) == BRANCH)
+ {
+ regtail(br, lastbranch);
+ br = OPERAND(br);
+ }
+ else
+ br = regnext(br);
+ }
+ }
+ *flagp &= ~(HASWIDTH | SIMPLE);
+ break;
+ }
+
+ case 'd': /* %d123 decimal */
+ case 'o': /* %o123 octal */
+ case 'x': /* %xab hex 2 */
+ case 'u': /* %uabcd hex 4 */
+ case 'U': /* %U1234abcd hex 8 */
+ {
+ long i;
+
+ switch (c)
+ {
+ case 'd': i = getdecchrs(); break;
+ case 'o': i = getoctchrs(); break;
+ case 'x': i = gethexchrs(2); break;
+ case 'u': i = gethexchrs(4); break;
+ case 'U': i = gethexchrs(8); break;
+ default: i = -1; break;
+ }
+
+ if (i < 0)
+ EMSG2_RET_NULL(
+ _("E678: Invalid character after %s%%[dxouU]"),
+ reg_magic == MAGIC_ALL);
+ if (use_multibytecode(i))
+ ret = regnode(MULTIBYTECODE);
+ else
+ ret = regnode(EXACTLY);
+ if (i == 0)
+ regc(0x0a);
+ else
+ regmbc(i);
+ regc(NUL);
+ *flagp |= HASWIDTH;
+ break;
+ }
+
+ default:
+ if (VIM_ISDIGIT(c) || c == '<' || c == '>'
+ || c == '\'')
+ {
+ long_u n = 0;
+ int cmp;
+
+ cmp = c;
+ if (cmp == '<' || cmp == '>')
+ c = getchr();
+ while (VIM_ISDIGIT(c))
+ {
+ n = n * 10 + (c - '0');
+ c = getchr();
+ }
+ if (c == '\'' && n == 0)
+ {
+ /* "\%'m", "\%<'m" and "\%>'m": Mark */
+ c = getchr();
+ ret = regnode(RE_MARK);
+ if (ret == JUST_CALC_SIZE)
+ regsize += 2;
+ else
+ {
+ *regcode++ = c;
+ *regcode++ = cmp;
+ }
+ break;
+ }
+ else if (c == 'l' || c == 'c' || c == 'v')
+ {
+ if (c == 'l')
+ {
+ ret = regnode(RE_LNUM);
+ if (save_prev_at_start)
+ at_start = TRUE;
+ }
+ else if (c == 'c')
+ ret = regnode(RE_COL);
+ else
+ ret = regnode(RE_VCOL);
+ if (ret == JUST_CALC_SIZE)
+ regsize += 5;
+ else
+ {
+ /* put the number and the optional
+ * comparator after the opcode */
+ regcode = re_put_long(regcode, n);
+ *regcode++ = cmp;
+ }
+ break;
+ }
+ }
+
+ EMSG2_RET_NULL(_("E71: Invalid character after %s%%"),
+ reg_magic == MAGIC_ALL);
+ }
+ }
+ break;
+
+ case Magic('['):
+collection:
+ {
+ char_u *lp;
+
+ /*
+ * If there is no matching ']', we assume the '[' is a normal
+ * character. This makes 'incsearch' and ":help [" work.
+ */
+ lp = skip_anyof(regparse);
+ if (*lp == ']') /* there is a matching ']' */
+ {
+ int startc = -1; /* > 0 when next '-' is a range */
+ int endc;
+
+ /*
+ * In a character class, different parsing rules apply.
+ * Not even \ is special anymore, nothing is.
+ */
+ if (*regparse == '^') /* Complement of range. */
+ {
+ ret = regnode(ANYBUT + extra);
+ regparse++;
+ }
+ else
+ ret = regnode(ANYOF + extra);
+
+ /* At the start ']' and '-' mean the literal character. */
+ if (*regparse == ']' || *regparse == '-')
+ {
+ startc = *regparse;
+ regc(*regparse++);
+ }
+
+ while (*regparse != NUL && *regparse != ']')
+ {
+ if (*regparse == '-')
+ {
+ ++regparse;
+ /* The '-' is not used for a range at the end and
+ * after or before a '\n'. */
+ if (*regparse == ']' || *regparse == NUL
+ || startc == -1
+ || (regparse[0] == '\\' && regparse[1] == 'n'))
+ {
+ regc('-');
+ startc = '-'; /* [--x] is a range */
+ }
+ else
+ {
+ /* Also accept "a-[.z.]" */
+ endc = 0;
+ if (*regparse == '[')
+ endc = get_coll_element(&regparse);
+ if (endc == 0)
+ {
+ if (has_mbyte)
+ endc = mb_ptr2char_adv(&regparse);
+ else
+ endc = *regparse++;
+ }
+
+ /* Handle \o40, \x20 and \u20AC style sequences */
+ if (endc == '\\' && !reg_cpo_lit && !reg_cpo_bsl)
+ endc = coll_get_char();
+
+ if (startc > endc)
+ EMSG_RET_NULL(_(e_reverse_range));
+ if (has_mbyte && ((*mb_char2len)(startc) > 1
+ || (*mb_char2len)(endc) > 1))
+ {
+ /* Limit to a range of 256 chars. */
+ if (endc > startc + 256)
+ EMSG_RET_NULL(_(e_large_class));
+ while (++startc <= endc)
+ regmbc(startc);
+ }
+ else
+ {
+#ifdef EBCDIC
+ int alpha_only = FALSE;
+
+ /* for alphabetical range skip the gaps
+ * 'i'-'j', 'r'-'s', 'I'-'J' and 'R'-'S'. */
+ if (isalpha(startc) && isalpha(endc))
+ alpha_only = TRUE;
+#endif
+ while (++startc <= endc)
+#ifdef EBCDIC
+ if (!alpha_only || isalpha(startc))
+#endif
+ regc(startc);
+ }
+ startc = -1;
+ }
+ }
+ /*
+ * Only "\]", "\^", "\]" and "\\" are special in Vi. Vim
+ * accepts "\t", "\e", etc., but only when the 'l' flag in
+ * 'cpoptions' is not included.
+ * Posix doesn't recognize backslash at all.
+ */
+ else if (*regparse == '\\'
+ && !reg_cpo_bsl
+ && (vim_strchr(REGEXP_INRANGE, regparse[1]) != NULL
+ || (!reg_cpo_lit
+ && vim_strchr(REGEXP_ABBR,
+ regparse[1]) != NULL)))
+ {
+ regparse++;
+ if (*regparse == 'n')
+ {
+ /* '\n' in range: also match NL */
+ if (ret != JUST_CALC_SIZE)
+ {
+ /* Using \n inside [^] does not change what
+ * matches. "[^\n]" is the same as ".". */
+ if (*ret == ANYOF)
+ {
+ *ret = ANYOF + ADD_NL;
+ *flagp |= HASNL;
+ }
+ /* else: must have had a \n already */
+ }
+ regparse++;
+ startc = -1;
+ }
+ else if (*regparse == 'd'
+ || *regparse == 'o'
+ || *regparse == 'x'
+ || *regparse == 'u'
+ || *regparse == 'U')
+ {
+ startc = coll_get_char();
+ if (startc == 0)
+ regc(0x0a);
+ else
+ regmbc(startc);
+ }
+ else
+ {
+ startc = backslash_trans(*regparse++);
+ regc(startc);
+ }
+ }
+ else if (*regparse == '[')
+ {
+ int c_class;
+ int cu;
+
+ c_class = get_char_class(&regparse);
+ startc = -1;
+ /* Characters assumed to be 8 bits! */
+ switch (c_class)
+ {
+ case CLASS_NONE:
+ c_class = get_equi_class(&regparse);
+ if (c_class != 0)
+ {
+ /* produce equivalence class */
+ reg_equi_class(c_class);
+ }
+ else if ((c_class =
+ get_coll_element(&regparse)) != 0)
+ {
+ /* produce a collating element */
+ regmbc(c_class);
+ }
+ else
+ {
+ /* literal '[', allow [[-x] as a range */
+ startc = *regparse++;
+ regc(startc);
+ }
+ break;
+ case CLASS_ALNUM:
+ for (cu = 1; cu < 128; cu++)
+ if (isalnum(cu))
+ regmbc(cu);
+ break;
+ case CLASS_ALPHA:
+ for (cu = 1; cu < 128; cu++)
+ if (isalpha(cu))
+ regmbc(cu);
+ break;
+ case CLASS_BLANK:
+ regc(' ');
+ regc('\t');
+ break;
+ case CLASS_CNTRL:
+ for (cu = 1; cu <= 127; cu++)
+ if (iscntrl(cu))
+ regmbc(cu);
+ break;
+ case CLASS_DIGIT:
+ for (cu = 1; cu <= 127; cu++)
+ if (VIM_ISDIGIT(cu))
+ regmbc(cu);
+ break;
+ case CLASS_GRAPH:
+ for (cu = 1; cu <= 127; cu++)
+ if (isgraph(cu))
+ regmbc(cu);
+ break;
+ case CLASS_LOWER:
+ for (cu = 1; cu <= 255; cu++)
+ if (MB_ISLOWER(cu) && cu != 170
+ && cu != 186)
+ regmbc(cu);
+ break;
+ case CLASS_PRINT:
+ for (cu = 1; cu <= 255; cu++)
+ if (vim_isprintc(cu))
+ regmbc(cu);
+ break;
+ case CLASS_PUNCT:
+ for (cu = 1; cu < 128; cu++)
+ if (ispunct(cu))
+ regmbc(cu);
+ break;
+ case CLASS_SPACE:
+ for (cu = 9; cu <= 13; cu++)
+ regc(cu);
+ regc(' ');
+ break;
+ case CLASS_UPPER:
+ for (cu = 1; cu <= 255; cu++)
+ if (MB_ISUPPER(cu))
+ regmbc(cu);
+ break;
+ case CLASS_XDIGIT:
+ for (cu = 1; cu <= 255; cu++)
+ if (vim_isxdigit(cu))
+ regmbc(cu);
+ break;
+ case CLASS_TAB:
+ regc('\t');
+ break;
+ case CLASS_RETURN:
+ regc('\r');
+ break;
+ case CLASS_BACKSPACE:
+ regc('\b');
+ break;
+ case CLASS_ESCAPE:
+ regc('\033');
+ break;
+ case CLASS_IDENT:
+ for (cu = 1; cu <= 255; cu++)
+ if (vim_isIDc(cu))
+ regmbc(cu);
+ break;
+ case CLASS_KEYWORD:
+ for (cu = 1; cu <= 255; cu++)
+ if (reg_iswordc(cu))
+ regmbc(cu);
+ break;
+ case CLASS_FNAME:
+ for (cu = 1; cu <= 255; cu++)
+ if (vim_isfilec(cu))
+ regmbc(cu);
+ break;
+ }
+ }
+ else
+ {
+ if (has_mbyte)
+ {
+ int len;
+
+ /* produce a multibyte character, including any
+ * following composing characters */
+ startc = mb_ptr2char(regparse);
+ len = (*mb_ptr2len)(regparse);
+ if (enc_utf8 && utf_char2len(startc) != len)
+ startc = -1; /* composing chars */
+ while (--len >= 0)
+ regc(*regparse++);
+ }
+ else
+ {
+ startc = *regparse++;
+ regc(startc);
+ }
+ }
+ }
+ regc(NUL);
+ prevchr_len = 1; /* last char was the ']' */
+ if (*regparse != ']')
+ EMSG_RET_NULL(_(e_toomsbra)); /* Cannot happen? */
+ skipchr(); /* let's be friends with the lexer again */
+ *flagp |= HASWIDTH | SIMPLE;
+ break;
+ }
+ else if (reg_strict)
+ EMSG2_RET_NULL(_(e_missingbracket), reg_magic > MAGIC_OFF);
+ }
+ /* FALLTHROUGH */
+
+ default:
+ {
+ int len;
+
+ /* A multi-byte character is handled as a separate atom if it's
+ * before a multi and when it's a composing char. */
+ if (use_multibytecode(c))
+ {
+do_multibyte:
+ ret = regnode(MULTIBYTECODE);
+ regmbc(c);
+ *flagp |= HASWIDTH | SIMPLE;
+ break;
+ }
+
+ ret = regnode(EXACTLY);
+
+ /*
+ * Append characters as long as:
+ * - there is no following multi, we then need the character in
+ * front of it as a single character operand
+ * - not running into a Magic character
+ * - "one_exactly" is not set
+ * But always emit at least one character. Might be a Multi,
+ * e.g., a "[" without matching "]".
+ */
+ for (len = 0; c != NUL && (len == 0
+ || (re_multi_type(peekchr()) == NOT_MULTI
+ && !one_exactly
+ && !is_Magic(c))); ++len)
+ {
+ c = no_Magic(c);
+ if (has_mbyte)
+ {
+ regmbc(c);
+ if (enc_utf8)
+ {
+ int l;
+
+ /* Need to get composing character too. */
+ for (;;)
+ {
+ l = utf_ptr2len(regparse);
+ if (!UTF_COMPOSINGLIKE(regparse, regparse + l))
+ break;
+ regmbc(utf_ptr2char(regparse));
+ skipchr();
+ }
+ }
+ }
+ else
+ regc(c);
+ c = getchr();
+ }
+ ungetchr();
+
+ regc(NUL);
+ *flagp |= HASWIDTH;
+ if (len == 1)
+ *flagp |= SIMPLE;
+ }
+ break;
+ }
+
+ return ret;
+}
+
+/*
+ * Return TRUE if MULTIBYTECODE should be used instead of EXACTLY for
+ * character "c".
+ */
+ static int
+use_multibytecode(int c)
+{
+ return has_mbyte && (*mb_char2len)(c) > 1
+ && (re_multi_type(peekchr()) != NOT_MULTI
+ || (enc_utf8 && utf_iscomposing(c)));
+}
+
+/*
+ * Emit a node.
+ * Return pointer to generated code.
+ */
+ static char_u *
+regnode(int op)
+{
+ char_u *ret;
+
+ ret = regcode;
+ if (ret == JUST_CALC_SIZE)
+ regsize += 3;
+ else
+ {
+ *regcode++ = op;
+ *regcode++ = NUL; /* Null "next" pointer. */
+ *regcode++ = NUL;
+ }
+ return ret;
+}
+
+/*
+ * Emit (if appropriate) a byte of code
+ */
+ static void
+regc(int b)
+{
+ if (regcode == JUST_CALC_SIZE)
+ regsize++;
+ else
+ *regcode++ = b;
+}
+
+/*
+ * Emit (if appropriate) a multi-byte character of code
+ */
+ static void
+regmbc(int c)
+{
+ if (!has_mbyte && c > 0xff)
+ return;
+ if (regcode == JUST_CALC_SIZE)
+ regsize += (*mb_char2len)(c);
+ else
+ regcode += (*mb_char2bytes)(c, regcode);
+}
+
+/*
+ * Insert an operator in front of already-emitted operand
+ *
+ * Means relocating the operand.
+ */
+ static void
+reginsert(int op, char_u *opnd)
+{
+ char_u *src;
+ char_u *dst;
+ char_u *place;
+
+ if (regcode == JUST_CALC_SIZE)
+ {
+ regsize += 3;
+ return;
+ }
+ src = regcode;
+ regcode += 3;
+ dst = regcode;
+ while (src > opnd)
+ *--dst = *--src;
+
+ place = opnd; /* Op node, where operand used to be. */
+ *place++ = op;
+ *place++ = NUL;
+ *place = NUL;
+}
+
+/*
+ * Insert an operator in front of already-emitted operand.
+ * Add a number to the operator.
+ */
+ static void
+reginsert_nr(int op, long val, char_u *opnd)
+{
+ char_u *src;
+ char_u *dst;
+ char_u *place;
+
+ if (regcode == JUST_CALC_SIZE)
+ {
+ regsize += 7;
+ return;
+ }
+ src = regcode;
+ regcode += 7;
+ dst = regcode;
+ while (src > opnd)
+ *--dst = *--src;
+
+ place = opnd; /* Op node, where operand used to be. */
+ *place++ = op;
+ *place++ = NUL;
+ *place++ = NUL;
+ place = re_put_long(place, (long_u)val);
+}
+
+/*
+ * Insert an operator in front of already-emitted operand.
+ * The operator has the given limit values as operands. Also set next pointer.
+ *
+ * Means relocating the operand.
+ */
+ static void
+reginsert_limits(
+ int op,
+ long minval,
+ long maxval,
+ char_u *opnd)
+{
+ char_u *src;
+ char_u *dst;
+ char_u *place;
+
+ if (regcode == JUST_CALC_SIZE)
+ {
+ regsize += 11;
+ return;
+ }
+ src = regcode;
+ regcode += 11;
+ dst = regcode;
+ while (src > opnd)
+ *--dst = *--src;
+
+ place = opnd; /* Op node, where operand used to be. */
+ *place++ = op;
+ *place++ = NUL;
+ *place++ = NUL;
+ place = re_put_long(place, (long_u)minval);
+ place = re_put_long(place, (long_u)maxval);
+ regtail(opnd, place);
+}
+
+/*
+ * Write a long as four bytes at "p" and return pointer to the next char.
+ */
+ static char_u *
+re_put_long(char_u *p, long_u val)
+{
+ *p++ = (char_u) ((val >> 24) & 0377);
+ *p++ = (char_u) ((val >> 16) & 0377);
+ *p++ = (char_u) ((val >> 8) & 0377);
+ *p++ = (char_u) (val & 0377);
+ return p;
+}
+
+/*
+ * Set the next-pointer at the end of a node chain.
+ */
+ static void
+regtail(char_u *p, char_u *val)
+{
+ char_u *scan;
+ char_u *temp;
+ int offset;
+
+ if (p == JUST_CALC_SIZE)
+ return;
+
+ /* Find last node. */
+ scan = p;
+ for (;;)
+ {
+ temp = regnext(scan);
+ if (temp == NULL)
+ break;
+ scan = temp;
+ }
+
+ if (OP(scan) == BACK)
+ offset = (int)(scan - val);
+ else
+ offset = (int)(val - scan);
+ /* When the offset uses more than 16 bits it can no longer fit in the two
+ * bytes available. Use a global flag to avoid having to check return
+ * values in too many places. */
+ if (offset > 0xffff)
+ reg_toolong = TRUE;
+ else
+ {
+ *(scan + 1) = (char_u) (((unsigned)offset >> 8) & 0377);
+ *(scan + 2) = (char_u) (offset & 0377);
+ }
+}
+
+/*
+ * Like regtail, on item after a BRANCH; nop if none.
+ */
+ static void
+regoptail(char_u *p, char_u *val)
+{
+ /* When op is neither BRANCH nor BRACE_COMPLEX0-9, it is "operandless" */
+ if (p == NULL || p == JUST_CALC_SIZE
+ || (OP(p) != BRANCH
+ && (OP(p) < BRACE_COMPLEX || OP(p) > BRACE_COMPLEX + 9)))
+ return;
+ regtail(OPERAND(p), val);
+}
+
+/*
+ * Functions for getting characters from the regexp input.
+ */
+/*
+ * Start parsing at "str".
+ */
+ static void
+initchr(char_u *str)
+{
+ regparse = str;
+ prevchr_len = 0;
+ curchr = prevprevchr = prevchr = nextchr = -1;
+ at_start = TRUE;
+ prev_at_start = FALSE;
+}
+
+/*
+ * Save the current parse state, so that it can be restored and parsing
+ * starts in the same state again.
+ */
+ static void
+save_parse_state(parse_state_T *ps)
+{
+ ps->regparse = regparse;
+ ps->prevchr_len = prevchr_len;
+ ps->curchr = curchr;
+ ps->prevchr = prevchr;
+ ps->prevprevchr = prevprevchr;
+ ps->nextchr = nextchr;
+ ps->at_start = at_start;
+ ps->prev_at_start = prev_at_start;
+ ps->regnpar = regnpar;
+}
+
+/*
+ * Restore a previously saved parse state.
+ */
+ static void
+restore_parse_state(parse_state_T *ps)
+{
+ regparse = ps->regparse;
+ prevchr_len = ps->prevchr_len;
+ curchr = ps->curchr;
+ prevchr = ps->prevchr;
+ prevprevchr = ps->prevprevchr;
+ nextchr = ps->nextchr;
+ at_start = ps->at_start;
+ prev_at_start = ps->prev_at_start;
+ regnpar = ps->regnpar;
+}
+
+
+/*
+ * Get the next character without advancing.
+ */
+ static int
+peekchr(void)
+{
+ static int after_slash = FALSE;
+
+ if (curchr == -1)
+ {
+ switch (curchr = regparse[0])
+ {
+ case '.':
+ case '[':
+ case '~':
+ /* magic when 'magic' is on */
+ if (reg_magic >= MAGIC_ON)
+ curchr = Magic(curchr);
+ break;
+ case '(':
+ case ')':
+ case '{':
+ case '%':
+ case '+':
+ case '=':
+ case '?':
+ case '@':
+ case '!':
+ case '&':
+ case '|':
+ case '<':
+ case '>':
+ case '#': /* future ext. */
+ case '"': /* future ext. */
+ case '\'': /* future ext. */
+ case ',': /* future ext. */
+ case '-': /* future ext. */
+ case ':': /* future ext. */
+ case ';': /* future ext. */
+ case '`': /* future ext. */
+ case '/': /* Can't be used in / command */
+ /* magic only after "\v" */
+ if (reg_magic == MAGIC_ALL)
+ curchr = Magic(curchr);
+ break;
+ case '*':
+ /* * is not magic as the very first character, eg "?*ptr", when
+ * after '^', eg "/^*ptr" and when after "\(", "\|", "\&". But
+ * "\(\*" is not magic, thus must be magic if "after_slash" */
+ if (reg_magic >= MAGIC_ON
+ && !at_start
+ && !(prev_at_start && prevchr == Magic('^'))
+ && (after_slash
+ || (prevchr != Magic('(')
+ && prevchr != Magic('&')
+ && prevchr != Magic('|'))))
+ curchr = Magic('*');
+ break;
+ case '^':
+ /* '^' is only magic as the very first character and if it's after
+ * "\(", "\|", "\&' or "\n" */
+ if (reg_magic >= MAGIC_OFF
+ && (at_start
+ || reg_magic == MAGIC_ALL
+ || prevchr == Magic('(')
+ || prevchr == Magic('|')
+ || prevchr == Magic('&')
+ || prevchr == Magic('n')
+ || (no_Magic(prevchr) == '('
+ && prevprevchr == Magic('%'))))
+ {
+ curchr = Magic('^');
+ at_start = TRUE;
+ prev_at_start = FALSE;
+ }
+ break;
+ case '$':
+ /* '$' is only magic as the very last char and if it's in front of
+ * either "\|", "\)", "\&", or "\n" */
+ if (reg_magic >= MAGIC_OFF)
+ {
+ char_u *p = regparse + 1;
+ int is_magic_all = (reg_magic == MAGIC_ALL);
+
+ /* ignore \c \C \m \M \v \V and \Z after '$' */
+ while (p[0] == '\\' && (p[1] == 'c' || p[1] == 'C'
+ || p[1] == 'm' || p[1] == 'M'
+ || p[1] == 'v' || p[1] == 'V' || p[1] == 'Z'))
+ {
+ if (p[1] == 'v')
+ is_magic_all = TRUE;
+ else if (p[1] == 'm' || p[1] == 'M' || p[1] == 'V')
+ is_magic_all = FALSE;
+ p += 2;
+ }
+ if (p[0] == NUL
+ || (p[0] == '\\'
+ && (p[1] == '|' || p[1] == '&' || p[1] == ')'
+ || p[1] == 'n'))
+ || (is_magic_all
+ && (p[0] == '|' || p[0] == '&' || p[0] == ')'))
+ || reg_magic == MAGIC_ALL)
+ curchr = Magic('$');
+ }
+ break;
+ case '\\':
+ {
+ int c = regparse[1];
+
+ if (c == NUL)
+ curchr = '\\'; /* trailing '\' */
+ else if (
+#ifdef EBCDIC
+ vim_strchr(META, c)
+#else
+ c <= '~' && META_flags[c]
+#endif
+ )
+ {
+ /*
+ * META contains everything that may be magic sometimes,
+ * except ^ and $ ("\^" and "\$" are only magic after
+ * "\V"). We now fetch the next character and toggle its
+ * magicness. Therefore, \ is so meta-magic that it is
+ * not in META.
+ */
+ curchr = -1;
+ prev_at_start = at_start;
+ at_start = FALSE; /* be able to say "/\*ptr" */
+ ++regparse;
+ ++after_slash;
+ peekchr();
+ --regparse;
+ --after_slash;
+ curchr = toggle_Magic(curchr);
+ }
+ else if (vim_strchr(REGEXP_ABBR, c))
+ {
+ /*
+ * Handle abbreviations, like "\t" for TAB -- webb
+ */
+ curchr = backslash_trans(c);
+ }
+ else if (reg_magic == MAGIC_NONE && (c == '$' || c == '^'))
+ curchr = toggle_Magic(c);
+ else
+ {
+ /*
+ * Next character can never be (made) magic?
+ * Then backslashing it won't do anything.
+ */
+ if (has_mbyte)
+ curchr = (*mb_ptr2char)(regparse + 1);
+ else
+ curchr = c;
+ }
+ break;
+ }
+
+ default:
+ if (has_mbyte)
+ curchr = (*mb_ptr2char)(regparse);
+ }
+ }
+
+ return curchr;
+}
+
+/*
+ * Eat one lexed character. Do this in a way that we can undo it.
+ */
+ static void
+skipchr(void)
+{
+ /* peekchr() eats a backslash, do the same here */
+ if (*regparse == '\\')
+ prevchr_len = 1;
+ else
+ prevchr_len = 0;
+ if (regparse[prevchr_len] != NUL)
+ {
+ if (enc_utf8)
+ /* exclude composing chars that mb_ptr2len does include */
+ prevchr_len += utf_ptr2len(regparse + prevchr_len);
+ else if (has_mbyte)
+ prevchr_len += (*mb_ptr2len)(regparse + prevchr_len);
+ else
+ ++prevchr_len;
+ }
+ regparse += prevchr_len;
+ prev_at_start = at_start;
+ at_start = FALSE;
+ prevprevchr = prevchr;
+ prevchr = curchr;
+ curchr = nextchr; /* use previously unget char, or -1 */
+ nextchr = -1;
+}
+
+/*
+ * Skip a character while keeping the value of prev_at_start for at_start.
+ * prevchr and prevprevchr are also kept.
+ */
+ static void
+skipchr_keepstart(void)
+{
+ int as = prev_at_start;
+ int pr = prevchr;
+ int prpr = prevprevchr;
+
+ skipchr();
+ at_start = as;
+ prevchr = pr;
+ prevprevchr = prpr;
+}
+
+/*
+ * Get the next character from the pattern. We know about magic and such, so
+ * therefore we need a lexical analyzer.
+ */
+ static int
+getchr(void)
+{
+ int chr = peekchr();
+
+ skipchr();
+ return chr;
+}
+
+/*
+ * put character back. Works only once!
+ */
+ static void
+ungetchr(void)
+{
+ nextchr = curchr;
+ curchr = prevchr;
+ prevchr = prevprevchr;
+ at_start = prev_at_start;
+ prev_at_start = FALSE;
+
+ /* Backup regparse, so that it's at the same position as before the
+ * getchr(). */
+ regparse -= prevchr_len;
+}
+
+/*
+ * Get and return the value of the hex string at the current position.
+ * Return -1 if there is no valid hex number.
+ * The position is updated:
+ * blahblah\%x20asdf
+ * before-^ ^-after
+ * The parameter controls the maximum number of input characters. This will be
+ * 2 when reading a \%x20 sequence and 4 when reading a \%u20AC sequence.
+ */
+ static long
+gethexchrs(int maxinputlen)
+{
+ long_u nr = 0;
+ int c;
+ int i;
+
+ for (i = 0; i < maxinputlen; ++i)
+ {
+ c = regparse[0];
+ if (!vim_isxdigit(c))
+ break;
+ nr <<= 4;
+ nr |= hex2nr(c);
+ ++regparse;
+ }
+
+ if (i == 0)
+ return -1;
+ return (long)nr;
+}
+
+/*
+ * Get and return the value of the decimal string immediately after the
+ * current position. Return -1 for invalid. Consumes all digits.
+ */
+ static long
+getdecchrs(void)
+{
+ long_u nr = 0;
+ int c;
+ int i;
+
+ for (i = 0; ; ++i)
+ {
+ c = regparse[0];
+ if (c < '0' || c > '9')
+ break;
+ nr *= 10;
+ nr += c - '0';
+ ++regparse;
+ curchr = -1; /* no longer valid */
+ }
+
+ if (i == 0)
+ return -1;
+ return (long)nr;
+}
+
+/*
+ * get and return the value of the octal string immediately after the current
+ * position. Return -1 for invalid, or 0-255 for valid. Smart enough to handle
+ * numbers > 377 correctly (for example, 400 is treated as 40) and doesn't
+ * treat 8 or 9 as recognised characters. Position is updated:
+ * blahblah\%o210asdf
+ * before-^ ^-after
+ */
+ static long
+getoctchrs(void)
+{
+ long_u nr = 0;
+ int c;
+ int i;
+
+ for (i = 0; i < 3 && nr < 040; ++i)
+ {
+ c = regparse[0];
+ if (c < '0' || c > '7')
+ break;
+ nr <<= 3;
+ nr |= hex2nr(c);
+ ++regparse;
+ }
+
+ if (i == 0)
+ return -1;
+ return (long)nr;
+}
+
+/*
+ * Get a number after a backslash that is inside [].
+ * When nothing is recognized return a backslash.
+ */
+ static int
+coll_get_char(void)
+{
+ long nr = -1;
+
+ switch (*regparse++)
+ {
+ case 'd': nr = getdecchrs(); break;
+ case 'o': nr = getoctchrs(); break;
+ case 'x': nr = gethexchrs(2); break;
+ case 'u': nr = gethexchrs(4); break;
+ case 'U': nr = gethexchrs(8); break;
+ }
+ if (nr < 0)
+ {
+ /* If getting the number fails be backwards compatible: the character
+ * is a backslash. */
+ --regparse;
+ nr = '\\';
+ }
+ return nr;
+}
+
+/*
+ * read_limits - Read two integers to be taken as a minimum and maximum.
+ * If the first character is '-', then the range is reversed.
+ * Should end with 'end'. If minval is missing, zero is default, if maxval is
+ * missing, a very big number is the default.
+ */
+ static int
+read_limits(long *minval, long *maxval)
+{
+ int reverse = FALSE;
+ char_u *first_char;
+ long tmp;
+
+ if (*regparse == '-')
+ {
+ /* Starts with '-', so reverse the range later */
+ regparse++;
+ reverse = TRUE;
+ }
+ first_char = regparse;
+ *minval = getdigits(&regparse);
+ if (*regparse == ',') /* There is a comma */
+ {
+ if (vim_isdigit(*++regparse))
+ *maxval = getdigits(&regparse);
+ else
+ *maxval = MAX_LIMIT;
+ }
+ else if (VIM_ISDIGIT(*first_char))
+ *maxval = *minval; /* It was \{n} or \{-n} */
+ else
+ *maxval = MAX_LIMIT; /* It was \{} or \{-} */
+ if (*regparse == '\\')
+ regparse++; /* Allow either \{...} or \{...\} */
+ if (*regparse != '}')
+ EMSG2_RET_FAIL(_("E554: Syntax error in %s{...}"),
+ reg_magic == MAGIC_ALL);
+
+ /*
+ * Reverse the range if there was a '-', or make sure it is in the right
+ * order otherwise.
+ */
+ if ((!reverse && *minval > *maxval) || (reverse && *minval < *maxval))
+ {
+ tmp = *minval;
+ *minval = *maxval;
+ *maxval = tmp;
+ }
+ skipchr(); /* let's be friends with the lexer again */
+ return OK;
+}
+
+/*
+ * vim_regexec and friends
+ */
+
+/*
+ * Global work variables for vim_regexec().
+ */
+
+/*
+ * Structure used to save the current input state, when it needs to be
+ * restored after trying a match. Used by reg_save() and reg_restore().
+ * Also stores the length of "backpos".
+ */
+typedef struct
+{
+ union
+ {
+ char_u *ptr; /* rex.input pointer, for single-line regexp */
+ lpos_T pos; /* rex.input pos, for multi-line regexp */
+ } rs_u;
+ int rs_len;
+} regsave_T;
+
+/* struct to save start/end pointer/position in for \(\) */
+typedef struct
+{
+ union
+ {
+ char_u *ptr;
+ lpos_T pos;
+ } se_u;
+} save_se_T;
+
+/* used for BEHIND and NOBEHIND matching */
+typedef struct regbehind_S
+{
+ regsave_T save_after;
+ regsave_T save_behind;
+ int save_need_clear_subexpr;
+ save_se_T save_start[NSUBEXP];
+ save_se_T save_end[NSUBEXP];
+} regbehind_T;
+
+static long bt_regexec_both(char_u *line, colnr_T col, proftime_T *tm, int *timed_out);
+static long regtry(bt_regprog_T *prog, colnr_T col, proftime_T *tm, int *timed_out);
+static void cleanup_subexpr(void);
+#ifdef FEAT_SYN_HL
+static void cleanup_zsubexpr(void);
+#endif
+static void save_subexpr(regbehind_T *bp);
+static void restore_subexpr(regbehind_T *bp);
+static void reg_nextline(void);
+static void reg_save(regsave_T *save, garray_T *gap);
+static void reg_restore(regsave_T *save, garray_T *gap);
+static int reg_save_equal(regsave_T *save);
+static void save_se_multi(save_se_T *savep, lpos_T *posp);
+static void save_se_one(save_se_T *savep, char_u **pp);
+
+/* Save the sub-expressions before attempting a match. */
+#define save_se(savep, posp, pp) \
+ REG_MULTI ? save_se_multi((savep), (posp)) : save_se_one((savep), (pp))
+
+/* After a failed match restore the sub-expressions. */
+#define restore_se(savep, posp, pp) { \
+ if (REG_MULTI) \
+ *(posp) = (savep)->se_u.pos; \
+ else \
+ *(pp) = (savep)->se_u.ptr; }
+
+static int re_num_cmp(long_u val, char_u *scan);
+static int match_with_backref(linenr_T start_lnum, colnr_T start_col, linenr_T end_lnum, colnr_T end_col, int *bytelen);
+static int regmatch(char_u *prog, proftime_T *tm, int *timed_out);
+static int regrepeat(char_u *p, long maxcount);
+
+#ifdef DEBUG
+int regnarrate = 0;
+#endif
+
+/*
+ * Sometimes need to save a copy of a line. Since alloc()/free() is very
+ * slow, we keep one allocated piece of memory and only re-allocate it when
+ * it's too small. It's freed in bt_regexec_both() when finished.
+ */
+static char_u *reg_tofree = NULL;
+static unsigned reg_tofreelen;
+
+/*
+ * Structure used to store the execution state of the regex engine.
+ * Which ones are set depends on whether a single-line or multi-line match is
+ * done:
+ * single-line multi-line
+ * reg_match &regmatch_T NULL
+ * reg_mmatch NULL &regmmatch_T
+ * reg_startp reg_match->startp <invalid>
+ * reg_endp reg_match->endp <invalid>
+ * reg_startpos <invalid> reg_mmatch->startpos
+ * reg_endpos <invalid> reg_mmatch->endpos
+ * reg_win NULL window in which to search
+ * reg_buf curbuf buffer in which to search
+ * reg_firstlnum <invalid> first line in which to search
+ * reg_maxline 0 last line nr
+ * reg_line_lbr FALSE or TRUE FALSE
+ */
+typedef struct {
+ regmatch_T *reg_match;
+ regmmatch_T *reg_mmatch;
+ char_u **reg_startp;
+ char_u **reg_endp;
+ lpos_T *reg_startpos;
+ lpos_T *reg_endpos;
+ win_T *reg_win;
+ buf_T *reg_buf;
+ linenr_T reg_firstlnum;
+ linenr_T reg_maxline;
+ int reg_line_lbr; /* "\n" in string is line break */
+
+ // The current match-position is stord in these variables:
+ linenr_T lnum; // line number, relative to first line
+ char_u *line; // start of current line
+ char_u *input; // current input, points into "regline"
+
+ int need_clear_subexpr; // subexpressions still need to be cleared
+#ifdef FEAT_SYN_HL
+ int need_clear_zsubexpr; // extmatch subexpressions still need to be
+ // cleared
+#endif
+
+ /* Internal copy of 'ignorecase'. It is set at each call to vim_regexec().
+ * Normally it gets the value of "rm_ic" or "rmm_ic", but when the pattern
+ * contains '\c' or '\C' the value is overruled. */
+ int reg_ic;
+
+ /* Similar to "reg_ic", but only for 'combining' characters. Set with \Z
+ * flag in the regexp. Defaults to false, always. */
+ int reg_icombine;
+
+ /* Copy of "rmm_maxcol": maximum column to search for a match. Zero when
+ * there is no maximum. */
+ colnr_T reg_maxcol;
+
+ // State for the NFA engine regexec.
+ int nfa_has_zend; // NFA regexp \ze operator encountered.
+ int nfa_has_backref; // NFA regexp \1 .. \9 encountered.
+ int nfa_nsubexpr; // Number of sub expressions actually being used
+ // during execution. 1 if only the whole match
+ // (subexpr 0) is used.
+ // listid is global, so that it increases on recursive calls to
+ // nfa_regmatch(), which means we don't have to clear the lastlist field of
+ // all the states.
+ int nfa_listid;
+ int nfa_alt_listid;
+
+#ifdef FEAT_SYN_HL
+ int nfa_has_zsubexpr; // NFA regexp has \z( ), set zsubexpr.
+#endif
+} regexec_T;
+
+static regexec_T rex;
+static int rex_in_use = FALSE;
+
+
+/* Values for rs_state in regitem_T. */
+typedef enum regstate_E
+{
+ RS_NOPEN = 0 /* NOPEN and NCLOSE */
+ , RS_MOPEN /* MOPEN + [0-9] */
+ , RS_MCLOSE /* MCLOSE + [0-9] */
+#ifdef FEAT_SYN_HL
+ , RS_ZOPEN /* ZOPEN + [0-9] */
+ , RS_ZCLOSE /* ZCLOSE + [0-9] */
+#endif
+ , RS_BRANCH /* BRANCH */
+ , RS_BRCPLX_MORE /* BRACE_COMPLEX and trying one more match */
+ , RS_BRCPLX_LONG /* BRACE_COMPLEX and trying longest match */
+ , RS_BRCPLX_SHORT /* BRACE_COMPLEX and trying shortest match */
+ , RS_NOMATCH /* NOMATCH */
+ , RS_BEHIND1 /* BEHIND / NOBEHIND matching rest */
+ , RS_BEHIND2 /* BEHIND / NOBEHIND matching behind part */
+ , RS_STAR_LONG /* STAR/PLUS/BRACE_SIMPLE longest match */
+ , RS_STAR_SHORT /* STAR/PLUS/BRACE_SIMPLE shortest match */
+} regstate_T;
+
+/*
+ * When there are alternatives a regstate_T is put on the regstack to remember
+ * what we are doing.
+ * Before it may be another type of item, depending on rs_state, to remember
+ * more things.
+ */
+typedef struct regitem_S
+{
+ regstate_T rs_state; /* what we are doing, one of RS_ above */
+ char_u *rs_scan; /* current node in program */
+ union
+ {
+ save_se_T sesave;
+ regsave_T regsave;
+ } rs_un; /* room for saving rex.input */
+ short rs_no; /* submatch nr or BEHIND/NOBEHIND */
+} regitem_T;
+
+static regitem_T *regstack_push(regstate_T state, char_u *scan);
+static void regstack_pop(char_u **scan);
+
+/* used for STAR, PLUS and BRACE_SIMPLE matching */
+typedef struct regstar_S
+{
+ int nextb; /* next byte */
+ int nextb_ic; /* next byte reverse case */
+ long count;
+ long minval;
+ long maxval;
+} regstar_T;
+
+/* used to store input position when a BACK was encountered, so that we now if
+ * we made any progress since the last time. */
+typedef struct backpos_S
+{
+ char_u *bp_scan; /* "scan" where BACK was encountered */
+ regsave_T bp_pos; /* last input position */
+} backpos_T;
+
+/*
+ * "regstack" and "backpos" are used by regmatch(). They are kept over calls
+ * to avoid invoking malloc() and free() often.
+ * "regstack" is a stack with regitem_T items, sometimes preceded by regstar_T
+ * or regbehind_T.
+ * "backpos_T" is a table with backpos_T for BACK
+ */
+static garray_T regstack = {0, 0, 0, 0, NULL};
+static garray_T backpos = {0, 0, 0, 0, NULL};
+
+/*
+ * Both for regstack and backpos tables we use the following strategy of
+ * allocation (to reduce malloc/free calls):
+ * - Initial size is fairly small.
+ * - When needed, the tables are grown bigger (8 times at first, double after
+ * that).
+ * - After executing the match we free the memory only if the array has grown.
+ * Thus the memory is kept allocated when it's at the initial size.
+ * This makes it fast while not keeping a lot of memory allocated.
+ * A three times speed increase was observed when using many simple patterns.
+ */
+#define REGSTACK_INITIAL 2048
+#define BACKPOS_INITIAL 64
+
+#if defined(EXITFREE) || defined(PROTO)
+ void
+free_regexp_stuff(void)
+{
+ ga_clear(&regstack);
+ ga_clear(&backpos);
+ vim_free(reg_tofree);
+ vim_free(reg_prev_sub);
+}
+#endif
+
+/*
+ * Return TRUE if character 'c' is included in 'iskeyword' option for
+ * "reg_buf" buffer.
+ */
+ static int
+reg_iswordc(int c)
+{
+ return vim_iswordc_buf(c, rex.reg_buf);
+}
+
+/*
+ * Get pointer to the line "lnum", which is relative to "reg_firstlnum".
+ */
+ static char_u *
+reg_getline(linenr_T lnum)
+{
+ /* when looking behind for a match/no-match lnum is negative. But we
+ * can't go before line 1 */
+ if (rex.reg_firstlnum + lnum < 1)
+ return NULL;
+ if (lnum > rex.reg_maxline)
+ /* Must have matched the "\n" in the last line. */
+ return (char_u *)"";
+ return ml_get_buf(rex.reg_buf, rex.reg_firstlnum + lnum, FALSE);
+}
+
+static regsave_T behind_pos;
+
+#ifdef FEAT_SYN_HL
+static char_u *reg_startzp[NSUBEXP]; /* Workspace to mark beginning */
+static char_u *reg_endzp[NSUBEXP]; /* and end of \z(...\) matches */
+static lpos_T reg_startzpos[NSUBEXP]; /* idem, beginning pos */
+static lpos_T reg_endzpos[NSUBEXP]; /* idem, end pos */
+#endif
+
+/* TRUE if using multi-line regexp. */
+#define REG_MULTI (rex.reg_match == NULL)
+
+/*
+ * Match a regexp against a string.
+ * "rmp->regprog" is a compiled regexp as returned by vim_regcomp().
+ * Uses curbuf for line count and 'iskeyword'.
+ * if "line_lbr" is TRUE consider a "\n" in "line" to be a line break.
+ *
+ * Returns 0 for failure, number of lines contained in the match otherwise.
+ */
+ static int
+bt_regexec_nl(
+ regmatch_T *rmp,
+ char_u *line, /* string to match against */
+ colnr_T col, /* column to start looking for match */
+ int line_lbr)
+{
+ rex.reg_match = rmp;
+ rex.reg_mmatch = NULL;
+ rex.reg_maxline = 0;
+ rex.reg_line_lbr = line_lbr;
+ rex.reg_buf = curbuf;
+ rex.reg_win = NULL;
+ rex.reg_ic = rmp->rm_ic;
+ rex.reg_icombine = FALSE;
+ rex.reg_maxcol = 0;
+
+ return bt_regexec_both(line, col, NULL, NULL);
+}
+
+/*
+ * Match a regexp against multiple lines.
+ * "rmp->regprog" is a compiled regexp as returned by vim_regcomp().
+ * Uses curbuf for line count and 'iskeyword'.
+ *
+ * Return zero if there is no match. Return number of lines contained in the
+ * match otherwise.
+ */
+ static long
+bt_regexec_multi(
+ regmmatch_T *rmp,
+ win_T *win, /* window in which to search or NULL */
+ buf_T *buf, /* buffer in which to search */
+ linenr_T lnum, /* nr of line to start looking for match */
+ colnr_T col, /* column to start looking for match */
+ proftime_T *tm, /* timeout limit or NULL */
+ int *timed_out) /* flag set on timeout or NULL */
+{
+ rex.reg_match = NULL;
+ rex.reg_mmatch = rmp;
+ rex.reg_buf = buf;
+ rex.reg_win = win;
+ rex.reg_firstlnum = lnum;
+ rex.reg_maxline = rex.reg_buf->b_ml.ml_line_count - lnum;
+ rex.reg_line_lbr = FALSE;
+ rex.reg_ic = rmp->rmm_ic;
+ rex.reg_icombine = FALSE;
+ rex.reg_maxcol = rmp->rmm_maxcol;
+
+ return bt_regexec_both(NULL, col, tm, timed_out);
+}
+
+/*
+ * Match a regexp against a string ("line" points to the string) or multiple
+ * lines ("line" is NULL, use reg_getline()).
+ * Returns 0 for failure, number of lines contained in the match otherwise.
+ */
+ static long
+bt_regexec_both(
+ char_u *line,
+ colnr_T col, /* column to start looking for match */
+ proftime_T *tm, /* timeout limit or NULL */
+ int *timed_out) /* flag set on timeout or NULL */
+{
+ bt_regprog_T *prog;
+ char_u *s;
+ long retval = 0L;
+
+ /* Create "regstack" and "backpos" if they are not allocated yet.
+ * We allocate *_INITIAL amount of bytes first and then set the grow size
+ * to much bigger value to avoid many malloc calls in case of deep regular
+ * expressions. */
+ if (regstack.ga_data == NULL)
+ {
+ /* Use an item size of 1 byte, since we push different things
+ * onto the regstack. */
+ ga_init2(&regstack, 1, REGSTACK_INITIAL);
+ (void)ga_grow(&regstack, REGSTACK_INITIAL);
+ regstack.ga_growsize = REGSTACK_INITIAL * 8;
+ }
+
+ if (backpos.ga_data == NULL)
+ {
+ ga_init2(&backpos, sizeof(backpos_T), BACKPOS_INITIAL);
+ (void)ga_grow(&backpos, BACKPOS_INITIAL);
+ backpos.ga_growsize = BACKPOS_INITIAL * 8;
+ }
+
+ if (REG_MULTI)
+ {
+ prog = (bt_regprog_T *)rex.reg_mmatch->regprog;
+ line = reg_getline((linenr_T)0);
+ rex.reg_startpos = rex.reg_mmatch->startpos;
+ rex.reg_endpos = rex.reg_mmatch->endpos;
+ }
+ else
+ {
+ prog = (bt_regprog_T *)rex.reg_match->regprog;
+ rex.reg_startp = rex.reg_match->startp;
+ rex.reg_endp = rex.reg_match->endp;
+ }
+
+ /* Be paranoid... */
+ if (prog == NULL || line == NULL)
+ {
+ emsg(_(e_null));
+ goto theend;
+ }
+
+ /* Check validity of program. */
+ if (prog_magic_wrong())
+ goto theend;
+
+ /* If the start column is past the maximum column: no need to try. */
+ if (rex.reg_maxcol > 0 && col >= rex.reg_maxcol)
+ goto theend;
+
+ /* If pattern contains "\c" or "\C": overrule value of rex.reg_ic */
+ if (prog->regflags & RF_ICASE)
+ rex.reg_ic = TRUE;
+ else if (prog->regflags & RF_NOICASE)
+ rex.reg_ic = FALSE;
+
+ /* If pattern contains "\Z" overrule value of rex.reg_icombine */
+ if (prog->regflags & RF_ICOMBINE)
+ rex.reg_icombine = TRUE;
+
+ /* If there is a "must appear" string, look for it. */
+ if (prog->regmust != NULL)
+ {
+ int c;
+
+ if (has_mbyte)
+ c = (*mb_ptr2char)(prog->regmust);
+ else
+ c = *prog->regmust;
+ s = line + col;
+
+ /*
+ * This is used very often, esp. for ":global". Use three versions of
+ * the loop to avoid overhead of conditions.
+ */
+ if (!rex.reg_ic && !has_mbyte)
+ while ((s = vim_strbyte(s, c)) != NULL)
+ {
+ if (cstrncmp(s, prog->regmust, &prog->regmlen) == 0)
+ break; /* Found it. */
+ ++s;
+ }
+ else if (!rex.reg_ic || (!enc_utf8 && mb_char2len(c) > 1))
+ while ((s = vim_strchr(s, c)) != NULL)
+ {
+ if (cstrncmp(s, prog->regmust, &prog->regmlen) == 0)
+ break; /* Found it. */
+ MB_PTR_ADV(s);
+ }
+ else
+ while ((s = cstrchr(s, c)) != NULL)
+ {
+ if (cstrncmp(s, prog->regmust, &prog->regmlen) == 0)
+ break; /* Found it. */
+ MB_PTR_ADV(s);
+ }
+ if (s == NULL) /* Not present. */
+ goto theend;
+ }
+
+ rex.line = line;
+ rex.lnum = 0;
+ reg_toolong = FALSE;
+
+ /* Simplest case: Anchored match need be tried only once. */
+ if (prog->reganch)
+ {
+ int c;
+
+ if (has_mbyte)
+ c = (*mb_ptr2char)(rex.line + col);
+ else
+ c = rex.line[col];
+ if (prog->regstart == NUL
+ || prog->regstart == c
+ || (rex.reg_ic
+ && (((enc_utf8 && utf_fold(prog->regstart) == utf_fold(c)))
+ || (c < 255 && prog->regstart < 255 &&
+ MB_TOLOWER(prog->regstart) == MB_TOLOWER(c)))))
+ retval = regtry(prog, col, tm, timed_out);
+ else
+ retval = 0;
+ }
+ else
+ {
+#ifdef FEAT_RELTIME
+ int tm_count = 0;
+#endif
+ /* Messy cases: unanchored match. */
+ while (!got_int)
+ {
+ if (prog->regstart != NUL)
+ {
+ /* Skip until the char we know it must start with.
+ * Used often, do some work to avoid call overhead. */
+ if (!rex.reg_ic && !has_mbyte)
+ s = vim_strbyte(rex.line + col, prog->regstart);
+ else
+ s = cstrchr(rex.line + col, prog->regstart);
+ if (s == NULL)
+ {
+ retval = 0;
+ break;
+ }
+ col = (int)(s - rex.line);
+ }
+
+ /* Check for maximum column to try. */
+ if (rex.reg_maxcol > 0 && col >= rex.reg_maxcol)
+ {
+ retval = 0;
+ break;
+ }
+
+ retval = regtry(prog, col, tm, timed_out);
+ if (retval > 0)
+ break;
+
+ /* if not currently on the first line, get it again */
+ if (rex.lnum != 0)
+ {
+ rex.lnum = 0;
+ rex.line = reg_getline((linenr_T)0);
+ }
+ if (rex.line[col] == NUL)
+ break;
+ if (has_mbyte)
+ col += (*mb_ptr2len)(rex.line + col);
+ else
+ ++col;
+#ifdef FEAT_RELTIME
+ /* Check for timeout once in a twenty times to avoid overhead. */
+ if (tm != NULL && ++tm_count == 20)
+ {
+ tm_count = 0;
+ if (profile_passed_limit(tm))
+ {
+ if (timed_out != NULL)
+ *timed_out = TRUE;
+ break;
+ }
+ }
+#endif
+ }
+ }
+
+theend:
+ /* Free "reg_tofree" when it's a bit big.
+ * Free regstack and backpos if they are bigger than their initial size. */
+ if (reg_tofreelen > 400)
+ VIM_CLEAR(reg_tofree);
+ if (regstack.ga_maxlen > REGSTACK_INITIAL)
+ ga_clear(&regstack);
+ if (backpos.ga_maxlen > BACKPOS_INITIAL)
+ ga_clear(&backpos);
+
+ return retval;
+}
+
+#ifdef FEAT_SYN_HL
+/*
+ * Create a new extmatch and mark it as referenced once.
+ */
+ static reg_extmatch_T *
+make_extmatch(void)
+{
+ reg_extmatch_T *em;
+
+ em = (reg_extmatch_T *)alloc_clear((unsigned)sizeof(reg_extmatch_T));
+ if (em != NULL)
+ em->refcnt = 1;
+ return em;
+}
+
+/*
+ * Add a reference to an extmatch.
+ */
+ reg_extmatch_T *
+ref_extmatch(reg_extmatch_T *em)
+{
+ if (em != NULL)
+ em->refcnt++;
+ return em;
+}
+
+/*
+ * Remove a reference to an extmatch. If there are no references left, free
+ * the info.
+ */
+ void
+unref_extmatch(reg_extmatch_T *em)
+{
+ int i;
+
+ if (em != NULL && --em->refcnt <= 0)
+ {
+ for (i = 0; i < NSUBEXP; ++i)
+ vim_free(em->matches[i]);
+ vim_free(em);
+ }
+}
+#endif
+
+/*
+ * regtry - try match of "prog" with at rex.line["col"].
+ * Returns 0 for failure, number of lines contained in the match otherwise.
+ */
+ static long
+regtry(
+ bt_regprog_T *prog,
+ colnr_T col,
+ proftime_T *tm, /* timeout limit or NULL */
+ int *timed_out) /* flag set on timeout or NULL */
+{
+ rex.input = rex.line + col;
+ rex.need_clear_subexpr = TRUE;
+#ifdef FEAT_SYN_HL
+ // Clear the external match subpointers if necessary.
+ rex.need_clear_zsubexpr = (prog->reghasz == REX_SET);
+#endif
+
+ if (regmatch(prog->program + 1, tm, timed_out) == 0)
+ return 0;
+
+ cleanup_subexpr();
+ if (REG_MULTI)
+ {
+ if (rex.reg_startpos[0].lnum < 0)
+ {
+ rex.reg_startpos[0].lnum = 0;
+ rex.reg_startpos[0].col = col;
+ }
+ if (rex.reg_endpos[0].lnum < 0)
+ {
+ rex.reg_endpos[0].lnum = rex.lnum;
+ rex.reg_endpos[0].col = (int)(rex.input - rex.line);
+ }
+ else
+ /* Use line number of "\ze". */
+ rex.lnum = rex.reg_endpos[0].lnum;
+ }
+ else
+ {
+ if (rex.reg_startp[0] == NULL)
+ rex.reg_startp[0] = rex.line + col;
+ if (rex.reg_endp[0] == NULL)
+ rex.reg_endp[0] = rex.input;
+ }
+#ifdef FEAT_SYN_HL
+ /* Package any found \z(...\) matches for export. Default is none. */
+ unref_extmatch(re_extmatch_out);
+ re_extmatch_out = NULL;
+
+ if (prog->reghasz == REX_SET)
+ {
+ int i;
+
+ cleanup_zsubexpr();
+ re_extmatch_out = make_extmatch();
+ for (i = 0; i < NSUBEXP; i++)
+ {
+ if (REG_MULTI)
+ {
+ /* Only accept single line matches. */
+ if (reg_startzpos[i].lnum >= 0
+ && reg_endzpos[i].lnum == reg_startzpos[i].lnum
+ && reg_endzpos[i].col >= reg_startzpos[i].col)
+ re_extmatch_out->matches[i] =
+ vim_strnsave(reg_getline(reg_startzpos[i].lnum)
+ + reg_startzpos[i].col,
+ reg_endzpos[i].col - reg_startzpos[i].col);
+ }
+ else
+ {
+ if (reg_startzp[i] != NULL && reg_endzp[i] != NULL)
+ re_extmatch_out->matches[i] =
+ vim_strnsave(reg_startzp[i],
+ (int)(reg_endzp[i] - reg_startzp[i]));
+ }
+ }
+ }
+#endif
+ return 1 + rex.lnum;
+}
+
+/*
+ * Get class of previous character.
+ */
+ static int
+reg_prev_class(void)
+{
+ if (rex.input > rex.line)
+ return mb_get_class_buf(rex.input - 1
+ - (*mb_head_off)(rex.line, rex.input - 1), rex.reg_buf);
+ return -1;
+}
+
+/*
+ * Return TRUE if the current rex.input position matches the Visual area.
+ */
+ static int
+reg_match_visual(void)
+{
+ pos_T top, bot;
+ linenr_T lnum;
+ colnr_T col;
+ win_T *wp = rex.reg_win == NULL ? curwin : rex.reg_win;
+ int mode;
+ colnr_T start, end;
+ colnr_T start2, end2;
+ colnr_T cols;
+
+ /* Check if the buffer is the current buffer. */
+ if (rex.reg_buf != curbuf || VIsual.lnum == 0)
+ return FALSE;
+
+ if (VIsual_active)
+ {
+ if (LT_POS(VIsual, wp->w_cursor))
+ {
+ top = VIsual;
+ bot = wp->w_cursor;
+ }
+ else
+ {
+ top = wp->w_cursor;
+ bot = VIsual;
+ }
+ mode = VIsual_mode;
+ }
+ else
+ {
+ if (LT_POS(curbuf->b_visual.vi_start, curbuf->b_visual.vi_end))
+ {
+ top = curbuf->b_visual.vi_start;
+ bot = curbuf->b_visual.vi_end;
+ }
+ else
+ {
+ top = curbuf->b_visual.vi_end;
+ bot = curbuf->b_visual.vi_start;
+ }
+ mode = curbuf->b_visual.vi_mode;
+ }
+ lnum = rex.lnum + rex.reg_firstlnum;
+ if (lnum < top.lnum || lnum > bot.lnum)
+ return FALSE;
+
+ if (mode == 'v')
+ {
+ col = (colnr_T)(rex.input - rex.line);
+ if ((lnum == top.lnum && col < top.col)
+ || (lnum == bot.lnum && col >= bot.col + (*p_sel != 'e')))
+ return FALSE;
+ }
+ else if (mode == Ctrl_V)
+ {
+ getvvcol(wp, &top, &start, NULL, &end);
+ getvvcol(wp, &bot, &start2, NULL, &end2);
+ if (start2 < start)
+ start = start2;
+ if (end2 > end)
+ end = end2;
+ if (top.col == MAXCOL || bot.col == MAXCOL)
+ end = MAXCOL;
+ cols = win_linetabsize(wp, rex.line, (colnr_T)(rex.input - rex.line));
+ if (cols < start || cols > end - (*p_sel == 'e'))
+ return FALSE;
+ }
+ return TRUE;
+}
+
+#define ADVANCE_REGINPUT() MB_PTR_ADV(rex.input)
+
+/*
+ * The arguments from BRACE_LIMITS are stored here. They are actually local
+ * to regmatch(), but they are here to reduce the amount of stack space used
+ * (it can be called recursively many times).
+ */
+static long bl_minval;
+static long bl_maxval;
+
+/*
+ * regmatch - main matching routine
+ *
+ * Conceptually the strategy is simple: Check to see whether the current node
+ * matches, push an item onto the regstack and loop to see whether the rest
+ * matches, and then act accordingly. In practice we make some effort to
+ * avoid using the regstack, in particular by going through "ordinary" nodes
+ * (that don't need to know whether the rest of the match failed) by a nested
+ * loop.
+ *
+ * Returns TRUE when there is a match. Leaves rex.input and rex.lnum just after
+ * the last matched character.
+ * Returns FALSE when there is no match. Leaves rex.input and rex.lnum in an
+ * undefined state!
+ */
+ static int
+regmatch(
+ char_u *scan, /* Current node. */
+ proftime_T *tm UNUSED, /* timeout limit or NULL */
+ int *timed_out UNUSED) /* flag set on timeout or NULL */
+{
+ char_u *next; /* Next node. */
+ int op;
+ int c;
+ regitem_T *rp;
+ int no;
+ int status; /* one of the RA_ values: */
+#define RA_FAIL 1 /* something failed, abort */
+#define RA_CONT 2 /* continue in inner loop */
+#define RA_BREAK 3 /* break inner loop */
+#define RA_MATCH 4 /* successful match */
+#define RA_NOMATCH 5 /* didn't match */
+#ifdef FEAT_RELTIME
+ int tm_count = 0;
+#endif
+
+ /* Make "regstack" and "backpos" empty. They are allocated and freed in
+ * bt_regexec_both() to reduce malloc()/free() calls. */
+ regstack.ga_len = 0;
+ backpos.ga_len = 0;
+
+ /*
+ * Repeat until "regstack" is empty.
+ */
+ for (;;)
+ {
+ /* Some patterns may take a long time to match, e.g., "\([a-z]\+\)\+Q".
+ * Allow interrupting them with CTRL-C. */
+ fast_breakcheck();
+
+#ifdef DEBUG
+ if (scan != NULL && regnarrate)
+ {
+ mch_errmsg((char *)regprop(scan));
+ mch_errmsg("(\n");
+ }
+#endif
+
+ /*
+ * Repeat for items that can be matched sequentially, without using the
+ * regstack.
+ */
+ for (;;)
+ {
+ if (got_int || scan == NULL)
+ {
+ status = RA_FAIL;
+ break;
+ }
+#ifdef FEAT_RELTIME
+ /* Check for timeout once in a 100 times to avoid overhead. */
+ if (tm != NULL && ++tm_count == 100)
+ {
+ tm_count = 0;
+ if (profile_passed_limit(tm))
+ {
+ if (timed_out != NULL)
+ *timed_out = TRUE;
+ status = RA_FAIL;
+ break;
+ }
+ }
+#endif
+ status = RA_CONT;
+
+#ifdef DEBUG
+ if (regnarrate)
+ {
+ mch_errmsg((char *)regprop(scan));
+ mch_errmsg("...\n");
+# ifdef FEAT_SYN_HL
+ if (re_extmatch_in != NULL)
+ {
+ int i;
+
+ mch_errmsg(_("External submatches:\n"));
+ for (i = 0; i < NSUBEXP; i++)
+ {
+ mch_errmsg(" \"");
+ if (re_extmatch_in->matches[i] != NULL)
+ mch_errmsg((char *)re_extmatch_in->matches[i]);
+ mch_errmsg("\"\n");
+ }
+ }
+# endif
+ }
+#endif
+ next = regnext(scan);
+
+ op = OP(scan);
+ /* Check for character class with NL added. */
+ if (!rex.reg_line_lbr && WITH_NL(op) && REG_MULTI
+ && *rex.input == NUL && rex.lnum <= rex.reg_maxline)
+ {
+ reg_nextline();
+ }
+ else if (rex.reg_line_lbr && WITH_NL(op) && *rex.input == '\n')
+ {
+ ADVANCE_REGINPUT();
+ }
+ else
+ {
+ if (WITH_NL(op))
+ op -= ADD_NL;
+ if (has_mbyte)
+ c = (*mb_ptr2char)(rex.input);
+ else
+ c = *rex.input;
+ switch (op)
+ {
+ case BOL:
+ if (rex.input != rex.line)
+ status = RA_NOMATCH;
+ break;
+
+ case EOL:
+ if (c != NUL)
+ status = RA_NOMATCH;
+ break;
+
+ case RE_BOF:
+ /* We're not at the beginning of the file when below the first
+ * line where we started, not at the start of the line or we
+ * didn't start at the first line of the buffer. */
+ if (rex.lnum != 0 || rex.input != rex.line
+ || (REG_MULTI && rex.reg_firstlnum > 1))
+ status = RA_NOMATCH;
+ break;
+
+ case RE_EOF:
+ if (rex.lnum != rex.reg_maxline || c != NUL)
+ status = RA_NOMATCH;
+ break;
+
+ case CURSOR:
+ /* Check if the buffer is in a window and compare the
+ * rex.reg_win->w_cursor position to the match position. */
+ if (rex.reg_win == NULL
+ || (rex.lnum + rex.reg_firstlnum
+ != rex.reg_win->w_cursor.lnum)
+ || ((colnr_T)(rex.input - rex.line)
+ != rex.reg_win->w_cursor.col))
+ status = RA_NOMATCH;
+ break;
+
+ case RE_MARK:
+ /* Compare the mark position to the match position. */
+ {
+ int mark = OPERAND(scan)[0];
+ int cmp = OPERAND(scan)[1];
+ pos_T *pos;
+
+ pos = getmark_buf(rex.reg_buf, mark, FALSE);
+ if (pos == NULL /* mark doesn't exist */
+ || pos->lnum <= 0 /* mark isn't set in reg_buf */
+ || (pos->lnum == rex.lnum + rex.reg_firstlnum
+ ? (pos->col == (colnr_T)(rex.input - rex.line)
+ ? (cmp == '<' || cmp == '>')
+ : (pos->col < (colnr_T)(rex.input - rex.line)
+ ? cmp != '>'
+ : cmp != '<'))
+ : (pos->lnum < rex.lnum + rex.reg_firstlnum
+ ? cmp != '>'
+ : cmp != '<')))
+ status = RA_NOMATCH;
+ }
+ break;
+
+ case RE_VISUAL:
+ if (!reg_match_visual())
+ status = RA_NOMATCH;
+ break;
+
+ case RE_LNUM:
+ if (!REG_MULTI || !re_num_cmp((long_u)(rex.lnum + rex.reg_firstlnum),
+ scan))
+ status = RA_NOMATCH;
+ break;
+
+ case RE_COL:
+ if (!re_num_cmp((long_u)(rex.input - rex.line) + 1, scan))
+ status = RA_NOMATCH;
+ break;
+
+ case RE_VCOL:
+ if (!re_num_cmp((long_u)win_linetabsize(
+ rex.reg_win == NULL ? curwin : rex.reg_win,
+ rex.line, (colnr_T)(rex.input - rex.line)) + 1, scan))
+ status = RA_NOMATCH;
+ break;
+
+ case BOW: /* \<word; rex.input points to w */
+ if (c == NUL) /* Can't match at end of line */
+ status = RA_NOMATCH;
+ else if (has_mbyte)
+ {
+ int this_class;
+
+ /* Get class of current and previous char (if it exists). */
+ this_class = mb_get_class_buf(rex.input, rex.reg_buf);
+ if (this_class <= 1)
+ status = RA_NOMATCH; /* not on a word at all */
+ else if (reg_prev_class() == this_class)
+ status = RA_NOMATCH; /* previous char is in same word */
+ }
+ else
+ {
+ if (!vim_iswordc_buf(c, rex.reg_buf) || (rex.input > rex.line
+ && vim_iswordc_buf(rex.input[-1], rex.reg_buf)))
+ status = RA_NOMATCH;
+ }
+ break;
+
+ case EOW: /* word\>; rex.input points after d */
+ if (rex.input == rex.line) /* Can't match at start of line */
+ status = RA_NOMATCH;
+ else if (has_mbyte)
+ {
+ int this_class, prev_class;
+
+ /* Get class of current and previous char (if it exists). */
+ this_class = mb_get_class_buf(rex.input, rex.reg_buf);
+ prev_class = reg_prev_class();
+ if (this_class == prev_class
+ || prev_class == 0 || prev_class == 1)
+ status = RA_NOMATCH;
+ }
+ else
+ {
+ if (!vim_iswordc_buf(rex.input[-1], rex.reg_buf)
+ || (rex.input[0] != NUL
+ && vim_iswordc_buf(c, rex.reg_buf)))
+ status = RA_NOMATCH;
+ }
+ break; /* Matched with EOW */
+
+ case ANY:
+ /* ANY does not match new lines. */
+ if (c == NUL)
+ status = RA_NOMATCH;
+ else
+ ADVANCE_REGINPUT();
+ break;
+
+ case IDENT:
+ if (!vim_isIDc(c))
+ status = RA_NOMATCH;
+ else
+ ADVANCE_REGINPUT();
+ break;
+
+ case SIDENT:
+ if (VIM_ISDIGIT(*rex.input) || !vim_isIDc(c))
+ status = RA_NOMATCH;
+ else
+ ADVANCE_REGINPUT();
+ break;
+
+ case KWORD:
+ if (!vim_iswordp_buf(rex.input, rex.reg_buf))
+ status = RA_NOMATCH;
+ else
+ ADVANCE_REGINPUT();
+ break;
+
+ case SKWORD:
+ if (VIM_ISDIGIT(*rex.input)
+ || !vim_iswordp_buf(rex.input, rex.reg_buf))
+ status = RA_NOMATCH;
+ else
+ ADVANCE_REGINPUT();
+ break;
+
+ case FNAME:
+ if (!vim_isfilec(c))
+ status = RA_NOMATCH;
+ else
+ ADVANCE_REGINPUT();
+ break;
+
+ case SFNAME:
+ if (VIM_ISDIGIT(*rex.input) || !vim_isfilec(c))
+ status = RA_NOMATCH;
+ else
+ ADVANCE_REGINPUT();
+ break;
+
+ case PRINT:
+ if (!vim_isprintc(PTR2CHAR(rex.input)))
+ status = RA_NOMATCH;
+ else
+ ADVANCE_REGINPUT();
+ break;
+
+ case SPRINT:
+ if (VIM_ISDIGIT(*rex.input) || !vim_isprintc(PTR2CHAR(rex.input)))
+ status = RA_NOMATCH;
+ else
+ ADVANCE_REGINPUT();
+ break;
+
+ case WHITE:
+ if (!VIM_ISWHITE(c))
+ status = RA_NOMATCH;
+ else
+ ADVANCE_REGINPUT();
+ break;
+
+ case NWHITE:
+ if (c == NUL || VIM_ISWHITE(c))
+ status = RA_NOMATCH;
+ else
+ ADVANCE_REGINPUT();
+ break;
+
+ case DIGIT:
+ if (!ri_digit(c))
+ status = RA_NOMATCH;
+ else
+ ADVANCE_REGINPUT();
+ break;
+
+ case NDIGIT:
+ if (c == NUL || ri_digit(c))
+ status = RA_NOMATCH;
+ else
+ ADVANCE_REGINPUT();
+ break;
+
+ case HEX:
+ if (!ri_hex(c))
+ status = RA_NOMATCH;
+ else
+ ADVANCE_REGINPUT();
+ break;
+
+ case NHEX:
+ if (c == NUL || ri_hex(c))
+ status = RA_NOMATCH;
+ else
+ ADVANCE_REGINPUT();
+ break;
+
+ case OCTAL:
+ if (!ri_octal(c))
+ status = RA_NOMATCH;
+ else
+ ADVANCE_REGINPUT();
+ break;
+
+ case NOCTAL:
+ if (c == NUL || ri_octal(c))
+ status = RA_NOMATCH;
+ else
+ ADVANCE_REGINPUT();
+ break;
+
+ case WORD:
+ if (!ri_word(c))
+ status = RA_NOMATCH;
+ else
+ ADVANCE_REGINPUT();
+ break;
+
+ case NWORD:
+ if (c == NUL || ri_word(c))
+ status = RA_NOMATCH;
+ else
+ ADVANCE_REGINPUT();
+ break;
+
+ case HEAD:
+ if (!ri_head(c))
+ status = RA_NOMATCH;
+ else
+ ADVANCE_REGINPUT();
+ break;
+
+ case NHEAD:
+ if (c == NUL || ri_head(c))
+ status = RA_NOMATCH;
+ else
+ ADVANCE_REGINPUT();
+ break;
+
+ case ALPHA:
+ if (!ri_alpha(c))
+ status = RA_NOMATCH;
+ else
+ ADVANCE_REGINPUT();
+ break;
+
+ case NALPHA:
+ if (c == NUL || ri_alpha(c))
+ status = RA_NOMATCH;
+ else
+ ADVANCE_REGINPUT();
+ break;
+
+ case LOWER:
+ if (!ri_lower(c))
+ status = RA_NOMATCH;
+ else
+ ADVANCE_REGINPUT();
+ break;
+
+ case NLOWER:
+ if (c == NUL || ri_lower(c))
+ status = RA_NOMATCH;
+ else
+ ADVANCE_REGINPUT();
+ break;
+
+ case UPPER:
+ if (!ri_upper(c))
+ status = RA_NOMATCH;
+ else
+ ADVANCE_REGINPUT();
+ break;
+
+ case NUPPER:
+ if (c == NUL || ri_upper(c))
+ status = RA_NOMATCH;
+ else
+ ADVANCE_REGINPUT();
+ break;
+
+ case EXACTLY:
+ {
+ int len;
+ char_u *opnd;
+
+ opnd = OPERAND(scan);
+ /* Inline the first byte, for speed. */
+ if (*opnd != *rex.input
+ && (!rex.reg_ic
+ || (!enc_utf8
+ && MB_TOLOWER(*opnd) != MB_TOLOWER(*rex.input))))
+ status = RA_NOMATCH;
+ else if (*opnd == NUL)
+ {
+ /* match empty string always works; happens when "~" is
+ * empty. */
+ }
+ else
+ {
+ if (opnd[1] == NUL && !(enc_utf8 && rex.reg_ic))
+ {
+ len = 1; /* matched a single byte above */
+ }
+ else
+ {
+ /* Need to match first byte again for multi-byte. */
+ len = (int)STRLEN(opnd);
+ if (cstrncmp(opnd, rex.input, &len) != 0)
+ status = RA_NOMATCH;
+ }
+ /* Check for following composing character, unless %C
+ * follows (skips over all composing chars). */
+ if (status != RA_NOMATCH
+ && enc_utf8
+ && UTF_COMPOSINGLIKE(rex.input, rex.input + len)
+ && !rex.reg_icombine
+ && OP(next) != RE_COMPOSING)
+ {
+ /* raaron: This code makes a composing character get
+ * ignored, which is the correct behavior (sometimes)
+ * for voweled Hebrew texts. */
+ status = RA_NOMATCH;
+ }
+ if (status != RA_NOMATCH)
+ rex.input += len;
+ }
+ }
+ break;
+
+ case ANYOF:
+ case ANYBUT:
+ if (c == NUL)
+ status = RA_NOMATCH;
+ else if ((cstrchr(OPERAND(scan), c) == NULL) == (op == ANYOF))
+ status = RA_NOMATCH;
+ else
+ ADVANCE_REGINPUT();
+ break;
+
+ case MULTIBYTECODE:
+ if (has_mbyte)
+ {
+ int i, len;
+ char_u *opnd;
+ int opndc = 0, inpc;
+
+ opnd = OPERAND(scan);
+ /* Safety check (just in case 'encoding' was changed since
+ * compiling the program). */
+ if ((len = (*mb_ptr2len)(opnd)) < 2)
+ {
+ status = RA_NOMATCH;
+ break;
+ }
+ if (enc_utf8)
+ opndc = utf_ptr2char(opnd);
+ if (enc_utf8 && utf_iscomposing(opndc))
+ {
+ /* When only a composing char is given match at any
+ * position where that composing char appears. */
+ status = RA_NOMATCH;
+ for (i = 0; rex.input[i] != NUL;
+ i += utf_ptr2len(rex.input + i))
+ {
+ inpc = utf_ptr2char(rex.input + i);
+ if (!utf_iscomposing(inpc))
+ {
+ if (i > 0)
+ break;
+ }
+ else if (opndc == inpc)
+ {
+ /* Include all following composing chars. */
+ len = i + utfc_ptr2len(rex.input + i);
+ status = RA_MATCH;
+ break;
+ }
+ }
+ }
+ else
+ for (i = 0; i < len; ++i)
+ if (opnd[i] != rex.input[i])
+ {
+ status = RA_NOMATCH;
+ break;
+ }
+ rex.input += len;
+ }
+ else
+ status = RA_NOMATCH;
+ break;
+ case RE_COMPOSING:
+ if (enc_utf8)
+ {
+ /* Skip composing characters. */
+ while (utf_iscomposing(utf_ptr2char(rex.input)))
+ MB_CPTR_ADV(rex.input);
+ }
+ break;
+
+ case NOTHING:
+ break;
+
+ case BACK:
+ {
+ int i;
+ backpos_T *bp;
+
+ /*
+ * When we run into BACK we need to check if we don't keep
+ * looping without matching any input. The second and later
+ * times a BACK is encountered it fails if the input is still
+ * at the same position as the previous time.
+ * The positions are stored in "backpos" and found by the
+ * current value of "scan", the position in the RE program.
+ */
+ bp = (backpos_T *)backpos.ga_data;
+ for (i = 0; i < backpos.ga_len; ++i)
+ if (bp[i].bp_scan == scan)
+ break;
+ if (i == backpos.ga_len)
+ {
+ /* First time at this BACK, make room to store the pos. */
+ if (ga_grow(&backpos, 1) == FAIL)
+ status = RA_FAIL;
+ else
+ {
+ /* get "ga_data" again, it may have changed */
+ bp = (backpos_T *)backpos.ga_data;
+ bp[i].bp_scan = scan;
+ ++backpos.ga_len;
+ }
+ }
+ else if (reg_save_equal(&bp[i].bp_pos))
+ /* Still at same position as last time, fail. */
+ status = RA_NOMATCH;
+
+ if (status != RA_FAIL && status != RA_NOMATCH)
+ reg_save(&bp[i].bp_pos, &backpos);
+ }
+ break;
+
+ case MOPEN + 0: /* Match start: \zs */
+ case MOPEN + 1: /* \( */
+ case MOPEN + 2:
+ case MOPEN + 3:
+ case MOPEN + 4:
+ case MOPEN + 5:
+ case MOPEN + 6:
+ case MOPEN + 7:
+ case MOPEN + 8:
+ case MOPEN + 9:
+ {
+ no = op - MOPEN;
+ cleanup_subexpr();
+ rp = regstack_push(RS_MOPEN, scan);
+ if (rp == NULL)
+ status = RA_FAIL;
+ else
+ {
+ rp->rs_no = no;
+ save_se(&rp->rs_un.sesave, &rex.reg_startpos[no],
+ &rex.reg_startp[no]);
+ /* We simply continue and handle the result when done. */
+ }
+ }
+ break;
+
+ case NOPEN: /* \%( */
+ case NCLOSE: /* \) after \%( */
+ if (regstack_push(RS_NOPEN, scan) == NULL)
+ status = RA_FAIL;
+ /* We simply continue and handle the result when done. */
+ break;
+
+#ifdef FEAT_SYN_HL
+ case ZOPEN + 1:
+ case ZOPEN + 2:
+ case ZOPEN + 3:
+ case ZOPEN + 4:
+ case ZOPEN + 5:
+ case ZOPEN + 6:
+ case ZOPEN + 7:
+ case ZOPEN + 8:
+ case ZOPEN + 9:
+ {
+ no = op - ZOPEN;
+ cleanup_zsubexpr();
+ rp = regstack_push(RS_ZOPEN, scan);
+ if (rp == NULL)
+ status = RA_FAIL;
+ else
+ {
+ rp->rs_no = no;
+ save_se(&rp->rs_un.sesave, &reg_startzpos[no],
+ &reg_startzp[no]);
+ /* We simply continue and handle the result when done. */
+ }
+ }
+ break;
+#endif
+
+ case MCLOSE + 0: /* Match end: \ze */
+ case MCLOSE + 1: /* \) */
+ case MCLOSE + 2:
+ case MCLOSE + 3:
+ case MCLOSE + 4:
+ case MCLOSE + 5:
+ case MCLOSE + 6:
+ case MCLOSE + 7:
+ case MCLOSE + 8:
+ case MCLOSE + 9:
+ {
+ no = op - MCLOSE;
+ cleanup_subexpr();
+ rp = regstack_push(RS_MCLOSE, scan);
+ if (rp == NULL)
+ status = RA_FAIL;
+ else
+ {
+ rp->rs_no = no;
+ save_se(&rp->rs_un.sesave, &rex.reg_endpos[no],
+ &rex.reg_endp[no]);
+ /* We simply continue and handle the result when done. */
+ }
+ }
+ break;
+
+#ifdef FEAT_SYN_HL
+ case ZCLOSE + 1: /* \) after \z( */
+ case ZCLOSE + 2:
+ case ZCLOSE + 3:
+ case ZCLOSE + 4:
+ case ZCLOSE + 5:
+ case ZCLOSE + 6:
+ case ZCLOSE + 7:
+ case ZCLOSE + 8:
+ case ZCLOSE + 9:
+ {
+ no = op - ZCLOSE;
+ cleanup_zsubexpr();
+ rp = regstack_push(RS_ZCLOSE, scan);
+ if (rp == NULL)
+ status = RA_FAIL;
+ else
+ {
+ rp->rs_no = no;
+ save_se(&rp->rs_un.sesave, &reg_endzpos[no],
+ &reg_endzp[no]);
+ /* We simply continue and handle the result when done. */
+ }
+ }
+ break;
+#endif
+
+ case BACKREF + 1:
+ case BACKREF + 2:
+ case BACKREF + 3:
+ case BACKREF + 4:
+ case BACKREF + 5:
+ case BACKREF + 6:
+ case BACKREF + 7:
+ case BACKREF + 8:
+ case BACKREF + 9:
+ {
+ int len;
+
+ no = op - BACKREF;
+ cleanup_subexpr();
+ if (!REG_MULTI) /* Single-line regexp */
+ {
+ if (rex.reg_startp[no] == NULL || rex.reg_endp[no] == NULL)
+ {
+ /* Backref was not set: Match an empty string. */
+ len = 0;
+ }
+ else
+ {
+ /* Compare current input with back-ref in the same
+ * line. */
+ len = (int)(rex.reg_endp[no] - rex.reg_startp[no]);
+ if (cstrncmp(rex.reg_startp[no], rex.input, &len) != 0)
+ status = RA_NOMATCH;
+ }
+ }
+ else /* Multi-line regexp */
+ {
+ if (rex.reg_startpos[no].lnum < 0
+ || rex.reg_endpos[no].lnum < 0)
+ {
+ /* Backref was not set: Match an empty string. */
+ len = 0;
+ }
+ else
+ {
+ if (rex.reg_startpos[no].lnum == rex.lnum
+ && rex.reg_endpos[no].lnum == rex.lnum)
+ {
+ /* Compare back-ref within the current line. */
+ len = rex.reg_endpos[no].col
+ - rex.reg_startpos[no].col;
+ if (cstrncmp(rex.line + rex.reg_startpos[no].col,
+ rex.input, &len) != 0)
+ status = RA_NOMATCH;
+ }
+ else
+ {
+ /* Messy situation: Need to compare between two
+ * lines. */
+ int r = match_with_backref(
+ rex.reg_startpos[no].lnum,
+ rex.reg_startpos[no].col,
+ rex.reg_endpos[no].lnum,
+ rex.reg_endpos[no].col,
+ &len);
+
+ if (r != RA_MATCH)
+ status = r;
+ }
+ }
+ }
+
+ /* Matched the backref, skip over it. */
+ rex.input += len;
+ }
+ break;
+
+#ifdef FEAT_SYN_HL
+ case ZREF + 1:
+ case ZREF + 2:
+ case ZREF + 3:
+ case ZREF + 4:
+ case ZREF + 5:
+ case ZREF + 6:
+ case ZREF + 7:
+ case ZREF + 8:
+ case ZREF + 9:
+ {
+ int len;
+
+ cleanup_zsubexpr();
+ no = op - ZREF;
+ if (re_extmatch_in != NULL
+ && re_extmatch_in->matches[no] != NULL)
+ {
+ len = (int)STRLEN(re_extmatch_in->matches[no]);
+ if (cstrncmp(re_extmatch_in->matches[no],
+ rex.input, &len) != 0)
+ status = RA_NOMATCH;
+ else
+ rex.input += len;
+ }
+ else
+ {
+ /* Backref was not set: Match an empty string. */
+ }
+ }
+ break;
+#endif
+
+ case BRANCH:
+ {
+ if (OP(next) != BRANCH) /* No choice. */
+ next = OPERAND(scan); /* Avoid recursion. */
+ else
+ {
+ rp = regstack_push(RS_BRANCH, scan);
+ if (rp == NULL)
+ status = RA_FAIL;
+ else
+ status = RA_BREAK; /* rest is below */
+ }
+ }
+ break;
+
+ case BRACE_LIMITS:
+ {
+ if (OP(next) == BRACE_SIMPLE)
+ {
+ bl_minval = OPERAND_MIN(scan);
+ bl_maxval = OPERAND_MAX(scan);
+ }
+ else if (OP(next) >= BRACE_COMPLEX
+ && OP(next) < BRACE_COMPLEX + 10)
+ {
+ no = OP(next) - BRACE_COMPLEX;
+ brace_min[no] = OPERAND_MIN(scan);
+ brace_max[no] = OPERAND_MAX(scan);
+ brace_count[no] = 0;
+ }
+ else
+ {
+ internal_error("BRACE_LIMITS");
+ status = RA_FAIL;
+ }
+ }
+ break;
+
+ case BRACE_COMPLEX + 0:
+ case BRACE_COMPLEX + 1:
+ case BRACE_COMPLEX + 2:
+ case BRACE_COMPLEX + 3:
+ case BRACE_COMPLEX + 4:
+ case BRACE_COMPLEX + 5:
+ case BRACE_COMPLEX + 6:
+ case BRACE_COMPLEX + 7:
+ case BRACE_COMPLEX + 8:
+ case BRACE_COMPLEX + 9:
+ {
+ no = op - BRACE_COMPLEX;
+ ++brace_count[no];
+
+ /* If not matched enough times yet, try one more */
+ if (brace_count[no] <= (brace_min[no] <= brace_max[no]
+ ? brace_min[no] : brace_max[no]))
+ {
+ rp = regstack_push(RS_BRCPLX_MORE, scan);
+ if (rp == NULL)
+ status = RA_FAIL;
+ else
+ {
+ rp->rs_no = no;
+ reg_save(&rp->rs_un.regsave, &backpos);
+ next = OPERAND(scan);
+ /* We continue and handle the result when done. */
+ }
+ break;
+ }
+
+ /* If matched enough times, may try matching some more */
+ if (brace_min[no] <= brace_max[no])
+ {
+ /* Range is the normal way around, use longest match */
+ if (brace_count[no] <= brace_max[no])
+ {
+ rp = regstack_push(RS_BRCPLX_LONG, scan);
+ if (rp == NULL)
+ status = RA_FAIL;
+ else
+ {
+ rp->rs_no = no;
+ reg_save(&rp->rs_un.regsave, &backpos);
+ next = OPERAND(scan);
+ /* We continue and handle the result when done. */
+ }
+ }
+ }
+ else
+ {
+ /* Range is backwards, use shortest match first */
+ if (brace_count[no] <= brace_min[no])
+ {
+ rp = regstack_push(RS_BRCPLX_SHORT, scan);
+ if (rp == NULL)
+ status = RA_FAIL;
+ else
+ {
+ reg_save(&rp->rs_un.regsave, &backpos);
+ /* We continue and handle the result when done. */
+ }
+ }
+ }
+ }
+ break;
+
+ case BRACE_SIMPLE:
+ case STAR:
+ case PLUS:
+ {
+ regstar_T rst;
+
+ /*
+ * Lookahead to avoid useless match attempts when we know
+ * what character comes next.
+ */
+ if (OP(next) == EXACTLY)
+ {
+ rst.nextb = *OPERAND(next);
+ if (rex.reg_ic)
+ {
+ if (MB_ISUPPER(rst.nextb))
+ rst.nextb_ic = MB_TOLOWER(rst.nextb);
+ else
+ rst.nextb_ic = MB_TOUPPER(rst.nextb);
+ }
+ else
+ rst.nextb_ic = rst.nextb;
+ }
+ else
+ {
+ rst.nextb = NUL;
+ rst.nextb_ic = NUL;
+ }
+ if (op != BRACE_SIMPLE)
+ {
+ rst.minval = (op == STAR) ? 0 : 1;
+ rst.maxval = MAX_LIMIT;
+ }
+ else
+ {
+ rst.minval = bl_minval;
+ rst.maxval = bl_maxval;
+ }
+
+ /*
+ * When maxval > minval, try matching as much as possible, up
+ * to maxval. When maxval < minval, try matching at least the
+ * minimal number (since the range is backwards, that's also
+ * maxval!).
+ */
+ rst.count = regrepeat(OPERAND(scan), rst.maxval);
+ if (got_int)
+ {
+ status = RA_FAIL;
+ break;
+ }
+ if (rst.minval <= rst.maxval
+ ? rst.count >= rst.minval : rst.count >= rst.maxval)
+ {
+ /* It could match. Prepare for trying to match what
+ * follows. The code is below. Parameters are stored in
+ * a regstar_T on the regstack. */
+ if ((long)((unsigned)regstack.ga_len >> 10) >= p_mmp)
+ {
+ emsg(_(e_maxmempat));
+ status = RA_FAIL;
+ }
+ else if (ga_grow(&regstack, sizeof(regstar_T)) == FAIL)
+ status = RA_FAIL;
+ else
+ {
+ regstack.ga_len += sizeof(regstar_T);
+ rp = regstack_push(rst.minval <= rst.maxval
+ ? RS_STAR_LONG : RS_STAR_SHORT, scan);
+ if (rp == NULL)
+ status = RA_FAIL;
+ else
+ {
+ *(((regstar_T *)rp) - 1) = rst;
+ status = RA_BREAK; /* skip the restore bits */
+ }
+ }
+ }
+ else
+ status = RA_NOMATCH;
+
+ }
+ break;
+
+ case NOMATCH:
+ case MATCH:
+ case SUBPAT:
+ rp = regstack_push(RS_NOMATCH, scan);
+ if (rp == NULL)
+ status = RA_FAIL;
+ else
+ {
+ rp->rs_no = op;
+ reg_save(&rp->rs_un.regsave, &backpos);
+ next = OPERAND(scan);
+ /* We continue and handle the result when done. */
+ }
+ break;
+
+ case BEHIND:
+ case NOBEHIND:
+ /* Need a bit of room to store extra positions. */
+ if ((long)((unsigned)regstack.ga_len >> 10) >= p_mmp)
+ {
+ emsg(_(e_maxmempat));
+ status = RA_FAIL;
+ }
+ else if (ga_grow(&regstack, sizeof(regbehind_T)) == FAIL)
+ status = RA_FAIL;
+ else
+ {
+ regstack.ga_len += sizeof(regbehind_T);
+ rp = regstack_push(RS_BEHIND1, scan);
+ if (rp == NULL)
+ status = RA_FAIL;
+ else
+ {
+ /* Need to save the subexpr to be able to restore them
+ * when there is a match but we don't use it. */
+ save_subexpr(((regbehind_T *)rp) - 1);
+
+ rp->rs_no = op;
+ reg_save(&rp->rs_un.regsave, &backpos);
+ /* First try if what follows matches. If it does then we
+ * check the behind match by looping. */
+ }
+ }
+ break;
+
+ case BHPOS:
+ if (REG_MULTI)
+ {
+ if (behind_pos.rs_u.pos.col != (colnr_T)(rex.input - rex.line)
+ || behind_pos.rs_u.pos.lnum != rex.lnum)
+ status = RA_NOMATCH;
+ }
+ else if (behind_pos.rs_u.ptr != rex.input)
+ status = RA_NOMATCH;
+ break;
+
+ case NEWL:
+ if ((c != NUL || !REG_MULTI || rex.lnum > rex.reg_maxline
+ || rex.reg_line_lbr)
+ && (c != '\n' || !rex.reg_line_lbr))
+ status = RA_NOMATCH;
+ else if (rex.reg_line_lbr)
+ ADVANCE_REGINPUT();
+ else
+ reg_nextline();
+ break;
+
+ case END:
+ status = RA_MATCH; /* Success! */
+ break;
+
+ default:
+ emsg(_(e_re_corr));
+#ifdef DEBUG
+ printf("Illegal op code %d\n", op);
+#endif
+ status = RA_FAIL;
+ break;
+ }
+ }
+
+ /* If we can't continue sequentially, break the inner loop. */
+ if (status != RA_CONT)
+ break;
+
+ /* Continue in inner loop, advance to next item. */
+ scan = next;
+
+ } /* end of inner loop */
+
+ /*
+ * If there is something on the regstack execute the code for the state.
+ * If the state is popped then loop and use the older state.
+ */
+ while (regstack.ga_len > 0 && status != RA_FAIL)
+ {
+ rp = (regitem_T *)((char *)regstack.ga_data + regstack.ga_len) - 1;
+ switch (rp->rs_state)
+ {
+ case RS_NOPEN:
+ /* Result is passed on as-is, simply pop the state. */
+ regstack_pop(&scan);
+ break;
+
+ case RS_MOPEN:
+ /* Pop the state. Restore pointers when there is no match. */
+ if (status == RA_NOMATCH)
+ restore_se(&rp->rs_un.sesave, &rex.reg_startpos[rp->rs_no],
+ &rex.reg_startp[rp->rs_no]);
+ regstack_pop(&scan);
+ break;
+
+#ifdef FEAT_SYN_HL
+ case RS_ZOPEN:
+ /* Pop the state. Restore pointers when there is no match. */
+ if (status == RA_NOMATCH)
+ restore_se(&rp->rs_un.sesave, &reg_startzpos[rp->rs_no],
+ &reg_startzp[rp->rs_no]);
+ regstack_pop(&scan);
+ break;
+#endif
+
+ case RS_MCLOSE:
+ /* Pop the state. Restore pointers when there is no match. */
+ if (status == RA_NOMATCH)
+ restore_se(&rp->rs_un.sesave, &rex.reg_endpos[rp->rs_no],
+ &rex.reg_endp[rp->rs_no]);
+ regstack_pop(&scan);
+ break;
+
+#ifdef FEAT_SYN_HL
+ case RS_ZCLOSE:
+ /* Pop the state. Restore pointers when there is no match. */
+ if (status == RA_NOMATCH)
+ restore_se(&rp->rs_un.sesave, &reg_endzpos[rp->rs_no],
+ &reg_endzp[rp->rs_no]);
+ regstack_pop(&scan);
+ break;
+#endif
+
+ case RS_BRANCH:
+ if (status == RA_MATCH)
+ /* this branch matched, use it */
+ regstack_pop(&scan);
+ else
+ {
+ if (status != RA_BREAK)
+ {
+ /* After a non-matching branch: try next one. */
+ reg_restore(&rp->rs_un.regsave, &backpos);
+ scan = rp->rs_scan;
+ }
+ if (scan == NULL || OP(scan) != BRANCH)
+ {
+ /* no more branches, didn't find a match */
+ status = RA_NOMATCH;
+ regstack_pop(&scan);
+ }
+ else
+ {
+ /* Prepare to try a branch. */
+ rp->rs_scan = regnext(scan);
+ reg_save(&rp->rs_un.regsave, &backpos);
+ scan = OPERAND(scan);
+ }
+ }
+ break;
+
+ case RS_BRCPLX_MORE:
+ /* Pop the state. Restore pointers when there is no match. */
+ if (status == RA_NOMATCH)
+ {
+ reg_restore(&rp->rs_un.regsave, &backpos);
+ --brace_count[rp->rs_no]; /* decrement match count */
+ }
+ regstack_pop(&scan);
+ break;
+
+ case RS_BRCPLX_LONG:
+ /* Pop the state. Restore pointers when there is no match. */
+ if (status == RA_NOMATCH)
+ {
+ /* There was no match, but we did find enough matches. */
+ reg_restore(&rp->rs_un.regsave, &backpos);
+ --brace_count[rp->rs_no];
+ /* continue with the items after "\{}" */
+ status = RA_CONT;
+ }
+ regstack_pop(&scan);
+ if (status == RA_CONT)
+ scan = regnext(scan);
+ break;
+
+ case RS_BRCPLX_SHORT:
+ /* Pop the state. Restore pointers when there is no match. */
+ if (status == RA_NOMATCH)
+ /* There was no match, try to match one more item. */
+ reg_restore(&rp->rs_un.regsave, &backpos);
+ regstack_pop(&scan);
+ if (status == RA_NOMATCH)
+ {
+ scan = OPERAND(scan);
+ status = RA_CONT;
+ }
+ break;
+
+ case RS_NOMATCH:
+ /* Pop the state. If the operand matches for NOMATCH or
+ * doesn't match for MATCH/SUBPAT, we fail. Otherwise backup,
+ * except for SUBPAT, and continue with the next item. */
+ if (status == (rp->rs_no == NOMATCH ? RA_MATCH : RA_NOMATCH))
+ status = RA_NOMATCH;
+ else
+ {
+ status = RA_CONT;
+ if (rp->rs_no != SUBPAT) /* zero-width */
+ reg_restore(&rp->rs_un.regsave, &backpos);
+ }
+ regstack_pop(&scan);
+ if (status == RA_CONT)
+ scan = regnext(scan);
+ break;
+
+ case RS_BEHIND1:
+ if (status == RA_NOMATCH)
+ {
+ regstack_pop(&scan);
+ regstack.ga_len -= sizeof(regbehind_T);
+ }
+ else
+ {
+ /* The stuff after BEHIND/NOBEHIND matches. Now try if
+ * the behind part does (not) match before the current
+ * position in the input. This must be done at every
+ * position in the input and checking if the match ends at
+ * the current position. */
+
+ /* save the position after the found match for next */
+ reg_save(&(((regbehind_T *)rp) - 1)->save_after, &backpos);
+
+ /* Start looking for a match with operand at the current
+ * position. Go back one character until we find the
+ * result, hitting the start of the line or the previous
+ * line (for multi-line matching).
+ * Set behind_pos to where the match should end, BHPOS
+ * will match it. Save the current value. */
+ (((regbehind_T *)rp) - 1)->save_behind = behind_pos;
+ behind_pos = rp->rs_un.regsave;
+
+ rp->rs_state = RS_BEHIND2;
+
+ reg_restore(&rp->rs_un.regsave, &backpos);
+ scan = OPERAND(rp->rs_scan) + 4;
+ }
+ break;
+
+ case RS_BEHIND2:
+ /*
+ * Looping for BEHIND / NOBEHIND match.
+ */
+ if (status == RA_MATCH && reg_save_equal(&behind_pos))
+ {
+ /* found a match that ends where "next" started */
+ behind_pos = (((regbehind_T *)rp) - 1)->save_behind;
+ if (rp->rs_no == BEHIND)
+ reg_restore(&(((regbehind_T *)rp) - 1)->save_after,
+ &backpos);
+ else
+ {
+ /* But we didn't want a match. Need to restore the
+ * subexpr, because what follows matched, so they have
+ * been set. */
+ status = RA_NOMATCH;
+ restore_subexpr(((regbehind_T *)rp) - 1);
+ }
+ regstack_pop(&scan);
+ regstack.ga_len -= sizeof(regbehind_T);
+ }
+ else
+ {
+ long limit;
+
+ /* No match or a match that doesn't end where we want it: Go
+ * back one character. May go to previous line once. */
+ no = OK;
+ limit = OPERAND_MIN(rp->rs_scan);
+ if (REG_MULTI)
+ {
+ if (limit > 0
+ && ((rp->rs_un.regsave.rs_u.pos.lnum
+ < behind_pos.rs_u.pos.lnum
+ ? (colnr_T)STRLEN(rex.line)
+ : behind_pos.rs_u.pos.col)
+ - rp->rs_un.regsave.rs_u.pos.col >= limit))
+ no = FAIL;
+ else if (rp->rs_un.regsave.rs_u.pos.col == 0)
+ {
+ if (rp->rs_un.regsave.rs_u.pos.lnum
+ < behind_pos.rs_u.pos.lnum
+ || reg_getline(
+ --rp->rs_un.regsave.rs_u.pos.lnum)
+ == NULL)
+ no = FAIL;
+ else
+ {
+ reg_restore(&rp->rs_un.regsave, &backpos);
+ rp->rs_un.regsave.rs_u.pos.col =
+ (colnr_T)STRLEN(rex.line);
+ }
+ }
+ else
+ {
+ if (has_mbyte)
+ {
+ char_u *line =
+ reg_getline(rp->rs_un.regsave.rs_u.pos.lnum);
+
+ rp->rs_un.regsave.rs_u.pos.col -=
+ (*mb_head_off)(line, line
+ + rp->rs_un.regsave.rs_u.pos.col - 1) + 1;
+ }
+ else
+ --rp->rs_un.regsave.rs_u.pos.col;
+ }
+ }
+ else
+ {
+ if (rp->rs_un.regsave.rs_u.ptr == rex.line)
+ no = FAIL;
+ else
+ {
+ MB_PTR_BACK(rex.line, rp->rs_un.regsave.rs_u.ptr);
+ if (limit > 0 && (long)(behind_pos.rs_u.ptr
+ - rp->rs_un.regsave.rs_u.ptr) > limit)
+ no = FAIL;
+ }
+ }
+ if (no == OK)
+ {
+ /* Advanced, prepare for finding match again. */
+ reg_restore(&rp->rs_un.regsave, &backpos);
+ scan = OPERAND(rp->rs_scan) + 4;
+ if (status == RA_MATCH)
+ {
+ /* We did match, so subexpr may have been changed,
+ * need to restore them for the next try. */
+ status = RA_NOMATCH;
+ restore_subexpr(((regbehind_T *)rp) - 1);
+ }
+ }
+ else
+ {
+ /* Can't advance. For NOBEHIND that's a match. */
+ behind_pos = (((regbehind_T *)rp) - 1)->save_behind;
+ if (rp->rs_no == NOBEHIND)
+ {
+ reg_restore(&(((regbehind_T *)rp) - 1)->save_after,
+ &backpos);
+ status = RA_MATCH;
+ }
+ else
+ {
+ /* We do want a proper match. Need to restore the
+ * subexpr if we had a match, because they may have
+ * been set. */
+ if (status == RA_MATCH)
+ {
+ status = RA_NOMATCH;
+ restore_subexpr(((regbehind_T *)rp) - 1);
+ }
+ }
+ regstack_pop(&scan);
+ regstack.ga_len -= sizeof(regbehind_T);
+ }
+ }
+ break;
+
+ case RS_STAR_LONG:
+ case RS_STAR_SHORT:
+ {
+ regstar_T *rst = ((regstar_T *)rp) - 1;
+
+ if (status == RA_MATCH)
+ {
+ regstack_pop(&scan);
+ regstack.ga_len -= sizeof(regstar_T);
+ break;
+ }
+
+ /* Tried once already, restore input pointers. */
+ if (status != RA_BREAK)
+ reg_restore(&rp->rs_un.regsave, &backpos);
+
+ /* Repeat until we found a position where it could match. */
+ for (;;)
+ {
+ if (status != RA_BREAK)
+ {
+ /* Tried first position already, advance. */
+ if (rp->rs_state == RS_STAR_LONG)
+ {
+ /* Trying for longest match, but couldn't or
+ * didn't match -- back up one char. */
+ if (--rst->count < rst->minval)
+ break;
+ if (rex.input == rex.line)
+ {
+ /* backup to last char of previous line */
+ --rex.lnum;
+ rex.line = reg_getline(rex.lnum);
+ /* Just in case regrepeat() didn't count
+ * right. */
+ if (rex.line == NULL)
+ break;
+ rex.input = rex.line + STRLEN(rex.line);
+ fast_breakcheck();
+ }
+ else
+ MB_PTR_BACK(rex.line, rex.input);
+ }
+ else
+ {
+ /* Range is backwards, use shortest match first.
+ * Careful: maxval and minval are exchanged!
+ * Couldn't or didn't match: try advancing one
+ * char. */
+ if (rst->count == rst->minval
+ || regrepeat(OPERAND(rp->rs_scan), 1L) == 0)
+ break;
+ ++rst->count;
+ }
+ if (got_int)
+ break;
+ }
+ else
+ status = RA_NOMATCH;
+
+ /* If it could match, try it. */
+ if (rst->nextb == NUL || *rex.input == rst->nextb
+ || *rex.input == rst->nextb_ic)
+ {
+ reg_save(&rp->rs_un.regsave, &backpos);
+ scan = regnext(rp->rs_scan);
+ status = RA_CONT;
+ break;
+ }
+ }
+ if (status != RA_CONT)
+ {
+ /* Failed. */
+ regstack_pop(&scan);
+ regstack.ga_len -= sizeof(regstar_T);
+ status = RA_NOMATCH;
+ }
+ }
+ break;
+ }
+
+ /* If we want to continue the inner loop or didn't pop a state
+ * continue matching loop */
+ if (status == RA_CONT || rp == (regitem_T *)
+ ((char *)regstack.ga_data + regstack.ga_len) - 1)
+ break;
+ }
+
+ /* May need to continue with the inner loop, starting at "scan". */
+ if (status == RA_CONT)
+ continue;
+
+ /*
+ * If the regstack is empty or something failed we are done.
+ */
+ if (regstack.ga_len == 0 || status == RA_FAIL)
+ {
+ if (scan == NULL)
+ {
+ /*
+ * We get here only if there's trouble -- normally "case END" is
+ * the terminating point.
+ */
+ emsg(_(e_re_corr));
+#ifdef DEBUG
+ printf("Premature EOL\n");
+#endif
+ }
+ return (status == RA_MATCH);
+ }
+
+ } /* End of loop until the regstack is empty. */
+
+ /* NOTREACHED */
+}
+
+/*
+ * Push an item onto the regstack.
+ * Returns pointer to new item. Returns NULL when out of memory.
+ */
+ static regitem_T *
+regstack_push(regstate_T state, char_u *scan)
+{
+ regitem_T *rp;
+
+ if ((long)((unsigned)regstack.ga_len >> 10) >= p_mmp)
+ {
+ emsg(_(e_maxmempat));
+ return NULL;
+ }
+ if (ga_grow(&regstack, sizeof(regitem_T)) == FAIL)
+ return NULL;
+
+ rp = (regitem_T *)((char *)regstack.ga_data + regstack.ga_len);
+ rp->rs_state = state;
+ rp->rs_scan = scan;
+
+ regstack.ga_len += sizeof(regitem_T);
+ return rp;
+}
+
+/*
+ * Pop an item from the regstack.
+ */
+ static void
+regstack_pop(char_u **scan)
+{
+ regitem_T *rp;
+
+ rp = (regitem_T *)((char *)regstack.ga_data + regstack.ga_len) - 1;
+ *scan = rp->rs_scan;
+
+ regstack.ga_len -= sizeof(regitem_T);
+}
+
+/*
+ * regrepeat - repeatedly match something simple, return how many.
+ * Advances rex.input (and rex.lnum) to just after the matched chars.
+ */
+ static int
+regrepeat(
+ char_u *p,
+ long maxcount) /* maximum number of matches allowed */
+{
+ long count = 0;
+ char_u *scan;
+ char_u *opnd;
+ int mask;
+ int testval = 0;
+
+ scan = rex.input; /* Make local copy of rex.input for speed. */
+ opnd = OPERAND(p);
+ switch (OP(p))
+ {
+ case ANY:
+ case ANY + ADD_NL:
+ while (count < maxcount)
+ {
+ /* Matching anything means we continue until end-of-line (or
+ * end-of-file for ANY + ADD_NL), only limited by maxcount. */
+ while (*scan != NUL && count < maxcount)
+ {
+ ++count;
+ MB_PTR_ADV(scan);
+ }
+ if (!REG_MULTI || !WITH_NL(OP(p)) || rex.lnum > rex.reg_maxline
+ || rex.reg_line_lbr || count == maxcount)
+ break;
+ ++count; /* count the line-break */
+ reg_nextline();
+ scan = rex.input;
+ if (got_int)
+ break;
+ }
+ break;
+
+ case IDENT:
+ case IDENT + ADD_NL:
+ testval = TRUE;
+ /* FALLTHROUGH */
+ case SIDENT:
+ case SIDENT + ADD_NL:
+ while (count < maxcount)
+ {
+ if (vim_isIDc(PTR2CHAR(scan)) && (testval || !VIM_ISDIGIT(*scan)))
+ {
+ MB_PTR_ADV(scan);
+ }
+ else if (*scan == NUL)
+ {
+ if (!REG_MULTI || !WITH_NL(OP(p)) || rex.lnum > rex.reg_maxline
+ || rex.reg_line_lbr)
+ break;
+ reg_nextline();
+ scan = rex.input;
+ if (got_int)
+ break;
+ }
+ else if (rex.reg_line_lbr && *scan == '\n' && WITH_NL(OP(p)))
+ ++scan;
+ else
+ break;
+ ++count;
+ }
+ break;
+
+ case KWORD:
+ case KWORD + ADD_NL:
+ testval = TRUE;
+ /* FALLTHROUGH */
+ case SKWORD:
+ case SKWORD + ADD_NL:
+ while (count < maxcount)
+ {
+ if (vim_iswordp_buf(scan, rex.reg_buf)
+ && (testval || !VIM_ISDIGIT(*scan)))
+ {
+ MB_PTR_ADV(scan);
+ }
+ else if (*scan == NUL)
+ {
+ if (!REG_MULTI || !WITH_NL(OP(p)) || rex.lnum > rex.reg_maxline
+ || rex.reg_line_lbr)
+ break;
+ reg_nextline();
+ scan = rex.input;
+ if (got_int)
+ break;
+ }
+ else if (rex.reg_line_lbr && *scan == '\n' && WITH_NL(OP(p)))
+ ++scan;
+ else
+ break;
+ ++count;
+ }
+ break;
+
+ case FNAME:
+ case FNAME + ADD_NL:
+ testval = TRUE;
+ /* FALLTHROUGH */
+ case SFNAME:
+ case SFNAME + ADD_NL:
+ while (count < maxcount)
+ {
+ if (vim_isfilec(PTR2CHAR(scan)) && (testval || !VIM_ISDIGIT(*scan)))
+ {
+ MB_PTR_ADV(scan);
+ }
+ else if (*scan == NUL)
+ {
+ if (!REG_MULTI || !WITH_NL(OP(p)) || rex.lnum > rex.reg_maxline
+ || rex.reg_line_lbr)
+ break;
+ reg_nextline();
+ scan = rex.input;
+ if (got_int)
+ break;
+ }
+ else if (rex.reg_line_lbr && *scan == '\n' && WITH_NL(OP(p)))
+ ++scan;
+ else
+ break;
+ ++count;
+ }
+ break;
+
+ case PRINT:
+ case PRINT + ADD_NL:
+ testval = TRUE;
+ /* FALLTHROUGH */
+ case SPRINT:
+ case SPRINT + ADD_NL:
+ while (count < maxcount)
+ {
+ if (*scan == NUL)
+ {
+ if (!REG_MULTI || !WITH_NL(OP(p)) || rex.lnum > rex.reg_maxline
+ || rex.reg_line_lbr)
+ break;
+ reg_nextline();
+ scan = rex.input;
+ if (got_int)
+ break;
+ }
+ else if (vim_isprintc(PTR2CHAR(scan)) == 1
+ && (testval || !VIM_ISDIGIT(*scan)))
+ {
+ MB_PTR_ADV(scan);
+ }
+ else if (rex.reg_line_lbr && *scan == '\n' && WITH_NL(OP(p)))
+ ++scan;
+ else
+ break;
+ ++count;
+ }
+ break;
+
+ case WHITE:
+ case WHITE + ADD_NL:
+ testval = mask = RI_WHITE;
+do_class:
+ while (count < maxcount)
+ {
+ int l;
+
+ if (*scan == NUL)
+ {
+ if (!REG_MULTI || !WITH_NL(OP(p)) || rex.lnum > rex.reg_maxline
+ || rex.reg_line_lbr)
+ break;
+ reg_nextline();
+ scan = rex.input;
+ if (got_int)
+ break;
+ }
+ else if (has_mbyte && (l = (*mb_ptr2len)(scan)) > 1)
+ {
+ if (testval != 0)
+ break;
+ scan += l;
+ }
+ else if ((class_tab[*scan] & mask) == testval)
+ ++scan;
+ else if (rex.reg_line_lbr && *scan == '\n' && WITH_NL(OP(p)))
+ ++scan;
+ else
+ break;
+ ++count;
+ }
+ break;
+
+ case NWHITE:
+ case NWHITE + ADD_NL:
+ mask = RI_WHITE;
+ goto do_class;
+ case DIGIT:
+ case DIGIT + ADD_NL:
+ testval = mask = RI_DIGIT;
+ goto do_class;
+ case NDIGIT:
+ case NDIGIT + ADD_NL:
+ mask = RI_DIGIT;
+ goto do_class;
+ case HEX:
+ case HEX + ADD_NL:
+ testval = mask = RI_HEX;
+ goto do_class;
+ case NHEX:
+ case NHEX + ADD_NL:
+ mask = RI_HEX;
+ goto do_class;
+ case OCTAL:
+ case OCTAL + ADD_NL:
+ testval = mask = RI_OCTAL;
+ goto do_class;
+ case NOCTAL:
+ case NOCTAL + ADD_NL:
+ mask = RI_OCTAL;
+ goto do_class;
+ case WORD:
+ case WORD + ADD_NL:
+ testval = mask = RI_WORD;
+ goto do_class;
+ case NWORD:
+ case NWORD + ADD_NL:
+ mask = RI_WORD;
+ goto do_class;
+ case HEAD:
+ case HEAD + ADD_NL:
+ testval = mask = RI_HEAD;
+ goto do_class;
+ case NHEAD:
+ case NHEAD + ADD_NL:
+ mask = RI_HEAD;
+ goto do_class;
+ case ALPHA:
+ case ALPHA + ADD_NL:
+ testval = mask = RI_ALPHA;
+ goto do_class;
+ case NALPHA:
+ case NALPHA + ADD_NL:
+ mask = RI_ALPHA;
+ goto do_class;
+ case LOWER:
+ case LOWER + ADD_NL:
+ testval = mask = RI_LOWER;
+ goto do_class;
+ case NLOWER:
+ case NLOWER + ADD_NL:
+ mask = RI_LOWER;
+ goto do_class;
+ case UPPER:
+ case UPPER + ADD_NL:
+ testval = mask = RI_UPPER;
+ goto do_class;
+ case NUPPER:
+ case NUPPER + ADD_NL:
+ mask = RI_UPPER;
+ goto do_class;
+
+ case EXACTLY:
+ {
+ int cu, cl;
+
+ /* This doesn't do a multi-byte character, because a MULTIBYTECODE
+ * would have been used for it. It does handle single-byte
+ * characters, such as latin1. */
+ if (rex.reg_ic)
+ {
+ cu = MB_TOUPPER(*opnd);
+ cl = MB_TOLOWER(*opnd);
+ while (count < maxcount && (*scan == cu || *scan == cl))
+ {
+ count++;
+ scan++;
+ }
+ }
+ else
+ {
+ cu = *opnd;
+ while (count < maxcount && *scan == cu)
+ {
+ count++;
+ scan++;
+ }
+ }
+ break;
+ }
+
+ case MULTIBYTECODE:
+ {
+ int i, len, cf = 0;
+
+ /* Safety check (just in case 'encoding' was changed since
+ * compiling the program). */
+ if ((len = (*mb_ptr2len)(opnd)) > 1)
+ {
+ if (rex.reg_ic && enc_utf8)
+ cf = utf_fold(utf_ptr2char(opnd));
+ while (count < maxcount && (*mb_ptr2len)(scan) >= len)
+ {
+ for (i = 0; i < len; ++i)
+ if (opnd[i] != scan[i])
+ break;
+ if (i < len && (!rex.reg_ic || !enc_utf8
+ || utf_fold(utf_ptr2char(scan)) != cf))
+ break;
+ scan += len;
+ ++count;
+ }
+ }
+ }
+ break;
+
+ case ANYOF:
+ case ANYOF + ADD_NL:
+ testval = TRUE;
+ /* FALLTHROUGH */
+
+ case ANYBUT:
+ case ANYBUT + ADD_NL:
+ while (count < maxcount)
+ {
+ int len;
+
+ if (*scan == NUL)
+ {
+ if (!REG_MULTI || !WITH_NL(OP(p)) || rex.lnum > rex.reg_maxline
+ || rex.reg_line_lbr)
+ break;
+ reg_nextline();
+ scan = rex.input;
+ if (got_int)
+ break;
+ }
+ else if (rex.reg_line_lbr && *scan == '\n' && WITH_NL(OP(p)))
+ ++scan;
+ else if (has_mbyte && (len = (*mb_ptr2len)(scan)) > 1)
+ {
+ if ((cstrchr(opnd, (*mb_ptr2char)(scan)) == NULL) == testval)
+ break;
+ scan += len;
+ }
+ else
+ {
+ if ((cstrchr(opnd, *scan) == NULL) == testval)
+ break;
+ ++scan;
+ }
+ ++count;
+ }
+ break;
+
+ case NEWL:
+ while (count < maxcount
+ && ((*scan == NUL && rex.lnum <= rex.reg_maxline
+ && !rex.reg_line_lbr && REG_MULTI)
+ || (*scan == '\n' && rex.reg_line_lbr)))
+ {
+ count++;
+ if (rex.reg_line_lbr)
+ ADVANCE_REGINPUT();
+ else
+ reg_nextline();
+ scan = rex.input;
+ if (got_int)
+ break;
+ }
+ break;
+
+ default: /* Oh dear. Called inappropriately. */
+ emsg(_(e_re_corr));
+#ifdef DEBUG
+ printf("Called regrepeat with op code %d\n", OP(p));
+#endif
+ break;
+ }
+
+ rex.input = scan;
+
+ return (int)count;
+}
+
+/*
+ * regnext - dig the "next" pointer out of a node
+ * Returns NULL when calculating size, when there is no next item and when
+ * there is an error.
+ */
+ static char_u *
+regnext(char_u *p)
+{
+ int offset;
+
+ if (p == JUST_CALC_SIZE || reg_toolong)
+ return NULL;
+
+ offset = NEXT(p);
+ if (offset == 0)
+ return NULL;
+
+ if (OP(p) == BACK)
+ return p - offset;
+ else
+ return p + offset;
+}
+
+/*
+ * Check the regexp program for its magic number.
+ * Return TRUE if it's wrong.
+ */
+ static int
+prog_magic_wrong(void)
+{
+ regprog_T *prog;
+
+ prog = REG_MULTI ? rex.reg_mmatch->regprog : rex.reg_match->regprog;
+ if (prog->engine == &nfa_regengine)
+ /* For NFA matcher we don't check the magic */
+ return FALSE;
+
+ if (UCHARAT(((bt_regprog_T *)prog)->program) != REGMAGIC)
+ {
+ emsg(_(e_re_corr));
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * Cleanup the subexpressions, if this wasn't done yet.
+ * This construction is used to clear the subexpressions only when they are
+ * used (to increase speed).
+ */
+ static void
+cleanup_subexpr(void)
+{
+ if (rex.need_clear_subexpr)
+ {
+ if (REG_MULTI)
+ {
+ /* Use 0xff to set lnum to -1 */
+ vim_memset(rex.reg_startpos, 0xff, sizeof(lpos_T) * NSUBEXP);
+ vim_memset(rex.reg_endpos, 0xff, sizeof(lpos_T) * NSUBEXP);
+ }
+ else
+ {
+ vim_memset(rex.reg_startp, 0, sizeof(char_u *) * NSUBEXP);
+ vim_memset(rex.reg_endp, 0, sizeof(char_u *) * NSUBEXP);
+ }
+ rex.need_clear_subexpr = FALSE;
+ }
+}
+
+#ifdef FEAT_SYN_HL
+ static void
+cleanup_zsubexpr(void)
+{
+ if (rex.need_clear_zsubexpr)
+ {
+ if (REG_MULTI)
+ {
+ /* Use 0xff to set lnum to -1 */
+ vim_memset(reg_startzpos, 0xff, sizeof(lpos_T) * NSUBEXP);
+ vim_memset(reg_endzpos, 0xff, sizeof(lpos_T) * NSUBEXP);
+ }
+ else
+ {
+ vim_memset(reg_startzp, 0, sizeof(char_u *) * NSUBEXP);
+ vim_memset(reg_endzp, 0, sizeof(char_u *) * NSUBEXP);
+ }
+ rex.need_clear_zsubexpr = FALSE;
+ }
+}
+#endif
+
+/*
+ * Save the current subexpr to "bp", so that they can be restored
+ * later by restore_subexpr().
+ */
+ static void
+save_subexpr(regbehind_T *bp)
+{
+ int i;
+
+ /* When "rex.need_clear_subexpr" is set we don't need to save the values, only
+ * remember that this flag needs to be set again when restoring. */
+ bp->save_need_clear_subexpr = rex.need_clear_subexpr;
+ if (!rex.need_clear_subexpr)
+ {
+ for (i = 0; i < NSUBEXP; ++i)
+ {
+ if (REG_MULTI)
+ {
+ bp->save_start[i].se_u.pos = rex.reg_startpos[i];
+ bp->save_end[i].se_u.pos = rex.reg_endpos[i];
+ }
+ else
+ {
+ bp->save_start[i].se_u.ptr = rex.reg_startp[i];
+ bp->save_end[i].se_u.ptr = rex.reg_endp[i];
+ }
+ }
+ }
+}
+
+/*
+ * Restore the subexpr from "bp".
+ */
+ static void
+restore_subexpr(regbehind_T *bp)
+{
+ int i;
+
+ /* Only need to restore saved values when they are not to be cleared. */
+ rex.need_clear_subexpr = bp->save_need_clear_subexpr;
+ if (!rex.need_clear_subexpr)
+ {
+ for (i = 0; i < NSUBEXP; ++i)
+ {
+ if (REG_MULTI)
+ {
+ rex.reg_startpos[i] = bp->save_start[i].se_u.pos;
+ rex.reg_endpos[i] = bp->save_end[i].se_u.pos;
+ }
+ else
+ {
+ rex.reg_startp[i] = bp->save_start[i].se_u.ptr;
+ rex.reg_endp[i] = bp->save_end[i].se_u.ptr;
+ }
+ }
+ }
+}
+
+/*
+ * Advance rex.lnum, rex.line and rex.input to the next line.
+ */
+ static void
+reg_nextline(void)
+{
+ rex.line = reg_getline(++rex.lnum);
+ rex.input = rex.line;
+ fast_breakcheck();
+}
+
+/*
+ * Save the input line and position in a regsave_T.
+ */
+ static void
+reg_save(regsave_T *save, garray_T *gap)
+{
+ if (REG_MULTI)
+ {
+ save->rs_u.pos.col = (colnr_T)(rex.input - rex.line);
+ save->rs_u.pos.lnum = rex.lnum;
+ }
+ else
+ save->rs_u.ptr = rex.input;
+ save->rs_len = gap->ga_len;
+}
+
+/*
+ * Restore the input line and position from a regsave_T.
+ */
+ static void
+reg_restore(regsave_T *save, garray_T *gap)
+{
+ if (REG_MULTI)
+ {
+ if (rex.lnum != save->rs_u.pos.lnum)
+ {
+ /* only call reg_getline() when the line number changed to save
+ * a bit of time */
+ rex.lnum = save->rs_u.pos.lnum;
+ rex.line = reg_getline(rex.lnum);
+ }
+ rex.input = rex.line + save->rs_u.pos.col;
+ }
+ else
+ rex.input = save->rs_u.ptr;
+ gap->ga_len = save->rs_len;
+}
+
+/*
+ * Return TRUE if current position is equal to saved position.
+ */
+ static int
+reg_save_equal(regsave_T *save)
+{
+ if (REG_MULTI)
+ return rex.lnum == save->rs_u.pos.lnum
+ && rex.input == rex.line + save->rs_u.pos.col;
+ return rex.input == save->rs_u.ptr;
+}
+
+/*
+ * Tentatively set the sub-expression start to the current position (after
+ * calling regmatch() they will have changed). Need to save the existing
+ * values for when there is no match.
+ * Use se_save() to use pointer (save_se_multi()) or position (save_se_one()),
+ * depending on REG_MULTI.
+ */
+ static void
+save_se_multi(save_se_T *savep, lpos_T *posp)
+{
+ savep->se_u.pos = *posp;
+ posp->lnum = rex.lnum;
+ posp->col = (colnr_T)(rex.input - rex.line);
+}
+
+ static void
+save_se_one(save_se_T *savep, char_u **pp)
+{
+ savep->se_u.ptr = *pp;
+ *pp = rex.input;
+}
+
+/*
+ * Compare a number with the operand of RE_LNUM, RE_COL or RE_VCOL.
+ */
+ static int
+re_num_cmp(long_u val, char_u *scan)
+{
+ long_u n = OPERAND_MIN(scan);
+
+ if (OPERAND_CMP(scan) == '>')
+ return val > n;
+ if (OPERAND_CMP(scan) == '<')
+ return val < n;
+ return val == n;
+}
+
+/*
+ * Check whether a backreference matches.
+ * Returns RA_FAIL, RA_NOMATCH or RA_MATCH.
+ * If "bytelen" is not NULL, it is set to the byte length of the match in the
+ * last line.
+ */
+ static int
+match_with_backref(
+ linenr_T start_lnum,
+ colnr_T start_col,
+ linenr_T end_lnum,
+ colnr_T end_col,
+ int *bytelen)
+{
+ linenr_T clnum = start_lnum;
+ colnr_T ccol = start_col;
+ int len;
+ char_u *p;
+
+ if (bytelen != NULL)
+ *bytelen = 0;
+ for (;;)
+ {
+ /* Since getting one line may invalidate the other, need to make copy.
+ * Slow! */
+ if (rex.line != reg_tofree)
+ {
+ len = (int)STRLEN(rex.line);
+ if (reg_tofree == NULL || len >= (int)reg_tofreelen)
+ {
+ len += 50; /* get some extra */
+ vim_free(reg_tofree);
+ reg_tofree = alloc(len);
+ if (reg_tofree == NULL)
+ return RA_FAIL; /* out of memory!*/
+ reg_tofreelen = len;
+ }
+ STRCPY(reg_tofree, rex.line);
+ rex.input = reg_tofree + (rex.input - rex.line);
+ rex.line = reg_tofree;
+ }
+
+ /* Get the line to compare with. */
+ p = reg_getline(clnum);
+ if (clnum == end_lnum)
+ len = end_col - ccol;
+ else
+ len = (int)STRLEN(p + ccol);
+
+ if (cstrncmp(p + ccol, rex.input, &len) != 0)
+ return RA_NOMATCH; /* doesn't match */
+ if (bytelen != NULL)
+ *bytelen += len;
+ if (clnum == end_lnum)
+ break; /* match and at end! */
+ if (rex.lnum >= rex.reg_maxline)
+ return RA_NOMATCH; /* text too short */
+
+ /* Advance to next line. */
+ reg_nextline();
+ if (bytelen != NULL)
+ *bytelen = 0;
+ ++clnum;
+ ccol = 0;
+ if (got_int)
+ return RA_FAIL;
+ }
+
+ /* found a match! Note that rex.line may now point to a copy of the line,
+ * that should not matter. */
+ return RA_MATCH;
+}
+
+#ifdef BT_REGEXP_DUMP
+
+/*
+ * regdump - dump a regexp onto stdout in vaguely comprehensible form
+ */
+ static void
+regdump(char_u *pattern, bt_regprog_T *r)
+{
+ char_u *s;
+ int op = EXACTLY; /* Arbitrary non-END op. */
+ char_u *next;
+ char_u *end = NULL;
+ FILE *f;
+
+#ifdef BT_REGEXP_LOG
+ f = fopen("bt_regexp_log.log", "a");
+#else
+ f = stdout;
+#endif
+ if (f == NULL)
+ return;
+ fprintf(f, "-------------------------------------\n\r\nregcomp(%s):\r\n", pattern);
+
+ s = r->program + 1;
+ /*
+ * Loop until we find the END that isn't before a referred next (an END
+ * can also appear in a NOMATCH operand).
+ */
+ while (op != END || s <= end)
+ {
+ op = OP(s);
+ fprintf(f, "%2d%s", (int)(s - r->program), regprop(s)); /* Where, what. */
+ next = regnext(s);
+ if (next == NULL) /* Next ptr. */
+ fprintf(f, "(0)");
+ else
+ fprintf(f, "(%d)", (int)((s - r->program) + (next - s)));
+ if (end < next)
+ end = next;
+ if (op == BRACE_LIMITS)
+ {
+ /* Two ints */
+ fprintf(f, " minval %ld, maxval %ld", OPERAND_MIN(s), OPERAND_MAX(s));
+ s += 8;
+ }
+ else if (op == BEHIND || op == NOBEHIND)
+ {
+ /* one int */
+ fprintf(f, " count %ld", OPERAND_MIN(s));
+ s += 4;
+ }
+ else if (op == RE_LNUM || op == RE_COL || op == RE_VCOL)
+ {
+ /* one int plus comperator */
+ fprintf(f, " count %ld", OPERAND_MIN(s));
+ s += 5;
+ }
+ s += 3;
+ if (op == ANYOF || op == ANYOF + ADD_NL
+ || op == ANYBUT || op == ANYBUT + ADD_NL
+ || op == EXACTLY)
+ {
+ /* Literal string, where present. */
+ fprintf(f, "\nxxxxxxxxx\n");
+ while (*s != NUL)
+ fprintf(f, "%c", *s++);
+ fprintf(f, "\nxxxxxxxxx\n");
+ s++;
+ }
+ fprintf(f, "\r\n");
+ }
+
+ /* Header fields of interest. */
+ if (r->regstart != NUL)
+ fprintf(f, "start `%s' 0x%x; ", r->regstart < 256
+ ? (char *)transchar(r->regstart)
+ : "multibyte", r->regstart);
+ if (r->reganch)
+ fprintf(f, "anchored; ");
+ if (r->regmust != NULL)
+ fprintf(f, "must have \"%s\"", r->regmust);
+ fprintf(f, "\r\n");
+
+#ifdef BT_REGEXP_LOG
+ fclose(f);
+#endif
+}
+#endif /* BT_REGEXP_DUMP */
+
+#ifdef DEBUG
+/*
+ * regprop - printable representation of opcode
+ */
+ static char_u *
+regprop(char_u *op)
+{
+ char *p;
+ static char buf[50];
+
+ STRCPY(buf, ":");
+
+ switch ((int) OP(op))
+ {
+ case BOL:
+ p = "BOL";
+ break;
+ case EOL:
+ p = "EOL";
+ break;
+ case RE_BOF:
+ p = "BOF";
+ break;
+ case RE_EOF:
+ p = "EOF";
+ break;
+ case CURSOR:
+ p = "CURSOR";
+ break;
+ case RE_VISUAL:
+ p = "RE_VISUAL";
+ break;
+ case RE_LNUM:
+ p = "RE_LNUM";
+ break;
+ case RE_MARK:
+ p = "RE_MARK";
+ break;
+ case RE_COL:
+ p = "RE_COL";
+ break;
+ case RE_VCOL:
+ p = "RE_VCOL";
+ break;
+ case BOW:
+ p = "BOW";
+ break;
+ case EOW:
+ p = "EOW";
+ break;
+ case ANY:
+ p = "ANY";
+ break;
+ case ANY + ADD_NL:
+ p = "ANY+NL";
+ break;
+ case ANYOF:
+ p = "ANYOF";
+ break;
+ case ANYOF + ADD_NL:
+ p = "ANYOF+NL";
+ break;
+ case ANYBUT:
+ p = "ANYBUT";
+ break;
+ case ANYBUT + ADD_NL:
+ p = "ANYBUT+NL";
+ break;
+ case IDENT:
+ p = "IDENT";
+ break;
+ case IDENT + ADD_NL:
+ p = "IDENT+NL";
+ break;
+ case SIDENT:
+ p = "SIDENT";
+ break;
+ case SIDENT + ADD_NL:
+ p = "SIDENT+NL";
+ break;
+ case KWORD:
+ p = "KWORD";
+ break;
+ case KWORD + ADD_NL:
+ p = "KWORD+NL";
+ break;
+ case SKWORD:
+ p = "SKWORD";
+ break;
+ case SKWORD + ADD_NL:
+ p = "SKWORD+NL";
+ break;
+ case FNAME:
+ p = "FNAME";
+ break;
+ case FNAME + ADD_NL:
+ p = "FNAME+NL";
+ break;
+ case SFNAME:
+ p = "SFNAME";
+ break;
+ case SFNAME + ADD_NL:
+ p = "SFNAME+NL";
+ break;
+ case PRINT:
+ p = "PRINT";
+ break;
+ case PRINT + ADD_NL:
+ p = "PRINT+NL";
+ break;
+ case SPRINT:
+ p = "SPRINT";
+ break;
+ case SPRINT + ADD_NL:
+ p = "SPRINT+NL";
+ break;
+ case WHITE:
+ p = "WHITE";
+ break;
+ case WHITE + ADD_NL:
+ p = "WHITE+NL";
+ break;
+ case NWHITE:
+ p = "NWHITE";
+ break;
+ case NWHITE + ADD_NL:
+ p = "NWHITE+NL";
+ break;
+ case DIGIT:
+ p = "DIGIT";
+ break;
+ case DIGIT + ADD_NL:
+ p = "DIGIT+NL";
+ break;
+ case NDIGIT:
+ p = "NDIGIT";
+ break;
+ case NDIGIT + ADD_NL:
+ p = "NDIGIT+NL";
+ break;
+ case HEX:
+ p = "HEX";
+ break;
+ case HEX + ADD_NL:
+ p = "HEX+NL";
+ break;
+ case NHEX:
+ p = "NHEX";
+ break;
+ case NHEX + ADD_NL:
+ p = "NHEX+NL";
+ break;
+ case OCTAL:
+ p = "OCTAL";
+ break;
+ case OCTAL + ADD_NL:
+ p = "OCTAL+NL";
+ break;
+ case NOCTAL:
+ p = "NOCTAL";
+ break;
+ case NOCTAL + ADD_NL:
+ p = "NOCTAL+NL";
+ break;
+ case WORD:
+ p = "WORD";
+ break;
+ case WORD + ADD_NL:
+ p = "WORD+NL";
+ break;
+ case NWORD:
+ p = "NWORD";
+ break;
+ case NWORD + ADD_NL:
+ p = "NWORD+NL";
+ break;
+ case HEAD:
+ p = "HEAD";
+ break;
+ case HEAD + ADD_NL:
+ p = "HEAD+NL";
+ break;
+ case NHEAD:
+ p = "NHEAD";
+ break;
+ case NHEAD + ADD_NL:
+ p = "NHEAD+NL";
+ break;
+ case ALPHA:
+ p = "ALPHA";
+ break;
+ case ALPHA + ADD_NL:
+ p = "ALPHA+NL";
+ break;
+ case NALPHA:
+ p = "NALPHA";
+ break;
+ case NALPHA + ADD_NL:
+ p = "NALPHA+NL";
+ break;
+ case LOWER:
+ p = "LOWER";
+ break;
+ case LOWER + ADD_NL:
+ p = "LOWER+NL";
+ break;
+ case NLOWER:
+ p = "NLOWER";
+ break;
+ case NLOWER + ADD_NL:
+ p = "NLOWER+NL";
+ break;
+ case UPPER:
+ p = "UPPER";
+ break;
+ case UPPER + ADD_NL:
+ p = "UPPER+NL";
+ break;
+ case NUPPER:
+ p = "NUPPER";
+ break;
+ case NUPPER + ADD_NL:
+ p = "NUPPER+NL";
+ break;
+ case BRANCH:
+ p = "BRANCH";
+ break;
+ case EXACTLY:
+ p = "EXACTLY";
+ break;
+ case NOTHING:
+ p = "NOTHING";
+ break;
+ case BACK:
+ p = "BACK";
+ break;
+ case END:
+ p = "END";
+ break;
+ case MOPEN + 0:
+ p = "MATCH START";
+ break;
+ case MOPEN + 1:
+ case MOPEN + 2:
+ case MOPEN + 3:
+ case MOPEN + 4:
+ case MOPEN + 5:
+ case MOPEN + 6:
+ case MOPEN + 7:
+ case MOPEN + 8:
+ case MOPEN + 9:
+ sprintf(buf + STRLEN(buf), "MOPEN%d", OP(op) - MOPEN);
+ p = NULL;
+ break;
+ case MCLOSE + 0:
+ p = "MATCH END";
+ break;
+ case MCLOSE + 1:
+ case MCLOSE + 2:
+ case MCLOSE + 3:
+ case MCLOSE + 4:
+ case MCLOSE + 5:
+ case MCLOSE + 6:
+ case MCLOSE + 7:
+ case MCLOSE + 8:
+ case MCLOSE + 9:
+ sprintf(buf + STRLEN(buf), "MCLOSE%d", OP(op) - MCLOSE);
+ p = NULL;
+ break;
+ case BACKREF + 1:
+ case BACKREF + 2:
+ case BACKREF + 3:
+ case BACKREF + 4:
+ case BACKREF + 5:
+ case BACKREF + 6:
+ case BACKREF + 7:
+ case BACKREF + 8:
+ case BACKREF + 9:
+ sprintf(buf + STRLEN(buf), "BACKREF%d", OP(op) - BACKREF);
+ p = NULL;
+ break;
+ case NOPEN:
+ p = "NOPEN";
+ break;
+ case NCLOSE:
+ p = "NCLOSE";
+ break;
+#ifdef FEAT_SYN_HL
+ case ZOPEN + 1:
+ case ZOPEN + 2:
+ case ZOPEN + 3:
+ case ZOPEN + 4:
+ case ZOPEN + 5:
+ case ZOPEN + 6:
+ case ZOPEN + 7:
+ case ZOPEN + 8:
+ case ZOPEN + 9:
+ sprintf(buf + STRLEN(buf), "ZOPEN%d", OP(op) - ZOPEN);
+ p = NULL;
+ break;
+ case ZCLOSE + 1:
+ case ZCLOSE + 2:
+ case ZCLOSE + 3:
+ case ZCLOSE + 4:
+ case ZCLOSE + 5:
+ case ZCLOSE + 6:
+ case ZCLOSE + 7:
+ case ZCLOSE + 8:
+ case ZCLOSE + 9:
+ sprintf(buf + STRLEN(buf), "ZCLOSE%d", OP(op) - ZCLOSE);
+ p = NULL;
+ break;
+ case ZREF + 1:
+ case ZREF + 2:
+ case ZREF + 3:
+ case ZREF + 4:
+ case ZREF + 5:
+ case ZREF + 6:
+ case ZREF + 7:
+ case ZREF + 8:
+ case ZREF + 9:
+ sprintf(buf + STRLEN(buf), "ZREF%d", OP(op) - ZREF);
+ p = NULL;
+ break;
+#endif
+ case STAR:
+ p = "STAR";
+ break;
+ case PLUS:
+ p = "PLUS";
+ break;
+ case NOMATCH:
+ p = "NOMATCH";
+ break;
+ case MATCH:
+ p = "MATCH";
+ break;
+ case BEHIND:
+ p = "BEHIND";
+ break;
+ case NOBEHIND:
+ p = "NOBEHIND";
+ break;
+ case SUBPAT:
+ p = "SUBPAT";
+ break;
+ case BRACE_LIMITS:
+ p = "BRACE_LIMITS";
+ break;
+ case BRACE_SIMPLE:
+ p = "BRACE_SIMPLE";
+ break;
+ case BRACE_COMPLEX + 0:
+ case BRACE_COMPLEX + 1:
+ case BRACE_COMPLEX + 2:
+ case BRACE_COMPLEX + 3:
+ case BRACE_COMPLEX + 4:
+ case BRACE_COMPLEX + 5:
+ case BRACE_COMPLEX + 6:
+ case BRACE_COMPLEX + 7:
+ case BRACE_COMPLEX + 8:
+ case BRACE_COMPLEX + 9:
+ sprintf(buf + STRLEN(buf), "BRACE_COMPLEX%d", OP(op) - BRACE_COMPLEX);
+ p = NULL;
+ break;
+ case MULTIBYTECODE:
+ p = "MULTIBYTECODE";
+ break;
+ case NEWL:
+ p = "NEWL";
+ break;
+ default:
+ sprintf(buf + STRLEN(buf), "corrupt %d", OP(op));
+ p = NULL;
+ break;
+ }
+ if (p != NULL)
+ STRCAT(buf, p);
+ return (char_u *)buf;
+}
+#endif /* DEBUG */
+
+/*
+ * Used in a place where no * or \+ can follow.
+ */
+ static int
+re_mult_next(char *what)
+{
+ if (re_multi_type(peekchr()) == MULTI_MULT)
+ {
+ semsg(_("E888: (NFA regexp) cannot repeat %s"), what);
+ rc_did_emsg = TRUE;
+ return FAIL;
+ }
+ return OK;
+}
+
+typedef struct
+{
+ int a, b, c;
+} decomp_T;
+
+
+/* 0xfb20 - 0xfb4f */
+static decomp_T decomp_table[0xfb4f-0xfb20+1] =
+{
+ {0x5e2,0,0}, /* 0xfb20 alt ayin */
+ {0x5d0,0,0}, /* 0xfb21 alt alef */
+ {0x5d3,0,0}, /* 0xfb22 alt dalet */
+ {0x5d4,0,0}, /* 0xfb23 alt he */
+ {0x5db,0,0}, /* 0xfb24 alt kaf */
+ {0x5dc,0,0}, /* 0xfb25 alt lamed */
+ {0x5dd,0,0}, /* 0xfb26 alt mem-sofit */
+ {0x5e8,0,0}, /* 0xfb27 alt resh */
+ {0x5ea,0,0}, /* 0xfb28 alt tav */
+ {'+', 0, 0}, /* 0xfb29 alt plus */
+ {0x5e9, 0x5c1, 0}, /* 0xfb2a shin+shin-dot */
+ {0x5e9, 0x5c2, 0}, /* 0xfb2b shin+sin-dot */
+ {0x5e9, 0x5c1, 0x5bc}, /* 0xfb2c shin+shin-dot+dagesh */
+ {0x5e9, 0x5c2, 0x5bc}, /* 0xfb2d shin+sin-dot+dagesh */
+ {0x5d0, 0x5b7, 0}, /* 0xfb2e alef+patah */
+ {0x5d0, 0x5b8, 0}, /* 0xfb2f alef+qamats */
+ {0x5d0, 0x5b4, 0}, /* 0xfb30 alef+hiriq */
+ {0x5d1, 0x5bc, 0}, /* 0xfb31 bet+dagesh */
+ {0x5d2, 0x5bc, 0}, /* 0xfb32 gimel+dagesh */
+ {0x5d3, 0x5bc, 0}, /* 0xfb33 dalet+dagesh */
+ {0x5d4, 0x5bc, 0}, /* 0xfb34 he+dagesh */
+ {0x5d5, 0x5bc, 0}, /* 0xfb35 vav+dagesh */
+ {0x5d6, 0x5bc, 0}, /* 0xfb36 zayin+dagesh */
+ {0xfb37, 0, 0}, /* 0xfb37 -- UNUSED */
+ {0x5d8, 0x5bc, 0}, /* 0xfb38 tet+dagesh */
+ {0x5d9, 0x5bc, 0}, /* 0xfb39 yud+dagesh */
+ {0x5da, 0x5bc, 0}, /* 0xfb3a kaf sofit+dagesh */
+ {0x5db, 0x5bc, 0}, /* 0xfb3b kaf+dagesh */
+ {0x5dc, 0x5bc, 0}, /* 0xfb3c lamed+dagesh */
+ {0xfb3d, 0, 0}, /* 0xfb3d -- UNUSED */
+ {0x5de, 0x5bc, 0}, /* 0xfb3e mem+dagesh */
+ {0xfb3f, 0, 0}, /* 0xfb3f -- UNUSED */
+ {0x5e0, 0x5bc, 0}, /* 0xfb40 nun+dagesh */
+ {0x5e1, 0x5bc, 0}, /* 0xfb41 samech+dagesh */
+ {0xfb42, 0, 0}, /* 0xfb42 -- UNUSED */
+ {0x5e3, 0x5bc, 0}, /* 0xfb43 pe sofit+dagesh */
+ {0x5e4, 0x5bc,0}, /* 0xfb44 pe+dagesh */
+ {0xfb45, 0, 0}, /* 0xfb45 -- UNUSED */
+ {0x5e6, 0x5bc, 0}, /* 0xfb46 tsadi+dagesh */
+ {0x5e7, 0x5bc, 0}, /* 0xfb47 qof+dagesh */
+ {0x5e8, 0x5bc, 0}, /* 0xfb48 resh+dagesh */
+ {0x5e9, 0x5bc, 0}, /* 0xfb49 shin+dagesh */
+ {0x5ea, 0x5bc, 0}, /* 0xfb4a tav+dagesh */
+ {0x5d5, 0x5b9, 0}, /* 0xfb4b vav+holam */
+ {0x5d1, 0x5bf, 0}, /* 0xfb4c bet+rafe */
+ {0x5db, 0x5bf, 0}, /* 0xfb4d kaf+rafe */
+ {0x5e4, 0x5bf, 0}, /* 0xfb4e pe+rafe */
+ {0x5d0, 0x5dc, 0} /* 0xfb4f alef-lamed */
+};
+
+ static void
+mb_decompose(int c, int *c1, int *c2, int *c3)
+{
+ decomp_T d;
+
+ if (c >= 0xfb20 && c <= 0xfb4f)
+ {
+ d = decomp_table[c - 0xfb20];
+ *c1 = d.a;
+ *c2 = d.b;
+ *c3 = d.c;
+ }
+ else
+ {
+ *c1 = c;
+ *c2 = *c3 = 0;
+ }
+}
+
+/*
+ * Compare two strings, ignore case if rex.reg_ic set.
+ * Return 0 if strings match, non-zero otherwise.
+ * Correct the length "*n" when composing characters are ignored.
+ */
+ static int
+cstrncmp(char_u *s1, char_u *s2, int *n)
+{
+ int result;
+
+ if (!rex.reg_ic)
+ result = STRNCMP(s1, s2, *n);
+ else
+ result = MB_STRNICMP(s1, s2, *n);
+
+ /* if it failed and it's utf8 and we want to combineignore: */
+ if (result != 0 && enc_utf8 && rex.reg_icombine)
+ {
+ char_u *str1, *str2;
+ int c1, c2, c11, c12;
+ int junk;
+
+ /* we have to handle the strcmp ourselves, since it is necessary to
+ * deal with the composing characters by ignoring them: */
+ str1 = s1;
+ str2 = s2;
+ c1 = c2 = 0;
+ while ((int)(str1 - s1) < *n)
+ {
+ c1 = mb_ptr2char_adv(&str1);
+ c2 = mb_ptr2char_adv(&str2);
+
+ /* decompose the character if necessary, into 'base' characters
+ * because I don't care about Arabic, I will hard-code the Hebrew
+ * which I *do* care about! So sue me... */
+ if (c1 != c2 && (!rex.reg_ic || utf_fold(c1) != utf_fold(c2)))
+ {
+ /* decomposition necessary? */
+ mb_decompose(c1, &c11, &junk, &junk);
+ mb_decompose(c2, &c12, &junk, &junk);
+ c1 = c11;
+ c2 = c12;
+ if (c11 != c12
+ && (!rex.reg_ic || utf_fold(c11) != utf_fold(c12)))
+ break;
+ }
+ }
+ result = c2 - c1;
+ if (result == 0)
+ *n = (int)(str2 - s2);
+ }
+
+ return result;
+}
+
+/*
+ * cstrchr: This function is used a lot for simple searches, keep it fast!
+ */
+ static char_u *
+cstrchr(char_u *s, int c)
+{
+ char_u *p;
+ int cc;
+
+ if (!rex.reg_ic || (!enc_utf8 && mb_char2len(c) > 1))
+ return vim_strchr(s, c);
+
+ /* tolower() and toupper() can be slow, comparing twice should be a lot
+ * faster (esp. when using MS Visual C++!).
+ * For UTF-8 need to use folded case. */
+ if (enc_utf8 && c > 0x80)
+ cc = utf_fold(c);
+ else
+ if (MB_ISUPPER(c))
+ cc = MB_TOLOWER(c);
+ else if (MB_ISLOWER(c))
+ cc = MB_TOUPPER(c);
+ else
+ return vim_strchr(s, c);
+
+ if (has_mbyte)
+ {
+ for (p = s; *p != NUL; p += (*mb_ptr2len)(p))
+ {
+ if (enc_utf8 && c > 0x80)
+ {
+ if (utf_fold(utf_ptr2char(p)) == cc)
+ return p;
+ }
+ else if (*p == c || *p == cc)
+ return p;
+ }
+ }
+ else
+ /* Faster version for when there are no multi-byte characters. */
+ for (p = s; *p != NUL; ++p)
+ if (*p == c || *p == cc)
+ return p;
+
+ return NULL;
+}
+
+/***************************************************************
+ * regsub stuff *
+ ***************************************************************/
+
+/*
+ * We should define ftpr as a pointer to a function returning a pointer to
+ * a function returning a pointer to a function ...
+ * This is impossible, so we declare a pointer to a function returning a
+ * pointer to a function returning void. This should work for all compilers.
+ */
+typedef void (*(*fptr_T)(int *, int))();
+
+static int vim_regsub_both(char_u *source, typval_T *expr, char_u *dest, int copy, int magic, int backslash);
+
+ static fptr_T
+do_upper(int *d, int c)
+{
+ *d = MB_TOUPPER(c);
+
+ return (fptr_T)NULL;
+}
+
+ static fptr_T
+do_Upper(int *d, int c)
+{
+ *d = MB_TOUPPER(c);
+
+ return (fptr_T)do_Upper;
+}
+
+ static fptr_T
+do_lower(int *d, int c)
+{
+ *d = MB_TOLOWER(c);
+
+ return (fptr_T)NULL;
+}
+
+ static fptr_T
+do_Lower(int *d, int c)
+{
+ *d = MB_TOLOWER(c);
+
+ return (fptr_T)do_Lower;
+}
+
+/*
+ * regtilde(): Replace tildes in the pattern by the old pattern.
+ *
+ * Short explanation of the tilde: It stands for the previous replacement
+ * pattern. If that previous pattern also contains a ~ we should go back a
+ * step further... But we insert the previous pattern into the current one
+ * and remember that.
+ * This still does not handle the case where "magic" changes. So require the
+ * user to keep his hands off of "magic".
+ *
+ * The tildes are parsed once before the first call to vim_regsub().
+ */
+ char_u *
+regtilde(char_u *source, int magic)
+{
+ char_u *newsub = source;
+ char_u *tmpsub;
+ char_u *p;
+ int len;
+ int prevlen;
+
+ for (p = newsub; *p; ++p)
+ {
+ if ((*p == '~' && magic) || (*p == '\\' && *(p + 1) == '~' && !magic))
+ {
+ if (reg_prev_sub != NULL)
+ {
+ /* length = len(newsub) - 1 + len(prev_sub) + 1 */
+ prevlen = (int)STRLEN(reg_prev_sub);
+ tmpsub = alloc((unsigned)(STRLEN(newsub) + prevlen));
+ if (tmpsub != NULL)
+ {
+ /* copy prefix */
+ len = (int)(p - newsub); /* not including ~ */
+ mch_memmove(tmpsub, newsub, (size_t)len);
+ /* interpret tilde */
+ mch_memmove(tmpsub + len, reg_prev_sub, (size_t)prevlen);
+ /* copy postfix */
+ if (!magic)
+ ++p; /* back off \ */
+ STRCPY(tmpsub + len + prevlen, p + 1);
+
+ if (newsub != source) /* already allocated newsub */
+ vim_free(newsub);
+ newsub = tmpsub;
+ p = newsub + len + prevlen;
+ }
+ }
+ else if (magic)
+ STRMOVE(p, p + 1); /* remove '~' */
+ else
+ STRMOVE(p, p + 2); /* remove '\~' */
+ --p;
+ }
+ else
+ {
+ if (*p == '\\' && p[1]) /* skip escaped characters */
+ ++p;
+ if (has_mbyte)
+ p += (*mb_ptr2len)(p) - 1;
+ }
+ }
+
+ vim_free(reg_prev_sub);
+ if (newsub != source) /* newsub was allocated, just keep it */
+ reg_prev_sub = newsub;
+ else /* no ~ found, need to save newsub */
+ reg_prev_sub = vim_strsave(newsub);
+ return newsub;
+}
+
+#ifdef FEAT_EVAL
+static int can_f_submatch = FALSE; /* TRUE when submatch() can be used */
+
+/* These pointers are used for reg_submatch(). Needed for when the
+ * substitution string is an expression that contains a call to substitute()
+ * and submatch(). */
+typedef struct {
+ regmatch_T *sm_match;
+ regmmatch_T *sm_mmatch;
+ linenr_T sm_firstlnum;
+ linenr_T sm_maxline;
+ int sm_line_lbr;
+} regsubmatch_T;
+
+static regsubmatch_T rsm; /* can only be used when can_f_submatch is TRUE */
+#endif
+
+#if defined(FEAT_MODIFY_FNAME) || defined(FEAT_EVAL) || defined(PROTO)
+
+/*
+ * Put the submatches in "argv[0]" which is a list passed into call_func() by
+ * vim_regsub_both().
+ */
+ static int
+fill_submatch_list(int argc UNUSED, typval_T *argv, int argcount)
+{
+ listitem_T *li;
+ int i;
+ char_u *s;
+
+ if (argcount == 0)
+ /* called function doesn't take an argument */
+ return 0;
+
+ /* Relies on sl_list to be the first item in staticList10_T. */
+ init_static_list((staticList10_T *)(argv->vval.v_list));
+
+ /* There are always 10 list items in staticList10_T. */
+ li = argv->vval.v_list->lv_first;
+ for (i = 0; i < 10; ++i)
+ {
+ s = rsm.sm_match->startp[i];
+ if (s == NULL || rsm.sm_match->endp[i] == NULL)
+ s = NULL;
+ else
+ s = vim_strnsave(s, (int)(rsm.sm_match->endp[i] - s));
+ li->li_tv.v_type = VAR_STRING;
+ li->li_tv.vval.v_string = s;
+ li = li->li_next;
+ }
+ return 1;
+}
+
+ static void
+clear_submatch_list(staticList10_T *sl)
+{
+ int i;
+
+ for (i = 0; i < 10; ++i)
+ vim_free(sl->sl_items[i].li_tv.vval.v_string);
+}
+
+/*
+ * vim_regsub() - perform substitutions after a vim_regexec() or
+ * vim_regexec_multi() match.
+ *
+ * If "copy" is TRUE really copy into "dest".
+ * If "copy" is FALSE nothing is copied, this is just to find out the length
+ * of the result.
+ *
+ * If "backslash" is TRUE, a backslash will be removed later, need to double
+ * them to keep them, and insert a backslash before a CR to avoid it being
+ * replaced with a line break later.
+ *
+ * Note: The matched text must not change between the call of
+ * vim_regexec()/vim_regexec_multi() and vim_regsub()! It would make the back
+ * references invalid!
+ *
+ * Returns the size of the replacement, including terminating NUL.
+ */
+ int
+vim_regsub(
+ regmatch_T *rmp,
+ char_u *source,
+ typval_T *expr,
+ char_u *dest,
+ int copy,
+ int magic,
+ int backslash)
+{
+ int result;
+ regexec_T rex_save;
+ int rex_in_use_save = rex_in_use;
+
+ if (rex_in_use)
+ /* Being called recursively, save the state. */
+ rex_save = rex;
+ rex_in_use = TRUE;
+
+ rex.reg_match = rmp;
+ rex.reg_mmatch = NULL;
+ rex.reg_maxline = 0;
+ rex.reg_buf = curbuf;
+ rex.reg_line_lbr = TRUE;
+ result = vim_regsub_both(source, expr, dest, copy, magic, backslash);
+
+ rex_in_use = rex_in_use_save;
+ if (rex_in_use)
+ rex = rex_save;
+
+ return result;
+}
+#endif
+
+ int
+vim_regsub_multi(
+ regmmatch_T *rmp,
+ linenr_T lnum,
+ char_u *source,
+ char_u *dest,
+ int copy,
+ int magic,
+ int backslash)
+{
+ int result;
+ regexec_T rex_save;
+ int rex_in_use_save = rex_in_use;
+
+ if (rex_in_use)
+ /* Being called recursively, save the state. */
+ rex_save = rex;
+ rex_in_use = TRUE;
+
+ rex.reg_match = NULL;
+ rex.reg_mmatch = rmp;
+ rex.reg_buf = curbuf; /* always works on the current buffer! */
+ rex.reg_firstlnum = lnum;
+ rex.reg_maxline = curbuf->b_ml.ml_line_count - lnum;
+ rex.reg_line_lbr = FALSE;
+ result = vim_regsub_both(source, NULL, dest, copy, magic, backslash);
+
+ rex_in_use = rex_in_use_save;
+ if (rex_in_use)
+ rex = rex_save;
+
+ return result;
+}
+
+ static int
+vim_regsub_both(
+ char_u *source,
+ typval_T *expr,
+ char_u *dest,
+ int copy,
+ int magic,
+ int backslash)
+{
+ char_u *src;
+ char_u *dst;
+ char_u *s;
+ int c;
+ int cc;
+ int no = -1;
+ fptr_T func_all = (fptr_T)NULL;
+ fptr_T func_one = (fptr_T)NULL;
+ linenr_T clnum = 0; /* init for GCC */
+ int len = 0; /* init for GCC */
+#ifdef FEAT_EVAL
+ static char_u *eval_result = NULL;
+#endif
+
+ /* Be paranoid... */
+ if ((source == NULL && expr == NULL) || dest == NULL)
+ {
+ emsg(_(e_null));
+ return 0;
+ }
+ if (prog_magic_wrong())
+ return 0;
+ src = source;
+ dst = dest;
+
+ /*
+ * When the substitute part starts with "\=" evaluate it as an expression.
+ */
+ if (expr != NULL || (source[0] == '\\' && source[1] == '='))
+ {
+#ifdef FEAT_EVAL
+ /* To make sure that the length doesn't change between checking the
+ * length and copying the string, and to speed up things, the
+ * resulting string is saved from the call with "copy" == FALSE to the
+ * call with "copy" == TRUE. */
+ if (copy)
+ {
+ if (eval_result != NULL)
+ {
+ STRCPY(dest, eval_result);
+ dst += STRLEN(eval_result);
+ VIM_CLEAR(eval_result);
+ }
+ }
+ else
+ {
+ int prev_can_f_submatch = can_f_submatch;
+ regsubmatch_T rsm_save;
+
+ vim_free(eval_result);
+
+ /* The expression may contain substitute(), which calls us
+ * recursively. Make sure submatch() gets the text from the first
+ * level. */
+ if (can_f_submatch)
+ rsm_save = rsm;
+ can_f_submatch = TRUE;
+ rsm.sm_match = rex.reg_match;
+ rsm.sm_mmatch = rex.reg_mmatch;
+ rsm.sm_firstlnum = rex.reg_firstlnum;
+ rsm.sm_maxline = rex.reg_maxline;
+ rsm.sm_line_lbr = rex.reg_line_lbr;
+
+ if (expr != NULL)
+ {
+ typval_T argv[2];
+ int dummy;
+ char_u buf[NUMBUFLEN];
+ typval_T rettv;
+ staticList10_T matchList;
+
+ rettv.v_type = VAR_STRING;
+ rettv.vval.v_string = NULL;
+ argv[0].v_type = VAR_LIST;
+ argv[0].vval.v_list = &matchList.sl_list;
+ matchList.sl_list.lv_len = 0;
+ if (expr->v_type == VAR_FUNC)
+ {
+ s = expr->vval.v_string;
+ call_func(s, (int)STRLEN(s), &rettv,
+ 1, argv, fill_submatch_list,
+ 0L, 0L, &dummy, TRUE, NULL, NULL);
+ }
+ else if (expr->v_type == VAR_PARTIAL)
+ {
+ partial_T *partial = expr->vval.v_partial;
+
+ s = partial_name(partial);
+ call_func(s, (int)STRLEN(s), &rettv,
+ 1, argv, fill_submatch_list,
+ 0L, 0L, &dummy, TRUE, partial, NULL);
+ }
+ if (matchList.sl_list.lv_len > 0)
+ /* fill_submatch_list() was called */
+ clear_submatch_list(&matchList);
+
+ eval_result = tv_get_string_buf_chk(&rettv, buf);
+ if (eval_result != NULL)
+ eval_result = vim_strsave(eval_result);
+ clear_tv(&rettv);
+ }
+ else
+ eval_result = eval_to_string(source + 2, NULL, TRUE);
+
+ if (eval_result != NULL)
+ {
+ int had_backslash = FALSE;
+
+ for (s = eval_result; *s != NUL; MB_PTR_ADV(s))
+ {
+ /* Change NL to CR, so that it becomes a line break,
+ * unless called from vim_regexec_nl().
+ * Skip over a backslashed character. */
+ if (*s == NL && !rsm.sm_line_lbr)
+ *s = CAR;
+ else if (*s == '\\' && s[1] != NUL)
+ {
+ ++s;
+ /* Change NL to CR here too, so that this works:
+ * :s/abc\\\ndef/\="aaa\\\nbbb"/ on text:
+ * abc\
+ * def
+ * Not when called from vim_regexec_nl().
+ */
+ if (*s == NL && !rsm.sm_line_lbr)
+ *s = CAR;
+ had_backslash = TRUE;
+ }
+ }
+ if (had_backslash && backslash)
+ {
+ /* Backslashes will be consumed, need to double them. */
+ s = vim_strsave_escaped(eval_result, (char_u *)"\\");
+ if (s != NULL)
+ {
+ vim_free(eval_result);
+ eval_result = s;
+ }
+ }
+
+ dst += STRLEN(eval_result);
+ }
+
+ can_f_submatch = prev_can_f_submatch;
+ if (can_f_submatch)
+ rsm = rsm_save;
+ }
+#endif
+ }
+ else
+ while ((c = *src++) != NUL)
+ {
+ if (c == '&' && magic)
+ no = 0;
+ else if (c == '\\' && *src != NUL)
+ {
+ if (*src == '&' && !magic)
+ {
+ ++src;
+ no = 0;
+ }
+ else if ('0' <= *src && *src <= '9')
+ {
+ no = *src++ - '0';
+ }
+ else if (vim_strchr((char_u *)"uUlLeE", *src))
+ {
+ switch (*src++)
+ {
+ case 'u': func_one = (fptr_T)do_upper;
+ continue;
+ case 'U': func_all = (fptr_T)do_Upper;
+ continue;
+ case 'l': func_one = (fptr_T)do_lower;
+ continue;
+ case 'L': func_all = (fptr_T)do_Lower;
+ continue;
+ case 'e':
+ case 'E': func_one = func_all = (fptr_T)NULL;
+ continue;
+ }
+ }
+ }
+ if (no < 0) /* Ordinary character. */
+ {
+ if (c == K_SPECIAL && src[0] != NUL && src[1] != NUL)
+ {
+ /* Copy a special key as-is. */
+ if (copy)
+ {
+ *dst++ = c;
+ *dst++ = *src++;
+ *dst++ = *src++;
+ }
+ else
+ {
+ dst += 3;
+ src += 2;
+ }
+ continue;
+ }
+
+ if (c == '\\' && *src != NUL)
+ {
+ /* Check for abbreviations -- webb */
+ switch (*src)
+ {
+ case 'r': c = CAR; ++src; break;
+ case 'n': c = NL; ++src; break;
+ case 't': c = TAB; ++src; break;
+ /* Oh no! \e already has meaning in subst pat :-( */
+ /* case 'e': c = ESC; ++src; break; */
+ case 'b': c = Ctrl_H; ++src; break;
+
+ /* If "backslash" is TRUE the backslash will be removed
+ * later. Used to insert a literal CR. */
+ default: if (backslash)
+ {
+ if (copy)
+ *dst = '\\';
+ ++dst;
+ }
+ c = *src++;
+ }
+ }
+ else if (has_mbyte)
+ c = mb_ptr2char(src - 1);
+
+ /* Write to buffer, if copy is set. */
+ if (func_one != (fptr_T)NULL)
+ /* Turbo C complains without the typecast */
+ func_one = (fptr_T)(func_one(&cc, c));
+ else if (func_all != (fptr_T)NULL)
+ /* Turbo C complains without the typecast */
+ func_all = (fptr_T)(func_all(&cc, c));
+ else /* just copy */
+ cc = c;
+
+ if (has_mbyte)
+ {
+ int totlen = mb_ptr2len(src - 1);
+
+ if (copy)
+ mb_char2bytes(cc, dst);
+ dst += mb_char2len(cc) - 1;
+ if (enc_utf8)
+ {
+ int clen = utf_ptr2len(src - 1);
+
+ /* If the character length is shorter than "totlen", there
+ * are composing characters; copy them as-is. */
+ if (clen < totlen)
+ {
+ if (copy)
+ mch_memmove(dst + 1, src - 1 + clen,
+ (size_t)(totlen - clen));
+ dst += totlen - clen;
+ }
+ }
+ src += totlen - 1;
+ }
+ else if (copy)
+ *dst = cc;
+ dst++;
+ }
+ else
+ {
+ if (REG_MULTI)
+ {
+ clnum = rex.reg_mmatch->startpos[no].lnum;
+ if (clnum < 0 || rex.reg_mmatch->endpos[no].lnum < 0)
+ s = NULL;
+ else
+ {
+ s = reg_getline(clnum) + rex.reg_mmatch->startpos[no].col;
+ if (rex.reg_mmatch->endpos[no].lnum == clnum)
+ len = rex.reg_mmatch->endpos[no].col
+ - rex.reg_mmatch->startpos[no].col;
+ else
+ len = (int)STRLEN(s);
+ }
+ }
+ else
+ {
+ s = rex.reg_match->startp[no];
+ if (rex.reg_match->endp[no] == NULL)
+ s = NULL;
+ else
+ len = (int)(rex.reg_match->endp[no] - s);
+ }
+ if (s != NULL)
+ {
+ for (;;)
+ {
+ if (len == 0)
+ {
+ if (REG_MULTI)
+ {
+ if (rex.reg_mmatch->endpos[no].lnum == clnum)
+ break;
+ if (copy)
+ *dst = CAR;
+ ++dst;
+ s = reg_getline(++clnum);
+ if (rex.reg_mmatch->endpos[no].lnum == clnum)
+ len = rex.reg_mmatch->endpos[no].col;
+ else
+ len = (int)STRLEN(s);
+ }
+ else
+ break;
+ }
+ else if (*s == NUL) /* we hit NUL. */
+ {
+ if (copy)
+ emsg(_(e_re_damg));
+ goto exit;
+ }
+ else
+ {
+ if (backslash && (*s == CAR || *s == '\\'))
+ {
+ /*
+ * Insert a backslash in front of a CR, otherwise
+ * it will be replaced by a line break.
+ * Number of backslashes will be halved later,
+ * double them here.
+ */
+ if (copy)
+ {
+ dst[0] = '\\';
+ dst[1] = *s;
+ }
+ dst += 2;
+ }
+ else
+ {
+ if (has_mbyte)
+ c = mb_ptr2char(s);
+ else
+ c = *s;
+
+ if (func_one != (fptr_T)NULL)
+ /* Turbo C complains without the typecast */
+ func_one = (fptr_T)(func_one(&cc, c));
+ else if (func_all != (fptr_T)NULL)
+ /* Turbo C complains without the typecast */
+ func_all = (fptr_T)(func_all(&cc, c));
+ else /* just copy */
+ cc = c;
+
+ if (has_mbyte)
+ {
+ int l;
+
+ /* Copy composing characters separately, one
+ * at a time. */
+ if (enc_utf8)
+ l = utf_ptr2len(s) - 1;
+ else
+ l = mb_ptr2len(s) - 1;
+
+ s += l;
+ len -= l;
+ if (copy)
+ mb_char2bytes(cc, dst);
+ dst += mb_char2len(cc) - 1;
+ }
+ else if (copy)
+ *dst = cc;
+ dst++;
+ }
+
+ ++s;
+ --len;
+ }
+ }
+ }
+ no = -1;
+ }
+ }
+ if (copy)
+ *dst = NUL;
+
+exit:
+ return (int)((dst - dest) + 1);
+}
+
+#ifdef FEAT_EVAL
+/*
+ * Call reg_getline() with the line numbers from the submatch. If a
+ * substitute() was used the reg_maxline and other values have been
+ * overwritten.
+ */
+ static char_u *
+reg_getline_submatch(linenr_T lnum)
+{
+ char_u *s;
+ linenr_T save_first = rex.reg_firstlnum;
+ linenr_T save_max = rex.reg_maxline;
+
+ rex.reg_firstlnum = rsm.sm_firstlnum;
+ rex.reg_maxline = rsm.sm_maxline;
+
+ s = reg_getline(lnum);
+
+ rex.reg_firstlnum = save_first;
+ rex.reg_maxline = save_max;
+ return s;
+}
+
+/*
+ * Used for the submatch() function: get the string from the n'th submatch in
+ * allocated memory.
+ * Returns NULL when not in a ":s" command and for a non-existing submatch.
+ */
+ char_u *
+reg_submatch(int no)
+{
+ char_u *retval = NULL;
+ char_u *s;
+ int len;
+ int round;
+ linenr_T lnum;
+
+ if (!can_f_submatch || no < 0)
+ return NULL;
+
+ if (rsm.sm_match == NULL)
+ {
+ /*
+ * First round: compute the length and allocate memory.
+ * Second round: copy the text.
+ */
+ for (round = 1; round <= 2; ++round)
+ {
+ lnum = rsm.sm_mmatch->startpos[no].lnum;
+ if (lnum < 0 || rsm.sm_mmatch->endpos[no].lnum < 0)
+ return NULL;
+
+ s = reg_getline_submatch(lnum) + rsm.sm_mmatch->startpos[no].col;
+ if (s == NULL) /* anti-crash check, cannot happen? */
+ break;
+ if (rsm.sm_mmatch->endpos[no].lnum == lnum)
+ {
+ /* Within one line: take form start to end col. */
+ len = rsm.sm_mmatch->endpos[no].col
+ - rsm.sm_mmatch->startpos[no].col;
+ if (round == 2)
+ vim_strncpy(retval, s, len);
+ ++len;
+ }
+ else
+ {
+ /* Multiple lines: take start line from start col, middle
+ * lines completely and end line up to end col. */
+ len = (int)STRLEN(s);
+ if (round == 2)
+ {
+ STRCPY(retval, s);
+ retval[len] = '\n';
+ }
+ ++len;
+ ++lnum;
+ while (lnum < rsm.sm_mmatch->endpos[no].lnum)
+ {
+ s = reg_getline_submatch(lnum++);
+ if (round == 2)
+ STRCPY(retval + len, s);
+ len += (int)STRLEN(s);
+ if (round == 2)
+ retval[len] = '\n';
+ ++len;
+ }
+ if (round == 2)
+ STRNCPY(retval + len, reg_getline_submatch(lnum),
+ rsm.sm_mmatch->endpos[no].col);
+ len += rsm.sm_mmatch->endpos[no].col;
+ if (round == 2)
+ retval[len] = NUL;
+ ++len;
+ }
+
+ if (retval == NULL)
+ {
+ retval = lalloc((long_u)len, TRUE);
+ if (retval == NULL)
+ return NULL;
+ }
+ }
+ }
+ else
+ {
+ s = rsm.sm_match->startp[no];
+ if (s == NULL || rsm.sm_match->endp[no] == NULL)
+ retval = NULL;
+ else
+ retval = vim_strnsave(s, (int)(rsm.sm_match->endp[no] - s));
+ }
+
+ return retval;
+}
+
+/*
+ * Used for the submatch() function with the optional non-zero argument: get
+ * the list of strings from the n'th submatch in allocated memory with NULs
+ * represented in NLs.
+ * Returns a list of allocated strings. Returns NULL when not in a ":s"
+ * command, for a non-existing submatch and for any error.
+ */
+ list_T *
+reg_submatch_list(int no)
+{
+ char_u *s;
+ linenr_T slnum;
+ linenr_T elnum;
+ colnr_T scol;
+ colnr_T ecol;
+ int i;
+ list_T *list;
+ int error = FALSE;
+
+ if (!can_f_submatch || no < 0)
+ return NULL;
+
+ if (rsm.sm_match == NULL)
+ {
+ slnum = rsm.sm_mmatch->startpos[no].lnum;
+ elnum = rsm.sm_mmatch->endpos[no].lnum;
+ if (slnum < 0 || elnum < 0)
+ return NULL;
+
+ scol = rsm.sm_mmatch->startpos[no].col;
+ ecol = rsm.sm_mmatch->endpos[no].col;
+
+ list = list_alloc();
+ if (list == NULL)
+ return NULL;
+
+ s = reg_getline_submatch(slnum) + scol;
+ if (slnum == elnum)
+ {
+ if (list_append_string(list, s, ecol - scol) == FAIL)
+ error = TRUE;
+ }
+ else
+ {
+ if (list_append_string(list, s, -1) == FAIL)
+ error = TRUE;
+ for (i = 1; i < elnum - slnum; i++)
+ {
+ s = reg_getline_submatch(slnum + i);
+ if (list_append_string(list, s, -1) == FAIL)
+ error = TRUE;
+ }
+ s = reg_getline_submatch(elnum);
+ if (list_append_string(list, s, ecol) == FAIL)
+ error = TRUE;
+ }
+ }
+ else
+ {
+ s = rsm.sm_match->startp[no];
+ if (s == NULL || rsm.sm_match->endp[no] == NULL)
+ return NULL;
+ list = list_alloc();
+ if (list == NULL)
+ return NULL;
+ if (list_append_string(list, s,
+ (int)(rsm.sm_match->endp[no] - s)) == FAIL)
+ error = TRUE;
+ }
+
+ if (error)
+ {
+ list_free(list);
+ return NULL;
+ }
+ return list;
+}
+#endif
+
+static regengine_T bt_regengine =
+{
+ bt_regcomp,
+ bt_regfree,
+ bt_regexec_nl,
+ bt_regexec_multi,
+ (char_u *)""
+};
+
+#include "regexp_nfa.c"
+
+static regengine_T nfa_regengine =
+{
+ nfa_regcomp,
+ nfa_regfree,
+ nfa_regexec_nl,
+ nfa_regexec_multi,
+ (char_u *)""
+};
+
+/* Which regexp engine to use? Needed for vim_regcomp().
+ * Must match with 'regexpengine'. */
+static int regexp_engine = 0;
+
+#ifdef DEBUG
+static char_u regname[][30] = {
+ "AUTOMATIC Regexp Engine",
+ "BACKTRACKING Regexp Engine",
+ "NFA Regexp Engine"
+ };
+#endif
+
+/*
+ * Compile a regular expression into internal code.
+ * Returns the program in allocated memory.
+ * Use vim_regfree() to free the memory.
+ * Returns NULL for an error.
+ */
+ regprog_T *
+vim_regcomp(char_u *expr_arg, int re_flags)
+{
+ regprog_T *prog = NULL;
+ char_u *expr = expr_arg;
+
+ regexp_engine = p_re;
+
+ /* Check for prefix "\%#=", that sets the regexp engine */
+ if (STRNCMP(expr, "\\%#=", 4) == 0)
+ {
+ int newengine = expr[4] - '0';
+
+ if (newengine == AUTOMATIC_ENGINE
+ || newengine == BACKTRACKING_ENGINE
+ || newengine == NFA_ENGINE)
+ {
+ regexp_engine = expr[4] - '0';
+ expr += 5;
+#ifdef DEBUG
+ smsg("New regexp mode selected (%d): %s",
+ regexp_engine, regname[newengine]);
+#endif
+ }
+ else
+ {
+ emsg(_("E864: \\%#= can only be followed by 0, 1, or 2. The automatic engine will be used "));
+ regexp_engine = AUTOMATIC_ENGINE;
+ }
+ }
+#ifdef DEBUG
+ bt_regengine.expr = expr;
+ nfa_regengine.expr = expr;
+#endif
+
+ /*
+ * First try the NFA engine, unless backtracking was requested.
+ */
+ if (regexp_engine != BACKTRACKING_ENGINE)
+ prog = nfa_regengine.regcomp(expr,
+ re_flags + (regexp_engine == AUTOMATIC_ENGINE ? RE_AUTO : 0));
+ else
+ prog = bt_regengine.regcomp(expr, re_flags);
+
+ /* Check for error compiling regexp with initial engine. */
+ if (prog == NULL)
+ {
+#ifdef BT_REGEXP_DEBUG_LOG
+ if (regexp_engine != BACKTRACKING_ENGINE) /* debugging log for NFA */
+ {
+ FILE *f;
+ f = fopen(BT_REGEXP_DEBUG_LOG_NAME, "a");
+ if (f)
+ {
+ fprintf(f, "Syntax error in \"%s\"\n", expr);
+ fclose(f);
+ }
+ else
+ semsg("(NFA) Could not open \"%s\" to write !!!",
+ BT_REGEXP_DEBUG_LOG_NAME);
+ }
+#endif
+ /*
+ * If the NFA engine failed, try the backtracking engine.
+ * The NFA engine also fails for patterns that it can't handle well
+ * but are still valid patterns, thus a retry should work.
+ */
+ if (regexp_engine == AUTOMATIC_ENGINE)
+ {
+ regexp_engine = BACKTRACKING_ENGINE;
+ prog = bt_regengine.regcomp(expr, re_flags);
+ }
+ }
+
+ if (prog != NULL)
+ {
+ /* Store the info needed to call regcomp() again when the engine turns
+ * out to be very slow when executing it. */
+ prog->re_engine = regexp_engine;
+ prog->re_flags = re_flags;
+ }
+
+ return prog;
+}
+
+/*
+ * Free a compiled regexp program, returned by vim_regcomp().
+ */
+ void
+vim_regfree(regprog_T *prog)
+{
+ if (prog != NULL)
+ prog->engine->regfree(prog);
+}
+
+#ifdef FEAT_EVAL
+ static void
+report_re_switch(char_u *pat)
+{
+ if (p_verbose > 0)
+ {
+ verbose_enter();
+ msg_puts(_("Switching to backtracking RE engine for pattern: "));
+ msg_puts((char *)pat);
+ verbose_leave();
+ }
+}
+#endif
+
+#if (defined(FEAT_X11) && (defined(FEAT_TITLE) || defined(FEAT_XCLIPBOARD))) \
+ || defined(PROTO)
+/*
+ * Return whether "prog" is currently being executed.
+ */
+ int
+regprog_in_use(regprog_T *prog)
+{
+ return prog->re_in_use;
+}
+#endif
+
+/*
+ * Match a regexp against a string.
+ * "rmp->regprog" is a compiled regexp as returned by vim_regcomp().
+ * Note: "rmp->regprog" may be freed and changed.
+ * Uses curbuf for line count and 'iskeyword'.
+ * When "nl" is TRUE consider a "\n" in "line" to be a line break.
+ *
+ * Return TRUE if there is a match, FALSE if not.
+ */
+ static int
+vim_regexec_string(
+ regmatch_T *rmp,
+ char_u *line, /* string to match against */
+ colnr_T col, /* column to start looking for match */
+ int nl)
+{
+ int result;
+ regexec_T rex_save;
+ int rex_in_use_save = rex_in_use;
+
+ // Cannot use the same prog recursively, it contains state.
+ if (rmp->regprog->re_in_use)
+ {
+ emsg(_(e_recursive));
+ return FALSE;
+ }
+ rmp->regprog->re_in_use = TRUE;
+
+ if (rex_in_use)
+ // Being called recursively, save the state.
+ rex_save = rex;
+ rex_in_use = TRUE;
+
+ rex.reg_startp = NULL;
+ rex.reg_endp = NULL;
+ rex.reg_startpos = NULL;
+ rex.reg_endpos = NULL;
+
+ result = rmp->regprog->engine->regexec_nl(rmp, line, col, nl);
+ rmp->regprog->re_in_use = FALSE;
+
+ /* NFA engine aborted because it's very slow. */
+ if (rmp->regprog->re_engine == AUTOMATIC_ENGINE
+ && result == NFA_TOO_EXPENSIVE)
+ {
+ int save_p_re = p_re;
+ int re_flags = rmp->regprog->re_flags;
+ char_u *pat = vim_strsave(((nfa_regprog_T *)rmp->regprog)->pattern);
+
+ p_re = BACKTRACKING_ENGINE;
+ vim_regfree(rmp->regprog);
+ if (pat != NULL)
+ {
+#ifdef FEAT_EVAL
+ report_re_switch(pat);
+#endif
+ rmp->regprog = vim_regcomp(pat, re_flags);
+ if (rmp->regprog != NULL)
+ {
+ rmp->regprog->re_in_use = TRUE;
+ result = rmp->regprog->engine->regexec_nl(rmp, line, col, nl);
+ rmp->regprog->re_in_use = FALSE;
+ }
+ vim_free(pat);
+ }
+
+ p_re = save_p_re;
+ }
+
+ rex_in_use = rex_in_use_save;
+ if (rex_in_use)
+ rex = rex_save;
+
+ return result > 0;
+}
+
+/*
+ * Note: "*prog" may be freed and changed.
+ * Return TRUE if there is a match, FALSE if not.
+ */
+ int
+vim_regexec_prog(
+ regprog_T **prog,
+ int ignore_case,
+ char_u *line,
+ colnr_T col)
+{
+ int r;
+ regmatch_T regmatch;
+
+ regmatch.regprog = *prog;
+ regmatch.rm_ic = ignore_case;
+ r = vim_regexec_string(&regmatch, line, col, FALSE);
+ *prog = regmatch.regprog;
+ return r;
+}
+
+/*
+ * Note: "rmp->regprog" may be freed and changed.
+ * Return TRUE if there is a match, FALSE if not.
+ */
+ int
+vim_regexec(regmatch_T *rmp, char_u *line, colnr_T col)
+{
+ return vim_regexec_string(rmp, line, col, FALSE);
+}
+
+#if defined(FEAT_MODIFY_FNAME) || defined(FEAT_EVAL) \
+ || defined(FIND_REPLACE_DIALOG) || defined(PROTO)
+/*
+ * Like vim_regexec(), but consider a "\n" in "line" to be a line break.
+ * Note: "rmp->regprog" may be freed and changed.
+ * Return TRUE if there is a match, FALSE if not.
+ */
+ int
+vim_regexec_nl(regmatch_T *rmp, char_u *line, colnr_T col)
+{
+ return vim_regexec_string(rmp, line, col, TRUE);
+}
+#endif
+
+/*
+ * Match a regexp against multiple lines.
+ * "rmp->regprog" must be a compiled regexp as returned by vim_regcomp().
+ * Note: "rmp->regprog" may be freed and changed, even set to NULL.
+ * Uses curbuf for line count and 'iskeyword'.
+ *
+ * Return zero if there is no match. Return number of lines contained in the
+ * match otherwise.
+ */
+ long
+vim_regexec_multi(
+ regmmatch_T *rmp,
+ win_T *win, /* window in which to search or NULL */
+ buf_T *buf, /* buffer in which to search */
+ linenr_T lnum, /* nr of line to start looking for match */
+ colnr_T col, /* column to start looking for match */
+ proftime_T *tm, /* timeout limit or NULL */
+ int *timed_out) /* flag is set when timeout limit reached */
+{
+ int result;
+ regexec_T rex_save;
+ int rex_in_use_save = rex_in_use;
+
+ // Cannot use the same prog recursively, it contains state.
+ if (rmp->regprog->re_in_use)
+ {
+ emsg(_(e_recursive));
+ return FALSE;
+ }
+ rmp->regprog->re_in_use = TRUE;
+
+ if (rex_in_use)
+ /* Being called recursively, save the state. */
+ rex_save = rex;
+ rex_in_use = TRUE;
+
+ result = rmp->regprog->engine->regexec_multi(
+ rmp, win, buf, lnum, col, tm, timed_out);
+ rmp->regprog->re_in_use = FALSE;
+
+ /* NFA engine aborted because it's very slow. */
+ if (rmp->regprog->re_engine == AUTOMATIC_ENGINE
+ && result == NFA_TOO_EXPENSIVE)
+ {
+ int save_p_re = p_re;
+ int re_flags = rmp->regprog->re_flags;
+ char_u *pat = vim_strsave(((nfa_regprog_T *)rmp->regprog)->pattern);
+
+ p_re = BACKTRACKING_ENGINE;
+ vim_regfree(rmp->regprog);
+ if (pat != NULL)
+ {
+#ifdef FEAT_EVAL
+ report_re_switch(pat);
+#endif
+#ifdef FEAT_SYN_HL
+ // checking for \z misuse was already done when compiling for NFA,
+ // allow all here
+ reg_do_extmatch = REX_ALL;
+#endif
+ rmp->regprog = vim_regcomp(pat, re_flags);
+#ifdef FEAT_SYN_HL
+ reg_do_extmatch = 0;
+#endif
+
+ if (rmp->regprog != NULL)
+ {
+ rmp->regprog->re_in_use = TRUE;
+ result = rmp->regprog->engine->regexec_multi(
+ rmp, win, buf, lnum, col, tm, timed_out);
+ rmp->regprog->re_in_use = FALSE;
+ }
+ vim_free(pat);
+ }
+ p_re = save_p_re;
+ }
+
+ rex_in_use = rex_in_use_save;
+ if (rex_in_use)
+ rex = rex_save;
+
+ return result <= 0 ? 0 : result;
+}
diff --git a/src/regexp.h b/src/regexp.h
new file mode 100644
index 0000000..fa3ff42
--- /dev/null
+++ b/src/regexp.h
@@ -0,0 +1,176 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE
+ *
+ * This is NOT the original regular expression code as written by Henry
+ * Spencer. This code has been modified specifically for use with Vim, and
+ * should not be used apart from compiling Vim. If you want a good regular
+ * expression library, get the original code.
+ *
+ * NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE
+ */
+
+#ifndef _REGEXP_H
+#define _REGEXP_H
+
+/*
+ * The number of sub-matches is limited to 10.
+ * The first one (index 0) is the whole match, referenced with "\0".
+ * The second one (index 1) is the first sub-match, referenced with "\1".
+ * This goes up to the tenth (index 9), referenced with "\9".
+ */
+#define NSUBEXP 10
+
+/*
+ * In the NFA engine: how many braces are allowed.
+ * TODO(RE): Use dynamic memory allocation instead of static, like here
+ */
+#define NFA_MAX_BRACES 20
+
+/*
+ * In the NFA engine: how many states are allowed
+ */
+#define NFA_MAX_STATES 100000
+#define NFA_TOO_EXPENSIVE -1
+
+/* Which regexp engine to use? Needed for vim_regcomp().
+ * Must match with 'regexpengine'. */
+#define AUTOMATIC_ENGINE 0
+#define BACKTRACKING_ENGINE 1
+#define NFA_ENGINE 2
+
+typedef struct regengine regengine_T;
+
+/*
+ * Structure returned by vim_regcomp() to pass on to vim_regexec().
+ * This is the general structure. For the actual matcher, two specific
+ * structures are used. See code below.
+ */
+typedef struct regprog
+{
+ regengine_T *engine;
+ unsigned regflags;
+ unsigned re_engine; // automatic, backtracking or nfa engine
+ unsigned re_flags; // second argument for vim_regcomp()
+ int re_in_use; // prog is being executed
+} regprog_T;
+
+/*
+ * Structure used by the back track matcher.
+ * These fields are only to be used in regexp.c!
+ * See regexp.c for an explanation.
+ */
+typedef struct
+{
+ /* These four members implement regprog_T */
+ regengine_T *engine;
+ unsigned regflags;
+ unsigned re_engine;
+ unsigned re_flags;
+ int re_in_use;
+
+ int regstart;
+ char_u reganch;
+ char_u *regmust;
+ int regmlen;
+#ifdef FEAT_SYN_HL
+ char_u reghasz;
+#endif
+ char_u program[1]; /* actually longer.. */
+} bt_regprog_T;
+
+/*
+ * Structure representing a NFA state.
+ * A NFA state may have no outgoing edge, when it is a NFA_MATCH state.
+ */
+typedef struct nfa_state nfa_state_T;
+struct nfa_state
+{
+ int c;
+ nfa_state_T *out;
+ nfa_state_T *out1;
+ int id;
+ int lastlist[2]; /* 0: normal, 1: recursive */
+ int val;
+};
+
+/*
+ * Structure used by the NFA matcher.
+ */
+typedef struct
+{
+ /* These three members implement regprog_T */
+ regengine_T *engine;
+ unsigned regflags;
+ unsigned re_engine;
+ unsigned re_flags;
+ int re_in_use;
+
+ nfa_state_T *start; /* points into state[] */
+
+ int reganch; /* pattern starts with ^ */
+ int regstart; /* char at start of pattern */
+ char_u *match_text; /* plain text to match with */
+
+ int has_zend; /* pattern contains \ze */
+ int has_backref; /* pattern contains \1 .. \9 */
+#ifdef FEAT_SYN_HL
+ int reghasz;
+#endif
+ char_u *pattern;
+ int nsubexp; /* number of () */
+ int nstate;
+ nfa_state_T state[1]; /* actually longer.. */
+} nfa_regprog_T;
+
+/*
+ * Structure to be used for single-line matching.
+ * Sub-match "no" starts at "startp[no]" and ends just before "endp[no]".
+ * When there is no match, the pointer is NULL.
+ */
+typedef struct
+{
+ regprog_T *regprog;
+ char_u *startp[NSUBEXP];
+ char_u *endp[NSUBEXP];
+ int rm_ic;
+} regmatch_T;
+
+/*
+ * Structure to be used for multi-line matching.
+ * Sub-match "no" starts in line "startpos[no].lnum" column "startpos[no].col"
+ * and ends in line "endpos[no].lnum" just before column "endpos[no].col".
+ * The line numbers are relative to the first line, thus startpos[0].lnum is
+ * always 0.
+ * When there is no match, the line number is -1.
+ */
+typedef struct
+{
+ regprog_T *regprog;
+ lpos_T startpos[NSUBEXP];
+ lpos_T endpos[NSUBEXP];
+ int rmm_ic;
+ colnr_T rmm_maxcol; /* when not zero: maximum column */
+} regmmatch_T;
+
+/*
+ * Structure used to store external references: "\z\(\)" to "\z\1".
+ * Use a reference count to avoid the need to copy this around. When it goes
+ * from 1 to zero the matches need to be freed.
+ */
+typedef struct
+{
+ short refcnt;
+ char_u *matches[NSUBEXP];
+} reg_extmatch_T;
+
+struct regengine
+{
+ regprog_T *(*regcomp)(char_u*, int);
+ void (*regfree)(regprog_T *);
+ int (*regexec_nl)(regmatch_T *, char_u *, colnr_T, int);
+ long (*regexec_multi)(regmmatch_T *, win_T *, buf_T *, linenr_T, colnr_T, proftime_T *, int *);
+ char_u *expr;
+};
+
+#endif /* _REGEXP_H */
diff --git a/src/regexp_nfa.c b/src/regexp_nfa.c
new file mode 100644
index 0000000..031a6cf
--- /dev/null
+++ b/src/regexp_nfa.c
@@ -0,0 +1,7362 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * NFA regular expression implementation.
+ *
+ * This file is included in "regexp.c".
+ */
+
+/*
+ * Logging of NFA engine.
+ *
+ * The NFA engine can write four log files:
+ * - Error log: Contains NFA engine's fatal errors.
+ * - Dump log: Contains compiled NFA state machine's information.
+ * - Run log: Contains information of matching procedure.
+ * - Debug log: Contains detailed information of matching procedure. Can be
+ * disabled by undefining NFA_REGEXP_DEBUG_LOG.
+ * The first one can also be used without debug mode.
+ * The last three are enabled when compiled as debug mode and individually
+ * disabled by commenting them out.
+ * The log files can get quite big!
+ * Do disable all of this when compiling Vim for debugging, undefine DEBUG in
+ * regexp.c
+ */
+#ifdef DEBUG
+# define NFA_REGEXP_ERROR_LOG "nfa_regexp_error.log"
+# define ENABLE_LOG
+# define NFA_REGEXP_DUMP_LOG "nfa_regexp_dump.log"
+# define NFA_REGEXP_RUN_LOG "nfa_regexp_run.log"
+# define NFA_REGEXP_DEBUG_LOG "nfa_regexp_debug.log"
+#endif
+
+/* Added to NFA_ANY - NFA_NUPPER_IC to include a NL. */
+#define NFA_ADD_NL 31
+
+enum
+{
+ NFA_SPLIT = -1024,
+ NFA_MATCH,
+ NFA_EMPTY, /* matches 0-length */
+
+ NFA_START_COLL, /* [abc] start */
+ NFA_END_COLL, /* [abc] end */
+ NFA_START_NEG_COLL, /* [^abc] start */
+ NFA_END_NEG_COLL, /* [^abc] end (postfix only) */
+ NFA_RANGE, /* range of the two previous items
+ * (postfix only) */
+ NFA_RANGE_MIN, /* low end of a range */
+ NFA_RANGE_MAX, /* high end of a range */
+
+ NFA_CONCAT, /* concatenate two previous items (postfix
+ * only) */
+ NFA_OR, /* \| (postfix only) */
+ NFA_STAR, /* greedy * (postfix only) */
+ NFA_STAR_NONGREEDY, /* non-greedy * (postfix only) */
+ NFA_QUEST, /* greedy \? (postfix only) */
+ NFA_QUEST_NONGREEDY, /* non-greedy \? (postfix only) */
+
+ NFA_BOL, /* ^ Begin line */
+ NFA_EOL, /* $ End line */
+ NFA_BOW, /* \< Begin word */
+ NFA_EOW, /* \> End word */
+ NFA_BOF, /* \%^ Begin file */
+ NFA_EOF, /* \%$ End file */
+ NFA_NEWL,
+ NFA_ZSTART, /* Used for \zs */
+ NFA_ZEND, /* Used for \ze */
+ NFA_NOPEN, /* Start of subexpression marked with \%( */
+ NFA_NCLOSE, /* End of subexpr. marked with \%( ... \) */
+ NFA_START_INVISIBLE,
+ NFA_START_INVISIBLE_FIRST,
+ NFA_START_INVISIBLE_NEG,
+ NFA_START_INVISIBLE_NEG_FIRST,
+ NFA_START_INVISIBLE_BEFORE,
+ NFA_START_INVISIBLE_BEFORE_FIRST,
+ NFA_START_INVISIBLE_BEFORE_NEG,
+ NFA_START_INVISIBLE_BEFORE_NEG_FIRST,
+ NFA_START_PATTERN,
+ NFA_END_INVISIBLE,
+ NFA_END_INVISIBLE_NEG,
+ NFA_END_PATTERN,
+ NFA_COMPOSING, /* Next nodes in NFA are part of the
+ composing multibyte char */
+ NFA_END_COMPOSING, /* End of a composing char in the NFA */
+ NFA_ANY_COMPOSING, /* \%C: Any composing characters. */
+ NFA_OPT_CHARS, /* \%[abc] */
+
+ /* The following are used only in the postfix form, not in the NFA */
+ NFA_PREV_ATOM_NO_WIDTH, /* Used for \@= */
+ NFA_PREV_ATOM_NO_WIDTH_NEG, /* Used for \@! */
+ NFA_PREV_ATOM_JUST_BEFORE, /* Used for \@<= */
+ NFA_PREV_ATOM_JUST_BEFORE_NEG, /* Used for \@<! */
+ NFA_PREV_ATOM_LIKE_PATTERN, /* Used for \@> */
+
+ NFA_BACKREF1, /* \1 */
+ NFA_BACKREF2, /* \2 */
+ NFA_BACKREF3, /* \3 */
+ NFA_BACKREF4, /* \4 */
+ NFA_BACKREF5, /* \5 */
+ NFA_BACKREF6, /* \6 */
+ NFA_BACKREF7, /* \7 */
+ NFA_BACKREF8, /* \8 */
+ NFA_BACKREF9, /* \9 */
+#ifdef FEAT_SYN_HL
+ NFA_ZREF1, /* \z1 */
+ NFA_ZREF2, /* \z2 */
+ NFA_ZREF3, /* \z3 */
+ NFA_ZREF4, /* \z4 */
+ NFA_ZREF5, /* \z5 */
+ NFA_ZREF6, /* \z6 */
+ NFA_ZREF7, /* \z7 */
+ NFA_ZREF8, /* \z8 */
+ NFA_ZREF9, /* \z9 */
+#endif
+ NFA_SKIP, /* Skip characters */
+
+ NFA_MOPEN,
+ NFA_MOPEN1,
+ NFA_MOPEN2,
+ NFA_MOPEN3,
+ NFA_MOPEN4,
+ NFA_MOPEN5,
+ NFA_MOPEN6,
+ NFA_MOPEN7,
+ NFA_MOPEN8,
+ NFA_MOPEN9,
+
+ NFA_MCLOSE,
+ NFA_MCLOSE1,
+ NFA_MCLOSE2,
+ NFA_MCLOSE3,
+ NFA_MCLOSE4,
+ NFA_MCLOSE5,
+ NFA_MCLOSE6,
+ NFA_MCLOSE7,
+ NFA_MCLOSE8,
+ NFA_MCLOSE9,
+
+#ifdef FEAT_SYN_HL
+ NFA_ZOPEN,
+ NFA_ZOPEN1,
+ NFA_ZOPEN2,
+ NFA_ZOPEN3,
+ NFA_ZOPEN4,
+ NFA_ZOPEN5,
+ NFA_ZOPEN6,
+ NFA_ZOPEN7,
+ NFA_ZOPEN8,
+ NFA_ZOPEN9,
+
+ NFA_ZCLOSE,
+ NFA_ZCLOSE1,
+ NFA_ZCLOSE2,
+ NFA_ZCLOSE3,
+ NFA_ZCLOSE4,
+ NFA_ZCLOSE5,
+ NFA_ZCLOSE6,
+ NFA_ZCLOSE7,
+ NFA_ZCLOSE8,
+ NFA_ZCLOSE9,
+#endif
+
+ /* NFA_FIRST_NL */
+ NFA_ANY, /* Match any one character. */
+ NFA_IDENT, /* Match identifier char */
+ NFA_SIDENT, /* Match identifier char but no digit */
+ NFA_KWORD, /* Match keyword char */
+ NFA_SKWORD, /* Match word char but no digit */
+ NFA_FNAME, /* Match file name char */
+ NFA_SFNAME, /* Match file name char but no digit */
+ NFA_PRINT, /* Match printable char */
+ NFA_SPRINT, /* Match printable char but no digit */
+ NFA_WHITE, /* Match whitespace char */
+ NFA_NWHITE, /* Match non-whitespace char */
+ NFA_DIGIT, /* Match digit char */
+ NFA_NDIGIT, /* Match non-digit char */
+ NFA_HEX, /* Match hex char */
+ NFA_NHEX, /* Match non-hex char */
+ NFA_OCTAL, /* Match octal char */
+ NFA_NOCTAL, /* Match non-octal char */
+ NFA_WORD, /* Match word char */
+ NFA_NWORD, /* Match non-word char */
+ NFA_HEAD, /* Match head char */
+ NFA_NHEAD, /* Match non-head char */
+ NFA_ALPHA, /* Match alpha char */
+ NFA_NALPHA, /* Match non-alpha char */
+ NFA_LOWER, /* Match lowercase char */
+ NFA_NLOWER, /* Match non-lowercase char */
+ NFA_UPPER, /* Match uppercase char */
+ NFA_NUPPER, /* Match non-uppercase char */
+ NFA_LOWER_IC, /* Match [a-z] */
+ NFA_NLOWER_IC, /* Match [^a-z] */
+ NFA_UPPER_IC, /* Match [A-Z] */
+ NFA_NUPPER_IC, /* Match [^A-Z] */
+
+ NFA_FIRST_NL = NFA_ANY + NFA_ADD_NL,
+ NFA_LAST_NL = NFA_NUPPER_IC + NFA_ADD_NL,
+
+ NFA_CURSOR, /* Match cursor pos */
+ NFA_LNUM, /* Match line number */
+ NFA_LNUM_GT, /* Match > line number */
+ NFA_LNUM_LT, /* Match < line number */
+ NFA_COL, /* Match cursor column */
+ NFA_COL_GT, /* Match > cursor column */
+ NFA_COL_LT, /* Match < cursor column */
+ NFA_VCOL, /* Match cursor virtual column */
+ NFA_VCOL_GT, /* Match > cursor virtual column */
+ NFA_VCOL_LT, /* Match < cursor virtual column */
+ NFA_MARK, /* Match mark */
+ NFA_MARK_GT, /* Match > mark */
+ NFA_MARK_LT, /* Match < mark */
+ NFA_VISUAL, /* Match Visual area */
+
+ /* Character classes [:alnum:] etc */
+ NFA_CLASS_ALNUM,
+ NFA_CLASS_ALPHA,
+ NFA_CLASS_BLANK,
+ NFA_CLASS_CNTRL,
+ NFA_CLASS_DIGIT,
+ NFA_CLASS_GRAPH,
+ NFA_CLASS_LOWER,
+ NFA_CLASS_PRINT,
+ NFA_CLASS_PUNCT,
+ NFA_CLASS_SPACE,
+ NFA_CLASS_UPPER,
+ NFA_CLASS_XDIGIT,
+ NFA_CLASS_TAB,
+ NFA_CLASS_RETURN,
+ NFA_CLASS_BACKSPACE,
+ NFA_CLASS_ESCAPE,
+ NFA_CLASS_IDENT,
+ NFA_CLASS_KEYWORD,
+ NFA_CLASS_FNAME
+};
+
+/* Keep in sync with classchars. */
+static int nfa_classcodes[] = {
+ NFA_ANY, NFA_IDENT, NFA_SIDENT, NFA_KWORD,NFA_SKWORD,
+ NFA_FNAME, NFA_SFNAME, NFA_PRINT, NFA_SPRINT,
+ NFA_WHITE, NFA_NWHITE, NFA_DIGIT, NFA_NDIGIT,
+ NFA_HEX, NFA_NHEX, NFA_OCTAL, NFA_NOCTAL,
+ NFA_WORD, NFA_NWORD, NFA_HEAD, NFA_NHEAD,
+ NFA_ALPHA, NFA_NALPHA, NFA_LOWER, NFA_NLOWER,
+ NFA_UPPER, NFA_NUPPER
+};
+
+static char_u e_nul_found[] = N_("E865: (NFA) Regexp end encountered prematurely");
+static char_u e_misplaced[] = N_("E866: (NFA regexp) Misplaced %c");
+static char_u e_ill_char_class[] = N_("E877: (NFA regexp) Invalid character class: %ld");
+
+// Variables only used in nfa_regcomp() and descendants.
+static int nfa_re_flags; // re_flags passed to nfa_regcomp()
+static int *post_start; // holds the postfix form of r.e.
+static int *post_end;
+static int *post_ptr;
+static int nstate; // Number of states in the NFA.
+static int istate; // Index in the state vector, used in alloc_state()
+
+/* If not NULL match must end at this position */
+static save_se_T *nfa_endp = NULL;
+
+/* 0 for first call to nfa_regmatch(), 1 for recursive call. */
+static int nfa_ll_index = 0;
+
+static int realloc_post_list(void);
+static int nfa_reg(int paren);
+#ifdef DEBUG
+static void nfa_print_state2(FILE *debugf, nfa_state_T *state, garray_T *indent);
+#endif
+static int match_follows(nfa_state_T *startstate, int depth);
+static int failure_chance(nfa_state_T *state, int depth);
+
+/* helper functions used when doing re2post() ... regatom() parsing */
+#define EMIT(c) do { \
+ if (post_ptr >= post_end && realloc_post_list() == FAIL) \
+ return FAIL; \
+ *post_ptr++ = c; \
+ } while (0)
+
+/*
+ * Initialize internal variables before NFA compilation.
+ * Return OK on success, FAIL otherwise.
+ */
+ static int
+nfa_regcomp_start(
+ char_u *expr,
+ int re_flags) /* see vim_regcomp() */
+{
+ size_t postfix_size;
+ int nstate_max;
+
+ nstate = 0;
+ istate = 0;
+ /* A reasonable estimation for maximum size */
+ nstate_max = (int)(STRLEN(expr) + 1) * 25;
+
+ /* Some items blow up in size, such as [A-z]. Add more space for that.
+ * When it is still not enough realloc_post_list() will be used. */
+ nstate_max += 1000;
+
+ /* Size for postfix representation of expr. */
+ postfix_size = sizeof(int) * nstate_max;
+
+ post_start = (int *)lalloc(postfix_size, TRUE);
+ if (post_start == NULL)
+ return FAIL;
+ post_ptr = post_start;
+ post_end = post_start + nstate_max;
+ rex.nfa_has_zend = FALSE;
+ rex.nfa_has_backref = FALSE;
+
+ /* shared with BT engine */
+ regcomp_start(expr, re_flags);
+
+ return OK;
+}
+
+/*
+ * Figure out if the NFA state list starts with an anchor, must match at start
+ * of the line.
+ */
+ static int
+nfa_get_reganch(nfa_state_T *start, int depth)
+{
+ nfa_state_T *p = start;
+
+ if (depth > 4)
+ return 0;
+
+ while (p != NULL)
+ {
+ switch (p->c)
+ {
+ case NFA_BOL:
+ case NFA_BOF:
+ return 1; /* yes! */
+
+ case NFA_ZSTART:
+ case NFA_ZEND:
+ case NFA_CURSOR:
+ case NFA_VISUAL:
+
+ case NFA_MOPEN:
+ case NFA_MOPEN1:
+ case NFA_MOPEN2:
+ case NFA_MOPEN3:
+ case NFA_MOPEN4:
+ case NFA_MOPEN5:
+ case NFA_MOPEN6:
+ case NFA_MOPEN7:
+ case NFA_MOPEN8:
+ case NFA_MOPEN9:
+ case NFA_NOPEN:
+#ifdef FEAT_SYN_HL
+ case NFA_ZOPEN:
+ case NFA_ZOPEN1:
+ case NFA_ZOPEN2:
+ case NFA_ZOPEN3:
+ case NFA_ZOPEN4:
+ case NFA_ZOPEN5:
+ case NFA_ZOPEN6:
+ case NFA_ZOPEN7:
+ case NFA_ZOPEN8:
+ case NFA_ZOPEN9:
+#endif
+ p = p->out;
+ break;
+
+ case NFA_SPLIT:
+ return nfa_get_reganch(p->out, depth + 1)
+ && nfa_get_reganch(p->out1, depth + 1);
+
+ default:
+ return 0; /* noooo */
+ }
+ }
+ return 0;
+}
+
+/*
+ * Figure out if the NFA state list starts with a character which must match
+ * at start of the match.
+ */
+ static int
+nfa_get_regstart(nfa_state_T *start, int depth)
+{
+ nfa_state_T *p = start;
+
+ if (depth > 4)
+ return 0;
+
+ while (p != NULL)
+ {
+ switch (p->c)
+ {
+ /* all kinds of zero-width matches */
+ case NFA_BOL:
+ case NFA_BOF:
+ case NFA_BOW:
+ case NFA_EOW:
+ case NFA_ZSTART:
+ case NFA_ZEND:
+ case NFA_CURSOR:
+ case NFA_VISUAL:
+ case NFA_LNUM:
+ case NFA_LNUM_GT:
+ case NFA_LNUM_LT:
+ case NFA_COL:
+ case NFA_COL_GT:
+ case NFA_COL_LT:
+ case NFA_VCOL:
+ case NFA_VCOL_GT:
+ case NFA_VCOL_LT:
+ case NFA_MARK:
+ case NFA_MARK_GT:
+ case NFA_MARK_LT:
+
+ case NFA_MOPEN:
+ case NFA_MOPEN1:
+ case NFA_MOPEN2:
+ case NFA_MOPEN3:
+ case NFA_MOPEN4:
+ case NFA_MOPEN5:
+ case NFA_MOPEN6:
+ case NFA_MOPEN7:
+ case NFA_MOPEN8:
+ case NFA_MOPEN9:
+ case NFA_NOPEN:
+#ifdef FEAT_SYN_HL
+ case NFA_ZOPEN:
+ case NFA_ZOPEN1:
+ case NFA_ZOPEN2:
+ case NFA_ZOPEN3:
+ case NFA_ZOPEN4:
+ case NFA_ZOPEN5:
+ case NFA_ZOPEN6:
+ case NFA_ZOPEN7:
+ case NFA_ZOPEN8:
+ case NFA_ZOPEN9:
+#endif
+ p = p->out;
+ break;
+
+ case NFA_SPLIT:
+ {
+ int c1 = nfa_get_regstart(p->out, depth + 1);
+ int c2 = nfa_get_regstart(p->out1, depth + 1);
+
+ if (c1 == c2)
+ return c1; /* yes! */
+ return 0;
+ }
+
+ default:
+ if (p->c > 0)
+ return p->c; /* yes! */
+ return 0;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Figure out if the NFA state list contains just literal text and nothing
+ * else. If so return a string in allocated memory with what must match after
+ * regstart. Otherwise return NULL.
+ */
+ static char_u *
+nfa_get_match_text(nfa_state_T *start)
+{
+ nfa_state_T *p = start;
+ int len = 0;
+ char_u *ret;
+ char_u *s;
+
+ if (p->c != NFA_MOPEN)
+ return NULL; /* just in case */
+ p = p->out;
+ while (p->c > 0)
+ {
+ len += MB_CHAR2LEN(p->c);
+ p = p->out;
+ }
+ if (p->c != NFA_MCLOSE || p->out->c != NFA_MATCH)
+ return NULL;
+
+ ret = alloc(len);
+ if (ret != NULL)
+ {
+ p = start->out->out; /* skip first char, it goes into regstart */
+ s = ret;
+ while (p->c > 0)
+ {
+ if (has_mbyte)
+ s += (*mb_char2bytes)(p->c, s);
+ else
+ *s++ = p->c;
+ p = p->out;
+ }
+ *s = NUL;
+ }
+ return ret;
+}
+
+/*
+ * Allocate more space for post_start. Called when
+ * running above the estimated number of states.
+ */
+ static int
+realloc_post_list(void)
+{
+ int nstate_max = (int)(post_end - post_start);
+ int new_max = nstate_max + 1000;
+ int *new_start;
+ int *old_start;
+
+ new_start = (int *)lalloc(new_max * sizeof(int), TRUE);
+ if (new_start == NULL)
+ return FAIL;
+ mch_memmove(new_start, post_start, nstate_max * sizeof(int));
+ old_start = post_start;
+ post_start = new_start;
+ post_ptr = new_start + (post_ptr - old_start);
+ post_end = post_start + new_max;
+ vim_free(old_start);
+ return OK;
+}
+
+/*
+ * Search between "start" and "end" and try to recognize a
+ * character class in expanded form. For example [0-9].
+ * On success, return the id the character class to be emitted.
+ * On failure, return 0 (=FAIL)
+ * Start points to the first char of the range, while end should point
+ * to the closing brace.
+ * Keep in mind that 'ignorecase' applies at execution time, thus [a-z] may
+ * need to be interpreted as [a-zA-Z].
+ */
+ static int
+nfa_recognize_char_class(char_u *start, char_u *end, int extra_newl)
+{
+# define CLASS_not 0x80
+# define CLASS_af 0x40
+# define CLASS_AF 0x20
+# define CLASS_az 0x10
+# define CLASS_AZ 0x08
+# define CLASS_o7 0x04
+# define CLASS_o9 0x02
+# define CLASS_underscore 0x01
+
+ int newl = FALSE;
+ char_u *p;
+ int config = 0;
+
+ if (extra_newl == TRUE)
+ newl = TRUE;
+
+ if (*end != ']')
+ return FAIL;
+ p = start;
+ if (*p == '^')
+ {
+ config |= CLASS_not;
+ p++;
+ }
+
+ while (p < end)
+ {
+ if (p + 2 < end && *(p + 1) == '-')
+ {
+ switch (*p)
+ {
+ case '0':
+ if (*(p + 2) == '9')
+ {
+ config |= CLASS_o9;
+ break;
+ }
+ if (*(p + 2) == '7')
+ {
+ config |= CLASS_o7;
+ break;
+ }
+ return FAIL;
+
+ case 'a':
+ if (*(p + 2) == 'z')
+ {
+ config |= CLASS_az;
+ break;
+ }
+ if (*(p + 2) == 'f')
+ {
+ config |= CLASS_af;
+ break;
+ }
+ return FAIL;
+
+ case 'A':
+ if (*(p + 2) == 'Z')
+ {
+ config |= CLASS_AZ;
+ break;
+ }
+ if (*(p + 2) == 'F')
+ {
+ config |= CLASS_AF;
+ break;
+ }
+ return FAIL;
+
+ default:
+ return FAIL;
+ }
+ p += 3;
+ }
+ else if (p + 1 < end && *p == '\\' && *(p + 1) == 'n')
+ {
+ newl = TRUE;
+ p += 2;
+ }
+ else if (*p == '_')
+ {
+ config |= CLASS_underscore;
+ p ++;
+ }
+ else if (*p == '\n')
+ {
+ newl = TRUE;
+ p ++;
+ }
+ else
+ return FAIL;
+ } /* while (p < end) */
+
+ if (p != end)
+ return FAIL;
+
+ if (newl == TRUE)
+ extra_newl = NFA_ADD_NL;
+
+ switch (config)
+ {
+ case CLASS_o9:
+ return extra_newl + NFA_DIGIT;
+ case CLASS_not | CLASS_o9:
+ return extra_newl + NFA_NDIGIT;
+ case CLASS_af | CLASS_AF | CLASS_o9:
+ return extra_newl + NFA_HEX;
+ case CLASS_not | CLASS_af | CLASS_AF | CLASS_o9:
+ return extra_newl + NFA_NHEX;
+ case CLASS_o7:
+ return extra_newl + NFA_OCTAL;
+ case CLASS_not | CLASS_o7:
+ return extra_newl + NFA_NOCTAL;
+ case CLASS_az | CLASS_AZ | CLASS_o9 | CLASS_underscore:
+ return extra_newl + NFA_WORD;
+ case CLASS_not | CLASS_az | CLASS_AZ | CLASS_o9 | CLASS_underscore:
+ return extra_newl + NFA_NWORD;
+ case CLASS_az | CLASS_AZ | CLASS_underscore:
+ return extra_newl + NFA_HEAD;
+ case CLASS_not | CLASS_az | CLASS_AZ | CLASS_underscore:
+ return extra_newl + NFA_NHEAD;
+ case CLASS_az | CLASS_AZ:
+ return extra_newl + NFA_ALPHA;
+ case CLASS_not | CLASS_az | CLASS_AZ:
+ return extra_newl + NFA_NALPHA;
+ case CLASS_az:
+ return extra_newl + NFA_LOWER_IC;
+ case CLASS_not | CLASS_az:
+ return extra_newl + NFA_NLOWER_IC;
+ case CLASS_AZ:
+ return extra_newl + NFA_UPPER_IC;
+ case CLASS_not | CLASS_AZ:
+ return extra_newl + NFA_NUPPER_IC;
+ }
+ return FAIL;
+}
+
+/*
+ * Produce the bytes for equivalence class "c".
+ * Currently only handles latin1, latin9 and utf-8.
+ * Emits bytes in postfix notation: 'a,b,NFA_OR,c,NFA_OR' is
+ * equivalent to 'a OR b OR c'
+ *
+ * NOTE! When changing this function, also update reg_equi_class()
+ */
+ static int
+nfa_emit_equi_class(int c)
+{
+#define EMIT2(c) EMIT(c); EMIT(NFA_CONCAT);
+#define EMITMBC(c) EMIT(c); EMIT(NFA_CONCAT);
+
+ if (enc_utf8 || STRCMP(p_enc, "latin1") == 0
+ || STRCMP(p_enc, "iso-8859-15") == 0)
+ {
+#ifdef EBCDIC
+# define A_circumflex 0x62
+# define A_diaeresis 0x63
+# define A_grave 0x64
+# define A_acute 0x65
+# define A_virguilla 0x66
+# define A_ring 0x67
+# define C_cedilla 0x68
+# define E_acute 0x71
+# define E_circumflex 0x72
+# define E_diaeresis 0x73
+# define E_grave 0x74
+# define I_acute 0x75
+# define I_circumflex 0x76
+# define I_diaeresis 0x77
+# define I_grave 0x78
+# define N_virguilla 0x69
+# define O_circumflex 0xeb
+# define O_diaeresis 0xec
+# define O_grave 0xed
+# define O_acute 0xee
+# define O_virguilla 0xef
+# define O_slash 0x80
+# define U_circumflex 0xfb
+# define U_diaeresis 0xfc
+# define U_grave 0xfd
+# define U_acute 0xfe
+# define Y_acute 0xba
+# define a_grave 0x42
+# define a_acute 0x43
+# define a_circumflex 0x44
+# define a_virguilla 0x45
+# define a_diaeresis 0x46
+# define a_ring 0x47
+# define c_cedilla 0x48
+# define e_grave 0x51
+# define e_acute 0x52
+# define e_circumflex 0x53
+# define e_diaeresis 0x54
+# define i_grave 0x55
+# define i_acute 0x56
+# define i_circumflex 0x57
+# define i_diaeresis 0x58
+# define n_virguilla 0x49
+# define o_grave 0xcb
+# define o_acute 0xcc
+# define o_circumflex 0xcd
+# define o_virguilla 0xce
+# define o_diaeresis 0xcf
+# define o_slash 0x70
+# define u_grave 0xdb
+# define u_acute 0xdc
+# define u_circumflex 0xdd
+# define u_diaeresis 0xde
+# define y_acute 0x8d
+# define y_diaeresis 0xdf
+#else
+# define A_grave 0xc0
+# define A_acute 0xc1
+# define A_circumflex 0xc2
+# define A_virguilla 0xc3
+# define A_diaeresis 0xc4
+# define A_ring 0xc5
+# define C_cedilla 0xc7
+# define E_grave 0xc8
+# define E_acute 0xc9
+# define E_circumflex 0xca
+# define E_diaeresis 0xcb
+# define I_grave 0xcc
+# define I_acute 0xcd
+# define I_circumflex 0xce
+# define I_diaeresis 0xcf
+# define N_virguilla 0xd1
+# define O_grave 0xd2
+# define O_acute 0xd3
+# define O_circumflex 0xd4
+# define O_virguilla 0xd5
+# define O_diaeresis 0xd6
+# define O_slash 0xd8
+# define U_grave 0xd9
+# define U_acute 0xda
+# define U_circumflex 0xdb
+# define U_diaeresis 0xdc
+# define Y_acute 0xdd
+# define a_grave 0xe0
+# define a_acute 0xe1
+# define a_circumflex 0xe2
+# define a_virguilla 0xe3
+# define a_diaeresis 0xe4
+# define a_ring 0xe5
+# define c_cedilla 0xe7
+# define e_grave 0xe8
+# define e_acute 0xe9
+# define e_circumflex 0xea
+# define e_diaeresis 0xeb
+# define i_grave 0xec
+# define i_acute 0xed
+# define i_circumflex 0xee
+# define i_diaeresis 0xef
+# define n_virguilla 0xf1
+# define o_grave 0xf2
+# define o_acute 0xf3
+# define o_circumflex 0xf4
+# define o_virguilla 0xf5
+# define o_diaeresis 0xf6
+# define o_slash 0xf8
+# define u_grave 0xf9
+# define u_acute 0xfa
+# define u_circumflex 0xfb
+# define u_diaeresis 0xfc
+# define y_acute 0xfd
+# define y_diaeresis 0xff
+#endif
+ switch (c)
+ {
+ case 'A': case A_grave: case A_acute: case A_circumflex:
+ case A_virguilla: case A_diaeresis: case A_ring:
+ CASEMBC(0x100) CASEMBC(0x102) CASEMBC(0x104)
+ CASEMBC(0x1cd) CASEMBC(0x1de) CASEMBC(0x1e0)
+ CASEMBC(0x1ea2)
+ EMIT2('A'); EMIT2(A_grave); EMIT2(A_acute);
+ EMIT2(A_circumflex); EMIT2(A_virguilla);
+ EMIT2(A_diaeresis); EMIT2(A_ring);
+ EMITMBC(0x100) EMITMBC(0x102) EMITMBC(0x104)
+ EMITMBC(0x1cd) EMITMBC(0x1de) EMITMBC(0x1e0)
+ EMITMBC(0x1ea2)
+ return OK;
+
+ case 'B': CASEMBC(0x1e02) CASEMBC(0x1e06)
+ EMIT2('B'); EMITMBC(0x1e02) EMITMBC(0x1e06)
+ return OK;
+
+ case 'C': case C_cedilla: CASEMBC(0x106) CASEMBC(0x108)
+ CASEMBC(0x10a) CASEMBC(0x10c)
+ EMIT2('C'); EMIT2(C_cedilla);
+ EMITMBC(0x106) EMITMBC(0x108)
+ EMITMBC(0x10a) EMITMBC(0x10c)
+ return OK;
+
+ case 'D': CASEMBC(0x10e) CASEMBC(0x110) CASEMBC(0x1e0a)
+ CASEMBC(0x1e0e) CASEMBC(0x1e10)
+ EMIT2('D'); EMITMBC(0x10e) EMITMBC(0x110) EMITMBC(0x1e0a)
+ EMITMBC(0x1e0e) EMITMBC(0x1e10)
+ return OK;
+
+ case 'E': case E_grave: case E_acute: case E_circumflex:
+ case E_diaeresis: CASEMBC(0x112) CASEMBC(0x114)
+ CASEMBC(0x116) CASEMBC(0x118) CASEMBC(0x11a)
+ CASEMBC(0x1eba) CASEMBC(0x1ebc)
+ EMIT2('E'); EMIT2(E_grave); EMIT2(E_acute);
+ EMIT2(E_circumflex); EMIT2(E_diaeresis);
+ EMITMBC(0x112) EMITMBC(0x114) EMITMBC(0x116)
+ EMITMBC(0x118) EMITMBC(0x11a) EMITMBC(0x1eba)
+ EMITMBC(0x1ebc)
+ return OK;
+
+ case 'F': CASEMBC(0x1e1e)
+ EMIT2('F'); EMITMBC(0x1e1e)
+ return OK;
+
+ case 'G': CASEMBC(0x11c) CASEMBC(0x11e) CASEMBC(0x120)
+ CASEMBC(0x122) CASEMBC(0x1e4) CASEMBC(0x1e6)
+ CASEMBC(0x1f4) CASEMBC(0x1e20)
+ EMIT2('G'); EMITMBC(0x11c) EMITMBC(0x11e) EMITMBC(0x120)
+ EMITMBC(0x122) EMITMBC(0x1e4) EMITMBC(0x1e6)
+ EMITMBC(0x1f4) EMITMBC(0x1e20)
+ return OK;
+
+ case 'H': CASEMBC(0x124) CASEMBC(0x126) CASEMBC(0x1e22)
+ CASEMBC(0x1e26) CASEMBC(0x1e28)
+ EMIT2('H'); EMITMBC(0x124) EMITMBC(0x126) EMITMBC(0x1e22)
+ EMITMBC(0x1e26) EMITMBC(0x1e28)
+ return OK;
+
+ case 'I': case I_grave: case I_acute: case I_circumflex:
+ case I_diaeresis: CASEMBC(0x128) CASEMBC(0x12a)
+ CASEMBC(0x12c) CASEMBC(0x12e) CASEMBC(0x130)
+ CASEMBC(0x1cf) CASEMBC(0x1ec8)
+ EMIT2('I'); EMIT2(I_grave); EMIT2(I_acute);
+ EMIT2(I_circumflex); EMIT2(I_diaeresis);
+ EMITMBC(0x128) EMITMBC(0x12a)
+ EMITMBC(0x12c) EMITMBC(0x12e) EMITMBC(0x130)
+ EMITMBC(0x1cf) EMITMBC(0x1ec8)
+ return OK;
+
+ case 'J': CASEMBC(0x134)
+ EMIT2('J'); EMITMBC(0x134)
+ return OK;
+
+ case 'K': CASEMBC(0x136) CASEMBC(0x1e8) CASEMBC(0x1e30)
+ CASEMBC(0x1e34)
+ EMIT2('K'); EMITMBC(0x136) EMITMBC(0x1e8) EMITMBC(0x1e30)
+ EMITMBC(0x1e34)
+ return OK;
+
+ case 'L': CASEMBC(0x139) CASEMBC(0x13b) CASEMBC(0x13d)
+ CASEMBC(0x13f) CASEMBC(0x141) CASEMBC(0x1e3a)
+ EMIT2('L'); EMITMBC(0x139) EMITMBC(0x13b) EMITMBC(0x13d)
+ EMITMBC(0x13f) EMITMBC(0x141) EMITMBC(0x1e3a)
+ return OK;
+
+ case 'M': CASEMBC(0x1e3e) CASEMBC(0x1e40)
+ EMIT2('M'); EMITMBC(0x1e3e) EMITMBC(0x1e40)
+ return OK;
+
+ case 'N': case N_virguilla: CASEMBC(0x143) CASEMBC(0x145)
+ CASEMBC(0x147) CASEMBC(0x1e44) CASEMBC(0x1e48)
+ EMIT2('N'); EMIT2(N_virguilla);
+ EMITMBC(0x143) EMITMBC(0x145)
+ EMITMBC(0x147) EMITMBC(0x1e44) EMITMBC(0x1e48)
+ return OK;
+
+ case 'O': case O_grave: case O_acute: case O_circumflex:
+ case O_virguilla: case O_diaeresis: case O_slash:
+ CASEMBC(0x14c) CASEMBC(0x14e) CASEMBC(0x150)
+ CASEMBC(0x1a0) CASEMBC(0x1d1) CASEMBC(0x1ea)
+ CASEMBC(0x1ec) CASEMBC(0x1ece)
+ EMIT2('O'); EMIT2(O_grave); EMIT2(O_acute);
+ EMIT2(O_circumflex); EMIT2(O_virguilla);
+ EMIT2(O_diaeresis); EMIT2(O_slash);
+ EMITMBC(0x14c) EMITMBC(0x14e) EMITMBC(0x150)
+ EMITMBC(0x1a0) EMITMBC(0x1d1) EMITMBC(0x1ea)
+ EMITMBC(0x1ec) EMITMBC(0x1ece)
+ return OK;
+
+ case 'P': case 0x1e54: case 0x1e56:
+ EMIT2('P'); EMITMBC(0x1e54) EMITMBC(0x1e56)
+ return OK;
+
+ case 'R': CASEMBC(0x154) CASEMBC(0x156) CASEMBC(0x158)
+ CASEMBC(0x1e58) CASEMBC(0x1e5e)
+ EMIT2('R'); EMITMBC(0x154) EMITMBC(0x156) EMITMBC(0x158)
+ EMITMBC(0x1e58) EMITMBC(0x1e5e)
+ return OK;
+
+ case 'S': CASEMBC(0x15a) CASEMBC(0x15c) CASEMBC(0x15e)
+ CASEMBC(0x160) CASEMBC(0x1e60)
+ EMIT2('S'); EMITMBC(0x15a) EMITMBC(0x15c) EMITMBC(0x15e)
+ EMITMBC(0x160) EMITMBC(0x1e60)
+ return OK;
+
+ case 'T': CASEMBC(0x162) CASEMBC(0x164) CASEMBC(0x166)
+ CASEMBC(0x1e6a) CASEMBC(0x1e6e)
+ EMIT2('T'); EMITMBC(0x162) EMITMBC(0x164) EMITMBC(0x166)
+ EMITMBC(0x1e6a) EMITMBC(0x1e6e)
+ return OK;
+
+ case 'U': case U_grave: case U_acute: case U_diaeresis:
+ case U_circumflex: CASEMBC(0x168) CASEMBC(0x16a)
+ CASEMBC(0x16c) CASEMBC(0x16e) CASEMBC(0x170)
+ CASEMBC(0x172) CASEMBC(0x1af) CASEMBC(0x1d3)
+ CASEMBC(0x1ee6)
+ EMIT2('U'); EMIT2(U_grave); EMIT2(U_acute);
+ EMIT2(U_diaeresis); EMIT2(U_circumflex);
+ EMITMBC(0x168) EMITMBC(0x16a)
+ EMITMBC(0x16c) EMITMBC(0x16e) EMITMBC(0x170)
+ EMITMBC(0x172) EMITMBC(0x1af) EMITMBC(0x1d3)
+ EMITMBC(0x1ee6)
+ return OK;
+
+ case 'V': CASEMBC(0x1e7c)
+ EMIT2('V'); EMITMBC(0x1e7c)
+ return OK;
+
+ case 'W': CASEMBC(0x174) CASEMBC(0x1e80) CASEMBC(0x1e82)
+ CASEMBC(0x1e84) CASEMBC(0x1e86)
+ EMIT2('W'); EMITMBC(0x174) EMITMBC(0x1e80) EMITMBC(0x1e82)
+ EMITMBC(0x1e84) EMITMBC(0x1e86)
+ return OK;
+
+ case 'X': CASEMBC(0x1e8a) CASEMBC(0x1e8c)
+ EMIT2('X'); EMITMBC(0x1e8a) EMITMBC(0x1e8c)
+ return OK;
+
+ case 'Y': case Y_acute: CASEMBC(0x176) CASEMBC(0x178)
+ CASEMBC(0x1e8e) CASEMBC(0x1ef2) CASEMBC(0x1ef6)
+ CASEMBC(0x1ef8)
+ EMIT2('Y'); EMIT2(Y_acute);
+ EMITMBC(0x176) EMITMBC(0x178)
+ EMITMBC(0x1e8e) EMITMBC(0x1ef2) EMITMBC(0x1ef6)
+ EMITMBC(0x1ef8)
+ return OK;
+
+ case 'Z': CASEMBC(0x179) CASEMBC(0x17b) CASEMBC(0x17d)
+ CASEMBC(0x1b5) CASEMBC(0x1e90) CASEMBC(0x1e94)
+ EMIT2('Z'); EMITMBC(0x179) EMITMBC(0x17b) EMITMBC(0x17d)
+ EMITMBC(0x1b5) EMITMBC(0x1e90) EMITMBC(0x1e94)
+ return OK;
+
+ case 'a': case a_grave: case a_acute: case a_circumflex:
+ case a_virguilla: case a_diaeresis: case a_ring:
+ CASEMBC(0x101) CASEMBC(0x103) CASEMBC(0x105)
+ CASEMBC(0x1ce) CASEMBC(0x1df) CASEMBC(0x1e1)
+ CASEMBC(0x1ea3)
+ EMIT2('a'); EMIT2(a_grave); EMIT2(a_acute);
+ EMIT2(a_circumflex); EMIT2(a_virguilla);
+ EMIT2(a_diaeresis); EMIT2(a_ring);
+ EMITMBC(0x101) EMITMBC(0x103) EMITMBC(0x105)
+ EMITMBC(0x1ce) EMITMBC(0x1df) EMITMBC(0x1e1)
+ EMITMBC(0x1ea3)
+ return OK;
+
+ case 'b': CASEMBC(0x1e03) CASEMBC(0x1e07)
+ EMIT2('b'); EMITMBC(0x1e03) EMITMBC(0x1e07)
+ return OK;
+
+ case 'c': case c_cedilla: CASEMBC(0x107) CASEMBC(0x109)
+ CASEMBC(0x10b) CASEMBC(0x10d)
+ EMIT2('c'); EMIT2(c_cedilla);
+ EMITMBC(0x107) EMITMBC(0x109)
+ EMITMBC(0x10b) EMITMBC(0x10d)
+ return OK;
+
+ case 'd': CASEMBC(0x10f) CASEMBC(0x111) CASEMBC(0x1e0b)
+ CASEMBC(0x1e0f) CASEMBC(0x1e11)
+ EMIT2('d'); EMITMBC(0x10f) EMITMBC(0x111)
+ EMITMBC(0x1e0b) EMITMBC(0x1e0f) EMITMBC(0x1e11)
+ return OK;
+
+ case 'e': case e_grave: case e_acute: case e_circumflex:
+ case e_diaeresis: CASEMBC(0x113) CASEMBC(0x115)
+ CASEMBC(0x117) CASEMBC(0x119) CASEMBC(0x11b)
+ CASEMBC(0x1ebb) CASEMBC(0x1ebd)
+ EMIT2('e'); EMIT2(e_grave); EMIT2(e_acute);
+ EMIT2(e_circumflex); EMIT2(e_diaeresis);
+ EMITMBC(0x113) EMITMBC(0x115)
+ EMITMBC(0x117) EMITMBC(0x119) EMITMBC(0x11b)
+ EMITMBC(0x1ebb) EMITMBC(0x1ebd)
+ return OK;
+
+ case 'f': CASEMBC(0x1e1f)
+ EMIT2('f'); EMITMBC(0x1e1f)
+ return OK;
+
+ case 'g': CASEMBC(0x11d) CASEMBC(0x11f) CASEMBC(0x121)
+ CASEMBC(0x123) CASEMBC(0x1e5) CASEMBC(0x1e7)
+ CASEMBC(0x1f5) CASEMBC(0x1e21)
+ EMIT2('g'); EMITMBC(0x11d) EMITMBC(0x11f) EMITMBC(0x121)
+ EMITMBC(0x123) EMITMBC(0x1e5) EMITMBC(0x1e7)
+ EMITMBC(0x1f5) EMITMBC(0x1e21)
+ return OK;
+
+ case 'h': CASEMBC(0x125) CASEMBC(0x127) CASEMBC(0x1e23)
+ CASEMBC(0x1e27) CASEMBC(0x1e29) CASEMBC(0x1e96)
+ EMIT2('h'); EMITMBC(0x125) EMITMBC(0x127) EMITMBC(0x1e23)
+ EMITMBC(0x1e27) EMITMBC(0x1e29) EMITMBC(0x1e96)
+ return OK;
+
+ case 'i': case i_grave: case i_acute: case i_circumflex:
+ case i_diaeresis: CASEMBC(0x129) CASEMBC(0x12b)
+ CASEMBC(0x12d) CASEMBC(0x12f) CASEMBC(0x1d0)
+ CASEMBC(0x1ec9)
+ EMIT2('i'); EMIT2(i_grave); EMIT2(i_acute);
+ EMIT2(i_circumflex); EMIT2(i_diaeresis);
+ EMITMBC(0x129) EMITMBC(0x12b)
+ EMITMBC(0x12d) EMITMBC(0x12f) EMITMBC(0x1d0)
+ EMITMBC(0x1ec9)
+ return OK;
+
+ case 'j': CASEMBC(0x135) CASEMBC(0x1f0)
+ EMIT2('j'); EMITMBC(0x135) EMITMBC(0x1f0)
+ return OK;
+
+ case 'k': CASEMBC(0x137) CASEMBC(0x1e9) CASEMBC(0x1e31)
+ CASEMBC(0x1e35)
+ EMIT2('k'); EMITMBC(0x137) EMITMBC(0x1e9) EMITMBC(0x1e31)
+ EMITMBC(0x1e35)
+ return OK;
+
+ case 'l': CASEMBC(0x13a) CASEMBC(0x13c) CASEMBC(0x13e)
+ CASEMBC(0x140) CASEMBC(0x142) CASEMBC(0x1e3b)
+ EMIT2('l'); EMITMBC(0x13a) EMITMBC(0x13c) EMITMBC(0x13e)
+ EMITMBC(0x140) EMITMBC(0x142) EMITMBC(0x1e3b)
+ return OK;
+
+ case 'm': CASEMBC(0x1e3f) CASEMBC(0x1e41)
+ EMIT2('m'); EMITMBC(0x1e3f) EMITMBC(0x1e41)
+ return OK;
+
+ case 'n': case n_virguilla: CASEMBC(0x144) CASEMBC(0x146)
+ CASEMBC(0x148) CASEMBC(0x149) CASEMBC(0x1e45)
+ CASEMBC(0x1e49)
+ EMIT2('n'); EMIT2(n_virguilla);
+ EMITMBC(0x144) EMITMBC(0x146)
+ EMITMBC(0x148) EMITMBC(0x149) EMITMBC(0x1e45)
+ EMITMBC(0x1e49)
+ return OK;
+
+ case 'o': case o_grave: case o_acute: case o_circumflex:
+ case o_virguilla: case o_diaeresis: case o_slash:
+ CASEMBC(0x14d) CASEMBC(0x14f) CASEMBC(0x151)
+ CASEMBC(0x1a1) CASEMBC(0x1d2) CASEMBC(0x1eb)
+ CASEMBC(0x1ed) CASEMBC(0x1ecf)
+ EMIT2('o'); EMIT2(o_grave); EMIT2(o_acute);
+ EMIT2(o_circumflex); EMIT2(o_virguilla);
+ EMIT2(o_diaeresis); EMIT2(o_slash);
+ EMITMBC(0x14d) EMITMBC(0x14f) EMITMBC(0x151)
+ EMITMBC(0x1a1) EMITMBC(0x1d2) EMITMBC(0x1eb)
+ EMITMBC(0x1ed) EMITMBC(0x1ecf)
+ return OK;
+
+ case 'p': CASEMBC(0x1e55) CASEMBC(0x1e57)
+ EMIT2('p'); EMITMBC(0x1e55) EMITMBC(0x1e57)
+ return OK;
+
+ case 'r': CASEMBC(0x155) CASEMBC(0x157) CASEMBC(0x159)
+ CASEMBC(0x1e59) CASEMBC(0x1e5f)
+ EMIT2('r'); EMITMBC(0x155) EMITMBC(0x157) EMITMBC(0x159)
+ EMITMBC(0x1e59) EMITMBC(0x1e5f)
+ return OK;
+
+ case 's': CASEMBC(0x15b) CASEMBC(0x15d) CASEMBC(0x15f)
+ CASEMBC(0x161) CASEMBC(0x1e61)
+ EMIT2('s'); EMITMBC(0x15b) EMITMBC(0x15d) EMITMBC(0x15f)
+ EMITMBC(0x161) EMITMBC(0x1e61)
+ return OK;
+
+ case 't': CASEMBC(0x163) CASEMBC(0x165) CASEMBC(0x167)
+ CASEMBC(0x1e6b) CASEMBC(0x1e6f) CASEMBC(0x1e97)
+ EMIT2('t'); EMITMBC(0x163) EMITMBC(0x165) EMITMBC(0x167)
+ EMITMBC(0x1e6b) EMITMBC(0x1e6f) EMITMBC(0x1e97)
+ return OK;
+
+ case 'u': case u_grave: case u_acute: case u_circumflex:
+ case u_diaeresis: CASEMBC(0x169) CASEMBC(0x16b)
+ CASEMBC(0x16d) CASEMBC(0x16f) CASEMBC(0x171)
+ CASEMBC(0x173) CASEMBC(0x1b0) CASEMBC(0x1d4)
+ CASEMBC(0x1ee7)
+ EMIT2('u'); EMIT2(u_grave); EMIT2(u_acute);
+ EMIT2(u_circumflex); EMIT2(u_diaeresis);
+ EMITMBC(0x169) EMITMBC(0x16b)
+ EMITMBC(0x16d) EMITMBC(0x16f) EMITMBC(0x171)
+ EMITMBC(0x173) EMITMBC(0x1b0) EMITMBC(0x1d4)
+ EMITMBC(0x1ee7)
+ return OK;
+
+ case 'v': CASEMBC(0x1e7d)
+ EMIT2('v'); EMITMBC(0x1e7d)
+ return OK;
+
+ case 'w': CASEMBC(0x175) CASEMBC(0x1e81) CASEMBC(0x1e83)
+ CASEMBC(0x1e85) CASEMBC(0x1e87) CASEMBC(0x1e98)
+ EMIT2('w'); EMITMBC(0x175) EMITMBC(0x1e81) EMITMBC(0x1e83)
+ EMITMBC(0x1e85) EMITMBC(0x1e87) EMITMBC(0x1e98)
+ return OK;
+
+ case 'x': CASEMBC(0x1e8b) CASEMBC(0x1e8d)
+ EMIT2('x'); EMITMBC(0x1e8b) EMITMBC(0x1e8d)
+ return OK;
+
+ case 'y': case y_acute: case y_diaeresis: CASEMBC(0x177)
+ CASEMBC(0x1e8f) CASEMBC(0x1e99) CASEMBC(0x1ef3)
+ CASEMBC(0x1ef7) CASEMBC(0x1ef9)
+ EMIT2('y'); EMIT2(y_acute); EMIT2(y_diaeresis);
+ EMITMBC(0x177)
+ EMITMBC(0x1e8f) EMITMBC(0x1e99) EMITMBC(0x1ef3)
+ EMITMBC(0x1ef7) EMITMBC(0x1ef9)
+ return OK;
+
+ case 'z': CASEMBC(0x17a) CASEMBC(0x17c) CASEMBC(0x17e)
+ CASEMBC(0x1b6) CASEMBC(0x1e91) CASEMBC(0x1e95)
+ EMIT2('z'); EMITMBC(0x17a) EMITMBC(0x17c) EMITMBC(0x17e)
+ EMITMBC(0x1b6) EMITMBC(0x1e91) EMITMBC(0x1e95)
+ return OK;
+
+ /* default: character itself */
+ }
+ }
+
+ EMIT2(c);
+ return OK;
+#undef EMIT2
+#undef EMITMBC
+}
+
+/*
+ * Code to parse regular expression.
+ *
+ * We try to reuse parsing functions in regexp.c to
+ * minimize surprise and keep the syntax consistent.
+ */
+
+/*
+ * Parse the lowest level.
+ *
+ * An atom can be one of a long list of items. Many atoms match one character
+ * in the text. It is often an ordinary character or a character class.
+ * Braces can be used to make a pattern into an atom. The "\z(\)" construct
+ * is only for syntax highlighting.
+ *
+ * atom ::= ordinary-atom
+ * or \( pattern \)
+ * or \%( pattern \)
+ * or \z( pattern \)
+ */
+ static int
+nfa_regatom(void)
+{
+ int c;
+ int charclass;
+ int equiclass;
+ int collclass;
+ int got_coll_char;
+ char_u *p;
+ char_u *endp;
+ char_u *old_regparse = regparse;
+ int extra = 0;
+ int emit_range;
+ int negated;
+ int result;
+ int startc = -1;
+ int endc = -1;
+ int oldstartc = -1;
+ int save_prev_at_start = prev_at_start;
+
+ c = getchr();
+ switch (c)
+ {
+ case NUL:
+ EMSG_RET_FAIL(_(e_nul_found));
+
+ case Magic('^'):
+ EMIT(NFA_BOL);
+ break;
+
+ case Magic('$'):
+ EMIT(NFA_EOL);
+#if defined(FEAT_SYN_HL) || defined(PROTO)
+ had_eol = TRUE;
+#endif
+ break;
+
+ case Magic('<'):
+ EMIT(NFA_BOW);
+ break;
+
+ case Magic('>'):
+ EMIT(NFA_EOW);
+ break;
+
+ case Magic('_'):
+ c = no_Magic(getchr());
+ if (c == NUL)
+ EMSG_RET_FAIL(_(e_nul_found));
+
+ if (c == '^') /* "\_^" is start-of-line */
+ {
+ EMIT(NFA_BOL);
+ break;
+ }
+ if (c == '$') /* "\_$" is end-of-line */
+ {
+ EMIT(NFA_EOL);
+#if defined(FEAT_SYN_HL) || defined(PROTO)
+ had_eol = TRUE;
+#endif
+ break;
+ }
+
+ extra = NFA_ADD_NL;
+
+ /* "\_[" is collection plus newline */
+ if (c == '[')
+ goto collection;
+
+ /* "\_x" is character class plus newline */
+ /* FALLTHROUGH */
+
+ /*
+ * Character classes.
+ */
+ case Magic('.'):
+ case Magic('i'):
+ case Magic('I'):
+ case Magic('k'):
+ case Magic('K'):
+ case Magic('f'):
+ case Magic('F'):
+ case Magic('p'):
+ case Magic('P'):
+ case Magic('s'):
+ case Magic('S'):
+ case Magic('d'):
+ case Magic('D'):
+ case Magic('x'):
+ case Magic('X'):
+ case Magic('o'):
+ case Magic('O'):
+ case Magic('w'):
+ case Magic('W'):
+ case Magic('h'):
+ case Magic('H'):
+ case Magic('a'):
+ case Magic('A'):
+ case Magic('l'):
+ case Magic('L'):
+ case Magic('u'):
+ case Magic('U'):
+ p = vim_strchr(classchars, no_Magic(c));
+ if (p == NULL)
+ {
+ if (extra == NFA_ADD_NL)
+ {
+ semsg(_(e_ill_char_class), c);
+ rc_did_emsg = TRUE;
+ return FAIL;
+ }
+ siemsg("INTERNAL: Unknown character class char: %d", c);
+ return FAIL;
+ }
+
+ /* When '.' is followed by a composing char ignore the dot, so that
+ * the composing char is matched here. */
+ if (enc_utf8 && c == Magic('.') && utf_iscomposing(peekchr()))
+ {
+ old_regparse = regparse;
+ c = getchr();
+ goto nfa_do_multibyte;
+ }
+ EMIT(nfa_classcodes[p - classchars]);
+ if (extra == NFA_ADD_NL)
+ {
+ EMIT(NFA_NEWL);
+ EMIT(NFA_OR);
+ regflags |= RF_HASNL;
+ }
+ break;
+
+ case Magic('n'):
+ if (reg_string)
+ /* In a string "\n" matches a newline character. */
+ EMIT(NL);
+ else
+ {
+ /* In buffer text "\n" matches the end of a line. */
+ EMIT(NFA_NEWL);
+ regflags |= RF_HASNL;
+ }
+ break;
+
+ case Magic('('):
+ if (nfa_reg(REG_PAREN) == FAIL)
+ return FAIL; /* cascaded error */
+ break;
+
+ case Magic('|'):
+ case Magic('&'):
+ case Magic(')'):
+ semsg(_(e_misplaced), no_Magic(c));
+ return FAIL;
+
+ case Magic('='):
+ case Magic('?'):
+ case Magic('+'):
+ case Magic('@'):
+ case Magic('*'):
+ case Magic('{'):
+ /* these should follow an atom, not form an atom */
+ semsg(_(e_misplaced), no_Magic(c));
+ return FAIL;
+
+ case Magic('~'):
+ {
+ char_u *lp;
+
+ /* Previous substitute pattern.
+ * Generated as "\%(pattern\)". */
+ if (reg_prev_sub == NULL)
+ {
+ emsg(_(e_nopresub));
+ return FAIL;
+ }
+ for (lp = reg_prev_sub; *lp != NUL; MB_CPTR_ADV(lp))
+ {
+ EMIT(PTR2CHAR(lp));
+ if (lp != reg_prev_sub)
+ EMIT(NFA_CONCAT);
+ }
+ EMIT(NFA_NOPEN);
+ break;
+ }
+
+ case Magic('1'):
+ case Magic('2'):
+ case Magic('3'):
+ case Magic('4'):
+ case Magic('5'):
+ case Magic('6'):
+ case Magic('7'):
+ case Magic('8'):
+ case Magic('9'):
+ {
+ int refnum = no_Magic(c) - '1';
+
+ if (!seen_endbrace(refnum + 1))
+ return FAIL;
+ EMIT(NFA_BACKREF1 + refnum);
+ rex.nfa_has_backref = TRUE;
+ }
+ break;
+
+ case Magic('z'):
+ c = no_Magic(getchr());
+ switch (c)
+ {
+ case 's':
+ EMIT(NFA_ZSTART);
+ if (re_mult_next("\\zs") == FAIL)
+ return FAIL;
+ break;
+ case 'e':
+ EMIT(NFA_ZEND);
+ rex.nfa_has_zend = TRUE;
+ if (re_mult_next("\\ze") == FAIL)
+ return FAIL;
+ break;
+#ifdef FEAT_SYN_HL
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ /* \z1...\z9 */
+ if ((reg_do_extmatch & REX_USE) == 0)
+ EMSG_RET_FAIL(_(e_z1_not_allowed));
+ EMIT(NFA_ZREF1 + (no_Magic(c) - '1'));
+ /* No need to set rex.nfa_has_backref, the sub-matches don't
+ * change when \z1 .. \z9 matches or not. */
+ re_has_z = REX_USE;
+ break;
+ case '(':
+ /* \z( */
+ if ((reg_do_extmatch & REX_SET) == 0)
+ EMSG_RET_FAIL(_(e_z_not_allowed));
+ if (nfa_reg(REG_ZPAREN) == FAIL)
+ return FAIL; /* cascaded error */
+ re_has_z = REX_SET;
+ break;
+#endif
+ default:
+ semsg(_("E867: (NFA) Unknown operator '\\z%c'"),
+ no_Magic(c));
+ return FAIL;
+ }
+ break;
+
+ case Magic('%'):
+ c = no_Magic(getchr());
+ switch (c)
+ {
+ /* () without a back reference */
+ case '(':
+ if (nfa_reg(REG_NPAREN) == FAIL)
+ return FAIL;
+ EMIT(NFA_NOPEN);
+ break;
+
+ case 'd': /* %d123 decimal */
+ case 'o': /* %o123 octal */
+ case 'x': /* %xab hex 2 */
+ case 'u': /* %uabcd hex 4 */
+ case 'U': /* %U1234abcd hex 8 */
+ {
+ long nr;
+
+ switch (c)
+ {
+ case 'd': nr = getdecchrs(); break;
+ case 'o': nr = getoctchrs(); break;
+ case 'x': nr = gethexchrs(2); break;
+ case 'u': nr = gethexchrs(4); break;
+ case 'U': nr = gethexchrs(8); break;
+ default: nr = -1; break;
+ }
+
+ if (nr < 0)
+ EMSG2_RET_FAIL(
+ _("E678: Invalid character after %s%%[dxouU]"),
+ reg_magic == MAGIC_ALL);
+ /* A NUL is stored in the text as NL */
+ /* TODO: what if a composing character follows? */
+ EMIT(nr == 0 ? 0x0a : nr);
+ }
+ break;
+
+ /* Catch \%^ and \%$ regardless of where they appear in the
+ * pattern -- regardless of whether or not it makes sense. */
+ case '^':
+ EMIT(NFA_BOF);
+ break;
+
+ case '$':
+ EMIT(NFA_EOF);
+ break;
+
+ case '#':
+ EMIT(NFA_CURSOR);
+ break;
+
+ case 'V':
+ EMIT(NFA_VISUAL);
+ break;
+
+ case 'C':
+ EMIT(NFA_ANY_COMPOSING);
+ break;
+
+ case '[':
+ {
+ int n;
+
+ /* \%[abc] */
+ for (n = 0; (c = peekchr()) != ']'; ++n)
+ {
+ if (c == NUL)
+ EMSG2_RET_FAIL(_(e_missing_sb),
+ reg_magic == MAGIC_ALL);
+ /* recursive call! */
+ if (nfa_regatom() == FAIL)
+ return FAIL;
+ }
+ getchr(); /* get the ] */
+ if (n == 0)
+ EMSG2_RET_FAIL(_(e_empty_sb),
+ reg_magic == MAGIC_ALL);
+ EMIT(NFA_OPT_CHARS);
+ EMIT(n);
+
+ /* Emit as "\%(\%[abc]\)" to be able to handle
+ * "\%[abc]*" which would cause the empty string to be
+ * matched an unlimited number of times. NFA_NOPEN is
+ * added only once at a position, while NFA_SPLIT is
+ * added multiple times. This is more efficient than
+ * not allowing NFA_SPLIT multiple times, it is used
+ * a lot. */
+ EMIT(NFA_NOPEN);
+ break;
+ }
+
+ default:
+ {
+ long n = 0;
+ int cmp = c;
+
+ if (c == '<' || c == '>')
+ c = getchr();
+ while (VIM_ISDIGIT(c))
+ {
+ n = n * 10 + (c - '0');
+ c = getchr();
+ }
+ if (c == 'l' || c == 'c' || c == 'v')
+ {
+ if (c == 'l')
+ {
+ /* \%{n}l \%{n}<l \%{n}>l */
+ EMIT(cmp == '<' ? NFA_LNUM_LT :
+ cmp == '>' ? NFA_LNUM_GT : NFA_LNUM);
+ if (save_prev_at_start)
+ at_start = TRUE;
+ }
+ else if (c == 'c')
+ /* \%{n}c \%{n}<c \%{n}>c */
+ EMIT(cmp == '<' ? NFA_COL_LT :
+ cmp == '>' ? NFA_COL_GT : NFA_COL);
+ else
+ /* \%{n}v \%{n}<v \%{n}>v */
+ EMIT(cmp == '<' ? NFA_VCOL_LT :
+ cmp == '>' ? NFA_VCOL_GT : NFA_VCOL);
+#if VIM_SIZEOF_INT < VIM_SIZEOF_LONG
+ if (n > INT_MAX)
+ {
+ emsg(_("E951: \\% value too large"));
+ return FAIL;
+ }
+#endif
+ EMIT((int)n);
+ break;
+ }
+ else if (c == '\'' && n == 0)
+ {
+ /* \%'m \%<'m \%>'m */
+ EMIT(cmp == '<' ? NFA_MARK_LT :
+ cmp == '>' ? NFA_MARK_GT : NFA_MARK);
+ EMIT(getchr());
+ break;
+ }
+ }
+ semsg(_("E867: (NFA) Unknown operator '\\%%%c'"),
+ no_Magic(c));
+ return FAIL;
+ }
+ break;
+
+ case Magic('['):
+collection:
+ /*
+ * [abc] uses NFA_START_COLL - NFA_END_COLL
+ * [^abc] uses NFA_START_NEG_COLL - NFA_END_NEG_COLL
+ * Each character is produced as a regular state, using
+ * NFA_CONCAT to bind them together.
+ * Besides normal characters there can be:
+ * - character classes NFA_CLASS_*
+ * - ranges, two characters followed by NFA_RANGE.
+ */
+
+ p = regparse;
+ endp = skip_anyof(p);
+ if (*endp == ']')
+ {
+ /*
+ * Try to reverse engineer character classes. For example,
+ * recognize that [0-9] stands for \d and [A-Za-z_] for \h,
+ * and perform the necessary substitutions in the NFA.
+ */
+ result = nfa_recognize_char_class(regparse, endp,
+ extra == NFA_ADD_NL);
+ if (result != FAIL)
+ {
+ if (result >= NFA_FIRST_NL && result <= NFA_LAST_NL)
+ {
+ EMIT(result - NFA_ADD_NL);
+ EMIT(NFA_NEWL);
+ EMIT(NFA_OR);
+ }
+ else
+ EMIT(result);
+ regparse = endp;
+ MB_PTR_ADV(regparse);
+ return OK;
+ }
+ /*
+ * Failed to recognize a character class. Use the simple
+ * version that turns [abc] into 'a' OR 'b' OR 'c'
+ */
+ startc = endc = oldstartc = -1;
+ negated = FALSE;
+ if (*regparse == '^') /* negated range */
+ {
+ negated = TRUE;
+ MB_PTR_ADV(regparse);
+ EMIT(NFA_START_NEG_COLL);
+ }
+ else
+ EMIT(NFA_START_COLL);
+ if (*regparse == '-')
+ {
+ startc = '-';
+ EMIT(startc);
+ EMIT(NFA_CONCAT);
+ MB_PTR_ADV(regparse);
+ }
+ /* Emit the OR branches for each character in the [] */
+ emit_range = FALSE;
+ while (regparse < endp)
+ {
+ oldstartc = startc;
+ startc = -1;
+ got_coll_char = FALSE;
+ if (*regparse == '[')
+ {
+ /* Check for [: :], [= =], [. .] */
+ equiclass = collclass = 0;
+ charclass = get_char_class(&regparse);
+ if (charclass == CLASS_NONE)
+ {
+ equiclass = get_equi_class(&regparse);
+ if (equiclass == 0)
+ collclass = get_coll_element(&regparse);
+ }
+
+ /* Character class like [:alpha:] */
+ if (charclass != CLASS_NONE)
+ {
+ switch (charclass)
+ {
+ case CLASS_ALNUM:
+ EMIT(NFA_CLASS_ALNUM);
+ break;
+ case CLASS_ALPHA:
+ EMIT(NFA_CLASS_ALPHA);
+ break;
+ case CLASS_BLANK:
+ EMIT(NFA_CLASS_BLANK);
+ break;
+ case CLASS_CNTRL:
+ EMIT(NFA_CLASS_CNTRL);
+ break;
+ case CLASS_DIGIT:
+ EMIT(NFA_CLASS_DIGIT);
+ break;
+ case CLASS_GRAPH:
+ EMIT(NFA_CLASS_GRAPH);
+ break;
+ case CLASS_LOWER:
+ EMIT(NFA_CLASS_LOWER);
+ break;
+ case CLASS_PRINT:
+ EMIT(NFA_CLASS_PRINT);
+ break;
+ case CLASS_PUNCT:
+ EMIT(NFA_CLASS_PUNCT);
+ break;
+ case CLASS_SPACE:
+ EMIT(NFA_CLASS_SPACE);
+ break;
+ case CLASS_UPPER:
+ EMIT(NFA_CLASS_UPPER);
+ break;
+ case CLASS_XDIGIT:
+ EMIT(NFA_CLASS_XDIGIT);
+ break;
+ case CLASS_TAB:
+ EMIT(NFA_CLASS_TAB);
+ break;
+ case CLASS_RETURN:
+ EMIT(NFA_CLASS_RETURN);
+ break;
+ case CLASS_BACKSPACE:
+ EMIT(NFA_CLASS_BACKSPACE);
+ break;
+ case CLASS_ESCAPE:
+ EMIT(NFA_CLASS_ESCAPE);
+ break;
+ case CLASS_IDENT:
+ EMIT(NFA_CLASS_IDENT);
+ break;
+ case CLASS_KEYWORD:
+ EMIT(NFA_CLASS_KEYWORD);
+ break;
+ case CLASS_FNAME:
+ EMIT(NFA_CLASS_FNAME);
+ break;
+ }
+ EMIT(NFA_CONCAT);
+ continue;
+ }
+ /* Try equivalence class [=a=] and the like */
+ if (equiclass != 0)
+ {
+ result = nfa_emit_equi_class(equiclass);
+ if (result == FAIL)
+ {
+ /* should never happen */
+ EMSG_RET_FAIL(_("E868: Error building NFA with equivalence class!"));
+ }
+ continue;
+ }
+ /* Try collating class like [. .] */
+ if (collclass != 0)
+ {
+ startc = collclass; /* allow [.a.]-x as a range */
+ /* Will emit the proper atom at the end of the
+ * while loop. */
+ }
+ }
+ /* Try a range like 'a-x' or '\t-z'. Also allows '-' as a
+ * start character. */
+ if (*regparse == '-' && oldstartc != -1)
+ {
+ emit_range = TRUE;
+ startc = oldstartc;
+ MB_PTR_ADV(regparse);
+ continue; /* reading the end of the range */
+ }
+
+ /* Now handle simple and escaped characters.
+ * Only "\]", "\^", "\]" and "\\" are special in Vi. Vim
+ * accepts "\t", "\e", etc., but only when the 'l' flag in
+ * 'cpoptions' is not included.
+ * Posix doesn't recognize backslash at all.
+ */
+ if (*regparse == '\\'
+ && !reg_cpo_bsl
+ && regparse + 1 <= endp
+ && (vim_strchr(REGEXP_INRANGE, regparse[1]) != NULL
+ || (!reg_cpo_lit
+ && vim_strchr(REGEXP_ABBR, regparse[1])
+ != NULL)
+ )
+ )
+ {
+ MB_PTR_ADV(regparse);
+
+ if (*regparse == 'n')
+ startc = reg_string ? NL : NFA_NEWL;
+ else
+ if (*regparse == 'd'
+ || *regparse == 'o'
+ || *regparse == 'x'
+ || *regparse == 'u'
+ || *regparse == 'U'
+ )
+ {
+ /* TODO(RE) This needs more testing */
+ startc = coll_get_char();
+ got_coll_char = TRUE;
+ MB_PTR_BACK(old_regparse, regparse);
+ }
+ else
+ {
+ /* \r,\t,\e,\b */
+ startc = backslash_trans(*regparse);
+ }
+ }
+
+ /* Normal printable char */
+ if (startc == -1)
+ startc = PTR2CHAR(regparse);
+
+ /* Previous char was '-', so this char is end of range. */
+ if (emit_range)
+ {
+ endc = startc;
+ startc = oldstartc;
+ if (startc > endc)
+ EMSG_RET_FAIL(_(e_reverse_range));
+
+ if (endc > startc + 2)
+ {
+ /* Emit a range instead of the sequence of
+ * individual characters. */
+ if (startc == 0)
+ /* \x00 is translated to \x0a, start at \x01. */
+ EMIT(1);
+ else
+ --post_ptr; /* remove NFA_CONCAT */
+ EMIT(endc);
+ EMIT(NFA_RANGE);
+ EMIT(NFA_CONCAT);
+ }
+ else if (has_mbyte && ((*mb_char2len)(startc) > 1
+ || (*mb_char2len)(endc) > 1))
+ {
+ /* Emit the characters in the range.
+ * "startc" was already emitted, so skip it.
+ * */
+ for (c = startc + 1; c <= endc; c++)
+ {
+ EMIT(c);
+ EMIT(NFA_CONCAT);
+ }
+ }
+ else
+ {
+#ifdef EBCDIC
+ int alpha_only = FALSE;
+
+ /* for alphabetical range skip the gaps
+ * 'i'-'j', 'r'-'s', 'I'-'J' and 'R'-'S'. */
+ if (isalpha(startc) && isalpha(endc))
+ alpha_only = TRUE;
+#endif
+ /* Emit the range. "startc" was already emitted, so
+ * skip it. */
+ for (c = startc + 1; c <= endc; c++)
+#ifdef EBCDIC
+ if (!alpha_only || isalpha(startc))
+#endif
+ {
+ EMIT(c);
+ EMIT(NFA_CONCAT);
+ }
+ }
+ emit_range = FALSE;
+ startc = -1;
+ }
+ else
+ {
+ /* This char (startc) is not part of a range. Just
+ * emit it.
+ * Normally, simply emit startc. But if we get char
+ * code=0 from a collating char, then replace it with
+ * 0x0a.
+ * This is needed to completely mimic the behaviour of
+ * the backtracking engine. */
+ if (startc == NFA_NEWL)
+ {
+ /* Line break can't be matched as part of the
+ * collection, add an OR below. But not for negated
+ * range. */
+ if (!negated)
+ extra = NFA_ADD_NL;
+ }
+ else
+ {
+ if (got_coll_char == TRUE && startc == 0)
+ EMIT(0x0a);
+ else
+ EMIT(startc);
+ EMIT(NFA_CONCAT);
+ }
+ }
+
+ MB_PTR_ADV(regparse);
+ } /* while (p < endp) */
+
+ MB_PTR_BACK(old_regparse, regparse);
+ if (*regparse == '-') /* if last, '-' is just a char */
+ {
+ EMIT('-');
+ EMIT(NFA_CONCAT);
+ }
+
+ /* skip the trailing ] */
+ regparse = endp;
+ MB_PTR_ADV(regparse);
+
+ /* Mark end of the collection. */
+ if (negated == TRUE)
+ EMIT(NFA_END_NEG_COLL);
+ else
+ EMIT(NFA_END_COLL);
+
+ /* \_[] also matches \n but it's not negated */
+ if (extra == NFA_ADD_NL)
+ {
+ EMIT(reg_string ? NL : NFA_NEWL);
+ EMIT(NFA_OR);
+ }
+
+ return OK;
+ } /* if exists closing ] */
+
+ if (reg_strict)
+ EMSG_RET_FAIL(_(e_missingbracket));
+ /* FALLTHROUGH */
+
+ default:
+ {
+ int plen;
+
+nfa_do_multibyte:
+ /* plen is length of current char with composing chars */
+ if (enc_utf8 && ((*mb_char2len)(c)
+ != (plen = utfc_ptr2len(old_regparse))
+ || utf_iscomposing(c)))
+ {
+ int i = 0;
+
+ /* A base character plus composing characters, or just one
+ * or more composing characters.
+ * This requires creating a separate atom as if enclosing
+ * the characters in (), where NFA_COMPOSING is the ( and
+ * NFA_END_COMPOSING is the ). Note that right now we are
+ * building the postfix form, not the NFA itself;
+ * a composing char could be: a, b, c, NFA_COMPOSING
+ * where 'b' and 'c' are chars with codes > 256. */
+ for (;;)
+ {
+ EMIT(c);
+ if (i > 0)
+ EMIT(NFA_CONCAT);
+ if ((i += utf_char2len(c)) >= plen)
+ break;
+ c = utf_ptr2char(old_regparse + i);
+ }
+ EMIT(NFA_COMPOSING);
+ regparse = old_regparse + plen;
+ }
+ else
+ {
+ c = no_Magic(c);
+ EMIT(c);
+ }
+ return OK;
+ }
+ }
+
+ return OK;
+}
+
+/*
+ * Parse something followed by possible [*+=].
+ *
+ * A piece is an atom, possibly followed by a multi, an indication of how many
+ * times the atom can be matched. Example: "a*" matches any sequence of "a"
+ * characters: "", "a", "aa", etc.
+ *
+ * piece ::= atom
+ * or atom multi
+ */
+ static int
+nfa_regpiece(void)
+{
+ int i;
+ int op;
+ int ret;
+ long minval, maxval;
+ int greedy = TRUE; /* Braces are prefixed with '-' ? */
+ parse_state_T old_state;
+ parse_state_T new_state;
+ long c2;
+ int old_post_pos;
+ int my_post_start;
+ int quest;
+
+ /* Save the current parse state, so that we can use it if <atom>{m,n} is
+ * next. */
+ save_parse_state(&old_state);
+
+ /* store current pos in the postfix form, for \{m,n} involving 0s */
+ my_post_start = (int)(post_ptr - post_start);
+
+ ret = nfa_regatom();
+ if (ret == FAIL)
+ return FAIL; /* cascaded error */
+
+ op = peekchr();
+ if (re_multi_type(op) == NOT_MULTI)
+ return OK;
+
+ skipchr();
+ switch (op)
+ {
+ case Magic('*'):
+ EMIT(NFA_STAR);
+ break;
+
+ case Magic('+'):
+ /*
+ * Trick: Normally, (a*)\+ would match the whole input "aaa". The
+ * first and only submatch would be "aaa". But the backtracking
+ * engine interprets the plus as "try matching one more time", and
+ * a* matches a second time at the end of the input, the empty
+ * string.
+ * The submatch will be the empty string.
+ *
+ * In order to be consistent with the old engine, we replace
+ * <atom>+ with <atom><atom>*
+ */
+ restore_parse_state(&old_state);
+ curchr = -1;
+ if (nfa_regatom() == FAIL)
+ return FAIL;
+ EMIT(NFA_STAR);
+ EMIT(NFA_CONCAT);
+ skipchr(); /* skip the \+ */
+ break;
+
+ case Magic('@'):
+ c2 = getdecchrs();
+ op = no_Magic(getchr());
+ i = 0;
+ switch(op)
+ {
+ case '=':
+ /* \@= */
+ i = NFA_PREV_ATOM_NO_WIDTH;
+ break;
+ case '!':
+ /* \@! */
+ i = NFA_PREV_ATOM_NO_WIDTH_NEG;
+ break;
+ case '<':
+ op = no_Magic(getchr());
+ if (op == '=')
+ /* \@<= */
+ i = NFA_PREV_ATOM_JUST_BEFORE;
+ else if (op == '!')
+ /* \@<! */
+ i = NFA_PREV_ATOM_JUST_BEFORE_NEG;
+ break;
+ case '>':
+ /* \@> */
+ i = NFA_PREV_ATOM_LIKE_PATTERN;
+ break;
+ }
+ if (i == 0)
+ {
+ semsg(_("E869: (NFA) Unknown operator '\\@%c'"), op);
+ return FAIL;
+ }
+ EMIT(i);
+ if (i == NFA_PREV_ATOM_JUST_BEFORE
+ || i == NFA_PREV_ATOM_JUST_BEFORE_NEG)
+ EMIT(c2);
+ break;
+
+ case Magic('?'):
+ case Magic('='):
+ EMIT(NFA_QUEST);
+ break;
+
+ case Magic('{'):
+ /* a{2,5} will expand to 'aaa?a?a?'
+ * a{-1,3} will expand to 'aa??a??', where ?? is the nongreedy
+ * version of '?'
+ * \v(ab){2,3} will expand to '(ab)(ab)(ab)?', where all the
+ * parenthesis have the same id
+ */
+
+ greedy = TRUE;
+ c2 = peekchr();
+ if (c2 == '-' || c2 == Magic('-'))
+ {
+ skipchr();
+ greedy = FALSE;
+ }
+ if (!read_limits(&minval, &maxval))
+ EMSG_RET_FAIL(_("E870: (NFA regexp) Error reading repetition limits"));
+
+ /* <atom>{0,inf}, <atom>{0,} and <atom>{} are equivalent to
+ * <atom>* */
+ if (minval == 0 && maxval == MAX_LIMIT)
+ {
+ if (greedy) /* { { (match the braces) */
+ /* \{}, \{0,} */
+ EMIT(NFA_STAR);
+ else /* { { (match the braces) */
+ /* \{-}, \{-0,} */
+ EMIT(NFA_STAR_NONGREEDY);
+ break;
+ }
+
+ /* Special case: x{0} or x{-0} */
+ if (maxval == 0)
+ {
+ /* Ignore result of previous call to nfa_regatom() */
+ post_ptr = post_start + my_post_start;
+ /* NFA_EMPTY is 0-length and works everywhere */
+ EMIT(NFA_EMPTY);
+ return OK;
+ }
+
+ /* The engine is very inefficient (uses too many states) when the
+ * maximum is much larger than the minimum and when the maximum is
+ * large. Bail out if we can use the other engine. */
+ if ((nfa_re_flags & RE_AUTO)
+ && (maxval > 500 || maxval > minval + 200))
+ return FAIL;
+
+ /* Ignore previous call to nfa_regatom() */
+ post_ptr = post_start + my_post_start;
+ /* Save parse state after the repeated atom and the \{} */
+ save_parse_state(&new_state);
+
+ quest = (greedy == TRUE? NFA_QUEST : NFA_QUEST_NONGREEDY);
+ for (i = 0; i < maxval; i++)
+ {
+ /* Goto beginning of the repeated atom */
+ restore_parse_state(&old_state);
+ old_post_pos = (int)(post_ptr - post_start);
+ if (nfa_regatom() == FAIL)
+ return FAIL;
+ /* after "minval" times, atoms are optional */
+ if (i + 1 > minval)
+ {
+ if (maxval == MAX_LIMIT)
+ {
+ if (greedy)
+ EMIT(NFA_STAR);
+ else
+ EMIT(NFA_STAR_NONGREEDY);
+ }
+ else
+ EMIT(quest);
+ }
+ if (old_post_pos != my_post_start)
+ EMIT(NFA_CONCAT);
+ if (i + 1 > minval && maxval == MAX_LIMIT)
+ break;
+ }
+
+ /* Go to just after the repeated atom and the \{} */
+ restore_parse_state(&new_state);
+ curchr = -1;
+
+ break;
+
+
+ default:
+ break;
+ } /* end switch */
+
+ if (re_multi_type(peekchr()) != NOT_MULTI)
+ /* Can't have a multi follow a multi. */
+ EMSG_RET_FAIL(_("E871: (NFA regexp) Can't have a multi follow a multi"));
+
+ return OK;
+}
+
+/*
+ * Parse one or more pieces, concatenated. It matches a match for the
+ * first piece, followed by a match for the second piece, etc. Example:
+ * "f[0-9]b", first matches "f", then a digit and then "b".
+ *
+ * concat ::= piece
+ * or piece piece
+ * or piece piece piece
+ * etc.
+ */
+ static int
+nfa_regconcat(void)
+{
+ int cont = TRUE;
+ int first = TRUE;
+
+ while (cont)
+ {
+ switch (peekchr())
+ {
+ case NUL:
+ case Magic('|'):
+ case Magic('&'):
+ case Magic(')'):
+ cont = FALSE;
+ break;
+
+ case Magic('Z'):
+ regflags |= RF_ICOMBINE;
+ skipchr_keepstart();
+ break;
+ case Magic('c'):
+ regflags |= RF_ICASE;
+ skipchr_keepstart();
+ break;
+ case Magic('C'):
+ regflags |= RF_NOICASE;
+ skipchr_keepstart();
+ break;
+ case Magic('v'):
+ reg_magic = MAGIC_ALL;
+ skipchr_keepstart();
+ curchr = -1;
+ break;
+ case Magic('m'):
+ reg_magic = MAGIC_ON;
+ skipchr_keepstart();
+ curchr = -1;
+ break;
+ case Magic('M'):
+ reg_magic = MAGIC_OFF;
+ skipchr_keepstart();
+ curchr = -1;
+ break;
+ case Magic('V'):
+ reg_magic = MAGIC_NONE;
+ skipchr_keepstart();
+ curchr = -1;
+ break;
+
+ default:
+ if (nfa_regpiece() == FAIL)
+ return FAIL;
+ if (first == FALSE)
+ EMIT(NFA_CONCAT);
+ else
+ first = FALSE;
+ break;
+ }
+ }
+
+ return OK;
+}
+
+/*
+ * Parse a branch, one or more concats, separated by "\&". It matches the
+ * last concat, but only if all the preceding concats also match at the same
+ * position. Examples:
+ * "foobeep\&..." matches "foo" in "foobeep".
+ * ".*Peter\&.*Bob" matches in a line containing both "Peter" and "Bob"
+ *
+ * branch ::= concat
+ * or concat \& concat
+ * or concat \& concat \& concat
+ * etc.
+ */
+ static int
+nfa_regbranch(void)
+{
+ int old_post_pos;
+
+ old_post_pos = (int)(post_ptr - post_start);
+
+ /* First branch, possibly the only one */
+ if (nfa_regconcat() == FAIL)
+ return FAIL;
+
+ /* Try next concats */
+ while (peekchr() == Magic('&'))
+ {
+ skipchr();
+ /* if concat is empty do emit a node */
+ if (old_post_pos == (int)(post_ptr - post_start))
+ EMIT(NFA_EMPTY);
+ EMIT(NFA_NOPEN);
+ EMIT(NFA_PREV_ATOM_NO_WIDTH);
+ old_post_pos = (int)(post_ptr - post_start);
+ if (nfa_regconcat() == FAIL)
+ return FAIL;
+ /* if concat is empty do emit a node */
+ if (old_post_pos == (int)(post_ptr - post_start))
+ EMIT(NFA_EMPTY);
+ EMIT(NFA_CONCAT);
+ }
+
+ /* if a branch is empty, emit one node for it */
+ if (old_post_pos == (int)(post_ptr - post_start))
+ EMIT(NFA_EMPTY);
+
+ return OK;
+}
+
+/*
+ * Parse a pattern, one or more branches, separated by "\|". It matches
+ * anything that matches one of the branches. Example: "foo\|beep" matches
+ * "foo" and matches "beep". If more than one branch matches, the first one
+ * is used.
+ *
+ * pattern ::= branch
+ * or branch \| branch
+ * or branch \| branch \| branch
+ * etc.
+ */
+ static int
+nfa_reg(
+ int paren) /* REG_NOPAREN, REG_PAREN, REG_NPAREN or REG_ZPAREN */
+{
+ int parno = 0;
+
+ if (paren == REG_PAREN)
+ {
+ if (regnpar >= NSUBEXP) /* Too many `(' */
+ EMSG_RET_FAIL(_("E872: (NFA regexp) Too many '('"));
+ parno = regnpar++;
+ }
+#ifdef FEAT_SYN_HL
+ else if (paren == REG_ZPAREN)
+ {
+ /* Make a ZOPEN node. */
+ if (regnzpar >= NSUBEXP)
+ EMSG_RET_FAIL(_("E879: (NFA regexp) Too many \\z("));
+ parno = regnzpar++;
+ }
+#endif
+
+ if (nfa_regbranch() == FAIL)
+ return FAIL; /* cascaded error */
+
+ while (peekchr() == Magic('|'))
+ {
+ skipchr();
+ if (nfa_regbranch() == FAIL)
+ return FAIL; /* cascaded error */
+ EMIT(NFA_OR);
+ }
+
+ /* Check for proper termination. */
+ if (paren != REG_NOPAREN && getchr() != Magic(')'))
+ {
+ if (paren == REG_NPAREN)
+ EMSG2_RET_FAIL(_(e_unmatchedpp), reg_magic == MAGIC_ALL);
+ else
+ EMSG2_RET_FAIL(_(e_unmatchedp), reg_magic == MAGIC_ALL);
+ }
+ else if (paren == REG_NOPAREN && peekchr() != NUL)
+ {
+ if (peekchr() == Magic(')'))
+ EMSG2_RET_FAIL(_(e_unmatchedpar), reg_magic == MAGIC_ALL);
+ else
+ EMSG_RET_FAIL(_("E873: (NFA regexp) proper termination error"));
+ }
+ /*
+ * Here we set the flag allowing back references to this set of
+ * parentheses.
+ */
+ if (paren == REG_PAREN)
+ {
+ had_endbrace[parno] = TRUE; /* have seen the close paren */
+ EMIT(NFA_MOPEN + parno);
+ }
+#ifdef FEAT_SYN_HL
+ else if (paren == REG_ZPAREN)
+ EMIT(NFA_ZOPEN + parno);
+#endif
+
+ return OK;
+}
+
+#ifdef DEBUG
+static char_u code[50];
+
+ static void
+nfa_set_code(int c)
+{
+ int addnl = FALSE;
+
+ if (c >= NFA_FIRST_NL && c <= NFA_LAST_NL)
+ {
+ addnl = TRUE;
+ c -= NFA_ADD_NL;
+ }
+
+ STRCPY(code, "");
+ switch (c)
+ {
+ case NFA_MATCH: STRCPY(code, "NFA_MATCH "); break;
+ case NFA_SPLIT: STRCPY(code, "NFA_SPLIT "); break;
+ case NFA_CONCAT: STRCPY(code, "NFA_CONCAT "); break;
+ case NFA_NEWL: STRCPY(code, "NFA_NEWL "); break;
+ case NFA_ZSTART: STRCPY(code, "NFA_ZSTART"); break;
+ case NFA_ZEND: STRCPY(code, "NFA_ZEND"); break;
+
+ case NFA_BACKREF1: STRCPY(code, "NFA_BACKREF1"); break;
+ case NFA_BACKREF2: STRCPY(code, "NFA_BACKREF2"); break;
+ case NFA_BACKREF3: STRCPY(code, "NFA_BACKREF3"); break;
+ case NFA_BACKREF4: STRCPY(code, "NFA_BACKREF4"); break;
+ case NFA_BACKREF5: STRCPY(code, "NFA_BACKREF5"); break;
+ case NFA_BACKREF6: STRCPY(code, "NFA_BACKREF6"); break;
+ case NFA_BACKREF7: STRCPY(code, "NFA_BACKREF7"); break;
+ case NFA_BACKREF8: STRCPY(code, "NFA_BACKREF8"); break;
+ case NFA_BACKREF9: STRCPY(code, "NFA_BACKREF9"); break;
+#ifdef FEAT_SYN_HL
+ case NFA_ZREF1: STRCPY(code, "NFA_ZREF1"); break;
+ case NFA_ZREF2: STRCPY(code, "NFA_ZREF2"); break;
+ case NFA_ZREF3: STRCPY(code, "NFA_ZREF3"); break;
+ case NFA_ZREF4: STRCPY(code, "NFA_ZREF4"); break;
+ case NFA_ZREF5: STRCPY(code, "NFA_ZREF5"); break;
+ case NFA_ZREF6: STRCPY(code, "NFA_ZREF6"); break;
+ case NFA_ZREF7: STRCPY(code, "NFA_ZREF7"); break;
+ case NFA_ZREF8: STRCPY(code, "NFA_ZREF8"); break;
+ case NFA_ZREF9: STRCPY(code, "NFA_ZREF9"); break;
+#endif
+ case NFA_SKIP: STRCPY(code, "NFA_SKIP"); break;
+
+ case NFA_PREV_ATOM_NO_WIDTH:
+ STRCPY(code, "NFA_PREV_ATOM_NO_WIDTH"); break;
+ case NFA_PREV_ATOM_NO_WIDTH_NEG:
+ STRCPY(code, "NFA_PREV_ATOM_NO_WIDTH_NEG"); break;
+ case NFA_PREV_ATOM_JUST_BEFORE:
+ STRCPY(code, "NFA_PREV_ATOM_JUST_BEFORE"); break;
+ case NFA_PREV_ATOM_JUST_BEFORE_NEG:
+ STRCPY(code, "NFA_PREV_ATOM_JUST_BEFORE_NEG"); break;
+ case NFA_PREV_ATOM_LIKE_PATTERN:
+ STRCPY(code, "NFA_PREV_ATOM_LIKE_PATTERN"); break;
+
+ case NFA_NOPEN: STRCPY(code, "NFA_NOPEN"); break;
+ case NFA_NCLOSE: STRCPY(code, "NFA_NCLOSE"); break;
+ case NFA_START_INVISIBLE: STRCPY(code, "NFA_START_INVISIBLE"); break;
+ case NFA_START_INVISIBLE_FIRST:
+ STRCPY(code, "NFA_START_INVISIBLE_FIRST"); break;
+ case NFA_START_INVISIBLE_NEG:
+ STRCPY(code, "NFA_START_INVISIBLE_NEG"); break;
+ case NFA_START_INVISIBLE_NEG_FIRST:
+ STRCPY(code, "NFA_START_INVISIBLE_NEG_FIRST"); break;
+ case NFA_START_INVISIBLE_BEFORE:
+ STRCPY(code, "NFA_START_INVISIBLE_BEFORE"); break;
+ case NFA_START_INVISIBLE_BEFORE_FIRST:
+ STRCPY(code, "NFA_START_INVISIBLE_BEFORE_FIRST"); break;
+ case NFA_START_INVISIBLE_BEFORE_NEG:
+ STRCPY(code, "NFA_START_INVISIBLE_BEFORE_NEG"); break;
+ case NFA_START_INVISIBLE_BEFORE_NEG_FIRST:
+ STRCPY(code, "NFA_START_INVISIBLE_BEFORE_NEG_FIRST"); break;
+ case NFA_START_PATTERN: STRCPY(code, "NFA_START_PATTERN"); break;
+ case NFA_END_INVISIBLE: STRCPY(code, "NFA_END_INVISIBLE"); break;
+ case NFA_END_INVISIBLE_NEG: STRCPY(code, "NFA_END_INVISIBLE_NEG"); break;
+ case NFA_END_PATTERN: STRCPY(code, "NFA_END_PATTERN"); break;
+
+ case NFA_COMPOSING: STRCPY(code, "NFA_COMPOSING"); break;
+ case NFA_END_COMPOSING: STRCPY(code, "NFA_END_COMPOSING"); break;
+ case NFA_OPT_CHARS: STRCPY(code, "NFA_OPT_CHARS"); break;
+
+ case NFA_MOPEN:
+ case NFA_MOPEN1:
+ case NFA_MOPEN2:
+ case NFA_MOPEN3:
+ case NFA_MOPEN4:
+ case NFA_MOPEN5:
+ case NFA_MOPEN6:
+ case NFA_MOPEN7:
+ case NFA_MOPEN8:
+ case NFA_MOPEN9:
+ STRCPY(code, "NFA_MOPEN(x)");
+ code[10] = c - NFA_MOPEN + '0';
+ break;
+ case NFA_MCLOSE:
+ case NFA_MCLOSE1:
+ case NFA_MCLOSE2:
+ case NFA_MCLOSE3:
+ case NFA_MCLOSE4:
+ case NFA_MCLOSE5:
+ case NFA_MCLOSE6:
+ case NFA_MCLOSE7:
+ case NFA_MCLOSE8:
+ case NFA_MCLOSE9:
+ STRCPY(code, "NFA_MCLOSE(x)");
+ code[11] = c - NFA_MCLOSE + '0';
+ break;
+#ifdef FEAT_SYN_HL
+ case NFA_ZOPEN:
+ case NFA_ZOPEN1:
+ case NFA_ZOPEN2:
+ case NFA_ZOPEN3:
+ case NFA_ZOPEN4:
+ case NFA_ZOPEN5:
+ case NFA_ZOPEN6:
+ case NFA_ZOPEN7:
+ case NFA_ZOPEN8:
+ case NFA_ZOPEN9:
+ STRCPY(code, "NFA_ZOPEN(x)");
+ code[10] = c - NFA_ZOPEN + '0';
+ break;
+ case NFA_ZCLOSE:
+ case NFA_ZCLOSE1:
+ case NFA_ZCLOSE2:
+ case NFA_ZCLOSE3:
+ case NFA_ZCLOSE4:
+ case NFA_ZCLOSE5:
+ case NFA_ZCLOSE6:
+ case NFA_ZCLOSE7:
+ case NFA_ZCLOSE8:
+ case NFA_ZCLOSE9:
+ STRCPY(code, "NFA_ZCLOSE(x)");
+ code[11] = c - NFA_ZCLOSE + '0';
+ break;
+#endif
+ case NFA_EOL: STRCPY(code, "NFA_EOL "); break;
+ case NFA_BOL: STRCPY(code, "NFA_BOL "); break;
+ case NFA_EOW: STRCPY(code, "NFA_EOW "); break;
+ case NFA_BOW: STRCPY(code, "NFA_BOW "); break;
+ case NFA_EOF: STRCPY(code, "NFA_EOF "); break;
+ case NFA_BOF: STRCPY(code, "NFA_BOF "); break;
+ case NFA_LNUM: STRCPY(code, "NFA_LNUM "); break;
+ case NFA_LNUM_GT: STRCPY(code, "NFA_LNUM_GT "); break;
+ case NFA_LNUM_LT: STRCPY(code, "NFA_LNUM_LT "); break;
+ case NFA_COL: STRCPY(code, "NFA_COL "); break;
+ case NFA_COL_GT: STRCPY(code, "NFA_COL_GT "); break;
+ case NFA_COL_LT: STRCPY(code, "NFA_COL_LT "); break;
+ case NFA_VCOL: STRCPY(code, "NFA_VCOL "); break;
+ case NFA_VCOL_GT: STRCPY(code, "NFA_VCOL_GT "); break;
+ case NFA_VCOL_LT: STRCPY(code, "NFA_VCOL_LT "); break;
+ case NFA_MARK: STRCPY(code, "NFA_MARK "); break;
+ case NFA_MARK_GT: STRCPY(code, "NFA_MARK_GT "); break;
+ case NFA_MARK_LT: STRCPY(code, "NFA_MARK_LT "); break;
+ case NFA_CURSOR: STRCPY(code, "NFA_CURSOR "); break;
+ case NFA_VISUAL: STRCPY(code, "NFA_VISUAL "); break;
+ case NFA_ANY_COMPOSING: STRCPY(code, "NFA_ANY_COMPOSING "); break;
+
+ case NFA_STAR: STRCPY(code, "NFA_STAR "); break;
+ case NFA_STAR_NONGREEDY: STRCPY(code, "NFA_STAR_NONGREEDY "); break;
+ case NFA_QUEST: STRCPY(code, "NFA_QUEST"); break;
+ case NFA_QUEST_NONGREEDY: STRCPY(code, "NFA_QUEST_NON_GREEDY"); break;
+ case NFA_EMPTY: STRCPY(code, "NFA_EMPTY"); break;
+ case NFA_OR: STRCPY(code, "NFA_OR"); break;
+
+ case NFA_START_COLL: STRCPY(code, "NFA_START_COLL"); break;
+ case NFA_END_COLL: STRCPY(code, "NFA_END_COLL"); break;
+ case NFA_START_NEG_COLL: STRCPY(code, "NFA_START_NEG_COLL"); break;
+ case NFA_END_NEG_COLL: STRCPY(code, "NFA_END_NEG_COLL"); break;
+ case NFA_RANGE: STRCPY(code, "NFA_RANGE"); break;
+ case NFA_RANGE_MIN: STRCPY(code, "NFA_RANGE_MIN"); break;
+ case NFA_RANGE_MAX: STRCPY(code, "NFA_RANGE_MAX"); break;
+
+ case NFA_CLASS_ALNUM: STRCPY(code, "NFA_CLASS_ALNUM"); break;
+ case NFA_CLASS_ALPHA: STRCPY(code, "NFA_CLASS_ALPHA"); break;
+ case NFA_CLASS_BLANK: STRCPY(code, "NFA_CLASS_BLANK"); break;
+ case NFA_CLASS_CNTRL: STRCPY(code, "NFA_CLASS_CNTRL"); break;
+ case NFA_CLASS_DIGIT: STRCPY(code, "NFA_CLASS_DIGIT"); break;
+ case NFA_CLASS_GRAPH: STRCPY(code, "NFA_CLASS_GRAPH"); break;
+ case NFA_CLASS_LOWER: STRCPY(code, "NFA_CLASS_LOWER"); break;
+ case NFA_CLASS_PRINT: STRCPY(code, "NFA_CLASS_PRINT"); break;
+ case NFA_CLASS_PUNCT: STRCPY(code, "NFA_CLASS_PUNCT"); break;
+ case NFA_CLASS_SPACE: STRCPY(code, "NFA_CLASS_SPACE"); break;
+ case NFA_CLASS_UPPER: STRCPY(code, "NFA_CLASS_UPPER"); break;
+ case NFA_CLASS_XDIGIT: STRCPY(code, "NFA_CLASS_XDIGIT"); break;
+ case NFA_CLASS_TAB: STRCPY(code, "NFA_CLASS_TAB"); break;
+ case NFA_CLASS_RETURN: STRCPY(code, "NFA_CLASS_RETURN"); break;
+ case NFA_CLASS_BACKSPACE: STRCPY(code, "NFA_CLASS_BACKSPACE"); break;
+ case NFA_CLASS_ESCAPE: STRCPY(code, "NFA_CLASS_ESCAPE"); break;
+ case NFA_CLASS_IDENT: STRCPY(code, "NFA_CLASS_IDENT"); break;
+ case NFA_CLASS_KEYWORD: STRCPY(code, "NFA_CLASS_KEYWORD"); break;
+ case NFA_CLASS_FNAME: STRCPY(code, "NFA_CLASS_FNAME"); break;
+
+ case NFA_ANY: STRCPY(code, "NFA_ANY"); break;
+ case NFA_IDENT: STRCPY(code, "NFA_IDENT"); break;
+ case NFA_SIDENT:STRCPY(code, "NFA_SIDENT"); break;
+ case NFA_KWORD: STRCPY(code, "NFA_KWORD"); break;
+ case NFA_SKWORD:STRCPY(code, "NFA_SKWORD"); break;
+ case NFA_FNAME: STRCPY(code, "NFA_FNAME"); break;
+ case NFA_SFNAME:STRCPY(code, "NFA_SFNAME"); break;
+ case NFA_PRINT: STRCPY(code, "NFA_PRINT"); break;
+ case NFA_SPRINT:STRCPY(code, "NFA_SPRINT"); break;
+ case NFA_WHITE: STRCPY(code, "NFA_WHITE"); break;
+ case NFA_NWHITE:STRCPY(code, "NFA_NWHITE"); break;
+ case NFA_DIGIT: STRCPY(code, "NFA_DIGIT"); break;
+ case NFA_NDIGIT:STRCPY(code, "NFA_NDIGIT"); break;
+ case NFA_HEX: STRCPY(code, "NFA_HEX"); break;
+ case NFA_NHEX: STRCPY(code, "NFA_NHEX"); break;
+ case NFA_OCTAL: STRCPY(code, "NFA_OCTAL"); break;
+ case NFA_NOCTAL:STRCPY(code, "NFA_NOCTAL"); break;
+ case NFA_WORD: STRCPY(code, "NFA_WORD"); break;
+ case NFA_NWORD: STRCPY(code, "NFA_NWORD"); break;
+ case NFA_HEAD: STRCPY(code, "NFA_HEAD"); break;
+ case NFA_NHEAD: STRCPY(code, "NFA_NHEAD"); break;
+ case NFA_ALPHA: STRCPY(code, "NFA_ALPHA"); break;
+ case NFA_NALPHA:STRCPY(code, "NFA_NALPHA"); break;
+ case NFA_LOWER: STRCPY(code, "NFA_LOWER"); break;
+ case NFA_NLOWER:STRCPY(code, "NFA_NLOWER"); break;
+ case NFA_UPPER: STRCPY(code, "NFA_UPPER"); break;
+ case NFA_NUPPER:STRCPY(code, "NFA_NUPPER"); break;
+ case NFA_LOWER_IC: STRCPY(code, "NFA_LOWER_IC"); break;
+ case NFA_NLOWER_IC: STRCPY(code, "NFA_NLOWER_IC"); break;
+ case NFA_UPPER_IC: STRCPY(code, "NFA_UPPER_IC"); break;
+ case NFA_NUPPER_IC: STRCPY(code, "NFA_NUPPER_IC"); break;
+
+ default:
+ STRCPY(code, "CHAR(x)");
+ code[5] = c;
+ }
+
+ if (addnl == TRUE)
+ STRCAT(code, " + NEWLINE ");
+
+}
+
+#ifdef ENABLE_LOG
+static FILE *log_fd;
+static char_u e_log_open_failed[] = N_("Could not open temporary log file for writing, displaying on stderr... ");
+
+/*
+ * Print the postfix notation of the current regexp.
+ */
+ static void
+nfa_postfix_dump(char_u *expr, int retval)
+{
+ int *p;
+ FILE *f;
+
+ f = fopen(NFA_REGEXP_DUMP_LOG, "a");
+ if (f != NULL)
+ {
+ fprintf(f, "\n-------------------------\n");
+ if (retval == FAIL)
+ fprintf(f, ">>> NFA engine failed... \n");
+ else if (retval == OK)
+ fprintf(f, ">>> NFA engine succeeded !\n");
+ fprintf(f, "Regexp: \"%s\"\nPostfix notation (char): \"", expr);
+ for (p = post_start; *p && p < post_ptr; p++)
+ {
+ nfa_set_code(*p);
+ fprintf(f, "%s, ", code);
+ }
+ fprintf(f, "\"\nPostfix notation (int): ");
+ for (p = post_start; *p && p < post_ptr; p++)
+ fprintf(f, "%d ", *p);
+ fprintf(f, "\n\n");
+ fclose(f);
+ }
+}
+
+/*
+ * Print the NFA starting with a root node "state".
+ */
+ static void
+nfa_print_state(FILE *debugf, nfa_state_T *state)
+{
+ garray_T indent;
+
+ ga_init2(&indent, 1, 64);
+ ga_append(&indent, '\0');
+ nfa_print_state2(debugf, state, &indent);
+ ga_clear(&indent);
+}
+
+ static void
+nfa_print_state2(FILE *debugf, nfa_state_T *state, garray_T *indent)
+{
+ char_u *p;
+
+ if (state == NULL)
+ return;
+
+ fprintf(debugf, "(%2d)", abs(state->id));
+
+ /* Output indent */
+ p = (char_u *)indent->ga_data;
+ if (indent->ga_len >= 3)
+ {
+ int last = indent->ga_len - 3;
+ char_u save[2];
+
+ STRNCPY(save, &p[last], 2);
+ STRNCPY(&p[last], "+-", 2);
+ fprintf(debugf, " %s", p);
+ STRNCPY(&p[last], save, 2);
+ }
+ else
+ fprintf(debugf, " %s", p);
+
+ nfa_set_code(state->c);
+ fprintf(debugf, "%s (%d) (id=%d) val=%d\n",
+ code,
+ state->c,
+ abs(state->id),
+ state->val);
+ if (state->id < 0)
+ return;
+
+ state->id = abs(state->id) * -1;
+
+ /* grow indent for state->out */
+ indent->ga_len -= 1;
+ if (state->out1)
+ ga_concat(indent, (char_u *)"| ");
+ else
+ ga_concat(indent, (char_u *)" ");
+ ga_append(indent, '\0');
+
+ nfa_print_state2(debugf, state->out, indent);
+
+ /* replace last part of indent for state->out1 */
+ indent->ga_len -= 3;
+ ga_concat(indent, (char_u *)" ");
+ ga_append(indent, '\0');
+
+ nfa_print_state2(debugf, state->out1, indent);
+
+ /* shrink indent */
+ indent->ga_len -= 3;
+ ga_append(indent, '\0');
+}
+
+/*
+ * Print the NFA state machine.
+ */
+ static void
+nfa_dump(nfa_regprog_T *prog)
+{
+ FILE *debugf = fopen(NFA_REGEXP_DUMP_LOG, "a");
+
+ if (debugf != NULL)
+ {
+ nfa_print_state(debugf, prog->start);
+
+ if (prog->reganch)
+ fprintf(debugf, "reganch: %d\n", prog->reganch);
+ if (prog->regstart != NUL)
+ fprintf(debugf, "regstart: %c (decimal: %d)\n",
+ prog->regstart, prog->regstart);
+ if (prog->match_text != NULL)
+ fprintf(debugf, "match_text: \"%s\"\n", prog->match_text);
+
+ fclose(debugf);
+ }
+}
+#endif /* ENABLE_LOG */
+#endif /* DEBUG */
+
+/*
+ * Parse r.e. @expr and convert it into postfix form.
+ * Return the postfix string on success, NULL otherwise.
+ */
+ static int *
+re2post(void)
+{
+ if (nfa_reg(REG_NOPAREN) == FAIL)
+ return NULL;
+ EMIT(NFA_MOPEN);
+ return post_start;
+}
+
+/* NB. Some of the code below is inspired by Russ's. */
+
+/*
+ * Represents an NFA state plus zero or one or two arrows exiting.
+ * if c == MATCH, no arrows out; matching state.
+ * If c == SPLIT, unlabeled arrows to out and out1 (if != NULL).
+ * If c < 256, labeled arrow with character c to out.
+ */
+
+static nfa_state_T *state_ptr; /* points to nfa_prog->state */
+
+/*
+ * Allocate and initialize nfa_state_T.
+ */
+ static nfa_state_T *
+alloc_state(int c, nfa_state_T *out, nfa_state_T *out1)
+{
+ nfa_state_T *s;
+
+ if (istate >= nstate)
+ return NULL;
+
+ s = &state_ptr[istate++];
+
+ s->c = c;
+ s->out = out;
+ s->out1 = out1;
+ s->val = 0;
+
+ s->id = istate;
+ s->lastlist[0] = 0;
+ s->lastlist[1] = 0;
+
+ return s;
+}
+
+/*
+ * A partially built NFA without the matching state filled in.
+ * Frag_T.start points at the start state.
+ * Frag_T.out is a list of places that need to be set to the
+ * next state for this fragment.
+ */
+
+/* Since the out pointers in the list are always
+ * uninitialized, we use the pointers themselves
+ * as storage for the Ptrlists. */
+typedef union Ptrlist Ptrlist;
+union Ptrlist
+{
+ Ptrlist *next;
+ nfa_state_T *s;
+};
+
+struct Frag
+{
+ nfa_state_T *start;
+ Ptrlist *out;
+};
+typedef struct Frag Frag_T;
+
+/*
+ * Initialize a Frag_T struct and return it.
+ */
+ static Frag_T
+frag(nfa_state_T *start, Ptrlist *out)
+{
+ Frag_T n;
+
+ n.start = start;
+ n.out = out;
+ return n;
+}
+
+/*
+ * Create singleton list containing just outp.
+ */
+ static Ptrlist *
+list1(
+ nfa_state_T **outp)
+{
+ Ptrlist *l;
+
+ l = (Ptrlist *)outp;
+ l->next = NULL;
+ return l;
+}
+
+/*
+ * Patch the list of states at out to point to start.
+ */
+ static void
+patch(Ptrlist *l, nfa_state_T *s)
+{
+ Ptrlist *next;
+
+ for (; l; l = next)
+ {
+ next = l->next;
+ l->s = s;
+ }
+}
+
+
+/*
+ * Join the two lists l1 and l2, returning the combination.
+ */
+ static Ptrlist *
+append(Ptrlist *l1, Ptrlist *l2)
+{
+ Ptrlist *oldl1;
+
+ oldl1 = l1;
+ while (l1->next)
+ l1 = l1->next;
+ l1->next = l2;
+ return oldl1;
+}
+
+/*
+ * Stack used for transforming postfix form into NFA.
+ */
+static Frag_T empty;
+
+ static void
+st_error(int *postfix UNUSED, int *end UNUSED, int *p UNUSED)
+{
+#ifdef NFA_REGEXP_ERROR_LOG
+ FILE *df;
+ int *p2;
+
+ df = fopen(NFA_REGEXP_ERROR_LOG, "a");
+ if (df)
+ {
+ fprintf(df, "Error popping the stack!\n");
+# ifdef DEBUG
+ fprintf(df, "Current regexp is \"%s\"\n", nfa_regengine.expr);
+# endif
+ fprintf(df, "Postfix form is: ");
+# ifdef DEBUG
+ for (p2 = postfix; p2 < end; p2++)
+ {
+ nfa_set_code(*p2);
+ fprintf(df, "%s, ", code);
+ }
+ nfa_set_code(*p);
+ fprintf(df, "\nCurrent position is: ");
+ for (p2 = postfix; p2 <= p; p2 ++)
+ {
+ nfa_set_code(*p2);
+ fprintf(df, "%s, ", code);
+ }
+# else
+ for (p2 = postfix; p2 < end; p2++)
+ {
+ fprintf(df, "%d, ", *p2);
+ }
+ fprintf(df, "\nCurrent position is: ");
+ for (p2 = postfix; p2 <= p; p2 ++)
+ {
+ fprintf(df, "%d, ", *p2);
+ }
+# endif
+ fprintf(df, "\n--------------------------\n");
+ fclose(df);
+ }
+#endif
+ emsg(_("E874: (NFA) Could not pop the stack!"));
+}
+
+/*
+ * Push an item onto the stack.
+ */
+ static void
+st_push(Frag_T s, Frag_T **p, Frag_T *stack_end)
+{
+ Frag_T *stackp = *p;
+
+ if (stackp >= stack_end)
+ return;
+ *stackp = s;
+ *p = *p + 1;
+}
+
+/*
+ * Pop an item from the stack.
+ */
+ static Frag_T
+st_pop(Frag_T **p, Frag_T *stack)
+{
+ Frag_T *stackp;
+
+ *p = *p - 1;
+ stackp = *p;
+ if (stackp < stack)
+ return empty;
+ return **p;
+}
+
+/*
+ * Estimate the maximum byte length of anything matching "state".
+ * When unknown or unlimited return -1.
+ */
+ static int
+nfa_max_width(nfa_state_T *startstate, int depth)
+{
+ int l, r;
+ nfa_state_T *state = startstate;
+ int len = 0;
+
+ /* detect looping in a NFA_SPLIT */
+ if (depth > 4)
+ return -1;
+
+ while (state != NULL)
+ {
+ switch (state->c)
+ {
+ case NFA_END_INVISIBLE:
+ case NFA_END_INVISIBLE_NEG:
+ /* the end, return what we have */
+ return len;
+
+ case NFA_SPLIT:
+ /* two alternatives, use the maximum */
+ l = nfa_max_width(state->out, depth + 1);
+ r = nfa_max_width(state->out1, depth + 1);
+ if (l < 0 || r < 0)
+ return -1;
+ return len + (l > r ? l : r);
+
+ case NFA_ANY:
+ case NFA_START_COLL:
+ case NFA_START_NEG_COLL:
+ /* matches some character, including composing chars */
+ if (enc_utf8)
+ len += MB_MAXBYTES;
+ else if (has_mbyte)
+ len += 2;
+ else
+ ++len;
+ if (state->c != NFA_ANY)
+ {
+ /* skip over the characters */
+ state = state->out1->out;
+ continue;
+ }
+ break;
+
+ case NFA_DIGIT:
+ case NFA_WHITE:
+ case NFA_HEX:
+ case NFA_OCTAL:
+ /* ascii */
+ ++len;
+ break;
+
+ case NFA_IDENT:
+ case NFA_SIDENT:
+ case NFA_KWORD:
+ case NFA_SKWORD:
+ case NFA_FNAME:
+ case NFA_SFNAME:
+ case NFA_PRINT:
+ case NFA_SPRINT:
+ case NFA_NWHITE:
+ case NFA_NDIGIT:
+ case NFA_NHEX:
+ case NFA_NOCTAL:
+ case NFA_WORD:
+ case NFA_NWORD:
+ case NFA_HEAD:
+ case NFA_NHEAD:
+ case NFA_ALPHA:
+ case NFA_NALPHA:
+ case NFA_LOWER:
+ case NFA_NLOWER:
+ case NFA_UPPER:
+ case NFA_NUPPER:
+ case NFA_LOWER_IC:
+ case NFA_NLOWER_IC:
+ case NFA_UPPER_IC:
+ case NFA_NUPPER_IC:
+ case NFA_ANY_COMPOSING:
+ /* possibly non-ascii */
+ if (has_mbyte)
+ len += 3;
+ else
+ ++len;
+ break;
+
+ case NFA_START_INVISIBLE:
+ case NFA_START_INVISIBLE_NEG:
+ case NFA_START_INVISIBLE_BEFORE:
+ case NFA_START_INVISIBLE_BEFORE_NEG:
+ /* zero-width, out1 points to the END state */
+ state = state->out1->out;
+ continue;
+
+ case NFA_BACKREF1:
+ case NFA_BACKREF2:
+ case NFA_BACKREF3:
+ case NFA_BACKREF4:
+ case NFA_BACKREF5:
+ case NFA_BACKREF6:
+ case NFA_BACKREF7:
+ case NFA_BACKREF8:
+ case NFA_BACKREF9:
+#ifdef FEAT_SYN_HL
+ case NFA_ZREF1:
+ case NFA_ZREF2:
+ case NFA_ZREF3:
+ case NFA_ZREF4:
+ case NFA_ZREF5:
+ case NFA_ZREF6:
+ case NFA_ZREF7:
+ case NFA_ZREF8:
+ case NFA_ZREF9:
+#endif
+ case NFA_NEWL:
+ case NFA_SKIP:
+ /* unknown width */
+ return -1;
+
+ case NFA_BOL:
+ case NFA_EOL:
+ case NFA_BOF:
+ case NFA_EOF:
+ case NFA_BOW:
+ case NFA_EOW:
+ case NFA_MOPEN:
+ case NFA_MOPEN1:
+ case NFA_MOPEN2:
+ case NFA_MOPEN3:
+ case NFA_MOPEN4:
+ case NFA_MOPEN5:
+ case NFA_MOPEN6:
+ case NFA_MOPEN7:
+ case NFA_MOPEN8:
+ case NFA_MOPEN9:
+#ifdef FEAT_SYN_HL
+ case NFA_ZOPEN:
+ case NFA_ZOPEN1:
+ case NFA_ZOPEN2:
+ case NFA_ZOPEN3:
+ case NFA_ZOPEN4:
+ case NFA_ZOPEN5:
+ case NFA_ZOPEN6:
+ case NFA_ZOPEN7:
+ case NFA_ZOPEN8:
+ case NFA_ZOPEN9:
+ case NFA_ZCLOSE:
+ case NFA_ZCLOSE1:
+ case NFA_ZCLOSE2:
+ case NFA_ZCLOSE3:
+ case NFA_ZCLOSE4:
+ case NFA_ZCLOSE5:
+ case NFA_ZCLOSE6:
+ case NFA_ZCLOSE7:
+ case NFA_ZCLOSE8:
+ case NFA_ZCLOSE9:
+#endif
+ case NFA_MCLOSE:
+ case NFA_MCLOSE1:
+ case NFA_MCLOSE2:
+ case NFA_MCLOSE3:
+ case NFA_MCLOSE4:
+ case NFA_MCLOSE5:
+ case NFA_MCLOSE6:
+ case NFA_MCLOSE7:
+ case NFA_MCLOSE8:
+ case NFA_MCLOSE9:
+ case NFA_NOPEN:
+ case NFA_NCLOSE:
+
+ case NFA_LNUM_GT:
+ case NFA_LNUM_LT:
+ case NFA_COL_GT:
+ case NFA_COL_LT:
+ case NFA_VCOL_GT:
+ case NFA_VCOL_LT:
+ case NFA_MARK_GT:
+ case NFA_MARK_LT:
+ case NFA_VISUAL:
+ case NFA_LNUM:
+ case NFA_CURSOR:
+ case NFA_COL:
+ case NFA_VCOL:
+ case NFA_MARK:
+
+ case NFA_ZSTART:
+ case NFA_ZEND:
+ case NFA_OPT_CHARS:
+ case NFA_EMPTY:
+ case NFA_START_PATTERN:
+ case NFA_END_PATTERN:
+ case NFA_COMPOSING:
+ case NFA_END_COMPOSING:
+ /* zero-width */
+ break;
+
+ default:
+ if (state->c < 0)
+ /* don't know what this is */
+ return -1;
+ /* normal character */
+ len += MB_CHAR2LEN(state->c);
+ break;
+ }
+
+ /* normal way to continue */
+ state = state->out;
+ }
+
+ /* unrecognized, "cannot happen" */
+ return -1;
+}
+
+/*
+ * Convert a postfix form into its equivalent NFA.
+ * Return the NFA start state on success, NULL otherwise.
+ */
+ static nfa_state_T *
+post2nfa(int *postfix, int *end, int nfa_calc_size)
+{
+ int *p;
+ int mopen;
+ int mclose;
+ Frag_T *stack = NULL;
+ Frag_T *stackp = NULL;
+ Frag_T *stack_end = NULL;
+ Frag_T e1;
+ Frag_T e2;
+ Frag_T e;
+ nfa_state_T *s;
+ nfa_state_T *s1;
+ nfa_state_T *matchstate;
+ nfa_state_T *ret = NULL;
+
+ if (postfix == NULL)
+ return NULL;
+
+#define PUSH(s) st_push((s), &stackp, stack_end)
+#define POP() st_pop(&stackp, stack); \
+ if (stackp < stack) \
+ { \
+ st_error(postfix, end, p); \
+ vim_free(stack); \
+ return NULL; \
+ }
+
+ if (nfa_calc_size == FALSE)
+ {
+ // Allocate space for the stack. Max states on the stack: "nstate'.
+ stack = (Frag_T *)lalloc((nstate + 1) * sizeof(Frag_T), TRUE);
+ if (stack == NULL)
+ return NULL;
+ stackp = stack;
+ stack_end = stack + (nstate + 1);
+ }
+
+ for (p = postfix; p < end; ++p)
+ {
+ switch (*p)
+ {
+ case NFA_CONCAT:
+ /* Concatenation.
+ * Pay attention: this operator does not exist in the r.e. itself
+ * (it is implicit, really). It is added when r.e. is translated
+ * to postfix form in re2post(). */
+ if (nfa_calc_size == TRUE)
+ {
+ /* nstate += 0; */
+ break;
+ }
+ e2 = POP();
+ e1 = POP();
+ patch(e1.out, e2.start);
+ PUSH(frag(e1.start, e2.out));
+ break;
+
+ case NFA_OR:
+ /* Alternation */
+ if (nfa_calc_size == TRUE)
+ {
+ nstate++;
+ break;
+ }
+ e2 = POP();
+ e1 = POP();
+ s = alloc_state(NFA_SPLIT, e1.start, e2.start);
+ if (s == NULL)
+ goto theend;
+ PUSH(frag(s, append(e1.out, e2.out)));
+ break;
+
+ case NFA_STAR:
+ /* Zero or more, prefer more */
+ if (nfa_calc_size == TRUE)
+ {
+ nstate++;
+ break;
+ }
+ e = POP();
+ s = alloc_state(NFA_SPLIT, e.start, NULL);
+ if (s == NULL)
+ goto theend;
+ patch(e.out, s);
+ PUSH(frag(s, list1(&s->out1)));
+ break;
+
+ case NFA_STAR_NONGREEDY:
+ /* Zero or more, prefer zero */
+ if (nfa_calc_size == TRUE)
+ {
+ nstate++;
+ break;
+ }
+ e = POP();
+ s = alloc_state(NFA_SPLIT, NULL, e.start);
+ if (s == NULL)
+ goto theend;
+ patch(e.out, s);
+ PUSH(frag(s, list1(&s->out)));
+ break;
+
+ case NFA_QUEST:
+ /* one or zero atoms=> greedy match */
+ if (nfa_calc_size == TRUE)
+ {
+ nstate++;
+ break;
+ }
+ e = POP();
+ s = alloc_state(NFA_SPLIT, e.start, NULL);
+ if (s == NULL)
+ goto theend;
+ PUSH(frag(s, append(e.out, list1(&s->out1))));
+ break;
+
+ case NFA_QUEST_NONGREEDY:
+ /* zero or one atoms => non-greedy match */
+ if (nfa_calc_size == TRUE)
+ {
+ nstate++;
+ break;
+ }
+ e = POP();
+ s = alloc_state(NFA_SPLIT, NULL, e.start);
+ if (s == NULL)
+ goto theend;
+ PUSH(frag(s, append(e.out, list1(&s->out))));
+ break;
+
+ case NFA_END_COLL:
+ case NFA_END_NEG_COLL:
+ /* On the stack is the sequence starting with NFA_START_COLL or
+ * NFA_START_NEG_COLL and all possible characters. Patch it to
+ * add the output to the start. */
+ if (nfa_calc_size == TRUE)
+ {
+ nstate++;
+ break;
+ }
+ e = POP();
+ s = alloc_state(NFA_END_COLL, NULL, NULL);
+ if (s == NULL)
+ goto theend;
+ patch(e.out, s);
+ e.start->out1 = s;
+ PUSH(frag(e.start, list1(&s->out)));
+ break;
+
+ case NFA_RANGE:
+ /* Before this are two characters, the low and high end of a
+ * range. Turn them into two states with MIN and MAX. */
+ if (nfa_calc_size == TRUE)
+ {
+ /* nstate += 0; */
+ break;
+ }
+ e2 = POP();
+ e1 = POP();
+ e2.start->val = e2.start->c;
+ e2.start->c = NFA_RANGE_MAX;
+ e1.start->val = e1.start->c;
+ e1.start->c = NFA_RANGE_MIN;
+ patch(e1.out, e2.start);
+ PUSH(frag(e1.start, e2.out));
+ break;
+
+ case NFA_EMPTY:
+ /* 0-length, used in a repetition with max/min count of 0 */
+ if (nfa_calc_size == TRUE)
+ {
+ nstate++;
+ break;
+ }
+ s = alloc_state(NFA_EMPTY, NULL, NULL);
+ if (s == NULL)
+ goto theend;
+ PUSH(frag(s, list1(&s->out)));
+ break;
+
+ case NFA_OPT_CHARS:
+ {
+ int n;
+
+ /* \%[abc] implemented as:
+ * NFA_SPLIT
+ * +-CHAR(a)
+ * | +-NFA_SPLIT
+ * | +-CHAR(b)
+ * | | +-NFA_SPLIT
+ * | | +-CHAR(c)
+ * | | | +-next
+ * | | +- next
+ * | +- next
+ * +- next
+ */
+ n = *++p; /* get number of characters */
+ if (nfa_calc_size == TRUE)
+ {
+ nstate += n;
+ break;
+ }
+ s = NULL; /* avoid compiler warning */
+ e1.out = NULL; /* stores list with out1's */
+ s1 = NULL; /* previous NFA_SPLIT to connect to */
+ while (n-- > 0)
+ {
+ e = POP(); /* get character */
+ s = alloc_state(NFA_SPLIT, e.start, NULL);
+ if (s == NULL)
+ goto theend;
+ if (e1.out == NULL)
+ e1 = e;
+ patch(e.out, s1);
+ append(e1.out, list1(&s->out1));
+ s1 = s;
+ }
+ PUSH(frag(s, e1.out));
+ break;
+ }
+
+ case NFA_PREV_ATOM_NO_WIDTH:
+ case NFA_PREV_ATOM_NO_WIDTH_NEG:
+ case NFA_PREV_ATOM_JUST_BEFORE:
+ case NFA_PREV_ATOM_JUST_BEFORE_NEG:
+ case NFA_PREV_ATOM_LIKE_PATTERN:
+ {
+ int before = (*p == NFA_PREV_ATOM_JUST_BEFORE
+ || *p == NFA_PREV_ATOM_JUST_BEFORE_NEG);
+ int pattern = (*p == NFA_PREV_ATOM_LIKE_PATTERN);
+ int start_state;
+ int end_state;
+ int n = 0;
+ nfa_state_T *zend;
+ nfa_state_T *skip;
+
+ switch (*p)
+ {
+ case NFA_PREV_ATOM_NO_WIDTH:
+ start_state = NFA_START_INVISIBLE;
+ end_state = NFA_END_INVISIBLE;
+ break;
+ case NFA_PREV_ATOM_NO_WIDTH_NEG:
+ start_state = NFA_START_INVISIBLE_NEG;
+ end_state = NFA_END_INVISIBLE_NEG;
+ break;
+ case NFA_PREV_ATOM_JUST_BEFORE:
+ start_state = NFA_START_INVISIBLE_BEFORE;
+ end_state = NFA_END_INVISIBLE;
+ break;
+ case NFA_PREV_ATOM_JUST_BEFORE_NEG:
+ start_state = NFA_START_INVISIBLE_BEFORE_NEG;
+ end_state = NFA_END_INVISIBLE_NEG;
+ break;
+ default: /* NFA_PREV_ATOM_LIKE_PATTERN: */
+ start_state = NFA_START_PATTERN;
+ end_state = NFA_END_PATTERN;
+ break;
+ }
+
+ if (before)
+ n = *++p; /* get the count */
+
+ /* The \@= operator: match the preceding atom with zero width.
+ * The \@! operator: no match for the preceding atom.
+ * The \@<= operator: match for the preceding atom.
+ * The \@<! operator: no match for the preceding atom.
+ * Surrounds the preceding atom with START_INVISIBLE and
+ * END_INVISIBLE, similarly to MOPEN. */
+
+ if (nfa_calc_size == TRUE)
+ {
+ nstate += pattern ? 4 : 2;
+ break;
+ }
+ e = POP();
+ s1 = alloc_state(end_state, NULL, NULL);
+ if (s1 == NULL)
+ goto theend;
+
+ s = alloc_state(start_state, e.start, s1);
+ if (s == NULL)
+ goto theend;
+ if (pattern)
+ {
+ /* NFA_ZEND -> NFA_END_PATTERN -> NFA_SKIP -> what follows. */
+ skip = alloc_state(NFA_SKIP, NULL, NULL);
+ if (skip == NULL)
+ goto theend;
+ zend = alloc_state(NFA_ZEND, s1, NULL);
+ if (zend == NULL)
+ goto theend;
+ s1->out= skip;
+ patch(e.out, zend);
+ PUSH(frag(s, list1(&skip->out)));
+ }
+ else
+ {
+ patch(e.out, s1);
+ PUSH(frag(s, list1(&s1->out)));
+ if (before)
+ {
+ if (n <= 0)
+ /* See if we can guess the maximum width, it avoids a
+ * lot of pointless tries. */
+ n = nfa_max_width(e.start, 0);
+ s->val = n; /* store the count */
+ }
+ }
+ break;
+ }
+
+ case NFA_COMPOSING: /* char with composing char */
+#if 0
+ /* TODO */
+ if (regflags & RF_ICOMBINE)
+ {
+ /* use the base character only */
+ }
+#endif
+ /* FALLTHROUGH */
+
+ case NFA_MOPEN: /* \( \) Submatch */
+ case NFA_MOPEN1:
+ case NFA_MOPEN2:
+ case NFA_MOPEN3:
+ case NFA_MOPEN4:
+ case NFA_MOPEN5:
+ case NFA_MOPEN6:
+ case NFA_MOPEN7:
+ case NFA_MOPEN8:
+ case NFA_MOPEN9:
+#ifdef FEAT_SYN_HL
+ case NFA_ZOPEN: /* \z( \) Submatch */
+ case NFA_ZOPEN1:
+ case NFA_ZOPEN2:
+ case NFA_ZOPEN3:
+ case NFA_ZOPEN4:
+ case NFA_ZOPEN5:
+ case NFA_ZOPEN6:
+ case NFA_ZOPEN7:
+ case NFA_ZOPEN8:
+ case NFA_ZOPEN9:
+#endif
+ case NFA_NOPEN: /* \%( \) "Invisible Submatch" */
+ if (nfa_calc_size == TRUE)
+ {
+ nstate += 2;
+ break;
+ }
+
+ mopen = *p;
+ switch (*p)
+ {
+ case NFA_NOPEN: mclose = NFA_NCLOSE; break;
+#ifdef FEAT_SYN_HL
+ case NFA_ZOPEN: mclose = NFA_ZCLOSE; break;
+ case NFA_ZOPEN1: mclose = NFA_ZCLOSE1; break;
+ case NFA_ZOPEN2: mclose = NFA_ZCLOSE2; break;
+ case NFA_ZOPEN3: mclose = NFA_ZCLOSE3; break;
+ case NFA_ZOPEN4: mclose = NFA_ZCLOSE4; break;
+ case NFA_ZOPEN5: mclose = NFA_ZCLOSE5; break;
+ case NFA_ZOPEN6: mclose = NFA_ZCLOSE6; break;
+ case NFA_ZOPEN7: mclose = NFA_ZCLOSE7; break;
+ case NFA_ZOPEN8: mclose = NFA_ZCLOSE8; break;
+ case NFA_ZOPEN9: mclose = NFA_ZCLOSE9; break;
+#endif
+ case NFA_COMPOSING: mclose = NFA_END_COMPOSING; break;
+ default:
+ /* NFA_MOPEN, NFA_MOPEN1 .. NFA_MOPEN9 */
+ mclose = *p + NSUBEXP;
+ break;
+ }
+
+ /* Allow "NFA_MOPEN" as a valid postfix representation for
+ * the empty regexp "". In this case, the NFA will be
+ * NFA_MOPEN -> NFA_MCLOSE. Note that this also allows
+ * empty groups of parenthesis, and empty mbyte chars */
+ if (stackp == stack)
+ {
+ s = alloc_state(mopen, NULL, NULL);
+ if (s == NULL)
+ goto theend;
+ s1 = alloc_state(mclose, NULL, NULL);
+ if (s1 == NULL)
+ goto theend;
+ patch(list1(&s->out), s1);
+ PUSH(frag(s, list1(&s1->out)));
+ break;
+ }
+
+ /* At least one node was emitted before NFA_MOPEN, so
+ * at least one node will be between NFA_MOPEN and NFA_MCLOSE */
+ e = POP();
+ s = alloc_state(mopen, e.start, NULL); /* `(' */
+ if (s == NULL)
+ goto theend;
+
+ s1 = alloc_state(mclose, NULL, NULL); /* `)' */
+ if (s1 == NULL)
+ goto theend;
+ patch(e.out, s1);
+
+ if (mopen == NFA_COMPOSING)
+ /* COMPOSING->out1 = END_COMPOSING */
+ patch(list1(&s->out1), s1);
+
+ PUSH(frag(s, list1(&s1->out)));
+ break;
+
+ case NFA_BACKREF1:
+ case NFA_BACKREF2:
+ case NFA_BACKREF3:
+ case NFA_BACKREF4:
+ case NFA_BACKREF5:
+ case NFA_BACKREF6:
+ case NFA_BACKREF7:
+ case NFA_BACKREF8:
+ case NFA_BACKREF9:
+#ifdef FEAT_SYN_HL
+ case NFA_ZREF1:
+ case NFA_ZREF2:
+ case NFA_ZREF3:
+ case NFA_ZREF4:
+ case NFA_ZREF5:
+ case NFA_ZREF6:
+ case NFA_ZREF7:
+ case NFA_ZREF8:
+ case NFA_ZREF9:
+#endif
+ if (nfa_calc_size == TRUE)
+ {
+ nstate += 2;
+ break;
+ }
+ s = alloc_state(*p, NULL, NULL);
+ if (s == NULL)
+ goto theend;
+ s1 = alloc_state(NFA_SKIP, NULL, NULL);
+ if (s1 == NULL)
+ goto theend;
+ patch(list1(&s->out), s1);
+ PUSH(frag(s, list1(&s1->out)));
+ break;
+
+ case NFA_LNUM:
+ case NFA_LNUM_GT:
+ case NFA_LNUM_LT:
+ case NFA_VCOL:
+ case NFA_VCOL_GT:
+ case NFA_VCOL_LT:
+ case NFA_COL:
+ case NFA_COL_GT:
+ case NFA_COL_LT:
+ case NFA_MARK:
+ case NFA_MARK_GT:
+ case NFA_MARK_LT:
+ {
+ int n = *++p; /* lnum, col or mark name */
+
+ if (nfa_calc_size == TRUE)
+ {
+ nstate += 1;
+ break;
+ }
+ s = alloc_state(p[-1], NULL, NULL);
+ if (s == NULL)
+ goto theend;
+ s->val = n;
+ PUSH(frag(s, list1(&s->out)));
+ break;
+ }
+
+ case NFA_ZSTART:
+ case NFA_ZEND:
+ default:
+ /* Operands */
+ if (nfa_calc_size == TRUE)
+ {
+ nstate++;
+ break;
+ }
+ s = alloc_state(*p, NULL, NULL);
+ if (s == NULL)
+ goto theend;
+ PUSH(frag(s, list1(&s->out)));
+ break;
+
+ } /* switch(*p) */
+
+ } /* for(p = postfix; *p; ++p) */
+
+ if (nfa_calc_size == TRUE)
+ {
+ nstate++;
+ goto theend; /* Return value when counting size is ignored anyway */
+ }
+
+ e = POP();
+ if (stackp != stack)
+ {
+ vim_free(stack);
+ EMSG_RET_NULL(_("E875: (NFA regexp) (While converting from postfix to NFA), too many states left on stack"));
+ }
+
+ if (istate >= nstate)
+ {
+ vim_free(stack);
+ EMSG_RET_NULL(_("E876: (NFA regexp) Not enough space to store the whole NFA "));
+ }
+
+ matchstate = &state_ptr[istate++]; /* the match state */
+ matchstate->c = NFA_MATCH;
+ matchstate->out = matchstate->out1 = NULL;
+ matchstate->id = 0;
+
+ patch(e.out, matchstate);
+ ret = e.start;
+
+theend:
+ vim_free(stack);
+ return ret;
+
+#undef POP1
+#undef PUSH1
+#undef POP2
+#undef PUSH2
+#undef POP
+#undef PUSH
+}
+
+/*
+ * After building the NFA program, inspect it to add optimization hints.
+ */
+ static void
+nfa_postprocess(nfa_regprog_T *prog)
+{
+ int i;
+ int c;
+
+ for (i = 0; i < prog->nstate; ++i)
+ {
+ c = prog->state[i].c;
+ if (c == NFA_START_INVISIBLE
+ || c == NFA_START_INVISIBLE_NEG
+ || c == NFA_START_INVISIBLE_BEFORE
+ || c == NFA_START_INVISIBLE_BEFORE_NEG)
+ {
+ int directly;
+
+ /* Do it directly when what follows is possibly the end of the
+ * match. */
+ if (match_follows(prog->state[i].out1->out, 0))
+ directly = TRUE;
+ else
+ {
+ int ch_invisible = failure_chance(prog->state[i].out, 0);
+ int ch_follows = failure_chance(prog->state[i].out1->out, 0);
+
+ /* Postpone when the invisible match is expensive or has a
+ * lower chance of failing. */
+ if (c == NFA_START_INVISIBLE_BEFORE
+ || c == NFA_START_INVISIBLE_BEFORE_NEG)
+ {
+ /* "before" matches are very expensive when
+ * unbounded, always prefer what follows then,
+ * unless what follows will always match.
+ * Otherwise strongly prefer what follows. */
+ if (prog->state[i].val <= 0 && ch_follows > 0)
+ directly = FALSE;
+ else
+ directly = ch_follows * 10 < ch_invisible;
+ }
+ else
+ {
+ /* normal invisible, first do the one with the
+ * highest failure chance */
+ directly = ch_follows < ch_invisible;
+ }
+ }
+ if (directly)
+ /* switch to the _FIRST state */
+ ++prog->state[i].c;
+ }
+ }
+}
+
+/****************************************************************
+ * NFA execution code.
+ ****************************************************************/
+
+typedef struct
+{
+ int in_use; /* number of subexpr with useful info */
+
+ /* When REG_MULTI is TRUE list.multi is used, otherwise list.line. */
+ union
+ {
+ struct multipos
+ {
+ linenr_T start_lnum;
+ linenr_T end_lnum;
+ colnr_T start_col;
+ colnr_T end_col;
+ } multi[NSUBEXP];
+ struct linepos
+ {
+ char_u *start;
+ char_u *end;
+ } line[NSUBEXP];
+ } list;
+} regsub_T;
+
+typedef struct
+{
+ regsub_T norm; /* \( .. \) matches */
+#ifdef FEAT_SYN_HL
+ regsub_T synt; /* \z( .. \) matches */
+#endif
+} regsubs_T;
+
+/* nfa_pim_T stores a Postponed Invisible Match. */
+typedef struct nfa_pim_S nfa_pim_T;
+struct nfa_pim_S
+{
+ int result; /* NFA_PIM_*, see below */
+ nfa_state_T *state; /* the invisible match start state */
+ regsubs_T subs; /* submatch info, only party used */
+ union
+ {
+ lpos_T pos;
+ char_u *ptr;
+ } end; /* where the match must end */
+};
+
+/* Values for done in nfa_pim_T. */
+#define NFA_PIM_UNUSED 0 /* pim not used */
+#define NFA_PIM_TODO 1 /* pim not done yet */
+#define NFA_PIM_MATCH 2 /* pim executed, matches */
+#define NFA_PIM_NOMATCH 3 /* pim executed, no match */
+
+
+/* nfa_thread_T contains execution information of a NFA state */
+typedef struct
+{
+ nfa_state_T *state;
+ int count;
+ nfa_pim_T pim; /* if pim.result != NFA_PIM_UNUSED: postponed
+ * invisible match */
+ regsubs_T subs; /* submatch info, only party used */
+} nfa_thread_T;
+
+/* nfa_list_T contains the alternative NFA execution states. */
+typedef struct
+{
+ nfa_thread_T *t; /* allocated array of states */
+ int n; /* nr of states currently in "t" */
+ int len; /* max nr of states in "t" */
+ int id; /* ID of the list */
+ int has_pim; /* TRUE when any state has a PIM */
+} nfa_list_T;
+
+#ifdef ENABLE_LOG
+static void log_subexpr(regsub_T *sub);
+
+ static void
+log_subsexpr(regsubs_T *subs)
+{
+ log_subexpr(&subs->norm);
+# ifdef FEAT_SYN_HL
+ if (rex.nfa_has_zsubexpr)
+ log_subexpr(&subs->synt);
+# endif
+}
+
+ static void
+log_subexpr(regsub_T *sub)
+{
+ int j;
+
+ for (j = 0; j < sub->in_use; j++)
+ if (REG_MULTI)
+ fprintf(log_fd, "*** group %d, start: c=%d, l=%d, end: c=%d, l=%d\n",
+ j,
+ sub->list.multi[j].start_col,
+ (int)sub->list.multi[j].start_lnum,
+ sub->list.multi[j].end_col,
+ (int)sub->list.multi[j].end_lnum);
+ else
+ {
+ char *s = (char *)sub->list.line[j].start;
+ char *e = (char *)sub->list.line[j].end;
+
+ fprintf(log_fd, "*** group %d, start: \"%s\", end: \"%s\"\n",
+ j,
+ s == NULL ? "NULL" : s,
+ e == NULL ? "NULL" : e);
+ }
+}
+
+ static char *
+pim_info(nfa_pim_T *pim)
+{
+ static char buf[30];
+
+ if (pim == NULL || pim->result == NFA_PIM_UNUSED)
+ buf[0] = NUL;
+ else
+ {
+ sprintf(buf, " PIM col %d", REG_MULTI ? (int)pim->end.pos.col
+ : (int)(pim->end.ptr - rex.input));
+ }
+ return buf;
+}
+
+#endif
+
+/* Used during execution: whether a match has been found. */
+static int nfa_match;
+#ifdef FEAT_RELTIME
+static proftime_T *nfa_time_limit;
+static int *nfa_timed_out;
+static int nfa_time_count;
+#endif
+
+static void copy_sub(regsub_T *to, regsub_T *from);
+static int pim_equal(nfa_pim_T *one, nfa_pim_T *two);
+
+/*
+ * Copy postponed invisible match info from "from" to "to".
+ */
+ static void
+copy_pim(nfa_pim_T *to, nfa_pim_T *from)
+{
+ to->result = from->result;
+ to->state = from->state;
+ copy_sub(&to->subs.norm, &from->subs.norm);
+#ifdef FEAT_SYN_HL
+ if (rex.nfa_has_zsubexpr)
+ copy_sub(&to->subs.synt, &from->subs.synt);
+#endif
+ to->end = from->end;
+}
+
+ static void
+clear_sub(regsub_T *sub)
+{
+ if (REG_MULTI)
+ /* Use 0xff to set lnum to -1 */
+ vim_memset(sub->list.multi, 0xff,
+ sizeof(struct multipos) * rex.nfa_nsubexpr);
+ else
+ vim_memset(sub->list.line, 0,
+ sizeof(struct linepos) * rex.nfa_nsubexpr);
+ sub->in_use = 0;
+}
+
+/*
+ * Copy the submatches from "from" to "to".
+ */
+ static void
+copy_sub(regsub_T *to, regsub_T *from)
+{
+ to->in_use = from->in_use;
+ if (from->in_use > 0)
+ {
+ /* Copy the match start and end positions. */
+ if (REG_MULTI)
+ mch_memmove(&to->list.multi[0],
+ &from->list.multi[0],
+ sizeof(struct multipos) * from->in_use);
+ else
+ mch_memmove(&to->list.line[0],
+ &from->list.line[0],
+ sizeof(struct linepos) * from->in_use);
+ }
+}
+
+/*
+ * Like copy_sub() but exclude the main match.
+ */
+ static void
+copy_sub_off(regsub_T *to, regsub_T *from)
+{
+ if (to->in_use < from->in_use)
+ to->in_use = from->in_use;
+ if (from->in_use > 1)
+ {
+ /* Copy the match start and end positions. */
+ if (REG_MULTI)
+ mch_memmove(&to->list.multi[1],
+ &from->list.multi[1],
+ sizeof(struct multipos) * (from->in_use - 1));
+ else
+ mch_memmove(&to->list.line[1],
+ &from->list.line[1],
+ sizeof(struct linepos) * (from->in_use - 1));
+ }
+}
+
+/*
+ * Like copy_sub() but only do the end of the main match if \ze is present.
+ */
+ static void
+copy_ze_off(regsub_T *to, regsub_T *from)
+{
+ if (rex.nfa_has_zend)
+ {
+ if (REG_MULTI)
+ {
+ if (from->list.multi[0].end_lnum >= 0)
+ {
+ to->list.multi[0].end_lnum = from->list.multi[0].end_lnum;
+ to->list.multi[0].end_col = from->list.multi[0].end_col;
+ }
+ }
+ else
+ {
+ if (from->list.line[0].end != NULL)
+ to->list.line[0].end = from->list.line[0].end;
+ }
+ }
+}
+
+/*
+ * Return TRUE if "sub1" and "sub2" have the same start positions.
+ * When using back-references also check the end position.
+ */
+ static int
+sub_equal(regsub_T *sub1, regsub_T *sub2)
+{
+ int i;
+ int todo;
+ linenr_T s1;
+ linenr_T s2;
+ char_u *sp1;
+ char_u *sp2;
+
+ todo = sub1->in_use > sub2->in_use ? sub1->in_use : sub2->in_use;
+ if (REG_MULTI)
+ {
+ for (i = 0; i < todo; ++i)
+ {
+ if (i < sub1->in_use)
+ s1 = sub1->list.multi[i].start_lnum;
+ else
+ s1 = -1;
+ if (i < sub2->in_use)
+ s2 = sub2->list.multi[i].start_lnum;
+ else
+ s2 = -1;
+ if (s1 != s2)
+ return FALSE;
+ if (s1 != -1 && sub1->list.multi[i].start_col
+ != sub2->list.multi[i].start_col)
+ return FALSE;
+
+ if (rex.nfa_has_backref)
+ {
+ if (i < sub1->in_use)
+ s1 = sub1->list.multi[i].end_lnum;
+ else
+ s1 = -1;
+ if (i < sub2->in_use)
+ s2 = sub2->list.multi[i].end_lnum;
+ else
+ s2 = -1;
+ if (s1 != s2)
+ return FALSE;
+ if (s1 != -1 && sub1->list.multi[i].end_col
+ != sub2->list.multi[i].end_col)
+ return FALSE;
+ }
+ }
+ }
+ else
+ {
+ for (i = 0; i < todo; ++i)
+ {
+ if (i < sub1->in_use)
+ sp1 = sub1->list.line[i].start;
+ else
+ sp1 = NULL;
+ if (i < sub2->in_use)
+ sp2 = sub2->list.line[i].start;
+ else
+ sp2 = NULL;
+ if (sp1 != sp2)
+ return FALSE;
+ if (rex.nfa_has_backref)
+ {
+ if (i < sub1->in_use)
+ sp1 = sub1->list.line[i].end;
+ else
+ sp1 = NULL;
+ if (i < sub2->in_use)
+ sp2 = sub2->list.line[i].end;
+ else
+ sp2 = NULL;
+ if (sp1 != sp2)
+ return FALSE;
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+#ifdef ENABLE_LOG
+ static void
+report_state(char *action,
+ regsub_T *sub,
+ nfa_state_T *state,
+ int lid,
+ nfa_pim_T *pim)
+{
+ int col;
+
+ if (sub->in_use <= 0)
+ col = -1;
+ else if (REG_MULTI)
+ col = sub->list.multi[0].start_col;
+ else
+ col = (int)(sub->list.line[0].start - rex.line);
+ nfa_set_code(state->c);
+ fprintf(log_fd, "> %s state %d to list %d. char %d: %s (start col %d)%s\n",
+ action, abs(state->id), lid, state->c, code, col,
+ pim_info(pim));
+}
+#endif
+
+/*
+ * Return TRUE if the same state is already in list "l" with the same
+ * positions as "subs".
+ */
+ static int
+has_state_with_pos(
+ nfa_list_T *l, /* runtime state list */
+ nfa_state_T *state, /* state to update */
+ regsubs_T *subs, /* pointers to subexpressions */
+ nfa_pim_T *pim) /* postponed match or NULL */
+{
+ nfa_thread_T *thread;
+ int i;
+
+ for (i = 0; i < l->n; ++i)
+ {
+ thread = &l->t[i];
+ if (thread->state->id == state->id
+ && sub_equal(&thread->subs.norm, &subs->norm)
+#ifdef FEAT_SYN_HL
+ && (!rex.nfa_has_zsubexpr
+ || sub_equal(&thread->subs.synt, &subs->synt))
+#endif
+ && pim_equal(&thread->pim, pim))
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * Return TRUE if "one" and "two" are equal. That includes when both are not
+ * set.
+ */
+ static int
+pim_equal(nfa_pim_T *one, nfa_pim_T *two)
+{
+ int one_unused = (one == NULL || one->result == NFA_PIM_UNUSED);
+ int two_unused = (two == NULL || two->result == NFA_PIM_UNUSED);
+
+ if (one_unused)
+ /* one is unused: equal when two is also unused */
+ return two_unused;
+ if (two_unused)
+ /* one is used and two is not: not equal */
+ return FALSE;
+ /* compare the state id */
+ if (one->state->id != two->state->id)
+ return FALSE;
+ /* compare the position */
+ if (REG_MULTI)
+ return one->end.pos.lnum == two->end.pos.lnum
+ && one->end.pos.col == two->end.pos.col;
+ return one->end.ptr == two->end.ptr;
+}
+
+/*
+ * Return TRUE if "state" leads to a NFA_MATCH without advancing the input.
+ */
+ static int
+match_follows(nfa_state_T *startstate, int depth)
+{
+ nfa_state_T *state = startstate;
+
+ /* avoid too much recursion */
+ if (depth > 10)
+ return FALSE;
+
+ while (state != NULL)
+ {
+ switch (state->c)
+ {
+ case NFA_MATCH:
+ case NFA_MCLOSE:
+ case NFA_END_INVISIBLE:
+ case NFA_END_INVISIBLE_NEG:
+ case NFA_END_PATTERN:
+ return TRUE;
+
+ case NFA_SPLIT:
+ return match_follows(state->out, depth + 1)
+ || match_follows(state->out1, depth + 1);
+
+ case NFA_START_INVISIBLE:
+ case NFA_START_INVISIBLE_FIRST:
+ case NFA_START_INVISIBLE_BEFORE:
+ case NFA_START_INVISIBLE_BEFORE_FIRST:
+ case NFA_START_INVISIBLE_NEG:
+ case NFA_START_INVISIBLE_NEG_FIRST:
+ case NFA_START_INVISIBLE_BEFORE_NEG:
+ case NFA_START_INVISIBLE_BEFORE_NEG_FIRST:
+ case NFA_COMPOSING:
+ /* skip ahead to next state */
+ state = state->out1->out;
+ continue;
+
+ case NFA_ANY:
+ case NFA_ANY_COMPOSING:
+ case NFA_IDENT:
+ case NFA_SIDENT:
+ case NFA_KWORD:
+ case NFA_SKWORD:
+ case NFA_FNAME:
+ case NFA_SFNAME:
+ case NFA_PRINT:
+ case NFA_SPRINT:
+ case NFA_WHITE:
+ case NFA_NWHITE:
+ case NFA_DIGIT:
+ case NFA_NDIGIT:
+ case NFA_HEX:
+ case NFA_NHEX:
+ case NFA_OCTAL:
+ case NFA_NOCTAL:
+ case NFA_WORD:
+ case NFA_NWORD:
+ case NFA_HEAD:
+ case NFA_NHEAD:
+ case NFA_ALPHA:
+ case NFA_NALPHA:
+ case NFA_LOWER:
+ case NFA_NLOWER:
+ case NFA_UPPER:
+ case NFA_NUPPER:
+ case NFA_LOWER_IC:
+ case NFA_NLOWER_IC:
+ case NFA_UPPER_IC:
+ case NFA_NUPPER_IC:
+ case NFA_START_COLL:
+ case NFA_START_NEG_COLL:
+ case NFA_NEWL:
+ /* state will advance input */
+ return FALSE;
+
+ default:
+ if (state->c > 0)
+ /* state will advance input */
+ return FALSE;
+
+ /* Others: zero-width or possibly zero-width, might still find
+ * a match at the same position, keep looking. */
+ break;
+ }
+ state = state->out;
+ }
+ return FALSE;
+}
+
+
+/*
+ * Return TRUE if "state" is already in list "l".
+ */
+ static int
+state_in_list(
+ nfa_list_T *l, /* runtime state list */
+ nfa_state_T *state, /* state to update */
+ regsubs_T *subs) /* pointers to subexpressions */
+{
+ if (state->lastlist[nfa_ll_index] == l->id)
+ {
+ if (!rex.nfa_has_backref || has_state_with_pos(l, state, subs, NULL))
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/* Offset used for "off" by addstate_here(). */
+#define ADDSTATE_HERE_OFFSET 10
+
+/*
+ * Add "state" and possibly what follows to state list ".".
+ * Returns "subs_arg", possibly copied into temp_subs.
+ */
+ static regsubs_T *
+addstate(
+ nfa_list_T *l, /* runtime state list */
+ nfa_state_T *state, /* state to update */
+ regsubs_T *subs_arg, /* pointers to subexpressions */
+ nfa_pim_T *pim, /* postponed look-behind match */
+ int off_arg) /* byte offset, when -1 go to next line */
+{
+ int subidx;
+ int off = off_arg;
+ int add_here = FALSE;
+ int listindex = 0;
+ int k;
+ int found = FALSE;
+ nfa_thread_T *thread;
+ struct multipos save_multipos;
+ int save_in_use;
+ char_u *save_ptr;
+ int i;
+ regsub_T *sub;
+ regsubs_T *subs = subs_arg;
+ static regsubs_T temp_subs;
+#ifdef ENABLE_LOG
+ int did_print = FALSE;
+#endif
+
+ if (off_arg <= -ADDSTATE_HERE_OFFSET)
+ {
+ add_here = TRUE;
+ off = 0;
+ listindex = -(off_arg + ADDSTATE_HERE_OFFSET);
+ }
+
+ switch (state->c)
+ {
+ case NFA_NCLOSE:
+ case NFA_MCLOSE:
+ case NFA_MCLOSE1:
+ case NFA_MCLOSE2:
+ case NFA_MCLOSE3:
+ case NFA_MCLOSE4:
+ case NFA_MCLOSE5:
+ case NFA_MCLOSE6:
+ case NFA_MCLOSE7:
+ case NFA_MCLOSE8:
+ case NFA_MCLOSE9:
+#ifdef FEAT_SYN_HL
+ case NFA_ZCLOSE:
+ case NFA_ZCLOSE1:
+ case NFA_ZCLOSE2:
+ case NFA_ZCLOSE3:
+ case NFA_ZCLOSE4:
+ case NFA_ZCLOSE5:
+ case NFA_ZCLOSE6:
+ case NFA_ZCLOSE7:
+ case NFA_ZCLOSE8:
+ case NFA_ZCLOSE9:
+#endif
+ case NFA_MOPEN:
+ case NFA_ZEND:
+ case NFA_SPLIT:
+ case NFA_EMPTY:
+ /* These nodes are not added themselves but their "out" and/or
+ * "out1" may be added below. */
+ break;
+
+ case NFA_BOL:
+ case NFA_BOF:
+ /* "^" won't match past end-of-line, don't bother trying.
+ * Except when at the end of the line, or when we are going to the
+ * next line for a look-behind match. */
+ if (rex.input > rex.line
+ && *rex.input != NUL
+ && (nfa_endp == NULL
+ || !REG_MULTI
+ || rex.lnum == nfa_endp->se_u.pos.lnum))
+ goto skip_add;
+ /* FALLTHROUGH */
+
+ case NFA_MOPEN1:
+ case NFA_MOPEN2:
+ case NFA_MOPEN3:
+ case NFA_MOPEN4:
+ case NFA_MOPEN5:
+ case NFA_MOPEN6:
+ case NFA_MOPEN7:
+ case NFA_MOPEN8:
+ case NFA_MOPEN9:
+#ifdef FEAT_SYN_HL
+ case NFA_ZOPEN:
+ case NFA_ZOPEN1:
+ case NFA_ZOPEN2:
+ case NFA_ZOPEN3:
+ case NFA_ZOPEN4:
+ case NFA_ZOPEN5:
+ case NFA_ZOPEN6:
+ case NFA_ZOPEN7:
+ case NFA_ZOPEN8:
+ case NFA_ZOPEN9:
+#endif
+ case NFA_NOPEN:
+ case NFA_ZSTART:
+ /* These nodes need to be added so that we can bail out when it
+ * was added to this list before at the same position to avoid an
+ * endless loop for "\(\)*" */
+
+ default:
+ if (state->lastlist[nfa_ll_index] == l->id && state->c != NFA_SKIP)
+ {
+ /* This state is already in the list, don't add it again,
+ * unless it is an MOPEN that is used for a backreference or
+ * when there is a PIM. For NFA_MATCH check the position,
+ * lower position is preferred. */
+ if (!rex.nfa_has_backref && pim == NULL && !l->has_pim
+ && state->c != NFA_MATCH)
+ {
+ /* When called from addstate_here() do insert before
+ * existing states. */
+ if (add_here)
+ {
+ for (k = 0; k < l->n && k < listindex; ++k)
+ if (l->t[k].state->id == state->id)
+ {
+ found = TRUE;
+ break;
+ }
+ }
+ if (!add_here || found)
+ {
+skip_add:
+#ifdef ENABLE_LOG
+ nfa_set_code(state->c);
+ fprintf(log_fd, "> Not adding state %d to list %d. char %d: %s pim: %s has_pim: %d found: %d\n",
+ abs(state->id), l->id, state->c, code,
+ pim == NULL ? "NULL" : "yes", l->has_pim, found);
+#endif
+ return subs;
+ }
+ }
+
+ /* Do not add the state again when it exists with the same
+ * positions. */
+ if (has_state_with_pos(l, state, subs, pim))
+ goto skip_add;
+ }
+
+ /* When there are backreferences or PIMs the number of states may
+ * be (a lot) bigger than anticipated. */
+ if (l->n == l->len)
+ {
+ int newlen = l->len * 3 / 2 + 50;
+
+ if (subs != &temp_subs)
+ {
+ /* "subs" may point into the current array, need to make a
+ * copy before it becomes invalid. */
+ copy_sub(&temp_subs.norm, &subs->norm);
+#ifdef FEAT_SYN_HL
+ if (rex.nfa_has_zsubexpr)
+ copy_sub(&temp_subs.synt, &subs->synt);
+#endif
+ subs = &temp_subs;
+ }
+
+ /* TODO: check for vim_realloc() returning NULL. */
+ l->t = vim_realloc(l->t, newlen * sizeof(nfa_thread_T));
+ l->len = newlen;
+ }
+
+ /* add the state to the list */
+ state->lastlist[nfa_ll_index] = l->id;
+ thread = &l->t[l->n++];
+ thread->state = state;
+ if (pim == NULL)
+ thread->pim.result = NFA_PIM_UNUSED;
+ else
+ {
+ copy_pim(&thread->pim, pim);
+ l->has_pim = TRUE;
+ }
+ copy_sub(&thread->subs.norm, &subs->norm);
+#ifdef FEAT_SYN_HL
+ if (rex.nfa_has_zsubexpr)
+ copy_sub(&thread->subs.synt, &subs->synt);
+#endif
+#ifdef ENABLE_LOG
+ report_state("Adding", &thread->subs.norm, state, l->id, pim);
+ did_print = TRUE;
+#endif
+ }
+
+#ifdef ENABLE_LOG
+ if (!did_print)
+ report_state("Processing", &subs->norm, state, l->id, pim);
+#endif
+ switch (state->c)
+ {
+ case NFA_MATCH:
+ break;
+
+ case NFA_SPLIT:
+ /* order matters here */
+ subs = addstate(l, state->out, subs, pim, off_arg);
+ subs = addstate(l, state->out1, subs, pim, off_arg);
+ break;
+
+ case NFA_EMPTY:
+ case NFA_NOPEN:
+ case NFA_NCLOSE:
+ subs = addstate(l, state->out, subs, pim, off_arg);
+ break;
+
+ case NFA_MOPEN:
+ case NFA_MOPEN1:
+ case NFA_MOPEN2:
+ case NFA_MOPEN3:
+ case NFA_MOPEN4:
+ case NFA_MOPEN5:
+ case NFA_MOPEN6:
+ case NFA_MOPEN7:
+ case NFA_MOPEN8:
+ case NFA_MOPEN9:
+#ifdef FEAT_SYN_HL
+ case NFA_ZOPEN:
+ case NFA_ZOPEN1:
+ case NFA_ZOPEN2:
+ case NFA_ZOPEN3:
+ case NFA_ZOPEN4:
+ case NFA_ZOPEN5:
+ case NFA_ZOPEN6:
+ case NFA_ZOPEN7:
+ case NFA_ZOPEN8:
+ case NFA_ZOPEN9:
+#endif
+ case NFA_ZSTART:
+ if (state->c == NFA_ZSTART)
+ {
+ subidx = 0;
+ sub = &subs->norm;
+ }
+#ifdef FEAT_SYN_HL
+ else if (state->c >= NFA_ZOPEN && state->c <= NFA_ZOPEN9)
+ {
+ subidx = state->c - NFA_ZOPEN;
+ sub = &subs->synt;
+ }
+#endif
+ else
+ {
+ subidx = state->c - NFA_MOPEN;
+ sub = &subs->norm;
+ }
+
+ /* avoid compiler warnings */
+ save_ptr = NULL;
+ vim_memset(&save_multipos, 0, sizeof(save_multipos));
+
+ /* Set the position (with "off" added) in the subexpression. Save
+ * and restore it when it was in use. Otherwise fill any gap. */
+ if (REG_MULTI)
+ {
+ if (subidx < sub->in_use)
+ {
+ save_multipos = sub->list.multi[subidx];
+ save_in_use = -1;
+ }
+ else
+ {
+ save_in_use = sub->in_use;
+ for (i = sub->in_use; i < subidx; ++i)
+ {
+ sub->list.multi[i].start_lnum = -1;
+ sub->list.multi[i].end_lnum = -1;
+ }
+ sub->in_use = subidx + 1;
+ }
+ if (off == -1)
+ {
+ sub->list.multi[subidx].start_lnum = rex.lnum + 1;
+ sub->list.multi[subidx].start_col = 0;
+ }
+ else
+ {
+ sub->list.multi[subidx].start_lnum = rex.lnum;
+ sub->list.multi[subidx].start_col =
+ (colnr_T)(rex.input - rex.line + off);
+ }
+ sub->list.multi[subidx].end_lnum = -1;
+ }
+ else
+ {
+ if (subidx < sub->in_use)
+ {
+ save_ptr = sub->list.line[subidx].start;
+ save_in_use = -1;
+ }
+ else
+ {
+ save_in_use = sub->in_use;
+ for (i = sub->in_use; i < subidx; ++i)
+ {
+ sub->list.line[i].start = NULL;
+ sub->list.line[i].end = NULL;
+ }
+ sub->in_use = subidx + 1;
+ }
+ sub->list.line[subidx].start = rex.input + off;
+ }
+
+ subs = addstate(l, state->out, subs, pim, off_arg);
+ /* "subs" may have changed, need to set "sub" again */
+#ifdef FEAT_SYN_HL
+ if (state->c >= NFA_ZOPEN && state->c <= NFA_ZOPEN9)
+ sub = &subs->synt;
+ else
+#endif
+ sub = &subs->norm;
+
+ if (save_in_use == -1)
+ {
+ if (REG_MULTI)
+ sub->list.multi[subidx] = save_multipos;
+ else
+ sub->list.line[subidx].start = save_ptr;
+ }
+ else
+ sub->in_use = save_in_use;
+ break;
+
+ case NFA_MCLOSE:
+ if (rex.nfa_has_zend && (REG_MULTI
+ ? subs->norm.list.multi[0].end_lnum >= 0
+ : subs->norm.list.line[0].end != NULL))
+ {
+ /* Do not overwrite the position set by \ze. */
+ subs = addstate(l, state->out, subs, pim, off_arg);
+ break;
+ }
+ /* FALLTHROUGH */
+ case NFA_MCLOSE1:
+ case NFA_MCLOSE2:
+ case NFA_MCLOSE3:
+ case NFA_MCLOSE4:
+ case NFA_MCLOSE5:
+ case NFA_MCLOSE6:
+ case NFA_MCLOSE7:
+ case NFA_MCLOSE8:
+ case NFA_MCLOSE9:
+#ifdef FEAT_SYN_HL
+ case NFA_ZCLOSE:
+ case NFA_ZCLOSE1:
+ case NFA_ZCLOSE2:
+ case NFA_ZCLOSE3:
+ case NFA_ZCLOSE4:
+ case NFA_ZCLOSE5:
+ case NFA_ZCLOSE6:
+ case NFA_ZCLOSE7:
+ case NFA_ZCLOSE8:
+ case NFA_ZCLOSE9:
+#endif
+ case NFA_ZEND:
+ if (state->c == NFA_ZEND)
+ {
+ subidx = 0;
+ sub = &subs->norm;
+ }
+#ifdef FEAT_SYN_HL
+ else if (state->c >= NFA_ZCLOSE && state->c <= NFA_ZCLOSE9)
+ {
+ subidx = state->c - NFA_ZCLOSE;
+ sub = &subs->synt;
+ }
+#endif
+ else
+ {
+ subidx = state->c - NFA_MCLOSE;
+ sub = &subs->norm;
+ }
+
+ /* We don't fill in gaps here, there must have been an MOPEN that
+ * has done that. */
+ save_in_use = sub->in_use;
+ if (sub->in_use <= subidx)
+ sub->in_use = subidx + 1;
+ if (REG_MULTI)
+ {
+ save_multipos = sub->list.multi[subidx];
+ if (off == -1)
+ {
+ sub->list.multi[subidx].end_lnum = rex.lnum + 1;
+ sub->list.multi[subidx].end_col = 0;
+ }
+ else
+ {
+ sub->list.multi[subidx].end_lnum = rex.lnum;
+ sub->list.multi[subidx].end_col =
+ (colnr_T)(rex.input - rex.line + off);
+ }
+ /* avoid compiler warnings */
+ save_ptr = NULL;
+ }
+ else
+ {
+ save_ptr = sub->list.line[subidx].end;
+ sub->list.line[subidx].end = rex.input + off;
+ /* avoid compiler warnings */
+ vim_memset(&save_multipos, 0, sizeof(save_multipos));
+ }
+
+ subs = addstate(l, state->out, subs, pim, off_arg);
+ /* "subs" may have changed, need to set "sub" again */
+#ifdef FEAT_SYN_HL
+ if (state->c >= NFA_ZCLOSE && state->c <= NFA_ZCLOSE9)
+ sub = &subs->synt;
+ else
+#endif
+ sub = &subs->norm;
+
+ if (REG_MULTI)
+ sub->list.multi[subidx] = save_multipos;
+ else
+ sub->list.line[subidx].end = save_ptr;
+ sub->in_use = save_in_use;
+ break;
+ }
+ return subs;
+}
+
+/*
+ * Like addstate(), but the new state(s) are put at position "*ip".
+ * Used for zero-width matches, next state to use is the added one.
+ * This makes sure the order of states to be tried does not change, which
+ * matters for alternatives.
+ */
+ static void
+addstate_here(
+ nfa_list_T *l, /* runtime state list */
+ nfa_state_T *state, /* state to update */
+ regsubs_T *subs, /* pointers to subexpressions */
+ nfa_pim_T *pim, /* postponed look-behind match */
+ int *ip)
+{
+ int tlen = l->n;
+ int count;
+ int listidx = *ip;
+
+ /* First add the state(s) at the end, so that we know how many there are.
+ * Pass the listidx as offset (avoids adding another argument to
+ * addstate(). */
+ addstate(l, state, subs, pim, -listidx - ADDSTATE_HERE_OFFSET);
+
+ /* when "*ip" was at the end of the list, nothing to do */
+ if (listidx + 1 == tlen)
+ return;
+
+ /* re-order to put the new state at the current position */
+ count = l->n - tlen;
+ if (count == 0)
+ return; /* no state got added */
+ if (count == 1)
+ {
+ /* overwrite the current state */
+ l->t[listidx] = l->t[l->n - 1];
+ }
+ else if (count > 1)
+ {
+ if (l->n + count - 1 >= l->len)
+ {
+ /* not enough space to move the new states, reallocate the list
+ * and move the states to the right position */
+ nfa_thread_T *newl;
+
+ l->len = l->len * 3 / 2 + 50;
+ newl = (nfa_thread_T *)alloc(l->len * sizeof(nfa_thread_T));
+ if (newl == NULL)
+ return;
+ mch_memmove(&(newl[0]),
+ &(l->t[0]),
+ sizeof(nfa_thread_T) * listidx);
+ mch_memmove(&(newl[listidx]),
+ &(l->t[l->n - count]),
+ sizeof(nfa_thread_T) * count);
+ mch_memmove(&(newl[listidx + count]),
+ &(l->t[listidx + 1]),
+ sizeof(nfa_thread_T) * (l->n - count - listidx - 1));
+ vim_free(l->t);
+ l->t = newl;
+ }
+ else
+ {
+ /* make space for new states, then move them from the
+ * end to the current position */
+ mch_memmove(&(l->t[listidx + count]),
+ &(l->t[listidx + 1]),
+ sizeof(nfa_thread_T) * (l->n - listidx - 1));
+ mch_memmove(&(l->t[listidx]),
+ &(l->t[l->n - 1]),
+ sizeof(nfa_thread_T) * count);
+ }
+ }
+ --l->n;
+ *ip = listidx - 1;
+}
+
+/*
+ * Check character class "class" against current character c.
+ */
+ static int
+check_char_class(int class, int c)
+{
+ switch (class)
+ {
+ case NFA_CLASS_ALNUM:
+ if (c >= 1 && c < 128 && isalnum(c))
+ return OK;
+ break;
+ case NFA_CLASS_ALPHA:
+ if (c >= 1 && c < 128 && isalpha(c))
+ return OK;
+ break;
+ case NFA_CLASS_BLANK:
+ if (c == ' ' || c == '\t')
+ return OK;
+ break;
+ case NFA_CLASS_CNTRL:
+ if (c >= 1 && c <= 127 && iscntrl(c))
+ return OK;
+ break;
+ case NFA_CLASS_DIGIT:
+ if (VIM_ISDIGIT(c))
+ return OK;
+ break;
+ case NFA_CLASS_GRAPH:
+ if (c >= 1 && c <= 127 && isgraph(c))
+ return OK;
+ break;
+ case NFA_CLASS_LOWER:
+ if (MB_ISLOWER(c) && c != 170 && c != 186)
+ return OK;
+ break;
+ case NFA_CLASS_PRINT:
+ if (vim_isprintc(c))
+ return OK;
+ break;
+ case NFA_CLASS_PUNCT:
+ if (c >= 1 && c < 128 && ispunct(c))
+ return OK;
+ break;
+ case NFA_CLASS_SPACE:
+ if ((c >= 9 && c <= 13) || (c == ' '))
+ return OK;
+ break;
+ case NFA_CLASS_UPPER:
+ if (MB_ISUPPER(c))
+ return OK;
+ break;
+ case NFA_CLASS_XDIGIT:
+ if (vim_isxdigit(c))
+ return OK;
+ break;
+ case NFA_CLASS_TAB:
+ if (c == '\t')
+ return OK;
+ break;
+ case NFA_CLASS_RETURN:
+ if (c == '\r')
+ return OK;
+ break;
+ case NFA_CLASS_BACKSPACE:
+ if (c == '\b')
+ return OK;
+ break;
+ case NFA_CLASS_ESCAPE:
+ if (c == '\033')
+ return OK;
+ break;
+ case NFA_CLASS_IDENT:
+ if (vim_isIDc(c))
+ return OK;
+ break;
+ case NFA_CLASS_KEYWORD:
+ if (reg_iswordc(c))
+ return OK;
+ break;
+ case NFA_CLASS_FNAME:
+ if (vim_isfilec(c))
+ return OK;
+ break;
+
+ default:
+ /* should not be here :P */
+ siemsg(_(e_ill_char_class), class);
+ return FAIL;
+ }
+ return FAIL;
+}
+
+/*
+ * Check for a match with subexpression "subidx".
+ * Return TRUE if it matches.
+ */
+ static int
+match_backref(
+ regsub_T *sub, /* pointers to subexpressions */
+ int subidx,
+ int *bytelen) /* out: length of match in bytes */
+{
+ int len;
+
+ if (sub->in_use <= subidx)
+ {
+retempty:
+ /* backref was not set, match an empty string */
+ *bytelen = 0;
+ return TRUE;
+ }
+
+ if (REG_MULTI)
+ {
+ if (sub->list.multi[subidx].start_lnum < 0
+ || sub->list.multi[subidx].end_lnum < 0)
+ goto retempty;
+ if (sub->list.multi[subidx].start_lnum == rex.lnum
+ && sub->list.multi[subidx].end_lnum == rex.lnum)
+ {
+ len = sub->list.multi[subidx].end_col
+ - sub->list.multi[subidx].start_col;
+ if (cstrncmp(rex.line + sub->list.multi[subidx].start_col,
+ rex.input, &len) == 0)
+ {
+ *bytelen = len;
+ return TRUE;
+ }
+ }
+ else
+ {
+ if (match_with_backref(
+ sub->list.multi[subidx].start_lnum,
+ sub->list.multi[subidx].start_col,
+ sub->list.multi[subidx].end_lnum,
+ sub->list.multi[subidx].end_col,
+ bytelen) == RA_MATCH)
+ return TRUE;
+ }
+ }
+ else
+ {
+ if (sub->list.line[subidx].start == NULL
+ || sub->list.line[subidx].end == NULL)
+ goto retempty;
+ len = (int)(sub->list.line[subidx].end - sub->list.line[subidx].start);
+ if (cstrncmp(sub->list.line[subidx].start, rex.input, &len) == 0)
+ {
+ *bytelen = len;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+#ifdef FEAT_SYN_HL
+
+/*
+ * Check for a match with \z subexpression "subidx".
+ * Return TRUE if it matches.
+ */
+ static int
+match_zref(
+ int subidx,
+ int *bytelen) /* out: length of match in bytes */
+{
+ int len;
+
+ cleanup_zsubexpr();
+ if (re_extmatch_in == NULL || re_extmatch_in->matches[subidx] == NULL)
+ {
+ /* backref was not set, match an empty string */
+ *bytelen = 0;
+ return TRUE;
+ }
+
+ len = (int)STRLEN(re_extmatch_in->matches[subidx]);
+ if (cstrncmp(re_extmatch_in->matches[subidx], rex.input, &len) == 0)
+ {
+ *bytelen = len;
+ return TRUE;
+ }
+ return FALSE;
+}
+#endif
+
+/*
+ * Save list IDs for all NFA states of "prog" into "list".
+ * Also reset the IDs to zero.
+ * Only used for the recursive value lastlist[1].
+ */
+ static void
+nfa_save_listids(nfa_regprog_T *prog, int *list)
+{
+ int i;
+ nfa_state_T *p;
+
+ /* Order in the list is reverse, it's a bit faster that way. */
+ p = &prog->state[0];
+ for (i = prog->nstate; --i >= 0; )
+ {
+ list[i] = p->lastlist[1];
+ p->lastlist[1] = 0;
+ ++p;
+ }
+}
+
+/*
+ * Restore list IDs from "list" to all NFA states.
+ */
+ static void
+nfa_restore_listids(nfa_regprog_T *prog, int *list)
+{
+ int i;
+ nfa_state_T *p;
+
+ p = &prog->state[0];
+ for (i = prog->nstate; --i >= 0; )
+ {
+ p->lastlist[1] = list[i];
+ ++p;
+ }
+}
+
+ static int
+nfa_re_num_cmp(long_u val, int op, long_u pos)
+{
+ if (op == 1) return pos > val;
+ if (op == 2) return pos < val;
+ return val == pos;
+}
+
+static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *submatch, regsubs_T *m);
+
+/*
+ * Recursively call nfa_regmatch()
+ * "pim" is NULL or contains info about a Postponed Invisible Match (start
+ * position).
+ */
+ static int
+recursive_regmatch(
+ nfa_state_T *state,
+ nfa_pim_T *pim,
+ nfa_regprog_T *prog,
+ regsubs_T *submatch,
+ regsubs_T *m,
+ int **listids,
+ int *listids_len)
+{
+ int save_reginput_col = (int)(rex.input - rex.line);
+ int save_reglnum = rex.lnum;
+ int save_nfa_match = nfa_match;
+ int save_nfa_listid = rex.nfa_listid;
+ save_se_T *save_nfa_endp = nfa_endp;
+ save_se_T endpos;
+ save_se_T *endposp = NULL;
+ int result;
+ int need_restore = FALSE;
+
+ if (pim != NULL)
+ {
+ /* start at the position where the postponed match was */
+ if (REG_MULTI)
+ rex.input = rex.line + pim->end.pos.col;
+ else
+ rex.input = pim->end.ptr;
+ }
+
+ if (state->c == NFA_START_INVISIBLE_BEFORE
+ || state->c == NFA_START_INVISIBLE_BEFORE_FIRST
+ || state->c == NFA_START_INVISIBLE_BEFORE_NEG
+ || state->c == NFA_START_INVISIBLE_BEFORE_NEG_FIRST)
+ {
+ /* The recursive match must end at the current position. When "pim" is
+ * not NULL it specifies the current position. */
+ endposp = &endpos;
+ if (REG_MULTI)
+ {
+ if (pim == NULL)
+ {
+ endpos.se_u.pos.col = (int)(rex.input - rex.line);
+ endpos.se_u.pos.lnum = rex.lnum;
+ }
+ else
+ endpos.se_u.pos = pim->end.pos;
+ }
+ else
+ {
+ if (pim == NULL)
+ endpos.se_u.ptr = rex.input;
+ else
+ endpos.se_u.ptr = pim->end.ptr;
+ }
+
+ /* Go back the specified number of bytes, or as far as the
+ * start of the previous line, to try matching "\@<=" or
+ * not matching "\@<!". This is very inefficient, limit the number of
+ * bytes if possible. */
+ if (state->val <= 0)
+ {
+ if (REG_MULTI)
+ {
+ rex.line = reg_getline(--rex.lnum);
+ if (rex.line == NULL)
+ /* can't go before the first line */
+ rex.line = reg_getline(++rex.lnum);
+ }
+ rex.input = rex.line;
+ }
+ else
+ {
+ if (REG_MULTI && (int)(rex.input - rex.line) < state->val)
+ {
+ /* Not enough bytes in this line, go to end of
+ * previous line. */
+ rex.line = reg_getline(--rex.lnum);
+ if (rex.line == NULL)
+ {
+ /* can't go before the first line */
+ rex.line = reg_getline(++rex.lnum);
+ rex.input = rex.line;
+ }
+ else
+ rex.input = rex.line + STRLEN(rex.line);
+ }
+ if ((int)(rex.input - rex.line) >= state->val)
+ {
+ rex.input -= state->val;
+ if (has_mbyte)
+ rex.input -= mb_head_off(rex.line, rex.input);
+ }
+ else
+ rex.input = rex.line;
+ }
+ }
+
+#ifdef ENABLE_LOG
+ if (log_fd != stderr)
+ fclose(log_fd);
+ log_fd = NULL;
+#endif
+ /* Have to clear the lastlist field of the NFA nodes, so that
+ * nfa_regmatch() and addstate() can run properly after recursion. */
+ if (nfa_ll_index == 1)
+ {
+ /* Already calling nfa_regmatch() recursively. Save the lastlist[1]
+ * values and clear them. */
+ if (*listids == NULL || *listids_len < prog->nstate)
+ {
+ vim_free(*listids);
+ *listids = (int *)lalloc(sizeof(int) * prog->nstate, TRUE);
+ if (*listids == NULL)
+ {
+ emsg(_("E878: (NFA) Could not allocate memory for branch traversal!"));
+ return 0;
+ }
+ *listids_len = prog->nstate;
+ }
+ nfa_save_listids(prog, *listids);
+ need_restore = TRUE;
+ /* any value of rex.nfa_listid will do */
+ }
+ else
+ {
+ /* First recursive nfa_regmatch() call, switch to the second lastlist
+ * entry. Make sure rex.nfa_listid is different from a previous
+ * recursive call, because some states may still have this ID. */
+ ++nfa_ll_index;
+ if (rex.nfa_listid <= rex.nfa_alt_listid)
+ rex.nfa_listid = rex.nfa_alt_listid;
+ }
+
+ /* Call nfa_regmatch() to check if the current concat matches at this
+ * position. The concat ends with the node NFA_END_INVISIBLE */
+ nfa_endp = endposp;
+ result = nfa_regmatch(prog, state->out, submatch, m);
+
+ if (need_restore)
+ nfa_restore_listids(prog, *listids);
+ else
+ {
+ --nfa_ll_index;
+ rex.nfa_alt_listid = rex.nfa_listid;
+ }
+
+ /* restore position in input text */
+ rex.lnum = save_reglnum;
+ if (REG_MULTI)
+ rex.line = reg_getline(rex.lnum);
+ rex.input = rex.line + save_reginput_col;
+ if (result != NFA_TOO_EXPENSIVE)
+ {
+ nfa_match = save_nfa_match;
+ rex.nfa_listid = save_nfa_listid;
+ }
+ nfa_endp = save_nfa_endp;
+
+#ifdef ENABLE_LOG
+ log_fd = fopen(NFA_REGEXP_RUN_LOG, "a");
+ if (log_fd != NULL)
+ {
+ fprintf(log_fd, "****************************\n");
+ fprintf(log_fd, "FINISHED RUNNING nfa_regmatch() recursively\n");
+ fprintf(log_fd, "MATCH = %s\n", result == TRUE ? "OK" : "FALSE");
+ fprintf(log_fd, "****************************\n");
+ }
+ else
+ {
+ emsg(_(e_log_open_failed));
+ log_fd = stderr;
+ }
+#endif
+
+ return result;
+}
+
+/*
+ * Estimate the chance of a match with "state" failing.
+ * empty match: 0
+ * NFA_ANY: 1
+ * specific character: 99
+ */
+ static int
+failure_chance(nfa_state_T *state, int depth)
+{
+ int c = state->c;
+ int l, r;
+
+ /* detect looping */
+ if (depth > 4)
+ return 1;
+
+ switch (c)
+ {
+ case NFA_SPLIT:
+ if (state->out->c == NFA_SPLIT || state->out1->c == NFA_SPLIT)
+ /* avoid recursive stuff */
+ return 1;
+ /* two alternatives, use the lowest failure chance */
+ l = failure_chance(state->out, depth + 1);
+ r = failure_chance(state->out1, depth + 1);
+ return l < r ? l : r;
+
+ case NFA_ANY:
+ /* matches anything, unlikely to fail */
+ return 1;
+
+ case NFA_MATCH:
+ case NFA_MCLOSE:
+ case NFA_ANY_COMPOSING:
+ /* empty match works always */
+ return 0;
+
+ case NFA_START_INVISIBLE:
+ case NFA_START_INVISIBLE_FIRST:
+ case NFA_START_INVISIBLE_NEG:
+ case NFA_START_INVISIBLE_NEG_FIRST:
+ case NFA_START_INVISIBLE_BEFORE:
+ case NFA_START_INVISIBLE_BEFORE_FIRST:
+ case NFA_START_INVISIBLE_BEFORE_NEG:
+ case NFA_START_INVISIBLE_BEFORE_NEG_FIRST:
+ case NFA_START_PATTERN:
+ /* recursive regmatch is expensive, use low failure chance */
+ return 5;
+
+ case NFA_BOL:
+ case NFA_EOL:
+ case NFA_BOF:
+ case NFA_EOF:
+ case NFA_NEWL:
+ return 99;
+
+ case NFA_BOW:
+ case NFA_EOW:
+ return 90;
+
+ case NFA_MOPEN:
+ case NFA_MOPEN1:
+ case NFA_MOPEN2:
+ case NFA_MOPEN3:
+ case NFA_MOPEN4:
+ case NFA_MOPEN5:
+ case NFA_MOPEN6:
+ case NFA_MOPEN7:
+ case NFA_MOPEN8:
+ case NFA_MOPEN9:
+#ifdef FEAT_SYN_HL
+ case NFA_ZOPEN:
+ case NFA_ZOPEN1:
+ case NFA_ZOPEN2:
+ case NFA_ZOPEN3:
+ case NFA_ZOPEN4:
+ case NFA_ZOPEN5:
+ case NFA_ZOPEN6:
+ case NFA_ZOPEN7:
+ case NFA_ZOPEN8:
+ case NFA_ZOPEN9:
+ case NFA_ZCLOSE:
+ case NFA_ZCLOSE1:
+ case NFA_ZCLOSE2:
+ case NFA_ZCLOSE3:
+ case NFA_ZCLOSE4:
+ case NFA_ZCLOSE5:
+ case NFA_ZCLOSE6:
+ case NFA_ZCLOSE7:
+ case NFA_ZCLOSE8:
+ case NFA_ZCLOSE9:
+#endif
+ case NFA_NOPEN:
+ case NFA_MCLOSE1:
+ case NFA_MCLOSE2:
+ case NFA_MCLOSE3:
+ case NFA_MCLOSE4:
+ case NFA_MCLOSE5:
+ case NFA_MCLOSE6:
+ case NFA_MCLOSE7:
+ case NFA_MCLOSE8:
+ case NFA_MCLOSE9:
+ case NFA_NCLOSE:
+ return failure_chance(state->out, depth + 1);
+
+ case NFA_BACKREF1:
+ case NFA_BACKREF2:
+ case NFA_BACKREF3:
+ case NFA_BACKREF4:
+ case NFA_BACKREF5:
+ case NFA_BACKREF6:
+ case NFA_BACKREF7:
+ case NFA_BACKREF8:
+ case NFA_BACKREF9:
+#ifdef FEAT_SYN_HL
+ case NFA_ZREF1:
+ case NFA_ZREF2:
+ case NFA_ZREF3:
+ case NFA_ZREF4:
+ case NFA_ZREF5:
+ case NFA_ZREF6:
+ case NFA_ZREF7:
+ case NFA_ZREF8:
+ case NFA_ZREF9:
+#endif
+ /* backreferences don't match in many places */
+ return 94;
+
+ case NFA_LNUM_GT:
+ case NFA_LNUM_LT:
+ case NFA_COL_GT:
+ case NFA_COL_LT:
+ case NFA_VCOL_GT:
+ case NFA_VCOL_LT:
+ case NFA_MARK_GT:
+ case NFA_MARK_LT:
+ case NFA_VISUAL:
+ /* before/after positions don't match very often */
+ return 85;
+
+ case NFA_LNUM:
+ return 90;
+
+ case NFA_CURSOR:
+ case NFA_COL:
+ case NFA_VCOL:
+ case NFA_MARK:
+ /* specific positions rarely match */
+ return 98;
+
+ case NFA_COMPOSING:
+ return 95;
+
+ default:
+ if (c > 0)
+ /* character match fails often */
+ return 95;
+ }
+
+ /* something else, includes character classes */
+ return 50;
+}
+
+/*
+ * Skip until the char "c" we know a match must start with.
+ */
+ static int
+skip_to_start(int c, colnr_T *colp)
+{
+ char_u *s;
+
+ /* Used often, do some work to avoid call overhead. */
+ if (!rex.reg_ic && !has_mbyte)
+ s = vim_strbyte(rex.line + *colp, c);
+ else
+ s = cstrchr(rex.line + *colp, c);
+ if (s == NULL)
+ return FAIL;
+ *colp = (int)(s - rex.line);
+ return OK;
+}
+
+/*
+ * Check for a match with match_text.
+ * Called after skip_to_start() has found regstart.
+ * Returns zero for no match, 1 for a match.
+ */
+ static long
+find_match_text(colnr_T startcol, int regstart, char_u *match_text)
+{
+ colnr_T col = startcol;
+ int c1, c2;
+ int len1, len2;
+ int match;
+
+ for (;;)
+ {
+ match = TRUE;
+ len2 = MB_CHAR2LEN(regstart); /* skip regstart */
+ for (len1 = 0; match_text[len1] != NUL; len1 += MB_CHAR2LEN(c1))
+ {
+ c1 = PTR2CHAR(match_text + len1);
+ c2 = PTR2CHAR(rex.line + col + len2);
+ if (c1 != c2 && (!rex.reg_ic || MB_TOLOWER(c1) != MB_TOLOWER(c2)))
+ {
+ match = FALSE;
+ break;
+ }
+ len2 += MB_CHAR2LEN(c2);
+ }
+ if (match
+ /* check that no composing char follows */
+ && !(enc_utf8
+ && utf_iscomposing(PTR2CHAR(rex.line + col + len2))))
+ {
+ cleanup_subexpr();
+ if (REG_MULTI)
+ {
+ rex.reg_startpos[0].lnum = rex.lnum;
+ rex.reg_startpos[0].col = col;
+ rex.reg_endpos[0].lnum = rex.lnum;
+ rex.reg_endpos[0].col = col + len2;
+ }
+ else
+ {
+ rex.reg_startp[0] = rex.line + col;
+ rex.reg_endp[0] = rex.line + col + len2;
+ }
+ return 1L;
+ }
+
+ /* Try finding regstart after the current match. */
+ col += MB_CHAR2LEN(regstart); /* skip regstart */
+ if (skip_to_start(regstart, &col) == FAIL)
+ break;
+ }
+ return 0L;
+}
+
+#ifdef FEAT_RELTIME
+ static int
+nfa_did_time_out()
+{
+ if (nfa_time_limit != NULL && profile_passed_limit(nfa_time_limit))
+ {
+ if (nfa_timed_out != NULL)
+ *nfa_timed_out = TRUE;
+ return TRUE;
+ }
+ return FALSE;
+}
+#endif
+
+/*
+ * Main matching routine.
+ *
+ * Run NFA to determine whether it matches rex.input.
+ *
+ * When "nfa_endp" is not NULL it is a required end-of-match position.
+ *
+ * Return TRUE if there is a match, FALSE otherwise.
+ * When there is a match "submatch" contains the positions.
+ * Note: Caller must ensure that: start != NULL.
+ */
+ static int
+nfa_regmatch(
+ nfa_regprog_T *prog,
+ nfa_state_T *start,
+ regsubs_T *submatch,
+ regsubs_T *m)
+{
+ int result;
+ size_t size = 0;
+ int flag = 0;
+ int go_to_nextline = FALSE;
+ nfa_thread_T *t;
+ nfa_list_T list[2];
+ int listidx;
+ nfa_list_T *thislist;
+ nfa_list_T *nextlist;
+ int *listids = NULL;
+ int listids_len = 0;
+ nfa_state_T *add_state;
+ int add_here;
+ int add_count;
+ int add_off = 0;
+ int toplevel = start->c == NFA_MOPEN;
+#ifdef NFA_REGEXP_DEBUG_LOG
+ FILE *debug;
+#endif
+
+ /* Some patterns may take a long time to match, especially when using
+ * recursive_regmatch(). Allow interrupting them with CTRL-C. */
+ fast_breakcheck();
+ if (got_int)
+ return FALSE;
+#ifdef FEAT_RELTIME
+ if (nfa_did_time_out())
+ return FALSE;
+#endif
+
+#ifdef NFA_REGEXP_DEBUG_LOG
+ debug = fopen(NFA_REGEXP_DEBUG_LOG, "a");
+ if (debug == NULL)
+ {
+ semsg("(NFA) COULD NOT OPEN %s!", NFA_REGEXP_DEBUG_LOG);
+ return FALSE;
+ }
+#endif
+ nfa_match = FALSE;
+
+ /* Allocate memory for the lists of nodes. */
+ size = (prog->nstate + 1) * sizeof(nfa_thread_T);
+
+ list[0].t = (nfa_thread_T *)lalloc(size, TRUE);
+ list[0].len = prog->nstate + 1;
+ list[1].t = (nfa_thread_T *)lalloc(size, TRUE);
+ list[1].len = prog->nstate + 1;
+ if (list[0].t == NULL || list[1].t == NULL)
+ goto theend;
+
+#ifdef ENABLE_LOG
+ log_fd = fopen(NFA_REGEXP_RUN_LOG, "a");
+ if (log_fd != NULL)
+ {
+ fprintf(log_fd, "**********************************\n");
+ nfa_set_code(start->c);
+ fprintf(log_fd, " RUNNING nfa_regmatch() starting with state %d, code %s\n",
+ abs(start->id), code);
+ fprintf(log_fd, "**********************************\n");
+ }
+ else
+ {
+ emsg(_(e_log_open_failed));
+ log_fd = stderr;
+ }
+#endif
+
+ thislist = &list[0];
+ thislist->n = 0;
+ thislist->has_pim = FALSE;
+ nextlist = &list[1];
+ nextlist->n = 0;
+ nextlist->has_pim = FALSE;
+#ifdef ENABLE_LOG
+ fprintf(log_fd, "(---) STARTSTATE first\n");
+#endif
+ thislist->id = rex.nfa_listid + 1;
+
+ /* Inline optimized code for addstate(thislist, start, m, 0) if we know
+ * it's the first MOPEN. */
+ if (toplevel)
+ {
+ if (REG_MULTI)
+ {
+ m->norm.list.multi[0].start_lnum = rex.lnum;
+ m->norm.list.multi[0].start_col = (colnr_T)(rex.input - rex.line);
+ }
+ else
+ m->norm.list.line[0].start = rex.input;
+ m->norm.in_use = 1;
+ addstate(thislist, start->out, m, NULL, 0);
+ }
+ else
+ addstate(thislist, start, m, NULL, 0);
+
+#define ADD_STATE_IF_MATCH(state) \
+ if (result) { \
+ add_state = state->out; \
+ add_off = clen; \
+ }
+
+ /*
+ * Run for each character.
+ */
+ for (;;)
+ {
+ int curc;
+ int clen;
+
+ if (has_mbyte)
+ {
+ curc = (*mb_ptr2char)(rex.input);
+ clen = (*mb_ptr2len)(rex.input);
+ }
+ else
+ {
+ curc = *rex.input;
+ clen = 1;
+ }
+ if (curc == NUL)
+ {
+ clen = 0;
+ go_to_nextline = FALSE;
+ }
+
+ /* swap lists */
+ thislist = &list[flag];
+ nextlist = &list[flag ^= 1];
+ nextlist->n = 0; /* clear nextlist */
+ nextlist->has_pim = FALSE;
+ ++rex.nfa_listid;
+ if (prog->re_engine == AUTOMATIC_ENGINE
+ && (rex.nfa_listid >= NFA_MAX_STATES
+# ifdef FEAT_EVAL
+ || nfa_fail_for_testing
+# endif
+ ))
+ {
+ /* too many states, retry with old engine */
+ nfa_match = NFA_TOO_EXPENSIVE;
+ goto theend;
+ }
+
+ thislist->id = rex.nfa_listid;
+ nextlist->id = rex.nfa_listid + 1;
+
+#ifdef ENABLE_LOG
+ fprintf(log_fd, "------------------------------------------\n");
+ fprintf(log_fd, ">>> Reginput is \"%s\"\n", rex.input);
+ fprintf(log_fd, ">>> Advanced one character... Current char is %c (code %d) \n", curc, (int)curc);
+ fprintf(log_fd, ">>> Thislist has %d states available: ", thislist->n);
+ {
+ int i;
+
+ for (i = 0; i < thislist->n; i++)
+ fprintf(log_fd, "%d ", abs(thislist->t[i].state->id));
+ }
+ fprintf(log_fd, "\n");
+#endif
+
+#ifdef NFA_REGEXP_DEBUG_LOG
+ fprintf(debug, "\n-------------------\n");
+#endif
+ /*
+ * If the state lists are empty we can stop.
+ */
+ if (thislist->n == 0)
+ break;
+
+ /* compute nextlist */
+ for (listidx = 0; listidx < thislist->n; ++listidx)
+ {
+ /* If the list gets very long there probably is something wrong.
+ * At least allow interrupting with CTRL-C. */
+ fast_breakcheck();
+ if (got_int)
+ break;
+#ifdef FEAT_RELTIME
+ if (nfa_time_limit != NULL && ++nfa_time_count == 20)
+ {
+ nfa_time_count = 0;
+ if (nfa_did_time_out())
+ break;
+ }
+#endif
+ t = &thislist->t[listidx];
+
+#ifdef NFA_REGEXP_DEBUG_LOG
+ nfa_set_code(t->state->c);
+ fprintf(debug, "%s, ", code);
+#endif
+#ifdef ENABLE_LOG
+ {
+ int col;
+
+ if (t->subs.norm.in_use <= 0)
+ col = -1;
+ else if (REG_MULTI)
+ col = t->subs.norm.list.multi[0].start_col;
+ else
+ col = (int)(t->subs.norm.list.line[0].start - rex.line);
+ nfa_set_code(t->state->c);
+ fprintf(log_fd, "(%d) char %d %s (start col %d)%s... \n",
+ abs(t->state->id), (int)t->state->c, code, col,
+ pim_info(&t->pim));
+ }
+#endif
+
+ /*
+ * Handle the possible codes of the current state.
+ * The most important is NFA_MATCH.
+ */
+ add_state = NULL;
+ add_here = FALSE;
+ add_count = 0;
+ switch (t->state->c)
+ {
+ case NFA_MATCH:
+ {
+ /* If the match ends before a composing characters and
+ * rex.reg_icombine is not set, that is not really a match. */
+ if (enc_utf8 && !rex.reg_icombine && utf_iscomposing(curc))
+ break;
+
+ nfa_match = TRUE;
+ copy_sub(&submatch->norm, &t->subs.norm);
+#ifdef FEAT_SYN_HL
+ if (rex.nfa_has_zsubexpr)
+ copy_sub(&submatch->synt, &t->subs.synt);
+#endif
+#ifdef ENABLE_LOG
+ log_subsexpr(&t->subs);
+#endif
+ /* Found the left-most longest match, do not look at any other
+ * states at this position. When the list of states is going
+ * to be empty quit without advancing, so that "rex.input" is
+ * correct. */
+ if (nextlist->n == 0)
+ clen = 0;
+ goto nextchar;
+ }
+
+ case NFA_END_INVISIBLE:
+ case NFA_END_INVISIBLE_NEG:
+ case NFA_END_PATTERN:
+ /*
+ * This is only encountered after a NFA_START_INVISIBLE or
+ * NFA_START_INVISIBLE_BEFORE node.
+ * They surround a zero-width group, used with "\@=", "\&",
+ * "\@!", "\@<=" and "\@<!".
+ * If we got here, it means that the current "invisible" group
+ * finished successfully, so return control to the parent
+ * nfa_regmatch(). For a look-behind match only when it ends
+ * in the position in "nfa_endp".
+ * Submatches are stored in *m, and used in the parent call.
+ */
+#ifdef ENABLE_LOG
+ if (nfa_endp != NULL)
+ {
+ if (REG_MULTI)
+ fprintf(log_fd, "Current lnum: %d, endp lnum: %d; current col: %d, endp col: %d\n",
+ (int)rex.lnum,
+ (int)nfa_endp->se_u.pos.lnum,
+ (int)(rex.input - rex.line),
+ nfa_endp->se_u.pos.col);
+ else
+ fprintf(log_fd, "Current col: %d, endp col: %d\n",
+ (int)(rex.input - rex.line),
+ (int)(nfa_endp->se_u.ptr - rex.input));
+ }
+#endif
+ /* If "nfa_endp" is set it's only a match if it ends at
+ * "nfa_endp" */
+ if (nfa_endp != NULL && (REG_MULTI
+ ? (rex.lnum != nfa_endp->se_u.pos.lnum
+ || (int)(rex.input - rex.line)
+ != nfa_endp->se_u.pos.col)
+ : rex.input != nfa_endp->se_u.ptr))
+ break;
+
+ /* do not set submatches for \@! */
+ if (t->state->c != NFA_END_INVISIBLE_NEG)
+ {
+ copy_sub(&m->norm, &t->subs.norm);
+#ifdef FEAT_SYN_HL
+ if (rex.nfa_has_zsubexpr)
+ copy_sub(&m->synt, &t->subs.synt);
+#endif
+ }
+#ifdef ENABLE_LOG
+ fprintf(log_fd, "Match found:\n");
+ log_subsexpr(m);
+#endif
+ nfa_match = TRUE;
+ /* See comment above at "goto nextchar". */
+ if (nextlist->n == 0)
+ clen = 0;
+ goto nextchar;
+
+ case NFA_START_INVISIBLE:
+ case NFA_START_INVISIBLE_FIRST:
+ case NFA_START_INVISIBLE_NEG:
+ case NFA_START_INVISIBLE_NEG_FIRST:
+ case NFA_START_INVISIBLE_BEFORE:
+ case NFA_START_INVISIBLE_BEFORE_FIRST:
+ case NFA_START_INVISIBLE_BEFORE_NEG:
+ case NFA_START_INVISIBLE_BEFORE_NEG_FIRST:
+ {
+#ifdef ENABLE_LOG
+ fprintf(log_fd, "Failure chance invisible: %d, what follows: %d\n",
+ failure_chance(t->state->out, 0),
+ failure_chance(t->state->out1->out, 0));
+#endif
+ /* Do it directly if there already is a PIM or when
+ * nfa_postprocess() detected it will work better. */
+ if (t->pim.result != NFA_PIM_UNUSED
+ || t->state->c == NFA_START_INVISIBLE_FIRST
+ || t->state->c == NFA_START_INVISIBLE_NEG_FIRST
+ || t->state->c == NFA_START_INVISIBLE_BEFORE_FIRST
+ || t->state->c == NFA_START_INVISIBLE_BEFORE_NEG_FIRST)
+ {
+ int in_use = m->norm.in_use;
+
+ /* Copy submatch info for the recursive call, opposite
+ * of what happens on success below. */
+ copy_sub_off(&m->norm, &t->subs.norm);
+#ifdef FEAT_SYN_HL
+ if (rex.nfa_has_zsubexpr)
+ copy_sub_off(&m->synt, &t->subs.synt);
+#endif
+
+ /*
+ * First try matching the invisible match, then what
+ * follows.
+ */
+ result = recursive_regmatch(t->state, NULL, prog,
+ submatch, m, &listids, &listids_len);
+ if (result == NFA_TOO_EXPENSIVE)
+ {
+ nfa_match = result;
+ goto theend;
+ }
+
+ /* for \@! and \@<! it is a match when the result is
+ * FALSE */
+ if (result != (t->state->c == NFA_START_INVISIBLE_NEG
+ || t->state->c == NFA_START_INVISIBLE_NEG_FIRST
+ || t->state->c
+ == NFA_START_INVISIBLE_BEFORE_NEG
+ || t->state->c
+ == NFA_START_INVISIBLE_BEFORE_NEG_FIRST))
+ {
+ /* Copy submatch info from the recursive call */
+ copy_sub_off(&t->subs.norm, &m->norm);
+#ifdef FEAT_SYN_HL
+ if (rex.nfa_has_zsubexpr)
+ copy_sub_off(&t->subs.synt, &m->synt);
+#endif
+ /* If the pattern has \ze and it matched in the
+ * sub pattern, use it. */
+ copy_ze_off(&t->subs.norm, &m->norm);
+
+ /* t->state->out1 is the corresponding
+ * END_INVISIBLE node; Add its out to the current
+ * list (zero-width match). */
+ add_here = TRUE;
+ add_state = t->state->out1->out;
+ }
+ m->norm.in_use = in_use;
+ }
+ else
+ {
+ nfa_pim_T pim;
+
+ /*
+ * First try matching what follows. Only if a match
+ * is found verify the invisible match matches. Add a
+ * nfa_pim_T to the following states, it contains info
+ * about the invisible match.
+ */
+ pim.state = t->state;
+ pim.result = NFA_PIM_TODO;
+ pim.subs.norm.in_use = 0;
+#ifdef FEAT_SYN_HL
+ pim.subs.synt.in_use = 0;
+#endif
+ if (REG_MULTI)
+ {
+ pim.end.pos.col = (int)(rex.input - rex.line);
+ pim.end.pos.lnum = rex.lnum;
+ }
+ else
+ pim.end.ptr = rex.input;
+
+ /* t->state->out1 is the corresponding END_INVISIBLE
+ * node; Add its out to the current list (zero-width
+ * match). */
+ addstate_here(thislist, t->state->out1->out, &t->subs,
+ &pim, &listidx);
+ }
+ }
+ break;
+
+ case NFA_START_PATTERN:
+ {
+ nfa_state_T *skip = NULL;
+#ifdef ENABLE_LOG
+ int skip_lid = 0;
+#endif
+
+ /* There is no point in trying to match the pattern if the
+ * output state is not going to be added to the list. */
+ if (state_in_list(nextlist, t->state->out1->out, &t->subs))
+ {
+ skip = t->state->out1->out;
+#ifdef ENABLE_LOG
+ skip_lid = nextlist->id;
+#endif
+ }
+ else if (state_in_list(nextlist,
+ t->state->out1->out->out, &t->subs))
+ {
+ skip = t->state->out1->out->out;
+#ifdef ENABLE_LOG
+ skip_lid = nextlist->id;
+#endif
+ }
+ else if (state_in_list(thislist,
+ t->state->out1->out->out, &t->subs))
+ {
+ skip = t->state->out1->out->out;
+#ifdef ENABLE_LOG
+ skip_lid = thislist->id;
+#endif
+ }
+ if (skip != NULL)
+ {
+#ifdef ENABLE_LOG
+ nfa_set_code(skip->c);
+ fprintf(log_fd, "> Not trying to match pattern, output state %d is already in list %d. char %d: %s\n",
+ abs(skip->id), skip_lid, skip->c, code);
+#endif
+ break;
+ }
+ /* Copy submatch info to the recursive call, opposite of what
+ * happens afterwards. */
+ copy_sub_off(&m->norm, &t->subs.norm);
+#ifdef FEAT_SYN_HL
+ if (rex.nfa_has_zsubexpr)
+ copy_sub_off(&m->synt, &t->subs.synt);
+#endif
+
+ /* First try matching the pattern. */
+ result = recursive_regmatch(t->state, NULL, prog,
+ submatch, m, &listids, &listids_len);
+ if (result == NFA_TOO_EXPENSIVE)
+ {
+ nfa_match = result;
+ goto theend;
+ }
+ if (result)
+ {
+ int bytelen;
+
+#ifdef ENABLE_LOG
+ fprintf(log_fd, "NFA_START_PATTERN matches:\n");
+ log_subsexpr(m);
+#endif
+ /* Copy submatch info from the recursive call */
+ copy_sub_off(&t->subs.norm, &m->norm);
+#ifdef FEAT_SYN_HL
+ if (rex.nfa_has_zsubexpr)
+ copy_sub_off(&t->subs.synt, &m->synt);
+#endif
+ /* Now we need to skip over the matched text and then
+ * continue with what follows. */
+ if (REG_MULTI)
+ /* TODO: multi-line match */
+ bytelen = m->norm.list.multi[0].end_col
+ - (int)(rex.input - rex.line);
+ else
+ bytelen = (int)(m->norm.list.line[0].end - rex.input);
+
+#ifdef ENABLE_LOG
+ fprintf(log_fd, "NFA_START_PATTERN length: %d\n", bytelen);
+#endif
+ if (bytelen == 0)
+ {
+ /* empty match, output of corresponding
+ * NFA_END_PATTERN/NFA_SKIP to be used at current
+ * position */
+ add_here = TRUE;
+ add_state = t->state->out1->out->out;
+ }
+ else if (bytelen <= clen)
+ {
+ /* match current character, output of corresponding
+ * NFA_END_PATTERN to be used at next position. */
+ add_state = t->state->out1->out->out;
+ add_off = clen;
+ }
+ else
+ {
+ /* skip over the matched characters, set character
+ * count in NFA_SKIP */
+ add_state = t->state->out1->out;
+ add_off = bytelen;
+ add_count = bytelen - clen;
+ }
+ }
+ break;
+ }
+
+ case NFA_BOL:
+ if (rex.input == rex.line)
+ {
+ add_here = TRUE;
+ add_state = t->state->out;
+ }
+ break;
+
+ case NFA_EOL:
+ if (curc == NUL)
+ {
+ add_here = TRUE;
+ add_state = t->state->out;
+ }
+ break;
+
+ case NFA_BOW:
+ result = TRUE;
+
+ if (curc == NUL)
+ result = FALSE;
+ else if (has_mbyte)
+ {
+ int this_class;
+
+ /* Get class of current and previous char (if it exists). */
+ this_class = mb_get_class_buf(rex.input, rex.reg_buf);
+ if (this_class <= 1)
+ result = FALSE;
+ else if (reg_prev_class() == this_class)
+ result = FALSE;
+ }
+ else if (!vim_iswordc_buf(curc, rex.reg_buf)
+ || (rex.input > rex.line
+ && vim_iswordc_buf(rex.input[-1], rex.reg_buf)))
+ result = FALSE;
+ if (result)
+ {
+ add_here = TRUE;
+ add_state = t->state->out;
+ }
+ break;
+
+ case NFA_EOW:
+ result = TRUE;
+ if (rex.input == rex.line)
+ result = FALSE;
+ else if (has_mbyte)
+ {
+ int this_class, prev_class;
+
+ /* Get class of current and previous char (if it exists). */
+ this_class = mb_get_class_buf(rex.input, rex.reg_buf);
+ prev_class = reg_prev_class();
+ if (this_class == prev_class
+ || prev_class == 0 || prev_class == 1)
+ result = FALSE;
+ }
+ else if (!vim_iswordc_buf(rex.input[-1], rex.reg_buf)
+ || (rex.input[0] != NUL
+ && vim_iswordc_buf(curc, rex.reg_buf)))
+ result = FALSE;
+ if (result)
+ {
+ add_here = TRUE;
+ add_state = t->state->out;
+ }
+ break;
+
+ case NFA_BOF:
+ if (rex.lnum == 0 && rex.input == rex.line
+ && (!REG_MULTI || rex.reg_firstlnum == 1))
+ {
+ add_here = TRUE;
+ add_state = t->state->out;
+ }
+ break;
+
+ case NFA_EOF:
+ if (rex.lnum == rex.reg_maxline && curc == NUL)
+ {
+ add_here = TRUE;
+ add_state = t->state->out;
+ }
+ break;
+
+ case NFA_COMPOSING:
+ {
+ int mc = curc;
+ int len = 0;
+ nfa_state_T *end;
+ nfa_state_T *sta;
+ int cchars[MAX_MCO];
+ int ccount = 0;
+ int j;
+
+ sta = t->state->out;
+ len = 0;
+ if (utf_iscomposing(sta->c))
+ {
+ /* Only match composing character(s), ignore base
+ * character. Used for ".{composing}" and "{composing}"
+ * (no preceding character). */
+ len += mb_char2len(mc);
+ }
+ if (rex.reg_icombine && len == 0)
+ {
+ /* If \Z was present, then ignore composing characters.
+ * When ignoring the base character this always matches. */
+ if (sta->c != curc)
+ result = FAIL;
+ else
+ result = OK;
+ while (sta->c != NFA_END_COMPOSING)
+ sta = sta->out;
+ }
+
+ /* Check base character matches first, unless ignored. */
+ else if (len > 0 || mc == sta->c)
+ {
+ if (len == 0)
+ {
+ len += mb_char2len(mc);
+ sta = sta->out;
+ }
+
+ /* We don't care about the order of composing characters.
+ * Get them into cchars[] first. */
+ while (len < clen)
+ {
+ mc = mb_ptr2char(rex.input + len);
+ cchars[ccount++] = mc;
+ len += mb_char2len(mc);
+ if (ccount == MAX_MCO)
+ break;
+ }
+
+ /* Check that each composing char in the pattern matches a
+ * composing char in the text. We do not check if all
+ * composing chars are matched. */
+ result = OK;
+ while (sta->c != NFA_END_COMPOSING)
+ {
+ for (j = 0; j < ccount; ++j)
+ if (cchars[j] == sta->c)
+ break;
+ if (j == ccount)
+ {
+ result = FAIL;
+ break;
+ }
+ sta = sta->out;
+ }
+ }
+ else
+ result = FAIL;
+
+ end = t->state->out1; /* NFA_END_COMPOSING */
+ ADD_STATE_IF_MATCH(end);
+ break;
+ }
+
+ case NFA_NEWL:
+ if (curc == NUL && !rex.reg_line_lbr && REG_MULTI
+ && rex.lnum <= rex.reg_maxline)
+ {
+ go_to_nextline = TRUE;
+ /* Pass -1 for the offset, which means taking the position
+ * at the start of the next line. */
+ add_state = t->state->out;
+ add_off = -1;
+ }
+ else if (curc == '\n' && rex.reg_line_lbr)
+ {
+ /* match \n as if it is an ordinary character */
+ add_state = t->state->out;
+ add_off = 1;
+ }
+ break;
+
+ case NFA_START_COLL:
+ case NFA_START_NEG_COLL:
+ {
+ /* What follows is a list of characters, until NFA_END_COLL.
+ * One of them must match or none of them must match. */
+ nfa_state_T *state;
+ int result_if_matched;
+ int c1, c2;
+
+ /* Never match EOL. If it's part of the collection it is added
+ * as a separate state with an OR. */
+ if (curc == NUL)
+ break;
+
+ state = t->state->out;
+ result_if_matched = (t->state->c == NFA_START_COLL);
+ for (;;)
+ {
+ if (state->c == NFA_END_COLL)
+ {
+ result = !result_if_matched;
+ break;
+ }
+ if (state->c == NFA_RANGE_MIN)
+ {
+ c1 = state->val;
+ state = state->out; /* advance to NFA_RANGE_MAX */
+ c2 = state->val;
+#ifdef ENABLE_LOG
+ fprintf(log_fd, "NFA_RANGE_MIN curc=%d c1=%d c2=%d\n",
+ curc, c1, c2);
+#endif
+ if (curc >= c1 && curc <= c2)
+ {
+ result = result_if_matched;
+ break;
+ }
+ if (rex.reg_ic)
+ {
+ int curc_low = MB_TOLOWER(curc);
+ int done = FALSE;
+
+ for ( ; c1 <= c2; ++c1)
+ if (MB_TOLOWER(c1) == curc_low)
+ {
+ result = result_if_matched;
+ done = TRUE;
+ break;
+ }
+ if (done)
+ break;
+ }
+ }
+ else if (state->c < 0 ? check_char_class(state->c, curc)
+ : (curc == state->c
+ || (rex.reg_ic && MB_TOLOWER(curc)
+ == MB_TOLOWER(state->c))))
+ {
+ result = result_if_matched;
+ break;
+ }
+ state = state->out;
+ }
+ if (result)
+ {
+ /* next state is in out of the NFA_END_COLL, out1 of
+ * START points to the END state */
+ add_state = t->state->out1->out;
+ add_off = clen;
+ }
+ break;
+ }
+
+ case NFA_ANY:
+ /* Any char except '\0', (end of input) does not match. */
+ if (curc > 0)
+ {
+ add_state = t->state->out;
+ add_off = clen;
+ }
+ break;
+
+ case NFA_ANY_COMPOSING:
+ /* On a composing character skip over it. Otherwise do
+ * nothing. Always matches. */
+ if (enc_utf8 && utf_iscomposing(curc))
+ {
+ add_off = clen;
+ }
+ else
+ {
+ add_here = TRUE;
+ add_off = 0;
+ }
+ add_state = t->state->out;
+ break;
+
+ /*
+ * Character classes like \a for alpha, \d for digit etc.
+ */
+ case NFA_IDENT: /* \i */
+ result = vim_isIDc(curc);
+ ADD_STATE_IF_MATCH(t->state);
+ break;
+
+ case NFA_SIDENT: /* \I */
+ result = !VIM_ISDIGIT(curc) && vim_isIDc(curc);
+ ADD_STATE_IF_MATCH(t->state);
+ break;
+
+ case NFA_KWORD: /* \k */
+ result = vim_iswordp_buf(rex.input, rex.reg_buf);
+ ADD_STATE_IF_MATCH(t->state);
+ break;
+
+ case NFA_SKWORD: /* \K */
+ result = !VIM_ISDIGIT(curc)
+ && vim_iswordp_buf(rex.input, rex.reg_buf);
+ ADD_STATE_IF_MATCH(t->state);
+ break;
+
+ case NFA_FNAME: /* \f */
+ result = vim_isfilec(curc);
+ ADD_STATE_IF_MATCH(t->state);
+ break;
+
+ case NFA_SFNAME: /* \F */
+ result = !VIM_ISDIGIT(curc) && vim_isfilec(curc);
+ ADD_STATE_IF_MATCH(t->state);
+ break;
+
+ case NFA_PRINT: /* \p */
+ result = vim_isprintc(PTR2CHAR(rex.input));
+ ADD_STATE_IF_MATCH(t->state);
+ break;
+
+ case NFA_SPRINT: /* \P */
+ result = !VIM_ISDIGIT(curc) && vim_isprintc(PTR2CHAR(rex.input));
+ ADD_STATE_IF_MATCH(t->state);
+ break;
+
+ case NFA_WHITE: /* \s */
+ result = VIM_ISWHITE(curc);
+ ADD_STATE_IF_MATCH(t->state);
+ break;
+
+ case NFA_NWHITE: /* \S */
+ result = curc != NUL && !VIM_ISWHITE(curc);
+ ADD_STATE_IF_MATCH(t->state);
+ break;
+
+ case NFA_DIGIT: /* \d */
+ result = ri_digit(curc);
+ ADD_STATE_IF_MATCH(t->state);
+ break;
+
+ case NFA_NDIGIT: /* \D */
+ result = curc != NUL && !ri_digit(curc);
+ ADD_STATE_IF_MATCH(t->state);
+ break;
+
+ case NFA_HEX: /* \x */
+ result = ri_hex(curc);
+ ADD_STATE_IF_MATCH(t->state);
+ break;
+
+ case NFA_NHEX: /* \X */
+ result = curc != NUL && !ri_hex(curc);
+ ADD_STATE_IF_MATCH(t->state);
+ break;
+
+ case NFA_OCTAL: /* \o */
+ result = ri_octal(curc);
+ ADD_STATE_IF_MATCH(t->state);
+ break;
+
+ case NFA_NOCTAL: /* \O */
+ result = curc != NUL && !ri_octal(curc);
+ ADD_STATE_IF_MATCH(t->state);
+ break;
+
+ case NFA_WORD: /* \w */
+ result = ri_word(curc);
+ ADD_STATE_IF_MATCH(t->state);
+ break;
+
+ case NFA_NWORD: /* \W */
+ result = curc != NUL && !ri_word(curc);
+ ADD_STATE_IF_MATCH(t->state);
+ break;
+
+ case NFA_HEAD: /* \h */
+ result = ri_head(curc);
+ ADD_STATE_IF_MATCH(t->state);
+ break;
+
+ case NFA_NHEAD: /* \H */
+ result = curc != NUL && !ri_head(curc);
+ ADD_STATE_IF_MATCH(t->state);
+ break;
+
+ case NFA_ALPHA: /* \a */
+ result = ri_alpha(curc);
+ ADD_STATE_IF_MATCH(t->state);
+ break;
+
+ case NFA_NALPHA: /* \A */
+ result = curc != NUL && !ri_alpha(curc);
+ ADD_STATE_IF_MATCH(t->state);
+ break;
+
+ case NFA_LOWER: /* \l */
+ result = ri_lower(curc);
+ ADD_STATE_IF_MATCH(t->state);
+ break;
+
+ case NFA_NLOWER: /* \L */
+ result = curc != NUL && !ri_lower(curc);
+ ADD_STATE_IF_MATCH(t->state);
+ break;
+
+ case NFA_UPPER: /* \u */
+ result = ri_upper(curc);
+ ADD_STATE_IF_MATCH(t->state);
+ break;
+
+ case NFA_NUPPER: /* \U */
+ result = curc != NUL && !ri_upper(curc);
+ ADD_STATE_IF_MATCH(t->state);
+ break;
+
+ case NFA_LOWER_IC: /* [a-z] */
+ result = ri_lower(curc) || (rex.reg_ic && ri_upper(curc));
+ ADD_STATE_IF_MATCH(t->state);
+ break;
+
+ case NFA_NLOWER_IC: /* [^a-z] */
+ result = curc != NUL
+ && !(ri_lower(curc) || (rex.reg_ic && ri_upper(curc)));
+ ADD_STATE_IF_MATCH(t->state);
+ break;
+
+ case NFA_UPPER_IC: /* [A-Z] */
+ result = ri_upper(curc) || (rex.reg_ic && ri_lower(curc));
+ ADD_STATE_IF_MATCH(t->state);
+ break;
+
+ case NFA_NUPPER_IC: /* ^[A-Z] */
+ result = curc != NUL
+ && !(ri_upper(curc) || (rex.reg_ic && ri_lower(curc)));
+ ADD_STATE_IF_MATCH(t->state);
+ break;
+
+ case NFA_BACKREF1:
+ case NFA_BACKREF2:
+ case NFA_BACKREF3:
+ case NFA_BACKREF4:
+ case NFA_BACKREF5:
+ case NFA_BACKREF6:
+ case NFA_BACKREF7:
+ case NFA_BACKREF8:
+ case NFA_BACKREF9:
+#ifdef FEAT_SYN_HL
+ case NFA_ZREF1:
+ case NFA_ZREF2:
+ case NFA_ZREF3:
+ case NFA_ZREF4:
+ case NFA_ZREF5:
+ case NFA_ZREF6:
+ case NFA_ZREF7:
+ case NFA_ZREF8:
+ case NFA_ZREF9:
+#endif
+ /* \1 .. \9 \z1 .. \z9 */
+ {
+ int subidx;
+ int bytelen;
+
+ if (t->state->c <= NFA_BACKREF9)
+ {
+ subidx = t->state->c - NFA_BACKREF1 + 1;
+ result = match_backref(&t->subs.norm, subidx, &bytelen);
+ }
+#ifdef FEAT_SYN_HL
+ else
+ {
+ subidx = t->state->c - NFA_ZREF1 + 1;
+ result = match_zref(subidx, &bytelen);
+ }
+#endif
+
+ if (result)
+ {
+ if (bytelen == 0)
+ {
+ /* empty match always works, output of NFA_SKIP to be
+ * used next */
+ add_here = TRUE;
+ add_state = t->state->out->out;
+ }
+ else if (bytelen <= clen)
+ {
+ /* match current character, jump ahead to out of
+ * NFA_SKIP */
+ add_state = t->state->out->out;
+ add_off = clen;
+ }
+ else
+ {
+ /* skip over the matched characters, set character
+ * count in NFA_SKIP */
+ add_state = t->state->out;
+ add_off = bytelen;
+ add_count = bytelen - clen;
+ }
+ }
+ break;
+ }
+ case NFA_SKIP:
+ /* character of previous matching \1 .. \9 or \@> */
+ if (t->count - clen <= 0)
+ {
+ /* end of match, go to what follows */
+ add_state = t->state->out;
+ add_off = clen;
+ }
+ else
+ {
+ /* add state again with decremented count */
+ add_state = t->state;
+ add_off = 0;
+ add_count = t->count - clen;
+ }
+ break;
+
+ case NFA_LNUM:
+ case NFA_LNUM_GT:
+ case NFA_LNUM_LT:
+ result = (REG_MULTI &&
+ nfa_re_num_cmp(t->state->val, t->state->c - NFA_LNUM,
+ (long_u)(rex.lnum + rex.reg_firstlnum)));
+ if (result)
+ {
+ add_here = TRUE;
+ add_state = t->state->out;
+ }
+ break;
+
+ case NFA_COL:
+ case NFA_COL_GT:
+ case NFA_COL_LT:
+ result = nfa_re_num_cmp(t->state->val, t->state->c - NFA_COL,
+ (long_u)(rex.input - rex.line) + 1);
+ if (result)
+ {
+ add_here = TRUE;
+ add_state = t->state->out;
+ }
+ break;
+
+ case NFA_VCOL:
+ case NFA_VCOL_GT:
+ case NFA_VCOL_LT:
+ {
+ int op = t->state->c - NFA_VCOL;
+ colnr_T col = (colnr_T)(rex.input - rex.line);
+ win_T *wp = rex.reg_win == NULL ? curwin : rex.reg_win;
+
+ /* Bail out quickly when there can't be a match, avoid the
+ * overhead of win_linetabsize() on long lines. */
+ if (op != 1 && col > t->state->val
+ * (has_mbyte ? MB_MAXBYTES : 1))
+ break;
+ result = FALSE;
+ if (op == 1 && col - 1 > t->state->val && col > 100)
+ {
+ int ts = wp->w_buffer->b_p_ts;
+
+ /* Guess that a character won't use more columns than
+ * 'tabstop', with a minimum of 4. */
+ if (ts < 4)
+ ts = 4;
+ result = col > t->state->val * ts;
+ }
+ if (!result)
+ result = nfa_re_num_cmp(t->state->val, op,
+ (long_u)win_linetabsize(wp, rex.line, col) + 1);
+ if (result)
+ {
+ add_here = TRUE;
+ add_state = t->state->out;
+ }
+ }
+ break;
+
+ case NFA_MARK:
+ case NFA_MARK_GT:
+ case NFA_MARK_LT:
+ {
+ pos_T *pos = getmark_buf(rex.reg_buf, t->state->val, FALSE);
+
+ /* Compare the mark position to the match position. */
+ result = (pos != NULL /* mark doesn't exist */
+ && pos->lnum > 0 /* mark isn't set in reg_buf */
+ && (pos->lnum == rex.lnum + rex.reg_firstlnum
+ ? (pos->col == (colnr_T)(rex.input - rex.line)
+ ? t->state->c == NFA_MARK
+ : (pos->col < (colnr_T)(rex.input - rex.line)
+ ? t->state->c == NFA_MARK_GT
+ : t->state->c == NFA_MARK_LT))
+ : (pos->lnum < rex.lnum + rex.reg_firstlnum
+ ? t->state->c == NFA_MARK_GT
+ : t->state->c == NFA_MARK_LT)));
+ if (result)
+ {
+ add_here = TRUE;
+ add_state = t->state->out;
+ }
+ break;
+ }
+
+ case NFA_CURSOR:
+ result = (rex.reg_win != NULL
+ && (rex.lnum + rex.reg_firstlnum
+ == rex.reg_win->w_cursor.lnum)
+ && ((colnr_T)(rex.input - rex.line)
+ == rex.reg_win->w_cursor.col));
+ if (result)
+ {
+ add_here = TRUE;
+ add_state = t->state->out;
+ }
+ break;
+
+ case NFA_VISUAL:
+ result = reg_match_visual();
+ if (result)
+ {
+ add_here = TRUE;
+ add_state = t->state->out;
+ }
+ break;
+
+ case NFA_MOPEN1:
+ case NFA_MOPEN2:
+ case NFA_MOPEN3:
+ case NFA_MOPEN4:
+ case NFA_MOPEN5:
+ case NFA_MOPEN6:
+ case NFA_MOPEN7:
+ case NFA_MOPEN8:
+ case NFA_MOPEN9:
+#ifdef FEAT_SYN_HL
+ case NFA_ZOPEN:
+ case NFA_ZOPEN1:
+ case NFA_ZOPEN2:
+ case NFA_ZOPEN3:
+ case NFA_ZOPEN4:
+ case NFA_ZOPEN5:
+ case NFA_ZOPEN6:
+ case NFA_ZOPEN7:
+ case NFA_ZOPEN8:
+ case NFA_ZOPEN9:
+#endif
+ case NFA_NOPEN:
+ case NFA_ZSTART:
+ /* These states are only added to be able to bail out when
+ * they are added again, nothing is to be done. */
+ break;
+
+ default: /* regular character */
+ {
+ int c = t->state->c;
+
+#ifdef DEBUG
+ if (c < 0)
+ siemsg("INTERNAL: Negative state char: %ld", c);
+#endif
+ result = (c == curc);
+
+ if (!result && rex.reg_ic)
+ result = MB_TOLOWER(c) == MB_TOLOWER(curc);
+ /* If rex.reg_icombine is not set only skip over the character
+ * itself. When it is set skip over composing characters. */
+ if (result && enc_utf8 && !rex.reg_icombine)
+ clen = utf_ptr2len(rex.input);
+ ADD_STATE_IF_MATCH(t->state);
+ break;
+ }
+
+ } /* switch (t->state->c) */
+
+ if (add_state != NULL)
+ {
+ nfa_pim_T *pim;
+ nfa_pim_T pim_copy;
+
+ if (t->pim.result == NFA_PIM_UNUSED)
+ pim = NULL;
+ else
+ pim = &t->pim;
+
+ /* Handle the postponed invisible match if the match might end
+ * without advancing and before the end of the line. */
+ if (pim != NULL && (clen == 0 || match_follows(add_state, 0)))
+ {
+ if (pim->result == NFA_PIM_TODO)
+ {
+#ifdef ENABLE_LOG
+ fprintf(log_fd, "\n");
+ fprintf(log_fd, "==================================\n");
+ fprintf(log_fd, "Postponed recursive nfa_regmatch()\n");
+ fprintf(log_fd, "\n");
+#endif
+ result = recursive_regmatch(pim->state, pim,
+ prog, submatch, m, &listids, &listids_len);
+ pim->result = result ? NFA_PIM_MATCH : NFA_PIM_NOMATCH;
+ /* for \@! and \@<! it is a match when the result is
+ * FALSE */
+ if (result != (pim->state->c == NFA_START_INVISIBLE_NEG
+ || pim->state->c == NFA_START_INVISIBLE_NEG_FIRST
+ || pim->state->c
+ == NFA_START_INVISIBLE_BEFORE_NEG
+ || pim->state->c
+ == NFA_START_INVISIBLE_BEFORE_NEG_FIRST))
+ {
+ /* Copy submatch info from the recursive call */
+ copy_sub_off(&pim->subs.norm, &m->norm);
+#ifdef FEAT_SYN_HL
+ if (rex.nfa_has_zsubexpr)
+ copy_sub_off(&pim->subs.synt, &m->synt);
+#endif
+ }
+ }
+ else
+ {
+ result = (pim->result == NFA_PIM_MATCH);
+#ifdef ENABLE_LOG
+ fprintf(log_fd, "\n");
+ fprintf(log_fd, "Using previous recursive nfa_regmatch() result, result == %d\n", pim->result);
+ fprintf(log_fd, "MATCH = %s\n", result == TRUE ? "OK" : "FALSE");
+ fprintf(log_fd, "\n");
+#endif
+ }
+
+ /* for \@! and \@<! it is a match when result is FALSE */
+ if (result != (pim->state->c == NFA_START_INVISIBLE_NEG
+ || pim->state->c == NFA_START_INVISIBLE_NEG_FIRST
+ || pim->state->c
+ == NFA_START_INVISIBLE_BEFORE_NEG
+ || pim->state->c
+ == NFA_START_INVISIBLE_BEFORE_NEG_FIRST))
+ {
+ /* Copy submatch info from the recursive call */
+ copy_sub_off(&t->subs.norm, &pim->subs.norm);
+#ifdef FEAT_SYN_HL
+ if (rex.nfa_has_zsubexpr)
+ copy_sub_off(&t->subs.synt, &pim->subs.synt);
+#endif
+ }
+ else
+ /* look-behind match failed, don't add the state */
+ continue;
+
+ /* Postponed invisible match was handled, don't add it to
+ * following states. */
+ pim = NULL;
+ }
+
+ /* If "pim" points into l->t it will become invalid when
+ * adding the state causes the list to be reallocated. Make a
+ * local copy to avoid that. */
+ if (pim == &t->pim)
+ {
+ copy_pim(&pim_copy, pim);
+ pim = &pim_copy;
+ }
+
+ if (add_here)
+ addstate_here(thislist, add_state, &t->subs, pim, &listidx);
+ else
+ {
+ addstate(nextlist, add_state, &t->subs, pim, add_off);
+ if (add_count > 0)
+ nextlist->t[nextlist->n - 1].count = add_count;
+ }
+ }
+
+ } /* for (thislist = thislist; thislist->state; thislist++) */
+
+ /* Look for the start of a match in the current position by adding the
+ * start state to the list of states.
+ * The first found match is the leftmost one, thus the order of states
+ * matters!
+ * Do not add the start state in recursive calls of nfa_regmatch(),
+ * because recursive calls should only start in the first position.
+ * Unless "nfa_endp" is not NULL, then we match the end position.
+ * Also don't start a match past the first line. */
+ if (nfa_match == FALSE
+ && ((toplevel
+ && rex.lnum == 0
+ && clen != 0
+ && (rex.reg_maxcol == 0
+ || (colnr_T)(rex.input - rex.line) < rex.reg_maxcol))
+ || (nfa_endp != NULL
+ && (REG_MULTI
+ ? (rex.lnum < nfa_endp->se_u.pos.lnum
+ || (rex.lnum == nfa_endp->se_u.pos.lnum
+ && (int)(rex.input - rex.line)
+ < nfa_endp->se_u.pos.col))
+ : rex.input < nfa_endp->se_u.ptr))))
+ {
+#ifdef ENABLE_LOG
+ fprintf(log_fd, "(---) STARTSTATE\n");
+#endif
+ /* Inline optimized code for addstate() if we know the state is
+ * the first MOPEN. */
+ if (toplevel)
+ {
+ int add = TRUE;
+ int c;
+
+ if (prog->regstart != NUL && clen != 0)
+ {
+ if (nextlist->n == 0)
+ {
+ colnr_T col = (colnr_T)(rex.input - rex.line) + clen;
+
+ /* Nextlist is empty, we can skip ahead to the
+ * character that must appear at the start. */
+ if (skip_to_start(prog->regstart, &col) == FAIL)
+ break;
+#ifdef ENABLE_LOG
+ fprintf(log_fd, " Skipping ahead %d bytes to regstart\n",
+ col - ((colnr_T)(rex.input - rex.line) + clen));
+#endif
+ rex.input = rex.line + col - clen;
+ }
+ else
+ {
+ /* Checking if the required start character matches is
+ * cheaper than adding a state that won't match. */
+ c = PTR2CHAR(rex.input + clen);
+ if (c != prog->regstart && (!rex.reg_ic
+ || MB_TOLOWER(c) != MB_TOLOWER(prog->regstart)))
+ {
+#ifdef ENABLE_LOG
+ fprintf(log_fd, " Skipping start state, regstart does not match\n");
+#endif
+ add = FALSE;
+ }
+ }
+ }
+
+ if (add)
+ {
+ if (REG_MULTI)
+ m->norm.list.multi[0].start_col =
+ (colnr_T)(rex.input - rex.line) + clen;
+ else
+ m->norm.list.line[0].start = rex.input + clen;
+ addstate(nextlist, start->out, m, NULL, clen);
+ }
+ }
+ else
+ addstate(nextlist, start, m, NULL, clen);
+ }
+
+#ifdef ENABLE_LOG
+ fprintf(log_fd, ">>> Thislist had %d states available: ", thislist->n);
+ {
+ int i;
+
+ for (i = 0; i < thislist->n; i++)
+ fprintf(log_fd, "%d ", abs(thislist->t[i].state->id));
+ }
+ fprintf(log_fd, "\n");
+#endif
+
+nextchar:
+ /* Advance to the next character, or advance to the next line, or
+ * finish. */
+ if (clen != 0)
+ rex.input += clen;
+ else if (go_to_nextline || (nfa_endp != NULL && REG_MULTI
+ && rex.lnum < nfa_endp->se_u.pos.lnum))
+ reg_nextline();
+ else
+ break;
+
+ /* Allow interrupting with CTRL-C. */
+ line_breakcheck();
+ if (got_int)
+ break;
+#ifdef FEAT_RELTIME
+ /* Check for timeout once in a twenty times to avoid overhead. */
+ if (nfa_time_limit != NULL && ++nfa_time_count == 20)
+ {
+ nfa_time_count = 0;
+ if (nfa_did_time_out())
+ break;
+ }
+#endif
+ }
+
+#ifdef ENABLE_LOG
+ if (log_fd != stderr)
+ fclose(log_fd);
+ log_fd = NULL;
+#endif
+
+theend:
+ /* Free memory */
+ vim_free(list[0].t);
+ vim_free(list[1].t);
+ vim_free(listids);
+#undef ADD_STATE_IF_MATCH
+#ifdef NFA_REGEXP_DEBUG_LOG
+ fclose(debug);
+#endif
+
+ return nfa_match;
+}
+
+/*
+ * Try match of "prog" with at rex.line["col"].
+ * Returns <= 0 for failure, number of lines contained in the match otherwise.
+ */
+ static long
+nfa_regtry(
+ nfa_regprog_T *prog,
+ colnr_T col,
+ proftime_T *tm UNUSED, /* timeout limit or NULL */
+ int *timed_out UNUSED) /* flag set on timeout or NULL */
+{
+ int i;
+ regsubs_T subs, m;
+ nfa_state_T *start = prog->start;
+ int result;
+#ifdef ENABLE_LOG
+ FILE *f;
+#endif
+
+ rex.input = rex.line + col;
+#ifdef FEAT_RELTIME
+ nfa_time_limit = tm;
+ nfa_timed_out = timed_out;
+ nfa_time_count = 0;
+#endif
+
+#ifdef ENABLE_LOG
+ f = fopen(NFA_REGEXP_RUN_LOG, "a");
+ if (f != NULL)
+ {
+ fprintf(f, "\n\n\t=======================================================\n");
+#ifdef DEBUG
+ fprintf(f, "\tRegexp is \"%s\"\n", nfa_regengine.expr);
+#endif
+ fprintf(f, "\tInput text is \"%s\" \n", rex.input);
+ fprintf(f, "\t=======================================================\n\n");
+ nfa_print_state(f, start);
+ fprintf(f, "\n\n");
+ fclose(f);
+ }
+ else
+ emsg("Could not open temporary log file for writing");
+#endif
+
+ clear_sub(&subs.norm);
+ clear_sub(&m.norm);
+#ifdef FEAT_SYN_HL
+ clear_sub(&subs.synt);
+ clear_sub(&m.synt);
+#endif
+
+ result = nfa_regmatch(prog, start, &subs, &m);
+ if (result == FALSE)
+ return 0;
+ else if (result == NFA_TOO_EXPENSIVE)
+ return result;
+
+ cleanup_subexpr();
+ if (REG_MULTI)
+ {
+ for (i = 0; i < subs.norm.in_use; i++)
+ {
+ rex.reg_startpos[i].lnum = subs.norm.list.multi[i].start_lnum;
+ rex.reg_startpos[i].col = subs.norm.list.multi[i].start_col;
+
+ rex.reg_endpos[i].lnum = subs.norm.list.multi[i].end_lnum;
+ rex.reg_endpos[i].col = subs.norm.list.multi[i].end_col;
+ }
+
+ if (rex.reg_startpos[0].lnum < 0)
+ {
+ rex.reg_startpos[0].lnum = 0;
+ rex.reg_startpos[0].col = col;
+ }
+ if (rex.reg_endpos[0].lnum < 0)
+ {
+ /* pattern has a \ze but it didn't match, use current end */
+ rex.reg_endpos[0].lnum = rex.lnum;
+ rex.reg_endpos[0].col = (int)(rex.input - rex.line);
+ }
+ else
+ /* Use line number of "\ze". */
+ rex.lnum = rex.reg_endpos[0].lnum;
+ }
+ else
+ {
+ for (i = 0; i < subs.norm.in_use; i++)
+ {
+ rex.reg_startp[i] = subs.norm.list.line[i].start;
+ rex.reg_endp[i] = subs.norm.list.line[i].end;
+ }
+
+ if (rex.reg_startp[0] == NULL)
+ rex.reg_startp[0] = rex.line + col;
+ if (rex.reg_endp[0] == NULL)
+ rex.reg_endp[0] = rex.input;
+ }
+
+#ifdef FEAT_SYN_HL
+ /* Package any found \z(...\) matches for export. Default is none. */
+ unref_extmatch(re_extmatch_out);
+ re_extmatch_out = NULL;
+
+ if (prog->reghasz == REX_SET)
+ {
+ cleanup_zsubexpr();
+ re_extmatch_out = make_extmatch();
+ /* Loop over \z1, \z2, etc. There is no \z0. */
+ for (i = 1; i < subs.synt.in_use; i++)
+ {
+ if (REG_MULTI)
+ {
+ struct multipos *mpos = &subs.synt.list.multi[i];
+
+ /* Only accept single line matches that are valid. */
+ if (mpos->start_lnum >= 0
+ && mpos->start_lnum == mpos->end_lnum
+ && mpos->end_col >= mpos->start_col)
+ re_extmatch_out->matches[i] =
+ vim_strnsave(reg_getline(mpos->start_lnum)
+ + mpos->start_col,
+ mpos->end_col - mpos->start_col);
+ }
+ else
+ {
+ struct linepos *lpos = &subs.synt.list.line[i];
+
+ if (lpos->start != NULL && lpos->end != NULL)
+ re_extmatch_out->matches[i] =
+ vim_strnsave(lpos->start,
+ (int)(lpos->end - lpos->start));
+ }
+ }
+ }
+#endif
+
+ return 1 + rex.lnum;
+}
+
+/*
+ * Match a regexp against a string ("line" points to the string) or multiple
+ * lines ("line" is NULL, use reg_getline()).
+ *
+ * Returns <= 0 for failure, number of lines contained in the match otherwise.
+ */
+ static long
+nfa_regexec_both(
+ char_u *line,
+ colnr_T startcol, /* column to start looking for match */
+ proftime_T *tm, /* timeout limit or NULL */
+ int *timed_out) /* flag set on timeout or NULL */
+{
+ nfa_regprog_T *prog;
+ long retval = 0L;
+ int i;
+ colnr_T col = startcol;
+
+ if (REG_MULTI)
+ {
+ prog = (nfa_regprog_T *)rex.reg_mmatch->regprog;
+ line = reg_getline((linenr_T)0); /* relative to the cursor */
+ rex.reg_startpos = rex.reg_mmatch->startpos;
+ rex.reg_endpos = rex.reg_mmatch->endpos;
+ }
+ else
+ {
+ prog = (nfa_regprog_T *)rex.reg_match->regprog;
+ rex.reg_startp = rex.reg_match->startp;
+ rex.reg_endp = rex.reg_match->endp;
+ }
+
+ /* Be paranoid... */
+ if (prog == NULL || line == NULL)
+ {
+ emsg(_(e_null));
+ goto theend;
+ }
+
+ /* If pattern contains "\c" or "\C": overrule value of rex.reg_ic */
+ if (prog->regflags & RF_ICASE)
+ rex.reg_ic = TRUE;
+ else if (prog->regflags & RF_NOICASE)
+ rex.reg_ic = FALSE;
+
+ /* If pattern contains "\Z" overrule value of rex.reg_icombine */
+ if (prog->regflags & RF_ICOMBINE)
+ rex.reg_icombine = TRUE;
+
+ rex.line = line;
+ rex.lnum = 0; /* relative to line */
+
+ rex.nfa_has_zend = prog->has_zend;
+ rex.nfa_has_backref = prog->has_backref;
+ rex.nfa_nsubexpr = prog->nsubexp;
+ rex.nfa_listid = 1;
+ rex.nfa_alt_listid = 2;
+#ifdef DEBUG
+ nfa_regengine.expr = prog->pattern;
+#endif
+
+ if (prog->reganch && col > 0)
+ return 0L;
+
+ rex.need_clear_subexpr = TRUE;
+#ifdef FEAT_SYN_HL
+ /* Clear the external match subpointers if necessary. */
+ if (prog->reghasz == REX_SET)
+ {
+ rex.nfa_has_zsubexpr = TRUE;
+ rex.need_clear_zsubexpr = TRUE;
+ }
+ else
+ {
+ rex.nfa_has_zsubexpr = FALSE;
+ rex.need_clear_zsubexpr = FALSE;
+ }
+#endif
+
+ if (prog->regstart != NUL)
+ {
+ /* Skip ahead until a character we know the match must start with.
+ * When there is none there is no match. */
+ if (skip_to_start(prog->regstart, &col) == FAIL)
+ return 0L;
+
+ /* If match_text is set it contains the full text that must match.
+ * Nothing else to try. Doesn't handle combining chars well. */
+ if (prog->match_text != NULL && !rex.reg_icombine)
+ return find_match_text(col, prog->regstart, prog->match_text);
+ }
+
+ /* If the start column is past the maximum column: no need to try. */
+ if (rex.reg_maxcol > 0 && col >= rex.reg_maxcol)
+ goto theend;
+
+ // Set the "nstate" used by nfa_regcomp() to zero to trigger an error when
+ // it's accidentally used during execution.
+ nstate = 0;
+ for (i = 0; i < prog->nstate; ++i)
+ {
+ prog->state[i].id = i;
+ prog->state[i].lastlist[0] = 0;
+ prog->state[i].lastlist[1] = 0;
+ }
+
+ retval = nfa_regtry(prog, col, tm, timed_out);
+
+#ifdef DEBUG
+ nfa_regengine.expr = NULL;
+#endif
+
+theend:
+ return retval;
+}
+
+/*
+ * Compile a regular expression into internal code for the NFA matcher.
+ * Returns the program in allocated space. Returns NULL for an error.
+ */
+ static regprog_T *
+nfa_regcomp(char_u *expr, int re_flags)
+{
+ nfa_regprog_T *prog = NULL;
+ size_t prog_size;
+ int *postfix;
+
+ if (expr == NULL)
+ return NULL;
+
+#ifdef DEBUG
+ nfa_regengine.expr = expr;
+#endif
+ nfa_re_flags = re_flags;
+
+ init_class_tab();
+
+ if (nfa_regcomp_start(expr, re_flags) == FAIL)
+ return NULL;
+
+ /* Build postfix form of the regexp. Needed to build the NFA
+ * (and count its size). */
+ postfix = re2post();
+ if (postfix == NULL)
+ {
+ /* TODO: only give this error for debugging? */
+ if (post_ptr >= post_end)
+ siemsg("Internal error: estimated max number of states insufficient: %ld", post_end - post_start);
+ goto fail; /* Cascaded (syntax?) error */
+ }
+
+ /*
+ * In order to build the NFA, we parse the input regexp twice:
+ * 1. first pass to count size (so we can allocate space)
+ * 2. second to emit code
+ */
+#ifdef ENABLE_LOG
+ {
+ FILE *f = fopen(NFA_REGEXP_RUN_LOG, "a");
+
+ if (f != NULL)
+ {
+ fprintf(f, "\n*****************************\n\n\n\n\tCompiling regexp \"%s\"... hold on !\n", expr);
+ fclose(f);
+ }
+ }
+#endif
+
+ /*
+ * PASS 1
+ * Count number of NFA states in "nstate". Do not build the NFA.
+ */
+ post2nfa(postfix, post_ptr, TRUE);
+
+ /* allocate the regprog with space for the compiled regexp */
+ prog_size = sizeof(nfa_regprog_T) + sizeof(nfa_state_T) * (nstate - 1);
+ prog = (nfa_regprog_T *)lalloc(prog_size, TRUE);
+ if (prog == NULL)
+ goto fail;
+ state_ptr = prog->state;
+ prog->re_in_use = FALSE;
+
+ /*
+ * PASS 2
+ * Build the NFA
+ */
+ prog->start = post2nfa(postfix, post_ptr, FALSE);
+ if (prog->start == NULL)
+ goto fail;
+
+ prog->regflags = regflags;
+ prog->engine = &nfa_regengine;
+ prog->nstate = nstate;
+ prog->has_zend = rex.nfa_has_zend;
+ prog->has_backref = rex.nfa_has_backref;
+ prog->nsubexp = regnpar;
+
+ nfa_postprocess(prog);
+
+ prog->reganch = nfa_get_reganch(prog->start, 0);
+ prog->regstart = nfa_get_regstart(prog->start, 0);
+ prog->match_text = nfa_get_match_text(prog->start);
+
+#ifdef ENABLE_LOG
+ nfa_postfix_dump(expr, OK);
+ nfa_dump(prog);
+#endif
+#ifdef FEAT_SYN_HL
+ /* Remember whether this pattern has any \z specials in it. */
+ prog->reghasz = re_has_z;
+#endif
+ prog->pattern = vim_strsave(expr);
+#ifdef DEBUG
+ nfa_regengine.expr = NULL;
+#endif
+
+out:
+ VIM_CLEAR(post_start);
+ post_ptr = post_end = NULL;
+ state_ptr = NULL;
+ return (regprog_T *)prog;
+
+fail:
+ VIM_CLEAR(prog);
+#ifdef ENABLE_LOG
+ nfa_postfix_dump(expr, FAIL);
+#endif
+#ifdef DEBUG
+ nfa_regengine.expr = NULL;
+#endif
+ goto out;
+}
+
+/*
+ * Free a compiled regexp program, returned by nfa_regcomp().
+ */
+ static void
+nfa_regfree(regprog_T *prog)
+{
+ if (prog != NULL)
+ {
+ vim_free(((nfa_regprog_T *)prog)->match_text);
+ vim_free(((nfa_regprog_T *)prog)->pattern);
+ vim_free(prog);
+ }
+}
+
+/*
+ * Match a regexp against a string.
+ * "rmp->regprog" is a compiled regexp as returned by nfa_regcomp().
+ * Uses curbuf for line count and 'iskeyword'.
+ * If "line_lbr" is TRUE consider a "\n" in "line" to be a line break.
+ *
+ * Returns <= 0 for failure, number of lines contained in the match otherwise.
+ */
+ static int
+nfa_regexec_nl(
+ regmatch_T *rmp,
+ char_u *line, /* string to match against */
+ colnr_T col, /* column to start looking for match */
+ int line_lbr)
+{
+ rex.reg_match = rmp;
+ rex.reg_mmatch = NULL;
+ rex.reg_maxline = 0;
+ rex.reg_line_lbr = line_lbr;
+ rex.reg_buf = curbuf;
+ rex.reg_win = NULL;
+ rex.reg_ic = rmp->rm_ic;
+ rex.reg_icombine = FALSE;
+ rex.reg_maxcol = 0;
+ return nfa_regexec_both(line, col, NULL, NULL);
+}
+
+
+/*
+ * Match a regexp against multiple lines.
+ * "rmp->regprog" is a compiled regexp as returned by vim_regcomp().
+ * Uses curbuf for line count and 'iskeyword'.
+ *
+ * Return <= 0 if there is no match. Return number of lines contained in the
+ * match otherwise.
+ *
+ * Note: the body is the same as bt_regexec() except for nfa_regexec_both()
+ *
+ * ! Also NOTE : match may actually be in another line. e.g.:
+ * when r.e. is \nc, cursor is at 'a' and the text buffer looks like
+ *
+ * +-------------------------+
+ * |a |
+ * |b |
+ * |c |
+ * | |
+ * +-------------------------+
+ *
+ * then nfa_regexec_multi() returns 3. while the original
+ * vim_regexec_multi() returns 0 and a second call at line 2 will return 2.
+ *
+ * FIXME if this behavior is not compatible.
+ */
+ static long
+nfa_regexec_multi(
+ regmmatch_T *rmp,
+ win_T *win, /* window in which to search or NULL */
+ buf_T *buf, /* buffer in which to search */
+ linenr_T lnum, /* nr of line to start looking for match */
+ colnr_T col, /* column to start looking for match */
+ proftime_T *tm, /* timeout limit or NULL */
+ int *timed_out) /* flag set on timeout or NULL */
+{
+ rex.reg_match = NULL;
+ rex.reg_mmatch = rmp;
+ rex.reg_buf = buf;
+ rex.reg_win = win;
+ rex.reg_firstlnum = lnum;
+ rex.reg_maxline = rex.reg_buf->b_ml.ml_line_count - lnum;
+ rex.reg_line_lbr = FALSE;
+ rex.reg_ic = rmp->rmm_ic;
+ rex.reg_icombine = FALSE;
+ rex.reg_maxcol = rmp->rmm_maxcol;
+
+ return nfa_regexec_both(NULL, col, tm, timed_out);
+}
+
+#ifdef DEBUG
+# undef ENABLE_LOG
+#endif
diff --git a/src/screen.c b/src/screen.c
new file mode 100644
index 0000000..caf6e2c
--- /dev/null
+++ b/src/screen.c
@@ -0,0 +1,11034 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * screen.c: code for displaying on the screen
+ *
+ * Output to the screen (console, terminal emulator or GUI window) is minimized
+ * by remembering what is already on the screen, and only updating the parts
+ * that changed.
+ *
+ * ScreenLines[off] Contains a copy of the whole screen, as it is currently
+ * displayed (excluding text written by external commands).
+ * ScreenAttrs[off] Contains the associated attributes.
+ * LineOffset[row] Contains the offset into ScreenLines*[] and ScreenAttrs[]
+ * for each line.
+ * LineWraps[row] Flag for each line whether it wraps to the next line.
+ *
+ * For double-byte characters, two consecutive bytes in ScreenLines[] can form
+ * one character which occupies two display cells.
+ * For UTF-8 a multi-byte character is converted to Unicode and stored in
+ * ScreenLinesUC[]. ScreenLines[] contains the first byte only. For an ASCII
+ * character without composing chars ScreenLinesUC[] will be 0 and
+ * ScreenLinesC[][] is not used. When the character occupies two display
+ * cells the next byte in ScreenLines[] is 0.
+ * ScreenLinesC[][] contain up to 'maxcombine' composing characters
+ * (drawn on top of the first character). There is 0 after the last one used.
+ * ScreenLines2[] is only used for euc-jp to store the second byte if the
+ * first byte is 0x8e (single-width character).
+ *
+ * The screen_*() functions write to the screen and handle updating
+ * ScreenLines[].
+ *
+ * update_screen() is the function that updates all windows and status lines.
+ * It is called form the main loop when must_redraw is non-zero. It may be
+ * called from other places when an immediate screen update is needed.
+ *
+ * The part of the buffer that is displayed in a window is set with:
+ * - w_topline (first buffer line in window)
+ * - w_topfill (filler lines above the first line)
+ * - w_leftcol (leftmost window cell in window),
+ * - w_skipcol (skipped window cells of first line)
+ *
+ * Commands that only move the cursor around in a window, do not need to take
+ * action to update the display. The main loop will check if w_topline is
+ * valid and update it (scroll the window) when needed.
+ *
+ * Commands that scroll a window change w_topline and must call
+ * check_cursor() to move the cursor into the visible part of the window, and
+ * call redraw_later(VALID) to have the window displayed by update_screen()
+ * later.
+ *
+ * Commands that change text in the buffer must call changed_bytes() or
+ * changed_lines() to mark the area that changed and will require updating
+ * later. The main loop will call update_screen(), which will update each
+ * window that shows the changed buffer. This assumes text above the change
+ * can remain displayed as it is. Text after the change may need updating for
+ * scrolling, folding and syntax highlighting.
+ *
+ * Commands that change how a window is displayed (e.g., setting 'list') or
+ * invalidate the contents of a window in another way (e.g., change fold
+ * settings), must call redraw_later(NOT_VALID) to have the whole window
+ * redisplayed by update_screen() later.
+ *
+ * Commands that change how a buffer is displayed (e.g., setting 'tabstop')
+ * must call redraw_curbuf_later(NOT_VALID) to have all the windows for the
+ * buffer redisplayed by update_screen() later.
+ *
+ * Commands that change highlighting and possibly cause a scroll too must call
+ * redraw_later(SOME_VALID) to update the whole window but still use scrolling
+ * to avoid redrawing everything. But the length of displayed lines must not
+ * change, use NOT_VALID then.
+ *
+ * Commands that move the window position must call redraw_later(NOT_VALID).
+ * TODO: should minimize redrawing by scrolling when possible.
+ *
+ * Commands that change everything (e.g., resizing the screen) must call
+ * redraw_all_later(NOT_VALID) or redraw_all_later(CLEAR).
+ *
+ * Things that are handled indirectly:
+ * - When messages scroll the screen up, msg_scrolled will be set and
+ * update_screen() called to redraw.
+ */
+
+#include "vim.h"
+
+#define MB_FILLER_CHAR '<' /* character used when a double-width character
+ * doesn't fit. */
+
+/*
+ * The attributes that are actually active for writing to the screen.
+ */
+static int screen_attr = 0;
+
+/*
+ * Positioning the cursor is reduced by remembering the last position.
+ * Mostly used by windgoto() and screen_char().
+ */
+static int screen_cur_row, screen_cur_col; /* last known cursor position */
+
+#ifdef FEAT_SEARCH_EXTRA
+static match_T search_hl; /* used for 'hlsearch' highlight matching */
+#endif
+
+#ifdef FEAT_FOLDING
+static foldinfo_T win_foldinfo; /* info for 'foldcolumn' */
+static int compute_foldcolumn(win_T *wp, int col);
+#endif
+
+/* Flag that is set when drawing for a callback, not from the main command
+ * loop. */
+static int redrawing_for_callback = 0;
+
+/*
+ * Buffer for one screen line (characters and attributes).
+ */
+static schar_T *current_ScreenLine;
+
+static void win_update(win_T *wp);
+static void win_redr_status(win_T *wp, int ignore_pum);
+static void win_draw_end(win_T *wp, int c1, int c2, int row, int endrow, hlf_T hl);
+#ifdef FEAT_FOLDING
+static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T lnum, int row);
+static void fill_foldcolumn(char_u *p, win_T *wp, int closed, linenr_T lnum);
+static void copy_text_attr(int off, char_u *buf, int len, int attr);
+#endif
+static int win_line(win_T *, linenr_T, int, int, int nochange, int number_only);
+static void draw_vsep_win(win_T *wp, int row);
+#ifdef FEAT_STL_OPT
+static void redraw_custom_statusline(win_T *wp);
+#endif
+#ifdef FEAT_SEARCH_EXTRA
+# define SEARCH_HL_PRIORITY 0
+static void start_search_hl(void);
+static void end_search_hl(void);
+static void init_search_hl(win_T *wp);
+static void prepare_search_hl(win_T *wp, linenr_T lnum);
+static void next_search_hl(win_T *win, match_T *shl, linenr_T lnum, colnr_T mincol, matchitem_T *cur);
+static int next_search_hl_pos(match_T *shl, linenr_T lnum, posmatch_T *pos, colnr_T mincol);
+#endif
+static void screen_char(unsigned off, int row, int col);
+static void screen_char_2(unsigned off, int row, int col);
+static void screenclear2(void);
+static void lineclear(unsigned off, int width, int attr);
+static void lineinvalid(unsigned off, int width);
+static int win_do_lines(win_T *wp, int row, int line_count, int mayclear, int del, int clear_attr);
+static void win_rest_invalid(win_T *wp);
+static void msg_pos_mode(void);
+static void recording_mode(int attr);
+static int fillchar_status(int *attr, win_T *wp);
+static int fillchar_vsep(int *attr);
+#ifdef FEAT_MENU
+static void redraw_win_toolbar(win_T *wp);
+#endif
+#ifdef FEAT_STL_OPT
+static void win_redr_custom(win_T *wp, int draw_ruler);
+#endif
+#ifdef FEAT_CMDL_INFO
+static void win_redr_ruler(win_T *wp, int always, int ignore_pum);
+#endif
+
+/* Ugly global: overrule attribute used by screen_char() */
+static int screen_char_attr = 0;
+
+#if defined(FEAT_SYN_HL) && defined(FEAT_RELTIME)
+/* Can limit syntax highlight time to 'redrawtime'. */
+# define SYN_TIME_LIMIT 1
+#endif
+
+#ifdef FEAT_RIGHTLEFT
+# define HAS_RIGHTLEFT(x) x
+#else
+# define HAS_RIGHTLEFT(x) FALSE
+#endif
+
+/*
+ * Redraw the current window later, with update_screen(type).
+ * Set must_redraw only if not already set to a higher value.
+ * E.g. if must_redraw is CLEAR, type NOT_VALID will do nothing.
+ */
+ void
+redraw_later(int type)
+{
+ redraw_win_later(curwin, type);
+}
+
+ void
+redraw_win_later(
+ win_T *wp,
+ int type)
+{
+ if (!exiting && wp->w_redr_type < type)
+ {
+ wp->w_redr_type = type;
+ if (type >= NOT_VALID)
+ wp->w_lines_valid = 0;
+ if (must_redraw < type) /* must_redraw is the maximum of all windows */
+ must_redraw = type;
+ }
+}
+
+/*
+ * Force a complete redraw later. Also resets the highlighting. To be used
+ * after executing a shell command that messes up the screen.
+ */
+ void
+redraw_later_clear(void)
+{
+ redraw_all_later(CLEAR);
+#ifdef FEAT_GUI
+ if (gui.in_use)
+ /* Use a code that will reset gui.highlight_mask in
+ * gui_stop_highlight(). */
+ screen_attr = HL_ALL + 1;
+ else
+#endif
+ /* Use attributes that is very unlikely to appear in text. */
+ screen_attr = HL_BOLD | HL_UNDERLINE | HL_INVERSE | HL_STRIKETHROUGH;
+}
+
+/*
+ * Mark all windows to be redrawn later.
+ */
+ void
+redraw_all_later(int type)
+{
+ win_T *wp;
+
+ FOR_ALL_WINDOWS(wp)
+ {
+ redraw_win_later(wp, type);
+ }
+ // This may be needed when switching tabs.
+ if (must_redraw < type)
+ must_redraw = type;
+}
+
+/*
+ * Mark all windows that are editing the current buffer to be updated later.
+ */
+ void
+redraw_curbuf_later(int type)
+{
+ redraw_buf_later(curbuf, type);
+}
+
+ void
+redraw_buf_later(buf_T *buf, int type)
+{
+ win_T *wp;
+
+ FOR_ALL_WINDOWS(wp)
+ {
+ if (wp->w_buffer == buf)
+ redraw_win_later(wp, type);
+ }
+}
+
+#if defined(FEAT_SIGNS) || defined(PROTO)
+ void
+redraw_buf_line_later(buf_T *buf, linenr_T lnum)
+{
+ win_T *wp;
+
+ FOR_ALL_WINDOWS(wp)
+ if (wp->w_buffer == buf && lnum >= wp->w_topline
+ && lnum < wp->w_botline)
+ redrawWinline(wp, lnum);
+}
+#endif
+
+#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
+ void
+redraw_buf_and_status_later(buf_T *buf, int type)
+{
+ win_T *wp;
+
+#ifdef FEAT_WILDMENU
+ if (wild_menu_showing != 0)
+ /* Don't redraw while the command line completion is displayed, it
+ * would disappear. */
+ return;
+#endif
+ FOR_ALL_WINDOWS(wp)
+ {
+ if (wp->w_buffer == buf)
+ {
+ redraw_win_later(wp, type);
+ wp->w_redr_status = TRUE;
+ }
+ }
+}
+#endif
+
+#if defined(FEAT_TERMRESPONSE) || defined(PROTO)
+/*
+ * Redraw as soon as possible. When the command line is not scrolled redraw
+ * right away and restore what was on the command line.
+ * Return a code indicating what happened.
+ */
+ int
+redraw_asap(int type)
+{
+ int rows;
+ int cols = screen_Columns;
+ int r;
+ int ret = 0;
+ schar_T *screenline; /* copy from ScreenLines[] */
+ sattr_T *screenattr; /* copy from ScreenAttrs[] */
+ int i;
+ u8char_T *screenlineUC = NULL; /* copy from ScreenLinesUC[] */
+ u8char_T *screenlineC[MAX_MCO]; /* copy from ScreenLinesC[][] */
+ schar_T *screenline2 = NULL; /* copy from ScreenLines2[] */
+
+ redraw_later(type);
+ if (msg_scrolled || (State != NORMAL && State != NORMAL_BUSY) || exiting)
+ return ret;
+
+ /* Allocate space to save the text displayed in the command line area. */
+ rows = screen_Rows - cmdline_row;
+ screenline = (schar_T *)lalloc(
+ (long_u)(rows * cols * sizeof(schar_T)), FALSE);
+ screenattr = (sattr_T *)lalloc(
+ (long_u)(rows * cols * sizeof(sattr_T)), FALSE);
+ if (screenline == NULL || screenattr == NULL)
+ ret = 2;
+ if (enc_utf8)
+ {
+ screenlineUC = (u8char_T *)lalloc(
+ (long_u)(rows * cols * sizeof(u8char_T)), FALSE);
+ if (screenlineUC == NULL)
+ ret = 2;
+ for (i = 0; i < p_mco; ++i)
+ {
+ screenlineC[i] = (u8char_T *)lalloc(
+ (long_u)(rows * cols * sizeof(u8char_T)), FALSE);
+ if (screenlineC[i] == NULL)
+ ret = 2;
+ }
+ }
+ if (enc_dbcs == DBCS_JPNU)
+ {
+ screenline2 = (schar_T *)lalloc(
+ (long_u)(rows * cols * sizeof(schar_T)), FALSE);
+ if (screenline2 == NULL)
+ ret = 2;
+ }
+
+ if (ret != 2)
+ {
+ /* Save the text displayed in the command line area. */
+ for (r = 0; r < rows; ++r)
+ {
+ mch_memmove(screenline + r * cols,
+ ScreenLines + LineOffset[cmdline_row + r],
+ (size_t)cols * sizeof(schar_T));
+ mch_memmove(screenattr + r * cols,
+ ScreenAttrs + LineOffset[cmdline_row + r],
+ (size_t)cols * sizeof(sattr_T));
+ if (enc_utf8)
+ {
+ mch_memmove(screenlineUC + r * cols,
+ ScreenLinesUC + LineOffset[cmdline_row + r],
+ (size_t)cols * sizeof(u8char_T));
+ for (i = 0; i < p_mco; ++i)
+ mch_memmove(screenlineC[i] + r * cols,
+ ScreenLinesC[i] + LineOffset[cmdline_row + r],
+ (size_t)cols * sizeof(u8char_T));
+ }
+ if (enc_dbcs == DBCS_JPNU)
+ mch_memmove(screenline2 + r * cols,
+ ScreenLines2 + LineOffset[cmdline_row + r],
+ (size_t)cols * sizeof(schar_T));
+ }
+
+ update_screen(0);
+ ret = 3;
+
+ if (must_redraw == 0)
+ {
+ int off = (int)(current_ScreenLine - ScreenLines);
+
+ /* Restore the text displayed in the command line area. */
+ for (r = 0; r < rows; ++r)
+ {
+ mch_memmove(current_ScreenLine,
+ screenline + r * cols,
+ (size_t)cols * sizeof(schar_T));
+ mch_memmove(ScreenAttrs + off,
+ screenattr + r * cols,
+ (size_t)cols * sizeof(sattr_T));
+ if (enc_utf8)
+ {
+ mch_memmove(ScreenLinesUC + off,
+ screenlineUC + r * cols,
+ (size_t)cols * sizeof(u8char_T));
+ for (i = 0; i < p_mco; ++i)
+ mch_memmove(ScreenLinesC[i] + off,
+ screenlineC[i] + r * cols,
+ (size_t)cols * sizeof(u8char_T));
+ }
+ if (enc_dbcs == DBCS_JPNU)
+ mch_memmove(ScreenLines2 + off,
+ screenline2 + r * cols,
+ (size_t)cols * sizeof(schar_T));
+ screen_line(cmdline_row + r, 0, cols, cols, FALSE);
+ }
+ ret = 4;
+ }
+ }
+
+ vim_free(screenline);
+ vim_free(screenattr);
+ if (enc_utf8)
+ {
+ vim_free(screenlineUC);
+ for (i = 0; i < p_mco; ++i)
+ vim_free(screenlineC[i]);
+ }
+ if (enc_dbcs == DBCS_JPNU)
+ vim_free(screenline2);
+
+ /* Show the intro message when appropriate. */
+ maybe_intro_message();
+
+ setcursor();
+
+ return ret;
+}
+#endif
+
+/*
+ * Invoked after an asynchronous callback is called.
+ * If an echo command was used the cursor needs to be put back where
+ * it belongs. If highlighting was changed a redraw is needed.
+ * If "call_update_screen" is FALSE don't call update_screen() when at the
+ * command line.
+ */
+ void
+redraw_after_callback(int call_update_screen)
+{
+ ++redrawing_for_callback;
+
+ if (State == HITRETURN || State == ASKMORE)
+ ; // do nothing
+ else if (State & CMDLINE)
+ {
+ // Don't redraw when in prompt_for_number().
+ if (cmdline_row > 0)
+ {
+ // Redrawing only works when the screen didn't scroll. Don't clear
+ // wildmenu entries.
+ if (msg_scrolled == 0
+#ifdef FEAT_WILDMENU
+ && wild_menu_showing == 0
+#endif
+ && call_update_screen)
+ update_screen(0);
+
+ // Redraw in the same position, so that the user can continue
+ // editing the command.
+ redrawcmdline_ex(FALSE);
+ }
+ }
+ else if (State & (NORMAL | INSERT | TERMINAL))
+ {
+ // keep the command line if possible
+ update_screen(VALID_NO_UPDATE);
+ setcursor();
+ }
+ cursor_on();
+#ifdef FEAT_GUI
+ if (gui.in_use && !gui_mch_is_blink_off())
+ // Don't update the cursor when it is blinking and off to avoid
+ // flicker.
+ out_flush_cursor(FALSE, FALSE);
+ else
+#endif
+ out_flush();
+
+ --redrawing_for_callback;
+}
+
+/*
+ * Changed something in the current window, at buffer line "lnum", that
+ * requires that line and possibly other lines to be redrawn.
+ * Used when entering/leaving Insert mode with the cursor on a folded line.
+ * Used to remove the "$" from a change command.
+ * Note that when also inserting/deleting lines w_redraw_top and w_redraw_bot
+ * may become invalid and the whole window will have to be redrawn.
+ */
+ void
+redrawWinline(
+ win_T *wp,
+ linenr_T lnum)
+{
+ if (wp->w_redraw_top == 0 || wp->w_redraw_top > lnum)
+ wp->w_redraw_top = lnum;
+ if (wp->w_redraw_bot == 0 || wp->w_redraw_bot < lnum)
+ wp->w_redraw_bot = lnum;
+ redraw_win_later(wp, VALID);
+}
+
+ void
+reset_updating_screen(int may_resize_shell UNUSED)
+{
+ updating_screen = FALSE;
+#ifdef FEAT_GUI
+ if (may_resize_shell)
+ gui_may_resize_shell();
+#endif
+#ifdef FEAT_TERMINAL
+ term_check_channel_closed_recently();
+#endif
+
+#ifdef HAVE_DROP_FILE
+ // If handle_drop() was called while updating_screen was TRUE need to
+ // handle the drop now.
+ handle_any_postponed_drop();
+#endif
+}
+
+/*
+ * Update all windows that are editing the current buffer.
+ */
+ void
+update_curbuf(int type)
+{
+ redraw_curbuf_later(type);
+ update_screen(type);
+}
+
+/*
+ * Based on the current value of curwin->w_topline, transfer a screenfull
+ * of stuff from Filemem to ScreenLines[], and update curwin->w_botline.
+ * Return OK when the screen was updated, FAIL if it was not done.
+ */
+ int
+update_screen(int type_arg)
+{
+ int type = type_arg;
+ win_T *wp;
+ static int did_intro = FALSE;
+#if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_CLIPBOARD)
+ int did_one;
+#endif
+#ifdef FEAT_GUI
+ int did_undraw = FALSE;
+ int gui_cursor_col;
+ int gui_cursor_row;
+#endif
+ int no_update = FALSE;
+
+ /* Don't do anything if the screen structures are (not yet) valid. */
+ if (!screen_valid(TRUE))
+ return FAIL;
+
+ if (type == VALID_NO_UPDATE)
+ {
+ no_update = TRUE;
+ type = 0;
+ }
+
+ if (must_redraw)
+ {
+ if (type < must_redraw) /* use maximal type */
+ type = must_redraw;
+
+ /* must_redraw is reset here, so that when we run into some weird
+ * reason to redraw while busy redrawing (e.g., asynchronous
+ * scrolling), or update_topline() in win_update() will cause a
+ * scroll, the screen will be redrawn later or in win_update(). */
+ must_redraw = 0;
+ }
+
+ /* May need to update w_lines[]. */
+ if (curwin->w_lines_valid == 0 && type < NOT_VALID
+#ifdef FEAT_TERMINAL
+ && !term_do_update_window(curwin)
+#endif
+ )
+ type = NOT_VALID;
+
+ /* Postpone the redrawing when it's not needed and when being called
+ * recursively. */
+ if (!redrawing() || updating_screen)
+ {
+ redraw_later(type); /* remember type for next time */
+ must_redraw = type;
+ if (type > INVERTED_ALL)
+ curwin->w_lines_valid = 0; /* don't use w_lines[].wl_size now */
+ return FAIL;
+ }
+
+ updating_screen = TRUE;
+#ifdef FEAT_SYN_HL
+ ++display_tick; /* let syntax code know we're in a next round of
+ * display updating */
+#endif
+ if (no_update)
+ ++no_win_do_lines_ins;
+
+ /*
+ * if the screen was scrolled up when displaying a message, scroll it down
+ */
+ if (msg_scrolled)
+ {
+ clear_cmdline = TRUE;
+ if (msg_scrolled > Rows - 5) /* clearing is faster */
+ type = CLEAR;
+ else if (type != CLEAR)
+ {
+ check_for_delay(FALSE);
+ if (screen_ins_lines(0, 0, msg_scrolled, (int)Rows, 0, NULL)
+ == FAIL)
+ type = CLEAR;
+ FOR_ALL_WINDOWS(wp)
+ {
+ if (W_WINROW(wp) < msg_scrolled)
+ {
+ if (W_WINROW(wp) + wp->w_height > msg_scrolled
+ && wp->w_redr_type < REDRAW_TOP
+ && wp->w_lines_valid > 0
+ && wp->w_topline == wp->w_lines[0].wl_lnum)
+ {
+ wp->w_upd_rows = msg_scrolled - W_WINROW(wp);
+ wp->w_redr_type = REDRAW_TOP;
+ }
+ else
+ {
+ wp->w_redr_type = NOT_VALID;
+ if (W_WINROW(wp) + wp->w_height + wp->w_status_height
+ <= msg_scrolled)
+ wp->w_redr_status = TRUE;
+ }
+ }
+ }
+ if (!no_update)
+ redraw_cmdline = TRUE;
+ redraw_tabline = TRUE;
+ }
+ msg_scrolled = 0;
+ need_wait_return = FALSE;
+ }
+
+ /* reset cmdline_row now (may have been changed temporarily) */
+ compute_cmdrow();
+
+ /* Check for changed highlighting */
+ if (need_highlight_changed)
+ highlight_changed();
+
+ if (type == CLEAR) /* first clear screen */
+ {
+ screenclear(); /* will reset clear_cmdline */
+ type = NOT_VALID;
+ /* must_redraw may be set indirectly, avoid another redraw later */
+ must_redraw = 0;
+ }
+
+ if (clear_cmdline) /* going to clear cmdline (done below) */
+ check_for_delay(FALSE);
+
+#ifdef FEAT_LINEBREAK
+ /* Force redraw when width of 'number' or 'relativenumber' column
+ * changes. */
+ if (curwin->w_redr_type < NOT_VALID
+ && curwin->w_nrwidth != ((curwin->w_p_nu || curwin->w_p_rnu)
+ ? number_width(curwin) : 0))
+ curwin->w_redr_type = NOT_VALID;
+#endif
+
+ /*
+ * Only start redrawing if there is really something to do.
+ */
+ if (type == INVERTED)
+ update_curswant();
+ if (curwin->w_redr_type < type
+ && !((type == VALID
+ && curwin->w_lines[0].wl_valid
+#ifdef FEAT_DIFF
+ && curwin->w_topfill == curwin->w_old_topfill
+ && curwin->w_botfill == curwin->w_old_botfill
+#endif
+ && curwin->w_topline == curwin->w_lines[0].wl_lnum)
+ || (type == INVERTED
+ && VIsual_active
+ && curwin->w_old_cursor_lnum == curwin->w_cursor.lnum
+ && curwin->w_old_visual_mode == VIsual_mode
+ && (curwin->w_valid & VALID_VIRTCOL)
+ && curwin->w_old_curswant == curwin->w_curswant)
+ ))
+ curwin->w_redr_type = type;
+
+ /* Redraw the tab pages line if needed. */
+ if (redraw_tabline || type >= NOT_VALID)
+ draw_tabline();
+
+#ifdef FEAT_SYN_HL
+ /*
+ * Correct stored syntax highlighting info for changes in each displayed
+ * buffer. Each buffer must only be done once.
+ */
+ FOR_ALL_WINDOWS(wp)
+ {
+ if (wp->w_buffer->b_mod_set)
+ {
+ win_T *wwp;
+
+ /* Check if we already did this buffer. */
+ for (wwp = firstwin; wwp != wp; wwp = wwp->w_next)
+ if (wwp->w_buffer == wp->w_buffer)
+ break;
+ if (wwp == wp && syntax_present(wp))
+ syn_stack_apply_changes(wp->w_buffer);
+ }
+ }
+#endif
+
+ /*
+ * Go from top to bottom through the windows, redrawing the ones that need
+ * it.
+ */
+#if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_CLIPBOARD)
+ did_one = FALSE;
+#endif
+#ifdef FEAT_SEARCH_EXTRA
+ search_hl.rm.regprog = NULL;
+#endif
+ FOR_ALL_WINDOWS(wp)
+ {
+ if (wp->w_redr_type != 0)
+ {
+ cursor_off();
+#if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_CLIPBOARD)
+ if (!did_one)
+ {
+ did_one = TRUE;
+# ifdef FEAT_SEARCH_EXTRA
+ start_search_hl();
+# endif
+# ifdef FEAT_CLIPBOARD
+ /* When Visual area changed, may have to update selection. */
+ if (clip_star.available && clip_isautosel_star())
+ clip_update_selection(&clip_star);
+ if (clip_plus.available && clip_isautosel_plus())
+ clip_update_selection(&clip_plus);
+# endif
+#ifdef FEAT_GUI
+ /* Remove the cursor before starting to do anything, because
+ * scrolling may make it difficult to redraw the text under
+ * it. */
+ if (gui.in_use && wp == curwin)
+ {
+ gui_cursor_col = gui.cursor_col;
+ gui_cursor_row = gui.cursor_row;
+ gui_undraw_cursor();
+ did_undraw = TRUE;
+ }
+#endif
+ }
+#endif
+ win_update(wp);
+ }
+
+ /* redraw status line after the window to minimize cursor movement */
+ if (wp->w_redr_status)
+ {
+ cursor_off();
+ win_redr_status(wp, TRUE); // any popup menu will be redrawn below
+ }
+ }
+#if defined(FEAT_SEARCH_EXTRA)
+ end_search_hl();
+#endif
+#ifdef FEAT_INS_EXPAND
+ /* May need to redraw the popup menu. */
+ pum_may_redraw();
+#endif
+
+ /* Reset b_mod_set flags. Going through all windows is probably faster
+ * than going through all buffers (there could be many buffers). */
+ FOR_ALL_WINDOWS(wp)
+ wp->w_buffer->b_mod_set = FALSE;
+
+ reset_updating_screen(TRUE);
+
+ /* Clear or redraw the command line. Done last, because scrolling may
+ * mess up the command line. */
+ if (clear_cmdline || redraw_cmdline)
+ showmode();
+
+ if (no_update)
+ --no_win_do_lines_ins;
+
+ /* May put up an introductory message when not editing a file */
+ if (!did_intro)
+ maybe_intro_message();
+ did_intro = TRUE;
+
+#ifdef FEAT_GUI
+ /* Redraw the cursor and update the scrollbars when all screen updating is
+ * done. */
+ if (gui.in_use)
+ {
+ if (did_undraw && !gui_mch_is_blink_off())
+ {
+ mch_disable_flush();
+ out_flush(); /* required before updating the cursor */
+ mch_enable_flush();
+
+ /* Put the GUI position where the cursor was, gui_update_cursor()
+ * uses that. */
+ gui.col = gui_cursor_col;
+ gui.row = gui_cursor_row;
+ gui.col = mb_fix_col(gui.col, gui.row);
+ gui_update_cursor(FALSE, FALSE);
+ gui_may_flush();
+ screen_cur_col = gui.col;
+ screen_cur_row = gui.row;
+ }
+ else
+ out_flush();
+ gui_update_scrollbars(FALSE);
+ }
+#endif
+ return OK;
+}
+
+#if defined(FEAT_SIGNS) || defined(FEAT_GUI) || defined(FEAT_CONCEAL)
+/*
+ * Prepare for updating one or more windows.
+ * Caller must check for "updating_screen" already set to avoid recursiveness.
+ */
+ static void
+update_prepare(void)
+{
+ cursor_off();
+ updating_screen = TRUE;
+#ifdef FEAT_GUI
+ /* Remove the cursor before starting to do anything, because scrolling may
+ * make it difficult to redraw the text under it. */
+ if (gui.in_use)
+ gui_undraw_cursor();
+#endif
+#ifdef FEAT_SEARCH_EXTRA
+ start_search_hl();
+#endif
+}
+
+/*
+ * Finish updating one or more windows.
+ */
+ static void
+update_finish(void)
+{
+ if (redraw_cmdline)
+ showmode();
+
+# ifdef FEAT_SEARCH_EXTRA
+ end_search_hl();
+# endif
+
+ reset_updating_screen(TRUE);
+
+# ifdef FEAT_GUI
+ /* Redraw the cursor and update the scrollbars when all screen updating is
+ * done. */
+ if (gui.in_use)
+ {
+ out_flush_cursor(FALSE, FALSE);
+ gui_update_scrollbars(FALSE);
+ }
+# endif
+}
+#endif
+
+#if defined(FEAT_CONCEAL) || defined(PROTO)
+/*
+ * Return TRUE if the cursor line in window "wp" may be concealed, according
+ * to the 'concealcursor' option.
+ */
+ int
+conceal_cursor_line(win_T *wp)
+{
+ int c;
+
+ if (*wp->w_p_cocu == NUL)
+ return FALSE;
+ if (get_real_state() & VISUAL)
+ c = 'v';
+ else if (State & INSERT)
+ c = 'i';
+ else if (State & NORMAL)
+ c = 'n';
+ else if (State & CMDLINE)
+ c = 'c';
+ else
+ return FALSE;
+ return vim_strchr(wp->w_p_cocu, c) != NULL;
+}
+
+/*
+ * Check if the cursor line needs to be redrawn because of 'concealcursor'.
+ */
+ void
+conceal_check_cursor_line(void)
+{
+ if (curwin->w_p_cole > 0 && conceal_cursor_line(curwin))
+ {
+ need_cursor_line_redraw = TRUE;
+ /* Need to recompute cursor column, e.g., when starting Visual mode
+ * without concealing. */
+ curs_columns(TRUE);
+ }
+}
+#endif
+
+#if defined(FEAT_NETBEANS_INTG) || defined(PROTO)
+ void
+update_debug_sign(buf_T *buf, linenr_T lnum)
+{
+ win_T *wp;
+ int doit = FALSE;
+
+# ifdef FEAT_FOLDING
+ win_foldinfo.fi_level = 0;
+# endif
+
+ // update/delete a specific sign
+ redraw_buf_line_later(buf, lnum);
+
+ // check if it resulted in the need to redraw a window
+ FOR_ALL_WINDOWS(wp)
+ if (wp->w_redr_type != 0)
+ doit = TRUE;
+
+ /* Return when there is nothing to do, screen updating is already
+ * happening (recursive call), messages on the screen or still starting up.
+ */
+ if (!doit || updating_screen
+ || State == ASKMORE || State == HITRETURN
+ || msg_scrolled
+#ifdef FEAT_GUI
+ || gui.starting
+#endif
+ || starting)
+ return;
+
+ /* update all windows that need updating */
+ update_prepare();
+
+ FOR_ALL_WINDOWS(wp)
+ {
+ if (wp->w_redr_type != 0)
+ win_update(wp);
+ if (wp->w_redr_status)
+ win_redr_status(wp, FALSE);
+ }
+
+ update_finish();
+}
+#endif
+
+
+#if defined(FEAT_GUI) || defined(PROTO)
+/*
+ * Update a single window, its status line and maybe the command line msg.
+ * Used for the GUI scrollbar.
+ */
+ void
+updateWindow(win_T *wp)
+{
+ /* return if already busy updating */
+ if (updating_screen)
+ return;
+
+ update_prepare();
+
+#ifdef FEAT_CLIPBOARD
+ /* When Visual area changed, may have to update selection. */
+ if (clip_star.available && clip_isautosel_star())
+ clip_update_selection(&clip_star);
+ if (clip_plus.available && clip_isautosel_plus())
+ clip_update_selection(&clip_plus);
+#endif
+
+ win_update(wp);
+
+ /* When the screen was cleared redraw the tab pages line. */
+ if (redraw_tabline)
+ draw_tabline();
+
+ if (wp->w_redr_status
+# ifdef FEAT_CMDL_INFO
+ || p_ru
+# endif
+# ifdef FEAT_STL_OPT
+ || *p_stl != NUL || *wp->w_p_stl != NUL
+# endif
+ )
+ win_redr_status(wp, FALSE);
+
+ update_finish();
+}
+#endif
+
+/*
+ * Update a single window.
+ *
+ * This may cause the windows below it also to be redrawn (when clearing the
+ * screen or scrolling lines).
+ *
+ * How the window is redrawn depends on wp->w_redr_type. Each type also
+ * implies the one below it.
+ * NOT_VALID redraw the whole window
+ * SOME_VALID redraw the whole window but do scroll when possible
+ * REDRAW_TOP redraw the top w_upd_rows window lines, otherwise like VALID
+ * INVERTED redraw the changed part of the Visual area
+ * INVERTED_ALL redraw the whole Visual area
+ * VALID 1. scroll up/down to adjust for a changed w_topline
+ * 2. update lines at the top when scrolled down
+ * 3. redraw changed text:
+ * - if wp->w_buffer->b_mod_set set, update lines between
+ * b_mod_top and b_mod_bot.
+ * - if wp->w_redraw_top non-zero, redraw lines between
+ * wp->w_redraw_top and wp->w_redr_bot.
+ * - continue redrawing when syntax status is invalid.
+ * 4. if scrolled up, update lines at the bottom.
+ * This results in three areas that may need updating:
+ * top: from first row to top_end (when scrolled down)
+ * mid: from mid_start to mid_end (update inversion or changed text)
+ * bot: from bot_start to last row (when scrolled up)
+ */
+ static void
+win_update(win_T *wp)
+{
+ buf_T *buf = wp->w_buffer;
+ int type;
+ int top_end = 0; /* Below last row of the top area that needs
+ updating. 0 when no top area updating. */
+ int mid_start = 999;/* first row of the mid area that needs
+ updating. 999 when no mid area updating. */
+ int mid_end = 0; /* Below last row of the mid area that needs
+ updating. 0 when no mid area updating. */
+ int bot_start = 999;/* first row of the bot area that needs
+ updating. 999 when no bot area updating */
+ int scrolled_down = FALSE; /* TRUE when scrolled down when
+ w_topline got smaller a bit */
+#ifdef FEAT_SEARCH_EXTRA
+ matchitem_T *cur; /* points to the match list */
+ int top_to_mod = FALSE; /* redraw above mod_top */
+#endif
+
+ int row; /* current window row to display */
+ linenr_T lnum; /* current buffer lnum to display */
+ int idx; /* current index in w_lines[] */
+ int srow; /* starting row of the current line */
+
+ int eof = FALSE; /* if TRUE, we hit the end of the file */
+ int didline = FALSE; /* if TRUE, we finished the last line */
+ int i;
+ long j;
+ static int recursive = FALSE; /* being called recursively */
+ int old_botline = wp->w_botline;
+#ifdef FEAT_FOLDING
+ long fold_count;
+#endif
+#ifdef FEAT_SYN_HL
+ /* remember what happened to the previous line, to know if
+ * check_visual_highlight() can be used */
+#define DID_NONE 1 /* didn't update a line */
+#define DID_LINE 2 /* updated a normal line */
+#define DID_FOLD 3 /* updated a folded line */
+ int did_update = DID_NONE;
+ linenr_T syntax_last_parsed = 0; /* last parsed text line */
+#endif
+ linenr_T mod_top = 0;
+ linenr_T mod_bot = 0;
+#if defined(FEAT_SYN_HL) || defined(FEAT_SEARCH_EXTRA)
+ int save_got_int;
+#endif
+#ifdef SYN_TIME_LIMIT
+ proftime_T syntax_tm;
+#endif
+
+ type = wp->w_redr_type;
+
+ if (type == NOT_VALID)
+ {
+ wp->w_redr_status = TRUE;
+ wp->w_lines_valid = 0;
+ }
+
+ /* Window is zero-height: nothing to draw. */
+ if (wp->w_height + WINBAR_HEIGHT(wp) == 0)
+ {
+ wp->w_redr_type = 0;
+ return;
+ }
+
+ /* Window is zero-width: Only need to draw the separator. */
+ if (wp->w_width == 0)
+ {
+ /* draw the vertical separator right of this window */
+ draw_vsep_win(wp, 0);
+ wp->w_redr_type = 0;
+ return;
+ }
+
+#ifdef FEAT_TERMINAL
+ // If this window contains a terminal, redraw works completely differently.
+ if (term_do_update_window(wp))
+ {
+ term_update_window(wp);
+# ifdef FEAT_MENU
+ /* Draw the window toolbar, if there is one. */
+ if (winbar_height(wp) > 0)
+ redraw_win_toolbar(wp);
+# endif
+ wp->w_redr_type = 0;
+ return;
+ }
+#endif
+
+#ifdef FEAT_SEARCH_EXTRA
+ init_search_hl(wp);
+#endif
+
+#ifdef FEAT_LINEBREAK
+ /* Force redraw when width of 'number' or 'relativenumber' column
+ * changes. */
+ i = (wp->w_p_nu || wp->w_p_rnu) ? number_width(wp) : 0;
+ if (wp->w_nrwidth != i)
+ {
+ type = NOT_VALID;
+ wp->w_nrwidth = i;
+ }
+ else
+#endif
+
+ if (buf->b_mod_set && buf->b_mod_xlines != 0 && wp->w_redraw_top != 0)
+ {
+ /*
+ * When there are both inserted/deleted lines and specific lines to be
+ * redrawn, w_redraw_top and w_redraw_bot may be invalid, just redraw
+ * everything (only happens when redrawing is off for while).
+ */
+ type = NOT_VALID;
+ }
+ else
+ {
+ /*
+ * Set mod_top to the first line that needs displaying because of
+ * changes. Set mod_bot to the first line after the changes.
+ */
+ mod_top = wp->w_redraw_top;
+ if (wp->w_redraw_bot != 0)
+ mod_bot = wp->w_redraw_bot + 1;
+ else
+ mod_bot = 0;
+ if (buf->b_mod_set)
+ {
+ if (mod_top == 0 || mod_top > buf->b_mod_top)
+ {
+ mod_top = buf->b_mod_top;
+#ifdef FEAT_SYN_HL
+ /* Need to redraw lines above the change that may be included
+ * in a pattern match. */
+ if (syntax_present(wp))
+ {
+ mod_top -= buf->b_s.b_syn_sync_linebreaks;
+ if (mod_top < 1)
+ mod_top = 1;
+ }
+#endif
+ }
+ if (mod_bot == 0 || mod_bot < buf->b_mod_bot)
+ mod_bot = buf->b_mod_bot;
+
+#ifdef FEAT_SEARCH_EXTRA
+ /* When 'hlsearch' is on and using a multi-line search pattern, a
+ * change in one line may make the Search highlighting in a
+ * previous line invalid. Simple solution: redraw all visible
+ * lines above the change.
+ * Same for a match pattern.
+ */
+ if (search_hl.rm.regprog != NULL
+ && re_multiline(search_hl.rm.regprog))
+ top_to_mod = TRUE;
+ else
+ {
+ cur = wp->w_match_head;
+ while (cur != NULL)
+ {
+ if (cur->match.regprog != NULL
+ && re_multiline(cur->match.regprog))
+ {
+ top_to_mod = TRUE;
+ break;
+ }
+ cur = cur->next;
+ }
+ }
+#endif
+ }
+#ifdef FEAT_FOLDING
+ if (mod_top != 0 && hasAnyFolding(wp))
+ {
+ linenr_T lnumt, lnumb;
+
+ /*
+ * A change in a line can cause lines above it to become folded or
+ * unfolded. Find the top most buffer line that may be affected.
+ * If the line was previously folded and displayed, get the first
+ * line of that fold. If the line is folded now, get the first
+ * folded line. Use the minimum of these two.
+ */
+
+ /* Find last valid w_lines[] entry above mod_top. Set lnumt to
+ * the line below it. If there is no valid entry, use w_topline.
+ * Find the first valid w_lines[] entry below mod_bot. Set lnumb
+ * to this line. If there is no valid entry, use MAXLNUM. */
+ lnumt = wp->w_topline;
+ lnumb = MAXLNUM;
+ for (i = 0; i < wp->w_lines_valid; ++i)
+ if (wp->w_lines[i].wl_valid)
+ {
+ if (wp->w_lines[i].wl_lastlnum < mod_top)
+ lnumt = wp->w_lines[i].wl_lastlnum + 1;
+ if (lnumb == MAXLNUM && wp->w_lines[i].wl_lnum >= mod_bot)
+ {
+ lnumb = wp->w_lines[i].wl_lnum;
+ /* When there is a fold column it might need updating
+ * in the next line ("J" just above an open fold). */
+ if (compute_foldcolumn(wp, 0) > 0)
+ ++lnumb;
+ }
+ }
+
+ (void)hasFoldingWin(wp, mod_top, &mod_top, NULL, TRUE, NULL);
+ if (mod_top > lnumt)
+ mod_top = lnumt;
+
+ /* Now do the same for the bottom line (one above mod_bot). */
+ --mod_bot;
+ (void)hasFoldingWin(wp, mod_bot, NULL, &mod_bot, TRUE, NULL);
+ ++mod_bot;
+ if (mod_bot < lnumb)
+ mod_bot = lnumb;
+ }
+#endif
+
+ /* When a change starts above w_topline and the end is below
+ * w_topline, start redrawing at w_topline.
+ * If the end of the change is above w_topline: do like no change was
+ * made, but redraw the first line to find changes in syntax. */
+ if (mod_top != 0 && mod_top < wp->w_topline)
+ {
+ if (mod_bot > wp->w_topline)
+ mod_top = wp->w_topline;
+#ifdef FEAT_SYN_HL
+ else if (syntax_present(wp))
+ top_end = 1;
+#endif
+ }
+
+ /* When line numbers are displayed need to redraw all lines below
+ * inserted/deleted lines. */
+ if (mod_top != 0 && buf->b_mod_xlines != 0 && wp->w_p_nu)
+ mod_bot = MAXLNUM;
+ }
+ wp->w_redraw_top = 0; // reset for next time
+ wp->w_redraw_bot = 0;
+
+ /*
+ * When only displaying the lines at the top, set top_end. Used when
+ * window has scrolled down for msg_scrolled.
+ */
+ if (type == REDRAW_TOP)
+ {
+ j = 0;
+ for (i = 0; i < wp->w_lines_valid; ++i)
+ {
+ j += wp->w_lines[i].wl_size;
+ if (j >= wp->w_upd_rows)
+ {
+ top_end = j;
+ break;
+ }
+ }
+ if (top_end == 0)
+ /* not found (cannot happen?): redraw everything */
+ type = NOT_VALID;
+ else
+ /* top area defined, the rest is VALID */
+ type = VALID;
+ }
+
+ /* Trick: we want to avoid clearing the screen twice. screenclear() will
+ * set "screen_cleared" to TRUE. The special value MAYBE (which is still
+ * non-zero and thus not FALSE) will indicate that screenclear() was not
+ * called. */
+ if (screen_cleared)
+ screen_cleared = MAYBE;
+
+ /*
+ * If there are no changes on the screen that require a complete redraw,
+ * handle three cases:
+ * 1: we are off the top of the screen by a few lines: scroll down
+ * 2: wp->w_topline is below wp->w_lines[0].wl_lnum: may scroll up
+ * 3: wp->w_topline is wp->w_lines[0].wl_lnum: find first entry in
+ * w_lines[] that needs updating.
+ */
+ if ((type == VALID || type == SOME_VALID
+ || type == INVERTED || type == INVERTED_ALL)
+#ifdef FEAT_DIFF
+ && !wp->w_botfill && !wp->w_old_botfill
+#endif
+ )
+ {
+ if (mod_top != 0 && wp->w_topline == mod_top)
+ {
+ /*
+ * w_topline is the first changed line, the scrolling will be done
+ * further down.
+ */
+ }
+ else if (wp->w_lines[0].wl_valid
+ && (wp->w_topline < wp->w_lines[0].wl_lnum
+#ifdef FEAT_DIFF
+ || (wp->w_topline == wp->w_lines[0].wl_lnum
+ && wp->w_topfill > wp->w_old_topfill)
+#endif
+ ))
+ {
+ /*
+ * New topline is above old topline: May scroll down.
+ */
+#ifdef FEAT_FOLDING
+ if (hasAnyFolding(wp))
+ {
+ linenr_T ln;
+
+ /* count the number of lines we are off, counting a sequence
+ * of folded lines as one */
+ j = 0;
+ for (ln = wp->w_topline; ln < wp->w_lines[0].wl_lnum; ++ln)
+ {
+ ++j;
+ if (j >= wp->w_height - 2)
+ break;
+ (void)hasFoldingWin(wp, ln, NULL, &ln, TRUE, NULL);
+ }
+ }
+ else
+#endif
+ j = wp->w_lines[0].wl_lnum - wp->w_topline;
+ if (j < wp->w_height - 2) /* not too far off */
+ {
+ i = plines_m_win(wp, wp->w_topline, wp->w_lines[0].wl_lnum - 1);
+#ifdef FEAT_DIFF
+ /* insert extra lines for previously invisible filler lines */
+ if (wp->w_lines[0].wl_lnum != wp->w_topline)
+ i += diff_check_fill(wp, wp->w_lines[0].wl_lnum)
+ - wp->w_old_topfill;
+#endif
+ if (i < wp->w_height - 2) /* less than a screen off */
+ {
+ /*
+ * Try to insert the correct number of lines.
+ * If not the last window, delete the lines at the bottom.
+ * win_ins_lines may fail when the terminal can't do it.
+ */
+ if (i > 0)
+ check_for_delay(FALSE);
+ if (win_ins_lines(wp, 0, i, FALSE, wp == firstwin) == OK)
+ {
+ if (wp->w_lines_valid != 0)
+ {
+ /* Need to update rows that are new, stop at the
+ * first one that scrolled down. */
+ top_end = i;
+ scrolled_down = TRUE;
+
+ /* Move the entries that were scrolled, disable
+ * the entries for the lines to be redrawn. */
+ if ((wp->w_lines_valid += j) > wp->w_height)
+ wp->w_lines_valid = wp->w_height;
+ for (idx = wp->w_lines_valid; idx - j >= 0; idx--)
+ wp->w_lines[idx] = wp->w_lines[idx - j];
+ while (idx >= 0)
+ wp->w_lines[idx--].wl_valid = FALSE;
+ }
+ }
+ else
+ mid_start = 0; /* redraw all lines */
+ }
+ else
+ mid_start = 0; /* redraw all lines */
+ }
+ else
+ mid_start = 0; /* redraw all lines */
+ }
+ else
+ {
+ /*
+ * New topline is at or below old topline: May scroll up.
+ * When topline didn't change, find first entry in w_lines[] that
+ * needs updating.
+ */
+
+ /* try to find wp->w_topline in wp->w_lines[].wl_lnum */
+ j = -1;
+ row = 0;
+ for (i = 0; i < wp->w_lines_valid; i++)
+ {
+ if (wp->w_lines[i].wl_valid
+ && wp->w_lines[i].wl_lnum == wp->w_topline)
+ {
+ j = i;
+ break;
+ }
+ row += wp->w_lines[i].wl_size;
+ }
+ if (j == -1)
+ {
+ /* if wp->w_topline is not in wp->w_lines[].wl_lnum redraw all
+ * lines */
+ mid_start = 0;
+ }
+ else
+ {
+ /*
+ * Try to delete the correct number of lines.
+ * wp->w_topline is at wp->w_lines[i].wl_lnum.
+ */
+#ifdef FEAT_DIFF
+ /* If the topline didn't change, delete old filler lines,
+ * otherwise delete filler lines of the new topline... */
+ if (wp->w_lines[0].wl_lnum == wp->w_topline)
+ row += wp->w_old_topfill;
+ else
+ row += diff_check_fill(wp, wp->w_topline);
+ /* ... but don't delete new filler lines. */
+ row -= wp->w_topfill;
+#endif
+ if (row > 0)
+ {
+ check_for_delay(FALSE);
+ if (win_del_lines(wp, 0, row, FALSE, wp == firstwin, 0)
+ == OK)
+ bot_start = wp->w_height - row;
+ else
+ mid_start = 0; /* redraw all lines */
+ }
+ if ((row == 0 || bot_start < 999) && wp->w_lines_valid != 0)
+ {
+ /*
+ * Skip the lines (below the deleted lines) that are still
+ * valid and don't need redrawing. Copy their info
+ * upwards, to compensate for the deleted lines. Set
+ * bot_start to the first row that needs redrawing.
+ */
+ bot_start = 0;
+ idx = 0;
+ for (;;)
+ {
+ wp->w_lines[idx] = wp->w_lines[j];
+ /* stop at line that didn't fit, unless it is still
+ * valid (no lines deleted) */
+ if (row > 0 && bot_start + row
+ + (int)wp->w_lines[j].wl_size > wp->w_height)
+ {
+ wp->w_lines_valid = idx + 1;
+ break;
+ }
+ bot_start += wp->w_lines[idx++].wl_size;
+
+ /* stop at the last valid entry in w_lines[].wl_size */
+ if (++j >= wp->w_lines_valid)
+ {
+ wp->w_lines_valid = idx;
+ break;
+ }
+ }
+#ifdef FEAT_DIFF
+ /* Correct the first entry for filler lines at the top
+ * when it won't get updated below. */
+ if (wp->w_p_diff && bot_start > 0)
+ wp->w_lines[0].wl_size =
+ plines_win_nofill(wp, wp->w_topline, TRUE)
+ + wp->w_topfill;
+#endif
+ }
+ }
+ }
+
+ /* When starting redraw in the first line, redraw all lines. When
+ * there is only one window it's probably faster to clear the screen
+ * first. */
+ if (mid_start == 0)
+ {
+ mid_end = wp->w_height;
+ if (ONE_WINDOW)
+ {
+ /* Clear the screen when it was not done by win_del_lines() or
+ * win_ins_lines() above, "screen_cleared" is FALSE or MAYBE
+ * then. */
+ if (screen_cleared != TRUE)
+ screenclear();
+ /* The screen was cleared, redraw the tab pages line. */
+ if (redraw_tabline)
+ draw_tabline();
+ }
+ }
+
+ /* When win_del_lines() or win_ins_lines() caused the screen to be
+ * cleared (only happens for the first window) or when screenclear()
+ * was called directly above, "must_redraw" will have been set to
+ * NOT_VALID, need to reset it here to avoid redrawing twice. */
+ if (screen_cleared == TRUE)
+ must_redraw = 0;
+ }
+ else
+ {
+ /* Not VALID or INVERTED: redraw all lines. */
+ mid_start = 0;
+ mid_end = wp->w_height;
+ }
+
+ if (type == SOME_VALID)
+ {
+ /* SOME_VALID: redraw all lines. */
+ mid_start = 0;
+ mid_end = wp->w_height;
+ type = NOT_VALID;
+ }
+
+ /* check if we are updating or removing the inverted part */
+ if ((VIsual_active && buf == curwin->w_buffer)
+ || (wp->w_old_cursor_lnum != 0 && type != NOT_VALID))
+ {
+ linenr_T from, to;
+
+ if (VIsual_active)
+ {
+ if (VIsual_active
+ && (VIsual_mode != wp->w_old_visual_mode
+ || type == INVERTED_ALL))
+ {
+ /*
+ * If the type of Visual selection changed, redraw the whole
+ * selection. Also when the ownership of the X selection is
+ * gained or lost.
+ */
+ if (curwin->w_cursor.lnum < VIsual.lnum)
+ {
+ from = curwin->w_cursor.lnum;
+ to = VIsual.lnum;
+ }
+ else
+ {
+ from = VIsual.lnum;
+ to = curwin->w_cursor.lnum;
+ }
+ /* redraw more when the cursor moved as well */
+ if (wp->w_old_cursor_lnum < from)
+ from = wp->w_old_cursor_lnum;
+ if (wp->w_old_cursor_lnum > to)
+ to = wp->w_old_cursor_lnum;
+ if (wp->w_old_visual_lnum < from)
+ from = wp->w_old_visual_lnum;
+ if (wp->w_old_visual_lnum > to)
+ to = wp->w_old_visual_lnum;
+ }
+ else
+ {
+ /*
+ * Find the line numbers that need to be updated: The lines
+ * between the old cursor position and the current cursor
+ * position. Also check if the Visual position changed.
+ */
+ if (curwin->w_cursor.lnum < wp->w_old_cursor_lnum)
+ {
+ from = curwin->w_cursor.lnum;
+ to = wp->w_old_cursor_lnum;
+ }
+ else
+ {
+ from = wp->w_old_cursor_lnum;
+ to = curwin->w_cursor.lnum;
+ if (from == 0) /* Visual mode just started */
+ from = to;
+ }
+
+ if (VIsual.lnum != wp->w_old_visual_lnum
+ || VIsual.col != wp->w_old_visual_col)
+ {
+ if (wp->w_old_visual_lnum < from
+ && wp->w_old_visual_lnum != 0)
+ from = wp->w_old_visual_lnum;
+ if (wp->w_old_visual_lnum > to)
+ to = wp->w_old_visual_lnum;
+ if (VIsual.lnum < from)
+ from = VIsual.lnum;
+ if (VIsual.lnum > to)
+ to = VIsual.lnum;
+ }
+ }
+
+ /*
+ * If in block mode and changed column or curwin->w_curswant:
+ * update all lines.
+ * First compute the actual start and end column.
+ */
+ if (VIsual_mode == Ctrl_V)
+ {
+ colnr_T fromc, toc;
+#if defined(FEAT_LINEBREAK)
+ int save_ve_flags = ve_flags;
+
+ if (curwin->w_p_lbr)
+ ve_flags = VE_ALL;
+#endif
+ getvcols(wp, &VIsual, &curwin->w_cursor, &fromc, &toc);
+#if defined(FEAT_LINEBREAK)
+ ve_flags = save_ve_flags;
+#endif
+ ++toc;
+ if (curwin->w_curswant == MAXCOL)
+ toc = MAXCOL;
+
+ if (fromc != wp->w_old_cursor_fcol
+ || toc != wp->w_old_cursor_lcol)
+ {
+ if (from > VIsual.lnum)
+ from = VIsual.lnum;
+ if (to < VIsual.lnum)
+ to = VIsual.lnum;
+ }
+ wp->w_old_cursor_fcol = fromc;
+ wp->w_old_cursor_lcol = toc;
+ }
+ }
+ else
+ {
+ /* Use the line numbers of the old Visual area. */
+ if (wp->w_old_cursor_lnum < wp->w_old_visual_lnum)
+ {
+ from = wp->w_old_cursor_lnum;
+ to = wp->w_old_visual_lnum;
+ }
+ else
+ {
+ from = wp->w_old_visual_lnum;
+ to = wp->w_old_cursor_lnum;
+ }
+ }
+
+ /*
+ * There is no need to update lines above the top of the window.
+ */
+ if (from < wp->w_topline)
+ from = wp->w_topline;
+
+ /*
+ * If we know the value of w_botline, use it to restrict the update to
+ * the lines that are visible in the window.
+ */
+ if (wp->w_valid & VALID_BOTLINE)
+ {
+ if (from >= wp->w_botline)
+ from = wp->w_botline - 1;
+ if (to >= wp->w_botline)
+ to = wp->w_botline - 1;
+ }
+
+ /*
+ * Find the minimal part to be updated.
+ * Watch out for scrolling that made entries in w_lines[] invalid.
+ * E.g., CTRL-U makes the first half of w_lines[] invalid and sets
+ * top_end; need to redraw from top_end to the "to" line.
+ * A middle mouse click with a Visual selection may change the text
+ * above the Visual area and reset wl_valid, do count these for
+ * mid_end (in srow).
+ */
+ if (mid_start > 0)
+ {
+ lnum = wp->w_topline;
+ idx = 0;
+ srow = 0;
+ if (scrolled_down)
+ mid_start = top_end;
+ else
+ mid_start = 0;
+ while (lnum < from && idx < wp->w_lines_valid) /* find start */
+ {
+ if (wp->w_lines[idx].wl_valid)
+ mid_start += wp->w_lines[idx].wl_size;
+ else if (!scrolled_down)
+ srow += wp->w_lines[idx].wl_size;
+ ++idx;
+# ifdef FEAT_FOLDING
+ if (idx < wp->w_lines_valid && wp->w_lines[idx].wl_valid)
+ lnum = wp->w_lines[idx].wl_lnum;
+ else
+# endif
+ ++lnum;
+ }
+ srow += mid_start;
+ mid_end = wp->w_height;
+ for ( ; idx < wp->w_lines_valid; ++idx) /* find end */
+ {
+ if (wp->w_lines[idx].wl_valid
+ && wp->w_lines[idx].wl_lnum >= to + 1)
+ {
+ /* Only update until first row of this line */
+ mid_end = srow;
+ break;
+ }
+ srow += wp->w_lines[idx].wl_size;
+ }
+ }
+ }
+
+ if (VIsual_active && buf == curwin->w_buffer)
+ {
+ wp->w_old_visual_mode = VIsual_mode;
+ wp->w_old_cursor_lnum = curwin->w_cursor.lnum;
+ wp->w_old_visual_lnum = VIsual.lnum;
+ wp->w_old_visual_col = VIsual.col;
+ wp->w_old_curswant = curwin->w_curswant;
+ }
+ else
+ {
+ wp->w_old_visual_mode = 0;
+ wp->w_old_cursor_lnum = 0;
+ wp->w_old_visual_lnum = 0;
+ wp->w_old_visual_col = 0;
+ }
+
+#if defined(FEAT_SYN_HL) || defined(FEAT_SEARCH_EXTRA)
+ /* reset got_int, otherwise regexp won't work */
+ save_got_int = got_int;
+ got_int = 0;
+#endif
+#ifdef SYN_TIME_LIMIT
+ /* Set the time limit to 'redrawtime'. */
+ profile_setlimit(p_rdt, &syntax_tm);
+ syn_set_timeout(&syntax_tm);
+#endif
+#ifdef FEAT_FOLDING
+ win_foldinfo.fi_level = 0;
+#endif
+
+#ifdef FEAT_MENU
+ /*
+ * Draw the window toolbar, if there is one.
+ * TODO: only when needed.
+ */
+ if (winbar_height(wp) > 0)
+ redraw_win_toolbar(wp);
+#endif
+
+ /*
+ * Update all the window rows.
+ */
+ idx = 0; /* first entry in w_lines[].wl_size */
+ row = 0;
+ srow = 0;
+ lnum = wp->w_topline; /* first line shown in window */
+ for (;;)
+ {
+ /* stop updating when reached the end of the window (check for _past_
+ * the end of the window is at the end of the loop) */
+ if (row == wp->w_height)
+ {
+ didline = TRUE;
+ break;
+ }
+
+ /* stop updating when hit the end of the file */
+ if (lnum > buf->b_ml.ml_line_count)
+ {
+ eof = TRUE;
+ break;
+ }
+
+ /* Remember the starting row of the line that is going to be dealt
+ * with. It is used further down when the line doesn't fit. */
+ srow = row;
+
+ /*
+ * Update a line when it is in an area that needs updating, when it
+ * has changes or w_lines[idx] is invalid.
+ * "bot_start" may be halfway a wrapped line after using
+ * win_del_lines(), check if the current line includes it.
+ * When syntax folding is being used, the saved syntax states will
+ * already have been updated, we can't see where the syntax state is
+ * the same again, just update until the end of the window.
+ */
+ if (row < top_end
+ || (row >= mid_start && row < mid_end)
+#ifdef FEAT_SEARCH_EXTRA
+ || top_to_mod
+#endif
+ || idx >= wp->w_lines_valid
+ || (row + wp->w_lines[idx].wl_size > bot_start)
+ || (mod_top != 0
+ && (lnum == mod_top
+ || (lnum >= mod_top
+ && (lnum < mod_bot
+#ifdef FEAT_SYN_HL
+ || did_update == DID_FOLD
+ || (did_update == DID_LINE
+ && syntax_present(wp)
+ && (
+# ifdef FEAT_FOLDING
+ (foldmethodIsSyntax(wp)
+ && hasAnyFolding(wp)) ||
+# endif
+ syntax_check_changed(lnum)))
+#endif
+#ifdef FEAT_SEARCH_EXTRA
+ /* match in fixed position might need redraw
+ * if lines were inserted or deleted */
+ || (wp->w_match_head != NULL
+ && buf->b_mod_xlines != 0)
+#endif
+ )))))
+ {
+#ifdef FEAT_SEARCH_EXTRA
+ if (lnum == mod_top)
+ top_to_mod = FALSE;
+#endif
+
+ /*
+ * When at start of changed lines: May scroll following lines
+ * up or down to minimize redrawing.
+ * Don't do this when the change continues until the end.
+ * Don't scroll when dollar_vcol >= 0, keep the "$".
+ */
+ if (lnum == mod_top
+ && mod_bot != MAXLNUM
+ && !(dollar_vcol >= 0 && mod_bot == mod_top + 1))
+ {
+ int old_rows = 0;
+ int new_rows = 0;
+ int xtra_rows;
+ linenr_T l;
+
+ /* Count the old number of window rows, using w_lines[], which
+ * should still contain the sizes for the lines as they are
+ * currently displayed. */
+ for (i = idx; i < wp->w_lines_valid; ++i)
+ {
+ /* Only valid lines have a meaningful wl_lnum. Invalid
+ * lines are part of the changed area. */
+ if (wp->w_lines[i].wl_valid
+ && wp->w_lines[i].wl_lnum == mod_bot)
+ break;
+ old_rows += wp->w_lines[i].wl_size;
+#ifdef FEAT_FOLDING
+ if (wp->w_lines[i].wl_valid
+ && wp->w_lines[i].wl_lastlnum + 1 == mod_bot)
+ {
+ /* Must have found the last valid entry above mod_bot.
+ * Add following invalid entries. */
+ ++i;
+ while (i < wp->w_lines_valid
+ && !wp->w_lines[i].wl_valid)
+ old_rows += wp->w_lines[i++].wl_size;
+ break;
+ }
+#endif
+ }
+
+ if (i >= wp->w_lines_valid)
+ {
+ /* We can't find a valid line below the changed lines,
+ * need to redraw until the end of the window.
+ * Inserting/deleting lines has no use. */
+ bot_start = 0;
+ }
+ else
+ {
+ /* Able to count old number of rows: Count new window
+ * rows, and may insert/delete lines */
+ j = idx;
+ for (l = lnum; l < mod_bot; ++l)
+ {
+#ifdef FEAT_FOLDING
+ if (hasFoldingWin(wp, l, NULL, &l, TRUE, NULL))
+ ++new_rows;
+ else
+#endif
+#ifdef FEAT_DIFF
+ if (l == wp->w_topline)
+ new_rows += plines_win_nofill(wp, l, TRUE)
+ + wp->w_topfill;
+ else
+#endif
+ new_rows += plines_win(wp, l, TRUE);
+ ++j;
+ if (new_rows > wp->w_height - row - 2)
+ {
+ /* it's getting too much, must redraw the rest */
+ new_rows = 9999;
+ break;
+ }
+ }
+ xtra_rows = new_rows - old_rows;
+ if (xtra_rows < 0)
+ {
+ /* May scroll text up. If there is not enough
+ * remaining text or scrolling fails, must redraw the
+ * rest. If scrolling works, must redraw the text
+ * below the scrolled text. */
+ if (row - xtra_rows >= wp->w_height - 2)
+ mod_bot = MAXLNUM;
+ else
+ {
+ check_for_delay(FALSE);
+ if (win_del_lines(wp, row,
+ -xtra_rows, FALSE, FALSE, 0) == FAIL)
+ mod_bot = MAXLNUM;
+ else
+ bot_start = wp->w_height + xtra_rows;
+ }
+ }
+ else if (xtra_rows > 0)
+ {
+ /* May scroll text down. If there is not enough
+ * remaining text of scrolling fails, must redraw the
+ * rest. */
+ if (row + xtra_rows >= wp->w_height - 2)
+ mod_bot = MAXLNUM;
+ else
+ {
+ check_for_delay(FALSE);
+ if (win_ins_lines(wp, row + old_rows,
+ xtra_rows, FALSE, FALSE) == FAIL)
+ mod_bot = MAXLNUM;
+ else if (top_end > row + old_rows)
+ /* Scrolled the part at the top that requires
+ * updating down. */
+ top_end += xtra_rows;
+ }
+ }
+
+ /* When not updating the rest, may need to move w_lines[]
+ * entries. */
+ if (mod_bot != MAXLNUM && i != j)
+ {
+ if (j < i)
+ {
+ int x = row + new_rows;
+
+ /* move entries in w_lines[] upwards */
+ for (;;)
+ {
+ /* stop at last valid entry in w_lines[] */
+ if (i >= wp->w_lines_valid)
+ {
+ wp->w_lines_valid = j;
+ break;
+ }
+ wp->w_lines[j] = wp->w_lines[i];
+ /* stop at a line that won't fit */
+ if (x + (int)wp->w_lines[j].wl_size
+ > wp->w_height)
+ {
+ wp->w_lines_valid = j + 1;
+ break;
+ }
+ x += wp->w_lines[j++].wl_size;
+ ++i;
+ }
+ if (bot_start > x)
+ bot_start = x;
+ }
+ else /* j > i */
+ {
+ /* move entries in w_lines[] downwards */
+ j -= i;
+ wp->w_lines_valid += j;
+ if (wp->w_lines_valid > wp->w_height)
+ wp->w_lines_valid = wp->w_height;
+ for (i = wp->w_lines_valid; i - j >= idx; --i)
+ wp->w_lines[i] = wp->w_lines[i - j];
+
+ /* The w_lines[] entries for inserted lines are
+ * now invalid, but wl_size may be used above.
+ * Reset to zero. */
+ while (i >= idx)
+ {
+ wp->w_lines[i].wl_size = 0;
+ wp->w_lines[i--].wl_valid = FALSE;
+ }
+ }
+ }
+ }
+ }
+
+#ifdef FEAT_FOLDING
+ /*
+ * When lines are folded, display one line for all of them.
+ * Otherwise, display normally (can be several display lines when
+ * 'wrap' is on).
+ */
+ fold_count = foldedCount(wp, lnum, &win_foldinfo);
+ if (fold_count != 0)
+ {
+ fold_line(wp, fold_count, &win_foldinfo, lnum, row);
+ ++row;
+ --fold_count;
+ wp->w_lines[idx].wl_folded = TRUE;
+ wp->w_lines[idx].wl_lastlnum = lnum + fold_count;
+# ifdef FEAT_SYN_HL
+ did_update = DID_FOLD;
+# endif
+ }
+ else
+#endif
+ if (idx < wp->w_lines_valid
+ && wp->w_lines[idx].wl_valid
+ && wp->w_lines[idx].wl_lnum == lnum
+ && lnum > wp->w_topline
+ && !(dy_flags & (DY_LASTLINE | DY_TRUNCATE))
+ && srow + wp->w_lines[idx].wl_size > wp->w_height
+#ifdef FEAT_DIFF
+ && diff_check_fill(wp, lnum) == 0
+#endif
+ )
+ {
+ /* This line is not going to fit. Don't draw anything here,
+ * will draw "@ " lines below. */
+ row = wp->w_height + 1;
+ }
+ else
+ {
+#ifdef FEAT_SEARCH_EXTRA
+ prepare_search_hl(wp, lnum);
+#endif
+#ifdef FEAT_SYN_HL
+ /* Let the syntax stuff know we skipped a few lines. */
+ if (syntax_last_parsed != 0 && syntax_last_parsed + 1 < lnum
+ && syntax_present(wp))
+ syntax_end_parsing(syntax_last_parsed + 1);
+#endif
+
+ /*
+ * Display one line.
+ */
+ row = win_line(wp, lnum, srow, wp->w_height,
+ mod_top == 0, FALSE);
+
+#ifdef FEAT_FOLDING
+ wp->w_lines[idx].wl_folded = FALSE;
+ wp->w_lines[idx].wl_lastlnum = lnum;
+#endif
+#ifdef FEAT_SYN_HL
+ did_update = DID_LINE;
+ syntax_last_parsed = lnum;
+#endif
+ }
+
+ wp->w_lines[idx].wl_lnum = lnum;
+ wp->w_lines[idx].wl_valid = TRUE;
+
+ /* Past end of the window or end of the screen. Note that after
+ * resizing wp->w_height may be end up too big. That's a problem
+ * elsewhere, but prevent a crash here. */
+ if (row > wp->w_height || row + wp->w_winrow >= Rows)
+ {
+ /* we may need the size of that too long line later on */
+ if (dollar_vcol == -1)
+ wp->w_lines[idx].wl_size = plines_win(wp, lnum, TRUE);
+ ++idx;
+ break;
+ }
+ if (dollar_vcol == -1)
+ wp->w_lines[idx].wl_size = row - srow;
+ ++idx;
+#ifdef FEAT_FOLDING
+ lnum += fold_count + 1;
+#else
+ ++lnum;
+#endif
+ }
+ else
+ {
+ if (wp->w_p_rnu)
+ {
+#ifdef FEAT_FOLDING
+ // 'relativenumber' set: The text doesn't need to be drawn, but
+ // the number column nearly always does.
+ fold_count = foldedCount(wp, lnum, &win_foldinfo);
+ if (fold_count != 0)
+ fold_line(wp, fold_count, &win_foldinfo, lnum, row);
+ else
+#endif
+ (void)win_line(wp, lnum, srow, wp->w_height, TRUE, TRUE);
+ }
+
+ // This line does not need to be drawn, advance to the next one.
+ row += wp->w_lines[idx++].wl_size;
+ if (row > wp->w_height) /* past end of screen */
+ break;
+#ifdef FEAT_FOLDING
+ lnum = wp->w_lines[idx - 1].wl_lastlnum + 1;
+#else
+ ++lnum;
+#endif
+#ifdef FEAT_SYN_HL
+ did_update = DID_NONE;
+#endif
+ }
+
+ if (lnum > buf->b_ml.ml_line_count)
+ {
+ eof = TRUE;
+ break;
+ }
+ }
+ /*
+ * End of loop over all window lines.
+ */
+
+#ifdef FEAT_VTP
+ /* Rewrite the character at the end of the screen line. */
+ if (use_vtp())
+ {
+ int i;
+
+ for (i = 0; i < Rows; ++i)
+ if (enc_utf8)
+ if ((*mb_off2cells)(LineOffset[i] + Columns - 2,
+ LineOffset[i] + screen_Columns) > 1)
+ screen_draw_rectangle(i, Columns - 2, 1, 2, FALSE);
+ else
+ screen_draw_rectangle(i, Columns - 1, 1, 1, FALSE);
+ else
+ screen_char(LineOffset[i] + Columns - 1, i, Columns - 1);
+ }
+#endif
+
+ if (idx > wp->w_lines_valid)
+ wp->w_lines_valid = idx;
+
+#ifdef FEAT_SYN_HL
+ /*
+ * Let the syntax stuff know we stop parsing here.
+ */
+ if (syntax_last_parsed != 0 && syntax_present(wp))
+ syntax_end_parsing(syntax_last_parsed + 1);
+#endif
+
+ /*
+ * If we didn't hit the end of the file, and we didn't finish the last
+ * line we were working on, then the line didn't fit.
+ */
+ wp->w_empty_rows = 0;
+#ifdef FEAT_DIFF
+ wp->w_filler_rows = 0;
+#endif
+ if (!eof && !didline)
+ {
+ if (lnum == wp->w_topline)
+ {
+ /*
+ * Single line that does not fit!
+ * Don't overwrite it, it can be edited.
+ */
+ wp->w_botline = lnum + 1;
+ }
+#ifdef FEAT_DIFF
+ else if (diff_check_fill(wp, lnum) >= wp->w_height - srow)
+ {
+ /* Window ends in filler lines. */
+ wp->w_botline = lnum;
+ wp->w_filler_rows = wp->w_height - srow;
+ }
+#endif
+ else if (dy_flags & DY_TRUNCATE) /* 'display' has "truncate" */
+ {
+ int scr_row = W_WINROW(wp) + wp->w_height - 1;
+
+ /*
+ * Last line isn't finished: Display "@@@" in the last screen line.
+ */
+ screen_puts_len((char_u *)"@@", 2, scr_row, wp->w_wincol,
+ HL_ATTR(HLF_AT));
+ screen_fill(scr_row, scr_row + 1,
+ (int)wp->w_wincol + 2, (int)W_ENDCOL(wp),
+ '@', ' ', HL_ATTR(HLF_AT));
+ set_empty_rows(wp, srow);
+ wp->w_botline = lnum;
+ }
+ else if (dy_flags & DY_LASTLINE) /* 'display' has "lastline" */
+ {
+ /*
+ * Last line isn't finished: Display "@@@" at the end.
+ */
+ screen_fill(W_WINROW(wp) + wp->w_height - 1,
+ W_WINROW(wp) + wp->w_height,
+ (int)W_ENDCOL(wp) - 3, (int)W_ENDCOL(wp),
+ '@', '@', HL_ATTR(HLF_AT));
+ set_empty_rows(wp, srow);
+ wp->w_botline = lnum;
+ }
+ else
+ {
+ win_draw_end(wp, '@', ' ', srow, wp->w_height, HLF_AT);
+ wp->w_botline = lnum;
+ }
+ }
+ else
+ {
+ draw_vsep_win(wp, row);
+ if (eof) /* we hit the end of the file */
+ {
+ wp->w_botline = buf->b_ml.ml_line_count + 1;
+#ifdef FEAT_DIFF
+ j = diff_check_fill(wp, wp->w_botline);
+ if (j > 0 && !wp->w_botfill)
+ {
+ /*
+ * Display filler lines at the end of the file
+ */
+ if (char2cells(fill_diff) > 1)
+ i = '-';
+ else
+ i = fill_diff;
+ if (row + j > wp->w_height)
+ j = wp->w_height - row;
+ win_draw_end(wp, i, i, row, row + (int)j, HLF_DED);
+ row += j;
+ }
+#endif
+ }
+ else if (dollar_vcol == -1)
+ wp->w_botline = lnum;
+
+ /* make sure the rest of the screen is blank */
+ /* put '~'s on rows that aren't part of the file. */
+ win_draw_end(wp, '~', ' ', row, wp->w_height, HLF_EOB);
+ }
+
+#ifdef SYN_TIME_LIMIT
+ syn_set_timeout(NULL);
+#endif
+
+ /* Reset the type of redrawing required, the window has been updated. */
+ wp->w_redr_type = 0;
+#ifdef FEAT_DIFF
+ wp->w_old_topfill = wp->w_topfill;
+ wp->w_old_botfill = wp->w_botfill;
+#endif
+
+ if (dollar_vcol == -1)
+ {
+ /*
+ * There is a trick with w_botline. If we invalidate it on each
+ * change that might modify it, this will cause a lot of expensive
+ * calls to plines() in update_topline() each time. Therefore the
+ * value of w_botline is often approximated, and this value is used to
+ * compute the value of w_topline. If the value of w_botline was
+ * wrong, check that the value of w_topline is correct (cursor is on
+ * the visible part of the text). If it's not, we need to redraw
+ * again. Mostly this just means scrolling up a few lines, so it
+ * doesn't look too bad. Only do this for the current window (where
+ * changes are relevant).
+ */
+ wp->w_valid |= VALID_BOTLINE;
+ if (wp == curwin && wp->w_botline != old_botline && !recursive)
+ {
+ recursive = TRUE;
+ curwin->w_valid &= ~VALID_TOPLINE;
+ update_topline(); /* may invalidate w_botline again */
+ if (must_redraw != 0)
+ {
+ /* Don't update for changes in buffer again. */
+ i = curbuf->b_mod_set;
+ curbuf->b_mod_set = FALSE;
+ win_update(curwin);
+ must_redraw = 0;
+ curbuf->b_mod_set = i;
+ }
+ recursive = FALSE;
+ }
+ }
+
+#if defined(FEAT_SYN_HL) || defined(FEAT_SEARCH_EXTRA)
+ /* restore got_int, unless CTRL-C was hit while redrawing */
+ if (!got_int)
+ got_int = save_got_int;
+#endif
+}
+
+/*
+ * Clear the rest of the window and mark the unused lines with "c1". use "c2"
+ * as the filler character.
+ */
+ static void
+win_draw_end(
+ win_T *wp,
+ int c1,
+ int c2,
+ int row,
+ int endrow,
+ hlf_T hl)
+{
+#if defined(FEAT_FOLDING) || defined(FEAT_SIGNS) || defined(FEAT_CMDWIN)
+ int n = 0;
+# define FDC_OFF n
+#else
+# define FDC_OFF 0
+#endif
+#ifdef FEAT_FOLDING
+ int fdc = compute_foldcolumn(wp, 0);
+#endif
+
+#ifdef FEAT_RIGHTLEFT
+ if (wp->w_p_rl)
+ {
+ /* No check for cmdline window: should never be right-left. */
+# ifdef FEAT_FOLDING
+ n = fdc;
+
+ if (n > 0)
+ {
+ /* draw the fold column at the right */
+ if (n > wp->w_width)
+ n = wp->w_width;
+ screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
+ W_ENDCOL(wp) - n, (int)W_ENDCOL(wp),
+ ' ', ' ', HL_ATTR(HLF_FC));
+ }
+# endif
+# ifdef FEAT_SIGNS
+ if (signcolumn_on(wp))
+ {
+ int nn = n + 2;
+
+ /* draw the sign column left of the fold column */
+ if (nn > wp->w_width)
+ nn = wp->w_width;
+ screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
+ W_ENDCOL(wp) - nn, (int)W_ENDCOL(wp) - n,
+ ' ', ' ', HL_ATTR(HLF_SC));
+ n = nn;
+ }
+# endif
+ screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
+ wp->w_wincol, W_ENDCOL(wp) - 1 - FDC_OFF,
+ c2, c2, HL_ATTR(hl));
+ screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
+ W_ENDCOL(wp) - 1 - FDC_OFF, W_ENDCOL(wp) - FDC_OFF,
+ c1, c2, HL_ATTR(hl));
+ }
+ else
+#endif
+ {
+#ifdef FEAT_CMDWIN
+ if (cmdwin_type != 0 && wp == curwin)
+ {
+ /* draw the cmdline character in the leftmost column */
+ n = 1;
+ if (n > wp->w_width)
+ n = wp->w_width;
+ screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
+ wp->w_wincol, (int)wp->w_wincol + n,
+ cmdwin_type, ' ', HL_ATTR(HLF_AT));
+ }
+#endif
+#ifdef FEAT_FOLDING
+ if (fdc > 0)
+ {
+ int nn = n + fdc;
+
+ /* draw the fold column at the left */
+ if (nn > wp->w_width)
+ nn = wp->w_width;
+ screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
+ wp->w_wincol + n, (int)wp->w_wincol + nn,
+ ' ', ' ', HL_ATTR(HLF_FC));
+ n = nn;
+ }
+#endif
+#ifdef FEAT_SIGNS
+ if (signcolumn_on(wp))
+ {
+ int nn = n + 2;
+
+ /* draw the sign column after the fold column */
+ if (nn > wp->w_width)
+ nn = wp->w_width;
+ screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
+ wp->w_wincol + n, (int)wp->w_wincol + nn,
+ ' ', ' ', HL_ATTR(HLF_SC));
+ n = nn;
+ }
+#endif
+ screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
+ wp->w_wincol + FDC_OFF, (int)W_ENDCOL(wp),
+ c1, c2, HL_ATTR(hl));
+ }
+ set_empty_rows(wp, row);
+}
+
+#ifdef FEAT_SYN_HL
+/*
+ * Advance **color_cols and return TRUE when there are columns to draw.
+ */
+ static int
+advance_color_col(int vcol, int **color_cols)
+{
+ while (**color_cols >= 0 && vcol > **color_cols)
+ ++*color_cols;
+ return (**color_cols >= 0);
+}
+#endif
+
+#if defined(FEAT_MENU) || defined(FEAT_FOLDING)
+/*
+ * Copy "text" to ScreenLines using "attr".
+ * Returns the next screen column.
+ */
+ static int
+text_to_screenline(win_T *wp, char_u *text, int col)
+{
+ int off = (int)(current_ScreenLine - ScreenLines);
+
+ if (has_mbyte)
+ {
+ int cells;
+ int u8c, u8cc[MAX_MCO];
+ int i;
+ int idx;
+ int c_len;
+ char_u *p;
+# ifdef FEAT_ARABIC
+ int prev_c = 0; /* previous Arabic character */
+ int prev_c1 = 0; /* first composing char for prev_c */
+# endif
+
+# ifdef FEAT_RIGHTLEFT
+ if (wp->w_p_rl)
+ idx = off;
+ else
+# endif
+ idx = off + col;
+
+ /* Store multibyte characters in ScreenLines[] et al. correctly. */
+ for (p = text; *p != NUL; )
+ {
+ cells = (*mb_ptr2cells)(p);
+ c_len = (*mb_ptr2len)(p);
+ if (col + cells > wp->w_width
+# ifdef FEAT_RIGHTLEFT
+ - (wp->w_p_rl ? col : 0)
+# endif
+ )
+ break;
+ ScreenLines[idx] = *p;
+ if (enc_utf8)
+ {
+ u8c = utfc_ptr2char(p, u8cc);
+ if (*p < 0x80 && u8cc[0] == 0)
+ {
+ ScreenLinesUC[idx] = 0;
+#ifdef FEAT_ARABIC
+ prev_c = u8c;
+#endif
+ }
+ else
+ {
+#ifdef FEAT_ARABIC
+ if (p_arshape && !p_tbidi && ARABIC_CHAR(u8c))
+ {
+ /* Do Arabic shaping. */
+ int pc, pc1, nc;
+ int pcc[MAX_MCO];
+ int firstbyte = *p;
+
+ /* The idea of what is the previous and next
+ * character depends on 'rightleft'. */
+ if (wp->w_p_rl)
+ {
+ pc = prev_c;
+ pc1 = prev_c1;
+ nc = utf_ptr2char(p + c_len);
+ prev_c1 = u8cc[0];
+ }
+ else
+ {
+ pc = utfc_ptr2char(p + c_len, pcc);
+ nc = prev_c;
+ pc1 = pcc[0];
+ }
+ prev_c = u8c;
+
+ u8c = arabic_shape(u8c, &firstbyte, &u8cc[0],
+ pc, pc1, nc);
+ ScreenLines[idx] = firstbyte;
+ }
+ else
+ prev_c = u8c;
+#endif
+ /* Non-BMP character: display as ? or fullwidth ?. */
+ ScreenLinesUC[idx] = u8c;
+ for (i = 0; i < Screen_mco; ++i)
+ {
+ ScreenLinesC[i][idx] = u8cc[i];
+ if (u8cc[i] == 0)
+ break;
+ }
+ }
+ if (cells > 1)
+ ScreenLines[idx + 1] = 0;
+ }
+ else if (enc_dbcs == DBCS_JPNU && *p == 0x8e)
+ /* double-byte single width character */
+ ScreenLines2[idx] = p[1];
+ else if (cells > 1)
+ /* double-width character */
+ ScreenLines[idx + 1] = p[1];
+ col += cells;
+ idx += cells;
+ p += c_len;
+ }
+ }
+ else
+ {
+ int len = (int)STRLEN(text);
+
+ if (len > wp->w_width - col)
+ len = wp->w_width - col;
+ if (len > 0)
+ {
+#ifdef FEAT_RIGHTLEFT
+ if (wp->w_p_rl)
+ STRNCPY(current_ScreenLine, text, len);
+ else
+#endif
+ STRNCPY(current_ScreenLine + col, text, len);
+ col += len;
+ }
+ }
+ return col;
+}
+#endif
+
+#ifdef FEAT_FOLDING
+/*
+ * Compute the width of the foldcolumn. Based on 'foldcolumn' and how much
+ * space is available for window "wp", minus "col".
+ */
+ static int
+compute_foldcolumn(win_T *wp, int col)
+{
+ int fdc = wp->w_p_fdc;
+ int wmw = wp == curwin && p_wmw == 0 ? 1 : p_wmw;
+ int wwidth = wp->w_width;
+
+ if (fdc > wwidth - (col + wmw))
+ fdc = wwidth - (col + wmw);
+ return fdc;
+}
+
+/*
+ * Display one folded line.
+ */
+ static void
+fold_line(
+ win_T *wp,
+ long fold_count,
+ foldinfo_T *foldinfo,
+ linenr_T lnum,
+ int row)
+{
+ char_u buf[FOLD_TEXT_LEN];
+ pos_T *top, *bot;
+ linenr_T lnume = lnum + fold_count - 1;
+ int len;
+ char_u *text;
+ int fdc;
+ int col;
+ int txtcol;
+ int off = (int)(current_ScreenLine - ScreenLines);
+ int ri;
+
+ /* Build the fold line:
+ * 1. Add the cmdwin_type for the command-line window
+ * 2. Add the 'foldcolumn'
+ * 3. Add the 'number' or 'relativenumber' column
+ * 4. Compose the text
+ * 5. Add the text
+ * 6. set highlighting for the Visual area an other text
+ */
+ col = 0;
+
+ /*
+ * 1. Add the cmdwin_type for the command-line window
+ * Ignores 'rightleft', this window is never right-left.
+ */
+#ifdef FEAT_CMDWIN
+ if (cmdwin_type != 0 && wp == curwin)
+ {
+ ScreenLines[off] = cmdwin_type;
+ ScreenAttrs[off] = HL_ATTR(HLF_AT);
+ if (enc_utf8)
+ ScreenLinesUC[off] = 0;
+ ++col;
+ }
+#endif
+
+ /*
+ * 2. Add the 'foldcolumn'
+ * Reduce the width when there is not enough space.
+ */
+ fdc = compute_foldcolumn(wp, col);
+ if (fdc > 0)
+ {
+ fill_foldcolumn(buf, wp, TRUE, lnum);
+#ifdef FEAT_RIGHTLEFT
+ if (wp->w_p_rl)
+ {
+ int i;
+
+ copy_text_attr(off + wp->w_width - fdc - col, buf, fdc,
+ HL_ATTR(HLF_FC));
+ /* reverse the fold column */
+ for (i = 0; i < fdc; ++i)
+ ScreenLines[off + wp->w_width - i - 1 - col] = buf[i];
+ }
+ else
+#endif
+ copy_text_attr(off + col, buf, fdc, HL_ATTR(HLF_FC));
+ col += fdc;
+ }
+
+#ifdef FEAT_RIGHTLEFT
+# define RL_MEMSET(p, v, l) \
+ do { \
+ if (wp->w_p_rl) \
+ for (ri = 0; ri < l; ++ri) \
+ ScreenAttrs[off + (wp->w_width - (p) - (l)) + ri] = v; \
+ else \
+ for (ri = 0; ri < l; ++ri) \
+ ScreenAttrs[off + (p) + ri] = v; \
+ } while (0)
+#else
+# define RL_MEMSET(p, v, l) \
+ do { \
+ for (ri = 0; ri < l; ++ri) \
+ ScreenAttrs[off + (p) + ri] = v; \
+ } while (0)
+#endif
+
+ /* Set all attributes of the 'number' or 'relativenumber' column and the
+ * text */
+ RL_MEMSET(col, HL_ATTR(HLF_FL), wp->w_width - col);
+
+#ifdef FEAT_SIGNS
+ /* If signs are being displayed, add two spaces. */
+ if (signcolumn_on(wp))
+ {
+ len = wp->w_width - col;
+ if (len > 0)
+ {
+ if (len > 2)
+ len = 2;
+# ifdef FEAT_RIGHTLEFT
+ if (wp->w_p_rl)
+ /* the line number isn't reversed */
+ copy_text_attr(off + wp->w_width - len - col,
+ (char_u *)" ", len, HL_ATTR(HLF_FL));
+ else
+# endif
+ copy_text_attr(off + col, (char_u *)" ", len, HL_ATTR(HLF_FL));
+ col += len;
+ }
+ }
+#endif
+
+ /*
+ * 3. Add the 'number' or 'relativenumber' column
+ */
+ if (wp->w_p_nu || wp->w_p_rnu)
+ {
+ len = wp->w_width - col;
+ if (len > 0)
+ {
+ int w = number_width(wp);
+ long num;
+ char *fmt = "%*ld ";
+
+ if (len > w + 1)
+ len = w + 1;
+
+ if (wp->w_p_nu && !wp->w_p_rnu)
+ /* 'number' + 'norelativenumber' */
+ num = (long)lnum;
+ else
+ {
+ /* 'relativenumber', don't use negative numbers */
+ num = labs((long)get_cursor_rel_lnum(wp, lnum));
+ if (num == 0 && wp->w_p_nu && wp->w_p_rnu)
+ {
+ /* 'number' + 'relativenumber': cursor line shows absolute
+ * line number */
+ num = lnum;
+ fmt = "%-*ld ";
+ }
+ }
+
+ sprintf((char *)buf, fmt, w, num);
+#ifdef FEAT_RIGHTLEFT
+ if (wp->w_p_rl)
+ /* the line number isn't reversed */
+ copy_text_attr(off + wp->w_width - len - col, buf, len,
+ HL_ATTR(HLF_FL));
+ else
+#endif
+ copy_text_attr(off + col, buf, len, HL_ATTR(HLF_FL));
+ col += len;
+ }
+ }
+
+ /*
+ * 4. Compose the folded-line string with 'foldtext', if set.
+ */
+ text = get_foldtext(wp, lnum, lnume, foldinfo, buf);
+
+ txtcol = col; /* remember where text starts */
+
+ /*
+ * 5. move the text to current_ScreenLine. Fill up with "fill_fold".
+ * Right-left text is put in columns 0 - number-col, normal text is put
+ * in columns number-col - window-width.
+ */
+ col = text_to_screenline(wp, text, col);
+
+ /* Fill the rest of the line with the fold filler */
+#ifdef FEAT_RIGHTLEFT
+ if (wp->w_p_rl)
+ col -= txtcol;
+#endif
+ while (col < wp->w_width
+#ifdef FEAT_RIGHTLEFT
+ - (wp->w_p_rl ? txtcol : 0)
+#endif
+ )
+ {
+ if (enc_utf8)
+ {
+ if (fill_fold >= 0x80)
+ {
+ ScreenLinesUC[off + col] = fill_fold;
+ ScreenLinesC[0][off + col] = 0;
+ ScreenLines[off + col] = 0x80; /* avoid storing zero */
+ }
+ else
+ {
+ ScreenLinesUC[off + col] = 0;
+ ScreenLines[off + col] = fill_fold;
+ }
+ col++;
+ }
+ else
+ ScreenLines[off + col++] = fill_fold;
+ }
+
+ if (text != buf)
+ vim_free(text);
+
+ /*
+ * 6. set highlighting for the Visual area an other text.
+ * If all folded lines are in the Visual area, highlight the line.
+ */
+ if (VIsual_active && wp->w_buffer == curwin->w_buffer)
+ {
+ if (LTOREQ_POS(curwin->w_cursor, VIsual))
+ {
+ /* Visual is after curwin->w_cursor */
+ top = &curwin->w_cursor;
+ bot = &VIsual;
+ }
+ else
+ {
+ /* Visual is before curwin->w_cursor */
+ top = &VIsual;
+ bot = &curwin->w_cursor;
+ }
+ if (lnum >= top->lnum
+ && lnume <= bot->lnum
+ && (VIsual_mode != 'v'
+ || ((lnum > top->lnum
+ || (lnum == top->lnum
+ && top->col == 0))
+ && (lnume < bot->lnum
+ || (lnume == bot->lnum
+ && (bot->col - (*p_sel == 'e'))
+ >= (colnr_T)STRLEN(ml_get_buf(wp->w_buffer, lnume, FALSE)))))))
+ {
+ if (VIsual_mode == Ctrl_V)
+ {
+ /* Visual block mode: highlight the chars part of the block */
+ if (wp->w_old_cursor_fcol + txtcol < (colnr_T)wp->w_width)
+ {
+ if (wp->w_old_cursor_lcol != MAXCOL
+ && wp->w_old_cursor_lcol + txtcol
+ < (colnr_T)wp->w_width)
+ len = wp->w_old_cursor_lcol;
+ else
+ len = wp->w_width - txtcol;
+ RL_MEMSET(wp->w_old_cursor_fcol + txtcol, HL_ATTR(HLF_V),
+ len - (int)wp->w_old_cursor_fcol);
+ }
+ }
+ else
+ {
+ /* Set all attributes of the text */
+ RL_MEMSET(txtcol, HL_ATTR(HLF_V), wp->w_width - txtcol);
+ }
+ }
+ }
+
+#ifdef FEAT_SYN_HL
+ /* Show colorcolumn in the fold line, but let cursorcolumn override it. */
+ if (wp->w_p_cc_cols)
+ {
+ int i = 0;
+ int j = wp->w_p_cc_cols[i];
+ int old_txtcol = txtcol;
+
+ while (j > -1)
+ {
+ txtcol += j;
+ if (wp->w_p_wrap)
+ txtcol -= wp->w_skipcol;
+ else
+ txtcol -= wp->w_leftcol;
+ if (txtcol >= 0 && txtcol < wp->w_width)
+ ScreenAttrs[off + txtcol] = hl_combine_attr(
+ ScreenAttrs[off + txtcol], HL_ATTR(HLF_MC));
+ txtcol = old_txtcol;
+ j = wp->w_p_cc_cols[++i];
+ }
+ }
+
+ /* Show 'cursorcolumn' in the fold line. */
+ if (wp->w_p_cuc)
+ {
+ txtcol += wp->w_virtcol;
+ if (wp->w_p_wrap)
+ txtcol -= wp->w_skipcol;
+ else
+ txtcol -= wp->w_leftcol;
+ if (txtcol >= 0 && txtcol < wp->w_width)
+ ScreenAttrs[off + txtcol] = hl_combine_attr(
+ ScreenAttrs[off + txtcol], HL_ATTR(HLF_CUC));
+ }
+#endif
+
+ screen_line(row + W_WINROW(wp), wp->w_wincol, (int)wp->w_width,
+ (int)wp->w_width, FALSE);
+
+ /*
+ * Update w_cline_height and w_cline_folded if the cursor line was
+ * updated (saves a call to plines() later).
+ */
+ if (wp == curwin
+ && lnum <= curwin->w_cursor.lnum
+ && lnume >= curwin->w_cursor.lnum)
+ {
+ curwin->w_cline_row = row;
+ curwin->w_cline_height = 1;
+ curwin->w_cline_folded = TRUE;
+ curwin->w_valid |= (VALID_CHEIGHT|VALID_CROW);
+ }
+}
+
+/*
+ * Copy "buf[len]" to ScreenLines["off"] and set attributes to "attr".
+ */
+ static void
+copy_text_attr(
+ int off,
+ char_u *buf,
+ int len,
+ int attr)
+{
+ int i;
+
+ mch_memmove(ScreenLines + off, buf, (size_t)len);
+ if (enc_utf8)
+ vim_memset(ScreenLinesUC + off, 0, sizeof(u8char_T) * (size_t)len);
+ for (i = 0; i < len; ++i)
+ ScreenAttrs[off + i] = attr;
+}
+
+/*
+ * Fill the foldcolumn at "p" for window "wp".
+ * Only to be called when 'foldcolumn' > 0.
+ */
+ static void
+fill_foldcolumn(
+ char_u *p,
+ win_T *wp,
+ int closed, /* TRUE of FALSE */
+ linenr_T lnum) /* current line number */
+{
+ int i = 0;
+ int level;
+ int first_level;
+ int empty;
+ int fdc = compute_foldcolumn(wp, 0);
+
+ /* Init to all spaces. */
+ vim_memset(p, ' ', (size_t)fdc);
+
+ level = win_foldinfo.fi_level;
+ if (level > 0)
+ {
+ /* If there is only one column put more info in it. */
+ empty = (fdc == 1) ? 0 : 1;
+
+ /* If the column is too narrow, we start at the lowest level that
+ * fits and use numbers to indicated the depth. */
+ first_level = level - fdc - closed + 1 + empty;
+ if (first_level < 1)
+ first_level = 1;
+
+ for (i = 0; i + empty < fdc; ++i)
+ {
+ if (win_foldinfo.fi_lnum == lnum
+ && first_level + i >= win_foldinfo.fi_low_level)
+ p[i] = '-';
+ else if (first_level == 1)
+ p[i] = '|';
+ else if (first_level + i <= 9)
+ p[i] = '0' + first_level + i;
+ else
+ p[i] = '>';
+ if (first_level + i == level)
+ break;
+ }
+ }
+ if (closed)
+ p[i >= fdc ? i - 1 : i] = '+';
+}
+#endif /* FEAT_FOLDING */
+
+#ifdef FEAT_TEXT_PROP
+static textprop_T *current_text_props = NULL;
+static buf_T *current_buf = NULL;
+
+ static int
+#ifdef __BORLANDC__
+_RTLENTRYF
+#endif
+text_prop_compare(const void *s1, const void *s2)
+{
+ int idx1, idx2;
+ proptype_T *pt1, *pt2;
+ colnr_T col1, col2;
+
+ idx1 = *(int *)s1;
+ idx2 = *(int *)s2;
+ pt1 = text_prop_type_by_id(current_buf, current_text_props[idx1].tp_type);
+ pt2 = text_prop_type_by_id(current_buf, current_text_props[idx2].tp_type);
+ if (pt1 == pt2)
+ return 0;
+ if (pt1 == NULL)
+ return -1;
+ if (pt2 == NULL)
+ return 1;
+ if (pt1->pt_priority != pt2->pt_priority)
+ return pt1->pt_priority > pt2->pt_priority ? 1 : -1;
+ col1 = current_text_props[idx1].tp_col;
+ col2 = current_text_props[idx2].tp_col;
+ return col1 == col2 ? 0 : col1 > col2 ? 1 : -1;
+}
+#endif
+
+/*
+ * Display line "lnum" of window 'wp' on the screen.
+ * Start at row "startrow", stop when "endrow" is reached.
+ * wp->w_virtcol needs to be valid.
+ *
+ * Return the number of last row the line occupies.
+ */
+ static int
+win_line(
+ win_T *wp,
+ linenr_T lnum,
+ int startrow,
+ int endrow,
+ int nochange UNUSED, // not updating for changed text
+ int number_only) // only update the number column
+{
+ int col = 0; /* visual column on screen */
+ unsigned off; /* offset in ScreenLines/ScreenAttrs */
+ int c = 0; /* init for GCC */
+ long vcol = 0; /* virtual column (for tabs) */
+#ifdef FEAT_LINEBREAK
+ long vcol_sbr = -1; /* virtual column after showbreak */
+#endif
+ long vcol_prev = -1; /* "vcol" of previous character */
+ char_u *line; /* current line */
+ char_u *ptr; /* current position in "line" */
+ int row; /* row in the window, excl w_winrow */
+ int screen_row; /* row on the screen, incl w_winrow */
+
+ char_u extra[18]; /* "%ld" and 'fdc' must fit in here */
+ int n_extra = 0; /* number of extra chars */
+ char_u *p_extra = NULL; /* string of extra chars, plus NUL */
+ char_u *p_extra_free = NULL; /* p_extra needs to be freed */
+ int c_extra = NUL; /* extra chars, all the same */
+ int c_final = NUL; /* final char, mandatory if set */
+ int extra_attr = 0; /* attributes when n_extra != 0 */
+ static char_u *at_end_str = (char_u *)""; /* used for p_extra when
+ displaying lcs_eol at end-of-line */
+ int lcs_eol_one = lcs_eol; /* lcs_eol until it's been used */
+ int lcs_prec_todo = lcs_prec; /* lcs_prec until it's been used */
+
+ /* saved "extra" items for when draw_state becomes WL_LINE (again) */
+ int saved_n_extra = 0;
+ char_u *saved_p_extra = NULL;
+ int saved_c_extra = 0;
+ int saved_c_final = 0;
+ int saved_char_attr = 0;
+
+ int n_attr = 0; /* chars with special attr */
+ int saved_attr2 = 0; /* char_attr saved for n_attr */
+ int n_attr3 = 0; /* chars with overruling special attr */
+ int saved_attr3 = 0; /* char_attr saved for n_attr3 */
+
+ int n_skip = 0; /* nr of chars to skip for 'nowrap' */
+
+ int fromcol, tocol; /* start/end of inverting */
+ int fromcol_prev = -2; /* start of inverting after cursor */
+ int noinvcur = FALSE; /* don't invert the cursor */
+ pos_T *top, *bot;
+ int lnum_in_visual_area = FALSE;
+ pos_T pos;
+ long v;
+
+ int char_attr = 0; /* attributes for next character */
+ int attr_pri = FALSE; /* char_attr has priority */
+ int area_highlighting = FALSE; /* Visual or incsearch highlighting
+ in this line */
+ int attr = 0; /* attributes for area highlighting */
+ int area_attr = 0; /* attributes desired by highlighting */
+ int search_attr = 0; /* attributes desired by 'hlsearch' */
+#ifdef FEAT_SYN_HL
+ int vcol_save_attr = 0; /* saved attr for 'cursorcolumn' */
+ int syntax_attr = 0; /* attributes desired by syntax */
+ int has_syntax = FALSE; /* this buffer has syntax highl. */
+ int save_did_emsg;
+ int eol_hl_off = 0; /* 1 if highlighted char after EOL */
+ int draw_color_col = FALSE; /* highlight colorcolumn */
+ int *color_cols = NULL; /* pointer to according columns array */
+#endif
+#ifdef FEAT_TEXT_PROP
+ int text_prop_count;
+ int text_prop_next = 0; // next text property to use
+ textprop_T *text_props = NULL;
+ int *text_prop_idxs = NULL;
+ int text_props_active = 0;
+ proptype_T *text_prop_type = NULL;
+ int text_prop_attr = 0;
+#endif
+#ifdef FEAT_SPELL
+ int has_spell = FALSE; /* this buffer has spell checking */
+# define SPWORDLEN 150
+ char_u nextline[SPWORDLEN * 2];/* text with start of the next line */
+ int nextlinecol = 0; /* column where nextline[] starts */
+ int nextline_idx = 0; /* index in nextline[] where next line
+ starts */
+ int spell_attr = 0; /* attributes desired by spelling */
+ int word_end = 0; /* last byte with same spell_attr */
+ static linenr_T checked_lnum = 0; /* line number for "checked_col" */
+ static int checked_col = 0; /* column in "checked_lnum" up to which
+ * there are no spell errors */
+ static int cap_col = -1; /* column to check for Cap word */
+ static linenr_T capcol_lnum = 0; /* line number where "cap_col" used */
+ int cur_checked_col = 0; /* checked column for current line */
+#endif
+ int extra_check = 0; // has extra highlighting
+ int multi_attr = 0; /* attributes desired by multibyte */
+ int mb_l = 1; /* multi-byte byte length */
+ int mb_c = 0; /* decoded multi-byte character */
+ int mb_utf8 = FALSE; /* screen char is UTF-8 char */
+ int u8cc[MAX_MCO]; /* composing UTF-8 chars */
+#ifdef FEAT_DIFF
+ int filler_lines; /* nr of filler lines to be drawn */
+ int filler_todo; /* nr of filler lines still to do + 1 */
+ hlf_T diff_hlf = (hlf_T)0; /* type of diff highlighting */
+ int change_start = MAXCOL; /* first col of changed area */
+ int change_end = -1; /* last col of changed area */
+#endif
+ colnr_T trailcol = MAXCOL; /* start of trailing spaces */
+#ifdef FEAT_LINEBREAK
+ int need_showbreak = FALSE; /* overlong line, skipping first x
+ chars */
+#endif
+#if defined(FEAT_SIGNS) || defined(FEAT_QUICKFIX) \
+ || defined(FEAT_SYN_HL) || defined(FEAT_DIFF)
+# define LINE_ATTR
+ int line_attr = 0; /* attribute for the whole line */
+#endif
+#ifdef FEAT_SEARCH_EXTRA
+ matchitem_T *cur; /* points to the match list */
+ match_T *shl; /* points to search_hl or a match */
+ int shl_flag; /* flag to indicate whether search_hl
+ has been processed or not */
+ int pos_inprogress; /* marks that position match search is
+ in progress */
+ int prevcol_hl_flag; /* flag to indicate whether prevcol
+ equals startcol of search_hl or one
+ of the matches */
+#endif
+#ifdef FEAT_ARABIC
+ int prev_c = 0; /* previous Arabic character */
+ int prev_c1 = 0; /* first composing char for prev_c */
+#endif
+#if defined(LINE_ATTR)
+ int did_line_attr = 0;
+#endif
+#ifdef FEAT_TERMINAL
+ int get_term_attr = FALSE;
+ int term_attr = 0; /* background for terminal window */
+#endif
+
+ /* draw_state: items that are drawn in sequence: */
+#define WL_START 0 /* nothing done yet */
+#ifdef FEAT_CMDWIN
+# define WL_CMDLINE WL_START + 1 /* cmdline window column */
+#else
+# define WL_CMDLINE WL_START
+#endif
+#ifdef FEAT_FOLDING
+# define WL_FOLD WL_CMDLINE + 1 /* 'foldcolumn' */
+#else
+# define WL_FOLD WL_CMDLINE
+#endif
+#ifdef FEAT_SIGNS
+# define WL_SIGN WL_FOLD + 1 /* column for signs */
+#else
+# define WL_SIGN WL_FOLD /* column for signs */
+#endif
+#define WL_NR WL_SIGN + 1 /* line number */
+#ifdef FEAT_LINEBREAK
+# define WL_BRI WL_NR + 1 /* 'breakindent' */
+#else
+# define WL_BRI WL_NR
+#endif
+#if defined(FEAT_LINEBREAK) || defined(FEAT_DIFF)
+# define WL_SBR WL_BRI + 1 /* 'showbreak' or 'diff' */
+#else
+# define WL_SBR WL_BRI
+#endif
+#define WL_LINE WL_SBR + 1 /* text in the line */
+ int draw_state = WL_START; /* what to draw next */
+#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
+ int feedback_col = 0;
+ int feedback_old_attr = -1;
+#endif
+
+#ifdef FEAT_CONCEAL
+ int syntax_flags = 0;
+ int syntax_seqnr = 0;
+ int prev_syntax_id = 0;
+ int conceal_attr = HL_ATTR(HLF_CONCEAL);
+ int is_concealing = FALSE;
+ int boguscols = 0; /* nonexistent columns added to force
+ wrapping */
+ int vcol_off = 0; /* offset for concealed characters */
+ int did_wcol = FALSE;
+ int match_conc = 0; /* cchar for match functions */
+ int has_match_conc = 0; /* match wants to conceal */
+ int old_boguscols = 0;
+# define VCOL_HLC (vcol - vcol_off)
+# define FIX_FOR_BOGUSCOLS \
+ { \
+ n_extra += vcol_off; \
+ vcol -= vcol_off; \
+ vcol_off = 0; \
+ col -= boguscols; \
+ old_boguscols = boguscols; \
+ boguscols = 0; \
+ }
+#else
+# define VCOL_HLC (vcol)
+#endif
+
+ if (startrow > endrow) /* past the end already! */
+ return startrow;
+
+ row = startrow;
+ screen_row = row + W_WINROW(wp);
+
+ if (!number_only)
+ {
+ /*
+ * To speed up the loop below, set extra_check when there is linebreak,
+ * trailing white space and/or syntax processing to be done.
+ */
+#ifdef FEAT_LINEBREAK
+ extra_check = wp->w_p_lbr;
+#endif
+#ifdef FEAT_SYN_HL
+ if (syntax_present(wp) && !wp->w_s->b_syn_error
+# ifdef SYN_TIME_LIMIT
+ && !wp->w_s->b_syn_slow
+# endif
+ )
+ {
+ /* Prepare for syntax highlighting in this line. When there is an
+ * error, stop syntax highlighting. */
+ save_did_emsg = did_emsg;
+ did_emsg = FALSE;
+ syntax_start(wp, lnum);
+ if (did_emsg)
+ wp->w_s->b_syn_error = TRUE;
+ else
+ {
+ did_emsg = save_did_emsg;
+#ifdef SYN_TIME_LIMIT
+ if (!wp->w_s->b_syn_slow)
+#endif
+ {
+ has_syntax = TRUE;
+ extra_check = TRUE;
+ }
+ }
+ }
+
+ /* Check for columns to display for 'colorcolumn'. */
+ color_cols = wp->w_p_cc_cols;
+ if (color_cols != NULL)
+ draw_color_col = advance_color_col(VCOL_HLC, &color_cols);
+#endif
+
+#ifdef FEAT_TERMINAL
+ if (term_show_buffer(wp->w_buffer))
+ {
+ extra_check = TRUE;
+ get_term_attr = TRUE;
+ term_attr = term_get_attr(wp->w_buffer, lnum, -1);
+ }
+#endif
+
+#ifdef FEAT_SPELL
+ if (wp->w_p_spell
+ && *wp->w_s->b_p_spl != NUL
+ && wp->w_s->b_langp.ga_len > 0
+ && *(char **)(wp->w_s->b_langp.ga_data) != NULL)
+ {
+ /* Prepare for spell checking. */
+ has_spell = TRUE;
+ extra_check = TRUE;
+
+ /* Get the start of the next line, so that words that wrap to the
+ * next line are found too: "et<line-break>al.".
+ * Trick: skip a few chars for C/shell/Vim comments */
+ nextline[SPWORDLEN] = NUL;
+ if (lnum < wp->w_buffer->b_ml.ml_line_count)
+ {
+ line = ml_get_buf(wp->w_buffer, lnum + 1, FALSE);
+ spell_cat_line(nextline + SPWORDLEN, line, SPWORDLEN);
+ }
+
+ /* When a word wrapped from the previous line the start of the
+ * current line is valid. */
+ if (lnum == checked_lnum)
+ cur_checked_col = checked_col;
+ checked_lnum = 0;
+
+ /* When there was a sentence end in the previous line may require a
+ * word starting with capital in this line. In line 1 always check
+ * the first word. */
+ if (lnum != capcol_lnum)
+ cap_col = -1;
+ if (lnum == 1)
+ cap_col = 0;
+ capcol_lnum = 0;
+ }
+#endif
+
+ /*
+ * handle visual active in this window
+ */
+ fromcol = -10;
+ tocol = MAXCOL;
+ if (VIsual_active && wp->w_buffer == curwin->w_buffer)
+ {
+ /* Visual is after curwin->w_cursor */
+ if (LTOREQ_POS(curwin->w_cursor, VIsual))
+ {
+ top = &curwin->w_cursor;
+ bot = &VIsual;
+ }
+ else /* Visual is before curwin->w_cursor */
+ {
+ top = &VIsual;
+ bot = &curwin->w_cursor;
+ }
+ lnum_in_visual_area = (lnum >= top->lnum && lnum <= bot->lnum);
+ if (VIsual_mode == Ctrl_V) /* block mode */
+ {
+ if (lnum_in_visual_area)
+ {
+ fromcol = wp->w_old_cursor_fcol;
+ tocol = wp->w_old_cursor_lcol;
+ }
+ }
+ else /* non-block mode */
+ {
+ if (lnum > top->lnum && lnum <= bot->lnum)
+ fromcol = 0;
+ else if (lnum == top->lnum)
+ {
+ if (VIsual_mode == 'V') /* linewise */
+ fromcol = 0;
+ else
+ {
+ getvvcol(wp, top, (colnr_T *)&fromcol, NULL, NULL);
+ if (gchar_pos(top) == NUL)
+ tocol = fromcol + 1;
+ }
+ }
+ if (VIsual_mode != 'V' && lnum == bot->lnum)
+ {
+ if (*p_sel == 'e' && bot->col == 0 && bot->coladd == 0)
+ {
+ fromcol = -10;
+ tocol = MAXCOL;
+ }
+ else if (bot->col == MAXCOL)
+ tocol = MAXCOL;
+ else
+ {
+ pos = *bot;
+ if (*p_sel == 'e')
+ getvvcol(wp, &pos, (colnr_T *)&tocol, NULL, NULL);
+ else
+ {
+ getvvcol(wp, &pos, NULL, NULL, (colnr_T *)&tocol);
+ ++tocol;
+ }
+ }
+ }
+ }
+
+ /* Check if the character under the cursor should not be inverted */
+ if (!highlight_match && lnum == curwin->w_cursor.lnum && wp == curwin
+#ifdef FEAT_GUI
+ && !gui.in_use
+#endif
+ )
+ noinvcur = TRUE;
+
+ /* if inverting in this line set area_highlighting */
+ if (fromcol >= 0)
+ {
+ area_highlighting = TRUE;
+ attr = HL_ATTR(HLF_V);
+#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
+ if ((clip_star.available && !clip_star.owned
+ && clip_isautosel_star())
+ || (clip_plus.available && !clip_plus.owned
+ && clip_isautosel_plus()))
+ attr = HL_ATTR(HLF_VNC);
+#endif
+ }
+ }
+
+ /*
+ * handle 'incsearch' and ":s///c" highlighting
+ */
+ else if (highlight_match
+ && wp == curwin
+ && lnum >= curwin->w_cursor.lnum
+ && lnum <= curwin->w_cursor.lnum + search_match_lines)
+ {
+ if (lnum == curwin->w_cursor.lnum)
+ getvcol(curwin, &(curwin->w_cursor),
+ (colnr_T *)&fromcol, NULL, NULL);
+ else
+ fromcol = 0;
+ if (lnum == curwin->w_cursor.lnum + search_match_lines)
+ {
+ pos.lnum = lnum;
+ pos.col = search_match_endcol;
+ getvcol(curwin, &pos, (colnr_T *)&tocol, NULL, NULL);
+ }
+ else
+ tocol = MAXCOL;
+ /* do at least one character; happens when past end of line */
+ if (fromcol == tocol)
+ tocol = fromcol + 1;
+ area_highlighting = TRUE;
+ attr = HL_ATTR(HLF_I);
+ }
+ }
+
+#ifdef FEAT_DIFF
+ filler_lines = diff_check(wp, lnum);
+ if (filler_lines < 0)
+ {
+ if (filler_lines == -1)
+ {
+ if (diff_find_change(wp, lnum, &change_start, &change_end))
+ diff_hlf = HLF_ADD; /* added line */
+ else if (change_start == 0)
+ diff_hlf = HLF_TXD; /* changed text */
+ else
+ diff_hlf = HLF_CHD; /* changed line */
+ }
+ else
+ diff_hlf = HLF_ADD; /* added line */
+ filler_lines = 0;
+ area_highlighting = TRUE;
+ }
+ if (lnum == wp->w_topline)
+ filler_lines = wp->w_topfill;
+ filler_todo = filler_lines;
+#endif
+
+#ifdef LINE_ATTR
+# ifdef FEAT_SIGNS
+ /* If this line has a sign with line highlighting set line_attr. */
+ v = buf_getsigntype(wp->w_buffer, lnum, SIGN_LINEHL);
+ if (v != 0)
+ line_attr = sign_get_attr((int)v, TRUE);
+# endif
+# if defined(FEAT_QUICKFIX)
+ /* Highlight the current line in the quickfix window. */
+ if (bt_quickfix(wp->w_buffer) && qf_current_entry(wp) == lnum)
+ line_attr = HL_ATTR(HLF_QFL);
+# endif
+ if (line_attr != 0)
+ area_highlighting = TRUE;
+#endif
+
+ line = ml_get_buf(wp->w_buffer, lnum, FALSE);
+ ptr = line;
+
+#ifdef FEAT_SPELL
+ if (has_spell && !number_only)
+ {
+ /* For checking first word with a capital skip white space. */
+ if (cap_col == 0)
+ cap_col = getwhitecols(line);
+
+ /* To be able to spell-check over line boundaries copy the end of the
+ * current line into nextline[]. Above the start of the next line was
+ * copied to nextline[SPWORDLEN]. */
+ if (nextline[SPWORDLEN] == NUL)
+ {
+ /* No next line or it is empty. */
+ nextlinecol = MAXCOL;
+ nextline_idx = 0;
+ }
+ else
+ {
+ v = (long)STRLEN(line);
+ if (v < SPWORDLEN)
+ {
+ /* Short line, use it completely and append the start of the
+ * next line. */
+ nextlinecol = 0;
+ mch_memmove(nextline, line, (size_t)v);
+ STRMOVE(nextline + v, nextline + SPWORDLEN);
+ nextline_idx = v + 1;
+ }
+ else
+ {
+ /* Long line, use only the last SPWORDLEN bytes. */
+ nextlinecol = v - SPWORDLEN;
+ mch_memmove(nextline, line + nextlinecol, SPWORDLEN);
+ nextline_idx = SPWORDLEN + 1;
+ }
+ }
+ }
+#endif
+
+ if (wp->w_p_list)
+ {
+ if (lcs_space || lcs_trail || lcs_nbsp)
+ extra_check = TRUE;
+ /* find start of trailing whitespace */
+ if (lcs_trail)
+ {
+ trailcol = (colnr_T)STRLEN(ptr);
+ while (trailcol > (colnr_T)0 && VIM_ISWHITE(ptr[trailcol - 1]))
+ --trailcol;
+ trailcol += (colnr_T) (ptr - line);
+ }
+ }
+
+ /*
+ * 'nowrap' or 'wrap' and a single line that doesn't fit: Advance to the
+ * first character to be displayed.
+ */
+ if (wp->w_p_wrap)
+ v = wp->w_skipcol;
+ else
+ v = wp->w_leftcol;
+ if (v > 0 && !number_only)
+ {
+ char_u *prev_ptr = ptr;
+
+ while (vcol < v && *ptr != NUL)
+ {
+ c = win_lbr_chartabsize(wp, line, ptr, (colnr_T)vcol, NULL);
+ vcol += c;
+ prev_ptr = ptr;
+ MB_PTR_ADV(ptr);
+ }
+
+ /* When:
+ * - 'cuc' is set, or
+ * - 'colorcolumn' is set, or
+ * - 'virtualedit' is set, or
+ * - the visual mode is active,
+ * the end of the line may be before the start of the displayed part.
+ */
+ if (vcol < v && (
+#ifdef FEAT_SYN_HL
+ wp->w_p_cuc || draw_color_col ||
+#endif
+ virtual_active() ||
+ (VIsual_active && wp->w_buffer == curwin->w_buffer)))
+ {
+ vcol = v;
+ }
+
+ /* Handle a character that's not completely on the screen: Put ptr at
+ * that character but skip the first few screen characters. */
+ if (vcol > v)
+ {
+ vcol -= c;
+ ptr = prev_ptr;
+ /* If the character fits on the screen, don't need to skip it.
+ * Except for a TAB. */
+ if (( (*mb_ptr2cells)(ptr) >= c || *ptr == TAB) && col == 0)
+ n_skip = v - vcol;
+ }
+
+ /*
+ * Adjust for when the inverted text is before the screen,
+ * and when the start of the inverted text is before the screen.
+ */
+ if (tocol <= vcol)
+ fromcol = 0;
+ else if (fromcol >= 0 && fromcol < vcol)
+ fromcol = vcol;
+
+#ifdef FEAT_LINEBREAK
+ /* When w_skipcol is non-zero, first line needs 'showbreak' */
+ if (wp->w_p_wrap)
+ need_showbreak = TRUE;
+#endif
+#ifdef FEAT_SPELL
+ /* When spell checking a word we need to figure out the start of the
+ * word and if it's badly spelled or not. */
+ if (has_spell)
+ {
+ int len;
+ colnr_T linecol = (colnr_T)(ptr - line);
+ hlf_T spell_hlf = HLF_COUNT;
+
+ pos = wp->w_cursor;
+ wp->w_cursor.lnum = lnum;
+ wp->w_cursor.col = linecol;
+ len = spell_move_to(wp, FORWARD, TRUE, TRUE, &spell_hlf);
+
+ /* spell_move_to() may call ml_get() and make "line" invalid */
+ line = ml_get_buf(wp->w_buffer, lnum, FALSE);
+ ptr = line + linecol;
+
+ if (len == 0 || (int)wp->w_cursor.col > ptr - line)
+ {
+ /* no bad word found at line start, don't check until end of a
+ * word */
+ spell_hlf = HLF_COUNT;
+ word_end = (int)(spell_to_word_end(ptr, wp) - line + 1);
+ }
+ else
+ {
+ /* bad word found, use attributes until end of word */
+ word_end = wp->w_cursor.col + len + 1;
+
+ /* Turn index into actual attributes. */
+ if (spell_hlf != HLF_COUNT)
+ spell_attr = highlight_attr[spell_hlf];
+ }
+ wp->w_cursor = pos;
+
+# ifdef FEAT_SYN_HL
+ /* Need to restart syntax highlighting for this line. */
+ if (has_syntax)
+ syntax_start(wp, lnum);
+# endif
+ }
+#endif
+ }
+
+ /*
+ * Correct highlighting for cursor that can't be disabled.
+ * Avoids having to check this for each character.
+ */
+ if (fromcol >= 0)
+ {
+ if (noinvcur)
+ {
+ if ((colnr_T)fromcol == wp->w_virtcol)
+ {
+ /* highlighting starts at cursor, let it start just after the
+ * cursor */
+ fromcol_prev = fromcol;
+ fromcol = -1;
+ }
+ else if ((colnr_T)fromcol < wp->w_virtcol)
+ /* restart highlighting after the cursor */
+ fromcol_prev = wp->w_virtcol;
+ }
+ if (fromcol >= tocol)
+ fromcol = -1;
+ }
+
+#ifdef FEAT_SEARCH_EXTRA
+ /*
+ * Handle highlighting the last used search pattern and matches.
+ * Do this for both search_hl and the match list.
+ */
+ cur = wp->w_match_head;
+ shl_flag = FALSE;
+ while ((cur != NULL || shl_flag == FALSE) && !number_only)
+ {
+ if (shl_flag == FALSE)
+ {
+ shl = &search_hl;
+ shl_flag = TRUE;
+ }
+ else
+ shl = &cur->hl;
+ shl->startcol = MAXCOL;
+ shl->endcol = MAXCOL;
+ shl->attr_cur = 0;
+ shl->is_addpos = FALSE;
+ v = (long)(ptr - line);
+ if (cur != NULL)
+ cur->pos.cur = 0;
+ next_search_hl(wp, shl, lnum, (colnr_T)v,
+ shl == &search_hl ? NULL : cur);
+
+ /* Need to get the line again, a multi-line regexp may have made it
+ * invalid. */
+ line = ml_get_buf(wp->w_buffer, lnum, FALSE);
+ ptr = line + v;
+
+ if (shl->lnum != 0 && shl->lnum <= lnum)
+ {
+ if (shl->lnum == lnum)
+ shl->startcol = shl->rm.startpos[0].col;
+ else
+ shl->startcol = 0;
+ if (lnum == shl->lnum + shl->rm.endpos[0].lnum
+ - shl->rm.startpos[0].lnum)
+ shl->endcol = shl->rm.endpos[0].col;
+ else
+ shl->endcol = MAXCOL;
+ /* Highlight one character for an empty match. */
+ if (shl->startcol == shl->endcol)
+ {
+ if (has_mbyte && line[shl->endcol] != NUL)
+ shl->endcol += (*mb_ptr2len)(line + shl->endcol);
+ else
+ ++shl->endcol;
+ }
+ if ((long)shl->startcol < v) /* match at leftcol */
+ {
+ shl->attr_cur = shl->attr;
+ search_attr = shl->attr;
+ }
+ area_highlighting = TRUE;
+ }
+ if (shl != &search_hl && cur != NULL)
+ cur = cur->next;
+ }
+#endif
+
+#ifdef FEAT_SYN_HL
+ /* Cursor line highlighting for 'cursorline' in the current window. Not
+ * when Visual mode is active, because it's not clear what is selected
+ * then. */
+ if (wp->w_p_cul && lnum == wp->w_cursor.lnum
+ && !(wp == curwin && VIsual_active))
+ {
+ line_attr = HL_ATTR(HLF_CUL);
+ area_highlighting = TRUE;
+ wp->w_last_cursorline = wp->w_cursor.lnum;
+ }
+#endif
+
+#ifdef FEAT_TEXT_PROP
+ {
+ char_u *prop_start;
+
+ text_prop_count = get_text_props(wp->w_buffer, lnum,
+ &prop_start, FALSE);
+ if (text_prop_count > 0)
+ {
+ // Make a copy of the properties, so that they are properly
+ // aligned.
+ text_props = (textprop_T *)alloc(
+ text_prop_count * sizeof(textprop_T));
+ if (text_props != NULL)
+ mch_memmove(text_props, prop_start,
+ text_prop_count * sizeof(textprop_T));
+
+ // Allocate an array for the indexes.
+ text_prop_idxs = (int *)alloc(text_prop_count * sizeof(int));
+ area_highlighting = TRUE;
+ extra_check = TRUE;
+ }
+ }
+#endif
+
+ off = (unsigned)(current_ScreenLine - ScreenLines);
+ col = 0;
+#ifdef FEAT_RIGHTLEFT
+ if (wp->w_p_rl)
+ {
+ /* Rightleft window: process the text in the normal direction, but put
+ * it in current_ScreenLine[] from right to left. Start at the
+ * rightmost column of the window. */
+ col = wp->w_width - 1;
+ off += col;
+ }
+#endif
+
+ /*
+ * Repeat for the whole displayed line.
+ */
+ for (;;)
+ {
+#ifdef FEAT_CONCEAL
+ has_match_conc = 0;
+#endif
+ /* Skip this quickly when working on the text. */
+ if (draw_state != WL_LINE)
+ {
+#ifdef FEAT_CMDWIN
+ if (draw_state == WL_CMDLINE - 1 && n_extra == 0)
+ {
+ draw_state = WL_CMDLINE;
+ if (cmdwin_type != 0 && wp == curwin)
+ {
+ /* Draw the cmdline character. */
+ n_extra = 1;
+ c_extra = cmdwin_type;
+ c_final = NUL;
+ char_attr = HL_ATTR(HLF_AT);
+ }
+ }
+#endif
+
+#ifdef FEAT_FOLDING
+ if (draw_state == WL_FOLD - 1 && n_extra == 0)
+ {
+ int fdc = compute_foldcolumn(wp, 0);
+
+ draw_state = WL_FOLD;
+ if (fdc > 0)
+ {
+ /* Draw the 'foldcolumn'. Allocate a buffer, "extra" may
+ * already be in use. */
+ vim_free(p_extra_free);
+ p_extra_free = alloc(12 + 1);
+
+ if (p_extra_free != NULL)
+ {
+ fill_foldcolumn(p_extra_free, wp, FALSE, lnum);
+ n_extra = fdc;
+ p_extra_free[n_extra] = NUL;
+ p_extra = p_extra_free;
+ c_extra = NUL;
+ c_final = NUL;
+ char_attr = HL_ATTR(HLF_FC);
+ }
+ }
+ }
+#endif
+
+#ifdef FEAT_SIGNS
+ if (draw_state == WL_SIGN - 1 && n_extra == 0)
+ {
+ draw_state = WL_SIGN;
+ /* Show the sign column when there are any signs in this
+ * buffer or when using Netbeans. */
+ if (signcolumn_on(wp))
+ {
+ int text_sign;
+# ifdef FEAT_SIGN_ICONS
+ int icon_sign;
+# endif
+
+ /* Draw two cells with the sign value or blank. */
+ c_extra = ' ';
+ c_final = NUL;
+ char_attr = HL_ATTR(HLF_SC);
+ n_extra = 2;
+
+ if (row == startrow
+#ifdef FEAT_DIFF
+ + filler_lines && filler_todo <= 0
+#endif
+ )
+ {
+ text_sign = buf_getsigntype(wp->w_buffer, lnum,
+ SIGN_TEXT);
+# ifdef FEAT_SIGN_ICONS
+ icon_sign = buf_getsigntype(wp->w_buffer, lnum,
+ SIGN_ICON);
+ if (gui.in_use && icon_sign != 0)
+ {
+ /* Use the image in this position. */
+ c_extra = SIGN_BYTE;
+ c_final = NUL;
+# ifdef FEAT_NETBEANS_INTG
+ if (buf_signcount(wp->w_buffer, lnum) > 1)
+ {
+ c_extra = MULTISIGN_BYTE;
+ c_final = NUL;
+ }
+# endif
+ char_attr = icon_sign;
+ }
+ else
+# endif
+ if (text_sign != 0)
+ {
+ p_extra = sign_get_text(text_sign);
+ if (p_extra != NULL)
+ {
+ c_extra = NUL;
+ c_final = NUL;
+ n_extra = (int)STRLEN(p_extra);
+ }
+ char_attr = sign_get_attr(text_sign, FALSE);
+ }
+ }
+ }
+ }
+#endif
+
+ if (draw_state == WL_NR - 1 && n_extra == 0)
+ {
+ draw_state = WL_NR;
+ /* Display the absolute or relative line number. After the
+ * first fill with blanks when the 'n' flag isn't in 'cpo' */
+ if ((wp->w_p_nu || wp->w_p_rnu)
+ && (row == startrow
+#ifdef FEAT_DIFF
+ + filler_lines
+#endif
+ || vim_strchr(p_cpo, CPO_NUMCOL) == NULL))
+ {
+ /* Draw the line number (empty space after wrapping). */
+ if (row == startrow
+#ifdef FEAT_DIFF
+ + filler_lines
+#endif
+ )
+ {
+ long num;
+ char *fmt = "%*ld ";
+
+ if (wp->w_p_nu && !wp->w_p_rnu)
+ /* 'number' + 'norelativenumber' */
+ num = (long)lnum;
+ else
+ {
+ /* 'relativenumber', don't use negative numbers */
+ num = labs((long)get_cursor_rel_lnum(wp, lnum));
+ if (num == 0 && wp->w_p_nu && wp->w_p_rnu)
+ {
+ /* 'number' + 'relativenumber' */
+ num = lnum;
+ fmt = "%-*ld ";
+ }
+ }
+
+ sprintf((char *)extra, fmt,
+ number_width(wp), num);
+ if (wp->w_skipcol > 0)
+ for (p_extra = extra; *p_extra == ' '; ++p_extra)
+ *p_extra = '-';
+#ifdef FEAT_RIGHTLEFT
+ if (wp->w_p_rl) /* reverse line numbers */
+ rl_mirror(extra);
+#endif
+ p_extra = extra;
+ c_extra = NUL;
+ c_final = NUL;
+ }
+ else
+ {
+ c_extra = ' ';
+ c_final = NUL;
+ }
+ n_extra = number_width(wp) + 1;
+ char_attr = HL_ATTR(HLF_N);
+#ifdef FEAT_SYN_HL
+ /* When 'cursorline' is set highlight the line number of
+ * the current line differently.
+ * TODO: Can we use CursorLine instead of CursorLineNr
+ * when CursorLineNr isn't set? */
+ if ((wp->w_p_cul || wp->w_p_rnu)
+ && lnum == wp->w_cursor.lnum)
+ char_attr = HL_ATTR(HLF_CLN);
+#endif
+ }
+ }
+
+#ifdef FEAT_LINEBREAK
+ if (wp->w_p_brisbr && draw_state == WL_BRI - 1
+ && n_extra == 0 && *p_sbr != NUL)
+ /* draw indent after showbreak value */
+ draw_state = WL_BRI;
+ else if (wp->w_p_brisbr && draw_state == WL_SBR && n_extra == 0)
+ /* After the showbreak, draw the breakindent */
+ draw_state = WL_BRI - 1;
+
+ /* draw 'breakindent': indent wrapped text accordingly */
+ if (draw_state == WL_BRI - 1 && n_extra == 0)
+ {
+ draw_state = WL_BRI;
+ /* if need_showbreak is set, breakindent also applies */
+ if (wp->w_p_bri && n_extra == 0
+ && (row != startrow || need_showbreak)
+# ifdef FEAT_DIFF
+ && filler_lines == 0
+# endif
+ )
+ {
+ char_attr = 0;
+# ifdef FEAT_DIFF
+ if (diff_hlf != (hlf_T)0)
+ {
+ char_attr = HL_ATTR(diff_hlf);
+# ifdef FEAT_SYN_HL
+ if (wp->w_p_cul && lnum == wp->w_cursor.lnum)
+ char_attr = hl_combine_attr(char_attr,
+ HL_ATTR(HLF_CUL));
+# endif
+ }
+# endif
+ p_extra = NULL;
+ c_extra = ' ';
+ n_extra = get_breakindent_win(wp,
+ ml_get_buf(wp->w_buffer, lnum, FALSE));
+ /* Correct end of highlighted area for 'breakindent',
+ * required when 'linebreak' is also set. */
+ if (tocol == vcol)
+ tocol += n_extra;
+ }
+ }
+#endif
+
+#if defined(FEAT_LINEBREAK) || defined(FEAT_DIFF)
+ if (draw_state == WL_SBR - 1 && n_extra == 0)
+ {
+ draw_state = WL_SBR;
+# ifdef FEAT_DIFF
+ if (filler_todo > 0)
+ {
+ /* Draw "deleted" diff line(s). */
+ if (char2cells(fill_diff) > 1)
+ {
+ c_extra = '-';
+ c_final = NUL;
+ }
+ else
+ {
+ c_extra = fill_diff;
+ c_final = NUL;
+ }
+# ifdef FEAT_RIGHTLEFT
+ if (wp->w_p_rl)
+ n_extra = col + 1;
+ else
+# endif
+ n_extra = wp->w_width - col;
+ char_attr = HL_ATTR(HLF_DED);
+ }
+# endif
+# ifdef FEAT_LINEBREAK
+ if (*p_sbr != NUL && need_showbreak)
+ {
+ /* Draw 'showbreak' at the start of each broken line. */
+ p_extra = p_sbr;
+ c_extra = NUL;
+ c_final = NUL;
+ n_extra = (int)STRLEN(p_sbr);
+ char_attr = HL_ATTR(HLF_AT);
+ need_showbreak = FALSE;
+ vcol_sbr = vcol + MB_CHARLEN(p_sbr);
+ /* Correct end of highlighted area for 'showbreak',
+ * required when 'linebreak' is also set. */
+ if (tocol == vcol)
+ tocol += n_extra;
+#ifdef FEAT_SYN_HL
+ /* combine 'showbreak' with 'cursorline' */
+ if (wp->w_p_cul && lnum == wp->w_cursor.lnum)
+ char_attr = hl_combine_attr(char_attr,
+ HL_ATTR(HLF_CUL));
+#endif
+ }
+# endif
+ }
+#endif
+
+ if (draw_state == WL_LINE - 1 && n_extra == 0)
+ {
+ draw_state = WL_LINE;
+ if (saved_n_extra)
+ {
+ /* Continue item from end of wrapped line. */
+ n_extra = saved_n_extra;
+ c_extra = saved_c_extra;
+ c_final = saved_c_final;
+ p_extra = saved_p_extra;
+ char_attr = saved_char_attr;
+ }
+ else
+ char_attr = 0;
+ }
+ }
+
+ // When still displaying '$' of change command, stop at cursor.
+ // When only displaying the (relative) line number and that's done,
+ // stop here.
+ if ((dollar_vcol >= 0 && wp == curwin
+ && lnum == wp->w_cursor.lnum && vcol >= (long)wp->w_virtcol
+#ifdef FEAT_DIFF
+ && filler_todo <= 0
+#endif
+ )
+ || (number_only && draw_state > WL_NR))
+ {
+ screen_line(screen_row, wp->w_wincol, col, -(int)wp->w_width,
+ HAS_RIGHTLEFT(wp->w_p_rl));
+ /* Pretend we have finished updating the window. Except when
+ * 'cursorcolumn' is set. */
+#ifdef FEAT_SYN_HL
+ if (wp->w_p_cuc)
+ row = wp->w_cline_row + wp->w_cline_height;
+ else
+#endif
+ row = wp->w_height;
+ break;
+ }
+
+ if (draw_state == WL_LINE && (area_highlighting
+#ifdef FEAT_SPELL
+ || has_spell
+#endif
+ ))
+ {
+ /* handle Visual or match highlighting in this line */
+ if (vcol == fromcol
+ || (has_mbyte && vcol + 1 == fromcol && n_extra == 0
+ && (*mb_ptr2cells)(ptr) > 1)
+ || ((int)vcol_prev == fromcol_prev
+ && vcol_prev < vcol /* not at margin */
+ && vcol < tocol))
+ area_attr = attr; /* start highlighting */
+ else if (area_attr != 0
+ && (vcol == tocol
+ || (noinvcur && (colnr_T)vcol == wp->w_virtcol)))
+ area_attr = 0; /* stop highlighting */
+
+#ifdef FEAT_SEARCH_EXTRA
+ if (!n_extra)
+ {
+ /*
+ * Check for start/end of search pattern match.
+ * After end, check for start/end of next match.
+ * When another match, have to check for start again.
+ * Watch out for matching an empty string!
+ * Do this for 'search_hl' and the match list (ordered by
+ * priority).
+ */
+ v = (long)(ptr - line);
+ cur = wp->w_match_head;
+ shl_flag = FALSE;
+ while (cur != NULL || shl_flag == FALSE)
+ {
+ if (shl_flag == FALSE
+ && ((cur != NULL
+ && cur->priority > SEARCH_HL_PRIORITY)
+ || cur == NULL))
+ {
+ shl = &search_hl;
+ shl_flag = TRUE;
+ }
+ else
+ shl = &cur->hl;
+ if (cur != NULL)
+ cur->pos.cur = 0;
+ pos_inprogress = TRUE;
+ while (shl->rm.regprog != NULL
+ || (cur != NULL && pos_inprogress))
+ {
+ if (shl->startcol != MAXCOL
+ && v >= (long)shl->startcol
+ && v < (long)shl->endcol)
+ {
+ int tmp_col = v + MB_PTR2LEN(ptr);
+
+ if (shl->endcol < tmp_col)
+ shl->endcol = tmp_col;
+ shl->attr_cur = shl->attr;
+#ifdef FEAT_CONCEAL
+ if (cur != NULL && syn_name2id((char_u *)"Conceal")
+ == cur->hlg_id)
+ {
+ has_match_conc =
+ v == (long)shl->startcol ? 2 : 1;
+ match_conc = cur->conceal_char;
+ }
+ else
+ has_match_conc = match_conc = 0;
+#endif
+ }
+ else if (v == (long)shl->endcol)
+ {
+ shl->attr_cur = 0;
+ next_search_hl(wp, shl, lnum, (colnr_T)v,
+ shl == &search_hl ? NULL : cur);
+ pos_inprogress = cur == NULL || cur->pos.cur == 0
+ ? FALSE : TRUE;
+
+ /* Need to get the line again, a multi-line regexp
+ * may have made it invalid. */
+ line = ml_get_buf(wp->w_buffer, lnum, FALSE);
+ ptr = line + v;
+
+ if (shl->lnum == lnum)
+ {
+ shl->startcol = shl->rm.startpos[0].col;
+ if (shl->rm.endpos[0].lnum == 0)
+ shl->endcol = shl->rm.endpos[0].col;
+ else
+ shl->endcol = MAXCOL;
+
+ if (shl->startcol == shl->endcol)
+ {
+ /* highlight empty match, try again after
+ * it */
+ if (has_mbyte)
+ shl->endcol += (*mb_ptr2len)(line
+ + shl->endcol);
+ else
+ ++shl->endcol;
+ }
+
+ /* Loop to check if the match starts at the
+ * current position */
+ continue;
+ }
+ }
+ break;
+ }
+ if (shl != &search_hl && cur != NULL)
+ cur = cur->next;
+ }
+
+ /* Use attributes from match with highest priority among
+ * 'search_hl' and the match list. */
+ search_attr = search_hl.attr_cur;
+ cur = wp->w_match_head;
+ shl_flag = FALSE;
+ while (cur != NULL || shl_flag == FALSE)
+ {
+ if (shl_flag == FALSE
+ && ((cur != NULL
+ && cur->priority > SEARCH_HL_PRIORITY)
+ || cur == NULL))
+ {
+ shl = &search_hl;
+ shl_flag = TRUE;
+ }
+ else
+ shl = &cur->hl;
+ if (shl->attr_cur != 0)
+ search_attr = shl->attr_cur;
+ if (shl != &search_hl && cur != NULL)
+ cur = cur->next;
+ }
+ /* Only highlight one character after the last column. */
+ if (*ptr == NUL && (did_line_attr >= 1
+ || (wp->w_p_list && lcs_eol_one == -1)))
+ search_attr = 0;
+ }
+#endif
+
+#ifdef FEAT_DIFF
+ if (diff_hlf != (hlf_T)0)
+ {
+ if (diff_hlf == HLF_CHD && ptr - line >= change_start
+ && n_extra == 0)
+ diff_hlf = HLF_TXD; /* changed text */
+ if (diff_hlf == HLF_TXD && ptr - line > change_end
+ && n_extra == 0)
+ diff_hlf = HLF_CHD; /* changed line */
+ line_attr = HL_ATTR(diff_hlf);
+ if (wp->w_p_cul && lnum == wp->w_cursor.lnum)
+ line_attr = hl_combine_attr(line_attr, HL_ATTR(HLF_CUL));
+ }
+#endif
+
+#ifdef FEAT_TEXT_PROP
+ if (text_props != NULL)
+ {
+ int pi;
+ int bcol = (int)(ptr - line);
+
+ // Check if any active property ends.
+ for (pi = 0; pi < text_props_active; ++pi)
+ {
+ int tpi = text_prop_idxs[pi];
+
+ if (bcol >= text_props[tpi].tp_col - 1
+ + text_props[tpi].tp_len)
+ {
+ if (pi + 1 < text_props_active)
+ mch_memmove(text_prop_idxs + pi,
+ text_prop_idxs + pi + 1,
+ sizeof(int)
+ * (text_props_active - (pi + 1)));
+ --text_props_active;
+ --pi;
+ }
+ }
+
+ // Add any text property that starts in this column.
+ while (text_prop_next < text_prop_count
+ && bcol >= text_props[text_prop_next].tp_col - 1)
+ text_prop_idxs[text_props_active++] = text_prop_next++;
+
+ text_prop_attr = 0;
+ if (text_props_active > 0)
+ {
+ // Sort the properties on priority and/or starting last.
+ // Then combine the attributes, highest priority last.
+ current_text_props = text_props;
+ current_buf = wp->w_buffer;
+ qsort((void *)text_prop_idxs, (size_t)text_props_active,
+ sizeof(int), text_prop_compare);
+
+ for (pi = 0; pi < text_props_active; ++pi)
+ {
+ int tpi = text_prop_idxs[pi];
+ proptype_T *pt = text_prop_type_by_id(wp->w_buffer, text_props[tpi].tp_type);
+
+ if (pt != NULL)
+ {
+ int pt_attr = syn_id2attr(pt->pt_hl_id);
+
+ text_prop_type = pt;
+ if (text_prop_attr == 0)
+ text_prop_attr = pt_attr;
+ else
+ text_prop_attr = hl_combine_attr(text_prop_attr, pt_attr);
+ }
+ }
+ }
+ }
+#endif
+
+ /* Decide which of the highlight attributes to use. */
+ attr_pri = TRUE;
+#ifdef LINE_ATTR
+ if (area_attr != 0)
+ char_attr = hl_combine_attr(line_attr, area_attr);
+ else if (search_attr != 0)
+ char_attr = hl_combine_attr(line_attr, search_attr);
+ /* Use line_attr when not in the Visual or 'incsearch' area
+ * (area_attr may be 0 when "noinvcur" is set). */
+ else if (line_attr != 0 && ((fromcol == -10 && tocol == MAXCOL)
+ || vcol < fromcol || vcol_prev < fromcol_prev
+ || vcol >= tocol))
+ char_attr = line_attr;
+#else
+ if (area_attr != 0)
+ char_attr = area_attr;
+ else if (search_attr != 0)
+ char_attr = search_attr;
+#endif
+ else
+ {
+ attr_pri = FALSE;
+#ifdef FEAT_TEXT_PROP
+ if (text_prop_type != NULL)
+ char_attr = text_prop_attr;
+ else
+#endif
+#ifdef FEAT_SYN_HL
+ if (has_syntax)
+ char_attr = syntax_attr;
+ else
+#endif
+ char_attr = 0;
+ }
+ }
+
+ /*
+ * Get the next character to put on the screen.
+ */
+ /*
+ * The "p_extra" points to the extra stuff that is inserted to
+ * represent special characters (non-printable stuff) and other
+ * things. When all characters are the same, c_extra is used.
+ * If c_final is set, it will compulsorily be used at the end.
+ * "p_extra" must end in a NUL to avoid mb_ptr2len() reads past
+ * "p_extra[n_extra]".
+ * For the '$' of the 'list' option, n_extra == 1, p_extra == "".
+ */
+ if (n_extra > 0)
+ {
+ if (c_extra != NUL || (n_extra == 1 && c_final != NUL))
+ {
+ c = (n_extra == 1 && c_final != NUL) ? c_final : c_extra;
+ mb_c = c; /* doesn't handle non-utf-8 multi-byte! */
+ if (enc_utf8 && utf_char2len(c) > 1)
+ {
+ mb_utf8 = TRUE;
+ u8cc[0] = 0;
+ c = 0xc0;
+ }
+ else
+ mb_utf8 = FALSE;
+ }
+ else
+ {
+ c = *p_extra;
+ if (has_mbyte)
+ {
+ mb_c = c;
+ if (enc_utf8)
+ {
+ /* If the UTF-8 character is more than one byte:
+ * Decode it into "mb_c". */
+ mb_l = utfc_ptr2len(p_extra);
+ mb_utf8 = FALSE;
+ if (mb_l > n_extra)
+ mb_l = 1;
+ else if (mb_l > 1)
+ {
+ mb_c = utfc_ptr2char(p_extra, u8cc);
+ mb_utf8 = TRUE;
+ c = 0xc0;
+ }
+ }
+ else
+ {
+ /* if this is a DBCS character, put it in "mb_c" */
+ mb_l = MB_BYTE2LEN(c);
+ if (mb_l >= n_extra)
+ mb_l = 1;
+ else if (mb_l > 1)
+ mb_c = (c << 8) + p_extra[1];
+ }
+ if (mb_l == 0) /* at the NUL at end-of-line */
+ mb_l = 1;
+
+ /* If a double-width char doesn't fit display a '>' in the
+ * last column. */
+ if ((
+# ifdef FEAT_RIGHTLEFT
+ wp->w_p_rl ? (col <= 0) :
+# endif
+ (col >= wp->w_width - 1))
+ && (*mb_char2cells)(mb_c) == 2)
+ {
+ c = '>';
+ mb_c = c;
+ mb_l = 1;
+ mb_utf8 = FALSE;
+ multi_attr = HL_ATTR(HLF_AT);
+ /* put the pointer back to output the double-width
+ * character at the start of the next line. */
+ ++n_extra;
+ --p_extra;
+ }
+ else
+ {
+ n_extra -= mb_l - 1;
+ p_extra += mb_l - 1;
+ }
+ }
+ ++p_extra;
+ }
+ --n_extra;
+ }
+ else
+ {
+#ifdef FEAT_LINEBREAK
+ int c0;
+#endif
+
+ if (p_extra_free != NULL)
+ VIM_CLEAR(p_extra_free);
+ /*
+ * Get a character from the line itself.
+ */
+ c = *ptr;
+#ifdef FEAT_LINEBREAK
+ c0 = *ptr;
+#endif
+ if (has_mbyte)
+ {
+ mb_c = c;
+ if (enc_utf8)
+ {
+ /* If the UTF-8 character is more than one byte: Decode it
+ * into "mb_c". */
+ mb_l = utfc_ptr2len(ptr);
+ mb_utf8 = FALSE;
+ if (mb_l > 1)
+ {
+ mb_c = utfc_ptr2char(ptr, u8cc);
+ /* Overlong encoded ASCII or ASCII with composing char
+ * is displayed normally, except a NUL. */
+ if (mb_c < 0x80)
+ {
+ c = mb_c;
+#ifdef FEAT_LINEBREAK
+ c0 = mb_c;
+#endif
+ }
+ mb_utf8 = TRUE;
+
+ /* At start of the line we can have a composing char.
+ * Draw it as a space with a composing char. */
+ if (utf_iscomposing(mb_c))
+ {
+ int i;
+
+ for (i = Screen_mco - 1; i > 0; --i)
+ u8cc[i] = u8cc[i - 1];
+ u8cc[0] = mb_c;
+ mb_c = ' ';
+ }
+ }
+
+ if ((mb_l == 1 && c >= 0x80)
+ || (mb_l >= 1 && mb_c == 0)
+ || (mb_l > 1 && (!vim_isprintc(mb_c))))
+ {
+ /*
+ * Illegal UTF-8 byte: display as <xx>.
+ * Non-BMP character : display as ? or fullwidth ?.
+ */
+ transchar_hex(extra, mb_c);
+# ifdef FEAT_RIGHTLEFT
+ if (wp->w_p_rl) /* reverse */
+ rl_mirror(extra);
+# endif
+ p_extra = extra;
+ c = *p_extra;
+ mb_c = mb_ptr2char_adv(&p_extra);
+ mb_utf8 = (c >= 0x80);
+ n_extra = (int)STRLEN(p_extra);
+ c_extra = NUL;
+ c_final = NUL;
+ if (area_attr == 0 && search_attr == 0)
+ {
+ n_attr = n_extra + 1;
+ extra_attr = HL_ATTR(HLF_8);
+ saved_attr2 = char_attr; /* save current attr */
+ }
+ }
+ else if (mb_l == 0) /* at the NUL at end-of-line */
+ mb_l = 1;
+#ifdef FEAT_ARABIC
+ else if (p_arshape && !p_tbidi && ARABIC_CHAR(mb_c))
+ {
+ /* Do Arabic shaping. */
+ int pc, pc1, nc;
+ int pcc[MAX_MCO];
+
+ /* The idea of what is the previous and next
+ * character depends on 'rightleft'. */
+ if (wp->w_p_rl)
+ {
+ pc = prev_c;
+ pc1 = prev_c1;
+ nc = utf_ptr2char(ptr + mb_l);
+ prev_c1 = u8cc[0];
+ }
+ else
+ {
+ pc = utfc_ptr2char(ptr + mb_l, pcc);
+ nc = prev_c;
+ pc1 = pcc[0];
+ }
+ prev_c = mb_c;
+
+ mb_c = arabic_shape(mb_c, &c, &u8cc[0], pc, pc1, nc);
+ }
+ else
+ prev_c = mb_c;
+#endif
+ }
+ else /* enc_dbcs */
+ {
+ mb_l = MB_BYTE2LEN(c);
+ if (mb_l == 0) /* at the NUL at end-of-line */
+ mb_l = 1;
+ else if (mb_l > 1)
+ {
+ /* We assume a second byte below 32 is illegal.
+ * Hopefully this is OK for all double-byte encodings!
+ */
+ if (ptr[1] >= 32)
+ mb_c = (c << 8) + ptr[1];
+ else
+ {
+ if (ptr[1] == NUL)
+ {
+ /* head byte at end of line */
+ mb_l = 1;
+ transchar_nonprint(extra, c);
+ }
+ else
+ {
+ /* illegal tail byte */
+ mb_l = 2;
+ STRCPY(extra, "XX");
+ }
+ p_extra = extra;
+ n_extra = (int)STRLEN(extra) - 1;
+ c_extra = NUL;
+ c_final = NUL;
+ c = *p_extra++;
+ if (area_attr == 0 && search_attr == 0)
+ {
+ n_attr = n_extra + 1;
+ extra_attr = HL_ATTR(HLF_8);
+ saved_attr2 = char_attr; /* save current attr */
+ }
+ mb_c = c;
+ }
+ }
+ }
+ /* If a double-width char doesn't fit display a '>' in the
+ * last column; the character is displayed at the start of the
+ * next line. */
+ if ((
+# ifdef FEAT_RIGHTLEFT
+ wp->w_p_rl ? (col <= 0) :
+# endif
+ (col >= wp->w_width - 1))
+ && (*mb_char2cells)(mb_c) == 2)
+ {
+ c = '>';
+ mb_c = c;
+ mb_utf8 = FALSE;
+ mb_l = 1;
+ multi_attr = HL_ATTR(HLF_AT);
+ /* Put pointer back so that the character will be
+ * displayed at the start of the next line. */
+ --ptr;
+ }
+ else if (*ptr != NUL)
+ ptr += mb_l - 1;
+
+ /* If a double-width char doesn't fit at the left side display
+ * a '<' in the first column. Don't do this for unprintable
+ * characters. */
+ if (n_skip > 0 && mb_l > 1 && n_extra == 0)
+ {
+ n_extra = 1;
+ c_extra = MB_FILLER_CHAR;
+ c_final = NUL;
+ c = ' ';
+ if (area_attr == 0 && search_attr == 0)
+ {
+ n_attr = n_extra + 1;
+ extra_attr = HL_ATTR(HLF_AT);
+ saved_attr2 = char_attr; /* save current attr */
+ }
+ mb_c = c;
+ mb_utf8 = FALSE;
+ mb_l = 1;
+ }
+
+ }
+ ++ptr;
+
+ if (extra_check)
+ {
+#ifdef FEAT_SPELL
+ int can_spell = TRUE;
+#endif
+
+#ifdef FEAT_TERMINAL
+ if (get_term_attr)
+ {
+ syntax_attr = term_get_attr(wp->w_buffer, lnum, vcol);
+
+ if (!attr_pri)
+ char_attr = syntax_attr;
+ else
+ char_attr = hl_combine_attr(syntax_attr, char_attr);
+ }
+#endif
+
+#ifdef FEAT_SYN_HL
+ // Get syntax attribute, unless still at the start of the line
+ // (double-wide char that doesn't fit).
+ v = (long)(ptr - line);
+ if (has_syntax && v > 0)
+ {
+ /* Get the syntax attribute for the character. If there
+ * is an error, disable syntax highlighting. */
+ save_did_emsg = did_emsg;
+ did_emsg = FALSE;
+
+ syntax_attr = get_syntax_attr((colnr_T)v - 1,
+# ifdef FEAT_SPELL
+ has_spell ? &can_spell :
+# endif
+ NULL, FALSE);
+
+ if (did_emsg)
+ {
+ wp->w_s->b_syn_error = TRUE;
+ has_syntax = FALSE;
+ }
+ else
+ did_emsg = save_did_emsg;
+#ifdef SYN_TIME_LIMIT
+ if (wp->w_s->b_syn_slow)
+ has_syntax = FALSE;
+#endif
+
+ /* Need to get the line again, a multi-line regexp may
+ * have made it invalid. */
+ line = ml_get_buf(wp->w_buffer, lnum, FALSE);
+ ptr = line + v;
+
+# ifdef FEAT_TEXT_PROP
+ // Text properties overrule syntax highlighting.
+ if (text_prop_attr == 0)
+#endif
+ {
+ if (!attr_pri)
+ char_attr = syntax_attr;
+ else
+ char_attr = hl_combine_attr(syntax_attr, char_attr);
+ }
+# ifdef FEAT_CONCEAL
+ /* no concealing past the end of the line, it interferes
+ * with line highlighting */
+ if (c == NUL)
+ syntax_flags = 0;
+ else
+ syntax_flags = get_syntax_info(&syntax_seqnr);
+# endif
+ }
+#endif
+
+#ifdef FEAT_SPELL
+ /* Check spelling (unless at the end of the line).
+ * Only do this when there is no syntax highlighting, the
+ * @Spell cluster is not used or the current syntax item
+ * contains the @Spell cluster. */
+ if (has_spell && v >= word_end && v > cur_checked_col)
+ {
+ spell_attr = 0;
+ if (c != 0 && (
+# ifdef FEAT_SYN_HL
+ !has_syntax ||
+# endif
+ can_spell))
+ {
+ char_u *prev_ptr, *p;
+ int len;
+ hlf_T spell_hlf = HLF_COUNT;
+ if (has_mbyte)
+ {
+ prev_ptr = ptr - mb_l;
+ v -= mb_l - 1;
+ }
+ else
+ prev_ptr = ptr - 1;
+
+ /* Use nextline[] if possible, it has the start of the
+ * next line concatenated. */
+ if ((prev_ptr - line) - nextlinecol >= 0)
+ p = nextline + (prev_ptr - line) - nextlinecol;
+ else
+ p = prev_ptr;
+ cap_col -= (int)(prev_ptr - line);
+ len = spell_check(wp, p, &spell_hlf, &cap_col,
+ nochange);
+ word_end = v + len;
+
+ /* In Insert mode only highlight a word that
+ * doesn't touch the cursor. */
+ if (spell_hlf != HLF_COUNT
+ && (State & INSERT) != 0
+ && wp->w_cursor.lnum == lnum
+ && wp->w_cursor.col >=
+ (colnr_T)(prev_ptr - line)
+ && wp->w_cursor.col < (colnr_T)word_end)
+ {
+ spell_hlf = HLF_COUNT;
+ spell_redraw_lnum = lnum;
+ }
+
+ if (spell_hlf == HLF_COUNT && p != prev_ptr
+ && (p - nextline) + len > nextline_idx)
+ {
+ /* Remember that the good word continues at the
+ * start of the next line. */
+ checked_lnum = lnum + 1;
+ checked_col = (int)((p - nextline) + len - nextline_idx);
+ }
+
+ /* Turn index into actual attributes. */
+ if (spell_hlf != HLF_COUNT)
+ spell_attr = highlight_attr[spell_hlf];
+
+ if (cap_col > 0)
+ {
+ if (p != prev_ptr
+ && (p - nextline) + cap_col >= nextline_idx)
+ {
+ /* Remember that the word in the next line
+ * must start with a capital. */
+ capcol_lnum = lnum + 1;
+ cap_col = (int)((p - nextline) + cap_col
+ - nextline_idx);
+ }
+ else
+ /* Compute the actual column. */
+ cap_col += (int)(prev_ptr - line);
+ }
+ }
+ }
+ if (spell_attr != 0)
+ {
+ if (!attr_pri)
+ char_attr = hl_combine_attr(char_attr, spell_attr);
+ else
+ char_attr = hl_combine_attr(spell_attr, char_attr);
+ }
+#endif
+#ifdef FEAT_LINEBREAK
+ /*
+ * Found last space before word: check for line break.
+ */
+ if (wp->w_p_lbr && c0 == c
+ && VIM_ISBREAK(c) && !VIM_ISBREAK((int)*ptr))
+ {
+ int mb_off = has_mbyte ? (*mb_head_off)(line, ptr - 1) : 0;
+ char_u *p = ptr - (mb_off + 1);
+
+ /* TODO: is passing p for start of the line OK? */
+ n_extra = win_lbr_chartabsize(wp, line, p, (colnr_T)vcol,
+ NULL) - 1;
+ if (c == TAB && n_extra + col > wp->w_width)
+# ifdef FEAT_VARTABS
+ n_extra = tabstop_padding(vcol, wp->w_buffer->b_p_ts,
+ wp->w_buffer->b_p_vts_array) - 1;
+# else
+ n_extra = (int)wp->w_buffer->b_p_ts
+ - vcol % (int)wp->w_buffer->b_p_ts - 1;
+# endif
+
+ c_extra = mb_off > 0 ? MB_FILLER_CHAR : ' ';
+ c_final = NUL;
+ if (VIM_ISWHITE(c))
+ {
+#ifdef FEAT_CONCEAL
+ if (c == TAB)
+ /* See "Tab alignment" below. */
+ FIX_FOR_BOGUSCOLS;
+#endif
+ if (!wp->w_p_list)
+ c = ' ';
+ }
+ }
+#endif
+
+ /* 'list': change char 160 to lcs_nbsp and space to lcs_space.
+ */
+ if (wp->w_p_list
+ && (((c == 160
+ || (mb_utf8 && (mb_c == 160 || mb_c == 0x202f)))
+ && lcs_nbsp)
+ || (c == ' ' && lcs_space && ptr - line <= trailcol)))
+ {
+ c = (c == ' ') ? lcs_space : lcs_nbsp;
+ if (area_attr == 0 && search_attr == 0)
+ {
+ n_attr = 1;
+ extra_attr = HL_ATTR(HLF_8);
+ saved_attr2 = char_attr; /* save current attr */
+ }
+ mb_c = c;
+ if (enc_utf8 && utf_char2len(c) > 1)
+ {
+ mb_utf8 = TRUE;
+ u8cc[0] = 0;
+ c = 0xc0;
+ }
+ else
+ mb_utf8 = FALSE;
+ }
+
+ if (trailcol != MAXCOL && ptr > line + trailcol && c == ' ')
+ {
+ c = lcs_trail;
+ if (!attr_pri)
+ {
+ n_attr = 1;
+ extra_attr = HL_ATTR(HLF_8);
+ saved_attr2 = char_attr; /* save current attr */
+ }
+ mb_c = c;
+ if (enc_utf8 && utf_char2len(c) > 1)
+ {
+ mb_utf8 = TRUE;
+ u8cc[0] = 0;
+ c = 0xc0;
+ }
+ else
+ mb_utf8 = FALSE;
+ }
+ }
+
+ /*
+ * Handling of non-printable characters.
+ */
+ if (!vim_isprintc(c))
+ {
+ /*
+ * when getting a character from the file, we may have to
+ * turn it into something else on the way to putting it
+ * into "ScreenLines".
+ */
+ if (c == TAB && (!wp->w_p_list || lcs_tab1))
+ {
+ int tab_len = 0;
+ long vcol_adjusted = vcol; /* removed showbreak length */
+#ifdef FEAT_LINEBREAK
+ /* only adjust the tab_len, when at the first column
+ * after the showbreak value was drawn */
+ if (*p_sbr != NUL && vcol == vcol_sbr && wp->w_p_wrap)
+ vcol_adjusted = vcol - MB_CHARLEN(p_sbr);
+#endif
+ /* tab amount depends on current column */
+#ifdef FEAT_VARTABS
+ tab_len = tabstop_padding(vcol_adjusted,
+ wp->w_buffer->b_p_ts,
+ wp->w_buffer->b_p_vts_array) - 1;
+#else
+ tab_len = (int)wp->w_buffer->b_p_ts
+ - vcol_adjusted % (int)wp->w_buffer->b_p_ts - 1;
+#endif
+
+#ifdef FEAT_LINEBREAK
+ if (!wp->w_p_lbr || !wp->w_p_list)
+#endif
+ /* tab amount depends on current column */
+ n_extra = tab_len;
+#ifdef FEAT_LINEBREAK
+ else
+ {
+ char_u *p;
+ int len = n_extra;
+ int i;
+ int saved_nextra = n_extra;
+
+#ifdef FEAT_CONCEAL
+ if (vcol_off > 0)
+ /* there are characters to conceal */
+ tab_len += vcol_off;
+ /* boguscols before FIX_FOR_BOGUSCOLS macro from above
+ */
+ if (wp->w_p_list && lcs_tab1 && old_boguscols > 0
+ && n_extra > tab_len)
+ tab_len += n_extra - tab_len;
+#endif
+
+ /* if n_extra > 0, it gives the number of chars, to
+ * use for a tab, else we need to calculate the width
+ * for a tab */
+ len = (tab_len * mb_char2len(lcs_tab2));
+ if (n_extra > 0)
+ len += n_extra - tab_len;
+ c = lcs_tab1;
+ p = alloc((unsigned)(len + 1));
+ vim_memset(p, ' ', len);
+ p[len] = NUL;
+ vim_free(p_extra_free);
+ p_extra_free = p;
+ for (i = 0; i < tab_len; i++)
+ {
+ if (*p == NUL)
+ {
+ tab_len = i;
+ break;
+ }
+ mb_char2bytes(lcs_tab2, p);
+ p += mb_char2len(lcs_tab2);
+ n_extra += mb_char2len(lcs_tab2)
+ - (saved_nextra > 0 ? 1 : 0);
+ }
+ p_extra = p_extra_free;
+#ifdef FEAT_CONCEAL
+ /* n_extra will be increased by FIX_FOX_BOGUSCOLS
+ * macro below, so need to adjust for that here */
+ if (vcol_off > 0)
+ n_extra -= vcol_off;
+#endif
+ }
+#endif
+#ifdef FEAT_CONCEAL
+ {
+ int vc_saved = vcol_off;
+
+ /* Tab alignment should be identical regardless of
+ * 'conceallevel' value. So tab compensates of all
+ * previous concealed characters, and thus resets
+ * vcol_off and boguscols accumulated so far in the
+ * line. Note that the tab can be longer than
+ * 'tabstop' when there are concealed characters. */
+ FIX_FOR_BOGUSCOLS;
+
+ /* Make sure, the highlighting for the tab char will be
+ * correctly set further below (effectively reverts the
+ * FIX_FOR_BOGSUCOLS macro */
+ if (n_extra == tab_len + vc_saved && wp->w_p_list
+ && lcs_tab1)
+ tab_len += vc_saved;
+ }
+#endif
+ mb_utf8 = FALSE; /* don't draw as UTF-8 */
+ if (wp->w_p_list)
+ {
+ c = (n_extra == 0 && lcs_tab3) ? lcs_tab3 : lcs_tab1;
+#ifdef FEAT_LINEBREAK
+ if (wp->w_p_lbr)
+ c_extra = NUL; /* using p_extra from above */
+ else
+#endif
+ c_extra = lcs_tab2;
+ c_final = lcs_tab3;
+ n_attr = tab_len + 1;
+ extra_attr = HL_ATTR(HLF_8);
+ saved_attr2 = char_attr; /* save current attr */
+ mb_c = c;
+ if (enc_utf8 && utf_char2len(c) > 1)
+ {
+ mb_utf8 = TRUE;
+ u8cc[0] = 0;
+ c = 0xc0;
+ }
+ }
+ else
+ {
+ c_final = NUL;
+ c_extra = ' ';
+ c = ' ';
+ }
+ }
+ else if (c == NUL
+ && (wp->w_p_list
+ || ((fromcol >= 0 || fromcol_prev >= 0)
+ && tocol > vcol
+ && VIsual_mode != Ctrl_V
+ && (
+# ifdef FEAT_RIGHTLEFT
+ wp->w_p_rl ? (col >= 0) :
+# endif
+ (col < wp->w_width))
+ && !(noinvcur
+ && lnum == wp->w_cursor.lnum
+ && (colnr_T)vcol == wp->w_virtcol)))
+ && lcs_eol_one > 0)
+ {
+ /* Display a '$' after the line or highlight an extra
+ * character if the line break is included. */
+#if defined(FEAT_DIFF) || defined(LINE_ATTR)
+ /* For a diff line the highlighting continues after the
+ * "$". */
+ if (
+# ifdef FEAT_DIFF
+ diff_hlf == (hlf_T)0
+# ifdef LINE_ATTR
+ &&
+# endif
+# endif
+# ifdef LINE_ATTR
+ line_attr == 0
+# endif
+ )
+#endif
+ {
+ /* In virtualedit, visual selections may extend
+ * beyond end of line. */
+ if (area_highlighting && virtual_active()
+ && tocol != MAXCOL && vcol < tocol)
+ n_extra = 0;
+ else
+ {
+ p_extra = at_end_str;
+ n_extra = 1;
+ c_extra = NUL;
+ c_final = NUL;
+ }
+ }
+ if (wp->w_p_list && lcs_eol > 0)
+ c = lcs_eol;
+ else
+ c = ' ';
+ lcs_eol_one = -1;
+ --ptr; /* put it back at the NUL */
+ if (!attr_pri)
+ {
+ extra_attr = HL_ATTR(HLF_AT);
+ n_attr = 1;
+ }
+ mb_c = c;
+ if (enc_utf8 && utf_char2len(c) > 1)
+ {
+ mb_utf8 = TRUE;
+ u8cc[0] = 0;
+ c = 0xc0;
+ }
+ else
+ mb_utf8 = FALSE; /* don't draw as UTF-8 */
+ }
+ else if (c != NUL)
+ {
+ p_extra = transchar(c);
+ if (n_extra == 0)
+ n_extra = byte2cells(c) - 1;
+#ifdef FEAT_RIGHTLEFT
+ if ((dy_flags & DY_UHEX) && wp->w_p_rl)
+ rl_mirror(p_extra); /* reverse "<12>" */
+#endif
+ c_extra = NUL;
+ c_final = NUL;
+#ifdef FEAT_LINEBREAK
+ if (wp->w_p_lbr)
+ {
+ char_u *p;
+
+ c = *p_extra;
+ p = alloc((unsigned)n_extra + 1);
+ vim_memset(p, ' ', n_extra);
+ STRNCPY(p, p_extra + 1, STRLEN(p_extra) - 1);
+ p[n_extra] = NUL;
+ vim_free(p_extra_free);
+ p_extra_free = p_extra = p;
+ }
+ else
+#endif
+ {
+ n_extra = byte2cells(c) - 1;
+ c = *p_extra++;
+ }
+ if (!attr_pri)
+ {
+ n_attr = n_extra + 1;
+ extra_attr = HL_ATTR(HLF_8);
+ saved_attr2 = char_attr; /* save current attr */
+ }
+ mb_utf8 = FALSE; /* don't draw as UTF-8 */
+ }
+ else if (VIsual_active
+ && (VIsual_mode == Ctrl_V
+ || VIsual_mode == 'v')
+ && virtual_active()
+ && tocol != MAXCOL
+ && vcol < tocol
+ && (
+#ifdef FEAT_RIGHTLEFT
+ wp->w_p_rl ? (col >= 0) :
+#endif
+ (col < wp->w_width)))
+ {
+ c = ' ';
+ --ptr; /* put it back at the NUL */
+ }
+#if defined(LINE_ATTR)
+ else if ((
+# ifdef FEAT_DIFF
+ diff_hlf != (hlf_T)0 ||
+# endif
+# ifdef FEAT_TERMINAL
+ term_attr != 0 ||
+# endif
+ line_attr != 0
+ ) && (
+# ifdef FEAT_RIGHTLEFT
+ wp->w_p_rl ? (col >= 0) :
+# endif
+ (col
+# ifdef FEAT_CONCEAL
+ - boguscols
+# endif
+ < wp->w_width)))
+ {
+ /* Highlight until the right side of the window */
+ c = ' ';
+ --ptr; /* put it back at the NUL */
+
+ /* Remember we do the char for line highlighting. */
+ ++did_line_attr;
+
+ /* don't do search HL for the rest of the line */
+ if (line_attr != 0 && char_attr == search_attr
+ && (did_line_attr > 1
+ || (wp->w_p_list && lcs_eol > 0)))
+ char_attr = line_attr;
+# ifdef FEAT_DIFF
+ if (diff_hlf == HLF_TXD)
+ {
+ diff_hlf = HLF_CHD;
+ if (attr == 0 || char_attr != attr)
+ {
+ char_attr = HL_ATTR(diff_hlf);
+ if (wp->w_p_cul && lnum == wp->w_cursor.lnum)
+ char_attr = hl_combine_attr(char_attr,
+ HL_ATTR(HLF_CUL));
+ }
+ }
+# endif
+# ifdef FEAT_TERMINAL
+ if (term_attr != 0)
+ {
+ char_attr = term_attr;
+ if (wp->w_p_cul && lnum == wp->w_cursor.lnum)
+ char_attr = hl_combine_attr(char_attr,
+ HL_ATTR(HLF_CUL));
+ }
+# endif
+ }
+#endif
+ }
+
+#ifdef FEAT_CONCEAL
+ if ( wp->w_p_cole > 0
+ && (wp != curwin || lnum != wp->w_cursor.lnum ||
+ conceal_cursor_line(wp) )
+ && ( (syntax_flags & HL_CONCEAL) != 0 || has_match_conc > 0)
+ && !(lnum_in_visual_area
+ && vim_strchr(wp->w_p_cocu, 'v') == NULL))
+ {
+ char_attr = conceal_attr;
+ if ((prev_syntax_id != syntax_seqnr || has_match_conc > 1)
+ && (syn_get_sub_char() != NUL || match_conc
+ || wp->w_p_cole == 1)
+ && wp->w_p_cole != 3)
+ {
+ /* First time at this concealed item: display one
+ * character. */
+ if (match_conc)
+ c = match_conc;
+ else if (syn_get_sub_char() != NUL)
+ c = syn_get_sub_char();
+ else if (lcs_conceal != NUL)
+ c = lcs_conceal;
+ else
+ c = ' ';
+
+ prev_syntax_id = syntax_seqnr;
+
+ if (n_extra > 0)
+ vcol_off += n_extra;
+ vcol += n_extra;
+ if (wp->w_p_wrap && n_extra > 0)
+ {
+# ifdef FEAT_RIGHTLEFT
+ if (wp->w_p_rl)
+ {
+ col -= n_extra;
+ boguscols -= n_extra;
+ }
+ else
+# endif
+ {
+ boguscols += n_extra;
+ col += n_extra;
+ }
+ }
+ n_extra = 0;
+ n_attr = 0;
+ }
+ else if (n_skip == 0)
+ {
+ is_concealing = TRUE;
+ n_skip = 1;
+ }
+ mb_c = c;
+ if (enc_utf8 && utf_char2len(c) > 1)
+ {
+ mb_utf8 = TRUE;
+ u8cc[0] = 0;
+ c = 0xc0;
+ }
+ else
+ mb_utf8 = FALSE; /* don't draw as UTF-8 */
+ }
+ else
+ {
+ prev_syntax_id = 0;
+ is_concealing = FALSE;
+ }
+#endif /* FEAT_CONCEAL */
+ }
+
+#ifdef FEAT_CONCEAL
+ /* In the cursor line and we may be concealing characters: correct
+ * the cursor column when we reach its position. */
+ if (!did_wcol && draw_state == WL_LINE
+ && wp == curwin && lnum == wp->w_cursor.lnum
+ && conceal_cursor_line(wp)
+ && (int)wp->w_virtcol <= vcol + n_skip)
+ {
+# ifdef FEAT_RIGHTLEFT
+ if (wp->w_p_rl)
+ wp->w_wcol = wp->w_width - col + boguscols - 1;
+ else
+# endif
+ wp->w_wcol = col - boguscols;
+ wp->w_wrow = row;
+ did_wcol = TRUE;
+ }
+#endif
+
+ /* Don't override visual selection highlighting. */
+ if (n_attr > 0
+ && draw_state == WL_LINE
+ && !attr_pri)
+ char_attr = extra_attr;
+
+#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
+ /* XIM don't send preedit_start and preedit_end, but they send
+ * preedit_changed and commit. Thus Vim can't set "im_is_active", use
+ * im_is_preediting() here. */
+ if (p_imst == IM_ON_THE_SPOT
+ && xic != NULL
+ && lnum == wp->w_cursor.lnum
+ && (State & INSERT)
+ && !p_imdisable
+ && im_is_preediting()
+ && draw_state == WL_LINE)
+ {
+ colnr_T tcol;
+
+ if (preedit_end_col == MAXCOL)
+ getvcol(curwin, &(wp->w_cursor), &tcol, NULL, NULL);
+ else
+ tcol = preedit_end_col;
+ if ((long)preedit_start_col <= vcol && vcol < (long)tcol)
+ {
+ if (feedback_old_attr < 0)
+ {
+ feedback_col = 0;
+ feedback_old_attr = char_attr;
+ }
+ char_attr = im_get_feedback_attr(feedback_col);
+ if (char_attr < 0)
+ char_attr = feedback_old_attr;
+ feedback_col++;
+ }
+ else if (feedback_old_attr >= 0)
+ {
+ char_attr = feedback_old_attr;
+ feedback_old_attr = -1;
+ feedback_col = 0;
+ }
+ }
+#endif
+ /*
+ * Handle the case where we are in column 0 but not on the first
+ * character of the line and the user wants us to show us a
+ * special character (via 'listchars' option "precedes:<char>".
+ */
+ if (lcs_prec_todo != NUL
+ && wp->w_p_list
+ && (wp->w_p_wrap ? wp->w_skipcol > 0 : wp->w_leftcol > 0)
+#ifdef FEAT_DIFF
+ && filler_todo <= 0
+#endif
+ && draw_state > WL_NR
+ && c != NUL)
+ {
+ c = lcs_prec;
+ lcs_prec_todo = NUL;
+ if (has_mbyte && (*mb_char2cells)(mb_c) > 1)
+ {
+ /* Double-width character being overwritten by the "precedes"
+ * character, need to fill up half the character. */
+ c_extra = MB_FILLER_CHAR;
+ c_final = NUL;
+ n_extra = 1;
+ n_attr = 2;
+ extra_attr = HL_ATTR(HLF_AT);
+ }
+ mb_c = c;
+ if (enc_utf8 && utf_char2len(c) > 1)
+ {
+ mb_utf8 = TRUE;
+ u8cc[0] = 0;
+ c = 0xc0;
+ }
+ else
+ mb_utf8 = FALSE; /* don't draw as UTF-8 */
+ if (!attr_pri)
+ {
+ saved_attr3 = char_attr; /* save current attr */
+ char_attr = HL_ATTR(HLF_AT); /* later copied to char_attr */
+ n_attr3 = 1;
+ }
+ }
+
+ /*
+ * At end of the text line or just after the last character.
+ */
+ if (c == NUL
+#if defined(LINE_ATTR)
+ || did_line_attr == 1
+#endif
+ )
+ {
+#ifdef FEAT_SEARCH_EXTRA
+ long prevcol = (long)(ptr - line) - (c == NUL);
+
+ /* we're not really at that column when skipping some text */
+ if ((long)(wp->w_p_wrap ? wp->w_skipcol : wp->w_leftcol) > prevcol)
+ ++prevcol;
+#endif
+
+ /* Invert at least one char, used for Visual and empty line or
+ * highlight match at end of line. If it's beyond the last
+ * char on the screen, just overwrite that one (tricky!) Not
+ * needed when a '$' was displayed for 'list'. */
+#ifdef FEAT_SEARCH_EXTRA
+ prevcol_hl_flag = FALSE;
+ if (!search_hl.is_addpos && prevcol == (long)search_hl.startcol)
+ prevcol_hl_flag = TRUE;
+ else
+ {
+ cur = wp->w_match_head;
+ while (cur != NULL)
+ {
+ if (!cur->hl.is_addpos && prevcol == (long)cur->hl.startcol)
+ {
+ prevcol_hl_flag = TRUE;
+ break;
+ }
+ cur = cur->next;
+ }
+ }
+#endif
+ if (lcs_eol == lcs_eol_one
+ && ((area_attr != 0 && vcol == fromcol
+ && (VIsual_mode != Ctrl_V
+ || lnum == VIsual.lnum
+ || lnum == curwin->w_cursor.lnum)
+ && c == NUL)
+#ifdef FEAT_SEARCH_EXTRA
+ /* highlight 'hlsearch' match at end of line */
+ || (prevcol_hl_flag == TRUE
+# ifdef FEAT_SYN_HL
+ && !(wp->w_p_cul && lnum == wp->w_cursor.lnum
+ && !(wp == curwin && VIsual_active))
+# endif
+# ifdef FEAT_DIFF
+ && diff_hlf == (hlf_T)0
+# endif
+# if defined(LINE_ATTR)
+ && did_line_attr <= 1
+# endif
+ )
+#endif
+ ))
+ {
+ int n = 0;
+
+#ifdef FEAT_RIGHTLEFT
+ if (wp->w_p_rl)
+ {
+ if (col < 0)
+ n = 1;
+ }
+ else
+#endif
+ {
+ if (col >= wp->w_width)
+ n = -1;
+ }
+ if (n != 0)
+ {
+ /* At the window boundary, highlight the last character
+ * instead (better than nothing). */
+ off += n;
+ col += n;
+ }
+ else
+ {
+ /* Add a blank character to highlight. */
+ ScreenLines[off] = ' ';
+ if (enc_utf8)
+ ScreenLinesUC[off] = 0;
+ }
+#ifdef FEAT_SEARCH_EXTRA
+ if (area_attr == 0)
+ {
+ /* Use attributes from match with highest priority among
+ * 'search_hl' and the match list. */
+ char_attr = search_hl.attr;
+ cur = wp->w_match_head;
+ shl_flag = FALSE;
+ while (cur != NULL || shl_flag == FALSE)
+ {
+ if (shl_flag == FALSE
+ && ((cur != NULL
+ && cur->priority > SEARCH_HL_PRIORITY)
+ || cur == NULL))
+ {
+ shl = &search_hl;
+ shl_flag = TRUE;
+ }
+ else
+ shl = &cur->hl;
+ if ((ptr - line) - 1 == (long)shl->startcol
+ && (shl == &search_hl || !shl->is_addpos))
+ char_attr = shl->attr;
+ if (shl != &search_hl && cur != NULL)
+ cur = cur->next;
+ }
+ }
+#endif
+ ScreenAttrs[off] = char_attr;
+#ifdef FEAT_RIGHTLEFT
+ if (wp->w_p_rl)
+ {
+ --col;
+ --off;
+ }
+ else
+#endif
+ {
+ ++col;
+ ++off;
+ }
+ ++vcol;
+#ifdef FEAT_SYN_HL
+ eol_hl_off = 1;
+#endif
+ }
+ }
+
+ /*
+ * At end of the text line.
+ */
+ if (c == NUL)
+ {
+#ifdef FEAT_SYN_HL
+ /* Highlight 'cursorcolumn' & 'colorcolumn' past end of the line. */
+ if (wp->w_p_wrap)
+ v = wp->w_skipcol;
+ else
+ v = wp->w_leftcol;
+
+ /* check if line ends before left margin */
+ if (vcol < v + col - win_col_off(wp))
+ vcol = v + col - win_col_off(wp);
+#ifdef FEAT_CONCEAL
+ /* Get rid of the boguscols now, we want to draw until the right
+ * edge for 'cursorcolumn'. */
+ col -= boguscols;
+ boguscols = 0;
+#endif
+
+ if (draw_color_col)
+ draw_color_col = advance_color_col(VCOL_HLC, &color_cols);
+
+ if (((wp->w_p_cuc
+ && (int)wp->w_virtcol >= VCOL_HLC - eol_hl_off
+ && (int)wp->w_virtcol <
+ wp->w_width * (row - startrow + 1) + v
+ && lnum != wp->w_cursor.lnum)
+ || draw_color_col)
+# ifdef FEAT_RIGHTLEFT
+ && !wp->w_p_rl
+# endif
+ )
+ {
+ int rightmost_vcol = 0;
+ int i;
+
+ if (wp->w_p_cuc)
+ rightmost_vcol = wp->w_virtcol;
+ if (draw_color_col)
+ /* determine rightmost colorcolumn to possibly draw */
+ for (i = 0; color_cols[i] >= 0; ++i)
+ if (rightmost_vcol < color_cols[i])
+ rightmost_vcol = color_cols[i];
+
+ while (col < wp->w_width)
+ {
+ ScreenLines[off] = ' ';
+ if (enc_utf8)
+ ScreenLinesUC[off] = 0;
+ ++col;
+ if (draw_color_col)
+ draw_color_col = advance_color_col(VCOL_HLC,
+ &color_cols);
+
+ if (wp->w_p_cuc && VCOL_HLC == (long)wp->w_virtcol)
+ ScreenAttrs[off++] = HL_ATTR(HLF_CUC);
+ else if (draw_color_col && VCOL_HLC == *color_cols)
+ ScreenAttrs[off++] = HL_ATTR(HLF_MC);
+ else
+ ScreenAttrs[off++] = 0;
+
+ if (VCOL_HLC >= rightmost_vcol)
+ break;
+
+ ++vcol;
+ }
+ }
+#endif
+
+ screen_line(screen_row, wp->w_wincol, col,
+ (int)wp->w_width, HAS_RIGHTLEFT(wp->w_p_rl));
+ row++;
+
+ /*
+ * Update w_cline_height and w_cline_folded if the cursor line was
+ * updated (saves a call to plines() later).
+ */
+ if (wp == curwin && lnum == curwin->w_cursor.lnum)
+ {
+ curwin->w_cline_row = startrow;
+ curwin->w_cline_height = row - startrow;
+#ifdef FEAT_FOLDING
+ curwin->w_cline_folded = FALSE;
+#endif
+ curwin->w_valid |= (VALID_CHEIGHT|VALID_CROW);
+ }
+
+ break;
+ }
+
+ /* line continues beyond line end */
+ if (lcs_ext
+ && !wp->w_p_wrap
+#ifdef FEAT_DIFF
+ && filler_todo <= 0
+#endif
+ && (
+#ifdef FEAT_RIGHTLEFT
+ wp->w_p_rl ? col == 0 :
+#endif
+ col == wp->w_width - 1)
+ && (*ptr != NUL
+ || (wp->w_p_list && lcs_eol_one > 0)
+ || (n_extra && (c_extra != NUL || *p_extra != NUL))))
+ {
+ c = lcs_ext;
+ char_attr = HL_ATTR(HLF_AT);
+ mb_c = c;
+ if (enc_utf8 && utf_char2len(c) > 1)
+ {
+ mb_utf8 = TRUE;
+ u8cc[0] = 0;
+ c = 0xc0;
+ }
+ else
+ mb_utf8 = FALSE;
+ }
+
+#ifdef FEAT_SYN_HL
+ /* advance to the next 'colorcolumn' */
+ if (draw_color_col)
+ draw_color_col = advance_color_col(VCOL_HLC, &color_cols);
+
+ /* Highlight the cursor column if 'cursorcolumn' is set. But don't
+ * highlight the cursor position itself.
+ * Also highlight the 'colorcolumn' if it is different than
+ * 'cursorcolumn' */
+ vcol_save_attr = -1;
+ if (draw_state == WL_LINE && !lnum_in_visual_area
+ && search_attr == 0 && area_attr == 0)
+ {
+ if (wp->w_p_cuc && VCOL_HLC == (long)wp->w_virtcol
+ && lnum != wp->w_cursor.lnum)
+ {
+ vcol_save_attr = char_attr;
+ char_attr = hl_combine_attr(char_attr, HL_ATTR(HLF_CUC));
+ }
+ else if (draw_color_col && VCOL_HLC == *color_cols)
+ {
+ vcol_save_attr = char_attr;
+ char_attr = hl_combine_attr(char_attr, HL_ATTR(HLF_MC));
+ }
+ }
+#endif
+
+ /*
+ * Store character to be displayed.
+ * Skip characters that are left of the screen for 'nowrap'.
+ */
+ vcol_prev = vcol;
+ if (draw_state < WL_LINE || n_skip <= 0)
+ {
+ /*
+ * Store the character.
+ */
+#if defined(FEAT_RIGHTLEFT)
+ if (has_mbyte && wp->w_p_rl && (*mb_char2cells)(mb_c) > 1)
+ {
+ /* A double-wide character is: put first halve in left cell. */
+ --off;
+ --col;
+ }
+#endif
+ ScreenLines[off] = c;
+ if (enc_dbcs == DBCS_JPNU)
+ {
+ if ((mb_c & 0xff00) == 0x8e00)
+ ScreenLines[off] = 0x8e;
+ ScreenLines2[off] = mb_c & 0xff;
+ }
+ else if (enc_utf8)
+ {
+ if (mb_utf8)
+ {
+ int i;
+
+ ScreenLinesUC[off] = mb_c;
+ if ((c & 0xff) == 0)
+ ScreenLines[off] = 0x80; /* avoid storing zero */
+ for (i = 0; i < Screen_mco; ++i)
+ {
+ ScreenLinesC[i][off] = u8cc[i];
+ if (u8cc[i] == 0)
+ break;
+ }
+ }
+ else
+ ScreenLinesUC[off] = 0;
+ }
+ if (multi_attr)
+ {
+ ScreenAttrs[off] = multi_attr;
+ multi_attr = 0;
+ }
+ else
+ ScreenAttrs[off] = char_attr;
+
+ if (has_mbyte && (*mb_char2cells)(mb_c) > 1)
+ {
+ /* Need to fill two screen columns. */
+ ++off;
+ ++col;
+ if (enc_utf8)
+ /* UTF-8: Put a 0 in the second screen char. */
+ ScreenLines[off] = 0;
+ else
+ /* DBCS: Put second byte in the second screen char. */
+ ScreenLines[off] = mb_c & 0xff;
+ if (draw_state > WL_NR
+#ifdef FEAT_DIFF
+ && filler_todo <= 0
+#endif
+ )
+ ++vcol;
+ /* When "tocol" is halfway a character, set it to the end of
+ * the character, otherwise highlighting won't stop. */
+ if (tocol == vcol)
+ ++tocol;
+#ifdef FEAT_RIGHTLEFT
+ if (wp->w_p_rl)
+ {
+ /* now it's time to backup one cell */
+ --off;
+ --col;
+ }
+#endif
+ }
+#ifdef FEAT_RIGHTLEFT
+ if (wp->w_p_rl)
+ {
+ --off;
+ --col;
+ }
+ else
+#endif
+ {
+ ++off;
+ ++col;
+ }
+ }
+#ifdef FEAT_CONCEAL
+ else if (wp->w_p_cole > 0 && is_concealing)
+ {
+ --n_skip;
+ ++vcol_off;
+ if (n_extra > 0)
+ vcol_off += n_extra;
+ if (wp->w_p_wrap)
+ {
+ /*
+ * Special voodoo required if 'wrap' is on.
+ *
+ * Advance the column indicator to force the line
+ * drawing to wrap early. This will make the line
+ * take up the same screen space when parts are concealed,
+ * so that cursor line computations aren't messed up.
+ *
+ * To avoid the fictitious advance of 'col' causing
+ * trailing junk to be written out of the screen line
+ * we are building, 'boguscols' keeps track of the number
+ * of bad columns we have advanced.
+ */
+ if (n_extra > 0)
+ {
+ vcol += n_extra;
+# ifdef FEAT_RIGHTLEFT
+ if (wp->w_p_rl)
+ {
+ col -= n_extra;
+ boguscols -= n_extra;
+ }
+ else
+# endif
+ {
+ col += n_extra;
+ boguscols += n_extra;
+ }
+ n_extra = 0;
+ n_attr = 0;
+ }
+
+
+ if (has_mbyte && (*mb_char2cells)(mb_c) > 1)
+ {
+ /* Need to fill two screen columns. */
+# ifdef FEAT_RIGHTLEFT
+ if (wp->w_p_rl)
+ {
+ --boguscols;
+ --col;
+ }
+ else
+# endif
+ {
+ ++boguscols;
+ ++col;
+ }
+ }
+
+# ifdef FEAT_RIGHTLEFT
+ if (wp->w_p_rl)
+ {
+ --boguscols;
+ --col;
+ }
+ else
+# endif
+ {
+ ++boguscols;
+ ++col;
+ }
+ }
+ else
+ {
+ if (n_extra > 0)
+ {
+ vcol += n_extra;
+ n_extra = 0;
+ n_attr = 0;
+ }
+ }
+
+ }
+#endif /* FEAT_CONCEAL */
+ else
+ --n_skip;
+
+ /* Only advance the "vcol" when after the 'number' or 'relativenumber'
+ * column. */
+ if (draw_state > WL_NR
+#ifdef FEAT_DIFF
+ && filler_todo <= 0
+#endif
+ )
+ ++vcol;
+
+#ifdef FEAT_SYN_HL
+ if (vcol_save_attr >= 0)
+ char_attr = vcol_save_attr;
+#endif
+
+ /* restore attributes after "predeces" in 'listchars' */
+ if (draw_state > WL_NR && n_attr3 > 0 && --n_attr3 == 0)
+ char_attr = saved_attr3;
+
+ /* restore attributes after last 'listchars' or 'number' char */
+ if (n_attr > 0 && draw_state == WL_LINE && --n_attr == 0)
+ char_attr = saved_attr2;
+
+ /*
+ * At end of screen line and there is more to come: Display the line
+ * so far. If there is no more to display it is caught above.
+ */
+ if ((
+#ifdef FEAT_RIGHTLEFT
+ wp->w_p_rl ? (col < 0) :
+#endif
+ (col >= wp->w_width))
+ && (*ptr != NUL
+#ifdef FEAT_DIFF
+ || filler_todo > 0
+#endif
+ || (wp->w_p_list && lcs_eol != NUL && p_extra != at_end_str)
+ || (n_extra != 0 && (c_extra != NUL || *p_extra != NUL)))
+ )
+ {
+#ifdef FEAT_CONCEAL
+ screen_line(screen_row, wp->w_wincol, col - boguscols,
+ (int)wp->w_width, HAS_RIGHTLEFT(wp->w_p_rl));
+ boguscols = 0;
+#else
+ screen_line(screen_row, wp->w_wincol, col,
+ (int)wp->w_width, HAS_RIGHTLEFT(wp->w_p_rl));
+#endif
+ ++row;
+ ++screen_row;
+
+ /* When not wrapping and finished diff lines, or when displayed
+ * '$' and highlighting until last column, break here. */
+ if ((!wp->w_p_wrap
+#ifdef FEAT_DIFF
+ && filler_todo <= 0
+#endif
+ ) || lcs_eol_one == -1)
+ break;
+
+ /* When the window is too narrow draw all "@" lines. */
+ if (draw_state != WL_LINE
+#ifdef FEAT_DIFF
+ && filler_todo <= 0
+#endif
+ )
+ {
+ win_draw_end(wp, '@', ' ', row, wp->w_height, HLF_AT);
+ draw_vsep_win(wp, row);
+ row = endrow;
+ }
+
+ /* When line got too long for screen break here. */
+ if (row == endrow)
+ {
+ ++row;
+ break;
+ }
+
+ if (screen_cur_row == screen_row - 1
+#ifdef FEAT_DIFF
+ && filler_todo <= 0
+#endif
+ && wp->w_width == Columns)
+ {
+ /* Remember that the line wraps, used for modeless copy. */
+ LineWraps[screen_row - 1] = TRUE;
+
+ /*
+ * Special trick to make copy/paste of wrapped lines work with
+ * xterm/screen: write an extra character beyond the end of
+ * the line. This will work with all terminal types
+ * (regardless of the xn,am settings).
+ * Only do this on a fast tty.
+ * Only do this if the cursor is on the current line
+ * (something has been written in it).
+ * Don't do this for the GUI.
+ * Don't do this for double-width characters.
+ * Don't do this for a window not at the right screen border.
+ */
+ if (p_tf
+#ifdef FEAT_GUI
+ && !gui.in_use
+#endif
+ && !(has_mbyte
+ && ((*mb_off2cells)(LineOffset[screen_row],
+ LineOffset[screen_row] + screen_Columns)
+ == 2
+ || (*mb_off2cells)(LineOffset[screen_row - 1]
+ + (int)Columns - 2,
+ LineOffset[screen_row] + screen_Columns)
+ == 2)))
+ {
+ /* First make sure we are at the end of the screen line,
+ * then output the same character again to let the
+ * terminal know about the wrap. If the terminal doesn't
+ * auto-wrap, we overwrite the character. */
+ if (screen_cur_col != wp->w_width)
+ screen_char(LineOffset[screen_row - 1]
+ + (unsigned)Columns - 1,
+ screen_row - 1, (int)(Columns - 1));
+
+ /* When there is a multi-byte character, just output a
+ * space to keep it simple. */
+ if (has_mbyte && MB_BYTE2LEN(ScreenLines[LineOffset[
+ screen_row - 1] + (Columns - 1)]) > 1)
+ out_char(' ');
+ else
+ out_char(ScreenLines[LineOffset[screen_row - 1]
+ + (Columns - 1)]);
+ /* force a redraw of the first char on the next line */
+ ScreenAttrs[LineOffset[screen_row]] = (sattr_T)-1;
+ screen_start(); /* don't know where cursor is now */
+ }
+ }
+
+ col = 0;
+ off = (unsigned)(current_ScreenLine - ScreenLines);
+#ifdef FEAT_RIGHTLEFT
+ if (wp->w_p_rl)
+ {
+ col = wp->w_width - 1; /* col is not used if breaking! */
+ off += col;
+ }
+#endif
+
+ /* reset the drawing state for the start of a wrapped line */
+ draw_state = WL_START;
+ saved_n_extra = n_extra;
+ saved_p_extra = p_extra;
+ saved_c_extra = c_extra;
+ saved_c_final = c_final;
+ saved_char_attr = char_attr;
+ n_extra = 0;
+ lcs_prec_todo = lcs_prec;
+#ifdef FEAT_LINEBREAK
+# ifdef FEAT_DIFF
+ if (filler_todo <= 0)
+# endif
+ need_showbreak = TRUE;
+#endif
+#ifdef FEAT_DIFF
+ --filler_todo;
+ /* When the filler lines are actually below the last line of the
+ * file, don't draw the line itself, break here. */
+ if (filler_todo == 0 && wp->w_botfill)
+ break;
+#endif
+ }
+
+ } /* for every character in the line */
+
+#ifdef FEAT_SPELL
+ /* After an empty line check first word for capital. */
+ if (*skipwhite(line) == NUL)
+ {
+ capcol_lnum = lnum + 1;
+ cap_col = 0;
+ }
+#endif
+#ifdef FEAT_TEXT_PROP
+ vim_free(text_props);
+ vim_free(text_prop_idxs);
+#endif
+
+ vim_free(p_extra_free);
+ return row;
+}
+
+/*
+ * Return if the composing characters at "off_from" and "off_to" differ.
+ * Only to be used when ScreenLinesUC[off_from] != 0.
+ */
+ static int
+comp_char_differs(int off_from, int off_to)
+{
+ int i;
+
+ for (i = 0; i < Screen_mco; ++i)
+ {
+ if (ScreenLinesC[i][off_from] != ScreenLinesC[i][off_to])
+ return TRUE;
+ if (ScreenLinesC[i][off_from] == 0)
+ break;
+ }
+ return FALSE;
+}
+
+/*
+ * Check whether the given character needs redrawing:
+ * - the (first byte of the) character is different
+ * - the attributes are different
+ * - the character is multi-byte and the next byte is different
+ * - the character is two cells wide and the second cell differs.
+ */
+ static int
+char_needs_redraw(int off_from, int off_to, int cols)
+{
+ if (cols > 0
+ && ((ScreenLines[off_from] != ScreenLines[off_to]
+ || ScreenAttrs[off_from] != ScreenAttrs[off_to])
+ || (enc_dbcs != 0
+ && MB_BYTE2LEN(ScreenLines[off_from]) > 1
+ && (enc_dbcs == DBCS_JPNU && ScreenLines[off_from] == 0x8e
+ ? ScreenLines2[off_from] != ScreenLines2[off_to]
+ : (cols > 1 && ScreenLines[off_from + 1]
+ != ScreenLines[off_to + 1])))
+ || (enc_utf8
+ && (ScreenLinesUC[off_from] != ScreenLinesUC[off_to]
+ || (ScreenLinesUC[off_from] != 0
+ && comp_char_differs(off_from, off_to))
+ || ((*mb_off2cells)(off_from, off_from + cols) > 1
+ && ScreenLines[off_from + 1]
+ != ScreenLines[off_to + 1])))))
+ return TRUE;
+ return FALSE;
+}
+
+#if defined(FEAT_TERMINAL) || defined(PROTO)
+/*
+ * Return the index in ScreenLines[] for the current screen line.
+ */
+ int
+screen_get_current_line_off()
+{
+ return (int)(current_ScreenLine - ScreenLines);
+}
+#endif
+
+/*
+ * Move one "cooked" screen line to the screen, but only the characters that
+ * have actually changed. Handle insert/delete character.
+ * "coloff" gives the first column on the screen for this line.
+ * "endcol" gives the columns where valid characters are.
+ * "clear_width" is the width of the window. It's > 0 if the rest of the line
+ * needs to be cleared, negative otherwise.
+ * "rlflag" is TRUE in a rightleft window:
+ * When TRUE and "clear_width" > 0, clear columns 0 to "endcol"
+ * When FALSE and "clear_width" > 0, clear columns "endcol" to "clear_width"
+ */
+ void
+screen_line(
+ int row,
+ int coloff,
+ int endcol,
+ int clear_width,
+ int rlflag UNUSED)
+{
+ unsigned off_from;
+ unsigned off_to;
+ unsigned max_off_from;
+ unsigned max_off_to;
+ int col = 0;
+ int hl;
+ int force = FALSE; /* force update rest of the line */
+ int redraw_this /* bool: does character need redraw? */
+#ifdef FEAT_GUI
+ = TRUE /* For GUI when while-loop empty */
+#endif
+ ;
+ int redraw_next; /* redraw_this for next character */
+ int clear_next = FALSE;
+ int char_cells; /* 1: normal char */
+ /* 2: occupies two display cells */
+# define CHAR_CELLS char_cells
+
+ /* Check for illegal row and col, just in case. */
+ if (row >= Rows)
+ row = Rows - 1;
+ if (endcol > Columns)
+ endcol = Columns;
+
+# ifdef FEAT_CLIPBOARD
+ clip_may_clear_selection(row, row);
+# endif
+
+ off_from = (unsigned)(current_ScreenLine - ScreenLines);
+ off_to = LineOffset[row] + coloff;
+ max_off_from = off_from + screen_Columns;
+ max_off_to = LineOffset[row] + screen_Columns;
+
+#ifdef FEAT_RIGHTLEFT
+ if (rlflag)
+ {
+ /* Clear rest first, because it's left of the text. */
+ if (clear_width > 0)
+ {
+ while (col <= endcol && ScreenLines[off_to] == ' '
+ && ScreenAttrs[off_to] == 0
+ && (!enc_utf8 || ScreenLinesUC[off_to] == 0))
+ {
+ ++off_to;
+ ++col;
+ }
+ if (col <= endcol)
+ screen_fill(row, row + 1, col + coloff,
+ endcol + coloff + 1, ' ', ' ', 0);
+ }
+ col = endcol + 1;
+ off_to = LineOffset[row] + col + coloff;
+ off_from += col;
+ endcol = (clear_width > 0 ? clear_width : -clear_width);
+ }
+#endif /* FEAT_RIGHTLEFT */
+
+ redraw_next = char_needs_redraw(off_from, off_to, endcol - col);
+
+ while (col < endcol)
+ {
+ if (has_mbyte && (col + 1 < endcol))
+ char_cells = (*mb_off2cells)(off_from, max_off_from);
+ else
+ char_cells = 1;
+
+ redraw_this = redraw_next;
+ redraw_next = force || char_needs_redraw(off_from + CHAR_CELLS,
+ off_to + CHAR_CELLS, endcol - col - CHAR_CELLS);
+
+#ifdef FEAT_GUI
+ /* If the next character was bold, then redraw the current character to
+ * remove any pixels that might have spilt over into us. This only
+ * happens in the GUI.
+ */
+ if (redraw_next && gui.in_use)
+ {
+ hl = ScreenAttrs[off_to + CHAR_CELLS];
+ if (hl > HL_ALL)
+ hl = syn_attr2attr(hl);
+ if (hl & HL_BOLD)
+ redraw_this = TRUE;
+ }
+#endif
+
+ if (redraw_this)
+ {
+ /*
+ * Special handling when 'xs' termcap flag set (hpterm):
+ * Attributes for characters are stored at the position where the
+ * cursor is when writing the highlighting code. The
+ * start-highlighting code must be written with the cursor on the
+ * first highlighted character. The stop-highlighting code must
+ * be written with the cursor just after the last highlighted
+ * character.
+ * Overwriting a character doesn't remove its highlighting. Need
+ * to clear the rest of the line, and force redrawing it
+ * completely.
+ */
+ if ( p_wiv
+ && !force
+#ifdef FEAT_GUI
+ && !gui.in_use
+#endif
+ && ScreenAttrs[off_to] != 0
+ && ScreenAttrs[off_from] != ScreenAttrs[off_to])
+ {
+ /*
+ * Need to remove highlighting attributes here.
+ */
+ windgoto(row, col + coloff);
+ out_str(T_CE); /* clear rest of this screen line */
+ screen_start(); /* don't know where cursor is now */
+ force = TRUE; /* force redraw of rest of the line */
+ redraw_next = TRUE; /* or else next char would miss out */
+
+ /*
+ * If the previous character was highlighted, need to stop
+ * highlighting at this character.
+ */
+ if (col + coloff > 0 && ScreenAttrs[off_to - 1] != 0)
+ {
+ screen_attr = ScreenAttrs[off_to - 1];
+ term_windgoto(row, col + coloff);
+ screen_stop_highlight();
+ }
+ else
+ screen_attr = 0; /* highlighting has stopped */
+ }
+ if (enc_dbcs != 0)
+ {
+ /* Check if overwriting a double-byte with a single-byte or
+ * the other way around requires another character to be
+ * redrawn. For UTF-8 this isn't needed, because comparing
+ * ScreenLinesUC[] is sufficient. */
+ if (char_cells == 1
+ && col + 1 < endcol
+ && (*mb_off2cells)(off_to, max_off_to) > 1)
+ {
+ /* Writing a single-cell character over a double-cell
+ * character: need to redraw the next cell. */
+ ScreenLines[off_to + 1] = 0;
+ redraw_next = TRUE;
+ }
+ else if (char_cells == 2
+ && col + 2 < endcol
+ && (*mb_off2cells)(off_to, max_off_to) == 1
+ && (*mb_off2cells)(off_to + 1, max_off_to) > 1)
+ {
+ /* Writing the second half of a double-cell character over
+ * a double-cell character: need to redraw the second
+ * cell. */
+ ScreenLines[off_to + 2] = 0;
+ redraw_next = TRUE;
+ }
+
+ if (enc_dbcs == DBCS_JPNU)
+ ScreenLines2[off_to] = ScreenLines2[off_from];
+ }
+ /* When writing a single-width character over a double-width
+ * character and at the end of the redrawn text, need to clear out
+ * the right halve of the old character.
+ * Also required when writing the right halve of a double-width
+ * char over the left halve of an existing one. */
+ if (has_mbyte && col + char_cells == endcol
+ && ((char_cells == 1
+ && (*mb_off2cells)(off_to, max_off_to) > 1)
+ || (char_cells == 2
+ && (*mb_off2cells)(off_to, max_off_to) == 1
+ && (*mb_off2cells)(off_to + 1, max_off_to) > 1)))
+ clear_next = TRUE;
+
+ ScreenLines[off_to] = ScreenLines[off_from];
+ if (enc_utf8)
+ {
+ ScreenLinesUC[off_to] = ScreenLinesUC[off_from];
+ if (ScreenLinesUC[off_from] != 0)
+ {
+ int i;
+
+ for (i = 0; i < Screen_mco; ++i)
+ ScreenLinesC[i][off_to] = ScreenLinesC[i][off_from];
+ }
+ }
+ if (char_cells == 2)
+ ScreenLines[off_to + 1] = ScreenLines[off_from + 1];
+
+#if defined(FEAT_GUI) || defined(UNIX)
+ /* The bold trick makes a single column of pixels appear in the
+ * next character. When a bold character is removed, the next
+ * character should be redrawn too. This happens for our own GUI
+ * and for some xterms. */
+ if (
+# ifdef FEAT_GUI
+ gui.in_use
+# endif
+# if defined(FEAT_GUI) && defined(UNIX)
+ ||
+# endif
+# ifdef UNIX
+ term_is_xterm
+# endif
+ )
+ {
+ hl = ScreenAttrs[off_to];
+ if (hl > HL_ALL)
+ hl = syn_attr2attr(hl);
+ if (hl & HL_BOLD)
+ redraw_next = TRUE;
+ }
+#endif
+ ScreenAttrs[off_to] = ScreenAttrs[off_from];
+
+ /* For simplicity set the attributes of second half of a
+ * double-wide character equal to the first half. */
+ if (char_cells == 2)
+ ScreenAttrs[off_to + 1] = ScreenAttrs[off_from];
+
+ if (enc_dbcs != 0 && char_cells == 2)
+ screen_char_2(off_to, row, col + coloff);
+ else
+ screen_char(off_to, row, col + coloff);
+ }
+ else if ( p_wiv
+#ifdef FEAT_GUI
+ && !gui.in_use
+#endif
+ && col + coloff > 0)
+ {
+ if (ScreenAttrs[off_to] == ScreenAttrs[off_to - 1])
+ {
+ /*
+ * Don't output stop-highlight when moving the cursor, it will
+ * stop the highlighting when it should continue.
+ */
+ screen_attr = 0;
+ }
+ else if (screen_attr != 0)
+ screen_stop_highlight();
+ }
+
+ off_to += CHAR_CELLS;
+ off_from += CHAR_CELLS;
+ col += CHAR_CELLS;
+ }
+
+ if (clear_next)
+ {
+ /* Clear the second half of a double-wide character of which the left
+ * half was overwritten with a single-wide character. */
+ ScreenLines[off_to] = ' ';
+ if (enc_utf8)
+ ScreenLinesUC[off_to] = 0;
+ screen_char(off_to, row, col + coloff);
+ }
+
+ if (clear_width > 0
+#ifdef FEAT_RIGHTLEFT
+ && !rlflag
+#endif
+ )
+ {
+#ifdef FEAT_GUI
+ int startCol = col;
+#endif
+
+ /* blank out the rest of the line */
+ while (col < clear_width && ScreenLines[off_to] == ' '
+ && ScreenAttrs[off_to] == 0
+ && (!enc_utf8 || ScreenLinesUC[off_to] == 0))
+ {
+ ++off_to;
+ ++col;
+ }
+ if (col < clear_width)
+ {
+#ifdef FEAT_GUI
+ /*
+ * In the GUI, clearing the rest of the line may leave pixels
+ * behind if the first character cleared was bold. Some bold
+ * fonts spill over the left. In this case we redraw the previous
+ * character too. If we didn't skip any blanks above, then we
+ * only redraw if the character wasn't already redrawn anyway.
+ */
+ if (gui.in_use && (col > startCol || !redraw_this))
+ {
+ hl = ScreenAttrs[off_to];
+ if (hl > HL_ALL || (hl & HL_BOLD))
+ {
+ int prev_cells = 1;
+
+ if (enc_utf8)
+ /* for utf-8, ScreenLines[char_offset + 1] == 0 means
+ * that its width is 2. */
+ prev_cells = ScreenLines[off_to - 1] == 0 ? 2 : 1;
+ else if (enc_dbcs != 0)
+ {
+ /* find previous character by counting from first
+ * column and get its width. */
+ unsigned off = LineOffset[row];
+ unsigned max_off = LineOffset[row] + screen_Columns;
+
+ while (off < off_to)
+ {
+ prev_cells = (*mb_off2cells)(off, max_off);
+ off += prev_cells;
+ }
+ }
+
+ if (enc_dbcs != 0 && prev_cells > 1)
+ screen_char_2(off_to - prev_cells, row,
+ col + coloff - prev_cells);
+ else
+ screen_char(off_to - prev_cells, row,
+ col + coloff - prev_cells);
+ }
+ }
+#endif
+ screen_fill(row, row + 1, col + coloff, clear_width + coloff,
+ ' ', ' ', 0);
+ off_to += clear_width - col;
+ col = clear_width;
+ }
+ }
+
+ if (clear_width > 0)
+ {
+ /* For a window that's left of another, draw the separator char. */
+ if (col + coloff < Columns)
+ {
+ int c;
+
+ c = fillchar_vsep(&hl);
+ if (ScreenLines[off_to] != (schar_T)c
+ || (enc_utf8 && (int)ScreenLinesUC[off_to]
+ != (c >= 0x80 ? c : 0))
+ || ScreenAttrs[off_to] != hl)
+ {
+ ScreenLines[off_to] = c;
+ ScreenAttrs[off_to] = hl;
+ if (enc_utf8)
+ {
+ if (c >= 0x80)
+ {
+ ScreenLinesUC[off_to] = c;
+ ScreenLinesC[0][off_to] = 0;
+ }
+ else
+ ScreenLinesUC[off_to] = 0;
+ }
+ screen_char(off_to, row, col + coloff);
+ }
+ }
+ else
+ LineWraps[row] = FALSE;
+ }
+}
+
+#if defined(FEAT_RIGHTLEFT) || defined(PROTO)
+/*
+ * Mirror text "str" for right-left displaying.
+ * Only works for single-byte characters (e.g., numbers).
+ */
+ void
+rl_mirror(char_u *str)
+{
+ char_u *p1, *p2;
+ int t;
+
+ for (p1 = str, p2 = str + STRLEN(str) - 1; p1 < p2; ++p1, --p2)
+ {
+ t = *p1;
+ *p1 = *p2;
+ *p2 = t;
+ }
+}
+#endif
+
+/*
+ * mark all status lines for redraw; used after first :cd
+ */
+ void
+status_redraw_all(void)
+{
+ win_T *wp;
+
+ FOR_ALL_WINDOWS(wp)
+ if (wp->w_status_height)
+ {
+ wp->w_redr_status = TRUE;
+ redraw_later(VALID);
+ }
+}
+
+/*
+ * mark all status lines of the current buffer for redraw
+ */
+ void
+status_redraw_curbuf(void)
+{
+ win_T *wp;
+
+ FOR_ALL_WINDOWS(wp)
+ if (wp->w_status_height != 0 && wp->w_buffer == curbuf)
+ {
+ wp->w_redr_status = TRUE;
+ redraw_later(VALID);
+ }
+}
+
+/*
+ * Redraw all status lines that need to be redrawn.
+ */
+ void
+redraw_statuslines(void)
+{
+ win_T *wp;
+
+ FOR_ALL_WINDOWS(wp)
+ if (wp->w_redr_status)
+ win_redr_status(wp, FALSE);
+ if (redraw_tabline)
+ draw_tabline();
+}
+
+#if defined(FEAT_WILDMENU) || defined(PROTO)
+/*
+ * Redraw all status lines at the bottom of frame "frp".
+ */
+ void
+win_redraw_last_status(frame_T *frp)
+{
+ if (frp->fr_layout == FR_LEAF)
+ frp->fr_win->w_redr_status = TRUE;
+ else if (frp->fr_layout == FR_ROW)
+ {
+ FOR_ALL_FRAMES(frp, frp->fr_child)
+ win_redraw_last_status(frp);
+ }
+ else /* frp->fr_layout == FR_COL */
+ {
+ frp = frp->fr_child;
+ while (frp->fr_next != NULL)
+ frp = frp->fr_next;
+ win_redraw_last_status(frp);
+ }
+}
+#endif
+
+/*
+ * Draw the verticap separator right of window "wp" starting with line "row".
+ */
+ static void
+draw_vsep_win(win_T *wp, int row)
+{
+ int hl;
+ int c;
+
+ if (wp->w_vsep_width)
+ {
+ /* draw the vertical separator right of this window */
+ c = fillchar_vsep(&hl);
+ screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + wp->w_height,
+ W_ENDCOL(wp), W_ENDCOL(wp) + 1,
+ c, ' ', hl);
+ }
+}
+
+#ifdef FEAT_WILDMENU
+static int skip_status_match_char(expand_T *xp, char_u *s);
+
+/*
+ * Get the length of an item as it will be shown in the status line.
+ */
+ static int
+status_match_len(expand_T *xp, char_u *s)
+{
+ int len = 0;
+
+#ifdef FEAT_MENU
+ int emenu = (xp->xp_context == EXPAND_MENUS
+ || xp->xp_context == EXPAND_MENUNAMES);
+
+ /* Check for menu separators - replace with '|'. */
+ if (emenu && menu_is_separator(s))
+ return 1;
+#endif
+
+ while (*s != NUL)
+ {
+ s += skip_status_match_char(xp, s);
+ len += ptr2cells(s);
+ MB_PTR_ADV(s);
+ }
+
+ return len;
+}
+
+/*
+ * Return the number of characters that should be skipped in a status match.
+ * These are backslashes used for escaping. Do show backslashes in help tags.
+ */
+ static int
+skip_status_match_char(expand_T *xp, char_u *s)
+{
+ if ((rem_backslash(s) && xp->xp_context != EXPAND_HELP)
+#ifdef FEAT_MENU
+ || ((xp->xp_context == EXPAND_MENUS
+ || xp->xp_context == EXPAND_MENUNAMES)
+ && (s[0] == '\t' || (s[0] == '\\' && s[1] != NUL)))
+#endif
+ )
+ {
+#ifndef BACKSLASH_IN_FILENAME
+ if (xp->xp_shell && csh_like_shell() && s[1] == '\\' && s[2] == '!')
+ return 2;
+#endif
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Show wildchar matches in the status line.
+ * Show at least the "match" item.
+ * We start at item 'first_match' in the list and show all matches that fit.
+ *
+ * If inversion is possible we use it. Else '=' characters are used.
+ */
+ void
+win_redr_status_matches(
+ expand_T *xp,
+ int num_matches,
+ char_u **matches, /* list of matches */
+ int match,
+ int showtail)
+{
+#define L_MATCH(m) (showtail ? sm_gettail(matches[m]) : matches[m])
+ int row;
+ char_u *buf;
+ int len;
+ int clen; /* length in screen cells */
+ int fillchar;
+ int attr;
+ int i;
+ int highlight = TRUE;
+ char_u *selstart = NULL;
+ int selstart_col = 0;
+ char_u *selend = NULL;
+ static int first_match = 0;
+ int add_left = FALSE;
+ char_u *s;
+#ifdef FEAT_MENU
+ int emenu;
+#endif
+ int l;
+
+ if (matches == NULL) /* interrupted completion? */
+ return;
+
+ if (has_mbyte)
+ buf = alloc((unsigned)Columns * MB_MAXBYTES + 1);
+ else
+ buf = alloc((unsigned)Columns + 1);
+ if (buf == NULL)
+ return;
+
+ if (match == -1) /* don't show match but original text */
+ {
+ match = 0;
+ highlight = FALSE;
+ }
+ /* count 1 for the ending ">" */
+ clen = status_match_len(xp, L_MATCH(match)) + 3;
+ if (match == 0)
+ first_match = 0;
+ else if (match < first_match)
+ {
+ /* jumping left, as far as we can go */
+ first_match = match;
+ add_left = TRUE;
+ }
+ else
+ {
+ /* check if match fits on the screen */
+ for (i = first_match; i < match; ++i)
+ clen += status_match_len(xp, L_MATCH(i)) + 2;
+ if (first_match > 0)
+ clen += 2;
+ /* jumping right, put match at the left */
+ if ((long)clen > Columns)
+ {
+ first_match = match;
+ /* if showing the last match, we can add some on the left */
+ clen = 2;
+ for (i = match; i < num_matches; ++i)
+ {
+ clen += status_match_len(xp, L_MATCH(i)) + 2;
+ if ((long)clen >= Columns)
+ break;
+ }
+ if (i == num_matches)
+ add_left = TRUE;
+ }
+ }
+ if (add_left)
+ while (first_match > 0)
+ {
+ clen += status_match_len(xp, L_MATCH(first_match - 1)) + 2;
+ if ((long)clen >= Columns)
+ break;
+ --first_match;
+ }
+
+ fillchar = fillchar_status(&attr, curwin);
+
+ if (first_match == 0)
+ {
+ *buf = NUL;
+ len = 0;
+ }
+ else
+ {
+ STRCPY(buf, "< ");
+ len = 2;
+ }
+ clen = len;
+
+ i = first_match;
+ while ((long)(clen + status_match_len(xp, L_MATCH(i)) + 2) < Columns)
+ {
+ if (i == match)
+ {
+ selstart = buf + len;
+ selstart_col = clen;
+ }
+
+ s = L_MATCH(i);
+ /* Check for menu separators - replace with '|' */
+#ifdef FEAT_MENU
+ emenu = (xp->xp_context == EXPAND_MENUS
+ || xp->xp_context == EXPAND_MENUNAMES);
+ if (emenu && menu_is_separator(s))
+ {
+ STRCPY(buf + len, transchar('|'));
+ l = (int)STRLEN(buf + len);
+ len += l;
+ clen += l;
+ }
+ else
+#endif
+ for ( ; *s != NUL; ++s)
+ {
+ s += skip_status_match_char(xp, s);
+ clen += ptr2cells(s);
+ if (has_mbyte && (l = (*mb_ptr2len)(s)) > 1)
+ {
+ STRNCPY(buf + len, s, l);
+ s += l - 1;
+ len += l;
+ }
+ else
+ {
+ STRCPY(buf + len, transchar_byte(*s));
+ len += (int)STRLEN(buf + len);
+ }
+ }
+ if (i == match)
+ selend = buf + len;
+
+ *(buf + len++) = ' ';
+ *(buf + len++) = ' ';
+ clen += 2;
+ if (++i == num_matches)
+ break;
+ }
+
+ if (i != num_matches)
+ {
+ *(buf + len++) = '>';
+ ++clen;
+ }
+
+ buf[len] = NUL;
+
+ row = cmdline_row - 1;
+ if (row >= 0)
+ {
+ if (wild_menu_showing == 0)
+ {
+ if (msg_scrolled > 0)
+ {
+ /* Put the wildmenu just above the command line. If there is
+ * no room, scroll the screen one line up. */
+ if (cmdline_row == Rows - 1)
+ {
+ screen_del_lines(0, 0, 1, (int)Rows, TRUE, 0, NULL);
+ ++msg_scrolled;
+ }
+ else
+ {
+ ++cmdline_row;
+ ++row;
+ }
+ wild_menu_showing = WM_SCROLLED;
+ }
+ else
+ {
+ /* Create status line if needed by setting 'laststatus' to 2.
+ * Set 'winminheight' to zero to avoid that the window is
+ * resized. */
+ if (lastwin->w_status_height == 0)
+ {
+ save_p_ls = p_ls;
+ save_p_wmh = p_wmh;
+ p_ls = 2;
+ p_wmh = 0;
+ last_status(FALSE);
+ }
+ wild_menu_showing = WM_SHOWN;
+ }
+ }
+
+ screen_puts(buf, row, 0, attr);
+ if (selstart != NULL && highlight)
+ {
+ *selend = NUL;
+ screen_puts(selstart, row, selstart_col, HL_ATTR(HLF_WM));
+ }
+
+ screen_fill(row, row + 1, clen, (int)Columns, fillchar, fillchar, attr);
+ }
+
+ win_redraw_last_status(topframe);
+ vim_free(buf);
+}
+#endif
+
+/*
+ * Redraw the status line of window wp.
+ *
+ * If inversion is possible we use it. Else '=' characters are used.
+ * If "ignore_pum" is TRUE, also redraw statusline when the popup menu is
+ * displayed.
+ */
+ static void
+win_redr_status(win_T *wp, int ignore_pum UNUSED)
+{
+ int row;
+ char_u *p;
+ int len;
+ int fillchar;
+ int attr;
+ int this_ru_col;
+ static int busy = FALSE;
+
+ /* It's possible to get here recursively when 'statusline' (indirectly)
+ * invokes ":redrawstatus". Simply ignore the call then. */
+ if (busy)
+ return;
+ busy = TRUE;
+
+ wp->w_redr_status = FALSE;
+ if (wp->w_status_height == 0)
+ {
+ /* no status line, can only be last window */
+ redraw_cmdline = TRUE;
+ }
+ else if (!redrawing()
+#ifdef FEAT_INS_EXPAND
+ // don't update status line when popup menu is visible and may be
+ // drawn over it, unless it will be redrawn later
+ || (!ignore_pum && pum_visible())
+#endif
+ )
+ {
+ /* Don't redraw right now, do it later. */
+ wp->w_redr_status = TRUE;
+ }
+#ifdef FEAT_STL_OPT
+ else if (*p_stl != NUL || *wp->w_p_stl != NUL)
+ {
+ /* redraw custom status line */
+ redraw_custom_statusline(wp);
+ }
+#endif
+ else
+ {
+ fillchar = fillchar_status(&attr, wp);
+
+ get_trans_bufname(wp->w_buffer);
+ p = NameBuff;
+ len = (int)STRLEN(p);
+
+ if (bt_help(wp->w_buffer)
+#ifdef FEAT_QUICKFIX
+ || wp->w_p_pvw
+#endif
+ || bufIsChanged(wp->w_buffer)
+ || wp->w_buffer->b_p_ro)
+ *(p + len++) = ' ';
+ if (bt_help(wp->w_buffer))
+ {
+ STRCPY(p + len, _("[Help]"));
+ len += (int)STRLEN(p + len);
+ }
+#ifdef FEAT_QUICKFIX
+ if (wp->w_p_pvw)
+ {
+ STRCPY(p + len, _("[Preview]"));
+ len += (int)STRLEN(p + len);
+ }
+#endif
+ if (bufIsChanged(wp->w_buffer)
+#ifdef FEAT_TERMINAL
+ && !bt_terminal(wp->w_buffer)
+#endif
+ )
+ {
+ STRCPY(p + len, "[+]");
+ len += 3;
+ }
+ if (wp->w_buffer->b_p_ro)
+ {
+ STRCPY(p + len, _("[RO]"));
+ len += (int)STRLEN(p + len);
+ }
+
+ this_ru_col = ru_col - (Columns - wp->w_width);
+ if (this_ru_col < (wp->w_width + 1) / 2)
+ this_ru_col = (wp->w_width + 1) / 2;
+ if (this_ru_col <= 1)
+ {
+ p = (char_u *)"<"; /* No room for file name! */
+ len = 1;
+ }
+ else if (has_mbyte)
+ {
+ int clen = 0, i;
+
+ /* Count total number of display cells. */
+ clen = mb_string2cells(p, -1);
+
+ /* Find first character that will fit.
+ * Going from start to end is much faster for DBCS. */
+ for (i = 0; p[i] != NUL && clen >= this_ru_col - 1;
+ i += (*mb_ptr2len)(p + i))
+ clen -= (*mb_ptr2cells)(p + i);
+ len = clen;
+ if (i > 0)
+ {
+ p = p + i - 1;
+ *p = '<';
+ ++len;
+ }
+
+ }
+ else if (len > this_ru_col - 1)
+ {
+ p += len - (this_ru_col - 1);
+ *p = '<';
+ len = this_ru_col - 1;
+ }
+
+ row = W_WINROW(wp) + wp->w_height;
+ screen_puts(p, row, wp->w_wincol, attr);
+ screen_fill(row, row + 1, len + wp->w_wincol,
+ this_ru_col + wp->w_wincol, fillchar, fillchar, attr);
+
+ if (get_keymap_str(wp, (char_u *)"<%s>", NameBuff, MAXPATHL)
+ && (int)(this_ru_col - len) > (int)(STRLEN(NameBuff) + 1))
+ screen_puts(NameBuff, row, (int)(this_ru_col - STRLEN(NameBuff)
+ - 1 + wp->w_wincol), attr);
+
+#ifdef FEAT_CMDL_INFO
+ win_redr_ruler(wp, TRUE, ignore_pum);
+#endif
+ }
+
+ /*
+ * May need to draw the character below the vertical separator.
+ */
+ if (wp->w_vsep_width != 0 && wp->w_status_height != 0 && redrawing())
+ {
+ if (stl_connected(wp))
+ fillchar = fillchar_status(&attr, wp);
+ else
+ fillchar = fillchar_vsep(&attr);
+ screen_putchar(fillchar, W_WINROW(wp) + wp->w_height, W_ENDCOL(wp),
+ attr);
+ }
+ busy = FALSE;
+}
+
+#ifdef FEAT_STL_OPT
+/*
+ * Redraw the status line according to 'statusline' and take care of any
+ * errors encountered.
+ */
+ static void
+redraw_custom_statusline(win_T *wp)
+{
+ static int entered = FALSE;
+ int saved_did_emsg = did_emsg;
+
+ /* When called recursively return. This can happen when the statusline
+ * contains an expression that triggers a redraw. */
+ if (entered)
+ return;
+ entered = TRUE;
+
+ did_emsg = FALSE;
+ win_redr_custom(wp, FALSE);
+ if (did_emsg)
+ {
+ /* When there is an error disable the statusline, otherwise the
+ * display is messed up with errors and a redraw triggers the problem
+ * again and again. */
+ set_string_option_direct((char_u *)"statusline", -1,
+ (char_u *)"", OPT_FREE | (*wp->w_p_stl != NUL
+ ? OPT_LOCAL : OPT_GLOBAL), SID_ERROR);
+ }
+ did_emsg |= saved_did_emsg;
+ entered = FALSE;
+}
+#endif
+
+/*
+ * Return TRUE if the status line of window "wp" is connected to the status
+ * line of the window right of it. If not, then it's a vertical separator.
+ * Only call if (wp->w_vsep_width != 0).
+ */
+ int
+stl_connected(win_T *wp)
+{
+ frame_T *fr;
+
+ fr = wp->w_frame;
+ while (fr->fr_parent != NULL)
+ {
+ if (fr->fr_parent->fr_layout == FR_COL)
+ {
+ if (fr->fr_next != NULL)
+ break;
+ }
+ else
+ {
+ if (fr->fr_next != NULL)
+ return TRUE;
+ }
+ fr = fr->fr_parent;
+ }
+ return FALSE;
+}
+
+
+/*
+ * Get the value to show for the language mappings, active 'keymap'.
+ */
+ int
+get_keymap_str(
+ win_T *wp,
+ char_u *fmt, /* format string containing one %s item */
+ char_u *buf, /* buffer for the result */
+ int len) /* length of buffer */
+{
+ char_u *p;
+
+ if (wp->w_buffer->b_p_iminsert != B_IMODE_LMAP)
+ return FALSE;
+
+ {
+#ifdef FEAT_EVAL
+ buf_T *old_curbuf = curbuf;
+ win_T *old_curwin = curwin;
+ char_u *s;
+
+ curbuf = wp->w_buffer;
+ curwin = wp;
+ STRCPY(buf, "b:keymap_name"); /* must be writable */
+ ++emsg_skip;
+ s = p = eval_to_string(buf, NULL, FALSE);
+ --emsg_skip;
+ curbuf = old_curbuf;
+ curwin = old_curwin;
+ if (p == NULL || *p == NUL)
+#endif
+ {
+#ifdef FEAT_KEYMAP
+ if (wp->w_buffer->b_kmap_state & KEYMAP_LOADED)
+ p = wp->w_buffer->b_p_keymap;
+ else
+#endif
+ p = (char_u *)"lang";
+ }
+ if (vim_snprintf((char *)buf, len, (char *)fmt, p) > len - 1)
+ buf[0] = NUL;
+#ifdef FEAT_EVAL
+ vim_free(s);
+#endif
+ }
+ return buf[0] != NUL;
+}
+
+#if defined(FEAT_STL_OPT) || defined(PROTO)
+/*
+ * Redraw the status line or ruler of window "wp".
+ * When "wp" is NULL redraw the tab pages line from 'tabline'.
+ */
+ static void
+win_redr_custom(
+ win_T *wp,
+ int draw_ruler) /* TRUE or FALSE */
+{
+ static int entered = FALSE;
+ int attr;
+ int curattr;
+ int row;
+ int col = 0;
+ int maxwidth;
+ int width;
+ int n;
+ int len;
+ int fillchar;
+ char_u buf[MAXPATHL];
+ char_u *stl;
+ char_u *p;
+ struct stl_hlrec hltab[STL_MAX_ITEM];
+ struct stl_hlrec tabtab[STL_MAX_ITEM];
+ int use_sandbox = FALSE;
+ win_T *ewp;
+ int p_crb_save;
+
+ /* There is a tiny chance that this gets called recursively: When
+ * redrawing a status line triggers redrawing the ruler or tabline.
+ * Avoid trouble by not allowing recursion. */
+ if (entered)
+ return;
+ entered = TRUE;
+
+ /* setup environment for the task at hand */
+ if (wp == NULL)
+ {
+ /* Use 'tabline'. Always at the first line of the screen. */
+ stl = p_tal;
+ row = 0;
+ fillchar = ' ';
+ attr = HL_ATTR(HLF_TPF);
+ maxwidth = Columns;
+# ifdef FEAT_EVAL
+ use_sandbox = was_set_insecurely((char_u *)"tabline", 0);
+# endif
+ }
+ else
+ {
+ row = W_WINROW(wp) + wp->w_height;
+ fillchar = fillchar_status(&attr, wp);
+ maxwidth = wp->w_width;
+
+ if (draw_ruler)
+ {
+ stl = p_ruf;
+ /* advance past any leading group spec - implicit in ru_col */
+ if (*stl == '%')
+ {
+ if (*++stl == '-')
+ stl++;
+ if (atoi((char *)stl))
+ while (VIM_ISDIGIT(*stl))
+ stl++;
+ if (*stl++ != '(')
+ stl = p_ruf;
+ }
+ col = ru_col - (Columns - wp->w_width);
+ if (col < (wp->w_width + 1) / 2)
+ col = (wp->w_width + 1) / 2;
+ maxwidth = wp->w_width - col;
+ if (!wp->w_status_height)
+ {
+ row = Rows - 1;
+ --maxwidth; /* writing in last column may cause scrolling */
+ fillchar = ' ';
+ attr = 0;
+ }
+
+# ifdef FEAT_EVAL
+ use_sandbox = was_set_insecurely((char_u *)"rulerformat", 0);
+# endif
+ }
+ else
+ {
+ if (*wp->w_p_stl != NUL)
+ stl = wp->w_p_stl;
+ else
+ stl = p_stl;
+# ifdef FEAT_EVAL
+ use_sandbox = was_set_insecurely((char_u *)"statusline",
+ *wp->w_p_stl == NUL ? 0 : OPT_LOCAL);
+# endif
+ }
+
+ col += wp->w_wincol;
+ }
+
+ if (maxwidth <= 0)
+ goto theend;
+
+ /* Temporarily reset 'cursorbind', we don't want a side effect from moving
+ * the cursor away and back. */
+ ewp = wp == NULL ? curwin : wp;
+ p_crb_save = ewp->w_p_crb;
+ ewp->w_p_crb = FALSE;
+
+ /* Make a copy, because the statusline may include a function call that
+ * might change the option value and free the memory. */
+ stl = vim_strsave(stl);
+ width = build_stl_str_hl(ewp, buf, sizeof(buf),
+ stl, use_sandbox,
+ fillchar, maxwidth, hltab, tabtab);
+ vim_free(stl);
+ ewp->w_p_crb = p_crb_save;
+
+ /* Make all characters printable. */
+ p = transstr(buf);
+ if (p != NULL)
+ {
+ vim_strncpy(buf, p, sizeof(buf) - 1);
+ vim_free(p);
+ }
+
+ /* fill up with "fillchar" */
+ len = (int)STRLEN(buf);
+ while (width < maxwidth && len < (int)sizeof(buf) - 1)
+ {
+ len += (*mb_char2bytes)(fillchar, buf + len);
+ ++width;
+ }
+ buf[len] = NUL;
+
+ /*
+ * Draw each snippet with the specified highlighting.
+ */
+ curattr = attr;
+ p = buf;
+ for (n = 0; hltab[n].start != NULL; n++)
+ {
+ len = (int)(hltab[n].start - p);
+ screen_puts_len(p, len, row, col, curattr);
+ col += vim_strnsize(p, len);
+ p = hltab[n].start;
+
+ if (hltab[n].userhl == 0)
+ curattr = attr;
+ else if (hltab[n].userhl < 0)
+ curattr = syn_id2attr(-hltab[n].userhl);
+#ifdef FEAT_TERMINAL
+ else if (wp != NULL && wp != curwin && bt_terminal(wp->w_buffer)
+ && wp->w_status_height != 0)
+ curattr = highlight_stltermnc[hltab[n].userhl - 1];
+ else if (wp != NULL && bt_terminal(wp->w_buffer)
+ && wp->w_status_height != 0)
+ curattr = highlight_stlterm[hltab[n].userhl - 1];
+#endif
+ else if (wp != NULL && wp != curwin && wp->w_status_height != 0)
+ curattr = highlight_stlnc[hltab[n].userhl - 1];
+ else
+ curattr = highlight_user[hltab[n].userhl - 1];
+ }
+ screen_puts(p, row, col, curattr);
+
+ if (wp == NULL)
+ {
+ /* Fill the TabPageIdxs[] array for clicking in the tab pagesline. */
+ col = 0;
+ len = 0;
+ p = buf;
+ fillchar = 0;
+ for (n = 0; tabtab[n].start != NULL; n++)
+ {
+ len += vim_strnsize(p, (int)(tabtab[n].start - p));
+ while (col < len)
+ TabPageIdxs[col++] = fillchar;
+ p = tabtab[n].start;
+ fillchar = tabtab[n].userhl;
+ }
+ while (col < Columns)
+ TabPageIdxs[col++] = fillchar;
+ }
+
+theend:
+ entered = FALSE;
+}
+
+#endif /* FEAT_STL_OPT */
+
+/*
+ * Output a single character directly to the screen and update ScreenLines.
+ */
+ void
+screen_putchar(int c, int row, int col, int attr)
+{
+ char_u buf[MB_MAXBYTES + 1];
+
+ if (has_mbyte)
+ buf[(*mb_char2bytes)(c, buf)] = NUL;
+ else
+ {
+ buf[0] = c;
+ buf[1] = NUL;
+ }
+ screen_puts(buf, row, col, attr);
+}
+
+/*
+ * Get a single character directly from ScreenLines into "bytes[]".
+ * Also return its attribute in *attrp;
+ */
+ void
+screen_getbytes(int row, int col, char_u *bytes, int *attrp)
+{
+ unsigned off;
+
+ /* safety check */
+ if (ScreenLines != NULL && row < screen_Rows && col < screen_Columns)
+ {
+ off = LineOffset[row] + col;
+ *attrp = ScreenAttrs[off];
+ bytes[0] = ScreenLines[off];
+ bytes[1] = NUL;
+
+ if (enc_utf8 && ScreenLinesUC[off] != 0)
+ bytes[utfc_char2bytes(off, bytes)] = NUL;
+ else if (enc_dbcs == DBCS_JPNU && ScreenLines[off] == 0x8e)
+ {
+ bytes[0] = ScreenLines[off];
+ bytes[1] = ScreenLines2[off];
+ bytes[2] = NUL;
+ }
+ else if (enc_dbcs && MB_BYTE2LEN(bytes[0]) > 1)
+ {
+ bytes[1] = ScreenLines[off + 1];
+ bytes[2] = NUL;
+ }
+ }
+}
+
+/*
+ * Return TRUE if composing characters for screen posn "off" differs from
+ * composing characters in "u8cc".
+ * Only to be used when ScreenLinesUC[off] != 0.
+ */
+ static int
+screen_comp_differs(int off, int *u8cc)
+{
+ int i;
+
+ for (i = 0; i < Screen_mco; ++i)
+ {
+ if (ScreenLinesC[i][off] != (u8char_T)u8cc[i])
+ return TRUE;
+ if (u8cc[i] == 0)
+ break;
+ }
+ return FALSE;
+}
+
+/*
+ * Put string '*text' on the screen at position 'row' and 'col', with
+ * attributes 'attr', and update ScreenLines[] and ScreenAttrs[].
+ * Note: only outputs within one row, message is truncated at screen boundary!
+ * Note: if ScreenLines[], row and/or col is invalid, nothing is done.
+ */
+ void
+screen_puts(
+ char_u *text,
+ int row,
+ int col,
+ int attr)
+{
+ screen_puts_len(text, -1, row, col, attr);
+}
+
+/*
+ * Like screen_puts(), but output "text[len]". When "len" is -1 output up to
+ * a NUL.
+ */
+ void
+screen_puts_len(
+ char_u *text,
+ int textlen,
+ int row,
+ int col,
+ int attr)
+{
+ unsigned off;
+ char_u *ptr = text;
+ int len = textlen;
+ int c;
+ unsigned max_off;
+ int mbyte_blen = 1;
+ int mbyte_cells = 1;
+ int u8c = 0;
+ int u8cc[MAX_MCO];
+ int clear_next_cell = FALSE;
+#ifdef FEAT_ARABIC
+ int prev_c = 0; /* previous Arabic character */
+ int pc, nc, nc1;
+ int pcc[MAX_MCO];
+#endif
+ int force_redraw_this;
+ int force_redraw_next = FALSE;
+ int need_redraw;
+
+ if (ScreenLines == NULL || row >= screen_Rows) /* safety check */
+ return;
+ off = LineOffset[row] + col;
+
+ /* When drawing over the right halve of a double-wide char clear out the
+ * left halve. Only needed in a terminal. */
+ if (has_mbyte && col > 0 && col < screen_Columns
+#ifdef FEAT_GUI
+ && !gui.in_use
+#endif
+ && mb_fix_col(col, row) != col)
+ {
+ ScreenLines[off - 1] = ' ';
+ ScreenAttrs[off - 1] = 0;
+ if (enc_utf8)
+ {
+ ScreenLinesUC[off - 1] = 0;
+ ScreenLinesC[0][off - 1] = 0;
+ }
+ /* redraw the previous cell, make it empty */
+ screen_char(off - 1, row, col - 1);
+ /* force the cell at "col" to be redrawn */
+ force_redraw_next = TRUE;
+ }
+
+ max_off = LineOffset[row] + screen_Columns;
+ while (col < screen_Columns
+ && (len < 0 || (int)(ptr - text) < len)
+ && *ptr != NUL)
+ {
+ c = *ptr;
+ /* check if this is the first byte of a multibyte */
+ if (has_mbyte)
+ {
+ if (enc_utf8 && len > 0)
+ mbyte_blen = utfc_ptr2len_len(ptr, (int)((text + len) - ptr));
+ else
+ mbyte_blen = (*mb_ptr2len)(ptr);
+ if (enc_dbcs == DBCS_JPNU && c == 0x8e)
+ mbyte_cells = 1;
+ else if (enc_dbcs != 0)
+ mbyte_cells = mbyte_blen;
+ else /* enc_utf8 */
+ {
+ if (len >= 0)
+ u8c = utfc_ptr2char_len(ptr, u8cc,
+ (int)((text + len) - ptr));
+ else
+ u8c = utfc_ptr2char(ptr, u8cc);
+ mbyte_cells = utf_char2cells(u8c);
+#ifdef FEAT_ARABIC
+ if (p_arshape && !p_tbidi && ARABIC_CHAR(u8c))
+ {
+ /* Do Arabic shaping. */
+ if (len >= 0 && (int)(ptr - text) + mbyte_blen >= len)
+ {
+ /* Past end of string to be displayed. */
+ nc = NUL;
+ nc1 = NUL;
+ }
+ else
+ {
+ nc = utfc_ptr2char_len(ptr + mbyte_blen, pcc,
+ (int)((text + len) - ptr - mbyte_blen));
+ nc1 = pcc[0];
+ }
+ pc = prev_c;
+ prev_c = u8c;
+ u8c = arabic_shape(u8c, &c, &u8cc[0], nc, nc1, pc);
+ }
+ else
+ prev_c = u8c;
+#endif
+ if (col + mbyte_cells > screen_Columns)
+ {
+ /* Only 1 cell left, but character requires 2 cells:
+ * display a '>' in the last column to avoid wrapping. */
+ c = '>';
+ mbyte_cells = 1;
+ }
+ }
+ }
+
+ force_redraw_this = force_redraw_next;
+ force_redraw_next = FALSE;
+
+ need_redraw = ScreenLines[off] != c
+ || (mbyte_cells == 2
+ && ScreenLines[off + 1] != (enc_dbcs ? ptr[1] : 0))
+ || (enc_dbcs == DBCS_JPNU
+ && c == 0x8e
+ && ScreenLines2[off] != ptr[1])
+ || (enc_utf8
+ && (ScreenLinesUC[off] !=
+ (u8char_T)(c < 0x80 && u8cc[0] == 0 ? 0 : u8c)
+ || (ScreenLinesUC[off] != 0
+ && screen_comp_differs(off, u8cc))))
+ || ScreenAttrs[off] != attr
+ || exmode_active;
+
+ if (need_redraw || force_redraw_this)
+ {
+#if defined(FEAT_GUI) || defined(UNIX)
+ /* The bold trick makes a single row of pixels appear in the next
+ * character. When a bold character is removed, the next
+ * character should be redrawn too. This happens for our own GUI
+ * and for some xterms. */
+ if (need_redraw && ScreenLines[off] != ' ' && (
+# ifdef FEAT_GUI
+ gui.in_use
+# endif
+# if defined(FEAT_GUI) && defined(UNIX)
+ ||
+# endif
+# ifdef UNIX
+ term_is_xterm
+# endif
+ ))
+ {
+ int n = ScreenAttrs[off];
+
+ if (n > HL_ALL)
+ n = syn_attr2attr(n);
+ if (n & HL_BOLD)
+ force_redraw_next = TRUE;
+ }
+#endif
+ /* When at the end of the text and overwriting a two-cell
+ * character with a one-cell character, need to clear the next
+ * cell. Also when overwriting the left halve of a two-cell char
+ * with the right halve of a two-cell char. Do this only once
+ * (mb_off2cells() may return 2 on the right halve). */
+ if (clear_next_cell)
+ clear_next_cell = FALSE;
+ else if (has_mbyte
+ && (len < 0 ? ptr[mbyte_blen] == NUL
+ : ptr + mbyte_blen >= text + len)
+ && ((mbyte_cells == 1 && (*mb_off2cells)(off, max_off) > 1)
+ || (mbyte_cells == 2
+ && (*mb_off2cells)(off, max_off) == 1
+ && (*mb_off2cells)(off + 1, max_off) > 1)))
+ clear_next_cell = TRUE;
+
+ /* Make sure we never leave a second byte of a double-byte behind,
+ * it confuses mb_off2cells(). */
+ if (enc_dbcs
+ && ((mbyte_cells == 1 && (*mb_off2cells)(off, max_off) > 1)
+ || (mbyte_cells == 2
+ && (*mb_off2cells)(off, max_off) == 1
+ && (*mb_off2cells)(off + 1, max_off) > 1)))
+ ScreenLines[off + mbyte_blen] = 0;
+ ScreenLines[off] = c;
+ ScreenAttrs[off] = attr;
+ if (enc_utf8)
+ {
+ if (c < 0x80 && u8cc[0] == 0)
+ ScreenLinesUC[off] = 0;
+ else
+ {
+ int i;
+
+ ScreenLinesUC[off] = u8c;
+ for (i = 0; i < Screen_mco; ++i)
+ {
+ ScreenLinesC[i][off] = u8cc[i];
+ if (u8cc[i] == 0)
+ break;
+ }
+ }
+ if (mbyte_cells == 2)
+ {
+ ScreenLines[off + 1] = 0;
+ ScreenAttrs[off + 1] = attr;
+ }
+ screen_char(off, row, col);
+ }
+ else if (mbyte_cells == 2)
+ {
+ ScreenLines[off + 1] = ptr[1];
+ ScreenAttrs[off + 1] = attr;
+ screen_char_2(off, row, col);
+ }
+ else if (enc_dbcs == DBCS_JPNU && c == 0x8e)
+ {
+ ScreenLines2[off] = ptr[1];
+ screen_char(off, row, col);
+ }
+ else
+ screen_char(off, row, col);
+ }
+ if (has_mbyte)
+ {
+ off += mbyte_cells;
+ col += mbyte_cells;
+ ptr += mbyte_blen;
+ if (clear_next_cell)
+ {
+ /* This only happens at the end, display one space next. */
+ ptr = (char_u *)" ";
+ len = -1;
+ }
+ }
+ else
+ {
+ ++off;
+ ++col;
+ ++ptr;
+ }
+ }
+
+ /* If we detected the next character needs to be redrawn, but the text
+ * doesn't extend up to there, update the character here. */
+ if (force_redraw_next && col < screen_Columns)
+ {
+ if (enc_dbcs != 0 && dbcs_off2cells(off, max_off) > 1)
+ screen_char_2(off, row, col);
+ else
+ screen_char(off, row, col);
+ }
+}
+
+#ifdef FEAT_SEARCH_EXTRA
+/*
+ * Prepare for 'hlsearch' highlighting.
+ */
+ static void
+start_search_hl(void)
+{
+ if (p_hls && !no_hlsearch)
+ {
+ last_pat_prog(&search_hl.rm);
+ search_hl.attr = HL_ATTR(HLF_L);
+# ifdef FEAT_RELTIME
+ /* Set the time limit to 'redrawtime'. */
+ profile_setlimit(p_rdt, &search_hl.tm);
+# endif
+ }
+}
+
+/*
+ * Clean up for 'hlsearch' highlighting.
+ */
+ static void
+end_search_hl(void)
+{
+ if (search_hl.rm.regprog != NULL)
+ {
+ vim_regfree(search_hl.rm.regprog);
+ search_hl.rm.regprog = NULL;
+ }
+}
+
+/*
+ * Init for calling prepare_search_hl().
+ */
+ static void
+init_search_hl(win_T *wp)
+{
+ matchitem_T *cur;
+
+ /* Setup for match and 'hlsearch' highlighting. Disable any previous
+ * match */
+ cur = wp->w_match_head;
+ while (cur != NULL)
+ {
+ cur->hl.rm = cur->match;
+ if (cur->hlg_id == 0)
+ cur->hl.attr = 0;
+ else
+ cur->hl.attr = syn_id2attr(cur->hlg_id);
+ cur->hl.buf = wp->w_buffer;
+ cur->hl.lnum = 0;
+ cur->hl.first_lnum = 0;
+# ifdef FEAT_RELTIME
+ /* Set the time limit to 'redrawtime'. */
+ profile_setlimit(p_rdt, &(cur->hl.tm));
+# endif
+ cur = cur->next;
+ }
+ search_hl.buf = wp->w_buffer;
+ search_hl.lnum = 0;
+ search_hl.first_lnum = 0;
+ /* time limit is set at the toplevel, for all windows */
+}
+
+/*
+ * Advance to the match in window "wp" line "lnum" or past it.
+ */
+ static void
+prepare_search_hl(win_T *wp, linenr_T lnum)
+{
+ matchitem_T *cur; /* points to the match list */
+ match_T *shl; /* points to search_hl or a match */
+ int shl_flag; /* flag to indicate whether search_hl
+ has been processed or not */
+ int pos_inprogress; /* marks that position match search is
+ in progress */
+ int n;
+
+ /*
+ * When using a multi-line pattern, start searching at the top
+ * of the window or just after a closed fold.
+ * Do this both for search_hl and the match list.
+ */
+ cur = wp->w_match_head;
+ shl_flag = FALSE;
+ while (cur != NULL || shl_flag == FALSE)
+ {
+ if (shl_flag == FALSE)
+ {
+ shl = &search_hl;
+ shl_flag = TRUE;
+ }
+ else
+ shl = &cur->hl;
+ if (shl->rm.regprog != NULL
+ && shl->lnum == 0
+ && re_multiline(shl->rm.regprog))
+ {
+ if (shl->first_lnum == 0)
+ {
+# ifdef FEAT_FOLDING
+ for (shl->first_lnum = lnum;
+ shl->first_lnum > wp->w_topline; --shl->first_lnum)
+ if (hasFoldingWin(wp, shl->first_lnum - 1,
+ NULL, NULL, TRUE, NULL))
+ break;
+# else
+ shl->first_lnum = wp->w_topline;
+# endif
+ }
+ if (cur != NULL)
+ cur->pos.cur = 0;
+ pos_inprogress = TRUE;
+ n = 0;
+ while (shl->first_lnum < lnum && (shl->rm.regprog != NULL
+ || (cur != NULL && pos_inprogress)))
+ {
+ next_search_hl(wp, shl, shl->first_lnum, (colnr_T)n,
+ shl == &search_hl ? NULL : cur);
+ pos_inprogress = cur == NULL || cur->pos.cur == 0
+ ? FALSE : TRUE;
+ if (shl->lnum != 0)
+ {
+ shl->first_lnum = shl->lnum
+ + shl->rm.endpos[0].lnum
+ - shl->rm.startpos[0].lnum;
+ n = shl->rm.endpos[0].col;
+ }
+ else
+ {
+ ++shl->first_lnum;
+ n = 0;
+ }
+ }
+ }
+ if (shl != &search_hl && cur != NULL)
+ cur = cur->next;
+ }
+}
+
+/*
+ * Search for a next 'hlsearch' or match.
+ * Uses shl->buf.
+ * Sets shl->lnum and shl->rm contents.
+ * Note: Assumes a previous match is always before "lnum", unless
+ * shl->lnum is zero.
+ * Careful: Any pointers for buffer lines will become invalid.
+ */
+ static void
+next_search_hl(
+ win_T *win,
+ match_T *shl, /* points to search_hl or a match */
+ linenr_T lnum,
+ colnr_T mincol, /* minimal column for a match */
+ matchitem_T *cur) /* to retrieve match positions if any */
+{
+ linenr_T l;
+ colnr_T matchcol;
+ long nmatched;
+ int save_called_emsg = called_emsg;
+
+ // for :{range}s/pat only highlight inside the range
+ if (lnum < search_first_line || lnum > search_last_line)
+ {
+ shl->lnum = 0;
+ return;
+ }
+
+ if (shl->lnum != 0)
+ {
+ /* Check for three situations:
+ * 1. If the "lnum" is below a previous match, start a new search.
+ * 2. If the previous match includes "mincol", use it.
+ * 3. Continue after the previous match.
+ */
+ l = shl->lnum + shl->rm.endpos[0].lnum - shl->rm.startpos[0].lnum;
+ if (lnum > l)
+ shl->lnum = 0;
+ else if (lnum < l || shl->rm.endpos[0].col > mincol)
+ return;
+ }
+
+ /*
+ * Repeat searching for a match until one is found that includes "mincol"
+ * or none is found in this line.
+ */
+ called_emsg = FALSE;
+ for (;;)
+ {
+#ifdef FEAT_RELTIME
+ /* Stop searching after passing the time limit. */
+ if (profile_passed_limit(&(shl->tm)))
+ {
+ shl->lnum = 0; /* no match found in time */
+ break;
+ }
+#endif
+ /* Three situations:
+ * 1. No useful previous match: search from start of line.
+ * 2. Not Vi compatible or empty match: continue at next character.
+ * Break the loop if this is beyond the end of the line.
+ * 3. Vi compatible searching: continue at end of previous match.
+ */
+ if (shl->lnum == 0)
+ matchcol = 0;
+ else if (vim_strchr(p_cpo, CPO_SEARCH) == NULL
+ || (shl->rm.endpos[0].lnum == 0
+ && shl->rm.endpos[0].col <= shl->rm.startpos[0].col))
+ {
+ char_u *ml;
+
+ matchcol = shl->rm.startpos[0].col;
+ ml = ml_get_buf(shl->buf, lnum, FALSE) + matchcol;
+ if (*ml == NUL)
+ {
+ ++matchcol;
+ shl->lnum = 0;
+ break;
+ }
+ if (has_mbyte)
+ matchcol += mb_ptr2len(ml);
+ else
+ ++matchcol;
+ }
+ else
+ matchcol = shl->rm.endpos[0].col;
+
+ shl->lnum = lnum;
+ if (shl->rm.regprog != NULL)
+ {
+ /* Remember whether shl->rm is using a copy of the regprog in
+ * cur->match. */
+ int regprog_is_copy = (shl != &search_hl && cur != NULL
+ && shl == &cur->hl
+ && cur->match.regprog == cur->hl.rm.regprog);
+ int timed_out = FALSE;
+
+ nmatched = vim_regexec_multi(&shl->rm, win, shl->buf, lnum,
+ matchcol,
+#ifdef FEAT_RELTIME
+ &(shl->tm), &timed_out
+#else
+ NULL, NULL
+#endif
+ );
+ /* Copy the regprog, in case it got freed and recompiled. */
+ if (regprog_is_copy)
+ cur->match.regprog = cur->hl.rm.regprog;
+
+ if (called_emsg || got_int || timed_out)
+ {
+ /* Error while handling regexp: stop using this regexp. */
+ if (shl == &search_hl)
+ {
+ /* don't free regprog in the match list, it's a copy */
+ vim_regfree(shl->rm.regprog);
+ set_no_hlsearch(TRUE);
+ }
+ shl->rm.regprog = NULL;
+ shl->lnum = 0;
+ got_int = FALSE; /* avoid the "Type :quit to exit Vim"
+ message */
+ break;
+ }
+ }
+ else if (cur != NULL)
+ nmatched = next_search_hl_pos(shl, lnum, &(cur->pos), matchcol);
+ else
+ nmatched = 0;
+ if (nmatched == 0)
+ {
+ shl->lnum = 0; /* no match found */
+ break;
+ }
+ if (shl->rm.startpos[0].lnum > 0
+ || shl->rm.startpos[0].col >= mincol
+ || nmatched > 1
+ || shl->rm.endpos[0].col > mincol)
+ {
+ shl->lnum += shl->rm.startpos[0].lnum;
+ break; /* useful match found */
+ }
+ }
+
+ // Restore called_emsg for assert_fails().
+ called_emsg = save_called_emsg;
+}
+
+/*
+ * If there is a match fill "shl" and return one.
+ * Return zero otherwise.
+ */
+ static int
+next_search_hl_pos(
+ match_T *shl, /* points to a match */
+ linenr_T lnum,
+ posmatch_T *posmatch, /* match positions */
+ colnr_T mincol) /* minimal column for a match */
+{
+ int i;
+ int found = -1;
+
+ for (i = posmatch->cur; i < MAXPOSMATCH; i++)
+ {
+ llpos_T *pos = &posmatch->pos[i];
+
+ if (pos->lnum == 0)
+ break;
+ if (pos->len == 0 && pos->col < mincol)
+ continue;
+ if (pos->lnum == lnum)
+ {
+ if (found >= 0)
+ {
+ /* if this match comes before the one at "found" then swap
+ * them */
+ if (pos->col < posmatch->pos[found].col)
+ {
+ llpos_T tmp = *pos;
+
+ *pos = posmatch->pos[found];
+ posmatch->pos[found] = tmp;
+ }
+ }
+ else
+ found = i;
+ }
+ }
+ posmatch->cur = 0;
+ if (found >= 0)
+ {
+ colnr_T start = posmatch->pos[found].col == 0
+ ? 0 : posmatch->pos[found].col - 1;
+ colnr_T end = posmatch->pos[found].col == 0
+ ? MAXCOL : start + posmatch->pos[found].len;
+
+ shl->lnum = lnum;
+ shl->rm.startpos[0].lnum = 0;
+ shl->rm.startpos[0].col = start;
+ shl->rm.endpos[0].lnum = 0;
+ shl->rm.endpos[0].col = end;
+ shl->is_addpos = TRUE;
+ posmatch->cur = found + 1;
+ return 1;
+ }
+ return 0;
+}
+#endif
+
+ static void
+screen_start_highlight(int attr)
+{
+ attrentry_T *aep = NULL;
+
+ screen_attr = attr;
+ if (full_screen
+#ifdef WIN3264
+ && termcap_active
+#endif
+ )
+ {
+#ifdef FEAT_GUI
+ if (gui.in_use)
+ {
+ char buf[20];
+
+ /* The GUI handles this internally. */
+ sprintf(buf, IF_EB("\033|%dh", ESC_STR "|%dh"), attr);
+ OUT_STR(buf);
+ }
+ else
+#endif
+ {
+ if (attr > HL_ALL) /* special HL attr. */
+ {
+ if (IS_CTERM)
+ aep = syn_cterm_attr2entry(attr);
+ else
+ aep = syn_term_attr2entry(attr);
+ if (aep == NULL) /* did ":syntax clear" */
+ attr = 0;
+ else
+ attr = aep->ae_attr;
+ }
+ if ((attr & HL_BOLD) && *T_MD != NUL) /* bold */
+ out_str(T_MD);
+ else if (aep != NULL && cterm_normal_fg_bold && (
+#ifdef FEAT_TERMGUICOLORS
+ p_tgc && aep->ae_u.cterm.fg_rgb != CTERMCOLOR
+ ? aep->ae_u.cterm.fg_rgb != INVALCOLOR
+ :
+#endif
+ t_colors > 1 && aep->ae_u.cterm.fg_color))
+ /* If the Normal FG color has BOLD attribute and the new HL
+ * has a FG color defined, clear BOLD. */
+ out_str(T_ME);
+ if ((attr & HL_STANDOUT) && *T_SO != NUL) /* standout */
+ out_str(T_SO);
+ if ((attr & HL_UNDERCURL) && *T_UCS != NUL) /* undercurl */
+ out_str(T_UCS);
+ if (((attr & HL_UNDERLINE) /* underline or undercurl */
+ || ((attr & HL_UNDERCURL) && *T_UCS == NUL))
+ && *T_US != NUL)
+ out_str(T_US);
+ if ((attr & HL_ITALIC) && *T_CZH != NUL) /* italic */
+ out_str(T_CZH);
+ if ((attr & HL_INVERSE) && *T_MR != NUL) /* inverse (reverse) */
+ out_str(T_MR);
+ if ((attr & HL_STRIKETHROUGH) && *T_STS != NUL) /* strike */
+ out_str(T_STS);
+
+ /*
+ * Output the color or start string after bold etc., in case the
+ * bold etc. override the color setting.
+ */
+ if (aep != NULL)
+ {
+#ifdef FEAT_TERMGUICOLORS
+ /* When 'termguicolors' is set but fg or bg is unset,
+ * fall back to the cterm colors. This helps for SpellBad,
+ * where the GUI uses a red undercurl. */
+ if (p_tgc && aep->ae_u.cterm.fg_rgb != CTERMCOLOR)
+ {
+ if (aep->ae_u.cterm.fg_rgb != INVALCOLOR)
+ term_fg_rgb_color(aep->ae_u.cterm.fg_rgb);
+ }
+ else
+#endif
+ if (t_colors > 1)
+ {
+ if (aep->ae_u.cterm.fg_color)
+ term_fg_color(aep->ae_u.cterm.fg_color - 1);
+ }
+#ifdef FEAT_TERMGUICOLORS
+ if (p_tgc && aep->ae_u.cterm.bg_rgb != CTERMCOLOR)
+ {
+ if (aep->ae_u.cterm.bg_rgb != INVALCOLOR)
+ term_bg_rgb_color(aep->ae_u.cterm.bg_rgb);
+ }
+ else
+#endif
+ if (t_colors > 1)
+ {
+ if (aep->ae_u.cterm.bg_color)
+ term_bg_color(aep->ae_u.cterm.bg_color - 1);
+ }
+
+ if (!IS_CTERM)
+ {
+ if (aep->ae_u.term.start != NULL)
+ out_str(aep->ae_u.term.start);
+ }
+ }
+ }
+ }
+}
+
+ void
+screen_stop_highlight(void)
+{
+ int do_ME = FALSE; /* output T_ME code */
+
+ if (screen_attr != 0
+#ifdef WIN3264
+ && termcap_active
+#endif
+ )
+ {
+#ifdef FEAT_GUI
+ if (gui.in_use)
+ {
+ char buf[20];
+
+ /* use internal GUI code */
+ sprintf(buf, IF_EB("\033|%dH", ESC_STR "|%dH"), screen_attr);
+ OUT_STR(buf);
+ }
+ else
+#endif
+ {
+ if (screen_attr > HL_ALL) /* special HL attr. */
+ {
+ attrentry_T *aep;
+
+ if (IS_CTERM)
+ {
+ /*
+ * Assume that t_me restores the original colors!
+ */
+ aep = syn_cterm_attr2entry(screen_attr);
+ if (aep != NULL && ((
+#ifdef FEAT_TERMGUICOLORS
+ p_tgc && aep->ae_u.cterm.fg_rgb != CTERMCOLOR
+ ? aep->ae_u.cterm.fg_rgb != INVALCOLOR
+ :
+#endif
+ aep->ae_u.cterm.fg_color) || (
+#ifdef FEAT_TERMGUICOLORS
+ p_tgc && aep->ae_u.cterm.bg_rgb != CTERMCOLOR
+ ? aep->ae_u.cterm.bg_rgb != INVALCOLOR
+ :
+#endif
+ aep->ae_u.cterm.bg_color)))
+ do_ME = TRUE;
+ }
+ else
+ {
+ aep = syn_term_attr2entry(screen_attr);
+ if (aep != NULL && aep->ae_u.term.stop != NULL)
+ {
+ if (STRCMP(aep->ae_u.term.stop, T_ME) == 0)
+ do_ME = TRUE;
+ else
+ out_str(aep->ae_u.term.stop);
+ }
+ }
+ if (aep == NULL) /* did ":syntax clear" */
+ screen_attr = 0;
+ else
+ screen_attr = aep->ae_attr;
+ }
+
+ /*
+ * Often all ending-codes are equal to T_ME. Avoid outputting the
+ * same sequence several times.
+ */
+ if (screen_attr & HL_STANDOUT)
+ {
+ if (STRCMP(T_SE, T_ME) == 0)
+ do_ME = TRUE;
+ else
+ out_str(T_SE);
+ }
+ if ((screen_attr & HL_UNDERCURL) && *T_UCE != NUL)
+ {
+ if (STRCMP(T_UCE, T_ME) == 0)
+ do_ME = TRUE;
+ else
+ out_str(T_UCE);
+ }
+ if ((screen_attr & HL_UNDERLINE)
+ || ((screen_attr & HL_UNDERCURL) && *T_UCE == NUL))
+ {
+ if (STRCMP(T_UE, T_ME) == 0)
+ do_ME = TRUE;
+ else
+ out_str(T_UE);
+ }
+ if (screen_attr & HL_ITALIC)
+ {
+ if (STRCMP(T_CZR, T_ME) == 0)
+ do_ME = TRUE;
+ else
+ out_str(T_CZR);
+ }
+ if (screen_attr & HL_STRIKETHROUGH)
+ {
+ if (STRCMP(T_STE, T_ME) == 0)
+ do_ME = TRUE;
+ else
+ out_str(T_STE);
+ }
+ if (do_ME || (screen_attr & (HL_BOLD | HL_INVERSE)))
+ out_str(T_ME);
+
+#ifdef FEAT_TERMGUICOLORS
+ if (p_tgc)
+ {
+ if (cterm_normal_fg_gui_color != INVALCOLOR)
+ term_fg_rgb_color(cterm_normal_fg_gui_color);
+ if (cterm_normal_bg_gui_color != INVALCOLOR)
+ term_bg_rgb_color(cterm_normal_bg_gui_color);
+ }
+ else
+#endif
+ {
+ if (t_colors > 1)
+ {
+ /* set Normal cterm colors */
+ if (cterm_normal_fg_color != 0)
+ term_fg_color(cterm_normal_fg_color - 1);
+ if (cterm_normal_bg_color != 0)
+ term_bg_color(cterm_normal_bg_color - 1);
+ if (cterm_normal_fg_bold)
+ out_str(T_MD);
+ }
+ }
+ }
+ }
+ screen_attr = 0;
+}
+
+/*
+ * Reset the colors for a cterm. Used when leaving Vim.
+ * The machine specific code may override this again.
+ */
+ void
+reset_cterm_colors(void)
+{
+ if (IS_CTERM)
+ {
+ /* set Normal cterm colors */
+#ifdef FEAT_TERMGUICOLORS
+ if (p_tgc ? (cterm_normal_fg_gui_color != INVALCOLOR
+ || cterm_normal_bg_gui_color != INVALCOLOR)
+ : (cterm_normal_fg_color > 0 || cterm_normal_bg_color > 0))
+#else
+ if (cterm_normal_fg_color > 0 || cterm_normal_bg_color > 0)
+#endif
+ {
+ out_str(T_OP);
+ screen_attr = -1;
+ }
+ if (cterm_normal_fg_bold)
+ {
+ out_str(T_ME);
+ screen_attr = -1;
+ }
+ }
+}
+
+/*
+ * Put character ScreenLines["off"] on the screen at position "row" and "col",
+ * using the attributes from ScreenAttrs["off"].
+ */
+ static void
+screen_char(unsigned off, int row, int col)
+{
+ int attr;
+
+ /* Check for illegal values, just in case (could happen just after
+ * resizing). */
+ if (row >= screen_Rows || col >= screen_Columns)
+ return;
+
+#ifdef FEAT_INS_EXPAND
+ if (pum_under_menu(row, col))
+ return;
+#endif
+ /* Outputting a character in the last cell on the screen may scroll the
+ * screen up. Only do it when the "xn" termcap property is set, otherwise
+ * mark the character invalid (update it when scrolled up). */
+ if (*T_XN == NUL
+ && row == screen_Rows - 1 && col == screen_Columns - 1
+#ifdef FEAT_RIGHTLEFT
+ /* account for first command-line character in rightleft mode */
+ && !cmdmsg_rl
+#endif
+ )
+ {
+ ScreenAttrs[off] = (sattr_T)-1;
+ return;
+ }
+
+ /*
+ * Stop highlighting first, so it's easier to move the cursor.
+ */
+ if (screen_char_attr != 0)
+ attr = screen_char_attr;
+ else
+ attr = ScreenAttrs[off];
+ if (screen_attr != attr)
+ screen_stop_highlight();
+
+ windgoto(row, col);
+
+ if (screen_attr != attr)
+ screen_start_highlight(attr);
+
+ if (enc_utf8 && ScreenLinesUC[off] != 0)
+ {
+ char_u buf[MB_MAXBYTES + 1];
+
+ if (utf_ambiguous_width(ScreenLinesUC[off]))
+ {
+ if (*p_ambw == 'd'
+#ifdef FEAT_GUI
+ && !gui.in_use
+#endif
+ )
+ {
+ /* Clear the two screen cells. If the character is actually
+ * single width it won't change the second cell. */
+ out_str((char_u *)" ");
+ term_windgoto(row, col);
+ }
+ /* not sure where the cursor is after drawing the ambiguous width
+ * character */
+ screen_cur_col = 9999;
+ }
+ else if (utf_char2cells(ScreenLinesUC[off]) > 1)
+ ++screen_cur_col;
+
+ /* Convert the UTF-8 character to bytes and write it. */
+ buf[utfc_char2bytes(off, buf)] = NUL;
+ out_str(buf);
+ }
+ else
+ {
+ out_flush_check();
+ out_char(ScreenLines[off]);
+ /* double-byte character in single-width cell */
+ if (enc_dbcs == DBCS_JPNU && ScreenLines[off] == 0x8e)
+ out_char(ScreenLines2[off]);
+ }
+
+ screen_cur_col++;
+}
+
+/*
+ * Used for enc_dbcs only: Put one double-wide character at ScreenLines["off"]
+ * on the screen at position 'row' and 'col'.
+ * The attributes of the first byte is used for all. This is required to
+ * output the two bytes of a double-byte character with nothing in between.
+ */
+ static void
+screen_char_2(unsigned off, int row, int col)
+{
+ /* Check for illegal values (could be wrong when screen was resized). */
+ if (off + 1 >= (unsigned)(screen_Rows * screen_Columns))
+ return;
+
+ /* Outputting the last character on the screen may scrollup the screen.
+ * Don't to it! Mark the character invalid (update it when scrolled up) */
+ if (row == screen_Rows - 1 && col >= screen_Columns - 2)
+ {
+ ScreenAttrs[off] = (sattr_T)-1;
+ return;
+ }
+
+ /* Output the first byte normally (positions the cursor), then write the
+ * second byte directly. */
+ screen_char(off, row, col);
+ out_char(ScreenLines[off + 1]);
+ ++screen_cur_col;
+}
+
+/*
+ * Draw a rectangle of the screen, inverted when "invert" is TRUE.
+ * This uses the contents of ScreenLines[] and doesn't change it.
+ */
+ void
+screen_draw_rectangle(
+ int row,
+ int col,
+ int height,
+ int width,
+ int invert)
+{
+ int r, c;
+ int off;
+ int max_off;
+
+ /* Can't use ScreenLines unless initialized */
+ if (ScreenLines == NULL)
+ return;
+
+ if (invert)
+ screen_char_attr = HL_INVERSE;
+ for (r = row; r < row + height; ++r)
+ {
+ off = LineOffset[r];
+ max_off = off + screen_Columns;
+ for (c = col; c < col + width; ++c)
+ {
+ if (enc_dbcs != 0 && dbcs_off2cells(off + c, max_off) > 1)
+ {
+ screen_char_2(off + c, r, c);
+ ++c;
+ }
+ else
+ {
+ screen_char(off + c, r, c);
+ if (utf_off2cells(off + c, max_off) > 1)
+ ++c;
+ }
+ }
+ }
+ screen_char_attr = 0;
+}
+
+/*
+ * Redraw the characters for a vertically split window.
+ */
+ static void
+redraw_block(int row, int end, win_T *wp)
+{
+ int col;
+ int width;
+
+# ifdef FEAT_CLIPBOARD
+ clip_may_clear_selection(row, end - 1);
+# endif
+
+ if (wp == NULL)
+ {
+ col = 0;
+ width = Columns;
+ }
+ else
+ {
+ col = wp->w_wincol;
+ width = wp->w_width;
+ }
+ screen_draw_rectangle(row, col, end - row, width, FALSE);
+}
+
+ static void
+space_to_screenline(int off, int attr)
+{
+ ScreenLines[off] = ' ';
+ ScreenAttrs[off] = attr;
+ if (enc_utf8)
+ ScreenLinesUC[off] = 0;
+}
+
+/*
+ * Fill the screen from 'start_row' to 'end_row', from 'start_col' to 'end_col'
+ * with character 'c1' in first column followed by 'c2' in the other columns.
+ * Use attributes 'attr'.
+ */
+ void
+screen_fill(
+ int start_row,
+ int end_row,
+ int start_col,
+ int end_col,
+ int c1,
+ int c2,
+ int attr)
+{
+ int row;
+ int col;
+ int off;
+ int end_off;
+ int did_delete;
+ int c;
+ int norm_term;
+#if defined(FEAT_GUI) || defined(UNIX)
+ int force_next = FALSE;
+#endif
+
+ if (end_row > screen_Rows) /* safety check */
+ end_row = screen_Rows;
+ if (end_col > screen_Columns) /* safety check */
+ end_col = screen_Columns;
+ if (ScreenLines == NULL
+ || start_row >= end_row
+ || start_col >= end_col) /* nothing to do */
+ return;
+
+ /* it's a "normal" terminal when not in a GUI or cterm */
+ norm_term = (
+#ifdef FEAT_GUI
+ !gui.in_use &&
+#endif
+ !IS_CTERM);
+ for (row = start_row; row < end_row; ++row)
+ {
+ if (has_mbyte
+#ifdef FEAT_GUI
+ && !gui.in_use
+#endif
+ )
+ {
+ /* When drawing over the right halve of a double-wide char clear
+ * out the left halve. When drawing over the left halve of a
+ * double wide-char clear out the right halve. Only needed in a
+ * terminal. */
+ if (start_col > 0 && mb_fix_col(start_col, row) != start_col)
+ screen_puts_len((char_u *)" ", 1, row, start_col - 1, 0);
+ if (end_col < screen_Columns && mb_fix_col(end_col, row) != end_col)
+ screen_puts_len((char_u *)" ", 1, row, end_col, 0);
+ }
+ /*
+ * Try to use delete-line termcap code, when no attributes or in a
+ * "normal" terminal, where a bold/italic space is just a
+ * space.
+ */
+ did_delete = FALSE;
+ if (c2 == ' '
+ && end_col == Columns
+ && can_clear(T_CE)
+ && (attr == 0
+ || (norm_term
+ && attr <= HL_ALL
+ && ((attr & ~(HL_BOLD | HL_ITALIC)) == 0))))
+ {
+ /*
+ * check if we really need to clear something
+ */
+ col = start_col;
+ if (c1 != ' ') /* don't clear first char */
+ ++col;
+
+ off = LineOffset[row] + col;
+ end_off = LineOffset[row] + end_col;
+
+ /* skip blanks (used often, keep it fast!) */
+ if (enc_utf8)
+ while (off < end_off && ScreenLines[off] == ' '
+ && ScreenAttrs[off] == 0 && ScreenLinesUC[off] == 0)
+ ++off;
+ else
+ while (off < end_off && ScreenLines[off] == ' '
+ && ScreenAttrs[off] == 0)
+ ++off;
+ if (off < end_off) /* something to be cleared */
+ {
+ col = off - LineOffset[row];
+ screen_stop_highlight();
+ term_windgoto(row, col);/* clear rest of this screen line */
+ out_str(T_CE);
+ screen_start(); /* don't know where cursor is now */
+ col = end_col - col;
+ while (col--) /* clear chars in ScreenLines */
+ {
+ space_to_screenline(off, 0);
+ ++off;
+ }
+ }
+ did_delete = TRUE; /* the chars are cleared now */
+ }
+
+ off = LineOffset[row] + start_col;
+ c = c1;
+ for (col = start_col; col < end_col; ++col)
+ {
+ if (ScreenLines[off] != c
+ || (enc_utf8 && (int)ScreenLinesUC[off]
+ != (c >= 0x80 ? c : 0))
+ || ScreenAttrs[off] != attr
+#if defined(FEAT_GUI) || defined(UNIX)
+ || force_next
+#endif
+ )
+ {
+#if defined(FEAT_GUI) || defined(UNIX)
+ /* The bold trick may make a single row of pixels appear in
+ * the next character. When a bold character is removed, the
+ * next character should be redrawn too. This happens for our
+ * own GUI and for some xterms. */
+ if (
+# ifdef FEAT_GUI
+ gui.in_use
+# endif
+# if defined(FEAT_GUI) && defined(UNIX)
+ ||
+# endif
+# ifdef UNIX
+ term_is_xterm
+# endif
+ )
+ {
+ if (ScreenLines[off] != ' '
+ && (ScreenAttrs[off] > HL_ALL
+ || ScreenAttrs[off] & HL_BOLD))
+ force_next = TRUE;
+ else
+ force_next = FALSE;
+ }
+#endif
+ ScreenLines[off] = c;
+ if (enc_utf8)
+ {
+ if (c >= 0x80)
+ {
+ ScreenLinesUC[off] = c;
+ ScreenLinesC[0][off] = 0;
+ }
+ else
+ ScreenLinesUC[off] = 0;
+ }
+ ScreenAttrs[off] = attr;
+ if (!did_delete || c != ' ')
+ screen_char(off, row, col);
+ }
+ ++off;
+ if (col == start_col)
+ {
+ if (did_delete)
+ break;
+ c = c2;
+ }
+ }
+ if (end_col == Columns)
+ LineWraps[row] = FALSE;
+ if (row == Rows - 1) /* overwritten the command line */
+ {
+ redraw_cmdline = TRUE;
+ if (start_col == 0 && end_col == Columns
+ && c1 == ' ' && c2 == ' ' && attr == 0)
+ clear_cmdline = FALSE; /* command line has been cleared */
+ if (start_col == 0)
+ mode_displayed = FALSE; /* mode cleared or overwritten */
+ }
+ }
+}
+
+/*
+ * Check if there should be a delay. Used before clearing or redrawing the
+ * screen or the command line.
+ */
+ void
+check_for_delay(int check_msg_scroll)
+{
+ if ((emsg_on_display || (check_msg_scroll && msg_scroll))
+ && !did_wait_return
+ && emsg_silent == 0)
+ {
+ out_flush();
+ ui_delay(1000L, TRUE);
+ emsg_on_display = FALSE;
+ if (check_msg_scroll)
+ msg_scroll = FALSE;
+ }
+}
+
+/*
+ * screen_valid - allocate screen buffers if size changed
+ * If "doclear" is TRUE: clear screen if it has been resized.
+ * Returns TRUE if there is a valid screen to write to.
+ * Returns FALSE when starting up and screen not initialized yet.
+ */
+ int
+screen_valid(int doclear)
+{
+ screenalloc(doclear); /* allocate screen buffers if size changed */
+ return (ScreenLines != NULL);
+}
+
+/*
+ * Resize the shell to Rows and Columns.
+ * Allocate ScreenLines[] and associated items.
+ *
+ * There may be some time between setting Rows and Columns and (re)allocating
+ * ScreenLines[]. This happens when starting up and when (manually) changing
+ * the shell size. Always use screen_Rows and screen_Columns to access items
+ * in ScreenLines[]. Use Rows and Columns for positioning text etc. where the
+ * final size of the shell is needed.
+ */
+ void
+screenalloc(int doclear)
+{
+ int new_row, old_row;
+#ifdef FEAT_GUI
+ int old_Rows;
+#endif
+ win_T *wp;
+ int outofmem = FALSE;
+ int len;
+ schar_T *new_ScreenLines;
+ u8char_T *new_ScreenLinesUC = NULL;
+ u8char_T *new_ScreenLinesC[MAX_MCO];
+ schar_T *new_ScreenLines2 = NULL;
+ int i;
+ sattr_T *new_ScreenAttrs;
+ unsigned *new_LineOffset;
+ char_u *new_LineWraps;
+ short *new_TabPageIdxs;
+ tabpage_T *tp;
+ static int entered = FALSE; /* avoid recursiveness */
+ static int done_outofmem_msg = FALSE; /* did outofmem message */
+ int retry_count = 0;
+
+retry:
+ /*
+ * Allocation of the screen buffers is done only when the size changes and
+ * when Rows and Columns have been set and we have started doing full
+ * screen stuff.
+ */
+ if ((ScreenLines != NULL
+ && Rows == screen_Rows
+ && Columns == screen_Columns
+ && enc_utf8 == (ScreenLinesUC != NULL)
+ && (enc_dbcs == DBCS_JPNU) == (ScreenLines2 != NULL)
+ && p_mco == Screen_mco)
+ || Rows == 0
+ || Columns == 0
+ || (!full_screen && ScreenLines == NULL))
+ return;
+
+ /*
+ * It's possible that we produce an out-of-memory message below, which
+ * will cause this function to be called again. To break the loop, just
+ * return here.
+ */
+ if (entered)
+ return;
+ entered = TRUE;
+
+ /*
+ * Note that the window sizes are updated before reallocating the arrays,
+ * thus we must not redraw here!
+ */
+ ++RedrawingDisabled;
+
+ win_new_shellsize(); /* fit the windows in the new sized shell */
+
+ comp_col(); /* recompute columns for shown command and ruler */
+
+ /*
+ * We're changing the size of the screen.
+ * - Allocate new arrays for ScreenLines and ScreenAttrs.
+ * - Move lines from the old arrays into the new arrays, clear extra
+ * lines (unless the screen is going to be cleared).
+ * - Free the old arrays.
+ *
+ * If anything fails, make ScreenLines NULL, so we don't do anything!
+ * Continuing with the old ScreenLines may result in a crash, because the
+ * size is wrong.
+ */
+ FOR_ALL_TAB_WINDOWS(tp, wp)
+ win_free_lsize(wp);
+ if (aucmd_win != NULL)
+ win_free_lsize(aucmd_win);
+
+ new_ScreenLines = (schar_T *)lalloc((long_u)(
+ (Rows + 1) * Columns * sizeof(schar_T)), FALSE);
+ vim_memset(new_ScreenLinesC, 0, sizeof(u8char_T *) * MAX_MCO);
+ if (enc_utf8)
+ {
+ new_ScreenLinesUC = (u8char_T *)lalloc((long_u)(
+ (Rows + 1) * Columns * sizeof(u8char_T)), FALSE);
+ for (i = 0; i < p_mco; ++i)
+ new_ScreenLinesC[i] = (u8char_T *)lalloc_clear((long_u)(
+ (Rows + 1) * Columns * sizeof(u8char_T)), FALSE);
+ }
+ if (enc_dbcs == DBCS_JPNU)
+ new_ScreenLines2 = (schar_T *)lalloc((long_u)(
+ (Rows + 1) * Columns * sizeof(schar_T)), FALSE);
+ new_ScreenAttrs = (sattr_T *)lalloc((long_u)(
+ (Rows + 1) * Columns * sizeof(sattr_T)), FALSE);
+ new_LineOffset = (unsigned *)lalloc((long_u)(
+ Rows * sizeof(unsigned)), FALSE);
+ new_LineWraps = (char_u *)lalloc((long_u)(Rows * sizeof(char_u)), FALSE);
+ new_TabPageIdxs = (short *)lalloc((long_u)(Columns * sizeof(short)), FALSE);
+
+ FOR_ALL_TAB_WINDOWS(tp, wp)
+ {
+ if (win_alloc_lines(wp) == FAIL)
+ {
+ outofmem = TRUE;
+ goto give_up;
+ }
+ }
+ if (aucmd_win != NULL && aucmd_win->w_lines == NULL
+ && win_alloc_lines(aucmd_win) == FAIL)
+ outofmem = TRUE;
+give_up:
+
+ for (i = 0; i < p_mco; ++i)
+ if (new_ScreenLinesC[i] == NULL)
+ break;
+ if (new_ScreenLines == NULL
+ || (enc_utf8 && (new_ScreenLinesUC == NULL || i != p_mco))
+ || (enc_dbcs == DBCS_JPNU && new_ScreenLines2 == NULL)
+ || new_ScreenAttrs == NULL
+ || new_LineOffset == NULL
+ || new_LineWraps == NULL
+ || new_TabPageIdxs == NULL
+ || outofmem)
+ {
+ if (ScreenLines != NULL || !done_outofmem_msg)
+ {
+ /* guess the size */
+ do_outofmem_msg((long_u)((Rows + 1) * Columns));
+
+ /* Remember we did this to avoid getting outofmem messages over
+ * and over again. */
+ done_outofmem_msg = TRUE;
+ }
+ VIM_CLEAR(new_ScreenLines);
+ VIM_CLEAR(new_ScreenLinesUC);
+ for (i = 0; i < p_mco; ++i)
+ VIM_CLEAR(new_ScreenLinesC[i]);
+ VIM_CLEAR(new_ScreenLines2);
+ VIM_CLEAR(new_ScreenAttrs);
+ VIM_CLEAR(new_LineOffset);
+ VIM_CLEAR(new_LineWraps);
+ VIM_CLEAR(new_TabPageIdxs);
+ }
+ else
+ {
+ done_outofmem_msg = FALSE;
+
+ for (new_row = 0; new_row < Rows; ++new_row)
+ {
+ new_LineOffset[new_row] = new_row * Columns;
+ new_LineWraps[new_row] = FALSE;
+
+ /*
+ * If the screen is not going to be cleared, copy as much as
+ * possible from the old screen to the new one and clear the rest
+ * (used when resizing the window at the "--more--" prompt or when
+ * executing an external command, for the GUI).
+ */
+ if (!doclear)
+ {
+ (void)vim_memset(new_ScreenLines + new_row * Columns,
+ ' ', (size_t)Columns * sizeof(schar_T));
+ if (enc_utf8)
+ {
+ (void)vim_memset(new_ScreenLinesUC + new_row * Columns,
+ 0, (size_t)Columns * sizeof(u8char_T));
+ for (i = 0; i < p_mco; ++i)
+ (void)vim_memset(new_ScreenLinesC[i]
+ + new_row * Columns,
+ 0, (size_t)Columns * sizeof(u8char_T));
+ }
+ if (enc_dbcs == DBCS_JPNU)
+ (void)vim_memset(new_ScreenLines2 + new_row * Columns,
+ 0, (size_t)Columns * sizeof(schar_T));
+ (void)vim_memset(new_ScreenAttrs + new_row * Columns,
+ 0, (size_t)Columns * sizeof(sattr_T));
+ old_row = new_row + (screen_Rows - Rows);
+ if (old_row >= 0 && ScreenLines != NULL)
+ {
+ if (screen_Columns < Columns)
+ len = screen_Columns;
+ else
+ len = Columns;
+ /* When switching to utf-8 don't copy characters, they
+ * may be invalid now. Also when p_mco changes. */
+ if (!(enc_utf8 && ScreenLinesUC == NULL)
+ && p_mco == Screen_mco)
+ mch_memmove(new_ScreenLines + new_LineOffset[new_row],
+ ScreenLines + LineOffset[old_row],
+ (size_t)len * sizeof(schar_T));
+ if (enc_utf8 && ScreenLinesUC != NULL
+ && p_mco == Screen_mco)
+ {
+ mch_memmove(new_ScreenLinesUC + new_LineOffset[new_row],
+ ScreenLinesUC + LineOffset[old_row],
+ (size_t)len * sizeof(u8char_T));
+ for (i = 0; i < p_mco; ++i)
+ mch_memmove(new_ScreenLinesC[i]
+ + new_LineOffset[new_row],
+ ScreenLinesC[i] + LineOffset[old_row],
+ (size_t)len * sizeof(u8char_T));
+ }
+ if (enc_dbcs == DBCS_JPNU && ScreenLines2 != NULL)
+ mch_memmove(new_ScreenLines2 + new_LineOffset[new_row],
+ ScreenLines2 + LineOffset[old_row],
+ (size_t)len * sizeof(schar_T));
+ mch_memmove(new_ScreenAttrs + new_LineOffset[new_row],
+ ScreenAttrs + LineOffset[old_row],
+ (size_t)len * sizeof(sattr_T));
+ }
+ }
+ }
+ /* Use the last line of the screen for the current line. */
+ current_ScreenLine = new_ScreenLines + Rows * Columns;
+ }
+
+ free_screenlines();
+
+ ScreenLines = new_ScreenLines;
+ ScreenLinesUC = new_ScreenLinesUC;
+ for (i = 0; i < p_mco; ++i)
+ ScreenLinesC[i] = new_ScreenLinesC[i];
+ Screen_mco = p_mco;
+ ScreenLines2 = new_ScreenLines2;
+ ScreenAttrs = new_ScreenAttrs;
+ LineOffset = new_LineOffset;
+ LineWraps = new_LineWraps;
+ TabPageIdxs = new_TabPageIdxs;
+
+ /* It's important that screen_Rows and screen_Columns reflect the actual
+ * size of ScreenLines[]. Set them before calling anything. */
+#ifdef FEAT_GUI
+ old_Rows = screen_Rows;
+#endif
+ screen_Rows = Rows;
+ screen_Columns = Columns;
+
+ must_redraw = CLEAR; /* need to clear the screen later */
+ if (doclear)
+ screenclear2();
+
+#ifdef FEAT_GUI
+ else if (gui.in_use
+ && !gui.starting
+ && ScreenLines != NULL
+ && old_Rows != Rows)
+ {
+ (void)gui_redraw_block(0, 0, (int)Rows - 1, (int)Columns - 1, 0);
+ /*
+ * Adjust the position of the cursor, for when executing an external
+ * command.
+ */
+ if (msg_row >= Rows) /* Rows got smaller */
+ msg_row = Rows - 1; /* put cursor at last row */
+ else if (Rows > old_Rows) /* Rows got bigger */
+ msg_row += Rows - old_Rows; /* put cursor in same place */
+ if (msg_col >= Columns) /* Columns got smaller */
+ msg_col = Columns - 1; /* put cursor at last column */
+ }
+#endif
+
+ entered = FALSE;
+ --RedrawingDisabled;
+
+ /*
+ * Do not apply autocommands more than 3 times to avoid an endless loop
+ * in case applying autocommands always changes Rows or Columns.
+ */
+ if (starting == 0 && ++retry_count <= 3)
+ {
+ apply_autocmds(EVENT_VIMRESIZED, NULL, NULL, FALSE, curbuf);
+ /* In rare cases, autocommands may have altered Rows or Columns,
+ * jump back to check if we need to allocate the screen again. */
+ goto retry;
+ }
+}
+
+ void
+free_screenlines(void)
+{
+ int i;
+
+ vim_free(ScreenLinesUC);
+ for (i = 0; i < Screen_mco; ++i)
+ vim_free(ScreenLinesC[i]);
+ vim_free(ScreenLines2);
+ vim_free(ScreenLines);
+ vim_free(ScreenAttrs);
+ vim_free(LineOffset);
+ vim_free(LineWraps);
+ vim_free(TabPageIdxs);
+}
+
+ void
+screenclear(void)
+{
+ check_for_delay(FALSE);
+ screenalloc(FALSE); /* allocate screen buffers if size changed */
+ screenclear2(); /* clear the screen */
+}
+
+ static void
+screenclear2(void)
+{
+ int i;
+
+ if (starting == NO_SCREEN || ScreenLines == NULL
+#ifdef FEAT_GUI
+ || (gui.in_use && gui.starting)
+#endif
+ )
+ return;
+
+#ifdef FEAT_GUI
+ if (!gui.in_use)
+#endif
+ screen_attr = -1; /* force setting the Normal colors */
+ screen_stop_highlight(); /* don't want highlighting here */
+
+#ifdef FEAT_CLIPBOARD
+ /* disable selection without redrawing it */
+ clip_scroll_selection(9999);
+#endif
+
+ /* blank out ScreenLines */
+ for (i = 0; i < Rows; ++i)
+ {
+ lineclear(LineOffset[i], (int)Columns, 0);
+ LineWraps[i] = FALSE;
+ }
+
+ if (can_clear(T_CL))
+ {
+ out_str(T_CL); /* clear the display */
+ clear_cmdline = FALSE;
+ mode_displayed = FALSE;
+ }
+ else
+ {
+ /* can't clear the screen, mark all chars with invalid attributes */
+ for (i = 0; i < Rows; ++i)
+ lineinvalid(LineOffset[i], (int)Columns);
+ clear_cmdline = TRUE;
+ }
+
+ screen_cleared = TRUE; /* can use contents of ScreenLines now */
+
+ win_rest_invalid(firstwin);
+ redraw_cmdline = TRUE;
+ redraw_tabline = TRUE;
+ if (must_redraw == CLEAR) /* no need to clear again */
+ must_redraw = NOT_VALID;
+ compute_cmdrow();
+ msg_row = cmdline_row; /* put cursor on last line for messages */
+ msg_col = 0;
+ screen_start(); /* don't know where cursor is now */
+ msg_scrolled = 0; /* can't scroll back */
+ msg_didany = FALSE;
+ msg_didout = FALSE;
+}
+
+/*
+ * Clear one line in ScreenLines.
+ */
+ static void
+lineclear(unsigned off, int width, int attr)
+{
+ (void)vim_memset(ScreenLines + off, ' ', (size_t)width * sizeof(schar_T));
+ if (enc_utf8)
+ (void)vim_memset(ScreenLinesUC + off, 0,
+ (size_t)width * sizeof(u8char_T));
+ (void)vim_memset(ScreenAttrs + off, attr, (size_t)width * sizeof(sattr_T));
+}
+
+/*
+ * Mark one line in ScreenLines invalid by setting the attributes to an
+ * invalid value.
+ */
+ static void
+lineinvalid(unsigned off, int width)
+{
+ (void)vim_memset(ScreenAttrs + off, -1, (size_t)width * sizeof(sattr_T));
+}
+
+/*
+ * Copy part of a Screenline for vertically split window "wp".
+ */
+ static void
+linecopy(int to, int from, win_T *wp)
+{
+ unsigned off_to = LineOffset[to] + wp->w_wincol;
+ unsigned off_from = LineOffset[from] + wp->w_wincol;
+
+ mch_memmove(ScreenLines + off_to, ScreenLines + off_from,
+ wp->w_width * sizeof(schar_T));
+ if (enc_utf8)
+ {
+ int i;
+
+ mch_memmove(ScreenLinesUC + off_to, ScreenLinesUC + off_from,
+ wp->w_width * sizeof(u8char_T));
+ for (i = 0; i < p_mco; ++i)
+ mch_memmove(ScreenLinesC[i] + off_to, ScreenLinesC[i] + off_from,
+ wp->w_width * sizeof(u8char_T));
+ }
+ if (enc_dbcs == DBCS_JPNU)
+ mch_memmove(ScreenLines2 + off_to, ScreenLines2 + off_from,
+ wp->w_width * sizeof(schar_T));
+ mch_memmove(ScreenAttrs + off_to, ScreenAttrs + off_from,
+ wp->w_width * sizeof(sattr_T));
+}
+
+/*
+ * Return TRUE if clearing with term string "p" would work.
+ * It can't work when the string is empty or it won't set the right background.
+ */
+ int
+can_clear(char_u *p)
+{
+ return (*p != NUL && (t_colors <= 1
+#ifdef FEAT_GUI
+ || gui.in_use
+#endif
+#ifdef FEAT_TERMGUICOLORS
+ || (p_tgc && cterm_normal_bg_gui_color == INVALCOLOR)
+ || (!p_tgc && cterm_normal_bg_color == 0)
+#else
+ || cterm_normal_bg_color == 0
+#endif
+ || *T_UT != NUL));
+}
+
+/*
+ * Reset cursor position. Use whenever cursor was moved because of outputting
+ * something directly to the screen (shell commands) or a terminal control
+ * code.
+ */
+ void
+screen_start(void)
+{
+ screen_cur_row = screen_cur_col = 9999;
+}
+
+/*
+ * Move the cursor to position "row","col" in the screen.
+ * This tries to find the most efficient way to move, minimizing the number of
+ * characters sent to the terminal.
+ */
+ void
+windgoto(int row, int col)
+{
+ sattr_T *p;
+ int i;
+ int plan;
+ int cost;
+ int wouldbe_col;
+ int noinvcurs;
+ char_u *bs;
+ int goto_cost;
+ int attr;
+
+#define GOTO_COST 7 /* assume a term_windgoto() takes about 7 chars */
+#define HIGHL_COST 5 /* assume unhighlight takes 5 chars */
+
+#define PLAN_LE 1
+#define PLAN_CR 2
+#define PLAN_NL 3
+#define PLAN_WRITE 4
+ /* Can't use ScreenLines unless initialized */
+ if (ScreenLines == NULL)
+ return;
+
+ if (col != screen_cur_col || row != screen_cur_row)
+ {
+ /* Check for valid position. */
+ if (row < 0) /* window without text lines? */
+ row = 0;
+ if (row >= screen_Rows)
+ row = screen_Rows - 1;
+ if (col >= screen_Columns)
+ col = screen_Columns - 1;
+
+ /* check if no cursor movement is allowed in highlight mode */
+ if (screen_attr && *T_MS == NUL)
+ noinvcurs = HIGHL_COST;
+ else
+ noinvcurs = 0;
+ goto_cost = GOTO_COST + noinvcurs;
+
+ /*
+ * Plan how to do the positioning:
+ * 1. Use CR to move it to column 0, same row.
+ * 2. Use T_LE to move it a few columns to the left.
+ * 3. Use NL to move a few lines down, column 0.
+ * 4. Move a few columns to the right with T_ND or by writing chars.
+ *
+ * Don't do this if the cursor went beyond the last column, the cursor
+ * position is unknown then (some terminals wrap, some don't )
+ *
+ * First check if the highlighting attributes allow us to write
+ * characters to move the cursor to the right.
+ */
+ if (row >= screen_cur_row && screen_cur_col < Columns)
+ {
+ /*
+ * If the cursor is in the same row, bigger col, we can use CR
+ * or T_LE.
+ */
+ bs = NULL; /* init for GCC */
+ attr = screen_attr;
+ if (row == screen_cur_row && col < screen_cur_col)
+ {
+ /* "le" is preferred over "bc", because "bc" is obsolete */
+ if (*T_LE)
+ bs = T_LE; /* "cursor left" */
+ else
+ bs = T_BC; /* "backspace character (old) */
+ if (*bs)
+ cost = (screen_cur_col - col) * (int)STRLEN(bs);
+ else
+ cost = 999;
+ if (col + 1 < cost) /* using CR is less characters */
+ {
+ plan = PLAN_CR;
+ wouldbe_col = 0;
+ cost = 1; /* CR is just one character */
+ }
+ else
+ {
+ plan = PLAN_LE;
+ wouldbe_col = col;
+ }
+ if (noinvcurs) /* will stop highlighting */
+ {
+ cost += noinvcurs;
+ attr = 0;
+ }
+ }
+
+ /*
+ * If the cursor is above where we want to be, we can use CR LF.
+ */
+ else if (row > screen_cur_row)
+ {
+ plan = PLAN_NL;
+ wouldbe_col = 0;
+ cost = (row - screen_cur_row) * 2; /* CR LF */
+ if (noinvcurs) /* will stop highlighting */
+ {
+ cost += noinvcurs;
+ attr = 0;
+ }
+ }
+
+ /*
+ * If the cursor is in the same row, smaller col, just use write.
+ */
+ else
+ {
+ plan = PLAN_WRITE;
+ wouldbe_col = screen_cur_col;
+ cost = 0;
+ }
+
+ /*
+ * Check if any characters that need to be written have the
+ * correct attributes. Also avoid UTF-8 characters.
+ */
+ i = col - wouldbe_col;
+ if (i > 0)
+ cost += i;
+ if (cost < goto_cost && i > 0)
+ {
+ /*
+ * Check if the attributes are correct without additionally
+ * stopping highlighting.
+ */
+ p = ScreenAttrs + LineOffset[row] + wouldbe_col;
+ while (i && *p++ == attr)
+ --i;
+ if (i != 0)
+ {
+ /*
+ * Try if it works when highlighting is stopped here.
+ */
+ if (*--p == 0)
+ {
+ cost += noinvcurs;
+ while (i && *p++ == 0)
+ --i;
+ }
+ if (i != 0)
+ cost = 999; /* different attributes, don't do it */
+ }
+ if (enc_utf8)
+ {
+ /* Don't use an UTF-8 char for positioning, it's slow. */
+ for (i = wouldbe_col; i < col; ++i)
+ if (ScreenLinesUC[LineOffset[row] + i] != 0)
+ {
+ cost = 999;
+ break;
+ }
+ }
+ }
+
+ /*
+ * We can do it without term_windgoto()!
+ */
+ if (cost < goto_cost)
+ {
+ if (plan == PLAN_LE)
+ {
+ if (noinvcurs)
+ screen_stop_highlight();
+ while (screen_cur_col > col)
+ {
+ out_str(bs);
+ --screen_cur_col;
+ }
+ }
+ else if (plan == PLAN_CR)
+ {
+ if (noinvcurs)
+ screen_stop_highlight();
+ out_char('\r');
+ screen_cur_col = 0;
+ }
+ else if (plan == PLAN_NL)
+ {
+ if (noinvcurs)
+ screen_stop_highlight();
+ while (screen_cur_row < row)
+ {
+ out_char('\n');
+ ++screen_cur_row;
+ }
+ screen_cur_col = 0;
+ }
+
+ i = col - screen_cur_col;
+ if (i > 0)
+ {
+ /*
+ * Use cursor-right if it's one character only. Avoids
+ * removing a line of pixels from the last bold char, when
+ * using the bold trick in the GUI.
+ */
+ if (T_ND[0] != NUL && T_ND[1] == NUL)
+ {
+ while (i-- > 0)
+ out_char(*T_ND);
+ }
+ else
+ {
+ int off;
+
+ off = LineOffset[row] + screen_cur_col;
+ while (i-- > 0)
+ {
+ if (ScreenAttrs[off] != screen_attr)
+ screen_stop_highlight();
+ out_flush_check();
+ out_char(ScreenLines[off]);
+ if (enc_dbcs == DBCS_JPNU
+ && ScreenLines[off] == 0x8e)
+ out_char(ScreenLines2[off]);
+ ++off;
+ }
+ }
+ }
+ }
+ }
+ else
+ cost = 999;
+
+ if (cost >= goto_cost)
+ {
+ if (noinvcurs)
+ screen_stop_highlight();
+ if (row == screen_cur_row && (col > screen_cur_col)
+ && *T_CRI != NUL)
+ term_cursor_right(col - screen_cur_col);
+ else
+ term_windgoto(row, col);
+ }
+ screen_cur_row = row;
+ screen_cur_col = col;
+ }
+}
+
+/*
+ * Set cursor to its position in the current window.
+ */
+ void
+setcursor(void)
+{
+ setcursor_mayforce(FALSE);
+}
+
+/*
+ * Set cursor to its position in the current window.
+ * When "force" is TRUE also when not redrawing.
+ */
+ void
+setcursor_mayforce(int force)
+{
+ if (force || redrawing())
+ {
+ validate_cursor();
+ windgoto(W_WINROW(curwin) + curwin->w_wrow,
+ curwin->w_wincol + (
+#ifdef FEAT_RIGHTLEFT
+ /* With 'rightleft' set and the cursor on a double-wide
+ * character, position it on the leftmost column. */
+ curwin->w_p_rl ? ((int)curwin->w_width - curwin->w_wcol
+ - ((has_mbyte
+ && (*mb_ptr2cells)(ml_get_cursor()) == 2
+ && vim_isprintc(gchar_cursor())) ? 2 : 1)) :
+#endif
+ curwin->w_wcol));
+ }
+}
+
+
+/*
+ * Insert 'line_count' lines at 'row' in window 'wp'.
+ * If 'invalid' is TRUE the wp->w_lines[].wl_lnum is invalidated.
+ * If 'mayclear' is TRUE the screen will be cleared if it is faster than
+ * scrolling.
+ * Returns FAIL if the lines are not inserted, OK for success.
+ */
+ int
+win_ins_lines(
+ win_T *wp,
+ int row,
+ int line_count,
+ int invalid,
+ int mayclear)
+{
+ int did_delete;
+ int nextrow;
+ int lastrow;
+ int retval;
+
+ if (invalid)
+ wp->w_lines_valid = 0;
+
+ if (wp->w_height < 5)
+ return FAIL;
+
+ if (line_count > wp->w_height - row)
+ line_count = wp->w_height - row;
+
+ retval = win_do_lines(wp, row, line_count, mayclear, FALSE, 0);
+ if (retval != MAYBE)
+ return retval;
+
+ /*
+ * If there is a next window or a status line, we first try to delete the
+ * lines at the bottom to avoid messing what is after the window.
+ * If this fails and there are following windows, don't do anything to avoid
+ * messing up those windows, better just redraw.
+ */
+ did_delete = FALSE;
+ if (wp->w_next != NULL || wp->w_status_height)
+ {
+ if (screen_del_lines(0, W_WINROW(wp) + wp->w_height - line_count,
+ line_count, (int)Rows, FALSE, 0, NULL) == OK)
+ did_delete = TRUE;
+ else if (wp->w_next)
+ return FAIL;
+ }
+ /*
+ * if no lines deleted, blank the lines that will end up below the window
+ */
+ if (!did_delete)
+ {
+ wp->w_redr_status = TRUE;
+ redraw_cmdline = TRUE;
+ nextrow = W_WINROW(wp) + wp->w_height + wp->w_status_height;
+ lastrow = nextrow + line_count;
+ if (lastrow > Rows)
+ lastrow = Rows;
+ screen_fill(nextrow - line_count, lastrow - line_count,
+ wp->w_wincol, (int)W_ENDCOL(wp),
+ ' ', ' ', 0);
+ }
+
+ if (screen_ins_lines(0, W_WINROW(wp) + row, line_count, (int)Rows, 0, NULL)
+ == FAIL)
+ {
+ /* deletion will have messed up other windows */
+ if (did_delete)
+ {
+ wp->w_redr_status = TRUE;
+ win_rest_invalid(W_NEXT(wp));
+ }
+ return FAIL;
+ }
+
+ return OK;
+}
+
+/*
+ * Delete "line_count" window lines at "row" in window "wp".
+ * If "invalid" is TRUE curwin->w_lines[] is invalidated.
+ * If "mayclear" is TRUE the screen will be cleared if it is faster than
+ * scrolling
+ * Return OK for success, FAIL if the lines are not deleted.
+ */
+ int
+win_del_lines(
+ win_T *wp,
+ int row,
+ int line_count,
+ int invalid,
+ int mayclear,
+ int clear_attr) /* for clearing lines */
+{
+ int retval;
+
+ if (invalid)
+ wp->w_lines_valid = 0;
+
+ if (line_count > wp->w_height - row)
+ line_count = wp->w_height - row;
+
+ retval = win_do_lines(wp, row, line_count, mayclear, TRUE, clear_attr);
+ if (retval != MAYBE)
+ return retval;
+
+ if (screen_del_lines(0, W_WINROW(wp) + row, line_count,
+ (int)Rows, FALSE, clear_attr, NULL) == FAIL)
+ return FAIL;
+
+ /*
+ * If there are windows or status lines below, try to put them at the
+ * correct place. If we can't do that, they have to be redrawn.
+ */
+ if (wp->w_next || wp->w_status_height || cmdline_row < Rows - 1)
+ {
+ if (screen_ins_lines(0, W_WINROW(wp) + wp->w_height - line_count,
+ line_count, (int)Rows, clear_attr, NULL) == FAIL)
+ {
+ wp->w_redr_status = TRUE;
+ win_rest_invalid(wp->w_next);
+ }
+ }
+ /*
+ * If this is the last window and there is no status line, redraw the
+ * command line later.
+ */
+ else
+ redraw_cmdline = TRUE;
+ return OK;
+}
+
+/*
+ * Common code for win_ins_lines() and win_del_lines().
+ * Returns OK or FAIL when the work has been done.
+ * Returns MAYBE when not finished yet.
+ */
+ static int
+win_do_lines(
+ win_T *wp,
+ int row,
+ int line_count,
+ int mayclear,
+ int del,
+ int clear_attr)
+{
+ int retval;
+
+ if (!redrawing() || line_count <= 0)
+ return FAIL;
+
+ /* When inserting lines would result in loss of command output, just redraw
+ * the lines. */
+ if (no_win_do_lines_ins && !del)
+ return FAIL;
+
+ /* only a few lines left: redraw is faster */
+ if (mayclear && Rows - line_count < 5 && wp->w_width == Columns)
+ {
+ if (!no_win_do_lines_ins)
+ screenclear(); /* will set wp->w_lines_valid to 0 */
+ return FAIL;
+ }
+
+ /*
+ * Delete all remaining lines
+ */
+ if (row + line_count >= wp->w_height)
+ {
+ screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + wp->w_height,
+ wp->w_wincol, (int)W_ENDCOL(wp),
+ ' ', ' ', 0);
+ return OK;
+ }
+
+ /*
+ * When scrolling, the message on the command line should be cleared,
+ * otherwise it will stay there forever.
+ * Don't do this when avoiding to insert lines.
+ */
+ if (!no_win_do_lines_ins)
+ clear_cmdline = TRUE;
+
+ /*
+ * If the terminal can set a scroll region, use that.
+ * Always do this in a vertically split window. This will redraw from
+ * ScreenLines[] when t_CV isn't defined. That's faster than using
+ * win_line().
+ * Don't use a scroll region when we are going to redraw the text, writing
+ * a character in the lower right corner of the scroll region may cause a
+ * scroll-up .
+ */
+ if (scroll_region || wp->w_width != Columns)
+ {
+ if (scroll_region && (wp->w_width == Columns || *T_CSV != NUL))
+ scroll_region_set(wp, row);
+ if (del)
+ retval = screen_del_lines(W_WINROW(wp) + row, 0, line_count,
+ wp->w_height - row, FALSE, clear_attr, wp);
+ else
+ retval = screen_ins_lines(W_WINROW(wp) + row, 0, line_count,
+ wp->w_height - row, clear_attr, wp);
+ if (scroll_region && (wp->w_width == Columns || *T_CSV != NUL))
+ scroll_region_reset();
+ return retval;
+ }
+
+ if (wp->w_next != NULL && p_tf) /* don't delete/insert on fast terminal */
+ return FAIL;
+
+ return MAYBE;
+}
+
+/*
+ * window 'wp' and everything after it is messed up, mark it for redraw
+ */
+ static void
+win_rest_invalid(win_T *wp)
+{
+ while (wp != NULL)
+ {
+ redraw_win_later(wp, NOT_VALID);
+ wp->w_redr_status = TRUE;
+ wp = wp->w_next;
+ }
+ redraw_cmdline = TRUE;
+}
+
+/*
+ * The rest of the routines in this file perform screen manipulations. The
+ * given operation is performed physically on the screen. The corresponding
+ * change is also made to the internal screen image. In this way, the editor
+ * anticipates the effect of editing changes on the appearance of the screen.
+ * That way, when we call screenupdate a complete redraw isn't usually
+ * necessary. Another advantage is that we can keep adding code to anticipate
+ * screen changes, and in the meantime, everything still works.
+ */
+
+/*
+ * types for inserting or deleting lines
+ */
+#define USE_T_CAL 1
+#define USE_T_CDL 2
+#define USE_T_AL 3
+#define USE_T_CE 4
+#define USE_T_DL 5
+#define USE_T_SR 6
+#define USE_NL 7
+#define USE_T_CD 8
+#define USE_REDRAW 9
+
+/*
+ * insert lines on the screen and update ScreenLines[]
+ * 'end' is the line after the scrolled part. Normally it is Rows.
+ * When scrolling region used 'off' is the offset from the top for the region.
+ * 'row' and 'end' are relative to the start of the region.
+ *
+ * return FAIL for failure, OK for success.
+ */
+ int
+screen_ins_lines(
+ int off,
+ int row,
+ int line_count,
+ int end,
+ int clear_attr,
+ win_T *wp) /* NULL or window to use width from */
+{
+ int i;
+ int j;
+ unsigned temp;
+ int cursor_row;
+ int cursor_col = 0;
+ int type;
+ int result_empty;
+ int can_ce = can_clear(T_CE);
+
+ /*
+ * FAIL if
+ * - there is no valid screen
+ * - the screen has to be redrawn completely
+ * - the line count is less than one
+ * - the line count is more than 'ttyscroll'
+ * - redrawing for a callback and there is a modeless selection
+ */
+ if (!screen_valid(TRUE) || line_count <= 0 || line_count > p_ttyscroll
+#ifdef FEAT_CLIPBOARD
+ || (clip_star.state != SELECT_CLEARED
+ && redrawing_for_callback > 0)
+#endif
+ )
+ return FAIL;
+
+ /*
+ * There are seven ways to insert lines:
+ * 0. When in a vertically split window and t_CV isn't set, redraw the
+ * characters from ScreenLines[].
+ * 1. Use T_CD (clear to end of display) if it exists and the result of
+ * the insert is just empty lines
+ * 2. Use T_CAL (insert multiple lines) if it exists and T_AL is not
+ * present or line_count > 1. It looks better if we do all the inserts
+ * at once.
+ * 3. Use T_CDL (delete multiple lines) if it exists and the result of the
+ * insert is just empty lines and T_CE is not present or line_count >
+ * 1.
+ * 4. Use T_AL (insert line) if it exists.
+ * 5. Use T_CE (erase line) if it exists and the result of the insert is
+ * just empty lines.
+ * 6. Use T_DL (delete line) if it exists and the result of the insert is
+ * just empty lines.
+ * 7. Use T_SR (scroll reverse) if it exists and inserting at row 0 and
+ * the 'da' flag is not set or we have clear line capability.
+ * 8. redraw the characters from ScreenLines[].
+ *
+ * Careful: In a hpterm scroll reverse doesn't work as expected, it moves
+ * the scrollbar for the window. It does have insert line, use that if it
+ * exists.
+ */
+ result_empty = (row + line_count >= end);
+ if (wp != NULL && wp->w_width != Columns && *T_CSV == NUL)
+ type = USE_REDRAW;
+ else if (can_clear(T_CD) && result_empty)
+ type = USE_T_CD;
+ else if (*T_CAL != NUL && (line_count > 1 || *T_AL == NUL))
+ type = USE_T_CAL;
+ else if (*T_CDL != NUL && result_empty && (line_count > 1 || !can_ce))
+ type = USE_T_CDL;
+ else if (*T_AL != NUL)
+ type = USE_T_AL;
+ else if (can_ce && result_empty)
+ type = USE_T_CE;
+ else if (*T_DL != NUL && result_empty)
+ type = USE_T_DL;
+ else if (*T_SR != NUL && row == 0 && (*T_DA == NUL || can_ce))
+ type = USE_T_SR;
+ else
+ return FAIL;
+
+ /*
+ * For clearing the lines screen_del_lines() is used. This will also take
+ * care of t_db if necessary.
+ */
+ if (type == USE_T_CD || type == USE_T_CDL ||
+ type == USE_T_CE || type == USE_T_DL)
+ return screen_del_lines(off, row, line_count, end, FALSE, 0, wp);
+
+ /*
+ * If text is retained below the screen, first clear or delete as many
+ * lines at the bottom of the window as are about to be inserted so that
+ * the deleted lines won't later surface during a screen_del_lines.
+ */
+ if (*T_DB)
+ screen_del_lines(off, end - line_count, line_count, end, FALSE, 0, wp);
+
+#ifdef FEAT_CLIPBOARD
+ /* Remove a modeless selection when inserting lines halfway the screen
+ * or not the full width of the screen. */
+ if (off + row > 0 || (wp != NULL && wp->w_width != Columns))
+ clip_clear_selection(&clip_star);
+ else
+ clip_scroll_selection(-line_count);
+#endif
+
+#ifdef FEAT_GUI
+ /* Don't update the GUI cursor here, ScreenLines[] is invalid until the
+ * scrolling is actually carried out. */
+ gui_dont_update_cursor(row + off <= gui.cursor_row);
+#endif
+
+ if (wp != NULL && wp->w_wincol != 0 && *T_CSV != NUL && *T_CCS == NUL)
+ cursor_col = wp->w_wincol;
+
+ if (*T_CCS != NUL) /* cursor relative to region */
+ cursor_row = row;
+ else
+ cursor_row = row + off;
+
+ /*
+ * Shift LineOffset[] line_count down to reflect the inserted lines.
+ * Clear the inserted lines in ScreenLines[].
+ */
+ row += off;
+ end += off;
+ for (i = 0; i < line_count; ++i)
+ {
+ if (wp != NULL && wp->w_width != Columns)
+ {
+ /* need to copy part of a line */
+ j = end - 1 - i;
+ while ((j -= line_count) >= row)
+ linecopy(j + line_count, j, wp);
+ j += line_count;
+ if (can_clear((char_u *)" "))
+ lineclear(LineOffset[j] + wp->w_wincol, wp->w_width,
+ clear_attr);
+ else
+ lineinvalid(LineOffset[j] + wp->w_wincol, wp->w_width);
+ LineWraps[j] = FALSE;
+ }
+ else
+ {
+ j = end - 1 - i;
+ temp = LineOffset[j];
+ while ((j -= line_count) >= row)
+ {
+ LineOffset[j + line_count] = LineOffset[j];
+ LineWraps[j + line_count] = LineWraps[j];
+ }
+ LineOffset[j + line_count] = temp;
+ LineWraps[j + line_count] = FALSE;
+ if (can_clear((char_u *)" "))
+ lineclear(temp, (int)Columns, clear_attr);
+ else
+ lineinvalid(temp, (int)Columns);
+ }
+ }
+
+ screen_stop_highlight();
+ windgoto(cursor_row, cursor_col);
+ if (clear_attr != 0)
+ screen_start_highlight(clear_attr);
+
+ /* redraw the characters */
+ if (type == USE_REDRAW)
+ redraw_block(row, end, wp);
+ else if (type == USE_T_CAL)
+ {
+ term_append_lines(line_count);
+ screen_start(); /* don't know where cursor is now */
+ }
+ else
+ {
+ for (i = 0; i < line_count; i++)
+ {
+ if (type == USE_T_AL)
+ {
+ if (i && cursor_row != 0)
+ windgoto(cursor_row, cursor_col);
+ out_str(T_AL);
+ }
+ else /* type == USE_T_SR */
+ out_str(T_SR);
+ screen_start(); /* don't know where cursor is now */
+ }
+ }
+
+ /*
+ * With scroll-reverse and 'da' flag set we need to clear the lines that
+ * have been scrolled down into the region.
+ */
+ if (type == USE_T_SR && *T_DA)
+ {
+ for (i = 0; i < line_count; ++i)
+ {
+ windgoto(off + i, cursor_col);
+ out_str(T_CE);
+ screen_start(); /* don't know where cursor is now */
+ }
+ }
+
+#ifdef FEAT_GUI
+ gui_can_update_cursor();
+ if (gui.in_use)
+ out_flush(); /* always flush after a scroll */
+#endif
+ return OK;
+}
+
+/*
+ * Delete lines on the screen and update ScreenLines[].
+ * "end" is the line after the scrolled part. Normally it is Rows.
+ * When scrolling region used "off" is the offset from the top for the region.
+ * "row" and "end" are relative to the start of the region.
+ *
+ * Return OK for success, FAIL if the lines are not deleted.
+ */
+ int
+screen_del_lines(
+ int off,
+ int row,
+ int line_count,
+ int end,
+ int force, /* even when line_count > p_ttyscroll */
+ int clear_attr, /* used for clearing lines */
+ win_T *wp UNUSED) /* NULL or window to use width from */
+{
+ int j;
+ int i;
+ unsigned temp;
+ int cursor_row;
+ int cursor_col = 0;
+ int cursor_end;
+ int result_empty; /* result is empty until end of region */
+ int can_delete; /* deleting line codes can be used */
+ int type;
+
+ /*
+ * FAIL if
+ * - there is no valid screen
+ * - the screen has to be redrawn completely
+ * - the line count is less than one
+ * - the line count is more than 'ttyscroll'
+ * - redrawing for a callback and there is a modeless selection
+ */
+ if (!screen_valid(TRUE) || line_count <= 0
+ || (!force && line_count > p_ttyscroll)
+#ifdef FEAT_CLIPBOARD
+ || (clip_star.state != SELECT_CLEARED
+ && redrawing_for_callback > 0)
+#endif
+ )
+ return FAIL;
+
+ /*
+ * Check if the rest of the current region will become empty.
+ */
+ result_empty = row + line_count >= end;
+
+ /*
+ * We can delete lines only when 'db' flag not set or when 'ce' option
+ * available.
+ */
+ can_delete = (*T_DB == NUL || can_clear(T_CE));
+
+ /*
+ * There are six ways to delete lines:
+ * 0. When in a vertically split window and t_CV isn't set, redraw the
+ * characters from ScreenLines[].
+ * 1. Use T_CD if it exists and the result is empty.
+ * 2. Use newlines if row == 0 and count == 1 or T_CDL does not exist.
+ * 3. Use T_CDL (delete multiple lines) if it exists and line_count > 1 or
+ * none of the other ways work.
+ * 4. Use T_CE (erase line) if the result is empty.
+ * 5. Use T_DL (delete line) if it exists.
+ * 6. redraw the characters from ScreenLines[].
+ */
+ if (wp != NULL && wp->w_width != Columns && *T_CSV == NUL)
+ type = USE_REDRAW;
+ else if (can_clear(T_CD) && result_empty)
+ type = USE_T_CD;
+#if defined(__BEOS__) && defined(BEOS_DR8)
+ /*
+ * USE_NL does not seem to work in Terminal of DR8 so we set T_DB="" in
+ * its internal termcap... this works okay for tests which test *T_DB !=
+ * NUL. It has the disadvantage that the user cannot use any :set t_*
+ * command to get T_DB (back) to empty_option, only :set term=... will do
+ * the trick...
+ * Anyway, this hack will hopefully go away with the next OS release.
+ * (Olaf Seibert)
+ */
+ else if (row == 0 && T_DB == empty_option
+ && (line_count == 1 || *T_CDL == NUL))
+#else
+ else if (row == 0 && (
+#ifndef AMIGA
+ /* On the Amiga, somehow '\n' on the last line doesn't always scroll
+ * up, so use delete-line command */
+ line_count == 1 ||
+#endif
+ *T_CDL == NUL))
+#endif
+ type = USE_NL;
+ else if (*T_CDL != NUL && line_count > 1 && can_delete)
+ type = USE_T_CDL;
+ else if (can_clear(T_CE) && result_empty
+ && (wp == NULL || wp->w_width == Columns))
+ type = USE_T_CE;
+ else if (*T_DL != NUL && can_delete)
+ type = USE_T_DL;
+ else if (*T_CDL != NUL && can_delete)
+ type = USE_T_CDL;
+ else
+ return FAIL;
+
+#ifdef FEAT_CLIPBOARD
+ /* Remove a modeless selection when deleting lines halfway the screen or
+ * not the full width of the screen. */
+ if (off + row > 0 || (wp != NULL && wp->w_width != Columns))
+ clip_clear_selection(&clip_star);
+ else
+ clip_scroll_selection(line_count);
+#endif
+
+#ifdef FEAT_GUI
+ /* Don't update the GUI cursor here, ScreenLines[] is invalid until the
+ * scrolling is actually carried out. */
+ gui_dont_update_cursor(gui.cursor_row >= row + off
+ && gui.cursor_row < end + off);
+#endif
+
+ if (wp != NULL && wp->w_wincol != 0 && *T_CSV != NUL && *T_CCS == NUL)
+ cursor_col = wp->w_wincol;
+
+ if (*T_CCS != NUL) /* cursor relative to region */
+ {
+ cursor_row = row;
+ cursor_end = end;
+ }
+ else
+ {
+ cursor_row = row + off;
+ cursor_end = end + off;
+ }
+
+ /*
+ * Now shift LineOffset[] line_count up to reflect the deleted lines.
+ * Clear the inserted lines in ScreenLines[].
+ */
+ row += off;
+ end += off;
+ for (i = 0; i < line_count; ++i)
+ {
+ if (wp != NULL && wp->w_width != Columns)
+ {
+ /* need to copy part of a line */
+ j = row + i;
+ while ((j += line_count) <= end - 1)
+ linecopy(j - line_count, j, wp);
+ j -= line_count;
+ if (can_clear((char_u *)" "))
+ lineclear(LineOffset[j] + wp->w_wincol, wp->w_width,
+ clear_attr);
+ else
+ lineinvalid(LineOffset[j] + wp->w_wincol, wp->w_width);
+ LineWraps[j] = FALSE;
+ }
+ else
+ {
+ /* whole width, moving the line pointers is faster */
+ j = row + i;
+ temp = LineOffset[j];
+ while ((j += line_count) <= end - 1)
+ {
+ LineOffset[j - line_count] = LineOffset[j];
+ LineWraps[j - line_count] = LineWraps[j];
+ }
+ LineOffset[j - line_count] = temp;
+ LineWraps[j - line_count] = FALSE;
+ if (can_clear((char_u *)" "))
+ lineclear(temp, (int)Columns, clear_attr);
+ else
+ lineinvalid(temp, (int)Columns);
+ }
+ }
+
+ if (screen_attr != clear_attr)
+ screen_stop_highlight();
+ if (clear_attr != 0)
+ screen_start_highlight(clear_attr);
+
+ /* redraw the characters */
+ if (type == USE_REDRAW)
+ redraw_block(row, end, wp);
+ else if (type == USE_T_CD) /* delete the lines */
+ {
+ windgoto(cursor_row, cursor_col);
+ out_str(T_CD);
+ screen_start(); /* don't know where cursor is now */
+ }
+ else if (type == USE_T_CDL)
+ {
+ windgoto(cursor_row, cursor_col);
+ term_delete_lines(line_count);
+ screen_start(); /* don't know where cursor is now */
+ }
+ /*
+ * Deleting lines at top of the screen or scroll region: Just scroll
+ * the whole screen (scroll region) up by outputting newlines on the
+ * last line.
+ */
+ else if (type == USE_NL)
+ {
+ windgoto(cursor_end - 1, cursor_col);
+ for (i = line_count; --i >= 0; )
+ out_char('\n'); /* cursor will remain on same line */
+ }
+ else
+ {
+ for (i = line_count; --i >= 0; )
+ {
+ if (type == USE_T_DL)
+ {
+ windgoto(cursor_row, cursor_col);
+ out_str(T_DL); /* delete a line */
+ }
+ else /* type == USE_T_CE */
+ {
+ windgoto(cursor_row + i, cursor_col);
+ out_str(T_CE); /* erase a line */
+ }
+ screen_start(); /* don't know where cursor is now */
+ }
+ }
+
+ /*
+ * If the 'db' flag is set, we need to clear the lines that have been
+ * scrolled up at the bottom of the region.
+ */
+ if (*T_DB && (type == USE_T_DL || type == USE_T_CDL))
+ {
+ for (i = line_count; i > 0; --i)
+ {
+ windgoto(cursor_end - i, cursor_col);
+ out_str(T_CE); /* erase a line */
+ screen_start(); /* don't know where cursor is now */
+ }
+ }
+
+#ifdef FEAT_GUI
+ gui_can_update_cursor();
+ if (gui.in_use)
+ out_flush(); /* always flush after a scroll */
+#endif
+
+ return OK;
+}
+
+/*
+ * Return TRUE when postponing displaying the mode message: when not redrawing
+ * or inside a mapping.
+ */
+ int
+skip_showmode()
+{
+ // Call char_avail() only when we are going to show something, because it
+ // takes a bit of time. redrawing() may also call char_avail_avail().
+ if (global_busy
+ || msg_silent != 0
+ || !redrawing()
+ || (char_avail() && !KeyTyped))
+ {
+ redraw_cmdline = TRUE; // show mode later
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * Show the current mode and ruler.
+ *
+ * If clear_cmdline is TRUE, clear the rest of the cmdline.
+ * If clear_cmdline is FALSE there may be a message there that needs to be
+ * cleared only if a mode is shown.
+ * Return the length of the message (0 if no message).
+ */
+ int
+showmode(void)
+{
+ int need_clear;
+ int length = 0;
+ int do_mode;
+ int attr;
+ int nwr_save;
+#ifdef FEAT_INS_EXPAND
+ int sub_attr;
+#endif
+
+ do_mode = ((p_smd && msg_silent == 0)
+ && ((State & INSERT)
+ || restart_edit != NUL
+ || VIsual_active));
+ if (do_mode || reg_recording != 0)
+ {
+ if (skip_showmode())
+ return 0; // show mode later
+
+ nwr_save = need_wait_return;
+
+ /* wait a bit before overwriting an important message */
+ check_for_delay(FALSE);
+
+ /* if the cmdline is more than one line high, erase top lines */
+ need_clear = clear_cmdline;
+ if (clear_cmdline && cmdline_row < Rows - 1)
+ msg_clr_cmdline(); /* will reset clear_cmdline */
+
+ /* Position on the last line in the window, column 0 */
+ msg_pos_mode();
+ cursor_off();
+ attr = HL_ATTR(HLF_CM); /* Highlight mode */
+ if (do_mode)
+ {
+ msg_puts_attr("--", attr);
+#if defined(FEAT_XIM)
+ if (
+# ifdef FEAT_GUI_GTK
+ preedit_get_status()
+# else
+ im_get_status()
+# endif
+ )
+# ifdef FEAT_GUI_GTK /* most of the time, it's not XIM being used */
+ msg_puts_attr(" IM", attr);
+# else
+ msg_puts_attr(" XIM", attr);
+# endif
+#endif
+#if defined(FEAT_HANGULIN) && defined(FEAT_GUI)
+ if (gui.in_use)
+ {
+ if (hangul_input_state_get())
+ {
+ /* HANGUL */
+ if (enc_utf8)
+ msg_puts_attr(" \355\225\234\352\270\200", attr);
+ else
+ msg_puts_attr(" \307\321\261\333", attr);
+ }
+ }
+#endif
+#ifdef FEAT_INS_EXPAND
+ /* CTRL-X in Insert mode */
+ if (edit_submode != NULL && !shortmess(SHM_COMPLETIONMENU))
+ {
+ /* These messages can get long, avoid a wrap in a narrow
+ * window. Prefer showing edit_submode_extra. */
+ length = (Rows - msg_row) * Columns - 3;
+ if (edit_submode_extra != NULL)
+ length -= vim_strsize(edit_submode_extra);
+ if (length > 0)
+ {
+ if (edit_submode_pre != NULL)
+ length -= vim_strsize(edit_submode_pre);
+ if (length - vim_strsize(edit_submode) > 0)
+ {
+ if (edit_submode_pre != NULL)
+ msg_puts_attr((char *)edit_submode_pre, attr);
+ msg_puts_attr((char *)edit_submode, attr);
+ }
+ if (edit_submode_extra != NULL)
+ {
+ msg_puts_attr(" ", attr); /* add a space in between */
+ if ((int)edit_submode_highl < (int)HLF_COUNT)
+ sub_attr = HL_ATTR(edit_submode_highl);
+ else
+ sub_attr = attr;
+ msg_puts_attr((char *)edit_submode_extra, sub_attr);
+ }
+ }
+ }
+ else
+#endif
+ {
+ if (State & VREPLACE_FLAG)
+ msg_puts_attr(_(" VREPLACE"), attr);
+ else if (State & REPLACE_FLAG)
+ msg_puts_attr(_(" REPLACE"), attr);
+ else if (State & INSERT)
+ {
+#ifdef FEAT_RIGHTLEFT
+ if (p_ri)
+ msg_puts_attr(_(" REVERSE"), attr);
+#endif
+ msg_puts_attr(_(" INSERT"), attr);
+ }
+ else if (restart_edit == 'I' || restart_edit == 'A')
+ msg_puts_attr(_(" (insert)"), attr);
+ else if (restart_edit == 'R')
+ msg_puts_attr(_(" (replace)"), attr);
+ else if (restart_edit == 'V')
+ msg_puts_attr(_(" (vreplace)"), attr);
+#ifdef FEAT_RIGHTLEFT
+ if (p_hkmap)
+ msg_puts_attr(_(" Hebrew"), attr);
+# ifdef FEAT_FKMAP
+ if (p_fkmap)
+ msg_puts_attr(farsi_text_5, attr);
+# endif
+#endif
+#ifdef FEAT_KEYMAP
+ if (State & LANGMAP)
+ {
+# ifdef FEAT_ARABIC
+ if (curwin->w_p_arab)
+ msg_puts_attr(_(" Arabic"), attr);
+ else
+# endif
+ if (get_keymap_str(curwin, (char_u *)" (%s)",
+ NameBuff, MAXPATHL))
+ msg_puts_attr((char *)NameBuff, attr);
+ }
+#endif
+ if ((State & INSERT) && p_paste)
+ msg_puts_attr(_(" (paste)"), attr);
+
+ if (VIsual_active)
+ {
+ char *p;
+
+ /* Don't concatenate separate words to avoid translation
+ * problems. */
+ switch ((VIsual_select ? 4 : 0)
+ + (VIsual_mode == Ctrl_V) * 2
+ + (VIsual_mode == 'V'))
+ {
+ case 0: p = N_(" VISUAL"); break;
+ case 1: p = N_(" VISUAL LINE"); break;
+ case 2: p = N_(" VISUAL BLOCK"); break;
+ case 4: p = N_(" SELECT"); break;
+ case 5: p = N_(" SELECT LINE"); break;
+ default: p = N_(" SELECT BLOCK"); break;
+ }
+ msg_puts_attr(_(p), attr);
+ }
+ msg_puts_attr(" --", attr);
+ }
+
+ need_clear = TRUE;
+ }
+ if (reg_recording != 0
+#ifdef FEAT_INS_EXPAND
+ && edit_submode == NULL /* otherwise it gets too long */
+#endif
+ )
+ {
+ recording_mode(attr);
+ need_clear = TRUE;
+ }
+
+ mode_displayed = TRUE;
+ if (need_clear || clear_cmdline)
+ msg_clr_eos();
+ msg_didout = FALSE; /* overwrite this message */
+ length = msg_col;
+ msg_col = 0;
+ need_wait_return = nwr_save; /* never ask for hit-return for this */
+ }
+ else if (clear_cmdline && msg_silent == 0)
+ /* Clear the whole command line. Will reset "clear_cmdline". */
+ msg_clr_cmdline();
+
+#ifdef FEAT_CMDL_INFO
+ /* In Visual mode the size of the selected area must be redrawn. */
+ if (VIsual_active)
+ clear_showcmd();
+
+ /* If the last window has no status line, the ruler is after the mode
+ * message and must be redrawn */
+ if (redrawing() && lastwin->w_status_height == 0)
+ win_redr_ruler(lastwin, TRUE, FALSE);
+#endif
+ redraw_cmdline = FALSE;
+ clear_cmdline = FALSE;
+
+ return length;
+}
+
+/*
+ * Position for a mode message.
+ */
+ static void
+msg_pos_mode(void)
+{
+ msg_col = 0;
+ msg_row = Rows - 1;
+}
+
+/*
+ * Delete mode message. Used when ESC is typed which is expected to end
+ * Insert mode (but Insert mode didn't end yet!).
+ * Caller should check "mode_displayed".
+ */
+ void
+unshowmode(int force)
+{
+ /*
+ * Don't delete it right now, when not redrawing or inside a mapping.
+ */
+ if (!redrawing() || (!force && char_avail() && !KeyTyped))
+ redraw_cmdline = TRUE; /* delete mode later */
+ else
+ clearmode();
+}
+
+/*
+ * Clear the mode message.
+ */
+ void
+clearmode(void)
+{
+ int save_msg_row = msg_row;
+ int save_msg_col = msg_col;
+
+ msg_pos_mode();
+ if (reg_recording != 0)
+ recording_mode(HL_ATTR(HLF_CM));
+ msg_clr_eos();
+
+ msg_col = save_msg_col;
+ msg_row = save_msg_row;
+}
+
+ static void
+recording_mode(int attr)
+{
+ msg_puts_attr(_("recording"), attr);
+ if (!shortmess(SHM_RECORDING))
+ {
+ char s[4];
+
+ sprintf(s, " @%c", reg_recording);
+ msg_puts_attr(s, attr);
+ }
+}
+
+/*
+ * Draw the tab pages line at the top of the Vim window.
+ */
+ void
+draw_tabline(void)
+{
+ int tabcount = 0;
+ tabpage_T *tp;
+ int tabwidth;
+ int col = 0;
+ int scol = 0;
+ int attr;
+ win_T *wp;
+ win_T *cwp;
+ int wincount;
+ int modified;
+ int c;
+ int len;
+ int attr_sel = HL_ATTR(HLF_TPS);
+ int attr_nosel = HL_ATTR(HLF_TP);
+ int attr_fill = HL_ATTR(HLF_TPF);
+ char_u *p;
+ int room;
+ int use_sep_chars = (t_colors < 8
+#ifdef FEAT_GUI
+ && !gui.in_use
+#endif
+#ifdef FEAT_TERMGUICOLORS
+ && !p_tgc
+#endif
+ );
+
+ if (ScreenLines == NULL)
+ return;
+ redraw_tabline = FALSE;
+
+#ifdef FEAT_GUI_TABLINE
+ /* Take care of a GUI tabline. */
+ if (gui_use_tabline())
+ {
+ gui_update_tabline();
+ return;
+ }
+#endif
+
+ if (tabline_height() < 1)
+ return;
+
+#if defined(FEAT_STL_OPT)
+
+ /* Init TabPageIdxs[] to zero: Clicking outside of tabs has no effect. */
+ for (scol = 0; scol < Columns; ++scol)
+ TabPageIdxs[scol] = 0;
+
+ /* Use the 'tabline' option if it's set. */
+ if (*p_tal != NUL)
+ {
+ int saved_did_emsg = did_emsg;
+
+ /* Check for an error. If there is one we would loop in redrawing the
+ * screen. Avoid that by making 'tabline' empty. */
+ did_emsg = FALSE;
+ win_redr_custom(NULL, FALSE);
+ if (did_emsg)
+ set_string_option_direct((char_u *)"tabline", -1,
+ (char_u *)"", OPT_FREE, SID_ERROR);
+ did_emsg |= saved_did_emsg;
+ }
+ else
+#endif
+ {
+ FOR_ALL_TABPAGES(tp)
+ ++tabcount;
+
+ tabwidth = (Columns - 1 + tabcount / 2) / tabcount;
+ if (tabwidth < 6)
+ tabwidth = 6;
+
+ attr = attr_nosel;
+ tabcount = 0;
+ scol = 0;
+ for (tp = first_tabpage; tp != NULL && col < Columns - 4;
+ tp = tp->tp_next)
+ {
+ scol = col;
+
+ if (tp->tp_topframe == topframe)
+ attr = attr_sel;
+ if (use_sep_chars && col > 0)
+ screen_putchar('|', 0, col++, attr);
+
+ if (tp->tp_topframe != topframe)
+ attr = attr_nosel;
+
+ screen_putchar(' ', 0, col++, attr);
+
+ if (tp == curtab)
+ {
+ cwp = curwin;
+ wp = firstwin;
+ }
+ else
+ {
+ cwp = tp->tp_curwin;
+ wp = tp->tp_firstwin;
+ }
+
+ modified = FALSE;
+ for (wincount = 0; wp != NULL; wp = wp->w_next, ++wincount)
+ if (bufIsChanged(wp->w_buffer))
+ modified = TRUE;
+ if (modified || wincount > 1)
+ {
+ if (wincount > 1)
+ {
+ vim_snprintf((char *)NameBuff, MAXPATHL, "%d", wincount);
+ len = (int)STRLEN(NameBuff);
+ if (col + len >= Columns - 3)
+ break;
+ screen_puts_len(NameBuff, len, 0, col,
+#if defined(FEAT_SYN_HL)
+ hl_combine_attr(attr, HL_ATTR(HLF_T))
+#else
+ attr
+#endif
+ );
+ col += len;
+ }
+ if (modified)
+ screen_puts_len((char_u *)"+", 1, 0, col++, attr);
+ screen_putchar(' ', 0, col++, attr);
+ }
+
+ room = scol - col + tabwidth - 1;
+ if (room > 0)
+ {
+ /* Get buffer name in NameBuff[] */
+ get_trans_bufname(cwp->w_buffer);
+ shorten_dir(NameBuff);
+ len = vim_strsize(NameBuff);
+ p = NameBuff;
+ if (has_mbyte)
+ while (len > room)
+ {
+ len -= ptr2cells(p);
+ MB_PTR_ADV(p);
+ }
+ else if (len > room)
+ {
+ p += len - room;
+ len = room;
+ }
+ if (len > Columns - col - 1)
+ len = Columns - col - 1;
+
+ screen_puts_len(p, (int)STRLEN(p), 0, col, attr);
+ col += len;
+ }
+ screen_putchar(' ', 0, col++, attr);
+
+ /* Store the tab page number in TabPageIdxs[], so that
+ * jump_to_mouse() knows where each one is. */
+ ++tabcount;
+ while (scol < col)
+ TabPageIdxs[scol++] = tabcount;
+ }
+
+ if (use_sep_chars)
+ c = '_';
+ else
+ c = ' ';
+ screen_fill(0, 1, col, (int)Columns, c, c, attr_fill);
+
+ /* Put an "X" for closing the current tab if there are several. */
+ if (first_tabpage->tp_next != NULL)
+ {
+ screen_putchar('X', 0, (int)Columns - 1, attr_nosel);
+ TabPageIdxs[Columns - 1] = -999;
+ }
+ }
+
+ /* Reset the flag here again, in case evaluating 'tabline' causes it to be
+ * set. */
+ redraw_tabline = FALSE;
+}
+
+/*
+ * Get buffer name for "buf" into NameBuff[].
+ * Takes care of special buffer names and translates special characters.
+ */
+ void
+get_trans_bufname(buf_T *buf)
+{
+ if (buf_spname(buf) != NULL)
+ vim_strncpy(NameBuff, buf_spname(buf), MAXPATHL - 1);
+ else
+ home_replace(buf, buf->b_fname, NameBuff, MAXPATHL, TRUE);
+ trans_characters(NameBuff, MAXPATHL);
+}
+
+/*
+ * Get the character to use in a status line. Get its attributes in "*attr".
+ */
+ static int
+fillchar_status(int *attr, win_T *wp)
+{
+ int fill;
+
+#ifdef FEAT_TERMINAL
+ if (bt_terminal(wp->w_buffer))
+ {
+ if (wp == curwin)
+ {
+ *attr = HL_ATTR(HLF_ST);
+ fill = fill_stl;
+ }
+ else
+ {
+ *attr = HL_ATTR(HLF_STNC);
+ fill = fill_stlnc;
+ }
+ }
+ else
+#endif
+ if (wp == curwin)
+ {
+ *attr = HL_ATTR(HLF_S);
+ fill = fill_stl;
+ }
+ else
+ {
+ *attr = HL_ATTR(HLF_SNC);
+ fill = fill_stlnc;
+ }
+ /* Use fill when there is highlighting, and highlighting of current
+ * window differs, or the fillchars differ, or this is not the
+ * current window */
+ if (*attr != 0 && ((HL_ATTR(HLF_S) != HL_ATTR(HLF_SNC)
+ || wp != curwin || ONE_WINDOW)
+ || (fill_stl != fill_stlnc)))
+ return fill;
+ if (wp == curwin)
+ return '^';
+ return '=';
+}
+
+/*
+ * Get the character to use in a separator between vertically split windows.
+ * Get its attributes in "*attr".
+ */
+ static int
+fillchar_vsep(int *attr)
+{
+ *attr = HL_ATTR(HLF_C);
+ if (*attr == 0 && fill_vert == ' ')
+ return '|';
+ else
+ return fill_vert;
+}
+
+/*
+ * Return TRUE if redrawing should currently be done.
+ */
+ int
+redrawing(void)
+{
+#ifdef FEAT_EVAL
+ if (disable_redraw_for_testing)
+ return 0;
+ else
+#endif
+ return ((!RedrawingDisabled
+#ifdef FEAT_EVAL
+ || ignore_redraw_flag_for_testing
+#endif
+ ) && !(p_lz && char_avail() && !KeyTyped && !do_redraw));
+}
+
+/*
+ * Return TRUE if printing messages should currently be done.
+ */
+ int
+messaging(void)
+{
+ return (!(p_lz && char_avail() && !KeyTyped));
+}
+
+#ifdef FEAT_MENU
+/*
+ * Draw the window toolbar.
+ */
+ static void
+redraw_win_toolbar(win_T *wp)
+{
+ vimmenu_T *menu;
+ int item_idx = 0;
+ int item_count = 0;
+ int col = 0;
+ int next_col;
+ int off = (int)(current_ScreenLine - ScreenLines);
+ int fill_attr = syn_name2attr((char_u *)"ToolbarLine");
+ int button_attr = syn_name2attr((char_u *)"ToolbarButton");
+
+ vim_free(wp->w_winbar_items);
+ for (menu = wp->w_winbar->children; menu != NULL; menu = menu->next)
+ ++item_count;
+ wp->w_winbar_items = (winbar_item_T *)alloc_clear(
+ (unsigned)sizeof(winbar_item_T) * (item_count + 1));
+
+ /* TODO: use fewer spaces if there is not enough room */
+ for (menu = wp->w_winbar->children;
+ menu != NULL && col < wp->w_width; menu = menu->next)
+ {
+ space_to_screenline(off + col, fill_attr);
+ if (++col >= wp->w_width)
+ break;
+ if (col > 1)
+ {
+ space_to_screenline(off + col, fill_attr);
+ if (++col >= wp->w_width)
+ break;
+ }
+
+ wp->w_winbar_items[item_idx].wb_startcol = col;
+ space_to_screenline(off + col, button_attr);
+ if (++col >= wp->w_width)
+ break;
+
+ next_col = text_to_screenline(wp, menu->name, col);
+ while (col < next_col)
+ {
+ ScreenAttrs[off + col] = button_attr;
+ ++col;
+ }
+ wp->w_winbar_items[item_idx].wb_endcol = col;
+ wp->w_winbar_items[item_idx].wb_menu = menu;
+ ++item_idx;
+
+ if (col >= wp->w_width)
+ break;
+ space_to_screenline(off + col, button_attr);
+ ++col;
+ }
+ while (col < wp->w_width)
+ {
+ space_to_screenline(off + col, fill_attr);
+ ++col;
+ }
+ wp->w_winbar_items[item_idx].wb_menu = NULL; /* end marker */
+
+ screen_line(wp->w_winrow, wp->w_wincol, (int)wp->w_width,
+ (int)wp->w_width, FALSE);
+}
+#endif
+
+/*
+ * Show current status info in ruler and various other places
+ * If always is FALSE, only show ruler if position has changed.
+ */
+ void
+showruler(int always)
+{
+ if (!always && !redrawing())
+ return;
+#ifdef FEAT_INS_EXPAND
+ if (pum_visible())
+ {
+ /* Don't redraw right now, do it later. */
+ curwin->w_redr_status = TRUE;
+ return;
+ }
+#endif
+#if defined(FEAT_STL_OPT)
+ if ((*p_stl != NUL || *curwin->w_p_stl != NUL) && curwin->w_status_height)
+ {
+ redraw_custom_statusline(curwin);
+ }
+ else
+#endif
+#ifdef FEAT_CMDL_INFO
+ win_redr_ruler(curwin, always, FALSE);
+#endif
+
+#ifdef FEAT_TITLE
+ if (need_maketitle
+# ifdef FEAT_STL_OPT
+ || (p_icon && (stl_syntax & STL_IN_ICON))
+ || (p_title && (stl_syntax & STL_IN_TITLE))
+# endif
+ )
+ maketitle();
+#endif
+ /* Redraw the tab pages line if needed. */
+ if (redraw_tabline)
+ draw_tabline();
+}
+
+#ifdef FEAT_CMDL_INFO
+ static void
+win_redr_ruler(win_T *wp, int always, int ignore_pum)
+{
+#define RULER_BUF_LEN 70
+ char_u buffer[RULER_BUF_LEN];
+ int row;
+ int fillchar;
+ int attr;
+ int empty_line = FALSE;
+ colnr_T virtcol;
+ int i;
+ size_t len;
+ int o;
+ int this_ru_col;
+ int off = 0;
+ int width = Columns;
+
+ /* If 'ruler' off or redrawing disabled, don't do anything */
+ if (!p_ru)
+ return;
+
+ /*
+ * Check if cursor.lnum is valid, since win_redr_ruler() may be called
+ * after deleting lines, before cursor.lnum is corrected.
+ */
+ if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
+ return;
+
+#ifdef FEAT_INS_EXPAND
+ /* Don't draw the ruler while doing insert-completion, it might overwrite
+ * the (long) mode message. */
+ if (wp == lastwin && lastwin->w_status_height == 0)
+ if (edit_submode != NULL)
+ return;
+ // Don't draw the ruler when the popup menu is visible, it may overlap.
+ // Except when the popup menu will be redrawn anyway.
+ if (!ignore_pum && pum_visible())
+ return;
+#endif
+
+#ifdef FEAT_STL_OPT
+ if (*p_ruf)
+ {
+ int save_called_emsg = called_emsg;
+
+ called_emsg = FALSE;
+ win_redr_custom(wp, TRUE);
+ if (called_emsg)
+ set_string_option_direct((char_u *)"rulerformat", -1,
+ (char_u *)"", OPT_FREE, SID_ERROR);
+ called_emsg |= save_called_emsg;
+ return;
+ }
+#endif
+
+ /*
+ * Check if not in Insert mode and the line is empty (will show "0-1").
+ */
+ if (!(State & INSERT)
+ && *ml_get_buf(wp->w_buffer, wp->w_cursor.lnum, FALSE) == NUL)
+ empty_line = TRUE;
+
+ /*
+ * Only draw the ruler when something changed.
+ */
+ validate_virtcol_win(wp);
+ if ( redraw_cmdline
+ || always
+ || wp->w_cursor.lnum != wp->w_ru_cursor.lnum
+ || wp->w_cursor.col != wp->w_ru_cursor.col
+ || wp->w_virtcol != wp->w_ru_virtcol
+ || wp->w_cursor.coladd != wp->w_ru_cursor.coladd
+ || wp->w_topline != wp->w_ru_topline
+ || wp->w_buffer->b_ml.ml_line_count != wp->w_ru_line_count
+#ifdef FEAT_DIFF
+ || wp->w_topfill != wp->w_ru_topfill
+#endif
+ || empty_line != wp->w_ru_empty)
+ {
+ cursor_off();
+ if (wp->w_status_height)
+ {
+ row = W_WINROW(wp) + wp->w_height;
+ fillchar = fillchar_status(&attr, wp);
+ off = wp->w_wincol;
+ width = wp->w_width;
+ }
+ else
+ {
+ row = Rows - 1;
+ fillchar = ' ';
+ attr = 0;
+ width = Columns;
+ off = 0;
+ }
+
+ /* In list mode virtcol needs to be recomputed */
+ virtcol = wp->w_virtcol;
+ if (wp->w_p_list && lcs_tab1 == NUL)
+ {
+ wp->w_p_list = FALSE;
+ getvvcol(wp, &wp->w_cursor, NULL, &virtcol, NULL);
+ wp->w_p_list = TRUE;
+ }
+
+ /*
+ * Some sprintfs return the length, some return a pointer.
+ * To avoid portability problems we use strlen() here.
+ */
+ vim_snprintf((char *)buffer, RULER_BUF_LEN, "%ld,",
+ (wp->w_buffer->b_ml.ml_flags & ML_EMPTY)
+ ? 0L
+ : (long)(wp->w_cursor.lnum));
+ len = STRLEN(buffer);
+ col_print(buffer + len, RULER_BUF_LEN - len,
+ empty_line ? 0 : (int)wp->w_cursor.col + 1,
+ (int)virtcol + 1);
+
+ /*
+ * Add a "50%" if there is room for it.
+ * On the last line, don't print in the last column (scrolls the
+ * screen up on some terminals).
+ */
+ i = (int)STRLEN(buffer);
+ get_rel_pos(wp, buffer + i + 1, RULER_BUF_LEN - i - 1);
+ o = i + vim_strsize(buffer + i + 1);
+ if (wp->w_status_height == 0) /* can't use last char of screen */
+ ++o;
+ this_ru_col = ru_col - (Columns - width);
+ if (this_ru_col < 0)
+ this_ru_col = 0;
+ /* Never use more than half the window/screen width, leave the other
+ * half for the filename. */
+ if (this_ru_col < (width + 1) / 2)
+ this_ru_col = (width + 1) / 2;
+ if (this_ru_col + o < width)
+ {
+ /* need at least 3 chars left for get_rel_pos() + NUL */
+ while (this_ru_col + o < width && RULER_BUF_LEN > i + 4)
+ {
+ if (has_mbyte)
+ i += (*mb_char2bytes)(fillchar, buffer + i);
+ else
+ buffer[i++] = fillchar;
+ ++o;
+ }
+ get_rel_pos(wp, buffer + i, RULER_BUF_LEN - i);
+ }
+ /* Truncate at window boundary. */
+ if (has_mbyte)
+ {
+ o = 0;
+ for (i = 0; buffer[i] != NUL; i += (*mb_ptr2len)(buffer + i))
+ {
+ o += (*mb_ptr2cells)(buffer + i);
+ if (this_ru_col + o > width)
+ {
+ buffer[i] = NUL;
+ break;
+ }
+ }
+ }
+ else if (this_ru_col + (int)STRLEN(buffer) > width)
+ buffer[width - this_ru_col] = NUL;
+
+ screen_puts(buffer, row, this_ru_col + off, attr);
+ i = redraw_cmdline;
+ screen_fill(row, row + 1,
+ this_ru_col + off + (int)STRLEN(buffer),
+ (int)(off + width),
+ fillchar, fillchar, attr);
+ /* don't redraw the cmdline because of showing the ruler */
+ redraw_cmdline = i;
+ wp->w_ru_cursor = wp->w_cursor;
+ wp->w_ru_virtcol = wp->w_virtcol;
+ wp->w_ru_empty = empty_line;
+ wp->w_ru_topline = wp->w_topline;
+ wp->w_ru_line_count = wp->w_buffer->b_ml.ml_line_count;
+#ifdef FEAT_DIFF
+ wp->w_ru_topfill = wp->w_topfill;
+#endif
+ }
+}
+#endif
+
+#if defined(FEAT_LINEBREAK) || defined(PROTO)
+/*
+ * Return the width of the 'number' and 'relativenumber' column.
+ * Caller may need to check if 'number' or 'relativenumber' is set.
+ * Otherwise it depends on 'numberwidth' and the line count.
+ */
+ int
+number_width(win_T *wp)
+{
+ int n;
+ linenr_T lnum;
+
+ if (wp->w_p_rnu && !wp->w_p_nu)
+ /* cursor line shows "0" */
+ lnum = wp->w_height;
+ else
+ /* cursor line shows absolute line number */
+ lnum = wp->w_buffer->b_ml.ml_line_count;
+
+ if (lnum == wp->w_nrwidth_line_count && wp->w_nuw_cached == wp->w_p_nuw)
+ return wp->w_nrwidth_width;
+ wp->w_nrwidth_line_count = lnum;
+
+ n = 0;
+ do
+ {
+ lnum /= 10;
+ ++n;
+ } while (lnum > 0);
+
+ /* 'numberwidth' gives the minimal width plus one */
+ if (n < wp->w_p_nuw - 1)
+ n = wp->w_p_nuw - 1;
+
+ wp->w_nrwidth_width = n;
+ wp->w_nuw_cached = wp->w_p_nuw;
+ return n;
+}
+#endif
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * Return the current cursor column. This is the actual position on the
+ * screen. First column is 0.
+ */
+ int
+screen_screencol(void)
+{
+ return screen_cur_col;
+}
+
+/*
+ * Return the current cursor row. This is the actual position on the screen.
+ * First row is 0.
+ */
+ int
+screen_screenrow(void)
+{
+ return screen_cur_row;
+}
+#endif
diff --git a/src/search.c b/src/search.c
new file mode 100644
index 0000000..4b3f853
--- /dev/null
+++ b/src/search.c
@@ -0,0 +1,5751 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+/*
+ * search.c: code for normal mode searching commands
+ */
+
+#include "vim.h"
+
+#ifdef FEAT_EVAL
+static void set_vv_searchforward(void);
+static int first_submatch(regmmatch_T *rp);
+#endif
+static int check_linecomment(char_u *line);
+static int cls(void);
+static int skip_chars(int, int);
+#ifdef FEAT_FIND_ID
+static void show_pat_in_path(char_u *, int,
+ int, int, FILE *, linenr_T *, long);
+#endif
+#ifdef FEAT_VIMINFO
+static void wvsp_one(FILE *fp, int idx, char *s, int sc);
+#endif
+
+/*
+ * This file contains various searching-related routines. These fall into
+ * three groups:
+ * 1. string searches (for /, ?, n, and N)
+ * 2. character searches within a single line (for f, F, t, T, etc)
+ * 3. "other" kinds of searches like the '%' command, and 'word' searches.
+ */
+
+/*
+ * String searches
+ *
+ * The string search functions are divided into two levels:
+ * lowest: searchit(); uses an pos_T for starting position and found match.
+ * Highest: do_search(); uses curwin->w_cursor; calls searchit().
+ *
+ * The last search pattern is remembered for repeating the same search.
+ * This pattern is shared between the :g, :s, ? and / commands.
+ * This is in search_regcomp().
+ *
+ * The actual string matching is done using a heavily modified version of
+ * Henry Spencer's regular expression library. See regexp.c.
+ */
+
+/* The offset for a search command is store in a soff struct */
+/* Note: only spats[0].off is really used */
+struct soffset
+{
+ int dir; /* search direction, '/' or '?' */
+ int line; /* search has line offset */
+ int end; /* search set cursor at end */
+ long off; /* line or char offset */
+};
+
+/* A search pattern and its attributes are stored in a spat struct */
+struct spat
+{
+ char_u *pat; /* the pattern (in allocated memory) or NULL */
+ int magic; /* magicness of the pattern */
+ int no_scs; /* no smartcase for this pattern */
+ struct soffset off;
+};
+
+/*
+ * Two search patterns are remembered: One for the :substitute command and
+ * one for other searches. last_idx points to the one that was used the last
+ * time.
+ */
+static struct spat spats[2] =
+{
+ {NULL, TRUE, FALSE, {'/', 0, 0, 0L}}, /* last used search pat */
+ {NULL, TRUE, FALSE, {'/', 0, 0, 0L}} /* last used substitute pat */
+};
+
+static int last_idx = 0; /* index in spats[] for RE_LAST */
+
+static char_u lastc[2] = {NUL, NUL}; /* last character searched for */
+static int lastcdir = FORWARD; /* last direction of character search */
+static int last_t_cmd = TRUE; /* last search t_cmd */
+static char_u lastc_bytes[MB_MAXBYTES + 1];
+static int lastc_bytelen = 1; /* >1 for multi-byte char */
+
+/* copy of spats[], for keeping the search patterns while executing autocmds */
+static struct spat saved_spats[2];
+# ifdef FEAT_SEARCH_EXTRA
+static int saved_spats_last_idx = 0;
+static int saved_spats_no_hlsearch = 0;
+# endif
+
+static char_u *mr_pattern = NULL; /* pattern used by search_regcomp() */
+#ifdef FEAT_RIGHTLEFT
+static int mr_pattern_alloced = FALSE; /* mr_pattern was allocated */
+#endif
+
+#ifdef FEAT_FIND_ID
+/*
+ * Type used by find_pattern_in_path() to remember which included files have
+ * been searched already.
+ */
+typedef struct SearchedFile
+{
+ FILE *fp; /* File pointer */
+ char_u *name; /* Full name of file */
+ linenr_T lnum; /* Line we were up to in file */
+ int matched; /* Found a match in this file */
+} SearchedFile;
+#endif
+
+/*
+ * translate search pattern for vim_regcomp()
+ *
+ * pat_save == RE_SEARCH: save pat in spats[RE_SEARCH].pat (normal search cmd)
+ * pat_save == RE_SUBST: save pat in spats[RE_SUBST].pat (:substitute command)
+ * pat_save == RE_BOTH: save pat in both patterns (:global command)
+ * pat_use == RE_SEARCH: use previous search pattern if "pat" is NULL
+ * pat_use == RE_SUBST: use previous substitute pattern if "pat" is NULL
+ * pat_use == RE_LAST: use last used pattern if "pat" is NULL
+ * options & SEARCH_HIS: put search string in history
+ * options & SEARCH_KEEP: keep previous search pattern
+ *
+ * returns FAIL if failed, OK otherwise.
+ */
+ int
+search_regcomp(
+ char_u *pat,
+ int pat_save,
+ int pat_use,
+ int options,
+ regmmatch_T *regmatch) /* return: pattern and ignore-case flag */
+{
+ int magic;
+ int i;
+
+ rc_did_emsg = FALSE;
+ magic = p_magic;
+
+ /*
+ * If no pattern given, use a previously defined pattern.
+ */
+ if (pat == NULL || *pat == NUL)
+ {
+ if (pat_use == RE_LAST)
+ i = last_idx;
+ else
+ i = pat_use;
+ if (spats[i].pat == NULL) /* pattern was never defined */
+ {
+ if (pat_use == RE_SUBST)
+ emsg(_(e_nopresub));
+ else
+ emsg(_(e_noprevre));
+ rc_did_emsg = TRUE;
+ return FAIL;
+ }
+ pat = spats[i].pat;
+ magic = spats[i].magic;
+ no_smartcase = spats[i].no_scs;
+ }
+#ifdef FEAT_CMDHIST
+ else if (options & SEARCH_HIS) /* put new pattern in history */
+ add_to_history(HIST_SEARCH, pat, TRUE, NUL);
+#endif
+
+#ifdef FEAT_RIGHTLEFT
+ if (mr_pattern_alloced)
+ {
+ vim_free(mr_pattern);
+ mr_pattern_alloced = FALSE;
+ }
+
+ if (curwin->w_p_rl && *curwin->w_p_rlc == 's')
+ {
+ char_u *rev_pattern;
+
+ rev_pattern = reverse_text(pat);
+ if (rev_pattern == NULL)
+ mr_pattern = pat; /* out of memory, keep normal pattern. */
+ else
+ {
+ mr_pattern = rev_pattern;
+ mr_pattern_alloced = TRUE;
+ }
+ }
+ else
+#endif
+ mr_pattern = pat;
+
+ /*
+ * Save the currently used pattern in the appropriate place,
+ * unless the pattern should not be remembered.
+ */
+ if (!(options & SEARCH_KEEP) && !cmdmod.keeppatterns)
+ {
+ /* search or global command */
+ if (pat_save == RE_SEARCH || pat_save == RE_BOTH)
+ save_re_pat(RE_SEARCH, pat, magic);
+ /* substitute or global command */
+ if (pat_save == RE_SUBST || pat_save == RE_BOTH)
+ save_re_pat(RE_SUBST, pat, magic);
+ }
+
+ regmatch->rmm_ic = ignorecase(pat);
+ regmatch->rmm_maxcol = 0;
+ regmatch->regprog = vim_regcomp(pat, magic ? RE_MAGIC : 0);
+ if (regmatch->regprog == NULL)
+ return FAIL;
+ return OK;
+}
+
+/*
+ * Get search pattern used by search_regcomp().
+ */
+ char_u *
+get_search_pat(void)
+{
+ return mr_pattern;
+}
+
+#if defined(FEAT_RIGHTLEFT) || defined(PROTO)
+/*
+ * Reverse text into allocated memory.
+ * Returns the allocated string, NULL when out of memory.
+ */
+ char_u *
+reverse_text(char_u *s)
+{
+ unsigned len;
+ unsigned s_i, rev_i;
+ char_u *rev;
+
+ /*
+ * Reverse the pattern.
+ */
+ len = (unsigned)STRLEN(s);
+ rev = alloc(len + 1);
+ if (rev != NULL)
+ {
+ rev_i = len;
+ for (s_i = 0; s_i < len; ++s_i)
+ {
+ if (has_mbyte)
+ {
+ int mb_len;
+
+ mb_len = (*mb_ptr2len)(s + s_i);
+ rev_i -= mb_len;
+ mch_memmove(rev + rev_i, s + s_i, mb_len);
+ s_i += mb_len - 1;
+ }
+ else
+ rev[--rev_i] = s[s_i];
+
+ }
+ rev[len] = NUL;
+ }
+ return rev;
+}
+#endif
+
+ void
+save_re_pat(int idx, char_u *pat, int magic)
+{
+ if (spats[idx].pat != pat)
+ {
+ vim_free(spats[idx].pat);
+ spats[idx].pat = vim_strsave(pat);
+ spats[idx].magic = magic;
+ spats[idx].no_scs = no_smartcase;
+ last_idx = idx;
+#ifdef FEAT_SEARCH_EXTRA
+ /* If 'hlsearch' set and search pat changed: need redraw. */
+ if (p_hls)
+ redraw_all_later(SOME_VALID);
+ set_no_hlsearch(FALSE);
+#endif
+ }
+}
+
+/*
+ * Save the search patterns, so they can be restored later.
+ * Used before/after executing autocommands and user functions.
+ */
+static int save_level = 0;
+
+ void
+save_search_patterns(void)
+{
+ if (save_level++ == 0)
+ {
+ saved_spats[0] = spats[0];
+ if (spats[0].pat != NULL)
+ saved_spats[0].pat = vim_strsave(spats[0].pat);
+ saved_spats[1] = spats[1];
+ if (spats[1].pat != NULL)
+ saved_spats[1].pat = vim_strsave(spats[1].pat);
+#ifdef FEAT_SEARCH_EXTRA
+ saved_spats_last_idx = last_idx;
+ saved_spats_no_hlsearch = no_hlsearch;
+#endif
+ }
+}
+
+ void
+restore_search_patterns(void)
+{
+ if (--save_level == 0)
+ {
+ vim_free(spats[0].pat);
+ spats[0] = saved_spats[0];
+#if defined(FEAT_EVAL)
+ set_vv_searchforward();
+#endif
+ vim_free(spats[1].pat);
+ spats[1] = saved_spats[1];
+#ifdef FEAT_SEARCH_EXTRA
+ last_idx = saved_spats_last_idx;
+ set_no_hlsearch(saved_spats_no_hlsearch);
+#endif
+ }
+}
+
+#if defined(EXITFREE) || defined(PROTO)
+ void
+free_search_patterns(void)
+{
+ vim_free(spats[0].pat);
+ vim_free(spats[1].pat);
+
+# ifdef FEAT_RIGHTLEFT
+ if (mr_pattern_alloced)
+ {
+ vim_free(mr_pattern);
+ mr_pattern_alloced = FALSE;
+ mr_pattern = NULL;
+ }
+# endif
+}
+#endif
+
+#ifdef FEAT_SEARCH_EXTRA
+// copy of spats[RE_SEARCH], for keeping the search patterns while incremental
+// searching
+static struct spat saved_last_search_spat;
+static int did_save_last_search_spat = 0;
+static int saved_last_idx = 0;
+static int saved_no_hlsearch = 0;
+
+/*
+ * Save and restore the search pattern for incremental highlight search
+ * feature.
+ *
+ * It's similar to but different from save_search_patterns() and
+ * restore_search_patterns(), because the search pattern must be restored when
+ * canceling incremental searching even if it's called inside user functions.
+ */
+ void
+save_last_search_pattern(void)
+{
+ if (did_save_last_search_spat != 0)
+ iemsg("did_save_last_search_spat is not zero");
+ else
+ ++did_save_last_search_spat;
+
+ saved_last_search_spat = spats[RE_SEARCH];
+ if (spats[RE_SEARCH].pat != NULL)
+ saved_last_search_spat.pat = vim_strsave(spats[RE_SEARCH].pat);
+ saved_last_idx = last_idx;
+ saved_no_hlsearch = no_hlsearch;
+}
+
+ void
+restore_last_search_pattern(void)
+{
+ if (did_save_last_search_spat != 1)
+ {
+ iemsg("did_save_last_search_spat is not one");
+ return;
+ }
+ --did_save_last_search_spat;
+
+ vim_free(spats[RE_SEARCH].pat);
+ spats[RE_SEARCH] = saved_last_search_spat;
+ saved_last_search_spat.pat = NULL;
+# if defined(FEAT_EVAL)
+ set_vv_searchforward();
+# endif
+ last_idx = saved_last_idx;
+ set_no_hlsearch(saved_no_hlsearch);
+}
+
+ char_u *
+last_search_pattern(void)
+{
+ return spats[RE_SEARCH].pat;
+}
+#endif
+
+/*
+ * Return TRUE when case should be ignored for search pattern "pat".
+ * Uses the 'ignorecase' and 'smartcase' options.
+ */
+ int
+ignorecase(char_u *pat)
+{
+ return ignorecase_opt(pat, p_ic, p_scs);
+}
+
+/*
+ * As ignorecase() put pass the "ic" and "scs" flags.
+ */
+ int
+ignorecase_opt(char_u *pat, int ic_in, int scs)
+{
+ int ic = ic_in;
+
+ if (ic && !no_smartcase && scs
+#ifdef FEAT_INS_EXPAND
+ && !(ctrl_x_mode_not_default() && curbuf->b_p_inf)
+#endif
+ )
+ ic = !pat_has_uppercase(pat);
+ no_smartcase = FALSE;
+
+ return ic;
+}
+
+/*
+ * Return TRUE if pattern "pat" has an uppercase character.
+ */
+ int
+pat_has_uppercase(char_u *pat)
+{
+ char_u *p = pat;
+
+ while (*p != NUL)
+ {
+ int l;
+
+ if (has_mbyte && (l = (*mb_ptr2len)(p)) > 1)
+ {
+ if (enc_utf8 && utf_isupper(utf_ptr2char(p)))
+ return TRUE;
+ p += l;
+ }
+ else if (*p == '\\')
+ {
+ if (p[1] == '_' && p[2] != NUL) /* skip "\_X" */
+ p += 3;
+ else if (p[1] == '%' && p[2] != NUL) /* skip "\%X" */
+ p += 3;
+ else if (p[1] != NUL) /* skip "\X" */
+ p += 2;
+ else
+ p += 1;
+ }
+ else if (MB_ISUPPER(*p))
+ return TRUE;
+ else
+ ++p;
+ }
+ return FALSE;
+}
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+ char_u *
+last_csearch(void)
+{
+ return lastc_bytes;
+}
+
+ int
+last_csearch_forward(void)
+{
+ return lastcdir == FORWARD;
+}
+
+ int
+last_csearch_until(void)
+{
+ return last_t_cmd == TRUE;
+}
+
+ void
+set_last_csearch(int c, char_u *s UNUSED, int len UNUSED)
+{
+ *lastc = c;
+ lastc_bytelen = len;
+ if (len)
+ memcpy(lastc_bytes, s, len);
+ else
+ vim_memset(lastc_bytes, 0, sizeof(lastc_bytes));
+}
+#endif
+
+ void
+set_csearch_direction(int cdir)
+{
+ lastcdir = cdir;
+}
+
+ void
+set_csearch_until(int t_cmd)
+{
+ last_t_cmd = t_cmd;
+}
+
+ char_u *
+last_search_pat(void)
+{
+ return spats[last_idx].pat;
+}
+
+/*
+ * Reset search direction to forward. For "gd" and "gD" commands.
+ */
+ void
+reset_search_dir(void)
+{
+ spats[0].off.dir = '/';
+#if defined(FEAT_EVAL)
+ set_vv_searchforward();
+#endif
+}
+
+#if defined(FEAT_EVAL) || defined(FEAT_VIMINFO)
+/*
+ * Set the last search pattern. For ":let @/ =" and viminfo.
+ * Also set the saved search pattern, so that this works in an autocommand.
+ */
+ void
+set_last_search_pat(
+ char_u *s,
+ int idx,
+ int magic,
+ int setlast)
+{
+ vim_free(spats[idx].pat);
+ /* An empty string means that nothing should be matched. */
+ if (*s == NUL)
+ spats[idx].pat = NULL;
+ else
+ spats[idx].pat = vim_strsave(s);
+ spats[idx].magic = magic;
+ spats[idx].no_scs = FALSE;
+ spats[idx].off.dir = '/';
+#if defined(FEAT_EVAL)
+ set_vv_searchforward();
+#endif
+ spats[idx].off.line = FALSE;
+ spats[idx].off.end = FALSE;
+ spats[idx].off.off = 0;
+ if (setlast)
+ last_idx = idx;
+ if (save_level)
+ {
+ vim_free(saved_spats[idx].pat);
+ saved_spats[idx] = spats[0];
+ if (spats[idx].pat == NULL)
+ saved_spats[idx].pat = NULL;
+ else
+ saved_spats[idx].pat = vim_strsave(spats[idx].pat);
+ saved_spats_last_idx = last_idx;
+ }
+# ifdef FEAT_SEARCH_EXTRA
+ /* If 'hlsearch' set and search pat changed: need redraw. */
+ if (p_hls && idx == last_idx && !no_hlsearch)
+ redraw_all_later(SOME_VALID);
+# endif
+}
+#endif
+
+#ifdef FEAT_SEARCH_EXTRA
+/*
+ * Get a regexp program for the last used search pattern.
+ * This is used for highlighting all matches in a window.
+ * Values returned in regmatch->regprog and regmatch->rmm_ic.
+ */
+ void
+last_pat_prog(regmmatch_T *regmatch)
+{
+ if (spats[last_idx].pat == NULL)
+ {
+ regmatch->regprog = NULL;
+ return;
+ }
+ ++emsg_off; /* So it doesn't beep if bad expr */
+ (void)search_regcomp((char_u *)"", 0, last_idx, SEARCH_KEEP, regmatch);
+ --emsg_off;
+}
+#endif
+
+/*
+ * Lowest level search function.
+ * Search for 'count'th occurrence of pattern "pat" in direction "dir".
+ * Start at position "pos" and return the found position in "pos".
+ *
+ * if (options & SEARCH_MSG) == 0 don't give any messages
+ * if (options & SEARCH_MSG) == SEARCH_NFMSG don't give 'notfound' messages
+ * if (options & SEARCH_MSG) == SEARCH_MSG give all messages
+ * if (options & SEARCH_HIS) put search pattern in history
+ * if (options & SEARCH_END) return position at end of match
+ * if (options & SEARCH_START) accept match at pos itself
+ * if (options & SEARCH_KEEP) keep previous search pattern
+ * if (options & SEARCH_FOLD) match only once in a closed fold
+ * if (options & SEARCH_PEEK) check for typed char, cancel search
+ * if (options & SEARCH_COL) start at pos->col instead of zero
+ *
+ * Return FAIL (zero) for failure, non-zero for success.
+ * When FEAT_EVAL is defined, returns the index of the first matching
+ * subpattern plus one; one if there was none.
+ */
+ int
+searchit(
+ win_T *win, /* window to search in; can be NULL for a
+ buffer without a window! */
+ buf_T *buf,
+ pos_T *pos,
+ pos_T *end_pos, // set to end of the match, unless NULL
+ int dir,
+ char_u *pat,
+ long count,
+ int options,
+ int pat_use, /* which pattern to use when "pat" is empty */
+ linenr_T stop_lnum, /* stop after this line number when != 0 */
+ proftime_T *tm UNUSED, /* timeout limit or NULL */
+ int *timed_out UNUSED) /* set when timed out or NULL */
+{
+ int found;
+ linenr_T lnum; /* no init to shut up Apollo cc */
+ colnr_T col;
+ regmmatch_T regmatch;
+ char_u *ptr;
+ colnr_T matchcol;
+ lpos_T endpos;
+ lpos_T matchpos;
+ int loop;
+ pos_T start_pos;
+ int at_first_line;
+ int extra_col;
+ int start_char_len;
+ int match_ok;
+ long nmatched;
+ int submatch = 0;
+ int first_match = TRUE;
+ int save_called_emsg = called_emsg;
+#ifdef FEAT_SEARCH_EXTRA
+ int break_loop = FALSE;
+#endif
+
+ if (search_regcomp(pat, RE_SEARCH, pat_use,
+ (options & (SEARCH_HIS + SEARCH_KEEP)), &regmatch) == FAIL)
+ {
+ if ((options & SEARCH_MSG) && !rc_did_emsg)
+ semsg(_("E383: Invalid search string: %s"), mr_pattern);
+ return FAIL;
+ }
+
+ /*
+ * find the string
+ */
+ called_emsg = FALSE;
+ do /* loop for count */
+ {
+ /* When not accepting a match at the start position set "extra_col" to
+ * a non-zero value. Don't do that when starting at MAXCOL, since
+ * MAXCOL + 1 is zero. */
+ if (pos->col == MAXCOL)
+ start_char_len = 0;
+ /* Watch out for the "col" being MAXCOL - 2, used in a closed fold. */
+ else if (has_mbyte
+ && pos->lnum >= 1 && pos->lnum <= buf->b_ml.ml_line_count
+ && pos->col < MAXCOL - 2)
+ {
+ ptr = ml_get_buf(buf, pos->lnum, FALSE);
+ if ((int)STRLEN(ptr) <= pos->col)
+ start_char_len = 1;
+ else
+ start_char_len = (*mb_ptr2len)(ptr + pos->col);
+ }
+ else
+ start_char_len = 1;
+ if (dir == FORWARD)
+ {
+ if (options & SEARCH_START)
+ extra_col = 0;
+ else
+ extra_col = start_char_len;
+ }
+ else
+ {
+ if (options & SEARCH_START)
+ extra_col = start_char_len;
+ else
+ extra_col = 0;
+ }
+
+ start_pos = *pos; /* remember start pos for detecting no match */
+ found = 0; /* default: not found */
+ at_first_line = TRUE; /* default: start in first line */
+ if (pos->lnum == 0) /* correct lnum for when starting in line 0 */
+ {
+ pos->lnum = 1;
+ pos->col = 0;
+ at_first_line = FALSE; /* not in first line now */
+ }
+
+ /*
+ * Start searching in current line, unless searching backwards and
+ * we're in column 0.
+ * If we are searching backwards, in column 0, and not including the
+ * current position, gain some efficiency by skipping back a line.
+ * Otherwise begin the search in the current line.
+ */
+ if (dir == BACKWARD && start_pos.col == 0
+ && (options & SEARCH_START) == 0)
+ {
+ lnum = pos->lnum - 1;
+ at_first_line = FALSE;
+ }
+ else
+ lnum = pos->lnum;
+
+ for (loop = 0; loop <= 1; ++loop) /* loop twice if 'wrapscan' set */
+ {
+ for ( ; lnum > 0 && lnum <= buf->b_ml.ml_line_count;
+ lnum += dir, at_first_line = FALSE)
+ {
+ /* Stop after checking "stop_lnum", if it's set. */
+ if (stop_lnum != 0 && (dir == FORWARD
+ ? lnum > stop_lnum : lnum < stop_lnum))
+ break;
+#ifdef FEAT_RELTIME
+ /* Stop after passing the "tm" time limit. */
+ if (tm != NULL && profile_passed_limit(tm))
+ break;
+#endif
+
+ /*
+ * Look for a match somewhere in line "lnum".
+ */
+ col = at_first_line && (options & SEARCH_COL) ? pos->col
+ : (colnr_T)0;
+ nmatched = vim_regexec_multi(&regmatch, win, buf,
+ lnum, col,
+#ifdef FEAT_RELTIME
+ tm, timed_out
+#else
+ NULL, NULL
+#endif
+ );
+ /* Abort searching on an error (e.g., out of stack). */
+ if (called_emsg
+#ifdef FEAT_RELTIME
+ || (timed_out != NULL && *timed_out)
+#endif
+ )
+ break;
+ if (nmatched > 0)
+ {
+ /* match may actually be in another line when using \zs */
+ matchpos = regmatch.startpos[0];
+ endpos = regmatch.endpos[0];
+#ifdef FEAT_EVAL
+ submatch = first_submatch(&regmatch);
+#endif
+ /* "lnum" may be past end of buffer for "\n\zs". */
+ if (lnum + matchpos.lnum > buf->b_ml.ml_line_count)
+ ptr = (char_u *)"";
+ else
+ ptr = ml_get_buf(buf, lnum + matchpos.lnum, FALSE);
+
+ /*
+ * Forward search in the first line: match should be after
+ * the start position. If not, continue at the end of the
+ * match (this is vi compatible) or on the next char.
+ */
+ if (dir == FORWARD && at_first_line)
+ {
+ match_ok = TRUE;
+ /*
+ * When the match starts in a next line it's certainly
+ * past the start position.
+ * When match lands on a NUL the cursor will be put
+ * one back afterwards, compare with that position,
+ * otherwise "/$" will get stuck on end of line.
+ */
+ while (matchpos.lnum == 0
+ && ((options & SEARCH_END) && first_match
+ ? (nmatched == 1
+ && (int)endpos.col - 1
+ < (int)start_pos.col + extra_col)
+ : ((int)matchpos.col
+ - (ptr[matchpos.col] == NUL)
+ < (int)start_pos.col + extra_col)))
+ {
+ /*
+ * If vi-compatible searching, continue at the end
+ * of the match, otherwise continue one position
+ * forward.
+ */
+ if (vim_strchr(p_cpo, CPO_SEARCH) != NULL)
+ {
+ if (nmatched > 1)
+ {
+ /* end is in next line, thus no match in
+ * this line */
+ match_ok = FALSE;
+ break;
+ }
+ matchcol = endpos.col;
+ /* for empty match: advance one char */
+ if (matchcol == matchpos.col
+ && ptr[matchcol] != NUL)
+ {
+ if (has_mbyte)
+ matchcol +=
+ (*mb_ptr2len)(ptr + matchcol);
+ else
+ ++matchcol;
+ }
+ }
+ else
+ {
+ matchcol = matchpos.col;
+ if (ptr[matchcol] != NUL)
+ {
+ if (has_mbyte)
+ matchcol += (*mb_ptr2len)(ptr
+ + matchcol);
+ else
+ ++matchcol;
+ }
+ }
+ if (matchcol == 0 && (options & SEARCH_START))
+ break;
+ if (ptr[matchcol] == NUL
+ || (nmatched = vim_regexec_multi(&regmatch,
+ win, buf, lnum + matchpos.lnum,
+ matchcol,
+#ifdef FEAT_RELTIME
+ tm, timed_out
+#else
+ NULL, NULL
+#endif
+ )) == 0)
+ {
+ match_ok = FALSE;
+ break;
+ }
+ matchpos = regmatch.startpos[0];
+ endpos = regmatch.endpos[0];
+# ifdef FEAT_EVAL
+ submatch = first_submatch(&regmatch);
+# endif
+
+ /* Need to get the line pointer again, a
+ * multi-line search may have made it invalid. */
+ ptr = ml_get_buf(buf, lnum + matchpos.lnum, FALSE);
+ }
+ if (!match_ok)
+ continue;
+ }
+ if (dir == BACKWARD)
+ {
+ /*
+ * Now, if there are multiple matches on this line,
+ * we have to get the last one. Or the last one before
+ * the cursor, if we're on that line.
+ * When putting the new cursor at the end, compare
+ * relative to the end of the match.
+ */
+ match_ok = FALSE;
+ for (;;)
+ {
+ /* Remember a position that is before the start
+ * position, we use it if it's the last match in
+ * the line. Always accept a position after
+ * wrapping around. */
+ if (loop
+ || ((options & SEARCH_END)
+ ? (lnum + regmatch.endpos[0].lnum
+ < start_pos.lnum
+ || (lnum + regmatch.endpos[0].lnum
+ == start_pos.lnum
+ && (int)regmatch.endpos[0].col - 1
+ < (int)start_pos.col
+ + extra_col))
+ : (lnum + regmatch.startpos[0].lnum
+ < start_pos.lnum
+ || (lnum + regmatch.startpos[0].lnum
+ == start_pos.lnum
+ && (int)regmatch.startpos[0].col
+ < (int)start_pos.col
+ + extra_col))))
+ {
+ match_ok = TRUE;
+ matchpos = regmatch.startpos[0];
+ endpos = regmatch.endpos[0];
+# ifdef FEAT_EVAL
+ submatch = first_submatch(&regmatch);
+# endif
+ }
+ else
+ break;
+
+ /*
+ * We found a valid match, now check if there is
+ * another one after it.
+ * If vi-compatible searching, continue at the end
+ * of the match, otherwise continue one position
+ * forward.
+ */
+ if (vim_strchr(p_cpo, CPO_SEARCH) != NULL)
+ {
+ if (nmatched > 1)
+ break;
+ matchcol = endpos.col;
+ /* for empty match: advance one char */
+ if (matchcol == matchpos.col
+ && ptr[matchcol] != NUL)
+ {
+ if (has_mbyte)
+ matchcol +=
+ (*mb_ptr2len)(ptr + matchcol);
+ else
+ ++matchcol;
+ }
+ }
+ else
+ {
+ /* Stop when the match is in a next line. */
+ if (matchpos.lnum > 0)
+ break;
+ matchcol = matchpos.col;
+ if (ptr[matchcol] != NUL)
+ {
+ if (has_mbyte)
+ matchcol +=
+ (*mb_ptr2len)(ptr + matchcol);
+ else
+ ++matchcol;
+ }
+ }
+ if (ptr[matchcol] == NUL
+ || (nmatched = vim_regexec_multi(&regmatch,
+ win, buf, lnum + matchpos.lnum,
+ matchcol,
+#ifdef FEAT_RELTIME
+ tm, timed_out
+#else
+ NULL, NULL
+#endif
+ )) == 0)
+ {
+#ifdef FEAT_RELTIME
+ /* If the search timed out, we did find a match
+ * but it might be the wrong one, so that's not
+ * OK. */
+ if (timed_out != NULL && *timed_out)
+ match_ok = FALSE;
+#endif
+ break;
+ }
+
+ /* Need to get the line pointer again, a
+ * multi-line search may have made it invalid. */
+ ptr = ml_get_buf(buf, lnum + matchpos.lnum, FALSE);
+ }
+
+ /*
+ * If there is only a match after the cursor, skip
+ * this match.
+ */
+ if (!match_ok)
+ continue;
+ }
+
+ /* With the SEARCH_END option move to the last character
+ * of the match. Don't do it for an empty match, end
+ * should be same as start then. */
+ if ((options & SEARCH_END) && !(options & SEARCH_NOOF)
+ && !(matchpos.lnum == endpos.lnum
+ && matchpos.col == endpos.col))
+ {
+ /* For a match in the first column, set the position
+ * on the NUL in the previous line. */
+ pos->lnum = lnum + endpos.lnum;
+ pos->col = endpos.col;
+ if (endpos.col == 0)
+ {
+ if (pos->lnum > 1) /* just in case */
+ {
+ --pos->lnum;
+ pos->col = (colnr_T)STRLEN(ml_get_buf(buf,
+ pos->lnum, FALSE));
+ }
+ }
+ else
+ {
+ --pos->col;
+ if (has_mbyte
+ && pos->lnum <= buf->b_ml.ml_line_count)
+ {
+ ptr = ml_get_buf(buf, pos->lnum, FALSE);
+ pos->col -= (*mb_head_off)(ptr, ptr + pos->col);
+ }
+ }
+ if (end_pos != NULL)
+ {
+ end_pos->lnum = lnum + matchpos.lnum;
+ end_pos->col = matchpos.col;
+ }
+ }
+ else
+ {
+ pos->lnum = lnum + matchpos.lnum;
+ pos->col = matchpos.col;
+ if (end_pos != NULL)
+ {
+ end_pos->lnum = lnum + endpos.lnum;
+ end_pos->col = endpos.col;
+ }
+ }
+ pos->coladd = 0;
+ if (end_pos != NULL)
+ end_pos->coladd = 0;
+ found = 1;
+ first_match = FALSE;
+
+ /* Set variables used for 'incsearch' highlighting. */
+ search_match_lines = endpos.lnum - matchpos.lnum;
+ search_match_endcol = endpos.col;
+ break;
+ }
+ line_breakcheck(); /* stop if ctrl-C typed */
+ if (got_int)
+ break;
+
+#ifdef FEAT_SEARCH_EXTRA
+ /* Cancel searching if a character was typed. Used for
+ * 'incsearch'. Don't check too often, that would slowdown
+ * searching too much. */
+ if ((options & SEARCH_PEEK)
+ && ((lnum - pos->lnum) & 0x3f) == 0
+ && char_avail())
+ {
+ break_loop = TRUE;
+ break;
+ }
+#endif
+
+ if (loop && lnum == start_pos.lnum)
+ break; /* if second loop, stop where started */
+ }
+ at_first_line = FALSE;
+
+ /*
+ * Stop the search if wrapscan isn't set, "stop_lnum" is
+ * specified, after an interrupt, after a match and after looping
+ * twice.
+ */
+ if (!p_ws || stop_lnum != 0 || got_int || called_emsg
+#ifdef FEAT_RELTIME
+ || (timed_out != NULL && *timed_out)
+#endif
+#ifdef FEAT_SEARCH_EXTRA
+ || break_loop
+#endif
+ || found || loop)
+ break;
+
+ /*
+ * If 'wrapscan' is set we continue at the other end of the file.
+ * If 'shortmess' does not contain 's', we give a message.
+ * This message is also remembered in keep_msg for when the screen
+ * is redrawn. The keep_msg is cleared whenever another message is
+ * written.
+ */
+ if (dir == BACKWARD) /* start second loop at the other end */
+ lnum = buf->b_ml.ml_line_count;
+ else
+ lnum = 1;
+ if (!shortmess(SHM_SEARCH) && (options & SEARCH_MSG))
+ give_warning((char_u *)_(dir == BACKWARD
+ ? top_bot_msg : bot_top_msg), TRUE);
+ }
+ if (got_int || called_emsg
+#ifdef FEAT_RELTIME
+ || (timed_out != NULL && *timed_out)
+#endif
+#ifdef FEAT_SEARCH_EXTRA
+ || break_loop
+#endif
+ )
+ break;
+ }
+ while (--count > 0 && found); /* stop after count matches or no match */
+
+ vim_regfree(regmatch.regprog);
+
+ called_emsg |= save_called_emsg;
+
+ if (!found) /* did not find it */
+ {
+ if (got_int)
+ emsg(_(e_interr));
+ else if ((options & SEARCH_MSG) == SEARCH_MSG)
+ {
+ if (p_ws)
+ semsg(_(e_patnotf2), mr_pattern);
+ else if (lnum == 0)
+ semsg(_("E384: search hit TOP without match for: %s"),
+ mr_pattern);
+ else
+ semsg(_("E385: search hit BOTTOM without match for: %s"),
+ mr_pattern);
+ }
+ return FAIL;
+ }
+
+ /* A pattern like "\n\zs" may go past the last line. */
+ if (pos->lnum > buf->b_ml.ml_line_count)
+ {
+ pos->lnum = buf->b_ml.ml_line_count;
+ pos->col = (int)STRLEN(ml_get_buf(buf, pos->lnum, FALSE));
+ if (pos->col > 0)
+ --pos->col;
+ }
+
+ return submatch + 1;
+}
+
+#ifdef FEAT_EVAL
+ void
+set_search_direction(int cdir)
+{
+ spats[0].off.dir = cdir;
+}
+
+ static void
+set_vv_searchforward(void)
+{
+ set_vim_var_nr(VV_SEARCHFORWARD, (long)(spats[0].off.dir == '/'));
+}
+
+/*
+ * Return the number of the first subpat that matched.
+ * Return zero if none of them matched.
+ */
+ static int
+first_submatch(regmmatch_T *rp)
+{
+ int submatch;
+
+ for (submatch = 1; ; ++submatch)
+ {
+ if (rp->startpos[submatch].lnum >= 0)
+ break;
+ if (submatch == 9)
+ {
+ submatch = 0;
+ break;
+ }
+ }
+ return submatch;
+}
+#endif
+
+/*
+ * Highest level string search function.
+ * Search for the 'count'th occurrence of pattern 'pat' in direction 'dirc'
+ * If 'dirc' is 0: use previous dir.
+ * If 'pat' is NULL or empty : use previous string.
+ * If 'options & SEARCH_REV' : go in reverse of previous dir.
+ * If 'options & SEARCH_ECHO': echo the search command and handle options
+ * If 'options & SEARCH_MSG' : may give error message
+ * If 'options & SEARCH_OPT' : interpret optional flags
+ * If 'options & SEARCH_HIS' : put search pattern in history
+ * If 'options & SEARCH_NOOF': don't add offset to position
+ * If 'options & SEARCH_MARK': set previous context mark
+ * If 'options & SEARCH_KEEP': keep previous search pattern
+ * If 'options & SEARCH_START': accept match at curpos itself
+ * If 'options & SEARCH_PEEK': check for typed char, cancel search
+ *
+ * Careful: If spats[0].off.line == TRUE and spats[0].off.off == 0 this
+ * makes the movement linewise without moving the match position.
+ *
+ * Return 0 for failure, 1 for found, 2 for found and line offset added.
+ */
+ int
+do_search(
+ oparg_T *oap, /* can be NULL */
+ int dirc, /* '/' or '?' */
+ char_u *pat,
+ long count,
+ int options,
+ proftime_T *tm, /* timeout limit or NULL */
+ int *timed_out) /* flag set on timeout or NULL */
+{
+ pos_T pos; /* position of the last match */
+ char_u *searchstr;
+ struct soffset old_off;
+ int retval; /* Return value */
+ char_u *p;
+ long c;
+ char_u *dircp;
+ char_u *strcopy = NULL;
+ char_u *ps;
+
+ /*
+ * A line offset is not remembered, this is vi compatible.
+ */
+ if (spats[0].off.line && vim_strchr(p_cpo, CPO_LINEOFF) != NULL)
+ {
+ spats[0].off.line = FALSE;
+ spats[0].off.off = 0;
+ }
+
+ /*
+ * Save the values for when (options & SEARCH_KEEP) is used.
+ * (there is no "if ()" around this because gcc wants them initialized)
+ */
+ old_off = spats[0].off;
+
+ pos = curwin->w_cursor; /* start searching at the cursor position */
+
+ /*
+ * Find out the direction of the search.
+ */
+ if (dirc == 0)
+ dirc = spats[0].off.dir;
+ else
+ {
+ spats[0].off.dir = dirc;
+#if defined(FEAT_EVAL)
+ set_vv_searchforward();
+#endif
+ }
+ if (options & SEARCH_REV)
+ {
+#ifdef WIN32
+ /* There is a bug in the Visual C++ 2.2 compiler which means that
+ * dirc always ends up being '/' */
+ dirc = (dirc == '/') ? '?' : '/';
+#else
+ if (dirc == '/')
+ dirc = '?';
+ else
+ dirc = '/';
+#endif
+ }
+
+#ifdef FEAT_FOLDING
+ /* If the cursor is in a closed fold, don't find another match in the same
+ * fold. */
+ if (dirc == '/')
+ {
+ if (hasFolding(pos.lnum, NULL, &pos.lnum))
+ pos.col = MAXCOL - 2; /* avoid overflow when adding 1 */
+ }
+ else
+ {
+ if (hasFolding(pos.lnum, &pos.lnum, NULL))
+ pos.col = 0;
+ }
+#endif
+
+#ifdef FEAT_SEARCH_EXTRA
+ /*
+ * Turn 'hlsearch' highlighting back on.
+ */
+ if (no_hlsearch && !(options & SEARCH_KEEP))
+ {
+ redraw_all_later(SOME_VALID);
+ set_no_hlsearch(FALSE);
+ }
+#endif
+
+ /*
+ * Repeat the search when pattern followed by ';', e.g. "/foo/;?bar".
+ */
+ for (;;)
+ {
+ searchstr = pat;
+ dircp = NULL;
+ /* use previous pattern */
+ if (pat == NULL || *pat == NUL || *pat == dirc)
+ {
+ if (spats[RE_SEARCH].pat == NULL) /* no previous pattern */
+ {
+ searchstr = spats[RE_SUBST].pat;
+ if (searchstr == NULL)
+ {
+ emsg(_(e_noprevre));
+ retval = 0;
+ goto end_do_search;
+ }
+ }
+ else
+ {
+ /* make search_regcomp() use spats[RE_SEARCH].pat */
+ searchstr = (char_u *)"";
+ }
+ }
+
+ if (pat != NULL && *pat != NUL) /* look for (new) offset */
+ {
+ /*
+ * Find end of regular expression.
+ * If there is a matching '/' or '?', toss it.
+ */
+ ps = strcopy;
+ p = skip_regexp(pat, dirc, (int)p_magic, &strcopy);
+ if (strcopy != ps)
+ {
+ /* made a copy of "pat" to change "\?" to "?" */
+ searchcmdlen += (int)(STRLEN(pat) - STRLEN(strcopy));
+ pat = strcopy;
+ searchstr = strcopy;
+ }
+ if (*p == dirc)
+ {
+ dircp = p; /* remember where we put the NUL */
+ *p++ = NUL;
+ }
+ spats[0].off.line = FALSE;
+ spats[0].off.end = FALSE;
+ spats[0].off.off = 0;
+ /*
+ * Check for a line offset or a character offset.
+ * For get_address (echo off) we don't check for a character
+ * offset, because it is meaningless and the 's' could be a
+ * substitute command.
+ */
+ if (*p == '+' || *p == '-' || VIM_ISDIGIT(*p))
+ spats[0].off.line = TRUE;
+ else if ((options & SEARCH_OPT) &&
+ (*p == 'e' || *p == 's' || *p == 'b'))
+ {
+ if (*p == 'e') /* end */
+ spats[0].off.end = SEARCH_END;
+ ++p;
+ }
+ if (VIM_ISDIGIT(*p) || *p == '+' || *p == '-') /* got an offset */
+ {
+ /* 'nr' or '+nr' or '-nr' */
+ if (VIM_ISDIGIT(*p) || VIM_ISDIGIT(*(p + 1)))
+ spats[0].off.off = atol((char *)p);
+ else if (*p == '-') /* single '-' */
+ spats[0].off.off = -1;
+ else /* single '+' */
+ spats[0].off.off = 1;
+ ++p;
+ while (VIM_ISDIGIT(*p)) /* skip number */
+ ++p;
+ }
+
+ /* compute length of search command for get_address() */
+ searchcmdlen += (int)(p - pat);
+
+ pat = p; /* put pat after search command */
+ }
+
+ if ((options & SEARCH_ECHO) && messaging()
+ && !cmd_silent && msg_silent == 0)
+ {
+ char_u *msgbuf;
+ char_u *trunc;
+
+ if (*searchstr == NUL)
+ p = spats[0].pat;
+ else
+ p = searchstr;
+ msgbuf = alloc((unsigned)(STRLEN(p) + 40));
+ if (msgbuf != NULL)
+ {
+ msgbuf[0] = dirc;
+ if (enc_utf8 && utf_iscomposing(utf_ptr2char(p)))
+ {
+ /* Use a space to draw the composing char on. */
+ msgbuf[1] = ' ';
+ STRCPY(msgbuf + 2, p);
+ }
+ else
+ STRCPY(msgbuf + 1, p);
+ if (spats[0].off.line || spats[0].off.end || spats[0].off.off)
+ {
+ p = msgbuf + STRLEN(msgbuf);
+ *p++ = dirc;
+ if (spats[0].off.end)
+ *p++ = 'e';
+ else if (!spats[0].off.line)
+ *p++ = 's';
+ if (spats[0].off.off > 0 || spats[0].off.line)
+ *p++ = '+';
+ if (spats[0].off.off != 0 || spats[0].off.line)
+ sprintf((char *)p, "%ld", spats[0].off.off);
+ else
+ *p = NUL;
+ }
+
+ msg_start();
+ trunc = msg_strtrunc(msgbuf, FALSE);
+
+#ifdef FEAT_RIGHTLEFT
+ /* The search pattern could be shown on the right in rightleft
+ * mode, but the 'ruler' and 'showcmd' area use it too, thus
+ * it would be blanked out again very soon. Show it on the
+ * left, but do reverse the text. */
+ if (curwin->w_p_rl && *curwin->w_p_rlc == 's')
+ {
+ char_u *r;
+
+ r = reverse_text(trunc != NULL ? trunc : msgbuf);
+ if (r != NULL)
+ {
+ vim_free(trunc);
+ trunc = r;
+ }
+ }
+#endif
+ if (trunc != NULL)
+ {
+ msg_outtrans(trunc);
+ vim_free(trunc);
+ }
+ else
+ msg_outtrans(msgbuf);
+ msg_clr_eos();
+ msg_check();
+ vim_free(msgbuf);
+
+ gotocmdline(FALSE);
+ out_flush();
+ msg_nowait = TRUE; /* don't wait for this message */
+ }
+ }
+
+ /*
+ * If there is a character offset, subtract it from the current
+ * position, so we don't get stuck at "?pat?e+2" or "/pat/s-2".
+ * Skip this if pos.col is near MAXCOL (closed fold).
+ * This is not done for a line offset, because then we would not be vi
+ * compatible.
+ */
+ if (!spats[0].off.line && spats[0].off.off && pos.col < MAXCOL - 2)
+ {
+ if (spats[0].off.off > 0)
+ {
+ for (c = spats[0].off.off; c; --c)
+ if (decl(&pos) == -1)
+ break;
+ if (c) /* at start of buffer */
+ {
+ pos.lnum = 0; /* allow lnum == 0 here */
+ pos.col = MAXCOL;
+ }
+ }
+ else
+ {
+ for (c = spats[0].off.off; c; ++c)
+ if (incl(&pos) == -1)
+ break;
+ if (c) /* at end of buffer */
+ {
+ pos.lnum = curbuf->b_ml.ml_line_count + 1;
+ pos.col = 0;
+ }
+ }
+ }
+
+#ifdef FEAT_FKMAP /* when in Farsi mode, reverse the character flow */
+ if (p_altkeymap && curwin->w_p_rl)
+ lrFswap(searchstr,0);
+#endif
+
+ c = searchit(curwin, curbuf, &pos, NULL, dirc == '/' ? FORWARD : BACKWARD,
+ searchstr, count, spats[0].off.end + (options &
+ (SEARCH_KEEP + SEARCH_PEEK + SEARCH_HIS
+ + SEARCH_MSG + SEARCH_START
+ + ((pat != NULL && *pat == ';') ? 0 : SEARCH_NOOF))),
+ RE_LAST, (linenr_T)0, tm, timed_out);
+
+ if (dircp != NULL)
+ *dircp = dirc; /* restore second '/' or '?' for normal_cmd() */
+ if (c == FAIL)
+ {
+ retval = 0;
+ goto end_do_search;
+ }
+ if (spats[0].off.end && oap != NULL)
+ oap->inclusive = TRUE; /* 'e' includes last character */
+
+ retval = 1; /* pattern found */
+
+ /*
+ * Add character and/or line offset
+ */
+ if (!(options & SEARCH_NOOF) || (pat != NULL && *pat == ';'))
+ {
+ if (spats[0].off.line) /* Add the offset to the line number. */
+ {
+ c = pos.lnum + spats[0].off.off;
+ if (c < 1)
+ pos.lnum = 1;
+ else if (c > curbuf->b_ml.ml_line_count)
+ pos.lnum = curbuf->b_ml.ml_line_count;
+ else
+ pos.lnum = c;
+ pos.col = 0;
+
+ retval = 2; /* pattern found, line offset added */
+ }
+ else if (pos.col < MAXCOL - 2) /* just in case */
+ {
+ /* to the right, check for end of file */
+ c = spats[0].off.off;
+ if (c > 0)
+ {
+ while (c-- > 0)
+ if (incl(&pos) == -1)
+ break;
+ }
+ /* to the left, check for start of file */
+ else
+ {
+ while (c++ < 0)
+ if (decl(&pos) == -1)
+ break;
+ }
+ }
+ }
+
+ /*
+ * The search command can be followed by a ';' to do another search.
+ * For example: "/pat/;/foo/+3;?bar"
+ * This is like doing another search command, except:
+ * - The remembered direction '/' or '?' is from the first search.
+ * - When an error happens the cursor isn't moved at all.
+ * Don't do this when called by get_address() (it handles ';' itself).
+ */
+ if (!(options & SEARCH_OPT) || pat == NULL || *pat != ';')
+ break;
+
+ dirc = *++pat;
+ if (dirc != '?' && dirc != '/')
+ {
+ retval = 0;
+ emsg(_("E386: Expected '?' or '/' after ';'"));
+ goto end_do_search;
+ }
+ ++pat;
+ }
+
+ if (options & SEARCH_MARK)
+ setpcmark();
+ curwin->w_cursor = pos;
+ curwin->w_set_curswant = TRUE;
+
+end_do_search:
+ if ((options & SEARCH_KEEP) || cmdmod.keeppatterns)
+ spats[0].off = old_off;
+ vim_free(strcopy);
+
+ return retval;
+}
+
+#if defined(FEAT_INS_EXPAND) || defined(PROTO)
+/*
+ * search_for_exact_line(buf, pos, dir, pat)
+ *
+ * Search for a line starting with the given pattern (ignoring leading
+ * white-space), starting from pos and going in direction "dir". "pos" will
+ * contain the position of the match found. Blank lines match only if
+ * ADDING is set. If p_ic is set then the pattern must be in lowercase.
+ * Return OK for success, or FAIL if no line found.
+ */
+ int
+search_for_exact_line(
+ buf_T *buf,
+ pos_T *pos,
+ int dir,
+ char_u *pat)
+{
+ linenr_T start = 0;
+ char_u *ptr;
+ char_u *p;
+
+ if (buf->b_ml.ml_line_count == 0)
+ return FAIL;
+ for (;;)
+ {
+ pos->lnum += dir;
+ if (pos->lnum < 1)
+ {
+ if (p_ws)
+ {
+ pos->lnum = buf->b_ml.ml_line_count;
+ if (!shortmess(SHM_SEARCH))
+ give_warning((char_u *)_(top_bot_msg), TRUE);
+ }
+ else
+ {
+ pos->lnum = 1;
+ break;
+ }
+ }
+ else if (pos->lnum > buf->b_ml.ml_line_count)
+ {
+ if (p_ws)
+ {
+ pos->lnum = 1;
+ if (!shortmess(SHM_SEARCH))
+ give_warning((char_u *)_(bot_top_msg), TRUE);
+ }
+ else
+ {
+ pos->lnum = 1;
+ break;
+ }
+ }
+ if (pos->lnum == start)
+ break;
+ if (start == 0)
+ start = pos->lnum;
+ ptr = ml_get_buf(buf, pos->lnum, FALSE);
+ p = skipwhite(ptr);
+ pos->col = (colnr_T) (p - ptr);
+
+ /* when adding lines the matching line may be empty but it is not
+ * ignored because we are interested in the next line -- Acevedo */
+ if ((compl_cont_status & CONT_ADDING)
+ && !(compl_cont_status & CONT_SOL))
+ {
+ if ((p_ic ? MB_STRICMP(p, pat) : STRCMP(p, pat)) == 0)
+ return OK;
+ }
+ else if (*p != NUL) /* ignore empty lines */
+ { /* expanding lines or words */
+ if ((p_ic ? MB_STRNICMP(p, pat, compl_length)
+ : STRNCMP(p, pat, compl_length)) == 0)
+ return OK;
+ }
+ }
+ return FAIL;
+}
+#endif /* FEAT_INS_EXPAND */
+
+/*
+ * Character Searches
+ */
+
+/*
+ * Search for a character in a line. If "t_cmd" is FALSE, move to the
+ * position of the character, otherwise move to just before the char.
+ * Do this "cap->count1" times.
+ * Return FAIL or OK.
+ */
+ int
+searchc(cmdarg_T *cap, int t_cmd)
+{
+ int c = cap->nchar; /* char to search for */
+ int dir = cap->arg; /* TRUE for searching forward */
+ long count = cap->count1; /* repeat count */
+ int col;
+ char_u *p;
+ int len;
+ int stop = TRUE;
+
+ if (c != NUL) /* normal search: remember args for repeat */
+ {
+ if (!KeyStuffed) /* don't remember when redoing */
+ {
+ *lastc = c;
+ set_csearch_direction(dir);
+ set_csearch_until(t_cmd);
+ lastc_bytelen = (*mb_char2bytes)(c, lastc_bytes);
+ if (cap->ncharC1 != 0)
+ {
+ lastc_bytelen += (*mb_char2bytes)(cap->ncharC1,
+ lastc_bytes + lastc_bytelen);
+ if (cap->ncharC2 != 0)
+ lastc_bytelen += (*mb_char2bytes)(cap->ncharC2,
+ lastc_bytes + lastc_bytelen);
+ }
+ }
+ }
+ else /* repeat previous search */
+ {
+ if (*lastc == NUL && lastc_bytelen == 1)
+ return FAIL;
+ if (dir) /* repeat in opposite direction */
+ dir = -lastcdir;
+ else
+ dir = lastcdir;
+ t_cmd = last_t_cmd;
+ c = *lastc;
+ /* For multi-byte re-use last lastc_bytes[] and lastc_bytelen. */
+
+ /* Force a move of at least one char, so ";" and "," will move the
+ * cursor, even if the cursor is right in front of char we are looking
+ * at. */
+ if (vim_strchr(p_cpo, CPO_SCOLON) == NULL && count == 1 && t_cmd)
+ stop = FALSE;
+ }
+
+ if (dir == BACKWARD)
+ cap->oap->inclusive = FALSE;
+ else
+ cap->oap->inclusive = TRUE;
+
+ p = ml_get_curline();
+ col = curwin->w_cursor.col;
+ len = (int)STRLEN(p);
+
+ while (count--)
+ {
+ if (has_mbyte)
+ {
+ for (;;)
+ {
+ if (dir > 0)
+ {
+ col += (*mb_ptr2len)(p + col);
+ if (col >= len)
+ return FAIL;
+ }
+ else
+ {
+ if (col == 0)
+ return FAIL;
+ col -= (*mb_head_off)(p, p + col - 1) + 1;
+ }
+ if (lastc_bytelen == 1)
+ {
+ if (p[col] == c && stop)
+ break;
+ }
+ else if (STRNCMP(p + col, lastc_bytes, lastc_bytelen) == 0
+ && stop)
+ break;
+ stop = TRUE;
+ }
+ }
+ else
+ {
+ for (;;)
+ {
+ if ((col += dir) < 0 || col >= len)
+ return FAIL;
+ if (p[col] == c && stop)
+ break;
+ stop = TRUE;
+ }
+ }
+ }
+
+ if (t_cmd)
+ {
+ /* backup to before the character (possibly double-byte) */
+ col -= dir;
+ if (has_mbyte)
+ {
+ if (dir < 0)
+ /* Landed on the search char which is lastc_bytelen long */
+ col += lastc_bytelen - 1;
+ else
+ /* To previous char, which may be multi-byte. */
+ col -= (*mb_head_off)(p, p + col);
+ }
+ }
+ curwin->w_cursor.col = col;
+
+ return OK;
+}
+
+/*
+ * "Other" Searches
+ */
+
+/*
+ * findmatch - find the matching paren or brace
+ *
+ * Improvement over vi: Braces inside quotes are ignored.
+ */
+ pos_T *
+findmatch(oparg_T *oap, int initc)
+{
+ return findmatchlimit(oap, initc, 0, 0);
+}
+
+/*
+ * Return TRUE if the character before "linep[col]" equals "ch".
+ * Return FALSE if "col" is zero.
+ * Update "*prevcol" to the column of the previous character, unless "prevcol"
+ * is NULL.
+ * Handles multibyte string correctly.
+ */
+ static int
+check_prevcol(
+ char_u *linep,
+ int col,
+ int ch,
+ int *prevcol)
+{
+ --col;
+ if (col > 0 && has_mbyte)
+ col -= (*mb_head_off)(linep, linep + col);
+ if (prevcol)
+ *prevcol = col;
+ return (col >= 0 && linep[col] == ch) ? TRUE : FALSE;
+}
+
+/*
+ * Raw string start is found at linep[startpos.col - 1].
+ * Return TRUE if the matching end can be found between startpos and endpos.
+ */
+ static int
+find_rawstring_end(char_u *linep, pos_T *startpos, pos_T *endpos)
+{
+ char_u *p;
+ char_u *delim_copy;
+ size_t delim_len;
+ linenr_T lnum;
+ int found = FALSE;
+
+ for (p = linep + startpos->col + 1; *p && *p != '('; ++p)
+ ;
+ delim_len = (p - linep) - startpos->col - 1;
+ delim_copy = vim_strnsave(linep + startpos->col + 1, (int)delim_len);
+ if (delim_copy == NULL)
+ return FALSE;
+ for (lnum = startpos->lnum; lnum <= endpos->lnum; ++lnum)
+ {
+ char_u *line = ml_get(lnum);
+
+ for (p = line + (lnum == startpos->lnum
+ ? startpos->col + 1 : 0); *p; ++p)
+ {
+ if (lnum == endpos->lnum && (colnr_T)(p - line) >= endpos->col)
+ break;
+ if (*p == ')' && p[delim_len + 1] == '"'
+ && STRNCMP(delim_copy, p + 1, delim_len) == 0)
+ {
+ found = TRUE;
+ break;
+ }
+ }
+ if (found)
+ break;
+ }
+ vim_free(delim_copy);
+ return found;
+}
+
+/*
+ * findmatchlimit -- find the matching paren or brace, if it exists within
+ * maxtravel lines of the cursor. A maxtravel of 0 means search until falling
+ * off the edge of the file.
+ *
+ * "initc" is the character to find a match for. NUL means to find the
+ * character at or after the cursor. Special values:
+ * '*' look for C-style comment / *
+ * '/' look for C-style comment / *, ignoring comment-end
+ * '#' look for preprocessor directives
+ * 'R' look for raw string start: R"delim(text)delim" (only backwards)
+ *
+ * flags: FM_BACKWARD search backwards (when initc is '/', '*' or '#')
+ * FM_FORWARD search forwards (when initc is '/', '*' or '#')
+ * FM_BLOCKSTOP stop at start/end of block ({ or } in column 0)
+ * FM_SKIPCOMM skip comments (not implemented yet!)
+ *
+ * "oap" is only used to set oap->motion_type for a linewise motion, it can be
+ * NULL
+ */
+
+ pos_T *
+findmatchlimit(
+ oparg_T *oap,
+ int initc,
+ int flags,
+ int maxtravel)
+{
+ static pos_T pos; /* current search position */
+ int findc = 0; /* matching brace */
+ int c;
+ int count = 0; /* cumulative number of braces */
+ int backwards = FALSE; /* init for gcc */
+ int raw_string = FALSE; /* search for raw string */
+ int inquote = FALSE; /* TRUE when inside quotes */
+ char_u *linep; /* pointer to current line */
+ char_u *ptr;
+ int do_quotes; /* check for quotes in current line */
+ int at_start; /* do_quotes value at start position */
+ int hash_dir = 0; /* Direction searched for # things */
+ int comment_dir = 0; /* Direction searched for comments */
+ pos_T match_pos; /* Where last slash-star was found */
+ int start_in_quotes; /* start position is in quotes */
+ int traveled = 0; /* how far we've searched so far */
+ int ignore_cend = FALSE; /* ignore comment end */
+ int cpo_match; /* vi compatible matching */
+ int cpo_bsl; /* don't recognize backslashes */
+ int match_escaped = 0; /* search for escaped match */
+ int dir; /* Direction to search */
+ int comment_col = MAXCOL; /* start of / / comment */
+#ifdef FEAT_LISP
+ int lispcomm = FALSE; /* inside of Lisp-style comment */
+ int lisp = curbuf->b_p_lisp; /* engage Lisp-specific hacks ;) */
+#endif
+
+ pos = curwin->w_cursor;
+ pos.coladd = 0;
+ linep = ml_get(pos.lnum);
+
+ cpo_match = (vim_strchr(p_cpo, CPO_MATCH) != NULL);
+ cpo_bsl = (vim_strchr(p_cpo, CPO_MATCHBSL) != NULL);
+
+ /* Direction to search when initc is '/', '*' or '#' */
+ if (flags & FM_BACKWARD)
+ dir = BACKWARD;
+ else if (flags & FM_FORWARD)
+ dir = FORWARD;
+ else
+ dir = 0;
+
+ /*
+ * if initc given, look in the table for the matching character
+ * '/' and '*' are special cases: look for start or end of comment.
+ * When '/' is used, we ignore running backwards into an star-slash, for
+ * "[*" command, we just want to find any comment.
+ */
+ if (initc == '/' || initc == '*' || initc == 'R')
+ {
+ comment_dir = dir;
+ if (initc == '/')
+ ignore_cend = TRUE;
+ backwards = (dir == FORWARD) ? FALSE : TRUE;
+ raw_string = (initc == 'R');
+ initc = NUL;
+ }
+ else if (initc != '#' && initc != NUL)
+ {
+ find_mps_values(&initc, &findc, &backwards, TRUE);
+ if (findc == NUL)
+ return NULL;
+ }
+ else
+ {
+ /*
+ * Either initc is '#', or no initc was given and we need to look
+ * under the cursor.
+ */
+ if (initc == '#')
+ {
+ hash_dir = dir;
+ }
+ else
+ {
+ /*
+ * initc was not given, must look for something to match under
+ * or near the cursor.
+ * Only check for special things when 'cpo' doesn't have '%'.
+ */
+ if (!cpo_match)
+ {
+ /* Are we before or at #if, #else etc.? */
+ ptr = skipwhite(linep);
+ if (*ptr == '#' && pos.col <= (colnr_T)(ptr - linep))
+ {
+ ptr = skipwhite(ptr + 1);
+ if ( STRNCMP(ptr, "if", 2) == 0
+ || STRNCMP(ptr, "endif", 5) == 0
+ || STRNCMP(ptr, "el", 2) == 0)
+ hash_dir = 1;
+ }
+
+ /* Are we on a comment? */
+ else if (linep[pos.col] == '/')
+ {
+ if (linep[pos.col + 1] == '*')
+ {
+ comment_dir = FORWARD;
+ backwards = FALSE;
+ pos.col++;
+ }
+ else if (pos.col > 0 && linep[pos.col - 1] == '*')
+ {
+ comment_dir = BACKWARD;
+ backwards = TRUE;
+ pos.col--;
+ }
+ }
+ else if (linep[pos.col] == '*')
+ {
+ if (linep[pos.col + 1] == '/')
+ {
+ comment_dir = BACKWARD;
+ backwards = TRUE;
+ }
+ else if (pos.col > 0 && linep[pos.col - 1] == '/')
+ {
+ comment_dir = FORWARD;
+ backwards = FALSE;
+ }
+ }
+ }
+
+ /*
+ * If we are not on a comment or the # at the start of a line, then
+ * look for brace anywhere on this line after the cursor.
+ */
+ if (!hash_dir && !comment_dir)
+ {
+ /*
+ * Find the brace under or after the cursor.
+ * If beyond the end of the line, use the last character in
+ * the line.
+ */
+ if (linep[pos.col] == NUL && pos.col)
+ --pos.col;
+ for (;;)
+ {
+ initc = PTR2CHAR(linep + pos.col);
+ if (initc == NUL)
+ break;
+
+ find_mps_values(&initc, &findc, &backwards, FALSE);
+ if (findc)
+ break;
+ pos.col += MB_PTR2LEN(linep + pos.col);
+ }
+ if (!findc)
+ {
+ /* no brace in the line, maybe use " #if" then */
+ if (!cpo_match && *skipwhite(linep) == '#')
+ hash_dir = 1;
+ else
+ return NULL;
+ }
+ else if (!cpo_bsl)
+ {
+ int col, bslcnt = 0;
+
+ /* Set "match_escaped" if there are an odd number of
+ * backslashes. */
+ for (col = pos.col; check_prevcol(linep, col, '\\', &col);)
+ bslcnt++;
+ match_escaped = (bslcnt & 1);
+ }
+ }
+ }
+ if (hash_dir)
+ {
+ /*
+ * Look for matching #if, #else, #elif, or #endif
+ */
+ if (oap != NULL)
+ oap->motion_type = MLINE; /* Linewise for this case only */
+ if (initc != '#')
+ {
+ ptr = skipwhite(skipwhite(linep) + 1);
+ if (STRNCMP(ptr, "if", 2) == 0 || STRNCMP(ptr, "el", 2) == 0)
+ hash_dir = 1;
+ else if (STRNCMP(ptr, "endif", 5) == 0)
+ hash_dir = -1;
+ else
+ return NULL;
+ }
+ pos.col = 0;
+ while (!got_int)
+ {
+ if (hash_dir > 0)
+ {
+ if (pos.lnum == curbuf->b_ml.ml_line_count)
+ break;
+ }
+ else if (pos.lnum == 1)
+ break;
+ pos.lnum += hash_dir;
+ linep = ml_get(pos.lnum);
+ line_breakcheck(); /* check for CTRL-C typed */
+ ptr = skipwhite(linep);
+ if (*ptr != '#')
+ continue;
+ pos.col = (colnr_T) (ptr - linep);
+ ptr = skipwhite(ptr + 1);
+ if (hash_dir > 0)
+ {
+ if (STRNCMP(ptr, "if", 2) == 0)
+ count++;
+ else if (STRNCMP(ptr, "el", 2) == 0)
+ {
+ if (count == 0)
+ return &pos;
+ }
+ else if (STRNCMP(ptr, "endif", 5) == 0)
+ {
+ if (count == 0)
+ return &pos;
+ count--;
+ }
+ }
+ else
+ {
+ if (STRNCMP(ptr, "if", 2) == 0)
+ {
+ if (count == 0)
+ return &pos;
+ count--;
+ }
+ else if (initc == '#' && STRNCMP(ptr, "el", 2) == 0)
+ {
+ if (count == 0)
+ return &pos;
+ }
+ else if (STRNCMP(ptr, "endif", 5) == 0)
+ count++;
+ }
+ }
+ return NULL;
+ }
+ }
+
+#ifdef FEAT_RIGHTLEFT
+ /* This is just guessing: when 'rightleft' is set, search for a matching
+ * paren/brace in the other direction. */
+ if (curwin->w_p_rl && vim_strchr((char_u *)"()[]{}<>", initc) != NULL)
+ backwards = !backwards;
+#endif
+
+ do_quotes = -1;
+ start_in_quotes = MAYBE;
+ CLEAR_POS(&match_pos);
+
+ /* backward search: Check if this line contains a single-line comment */
+ if ((backwards && comment_dir)
+#ifdef FEAT_LISP
+ || lisp
+#endif
+ )
+ comment_col = check_linecomment(linep);
+#ifdef FEAT_LISP
+ if (lisp && comment_col != MAXCOL && pos.col > (colnr_T)comment_col)
+ lispcomm = TRUE; /* find match inside this comment */
+#endif
+ while (!got_int)
+ {
+ /*
+ * Go to the next position, forward or backward. We could use
+ * inc() and dec() here, but that is much slower
+ */
+ if (backwards)
+ {
+#ifdef FEAT_LISP
+ /* char to match is inside of comment, don't search outside */
+ if (lispcomm && pos.col < (colnr_T)comment_col)
+ break;
+#endif
+ if (pos.col == 0) /* at start of line, go to prev. one */
+ {
+ if (pos.lnum == 1) /* start of file */
+ break;
+ --pos.lnum;
+
+ if (maxtravel > 0 && ++traveled > maxtravel)
+ break;
+
+ linep = ml_get(pos.lnum);
+ pos.col = (colnr_T)STRLEN(linep); /* pos.col on trailing NUL */
+ do_quotes = -1;
+ line_breakcheck();
+
+ /* Check if this line contains a single-line comment */
+ if (comment_dir
+#ifdef FEAT_LISP
+ || lisp
+#endif
+ )
+ comment_col = check_linecomment(linep);
+#ifdef FEAT_LISP
+ /* skip comment */
+ if (lisp && comment_col != MAXCOL)
+ pos.col = comment_col;
+#endif
+ }
+ else
+ {
+ --pos.col;
+ if (has_mbyte)
+ pos.col -= (*mb_head_off)(linep, linep + pos.col);
+ }
+ }
+ else /* forward search */
+ {
+ if (linep[pos.col] == NUL
+ /* at end of line, go to next one */
+#ifdef FEAT_LISP
+ /* don't search for match in comment */
+ || (lisp && comment_col != MAXCOL
+ && pos.col == (colnr_T)comment_col)
+#endif
+ )
+ {
+ if (pos.lnum == curbuf->b_ml.ml_line_count /* end of file */
+#ifdef FEAT_LISP
+ /* line is exhausted and comment with it,
+ * don't search for match in code */
+ || lispcomm
+#endif
+ )
+ break;
+ ++pos.lnum;
+
+ if (maxtravel && traveled++ > maxtravel)
+ break;
+
+ linep = ml_get(pos.lnum);
+ pos.col = 0;
+ do_quotes = -1;
+ line_breakcheck();
+#ifdef FEAT_LISP
+ if (lisp) /* find comment pos in new line */
+ comment_col = check_linecomment(linep);
+#endif
+ }
+ else
+ {
+ if (has_mbyte)
+ pos.col += (*mb_ptr2len)(linep + pos.col);
+ else
+ ++pos.col;
+ }
+ }
+
+ /*
+ * If FM_BLOCKSTOP given, stop at a '{' or '}' in column 0.
+ */
+ if (pos.col == 0 && (flags & FM_BLOCKSTOP) &&
+ (linep[0] == '{' || linep[0] == '}'))
+ {
+ if (linep[0] == findc && count == 0) /* match! */
+ return &pos;
+ break; /* out of scope */
+ }
+
+ if (comment_dir)
+ {
+ /* Note: comments do not nest, and we ignore quotes in them */
+ /* TODO: ignore comment brackets inside strings */
+ if (comment_dir == FORWARD)
+ {
+ if (linep[pos.col] == '*' && linep[pos.col + 1] == '/')
+ {
+ pos.col++;
+ return &pos;
+ }
+ }
+ else /* Searching backwards */
+ {
+ /*
+ * A comment may contain / * or / /, it may also start or end
+ * with / * /. Ignore a / * after / / and after *.
+ */
+ if (pos.col == 0)
+ continue;
+ else if (raw_string)
+ {
+ if (linep[pos.col - 1] == 'R'
+ && linep[pos.col] == '"'
+ && vim_strchr(linep + pos.col + 1, '(') != NULL)
+ {
+ /* Possible start of raw string. Now that we have the
+ * delimiter we can check if it ends before where we
+ * started searching, or before the previously found
+ * raw string start. */
+ if (!find_rawstring_end(linep, &pos,
+ count > 0 ? &match_pos : &curwin->w_cursor))
+ {
+ count++;
+ match_pos = pos;
+ match_pos.col--;
+ }
+ linep = ml_get(pos.lnum); /* may have been released */
+ }
+ }
+ else if ( linep[pos.col - 1] == '/'
+ && linep[pos.col] == '*'
+ && (pos.col == 1 || linep[pos.col - 2] != '*')
+ && (int)pos.col < comment_col)
+ {
+ count++;
+ match_pos = pos;
+ match_pos.col--;
+ }
+ else if (linep[pos.col - 1] == '*' && linep[pos.col] == '/')
+ {
+ if (count > 0)
+ pos = match_pos;
+ else if (pos.col > 1 && linep[pos.col - 2] == '/'
+ && (int)pos.col <= comment_col)
+ pos.col -= 2;
+ else if (ignore_cend)
+ continue;
+ else
+ return NULL;
+ return &pos;
+ }
+ }
+ continue;
+ }
+
+ /*
+ * If smart matching ('cpoptions' does not contain '%'), braces inside
+ * of quotes are ignored, but only if there is an even number of
+ * quotes in the line.
+ */
+ if (cpo_match)
+ do_quotes = 0;
+ else if (do_quotes == -1)
+ {
+ /*
+ * Count the number of quotes in the line, skipping \" and '"'.
+ * Watch out for "\\".
+ */
+ at_start = do_quotes;
+ for (ptr = linep; *ptr; ++ptr)
+ {
+ if (ptr == linep + pos.col + backwards)
+ at_start = (do_quotes & 1);
+ if (*ptr == '"'
+ && (ptr == linep || ptr[-1] != '\'' || ptr[1] != '\''))
+ ++do_quotes;
+ if (*ptr == '\\' && ptr[1] != NUL)
+ ++ptr;
+ }
+ do_quotes &= 1; /* result is 1 with even number of quotes */
+
+ /*
+ * If we find an uneven count, check current line and previous
+ * one for a '\' at the end.
+ */
+ if (!do_quotes)
+ {
+ inquote = FALSE;
+ if (ptr[-1] == '\\')
+ {
+ do_quotes = 1;
+ if (start_in_quotes == MAYBE)
+ {
+ /* Do we need to use at_start here? */
+ inquote = TRUE;
+ start_in_quotes = TRUE;
+ }
+ else if (backwards)
+ inquote = TRUE;
+ }
+ if (pos.lnum > 1)
+ {
+ ptr = ml_get(pos.lnum - 1);
+ if (*ptr && *(ptr + STRLEN(ptr) - 1) == '\\')
+ {
+ do_quotes = 1;
+ if (start_in_quotes == MAYBE)
+ {
+ inquote = at_start;
+ if (inquote)
+ start_in_quotes = TRUE;
+ }
+ else if (!backwards)
+ inquote = TRUE;
+ }
+
+ /* ml_get() only keeps one line, need to get linep again */
+ linep = ml_get(pos.lnum);
+ }
+ }
+ }
+ if (start_in_quotes == MAYBE)
+ start_in_quotes = FALSE;
+
+ /*
+ * If 'smartmatch' is set:
+ * Things inside quotes are ignored by setting 'inquote'. If we
+ * find a quote without a preceding '\' invert 'inquote'. At the
+ * end of a line not ending in '\' we reset 'inquote'.
+ *
+ * In lines with an uneven number of quotes (without preceding '\')
+ * we do not know which part to ignore. Therefore we only set
+ * inquote if the number of quotes in a line is even, unless this
+ * line or the previous one ends in a '\'. Complicated, isn't it?
+ */
+ c = PTR2CHAR(linep + pos.col);
+ switch (c)
+ {
+ case NUL:
+ /* at end of line without trailing backslash, reset inquote */
+ if (pos.col == 0 || linep[pos.col - 1] != '\\')
+ {
+ inquote = FALSE;
+ start_in_quotes = FALSE;
+ }
+ break;
+
+ case '"':
+ /* a quote that is preceded with an odd number of backslashes is
+ * ignored */
+ if (do_quotes)
+ {
+ int col;
+
+ for (col = pos.col - 1; col >= 0; --col)
+ if (linep[col] != '\\')
+ break;
+ if ((((int)pos.col - 1 - col) & 1) == 0)
+ {
+ inquote = !inquote;
+ start_in_quotes = FALSE;
+ }
+ }
+ break;
+
+ /*
+ * If smart matching ('cpoptions' does not contain '%'):
+ * Skip things in single quotes: 'x' or '\x'. Be careful for single
+ * single quotes, eg jon's. Things like '\233' or '\x3f' are not
+ * skipped, there is never a brace in them.
+ * Ignore this when finding matches for `'.
+ */
+ case '\'':
+ if (!cpo_match && initc != '\'' && findc != '\'')
+ {
+ if (backwards)
+ {
+ if (pos.col > 1)
+ {
+ if (linep[pos.col - 2] == '\'')
+ {
+ pos.col -= 2;
+ break;
+ }
+ else if (linep[pos.col - 2] == '\\' &&
+ pos.col > 2 && linep[pos.col - 3] == '\'')
+ {
+ pos.col -= 3;
+ break;
+ }
+ }
+ }
+ else if (linep[pos.col + 1]) /* forward search */
+ {
+ if (linep[pos.col + 1] == '\\' &&
+ linep[pos.col + 2] && linep[pos.col + 3] == '\'')
+ {
+ pos.col += 3;
+ break;
+ }
+ else if (linep[pos.col + 2] == '\'')
+ {
+ pos.col += 2;
+ break;
+ }
+ }
+ }
+ /* FALLTHROUGH */
+
+ default:
+#ifdef FEAT_LISP
+ /*
+ * For Lisp skip over backslashed (), {} and [].
+ * (actually, we skip #\( et al)
+ */
+ if (curbuf->b_p_lisp
+ && vim_strchr((char_u *)"(){}[]", c) != NULL
+ && pos.col > 1
+ && check_prevcol(linep, pos.col, '\\', NULL)
+ && check_prevcol(linep, pos.col - 1, '#', NULL))
+ break;
+#endif
+
+ /* Check for match outside of quotes, and inside of
+ * quotes when the start is also inside of quotes. */
+ if ((!inquote || start_in_quotes == TRUE)
+ && (c == initc || c == findc))
+ {
+ int col, bslcnt = 0;
+
+ if (!cpo_bsl)
+ {
+ for (col = pos.col; check_prevcol(linep, col, '\\', &col);)
+ bslcnt++;
+ }
+ /* Only accept a match when 'M' is in 'cpo' or when escaping
+ * is what we expect. */
+ if (cpo_bsl || (bslcnt & 1) == match_escaped)
+ {
+ if (c == initc)
+ count++;
+ else
+ {
+ if (count == 0)
+ return &pos;
+ count--;
+ }
+ }
+ }
+ }
+ }
+
+ if (comment_dir == BACKWARD && count > 0)
+ {
+ pos = match_pos;
+ return &pos;
+ }
+ return (pos_T *)NULL; /* never found it */
+}
+
+/*
+ * Check if line[] contains a / / comment.
+ * Return MAXCOL if not, otherwise return the column.
+ * TODO: skip strings.
+ */
+ static int
+check_linecomment(char_u *line)
+{
+ char_u *p;
+
+ p = line;
+#ifdef FEAT_LISP
+ /* skip Lispish one-line comments */
+ if (curbuf->b_p_lisp)
+ {
+ if (vim_strchr(p, ';') != NULL) /* there may be comments */
+ {
+ int in_str = FALSE; /* inside of string */
+
+ p = line; /* scan from start */
+ while ((p = vim_strpbrk(p, (char_u *)"\";")) != NULL)
+ {
+ if (*p == '"')
+ {
+ if (in_str)
+ {
+ if (*(p - 1) != '\\') /* skip escaped quote */
+ in_str = FALSE;
+ }
+ else if (p == line || ((p - line) >= 2
+ /* skip #\" form */
+ && *(p - 1) != '\\' && *(p - 2) != '#'))
+ in_str = TRUE;
+ }
+ else if (!in_str && ((p - line) < 2
+ || (*(p - 1) != '\\' && *(p - 2) != '#')))
+ break; /* found! */
+ ++p;
+ }
+ }
+ else
+ p = NULL;
+ }
+ else
+#endif
+ while ((p = vim_strchr(p, '/')) != NULL)
+ {
+ /* accept a double /, unless it's preceded with * and followed by *,
+ * because * / / * is an end and start of a C comment */
+ if (p[1] == '/' && (p == line || p[-1] != '*' || p[2] != '*'))
+ break;
+ ++p;
+ }
+
+ if (p == NULL)
+ return MAXCOL;
+ return (int)(p - line);
+}
+
+/*
+ * Move cursor briefly to character matching the one under the cursor.
+ * Used for Insert mode and "r" command.
+ * Show the match only if it is visible on the screen.
+ * If there isn't a match, then beep.
+ */
+ void
+showmatch(
+ int c) /* char to show match for */
+{
+ pos_T *lpos, save_cursor;
+ pos_T mpos;
+ colnr_T vcol;
+ long save_so;
+ long save_siso;
+#ifdef CURSOR_SHAPE
+ int save_state;
+#endif
+ colnr_T save_dollar_vcol;
+ char_u *p;
+ long *so = curwin->w_p_so >= 0 ? &curwin->w_p_so : &p_so;
+ long *siso = curwin->w_p_siso >= 0 ? &curwin->w_p_siso : &p_siso;
+
+ /*
+ * Only show match for chars in the 'matchpairs' option.
+ */
+ /* 'matchpairs' is "x:y,x:y" */
+ for (p = curbuf->b_p_mps; *p != NUL; ++p)
+ {
+#ifdef FEAT_RIGHTLEFT
+ if (PTR2CHAR(p) == c && (curwin->w_p_rl ^ p_ri))
+ break;
+#endif
+ p += MB_PTR2LEN(p) + 1;
+ if (PTR2CHAR(p) == c
+#ifdef FEAT_RIGHTLEFT
+ && !(curwin->w_p_rl ^ p_ri)
+#endif
+ )
+ break;
+ p += MB_PTR2LEN(p);
+ if (*p == NUL)
+ return;
+ }
+
+ if ((lpos = findmatch(NULL, NUL)) == NULL) /* no match, so beep */
+ vim_beep(BO_MATCH);
+ else if (lpos->lnum >= curwin->w_topline && lpos->lnum < curwin->w_botline)
+ {
+ if (!curwin->w_p_wrap)
+ getvcol(curwin, lpos, NULL, &vcol, NULL);
+ if (curwin->w_p_wrap || (vcol >= curwin->w_leftcol
+ && vcol < curwin->w_leftcol + curwin->w_width))
+ {
+ mpos = *lpos; /* save the pos, update_screen() may change it */
+ save_cursor = curwin->w_cursor;
+ save_so = *so;
+ save_siso = *siso;
+ /* Handle "$" in 'cpo': If the ')' is typed on top of the "$",
+ * stop displaying the "$". */
+ if (dollar_vcol >= 0 && dollar_vcol == curwin->w_virtcol)
+ dollar_vcol = -1;
+ ++curwin->w_virtcol; /* do display ')' just before "$" */
+ update_screen(VALID); /* show the new char first */
+
+ save_dollar_vcol = dollar_vcol;
+#ifdef CURSOR_SHAPE
+ save_state = State;
+ State = SHOWMATCH;
+ ui_cursor_shape(); /* may show different cursor shape */
+#endif
+ curwin->w_cursor = mpos; /* move to matching char */
+ *so = 0; /* don't use 'scrolloff' here */
+ *siso = 0; /* don't use 'sidescrolloff' here */
+ showruler(FALSE);
+ setcursor();
+ cursor_on(); /* make sure that the cursor is shown */
+ out_flush_cursor(TRUE, FALSE);
+
+ /* Restore dollar_vcol(), because setcursor() may call curs_rows()
+ * which resets it if the matching position is in a previous line
+ * and has a higher column number. */
+ dollar_vcol = save_dollar_vcol;
+
+ /*
+ * brief pause, unless 'm' is present in 'cpo' and a character is
+ * available.
+ */
+ if (vim_strchr(p_cpo, CPO_SHOWMATCH) != NULL)
+ ui_delay(p_mat * 100L, TRUE);
+ else if (!char_avail())
+ ui_delay(p_mat * 100L, FALSE);
+ curwin->w_cursor = save_cursor; /* restore cursor position */
+ *so = save_so;
+ *siso = save_siso;
+#ifdef CURSOR_SHAPE
+ State = save_state;
+ ui_cursor_shape(); /* may show different cursor shape */
+#endif
+ }
+ }
+}
+
+/*
+ * Find the start of the next sentence, searching in the direction specified
+ * by the "dir" argument. The cursor is positioned on the start of the next
+ * sentence when found. If the next sentence is found, return OK. Return FAIL
+ * otherwise. See ":h sentence" for the precise definition of a "sentence"
+ * text object.
+ */
+ int
+findsent(int dir, long count)
+{
+ pos_T pos, tpos;
+ int c;
+ int (*func)(pos_T *);
+ int startlnum;
+ int noskip = FALSE; /* do not skip blanks */
+ int cpo_J;
+ int found_dot;
+
+ pos = curwin->w_cursor;
+ if (dir == FORWARD)
+ func = incl;
+ else
+ func = decl;
+
+ while (count--)
+ {
+ /*
+ * if on an empty line, skip upto a non-empty line
+ */
+ if (gchar_pos(&pos) == NUL)
+ {
+ do
+ if ((*func)(&pos) == -1)
+ break;
+ while (gchar_pos(&pos) == NUL);
+ if (dir == FORWARD)
+ goto found;
+ }
+ /*
+ * if on the start of a paragraph or a section and searching forward,
+ * go to the next line
+ */
+ else if (dir == FORWARD && pos.col == 0 &&
+ startPS(pos.lnum, NUL, FALSE))
+ {
+ if (pos.lnum == curbuf->b_ml.ml_line_count)
+ return FAIL;
+ ++pos.lnum;
+ goto found;
+ }
+ else if (dir == BACKWARD)
+ decl(&pos);
+
+ // go back to the previous non-white non-punctuation character
+ found_dot = FALSE;
+ while (c = gchar_pos(&pos), VIM_ISWHITE(c)
+ || vim_strchr((char_u *)".!?)]\"'", c) != NULL)
+ {
+ tpos = pos;
+ if (decl(&tpos) == -1 || (LINEEMPTY(tpos.lnum) && dir == FORWARD))
+ break;
+
+ if (found_dot)
+ break;
+ if (vim_strchr((char_u *) ".!?", c) != NULL)
+ found_dot = TRUE;
+
+ if (vim_strchr((char_u *) ")]\"'", c) != NULL
+ && vim_strchr((char_u *) ".!?)]\"'", gchar_pos(&tpos)) == NULL)
+ break;
+
+ decl(&pos);
+ }
+
+ /* remember the line where the search started */
+ startlnum = pos.lnum;
+ cpo_J = vim_strchr(p_cpo, CPO_ENDOFSENT) != NULL;
+
+ for (;;) /* find end of sentence */
+ {
+ c = gchar_pos(&pos);
+ if (c == NUL || (pos.col == 0 && startPS(pos.lnum, NUL, FALSE)))
+ {
+ if (dir == BACKWARD && pos.lnum != startlnum)
+ ++pos.lnum;
+ break;
+ }
+ if (c == '.' || c == '!' || c == '?')
+ {
+ tpos = pos;
+ do
+ if ((c = inc(&tpos)) == -1)
+ break;
+ while (vim_strchr((char_u *)")]\"'", c = gchar_pos(&tpos))
+ != NULL);
+ if (c == -1 || (!cpo_J && (c == ' ' || c == '\t')) || c == NUL
+ || (cpo_J && (c == ' ' && inc(&tpos) >= 0
+ && gchar_pos(&tpos) == ' ')))
+ {
+ pos = tpos;
+ if (gchar_pos(&pos) == NUL) /* skip NUL at EOL */
+ inc(&pos);
+ break;
+ }
+ }
+ if ((*func)(&pos) == -1)
+ {
+ if (count)
+ return FAIL;
+ noskip = TRUE;
+ break;
+ }
+ }
+found:
+ /* skip white space */
+ while (!noskip && ((c = gchar_pos(&pos)) == ' ' || c == '\t'))
+ if (incl(&pos) == -1)
+ break;
+ }
+
+ setpcmark();
+ curwin->w_cursor = pos;
+ return OK;
+}
+
+/*
+ * Find the next paragraph or section in direction 'dir'.
+ * Paragraphs are currently supposed to be separated by empty lines.
+ * If 'what' is NUL we go to the next paragraph.
+ * If 'what' is '{' or '}' we go to the next section.
+ * If 'both' is TRUE also stop at '}'.
+ * Return TRUE if the next paragraph or section was found.
+ */
+ int
+findpar(
+ int *pincl, /* Return: TRUE if last char is to be included */
+ int dir,
+ long count,
+ int what,
+ int both)
+{
+ linenr_T curr;
+ int did_skip; /* TRUE after separating lines have been skipped */
+ int first; /* TRUE on first line */
+ int posix = (vim_strchr(p_cpo, CPO_PARA) != NULL);
+#ifdef FEAT_FOLDING
+ linenr_T fold_first; /* first line of a closed fold */
+ linenr_T fold_last; /* last line of a closed fold */
+ int fold_skipped; /* TRUE if a closed fold was skipped this
+ iteration */
+#endif
+
+ curr = curwin->w_cursor.lnum;
+
+ while (count--)
+ {
+ did_skip = FALSE;
+ for (first = TRUE; ; first = FALSE)
+ {
+ if (*ml_get(curr) != NUL)
+ did_skip = TRUE;
+
+#ifdef FEAT_FOLDING
+ /* skip folded lines */
+ fold_skipped = FALSE;
+ if (first && hasFolding(curr, &fold_first, &fold_last))
+ {
+ curr = ((dir > 0) ? fold_last : fold_first) + dir;
+ fold_skipped = TRUE;
+ }
+#endif
+
+ /* POSIX has its own ideas of what a paragraph boundary is and it
+ * doesn't match historical Vi: It also stops at a "{" in the
+ * first column and at an empty line. */
+ if (!first && did_skip && (startPS(curr, what, both)
+ || (posix && what == NUL && *ml_get(curr) == '{')))
+ break;
+
+#ifdef FEAT_FOLDING
+ if (fold_skipped)
+ curr -= dir;
+#endif
+ if ((curr += dir) < 1 || curr > curbuf->b_ml.ml_line_count)
+ {
+ if (count)
+ return FALSE;
+ curr -= dir;
+ break;
+ }
+ }
+ }
+ setpcmark();
+ if (both && *ml_get(curr) == '}') /* include line with '}' */
+ ++curr;
+ curwin->w_cursor.lnum = curr;
+ if (curr == curbuf->b_ml.ml_line_count && what != '}')
+ {
+ char_u *line = ml_get(curr);
+
+ /* Put the cursor on the last character in the last line and make the
+ * motion inclusive. */
+ if ((curwin->w_cursor.col = (colnr_T)STRLEN(line)) != 0)
+ {
+ --curwin->w_cursor.col;
+ curwin->w_cursor.col -=
+ (*mb_head_off)(line, line + curwin->w_cursor.col);
+ *pincl = TRUE;
+ }
+ }
+ else
+ curwin->w_cursor.col = 0;
+ return TRUE;
+}
+
+/*
+ * check if the string 's' is a nroff macro that is in option 'opt'
+ */
+ static int
+inmacro(char_u *opt, char_u *s)
+{
+ char_u *macro;
+
+ for (macro = opt; macro[0]; ++macro)
+ {
+ /* Accept two characters in the option being equal to two characters
+ * in the line. A space in the option matches with a space in the
+ * line or the line having ended. */
+ if ( (macro[0] == s[0]
+ || (macro[0] == ' '
+ && (s[0] == NUL || s[0] == ' ')))
+ && (macro[1] == s[1]
+ || ((macro[1] == NUL || macro[1] == ' ')
+ && (s[0] == NUL || s[1] == NUL || s[1] == ' '))))
+ break;
+ ++macro;
+ if (macro[0] == NUL)
+ break;
+ }
+ return (macro[0] != NUL);
+}
+
+/*
+ * startPS: return TRUE if line 'lnum' is the start of a section or paragraph.
+ * If 'para' is '{' or '}' only check for sections.
+ * If 'both' is TRUE also stop at '}'
+ */
+ int
+startPS(linenr_T lnum, int para, int both)
+{
+ char_u *s;
+
+ s = ml_get(lnum);
+ if (*s == para || *s == '\f' || (both && *s == '}'))
+ return TRUE;
+ if (*s == '.' && (inmacro(p_sections, s + 1) ||
+ (!para && inmacro(p_para, s + 1))))
+ return TRUE;
+ return FALSE;
+}
+
+/*
+ * The following routines do the word searches performed by the 'w', 'W',
+ * 'b', 'B', 'e', and 'E' commands.
+ */
+
+/*
+ * To perform these searches, characters are placed into one of three
+ * classes, and transitions between classes determine word boundaries.
+ *
+ * The classes are:
+ *
+ * 0 - white space
+ * 1 - punctuation
+ * 2 or higher - keyword characters (letters, digits and underscore)
+ */
+
+static int cls_bigword; /* TRUE for "W", "B" or "E" */
+
+/*
+ * cls() - returns the class of character at curwin->w_cursor
+ *
+ * If a 'W', 'B', or 'E' motion is being done (cls_bigword == TRUE), chars
+ * from class 2 and higher are reported as class 1 since only white space
+ * boundaries are of interest.
+ */
+ static int
+cls(void)
+{
+ int c;
+
+ c = gchar_cursor();
+#ifdef FEAT_FKMAP /* when 'akm' (Farsi mode), take care of Farsi blank */
+ if (p_altkeymap && c == F_BLANK)
+ return 0;
+#endif
+ if (c == ' ' || c == '\t' || c == NUL)
+ return 0;
+ if (enc_dbcs != 0 && c > 0xFF)
+ {
+ /* If cls_bigword, report multi-byte chars as class 1. */
+ if (enc_dbcs == DBCS_KOR && cls_bigword)
+ return 1;
+
+ /* process code leading/trailing bytes */
+ return dbcs_class(((unsigned)c >> 8), (c & 0xFF));
+ }
+ if (enc_utf8)
+ {
+ c = utf_class(c);
+ if (c != 0 && cls_bigword)
+ return 1;
+ return c;
+ }
+
+ /* If cls_bigword is TRUE, report all non-blanks as class 1. */
+ if (cls_bigword)
+ return 1;
+
+ if (vim_iswordc(c))
+ return 2;
+ return 1;
+}
+
+
+/*
+ * fwd_word(count, type, eol) - move forward one word
+ *
+ * Returns FAIL if the cursor was already at the end of the file.
+ * If eol is TRUE, last word stops at end of line (for operators).
+ */
+ int
+fwd_word(
+ long count,
+ int bigword, /* "W", "E" or "B" */
+ int eol)
+{
+ int sclass; /* starting class */
+ int i;
+ int last_line;
+
+ curwin->w_cursor.coladd = 0;
+ cls_bigword = bigword;
+ while (--count >= 0)
+ {
+#ifdef FEAT_FOLDING
+ /* When inside a range of folded lines, move to the last char of the
+ * last line. */
+ if (hasFolding(curwin->w_cursor.lnum, NULL, &curwin->w_cursor.lnum))
+ coladvance((colnr_T)MAXCOL);
+#endif
+ sclass = cls();
+
+ /*
+ * We always move at least one character, unless on the last
+ * character in the buffer.
+ */
+ last_line = (curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count);
+ i = inc_cursor();
+ if (i == -1 || (i >= 1 && last_line)) /* started at last char in file */
+ return FAIL;
+ if (i >= 1 && eol && count == 0) /* started at last char in line */
+ return OK;
+
+ /*
+ * Go one char past end of current word (if any)
+ */
+ if (sclass != 0)
+ while (cls() == sclass)
+ {
+ i = inc_cursor();
+ if (i == -1 || (i >= 1 && eol && count == 0))
+ return OK;
+ }
+
+ /*
+ * go to next non-white
+ */
+ while (cls() == 0)
+ {
+ /*
+ * We'll stop if we land on a blank line
+ */
+ if (curwin->w_cursor.col == 0 && *ml_get_curline() == NUL)
+ break;
+
+ i = inc_cursor();
+ if (i == -1 || (i >= 1 && eol && count == 0))
+ return OK;
+ }
+ }
+ return OK;
+}
+
+/*
+ * bck_word() - move backward 'count' words
+ *
+ * If stop is TRUE and we are already on the start of a word, move one less.
+ *
+ * Returns FAIL if top of the file was reached.
+ */
+ int
+bck_word(long count, int bigword, int stop)
+{
+ int sclass; /* starting class */
+
+ curwin->w_cursor.coladd = 0;
+ cls_bigword = bigword;
+ while (--count >= 0)
+ {
+#ifdef FEAT_FOLDING
+ /* When inside a range of folded lines, move to the first char of the
+ * first line. */
+ if (hasFolding(curwin->w_cursor.lnum, &curwin->w_cursor.lnum, NULL))
+ curwin->w_cursor.col = 0;
+#endif
+ sclass = cls();
+ if (dec_cursor() == -1) /* started at start of file */
+ return FAIL;
+
+ if (!stop || sclass == cls() || sclass == 0)
+ {
+ /*
+ * Skip white space before the word.
+ * Stop on an empty line.
+ */
+ while (cls() == 0)
+ {
+ if (curwin->w_cursor.col == 0
+ && LINEEMPTY(curwin->w_cursor.lnum))
+ goto finished;
+ if (dec_cursor() == -1) /* hit start of file, stop here */
+ return OK;
+ }
+
+ /*
+ * Move backward to start of this word.
+ */
+ if (skip_chars(cls(), BACKWARD))
+ return OK;
+ }
+
+ inc_cursor(); /* overshot - forward one */
+finished:
+ stop = FALSE;
+ }
+ return OK;
+}
+
+/*
+ * end_word() - move to the end of the word
+ *
+ * There is an apparent bug in the 'e' motion of the real vi. At least on the
+ * System V Release 3 version for the 80386. Unlike 'b' and 'w', the 'e'
+ * motion crosses blank lines. When the real vi crosses a blank line in an
+ * 'e' motion, the cursor is placed on the FIRST character of the next
+ * non-blank line. The 'E' command, however, works correctly. Since this
+ * appears to be a bug, I have not duplicated it here.
+ *
+ * Returns FAIL if end of the file was reached.
+ *
+ * If stop is TRUE and we are already on the end of a word, move one less.
+ * If empty is TRUE stop on an empty line.
+ */
+ int
+end_word(
+ long count,
+ int bigword,
+ int stop,
+ int empty)
+{
+ int sclass; /* starting class */
+
+ curwin->w_cursor.coladd = 0;
+ cls_bigword = bigword;
+ while (--count >= 0)
+ {
+#ifdef FEAT_FOLDING
+ /* When inside a range of folded lines, move to the last char of the
+ * last line. */
+ if (hasFolding(curwin->w_cursor.lnum, NULL, &curwin->w_cursor.lnum))
+ coladvance((colnr_T)MAXCOL);
+#endif
+ sclass = cls();
+ if (inc_cursor() == -1)
+ return FAIL;
+
+ /*
+ * If we're in the middle of a word, we just have to move to the end
+ * of it.
+ */
+ if (cls() == sclass && sclass != 0)
+ {
+ /*
+ * Move forward to end of the current word
+ */
+ if (skip_chars(sclass, FORWARD))
+ return FAIL;
+ }
+ else if (!stop || sclass == 0)
+ {
+ /*
+ * We were at the end of a word. Go to the end of the next word.
+ * First skip white space, if 'empty' is TRUE, stop at empty line.
+ */
+ while (cls() == 0)
+ {
+ if (empty && curwin->w_cursor.col == 0
+ && LINEEMPTY(curwin->w_cursor.lnum))
+ goto finished;
+ if (inc_cursor() == -1) /* hit end of file, stop here */
+ return FAIL;
+ }
+
+ /*
+ * Move forward to the end of this word.
+ */
+ if (skip_chars(cls(), FORWARD))
+ return FAIL;
+ }
+ dec_cursor(); /* overshot - one char backward */
+finished:
+ stop = FALSE; /* we move only one word less */
+ }
+ return OK;
+}
+
+/*
+ * Move back to the end of the word.
+ *
+ * Returns FAIL if start of the file was reached.
+ */
+ int
+bckend_word(
+ long count,
+ int bigword, /* TRUE for "B" */
+ int eol) /* TRUE: stop at end of line. */
+{
+ int sclass; /* starting class */
+ int i;
+
+ curwin->w_cursor.coladd = 0;
+ cls_bigword = bigword;
+ while (--count >= 0)
+ {
+ sclass = cls();
+ if ((i = dec_cursor()) == -1)
+ return FAIL;
+ if (eol && i == 1)
+ return OK;
+
+ /*
+ * Move backward to before the start of this word.
+ */
+ if (sclass != 0)
+ {
+ while (cls() == sclass)
+ if ((i = dec_cursor()) == -1 || (eol && i == 1))
+ return OK;
+ }
+
+ /*
+ * Move backward to end of the previous word
+ */
+ while (cls() == 0)
+ {
+ if (curwin->w_cursor.col == 0 && LINEEMPTY(curwin->w_cursor.lnum))
+ break;
+ if ((i = dec_cursor()) == -1 || (eol && i == 1))
+ return OK;
+ }
+ }
+ return OK;
+}
+
+/*
+ * Skip a row of characters of the same class.
+ * Return TRUE when end-of-file reached, FALSE otherwise.
+ */
+ static int
+skip_chars(int cclass, int dir)
+{
+ while (cls() == cclass)
+ if ((dir == FORWARD ? inc_cursor() : dec_cursor()) == -1)
+ return TRUE;
+ return FALSE;
+}
+
+#ifdef FEAT_TEXTOBJ
+/*
+ * Go back to the start of the word or the start of white space
+ */
+ static void
+back_in_line(void)
+{
+ int sclass; /* starting class */
+
+ sclass = cls();
+ for (;;)
+ {
+ if (curwin->w_cursor.col == 0) /* stop at start of line */
+ break;
+ dec_cursor();
+ if (cls() != sclass) /* stop at start of word */
+ {
+ inc_cursor();
+ break;
+ }
+ }
+}
+
+ static void
+find_first_blank(pos_T *posp)
+{
+ int c;
+
+ while (decl(posp) != -1)
+ {
+ c = gchar_pos(posp);
+ if (!VIM_ISWHITE(c))
+ {
+ incl(posp);
+ break;
+ }
+ }
+}
+
+/*
+ * Skip count/2 sentences and count/2 separating white spaces.
+ */
+ static void
+findsent_forward(
+ long count,
+ int at_start_sent) /* cursor is at start of sentence */
+{
+ while (count--)
+ {
+ findsent(FORWARD, 1L);
+ if (at_start_sent)
+ find_first_blank(&curwin->w_cursor);
+ if (count == 0 || at_start_sent)
+ decl(&curwin->w_cursor);
+ at_start_sent = !at_start_sent;
+ }
+}
+
+/*
+ * Find word under cursor, cursor at end.
+ * Used while an operator is pending, and in Visual mode.
+ */
+ int
+current_word(
+ oparg_T *oap,
+ long count,
+ int include, /* TRUE: include word and white space */
+ int bigword) /* FALSE == word, TRUE == WORD */
+{
+ pos_T start_pos;
+ pos_T pos;
+ int inclusive = TRUE;
+ int include_white = FALSE;
+
+ cls_bigword = bigword;
+ CLEAR_POS(&start_pos);
+
+ /* Correct cursor when 'selection' is exclusive */
+ if (VIsual_active && *p_sel == 'e' && LT_POS(VIsual, curwin->w_cursor))
+ dec_cursor();
+
+ /*
+ * When Visual mode is not active, or when the VIsual area is only one
+ * character, select the word and/or white space under the cursor.
+ */
+ if (!VIsual_active || EQUAL_POS(curwin->w_cursor, VIsual))
+ {
+ /*
+ * Go to start of current word or white space.
+ */
+ back_in_line();
+ start_pos = curwin->w_cursor;
+
+ /*
+ * If the start is on white space, and white space should be included
+ * (" word"), or start is not on white space, and white space should
+ * not be included ("word"), find end of word.
+ */
+ if ((cls() == 0) == include)
+ {
+ if (end_word(1L, bigword, TRUE, TRUE) == FAIL)
+ return FAIL;
+ }
+ else
+ {
+ /*
+ * If the start is not on white space, and white space should be
+ * included ("word "), or start is on white space and white
+ * space should not be included (" "), find start of word.
+ * If we end up in the first column of the next line (single char
+ * word) back up to end of the line.
+ */
+ fwd_word(1L, bigword, TRUE);
+ if (curwin->w_cursor.col == 0)
+ decl(&curwin->w_cursor);
+ else
+ oneleft();
+
+ if (include)
+ include_white = TRUE;
+ }
+
+ if (VIsual_active)
+ {
+ /* should do something when inclusive == FALSE ! */
+ VIsual = start_pos;
+ redraw_curbuf_later(INVERTED); /* update the inversion */
+ }
+ else
+ {
+ oap->start = start_pos;
+ oap->motion_type = MCHAR;
+ }
+ --count;
+ }
+
+ /*
+ * When count is still > 0, extend with more objects.
+ */
+ while (count > 0)
+ {
+ inclusive = TRUE;
+ if (VIsual_active && LT_POS(curwin->w_cursor, VIsual))
+ {
+ /*
+ * In Visual mode, with cursor at start: move cursor back.
+ */
+ if (decl(&curwin->w_cursor) == -1)
+ return FAIL;
+ if (include != (cls() != 0))
+ {
+ if (bck_word(1L, bigword, TRUE) == FAIL)
+ return FAIL;
+ }
+ else
+ {
+ if (bckend_word(1L, bigword, TRUE) == FAIL)
+ return FAIL;
+ (void)incl(&curwin->w_cursor);
+ }
+ }
+ else
+ {
+ /*
+ * Move cursor forward one word and/or white area.
+ */
+ if (incl(&curwin->w_cursor) == -1)
+ return FAIL;
+ if (include != (cls() == 0))
+ {
+ if (fwd_word(1L, bigword, TRUE) == FAIL && count > 1)
+ return FAIL;
+ /*
+ * If end is just past a new-line, we don't want to include
+ * the first character on the line.
+ * Put cursor on last char of white.
+ */
+ if (oneleft() == FAIL)
+ inclusive = FALSE;
+ }
+ else
+ {
+ if (end_word(1L, bigword, TRUE, TRUE) == FAIL)
+ return FAIL;
+ }
+ }
+ --count;
+ }
+
+ if (include_white && (cls() != 0
+ || (curwin->w_cursor.col == 0 && !inclusive)))
+ {
+ /*
+ * If we don't include white space at the end, move the start
+ * to include some white space there. This makes "daw" work
+ * better on the last word in a sentence (and "2daw" on last-but-one
+ * word). Also when "2daw" deletes "word." at the end of the line
+ * (cursor is at start of next line).
+ * But don't delete white space at start of line (indent).
+ */
+ pos = curwin->w_cursor; /* save cursor position */
+ curwin->w_cursor = start_pos;
+ if (oneleft() == OK)
+ {
+ back_in_line();
+ if (cls() == 0 && curwin->w_cursor.col > 0)
+ {
+ if (VIsual_active)
+ VIsual = curwin->w_cursor;
+ else
+ oap->start = curwin->w_cursor;
+ }
+ }
+ curwin->w_cursor = pos; /* put cursor back at end */
+ }
+
+ if (VIsual_active)
+ {
+ if (*p_sel == 'e' && inclusive && LTOREQ_POS(VIsual, curwin->w_cursor))
+ inc_cursor();
+ if (VIsual_mode == 'V')
+ {
+ VIsual_mode = 'v';
+ redraw_cmdline = TRUE; /* show mode later */
+ }
+ }
+ else
+ oap->inclusive = inclusive;
+
+ return OK;
+}
+
+/*
+ * Find sentence(s) under the cursor, cursor at end.
+ * When Visual active, extend it by one or more sentences.
+ */
+ int
+current_sent(oparg_T *oap, long count, int include)
+{
+ pos_T start_pos;
+ pos_T pos;
+ int start_blank;
+ int c;
+ int at_start_sent;
+ long ncount;
+
+ start_pos = curwin->w_cursor;
+ pos = start_pos;
+ findsent(FORWARD, 1L); /* Find start of next sentence. */
+
+ /*
+ * When the Visual area is bigger than one character: Extend it.
+ */
+ if (VIsual_active && !EQUAL_POS(start_pos, VIsual))
+ {
+extend:
+ if (LT_POS(start_pos, VIsual))
+ {
+ /*
+ * Cursor at start of Visual area.
+ * Find out where we are:
+ * - in the white space before a sentence
+ * - in a sentence or just after it
+ * - at the start of a sentence
+ */
+ at_start_sent = TRUE;
+ decl(&pos);
+ while (LT_POS(pos, curwin->w_cursor))
+ {
+ c = gchar_pos(&pos);
+ if (!VIM_ISWHITE(c))
+ {
+ at_start_sent = FALSE;
+ break;
+ }
+ incl(&pos);
+ }
+ if (!at_start_sent)
+ {
+ findsent(BACKWARD, 1L);
+ if (EQUAL_POS(curwin->w_cursor, start_pos))
+ at_start_sent = TRUE; /* exactly at start of sentence */
+ else
+ /* inside a sentence, go to its end (start of next) */
+ findsent(FORWARD, 1L);
+ }
+ if (include) /* "as" gets twice as much as "is" */
+ count *= 2;
+ while (count--)
+ {
+ if (at_start_sent)
+ find_first_blank(&curwin->w_cursor);
+ c = gchar_cursor();
+ if (!at_start_sent || (!include && !VIM_ISWHITE(c)))
+ findsent(BACKWARD, 1L);
+ at_start_sent = !at_start_sent;
+ }
+ }
+ else
+ {
+ /*
+ * Cursor at end of Visual area.
+ * Find out where we are:
+ * - just before a sentence
+ * - just before or in the white space before a sentence
+ * - in a sentence
+ */
+ incl(&pos);
+ at_start_sent = TRUE;
+ /* not just before a sentence */
+ if (!EQUAL_POS(pos, curwin->w_cursor))
+ {
+ at_start_sent = FALSE;
+ while (LT_POS(pos, curwin->w_cursor))
+ {
+ c = gchar_pos(&pos);
+ if (!VIM_ISWHITE(c))
+ {
+ at_start_sent = TRUE;
+ break;
+ }
+ incl(&pos);
+ }
+ if (at_start_sent) /* in the sentence */
+ findsent(BACKWARD, 1L);
+ else /* in/before white before a sentence */
+ curwin->w_cursor = start_pos;
+ }
+
+ if (include) /* "as" gets twice as much as "is" */
+ count *= 2;
+ findsent_forward(count, at_start_sent);
+ if (*p_sel == 'e')
+ ++curwin->w_cursor.col;
+ }
+ return OK;
+ }
+
+ /*
+ * If the cursor started on a blank, check if it is just before the start
+ * of the next sentence.
+ */
+ while (c = gchar_pos(&pos), VIM_ISWHITE(c)) /* VIM_ISWHITE() is a macro */
+ incl(&pos);
+ if (EQUAL_POS(pos, curwin->w_cursor))
+ {
+ start_blank = TRUE;
+ find_first_blank(&start_pos); /* go back to first blank */
+ }
+ else
+ {
+ start_blank = FALSE;
+ findsent(BACKWARD, 1L);
+ start_pos = curwin->w_cursor;
+ }
+ if (include)
+ ncount = count * 2;
+ else
+ {
+ ncount = count;
+ if (start_blank)
+ --ncount;
+ }
+ if (ncount > 0)
+ findsent_forward(ncount, TRUE);
+ else
+ decl(&curwin->w_cursor);
+
+ if (include)
+ {
+ /*
+ * If the blank in front of the sentence is included, exclude the
+ * blanks at the end of the sentence, go back to the first blank.
+ * If there are no trailing blanks, try to include leading blanks.
+ */
+ if (start_blank)
+ {
+ find_first_blank(&curwin->w_cursor);
+ c = gchar_pos(&curwin->w_cursor); /* VIM_ISWHITE() is a macro */
+ if (VIM_ISWHITE(c))
+ decl(&curwin->w_cursor);
+ }
+ else if (c = gchar_cursor(), !VIM_ISWHITE(c))
+ find_first_blank(&start_pos);
+ }
+
+ if (VIsual_active)
+ {
+ /* Avoid getting stuck with "is" on a single space before a sentence. */
+ if (EQUAL_POS(start_pos, curwin->w_cursor))
+ goto extend;
+ if (*p_sel == 'e')
+ ++curwin->w_cursor.col;
+ VIsual = start_pos;
+ VIsual_mode = 'v';
+ redraw_cmdline = TRUE; /* show mode later */
+ redraw_curbuf_later(INVERTED); /* update the inversion */
+ }
+ else
+ {
+ /* include a newline after the sentence, if there is one */
+ if (incl(&curwin->w_cursor) == -1)
+ oap->inclusive = TRUE;
+ else
+ oap->inclusive = FALSE;
+ oap->start = start_pos;
+ oap->motion_type = MCHAR;
+ }
+ return OK;
+}
+
+/*
+ * Find block under the cursor, cursor at end.
+ * "what" and "other" are two matching parenthesis/brace/etc.
+ */
+ int
+current_block(
+ oparg_T *oap,
+ long count,
+ int include, /* TRUE == include white space */
+ int what, /* '(', '{', etc. */
+ int other) /* ')', '}', etc. */
+{
+ pos_T old_pos;
+ pos_T *pos = NULL;
+ pos_T start_pos;
+ pos_T *end_pos;
+ pos_T old_start, old_end;
+ char_u *save_cpo;
+ int sol = FALSE; /* '{' at start of line */
+
+ old_pos = curwin->w_cursor;
+ old_end = curwin->w_cursor; /* remember where we started */
+ old_start = old_end;
+
+ /*
+ * If we start on '(', '{', ')', '}', etc., use the whole block inclusive.
+ */
+ if (!VIsual_active || EQUAL_POS(VIsual, curwin->w_cursor))
+ {
+ setpcmark();
+ if (what == '{') /* ignore indent */
+ while (inindent(1))
+ if (inc_cursor() != 0)
+ break;
+ if (gchar_cursor() == what)
+ /* cursor on '(' or '{', move cursor just after it */
+ ++curwin->w_cursor.col;
+ }
+ else if (LT_POS(VIsual, curwin->w_cursor))
+ {
+ old_start = VIsual;
+ curwin->w_cursor = VIsual; /* cursor at low end of Visual */
+ }
+ else
+ old_end = VIsual;
+
+ /*
+ * Search backwards for unclosed '(', '{', etc..
+ * Put this position in start_pos.
+ * Ignore quotes here. Keep the "M" flag in 'cpo', as that is what the
+ * user wants.
+ */
+ save_cpo = p_cpo;
+ p_cpo = (char_u *)(vim_strchr(p_cpo, CPO_MATCHBSL) != NULL ? "%M" : "%");
+ while (count-- > 0)
+ {
+ if ((pos = findmatch(NULL, what)) == NULL)
+ break;
+ curwin->w_cursor = *pos;
+ start_pos = *pos; /* the findmatch for end_pos will overwrite *pos */
+ }
+ p_cpo = save_cpo;
+
+ /*
+ * Search for matching ')', '}', etc.
+ * Put this position in curwin->w_cursor.
+ */
+ if (pos == NULL || (end_pos = findmatch(NULL, other)) == NULL)
+ {
+ curwin->w_cursor = old_pos;
+ return FAIL;
+ }
+ curwin->w_cursor = *end_pos;
+
+ /*
+ * Try to exclude the '(', '{', ')', '}', etc. when "include" is FALSE.
+ * If the ending '}', ')' or ']' is only preceded by indent, skip that
+ * indent. But only if the resulting area is not smaller than what we
+ * started with.
+ */
+ while (!include)
+ {
+ incl(&start_pos);
+ sol = (curwin->w_cursor.col == 0);
+ decl(&curwin->w_cursor);
+ while (inindent(1))
+ {
+ sol = TRUE;
+ if (decl(&curwin->w_cursor) != 0)
+ break;
+ }
+
+ /*
+ * In Visual mode, when the resulting area is not bigger than what we
+ * started with, extend it to the next block, and then exclude again.
+ */
+ if (!LT_POS(start_pos, old_start) && !LT_POS(old_end, curwin->w_cursor)
+ && VIsual_active)
+ {
+ curwin->w_cursor = old_start;
+ decl(&curwin->w_cursor);
+ if ((pos = findmatch(NULL, what)) == NULL)
+ {
+ curwin->w_cursor = old_pos;
+ return FAIL;
+ }
+ start_pos = *pos;
+ curwin->w_cursor = *pos;
+ if ((end_pos = findmatch(NULL, other)) == NULL)
+ {
+ curwin->w_cursor = old_pos;
+ return FAIL;
+ }
+ curwin->w_cursor = *end_pos;
+ }
+ else
+ break;
+ }
+
+ if (VIsual_active)
+ {
+ if (*p_sel == 'e')
+ inc(&curwin->w_cursor);
+ if (sol && gchar_cursor() != NUL)
+ inc(&curwin->w_cursor); /* include the line break */
+ VIsual = start_pos;
+ VIsual_mode = 'v';
+ redraw_curbuf_later(INVERTED); /* update the inversion */
+ showmode();
+ }
+ else
+ {
+ oap->start = start_pos;
+ oap->motion_type = MCHAR;
+ oap->inclusive = FALSE;
+ if (sol)
+ incl(&curwin->w_cursor);
+ else if (LTOREQ_POS(start_pos, curwin->w_cursor))
+ /* Include the character under the cursor. */
+ oap->inclusive = TRUE;
+ else
+ /* End is before the start (no text in between <>, [], etc.): don't
+ * operate on any text. */
+ curwin->w_cursor = start_pos;
+ }
+
+ return OK;
+}
+
+/*
+ * Return TRUE if the cursor is on a "<aaa>" tag. Ignore "<aaa/>".
+ * When "end_tag" is TRUE return TRUE if the cursor is on "</aaa>".
+ */
+ static int
+in_html_tag(
+ int end_tag)
+{
+ char_u *line = ml_get_curline();
+ char_u *p;
+ int c;
+ int lc = NUL;
+ pos_T pos;
+
+ if (enc_dbcs)
+ {
+ char_u *lp = NULL;
+
+ /* We search forward until the cursor, because searching backwards is
+ * very slow for DBCS encodings. */
+ for (p = line; p < line + curwin->w_cursor.col; MB_PTR_ADV(p))
+ if (*p == '>' || *p == '<')
+ {
+ lc = *p;
+ lp = p;
+ }
+ if (*p != '<') /* check for '<' under cursor */
+ {
+ if (lc != '<')
+ return FALSE;
+ p = lp;
+ }
+ }
+ else
+ {
+ for (p = line + curwin->w_cursor.col; p > line; )
+ {
+ if (*p == '<') /* find '<' under/before cursor */
+ break;
+ MB_PTR_BACK(line, p);
+ if (*p == '>') /* find '>' before cursor */
+ break;
+ }
+ if (*p != '<')
+ return FALSE;
+ }
+
+ pos.lnum = curwin->w_cursor.lnum;
+ pos.col = (colnr_T)(p - line);
+
+ MB_PTR_ADV(p);
+ if (end_tag)
+ /* check that there is a '/' after the '<' */
+ return *p == '/';
+
+ /* check that there is no '/' after the '<' */
+ if (*p == '/')
+ return FALSE;
+
+ /* check that the matching '>' is not preceded by '/' */
+ for (;;)
+ {
+ if (inc(&pos) < 0)
+ return FALSE;
+ c = *ml_get_pos(&pos);
+ if (c == '>')
+ break;
+ lc = c;
+ }
+ return lc != '/';
+}
+
+/*
+ * Find tag block under the cursor, cursor at end.
+ */
+ int
+current_tagblock(
+ oparg_T *oap,
+ long count_arg,
+ int include) /* TRUE == include white space */
+{
+ long count = count_arg;
+ long n;
+ pos_T old_pos;
+ pos_T start_pos;
+ pos_T end_pos;
+ pos_T old_start, old_end;
+ char_u *spat, *epat;
+ char_u *p;
+ char_u *cp;
+ int len;
+ int r;
+ int do_include = include;
+ int save_p_ws = p_ws;
+ int retval = FAIL;
+ int is_inclusive = TRUE;
+
+ p_ws = FALSE;
+
+ old_pos = curwin->w_cursor;
+ old_end = curwin->w_cursor; /* remember where we started */
+ old_start = old_end;
+ if (!VIsual_active || *p_sel == 'e')
+ decl(&old_end); /* old_end is inclusive */
+
+ /*
+ * If we start on "<aaa>" select that block.
+ */
+ if (!VIsual_active || EQUAL_POS(VIsual, curwin->w_cursor))
+ {
+ setpcmark();
+
+ /* ignore indent */
+ while (inindent(1))
+ if (inc_cursor() != 0)
+ break;
+
+ if (in_html_tag(FALSE))
+ {
+ /* cursor on start tag, move to its '>' */
+ while (*ml_get_cursor() != '>')
+ if (inc_cursor() < 0)
+ break;
+ }
+ else if (in_html_tag(TRUE))
+ {
+ /* cursor on end tag, move to just before it */
+ while (*ml_get_cursor() != '<')
+ if (dec_cursor() < 0)
+ break;
+ dec_cursor();
+ old_end = curwin->w_cursor;
+ }
+ }
+ else if (LT_POS(VIsual, curwin->w_cursor))
+ {
+ old_start = VIsual;
+ curwin->w_cursor = VIsual; /* cursor at low end of Visual */
+ }
+ else
+ old_end = VIsual;
+
+again:
+ /*
+ * Search backwards for unclosed "<aaa>".
+ * Put this position in start_pos.
+ */
+ for (n = 0; n < count; ++n)
+ {
+ if (do_searchpair((char_u *)"<[^ \t>/!]\\+\\%(\\_s\\_[^>]\\{-}[^/]>\\|$\\|\\_s\\=>\\)",
+ (char_u *)"",
+ (char_u *)"</[^>]*>", BACKWARD, NULL, 0,
+ NULL, (linenr_T)0, 0L) <= 0)
+ {
+ curwin->w_cursor = old_pos;
+ goto theend;
+ }
+ }
+ start_pos = curwin->w_cursor;
+
+ /*
+ * Search for matching "</aaa>". First isolate the "aaa".
+ */
+ inc_cursor();
+ p = ml_get_cursor();
+ for (cp = p; *cp != NUL && *cp != '>' && !VIM_ISWHITE(*cp); MB_PTR_ADV(cp))
+ ;
+ len = (int)(cp - p);
+ if (len == 0)
+ {
+ curwin->w_cursor = old_pos;
+ goto theend;
+ }
+ spat = alloc(len + 31);
+ epat = alloc(len + 9);
+ if (spat == NULL || epat == NULL)
+ {
+ vim_free(spat);
+ vim_free(epat);
+ curwin->w_cursor = old_pos;
+ goto theend;
+ }
+ sprintf((char *)spat, "<%.*s\\>\\%%(\\s\\_[^>]\\{-}[^/]>\\|>\\)\\c", len, p);
+ sprintf((char *)epat, "</%.*s>\\c", len, p);
+
+ r = do_searchpair(spat, (char_u *)"", epat, FORWARD, NULL,
+ 0, NULL, (linenr_T)0, 0L);
+
+ vim_free(spat);
+ vim_free(epat);
+
+ if (r < 1 || LT_POS(curwin->w_cursor, old_end))
+ {
+ /* Can't find other end or it's before the previous end. Could be a
+ * HTML tag that doesn't have a matching end. Search backwards for
+ * another starting tag. */
+ count = 1;
+ curwin->w_cursor = start_pos;
+ goto again;
+ }
+
+ if (do_include)
+ {
+ /* Include up to the '>'. */
+ while (*ml_get_cursor() != '>')
+ if (inc_cursor() < 0)
+ break;
+ }
+ else
+ {
+ char_u *c = ml_get_cursor();
+
+ /* Exclude the '<' of the end tag.
+ * If the closing tag is on new line, do not decrement cursor, but
+ * make operation exclusive, so that the linefeed will be selected */
+ if (*c == '<' && !VIsual_active && curwin->w_cursor.col == 0)
+ /* do not decrement cursor */
+ is_inclusive = FALSE;
+ else if (*c == '<')
+ dec_cursor();
+ }
+ end_pos = curwin->w_cursor;
+
+ if (!do_include)
+ {
+ /* Exclude the start tag. */
+ curwin->w_cursor = start_pos;
+ while (inc_cursor() >= 0)
+ if (*ml_get_cursor() == '>')
+ {
+ inc_cursor();
+ start_pos = curwin->w_cursor;
+ break;
+ }
+ curwin->w_cursor = end_pos;
+
+ // If we are in Visual mode and now have the same text as before set
+ // "do_include" and try again.
+ if (VIsual_active && EQUAL_POS(start_pos, old_start)
+ && EQUAL_POS(end_pos, old_end))
+ {
+ do_include = TRUE;
+ curwin->w_cursor = old_start;
+ count = count_arg;
+ goto again;
+ }
+ }
+
+ if (VIsual_active)
+ {
+ /* If the end is before the start there is no text between tags, select
+ * the char under the cursor. */
+ if (LT_POS(end_pos, start_pos))
+ curwin->w_cursor = start_pos;
+ else if (*p_sel == 'e')
+ inc_cursor();
+ VIsual = start_pos;
+ VIsual_mode = 'v';
+ redraw_curbuf_later(INVERTED); /* update the inversion */
+ showmode();
+ }
+ else
+ {
+ oap->start = start_pos;
+ oap->motion_type = MCHAR;
+ if (LT_POS(end_pos, start_pos))
+ {
+ /* End is before the start: there is no text between tags; operate
+ * on an empty area. */
+ curwin->w_cursor = start_pos;
+ oap->inclusive = FALSE;
+ }
+ else
+ oap->inclusive = is_inclusive;
+ }
+ retval = OK;
+
+theend:
+ p_ws = save_p_ws;
+ return retval;
+}
+
+ int
+current_par(
+ oparg_T *oap,
+ long count,
+ int include, /* TRUE == include white space */
+ int type) /* 'p' for paragraph, 'S' for section */
+{
+ linenr_T start_lnum;
+ linenr_T end_lnum;
+ int white_in_front;
+ int dir;
+ int start_is_white;
+ int prev_start_is_white;
+ int retval = OK;
+ int do_white = FALSE;
+ int t;
+ int i;
+
+ if (type == 'S') /* not implemented yet */
+ return FAIL;
+
+ start_lnum = curwin->w_cursor.lnum;
+
+ /*
+ * When visual area is more than one line: extend it.
+ */
+ if (VIsual_active && start_lnum != VIsual.lnum)
+ {
+extend:
+ if (start_lnum < VIsual.lnum)
+ dir = BACKWARD;
+ else
+ dir = FORWARD;
+ for (i = count; --i >= 0; )
+ {
+ if (start_lnum ==
+ (dir == BACKWARD ? 1 : curbuf->b_ml.ml_line_count))
+ {
+ retval = FAIL;
+ break;
+ }
+
+ prev_start_is_white = -1;
+ for (t = 0; t < 2; ++t)
+ {
+ start_lnum += dir;
+ start_is_white = linewhite(start_lnum);
+ if (prev_start_is_white == start_is_white)
+ {
+ start_lnum -= dir;
+ break;
+ }
+ for (;;)
+ {
+ if (start_lnum == (dir == BACKWARD
+ ? 1 : curbuf->b_ml.ml_line_count))
+ break;
+ if (start_is_white != linewhite(start_lnum + dir)
+ || (!start_is_white
+ && startPS(start_lnum + (dir > 0
+ ? 1 : 0), 0, 0)))
+ break;
+ start_lnum += dir;
+ }
+ if (!include)
+ break;
+ if (start_lnum == (dir == BACKWARD
+ ? 1 : curbuf->b_ml.ml_line_count))
+ break;
+ prev_start_is_white = start_is_white;
+ }
+ }
+ curwin->w_cursor.lnum = start_lnum;
+ curwin->w_cursor.col = 0;
+ return retval;
+ }
+
+ /*
+ * First move back to the start_lnum of the paragraph or white lines
+ */
+ white_in_front = linewhite(start_lnum);
+ while (start_lnum > 1)
+ {
+ if (white_in_front) /* stop at first white line */
+ {
+ if (!linewhite(start_lnum - 1))
+ break;
+ }
+ else /* stop at first non-white line of start of paragraph */
+ {
+ if (linewhite(start_lnum - 1) || startPS(start_lnum, 0, 0))
+ break;
+ }
+ --start_lnum;
+ }
+
+ /*
+ * Move past the end of any white lines.
+ */
+ end_lnum = start_lnum;
+ while (end_lnum <= curbuf->b_ml.ml_line_count && linewhite(end_lnum))
+ ++end_lnum;
+
+ --end_lnum;
+ i = count;
+ if (!include && white_in_front)
+ --i;
+ while (i--)
+ {
+ if (end_lnum == curbuf->b_ml.ml_line_count)
+ return FAIL;
+
+ if (!include)
+ do_white = linewhite(end_lnum + 1);
+
+ if (include || !do_white)
+ {
+ ++end_lnum;
+ /*
+ * skip to end of paragraph
+ */
+ while (end_lnum < curbuf->b_ml.ml_line_count
+ && !linewhite(end_lnum + 1)
+ && !startPS(end_lnum + 1, 0, 0))
+ ++end_lnum;
+ }
+
+ if (i == 0 && white_in_front && include)
+ break;
+
+ /*
+ * skip to end of white lines after paragraph
+ */
+ if (include || do_white)
+ while (end_lnum < curbuf->b_ml.ml_line_count
+ && linewhite(end_lnum + 1))
+ ++end_lnum;
+ }
+
+ /*
+ * If there are no empty lines at the end, try to find some empty lines at
+ * the start (unless that has been done already).
+ */
+ if (!white_in_front && !linewhite(end_lnum) && include)
+ while (start_lnum > 1 && linewhite(start_lnum - 1))
+ --start_lnum;
+
+ if (VIsual_active)
+ {
+ /* Problem: when doing "Vipipip" nothing happens in a single white
+ * line, we get stuck there. Trap this here. */
+ if (VIsual_mode == 'V' && start_lnum == curwin->w_cursor.lnum)
+ goto extend;
+ if (VIsual.lnum != start_lnum)
+ {
+ VIsual.lnum = start_lnum;
+ VIsual.col = 0;
+ }
+ VIsual_mode = 'V';
+ redraw_curbuf_later(INVERTED); /* update the inversion */
+ showmode();
+ }
+ else
+ {
+ oap->start.lnum = start_lnum;
+ oap->start.col = 0;
+ oap->motion_type = MLINE;
+ }
+ curwin->w_cursor.lnum = end_lnum;
+ curwin->w_cursor.col = 0;
+
+ return OK;
+}
+
+/*
+ * Search quote char from string line[col].
+ * Quote character escaped by one of the characters in "escape" is not counted
+ * as a quote.
+ * Returns column number of "quotechar" or -1 when not found.
+ */
+ static int
+find_next_quote(
+ char_u *line,
+ int col,
+ int quotechar,
+ char_u *escape) /* escape characters, can be NULL */
+{
+ int c;
+
+ for (;;)
+ {
+ c = line[col];
+ if (c == NUL)
+ return -1;
+ else if (escape != NULL && vim_strchr(escape, c))
+ ++col;
+ else if (c == quotechar)
+ break;
+ if (has_mbyte)
+ col += (*mb_ptr2len)(line + col);
+ else
+ ++col;
+ }
+ return col;
+}
+
+/*
+ * Search backwards in "line" from column "col_start" to find "quotechar".
+ * Quote character escaped by one of the characters in "escape" is not counted
+ * as a quote.
+ * Return the found column or zero.
+ */
+ static int
+find_prev_quote(
+ char_u *line,
+ int col_start,
+ int quotechar,
+ char_u *escape) /* escape characters, can be NULL */
+{
+ int n;
+
+ while (col_start > 0)
+ {
+ --col_start;
+ col_start -= (*mb_head_off)(line, line + col_start);
+ n = 0;
+ if (escape != NULL)
+ while (col_start - n > 0 && vim_strchr(escape,
+ line[col_start - n - 1]) != NULL)
+ ++n;
+ if (n & 1)
+ col_start -= n; /* uneven number of escape chars, skip it */
+ else if (line[col_start] == quotechar)
+ break;
+ }
+ return col_start;
+}
+
+/*
+ * Find quote under the cursor, cursor at end.
+ * Returns TRUE if found, else FALSE.
+ */
+ int
+current_quote(
+ oparg_T *oap,
+ long count,
+ int include, /* TRUE == include quote char */
+ int quotechar) /* Quote character */
+{
+ char_u *line = ml_get_curline();
+ int col_end;
+ int col_start = curwin->w_cursor.col;
+ int inclusive = FALSE;
+ int vis_empty = TRUE; /* Visual selection <= 1 char */
+ int vis_bef_curs = FALSE; /* Visual starts before cursor */
+ int inside_quotes = FALSE; /* Looks like "i'" done before */
+ int selected_quote = FALSE; /* Has quote inside selection */
+ int i;
+
+ /* Correct cursor when 'selection' is "exclusive". */
+ if (VIsual_active)
+ {
+ /* this only works within one line */
+ if (VIsual.lnum != curwin->w_cursor.lnum)
+ return FALSE;
+
+ vis_bef_curs = LT_POS(VIsual, curwin->w_cursor);
+ if (*p_sel == 'e')
+ {
+ if (!vis_bef_curs)
+ {
+ /* VIsual needs to be start of Visual selection. */
+ pos_T t = curwin->w_cursor;
+
+ curwin->w_cursor = VIsual;
+ VIsual = t;
+ vis_bef_curs = TRUE;
+ }
+ dec_cursor();
+ }
+ vis_empty = EQUAL_POS(VIsual, curwin->w_cursor);
+ }
+
+ if (!vis_empty)
+ {
+ /* Check if the existing selection exactly spans the text inside
+ * quotes. */
+ if (vis_bef_curs)
+ {
+ inside_quotes = VIsual.col > 0
+ && line[VIsual.col - 1] == quotechar
+ && line[curwin->w_cursor.col] != NUL
+ && line[curwin->w_cursor.col + 1] == quotechar;
+ i = VIsual.col;
+ col_end = curwin->w_cursor.col;
+ }
+ else
+ {
+ inside_quotes = curwin->w_cursor.col > 0
+ && line[curwin->w_cursor.col - 1] == quotechar
+ && line[VIsual.col] != NUL
+ && line[VIsual.col + 1] == quotechar;
+ i = curwin->w_cursor.col;
+ col_end = VIsual.col;
+ }
+
+ /* Find out if we have a quote in the selection. */
+ while (i <= col_end)
+ if (line[i++] == quotechar)
+ {
+ selected_quote = TRUE;
+ break;
+ }
+ }
+
+ if (!vis_empty && line[col_start] == quotechar)
+ {
+ /* Already selecting something and on a quote character. Find the
+ * next quoted string. */
+ if (vis_bef_curs)
+ {
+ /* Assume we are on a closing quote: move to after the next
+ * opening quote. */
+ col_start = find_next_quote(line, col_start + 1, quotechar, NULL);
+ if (col_start < 0)
+ return FALSE;
+ col_end = find_next_quote(line, col_start + 1, quotechar,
+ curbuf->b_p_qe);
+ if (col_end < 0)
+ {
+ /* We were on a starting quote perhaps? */
+ col_end = col_start;
+ col_start = curwin->w_cursor.col;
+ }
+ }
+ else
+ {
+ col_end = find_prev_quote(line, col_start, quotechar, NULL);
+ if (line[col_end] != quotechar)
+ return FALSE;
+ col_start = find_prev_quote(line, col_end, quotechar,
+ curbuf->b_p_qe);
+ if (line[col_start] != quotechar)
+ {
+ /* We were on an ending quote perhaps? */
+ col_start = col_end;
+ col_end = curwin->w_cursor.col;
+ }
+ }
+ }
+ else
+
+ if (line[col_start] == quotechar || !vis_empty)
+ {
+ int first_col = col_start;
+
+ if (!vis_empty)
+ {
+ if (vis_bef_curs)
+ first_col = find_next_quote(line, col_start, quotechar, NULL);
+ else
+ first_col = find_prev_quote(line, col_start, quotechar, NULL);
+ }
+
+ /* The cursor is on a quote, we don't know if it's the opening or
+ * closing quote. Search from the start of the line to find out.
+ * Also do this when there is a Visual area, a' may leave the cursor
+ * in between two strings. */
+ col_start = 0;
+ for (;;)
+ {
+ /* Find open quote character. */
+ col_start = find_next_quote(line, col_start, quotechar, NULL);
+ if (col_start < 0 || col_start > first_col)
+ return FALSE;
+ /* Find close quote character. */
+ col_end = find_next_quote(line, col_start + 1, quotechar,
+ curbuf->b_p_qe);
+ if (col_end < 0)
+ return FALSE;
+ /* If is cursor between start and end quote character, it is
+ * target text object. */
+ if (col_start <= first_col && first_col <= col_end)
+ break;
+ col_start = col_end + 1;
+ }
+ }
+ else
+ {
+ /* Search backward for a starting quote. */
+ col_start = find_prev_quote(line, col_start, quotechar, curbuf->b_p_qe);
+ if (line[col_start] != quotechar)
+ {
+ /* No quote before the cursor, look after the cursor. */
+ col_start = find_next_quote(line, col_start, quotechar, NULL);
+ if (col_start < 0)
+ return FALSE;
+ }
+
+ /* Find close quote character. */
+ col_end = find_next_quote(line, col_start + 1, quotechar,
+ curbuf->b_p_qe);
+ if (col_end < 0)
+ return FALSE;
+ }
+
+ /* When "include" is TRUE, include spaces after closing quote or before
+ * the starting quote. */
+ if (include)
+ {
+ if (VIM_ISWHITE(line[col_end + 1]))
+ while (VIM_ISWHITE(line[col_end + 1]))
+ ++col_end;
+ else
+ while (col_start > 0 && VIM_ISWHITE(line[col_start - 1]))
+ --col_start;
+ }
+
+ /* Set start position. After vi" another i" must include the ".
+ * For v2i" include the quotes. */
+ if (!include && count < 2 && (vis_empty || !inside_quotes))
+ ++col_start;
+ curwin->w_cursor.col = col_start;
+ if (VIsual_active)
+ {
+ /* Set the start of the Visual area when the Visual area was empty, we
+ * were just inside quotes or the Visual area didn't start at a quote
+ * and didn't include a quote.
+ */
+ if (vis_empty
+ || (vis_bef_curs
+ && !selected_quote
+ && (inside_quotes
+ || (line[VIsual.col] != quotechar
+ && (VIsual.col == 0
+ || line[VIsual.col - 1] != quotechar)))))
+ {
+ VIsual = curwin->w_cursor;
+ redraw_curbuf_later(INVERTED);
+ }
+ }
+ else
+ {
+ oap->start = curwin->w_cursor;
+ oap->motion_type = MCHAR;
+ }
+
+ /* Set end position. */
+ curwin->w_cursor.col = col_end;
+ if ((include || count > 1 /* After vi" another i" must include the ". */
+ || (!vis_empty && inside_quotes)
+ ) && inc_cursor() == 2)
+ inclusive = TRUE;
+ if (VIsual_active)
+ {
+ if (vis_empty || vis_bef_curs)
+ {
+ /* decrement cursor when 'selection' is not exclusive */
+ if (*p_sel != 'e')
+ dec_cursor();
+ }
+ else
+ {
+ /* Cursor is at start of Visual area. Set the end of the Visual
+ * area when it was just inside quotes or it didn't end at a
+ * quote. */
+ if (inside_quotes
+ || (!selected_quote
+ && line[VIsual.col] != quotechar
+ && (line[VIsual.col] == NUL
+ || line[VIsual.col + 1] != quotechar)))
+ {
+ dec_cursor();
+ VIsual = curwin->w_cursor;
+ }
+ curwin->w_cursor.col = col_start;
+ }
+ if (VIsual_mode == 'V')
+ {
+ VIsual_mode = 'v';
+ redraw_cmdline = TRUE; /* show mode later */
+ }
+ }
+ else
+ {
+ /* Set inclusive and other oap's flags. */
+ oap->inclusive = inclusive;
+ }
+
+ return OK;
+}
+
+#endif /* FEAT_TEXTOBJ */
+
+static int is_one_char(char_u *pattern, int move, pos_T *cur, int direction);
+
+/*
+ * Find next search match under cursor, cursor at end.
+ * Used while an operator is pending, and in Visual mode.
+ */
+ int
+current_search(
+ long count,
+ int forward) // TRUE for forward, FALSE for backward
+{
+ pos_T start_pos; // start position of the pattern match
+ pos_T end_pos; // end position of the pattern match
+ pos_T orig_pos; // position of the cursor at beginning
+ pos_T pos; // position after the pattern
+ int i;
+ int dir;
+ int result; // result of various function calls
+ char_u old_p_ws = p_ws;
+ int flags = 0;
+ pos_T save_VIsual = VIsual;
+ int one_char;
+
+ /* wrapping should not occur */
+ p_ws = FALSE;
+
+ /* Correct cursor when 'selection' is exclusive */
+ if (VIsual_active && *p_sel == 'e' && LT_POS(VIsual, curwin->w_cursor))
+ dec_cursor();
+
+ if (VIsual_active)
+ {
+ orig_pos = curwin->w_cursor;
+
+ pos = curwin->w_cursor;
+
+ /* make sure, searching further will extend the match */
+ if (VIsual_active)
+ {
+ if (forward)
+ incl(&pos);
+ else
+ decl(&pos);
+ }
+ }
+ else
+ orig_pos = pos = curwin->w_cursor;
+
+ /* Is the pattern is zero-width?, this time, don't care about the direction
+ */
+ one_char = is_one_char(spats[last_idx].pat, TRUE, &curwin->w_cursor,
+ FORWARD);
+ if (one_char == -1)
+ {
+ p_ws = old_p_ws;
+ return FAIL; /* pattern not found */
+ }
+
+ /*
+ * The trick is to first search backwards and then search forward again,
+ * so that a match at the current cursor position will be correctly
+ * captured.
+ */
+ for (i = 0; i < 2; i++)
+ {
+ if (forward)
+ dir = i;
+ else
+ dir = !i;
+
+ flags = 0;
+ if (!dir && !one_char)
+ flags = SEARCH_END;
+ end_pos = pos;
+
+ result = searchit(curwin, curbuf, &pos, &end_pos,
+ (dir ? FORWARD : BACKWARD),
+ spats[last_idx].pat, (long) (i ? count : 1),
+ SEARCH_KEEP | flags, RE_SEARCH, 0, NULL, NULL);
+
+ /* First search may fail, but then start searching from the
+ * beginning of the file (cursor might be on the search match)
+ * except when Visual mode is active, so that extending the visual
+ * selection works. */
+ if (i == 1 && !result) /* not found, abort */
+ {
+ curwin->w_cursor = orig_pos;
+ if (VIsual_active)
+ VIsual = save_VIsual;
+ p_ws = old_p_ws;
+ return FAIL;
+ }
+ else if (i == 0 && !result)
+ {
+ if (forward)
+ {
+ /* try again from start of buffer */
+ CLEAR_POS(&pos);
+ }
+ else
+ {
+ /* try again from end of buffer */
+ /* searching backwards, so set pos to last line and col */
+ pos.lnum = curwin->w_buffer->b_ml.ml_line_count;
+ pos.col = (colnr_T)STRLEN(
+ ml_get(curwin->w_buffer->b_ml.ml_line_count));
+ }
+ }
+ p_ws = old_p_ws;
+ }
+
+ start_pos = pos;
+ p_ws = old_p_ws;
+
+ if (!VIsual_active)
+ VIsual = start_pos;
+
+ // put cursor on last character of match
+ curwin->w_cursor = end_pos;
+ if (LT_POS(VIsual, end_pos))
+ dec_cursor();
+ VIsual_active = TRUE;
+ VIsual_mode = 'v';
+
+ if (VIsual_active)
+ {
+ redraw_curbuf_later(INVERTED); /* update the inversion */
+ if (*p_sel == 'e')
+ {
+ /* Correction for exclusive selection depends on the direction. */
+ if (forward && LTOREQ_POS(VIsual, curwin->w_cursor))
+ inc_cursor();
+ else if (!forward && LTOREQ_POS(curwin->w_cursor, VIsual))
+ inc(&VIsual);
+ }
+
+ }
+
+#ifdef FEAT_FOLDING
+ if (fdo_flags & FDO_SEARCH && KeyTyped)
+ foldOpenCursor();
+#endif
+
+ may_start_select('c');
+#ifdef FEAT_MOUSE
+ setmouse();
+#endif
+#ifdef FEAT_CLIPBOARD
+ /* Make sure the clipboard gets updated. Needed because start and
+ * end are still the same, and the selection needs to be owned */
+ clip_star.vmode = NUL;
+#endif
+ redraw_curbuf_later(INVERTED);
+ showmode();
+
+ return OK;
+}
+
+/*
+ * Check if the pattern is one character long or zero-width.
+ * If move is TRUE, check from the beginning of the buffer, else from position
+ * "cur".
+ * "direction" is FORWARD or BACKWARD.
+ * Returns TRUE, FALSE or -1 for failure.
+ */
+ static int
+is_one_char(char_u *pattern, int move, pos_T *cur, int direction)
+{
+ regmmatch_T regmatch;
+ int nmatched = 0;
+ int result = -1;
+ pos_T pos;
+ int save_called_emsg = called_emsg;
+ int flag = 0;
+
+ if (pattern == NULL)
+ pattern = spats[last_idx].pat;
+
+ if (search_regcomp(pattern, RE_SEARCH, RE_SEARCH,
+ SEARCH_KEEP, &regmatch) == FAIL)
+ return -1;
+
+ /* init startcol correctly */
+ regmatch.startpos[0].col = -1;
+ /* move to match */
+ if (move)
+ {
+ CLEAR_POS(&pos);
+ }
+ else
+ {
+ pos = *cur;
+ /* accept a match at the cursor position */
+ flag = SEARCH_START;
+ }
+
+ if (searchit(curwin, curbuf, &pos, NULL, direction, pattern, 1,
+ SEARCH_KEEP + flag, RE_SEARCH, 0, NULL, NULL) != FAIL)
+ {
+ /* Zero-width pattern should match somewhere, then we can check if
+ * start and end are in the same position. */
+ called_emsg = FALSE;
+ do
+ {
+ regmatch.startpos[0].col++;
+ nmatched = vim_regexec_multi(&regmatch, curwin, curbuf,
+ pos.lnum, regmatch.startpos[0].col, NULL, NULL);
+ if (!nmatched)
+ break;
+ } while (direction == FORWARD ? regmatch.startpos[0].col < pos.col
+ : regmatch.startpos[0].col > pos.col);
+
+ if (!called_emsg)
+ {
+ result = (nmatched != 0
+ && regmatch.startpos[0].lnum == regmatch.endpos[0].lnum
+ && regmatch.startpos[0].col == regmatch.endpos[0].col);
+ /* one char width */
+ if (!result && inc(&pos) >= 0 && pos.col == regmatch.endpos[0].col)
+ result = TRUE;
+ }
+ }
+
+ called_emsg |= save_called_emsg;
+ vim_regfree(regmatch.regprog);
+ return result;
+}
+
+#if defined(FEAT_LISP) || defined(FEAT_CINDENT) || defined(FEAT_TEXTOBJ) \
+ || defined(PROTO)
+/*
+ * return TRUE if line 'lnum' is empty or has white chars only.
+ */
+ int
+linewhite(linenr_T lnum)
+{
+ char_u *p;
+
+ p = skipwhite(ml_get(lnum));
+ return (*p == NUL);
+}
+#endif
+
+#if defined(FEAT_FIND_ID) || defined(PROTO)
+/*
+ * Find identifiers or defines in included files.
+ * If p_ic && (compl_cont_status & CONT_SOL) then ptr must be in lowercase.
+ */
+ void
+find_pattern_in_path(
+ char_u *ptr, /* pointer to search pattern */
+ int dir UNUSED, /* direction of expansion */
+ int len, /* length of search pattern */
+ int whole, /* match whole words only */
+ int skip_comments, /* don't match inside comments */
+ int type, /* Type of search; are we looking for a type?
+ a macro? */
+ long count,
+ int action, /* What to do when we find it */
+ linenr_T start_lnum, /* first line to start searching */
+ linenr_T end_lnum) /* last line for searching */
+{
+ SearchedFile *files; /* Stack of included files */
+ SearchedFile *bigger; /* When we need more space */
+ int max_path_depth = 50;
+ long match_count = 1;
+
+ char_u *pat;
+ char_u *new_fname;
+ char_u *curr_fname = curbuf->b_fname;
+ char_u *prev_fname = NULL;
+ linenr_T lnum;
+ int depth;
+ int depth_displayed; /* For type==CHECK_PATH */
+ int old_files;
+ int already_searched;
+ char_u *file_line;
+ char_u *line;
+ char_u *p;
+ char_u save_char;
+ int define_matched;
+ regmatch_T regmatch;
+ regmatch_T incl_regmatch;
+ regmatch_T def_regmatch;
+ int matched = FALSE;
+ int did_show = FALSE;
+ int found = FALSE;
+ int i;
+ char_u *already = NULL;
+ char_u *startp = NULL;
+ char_u *inc_opt = NULL;
+#if defined(FEAT_QUICKFIX)
+ win_T *curwin_save = NULL;
+#endif
+
+ regmatch.regprog = NULL;
+ incl_regmatch.regprog = NULL;
+ def_regmatch.regprog = NULL;
+
+ file_line = alloc(LSIZE);
+ if (file_line == NULL)
+ return;
+
+ if (type != CHECK_PATH && type != FIND_DEFINE
+#ifdef FEAT_INS_EXPAND
+ /* when CONT_SOL is set compare "ptr" with the beginning of the line
+ * is faster than quote_meta/regcomp/regexec "ptr" -- Acevedo */
+ && !(compl_cont_status & CONT_SOL)
+#endif
+ )
+ {
+ pat = alloc(len + 5);
+ if (pat == NULL)
+ goto fpip_end;
+ sprintf((char *)pat, whole ? "\\<%.*s\\>" : "%.*s", len, ptr);
+ /* ignore case according to p_ic, p_scs and pat */
+ regmatch.rm_ic = ignorecase(pat);
+ regmatch.regprog = vim_regcomp(pat, p_magic ? RE_MAGIC : 0);
+ vim_free(pat);
+ if (regmatch.regprog == NULL)
+ goto fpip_end;
+ }
+ inc_opt = (*curbuf->b_p_inc == NUL) ? p_inc : curbuf->b_p_inc;
+ if (*inc_opt != NUL)
+ {
+ incl_regmatch.regprog = vim_regcomp(inc_opt, p_magic ? RE_MAGIC : 0);
+ if (incl_regmatch.regprog == NULL)
+ goto fpip_end;
+ incl_regmatch.rm_ic = FALSE; /* don't ignore case in incl. pat. */
+ }
+ if (type == FIND_DEFINE && (*curbuf->b_p_def != NUL || *p_def != NUL))
+ {
+ def_regmatch.regprog = vim_regcomp(*curbuf->b_p_def == NUL
+ ? p_def : curbuf->b_p_def, p_magic ? RE_MAGIC : 0);
+ if (def_regmatch.regprog == NULL)
+ goto fpip_end;
+ def_regmatch.rm_ic = FALSE; /* don't ignore case in define pat. */
+ }
+ files = (SearchedFile *)lalloc_clear((long_u)
+ (max_path_depth * sizeof(SearchedFile)), TRUE);
+ if (files == NULL)
+ goto fpip_end;
+ old_files = max_path_depth;
+ depth = depth_displayed = -1;
+
+ lnum = start_lnum;
+ if (end_lnum > curbuf->b_ml.ml_line_count)
+ end_lnum = curbuf->b_ml.ml_line_count;
+ if (lnum > end_lnum) /* do at least one line */
+ lnum = end_lnum;
+ line = ml_get(lnum);
+
+ for (;;)
+ {
+ if (incl_regmatch.regprog != NULL
+ && vim_regexec(&incl_regmatch, line, (colnr_T)0))
+ {
+ char_u *p_fname = (curr_fname == curbuf->b_fname)
+ ? curbuf->b_ffname : curr_fname;
+
+ if (inc_opt != NULL && strstr((char *)inc_opt, "\\zs") != NULL)
+ /* Use text from '\zs' to '\ze' (or end) of 'include'. */
+ new_fname = find_file_name_in_path(incl_regmatch.startp[0],
+ (int)(incl_regmatch.endp[0] - incl_regmatch.startp[0]),
+ FNAME_EXP|FNAME_INCL|FNAME_REL, 1L, p_fname);
+ else
+ /* Use text after match with 'include'. */
+ new_fname = file_name_in_line(incl_regmatch.endp[0], 0,
+ FNAME_EXP|FNAME_INCL|FNAME_REL, 1L, p_fname, NULL);
+ already_searched = FALSE;
+ if (new_fname != NULL)
+ {
+ /* Check whether we have already searched in this file */
+ for (i = 0;; i++)
+ {
+ if (i == depth + 1)
+ i = old_files;
+ if (i == max_path_depth)
+ break;
+ if (fullpathcmp(new_fname, files[i].name, TRUE) & FPC_SAME)
+ {
+ if (type != CHECK_PATH &&
+ action == ACTION_SHOW_ALL && files[i].matched)
+ {
+ msg_putchar('\n'); /* cursor below last one */
+ if (!got_int) /* don't display if 'q'
+ typed at "--more--"
+ message */
+ {
+ msg_home_replace_hl(new_fname);
+ msg_puts(_(" (includes previously listed match)"));
+ prev_fname = NULL;
+ }
+ }
+ VIM_CLEAR(new_fname);
+ already_searched = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (type == CHECK_PATH && (action == ACTION_SHOW_ALL
+ || (new_fname == NULL && !already_searched)))
+ {
+ if (did_show)
+ msg_putchar('\n'); /* cursor below last one */
+ else
+ {
+ gotocmdline(TRUE); /* cursor at status line */
+ msg_puts_title(_("--- Included files "));
+ if (action != ACTION_SHOW_ALL)
+ msg_puts_title(_("not found "));
+ msg_puts_title(_("in path ---\n"));
+ }
+ did_show = TRUE;
+ while (depth_displayed < depth && !got_int)
+ {
+ ++depth_displayed;
+ for (i = 0; i < depth_displayed; i++)
+ msg_puts(" ");
+ msg_home_replace(files[depth_displayed].name);
+ msg_puts(" -->\n");
+ }
+ if (!got_int) /* don't display if 'q' typed
+ for "--more--" message */
+ {
+ for (i = 0; i <= depth_displayed; i++)
+ msg_puts(" ");
+ if (new_fname != NULL)
+ {
+ /* using "new_fname" is more reliable, e.g., when
+ * 'includeexpr' is set. */
+ msg_outtrans_attr(new_fname, HL_ATTR(HLF_D));
+ }
+ else
+ {
+ /*
+ * Isolate the file name.
+ * Include the surrounding "" or <> if present.
+ */
+ if (inc_opt != NULL
+ && strstr((char *)inc_opt, "\\zs") != NULL)
+ {
+ /* pattern contains \zs, use the match */
+ p = incl_regmatch.startp[0];
+ i = (int)(incl_regmatch.endp[0]
+ - incl_regmatch.startp[0]);
+ }
+ else
+ {
+ /* find the file name after the end of the match */
+ for (p = incl_regmatch.endp[0];
+ *p && !vim_isfilec(*p); p++)
+ ;
+ for (i = 0; vim_isfilec(p[i]); i++)
+ ;
+ }
+
+ if (i == 0)
+ {
+ /* Nothing found, use the rest of the line. */
+ p = incl_regmatch.endp[0];
+ i = (int)STRLEN(p);
+ }
+ /* Avoid checking before the start of the line, can
+ * happen if \zs appears in the regexp. */
+ else if (p > line)
+ {
+ if (p[-1] == '"' || p[-1] == '<')
+ {
+ --p;
+ ++i;
+ }
+ if (p[i] == '"' || p[i] == '>')
+ ++i;
+ }
+ save_char = p[i];
+ p[i] = NUL;
+ msg_outtrans_attr(p, HL_ATTR(HLF_D));
+ p[i] = save_char;
+ }
+
+ if (new_fname == NULL && action == ACTION_SHOW_ALL)
+ {
+ if (already_searched)
+ msg_puts(_(" (Already listed)"));
+ else
+ msg_puts(_(" NOT FOUND"));
+ }
+ }
+ out_flush(); /* output each line directly */
+ }
+
+ if (new_fname != NULL)
+ {
+ /* Push the new file onto the file stack */
+ if (depth + 1 == old_files)
+ {
+ bigger = (SearchedFile *)lalloc((long_u)(
+ max_path_depth * 2 * sizeof(SearchedFile)), TRUE);
+ if (bigger != NULL)
+ {
+ for (i = 0; i <= depth; i++)
+ bigger[i] = files[i];
+ for (i = depth + 1; i < old_files + max_path_depth; i++)
+ {
+ bigger[i].fp = NULL;
+ bigger[i].name = NULL;
+ bigger[i].lnum = 0;
+ bigger[i].matched = FALSE;
+ }
+ for (i = old_files; i < max_path_depth; i++)
+ bigger[i + max_path_depth] = files[i];
+ old_files += max_path_depth;
+ max_path_depth *= 2;
+ vim_free(files);
+ files = bigger;
+ }
+ }
+ if ((files[depth + 1].fp = mch_fopen((char *)new_fname, "r"))
+ == NULL)
+ vim_free(new_fname);
+ else
+ {
+ if (++depth == old_files)
+ {
+ /*
+ * lalloc() for 'bigger' must have failed above. We
+ * will forget one of our already visited files now.
+ */
+ vim_free(files[old_files].name);
+ ++old_files;
+ }
+ files[depth].name = curr_fname = new_fname;
+ files[depth].lnum = 0;
+ files[depth].matched = FALSE;
+#ifdef FEAT_INS_EXPAND
+ if (action == ACTION_EXPAND)
+ {
+ msg_hist_off = TRUE; /* reset in msg_trunc_attr() */
+ vim_snprintf((char*)IObuff, IOSIZE,
+ _("Scanning included file: %s"),
+ (char *)new_fname);
+ msg_trunc_attr((char *)IObuff, TRUE, HL_ATTR(HLF_R));
+ }
+ else
+#endif
+ if (p_verbose >= 5)
+ {
+ verbose_enter();
+ smsg(_("Searching included file %s"),
+ (char *)new_fname);
+ verbose_leave();
+ }
+
+ }
+ }
+ }
+ else
+ {
+ /*
+ * Check if the line is a define (type == FIND_DEFINE)
+ */
+ p = line;
+search_line:
+ define_matched = FALSE;
+ if (def_regmatch.regprog != NULL
+ && vim_regexec(&def_regmatch, line, (colnr_T)0))
+ {
+ /*
+ * Pattern must be first identifier after 'define', so skip
+ * to that position before checking for match of pattern. Also
+ * don't let it match beyond the end of this identifier.
+ */
+ p = def_regmatch.endp[0];
+ while (*p && !vim_iswordc(*p))
+ p++;
+ define_matched = TRUE;
+ }
+
+ /*
+ * Look for a match. Don't do this if we are looking for a
+ * define and this line didn't match define_prog above.
+ */
+ if (def_regmatch.regprog == NULL || define_matched)
+ {
+ if (define_matched
+#ifdef FEAT_INS_EXPAND
+ || (compl_cont_status & CONT_SOL)
+#endif
+ )
+ {
+ /* compare the first "len" chars from "ptr" */
+ startp = skipwhite(p);
+ if (p_ic)
+ matched = !MB_STRNICMP(startp, ptr, len);
+ else
+ matched = !STRNCMP(startp, ptr, len);
+ if (matched && define_matched && whole
+ && vim_iswordc(startp[len]))
+ matched = FALSE;
+ }
+ else if (regmatch.regprog != NULL
+ && vim_regexec(&regmatch, line, (colnr_T)(p - line)))
+ {
+ matched = TRUE;
+ startp = regmatch.startp[0];
+ /*
+ * Check if the line is not a comment line (unless we are
+ * looking for a define). A line starting with "# define"
+ * is not considered to be a comment line.
+ */
+ if (!define_matched && skip_comments)
+ {
+#ifdef FEAT_COMMENTS
+ if ((*line != '#' ||
+ STRNCMP(skipwhite(line + 1), "define", 6) != 0)
+ && get_leader_len(line, NULL, FALSE, TRUE))
+ matched = FALSE;
+
+ /*
+ * Also check for a "/ *" or "/ /" before the match.
+ * Skips lines like "int backwards; / * normal index
+ * * /" when looking for "normal".
+ * Note: Doesn't skip "/ *" in comments.
+ */
+ p = skipwhite(line);
+ if (matched
+ || (p[0] == '/' && p[1] == '*') || p[0] == '*')
+#endif
+ for (p = line; *p && p < startp; ++p)
+ {
+ if (matched
+ && p[0] == '/'
+ && (p[1] == '*' || p[1] == '/'))
+ {
+ matched = FALSE;
+ /* After "//" all text is comment */
+ if (p[1] == '/')
+ break;
+ ++p;
+ }
+ else if (!matched && p[0] == '*' && p[1] == '/')
+ {
+ /* Can find match after "* /". */
+ matched = TRUE;
+ ++p;
+ }
+ }
+ }
+ }
+ }
+ }
+ if (matched)
+ {
+#ifdef FEAT_INS_EXPAND
+ if (action == ACTION_EXPAND)
+ {
+ int reuse = 0;
+ int add_r;
+ char_u *aux;
+
+ if (depth == -1 && lnum == curwin->w_cursor.lnum)
+ break;
+ found = TRUE;
+ aux = p = startp;
+ if (compl_cont_status & CONT_ADDING)
+ {
+ p += compl_length;
+ if (vim_iswordp(p))
+ goto exit_matched;
+ p = find_word_start(p);
+ }
+ p = find_word_end(p);
+ i = (int)(p - aux);
+
+ if ((compl_cont_status & CONT_ADDING) && i == compl_length)
+ {
+ /* IOSIZE > compl_length, so the STRNCPY works */
+ STRNCPY(IObuff, aux, i);
+
+ /* Get the next line: when "depth" < 0 from the current
+ * buffer, otherwise from the included file. Jump to
+ * exit_matched when past the last line. */
+ if (depth < 0)
+ {
+ if (lnum >= end_lnum)
+ goto exit_matched;
+ line = ml_get(++lnum);
+ }
+ else if (vim_fgets(line = file_line,
+ LSIZE, files[depth].fp))
+ goto exit_matched;
+
+ /* we read a line, set "already" to check this "line" later
+ * if depth >= 0 we'll increase files[depth].lnum far
+ * bellow -- Acevedo */
+ already = aux = p = skipwhite(line);
+ p = find_word_start(p);
+ p = find_word_end(p);
+ if (p > aux)
+ {
+ if (*aux != ')' && IObuff[i-1] != TAB)
+ {
+ if (IObuff[i-1] != ' ')
+ IObuff[i++] = ' ';
+ /* IObuf =~ "\(\k\|\i\).* ", thus i >= 2*/
+ if (p_js
+ && (IObuff[i-2] == '.'
+ || (vim_strchr(p_cpo, CPO_JOINSP) == NULL
+ && (IObuff[i-2] == '?'
+ || IObuff[i-2] == '!'))))
+ IObuff[i++] = ' ';
+ }
+ /* copy as much as possible of the new word */
+ if (p - aux >= IOSIZE - i)
+ p = aux + IOSIZE - i - 1;
+ STRNCPY(IObuff + i, aux, p - aux);
+ i += (int)(p - aux);
+ reuse |= CONT_S_IPOS;
+ }
+ IObuff[i] = NUL;
+ aux = IObuff;
+
+ if (i == compl_length)
+ goto exit_matched;
+ }
+
+ add_r = ins_compl_add_infercase(aux, i, p_ic,
+ curr_fname == curbuf->b_fname ? NULL : curr_fname,
+ dir, reuse);
+ if (add_r == OK)
+ /* if dir was BACKWARD then honor it just once */
+ dir = FORWARD;
+ else if (add_r == FAIL)
+ break;
+ }
+ else
+#endif
+ if (action == ACTION_SHOW_ALL)
+ {
+ found = TRUE;
+ if (!did_show)
+ gotocmdline(TRUE); /* cursor at status line */
+ if (curr_fname != prev_fname)
+ {
+ if (did_show)
+ msg_putchar('\n'); /* cursor below last one */
+ if (!got_int) /* don't display if 'q' typed
+ at "--more--" message */
+ msg_home_replace_hl(curr_fname);
+ prev_fname = curr_fname;
+ }
+ did_show = TRUE;
+ if (!got_int)
+ show_pat_in_path(line, type, TRUE, action,
+ (depth == -1) ? NULL : files[depth].fp,
+ (depth == -1) ? &lnum : &files[depth].lnum,
+ match_count++);
+
+ /* Set matched flag for this file and all the ones that
+ * include it */
+ for (i = 0; i <= depth; ++i)
+ files[i].matched = TRUE;
+ }
+ else if (--count <= 0)
+ {
+ found = TRUE;
+ if (depth == -1 && lnum == curwin->w_cursor.lnum
+#if defined(FEAT_QUICKFIX)
+ && g_do_tagpreview == 0
+#endif
+ )
+ emsg(_("E387: Match is on current line"));
+ else if (action == ACTION_SHOW)
+ {
+ show_pat_in_path(line, type, did_show, action,
+ (depth == -1) ? NULL : files[depth].fp,
+ (depth == -1) ? &lnum : &files[depth].lnum, 1L);
+ did_show = TRUE;
+ }
+ else
+ {
+#ifdef FEAT_GUI
+ need_mouse_correct = TRUE;
+#endif
+#if defined(FEAT_QUICKFIX)
+ /* ":psearch" uses the preview window */
+ if (g_do_tagpreview != 0)
+ {
+ curwin_save = curwin;
+ prepare_tagpreview(TRUE);
+ }
+#endif
+ if (action == ACTION_SPLIT)
+ {
+ if (win_split(0, 0) == FAIL)
+ break;
+ RESET_BINDING(curwin);
+ }
+ if (depth == -1)
+ {
+ /* match in current file */
+#if defined(FEAT_QUICKFIX)
+ if (g_do_tagpreview != 0)
+ {
+ if (!GETFILE_SUCCESS(getfile(
+ curwin_save->w_buffer->b_fnum, NULL,
+ NULL, TRUE, lnum, FALSE)))
+ break; /* failed to jump to file */
+ }
+ else
+#endif
+ setpcmark();
+ curwin->w_cursor.lnum = lnum;
+ check_cursor();
+ }
+ else
+ {
+ if (!GETFILE_SUCCESS(getfile(
+ 0, files[depth].name, NULL, TRUE,
+ files[depth].lnum, FALSE)))
+ break; /* failed to jump to file */
+ /* autocommands may have changed the lnum, we don't
+ * want that here */
+ curwin->w_cursor.lnum = files[depth].lnum;
+ }
+ }
+ if (action != ACTION_SHOW)
+ {
+ curwin->w_cursor.col = (colnr_T)(startp - line);
+ curwin->w_set_curswant = TRUE;
+ }
+
+#if defined(FEAT_QUICKFIX)
+ if (g_do_tagpreview != 0
+ && curwin != curwin_save && win_valid(curwin_save))
+ {
+ /* Return cursor to where we were */
+ validate_cursor();
+ redraw_later(VALID);
+ win_enter(curwin_save, TRUE);
+ }
+#endif
+ break;
+ }
+#ifdef FEAT_INS_EXPAND
+exit_matched:
+#endif
+ matched = FALSE;
+ /* look for other matches in the rest of the line if we
+ * are not at the end of it already */
+ if (def_regmatch.regprog == NULL
+#ifdef FEAT_INS_EXPAND
+ && action == ACTION_EXPAND
+ && !(compl_cont_status & CONT_SOL)
+#endif
+ && *startp != NUL
+ && *(p = startp + MB_PTR2LEN(startp)) != NUL)
+ goto search_line;
+ }
+ line_breakcheck();
+#ifdef FEAT_INS_EXPAND
+ if (action == ACTION_EXPAND)
+ ins_compl_check_keys(30, FALSE);
+ if (got_int || compl_interrupted)
+#else
+ if (got_int)
+#endif
+ break;
+
+ /*
+ * Read the next line. When reading an included file and encountering
+ * end-of-file, close the file and continue in the file that included
+ * it.
+ */
+ while (depth >= 0 && !already
+ && vim_fgets(line = file_line, LSIZE, files[depth].fp))
+ {
+ fclose(files[depth].fp);
+ --old_files;
+ files[old_files].name = files[depth].name;
+ files[old_files].matched = files[depth].matched;
+ --depth;
+ curr_fname = (depth == -1) ? curbuf->b_fname
+ : files[depth].name;
+ if (depth < depth_displayed)
+ depth_displayed = depth;
+ }
+ if (depth >= 0) /* we could read the line */
+ {
+ files[depth].lnum++;
+ /* Remove any CR and LF from the line. */
+ i = (int)STRLEN(line);
+ if (i > 0 && line[i - 1] == '\n')
+ line[--i] = NUL;
+ if (i > 0 && line[i - 1] == '\r')
+ line[--i] = NUL;
+ }
+ else if (!already)
+ {
+ if (++lnum > end_lnum)
+ break;
+ line = ml_get(lnum);
+ }
+ already = NULL;
+ }
+ /* End of big for (;;) loop. */
+
+ /* Close any files that are still open. */
+ for (i = 0; i <= depth; i++)
+ {
+ fclose(files[i].fp);
+ vim_free(files[i].name);
+ }
+ for (i = old_files; i < max_path_depth; i++)
+ vim_free(files[i].name);
+ vim_free(files);
+
+ if (type == CHECK_PATH)
+ {
+ if (!did_show)
+ {
+ if (action != ACTION_SHOW_ALL)
+ msg(_("All included files were found"));
+ else
+ msg(_("No included files"));
+ }
+ }
+ else if (!found
+#ifdef FEAT_INS_EXPAND
+ && action != ACTION_EXPAND
+#endif
+ )
+ {
+#ifdef FEAT_INS_EXPAND
+ if (got_int || compl_interrupted)
+#else
+ if (got_int)
+#endif
+ emsg(_(e_interr));
+ else if (type == FIND_DEFINE)
+ emsg(_("E388: Couldn't find definition"));
+ else
+ emsg(_("E389: Couldn't find pattern"));
+ }
+ if (action == ACTION_SHOW || action == ACTION_SHOW_ALL)
+ msg_end();
+
+fpip_end:
+ vim_free(file_line);
+ vim_regfree(regmatch.regprog);
+ vim_regfree(incl_regmatch.regprog);
+ vim_regfree(def_regmatch.regprog);
+}
+
+ static void
+show_pat_in_path(
+ char_u *line,
+ int type,
+ int did_show,
+ int action,
+ FILE *fp,
+ linenr_T *lnum,
+ long count)
+{
+ char_u *p;
+
+ if (did_show)
+ msg_putchar('\n'); /* cursor below last one */
+ else if (!msg_silent)
+ gotocmdline(TRUE); /* cursor at status line */
+ if (got_int) /* 'q' typed at "--more--" message */
+ return;
+ for (;;)
+ {
+ p = line + STRLEN(line) - 1;
+ if (fp != NULL)
+ {
+ /* We used fgets(), so get rid of newline at end */
+ if (p >= line && *p == '\n')
+ --p;
+ if (p >= line && *p == '\r')
+ --p;
+ *(p + 1) = NUL;
+ }
+ if (action == ACTION_SHOW_ALL)
+ {
+ sprintf((char *)IObuff, "%3ld: ", count); /* show match nr */
+ msg_puts((char *)IObuff);
+ sprintf((char *)IObuff, "%4ld", *lnum); /* show line nr */
+ /* Highlight line numbers */
+ msg_puts_attr((char *)IObuff, HL_ATTR(HLF_N));
+ msg_puts(" ");
+ }
+ msg_prt_line(line, FALSE);
+ out_flush(); /* show one line at a time */
+
+ /* Definition continues until line that doesn't end with '\' */
+ if (got_int || type != FIND_DEFINE || p < line || *p != '\\')
+ break;
+
+ if (fp != NULL)
+ {
+ if (vim_fgets(line, LSIZE, fp)) /* end of file */
+ break;
+ ++*lnum;
+ }
+ else
+ {
+ if (++*lnum > curbuf->b_ml.ml_line_count)
+ break;
+ line = ml_get(*lnum);
+ }
+ msg_putchar('\n');
+ }
+}
+#endif
+
+#ifdef FEAT_VIMINFO
+ int
+read_viminfo_search_pattern(vir_T *virp, int force)
+{
+ char_u *lp;
+ int idx = -1;
+ int magic = FALSE;
+ int no_scs = FALSE;
+ int off_line = FALSE;
+ int off_end = 0;
+ long off = 0;
+ int setlast = FALSE;
+#ifdef FEAT_SEARCH_EXTRA
+ static int hlsearch_on = FALSE;
+#endif
+ char_u *val;
+
+ /*
+ * Old line types:
+ * "/pat", "&pat": search/subst. pat
+ * "~/pat", "~&pat": last used search/subst. pat
+ * New line types:
+ * "~h", "~H": hlsearch highlighting off/on
+ * "~<magic><smartcase><line><end><off><last><which>pat"
+ * <magic>: 'm' off, 'M' on
+ * <smartcase>: 's' off, 'S' on
+ * <line>: 'L' line offset, 'l' char offset
+ * <end>: 'E' from end, 'e' from start
+ * <off>: decimal, offset
+ * <last>: '~' last used pattern
+ * <which>: '/' search pat, '&' subst. pat
+ */
+ lp = virp->vir_line;
+ if (lp[0] == '~' && (lp[1] == 'm' || lp[1] == 'M')) /* new line type */
+ {
+ if (lp[1] == 'M') /* magic on */
+ magic = TRUE;
+ if (lp[2] == 's')
+ no_scs = TRUE;
+ if (lp[3] == 'L')
+ off_line = TRUE;
+ if (lp[4] == 'E')
+ off_end = SEARCH_END;
+ lp += 5;
+ off = getdigits(&lp);
+ }
+ if (lp[0] == '~') /* use this pattern for last-used pattern */
+ {
+ setlast = TRUE;
+ lp++;
+ }
+ if (lp[0] == '/')
+ idx = RE_SEARCH;
+ else if (lp[0] == '&')
+ idx = RE_SUBST;
+#ifdef FEAT_SEARCH_EXTRA
+ else if (lp[0] == 'h') /* ~h: 'hlsearch' highlighting off */
+ hlsearch_on = FALSE;
+ else if (lp[0] == 'H') /* ~H: 'hlsearch' highlighting on */
+ hlsearch_on = TRUE;
+#endif
+ if (idx >= 0)
+ {
+ if (force || spats[idx].pat == NULL)
+ {
+ val = viminfo_readstring(virp, (int)(lp - virp->vir_line + 1),
+ TRUE);
+ if (val != NULL)
+ {
+ set_last_search_pat(val, idx, magic, setlast);
+ vim_free(val);
+ spats[idx].no_scs = no_scs;
+ spats[idx].off.line = off_line;
+ spats[idx].off.end = off_end;
+ spats[idx].off.off = off;
+#ifdef FEAT_SEARCH_EXTRA
+ if (setlast)
+ set_no_hlsearch(!hlsearch_on);
+#endif
+ }
+ }
+ }
+ return viminfo_readline(virp);
+}
+
+ void
+write_viminfo_search_pattern(FILE *fp)
+{
+ if (get_viminfo_parameter('/') != 0)
+ {
+#ifdef FEAT_SEARCH_EXTRA
+ fprintf(fp, "\n# hlsearch on (H) or off (h):\n~%c",
+ (no_hlsearch || find_viminfo_parameter('h') != NULL) ? 'h' : 'H');
+#endif
+ wvsp_one(fp, RE_SEARCH, "", '/');
+ wvsp_one(fp, RE_SUBST, _("Substitute "), '&');
+ }
+}
+
+ static void
+wvsp_one(
+ FILE *fp, /* file to write to */
+ int idx, /* spats[] index */
+ char *s, /* search pat */
+ int sc) /* dir char */
+{
+ if (spats[idx].pat != NULL)
+ {
+ fprintf(fp, _("\n# Last %sSearch Pattern:\n~"), s);
+ /* off.dir is not stored, it's reset to forward */
+ fprintf(fp, "%c%c%c%c%ld%s%c",
+ spats[idx].magic ? 'M' : 'm', /* magic */
+ spats[idx].no_scs ? 's' : 'S', /* smartcase */
+ spats[idx].off.line ? 'L' : 'l', /* line offset */
+ spats[idx].off.end ? 'E' : 'e', /* offset from end */
+ spats[idx].off.off, /* offset */
+ last_idx == idx ? "~" : "", /* last used pat */
+ sc);
+ viminfo_writestring(fp, spats[idx].pat);
+ }
+}
+#endif /* FEAT_VIMINFO */
diff --git a/src/sha256.c b/src/sha256.c
new file mode 100644
index 0000000..98ccffe
--- /dev/null
+++ b/src/sha256.c
@@ -0,0 +1,427 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ *
+ * FIPS-180-2 compliant SHA-256 implementation
+ * GPL by Christophe Devine, applies to older version.
+ * Modified for md5deep, in public domain.
+ * Modified For Vim, Mohsin Ahmed, http://www.cs.albany.edu/~mosh
+ * Mohsin Ahmed states this work is distributed under the VIM License or GPL,
+ * at your choice.
+ *
+ * Vim specific notes:
+ * Functions exported by this file:
+ * 1. sha256_key() hashes the password to 64 bytes char string.
+ * 2. sha2_seed() generates a random header.
+ * sha256_self_test() is implicitly called once.
+ */
+
+#include "vim.h"
+
+#if defined(FEAT_CRYPT) || defined(FEAT_PERSISTENT_UNDO)
+
+#define GET_UINT32(n, b, i) \
+{ \
+ (n) = ( (UINT32_T)(b)[(i) ] << 24) \
+ | ( (UINT32_T)(b)[(i) + 1] << 16) \
+ | ( (UINT32_T)(b)[(i) + 2] << 8) \
+ | ( (UINT32_T)(b)[(i) + 3] ); \
+}
+
+#define PUT_UINT32(n,b,i) \
+{ \
+ (b)[(i) ] = (char_u)((n) >> 24); \
+ (b)[(i) + 1] = (char_u)((n) >> 16); \
+ (b)[(i) + 2] = (char_u)((n) >> 8); \
+ (b)[(i) + 3] = (char_u)((n) ); \
+}
+
+ void
+sha256_start(context_sha256_T *ctx)
+{
+ ctx->total[0] = 0;
+ ctx->total[1] = 0;
+
+ ctx->state[0] = 0x6A09E667;
+ ctx->state[1] = 0xBB67AE85;
+ ctx->state[2] = 0x3C6EF372;
+ ctx->state[3] = 0xA54FF53A;
+ ctx->state[4] = 0x510E527F;
+ ctx->state[5] = 0x9B05688C;
+ ctx->state[6] = 0x1F83D9AB;
+ ctx->state[7] = 0x5BE0CD19;
+}
+
+ static void
+sha256_process(context_sha256_T *ctx, char_u data[64])
+{
+ UINT32_T temp1, temp2, W[64];
+ UINT32_T A, B, C, D, E, F, G, H;
+
+ GET_UINT32(W[0], data, 0);
+ GET_UINT32(W[1], data, 4);
+ GET_UINT32(W[2], data, 8);
+ GET_UINT32(W[3], data, 12);
+ GET_UINT32(W[4], data, 16);
+ GET_UINT32(W[5], data, 20);
+ GET_UINT32(W[6], data, 24);
+ GET_UINT32(W[7], data, 28);
+ GET_UINT32(W[8], data, 32);
+ GET_UINT32(W[9], data, 36);
+ GET_UINT32(W[10], data, 40);
+ GET_UINT32(W[11], data, 44);
+ GET_UINT32(W[12], data, 48);
+ GET_UINT32(W[13], data, 52);
+ GET_UINT32(W[14], data, 56);
+ GET_UINT32(W[15], data, 60);
+
+#define SHR(x, n) ((x & 0xFFFFFFFF) >> n)
+#define ROTR(x, n) (SHR(x, n) | (x << (32 - n)))
+
+#define S0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHR(x, 3))
+#define S1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHR(x, 10))
+
+#define S2(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22))
+#define S3(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25))
+
+#define F0(x, y, z) ((x & y) | (z & (x | y)))
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+
+#define R(t) \
+( \
+ W[t] = S1(W[t - 2]) + W[t - 7] + \
+ S0(W[t - 15]) + W[t - 16] \
+)
+
+#define P(a,b,c,d,e,f,g,h,x,K) \
+{ \
+ temp1 = h + S3(e) + F1(e, f, g) + K + x; \
+ temp2 = S2(a) + F0(a, b, c); \
+ d += temp1; h = temp1 + temp2; \
+}
+
+ A = ctx->state[0];
+ B = ctx->state[1];
+ C = ctx->state[2];
+ D = ctx->state[3];
+ E = ctx->state[4];
+ F = ctx->state[5];
+ G = ctx->state[6];
+ H = ctx->state[7];
+
+ P( A, B, C, D, E, F, G, H, W[ 0], 0x428A2F98);
+ P( H, A, B, C, D, E, F, G, W[ 1], 0x71374491);
+ P( G, H, A, B, C, D, E, F, W[ 2], 0xB5C0FBCF);
+ P( F, G, H, A, B, C, D, E, W[ 3], 0xE9B5DBA5);
+ P( E, F, G, H, A, B, C, D, W[ 4], 0x3956C25B);
+ P( D, E, F, G, H, A, B, C, W[ 5], 0x59F111F1);
+ P( C, D, E, F, G, H, A, B, W[ 6], 0x923F82A4);
+ P( B, C, D, E, F, G, H, A, W[ 7], 0xAB1C5ED5);
+ P( A, B, C, D, E, F, G, H, W[ 8], 0xD807AA98);
+ P( H, A, B, C, D, E, F, G, W[ 9], 0x12835B01);
+ P( G, H, A, B, C, D, E, F, W[10], 0x243185BE);
+ P( F, G, H, A, B, C, D, E, W[11], 0x550C7DC3);
+ P( E, F, G, H, A, B, C, D, W[12], 0x72BE5D74);
+ P( D, E, F, G, H, A, B, C, W[13], 0x80DEB1FE);
+ P( C, D, E, F, G, H, A, B, W[14], 0x9BDC06A7);
+ P( B, C, D, E, F, G, H, A, W[15], 0xC19BF174);
+ P( A, B, C, D, E, F, G, H, R(16), 0xE49B69C1);
+ P( H, A, B, C, D, E, F, G, R(17), 0xEFBE4786);
+ P( G, H, A, B, C, D, E, F, R(18), 0x0FC19DC6);
+ P( F, G, H, A, B, C, D, E, R(19), 0x240CA1CC);
+ P( E, F, G, H, A, B, C, D, R(20), 0x2DE92C6F);
+ P( D, E, F, G, H, A, B, C, R(21), 0x4A7484AA);
+ P( C, D, E, F, G, H, A, B, R(22), 0x5CB0A9DC);
+ P( B, C, D, E, F, G, H, A, R(23), 0x76F988DA);
+ P( A, B, C, D, E, F, G, H, R(24), 0x983E5152);
+ P( H, A, B, C, D, E, F, G, R(25), 0xA831C66D);
+ P( G, H, A, B, C, D, E, F, R(26), 0xB00327C8);
+ P( F, G, H, A, B, C, D, E, R(27), 0xBF597FC7);
+ P( E, F, G, H, A, B, C, D, R(28), 0xC6E00BF3);
+ P( D, E, F, G, H, A, B, C, R(29), 0xD5A79147);
+ P( C, D, E, F, G, H, A, B, R(30), 0x06CA6351);
+ P( B, C, D, E, F, G, H, A, R(31), 0x14292967);
+ P( A, B, C, D, E, F, G, H, R(32), 0x27B70A85);
+ P( H, A, B, C, D, E, F, G, R(33), 0x2E1B2138);
+ P( G, H, A, B, C, D, E, F, R(34), 0x4D2C6DFC);
+ P( F, G, H, A, B, C, D, E, R(35), 0x53380D13);
+ P( E, F, G, H, A, B, C, D, R(36), 0x650A7354);
+ P( D, E, F, G, H, A, B, C, R(37), 0x766A0ABB);
+ P( C, D, E, F, G, H, A, B, R(38), 0x81C2C92E);
+ P( B, C, D, E, F, G, H, A, R(39), 0x92722C85);
+ P( A, B, C, D, E, F, G, H, R(40), 0xA2BFE8A1);
+ P( H, A, B, C, D, E, F, G, R(41), 0xA81A664B);
+ P( G, H, A, B, C, D, E, F, R(42), 0xC24B8B70);
+ P( F, G, H, A, B, C, D, E, R(43), 0xC76C51A3);
+ P( E, F, G, H, A, B, C, D, R(44), 0xD192E819);
+ P( D, E, F, G, H, A, B, C, R(45), 0xD6990624);
+ P( C, D, E, F, G, H, A, B, R(46), 0xF40E3585);
+ P( B, C, D, E, F, G, H, A, R(47), 0x106AA070);
+ P( A, B, C, D, E, F, G, H, R(48), 0x19A4C116);
+ P( H, A, B, C, D, E, F, G, R(49), 0x1E376C08);
+ P( G, H, A, B, C, D, E, F, R(50), 0x2748774C);
+ P( F, G, H, A, B, C, D, E, R(51), 0x34B0BCB5);
+ P( E, F, G, H, A, B, C, D, R(52), 0x391C0CB3);
+ P( D, E, F, G, H, A, B, C, R(53), 0x4ED8AA4A);
+ P( C, D, E, F, G, H, A, B, R(54), 0x5B9CCA4F);
+ P( B, C, D, E, F, G, H, A, R(55), 0x682E6FF3);
+ P( A, B, C, D, E, F, G, H, R(56), 0x748F82EE);
+ P( H, A, B, C, D, E, F, G, R(57), 0x78A5636F);
+ P( G, H, A, B, C, D, E, F, R(58), 0x84C87814);
+ P( F, G, H, A, B, C, D, E, R(59), 0x8CC70208);
+ P( E, F, G, H, A, B, C, D, R(60), 0x90BEFFFA);
+ P( D, E, F, G, H, A, B, C, R(61), 0xA4506CEB);
+ P( C, D, E, F, G, H, A, B, R(62), 0xBEF9A3F7);
+ P( B, C, D, E, F, G, H, A, R(63), 0xC67178F2);
+
+ ctx->state[0] += A;
+ ctx->state[1] += B;
+ ctx->state[2] += C;
+ ctx->state[3] += D;
+ ctx->state[4] += E;
+ ctx->state[5] += F;
+ ctx->state[6] += G;
+ ctx->state[7] += H;
+}
+
+ void
+sha256_update(context_sha256_T *ctx, char_u *input, UINT32_T length)
+{
+ UINT32_T left, fill;
+
+ if (length == 0)
+ return;
+
+ left = ctx->total[0] & 0x3F;
+ fill = 64 - left;
+
+ ctx->total[0] += length;
+ ctx->total[0] &= 0xFFFFFFFF;
+
+ if (ctx->total[0] < length)
+ ctx->total[1]++;
+
+ if (left && length >= fill)
+ {
+ memcpy((void *)(ctx->buffer + left), (void *)input, fill);
+ sha256_process(ctx, ctx->buffer);
+ length -= fill;
+ input += fill;
+ left = 0;
+ }
+
+ while (length >= 64)
+ {
+ sha256_process(ctx, input);
+ length -= 64;
+ input += 64;
+ }
+
+ if (length)
+ memcpy((void *)(ctx->buffer + left), (void *)input, length);
+}
+
+static char_u sha256_padding[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+ void
+sha256_finish(context_sha256_T *ctx, char_u digest[32])
+{
+ UINT32_T last, padn;
+ UINT32_T high, low;
+ char_u msglen[8];
+
+ high = (ctx->total[0] >> 29) | (ctx->total[1] << 3);
+ low = (ctx->total[0] << 3);
+
+ PUT_UINT32(high, msglen, 0);
+ PUT_UINT32(low, msglen, 4);
+
+ last = ctx->total[0] & 0x3F;
+ padn = (last < 56) ? (56 - last) : (120 - last);
+
+ sha256_update(ctx, sha256_padding, padn);
+ sha256_update(ctx, msglen, 8);
+
+ PUT_UINT32(ctx->state[0], digest, 0);
+ PUT_UINT32(ctx->state[1], digest, 4);
+ PUT_UINT32(ctx->state[2], digest, 8);
+ PUT_UINT32(ctx->state[3], digest, 12);
+ PUT_UINT32(ctx->state[4], digest, 16);
+ PUT_UINT32(ctx->state[5], digest, 20);
+ PUT_UINT32(ctx->state[6], digest, 24);
+ PUT_UINT32(ctx->state[7], digest, 28);
+}
+#endif /* FEAT_CRYPT || FEAT_PERSISTENT_UNDO */
+
+#if defined(FEAT_CRYPT) || defined(PROTO)
+/*
+ * Returns hex digest of "buf[buf_len]" in a static array.
+ * if "salt" is not NULL also do "salt[salt_len]".
+ */
+ char_u *
+sha256_bytes(
+ char_u *buf,
+ int buf_len,
+ char_u *salt,
+ int salt_len)
+{
+ char_u sha256sum[32];
+ static char_u hexit[65];
+ int j;
+ context_sha256_T ctx;
+
+ sha256_self_test();
+
+ sha256_start(&ctx);
+ sha256_update(&ctx, buf, buf_len);
+ if (salt != NULL)
+ sha256_update(&ctx, salt, salt_len);
+ sha256_finish(&ctx, sha256sum);
+ for (j = 0; j < 32; j++)
+ sprintf((char *)hexit + j * 2, "%02x", sha256sum[j]);
+ hexit[sizeof(hexit) - 1] = '\0';
+ return hexit;
+}
+
+/*
+ * Returns sha256(buf) as 64 hex chars in static array.
+ */
+ char_u *
+sha256_key(
+ char_u *buf,
+ char_u *salt,
+ int salt_len)
+{
+ /* No passwd means don't encrypt */
+ if (buf == NULL || *buf == NUL)
+ return (char_u *)"";
+
+ return sha256_bytes(buf, (int)STRLEN(buf), salt, salt_len);
+}
+
+/*
+ * These are the standard FIPS-180-2 test vectors
+ */
+
+static char *sha_self_test_msg[] = {
+ "abc",
+ "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+ NULL
+};
+
+static char *sha_self_test_vector[] = {
+ "ba7816bf8f01cfea414140de5dae2223" \
+ "b00361a396177a9cb410ff61f20015ad",
+ "248d6a61d20638b8e5c026930c3e6039" \
+ "a33ce45964ff2167f6ecedd419db06c1",
+ "cdc76e5c9914fb9281a1c7e284d73e67" \
+ "f1809a48a497200e046d39ccc7112cd0"
+};
+
+/*
+ * Perform a test on the SHA256 algorithm.
+ * Return FAIL or OK.
+ */
+ int
+sha256_self_test(void)
+{
+ int i, j;
+ char output[65];
+ context_sha256_T ctx;
+ char_u buf[1000];
+ char_u sha256sum[32];
+ static int failures = 0;
+ char_u *hexit;
+ static int sha256_self_tested = 0;
+
+ if (sha256_self_tested > 0)
+ return failures > 0 ? FAIL : OK;
+ sha256_self_tested = 1;
+
+ for (i = 0; i < 3; i++)
+ {
+ if (i < 2)
+ {
+ hexit = sha256_bytes((char_u *)sha_self_test_msg[i],
+ (int)STRLEN(sha_self_test_msg[i]),
+ NULL, 0);
+ STRCPY(output, hexit);
+ }
+ else
+ {
+ sha256_start(&ctx);
+ vim_memset(buf, 'a', 1000);
+ for (j = 0; j < 1000; j++)
+ sha256_update(&ctx, (char_u *)buf, 1000);
+ sha256_finish(&ctx, sha256sum);
+ for (j = 0; j < 32; j++)
+ sprintf(output + j * 2, "%02x", sha256sum[j]);
+ }
+ if (memcmp(output, sha_self_test_vector[i], 64))
+ {
+ failures++;
+ output[sizeof(output) - 1] = '\0';
+ /* printf("sha256_self_test %d failed %s\n", i, output); */
+ }
+ }
+ return failures > 0 ? FAIL : OK;
+}
+
+ static unsigned int
+get_some_time(void)
+{
+# ifdef HAVE_GETTIMEOFDAY
+ struct timeval tv;
+
+ /* Using usec makes it less predictable. */
+ gettimeofday(&tv, NULL);
+ return (unsigned int)(tv.tv_sec + tv.tv_usec);
+# else
+ return (unsigned int)time(NULL);
+# endif
+}
+
+/*
+ * Fill "header[header_len]" with random_data.
+ * Also "salt[salt_len]" when "salt" is not NULL.
+ */
+ void
+sha2_seed(
+ char_u *header,
+ int header_len,
+ char_u *salt,
+ int salt_len)
+{
+ int i;
+ static char_u random_data[1000];
+ char_u sha256sum[32];
+ context_sha256_T ctx;
+
+ srand(get_some_time());
+
+ for (i = 0; i < (int)sizeof(random_data) - 1; i++)
+ random_data[i] = (char_u)((get_some_time() ^ rand()) & 0xff);
+ sha256_start(&ctx);
+ sha256_update(&ctx, (char_u *)random_data, sizeof(random_data));
+ sha256_finish(&ctx, sha256sum);
+
+ /* put first block into header. */
+ for (i = 0; i < header_len; i++)
+ header[i] = sha256sum[i % sizeof(sha256sum)];
+
+ /* put remaining block into salt. */
+ if (salt != NULL)
+ for (i = 0; i < salt_len; i++)
+ salt[i] = sha256sum[(i + header_len) % sizeof(sha256sum)];
+}
+
+#endif /* FEAT_CRYPT */
diff --git a/src/sign.c b/src/sign.c
new file mode 100644
index 0000000..44b638c
--- /dev/null
+++ b/src/sign.c
@@ -0,0 +1,1941 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * sign.c: functions for managing signs
+ */
+
+#include "vim.h"
+
+#if defined(FEAT_SIGNS) || defined(PROTO)
+
+/*
+ * Struct to hold the sign properties.
+ */
+typedef struct sign sign_T;
+
+struct sign
+{
+ sign_T *sn_next; // next sign in list
+ int sn_typenr; // type number of sign
+ char_u *sn_name; // name of sign
+ char_u *sn_icon; // name of pixmap
+# ifdef FEAT_SIGN_ICONS
+ void *sn_image; // icon image
+# endif
+ char_u *sn_text; // text used instead of pixmap
+ int sn_line_hl; // highlight ID for line
+ int sn_text_hl; // highlight ID for text
+};
+
+static sign_T *first_sign = NULL;
+static int next_sign_typenr = 1;
+
+static void sign_list_defined(sign_T *sp);
+static void sign_undefine(sign_T *sp, sign_T *sp_prev);
+
+static char *cmds[] = {
+ "define",
+# define SIGNCMD_DEFINE 0
+ "undefine",
+# define SIGNCMD_UNDEFINE 1
+ "list",
+# define SIGNCMD_LIST 2
+ "place",
+# define SIGNCMD_PLACE 3
+ "unplace",
+# define SIGNCMD_UNPLACE 4
+ "jump",
+# define SIGNCMD_JUMP 5
+ NULL
+# define SIGNCMD_LAST 6
+};
+
+static hashtab_T sg_table; // sign group (signgroup_T) hashtable
+static int next_sign_id = 1; // next sign id in the global group
+
+/*
+ * Initialize data needed for managing signs
+ */
+ void
+init_signs(void)
+{
+ hash_init(&sg_table); // sign group hash table
+}
+
+/*
+ * A new sign in group 'groupname' is added. If the group is not present,
+ * create it. Otherwise reference the group.
+ */
+ static signgroup_T *
+sign_group_ref(char_u *groupname)
+{
+ hash_T hash;
+ hashitem_T *hi;
+ signgroup_T *group;
+
+ hash = hash_hash(groupname);
+ hi = hash_lookup(&sg_table, groupname, hash);
+ if (HASHITEM_EMPTY(hi))
+ {
+ // new group
+ group = (signgroup_T *)alloc(
+ (unsigned)(sizeof(signgroup_T) + STRLEN(groupname)));
+ if (group == NULL)
+ return NULL;
+ STRCPY(group->sg_name, groupname);
+ group->refcount = 1;
+ group->next_sign_id = 1;
+ hash_add_item(&sg_table, hi, group->sg_name, hash);
+ }
+ else
+ {
+ // existing group
+ group = HI2SG(hi);
+ group->refcount++;
+ }
+
+ return group;
+}
+
+/*
+ * A sign in group 'groupname' is removed. If all the signs in this group are
+ * removed, then remove the group.
+ */
+ static void
+sign_group_unref(char_u *groupname)
+{
+ hashitem_T *hi;
+ signgroup_T *group;
+
+ hi = hash_find(&sg_table, groupname);
+ if (!HASHITEM_EMPTY(hi))
+ {
+ group = HI2SG(hi);
+ group->refcount--;
+ if (group->refcount == 0)
+ {
+ // All the signs in this group are removed
+ hash_remove(&sg_table, hi);
+ vim_free(group);
+ }
+ }
+}
+
+/*
+ * Returns TRUE if 'sign' is in 'group'.
+ * A sign can either be in the global group (sign->group == NULL)
+ * or in a named group. If 'group' is '*', then the sign is part of the group.
+ */
+ static int
+sign_in_group(signlist_T *sign, char_u *group)
+{
+ return ((group != NULL && STRCMP(group, "*") == 0)
+ || (group == NULL && sign->group == NULL)
+ || (group != NULL && sign->group != NULL
+ && STRCMP(group, sign->group->sg_name) == 0));
+}
+
+/*
+ * Get the next free sign identifier in the specified group
+ */
+ static int
+sign_group_get_next_signid(buf_T *buf, char_u *groupname)
+{
+ int id = 1;
+ signgroup_T *group = NULL;
+ signlist_T *sign;
+ hashitem_T *hi;
+ int found = FALSE;
+
+ if (groupname != NULL)
+ {
+ hi = hash_find(&sg_table, groupname);
+ if (HASHITEM_EMPTY(hi))
+ return id;
+ group = HI2SG(hi);
+ }
+
+ // Search for the next usable sign identifier
+ while (!found)
+ {
+ if (group == NULL)
+ id = next_sign_id++; // global group
+ else
+ id = group->next_sign_id++;
+
+ // Check whether this sign is already placed in the buffer
+ found = TRUE;
+ FOR_ALL_SIGNS_IN_BUF(buf, sign)
+ {
+ if (id == sign->id && sign_in_group(sign, groupname))
+ {
+ found = FALSE; // sign identifier is in use
+ break;
+ }
+ }
+ }
+
+ return id;
+}
+
+/*
+ * Insert a new sign into the signlist for buffer 'buf' between the 'prev' and
+ * 'next' signs.
+ */
+ static void
+insert_sign(
+ buf_T *buf, // buffer to store sign in
+ signlist_T *prev, // previous sign entry
+ signlist_T *next, // next sign entry
+ int id, // sign ID
+ char_u *group, // sign group; NULL for global group
+ int prio, // sign priority
+ linenr_T lnum, // line number which gets the mark
+ int typenr) // typenr of sign we are adding
+{
+ signlist_T *newsign;
+
+ newsign = (signlist_T *)lalloc_id((long_u)sizeof(signlist_T), FALSE,
+ aid_insert_sign);
+ if (newsign != NULL)
+ {
+ newsign->id = id;
+ newsign->lnum = lnum;
+ newsign->typenr = typenr;
+ if (group != NULL)
+ {
+ newsign->group = sign_group_ref(group);
+ if (newsign->group == NULL)
+ {
+ vim_free(newsign);
+ return;
+ }
+ }
+ else
+ newsign->group = NULL;
+ newsign->priority = prio;
+ newsign->next = next;
+ newsign->prev = prev;
+ if (next != NULL)
+ next->prev = newsign;
+
+ if (prev == NULL)
+ {
+ // When adding first sign need to redraw the windows to create the
+ // column for signs.
+ if (buf->b_signlist == NULL)
+ {
+ redraw_buf_later(buf, NOT_VALID);
+ changed_cline_bef_curs();
+ }
+
+ // first sign in signlist
+ buf->b_signlist = newsign;
+#ifdef FEAT_NETBEANS_INTG
+ if (netbeans_active())
+ buf->b_has_sign_column = TRUE;
+#endif
+ }
+ else
+ prev->next = newsign;
+ }
+}
+
+/*
+ * Insert a new sign sorted by line number and sign priority.
+ */
+ static void
+insert_sign_by_lnum_prio(
+ buf_T *buf, // buffer to store sign in
+ signlist_T *prev, // previous sign entry
+ int id, // sign ID
+ char_u *group, // sign group; NULL for global group
+ int prio, // sign priority
+ linenr_T lnum, // line number which gets the mark
+ int typenr) // typenr of sign we are adding
+{
+ signlist_T *sign;
+
+ // keep signs sorted by lnum and by priority: insert new sign at
+ // the proper position in the list for this lnum.
+ while (prev != NULL && prev->lnum == lnum && prev->priority <= prio)
+ prev = prev->prev;
+ if (prev == NULL)
+ sign = buf->b_signlist;
+ else
+ sign = prev->next;
+
+ insert_sign(buf, prev, sign, id, group, prio, lnum, typenr);
+}
+
+/*
+ * Get the name of a sign by its typenr.
+ */
+ static char_u *
+sign_typenr2name(int typenr)
+{
+ sign_T *sp;
+
+ for (sp = first_sign; sp != NULL; sp = sp->sn_next)
+ if (sp->sn_typenr == typenr)
+ return sp->sn_name;
+ return (char_u *)_("[Deleted]");
+}
+
+/*
+ * Return information about a sign in a Dict
+ */
+ static dict_T *
+sign_get_info(signlist_T *sign)
+{
+ dict_T *d;
+
+ if ((d = dict_alloc_id(aid_sign_getinfo)) == NULL)
+ return NULL;
+ dict_add_number(d, "id", sign->id);
+ dict_add_string(d, "group", (sign->group == NULL) ?
+ (char_u *)"" : sign->group->sg_name);
+ dict_add_number(d, "lnum", sign->lnum);
+ dict_add_string(d, "name", sign_typenr2name(sign->typenr));
+ dict_add_number(d, "priority", sign->priority);
+
+ return d;
+}
+
+/*
+ * Add the sign into the signlist. Find the right spot to do it though.
+ */
+ static void
+buf_addsign(
+ buf_T *buf, // buffer to store sign in
+ int id, // sign ID
+ char_u *groupname, // sign group
+ int prio, // sign priority
+ linenr_T lnum, // line number which gets the mark
+ int typenr) // typenr of sign we are adding
+{
+ signlist_T *sign; // a sign in the signlist
+ signlist_T *prev; // the previous sign
+
+ prev = NULL;
+ FOR_ALL_SIGNS_IN_BUF(buf, sign)
+ {
+ if (lnum == sign->lnum && id == sign->id
+ && sign_in_group(sign, groupname))
+ {
+ // Update an existing sign
+ sign->typenr = typenr;
+ return;
+ }
+ else if (lnum < sign->lnum)
+ {
+ insert_sign_by_lnum_prio(buf, prev, id, groupname, prio,
+ lnum, typenr);
+ return;
+ }
+ prev = sign;
+ }
+
+ insert_sign_by_lnum_prio(buf, prev, id, groupname, prio, lnum, typenr);
+ return;
+}
+
+/*
+ * For an existing, placed sign "markId" change the type to "typenr".
+ * Returns the line number of the sign, or zero if the sign is not found.
+ */
+ static linenr_T
+buf_change_sign_type(
+ buf_T *buf, // buffer to store sign in
+ int markId, // sign ID
+ char_u *group, // sign group
+ int typenr) // typenr of sign we are adding
+{
+ signlist_T *sign; // a sign in the signlist
+
+ FOR_ALL_SIGNS_IN_BUF(buf, sign)
+ {
+ if (sign->id == markId && sign_in_group(sign, group))
+ {
+ sign->typenr = typenr;
+ return sign->lnum;
+ }
+ }
+
+ return (linenr_T)0;
+}
+
+/*
+ * Return the type number of the sign at line number 'lnum' in buffer 'buf'
+ * which has the attribute specified by 'type'. Returns 0 if a sign is not
+ * found at the line number or it doesn't have the specified attribute.
+ */
+ int
+buf_getsigntype(
+ buf_T *buf,
+ linenr_T lnum,
+ int type) // SIGN_ICON, SIGN_TEXT, SIGN_ANY, SIGN_LINEHL
+{
+ signlist_T *sign; // a sign in a b_signlist
+
+ FOR_ALL_SIGNS_IN_BUF(buf, sign)
+ if (sign->lnum == lnum
+ && (type == SIGN_ANY
+# ifdef FEAT_SIGN_ICONS
+ || (type == SIGN_ICON
+ && sign_get_image(sign->typenr) != NULL)
+# endif
+ || (type == SIGN_TEXT
+ && sign_get_text(sign->typenr) != NULL)
+ || (type == SIGN_LINEHL
+ && sign_get_attr(sign->typenr, TRUE) != 0)))
+ return sign->typenr;
+ return 0;
+}
+
+/*
+ * Delete sign 'id' in group 'group' from buffer 'buf'.
+ * If 'id' is zero, then delete all the signs in group 'group'. Otherwise
+ * delete only the specified sign.
+ * If 'group' is '*', then delete the sign in all the groups. If 'group' is
+ * NULL, then delete the sign in the global group. Otherwise delete the sign in
+ * the specified group.
+ * Returns the line number of the deleted sign. If multiple signs are deleted,
+ * then returns the line number of the last sign deleted.
+ */
+ linenr_T
+buf_delsign(
+ buf_T *buf, // buffer sign is stored in
+ linenr_T atlnum, // sign at this line, 0 - at any line
+ int id, // sign id
+ char_u *group) // sign group
+{
+ signlist_T **lastp; // pointer to pointer to current sign
+ signlist_T *sign; // a sign in a b_signlist
+ signlist_T *next; // the next sign in a b_signlist
+ linenr_T lnum; // line number whose sign was deleted
+
+ lastp = &buf->b_signlist;
+ lnum = 0;
+ for (sign = buf->b_signlist; sign != NULL; sign = next)
+ {
+ next = sign->next;
+ if ((id == 0 || sign->id == id)
+ && (atlnum == 0 || sign->lnum == atlnum)
+ && sign_in_group(sign, group))
+
+ {
+ *lastp = next;
+ if (next != NULL)
+ next->prev = sign->prev;
+ lnum = sign->lnum;
+ if (sign->group != NULL)
+ sign_group_unref(sign->group->sg_name);
+ vim_free(sign);
+ redraw_buf_line_later(buf, lnum);
+
+ // Check whether only one sign needs to be deleted
+ // If deleting a sign with a specific identifier in a particular
+ // group or deleting any sign at a particular line number, delete
+ // only one sign.
+ if (group == NULL
+ || (*group != '*' && id != 0)
+ || (*group == '*' && atlnum != 0))
+ break;
+ }
+ else
+ lastp = &sign->next;
+ }
+
+ // When deleting the last sign the cursor position may change, because the
+ // sign columns no longer shows. And the 'signcolumn' may be hidden.
+ if (buf->b_signlist == NULL)
+ {
+ redraw_buf_later(buf, NOT_VALID);
+ changed_cline_bef_curs();
+ }
+
+ return lnum;
+}
+
+
+/*
+ * Find the line number of the sign with the requested id in group 'group'. If
+ * the sign does not exist, return 0 as the line number. This will still let
+ * the correct file get loaded.
+ */
+ int
+buf_findsign(
+ buf_T *buf, // buffer to store sign in
+ int id, // sign ID
+ char_u *group) // sign group
+{
+ signlist_T *sign; // a sign in the signlist
+
+ FOR_ALL_SIGNS_IN_BUF(buf, sign)
+ if (sign->id == id && sign_in_group(sign, group))
+ return sign->lnum;
+
+ return 0;
+}
+
+/*
+ * Return the sign at line 'lnum' in buffer 'buf'. Returns NULL if a sign is
+ * not found at the line. If 'groupname' is NULL, searches in the global group.
+ */
+ static signlist_T *
+buf_getsign_at_line(
+ buf_T *buf, // buffer whose sign we are searching for
+ linenr_T lnum, // line number of sign
+ char_u *groupname) // sign group name
+{
+ signlist_T *sign; // a sign in the signlist
+
+ FOR_ALL_SIGNS_IN_BUF(buf, sign)
+ if (sign->lnum == lnum && sign_in_group(sign, groupname))
+ return sign;
+
+ return NULL;
+}
+
+/*
+ * Return the identifier of the sign at line number 'lnum' in buffer 'buf'.
+ */
+ int
+buf_findsign_id(
+ buf_T *buf, // buffer whose sign we are searching for
+ linenr_T lnum, // line number of sign
+ char_u *groupname) // sign group name
+{
+ signlist_T *sign; // a sign in the signlist
+
+ sign = buf_getsign_at_line(buf, lnum, groupname);
+ if (sign != NULL)
+ return sign->id;
+
+ return 0;
+}
+
+# if defined(FEAT_NETBEANS_INTG) || defined(PROTO)
+/*
+ * See if a given type of sign exists on a specific line.
+ */
+ int
+buf_findsigntype_id(
+ buf_T *buf, // buffer whose sign we are searching for
+ linenr_T lnum, // line number of sign
+ int typenr) // sign type number
+{
+ signlist_T *sign; // a sign in the signlist
+
+ FOR_ALL_SIGNS_IN_BUF(buf, sign)
+ if (sign->lnum == lnum && sign->typenr == typenr)
+ return sign->id;
+
+ return 0;
+}
+
+
+# if defined(FEAT_SIGN_ICONS) || defined(PROTO)
+/*
+ * Return the number of icons on the given line.
+ */
+ int
+buf_signcount(buf_T *buf, linenr_T lnum)
+{
+ signlist_T *sign; // a sign in the signlist
+ int count = 0;
+
+ FOR_ALL_SIGNS_IN_BUF(buf, sign)
+ if (sign->lnum == lnum)
+ if (sign_get_image(sign->typenr) != NULL)
+ count++;
+
+ return count;
+}
+# endif /* FEAT_SIGN_ICONS */
+# endif /* FEAT_NETBEANS_INTG */
+
+/*
+ * Delete signs in group 'group' in buffer "buf". If 'group' is '*', then
+ * delete all the signs.
+ */
+ void
+buf_delete_signs(buf_T *buf, char_u *group)
+{
+ signlist_T *sign;
+ signlist_T **lastp; // pointer to pointer to current sign
+ signlist_T *next;
+
+ // When deleting the last sign need to redraw the windows to remove the
+ // sign column. Not when curwin is NULL (this means we're exiting).
+ if (buf->b_signlist != NULL && curwin != NULL)
+ {
+ redraw_buf_later(buf, NOT_VALID);
+ changed_cline_bef_curs();
+ }
+
+ lastp = &buf->b_signlist;
+ for (sign = buf->b_signlist; sign != NULL; sign = next)
+ {
+ next = sign->next;
+ if (sign_in_group(sign, group))
+ {
+ *lastp = next;
+ if (next != NULL)
+ next->prev = sign->prev;
+ if (sign->group != NULL)
+ sign_group_unref(sign->group->sg_name);
+ vim_free(sign);
+ }
+ else
+ lastp = &sign->next;
+ }
+}
+
+/*
+ * List placed signs for "rbuf". If "rbuf" is NULL do it for all buffers.
+ */
+ static void
+sign_list_placed(buf_T *rbuf, char_u *sign_group)
+{
+ buf_T *buf;
+ signlist_T *sign;
+ char lbuf[MSG_BUF_LEN];
+ char group[MSG_BUF_LEN];
+
+ msg_puts_title(_("\n--- Signs ---"));
+ msg_putchar('\n');
+ if (rbuf == NULL)
+ buf = firstbuf;
+ else
+ buf = rbuf;
+ while (buf != NULL && !got_int)
+ {
+ if (buf->b_signlist != NULL)
+ {
+ vim_snprintf(lbuf, MSG_BUF_LEN, _("Signs for %s:"), buf->b_fname);
+ msg_puts_attr(lbuf, HL_ATTR(HLF_D));
+ msg_putchar('\n');
+ }
+ FOR_ALL_SIGNS_IN_BUF(buf, sign)
+ {
+ if (got_int)
+ break;
+ if (!sign_in_group(sign, sign_group))
+ continue;
+ if (sign->group != NULL)
+ vim_snprintf(group, MSG_BUF_LEN, _(" group=%s"),
+ sign->group->sg_name);
+ else
+ group[0] = '\0';
+ vim_snprintf(lbuf, MSG_BUF_LEN,
+ _(" line=%ld id=%d%s name=%s priority=%d"),
+ (long)sign->lnum, sign->id, group,
+ sign_typenr2name(sign->typenr), sign->priority);
+ msg_puts(lbuf);
+ msg_putchar('\n');
+ }
+ if (rbuf != NULL)
+ break;
+ buf = buf->b_next;
+ }
+}
+
+/*
+ * Adjust a placed sign for inserted/deleted lines.
+ */
+ void
+sign_mark_adjust(
+ linenr_T line1,
+ linenr_T line2,
+ long amount,
+ long amount_after)
+{
+ signlist_T *sign; // a sign in a b_signlist
+ linenr_T new_lnum;
+
+ FOR_ALL_SIGNS_IN_BUF(curbuf, sign)
+ {
+ // Ignore changes to lines after the sign
+ if (sign->lnum < line1)
+ continue;
+ new_lnum = sign->lnum;
+ if (sign->lnum >= line1 && sign->lnum <= line2)
+ {
+ if (amount != MAXLNUM)
+ new_lnum += amount;
+ }
+ else if (sign->lnum > line2)
+ // Lines inserted or deleted before the sign
+ new_lnum += amount_after;
+
+ // If the new sign line number is past the last line in the buffer,
+ // then don't adjust the line number. Otherwise, it will always be past
+ // the last line and will not be visible.
+ if (new_lnum <= curbuf->b_ml.ml_line_count)
+ sign->lnum = new_lnum;
+ }
+}
+
+/*
+ * Find index of a ":sign" subcmd from its name.
+ * "*end_cmd" must be writable.
+ */
+ static int
+sign_cmd_idx(
+ char_u *begin_cmd, // begin of sign subcmd
+ char_u *end_cmd) // just after sign subcmd
+{
+ int idx;
+ char save = *end_cmd;
+
+ *end_cmd = NUL;
+ for (idx = 0; ; ++idx)
+ if (cmds[idx] == NULL || STRCMP(begin_cmd, cmds[idx]) == 0)
+ break;
+ *end_cmd = save;
+ return idx;
+}
+
+/*
+ * Find a sign by name. Also returns pointer to the previous sign.
+ */
+ static sign_T *
+sign_find(char_u *name, sign_T **sp_prev)
+{
+ sign_T *sp;
+
+ if (sp_prev != NULL)
+ *sp_prev = NULL;
+ for (sp = first_sign; sp != NULL; sp = sp->sn_next)
+ {
+ if (STRCMP(sp->sn_name, name) == 0)
+ break;
+ if (sp_prev != NULL)
+ *sp_prev = sp;
+ }
+
+ return sp;
+}
+
+/*
+ * Allocate a new sign
+ */
+ static sign_T *
+alloc_new_sign(char_u *name)
+{
+ sign_T *sp;
+ sign_T *lp;
+ int start = next_sign_typenr;
+
+ // Allocate a new sign.
+ sp = (sign_T *)alloc_clear_id((unsigned)sizeof(sign_T),
+ aid_sign_define_by_name);
+ if (sp == NULL)
+ return NULL;
+
+ // Check that next_sign_typenr is not already being used.
+ // This only happens after wrapping around. Hopefully
+ // another one got deleted and we can use its number.
+ for (lp = first_sign; lp != NULL; )
+ {
+ if (lp->sn_typenr == next_sign_typenr)
+ {
+ ++next_sign_typenr;
+ if (next_sign_typenr == MAX_TYPENR)
+ next_sign_typenr = 1;
+ if (next_sign_typenr == start)
+ {
+ vim_free(sp);
+ emsg(_("E612: Too many signs defined"));
+ return NULL;
+ }
+ lp = first_sign; // start all over
+ continue;
+ }
+ lp = lp->sn_next;
+ }
+
+ sp->sn_typenr = next_sign_typenr;
+ if (++next_sign_typenr == MAX_TYPENR)
+ next_sign_typenr = 1; // wrap around
+
+ sp->sn_name = vim_strsave(name);
+ if (sp->sn_name == NULL) // out of memory
+ {
+ vim_free(sp);
+ return NULL;
+ }
+
+ return sp;
+}
+
+/*
+ * Initialize the icon information for a new sign
+ */
+ static void
+sign_define_init_icon(sign_T *sp, char_u *icon)
+{
+ vim_free(sp->sn_icon);
+ sp->sn_icon = vim_strsave(icon);
+ backslash_halve(sp->sn_icon);
+# ifdef FEAT_SIGN_ICONS
+ if (gui.in_use)
+ {
+ out_flush();
+ if (sp->sn_image != NULL)
+ gui_mch_destroy_sign(sp->sn_image);
+ sp->sn_image = gui_mch_register_sign(sp->sn_icon);
+ }
+# endif
+}
+
+/*
+ * Initialize the text for a new sign
+ */
+ static int
+sign_define_init_text(sign_T *sp, char_u *text)
+{
+ char_u *s;
+ char_u *endp;
+ int cells;
+ int len;
+
+ endp = text + (int)STRLEN(text);
+
+ // Remove backslashes so that it is possible to use a space.
+ for (s = text; s + 1 < endp; ++s)
+ if (*s == '\\')
+ {
+ STRMOVE(s, s + 1);
+ --endp;
+ }
+
+ // Count cells and check for non-printable chars
+ if (has_mbyte)
+ {
+ cells = 0;
+ for (s = text; s < endp; s += (*mb_ptr2len)(s))
+ {
+ if (!vim_isprintc((*mb_ptr2char)(s)))
+ break;
+ cells += (*mb_ptr2cells)(s);
+ }
+ }
+ else
+ {
+ for (s = text; s < endp; ++s)
+ if (!vim_isprintc(*s))
+ break;
+ cells = (int)(s - text);
+ }
+
+ // Currently sign text must be one or two display cells
+ if (s != endp || cells < 1 || cells > 2)
+ {
+ semsg(_("E239: Invalid sign text: %s"), text);
+ return FAIL;
+ }
+
+ vim_free(sp->sn_text);
+ // Allocate one byte more if we need to pad up
+ // with a space.
+ len = (int)(endp - text + ((cells == 1) ? 1 : 0));
+ sp->sn_text = vim_strnsave(text, len);
+
+ // For single character sign text, pad with a space.
+ if (sp->sn_text != NULL && cells == 1)
+ STRCPY(sp->sn_text + len - 1, " ");
+
+ return OK;
+}
+
+/*
+ * Define a new sign or update an existing sign
+ */
+ int
+sign_define_by_name(
+ char_u *name,
+ char_u *icon,
+ char_u *linehl,
+ char_u *text,
+ char_u *texthl)
+{
+ sign_T *sp_prev;
+ sign_T *sp;
+
+ sp = sign_find(name, &sp_prev);
+ if (sp == NULL)
+ {
+ sp = alloc_new_sign(name);
+ if (sp == NULL)
+ return FAIL;
+
+ // add the new sign to the list of signs
+ if (sp_prev == NULL)
+ first_sign = sp;
+ else
+ sp_prev->sn_next = sp;
+ }
+
+ // set values for a defined sign.
+ if (icon != NULL)
+ sign_define_init_icon(sp, icon);
+
+ if (text != NULL && (sign_define_init_text(sp, text) == FAIL))
+ return FAIL;
+
+ if (linehl != NULL)
+ sp->sn_line_hl = syn_check_group(linehl, (int)STRLEN(linehl));
+
+ if (texthl != NULL)
+ sp->sn_text_hl = syn_check_group(texthl, (int)STRLEN(texthl));
+
+ return OK;
+}
+
+/*
+ * Free the sign specified by 'name'.
+ */
+ int
+sign_undefine_by_name(char_u *name)
+{
+ sign_T *sp_prev;
+ sign_T *sp;
+
+ sp = sign_find(name, &sp_prev);
+ if (sp == NULL)
+ {
+ semsg(_("E155: Unknown sign: %s"), name);
+ return FAIL;
+ }
+ sign_undefine(sp, sp_prev);
+
+ return OK;
+}
+
+/*
+ * List the signs matching 'name'
+ */
+ static void
+sign_list_by_name(char_u *name)
+{
+ sign_T *sp;
+
+ sp = sign_find(name, NULL);
+ if (sp != NULL)
+ sign_list_defined(sp);
+ else
+ semsg(_("E155: Unknown sign: %s"), name);
+}
+
+/*
+ * Place a sign at the specified file location or update a sign.
+ */
+ int
+sign_place(
+ int *sign_id,
+ char_u *sign_group,
+ char_u *sign_name,
+ buf_T *buf,
+ linenr_T lnum,
+ int prio)
+{
+ sign_T *sp;
+
+ // Check for reserved character '*' in group name
+ if (sign_group != NULL && (*sign_group == '*' || *sign_group == '\0'))
+ return FAIL;
+
+ for (sp = first_sign; sp != NULL; sp = sp->sn_next)
+ if (STRCMP(sp->sn_name, sign_name) == 0)
+ break;
+ if (sp == NULL)
+ {
+ semsg(_("E155: Unknown sign: %s"), sign_name);
+ return FAIL;
+ }
+ if (*sign_id == 0)
+ *sign_id = sign_group_get_next_signid(buf, sign_group);
+
+ if (lnum > 0)
+ // ":sign place {id} line={lnum} name={name} file={fname}":
+ // place a sign
+ buf_addsign(buf, *sign_id, sign_group, prio, lnum, sp->sn_typenr);
+ else
+ // ":sign place {id} file={fname}": change sign type
+ lnum = buf_change_sign_type(buf, *sign_id, sign_group, sp->sn_typenr);
+ if (lnum > 0)
+ redraw_buf_line_later(buf, lnum);
+ else
+ {
+ semsg(_("E885: Not possible to change sign %s"), sign_name);
+ return FAIL;
+ }
+
+ return OK;
+}
+
+/*
+ * Unplace the specified sign
+ */
+ int
+sign_unplace(int sign_id, char_u *sign_group, buf_T *buf, linenr_T atlnum)
+{
+ if (buf->b_signlist == NULL) // No signs in the buffer
+ return OK;
+
+ if (sign_id == 0)
+ {
+ // Delete all the signs in the specified buffer
+ redraw_buf_later(buf, NOT_VALID);
+ buf_delete_signs(buf, sign_group);
+ }
+ else
+ {
+ linenr_T lnum;
+
+ // Delete only the specified signs
+ lnum = buf_delsign(buf, atlnum, sign_id, sign_group);
+ if (lnum == 0)
+ return FAIL;
+ }
+
+ return OK;
+}
+
+/*
+ * Unplace the sign at the current cursor line.
+ */
+ static void
+sign_unplace_at_cursor(char_u *groupname)
+{
+ int id = -1;
+
+ id = buf_findsign_id(curwin->w_buffer, curwin->w_cursor.lnum, groupname);
+ if (id > 0)
+ sign_unplace(id, groupname, curwin->w_buffer, curwin->w_cursor.lnum);
+ else
+ emsg(_("E159: Missing sign number"));
+}
+
+/*
+ * Jump to a sign.
+ */
+ linenr_T
+sign_jump(int sign_id, char_u *sign_group, buf_T *buf)
+{
+ linenr_T lnum;
+
+ if ((lnum = buf_findsign(buf, sign_id, sign_group)) <= 0)
+ {
+ semsg(_("E157: Invalid sign ID: %d"), sign_id);
+ return -1;
+ }
+
+ // goto a sign ...
+ if (buf_jump_open_win(buf) != NULL)
+ { // ... in a current window
+ curwin->w_cursor.lnum = lnum;
+ check_cursor_lnum();
+ beginline(BL_WHITE);
+ }
+ else
+ { // ... not currently in a window
+ char_u *cmd;
+
+ if (buf->b_fname == NULL)
+ {
+ emsg(_("E934: Cannot jump to a buffer that does not have a name"));
+ return -1;
+ }
+ cmd = alloc((unsigned)STRLEN(buf->b_fname) + 25);
+ if (cmd == NULL)
+ return -1;
+ sprintf((char *)cmd, "e +%ld %s", (long)lnum, buf->b_fname);
+ do_cmdline_cmd(cmd);
+ vim_free(cmd);
+ }
+# ifdef FEAT_FOLDING
+ foldOpenCursor();
+# endif
+
+ return lnum;
+}
+
+/*
+ * ":sign define {name} ..." command
+ */
+ static void
+sign_define_cmd(char_u *sign_name, char_u *cmdline)
+{
+ char_u *arg;
+ char_u *p = cmdline;
+ char_u *icon = NULL;
+ char_u *text = NULL;
+ char_u *linehl = NULL;
+ char_u *texthl = NULL;
+ int failed = FALSE;
+
+ // set values for a defined sign.
+ for (;;)
+ {
+ arg = skipwhite(p);
+ if (*arg == NUL)
+ break;
+ p = skiptowhite_esc(arg);
+ if (STRNCMP(arg, "icon=", 5) == 0)
+ {
+ arg += 5;
+ icon = vim_strnsave(arg, (int)(p - arg));
+ }
+ else if (STRNCMP(arg, "text=", 5) == 0)
+ {
+ arg += 5;
+ text = vim_strnsave(arg, (int)(p - arg));
+ }
+ else if (STRNCMP(arg, "linehl=", 7) == 0)
+ {
+ arg += 7;
+ linehl = vim_strnsave(arg, (int)(p - arg));
+ }
+ else if (STRNCMP(arg, "texthl=", 7) == 0)
+ {
+ arg += 7;
+ texthl = vim_strnsave(arg, (int)(p - arg));
+ }
+ else
+ {
+ semsg(_(e_invarg2), arg);
+ failed = TRUE;
+ break;
+ }
+ }
+
+ if (!failed)
+ sign_define_by_name(sign_name, icon, linehl, text, texthl);
+
+ vim_free(icon);
+ vim_free(text);
+ vim_free(linehl);
+ vim_free(texthl);
+}
+
+/*
+ * ":sign place" command
+ */
+ static void
+sign_place_cmd(
+ buf_T *buf,
+ linenr_T lnum,
+ char_u *sign_name,
+ int id,
+ char_u *group,
+ int prio)
+{
+ if (id <= 0)
+ {
+ // List signs placed in a file/buffer
+ // :sign place file={fname}
+ // :sign place group={group} file={fname}
+ // :sign place group=* file={fname}
+ // :sign place buffer={nr}
+ // :sign place group={group} buffer={nr}
+ // :sign place group=* buffer={nr}
+ // :sign place
+ // :sign place group={group}
+ // :sign place group=*
+ if (lnum >= 0 || sign_name != NULL
+ || (group != NULL && *group == '\0'))
+ emsg(_(e_invarg));
+ else
+ sign_list_placed(buf, group);
+ }
+ else
+ {
+ // Place a new sign
+ if (sign_name == NULL || buf == NULL
+ || (group != NULL && *group == '\0'))
+ {
+ emsg(_(e_invarg));
+ return;
+ }
+
+ sign_place(&id, group, sign_name, buf, lnum, prio);
+ }
+}
+
+/*
+ * ":sign unplace" command
+ */
+ static void
+sign_unplace_cmd(
+ buf_T *buf,
+ linenr_T lnum,
+ char_u *sign_name,
+ int id,
+ char_u *group)
+{
+ if (lnum >= 0 || sign_name != NULL || (group != NULL && *group == '\0'))
+ {
+ emsg(_(e_invarg));
+ return;
+ }
+
+ if (id == -2)
+ {
+ if (buf != NULL)
+ // :sign unplace * file={fname}
+ // :sign unplace * group={group} file={fname}
+ // :sign unplace * group=* file={fname}
+ // :sign unplace * buffer={nr}
+ // :sign unplace * group={group} buffer={nr}
+ // :sign unplace * group=* buffer={nr}
+ sign_unplace(0, group, buf, 0);
+ else
+ // :sign unplace *
+ // :sign unplace * group={group}
+ // :sign unplace * group=*
+ FOR_ALL_BUFFERS(buf)
+ if (buf->b_signlist != NULL)
+ buf_delete_signs(buf, group);
+ }
+ else
+ {
+ if (buf != NULL)
+ // :sign unplace {id} file={fname}
+ // :sign unplace {id} group={group} file={fname}
+ // :sign unplace {id} group=* file={fname}
+ // :sign unplace {id} buffer={nr}
+ // :sign unplace {id} group={group} buffer={nr}
+ // :sign unplace {id} group=* buffer={nr}
+ sign_unplace(id, group, buf, 0);
+ else
+ {
+ if (id == -1)
+ {
+ // :sign unplace group={group}
+ // :sign unplace group=*
+ sign_unplace_at_cursor(group);
+ }
+ else
+ {
+ // :sign unplace {id}
+ // :sign unplace {id} group={group}
+ // :sign unplace {id} group=*
+ FOR_ALL_BUFFERS(buf)
+ sign_unplace(id, group, buf, 0);
+ }
+ }
+ }
+}
+
+/*
+ * Jump to a placed sign commands:
+ * :sign jump {id} file={fname}
+ * :sign jump {id} buffer={nr}
+ * :sign jump {id} group={group} file={fname}
+ * :sign jump {id} group={group} buffer={nr}
+ */
+ static void
+sign_jump_cmd(
+ buf_T *buf,
+ linenr_T lnum,
+ char_u *sign_name,
+ int id,
+ char_u *group)
+{
+ if (sign_name == NULL && group == NULL && id == -1)
+ {
+ emsg(_(e_argreq));
+ return;
+ }
+
+ if (buf == NULL || (group != NULL && *group == '\0')
+ || lnum >= 0 || sign_name != NULL)
+ {
+ // File or buffer is not specified or an empty group is used
+ // or a line number or a sign name is specified.
+ emsg(_(e_invarg));
+ return;
+ }
+ (void)sign_jump(id, group, buf);
+}
+
+/*
+ * Parse the command line arguments for the ":sign place", ":sign unplace" and
+ * ":sign jump" commands.
+ * The supported arguments are: line={lnum} name={name} group={group}
+ * priority={prio} and file={fname} or buffer={nr}.
+ */
+ static int
+parse_sign_cmd_args(
+ int cmd,
+ char_u *arg,
+ char_u **sign_name,
+ int *signid,
+ char_u **group,
+ int *prio,
+ buf_T **buf,
+ linenr_T *lnum)
+{
+ char_u *arg1;
+ char_u *name;
+ char_u *filename = NULL;
+ int lnum_arg = FALSE;
+
+ // first arg could be placed sign id
+ arg1 = arg;
+ if (VIM_ISDIGIT(*arg))
+ {
+ *signid = getdigits(&arg);
+ if (!VIM_ISWHITE(*arg) && *arg != NUL)
+ {
+ *signid = -1;
+ arg = arg1;
+ }
+ else
+ arg = skipwhite(arg);
+ }
+
+ while (*arg != NUL)
+ {
+ if (STRNCMP(arg, "line=", 5) == 0)
+ {
+ arg += 5;
+ *lnum = atoi((char *)arg);
+ arg = skiptowhite(arg);
+ lnum_arg = TRUE;
+ }
+ else if (STRNCMP(arg, "*", 1) == 0 && cmd == SIGNCMD_UNPLACE)
+ {
+ if (*signid != -1)
+ {
+ emsg(_(e_invarg));
+ return FAIL;
+ }
+ *signid = -2;
+ arg = skiptowhite(arg + 1);
+ }
+ else if (STRNCMP(arg, "name=", 5) == 0)
+ {
+ arg += 5;
+ name = arg;
+ arg = skiptowhite(arg);
+ if (*arg != NUL)
+ *arg++ = NUL;
+ while (name[0] == '0' && name[1] != NUL)
+ ++name;
+ *sign_name = name;
+ }
+ else if (STRNCMP(arg, "group=", 6) == 0)
+ {
+ arg += 6;
+ *group = arg;
+ arg = skiptowhite(arg);
+ if (*arg != NUL)
+ *arg++ = NUL;
+ }
+ else if (STRNCMP(arg, "priority=", 9) == 0)
+ {
+ arg += 9;
+ *prio = atoi((char *)arg);
+ arg = skiptowhite(arg);
+ }
+ else if (STRNCMP(arg, "file=", 5) == 0)
+ {
+ arg += 5;
+ filename = arg;
+ *buf = buflist_findname_exp(arg);
+ break;
+ }
+ else if (STRNCMP(arg, "buffer=", 7) == 0)
+ {
+ arg += 7;
+ filename = arg;
+ *buf = buflist_findnr((int)getdigits(&arg));
+ if (*skipwhite(arg) != NUL)
+ emsg(_(e_trailing));
+ break;
+ }
+ else
+ {
+ emsg(_(e_invarg));
+ return FAIL;
+ }
+ arg = skipwhite(arg);
+ }
+
+ if (filename != NULL && *buf == NULL)
+ {
+ semsg(_("E158: Invalid buffer name: %s"), filename);
+ return FAIL;
+ }
+
+ // If the filename is not supplied for the sign place or the sign jump
+ // command, then use the current buffer.
+ if (filename == NULL && ((cmd == SIGNCMD_PLACE && lnum_arg)
+ || cmd == SIGNCMD_JUMP))
+ *buf = curwin->w_buffer;
+
+ return OK;
+}
+
+/*
+ * ":sign" command
+ */
+ void
+ex_sign(exarg_T *eap)
+{
+ char_u *arg = eap->arg;
+ char_u *p;
+ int idx;
+ sign_T *sp;
+ buf_T *buf = NULL;
+
+ // Parse the subcommand.
+ p = skiptowhite(arg);
+ idx = sign_cmd_idx(arg, p);
+ if (idx == SIGNCMD_LAST)
+ {
+ semsg(_("E160: Unknown sign command: %s"), arg);
+ return;
+ }
+ arg = skipwhite(p);
+
+ if (idx <= SIGNCMD_LIST)
+ {
+ // Define, undefine or list signs.
+ if (idx == SIGNCMD_LIST && *arg == NUL)
+ {
+ // ":sign list": list all defined signs
+ for (sp = first_sign; sp != NULL && !got_int; sp = sp->sn_next)
+ sign_list_defined(sp);
+ }
+ else if (*arg == NUL)
+ emsg(_("E156: Missing sign name"));
+ else
+ {
+ char_u *name;
+
+ // Isolate the sign name. If it's a number skip leading zeroes,
+ // so that "099" and "99" are the same sign. But keep "0".
+ p = skiptowhite(arg);
+ if (*p != NUL)
+ *p++ = NUL;
+ while (arg[0] == '0' && arg[1] != NUL)
+ ++arg;
+ name = vim_strsave(arg);
+
+ if (idx == SIGNCMD_DEFINE)
+ sign_define_cmd(name, p);
+ else if (idx == SIGNCMD_LIST)
+ // ":sign list {name}"
+ sign_list_by_name(name);
+ else
+ // ":sign undefine {name}"
+ sign_undefine_by_name(name);
+
+ vim_free(name);
+ return;
+ }
+ }
+ else
+ {
+ int id = -1;
+ linenr_T lnum = -1;
+ char_u *sign_name = NULL;
+ char_u *group = NULL;
+ int prio = SIGN_DEF_PRIO;
+
+ // Parse command line arguments
+ if (parse_sign_cmd_args(idx, arg, &sign_name, &id, &group, &prio,
+ &buf, &lnum) == FAIL)
+ return;
+
+ if (idx == SIGNCMD_PLACE)
+ sign_place_cmd(buf, lnum, sign_name, id, group, prio);
+ else if (idx == SIGNCMD_UNPLACE)
+ sign_unplace_cmd(buf, lnum, sign_name, id, group);
+ else if (idx == SIGNCMD_JUMP)
+ sign_jump_cmd(buf, lnum, sign_name, id, group);
+ }
+}
+
+/*
+ * Return information about a specified sign
+ */
+ static void
+sign_getinfo(sign_T *sp, dict_T *retdict)
+{
+ char_u *p;
+
+ dict_add_string(retdict, "name", (char_u *)sp->sn_name);
+ if (sp->sn_icon != NULL)
+ dict_add_string(retdict, "icon", (char_u *)sp->sn_icon);
+ if (sp->sn_text != NULL)
+ dict_add_string(retdict, "text", (char_u *)sp->sn_text);
+ if (sp->sn_line_hl > 0)
+ {
+ p = get_highlight_name_ext(NULL, sp->sn_line_hl - 1, FALSE);
+ if (p == NULL)
+ p = (char_u *)"NONE";
+ dict_add_string(retdict, "linehl", (char_u *)p);
+ }
+ if (sp->sn_text_hl > 0)
+ {
+ p = get_highlight_name_ext(NULL, sp->sn_text_hl - 1, FALSE);
+ if (p == NULL)
+ p = (char_u *)"NONE";
+ dict_add_string(retdict, "texthl", (char_u *)p);
+ }
+}
+
+/*
+ * If 'name' is NULL, return a list of all the defined signs.
+ * Otherwise, return information about the specified sign.
+ */
+ void
+sign_getlist(char_u *name, list_T *retlist)
+{
+ sign_T *sp = first_sign;
+ dict_T *dict;
+
+ if (name != NULL)
+ {
+ sp = sign_find(name, NULL);
+ if (sp == NULL)
+ return;
+ }
+
+ for (; sp != NULL && !got_int; sp = sp->sn_next)
+ {
+ if ((dict = dict_alloc_id(aid_sign_getlist)) == NULL)
+ return;
+ if (list_append_dict(retlist, dict) == FAIL)
+ return;
+ sign_getinfo(sp, dict);
+
+ if (name != NULL) // handle only the specified sign
+ break;
+ }
+}
+
+/*
+ * Returns information about signs placed in a buffer as list of dicts.
+ */
+ void
+get_buffer_signs(buf_T *buf, list_T *l)
+{
+ signlist_T *sign;
+ dict_T *d;
+
+ FOR_ALL_SIGNS_IN_BUF(buf, sign)
+ {
+ if ((d = sign_get_info(sign)) != NULL)
+ list_append_dict(l, d);
+ }
+}
+
+/*
+ * Return information about all the signs placed in a buffer
+ */
+ static void
+sign_get_placed_in_buf(
+ buf_T *buf,
+ linenr_T lnum,
+ int sign_id,
+ char_u *sign_group,
+ list_T *retlist)
+{
+ dict_T *d;
+ list_T *l;
+ signlist_T *sign;
+ dict_T *sdict;
+
+ if ((d = dict_alloc_id(aid_sign_getplaced_dict)) == NULL)
+ return;
+ list_append_dict(retlist, d);
+
+ dict_add_number(d, "bufnr", (long)buf->b_fnum);
+
+ if ((l = list_alloc_id(aid_sign_getplaced_list)) == NULL)
+ return;
+ dict_add_list(d, "signs", l);
+
+ FOR_ALL_SIGNS_IN_BUF(buf, sign)
+ {
+ if (!sign_in_group(sign, sign_group))
+ continue;
+ if ((lnum == 0 && sign_id == 0)
+ || (sign_id == 0 && lnum == sign->lnum)
+ || (lnum == 0 && sign_id == sign->id)
+ || (lnum == sign->lnum && sign_id == sign->id))
+ {
+ if ((sdict = sign_get_info(sign)) != NULL)
+ list_append_dict(l, sdict);
+ }
+ }
+}
+
+/*
+ * Get a list of signs placed in buffer 'buf'. If 'num' is non-zero, return the
+ * sign placed at the line number. If 'lnum' is zero, return all the signs
+ * placed in 'buf'. If 'buf' is NULL, return signs placed in all the buffers.
+ */
+ void
+sign_get_placed(
+ buf_T *buf,
+ linenr_T lnum,
+ int sign_id,
+ char_u *sign_group,
+ list_T *retlist)
+{
+ if (buf != NULL)
+ sign_get_placed_in_buf(buf, lnum, sign_id, sign_group, retlist);
+ else
+ {
+ FOR_ALL_BUFFERS(buf)
+ {
+ if (buf->b_signlist != NULL)
+ sign_get_placed_in_buf(buf, 0, sign_id, sign_group, retlist);
+ }
+ }
+}
+
+# if defined(FEAT_SIGN_ICONS) || defined(PROTO)
+/*
+ * Allocate the icons. Called when the GUI has started. Allows defining
+ * signs before it starts.
+ */
+ void
+sign_gui_started(void)
+{
+ sign_T *sp;
+
+ for (sp = first_sign; sp != NULL; sp = sp->sn_next)
+ if (sp->sn_icon != NULL)
+ sp->sn_image = gui_mch_register_sign(sp->sn_icon);
+}
+# endif
+
+/*
+ * List one sign.
+ */
+ static void
+sign_list_defined(sign_T *sp)
+{
+ char_u *p;
+
+ smsg("sign %s", sp->sn_name);
+ if (sp->sn_icon != NULL)
+ {
+ msg_puts(" icon=");
+ msg_outtrans(sp->sn_icon);
+# ifdef FEAT_SIGN_ICONS
+ if (sp->sn_image == NULL)
+ msg_puts(_(" (NOT FOUND)"));
+# else
+ msg_puts(_(" (not supported)"));
+# endif
+ }
+ if (sp->sn_text != NULL)
+ {
+ msg_puts(" text=");
+ msg_outtrans(sp->sn_text);
+ }
+ if (sp->sn_line_hl > 0)
+ {
+ msg_puts(" linehl=");
+ p = get_highlight_name_ext(NULL, sp->sn_line_hl - 1, FALSE);
+ if (p == NULL)
+ msg_puts("NONE");
+ else
+ msg_puts((char *)p);
+ }
+ if (sp->sn_text_hl > 0)
+ {
+ msg_puts(" texthl=");
+ p = get_highlight_name_ext(NULL, sp->sn_text_hl - 1, FALSE);
+ if (p == NULL)
+ msg_puts("NONE");
+ else
+ msg_puts((char *)p);
+ }
+}
+
+/*
+ * Undefine a sign and free its memory.
+ */
+ static void
+sign_undefine(sign_T *sp, sign_T *sp_prev)
+{
+ vim_free(sp->sn_name);
+ vim_free(sp->sn_icon);
+# ifdef FEAT_SIGN_ICONS
+ if (sp->sn_image != NULL)
+ {
+ out_flush();
+ gui_mch_destroy_sign(sp->sn_image);
+ }
+# endif
+ vim_free(sp->sn_text);
+ if (sp_prev == NULL)
+ first_sign = sp->sn_next;
+ else
+ sp_prev->sn_next = sp->sn_next;
+ vim_free(sp);
+}
+
+/*
+ * Get highlighting attribute for sign "typenr".
+ * If "line" is TRUE: line highl, if FALSE: text highl.
+ */
+ int
+sign_get_attr(int typenr, int line)
+{
+ sign_T *sp;
+
+ for (sp = first_sign; sp != NULL; sp = sp->sn_next)
+ if (sp->sn_typenr == typenr)
+ {
+ if (line)
+ {
+ if (sp->sn_line_hl > 0)
+ return syn_id2attr(sp->sn_line_hl);
+ }
+ else
+ {
+ if (sp->sn_text_hl > 0)
+ return syn_id2attr(sp->sn_text_hl);
+ }
+ break;
+ }
+ return 0;
+}
+
+/*
+ * Get text mark for sign "typenr".
+ * Returns NULL if there isn't one.
+ */
+ char_u *
+sign_get_text(int typenr)
+{
+ sign_T *sp;
+
+ for (sp = first_sign; sp != NULL; sp = sp->sn_next)
+ if (sp->sn_typenr == typenr)
+ return sp->sn_text;
+ return NULL;
+}
+
+# if defined(FEAT_SIGN_ICONS) || defined(PROTO)
+ void *
+sign_get_image(
+ int typenr) // the attribute which may have a sign
+{
+ sign_T *sp;
+
+ for (sp = first_sign; sp != NULL; sp = sp->sn_next)
+ if (sp->sn_typenr == typenr)
+ return sp->sn_image;
+ return NULL;
+}
+# endif
+
+/*
+ * Undefine/free all signs.
+ */
+ void
+free_signs(void)
+{
+ while (first_sign != NULL)
+ sign_undefine(first_sign, NULL);
+}
+
+# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
+static enum
+{
+ EXP_SUBCMD, // expand :sign sub-commands
+ EXP_DEFINE, // expand :sign define {name} args
+ EXP_PLACE, // expand :sign place {id} args
+ EXP_UNPLACE, // expand :sign unplace"
+ EXP_SIGN_NAMES // expand with name of placed signs
+} expand_what;
+
+/*
+ * Function given to ExpandGeneric() to obtain the sign command
+ * expansion.
+ */
+ char_u *
+get_sign_name(expand_T *xp UNUSED, int idx)
+{
+ sign_T *sp;
+ int current_idx;
+
+ switch (expand_what)
+ {
+ case EXP_SUBCMD:
+ return (char_u *)cmds[idx];
+ case EXP_DEFINE:
+ {
+ char *define_arg[] =
+ {
+ "icon=", "linehl=", "text=", "texthl=", NULL
+ };
+ return (char_u *)define_arg[idx];
+ }
+ case EXP_PLACE:
+ {
+ char *place_arg[] =
+ {
+ "line=", "name=", "group=", "priority=", "file=",
+ "buffer=", NULL
+ };
+ return (char_u *)place_arg[idx];
+ }
+ case EXP_UNPLACE:
+ {
+ char *unplace_arg[] = { "group=", "file=", "buffer=", NULL };
+ return (char_u *)unplace_arg[idx];
+ }
+ case EXP_SIGN_NAMES:
+ // Complete with name of signs already defined
+ current_idx = 0;
+ for (sp = first_sign; sp != NULL; sp = sp->sn_next)
+ if (current_idx++ == idx)
+ return sp->sn_name;
+ return NULL;
+ default:
+ return NULL;
+ }
+}
+
+/*
+ * Handle command line completion for :sign command.
+ */
+ void
+set_context_in_sign_cmd(expand_T *xp, char_u *arg)
+{
+ char_u *p;
+ char_u *end_subcmd;
+ char_u *last;
+ int cmd_idx;
+ char_u *begin_subcmd_args;
+
+ // Default: expand subcommands.
+ xp->xp_context = EXPAND_SIGN;
+ expand_what = EXP_SUBCMD;
+ xp->xp_pattern = arg;
+
+ end_subcmd = skiptowhite(arg);
+ if (*end_subcmd == NUL)
+ // expand subcmd name
+ // :sign {subcmd}<CTRL-D>
+ return;
+
+ cmd_idx = sign_cmd_idx(arg, end_subcmd);
+
+ // :sign {subcmd} {subcmd_args}
+ // |
+ // begin_subcmd_args
+ begin_subcmd_args = skipwhite(end_subcmd);
+ p = skiptowhite(begin_subcmd_args);
+ if (*p == NUL)
+ {
+ //
+ // Expand first argument of subcmd when possible.
+ // For ":jump {id}" and ":unplace {id}", we could
+ // possibly expand the ids of all signs already placed.
+ //
+ xp->xp_pattern = begin_subcmd_args;
+ switch (cmd_idx)
+ {
+ case SIGNCMD_LIST:
+ case SIGNCMD_UNDEFINE:
+ // :sign list <CTRL-D>
+ // :sign undefine <CTRL-D>
+ expand_what = EXP_SIGN_NAMES;
+ break;
+ default:
+ xp->xp_context = EXPAND_NOTHING;
+ }
+ return;
+ }
+
+ // expand last argument of subcmd
+
+ // :sign define {name} {args}...
+ // |
+ // p
+
+ // Loop until reaching last argument.
+ do
+ {
+ p = skipwhite(p);
+ last = p;
+ p = skiptowhite(p);
+ } while (*p != NUL);
+
+ p = vim_strchr(last, '=');
+
+ // :sign define {name} {args}... {last}=
+ // | |
+ // last p
+ if (p == NULL)
+ {
+ // Expand last argument name (before equal sign).
+ xp->xp_pattern = last;
+ switch (cmd_idx)
+ {
+ case SIGNCMD_DEFINE:
+ expand_what = EXP_DEFINE;
+ break;
+ case SIGNCMD_PLACE:
+ expand_what = EXP_PLACE;
+ break;
+ case SIGNCMD_JUMP:
+ case SIGNCMD_UNPLACE:
+ expand_what = EXP_UNPLACE;
+ break;
+ default:
+ xp->xp_context = EXPAND_NOTHING;
+ }
+ }
+ else
+ {
+ // Expand last argument value (after equal sign).
+ xp->xp_pattern = p + 1;
+ switch (cmd_idx)
+ {
+ case SIGNCMD_DEFINE:
+ if (STRNCMP(last, "texthl", p - last) == 0
+ || STRNCMP(last, "linehl", p - last) == 0)
+ xp->xp_context = EXPAND_HIGHLIGHT;
+ else if (STRNCMP(last, "icon", p - last) == 0)
+ xp->xp_context = EXPAND_FILES;
+ else
+ xp->xp_context = EXPAND_NOTHING;
+ break;
+ case SIGNCMD_PLACE:
+ if (STRNCMP(last, "name", p - last) == 0)
+ expand_what = EXP_SIGN_NAMES;
+ else
+ xp->xp_context = EXPAND_NOTHING;
+ break;
+ default:
+ xp->xp_context = EXPAND_NOTHING;
+ }
+ }
+}
+# endif
+
+#endif /* FEAT_SIGNS */
diff --git a/src/spell.c b/src/spell.c
new file mode 100644
index 0000000..8aadb99
--- /dev/null
+++ b/src/spell.c
@@ -0,0 +1,8841 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * spell.c: code for spell checking
+ *
+ * See spellfile.c for the Vim spell file format.
+ *
+ * The spell checking mechanism uses a tree (aka trie). Each node in the tree
+ * has a list of bytes that can appear (siblings). For each byte there is a
+ * pointer to the node with the byte that follows in the word (child).
+ *
+ * A NUL byte is used where the word may end. The bytes are sorted, so that
+ * binary searching can be used and the NUL bytes are at the start. The
+ * number of possible bytes is stored before the list of bytes.
+ *
+ * The tree uses two arrays: "byts" stores the characters, "idxs" stores
+ * either the next index or flags. The tree starts at index 0. For example,
+ * to lookup "vi" this sequence is followed:
+ * i = 0
+ * len = byts[i]
+ * n = where "v" appears in byts[i + 1] to byts[i + len]
+ * i = idxs[n]
+ * len = byts[i]
+ * n = where "i" appears in byts[i + 1] to byts[i + len]
+ * i = idxs[n]
+ * len = byts[i]
+ * find that byts[i + 1] is 0, idxs[i + 1] has flags for "vi".
+ *
+ * There are two word trees: one with case-folded words and one with words in
+ * original case. The second one is only used for keep-case words and is
+ * usually small.
+ *
+ * There is one additional tree for when not all prefixes are applied when
+ * generating the .spl file. This tree stores all the possible prefixes, as
+ * if they were words. At each word (prefix) end the prefix nr is stored, the
+ * following word must support this prefix nr. And the condition nr is
+ * stored, used to lookup the condition that the word must match with.
+ *
+ * Thanks to Olaf Seibert for providing an example implementation of this tree
+ * and the compression mechanism.
+ * LZ trie ideas:
+ * http://www.irb.hr/hr/home/ristov/papers/RistovLZtrieRevision1.pdf
+ * More papers: http://www-igm.univ-mlv.fr/~laporte/publi_en.html
+ *
+ * Matching involves checking the caps type: Onecap ALLCAP KeepCap.
+ *
+ * Why doesn't Vim use aspell/ispell/myspell/etc.?
+ * See ":help develop-spell".
+ */
+
+/*
+ * Use this to adjust the score after finding suggestions, based on the
+ * suggested word sounding like the bad word. This is much faster than doing
+ * it for every possible suggestion.
+ * Disadvantage: When "the" is typed as "hte" it sounds quite different ("@"
+ * vs "ht") and goes down in the list.
+ * Used when 'spellsuggest' is set to "best".
+ */
+#define RESCORE(word_score, sound_score) ((3 * word_score + sound_score) / 4)
+
+/*
+ * Do the opposite: based on a maximum end score and a known sound score,
+ * compute the maximum word score that can be used.
+ */
+#define MAXSCORE(word_score, sound_score) ((4 * word_score - sound_score) / 3)
+
+#define IN_SPELL_C
+#include "vim.h"
+
+#if defined(FEAT_SPELL) || defined(PROTO)
+
+#ifndef UNIX /* it's in os_unix.h for Unix */
+# include <time.h> /* for time_t */
+#endif
+
+/* only used for su_badflags */
+#define WF_MIXCAP 0x20 /* mix of upper and lower case: macaRONI */
+
+#define WF_CAPMASK (WF_ONECAP | WF_ALLCAP | WF_KEEPCAP | WF_FIXCAP)
+
+#define REGION_ALL 0xff /* word valid in all regions */
+
+#define VIMSUGMAGIC "VIMsug" /* string at start of Vim .sug file */
+#define VIMSUGMAGICL 6
+#define VIMSUGVERSION 1
+
+/* Result values. Lower number is accepted over higher one. */
+#define SP_BANNED -1
+#define SP_OK 0
+#define SP_RARE 1
+#define SP_LOCAL 2
+#define SP_BAD 3
+
+typedef struct wordcount_S
+{
+ short_u wc_count; /* nr of times word was seen */
+ char_u wc_word[1]; /* word, actually longer */
+} wordcount_T;
+
+#define WC_KEY_OFF offsetof(wordcount_T, wc_word)
+#define HI2WC(hi) ((wordcount_T *)((hi)->hi_key - WC_KEY_OFF))
+#define MAXWORDCOUNT 0xffff
+
+/*
+ * Information used when looking for suggestions.
+ */
+typedef struct suginfo_S
+{
+ garray_T su_ga; /* suggestions, contains "suggest_T" */
+ int su_maxcount; /* max. number of suggestions displayed */
+ int su_maxscore; /* maximum score for adding to su_ga */
+ int su_sfmaxscore; /* idem, for when doing soundfold words */
+ garray_T su_sga; /* like su_ga, sound-folded scoring */
+ char_u *su_badptr; /* start of bad word in line */
+ int su_badlen; /* length of detected bad word in line */
+ int su_badflags; /* caps flags for bad word */
+ char_u su_badword[MAXWLEN]; /* bad word truncated at su_badlen */
+ char_u su_fbadword[MAXWLEN]; /* su_badword case-folded */
+ char_u su_sal_badword[MAXWLEN]; /* su_badword soundfolded */
+ hashtab_T su_banned; /* table with banned words */
+ slang_T *su_sallang; /* default language for sound folding */
+} suginfo_T;
+
+/* One word suggestion. Used in "si_ga". */
+typedef struct suggest_S
+{
+ char_u *st_word; /* suggested word, allocated string */
+ int st_wordlen; /* STRLEN(st_word) */
+ int st_orglen; /* length of replaced text */
+ int st_score; /* lower is better */
+ int st_altscore; /* used when st_score compares equal */
+ int st_salscore; /* st_score is for soundalike */
+ int st_had_bonus; /* bonus already included in score */
+ slang_T *st_slang; /* language used for sound folding */
+} suggest_T;
+
+#define SUG(ga, i) (((suggest_T *)(ga).ga_data)[i])
+
+/* TRUE if a word appears in the list of banned words. */
+#define WAS_BANNED(su, word) (!HASHITEM_EMPTY(hash_find(&su->su_banned, word)))
+
+/* Number of suggestions kept when cleaning up. We need to keep more than
+ * what is displayed, because when rescore_suggestions() is called the score
+ * may change and wrong suggestions may be removed later. */
+#define SUG_CLEAN_COUNT(su) ((su)->su_maxcount < 130 ? 150 : (su)->su_maxcount + 20)
+
+/* Threshold for sorting and cleaning up suggestions. Don't want to keep lots
+ * of suggestions that are not going to be displayed. */
+#define SUG_MAX_COUNT(su) (SUG_CLEAN_COUNT(su) + 50)
+
+/* score for various changes */
+#define SCORE_SPLIT 149 /* split bad word */
+#define SCORE_SPLIT_NO 249 /* split bad word with NOSPLITSUGS */
+#define SCORE_ICASE 52 /* slightly different case */
+#define SCORE_REGION 200 /* word is for different region */
+#define SCORE_RARE 180 /* rare word */
+#define SCORE_SWAP 75 /* swap two characters */
+#define SCORE_SWAP3 110 /* swap two characters in three */
+#define SCORE_REP 65 /* REP replacement */
+#define SCORE_SUBST 93 /* substitute a character */
+#define SCORE_SIMILAR 33 /* substitute a similar character */
+#define SCORE_SUBCOMP 33 /* substitute a composing character */
+#define SCORE_DEL 94 /* delete a character */
+#define SCORE_DELDUP 66 /* delete a duplicated character */
+#define SCORE_DELCOMP 28 /* delete a composing character */
+#define SCORE_INS 96 /* insert a character */
+#define SCORE_INSDUP 67 /* insert a duplicate character */
+#define SCORE_INSCOMP 30 /* insert a composing character */
+#define SCORE_NONWORD 103 /* change non-word to word char */
+
+#define SCORE_FILE 30 /* suggestion from a file */
+#define SCORE_MAXINIT 350 /* Initial maximum score: higher == slower.
+ * 350 allows for about three changes. */
+
+#define SCORE_COMMON1 30 /* subtracted for words seen before */
+#define SCORE_COMMON2 40 /* subtracted for words often seen */
+#define SCORE_COMMON3 50 /* subtracted for words very often seen */
+#define SCORE_THRES2 10 /* word count threshold for COMMON2 */
+#define SCORE_THRES3 100 /* word count threshold for COMMON3 */
+
+/* When trying changed soundfold words it becomes slow when trying more than
+ * two changes. With less then two changes it's slightly faster but we miss a
+ * few good suggestions. In rare cases we need to try three of four changes.
+ */
+#define SCORE_SFMAX1 200 /* maximum score for first try */
+#define SCORE_SFMAX2 300 /* maximum score for second try */
+#define SCORE_SFMAX3 400 /* maximum score for third try */
+
+#define SCORE_BIG SCORE_INS * 3 /* big difference */
+#define SCORE_MAXMAX 999999 /* accept any score */
+#define SCORE_LIMITMAX 350 /* for spell_edit_score_limit() */
+
+/* for spell_edit_score_limit() we need to know the minimum value of
+ * SCORE_ICASE, SCORE_SWAP, SCORE_DEL, SCORE_SIMILAR and SCORE_INS */
+#define SCORE_EDIT_MIN SCORE_SIMILAR
+
+/*
+ * Structure to store info for word matching.
+ */
+typedef struct matchinf_S
+{
+ langp_T *mi_lp; /* info for language and region */
+
+ /* pointers to original text to be checked */
+ char_u *mi_word; /* start of word being checked */
+ char_u *mi_end; /* end of matching word so far */
+ char_u *mi_fend; /* next char to be added to mi_fword */
+ char_u *mi_cend; /* char after what was used for
+ mi_capflags */
+
+ /* case-folded text */
+ char_u mi_fword[MAXWLEN + 1]; /* mi_word case-folded */
+ int mi_fwordlen; /* nr of valid bytes in mi_fword */
+
+ /* for when checking word after a prefix */
+ int mi_prefarridx; /* index in sl_pidxs with list of
+ affixID/condition */
+ int mi_prefcnt; /* number of entries at mi_prefarridx */
+ int mi_prefixlen; /* byte length of prefix */
+ int mi_cprefixlen; /* byte length of prefix in original
+ case */
+
+ /* for when checking a compound word */
+ int mi_compoff; /* start of following word offset */
+ char_u mi_compflags[MAXWLEN]; /* flags for compound words used */
+ int mi_complen; /* nr of compound words used */
+ int mi_compextra; /* nr of COMPOUNDROOT words */
+
+ /* others */
+ int mi_result; /* result so far: SP_BAD, SP_OK, etc. */
+ int mi_capflags; /* WF_ONECAP WF_ALLCAP WF_KEEPCAP */
+ win_T *mi_win; /* buffer being checked */
+
+ /* for NOBREAK */
+ int mi_result2; /* "mi_resul" without following word */
+ char_u *mi_end2; /* "mi_end" without following word */
+} matchinf_T;
+
+
+static int spell_iswordp(char_u *p, win_T *wp);
+static int spell_mb_isword_class(int cl, win_T *wp);
+
+/*
+ * For finding suggestions: At each node in the tree these states are tried:
+ */
+typedef enum
+{
+ STATE_START = 0, /* At start of node check for NUL bytes (goodword
+ * ends); if badword ends there is a match, otherwise
+ * try splitting word. */
+ STATE_NOPREFIX, /* try without prefix */
+ STATE_SPLITUNDO, /* Undo splitting. */
+ STATE_ENDNUL, /* Past NUL bytes at start of the node. */
+ STATE_PLAIN, /* Use each byte of the node. */
+ STATE_DEL, /* Delete a byte from the bad word. */
+ STATE_INS_PREP, /* Prepare for inserting bytes. */
+ STATE_INS, /* Insert a byte in the bad word. */
+ STATE_SWAP, /* Swap two bytes. */
+ STATE_UNSWAP, /* Undo swap two characters. */
+ STATE_SWAP3, /* Swap two characters over three. */
+ STATE_UNSWAP3, /* Undo Swap two characters over three. */
+ STATE_UNROT3L, /* Undo rotate three characters left */
+ STATE_UNROT3R, /* Undo rotate three characters right */
+ STATE_REP_INI, /* Prepare for using REP items. */
+ STATE_REP, /* Use matching REP items from the .aff file. */
+ STATE_REP_UNDO, /* Undo a REP item replacement. */
+ STATE_FINAL /* End of this node. */
+} state_T;
+
+/*
+ * Struct to keep the state at each level in suggest_try_change().
+ */
+typedef struct trystate_S
+{
+ state_T ts_state; /* state at this level, STATE_ */
+ int ts_score; /* score */
+ idx_T ts_arridx; /* index in tree array, start of node */
+ short ts_curi; /* index in list of child nodes */
+ char_u ts_fidx; /* index in fword[], case-folded bad word */
+ char_u ts_fidxtry; /* ts_fidx at which bytes may be changed */
+ char_u ts_twordlen; /* valid length of tword[] */
+ char_u ts_prefixdepth; /* stack depth for end of prefix or
+ * PFD_PREFIXTREE or PFD_NOPREFIX */
+ char_u ts_flags; /* TSF_ flags */
+ char_u ts_tcharlen; /* number of bytes in tword character */
+ char_u ts_tcharidx; /* current byte index in tword character */
+ char_u ts_isdiff; /* DIFF_ values */
+ char_u ts_fcharstart; /* index in fword where badword char started */
+ char_u ts_prewordlen; /* length of word in "preword[]" */
+ char_u ts_splitoff; /* index in "tword" after last split */
+ char_u ts_splitfidx; /* "ts_fidx" at word split */
+ char_u ts_complen; /* nr of compound words used */
+ char_u ts_compsplit; /* index for "compflags" where word was spit */
+ char_u ts_save_badflags; /* su_badflags saved here */
+ char_u ts_delidx; /* index in fword for char that was deleted,
+ valid when "ts_flags" has TSF_DIDDEL */
+} trystate_T;
+
+/* values for ts_isdiff */
+#define DIFF_NONE 0 /* no different byte (yet) */
+#define DIFF_YES 1 /* different byte found */
+#define DIFF_INSERT 2 /* inserting character */
+
+/* values for ts_flags */
+#define TSF_PREFIXOK 1 /* already checked that prefix is OK */
+#define TSF_DIDSPLIT 2 /* tried split at this point */
+#define TSF_DIDDEL 4 /* did a delete, "ts_delidx" has index */
+
+/* special values ts_prefixdepth */
+#define PFD_NOPREFIX 0xff /* not using prefixes */
+#define PFD_PREFIXTREE 0xfe /* walking through the prefix tree */
+#define PFD_NOTSPECIAL 0xfd /* highest value that's not special */
+
+/* mode values for find_word */
+#define FIND_FOLDWORD 0 /* find word case-folded */
+#define FIND_KEEPWORD 1 /* find keep-case word */
+#define FIND_PREFIX 2 /* find word after prefix */
+#define FIND_COMPOUND 3 /* find case-folded compound word */
+#define FIND_KEEPCOMPOUND 4 /* find keep-case compound word */
+
+static void find_word(matchinf_T *mip, int mode);
+static int match_checkcompoundpattern(char_u *ptr, int wlen, garray_T *gap);
+static int can_compound(slang_T *slang, char_u *word, char_u *flags);
+static int match_compoundrule(slang_T *slang, char_u *compflags);
+static int valid_word_prefix(int totprefcnt, int arridx, int flags, char_u *word, slang_T *slang, int cond_req);
+static void find_prefix(matchinf_T *mip, int mode);
+static int fold_more(matchinf_T *mip);
+static int spell_valid_case(int wordflags, int treeflags);
+static void spell_load_cb(char_u *fname, void *cookie);
+static int count_syllables(slang_T *slang, char_u *word);
+static void clear_midword(win_T *buf);
+static void use_midword(slang_T *lp, win_T *buf);
+static int find_region(char_u *rp, char_u *region);
+static int check_need_cap(linenr_T lnum, colnr_T col);
+static void spell_find_suggest(char_u *badptr, int badlen, suginfo_T *su, int maxcount, int banbadword, int need_cap, int interactive);
+#ifdef FEAT_EVAL
+static void spell_suggest_expr(suginfo_T *su, char_u *expr);
+#endif
+static void spell_suggest_file(suginfo_T *su, char_u *fname);
+static void spell_suggest_intern(suginfo_T *su, int interactive);
+static void spell_find_cleanup(suginfo_T *su);
+static void suggest_try_special(suginfo_T *su);
+static void suggest_try_change(suginfo_T *su);
+static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, int soundfold);
+static void go_deeper(trystate_T *stack, int depth, int score_add);
+static int nofold_len(char_u *fword, int flen, char_u *word);
+static void find_keepcap_word(slang_T *slang, char_u *fword, char_u *kword);
+static void score_comp_sal(suginfo_T *su);
+static void score_combine(suginfo_T *su);
+static int stp_sal_score(suggest_T *stp, suginfo_T *su, slang_T *slang, char_u *badsound);
+static void suggest_try_soundalike_prep(void);
+static void suggest_try_soundalike(suginfo_T *su);
+static void suggest_try_soundalike_finish(void);
+static void add_sound_suggest(suginfo_T *su, char_u *goodword, int score, langp_T *lp);
+static int soundfold_find(slang_T *slang, char_u *word);
+static void make_case_word(char_u *fword, char_u *cword, int flags);
+static int similar_chars(slang_T *slang, int c1, int c2);
+static void add_suggestion(suginfo_T *su, garray_T *gap, char_u *goodword, int badlen, int score, int altscore, int had_bonus, slang_T *slang, int maxsf);
+static void check_suggestions(suginfo_T *su, garray_T *gap);
+static void add_banned(suginfo_T *su, char_u *word);
+static void rescore_suggestions(suginfo_T *su);
+static void rescore_one(suginfo_T *su, suggest_T *stp);
+static int cleanup_suggestions(garray_T *gap, int maxscore, int keep);
+static void spell_soundfold_sofo(slang_T *slang, char_u *inword, char_u *res);
+static void spell_soundfold_sal(slang_T *slang, char_u *inword, char_u *res);
+static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res);
+static int soundalike_score(char_u *goodsound, char_u *badsound);
+static int spell_edit_score(slang_T *slang, char_u *badword, char_u *goodword);
+static int spell_edit_score_limit(slang_T *slang, char_u *badword, char_u *goodword, int limit);
+static int spell_edit_score_limit_w(slang_T *slang, char_u *badword, char_u *goodword, int limit);
+static void dump_word(slang_T *slang, char_u *word, char_u *pat, int *dir, int round, int flags, linenr_T lnum);
+static linenr_T dump_prefixes(slang_T *slang, char_u *word, char_u *pat, int *dir, int round, int flags, linenr_T startlnum);
+
+
+/* Remember what "z?" replaced. */
+static char_u *repl_from = NULL;
+static char_u *repl_to = NULL;
+
+/*
+ * Main spell-checking function.
+ * "ptr" points to a character that could be the start of a word.
+ * "*attrp" is set to the highlight index for a badly spelled word. For a
+ * non-word or when it's OK it remains unchanged.
+ * This must only be called when 'spelllang' is not empty.
+ *
+ * "capcol" is used to check for a Capitalised word after the end of a
+ * sentence. If it's zero then perform the check. Return the column where to
+ * check next, or -1 when no sentence end was found. If it's NULL then don't
+ * worry.
+ *
+ * Returns the length of the word in bytes, also when it's OK, so that the
+ * caller can skip over the word.
+ */
+ int
+spell_check(
+ win_T *wp, /* current window */
+ char_u *ptr,
+ hlf_T *attrp,
+ int *capcol, /* column to check for Capital */
+ int docount) /* count good words */
+{
+ matchinf_T mi; /* Most things are put in "mi" so that it can
+ be passed to functions quickly. */
+ int nrlen = 0; /* found a number first */
+ int c;
+ int wrongcaplen = 0;
+ int lpi;
+ int count_word = docount;
+
+ /* A word never starts at a space or a control character. Return quickly
+ * then, skipping over the character. */
+ if (*ptr <= ' ')
+ return 1;
+
+ /* Return here when loading language files failed. */
+ if (wp->w_s->b_langp.ga_len == 0)
+ return 1;
+
+ vim_memset(&mi, 0, sizeof(matchinf_T));
+
+ /* A number is always OK. Also skip hexadecimal numbers 0xFF99 and
+ * 0X99FF. But always do check spelling to find "3GPP" and "11
+ * julifeest". */
+ if (*ptr >= '0' && *ptr <= '9')
+ {
+ if (*ptr == '0' && (ptr[1] == 'b' || ptr[1] == 'B'))
+ mi.mi_end = skipbin(ptr + 2);
+ else if (*ptr == '0' && (ptr[1] == 'x' || ptr[1] == 'X'))
+ mi.mi_end = skiphex(ptr + 2);
+ else
+ mi.mi_end = skipdigits(ptr);
+ nrlen = (int)(mi.mi_end - ptr);
+ }
+
+ /* Find the normal end of the word (until the next non-word character). */
+ mi.mi_word = ptr;
+ mi.mi_fend = ptr;
+ if (spell_iswordp(mi.mi_fend, wp))
+ {
+ do
+ {
+ MB_PTR_ADV(mi.mi_fend);
+ } while (*mi.mi_fend != NUL && spell_iswordp(mi.mi_fend, wp));
+
+ if (capcol != NULL && *capcol == 0 && wp->w_s->b_cap_prog != NULL)
+ {
+ /* Check word starting with capital letter. */
+ c = PTR2CHAR(ptr);
+ if (!SPELL_ISUPPER(c))
+ wrongcaplen = (int)(mi.mi_fend - ptr);
+ }
+ }
+ if (capcol != NULL)
+ *capcol = -1;
+
+ /* We always use the characters up to the next non-word character,
+ * also for bad words. */
+ mi.mi_end = mi.mi_fend;
+
+ /* Check caps type later. */
+ mi.mi_capflags = 0;
+ mi.mi_cend = NULL;
+ mi.mi_win = wp;
+
+ /* case-fold the word with one non-word character, so that we can check
+ * for the word end. */
+ if (*mi.mi_fend != NUL)
+ MB_PTR_ADV(mi.mi_fend);
+
+ (void)spell_casefold(ptr, (int)(mi.mi_fend - ptr), mi.mi_fword,
+ MAXWLEN + 1);
+ mi.mi_fwordlen = (int)STRLEN(mi.mi_fword);
+
+ /* The word is bad unless we recognize it. */
+ mi.mi_result = SP_BAD;
+ mi.mi_result2 = SP_BAD;
+
+ /*
+ * Loop over the languages specified in 'spelllang'.
+ * We check them all, because a word may be matched longer in another
+ * language.
+ */
+ for (lpi = 0; lpi < wp->w_s->b_langp.ga_len; ++lpi)
+ {
+ mi.mi_lp = LANGP_ENTRY(wp->w_s->b_langp, lpi);
+
+ /* If reloading fails the language is still in the list but everything
+ * has been cleared. */
+ if (mi.mi_lp->lp_slang->sl_fidxs == NULL)
+ continue;
+
+ /* Check for a matching word in case-folded words. */
+ find_word(&mi, FIND_FOLDWORD);
+
+ /* Check for a matching word in keep-case words. */
+ find_word(&mi, FIND_KEEPWORD);
+
+ /* Check for matching prefixes. */
+ find_prefix(&mi, FIND_FOLDWORD);
+
+ /* For a NOBREAK language, may want to use a word without a following
+ * word as a backup. */
+ if (mi.mi_lp->lp_slang->sl_nobreak && mi.mi_result == SP_BAD
+ && mi.mi_result2 != SP_BAD)
+ {
+ mi.mi_result = mi.mi_result2;
+ mi.mi_end = mi.mi_end2;
+ }
+
+ /* Count the word in the first language where it's found to be OK. */
+ if (count_word && mi.mi_result == SP_OK)
+ {
+ count_common_word(mi.mi_lp->lp_slang, ptr,
+ (int)(mi.mi_end - ptr), 1);
+ count_word = FALSE;
+ }
+ }
+
+ if (mi.mi_result != SP_OK)
+ {
+ /* If we found a number skip over it. Allows for "42nd". Do flag
+ * rare and local words, e.g., "3GPP". */
+ if (nrlen > 0)
+ {
+ if (mi.mi_result == SP_BAD || mi.mi_result == SP_BANNED)
+ return nrlen;
+ }
+
+ /* When we are at a non-word character there is no error, just
+ * skip over the character (try looking for a word after it). */
+ else if (!spell_iswordp_nmw(ptr, wp))
+ {
+ if (capcol != NULL && wp->w_s->b_cap_prog != NULL)
+ {
+ regmatch_T regmatch;
+ int r;
+
+ /* Check for end of sentence. */
+ regmatch.regprog = wp->w_s->b_cap_prog;
+ regmatch.rm_ic = FALSE;
+ r = vim_regexec(&regmatch, ptr, 0);
+ wp->w_s->b_cap_prog = regmatch.regprog;
+ if (r)
+ *capcol = (int)(regmatch.endp[0] - ptr);
+ }
+
+ if (has_mbyte)
+ return (*mb_ptr2len)(ptr);
+ return 1;
+ }
+ else if (mi.mi_end == ptr)
+ /* Always include at least one character. Required for when there
+ * is a mixup in "midword". */
+ MB_PTR_ADV(mi.mi_end);
+ else if (mi.mi_result == SP_BAD
+ && LANGP_ENTRY(wp->w_s->b_langp, 0)->lp_slang->sl_nobreak)
+ {
+ char_u *p, *fp;
+ int save_result = mi.mi_result;
+
+ /* First language in 'spelllang' is NOBREAK. Find first position
+ * at which any word would be valid. */
+ mi.mi_lp = LANGP_ENTRY(wp->w_s->b_langp, 0);
+ if (mi.mi_lp->lp_slang->sl_fidxs != NULL)
+ {
+ p = mi.mi_word;
+ fp = mi.mi_fword;
+ for (;;)
+ {
+ MB_PTR_ADV(p);
+ MB_PTR_ADV(fp);
+ if (p >= mi.mi_end)
+ break;
+ mi.mi_compoff = (int)(fp - mi.mi_fword);
+ find_word(&mi, FIND_COMPOUND);
+ if (mi.mi_result != SP_BAD)
+ {
+ mi.mi_end = p;
+ break;
+ }
+ }
+ mi.mi_result = save_result;
+ }
+ }
+
+ if (mi.mi_result == SP_BAD || mi.mi_result == SP_BANNED)
+ *attrp = HLF_SPB;
+ else if (mi.mi_result == SP_RARE)
+ *attrp = HLF_SPR;
+ else
+ *attrp = HLF_SPL;
+ }
+
+ if (wrongcaplen > 0 && (mi.mi_result == SP_OK || mi.mi_result == SP_RARE))
+ {
+ /* Report SpellCap only when the word isn't badly spelled. */
+ *attrp = HLF_SPC;
+ return wrongcaplen;
+ }
+
+ return (int)(mi.mi_end - ptr);
+}
+
+/*
+ * Check if the word at "mip->mi_word" is in the tree.
+ * When "mode" is FIND_FOLDWORD check in fold-case word tree.
+ * When "mode" is FIND_KEEPWORD check in keep-case word tree.
+ * When "mode" is FIND_PREFIX check for word after prefix in fold-case word
+ * tree.
+ *
+ * For a match mip->mi_result is updated.
+ */
+ static void
+find_word(matchinf_T *mip, int mode)
+{
+ idx_T arridx = 0;
+ int endlen[MAXWLEN]; /* length at possible word endings */
+ idx_T endidx[MAXWLEN]; /* possible word endings */
+ int endidxcnt = 0;
+ int len;
+ int wlen = 0;
+ int flen;
+ int c;
+ char_u *ptr;
+ idx_T lo, hi, m;
+ char_u *s;
+ char_u *p;
+ int res = SP_BAD;
+ slang_T *slang = mip->mi_lp->lp_slang;
+ unsigned flags;
+ char_u *byts;
+ idx_T *idxs;
+ int word_ends;
+ int prefix_found;
+ int nobreak_result;
+
+ if (mode == FIND_KEEPWORD || mode == FIND_KEEPCOMPOUND)
+ {
+ /* Check for word with matching case in keep-case tree. */
+ ptr = mip->mi_word;
+ flen = 9999; /* no case folding, always enough bytes */
+ byts = slang->sl_kbyts;
+ idxs = slang->sl_kidxs;
+
+ if (mode == FIND_KEEPCOMPOUND)
+ /* Skip over the previously found word(s). */
+ wlen += mip->mi_compoff;
+ }
+ else
+ {
+ /* Check for case-folded in case-folded tree. */
+ ptr = mip->mi_fword;
+ flen = mip->mi_fwordlen; /* available case-folded bytes */
+ byts = slang->sl_fbyts;
+ idxs = slang->sl_fidxs;
+
+ if (mode == FIND_PREFIX)
+ {
+ /* Skip over the prefix. */
+ wlen = mip->mi_prefixlen;
+ flen -= mip->mi_prefixlen;
+ }
+ else if (mode == FIND_COMPOUND)
+ {
+ /* Skip over the previously found word(s). */
+ wlen = mip->mi_compoff;
+ flen -= mip->mi_compoff;
+ }
+
+ }
+
+ if (byts == NULL)
+ return; /* array is empty */
+
+ /*
+ * Repeat advancing in the tree until:
+ * - there is a byte that doesn't match,
+ * - we reach the end of the tree,
+ * - or we reach the end of the line.
+ */
+ for (;;)
+ {
+ if (flen <= 0 && *mip->mi_fend != NUL)
+ flen = fold_more(mip);
+
+ len = byts[arridx++];
+
+ /* If the first possible byte is a zero the word could end here.
+ * Remember this index, we first check for the longest word. */
+ if (byts[arridx] == 0)
+ {
+ if (endidxcnt == MAXWLEN)
+ {
+ /* Must be a corrupted spell file. */
+ emsg(_(e_format));
+ return;
+ }
+ endlen[endidxcnt] = wlen;
+ endidx[endidxcnt++] = arridx++;
+ --len;
+
+ /* Skip over the zeros, there can be several flag/region
+ * combinations. */
+ while (len > 0 && byts[arridx] == 0)
+ {
+ ++arridx;
+ --len;
+ }
+ if (len == 0)
+ break; /* no children, word must end here */
+ }
+
+ /* Stop looking at end of the line. */
+ if (ptr[wlen] == NUL)
+ break;
+
+ /* Perform a binary search in the list of accepted bytes. */
+ c = ptr[wlen];
+ if (c == TAB) /* <Tab> is handled like <Space> */
+ c = ' ';
+ lo = arridx;
+ hi = arridx + len - 1;
+ while (lo < hi)
+ {
+ m = (lo + hi) / 2;
+ if (byts[m] > c)
+ hi = m - 1;
+ else if (byts[m] < c)
+ lo = m + 1;
+ else
+ {
+ lo = hi = m;
+ break;
+ }
+ }
+
+ /* Stop if there is no matching byte. */
+ if (hi < lo || byts[lo] != c)
+ break;
+
+ /* Continue at the child (if there is one). */
+ arridx = idxs[lo];
+ ++wlen;
+ --flen;
+
+ /* One space in the good word may stand for several spaces in the
+ * checked word. */
+ if (c == ' ')
+ {
+ for (;;)
+ {
+ if (flen <= 0 && *mip->mi_fend != NUL)
+ flen = fold_more(mip);
+ if (ptr[wlen] != ' ' && ptr[wlen] != TAB)
+ break;
+ ++wlen;
+ --flen;
+ }
+ }
+ }
+
+ /*
+ * Verify that one of the possible endings is valid. Try the longest
+ * first.
+ */
+ while (endidxcnt > 0)
+ {
+ --endidxcnt;
+ arridx = endidx[endidxcnt];
+ wlen = endlen[endidxcnt];
+
+ if ((*mb_head_off)(ptr, ptr + wlen) > 0)
+ continue; /* not at first byte of character */
+ if (spell_iswordp(ptr + wlen, mip->mi_win))
+ {
+ if (slang->sl_compprog == NULL && !slang->sl_nobreak)
+ continue; /* next char is a word character */
+ word_ends = FALSE;
+ }
+ else
+ word_ends = TRUE;
+ /* The prefix flag is before compound flags. Once a valid prefix flag
+ * has been found we try compound flags. */
+ prefix_found = FALSE;
+
+ if (mode != FIND_KEEPWORD && has_mbyte)
+ {
+ /* Compute byte length in original word, length may change
+ * when folding case. This can be slow, take a shortcut when the
+ * case-folded word is equal to the keep-case word. */
+ p = mip->mi_word;
+ if (STRNCMP(ptr, p, wlen) != 0)
+ {
+ for (s = ptr; s < ptr + wlen; MB_PTR_ADV(s))
+ MB_PTR_ADV(p);
+ wlen = (int)(p - mip->mi_word);
+ }
+ }
+
+ /* Check flags and region. For FIND_PREFIX check the condition and
+ * prefix ID.
+ * Repeat this if there are more flags/region alternatives until there
+ * is a match. */
+ res = SP_BAD;
+ for (len = byts[arridx - 1]; len > 0 && byts[arridx] == 0;
+ --len, ++arridx)
+ {
+ flags = idxs[arridx];
+
+ /* For the fold-case tree check that the case of the checked word
+ * matches with what the word in the tree requires.
+ * For keep-case tree the case is always right. For prefixes we
+ * don't bother to check. */
+ if (mode == FIND_FOLDWORD)
+ {
+ if (mip->mi_cend != mip->mi_word + wlen)
+ {
+ /* mi_capflags was set for a different word length, need
+ * to do it again. */
+ mip->mi_cend = mip->mi_word + wlen;
+ mip->mi_capflags = captype(mip->mi_word, mip->mi_cend);
+ }
+
+ if (mip->mi_capflags == WF_KEEPCAP
+ || !spell_valid_case(mip->mi_capflags, flags))
+ continue;
+ }
+
+ /* When mode is FIND_PREFIX the word must support the prefix:
+ * check the prefix ID and the condition. Do that for the list at
+ * mip->mi_prefarridx that find_prefix() filled. */
+ else if (mode == FIND_PREFIX && !prefix_found)
+ {
+ c = valid_word_prefix(mip->mi_prefcnt, mip->mi_prefarridx,
+ flags,
+ mip->mi_word + mip->mi_cprefixlen, slang,
+ FALSE);
+ if (c == 0)
+ continue;
+
+ /* Use the WF_RARE flag for a rare prefix. */
+ if (c & WF_RAREPFX)
+ flags |= WF_RARE;
+ prefix_found = TRUE;
+ }
+
+ if (slang->sl_nobreak)
+ {
+ if ((mode == FIND_COMPOUND || mode == FIND_KEEPCOMPOUND)
+ && (flags & WF_BANNED) == 0)
+ {
+ /* NOBREAK: found a valid following word. That's all we
+ * need to know, so return. */
+ mip->mi_result = SP_OK;
+ break;
+ }
+ }
+
+ else if ((mode == FIND_COMPOUND || mode == FIND_KEEPCOMPOUND
+ || !word_ends))
+ {
+ /* If there is no compound flag or the word is shorter than
+ * COMPOUNDMIN reject it quickly.
+ * Makes you wonder why someone puts a compound flag on a word
+ * that's too short... Myspell compatibility requires this
+ * anyway. */
+ if (((unsigned)flags >> 24) == 0
+ || wlen - mip->mi_compoff < slang->sl_compminlen)
+ continue;
+ /* For multi-byte chars check character length against
+ * COMPOUNDMIN. */
+ if (has_mbyte
+ && slang->sl_compminlen > 0
+ && mb_charlen_len(mip->mi_word + mip->mi_compoff,
+ wlen - mip->mi_compoff) < slang->sl_compminlen)
+ continue;
+
+ /* Limit the number of compound words to COMPOUNDWORDMAX if no
+ * maximum for syllables is specified. */
+ if (!word_ends && mip->mi_complen + mip->mi_compextra + 2
+ > slang->sl_compmax
+ && slang->sl_compsylmax == MAXWLEN)
+ continue;
+
+ /* Don't allow compounding on a side where an affix was added,
+ * unless COMPOUNDPERMITFLAG was used. */
+ if (mip->mi_complen > 0 && (flags & WF_NOCOMPBEF))
+ continue;
+ if (!word_ends && (flags & WF_NOCOMPAFT))
+ continue;
+
+ /* Quickly check if compounding is possible with this flag. */
+ if (!byte_in_str(mip->mi_complen == 0
+ ? slang->sl_compstartflags
+ : slang->sl_compallflags,
+ ((unsigned)flags >> 24)))
+ continue;
+
+ /* If there is a match with a CHECKCOMPOUNDPATTERN rule
+ * discard the compound word. */
+ if (match_checkcompoundpattern(ptr, wlen, &slang->sl_comppat))
+ continue;
+
+ if (mode == FIND_COMPOUND)
+ {
+ int capflags;
+
+ /* Need to check the caps type of the appended compound
+ * word. */
+ if (has_mbyte && STRNCMP(ptr, mip->mi_word,
+ mip->mi_compoff) != 0)
+ {
+ /* case folding may have changed the length */
+ p = mip->mi_word;
+ for (s = ptr; s < ptr + mip->mi_compoff; MB_PTR_ADV(s))
+ MB_PTR_ADV(p);
+ }
+ else
+ p = mip->mi_word + mip->mi_compoff;
+ capflags = captype(p, mip->mi_word + wlen);
+ if (capflags == WF_KEEPCAP || (capflags == WF_ALLCAP
+ && (flags & WF_FIXCAP) != 0))
+ continue;
+
+ if (capflags != WF_ALLCAP)
+ {
+ /* When the character before the word is a word
+ * character we do not accept a Onecap word. We do
+ * accept a no-caps word, even when the dictionary
+ * word specifies ONECAP. */
+ MB_PTR_BACK(mip->mi_word, p);
+ if (spell_iswordp_nmw(p, mip->mi_win)
+ ? capflags == WF_ONECAP
+ : (flags & WF_ONECAP) != 0
+ && capflags != WF_ONECAP)
+ continue;
+ }
+ }
+
+ /* If the word ends the sequence of compound flags of the
+ * words must match with one of the COMPOUNDRULE items and
+ * the number of syllables must not be too large. */
+ mip->mi_compflags[mip->mi_complen] = ((unsigned)flags >> 24);
+ mip->mi_compflags[mip->mi_complen + 1] = NUL;
+ if (word_ends)
+ {
+ char_u fword[MAXWLEN];
+
+ if (slang->sl_compsylmax < MAXWLEN)
+ {
+ /* "fword" is only needed for checking syllables. */
+ if (ptr == mip->mi_word)
+ (void)spell_casefold(ptr, wlen, fword, MAXWLEN);
+ else
+ vim_strncpy(fword, ptr, endlen[endidxcnt]);
+ }
+ if (!can_compound(slang, fword, mip->mi_compflags))
+ continue;
+ }
+ else if (slang->sl_comprules != NULL
+ && !match_compoundrule(slang, mip->mi_compflags))
+ /* The compound flags collected so far do not match any
+ * COMPOUNDRULE, discard the compounded word. */
+ continue;
+ }
+
+ /* Check NEEDCOMPOUND: can't use word without compounding. */
+ else if (flags & WF_NEEDCOMP)
+ continue;
+
+ nobreak_result = SP_OK;
+
+ if (!word_ends)
+ {
+ int save_result = mip->mi_result;
+ char_u *save_end = mip->mi_end;
+ langp_T *save_lp = mip->mi_lp;
+ int lpi;
+
+ /* Check that a valid word follows. If there is one and we
+ * are compounding, it will set "mi_result", thus we are
+ * always finished here. For NOBREAK we only check that a
+ * valid word follows.
+ * Recursive! */
+ if (slang->sl_nobreak)
+ mip->mi_result = SP_BAD;
+
+ /* Find following word in case-folded tree. */
+ mip->mi_compoff = endlen[endidxcnt];
+ if (has_mbyte && mode == FIND_KEEPWORD)
+ {
+ /* Compute byte length in case-folded word from "wlen":
+ * byte length in keep-case word. Length may change when
+ * folding case. This can be slow, take a shortcut when
+ * the case-folded word is equal to the keep-case word. */
+ p = mip->mi_fword;
+ if (STRNCMP(ptr, p, wlen) != 0)
+ {
+ for (s = ptr; s < ptr + wlen; MB_PTR_ADV(s))
+ MB_PTR_ADV(p);
+ mip->mi_compoff = (int)(p - mip->mi_fword);
+ }
+ }
+#if 0 /* Disabled, see below */
+ c = mip->mi_compoff;
+#endif
+ ++mip->mi_complen;
+ if (flags & WF_COMPROOT)
+ ++mip->mi_compextra;
+
+ /* For NOBREAK we need to try all NOBREAK languages, at least
+ * to find the ".add" file(s). */
+ for (lpi = 0; lpi < mip->mi_win->w_s->b_langp.ga_len; ++lpi)
+ {
+ if (slang->sl_nobreak)
+ {
+ mip->mi_lp = LANGP_ENTRY(mip->mi_win->w_s->b_langp, lpi);
+ if (mip->mi_lp->lp_slang->sl_fidxs == NULL
+ || !mip->mi_lp->lp_slang->sl_nobreak)
+ continue;
+ }
+
+ find_word(mip, FIND_COMPOUND);
+
+ /* When NOBREAK any word that matches is OK. Otherwise we
+ * need to find the longest match, thus try with keep-case
+ * and prefix too. */
+ if (!slang->sl_nobreak || mip->mi_result == SP_BAD)
+ {
+ /* Find following word in keep-case tree. */
+ mip->mi_compoff = wlen;
+ find_word(mip, FIND_KEEPCOMPOUND);
+
+#if 0 /* Disabled, a prefix must not appear halfway a compound word,
+ unless the COMPOUNDPERMITFLAG is used and then it can't be a
+ postponed prefix. */
+ if (!slang->sl_nobreak || mip->mi_result == SP_BAD)
+ {
+ /* Check for following word with prefix. */
+ mip->mi_compoff = c;
+ find_prefix(mip, FIND_COMPOUND);
+ }
+#endif
+ }
+
+ if (!slang->sl_nobreak)
+ break;
+ }
+ --mip->mi_complen;
+ if (flags & WF_COMPROOT)
+ --mip->mi_compextra;
+ mip->mi_lp = save_lp;
+
+ if (slang->sl_nobreak)
+ {
+ nobreak_result = mip->mi_result;
+ mip->mi_result = save_result;
+ mip->mi_end = save_end;
+ }
+ else
+ {
+ if (mip->mi_result == SP_OK)
+ break;
+ continue;
+ }
+ }
+
+ if (flags & WF_BANNED)
+ res = SP_BANNED;
+ else if (flags & WF_REGION)
+ {
+ /* Check region. */
+ if ((mip->mi_lp->lp_region & (flags >> 16)) != 0)
+ res = SP_OK;
+ else
+ res = SP_LOCAL;
+ }
+ else if (flags & WF_RARE)
+ res = SP_RARE;
+ else
+ res = SP_OK;
+
+ /* Always use the longest match and the best result. For NOBREAK
+ * we separately keep the longest match without a following good
+ * word as a fall-back. */
+ if (nobreak_result == SP_BAD)
+ {
+ if (mip->mi_result2 > res)
+ {
+ mip->mi_result2 = res;
+ mip->mi_end2 = mip->mi_word + wlen;
+ }
+ else if (mip->mi_result2 == res
+ && mip->mi_end2 < mip->mi_word + wlen)
+ mip->mi_end2 = mip->mi_word + wlen;
+ }
+ else if (mip->mi_result > res)
+ {
+ mip->mi_result = res;
+ mip->mi_end = mip->mi_word + wlen;
+ }
+ else if (mip->mi_result == res && mip->mi_end < mip->mi_word + wlen)
+ mip->mi_end = mip->mi_word + wlen;
+
+ if (mip->mi_result == SP_OK)
+ break;
+ }
+
+ if (mip->mi_result == SP_OK)
+ break;
+ }
+}
+
+/*
+ * Return TRUE if there is a match between the word ptr[wlen] and
+ * CHECKCOMPOUNDPATTERN rules, assuming that we will concatenate with another
+ * word.
+ * A match means that the first part of CHECKCOMPOUNDPATTERN matches at the
+ * end of ptr[wlen] and the second part matches after it.
+ */
+ static int
+match_checkcompoundpattern(
+ char_u *ptr,
+ int wlen,
+ garray_T *gap) /* &sl_comppat */
+{
+ int i;
+ char_u *p;
+ int len;
+
+ for (i = 0; i + 1 < gap->ga_len; i += 2)
+ {
+ p = ((char_u **)gap->ga_data)[i + 1];
+ if (STRNCMP(ptr + wlen, p, STRLEN(p)) == 0)
+ {
+ /* Second part matches at start of following compound word, now
+ * check if first part matches at end of previous word. */
+ p = ((char_u **)gap->ga_data)[i];
+ len = (int)STRLEN(p);
+ if (len <= wlen && STRNCMP(ptr + wlen - len, p, len) == 0)
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/*
+ * Return TRUE if "flags" is a valid sequence of compound flags and "word"
+ * does not have too many syllables.
+ */
+ static int
+can_compound(slang_T *slang, char_u *word, char_u *flags)
+{
+ char_u uflags[MAXWLEN * 2];
+ int i;
+ char_u *p;
+
+ if (slang->sl_compprog == NULL)
+ return FALSE;
+ if (enc_utf8)
+ {
+ /* Need to convert the single byte flags to utf8 characters. */
+ p = uflags;
+ for (i = 0; flags[i] != NUL; ++i)
+ p += utf_char2bytes(flags[i], p);
+ *p = NUL;
+ p = uflags;
+ }
+ else
+ p = flags;
+ if (!vim_regexec_prog(&slang->sl_compprog, FALSE, p, 0))
+ return FALSE;
+
+ /* Count the number of syllables. This may be slow, do it last. If there
+ * are too many syllables AND the number of compound words is above
+ * COMPOUNDWORDMAX then compounding is not allowed. */
+ if (slang->sl_compsylmax < MAXWLEN
+ && count_syllables(slang, word) > slang->sl_compsylmax)
+ return (int)STRLEN(flags) < slang->sl_compmax;
+ return TRUE;
+}
+
+/*
+ * Return TRUE when the sequence of flags in "compflags" plus "flag" can
+ * possibly form a valid compounded word. This also checks the COMPOUNDRULE
+ * lines if they don't contain wildcards.
+ */
+ static int
+can_be_compound(
+ trystate_T *sp,
+ slang_T *slang,
+ char_u *compflags,
+ int flag)
+{
+ /* If the flag doesn't appear in sl_compstartflags or sl_compallflags
+ * then it can't possibly compound. */
+ if (!byte_in_str(sp->ts_complen == sp->ts_compsplit
+ ? slang->sl_compstartflags : slang->sl_compallflags, flag))
+ return FALSE;
+
+ /* If there are no wildcards, we can check if the flags collected so far
+ * possibly can form a match with COMPOUNDRULE patterns. This only
+ * makes sense when we have two or more words. */
+ if (slang->sl_comprules != NULL && sp->ts_complen > sp->ts_compsplit)
+ {
+ int v;
+
+ compflags[sp->ts_complen] = flag;
+ compflags[sp->ts_complen + 1] = NUL;
+ v = match_compoundrule(slang, compflags + sp->ts_compsplit);
+ compflags[sp->ts_complen] = NUL;
+ return v;
+ }
+
+ return TRUE;
+}
+
+
+/*
+ * Return TRUE if the compound flags in compflags[] match the start of any
+ * compound rule. This is used to stop trying a compound if the flags
+ * collected so far can't possibly match any compound rule.
+ * Caller must check that slang->sl_comprules is not NULL.
+ */
+ static int
+match_compoundrule(slang_T *slang, char_u *compflags)
+{
+ char_u *p;
+ int i;
+ int c;
+
+ /* loop over all the COMPOUNDRULE entries */
+ for (p = slang->sl_comprules; *p != NUL; ++p)
+ {
+ /* loop over the flags in the compound word we have made, match
+ * them against the current rule entry */
+ for (i = 0; ; ++i)
+ {
+ c = compflags[i];
+ if (c == NUL)
+ /* found a rule that matches for the flags we have so far */
+ return TRUE;
+ if (*p == '/' || *p == NUL)
+ break; /* end of rule, it's too short */
+ if (*p == '[')
+ {
+ int match = FALSE;
+
+ /* compare against all the flags in [] */
+ ++p;
+ while (*p != ']' && *p != NUL)
+ if (*p++ == c)
+ match = TRUE;
+ if (!match)
+ break; /* none matches */
+ }
+ else if (*p != c)
+ break; /* flag of word doesn't match flag in pattern */
+ ++p;
+ }
+
+ /* Skip to the next "/", where the next pattern starts. */
+ p = vim_strchr(p, '/');
+ if (p == NULL)
+ break;
+ }
+
+ /* Checked all the rules and none of them match the flags, so there
+ * can't possibly be a compound starting with these flags. */
+ return FALSE;
+}
+
+/*
+ * Return non-zero if the prefix indicated by "arridx" matches with the prefix
+ * ID in "flags" for the word "word".
+ * The WF_RAREPFX flag is included in the return value for a rare prefix.
+ */
+ static int
+valid_word_prefix(
+ int totprefcnt, /* nr of prefix IDs */
+ int arridx, /* idx in sl_pidxs[] */
+ int flags,
+ char_u *word,
+ slang_T *slang,
+ int cond_req) /* only use prefixes with a condition */
+{
+ int prefcnt;
+ int pidx;
+ regprog_T **rp;
+ int prefid;
+
+ prefid = (unsigned)flags >> 24;
+ for (prefcnt = totprefcnt - 1; prefcnt >= 0; --prefcnt)
+ {
+ pidx = slang->sl_pidxs[arridx + prefcnt];
+
+ /* Check the prefix ID. */
+ if (prefid != (pidx & 0xff))
+ continue;
+
+ /* Check if the prefix doesn't combine and the word already has a
+ * suffix. */
+ if ((flags & WF_HAS_AFF) && (pidx & WF_PFX_NC))
+ continue;
+
+ /* Check the condition, if there is one. The condition index is
+ * stored in the two bytes above the prefix ID byte. */
+ rp = &slang->sl_prefprog[((unsigned)pidx >> 8) & 0xffff];
+ if (*rp != NULL)
+ {
+ if (!vim_regexec_prog(rp, FALSE, word, 0))
+ continue;
+ }
+ else if (cond_req)
+ continue;
+
+ /* It's a match! Return the WF_ flags. */
+ return pidx;
+ }
+ return 0;
+}
+
+/*
+ * Check if the word at "mip->mi_word" has a matching prefix.
+ * If it does, then check the following word.
+ *
+ * If "mode" is "FIND_COMPOUND" then do the same after another word, find a
+ * prefix in a compound word.
+ *
+ * For a match mip->mi_result is updated.
+ */
+ static void
+find_prefix(matchinf_T *mip, int mode)
+{
+ idx_T arridx = 0;
+ int len;
+ int wlen = 0;
+ int flen;
+ int c;
+ char_u *ptr;
+ idx_T lo, hi, m;
+ slang_T *slang = mip->mi_lp->lp_slang;
+ char_u *byts;
+ idx_T *idxs;
+
+ byts = slang->sl_pbyts;
+ if (byts == NULL)
+ return; /* array is empty */
+
+ /* We use the case-folded word here, since prefixes are always
+ * case-folded. */
+ ptr = mip->mi_fword;
+ flen = mip->mi_fwordlen; /* available case-folded bytes */
+ if (mode == FIND_COMPOUND)
+ {
+ /* Skip over the previously found word(s). */
+ ptr += mip->mi_compoff;
+ flen -= mip->mi_compoff;
+ }
+ idxs = slang->sl_pidxs;
+
+ /*
+ * Repeat advancing in the tree until:
+ * - there is a byte that doesn't match,
+ * - we reach the end of the tree,
+ * - or we reach the end of the line.
+ */
+ for (;;)
+ {
+ if (flen == 0 && *mip->mi_fend != NUL)
+ flen = fold_more(mip);
+
+ len = byts[arridx++];
+
+ /* If the first possible byte is a zero the prefix could end here.
+ * Check if the following word matches and supports the prefix. */
+ if (byts[arridx] == 0)
+ {
+ /* There can be several prefixes with different conditions. We
+ * try them all, since we don't know which one will give the
+ * longest match. The word is the same each time, pass the list
+ * of possible prefixes to find_word(). */
+ mip->mi_prefarridx = arridx;
+ mip->mi_prefcnt = len;
+ while (len > 0 && byts[arridx] == 0)
+ {
+ ++arridx;
+ --len;
+ }
+ mip->mi_prefcnt -= len;
+
+ /* Find the word that comes after the prefix. */
+ mip->mi_prefixlen = wlen;
+ if (mode == FIND_COMPOUND)
+ /* Skip over the previously found word(s). */
+ mip->mi_prefixlen += mip->mi_compoff;
+
+ if (has_mbyte)
+ {
+ /* Case-folded length may differ from original length. */
+ mip->mi_cprefixlen = nofold_len(mip->mi_fword,
+ mip->mi_prefixlen, mip->mi_word);
+ }
+ else
+ mip->mi_cprefixlen = mip->mi_prefixlen;
+ find_word(mip, FIND_PREFIX);
+
+
+ if (len == 0)
+ break; /* no children, word must end here */
+ }
+
+ /* Stop looking at end of the line. */
+ if (ptr[wlen] == NUL)
+ break;
+
+ /* Perform a binary search in the list of accepted bytes. */
+ c = ptr[wlen];
+ lo = arridx;
+ hi = arridx + len - 1;
+ while (lo < hi)
+ {
+ m = (lo + hi) / 2;
+ if (byts[m] > c)
+ hi = m - 1;
+ else if (byts[m] < c)
+ lo = m + 1;
+ else
+ {
+ lo = hi = m;
+ break;
+ }
+ }
+
+ /* Stop if there is no matching byte. */
+ if (hi < lo || byts[lo] != c)
+ break;
+
+ /* Continue at the child (if there is one). */
+ arridx = idxs[lo];
+ ++wlen;
+ --flen;
+ }
+}
+
+/*
+ * Need to fold at least one more character. Do until next non-word character
+ * for efficiency. Include the non-word character too.
+ * Return the length of the folded chars in bytes.
+ */
+ static int
+fold_more(matchinf_T *mip)
+{
+ int flen;
+ char_u *p;
+
+ p = mip->mi_fend;
+ do
+ {
+ MB_PTR_ADV(mip->mi_fend);
+ } while (*mip->mi_fend != NUL && spell_iswordp(mip->mi_fend, mip->mi_win));
+
+ /* Include the non-word character so that we can check for the word end. */
+ if (*mip->mi_fend != NUL)
+ MB_PTR_ADV(mip->mi_fend);
+
+ (void)spell_casefold(p, (int)(mip->mi_fend - p),
+ mip->mi_fword + mip->mi_fwordlen,
+ MAXWLEN - mip->mi_fwordlen);
+ flen = (int)STRLEN(mip->mi_fword + mip->mi_fwordlen);
+ mip->mi_fwordlen += flen;
+ return flen;
+}
+
+/*
+ * Check case flags for a word. Return TRUE if the word has the requested
+ * case.
+ */
+ static int
+spell_valid_case(
+ int wordflags, /* flags for the checked word. */
+ int treeflags) /* flags for the word in the spell tree */
+{
+ return ((wordflags == WF_ALLCAP && (treeflags & WF_FIXCAP) == 0)
+ || ((treeflags & (WF_ALLCAP | WF_KEEPCAP)) == 0
+ && ((treeflags & WF_ONECAP) == 0
+ || (wordflags & WF_ONECAP) != 0)));
+}
+
+/*
+ * Return TRUE if spell checking is not enabled.
+ */
+ static int
+no_spell_checking(win_T *wp)
+{
+ if (!wp->w_p_spell || *wp->w_s->b_p_spl == NUL
+ || wp->w_s->b_langp.ga_len == 0)
+ {
+ emsg(_("E756: Spell checking is not enabled"));
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * Move to next spell error.
+ * "curline" is FALSE for "[s", "]s", "[S" and "]S".
+ * "curline" is TRUE to find word under/after cursor in the same line.
+ * For Insert mode completion "dir" is BACKWARD and "curline" is TRUE: move
+ * to after badly spelled word before the cursor.
+ * Return 0 if not found, length of the badly spelled word otherwise.
+ */
+ int
+spell_move_to(
+ win_T *wp,
+ int dir, /* FORWARD or BACKWARD */
+ int allwords, /* TRUE for "[s"/"]s", FALSE for "[S"/"]S" */
+ int curline,
+ hlf_T *attrp) /* return: attributes of bad word or NULL
+ (only when "dir" is FORWARD) */
+{
+ linenr_T lnum;
+ pos_T found_pos;
+ int found_len = 0;
+ char_u *line;
+ char_u *p;
+ char_u *endp;
+ hlf_T attr;
+ int len;
+#ifdef FEAT_SYN_HL
+ int has_syntax = syntax_present(wp);
+#endif
+ int col;
+ int can_spell;
+ char_u *buf = NULL;
+ int buflen = 0;
+ int skip = 0;
+ int capcol = -1;
+ int found_one = FALSE;
+ int wrapped = FALSE;
+
+ if (no_spell_checking(wp))
+ return 0;
+
+ /*
+ * Start looking for bad word at the start of the line, because we can't
+ * start halfway a word, we don't know where it starts or ends.
+ *
+ * When searching backwards, we continue in the line to find the last
+ * bad word (in the cursor line: before the cursor).
+ *
+ * We concatenate the start of the next line, so that wrapped words work
+ * (e.g. "et<line-break>cetera"). Doesn't work when searching backwards
+ * though...
+ */
+ lnum = wp->w_cursor.lnum;
+ CLEAR_POS(&found_pos);
+
+ while (!got_int)
+ {
+ line = ml_get_buf(wp->w_buffer, lnum, FALSE);
+
+ len = (int)STRLEN(line);
+ if (buflen < len + MAXWLEN + 2)
+ {
+ vim_free(buf);
+ buflen = len + MAXWLEN + 2;
+ buf = alloc(buflen);
+ if (buf == NULL)
+ break;
+ }
+
+ /* In first line check first word for Capital. */
+ if (lnum == 1)
+ capcol = 0;
+
+ /* For checking first word with a capital skip white space. */
+ if (capcol == 0)
+ capcol = getwhitecols(line);
+ else if (curline && wp == curwin)
+ {
+ /* For spellbadword(): check if first word needs a capital. */
+ col = getwhitecols(line);
+ if (check_need_cap(lnum, col))
+ capcol = col;
+
+ /* Need to get the line again, may have looked at the previous
+ * one. */
+ line = ml_get_buf(wp->w_buffer, lnum, FALSE);
+ }
+
+ /* Copy the line into "buf" and append the start of the next line if
+ * possible. */
+ STRCPY(buf, line);
+ if (lnum < wp->w_buffer->b_ml.ml_line_count)
+ spell_cat_line(buf + STRLEN(buf),
+ ml_get_buf(wp->w_buffer, lnum + 1, FALSE), MAXWLEN);
+
+ p = buf + skip;
+ endp = buf + len;
+ while (p < endp)
+ {
+ /* When searching backward don't search after the cursor. Unless
+ * we wrapped around the end of the buffer. */
+ if (dir == BACKWARD
+ && lnum == wp->w_cursor.lnum
+ && !wrapped
+ && (colnr_T)(p - buf) >= wp->w_cursor.col)
+ break;
+
+ /* start of word */
+ attr = HLF_COUNT;
+ len = spell_check(wp, p, &attr, &capcol, FALSE);
+
+ if (attr != HLF_COUNT)
+ {
+ /* We found a bad word. Check the attribute. */
+ if (allwords || attr == HLF_SPB)
+ {
+ /* When searching forward only accept a bad word after
+ * the cursor. */
+ if (dir == BACKWARD
+ || lnum != wp->w_cursor.lnum
+ || (lnum == wp->w_cursor.lnum
+ && (wrapped
+ || (colnr_T)(curline ? p - buf + len
+ : p - buf)
+ > wp->w_cursor.col)))
+ {
+#ifdef FEAT_SYN_HL
+ if (has_syntax)
+ {
+ col = (int)(p - buf);
+ (void)syn_get_id(wp, lnum, (colnr_T)col,
+ FALSE, &can_spell, FALSE);
+ if (!can_spell)
+ attr = HLF_COUNT;
+ }
+ else
+#endif
+ can_spell = TRUE;
+
+ if (can_spell)
+ {
+ found_one = TRUE;
+ found_pos.lnum = lnum;
+ found_pos.col = (int)(p - buf);
+ found_pos.coladd = 0;
+ if (dir == FORWARD)
+ {
+ /* No need to search further. */
+ wp->w_cursor = found_pos;
+ vim_free(buf);
+ if (attrp != NULL)
+ *attrp = attr;
+ return len;
+ }
+ else if (curline)
+ /* Insert mode completion: put cursor after
+ * the bad word. */
+ found_pos.col += len;
+ found_len = len;
+ }
+ }
+ else
+ found_one = TRUE;
+ }
+ }
+
+ /* advance to character after the word */
+ p += len;
+ capcol -= len;
+ }
+
+ if (dir == BACKWARD && found_pos.lnum != 0)
+ {
+ /* Use the last match in the line (before the cursor). */
+ wp->w_cursor = found_pos;
+ vim_free(buf);
+ return found_len;
+ }
+
+ if (curline)
+ break; /* only check cursor line */
+
+ /* If we are back at the starting line and searched it again there
+ * is no match, give up. */
+ if (lnum == wp->w_cursor.lnum && wrapped)
+ break;
+
+ /* Advance to next line. */
+ if (dir == BACKWARD)
+ {
+ if (lnum > 1)
+ --lnum;
+ else if (!p_ws)
+ break; /* at first line and 'nowrapscan' */
+ else
+ {
+ /* Wrap around to the end of the buffer. May search the
+ * starting line again and accept the last match. */
+ lnum = wp->w_buffer->b_ml.ml_line_count;
+ wrapped = TRUE;
+ if (!shortmess(SHM_SEARCH))
+ give_warning((char_u *)_(top_bot_msg), TRUE);
+ }
+ capcol = -1;
+ }
+ else
+ {
+ if (lnum < wp->w_buffer->b_ml.ml_line_count)
+ ++lnum;
+ else if (!p_ws)
+ break; /* at first line and 'nowrapscan' */
+ else
+ {
+ /* Wrap around to the start of the buffer. May search the
+ * starting line again and accept the first match. */
+ lnum = 1;
+ wrapped = TRUE;
+ if (!shortmess(SHM_SEARCH))
+ give_warning((char_u *)_(bot_top_msg), TRUE);
+ }
+
+ /* If we are back at the starting line and there is no match then
+ * give up. */
+ if (lnum == wp->w_cursor.lnum && !found_one)
+ break;
+
+ /* Skip the characters at the start of the next line that were
+ * included in a match crossing line boundaries. */
+ if (attr == HLF_COUNT)
+ skip = (int)(p - endp);
+ else
+ skip = 0;
+
+ /* Capcol skips over the inserted space. */
+ --capcol;
+
+ /* But after empty line check first word in next line */
+ if (*skipwhite(line) == NUL)
+ capcol = 0;
+ }
+
+ line_breakcheck();
+ }
+
+ vim_free(buf);
+ return 0;
+}
+
+/*
+ * For spell checking: concatenate the start of the following line "line" into
+ * "buf", blanking-out special characters. Copy less then "maxlen" bytes.
+ * Keep the blanks at the start of the next line, this is used in win_line()
+ * to skip those bytes if the word was OK.
+ */
+ void
+spell_cat_line(char_u *buf, char_u *line, int maxlen)
+{
+ char_u *p;
+ int n;
+
+ p = skipwhite(line);
+ while (vim_strchr((char_u *)"*#/\"\t", *p) != NULL)
+ p = skipwhite(p + 1);
+
+ if (*p != NUL)
+ {
+ /* Only worth concatenating if there is something else than spaces to
+ * concatenate. */
+ n = (int)(p - line) + 1;
+ if (n < maxlen - 1)
+ {
+ vim_memset(buf, ' ', n);
+ vim_strncpy(buf + n, p, maxlen - 1 - n);
+ }
+ }
+}
+
+/*
+ * Structure used for the cookie argument of do_in_runtimepath().
+ */
+typedef struct spelload_S
+{
+ char_u sl_lang[MAXWLEN + 1]; /* language name */
+ slang_T *sl_slang; /* resulting slang_T struct */
+ int sl_nobreak; /* NOBREAK language found */
+} spelload_T;
+
+/*
+ * Load word list(s) for "lang" from Vim spell file(s).
+ * "lang" must be the language without the region: e.g., "en".
+ */
+ static void
+spell_load_lang(char_u *lang)
+{
+ char_u fname_enc[85];
+ int r;
+ spelload_T sl;
+ int round;
+
+ /* Copy the language name to pass it to spell_load_cb() as a cookie.
+ * It's truncated when an error is detected. */
+ STRCPY(sl.sl_lang, lang);
+ sl.sl_slang = NULL;
+ sl.sl_nobreak = FALSE;
+
+ /* We may retry when no spell file is found for the language, an
+ * autocommand may load it then. */
+ for (round = 1; round <= 2; ++round)
+ {
+ /*
+ * Find the first spell file for "lang" in 'runtimepath' and load it.
+ */
+ vim_snprintf((char *)fname_enc, sizeof(fname_enc) - 5,
+#ifdef VMS
+ "spell/%s_%s.spl",
+#else
+ "spell/%s.%s.spl",
+#endif
+ lang, spell_enc());
+ r = do_in_runtimepath(fname_enc, 0, spell_load_cb, &sl);
+
+ if (r == FAIL && *sl.sl_lang != NUL)
+ {
+ /* Try loading the ASCII version. */
+ vim_snprintf((char *)fname_enc, sizeof(fname_enc) - 5,
+#ifdef VMS
+ "spell/%s_ascii.spl",
+#else
+ "spell/%s.ascii.spl",
+#endif
+ lang);
+ r = do_in_runtimepath(fname_enc, 0, spell_load_cb, &sl);
+
+ if (r == FAIL && *sl.sl_lang != NUL && round == 1
+ && apply_autocmds(EVENT_SPELLFILEMISSING, lang,
+ curbuf->b_fname, FALSE, curbuf))
+ continue;
+ break;
+ }
+ break;
+ }
+
+ if (r == FAIL)
+ {
+ smsg(
+#ifdef VMS
+ _("Warning: Cannot find word list \"%s_%s.spl\" or \"%s_ascii.spl\""),
+#else
+ _("Warning: Cannot find word list \"%s.%s.spl\" or \"%s.ascii.spl\""),
+#endif
+ lang, spell_enc(), lang);
+ }
+ else if (sl.sl_slang != NULL)
+ {
+ /* At least one file was loaded, now load ALL the additions. */
+ STRCPY(fname_enc + STRLEN(fname_enc) - 3, "add.spl");
+ do_in_runtimepath(fname_enc, DIP_ALL, spell_load_cb, &sl);
+ }
+}
+
+/*
+ * Return the encoding used for spell checking: Use 'encoding', except that we
+ * use "latin1" for "latin9". And limit to 60 characters (just in case).
+ */
+ char_u *
+spell_enc(void)
+{
+
+ if (STRLEN(p_enc) < 60 && STRCMP(p_enc, "iso-8859-15") != 0)
+ return p_enc;
+ return (char_u *)"latin1";
+}
+
+/*
+ * Get the name of the .spl file for the internal wordlist into
+ * "fname[MAXPATHL]".
+ */
+ static void
+int_wordlist_spl(char_u *fname)
+{
+ vim_snprintf((char *)fname, MAXPATHL, SPL_FNAME_TMPL,
+ int_wordlist, spell_enc());
+}
+
+/*
+ * Allocate a new slang_T for language "lang". "lang" can be NULL.
+ * Caller must fill "sl_next".
+ */
+ slang_T *
+slang_alloc(char_u *lang)
+{
+ slang_T *lp;
+
+ lp = (slang_T *)alloc_clear(sizeof(slang_T));
+ if (lp != NULL)
+ {
+ if (lang != NULL)
+ lp->sl_name = vim_strsave(lang);
+ ga_init2(&lp->sl_rep, sizeof(fromto_T), 10);
+ ga_init2(&lp->sl_repsal, sizeof(fromto_T), 10);
+ lp->sl_compmax = MAXWLEN;
+ lp->sl_compsylmax = MAXWLEN;
+ hash_init(&lp->sl_wordcount);
+ }
+
+ return lp;
+}
+
+/*
+ * Free the contents of an slang_T and the structure itself.
+ */
+ void
+slang_free(slang_T *lp)
+{
+ vim_free(lp->sl_name);
+ vim_free(lp->sl_fname);
+ slang_clear(lp);
+ vim_free(lp);
+}
+
+/*
+ * Clear an slang_T so that the file can be reloaded.
+ */
+ void
+slang_clear(slang_T *lp)
+{
+ garray_T *gap;
+ fromto_T *ftp;
+ salitem_T *smp;
+ int i;
+ int round;
+
+ VIM_CLEAR(lp->sl_fbyts);
+ VIM_CLEAR(lp->sl_kbyts);
+ VIM_CLEAR(lp->sl_pbyts);
+
+ VIM_CLEAR(lp->sl_fidxs);
+ VIM_CLEAR(lp->sl_kidxs);
+ VIM_CLEAR(lp->sl_pidxs);
+
+ for (round = 1; round <= 2; ++round)
+ {
+ gap = round == 1 ? &lp->sl_rep : &lp->sl_repsal;
+ while (gap->ga_len > 0)
+ {
+ ftp = &((fromto_T *)gap->ga_data)[--gap->ga_len];
+ vim_free(ftp->ft_from);
+ vim_free(ftp->ft_to);
+ }
+ ga_clear(gap);
+ }
+
+ gap = &lp->sl_sal;
+ if (lp->sl_sofo)
+ {
+ /* "ga_len" is set to 1 without adding an item for latin1 */
+ if (gap->ga_data != NULL)
+ /* SOFOFROM and SOFOTO items: free lists of wide characters. */
+ for (i = 0; i < gap->ga_len; ++i)
+ vim_free(((int **)gap->ga_data)[i]);
+ }
+ else
+ /* SAL items: free salitem_T items */
+ while (gap->ga_len > 0)
+ {
+ smp = &((salitem_T *)gap->ga_data)[--gap->ga_len];
+ vim_free(smp->sm_lead);
+ /* Don't free sm_oneof and sm_rules, they point into sm_lead. */
+ vim_free(smp->sm_to);
+ vim_free(smp->sm_lead_w);
+ vim_free(smp->sm_oneof_w);
+ vim_free(smp->sm_to_w);
+ }
+ ga_clear(gap);
+
+ for (i = 0; i < lp->sl_prefixcnt; ++i)
+ vim_regfree(lp->sl_prefprog[i]);
+ lp->sl_prefixcnt = 0;
+ VIM_CLEAR(lp->sl_prefprog);
+
+ VIM_CLEAR(lp->sl_info);
+
+ VIM_CLEAR(lp->sl_midword);
+
+ vim_regfree(lp->sl_compprog);
+ lp->sl_compprog = NULL;
+ VIM_CLEAR(lp->sl_comprules);
+ VIM_CLEAR(lp->sl_compstartflags);
+ VIM_CLEAR(lp->sl_compallflags);
+
+ VIM_CLEAR(lp->sl_syllable);
+ ga_clear(&lp->sl_syl_items);
+
+ ga_clear_strings(&lp->sl_comppat);
+
+ hash_clear_all(&lp->sl_wordcount, WC_KEY_OFF);
+ hash_init(&lp->sl_wordcount);
+
+ hash_clear_all(&lp->sl_map_hash, 0);
+
+ /* Clear info from .sug file. */
+ slang_clear_sug(lp);
+
+ lp->sl_compmax = MAXWLEN;
+ lp->sl_compminlen = 0;
+ lp->sl_compsylmax = MAXWLEN;
+ lp->sl_regions[0] = NUL;
+}
+
+/*
+ * Clear the info from the .sug file in "lp".
+ */
+ void
+slang_clear_sug(slang_T *lp)
+{
+ VIM_CLEAR(lp->sl_sbyts);
+ VIM_CLEAR(lp->sl_sidxs);
+ close_spellbuf(lp->sl_sugbuf);
+ lp->sl_sugbuf = NULL;
+ lp->sl_sugloaded = FALSE;
+ lp->sl_sugtime = 0;
+}
+
+/*
+ * Load one spell file and store the info into a slang_T.
+ * Invoked through do_in_runtimepath().
+ */
+ static void
+spell_load_cb(char_u *fname, void *cookie)
+{
+ spelload_T *slp = (spelload_T *)cookie;
+ slang_T *slang;
+
+ slang = spell_load_file(fname, slp->sl_lang, NULL, FALSE);
+ if (slang != NULL)
+ {
+ /* When a previously loaded file has NOBREAK also use it for the
+ * ".add" files. */
+ if (slp->sl_nobreak && slang->sl_add)
+ slang->sl_nobreak = TRUE;
+ else if (slang->sl_nobreak)
+ slp->sl_nobreak = TRUE;
+
+ slp->sl_slang = slang;
+ }
+}
+
+
+/*
+ * Add a word to the hashtable of common words.
+ * If it's already there then the counter is increased.
+ */
+ void
+count_common_word(
+ slang_T *lp,
+ char_u *word,
+ int len, /* word length, -1 for upto NUL */
+ int count) /* 1 to count once, 10 to init */
+{
+ hash_T hash;
+ hashitem_T *hi;
+ wordcount_T *wc;
+ char_u buf[MAXWLEN];
+ char_u *p;
+
+ if (len == -1)
+ p = word;
+ else
+ {
+ vim_strncpy(buf, word, len);
+ p = buf;
+ }
+
+ hash = hash_hash(p);
+ hi = hash_lookup(&lp->sl_wordcount, p, hash);
+ if (HASHITEM_EMPTY(hi))
+ {
+ wc = (wordcount_T *)alloc((unsigned)(sizeof(wordcount_T) + STRLEN(p)));
+ if (wc == NULL)
+ return;
+ STRCPY(wc->wc_word, p);
+ wc->wc_count = count;
+ hash_add_item(&lp->sl_wordcount, hi, wc->wc_word, hash);
+ }
+ else
+ {
+ wc = HI2WC(hi);
+ if ((wc->wc_count += count) < (unsigned)count) /* check for overflow */
+ wc->wc_count = MAXWORDCOUNT;
+ }
+}
+
+/*
+ * Adjust the score of common words.
+ */
+ static int
+score_wordcount_adj(
+ slang_T *slang,
+ int score,
+ char_u *word,
+ int split) /* word was split, less bonus */
+{
+ hashitem_T *hi;
+ wordcount_T *wc;
+ int bonus;
+ int newscore;
+
+ hi = hash_find(&slang->sl_wordcount, word);
+ if (!HASHITEM_EMPTY(hi))
+ {
+ wc = HI2WC(hi);
+ if (wc->wc_count < SCORE_THRES2)
+ bonus = SCORE_COMMON1;
+ else if (wc->wc_count < SCORE_THRES3)
+ bonus = SCORE_COMMON2;
+ else
+ bonus = SCORE_COMMON3;
+ if (split)
+ newscore = score - bonus / 2;
+ else
+ newscore = score - bonus;
+ if (newscore < 0)
+ return 0;
+ return newscore;
+ }
+ return score;
+}
+
+
+/*
+ * Return TRUE if byte "n" appears in "str".
+ * Like strchr() but independent of locale.
+ */
+ int
+byte_in_str(char_u *str, int n)
+{
+ char_u *p;
+
+ for (p = str; *p != NUL; ++p)
+ if (*p == n)
+ return TRUE;
+ return FALSE;
+}
+
+#define SY_MAXLEN 30
+typedef struct syl_item_S
+{
+ char_u sy_chars[SY_MAXLEN]; /* the sequence of chars */
+ int sy_len;
+} syl_item_T;
+
+/*
+ * Truncate "slang->sl_syllable" at the first slash and put the following items
+ * in "slang->sl_syl_items".
+ */
+ int
+init_syl_tab(slang_T *slang)
+{
+ char_u *p;
+ char_u *s;
+ int l;
+ syl_item_T *syl;
+
+ ga_init2(&slang->sl_syl_items, sizeof(syl_item_T), 4);
+ p = vim_strchr(slang->sl_syllable, '/');
+ while (p != NULL)
+ {
+ *p++ = NUL;
+ if (*p == NUL) /* trailing slash */
+ break;
+ s = p;
+ p = vim_strchr(p, '/');
+ if (p == NULL)
+ l = (int)STRLEN(s);
+ else
+ l = (int)(p - s);
+ if (l >= SY_MAXLEN)
+ return SP_FORMERROR;
+ if (ga_grow(&slang->sl_syl_items, 1) == FAIL)
+ return SP_OTHERERROR;
+ syl = ((syl_item_T *)slang->sl_syl_items.ga_data)
+ + slang->sl_syl_items.ga_len++;
+ vim_strncpy(syl->sy_chars, s, l);
+ syl->sy_len = l;
+ }
+ return OK;
+}
+
+/*
+ * Count the number of syllables in "word".
+ * When "word" contains spaces the syllables after the last space are counted.
+ * Returns zero if syllables are not defines.
+ */
+ static int
+count_syllables(slang_T *slang, char_u *word)
+{
+ int cnt = 0;
+ int skip = FALSE;
+ char_u *p;
+ int len;
+ int i;
+ syl_item_T *syl;
+ int c;
+
+ if (slang->sl_syllable == NULL)
+ return 0;
+
+ for (p = word; *p != NUL; p += len)
+ {
+ /* When running into a space reset counter. */
+ if (*p == ' ')
+ {
+ len = 1;
+ cnt = 0;
+ continue;
+ }
+
+ /* Find longest match of syllable items. */
+ len = 0;
+ for (i = 0; i < slang->sl_syl_items.ga_len; ++i)
+ {
+ syl = ((syl_item_T *)slang->sl_syl_items.ga_data) + i;
+ if (syl->sy_len > len
+ && STRNCMP(p, syl->sy_chars, syl->sy_len) == 0)
+ len = syl->sy_len;
+ }
+ if (len != 0) /* found a match, count syllable */
+ {
+ ++cnt;
+ skip = FALSE;
+ }
+ else
+ {
+ /* No recognized syllable item, at least a syllable char then? */
+ c = mb_ptr2char(p);
+ len = (*mb_ptr2len)(p);
+ if (vim_strchr(slang->sl_syllable, c) == NULL)
+ skip = FALSE; /* No, search for next syllable */
+ else if (!skip)
+ {
+ ++cnt; /* Yes, count it */
+ skip = TRUE; /* don't count following syllable chars */
+ }
+ }
+ }
+ return cnt;
+}
+
+/*
+ * Parse 'spelllang' and set w_s->b_langp accordingly.
+ * Returns NULL if it's OK, an error message otherwise.
+ */
+ char *
+did_set_spelllang(win_T *wp)
+{
+ garray_T ga;
+ char_u *splp;
+ char_u *region;
+ char_u region_cp[3];
+ int filename;
+ int region_mask;
+ slang_T *slang;
+ int c;
+ char_u lang[MAXWLEN + 1];
+ char_u spf_name[MAXPATHL];
+ int len;
+ char_u *p;
+ int round;
+ char_u *spf;
+ char_u *use_region = NULL;
+ int dont_use_region = FALSE;
+ int nobreak = FALSE;
+ int i, j;
+ langp_T *lp, *lp2;
+ static int recursive = FALSE;
+ char *ret_msg = NULL;
+ char_u *spl_copy;
+ bufref_T bufref;
+
+ set_bufref(&bufref, wp->w_buffer);
+
+ /* We don't want to do this recursively. May happen when a language is
+ * not available and the SpellFileMissing autocommand opens a new buffer
+ * in which 'spell' is set. */
+ if (recursive)
+ return NULL;
+ recursive = TRUE;
+
+ ga_init2(&ga, sizeof(langp_T), 2);
+ clear_midword(wp);
+
+ /* Make a copy of 'spelllang', the SpellFileMissing autocommands may change
+ * it under our fingers. */
+ spl_copy = vim_strsave(wp->w_s->b_p_spl);
+ if (spl_copy == NULL)
+ goto theend;
+
+ wp->w_s->b_cjk = 0;
+
+ /* Loop over comma separated language names. */
+ for (splp = spl_copy; *splp != NUL; )
+ {
+ /* Get one language name. */
+ copy_option_part(&splp, lang, MAXWLEN, ",");
+ region = NULL;
+ len = (int)STRLEN(lang);
+
+ if (STRCMP(lang, "cjk") == 0)
+ {
+ wp->w_s->b_cjk = 1;
+ continue;
+ }
+
+ /* If the name ends in ".spl" use it as the name of the spell file.
+ * If there is a region name let "region" point to it and remove it
+ * from the name. */
+ if (len > 4 && fnamecmp(lang + len - 4, ".spl") == 0)
+ {
+ filename = TRUE;
+
+ /* Locate a region and remove it from the file name. */
+ p = vim_strchr(gettail(lang), '_');
+ if (p != NULL && ASCII_ISALPHA(p[1]) && ASCII_ISALPHA(p[2])
+ && !ASCII_ISALPHA(p[3]))
+ {
+ vim_strncpy(region_cp, p + 1, 2);
+ mch_memmove(p, p + 3, len - (p - lang) - 2);
+ region = region_cp;
+ }
+ else
+ dont_use_region = TRUE;
+
+ /* Check if we loaded this language before. */
+ for (slang = first_lang; slang != NULL; slang = slang->sl_next)
+ if (fullpathcmp(lang, slang->sl_fname, FALSE) == FPC_SAME)
+ break;
+ }
+ else
+ {
+ filename = FALSE;
+ if (len > 3 && lang[len - 3] == '_')
+ {
+ region = lang + len - 2;
+ len -= 3;
+ lang[len] = NUL;
+ }
+ else
+ dont_use_region = TRUE;
+
+ /* Check if we loaded this language before. */
+ for (slang = first_lang; slang != NULL; slang = slang->sl_next)
+ if (STRICMP(lang, slang->sl_name) == 0)
+ break;
+ }
+
+ if (region != NULL)
+ {
+ /* If the region differs from what was used before then don't
+ * use it for 'spellfile'. */
+ if (use_region != NULL && STRCMP(region, use_region) != 0)
+ dont_use_region = TRUE;
+ use_region = region;
+ }
+
+ /* If not found try loading the language now. */
+ if (slang == NULL)
+ {
+ if (filename)
+ (void)spell_load_file(lang, lang, NULL, FALSE);
+ else
+ {
+ spell_load_lang(lang);
+ /* SpellFileMissing autocommands may do anything, including
+ * destroying the buffer we are using... */
+ if (!bufref_valid(&bufref))
+ {
+ ret_msg = N_("E797: SpellFileMissing autocommand deleted buffer");
+ goto theend;
+ }
+ }
+ }
+
+ /*
+ * Loop over the languages, there can be several files for "lang".
+ */
+ for (slang = first_lang; slang != NULL; slang = slang->sl_next)
+ if (filename ? fullpathcmp(lang, slang->sl_fname, FALSE) == FPC_SAME
+ : STRICMP(lang, slang->sl_name) == 0)
+ {
+ region_mask = REGION_ALL;
+ if (!filename && region != NULL)
+ {
+ /* find region in sl_regions */
+ c = find_region(slang->sl_regions, region);
+ if (c == REGION_ALL)
+ {
+ if (slang->sl_add)
+ {
+ if (*slang->sl_regions != NUL)
+ /* This addition file is for other regions. */
+ region_mask = 0;
+ }
+ else
+ /* This is probably an error. Give a warning and
+ * accept the words anyway. */
+ smsg(_("Warning: region %s not supported"),
+ region);
+ }
+ else
+ region_mask = 1 << c;
+ }
+
+ if (region_mask != 0)
+ {
+ if (ga_grow(&ga, 1) == FAIL)
+ {
+ ga_clear(&ga);
+ ret_msg = e_outofmem;
+ goto theend;
+ }
+ LANGP_ENTRY(ga, ga.ga_len)->lp_slang = slang;
+ LANGP_ENTRY(ga, ga.ga_len)->lp_region = region_mask;
+ ++ga.ga_len;
+ use_midword(slang, wp);
+ if (slang->sl_nobreak)
+ nobreak = TRUE;
+ }
+ }
+ }
+
+ /* round 0: load int_wordlist, if possible.
+ * round 1: load first name in 'spellfile'.
+ * round 2: load second name in 'spellfile.
+ * etc. */
+ spf = curwin->w_s->b_p_spf;
+ for (round = 0; round == 0 || *spf != NUL; ++round)
+ {
+ if (round == 0)
+ {
+ /* Internal wordlist, if there is one. */
+ if (int_wordlist == NULL)
+ continue;
+ int_wordlist_spl(spf_name);
+ }
+ else
+ {
+ /* One entry in 'spellfile'. */
+ copy_option_part(&spf, spf_name, MAXPATHL - 5, ",");
+ STRCAT(spf_name, ".spl");
+
+ /* If it was already found above then skip it. */
+ for (c = 0; c < ga.ga_len; ++c)
+ {
+ p = LANGP_ENTRY(ga, c)->lp_slang->sl_fname;
+ if (p != NULL && fullpathcmp(spf_name, p, FALSE) == FPC_SAME)
+ break;
+ }
+ if (c < ga.ga_len)
+ continue;
+ }
+
+ /* Check if it was loaded already. */
+ for (slang = first_lang; slang != NULL; slang = slang->sl_next)
+ if (fullpathcmp(spf_name, slang->sl_fname, FALSE) == FPC_SAME)
+ break;
+ if (slang == NULL)
+ {
+ /* Not loaded, try loading it now. The language name includes the
+ * region name, the region is ignored otherwise. for int_wordlist
+ * use an arbitrary name. */
+ if (round == 0)
+ STRCPY(lang, "internal wordlist");
+ else
+ {
+ vim_strncpy(lang, gettail(spf_name), MAXWLEN);
+ p = vim_strchr(lang, '.');
+ if (p != NULL)
+ *p = NUL; /* truncate at ".encoding.add" */
+ }
+ slang = spell_load_file(spf_name, lang, NULL, TRUE);
+
+ /* If one of the languages has NOBREAK we assume the addition
+ * files also have this. */
+ if (slang != NULL && nobreak)
+ slang->sl_nobreak = TRUE;
+ }
+ if (slang != NULL && ga_grow(&ga, 1) == OK)
+ {
+ region_mask = REGION_ALL;
+ if (use_region != NULL && !dont_use_region)
+ {
+ /* find region in sl_regions */
+ c = find_region(slang->sl_regions, use_region);
+ if (c != REGION_ALL)
+ region_mask = 1 << c;
+ else if (*slang->sl_regions != NUL)
+ /* This spell file is for other regions. */
+ region_mask = 0;
+ }
+
+ if (region_mask != 0)
+ {
+ LANGP_ENTRY(ga, ga.ga_len)->lp_slang = slang;
+ LANGP_ENTRY(ga, ga.ga_len)->lp_sallang = NULL;
+ LANGP_ENTRY(ga, ga.ga_len)->lp_replang = NULL;
+ LANGP_ENTRY(ga, ga.ga_len)->lp_region = region_mask;
+ ++ga.ga_len;
+ use_midword(slang, wp);
+ }
+ }
+ }
+
+ /* Everything is fine, store the new b_langp value. */
+ ga_clear(&wp->w_s->b_langp);
+ wp->w_s->b_langp = ga;
+
+ /* For each language figure out what language to use for sound folding and
+ * REP items. If the language doesn't support it itself use another one
+ * with the same name. E.g. for "en-math" use "en". */
+ for (i = 0; i < ga.ga_len; ++i)
+ {
+ lp = LANGP_ENTRY(ga, i);
+
+ /* sound folding */
+ if (lp->lp_slang->sl_sal.ga_len > 0)
+ /* language does sound folding itself */
+ lp->lp_sallang = lp->lp_slang;
+ else
+ /* find first similar language that does sound folding */
+ for (j = 0; j < ga.ga_len; ++j)
+ {
+ lp2 = LANGP_ENTRY(ga, j);
+ if (lp2->lp_slang->sl_sal.ga_len > 0
+ && STRNCMP(lp->lp_slang->sl_name,
+ lp2->lp_slang->sl_name, 2) == 0)
+ {
+ lp->lp_sallang = lp2->lp_slang;
+ break;
+ }
+ }
+
+ /* REP items */
+ if (lp->lp_slang->sl_rep.ga_len > 0)
+ /* language has REP items itself */
+ lp->lp_replang = lp->lp_slang;
+ else
+ /* find first similar language that has REP items */
+ for (j = 0; j < ga.ga_len; ++j)
+ {
+ lp2 = LANGP_ENTRY(ga, j);
+ if (lp2->lp_slang->sl_rep.ga_len > 0
+ && STRNCMP(lp->lp_slang->sl_name,
+ lp2->lp_slang->sl_name, 2) == 0)
+ {
+ lp->lp_replang = lp2->lp_slang;
+ break;
+ }
+ }
+ }
+
+theend:
+ vim_free(spl_copy);
+ recursive = FALSE;
+ redraw_win_later(wp, NOT_VALID);
+ return ret_msg;
+}
+
+/*
+ * Clear the midword characters for buffer "buf".
+ */
+ static void
+clear_midword(win_T *wp)
+{
+ vim_memset(wp->w_s->b_spell_ismw, 0, 256);
+ VIM_CLEAR(wp->w_s->b_spell_ismw_mb);
+}
+
+/*
+ * Use the "sl_midword" field of language "lp" for buffer "buf".
+ * They add up to any currently used midword characters.
+ */
+ static void
+use_midword(slang_T *lp, win_T *wp)
+{
+ char_u *p;
+
+ if (lp->sl_midword == NULL) /* there aren't any */
+ return;
+
+ for (p = lp->sl_midword; *p != NUL; )
+ if (has_mbyte)
+ {
+ int c, l, n;
+ char_u *bp;
+
+ c = mb_ptr2char(p);
+ l = (*mb_ptr2len)(p);
+ if (c < 256 && l <= 2)
+ wp->w_s->b_spell_ismw[c] = TRUE;
+ else if (wp->w_s->b_spell_ismw_mb == NULL)
+ /* First multi-byte char in "b_spell_ismw_mb". */
+ wp->w_s->b_spell_ismw_mb = vim_strnsave(p, l);
+ else
+ {
+ /* Append multi-byte chars to "b_spell_ismw_mb". */
+ n = (int)STRLEN(wp->w_s->b_spell_ismw_mb);
+ bp = vim_strnsave(wp->w_s->b_spell_ismw_mb, n + l);
+ if (bp != NULL)
+ {
+ vim_free(wp->w_s->b_spell_ismw_mb);
+ wp->w_s->b_spell_ismw_mb = bp;
+ vim_strncpy(bp + n, p, l);
+ }
+ }
+ p += l;
+ }
+ else
+ wp->w_s->b_spell_ismw[*p++] = TRUE;
+}
+
+/*
+ * Find the region "region[2]" in "rp" (points to "sl_regions").
+ * Each region is simply stored as the two characters of its name.
+ * Returns the index if found (first is 0), REGION_ALL if not found.
+ */
+ static int
+find_region(char_u *rp, char_u *region)
+{
+ int i;
+
+ for (i = 0; ; i += 2)
+ {
+ if (rp[i] == NUL)
+ return REGION_ALL;
+ if (rp[i] == region[0] && rp[i + 1] == region[1])
+ break;
+ }
+ return i / 2;
+}
+
+/*
+ * Return case type of word:
+ * w word 0
+ * Word WF_ONECAP
+ * W WORD WF_ALLCAP
+ * WoRd wOrd WF_KEEPCAP
+ */
+ int
+captype(
+ char_u *word,
+ char_u *end) /* When NULL use up to NUL byte. */
+{
+ char_u *p;
+ int c;
+ int firstcap;
+ int allcap;
+ int past_second = FALSE; /* past second word char */
+
+ /* find first letter */
+ for (p = word; !spell_iswordp_nmw(p, curwin); MB_PTR_ADV(p))
+ if (end == NULL ? *p == NUL : p >= end)
+ return 0; /* only non-word characters, illegal word */
+ if (has_mbyte)
+ c = mb_ptr2char_adv(&p);
+ else
+ c = *p++;
+ firstcap = allcap = SPELL_ISUPPER(c);
+
+ /*
+ * Need to check all letters to find a word with mixed upper/lower.
+ * But a word with an upper char only at start is a ONECAP.
+ */
+ for ( ; end == NULL ? *p != NUL : p < end; MB_PTR_ADV(p))
+ if (spell_iswordp_nmw(p, curwin))
+ {
+ c = PTR2CHAR(p);
+ if (!SPELL_ISUPPER(c))
+ {
+ /* UUl -> KEEPCAP */
+ if (past_second && allcap)
+ return WF_KEEPCAP;
+ allcap = FALSE;
+ }
+ else if (!allcap)
+ /* UlU -> KEEPCAP */
+ return WF_KEEPCAP;
+ past_second = TRUE;
+ }
+
+ if (allcap)
+ return WF_ALLCAP;
+ if (firstcap)
+ return WF_ONECAP;
+ return 0;
+}
+
+/*
+ * Like captype() but for a KEEPCAP word add ONECAP if the word starts with a
+ * capital. So that make_case_word() can turn WOrd into Word.
+ * Add ALLCAP for "WOrD".
+ */
+ static int
+badword_captype(char_u *word, char_u *end)
+{
+ int flags = captype(word, end);
+ int c;
+ int l, u;
+ int first;
+ char_u *p;
+
+ if (flags & WF_KEEPCAP)
+ {
+ /* Count the number of UPPER and lower case letters. */
+ l = u = 0;
+ first = FALSE;
+ for (p = word; p < end; MB_PTR_ADV(p))
+ {
+ c = PTR2CHAR(p);
+ if (SPELL_ISUPPER(c))
+ {
+ ++u;
+ if (p == word)
+ first = TRUE;
+ }
+ else
+ ++l;
+ }
+
+ /* If there are more UPPER than lower case letters suggest an
+ * ALLCAP word. Otherwise, if the first letter is UPPER then
+ * suggest ONECAP. Exception: "ALl" most likely should be "All",
+ * require three upper case letters. */
+ if (u > l && u > 2)
+ flags |= WF_ALLCAP;
+ else if (first)
+ flags |= WF_ONECAP;
+
+ if (u >= 2 && l >= 2) /* maCARONI maCAroni */
+ flags |= WF_MIXCAP;
+ }
+ return flags;
+}
+
+/*
+ * Delete the internal wordlist and its .spl file.
+ */
+ void
+spell_delete_wordlist(void)
+{
+ char_u fname[MAXPATHL];
+
+ if (int_wordlist != NULL)
+ {
+ mch_remove(int_wordlist);
+ int_wordlist_spl(fname);
+ mch_remove(fname);
+ VIM_CLEAR(int_wordlist);
+ }
+}
+
+/*
+ * Free all languages.
+ */
+ void
+spell_free_all(void)
+{
+ slang_T *slang;
+ buf_T *buf;
+
+ /* Go through all buffers and handle 'spelllang'. <VN> */
+ FOR_ALL_BUFFERS(buf)
+ ga_clear(&buf->b_s.b_langp);
+
+ while (first_lang != NULL)
+ {
+ slang = first_lang;
+ first_lang = slang->sl_next;
+ slang_free(slang);
+ }
+
+ spell_delete_wordlist();
+
+ VIM_CLEAR(repl_to);
+ VIM_CLEAR(repl_from);
+}
+
+/*
+ * Clear all spelling tables and reload them.
+ * Used after 'encoding' is set and when ":mkspell" was used.
+ */
+ void
+spell_reload(void)
+{
+ win_T *wp;
+
+ /* Initialize the table for spell_iswordp(). */
+ init_spell_chartab();
+
+ /* Unload all allocated memory. */
+ spell_free_all();
+
+ /* Go through all buffers and handle 'spelllang'. */
+ FOR_ALL_WINDOWS(wp)
+ {
+ /* Only load the wordlists when 'spelllang' is set and there is a
+ * window for this buffer in which 'spell' is set. */
+ if (*wp->w_s->b_p_spl != NUL)
+ {
+ if (wp->w_p_spell)
+ {
+ (void)did_set_spelllang(wp);
+ break;
+ }
+ }
+ }
+}
+
+/*
+ * Opposite of offset2bytes().
+ * "pp" points to the bytes and is advanced over it.
+ * Returns the offset.
+ */
+ static int
+bytes2offset(char_u **pp)
+{
+ char_u *p = *pp;
+ int nr;
+ int c;
+
+ c = *p++;
+ if ((c & 0x80) == 0x00) /* 1 byte */
+ {
+ nr = c - 1;
+ }
+ else if ((c & 0xc0) == 0x80) /* 2 bytes */
+ {
+ nr = (c & 0x3f) - 1;
+ nr = nr * 255 + (*p++ - 1);
+ }
+ else if ((c & 0xe0) == 0xc0) /* 3 bytes */
+ {
+ nr = (c & 0x1f) - 1;
+ nr = nr * 255 + (*p++ - 1);
+ nr = nr * 255 + (*p++ - 1);
+ }
+ else /* 4 bytes */
+ {
+ nr = (c & 0x0f) - 1;
+ nr = nr * 255 + (*p++ - 1);
+ nr = nr * 255 + (*p++ - 1);
+ nr = nr * 255 + (*p++ - 1);
+ }
+
+ *pp = p;
+ return nr;
+}
+
+
+/*
+ * Open a spell buffer. This is a nameless buffer that is not in the buffer
+ * list and only contains text lines. Can use a swapfile to reduce memory
+ * use.
+ * Most other fields are invalid! Esp. watch out for string options being
+ * NULL and there is no undo info.
+ * Returns NULL when out of memory.
+ */
+ buf_T *
+open_spellbuf(void)
+{
+ buf_T *buf;
+
+ buf = (buf_T *)alloc_clear(sizeof(buf_T));
+ if (buf != NULL)
+ {
+ buf->b_spell = TRUE;
+ buf->b_p_swf = TRUE; /* may create a swap file */
+#ifdef FEAT_CRYPT
+ buf->b_p_key = empty_option;
+#endif
+ ml_open(buf);
+ ml_open_file(buf); /* create swap file now */
+ }
+ return buf;
+}
+
+/*
+ * Close the buffer used for spell info.
+ */
+ void
+close_spellbuf(buf_T *buf)
+{
+ if (buf != NULL)
+ {
+ ml_close(buf, TRUE);
+ vim_free(buf);
+ }
+}
+
+/*
+ * Init the chartab used for spelling for ASCII.
+ * EBCDIC is not supported!
+ */
+ void
+clear_spell_chartab(spelltab_T *sp)
+{
+ int i;
+
+ /* Init everything to FALSE. */
+ vim_memset(sp->st_isw, FALSE, sizeof(sp->st_isw));
+ vim_memset(sp->st_isu, FALSE, sizeof(sp->st_isu));
+ for (i = 0; i < 256; ++i)
+ {
+ sp->st_fold[i] = i;
+ sp->st_upper[i] = i;
+ }
+
+ /* We include digits. A word shouldn't start with a digit, but handling
+ * that is done separately. */
+ for (i = '0'; i <= '9'; ++i)
+ sp->st_isw[i] = TRUE;
+ for (i = 'A'; i <= 'Z'; ++i)
+ {
+ sp->st_isw[i] = TRUE;
+ sp->st_isu[i] = TRUE;
+ sp->st_fold[i] = i + 0x20;
+ }
+ for (i = 'a'; i <= 'z'; ++i)
+ {
+ sp->st_isw[i] = TRUE;
+ sp->st_upper[i] = i - 0x20;
+ }
+}
+
+/*
+ * Init the chartab used for spelling. Only depends on 'encoding'.
+ * Called once while starting up and when 'encoding' changes.
+ * The default is to use isalpha(), but the spell file should define the word
+ * characters to make it possible that 'encoding' differs from the current
+ * locale. For utf-8 we don't use isalpha() but our own functions.
+ */
+ void
+init_spell_chartab(void)
+{
+ int i;
+
+ did_set_spelltab = FALSE;
+ clear_spell_chartab(&spelltab);
+ if (enc_dbcs)
+ {
+ /* DBCS: assume double-wide characters are word characters. */
+ for (i = 128; i <= 255; ++i)
+ if (MB_BYTE2LEN(i) == 2)
+ spelltab.st_isw[i] = TRUE;
+ }
+ else if (enc_utf8)
+ {
+ for (i = 128; i < 256; ++i)
+ {
+ int f = utf_fold(i);
+ int u = utf_toupper(i);
+
+ spelltab.st_isu[i] = utf_isupper(i);
+ spelltab.st_isw[i] = spelltab.st_isu[i] || utf_islower(i);
+ /* The folded/upper-cased value is different between latin1 and
+ * utf8 for 0xb5, causing E763 for no good reason. Use the latin1
+ * value for utf-8 to avoid this. */
+ spelltab.st_fold[i] = (f < 256) ? f : i;
+ spelltab.st_upper[i] = (u < 256) ? u : i;
+ }
+ }
+ else
+ {
+ /* Rough guess: use locale-dependent library functions. */
+ for (i = 128; i < 256; ++i)
+ {
+ if (MB_ISUPPER(i))
+ {
+ spelltab.st_isw[i] = TRUE;
+ spelltab.st_isu[i] = TRUE;
+ spelltab.st_fold[i] = MB_TOLOWER(i);
+ }
+ else if (MB_ISLOWER(i))
+ {
+ spelltab.st_isw[i] = TRUE;
+ spelltab.st_upper[i] = MB_TOUPPER(i);
+ }
+ }
+ }
+}
+
+
+/*
+ * Return TRUE if "p" points to a word character.
+ * As a special case we see "midword" characters as word character when it is
+ * followed by a word character. This finds they'there but not 'they there'.
+ * Thus this only works properly when past the first character of the word.
+ */
+ static int
+spell_iswordp(
+ char_u *p,
+ win_T *wp) /* buffer used */
+{
+ char_u *s;
+ int l;
+ int c;
+
+ if (has_mbyte)
+ {
+ l = MB_PTR2LEN(p);
+ s = p;
+ if (l == 1)
+ {
+ /* be quick for ASCII */
+ if (wp->w_s->b_spell_ismw[*p])
+ s = p + 1; /* skip a mid-word character */
+ }
+ else
+ {
+ c = mb_ptr2char(p);
+ if (c < 256 ? wp->w_s->b_spell_ismw[c]
+ : (wp->w_s->b_spell_ismw_mb != NULL
+ && vim_strchr(wp->w_s->b_spell_ismw_mb, c) != NULL))
+ s = p + l;
+ }
+
+ c = mb_ptr2char(s);
+ if (c > 255)
+ return spell_mb_isword_class(mb_get_class(s), wp);
+ return spelltab.st_isw[c];
+ }
+
+ return spelltab.st_isw[wp->w_s->b_spell_ismw[*p] ? p[1] : p[0]];
+}
+
+/*
+ * Return TRUE if "p" points to a word character.
+ * Unlike spell_iswordp() this doesn't check for "midword" characters.
+ */
+ int
+spell_iswordp_nmw(char_u *p, win_T *wp)
+{
+ int c;
+
+ if (has_mbyte)
+ {
+ c = mb_ptr2char(p);
+ if (c > 255)
+ return spell_mb_isword_class(mb_get_class(p), wp);
+ return spelltab.st_isw[c];
+ }
+ return spelltab.st_isw[*p];
+}
+
+/*
+ * Return TRUE if word class indicates a word character.
+ * Only for characters above 255.
+ * Unicode subscript and superscript are not considered word characters.
+ * See also dbcs_class() and utf_class() in mbyte.c.
+ */
+ static int
+spell_mb_isword_class(int cl, win_T *wp)
+{
+ if (wp->w_s->b_cjk)
+ /* East Asian characters are not considered word characters. */
+ return cl == 2 || cl == 0x2800;
+ return cl >= 2 && cl != 0x2070 && cl != 0x2080;
+}
+
+/*
+ * Return TRUE if "p" points to a word character.
+ * Wide version of spell_iswordp().
+ */
+ static int
+spell_iswordp_w(int *p, win_T *wp)
+{
+ int *s;
+
+ if (*p < 256 ? wp->w_s->b_spell_ismw[*p]
+ : (wp->w_s->b_spell_ismw_mb != NULL
+ && vim_strchr(wp->w_s->b_spell_ismw_mb, *p) != NULL))
+ s = p + 1;
+ else
+ s = p;
+
+ if (*s > 255)
+ {
+ if (enc_utf8)
+ return spell_mb_isword_class(utf_class(*s), wp);
+ if (enc_dbcs)
+ return spell_mb_isword_class(
+ dbcs_class((unsigned)*s >> 8, *s & 0xff), wp);
+ return 0;
+ }
+ return spelltab.st_isw[*s];
+}
+
+/*
+ * Case-fold "str[len]" into "buf[buflen]". The result is NUL terminated.
+ * Uses the character definitions from the .spl file.
+ * When using a multi-byte 'encoding' the length may change!
+ * Returns FAIL when something wrong.
+ */
+ int
+spell_casefold(
+ char_u *str,
+ int len,
+ char_u *buf,
+ int buflen)
+{
+ int i;
+
+ if (len >= buflen)
+ {
+ buf[0] = NUL;
+ return FAIL; /* result will not fit */
+ }
+
+ if (has_mbyte)
+ {
+ int outi = 0;
+ char_u *p;
+ int c;
+
+ /* Fold one character at a time. */
+ for (p = str; p < str + len; )
+ {
+ if (outi + MB_MAXBYTES > buflen)
+ {
+ buf[outi] = NUL;
+ return FAIL;
+ }
+ c = mb_cptr2char_adv(&p);
+ outi += mb_char2bytes(SPELL_TOFOLD(c), buf + outi);
+ }
+ buf[outi] = NUL;
+ }
+ else
+ {
+ /* Be quick for non-multibyte encodings. */
+ for (i = 0; i < len; ++i)
+ buf[i] = spelltab.st_fold[str[i]];
+ buf[i] = NUL;
+ }
+
+ return OK;
+}
+
+/* values for sps_flags */
+#define SPS_BEST 1
+#define SPS_FAST 2
+#define SPS_DOUBLE 4
+
+static int sps_flags = SPS_BEST; /* flags from 'spellsuggest' */
+static int sps_limit = 9999; /* max nr of suggestions given */
+
+/*
+ * Check the 'spellsuggest' option. Return FAIL if it's wrong.
+ * Sets "sps_flags" and "sps_limit".
+ */
+ int
+spell_check_sps(void)
+{
+ char_u *p;
+ char_u *s;
+ char_u buf[MAXPATHL];
+ int f;
+
+ sps_flags = 0;
+ sps_limit = 9999;
+
+ for (p = p_sps; *p != NUL; )
+ {
+ copy_option_part(&p, buf, MAXPATHL, ",");
+
+ f = 0;
+ if (VIM_ISDIGIT(*buf))
+ {
+ s = buf;
+ sps_limit = getdigits(&s);
+ if (*s != NUL && !VIM_ISDIGIT(*s))
+ f = -1;
+ }
+ else if (STRCMP(buf, "best") == 0)
+ f = SPS_BEST;
+ else if (STRCMP(buf, "fast") == 0)
+ f = SPS_FAST;
+ else if (STRCMP(buf, "double") == 0)
+ f = SPS_DOUBLE;
+ else if (STRNCMP(buf, "expr:", 5) != 0
+ && STRNCMP(buf, "file:", 5) != 0)
+ f = -1;
+
+ if (f == -1 || (sps_flags != 0 && f != 0))
+ {
+ sps_flags = SPS_BEST;
+ sps_limit = 9999;
+ return FAIL;
+ }
+ if (f != 0)
+ sps_flags = f;
+ }
+
+ if (sps_flags == 0)
+ sps_flags = SPS_BEST;
+
+ return OK;
+}
+
+/*
+ * "z=": Find badly spelled word under or after the cursor.
+ * Give suggestions for the properly spelled word.
+ * In Visual mode use the highlighted word as the bad word.
+ * When "count" is non-zero use that suggestion.
+ */
+ void
+spell_suggest(int count)
+{
+ char_u *line;
+ pos_T prev_cursor = curwin->w_cursor;
+ char_u wcopy[MAXWLEN + 2];
+ char_u *p;
+ int i;
+ int c;
+ suginfo_T sug;
+ suggest_T *stp;
+ int mouse_used;
+ int need_cap;
+ int limit;
+ int selected = count;
+ int badlen = 0;
+ int msg_scroll_save = msg_scroll;
+
+ if (no_spell_checking(curwin))
+ return;
+
+ if (VIsual_active)
+ {
+ /* Use the Visually selected text as the bad word. But reject
+ * a multi-line selection. */
+ if (curwin->w_cursor.lnum != VIsual.lnum)
+ {
+ vim_beep(BO_SPELL);
+ return;
+ }
+ badlen = (int)curwin->w_cursor.col - (int)VIsual.col;
+ if (badlen < 0)
+ badlen = -badlen;
+ else
+ curwin->w_cursor.col = VIsual.col;
+ ++badlen;
+ end_visual_mode();
+ }
+ /* Find the start of the badly spelled word. */
+ else if (spell_move_to(curwin, FORWARD, TRUE, TRUE, NULL) == 0
+ || curwin->w_cursor.col > prev_cursor.col)
+ {
+ /* No bad word or it starts after the cursor: use the word under the
+ * cursor. */
+ curwin->w_cursor = prev_cursor;
+ line = ml_get_curline();
+ p = line + curwin->w_cursor.col;
+ /* Backup to before start of word. */
+ while (p > line && spell_iswordp_nmw(p, curwin))
+ MB_PTR_BACK(line, p);
+ /* Forward to start of word. */
+ while (*p != NUL && !spell_iswordp_nmw(p, curwin))
+ MB_PTR_ADV(p);
+
+ if (!spell_iswordp_nmw(p, curwin)) /* No word found. */
+ {
+ beep_flush();
+ return;
+ }
+ curwin->w_cursor.col = (colnr_T)(p - line);
+ }
+
+ /* Get the word and its length. */
+
+ /* Figure out if the word should be capitalised. */
+ need_cap = check_need_cap(curwin->w_cursor.lnum, curwin->w_cursor.col);
+
+ /* Make a copy of current line since autocommands may free the line. */
+ line = vim_strsave(ml_get_curline());
+ if (line == NULL)
+ goto skip;
+
+ /* Get the list of suggestions. Limit to 'lines' - 2 or the number in
+ * 'spellsuggest', whatever is smaller. */
+ if (sps_limit > (int)Rows - 2)
+ limit = (int)Rows - 2;
+ else
+ limit = sps_limit;
+ spell_find_suggest(line + curwin->w_cursor.col, badlen, &sug, limit,
+ TRUE, need_cap, TRUE);
+
+ if (sug.su_ga.ga_len == 0)
+ msg(_("Sorry, no suggestions"));
+ else if (count > 0)
+ {
+ if (count > sug.su_ga.ga_len)
+ smsg(_("Sorry, only %ld suggestions"),
+ (long)sug.su_ga.ga_len);
+ }
+ else
+ {
+ VIM_CLEAR(repl_from);
+ VIM_CLEAR(repl_to);
+
+#ifdef FEAT_RIGHTLEFT
+ /* When 'rightleft' is set the list is drawn right-left. */
+ cmdmsg_rl = curwin->w_p_rl;
+ if (cmdmsg_rl)
+ msg_col = Columns - 1;
+#endif
+
+ /* List the suggestions. */
+ msg_start();
+ msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
+ lines_left = Rows; /* avoid more prompt */
+ vim_snprintf((char *)IObuff, IOSIZE, _("Change \"%.*s\" to:"),
+ sug.su_badlen, sug.su_badptr);
+#ifdef FEAT_RIGHTLEFT
+ if (cmdmsg_rl && STRNCMP(IObuff, "Change", 6) == 0)
+ {
+ /* And now the rabbit from the high hat: Avoid showing the
+ * untranslated message rightleft. */
+ vim_snprintf((char *)IObuff, IOSIZE, ":ot \"%.*s\" egnahC",
+ sug.su_badlen, sug.su_badptr);
+ }
+#endif
+ msg_puts((char *)IObuff);
+ msg_clr_eos();
+ msg_putchar('\n');
+
+ msg_scroll = TRUE;
+ for (i = 0; i < sug.su_ga.ga_len; ++i)
+ {
+ stp = &SUG(sug.su_ga, i);
+
+ /* The suggested word may replace only part of the bad word, add
+ * the not replaced part. */
+ vim_strncpy(wcopy, stp->st_word, MAXWLEN);
+ if (sug.su_badlen > stp->st_orglen)
+ vim_strncpy(wcopy + stp->st_wordlen,
+ sug.su_badptr + stp->st_orglen,
+ sug.su_badlen - stp->st_orglen);
+ vim_snprintf((char *)IObuff, IOSIZE, "%2d", i + 1);
+#ifdef FEAT_RIGHTLEFT
+ if (cmdmsg_rl)
+ rl_mirror(IObuff);
+#endif
+ msg_puts((char *)IObuff);
+
+ vim_snprintf((char *)IObuff, IOSIZE, " \"%s\"", wcopy);
+ msg_puts((char *)IObuff);
+
+ /* The word may replace more than "su_badlen". */
+ if (sug.su_badlen < stp->st_orglen)
+ {
+ vim_snprintf((char *)IObuff, IOSIZE, _(" < \"%.*s\""),
+ stp->st_orglen, sug.su_badptr);
+ msg_puts((char *)IObuff);
+ }
+
+ if (p_verbose > 0)
+ {
+ /* Add the score. */
+ if (sps_flags & (SPS_DOUBLE | SPS_BEST))
+ vim_snprintf((char *)IObuff, IOSIZE, " (%s%d - %d)",
+ stp->st_salscore ? "s " : "",
+ stp->st_score, stp->st_altscore);
+ else
+ vim_snprintf((char *)IObuff, IOSIZE, " (%d)",
+ stp->st_score);
+#ifdef FEAT_RIGHTLEFT
+ if (cmdmsg_rl)
+ /* Mirror the numbers, but keep the leading space. */
+ rl_mirror(IObuff + 1);
+#endif
+ msg_advance(30);
+ msg_puts((char *)IObuff);
+ }
+ msg_putchar('\n');
+ }
+
+#ifdef FEAT_RIGHTLEFT
+ cmdmsg_rl = FALSE;
+ msg_col = 0;
+#endif
+ /* Ask for choice. */
+ selected = prompt_for_number(&mouse_used);
+ if (mouse_used)
+ selected -= lines_left;
+ lines_left = Rows; /* avoid more prompt */
+ /* don't delay for 'smd' in normal_cmd() */
+ msg_scroll = msg_scroll_save;
+ }
+
+ if (selected > 0 && selected <= sug.su_ga.ga_len && u_save_cursor() == OK)
+ {
+ /* Save the from and to text for :spellrepall. */
+ stp = &SUG(sug.su_ga, selected - 1);
+ if (sug.su_badlen > stp->st_orglen)
+ {
+ /* Replacing less than "su_badlen", append the remainder to
+ * repl_to. */
+ repl_from = vim_strnsave(sug.su_badptr, sug.su_badlen);
+ vim_snprintf((char *)IObuff, IOSIZE, "%s%.*s", stp->st_word,
+ sug.su_badlen - stp->st_orglen,
+ sug.su_badptr + stp->st_orglen);
+ repl_to = vim_strsave(IObuff);
+ }
+ else
+ {
+ /* Replacing su_badlen or more, use the whole word. */
+ repl_from = vim_strnsave(sug.su_badptr, stp->st_orglen);
+ repl_to = vim_strsave(stp->st_word);
+ }
+
+ /* Replace the word. */
+ p = alloc((unsigned)STRLEN(line) - stp->st_orglen
+ + stp->st_wordlen + 1);
+ if (p != NULL)
+ {
+ c = (int)(sug.su_badptr - line);
+ mch_memmove(p, line, c);
+ STRCPY(p + c, stp->st_word);
+ STRCAT(p, sug.su_badptr + stp->st_orglen);
+ ml_replace(curwin->w_cursor.lnum, p, FALSE);
+ curwin->w_cursor.col = c;
+
+ /* For redo we use a change-word command. */
+ ResetRedobuff();
+ AppendToRedobuff((char_u *)"ciw");
+ AppendToRedobuffLit(p + c,
+ stp->st_wordlen + sug.su_badlen - stp->st_orglen);
+ AppendCharToRedobuff(ESC);
+
+ /* After this "p" may be invalid. */
+ changed_bytes(curwin->w_cursor.lnum, c);
+ }
+ }
+ else
+ curwin->w_cursor = prev_cursor;
+
+ spell_find_cleanup(&sug);
+skip:
+ vim_free(line);
+}
+
+/*
+ * Check if the word at line "lnum" column "col" is required to start with a
+ * capital. This uses 'spellcapcheck' of the current buffer.
+ */
+ static int
+check_need_cap(linenr_T lnum, colnr_T col)
+{
+ int need_cap = FALSE;
+ char_u *line;
+ char_u *line_copy = NULL;
+ char_u *p;
+ colnr_T endcol;
+ regmatch_T regmatch;
+
+ if (curwin->w_s->b_cap_prog == NULL)
+ return FALSE;
+
+ line = ml_get_curline();
+ endcol = 0;
+ if (getwhitecols(line) >= (int)col)
+ {
+ /* At start of line, check if previous line is empty or sentence
+ * ends there. */
+ if (lnum == 1)
+ need_cap = TRUE;
+ else
+ {
+ line = ml_get(lnum - 1);
+ if (*skipwhite(line) == NUL)
+ need_cap = TRUE;
+ else
+ {
+ /* Append a space in place of the line break. */
+ line_copy = concat_str(line, (char_u *)" ");
+ line = line_copy;
+ endcol = (colnr_T)STRLEN(line);
+ }
+ }
+ }
+ else
+ endcol = col;
+
+ if (endcol > 0)
+ {
+ /* Check if sentence ends before the bad word. */
+ regmatch.regprog = curwin->w_s->b_cap_prog;
+ regmatch.rm_ic = FALSE;
+ p = line + endcol;
+ for (;;)
+ {
+ MB_PTR_BACK(line, p);
+ if (p == line || spell_iswordp_nmw(p, curwin))
+ break;
+ if (vim_regexec(&regmatch, p, 0)
+ && regmatch.endp[0] == line + endcol)
+ {
+ need_cap = TRUE;
+ break;
+ }
+ }
+ curwin->w_s->b_cap_prog = regmatch.regprog;
+ }
+
+ vim_free(line_copy);
+
+ return need_cap;
+}
+
+
+/*
+ * ":spellrepall"
+ */
+ void
+ex_spellrepall(exarg_T *eap UNUSED)
+{
+ pos_T pos = curwin->w_cursor;
+ char_u *frompat;
+ int addlen;
+ char_u *line;
+ char_u *p;
+ int save_ws = p_ws;
+ linenr_T prev_lnum = 0;
+
+ if (repl_from == NULL || repl_to == NULL)
+ {
+ emsg(_("E752: No previous spell replacement"));
+ return;
+ }
+ addlen = (int)(STRLEN(repl_to) - STRLEN(repl_from));
+
+ frompat = alloc((unsigned)STRLEN(repl_from) + 7);
+ if (frompat == NULL)
+ return;
+ sprintf((char *)frompat, "\\V\\<%s\\>", repl_from);
+ p_ws = FALSE;
+
+ sub_nsubs = 0;
+ sub_nlines = 0;
+ curwin->w_cursor.lnum = 0;
+ while (!got_int)
+ {
+ if (do_search(NULL, '/', frompat, 1L, SEARCH_KEEP, NULL, NULL) == 0
+ || u_save_cursor() == FAIL)
+ break;
+
+ /* Only replace when the right word isn't there yet. This happens
+ * when changing "etc" to "etc.". */
+ line = ml_get_curline();
+ if (addlen <= 0 || STRNCMP(line + curwin->w_cursor.col,
+ repl_to, STRLEN(repl_to)) != 0)
+ {
+ p = alloc((unsigned)STRLEN(line) + addlen + 1);
+ if (p == NULL)
+ break;
+ mch_memmove(p, line, curwin->w_cursor.col);
+ STRCPY(p + curwin->w_cursor.col, repl_to);
+ STRCAT(p, line + curwin->w_cursor.col + STRLEN(repl_from));
+ ml_replace(curwin->w_cursor.lnum, p, FALSE);
+ changed_bytes(curwin->w_cursor.lnum, curwin->w_cursor.col);
+
+ if (curwin->w_cursor.lnum != prev_lnum)
+ {
+ ++sub_nlines;
+ prev_lnum = curwin->w_cursor.lnum;
+ }
+ ++sub_nsubs;
+ }
+ curwin->w_cursor.col += (colnr_T)STRLEN(repl_to);
+ }
+
+ p_ws = save_ws;
+ curwin->w_cursor = pos;
+ vim_free(frompat);
+
+ if (sub_nsubs == 0)
+ semsg(_("E753: Not found: %s"), repl_from);
+ else
+ do_sub_msg(FALSE);
+}
+
+/*
+ * Find spell suggestions for "word". Return them in the growarray "*gap" as
+ * a list of allocated strings.
+ */
+ void
+spell_suggest_list(
+ garray_T *gap,
+ char_u *word,
+ int maxcount, /* maximum nr of suggestions */
+ int need_cap, /* 'spellcapcheck' matched */
+ int interactive)
+{
+ suginfo_T sug;
+ int i;
+ suggest_T *stp;
+ char_u *wcopy;
+
+ spell_find_suggest(word, 0, &sug, maxcount, FALSE, need_cap, interactive);
+
+ /* Make room in "gap". */
+ ga_init2(gap, sizeof(char_u *), sug.su_ga.ga_len + 1);
+ if (ga_grow(gap, sug.su_ga.ga_len) == OK)
+ {
+ for (i = 0; i < sug.su_ga.ga_len; ++i)
+ {
+ stp = &SUG(sug.su_ga, i);
+
+ /* The suggested word may replace only part of "word", add the not
+ * replaced part. */
+ wcopy = alloc(stp->st_wordlen
+ + (unsigned)STRLEN(sug.su_badptr + stp->st_orglen) + 1);
+ if (wcopy == NULL)
+ break;
+ STRCPY(wcopy, stp->st_word);
+ STRCPY(wcopy + stp->st_wordlen, sug.su_badptr + stp->st_orglen);
+ ((char_u **)gap->ga_data)[gap->ga_len++] = wcopy;
+ }
+ }
+
+ spell_find_cleanup(&sug);
+}
+
+/*
+ * Find spell suggestions for the word at the start of "badptr".
+ * Return the suggestions in "su->su_ga".
+ * The maximum number of suggestions is "maxcount".
+ * Note: does use info for the current window.
+ * This is based on the mechanisms of Aspell, but completely reimplemented.
+ */
+ static void
+spell_find_suggest(
+ char_u *badptr,
+ int badlen, /* length of bad word or 0 if unknown */
+ suginfo_T *su,
+ int maxcount,
+ int banbadword, /* don't include badword in suggestions */
+ int need_cap, /* word should start with capital */
+ int interactive)
+{
+ hlf_T attr = HLF_COUNT;
+ char_u buf[MAXPATHL];
+ char_u *p;
+ int do_combine = FALSE;
+ char_u *sps_copy;
+#ifdef FEAT_EVAL
+ static int expr_busy = FALSE;
+#endif
+ int c;
+ int i;
+ langp_T *lp;
+
+ /*
+ * Set the info in "*su".
+ */
+ vim_memset(su, 0, sizeof(suginfo_T));
+ ga_init2(&su->su_ga, (int)sizeof(suggest_T), 10);
+ ga_init2(&su->su_sga, (int)sizeof(suggest_T), 10);
+ if (*badptr == NUL)
+ return;
+ hash_init(&su->su_banned);
+
+ su->su_badptr = badptr;
+ if (badlen != 0)
+ su->su_badlen = badlen;
+ else
+ su->su_badlen = spell_check(curwin, su->su_badptr, &attr, NULL, FALSE);
+ su->su_maxcount = maxcount;
+ su->su_maxscore = SCORE_MAXINIT;
+
+ if (su->su_badlen >= MAXWLEN)
+ su->su_badlen = MAXWLEN - 1; /* just in case */
+ vim_strncpy(su->su_badword, su->su_badptr, su->su_badlen);
+ (void)spell_casefold(su->su_badptr, su->su_badlen,
+ su->su_fbadword, MAXWLEN);
+ /* TODO: make this work if the case-folded text is longer than the original
+ * text. Currently an illegal byte causes wrong pointer computations. */
+ su->su_fbadword[su->su_badlen] = NUL;
+
+ /* get caps flags for bad word */
+ su->su_badflags = badword_captype(su->su_badptr,
+ su->su_badptr + su->su_badlen);
+ if (need_cap)
+ su->su_badflags |= WF_ONECAP;
+
+ /* Find the default language for sound folding. We simply use the first
+ * one in 'spelllang' that supports sound folding. That's good for when
+ * using multiple files for one language, it's not that bad when mixing
+ * languages (e.g., "pl,en"). */
+ for (i = 0; i < curbuf->b_s.b_langp.ga_len; ++i)
+ {
+ lp = LANGP_ENTRY(curbuf->b_s.b_langp, i);
+ if (lp->lp_sallang != NULL)
+ {
+ su->su_sallang = lp->lp_sallang;
+ break;
+ }
+ }
+
+ /* Soundfold the bad word with the default sound folding, so that we don't
+ * have to do this many times. */
+ if (su->su_sallang != NULL)
+ spell_soundfold(su->su_sallang, su->su_fbadword, TRUE,
+ su->su_sal_badword);
+
+ /* If the word is not capitalised and spell_check() doesn't consider the
+ * word to be bad then it might need to be capitalised. Add a suggestion
+ * for that. */
+ c = PTR2CHAR(su->su_badptr);
+ if (!SPELL_ISUPPER(c) && attr == HLF_COUNT)
+ {
+ make_case_word(su->su_badword, buf, WF_ONECAP);
+ add_suggestion(su, &su->su_ga, buf, su->su_badlen, SCORE_ICASE,
+ 0, TRUE, su->su_sallang, FALSE);
+ }
+
+ /* Ban the bad word itself. It may appear in another region. */
+ if (banbadword)
+ add_banned(su, su->su_badword);
+
+ /* Make a copy of 'spellsuggest', because the expression may change it. */
+ sps_copy = vim_strsave(p_sps);
+ if (sps_copy == NULL)
+ return;
+
+ /* Loop over the items in 'spellsuggest'. */
+ for (p = sps_copy; *p != NUL; )
+ {
+ copy_option_part(&p, buf, MAXPATHL, ",");
+
+ if (STRNCMP(buf, "expr:", 5) == 0)
+ {
+#ifdef FEAT_EVAL
+ /* Evaluate an expression. Skip this when called recursively,
+ * when using spellsuggest() in the expression. */
+ if (!expr_busy)
+ {
+ expr_busy = TRUE;
+ spell_suggest_expr(su, buf + 5);
+ expr_busy = FALSE;
+ }
+#endif
+ }
+ else if (STRNCMP(buf, "file:", 5) == 0)
+ /* Use list of suggestions in a file. */
+ spell_suggest_file(su, buf + 5);
+ else
+ {
+ /* Use internal method. */
+ spell_suggest_intern(su, interactive);
+ if (sps_flags & SPS_DOUBLE)
+ do_combine = TRUE;
+ }
+ }
+
+ vim_free(sps_copy);
+
+ if (do_combine)
+ /* Combine the two list of suggestions. This must be done last,
+ * because sorting changes the order again. */
+ score_combine(su);
+}
+
+#ifdef FEAT_EVAL
+/*
+ * Find suggestions by evaluating expression "expr".
+ */
+ static void
+spell_suggest_expr(suginfo_T *su, char_u *expr)
+{
+ list_T *list;
+ listitem_T *li;
+ int score;
+ char_u *p;
+
+ /* The work is split up in a few parts to avoid having to export
+ * suginfo_T.
+ * First evaluate the expression and get the resulting list. */
+ list = eval_spell_expr(su->su_badword, expr);
+ if (list != NULL)
+ {
+ /* Loop over the items in the list. */
+ for (li = list->lv_first; li != NULL; li = li->li_next)
+ if (li->li_tv.v_type == VAR_LIST)
+ {
+ /* Get the word and the score from the items. */
+ score = get_spellword(li->li_tv.vval.v_list, &p);
+ if (score >= 0 && score <= su->su_maxscore)
+ add_suggestion(su, &su->su_ga, p, su->su_badlen,
+ score, 0, TRUE, su->su_sallang, FALSE);
+ }
+ list_unref(list);
+ }
+
+ /* Remove bogus suggestions, sort and truncate at "maxcount". */
+ check_suggestions(su, &su->su_ga);
+ (void)cleanup_suggestions(&su->su_ga, su->su_maxscore, su->su_maxcount);
+}
+#endif
+
+/*
+ * Find suggestions in file "fname". Used for "file:" in 'spellsuggest'.
+ */
+ static void
+spell_suggest_file(suginfo_T *su, char_u *fname)
+{
+ FILE *fd;
+ char_u line[MAXWLEN * 2];
+ char_u *p;
+ int len;
+ char_u cword[MAXWLEN];
+
+ /* Open the file. */
+ fd = mch_fopen((char *)fname, "r");
+ if (fd == NULL)
+ {
+ semsg(_(e_notopen), fname);
+ return;
+ }
+
+ /* Read it line by line. */
+ while (!vim_fgets(line, MAXWLEN * 2, fd) && !got_int)
+ {
+ line_breakcheck();
+
+ p = vim_strchr(line, '/');
+ if (p == NULL)
+ continue; /* No Tab found, just skip the line. */
+ *p++ = NUL;
+ if (STRICMP(su->su_badword, line) == 0)
+ {
+ /* Match! Isolate the good word, until CR or NL. */
+ for (len = 0; p[len] >= ' '; ++len)
+ ;
+ p[len] = NUL;
+
+ /* If the suggestion doesn't have specific case duplicate the case
+ * of the bad word. */
+ if (captype(p, NULL) == 0)
+ {
+ make_case_word(p, cword, su->su_badflags);
+ p = cword;
+ }
+
+ add_suggestion(su, &su->su_ga, p, su->su_badlen,
+ SCORE_FILE, 0, TRUE, su->su_sallang, FALSE);
+ }
+ }
+
+ fclose(fd);
+
+ /* Remove bogus suggestions, sort and truncate at "maxcount". */
+ check_suggestions(su, &su->su_ga);
+ (void)cleanup_suggestions(&su->su_ga, su->su_maxscore, su->su_maxcount);
+}
+
+/*
+ * Find suggestions for the internal method indicated by "sps_flags".
+ */
+ static void
+spell_suggest_intern(suginfo_T *su, int interactive)
+{
+ /*
+ * Load the .sug file(s) that are available and not done yet.
+ */
+ suggest_load_files();
+
+ /*
+ * 1. Try special cases, such as repeating a word: "the the" -> "the".
+ *
+ * Set a maximum score to limit the combination of operations that is
+ * tried.
+ */
+ suggest_try_special(su);
+
+ /*
+ * 2. Try inserting/deleting/swapping/changing a letter, use REP entries
+ * from the .aff file and inserting a space (split the word).
+ */
+ suggest_try_change(su);
+
+ /* For the resulting top-scorers compute the sound-a-like score. */
+ if (sps_flags & SPS_DOUBLE)
+ score_comp_sal(su);
+
+ /*
+ * 3. Try finding sound-a-like words.
+ */
+ if ((sps_flags & SPS_FAST) == 0)
+ {
+ if (sps_flags & SPS_BEST)
+ /* Adjust the word score for the suggestions found so far for how
+ * they sounds like. */
+ rescore_suggestions(su);
+
+ /*
+ * While going through the soundfold tree "su_maxscore" is the score
+ * for the soundfold word, limits the changes that are being tried,
+ * and "su_sfmaxscore" the rescored score, which is set by
+ * cleanup_suggestions().
+ * First find words with a small edit distance, because this is much
+ * faster and often already finds the top-N suggestions. If we didn't
+ * find many suggestions try again with a higher edit distance.
+ * "sl_sounddone" is used to avoid doing the same word twice.
+ */
+ suggest_try_soundalike_prep();
+ su->su_maxscore = SCORE_SFMAX1;
+ su->su_sfmaxscore = SCORE_MAXINIT * 3;
+ suggest_try_soundalike(su);
+ if (su->su_ga.ga_len < SUG_CLEAN_COUNT(su))
+ {
+ /* We didn't find enough matches, try again, allowing more
+ * changes to the soundfold word. */
+ su->su_maxscore = SCORE_SFMAX2;
+ suggest_try_soundalike(su);
+ if (su->su_ga.ga_len < SUG_CLEAN_COUNT(su))
+ {
+ /* Still didn't find enough matches, try again, allowing even
+ * more changes to the soundfold word. */
+ su->su_maxscore = SCORE_SFMAX3;
+ suggest_try_soundalike(su);
+ }
+ }
+ su->su_maxscore = su->su_sfmaxscore;
+ suggest_try_soundalike_finish();
+ }
+
+ /* When CTRL-C was hit while searching do show the results. Only clear
+ * got_int when using a command, not for spellsuggest(). */
+ ui_breakcheck();
+ if (interactive && got_int)
+ {
+ (void)vgetc();
+ got_int = FALSE;
+ }
+
+ if ((sps_flags & SPS_DOUBLE) == 0 && su->su_ga.ga_len != 0)
+ {
+ if (sps_flags & SPS_BEST)
+ /* Adjust the word score for how it sounds like. */
+ rescore_suggestions(su);
+
+ /* Remove bogus suggestions, sort and truncate at "maxcount". */
+ check_suggestions(su, &su->su_ga);
+ (void)cleanup_suggestions(&su->su_ga, su->su_maxscore, su->su_maxcount);
+ }
+}
+
+/*
+ * Free the info put in "*su" by spell_find_suggest().
+ */
+ static void
+spell_find_cleanup(suginfo_T *su)
+{
+ int i;
+
+ /* Free the suggestions. */
+ for (i = 0; i < su->su_ga.ga_len; ++i)
+ vim_free(SUG(su->su_ga, i).st_word);
+ ga_clear(&su->su_ga);
+ for (i = 0; i < su->su_sga.ga_len; ++i)
+ vim_free(SUG(su->su_sga, i).st_word);
+ ga_clear(&su->su_sga);
+
+ /* Free the banned words. */
+ hash_clear_all(&su->su_banned, 0);
+}
+
+/*
+ * Make a copy of "word", with the first letter upper or lower cased, to
+ * "wcopy[MAXWLEN]". "word" must not be empty.
+ * The result is NUL terminated.
+ */
+ void
+onecap_copy(
+ char_u *word,
+ char_u *wcopy,
+ int upper) /* TRUE: first letter made upper case */
+{
+ char_u *p;
+ int c;
+ int l;
+
+ p = word;
+ if (has_mbyte)
+ c = mb_cptr2char_adv(&p);
+ else
+ c = *p++;
+ if (upper)
+ c = SPELL_TOUPPER(c);
+ else
+ c = SPELL_TOFOLD(c);
+ if (has_mbyte)
+ l = mb_char2bytes(c, wcopy);
+ else
+ {
+ l = 1;
+ wcopy[0] = c;
+ }
+ vim_strncpy(wcopy + l, p, MAXWLEN - l - 1);
+}
+
+/*
+ * Make a copy of "word" with all the letters upper cased into
+ * "wcopy[MAXWLEN]". The result is NUL terminated.
+ */
+ static void
+allcap_copy(char_u *word, char_u *wcopy)
+{
+ char_u *s;
+ char_u *d;
+ int c;
+
+ d = wcopy;
+ for (s = word; *s != NUL; )
+ {
+ if (has_mbyte)
+ c = mb_cptr2char_adv(&s);
+ else
+ c = *s++;
+
+ /* We only change 0xdf to SS when we are certain latin1 is used. It
+ * would cause weird errors in other 8-bit encodings. */
+ if (enc_latin1like && c == 0xdf)
+ {
+ c = 'S';
+ if (d - wcopy >= MAXWLEN - 1)
+ break;
+ *d++ = c;
+ }
+ else
+ c = SPELL_TOUPPER(c);
+
+ if (has_mbyte)
+ {
+ if (d - wcopy >= MAXWLEN - MB_MAXBYTES)
+ break;
+ d += mb_char2bytes(c, d);
+ }
+ else
+ {
+ if (d - wcopy >= MAXWLEN - 1)
+ break;
+ *d++ = c;
+ }
+ }
+ *d = NUL;
+}
+
+/*
+ * Try finding suggestions by recognizing specific situations.
+ */
+ static void
+suggest_try_special(suginfo_T *su)
+{
+ char_u *p;
+ size_t len;
+ int c;
+ char_u word[MAXWLEN];
+
+ /*
+ * Recognize a word that is repeated: "the the".
+ */
+ p = skiptowhite(su->su_fbadword);
+ len = p - su->su_fbadword;
+ p = skipwhite(p);
+ if (STRLEN(p) == len && STRNCMP(su->su_fbadword, p, len) == 0)
+ {
+ /* Include badflags: if the badword is onecap or allcap
+ * use that for the goodword too: "The the" -> "The". */
+ c = su->su_fbadword[len];
+ su->su_fbadword[len] = NUL;
+ make_case_word(su->su_fbadword, word, su->su_badflags);
+ su->su_fbadword[len] = c;
+
+ /* Give a soundalike score of 0, compute the score as if deleting one
+ * character. */
+ add_suggestion(su, &su->su_ga, word, su->su_badlen,
+ RESCORE(SCORE_REP, 0), 0, TRUE, su->su_sallang, FALSE);
+ }
+}
+
+/*
+ * Change the 0 to 1 to measure how much time is spent in each state.
+ * Output is dumped in "suggestprof".
+ */
+#if 0
+# define SUGGEST_PROFILE
+proftime_T current;
+proftime_T total;
+proftime_T times[STATE_FINAL + 1];
+long counts[STATE_FINAL + 1];
+
+ static void
+prof_init(void)
+{
+ for (int i = 0; i <= STATE_FINAL; ++i)
+ {
+ profile_zero(&times[i]);
+ counts[i] = 0;
+ }
+ profile_start(&current);
+ profile_start(&total);
+}
+
+/* call before changing state */
+ static void
+prof_store(state_T state)
+{
+ profile_end(&current);
+ profile_add(&times[state], &current);
+ ++counts[state];
+ profile_start(&current);
+}
+# define PROF_STORE(state) prof_store(state);
+
+ static void
+prof_report(char *name)
+{
+ FILE *fd = fopen("suggestprof", "a");
+
+ profile_end(&total);
+ fprintf(fd, "-----------------------\n");
+ fprintf(fd, "%s: %s\n", name, profile_msg(&total));
+ for (int i = 0; i <= STATE_FINAL; ++i)
+ fprintf(fd, "%d: %s (%ld)\n", i, profile_msg(&times[i]), counts[i]);
+ fclose(fd);
+}
+#else
+# define PROF_STORE(state)
+#endif
+
+/*
+ * Try finding suggestions by adding/removing/swapping letters.
+ */
+ static void
+suggest_try_change(suginfo_T *su)
+{
+ char_u fword[MAXWLEN]; /* copy of the bad word, case-folded */
+ int n;
+ char_u *p;
+ int lpi;
+ langp_T *lp;
+
+ /* We make a copy of the case-folded bad word, so that we can modify it
+ * to find matches (esp. REP items). Append some more text, changing
+ * chars after the bad word may help. */
+ STRCPY(fword, su->su_fbadword);
+ n = (int)STRLEN(fword);
+ p = su->su_badptr + su->su_badlen;
+ (void)spell_casefold(p, (int)STRLEN(p), fword + n, MAXWLEN - n);
+
+ for (lpi = 0; lpi < curwin->w_s->b_langp.ga_len; ++lpi)
+ {
+ lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi);
+
+ /* If reloading a spell file fails it's still in the list but
+ * everything has been cleared. */
+ if (lp->lp_slang->sl_fbyts == NULL)
+ continue;
+
+ /* Try it for this language. Will add possible suggestions. */
+#ifdef SUGGEST_PROFILE
+ prof_init();
+#endif
+ suggest_trie_walk(su, lp, fword, FALSE);
+#ifdef SUGGEST_PROFILE
+ prof_report("try_change");
+#endif
+ }
+}
+
+/* Check the maximum score, if we go over it we won't try this change. */
+#define TRY_DEEPER(su, stack, depth, add) \
+ (stack[depth].ts_score + (add) < su->su_maxscore)
+
+/*
+ * Try finding suggestions by adding/removing/swapping letters.
+ *
+ * This uses a state machine. At each node in the tree we try various
+ * operations. When trying if an operation works "depth" is increased and the
+ * stack[] is used to store info. This allows combinations, thus insert one
+ * character, replace one and delete another. The number of changes is
+ * limited by su->su_maxscore.
+ *
+ * After implementing this I noticed an article by Kemal Oflazer that
+ * describes something similar: "Error-tolerant Finite State Recognition with
+ * Applications to Morphological Analysis and Spelling Correction" (1996).
+ * The implementation in the article is simplified and requires a stack of
+ * unknown depth. The implementation here only needs a stack depth equal to
+ * the length of the word.
+ *
+ * This is also used for the sound-folded word, "soundfold" is TRUE then.
+ * The mechanism is the same, but we find a match with a sound-folded word
+ * that comes from one or more original words. Each of these words may be
+ * added, this is done by add_sound_suggest().
+ * Don't use:
+ * the prefix tree or the keep-case tree
+ * "su->su_badlen"
+ * anything to do with upper and lower case
+ * anything to do with word or non-word characters ("spell_iswordp()")
+ * banned words
+ * word flags (rare, region, compounding)
+ * word splitting for now
+ * "similar_chars()"
+ * use "slang->sl_repsal" instead of "lp->lp_replang->sl_rep"
+ */
+ static void
+suggest_trie_walk(
+ suginfo_T *su,
+ langp_T *lp,
+ char_u *fword,
+ int soundfold)
+{
+ char_u tword[MAXWLEN]; /* good word collected so far */
+ trystate_T stack[MAXWLEN];
+ char_u preword[MAXWLEN * 3]; /* word found with proper case;
+ * concatenation of prefix compound
+ * words and split word. NUL terminated
+ * when going deeper but not when coming
+ * back. */
+ char_u compflags[MAXWLEN]; /* compound flags, one for each word */
+ trystate_T *sp;
+ int newscore;
+ int score;
+ char_u *byts, *fbyts, *pbyts;
+ idx_T *idxs, *fidxs, *pidxs;
+ int depth;
+ int c, c2, c3;
+ int n = 0;
+ int flags;
+ garray_T *gap;
+ idx_T arridx;
+ int len;
+ char_u *p;
+ fromto_T *ftp;
+ int fl = 0, tl;
+ int repextra = 0; /* extra bytes in fword[] from REP item */
+ slang_T *slang = lp->lp_slang;
+ int fword_ends;
+ int goodword_ends;
+#ifdef DEBUG_TRIEWALK
+ /* Stores the name of the change made at each level. */
+ char_u changename[MAXWLEN][80];
+#endif
+ int breakcheckcount = 1000;
+ int compound_ok;
+
+ /*
+ * Go through the whole case-fold tree, try changes at each node.
+ * "tword[]" contains the word collected from nodes in the tree.
+ * "fword[]" the word we are trying to match with (initially the bad
+ * word).
+ */
+ depth = 0;
+ sp = &stack[0];
+ vim_memset(sp, 0, sizeof(trystate_T));
+ sp->ts_curi = 1;
+
+ if (soundfold)
+ {
+ /* Going through the soundfold tree. */
+ byts = fbyts = slang->sl_sbyts;
+ idxs = fidxs = slang->sl_sidxs;
+ pbyts = NULL;
+ pidxs = NULL;
+ sp->ts_prefixdepth = PFD_NOPREFIX;
+ sp->ts_state = STATE_START;
+ }
+ else
+ {
+ /*
+ * When there are postponed prefixes we need to use these first. At
+ * the end of the prefix we continue in the case-fold tree.
+ */
+ fbyts = slang->sl_fbyts;
+ fidxs = slang->sl_fidxs;
+ pbyts = slang->sl_pbyts;
+ pidxs = slang->sl_pidxs;
+ if (pbyts != NULL)
+ {
+ byts = pbyts;
+ idxs = pidxs;
+ sp->ts_prefixdepth = PFD_PREFIXTREE;
+ sp->ts_state = STATE_NOPREFIX; /* try without prefix first */
+ }
+ else
+ {
+ byts = fbyts;
+ idxs = fidxs;
+ sp->ts_prefixdepth = PFD_NOPREFIX;
+ sp->ts_state = STATE_START;
+ }
+ }
+
+ /*
+ * Loop to find all suggestions. At each round we either:
+ * - For the current state try one operation, advance "ts_curi",
+ * increase "depth".
+ * - When a state is done go to the next, set "ts_state".
+ * - When all states are tried decrease "depth".
+ */
+ while (depth >= 0 && !got_int)
+ {
+ sp = &stack[depth];
+ switch (sp->ts_state)
+ {
+ case STATE_START:
+ case STATE_NOPREFIX:
+ /*
+ * Start of node: Deal with NUL bytes, which means
+ * tword[] may end here.
+ */
+ arridx = sp->ts_arridx; /* current node in the tree */
+ len = byts[arridx]; /* bytes in this node */
+ arridx += sp->ts_curi; /* index of current byte */
+
+ if (sp->ts_prefixdepth == PFD_PREFIXTREE)
+ {
+ /* Skip over the NUL bytes, we use them later. */
+ for (n = 0; n < len && byts[arridx + n] == 0; ++n)
+ ;
+ sp->ts_curi += n;
+
+ /* Always past NUL bytes now. */
+ n = (int)sp->ts_state;
+ PROF_STORE(sp->ts_state)
+ sp->ts_state = STATE_ENDNUL;
+ sp->ts_save_badflags = su->su_badflags;
+
+ /* At end of a prefix or at start of prefixtree: check for
+ * following word. */
+ if (byts[arridx] == 0 || n == (int)STATE_NOPREFIX)
+ {
+ /* Set su->su_badflags to the caps type at this position.
+ * Use the caps type until here for the prefix itself. */
+ if (has_mbyte)
+ n = nofold_len(fword, sp->ts_fidx, su->su_badptr);
+ else
+ n = sp->ts_fidx;
+ flags = badword_captype(su->su_badptr, su->su_badptr + n);
+ su->su_badflags = badword_captype(su->su_badptr + n,
+ su->su_badptr + su->su_badlen);
+#ifdef DEBUG_TRIEWALK
+ sprintf(changename[depth], "prefix");
+#endif
+ go_deeper(stack, depth, 0);
+ ++depth;
+ sp = &stack[depth];
+ sp->ts_prefixdepth = depth - 1;
+ byts = fbyts;
+ idxs = fidxs;
+ sp->ts_arridx = 0;
+
+ /* Move the prefix to preword[] with the right case
+ * and make find_keepcap_word() works. */
+ tword[sp->ts_twordlen] = NUL;
+ make_case_word(tword + sp->ts_splitoff,
+ preword + sp->ts_prewordlen, flags);
+ sp->ts_prewordlen = (char_u)STRLEN(preword);
+ sp->ts_splitoff = sp->ts_twordlen;
+ }
+ break;
+ }
+
+ if (sp->ts_curi > len || byts[arridx] != 0)
+ {
+ /* Past bytes in node and/or past NUL bytes. */
+ PROF_STORE(sp->ts_state)
+ sp->ts_state = STATE_ENDNUL;
+ sp->ts_save_badflags = su->su_badflags;
+ break;
+ }
+
+ /*
+ * End of word in tree.
+ */
+ ++sp->ts_curi; /* eat one NUL byte */
+
+ flags = (int)idxs[arridx];
+
+ /* Skip words with the NOSUGGEST flag. */
+ if (flags & WF_NOSUGGEST)
+ break;
+
+ fword_ends = (fword[sp->ts_fidx] == NUL
+ || (soundfold
+ ? VIM_ISWHITE(fword[sp->ts_fidx])
+ : !spell_iswordp(fword + sp->ts_fidx, curwin)));
+ tword[sp->ts_twordlen] = NUL;
+
+ if (sp->ts_prefixdepth <= PFD_NOTSPECIAL
+ && (sp->ts_flags & TSF_PREFIXOK) == 0)
+ {
+ /* There was a prefix before the word. Check that the prefix
+ * can be used with this word. */
+ /* Count the length of the NULs in the prefix. If there are
+ * none this must be the first try without a prefix. */
+ n = stack[sp->ts_prefixdepth].ts_arridx;
+ len = pbyts[n++];
+ for (c = 0; c < len && pbyts[n + c] == 0; ++c)
+ ;
+ if (c > 0)
+ {
+ c = valid_word_prefix(c, n, flags,
+ tword + sp->ts_splitoff, slang, FALSE);
+ if (c == 0)
+ break;
+
+ /* Use the WF_RARE flag for a rare prefix. */
+ if (c & WF_RAREPFX)
+ flags |= WF_RARE;
+
+ /* Tricky: when checking for both prefix and compounding
+ * we run into the prefix flag first.
+ * Remember that it's OK, so that we accept the prefix
+ * when arriving at a compound flag. */
+ sp->ts_flags |= TSF_PREFIXOK;
+ }
+ }
+
+ /* Check NEEDCOMPOUND: can't use word without compounding. Do try
+ * appending another compound word below. */
+ if (sp->ts_complen == sp->ts_compsplit && fword_ends
+ && (flags & WF_NEEDCOMP))
+ goodword_ends = FALSE;
+ else
+ goodword_ends = TRUE;
+
+ p = NULL;
+ compound_ok = TRUE;
+ if (sp->ts_complen > sp->ts_compsplit)
+ {
+ if (slang->sl_nobreak)
+ {
+ /* There was a word before this word. When there was no
+ * change in this word (it was correct) add the first word
+ * as a suggestion. If this word was corrected too, we
+ * need to check if a correct word follows. */
+ if (sp->ts_fidx - sp->ts_splitfidx
+ == sp->ts_twordlen - sp->ts_splitoff
+ && STRNCMP(fword + sp->ts_splitfidx,
+ tword + sp->ts_splitoff,
+ sp->ts_fidx - sp->ts_splitfidx) == 0)
+ {
+ preword[sp->ts_prewordlen] = NUL;
+ newscore = score_wordcount_adj(slang, sp->ts_score,
+ preword + sp->ts_prewordlen,
+ sp->ts_prewordlen > 0);
+ /* Add the suggestion if the score isn't too bad. */
+ if (newscore <= su->su_maxscore)
+ add_suggestion(su, &su->su_ga, preword,
+ sp->ts_splitfidx - repextra,
+ newscore, 0, FALSE,
+ lp->lp_sallang, FALSE);
+ break;
+ }
+ }
+ else
+ {
+ /* There was a compound word before this word. If this
+ * word does not support compounding then give up
+ * (splitting is tried for the word without compound
+ * flag). */
+ if (((unsigned)flags >> 24) == 0
+ || sp->ts_twordlen - sp->ts_splitoff
+ < slang->sl_compminlen)
+ break;
+ /* For multi-byte chars check character length against
+ * COMPOUNDMIN. */
+ if (has_mbyte
+ && slang->sl_compminlen > 0
+ && mb_charlen(tword + sp->ts_splitoff)
+ < slang->sl_compminlen)
+ break;
+
+ compflags[sp->ts_complen] = ((unsigned)flags >> 24);
+ compflags[sp->ts_complen + 1] = NUL;
+ vim_strncpy(preword + sp->ts_prewordlen,
+ tword + sp->ts_splitoff,
+ sp->ts_twordlen - sp->ts_splitoff);
+
+ /* Verify CHECKCOMPOUNDPATTERN rules. */
+ if (match_checkcompoundpattern(preword, sp->ts_prewordlen,
+ &slang->sl_comppat))
+ compound_ok = FALSE;
+
+ if (compound_ok)
+ {
+ p = preword;
+ while (*skiptowhite(p) != NUL)
+ p = skipwhite(skiptowhite(p));
+ if (fword_ends && !can_compound(slang, p,
+ compflags + sp->ts_compsplit))
+ /* Compound is not allowed. But it may still be
+ * possible if we add another (short) word. */
+ compound_ok = FALSE;
+ }
+
+ /* Get pointer to last char of previous word. */
+ p = preword + sp->ts_prewordlen;
+ MB_PTR_BACK(preword, p);
+ }
+ }
+
+ /*
+ * Form the word with proper case in preword.
+ * If there is a word from a previous split, append.
+ * For the soundfold tree don't change the case, simply append.
+ */
+ if (soundfold)
+ STRCPY(preword + sp->ts_prewordlen, tword + sp->ts_splitoff);
+ else if (flags & WF_KEEPCAP)
+ /* Must find the word in the keep-case tree. */
+ find_keepcap_word(slang, tword + sp->ts_splitoff,
+ preword + sp->ts_prewordlen);
+ else
+ {
+ /* Include badflags: If the badword is onecap or allcap
+ * use that for the goodword too. But if the badword is
+ * allcap and it's only one char long use onecap. */
+ c = su->su_badflags;
+ if ((c & WF_ALLCAP)
+ && su->su_badlen == (*mb_ptr2len)(su->su_badptr))
+ c = WF_ONECAP;
+ c |= flags;
+
+ /* When appending a compound word after a word character don't
+ * use Onecap. */
+ if (p != NULL && spell_iswordp_nmw(p, curwin))
+ c &= ~WF_ONECAP;
+ make_case_word(tword + sp->ts_splitoff,
+ preword + sp->ts_prewordlen, c);
+ }
+
+ if (!soundfold)
+ {
+ /* Don't use a banned word. It may appear again as a good
+ * word, thus remember it. */
+ if (flags & WF_BANNED)
+ {
+ add_banned(su, preword + sp->ts_prewordlen);
+ break;
+ }
+ if ((sp->ts_complen == sp->ts_compsplit
+ && WAS_BANNED(su, preword + sp->ts_prewordlen))
+ || WAS_BANNED(su, preword))
+ {
+ if (slang->sl_compprog == NULL)
+ break;
+ /* the word so far was banned but we may try compounding */
+ goodword_ends = FALSE;
+ }
+ }
+
+ newscore = 0;
+ if (!soundfold) /* soundfold words don't have flags */
+ {
+ if ((flags & WF_REGION)
+ && (((unsigned)flags >> 16) & lp->lp_region) == 0)
+ newscore += SCORE_REGION;
+ if (flags & WF_RARE)
+ newscore += SCORE_RARE;
+
+ if (!spell_valid_case(su->su_badflags,
+ captype(preword + sp->ts_prewordlen, NULL)))
+ newscore += SCORE_ICASE;
+ }
+
+ /* TODO: how about splitting in the soundfold tree? */
+ if (fword_ends
+ && goodword_ends
+ && sp->ts_fidx >= sp->ts_fidxtry
+ && compound_ok)
+ {
+ /* The badword also ends: add suggestions. */
+#ifdef DEBUG_TRIEWALK
+ if (soundfold && STRCMP(preword, "smwrd") == 0)
+ {
+ int j;
+
+ /* print the stack of changes that brought us here */
+ smsg("------ %s -------", fword);
+ for (j = 0; j < depth; ++j)
+ smsg("%s", changename[j]);
+ }
+#endif
+ if (soundfold)
+ {
+ /* For soundfolded words we need to find the original
+ * words, the edit distance and then add them. */
+ add_sound_suggest(su, preword, sp->ts_score, lp);
+ }
+ else if (sp->ts_fidx > 0)
+ {
+ /* Give a penalty when changing non-word char to word
+ * char, e.g., "thes," -> "these". */
+ p = fword + sp->ts_fidx;
+ MB_PTR_BACK(fword, p);
+ if (!spell_iswordp(p, curwin))
+ {
+ p = preword + STRLEN(preword);
+ MB_PTR_BACK(preword, p);
+ if (spell_iswordp(p, curwin))
+ newscore += SCORE_NONWORD;
+ }
+
+ /* Give a bonus to words seen before. */
+ score = score_wordcount_adj(slang,
+ sp->ts_score + newscore,
+ preword + sp->ts_prewordlen,
+ sp->ts_prewordlen > 0);
+
+ /* Add the suggestion if the score isn't too bad. */
+ if (score <= su->su_maxscore)
+ {
+ add_suggestion(su, &su->su_ga, preword,
+ sp->ts_fidx - repextra,
+ score, 0, FALSE, lp->lp_sallang, FALSE);
+
+ if (su->su_badflags & WF_MIXCAP)
+ {
+ /* We really don't know if the word should be
+ * upper or lower case, add both. */
+ c = captype(preword, NULL);
+ if (c == 0 || c == WF_ALLCAP)
+ {
+ make_case_word(tword + sp->ts_splitoff,
+ preword + sp->ts_prewordlen,
+ c == 0 ? WF_ALLCAP : 0);
+
+ add_suggestion(su, &su->su_ga, preword,
+ sp->ts_fidx - repextra,
+ score + SCORE_ICASE, 0, FALSE,
+ lp->lp_sallang, FALSE);
+ }
+ }
+ }
+ }
+ }
+
+ /*
+ * Try word split and/or compounding.
+ */
+ if ((sp->ts_fidx >= sp->ts_fidxtry || fword_ends)
+ /* Don't split halfway a character. */
+ && (!has_mbyte || sp->ts_tcharlen == 0))
+ {
+ int try_compound;
+ int try_split;
+
+ /* If past the end of the bad word don't try a split.
+ * Otherwise try changing the next word. E.g., find
+ * suggestions for "the the" where the second "the" is
+ * different. It's done like a split.
+ * TODO: word split for soundfold words */
+ try_split = (sp->ts_fidx - repextra < su->su_badlen)
+ && !soundfold;
+
+ /* Get here in several situations:
+ * 1. The word in the tree ends:
+ * If the word allows compounding try that. Otherwise try
+ * a split by inserting a space. For both check that a
+ * valid words starts at fword[sp->ts_fidx].
+ * For NOBREAK do like compounding to be able to check if
+ * the next word is valid.
+ * 2. The badword does end, but it was due to a change (e.g.,
+ * a swap). No need to split, but do check that the
+ * following word is valid.
+ * 3. The badword and the word in the tree end. It may still
+ * be possible to compound another (short) word.
+ */
+ try_compound = FALSE;
+ if (!soundfold
+ && !slang->sl_nocompoundsugs
+ && slang->sl_compprog != NULL
+ && ((unsigned)flags >> 24) != 0
+ && sp->ts_twordlen - sp->ts_splitoff
+ >= slang->sl_compminlen
+ && (!has_mbyte
+ || slang->sl_compminlen == 0
+ || mb_charlen(tword + sp->ts_splitoff)
+ >= slang->sl_compminlen)
+ && (slang->sl_compsylmax < MAXWLEN
+ || sp->ts_complen + 1 - sp->ts_compsplit
+ < slang->sl_compmax)
+ && (can_be_compound(sp, slang,
+ compflags, ((unsigned)flags >> 24))))
+
+ {
+ try_compound = TRUE;
+ compflags[sp->ts_complen] = ((unsigned)flags >> 24);
+ compflags[sp->ts_complen + 1] = NUL;
+ }
+
+ /* For NOBREAK we never try splitting, it won't make any word
+ * valid. */
+ if (slang->sl_nobreak && !slang->sl_nocompoundsugs)
+ try_compound = TRUE;
+
+ /* If we could add a compound word, and it's also possible to
+ * split at this point, do the split first and set
+ * TSF_DIDSPLIT to avoid doing it again. */
+ else if (!fword_ends
+ && try_compound
+ && (sp->ts_flags & TSF_DIDSPLIT) == 0)
+ {
+ try_compound = FALSE;
+ sp->ts_flags |= TSF_DIDSPLIT;
+ --sp->ts_curi; /* do the same NUL again */
+ compflags[sp->ts_complen] = NUL;
+ }
+ else
+ sp->ts_flags &= ~TSF_DIDSPLIT;
+
+ if (try_split || try_compound)
+ {
+ if (!try_compound && (!fword_ends || !goodword_ends))
+ {
+ /* If we're going to split need to check that the
+ * words so far are valid for compounding. If there
+ * is only one word it must not have the NEEDCOMPOUND
+ * flag. */
+ if (sp->ts_complen == sp->ts_compsplit
+ && (flags & WF_NEEDCOMP))
+ break;
+ p = preword;
+ while (*skiptowhite(p) != NUL)
+ p = skipwhite(skiptowhite(p));
+ if (sp->ts_complen > sp->ts_compsplit
+ && !can_compound(slang, p,
+ compflags + sp->ts_compsplit))
+ break;
+
+ if (slang->sl_nosplitsugs)
+ newscore += SCORE_SPLIT_NO;
+ else
+ newscore += SCORE_SPLIT;
+
+ /* Give a bonus to words seen before. */
+ newscore = score_wordcount_adj(slang, newscore,
+ preword + sp->ts_prewordlen, TRUE);
+ }
+
+ if (TRY_DEEPER(su, stack, depth, newscore))
+ {
+ go_deeper(stack, depth, newscore);
+#ifdef DEBUG_TRIEWALK
+ if (!try_compound && !fword_ends)
+ sprintf(changename[depth], "%.*s-%s: split",
+ sp->ts_twordlen, tword, fword + sp->ts_fidx);
+ else
+ sprintf(changename[depth], "%.*s-%s: compound",
+ sp->ts_twordlen, tword, fword + sp->ts_fidx);
+#endif
+ /* Save things to be restored at STATE_SPLITUNDO. */
+ sp->ts_save_badflags = su->su_badflags;
+ PROF_STORE(sp->ts_state)
+ sp->ts_state = STATE_SPLITUNDO;
+
+ ++depth;
+ sp = &stack[depth];
+
+ /* Append a space to preword when splitting. */
+ if (!try_compound && !fword_ends)
+ STRCAT(preword, " ");
+ sp->ts_prewordlen = (char_u)STRLEN(preword);
+ sp->ts_splitoff = sp->ts_twordlen;
+ sp->ts_splitfidx = sp->ts_fidx;
+
+ /* If the badword has a non-word character at this
+ * position skip it. That means replacing the
+ * non-word character with a space. Always skip a
+ * character when the word ends. But only when the
+ * good word can end. */
+ if (((!try_compound && !spell_iswordp_nmw(fword
+ + sp->ts_fidx,
+ curwin))
+ || fword_ends)
+ && fword[sp->ts_fidx] != NUL
+ && goodword_ends)
+ {
+ int l;
+
+ l = MB_PTR2LEN(fword + sp->ts_fidx);
+ if (fword_ends)
+ {
+ /* Copy the skipped character to preword. */
+ mch_memmove(preword + sp->ts_prewordlen,
+ fword + sp->ts_fidx, l);
+ sp->ts_prewordlen += l;
+ preword[sp->ts_prewordlen] = NUL;
+ }
+ else
+ sp->ts_score -= SCORE_SPLIT - SCORE_SUBST;
+ sp->ts_fidx += l;
+ }
+
+ /* When compounding include compound flag in
+ * compflags[] (already set above). When splitting we
+ * may start compounding over again. */
+ if (try_compound)
+ ++sp->ts_complen;
+ else
+ sp->ts_compsplit = sp->ts_complen;
+ sp->ts_prefixdepth = PFD_NOPREFIX;
+
+ /* set su->su_badflags to the caps type at this
+ * position */
+ if (has_mbyte)
+ n = nofold_len(fword, sp->ts_fidx, su->su_badptr);
+ else
+ n = sp->ts_fidx;
+ su->su_badflags = badword_captype(su->su_badptr + n,
+ su->su_badptr + su->su_badlen);
+
+ /* Restart at top of the tree. */
+ sp->ts_arridx = 0;
+
+ /* If there are postponed prefixes, try these too. */
+ if (pbyts != NULL)
+ {
+ byts = pbyts;
+ idxs = pidxs;
+ sp->ts_prefixdepth = PFD_PREFIXTREE;
+ PROF_STORE(sp->ts_state)
+ sp->ts_state = STATE_NOPREFIX;
+ }
+ }
+ }
+ }
+ break;
+
+ case STATE_SPLITUNDO:
+ /* Undo the changes done for word split or compound word. */
+ su->su_badflags = sp->ts_save_badflags;
+
+ /* Continue looking for NUL bytes. */
+ PROF_STORE(sp->ts_state)
+ sp->ts_state = STATE_START;
+
+ /* In case we went into the prefix tree. */
+ byts = fbyts;
+ idxs = fidxs;
+ break;
+
+ case STATE_ENDNUL:
+ /* Past the NUL bytes in the node. */
+ su->su_badflags = sp->ts_save_badflags;
+ if (fword[sp->ts_fidx] == NUL && sp->ts_tcharlen == 0)
+ {
+ /* The badword ends, can't use STATE_PLAIN. */
+ PROF_STORE(sp->ts_state)
+ sp->ts_state = STATE_DEL;
+ break;
+ }
+ PROF_STORE(sp->ts_state)
+ sp->ts_state = STATE_PLAIN;
+ /* FALLTHROUGH */
+
+ case STATE_PLAIN:
+ /*
+ * Go over all possible bytes at this node, add each to tword[]
+ * and use child node. "ts_curi" is the index.
+ */
+ arridx = sp->ts_arridx;
+ if (sp->ts_curi > byts[arridx])
+ {
+ /* Done all bytes at this node, do next state. When still at
+ * already changed bytes skip the other tricks. */
+ PROF_STORE(sp->ts_state)
+ if (sp->ts_fidx >= sp->ts_fidxtry)
+ sp->ts_state = STATE_DEL;
+ else
+ sp->ts_state = STATE_FINAL;
+ }
+ else
+ {
+ arridx += sp->ts_curi++;
+ c = byts[arridx];
+
+ /* Normal byte, go one level deeper. If it's not equal to the
+ * byte in the bad word adjust the score. But don't even try
+ * when the byte was already changed. And don't try when we
+ * just deleted this byte, accepting it is always cheaper than
+ * delete + substitute. */
+ if (c == fword[sp->ts_fidx]
+ || (sp->ts_tcharlen > 0 && sp->ts_isdiff != DIFF_NONE))
+ newscore = 0;
+ else
+ newscore = SCORE_SUBST;
+ if ((newscore == 0
+ || (sp->ts_fidx >= sp->ts_fidxtry
+ && ((sp->ts_flags & TSF_DIDDEL) == 0
+ || c != fword[sp->ts_delidx])))
+ && TRY_DEEPER(su, stack, depth, newscore))
+ {
+ go_deeper(stack, depth, newscore);
+#ifdef DEBUG_TRIEWALK
+ if (newscore > 0)
+ sprintf(changename[depth], "%.*s-%s: subst %c to %c",
+ sp->ts_twordlen, tword, fword + sp->ts_fidx,
+ fword[sp->ts_fidx], c);
+ else
+ sprintf(changename[depth], "%.*s-%s: accept %c",
+ sp->ts_twordlen, tword, fword + sp->ts_fidx,
+ fword[sp->ts_fidx]);
+#endif
+ ++depth;
+ sp = &stack[depth];
+ ++sp->ts_fidx;
+ tword[sp->ts_twordlen++] = c;
+ sp->ts_arridx = idxs[arridx];
+ if (newscore == SCORE_SUBST)
+ sp->ts_isdiff = DIFF_YES;
+ if (has_mbyte)
+ {
+ /* Multi-byte characters are a bit complicated to
+ * handle: They differ when any of the bytes differ
+ * and then their length may also differ. */
+ if (sp->ts_tcharlen == 0)
+ {
+ /* First byte. */
+ sp->ts_tcharidx = 0;
+ sp->ts_tcharlen = MB_BYTE2LEN(c);
+ sp->ts_fcharstart = sp->ts_fidx - 1;
+ sp->ts_isdiff = (newscore != 0)
+ ? DIFF_YES : DIFF_NONE;
+ }
+ else if (sp->ts_isdiff == DIFF_INSERT)
+ /* When inserting trail bytes don't advance in the
+ * bad word. */
+ --sp->ts_fidx;
+ if (++sp->ts_tcharidx == sp->ts_tcharlen)
+ {
+ /* Last byte of character. */
+ if (sp->ts_isdiff == DIFF_YES)
+ {
+ /* Correct ts_fidx for the byte length of the
+ * character (we didn't check that before). */
+ sp->ts_fidx = sp->ts_fcharstart
+ + MB_PTR2LEN(
+ fword + sp->ts_fcharstart);
+ /* For changing a composing character adjust
+ * the score from SCORE_SUBST to
+ * SCORE_SUBCOMP. */
+ if (enc_utf8
+ && utf_iscomposing(
+ utf_ptr2char(tword
+ + sp->ts_twordlen
+ - sp->ts_tcharlen))
+ && utf_iscomposing(
+ utf_ptr2char(fword
+ + sp->ts_fcharstart)))
+ sp->ts_score -=
+ SCORE_SUBST - SCORE_SUBCOMP;
+
+ /* For a similar character adjust score from
+ * SCORE_SUBST to SCORE_SIMILAR. */
+ else if (!soundfold
+ && slang->sl_has_map
+ && similar_chars(slang,
+ mb_ptr2char(tword
+ + sp->ts_twordlen
+ - sp->ts_tcharlen),
+ mb_ptr2char(fword
+ + sp->ts_fcharstart)))
+ sp->ts_score -=
+ SCORE_SUBST - SCORE_SIMILAR;
+ }
+ else if (sp->ts_isdiff == DIFF_INSERT
+ && sp->ts_twordlen > sp->ts_tcharlen)
+ {
+ p = tword + sp->ts_twordlen - sp->ts_tcharlen;
+ c = mb_ptr2char(p);
+ if (enc_utf8 && utf_iscomposing(c))
+ {
+ /* Inserting a composing char doesn't
+ * count that much. */
+ sp->ts_score -= SCORE_INS - SCORE_INSCOMP;
+ }
+ else
+ {
+ /* If the previous character was the same,
+ * thus doubling a character, give a bonus
+ * to the score. Also for the soundfold
+ * tree (might seem illogical but does
+ * give better scores). */
+ MB_PTR_BACK(tword, p);
+ if (c == mb_ptr2char(p))
+ sp->ts_score -= SCORE_INS
+ - SCORE_INSDUP;
+ }
+ }
+
+ /* Starting a new char, reset the length. */
+ sp->ts_tcharlen = 0;
+ }
+ }
+ else
+ {
+ /* If we found a similar char adjust the score.
+ * We do this after calling go_deeper() because
+ * it's slow. */
+ if (newscore != 0
+ && !soundfold
+ && slang->sl_has_map
+ && similar_chars(slang,
+ c, fword[sp->ts_fidx - 1]))
+ sp->ts_score -= SCORE_SUBST - SCORE_SIMILAR;
+ }
+ }
+ }
+ break;
+
+ case STATE_DEL:
+ /* When past the first byte of a multi-byte char don't try
+ * delete/insert/swap a character. */
+ if (has_mbyte && sp->ts_tcharlen > 0)
+ {
+ PROF_STORE(sp->ts_state)
+ sp->ts_state = STATE_FINAL;
+ break;
+ }
+ /*
+ * Try skipping one character in the bad word (delete it).
+ */
+ PROF_STORE(sp->ts_state)
+ sp->ts_state = STATE_INS_PREP;
+ sp->ts_curi = 1;
+ if (soundfold && sp->ts_fidx == 0 && fword[sp->ts_fidx] == '*')
+ /* Deleting a vowel at the start of a word counts less, see
+ * soundalike_score(). */
+ newscore = 2 * SCORE_DEL / 3;
+ else
+ newscore = SCORE_DEL;
+ if (fword[sp->ts_fidx] != NUL
+ && TRY_DEEPER(su, stack, depth, newscore))
+ {
+ go_deeper(stack, depth, newscore);
+#ifdef DEBUG_TRIEWALK
+ sprintf(changename[depth], "%.*s-%s: delete %c",
+ sp->ts_twordlen, tword, fword + sp->ts_fidx,
+ fword[sp->ts_fidx]);
+#endif
+ ++depth;
+
+ /* Remember what character we deleted, so that we can avoid
+ * inserting it again. */
+ stack[depth].ts_flags |= TSF_DIDDEL;
+ stack[depth].ts_delidx = sp->ts_fidx;
+
+ /* Advance over the character in fword[]. Give a bonus to the
+ * score if the same character is following "nn" -> "n". It's
+ * a bit illogical for soundfold tree but it does give better
+ * results. */
+ if (has_mbyte)
+ {
+ c = mb_ptr2char(fword + sp->ts_fidx);
+ stack[depth].ts_fidx += MB_PTR2LEN(fword + sp->ts_fidx);
+ if (enc_utf8 && utf_iscomposing(c))
+ stack[depth].ts_score -= SCORE_DEL - SCORE_DELCOMP;
+ else if (c == mb_ptr2char(fword + stack[depth].ts_fidx))
+ stack[depth].ts_score -= SCORE_DEL - SCORE_DELDUP;
+ }
+ else
+ {
+ ++stack[depth].ts_fidx;
+ if (fword[sp->ts_fidx] == fword[sp->ts_fidx + 1])
+ stack[depth].ts_score -= SCORE_DEL - SCORE_DELDUP;
+ }
+ break;
+ }
+ /* FALLTHROUGH */
+
+ case STATE_INS_PREP:
+ if (sp->ts_flags & TSF_DIDDEL)
+ {
+ /* If we just deleted a byte then inserting won't make sense,
+ * a substitute is always cheaper. */
+ PROF_STORE(sp->ts_state)
+ sp->ts_state = STATE_SWAP;
+ break;
+ }
+
+ /* skip over NUL bytes */
+ n = sp->ts_arridx;
+ for (;;)
+ {
+ if (sp->ts_curi > byts[n])
+ {
+ /* Only NUL bytes at this node, go to next state. */
+ PROF_STORE(sp->ts_state)
+ sp->ts_state = STATE_SWAP;
+ break;
+ }
+ if (byts[n + sp->ts_curi] != NUL)
+ {
+ /* Found a byte to insert. */
+ PROF_STORE(sp->ts_state)
+ sp->ts_state = STATE_INS;
+ break;
+ }
+ ++sp->ts_curi;
+ }
+ break;
+
+ /* FALLTHROUGH */
+
+ case STATE_INS:
+ /* Insert one byte. Repeat this for each possible byte at this
+ * node. */
+ n = sp->ts_arridx;
+ if (sp->ts_curi > byts[n])
+ {
+ /* Done all bytes at this node, go to next state. */
+ PROF_STORE(sp->ts_state)
+ sp->ts_state = STATE_SWAP;
+ break;
+ }
+
+ /* Do one more byte at this node, but:
+ * - Skip NUL bytes.
+ * - Skip the byte if it's equal to the byte in the word,
+ * accepting that byte is always better.
+ */
+ n += sp->ts_curi++;
+ c = byts[n];
+ if (soundfold && sp->ts_twordlen == 0 && c == '*')
+ /* Inserting a vowel at the start of a word counts less,
+ * see soundalike_score(). */
+ newscore = 2 * SCORE_INS / 3;
+ else
+ newscore = SCORE_INS;
+ if (c != fword[sp->ts_fidx]
+ && TRY_DEEPER(su, stack, depth, newscore))
+ {
+ go_deeper(stack, depth, newscore);
+#ifdef DEBUG_TRIEWALK
+ sprintf(changename[depth], "%.*s-%s: insert %c",
+ sp->ts_twordlen, tword, fword + sp->ts_fidx,
+ c);
+#endif
+ ++depth;
+ sp = &stack[depth];
+ tword[sp->ts_twordlen++] = c;
+ sp->ts_arridx = idxs[n];
+ if (has_mbyte)
+ {
+ fl = MB_BYTE2LEN(c);
+ if (fl > 1)
+ {
+ /* There are following bytes for the same character.
+ * We must find all bytes before trying
+ * delete/insert/swap/etc. */
+ sp->ts_tcharlen = fl;
+ sp->ts_tcharidx = 1;
+ sp->ts_isdiff = DIFF_INSERT;
+ }
+ }
+ else
+ fl = 1;
+ if (fl == 1)
+ {
+ /* If the previous character was the same, thus doubling a
+ * character, give a bonus to the score. Also for
+ * soundfold words (illogical but does give a better
+ * score). */
+ if (sp->ts_twordlen >= 2
+ && tword[sp->ts_twordlen - 2] == c)
+ sp->ts_score -= SCORE_INS - SCORE_INSDUP;
+ }
+ }
+ break;
+
+ case STATE_SWAP:
+ /*
+ * Swap two bytes in the bad word: "12" -> "21".
+ * We change "fword" here, it's changed back afterwards at
+ * STATE_UNSWAP.
+ */
+ p = fword + sp->ts_fidx;
+ c = *p;
+ if (c == NUL)
+ {
+ /* End of word, can't swap or replace. */
+ PROF_STORE(sp->ts_state)
+ sp->ts_state = STATE_FINAL;
+ break;
+ }
+
+ /* Don't swap if the first character is not a word character.
+ * SWAP3 etc. also don't make sense then. */
+ if (!soundfold && !spell_iswordp(p, curwin))
+ {
+ PROF_STORE(sp->ts_state)
+ sp->ts_state = STATE_REP_INI;
+ break;
+ }
+
+ if (has_mbyte)
+ {
+ n = MB_CPTR2LEN(p);
+ c = mb_ptr2char(p);
+ if (p[n] == NUL)
+ c2 = NUL;
+ else if (!soundfold && !spell_iswordp(p + n, curwin))
+ c2 = c; /* don't swap non-word char */
+ else
+ c2 = mb_ptr2char(p + n);
+ }
+ else
+ {
+ if (p[1] == NUL)
+ c2 = NUL;
+ else if (!soundfold && !spell_iswordp(p + 1, curwin))
+ c2 = c; /* don't swap non-word char */
+ else
+ c2 = p[1];
+ }
+
+ /* When the second character is NUL we can't swap. */
+ if (c2 == NUL)
+ {
+ PROF_STORE(sp->ts_state)
+ sp->ts_state = STATE_REP_INI;
+ break;
+ }
+
+ /* When characters are identical, swap won't do anything.
+ * Also get here if the second char is not a word character. */
+ if (c == c2)
+ {
+ PROF_STORE(sp->ts_state)
+ sp->ts_state = STATE_SWAP3;
+ break;
+ }
+ if (c2 != NUL && TRY_DEEPER(su, stack, depth, SCORE_SWAP))
+ {
+ go_deeper(stack, depth, SCORE_SWAP);
+#ifdef DEBUG_TRIEWALK
+ sprintf(changename[depth], "%.*s-%s: swap %c and %c",
+ sp->ts_twordlen, tword, fword + sp->ts_fidx,
+ c, c2);
+#endif
+ PROF_STORE(sp->ts_state)
+ sp->ts_state = STATE_UNSWAP;
+ ++depth;
+ if (has_mbyte)
+ {
+ fl = mb_char2len(c2);
+ mch_memmove(p, p + n, fl);
+ mb_char2bytes(c, p + fl);
+ stack[depth].ts_fidxtry = sp->ts_fidx + n + fl;
+ }
+ else
+ {
+ p[0] = c2;
+ p[1] = c;
+ stack[depth].ts_fidxtry = sp->ts_fidx + 2;
+ }
+ }
+ else
+ {
+ /* If this swap doesn't work then SWAP3 won't either. */
+ PROF_STORE(sp->ts_state)
+ sp->ts_state = STATE_REP_INI;
+ }
+ break;
+
+ case STATE_UNSWAP:
+ /* Undo the STATE_SWAP swap: "21" -> "12". */
+ p = fword + sp->ts_fidx;
+ if (has_mbyte)
+ {
+ n = MB_PTR2LEN(p);
+ c = mb_ptr2char(p + n);
+ mch_memmove(p + MB_PTR2LEN(p + n), p, n);
+ mb_char2bytes(c, p);
+ }
+ else
+ {
+ c = *p;
+ *p = p[1];
+ p[1] = c;
+ }
+ /* FALLTHROUGH */
+
+ case STATE_SWAP3:
+ /* Swap two bytes, skipping one: "123" -> "321". We change
+ * "fword" here, it's changed back afterwards at STATE_UNSWAP3. */
+ p = fword + sp->ts_fidx;
+ if (has_mbyte)
+ {
+ n = MB_CPTR2LEN(p);
+ c = mb_ptr2char(p);
+ fl = MB_CPTR2LEN(p + n);
+ c2 = mb_ptr2char(p + n);
+ if (!soundfold && !spell_iswordp(p + n + fl, curwin))
+ c3 = c; /* don't swap non-word char */
+ else
+ c3 = mb_ptr2char(p + n + fl);
+ }
+ else
+ {
+ c = *p;
+ c2 = p[1];
+ if (!soundfold && !spell_iswordp(p + 2, curwin))
+ c3 = c; /* don't swap non-word char */
+ else
+ c3 = p[2];
+ }
+
+ /* When characters are identical: "121" then SWAP3 result is
+ * identical, ROT3L result is same as SWAP: "211", ROT3L result is
+ * same as SWAP on next char: "112". Thus skip all swapping.
+ * Also skip when c3 is NUL.
+ * Also get here when the third character is not a word character.
+ * Second character may any char: "a.b" -> "b.a" */
+ if (c == c3 || c3 == NUL)
+ {
+ PROF_STORE(sp->ts_state)
+ sp->ts_state = STATE_REP_INI;
+ break;
+ }
+ if (TRY_DEEPER(su, stack, depth, SCORE_SWAP3))
+ {
+ go_deeper(stack, depth, SCORE_SWAP3);
+#ifdef DEBUG_TRIEWALK
+ sprintf(changename[depth], "%.*s-%s: swap3 %c and %c",
+ sp->ts_twordlen, tword, fword + sp->ts_fidx,
+ c, c3);
+#endif
+ PROF_STORE(sp->ts_state)
+ sp->ts_state = STATE_UNSWAP3;
+ ++depth;
+ if (has_mbyte)
+ {
+ tl = mb_char2len(c3);
+ mch_memmove(p, p + n + fl, tl);
+ mb_char2bytes(c2, p + tl);
+ mb_char2bytes(c, p + fl + tl);
+ stack[depth].ts_fidxtry = sp->ts_fidx + n + fl + tl;
+ }
+ else
+ {
+ p[0] = p[2];
+ p[2] = c;
+ stack[depth].ts_fidxtry = sp->ts_fidx + 3;
+ }
+ }
+ else
+ {
+ PROF_STORE(sp->ts_state)
+ sp->ts_state = STATE_REP_INI;
+ }
+ break;
+
+ case STATE_UNSWAP3:
+ /* Undo STATE_SWAP3: "321" -> "123" */
+ p = fword + sp->ts_fidx;
+ if (has_mbyte)
+ {
+ n = MB_PTR2LEN(p);
+ c2 = mb_ptr2char(p + n);
+ fl = MB_PTR2LEN(p + n);
+ c = mb_ptr2char(p + n + fl);
+ tl = MB_PTR2LEN(p + n + fl);
+ mch_memmove(p + fl + tl, p, n);
+ mb_char2bytes(c, p);
+ mb_char2bytes(c2, p + tl);
+ p = p + tl;
+ }
+ else
+ {
+ c = *p;
+ *p = p[2];
+ p[2] = c;
+ ++p;
+ }
+
+ if (!soundfold && !spell_iswordp(p, curwin))
+ {
+ /* Middle char is not a word char, skip the rotate. First and
+ * third char were already checked at swap and swap3. */
+ PROF_STORE(sp->ts_state)
+ sp->ts_state = STATE_REP_INI;
+ break;
+ }
+
+ /* Rotate three characters left: "123" -> "231". We change
+ * "fword" here, it's changed back afterwards at STATE_UNROT3L. */
+ if (TRY_DEEPER(su, stack, depth, SCORE_SWAP3))
+ {
+ go_deeper(stack, depth, SCORE_SWAP3);
+#ifdef DEBUG_TRIEWALK
+ p = fword + sp->ts_fidx;
+ sprintf(changename[depth], "%.*s-%s: rotate left %c%c%c",
+ sp->ts_twordlen, tword, fword + sp->ts_fidx,
+ p[0], p[1], p[2]);
+#endif
+ PROF_STORE(sp->ts_state)
+ sp->ts_state = STATE_UNROT3L;
+ ++depth;
+ p = fword + sp->ts_fidx;
+ if (has_mbyte)
+ {
+ n = MB_CPTR2LEN(p);
+ c = mb_ptr2char(p);
+ fl = MB_CPTR2LEN(p + n);
+ fl += MB_CPTR2LEN(p + n + fl);
+ mch_memmove(p, p + n, fl);
+ mb_char2bytes(c, p + fl);
+ stack[depth].ts_fidxtry = sp->ts_fidx + n + fl;
+ }
+ else
+ {
+ c = *p;
+ *p = p[1];
+ p[1] = p[2];
+ p[2] = c;
+ stack[depth].ts_fidxtry = sp->ts_fidx + 3;
+ }
+ }
+ else
+ {
+ PROF_STORE(sp->ts_state)
+ sp->ts_state = STATE_REP_INI;
+ }
+ break;
+
+ case STATE_UNROT3L:
+ /* Undo ROT3L: "231" -> "123" */
+ p = fword + sp->ts_fidx;
+ if (has_mbyte)
+ {
+ n = MB_PTR2LEN(p);
+ n += MB_PTR2LEN(p + n);
+ c = mb_ptr2char(p + n);
+ tl = MB_PTR2LEN(p + n);
+ mch_memmove(p + tl, p, n);
+ mb_char2bytes(c, p);
+ }
+ else
+ {
+ c = p[2];
+ p[2] = p[1];
+ p[1] = *p;
+ *p = c;
+ }
+
+ /* Rotate three bytes right: "123" -> "312". We change "fword"
+ * here, it's changed back afterwards at STATE_UNROT3R. */
+ if (TRY_DEEPER(su, stack, depth, SCORE_SWAP3))
+ {
+ go_deeper(stack, depth, SCORE_SWAP3);
+#ifdef DEBUG_TRIEWALK
+ p = fword + sp->ts_fidx;
+ sprintf(changename[depth], "%.*s-%s: rotate right %c%c%c",
+ sp->ts_twordlen, tword, fword + sp->ts_fidx,
+ p[0], p[1], p[2]);
+#endif
+ PROF_STORE(sp->ts_state)
+ sp->ts_state = STATE_UNROT3R;
+ ++depth;
+ p = fword + sp->ts_fidx;
+ if (has_mbyte)
+ {
+ n = MB_CPTR2LEN(p);
+ n += MB_CPTR2LEN(p + n);
+ c = mb_ptr2char(p + n);
+ tl = MB_CPTR2LEN(p + n);
+ mch_memmove(p + tl, p, n);
+ mb_char2bytes(c, p);
+ stack[depth].ts_fidxtry = sp->ts_fidx + n + tl;
+ }
+ else
+ {
+ c = p[2];
+ p[2] = p[1];
+ p[1] = *p;
+ *p = c;
+ stack[depth].ts_fidxtry = sp->ts_fidx + 3;
+ }
+ }
+ else
+ {
+ PROF_STORE(sp->ts_state)
+ sp->ts_state = STATE_REP_INI;
+ }
+ break;
+
+ case STATE_UNROT3R:
+ /* Undo ROT3R: "312" -> "123" */
+ p = fword + sp->ts_fidx;
+ if (has_mbyte)
+ {
+ c = mb_ptr2char(p);
+ tl = MB_PTR2LEN(p);
+ n = MB_PTR2LEN(p + tl);
+ n += MB_PTR2LEN(p + tl + n);
+ mch_memmove(p, p + tl, n);
+ mb_char2bytes(c, p + n);
+ }
+ else
+ {
+ c = *p;
+ *p = p[1];
+ p[1] = p[2];
+ p[2] = c;
+ }
+ /* FALLTHROUGH */
+
+ case STATE_REP_INI:
+ /* Check if matching with REP items from the .aff file would work.
+ * Quickly skip if:
+ * - there are no REP items and we are not in the soundfold trie
+ * - the score is going to be too high anyway
+ * - already applied a REP item or swapped here */
+ if ((lp->lp_replang == NULL && !soundfold)
+ || sp->ts_score + SCORE_REP >= su->su_maxscore
+ || sp->ts_fidx < sp->ts_fidxtry)
+ {
+ PROF_STORE(sp->ts_state)
+ sp->ts_state = STATE_FINAL;
+ break;
+ }
+
+ /* Use the first byte to quickly find the first entry that may
+ * match. If the index is -1 there is none. */
+ if (soundfold)
+ sp->ts_curi = slang->sl_repsal_first[fword[sp->ts_fidx]];
+ else
+ sp->ts_curi = lp->lp_replang->sl_rep_first[fword[sp->ts_fidx]];
+
+ if (sp->ts_curi < 0)
+ {
+ PROF_STORE(sp->ts_state)
+ sp->ts_state = STATE_FINAL;
+ break;
+ }
+
+ PROF_STORE(sp->ts_state)
+ sp->ts_state = STATE_REP;
+ /* FALLTHROUGH */
+
+ case STATE_REP:
+ /* Try matching with REP items from the .aff file. For each match
+ * replace the characters and check if the resulting word is
+ * valid. */
+ p = fword + sp->ts_fidx;
+
+ if (soundfold)
+ gap = &slang->sl_repsal;
+ else
+ gap = &lp->lp_replang->sl_rep;
+ while (sp->ts_curi < gap->ga_len)
+ {
+ ftp = (fromto_T *)gap->ga_data + sp->ts_curi++;
+ if (*ftp->ft_from != *p)
+ {
+ /* past possible matching entries */
+ sp->ts_curi = gap->ga_len;
+ break;
+ }
+ if (STRNCMP(ftp->ft_from, p, STRLEN(ftp->ft_from)) == 0
+ && TRY_DEEPER(su, stack, depth, SCORE_REP))
+ {
+ go_deeper(stack, depth, SCORE_REP);
+#ifdef DEBUG_TRIEWALK
+ sprintf(changename[depth], "%.*s-%s: replace %s with %s",
+ sp->ts_twordlen, tword, fword + sp->ts_fidx,
+ ftp->ft_from, ftp->ft_to);
+#endif
+ /* Need to undo this afterwards. */
+ PROF_STORE(sp->ts_state)
+ sp->ts_state = STATE_REP_UNDO;
+
+ /* Change the "from" to the "to" string. */
+ ++depth;
+ fl = (int)STRLEN(ftp->ft_from);
+ tl = (int)STRLEN(ftp->ft_to);
+ if (fl != tl)
+ {
+ STRMOVE(p + tl, p + fl);
+ repextra += tl - fl;
+ }
+ mch_memmove(p, ftp->ft_to, tl);
+ stack[depth].ts_fidxtry = sp->ts_fidx + tl;
+ stack[depth].ts_tcharlen = 0;
+ break;
+ }
+ }
+
+ if (sp->ts_curi >= gap->ga_len && sp->ts_state == STATE_REP)
+ {
+ /* No (more) matches. */
+ PROF_STORE(sp->ts_state)
+ sp->ts_state = STATE_FINAL;
+ }
+
+ break;
+
+ case STATE_REP_UNDO:
+ /* Undo a REP replacement and continue with the next one. */
+ if (soundfold)
+ gap = &slang->sl_repsal;
+ else
+ gap = &lp->lp_replang->sl_rep;
+ ftp = (fromto_T *)gap->ga_data + sp->ts_curi - 1;
+ fl = (int)STRLEN(ftp->ft_from);
+ tl = (int)STRLEN(ftp->ft_to);
+ p = fword + sp->ts_fidx;
+ if (fl != tl)
+ {
+ STRMOVE(p + fl, p + tl);
+ repextra -= tl - fl;
+ }
+ mch_memmove(p, ftp->ft_from, fl);
+ PROF_STORE(sp->ts_state)
+ sp->ts_state = STATE_REP;
+ break;
+
+ default:
+ /* Did all possible states at this level, go up one level. */
+ --depth;
+
+ if (depth >= 0 && stack[depth].ts_prefixdepth == PFD_PREFIXTREE)
+ {
+ /* Continue in or go back to the prefix tree. */
+ byts = pbyts;
+ idxs = pidxs;
+ }
+
+ /* Don't check for CTRL-C too often, it takes time. */
+ if (--breakcheckcount == 0)
+ {
+ ui_breakcheck();
+ breakcheckcount = 1000;
+ }
+ }
+ }
+}
+
+
+/*
+ * Go one level deeper in the tree.
+ */
+ static void
+go_deeper(trystate_T *stack, int depth, int score_add)
+{
+ stack[depth + 1] = stack[depth];
+ stack[depth + 1].ts_state = STATE_START;
+ stack[depth + 1].ts_score = stack[depth].ts_score + score_add;
+ stack[depth + 1].ts_curi = 1; /* start just after length byte */
+ stack[depth + 1].ts_flags = 0;
+}
+
+/*
+ * Case-folding may change the number of bytes: Count nr of chars in
+ * fword[flen] and return the byte length of that many chars in "word".
+ */
+ static int
+nofold_len(char_u *fword, int flen, char_u *word)
+{
+ char_u *p;
+ int i = 0;
+
+ for (p = fword; p < fword + flen; MB_PTR_ADV(p))
+ ++i;
+ for (p = word; i > 0; MB_PTR_ADV(p))
+ --i;
+ return (int)(p - word);
+}
+
+/*
+ * "fword" is a good word with case folded. Find the matching keep-case
+ * words and put it in "kword".
+ * Theoretically there could be several keep-case words that result in the
+ * same case-folded word, but we only find one...
+ */
+ static void
+find_keepcap_word(slang_T *slang, char_u *fword, char_u *kword)
+{
+ char_u uword[MAXWLEN]; /* "fword" in upper-case */
+ int depth;
+ idx_T tryidx;
+
+ /* The following arrays are used at each depth in the tree. */
+ idx_T arridx[MAXWLEN];
+ int round[MAXWLEN];
+ int fwordidx[MAXWLEN];
+ int uwordidx[MAXWLEN];
+ int kwordlen[MAXWLEN];
+
+ int flen, ulen;
+ int l;
+ int len;
+ int c;
+ idx_T lo, hi, m;
+ char_u *p;
+ char_u *byts = slang->sl_kbyts; /* array with bytes of the words */
+ idx_T *idxs = slang->sl_kidxs; /* array with indexes */
+
+ if (byts == NULL)
+ {
+ /* array is empty: "cannot happen" */
+ *kword = NUL;
+ return;
+ }
+
+ /* Make an all-cap version of "fword". */
+ allcap_copy(fword, uword);
+
+ /*
+ * Each character needs to be tried both case-folded and upper-case.
+ * All this gets very complicated if we keep in mind that changing case
+ * may change the byte length of a multi-byte character...
+ */
+ depth = 0;
+ arridx[0] = 0;
+ round[0] = 0;
+ fwordidx[0] = 0;
+ uwordidx[0] = 0;
+ kwordlen[0] = 0;
+ while (depth >= 0)
+ {
+ if (fword[fwordidx[depth]] == NUL)
+ {
+ /* We are at the end of "fword". If the tree allows a word to end
+ * here we have found a match. */
+ if (byts[arridx[depth] + 1] == 0)
+ {
+ kword[kwordlen[depth]] = NUL;
+ return;
+ }
+
+ /* kword is getting too long, continue one level up */
+ --depth;
+ }
+ else if (++round[depth] > 2)
+ {
+ /* tried both fold-case and upper-case character, continue one
+ * level up */
+ --depth;
+ }
+ else
+ {
+ /*
+ * round[depth] == 1: Try using the folded-case character.
+ * round[depth] == 2: Try using the upper-case character.
+ */
+ if (has_mbyte)
+ {
+ flen = MB_CPTR2LEN(fword + fwordidx[depth]);
+ ulen = MB_CPTR2LEN(uword + uwordidx[depth]);
+ }
+ else
+ ulen = flen = 1;
+ if (round[depth] == 1)
+ {
+ p = fword + fwordidx[depth];
+ l = flen;
+ }
+ else
+ {
+ p = uword + uwordidx[depth];
+ l = ulen;
+ }
+
+ for (tryidx = arridx[depth]; l > 0; --l)
+ {
+ /* Perform a binary search in the list of accepted bytes. */
+ len = byts[tryidx++];
+ c = *p++;
+ lo = tryidx;
+ hi = tryidx + len - 1;
+ while (lo < hi)
+ {
+ m = (lo + hi) / 2;
+ if (byts[m] > c)
+ hi = m - 1;
+ else if (byts[m] < c)
+ lo = m + 1;
+ else
+ {
+ lo = hi = m;
+ break;
+ }
+ }
+
+ /* Stop if there is no matching byte. */
+ if (hi < lo || byts[lo] != c)
+ break;
+
+ /* Continue at the child (if there is one). */
+ tryidx = idxs[lo];
+ }
+
+ if (l == 0)
+ {
+ /*
+ * Found the matching char. Copy it to "kword" and go a
+ * level deeper.
+ */
+ if (round[depth] == 1)
+ {
+ STRNCPY(kword + kwordlen[depth], fword + fwordidx[depth],
+ flen);
+ kwordlen[depth + 1] = kwordlen[depth] + flen;
+ }
+ else
+ {
+ STRNCPY(kword + kwordlen[depth], uword + uwordidx[depth],
+ ulen);
+ kwordlen[depth + 1] = kwordlen[depth] + ulen;
+ }
+ fwordidx[depth + 1] = fwordidx[depth] + flen;
+ uwordidx[depth + 1] = uwordidx[depth] + ulen;
+
+ ++depth;
+ arridx[depth] = tryidx;
+ round[depth] = 0;
+ }
+ }
+ }
+
+ /* Didn't find it: "cannot happen". */
+ *kword = NUL;
+}
+
+/*
+ * Compute the sound-a-like score for suggestions in su->su_ga and add them to
+ * su->su_sga.
+ */
+ static void
+score_comp_sal(suginfo_T *su)
+{
+ langp_T *lp;
+ char_u badsound[MAXWLEN];
+ int i;
+ suggest_T *stp;
+ suggest_T *sstp;
+ int score;
+ int lpi;
+
+ if (ga_grow(&su->su_sga, su->su_ga.ga_len) == FAIL)
+ return;
+
+ /* Use the sound-folding of the first language that supports it. */
+ for (lpi = 0; lpi < curwin->w_s->b_langp.ga_len; ++lpi)
+ {
+ lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi);
+ if (lp->lp_slang->sl_sal.ga_len > 0)
+ {
+ /* soundfold the bad word */
+ spell_soundfold(lp->lp_slang, su->su_fbadword, TRUE, badsound);
+
+ for (i = 0; i < su->su_ga.ga_len; ++i)
+ {
+ stp = &SUG(su->su_ga, i);
+
+ /* Case-fold the suggested word, sound-fold it and compute the
+ * sound-a-like score. */
+ score = stp_sal_score(stp, su, lp->lp_slang, badsound);
+ if (score < SCORE_MAXMAX)
+ {
+ /* Add the suggestion. */
+ sstp = &SUG(su->su_sga, su->su_sga.ga_len);
+ sstp->st_word = vim_strsave(stp->st_word);
+ if (sstp->st_word != NULL)
+ {
+ sstp->st_wordlen = stp->st_wordlen;
+ sstp->st_score = score;
+ sstp->st_altscore = 0;
+ sstp->st_orglen = stp->st_orglen;
+ ++su->su_sga.ga_len;
+ }
+ }
+ }
+ break;
+ }
+ }
+}
+
+/*
+ * Combine the list of suggestions in su->su_ga and su->su_sga.
+ * They are entwined.
+ */
+ static void
+score_combine(suginfo_T *su)
+{
+ int i;
+ int j;
+ garray_T ga;
+ garray_T *gap;
+ langp_T *lp;
+ suggest_T *stp;
+ char_u *p;
+ char_u badsound[MAXWLEN];
+ int round;
+ int lpi;
+ slang_T *slang = NULL;
+
+ /* Add the alternate score to su_ga. */
+ for (lpi = 0; lpi < curwin->w_s->b_langp.ga_len; ++lpi)
+ {
+ lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi);
+ if (lp->lp_slang->sl_sal.ga_len > 0)
+ {
+ /* soundfold the bad word */
+ slang = lp->lp_slang;
+ spell_soundfold(slang, su->su_fbadword, TRUE, badsound);
+
+ for (i = 0; i < su->su_ga.ga_len; ++i)
+ {
+ stp = &SUG(su->su_ga, i);
+ stp->st_altscore = stp_sal_score(stp, su, slang, badsound);
+ if (stp->st_altscore == SCORE_MAXMAX)
+ stp->st_score = (stp->st_score * 3 + SCORE_BIG) / 4;
+ else
+ stp->st_score = (stp->st_score * 3
+ + stp->st_altscore) / 4;
+ stp->st_salscore = FALSE;
+ }
+ break;
+ }
+ }
+
+ if (slang == NULL) /* Using "double" without sound folding. */
+ {
+ (void)cleanup_suggestions(&su->su_ga, su->su_maxscore,
+ su->su_maxcount);
+ return;
+ }
+
+ /* Add the alternate score to su_sga. */
+ for (i = 0; i < su->su_sga.ga_len; ++i)
+ {
+ stp = &SUG(su->su_sga, i);
+ stp->st_altscore = spell_edit_score(slang,
+ su->su_badword, stp->st_word);
+ if (stp->st_score == SCORE_MAXMAX)
+ stp->st_score = (SCORE_BIG * 7 + stp->st_altscore) / 8;
+ else
+ stp->st_score = (stp->st_score * 7 + stp->st_altscore) / 8;
+ stp->st_salscore = TRUE;
+ }
+
+ /* Remove bad suggestions, sort the suggestions and truncate at "maxcount"
+ * for both lists. */
+ check_suggestions(su, &su->su_ga);
+ (void)cleanup_suggestions(&su->su_ga, su->su_maxscore, su->su_maxcount);
+ check_suggestions(su, &su->su_sga);
+ (void)cleanup_suggestions(&su->su_sga, su->su_maxscore, su->su_maxcount);
+
+ ga_init2(&ga, (int)sizeof(suginfo_T), 1);
+ if (ga_grow(&ga, su->su_ga.ga_len + su->su_sga.ga_len) == FAIL)
+ return;
+
+ stp = &SUG(ga, 0);
+ for (i = 0; i < su->su_ga.ga_len || i < su->su_sga.ga_len; ++i)
+ {
+ /* round 1: get a suggestion from su_ga
+ * round 2: get a suggestion from su_sga */
+ for (round = 1; round <= 2; ++round)
+ {
+ gap = round == 1 ? &su->su_ga : &su->su_sga;
+ if (i < gap->ga_len)
+ {
+ /* Don't add a word if it's already there. */
+ p = SUG(*gap, i).st_word;
+ for (j = 0; j < ga.ga_len; ++j)
+ if (STRCMP(stp[j].st_word, p) == 0)
+ break;
+ if (j == ga.ga_len)
+ stp[ga.ga_len++] = SUG(*gap, i);
+ else
+ vim_free(p);
+ }
+ }
+ }
+
+ ga_clear(&su->su_ga);
+ ga_clear(&su->su_sga);
+
+ /* Truncate the list to the number of suggestions that will be displayed. */
+ if (ga.ga_len > su->su_maxcount)
+ {
+ for (i = su->su_maxcount; i < ga.ga_len; ++i)
+ vim_free(stp[i].st_word);
+ ga.ga_len = su->su_maxcount;
+ }
+
+ su->su_ga = ga;
+}
+
+/*
+ * For the goodword in "stp" compute the soundalike score compared to the
+ * badword.
+ */
+ static int
+stp_sal_score(
+ suggest_T *stp,
+ suginfo_T *su,
+ slang_T *slang,
+ char_u *badsound) /* sound-folded badword */
+{
+ char_u *p;
+ char_u *pbad;
+ char_u *pgood;
+ char_u badsound2[MAXWLEN];
+ char_u fword[MAXWLEN];
+ char_u goodsound[MAXWLEN];
+ char_u goodword[MAXWLEN];
+ int lendiff;
+
+ lendiff = (int)(su->su_badlen - stp->st_orglen);
+ if (lendiff >= 0)
+ pbad = badsound;
+ else
+ {
+ /* soundfold the bad word with more characters following */
+ (void)spell_casefold(su->su_badptr, stp->st_orglen, fword, MAXWLEN);
+
+ /* When joining two words the sound often changes a lot. E.g., "t he"
+ * sounds like "t h" while "the" sounds like "@". Avoid that by
+ * removing the space. Don't do it when the good word also contains a
+ * space. */
+ if (VIM_ISWHITE(su->su_badptr[su->su_badlen])
+ && *skiptowhite(stp->st_word) == NUL)
+ for (p = fword; *(p = skiptowhite(p)) != NUL; )
+ STRMOVE(p, p + 1);
+
+ spell_soundfold(slang, fword, TRUE, badsound2);
+ pbad = badsound2;
+ }
+
+ if (lendiff > 0 && stp->st_wordlen + lendiff < MAXWLEN)
+ {
+ /* Add part of the bad word to the good word, so that we soundfold
+ * what replaces the bad word. */
+ STRCPY(goodword, stp->st_word);
+ vim_strncpy(goodword + stp->st_wordlen,
+ su->su_badptr + su->su_badlen - lendiff, lendiff);
+ pgood = goodword;
+ }
+ else
+ pgood = stp->st_word;
+
+ /* Sound-fold the word and compute the score for the difference. */
+ spell_soundfold(slang, pgood, FALSE, goodsound);
+
+ return soundalike_score(goodsound, pbad);
+}
+
+/* structure used to store soundfolded words that add_sound_suggest() has
+ * handled already. */
+typedef struct
+{
+ short sft_score; /* lowest score used */
+ char_u sft_word[1]; /* soundfolded word, actually longer */
+} sftword_T;
+
+static sftword_T dumsft;
+#define HIKEY2SFT(p) ((sftword_T *)(p - (dumsft.sft_word - (char_u *)&dumsft)))
+#define HI2SFT(hi) HIKEY2SFT((hi)->hi_key)
+
+/*
+ * Prepare for calling suggest_try_soundalike().
+ */
+ static void
+suggest_try_soundalike_prep(void)
+{
+ langp_T *lp;
+ int lpi;
+ slang_T *slang;
+
+ /* Do this for all languages that support sound folding and for which a
+ * .sug file has been loaded. */
+ for (lpi = 0; lpi < curwin->w_s->b_langp.ga_len; ++lpi)
+ {
+ lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi);
+ slang = lp->lp_slang;
+ if (slang->sl_sal.ga_len > 0 && slang->sl_sbyts != NULL)
+ /* prepare the hashtable used by add_sound_suggest() */
+ hash_init(&slang->sl_sounddone);
+ }
+}
+
+/*
+ * Find suggestions by comparing the word in a sound-a-like form.
+ * Note: This doesn't support postponed prefixes.
+ */
+ static void
+suggest_try_soundalike(suginfo_T *su)
+{
+ char_u salword[MAXWLEN];
+ langp_T *lp;
+ int lpi;
+ slang_T *slang;
+
+ /* Do this for all languages that support sound folding and for which a
+ * .sug file has been loaded. */
+ for (lpi = 0; lpi < curwin->w_s->b_langp.ga_len; ++lpi)
+ {
+ lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi);
+ slang = lp->lp_slang;
+ if (slang->sl_sal.ga_len > 0 && slang->sl_sbyts != NULL)
+ {
+ /* soundfold the bad word */
+ spell_soundfold(slang, su->su_fbadword, TRUE, salword);
+
+ /* try all kinds of inserts/deletes/swaps/etc. */
+ /* TODO: also soundfold the next words, so that we can try joining
+ * and splitting */
+#ifdef SUGGEST_PROFILE
+ prof_init();
+#endif
+ suggest_trie_walk(su, lp, salword, TRUE);
+#ifdef SUGGEST_PROFILE
+ prof_report("soundalike");
+#endif
+ }
+ }
+}
+
+/*
+ * Finish up after calling suggest_try_soundalike().
+ */
+ static void
+suggest_try_soundalike_finish(void)
+{
+ langp_T *lp;
+ int lpi;
+ slang_T *slang;
+ int todo;
+ hashitem_T *hi;
+
+ /* Do this for all languages that support sound folding and for which a
+ * .sug file has been loaded. */
+ for (lpi = 0; lpi < curwin->w_s->b_langp.ga_len; ++lpi)
+ {
+ lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi);
+ slang = lp->lp_slang;
+ if (slang->sl_sal.ga_len > 0 && slang->sl_sbyts != NULL)
+ {
+ /* Free the info about handled words. */
+ todo = (int)slang->sl_sounddone.ht_used;
+ for (hi = slang->sl_sounddone.ht_array; todo > 0; ++hi)
+ if (!HASHITEM_EMPTY(hi))
+ {
+ vim_free(HI2SFT(hi));
+ --todo;
+ }
+
+ /* Clear the hashtable, it may also be used by another region. */
+ hash_clear(&slang->sl_sounddone);
+ hash_init(&slang->sl_sounddone);
+ }
+ }
+}
+
+/*
+ * A match with a soundfolded word is found. Add the good word(s) that
+ * produce this soundfolded word.
+ */
+ static void
+add_sound_suggest(
+ suginfo_T *su,
+ char_u *goodword,
+ int score, /* soundfold score */
+ langp_T *lp)
+{
+ slang_T *slang = lp->lp_slang; /* language for sound folding */
+ int sfwordnr;
+ char_u *nrline;
+ int orgnr;
+ char_u theword[MAXWLEN];
+ int i;
+ int wlen;
+ char_u *byts;
+ idx_T *idxs;
+ int n;
+ int wordcount;
+ int wc;
+ int goodscore;
+ hash_T hash;
+ hashitem_T *hi;
+ sftword_T *sft;
+ int bc, gc;
+ int limit;
+
+ /*
+ * It's very well possible that the same soundfold word is found several
+ * times with different scores. Since the following is quite slow only do
+ * the words that have a better score than before. Use a hashtable to
+ * remember the words that have been done.
+ */
+ hash = hash_hash(goodword);
+ hi = hash_lookup(&slang->sl_sounddone, goodword, hash);
+ if (HASHITEM_EMPTY(hi))
+ {
+ sft = (sftword_T *)alloc((unsigned)(sizeof(sftword_T)
+ + STRLEN(goodword)));
+ if (sft != NULL)
+ {
+ sft->sft_score = score;
+ STRCPY(sft->sft_word, goodword);
+ hash_add_item(&slang->sl_sounddone, hi, sft->sft_word, hash);
+ }
+ }
+ else
+ {
+ sft = HI2SFT(hi);
+ if (score >= sft->sft_score)
+ return;
+ sft->sft_score = score;
+ }
+
+ /*
+ * Find the word nr in the soundfold tree.
+ */
+ sfwordnr = soundfold_find(slang, goodword);
+ if (sfwordnr < 0)
+ {
+ internal_error("add_sound_suggest()");
+ return;
+ }
+
+ /*
+ * go over the list of good words that produce this soundfold word
+ */
+ nrline = ml_get_buf(slang->sl_sugbuf, (linenr_T)(sfwordnr + 1), FALSE);
+ orgnr = 0;
+ while (*nrline != NUL)
+ {
+ /* The wordnr was stored in a minimal nr of bytes as an offset to the
+ * previous wordnr. */
+ orgnr += bytes2offset(&nrline);
+
+ byts = slang->sl_fbyts;
+ idxs = slang->sl_fidxs;
+
+ /* Lookup the word "orgnr" one of the two tries. */
+ n = 0;
+ wordcount = 0;
+ for (wlen = 0; wlen < MAXWLEN - 3; ++wlen)
+ {
+ i = 1;
+ if (wordcount == orgnr && byts[n + 1] == NUL)
+ break; /* found end of word */
+
+ if (byts[n + 1] == NUL)
+ ++wordcount;
+
+ /* skip over the NUL bytes */
+ for ( ; byts[n + i] == NUL; ++i)
+ if (i > byts[n]) /* safety check */
+ {
+ STRCPY(theword + wlen, "BAD");
+ wlen += 3;
+ goto badword;
+ }
+
+ /* One of the siblings must have the word. */
+ for ( ; i < byts[n]; ++i)
+ {
+ wc = idxs[idxs[n + i]]; /* nr of words under this byte */
+ if (wordcount + wc > orgnr)
+ break;
+ wordcount += wc;
+ }
+
+ theword[wlen] = byts[n + i];
+ n = idxs[n + i];
+ }
+badword:
+ theword[wlen] = NUL;
+
+ /* Go over the possible flags and regions. */
+ for (; i <= byts[n] && byts[n + i] == NUL; ++i)
+ {
+ char_u cword[MAXWLEN];
+ char_u *p;
+ int flags = (int)idxs[n + i];
+
+ /* Skip words with the NOSUGGEST flag */
+ if (flags & WF_NOSUGGEST)
+ continue;
+
+ if (flags & WF_KEEPCAP)
+ {
+ /* Must find the word in the keep-case tree. */
+ find_keepcap_word(slang, theword, cword);
+ p = cword;
+ }
+ else
+ {
+ flags |= su->su_badflags;
+ if ((flags & WF_CAPMASK) != 0)
+ {
+ /* Need to fix case according to "flags". */
+ make_case_word(theword, cword, flags);
+ p = cword;
+ }
+ else
+ p = theword;
+ }
+
+ /* Add the suggestion. */
+ if (sps_flags & SPS_DOUBLE)
+ {
+ /* Add the suggestion if the score isn't too bad. */
+ if (score <= su->su_maxscore)
+ add_suggestion(su, &su->su_sga, p, su->su_badlen,
+ score, 0, FALSE, slang, FALSE);
+ }
+ else
+ {
+ /* Add a penalty for words in another region. */
+ if ((flags & WF_REGION)
+ && (((unsigned)flags >> 16) & lp->lp_region) == 0)
+ goodscore = SCORE_REGION;
+ else
+ goodscore = 0;
+
+ /* Add a small penalty for changing the first letter from
+ * lower to upper case. Helps for "tath" -> "Kath", which is
+ * less common than "tath" -> "path". Don't do it when the
+ * letter is the same, that has already been counted. */
+ gc = PTR2CHAR(p);
+ if (SPELL_ISUPPER(gc))
+ {
+ bc = PTR2CHAR(su->su_badword);
+ if (!SPELL_ISUPPER(bc)
+ && SPELL_TOFOLD(bc) != SPELL_TOFOLD(gc))
+ goodscore += SCORE_ICASE / 2;
+ }
+
+ /* Compute the score for the good word. This only does letter
+ * insert/delete/swap/replace. REP items are not considered,
+ * which may make the score a bit higher.
+ * Use a limit for the score to make it work faster. Use
+ * MAXSCORE(), because RESCORE() will change the score.
+ * If the limit is very high then the iterative method is
+ * inefficient, using an array is quicker. */
+ limit = MAXSCORE(su->su_sfmaxscore - goodscore, score);
+ if (limit > SCORE_LIMITMAX)
+ goodscore += spell_edit_score(slang, su->su_badword, p);
+ else
+ goodscore += spell_edit_score_limit(slang, su->su_badword,
+ p, limit);
+
+ /* When going over the limit don't bother to do the rest. */
+ if (goodscore < SCORE_MAXMAX)
+ {
+ /* Give a bonus to words seen before. */
+ goodscore = score_wordcount_adj(slang, goodscore, p, FALSE);
+
+ /* Add the suggestion if the score isn't too bad. */
+ goodscore = RESCORE(goodscore, score);
+ if (goodscore <= su->su_sfmaxscore)
+ add_suggestion(su, &su->su_ga, p, su->su_badlen,
+ goodscore, score, TRUE, slang, TRUE);
+ }
+ }
+ }
+ /* smsg("word %s (%d): %s (%d)", sftword, sftnr, theword, orgnr); */
+ }
+}
+
+/*
+ * Find word "word" in fold-case tree for "slang" and return the word number.
+ */
+ static int
+soundfold_find(slang_T *slang, char_u *word)
+{
+ idx_T arridx = 0;
+ int len;
+ int wlen = 0;
+ int c;
+ char_u *ptr = word;
+ char_u *byts;
+ idx_T *idxs;
+ int wordnr = 0;
+
+ byts = slang->sl_sbyts;
+ idxs = slang->sl_sidxs;
+
+ for (;;)
+ {
+ /* First byte is the number of possible bytes. */
+ len = byts[arridx++];
+
+ /* If the first possible byte is a zero the word could end here.
+ * If the word ends we found the word. If not skip the NUL bytes. */
+ c = ptr[wlen];
+ if (byts[arridx] == NUL)
+ {
+ if (c == NUL)
+ break;
+
+ /* Skip over the zeros, there can be several. */
+ while (len > 0 && byts[arridx] == NUL)
+ {
+ ++arridx;
+ --len;
+ }
+ if (len == 0)
+ return -1; /* no children, word should have ended here */
+ ++wordnr;
+ }
+
+ /* If the word ends we didn't find it. */
+ if (c == NUL)
+ return -1;
+
+ /* Perform a binary search in the list of accepted bytes. */
+ if (c == TAB) /* <Tab> is handled like <Space> */
+ c = ' ';
+ while (byts[arridx] < c)
+ {
+ /* The word count is in the first idxs[] entry of the child. */
+ wordnr += idxs[idxs[arridx]];
+ ++arridx;
+ if (--len == 0) /* end of the bytes, didn't find it */
+ return -1;
+ }
+ if (byts[arridx] != c) /* didn't find the byte */
+ return -1;
+
+ /* Continue at the child (if there is one). */
+ arridx = idxs[arridx];
+ ++wlen;
+
+ /* One space in the good word may stand for several spaces in the
+ * checked word. */
+ if (c == ' ')
+ while (ptr[wlen] == ' ' || ptr[wlen] == TAB)
+ ++wlen;
+ }
+
+ return wordnr;
+}
+
+/*
+ * Copy "fword" to "cword", fixing case according to "flags".
+ */
+ static void
+make_case_word(char_u *fword, char_u *cword, int flags)
+{
+ if (flags & WF_ALLCAP)
+ /* Make it all upper-case */
+ allcap_copy(fword, cword);
+ else if (flags & WF_ONECAP)
+ /* Make the first letter upper-case */
+ onecap_copy(fword, cword, TRUE);
+ else
+ /* Use goodword as-is. */
+ STRCPY(cword, fword);
+}
+
+
+/*
+ * Return TRUE if "c1" and "c2" are similar characters according to the MAP
+ * lines in the .aff file.
+ */
+ static int
+similar_chars(slang_T *slang, int c1, int c2)
+{
+ int m1, m2;
+ char_u buf[MB_MAXBYTES + 1];
+ hashitem_T *hi;
+
+ if (c1 >= 256)
+ {
+ buf[mb_char2bytes(c1, buf)] = 0;
+ hi = hash_find(&slang->sl_map_hash, buf);
+ if (HASHITEM_EMPTY(hi))
+ m1 = 0;
+ else
+ m1 = mb_ptr2char(hi->hi_key + STRLEN(hi->hi_key) + 1);
+ }
+ else
+ m1 = slang->sl_map_array[c1];
+ if (m1 == 0)
+ return FALSE;
+
+
+ if (c2 >= 256)
+ {
+ buf[mb_char2bytes(c2, buf)] = 0;
+ hi = hash_find(&slang->sl_map_hash, buf);
+ if (HASHITEM_EMPTY(hi))
+ m2 = 0;
+ else
+ m2 = mb_ptr2char(hi->hi_key + STRLEN(hi->hi_key) + 1);
+ }
+ else
+ m2 = slang->sl_map_array[c2];
+
+ return m1 == m2;
+}
+
+/*
+ * Add a suggestion to the list of suggestions.
+ * For a suggestion that is already in the list the lowest score is remembered.
+ */
+ static void
+add_suggestion(
+ suginfo_T *su,
+ garray_T *gap, /* either su_ga or su_sga */
+ char_u *goodword,
+ int badlenarg, /* len of bad word replaced with "goodword" */
+ int score,
+ int altscore,
+ int had_bonus, /* value for st_had_bonus */
+ slang_T *slang, /* language for sound folding */
+ int maxsf) /* su_maxscore applies to soundfold score,
+ su_sfmaxscore to the total score. */
+{
+ int goodlen; /* len of goodword changed */
+ int badlen; /* len of bad word changed */
+ suggest_T *stp;
+ suggest_T new_sug;
+ int i;
+ char_u *pgood, *pbad;
+
+ /* Minimize "badlen" for consistency. Avoids that changing "the the" to
+ * "thee the" is added next to changing the first "the" the "thee". */
+ pgood = goodword + STRLEN(goodword);
+ pbad = su->su_badptr + badlenarg;
+ for (;;)
+ {
+ goodlen = (int)(pgood - goodword);
+ badlen = (int)(pbad - su->su_badptr);
+ if (goodlen <= 0 || badlen <= 0)
+ break;
+ MB_PTR_BACK(goodword, pgood);
+ MB_PTR_BACK(su->su_badptr, pbad);
+ if (has_mbyte)
+ {
+ if (mb_ptr2char(pgood) != mb_ptr2char(pbad))
+ break;
+ }
+ else if (*pgood != *pbad)
+ break;
+ }
+
+ if (badlen == 0 && goodlen == 0)
+ /* goodword doesn't change anything; may happen for "the the" changing
+ * the first "the" to itself. */
+ return;
+
+ if (gap->ga_len == 0)
+ i = -1;
+ else
+ {
+ /* Check if the word is already there. Also check the length that is
+ * being replaced "thes," -> "these" is a different suggestion from
+ * "thes" -> "these". */
+ stp = &SUG(*gap, 0);
+ for (i = gap->ga_len; --i >= 0; ++stp)
+ if (stp->st_wordlen == goodlen
+ && stp->st_orglen == badlen
+ && STRNCMP(stp->st_word, goodword, goodlen) == 0)
+ {
+ /*
+ * Found it. Remember the word with the lowest score.
+ */
+ if (stp->st_slang == NULL)
+ stp->st_slang = slang;
+
+ new_sug.st_score = score;
+ new_sug.st_altscore = altscore;
+ new_sug.st_had_bonus = had_bonus;
+
+ if (stp->st_had_bonus != had_bonus)
+ {
+ /* Only one of the two had the soundalike score computed.
+ * Need to do that for the other one now, otherwise the
+ * scores can't be compared. This happens because
+ * suggest_try_change() doesn't compute the soundalike
+ * word to keep it fast, while some special methods set
+ * the soundalike score to zero. */
+ if (had_bonus)
+ rescore_one(su, stp);
+ else
+ {
+ new_sug.st_word = stp->st_word;
+ new_sug.st_wordlen = stp->st_wordlen;
+ new_sug.st_slang = stp->st_slang;
+ new_sug.st_orglen = badlen;
+ rescore_one(su, &new_sug);
+ }
+ }
+
+ if (stp->st_score > new_sug.st_score)
+ {
+ stp->st_score = new_sug.st_score;
+ stp->st_altscore = new_sug.st_altscore;
+ stp->st_had_bonus = new_sug.st_had_bonus;
+ }
+ break;
+ }
+ }
+
+ if (i < 0 && ga_grow(gap, 1) == OK)
+ {
+ /* Add a suggestion. */
+ stp = &SUG(*gap, gap->ga_len);
+ stp->st_word = vim_strnsave(goodword, goodlen);
+ if (stp->st_word != NULL)
+ {
+ stp->st_wordlen = goodlen;
+ stp->st_score = score;
+ stp->st_altscore = altscore;
+ stp->st_had_bonus = had_bonus;
+ stp->st_orglen = badlen;
+ stp->st_slang = slang;
+ ++gap->ga_len;
+
+ /* If we have too many suggestions now, sort the list and keep
+ * the best suggestions. */
+ if (gap->ga_len > SUG_MAX_COUNT(su))
+ {
+ if (maxsf)
+ su->su_sfmaxscore = cleanup_suggestions(gap,
+ su->su_sfmaxscore, SUG_CLEAN_COUNT(su));
+ else
+ su->su_maxscore = cleanup_suggestions(gap,
+ su->su_maxscore, SUG_CLEAN_COUNT(su));
+ }
+ }
+ }
+}
+
+/*
+ * Suggestions may in fact be flagged as errors. Esp. for banned words and
+ * for split words, such as "the the". Remove these from the list here.
+ */
+ static void
+check_suggestions(
+ suginfo_T *su,
+ garray_T *gap) /* either su_ga or su_sga */
+{
+ suggest_T *stp;
+ int i;
+ char_u longword[MAXWLEN + 1];
+ int len;
+ hlf_T attr;
+
+ stp = &SUG(*gap, 0);
+ for (i = gap->ga_len - 1; i >= 0; --i)
+ {
+ /* Need to append what follows to check for "the the". */
+ vim_strncpy(longword, stp[i].st_word, MAXWLEN);
+ len = stp[i].st_wordlen;
+ vim_strncpy(longword + len, su->su_badptr + stp[i].st_orglen,
+ MAXWLEN - len);
+ attr = HLF_COUNT;
+ (void)spell_check(curwin, longword, &attr, NULL, FALSE);
+ if (attr != HLF_COUNT)
+ {
+ /* Remove this entry. */
+ vim_free(stp[i].st_word);
+ --gap->ga_len;
+ if (i < gap->ga_len)
+ mch_memmove(stp + i, stp + i + 1,
+ sizeof(suggest_T) * (gap->ga_len - i));
+ }
+ }
+}
+
+
+/*
+ * Add a word to be banned.
+ */
+ static void
+add_banned(
+ suginfo_T *su,
+ char_u *word)
+{
+ char_u *s;
+ hash_T hash;
+ hashitem_T *hi;
+
+ hash = hash_hash(word);
+ hi = hash_lookup(&su->su_banned, word, hash);
+ if (HASHITEM_EMPTY(hi))
+ {
+ s = vim_strsave(word);
+ if (s != NULL)
+ hash_add_item(&su->su_banned, hi, s, hash);
+ }
+}
+
+/*
+ * Recompute the score for all suggestions if sound-folding is possible. This
+ * is slow, thus only done for the final results.
+ */
+ static void
+rescore_suggestions(suginfo_T *su)
+{
+ int i;
+
+ if (su->su_sallang != NULL)
+ for (i = 0; i < su->su_ga.ga_len; ++i)
+ rescore_one(su, &SUG(su->su_ga, i));
+}
+
+/*
+ * Recompute the score for one suggestion if sound-folding is possible.
+ */
+ static void
+rescore_one(suginfo_T *su, suggest_T *stp)
+{
+ slang_T *slang = stp->st_slang;
+ char_u sal_badword[MAXWLEN];
+ char_u *p;
+
+ /* Only rescore suggestions that have no sal score yet and do have a
+ * language. */
+ if (slang != NULL && slang->sl_sal.ga_len > 0 && !stp->st_had_bonus)
+ {
+ if (slang == su->su_sallang)
+ p = su->su_sal_badword;
+ else
+ {
+ spell_soundfold(slang, su->su_fbadword, TRUE, sal_badword);
+ p = sal_badword;
+ }
+
+ stp->st_altscore = stp_sal_score(stp, su, slang, p);
+ if (stp->st_altscore == SCORE_MAXMAX)
+ stp->st_altscore = SCORE_BIG;
+ stp->st_score = RESCORE(stp->st_score, stp->st_altscore);
+ stp->st_had_bonus = TRUE;
+ }
+}
+
+static int
+#ifdef __BORLANDC__
+_RTLENTRYF
+#endif
+sug_compare(const void *s1, const void *s2);
+
+/*
+ * Function given to qsort() to sort the suggestions on st_score.
+ * First on "st_score", then "st_altscore" then alphabetically.
+ */
+ static int
+#ifdef __BORLANDC__
+_RTLENTRYF
+#endif
+sug_compare(const void *s1, const void *s2)
+{
+ suggest_T *p1 = (suggest_T *)s1;
+ suggest_T *p2 = (suggest_T *)s2;
+ int n = p1->st_score - p2->st_score;
+
+ if (n == 0)
+ {
+ n = p1->st_altscore - p2->st_altscore;
+ if (n == 0)
+ n = STRICMP(p1->st_word, p2->st_word);
+ }
+ return n;
+}
+
+/*
+ * Cleanup the suggestions:
+ * - Sort on score.
+ * - Remove words that won't be displayed.
+ * Returns the maximum score in the list or "maxscore" unmodified.
+ */
+ static int
+cleanup_suggestions(
+ garray_T *gap,
+ int maxscore,
+ int keep) /* nr of suggestions to keep */
+{
+ suggest_T *stp = &SUG(*gap, 0);
+ int i;
+
+ /* Sort the list. */
+ qsort(gap->ga_data, (size_t)gap->ga_len, sizeof(suggest_T), sug_compare);
+
+ /* Truncate the list to the number of suggestions that will be displayed. */
+ if (gap->ga_len > keep)
+ {
+ for (i = keep; i < gap->ga_len; ++i)
+ vim_free(stp[i].st_word);
+ gap->ga_len = keep;
+ return stp[keep - 1].st_score;
+ }
+ return maxscore;
+}
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * Soundfold a string, for soundfold().
+ * Result is in allocated memory, NULL for an error.
+ */
+ char_u *
+eval_soundfold(char_u *word)
+{
+ langp_T *lp;
+ char_u sound[MAXWLEN];
+ int lpi;
+
+ if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
+ /* Use the sound-folding of the first language that supports it. */
+ for (lpi = 0; lpi < curwin->w_s->b_langp.ga_len; ++lpi)
+ {
+ lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi);
+ if (lp->lp_slang->sl_sal.ga_len > 0)
+ {
+ /* soundfold the word */
+ spell_soundfold(lp->lp_slang, word, FALSE, sound);
+ return vim_strsave(sound);
+ }
+ }
+
+ /* No language with sound folding, return word as-is. */
+ return vim_strsave(word);
+}
+#endif
+
+/*
+ * Turn "inword" into its sound-a-like equivalent in "res[MAXWLEN]".
+ *
+ * There are many ways to turn a word into a sound-a-like representation. The
+ * oldest is Soundex (1918!). A nice overview can be found in "Approximate
+ * swedish name matching - survey and test of different algorithms" by Klas
+ * Erikson.
+ *
+ * We support two methods:
+ * 1. SOFOFROM/SOFOTO do a simple character mapping.
+ * 2. SAL items define a more advanced sound-folding (and much slower).
+ */
+ void
+spell_soundfold(
+ slang_T *slang,
+ char_u *inword,
+ int folded, /* "inword" is already case-folded */
+ char_u *res)
+{
+ char_u fword[MAXWLEN];
+ char_u *word;
+
+ if (slang->sl_sofo)
+ /* SOFOFROM and SOFOTO used */
+ spell_soundfold_sofo(slang, inword, res);
+ else
+ {
+ /* SAL items used. Requires the word to be case-folded. */
+ if (folded)
+ word = inword;
+ else
+ {
+ (void)spell_casefold(inword, (int)STRLEN(inword), fword, MAXWLEN);
+ word = fword;
+ }
+
+ if (has_mbyte)
+ spell_soundfold_wsal(slang, word, res);
+ else
+ spell_soundfold_sal(slang, word, res);
+ }
+}
+
+/*
+ * Perform sound folding of "inword" into "res" according to SOFOFROM and
+ * SOFOTO lines.
+ */
+ static void
+spell_soundfold_sofo(slang_T *slang, char_u *inword, char_u *res)
+{
+ char_u *s;
+ int ri = 0;
+ int c;
+
+ if (has_mbyte)
+ {
+ int prevc = 0;
+ int *ip;
+
+ /* The sl_sal_first[] table contains the translation for chars up to
+ * 255, sl_sal the rest. */
+ for (s = inword; *s != NUL; )
+ {
+ c = mb_cptr2char_adv(&s);
+ if (enc_utf8 ? utf_class(c) == 0 : VIM_ISWHITE(c))
+ c = ' ';
+ else if (c < 256)
+ c = slang->sl_sal_first[c];
+ else
+ {
+ ip = ((int **)slang->sl_sal.ga_data)[c & 0xff];
+ if (ip == NULL) /* empty list, can't match */
+ c = NUL;
+ else
+ for (;;) /* find "c" in the list */
+ {
+ if (*ip == 0) /* not found */
+ {
+ c = NUL;
+ break;
+ }
+ if (*ip == c) /* match! */
+ {
+ c = ip[1];
+ break;
+ }
+ ip += 2;
+ }
+ }
+
+ if (c != NUL && c != prevc)
+ {
+ ri += mb_char2bytes(c, res + ri);
+ if (ri + MB_MAXBYTES > MAXWLEN)
+ break;
+ prevc = c;
+ }
+ }
+ }
+ else
+ {
+ /* The sl_sal_first[] table contains the translation. */
+ for (s = inword; (c = *s) != NUL; ++s)
+ {
+ if (VIM_ISWHITE(c))
+ c = ' ';
+ else
+ c = slang->sl_sal_first[c];
+ if (c != NUL && (ri == 0 || res[ri - 1] != c))
+ res[ri++] = c;
+ }
+ }
+
+ res[ri] = NUL;
+}
+
+ static void
+spell_soundfold_sal(slang_T *slang, char_u *inword, char_u *res)
+{
+ salitem_T *smp;
+ char_u word[MAXWLEN];
+ char_u *s = inword;
+ char_u *t;
+ char_u *pf;
+ int i, j, z;
+ int reslen;
+ int n, k = 0;
+ int z0;
+ int k0;
+ int n0;
+ int c;
+ int pri;
+ int p0 = -333;
+ int c0;
+
+ /* Remove accents, if wanted. We actually remove all non-word characters.
+ * But keep white space. We need a copy, the word may be changed here. */
+ if (slang->sl_rem_accents)
+ {
+ t = word;
+ while (*s != NUL)
+ {
+ if (VIM_ISWHITE(*s))
+ {
+ *t++ = ' ';
+ s = skipwhite(s);
+ }
+ else
+ {
+ if (spell_iswordp_nmw(s, curwin))
+ *t++ = *s;
+ ++s;
+ }
+ }
+ *t = NUL;
+ }
+ else
+ vim_strncpy(word, s, MAXWLEN - 1);
+
+ smp = (salitem_T *)slang->sl_sal.ga_data;
+
+ /*
+ * This comes from Aspell phonet.cpp. Converted from C++ to C.
+ * Changed to keep spaces.
+ */
+ i = reslen = z = 0;
+ while ((c = word[i]) != NUL)
+ {
+ /* Start with the first rule that has the character in the word. */
+ n = slang->sl_sal_first[c];
+ z0 = 0;
+
+ if (n >= 0)
+ {
+ /* check all rules for the same letter */
+ for (; (s = smp[n].sm_lead)[0] == c; ++n)
+ {
+ /* Quickly skip entries that don't match the word. Most
+ * entries are less then three chars, optimize for that. */
+ k = smp[n].sm_leadlen;
+ if (k > 1)
+ {
+ if (word[i + 1] != s[1])
+ continue;
+ if (k > 2)
+ {
+ for (j = 2; j < k; ++j)
+ if (word[i + j] != s[j])
+ break;
+ if (j < k)
+ continue;
+ }
+ }
+
+ if ((pf = smp[n].sm_oneof) != NULL)
+ {
+ /* Check for match with one of the chars in "sm_oneof". */
+ while (*pf != NUL && *pf != word[i + k])
+ ++pf;
+ if (*pf == NUL)
+ continue;
+ ++k;
+ }
+ s = smp[n].sm_rules;
+ pri = 5; /* default priority */
+
+ p0 = *s;
+ k0 = k;
+ while (*s == '-' && k > 1)
+ {
+ k--;
+ s++;
+ }
+ if (*s == '<')
+ s++;
+ if (VIM_ISDIGIT(*s))
+ {
+ /* determine priority */
+ pri = *s - '0';
+ s++;
+ }
+ if (*s == '^' && *(s + 1) == '^')
+ s++;
+
+ if (*s == NUL
+ || (*s == '^'
+ && (i == 0 || !(word[i - 1] == ' '
+ || spell_iswordp(word + i - 1, curwin)))
+ && (*(s + 1) != '$'
+ || (!spell_iswordp(word + i + k0, curwin))))
+ || (*s == '$' && i > 0
+ && spell_iswordp(word + i - 1, curwin)
+ && (!spell_iswordp(word + i + k0, curwin))))
+ {
+ /* search for followup rules, if: */
+ /* followup and k > 1 and NO '-' in searchstring */
+ c0 = word[i + k - 1];
+ n0 = slang->sl_sal_first[c0];
+
+ if (slang->sl_followup && k > 1 && n0 >= 0
+ && p0 != '-' && word[i + k] != NUL)
+ {
+ /* test follow-up rule for "word[i + k]" */
+ for ( ; (s = smp[n0].sm_lead)[0] == c0; ++n0)
+ {
+ /* Quickly skip entries that don't match the word.
+ * */
+ k0 = smp[n0].sm_leadlen;
+ if (k0 > 1)
+ {
+ if (word[i + k] != s[1])
+ continue;
+ if (k0 > 2)
+ {
+ pf = word + i + k + 1;
+ for (j = 2; j < k0; ++j)
+ if (*pf++ != s[j])
+ break;
+ if (j < k0)
+ continue;
+ }
+ }
+ k0 += k - 1;
+
+ if ((pf = smp[n0].sm_oneof) != NULL)
+ {
+ /* Check for match with one of the chars in
+ * "sm_oneof". */
+ while (*pf != NUL && *pf != word[i + k0])
+ ++pf;
+ if (*pf == NUL)
+ continue;
+ ++k0;
+ }
+
+ p0 = 5;
+ s = smp[n0].sm_rules;
+ while (*s == '-')
+ {
+ /* "k0" gets NOT reduced because
+ * "if (k0 == k)" */
+ s++;
+ }
+ if (*s == '<')
+ s++;
+ if (VIM_ISDIGIT(*s))
+ {
+ p0 = *s - '0';
+ s++;
+ }
+
+ if (*s == NUL
+ /* *s == '^' cuts */
+ || (*s == '$'
+ && !spell_iswordp(word + i + k0,
+ curwin)))
+ {
+ if (k0 == k)
+ /* this is just a piece of the string */
+ continue;
+
+ if (p0 < pri)
+ /* priority too low */
+ continue;
+ /* rule fits; stop search */
+ break;
+ }
+ }
+
+ if (p0 >= pri && smp[n0].sm_lead[0] == c0)
+ continue;
+ }
+
+ /* replace string */
+ s = smp[n].sm_to;
+ if (s == NULL)
+ s = (char_u *)"";
+ pf = smp[n].sm_rules;
+ p0 = (vim_strchr(pf, '<') != NULL) ? 1 : 0;
+ if (p0 == 1 && z == 0)
+ {
+ /* rule with '<' is used */
+ if (reslen > 0 && *s != NUL && (res[reslen - 1] == c
+ || res[reslen - 1] == *s))
+ reslen--;
+ z0 = 1;
+ z = 1;
+ k0 = 0;
+ while (*s != NUL && word[i + k0] != NUL)
+ {
+ word[i + k0] = *s;
+ k0++;
+ s++;
+ }
+ if (k > k0)
+ STRMOVE(word + i + k0, word + i + k);
+
+ /* new "actual letter" */
+ c = word[i];
+ }
+ else
+ {
+ /* no '<' rule used */
+ i += k - 1;
+ z = 0;
+ while (*s != NUL && s[1] != NUL && reslen < MAXWLEN)
+ {
+ if (reslen == 0 || res[reslen - 1] != *s)
+ res[reslen++] = *s;
+ s++;
+ }
+ /* new "actual letter" */
+ c = *s;
+ if (strstr((char *)pf, "^^") != NULL)
+ {
+ if (c != NUL)
+ res[reslen++] = c;
+ STRMOVE(word, word + i + 1);
+ i = 0;
+ z0 = 1;
+ }
+ }
+ break;
+ }
+ }
+ }
+ else if (VIM_ISWHITE(c))
+ {
+ c = ' ';
+ k = 1;
+ }
+
+ if (z0 == 0)
+ {
+ if (k && !p0 && reslen < MAXWLEN && c != NUL
+ && (!slang->sl_collapse || reslen == 0
+ || res[reslen - 1] != c))
+ /* condense only double letters */
+ res[reslen++] = c;
+
+ i++;
+ z = 0;
+ k = 0;
+ }
+ }
+
+ res[reslen] = NUL;
+}
+
+/*
+ * Turn "inword" into its sound-a-like equivalent in "res[MAXWLEN]".
+ * Multi-byte version of spell_soundfold().
+ */
+ static void
+spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res)
+{
+ salitem_T *smp = (salitem_T *)slang->sl_sal.ga_data;
+ int word[MAXWLEN];
+ int wres[MAXWLEN];
+ int l;
+ char_u *s;
+ int *ws;
+ char_u *t;
+ int *pf;
+ int i, j, z;
+ int reslen;
+ int n, k = 0;
+ int z0;
+ int k0;
+ int n0;
+ int c;
+ int pri;
+ int p0 = -333;
+ int c0;
+ int did_white = FALSE;
+ int wordlen;
+
+
+ /*
+ * Convert the multi-byte string to a wide-character string.
+ * Remove accents, if wanted. We actually remove all non-word characters.
+ * But keep white space.
+ */
+ wordlen = 0;
+ for (s = inword; *s != NUL; )
+ {
+ t = s;
+ c = mb_cptr2char_adv(&s);
+ if (slang->sl_rem_accents)
+ {
+ if (enc_utf8 ? utf_class(c) == 0 : VIM_ISWHITE(c))
+ {
+ if (did_white)
+ continue;
+ c = ' ';
+ did_white = TRUE;
+ }
+ else
+ {
+ did_white = FALSE;
+ if (!spell_iswordp_nmw(t, curwin))
+ continue;
+ }
+ }
+ word[wordlen++] = c;
+ }
+ word[wordlen] = NUL;
+
+ /*
+ * This algorithm comes from Aspell phonet.cpp.
+ * Converted from C++ to C. Added support for multi-byte chars.
+ * Changed to keep spaces.
+ */
+ i = reslen = z = 0;
+ while ((c = word[i]) != NUL)
+ {
+ /* Start with the first rule that has the character in the word. */
+ n = slang->sl_sal_first[c & 0xff];
+ z0 = 0;
+
+ if (n >= 0)
+ {
+ /* Check all rules for the same index byte.
+ * If c is 0x300 need extra check for the end of the array, as
+ * (c & 0xff) is NUL. */
+ for (; ((ws = smp[n].sm_lead_w)[0] & 0xff) == (c & 0xff)
+ && ws[0] != NUL; ++n)
+ {
+ /* Quickly skip entries that don't match the word. Most
+ * entries are less then three chars, optimize for that. */
+ if (c != ws[0])
+ continue;
+ k = smp[n].sm_leadlen;
+ if (k > 1)
+ {
+ if (word[i + 1] != ws[1])
+ continue;
+ if (k > 2)
+ {
+ for (j = 2; j < k; ++j)
+ if (word[i + j] != ws[j])
+ break;
+ if (j < k)
+ continue;
+ }
+ }
+
+ if ((pf = smp[n].sm_oneof_w) != NULL)
+ {
+ /* Check for match with one of the chars in "sm_oneof". */
+ while (*pf != NUL && *pf != word[i + k])
+ ++pf;
+ if (*pf == NUL)
+ continue;
+ ++k;
+ }
+ s = smp[n].sm_rules;
+ pri = 5; /* default priority */
+
+ p0 = *s;
+ k0 = k;
+ while (*s == '-' && k > 1)
+ {
+ k--;
+ s++;
+ }
+ if (*s == '<')
+ s++;
+ if (VIM_ISDIGIT(*s))
+ {
+ /* determine priority */
+ pri = *s - '0';
+ s++;
+ }
+ if (*s == '^' && *(s + 1) == '^')
+ s++;
+
+ if (*s == NUL
+ || (*s == '^'
+ && (i == 0 || !(word[i - 1] == ' '
+ || spell_iswordp_w(word + i - 1, curwin)))
+ && (*(s + 1) != '$'
+ || (!spell_iswordp_w(word + i + k0, curwin))))
+ || (*s == '$' && i > 0
+ && spell_iswordp_w(word + i - 1, curwin)
+ && (!spell_iswordp_w(word + i + k0, curwin))))
+ {
+ /* search for followup rules, if: */
+ /* followup and k > 1 and NO '-' in searchstring */
+ c0 = word[i + k - 1];
+ n0 = slang->sl_sal_first[c0 & 0xff];
+
+ if (slang->sl_followup && k > 1 && n0 >= 0
+ && p0 != '-' && word[i + k] != NUL)
+ {
+ /* Test follow-up rule for "word[i + k]"; loop over
+ * all entries with the same index byte. */
+ for ( ; ((ws = smp[n0].sm_lead_w)[0] & 0xff)
+ == (c0 & 0xff); ++n0)
+ {
+ /* Quickly skip entries that don't match the word.
+ */
+ if (c0 != ws[0])
+ continue;
+ k0 = smp[n0].sm_leadlen;
+ if (k0 > 1)
+ {
+ if (word[i + k] != ws[1])
+ continue;
+ if (k0 > 2)
+ {
+ pf = word + i + k + 1;
+ for (j = 2; j < k0; ++j)
+ if (*pf++ != ws[j])
+ break;
+ if (j < k0)
+ continue;
+ }
+ }
+ k0 += k - 1;
+
+ if ((pf = smp[n0].sm_oneof_w) != NULL)
+ {
+ /* Check for match with one of the chars in
+ * "sm_oneof". */
+ while (*pf != NUL && *pf != word[i + k0])
+ ++pf;
+ if (*pf == NUL)
+ continue;
+ ++k0;
+ }
+
+ p0 = 5;
+ s = smp[n0].sm_rules;
+ while (*s == '-')
+ {
+ /* "k0" gets NOT reduced because
+ * "if (k0 == k)" */
+ s++;
+ }
+ if (*s == '<')
+ s++;
+ if (VIM_ISDIGIT(*s))
+ {
+ p0 = *s - '0';
+ s++;
+ }
+
+ if (*s == NUL
+ /* *s == '^' cuts */
+ || (*s == '$'
+ && !spell_iswordp_w(word + i + k0,
+ curwin)))
+ {
+ if (k0 == k)
+ /* this is just a piece of the string */
+ continue;
+
+ if (p0 < pri)
+ /* priority too low */
+ continue;
+ /* rule fits; stop search */
+ break;
+ }
+ }
+
+ if (p0 >= pri && (smp[n0].sm_lead_w[0] & 0xff)
+ == (c0 & 0xff))
+ continue;
+ }
+
+ /* replace string */
+ ws = smp[n].sm_to_w;
+ s = smp[n].sm_rules;
+ p0 = (vim_strchr(s, '<') != NULL) ? 1 : 0;
+ if (p0 == 1 && z == 0)
+ {
+ /* rule with '<' is used */
+ if (reslen > 0 && ws != NULL && *ws != NUL
+ && (wres[reslen - 1] == c
+ || wres[reslen - 1] == *ws))
+ reslen--;
+ z0 = 1;
+ z = 1;
+ k0 = 0;
+ if (ws != NULL)
+ while (*ws != NUL && word[i + k0] != NUL)
+ {
+ word[i + k0] = *ws;
+ k0++;
+ ws++;
+ }
+ if (k > k0)
+ mch_memmove(word + i + k0, word + i + k,
+ sizeof(int) * (wordlen - (i + k) + 1));
+
+ /* new "actual letter" */
+ c = word[i];
+ }
+ else
+ {
+ /* no '<' rule used */
+ i += k - 1;
+ z = 0;
+ if (ws != NULL)
+ while (*ws != NUL && ws[1] != NUL
+ && reslen < MAXWLEN)
+ {
+ if (reslen == 0 || wres[reslen - 1] != *ws)
+ wres[reslen++] = *ws;
+ ws++;
+ }
+ /* new "actual letter" */
+ if (ws == NULL)
+ c = NUL;
+ else
+ c = *ws;
+ if (strstr((char *)s, "^^") != NULL)
+ {
+ if (c != NUL)
+ wres[reslen++] = c;
+ mch_memmove(word, word + i + 1,
+ sizeof(int) * (wordlen - (i + 1) + 1));
+ i = 0;
+ z0 = 1;
+ }
+ }
+ break;
+ }
+ }
+ }
+ else if (VIM_ISWHITE(c))
+ {
+ c = ' ';
+ k = 1;
+ }
+
+ if (z0 == 0)
+ {
+ if (k && !p0 && reslen < MAXWLEN && c != NUL
+ && (!slang->sl_collapse || reslen == 0
+ || wres[reslen - 1] != c))
+ /* condense only double letters */
+ wres[reslen++] = c;
+
+ i++;
+ z = 0;
+ k = 0;
+ }
+ }
+
+ /* Convert wide characters in "wres" to a multi-byte string in "res". */
+ l = 0;
+ for (n = 0; n < reslen; ++n)
+ {
+ l += mb_char2bytes(wres[n], res + l);
+ if (l + MB_MAXBYTES > MAXWLEN)
+ break;
+ }
+ res[l] = NUL;
+}
+
+/*
+ * Compute a score for two sound-a-like words.
+ * This permits up to two inserts/deletes/swaps/etc. to keep things fast.
+ * Instead of a generic loop we write out the code. That keeps it fast by
+ * avoiding checks that will not be possible.
+ */
+ static int
+soundalike_score(
+ char_u *goodstart, /* sound-folded good word */
+ char_u *badstart) /* sound-folded bad word */
+{
+ char_u *goodsound = goodstart;
+ char_u *badsound = badstart;
+ int goodlen;
+ int badlen;
+ int n;
+ char_u *pl, *ps;
+ char_u *pl2, *ps2;
+ int score = 0;
+
+ /* Adding/inserting "*" at the start (word starts with vowel) shouldn't be
+ * counted so much, vowels halfway the word aren't counted at all. */
+ if ((*badsound == '*' || *goodsound == '*') && *badsound != *goodsound)
+ {
+ if ((badsound[0] == NUL && goodsound[1] == NUL)
+ || (goodsound[0] == NUL && badsound[1] == NUL))
+ /* changing word with vowel to word without a sound */
+ return SCORE_DEL;
+ if (badsound[0] == NUL || goodsound[0] == NUL)
+ /* more than two changes */
+ return SCORE_MAXMAX;
+
+ if (badsound[1] == goodsound[1]
+ || (badsound[1] != NUL
+ && goodsound[1] != NUL
+ && badsound[2] == goodsound[2]))
+ {
+ /* handle like a substitute */
+ }
+ else
+ {
+ score = 2 * SCORE_DEL / 3;
+ if (*badsound == '*')
+ ++badsound;
+ else
+ ++goodsound;
+ }
+ }
+
+ goodlen = (int)STRLEN(goodsound);
+ badlen = (int)STRLEN(badsound);
+
+ /* Return quickly if the lengths are too different to be fixed by two
+ * changes. */
+ n = goodlen - badlen;
+ if (n < -2 || n > 2)
+ return SCORE_MAXMAX;
+
+ if (n > 0)
+ {
+ pl = goodsound; /* goodsound is longest */
+ ps = badsound;
+ }
+ else
+ {
+ pl = badsound; /* badsound is longest */
+ ps = goodsound;
+ }
+
+ /* Skip over the identical part. */
+ while (*pl == *ps && *pl != NUL)
+ {
+ ++pl;
+ ++ps;
+ }
+
+ switch (n)
+ {
+ case -2:
+ case 2:
+ /*
+ * Must delete two characters from "pl".
+ */
+ ++pl; /* first delete */
+ while (*pl == *ps)
+ {
+ ++pl;
+ ++ps;
+ }
+ /* strings must be equal after second delete */
+ if (STRCMP(pl + 1, ps) == 0)
+ return score + SCORE_DEL * 2;
+
+ /* Failed to compare. */
+ break;
+
+ case -1:
+ case 1:
+ /*
+ * Minimal one delete from "pl" required.
+ */
+
+ /* 1: delete */
+ pl2 = pl + 1;
+ ps2 = ps;
+ while (*pl2 == *ps2)
+ {
+ if (*pl2 == NUL) /* reached the end */
+ return score + SCORE_DEL;
+ ++pl2;
+ ++ps2;
+ }
+
+ /* 2: delete then swap, then rest must be equal */
+ if (pl2[0] == ps2[1] && pl2[1] == ps2[0]
+ && STRCMP(pl2 + 2, ps2 + 2) == 0)
+ return score + SCORE_DEL + SCORE_SWAP;
+
+ /* 3: delete then substitute, then the rest must be equal */
+ if (STRCMP(pl2 + 1, ps2 + 1) == 0)
+ return score + SCORE_DEL + SCORE_SUBST;
+
+ /* 4: first swap then delete */
+ if (pl[0] == ps[1] && pl[1] == ps[0])
+ {
+ pl2 = pl + 2; /* swap, skip two chars */
+ ps2 = ps + 2;
+ while (*pl2 == *ps2)
+ {
+ ++pl2;
+ ++ps2;
+ }
+ /* delete a char and then strings must be equal */
+ if (STRCMP(pl2 + 1, ps2) == 0)
+ return score + SCORE_SWAP + SCORE_DEL;
+ }
+
+ /* 5: first substitute then delete */
+ pl2 = pl + 1; /* substitute, skip one char */
+ ps2 = ps + 1;
+ while (*pl2 == *ps2)
+ {
+ ++pl2;
+ ++ps2;
+ }
+ /* delete a char and then strings must be equal */
+ if (STRCMP(pl2 + 1, ps2) == 0)
+ return score + SCORE_SUBST + SCORE_DEL;
+
+ /* Failed to compare. */
+ break;
+
+ case 0:
+ /*
+ * Lengths are equal, thus changes must result in same length: An
+ * insert is only possible in combination with a delete.
+ * 1: check if for identical strings
+ */
+ if (*pl == NUL)
+ return score;
+
+ /* 2: swap */
+ if (pl[0] == ps[1] && pl[1] == ps[0])
+ {
+ pl2 = pl + 2; /* swap, skip two chars */
+ ps2 = ps + 2;
+ while (*pl2 == *ps2)
+ {
+ if (*pl2 == NUL) /* reached the end */
+ return score + SCORE_SWAP;
+ ++pl2;
+ ++ps2;
+ }
+ /* 3: swap and swap again */
+ if (pl2[0] == ps2[1] && pl2[1] == ps2[0]
+ && STRCMP(pl2 + 2, ps2 + 2) == 0)
+ return score + SCORE_SWAP + SCORE_SWAP;
+
+ /* 4: swap and substitute */
+ if (STRCMP(pl2 + 1, ps2 + 1) == 0)
+ return score + SCORE_SWAP + SCORE_SUBST;
+ }
+
+ /* 5: substitute */
+ pl2 = pl + 1;
+ ps2 = ps + 1;
+ while (*pl2 == *ps2)
+ {
+ if (*pl2 == NUL) /* reached the end */
+ return score + SCORE_SUBST;
+ ++pl2;
+ ++ps2;
+ }
+
+ /* 6: substitute and swap */
+ if (pl2[0] == ps2[1] && pl2[1] == ps2[0]
+ && STRCMP(pl2 + 2, ps2 + 2) == 0)
+ return score + SCORE_SUBST + SCORE_SWAP;
+
+ /* 7: substitute and substitute */
+ if (STRCMP(pl2 + 1, ps2 + 1) == 0)
+ return score + SCORE_SUBST + SCORE_SUBST;
+
+ /* 8: insert then delete */
+ pl2 = pl;
+ ps2 = ps + 1;
+ while (*pl2 == *ps2)
+ {
+ ++pl2;
+ ++ps2;
+ }
+ if (STRCMP(pl2 + 1, ps2) == 0)
+ return score + SCORE_INS + SCORE_DEL;
+
+ /* 9: delete then insert */
+ pl2 = pl + 1;
+ ps2 = ps;
+ while (*pl2 == *ps2)
+ {
+ ++pl2;
+ ++ps2;
+ }
+ if (STRCMP(pl2, ps2 + 1) == 0)
+ return score + SCORE_INS + SCORE_DEL;
+
+ /* Failed to compare. */
+ break;
+ }
+
+ return SCORE_MAXMAX;
+}
+
+/*
+ * Compute the "edit distance" to turn "badword" into "goodword". The less
+ * deletes/inserts/substitutes/swaps are required the lower the score.
+ *
+ * The algorithm is described by Du and Chang, 1992.
+ * The implementation of the algorithm comes from Aspell editdist.cpp,
+ * edit_distance(). It has been converted from C++ to C and modified to
+ * support multi-byte characters.
+ */
+ static int
+spell_edit_score(
+ slang_T *slang,
+ char_u *badword,
+ char_u *goodword)
+{
+ int *cnt;
+ int badlen, goodlen; /* lengths including NUL */
+ int j, i;
+ int t;
+ int bc, gc;
+ int pbc, pgc;
+ char_u *p;
+ int wbadword[MAXWLEN];
+ int wgoodword[MAXWLEN];
+
+ if (has_mbyte)
+ {
+ /* Get the characters from the multi-byte strings and put them in an
+ * int array for easy access. */
+ for (p = badword, badlen = 0; *p != NUL; )
+ wbadword[badlen++] = mb_cptr2char_adv(&p);
+ wbadword[badlen++] = 0;
+ for (p = goodword, goodlen = 0; *p != NUL; )
+ wgoodword[goodlen++] = mb_cptr2char_adv(&p);
+ wgoodword[goodlen++] = 0;
+ }
+ else
+ {
+ badlen = (int)STRLEN(badword) + 1;
+ goodlen = (int)STRLEN(goodword) + 1;
+ }
+
+ /* We use "cnt" as an array: CNT(badword_idx, goodword_idx). */
+#define CNT(a, b) cnt[(a) + (b) * (badlen + 1)]
+ cnt = (int *)lalloc((long_u)(sizeof(int) * (badlen + 1) * (goodlen + 1)),
+ TRUE);
+ if (cnt == NULL)
+ return 0; /* out of memory */
+
+ CNT(0, 0) = 0;
+ for (j = 1; j <= goodlen; ++j)
+ CNT(0, j) = CNT(0, j - 1) + SCORE_INS;
+
+ for (i = 1; i <= badlen; ++i)
+ {
+ CNT(i, 0) = CNT(i - 1, 0) + SCORE_DEL;
+ for (j = 1; j <= goodlen; ++j)
+ {
+ if (has_mbyte)
+ {
+ bc = wbadword[i - 1];
+ gc = wgoodword[j - 1];
+ }
+ else
+ {
+ bc = badword[i - 1];
+ gc = goodword[j - 1];
+ }
+ if (bc == gc)
+ CNT(i, j) = CNT(i - 1, j - 1);
+ else
+ {
+ /* Use a better score when there is only a case difference. */
+ if (SPELL_TOFOLD(bc) == SPELL_TOFOLD(gc))
+ CNT(i, j) = SCORE_ICASE + CNT(i - 1, j - 1);
+ else
+ {
+ /* For a similar character use SCORE_SIMILAR. */
+ if (slang != NULL
+ && slang->sl_has_map
+ && similar_chars(slang, gc, bc))
+ CNT(i, j) = SCORE_SIMILAR + CNT(i - 1, j - 1);
+ else
+ CNT(i, j) = SCORE_SUBST + CNT(i - 1, j - 1);
+ }
+
+ if (i > 1 && j > 1)
+ {
+ if (has_mbyte)
+ {
+ pbc = wbadword[i - 2];
+ pgc = wgoodword[j - 2];
+ }
+ else
+ {
+ pbc = badword[i - 2];
+ pgc = goodword[j - 2];
+ }
+ if (bc == pgc && pbc == gc)
+ {
+ t = SCORE_SWAP + CNT(i - 2, j - 2);
+ if (t < CNT(i, j))
+ CNT(i, j) = t;
+ }
+ }
+ t = SCORE_DEL + CNT(i - 1, j);
+ if (t < CNT(i, j))
+ CNT(i, j) = t;
+ t = SCORE_INS + CNT(i, j - 1);
+ if (t < CNT(i, j))
+ CNT(i, j) = t;
+ }
+ }
+ }
+
+ i = CNT(badlen - 1, goodlen - 1);
+ vim_free(cnt);
+ return i;
+}
+
+typedef struct
+{
+ int badi;
+ int goodi;
+ int score;
+} limitscore_T;
+
+/*
+ * Like spell_edit_score(), but with a limit on the score to make it faster.
+ * May return SCORE_MAXMAX when the score is higher than "limit".
+ *
+ * This uses a stack for the edits still to be tried.
+ * The idea comes from Aspell leditdist.cpp. Rewritten in C and added support
+ * for multi-byte characters.
+ */
+ static int
+spell_edit_score_limit(
+ slang_T *slang,
+ char_u *badword,
+ char_u *goodword,
+ int limit)
+{
+ limitscore_T stack[10]; /* allow for over 3 * 2 edits */
+ int stackidx;
+ int bi, gi;
+ int bi2, gi2;
+ int bc, gc;
+ int score;
+ int score_off;
+ int minscore;
+ int round;
+
+ /* Multi-byte characters require a bit more work, use a different function
+ * to avoid testing "has_mbyte" quite often. */
+ if (has_mbyte)
+ return spell_edit_score_limit_w(slang, badword, goodword, limit);
+
+ /*
+ * The idea is to go from start to end over the words. So long as
+ * characters are equal just continue, this always gives the lowest score.
+ * When there is a difference try several alternatives. Each alternative
+ * increases "score" for the edit distance. Some of the alternatives are
+ * pushed unto a stack and tried later, some are tried right away. At the
+ * end of the word the score for one alternative is known. The lowest
+ * possible score is stored in "minscore".
+ */
+ stackidx = 0;
+ bi = 0;
+ gi = 0;
+ score = 0;
+ minscore = limit + 1;
+
+ for (;;)
+ {
+ /* Skip over an equal part, score remains the same. */
+ for (;;)
+ {
+ bc = badword[bi];
+ gc = goodword[gi];
+ if (bc != gc) /* stop at a char that's different */
+ break;
+ if (bc == NUL) /* both words end */
+ {
+ if (score < minscore)
+ minscore = score;
+ goto pop; /* do next alternative */
+ }
+ ++bi;
+ ++gi;
+ }
+
+ if (gc == NUL) /* goodword ends, delete badword chars */
+ {
+ do
+ {
+ if ((score += SCORE_DEL) >= minscore)
+ goto pop; /* do next alternative */
+ } while (badword[++bi] != NUL);
+ minscore = score;
+ }
+ else if (bc == NUL) /* badword ends, insert badword chars */
+ {
+ do
+ {
+ if ((score += SCORE_INS) >= minscore)
+ goto pop; /* do next alternative */
+ } while (goodword[++gi] != NUL);
+ minscore = score;
+ }
+ else /* both words continue */
+ {
+ /* If not close to the limit, perform a change. Only try changes
+ * that may lead to a lower score than "minscore".
+ * round 0: try deleting a char from badword
+ * round 1: try inserting a char in badword */
+ for (round = 0; round <= 1; ++round)
+ {
+ score_off = score + (round == 0 ? SCORE_DEL : SCORE_INS);
+ if (score_off < minscore)
+ {
+ if (score_off + SCORE_EDIT_MIN >= minscore)
+ {
+ /* Near the limit, rest of the words must match. We
+ * can check that right now, no need to push an item
+ * onto the stack. */
+ bi2 = bi + 1 - round;
+ gi2 = gi + round;
+ while (goodword[gi2] == badword[bi2])
+ {
+ if (goodword[gi2] == NUL)
+ {
+ minscore = score_off;
+ break;
+ }
+ ++bi2;
+ ++gi2;
+ }
+ }
+ else
+ {
+ /* try deleting/inserting a character later */
+ stack[stackidx].badi = bi + 1 - round;
+ stack[stackidx].goodi = gi + round;
+ stack[stackidx].score = score_off;
+ ++stackidx;
+ }
+ }
+ }
+
+ if (score + SCORE_SWAP < minscore)
+ {
+ /* If swapping two characters makes a match then the
+ * substitution is more expensive, thus there is no need to
+ * try both. */
+ if (gc == badword[bi + 1] && bc == goodword[gi + 1])
+ {
+ /* Swap two characters, that is: skip them. */
+ gi += 2;
+ bi += 2;
+ score += SCORE_SWAP;
+ continue;
+ }
+ }
+
+ /* Substitute one character for another which is the same
+ * thing as deleting a character from both goodword and badword.
+ * Use a better score when there is only a case difference. */
+ if (SPELL_TOFOLD(bc) == SPELL_TOFOLD(gc))
+ score += SCORE_ICASE;
+ else
+ {
+ /* For a similar character use SCORE_SIMILAR. */
+ if (slang != NULL
+ && slang->sl_has_map
+ && similar_chars(slang, gc, bc))
+ score += SCORE_SIMILAR;
+ else
+ score += SCORE_SUBST;
+ }
+
+ if (score < minscore)
+ {
+ /* Do the substitution. */
+ ++gi;
+ ++bi;
+ continue;
+ }
+ }
+pop:
+ /*
+ * Get here to try the next alternative, pop it from the stack.
+ */
+ if (stackidx == 0) /* stack is empty, finished */
+ break;
+
+ /* pop an item from the stack */
+ --stackidx;
+ gi = stack[stackidx].goodi;
+ bi = stack[stackidx].badi;
+ score = stack[stackidx].score;
+ }
+
+ /* When the score goes over "limit" it may actually be much higher.
+ * Return a very large number to avoid going below the limit when giving a
+ * bonus. */
+ if (minscore > limit)
+ return SCORE_MAXMAX;
+ return minscore;
+}
+
+/*
+ * Multi-byte version of spell_edit_score_limit().
+ * Keep it in sync with the above!
+ */
+ static int
+spell_edit_score_limit_w(
+ slang_T *slang,
+ char_u *badword,
+ char_u *goodword,
+ int limit)
+{
+ limitscore_T stack[10]; /* allow for over 3 * 2 edits */
+ int stackidx;
+ int bi, gi;
+ int bi2, gi2;
+ int bc, gc;
+ int score;
+ int score_off;
+ int minscore;
+ int round;
+ char_u *p;
+ int wbadword[MAXWLEN];
+ int wgoodword[MAXWLEN];
+
+ /* Get the characters from the multi-byte strings and put them in an
+ * int array for easy access. */
+ bi = 0;
+ for (p = badword; *p != NUL; )
+ wbadword[bi++] = mb_cptr2char_adv(&p);
+ wbadword[bi++] = 0;
+ gi = 0;
+ for (p = goodword; *p != NUL; )
+ wgoodword[gi++] = mb_cptr2char_adv(&p);
+ wgoodword[gi++] = 0;
+
+ /*
+ * The idea is to go from start to end over the words. So long as
+ * characters are equal just continue, this always gives the lowest score.
+ * When there is a difference try several alternatives. Each alternative
+ * increases "score" for the edit distance. Some of the alternatives are
+ * pushed unto a stack and tried later, some are tried right away. At the
+ * end of the word the score for one alternative is known. The lowest
+ * possible score is stored in "minscore".
+ */
+ stackidx = 0;
+ bi = 0;
+ gi = 0;
+ score = 0;
+ minscore = limit + 1;
+
+ for (;;)
+ {
+ /* Skip over an equal part, score remains the same. */
+ for (;;)
+ {
+ bc = wbadword[bi];
+ gc = wgoodword[gi];
+
+ if (bc != gc) /* stop at a char that's different */
+ break;
+ if (bc == NUL) /* both words end */
+ {
+ if (score < minscore)
+ minscore = score;
+ goto pop; /* do next alternative */
+ }
+ ++bi;
+ ++gi;
+ }
+
+ if (gc == NUL) /* goodword ends, delete badword chars */
+ {
+ do
+ {
+ if ((score += SCORE_DEL) >= minscore)
+ goto pop; /* do next alternative */
+ } while (wbadword[++bi] != NUL);
+ minscore = score;
+ }
+ else if (bc == NUL) /* badword ends, insert badword chars */
+ {
+ do
+ {
+ if ((score += SCORE_INS) >= minscore)
+ goto pop; /* do next alternative */
+ } while (wgoodword[++gi] != NUL);
+ minscore = score;
+ }
+ else /* both words continue */
+ {
+ /* If not close to the limit, perform a change. Only try changes
+ * that may lead to a lower score than "minscore".
+ * round 0: try deleting a char from badword
+ * round 1: try inserting a char in badword */
+ for (round = 0; round <= 1; ++round)
+ {
+ score_off = score + (round == 0 ? SCORE_DEL : SCORE_INS);
+ if (score_off < minscore)
+ {
+ if (score_off + SCORE_EDIT_MIN >= minscore)
+ {
+ /* Near the limit, rest of the words must match. We
+ * can check that right now, no need to push an item
+ * onto the stack. */
+ bi2 = bi + 1 - round;
+ gi2 = gi + round;
+ while (wgoodword[gi2] == wbadword[bi2])
+ {
+ if (wgoodword[gi2] == NUL)
+ {
+ minscore = score_off;
+ break;
+ }
+ ++bi2;
+ ++gi2;
+ }
+ }
+ else
+ {
+ /* try deleting a character from badword later */
+ stack[stackidx].badi = bi + 1 - round;
+ stack[stackidx].goodi = gi + round;
+ stack[stackidx].score = score_off;
+ ++stackidx;
+ }
+ }
+ }
+
+ if (score + SCORE_SWAP < minscore)
+ {
+ /* If swapping two characters makes a match then the
+ * substitution is more expensive, thus there is no need to
+ * try both. */
+ if (gc == wbadword[bi + 1] && bc == wgoodword[gi + 1])
+ {
+ /* Swap two characters, that is: skip them. */
+ gi += 2;
+ bi += 2;
+ score += SCORE_SWAP;
+ continue;
+ }
+ }
+
+ /* Substitute one character for another which is the same
+ * thing as deleting a character from both goodword and badword.
+ * Use a better score when there is only a case difference. */
+ if (SPELL_TOFOLD(bc) == SPELL_TOFOLD(gc))
+ score += SCORE_ICASE;
+ else
+ {
+ /* For a similar character use SCORE_SIMILAR. */
+ if (slang != NULL
+ && slang->sl_has_map
+ && similar_chars(slang, gc, bc))
+ score += SCORE_SIMILAR;
+ else
+ score += SCORE_SUBST;
+ }
+
+ if (score < minscore)
+ {
+ /* Do the substitution. */
+ ++gi;
+ ++bi;
+ continue;
+ }
+ }
+pop:
+ /*
+ * Get here to try the next alternative, pop it from the stack.
+ */
+ if (stackidx == 0) /* stack is empty, finished */
+ break;
+
+ /* pop an item from the stack */
+ --stackidx;
+ gi = stack[stackidx].goodi;
+ bi = stack[stackidx].badi;
+ score = stack[stackidx].score;
+ }
+
+ /* When the score goes over "limit" it may actually be much higher.
+ * Return a very large number to avoid going below the limit when giving a
+ * bonus. */
+ if (minscore > limit)
+ return SCORE_MAXMAX;
+ return minscore;
+}
+
+/*
+ * ":spellinfo"
+ */
+ void
+ex_spellinfo(exarg_T *eap UNUSED)
+{
+ int lpi;
+ langp_T *lp;
+ char_u *p;
+
+ if (no_spell_checking(curwin))
+ return;
+
+ msg_start();
+ for (lpi = 0; lpi < curwin->w_s->b_langp.ga_len && !got_int; ++lpi)
+ {
+ lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi);
+ msg_puts("file: ");
+ msg_puts((char *)lp->lp_slang->sl_fname);
+ msg_putchar('\n');
+ p = lp->lp_slang->sl_info;
+ if (p != NULL)
+ {
+ msg_puts((char *)p);
+ msg_putchar('\n');
+ }
+ }
+ msg_end();
+}
+
+#define DUMPFLAG_KEEPCASE 1 /* round 2: keep-case tree */
+#define DUMPFLAG_COUNT 2 /* include word count */
+#define DUMPFLAG_ICASE 4 /* ignore case when finding matches */
+#define DUMPFLAG_ONECAP 8 /* pattern starts with capital */
+#define DUMPFLAG_ALLCAP 16 /* pattern is all capitals */
+
+/*
+ * ":spelldump"
+ */
+ void
+ex_spelldump(exarg_T *eap)
+{
+ char_u *spl;
+ long dummy;
+
+ if (no_spell_checking(curwin))
+ return;
+ get_option_value((char_u*)"spl", &dummy, &spl, OPT_LOCAL);
+
+ /* Create a new empty buffer in a new window. */
+ do_cmdline_cmd((char_u *)"new");
+
+ /* enable spelling locally in the new window */
+ set_option_value((char_u*)"spell", TRUE, (char_u*)"", OPT_LOCAL);
+ set_option_value((char_u*)"spl", dummy, spl, OPT_LOCAL);
+ vim_free(spl);
+
+ if (!BUFEMPTY())
+ return;
+
+ spell_dump_compl(NULL, 0, NULL, eap->forceit ? DUMPFLAG_COUNT : 0);
+
+ /* Delete the empty line that we started with. */
+ if (curbuf->b_ml.ml_line_count > 1)
+ ml_delete(curbuf->b_ml.ml_line_count, FALSE);
+
+ redraw_later(NOT_VALID);
+}
+
+/*
+ * Go through all possible words and:
+ * 1. When "pat" is NULL: dump a list of all words in the current buffer.
+ * "ic" and "dir" are not used.
+ * 2. When "pat" is not NULL: add matching words to insert mode completion.
+ */
+ void
+spell_dump_compl(
+ char_u *pat, /* leading part of the word */
+ int ic, /* ignore case */
+ int *dir, /* direction for adding matches */
+ int dumpflags_arg) /* DUMPFLAG_* */
+{
+ langp_T *lp;
+ slang_T *slang;
+ idx_T arridx[MAXWLEN];
+ int curi[MAXWLEN];
+ char_u word[MAXWLEN];
+ int c;
+ char_u *byts;
+ idx_T *idxs;
+ linenr_T lnum = 0;
+ int round;
+ int depth;
+ int n;
+ int flags;
+ char_u *region_names = NULL; /* region names being used */
+ int do_region = TRUE; /* dump region names and numbers */
+ char_u *p;
+ int lpi;
+ int dumpflags = dumpflags_arg;
+ int patlen;
+
+ /* When ignoring case or when the pattern starts with capital pass this on
+ * to dump_word(). */
+ if (pat != NULL)
+ {
+ if (ic)
+ dumpflags |= DUMPFLAG_ICASE;
+ else
+ {
+ n = captype(pat, NULL);
+ if (n == WF_ONECAP)
+ dumpflags |= DUMPFLAG_ONECAP;
+ else if (n == WF_ALLCAP && (int)STRLEN(pat) > mb_ptr2len(pat))
+ dumpflags |= DUMPFLAG_ALLCAP;
+ }
+ }
+
+ /* Find out if we can support regions: All languages must support the same
+ * regions or none at all. */
+ for (lpi = 0; lpi < curwin->w_s->b_langp.ga_len; ++lpi)
+ {
+ lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi);
+ p = lp->lp_slang->sl_regions;
+ if (p[0] != 0)
+ {
+ if (region_names == NULL) /* first language with regions */
+ region_names = p;
+ else if (STRCMP(region_names, p) != 0)
+ {
+ do_region = FALSE; /* region names are different */
+ break;
+ }
+ }
+ }
+
+ if (do_region && region_names != NULL)
+ {
+ if (pat == NULL)
+ {
+ vim_snprintf((char *)IObuff, IOSIZE, "/regions=%s", region_names);
+ ml_append(lnum++, IObuff, (colnr_T)0, FALSE);
+ }
+ }
+ else
+ do_region = FALSE;
+
+ /*
+ * Loop over all files loaded for the entries in 'spelllang'.
+ */
+ for (lpi = 0; lpi < curwin->w_s->b_langp.ga_len; ++lpi)
+ {
+ lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi);
+ slang = lp->lp_slang;
+ if (slang->sl_fbyts == NULL) /* reloading failed */
+ continue;
+
+ if (pat == NULL)
+ {
+ vim_snprintf((char *)IObuff, IOSIZE, "# file: %s", slang->sl_fname);
+ ml_append(lnum++, IObuff, (colnr_T)0, FALSE);
+ }
+
+ /* When matching with a pattern and there are no prefixes only use
+ * parts of the tree that match "pat". */
+ if (pat != NULL && slang->sl_pbyts == NULL)
+ patlen = (int)STRLEN(pat);
+ else
+ patlen = -1;
+
+ /* round 1: case-folded tree
+ * round 2: keep-case tree */
+ for (round = 1; round <= 2; ++round)
+ {
+ if (round == 1)
+ {
+ dumpflags &= ~DUMPFLAG_KEEPCASE;
+ byts = slang->sl_fbyts;
+ idxs = slang->sl_fidxs;
+ }
+ else
+ {
+ dumpflags |= DUMPFLAG_KEEPCASE;
+ byts = slang->sl_kbyts;
+ idxs = slang->sl_kidxs;
+ }
+ if (byts == NULL)
+ continue; /* array is empty */
+
+ depth = 0;
+ arridx[0] = 0;
+ curi[0] = 1;
+ while (depth >= 0 && !got_int
+ && (pat == NULL || !compl_interrupted))
+ {
+ if (curi[depth] > byts[arridx[depth]])
+ {
+ /* Done all bytes at this node, go up one level. */
+ --depth;
+ line_breakcheck();
+ ins_compl_check_keys(50, FALSE);
+ }
+ else
+ {
+ /* Do one more byte at this node. */
+ n = arridx[depth] + curi[depth];
+ ++curi[depth];
+ c = byts[n];
+ if (c == 0)
+ {
+ /* End of word, deal with the word.
+ * Don't use keep-case words in the fold-case tree,
+ * they will appear in the keep-case tree.
+ * Only use the word when the region matches. */
+ flags = (int)idxs[n];
+ if ((round == 2 || (flags & WF_KEEPCAP) == 0)
+ && (flags & WF_NEEDCOMP) == 0
+ && (do_region
+ || (flags & WF_REGION) == 0
+ || (((unsigned)flags >> 16)
+ & lp->lp_region) != 0))
+ {
+ word[depth] = NUL;
+ if (!do_region)
+ flags &= ~WF_REGION;
+
+ /* Dump the basic word if there is no prefix or
+ * when it's the first one. */
+ c = (unsigned)flags >> 24;
+ if (c == 0 || curi[depth] == 2)
+ {
+ dump_word(slang, word, pat, dir,
+ dumpflags, flags, lnum);
+ if (pat == NULL)
+ ++lnum;
+ }
+
+ /* Apply the prefix, if there is one. */
+ if (c != 0)
+ lnum = dump_prefixes(slang, word, pat, dir,
+ dumpflags, flags, lnum);
+ }
+ }
+ else
+ {
+ /* Normal char, go one level deeper. */
+ word[depth++] = c;
+ arridx[depth] = idxs[n];
+ curi[depth] = 1;
+
+ /* Check if this characters matches with the pattern.
+ * If not skip the whole tree below it.
+ * Always ignore case here, dump_word() will check
+ * proper case later. This isn't exactly right when
+ * length changes for multi-byte characters with
+ * ignore case... */
+ if (depth <= patlen
+ && MB_STRNICMP(word, pat, depth) != 0)
+ --depth;
+ }
+ }
+ }
+ }
+ }
+}
+
+/*
+ * Dump one word: apply case modifications and append a line to the buffer.
+ * When "lnum" is zero add insert mode completion.
+ */
+ static void
+dump_word(
+ slang_T *slang,
+ char_u *word,
+ char_u *pat,
+ int *dir,
+ int dumpflags,
+ int wordflags,
+ linenr_T lnum)
+{
+ int keepcap = FALSE;
+ char_u *p;
+ char_u *tw;
+ char_u cword[MAXWLEN];
+ char_u badword[MAXWLEN + 10];
+ int i;
+ int flags = wordflags;
+
+ if (dumpflags & DUMPFLAG_ONECAP)
+ flags |= WF_ONECAP;
+ if (dumpflags & DUMPFLAG_ALLCAP)
+ flags |= WF_ALLCAP;
+
+ if ((dumpflags & DUMPFLAG_KEEPCASE) == 0 && (flags & WF_CAPMASK) != 0)
+ {
+ /* Need to fix case according to "flags". */
+ make_case_word(word, cword, flags);
+ p = cword;
+ }
+ else
+ {
+ p = word;
+ if ((dumpflags & DUMPFLAG_KEEPCASE)
+ && ((captype(word, NULL) & WF_KEEPCAP) == 0
+ || (flags & WF_FIXCAP) != 0))
+ keepcap = TRUE;
+ }
+ tw = p;
+
+ if (pat == NULL)
+ {
+ /* Add flags and regions after a slash. */
+ if ((flags & (WF_BANNED | WF_RARE | WF_REGION)) || keepcap)
+ {
+ STRCPY(badword, p);
+ STRCAT(badword, "/");
+ if (keepcap)
+ STRCAT(badword, "=");
+ if (flags & WF_BANNED)
+ STRCAT(badword, "!");
+ else if (flags & WF_RARE)
+ STRCAT(badword, "?");
+ if (flags & WF_REGION)
+ for (i = 0; i < 7; ++i)
+ if (flags & (0x10000 << i))
+ sprintf((char *)badword + STRLEN(badword), "%d", i + 1);
+ p = badword;
+ }
+
+ if (dumpflags & DUMPFLAG_COUNT)
+ {
+ hashitem_T *hi;
+
+ /* Include the word count for ":spelldump!". */
+ hi = hash_find(&slang->sl_wordcount, tw);
+ if (!HASHITEM_EMPTY(hi))
+ {
+ vim_snprintf((char *)IObuff, IOSIZE, "%s\t%d",
+ tw, HI2WC(hi)->wc_count);
+ p = IObuff;
+ }
+ }
+
+ ml_append(lnum, p, (colnr_T)0, FALSE);
+ }
+ else if (((dumpflags & DUMPFLAG_ICASE)
+ ? MB_STRNICMP(p, pat, STRLEN(pat)) == 0
+ : STRNCMP(p, pat, STRLEN(pat)) == 0)
+ && ins_compl_add_infercase(p, (int)STRLEN(p),
+ p_ic, NULL, *dir, 0) == OK)
+ /* if dir was BACKWARD then honor it just once */
+ *dir = FORWARD;
+}
+
+/*
+ * For ":spelldump": Find matching prefixes for "word". Prepend each to
+ * "word" and append a line to the buffer.
+ * When "lnum" is zero add insert mode completion.
+ * Return the updated line number.
+ */
+ static linenr_T
+dump_prefixes(
+ slang_T *slang,
+ char_u *word, /* case-folded word */
+ char_u *pat,
+ int *dir,
+ int dumpflags,
+ int flags, /* flags with prefix ID */
+ linenr_T startlnum)
+{
+ idx_T arridx[MAXWLEN];
+ int curi[MAXWLEN];
+ char_u prefix[MAXWLEN];
+ char_u word_up[MAXWLEN];
+ int has_word_up = FALSE;
+ int c;
+ char_u *byts;
+ idx_T *idxs;
+ linenr_T lnum = startlnum;
+ int depth;
+ int n;
+ int len;
+ int i;
+
+ /* If the word starts with a lower-case letter make the word with an
+ * upper-case letter in word_up[]. */
+ c = PTR2CHAR(word);
+ if (SPELL_TOUPPER(c) != c)
+ {
+ onecap_copy(word, word_up, TRUE);
+ has_word_up = TRUE;
+ }
+
+ byts = slang->sl_pbyts;
+ idxs = slang->sl_pidxs;
+ if (byts != NULL) /* array not is empty */
+ {
+ /*
+ * Loop over all prefixes, building them byte-by-byte in prefix[].
+ * When at the end of a prefix check that it supports "flags".
+ */
+ depth = 0;
+ arridx[0] = 0;
+ curi[0] = 1;
+ while (depth >= 0 && !got_int)
+ {
+ n = arridx[depth];
+ len = byts[n];
+ if (curi[depth] > len)
+ {
+ /* Done all bytes at this node, go up one level. */
+ --depth;
+ line_breakcheck();
+ }
+ else
+ {
+ /* Do one more byte at this node. */
+ n += curi[depth];
+ ++curi[depth];
+ c = byts[n];
+ if (c == 0)
+ {
+ /* End of prefix, find out how many IDs there are. */
+ for (i = 1; i < len; ++i)
+ if (byts[n + i] != 0)
+ break;
+ curi[depth] += i - 1;
+
+ c = valid_word_prefix(i, n, flags, word, slang, FALSE);
+ if (c != 0)
+ {
+ vim_strncpy(prefix + depth, word, MAXWLEN - depth - 1);
+ dump_word(slang, prefix, pat, dir, dumpflags,
+ (c & WF_RAREPFX) ? (flags | WF_RARE)
+ : flags, lnum);
+ if (lnum != 0)
+ ++lnum;
+ }
+
+ /* Check for prefix that matches the word when the
+ * first letter is upper-case, but only if the prefix has
+ * a condition. */
+ if (has_word_up)
+ {
+ c = valid_word_prefix(i, n, flags, word_up, slang,
+ TRUE);
+ if (c != 0)
+ {
+ vim_strncpy(prefix + depth, word_up,
+ MAXWLEN - depth - 1);
+ dump_word(slang, prefix, pat, dir, dumpflags,
+ (c & WF_RAREPFX) ? (flags | WF_RARE)
+ : flags, lnum);
+ if (lnum != 0)
+ ++lnum;
+ }
+ }
+ }
+ else
+ {
+ /* Normal char, go one level deeper. */
+ prefix[depth++] = c;
+ arridx[depth] = idxs[n];
+ curi[depth] = 1;
+ }
+ }
+ }
+ }
+
+ return lnum;
+}
+
+/*
+ * Move "p" to the end of word "start".
+ * Uses the spell-checking word characters.
+ */
+ char_u *
+spell_to_word_end(char_u *start, win_T *win)
+{
+ char_u *p = start;
+
+ while (*p != NUL && spell_iswordp(p, win))
+ MB_PTR_ADV(p);
+ return p;
+}
+
+#if defined(FEAT_INS_EXPAND) || defined(PROTO)
+/*
+ * For Insert mode completion CTRL-X s:
+ * Find start of the word in front of column "startcol".
+ * We don't check if it is badly spelled, with completion we can only change
+ * the word in front of the cursor.
+ * Returns the column number of the word.
+ */
+ int
+spell_word_start(int startcol)
+{
+ char_u *line;
+ char_u *p;
+ int col = 0;
+
+ if (no_spell_checking(curwin))
+ return startcol;
+
+ /* Find a word character before "startcol". */
+ line = ml_get_curline();
+ for (p = line + startcol; p > line; )
+ {
+ MB_PTR_BACK(line, p);
+ if (spell_iswordp_nmw(p, curwin))
+ break;
+ }
+
+ /* Go back to start of the word. */
+ while (p > line)
+ {
+ col = (int)(p - line);
+ MB_PTR_BACK(line, p);
+ if (!spell_iswordp(p, curwin))
+ break;
+ col = 0;
+ }
+
+ return col;
+}
+
+/*
+ * Need to check for 'spellcapcheck' now, the word is removed before
+ * expand_spelling() is called. Therefore the ugly global variable.
+ */
+static int spell_expand_need_cap;
+
+ void
+spell_expand_check_cap(colnr_T col)
+{
+ spell_expand_need_cap = check_need_cap(curwin->w_cursor.lnum, col);
+}
+
+/*
+ * Get list of spelling suggestions.
+ * Used for Insert mode completion CTRL-X ?.
+ * Returns the number of matches. The matches are in "matchp[]", array of
+ * allocated strings.
+ */
+ int
+expand_spelling(
+ linenr_T lnum UNUSED,
+ char_u *pat,
+ char_u ***matchp)
+{
+ garray_T ga;
+
+ spell_suggest_list(&ga, pat, 100, spell_expand_need_cap, TRUE);
+ *matchp = ga.ga_data;
+ return ga.ga_len;
+}
+#endif
+
+#endif /* FEAT_SPELL */
diff --git a/src/spell.h b/src/spell.h
new file mode 100644
index 0000000..085f18c
--- /dev/null
+++ b/src/spell.h
@@ -0,0 +1,301 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * spell.h: common code for spell checking, used by spell.c and spellfile.c.
+ */
+
+/* Use SPELL_PRINTTREE for debugging: dump the word tree after adding a word.
+ * Only use it for small word lists! */
+#if 0
+# define SPELL_PRINTTREE
+#endif
+
+/* Use SPELL_COMPRESS_ALLWAYS for debugging: compress the word tree after
+ * adding a word. Only use it for small word lists! */
+#if 0
+# define SPELL_COMPRESS_ALLWAYS
+#endif
+
+/* Use DEBUG_TRIEWALK to print the changes made in suggest_trie_walk() for a
+ * specific word. */
+#if 0
+# define DEBUG_TRIEWALK
+#endif
+
+#define MAXWLEN 254 /* Assume max. word len is this many bytes.
+ Some places assume a word length fits in a
+ byte, thus it can't be above 255.
+ Must be >= PFD_NOTSPECIAL. */
+
+#define MAXREGIONS 8 /* Number of regions supported. */
+
+/* Type used for indexes in the word tree need to be at least 4 bytes. If int
+ * is 8 bytes we could use something smaller, but what? */
+typedef int idx_T;
+
+typedef int salfirst_T;
+
+/*
+ * Structure used to store words and other info for one language, loaded from
+ * a .spl file.
+ * The main access is through the tree in "sl_fbyts/sl_fidxs", storing the
+ * case-folded words. "sl_kbyts/sl_kidxs" is for keep-case words.
+ *
+ * The "byts" array stores the possible bytes in each tree node, preceded by
+ * the number of possible bytes, sorted on byte value:
+ * <len> <byte1> <byte2> ...
+ * The "idxs" array stores the index of the child node corresponding to the
+ * byte in "byts".
+ * Exception: when the byte is zero, the word may end here and "idxs" holds
+ * the flags, region mask and affixID for the word. There may be several
+ * zeros in sequence for alternative flag/region/affixID combinations.
+ */
+typedef struct slang_S slang_T;
+struct slang_S
+{
+ slang_T *sl_next; /* next language */
+ char_u *sl_name; /* language name "en", "en.rare", "nl", etc. */
+ char_u *sl_fname; /* name of .spl file */
+ int sl_add; /* TRUE if it's a .add file. */
+
+ char_u *sl_fbyts; /* case-folded word bytes */
+ idx_T *sl_fidxs; /* case-folded word indexes */
+ char_u *sl_kbyts; /* keep-case word bytes */
+ idx_T *sl_kidxs; /* keep-case word indexes */
+ char_u *sl_pbyts; /* prefix tree word bytes */
+ idx_T *sl_pidxs; /* prefix tree word indexes */
+
+ char_u *sl_info; /* infotext string or NULL */
+
+ char_u sl_regions[MAXREGIONS * 2 + 1];
+ /* table with up to 8 region names plus NUL */
+
+ char_u *sl_midword; /* MIDWORD string or NULL */
+
+ hashtab_T sl_wordcount; /* hashtable with word count, wordcount_T */
+
+ int sl_compmax; /* COMPOUNDWORDMAX (default: MAXWLEN) */
+ int sl_compminlen; /* COMPOUNDMIN (default: 0) */
+ int sl_compsylmax; /* COMPOUNDSYLMAX (default: MAXWLEN) */
+ int sl_compoptions; /* COMP_* flags */
+ garray_T sl_comppat; /* CHECKCOMPOUNDPATTERN items */
+ regprog_T *sl_compprog; /* COMPOUNDRULE turned into a regexp progrm
+ * (NULL when no compounding) */
+ char_u *sl_comprules; /* all COMPOUNDRULE concatenated (or NULL) */
+ char_u *sl_compstartflags; /* flags for first compound word */
+ char_u *sl_compallflags; /* all flags for compound words */
+ char_u sl_nobreak; /* When TRUE: no spaces between words */
+ char_u *sl_syllable; /* SYLLABLE repeatable chars or NULL */
+ garray_T sl_syl_items; /* syllable items */
+
+ int sl_prefixcnt; /* number of items in "sl_prefprog" */
+ regprog_T **sl_prefprog; /* table with regprogs for prefixes */
+
+ garray_T sl_rep; /* list of fromto_T entries from REP lines */
+ short sl_rep_first[256]; /* indexes where byte first appears, -1 if
+ there is none */
+ garray_T sl_sal; /* list of salitem_T entries from SAL lines */
+ salfirst_T sl_sal_first[256]; /* indexes where byte first appears, -1 if
+ there is none */
+ int sl_followup; /* SAL followup */
+ int sl_collapse; /* SAL collapse_result */
+ int sl_rem_accents; /* SAL remove_accents */
+ int sl_sofo; /* SOFOFROM and SOFOTO instead of SAL items:
+ * "sl_sal_first" maps chars, when has_mbyte
+ * "sl_sal" is a list of wide char lists. */
+ garray_T sl_repsal; /* list of fromto_T entries from REPSAL lines */
+ short sl_repsal_first[256]; /* sl_rep_first for REPSAL lines */
+ int sl_nosplitsugs; /* don't suggest splitting a word */
+ int sl_nocompoundsugs; /* don't suggest compounding */
+
+ /* Info from the .sug file. Loaded on demand. */
+ time_t sl_sugtime; /* timestamp for .sug file */
+ char_u *sl_sbyts; /* soundfolded word bytes */
+ idx_T *sl_sidxs; /* soundfolded word indexes */
+ buf_T *sl_sugbuf; /* buffer with word number table */
+ int sl_sugloaded; /* TRUE when .sug file was loaded or failed to
+ load */
+
+ int sl_has_map; /* TRUE if there is a MAP line */
+ hashtab_T sl_map_hash; /* MAP for multi-byte chars */
+ int sl_map_array[256]; /* MAP for first 256 chars */
+ hashtab_T sl_sounddone; /* table with soundfolded words that have
+ handled, see add_sound_suggest() */
+};
+
+#ifdef VMS
+# define SPL_FNAME_TMPL "%s_%s.spl"
+# define SPL_FNAME_ADD "_add."
+# define SPL_FNAME_ASCII "_ascii."
+#else
+# define SPL_FNAME_TMPL "%s.%s.spl"
+# define SPL_FNAME_ADD ".add."
+# define SPL_FNAME_ASCII ".ascii."
+#endif
+
+/* Flags used for a word. Only the lowest byte can be used, the region byte
+ * comes above it. */
+#define WF_REGION 0x01 /* region byte follows */
+#define WF_ONECAP 0x02 /* word with one capital (or all capitals) */
+#define WF_ALLCAP 0x04 /* word must be all capitals */
+#define WF_RARE 0x08 /* rare word */
+#define WF_BANNED 0x10 /* bad word */
+#define WF_AFX 0x20 /* affix ID follows */
+#define WF_FIXCAP 0x40 /* keep-case word, allcap not allowed */
+#define WF_KEEPCAP 0x80 /* keep-case word */
+
+/* for <flags2>, shifted up one byte to be used in wn_flags */
+#define WF_HAS_AFF 0x0100 /* word includes affix */
+#define WF_NEEDCOMP 0x0200 /* word only valid in compound */
+#define WF_NOSUGGEST 0x0400 /* word not to be suggested */
+#define WF_COMPROOT 0x0800 /* already compounded word, COMPOUNDROOT */
+#define WF_NOCOMPBEF 0x1000 /* no compounding before this word */
+#define WF_NOCOMPAFT 0x2000 /* no compounding after this word */
+
+/* flags for <pflags> */
+#define WFP_RARE 0x01 /* rare prefix */
+#define WFP_NC 0x02 /* prefix is not combining */
+#define WFP_UP 0x04 /* to-upper prefix */
+#define WFP_COMPPERMIT 0x08 /* prefix with COMPOUNDPERMITFLAG */
+#define WFP_COMPFORBID 0x10 /* prefix with COMPOUNDFORBIDFLAG */
+
+/* Flags for postponed prefixes in "sl_pidxs". Must be above affixID (one
+ * byte) and prefcondnr (two bytes). */
+#define WF_RAREPFX (WFP_RARE << 24) /* rare postponed prefix */
+#define WF_PFX_NC (WFP_NC << 24) /* non-combining postponed prefix */
+#define WF_PFX_UP (WFP_UP << 24) /* to-upper postponed prefix */
+#define WF_PFX_COMPPERMIT (WFP_COMPPERMIT << 24) /* postponed prefix with
+ * COMPOUNDPERMITFLAG */
+#define WF_PFX_COMPFORBID (WFP_COMPFORBID << 24) /* postponed prefix with
+ * COMPOUNDFORBIDFLAG */
+
+/* flags for <compoptions> */
+#define COMP_CHECKDUP 1 /* CHECKCOMPOUNDDUP */
+#define COMP_CHECKREP 2 /* CHECKCOMPOUNDREP */
+#define COMP_CHECKCASE 4 /* CHECKCOMPOUNDCASE */
+#define COMP_CHECKTRIPLE 8 /* CHECKCOMPOUNDTRIPLE */
+
+/* Info from "REP", "REPSAL" and "SAL" entries in ".aff" file used in si_rep,
+ * si_repsal, sl_rep, and si_sal. Not for sl_sal!
+ * One replacement: from "ft_from" to "ft_to". */
+typedef struct fromto_S
+{
+ char_u *ft_from;
+ char_u *ft_to;
+} fromto_T;
+
+/* Info from "SAL" entries in ".aff" file used in sl_sal.
+ * The info is split for quick processing by spell_soundfold().
+ * Note that "sm_oneof" and "sm_rules" point into sm_lead. */
+typedef struct salitem_S
+{
+ char_u *sm_lead; /* leading letters */
+ int sm_leadlen; /* length of "sm_lead" */
+ char_u *sm_oneof; /* letters from () or NULL */
+ char_u *sm_rules; /* rules like ^, $, priority */
+ char_u *sm_to; /* replacement. */
+ int *sm_lead_w; /* wide character copy of "sm_lead" */
+ int *sm_oneof_w; /* wide character copy of "sm_oneof" */
+ int *sm_to_w; /* wide character copy of "sm_to" */
+} salitem_T;
+
+/* Values for SP_*ERROR are negative, positive values are used by
+ * read_cnt_string(). */
+#define SP_TRUNCERROR -1 /* spell file truncated error */
+#define SP_FORMERROR -2 /* format error in spell file */
+#define SP_OTHERERROR -3 /* other error while reading spell file */
+
+/*
+ * Structure used in "b_langp", filled from 'spelllang'.
+ */
+typedef struct langp_S
+{
+ slang_T *lp_slang; /* info for this language */
+ slang_T *lp_sallang; /* language used for sound folding or NULL */
+ slang_T *lp_replang; /* language used for REP items or NULL */
+ int lp_region; /* bitmask for region or REGION_ALL */
+} langp_T;
+
+#define LANGP_ENTRY(ga, i) (((langp_T *)(ga).ga_data) + (i))
+
+#define VIMSUGMAGIC "VIMsug" /* string at start of Vim .sug file */
+#define VIMSUGMAGICL 6
+#define VIMSUGVERSION 1
+
+/*
+ * The tables used for recognizing word characters according to spelling.
+ * These are only used for the first 256 characters of 'encoding'.
+ */
+typedef struct spelltab_S
+{
+ char_u st_isw[256]; /* flags: is word char */
+ char_u st_isu[256]; /* flags: is uppercase char */
+ char_u st_fold[256]; /* chars: folded case */
+ char_u st_upper[256]; /* chars: upper case */
+} spelltab_T;
+
+/*
+ * Use our own character-case definitions, because the current locale may
+ * differ from what the .spl file uses.
+ * These must not be called with negative number!
+ */
+#if defined(HAVE_WCHAR_H)
+# include <wchar.h> /* for towupper() and towlower() */
+#endif
+/* Multi-byte implementation. For Unicode we can call utf_*(), but don't do
+ * that for ASCII, because we don't want to use 'casemap' here. Otherwise use
+ * the "w" library function for characters above 255 if available. */
+#ifdef HAVE_TOWLOWER
+# define SPELL_TOFOLD(c) (enc_utf8 && (c) >= 128 ? utf_fold(c) \
+ : (c) < 256 ? (int)spelltab.st_fold[c] : (int)towlower(c))
+#else
+# define SPELL_TOFOLD(c) (enc_utf8 && (c) >= 128 ? utf_fold(c) \
+ : (c) < 256 ? (int)spelltab.st_fold[c] : (c))
+#endif
+
+#ifdef HAVE_TOWUPPER
+# define SPELL_TOUPPER(c) (enc_utf8 && (c) >= 128 ? utf_toupper(c) \
+ : (c) < 256 ? (int)spelltab.st_upper[c] : (int)towupper(c))
+#else
+# define SPELL_TOUPPER(c) (enc_utf8 && (c) >= 128 ? utf_toupper(c) \
+ : (c) < 256 ? (int)spelltab.st_upper[c] : (c))
+#endif
+
+#ifdef HAVE_ISWUPPER
+# define SPELL_ISUPPER(c) (enc_utf8 && (c) >= 128 ? utf_isupper(c) \
+ : (c) < 256 ? spelltab.st_isu[c] : iswupper(c))
+#else
+# define SPELL_ISUPPER(c) (enc_utf8 && (c) >= 128 ? utf_isupper(c) \
+ : (c) < 256 ? spelltab.st_isu[c] : (FALSE))
+#endif
+
+#ifdef FEAT_SPELL
+/* First language that is loaded, start of the linked list of loaded
+ * languages. */
+# ifdef IN_SPELL_C
+# define SPELL_EXTERN
+# define SPELL_INIT(x) x
+# else
+# define SPELL_EXTERN extern
+# define SPELL_INIT(x)
+# endif
+
+SPELL_EXTERN slang_T *first_lang SPELL_INIT(= NULL);
+
+/* file used for "zG" and "zW" */
+SPELL_EXTERN char_u *int_wordlist SPELL_INIT(= NULL);
+
+
+SPELL_EXTERN char e_format[] SPELL_INIT(= N_("E759: Format error in spell file"));
+
+SPELL_EXTERN spelltab_T spelltab;
+SPELL_EXTERN int did_set_spelltab;
+
+#endif
diff --git a/src/spellfile.c b/src/spellfile.c
new file mode 100644
index 0000000..00f6b7c
--- /dev/null
+++ b/src/spellfile.c
@@ -0,0 +1,6651 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * spellfile.c: code for reading and writing spell files.
+ *
+ * See spell.c for information about spell checking.
+ */
+
+/*
+ * Vim spell file format: <HEADER>
+ * <SECTIONS>
+ * <LWORDTREE>
+ * <KWORDTREE>
+ * <PREFIXTREE>
+ *
+ * <HEADER>: <fileID> <versionnr>
+ *
+ * <fileID> 8 bytes "VIMspell"
+ * <versionnr> 1 byte VIMSPELLVERSION
+ *
+ *
+ * Sections make it possible to add information to the .spl file without
+ * making it incompatible with previous versions. There are two kinds of
+ * sections:
+ * 1. Not essential for correct spell checking. E.g. for making suggestions.
+ * These are skipped when not supported.
+ * 2. Optional information, but essential for spell checking when present.
+ * E.g. conditions for affixes. When this section is present but not
+ * supported an error message is given.
+ *
+ * <SECTIONS>: <section> ... <sectionend>
+ *
+ * <section>: <sectionID> <sectionflags> <sectionlen> (section contents)
+ *
+ * <sectionID> 1 byte number from 0 to 254 identifying the section
+ *
+ * <sectionflags> 1 byte SNF_REQUIRED: this section is required for correct
+ * spell checking
+ *
+ * <sectionlen> 4 bytes length of section contents, MSB first
+ *
+ * <sectionend> 1 byte SN_END
+ *
+ *
+ * sectionID == SN_INFO: <infotext>
+ * <infotext> N bytes free format text with spell file info (version,
+ * website, etc)
+ *
+ * sectionID == SN_REGION: <regionname> ...
+ * <regionname> 2 bytes Up to MAXREGIONS region names: ca, au, etc. Lower
+ * case. First <regionname> is region 1.
+ *
+ * sectionID == SN_CHARFLAGS: <charflagslen> <charflags>
+ * <folcharslen> <folchars>
+ * <charflagslen> 1 byte Number of bytes in <charflags> (should be 128).
+ * <charflags> N bytes List of flags (first one is for character 128):
+ * 0x01 word character CF_WORD
+ * 0x02 upper-case character CF_UPPER
+ * <folcharslen> 2 bytes Number of bytes in <folchars>.
+ * <folchars> N bytes Folded characters, first one is for character 128.
+ *
+ * sectionID == SN_MIDWORD: <midword>
+ * <midword> N bytes Characters that are word characters only when used
+ * in the middle of a word.
+ *
+ * sectionID == SN_PREFCOND: <prefcondcnt> <prefcond> ...
+ * <prefcondcnt> 2 bytes Number of <prefcond> items following.
+ * <prefcond> : <condlen> <condstr>
+ * <condlen> 1 byte Length of <condstr>.
+ * <condstr> N bytes Condition for the prefix.
+ *
+ * sectionID == SN_REP: <repcount> <rep> ...
+ * <repcount> 2 bytes number of <rep> items, MSB first.
+ * <rep> : <repfromlen> <repfrom> <reptolen> <repto>
+ * <repfromlen> 1 byte length of <repfrom>
+ * <repfrom> N bytes "from" part of replacement
+ * <reptolen> 1 byte length of <repto>
+ * <repto> N bytes "to" part of replacement
+ *
+ * sectionID == SN_REPSAL: <repcount> <rep> ...
+ * just like SN_REP but for soundfolded words
+ *
+ * sectionID == SN_SAL: <salflags> <salcount> <sal> ...
+ * <salflags> 1 byte flags for soundsalike conversion:
+ * SAL_F0LLOWUP
+ * SAL_COLLAPSE
+ * SAL_REM_ACCENTS
+ * <salcount> 2 bytes number of <sal> items following
+ * <sal> : <salfromlen> <salfrom> <saltolen> <salto>
+ * <salfromlen> 1 byte length of <salfrom>
+ * <salfrom> N bytes "from" part of soundsalike
+ * <saltolen> 1 byte length of <salto>
+ * <salto> N bytes "to" part of soundsalike
+ *
+ * sectionID == SN_SOFO: <sofofromlen> <sofofrom> <sofotolen> <sofoto>
+ * <sofofromlen> 2 bytes length of <sofofrom>
+ * <sofofrom> N bytes "from" part of soundfold
+ * <sofotolen> 2 bytes length of <sofoto>
+ * <sofoto> N bytes "to" part of soundfold
+ *
+ * sectionID == SN_SUGFILE: <timestamp>
+ * <timestamp> 8 bytes time in seconds that must match with .sug file
+ *
+ * sectionID == SN_NOSPLITSUGS: nothing
+ *
+ * sectionID == SN_NOCOMPOUNDSUGS: nothing
+ *
+ * sectionID == SN_WORDS: <word> ...
+ * <word> N bytes NUL terminated common word
+ *
+ * sectionID == SN_MAP: <mapstr>
+ * <mapstr> N bytes String with sequences of similar characters,
+ * separated by slashes.
+ *
+ * sectionID == SN_COMPOUND: <compmax> <compminlen> <compsylmax> <compoptions>
+ * <comppatcount> <comppattern> ... <compflags>
+ * <compmax> 1 byte Maximum nr of words in compound word.
+ * <compminlen> 1 byte Minimal word length for compounding.
+ * <compsylmax> 1 byte Maximum nr of syllables in compound word.
+ * <compoptions> 2 bytes COMP_ flags.
+ * <comppatcount> 2 bytes number of <comppattern> following
+ * <compflags> N bytes Flags from COMPOUNDRULE items, separated by
+ * slashes.
+ *
+ * <comppattern>: <comppatlen> <comppattext>
+ * <comppatlen> 1 byte length of <comppattext>
+ * <comppattext> N bytes end or begin chars from CHECKCOMPOUNDPATTERN
+ *
+ * sectionID == SN_NOBREAK: (empty, its presence is what matters)
+ *
+ * sectionID == SN_SYLLABLE: <syllable>
+ * <syllable> N bytes String from SYLLABLE item.
+ *
+ * <LWORDTREE>: <wordtree>
+ *
+ * <KWORDTREE>: <wordtree>
+ *
+ * <PREFIXTREE>: <wordtree>
+ *
+ *
+ * <wordtree>: <nodecount> <nodedata> ...
+ *
+ * <nodecount> 4 bytes Number of nodes following. MSB first.
+ *
+ * <nodedata>: <siblingcount> <sibling> ...
+ *
+ * <siblingcount> 1 byte Number of siblings in this node. The siblings
+ * follow in sorted order.
+ *
+ * <sibling>: <byte> [ <nodeidx> <xbyte>
+ * | <flags> [<flags2>] [<region>] [<affixID>]
+ * | [<pflags>] <affixID> <prefcondnr> ]
+ *
+ * <byte> 1 byte Byte value of the sibling. Special cases:
+ * BY_NOFLAGS: End of word without flags and for all
+ * regions.
+ * For PREFIXTREE <affixID> and
+ * <prefcondnr> follow.
+ * BY_FLAGS: End of word, <flags> follow.
+ * For PREFIXTREE <pflags>, <affixID>
+ * and <prefcondnr> follow.
+ * BY_FLAGS2: End of word, <flags> and <flags2>
+ * follow. Not used in PREFIXTREE.
+ * BY_INDEX: Child of sibling is shared, <nodeidx>
+ * and <xbyte> follow.
+ *
+ * <nodeidx> 3 bytes Index of child for this sibling, MSB first.
+ *
+ * <xbyte> 1 byte byte value of the sibling.
+ *
+ * <flags> 1 byte bitmask of:
+ * WF_ALLCAP word must have only capitals
+ * WF_ONECAP first char of word must be capital
+ * WF_KEEPCAP keep-case word
+ * WF_FIXCAP keep-case word, all caps not allowed
+ * WF_RARE rare word
+ * WF_BANNED bad word
+ * WF_REGION <region> follows
+ * WF_AFX <affixID> follows
+ *
+ * <flags2> 1 byte Bitmask of:
+ * WF_HAS_AFF >> 8 word includes affix
+ * WF_NEEDCOMP >> 8 word only valid in compound
+ * WF_NOSUGGEST >> 8 word not used for suggestions
+ * WF_COMPROOT >> 8 word already a compound
+ * WF_NOCOMPBEF >> 8 no compounding before this word
+ * WF_NOCOMPAFT >> 8 no compounding after this word
+ *
+ * <pflags> 1 byte bitmask of:
+ * WFP_RARE rare prefix
+ * WFP_NC non-combining prefix
+ * WFP_UP letter after prefix made upper case
+ *
+ * <region> 1 byte Bitmask for regions in which word is valid. When
+ * omitted it's valid in all regions.
+ * Lowest bit is for region 1.
+ *
+ * <affixID> 1 byte ID of affix that can be used with this word. In
+ * PREFIXTREE used for the required prefix ID.
+ *
+ * <prefcondnr> 2 bytes Prefix condition number, index in <prefcond> list
+ * from HEADER.
+ *
+ * All text characters are in 'encoding', but stored as single bytes.
+ */
+
+/*
+ * Vim .sug file format: <SUGHEADER>
+ * <SUGWORDTREE>
+ * <SUGTABLE>
+ *
+ * <SUGHEADER>: <fileID> <versionnr> <timestamp>
+ *
+ * <fileID> 6 bytes "VIMsug"
+ * <versionnr> 1 byte VIMSUGVERSION
+ * <timestamp> 8 bytes timestamp that must match with .spl file
+ *
+ *
+ * <SUGWORDTREE>: <wordtree> (see above, no flags or region used)
+ *
+ *
+ * <SUGTABLE>: <sugwcount> <sugline> ...
+ *
+ * <sugwcount> 4 bytes number of <sugline> following
+ *
+ * <sugline>: <sugnr> ... NUL
+ *
+ * <sugnr>: X bytes word number that results in this soundfolded word,
+ * stored as an offset to the previous number in as
+ * few bytes as possible, see offset2bytes())
+ */
+
+#include "vim.h"
+
+#if defined(FEAT_SPELL) || defined(PROTO)
+
+#ifndef UNIX /* it's in os_unix.h for Unix */
+# include <time.h> /* for time_t */
+#endif
+
+#ifndef UNIX /* it's in os_unix.h for Unix */
+# include <time.h> /* for time_t */
+#endif
+
+/* Special byte values for <byte>. Some are only used in the tree for
+ * postponed prefixes, some only in the other trees. This is a bit messy... */
+#define BY_NOFLAGS 0 /* end of word without flags or region; for
+ * postponed prefix: no <pflags> */
+#define BY_INDEX 1 /* child is shared, index follows */
+#define BY_FLAGS 2 /* end of word, <flags> byte follows; for
+ * postponed prefix: <pflags> follows */
+#define BY_FLAGS2 3 /* end of word, <flags> and <flags2> bytes
+ * follow; never used in prefix tree */
+#define BY_SPECIAL BY_FLAGS2 /* highest special byte value */
+
+/* Flags used in .spl file for soundsalike flags. */
+#define SAL_F0LLOWUP 1
+#define SAL_COLLAPSE 2
+#define SAL_REM_ACCENTS 4
+
+#define VIMSPELLMAGIC "VIMspell" /* string at start of Vim spell file */
+#define VIMSPELLMAGICL 8
+#define VIMSPELLVERSION 50
+
+/* Section IDs. Only renumber them when VIMSPELLVERSION changes! */
+#define SN_REGION 0 /* <regionname> section */
+#define SN_CHARFLAGS 1 /* charflags section */
+#define SN_MIDWORD 2 /* <midword> section */
+#define SN_PREFCOND 3 /* <prefcond> section */
+#define SN_REP 4 /* REP items section */
+#define SN_SAL 5 /* SAL items section */
+#define SN_SOFO 6 /* soundfolding section */
+#define SN_MAP 7 /* MAP items section */
+#define SN_COMPOUND 8 /* compound words section */
+#define SN_SYLLABLE 9 /* syllable section */
+#define SN_NOBREAK 10 /* NOBREAK section */
+#define SN_SUGFILE 11 /* timestamp for .sug file */
+#define SN_REPSAL 12 /* REPSAL items section */
+#define SN_WORDS 13 /* common words */
+#define SN_NOSPLITSUGS 14 /* don't split word for suggestions */
+#define SN_INFO 15 /* info section */
+#define SN_NOCOMPOUNDSUGS 16 /* don't compound for suggestions */
+#define SN_END 255 /* end of sections */
+
+#define SNF_REQUIRED 1 /* <sectionflags>: required section */
+
+#define CF_WORD 0x01
+#define CF_UPPER 0x02
+
+static int set_spell_finish(spelltab_T *new_st);
+static int write_spell_prefcond(FILE *fd, garray_T *gap);
+static int read_region_section(FILE *fd, slang_T *slang, int len);
+static int read_charflags_section(FILE *fd);
+static int read_prefcond_section(FILE *fd, slang_T *lp);
+static int read_rep_section(FILE *fd, garray_T *gap, short *first);
+static int read_sal_section(FILE *fd, slang_T *slang);
+static int read_words_section(FILE *fd, slang_T *lp, int len);
+static int read_sofo_section(FILE *fd, slang_T *slang);
+static int read_compound(FILE *fd, slang_T *slang, int len);
+static int set_sofo(slang_T *lp, char_u *from, char_u *to);
+static void set_sal_first(slang_T *lp);
+static int *mb_str2wide(char_u *s);
+static int spell_read_tree(FILE *fd, char_u **bytsp, idx_T **idxsp, int prefixtree, int prefixcnt);
+static idx_T read_tree_node(FILE *fd, char_u *byts, idx_T *idxs, int maxidx, idx_T startidx, int prefixtree, int maxprefcondnr);
+static void set_spell_charflags(char_u *flags, int cnt, char_u *upp);
+static int set_spell_chartab(char_u *fol, char_u *low, char_u *upp);
+static void set_map_str(slang_T *lp, char_u *map);
+
+
+static char *e_spell_trunc = N_("E758: Truncated spell file");
+static char *e_afftrailing = N_("Trailing text in %s line %d: %s");
+static char *e_affname = N_("Affix name too long in %s line %d: %s");
+static char *e_affform = N_("E761: Format error in affix file FOL, LOW or UPP");
+static char *e_affrange = N_("E762: Character in FOL, LOW or UPP is out of range");
+static char *msg_compressing = N_("Compressing word tree...");
+
+/*
+ * Load one spell file and store the info into a slang_T.
+ *
+ * This is invoked in three ways:
+ * - From spell_load_cb() to load a spell file for the first time. "lang" is
+ * the language name, "old_lp" is NULL. Will allocate an slang_T.
+ * - To reload a spell file that was changed. "lang" is NULL and "old_lp"
+ * points to the existing slang_T.
+ * - Just after writing a .spl file; it's read back to produce the .sug file.
+ * "old_lp" is NULL and "lang" is NULL. Will allocate an slang_T.
+ *
+ * Returns the slang_T the spell file was loaded into. NULL for error.
+ */
+ slang_T *
+spell_load_file(
+ char_u *fname,
+ char_u *lang,
+ slang_T *old_lp,
+ int silent) /* no error if file doesn't exist */
+{
+ FILE *fd;
+ char_u buf[VIMSPELLMAGICL];
+ char_u *p;
+ int i;
+ int n;
+ int len;
+ char_u *save_sourcing_name = sourcing_name;
+ linenr_T save_sourcing_lnum = sourcing_lnum;
+ slang_T *lp = NULL;
+ int c = 0;
+ int res;
+
+ fd = mch_fopen((char *)fname, "r");
+ if (fd == NULL)
+ {
+ if (!silent)
+ semsg(_(e_notopen), fname);
+ else if (p_verbose > 2)
+ {
+ verbose_enter();
+ smsg((const char *)e_notopen, fname);
+ verbose_leave();
+ }
+ goto endFAIL;
+ }
+ if (p_verbose > 2)
+ {
+ verbose_enter();
+ smsg(_("Reading spell file \"%s\""), fname);
+ verbose_leave();
+ }
+
+ if (old_lp == NULL)
+ {
+ lp = slang_alloc(lang);
+ if (lp == NULL)
+ goto endFAIL;
+
+ /* Remember the file name, used to reload the file when it's updated. */
+ lp->sl_fname = vim_strsave(fname);
+ if (lp->sl_fname == NULL)
+ goto endFAIL;
+
+ /* Check for .add.spl (_add.spl for VMS). */
+ lp->sl_add = strstr((char *)gettail(fname), SPL_FNAME_ADD) != NULL;
+ }
+ else
+ lp = old_lp;
+
+ /* Set sourcing_name, so that error messages mention the file name. */
+ sourcing_name = fname;
+ sourcing_lnum = 0;
+
+ /*
+ * <HEADER>: <fileID>
+ */
+ for (i = 0; i < VIMSPELLMAGICL; ++i)
+ buf[i] = getc(fd); /* <fileID> */
+ if (STRNCMP(buf, VIMSPELLMAGIC, VIMSPELLMAGICL) != 0)
+ {
+ emsg(_("E757: This does not look like a spell file"));
+ goto endFAIL;
+ }
+ c = getc(fd); /* <versionnr> */
+ if (c < VIMSPELLVERSION)
+ {
+ emsg(_("E771: Old spell file, needs to be updated"));
+ goto endFAIL;
+ }
+ else if (c > VIMSPELLVERSION)
+ {
+ emsg(_("E772: Spell file is for newer version of Vim"));
+ goto endFAIL;
+ }
+
+
+ /*
+ * <SECTIONS>: <section> ... <sectionend>
+ * <section>: <sectionID> <sectionflags> <sectionlen> (section contents)
+ */
+ for (;;)
+ {
+ n = getc(fd); /* <sectionID> or <sectionend> */
+ if (n == SN_END)
+ break;
+ c = getc(fd); /* <sectionflags> */
+ len = get4c(fd); /* <sectionlen> */
+ if (len < 0)
+ goto truncerr;
+
+ res = 0;
+ switch (n)
+ {
+ case SN_INFO:
+ lp->sl_info = read_string(fd, len); /* <infotext> */
+ if (lp->sl_info == NULL)
+ goto endFAIL;
+ break;
+
+ case SN_REGION:
+ res = read_region_section(fd, lp, len);
+ break;
+
+ case SN_CHARFLAGS:
+ res = read_charflags_section(fd);
+ break;
+
+ case SN_MIDWORD:
+ lp->sl_midword = read_string(fd, len); /* <midword> */
+ if (lp->sl_midword == NULL)
+ goto endFAIL;
+ break;
+
+ case SN_PREFCOND:
+ res = read_prefcond_section(fd, lp);
+ break;
+
+ case SN_REP:
+ res = read_rep_section(fd, &lp->sl_rep, lp->sl_rep_first);
+ break;
+
+ case SN_REPSAL:
+ res = read_rep_section(fd, &lp->sl_repsal, lp->sl_repsal_first);
+ break;
+
+ case SN_SAL:
+ res = read_sal_section(fd, lp);
+ break;
+
+ case SN_SOFO:
+ res = read_sofo_section(fd, lp);
+ break;
+
+ case SN_MAP:
+ p = read_string(fd, len); /* <mapstr> */
+ if (p == NULL)
+ goto endFAIL;
+ set_map_str(lp, p);
+ vim_free(p);
+ break;
+
+ case SN_WORDS:
+ res = read_words_section(fd, lp, len);
+ break;
+
+ case SN_SUGFILE:
+ lp->sl_sugtime = get8ctime(fd); /* <timestamp> */
+ break;
+
+ case SN_NOSPLITSUGS:
+ lp->sl_nosplitsugs = TRUE;
+ break;
+
+ case SN_NOCOMPOUNDSUGS:
+ lp->sl_nocompoundsugs = TRUE;
+ break;
+
+ case SN_COMPOUND:
+ res = read_compound(fd, lp, len);
+ break;
+
+ case SN_NOBREAK:
+ lp->sl_nobreak = TRUE;
+ break;
+
+ case SN_SYLLABLE:
+ lp->sl_syllable = read_string(fd, len); /* <syllable> */
+ if (lp->sl_syllable == NULL)
+ goto endFAIL;
+ if (init_syl_tab(lp) == FAIL)
+ goto endFAIL;
+ break;
+
+ default:
+ /* Unsupported section. When it's required give an error
+ * message. When it's not required skip the contents. */
+ if (c & SNF_REQUIRED)
+ {
+ emsg(_("E770: Unsupported section in spell file"));
+ goto endFAIL;
+ }
+ while (--len >= 0)
+ if (getc(fd) < 0)
+ goto truncerr;
+ break;
+ }
+someerror:
+ if (res == SP_FORMERROR)
+ {
+ emsg(_(e_format));
+ goto endFAIL;
+ }
+ if (res == SP_TRUNCERROR)
+ {
+truncerr:
+ emsg(_(e_spell_trunc));
+ goto endFAIL;
+ }
+ if (res == SP_OTHERERROR)
+ goto endFAIL;
+ }
+
+ /* <LWORDTREE> */
+ res = spell_read_tree(fd, &lp->sl_fbyts, &lp->sl_fidxs, FALSE, 0);
+ if (res != 0)
+ goto someerror;
+
+ /* <KWORDTREE> */
+ res = spell_read_tree(fd, &lp->sl_kbyts, &lp->sl_kidxs, FALSE, 0);
+ if (res != 0)
+ goto someerror;
+
+ /* <PREFIXTREE> */
+ res = spell_read_tree(fd, &lp->sl_pbyts, &lp->sl_pidxs, TRUE,
+ lp->sl_prefixcnt);
+ if (res != 0)
+ goto someerror;
+
+ /* For a new file link it in the list of spell files. */
+ if (old_lp == NULL && lang != NULL)
+ {
+ lp->sl_next = first_lang;
+ first_lang = lp;
+ }
+
+ goto endOK;
+
+endFAIL:
+ if (lang != NULL)
+ /* truncating the name signals the error to spell_load_lang() */
+ *lang = NUL;
+ if (lp != NULL && old_lp == NULL)
+ slang_free(lp);
+ lp = NULL;
+
+endOK:
+ if (fd != NULL)
+ fclose(fd);
+ sourcing_name = save_sourcing_name;
+ sourcing_lnum = save_sourcing_lnum;
+
+ return lp;
+}
+
+/*
+ * Fill in the wordcount fields for a trie.
+ * Returns the total number of words.
+ */
+ static void
+tree_count_words(char_u *byts, idx_T *idxs)
+{
+ int depth;
+ idx_T arridx[MAXWLEN];
+ int curi[MAXWLEN];
+ int c;
+ idx_T n;
+ int wordcount[MAXWLEN];
+
+ arridx[0] = 0;
+ curi[0] = 1;
+ wordcount[0] = 0;
+ depth = 0;
+ while (depth >= 0 && !got_int)
+ {
+ if (curi[depth] > byts[arridx[depth]])
+ {
+ /* Done all bytes at this node, go up one level. */
+ idxs[arridx[depth]] = wordcount[depth];
+ if (depth > 0)
+ wordcount[depth - 1] += wordcount[depth];
+
+ --depth;
+ fast_breakcheck();
+ }
+ else
+ {
+ /* Do one more byte at this node. */
+ n = arridx[depth] + curi[depth];
+ ++curi[depth];
+
+ c = byts[n];
+ if (c == 0)
+ {
+ /* End of word, count it. */
+ ++wordcount[depth];
+
+ /* Skip over any other NUL bytes (same word with different
+ * flags). */
+ while (byts[n + 1] == 0)
+ {
+ ++n;
+ ++curi[depth];
+ }
+ }
+ else
+ {
+ /* Normal char, go one level deeper to count the words. */
+ ++depth;
+ arridx[depth] = idxs[n];
+ curi[depth] = 1;
+ wordcount[depth] = 0;
+ }
+ }
+ }
+}
+
+/*
+ * Load the .sug files for languages that have one and weren't loaded yet.
+ */
+ void
+suggest_load_files(void)
+{
+ langp_T *lp;
+ int lpi;
+ slang_T *slang;
+ char_u *dotp;
+ FILE *fd;
+ char_u buf[MAXWLEN];
+ int i;
+ time_t timestamp;
+ int wcount;
+ int wordnr;
+ garray_T ga;
+ int c;
+
+ /* Do this for all languages that support sound folding. */
+ for (lpi = 0; lpi < curwin->w_s->b_langp.ga_len; ++lpi)
+ {
+ lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi);
+ slang = lp->lp_slang;
+ if (slang->sl_sugtime != 0 && !slang->sl_sugloaded)
+ {
+ /* Change ".spl" to ".sug" and open the file. When the file isn't
+ * found silently skip it. Do set "sl_sugloaded" so that we
+ * don't try again and again. */
+ slang->sl_sugloaded = TRUE;
+
+ dotp = vim_strrchr(slang->sl_fname, '.');
+ if (dotp == NULL || fnamecmp(dotp, ".spl") != 0)
+ continue;
+ STRCPY(dotp, ".sug");
+ fd = mch_fopen((char *)slang->sl_fname, "r");
+ if (fd == NULL)
+ goto nextone;
+
+ /*
+ * <SUGHEADER>: <fileID> <versionnr> <timestamp>
+ */
+ for (i = 0; i < VIMSUGMAGICL; ++i)
+ buf[i] = getc(fd); /* <fileID> */
+ if (STRNCMP(buf, VIMSUGMAGIC, VIMSUGMAGICL) != 0)
+ {
+ semsg(_("E778: This does not look like a .sug file: %s"),
+ slang->sl_fname);
+ goto nextone;
+ }
+ c = getc(fd); /* <versionnr> */
+ if (c < VIMSUGVERSION)
+ {
+ semsg(_("E779: Old .sug file, needs to be updated: %s"),
+ slang->sl_fname);
+ goto nextone;
+ }
+ else if (c > VIMSUGVERSION)
+ {
+ semsg(_("E780: .sug file is for newer version of Vim: %s"),
+ slang->sl_fname);
+ goto nextone;
+ }
+
+ /* Check the timestamp, it must be exactly the same as the one in
+ * the .spl file. Otherwise the word numbers won't match. */
+ timestamp = get8ctime(fd); /* <timestamp> */
+ if (timestamp != slang->sl_sugtime)
+ {
+ semsg(_("E781: .sug file doesn't match .spl file: %s"),
+ slang->sl_fname);
+ goto nextone;
+ }
+
+ /*
+ * <SUGWORDTREE>: <wordtree>
+ * Read the trie with the soundfolded words.
+ */
+ if (spell_read_tree(fd, &slang->sl_sbyts, &slang->sl_sidxs,
+ FALSE, 0) != 0)
+ {
+someerror:
+ semsg(_("E782: error while reading .sug file: %s"),
+ slang->sl_fname);
+ slang_clear_sug(slang);
+ goto nextone;
+ }
+
+ /*
+ * <SUGTABLE>: <sugwcount> <sugline> ...
+ *
+ * Read the table with word numbers. We use a file buffer for
+ * this, because it's so much like a file with lines. Makes it
+ * possible to swap the info and save on memory use.
+ */
+ slang->sl_sugbuf = open_spellbuf();
+ if (slang->sl_sugbuf == NULL)
+ goto someerror;
+ /* <sugwcount> */
+ wcount = get4c(fd);
+ if (wcount < 0)
+ goto someerror;
+
+ /* Read all the wordnr lists into the buffer, one NUL terminated
+ * list per line. */
+ ga_init2(&ga, 1, 100);
+ for (wordnr = 0; wordnr < wcount; ++wordnr)
+ {
+ ga.ga_len = 0;
+ for (;;)
+ {
+ c = getc(fd); /* <sugline> */
+ if (c < 0 || ga_grow(&ga, 1) == FAIL)
+ goto someerror;
+ ((char_u *)ga.ga_data)[ga.ga_len++] = c;
+ if (c == NUL)
+ break;
+ }
+ if (ml_append_buf(slang->sl_sugbuf, (linenr_T)wordnr,
+ ga.ga_data, ga.ga_len, TRUE) == FAIL)
+ goto someerror;
+ }
+ ga_clear(&ga);
+
+ /*
+ * Need to put word counts in the word tries, so that we can find
+ * a word by its number.
+ */
+ tree_count_words(slang->sl_fbyts, slang->sl_fidxs);
+ tree_count_words(slang->sl_sbyts, slang->sl_sidxs);
+
+nextone:
+ if (fd != NULL)
+ fclose(fd);
+ STRCPY(dotp, ".spl");
+ }
+ }
+}
+
+
+/*
+ * Read a length field from "fd" in "cnt_bytes" bytes.
+ * Allocate memory, read the string into it and add a NUL at the end.
+ * Returns NULL when the count is zero.
+ * Sets "*cntp" to SP_*ERROR when there is an error, length of the result
+ * otherwise.
+ */
+ static char_u *
+read_cnt_string(FILE *fd, int cnt_bytes, int *cntp)
+{
+ int cnt = 0;
+ int i;
+ char_u *str;
+
+ /* read the length bytes, MSB first */
+ for (i = 0; i < cnt_bytes; ++i)
+ cnt = (cnt << 8) + getc(fd);
+ if (cnt < 0)
+ {
+ *cntp = SP_TRUNCERROR;
+ return NULL;
+ }
+ *cntp = cnt;
+ if (cnt == 0)
+ return NULL; /* nothing to read, return NULL */
+
+ str = read_string(fd, cnt);
+ if (str == NULL)
+ *cntp = SP_OTHERERROR;
+ return str;
+}
+
+/*
+ * Read SN_REGION: <regionname> ...
+ * Return SP_*ERROR flags.
+ */
+ static int
+read_region_section(FILE *fd, slang_T *lp, int len)
+{
+ int i;
+
+ if (len > MAXREGIONS * 2)
+ return SP_FORMERROR;
+ for (i = 0; i < len; ++i)
+ lp->sl_regions[i] = getc(fd); /* <regionname> */
+ lp->sl_regions[len] = NUL;
+ return 0;
+}
+
+/*
+ * Read SN_CHARFLAGS section: <charflagslen> <charflags>
+ * <folcharslen> <folchars>
+ * Return SP_*ERROR flags.
+ */
+ static int
+read_charflags_section(FILE *fd)
+{
+ char_u *flags;
+ char_u *fol;
+ int flagslen, follen;
+
+ /* <charflagslen> <charflags> */
+ flags = read_cnt_string(fd, 1, &flagslen);
+ if (flagslen < 0)
+ return flagslen;
+
+ /* <folcharslen> <folchars> */
+ fol = read_cnt_string(fd, 2, &follen);
+ if (follen < 0)
+ {
+ vim_free(flags);
+ return follen;
+ }
+
+ /* Set the word-char flags and fill SPELL_ISUPPER() table. */
+ if (flags != NULL && fol != NULL)
+ set_spell_charflags(flags, flagslen, fol);
+
+ vim_free(flags);
+ vim_free(fol);
+
+ /* When <charflagslen> is zero then <fcharlen> must also be zero. */
+ if ((flags == NULL) != (fol == NULL))
+ return SP_FORMERROR;
+ return 0;
+}
+
+/*
+ * Read SN_PREFCOND section.
+ * Return SP_*ERROR flags.
+ */
+ static int
+read_prefcond_section(FILE *fd, slang_T *lp)
+{
+ int cnt;
+ int i;
+ int n;
+ char_u *p;
+ char_u buf[MAXWLEN + 1];
+
+ /* <prefcondcnt> <prefcond> ... */
+ cnt = get2c(fd); /* <prefcondcnt> */
+ if (cnt <= 0)
+ return SP_FORMERROR;
+
+ lp->sl_prefprog = (regprog_T **)alloc_clear(
+ (unsigned)sizeof(regprog_T *) * cnt);
+ if (lp->sl_prefprog == NULL)
+ return SP_OTHERERROR;
+ lp->sl_prefixcnt = cnt;
+
+ for (i = 0; i < cnt; ++i)
+ {
+ /* <prefcond> : <condlen> <condstr> */
+ n = getc(fd); /* <condlen> */
+ if (n < 0 || n >= MAXWLEN)
+ return SP_FORMERROR;
+
+ /* When <condlen> is zero we have an empty condition. Otherwise
+ * compile the regexp program used to check for the condition. */
+ if (n > 0)
+ {
+ buf[0] = '^'; /* always match at one position only */
+ p = buf + 1;
+ while (n-- > 0)
+ *p++ = getc(fd); /* <condstr> */
+ *p = NUL;
+ lp->sl_prefprog[i] = vim_regcomp(buf, RE_MAGIC + RE_STRING);
+ }
+ }
+ return 0;
+}
+
+/*
+ * Read REP or REPSAL items section from "fd": <repcount> <rep> ...
+ * Return SP_*ERROR flags.
+ */
+ static int
+read_rep_section(FILE *fd, garray_T *gap, short *first)
+{
+ int cnt;
+ fromto_T *ftp;
+ int i;
+
+ cnt = get2c(fd); /* <repcount> */
+ if (cnt < 0)
+ return SP_TRUNCERROR;
+
+ if (ga_grow(gap, cnt) == FAIL)
+ return SP_OTHERERROR;
+
+ /* <rep> : <repfromlen> <repfrom> <reptolen> <repto> */
+ for (; gap->ga_len < cnt; ++gap->ga_len)
+ {
+ ftp = &((fromto_T *)gap->ga_data)[gap->ga_len];
+ ftp->ft_from = read_cnt_string(fd, 1, &i);
+ if (i < 0)
+ return i;
+ if (i == 0)
+ return SP_FORMERROR;
+ ftp->ft_to = read_cnt_string(fd, 1, &i);
+ if (i <= 0)
+ {
+ vim_free(ftp->ft_from);
+ if (i < 0)
+ return i;
+ return SP_FORMERROR;
+ }
+ }
+
+ /* Fill the first-index table. */
+ for (i = 0; i < 256; ++i)
+ first[i] = -1;
+ for (i = 0; i < gap->ga_len; ++i)
+ {
+ ftp = &((fromto_T *)gap->ga_data)[i];
+ if (first[*ftp->ft_from] == -1)
+ first[*ftp->ft_from] = i;
+ }
+ return 0;
+}
+
+/*
+ * Read SN_SAL section: <salflags> <salcount> <sal> ...
+ * Return SP_*ERROR flags.
+ */
+ static int
+read_sal_section(FILE *fd, slang_T *slang)
+{
+ int i;
+ int cnt;
+ garray_T *gap;
+ salitem_T *smp;
+ int ccnt;
+ char_u *p;
+ int c = NUL;
+
+ slang->sl_sofo = FALSE;
+
+ i = getc(fd); /* <salflags> */
+ if (i & SAL_F0LLOWUP)
+ slang->sl_followup = TRUE;
+ if (i & SAL_COLLAPSE)
+ slang->sl_collapse = TRUE;
+ if (i & SAL_REM_ACCENTS)
+ slang->sl_rem_accents = TRUE;
+
+ cnt = get2c(fd); /* <salcount> */
+ if (cnt < 0)
+ return SP_TRUNCERROR;
+
+ gap = &slang->sl_sal;
+ ga_init2(gap, sizeof(salitem_T), 10);
+ if (ga_grow(gap, cnt + 1) == FAIL)
+ return SP_OTHERERROR;
+
+ /* <sal> : <salfromlen> <salfrom> <saltolen> <salto> */
+ for (; gap->ga_len < cnt; ++gap->ga_len)
+ {
+ smp = &((salitem_T *)gap->ga_data)[gap->ga_len];
+ ccnt = getc(fd); /* <salfromlen> */
+ if (ccnt < 0)
+ return SP_TRUNCERROR;
+ if ((p = alloc(ccnt + 2)) == NULL)
+ return SP_OTHERERROR;
+ smp->sm_lead = p;
+
+ /* Read up to the first special char into sm_lead. */
+ for (i = 0; i < ccnt; ++i)
+ {
+ c = getc(fd); /* <salfrom> */
+ if (vim_strchr((char_u *)"0123456789(-<^$", c) != NULL)
+ break;
+ *p++ = c;
+ }
+ smp->sm_leadlen = (int)(p - smp->sm_lead);
+ *p++ = NUL;
+
+ /* Put (abc) chars in sm_oneof, if any. */
+ if (c == '(')
+ {
+ smp->sm_oneof = p;
+ for (++i; i < ccnt; ++i)
+ {
+ c = getc(fd); /* <salfrom> */
+ if (c == ')')
+ break;
+ *p++ = c;
+ }
+ *p++ = NUL;
+ if (++i < ccnt)
+ c = getc(fd);
+ }
+ else
+ smp->sm_oneof = NULL;
+
+ /* Any following chars go in sm_rules. */
+ smp->sm_rules = p;
+ if (i < ccnt)
+ /* store the char we got while checking for end of sm_lead */
+ *p++ = c;
+ for (++i; i < ccnt; ++i)
+ *p++ = getc(fd); /* <salfrom> */
+ *p++ = NUL;
+
+ /* <saltolen> <salto> */
+ smp->sm_to = read_cnt_string(fd, 1, &ccnt);
+ if (ccnt < 0)
+ {
+ vim_free(smp->sm_lead);
+ return ccnt;
+ }
+
+ if (has_mbyte)
+ {
+ /* convert the multi-byte strings to wide char strings */
+ smp->sm_lead_w = mb_str2wide(smp->sm_lead);
+ smp->sm_leadlen = mb_charlen(smp->sm_lead);
+ if (smp->sm_oneof == NULL)
+ smp->sm_oneof_w = NULL;
+ else
+ smp->sm_oneof_w = mb_str2wide(smp->sm_oneof);
+ if (smp->sm_to == NULL)
+ smp->sm_to_w = NULL;
+ else
+ smp->sm_to_w = mb_str2wide(smp->sm_to);
+ if (smp->sm_lead_w == NULL
+ || (smp->sm_oneof_w == NULL && smp->sm_oneof != NULL)
+ || (smp->sm_to_w == NULL && smp->sm_to != NULL))
+ {
+ vim_free(smp->sm_lead);
+ vim_free(smp->sm_to);
+ vim_free(smp->sm_lead_w);
+ vim_free(smp->sm_oneof_w);
+ vim_free(smp->sm_to_w);
+ return SP_OTHERERROR;
+ }
+ }
+ }
+
+ if (gap->ga_len > 0)
+ {
+ /* Add one extra entry to mark the end with an empty sm_lead. Avoids
+ * that we need to check the index every time. */
+ smp = &((salitem_T *)gap->ga_data)[gap->ga_len];
+ if ((p = alloc(1)) == NULL)
+ return SP_OTHERERROR;
+ p[0] = NUL;
+ smp->sm_lead = p;
+ smp->sm_leadlen = 0;
+ smp->sm_oneof = NULL;
+ smp->sm_rules = p;
+ smp->sm_to = NULL;
+ if (has_mbyte)
+ {
+ smp->sm_lead_w = mb_str2wide(smp->sm_lead);
+ smp->sm_leadlen = 0;
+ smp->sm_oneof_w = NULL;
+ smp->sm_to_w = NULL;
+ }
+ ++gap->ga_len;
+ }
+
+ /* Fill the first-index table. */
+ set_sal_first(slang);
+
+ return 0;
+}
+
+/*
+ * Read SN_WORDS: <word> ...
+ * Return SP_*ERROR flags.
+ */
+ static int
+read_words_section(FILE *fd, slang_T *lp, int len)
+{
+ int done = 0;
+ int i;
+ int c;
+ char_u word[MAXWLEN];
+
+ while (done < len)
+ {
+ /* Read one word at a time. */
+ for (i = 0; ; ++i)
+ {
+ c = getc(fd);
+ if (c == EOF)
+ return SP_TRUNCERROR;
+ word[i] = c;
+ if (word[i] == NUL)
+ break;
+ if (i == MAXWLEN - 1)
+ return SP_FORMERROR;
+ }
+
+ /* Init the count to 10. */
+ count_common_word(lp, word, -1, 10);
+ done += i + 1;
+ }
+ return 0;
+}
+
+/*
+ * SN_SOFO: <sofofromlen> <sofofrom> <sofotolen> <sofoto>
+ * Return SP_*ERROR flags.
+ */
+ static int
+read_sofo_section(FILE *fd, slang_T *slang)
+{
+ int cnt;
+ char_u *from, *to;
+ int res;
+
+ slang->sl_sofo = TRUE;
+
+ /* <sofofromlen> <sofofrom> */
+ from = read_cnt_string(fd, 2, &cnt);
+ if (cnt < 0)
+ return cnt;
+
+ /* <sofotolen> <sofoto> */
+ to = read_cnt_string(fd, 2, &cnt);
+ if (cnt < 0)
+ {
+ vim_free(from);
+ return cnt;
+ }
+
+ /* Store the info in slang->sl_sal and/or slang->sl_sal_first. */
+ if (from != NULL && to != NULL)
+ res = set_sofo(slang, from, to);
+ else if (from != NULL || to != NULL)
+ res = SP_FORMERROR; /* only one of two strings is an error */
+ else
+ res = 0;
+
+ vim_free(from);
+ vim_free(to);
+ return res;
+}
+
+/*
+ * Read the compound section from the .spl file:
+ * <compmax> <compminlen> <compsylmax> <compoptions> <compflags>
+ * Returns SP_*ERROR flags.
+ */
+ static int
+read_compound(FILE *fd, slang_T *slang, int len)
+{
+ int todo = len;
+ int c;
+ int atstart;
+ char_u *pat;
+ char_u *pp;
+ char_u *cp;
+ char_u *ap;
+ char_u *crp;
+ int cnt;
+ garray_T *gap;
+
+ if (todo < 2)
+ return SP_FORMERROR; /* need at least two bytes */
+
+ --todo;
+ c = getc(fd); /* <compmax> */
+ if (c < 2)
+ c = MAXWLEN;
+ slang->sl_compmax = c;
+
+ --todo;
+ c = getc(fd); /* <compminlen> */
+ if (c < 1)
+ c = 0;
+ slang->sl_compminlen = c;
+
+ --todo;
+ c = getc(fd); /* <compsylmax> */
+ if (c < 1)
+ c = MAXWLEN;
+ slang->sl_compsylmax = c;
+
+ c = getc(fd); /* <compoptions> */
+ if (c != 0)
+ ungetc(c, fd); /* be backwards compatible with Vim 7.0b */
+ else
+ {
+ --todo;
+ c = getc(fd); /* only use the lower byte for now */
+ --todo;
+ slang->sl_compoptions = c;
+
+ gap = &slang->sl_comppat;
+ c = get2c(fd); /* <comppatcount> */
+ todo -= 2;
+ ga_init2(gap, sizeof(char_u *), c);
+ if (ga_grow(gap, c) == OK)
+ while (--c >= 0)
+ {
+ ((char_u **)(gap->ga_data))[gap->ga_len++] =
+ read_cnt_string(fd, 1, &cnt);
+ /* <comppatlen> <comppattext> */
+ if (cnt < 0)
+ return cnt;
+ todo -= cnt + 1;
+ }
+ }
+ if (todo < 0)
+ return SP_FORMERROR;
+
+ /* Turn the COMPOUNDRULE items into a regexp pattern:
+ * "a[bc]/a*b+" -> "^\(a[bc]\|a*b\+\)$".
+ * Inserting backslashes may double the length, "^\(\)$<Nul>" is 7 bytes.
+ * Conversion to utf-8 may double the size. */
+ c = todo * 2 + 7;
+ if (enc_utf8)
+ c += todo * 2;
+ pat = alloc((unsigned)c);
+ if (pat == NULL)
+ return SP_OTHERERROR;
+
+ /* We also need a list of all flags that can appear at the start and one
+ * for all flags. */
+ cp = alloc(todo + 1);
+ if (cp == NULL)
+ {
+ vim_free(pat);
+ return SP_OTHERERROR;
+ }
+ slang->sl_compstartflags = cp;
+ *cp = NUL;
+
+ ap = alloc(todo + 1);
+ if (ap == NULL)
+ {
+ vim_free(pat);
+ return SP_OTHERERROR;
+ }
+ slang->sl_compallflags = ap;
+ *ap = NUL;
+
+ /* And a list of all patterns in their original form, for checking whether
+ * compounding may work in match_compoundrule(). This is freed when we
+ * encounter a wildcard, the check doesn't work then. */
+ crp = alloc(todo + 1);
+ slang->sl_comprules = crp;
+
+ pp = pat;
+ *pp++ = '^';
+ *pp++ = '\\';
+ *pp++ = '(';
+
+ atstart = 1;
+ while (todo-- > 0)
+ {
+ c = getc(fd); /* <compflags> */
+ if (c == EOF)
+ {
+ vim_free(pat);
+ return SP_TRUNCERROR;
+ }
+
+ /* Add all flags to "sl_compallflags". */
+ if (vim_strchr((char_u *)"?*+[]/", c) == NULL
+ && !byte_in_str(slang->sl_compallflags, c))
+ {
+ *ap++ = c;
+ *ap = NUL;
+ }
+
+ if (atstart != 0)
+ {
+ /* At start of item: copy flags to "sl_compstartflags". For a
+ * [abc] item set "atstart" to 2 and copy up to the ']'. */
+ if (c == '[')
+ atstart = 2;
+ else if (c == ']')
+ atstart = 0;
+ else
+ {
+ if (!byte_in_str(slang->sl_compstartflags, c))
+ {
+ *cp++ = c;
+ *cp = NUL;
+ }
+ if (atstart == 1)
+ atstart = 0;
+ }
+ }
+
+ /* Copy flag to "sl_comprules", unless we run into a wildcard. */
+ if (crp != NULL)
+ {
+ if (c == '?' || c == '+' || c == '*')
+ {
+ VIM_CLEAR(slang->sl_comprules);
+ crp = NULL;
+ }
+ else
+ *crp++ = c;
+ }
+
+ if (c == '/') /* slash separates two items */
+ {
+ *pp++ = '\\';
+ *pp++ = '|';
+ atstart = 1;
+ }
+ else /* normal char, "[abc]" and '*' are copied as-is */
+ {
+ if (c == '?' || c == '+' || c == '~')
+ *pp++ = '\\'; /* "a?" becomes "a\?", "a+" becomes "a\+" */
+ if (enc_utf8)
+ pp += mb_char2bytes(c, pp);
+ else
+ *pp++ = c;
+ }
+ }
+
+ *pp++ = '\\';
+ *pp++ = ')';
+ *pp++ = '$';
+ *pp = NUL;
+
+ if (crp != NULL)
+ *crp = NUL;
+
+ slang->sl_compprog = vim_regcomp(pat, RE_MAGIC + RE_STRING + RE_STRICT);
+ vim_free(pat);
+ if (slang->sl_compprog == NULL)
+ return SP_FORMERROR;
+
+ return 0;
+}
+
+/*
+ * Set the SOFOFROM and SOFOTO items in language "lp".
+ * Returns SP_*ERROR flags when there is something wrong.
+ */
+ static int
+set_sofo(slang_T *lp, char_u *from, char_u *to)
+{
+ int i;
+
+ garray_T *gap;
+ char_u *s;
+ char_u *p;
+ int c;
+ int *inp;
+
+ if (has_mbyte)
+ {
+ /* Use "sl_sal" as an array with 256 pointers to a list of wide
+ * characters. The index is the low byte of the character.
+ * The list contains from-to pairs with a terminating NUL.
+ * sl_sal_first[] is used for latin1 "from" characters. */
+ gap = &lp->sl_sal;
+ ga_init2(gap, sizeof(int *), 1);
+ if (ga_grow(gap, 256) == FAIL)
+ return SP_OTHERERROR;
+ vim_memset(gap->ga_data, 0, sizeof(int *) * 256);
+ gap->ga_len = 256;
+
+ /* First count the number of items for each list. Temporarily use
+ * sl_sal_first[] for this. */
+ for (p = from, s = to; *p != NUL && *s != NUL; )
+ {
+ c = mb_cptr2char_adv(&p);
+ MB_CPTR_ADV(s);
+ if (c >= 256)
+ ++lp->sl_sal_first[c & 0xff];
+ }
+ if (*p != NUL || *s != NUL) /* lengths differ */
+ return SP_FORMERROR;
+
+ /* Allocate the lists. */
+ for (i = 0; i < 256; ++i)
+ if (lp->sl_sal_first[i] > 0)
+ {
+ p = alloc(sizeof(int) * (lp->sl_sal_first[i] * 2 + 1));
+ if (p == NULL)
+ return SP_OTHERERROR;
+ ((int **)gap->ga_data)[i] = (int *)p;
+ *(int *)p = 0;
+ }
+
+ /* Put the characters up to 255 in sl_sal_first[] the rest in a sl_sal
+ * list. */
+ vim_memset(lp->sl_sal_first, 0, sizeof(salfirst_T) * 256);
+ for (p = from, s = to; *p != NUL && *s != NUL; )
+ {
+ c = mb_cptr2char_adv(&p);
+ i = mb_cptr2char_adv(&s);
+ if (c >= 256)
+ {
+ /* Append the from-to chars at the end of the list with
+ * the low byte. */
+ inp = ((int **)gap->ga_data)[c & 0xff];
+ while (*inp != 0)
+ ++inp;
+ *inp++ = c; /* from char */
+ *inp++ = i; /* to char */
+ *inp++ = NUL; /* NUL at the end */
+ }
+ else
+ /* mapping byte to char is done in sl_sal_first[] */
+ lp->sl_sal_first[c] = i;
+ }
+ }
+ else
+ {
+ /* mapping bytes to bytes is done in sl_sal_first[] */
+ if (STRLEN(from) != STRLEN(to))
+ return SP_FORMERROR;
+
+ for (i = 0; to[i] != NUL; ++i)
+ lp->sl_sal_first[from[i]] = to[i];
+ lp->sl_sal.ga_len = 1; /* indicates we have soundfolding */
+ }
+
+ return 0;
+}
+
+/*
+ * Fill the first-index table for "lp".
+ */
+ static void
+set_sal_first(slang_T *lp)
+{
+ salfirst_T *sfirst;
+ int i;
+ salitem_T *smp;
+ int c;
+ garray_T *gap = &lp->sl_sal;
+
+ sfirst = lp->sl_sal_first;
+ for (i = 0; i < 256; ++i)
+ sfirst[i] = -1;
+ smp = (salitem_T *)gap->ga_data;
+ for (i = 0; i < gap->ga_len; ++i)
+ {
+ if (has_mbyte)
+ /* Use the lowest byte of the first character. For latin1 it's
+ * the character, for other encodings it should differ for most
+ * characters. */
+ c = *smp[i].sm_lead_w & 0xff;
+ else
+ c = *smp[i].sm_lead;
+ if (sfirst[c] == -1)
+ {
+ sfirst[c] = i;
+ if (has_mbyte)
+ {
+ int n;
+
+ /* Make sure all entries with this byte are following each
+ * other. Move the ones that are in the wrong position. Do
+ * keep the same ordering! */
+ while (i + 1 < gap->ga_len
+ && (*smp[i + 1].sm_lead_w & 0xff) == c)
+ /* Skip over entry with same index byte. */
+ ++i;
+
+ for (n = 1; i + n < gap->ga_len; ++n)
+ if ((*smp[i + n].sm_lead_w & 0xff) == c)
+ {
+ salitem_T tsal;
+
+ /* Move entry with same index byte after the entries
+ * we already found. */
+ ++i;
+ --n;
+ tsal = smp[i + n];
+ mch_memmove(smp + i + 1, smp + i,
+ sizeof(salitem_T) * n);
+ smp[i] = tsal;
+ }
+ }
+ }
+ }
+}
+
+/*
+ * Turn a multi-byte string into a wide character string.
+ * Return it in allocated memory (NULL for out-of-memory)
+ */
+ static int *
+mb_str2wide(char_u *s)
+{
+ int *res;
+ char_u *p;
+ int i = 0;
+
+ res = (int *)alloc(sizeof(int) * (mb_charlen(s) + 1));
+ if (res != NULL)
+ {
+ for (p = s; *p != NUL; )
+ res[i++] = mb_ptr2char_adv(&p);
+ res[i] = NUL;
+ }
+ return res;
+}
+
+/*
+ * Read a tree from the .spl or .sug file.
+ * Allocates the memory and stores pointers in "bytsp" and "idxsp".
+ * This is skipped when the tree has zero length.
+ * Returns zero when OK, SP_ value for an error.
+ */
+ static int
+spell_read_tree(
+ FILE *fd,
+ char_u **bytsp,
+ idx_T **idxsp,
+ int prefixtree, /* TRUE for the prefix tree */
+ int prefixcnt) /* when "prefixtree" is TRUE: prefix count */
+{
+ long len;
+ int idx;
+ char_u *bp;
+ idx_T *ip;
+
+ /* The tree size was computed when writing the file, so that we can
+ * allocate it as one long block. <nodecount> */
+ len = get4c(fd);
+ if (len < 0)
+ return SP_TRUNCERROR;
+ if (len >= LONG_MAX / (long)sizeof(int))
+ /* Invalid length, multiply with sizeof(int) would overflow. */
+ return SP_FORMERROR;
+ if (len > 0)
+ {
+ /* Allocate the byte array. */
+ bp = lalloc((long_u)len, TRUE);
+ if (bp == NULL)
+ return SP_OTHERERROR;
+ *bytsp = bp;
+
+ /* Allocate the index array. */
+ ip = (idx_T *)lalloc_clear((long_u)(len * sizeof(int)), TRUE);
+ if (ip == NULL)
+ return SP_OTHERERROR;
+ *idxsp = ip;
+
+ /* Recursively read the tree and store it in the array. */
+ idx = read_tree_node(fd, bp, ip, len, 0, prefixtree, prefixcnt);
+ if (idx < 0)
+ return idx;
+ }
+ return 0;
+}
+
+/*
+ * Read one row of siblings from the spell file and store it in the byte array
+ * "byts" and index array "idxs". Recursively read the children.
+ *
+ * NOTE: The code here must match put_node()!
+ *
+ * Returns the index (>= 0) following the siblings.
+ * Returns SP_TRUNCERROR if the file is shorter than expected.
+ * Returns SP_FORMERROR if there is a format error.
+ */
+ static idx_T
+read_tree_node(
+ FILE *fd,
+ char_u *byts,
+ idx_T *idxs,
+ int maxidx, /* size of arrays */
+ idx_T startidx, /* current index in "byts" and "idxs" */
+ int prefixtree, /* TRUE for reading PREFIXTREE */
+ int maxprefcondnr) /* maximum for <prefcondnr> */
+{
+ int len;
+ int i;
+ int n;
+ idx_T idx = startidx;
+ int c;
+ int c2;
+#define SHARED_MASK 0x8000000
+
+ len = getc(fd); /* <siblingcount> */
+ if (len <= 0)
+ return SP_TRUNCERROR;
+
+ if (startidx + len >= maxidx)
+ return SP_FORMERROR;
+ byts[idx++] = len;
+
+ /* Read the byte values, flag/region bytes and shared indexes. */
+ for (i = 1; i <= len; ++i)
+ {
+ c = getc(fd); /* <byte> */
+ if (c < 0)
+ return SP_TRUNCERROR;
+ if (c <= BY_SPECIAL)
+ {
+ if (c == BY_NOFLAGS && !prefixtree)
+ {
+ /* No flags, all regions. */
+ idxs[idx] = 0;
+ c = 0;
+ }
+ else if (c != BY_INDEX)
+ {
+ if (prefixtree)
+ {
+ /* Read the optional pflags byte, the prefix ID and the
+ * condition nr. In idxs[] store the prefix ID in the low
+ * byte, the condition index shifted up 8 bits, the flags
+ * shifted up 24 bits. */
+ if (c == BY_FLAGS)
+ c = getc(fd) << 24; /* <pflags> */
+ else
+ c = 0;
+
+ c |= getc(fd); /* <affixID> */
+
+ n = get2c(fd); /* <prefcondnr> */
+ if (n >= maxprefcondnr)
+ return SP_FORMERROR;
+ c |= (n << 8);
+ }
+ else /* c must be BY_FLAGS or BY_FLAGS2 */
+ {
+ /* Read flags and optional region and prefix ID. In
+ * idxs[] the flags go in the low two bytes, region above
+ * that and prefix ID above the region. */
+ c2 = c;
+ c = getc(fd); /* <flags> */
+ if (c2 == BY_FLAGS2)
+ c = (getc(fd) << 8) + c; /* <flags2> */
+ if (c & WF_REGION)
+ c = (getc(fd) << 16) + c; /* <region> */
+ if (c & WF_AFX)
+ c = (getc(fd) << 24) + c; /* <affixID> */
+ }
+
+ idxs[idx] = c;
+ c = 0;
+ }
+ else /* c == BY_INDEX */
+ {
+ /* <nodeidx> */
+ n = get3c(fd);
+ if (n < 0 || n >= maxidx)
+ return SP_FORMERROR;
+ idxs[idx] = n + SHARED_MASK;
+ c = getc(fd); /* <xbyte> */
+ }
+ }
+ byts[idx++] = c;
+ }
+
+ /* Recursively read the children for non-shared siblings.
+ * Skip the end-of-word ones (zero byte value) and the shared ones (and
+ * remove SHARED_MASK) */
+ for (i = 1; i <= len; ++i)
+ if (byts[startidx + i] != 0)
+ {
+ if (idxs[startidx + i] & SHARED_MASK)
+ idxs[startidx + i] &= ~SHARED_MASK;
+ else
+ {
+ idxs[startidx + i] = idx;
+ idx = read_tree_node(fd, byts, idxs, maxidx, idx,
+ prefixtree, maxprefcondnr);
+ if (idx < 0)
+ break;
+ }
+ }
+
+ return idx;
+}
+
+/*
+ * Reload the spell file "fname" if it's loaded.
+ */
+ static void
+spell_reload_one(
+ char_u *fname,
+ int added_word) /* invoked through "zg" */
+{
+ slang_T *slang;
+ int didit = FALSE;
+
+ for (slang = first_lang; slang != NULL; slang = slang->sl_next)
+ {
+ if (fullpathcmp(fname, slang->sl_fname, FALSE) == FPC_SAME)
+ {
+ slang_clear(slang);
+ if (spell_load_file(fname, NULL, slang, FALSE) == NULL)
+ /* reloading failed, clear the language */
+ slang_clear(slang);
+ redraw_all_later(SOME_VALID);
+ didit = TRUE;
+ }
+ }
+
+ /* When "zg" was used and the file wasn't loaded yet, should redo
+ * 'spelllang' to load it now. */
+ if (added_word && !didit)
+ did_set_spelllang(curwin);
+}
+
+
+/*
+ * Functions for ":mkspell".
+ */
+
+#define MAXLINELEN 500 /* Maximum length in bytes of a line in a .aff
+ and .dic file. */
+/*
+ * Main structure to store the contents of a ".aff" file.
+ */
+typedef struct afffile_S
+{
+ char_u *af_enc; /* "SET", normalized, alloc'ed string or NULL */
+ int af_flagtype; /* AFT_CHAR, AFT_LONG, AFT_NUM or AFT_CAPLONG */
+ unsigned af_rare; /* RARE ID for rare word */
+ unsigned af_keepcase; /* KEEPCASE ID for keep-case word */
+ unsigned af_bad; /* BAD ID for banned word */
+ unsigned af_needaffix; /* NEEDAFFIX ID */
+ unsigned af_circumfix; /* CIRCUMFIX ID */
+ unsigned af_needcomp; /* NEEDCOMPOUND ID */
+ unsigned af_comproot; /* COMPOUNDROOT ID */
+ unsigned af_compforbid; /* COMPOUNDFORBIDFLAG ID */
+ unsigned af_comppermit; /* COMPOUNDPERMITFLAG ID */
+ unsigned af_nosuggest; /* NOSUGGEST ID */
+ int af_pfxpostpone; /* postpone prefixes without chop string and
+ without flags */
+ int af_ignoreextra; /* IGNOREEXTRA present */
+ hashtab_T af_pref; /* hashtable for prefixes, affheader_T */
+ hashtab_T af_suff; /* hashtable for suffixes, affheader_T */
+ hashtab_T af_comp; /* hashtable for compound flags, compitem_T */
+} afffile_T;
+
+#define AFT_CHAR 0 /* flags are one character */
+#define AFT_LONG 1 /* flags are two characters */
+#define AFT_CAPLONG 2 /* flags are one or two characters */
+#define AFT_NUM 3 /* flags are numbers, comma separated */
+
+typedef struct affentry_S affentry_T;
+/* Affix entry from ".aff" file. Used for prefixes and suffixes. */
+struct affentry_S
+{
+ affentry_T *ae_next; /* next affix with same name/number */
+ char_u *ae_chop; /* text to chop off basic word (can be NULL) */
+ char_u *ae_add; /* text to add to basic word (can be NULL) */
+ char_u *ae_flags; /* flags on the affix (can be NULL) */
+ char_u *ae_cond; /* condition (NULL for ".") */
+ regprog_T *ae_prog; /* regexp program for ae_cond or NULL */
+ char ae_compforbid; /* COMPOUNDFORBIDFLAG found */
+ char ae_comppermit; /* COMPOUNDPERMITFLAG found */
+};
+
+#define AH_KEY_LEN 17 /* 2 x 8 bytes + NUL */
+
+/* Affix header from ".aff" file. Used for af_pref and af_suff. */
+typedef struct affheader_S
+{
+ char_u ah_key[AH_KEY_LEN]; /* key for hashtab == name of affix */
+ unsigned ah_flag; /* affix name as number, uses "af_flagtype" */
+ int ah_newID; /* prefix ID after renumbering; 0 if not used */
+ int ah_combine; /* suffix may combine with prefix */
+ int ah_follows; /* another affix block should be following */
+ affentry_T *ah_first; /* first affix entry */
+} affheader_T;
+
+#define HI2AH(hi) ((affheader_T *)(hi)->hi_key)
+
+/* Flag used in compound items. */
+typedef struct compitem_S
+{
+ char_u ci_key[AH_KEY_LEN]; /* key for hashtab == name of compound */
+ unsigned ci_flag; /* affix name as number, uses "af_flagtype" */
+ int ci_newID; /* affix ID after renumbering. */
+} compitem_T;
+
+#define HI2CI(hi) ((compitem_T *)(hi)->hi_key)
+
+/*
+ * Structure that is used to store the items in the word tree. This avoids
+ * the need to keep track of each allocated thing, everything is freed all at
+ * once after ":mkspell" is done.
+ * Note: "sb_next" must be just before "sb_data" to make sure the alignment of
+ * "sb_data" is correct for systems where pointers must be aligned on
+ * pointer-size boundaries and sizeof(pointer) > sizeof(int) (e.g., Sparc).
+ */
+#define SBLOCKSIZE 16000 /* size of sb_data */
+typedef struct sblock_S sblock_T;
+struct sblock_S
+{
+ int sb_used; /* nr of bytes already in use */
+ sblock_T *sb_next; /* next block in list */
+ char_u sb_data[1]; /* data, actually longer */
+};
+
+/*
+ * A node in the tree.
+ */
+typedef struct wordnode_S wordnode_T;
+struct wordnode_S
+{
+ union /* shared to save space */
+ {
+ char_u hashkey[6]; /* the hash key, only used while compressing */
+ int index; /* index in written nodes (valid after first
+ round) */
+ } wn_u1;
+ union /* shared to save space */
+ {
+ wordnode_T *next; /* next node with same hash key */
+ wordnode_T *wnode; /* parent node that will write this node */
+ } wn_u2;
+ wordnode_T *wn_child; /* child (next byte in word) */
+ wordnode_T *wn_sibling; /* next sibling (alternate byte in word,
+ always sorted) */
+ int wn_refs; /* Nr. of references to this node. Only
+ relevant for first node in a list of
+ siblings, in following siblings it is
+ always one. */
+ char_u wn_byte; /* Byte for this node. NUL for word end */
+
+ /* Info for when "wn_byte" is NUL.
+ * In PREFIXTREE "wn_region" is used for the prefcondnr.
+ * In the soundfolded word tree "wn_flags" has the MSW of the wordnr and
+ * "wn_region" the LSW of the wordnr. */
+ char_u wn_affixID; /* supported/required prefix ID or 0 */
+ short_u wn_flags; /* WF_ flags */
+ short wn_region; /* region mask */
+
+#ifdef SPELL_PRINTTREE
+ int wn_nr; /* sequence nr for printing */
+#endif
+};
+
+#define WN_MASK 0xffff /* mask relevant bits of "wn_flags" */
+
+#define HI2WN(hi) (wordnode_T *)((hi)->hi_key)
+
+/*
+ * Info used while reading the spell files.
+ */
+typedef struct spellinfo_S
+{
+ wordnode_T *si_foldroot; /* tree with case-folded words */
+ long si_foldwcount; /* nr of words in si_foldroot */
+
+ wordnode_T *si_keeproot; /* tree with keep-case words */
+ long si_keepwcount; /* nr of words in si_keeproot */
+
+ wordnode_T *si_prefroot; /* tree with postponed prefixes */
+
+ long si_sugtree; /* creating the soundfolding trie */
+
+ sblock_T *si_blocks; /* memory blocks used */
+ long si_blocks_cnt; /* memory blocks allocated */
+ int si_did_emsg; /* TRUE when ran out of memory */
+
+ long si_compress_cnt; /* words to add before lowering
+ compression limit */
+ wordnode_T *si_first_free; /* List of nodes that have been freed during
+ compression, linked by "wn_child" field. */
+ long si_free_count; /* number of nodes in si_first_free */
+#ifdef SPELL_PRINTTREE
+ int si_wordnode_nr; /* sequence nr for nodes */
+#endif
+ buf_T *si_spellbuf; /* buffer used to store soundfold word table */
+
+ int si_ascii; /* handling only ASCII words */
+ int si_add; /* addition file */
+ int si_clear_chartab; /* when TRUE clear char tables */
+ int si_region; /* region mask */
+ vimconv_T si_conv; /* for conversion to 'encoding' */
+ int si_memtot; /* runtime memory used */
+ int si_verbose; /* verbose messages */
+ int si_msg_count; /* number of words added since last message */
+ char_u *si_info; /* info text chars or NULL */
+ int si_region_count; /* number of regions supported (1 when there
+ are no regions) */
+ char_u si_region_name[MAXREGIONS * 2 + 1];
+ /* region names; used only if
+ * si_region_count > 1) */
+
+ garray_T si_rep; /* list of fromto_T entries from REP lines */
+ garray_T si_repsal; /* list of fromto_T entries from REPSAL lines */
+ garray_T si_sal; /* list of fromto_T entries from SAL lines */
+ char_u *si_sofofr; /* SOFOFROM text */
+ char_u *si_sofoto; /* SOFOTO text */
+ int si_nosugfile; /* NOSUGFILE item found */
+ int si_nosplitsugs; /* NOSPLITSUGS item found */
+ int si_nocompoundsugs; /* NOCOMPOUNDSUGS item found */
+ int si_followup; /* soundsalike: ? */
+ int si_collapse; /* soundsalike: ? */
+ hashtab_T si_commonwords; /* hashtable for common words */
+ time_t si_sugtime; /* timestamp for .sug file */
+ int si_rem_accents; /* soundsalike: remove accents */
+ garray_T si_map; /* MAP info concatenated */
+ char_u *si_midword; /* MIDWORD chars or NULL */
+ int si_compmax; /* max nr of words for compounding */
+ int si_compminlen; /* minimal length for compounding */
+ int si_compsylmax; /* max nr of syllables for compounding */
+ int si_compoptions; /* COMP_ flags */
+ garray_T si_comppat; /* CHECKCOMPOUNDPATTERN items, each stored as
+ a string */
+ char_u *si_compflags; /* flags used for compounding */
+ char_u si_nobreak; /* NOBREAK */
+ char_u *si_syllable; /* syllable string */
+ garray_T si_prefcond; /* table with conditions for postponed
+ * prefixes, each stored as a string */
+ int si_newprefID; /* current value for ah_newID */
+ int si_newcompID; /* current value for compound ID */
+} spellinfo_T;
+
+static int is_aff_rule(char_u **items, int itemcnt, char *rulename, int mincount);
+static void aff_process_flags(afffile_T *affile, affentry_T *entry);
+static int spell_info_item(char_u *s);
+static unsigned affitem2flag(int flagtype, char_u *item, char_u *fname, int lnum);
+static unsigned get_affitem(int flagtype, char_u **pp);
+static void process_compflags(spellinfo_T *spin, afffile_T *aff, char_u *compflags);
+static void check_renumber(spellinfo_T *spin);
+static void aff_check_number(int spinval, int affval, char *name);
+static void aff_check_string(char_u *spinval, char_u *affval, char *name);
+static int str_equal(char_u *s1, char_u *s2);
+static void add_fromto(spellinfo_T *spin, garray_T *gap, char_u *from, char_u *to);
+static int sal_to_bool(char_u *s);
+static int get_affix_flags(afffile_T *affile, char_u *afflist);
+static int get_pfxlist(afffile_T *affile, char_u *afflist, char_u *store_afflist);
+static void get_compflags(afffile_T *affile, char_u *afflist, char_u *store_afflist);
+static int store_aff_word(spellinfo_T *spin, char_u *word, char_u *afflist, afffile_T *affile, hashtab_T *ht, hashtab_T *xht, int condit, int flags, char_u *pfxlist, int pfxlen);
+static void *getroom(spellinfo_T *spin, size_t len, int align);
+static char_u *getroom_save(spellinfo_T *spin, char_u *s);
+static int store_word(spellinfo_T *spin, char_u *word, int flags, int region, char_u *pfxlist, int need_affix);
+static int tree_add_word(spellinfo_T *spin, char_u *word, wordnode_T *tree, int flags, int region, int affixID);
+static wordnode_T *get_wordnode(spellinfo_T *spin);
+static void free_wordnode(spellinfo_T *spin, wordnode_T *n);
+static void wordtree_compress(spellinfo_T *spin, wordnode_T *root);
+static int node_compress(spellinfo_T *spin, wordnode_T *node, hashtab_T *ht, int *tot);
+static int node_equal(wordnode_T *n1, wordnode_T *n2);
+static void clear_node(wordnode_T *node);
+static int put_node(FILE *fd, wordnode_T *node, int idx, int regionmask, int prefixtree);
+static int sug_filltree(spellinfo_T *spin, slang_T *slang);
+static int sug_maketable(spellinfo_T *spin);
+static int sug_filltable(spellinfo_T *spin, wordnode_T *node, int startwordnr, garray_T *gap);
+static int offset2bytes(int nr, char_u *buf);
+static void sug_write(spellinfo_T *spin, char_u *fname);
+static void spell_message(spellinfo_T *spin, char_u *str);
+static void init_spellfile(void);
+
+/* In the postponed prefixes tree wn_flags is used to store the WFP_ flags,
+ * but it must be negative to indicate the prefix tree to tree_add_word().
+ * Use a negative number with the lower 8 bits zero. */
+#define PFX_FLAGS -256
+
+/* flags for "condit" argument of store_aff_word() */
+#define CONDIT_COMB 1 /* affix must combine */
+#define CONDIT_CFIX 2 /* affix must have CIRCUMFIX flag */
+#define CONDIT_SUF 4 /* add a suffix for matching flags */
+#define CONDIT_AFF 8 /* word already has an affix */
+
+/*
+ * Tunable parameters for when the tree is compressed. See 'mkspellmem'.
+ */
+static long compress_start = 30000; /* memory / SBLOCKSIZE */
+static long compress_inc = 100; /* memory / SBLOCKSIZE */
+static long compress_added = 500000; /* word count */
+
+/*
+ * Check the 'mkspellmem' option. Return FAIL if it's wrong.
+ * Sets "sps_flags".
+ */
+ int
+spell_check_msm(void)
+{
+ char_u *p = p_msm;
+ long start = 0;
+ long incr = 0;
+ long added = 0;
+
+ if (!VIM_ISDIGIT(*p))
+ return FAIL;
+ /* block count = (value * 1024) / SBLOCKSIZE (but avoid overflow)*/
+ start = (getdigits(&p) * 10) / (SBLOCKSIZE / 102);
+ if (*p != ',')
+ return FAIL;
+ ++p;
+ if (!VIM_ISDIGIT(*p))
+ return FAIL;
+ incr = (getdigits(&p) * 102) / (SBLOCKSIZE / 10);
+ if (*p != ',')
+ return FAIL;
+ ++p;
+ if (!VIM_ISDIGIT(*p))
+ return FAIL;
+ added = getdigits(&p) * 1024;
+ if (*p != NUL)
+ return FAIL;
+
+ if (start == 0 || incr == 0 || added == 0 || incr > start)
+ return FAIL;
+
+ compress_start = start;
+ compress_inc = incr;
+ compress_added = added;
+ return OK;
+}
+
+#ifdef SPELL_PRINTTREE
+/*
+ * For debugging the tree code: print the current tree in a (more or less)
+ * readable format, so that we can see what happens when adding a word and/or
+ * compressing the tree.
+ * Based on code from Olaf Seibert.
+ */
+#define PRINTLINESIZE 1000
+#define PRINTWIDTH 6
+
+#define PRINTSOME(l, depth, fmt, a1, a2) vim_snprintf(l + depth * PRINTWIDTH, \
+ PRINTLINESIZE - PRINTWIDTH * depth, fmt, a1, a2)
+
+static char line1[PRINTLINESIZE];
+static char line2[PRINTLINESIZE];
+static char line3[PRINTLINESIZE];
+
+ static void
+spell_clear_flags(wordnode_T *node)
+{
+ wordnode_T *np;
+
+ for (np = node; np != NULL; np = np->wn_sibling)
+ {
+ np->wn_u1.index = FALSE;
+ spell_clear_flags(np->wn_child);
+ }
+}
+
+ static void
+spell_print_node(wordnode_T *node, int depth)
+{
+ if (node->wn_u1.index)
+ {
+ /* Done this node before, print the reference. */
+ PRINTSOME(line1, depth, "(%d)", node->wn_nr, 0);
+ PRINTSOME(line2, depth, " ", 0, 0);
+ PRINTSOME(line3, depth, " ", 0, 0);
+ msg(line1);
+ msg(line2);
+ msg(line3);
+ }
+ else
+ {
+ node->wn_u1.index = TRUE;
+
+ if (node->wn_byte != NUL)
+ {
+ if (node->wn_child != NULL)
+ PRINTSOME(line1, depth, " %c -> ", node->wn_byte, 0);
+ else
+ /* Cannot happen? */
+ PRINTSOME(line1, depth, " %c ???", node->wn_byte, 0);
+ }
+ else
+ PRINTSOME(line1, depth, " $ ", 0, 0);
+
+ PRINTSOME(line2, depth, "%d/%d ", node->wn_nr, node->wn_refs);
+
+ if (node->wn_sibling != NULL)
+ PRINTSOME(line3, depth, " | ", 0, 0);
+ else
+ PRINTSOME(line3, depth, " ", 0, 0);
+
+ if (node->wn_byte == NUL)
+ {
+ msg(line1);
+ msg(line2);
+ msg(line3);
+ }
+
+ /* do the children */
+ if (node->wn_byte != NUL && node->wn_child != NULL)
+ spell_print_node(node->wn_child, depth + 1);
+
+ /* do the siblings */
+ if (node->wn_sibling != NULL)
+ {
+ /* get rid of all parent details except | */
+ STRCPY(line1, line3);
+ STRCPY(line2, line3);
+ spell_print_node(node->wn_sibling, depth);
+ }
+ }
+}
+
+ static void
+spell_print_tree(wordnode_T *root)
+{
+ if (root != NULL)
+ {
+ /* Clear the "wn_u1.index" fields, used to remember what has been
+ * done. */
+ spell_clear_flags(root);
+
+ /* Recursively print the tree. */
+ spell_print_node(root, 0);
+ }
+}
+#endif /* SPELL_PRINTTREE */
+
+/*
+ * Read the affix file "fname".
+ * Returns an afffile_T, NULL for complete failure.
+ */
+ static afffile_T *
+spell_read_aff(spellinfo_T *spin, char_u *fname)
+{
+ FILE *fd;
+ afffile_T *aff;
+ char_u rline[MAXLINELEN];
+ char_u *line;
+ char_u *pc = NULL;
+#define MAXITEMCNT 30
+ char_u *(items[MAXITEMCNT]);
+ int itemcnt;
+ char_u *p;
+ int lnum = 0;
+ affheader_T *cur_aff = NULL;
+ int did_postpone_prefix = FALSE;
+ int aff_todo = 0;
+ hashtab_T *tp;
+ char_u *low = NULL;
+ char_u *fol = NULL;
+ char_u *upp = NULL;
+ int do_rep;
+ int do_repsal;
+ int do_sal;
+ int do_mapline;
+ int found_map = FALSE;
+ hashitem_T *hi;
+ int l;
+ int compminlen = 0; /* COMPOUNDMIN value */
+ int compsylmax = 0; /* COMPOUNDSYLMAX value */
+ int compoptions = 0; /* COMP_ flags */
+ int compmax = 0; /* COMPOUNDWORDMAX value */
+ char_u *compflags = NULL; /* COMPOUNDFLAG and COMPOUNDRULE
+ concatenated */
+ char_u *midword = NULL; /* MIDWORD value */
+ char_u *syllable = NULL; /* SYLLABLE value */
+ char_u *sofofrom = NULL; /* SOFOFROM value */
+ char_u *sofoto = NULL; /* SOFOTO value */
+
+ /*
+ * Open the file.
+ */
+ fd = mch_fopen((char *)fname, "r");
+ if (fd == NULL)
+ {
+ semsg(_(e_notopen), fname);
+ return NULL;
+ }
+
+ vim_snprintf((char *)IObuff, IOSIZE, _("Reading affix file %s..."), fname);
+ spell_message(spin, IObuff);
+
+ /* Only do REP lines when not done in another .aff file already. */
+ do_rep = spin->si_rep.ga_len == 0;
+
+ /* Only do REPSAL lines when not done in another .aff file already. */
+ do_repsal = spin->si_repsal.ga_len == 0;
+
+ /* Only do SAL lines when not done in another .aff file already. */
+ do_sal = spin->si_sal.ga_len == 0;
+
+ /* Only do MAP lines when not done in another .aff file already. */
+ do_mapline = spin->si_map.ga_len == 0;
+
+ /*
+ * Allocate and init the afffile_T structure.
+ */
+ aff = (afffile_T *)getroom(spin, sizeof(afffile_T), TRUE);
+ if (aff == NULL)
+ {
+ fclose(fd);
+ return NULL;
+ }
+ hash_init(&aff->af_pref);
+ hash_init(&aff->af_suff);
+ hash_init(&aff->af_comp);
+
+ /*
+ * Read all the lines in the file one by one.
+ */
+ while (!vim_fgets(rline, MAXLINELEN, fd) && !got_int)
+ {
+ line_breakcheck();
+ ++lnum;
+
+ /* Skip comment lines. */
+ if (*rline == '#')
+ continue;
+
+ /* Convert from "SET" to 'encoding' when needed. */
+ vim_free(pc);
+ if (spin->si_conv.vc_type != CONV_NONE)
+ {
+ pc = string_convert(&spin->si_conv, rline, NULL);
+ if (pc == NULL)
+ {
+ smsg(_("Conversion failure for word in %s line %d: %s"),
+ fname, lnum, rline);
+ continue;
+ }
+ line = pc;
+ }
+ else
+ {
+ pc = NULL;
+ line = rline;
+ }
+
+ /* Split the line up in white separated items. Put a NUL after each
+ * item. */
+ itemcnt = 0;
+ for (p = line; ; )
+ {
+ while (*p != NUL && *p <= ' ') /* skip white space and CR/NL */
+ ++p;
+ if (*p == NUL)
+ break;
+ if (itemcnt == MAXITEMCNT) /* too many items */
+ break;
+ items[itemcnt++] = p;
+ /* A few items have arbitrary text argument, don't split them. */
+ if (itemcnt == 2 && spell_info_item(items[0]))
+ while (*p >= ' ' || *p == TAB) /* skip until CR/NL */
+ ++p;
+ else
+ while (*p > ' ') /* skip until white space or CR/NL */
+ ++p;
+ if (*p == NUL)
+ break;
+ *p++ = NUL;
+ }
+
+ /* Handle non-empty lines. */
+ if (itemcnt > 0)
+ {
+ if (is_aff_rule(items, itemcnt, "SET", 2) && aff->af_enc == NULL)
+ {
+ /* Setup for conversion from "ENC" to 'encoding'. */
+ aff->af_enc = enc_canonize(items[1]);
+ if (aff->af_enc != NULL && !spin->si_ascii
+ && convert_setup(&spin->si_conv, aff->af_enc,
+ p_enc) == FAIL)
+ smsg(_("Conversion in %s not supported: from %s to %s"),
+ fname, aff->af_enc, p_enc);
+ spin->si_conv.vc_fail = TRUE;
+ }
+ else if (is_aff_rule(items, itemcnt, "FLAG", 2)
+ && aff->af_flagtype == AFT_CHAR)
+ {
+ if (STRCMP(items[1], "long") == 0)
+ aff->af_flagtype = AFT_LONG;
+ else if (STRCMP(items[1], "num") == 0)
+ aff->af_flagtype = AFT_NUM;
+ else if (STRCMP(items[1], "caplong") == 0)
+ aff->af_flagtype = AFT_CAPLONG;
+ else
+ smsg(_("Invalid value for FLAG in %s line %d: %s"),
+ fname, lnum, items[1]);
+ if (aff->af_rare != 0
+ || aff->af_keepcase != 0
+ || aff->af_bad != 0
+ || aff->af_needaffix != 0
+ || aff->af_circumfix != 0
+ || aff->af_needcomp != 0
+ || aff->af_comproot != 0
+ || aff->af_nosuggest != 0
+ || compflags != NULL
+ || aff->af_suff.ht_used > 0
+ || aff->af_pref.ht_used > 0)
+ smsg(_("FLAG after using flags in %s line %d: %s"),
+ fname, lnum, items[1]);
+ }
+ else if (spell_info_item(items[0]))
+ {
+ p = (char_u *)getroom(spin,
+ (spin->si_info == NULL ? 0 : STRLEN(spin->si_info))
+ + STRLEN(items[0])
+ + STRLEN(items[1]) + 3, FALSE);
+ if (p != NULL)
+ {
+ if (spin->si_info != NULL)
+ {
+ STRCPY(p, spin->si_info);
+ STRCAT(p, "\n");
+ }
+ STRCAT(p, items[0]);
+ STRCAT(p, " ");
+ STRCAT(p, items[1]);
+ spin->si_info = p;
+ }
+ }
+ else if (is_aff_rule(items, itemcnt, "MIDWORD", 2)
+ && midword == NULL)
+ {
+ midword = getroom_save(spin, items[1]);
+ }
+ else if (is_aff_rule(items, itemcnt, "TRY", 2))
+ {
+ /* ignored, we look in the tree for what chars may appear */
+ }
+ /* TODO: remove "RAR" later */
+ else if ((is_aff_rule(items, itemcnt, "RAR", 2)
+ || is_aff_rule(items, itemcnt, "RARE", 2))
+ && aff->af_rare == 0)
+ {
+ aff->af_rare = affitem2flag(aff->af_flagtype, items[1],
+ fname, lnum);
+ }
+ /* TODO: remove "KEP" later */
+ else if ((is_aff_rule(items, itemcnt, "KEP", 2)
+ || is_aff_rule(items, itemcnt, "KEEPCASE", 2))
+ && aff->af_keepcase == 0)
+ {
+ aff->af_keepcase = affitem2flag(aff->af_flagtype, items[1],
+ fname, lnum);
+ }
+ else if ((is_aff_rule(items, itemcnt, "BAD", 2)
+ || is_aff_rule(items, itemcnt, "FORBIDDENWORD", 2))
+ && aff->af_bad == 0)
+ {
+ aff->af_bad = affitem2flag(aff->af_flagtype, items[1],
+ fname, lnum);
+ }
+ else if (is_aff_rule(items, itemcnt, "NEEDAFFIX", 2)
+ && aff->af_needaffix == 0)
+ {
+ aff->af_needaffix = affitem2flag(aff->af_flagtype, items[1],
+ fname, lnum);
+ }
+ else if (is_aff_rule(items, itemcnt, "CIRCUMFIX", 2)
+ && aff->af_circumfix == 0)
+ {
+ aff->af_circumfix = affitem2flag(aff->af_flagtype, items[1],
+ fname, lnum);
+ }
+ else if (is_aff_rule(items, itemcnt, "NOSUGGEST", 2)
+ && aff->af_nosuggest == 0)
+ {
+ aff->af_nosuggest = affitem2flag(aff->af_flagtype, items[1],
+ fname, lnum);
+ }
+ else if ((is_aff_rule(items, itemcnt, "NEEDCOMPOUND", 2)
+ || is_aff_rule(items, itemcnt, "ONLYINCOMPOUND", 2))
+ && aff->af_needcomp == 0)
+ {
+ aff->af_needcomp = affitem2flag(aff->af_flagtype, items[1],
+ fname, lnum);
+ }
+ else if (is_aff_rule(items, itemcnt, "COMPOUNDROOT", 2)
+ && aff->af_comproot == 0)
+ {
+ aff->af_comproot = affitem2flag(aff->af_flagtype, items[1],
+ fname, lnum);
+ }
+ else if (is_aff_rule(items, itemcnt, "COMPOUNDFORBIDFLAG", 2)
+ && aff->af_compforbid == 0)
+ {
+ aff->af_compforbid = affitem2flag(aff->af_flagtype, items[1],
+ fname, lnum);
+ if (aff->af_pref.ht_used > 0)
+ smsg(_("Defining COMPOUNDFORBIDFLAG after PFX item may give wrong results in %s line %d"),
+ fname, lnum);
+ }
+ else if (is_aff_rule(items, itemcnt, "COMPOUNDPERMITFLAG", 2)
+ && aff->af_comppermit == 0)
+ {
+ aff->af_comppermit = affitem2flag(aff->af_flagtype, items[1],
+ fname, lnum);
+ if (aff->af_pref.ht_used > 0)
+ smsg(_("Defining COMPOUNDPERMITFLAG after PFX item may give wrong results in %s line %d"),
+ fname, lnum);
+ }
+ else if (is_aff_rule(items, itemcnt, "COMPOUNDFLAG", 2)
+ && compflags == NULL)
+ {
+ /* Turn flag "c" into COMPOUNDRULE compatible string "c+",
+ * "Na" into "Na+", "1234" into "1234+". */
+ p = getroom(spin, STRLEN(items[1]) + 2, FALSE);
+ if (p != NULL)
+ {
+ STRCPY(p, items[1]);
+ STRCAT(p, "+");
+ compflags = p;
+ }
+ }
+ else if (is_aff_rule(items, itemcnt, "COMPOUNDRULES", 2))
+ {
+ /* We don't use the count, but do check that it's a number and
+ * not COMPOUNDRULE mistyped. */
+ if (atoi((char *)items[1]) == 0)
+ smsg(_("Wrong COMPOUNDRULES value in %s line %d: %s"),
+ fname, lnum, items[1]);
+ }
+ else if (is_aff_rule(items, itemcnt, "COMPOUNDRULE", 2))
+ {
+ /* Don't use the first rule if it is a number. */
+ if (compflags != NULL || *skipdigits(items[1]) != NUL)
+ {
+ /* Concatenate this string to previously defined ones,
+ * using a slash to separate them. */
+ l = (int)STRLEN(items[1]) + 1;
+ if (compflags != NULL)
+ l += (int)STRLEN(compflags) + 1;
+ p = getroom(spin, l, FALSE);
+ if (p != NULL)
+ {
+ if (compflags != NULL)
+ {
+ STRCPY(p, compflags);
+ STRCAT(p, "/");
+ }
+ STRCAT(p, items[1]);
+ compflags = p;
+ }
+ }
+ }
+ else if (is_aff_rule(items, itemcnt, "COMPOUNDWORDMAX", 2)
+ && compmax == 0)
+ {
+ compmax = atoi((char *)items[1]);
+ if (compmax == 0)
+ smsg(_("Wrong COMPOUNDWORDMAX value in %s line %d: %s"),
+ fname, lnum, items[1]);
+ }
+ else if (is_aff_rule(items, itemcnt, "COMPOUNDMIN", 2)
+ && compminlen == 0)
+ {
+ compminlen = atoi((char *)items[1]);
+ if (compminlen == 0)
+ smsg(_("Wrong COMPOUNDMIN value in %s line %d: %s"),
+ fname, lnum, items[1]);
+ }
+ else if (is_aff_rule(items, itemcnt, "COMPOUNDSYLMAX", 2)
+ && compsylmax == 0)
+ {
+ compsylmax = atoi((char *)items[1]);
+ if (compsylmax == 0)
+ smsg(_("Wrong COMPOUNDSYLMAX value in %s line %d: %s"),
+ fname, lnum, items[1]);
+ }
+ else if (is_aff_rule(items, itemcnt, "CHECKCOMPOUNDDUP", 1))
+ {
+ compoptions |= COMP_CHECKDUP;
+ }
+ else if (is_aff_rule(items, itemcnt, "CHECKCOMPOUNDREP", 1))
+ {
+ compoptions |= COMP_CHECKREP;
+ }
+ else if (is_aff_rule(items, itemcnt, "CHECKCOMPOUNDCASE", 1))
+ {
+ compoptions |= COMP_CHECKCASE;
+ }
+ else if (is_aff_rule(items, itemcnt, "CHECKCOMPOUNDTRIPLE", 1))
+ {
+ compoptions |= COMP_CHECKTRIPLE;
+ }
+ else if (is_aff_rule(items, itemcnt, "CHECKCOMPOUNDPATTERN", 2))
+ {
+ if (atoi((char *)items[1]) == 0)
+ smsg(_("Wrong CHECKCOMPOUNDPATTERN value in %s line %d: %s"),
+ fname, lnum, items[1]);
+ }
+ else if (is_aff_rule(items, itemcnt, "CHECKCOMPOUNDPATTERN", 3))
+ {
+ garray_T *gap = &spin->si_comppat;
+ int i;
+
+ /* Only add the couple if it isn't already there. */
+ for (i = 0; i < gap->ga_len - 1; i += 2)
+ if (STRCMP(((char_u **)(gap->ga_data))[i], items[1]) == 0
+ && STRCMP(((char_u **)(gap->ga_data))[i + 1],
+ items[2]) == 0)
+ break;
+ if (i >= gap->ga_len && ga_grow(gap, 2) == OK)
+ {
+ ((char_u **)(gap->ga_data))[gap->ga_len++]
+ = getroom_save(spin, items[1]);
+ ((char_u **)(gap->ga_data))[gap->ga_len++]
+ = getroom_save(spin, items[2]);
+ }
+ }
+ else if (is_aff_rule(items, itemcnt, "SYLLABLE", 2)
+ && syllable == NULL)
+ {
+ syllable = getroom_save(spin, items[1]);
+ }
+ else if (is_aff_rule(items, itemcnt, "NOBREAK", 1))
+ {
+ spin->si_nobreak = TRUE;
+ }
+ else if (is_aff_rule(items, itemcnt, "NOSPLITSUGS", 1))
+ {
+ spin->si_nosplitsugs = TRUE;
+ }
+ else if (is_aff_rule(items, itemcnt, "NOCOMPOUNDSUGS", 1))
+ {
+ spin->si_nocompoundsugs = TRUE;
+ }
+ else if (is_aff_rule(items, itemcnt, "NOSUGFILE", 1))
+ {
+ spin->si_nosugfile = TRUE;
+ }
+ else if (is_aff_rule(items, itemcnt, "PFXPOSTPONE", 1))
+ {
+ aff->af_pfxpostpone = TRUE;
+ }
+ else if (is_aff_rule(items, itemcnt, "IGNOREEXTRA", 1))
+ {
+ aff->af_ignoreextra = TRUE;
+ }
+ else if ((STRCMP(items[0], "PFX") == 0
+ || STRCMP(items[0], "SFX") == 0)
+ && aff_todo == 0
+ && itemcnt >= 4)
+ {
+ int lasti = 4;
+ char_u key[AH_KEY_LEN];
+
+ if (*items[0] == 'P')
+ tp = &aff->af_pref;
+ else
+ tp = &aff->af_suff;
+
+ /* Myspell allows the same affix name to be used multiple
+ * times. The affix files that do this have an undocumented
+ * "S" flag on all but the last block, thus we check for that
+ * and store it in ah_follows. */
+ vim_strncpy(key, items[1], AH_KEY_LEN - 1);
+ hi = hash_find(tp, key);
+ if (!HASHITEM_EMPTY(hi))
+ {
+ cur_aff = HI2AH(hi);
+ if (cur_aff->ah_combine != (*items[2] == 'Y'))
+ smsg(_("Different combining flag in continued affix block in %s line %d: %s"),
+ fname, lnum, items[1]);
+ if (!cur_aff->ah_follows)
+ smsg(_("Duplicate affix in %s line %d: %s"),
+ fname, lnum, items[1]);
+ }
+ else
+ {
+ /* New affix letter. */
+ cur_aff = (affheader_T *)getroom(spin,
+ sizeof(affheader_T), TRUE);
+ if (cur_aff == NULL)
+ break;
+ cur_aff->ah_flag = affitem2flag(aff->af_flagtype, items[1],
+ fname, lnum);
+ if (cur_aff->ah_flag == 0 || STRLEN(items[1]) >= AH_KEY_LEN)
+ break;
+ if (cur_aff->ah_flag == aff->af_bad
+ || cur_aff->ah_flag == aff->af_rare
+ || cur_aff->ah_flag == aff->af_keepcase
+ || cur_aff->ah_flag == aff->af_needaffix
+ || cur_aff->ah_flag == aff->af_circumfix
+ || cur_aff->ah_flag == aff->af_nosuggest
+ || cur_aff->ah_flag == aff->af_needcomp
+ || cur_aff->ah_flag == aff->af_comproot)
+ smsg(_("Affix also used for BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST in %s line %d: %s"),
+ fname, lnum, items[1]);
+ STRCPY(cur_aff->ah_key, items[1]);
+ hash_add(tp, cur_aff->ah_key);
+
+ cur_aff->ah_combine = (*items[2] == 'Y');
+ }
+
+ /* Check for the "S" flag, which apparently means that another
+ * block with the same affix name is following. */
+ if (itemcnt > lasti && STRCMP(items[lasti], "S") == 0)
+ {
+ ++lasti;
+ cur_aff->ah_follows = TRUE;
+ }
+ else
+ cur_aff->ah_follows = FALSE;
+
+ /* Myspell allows extra text after the item, but that might
+ * mean mistakes go unnoticed. Require a comment-starter. */
+ if (itemcnt > lasti && *items[lasti] != '#')
+ smsg(_(e_afftrailing), fname, lnum, items[lasti]);
+
+ if (STRCMP(items[2], "Y") != 0 && STRCMP(items[2], "N") != 0)
+ smsg(_("Expected Y or N in %s line %d: %s"),
+ fname, lnum, items[2]);
+
+ if (*items[0] == 'P' && aff->af_pfxpostpone)
+ {
+ if (cur_aff->ah_newID == 0)
+ {
+ /* Use a new number in the .spl file later, to be able
+ * to handle multiple .aff files. */
+ check_renumber(spin);
+ cur_aff->ah_newID = ++spin->si_newprefID;
+
+ /* We only really use ah_newID if the prefix is
+ * postponed. We know that only after handling all
+ * the items. */
+ did_postpone_prefix = FALSE;
+ }
+ else
+ /* Did use the ID in a previous block. */
+ did_postpone_prefix = TRUE;
+ }
+
+ aff_todo = atoi((char *)items[3]);
+ }
+ else if ((STRCMP(items[0], "PFX") == 0
+ || STRCMP(items[0], "SFX") == 0)
+ && aff_todo > 0
+ && STRCMP(cur_aff->ah_key, items[1]) == 0
+ && itemcnt >= 5)
+ {
+ affentry_T *aff_entry;
+ int upper = FALSE;
+ int lasti = 5;
+
+ /* Myspell allows extra text after the item, but that might
+ * mean mistakes go unnoticed. Require a comment-starter,
+ * unless IGNOREEXTRA is used. Hunspell uses a "-" item. */
+ if (itemcnt > lasti
+ && !aff->af_ignoreextra
+ && *items[lasti] != '#'
+ && (STRCMP(items[lasti], "-") != 0
+ || itemcnt != lasti + 1))
+ smsg(_(e_afftrailing), fname, lnum, items[lasti]);
+
+ /* New item for an affix letter. */
+ --aff_todo;
+ aff_entry = (affentry_T *)getroom(spin,
+ sizeof(affentry_T), TRUE);
+ if (aff_entry == NULL)
+ break;
+
+ if (STRCMP(items[2], "0") != 0)
+ aff_entry->ae_chop = getroom_save(spin, items[2]);
+ if (STRCMP(items[3], "0") != 0)
+ {
+ aff_entry->ae_add = getroom_save(spin, items[3]);
+
+ /* Recognize flags on the affix: abcd/XYZ */
+ aff_entry->ae_flags = vim_strchr(aff_entry->ae_add, '/');
+ if (aff_entry->ae_flags != NULL)
+ {
+ *aff_entry->ae_flags++ = NUL;
+ aff_process_flags(aff, aff_entry);
+ }
+ }
+
+ /* Don't use an affix entry with non-ASCII characters when
+ * "spin->si_ascii" is TRUE. */
+ if (!spin->si_ascii || !(has_non_ascii(aff_entry->ae_chop)
+ || has_non_ascii(aff_entry->ae_add)))
+ {
+ aff_entry->ae_next = cur_aff->ah_first;
+ cur_aff->ah_first = aff_entry;
+
+ if (STRCMP(items[4], ".") != 0)
+ {
+ char_u buf[MAXLINELEN];
+
+ aff_entry->ae_cond = getroom_save(spin, items[4]);
+ if (*items[0] == 'P')
+ sprintf((char *)buf, "^%s", items[4]);
+ else
+ sprintf((char *)buf, "%s$", items[4]);
+ aff_entry->ae_prog = vim_regcomp(buf,
+ RE_MAGIC + RE_STRING + RE_STRICT);
+ if (aff_entry->ae_prog == NULL)
+ smsg(_("Broken condition in %s line %d: %s"),
+ fname, lnum, items[4]);
+ }
+
+ /* For postponed prefixes we need an entry in si_prefcond
+ * for the condition. Use an existing one if possible.
+ * Can't be done for an affix with flags, ignoring
+ * COMPOUNDFORBIDFLAG and COMPOUNDPERMITFLAG. */
+ if (*items[0] == 'P' && aff->af_pfxpostpone
+ && aff_entry->ae_flags == NULL)
+ {
+ /* When the chop string is one lower-case letter and
+ * the add string ends in the upper-case letter we set
+ * the "upper" flag, clear "ae_chop" and remove the
+ * letters from "ae_add". The condition must either
+ * be empty or start with the same letter. */
+ if (aff_entry->ae_chop != NULL
+ && aff_entry->ae_add != NULL
+ && aff_entry->ae_chop[(*mb_ptr2len)(
+ aff_entry->ae_chop)] == NUL)
+ {
+ int c, c_up;
+
+ c = PTR2CHAR(aff_entry->ae_chop);
+ c_up = SPELL_TOUPPER(c);
+ if (c_up != c
+ && (aff_entry->ae_cond == NULL
+ || PTR2CHAR(aff_entry->ae_cond) == c))
+ {
+ p = aff_entry->ae_add
+ + STRLEN(aff_entry->ae_add);
+ MB_PTR_BACK(aff_entry->ae_add, p);
+ if (PTR2CHAR(p) == c_up)
+ {
+ upper = TRUE;
+ aff_entry->ae_chop = NULL;
+ *p = NUL;
+
+ /* The condition is matched with the
+ * actual word, thus must check for the
+ * upper-case letter. */
+ if (aff_entry->ae_cond != NULL)
+ {
+ char_u buf[MAXLINELEN];
+
+ if (has_mbyte)
+ {
+ onecap_copy(items[4], buf, TRUE);
+ aff_entry->ae_cond = getroom_save(
+ spin, buf);
+ }
+ else
+ *aff_entry->ae_cond = c_up;
+ if (aff_entry->ae_cond != NULL)
+ {
+ sprintf((char *)buf, "^%s",
+ aff_entry->ae_cond);
+ vim_regfree(aff_entry->ae_prog);
+ aff_entry->ae_prog = vim_regcomp(
+ buf, RE_MAGIC + RE_STRING);
+ }
+ }
+ }
+ }
+ }
+
+ if (aff_entry->ae_chop == NULL
+ && aff_entry->ae_flags == NULL)
+ {
+ int idx;
+ char_u **pp;
+ int n;
+
+ /* Find a previously used condition. */
+ for (idx = spin->si_prefcond.ga_len - 1; idx >= 0;
+ --idx)
+ {
+ p = ((char_u **)spin->si_prefcond.ga_data)[idx];
+ if (str_equal(p, aff_entry->ae_cond))
+ break;
+ }
+ if (idx < 0 && ga_grow(&spin->si_prefcond, 1) == OK)
+ {
+ /* Not found, add a new condition. */
+ idx = spin->si_prefcond.ga_len++;
+ pp = ((char_u **)spin->si_prefcond.ga_data)
+ + idx;
+ if (aff_entry->ae_cond == NULL)
+ *pp = NULL;
+ else
+ *pp = getroom_save(spin,
+ aff_entry->ae_cond);
+ }
+
+ /* Add the prefix to the prefix tree. */
+ if (aff_entry->ae_add == NULL)
+ p = (char_u *)"";
+ else
+ p = aff_entry->ae_add;
+
+ /* PFX_FLAGS is a negative number, so that
+ * tree_add_word() knows this is the prefix tree. */
+ n = PFX_FLAGS;
+ if (!cur_aff->ah_combine)
+ n |= WFP_NC;
+ if (upper)
+ n |= WFP_UP;
+ if (aff_entry->ae_comppermit)
+ n |= WFP_COMPPERMIT;
+ if (aff_entry->ae_compforbid)
+ n |= WFP_COMPFORBID;
+ tree_add_word(spin, p, spin->si_prefroot, n,
+ idx, cur_aff->ah_newID);
+ did_postpone_prefix = TRUE;
+ }
+
+ /* Didn't actually use ah_newID, backup si_newprefID. */
+ if (aff_todo == 0 && !did_postpone_prefix)
+ {
+ --spin->si_newprefID;
+ cur_aff->ah_newID = 0;
+ }
+ }
+ }
+ }
+ else if (is_aff_rule(items, itemcnt, "FOL", 2) && fol == NULL)
+ {
+ fol = vim_strsave(items[1]);
+ }
+ else if (is_aff_rule(items, itemcnt, "LOW", 2) && low == NULL)
+ {
+ low = vim_strsave(items[1]);
+ }
+ else if (is_aff_rule(items, itemcnt, "UPP", 2) && upp == NULL)
+ {
+ upp = vim_strsave(items[1]);
+ }
+ else if (is_aff_rule(items, itemcnt, "REP", 2)
+ || is_aff_rule(items, itemcnt, "REPSAL", 2))
+ {
+ /* Ignore REP/REPSAL count */;
+ if (!isdigit(*items[1]))
+ smsg(_("Expected REP(SAL) count in %s line %d"),
+ fname, lnum);
+ }
+ else if ((STRCMP(items[0], "REP") == 0
+ || STRCMP(items[0], "REPSAL") == 0)
+ && itemcnt >= 3)
+ {
+ /* REP/REPSAL item */
+ /* Myspell ignores extra arguments, we require it starts with
+ * # to detect mistakes. */
+ if (itemcnt > 3 && items[3][0] != '#')
+ smsg(_(e_afftrailing), fname, lnum, items[3]);
+ if (items[0][3] == 'S' ? do_repsal : do_rep)
+ {
+ /* Replace underscore with space (can't include a space
+ * directly). */
+ for (p = items[1]; *p != NUL; MB_PTR_ADV(p))
+ if (*p == '_')
+ *p = ' ';
+ for (p = items[2]; *p != NUL; MB_PTR_ADV(p))
+ if (*p == '_')
+ *p = ' ';
+ add_fromto(spin, items[0][3] == 'S'
+ ? &spin->si_repsal
+ : &spin->si_rep, items[1], items[2]);
+ }
+ }
+ else if (is_aff_rule(items, itemcnt, "MAP", 2))
+ {
+ /* MAP item or count */
+ if (!found_map)
+ {
+ /* First line contains the count. */
+ found_map = TRUE;
+ if (!isdigit(*items[1]))
+ smsg(_("Expected MAP count in %s line %d"),
+ fname, lnum);
+ }
+ else if (do_mapline)
+ {
+ int c;
+
+ /* Check that every character appears only once. */
+ for (p = items[1]; *p != NUL; )
+ {
+ c = mb_ptr2char_adv(&p);
+ if ((spin->si_map.ga_len > 0
+ && vim_strchr(spin->si_map.ga_data, c)
+ != NULL)
+ || vim_strchr(p, c) != NULL)
+ smsg(_("Duplicate character in MAP in %s line %d"),
+ fname, lnum);
+ }
+
+ /* We simply concatenate all the MAP strings, separated by
+ * slashes. */
+ ga_concat(&spin->si_map, items[1]);
+ ga_append(&spin->si_map, '/');
+ }
+ }
+ /* Accept "SAL from to" and "SAL from to #comment". */
+ else if (is_aff_rule(items, itemcnt, "SAL", 3))
+ {
+ if (do_sal)
+ {
+ /* SAL item (sounds-a-like)
+ * Either one of the known keys or a from-to pair. */
+ if (STRCMP(items[1], "followup") == 0)
+ spin->si_followup = sal_to_bool(items[2]);
+ else if (STRCMP(items[1], "collapse_result") == 0)
+ spin->si_collapse = sal_to_bool(items[2]);
+ else if (STRCMP(items[1], "remove_accents") == 0)
+ spin->si_rem_accents = sal_to_bool(items[2]);
+ else
+ /* when "to" is "_" it means empty */
+ add_fromto(spin, &spin->si_sal, items[1],
+ STRCMP(items[2], "_") == 0 ? (char_u *)""
+ : items[2]);
+ }
+ }
+ else if (is_aff_rule(items, itemcnt, "SOFOFROM", 2)
+ && sofofrom == NULL)
+ {
+ sofofrom = getroom_save(spin, items[1]);
+ }
+ else if (is_aff_rule(items, itemcnt, "SOFOTO", 2)
+ && sofoto == NULL)
+ {
+ sofoto = getroom_save(spin, items[1]);
+ }
+ else if (STRCMP(items[0], "COMMON") == 0)
+ {
+ int i;
+
+ for (i = 1; i < itemcnt; ++i)
+ {
+ if (HASHITEM_EMPTY(hash_find(&spin->si_commonwords,
+ items[i])))
+ {
+ p = vim_strsave(items[i]);
+ if (p == NULL)
+ break;
+ hash_add(&spin->si_commonwords, p);
+ }
+ }
+ }
+ else
+ smsg(_("Unrecognized or duplicate item in %s line %d: %s"),
+ fname, lnum, items[0]);
+ }
+ }
+
+ if (fol != NULL || low != NULL || upp != NULL)
+ {
+ if (spin->si_clear_chartab)
+ {
+ /* Clear the char type tables, don't want to use any of the
+ * currently used spell properties. */
+ init_spell_chartab();
+ spin->si_clear_chartab = FALSE;
+ }
+
+ /*
+ * Don't write a word table for an ASCII file, so that we don't check
+ * for conflicts with a word table that matches 'encoding'.
+ * Don't write one for utf-8 either, we use utf_*() and
+ * mb_get_class(), the list of chars in the file will be incomplete.
+ */
+ if (!spin->si_ascii && !enc_utf8)
+ {
+ if (fol == NULL || low == NULL || upp == NULL)
+ smsg(_("Missing FOL/LOW/UPP line in %s"), fname);
+ else
+ (void)set_spell_chartab(fol, low, upp);
+ }
+
+ vim_free(fol);
+ vim_free(low);
+ vim_free(upp);
+ }
+
+ /* Use compound specifications of the .aff file for the spell info. */
+ if (compmax != 0)
+ {
+ aff_check_number(spin->si_compmax, compmax, "COMPOUNDWORDMAX");
+ spin->si_compmax = compmax;
+ }
+
+ if (compminlen != 0)
+ {
+ aff_check_number(spin->si_compminlen, compminlen, "COMPOUNDMIN");
+ spin->si_compminlen = compminlen;
+ }
+
+ if (compsylmax != 0)
+ {
+ if (syllable == NULL)
+ smsg(_("COMPOUNDSYLMAX used without SYLLABLE"));
+ aff_check_number(spin->si_compsylmax, compsylmax, "COMPOUNDSYLMAX");
+ spin->si_compsylmax = compsylmax;
+ }
+
+ if (compoptions != 0)
+ {
+ aff_check_number(spin->si_compoptions, compoptions, "COMPOUND options");
+ spin->si_compoptions |= compoptions;
+ }
+
+ if (compflags != NULL)
+ process_compflags(spin, aff, compflags);
+
+ /* Check that we didn't use too many renumbered flags. */
+ if (spin->si_newcompID < spin->si_newprefID)
+ {
+ if (spin->si_newcompID == 127 || spin->si_newcompID == 255)
+ msg(_("Too many postponed prefixes"));
+ else if (spin->si_newprefID == 0 || spin->si_newprefID == 127)
+ msg(_("Too many compound flags"));
+ else
+ msg(_("Too many postponed prefixes and/or compound flags"));
+ }
+
+ if (syllable != NULL)
+ {
+ aff_check_string(spin->si_syllable, syllable, "SYLLABLE");
+ spin->si_syllable = syllable;
+ }
+
+ if (sofofrom != NULL || sofoto != NULL)
+ {
+ if (sofofrom == NULL || sofoto == NULL)
+ smsg(_("Missing SOFO%s line in %s"),
+ sofofrom == NULL ? "FROM" : "TO", fname);
+ else if (spin->si_sal.ga_len > 0)
+ smsg(_("Both SAL and SOFO lines in %s"), fname);
+ else
+ {
+ aff_check_string(spin->si_sofofr, sofofrom, "SOFOFROM");
+ aff_check_string(spin->si_sofoto, sofoto, "SOFOTO");
+ spin->si_sofofr = sofofrom;
+ spin->si_sofoto = sofoto;
+ }
+ }
+
+ if (midword != NULL)
+ {
+ aff_check_string(spin->si_midword, midword, "MIDWORD");
+ spin->si_midword = midword;
+ }
+
+ vim_free(pc);
+ fclose(fd);
+ return aff;
+}
+
+/*
+ * Return TRUE when items[0] equals "rulename", there are "mincount" items or
+ * a comment is following after item "mincount".
+ */
+ static int
+is_aff_rule(
+ char_u **items,
+ int itemcnt,
+ char *rulename,
+ int mincount)
+{
+ return (STRCMP(items[0], rulename) == 0
+ && (itemcnt == mincount
+ || (itemcnt > mincount && items[mincount][0] == '#')));
+}
+
+/*
+ * For affix "entry" move COMPOUNDFORBIDFLAG and COMPOUNDPERMITFLAG from
+ * ae_flags to ae_comppermit and ae_compforbid.
+ */
+ static void
+aff_process_flags(afffile_T *affile, affentry_T *entry)
+{
+ char_u *p;
+ char_u *prevp;
+ unsigned flag;
+
+ if (entry->ae_flags != NULL
+ && (affile->af_compforbid != 0 || affile->af_comppermit != 0))
+ {
+ for (p = entry->ae_flags; *p != NUL; )
+ {
+ prevp = p;
+ flag = get_affitem(affile->af_flagtype, &p);
+ if (flag == affile->af_comppermit || flag == affile->af_compforbid)
+ {
+ STRMOVE(prevp, p);
+ p = prevp;
+ if (flag == affile->af_comppermit)
+ entry->ae_comppermit = TRUE;
+ else
+ entry->ae_compforbid = TRUE;
+ }
+ if (affile->af_flagtype == AFT_NUM && *p == ',')
+ ++p;
+ }
+ if (*entry->ae_flags == NUL)
+ entry->ae_flags = NULL; /* nothing left */
+ }
+}
+
+/*
+ * Return TRUE if "s" is the name of an info item in the affix file.
+ */
+ static int
+spell_info_item(char_u *s)
+{
+ return STRCMP(s, "NAME") == 0
+ || STRCMP(s, "HOME") == 0
+ || STRCMP(s, "VERSION") == 0
+ || STRCMP(s, "AUTHOR") == 0
+ || STRCMP(s, "EMAIL") == 0
+ || STRCMP(s, "COPYRIGHT") == 0;
+}
+
+/*
+ * Turn an affix flag name into a number, according to the FLAG type.
+ * returns zero for failure.
+ */
+ static unsigned
+affitem2flag(
+ int flagtype,
+ char_u *item,
+ char_u *fname,
+ int lnum)
+{
+ unsigned res;
+ char_u *p = item;
+
+ res = get_affitem(flagtype, &p);
+ if (res == 0)
+ {
+ if (flagtype == AFT_NUM)
+ smsg(_("Flag is not a number in %s line %d: %s"),
+ fname, lnum, item);
+ else
+ smsg(_("Illegal flag in %s line %d: %s"),
+ fname, lnum, item);
+ }
+ if (*p != NUL)
+ {
+ smsg(_(e_affname), fname, lnum, item);
+ return 0;
+ }
+
+ return res;
+}
+
+/*
+ * Get one affix name from "*pp" and advance the pointer.
+ * Returns zero for an error, still advances the pointer then.
+ */
+ static unsigned
+get_affitem(int flagtype, char_u **pp)
+{
+ int res;
+
+ if (flagtype == AFT_NUM)
+ {
+ if (!VIM_ISDIGIT(**pp))
+ {
+ ++*pp; /* always advance, avoid getting stuck */
+ return 0;
+ }
+ res = getdigits(pp);
+ }
+ else
+ {
+ res = mb_ptr2char_adv(pp);
+ if (flagtype == AFT_LONG || (flagtype == AFT_CAPLONG
+ && res >= 'A' && res <= 'Z'))
+ {
+ if (**pp == NUL)
+ return 0;
+ res = mb_ptr2char_adv(pp) + (res << 16);
+ }
+ }
+ return res;
+}
+
+/*
+ * Process the "compflags" string used in an affix file and append it to
+ * spin->si_compflags.
+ * The processing involves changing the affix names to ID numbers, so that
+ * they fit in one byte.
+ */
+ static void
+process_compflags(
+ spellinfo_T *spin,
+ afffile_T *aff,
+ char_u *compflags)
+{
+ char_u *p;
+ char_u *prevp;
+ unsigned flag;
+ compitem_T *ci;
+ int id;
+ int len;
+ char_u *tp;
+ char_u key[AH_KEY_LEN];
+ hashitem_T *hi;
+
+ /* Make room for the old and the new compflags, concatenated with a / in
+ * between. Processing it makes it shorter, but we don't know by how
+ * much, thus allocate the maximum. */
+ len = (int)STRLEN(compflags) + 1;
+ if (spin->si_compflags != NULL)
+ len += (int)STRLEN(spin->si_compflags) + 1;
+ p = getroom(spin, len, FALSE);
+ if (p == NULL)
+ return;
+ if (spin->si_compflags != NULL)
+ {
+ STRCPY(p, spin->si_compflags);
+ STRCAT(p, "/");
+ }
+ spin->si_compflags = p;
+ tp = p + STRLEN(p);
+
+ for (p = compflags; *p != NUL; )
+ {
+ if (vim_strchr((char_u *)"/?*+[]", *p) != NULL)
+ /* Copy non-flag characters directly. */
+ *tp++ = *p++;
+ else
+ {
+ /* First get the flag number, also checks validity. */
+ prevp = p;
+ flag = get_affitem(aff->af_flagtype, &p);
+ if (flag != 0)
+ {
+ /* Find the flag in the hashtable. If it was used before, use
+ * the existing ID. Otherwise add a new entry. */
+ vim_strncpy(key, prevp, p - prevp);
+ hi = hash_find(&aff->af_comp, key);
+ if (!HASHITEM_EMPTY(hi))
+ id = HI2CI(hi)->ci_newID;
+ else
+ {
+ ci = (compitem_T *)getroom(spin, sizeof(compitem_T), TRUE);
+ if (ci == NULL)
+ break;
+ STRCPY(ci->ci_key, key);
+ ci->ci_flag = flag;
+ /* Avoid using a flag ID that has a special meaning in a
+ * regexp (also inside []). */
+ do
+ {
+ check_renumber(spin);
+ id = spin->si_newcompID--;
+ } while (vim_strchr((char_u *)"/?*+[]\\-^", id) != NULL);
+ ci->ci_newID = id;
+ hash_add(&aff->af_comp, ci->ci_key);
+ }
+ *tp++ = id;
+ }
+ if (aff->af_flagtype == AFT_NUM && *p == ',')
+ ++p;
+ }
+ }
+
+ *tp = NUL;
+}
+
+/*
+ * Check that the new IDs for postponed affixes and compounding don't overrun
+ * each other. We have almost 255 available, but start at 0-127 to avoid
+ * using two bytes for utf-8. When the 0-127 range is used up go to 128-255.
+ * When that is used up an error message is given.
+ */
+ static void
+check_renumber(spellinfo_T *spin)
+{
+ if (spin->si_newprefID == spin->si_newcompID && spin->si_newcompID < 128)
+ {
+ spin->si_newprefID = 127;
+ spin->si_newcompID = 255;
+ }
+}
+
+/*
+ * Return TRUE if flag "flag" appears in affix list "afflist".
+ */
+ static int
+flag_in_afflist(int flagtype, char_u *afflist, unsigned flag)
+{
+ char_u *p;
+ unsigned n;
+
+ switch (flagtype)
+ {
+ case AFT_CHAR:
+ return vim_strchr(afflist, flag) != NULL;
+
+ case AFT_CAPLONG:
+ case AFT_LONG:
+ for (p = afflist; *p != NUL; )
+ {
+ n = mb_ptr2char_adv(&p);
+ if ((flagtype == AFT_LONG || (n >= 'A' && n <= 'Z'))
+ && *p != NUL)
+ n = mb_ptr2char_adv(&p) + (n << 16);
+ if (n == flag)
+ return TRUE;
+ }
+ break;
+
+ case AFT_NUM:
+ for (p = afflist; *p != NUL; )
+ {
+ n = getdigits(&p);
+ if (n == flag)
+ return TRUE;
+ if (*p != NUL) /* skip over comma */
+ ++p;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+/*
+ * Give a warning when "spinval" and "affval" numbers are set and not the same.
+ */
+ static void
+aff_check_number(int spinval, int affval, char *name)
+{
+ if (spinval != 0 && spinval != affval)
+ smsg(_("%s value differs from what is used in another .aff file"), name);
+}
+
+/*
+ * Give a warning when "spinval" and "affval" strings are set and not the same.
+ */
+ static void
+aff_check_string(char_u *spinval, char_u *affval, char *name)
+{
+ if (spinval != NULL && STRCMP(spinval, affval) != 0)
+ smsg(_("%s value differs from what is used in another .aff file"), name);
+}
+
+/*
+ * Return TRUE if strings "s1" and "s2" are equal. Also consider both being
+ * NULL as equal.
+ */
+ static int
+str_equal(char_u *s1, char_u *s2)
+{
+ if (s1 == NULL || s2 == NULL)
+ return s1 == s2;
+ return STRCMP(s1, s2) == 0;
+}
+
+/*
+ * Add a from-to item to "gap". Used for REP and SAL items.
+ * They are stored case-folded.
+ */
+ static void
+add_fromto(
+ spellinfo_T *spin,
+ garray_T *gap,
+ char_u *from,
+ char_u *to)
+{
+ fromto_T *ftp;
+ char_u word[MAXWLEN];
+
+ if (ga_grow(gap, 1) == OK)
+ {
+ ftp = ((fromto_T *)gap->ga_data) + gap->ga_len;
+ (void)spell_casefold(from, (int)STRLEN(from), word, MAXWLEN);
+ ftp->ft_from = getroom_save(spin, word);
+ (void)spell_casefold(to, (int)STRLEN(to), word, MAXWLEN);
+ ftp->ft_to = getroom_save(spin, word);
+ ++gap->ga_len;
+ }
+}
+
+/*
+ * Convert a boolean argument in a SAL line to TRUE or FALSE;
+ */
+ static int
+sal_to_bool(char_u *s)
+{
+ return STRCMP(s, "1") == 0 || STRCMP(s, "true") == 0;
+}
+
+/*
+ * Free the structure filled by spell_read_aff().
+ */
+ static void
+spell_free_aff(afffile_T *aff)
+{
+ hashtab_T *ht;
+ hashitem_T *hi;
+ int todo;
+ affheader_T *ah;
+ affentry_T *ae;
+
+ vim_free(aff->af_enc);
+
+ /* All this trouble to free the "ae_prog" items... */
+ for (ht = &aff->af_pref; ; ht = &aff->af_suff)
+ {
+ todo = (int)ht->ht_used;
+ for (hi = ht->ht_array; todo > 0; ++hi)
+ {
+ if (!HASHITEM_EMPTY(hi))
+ {
+ --todo;
+ ah = HI2AH(hi);
+ for (ae = ah->ah_first; ae != NULL; ae = ae->ae_next)
+ vim_regfree(ae->ae_prog);
+ }
+ }
+ if (ht == &aff->af_suff)
+ break;
+ }
+
+ hash_clear(&aff->af_pref);
+ hash_clear(&aff->af_suff);
+ hash_clear(&aff->af_comp);
+}
+
+/*
+ * Read dictionary file "fname".
+ * Returns OK or FAIL;
+ */
+ static int
+spell_read_dic(spellinfo_T *spin, char_u *fname, afffile_T *affile)
+{
+ hashtab_T ht;
+ char_u line[MAXLINELEN];
+ char_u *p;
+ char_u *afflist;
+ char_u store_afflist[MAXWLEN];
+ int pfxlen;
+ int need_affix;
+ char_u *dw;
+ char_u *pc;
+ char_u *w;
+ int l;
+ hash_T hash;
+ hashitem_T *hi;
+ FILE *fd;
+ int lnum = 1;
+ int non_ascii = 0;
+ int retval = OK;
+ char_u message[MAXLINELEN + MAXWLEN];
+ int flags;
+ int duplicate = 0;
+
+ /*
+ * Open the file.
+ */
+ fd = mch_fopen((char *)fname, "r");
+ if (fd == NULL)
+ {
+ semsg(_(e_notopen), fname);
+ return FAIL;
+ }
+
+ /* The hashtable is only used to detect duplicated words. */
+ hash_init(&ht);
+
+ vim_snprintf((char *)IObuff, IOSIZE,
+ _("Reading dictionary file %s..."), fname);
+ spell_message(spin, IObuff);
+
+ /* start with a message for the first line */
+ spin->si_msg_count = 999999;
+
+ /* Read and ignore the first line: word count. */
+ (void)vim_fgets(line, MAXLINELEN, fd);
+ if (!vim_isdigit(*skipwhite(line)))
+ semsg(_("E760: No word count in %s"), fname);
+
+ /*
+ * Read all the lines in the file one by one.
+ * The words are converted to 'encoding' here, before being added to
+ * the hashtable.
+ */
+ while (!vim_fgets(line, MAXLINELEN, fd) && !got_int)
+ {
+ line_breakcheck();
+ ++lnum;
+ if (line[0] == '#' || line[0] == '/')
+ continue; /* comment line */
+
+ /* Remove CR, LF and white space from the end. White space halfway
+ * the word is kept to allow e.g., "et al.". */
+ l = (int)STRLEN(line);
+ while (l > 0 && line[l - 1] <= ' ')
+ --l;
+ if (l == 0)
+ continue; /* empty line */
+ line[l] = NUL;
+
+ /* Convert from "SET" to 'encoding' when needed. */
+ if (spin->si_conv.vc_type != CONV_NONE)
+ {
+ pc = string_convert(&spin->si_conv, line, NULL);
+ if (pc == NULL)
+ {
+ smsg(_("Conversion failure for word in %s line %d: %s"),
+ fname, lnum, line);
+ continue;
+ }
+ w = pc;
+ }
+ else
+ {
+ pc = NULL;
+ w = line;
+ }
+
+ /* Truncate the word at the "/", set "afflist" to what follows.
+ * Replace "\/" by "/" and "\\" by "\". */
+ afflist = NULL;
+ for (p = w; *p != NUL; MB_PTR_ADV(p))
+ {
+ if (*p == '\\' && (p[1] == '\\' || p[1] == '/'))
+ STRMOVE(p, p + 1);
+ else if (*p == '/')
+ {
+ *p = NUL;
+ afflist = p + 1;
+ break;
+ }
+ }
+
+ /* Skip non-ASCII words when "spin->si_ascii" is TRUE. */
+ if (spin->si_ascii && has_non_ascii(w))
+ {
+ ++non_ascii;
+ vim_free(pc);
+ continue;
+ }
+
+ /* This takes time, print a message every 10000 words. */
+ if (spin->si_verbose && spin->si_msg_count > 10000)
+ {
+ spin->si_msg_count = 0;
+ vim_snprintf((char *)message, sizeof(message),
+ _("line %6d, word %6ld - %s"),
+ lnum, spin->si_foldwcount + spin->si_keepwcount, w);
+ msg_start();
+ msg_outtrans_long_attr(message, 0);
+ msg_clr_eos();
+ msg_didout = FALSE;
+ msg_col = 0;
+ out_flush();
+ }
+
+ /* Store the word in the hashtable to be able to find duplicates. */
+ dw = (char_u *)getroom_save(spin, w);
+ if (dw == NULL)
+ {
+ retval = FAIL;
+ vim_free(pc);
+ break;
+ }
+
+ hash = hash_hash(dw);
+ hi = hash_lookup(&ht, dw, hash);
+ if (!HASHITEM_EMPTY(hi))
+ {
+ if (p_verbose > 0)
+ smsg(_("Duplicate word in %s line %d: %s"),
+ fname, lnum, dw);
+ else if (duplicate == 0)
+ smsg(_("First duplicate word in %s line %d: %s"),
+ fname, lnum, dw);
+ ++duplicate;
+ }
+ else
+ hash_add_item(&ht, hi, dw, hash);
+
+ flags = 0;
+ store_afflist[0] = NUL;
+ pfxlen = 0;
+ need_affix = FALSE;
+ if (afflist != NULL)
+ {
+ /* Extract flags from the affix list. */
+ flags |= get_affix_flags(affile, afflist);
+
+ if (affile->af_needaffix != 0 && flag_in_afflist(
+ affile->af_flagtype, afflist, affile->af_needaffix))
+ need_affix = TRUE;
+
+ if (affile->af_pfxpostpone)
+ /* Need to store the list of prefix IDs with the word. */
+ pfxlen = get_pfxlist(affile, afflist, store_afflist);
+
+ if (spin->si_compflags != NULL)
+ /* Need to store the list of compound flags with the word.
+ * Concatenate them to the list of prefix IDs. */
+ get_compflags(affile, afflist, store_afflist + pfxlen);
+ }
+
+ /* Add the word to the word tree(s). */
+ if (store_word(spin, dw, flags, spin->si_region,
+ store_afflist, need_affix) == FAIL)
+ retval = FAIL;
+
+ if (afflist != NULL)
+ {
+ /* Find all matching suffixes and add the resulting words.
+ * Additionally do matching prefixes that combine. */
+ if (store_aff_word(spin, dw, afflist, affile,
+ &affile->af_suff, &affile->af_pref,
+ CONDIT_SUF, flags, store_afflist, pfxlen) == FAIL)
+ retval = FAIL;
+
+ /* Find all matching prefixes and add the resulting words. */
+ if (store_aff_word(spin, dw, afflist, affile,
+ &affile->af_pref, NULL,
+ CONDIT_SUF, flags, store_afflist, pfxlen) == FAIL)
+ retval = FAIL;
+ }
+
+ vim_free(pc);
+ }
+
+ if (duplicate > 0)
+ smsg(_("%d duplicate word(s) in %s"), duplicate, fname);
+ if (spin->si_ascii && non_ascii > 0)
+ smsg(_("Ignored %d word(s) with non-ASCII characters in %s"),
+ non_ascii, fname);
+ hash_clear(&ht);
+
+ fclose(fd);
+ return retval;
+}
+
+/*
+ * Check for affix flags in "afflist" that are turned into word flags.
+ * Return WF_ flags.
+ */
+ static int
+get_affix_flags(afffile_T *affile, char_u *afflist)
+{
+ int flags = 0;
+
+ if (affile->af_keepcase != 0 && flag_in_afflist(
+ affile->af_flagtype, afflist, affile->af_keepcase))
+ flags |= WF_KEEPCAP | WF_FIXCAP;
+ if (affile->af_rare != 0 && flag_in_afflist(
+ affile->af_flagtype, afflist, affile->af_rare))
+ flags |= WF_RARE;
+ if (affile->af_bad != 0 && flag_in_afflist(
+ affile->af_flagtype, afflist, affile->af_bad))
+ flags |= WF_BANNED;
+ if (affile->af_needcomp != 0 && flag_in_afflist(
+ affile->af_flagtype, afflist, affile->af_needcomp))
+ flags |= WF_NEEDCOMP;
+ if (affile->af_comproot != 0 && flag_in_afflist(
+ affile->af_flagtype, afflist, affile->af_comproot))
+ flags |= WF_COMPROOT;
+ if (affile->af_nosuggest != 0 && flag_in_afflist(
+ affile->af_flagtype, afflist, affile->af_nosuggest))
+ flags |= WF_NOSUGGEST;
+ return flags;
+}
+
+/*
+ * Get the list of prefix IDs from the affix list "afflist".
+ * Used for PFXPOSTPONE.
+ * Put the resulting flags in "store_afflist[MAXWLEN]" with a terminating NUL
+ * and return the number of affixes.
+ */
+ static int
+get_pfxlist(
+ afffile_T *affile,
+ char_u *afflist,
+ char_u *store_afflist)
+{
+ char_u *p;
+ char_u *prevp;
+ int cnt = 0;
+ int id;
+ char_u key[AH_KEY_LEN];
+ hashitem_T *hi;
+
+ for (p = afflist; *p != NUL; )
+ {
+ prevp = p;
+ if (get_affitem(affile->af_flagtype, &p) != 0)
+ {
+ /* A flag is a postponed prefix flag if it appears in "af_pref"
+ * and its ID is not zero. */
+ vim_strncpy(key, prevp, p - prevp);
+ hi = hash_find(&affile->af_pref, key);
+ if (!HASHITEM_EMPTY(hi))
+ {
+ id = HI2AH(hi)->ah_newID;
+ if (id != 0)
+ store_afflist[cnt++] = id;
+ }
+ }
+ if (affile->af_flagtype == AFT_NUM && *p == ',')
+ ++p;
+ }
+
+ store_afflist[cnt] = NUL;
+ return cnt;
+}
+
+/*
+ * Get the list of compound IDs from the affix list "afflist" that are used
+ * for compound words.
+ * Puts the flags in "store_afflist[]".
+ */
+ static void
+get_compflags(
+ afffile_T *affile,
+ char_u *afflist,
+ char_u *store_afflist)
+{
+ char_u *p;
+ char_u *prevp;
+ int cnt = 0;
+ char_u key[AH_KEY_LEN];
+ hashitem_T *hi;
+
+ for (p = afflist; *p != NUL; )
+ {
+ prevp = p;
+ if (get_affitem(affile->af_flagtype, &p) != 0)
+ {
+ /* A flag is a compound flag if it appears in "af_comp". */
+ vim_strncpy(key, prevp, p - prevp);
+ hi = hash_find(&affile->af_comp, key);
+ if (!HASHITEM_EMPTY(hi))
+ store_afflist[cnt++] = HI2CI(hi)->ci_newID;
+ }
+ if (affile->af_flagtype == AFT_NUM && *p == ',')
+ ++p;
+ }
+
+ store_afflist[cnt] = NUL;
+}
+
+/*
+ * Apply affixes to a word and store the resulting words.
+ * "ht" is the hashtable with affentry_T that need to be applied, either
+ * prefixes or suffixes.
+ * "xht", when not NULL, is the prefix hashtable, to be used additionally on
+ * the resulting words for combining affixes.
+ *
+ * Returns FAIL when out of memory.
+ */
+ static int
+store_aff_word(
+ spellinfo_T *spin, /* spell info */
+ char_u *word, /* basic word start */
+ char_u *afflist, /* list of names of supported affixes */
+ afffile_T *affile,
+ hashtab_T *ht,
+ hashtab_T *xht,
+ int condit, /* CONDIT_SUF et al. */
+ int flags, /* flags for the word */
+ char_u *pfxlist, /* list of prefix IDs */
+ int pfxlen) /* nr of flags in "pfxlist" for prefixes, rest
+ * is compound flags */
+{
+ int todo;
+ hashitem_T *hi;
+ affheader_T *ah;
+ affentry_T *ae;
+ char_u newword[MAXWLEN];
+ int retval = OK;
+ int i, j;
+ char_u *p;
+ int use_flags;
+ char_u *use_pfxlist;
+ int use_pfxlen;
+ int need_affix;
+ char_u store_afflist[MAXWLEN];
+ char_u pfx_pfxlist[MAXWLEN];
+ size_t wordlen = STRLEN(word);
+ int use_condit;
+
+ todo = (int)ht->ht_used;
+ for (hi = ht->ht_array; todo > 0 && retval == OK; ++hi)
+ {
+ if (!HASHITEM_EMPTY(hi))
+ {
+ --todo;
+ ah = HI2AH(hi);
+
+ /* Check that the affix combines, if required, and that the word
+ * supports this affix. */
+ if (((condit & CONDIT_COMB) == 0 || ah->ah_combine)
+ && flag_in_afflist(affile->af_flagtype, afflist,
+ ah->ah_flag))
+ {
+ /* Loop over all affix entries with this name. */
+ for (ae = ah->ah_first; ae != NULL; ae = ae->ae_next)
+ {
+ /* Check the condition. It's not logical to match case
+ * here, but it is required for compatibility with
+ * Myspell.
+ * Another requirement from Myspell is that the chop
+ * string is shorter than the word itself.
+ * For prefixes, when "PFXPOSTPONE" was used, only do
+ * prefixes with a chop string and/or flags.
+ * When a previously added affix had CIRCUMFIX this one
+ * must have it too, if it had not then this one must not
+ * have one either. */
+ if ((xht != NULL || !affile->af_pfxpostpone
+ || ae->ae_chop != NULL
+ || ae->ae_flags != NULL)
+ && (ae->ae_chop == NULL
+ || STRLEN(ae->ae_chop) < wordlen)
+ && (ae->ae_prog == NULL
+ || vim_regexec_prog(&ae->ae_prog, FALSE,
+ word, (colnr_T)0))
+ && (((condit & CONDIT_CFIX) == 0)
+ == ((condit & CONDIT_AFF) == 0
+ || ae->ae_flags == NULL
+ || !flag_in_afflist(affile->af_flagtype,
+ ae->ae_flags, affile->af_circumfix))))
+ {
+ /* Match. Remove the chop and add the affix. */
+ if (xht == NULL)
+ {
+ /* prefix: chop/add at the start of the word */
+ if (ae->ae_add == NULL)
+ *newword = NUL;
+ else
+ vim_strncpy(newword, ae->ae_add, MAXWLEN - 1);
+ p = word;
+ if (ae->ae_chop != NULL)
+ {
+ /* Skip chop string. */
+ if (has_mbyte)
+ {
+ i = mb_charlen(ae->ae_chop);
+ for ( ; i > 0; --i)
+ MB_PTR_ADV(p);
+ }
+ else
+ p += STRLEN(ae->ae_chop);
+ }
+ STRCAT(newword, p);
+ }
+ else
+ {
+ /* suffix: chop/add at the end of the word */
+ vim_strncpy(newword, word, MAXWLEN - 1);
+ if (ae->ae_chop != NULL)
+ {
+ /* Remove chop string. */
+ p = newword + STRLEN(newword);
+ i = (int)MB_CHARLEN(ae->ae_chop);
+ for ( ; i > 0; --i)
+ MB_PTR_BACK(newword, p);
+ *p = NUL;
+ }
+ if (ae->ae_add != NULL)
+ STRCAT(newword, ae->ae_add);
+ }
+
+ use_flags = flags;
+ use_pfxlist = pfxlist;
+ use_pfxlen = pfxlen;
+ need_affix = FALSE;
+ use_condit = condit | CONDIT_COMB | CONDIT_AFF;
+ if (ae->ae_flags != NULL)
+ {
+ /* Extract flags from the affix list. */
+ use_flags |= get_affix_flags(affile, ae->ae_flags);
+
+ if (affile->af_needaffix != 0 && flag_in_afflist(
+ affile->af_flagtype, ae->ae_flags,
+ affile->af_needaffix))
+ need_affix = TRUE;
+
+ /* When there is a CIRCUMFIX flag the other affix
+ * must also have it and we don't add the word
+ * with one affix. */
+ if (affile->af_circumfix != 0 && flag_in_afflist(
+ affile->af_flagtype, ae->ae_flags,
+ affile->af_circumfix))
+ {
+ use_condit |= CONDIT_CFIX;
+ if ((condit & CONDIT_CFIX) == 0)
+ need_affix = TRUE;
+ }
+
+ if (affile->af_pfxpostpone
+ || spin->si_compflags != NULL)
+ {
+ if (affile->af_pfxpostpone)
+ /* Get prefix IDS from the affix list. */
+ use_pfxlen = get_pfxlist(affile,
+ ae->ae_flags, store_afflist);
+ else
+ use_pfxlen = 0;
+ use_pfxlist = store_afflist;
+
+ /* Combine the prefix IDs. Avoid adding the
+ * same ID twice. */
+ for (i = 0; i < pfxlen; ++i)
+ {
+ for (j = 0; j < use_pfxlen; ++j)
+ if (pfxlist[i] == use_pfxlist[j])
+ break;
+ if (j == use_pfxlen)
+ use_pfxlist[use_pfxlen++] = pfxlist[i];
+ }
+
+ if (spin->si_compflags != NULL)
+ /* Get compound IDS from the affix list. */
+ get_compflags(affile, ae->ae_flags,
+ use_pfxlist + use_pfxlen);
+
+ /* Combine the list of compound flags.
+ * Concatenate them to the prefix IDs list.
+ * Avoid adding the same ID twice. */
+ for (i = pfxlen; pfxlist[i] != NUL; ++i)
+ {
+ for (j = use_pfxlen;
+ use_pfxlist[j] != NUL; ++j)
+ if (pfxlist[i] == use_pfxlist[j])
+ break;
+ if (use_pfxlist[j] == NUL)
+ {
+ use_pfxlist[j++] = pfxlist[i];
+ use_pfxlist[j] = NUL;
+ }
+ }
+ }
+ }
+
+ /* Obey a "COMPOUNDFORBIDFLAG" of the affix: don't
+ * use the compound flags. */
+ if (use_pfxlist != NULL && ae->ae_compforbid)
+ {
+ vim_strncpy(pfx_pfxlist, use_pfxlist, use_pfxlen);
+ use_pfxlist = pfx_pfxlist;
+ }
+
+ /* When there are postponed prefixes... */
+ if (spin->si_prefroot != NULL
+ && spin->si_prefroot->wn_sibling != NULL)
+ {
+ /* ... add a flag to indicate an affix was used. */
+ use_flags |= WF_HAS_AFF;
+
+ /* ... don't use a prefix list if combining
+ * affixes is not allowed. But do use the
+ * compound flags after them. */
+ if (!ah->ah_combine && use_pfxlist != NULL)
+ use_pfxlist += use_pfxlen;
+ }
+
+ /* When compounding is supported and there is no
+ * "COMPOUNDPERMITFLAG" then forbid compounding on the
+ * side where the affix is applied. */
+ if (spin->si_compflags != NULL && !ae->ae_comppermit)
+ {
+ if (xht != NULL)
+ use_flags |= WF_NOCOMPAFT;
+ else
+ use_flags |= WF_NOCOMPBEF;
+ }
+
+ /* Store the modified word. */
+ if (store_word(spin, newword, use_flags,
+ spin->si_region, use_pfxlist,
+ need_affix) == FAIL)
+ retval = FAIL;
+
+ /* When added a prefix or a first suffix and the affix
+ * has flags may add a(nother) suffix. RECURSIVE! */
+ if ((condit & CONDIT_SUF) && ae->ae_flags != NULL)
+ if (store_aff_word(spin, newword, ae->ae_flags,
+ affile, &affile->af_suff, xht,
+ use_condit & (xht == NULL
+ ? ~0 : ~CONDIT_SUF),
+ use_flags, use_pfxlist, pfxlen) == FAIL)
+ retval = FAIL;
+
+ /* When added a suffix and combining is allowed also
+ * try adding a prefix additionally. Both for the
+ * word flags and for the affix flags. RECURSIVE! */
+ if (xht != NULL && ah->ah_combine)
+ {
+ if (store_aff_word(spin, newword,
+ afflist, affile,
+ xht, NULL, use_condit,
+ use_flags, use_pfxlist,
+ pfxlen) == FAIL
+ || (ae->ae_flags != NULL
+ && store_aff_word(spin, newword,
+ ae->ae_flags, affile,
+ xht, NULL, use_condit,
+ use_flags, use_pfxlist,
+ pfxlen) == FAIL))
+ retval = FAIL;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return retval;
+}
+
+/*
+ * Read a file with a list of words.
+ */
+ static int
+spell_read_wordfile(spellinfo_T *spin, char_u *fname)
+{
+ FILE *fd;
+ long lnum = 0;
+ char_u rline[MAXLINELEN];
+ char_u *line;
+ char_u *pc = NULL;
+ char_u *p;
+ int l;
+ int retval = OK;
+ int did_word = FALSE;
+ int non_ascii = 0;
+ int flags;
+ int regionmask;
+
+ /*
+ * Open the file.
+ */
+ fd = mch_fopen((char *)fname, "r");
+ if (fd == NULL)
+ {
+ semsg(_(e_notopen), fname);
+ return FAIL;
+ }
+
+ vim_snprintf((char *)IObuff, IOSIZE, _("Reading word file %s..."), fname);
+ spell_message(spin, IObuff);
+
+ /*
+ * Read all the lines in the file one by one.
+ */
+ while (!vim_fgets(rline, MAXLINELEN, fd) && !got_int)
+ {
+ line_breakcheck();
+ ++lnum;
+
+ /* Skip comment lines. */
+ if (*rline == '#')
+ continue;
+
+ /* Remove CR, LF and white space from the end. */
+ l = (int)STRLEN(rline);
+ while (l > 0 && rline[l - 1] <= ' ')
+ --l;
+ if (l == 0)
+ continue; /* empty or blank line */
+ rline[l] = NUL;
+
+ /* Convert from "/encoding={encoding}" to 'encoding' when needed. */
+ vim_free(pc);
+ if (spin->si_conv.vc_type != CONV_NONE)
+ {
+ pc = string_convert(&spin->si_conv, rline, NULL);
+ if (pc == NULL)
+ {
+ smsg(_("Conversion failure for word in %s line %d: %s"),
+ fname, lnum, rline);
+ continue;
+ }
+ line = pc;
+ }
+ else
+ {
+ pc = NULL;
+ line = rline;
+ }
+
+ if (*line == '/')
+ {
+ ++line;
+ if (STRNCMP(line, "encoding=", 9) == 0)
+ {
+ if (spin->si_conv.vc_type != CONV_NONE)
+ smsg(_("Duplicate /encoding= line ignored in %s line %d: %s"),
+ fname, lnum, line - 1);
+ else if (did_word)
+ smsg(_("/encoding= line after word ignored in %s line %d: %s"),
+ fname, lnum, line - 1);
+ else
+ {
+ char_u *enc;
+
+ /* Setup for conversion to 'encoding'. */
+ line += 9;
+ enc = enc_canonize(line);
+ if (enc != NULL && !spin->si_ascii
+ && convert_setup(&spin->si_conv, enc,
+ p_enc) == FAIL)
+ smsg(_("Conversion in %s not supported: from %s to %s"),
+ fname, line, p_enc);
+ vim_free(enc);
+ spin->si_conv.vc_fail = TRUE;
+ }
+ continue;
+ }
+
+ if (STRNCMP(line, "regions=", 8) == 0)
+ {
+ if (spin->si_region_count > 1)
+ smsg(_("Duplicate /regions= line ignored in %s line %d: %s"),
+ fname, lnum, line);
+ else
+ {
+ line += 8;
+ if (STRLEN(line) > MAXREGIONS * 2)
+ smsg(_("Too many regions in %s line %d: %s"),
+ fname, lnum, line);
+ else
+ {
+ spin->si_region_count = (int)STRLEN(line) / 2;
+ STRCPY(spin->si_region_name, line);
+
+ /* Adjust the mask for a word valid in all regions. */
+ spin->si_region = (1 << spin->si_region_count) - 1;
+ }
+ }
+ continue;
+ }
+
+ smsg(_("/ line ignored in %s line %d: %s"),
+ fname, lnum, line - 1);
+ continue;
+ }
+
+ flags = 0;
+ regionmask = spin->si_region;
+
+ /* Check for flags and region after a slash. */
+ p = vim_strchr(line, '/');
+ if (p != NULL)
+ {
+ *p++ = NUL;
+ while (*p != NUL)
+ {
+ if (*p == '=') /* keep-case word */
+ flags |= WF_KEEPCAP | WF_FIXCAP;
+ else if (*p == '!') /* Bad, bad, wicked word. */
+ flags |= WF_BANNED;
+ else if (*p == '?') /* Rare word. */
+ flags |= WF_RARE;
+ else if (VIM_ISDIGIT(*p)) /* region number(s) */
+ {
+ if ((flags & WF_REGION) == 0) /* first one */
+ regionmask = 0;
+ flags |= WF_REGION;
+
+ l = *p - '0';
+ if (l == 0 || l > spin->si_region_count)
+ {
+ smsg(_("Invalid region nr in %s line %d: %s"),
+ fname, lnum, p);
+ break;
+ }
+ regionmask |= 1 << (l - 1);
+ }
+ else
+ {
+ smsg(_("Unrecognized flags in %s line %d: %s"),
+ fname, lnum, p);
+ break;
+ }
+ ++p;
+ }
+ }
+
+ /* Skip non-ASCII words when "spin->si_ascii" is TRUE. */
+ if (spin->si_ascii && has_non_ascii(line))
+ {
+ ++non_ascii;
+ continue;
+ }
+
+ /* Normal word: store it. */
+ if (store_word(spin, line, flags, regionmask, NULL, FALSE) == FAIL)
+ {
+ retval = FAIL;
+ break;
+ }
+ did_word = TRUE;
+ }
+
+ vim_free(pc);
+ fclose(fd);
+
+ if (spin->si_ascii && non_ascii > 0)
+ {
+ vim_snprintf((char *)IObuff, IOSIZE,
+ _("Ignored %d words with non-ASCII characters"), non_ascii);
+ spell_message(spin, IObuff);
+ }
+
+ return retval;
+}
+
+/*
+ * Get part of an sblock_T, "len" bytes long.
+ * This avoids calling free() for every little struct we use (and keeping
+ * track of them).
+ * The memory is cleared to all zeros.
+ * Returns NULL when out of memory.
+ */
+ static void *
+getroom(
+ spellinfo_T *spin,
+ size_t len, /* length needed */
+ int align) /* align for pointer */
+{
+ char_u *p;
+ sblock_T *bl = spin->si_blocks;
+
+ if (align && bl != NULL)
+ /* Round size up for alignment. On some systems structures need to be
+ * aligned to the size of a pointer (e.g., SPARC). */
+ bl->sb_used = (bl->sb_used + sizeof(char *) - 1)
+ & ~(sizeof(char *) - 1);
+
+ if (bl == NULL || bl->sb_used + len > SBLOCKSIZE)
+ {
+ if (len >= SBLOCKSIZE)
+ bl = NULL;
+ else
+ /* Allocate a block of memory. It is not freed until much later. */
+ bl = (sblock_T *)alloc_clear(
+ (unsigned)(sizeof(sblock_T) + SBLOCKSIZE));
+ if (bl == NULL)
+ {
+ if (!spin->si_did_emsg)
+ {
+ emsg(_("E845: Insufficient memory, word list will be incomplete"));
+ spin->si_did_emsg = TRUE;
+ }
+ return NULL;
+ }
+ bl->sb_next = spin->si_blocks;
+ spin->si_blocks = bl;
+ bl->sb_used = 0;
+ ++spin->si_blocks_cnt;
+ }
+
+ p = bl->sb_data + bl->sb_used;
+ bl->sb_used += (int)len;
+
+ return p;
+}
+
+/*
+ * Make a copy of a string into memory allocated with getroom().
+ * Returns NULL when out of memory.
+ */
+ static char_u *
+getroom_save(spellinfo_T *spin, char_u *s)
+{
+ char_u *sc;
+
+ sc = (char_u *)getroom(spin, STRLEN(s) + 1, FALSE);
+ if (sc != NULL)
+ STRCPY(sc, s);
+ return sc;
+}
+
+
+/*
+ * Free the list of allocated sblock_T.
+ */
+ static void
+free_blocks(sblock_T *bl)
+{
+ sblock_T *next;
+
+ while (bl != NULL)
+ {
+ next = bl->sb_next;
+ vim_free(bl);
+ bl = next;
+ }
+}
+
+/*
+ * Allocate the root of a word tree.
+ * Returns NULL when out of memory.
+ */
+ static wordnode_T *
+wordtree_alloc(spellinfo_T *spin)
+{
+ return (wordnode_T *)getroom(spin, sizeof(wordnode_T), TRUE);
+}
+
+/*
+ * Store a word in the tree(s).
+ * Always store it in the case-folded tree. For a keep-case word this is
+ * useful when the word can also be used with all caps (no WF_FIXCAP flag) and
+ * used to find suggestions.
+ * For a keep-case word also store it in the keep-case tree.
+ * When "pfxlist" is not NULL store the word for each postponed prefix ID and
+ * compound flag.
+ */
+ static int
+store_word(
+ spellinfo_T *spin,
+ char_u *word,
+ int flags, /* extra flags, WF_BANNED */
+ int region, /* supported region(s) */
+ char_u *pfxlist, /* list of prefix IDs or NULL */
+ int need_affix) /* only store word with affix ID */
+{
+ int len = (int)STRLEN(word);
+ int ct = captype(word, word + len);
+ char_u foldword[MAXWLEN];
+ int res = OK;
+ char_u *p;
+
+ (void)spell_casefold(word, len, foldword, MAXWLEN);
+ for (p = pfxlist; res == OK; ++p)
+ {
+ if (!need_affix || (p != NULL && *p != NUL))
+ res = tree_add_word(spin, foldword, spin->si_foldroot, ct | flags,
+ region, p == NULL ? 0 : *p);
+ if (p == NULL || *p == NUL)
+ break;
+ }
+ ++spin->si_foldwcount;
+
+ if (res == OK && (ct == WF_KEEPCAP || (flags & WF_KEEPCAP)))
+ {
+ for (p = pfxlist; res == OK; ++p)
+ {
+ if (!need_affix || (p != NULL && *p != NUL))
+ res = tree_add_word(spin, word, spin->si_keeproot, flags,
+ region, p == NULL ? 0 : *p);
+ if (p == NULL || *p == NUL)
+ break;
+ }
+ ++spin->si_keepwcount;
+ }
+ return res;
+}
+
+/*
+ * Add word "word" to a word tree at "root".
+ * When "flags" < 0 we are adding to the prefix tree where "flags" is used for
+ * "rare" and "region" is the condition nr.
+ * Returns FAIL when out of memory.
+ */
+ static int
+tree_add_word(
+ spellinfo_T *spin,
+ char_u *word,
+ wordnode_T *root,
+ int flags,
+ int region,
+ int affixID)
+{
+ wordnode_T *node = root;
+ wordnode_T *np;
+ wordnode_T *copyp, **copyprev;
+ wordnode_T **prev = NULL;
+ int i;
+
+ /* Add each byte of the word to the tree, including the NUL at the end. */
+ for (i = 0; ; ++i)
+ {
+ /* When there is more than one reference to this node we need to make
+ * a copy, so that we can modify it. Copy the whole list of siblings
+ * (we don't optimize for a partly shared list of siblings). */
+ if (node != NULL && node->wn_refs > 1)
+ {
+ --node->wn_refs;
+ copyprev = prev;
+ for (copyp = node; copyp != NULL; copyp = copyp->wn_sibling)
+ {
+ /* Allocate a new node and copy the info. */
+ np = get_wordnode(spin);
+ if (np == NULL)
+ return FAIL;
+ np->wn_child = copyp->wn_child;
+ if (np->wn_child != NULL)
+ ++np->wn_child->wn_refs; /* child gets extra ref */
+ np->wn_byte = copyp->wn_byte;
+ if (np->wn_byte == NUL)
+ {
+ np->wn_flags = copyp->wn_flags;
+ np->wn_region = copyp->wn_region;
+ np->wn_affixID = copyp->wn_affixID;
+ }
+
+ /* Link the new node in the list, there will be one ref. */
+ np->wn_refs = 1;
+ if (copyprev != NULL)
+ *copyprev = np;
+ copyprev = &np->wn_sibling;
+
+ /* Let "node" point to the head of the copied list. */
+ if (copyp == node)
+ node = np;
+ }
+ }
+
+ /* Look for the sibling that has the same character. They are sorted
+ * on byte value, thus stop searching when a sibling is found with a
+ * higher byte value. For zero bytes (end of word) the sorting is
+ * done on flags and then on affixID. */
+ while (node != NULL
+ && (node->wn_byte < word[i]
+ || (node->wn_byte == NUL
+ && (flags < 0
+ ? node->wn_affixID < (unsigned)affixID
+ : (node->wn_flags < (unsigned)(flags & WN_MASK)
+ || (node->wn_flags == (flags & WN_MASK)
+ && (spin->si_sugtree
+ ? (node->wn_region & 0xffff) < region
+ : node->wn_affixID
+ < (unsigned)affixID)))))))
+ {
+ prev = &node->wn_sibling;
+ node = *prev;
+ }
+ if (node == NULL
+ || node->wn_byte != word[i]
+ || (word[i] == NUL
+ && (flags < 0
+ || spin->si_sugtree
+ || node->wn_flags != (flags & WN_MASK)
+ || node->wn_affixID != affixID)))
+ {
+ /* Allocate a new node. */
+ np = get_wordnode(spin);
+ if (np == NULL)
+ return FAIL;
+ np->wn_byte = word[i];
+
+ /* If "node" is NULL this is a new child or the end of the sibling
+ * list: ref count is one. Otherwise use ref count of sibling and
+ * make ref count of sibling one (matters when inserting in front
+ * of the list of siblings). */
+ if (node == NULL)
+ np->wn_refs = 1;
+ else
+ {
+ np->wn_refs = node->wn_refs;
+ node->wn_refs = 1;
+ }
+ if (prev != NULL)
+ *prev = np;
+ np->wn_sibling = node;
+ node = np;
+ }
+
+ if (word[i] == NUL)
+ {
+ node->wn_flags = flags;
+ node->wn_region |= region;
+ node->wn_affixID = affixID;
+ break;
+ }
+ prev = &node->wn_child;
+ node = *prev;
+ }
+#ifdef SPELL_PRINTTREE
+ smsg("Added \"%s\"", word);
+ spell_print_tree(root->wn_sibling);
+#endif
+
+ /* count nr of words added since last message */
+ ++spin->si_msg_count;
+
+ if (spin->si_compress_cnt > 1)
+ {
+ if (--spin->si_compress_cnt == 1)
+ /* Did enough words to lower the block count limit. */
+ spin->si_blocks_cnt += compress_inc;
+ }
+
+ /*
+ * When we have allocated lots of memory we need to compress the word tree
+ * to free up some room. But compression is slow, and we might actually
+ * need that room, thus only compress in the following situations:
+ * 1. When not compressed before (si_compress_cnt == 0): when using
+ * "compress_start" blocks.
+ * 2. When compressed before and used "compress_inc" blocks before
+ * adding "compress_added" words (si_compress_cnt > 1).
+ * 3. When compressed before, added "compress_added" words
+ * (si_compress_cnt == 1) and the number of free nodes drops below the
+ * maximum word length.
+ */
+#ifndef SPELL_COMPRESS_ALLWAYS
+ if (spin->si_compress_cnt == 1
+ ? spin->si_free_count < MAXWLEN
+ : spin->si_blocks_cnt >= compress_start)
+#endif
+ {
+ /* Decrement the block counter. The effect is that we compress again
+ * when the freed up room has been used and another "compress_inc"
+ * blocks have been allocated. Unless "compress_added" words have
+ * been added, then the limit is put back again. */
+ spin->si_blocks_cnt -= compress_inc;
+ spin->si_compress_cnt = compress_added;
+
+ if (spin->si_verbose)
+ {
+ msg_start();
+ msg_puts(_(msg_compressing));
+ msg_clr_eos();
+ msg_didout = FALSE;
+ msg_col = 0;
+ out_flush();
+ }
+
+ /* Compress both trees. Either they both have many nodes, which makes
+ * compression useful, or one of them is small, which means
+ * compression goes fast. But when filling the soundfold word tree
+ * there is no keep-case tree. */
+ wordtree_compress(spin, spin->si_foldroot);
+ if (affixID >= 0)
+ wordtree_compress(spin, spin->si_keeproot);
+ }
+
+ return OK;
+}
+
+/*
+ * Get a wordnode_T, either from the list of previously freed nodes or
+ * allocate a new one.
+ * Returns NULL when out of memory.
+ */
+ static wordnode_T *
+get_wordnode(spellinfo_T *spin)
+{
+ wordnode_T *n;
+
+ if (spin->si_first_free == NULL)
+ n = (wordnode_T *)getroom(spin, sizeof(wordnode_T), TRUE);
+ else
+ {
+ n = spin->si_first_free;
+ spin->si_first_free = n->wn_child;
+ vim_memset(n, 0, sizeof(wordnode_T));
+ --spin->si_free_count;
+ }
+#ifdef SPELL_PRINTTREE
+ if (n != NULL)
+ n->wn_nr = ++spin->si_wordnode_nr;
+#endif
+ return n;
+}
+
+/*
+ * Decrement the reference count on a node (which is the head of a list of
+ * siblings). If the reference count becomes zero free the node and its
+ * siblings.
+ * Returns the number of nodes actually freed.
+ */
+ static int
+deref_wordnode(spellinfo_T *spin, wordnode_T *node)
+{
+ wordnode_T *np;
+ int cnt = 0;
+
+ if (--node->wn_refs == 0)
+ {
+ for (np = node; np != NULL; np = np->wn_sibling)
+ {
+ if (np->wn_child != NULL)
+ cnt += deref_wordnode(spin, np->wn_child);
+ free_wordnode(spin, np);
+ ++cnt;
+ }
+ ++cnt; /* length field */
+ }
+ return cnt;
+}
+
+/*
+ * Free a wordnode_T for re-use later.
+ * Only the "wn_child" field becomes invalid.
+ */
+ static void
+free_wordnode(spellinfo_T *spin, wordnode_T *n)
+{
+ n->wn_child = spin->si_first_free;
+ spin->si_first_free = n;
+ ++spin->si_free_count;
+}
+
+/*
+ * Compress a tree: find tails that are identical and can be shared.
+ */
+ static void
+wordtree_compress(spellinfo_T *spin, wordnode_T *root)
+{
+ hashtab_T ht;
+ int n;
+ int tot = 0;
+ int perc;
+
+ /* Skip the root itself, it's not actually used. The first sibling is the
+ * start of the tree. */
+ if (root->wn_sibling != NULL)
+ {
+ hash_init(&ht);
+ n = node_compress(spin, root->wn_sibling, &ht, &tot);
+
+#ifndef SPELL_PRINTTREE
+ if (spin->si_verbose || p_verbose > 2)
+#endif
+ {
+ if (tot > 1000000)
+ perc = (tot - n) / (tot / 100);
+ else if (tot == 0)
+ perc = 0;
+ else
+ perc = (tot - n) * 100 / tot;
+ vim_snprintf((char *)IObuff, IOSIZE,
+ _("Compressed %d of %d nodes; %d (%d%%) remaining"),
+ n, tot, tot - n, perc);
+ spell_message(spin, IObuff);
+ }
+#ifdef SPELL_PRINTTREE
+ spell_print_tree(root->wn_sibling);
+#endif
+ hash_clear(&ht);
+ }
+}
+
+/*
+ * Compress a node, its siblings and its children, depth first.
+ * Returns the number of compressed nodes.
+ */
+ static int
+node_compress(
+ spellinfo_T *spin,
+ wordnode_T *node,
+ hashtab_T *ht,
+ int *tot) /* total count of nodes before compressing,
+ incremented while going through the tree */
+{
+ wordnode_T *np;
+ wordnode_T *tp;
+ wordnode_T *child;
+ hash_T hash;
+ hashitem_T *hi;
+ int len = 0;
+ unsigned nr, n;
+ int compressed = 0;
+
+ /*
+ * Go through the list of siblings. Compress each child and then try
+ * finding an identical child to replace it.
+ * Note that with "child" we mean not just the node that is pointed to,
+ * but the whole list of siblings of which the child node is the first.
+ */
+ for (np = node; np != NULL && !got_int; np = np->wn_sibling)
+ {
+ ++len;
+ if ((child = np->wn_child) != NULL)
+ {
+ /* Compress the child first. This fills hashkey. */
+ compressed += node_compress(spin, child, ht, tot);
+
+ /* Try to find an identical child. */
+ hash = hash_hash(child->wn_u1.hashkey);
+ hi = hash_lookup(ht, child->wn_u1.hashkey, hash);
+ if (!HASHITEM_EMPTY(hi))
+ {
+ /* There are children we encountered before with a hash value
+ * identical to the current child. Now check if there is one
+ * that is really identical. */
+ for (tp = HI2WN(hi); tp != NULL; tp = tp->wn_u2.next)
+ if (node_equal(child, tp))
+ {
+ /* Found one! Now use that child in place of the
+ * current one. This means the current child and all
+ * its siblings is unlinked from the tree. */
+ ++tp->wn_refs;
+ compressed += deref_wordnode(spin, child);
+ np->wn_child = tp;
+ break;
+ }
+ if (tp == NULL)
+ {
+ /* No other child with this hash value equals the child of
+ * the node, add it to the linked list after the first
+ * item. */
+ tp = HI2WN(hi);
+ child->wn_u2.next = tp->wn_u2.next;
+ tp->wn_u2.next = child;
+ }
+ }
+ else
+ /* No other child has this hash value, add it to the
+ * hashtable. */
+ hash_add_item(ht, hi, child->wn_u1.hashkey, hash);
+ }
+ }
+ *tot += len + 1; /* add one for the node that stores the length */
+
+ /*
+ * Make a hash key for the node and its siblings, so that we can quickly
+ * find a lookalike node. This must be done after compressing the sibling
+ * list, otherwise the hash key would become invalid by the compression.
+ */
+ node->wn_u1.hashkey[0] = len;
+ nr = 0;
+ for (np = node; np != NULL; np = np->wn_sibling)
+ {
+ if (np->wn_byte == NUL)
+ /* end node: use wn_flags, wn_region and wn_affixID */
+ n = np->wn_flags + (np->wn_region << 8) + (np->wn_affixID << 16);
+ else
+ /* byte node: use the byte value and the child pointer */
+ n = (unsigned)(np->wn_byte + ((long_u)np->wn_child << 8));
+ nr = nr * 101 + n;
+ }
+
+ /* Avoid NUL bytes, it terminates the hash key. */
+ n = nr & 0xff;
+ node->wn_u1.hashkey[1] = n == 0 ? 1 : n;
+ n = (nr >> 8) & 0xff;
+ node->wn_u1.hashkey[2] = n == 0 ? 1 : n;
+ n = (nr >> 16) & 0xff;
+ node->wn_u1.hashkey[3] = n == 0 ? 1 : n;
+ n = (nr >> 24) & 0xff;
+ node->wn_u1.hashkey[4] = n == 0 ? 1 : n;
+ node->wn_u1.hashkey[5] = NUL;
+
+ /* Check for CTRL-C pressed now and then. */
+ fast_breakcheck();
+
+ return compressed;
+}
+
+/*
+ * Return TRUE when two nodes have identical siblings and children.
+ */
+ static int
+node_equal(wordnode_T *n1, wordnode_T *n2)
+{
+ wordnode_T *p1;
+ wordnode_T *p2;
+
+ for (p1 = n1, p2 = n2; p1 != NULL && p2 != NULL;
+ p1 = p1->wn_sibling, p2 = p2->wn_sibling)
+ if (p1->wn_byte != p2->wn_byte
+ || (p1->wn_byte == NUL
+ ? (p1->wn_flags != p2->wn_flags
+ || p1->wn_region != p2->wn_region
+ || p1->wn_affixID != p2->wn_affixID)
+ : (p1->wn_child != p2->wn_child)))
+ break;
+
+ return p1 == NULL && p2 == NULL;
+}
+
+static int
+#ifdef __BORLANDC__
+_RTLENTRYF
+#endif
+rep_compare(const void *s1, const void *s2);
+
+/*
+ * Function given to qsort() to sort the REP items on "from" string.
+ */
+ static int
+#ifdef __BORLANDC__
+_RTLENTRYF
+#endif
+rep_compare(const void *s1, const void *s2)
+{
+ fromto_T *p1 = (fromto_T *)s1;
+ fromto_T *p2 = (fromto_T *)s2;
+
+ return STRCMP(p1->ft_from, p2->ft_from);
+}
+
+/*
+ * Write the Vim .spl file "fname".
+ * Return FAIL or OK;
+ */
+ static int
+write_vim_spell(spellinfo_T *spin, char_u *fname)
+{
+ FILE *fd;
+ int regionmask;
+ int round;
+ wordnode_T *tree;
+ int nodecount;
+ int i;
+ int l;
+ garray_T *gap;
+ fromto_T *ftp;
+ char_u *p;
+ int rr;
+ int retval = OK;
+ size_t fwv = 1; /* collect return value of fwrite() to avoid
+ warnings from picky compiler */
+
+ fd = mch_fopen((char *)fname, "w");
+ if (fd == NULL)
+ {
+ semsg(_(e_notopen), fname);
+ return FAIL;
+ }
+
+ /* <HEADER>: <fileID> <versionnr> */
+ /* <fileID> */
+ fwv &= fwrite(VIMSPELLMAGIC, VIMSPELLMAGICL, (size_t)1, fd);
+ if (fwv != (size_t)1)
+ /* Catch first write error, don't try writing more. */
+ goto theend;
+
+ putc(VIMSPELLVERSION, fd); /* <versionnr> */
+
+ /*
+ * <SECTIONS>: <section> ... <sectionend>
+ */
+
+ /* SN_INFO: <infotext> */
+ if (spin->si_info != NULL)
+ {
+ putc(SN_INFO, fd); /* <sectionID> */
+ putc(0, fd); /* <sectionflags> */
+
+ i = (int)STRLEN(spin->si_info);
+ put_bytes(fd, (long_u)i, 4); /* <sectionlen> */
+ fwv &= fwrite(spin->si_info, (size_t)i, (size_t)1, fd); /* <infotext> */
+ }
+
+ /* SN_REGION: <regionname> ...
+ * Write the region names only if there is more than one. */
+ if (spin->si_region_count > 1)
+ {
+ putc(SN_REGION, fd); /* <sectionID> */
+ putc(SNF_REQUIRED, fd); /* <sectionflags> */
+ l = spin->si_region_count * 2;
+ put_bytes(fd, (long_u)l, 4); /* <sectionlen> */
+ fwv &= fwrite(spin->si_region_name, (size_t)l, (size_t)1, fd);
+ /* <regionname> ... */
+ regionmask = (1 << spin->si_region_count) - 1;
+ }
+ else
+ regionmask = 0;
+
+ /* SN_CHARFLAGS: <charflagslen> <charflags> <folcharslen> <folchars>
+ *
+ * The table with character flags and the table for case folding.
+ * This makes sure the same characters are recognized as word characters
+ * when generating an when using a spell file.
+ * Skip this for ASCII, the table may conflict with the one used for
+ * 'encoding'.
+ * Also skip this for an .add.spl file, the main spell file must contain
+ * the table (avoids that it conflicts). File is shorter too.
+ */
+ if (!spin->si_ascii && !spin->si_add)
+ {
+ char_u folchars[128 * 8];
+ int flags;
+
+ putc(SN_CHARFLAGS, fd); /* <sectionID> */
+ putc(SNF_REQUIRED, fd); /* <sectionflags> */
+
+ /* Form the <folchars> string first, we need to know its length. */
+ l = 0;
+ for (i = 128; i < 256; ++i)
+ {
+ if (has_mbyte)
+ l += mb_char2bytes(spelltab.st_fold[i], folchars + l);
+ else
+ folchars[l++] = spelltab.st_fold[i];
+ }
+ put_bytes(fd, (long_u)(1 + 128 + 2 + l), 4); /* <sectionlen> */
+
+ fputc(128, fd); /* <charflagslen> */
+ for (i = 128; i < 256; ++i)
+ {
+ flags = 0;
+ if (spelltab.st_isw[i])
+ flags |= CF_WORD;
+ if (spelltab.st_isu[i])
+ flags |= CF_UPPER;
+ fputc(flags, fd); /* <charflags> */
+ }
+
+ put_bytes(fd, (long_u)l, 2); /* <folcharslen> */
+ fwv &= fwrite(folchars, (size_t)l, (size_t)1, fd); /* <folchars> */
+ }
+
+ /* SN_MIDWORD: <midword> */
+ if (spin->si_midword != NULL)
+ {
+ putc(SN_MIDWORD, fd); /* <sectionID> */
+ putc(SNF_REQUIRED, fd); /* <sectionflags> */
+
+ i = (int)STRLEN(spin->si_midword);
+ put_bytes(fd, (long_u)i, 4); /* <sectionlen> */
+ fwv &= fwrite(spin->si_midword, (size_t)i, (size_t)1, fd);
+ /* <midword> */
+ }
+
+ /* SN_PREFCOND: <prefcondcnt> <prefcond> ... */
+ if (spin->si_prefcond.ga_len > 0)
+ {
+ putc(SN_PREFCOND, fd); /* <sectionID> */
+ putc(SNF_REQUIRED, fd); /* <sectionflags> */
+
+ l = write_spell_prefcond(NULL, &spin->si_prefcond);
+ put_bytes(fd, (long_u)l, 4); /* <sectionlen> */
+
+ write_spell_prefcond(fd, &spin->si_prefcond);
+ }
+
+ /* SN_REP: <repcount> <rep> ...
+ * SN_SAL: <salflags> <salcount> <sal> ...
+ * SN_REPSAL: <repcount> <rep> ... */
+
+ /* round 1: SN_REP section
+ * round 2: SN_SAL section (unless SN_SOFO is used)
+ * round 3: SN_REPSAL section */
+ for (round = 1; round <= 3; ++round)
+ {
+ if (round == 1)
+ gap = &spin->si_rep;
+ else if (round == 2)
+ {
+ /* Don't write SN_SAL when using a SN_SOFO section */
+ if (spin->si_sofofr != NULL && spin->si_sofoto != NULL)
+ continue;
+ gap = &spin->si_sal;
+ }
+ else
+ gap = &spin->si_repsal;
+
+ /* Don't write the section if there are no items. */
+ if (gap->ga_len == 0)
+ continue;
+
+ /* Sort the REP/REPSAL items. */
+ if (round != 2)
+ qsort(gap->ga_data, (size_t)gap->ga_len,
+ sizeof(fromto_T), rep_compare);
+
+ i = round == 1 ? SN_REP : (round == 2 ? SN_SAL : SN_REPSAL);
+ putc(i, fd); /* <sectionID> */
+
+ /* This is for making suggestions, section is not required. */
+ putc(0, fd); /* <sectionflags> */
+
+ /* Compute the length of what follows. */
+ l = 2; /* count <repcount> or <salcount> */
+ for (i = 0; i < gap->ga_len; ++i)
+ {
+ ftp = &((fromto_T *)gap->ga_data)[i];
+ l += 1 + (int)STRLEN(ftp->ft_from); /* count <*fromlen> and <*from> */
+ l += 1 + (int)STRLEN(ftp->ft_to); /* count <*tolen> and <*to> */
+ }
+ if (round == 2)
+ ++l; /* count <salflags> */
+ put_bytes(fd, (long_u)l, 4); /* <sectionlen> */
+
+ if (round == 2)
+ {
+ i = 0;
+ if (spin->si_followup)
+ i |= SAL_F0LLOWUP;
+ if (spin->si_collapse)
+ i |= SAL_COLLAPSE;
+ if (spin->si_rem_accents)
+ i |= SAL_REM_ACCENTS;
+ putc(i, fd); /* <salflags> */
+ }
+
+ put_bytes(fd, (long_u)gap->ga_len, 2); /* <repcount> or <salcount> */
+ for (i = 0; i < gap->ga_len; ++i)
+ {
+ /* <rep> : <repfromlen> <repfrom> <reptolen> <repto> */
+ /* <sal> : <salfromlen> <salfrom> <saltolen> <salto> */
+ ftp = &((fromto_T *)gap->ga_data)[i];
+ for (rr = 1; rr <= 2; ++rr)
+ {
+ p = rr == 1 ? ftp->ft_from : ftp->ft_to;
+ l = (int)STRLEN(p);
+ putc(l, fd);
+ if (l > 0)
+ fwv &= fwrite(p, l, (size_t)1, fd);
+ }
+ }
+
+ }
+
+ /* SN_SOFO: <sofofromlen> <sofofrom> <sofotolen> <sofoto>
+ * This is for making suggestions, section is not required. */
+ if (spin->si_sofofr != NULL && spin->si_sofoto != NULL)
+ {
+ putc(SN_SOFO, fd); /* <sectionID> */
+ putc(0, fd); /* <sectionflags> */
+
+ l = (int)STRLEN(spin->si_sofofr);
+ put_bytes(fd, (long_u)(l + STRLEN(spin->si_sofoto) + 4), 4);
+ /* <sectionlen> */
+
+ put_bytes(fd, (long_u)l, 2); /* <sofofromlen> */
+ fwv &= fwrite(spin->si_sofofr, l, (size_t)1, fd); /* <sofofrom> */
+
+ l = (int)STRLEN(spin->si_sofoto);
+ put_bytes(fd, (long_u)l, 2); /* <sofotolen> */
+ fwv &= fwrite(spin->si_sofoto, l, (size_t)1, fd); /* <sofoto> */
+ }
+
+ /* SN_WORDS: <word> ...
+ * This is for making suggestions, section is not required. */
+ if (spin->si_commonwords.ht_used > 0)
+ {
+ putc(SN_WORDS, fd); /* <sectionID> */
+ putc(0, fd); /* <sectionflags> */
+
+ /* round 1: count the bytes
+ * round 2: write the bytes */
+ for (round = 1; round <= 2; ++round)
+ {
+ int todo;
+ int len = 0;
+ hashitem_T *hi;
+
+ todo = (int)spin->si_commonwords.ht_used;
+ for (hi = spin->si_commonwords.ht_array; todo > 0; ++hi)
+ if (!HASHITEM_EMPTY(hi))
+ {
+ l = (int)STRLEN(hi->hi_key) + 1;
+ len += l;
+ if (round == 2) /* <word> */
+ fwv &= fwrite(hi->hi_key, (size_t)l, (size_t)1, fd);
+ --todo;
+ }
+ if (round == 1)
+ put_bytes(fd, (long_u)len, 4); /* <sectionlen> */
+ }
+ }
+
+ /* SN_MAP: <mapstr>
+ * This is for making suggestions, section is not required. */
+ if (spin->si_map.ga_len > 0)
+ {
+ putc(SN_MAP, fd); /* <sectionID> */
+ putc(0, fd); /* <sectionflags> */
+ l = spin->si_map.ga_len;
+ put_bytes(fd, (long_u)l, 4); /* <sectionlen> */
+ fwv &= fwrite(spin->si_map.ga_data, (size_t)l, (size_t)1, fd);
+ /* <mapstr> */
+ }
+
+ /* SN_SUGFILE: <timestamp>
+ * This is used to notify that a .sug file may be available and at the
+ * same time allows for checking that a .sug file that is found matches
+ * with this .spl file. That's because the word numbers must be exactly
+ * right. */
+ if (!spin->si_nosugfile
+ && (spin->si_sal.ga_len > 0
+ || (spin->si_sofofr != NULL && spin->si_sofoto != NULL)))
+ {
+ putc(SN_SUGFILE, fd); /* <sectionID> */
+ putc(0, fd); /* <sectionflags> */
+ put_bytes(fd, (long_u)8, 4); /* <sectionlen> */
+
+ /* Set si_sugtime and write it to the file. */
+ spin->si_sugtime = time(NULL);
+ put_time(fd, spin->si_sugtime); /* <timestamp> */
+ }
+
+ /* SN_NOSPLITSUGS: nothing
+ * This is used to notify that no suggestions with word splits are to be
+ * made. */
+ if (spin->si_nosplitsugs)
+ {
+ putc(SN_NOSPLITSUGS, fd); /* <sectionID> */
+ putc(0, fd); /* <sectionflags> */
+ put_bytes(fd, (long_u)0, 4); /* <sectionlen> */
+ }
+
+ /* SN_NOCOMPUNDSUGS: nothing
+ * This is used to notify that no suggestions with compounds are to be
+ * made. */
+ if (spin->si_nocompoundsugs)
+ {
+ putc(SN_NOCOMPOUNDSUGS, fd); /* <sectionID> */
+ putc(0, fd); /* <sectionflags> */
+ put_bytes(fd, (long_u)0, 4); /* <sectionlen> */
+ }
+
+ /* SN_COMPOUND: compound info.
+ * We don't mark it required, when not supported all compound words will
+ * be bad words. */
+ if (spin->si_compflags != NULL)
+ {
+ putc(SN_COMPOUND, fd); /* <sectionID> */
+ putc(0, fd); /* <sectionflags> */
+
+ l = (int)STRLEN(spin->si_compflags);
+ for (i = 0; i < spin->si_comppat.ga_len; ++i)
+ l += (int)STRLEN(((char_u **)(spin->si_comppat.ga_data))[i]) + 1;
+ put_bytes(fd, (long_u)(l + 7), 4); /* <sectionlen> */
+
+ putc(spin->si_compmax, fd); /* <compmax> */
+ putc(spin->si_compminlen, fd); /* <compminlen> */
+ putc(spin->si_compsylmax, fd); /* <compsylmax> */
+ putc(0, fd); /* for Vim 7.0b compatibility */
+ putc(spin->si_compoptions, fd); /* <compoptions> */
+ put_bytes(fd, (long_u)spin->si_comppat.ga_len, 2);
+ /* <comppatcount> */
+ for (i = 0; i < spin->si_comppat.ga_len; ++i)
+ {
+ p = ((char_u **)(spin->si_comppat.ga_data))[i];
+ putc((int)STRLEN(p), fd); /* <comppatlen> */
+ fwv &= fwrite(p, (size_t)STRLEN(p), (size_t)1, fd);
+ /* <comppattext> */
+ }
+ /* <compflags> */
+ fwv &= fwrite(spin->si_compflags, (size_t)STRLEN(spin->si_compflags),
+ (size_t)1, fd);
+ }
+
+ /* SN_NOBREAK: NOBREAK flag */
+ if (spin->si_nobreak)
+ {
+ putc(SN_NOBREAK, fd); /* <sectionID> */
+ putc(0, fd); /* <sectionflags> */
+
+ /* It's empty, the presence of the section flags the feature. */
+ put_bytes(fd, (long_u)0, 4); /* <sectionlen> */
+ }
+
+ /* SN_SYLLABLE: syllable info.
+ * We don't mark it required, when not supported syllables will not be
+ * counted. */
+ if (spin->si_syllable != NULL)
+ {
+ putc(SN_SYLLABLE, fd); /* <sectionID> */
+ putc(0, fd); /* <sectionflags> */
+
+ l = (int)STRLEN(spin->si_syllable);
+ put_bytes(fd, (long_u)l, 4); /* <sectionlen> */
+ fwv &= fwrite(spin->si_syllable, (size_t)l, (size_t)1, fd);
+ /* <syllable> */
+ }
+
+ /* end of <SECTIONS> */
+ putc(SN_END, fd); /* <sectionend> */
+
+
+ /*
+ * <LWORDTREE> <KWORDTREE> <PREFIXTREE>
+ */
+ spin->si_memtot = 0;
+ for (round = 1; round <= 3; ++round)
+ {
+ if (round == 1)
+ tree = spin->si_foldroot->wn_sibling;
+ else if (round == 2)
+ tree = spin->si_keeproot->wn_sibling;
+ else
+ tree = spin->si_prefroot->wn_sibling;
+
+ /* Clear the index and wnode fields in the tree. */
+ clear_node(tree);
+
+ /* Count the number of nodes. Needed to be able to allocate the
+ * memory when reading the nodes. Also fills in index for shared
+ * nodes. */
+ nodecount = put_node(NULL, tree, 0, regionmask, round == 3);
+
+ /* number of nodes in 4 bytes */
+ put_bytes(fd, (long_u)nodecount, 4); /* <nodecount> */
+ spin->si_memtot += nodecount + nodecount * sizeof(int);
+
+ /* Write the nodes. */
+ (void)put_node(fd, tree, 0, regionmask, round == 3);
+ }
+
+ /* Write another byte to check for errors (file system full). */
+ if (putc(0, fd) == EOF)
+ retval = FAIL;
+theend:
+ if (fclose(fd) == EOF)
+ retval = FAIL;
+
+ if (fwv != (size_t)1)
+ retval = FAIL;
+ if (retval == FAIL)
+ emsg(_(e_write));
+
+ return retval;
+}
+
+/*
+ * Clear the index and wnode fields of "node", it siblings and its
+ * children. This is needed because they are a union with other items to save
+ * space.
+ */
+ static void
+clear_node(wordnode_T *node)
+{
+ wordnode_T *np;
+
+ if (node != NULL)
+ for (np = node; np != NULL; np = np->wn_sibling)
+ {
+ np->wn_u1.index = 0;
+ np->wn_u2.wnode = NULL;
+
+ if (np->wn_byte != NUL)
+ clear_node(np->wn_child);
+ }
+}
+
+
+/*
+ * Dump a word tree at node "node".
+ *
+ * This first writes the list of possible bytes (siblings). Then for each
+ * byte recursively write the children.
+ *
+ * NOTE: The code here must match the code in read_tree_node(), since
+ * assumptions are made about the indexes (so that we don't have to write them
+ * in the file).
+ *
+ * Returns the number of nodes used.
+ */
+ static int
+put_node(
+ FILE *fd, /* NULL when only counting */
+ wordnode_T *node,
+ int idx,
+ int regionmask,
+ int prefixtree) /* TRUE for PREFIXTREE */
+{
+ int newindex = idx;
+ int siblingcount = 0;
+ wordnode_T *np;
+ int flags;
+
+ /* If "node" is zero the tree is empty. */
+ if (node == NULL)
+ return 0;
+
+ /* Store the index where this node is written. */
+ node->wn_u1.index = idx;
+
+ /* Count the number of siblings. */
+ for (np = node; np != NULL; np = np->wn_sibling)
+ ++siblingcount;
+
+ /* Write the sibling count. */
+ if (fd != NULL)
+ putc(siblingcount, fd); /* <siblingcount> */
+
+ /* Write each sibling byte and optionally extra info. */
+ for (np = node; np != NULL; np = np->wn_sibling)
+ {
+ if (np->wn_byte == 0)
+ {
+ if (fd != NULL)
+ {
+ /* For a NUL byte (end of word) write the flags etc. */
+ if (prefixtree)
+ {
+ /* In PREFIXTREE write the required affixID and the
+ * associated condition nr (stored in wn_region). The
+ * byte value is misused to store the "rare" and "not
+ * combining" flags */
+ if (np->wn_flags == (short_u)PFX_FLAGS)
+ putc(BY_NOFLAGS, fd); /* <byte> */
+ else
+ {
+ putc(BY_FLAGS, fd); /* <byte> */
+ putc(np->wn_flags, fd); /* <pflags> */
+ }
+ putc(np->wn_affixID, fd); /* <affixID> */
+ put_bytes(fd, (long_u)np->wn_region, 2); /* <prefcondnr> */
+ }
+ else
+ {
+ /* For word trees we write the flag/region items. */
+ flags = np->wn_flags;
+ if (regionmask != 0 && np->wn_region != regionmask)
+ flags |= WF_REGION;
+ if (np->wn_affixID != 0)
+ flags |= WF_AFX;
+ if (flags == 0)
+ {
+ /* word without flags or region */
+ putc(BY_NOFLAGS, fd); /* <byte> */
+ }
+ else
+ {
+ if (np->wn_flags >= 0x100)
+ {
+ putc(BY_FLAGS2, fd); /* <byte> */
+ putc(flags, fd); /* <flags> */
+ putc((unsigned)flags >> 8, fd); /* <flags2> */
+ }
+ else
+ {
+ putc(BY_FLAGS, fd); /* <byte> */
+ putc(flags, fd); /* <flags> */
+ }
+ if (flags & WF_REGION)
+ putc(np->wn_region, fd); /* <region> */
+ if (flags & WF_AFX)
+ putc(np->wn_affixID, fd); /* <affixID> */
+ }
+ }
+ }
+ }
+ else
+ {
+ if (np->wn_child->wn_u1.index != 0
+ && np->wn_child->wn_u2.wnode != node)
+ {
+ /* The child is written elsewhere, write the reference. */
+ if (fd != NULL)
+ {
+ putc(BY_INDEX, fd); /* <byte> */
+ /* <nodeidx> */
+ put_bytes(fd, (long_u)np->wn_child->wn_u1.index, 3);
+ }
+ }
+ else if (np->wn_child->wn_u2.wnode == NULL)
+ /* We will write the child below and give it an index. */
+ np->wn_child->wn_u2.wnode = node;
+
+ if (fd != NULL)
+ if (putc(np->wn_byte, fd) == EOF) /* <byte> or <xbyte> */
+ {
+ emsg(_(e_write));
+ return 0;
+ }
+ }
+ }
+
+ /* Space used in the array when reading: one for each sibling and one for
+ * the count. */
+ newindex += siblingcount + 1;
+
+ /* Recursively dump the children of each sibling. */
+ for (np = node; np != NULL; np = np->wn_sibling)
+ if (np->wn_byte != 0 && np->wn_child->wn_u2.wnode == node)
+ newindex = put_node(fd, np->wn_child, newindex, regionmask,
+ prefixtree);
+
+ return newindex;
+}
+
+
+/*
+ * ":mkspell [-ascii] outfile infile ..."
+ * ":mkspell [-ascii] addfile"
+ */
+ void
+ex_mkspell(exarg_T *eap)
+{
+ int fcount;
+ char_u **fnames;
+ char_u *arg = eap->arg;
+ int ascii = FALSE;
+
+ if (STRNCMP(arg, "-ascii", 6) == 0)
+ {
+ ascii = TRUE;
+ arg = skipwhite(arg + 6);
+ }
+
+ /* Expand all the remaining arguments (e.g., $VIMRUNTIME). */
+ if (get_arglist_exp(arg, &fcount, &fnames, FALSE) == OK)
+ {
+ mkspell(fcount, fnames, ascii, eap->forceit, FALSE);
+ FreeWild(fcount, fnames);
+ }
+}
+
+/*
+ * Create the .sug file.
+ * Uses the soundfold info in "spin".
+ * Writes the file with the name "wfname", with ".spl" changed to ".sug".
+ */
+ static void
+spell_make_sugfile(spellinfo_T *spin, char_u *wfname)
+{
+ char_u *fname = NULL;
+ int len;
+ slang_T *slang;
+ int free_slang = FALSE;
+
+ /*
+ * Read back the .spl file that was written. This fills the required
+ * info for soundfolding. This also uses less memory than the
+ * pointer-linked version of the trie. And it avoids having two versions
+ * of the code for the soundfolding stuff.
+ * It might have been done already by spell_reload_one().
+ */
+ for (slang = first_lang; slang != NULL; slang = slang->sl_next)
+ if (fullpathcmp(wfname, slang->sl_fname, FALSE) == FPC_SAME)
+ break;
+ if (slang == NULL)
+ {
+ spell_message(spin, (char_u *)_("Reading back spell file..."));
+ slang = spell_load_file(wfname, NULL, NULL, FALSE);
+ if (slang == NULL)
+ return;
+ free_slang = TRUE;
+ }
+
+ /*
+ * Clear the info in "spin" that is used.
+ */
+ spin->si_blocks = NULL;
+ spin->si_blocks_cnt = 0;
+ spin->si_compress_cnt = 0; /* will stay at 0 all the time*/
+ spin->si_free_count = 0;
+ spin->si_first_free = NULL;
+ spin->si_foldwcount = 0;
+
+ /*
+ * Go through the trie of good words, soundfold each word and add it to
+ * the soundfold trie.
+ */
+ spell_message(spin, (char_u *)_("Performing soundfolding..."));
+ if (sug_filltree(spin, slang) == FAIL)
+ goto theend;
+
+ /*
+ * Create the table which links each soundfold word with a list of the
+ * good words it may come from. Creates buffer "spin->si_spellbuf".
+ * This also removes the wordnr from the NUL byte entries to make
+ * compression possible.
+ */
+ if (sug_maketable(spin) == FAIL)
+ goto theend;
+
+ smsg(_("Number of words after soundfolding: %ld"),
+ (long)spin->si_spellbuf->b_ml.ml_line_count);
+
+ /*
+ * Compress the soundfold trie.
+ */
+ spell_message(spin, (char_u *)_(msg_compressing));
+ wordtree_compress(spin, spin->si_foldroot);
+
+ /*
+ * Write the .sug file.
+ * Make the file name by changing ".spl" to ".sug".
+ */
+ fname = alloc(MAXPATHL);
+ if (fname == NULL)
+ goto theend;
+ vim_strncpy(fname, wfname, MAXPATHL - 1);
+ len = (int)STRLEN(fname);
+ fname[len - 2] = 'u';
+ fname[len - 1] = 'g';
+ sug_write(spin, fname);
+
+theend:
+ vim_free(fname);
+ if (free_slang)
+ slang_free(slang);
+ free_blocks(spin->si_blocks);
+ close_spellbuf(spin->si_spellbuf);
+}
+
+/*
+ * Build the soundfold trie for language "slang".
+ */
+ static int
+sug_filltree(spellinfo_T *spin, slang_T *slang)
+{
+ char_u *byts;
+ idx_T *idxs;
+ int depth;
+ idx_T arridx[MAXWLEN];
+ int curi[MAXWLEN];
+ char_u tword[MAXWLEN];
+ char_u tsalword[MAXWLEN];
+ int c;
+ idx_T n;
+ unsigned words_done = 0;
+ int wordcount[MAXWLEN];
+
+ /* We use si_foldroot for the soundfolded trie. */
+ spin->si_foldroot = wordtree_alloc(spin);
+ if (spin->si_foldroot == NULL)
+ return FAIL;
+
+ /* let tree_add_word() know we're adding to the soundfolded tree */
+ spin->si_sugtree = TRUE;
+
+ /*
+ * Go through the whole case-folded tree, soundfold each word and put it
+ * in the trie.
+ */
+ byts = slang->sl_fbyts;
+ idxs = slang->sl_fidxs;
+
+ arridx[0] = 0;
+ curi[0] = 1;
+ wordcount[0] = 0;
+
+ depth = 0;
+ while (depth >= 0 && !got_int)
+ {
+ if (curi[depth] > byts[arridx[depth]])
+ {
+ /* Done all bytes at this node, go up one level. */
+ idxs[arridx[depth]] = wordcount[depth];
+ if (depth > 0)
+ wordcount[depth - 1] += wordcount[depth];
+
+ --depth;
+ line_breakcheck();
+ }
+ else
+ {
+
+ /* Do one more byte at this node. */
+ n = arridx[depth] + curi[depth];
+ ++curi[depth];
+
+ c = byts[n];
+ if (c == 0)
+ {
+ /* Sound-fold the word. */
+ tword[depth] = NUL;
+ spell_soundfold(slang, tword, TRUE, tsalword);
+
+ /* We use the "flags" field for the MSB of the wordnr,
+ * "region" for the LSB of the wordnr. */
+ if (tree_add_word(spin, tsalword, spin->si_foldroot,
+ words_done >> 16, words_done & 0xffff,
+ 0) == FAIL)
+ return FAIL;
+
+ ++words_done;
+ ++wordcount[depth];
+
+ /* Reset the block count each time to avoid compression
+ * kicking in. */
+ spin->si_blocks_cnt = 0;
+
+ /* Skip over any other NUL bytes (same word with different
+ * flags). */
+ while (byts[n + 1] == 0)
+ {
+ ++n;
+ ++curi[depth];
+ }
+ }
+ else
+ {
+ /* Normal char, go one level deeper. */
+ tword[depth++] = c;
+ arridx[depth] = idxs[n];
+ curi[depth] = 1;
+ wordcount[depth] = 0;
+ }
+ }
+ }
+
+ smsg(_("Total number of words: %d"), words_done);
+
+ return OK;
+}
+
+/*
+ * Make the table that links each word in the soundfold trie to the words it
+ * can be produced from.
+ * This is not unlike lines in a file, thus use a memfile to be able to access
+ * the table efficiently.
+ * Returns FAIL when out of memory.
+ */
+ static int
+sug_maketable(spellinfo_T *spin)
+{
+ garray_T ga;
+ int res = OK;
+
+ /* Allocate a buffer, open a memline for it and create the swap file
+ * (uses a temp file, not a .swp file). */
+ spin->si_spellbuf = open_spellbuf();
+ if (spin->si_spellbuf == NULL)
+ return FAIL;
+
+ /* Use a buffer to store the line info, avoids allocating many small
+ * pieces of memory. */
+ ga_init2(&ga, 1, 100);
+
+ /* recursively go through the tree */
+ if (sug_filltable(spin, spin->si_foldroot->wn_sibling, 0, &ga) == -1)
+ res = FAIL;
+
+ ga_clear(&ga);
+ return res;
+}
+
+/*
+ * Fill the table for one node and its children.
+ * Returns the wordnr at the start of the node.
+ * Returns -1 when out of memory.
+ */
+ static int
+sug_filltable(
+ spellinfo_T *spin,
+ wordnode_T *node,
+ int startwordnr,
+ garray_T *gap) /* place to store line of numbers */
+{
+ wordnode_T *p, *np;
+ int wordnr = startwordnr;
+ int nr;
+ int prev_nr;
+
+ for (p = node; p != NULL; p = p->wn_sibling)
+ {
+ if (p->wn_byte == NUL)
+ {
+ gap->ga_len = 0;
+ prev_nr = 0;
+ for (np = p; np != NULL && np->wn_byte == NUL; np = np->wn_sibling)
+ {
+ if (ga_grow(gap, 10) == FAIL)
+ return -1;
+
+ nr = (np->wn_flags << 16) + (np->wn_region & 0xffff);
+ /* Compute the offset from the previous nr and store the
+ * offset in a way that it takes a minimum number of bytes.
+ * It's a bit like utf-8, but without the need to mark
+ * following bytes. */
+ nr -= prev_nr;
+ prev_nr += nr;
+ gap->ga_len += offset2bytes(nr,
+ (char_u *)gap->ga_data + gap->ga_len);
+ }
+
+ /* add the NUL byte */
+ ((char_u *)gap->ga_data)[gap->ga_len++] = NUL;
+
+ if (ml_append_buf(spin->si_spellbuf, (linenr_T)wordnr,
+ gap->ga_data, gap->ga_len, TRUE) == FAIL)
+ return -1;
+ ++wordnr;
+
+ /* Remove extra NUL entries, we no longer need them. We don't
+ * bother freeing the nodes, the won't be reused anyway. */
+ while (p->wn_sibling != NULL && p->wn_sibling->wn_byte == NUL)
+ p->wn_sibling = p->wn_sibling->wn_sibling;
+
+ /* Clear the flags on the remaining NUL node, so that compression
+ * works a lot better. */
+ p->wn_flags = 0;
+ p->wn_region = 0;
+ }
+ else
+ {
+ wordnr = sug_filltable(spin, p->wn_child, wordnr, gap);
+ if (wordnr == -1)
+ return -1;
+ }
+ }
+ return wordnr;
+}
+
+/*
+ * Convert an offset into a minimal number of bytes.
+ * Similar to utf_char2byters, but use 8 bits in followup bytes and avoid NUL
+ * bytes.
+ */
+ static int
+offset2bytes(int nr, char_u *buf)
+{
+ int rem;
+ int b1, b2, b3, b4;
+
+ /* Split the number in parts of base 255. We need to avoid NUL bytes. */
+ b1 = nr % 255 + 1;
+ rem = nr / 255;
+ b2 = rem % 255 + 1;
+ rem = rem / 255;
+ b3 = rem % 255 + 1;
+ b4 = rem / 255 + 1;
+
+ if (b4 > 1 || b3 > 0x1f) /* 4 bytes */
+ {
+ buf[0] = 0xe0 + b4;
+ buf[1] = b3;
+ buf[2] = b2;
+ buf[3] = b1;
+ return 4;
+ }
+ if (b3 > 1 || b2 > 0x3f ) /* 3 bytes */
+ {
+ buf[0] = 0xc0 + b3;
+ buf[1] = b2;
+ buf[2] = b1;
+ return 3;
+ }
+ if (b2 > 1 || b1 > 0x7f ) /* 2 bytes */
+ {
+ buf[0] = 0x80 + b2;
+ buf[1] = b1;
+ return 2;
+ }
+ /* 1 byte */
+ buf[0] = b1;
+ return 1;
+}
+
+/*
+ * Write the .sug file in "fname".
+ */
+ static void
+sug_write(spellinfo_T *spin, char_u *fname)
+{
+ FILE *fd;
+ wordnode_T *tree;
+ int nodecount;
+ int wcount;
+ char_u *line;
+ linenr_T lnum;
+ int len;
+
+ /* Create the file. Note that an existing file is silently overwritten! */
+ fd = mch_fopen((char *)fname, "w");
+ if (fd == NULL)
+ {
+ semsg(_(e_notopen), fname);
+ return;
+ }
+
+ vim_snprintf((char *)IObuff, IOSIZE,
+ _("Writing suggestion file %s..."), fname);
+ spell_message(spin, IObuff);
+
+ /*
+ * <SUGHEADER>: <fileID> <versionnr> <timestamp>
+ */
+ if (fwrite(VIMSUGMAGIC, VIMSUGMAGICL, (size_t)1, fd) != 1) /* <fileID> */
+ {
+ emsg(_(e_write));
+ goto theend;
+ }
+ putc(VIMSUGVERSION, fd); /* <versionnr> */
+
+ /* Write si_sugtime to the file. */
+ put_time(fd, spin->si_sugtime); /* <timestamp> */
+
+ /*
+ * <SUGWORDTREE>
+ */
+ spin->si_memtot = 0;
+ tree = spin->si_foldroot->wn_sibling;
+
+ /* Clear the index and wnode fields in the tree. */
+ clear_node(tree);
+
+ /* Count the number of nodes. Needed to be able to allocate the
+ * memory when reading the nodes. Also fills in index for shared
+ * nodes. */
+ nodecount = put_node(NULL, tree, 0, 0, FALSE);
+
+ /* number of nodes in 4 bytes */
+ put_bytes(fd, (long_u)nodecount, 4); /* <nodecount> */
+ spin->si_memtot += nodecount + nodecount * sizeof(int);
+
+ /* Write the nodes. */
+ (void)put_node(fd, tree, 0, 0, FALSE);
+
+ /*
+ * <SUGTABLE>: <sugwcount> <sugline> ...
+ */
+ wcount = spin->si_spellbuf->b_ml.ml_line_count;
+ put_bytes(fd, (long_u)wcount, 4); /* <sugwcount> */
+
+ for (lnum = 1; lnum <= (linenr_T)wcount; ++lnum)
+ {
+ /* <sugline>: <sugnr> ... NUL */
+ line = ml_get_buf(spin->si_spellbuf, lnum, FALSE);
+ len = (int)STRLEN(line) + 1;
+ if (fwrite(line, (size_t)len, (size_t)1, fd) == 0)
+ {
+ emsg(_(e_write));
+ goto theend;
+ }
+ spin->si_memtot += len;
+ }
+
+ /* Write another byte to check for errors. */
+ if (putc(0, fd) == EOF)
+ emsg(_(e_write));
+
+ vim_snprintf((char *)IObuff, IOSIZE,
+ _("Estimated runtime memory use: %d bytes"), spin->si_memtot);
+ spell_message(spin, IObuff);
+
+theend:
+ /* close the file */
+ fclose(fd);
+}
+
+
+/*
+ * Create a Vim spell file from one or more word lists.
+ * "fnames[0]" is the output file name.
+ * "fnames[fcount - 1]" is the last input file name.
+ * Exception: when "fnames[0]" ends in ".add" it's used as the input file name
+ * and ".spl" is appended to make the output file name.
+ */
+ void
+mkspell(
+ int fcount,
+ char_u **fnames,
+ int ascii, /* -ascii argument given */
+ int over_write, /* overwrite existing output file */
+ int added_word) /* invoked through "zg" */
+{
+ char_u *fname = NULL;
+ char_u *wfname;
+ char_u **innames;
+ int incount;
+ afffile_T *(afile[MAXREGIONS]);
+ int i;
+ int len;
+ stat_T st;
+ int error = FALSE;
+ spellinfo_T spin;
+
+ vim_memset(&spin, 0, sizeof(spin));
+ spin.si_verbose = !added_word;
+ spin.si_ascii = ascii;
+ spin.si_followup = TRUE;
+ spin.si_rem_accents = TRUE;
+ ga_init2(&spin.si_rep, (int)sizeof(fromto_T), 20);
+ ga_init2(&spin.si_repsal, (int)sizeof(fromto_T), 20);
+ ga_init2(&spin.si_sal, (int)sizeof(fromto_T), 20);
+ ga_init2(&spin.si_map, (int)sizeof(char_u), 100);
+ ga_init2(&spin.si_comppat, (int)sizeof(char_u *), 20);
+ ga_init2(&spin.si_prefcond, (int)sizeof(char_u *), 50);
+ hash_init(&spin.si_commonwords);
+ spin.si_newcompID = 127; /* start compound ID at first maximum */
+
+ /* default: fnames[0] is output file, following are input files */
+ innames = &fnames[1];
+ incount = fcount - 1;
+
+ wfname = alloc(MAXPATHL);
+ if (wfname == NULL)
+ return;
+
+ if (fcount >= 1)
+ {
+ len = (int)STRLEN(fnames[0]);
+ if (fcount == 1 && len > 4 && STRCMP(fnames[0] + len - 4, ".add") == 0)
+ {
+ /* For ":mkspell path/en.latin1.add" output file is
+ * "path/en.latin1.add.spl". */
+ innames = &fnames[0];
+ incount = 1;
+ vim_snprintf((char *)wfname, MAXPATHL, "%s.spl", fnames[0]);
+ }
+ else if (fcount == 1)
+ {
+ /* For ":mkspell path/vim" output file is "path/vim.latin1.spl". */
+ innames = &fnames[0];
+ incount = 1;
+ vim_snprintf((char *)wfname, MAXPATHL, SPL_FNAME_TMPL,
+ fnames[0], spin.si_ascii ? (char_u *)"ascii" : spell_enc());
+ }
+ else if (len > 4 && STRCMP(fnames[0] + len - 4, ".spl") == 0)
+ {
+ /* Name ends in ".spl", use as the file name. */
+ vim_strncpy(wfname, fnames[0], MAXPATHL - 1);
+ }
+ else
+ /* Name should be language, make the file name from it. */
+ vim_snprintf((char *)wfname, MAXPATHL, SPL_FNAME_TMPL,
+ fnames[0], spin.si_ascii ? (char_u *)"ascii" : spell_enc());
+
+ /* Check for .ascii.spl. */
+ if (strstr((char *)gettail(wfname), SPL_FNAME_ASCII) != NULL)
+ spin.si_ascii = TRUE;
+
+ /* Check for .add.spl. */
+ if (strstr((char *)gettail(wfname), SPL_FNAME_ADD) != NULL)
+ spin.si_add = TRUE;
+ }
+
+ if (incount <= 0)
+ emsg(_(e_invarg)); /* need at least output and input names */
+ else if (vim_strchr(gettail(wfname), '_') != NULL)
+ emsg(_("E751: Output file name must not have region name"));
+ else if (incount > MAXREGIONS)
+ semsg(_("E754: Only up to %d regions supported"), MAXREGIONS);
+ else
+ {
+ /* Check for overwriting before doing things that may take a lot of
+ * time. */
+ if (!over_write && mch_stat((char *)wfname, &st) >= 0)
+ {
+ emsg(_(e_exists));
+ goto theend;
+ }
+ if (mch_isdir(wfname))
+ {
+ semsg(_(e_isadir2), wfname);
+ goto theend;
+ }
+
+ fname = alloc(MAXPATHL);
+ if (fname == NULL)
+ goto theend;
+
+ /*
+ * Init the aff and dic pointers.
+ * Get the region names if there are more than 2 arguments.
+ */
+ for (i = 0; i < incount; ++i)
+ {
+ afile[i] = NULL;
+
+ if (incount > 1)
+ {
+ len = (int)STRLEN(innames[i]);
+ if (STRLEN(gettail(innames[i])) < 5
+ || innames[i][len - 3] != '_')
+ {
+ semsg(_("E755: Invalid region in %s"), innames[i]);
+ goto theend;
+ }
+ spin.si_region_name[i * 2] = TOLOWER_ASC(innames[i][len - 2]);
+ spin.si_region_name[i * 2 + 1] =
+ TOLOWER_ASC(innames[i][len - 1]);
+ }
+ }
+ spin.si_region_count = incount;
+
+ spin.si_foldroot = wordtree_alloc(&spin);
+ spin.si_keeproot = wordtree_alloc(&spin);
+ spin.si_prefroot = wordtree_alloc(&spin);
+ if (spin.si_foldroot == NULL
+ || spin.si_keeproot == NULL
+ || spin.si_prefroot == NULL)
+ {
+ free_blocks(spin.si_blocks);
+ goto theend;
+ }
+
+ /* When not producing a .add.spl file clear the character table when
+ * we encounter one in the .aff file. This means we dump the current
+ * one in the .spl file if the .aff file doesn't define one. That's
+ * better than guessing the contents, the table will match a
+ * previously loaded spell file. */
+ if (!spin.si_add)
+ spin.si_clear_chartab = TRUE;
+
+ /*
+ * Read all the .aff and .dic files.
+ * Text is converted to 'encoding'.
+ * Words are stored in the case-folded and keep-case trees.
+ */
+ for (i = 0; i < incount && !error; ++i)
+ {
+ spin.si_conv.vc_type = CONV_NONE;
+ spin.si_region = 1 << i;
+
+ vim_snprintf((char *)fname, MAXPATHL, "%s.aff", innames[i]);
+ if (mch_stat((char *)fname, &st) >= 0)
+ {
+ /* Read the .aff file. Will init "spin->si_conv" based on the
+ * "SET" line. */
+ afile[i] = spell_read_aff(&spin, fname);
+ if (afile[i] == NULL)
+ error = TRUE;
+ else
+ {
+ /* Read the .dic file and store the words in the trees. */
+ vim_snprintf((char *)fname, MAXPATHL, "%s.dic",
+ innames[i]);
+ if (spell_read_dic(&spin, fname, afile[i]) == FAIL)
+ error = TRUE;
+ }
+ }
+ else
+ {
+ /* No .aff file, try reading the file as a word list. Store
+ * the words in the trees. */
+ if (spell_read_wordfile(&spin, innames[i]) == FAIL)
+ error = TRUE;
+ }
+
+ /* Free any conversion stuff. */
+ convert_setup(&spin.si_conv, NULL, NULL);
+ }
+
+ if (spin.si_compflags != NULL && spin.si_nobreak)
+ msg(_("Warning: both compounding and NOBREAK specified"));
+
+ if (!error && !got_int)
+ {
+ /*
+ * Combine tails in the tree.
+ */
+ spell_message(&spin, (char_u *)_(msg_compressing));
+ wordtree_compress(&spin, spin.si_foldroot);
+ wordtree_compress(&spin, spin.si_keeproot);
+ wordtree_compress(&spin, spin.si_prefroot);
+ }
+
+ if (!error && !got_int)
+ {
+ /*
+ * Write the info in the spell file.
+ */
+ vim_snprintf((char *)IObuff, IOSIZE,
+ _("Writing spell file %s..."), wfname);
+ spell_message(&spin, IObuff);
+
+ error = write_vim_spell(&spin, wfname) == FAIL;
+
+ spell_message(&spin, (char_u *)_("Done!"));
+ vim_snprintf((char *)IObuff, IOSIZE,
+ _("Estimated runtime memory use: %d bytes"), spin.si_memtot);
+ spell_message(&spin, IObuff);
+
+ /*
+ * If the file is loaded need to reload it.
+ */
+ if (!error)
+ spell_reload_one(wfname, added_word);
+ }
+
+ /* Free the allocated memory. */
+ ga_clear(&spin.si_rep);
+ ga_clear(&spin.si_repsal);
+ ga_clear(&spin.si_sal);
+ ga_clear(&spin.si_map);
+ ga_clear(&spin.si_comppat);
+ ga_clear(&spin.si_prefcond);
+ hash_clear_all(&spin.si_commonwords, 0);
+
+ /* Free the .aff file structures. */
+ for (i = 0; i < incount; ++i)
+ if (afile[i] != NULL)
+ spell_free_aff(afile[i]);
+
+ /* Free all the bits and pieces at once. */
+ free_blocks(spin.si_blocks);
+
+ /*
+ * If there is soundfolding info and no NOSUGFILE item create the
+ * .sug file with the soundfolded word trie.
+ */
+ if (spin.si_sugtime != 0 && !error && !got_int)
+ spell_make_sugfile(&spin, wfname);
+
+ }
+
+theend:
+ vim_free(fname);
+ vim_free(wfname);
+}
+
+/*
+ * Display a message for spell file processing when 'verbose' is set or using
+ * ":mkspell". "str" can be IObuff.
+ */
+ static void
+spell_message(spellinfo_T *spin, char_u *str)
+{
+ if (spin->si_verbose || p_verbose > 2)
+ {
+ if (!spin->si_verbose)
+ verbose_enter();
+ msg((char *)str);
+ out_flush();
+ if (!spin->si_verbose)
+ verbose_leave();
+ }
+}
+
+/*
+ * ":[count]spellgood {word}"
+ * ":[count]spellwrong {word}"
+ * ":[count]spellundo {word}"
+ */
+ void
+ex_spell(exarg_T *eap)
+{
+ spell_add_word(eap->arg, (int)STRLEN(eap->arg), eap->cmdidx == CMD_spellwrong,
+ eap->forceit ? 0 : (int)eap->line2,
+ eap->cmdidx == CMD_spellundo);
+}
+
+/*
+ * Add "word[len]" to 'spellfile' as a good or bad word.
+ */
+ void
+spell_add_word(
+ char_u *word,
+ int len,
+ int bad,
+ int idx, /* "zG" and "zW": zero, otherwise index in
+ 'spellfile' */
+ int undo) /* TRUE for "zug", "zuG", "zuw" and "zuW" */
+{
+ FILE *fd = NULL;
+ buf_T *buf = NULL;
+ int new_spf = FALSE;
+ char_u *fname;
+ char_u *fnamebuf = NULL;
+ char_u line[MAXWLEN * 2];
+ long fpos, fpos_next = 0;
+ int i;
+ char_u *spf;
+
+ if (idx == 0) /* use internal wordlist */
+ {
+ if (int_wordlist == NULL)
+ {
+ int_wordlist = vim_tempname('s', FALSE);
+ if (int_wordlist == NULL)
+ return;
+ }
+ fname = int_wordlist;
+ }
+ else
+ {
+ /* If 'spellfile' isn't set figure out a good default value. */
+ if (*curwin->w_s->b_p_spf == NUL)
+ {
+ init_spellfile();
+ new_spf = TRUE;
+ }
+
+ if (*curwin->w_s->b_p_spf == NUL)
+ {
+ semsg(_(e_notset), "spellfile");
+ return;
+ }
+ fnamebuf = alloc(MAXPATHL);
+ if (fnamebuf == NULL)
+ return;
+
+ for (spf = curwin->w_s->b_p_spf, i = 1; *spf != NUL; ++i)
+ {
+ copy_option_part(&spf, fnamebuf, MAXPATHL, ",");
+ if (i == idx)
+ break;
+ if (*spf == NUL)
+ {
+ semsg(_("E765: 'spellfile' does not have %d entries"), idx);
+ vim_free(fnamebuf);
+ return;
+ }
+ }
+
+ /* Check that the user isn't editing the .add file somewhere. */
+ buf = buflist_findname_exp(fnamebuf);
+ if (buf != NULL && buf->b_ml.ml_mfp == NULL)
+ buf = NULL;
+ if (buf != NULL && bufIsChanged(buf))
+ {
+ emsg(_(e_bufloaded));
+ vim_free(fnamebuf);
+ return;
+ }
+
+ fname = fnamebuf;
+ }
+
+ if (bad || undo)
+ {
+ /* When the word appears as good word we need to remove that one,
+ * since its flags sort before the one with WF_BANNED. */
+ fd = mch_fopen((char *)fname, "r");
+ if (fd != NULL)
+ {
+ while (!vim_fgets(line, MAXWLEN * 2, fd))
+ {
+ fpos = fpos_next;
+ fpos_next = ftell(fd);
+ if (STRNCMP(word, line, len) == 0
+ && (line[len] == '/' || line[len] < ' '))
+ {
+ /* Found duplicate word. Remove it by writing a '#' at
+ * the start of the line. Mixing reading and writing
+ * doesn't work for all systems, close the file first. */
+ fclose(fd);
+ fd = mch_fopen((char *)fname, "r+");
+ if (fd == NULL)
+ break;
+ if (fseek(fd, fpos, SEEK_SET) == 0)
+ {
+ fputc('#', fd);
+ if (undo)
+ {
+ home_replace(NULL, fname, NameBuff, MAXPATHL, TRUE);
+ smsg(_("Word '%.*s' removed from %s"),
+ len, word, NameBuff);
+ }
+ }
+ fseek(fd, fpos_next, SEEK_SET);
+ }
+ }
+ if (fd != NULL)
+ fclose(fd);
+ }
+ }
+
+ if (!undo)
+ {
+ fd = mch_fopen((char *)fname, "a");
+ if (fd == NULL && new_spf)
+ {
+ char_u *p;
+
+ /* We just initialized the 'spellfile' option and can't open the
+ * file. We may need to create the "spell" directory first. We
+ * already checked the runtime directory is writable in
+ * init_spellfile(). */
+ if (!dir_of_file_exists(fname) && (p = gettail_sep(fname)) != fname)
+ {
+ int c = *p;
+
+ /* The directory doesn't exist. Try creating it and opening
+ * the file again. */
+ *p = NUL;
+ vim_mkdir(fname, 0755);
+ *p = c;
+ fd = mch_fopen((char *)fname, "a");
+ }
+ }
+
+ if (fd == NULL)
+ semsg(_(e_notopen), fname);
+ else
+ {
+ if (bad)
+ fprintf(fd, "%.*s/!\n", len, word);
+ else
+ fprintf(fd, "%.*s\n", len, word);
+ fclose(fd);
+
+ home_replace(NULL, fname, NameBuff, MAXPATHL, TRUE);
+ smsg(_("Word '%.*s' added to %s"), len, word, NameBuff);
+ }
+ }
+
+ if (fd != NULL)
+ {
+ /* Update the .add.spl file. */
+ mkspell(1, &fname, FALSE, TRUE, TRUE);
+
+ /* If the .add file is edited somewhere, reload it. */
+ if (buf != NULL)
+ buf_reload(buf, buf->b_orig_mode);
+
+ redraw_all_later(SOME_VALID);
+ }
+ vim_free(fnamebuf);
+}
+
+/*
+ * Initialize 'spellfile' for the current buffer.
+ */
+ static void
+init_spellfile(void)
+{
+ char_u *buf;
+ int l;
+ char_u *fname;
+ char_u *rtp;
+ char_u *lend;
+ int aspath = FALSE;
+ char_u *lstart = curbuf->b_s.b_p_spl;
+
+ if (*curwin->w_s->b_p_spl != NUL && curwin->w_s->b_langp.ga_len > 0)
+ {
+ buf = alloc(MAXPATHL);
+ if (buf == NULL)
+ return;
+
+ /* Find the end of the language name. Exclude the region. If there
+ * is a path separator remember the start of the tail. */
+ for (lend = curwin->w_s->b_p_spl; *lend != NUL
+ && vim_strchr((char_u *)",._", *lend) == NULL; ++lend)
+ if (vim_ispathsep(*lend))
+ {
+ aspath = TRUE;
+ lstart = lend + 1;
+ }
+
+ /* Loop over all entries in 'runtimepath'. Use the first one where we
+ * are allowed to write. */
+ rtp = p_rtp;
+ while (*rtp != NUL)
+ {
+ if (aspath)
+ /* Use directory of an entry with path, e.g., for
+ * "/dir/lg.utf-8.spl" use "/dir". */
+ vim_strncpy(buf, curbuf->b_s.b_p_spl,
+ lstart - curbuf->b_s.b_p_spl - 1);
+ else
+ /* Copy the path from 'runtimepath' to buf[]. */
+ copy_option_part(&rtp, buf, MAXPATHL, ",");
+ if (filewritable(buf) == 2)
+ {
+ /* Use the first language name from 'spelllang' and the
+ * encoding used in the first loaded .spl file. */
+ if (aspath)
+ vim_strncpy(buf, curbuf->b_s.b_p_spl,
+ lend - curbuf->b_s.b_p_spl);
+ else
+ {
+ /* Create the "spell" directory if it doesn't exist yet. */
+ l = (int)STRLEN(buf);
+ vim_snprintf((char *)buf + l, MAXPATHL - l, "/spell");
+ if (filewritable(buf) != 2)
+ vim_mkdir(buf, 0755);
+
+ l = (int)STRLEN(buf);
+ vim_snprintf((char *)buf + l, MAXPATHL - l,
+ "/%.*s", (int)(lend - lstart), lstart);
+ }
+ l = (int)STRLEN(buf);
+ fname = LANGP_ENTRY(curwin->w_s->b_langp, 0)
+ ->lp_slang->sl_fname;
+ vim_snprintf((char *)buf + l, MAXPATHL - l, ".%s.add",
+ fname != NULL
+ && strstr((char *)gettail(fname), ".ascii.") != NULL
+ ? (char_u *)"ascii" : spell_enc());
+ set_option_value((char_u *)"spellfile", 0L, buf, OPT_LOCAL);
+ break;
+ }
+ aspath = FALSE;
+ }
+
+ vim_free(buf);
+ }
+}
+
+
+
+/*
+ * Set the spell character tables from strings in the affix file.
+ */
+ static int
+set_spell_chartab(char_u *fol, char_u *low, char_u *upp)
+{
+ /* We build the new tables here first, so that we can compare with the
+ * previous one. */
+ spelltab_T new_st;
+ char_u *pf = fol, *pl = low, *pu = upp;
+ int f, l, u;
+
+ clear_spell_chartab(&new_st);
+
+ while (*pf != NUL)
+ {
+ if (*pl == NUL || *pu == NUL)
+ {
+ emsg(_(e_affform));
+ return FAIL;
+ }
+ f = mb_ptr2char_adv(&pf);
+ l = mb_ptr2char_adv(&pl);
+ u = mb_ptr2char_adv(&pu);
+
+ /* Every character that appears is a word character. */
+ if (f < 256)
+ new_st.st_isw[f] = TRUE;
+ if (l < 256)
+ new_st.st_isw[l] = TRUE;
+ if (u < 256)
+ new_st.st_isw[u] = TRUE;
+
+ /* if "LOW" and "FOL" are not the same the "LOW" char needs
+ * case-folding */
+ if (l < 256 && l != f)
+ {
+ if (f >= 256)
+ {
+ emsg(_(e_affrange));
+ return FAIL;
+ }
+ new_st.st_fold[l] = f;
+ }
+
+ /* if "UPP" and "FOL" are not the same the "UPP" char needs
+ * case-folding, it's upper case and the "UPP" is the upper case of
+ * "FOL" . */
+ if (u < 256 && u != f)
+ {
+ if (f >= 256)
+ {
+ emsg(_(e_affrange));
+ return FAIL;
+ }
+ new_st.st_fold[u] = f;
+ new_st.st_isu[u] = TRUE;
+ new_st.st_upper[f] = u;
+ }
+ }
+
+ if (*pl != NUL || *pu != NUL)
+ {
+ emsg(_(e_affform));
+ return FAIL;
+ }
+
+ return set_spell_finish(&new_st);
+}
+
+/*
+ * Set the spell character tables from strings in the .spl file.
+ */
+ static void
+set_spell_charflags(
+ char_u *flags,
+ int cnt, /* length of "flags" */
+ char_u *fol)
+{
+ /* We build the new tables here first, so that we can compare with the
+ * previous one. */
+ spelltab_T new_st;
+ int i;
+ char_u *p = fol;
+ int c;
+
+ clear_spell_chartab(&new_st);
+
+ for (i = 0; i < 128; ++i)
+ {
+ if (i < cnt)
+ {
+ new_st.st_isw[i + 128] = (flags[i] & CF_WORD) != 0;
+ new_st.st_isu[i + 128] = (flags[i] & CF_UPPER) != 0;
+ }
+
+ if (*p != NUL)
+ {
+ c = mb_ptr2char_adv(&p);
+ new_st.st_fold[i + 128] = c;
+ if (i + 128 != c && new_st.st_isu[i + 128] && c < 256)
+ new_st.st_upper[c] = i + 128;
+ }
+ }
+
+ (void)set_spell_finish(&new_st);
+}
+
+ static int
+set_spell_finish(spelltab_T *new_st)
+{
+ int i;
+
+ if (did_set_spelltab)
+ {
+ /* check that it's the same table */
+ for (i = 0; i < 256; ++i)
+ {
+ if (spelltab.st_isw[i] != new_st->st_isw[i]
+ || spelltab.st_isu[i] != new_st->st_isu[i]
+ || spelltab.st_fold[i] != new_st->st_fold[i]
+ || spelltab.st_upper[i] != new_st->st_upper[i])
+ {
+ emsg(_("E763: Word characters differ between spell files"));
+ return FAIL;
+ }
+ }
+ }
+ else
+ {
+ /* copy the new spelltab into the one being used */
+ spelltab = *new_st;
+ did_set_spelltab = TRUE;
+ }
+
+ return OK;
+}
+
+/*
+ * Write the table with prefix conditions to the .spl file.
+ * When "fd" is NULL only count the length of what is written.
+ */
+ static int
+write_spell_prefcond(FILE *fd, garray_T *gap)
+{
+ int i;
+ char_u *p;
+ int len;
+ int totlen;
+ size_t x = 1; /* collect return value of fwrite() */
+
+ if (fd != NULL)
+ put_bytes(fd, (long_u)gap->ga_len, 2); /* <prefcondcnt> */
+
+ totlen = 2 + gap->ga_len; /* length of <prefcondcnt> and <condlen> bytes */
+
+ for (i = 0; i < gap->ga_len; ++i)
+ {
+ /* <prefcond> : <condlen> <condstr> */
+ p = ((char_u **)gap->ga_data)[i];
+ if (p != NULL)
+ {
+ len = (int)STRLEN(p);
+ if (fd != NULL)
+ {
+ fputc(len, fd);
+ x &= fwrite(p, (size_t)len, (size_t)1, fd);
+ }
+ totlen += len;
+ }
+ else if (fd != NULL)
+ fputc(0, fd);
+ }
+
+ return totlen;
+}
+
+
+/*
+ * Use map string "map" for languages "lp".
+ */
+ static void
+set_map_str(slang_T *lp, char_u *map)
+{
+ char_u *p;
+ int headc = 0;
+ int c;
+ int i;
+
+ if (*map == NUL)
+ {
+ lp->sl_has_map = FALSE;
+ return;
+ }
+ lp->sl_has_map = TRUE;
+
+ /* Init the array and hash tables empty. */
+ for (i = 0; i < 256; ++i)
+ lp->sl_map_array[i] = 0;
+ hash_init(&lp->sl_map_hash);
+
+ /*
+ * The similar characters are stored separated with slashes:
+ * "aaa/bbb/ccc/". Fill sl_map_array[c] with the character before c and
+ * before the same slash. For characters above 255 sl_map_hash is used.
+ */
+ for (p = map; *p != NUL; )
+ {
+ c = mb_cptr2char_adv(&p);
+ if (c == '/')
+ headc = 0;
+ else
+ {
+ if (headc == 0)
+ headc = c;
+
+ /* Characters above 255 don't fit in sl_map_array[], put them in
+ * the hash table. Each entry is the char, a NUL the headchar and
+ * a NUL. */
+ if (c >= 256)
+ {
+ int cl = mb_char2len(c);
+ int headcl = mb_char2len(headc);
+ char_u *b;
+ hash_T hash;
+ hashitem_T *hi;
+
+ b = alloc((unsigned)(cl + headcl + 2));
+ if (b == NULL)
+ return;
+ mb_char2bytes(c, b);
+ b[cl] = NUL;
+ mb_char2bytes(headc, b + cl + 1);
+ b[cl + 1 + headcl] = NUL;
+ hash = hash_hash(b);
+ hi = hash_lookup(&lp->sl_map_hash, b, hash);
+ if (HASHITEM_EMPTY(hi))
+ hash_add_item(&lp->sl_map_hash, hi, b, hash);
+ else
+ {
+ /* This should have been checked when generating the .spl
+ * file. */
+ emsg(_("E783: duplicate char in MAP entry"));
+ vim_free(b);
+ }
+ }
+ else
+ lp->sl_map_array[c] = headc;
+ }
+ }
+}
+
+
+#endif /* FEAT_SPELL */
diff --git a/src/structs.h b/src/structs.h
new file mode 100644
index 0000000..5d0541b
--- /dev/null
+++ b/src/structs.h
@@ -0,0 +1,3540 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * Do ":help uganda" in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ */
+
+/*
+ * This file contains various definitions of structures that are used by Vim
+ */
+
+/*
+ * There is something wrong in the SAS compiler that makes typedefs not
+ * valid in include files. Has been fixed in version 6.58.
+ */
+#if defined(SASC) && SASC < 658
+typedef long linenr_T;
+typedef int colnr_T;
+typedef unsigned short short_u;
+#endif
+
+/*
+ * Position in file or buffer.
+ */
+typedef struct
+{
+ linenr_T lnum; // line number
+ colnr_T col; // column number
+ colnr_T coladd; // extra virtual column
+} pos_T;
+
+
+/*
+ * Same, but without coladd.
+ */
+typedef struct
+{
+ linenr_T lnum; // line number
+ colnr_T col; // column number
+} lpos_T;
+
+/*
+ * Structure used for growing arrays.
+ * This is used to store information that only grows, is deleted all at
+ * once, and needs to be accessed by index. See ga_clear() and ga_grow().
+ */
+typedef struct growarray
+{
+ int ga_len; /* current number of items used */
+ int ga_maxlen; /* maximum number of items possible */
+ int ga_itemsize; /* sizeof(item) */
+ int ga_growsize; /* number of items to grow each time */
+ void *ga_data; /* pointer to the first item */
+} garray_T;
+
+#define GA_EMPTY {0, 0, 0, 0, NULL}
+
+typedef struct window_S win_T;
+typedef struct wininfo_S wininfo_T;
+typedef struct frame_S frame_T;
+typedef int scid_T; /* script ID */
+typedef struct file_buffer buf_T; /* forward declaration */
+typedef struct terminal_S term_T;
+
+#ifdef FEAT_MENU
+typedef struct VimMenu vimmenu_T;
+#endif
+
+/*
+ * SCript ConteXt (SCTX): identifies a script script line.
+ * When sourcing a script "sc_lnum" is zero, "sourcing_lnum" is the current
+ * line number. When executing a user function "sc_lnum" is the line where the
+ * function was defined, "sourcing_lnum" is the line number inside the
+ * function. When stored with a function, mapping, option, etc. "sc_lnum" is
+ * the line number in the script "sc_sid".
+ */
+typedef struct {
+ scid_T sc_sid; // script ID
+ int sc_seq; // sourcing sequence number
+ linenr_T sc_lnum; // line number
+} sctx_T;
+
+/*
+ * Reference to a buffer that stores the value of buf_free_count.
+ * bufref_valid() only needs to check "buf" when the count differs.
+ */
+typedef struct {
+ buf_T *br_buf;
+ int br_fnum;
+ int br_buf_free_count;
+} bufref_T;
+
+/*
+ * This is here because regexp.h needs pos_T and below regprog_T is used.
+ */
+#include "regexp.h"
+
+/*
+ * This is here because gui.h needs the pos_T and win_T, and win_T needs gui.h
+ * for scrollbar_T.
+ */
+#ifdef FEAT_GUI
+# include "gui.h"
+#else
+# ifdef FEAT_XCLIPBOARD
+# include <X11/Intrinsic.h>
+# endif
+# define guicolor_T long
+# define INVALCOLOR ((guicolor_T)0x1ffffff)
+ /* only used for cterm.bg_rgb and cterm.fg_rgb: use cterm color */
+# define CTERMCOLOR ((guicolor_T)0x1fffffe)
+#endif
+#define COLOR_INVALID(x) ((x) == INVALCOLOR || (x) == CTERMCOLOR)
+
+/*
+ * marks: positions in a file
+ * (a normal mark is a lnum/col pair, the same as a file position)
+ */
+
+/* (Note: for EBCDIC there are more than 26, because there are gaps in the
+ * alphabet coding. To minimize changes to the code, I decided to just
+ * increase the number of possible marks. */
+#define NMARKS ('z' - 'a' + 1) /* max. # of named marks */
+#define JUMPLISTSIZE 100 /* max. # of marks in jump list */
+#define TAGSTACKSIZE 20 /* max. # of tags in tag stack */
+
+typedef struct filemark
+{
+ pos_T mark; /* cursor position */
+ int fnum; /* file number */
+} fmark_T;
+
+/* Xtended file mark: also has a file name */
+typedef struct xfilemark
+{
+ fmark_T fmark;
+ char_u *fname; /* file name, used when fnum == 0 */
+#ifdef FEAT_VIMINFO
+ time_T time_set;
+#endif
+} xfmark_T;
+
+/*
+ * The taggy struct is used to store the information about a :tag command.
+ */
+typedef struct taggy
+{
+ char_u *tagname; /* tag name */
+ fmark_T fmark; /* cursor position BEFORE ":tag" */
+ int cur_match; /* match number */
+ int cur_fnum; /* buffer number used for cur_match */
+} taggy_T;
+
+/*
+ * Structure that contains all options that are local to a window.
+ * Used twice in a window: for the current buffer and for all buffers.
+ * Also used in wininfo_T.
+ */
+typedef struct
+{
+#ifdef FEAT_ARABIC
+ int wo_arab;
+# define w_p_arab w_onebuf_opt.wo_arab /* 'arabic' */
+#endif
+#ifdef FEAT_LINEBREAK
+ int wo_bri;
+# define w_p_bri w_onebuf_opt.wo_bri /* 'breakindent' */
+ char_u *wo_briopt;
+# define w_p_briopt w_onebuf_opt.wo_briopt /* 'breakindentopt' */
+#endif
+#ifdef FEAT_DIFF
+ int wo_diff;
+# define w_p_diff w_onebuf_opt.wo_diff /* 'diff' */
+#endif
+#ifdef FEAT_FOLDING
+ long wo_fdc;
+# define w_p_fdc w_onebuf_opt.wo_fdc /* 'foldcolumn' */
+ int wo_fdc_save;
+# define w_p_fdc_save w_onebuf_opt.wo_fdc_save /* 'foldenable' saved for diff mode */
+ int wo_fen;
+# define w_p_fen w_onebuf_opt.wo_fen /* 'foldenable' */
+ int wo_fen_save;
+# define w_p_fen_save w_onebuf_opt.wo_fen_save /* 'foldenable' saved for diff mode */
+ char_u *wo_fdi;
+# define w_p_fdi w_onebuf_opt.wo_fdi /* 'foldignore' */
+ long wo_fdl;
+# define w_p_fdl w_onebuf_opt.wo_fdl /* 'foldlevel' */
+ int wo_fdl_save;
+# define w_p_fdl_save w_onebuf_opt.wo_fdl_save /* 'foldlevel' state saved for diff mode */
+ char_u *wo_fdm;
+# define w_p_fdm w_onebuf_opt.wo_fdm /* 'foldmethod' */
+ char_u *wo_fdm_save;
+# define w_p_fdm_save w_onebuf_opt.wo_fdm_save /* 'fdm' saved for diff mode */
+ long wo_fml;
+# define w_p_fml w_onebuf_opt.wo_fml /* 'foldminlines' */
+ long wo_fdn;
+# define w_p_fdn w_onebuf_opt.wo_fdn /* 'foldnestmax' */
+# ifdef FEAT_EVAL
+ char_u *wo_fde;
+# define w_p_fde w_onebuf_opt.wo_fde /* 'foldexpr' */
+ char_u *wo_fdt;
+# define w_p_fdt w_onebuf_opt.wo_fdt /* 'foldtext' */
+# endif
+ char_u *wo_fmr;
+# define w_p_fmr w_onebuf_opt.wo_fmr /* 'foldmarker' */
+#endif
+#ifdef FEAT_LINEBREAK
+ int wo_lbr;
+# define w_p_lbr w_onebuf_opt.wo_lbr /* 'linebreak' */
+#endif
+ int wo_list;
+#define w_p_list w_onebuf_opt.wo_list /* 'list' */
+ int wo_nu;
+#define w_p_nu w_onebuf_opt.wo_nu /* 'number' */
+ int wo_rnu;
+#define w_p_rnu w_onebuf_opt.wo_rnu /* 'relativenumber' */
+#ifdef FEAT_LINEBREAK
+ long wo_nuw;
+# define w_p_nuw w_onebuf_opt.wo_nuw /* 'numberwidth' */
+#endif
+ int wo_wfh;
+# define w_p_wfh w_onebuf_opt.wo_wfh /* 'winfixheight' */
+ int wo_wfw;
+# define w_p_wfw w_onebuf_opt.wo_wfw /* 'winfixwidth' */
+#if defined(FEAT_QUICKFIX)
+ int wo_pvw;
+# define w_p_pvw w_onebuf_opt.wo_pvw /* 'previewwindow' */
+#endif
+#ifdef FEAT_RIGHTLEFT
+ int wo_rl;
+# define w_p_rl w_onebuf_opt.wo_rl /* 'rightleft' */
+ char_u *wo_rlc;
+# define w_p_rlc w_onebuf_opt.wo_rlc /* 'rightleftcmd' */
+#endif
+ long wo_scr;
+#define w_p_scr w_onebuf_opt.wo_scr /* 'scroll' */
+#ifdef FEAT_SPELL
+ int wo_spell;
+# define w_p_spell w_onebuf_opt.wo_spell /* 'spell' */
+#endif
+#ifdef FEAT_SYN_HL
+ int wo_cuc;
+# define w_p_cuc w_onebuf_opt.wo_cuc /* 'cursorcolumn' */
+ int wo_cul;
+# define w_p_cul w_onebuf_opt.wo_cul /* 'cursorline' */
+ char_u *wo_cc;
+# define w_p_cc w_onebuf_opt.wo_cc /* 'colorcolumn' */
+#endif
+#ifdef FEAT_STL_OPT
+ char_u *wo_stl;
+#define w_p_stl w_onebuf_opt.wo_stl /* 'statusline' */
+#endif
+ int wo_scb;
+#define w_p_scb w_onebuf_opt.wo_scb /* 'scrollbind' */
+ int wo_diff_saved; /* options were saved for starting diff mode */
+#define w_p_diff_saved w_onebuf_opt.wo_diff_saved
+ int wo_scb_save; /* 'scrollbind' saved for diff mode*/
+#define w_p_scb_save w_onebuf_opt.wo_scb_save
+ int wo_wrap;
+#define w_p_wrap w_onebuf_opt.wo_wrap /* 'wrap' */
+#ifdef FEAT_DIFF
+ int wo_wrap_save; /* 'wrap' state saved for diff mode*/
+# define w_p_wrap_save w_onebuf_opt.wo_wrap_save
+#endif
+#ifdef FEAT_CONCEAL
+ char_u *wo_cocu; /* 'concealcursor' */
+# define w_p_cocu w_onebuf_opt.wo_cocu
+ long wo_cole; /* 'conceallevel' */
+# define w_p_cole w_onebuf_opt.wo_cole
+#endif
+ int wo_crb;
+#define w_p_crb w_onebuf_opt.wo_crb /* 'cursorbind' */
+ int wo_crb_save; /* 'cursorbind' state saved for diff mode*/
+#define w_p_crb_save w_onebuf_opt.wo_crb_save
+#ifdef FEAT_SIGNS
+ char_u *wo_scl;
+# define w_p_scl w_onebuf_opt.wo_scl /* 'signcolumn' */
+#endif
+#ifdef FEAT_TERMINAL
+ char_u *wo_twk;
+# define w_p_twk w_onebuf_opt.wo_twk /* 'termwinkey' */
+ char_u *wo_tws;
+# define w_p_tws w_onebuf_opt.wo_tws /* 'termwinsize' */
+ char_u *wo_tmod;
+# define w_p_tmod w_onebuf_opt.wo_tmod /* 'termmode' */
+#endif
+
+#ifdef FEAT_EVAL
+ sctx_T wo_script_ctx[WV_COUNT]; /* SCTXs for window-local options */
+# define w_p_script_ctx w_onebuf_opt.wo_script_ctx
+#endif
+} winopt_T;
+
+/*
+ * Window info stored with a buffer.
+ *
+ * Two types of info are kept for a buffer which are associated with a
+ * specific window:
+ * 1. Each window can have a different line number associated with a buffer.
+ * 2. The window-local options for a buffer work in a similar way.
+ * The window-info is kept in a list at b_wininfo. It is kept in
+ * most-recently-used order.
+ */
+struct wininfo_S
+{
+ wininfo_T *wi_next; /* next entry or NULL for last entry */
+ wininfo_T *wi_prev; /* previous entry or NULL for first entry */
+ win_T *wi_win; /* pointer to window that did set wi_fpos */
+ pos_T wi_fpos; /* last cursor position in the file */
+ int wi_optset; /* TRUE when wi_opt has useful values */
+ winopt_T wi_opt; /* local window options */
+#ifdef FEAT_FOLDING
+ int wi_fold_manual; /* copy of w_fold_manual */
+ garray_T wi_folds; /* clone of w_folds */
+#endif
+};
+
+/*
+ * Info used to pass info about a fold from the fold-detection code to the
+ * code that displays the foldcolumn.
+ */
+typedef struct foldinfo
+{
+ int fi_level; /* level of the fold; when this is zero the
+ other fields are invalid */
+ int fi_lnum; /* line number where fold starts */
+ int fi_low_level; /* lowest fold level that starts in the same
+ line */
+} foldinfo_T;
+
+/* Structure to store info about the Visual area. */
+typedef struct
+{
+ pos_T vi_start; /* start pos of last VIsual */
+ pos_T vi_end; /* end position of last VIsual */
+ int vi_mode; /* VIsual_mode of last VIsual */
+ colnr_T vi_curswant; /* MAXCOL from w_curswant */
+} visualinfo_T;
+
+/*
+ * structures used for undo
+ */
+
+// One line saved for undo. After the NUL terminated text there might be text
+// properties, thus ul_len can be larger than STRLEN(ul_line) + 1.
+typedef struct {
+ char_u *ul_line; // text of the line
+ long ul_len; // length of the line including NUL, plus text
+ // properties
+} undoline_T;
+
+typedef struct u_entry u_entry_T;
+typedef struct u_header u_header_T;
+struct u_entry
+{
+ u_entry_T *ue_next; /* pointer to next entry in list */
+ linenr_T ue_top; /* number of line above undo block */
+ linenr_T ue_bot; /* number of line below undo block */
+ linenr_T ue_lcount; /* linecount when u_save called */
+ undoline_T *ue_array; /* array of lines in undo block */
+ long ue_size; /* number of lines in ue_array */
+#ifdef U_DEBUG
+ int ue_magic; /* magic number to check allocation */
+#endif
+};
+
+struct u_header
+{
+ /* The following have a pointer and a number. The number is used when
+ * reading the undo file in u_read_undo() */
+ union {
+ u_header_T *ptr; /* pointer to next undo header in list */
+ long seq;
+ } uh_next;
+ union {
+ u_header_T *ptr; /* pointer to previous header in list */
+ long seq;
+ } uh_prev;
+ union {
+ u_header_T *ptr; /* pointer to next header for alt. redo */
+ long seq;
+ } uh_alt_next;
+ union {
+ u_header_T *ptr; /* pointer to previous header for alt. redo */
+ long seq;
+ } uh_alt_prev;
+ long uh_seq; /* sequence number, higher == newer undo */
+ int uh_walk; /* used by undo_time() */
+ u_entry_T *uh_entry; /* pointer to first entry */
+ u_entry_T *uh_getbot_entry; /* pointer to where ue_bot must be set */
+ pos_T uh_cursor; /* cursor position before saving */
+ long uh_cursor_vcol;
+ int uh_flags; /* see below */
+ pos_T uh_namedm[NMARKS]; /* marks before undo/after redo */
+ visualinfo_T uh_visual; /* Visual areas before undo/after redo */
+ time_T uh_time; /* timestamp when the change was made */
+ long uh_save_nr; /* set when the file was saved after the
+ changes in this block */
+#ifdef U_DEBUG
+ int uh_magic; /* magic number to check allocation */
+#endif
+};
+
+/* values for uh_flags */
+#define UH_CHANGED 0x01 /* b_changed flag before undo/after redo */
+#define UH_EMPTYBUF 0x02 /* buffer was empty */
+
+/*
+ * structures used in undo.c
+ */
+#define ALIGN_LONG /* longword alignment and use filler byte */
+#define ALIGN_SIZE (sizeof(long))
+
+#define ALIGN_MASK (ALIGN_SIZE - 1)
+
+typedef struct m_info minfo_T;
+
+/*
+ * structure used to link chunks in one of the free chunk lists.
+ */
+struct m_info
+{
+#ifdef ALIGN_LONG
+ long_u m_size; /* size of the chunk (including m_info) */
+#else
+ short_u m_size; /* size of the chunk (including m_info) */
+#endif
+ minfo_T *m_next; /* pointer to next free chunk in the list */
+};
+
+/*
+ * things used in memfile.c
+ */
+
+typedef struct block_hdr bhdr_T;
+typedef struct memfile memfile_T;
+typedef long blocknr_T;
+
+/*
+ * mf_hashtab_T is a chained hashtable with blocknr_T key and arbitrary
+ * structures as items. This is an intrusive data structure: we require
+ * that items begin with mf_hashitem_T which contains the key and linked
+ * list pointers. List of items in each bucket is doubly-linked.
+ */
+
+typedef struct mf_hashitem_S mf_hashitem_T;
+
+struct mf_hashitem_S
+{
+ mf_hashitem_T *mhi_next;
+ mf_hashitem_T *mhi_prev;
+ blocknr_T mhi_key;
+};
+
+#define MHT_INIT_SIZE 64
+
+typedef struct mf_hashtab_S
+{
+ long_u mht_mask; /* mask used for hash value (nr of items
+ * in array is "mht_mask" + 1) */
+ long_u mht_count; /* nr of items inserted into hashtable */
+ mf_hashitem_T **mht_buckets; /* points to mht_small_buckets or
+ *dynamically allocated array */
+ mf_hashitem_T *mht_small_buckets[MHT_INIT_SIZE]; /* initial buckets */
+ char mht_fixed; /* non-zero value forbids growth */
+} mf_hashtab_T;
+
+/*
+ * for each (previously) used block in the memfile there is one block header.
+ *
+ * The block may be linked in the used list OR in the free list.
+ * The used blocks are also kept in hash lists.
+ *
+ * The used list is a doubly linked list, most recently used block first.
+ * The blocks in the used list have a block of memory allocated.
+ * mf_used_count is the number of pages in the used list.
+ * The hash lists are used to quickly find a block in the used list.
+ * The free list is a single linked list, not sorted.
+ * The blocks in the free list have no block of memory allocated and
+ * the contents of the block in the file (if any) is irrelevant.
+ */
+
+struct block_hdr
+{
+ mf_hashitem_T bh_hashitem; /* header for hash table and key */
+#define bh_bnum bh_hashitem.mhi_key /* block number, part of bh_hashitem */
+
+ bhdr_T *bh_next; /* next block_hdr in free or used list */
+ bhdr_T *bh_prev; /* previous block_hdr in used list */
+ char_u *bh_data; /* pointer to memory (for used block) */
+ int bh_page_count; /* number of pages in this block */
+
+#define BH_DIRTY 1
+#define BH_LOCKED 2
+ char bh_flags; /* BH_DIRTY or BH_LOCKED */
+};
+
+/*
+ * when a block with a negative number is flushed to the file, it gets
+ * a positive number. Because the reference to the block is still the negative
+ * number, we remember the translation to the new positive number in the
+ * double linked trans lists. The structure is the same as the hash lists.
+ */
+typedef struct nr_trans NR_TRANS;
+
+struct nr_trans
+{
+ mf_hashitem_T nt_hashitem; /* header for hash table and key */
+#define nt_old_bnum nt_hashitem.mhi_key /* old, negative, number */
+
+ blocknr_T nt_new_bnum; /* new, positive, number */
+};
+
+
+typedef struct buffblock buffblock_T;
+typedef struct buffheader buffheader_T;
+
+/*
+ * structure used to store one block of the stuff/redo/recording buffers
+ */
+struct buffblock
+{
+ buffblock_T *b_next; /* pointer to next buffblock */
+ char_u b_str[1]; /* contents (actually longer) */
+};
+
+/*
+ * header used for the stuff buffer and the redo buffer
+ */
+struct buffheader
+{
+ buffblock_T bh_first; /* first (dummy) block of list */
+ buffblock_T *bh_curr; /* buffblock for appending */
+ int bh_index; /* index for reading */
+ int bh_space; /* space in bh_curr for appending */
+};
+
+typedef struct
+{
+ buffheader_T sr_redobuff;
+ buffheader_T sr_old_redobuff;
+} save_redo_T;
+
+/*
+ * used for completion on the command line
+ */
+typedef struct expand
+{
+ int xp_context; /* type of expansion */
+ char_u *xp_pattern; /* start of item to expand */
+ int xp_pattern_len; /* bytes in xp_pattern before cursor */
+#if defined(FEAT_USR_CMDS) && defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL)
+ char_u *xp_arg; /* completion function */
+ sctx_T xp_script_ctx; /* SCTX for completion function */
+#endif
+ int xp_backslash; /* one of the XP_BS_ values */
+#ifndef BACKSLASH_IN_FILENAME
+ int xp_shell; /* TRUE for a shell command, more
+ characters need to be escaped */
+#endif
+ int xp_numfiles; /* number of files found by
+ file name completion */
+ char_u **xp_files; /* list of files */
+ char_u *xp_line; /* text being completed */
+ int xp_col; /* cursor position in line */
+} expand_T;
+
+/* values for xp_backslash */
+#define XP_BS_NONE 0 /* nothing special for backslashes */
+#define XP_BS_ONE 1 /* uses one backslash before a space */
+#define XP_BS_THREE 2 /* uses three backslashes before a space */
+
+/*
+ * Command modifiers ":vertical", ":browse", ":confirm" and ":hide" set a flag.
+ * This needs to be saved for recursive commands, put them in a structure for
+ * easy manipulation.
+ */
+typedef struct
+{
+ int hide; /* TRUE when ":hide" was used */
+# ifdef FEAT_BROWSE_CMD
+ int browse; /* TRUE to invoke file dialog */
+# endif
+ int split; /* flags for win_split() */
+ int tab; /* > 0 when ":tab" was used */
+# if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
+ int confirm; /* TRUE to invoke yes/no dialog */
+# endif
+ int keepalt; /* TRUE when ":keepalt" was used */
+ int keepmarks; /* TRUE when ":keepmarks" was used */
+ int keepjumps; /* TRUE when ":keepjumps" was used */
+ int lockmarks; /* TRUE when ":lockmarks" was used */
+ int keeppatterns; /* TRUE when ":keeppatterns" was used */
+ int noswapfile; /* TRUE when ":noswapfile" was used */
+ char_u *save_ei; /* saved value of 'eventignore' */
+ regmatch_T filter_regmatch; /* set by :filter /pat/ */
+ int filter_force; /* set for :filter! */
+} cmdmod_T;
+
+#define MF_SEED_LEN 8
+
+struct memfile
+{
+ char_u *mf_fname; /* name of the file */
+ char_u *mf_ffname; /* idem, full path */
+ int mf_fd; /* file descriptor */
+ bhdr_T *mf_free_first; /* first block_hdr in free list */
+ bhdr_T *mf_used_first; /* mru block_hdr in used list */
+ bhdr_T *mf_used_last; /* lru block_hdr in used list */
+ unsigned mf_used_count; /* number of pages in used list */
+ unsigned mf_used_count_max; /* maximum number of pages in memory */
+ mf_hashtab_T mf_hash; /* hash lists */
+ mf_hashtab_T mf_trans; /* trans lists */
+ blocknr_T mf_blocknr_max; /* highest positive block number + 1*/
+ blocknr_T mf_blocknr_min; /* lowest negative block number - 1 */
+ blocknr_T mf_neg_count; /* number of negative blocks numbers */
+ blocknr_T mf_infile_count; /* number of pages in the file */
+ unsigned mf_page_size; /* number of bytes in a page */
+ int mf_dirty; /* TRUE if there are dirty blocks */
+#ifdef FEAT_CRYPT
+ buf_T *mf_buffer; /* buffer this memfile is for */
+ char_u mf_seed[MF_SEED_LEN]; /* seed for encryption */
+
+ /* Values for key, method and seed used for reading data blocks when
+ * updating for a newly set key or method. Only when mf_old_key != NULL. */
+ char_u *mf_old_key;
+ int mf_old_cm;
+ char_u mf_old_seed[MF_SEED_LEN];
+#endif
+};
+
+/*
+ * things used in memline.c
+ */
+/*
+ * When searching for a specific line, we remember what blocks in the tree
+ * are the branches leading to that block. This is stored in ml_stack. Each
+ * entry is a pointer to info in a block (may be data block or pointer block)
+ */
+typedef struct info_pointer
+{
+ blocknr_T ip_bnum; /* block number */
+ linenr_T ip_low; /* lowest lnum in this block */
+ linenr_T ip_high; /* highest lnum in this block */
+ int ip_index; /* index for block with current lnum */
+} infoptr_T; /* block/index pair */
+
+#ifdef FEAT_BYTEOFF
+typedef struct ml_chunksize
+{
+ int mlcs_numlines;
+ long mlcs_totalsize;
+} chunksize_T;
+
+ /* Flags when calling ml_updatechunk() */
+
+#define ML_CHNK_ADDLINE 1
+#define ML_CHNK_DELLINE 2
+#define ML_CHNK_UPDLINE 3
+#endif
+
+/*
+ * the memline structure holds all the information about a memline
+ */
+typedef struct memline
+{
+ linenr_T ml_line_count; /* number of lines in the buffer */
+
+ memfile_T *ml_mfp; /* pointer to associated memfile */
+
+#define ML_EMPTY 1 /* empty buffer */
+#define ML_LINE_DIRTY 2 /* cached line was changed and allocated */
+#define ML_LOCKED_DIRTY 4 /* ml_locked was changed */
+#define ML_LOCKED_POS 8 /* ml_locked needs positive block number */
+ int ml_flags;
+
+ infoptr_T *ml_stack; /* stack of pointer blocks (array of IPTRs) */
+ int ml_stack_top; /* current top of ml_stack */
+ int ml_stack_size; /* total number of entries in ml_stack */
+
+ linenr_T ml_line_lnum; /* line number of cached line, 0 if not valid */
+ char_u *ml_line_ptr; /* pointer to cached line */
+ colnr_T ml_line_len; /* length of the cached line, including NUL */
+
+ bhdr_T *ml_locked; /* block used by last ml_get */
+ linenr_T ml_locked_low; /* first line in ml_locked */
+ linenr_T ml_locked_high; /* last line in ml_locked */
+ int ml_locked_lineadd; /* number of lines inserted in ml_locked */
+#ifdef FEAT_BYTEOFF
+ chunksize_T *ml_chunksize;
+ int ml_numchunks;
+ int ml_usedchunks;
+#endif
+} memline_T;
+
+
+/*
+ * Structure defining text properties. These stick with the text.
+ * When stored in memline they are after the text, ml_line_len is larger than
+ * STRLEN(ml_line_ptr) + 1.
+ */
+typedef struct textprop_S
+{
+ colnr_T tp_col; // start column (one based, in bytes)
+ colnr_T tp_len; // length in bytes
+ int tp_id; // identifier
+ int tp_type; // property type
+ int tp_flags; // TP_FLAG_ values
+} textprop_T;
+
+#define TP_FLAG_CONT_NEXT 1 // property continues in next line
+#define TP_FLAG_CONT_PREV 2 // property was continued from prev line
+
+/*
+ * Structure defining a property type.
+ */
+typedef struct proptype_S
+{
+ int pt_id; // value used for tp_id
+ int pt_type; // number used for tp_type
+ int pt_hl_id; // highlighting
+ int pt_priority; // priority
+ int pt_flags; // PT_FLAG_ values
+ char_u pt_name[1]; // property type name, actually longer
+} proptype_T;
+
+#define PT_FLAG_INS_START_INCL 1 // insert at start included in property
+#define PT_FLAG_INS_END_INCL 2 // insert at end included in property
+
+// Sign group
+typedef struct signgroup_S
+{
+ short_u refcount; // number of signs in this group
+ int next_sign_id; // next sign id for this group
+ char_u sg_name[1]; // sign group name
+} signgroup_T;
+
+typedef struct signlist signlist_T;
+
+struct signlist
+{
+ int id; /* unique identifier for each placed sign */
+ linenr_T lnum; /* line number which has this sign */
+ int typenr; /* typenr of sign */
+ signgroup_T *group; /* sign group */
+ int priority; /* priority for highlighting */
+ signlist_T *next; /* next signlist entry */
+ signlist_T *prev; /* previous entry -- for easy reordering */
+};
+
+#if defined(FEAT_SIGNS) || defined(PROTO)
+// Macros to get the sign group structure from the group name
+#define SGN_KEY_OFF offsetof(signgroup_T, sg_name)
+#define HI2SG(hi) ((signgroup_T *)((hi)->hi_key - SGN_KEY_OFF))
+
+// Default sign priority for highlighting
+#define SIGN_DEF_PRIO 10
+
+/* type argument for buf_getsigntype() */
+#define SIGN_ANY 0
+#define SIGN_LINEHL 1
+#define SIGN_ICON 2
+#define SIGN_TEXT 3
+#endif
+
+/*
+ * Argument list: Array of file names.
+ * Used for the global argument list and the argument lists local to a window.
+ */
+typedef struct arglist
+{
+ garray_T al_ga; /* growarray with the array of file names */
+ int al_refcount; /* number of windows using this arglist */
+ int id; /* id of this arglist */
+} alist_T;
+
+/*
+ * For each argument remember the file name as it was given, and the buffer
+ * number that contains the expanded file name (required for when ":cd" is
+ * used.
+ */
+typedef struct argentry
+{
+ char_u *ae_fname; /* file name as specified */
+ int ae_fnum; /* buffer number with expanded file name */
+} aentry_T;
+
+#define ALIST(win) (win)->w_alist
+#define GARGLIST ((aentry_T *)global_alist.al_ga.ga_data)
+#define ARGLIST ((aentry_T *)ALIST(curwin)->al_ga.ga_data)
+#define WARGLIST(wp) ((aentry_T *)ALIST(wp)->al_ga.ga_data)
+#define AARGLIST(al) ((aentry_T *)((al)->al_ga.ga_data))
+#define GARGCOUNT (global_alist.al_ga.ga_len)
+#define ARGCOUNT (ALIST(curwin)->al_ga.ga_len)
+#define WARGCOUNT(wp) (ALIST(wp)->al_ga.ga_len)
+
+/*
+ * A list used for saving values of "emsg_silent". Used by ex_try() to save the
+ * value of "emsg_silent" if it was non-zero. When this is done, the CSF_SILENT
+ * flag below is set.
+ */
+
+typedef struct eslist_elem eslist_T;
+struct eslist_elem
+{
+ int saved_emsg_silent; /* saved value of "emsg_silent" */
+ eslist_T *next; /* next element on the list */
+};
+
+/*
+ * For conditional commands a stack is kept of nested conditionals.
+ * When cs_idx < 0, there is no conditional command.
+ */
+#define CSTACK_LEN 50
+
+struct condstack
+{
+ short cs_flags[CSTACK_LEN]; /* CSF_ flags */
+ char cs_pending[CSTACK_LEN]; /* CSTP_: what's pending in ":finally"*/
+ union {
+ void *csp_rv[CSTACK_LEN]; /* return typeval for pending return */
+ void *csp_ex[CSTACK_LEN]; /* exception for pending throw */
+ } cs_pend;
+ void *cs_forinfo[CSTACK_LEN]; /* info used by ":for" */
+ int cs_line[CSTACK_LEN]; /* line nr of ":while"/":for" line */
+ int cs_idx; /* current entry, or -1 if none */
+ int cs_looplevel; /* nr of nested ":while"s and ":for"s */
+ int cs_trylevel; /* nr of nested ":try"s */
+ eslist_T *cs_emsg_silent_list; /* saved values of "emsg_silent" */
+ char cs_lflags; /* loop flags: CSL_ flags */
+};
+# define cs_rettv cs_pend.csp_rv
+# define cs_exception cs_pend.csp_ex
+
+/* There is no CSF_IF, the lack of CSF_WHILE, CSF_FOR and CSF_TRY means ":if"
+ * was used. */
+# define CSF_TRUE 0x0001 /* condition was TRUE */
+# define CSF_ACTIVE 0x0002 /* current state is active */
+# define CSF_ELSE 0x0004 /* ":else" has been passed */
+# define CSF_WHILE 0x0008 /* is a ":while" */
+# define CSF_FOR 0x0010 /* is a ":for" */
+
+# define CSF_TRY 0x0100 /* is a ":try" */
+# define CSF_FINALLY 0x0200 /* ":finally" has been passed */
+# define CSF_THROWN 0x0400 /* exception thrown to this try conditional */
+# define CSF_CAUGHT 0x0800 /* exception caught by this try conditional */
+# define CSF_SILENT 0x1000 /* "emsg_silent" reset by ":try" */
+/* Note that CSF_ELSE is only used when CSF_TRY and CSF_WHILE are unset
+ * (an ":if"), and CSF_SILENT is only used when CSF_TRY is set. */
+
+/*
+ * What's pending for being reactivated at the ":endtry" of this try
+ * conditional:
+ */
+# define CSTP_NONE 0 /* nothing pending in ":finally" clause */
+# define CSTP_ERROR 1 /* an error is pending */
+# define CSTP_INTERRUPT 2 /* an interrupt is pending */
+# define CSTP_THROW 4 /* a throw is pending */
+# define CSTP_BREAK 8 /* ":break" is pending */
+# define CSTP_CONTINUE 16 /* ":continue" is pending */
+# define CSTP_RETURN 24 /* ":return" is pending */
+# define CSTP_FINISH 32 /* ":finish" is pending */
+
+/*
+ * Flags for the cs_lflags item in struct condstack.
+ */
+# define CSL_HAD_LOOP 1 /* just found ":while" or ":for" */
+# define CSL_HAD_ENDLOOP 2 /* just found ":endwhile" or ":endfor" */
+# define CSL_HAD_CONT 4 /* just found ":continue" */
+# define CSL_HAD_FINA 8 /* just found ":finally" */
+
+/*
+ * A list of error messages that can be converted to an exception. "throw_msg"
+ * is only set in the first element of the list. Usually, it points to the
+ * original message stored in that element, but sometimes it points to a later
+ * message in the list. See cause_errthrow() below.
+ */
+struct msglist
+{
+ char *msg; /* original message */
+ char *throw_msg; /* msg to throw: usually original one */
+ struct msglist *next; /* next of several messages in a row */
+};
+
+/*
+ * The exception types.
+ */
+typedef enum
+{
+ ET_USER, // exception caused by ":throw" command
+ ET_ERROR, // error exception
+ ET_INTERRUPT, // interrupt exception triggered by Ctrl-C
+} except_type_T;
+
+/*
+ * Structure describing an exception.
+ * (don't use "struct exception", it's used by the math library).
+ */
+typedef struct vim_exception except_T;
+struct vim_exception
+{
+ except_type_T type; /* exception type */
+ char *value; /* exception value */
+ struct msglist *messages; /* message(s) causing error exception */
+ char_u *throw_name; /* name of the throw point */
+ linenr_T throw_lnum; /* line number of the throw point */
+ except_T *caught; /* next exception on the caught stack */
+};
+
+/*
+ * Structure to save the error/interrupt/exception state between calls to
+ * enter_cleanup() and leave_cleanup(). Must be allocated as an automatic
+ * variable by the (common) caller of these functions.
+ */
+typedef struct cleanup_stuff cleanup_T;
+struct cleanup_stuff
+{
+ int pending; /* error/interrupt/exception state */
+ except_T *exception; /* exception value */
+};
+
+#ifdef FEAT_SYN_HL
+/* struct passed to in_id_list() */
+struct sp_syn
+{
+ int inc_tag; /* ":syn include" unique tag */
+ short id; /* highlight group ID of item */
+ short *cont_in_list; /* cont.in group IDs, if non-zero */
+};
+
+/*
+ * Each keyword has one keyentry, which is linked in a hash list.
+ */
+typedef struct keyentry keyentry_T;
+
+struct keyentry
+{
+ keyentry_T *ke_next; /* next entry with identical "keyword[]" */
+ struct sp_syn k_syn; /* struct passed to in_id_list() */
+ short *next_list; /* ID list for next match (if non-zero) */
+ int flags;
+ int k_char; /* conceal substitute character */
+ char_u keyword[1]; /* actually longer */
+};
+
+/*
+ * Struct used to store one state of the state stack.
+ */
+typedef struct buf_state
+{
+ int bs_idx; /* index of pattern */
+ int bs_flags; /* flags for pattern */
+#ifdef FEAT_CONCEAL
+ int bs_seqnr; /* stores si_seqnr */
+ int bs_cchar; /* stores si_cchar */
+#endif
+ reg_extmatch_T *bs_extmatch; /* external matches from start pattern */
+} bufstate_T;
+
+/*
+ * syn_state contains the syntax state stack for the start of one line.
+ * Used by b_sst_array[].
+ */
+typedef struct syn_state synstate_T;
+
+struct syn_state
+{
+ synstate_T *sst_next; /* next entry in used or free list */
+ linenr_T sst_lnum; /* line number for this state */
+ union
+ {
+ bufstate_T sst_stack[SST_FIX_STATES]; /* short state stack */
+ garray_T sst_ga; /* growarray for long state stack */
+ } sst_union;
+ int sst_next_flags; /* flags for sst_next_list */
+ int sst_stacksize; /* number of states on the stack */
+ short *sst_next_list; /* "nextgroup" list in this state
+ * (this is a copy, don't free it! */
+ disptick_T sst_tick; /* tick when last displayed */
+ linenr_T sst_change_lnum;/* when non-zero, change in this line
+ * may have made the state invalid */
+};
+#endif /* FEAT_SYN_HL */
+
+/*
+ * Structure shared between syntax.c, screen.c and gui_x11.c.
+ */
+typedef struct attr_entry
+{
+ short ae_attr; /* HL_BOLD, etc. */
+ union
+ {
+ struct
+ {
+ char_u *start; /* start escape sequence */
+ char_u *stop; /* stop escape sequence */
+ } term;
+ struct
+ {
+ /* These colors need to be > 8 bits to hold 256. */
+ short_u fg_color; /* foreground color number */
+ short_u bg_color; /* background color number */
+# ifdef FEAT_TERMGUICOLORS
+ guicolor_T fg_rgb; /* foreground color RGB */
+ guicolor_T bg_rgb; /* background color RGB */
+# endif
+ } cterm;
+# ifdef FEAT_GUI
+ struct
+ {
+ guicolor_T fg_color; /* foreground color handle */
+ guicolor_T bg_color; /* background color handle */
+ guicolor_T sp_color; /* special color handle */
+ GuiFont font; /* font handle */
+# ifdef FEAT_XFONTSET
+ GuiFontset fontset; /* fontset handle */
+# endif
+ } gui;
+# endif
+ } ae_u;
+} attrentry_T;
+
+#ifdef USE_ICONV
+# ifdef HAVE_ICONV_H
+# include <iconv.h>
+# else
+# if defined(MACOS_X)
+# include <sys/errno.h>
+# ifndef EILSEQ
+# define EILSEQ ENOENT /* Early MacOS X does not have EILSEQ */
+# endif
+typedef struct _iconv_t *iconv_t;
+# else
+# include <errno.h>
+# endif
+typedef void *iconv_t;
+# endif
+#endif
+
+/*
+ * Used for the typeahead buffer: typebuf.
+ */
+typedef struct
+{
+ char_u *tb_buf; /* buffer for typed characters */
+ char_u *tb_noremap; /* mapping flags for characters in tb_buf[] */
+ int tb_buflen; /* size of tb_buf[] */
+ int tb_off; /* current position in tb_buf[] */
+ int tb_len; /* number of valid bytes in tb_buf[] */
+ int tb_maplen; /* nr of mapped bytes in tb_buf[] */
+ int tb_silent; /* nr of silently mapped bytes in tb_buf[] */
+ int tb_no_abbr_cnt; /* nr of bytes without abbrev. in tb_buf[] */
+ int tb_change_cnt; /* nr of time tb_buf was changed; never zero */
+} typebuf_T;
+
+/* Struct to hold the saved typeahead for save_typeahead(). */
+typedef struct
+{
+ typebuf_T save_typebuf;
+ int typebuf_valid; /* TRUE when save_typebuf valid */
+ int old_char;
+ int old_mod_mask;
+ buffheader_T save_readbuf1;
+ buffheader_T save_readbuf2;
+#ifdef USE_INPUT_BUF
+ char_u *save_inputbuf;
+#endif
+} tasave_T;
+
+/*
+ * Used for conversion of terminal I/O and script files.
+ */
+typedef struct
+{
+ int vc_type; /* zero or one of the CONV_ values */
+ int vc_factor; /* max. expansion factor */
+# ifdef WIN3264
+ int vc_cpfrom; /* codepage to convert from (CONV_CODEPAGE) */
+ int vc_cpto; /* codepage to convert to (CONV_CODEPAGE) */
+# endif
+# ifdef USE_ICONV
+ iconv_t vc_fd; /* for CONV_ICONV */
+# endif
+ int vc_fail; /* fail for invalid char, don't use '?' */
+} vimconv_T;
+
+/*
+ * Structure used for reading from the viminfo file.
+ */
+typedef struct
+{
+ char_u *vir_line; /* text of the current line */
+ FILE *vir_fd; /* file descriptor */
+ vimconv_T vir_conv; /* encoding conversion */
+ int vir_version; /* viminfo version detected or -1 */
+ garray_T vir_barlines; /* lines starting with | */
+} vir_T;
+
+#define CONV_NONE 0
+#define CONV_TO_UTF8 1
+#define CONV_9_TO_UTF8 2
+#define CONV_TO_LATIN1 3
+#define CONV_TO_LATIN9 4
+#define CONV_ICONV 5
+#ifdef WIN3264
+# define CONV_CODEPAGE 10 /* codepage -> codepage */
+#endif
+#ifdef MACOS_X
+# define CONV_MAC_LATIN1 20
+# define CONV_LATIN1_MAC 21
+# define CONV_MAC_UTF8 22
+# define CONV_UTF8_MAC 23
+#endif
+
+/*
+ * Structure used for mappings and abbreviations.
+ */
+typedef struct mapblock mapblock_T;
+struct mapblock
+{
+ mapblock_T *m_next; /* next mapblock in list */
+ char_u *m_keys; /* mapped from, lhs */
+ char_u *m_str; /* mapped to, rhs */
+ char_u *m_orig_str; /* rhs as entered by the user */
+ int m_keylen; /* strlen(m_keys) */
+ int m_mode; /* valid mode */
+ int m_noremap; /* if non-zero no re-mapping for m_str */
+ char m_silent; /* <silent> used, don't echo commands */
+ char m_nowait; /* <nowait> used */
+#ifdef FEAT_EVAL
+ char m_expr; /* <expr> used, m_str is an expression */
+ sctx_T m_script_ctx; /* SCTX where map was defined */
+#endif
+};
+
+/*
+ * Used for highlighting in the status line.
+ */
+struct stl_hlrec
+{
+ char_u *start;
+ int userhl; /* 0: no HL, 1-9: User HL, < 0 for syn ID */
+};
+
+
+/*
+ * Syntax items - usually buffer-specific.
+ */
+
+/* Item for a hashtable. "hi_key" can be one of three values:
+ * NULL: Never been used
+ * HI_KEY_REMOVED: Entry was removed
+ * Otherwise: Used item, pointer to the actual key; this usually is
+ * inside the item, subtract an offset to locate the item.
+ * This reduces the size of hashitem by 1/3.
+ */
+typedef struct hashitem_S
+{
+ long_u hi_hash; /* cached hash number of hi_key */
+ char_u *hi_key;
+} hashitem_T;
+
+/* The address of "hash_removed" is used as a magic number for hi_key to
+ * indicate a removed item. */
+#define HI_KEY_REMOVED &hash_removed
+#define HASHITEM_EMPTY(hi) ((hi)->hi_key == NULL || (hi)->hi_key == &hash_removed)
+
+/* Initial size for a hashtable. Our items are relatively small and growing
+ * is expensive, thus use 16 as a start. Must be a power of 2. */
+#define HT_INIT_SIZE 16
+
+typedef struct hashtable_S
+{
+ long_u ht_mask; /* mask used for hash value (nr of items in
+ * array is "ht_mask" + 1) */
+ long_u ht_used; /* number of items used */
+ long_u ht_filled; /* number of items used + removed */
+ int ht_locked; /* counter for hash_lock() */
+ int ht_error; /* when set growing failed, can't add more
+ items before growing works */
+ hashitem_T *ht_array; /* points to the array, allocated when it's
+ not "ht_smallarray" */
+ hashitem_T ht_smallarray[HT_INIT_SIZE]; /* initial array */
+} hashtab_T;
+
+typedef long_u hash_T; /* Type for hi_hash */
+
+
+#ifdef FEAT_NUM64
+/* Use 64-bit Number. */
+# ifdef WIN3264
+# ifdef PROTO
+typedef long varnumber_T;
+typedef unsigned long uvarnumber_T;
+#define VARNUM_MIN LONG_MIN
+#define VARNUM_MAX LONG_MAX
+#define UVARNUM_MAX ULONG_MAX
+# else
+typedef __int64 varnumber_T;
+typedef unsigned __int64 uvarnumber_T;
+#define VARNUM_MIN _I64_MIN
+#define VARNUM_MAX _I64_MAX
+#define UVARNUM_MAX _UI64_MAX
+# endif
+# elif defined(HAVE_STDINT_H)
+typedef int64_t varnumber_T;
+typedef uint64_t uvarnumber_T;
+#define VARNUM_MIN INT64_MIN
+#define VARNUM_MAX INT64_MAX
+#define UVARNUM_MAX UINT64_MAX
+# else
+typedef long varnumber_T;
+typedef unsigned long uvarnumber_T;
+#define VARNUM_MIN LONG_MIN
+#define VARNUM_MAX LONG_MAX
+#define UVARNUM_MAX ULONG_MAX
+# endif
+#else
+/* Use 32-bit Number. */
+typedef int varnumber_T;
+typedef unsigned int uvarnumber_T;
+#define VARNUM_MIN INT_MIN
+#define VARNUM_MAX INT_MAX
+#define UVARNUM_MAX UINT_MAX
+#endif
+
+typedef double float_T;
+
+typedef struct listvar_S list_T;
+typedef struct dictvar_S dict_T;
+typedef struct partial_S partial_T;
+typedef struct blobvar_S blob_T;
+
+typedef struct jobvar_S job_T;
+typedef struct readq_S readq_T;
+typedef struct writeq_S writeq_T;
+typedef struct jsonq_S jsonq_T;
+typedef struct cbq_S cbq_T;
+typedef struct channel_S channel_T;
+
+typedef enum
+{
+ VAR_UNKNOWN = 0,
+ VAR_NUMBER, // "v_number" is used
+ VAR_STRING, // "v_string" is used
+ VAR_FUNC, // "v_string" is function name
+ VAR_PARTIAL, // "v_partial" is used
+ VAR_LIST, // "v_list" is used
+ VAR_DICT, // "v_dict" is used
+ VAR_FLOAT, // "v_float" is used
+ VAR_SPECIAL, // "v_number" is used
+ VAR_JOB, // "v_job" is used
+ VAR_CHANNEL, // "v_channel" is used
+ VAR_BLOB, // "v_blob" is used
+} vartype_T;
+
+/*
+ * Structure to hold an internal variable without a name.
+ */
+typedef struct
+{
+ vartype_T v_type;
+ char v_lock; /* see below: VAR_LOCKED, VAR_FIXED */
+ union
+ {
+ varnumber_T v_number; /* number value */
+#ifdef FEAT_FLOAT
+ float_T v_float; /* floating number value */
+#endif
+ char_u *v_string; /* string value (can be NULL!) */
+ list_T *v_list; /* list value (can be NULL!) */
+ dict_T *v_dict; /* dict value (can be NULL!) */
+ partial_T *v_partial; /* closure: function with args */
+#ifdef FEAT_JOB_CHANNEL
+ job_T *v_job; /* job value (can be NULL!) */
+ channel_T *v_channel; /* channel value (can be NULL!) */
+#endif
+ blob_T *v_blob; /* blob value (can be NULL!) */
+ } vval;
+} typval_T;
+
+/* Values for "dv_scope". */
+#define VAR_SCOPE 1 /* a:, v:, s:, etc. scope dictionaries */
+#define VAR_DEF_SCOPE 2 /* l:, g: scope dictionaries: here funcrefs are not
+ allowed to mask existing functions */
+
+/* Values for "v_lock". */
+#define VAR_LOCKED 1 /* locked with lock(), can use unlock() */
+#define VAR_FIXED 2 /* locked forever */
+
+/*
+ * Structure to hold an item of a list: an internal variable without a name.
+ */
+typedef struct listitem_S listitem_T;
+
+struct listitem_S
+{
+ listitem_T *li_next; /* next item in list */
+ listitem_T *li_prev; /* previous item in list */
+ typval_T li_tv; /* type and value of the variable */
+};
+
+/*
+ * Struct used by those that are using an item in a list.
+ */
+typedef struct listwatch_S listwatch_T;
+
+struct listwatch_S
+{
+ listitem_T *lw_item; /* item being watched */
+ listwatch_T *lw_next; /* next watcher */
+};
+
+/*
+ * Structure to hold info about a list.
+ * Order of members is optimized to reduce padding.
+ */
+struct listvar_S
+{
+ listitem_T *lv_first; /* first item, NULL if none */
+ listitem_T *lv_last; /* last item, NULL if none */
+ listwatch_T *lv_watch; /* first watcher, NULL if none */
+ listitem_T *lv_idx_item; /* when not NULL item at index "lv_idx" */
+ list_T *lv_copylist; /* copied list used by deepcopy() */
+ list_T *lv_used_next; /* next list in used lists list */
+ list_T *lv_used_prev; /* previous list in used lists list */
+ int lv_refcount; /* reference count */
+ int lv_len; /* number of items */
+ int lv_idx; /* cached index of an item */
+ int lv_copyID; /* ID used by deepcopy() */
+ char lv_lock; /* zero, VAR_LOCKED, VAR_FIXED */
+};
+
+/*
+ * Static list with 10 items. Use init_static_list() to initialize.
+ */
+typedef struct {
+ list_T sl_list; /* must be first */
+ listitem_T sl_items[10];
+} staticList10_T;
+
+/*
+ * Structure to hold an item of a Dictionary.
+ * Also used for a variable.
+ * The key is copied into "di_key" to avoid an extra alloc/free for it.
+ */
+struct dictitem_S
+{
+ typval_T di_tv; /* type and value of the variable */
+ char_u di_flags; /* flags (only used for variable) */
+ char_u di_key[1]; /* key (actually longer!) */
+};
+typedef struct dictitem_S dictitem_T;
+
+/* A dictitem with a 16 character key (plus NUL). */
+struct dictitem16_S
+{
+ typval_T di_tv; /* type and value of the variable */
+ char_u di_flags; /* flags (only used for variable) */
+ char_u di_key[17]; /* key */
+};
+typedef struct dictitem16_S dictitem16_T;
+
+#define DI_FLAGS_RO 1 /* "di_flags" value: read-only variable */
+#define DI_FLAGS_RO_SBX 2 /* "di_flags" value: read-only in the sandbox */
+#define DI_FLAGS_FIX 4 /* "di_flags" value: fixed: no :unlet or remove() */
+#define DI_FLAGS_LOCK 8 /* "di_flags" value: locked variable */
+#define DI_FLAGS_ALLOC 16 /* "di_flags" value: separately allocated */
+
+/*
+ * Structure to hold info about a Dictionary.
+ */
+struct dictvar_S
+{
+ char dv_lock; /* zero, VAR_LOCKED, VAR_FIXED */
+ char dv_scope; /* zero, VAR_SCOPE, VAR_DEF_SCOPE */
+ int dv_refcount; /* reference count */
+ int dv_copyID; /* ID used by deepcopy() */
+ hashtab_T dv_hashtab; /* hashtab that refers to the items */
+ dict_T *dv_copydict; /* copied dict used by deepcopy() */
+ dict_T *dv_used_next; /* next dict in used dicts list */
+ dict_T *dv_used_prev; /* previous dict in used dicts list */
+};
+
+/*
+ * Structure to hold info about a blob.
+ */
+struct blobvar_S
+{
+ garray_T bv_ga; // growarray with the data
+ int bv_refcount; // reference count
+ char bv_lock; // zero, VAR_LOCKED, VAR_FIXED
+};
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+typedef struct funccall_S funccall_T;
+
+/*
+ * Structure to hold info for a user function.
+ */
+typedef struct
+{
+ int uf_varargs; /* variable nr of arguments */
+ int uf_flags;
+ int uf_calls; /* nr of active calls */
+ int uf_cleared; /* func_clear() was already called */
+ garray_T uf_args; /* arguments */
+ garray_T uf_lines; /* function lines */
+# ifdef FEAT_PROFILE
+ int uf_profiling; /* TRUE when func is being profiled */
+ int uf_prof_initialized;
+ /* profiling the function as a whole */
+ int uf_tm_count; /* nr of calls */
+ proftime_T uf_tm_total; /* time spent in function + children */
+ proftime_T uf_tm_self; /* time spent in function itself */
+ proftime_T uf_tm_children; /* time spent in children this call */
+ /* profiling the function per line */
+ int *uf_tml_count; /* nr of times line was executed */
+ proftime_T *uf_tml_total; /* time spent in a line + children */
+ proftime_T *uf_tml_self; /* time spent in a line itself */
+ proftime_T uf_tml_start; /* start time for current line */
+ proftime_T uf_tml_children; /* time spent in children for this line */
+ proftime_T uf_tml_wait; /* start wait time for current line */
+ int uf_tml_idx; /* index of line being timed; -1 if none */
+ int uf_tml_execed; /* line being timed was executed */
+# endif
+ sctx_T uf_script_ctx; /* SCTX where function was defined,
+ used for s: variables */
+ int uf_refcount; /* reference count, see func_name_refcount() */
+ funccall_T *uf_scoped; /* l: local variables for closure */
+ char_u uf_name[1]; /* name of function (actually longer); can
+ start with <SNR>123_ (<SNR> is K_SPECIAL
+ KS_EXTRA KE_SNR) */
+} ufunc_T;
+
+#define MAX_FUNC_ARGS 20 /* maximum number of function arguments */
+#define VAR_SHORT_LEN 20 /* short variable name length */
+#define FIXVAR_CNT 12 /* number of fixed variables */
+
+/* structure to hold info for a function that is currently being executed. */
+struct funccall_S
+{
+ ufunc_T *func; /* function being called */
+ int linenr; /* next line to be executed */
+ int returned; /* ":return" used */
+ struct /* fixed variables for arguments */
+ {
+ dictitem_T var; /* variable (without room for name) */
+ char_u room[VAR_SHORT_LEN]; /* room for the name */
+ } fixvar[FIXVAR_CNT];
+ dict_T l_vars; /* l: local function variables */
+ dictitem_T l_vars_var; /* variable for l: scope */
+ dict_T l_avars; /* a: argument variables */
+ dictitem_T l_avars_var; /* variable for a: scope */
+ list_T l_varlist; /* list for a:000 */
+ listitem_T l_listitems[MAX_FUNC_ARGS]; /* listitems for a:000 */
+ typval_T *rettv; /* return value */
+ linenr_T breakpoint; /* next line with breakpoint or zero */
+ int dbg_tick; /* debug_tick when breakpoint was set */
+ int level; /* top nesting level of executed function */
+#ifdef FEAT_PROFILE
+ proftime_T prof_child; /* time spent in a child */
+#endif
+ funccall_T *caller; /* calling function or NULL */
+
+ /* for closure */
+ int fc_refcount; /* number of user functions that reference this
+ * funccal */
+ int fc_copyID; /* for garbage collection */
+ garray_T fc_funcs; /* list of ufunc_T* which keep a reference to
+ * "func" */
+};
+
+/*
+ * Struct used by trans_function_name()
+ */
+typedef struct
+{
+ dict_T *fd_dict; /* Dictionary used */
+ char_u *fd_newkey; /* new key in "dict" in allocated memory */
+ dictitem_T *fd_di; /* Dictionary item used */
+} funcdict_T;
+
+typedef struct funccal_entry funccal_entry_T;
+struct funccal_entry {
+ void *top_funccal;
+ funccal_entry_T *next;
+};
+
+#else
+/* dummy typedefs for function prototypes */
+typedef struct
+{
+ int dummy;
+} ufunc_T;
+typedef struct
+{
+ int dummy;
+} funcdict_T;
+typedef struct
+{
+ int dummy;
+} funccal_entry_T;
+#endif
+
+struct partial_S
+{
+ int pt_refcount; /* reference count */
+ char_u *pt_name; /* function name; when NULL use
+ * pt_func->uf_name */
+ ufunc_T *pt_func; /* function pointer; when NULL lookup function
+ * with pt_name */
+ int pt_auto; /* when TRUE the partial was created for using
+ dict.member in handle_subscript() */
+ int pt_argc; /* number of arguments */
+ typval_T *pt_argv; /* arguments in allocated array */
+ dict_T *pt_dict; /* dict for "self" */
+};
+
+/* Information returned by get_tty_info(). */
+typedef struct {
+ int backspace; /* what the Backspace key produces */
+ int enter; /* what the Enter key produces */
+ int interrupt; /* interrupt character */
+ int nl_does_cr; /* TRUE when a NL is expanded to CR-NL on output */
+} ttyinfo_T;
+
+/* Status of a job. Order matters! */
+typedef enum
+{
+ JOB_FAILED,
+ JOB_STARTED,
+ JOB_ENDED, // detected job done
+ JOB_FINISHED, // job done and cleanup done
+} jobstatus_T;
+
+/*
+ * Structure to hold info about a Job.
+ */
+struct jobvar_S
+{
+ job_T *jv_next;
+ job_T *jv_prev;
+#ifdef UNIX
+ pid_t jv_pid;
+#endif
+#ifdef WIN32
+ PROCESS_INFORMATION jv_proc_info;
+ HANDLE jv_job_object;
+#endif
+ char_u *jv_tty_in; /* controlling tty input, allocated */
+ char_u *jv_tty_out; /* controlling tty output, allocated */
+ jobstatus_T jv_status;
+ char_u *jv_stoponexit; /* allocated */
+#ifdef UNIX
+ char_u *jv_termsig; /* allocated */
+#endif
+ int jv_exitval;
+ char_u *jv_exit_cb; /* allocated */
+ partial_T *jv_exit_partial;
+
+ buf_T *jv_in_buf; /* buffer from "in-name" */
+
+ int jv_refcount; /* reference count */
+ int jv_copyID;
+
+ channel_T *jv_channel; /* channel for I/O, reference counted */
+ char **jv_argv; /* command line used to start the job */
+};
+
+/*
+ * Structures to hold info about a Channel.
+ */
+struct readq_S
+{
+ char_u *rq_buffer;
+ long_u rq_buflen;
+ readq_T *rq_next;
+ readq_T *rq_prev;
+};
+
+struct writeq_S
+{
+ garray_T wq_ga;
+ writeq_T *wq_next;
+ writeq_T *wq_prev;
+};
+
+struct jsonq_S
+{
+ typval_T *jq_value;
+ jsonq_T *jq_next;
+ jsonq_T *jq_prev;
+ int jq_no_callback; /* TRUE when no callback was found */
+};
+
+struct cbq_S
+{
+ char_u *cq_callback;
+ partial_T *cq_partial;
+ int cq_seq_nr;
+ cbq_T *cq_next;
+ cbq_T *cq_prev;
+};
+
+/* mode for a channel */
+typedef enum
+{
+ MODE_NL = 0,
+ MODE_RAW,
+ MODE_JSON,
+ MODE_JS,
+} ch_mode_T;
+
+typedef enum {
+ JIO_PIPE, // default
+ JIO_NULL,
+ JIO_FILE,
+ JIO_BUFFER,
+ JIO_OUT
+} job_io_T;
+
+#define CH_PART_FD(part) ch_part[part].ch_fd
+
+/* Ordering matters, it is used in for loops: IN is last, only SOCK/OUT/ERR
+ * are polled. */
+typedef enum {
+ PART_SOCK = 0,
+#define CH_SOCK_FD CH_PART_FD(PART_SOCK)
+#ifdef FEAT_JOB_CHANNEL
+ PART_OUT,
+# define CH_OUT_FD CH_PART_FD(PART_OUT)
+ PART_ERR,
+# define CH_ERR_FD CH_PART_FD(PART_ERR)
+ PART_IN,
+# define CH_IN_FD CH_PART_FD(PART_IN)
+#endif
+ PART_COUNT,
+} ch_part_T;
+
+#define INVALID_FD (-1)
+
+/* The per-fd info for a channel. */
+typedef struct {
+ sock_T ch_fd; /* socket/stdin/stdout/stderr, -1 if not used */
+
+# if defined(UNIX) && !defined(HAVE_SELECT)
+ int ch_poll_idx; /* used by channel_poll_setup() */
+# endif
+
+#ifdef FEAT_GUI_X11
+ XtInputId ch_inputHandler; /* Cookie for input */
+#endif
+#ifdef FEAT_GUI_GTK
+ gint ch_inputHandler; /* Cookie for input */
+#endif
+
+ ch_mode_T ch_mode;
+ job_io_T ch_io;
+ int ch_timeout; /* request timeout in msec */
+
+ readq_T ch_head; /* header for circular raw read queue */
+ jsonq_T ch_json_head; /* header for circular json read queue */
+ int ch_block_id; /* ID that channel_read_json_block() is
+ waiting for */
+ /* When ch_wait_len is non-zero use ch_deadline to wait for incomplete
+ * message to be complete. The value is the length of the incomplete
+ * message when the deadline was set. If it gets longer (something was
+ * received) the deadline is reset. */
+ size_t ch_wait_len;
+#ifdef WIN32
+ DWORD ch_deadline;
+#else
+ struct timeval ch_deadline;
+#endif
+ int ch_block_write; /* for testing: 0 when not used, -1 when write
+ * does not block, 1 simulate blocking */
+ int ch_nonblocking; /* write() is non-blocking */
+ writeq_T ch_writeque; /* header for write queue */
+
+ cbq_T ch_cb_head; /* dummy node for per-request callbacks */
+ char_u *ch_callback; /* call when a msg is not handled */
+ partial_T *ch_partial;
+
+ bufref_T ch_bufref; /* buffer to read from or write to */
+ int ch_nomodifiable; /* TRUE when buffer can be 'nomodifiable' */
+ int ch_nomod_error; /* TRUE when e_modifiable was given */
+ int ch_buf_append; /* write appended lines instead top-bot */
+ linenr_T ch_buf_top; /* next line to send */
+ linenr_T ch_buf_bot; /* last line to send */
+} chanpart_T;
+
+struct channel_S {
+ channel_T *ch_next;
+ channel_T *ch_prev;
+
+ int ch_id; /* ID of the channel */
+ int ch_last_msg_id; /* ID of the last message */
+
+ chanpart_T ch_part[PART_COUNT]; /* info for socket, out, err and in */
+ int ch_write_text_mode; /* write buffer lines with CR, not NL */
+
+ char *ch_hostname; /* only for socket, allocated */
+ int ch_port; /* only for socket */
+
+ int ch_to_be_closed; /* bitset of readable fds to be closed.
+ * When all readable fds have been closed,
+ * set to (1 << PART_COUNT). */
+ int ch_to_be_freed; /* When TRUE channel must be freed when it's
+ * safe to invoke callbacks. */
+ int ch_error; /* When TRUE an error was reported. Avoids
+ * giving pages full of error messages when
+ * the other side has exited, only mention the
+ * first error until the connection works
+ * again. */
+
+ void (*ch_nb_close_cb)(void);
+ /* callback for Netbeans when channel is
+ * closed */
+
+#ifdef WIN32
+ int ch_named_pipe; /* using named pipe instead of pty */
+#endif
+ char_u *ch_callback; /* call when any msg is not handled */
+ partial_T *ch_partial;
+ char_u *ch_close_cb; /* call when channel is closed */
+ partial_T *ch_close_partial;
+ int ch_drop_never;
+ int ch_keep_open; /* do not close on read error */
+ int ch_nonblock;
+
+ job_T *ch_job; // Job that uses this channel; this does not
+ // count as a reference to avoid a circular
+ // reference, the job refers to the channel.
+ int ch_job_killed; // TRUE when there was a job and it was killed
+ // or we know it died.
+ int ch_anonymous_pipe; // ConPTY
+ int ch_killing; // TerminateJobObject() was called
+
+ int ch_refcount; // reference count
+ int ch_copyID;
+};
+
+#define JO_MODE 0x0001 /* channel mode */
+#define JO_IN_MODE 0x0002 /* stdin mode */
+#define JO_OUT_MODE 0x0004 /* stdout mode */
+#define JO_ERR_MODE 0x0008 /* stderr mode */
+#define JO_CALLBACK 0x0010 /* channel callback */
+#define JO_OUT_CALLBACK 0x0020 /* stdout callback */
+#define JO_ERR_CALLBACK 0x0040 /* stderr callback */
+#define JO_CLOSE_CALLBACK 0x0080 /* "close_cb" */
+#define JO_WAITTIME 0x0100 /* only for ch_open() */
+#define JO_TIMEOUT 0x0200 /* all timeouts */
+#define JO_OUT_TIMEOUT 0x0400 /* stdout timeouts */
+#define JO_ERR_TIMEOUT 0x0800 /* stderr timeouts */
+#define JO_PART 0x1000 /* "part" */
+#define JO_ID 0x2000 /* "id" */
+#define JO_STOPONEXIT 0x4000 /* "stoponexit" */
+#define JO_EXIT_CB 0x8000 /* "exit_cb" */
+#define JO_OUT_IO 0x10000 /* "out_io" */
+#define JO_ERR_IO 0x20000 /* "err_io" (JO_OUT_IO << 1) */
+#define JO_IN_IO 0x40000 /* "in_io" (JO_OUT_IO << 2) */
+#define JO_OUT_NAME 0x80000 /* "out_name" */
+#define JO_ERR_NAME 0x100000 /* "err_name" (JO_OUT_NAME << 1) */
+#define JO_IN_NAME 0x200000 /* "in_name" (JO_OUT_NAME << 2) */
+#define JO_IN_TOP 0x400000 /* "in_top" */
+#define JO_IN_BOT 0x800000 /* "in_bot" */
+#define JO_OUT_BUF 0x1000000 /* "out_buf" */
+#define JO_ERR_BUF 0x2000000 /* "err_buf" (JO_OUT_BUF << 1) */
+#define JO_IN_BUF 0x4000000 /* "in_buf" (JO_OUT_BUF << 2) */
+#define JO_CHANNEL 0x8000000 /* "channel" */
+#define JO_BLOCK_WRITE 0x10000000 /* "block_write" */
+#define JO_OUT_MODIFIABLE 0x20000000 /* "out_modifiable" */
+#define JO_ERR_MODIFIABLE 0x40000000 /* "err_modifiable" (JO_OUT_ << 1) */
+#define JO_ALL 0x7fffffff
+
+#define JO2_OUT_MSG 0x0001 /* "out_msg" */
+#define JO2_ERR_MSG 0x0002 /* "err_msg" (JO_OUT_ << 1) */
+#define JO2_TERM_NAME 0x0004 /* "term_name" */
+#define JO2_TERM_FINISH 0x0008 /* "term_finish" */
+#define JO2_ENV 0x0010 /* "env" */
+#define JO2_CWD 0x0020 /* "cwd" */
+#define JO2_TERM_ROWS 0x0040 /* "term_rows" */
+#define JO2_TERM_COLS 0x0080 /* "term_cols" */
+#define JO2_VERTICAL 0x0100 /* "vertical" */
+#define JO2_CURWIN 0x0200 /* "curwin" */
+#define JO2_HIDDEN 0x0400 /* "hidden" */
+#define JO2_TERM_OPENCMD 0x0800 /* "term_opencmd" */
+#define JO2_EOF_CHARS 0x1000 /* "eof_chars" */
+#define JO2_NORESTORE 0x2000 /* "norestore" */
+#define JO2_TERM_KILL 0x4000 /* "term_kill" */
+#define JO2_ANSI_COLORS 0x8000 /* "ansi_colors" */
+#define JO2_TERM_MODE 0x10000 /* "term_mode" */
+
+#define JO_MODE_ALL (JO_MODE + JO_IN_MODE + JO_OUT_MODE + JO_ERR_MODE)
+#define JO_CB_ALL \
+ (JO_CALLBACK + JO_OUT_CALLBACK + JO_ERR_CALLBACK + JO_CLOSE_CALLBACK)
+#define JO_TIMEOUT_ALL (JO_TIMEOUT + JO_OUT_TIMEOUT + JO_ERR_TIMEOUT)
+
+/*
+ * Options for job and channel commands.
+ */
+typedef struct
+{
+ int jo_set; /* JO_ bits for values that were set */
+ int jo_set2; /* JO2_ bits for values that were set */
+
+ ch_mode_T jo_mode;
+ ch_mode_T jo_in_mode;
+ ch_mode_T jo_out_mode;
+ ch_mode_T jo_err_mode;
+ int jo_noblock;
+
+ job_io_T jo_io[4]; /* PART_OUT, PART_ERR, PART_IN */
+ char_u jo_io_name_buf[4][NUMBUFLEN];
+ char_u *jo_io_name[4]; /* not allocated! */
+ int jo_io_buf[4];
+ int jo_pty;
+ int jo_modifiable[4];
+ int jo_message[4];
+ channel_T *jo_channel;
+
+ linenr_T jo_in_top;
+ linenr_T jo_in_bot;
+
+ char_u *jo_callback; /* not allocated! */
+ partial_T *jo_partial; /* not referenced! */
+ char_u *jo_out_cb; /* not allocated! */
+ partial_T *jo_out_partial; /* not referenced! */
+ char_u *jo_err_cb; /* not allocated! */
+ partial_T *jo_err_partial; /* not referenced! */
+ char_u *jo_close_cb; /* not allocated! */
+ partial_T *jo_close_partial; /* not referenced! */
+ char_u *jo_exit_cb; /* not allocated! */
+ partial_T *jo_exit_partial; /* not referenced! */
+ int jo_drop_never;
+ int jo_waittime;
+ int jo_timeout;
+ int jo_out_timeout;
+ int jo_err_timeout;
+ int jo_block_write; /* for testing only */
+ int jo_part;
+ int jo_id;
+ char_u jo_soe_buf[NUMBUFLEN];
+ char_u *jo_stoponexit;
+ dict_T *jo_env; /* environment variables */
+ char_u jo_cwd_buf[NUMBUFLEN];
+ char_u *jo_cwd;
+
+#ifdef FEAT_TERMINAL
+ /* when non-zero run the job in a terminal window of this size */
+ int jo_term_rows;
+ int jo_term_cols;
+ int jo_vertical;
+ int jo_curwin;
+ int jo_hidden;
+ int jo_term_norestore;
+ char_u *jo_term_name;
+ char_u *jo_term_opencmd;
+ int jo_term_finish;
+ char_u *jo_eof_chars;
+ char_u *jo_term_kill;
+# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
+ long_u jo_ansi_colors[16];
+# endif
+ int jo_term_mode; // first character of "term_mode"
+#endif
+} jobopt_T;
+
+
+/* structure used for explicit stack while garbage collecting hash tables */
+typedef struct ht_stack_S
+{
+ hashtab_T *ht;
+ struct ht_stack_S *prev;
+} ht_stack_T;
+
+/* structure used for explicit stack while garbage collecting lists */
+typedef struct list_stack_S
+{
+ list_T *list;
+ struct list_stack_S *prev;
+} list_stack_T;
+
+/* values for b_syn_spell: what to do with toplevel text */
+#define SYNSPL_DEFAULT 0 /* spell check if @Spell not defined */
+#define SYNSPL_TOP 1 /* spell check toplevel text */
+#define SYNSPL_NOTOP 2 /* don't spell check toplevel text */
+
+/* avoid #ifdefs for when b_spell is not available */
+#ifdef FEAT_SPELL
+# define B_SPELL(buf) ((buf)->b_spell)
+#else
+# define B_SPELL(buf) (0)
+#endif
+
+#ifdef FEAT_QUICKFIX
+typedef struct qf_info_S qf_info_T;
+#endif
+
+#ifdef FEAT_PROFILE
+/*
+ * Used for :syntime: timing of executing a syntax pattern.
+ */
+typedef struct {
+ proftime_T total; /* total time used */
+ proftime_T slowest; /* time of slowest call */
+ long count; /* nr of times used */
+ long match; /* nr of times matched */
+} syn_time_T;
+#endif
+
+#ifdef FEAT_CRYPT
+/*
+ * Structure to hold the type of encryption and the state of encryption or
+ * decryption.
+ */
+typedef struct {
+ int method_nr;
+ void *method_state; /* method-specific state information */
+} cryptstate_T;
+
+/* values for method_nr */
+# define CRYPT_M_ZIP 0
+# define CRYPT_M_BF 1
+# define CRYPT_M_BF2 2
+# define CRYPT_M_COUNT 3 /* number of crypt methods */
+
+// Currently all crypt methods work inplace. If one is added that isn't then
+// define this.
+// # define CRYPT_NOT_INPLACE 1
+#endif
+
+
+/*
+ * These are items normally related to a buffer. But when using ":ownsyntax"
+ * a window may have its own instance.
+ */
+typedef struct {
+#ifdef FEAT_SYN_HL
+ hashtab_T b_keywtab; /* syntax keywords hash table */
+ hashtab_T b_keywtab_ic; /* idem, ignore case */
+ int b_syn_error; /* TRUE when error occurred in HL */
+# ifdef FEAT_RELTIME
+ int b_syn_slow; /* TRUE when 'redrawtime' reached */
+# endif
+ int b_syn_ic; /* ignore case for :syn cmds */
+ int b_syn_spell; /* SYNSPL_ values */
+ garray_T b_syn_patterns; /* table for syntax patterns */
+ garray_T b_syn_clusters; /* table for syntax clusters */
+ int b_spell_cluster_id; /* @Spell cluster ID or 0 */
+ int b_nospell_cluster_id; /* @NoSpell cluster ID or 0 */
+ int b_syn_containedin; /* TRUE when there is an item with a
+ "containedin" argument */
+ int b_syn_sync_flags; /* flags about how to sync */
+ short b_syn_sync_id; /* group to sync on */
+ long b_syn_sync_minlines; /* minimal sync lines offset */
+ long b_syn_sync_maxlines; /* maximal sync lines offset */
+ long b_syn_sync_linebreaks; /* offset for multi-line pattern */
+ char_u *b_syn_linecont_pat; /* line continuation pattern */
+ regprog_T *b_syn_linecont_prog; /* line continuation program */
+#ifdef FEAT_PROFILE
+ syn_time_T b_syn_linecont_time;
+#endif
+ int b_syn_linecont_ic; /* ignore-case flag for above */
+ int b_syn_topgrp; /* for ":syntax include" */
+# ifdef FEAT_CONCEAL
+ int b_syn_conceal; /* auto-conceal for :syn cmds */
+# endif
+# ifdef FEAT_FOLDING
+ int b_syn_folditems; /* number of patterns with the HL_FOLD
+ flag set */
+# endif
+ /*
+ * b_sst_array[] contains the state stack for a number of lines, for the
+ * start of that line (col == 0). This avoids having to recompute the
+ * syntax state too often.
+ * b_sst_array[] is allocated to hold the state for all displayed lines,
+ * and states for 1 out of about 20 other lines.
+ * b_sst_array pointer to an array of synstate_T
+ * b_sst_len number of entries in b_sst_array[]
+ * b_sst_first pointer to first used entry in b_sst_array[] or NULL
+ * b_sst_firstfree pointer to first free entry in b_sst_array[] or NULL
+ * b_sst_freecount number of free entries in b_sst_array[]
+ * b_sst_check_lnum entries after this lnum need to be checked for
+ * validity (MAXLNUM means no check needed)
+ */
+ synstate_T *b_sst_array;
+ int b_sst_len;
+ synstate_T *b_sst_first;
+ synstate_T *b_sst_firstfree;
+ int b_sst_freecount;
+ linenr_T b_sst_check_lnum;
+ short_u b_sst_lasttick; /* last display tick */
+#endif /* FEAT_SYN_HL */
+
+#ifdef FEAT_SPELL
+ /* for spell checking */
+ garray_T b_langp; /* list of pointers to slang_T, see spell.c */
+ char_u b_spell_ismw[256];/* flags: is midword char */
+ char_u *b_spell_ismw_mb; /* multi-byte midword chars */
+ char_u *b_p_spc; /* 'spellcapcheck' */
+ regprog_T *b_cap_prog; /* program for 'spellcapcheck' */
+ char_u *b_p_spf; /* 'spellfile' */
+ char_u *b_p_spl; /* 'spelllang' */
+ int b_cjk; /* all CJK letters as OK */
+#endif
+#if !defined(FEAT_SYN_HL) && !defined(FEAT_SPELL)
+ int dummy;
+#endif
+ char_u b_syn_chartab[32]; /* syntax iskeyword option */
+ char_u *b_syn_isk; /* iskeyword option */
+} synblock_T;
+
+
+/*
+ * buffer: structure that holds information about one file
+ *
+ * Several windows can share a single Buffer
+ * A buffer is unallocated if there is no memfile for it.
+ * A buffer is new if the associated file has never been loaded yet.
+ */
+
+struct file_buffer
+{
+ memline_T b_ml; /* associated memline (also contains line
+ count) */
+
+ buf_T *b_next; /* links in list of buffers */
+ buf_T *b_prev;
+
+ int b_nwindows; /* nr of windows open on this buffer */
+
+ int b_flags; /* various BF_ flags */
+ int b_locked; /* Buffer is being closed or referenced, don't
+ let autocommands wipe it out. */
+
+ /*
+ * b_ffname has the full path of the file (NULL for no name).
+ * b_sfname is the name as the user typed it (or NULL).
+ * b_fname is the same as b_sfname, unless ":cd" has been done,
+ * then it is the same as b_ffname (NULL for no name).
+ */
+ char_u *b_ffname; // full path file name, allocated
+ char_u *b_sfname; // short file name, allocated, may be equal to
+ // b_ffname
+ char_u *b_fname; // current file name, points to b_ffname or
+ // b_sfname
+
+#ifdef UNIX
+ int b_dev_valid; /* TRUE when b_dev has a valid number */
+ 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 */
+ unsigned int b_fab_mrs; /* Max record size */
+#endif
+ int b_fnum; /* buffer number for this file. */
+ char_u b_key[VIM_SIZEOF_INT * 2 + 1];
+ /* key used for buf_hashtab, holds b_fnum as
+ hex string */
+
+ int b_changed; /* 'modified': Set to TRUE if something in the
+ file has been changed and not written out. */
+ dictitem16_T b_ct_di; /* holds the b:changedtick value in
+ b_ct_di.di_tv.vval.v_number;
+ incremented for each change, also for undo */
+#define CHANGEDTICK(buf) ((buf)->b_ct_di.di_tv.vval.v_number)
+
+ varnumber_T b_last_changedtick; /* b:changedtick when TextChanged or
+ TextChangedI was last triggered. */
+#ifdef FEAT_INS_EXPAND
+ varnumber_T b_last_changedtick_pum; /* b:changedtick when TextChangedP was
+ last triggered. */
+#endif
+
+ int b_saving; /* Set to TRUE if we are in the middle of
+ saving the buffer. */
+
+ /*
+ * Changes to a buffer require updating of the display. To minimize the
+ * work, remember changes made and update everything at once.
+ */
+ int b_mod_set; /* TRUE when there are changes since the last
+ time the display was updated */
+ linenr_T b_mod_top; /* topmost lnum that was changed */
+ linenr_T b_mod_bot; /* lnum below last changed line, AFTER the
+ change */
+ long b_mod_xlines; /* number of extra buffer lines inserted;
+ negative when lines were deleted */
+
+ wininfo_T *b_wininfo; /* list of last used info for each window */
+
+ long b_mtime; /* last change time of original file */
+ long b_mtime_read; /* last change time when reading */
+ off_T b_orig_size; /* size of original file in bytes */
+ int b_orig_mode; /* mode of original file */
+#ifdef FEAT_VIMINFO
+ time_T b_last_used; /* time when the buffer was last used; used
+ * for viminfo */
+#endif
+
+ pos_T b_namedm[NMARKS]; /* current named marks (mark.c) */
+
+ /* These variables are set when VIsual_active becomes FALSE */
+ visualinfo_T b_visual;
+#ifdef FEAT_EVAL
+ int b_visual_mode_eval; /* b_visual.vi_mode for visualmode() */
+#endif
+
+ pos_T b_last_cursor; /* cursor position when last unloading this
+ buffer */
+ pos_T b_last_insert; /* where Insert mode was left */
+ pos_T b_last_change; /* position of last change: '. mark */
+
+#ifdef FEAT_JUMPLIST
+ /*
+ * the changelist contains old change positions
+ */
+ pos_T b_changelist[JUMPLISTSIZE];
+ int b_changelistlen; /* number of active entries */
+ int b_new_change; /* set by u_savecommon() */
+#endif
+
+ /*
+ * Character table, only used in charset.c for 'iskeyword'
+ * 32 bytes of 8 bits: 1 bit per character 0-255.
+ */
+ char_u b_chartab[32];
+
+#ifdef FEAT_LOCALMAP
+ /* Table used for mappings local to a buffer. */
+ mapblock_T *(b_maphash[256]);
+
+ /* First abbreviation local to a buffer. */
+ mapblock_T *b_first_abbr;
+#endif
+#ifdef FEAT_USR_CMDS
+ /* User commands local to the buffer. */
+ garray_T b_ucmds;
+#endif
+ /*
+ * start and end of an operator, also used for '[ and ']
+ */
+ pos_T b_op_start;
+ pos_T b_op_start_orig; /* used for Insstart_orig */
+ pos_T b_op_end;
+
+#ifdef FEAT_VIMINFO
+ int b_marks_read; /* Have we read viminfo marks yet? */
+#endif
+
+ /*
+ * The following only used in undo.c.
+ */
+ u_header_T *b_u_oldhead; /* pointer to oldest header */
+ u_header_T *b_u_newhead; /* pointer to newest header; may not be valid
+ if b_u_curhead is not NULL */
+ u_header_T *b_u_curhead; /* pointer to current header */
+ int b_u_numhead; /* current number of headers */
+ int b_u_synced; /* entry lists are synced */
+ long b_u_seq_last; /* last used undo sequence number */
+ long b_u_save_nr_last; /* counter for last file write */
+ long b_u_seq_cur; /* hu_seq of header below which we are now */
+ time_T b_u_time_cur; /* uh_time of header below which we are now */
+ long b_u_save_nr_cur; /* file write nr after which we are now */
+
+ /*
+ * variables for "U" command in undo.c
+ */
+ undoline_T b_u_line_ptr; /* saved line for "U" command */
+ linenr_T b_u_line_lnum; /* line number of line in u_line */
+ colnr_T b_u_line_colnr; /* optional column number */
+
+#ifdef FEAT_INS_EXPAND
+ int b_scanned; /* ^N/^P have scanned this buffer */
+#endif
+
+ /* flags for use of ":lmap" and IM control */
+ long b_p_iminsert; /* input mode for insert */
+ long b_p_imsearch; /* input mode for search */
+#define B_IMODE_USE_INSERT -1 /* Use b_p_iminsert value for search */
+#define B_IMODE_NONE 0 /* Input via none */
+#define B_IMODE_LMAP 1 /* Input via langmap */
+#define B_IMODE_IM 2 /* Input via input method */
+#define B_IMODE_LAST 2
+
+#ifdef FEAT_KEYMAP
+ short b_kmap_state; /* using "lmap" mappings */
+# define KEYMAP_INIT 1 /* 'keymap' was set, call keymap_init() */
+# define KEYMAP_LOADED 2 /* 'keymap' mappings have been loaded */
+ garray_T b_kmap_ga; /* the keymap table */
+#endif
+
+ /*
+ * Options local to a buffer.
+ * They are here because their value depends on the type of file
+ * or contents of the file being edited.
+ */
+ int b_p_initialized; /* set when options initialized */
+
+#ifdef FEAT_EVAL
+ sctx_T b_p_script_ctx[BV_COUNT]; /* SCTXs for buffer-local options */
+#endif
+
+ int b_p_ai; /* 'autoindent' */
+ int b_p_ai_nopaste; /* b_p_ai saved for paste mode */
+ char_u *b_p_bkc; /* 'backupcopy' */
+ unsigned b_bkc_flags; /* flags for 'backupcopy' */
+ int b_p_ci; /* 'copyindent' */
+ int b_p_bin; /* 'binary' */
+ int b_p_bomb; /* 'bomb' */
+ char_u *b_p_bh; /* 'bufhidden' */
+ char_u *b_p_bt; /* 'buftype' */
+#ifdef FEAT_QUICKFIX
+#define BUF_HAS_QF_ENTRY 1
+#define BUF_HAS_LL_ENTRY 2
+ int b_has_qf_entry;
+#endif
+ int b_p_bl; /* 'buflisted' */
+#ifdef FEAT_CINDENT
+ int b_p_cin; /* 'cindent' */
+ char_u *b_p_cino; /* 'cinoptions' */
+ char_u *b_p_cink; /* 'cinkeys' */
+#endif
+#if defined(FEAT_CINDENT) || defined(FEAT_SMARTINDENT)
+ char_u *b_p_cinw; /* 'cinwords' */
+#endif
+#ifdef FEAT_COMMENTS
+ char_u *b_p_com; /* 'comments' */
+#endif
+#ifdef FEAT_FOLDING
+ char_u *b_p_cms; /* 'commentstring' */
+#endif
+#ifdef FEAT_INS_EXPAND
+ char_u *b_p_cpt; /* 'complete' */
+#endif
+#ifdef FEAT_COMPL_FUNC
+ char_u *b_p_cfu; /* 'completefunc' */
+ char_u *b_p_ofu; /* 'omnifunc' */
+#endif
+ int b_p_eol; /* 'endofline' */
+ int b_p_fixeol; /* 'fixendofline' */
+ int b_p_et; /* 'expandtab' */
+ int b_p_et_nobin; /* b_p_et saved for binary mode */
+ int b_p_et_nopaste; /* b_p_et saved for paste mode */
+ char_u *b_p_fenc; /* 'fileencoding' */
+ char_u *b_p_ff; /* 'fileformat' */
+ char_u *b_p_ft; /* 'filetype' */
+ char_u *b_p_fo; /* 'formatoptions' */
+ char_u *b_p_flp; /* 'formatlistpat' */
+ int b_p_inf; /* 'infercase' */
+ char_u *b_p_isk; /* 'iskeyword' */
+#ifdef FEAT_FIND_ID
+ char_u *b_p_def; /* 'define' local value */
+ char_u *b_p_inc; /* 'include' */
+# ifdef FEAT_EVAL
+ char_u *b_p_inex; /* 'includeexpr' */
+ long_u b_p_inex_flags; /* flags for 'includeexpr' */
+# endif
+#endif
+#if defined(FEAT_CINDENT) && defined(FEAT_EVAL)
+ char_u *b_p_inde; /* 'indentexpr' */
+ long_u b_p_inde_flags; /* flags for 'indentexpr' */
+ char_u *b_p_indk; /* 'indentkeys' */
+#endif
+ char_u *b_p_fp; /* 'formatprg' */
+#if defined(FEAT_EVAL)
+ char_u *b_p_fex; /* 'formatexpr' */
+ long_u b_p_fex_flags; /* flags for 'formatexpr' */
+#endif
+#ifdef FEAT_CRYPT
+ char_u *b_p_key; /* 'key' */
+#endif
+ char_u *b_p_kp; /* 'keywordprg' */
+#ifdef FEAT_LISP
+ int b_p_lisp; /* 'lisp' */
+#endif
+ char_u *b_p_menc; /* 'makeencoding' */
+ char_u *b_p_mps; /* 'matchpairs' */
+ int b_p_ml; /* 'modeline' */
+ int b_p_ml_nobin; /* b_p_ml saved for binary mode */
+ int b_p_ma; /* 'modifiable' */
+ char_u *b_p_nf; /* 'nrformats' */
+ int b_p_pi; /* 'preserveindent' */
+#ifdef FEAT_TEXTOBJ
+ char_u *b_p_qe; /* 'quoteescape' */
+#endif
+ int b_p_ro; /* 'readonly' */
+ long b_p_sw; /* 'shiftwidth' */
+ int b_p_sn; /* 'shortname' */
+#ifdef FEAT_SMARTINDENT
+ int b_p_si; /* 'smartindent' */
+#endif
+ long b_p_sts; /* 'softtabstop' */
+ long b_p_sts_nopaste; /* b_p_sts saved for paste mode */
+#ifdef FEAT_SEARCHPATH
+ char_u *b_p_sua; /* 'suffixesadd' */
+#endif
+ int b_p_swf; /* 'swapfile' */
+#ifdef FEAT_SYN_HL
+ long b_p_smc; /* 'synmaxcol' */
+ char_u *b_p_syn; /* 'syntax' */
+#endif
+ long b_p_ts; /* 'tabstop' */
+ int b_p_tx; /* 'textmode' */
+ long b_p_tw; /* 'textwidth' */
+ long b_p_tw_nobin; /* b_p_tw saved for binary mode */
+ long b_p_tw_nopaste; /* b_p_tw saved for paste mode */
+ long b_p_wm; /* 'wrapmargin' */
+ long b_p_wm_nobin; /* b_p_wm saved for binary mode */
+ long b_p_wm_nopaste; /* b_p_wm saved for paste mode */
+#ifdef FEAT_VARTABS
+ char_u *b_p_vsts; /* 'varsofttabstop' */
+ int *b_p_vsts_array; /* 'varsofttabstop' in internal format */
+ char_u *b_p_vsts_nopaste; /* b_p_vsts saved for paste mode */
+ char_u *b_p_vts; /* 'vartabstop' */
+ int *b_p_vts_array; /* 'vartabstop' in internal format */
+#endif
+#ifdef FEAT_KEYMAP
+ char_u *b_p_keymap; /* 'keymap' */
+#endif
+
+ /* local values for options which are normally global */
+#ifdef FEAT_QUICKFIX
+ char_u *b_p_gp; /* 'grepprg' local value */
+ char_u *b_p_mp; /* 'makeprg' local value */
+ char_u *b_p_efm; /* 'errorformat' local value */
+#endif
+ char_u *b_p_ep; /* 'equalprg' local value */
+ char_u *b_p_path; /* 'path' local value */
+ int b_p_ar; /* 'autoread' local value */
+ char_u *b_p_tags; /* 'tags' local value */
+ char_u *b_p_tc; /* 'tagcase' local value */
+ unsigned b_tc_flags; /* flags for 'tagcase' */
+#ifdef FEAT_INS_EXPAND
+ char_u *b_p_dict; /* 'dictionary' local value */
+ char_u *b_p_tsr; /* 'thesaurus' local value */
+#endif
+ long b_p_ul; /* 'undolevels' local value */
+#ifdef FEAT_PERSISTENT_UNDO
+ int b_p_udf; /* 'undofile' */
+#endif
+#ifdef FEAT_LISP
+ char_u *b_p_lw; /* 'lispwords' local value */
+#endif
+#ifdef FEAT_TERMINAL
+ long b_p_twsl; /* 'termwinscroll' */
+#endif
+
+ /* end of buffer options */
+
+#ifdef FEAT_CINDENT
+ /* values set from b_p_cino */
+ int b_ind_level;
+ int b_ind_open_imag;
+ int b_ind_no_brace;
+ int b_ind_first_open;
+ int b_ind_open_extra;
+ int b_ind_close_extra;
+ int b_ind_open_left_imag;
+ int b_ind_jump_label;
+ int b_ind_case;
+ int b_ind_case_code;
+ int b_ind_case_break;
+ int b_ind_param;
+ int b_ind_func_type;
+ int b_ind_comment;
+ int b_ind_in_comment;
+ int b_ind_in_comment2;
+ int b_ind_cpp_baseclass;
+ int b_ind_continuation;
+ int b_ind_unclosed;
+ int b_ind_unclosed2;
+ int b_ind_unclosed_noignore;
+ int b_ind_unclosed_wrapped;
+ int b_ind_unclosed_whiteok;
+ int b_ind_matching_paren;
+ int b_ind_paren_prev;
+ int b_ind_maxparen;
+ int b_ind_maxcomment;
+ int b_ind_scopedecl;
+ int b_ind_scopedecl_code;
+ int b_ind_java;
+ int b_ind_js;
+ int b_ind_keep_case_label;
+ int b_ind_hash_comment;
+ int b_ind_cpp_namespace;
+ int b_ind_if_for_while;
+ int b_ind_cpp_extern_c;
+#endif
+
+ linenr_T b_no_eol_lnum; /* non-zero lnum when last line of next binary
+ * write should not have an end-of-line */
+
+ int b_start_eol; /* last line had eol when it was read */
+ int b_start_ffc; /* first char of 'ff' when edit started */
+ char_u *b_start_fenc; /* 'fileencoding' when edit started or NULL */
+ int b_bad_char; /* "++bad=" argument when edit started or 0 */
+ int b_start_bomb; /* 'bomb' when it was read */
+
+#ifdef FEAT_EVAL
+ dictitem_T b_bufvar; /* variable for "b:" Dictionary */
+ dict_T *b_vars; /* internal variables, local to buffer */
+#endif
+#ifdef FEAT_TEXT_PROP
+ int b_has_textprop; // TRUE when text props were added
+ hashtab_T *b_proptypes; // text property types local to buffer
+#endif
+
+#if defined(FEAT_BEVAL) && defined(FEAT_EVAL)
+ char_u *b_p_bexpr; /* 'balloonexpr' local value */
+ long_u b_p_bexpr_flags;/* flags for 'balloonexpr' */
+#endif
+#ifdef FEAT_CRYPT
+ char_u *b_p_cm; /* 'cryptmethod' */
+#endif
+
+ /* When a buffer is created, it starts without a swap file. b_may_swap is
+ * then set to indicate that a swap file may be opened later. It is reset
+ * if a swap file could not be opened.
+ */
+ int b_may_swap;
+ int b_did_warn; /* Set to 1 if user has been warned on first
+ change of a read-only file */
+
+ /* Two special kinds of buffers:
+ * help buffer - used for help files, won't use a swap file.
+ * spell buffer - used for spell info, never displayed and doesn't have a
+ * file name.
+ */
+ int b_help; /* TRUE for help file buffer (when set b_p_bt
+ is "help") */
+#ifdef FEAT_SPELL
+ int b_spell; /* TRUE for a spell file buffer, most fields
+ are not used! Use the B_SPELL macro to
+ access b_spell without #ifdef. */
+#endif
+
+ int b_shortname; /* this file has an 8.3 file name */
+
+#ifdef FEAT_JOB_CHANNEL
+ char_u *b_prompt_text; // set by prompt_setprompt()
+ char_u *b_prompt_callback; // set by prompt_setcallback()
+ partial_T *b_prompt_partial; // set by prompt_setcallback()
+ char_u *b_prompt_interrupt; // set by prompt_setinterrupt()
+ partial_T *b_prompt_int_partial; // set by prompt_setinterrupt()
+ int b_prompt_insert; // value for restart_edit when entering
+ // a prompt buffer window.
+#endif
+#ifdef FEAT_MZSCHEME
+ void *b_mzscheme_ref; /* The MzScheme reference to this buffer */
+#endif
+
+#ifdef FEAT_PERL
+ void *b_perl_private;
+#endif
+
+#ifdef FEAT_PYTHON
+ void *b_python_ref; /* The Python reference to this buffer */
+#endif
+
+#ifdef FEAT_PYTHON3
+ void *b_python3_ref; /* The Python3 reference to this buffer */
+#endif
+
+#ifdef FEAT_TCL
+ void *b_tcl_ref;
+#endif
+
+#ifdef FEAT_RUBY
+ void *b_ruby_ref;
+#endif
+
+#if defined(FEAT_SYN_HL) || defined(FEAT_SPELL)
+ synblock_T b_s; /* Info related to syntax highlighting. w_s
+ * normally points to this, but some windows
+ * may use a different synblock_T. */
+#endif
+
+#ifdef FEAT_SIGNS
+ signlist_T *b_signlist; /* list of signs to draw */
+# ifdef FEAT_NETBEANS_INTG
+ int b_has_sign_column; /* Flag that is set when a first sign is
+ * added and remains set until the end of
+ * the netbeans session. */
+# endif
+#endif
+
+#ifdef FEAT_NETBEANS_INTG
+ int b_netbeans_file; /* TRUE when buffer is owned by NetBeans */
+ int b_was_netbeans_file;/* TRUE if b_netbeans_file was once set */
+#endif
+#ifdef FEAT_JOB_CHANNEL
+ int b_write_to_channel; /* TRUE when appended lines are written to
+ * a channel. */
+#endif
+
+#ifdef FEAT_CRYPT
+ cryptstate_T *b_cryptstate; /* Encryption state while reading or writing
+ * the file. NULL when not using encryption. */
+#endif
+ int b_mapped_ctrl_c; /* modes where CTRL-C is mapped */
+
+#ifdef FEAT_TERMINAL
+ term_T *b_term; /* When not NULL this buffer is for a terminal
+ * window. */
+#endif
+#ifdef FEAT_DIFF
+ int b_diff_failed; // internal diff failed for this buffer
+#endif
+}; /* file_buffer */
+
+
+#ifdef FEAT_DIFF
+/*
+ * Stuff for diff mode.
+ */
+# define DB_COUNT 8 /* up to eight buffers can be diff'ed */
+
+/*
+ * Each diffblock defines where a block of lines starts in each of the buffers
+ * and how many lines it occupies in that buffer. When the lines are missing
+ * in the buffer the df_count[] is zero. This is all counted in
+ * buffer lines.
+ * There is always at least one unchanged line in between the diffs.
+ * Otherwise it would have been included in the diff above or below it.
+ * df_lnum[] + df_count[] is the lnum below the change. When in one buffer
+ * lines have been inserted, in the other buffer df_lnum[] is the line below
+ * the insertion and df_count[] is zero. When appending lines at the end of
+ * the buffer, df_lnum[] is one beyond the end!
+ * This is using a linked list, because the number of differences is expected
+ * to be reasonable small. The list is sorted on lnum.
+ */
+typedef struct diffblock_S diff_T;
+struct diffblock_S
+{
+ diff_T *df_next;
+ linenr_T df_lnum[DB_COUNT]; /* line number in buffer */
+ linenr_T df_count[DB_COUNT]; /* nr of inserted/changed lines */
+};
+#endif
+
+#define SNAP_HELP_IDX 0
+#define SNAP_AUCMD_IDX 1
+#define SNAP_COUNT 2
+
+/*
+ * Tab pages point to the top frame of each tab page.
+ * Note: Most values are NOT valid for the current tab page! Use "curwin",
+ * "firstwin", etc. for that. "tp_topframe" is always valid and can be
+ * compared against "topframe" to find the current tab page.
+ */
+typedef struct tabpage_S tabpage_T;
+struct tabpage_S
+{
+ tabpage_T *tp_next; /* next tabpage or NULL */
+ frame_T *tp_topframe; /* topframe for the windows */
+ win_T *tp_curwin; /* current window in this Tab page */
+ win_T *tp_prevwin; /* previous window in this Tab page */
+ win_T *tp_firstwin; /* first window in this Tab page */
+ win_T *tp_lastwin; /* last window in this Tab page */
+ long tp_old_Rows; /* Rows when Tab page was left */
+ long tp_old_Columns; /* Columns when Tab page was left */
+ long tp_ch_used; /* value of 'cmdheight' when frame size
+ was set */
+#ifdef FEAT_GUI
+ int tp_prev_which_scrollbars[3];
+ /* previous value of which_scrollbars */
+#endif
+#ifdef FEAT_DIFF
+ diff_T *tp_first_diff;
+ buf_T *(tp_diffbuf[DB_COUNT]);
+ int tp_diff_invalid; // list of diffs is outdated
+ int tp_diff_update; // update diffs before redrawing
+#endif
+ frame_T *(tp_snapshot[SNAP_COUNT]); /* window layout snapshots */
+#ifdef FEAT_EVAL
+ dictitem_T tp_winvar; /* variable for "t:" Dictionary */
+ dict_T *tp_vars; /* internal variables, local to tab page */
+#endif
+
+#ifdef FEAT_PYTHON
+ void *tp_python_ref; /* The Python value for this tab page */
+#endif
+
+#ifdef FEAT_PYTHON3
+ void *tp_python3_ref; /* The Python value for this tab page */
+#endif
+};
+
+/*
+ * Structure to cache info for displayed lines in w_lines[].
+ * Each logical line has one entry.
+ * The entry tells how the logical line is currently displayed in the window.
+ * This is updated when displaying the window.
+ * When the display is changed (e.g., when clearing the screen) w_lines_valid
+ * is changed to exclude invalid entries.
+ * When making changes to the buffer, wl_valid is reset to indicate wl_size
+ * may not reflect what is actually in the buffer. When wl_valid is FALSE,
+ * the entries can only be used to count the number of displayed lines used.
+ * wl_lnum and wl_lastlnum are invalid too.
+ */
+typedef struct w_line
+{
+ linenr_T wl_lnum; /* buffer line number for logical line */
+ short_u wl_size; /* height in screen lines */
+ char wl_valid; /* TRUE values are valid for text in buffer */
+#ifdef FEAT_FOLDING
+ char wl_folded; /* TRUE when this is a range of folded lines */
+ linenr_T wl_lastlnum; /* last buffer line number for logical line */
+#endif
+} wline_T;
+
+/*
+ * Windows are kept in a tree of frames. Each frame has a column (FR_COL)
+ * or row (FR_ROW) layout or is a leaf, which has a window.
+ */
+struct frame_S
+{
+ char fr_layout; /* FR_LEAF, FR_COL or FR_ROW */
+ int fr_width;
+ int fr_newwidth; /* new width used in win_equal_rec() */
+ int fr_height;
+ int fr_newheight; /* new height used in win_equal_rec() */
+ frame_T *fr_parent; /* containing frame or NULL */
+ frame_T *fr_next; /* frame right or below in same parent, NULL
+ for first */
+ frame_T *fr_prev; /* frame left or above in same parent, NULL
+ for last */
+ /* fr_child and fr_win are mutually exclusive */
+ frame_T *fr_child; /* first contained frame */
+ win_T *fr_win; /* window that fills this frame */
+};
+
+#define FR_LEAF 0 /* frame is a leaf */
+#define FR_ROW 1 /* frame with a row of windows */
+#define FR_COL 2 /* frame with a column of windows */
+
+/*
+ * Struct used for highlighting 'hlsearch' matches, matches defined by
+ * ":match" and matches defined by match functions.
+ * For 'hlsearch' there is one pattern for all windows. For ":match" and the
+ * match functions there is a different pattern for each window.
+ */
+typedef struct
+{
+ regmmatch_T rm; /* points to the regexp program; contains last found
+ match (may continue in next line) */
+ buf_T *buf; /* the buffer to search for a match */
+ linenr_T lnum; /* the line to search for a match */
+ int attr; /* attributes to be used for a match */
+ int attr_cur; /* attributes currently active in win_line() */
+ linenr_T first_lnum; /* first lnum to search for multi-line pat */
+ colnr_T startcol; /* in win_line() points to char where HL starts */
+ colnr_T endcol; /* in win_line() points to char where HL ends */
+ int is_addpos; /* position specified directly by
+ matchaddpos(). TRUE/FALSE */
+#ifdef FEAT_RELTIME
+ proftime_T tm; /* for a time limit */
+#endif
+} match_T;
+
+/* number of positions supported by matchaddpos() */
+#define MAXPOSMATCH 8
+
+/*
+ * Same as lpos_T, but with additional field len.
+ */
+typedef struct
+{
+ linenr_T lnum; /* line number */
+ colnr_T col; /* column number */
+ int len; /* length: 0 - to the end of line */
+} llpos_T;
+
+/*
+ * posmatch_T provides an array for storing match items for matchaddpos()
+ * function.
+ */
+typedef struct posmatch posmatch_T;
+struct posmatch
+{
+ llpos_T pos[MAXPOSMATCH]; /* array of positions */
+ int cur; /* internal position counter */
+ linenr_T toplnum; /* top buffer line */
+ linenr_T botlnum; /* bottom buffer line */
+};
+
+/*
+ * matchitem_T provides a linked list for storing match items for ":match" and
+ * the match functions.
+ */
+typedef struct matchitem matchitem_T;
+struct matchitem
+{
+ matchitem_T *next;
+ int id; /* match ID */
+ int priority; /* match priority */
+ char_u *pattern; /* pattern to highlight */
+ int hlg_id; /* highlight group ID */
+ regmmatch_T match; /* regexp program for pattern */
+ posmatch_T pos; /* position matches */
+ match_T hl; /* struct for doing the actual highlighting */
+#ifdef FEAT_CONCEAL
+ int conceal_char; /* cchar for Conceal highlighting */
+#endif
+};
+
+#ifdef FEAT_MENU
+typedef struct {
+ int wb_startcol;
+ int wb_endcol;
+ vimmenu_T *wb_menu;
+} winbar_item_T;
+#endif
+
+/*
+ * Structure which contains all information that belongs to a window
+ *
+ * All row numbers are relative to the start of the window, except w_winrow.
+ */
+struct window_S
+{
+ int w_id; /* unique window ID */
+
+ buf_T *w_buffer; /* buffer we are a window into (used
+ often, keep it the first item!) */
+
+#if defined(FEAT_SYN_HL) || defined(FEAT_SPELL)
+ synblock_T *w_s; /* for :ownsyntax */
+#endif
+
+ win_T *w_prev; /* link to previous window */
+ win_T *w_next; /* link to next window */
+ int w_closing; /* window is being closed, don't let
+ autocommands close it too. */
+
+ frame_T *w_frame; /* frame containing this window */
+
+ pos_T w_cursor; /* cursor position in buffer */
+
+ colnr_T w_curswant; /* The column we'd like to be at. This is
+ used to try to stay in the same column
+ for up/down cursor motions. */
+
+ int w_set_curswant; /* If set, then update w_curswant the next
+ time through cursupdate() to the
+ current virtual column */
+
+#ifdef FEAT_SYN_HL
+ linenr_T w_last_cursorline; // where last time 'cursorline' was drawn
+#endif
+
+ /*
+ * the next seven are used to update the visual part
+ */
+ char w_old_visual_mode; /* last known VIsual_mode */
+ linenr_T w_old_cursor_lnum; /* last known end of visual part */
+ colnr_T w_old_cursor_fcol; /* first column for block visual part */
+ colnr_T w_old_cursor_lcol; /* last column for block visual part */
+ linenr_T w_old_visual_lnum; /* last known start of visual part */
+ colnr_T w_old_visual_col; /* last known start of visual part */
+ colnr_T w_old_curswant; /* last known value of Curswant */
+
+ /*
+ * "w_topline", "w_leftcol" and "w_skipcol" specify the offsets for
+ * displaying the buffer.
+ */
+ linenr_T w_topline; /* buffer line number of the line at the
+ top of the window */
+ char w_topline_was_set; /* flag set to TRUE when topline is set,
+ e.g. by winrestview() */
+#ifdef FEAT_DIFF
+ int w_topfill; /* number of filler lines above w_topline */
+ int w_old_topfill; /* w_topfill at last redraw */
+ int w_botfill; /* TRUE when filler lines are actually
+ below w_topline (at end of file) */
+ int w_old_botfill; /* w_botfill at last redraw */
+#endif
+ colnr_T w_leftcol; /* window column number of the left most
+ character in the window; used when
+ 'wrap' is off */
+ colnr_T w_skipcol; /* starting column when a single line
+ doesn't fit in the window */
+
+ /*
+ * Layout of the window in the screen.
+ * May need to add "msg_scrolled" to "w_winrow" in rare situations.
+ */
+ int w_winrow; /* first row of window in screen */
+ int w_height; /* number of rows in window, excluding
+ status/command/winbar line(s) */
+ int w_status_height; /* number of status lines (0 or 1) */
+ int w_wincol; /* Leftmost column of window in screen. */
+ int w_width; /* Width of window, excluding separation. */
+ int w_vsep_width; /* Number of separator columns (0 or 1). */
+
+ /*
+ * === start of cached values ====
+ */
+ /*
+ * Recomputing is minimized by storing the result of computations.
+ * Use functions in screen.c to check if they are valid and to update.
+ * w_valid is a bitfield of flags, which indicate if specific values are
+ * valid or need to be recomputed. See screen.c for values.
+ */
+ int w_valid;
+ pos_T w_valid_cursor; /* last known position of w_cursor, used
+ to adjust w_valid */
+ colnr_T w_valid_leftcol; /* last known w_leftcol */
+
+ /*
+ * w_cline_height is the number of physical lines taken by the buffer line
+ * that the cursor is on. We use this to avoid extra calls to plines().
+ */
+ int w_cline_height; /* current size of cursor line */
+#ifdef FEAT_FOLDING
+ int w_cline_folded; /* cursor line is folded */
+#endif
+
+ int w_cline_row; /* starting row of the cursor line */
+
+ colnr_T w_virtcol; /* column number of the cursor in the
+ buffer line, as opposed to the column
+ number we're at on the screen. This
+ makes a difference on lines which span
+ more than one screen line or when
+ w_leftcol is non-zero */
+
+ /*
+ * w_wrow and w_wcol specify the cursor position in the window.
+ * This is related to positions in the window, not in the display or
+ * buffer, thus w_wrow is relative to w_winrow.
+ */
+ int w_wrow, w_wcol; /* cursor position in window */
+
+ linenr_T w_botline; /* number of the line below the bottom of
+ the window */
+ int w_empty_rows; /* number of ~ rows in window */
+#ifdef FEAT_DIFF
+ int w_filler_rows; /* number of filler rows at the end of the
+ window */
+#endif
+
+ /*
+ * Info about the lines currently in the window is remembered to avoid
+ * recomputing it every time. The allocated size of w_lines[] is Rows.
+ * Only the w_lines_valid entries are actually valid.
+ * When the display is up-to-date w_lines[0].wl_lnum is equal to w_topline
+ * and w_lines[w_lines_valid - 1].wl_lnum is equal to w_botline.
+ * Between changing text and updating the display w_lines[] represents
+ * what is currently displayed. wl_valid is reset to indicated this.
+ * This is used for efficient redrawing.
+ */
+ int w_lines_valid; /* number of valid entries */
+ wline_T *w_lines;
+
+#ifdef FEAT_FOLDING
+ garray_T w_folds; /* array of nested folds */
+ char w_fold_manual; /* when TRUE: some folds are opened/closed
+ manually */
+ char w_foldinvalid; /* when TRUE: folding needs to be
+ recomputed */
+#endif
+#ifdef FEAT_LINEBREAK
+ int w_nrwidth; /* width of 'number' and 'relativenumber'
+ column being used */
+#endif
+
+ /*
+ * === end of cached values ===
+ */
+
+ int w_redr_type; /* type of redraw to be performed on win */
+ int w_upd_rows; /* number of window lines to update when
+ w_redr_type is REDRAW_TOP */
+ linenr_T w_redraw_top; /* when != 0: first line needing redraw */
+ linenr_T w_redraw_bot; /* when != 0: last line needing redraw */
+ int w_redr_status; /* if TRUE status line must be redrawn */
+
+#ifdef FEAT_CMDL_INFO
+ /* remember what is shown in the ruler for this window (if 'ruler' set) */
+ pos_T w_ru_cursor; /* cursor position shown in ruler */
+ colnr_T w_ru_virtcol; /* virtcol shown in ruler */
+ linenr_T w_ru_topline; /* topline shown in ruler */
+ linenr_T w_ru_line_count; /* line count used for ruler */
+# ifdef FEAT_DIFF
+ int w_ru_topfill; /* topfill shown in ruler */
+# endif
+ char w_ru_empty; /* TRUE if ruler shows 0-1 (empty line) */
+#endif
+
+ int w_alt_fnum; /* alternate file (for # and CTRL-^) */
+
+ alist_T *w_alist; /* pointer to arglist for this window */
+ int w_arg_idx; /* current index in argument list (can be
+ out of range!) */
+ int w_arg_idx_invalid; /* editing another file than w_arg_idx */
+
+ char_u *w_localdir; /* absolute path of local directory or
+ NULL */
+#ifdef FEAT_MENU
+ vimmenu_T *w_winbar; /* The root of the WinBar menu hierarchy. */
+ winbar_item_T *w_winbar_items; /* list of items in the WinBar */
+ int w_winbar_height; /* 1 if there is a window toolbar */
+#endif
+
+ /*
+ * Options local to a window.
+ * They are local because they influence the layout of the window or
+ * depend on the window layout.
+ * There are two values: w_onebuf_opt is local to the buffer currently in
+ * this window, w_allbuf_opt is for all buffers in this window.
+ */
+ winopt_T w_onebuf_opt;
+ winopt_T w_allbuf_opt;
+
+ /* A few options have local flags for P_INSECURE. */
+#ifdef FEAT_STL_OPT
+ long_u w_p_stl_flags; /* flags for 'statusline' */
+#endif
+#ifdef FEAT_EVAL
+ long_u w_p_fde_flags; /* flags for 'foldexpr' */
+ long_u w_p_fdt_flags; /* flags for 'foldtext' */
+#endif
+#ifdef FEAT_SYN_HL
+ int *w_p_cc_cols; /* array of columns to highlight or NULL */
+#endif
+#ifdef FEAT_LINEBREAK
+ int w_p_brimin; /* minimum width for breakindent */
+ int w_p_brishift; /* additional shift for breakindent */
+ int w_p_brisbr; /* sbr in 'briopt' */
+#endif
+ long w_p_siso; /* 'sidescrolloff' local value */
+ long w_p_so; /* 'scrolloff' local value */
+
+ /* transform a pointer to a "onebuf" option into a "allbuf" option */
+#define GLOBAL_WO(p) ((char *)p + sizeof(winopt_T))
+
+ long w_scbind_pos;
+
+#ifdef FEAT_EVAL
+ dictitem_T w_winvar; /* variable for "w:" Dictionary */
+ dict_T *w_vars; /* internal variables, local to window */
+#endif
+
+#if defined(FEAT_RIGHTLEFT) && defined(FEAT_FKMAP)
+ int w_farsi; /* for the window dependent Farsi functions */
+#endif
+
+ /*
+ * The w_prev_pcmark field is used to check whether we really did jump to
+ * a new line after setting the w_pcmark. If not, then we revert to
+ * using the previous w_pcmark.
+ */
+ pos_T w_pcmark; /* previous context mark */
+ pos_T w_prev_pcmark; /* previous w_pcmark */
+
+#ifdef FEAT_JUMPLIST
+ /*
+ * the jumplist contains old cursor positions
+ */
+ xfmark_T w_jumplist[JUMPLISTSIZE];
+ int w_jumplistlen; /* number of active entries */
+ int w_jumplistidx; /* current position */
+
+ int w_changelistidx; /* current position in b_changelist */
+#endif
+
+#ifdef FEAT_SEARCH_EXTRA
+ matchitem_T *w_match_head; /* head of match list */
+ int w_next_match_id; /* next match ID */
+#endif
+
+ /*
+ * the tagstack grows from 0 upwards:
+ * entry 0: older
+ * entry 1: newer
+ * entry 2: newest
+ */
+ taggy_T w_tagstack[TAGSTACKSIZE]; /* the tag stack */
+ int w_tagstackidx; /* idx just below active entry */
+ int w_tagstacklen; /* number of tags on stack */
+
+ /*
+ * w_fraction is the fractional row of the cursor within the window, from
+ * 0 at the top row to FRACTION_MULT at the last row.
+ * w_prev_fraction_row was the actual cursor row when w_fraction was last
+ * calculated.
+ */
+ int w_fraction;
+ int w_prev_fraction_row;
+
+#ifdef FEAT_GUI
+ scrollbar_T w_scrollbars[2]; /* vert. Scrollbars for this window */
+#endif
+#ifdef FEAT_LINEBREAK
+ linenr_T w_nrwidth_line_count; /* line count when ml_nrwidth_width
+ * was computed. */
+ long w_nuw_cached; /* 'numberwidth' option cached */
+ int w_nrwidth_width; /* nr of chars to print line count. */
+#endif
+
+#ifdef FEAT_QUICKFIX
+ qf_info_T *w_llist; /* Location list for this window */
+ /*
+ * Location list reference used in the location list window.
+ * In a non-location list window, w_llist_ref is NULL.
+ */
+ qf_info_T *w_llist_ref;
+#endif
+
+
+#ifdef FEAT_MZSCHEME
+ void *w_mzscheme_ref; /* The MzScheme value for this window */
+#endif
+
+#ifdef FEAT_PERL
+ void *w_perl_private;
+#endif
+
+#ifdef FEAT_PYTHON
+ void *w_python_ref; /* The Python value for this window */
+#endif
+
+#ifdef FEAT_PYTHON3
+ void *w_python3_ref; /* The Python value for this window */
+#endif
+
+#ifdef FEAT_TCL
+ void *w_tcl_ref;
+#endif
+
+#ifdef FEAT_RUBY
+ void *w_ruby_ref;
+#endif
+};
+
+/*
+ * Arguments for operators.
+ */
+typedef struct oparg_S
+{
+ int op_type; /* current pending operator type */
+ int regname; /* register to use for the operator */
+ int motion_type; /* type of the current cursor motion */
+ int motion_force; /* force motion type: 'v', 'V' or CTRL-V */
+ int use_reg_one; /* TRUE if delete uses reg 1 even when not
+ linewise */
+ int inclusive; /* TRUE if char motion is inclusive (only
+ valid when motion_type is MCHAR */
+ int end_adjusted; /* backuped b_op_end one char (only used by
+ do_format()) */
+ pos_T start; /* start of the operator */
+ pos_T end; /* end of the operator */
+ pos_T cursor_start; /* cursor position before motion for "gw" */
+
+ long line_count; /* number of lines from op_start to op_end
+ (inclusive) */
+ int empty; /* op_start and op_end the same (only used by
+ do_change()) */
+ int is_VIsual; /* operator on Visual area */
+ int block_mode; /* current operator is Visual block mode */
+ colnr_T start_vcol; /* start col for block mode operator */
+ colnr_T end_vcol; /* end col for block mode operator */
+ long prev_opcount; /* ca.opcount saved for K_CURSORHOLD */
+ long prev_count0; /* ca.count0 saved for K_CURSORHOLD */
+} oparg_T;
+
+/*
+ * Arguments for Normal mode commands.
+ */
+typedef struct cmdarg_S
+{
+ oparg_T *oap; /* Operator arguments */
+ int prechar; /* prefix character (optional, always 'g') */
+ int cmdchar; /* command character */
+ int nchar; /* next command character (optional) */
+ int ncharC1; /* first composing character (optional) */
+ int ncharC2; /* second composing character (optional) */
+ int extra_char; /* yet another character (optional) */
+ long opcount; /* count before an operator */
+ long count0; /* count before command, default 0 */
+ long count1; /* count before command, default 1 */
+ int arg; /* extra argument from nv_cmds[] */
+ int retval; /* return: CA_* values */
+ char_u *searchbuf; /* return: pointer to search pattern or NULL */
+} cmdarg_T;
+
+/* values for retval: */
+#define CA_COMMAND_BUSY 1 /* skip restarting edit() once */
+#define CA_NO_ADJ_OP_END 2 /* don't adjust operator end */
+
+#ifdef CURSOR_SHAPE
+/*
+ * struct to store values from 'guicursor' and 'mouseshape'
+ */
+/* Indexes in shape_table[] */
+#define SHAPE_IDX_N 0 /* Normal mode */
+#define SHAPE_IDX_V 1 /* Visual mode */
+#define SHAPE_IDX_I 2 /* Insert mode */
+#define SHAPE_IDX_R 3 /* Replace mode */
+#define SHAPE_IDX_C 4 /* Command line Normal mode */
+#define SHAPE_IDX_CI 5 /* Command line Insert mode */
+#define SHAPE_IDX_CR 6 /* Command line Replace mode */
+#define SHAPE_IDX_O 7 /* Operator-pending mode */
+#define SHAPE_IDX_VE 8 /* Visual mode with 'selection' exclusive */
+#define SHAPE_IDX_CLINE 9 /* On command line */
+#define SHAPE_IDX_STATUS 10 /* A status line */
+#define SHAPE_IDX_SDRAG 11 /* dragging a status line */
+#define SHAPE_IDX_VSEP 12 /* A vertical separator line */
+#define SHAPE_IDX_VDRAG 13 /* dragging a vertical separator line */
+#define SHAPE_IDX_MORE 14 /* Hit-return or More */
+#define SHAPE_IDX_MOREL 15 /* Hit-return or More in last line */
+#define SHAPE_IDX_SM 16 /* showing matching paren */
+#define SHAPE_IDX_COUNT 17
+
+#define SHAPE_BLOCK 0 /* block cursor */
+#define SHAPE_HOR 1 /* horizontal bar cursor */
+#define SHAPE_VER 2 /* vertical bar cursor */
+
+#define MSHAPE_NUMBERED 1000 /* offset for shapes identified by number */
+#define MSHAPE_HIDE 1 /* hide mouse pointer */
+
+#define SHAPE_MOUSE 1 /* used for mouse pointer shape */
+#define SHAPE_CURSOR 2 /* used for text cursor shape */
+
+typedef struct cursor_entry
+{
+ int shape; /* one of the SHAPE_ defines */
+ int mshape; /* one of the MSHAPE defines */
+ int percentage; /* percentage of cell for bar */
+ long blinkwait; /* blinking, wait time before blinking starts */
+ long blinkon; /* blinking, on time */
+ long blinkoff; /* blinking, off time */
+ int id; /* highlight group ID */
+ int id_lm; /* highlight group ID for :lmap mode */
+ char *name; /* mode name (fixed) */
+ char used_for; /* SHAPE_MOUSE and/or SHAPE_CURSOR */
+} cursorentry_T;
+#endif /* CURSOR_SHAPE */
+
+#ifdef FEAT_MENU
+
+/* Indices into vimmenu_T->strings[] and vimmenu_T->noremap[] for each mode */
+#define MENU_INDEX_INVALID -1
+#define MENU_INDEX_NORMAL 0
+#define MENU_INDEX_VISUAL 1
+#define MENU_INDEX_SELECT 2
+#define MENU_INDEX_OP_PENDING 3
+#define MENU_INDEX_INSERT 4
+#define MENU_INDEX_CMDLINE 5
+#define MENU_INDEX_TERMINAL 6
+#define MENU_INDEX_TIP 7
+#define MENU_MODES 8
+
+/* Menu modes */
+#define MENU_NORMAL_MODE (1 << MENU_INDEX_NORMAL)
+#define MENU_VISUAL_MODE (1 << MENU_INDEX_VISUAL)
+#define MENU_SELECT_MODE (1 << MENU_INDEX_SELECT)
+#define MENU_OP_PENDING_MODE (1 << MENU_INDEX_OP_PENDING)
+#define MENU_INSERT_MODE (1 << MENU_INDEX_INSERT)
+#define MENU_CMDLINE_MODE (1 << MENU_INDEX_CMDLINE)
+#define MENU_TERMINAL_MODE (1 << MENU_INDEX_TERMINAL)
+#define MENU_TIP_MODE (1 << MENU_INDEX_TIP)
+#define MENU_ALL_MODES ((1 << MENU_INDEX_TIP) - 1)
+/*note MENU_INDEX_TIP is not a 'real' mode*/
+
+/* Start a menu name with this to not include it on the main menu bar */
+#define MNU_HIDDEN_CHAR ']'
+
+struct VimMenu
+{
+ int modes; /* Which modes is this menu visible for? */
+ int enabled; /* for which modes the menu is enabled */
+ char_u *name; /* Name of menu, possibly translated */
+ char_u *dname; /* Displayed Name ("name" without '&') */
+#ifdef FEAT_MULTI_LANG
+ char_u *en_name; /* "name" untranslated, NULL when "name"
+ * was not translated */
+ char_u *en_dname; /* "dname" untranslated, NULL when "dname"
+ * was not translated */
+#endif
+ int mnemonic; /* mnemonic key (after '&') */
+ char_u *actext; /* accelerator text (after TAB) */
+ int priority; /* Menu order priority */
+#ifdef FEAT_GUI
+ void (*cb)(vimmenu_T *); /* Call-back routine */
+#endif
+#ifdef FEAT_TOOLBAR
+ char_u *iconfile; /* name of file for icon or NULL */
+ int iconidx; /* icon index (-1 if not set) */
+ int icon_builtin; /* icon names is BuiltIn{nr} */
+#endif
+ char_u *strings[MENU_MODES]; /* Mapped string for each mode */
+ int noremap[MENU_MODES]; /* A REMAP_ flag for each mode */
+ char silent[MENU_MODES]; /* A silent flag for each mode */
+ vimmenu_T *children; /* Children of sub-menu */
+ vimmenu_T *parent; /* Parent of menu */
+ vimmenu_T *next; /* Next item in menu */
+#ifdef FEAT_GUI_X11
+ Widget id; /* Manage this to enable item */
+ Widget submenu_id; /* If this is submenu, add children here */
+#endif
+#ifdef FEAT_GUI_GTK
+ GtkWidget *id; /* Manage this to enable item */
+ GtkWidget *submenu_id; /* If this is submenu, add children here */
+# if defined(GTK_CHECK_VERSION) && !GTK_CHECK_VERSION(3,4,0)
+ GtkWidget *tearoff_handle;
+# endif
+ GtkWidget *label; /* Used by "set wak=" code. */
+#endif
+#ifdef FEAT_GUI_MOTIF
+ int sensitive; /* turn button on/off */
+ char **xpm; /* pixmap data */
+ char *xpm_fname; /* file with pixmap data */
+#endif
+#ifdef FEAT_GUI_ATHENA
+ Pixmap image; /* Toolbar image */
+#endif
+#ifdef FEAT_BEVAL_TIP
+ BalloonEval *tip; /* tooltip for this menu item */
+#endif
+#ifdef FEAT_GUI_W32
+ UINT id; /* Id of menu item */
+ HMENU submenu_id; /* If this is submenu, add children here */
+ HWND tearoff_handle; /* hWnd of tearoff if created */
+#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 belong */
+ 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;
+#endif
+};
+#else
+/* For generating prototypes when FEAT_MENU isn't defined. */
+typedef int vimmenu_T;
+
+#endif /* FEAT_MENU */
+
+/*
+ * Struct to save values in before executing autocommands for a buffer that is
+ * not the current buffer.
+ */
+typedef struct
+{
+ buf_T *save_curbuf; /* saved curbuf */
+ int use_aucmd_win; /* using aucmd_win */
+ win_T *save_curwin; /* saved curwin */
+ win_T *new_curwin; /* new curwin */
+ win_T *save_prevwin; /* saved prevwin */
+ bufref_T new_curbuf; /* new curbuf */
+ char_u *globaldir; /* saved value of globaldir */
+} aco_save_T;
+
+/*
+ * Generic option table item, only used for printer at the moment.
+ */
+typedef struct
+{
+ const char *name;
+ int hasnum;
+ long number;
+ char_u *string; /* points into option string */
+ int strlen;
+ int present;
+} option_table_T;
+
+/*
+ * Structure to hold printing color and font attributes.
+ */
+typedef struct
+{
+ long_u fg_color;
+ long_u bg_color;
+ int bold;
+ int italic;
+ int underline;
+ int undercurl;
+} prt_text_attr_T;
+
+/*
+ * Structure passed back to the generic printer code.
+ */
+typedef struct
+{
+ int n_collated_copies;
+ int n_uncollated_copies;
+ int duplex;
+ int chars_per_line;
+ int lines_per_page;
+ int has_color;
+ prt_text_attr_T number;
+#ifdef FEAT_SYN_HL
+ int modec;
+ int do_syntax;
+#endif
+ int user_abort;
+ char_u *jobname;
+#ifdef FEAT_POSTSCRIPT
+ char_u *outfile;
+ char_u *arguments;
+#endif
+} prt_settings_T;
+
+#define PRINT_NUMBER_WIDTH 8
+
+/*
+ * Used for popup menu items.
+ */
+typedef struct
+{
+ char_u *pum_text; /* main menu text */
+ char_u *pum_kind; /* extra kind text (may be truncated) */
+ char_u *pum_extra; /* extra menu text (may be truncated) */
+ char_u *pum_info; /* extra info */
+} pumitem_T;
+
+/*
+ * Structure used for get_tagfname().
+ */
+typedef struct
+{
+ char_u *tn_tags; /* value of 'tags' when starting */
+ char_u *tn_np; /* current position in tn_tags */
+ int tn_did_filefind_init;
+ int tn_hf_idx;
+ void *tn_search_ctx;
+} tagname_T;
+
+/*
+ * Array indexes used for cptext argument of ins_compl_add().
+ */
+#define CPT_ABBR 0 /* "abbr" */
+#define CPT_MENU 1 /* "menu" */
+#define CPT_KIND 2 /* "kind" */
+#define CPT_INFO 3 /* "info" */
+#define CPT_USER_DATA 4 /* "user data" */
+#define CPT_COUNT 5 /* Number of entries */
+
+typedef struct {
+ UINT32_T total[2];
+ UINT32_T state[8];
+ char_u buffer[64];
+} context_sha256_T;
+
+/*
+ * types for expressions.
+ */
+typedef enum
+{
+ TYPE_UNKNOWN = 0,
+ TYPE_EQUAL, // ==
+ TYPE_NEQUAL, // !=
+ TYPE_GREATER, // >
+ TYPE_GEQUAL, // >=
+ TYPE_SMALLER, // <
+ TYPE_SEQUAL, // <=
+ TYPE_MATCH, // =~
+ TYPE_NOMATCH, // !~
+} exptype_T;
+
+/*
+ * Structure used for reading in json_decode().
+ */
+struct js_reader
+{
+ char_u *js_buf; /* text to be decoded */
+ char_u *js_end; /* NUL in js_buf */
+ int js_used; /* bytes used from js_buf */
+ int (*js_fill)(struct js_reader *);
+ /* function to fill the buffer or NULL;
+ * return TRUE when the buffer was filled */
+ void *js_cookie; /* can be used by js_fill */
+ int js_cookie_arg; /* can be used by js_fill */
+};
+typedef struct js_reader js_read_T;
+
+typedef struct timer_S timer_T;
+struct timer_S
+{
+ long tr_id;
+#ifdef FEAT_TIMERS
+ timer_T *tr_next;
+ timer_T *tr_prev;
+ proftime_T tr_due; /* when the callback is to be invoked */
+ char tr_firing; /* when TRUE callback is being called */
+ char tr_paused; /* when TRUE callback is not invoked */
+ int tr_repeat; /* number of times to repeat, -1 forever */
+ long tr_interval; /* msec */
+ char_u *tr_callback; /* allocated */
+ partial_T *tr_partial;
+ int tr_emsg_count;
+#endif
+};
+
+/* Maximum number of commands from + or -c arguments. */
+#define MAX_ARG_CMDS 10
+
+/* values for "window_layout" */
+#define WIN_HOR 1 /* "-o" horizontally split windows */
+#define WIN_VER 2 /* "-O" vertically split windows */
+#define WIN_TABS 3 /* "-p" windows on tab pages */
+
+/* Struct for various parameters passed between main() and other functions. */
+typedef struct
+{
+ int argc;
+ char **argv;
+
+ char_u *fname; /* first file to edit */
+
+ int evim_mode; /* started as "evim" */
+ char_u *use_vimrc; /* vimrc from -u argument */
+ int clean; /* --clean argument */
+
+ int n_commands; /* no. of commands from + or -c */
+ char_u *commands[MAX_ARG_CMDS]; /* commands from + or -c arg. */
+ char_u cmds_tofree[MAX_ARG_CMDS]; /* commands that need free() */
+ int n_pre_commands; /* no. of commands from --cmd */
+ char_u *pre_commands[MAX_ARG_CMDS]; /* commands from --cmd argument */
+
+ int edit_type; /* type of editing to do */
+ char_u *tagname; /* tag from -t argument */
+#ifdef FEAT_QUICKFIX
+ char_u *use_ef; /* 'errorfile' from -q argument */
+#endif
+
+ int want_full_screen;
+ int not_a_term; /* no warning for missing term? */
+ int tty_fail; /* exit if not a tty */
+ char_u *term; /* specified terminal name */
+#ifdef FEAT_CRYPT
+ int ask_for_key; /* -x argument */
+#endif
+ int no_swap_file; /* "-n" argument used */
+#ifdef FEAT_EVAL
+ int use_debug_break_level;
+#endif
+ int window_count; /* number of windows to use */
+ int window_layout; /* 0, WIN_HOR, WIN_VER or WIN_TABS */
+
+#ifdef FEAT_CLIENTSERVER
+ int serverArg; /* TRUE when argument for a server */
+ char_u *serverName_arg; /* cmdline arg for server name */
+ char_u *serverStr; /* remote server command */
+ char_u *serverStrEnc; /* encoding of serverStr */
+ char_u *servername; /* allocated name for our server */
+#endif
+#if !defined(UNIX)
+# define EXPAND_FILENAMES
+ int literal; /* don't expand file names */
+#endif
+#ifdef MSWIN
+ int full_path; /* file name argument was full path */
+#endif
+#ifdef FEAT_DIFF
+ int diff_mode; /* start with 'diff' set */
+#endif
+} mparm_T;
+
+/*
+ * Structure returned by get_lval() and used by set_var_lval().
+ * For a plain name:
+ * "name" points to the variable name.
+ * "exp_name" is NULL.
+ * "tv" is NULL
+ * For a magic braces name:
+ * "name" points to the expanded variable name.
+ * "exp_name" is non-NULL, to be freed later.
+ * "tv" is NULL
+ * For an index in a list:
+ * "name" points to the (expanded) variable name.
+ * "exp_name" NULL or non-NULL, to be freed later.
+ * "tv" points to the (first) list item value
+ * "li" points to the (first) list item
+ * "range", "n1", "n2" and "empty2" indicate what items are used.
+ * For an existing Dict item:
+ * "name" points to the (expanded) variable name.
+ * "exp_name" NULL or non-NULL, to be freed later.
+ * "tv" points to the dict item value
+ * "newkey" is NULL
+ * For a non-existing Dict item:
+ * "name" points to the (expanded) variable name.
+ * "exp_name" NULL or non-NULL, to be freed later.
+ * "tv" points to the Dictionary typval_T
+ * "newkey" is the key for the new item.
+ */
+typedef struct lval_S
+{
+ char_u *ll_name; /* start of variable name (can be NULL) */
+ char_u *ll_exp_name; /* NULL or expanded name in allocated memory. */
+ typval_T *ll_tv; /* Typeval of item being used. If "newkey"
+ isn't NULL it's the Dict to which to add
+ the item. */
+ listitem_T *ll_li; /* The list item or NULL. */
+ list_T *ll_list; /* The list or NULL. */
+ int ll_range; /* TRUE when a [i:j] range was used */
+ long ll_n1; /* First index for list */
+ long ll_n2; /* Second index for list range */
+ int ll_empty2; /* Second index is empty: [i:] */
+ dict_T *ll_dict; /* The Dictionary or NULL */
+ dictitem_T *ll_di; /* The dictitem or NULL */
+ char_u *ll_newkey; /* New key for Dict in alloc. mem or NULL. */
+ blob_T *ll_blob; /* The Blob or NULL */
+} lval_T;
+
+/* Structure used to save the current state. Used when executing Normal mode
+ * commands while in any other mode. */
+typedef struct {
+ int save_msg_scroll;
+ int save_restart_edit;
+ int save_msg_didout;
+ int save_State;
+ int save_insertmode;
+ int save_finish_op;
+ int save_opcount;
+ tasave_T tabuf;
+} save_state_T;
+
+typedef struct {
+ varnumber_T vv_prevcount;
+ varnumber_T vv_count;
+ varnumber_T vv_count1;
+} vimvars_save_T;
diff --git a/src/syntax.c b/src/syntax.c
new file mode 100644
index 0000000..16c75f2
--- /dev/null
+++ b/src/syntax.c
@@ -0,0 +1,10346 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * syntax.c: code for syntax highlighting
+ */
+
+#include "vim.h"
+
+/*
+ * Structure that stores information about a highlight group.
+ * The ID of a highlight group is also called group ID. It is the index in
+ * the highlight_ga array PLUS ONE.
+ */
+struct hl_group
+{
+ char_u *sg_name; /* highlight group name */
+ char_u *sg_name_u; /* uppercase of sg_name */
+ int sg_cleared; /* "hi clear" was used */
+/* for normal terminals */
+ int sg_term; /* "term=" highlighting attributes */
+ char_u *sg_start; /* terminal string for start highl */
+ char_u *sg_stop; /* terminal string for stop highl */
+ int sg_term_attr; /* Screen attr for term mode */
+/* for color terminals */
+ int sg_cterm; /* "cterm=" highlighting attr */
+ int sg_cterm_bold; /* bold attr was set for light color */
+ int sg_cterm_fg; /* terminal fg color number + 1 */
+ int sg_cterm_bg; /* terminal bg color number + 1 */
+ int sg_cterm_attr; /* Screen attr for color term mode */
+/* for when using the GUI */
+#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
+ guicolor_T sg_gui_fg; /* GUI foreground color handle */
+ guicolor_T sg_gui_bg; /* GUI background color handle */
+#endif
+#ifdef FEAT_GUI
+ guicolor_T sg_gui_sp; /* GUI special color handle */
+ GuiFont sg_font; /* GUI font handle */
+#ifdef FEAT_XFONTSET
+ GuiFontset sg_fontset; /* GUI fontset handle */
+#endif
+ char_u *sg_font_name; /* GUI font or fontset name */
+ int sg_gui_attr; /* Screen attr for GUI mode */
+#endif
+#if defined(FEAT_GUI) || defined(FEAT_EVAL)
+/* Store the sp color name for the GUI or synIDattr() */
+ int sg_gui; /* "gui=" highlighting attributes */
+ char_u *sg_gui_fg_name;/* GUI foreground color name */
+ char_u *sg_gui_bg_name;/* GUI background color name */
+ char_u *sg_gui_sp_name;/* GUI special color name */
+#endif
+ int sg_link; /* link to this highlight group ID */
+ int sg_set; /* combination of SG_* flags */
+#ifdef FEAT_EVAL
+ sctx_T sg_script_ctx; /* script in which the group was last set */
+#endif
+};
+
+#define SG_TERM 1 /* term has been set */
+#define SG_CTERM 2 /* cterm has been set */
+#define SG_GUI 4 /* gui has been set */
+#define SG_LINK 8 /* link has been set */
+
+static garray_T highlight_ga; /* highlight groups for 'highlight' option */
+
+#define HL_TABLE() ((struct hl_group *)((highlight_ga.ga_data)))
+
+#define MAX_HL_ID 20000 /* maximum value for a highlight ID. */
+
+#ifdef FEAT_CMDL_COMPL
+/* Flags to indicate an additional string for highlight name completion. */
+static int include_none = 0; /* when 1 include "None" */
+static int include_default = 0; /* when 1 include "default" */
+static int include_link = 0; /* when 2 include "link" and "clear" */
+#endif
+
+/*
+ * The "term", "cterm" and "gui" arguments can be any combination of the
+ * following names, separated by commas (but no spaces!).
+ */
+static char *(hl_name_table[]) =
+ {"bold", "standout", "underline", "undercurl",
+ "italic", "reverse", "inverse", "nocombine", "strikethrough", "NONE"};
+static int hl_attr_table[] =
+ {HL_BOLD, HL_STANDOUT, HL_UNDERLINE, HL_UNDERCURL, HL_ITALIC, HL_INVERSE, HL_INVERSE, HL_NOCOMBINE, HL_STRIKETHROUGH, 0};
+#define ATTR_COMBINE(attr_a, attr_b) ((((attr_b) & HL_NOCOMBINE) ? attr_b : (attr_a)) | (attr_b))
+
+static void syn_unadd_group(void);
+static void set_hl_attr(int idx);
+static void highlight_list_one(int id);
+static int highlight_list_arg(int id, int didh, int type, int iarg, char_u *sarg, char *name);
+static int syn_add_group(char_u *name);
+static int syn_list_header(int did_header, int outlen, int id);
+static int hl_has_settings(int idx, int check_link);
+static void highlight_clear(int idx);
+
+#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
+static void gui_do_one_color(int idx, int do_menu, int do_tooltip);
+#endif
+#ifdef FEAT_GUI
+static int set_group_colors(char_u *name, guicolor_T *fgp, guicolor_T *bgp, int do_menu, int use_norm, int do_tooltip);
+static void hl_do_font(int idx, char_u *arg, int do_normal, int do_menu, int do_tooltip, int free_font);
+#endif
+
+/*
+ * An attribute number is the index in attr_table plus ATTR_OFF.
+ */
+#define ATTR_OFF (HL_ALL + 1)
+
+#if defined(FEAT_SYN_HL) || defined(PROTO)
+
+#define SYN_NAMELEN 50 /* maximum length of a syntax name */
+
+/* different types of offsets that are possible */
+#define SPO_MS_OFF 0 /* match start offset */
+#define SPO_ME_OFF 1 /* match end offset */
+#define SPO_HS_OFF 2 /* highl. start offset */
+#define SPO_HE_OFF 3 /* highl. end offset */
+#define SPO_RS_OFF 4 /* region start offset */
+#define SPO_RE_OFF 5 /* region end offset */
+#define SPO_LC_OFF 6 /* leading context offset */
+#define SPO_COUNT 7
+
+static char *(spo_name_tab[SPO_COUNT]) =
+ {"ms=", "me=", "hs=", "he=", "rs=", "re=", "lc="};
+
+/*
+ * The patterns that are being searched for are stored in a syn_pattern.
+ * A match item consists of one pattern.
+ * A start/end item consists of n start patterns and m end patterns.
+ * A start/skip/end item consists of n start patterns, one skip pattern and m
+ * end patterns.
+ * For the latter two, the patterns are always consecutive: start-skip-end.
+ *
+ * A character offset can be given for the matched text (_m_start and _m_end)
+ * and for the actually highlighted text (_h_start and _h_end).
+ *
+ * Note that ordering of members is optimized to reduce padding.
+ */
+typedef struct syn_pattern
+{
+ char sp_type; /* see SPTYPE_ defines below */
+ char sp_syncing; /* this item used for syncing */
+ short sp_syn_match_id; /* highlight group ID of pattern */
+ short sp_off_flags; /* see below */
+ int sp_offsets[SPO_COUNT]; /* offsets */
+ int sp_flags; /* see HL_ defines below */
+#ifdef FEAT_CONCEAL
+ int sp_cchar; /* conceal substitute character */
+#endif
+ int sp_ic; /* ignore-case flag for sp_prog */
+ int sp_sync_idx; /* sync item index (syncing only) */
+ int sp_line_id; /* ID of last line where tried */
+ int sp_startcol; /* next match in sp_line_id line */
+ short *sp_cont_list; /* cont. group IDs, if non-zero */
+ short *sp_next_list; /* next group IDs, if non-zero */
+ struct sp_syn sp_syn; /* struct passed to in_id_list() */
+ char_u *sp_pattern; /* regexp to match, pattern */
+ regprog_T *sp_prog; /* regexp to match, program */
+#ifdef FEAT_PROFILE
+ syn_time_T sp_time;
+#endif
+} synpat_T;
+
+/* The sp_off_flags are computed like this:
+ * offset from the start of the matched text: (1 << SPO_XX_OFF)
+ * offset from the end of the matched text: (1 << (SPO_XX_OFF + SPO_COUNT))
+ * When both are present, only one is used.
+ */
+
+#define SPTYPE_MATCH 1 /* match keyword with this group ID */
+#define SPTYPE_START 2 /* match a regexp, start of item */
+#define SPTYPE_END 3 /* match a regexp, end of item */
+#define SPTYPE_SKIP 4 /* match a regexp, skip within item */
+
+
+#define SYN_ITEMS(buf) ((synpat_T *)((buf)->b_syn_patterns.ga_data))
+
+#define NONE_IDX -2 /* value of sp_sync_idx for "NONE" */
+
+/*
+ * Flags for b_syn_sync_flags:
+ */
+#define SF_CCOMMENT 0x01 /* sync on a C-style comment */
+#define SF_MATCH 0x02 /* sync by matching a pattern */
+
+#define SYN_STATE_P(ssp) ((bufstate_T *)((ssp)->ga_data))
+
+#define MAXKEYWLEN 80 /* maximum length of a keyword */
+
+/*
+ * The attributes of the syntax item that has been recognized.
+ */
+static int current_attr = 0; /* attr of current syntax word */
+#ifdef FEAT_EVAL
+static int current_id = 0; /* ID of current char for syn_get_id() */
+static int current_trans_id = 0; /* idem, transparency removed */
+#endif
+#ifdef FEAT_CONCEAL
+static int current_flags = 0;
+static int current_seqnr = 0;
+static int current_sub_char = 0;
+#endif
+
+typedef struct syn_cluster_S
+{
+ char_u *scl_name; /* syntax cluster name */
+ char_u *scl_name_u; /* uppercase of scl_name */
+ short *scl_list; /* IDs in this syntax cluster */
+} syn_cluster_T;
+
+/*
+ * Methods of combining two clusters
+ */
+#define CLUSTER_REPLACE 1 /* replace first list with second */
+#define CLUSTER_ADD 2 /* add second list to first */
+#define CLUSTER_SUBTRACT 3 /* subtract second list from first */
+
+#define SYN_CLSTR(buf) ((syn_cluster_T *)((buf)->b_syn_clusters.ga_data))
+
+/*
+ * Syntax group IDs have different types:
+ * 0 - 19999 normal syntax groups
+ * 20000 - 20999 ALLBUT indicator (current_syn_inc_tag added)
+ * 21000 - 21999 TOP indicator (current_syn_inc_tag added)
+ * 22000 - 22999 CONTAINED indicator (current_syn_inc_tag added)
+ * 23000 - 32767 cluster IDs (subtract SYNID_CLUSTER for the cluster ID)
+ */
+#define SYNID_ALLBUT MAX_HL_ID /* syntax group ID for contains=ALLBUT */
+#define SYNID_TOP 21000 /* syntax group ID for contains=TOP */
+#define SYNID_CONTAINED 22000 /* syntax group ID for contains=CONTAINED */
+#define SYNID_CLUSTER 23000 /* first syntax group ID for clusters */
+
+#define MAX_SYN_INC_TAG 999 /* maximum before the above overflow */
+#define MAX_CLUSTER_ID (32767 - SYNID_CLUSTER)
+
+/*
+ * Annoying Hack(TM): ":syn include" needs this pointer to pass to
+ * expand_filename(). Most of the other syntax commands don't need it, so
+ * instead of passing it to them, we stow it here.
+ */
+static char_u **syn_cmdlinep;
+
+/*
+ * Another Annoying Hack(TM): To prevent rules from other ":syn include"'d
+ * files from leaking into ALLBUT lists, we assign a unique ID to the
+ * rules in each ":syn include"'d file.
+ */
+static int current_syn_inc_tag = 0;
+static int running_syn_inc_tag = 0;
+
+/*
+ * In a hashtable item "hi_key" points to "keyword" in a keyentry.
+ * This avoids adding a pointer to the hashtable item.
+ * KE2HIKEY() converts a var pointer to a hashitem key pointer.
+ * HIKEY2KE() converts a hashitem key pointer to a var pointer.
+ * HI2KE() converts a hashitem pointer to a var pointer.
+ */
+static keyentry_T dumkey;
+#define KE2HIKEY(kp) ((kp)->keyword)
+#define HIKEY2KE(p) ((keyentry_T *)((p) - (dumkey.keyword - (char_u *)&dumkey)))
+#define HI2KE(hi) HIKEY2KE((hi)->hi_key)
+
+/*
+ * To reduce the time spent in keepend(), remember at which level in the state
+ * stack the first item with "keepend" is present. When "-1", there is no
+ * "keepend" on the stack.
+ */
+static int keepend_level = -1;
+
+static char msg_no_items[] = N_("No Syntax items defined for this buffer");
+
+/*
+ * For the current state we need to remember more than just the idx.
+ * When si_m_endpos.lnum is 0, the items other than si_idx are unknown.
+ * (The end positions have the column number of the next char)
+ */
+typedef struct state_item
+{
+ int si_idx; /* index of syntax pattern or
+ KEYWORD_IDX */
+ int si_id; /* highlight group ID for keywords */
+ int si_trans_id; /* idem, transparency removed */
+ int si_m_lnum; /* lnum of the match */
+ int si_m_startcol; /* starting column of the match */
+ lpos_T si_m_endpos; /* just after end posn of the match */
+ lpos_T si_h_startpos; /* start position of the highlighting */
+ lpos_T si_h_endpos; /* end position of the highlighting */
+ lpos_T si_eoe_pos; /* end position of end pattern */
+ int si_end_idx; /* group ID for end pattern or zero */
+ int si_ends; /* if match ends before si_m_endpos */
+ int si_attr; /* attributes in this state */
+ long si_flags; /* HL_HAS_EOL flag in this state, and
+ * HL_SKIP* for si_next_list */
+#ifdef FEAT_CONCEAL
+ int si_seqnr; /* sequence number */
+ int si_cchar; /* substitution character for conceal */
+#endif
+ short *si_cont_list; /* list of contained groups */
+ short *si_next_list; /* nextgroup IDs after this item ends */
+ reg_extmatch_T *si_extmatch; /* \z(...\) matches from start
+ * pattern */
+} stateitem_T;
+
+#define KEYWORD_IDX -1 /* value of si_idx for keywords */
+#define ID_LIST_ALL (short *)-1 /* valid of si_cont_list for containing all
+ but contained groups */
+
+#ifdef FEAT_CONCEAL
+static int next_seqnr = 1; /* value to use for si_seqnr */
+#endif
+
+/*
+ * Struct to reduce the number of arguments to get_syn_options(), it's used
+ * very often.
+ */
+typedef struct
+{
+ int flags; /* flags for contained and transparent */
+ int keyword; /* TRUE for ":syn keyword" */
+ int *sync_idx; /* syntax item for "grouphere" argument, NULL
+ if not allowed */
+ char has_cont_list; /* TRUE if "cont_list" can be used */
+ short *cont_list; /* group IDs for "contains" argument */
+ short *cont_in_list; /* group IDs for "containedin" argument */
+ short *next_list; /* group IDs for "nextgroup" argument */
+} syn_opt_arg_T;
+
+/*
+ * The next possible match in the current line for any pattern is remembered,
+ * to avoid having to try for a match in each column.
+ * If next_match_idx == -1, not tried (in this line) yet.
+ * If next_match_col == MAXCOL, no match found in this line.
+ * (All end positions have the column of the char after the end)
+ */
+static int next_match_col; /* column for start of next match */
+static lpos_T next_match_m_endpos; /* position for end of next match */
+static lpos_T next_match_h_startpos; /* pos. for highl. start of next match */
+static lpos_T next_match_h_endpos; /* pos. for highl. end of next match */
+static int next_match_idx; /* index of matched item */
+static long next_match_flags; /* flags for next match */
+static lpos_T next_match_eos_pos; /* end of start pattn (start region) */
+static lpos_T next_match_eoe_pos; /* pos. for end of end pattern */
+static int next_match_end_idx; /* ID of group for end pattn or zero */
+static reg_extmatch_T *next_match_extmatch = NULL;
+
+/*
+ * A state stack is an array of integers or stateitem_T, stored in a
+ * garray_T. A state stack is invalid if its itemsize entry is zero.
+ */
+#define INVALID_STATE(ssp) ((ssp)->ga_itemsize == 0)
+#define VALID_STATE(ssp) ((ssp)->ga_itemsize != 0)
+
+/*
+ * The current state (within the line) of the recognition engine.
+ * When current_state.ga_itemsize is 0 the current state is invalid.
+ */
+static win_T *syn_win; /* current window for highlighting */
+static buf_T *syn_buf; /* current buffer for highlighting */
+static synblock_T *syn_block; /* current buffer for highlighting */
+#ifdef FEAT_RELTIME
+static proftime_T *syn_tm; /* timeout limit */
+#endif
+static linenr_T current_lnum = 0; /* lnum of current state */
+static colnr_T current_col = 0; /* column of current state */
+static int current_state_stored = 0; /* TRUE if stored current state
+ * after setting current_finished */
+static int current_finished = 0; /* current line has been finished */
+static garray_T current_state /* current stack of state_items */
+ = {0, 0, 0, 0, NULL};
+static short *current_next_list = NULL; /* when non-zero, nextgroup list */
+static int current_next_flags = 0; /* flags for current_next_list */
+static int current_line_id = 0; /* unique number for current line */
+
+#define CUR_STATE(idx) ((stateitem_T *)(current_state.ga_data))[idx]
+
+static void syn_sync(win_T *wp, linenr_T lnum, synstate_T *last_valid);
+static int syn_match_linecont(linenr_T lnum);
+static void syn_start_line(void);
+static void syn_update_ends(int startofline);
+static void syn_stack_alloc(void);
+static int syn_stack_cleanup(void);
+static void syn_stack_free_entry(synblock_T *block, synstate_T *p);
+static synstate_T *syn_stack_find_entry(linenr_T lnum);
+static synstate_T *store_current_state(void);
+static void load_current_state(synstate_T *from);
+static void invalidate_current_state(void);
+static int syn_stack_equal(synstate_T *sp);
+static void validate_current_state(void);
+static int syn_finish_line(int syncing);
+static int syn_current_attr(int syncing, int displaying, int *can_spell, int keep_state);
+static int did_match_already(int idx, garray_T *gap);
+static stateitem_T *push_next_match(stateitem_T *cur_si);
+static void check_state_ends(void);
+static void update_si_attr(int idx);
+static void check_keepend(void);
+static void update_si_end(stateitem_T *sip, int startcol, int force);
+static short *copy_id_list(short *list);
+static int in_id_list(stateitem_T *item, short *cont_list, struct sp_syn *ssp, int contained);
+static int push_current_state(int idx);
+static void pop_current_state(void);
+#ifdef FEAT_PROFILE
+static void syn_clear_time(syn_time_T *tt);
+static void syntime_clear(void);
+static void syntime_report(void);
+static int syn_time_on = FALSE;
+# define IF_SYN_TIME(p) (p)
+#else
+# define IF_SYN_TIME(p) NULL
+typedef int syn_time_T;
+#endif
+
+static void syn_stack_apply_changes_block(synblock_T *block, buf_T *buf);
+static void find_endpos(int idx, lpos_T *startpos, lpos_T *m_endpos, lpos_T *hl_endpos, long *flagsp, lpos_T *end_endpos, int *end_idx, reg_extmatch_T *start_ext);
+
+static void limit_pos(lpos_T *pos, lpos_T *limit);
+static void limit_pos_zero(lpos_T *pos, lpos_T *limit);
+static void syn_add_end_off(lpos_T *result, regmmatch_T *regmatch, synpat_T *spp, int idx, int extra);
+static void syn_add_start_off(lpos_T *result, regmmatch_T *regmatch, synpat_T *spp, int idx, int extra);
+static char_u *syn_getcurline(void);
+static int syn_regexec(regmmatch_T *rmp, linenr_T lnum, colnr_T col, syn_time_T *st);
+static int check_keyword_id(char_u *line, int startcol, int *endcol, long *flags, short **next_list, stateitem_T *cur_si, int *ccharp);
+static void syn_remove_pattern(synblock_T *block, int idx);
+static void syn_clear_pattern(synblock_T *block, int i);
+static void syn_clear_cluster(synblock_T *block, int i);
+static void syn_clear_one(int id, int syncing);
+static void syn_cmd_onoff(exarg_T *eap, char *name);
+static void syn_lines_msg(void);
+static void syn_match_msg(void);
+static void syn_list_one(int id, int syncing, int link_only);
+static void syn_list_cluster(int id);
+static void put_id_list(char_u *name, short *list, int attr);
+static void put_pattern(char *s, int c, synpat_T *spp, int attr);
+static int syn_list_keywords(int id, hashtab_T *ht, int did_header, int attr);
+static void syn_clear_keyword(int id, hashtab_T *ht);
+static void clear_keywtab(hashtab_T *ht);
+static int syn_scl_namen2id(char_u *linep, int len);
+static int syn_check_cluster(char_u *pp, int len);
+static int syn_add_cluster(char_u *name);
+static void init_syn_patterns(void);
+static char_u *get_syn_pattern(char_u *arg, synpat_T *ci);
+static int get_id_list(char_u **arg, int keylen, short **list, int skip);
+static void syn_combine_list(short **clstr1, short **clstr2, int list_op);
+
+#if defined(FEAT_RELTIME) || defined(PROTO)
+/*
+ * Set the timeout used for syntax highlighting.
+ * Use NULL to reset, no timeout.
+ */
+ void
+syn_set_timeout(proftime_T *tm)
+{
+ syn_tm = tm;
+}
+#endif
+
+/*
+ * Start the syntax recognition for a line. This function is normally called
+ * from the screen updating, once for each displayed line.
+ * The buffer is remembered in syn_buf, because get_syntax_attr() doesn't get
+ * it. Careful: curbuf and curwin are likely to point to another buffer and
+ * window.
+ */
+ void
+syntax_start(win_T *wp, linenr_T lnum)
+{
+ synstate_T *p;
+ synstate_T *last_valid = NULL;
+ synstate_T *last_min_valid = NULL;
+ synstate_T *sp, *prev = NULL;
+ linenr_T parsed_lnum;
+ linenr_T first_stored;
+ int dist;
+ static varnumber_T changedtick = 0; /* remember the last change ID */
+
+#ifdef FEAT_CONCEAL
+ current_sub_char = NUL;
+#endif
+
+ /*
+ * After switching buffers, invalidate current_state.
+ * Also do this when a change was made, the current state may be invalid
+ * then.
+ */
+ if (syn_block != wp->w_s
+ || syn_buf != wp->w_buffer
+ || changedtick != CHANGEDTICK(syn_buf))
+ {
+ invalidate_current_state();
+ syn_buf = wp->w_buffer;
+ syn_block = wp->w_s;
+ }
+ changedtick = CHANGEDTICK(syn_buf);
+ syn_win = wp;
+
+ /*
+ * Allocate syntax stack when needed.
+ */
+ syn_stack_alloc();
+ if (syn_block->b_sst_array == NULL)
+ return; /* out of memory */
+ syn_block->b_sst_lasttick = display_tick;
+
+ /*
+ * If the state of the end of the previous line is useful, store it.
+ */
+ if (VALID_STATE(&current_state)
+ && current_lnum < lnum
+ && current_lnum < syn_buf->b_ml.ml_line_count)
+ {
+ (void)syn_finish_line(FALSE);
+ if (!current_state_stored)
+ {
+ ++current_lnum;
+ (void)store_current_state();
+ }
+
+ /*
+ * If the current_lnum is now the same as "lnum", keep the current
+ * state (this happens very often!). Otherwise invalidate
+ * current_state and figure it out below.
+ */
+ if (current_lnum != lnum)
+ invalidate_current_state();
+ }
+ else
+ invalidate_current_state();
+
+ /*
+ * Try to synchronize from a saved state in b_sst_array[].
+ * Only do this if lnum is not before and not to far beyond a saved state.
+ */
+ if (INVALID_STATE(&current_state) && syn_block->b_sst_array != NULL)
+ {
+ /* Find last valid saved state before start_lnum. */
+ for (p = syn_block->b_sst_first; p != NULL; p = p->sst_next)
+ {
+ if (p->sst_lnum > lnum)
+ break;
+ if (p->sst_lnum <= lnum && p->sst_change_lnum == 0)
+ {
+ last_valid = p;
+ if (p->sst_lnum >= lnum - syn_block->b_syn_sync_minlines)
+ last_min_valid = p;
+ }
+ }
+ if (last_min_valid != NULL)
+ load_current_state(last_min_valid);
+ }
+
+ /*
+ * If "lnum" is before or far beyond a line with a saved state, need to
+ * re-synchronize.
+ */
+ if (INVALID_STATE(&current_state))
+ {
+ syn_sync(wp, lnum, last_valid);
+ if (current_lnum == 1)
+ /* First line is always valid, no matter "minlines". */
+ first_stored = 1;
+ else
+ /* Need to parse "minlines" lines before state can be considered
+ * valid to store. */
+ first_stored = current_lnum + syn_block->b_syn_sync_minlines;
+ }
+ else
+ first_stored = current_lnum;
+
+ /*
+ * Advance from the sync point or saved state until the current line.
+ * Save some entries for syncing with later on.
+ */
+ if (syn_block->b_sst_len <= Rows)
+ dist = 999999;
+ else
+ dist = syn_buf->b_ml.ml_line_count / (syn_block->b_sst_len - Rows) + 1;
+ while (current_lnum < lnum)
+ {
+ syn_start_line();
+ (void)syn_finish_line(FALSE);
+ ++current_lnum;
+
+ /* If we parsed at least "minlines" lines or started at a valid
+ * state, the current state is considered valid. */
+ if (current_lnum >= first_stored)
+ {
+ /* Check if the saved state entry is for the current line and is
+ * equal to the current state. If so, then validate all saved
+ * states that depended on a change before the parsed line. */
+ if (prev == NULL)
+ prev = syn_stack_find_entry(current_lnum - 1);
+ if (prev == NULL)
+ sp = syn_block->b_sst_first;
+ else
+ sp = prev;
+ while (sp != NULL && sp->sst_lnum < current_lnum)
+ sp = sp->sst_next;
+ if (sp != NULL
+ && sp->sst_lnum == current_lnum
+ && syn_stack_equal(sp))
+ {
+ parsed_lnum = current_lnum;
+ prev = sp;
+ while (sp != NULL && sp->sst_change_lnum <= parsed_lnum)
+ {
+ if (sp->sst_lnum <= lnum)
+ /* valid state before desired line, use this one */
+ prev = sp;
+ else if (sp->sst_change_lnum == 0)
+ /* past saved states depending on change, break here. */
+ break;
+ sp->sst_change_lnum = 0;
+ sp = sp->sst_next;
+ }
+ load_current_state(prev);
+ }
+ /* Store the state at this line when it's the first one, the line
+ * where we start parsing, or some distance from the previously
+ * saved state. But only when parsed at least 'minlines'. */
+ else if (prev == NULL
+ || current_lnum == lnum
+ || current_lnum >= prev->sst_lnum + dist)
+ prev = store_current_state();
+ }
+
+ /* This can take a long time: break when CTRL-C pressed. The current
+ * state will be wrong then. */
+ line_breakcheck();
+ if (got_int)
+ {
+ current_lnum = lnum;
+ break;
+ }
+ }
+
+ syn_start_line();
+}
+
+/*
+ * We cannot simply discard growarrays full of state_items or buf_states; we
+ * have to manually release their extmatch pointers first.
+ */
+ static void
+clear_syn_state(synstate_T *p)
+{
+ int i;
+ garray_T *gap;
+
+ if (p->sst_stacksize > SST_FIX_STATES)
+ {
+ gap = &(p->sst_union.sst_ga);
+ for (i = 0; i < gap->ga_len; i++)
+ unref_extmatch(SYN_STATE_P(gap)[i].bs_extmatch);
+ ga_clear(gap);
+ }
+ else
+ {
+ for (i = 0; i < p->sst_stacksize; i++)
+ unref_extmatch(p->sst_union.sst_stack[i].bs_extmatch);
+ }
+}
+
+/*
+ * Cleanup the current_state stack.
+ */
+ static void
+clear_current_state(void)
+{
+ int i;
+ stateitem_T *sip;
+
+ sip = (stateitem_T *)(current_state.ga_data);
+ for (i = 0; i < current_state.ga_len; i++)
+ unref_extmatch(sip[i].si_extmatch);
+ ga_clear(&current_state);
+}
+
+/*
+ * Try to find a synchronisation point for line "lnum".
+ *
+ * This sets current_lnum and the current state. One of three methods is
+ * used:
+ * 1. Search backwards for the end of a C-comment.
+ * 2. Search backwards for given sync patterns.
+ * 3. Simply start on a given number of lines above "lnum".
+ */
+ static void
+syn_sync(
+ win_T *wp,
+ linenr_T start_lnum,
+ synstate_T *last_valid)
+{
+ buf_T *curbuf_save;
+ win_T *curwin_save;
+ pos_T cursor_save;
+ int idx;
+ linenr_T lnum;
+ linenr_T end_lnum;
+ linenr_T break_lnum;
+ int had_sync_point;
+ stateitem_T *cur_si;
+ synpat_T *spp;
+ char_u *line;
+ int found_flags = 0;
+ int found_match_idx = 0;
+ linenr_T found_current_lnum = 0;
+ int found_current_col= 0;
+ lpos_T found_m_endpos;
+ colnr_T prev_current_col;
+
+ /*
+ * Clear any current state that might be hanging around.
+ */
+ invalidate_current_state();
+
+ /*
+ * Start at least "minlines" back. Default starting point for parsing is
+ * there.
+ * Start further back, to avoid that scrolling backwards will result in
+ * resyncing for every line. Now it resyncs only one out of N lines,
+ * where N is minlines * 1.5, or minlines * 2 if minlines is small.
+ * Watch out for overflow when minlines is MAXLNUM.
+ */
+ if (syn_block->b_syn_sync_minlines > start_lnum)
+ start_lnum = 1;
+ else
+ {
+ if (syn_block->b_syn_sync_minlines == 1)
+ lnum = 1;
+ else if (syn_block->b_syn_sync_minlines < 10)
+ lnum = syn_block->b_syn_sync_minlines * 2;
+ else
+ lnum = syn_block->b_syn_sync_minlines * 3 / 2;
+ if (syn_block->b_syn_sync_maxlines != 0
+ && lnum > syn_block->b_syn_sync_maxlines)
+ lnum = syn_block->b_syn_sync_maxlines;
+ if (lnum >= start_lnum)
+ start_lnum = 1;
+ else
+ start_lnum -= lnum;
+ }
+ current_lnum = start_lnum;
+
+ /*
+ * 1. Search backwards for the end of a C-style comment.
+ */
+ if (syn_block->b_syn_sync_flags & SF_CCOMMENT)
+ {
+ /* Need to make syn_buf the current buffer for a moment, to be able to
+ * use find_start_comment(). */
+ curwin_save = curwin;
+ curwin = wp;
+ curbuf_save = curbuf;
+ curbuf = syn_buf;
+
+ /*
+ * Skip lines that end in a backslash.
+ */
+ for ( ; start_lnum > 1; --start_lnum)
+ {
+ line = ml_get(start_lnum - 1);
+ if (*line == NUL || *(line + STRLEN(line) - 1) != '\\')
+ break;
+ }
+ current_lnum = start_lnum;
+
+ /* set cursor to start of search */
+ cursor_save = wp->w_cursor;
+ wp->w_cursor.lnum = start_lnum;
+ wp->w_cursor.col = 0;
+
+ /*
+ * If the line is inside a comment, need to find the syntax item that
+ * defines the comment.
+ * Restrict the search for the end of a comment to b_syn_sync_maxlines.
+ */
+ if (find_start_comment((int)syn_block->b_syn_sync_maxlines) != NULL)
+ {
+ for (idx = syn_block->b_syn_patterns.ga_len; --idx >= 0; )
+ if (SYN_ITEMS(syn_block)[idx].sp_syn.id
+ == syn_block->b_syn_sync_id
+ && SYN_ITEMS(syn_block)[idx].sp_type == SPTYPE_START)
+ {
+ validate_current_state();
+ if (push_current_state(idx) == OK)
+ update_si_attr(current_state.ga_len - 1);
+ break;
+ }
+ }
+
+ /* restore cursor and buffer */
+ wp->w_cursor = cursor_save;
+ curwin = curwin_save;
+ curbuf = curbuf_save;
+ }
+
+ /*
+ * 2. Search backwards for given sync patterns.
+ */
+ else if (syn_block->b_syn_sync_flags & SF_MATCH)
+ {
+ if (syn_block->b_syn_sync_maxlines != 0
+ && start_lnum > syn_block->b_syn_sync_maxlines)
+ break_lnum = start_lnum - syn_block->b_syn_sync_maxlines;
+ else
+ break_lnum = 0;
+
+ found_m_endpos.lnum = 0;
+ found_m_endpos.col = 0;
+ end_lnum = start_lnum;
+ lnum = start_lnum;
+ while (--lnum > break_lnum)
+ {
+ /* This can take a long time: break when CTRL-C pressed. */
+ line_breakcheck();
+ if (got_int)
+ {
+ invalidate_current_state();
+ current_lnum = start_lnum;
+ break;
+ }
+
+ /* Check if we have run into a valid saved state stack now. */
+ if (last_valid != NULL && lnum == last_valid->sst_lnum)
+ {
+ load_current_state(last_valid);
+ break;
+ }
+
+ /*
+ * Check if the previous line has the line-continuation pattern.
+ */
+ if (lnum > 1 && syn_match_linecont(lnum - 1))
+ continue;
+
+ /*
+ * Start with nothing on the state stack
+ */
+ validate_current_state();
+
+ for (current_lnum = lnum; current_lnum < end_lnum; ++current_lnum)
+ {
+ syn_start_line();
+ for (;;)
+ {
+ had_sync_point = syn_finish_line(TRUE);
+ /*
+ * When a sync point has been found, remember where, and
+ * continue to look for another one, further on in the line.
+ */
+ if (had_sync_point && current_state.ga_len)
+ {
+ cur_si = &CUR_STATE(current_state.ga_len - 1);
+ if (cur_si->si_m_endpos.lnum > start_lnum)
+ {
+ /* ignore match that goes to after where started */
+ current_lnum = end_lnum;
+ break;
+ }
+ if (cur_si->si_idx < 0)
+ {
+ /* Cannot happen? */
+ found_flags = 0;
+ found_match_idx = KEYWORD_IDX;
+ }
+ else
+ {
+ spp = &(SYN_ITEMS(syn_block)[cur_si->si_idx]);
+ found_flags = spp->sp_flags;
+ found_match_idx = spp->sp_sync_idx;
+ }
+ found_current_lnum = current_lnum;
+ found_current_col = current_col;
+ found_m_endpos = cur_si->si_m_endpos;
+ /*
+ * Continue after the match (be aware of a zero-length
+ * match).
+ */
+ if (found_m_endpos.lnum > current_lnum)
+ {
+ current_lnum = found_m_endpos.lnum;
+ current_col = found_m_endpos.col;
+ if (current_lnum >= end_lnum)
+ break;
+ }
+ else if (found_m_endpos.col > current_col)
+ current_col = found_m_endpos.col;
+ else
+ ++current_col;
+
+ /* syn_current_attr() will have skipped the check for
+ * an item that ends here, need to do that now. Be
+ * careful not to go past the NUL. */
+ prev_current_col = current_col;
+ if (syn_getcurline()[current_col] != NUL)
+ ++current_col;
+ check_state_ends();
+ current_col = prev_current_col;
+ }
+ else
+ break;
+ }
+ }
+
+ /*
+ * If a sync point was encountered, break here.
+ */
+ if (found_flags)
+ {
+ /*
+ * Put the item that was specified by the sync point on the
+ * state stack. If there was no item specified, make the
+ * state stack empty.
+ */
+ clear_current_state();
+ if (found_match_idx >= 0
+ && push_current_state(found_match_idx) == OK)
+ update_si_attr(current_state.ga_len - 1);
+
+ /*
+ * When using "grouphere", continue from the sync point
+ * match, until the end of the line. Parsing starts at
+ * the next line.
+ * For "groupthere" the parsing starts at start_lnum.
+ */
+ if (found_flags & HL_SYNC_HERE)
+ {
+ if (current_state.ga_len)
+ {
+ cur_si = &CUR_STATE(current_state.ga_len - 1);
+ cur_si->si_h_startpos.lnum = found_current_lnum;
+ cur_si->si_h_startpos.col = found_current_col;
+ update_si_end(cur_si, (int)current_col, TRUE);
+ check_keepend();
+ }
+ current_col = found_m_endpos.col;
+ current_lnum = found_m_endpos.lnum;
+ (void)syn_finish_line(FALSE);
+ ++current_lnum;
+ }
+ else
+ current_lnum = start_lnum;
+
+ break;
+ }
+
+ end_lnum = lnum;
+ invalidate_current_state();
+ }
+
+ /* Ran into start of the file or exceeded maximum number of lines */
+ if (lnum <= break_lnum)
+ {
+ invalidate_current_state();
+ current_lnum = break_lnum + 1;
+ }
+ }
+
+ validate_current_state();
+}
+
+ static void
+save_chartab(char_u *chartab)
+{
+ if (syn_block->b_syn_isk != empty_option)
+ {
+ mch_memmove(chartab, syn_buf->b_chartab, (size_t)32);
+ mch_memmove(syn_buf->b_chartab, syn_win->w_s->b_syn_chartab,
+ (size_t)32);
+ }
+}
+
+ static void
+restore_chartab(char_u *chartab)
+{
+ if (syn_win->w_s->b_syn_isk != empty_option)
+ mch_memmove(syn_buf->b_chartab, chartab, (size_t)32);
+}
+
+/*
+ * Return TRUE if the line-continuation pattern matches in line "lnum".
+ */
+ static int
+syn_match_linecont(linenr_T lnum)
+{
+ regmmatch_T regmatch;
+ int r;
+ char_u buf_chartab[32]; /* chartab array for syn iskyeyword */
+
+ if (syn_block->b_syn_linecont_prog != NULL)
+ {
+ /* use syntax iskeyword option */
+ save_chartab(buf_chartab);
+ regmatch.rmm_ic = syn_block->b_syn_linecont_ic;
+ regmatch.regprog = syn_block->b_syn_linecont_prog;
+ r = syn_regexec(&regmatch, lnum, (colnr_T)0,
+ IF_SYN_TIME(&syn_block->b_syn_linecont_time));
+ syn_block->b_syn_linecont_prog = regmatch.regprog;
+ restore_chartab(buf_chartab);
+ return r;
+ }
+ return FALSE;
+}
+
+/*
+ * Prepare the current state for the start of a line.
+ */
+ static void
+syn_start_line(void)
+{
+ current_finished = FALSE;
+ current_col = 0;
+
+ /*
+ * Need to update the end of a start/skip/end that continues from the
+ * previous line and regions that have "keepend".
+ */
+ if (current_state.ga_len > 0)
+ {
+ syn_update_ends(TRUE);
+ check_state_ends();
+ }
+
+ next_match_idx = -1;
+ ++current_line_id;
+#ifdef FEAT_CONCEAL
+ next_seqnr = 1;
+#endif
+}
+
+/*
+ * Check for items in the stack that need their end updated.
+ * When "startofline" is TRUE the last item is always updated.
+ * When "startofline" is FALSE the item with "keepend" is forcefully updated.
+ */
+ static void
+syn_update_ends(int startofline)
+{
+ stateitem_T *cur_si;
+ int i;
+ int seen_keepend;
+
+ if (startofline)
+ {
+ /* Check for a match carried over from a previous line with a
+ * contained region. The match ends as soon as the region ends. */
+ for (i = 0; i < current_state.ga_len; ++i)
+ {
+ cur_si = &CUR_STATE(i);
+ if (cur_si->si_idx >= 0
+ && (SYN_ITEMS(syn_block)[cur_si->si_idx]).sp_type
+ == SPTYPE_MATCH
+ && cur_si->si_m_endpos.lnum < current_lnum)
+ {
+ cur_si->si_flags |= HL_MATCHCONT;
+ cur_si->si_m_endpos.lnum = 0;
+ cur_si->si_m_endpos.col = 0;
+ cur_si->si_h_endpos = cur_si->si_m_endpos;
+ cur_si->si_ends = TRUE;
+ }
+ }
+ }
+
+ /*
+ * Need to update the end of a start/skip/end that continues from the
+ * previous line. And regions that have "keepend", because they may
+ * influence contained items. If we've just removed "extend"
+ * (startofline == 0) then we should update ends of normal regions
+ * contained inside "keepend" because "extend" could have extended
+ * these "keepend" regions as well as contained normal regions.
+ * Then check for items ending in column 0.
+ */
+ i = current_state.ga_len - 1;
+ if (keepend_level >= 0)
+ for ( ; i > keepend_level; --i)
+ if (CUR_STATE(i).si_flags & HL_EXTEND)
+ break;
+
+ seen_keepend = FALSE;
+ for ( ; i < current_state.ga_len; ++i)
+ {
+ cur_si = &CUR_STATE(i);
+ if ((cur_si->si_flags & HL_KEEPEND)
+ || (seen_keepend && !startofline)
+ || (i == current_state.ga_len - 1 && startofline))
+ {
+ cur_si->si_h_startpos.col = 0; /* start highl. in col 0 */
+ cur_si->si_h_startpos.lnum = current_lnum;
+
+ if (!(cur_si->si_flags & HL_MATCHCONT))
+ update_si_end(cur_si, (int)current_col, !startofline);
+
+ if (!startofline && (cur_si->si_flags & HL_KEEPEND))
+ seen_keepend = TRUE;
+ }
+ }
+ check_keepend();
+}
+
+/****************************************
+ * Handling of the state stack cache.
+ */
+
+/*
+ * EXPLANATION OF THE SYNTAX STATE STACK CACHE
+ *
+ * To speed up syntax highlighting, the state stack for the start of some
+ * lines is cached. These entries can be used to start parsing at that point.
+ *
+ * The stack is kept in b_sst_array[] for each buffer. There is a list of
+ * valid entries. b_sst_first points to the first one, then follow sst_next.
+ * The entries are sorted on line number. The first entry is often for line 2
+ * (line 1 always starts with an empty stack).
+ * There is also a list for free entries. This construction is used to avoid
+ * having to allocate and free memory blocks too often.
+ *
+ * When making changes to the buffer, this is logged in b_mod_*. When calling
+ * update_screen() to update the display, it will call
+ * syn_stack_apply_changes() for each displayed buffer to adjust the cached
+ * entries. The entries which are inside the changed area are removed,
+ * because they must be recomputed. Entries below the changed have their line
+ * number adjusted for deleted/inserted lines, and have their sst_change_lnum
+ * set to indicate that a check must be made if the changed lines would change
+ * the cached entry.
+ *
+ * When later displaying lines, an entry is stored for each line. Displayed
+ * lines are likely to be displayed again, in which case the state at the
+ * start of the line is needed.
+ * For not displayed lines, an entry is stored for every so many lines. These
+ * entries will be used e.g., when scrolling backwards. The distance between
+ * entries depends on the number of lines in the buffer. For small buffers
+ * the distance is fixed at SST_DIST, for large buffers there is a fixed
+ * number of entries SST_MAX_ENTRIES, and the distance is computed.
+ */
+
+ static void
+syn_stack_free_block(synblock_T *block)
+{
+ synstate_T *p;
+
+ if (block->b_sst_array != NULL)
+ {
+ for (p = block->b_sst_first; p != NULL; p = p->sst_next)
+ clear_syn_state(p);
+ VIM_CLEAR(block->b_sst_array);
+ block->b_sst_first = NULL;
+ block->b_sst_len = 0;
+ }
+}
+/*
+ * Free b_sst_array[] for buffer "buf".
+ * Used when syntax items changed to force resyncing everywhere.
+ */
+ void
+syn_stack_free_all(synblock_T *block)
+{
+#ifdef FEAT_FOLDING
+ win_T *wp;
+#endif
+
+ syn_stack_free_block(block);
+
+#ifdef FEAT_FOLDING
+ /* When using "syntax" fold method, must update all folds. */
+ FOR_ALL_WINDOWS(wp)
+ {
+ if (wp->w_s == block && foldmethodIsSyntax(wp))
+ foldUpdateAll(wp);
+ }
+#endif
+}
+
+/*
+ * Allocate the syntax state stack for syn_buf when needed.
+ * If the number of entries in b_sst_array[] is much too big or a bit too
+ * small, reallocate it.
+ * Also used to allocate b_sst_array[] for the first time.
+ */
+ static void
+syn_stack_alloc(void)
+{
+ long len;
+ synstate_T *to, *from;
+ synstate_T *sstp;
+
+ len = syn_buf->b_ml.ml_line_count / SST_DIST + Rows * 2;
+ if (len < SST_MIN_ENTRIES)
+ len = SST_MIN_ENTRIES;
+ else if (len > SST_MAX_ENTRIES)
+ len = SST_MAX_ENTRIES;
+ if (syn_block->b_sst_len > len * 2 || syn_block->b_sst_len < len)
+ {
+ /* Allocate 50% too much, to avoid reallocating too often. */
+ len = syn_buf->b_ml.ml_line_count;
+ len = (len + len / 2) / SST_DIST + Rows * 2;
+ if (len < SST_MIN_ENTRIES)
+ len = SST_MIN_ENTRIES;
+ else if (len > SST_MAX_ENTRIES)
+ len = SST_MAX_ENTRIES;
+
+ if (syn_block->b_sst_array != NULL)
+ {
+ /* When shrinking the array, cleanup the existing stack.
+ * Make sure that all valid entries fit in the new array. */
+ while (syn_block->b_sst_len - syn_block->b_sst_freecount + 2 > len
+ && syn_stack_cleanup())
+ ;
+ if (len < syn_block->b_sst_len - syn_block->b_sst_freecount + 2)
+ len = syn_block->b_sst_len - syn_block->b_sst_freecount + 2;
+ }
+
+ sstp = (synstate_T *)alloc_clear((unsigned)(len * sizeof(synstate_T)));
+ if (sstp == NULL) /* out of memory! */
+ return;
+
+ to = sstp - 1;
+ if (syn_block->b_sst_array != NULL)
+ {
+ /* Move the states from the old array to the new one. */
+ for (from = syn_block->b_sst_first; from != NULL;
+ from = from->sst_next)
+ {
+ ++to;
+ *to = *from;
+ to->sst_next = to + 1;
+ }
+ }
+ if (to != sstp - 1)
+ {
+ to->sst_next = NULL;
+ syn_block->b_sst_first = sstp;
+ syn_block->b_sst_freecount = len - (int)(to - sstp) - 1;
+ }
+ else
+ {
+ syn_block->b_sst_first = NULL;
+ syn_block->b_sst_freecount = len;
+ }
+
+ /* Create the list of free entries. */
+ syn_block->b_sst_firstfree = to + 1;
+ while (++to < sstp + len)
+ to->sst_next = to + 1;
+ (sstp + len - 1)->sst_next = NULL;
+
+ vim_free(syn_block->b_sst_array);
+ syn_block->b_sst_array = sstp;
+ syn_block->b_sst_len = len;
+ }
+}
+
+/*
+ * Check for changes in a buffer to affect stored syntax states. Uses the
+ * b_mod_* fields.
+ * Called from update_screen(), before screen is being updated, once for each
+ * displayed buffer.
+ */
+ void
+syn_stack_apply_changes(buf_T *buf)
+{
+ win_T *wp;
+
+ syn_stack_apply_changes_block(&buf->b_s, buf);
+
+ FOR_ALL_WINDOWS(wp)
+ {
+ if ((wp->w_buffer == buf) && (wp->w_s != &buf->b_s))
+ syn_stack_apply_changes_block(wp->w_s, buf);
+ }
+}
+
+ static void
+syn_stack_apply_changes_block(synblock_T *block, buf_T *buf)
+{
+ synstate_T *p, *prev, *np;
+ linenr_T n;
+
+ prev = NULL;
+ for (p = block->b_sst_first; p != NULL; )
+ {
+ if (p->sst_lnum + block->b_syn_sync_linebreaks > buf->b_mod_top)
+ {
+ n = p->sst_lnum + buf->b_mod_xlines;
+ if (n <= buf->b_mod_bot)
+ {
+ /* this state is inside the changed area, remove it */
+ np = p->sst_next;
+ if (prev == NULL)
+ block->b_sst_first = np;
+ else
+ prev->sst_next = np;
+ syn_stack_free_entry(block, p);
+ p = np;
+ continue;
+ }
+ /* This state is below the changed area. Remember the line
+ * that needs to be parsed before this entry can be made valid
+ * again. */
+ if (p->sst_change_lnum != 0 && p->sst_change_lnum > buf->b_mod_top)
+ {
+ if (p->sst_change_lnum + buf->b_mod_xlines > buf->b_mod_top)
+ p->sst_change_lnum += buf->b_mod_xlines;
+ else
+ p->sst_change_lnum = buf->b_mod_top;
+ }
+ if (p->sst_change_lnum == 0
+ || p->sst_change_lnum < buf->b_mod_bot)
+ p->sst_change_lnum = buf->b_mod_bot;
+
+ p->sst_lnum = n;
+ }
+ prev = p;
+ p = p->sst_next;
+ }
+}
+
+/*
+ * Reduce the number of entries in the state stack for syn_buf.
+ * Returns TRUE if at least one entry was freed.
+ */
+ static int
+syn_stack_cleanup(void)
+{
+ synstate_T *p, *prev;
+ disptick_T tick;
+ int above;
+ int dist;
+ int retval = FALSE;
+
+ if (syn_block->b_sst_first == NULL)
+ return retval;
+
+ /* Compute normal distance between non-displayed entries. */
+ if (syn_block->b_sst_len <= Rows)
+ dist = 999999;
+ else
+ dist = syn_buf->b_ml.ml_line_count / (syn_block->b_sst_len - Rows) + 1;
+
+ /*
+ * Go through the list to find the "tick" for the oldest entry that can
+ * be removed. Set "above" when the "tick" for the oldest entry is above
+ * "b_sst_lasttick" (the display tick wraps around).
+ */
+ tick = syn_block->b_sst_lasttick;
+ above = FALSE;
+ prev = syn_block->b_sst_first;
+ for (p = prev->sst_next; p != NULL; prev = p, p = p->sst_next)
+ {
+ if (prev->sst_lnum + dist > p->sst_lnum)
+ {
+ if (p->sst_tick > syn_block->b_sst_lasttick)
+ {
+ if (!above || p->sst_tick < tick)
+ tick = p->sst_tick;
+ above = TRUE;
+ }
+ else if (!above && p->sst_tick < tick)
+ tick = p->sst_tick;
+ }
+ }
+
+ /*
+ * Go through the list to make the entries for the oldest tick at an
+ * interval of several lines.
+ */
+ prev = syn_block->b_sst_first;
+ for (p = prev->sst_next; p != NULL; prev = p, p = p->sst_next)
+ {
+ if (p->sst_tick == tick && prev->sst_lnum + dist > p->sst_lnum)
+ {
+ /* Move this entry from used list to free list */
+ prev->sst_next = p->sst_next;
+ syn_stack_free_entry(syn_block, p);
+ p = prev;
+ retval = TRUE;
+ }
+ }
+ return retval;
+}
+
+/*
+ * Free the allocated memory for a syn_state item.
+ * Move the entry into the free list.
+ */
+ static void
+syn_stack_free_entry(synblock_T *block, synstate_T *p)
+{
+ clear_syn_state(p);
+ p->sst_next = block->b_sst_firstfree;
+ block->b_sst_firstfree = p;
+ ++block->b_sst_freecount;
+}
+
+/*
+ * Find an entry in the list of state stacks at or before "lnum".
+ * Returns NULL when there is no entry or the first entry is after "lnum".
+ */
+ static synstate_T *
+syn_stack_find_entry(linenr_T lnum)
+{
+ synstate_T *p, *prev;
+
+ prev = NULL;
+ for (p = syn_block->b_sst_first; p != NULL; prev = p, p = p->sst_next)
+ {
+ if (p->sst_lnum == lnum)
+ return p;
+ if (p->sst_lnum > lnum)
+ break;
+ }
+ return prev;
+}
+
+/*
+ * Try saving the current state in b_sst_array[].
+ * The current state must be valid for the start of the current_lnum line!
+ */
+ static synstate_T *
+store_current_state(void)
+{
+ int i;
+ synstate_T *p;
+ bufstate_T *bp;
+ stateitem_T *cur_si;
+ synstate_T *sp = syn_stack_find_entry(current_lnum);
+
+ /*
+ * If the current state contains a start or end pattern that continues
+ * from the previous line, we can't use it. Don't store it then.
+ */
+ for (i = current_state.ga_len - 1; i >= 0; --i)
+ {
+ cur_si = &CUR_STATE(i);
+ if (cur_si->si_h_startpos.lnum >= current_lnum
+ || cur_si->si_m_endpos.lnum >= current_lnum
+ || cur_si->si_h_endpos.lnum >= current_lnum
+ || (cur_si->si_end_idx
+ && cur_si->si_eoe_pos.lnum >= current_lnum))
+ break;
+ }
+ if (i >= 0)
+ {
+ if (sp != NULL)
+ {
+ /* find "sp" in the list and remove it */
+ if (syn_block->b_sst_first == sp)
+ /* it's the first entry */
+ syn_block->b_sst_first = sp->sst_next;
+ else
+ {
+ /* find the entry just before this one to adjust sst_next */
+ for (p = syn_block->b_sst_first; p != NULL; p = p->sst_next)
+ if (p->sst_next == sp)
+ break;
+ if (p != NULL) /* just in case */
+ p->sst_next = sp->sst_next;
+ }
+ syn_stack_free_entry(syn_block, sp);
+ sp = NULL;
+ }
+ }
+ else if (sp == NULL || sp->sst_lnum != current_lnum)
+ {
+ /*
+ * Add a new entry
+ */
+ /* If no free items, cleanup the array first. */
+ if (syn_block->b_sst_freecount == 0)
+ {
+ (void)syn_stack_cleanup();
+ /* "sp" may have been moved to the freelist now */
+ sp = syn_stack_find_entry(current_lnum);
+ }
+ /* Still no free items? Must be a strange problem... */
+ if (syn_block->b_sst_freecount == 0)
+ sp = NULL;
+ else
+ {
+ /* Take the first item from the free list and put it in the used
+ * list, after *sp */
+ p = syn_block->b_sst_firstfree;
+ syn_block->b_sst_firstfree = p->sst_next;
+ --syn_block->b_sst_freecount;
+ if (sp == NULL)
+ {
+ /* Insert in front of the list */
+ p->sst_next = syn_block->b_sst_first;
+ syn_block->b_sst_first = p;
+ }
+ else
+ {
+ /* insert in list after *sp */
+ p->sst_next = sp->sst_next;
+ sp->sst_next = p;
+ }
+ sp = p;
+ sp->sst_stacksize = 0;
+ sp->sst_lnum = current_lnum;
+ }
+ }
+ if (sp != NULL)
+ {
+ /* When overwriting an existing state stack, clear it first */
+ clear_syn_state(sp);
+ sp->sst_stacksize = current_state.ga_len;
+ if (current_state.ga_len > SST_FIX_STATES)
+ {
+ /* Need to clear it, might be something remaining from when the
+ * length was less than SST_FIX_STATES. */
+ ga_init2(&sp->sst_union.sst_ga, (int)sizeof(bufstate_T), 1);
+ if (ga_grow(&sp->sst_union.sst_ga, current_state.ga_len) == FAIL)
+ sp->sst_stacksize = 0;
+ else
+ sp->sst_union.sst_ga.ga_len = current_state.ga_len;
+ bp = SYN_STATE_P(&(sp->sst_union.sst_ga));
+ }
+ else
+ bp = sp->sst_union.sst_stack;
+ for (i = 0; i < sp->sst_stacksize; ++i)
+ {
+ bp[i].bs_idx = CUR_STATE(i).si_idx;
+ bp[i].bs_flags = CUR_STATE(i).si_flags;
+#ifdef FEAT_CONCEAL
+ bp[i].bs_seqnr = CUR_STATE(i).si_seqnr;
+ bp[i].bs_cchar = CUR_STATE(i).si_cchar;
+#endif
+ bp[i].bs_extmatch = ref_extmatch(CUR_STATE(i).si_extmatch);
+ }
+ sp->sst_next_flags = current_next_flags;
+ sp->sst_next_list = current_next_list;
+ sp->sst_tick = display_tick;
+ sp->sst_change_lnum = 0;
+ }
+ current_state_stored = TRUE;
+ return sp;
+}
+
+/*
+ * Copy a state stack from "from" in b_sst_array[] to current_state;
+ */
+ static void
+load_current_state(synstate_T *from)
+{
+ int i;
+ bufstate_T *bp;
+
+ clear_current_state();
+ validate_current_state();
+ keepend_level = -1;
+ if (from->sst_stacksize
+ && ga_grow(&current_state, from->sst_stacksize) != FAIL)
+ {
+ if (from->sst_stacksize > SST_FIX_STATES)
+ bp = SYN_STATE_P(&(from->sst_union.sst_ga));
+ else
+ bp = from->sst_union.sst_stack;
+ for (i = 0; i < from->sst_stacksize; ++i)
+ {
+ CUR_STATE(i).si_idx = bp[i].bs_idx;
+ CUR_STATE(i).si_flags = bp[i].bs_flags;
+#ifdef FEAT_CONCEAL
+ CUR_STATE(i).si_seqnr = bp[i].bs_seqnr;
+ CUR_STATE(i).si_cchar = bp[i].bs_cchar;
+#endif
+ CUR_STATE(i).si_extmatch = ref_extmatch(bp[i].bs_extmatch);
+ if (keepend_level < 0 && (CUR_STATE(i).si_flags & HL_KEEPEND))
+ keepend_level = i;
+ CUR_STATE(i).si_ends = FALSE;
+ CUR_STATE(i).si_m_lnum = 0;
+ if (CUR_STATE(i).si_idx >= 0)
+ CUR_STATE(i).si_next_list =
+ (SYN_ITEMS(syn_block)[CUR_STATE(i).si_idx]).sp_next_list;
+ else
+ CUR_STATE(i).si_next_list = NULL;
+ update_si_attr(i);
+ }
+ current_state.ga_len = from->sst_stacksize;
+ }
+ current_next_list = from->sst_next_list;
+ current_next_flags = from->sst_next_flags;
+ current_lnum = from->sst_lnum;
+}
+
+/*
+ * Compare saved state stack "*sp" with the current state.
+ * Return TRUE when they are equal.
+ */
+ static int
+syn_stack_equal(synstate_T *sp)
+{
+ int i, j;
+ bufstate_T *bp;
+ reg_extmatch_T *six, *bsx;
+
+ /* First a quick check if the stacks have the same size end nextlist. */
+ if (sp->sst_stacksize == current_state.ga_len
+ && sp->sst_next_list == current_next_list)
+ {
+ /* Need to compare all states on both stacks. */
+ if (sp->sst_stacksize > SST_FIX_STATES)
+ bp = SYN_STATE_P(&(sp->sst_union.sst_ga));
+ else
+ bp = sp->sst_union.sst_stack;
+
+ for (i = current_state.ga_len; --i >= 0; )
+ {
+ /* If the item has another index the state is different. */
+ if (bp[i].bs_idx != CUR_STATE(i).si_idx)
+ break;
+ if (bp[i].bs_extmatch != CUR_STATE(i).si_extmatch)
+ {
+ /* When the extmatch pointers are different, the strings in
+ * them can still be the same. Check if the extmatch
+ * references are equal. */
+ bsx = bp[i].bs_extmatch;
+ six = CUR_STATE(i).si_extmatch;
+ /* If one of the extmatch pointers is NULL the states are
+ * different. */
+ if (bsx == NULL || six == NULL)
+ break;
+ for (j = 0; j < NSUBEXP; ++j)
+ {
+ /* Check each referenced match string. They must all be
+ * equal. */
+ if (bsx->matches[j] != six->matches[j])
+ {
+ /* If the pointer is different it can still be the
+ * same text. Compare the strings, ignore case when
+ * the start item has the sp_ic flag set. */
+ if (bsx->matches[j] == NULL
+ || six->matches[j] == NULL)
+ break;
+ if ((SYN_ITEMS(syn_block)[CUR_STATE(i).si_idx]).sp_ic
+ ? MB_STRICMP(bsx->matches[j],
+ six->matches[j]) != 0
+ : STRCMP(bsx->matches[j], six->matches[j]) != 0)
+ break;
+ }
+ }
+ if (j != NSUBEXP)
+ break;
+ }
+ }
+ if (i < 0)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * We stop parsing syntax above line "lnum". If the stored state at or below
+ * this line depended on a change before it, it now depends on the line below
+ * the last parsed line.
+ * The window looks like this:
+ * line which changed
+ * displayed line
+ * displayed line
+ * lnum -> line below window
+ */
+ void
+syntax_end_parsing(linenr_T lnum)
+{
+ synstate_T *sp;
+
+ sp = syn_stack_find_entry(lnum);
+ if (sp != NULL && sp->sst_lnum < lnum)
+ sp = sp->sst_next;
+
+ if (sp != NULL && sp->sst_change_lnum != 0)
+ sp->sst_change_lnum = lnum;
+}
+
+/*
+ * End of handling of the state stack.
+ ****************************************/
+
+ static void
+invalidate_current_state(void)
+{
+ clear_current_state();
+ current_state.ga_itemsize = 0; /* mark current_state invalid */
+ current_next_list = NULL;
+ keepend_level = -1;
+}
+
+ static void
+validate_current_state(void)
+{
+ current_state.ga_itemsize = sizeof(stateitem_T);
+ current_state.ga_growsize = 3;
+}
+
+/*
+ * Return TRUE if the syntax at start of lnum changed since last time.
+ * This will only be called just after get_syntax_attr() for the previous
+ * line, to check if the next line needs to be redrawn too.
+ */
+ int
+syntax_check_changed(linenr_T lnum)
+{
+ int retval = TRUE;
+ synstate_T *sp;
+
+ /*
+ * Check the state stack when:
+ * - lnum is just below the previously syntaxed line.
+ * - lnum is not before the lines with saved states.
+ * - lnum is not past the lines with saved states.
+ * - lnum is at or before the last changed line.
+ */
+ if (VALID_STATE(&current_state) && lnum == current_lnum + 1)
+ {
+ sp = syn_stack_find_entry(lnum);
+ if (sp != NULL && sp->sst_lnum == lnum)
+ {
+ /*
+ * finish the previous line (needed when not all of the line was
+ * drawn)
+ */
+ (void)syn_finish_line(FALSE);
+
+ /*
+ * Compare the current state with the previously saved state of
+ * the line.
+ */
+ if (syn_stack_equal(sp))
+ retval = FALSE;
+
+ /*
+ * Store the current state in b_sst_array[] for later use.
+ */
+ ++current_lnum;
+ (void)store_current_state();
+ }
+ }
+
+ return retval;
+}
+
+/*
+ * Finish the current line.
+ * This doesn't return any attributes, it only gets the state at the end of
+ * the line. It can start anywhere in the line, as long as the current state
+ * is valid.
+ */
+ static int
+syn_finish_line(
+ int syncing) /* called for syncing */
+{
+ stateitem_T *cur_si;
+ colnr_T prev_current_col;
+
+ while (!current_finished)
+ {
+ (void)syn_current_attr(syncing, FALSE, NULL, FALSE);
+ /*
+ * When syncing, and found some item, need to check the item.
+ */
+ if (syncing && current_state.ga_len)
+ {
+ /*
+ * Check for match with sync item.
+ */
+ cur_si = &CUR_STATE(current_state.ga_len - 1);
+ if (cur_si->si_idx >= 0
+ && (SYN_ITEMS(syn_block)[cur_si->si_idx].sp_flags
+ & (HL_SYNC_HERE|HL_SYNC_THERE)))
+ return TRUE;
+
+ /* syn_current_attr() will have skipped the check for an item
+ * that ends here, need to do that now. Be careful not to go
+ * past the NUL. */
+ prev_current_col = current_col;
+ if (syn_getcurline()[current_col] != NUL)
+ ++current_col;
+ check_state_ends();
+ current_col = prev_current_col;
+ }
+ ++current_col;
+ }
+ return FALSE;
+}
+
+/*
+ * Return highlight attributes for next character.
+ * Must first call syntax_start() once for the line.
+ * "col" is normally 0 for the first use in a line, and increments by one each
+ * time. It's allowed to skip characters and to stop before the end of the
+ * line. But only a "col" after a previously used column is allowed.
+ * When "can_spell" is not NULL set it to TRUE when spell-checking should be
+ * done.
+ */
+ int
+get_syntax_attr(
+ colnr_T col,
+ int *can_spell,
+ int keep_state) /* keep state of char at "col" */
+{
+ int attr = 0;
+
+ if (can_spell != NULL)
+ /* Default: Only do spelling when there is no @Spell cluster or when
+ * ":syn spell toplevel" was used. */
+ *can_spell = syn_block->b_syn_spell == SYNSPL_DEFAULT
+ ? (syn_block->b_spell_cluster_id == 0)
+ : (syn_block->b_syn_spell == SYNSPL_TOP);
+
+ /* check for out of memory situation */
+ if (syn_block->b_sst_array == NULL)
+ return 0;
+
+ /* After 'synmaxcol' the attribute is always zero. */
+ if (syn_buf->b_p_smc > 0 && col >= (colnr_T)syn_buf->b_p_smc)
+ {
+ clear_current_state();
+#ifdef FEAT_EVAL
+ current_id = 0;
+ current_trans_id = 0;
+#endif
+#ifdef FEAT_CONCEAL
+ current_flags = 0;
+ current_seqnr = 0;
+#endif
+ return 0;
+ }
+
+ /* Make sure current_state is valid */
+ if (INVALID_STATE(&current_state))
+ validate_current_state();
+
+ /*
+ * Skip from the current column to "col", get the attributes for "col".
+ */
+ while (current_col <= col)
+ {
+ attr = syn_current_attr(FALSE, TRUE, can_spell,
+ current_col == col ? keep_state : FALSE);
+ ++current_col;
+ }
+
+ return attr;
+}
+
+/*
+ * Get syntax attributes for current_lnum, current_col.
+ */
+ static int
+syn_current_attr(
+ int syncing, /* When 1: called for syncing */
+ int displaying, /* result will be displayed */
+ int *can_spell, /* return: do spell checking */
+ int keep_state) /* keep syntax stack afterwards */
+{
+ int syn_id;
+ lpos_T endpos; /* was: char_u *endp; */
+ lpos_T hl_startpos; /* was: int hl_startcol; */
+ lpos_T hl_endpos;
+ lpos_T eos_pos; /* end-of-start match (start region) */
+ lpos_T eoe_pos; /* end-of-end pattern */
+ int end_idx; /* group ID for end pattern */
+ int idx;
+ synpat_T *spp;
+ stateitem_T *cur_si, *sip = NULL;
+ int startcol;
+ int endcol;
+ long flags;
+ int cchar;
+ short *next_list;
+ int found_match; /* found usable match */
+ static int try_next_column = FALSE; /* must try in next col */
+ int do_keywords;
+ regmmatch_T regmatch;
+ lpos_T pos;
+ int lc_col;
+ reg_extmatch_T *cur_extmatch = NULL;
+ char_u buf_chartab[32]; /* chartab array for syn iskyeyword */
+ char_u *line; /* current line. NOTE: becomes invalid after
+ looking for a pattern match! */
+
+ /* variables for zero-width matches that have a "nextgroup" argument */
+ int keep_next_list;
+ int zero_width_next_list = FALSE;
+ garray_T zero_width_next_ga;
+
+ /*
+ * No character, no attributes! Past end of line?
+ * Do try matching with an empty line (could be the start of a region).
+ */
+ line = syn_getcurline();
+ if (line[current_col] == NUL && current_col != 0)
+ {
+ /*
+ * If we found a match after the last column, use it.
+ */
+ if (next_match_idx >= 0 && next_match_col >= (int)current_col
+ && next_match_col != MAXCOL)
+ (void)push_next_match(NULL);
+
+ current_finished = TRUE;
+ current_state_stored = FALSE;
+ return 0;
+ }
+
+ /* if the current or next character is NUL, we will finish the line now */
+ if (line[current_col] == NUL || line[current_col + 1] == NUL)
+ {
+ current_finished = TRUE;
+ current_state_stored = FALSE;
+ }
+
+ /*
+ * When in the previous column there was a match but it could not be used
+ * (empty match or already matched in this column) need to try again in
+ * the next column.
+ */
+ if (try_next_column)
+ {
+ next_match_idx = -1;
+ try_next_column = FALSE;
+ }
+
+ /* Only check for keywords when not syncing and there are some. */
+ do_keywords = !syncing
+ && (syn_block->b_keywtab.ht_used > 0
+ || syn_block->b_keywtab_ic.ht_used > 0);
+
+ /* Init the list of zero-width matches with a nextlist. This is used to
+ * avoid matching the same item in the same position twice. */
+ ga_init2(&zero_width_next_ga, (int)sizeof(int), 10);
+
+ /* use syntax iskeyword option */
+ save_chartab(buf_chartab);
+
+ /*
+ * Repeat matching keywords and patterns, to find contained items at the
+ * same column. This stops when there are no extra matches at the current
+ * column.
+ */
+ do
+ {
+ found_match = FALSE;
+ keep_next_list = FALSE;
+ syn_id = 0;
+
+
+ /*
+ * 1. Check for a current state.
+ * Only when there is no current state, or if the current state may
+ * contain other things, we need to check for keywords and patterns.
+ * Always need to check for contained items if some item has the
+ * "containedin" argument (takes extra time!).
+ */
+ if (current_state.ga_len)
+ cur_si = &CUR_STATE(current_state.ga_len - 1);
+ else
+ cur_si = NULL;
+
+ if (syn_block->b_syn_containedin || cur_si == NULL
+ || cur_si->si_cont_list != NULL)
+ {
+ /*
+ * 2. Check for keywords, if on a keyword char after a non-keyword
+ * char. Don't do this when syncing.
+ */
+ if (do_keywords)
+ {
+ line = syn_getcurline();
+ if (vim_iswordp_buf(line + current_col, syn_buf)
+ && (current_col == 0
+ || !vim_iswordp_buf(line + current_col - 1
+ - (has_mbyte
+ ? (*mb_head_off)(line, line + current_col - 1)
+ : 0) , syn_buf)))
+ {
+ syn_id = check_keyword_id(line, (int)current_col,
+ &endcol, &flags, &next_list, cur_si,
+ &cchar);
+ if (syn_id != 0)
+ {
+ if (push_current_state(KEYWORD_IDX) == OK)
+ {
+ cur_si = &CUR_STATE(current_state.ga_len - 1);
+ cur_si->si_m_startcol = current_col;
+ cur_si->si_h_startpos.lnum = current_lnum;
+ cur_si->si_h_startpos.col = 0; /* starts right away */
+ cur_si->si_m_endpos.lnum = current_lnum;
+ cur_si->si_m_endpos.col = endcol;
+ cur_si->si_h_endpos.lnum = current_lnum;
+ cur_si->si_h_endpos.col = endcol;
+ cur_si->si_ends = TRUE;
+ cur_si->si_end_idx = 0;
+ cur_si->si_flags = flags;
+#ifdef FEAT_CONCEAL
+ cur_si->si_seqnr = next_seqnr++;
+ cur_si->si_cchar = cchar;
+ if (current_state.ga_len > 1)
+ cur_si->si_flags |=
+ CUR_STATE(current_state.ga_len - 2).si_flags
+ & HL_CONCEAL;
+#endif
+ cur_si->si_id = syn_id;
+ cur_si->si_trans_id = syn_id;
+ if (flags & HL_TRANSP)
+ {
+ if (current_state.ga_len < 2)
+ {
+ cur_si->si_attr = 0;
+ cur_si->si_trans_id = 0;
+ }
+ else
+ {
+ cur_si->si_attr = CUR_STATE(
+ current_state.ga_len - 2).si_attr;
+ cur_si->si_trans_id = CUR_STATE(
+ current_state.ga_len - 2).si_trans_id;
+ }
+ }
+ else
+ cur_si->si_attr = syn_id2attr(syn_id);
+ cur_si->si_cont_list = NULL;
+ cur_si->si_next_list = next_list;
+ check_keepend();
+ }
+ else
+ vim_free(next_list);
+ }
+ }
+ }
+
+ /*
+ * 3. Check for patterns (only if no keyword found).
+ */
+ if (syn_id == 0 && syn_block->b_syn_patterns.ga_len)
+ {
+ /*
+ * If we didn't check for a match yet, or we are past it, check
+ * for any match with a pattern.
+ */
+ if (next_match_idx < 0 || next_match_col < (int)current_col)
+ {
+ /*
+ * Check all relevant patterns for a match at this
+ * position. This is complicated, because matching with a
+ * pattern takes quite a bit of time, thus we want to
+ * avoid doing it when it's not needed.
+ */
+ next_match_idx = 0; /* no match in this line yet */
+ next_match_col = MAXCOL;
+ for (idx = syn_block->b_syn_patterns.ga_len; --idx >= 0; )
+ {
+ spp = &(SYN_ITEMS(syn_block)[idx]);
+ if ( spp->sp_syncing == syncing
+ && (displaying || !(spp->sp_flags & HL_DISPLAY))
+ && (spp->sp_type == SPTYPE_MATCH
+ || spp->sp_type == SPTYPE_START)
+ && (current_next_list != NULL
+ ? in_id_list(NULL, current_next_list,
+ &spp->sp_syn, 0)
+ : (cur_si == NULL
+ ? !(spp->sp_flags & HL_CONTAINED)
+ : in_id_list(cur_si,
+ cur_si->si_cont_list, &spp->sp_syn,
+ spp->sp_flags & HL_CONTAINED))))
+ {
+ int r;
+
+ /* If we already tried matching in this line, and
+ * there isn't a match before next_match_col, skip
+ * this item. */
+ if (spp->sp_line_id == current_line_id
+ && spp->sp_startcol >= next_match_col)
+ continue;
+ spp->sp_line_id = current_line_id;
+
+ lc_col = current_col - spp->sp_offsets[SPO_LC_OFF];
+ if (lc_col < 0)
+ lc_col = 0;
+
+ regmatch.rmm_ic = spp->sp_ic;
+ regmatch.regprog = spp->sp_prog;
+ r = syn_regexec(&regmatch,
+ current_lnum,
+ (colnr_T)lc_col,
+ IF_SYN_TIME(&spp->sp_time));
+ spp->sp_prog = regmatch.regprog;
+ if (!r)
+ {
+ /* no match in this line, try another one */
+ spp->sp_startcol = MAXCOL;
+ continue;
+ }
+
+ /*
+ * Compute the first column of the match.
+ */
+ syn_add_start_off(&pos, &regmatch,
+ spp, SPO_MS_OFF, -1);
+ if (pos.lnum > current_lnum)
+ {
+ /* must have used end of match in a next line,
+ * we can't handle that */
+ spp->sp_startcol = MAXCOL;
+ continue;
+ }
+ startcol = pos.col;
+
+ /* remember the next column where this pattern
+ * matches in the current line */
+ spp->sp_startcol = startcol;
+
+ /*
+ * If a previously found match starts at a lower
+ * column number, don't use this one.
+ */
+ if (startcol >= next_match_col)
+ continue;
+
+ /*
+ * If we matched this pattern at this position
+ * before, skip it. Must retry in the next
+ * column, because it may match from there.
+ */
+ if (did_match_already(idx, &zero_width_next_ga))
+ {
+ try_next_column = TRUE;
+ continue;
+ }
+
+ endpos.lnum = regmatch.endpos[0].lnum;
+ endpos.col = regmatch.endpos[0].col;
+
+ /* Compute the highlight start. */
+ syn_add_start_off(&hl_startpos, &regmatch,
+ spp, SPO_HS_OFF, -1);
+
+ /* Compute the region start. */
+ /* Default is to use the end of the match. */
+ syn_add_end_off(&eos_pos, &regmatch,
+ spp, SPO_RS_OFF, 0);
+
+ /*
+ * Grab the external submatches before they get
+ * overwritten. Reference count doesn't change.
+ */
+ unref_extmatch(cur_extmatch);
+ cur_extmatch = re_extmatch_out;
+ re_extmatch_out = NULL;
+
+ flags = 0;
+ eoe_pos.lnum = 0; /* avoid warning */
+ eoe_pos.col = 0;
+ end_idx = 0;
+ hl_endpos.lnum = 0;
+
+ /*
+ * For a "oneline" the end must be found in the
+ * same line too. Search for it after the end of
+ * the match with the start pattern. Set the
+ * resulting end positions at the same time.
+ */
+ if (spp->sp_type == SPTYPE_START
+ && (spp->sp_flags & HL_ONELINE))
+ {
+ lpos_T startpos;
+
+ startpos = endpos;
+ find_endpos(idx, &startpos, &endpos, &hl_endpos,
+ &flags, &eoe_pos, &end_idx, cur_extmatch);
+ if (endpos.lnum == 0)
+ continue; /* not found */
+ }
+
+ /*
+ * For a "match" the size must be > 0 after the
+ * end offset needs has been added. Except when
+ * syncing.
+ */
+ else if (spp->sp_type == SPTYPE_MATCH)
+ {
+ syn_add_end_off(&hl_endpos, &regmatch, spp,
+ SPO_HE_OFF, 0);
+ syn_add_end_off(&endpos, &regmatch, spp,
+ SPO_ME_OFF, 0);
+ if (endpos.lnum == current_lnum
+ && (int)endpos.col + syncing < startcol)
+ {
+ /*
+ * If an empty string is matched, may need
+ * to try matching again at next column.
+ */
+ if (regmatch.startpos[0].col
+ == regmatch.endpos[0].col)
+ try_next_column = TRUE;
+ continue;
+ }
+ }
+
+ /*
+ * keep the best match so far in next_match_*
+ */
+ /* Highlighting must start after startpos and end
+ * before endpos. */
+ if (hl_startpos.lnum == current_lnum
+ && (int)hl_startpos.col < startcol)
+ hl_startpos.col = startcol;
+ limit_pos_zero(&hl_endpos, &endpos);
+
+ next_match_idx = idx;
+ next_match_col = startcol;
+ next_match_m_endpos = endpos;
+ next_match_h_endpos = hl_endpos;
+ next_match_h_startpos = hl_startpos;
+ next_match_flags = flags;
+ next_match_eos_pos = eos_pos;
+ next_match_eoe_pos = eoe_pos;
+ next_match_end_idx = end_idx;
+ unref_extmatch(next_match_extmatch);
+ next_match_extmatch = cur_extmatch;
+ cur_extmatch = NULL;
+ }
+ }
+ }
+
+ /*
+ * If we found a match at the current column, use it.
+ */
+ if (next_match_idx >= 0 && next_match_col == (int)current_col)
+ {
+ synpat_T *lspp;
+
+ /* When a zero-width item matched which has a nextgroup,
+ * don't push the item but set nextgroup. */
+ lspp = &(SYN_ITEMS(syn_block)[next_match_idx]);
+ if (next_match_m_endpos.lnum == current_lnum
+ && next_match_m_endpos.col == current_col
+ && lspp->sp_next_list != NULL)
+ {
+ current_next_list = lspp->sp_next_list;
+ current_next_flags = lspp->sp_flags;
+ keep_next_list = TRUE;
+ zero_width_next_list = TRUE;
+
+ /* Add the index to a list, so that we can check
+ * later that we don't match it again (and cause an
+ * endless loop). */
+ if (ga_grow(&zero_width_next_ga, 1) == OK)
+ {
+ ((int *)(zero_width_next_ga.ga_data))
+ [zero_width_next_ga.ga_len++] = next_match_idx;
+ }
+ next_match_idx = -1;
+ }
+ else
+ cur_si = push_next_match(cur_si);
+ found_match = TRUE;
+ }
+ }
+ }
+
+ /*
+ * Handle searching for nextgroup match.
+ */
+ if (current_next_list != NULL && !keep_next_list)
+ {
+ /*
+ * If a nextgroup was not found, continue looking for one if:
+ * - this is an empty line and the "skipempty" option was given
+ * - we are on white space and the "skipwhite" option was given
+ */
+ if (!found_match)
+ {
+ line = syn_getcurline();
+ if (((current_next_flags & HL_SKIPWHITE)
+ && VIM_ISWHITE(line[current_col]))
+ || ((current_next_flags & HL_SKIPEMPTY)
+ && *line == NUL))
+ break;
+ }
+
+ /*
+ * If a nextgroup was found: Use it, and continue looking for
+ * contained matches.
+ * If a nextgroup was not found: Continue looking for a normal
+ * match.
+ * When did set current_next_list for a zero-width item and no
+ * match was found don't loop (would get stuck).
+ */
+ current_next_list = NULL;
+ next_match_idx = -1;
+ if (!zero_width_next_list)
+ found_match = TRUE;
+ }
+
+ } while (found_match);
+
+ restore_chartab(buf_chartab);
+
+ /*
+ * Use attributes from the current state, if within its highlighting.
+ * If not, use attributes from the current-but-one state, etc.
+ */
+ current_attr = 0;
+#ifdef FEAT_EVAL
+ current_id = 0;
+ current_trans_id = 0;
+#endif
+#ifdef FEAT_CONCEAL
+ current_flags = 0;
+ current_seqnr = 0;
+#endif
+ if (cur_si != NULL)
+ {
+#ifndef FEAT_EVAL
+ int current_trans_id = 0;
+#endif
+ for (idx = current_state.ga_len - 1; idx >= 0; --idx)
+ {
+ sip = &CUR_STATE(idx);
+ if ((current_lnum > sip->si_h_startpos.lnum
+ || (current_lnum == sip->si_h_startpos.lnum
+ && current_col >= sip->si_h_startpos.col))
+ && (sip->si_h_endpos.lnum == 0
+ || current_lnum < sip->si_h_endpos.lnum
+ || (current_lnum == sip->si_h_endpos.lnum
+ && current_col < sip->si_h_endpos.col)))
+ {
+ current_attr = sip->si_attr;
+#ifdef FEAT_EVAL
+ current_id = sip->si_id;
+#endif
+ current_trans_id = sip->si_trans_id;
+#ifdef FEAT_CONCEAL
+ current_flags = sip->si_flags;
+ current_seqnr = sip->si_seqnr;
+ current_sub_char = sip->si_cchar;
+#endif
+ break;
+ }
+ }
+
+ if (can_spell != NULL)
+ {
+ struct sp_syn sps;
+
+ /*
+ * set "can_spell" to TRUE if spell checking is supposed to be
+ * done in the current item.
+ */
+ if (syn_block->b_spell_cluster_id == 0)
+ {
+ /* There is no @Spell cluster: Do spelling for items without
+ * @NoSpell cluster. */
+ if (syn_block->b_nospell_cluster_id == 0
+ || current_trans_id == 0)
+ *can_spell = (syn_block->b_syn_spell != SYNSPL_NOTOP);
+ else
+ {
+ sps.inc_tag = 0;
+ sps.id = syn_block->b_nospell_cluster_id;
+ sps.cont_in_list = NULL;
+ *can_spell = !in_id_list(sip, sip->si_cont_list, &sps, 0);
+ }
+ }
+ else
+ {
+ /* The @Spell cluster is defined: Do spelling in items with
+ * the @Spell cluster. But not when @NoSpell is also there.
+ * At the toplevel only spell check when ":syn spell toplevel"
+ * was used. */
+ if (current_trans_id == 0)
+ *can_spell = (syn_block->b_syn_spell == SYNSPL_TOP);
+ else
+ {
+ sps.inc_tag = 0;
+ sps.id = syn_block->b_spell_cluster_id;
+ sps.cont_in_list = NULL;
+ *can_spell = in_id_list(sip, sip->si_cont_list, &sps, 0);
+
+ if (syn_block->b_nospell_cluster_id != 0)
+ {
+ sps.id = syn_block->b_nospell_cluster_id;
+ if (in_id_list(sip, sip->si_cont_list, &sps, 0))
+ *can_spell = FALSE;
+ }
+ }
+ }
+ }
+
+
+ /*
+ * Check for end of current state (and the states before it) at the
+ * next column. Don't do this for syncing, because we would miss a
+ * single character match.
+ * First check if the current state ends at the current column. It
+ * may be for an empty match and a containing item might end in the
+ * current column.
+ */
+ if (!syncing && !keep_state)
+ {
+ check_state_ends();
+ if (current_state.ga_len > 0
+ && syn_getcurline()[current_col] != NUL)
+ {
+ ++current_col;
+ check_state_ends();
+ --current_col;
+ }
+ }
+ }
+ else if (can_spell != NULL)
+ /* Default: Only do spelling when there is no @Spell cluster or when
+ * ":syn spell toplevel" was used. */
+ *can_spell = syn_block->b_syn_spell == SYNSPL_DEFAULT
+ ? (syn_block->b_spell_cluster_id == 0)
+ : (syn_block->b_syn_spell == SYNSPL_TOP);
+
+ /* nextgroup ends at end of line, unless "skipnl" or "skipempty" present */
+ if (current_next_list != NULL
+ && (line = syn_getcurline())[current_col] != NUL
+ && line[current_col + 1] == NUL
+ && !(current_next_flags & (HL_SKIPNL | HL_SKIPEMPTY)))
+ current_next_list = NULL;
+
+ if (zero_width_next_ga.ga_len > 0)
+ ga_clear(&zero_width_next_ga);
+
+ /* No longer need external matches. But keep next_match_extmatch. */
+ unref_extmatch(re_extmatch_out);
+ re_extmatch_out = NULL;
+ unref_extmatch(cur_extmatch);
+
+ return current_attr;
+}
+
+
+/*
+ * Check if we already matched pattern "idx" at the current column.
+ */
+ static int
+did_match_already(int idx, garray_T *gap)
+{
+ int i;
+
+ for (i = current_state.ga_len; --i >= 0; )
+ if (CUR_STATE(i).si_m_startcol == (int)current_col
+ && CUR_STATE(i).si_m_lnum == (int)current_lnum
+ && CUR_STATE(i).si_idx == idx)
+ return TRUE;
+
+ /* Zero-width matches with a nextgroup argument are not put on the syntax
+ * stack, and can only be matched once anyway. */
+ for (i = gap->ga_len; --i >= 0; )
+ if (((int *)(gap->ga_data))[i] == idx)
+ return TRUE;
+
+ return FALSE;
+}
+
+/*
+ * Push the next match onto the stack.
+ */
+ static stateitem_T *
+push_next_match(stateitem_T *cur_si)
+{
+ synpat_T *spp;
+#ifdef FEAT_CONCEAL
+ int save_flags;
+#endif
+
+ spp = &(SYN_ITEMS(syn_block)[next_match_idx]);
+
+ /*
+ * Push the item in current_state stack;
+ */
+ if (push_current_state(next_match_idx) == OK)
+ {
+ /*
+ * If it's a start-skip-end type that crosses lines, figure out how
+ * much it continues in this line. Otherwise just fill in the length.
+ */
+ cur_si = &CUR_STATE(current_state.ga_len - 1);
+ cur_si->si_h_startpos = next_match_h_startpos;
+ cur_si->si_m_startcol = current_col;
+ cur_si->si_m_lnum = current_lnum;
+ cur_si->si_flags = spp->sp_flags;
+#ifdef FEAT_CONCEAL
+ cur_si->si_seqnr = next_seqnr++;
+ cur_si->si_cchar = spp->sp_cchar;
+ if (current_state.ga_len > 1)
+ cur_si->si_flags |=
+ CUR_STATE(current_state.ga_len - 2).si_flags & HL_CONCEAL;
+#endif
+ cur_si->si_next_list = spp->sp_next_list;
+ cur_si->si_extmatch = ref_extmatch(next_match_extmatch);
+ if (spp->sp_type == SPTYPE_START && !(spp->sp_flags & HL_ONELINE))
+ {
+ /* Try to find the end pattern in the current line */
+ update_si_end(cur_si, (int)(next_match_m_endpos.col), TRUE);
+ check_keepend();
+ }
+ else
+ {
+ cur_si->si_m_endpos = next_match_m_endpos;
+ cur_si->si_h_endpos = next_match_h_endpos;
+ cur_si->si_ends = TRUE;
+ cur_si->si_flags |= next_match_flags;
+ cur_si->si_eoe_pos = next_match_eoe_pos;
+ cur_si->si_end_idx = next_match_end_idx;
+ }
+ if (keepend_level < 0 && (cur_si->si_flags & HL_KEEPEND))
+ keepend_level = current_state.ga_len - 1;
+ check_keepend();
+ update_si_attr(current_state.ga_len - 1);
+
+#ifdef FEAT_CONCEAL
+ save_flags = cur_si->si_flags & (HL_CONCEAL | HL_CONCEALENDS);
+#endif
+ /*
+ * If the start pattern has another highlight group, push another item
+ * on the stack for the start pattern.
+ */
+ if ( spp->sp_type == SPTYPE_START
+ && spp->sp_syn_match_id != 0
+ && push_current_state(next_match_idx) == OK)
+ {
+ cur_si = &CUR_STATE(current_state.ga_len - 1);
+ cur_si->si_h_startpos = next_match_h_startpos;
+ cur_si->si_m_startcol = current_col;
+ cur_si->si_m_lnum = current_lnum;
+ cur_si->si_m_endpos = next_match_eos_pos;
+ cur_si->si_h_endpos = next_match_eos_pos;
+ cur_si->si_ends = TRUE;
+ cur_si->si_end_idx = 0;
+ cur_si->si_flags = HL_MATCH;
+#ifdef FEAT_CONCEAL
+ cur_si->si_seqnr = next_seqnr++;
+ cur_si->si_flags |= save_flags;
+ if (cur_si->si_flags & HL_CONCEALENDS)
+ cur_si->si_flags |= HL_CONCEAL;
+#endif
+ cur_si->si_next_list = NULL;
+ check_keepend();
+ update_si_attr(current_state.ga_len - 1);
+ }
+ }
+
+ next_match_idx = -1; /* try other match next time */
+
+ return cur_si;
+}
+
+/*
+ * Check for end of current state (and the states before it).
+ */
+ static void
+check_state_ends(void)
+{
+ stateitem_T *cur_si;
+ int had_extend;
+
+ cur_si = &CUR_STATE(current_state.ga_len - 1);
+ for (;;)
+ {
+ if (cur_si->si_ends
+ && (cur_si->si_m_endpos.lnum < current_lnum
+ || (cur_si->si_m_endpos.lnum == current_lnum
+ && cur_si->si_m_endpos.col <= current_col)))
+ {
+ /*
+ * If there is an end pattern group ID, highlight the end pattern
+ * now. No need to pop the current item from the stack.
+ * Only do this if the end pattern continues beyond the current
+ * position.
+ */
+ if (cur_si->si_end_idx
+ && (cur_si->si_eoe_pos.lnum > current_lnum
+ || (cur_si->si_eoe_pos.lnum == current_lnum
+ && cur_si->si_eoe_pos.col > current_col)))
+ {
+ cur_si->si_idx = cur_si->si_end_idx;
+ cur_si->si_end_idx = 0;
+ cur_si->si_m_endpos = cur_si->si_eoe_pos;
+ cur_si->si_h_endpos = cur_si->si_eoe_pos;
+ cur_si->si_flags |= HL_MATCH;
+#ifdef FEAT_CONCEAL
+ cur_si->si_seqnr = next_seqnr++;
+ if (cur_si->si_flags & HL_CONCEALENDS)
+ cur_si->si_flags |= HL_CONCEAL;
+#endif
+ update_si_attr(current_state.ga_len - 1);
+
+ /* nextgroup= should not match in the end pattern */
+ current_next_list = NULL;
+
+ /* what matches next may be different now, clear it */
+ next_match_idx = 0;
+ next_match_col = MAXCOL;
+ break;
+ }
+ else
+ {
+ /* handle next_list, unless at end of line and no "skipnl" or
+ * "skipempty" */
+ current_next_list = cur_si->si_next_list;
+ current_next_flags = cur_si->si_flags;
+ if (!(current_next_flags & (HL_SKIPNL | HL_SKIPEMPTY))
+ && syn_getcurline()[current_col] == NUL)
+ current_next_list = NULL;
+
+ /* When the ended item has "extend", another item with
+ * "keepend" now needs to check for its end. */
+ had_extend = (cur_si->si_flags & HL_EXTEND);
+
+ pop_current_state();
+
+ if (current_state.ga_len == 0)
+ break;
+
+ if (had_extend && keepend_level >= 0)
+ {
+ syn_update_ends(FALSE);
+ if (current_state.ga_len == 0)
+ break;
+ }
+
+ cur_si = &CUR_STATE(current_state.ga_len - 1);
+
+ /*
+ * Only for a region the search for the end continues after
+ * the end of the contained item. If the contained match
+ * included the end-of-line, break here, the region continues.
+ * Don't do this when:
+ * - "keepend" is used for the contained item
+ * - not at the end of the line (could be end="x$"me=e-1).
+ * - "excludenl" is used (HL_HAS_EOL won't be set)
+ */
+ if (cur_si->si_idx >= 0
+ && SYN_ITEMS(syn_block)[cur_si->si_idx].sp_type
+ == SPTYPE_START
+ && !(cur_si->si_flags & (HL_MATCH | HL_KEEPEND)))
+ {
+ update_si_end(cur_si, (int)current_col, TRUE);
+ check_keepend();
+ if ((current_next_flags & HL_HAS_EOL)
+ && keepend_level < 0
+ && syn_getcurline()[current_col] == NUL)
+ break;
+ }
+ }
+ }
+ else
+ break;
+ }
+}
+
+/*
+ * Update an entry in the current_state stack for a match or region. This
+ * fills in si_attr, si_next_list and si_cont_list.
+ */
+ static void
+update_si_attr(int idx)
+{
+ stateitem_T *sip = &CUR_STATE(idx);
+ synpat_T *spp;
+
+ /* This should not happen... */
+ if (sip->si_idx < 0)
+ return;
+
+ spp = &(SYN_ITEMS(syn_block)[sip->si_idx]);
+ if (sip->si_flags & HL_MATCH)
+ sip->si_id = spp->sp_syn_match_id;
+ else
+ sip->si_id = spp->sp_syn.id;
+ sip->si_attr = syn_id2attr(sip->si_id);
+ sip->si_trans_id = sip->si_id;
+ if (sip->si_flags & HL_MATCH)
+ sip->si_cont_list = NULL;
+ else
+ sip->si_cont_list = spp->sp_cont_list;
+
+ /*
+ * For transparent items, take attr from outer item.
+ * Also take cont_list, if there is none.
+ * Don't do this for the matchgroup of a start or end pattern.
+ */
+ if ((spp->sp_flags & HL_TRANSP) && !(sip->si_flags & HL_MATCH))
+ {
+ if (idx == 0)
+ {
+ sip->si_attr = 0;
+ sip->si_trans_id = 0;
+ if (sip->si_cont_list == NULL)
+ sip->si_cont_list = ID_LIST_ALL;
+ }
+ else
+ {
+ sip->si_attr = CUR_STATE(idx - 1).si_attr;
+ sip->si_trans_id = CUR_STATE(idx - 1).si_trans_id;
+ sip->si_h_startpos = CUR_STATE(idx - 1).si_h_startpos;
+ sip->si_h_endpos = CUR_STATE(idx - 1).si_h_endpos;
+ if (sip->si_cont_list == NULL)
+ {
+ sip->si_flags |= HL_TRANS_CONT;
+ sip->si_cont_list = CUR_STATE(idx - 1).si_cont_list;
+ }
+ }
+ }
+}
+
+/*
+ * Check the current stack for patterns with "keepend" flag.
+ * Propagate the match-end to contained items, until a "skipend" item is found.
+ */
+ static void
+check_keepend(void)
+{
+ int i;
+ lpos_T maxpos;
+ lpos_T maxpos_h;
+ stateitem_T *sip;
+
+ /*
+ * This check can consume a lot of time; only do it from the level where
+ * there really is a keepend.
+ */
+ if (keepend_level < 0)
+ return;
+
+ /*
+ * Find the last index of an "extend" item. "keepend" items before that
+ * won't do anything. If there is no "extend" item "i" will be
+ * "keepend_level" and all "keepend" items will work normally.
+ */
+ for (i = current_state.ga_len - 1; i > keepend_level; --i)
+ if (CUR_STATE(i).si_flags & HL_EXTEND)
+ break;
+
+ maxpos.lnum = 0;
+ maxpos.col = 0;
+ maxpos_h.lnum = 0;
+ maxpos_h.col = 0;
+ for ( ; i < current_state.ga_len; ++i)
+ {
+ sip = &CUR_STATE(i);
+ if (maxpos.lnum != 0)
+ {
+ limit_pos_zero(&sip->si_m_endpos, &maxpos);
+ limit_pos_zero(&sip->si_h_endpos, &maxpos_h);
+ limit_pos_zero(&sip->si_eoe_pos, &maxpos);
+ sip->si_ends = TRUE;
+ }
+ if (sip->si_ends && (sip->si_flags & HL_KEEPEND))
+ {
+ if (maxpos.lnum == 0
+ || maxpos.lnum > sip->si_m_endpos.lnum
+ || (maxpos.lnum == sip->si_m_endpos.lnum
+ && maxpos.col > sip->si_m_endpos.col))
+ maxpos = sip->si_m_endpos;
+ if (maxpos_h.lnum == 0
+ || maxpos_h.lnum > sip->si_h_endpos.lnum
+ || (maxpos_h.lnum == sip->si_h_endpos.lnum
+ && maxpos_h.col > sip->si_h_endpos.col))
+ maxpos_h = sip->si_h_endpos;
+ }
+ }
+}
+
+/*
+ * Update an entry in the current_state stack for a start-skip-end pattern.
+ * This finds the end of the current item, if it's in the current line.
+ *
+ * Return the flags for the matched END.
+ */
+ static void
+update_si_end(
+ stateitem_T *sip,
+ int startcol, /* where to start searching for the end */
+ int force) /* when TRUE overrule a previous end */
+{
+ lpos_T startpos;
+ lpos_T endpos;
+ lpos_T hl_endpos;
+ lpos_T end_endpos;
+ int end_idx;
+
+ /* return quickly for a keyword */
+ if (sip->si_idx < 0)
+ return;
+
+ /* Don't update when it's already done. Can be a match of an end pattern
+ * that started in a previous line. Watch out: can also be a "keepend"
+ * from a containing item. */
+ if (!force && sip->si_m_endpos.lnum >= current_lnum)
+ return;
+
+ /*
+ * We need to find the end of the region. It may continue in the next
+ * line.
+ */
+ end_idx = 0;
+ startpos.lnum = current_lnum;
+ startpos.col = startcol;
+ find_endpos(sip->si_idx, &startpos, &endpos, &hl_endpos,
+ &(sip->si_flags), &end_endpos, &end_idx, sip->si_extmatch);
+
+ if (endpos.lnum == 0)
+ {
+ /* No end pattern matched. */
+ if (SYN_ITEMS(syn_block)[sip->si_idx].sp_flags & HL_ONELINE)
+ {
+ /* a "oneline" never continues in the next line */
+ sip->si_ends = TRUE;
+ sip->si_m_endpos.lnum = current_lnum;
+ sip->si_m_endpos.col = (colnr_T)STRLEN(syn_getcurline());
+ }
+ else
+ {
+ /* continues in the next line */
+ sip->si_ends = FALSE;
+ sip->si_m_endpos.lnum = 0;
+ }
+ sip->si_h_endpos = sip->si_m_endpos;
+ }
+ else
+ {
+ /* match within this line */
+ sip->si_m_endpos = endpos;
+ sip->si_h_endpos = hl_endpos;
+ sip->si_eoe_pos = end_endpos;
+ sip->si_ends = TRUE;
+ sip->si_end_idx = end_idx;
+ }
+}
+
+/*
+ * Add a new state to the current state stack.
+ * It is cleared and the index set to "idx".
+ * Return FAIL if it's not possible (out of memory).
+ */
+ static int
+push_current_state(int idx)
+{
+ if (ga_grow(&current_state, 1) == FAIL)
+ return FAIL;
+ vim_memset(&CUR_STATE(current_state.ga_len), 0, sizeof(stateitem_T));
+ CUR_STATE(current_state.ga_len).si_idx = idx;
+ ++current_state.ga_len;
+ return OK;
+}
+
+/*
+ * Remove a state from the current_state stack.
+ */
+ static void
+pop_current_state(void)
+{
+ if (current_state.ga_len)
+ {
+ unref_extmatch(CUR_STATE(current_state.ga_len - 1).si_extmatch);
+ --current_state.ga_len;
+ }
+ /* after the end of a pattern, try matching a keyword or pattern */
+ next_match_idx = -1;
+
+ /* if first state with "keepend" is popped, reset keepend_level */
+ if (keepend_level >= current_state.ga_len)
+ keepend_level = -1;
+}
+
+/*
+ * Find the end of a start/skip/end syntax region after "startpos".
+ * Only checks one line.
+ * Also handles a match item that continued from a previous line.
+ * If not found, the syntax item continues in the next line. m_endpos->lnum
+ * will be 0.
+ * If found, the end of the region and the end of the highlighting is
+ * computed.
+ */
+ static void
+find_endpos(
+ int idx, /* index of the pattern */
+ lpos_T *startpos, /* where to start looking for an END match */
+ lpos_T *m_endpos, /* return: end of match */
+ lpos_T *hl_endpos, /* return: end of highlighting */
+ long *flagsp, /* return: flags of matching END */
+ lpos_T *end_endpos, /* return: end of end pattern match */
+ int *end_idx, /* return: group ID for end pat. match, or 0 */
+ reg_extmatch_T *start_ext) /* submatches from the start pattern */
+{
+ colnr_T matchcol;
+ synpat_T *spp, *spp_skip;
+ int start_idx;
+ int best_idx;
+ regmmatch_T regmatch;
+ regmmatch_T best_regmatch; /* startpos/endpos of best match */
+ lpos_T pos;
+ char_u *line;
+ int had_match = FALSE;
+ char_u buf_chartab[32]; /* chartab array for syn option iskyeyword */
+
+ /* just in case we are invoked for a keyword */
+ if (idx < 0)
+ return;
+
+ /*
+ * Check for being called with a START pattern.
+ * Can happen with a match that continues to the next line, because it
+ * contained a region.
+ */
+ spp = &(SYN_ITEMS(syn_block)[idx]);
+ if (spp->sp_type != SPTYPE_START)
+ {
+ *hl_endpos = *startpos;
+ return;
+ }
+
+ /*
+ * Find the SKIP or first END pattern after the last START pattern.
+ */
+ for (;;)
+ {
+ spp = &(SYN_ITEMS(syn_block)[idx]);
+ if (spp->sp_type != SPTYPE_START)
+ break;
+ ++idx;
+ }
+
+ /*
+ * Lookup the SKIP pattern (if present)
+ */
+ if (spp->sp_type == SPTYPE_SKIP)
+ {
+ spp_skip = spp;
+ ++idx;
+ }
+ else
+ spp_skip = NULL;
+
+ /* Setup external matches for syn_regexec(). */
+ unref_extmatch(re_extmatch_in);
+ re_extmatch_in = ref_extmatch(start_ext);
+
+ matchcol = startpos->col; /* start looking for a match at sstart */
+ start_idx = idx; /* remember the first END pattern. */
+ best_regmatch.startpos[0].col = 0; /* avoid compiler warning */
+
+ /* use syntax iskeyword option */
+ save_chartab(buf_chartab);
+
+ for (;;)
+ {
+ /*
+ * Find end pattern that matches first after "matchcol".
+ */
+ best_idx = -1;
+ for (idx = start_idx; idx < syn_block->b_syn_patterns.ga_len; ++idx)
+ {
+ int lc_col = matchcol;
+ int r;
+
+ spp = &(SYN_ITEMS(syn_block)[idx]);
+ if (spp->sp_type != SPTYPE_END) /* past last END pattern */
+ break;
+ lc_col -= spp->sp_offsets[SPO_LC_OFF];
+ if (lc_col < 0)
+ lc_col = 0;
+
+ regmatch.rmm_ic = spp->sp_ic;
+ regmatch.regprog = spp->sp_prog;
+ r = syn_regexec(&regmatch, startpos->lnum, lc_col,
+ IF_SYN_TIME(&spp->sp_time));
+ spp->sp_prog = regmatch.regprog;
+ if (r)
+ {
+ if (best_idx == -1 || regmatch.startpos[0].col
+ < best_regmatch.startpos[0].col)
+ {
+ best_idx = idx;
+ best_regmatch.startpos[0] = regmatch.startpos[0];
+ best_regmatch.endpos[0] = regmatch.endpos[0];
+ }
+ }
+ }
+
+ /*
+ * If all end patterns have been tried, and there is no match, the
+ * item continues until end-of-line.
+ */
+ if (best_idx == -1)
+ break;
+
+ /*
+ * If the skip pattern matches before the end pattern,
+ * continue searching after the skip pattern.
+ */
+ if (spp_skip != NULL)
+ {
+ int lc_col = matchcol - spp_skip->sp_offsets[SPO_LC_OFF];
+ int r;
+
+ if (lc_col < 0)
+ lc_col = 0;
+ regmatch.rmm_ic = spp_skip->sp_ic;
+ regmatch.regprog = spp_skip->sp_prog;
+ r = syn_regexec(&regmatch, startpos->lnum, lc_col,
+ IF_SYN_TIME(&spp_skip->sp_time));
+ spp_skip->sp_prog = regmatch.regprog;
+ if (r && regmatch.startpos[0].col
+ <= best_regmatch.startpos[0].col)
+ {
+ int line_len;
+
+ /* Add offset to skip pattern match */
+ syn_add_end_off(&pos, &regmatch, spp_skip, SPO_ME_OFF, 1);
+
+ /* If the skip pattern goes on to the next line, there is no
+ * match with an end pattern in this line. */
+ if (pos.lnum > startpos->lnum)
+ break;
+
+ line = ml_get_buf(syn_buf, startpos->lnum, FALSE);
+ line_len = (int)STRLEN(line);
+
+ /* take care of an empty match or negative offset */
+ if (pos.col <= matchcol)
+ ++matchcol;
+ else if (pos.col <= regmatch.endpos[0].col)
+ matchcol = pos.col;
+ else
+ /* Be careful not to jump over the NUL at the end-of-line */
+ for (matchcol = regmatch.endpos[0].col;
+ matchcol < line_len && matchcol < pos.col;
+ ++matchcol)
+ ;
+
+ /* if the skip pattern includes end-of-line, break here */
+ if (matchcol >= line_len)
+ break;
+
+ continue; /* start with first end pattern again */
+ }
+ }
+
+ /*
+ * Match from start pattern to end pattern.
+ * Correct for match and highlight offset of end pattern.
+ */
+ spp = &(SYN_ITEMS(syn_block)[best_idx]);
+ syn_add_end_off(m_endpos, &best_regmatch, spp, SPO_ME_OFF, 1);
+ /* can't end before the start */
+ if (m_endpos->lnum == startpos->lnum && m_endpos->col < startpos->col)
+ m_endpos->col = startpos->col;
+
+ syn_add_end_off(end_endpos, &best_regmatch, spp, SPO_HE_OFF, 1);
+ /* can't end before the start */
+ if (end_endpos->lnum == startpos->lnum
+ && end_endpos->col < startpos->col)
+ end_endpos->col = startpos->col;
+ /* can't end after the match */
+ limit_pos(end_endpos, m_endpos);
+
+ /*
+ * If the end group is highlighted differently, adjust the pointers.
+ */
+ if (spp->sp_syn_match_id != spp->sp_syn.id && spp->sp_syn_match_id != 0)
+ {
+ *end_idx = best_idx;
+ if (spp->sp_off_flags & (1 << (SPO_RE_OFF + SPO_COUNT)))
+ {
+ hl_endpos->lnum = best_regmatch.endpos[0].lnum;
+ hl_endpos->col = best_regmatch.endpos[0].col;
+ }
+ else
+ {
+ hl_endpos->lnum = best_regmatch.startpos[0].lnum;
+ hl_endpos->col = best_regmatch.startpos[0].col;
+ }
+ hl_endpos->col += spp->sp_offsets[SPO_RE_OFF];
+
+ /* can't end before the start */
+ if (hl_endpos->lnum == startpos->lnum
+ && hl_endpos->col < startpos->col)
+ hl_endpos->col = startpos->col;
+ limit_pos(hl_endpos, m_endpos);
+
+ /* now the match ends where the highlighting ends, it is turned
+ * into the matchgroup for the end */
+ *m_endpos = *hl_endpos;
+ }
+ else
+ {
+ *end_idx = 0;
+ *hl_endpos = *end_endpos;
+ }
+
+ *flagsp = spp->sp_flags;
+
+ had_match = TRUE;
+ break;
+ }
+
+ /* no match for an END pattern in this line */
+ if (!had_match)
+ m_endpos->lnum = 0;
+
+ restore_chartab(buf_chartab);
+
+ /* Remove external matches. */
+ unref_extmatch(re_extmatch_in);
+ re_extmatch_in = NULL;
+}
+
+/*
+ * Limit "pos" not to be after "limit".
+ */
+ static void
+limit_pos(lpos_T *pos, lpos_T *limit)
+{
+ if (pos->lnum > limit->lnum)
+ *pos = *limit;
+ else if (pos->lnum == limit->lnum && pos->col > limit->col)
+ pos->col = limit->col;
+}
+
+/*
+ * Limit "pos" not to be after "limit", unless pos->lnum is zero.
+ */
+ static void
+limit_pos_zero(
+ lpos_T *pos,
+ lpos_T *limit)
+{
+ if (pos->lnum == 0)
+ *pos = *limit;
+ else
+ limit_pos(pos, limit);
+}
+
+/*
+ * Add offset to matched text for end of match or highlight.
+ */
+ static void
+syn_add_end_off(
+ lpos_T *result, /* returned position */
+ regmmatch_T *regmatch, /* start/end of match */
+ synpat_T *spp, /* matched pattern */
+ int idx, /* index of offset */
+ int extra) /* extra chars for offset to start */
+{
+ int col;
+ int off;
+ char_u *base;
+ char_u *p;
+
+ if (spp->sp_off_flags & (1 << idx))
+ {
+ result->lnum = regmatch->startpos[0].lnum;
+ col = regmatch->startpos[0].col;
+ off = spp->sp_offsets[idx] + extra;
+ }
+ else
+ {
+ result->lnum = regmatch->endpos[0].lnum;
+ col = regmatch->endpos[0].col;
+ off = spp->sp_offsets[idx];
+ }
+ /* Don't go past the end of the line. Matters for "rs=e+2" when there
+ * is a matchgroup. Watch out for match with last NL in the buffer. */
+ if (result->lnum > syn_buf->b_ml.ml_line_count)
+ col = 0;
+ else if (off != 0)
+ {
+ base = ml_get_buf(syn_buf, result->lnum, FALSE);
+ p = base + col;
+ if (off > 0)
+ {
+ while (off-- > 0 && *p != NUL)
+ MB_PTR_ADV(p);
+ }
+ else if (off < 0)
+ {
+ while (off++ < 0 && base < p)
+ MB_PTR_BACK(base, p);
+ }
+ col = (int)(p - base);
+ }
+ result->col = col;
+}
+
+/*
+ * Add offset to matched text for start of match or highlight.
+ * Avoid resulting column to become negative.
+ */
+ static void
+syn_add_start_off(
+ lpos_T *result, /* returned position */
+ regmmatch_T *regmatch, /* start/end of match */
+ synpat_T *spp,
+ int idx,
+ int extra) /* extra chars for offset to end */
+{
+ int col;
+ int off;
+ char_u *base;
+ char_u *p;
+
+ if (spp->sp_off_flags & (1 << (idx + SPO_COUNT)))
+ {
+ result->lnum = regmatch->endpos[0].lnum;
+ col = regmatch->endpos[0].col;
+ off = spp->sp_offsets[idx] + extra;
+ }
+ else
+ {
+ result->lnum = regmatch->startpos[0].lnum;
+ col = regmatch->startpos[0].col;
+ off = spp->sp_offsets[idx];
+ }
+ if (result->lnum > syn_buf->b_ml.ml_line_count)
+ {
+ /* a "\n" at the end of the pattern may take us below the last line */
+ result->lnum = syn_buf->b_ml.ml_line_count;
+ col = (int)STRLEN(ml_get_buf(syn_buf, result->lnum, FALSE));
+ }
+ if (off != 0)
+ {
+ base = ml_get_buf(syn_buf, result->lnum, FALSE);
+ p = base + col;
+ if (off > 0)
+ {
+ while (off-- && *p != NUL)
+ MB_PTR_ADV(p);
+ }
+ else if (off < 0)
+ {
+ while (off++ && base < p)
+ MB_PTR_BACK(base, p);
+ }
+ col = (int)(p - base);
+ }
+ result->col = col;
+}
+
+/*
+ * Get current line in syntax buffer.
+ */
+ static char_u *
+syn_getcurline(void)
+{
+ return ml_get_buf(syn_buf, current_lnum, FALSE);
+}
+
+/*
+ * Call vim_regexec() to find a match with "rmp" in "syn_buf".
+ * Returns TRUE when there is a match.
+ */
+ static int
+syn_regexec(
+ regmmatch_T *rmp,
+ linenr_T lnum,
+ colnr_T col,
+ syn_time_T *st UNUSED)
+{
+ int r;
+#ifdef FEAT_RELTIME
+ int timed_out = FALSE;
+#endif
+#ifdef FEAT_PROFILE
+ proftime_T pt;
+
+ if (syn_time_on)
+ profile_start(&pt);
+#endif
+
+ if (rmp->regprog == NULL)
+ // This can happen if a previous call to vim_regexec_multi() tried to
+ // use the NFA engine, which resulted in NFA_TOO_EXPENSIVE, and
+ // compiling the pattern with the other engine fails.
+ return FALSE;
+
+ rmp->rmm_maxcol = syn_buf->b_p_smc;
+ r = vim_regexec_multi(rmp, syn_win, syn_buf, lnum, col,
+#ifdef FEAT_RELTIME
+ syn_tm, &timed_out
+#else
+ NULL, NULL
+#endif
+ );
+
+#ifdef FEAT_PROFILE
+ if (syn_time_on)
+ {
+ profile_end(&pt);
+ profile_add(&st->total, &pt);
+ if (profile_cmp(&pt, &st->slowest) < 0)
+ st->slowest = pt;
+ ++st->count;
+ if (r > 0)
+ ++st->match;
+ }
+#endif
+#ifdef FEAT_RELTIME
+ if (timed_out && !syn_win->w_s->b_syn_slow)
+ {
+ syn_win->w_s->b_syn_slow = TRUE;
+ msg(_("'redrawtime' exceeded, syntax highlighting disabled"));
+ }
+#endif
+
+ if (r > 0)
+ {
+ rmp->startpos[0].lnum += lnum;
+ rmp->endpos[0].lnum += lnum;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * Check one position in a line for a matching keyword.
+ * The caller must check if a keyword can start at startcol.
+ * Return its ID if found, 0 otherwise.
+ */
+ static int
+check_keyword_id(
+ char_u *line,
+ int startcol, /* position in line to check for keyword */
+ int *endcolp, /* return: character after found keyword */
+ long *flagsp, /* return: flags of matching keyword */
+ short **next_listp, /* return: next_list of matching keyword */
+ stateitem_T *cur_si, /* item at the top of the stack */
+ int *ccharp UNUSED) /* conceal substitution char */
+{
+ keyentry_T *kp;
+ char_u *kwp;
+ int round;
+ int kwlen;
+ char_u keyword[MAXKEYWLEN + 1]; /* assume max. keyword len is 80 */
+ hashtab_T *ht;
+ hashitem_T *hi;
+
+ /* Find first character after the keyword. First character was already
+ * checked. */
+ kwp = line + startcol;
+ kwlen = 0;
+ do
+ {
+ if (has_mbyte)
+ kwlen += (*mb_ptr2len)(kwp + kwlen);
+ else
+ ++kwlen;
+ }
+ while (vim_iswordp_buf(kwp + kwlen, syn_buf));
+
+ if (kwlen > MAXKEYWLEN)
+ return 0;
+
+ /*
+ * Must make a copy of the keyword, so we can add a NUL and make it
+ * lowercase.
+ */
+ vim_strncpy(keyword, kwp, kwlen);
+
+ /*
+ * Try twice:
+ * 1. matching case
+ * 2. ignoring case
+ */
+ for (round = 1; round <= 2; ++round)
+ {
+ ht = round == 1 ? &syn_block->b_keywtab : &syn_block->b_keywtab_ic;
+ if (ht->ht_used == 0)
+ continue;
+ if (round == 2) /* ignore case */
+ (void)str_foldcase(kwp, kwlen, keyword, MAXKEYWLEN + 1);
+
+ /*
+ * Find keywords that match. There can be several with different
+ * attributes.
+ * When current_next_list is non-zero accept only that group, otherwise:
+ * Accept a not-contained keyword at toplevel.
+ * Accept a keyword at other levels only if it is in the contains list.
+ */
+ hi = hash_find(ht, keyword);
+ if (!HASHITEM_EMPTY(hi))
+ for (kp = HI2KE(hi); kp != NULL; kp = kp->ke_next)
+ {
+ if (current_next_list != 0
+ ? in_id_list(NULL, current_next_list, &kp->k_syn, 0)
+ : (cur_si == NULL
+ ? !(kp->flags & HL_CONTAINED)
+ : in_id_list(cur_si, cur_si->si_cont_list,
+ &kp->k_syn, kp->flags & HL_CONTAINED)))
+ {
+ *endcolp = startcol + kwlen;
+ *flagsp = kp->flags;
+ *next_listp = kp->next_list;
+#ifdef FEAT_CONCEAL
+ *ccharp = kp->k_char;
+#endif
+ return kp->k_syn.id;
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ * Handle ":syntax conceal" command.
+ */
+ static void
+syn_cmd_conceal(exarg_T *eap UNUSED, int syncing UNUSED)
+{
+#ifdef FEAT_CONCEAL
+ char_u *arg = eap->arg;
+ char_u *next;
+
+ eap->nextcmd = find_nextcmd(arg);
+ if (eap->skip)
+ return;
+
+ next = skiptowhite(arg);
+ if (*arg == NUL)
+ {
+ if (curwin->w_s->b_syn_conceal)
+ msg(_("syntax conceal on"));
+ else
+ msg(_("syntax conceal off"));
+ }
+ else if (STRNICMP(arg, "on", 2) == 0 && next - arg == 2)
+ curwin->w_s->b_syn_conceal = TRUE;
+ else if (STRNICMP(arg, "off", 3) == 0 && next - arg == 3)
+ curwin->w_s->b_syn_conceal = FALSE;
+ else
+ semsg(_("E390: Illegal argument: %s"), arg);
+#endif
+}
+
+/*
+ * Handle ":syntax case" command.
+ */
+ static void
+syn_cmd_case(exarg_T *eap, int syncing UNUSED)
+{
+ char_u *arg = eap->arg;
+ char_u *next;
+
+ eap->nextcmd = find_nextcmd(arg);
+ if (eap->skip)
+ return;
+
+ next = skiptowhite(arg);
+ if (*arg == NUL)
+ {
+ if (curwin->w_s->b_syn_ic)
+ msg(_("syntax case ignore"));
+ else
+ msg(_("syntax case match"));
+ }
+ else if (STRNICMP(arg, "match", 5) == 0 && next - arg == 5)
+ curwin->w_s->b_syn_ic = FALSE;
+ else if (STRNICMP(arg, "ignore", 6) == 0 && next - arg == 6)
+ curwin->w_s->b_syn_ic = TRUE;
+ else
+ semsg(_("E390: Illegal argument: %s"), arg);
+}
+
+/*
+ * Handle ":syntax spell" command.
+ */
+ static void
+syn_cmd_spell(exarg_T *eap, int syncing UNUSED)
+{
+ char_u *arg = eap->arg;
+ char_u *next;
+
+ eap->nextcmd = find_nextcmd(arg);
+ if (eap->skip)
+ return;
+
+ next = skiptowhite(arg);
+ if (*arg == NUL)
+ {
+ if (curwin->w_s->b_syn_spell == SYNSPL_TOP)
+ msg(_("syntax spell toplevel"));
+ else if (curwin->w_s->b_syn_spell == SYNSPL_NOTOP)
+ msg(_("syntax spell notoplevel"));
+ else
+ msg(_("syntax spell default"));
+ }
+ else if (STRNICMP(arg, "toplevel", 8) == 0 && next - arg == 8)
+ curwin->w_s->b_syn_spell = SYNSPL_TOP;
+ else if (STRNICMP(arg, "notoplevel", 10) == 0 && next - arg == 10)
+ curwin->w_s->b_syn_spell = SYNSPL_NOTOP;
+ else if (STRNICMP(arg, "default", 7) == 0 && next - arg == 7)
+ curwin->w_s->b_syn_spell = SYNSPL_DEFAULT;
+ else
+ {
+ semsg(_("E390: Illegal argument: %s"), arg);
+ return;
+ }
+
+ /* assume spell checking changed, force a redraw */
+ redraw_win_later(curwin, NOT_VALID);
+}
+
+/*
+ * Handle ":syntax iskeyword" command.
+ */
+ static void
+syn_cmd_iskeyword(exarg_T *eap, int syncing UNUSED)
+{
+ char_u *arg = eap->arg;
+ char_u save_chartab[32];
+ char_u *save_isk;
+
+ if (eap->skip)
+ return;
+
+ arg = skipwhite(arg);
+ if (*arg == NUL)
+ {
+ msg_puts("\n");
+ if (curwin->w_s->b_syn_isk != empty_option)
+ {
+ msg_puts(_("syntax iskeyword "));
+ msg_outtrans(curwin->w_s->b_syn_isk);
+ }
+ else
+ msg_outtrans((char_u *)_("syntax iskeyword not set"));
+ }
+ else
+ {
+ if (STRNICMP(arg, "clear", 5) == 0)
+ {
+ mch_memmove(curwin->w_s->b_syn_chartab, curbuf->b_chartab,
+ (size_t)32);
+ clear_string_option(&curwin->w_s->b_syn_isk);
+ }
+ else
+ {
+ mch_memmove(save_chartab, curbuf->b_chartab, (size_t)32);
+ save_isk = curbuf->b_p_isk;
+ curbuf->b_p_isk = vim_strsave(arg);
+
+ buf_init_chartab(curbuf, FALSE);
+ mch_memmove(curwin->w_s->b_syn_chartab, curbuf->b_chartab,
+ (size_t)32);
+ mch_memmove(curbuf->b_chartab, save_chartab, (size_t)32);
+ clear_string_option(&curwin->w_s->b_syn_isk);
+ curwin->w_s->b_syn_isk = curbuf->b_p_isk;
+ curbuf->b_p_isk = save_isk;
+ }
+ }
+ redraw_win_later(curwin, NOT_VALID);
+}
+
+/*
+ * Clear all syntax info for one buffer.
+ */
+ void
+syntax_clear(synblock_T *block)
+{
+ int i;
+
+ block->b_syn_error = FALSE; /* clear previous error */
+#ifdef FEAT_RELTIME
+ block->b_syn_slow = FALSE; /* clear previous timeout */
+#endif
+ block->b_syn_ic = FALSE; /* Use case, by default */
+ block->b_syn_spell = SYNSPL_DEFAULT; /* default spell checking */
+ block->b_syn_containedin = FALSE;
+#ifdef FEAT_CONCEAL
+ block->b_syn_conceal = FALSE;
+#endif
+
+ /* free the keywords */
+ clear_keywtab(&block->b_keywtab);
+ clear_keywtab(&block->b_keywtab_ic);
+
+ /* free the syntax patterns */
+ for (i = block->b_syn_patterns.ga_len; --i >= 0; )
+ syn_clear_pattern(block, i);
+ ga_clear(&block->b_syn_patterns);
+
+ /* free the syntax clusters */
+ for (i = block->b_syn_clusters.ga_len; --i >= 0; )
+ syn_clear_cluster(block, i);
+ ga_clear(&block->b_syn_clusters);
+ block->b_spell_cluster_id = 0;
+ block->b_nospell_cluster_id = 0;
+
+ block->b_syn_sync_flags = 0;
+ block->b_syn_sync_minlines = 0;
+ block->b_syn_sync_maxlines = 0;
+ block->b_syn_sync_linebreaks = 0;
+
+ vim_regfree(block->b_syn_linecont_prog);
+ block->b_syn_linecont_prog = NULL;
+ VIM_CLEAR(block->b_syn_linecont_pat);
+#ifdef FEAT_FOLDING
+ block->b_syn_folditems = 0;
+#endif
+ clear_string_option(&block->b_syn_isk);
+
+ /* free the stored states */
+ syn_stack_free_all(block);
+ invalidate_current_state();
+
+ /* Reset the counter for ":syn include" */
+ running_syn_inc_tag = 0;
+}
+
+/*
+ * Get rid of ownsyntax for window "wp".
+ */
+ void
+reset_synblock(win_T *wp)
+{
+ if (wp->w_s != &wp->w_buffer->b_s)
+ {
+ syntax_clear(wp->w_s);
+ vim_free(wp->w_s);
+ wp->w_s = &wp->w_buffer->b_s;
+ }
+}
+
+/*
+ * Clear syncing info for one buffer.
+ */
+ static void
+syntax_sync_clear(void)
+{
+ int i;
+
+ /* free the syntax patterns */
+ for (i = curwin->w_s->b_syn_patterns.ga_len; --i >= 0; )
+ if (SYN_ITEMS(curwin->w_s)[i].sp_syncing)
+ syn_remove_pattern(curwin->w_s, i);
+
+ curwin->w_s->b_syn_sync_flags = 0;
+ curwin->w_s->b_syn_sync_minlines = 0;
+ curwin->w_s->b_syn_sync_maxlines = 0;
+ curwin->w_s->b_syn_sync_linebreaks = 0;
+
+ vim_regfree(curwin->w_s->b_syn_linecont_prog);
+ curwin->w_s->b_syn_linecont_prog = NULL;
+ VIM_CLEAR(curwin->w_s->b_syn_linecont_pat);
+ clear_string_option(&curwin->w_s->b_syn_isk);
+
+ syn_stack_free_all(curwin->w_s); /* Need to recompute all syntax. */
+}
+
+/*
+ * Remove one pattern from the buffer's pattern list.
+ */
+ static void
+syn_remove_pattern(
+ synblock_T *block,
+ int idx)
+{
+ synpat_T *spp;
+
+ spp = &(SYN_ITEMS(block)[idx]);
+#ifdef FEAT_FOLDING
+ if (spp->sp_flags & HL_FOLD)
+ --block->b_syn_folditems;
+#endif
+ syn_clear_pattern(block, idx);
+ mch_memmove(spp, spp + 1,
+ sizeof(synpat_T) * (block->b_syn_patterns.ga_len - idx - 1));
+ --block->b_syn_patterns.ga_len;
+}
+
+/*
+ * Clear and free one syntax pattern. When clearing all, must be called from
+ * last to first!
+ */
+ static void
+syn_clear_pattern(synblock_T *block, int i)
+{
+ vim_free(SYN_ITEMS(block)[i].sp_pattern);
+ vim_regfree(SYN_ITEMS(block)[i].sp_prog);
+ /* Only free sp_cont_list and sp_next_list of first start pattern */
+ if (i == 0 || SYN_ITEMS(block)[i - 1].sp_type != SPTYPE_START)
+ {
+ vim_free(SYN_ITEMS(block)[i].sp_cont_list);
+ vim_free(SYN_ITEMS(block)[i].sp_next_list);
+ vim_free(SYN_ITEMS(block)[i].sp_syn.cont_in_list);
+ }
+}
+
+/*
+ * Clear and free one syntax cluster.
+ */
+ static void
+syn_clear_cluster(synblock_T *block, int i)
+{
+ vim_free(SYN_CLSTR(block)[i].scl_name);
+ vim_free(SYN_CLSTR(block)[i].scl_name_u);
+ vim_free(SYN_CLSTR(block)[i].scl_list);
+}
+
+/*
+ * Handle ":syntax clear" command.
+ */
+ static void
+syn_cmd_clear(exarg_T *eap, int syncing)
+{
+ char_u *arg = eap->arg;
+ char_u *arg_end;
+ int id;
+
+ eap->nextcmd = find_nextcmd(arg);
+ if (eap->skip)
+ return;
+
+ /*
+ * We have to disable this within ":syn include @group filename",
+ * because otherwise @group would get deleted.
+ * Only required for Vim 5.x syntax files, 6.0 ones don't contain ":syn
+ * clear".
+ */
+ if (curwin->w_s->b_syn_topgrp != 0)
+ return;
+
+ if (ends_excmd(*arg))
+ {
+ /*
+ * No argument: Clear all syntax items.
+ */
+ if (syncing)
+ syntax_sync_clear();
+ else
+ {
+ syntax_clear(curwin->w_s);
+ if (curwin->w_s == &curwin->w_buffer->b_s)
+ do_unlet((char_u *)"b:current_syntax", TRUE);
+ do_unlet((char_u *)"w:current_syntax", TRUE);
+ }
+ }
+ else
+ {
+ /*
+ * Clear the group IDs that are in the argument.
+ */
+ while (!ends_excmd(*arg))
+ {
+ arg_end = skiptowhite(arg);
+ if (*arg == '@')
+ {
+ id = syn_scl_namen2id(arg + 1, (int)(arg_end - arg - 1));
+ if (id == 0)
+ {
+ semsg(_("E391: No such syntax cluster: %s"), arg);
+ break;
+ }
+ else
+ {
+ /*
+ * We can't physically delete a cluster without changing
+ * the IDs of other clusters, so we do the next best thing
+ * and make it empty.
+ */
+ short scl_id = id - SYNID_CLUSTER;
+
+ VIM_CLEAR(SYN_CLSTR(curwin->w_s)[scl_id].scl_list);
+ }
+ }
+ else
+ {
+ id = syn_namen2id(arg, (int)(arg_end - arg));
+ if (id == 0)
+ {
+ semsg(_(e_nogroup), arg);
+ break;
+ }
+ else
+ syn_clear_one(id, syncing);
+ }
+ arg = skipwhite(arg_end);
+ }
+ }
+ redraw_curbuf_later(SOME_VALID);
+ syn_stack_free_all(curwin->w_s); /* Need to recompute all syntax. */
+}
+
+/*
+ * Clear one syntax group for the current buffer.
+ */
+ static void
+syn_clear_one(int id, int syncing)
+{
+ synpat_T *spp;
+ int idx;
+
+ /* Clear keywords only when not ":syn sync clear group-name" */
+ if (!syncing)
+ {
+ (void)syn_clear_keyword(id, &curwin->w_s->b_keywtab);
+ (void)syn_clear_keyword(id, &curwin->w_s->b_keywtab_ic);
+ }
+
+ /* clear the patterns for "id" */
+ for (idx = curwin->w_s->b_syn_patterns.ga_len; --idx >= 0; )
+ {
+ spp = &(SYN_ITEMS(curwin->w_s)[idx]);
+ if (spp->sp_syn.id != id || spp->sp_syncing != syncing)
+ continue;
+ syn_remove_pattern(curwin->w_s, idx);
+ }
+}
+
+/*
+ * Handle ":syntax on" command.
+ */
+ static void
+syn_cmd_on(exarg_T *eap, int syncing UNUSED)
+{
+ syn_cmd_onoff(eap, "syntax");
+}
+
+/*
+ * Handle ":syntax enable" command.
+ */
+ static void
+syn_cmd_enable(exarg_T *eap, int syncing UNUSED)
+{
+ set_internal_string_var((char_u *)"syntax_cmd", (char_u *)"enable");
+ syn_cmd_onoff(eap, "syntax");
+ do_unlet((char_u *)"g:syntax_cmd", TRUE);
+}
+
+/*
+ * Handle ":syntax reset" command.
+ * It actually resets highlighting, not syntax.
+ */
+ static void
+syn_cmd_reset(exarg_T *eap, int syncing UNUSED)
+{
+ eap->nextcmd = check_nextcmd(eap->arg);
+ if (!eap->skip)
+ {
+ set_internal_string_var((char_u *)"syntax_cmd", (char_u *)"reset");
+ do_cmdline_cmd((char_u *)"runtime! syntax/syncolor.vim");
+ do_unlet((char_u *)"g:syntax_cmd", TRUE);
+ }
+}
+
+/*
+ * Handle ":syntax manual" command.
+ */
+ static void
+syn_cmd_manual(exarg_T *eap, int syncing UNUSED)
+{
+ syn_cmd_onoff(eap, "manual");
+}
+
+/*
+ * Handle ":syntax off" command.
+ */
+ static void
+syn_cmd_off(exarg_T *eap, int syncing UNUSED)
+{
+ syn_cmd_onoff(eap, "nosyntax");
+}
+
+ static void
+syn_cmd_onoff(exarg_T *eap, char *name)
+{
+ char_u buf[100];
+
+ eap->nextcmd = check_nextcmd(eap->arg);
+ if (!eap->skip)
+ {
+ STRCPY(buf, "so ");
+ vim_snprintf((char *)buf + 3, sizeof(buf) - 3, SYNTAX_FNAME, name);
+ do_cmdline_cmd(buf);
+ }
+}
+
+/*
+ * Handle ":syntax [list]" command: list current syntax words.
+ */
+ static void
+syn_cmd_list(
+ exarg_T *eap,
+ int syncing) /* when TRUE: list syncing items */
+{
+ char_u *arg = eap->arg;
+ int id;
+ char_u *arg_end;
+
+ eap->nextcmd = find_nextcmd(arg);
+ if (eap->skip)
+ return;
+
+ if (!syntax_present(curwin))
+ {
+ msg(_(msg_no_items));
+ return;
+ }
+
+ if (syncing)
+ {
+ if (curwin->w_s->b_syn_sync_flags & SF_CCOMMENT)
+ {
+ msg_puts(_("syncing on C-style comments"));
+ syn_lines_msg();
+ syn_match_msg();
+ return;
+ }
+ else if (!(curwin->w_s->b_syn_sync_flags & SF_MATCH))
+ {
+ if (curwin->w_s->b_syn_sync_minlines == 0)
+ msg_puts(_("no syncing"));
+ else
+ {
+ msg_puts(_("syncing starts "));
+ msg_outnum(curwin->w_s->b_syn_sync_minlines);
+ msg_puts(_(" lines before top line"));
+ syn_match_msg();
+ }
+ return;
+ }
+ msg_puts_title(_("\n--- Syntax sync items ---"));
+ if (curwin->w_s->b_syn_sync_minlines > 0
+ || curwin->w_s->b_syn_sync_maxlines > 0
+ || curwin->w_s->b_syn_sync_linebreaks > 0)
+ {
+ msg_puts(_("\nsyncing on items"));
+ syn_lines_msg();
+ syn_match_msg();
+ }
+ }
+ else
+ msg_puts_title(_("\n--- Syntax items ---"));
+ if (ends_excmd(*arg))
+ {
+ /*
+ * No argument: List all group IDs and all syntax clusters.
+ */
+ for (id = 1; id <= highlight_ga.ga_len && !got_int; ++id)
+ syn_list_one(id, syncing, FALSE);
+ for (id = 0; id < curwin->w_s->b_syn_clusters.ga_len && !got_int; ++id)
+ syn_list_cluster(id);
+ }
+ else
+ {
+ /*
+ * List the group IDs and syntax clusters that are in the argument.
+ */
+ while (!ends_excmd(*arg) && !got_int)
+ {
+ arg_end = skiptowhite(arg);
+ if (*arg == '@')
+ {
+ id = syn_scl_namen2id(arg + 1, (int)(arg_end - arg - 1));
+ if (id == 0)
+ semsg(_("E392: No such syntax cluster: %s"), arg);
+ else
+ syn_list_cluster(id - SYNID_CLUSTER);
+ }
+ else
+ {
+ id = syn_namen2id(arg, (int)(arg_end - arg));
+ if (id == 0)
+ semsg(_(e_nogroup), arg);
+ else
+ syn_list_one(id, syncing, TRUE);
+ }
+ arg = skipwhite(arg_end);
+ }
+ }
+ eap->nextcmd = check_nextcmd(arg);
+}
+
+ static void
+syn_lines_msg(void)
+{
+ if (curwin->w_s->b_syn_sync_maxlines > 0
+ || curwin->w_s->b_syn_sync_minlines > 0)
+ {
+ msg_puts("; ");
+ if (curwin->w_s->b_syn_sync_minlines > 0)
+ {
+ msg_puts(_("minimal "));
+ msg_outnum(curwin->w_s->b_syn_sync_minlines);
+ if (curwin->w_s->b_syn_sync_maxlines)
+ msg_puts(", ");
+ }
+ if (curwin->w_s->b_syn_sync_maxlines > 0)
+ {
+ msg_puts(_("maximal "));
+ msg_outnum(curwin->w_s->b_syn_sync_maxlines);
+ }
+ msg_puts(_(" lines before top line"));
+ }
+}
+
+ static void
+syn_match_msg(void)
+{
+ if (curwin->w_s->b_syn_sync_linebreaks > 0)
+ {
+ msg_puts(_("; match "));
+ msg_outnum(curwin->w_s->b_syn_sync_linebreaks);
+ msg_puts(_(" line breaks"));
+ }
+}
+
+static int last_matchgroup;
+
+struct name_list
+{
+ int flag;
+ char *name;
+};
+
+static void syn_list_flags(struct name_list *nl, int flags, int attr);
+
+/*
+ * List one syntax item, for ":syntax" or "syntax list syntax_name".
+ */
+ static void
+syn_list_one(
+ int id,
+ int syncing, /* when TRUE: list syncing items */
+ int link_only) /* when TRUE; list link-only too */
+{
+ int attr;
+ int idx;
+ int did_header = FALSE;
+ synpat_T *spp;
+ static struct name_list namelist1[] =
+ {
+ {HL_DISPLAY, "display"},
+ {HL_CONTAINED, "contained"},
+ {HL_ONELINE, "oneline"},
+ {HL_KEEPEND, "keepend"},
+ {HL_EXTEND, "extend"},
+ {HL_EXCLUDENL, "excludenl"},
+ {HL_TRANSP, "transparent"},
+ {HL_FOLD, "fold"},
+#ifdef FEAT_CONCEAL
+ {HL_CONCEAL, "conceal"},
+ {HL_CONCEALENDS, "concealends"},
+#endif
+ {0, NULL}
+ };
+ static struct name_list namelist2[] =
+ {
+ {HL_SKIPWHITE, "skipwhite"},
+ {HL_SKIPNL, "skipnl"},
+ {HL_SKIPEMPTY, "skipempty"},
+ {0, NULL}
+ };
+
+ attr = HL_ATTR(HLF_D); /* highlight like directories */
+
+ /* list the keywords for "id" */
+ if (!syncing)
+ {
+ did_header = syn_list_keywords(id, &curwin->w_s->b_keywtab, FALSE, attr);
+ did_header = syn_list_keywords(id, &curwin->w_s->b_keywtab_ic,
+ did_header, attr);
+ }
+
+ /* list the patterns for "id" */
+ for (idx = 0; idx < curwin->w_s->b_syn_patterns.ga_len && !got_int; ++idx)
+ {
+ spp = &(SYN_ITEMS(curwin->w_s)[idx]);
+ if (spp->sp_syn.id != id || spp->sp_syncing != syncing)
+ continue;
+
+ (void)syn_list_header(did_header, 999, id);
+ did_header = TRUE;
+ last_matchgroup = 0;
+ if (spp->sp_type == SPTYPE_MATCH)
+ {
+ put_pattern("match", ' ', spp, attr);
+ msg_putchar(' ');
+ }
+ else if (spp->sp_type == SPTYPE_START)
+ {
+ while (SYN_ITEMS(curwin->w_s)[idx].sp_type == SPTYPE_START)
+ put_pattern("start", '=', &SYN_ITEMS(curwin->w_s)[idx++], attr);
+ if (SYN_ITEMS(curwin->w_s)[idx].sp_type == SPTYPE_SKIP)
+ put_pattern("skip", '=', &SYN_ITEMS(curwin->w_s)[idx++], attr);
+ while (idx < curwin->w_s->b_syn_patterns.ga_len
+ && SYN_ITEMS(curwin->w_s)[idx].sp_type == SPTYPE_END)
+ put_pattern("end", '=', &SYN_ITEMS(curwin->w_s)[idx++], attr);
+ --idx;
+ msg_putchar(' ');
+ }
+ syn_list_flags(namelist1, spp->sp_flags, attr);
+
+ if (spp->sp_cont_list != NULL)
+ put_id_list((char_u *)"contains", spp->sp_cont_list, attr);
+
+ if (spp->sp_syn.cont_in_list != NULL)
+ put_id_list((char_u *)"containedin",
+ spp->sp_syn.cont_in_list, attr);
+
+ if (spp->sp_next_list != NULL)
+ {
+ put_id_list((char_u *)"nextgroup", spp->sp_next_list, attr);
+ syn_list_flags(namelist2, spp->sp_flags, attr);
+ }
+ if (spp->sp_flags & (HL_SYNC_HERE|HL_SYNC_THERE))
+ {
+ if (spp->sp_flags & HL_SYNC_HERE)
+ msg_puts_attr("grouphere", attr);
+ else
+ msg_puts_attr("groupthere", attr);
+ msg_putchar(' ');
+ if (spp->sp_sync_idx >= 0)
+ msg_outtrans(HL_TABLE()[SYN_ITEMS(curwin->w_s)
+ [spp->sp_sync_idx].sp_syn.id - 1].sg_name);
+ else
+ msg_puts("NONE");
+ msg_putchar(' ');
+ }
+ }
+
+ /* list the link, if there is one */
+ if (HL_TABLE()[id - 1].sg_link && (did_header || link_only) && !got_int)
+ {
+ (void)syn_list_header(did_header, 999, id);
+ msg_puts_attr("links to", attr);
+ msg_putchar(' ');
+ msg_outtrans(HL_TABLE()[HL_TABLE()[id - 1].sg_link - 1].sg_name);
+ }
+}
+
+ static void
+syn_list_flags(struct name_list *nlist, int flags, int attr)
+{
+ int i;
+
+ for (i = 0; nlist[i].flag != 0; ++i)
+ if (flags & nlist[i].flag)
+ {
+ msg_puts_attr(nlist[i].name, attr);
+ msg_putchar(' ');
+ }
+}
+
+/*
+ * List one syntax cluster, for ":syntax" or "syntax list syntax_name".
+ */
+ static void
+syn_list_cluster(int id)
+{
+ int endcol = 15;
+
+ /* slight hack: roughly duplicate the guts of syn_list_header() */
+ msg_putchar('\n');
+ msg_outtrans(SYN_CLSTR(curwin->w_s)[id].scl_name);
+
+ if (msg_col >= endcol) /* output at least one space */
+ endcol = msg_col + 1;
+ if (Columns <= endcol) /* avoid hang for tiny window */
+ endcol = Columns - 1;
+
+ msg_advance(endcol);
+ if (SYN_CLSTR(curwin->w_s)[id].scl_list != NULL)
+ {
+ put_id_list((char_u *)"cluster", SYN_CLSTR(curwin->w_s)[id].scl_list,
+ HL_ATTR(HLF_D));
+ }
+ else
+ {
+ msg_puts_attr("cluster", HL_ATTR(HLF_D));
+ msg_puts("=NONE");
+ }
+}
+
+ static void
+put_id_list(char_u *name, short *list, int attr)
+{
+ short *p;
+
+ msg_puts_attr((char *)name, attr);
+ msg_putchar('=');
+ for (p = list; *p; ++p)
+ {
+ if (*p >= SYNID_ALLBUT && *p < SYNID_TOP)
+ {
+ if (p[1])
+ msg_puts("ALLBUT");
+ else
+ msg_puts("ALL");
+ }
+ else if (*p >= SYNID_TOP && *p < SYNID_CONTAINED)
+ {
+ msg_puts("TOP");
+ }
+ else if (*p >= SYNID_CONTAINED && *p < SYNID_CLUSTER)
+ {
+ msg_puts("CONTAINED");
+ }
+ else if (*p >= SYNID_CLUSTER)
+ {
+ short scl_id = *p - SYNID_CLUSTER;
+
+ msg_putchar('@');
+ msg_outtrans(SYN_CLSTR(curwin->w_s)[scl_id].scl_name);
+ }
+ else
+ msg_outtrans(HL_TABLE()[*p - 1].sg_name);
+ if (p[1])
+ msg_putchar(',');
+ }
+ msg_putchar(' ');
+}
+
+ static void
+put_pattern(
+ char *s,
+ int c,
+ synpat_T *spp,
+ int attr)
+{
+ long n;
+ int mask;
+ int first;
+ static char *sepchars = "/+=-#@\"|'^&";
+ int i;
+
+ /* May have to write "matchgroup=group" */
+ if (last_matchgroup != spp->sp_syn_match_id)
+ {
+ last_matchgroup = spp->sp_syn_match_id;
+ msg_puts_attr("matchgroup", attr);
+ msg_putchar('=');
+ if (last_matchgroup == 0)
+ msg_outtrans((char_u *)"NONE");
+ else
+ msg_outtrans(HL_TABLE()[last_matchgroup - 1].sg_name);
+ msg_putchar(' ');
+ }
+
+ /* output the name of the pattern and an '=' or ' ' */
+ msg_puts_attr(s, attr);
+ msg_putchar(c);
+
+ /* output the pattern, in between a char that is not in the pattern */
+ for (i = 0; vim_strchr(spp->sp_pattern, sepchars[i]) != NULL; )
+ if (sepchars[++i] == NUL)
+ {
+ i = 0; /* no good char found, just use the first one */
+ break;
+ }
+ msg_putchar(sepchars[i]);
+ msg_outtrans(spp->sp_pattern);
+ msg_putchar(sepchars[i]);
+
+ /* output any pattern options */
+ first = TRUE;
+ for (i = 0; i < SPO_COUNT; ++i)
+ {
+ mask = (1 << i);
+ if (spp->sp_off_flags & (mask + (mask << SPO_COUNT)))
+ {
+ if (!first)
+ msg_putchar(','); /* separate with commas */
+ msg_puts(spo_name_tab[i]);
+ n = spp->sp_offsets[i];
+ if (i != SPO_LC_OFF)
+ {
+ if (spp->sp_off_flags & mask)
+ msg_putchar('s');
+ else
+ msg_putchar('e');
+ if (n > 0)
+ msg_putchar('+');
+ }
+ if (n || i == SPO_LC_OFF)
+ msg_outnum(n);
+ first = FALSE;
+ }
+ }
+ msg_putchar(' ');
+}
+
+/*
+ * List or clear the keywords for one syntax group.
+ * Return TRUE if the header has been printed.
+ */
+ static int
+syn_list_keywords(
+ int id,
+ hashtab_T *ht,
+ int did_header, /* header has already been printed */
+ int attr)
+{
+ int outlen;
+ hashitem_T *hi;
+ keyentry_T *kp;
+ int todo;
+ int prev_contained = 0;
+ short *prev_next_list = NULL;
+ short *prev_cont_in_list = NULL;
+ int prev_skipnl = 0;
+ int prev_skipwhite = 0;
+ int prev_skipempty = 0;
+
+ /*
+ * Unfortunately, this list of keywords is not sorted on alphabet but on
+ * hash value...
+ */
+ todo = (int)ht->ht_used;
+ for (hi = ht->ht_array; todo > 0 && !got_int; ++hi)
+ {
+ if (!HASHITEM_EMPTY(hi))
+ {
+ --todo;
+ for (kp = HI2KE(hi); kp != NULL && !got_int; kp = kp->ke_next)
+ {
+ if (kp->k_syn.id == id)
+ {
+ if (prev_contained != (kp->flags & HL_CONTAINED)
+ || prev_skipnl != (kp->flags & HL_SKIPNL)
+ || prev_skipwhite != (kp->flags & HL_SKIPWHITE)
+ || prev_skipempty != (kp->flags & HL_SKIPEMPTY)
+ || prev_cont_in_list != kp->k_syn.cont_in_list
+ || prev_next_list != kp->next_list)
+ outlen = 9999;
+ else
+ outlen = (int)STRLEN(kp->keyword);
+ /* output "contained" and "nextgroup" on each line */
+ if (syn_list_header(did_header, outlen, id))
+ {
+ prev_contained = 0;
+ prev_next_list = NULL;
+ prev_cont_in_list = NULL;
+ prev_skipnl = 0;
+ prev_skipwhite = 0;
+ prev_skipempty = 0;
+ }
+ did_header = TRUE;
+ if (prev_contained != (kp->flags & HL_CONTAINED))
+ {
+ msg_puts_attr("contained", attr);
+ msg_putchar(' ');
+ prev_contained = (kp->flags & HL_CONTAINED);
+ }
+ if (kp->k_syn.cont_in_list != prev_cont_in_list)
+ {
+ put_id_list((char_u *)"containedin",
+ kp->k_syn.cont_in_list, attr);
+ msg_putchar(' ');
+ prev_cont_in_list = kp->k_syn.cont_in_list;
+ }
+ if (kp->next_list != prev_next_list)
+ {
+ put_id_list((char_u *)"nextgroup", kp->next_list, attr);
+ msg_putchar(' ');
+ prev_next_list = kp->next_list;
+ if (kp->flags & HL_SKIPNL)
+ {
+ msg_puts_attr("skipnl", attr);
+ msg_putchar(' ');
+ prev_skipnl = (kp->flags & HL_SKIPNL);
+ }
+ if (kp->flags & HL_SKIPWHITE)
+ {
+ msg_puts_attr("skipwhite", attr);
+ msg_putchar(' ');
+ prev_skipwhite = (kp->flags & HL_SKIPWHITE);
+ }
+ if (kp->flags & HL_SKIPEMPTY)
+ {
+ msg_puts_attr("skipempty", attr);
+ msg_putchar(' ');
+ prev_skipempty = (kp->flags & HL_SKIPEMPTY);
+ }
+ }
+ msg_outtrans(kp->keyword);
+ }
+ }
+ }
+ }
+
+ return did_header;
+}
+
+ static void
+syn_clear_keyword(int id, hashtab_T *ht)
+{
+ hashitem_T *hi;
+ keyentry_T *kp;
+ keyentry_T *kp_prev;
+ keyentry_T *kp_next;
+ int todo;
+
+ hash_lock(ht);
+ todo = (int)ht->ht_used;
+ for (hi = ht->ht_array; todo > 0; ++hi)
+ {
+ if (!HASHITEM_EMPTY(hi))
+ {
+ --todo;
+ kp_prev = NULL;
+ for (kp = HI2KE(hi); kp != NULL; )
+ {
+ if (kp->k_syn.id == id)
+ {
+ kp_next = kp->ke_next;
+ if (kp_prev == NULL)
+ {
+ if (kp_next == NULL)
+ hash_remove(ht, hi);
+ else
+ hi->hi_key = KE2HIKEY(kp_next);
+ }
+ else
+ kp_prev->ke_next = kp_next;
+ vim_free(kp->next_list);
+ vim_free(kp->k_syn.cont_in_list);
+ vim_free(kp);
+ kp = kp_next;
+ }
+ else
+ {
+ kp_prev = kp;
+ kp = kp->ke_next;
+ }
+ }
+ }
+ }
+ hash_unlock(ht);
+}
+
+/*
+ * Clear a whole keyword table.
+ */
+ static void
+clear_keywtab(hashtab_T *ht)
+{
+ hashitem_T *hi;
+ int todo;
+ keyentry_T *kp;
+ keyentry_T *kp_next;
+
+ todo = (int)ht->ht_used;
+ for (hi = ht->ht_array; todo > 0; ++hi)
+ {
+ if (!HASHITEM_EMPTY(hi))
+ {
+ --todo;
+ for (kp = HI2KE(hi); kp != NULL; kp = kp_next)
+ {
+ kp_next = kp->ke_next;
+ vim_free(kp->next_list);
+ vim_free(kp->k_syn.cont_in_list);
+ vim_free(kp);
+ }
+ }
+ }
+ hash_clear(ht);
+ hash_init(ht);
+}
+
+/*
+ * Add a keyword to the list of keywords.
+ */
+ static void
+add_keyword(
+ char_u *name, /* name of keyword */
+ int id, /* group ID for this keyword */
+ int flags, /* flags for this keyword */
+ short *cont_in_list, /* containedin for this keyword */
+ short *next_list, /* nextgroup for this keyword */
+ int conceal_char)
+{
+ keyentry_T *kp;
+ hashtab_T *ht;
+ hashitem_T *hi;
+ char_u *name_ic;
+ long_u hash;
+ char_u name_folded[MAXKEYWLEN + 1];
+
+ if (curwin->w_s->b_syn_ic)
+ name_ic = str_foldcase(name, (int)STRLEN(name),
+ name_folded, MAXKEYWLEN + 1);
+ else
+ name_ic = name;
+ kp = (keyentry_T *)alloc((int)(sizeof(keyentry_T) + STRLEN(name_ic)));
+ if (kp == NULL)
+ return;
+ STRCPY(kp->keyword, name_ic);
+ kp->k_syn.id = id;
+ kp->k_syn.inc_tag = current_syn_inc_tag;
+ kp->flags = flags;
+ kp->k_char = conceal_char;
+ kp->k_syn.cont_in_list = copy_id_list(cont_in_list);
+ if (cont_in_list != NULL)
+ curwin->w_s->b_syn_containedin = TRUE;
+ kp->next_list = copy_id_list(next_list);
+
+ if (curwin->w_s->b_syn_ic)
+ ht = &curwin->w_s->b_keywtab_ic;
+ else
+ ht = &curwin->w_s->b_keywtab;
+
+ hash = hash_hash(kp->keyword);
+ hi = hash_lookup(ht, kp->keyword, hash);
+ if (HASHITEM_EMPTY(hi))
+ {
+ /* new keyword, add to hashtable */
+ kp->ke_next = NULL;
+ hash_add_item(ht, hi, kp->keyword, hash);
+ }
+ else
+ {
+ /* keyword already exists, prepend to list */
+ kp->ke_next = HI2KE(hi);
+ hi->hi_key = KE2HIKEY(kp);
+ }
+}
+
+/*
+ * Get the start and end of the group name argument.
+ * Return a pointer to the first argument.
+ * Return NULL if the end of the command was found instead of further args.
+ */
+ static char_u *
+get_group_name(
+ char_u *arg, /* start of the argument */
+ char_u **name_end) /* pointer to end of the name */
+{
+ char_u *rest;
+
+ *name_end = skiptowhite(arg);
+ rest = skipwhite(*name_end);
+
+ /*
+ * Check if there are enough arguments. The first argument may be a
+ * pattern, where '|' is allowed, so only check for NUL.
+ */
+ if (ends_excmd(*arg) || *rest == NUL)
+ return NULL;
+ return rest;
+}
+
+/*
+ * Check for syntax command option arguments.
+ * This can be called at any place in the list of arguments, and just picks
+ * out the arguments that are known. Can be called several times in a row to
+ * collect all options in between other arguments.
+ * Return a pointer to the next argument (which isn't an option).
+ * Return NULL for any error;
+ */
+ static char_u *
+get_syn_options(
+ char_u *arg, /* next argument to be checked */
+ syn_opt_arg_T *opt, /* various things */
+ int *conceal_char UNUSED,
+ int skip) /* TRUE if skipping over command */
+{
+ char_u *gname_start, *gname;
+ int syn_id;
+ int len;
+ char *p;
+ int i;
+ int fidx;
+ static struct flag
+ {
+ char *name;
+ int argtype;
+ int flags;
+ } flagtab[] = { {"cCoOnNtTaAiInNeEdD", 0, HL_CONTAINED},
+ {"oOnNeElLiInNeE", 0, HL_ONELINE},
+ {"kKeEeEpPeEnNdD", 0, HL_KEEPEND},
+ {"eExXtTeEnNdD", 0, HL_EXTEND},
+ {"eExXcClLuUdDeEnNlL", 0, HL_EXCLUDENL},
+ {"tTrRaAnNsSpPaArReEnNtT", 0, HL_TRANSP},
+ {"sSkKiIpPnNlL", 0, HL_SKIPNL},
+ {"sSkKiIpPwWhHiItTeE", 0, HL_SKIPWHITE},
+ {"sSkKiIpPeEmMpPtTyY", 0, HL_SKIPEMPTY},
+ {"gGrRoOuUpPhHeErReE", 0, HL_SYNC_HERE},
+ {"gGrRoOuUpPtThHeErReE", 0, HL_SYNC_THERE},
+ {"dDiIsSpPlLaAyY", 0, HL_DISPLAY},
+ {"fFoOlLdD", 0, HL_FOLD},
+ {"cCoOnNcCeEaAlL", 0, HL_CONCEAL},
+ {"cCoOnNcCeEaAlLeEnNdDsS", 0, HL_CONCEALENDS},
+ {"cCcChHaArR", 11, 0},
+ {"cCoOnNtTaAiInNsS", 1, 0},
+ {"cCoOnNtTaAiInNeEdDiInN", 2, 0},
+ {"nNeExXtTgGrRoOuUpP", 3, 0},
+ };
+ static char *first_letters = "cCoOkKeEtTsSgGdDfFnN";
+
+ if (arg == NULL) /* already detected error */
+ return NULL;
+
+#ifdef FEAT_CONCEAL
+ if (curwin->w_s->b_syn_conceal)
+ opt->flags |= HL_CONCEAL;
+#endif
+
+ for (;;)
+ {
+ /*
+ * This is used very often when a large number of keywords is defined.
+ * Need to skip quickly when no option name is found.
+ * Also avoid tolower(), it's slow.
+ */
+ if (strchr(first_letters, *arg) == NULL)
+ break;
+
+ for (fidx = sizeof(flagtab) / sizeof(struct flag); --fidx >= 0; )
+ {
+ p = flagtab[fidx].name;
+ for (i = 0, len = 0; p[i] != NUL; i += 2, ++len)
+ if (arg[len] != p[i] && arg[len] != p[i + 1])
+ break;
+ if (p[i] == NUL && (VIM_ISWHITE(arg[len])
+ || (flagtab[fidx].argtype > 0
+ ? arg[len] == '='
+ : ends_excmd(arg[len]))))
+ {
+ if (opt->keyword
+ && (flagtab[fidx].flags == HL_DISPLAY
+ || flagtab[fidx].flags == HL_FOLD
+ || flagtab[fidx].flags == HL_EXTEND))
+ /* treat "display", "fold" and "extend" as a keyword */
+ fidx = -1;
+ break;
+ }
+ }
+ if (fidx < 0) /* no match found */
+ break;
+
+ if (flagtab[fidx].argtype == 1)
+ {
+ if (!opt->has_cont_list)
+ {
+ emsg(_("E395: contains argument not accepted here"));
+ return NULL;
+ }
+ if (get_id_list(&arg, 8, &opt->cont_list, skip) == FAIL)
+ return NULL;
+ }
+ else if (flagtab[fidx].argtype == 2)
+ {
+ if (get_id_list(&arg, 11, &opt->cont_in_list, skip) == FAIL)
+ return NULL;
+ }
+ else if (flagtab[fidx].argtype == 3)
+ {
+ if (get_id_list(&arg, 9, &opt->next_list, skip) == FAIL)
+ return NULL;
+ }
+ else if (flagtab[fidx].argtype == 11 && arg[5] == '=')
+ {
+ /* cchar=? */
+ if (has_mbyte)
+ {
+#ifdef FEAT_CONCEAL
+ *conceal_char = mb_ptr2char(arg + 6);
+#endif
+ arg += mb_ptr2len(arg + 6) - 1;
+ }
+ else
+ {
+#ifdef FEAT_CONCEAL
+ *conceal_char = arg[6];
+#else
+ ;
+#endif
+ }
+#ifdef FEAT_CONCEAL
+ if (!vim_isprintc_strict(*conceal_char))
+ {
+ emsg(_("E844: invalid cchar value"));
+ return NULL;
+ }
+#endif
+ arg = skipwhite(arg + 7);
+ }
+ else
+ {
+ opt->flags |= flagtab[fidx].flags;
+ arg = skipwhite(arg + len);
+
+ if (flagtab[fidx].flags == HL_SYNC_HERE
+ || flagtab[fidx].flags == HL_SYNC_THERE)
+ {
+ if (opt->sync_idx == NULL)
+ {
+ emsg(_("E393: group[t]here not accepted here"));
+ return NULL;
+ }
+ gname_start = arg;
+ arg = skiptowhite(arg);
+ if (gname_start == arg)
+ return NULL;
+ gname = vim_strnsave(gname_start, (int)(arg - gname_start));
+ if (gname == NULL)
+ return NULL;
+ if (STRCMP(gname, "NONE") == 0)
+ *opt->sync_idx = NONE_IDX;
+ else
+ {
+ syn_id = syn_name2id(gname);
+ for (i = curwin->w_s->b_syn_patterns.ga_len; --i >= 0; )
+ if (SYN_ITEMS(curwin->w_s)[i].sp_syn.id == syn_id
+ && SYN_ITEMS(curwin->w_s)[i].sp_type == SPTYPE_START)
+ {
+ *opt->sync_idx = i;
+ break;
+ }
+ if (i < 0)
+ {
+ semsg(_("E394: Didn't find region item for %s"), gname);
+ vim_free(gname);
+ return NULL;
+ }
+ }
+
+ vim_free(gname);
+ arg = skipwhite(arg);
+ }
+#ifdef FEAT_FOLDING
+ else if (flagtab[fidx].flags == HL_FOLD
+ && foldmethodIsSyntax(curwin))
+ /* Need to update folds later. */
+ foldUpdateAll(curwin);
+#endif
+ }
+ }
+
+ return arg;
+}
+
+/*
+ * Adjustments to syntax item when declared in a ":syn include"'d file.
+ * Set the contained flag, and if the item is not already contained, add it
+ * to the specified top-level group, if any.
+ */
+ static void
+syn_incl_toplevel(int id, int *flagsp)
+{
+ if ((*flagsp & HL_CONTAINED) || curwin->w_s->b_syn_topgrp == 0)
+ return;
+ *flagsp |= HL_CONTAINED;
+ if (curwin->w_s->b_syn_topgrp >= SYNID_CLUSTER)
+ {
+ /* We have to alloc this, because syn_combine_list() will free it. */
+ short *grp_list = (short *)alloc((unsigned)(2 * sizeof(short)));
+ int tlg_id = curwin->w_s->b_syn_topgrp - SYNID_CLUSTER;
+
+ if (grp_list != NULL)
+ {
+ grp_list[0] = id;
+ grp_list[1] = 0;
+ syn_combine_list(&SYN_CLSTR(curwin->w_s)[tlg_id].scl_list, &grp_list,
+ CLUSTER_ADD);
+ }
+ }
+}
+
+/*
+ * Handle ":syntax include [@{group-name}] filename" command.
+ */
+ static void
+syn_cmd_include(exarg_T *eap, int syncing UNUSED)
+{
+ char_u *arg = eap->arg;
+ int sgl_id = 1;
+ char_u *group_name_end;
+ char_u *rest;
+ char *errormsg = NULL;
+ int prev_toplvl_grp;
+ int prev_syn_inc_tag;
+ int source = FALSE;
+
+ eap->nextcmd = find_nextcmd(arg);
+ if (eap->skip)
+ return;
+
+ if (arg[0] == '@')
+ {
+ ++arg;
+ rest = get_group_name(arg, &group_name_end);
+ if (rest == NULL)
+ {
+ emsg(_("E397: Filename required"));
+ return;
+ }
+ sgl_id = syn_check_cluster(arg, (int)(group_name_end - arg));
+ if (sgl_id == 0)
+ return;
+ /* separate_nextcmd() and expand_filename() depend on this */
+ eap->arg = rest;
+ }
+
+ /*
+ * Everything that's left, up to the next command, should be the
+ * filename to include.
+ */
+ eap->argt |= (XFILE | NOSPC);
+ separate_nextcmd(eap);
+ if (*eap->arg == '<' || *eap->arg == '$' || mch_isFullName(eap->arg))
+ {
+ /* For an absolute path, "$VIM/..." or "<sfile>.." we ":source" the
+ * file. Need to expand the file name first. In other cases
+ * ":runtime!" is used. */
+ source = TRUE;
+ if (expand_filename(eap, syn_cmdlinep, &errormsg) == FAIL)
+ {
+ if (errormsg != NULL)
+ emsg(errormsg);
+ return;
+ }
+ }
+
+ /*
+ * Save and restore the existing top-level grouplist id and ":syn
+ * include" tag around the actual inclusion.
+ */
+ if (running_syn_inc_tag >= MAX_SYN_INC_TAG)
+ {
+ emsg(_("E847: Too many syntax includes"));
+ return;
+ }
+ prev_syn_inc_tag = current_syn_inc_tag;
+ current_syn_inc_tag = ++running_syn_inc_tag;
+ prev_toplvl_grp = curwin->w_s->b_syn_topgrp;
+ curwin->w_s->b_syn_topgrp = sgl_id;
+ if (source ? do_source(eap->arg, FALSE, DOSO_NONE) == FAIL
+ : source_runtime(eap->arg, DIP_ALL) == FAIL)
+ semsg(_(e_notopen), eap->arg);
+ curwin->w_s->b_syn_topgrp = prev_toplvl_grp;
+ current_syn_inc_tag = prev_syn_inc_tag;
+}
+
+/*
+ * Handle ":syntax keyword {group-name} [{option}] keyword .." command.
+ */
+ static void
+syn_cmd_keyword(exarg_T *eap, int syncing UNUSED)
+{
+ char_u *arg = eap->arg;
+ char_u *group_name_end;
+ int syn_id;
+ char_u *rest;
+ char_u *keyword_copy = NULL;
+ char_u *p;
+ char_u *kw;
+ syn_opt_arg_T syn_opt_arg;
+ int cnt;
+ int conceal_char = NUL;
+
+ rest = get_group_name(arg, &group_name_end);
+
+ if (rest != NULL)
+ {
+ if (eap->skip)
+ syn_id = -1;
+ else
+ syn_id = syn_check_group(arg, (int)(group_name_end - arg));
+ if (syn_id != 0)
+ /* allocate a buffer, for removing backslashes in the keyword */
+ keyword_copy = alloc((unsigned)STRLEN(rest) + 1);
+ if (keyword_copy != NULL)
+ {
+ syn_opt_arg.flags = 0;
+ syn_opt_arg.keyword = TRUE;
+ syn_opt_arg.sync_idx = NULL;
+ syn_opt_arg.has_cont_list = FALSE;
+ syn_opt_arg.cont_in_list = NULL;
+ syn_opt_arg.next_list = NULL;
+
+ /*
+ * The options given apply to ALL keywords, so all options must be
+ * found before keywords can be created.
+ * 1: collect the options and copy the keywords to keyword_copy.
+ */
+ cnt = 0;
+ p = keyword_copy;
+ for ( ; rest != NULL && !ends_excmd(*rest); rest = skipwhite(rest))
+ {
+ rest = get_syn_options(rest, &syn_opt_arg, &conceal_char,
+ eap->skip);
+ if (rest == NULL || ends_excmd(*rest))
+ break;
+ /* Copy the keyword, removing backslashes, and add a NUL. */
+ while (*rest != NUL && !VIM_ISWHITE(*rest))
+ {
+ if (*rest == '\\' && rest[1] != NUL)
+ ++rest;
+ *p++ = *rest++;
+ }
+ *p++ = NUL;
+ ++cnt;
+ }
+
+ if (!eap->skip)
+ {
+ /* Adjust flags for use of ":syn include". */
+ syn_incl_toplevel(syn_id, &syn_opt_arg.flags);
+
+ /*
+ * 2: Add an entry for each keyword.
+ */
+ for (kw = keyword_copy; --cnt >= 0; kw += STRLEN(kw) + 1)
+ {
+ for (p = vim_strchr(kw, '['); ; )
+ {
+ if (p != NULL)
+ *p = NUL;
+ add_keyword(kw, syn_id, syn_opt_arg.flags,
+ syn_opt_arg.cont_in_list,
+ syn_opt_arg.next_list, conceal_char);
+ if (p == NULL)
+ break;
+ if (p[1] == NUL)
+ {
+ semsg(_("E789: Missing ']': %s"), kw);
+ goto error;
+ }
+ if (p[1] == ']')
+ {
+ if (p[2] != NUL)
+ {
+ semsg(_("E890: trailing char after ']': %s]%s"),
+ kw, &p[2]);
+ goto error;
+ }
+ kw = p + 1; /* skip over the "]" */
+ break;
+ }
+ if (has_mbyte)
+ {
+ int l = (*mb_ptr2len)(p + 1);
+
+ mch_memmove(p, p + 1, l);
+ p += l;
+ }
+ else
+ {
+ p[0] = p[1];
+ ++p;
+ }
+ }
+ }
+ }
+error:
+ vim_free(keyword_copy);
+ vim_free(syn_opt_arg.cont_in_list);
+ vim_free(syn_opt_arg.next_list);
+ }
+ }
+
+ if (rest != NULL)
+ eap->nextcmd = check_nextcmd(rest);
+ else
+ semsg(_(e_invarg2), arg);
+
+ redraw_curbuf_later(SOME_VALID);
+ syn_stack_free_all(curwin->w_s); /* Need to recompute all syntax. */
+}
+
+/*
+ * Handle ":syntax match {name} [{options}] {pattern} [{options}]".
+ *
+ * Also ":syntax sync match {name} [[grouphere | groupthere] {group-name}] .."
+ */
+ static void
+syn_cmd_match(
+ exarg_T *eap,
+ int syncing) /* TRUE for ":syntax sync match .. " */
+{
+ char_u *arg = eap->arg;
+ char_u *group_name_end;
+ char_u *rest;
+ synpat_T item; /* the item found in the line */
+ int syn_id;
+ int idx;
+ syn_opt_arg_T syn_opt_arg;
+ int sync_idx = 0;
+ int conceal_char = NUL;
+
+ /* Isolate the group name, check for validity */
+ rest = get_group_name(arg, &group_name_end);
+
+ /* Get options before the pattern */
+ syn_opt_arg.flags = 0;
+ syn_opt_arg.keyword = FALSE;
+ syn_opt_arg.sync_idx = syncing ? &sync_idx : NULL;
+ syn_opt_arg.has_cont_list = TRUE;
+ syn_opt_arg.cont_list = NULL;
+ syn_opt_arg.cont_in_list = NULL;
+ syn_opt_arg.next_list = NULL;
+ rest = get_syn_options(rest, &syn_opt_arg, &conceal_char, eap->skip);
+
+ /* get the pattern. */
+ init_syn_patterns();
+ vim_memset(&item, 0, sizeof(item));
+ rest = get_syn_pattern(rest, &item);
+ if (vim_regcomp_had_eol() && !(syn_opt_arg.flags & HL_EXCLUDENL))
+ syn_opt_arg.flags |= HL_HAS_EOL;
+
+ /* Get options after the pattern */
+ rest = get_syn_options(rest, &syn_opt_arg, &conceal_char, eap->skip);
+
+ if (rest != NULL) /* all arguments are valid */
+ {
+ /*
+ * Check for trailing command and illegal trailing arguments.
+ */
+ eap->nextcmd = check_nextcmd(rest);
+ if (!ends_excmd(*rest) || eap->skip)
+ rest = NULL;
+ else if (ga_grow(&curwin->w_s->b_syn_patterns, 1) != FAIL
+ && (syn_id = syn_check_group(arg,
+ (int)(group_name_end - arg))) != 0)
+ {
+ syn_incl_toplevel(syn_id, &syn_opt_arg.flags);
+ /*
+ * Store the pattern in the syn_items list
+ */
+ idx = curwin->w_s->b_syn_patterns.ga_len;
+ SYN_ITEMS(curwin->w_s)[idx] = item;
+ SYN_ITEMS(curwin->w_s)[idx].sp_syncing = syncing;
+ SYN_ITEMS(curwin->w_s)[idx].sp_type = SPTYPE_MATCH;
+ SYN_ITEMS(curwin->w_s)[idx].sp_syn.id = syn_id;
+ SYN_ITEMS(curwin->w_s)[idx].sp_syn.inc_tag = current_syn_inc_tag;
+ SYN_ITEMS(curwin->w_s)[idx].sp_flags = syn_opt_arg.flags;
+ SYN_ITEMS(curwin->w_s)[idx].sp_sync_idx = sync_idx;
+ SYN_ITEMS(curwin->w_s)[idx].sp_cont_list = syn_opt_arg.cont_list;
+ SYN_ITEMS(curwin->w_s)[idx].sp_syn.cont_in_list =
+ syn_opt_arg.cont_in_list;
+#ifdef FEAT_CONCEAL
+ SYN_ITEMS(curwin->w_s)[idx].sp_cchar = conceal_char;
+#endif
+ if (syn_opt_arg.cont_in_list != NULL)
+ curwin->w_s->b_syn_containedin = TRUE;
+ SYN_ITEMS(curwin->w_s)[idx].sp_next_list = syn_opt_arg.next_list;
+ ++curwin->w_s->b_syn_patterns.ga_len;
+
+ /* remember that we found a match for syncing on */
+ if (syn_opt_arg.flags & (HL_SYNC_HERE|HL_SYNC_THERE))
+ curwin->w_s->b_syn_sync_flags |= SF_MATCH;
+#ifdef FEAT_FOLDING
+ if (syn_opt_arg.flags & HL_FOLD)
+ ++curwin->w_s->b_syn_folditems;
+#endif
+
+ redraw_curbuf_later(SOME_VALID);
+ syn_stack_free_all(curwin->w_s); /* Need to recompute all syntax. */
+ return; /* don't free the progs and patterns now */
+ }
+ }
+
+ /*
+ * Something failed, free the allocated memory.
+ */
+ vim_regfree(item.sp_prog);
+ vim_free(item.sp_pattern);
+ vim_free(syn_opt_arg.cont_list);
+ vim_free(syn_opt_arg.cont_in_list);
+ vim_free(syn_opt_arg.next_list);
+
+ if (rest == NULL)
+ semsg(_(e_invarg2), arg);
+}
+
+/*
+ * Handle ":syntax region {group-name} [matchgroup={group-name}]
+ * start {start} .. [skip {skip}] end {end} .. [{options}]".
+ */
+ static void
+syn_cmd_region(
+ exarg_T *eap,
+ int syncing) /* TRUE for ":syntax sync region .." */
+{
+ char_u *arg = eap->arg;
+ char_u *group_name_end;
+ char_u *rest; /* next arg, NULL on error */
+ char_u *key_end;
+ char_u *key = NULL;
+ char_u *p;
+ int item;
+#define ITEM_START 0
+#define ITEM_SKIP 1
+#define ITEM_END 2
+#define ITEM_MATCHGROUP 3
+ struct pat_ptr
+ {
+ synpat_T *pp_synp; /* pointer to syn_pattern */
+ int pp_matchgroup_id; /* matchgroup ID */
+ struct pat_ptr *pp_next; /* pointer to next pat_ptr */
+ } *(pat_ptrs[3]);
+ /* patterns found in the line */
+ struct pat_ptr *ppp;
+ struct pat_ptr *ppp_next;
+ int pat_count = 0; /* nr of syn_patterns found */
+ int syn_id;
+ int matchgroup_id = 0;
+ int not_enough = FALSE; /* not enough arguments */
+ int illegal = FALSE; /* illegal arguments */
+ int success = FALSE;
+ int idx;
+ syn_opt_arg_T syn_opt_arg;
+ int conceal_char = NUL;
+
+ /* Isolate the group name, check for validity */
+ rest = get_group_name(arg, &group_name_end);
+
+ pat_ptrs[0] = NULL;
+ pat_ptrs[1] = NULL;
+ pat_ptrs[2] = NULL;
+
+ init_syn_patterns();
+
+ syn_opt_arg.flags = 0;
+ syn_opt_arg.keyword = FALSE;
+ syn_opt_arg.sync_idx = NULL;
+ syn_opt_arg.has_cont_list = TRUE;
+ syn_opt_arg.cont_list = NULL;
+ syn_opt_arg.cont_in_list = NULL;
+ syn_opt_arg.next_list = NULL;
+
+ /*
+ * get the options, patterns and matchgroup.
+ */
+ while (rest != NULL && !ends_excmd(*rest))
+ {
+ /* Check for option arguments */
+ rest = get_syn_options(rest, &syn_opt_arg, &conceal_char, eap->skip);
+ if (rest == NULL || ends_excmd(*rest))
+ break;
+
+ /* must be a pattern or matchgroup then */
+ key_end = rest;
+ while (*key_end && !VIM_ISWHITE(*key_end) && *key_end != '=')
+ ++key_end;
+ vim_free(key);
+ key = vim_strnsave_up(rest, (int)(key_end - rest));
+ if (key == NULL) /* out of memory */
+ {
+ rest = NULL;
+ break;
+ }
+ if (STRCMP(key, "MATCHGROUP") == 0)
+ item = ITEM_MATCHGROUP;
+ else if (STRCMP(key, "START") == 0)
+ item = ITEM_START;
+ else if (STRCMP(key, "END") == 0)
+ item = ITEM_END;
+ else if (STRCMP(key, "SKIP") == 0)
+ {
+ if (pat_ptrs[ITEM_SKIP] != NULL) /* one skip pattern allowed */
+ {
+ illegal = TRUE;
+ break;
+ }
+ item = ITEM_SKIP;
+ }
+ else
+ break;
+ rest = skipwhite(key_end);
+ if (*rest != '=')
+ {
+ rest = NULL;
+ semsg(_("E398: Missing '=': %s"), arg);
+ break;
+ }
+ rest = skipwhite(rest + 1);
+ if (*rest == NUL)
+ {
+ not_enough = TRUE;
+ break;
+ }
+
+ if (item == ITEM_MATCHGROUP)
+ {
+ p = skiptowhite(rest);
+ if ((p - rest == 4 && STRNCMP(rest, "NONE", 4) == 0) || eap->skip)
+ matchgroup_id = 0;
+ else
+ {
+ matchgroup_id = syn_check_group(rest, (int)(p - rest));
+ if (matchgroup_id == 0)
+ {
+ illegal = TRUE;
+ break;
+ }
+ }
+ rest = skipwhite(p);
+ }
+ else
+ {
+ /*
+ * Allocate room for a syn_pattern, and link it in the list of
+ * syn_patterns for this item, at the start (because the list is
+ * used from end to start).
+ */
+ ppp = (struct pat_ptr *)alloc((unsigned)sizeof(struct pat_ptr));
+ if (ppp == NULL)
+ {
+ rest = NULL;
+ break;
+ }
+ ppp->pp_next = pat_ptrs[item];
+ pat_ptrs[item] = ppp;
+ ppp->pp_synp = (synpat_T *)alloc_clear((unsigned)sizeof(synpat_T));
+ if (ppp->pp_synp == NULL)
+ {
+ rest = NULL;
+ break;
+ }
+
+ /*
+ * Get the syntax pattern and the following offset(s).
+ */
+ /* Enable the appropriate \z specials. */
+ if (item == ITEM_START)
+ reg_do_extmatch = REX_SET;
+ else if (item == ITEM_SKIP || item == ITEM_END)
+ reg_do_extmatch = REX_USE;
+ rest = get_syn_pattern(rest, ppp->pp_synp);
+ reg_do_extmatch = 0;
+ if (item == ITEM_END && vim_regcomp_had_eol()
+ && !(syn_opt_arg.flags & HL_EXCLUDENL))
+ ppp->pp_synp->sp_flags |= HL_HAS_EOL;
+ ppp->pp_matchgroup_id = matchgroup_id;
+ ++pat_count;
+ }
+ }
+ vim_free(key);
+ if (illegal || not_enough)
+ rest = NULL;
+
+ /*
+ * Must have a "start" and "end" pattern.
+ */
+ if (rest != NULL && (pat_ptrs[ITEM_START] == NULL ||
+ pat_ptrs[ITEM_END] == NULL))
+ {
+ not_enough = TRUE;
+ rest = NULL;
+ }
+
+ if (rest != NULL)
+ {
+ /*
+ * Check for trailing garbage or command.
+ * If OK, add the item.
+ */
+ eap->nextcmd = check_nextcmd(rest);
+ if (!ends_excmd(*rest) || eap->skip)
+ rest = NULL;
+ else if (ga_grow(&(curwin->w_s->b_syn_patterns), pat_count) != FAIL
+ && (syn_id = syn_check_group(arg,
+ (int)(group_name_end - arg))) != 0)
+ {
+ syn_incl_toplevel(syn_id, &syn_opt_arg.flags);
+ /*
+ * Store the start/skip/end in the syn_items list
+ */
+ idx = curwin->w_s->b_syn_patterns.ga_len;
+ for (item = ITEM_START; item <= ITEM_END; ++item)
+ {
+ for (ppp = pat_ptrs[item]; ppp != NULL; ppp = ppp->pp_next)
+ {
+ SYN_ITEMS(curwin->w_s)[idx] = *(ppp->pp_synp);
+ SYN_ITEMS(curwin->w_s)[idx].sp_syncing = syncing;
+ SYN_ITEMS(curwin->w_s)[idx].sp_type =
+ (item == ITEM_START) ? SPTYPE_START :
+ (item == ITEM_SKIP) ? SPTYPE_SKIP : SPTYPE_END;
+ SYN_ITEMS(curwin->w_s)[idx].sp_flags |= syn_opt_arg.flags;
+ SYN_ITEMS(curwin->w_s)[idx].sp_syn.id = syn_id;
+ SYN_ITEMS(curwin->w_s)[idx].sp_syn.inc_tag =
+ current_syn_inc_tag;
+ SYN_ITEMS(curwin->w_s)[idx].sp_syn_match_id =
+ ppp->pp_matchgroup_id;
+#ifdef FEAT_CONCEAL
+ SYN_ITEMS(curwin->w_s)[idx].sp_cchar = conceal_char;
+#endif
+ if (item == ITEM_START)
+ {
+ SYN_ITEMS(curwin->w_s)[idx].sp_cont_list =
+ syn_opt_arg.cont_list;
+ SYN_ITEMS(curwin->w_s)[idx].sp_syn.cont_in_list =
+ syn_opt_arg.cont_in_list;
+ if (syn_opt_arg.cont_in_list != NULL)
+ curwin->w_s->b_syn_containedin = TRUE;
+ SYN_ITEMS(curwin->w_s)[idx].sp_next_list =
+ syn_opt_arg.next_list;
+ }
+ ++curwin->w_s->b_syn_patterns.ga_len;
+ ++idx;
+#ifdef FEAT_FOLDING
+ if (syn_opt_arg.flags & HL_FOLD)
+ ++curwin->w_s->b_syn_folditems;
+#endif
+ }
+ }
+
+ redraw_curbuf_later(SOME_VALID);
+ syn_stack_free_all(curwin->w_s); /* Need to recompute all syntax. */
+ success = TRUE; /* don't free the progs and patterns now */
+ }
+ }
+
+ /*
+ * Free the allocated memory.
+ */
+ for (item = ITEM_START; item <= ITEM_END; ++item)
+ for (ppp = pat_ptrs[item]; ppp != NULL; ppp = ppp_next)
+ {
+ if (!success)
+ {
+ vim_regfree(ppp->pp_synp->sp_prog);
+ vim_free(ppp->pp_synp->sp_pattern);
+ }
+ vim_free(ppp->pp_synp);
+ ppp_next = ppp->pp_next;
+ vim_free(ppp);
+ }
+
+ if (!success)
+ {
+ vim_free(syn_opt_arg.cont_list);
+ vim_free(syn_opt_arg.cont_in_list);
+ vim_free(syn_opt_arg.next_list);
+ if (not_enough)
+ semsg(_("E399: Not enough arguments: syntax region %s"), arg);
+ else if (illegal || rest == NULL)
+ semsg(_(e_invarg2), arg);
+ }
+}
+
+/*
+ * A simple syntax group ID comparison function suitable for use in qsort()
+ */
+ static int
+#ifdef __BORLANDC__
+_RTLENTRYF
+#endif
+syn_compare_stub(const void *v1, const void *v2)
+{
+ const short *s1 = v1;
+ const short *s2 = v2;
+
+ return (*s1 > *s2 ? 1 : *s1 < *s2 ? -1 : 0);
+}
+
+/*
+ * Combines lists of syntax clusters.
+ * *clstr1 and *clstr2 must both be allocated memory; they will be consumed.
+ */
+ static void
+syn_combine_list(short **clstr1, short **clstr2, int list_op)
+{
+ int count1 = 0;
+ int count2 = 0;
+ short *g1;
+ short *g2;
+ short *clstr = NULL;
+ int count;
+ int round;
+
+ /*
+ * Handle degenerate cases.
+ */
+ if (*clstr2 == NULL)
+ return;
+ if (*clstr1 == NULL || list_op == CLUSTER_REPLACE)
+ {
+ if (list_op == CLUSTER_REPLACE)
+ vim_free(*clstr1);
+ if (list_op == CLUSTER_REPLACE || list_op == CLUSTER_ADD)
+ *clstr1 = *clstr2;
+ else
+ vim_free(*clstr2);
+ return;
+ }
+
+ for (g1 = *clstr1; *g1; g1++)
+ ++count1;
+ for (g2 = *clstr2; *g2; g2++)
+ ++count2;
+
+ /*
+ * For speed purposes, sort both lists.
+ */
+ qsort(*clstr1, (size_t)count1, sizeof(short), syn_compare_stub);
+ qsort(*clstr2, (size_t)count2, sizeof(short), syn_compare_stub);
+
+ /*
+ * We proceed in two passes; in round 1, we count the elements to place
+ * in the new list, and in round 2, we allocate and populate the new
+ * list. For speed, we use a mergesort-like method, adding the smaller
+ * of the current elements in each list to the new list.
+ */
+ for (round = 1; round <= 2; round++)
+ {
+ g1 = *clstr1;
+ g2 = *clstr2;
+ count = 0;
+
+ /*
+ * First, loop through the lists until one of them is empty.
+ */
+ while (*g1 && *g2)
+ {
+ /*
+ * We always want to add from the first list.
+ */
+ if (*g1 < *g2)
+ {
+ if (round == 2)
+ clstr[count] = *g1;
+ count++;
+ g1++;
+ continue;
+ }
+ /*
+ * We only want to add from the second list if we're adding the
+ * lists.
+ */
+ if (list_op == CLUSTER_ADD)
+ {
+ if (round == 2)
+ clstr[count] = *g2;
+ count++;
+ }
+ if (*g1 == *g2)
+ g1++;
+ g2++;
+ }
+
+ /*
+ * Now add the leftovers from whichever list didn't get finished
+ * first. As before, we only want to add from the second list if
+ * we're adding the lists.
+ */
+ for (; *g1; g1++, count++)
+ if (round == 2)
+ clstr[count] = *g1;
+ if (list_op == CLUSTER_ADD)
+ for (; *g2; g2++, count++)
+ if (round == 2)
+ clstr[count] = *g2;
+
+ if (round == 1)
+ {
+ /*
+ * If the group ended up empty, we don't need to allocate any
+ * space for it.
+ */
+ if (count == 0)
+ {
+ clstr = NULL;
+ break;
+ }
+ clstr = (short *)alloc((unsigned)((count + 1) * sizeof(short)));
+ if (clstr == NULL)
+ break;
+ clstr[count] = 0;
+ }
+ }
+
+ /*
+ * Finally, put the new list in place.
+ */
+ vim_free(*clstr1);
+ vim_free(*clstr2);
+ *clstr1 = clstr;
+}
+
+/*
+ * Lookup a syntax cluster name and return its ID.
+ * If it is not found, 0 is returned.
+ */
+ static int
+syn_scl_name2id(char_u *name)
+{
+ int i;
+ char_u *name_u;
+
+ /* Avoid using stricmp() too much, it's slow on some systems */
+ name_u = vim_strsave_up(name);
+ if (name_u == NULL)
+ return 0;
+ for (i = curwin->w_s->b_syn_clusters.ga_len; --i >= 0; )
+ if (SYN_CLSTR(curwin->w_s)[i].scl_name_u != NULL
+ && STRCMP(name_u, SYN_CLSTR(curwin->w_s)[i].scl_name_u) == 0)
+ break;
+ vim_free(name_u);
+ return (i < 0 ? 0 : i + SYNID_CLUSTER);
+}
+
+/*
+ * Like syn_scl_name2id(), but take a pointer + length argument.
+ */
+ static int
+syn_scl_namen2id(char_u *linep, int len)
+{
+ char_u *name;
+ int id = 0;
+
+ name = vim_strnsave(linep, len);
+ if (name != NULL)
+ {
+ id = syn_scl_name2id(name);
+ vim_free(name);
+ }
+ return id;
+}
+
+/*
+ * Find syntax cluster name in the table and return its ID.
+ * The argument is a pointer to the name and the length of the name.
+ * If it doesn't exist yet, a new entry is created.
+ * Return 0 for failure.
+ */
+ static int
+syn_check_cluster(char_u *pp, int len)
+{
+ int id;
+ char_u *name;
+
+ name = vim_strnsave(pp, len);
+ if (name == NULL)
+ return 0;
+
+ id = syn_scl_name2id(name);
+ if (id == 0) /* doesn't exist yet */
+ id = syn_add_cluster(name);
+ else
+ vim_free(name);
+ return id;
+}
+
+/*
+ * Add new syntax cluster and return its ID.
+ * "name" must be an allocated string, it will be consumed.
+ * Return 0 for failure.
+ */
+ static int
+syn_add_cluster(char_u *name)
+{
+ int len;
+
+ /*
+ * First call for this growarray: init growing array.
+ */
+ if (curwin->w_s->b_syn_clusters.ga_data == NULL)
+ {
+ curwin->w_s->b_syn_clusters.ga_itemsize = sizeof(syn_cluster_T);
+ curwin->w_s->b_syn_clusters.ga_growsize = 10;
+ }
+
+ len = curwin->w_s->b_syn_clusters.ga_len;
+ if (len >= MAX_CLUSTER_ID)
+ {
+ emsg(_("E848: Too many syntax clusters"));
+ vim_free(name);
+ return 0;
+ }
+
+ /*
+ * Make room for at least one other cluster entry.
+ */
+ if (ga_grow(&curwin->w_s->b_syn_clusters, 1) == FAIL)
+ {
+ vim_free(name);
+ return 0;
+ }
+
+ vim_memset(&(SYN_CLSTR(curwin->w_s)[len]), 0, sizeof(syn_cluster_T));
+ SYN_CLSTR(curwin->w_s)[len].scl_name = name;
+ SYN_CLSTR(curwin->w_s)[len].scl_name_u = vim_strsave_up(name);
+ SYN_CLSTR(curwin->w_s)[len].scl_list = NULL;
+ ++curwin->w_s->b_syn_clusters.ga_len;
+
+ if (STRICMP(name, "Spell") == 0)
+ curwin->w_s->b_spell_cluster_id = len + SYNID_CLUSTER;
+ if (STRICMP(name, "NoSpell") == 0)
+ curwin->w_s->b_nospell_cluster_id = len + SYNID_CLUSTER;
+
+ return len + SYNID_CLUSTER;
+}
+
+/*
+ * Handle ":syntax cluster {cluster-name} [contains={groupname},..]
+ * [add={groupname},..] [remove={groupname},..]".
+ */
+ static void
+syn_cmd_cluster(exarg_T *eap, int syncing UNUSED)
+{
+ char_u *arg = eap->arg;
+ char_u *group_name_end;
+ char_u *rest;
+ int scl_id;
+ short *clstr_list;
+ int got_clstr = FALSE;
+ int opt_len;
+ int list_op;
+
+ eap->nextcmd = find_nextcmd(arg);
+ if (eap->skip)
+ return;
+
+ rest = get_group_name(arg, &group_name_end);
+
+ if (rest != NULL)
+ {
+ scl_id = syn_check_cluster(arg, (int)(group_name_end - arg));
+ if (scl_id == 0)
+ return;
+ scl_id -= SYNID_CLUSTER;
+
+ for (;;)
+ {
+ if (STRNICMP(rest, "add", 3) == 0
+ && (VIM_ISWHITE(rest[3]) || rest[3] == '='))
+ {
+ opt_len = 3;
+ list_op = CLUSTER_ADD;
+ }
+ else if (STRNICMP(rest, "remove", 6) == 0
+ && (VIM_ISWHITE(rest[6]) || rest[6] == '='))
+ {
+ opt_len = 6;
+ list_op = CLUSTER_SUBTRACT;
+ }
+ else if (STRNICMP(rest, "contains", 8) == 0
+ && (VIM_ISWHITE(rest[8]) || rest[8] == '='))
+ {
+ opt_len = 8;
+ list_op = CLUSTER_REPLACE;
+ }
+ else
+ break;
+
+ clstr_list = NULL;
+ if (get_id_list(&rest, opt_len, &clstr_list, eap->skip) == FAIL)
+ {
+ semsg(_(e_invarg2), rest);
+ break;
+ }
+ if (scl_id >= 0)
+ syn_combine_list(&SYN_CLSTR(curwin->w_s)[scl_id].scl_list,
+ &clstr_list, list_op);
+ else
+ vim_free(clstr_list);
+ got_clstr = TRUE;
+ }
+
+ if (got_clstr)
+ {
+ redraw_curbuf_later(SOME_VALID);
+ syn_stack_free_all(curwin->w_s); /* Need to recompute all. */
+ }
+ }
+
+ if (!got_clstr)
+ emsg(_("E400: No cluster specified"));
+ if (rest == NULL || !ends_excmd(*rest))
+ semsg(_(e_invarg2), arg);
+}
+
+/*
+ * On first call for current buffer: Init growing array.
+ */
+ static void
+init_syn_patterns(void)
+{
+ curwin->w_s->b_syn_patterns.ga_itemsize = sizeof(synpat_T);
+ curwin->w_s->b_syn_patterns.ga_growsize = 10;
+}
+
+/*
+ * Get one pattern for a ":syntax match" or ":syntax region" command.
+ * Stores the pattern and program in a synpat_T.
+ * Returns a pointer to the next argument, or NULL in case of an error.
+ */
+ static char_u *
+get_syn_pattern(char_u *arg, synpat_T *ci)
+{
+ char_u *end;
+ int *p;
+ int idx;
+ char_u *cpo_save;
+
+ /* need at least three chars */
+ if (arg == NULL || arg[0] == NUL || arg[1] == NUL || arg[2] == NUL)
+ return NULL;
+
+ end = skip_regexp(arg + 1, *arg, TRUE, NULL);
+ if (*end != *arg) /* end delimiter not found */
+ {
+ semsg(_("E401: Pattern delimiter not found: %s"), arg);
+ return NULL;
+ }
+ /* store the pattern and compiled regexp program */
+ if ((ci->sp_pattern = vim_strnsave(arg + 1, (int)(end - arg - 1))) == NULL)
+ return NULL;
+
+ /* Make 'cpoptions' empty, to avoid the 'l' flag */
+ cpo_save = p_cpo;
+ p_cpo = (char_u *)"";
+ ci->sp_prog = vim_regcomp(ci->sp_pattern, RE_MAGIC);
+ p_cpo = cpo_save;
+
+ if (ci->sp_prog == NULL)
+ return NULL;
+ ci->sp_ic = curwin->w_s->b_syn_ic;
+#ifdef FEAT_PROFILE
+ syn_clear_time(&ci->sp_time);
+#endif
+
+ /*
+ * Check for a match, highlight or region offset.
+ */
+ ++end;
+ do
+ {
+ for (idx = SPO_COUNT; --idx >= 0; )
+ if (STRNCMP(end, spo_name_tab[idx], 3) == 0)
+ break;
+ if (idx >= 0)
+ {
+ p = &(ci->sp_offsets[idx]);
+ if (idx != SPO_LC_OFF)
+ switch (end[3])
+ {
+ case 's': break;
+ case 'b': break;
+ case 'e': idx += SPO_COUNT; break;
+ default: idx = -1; break;
+ }
+ if (idx >= 0)
+ {
+ ci->sp_off_flags |= (1 << idx);
+ if (idx == SPO_LC_OFF) /* lc=99 */
+ {
+ end += 3;
+ *p = getdigits(&end);
+
+ /* "lc=" offset automatically sets "ms=" offset */
+ if (!(ci->sp_off_flags & (1 << SPO_MS_OFF)))
+ {
+ ci->sp_off_flags |= (1 << SPO_MS_OFF);
+ ci->sp_offsets[SPO_MS_OFF] = *p;
+ }
+ }
+ else /* yy=x+99 */
+ {
+ end += 4;
+ if (*end == '+')
+ {
+ ++end;
+ *p = getdigits(&end); /* positive offset */
+ }
+ else if (*end == '-')
+ {
+ ++end;
+ *p = -getdigits(&end); /* negative offset */
+ }
+ }
+ if (*end != ',')
+ break;
+ ++end;
+ }
+ }
+ } while (idx >= 0);
+
+ if (!ends_excmd(*end) && !VIM_ISWHITE(*end))
+ {
+ semsg(_("E402: Garbage after pattern: %s"), arg);
+ return NULL;
+ }
+ return skipwhite(end);
+}
+
+/*
+ * Handle ":syntax sync .." command.
+ */
+ static void
+syn_cmd_sync(exarg_T *eap, int syncing UNUSED)
+{
+ char_u *arg_start = eap->arg;
+ char_u *arg_end;
+ char_u *key = NULL;
+ char_u *next_arg;
+ int illegal = FALSE;
+ int finished = FALSE;
+ long n;
+ char_u *cpo_save;
+
+ if (ends_excmd(*arg_start))
+ {
+ syn_cmd_list(eap, TRUE);
+ return;
+ }
+
+ while (!ends_excmd(*arg_start))
+ {
+ arg_end = skiptowhite(arg_start);
+ next_arg = skipwhite(arg_end);
+ vim_free(key);
+ key = vim_strnsave_up(arg_start, (int)(arg_end - arg_start));
+ if (STRCMP(key, "CCOMMENT") == 0)
+ {
+ if (!eap->skip)
+ curwin->w_s->b_syn_sync_flags |= SF_CCOMMENT;
+ if (!ends_excmd(*next_arg))
+ {
+ arg_end = skiptowhite(next_arg);
+ if (!eap->skip)
+ curwin->w_s->b_syn_sync_id = syn_check_group(next_arg,
+ (int)(arg_end - next_arg));
+ next_arg = skipwhite(arg_end);
+ }
+ else if (!eap->skip)
+ curwin->w_s->b_syn_sync_id = syn_name2id((char_u *)"Comment");
+ }
+ else if ( STRNCMP(key, "LINES", 5) == 0
+ || STRNCMP(key, "MINLINES", 8) == 0
+ || STRNCMP(key, "MAXLINES", 8) == 0
+ || STRNCMP(key, "LINEBREAKS", 10) == 0)
+ {
+ if (key[4] == 'S')
+ arg_end = key + 6;
+ else if (key[0] == 'L')
+ arg_end = key + 11;
+ else
+ arg_end = key + 9;
+ if (arg_end[-1] != '=' || !VIM_ISDIGIT(*arg_end))
+ {
+ illegal = TRUE;
+ break;
+ }
+ n = getdigits(&arg_end);
+ if (!eap->skip)
+ {
+ if (key[4] == 'B')
+ curwin->w_s->b_syn_sync_linebreaks = n;
+ else if (key[1] == 'A')
+ curwin->w_s->b_syn_sync_maxlines = n;
+ else
+ curwin->w_s->b_syn_sync_minlines = n;
+ }
+ }
+ else if (STRCMP(key, "FROMSTART") == 0)
+ {
+ if (!eap->skip)
+ {
+ curwin->w_s->b_syn_sync_minlines = MAXLNUM;
+ curwin->w_s->b_syn_sync_maxlines = 0;
+ }
+ }
+ else if (STRCMP(key, "LINECONT") == 0)
+ {
+ if (*next_arg == NUL) /* missing pattern */
+ {
+ illegal = TRUE;
+ break;
+ }
+ if (curwin->w_s->b_syn_linecont_pat != NULL)
+ {
+ emsg(_("E403: syntax sync: line continuations pattern specified twice"));
+ finished = TRUE;
+ break;
+ }
+ arg_end = skip_regexp(next_arg + 1, *next_arg, TRUE, NULL);
+ if (*arg_end != *next_arg) /* end delimiter not found */
+ {
+ illegal = TRUE;
+ break;
+ }
+
+ if (!eap->skip)
+ {
+ /* store the pattern and compiled regexp program */
+ if ((curwin->w_s->b_syn_linecont_pat = vim_strnsave(next_arg + 1,
+ (int)(arg_end - next_arg - 1))) == NULL)
+ {
+ finished = TRUE;
+ break;
+ }
+ curwin->w_s->b_syn_linecont_ic = curwin->w_s->b_syn_ic;
+
+ /* Make 'cpoptions' empty, to avoid the 'l' flag */
+ cpo_save = p_cpo;
+ p_cpo = (char_u *)"";
+ curwin->w_s->b_syn_linecont_prog =
+ vim_regcomp(curwin->w_s->b_syn_linecont_pat, RE_MAGIC);
+ p_cpo = cpo_save;
+#ifdef FEAT_PROFILE
+ syn_clear_time(&curwin->w_s->b_syn_linecont_time);
+#endif
+
+ if (curwin->w_s->b_syn_linecont_prog == NULL)
+ {
+ VIM_CLEAR(curwin->w_s->b_syn_linecont_pat);
+ finished = TRUE;
+ break;
+ }
+ }
+ next_arg = skipwhite(arg_end + 1);
+ }
+ else
+ {
+ eap->arg = next_arg;
+ if (STRCMP(key, "MATCH") == 0)
+ syn_cmd_match(eap, TRUE);
+ else if (STRCMP(key, "REGION") == 0)
+ syn_cmd_region(eap, TRUE);
+ else if (STRCMP(key, "CLEAR") == 0)
+ syn_cmd_clear(eap, TRUE);
+ else
+ illegal = TRUE;
+ finished = TRUE;
+ break;
+ }
+ arg_start = next_arg;
+ }
+ vim_free(key);
+ if (illegal)
+ semsg(_("E404: Illegal arguments: %s"), arg_start);
+ else if (!finished)
+ {
+ eap->nextcmd = check_nextcmd(arg_start);
+ redraw_curbuf_later(SOME_VALID);
+ syn_stack_free_all(curwin->w_s); /* Need to recompute all syntax. */
+ }
+}
+
+/*
+ * Convert a line of highlight group names into a list of group ID numbers.
+ * "arg" should point to the "contains" or "nextgroup" keyword.
+ * "arg" is advanced to after the last group name.
+ * Careful: the argument is modified (NULs added).
+ * returns FAIL for some error, OK for success.
+ */
+ static int
+get_id_list(
+ char_u **arg,
+ int keylen, /* length of keyword */
+ short **list, /* where to store the resulting list, if not
+ NULL, the list is silently skipped! */
+ int skip)
+{
+ char_u *p = NULL;
+ char_u *end;
+ int round;
+ int count;
+ int total_count = 0;
+ short *retval = NULL;
+ char_u *name;
+ regmatch_T regmatch;
+ int id;
+ int i;
+ int failed = FALSE;
+
+ /*
+ * We parse the list twice:
+ * round == 1: count the number of items, allocate the array.
+ * round == 2: fill the array with the items.
+ * In round 1 new groups may be added, causing the number of items to
+ * grow when a regexp is used. In that case round 1 is done once again.
+ */
+ for (round = 1; round <= 2; ++round)
+ {
+ /*
+ * skip "contains"
+ */
+ p = skipwhite(*arg + keylen);
+ if (*p != '=')
+ {
+ semsg(_("E405: Missing equal sign: %s"), *arg);
+ break;
+ }
+ p = skipwhite(p + 1);
+ if (ends_excmd(*p))
+ {
+ semsg(_("E406: Empty argument: %s"), *arg);
+ break;
+ }
+
+ /*
+ * parse the arguments after "contains"
+ */
+ count = 0;
+ while (!ends_excmd(*p))
+ {
+ for (end = p; *end && !VIM_ISWHITE(*end) && *end != ','; ++end)
+ ;
+ name = alloc((int)(end - p + 3)); /* leave room for "^$" */
+ if (name == NULL)
+ {
+ failed = TRUE;
+ break;
+ }
+ vim_strncpy(name + 1, p, end - p);
+ if ( STRCMP(name + 1, "ALLBUT") == 0
+ || STRCMP(name + 1, "ALL") == 0
+ || STRCMP(name + 1, "TOP") == 0
+ || STRCMP(name + 1, "CONTAINED") == 0)
+ {
+ if (TOUPPER_ASC(**arg) != 'C')
+ {
+ semsg(_("E407: %s not allowed here"), name + 1);
+ failed = TRUE;
+ vim_free(name);
+ break;
+ }
+ if (count != 0)
+ {
+ semsg(_("E408: %s must be first in contains list"),
+ name + 1);
+ failed = TRUE;
+ vim_free(name);
+ break;
+ }
+ if (name[1] == 'A')
+ id = SYNID_ALLBUT;
+ else if (name[1] == 'T')
+ id = SYNID_TOP;
+ else
+ id = SYNID_CONTAINED;
+ id += current_syn_inc_tag;
+ }
+ else if (name[1] == '@')
+ {
+ if (skip)
+ id = -1;
+ else
+ id = syn_check_cluster(name + 2, (int)(end - p - 1));
+ }
+ else
+ {
+ /*
+ * Handle full group name.
+ */
+ if (vim_strpbrk(name + 1, (char_u *)"\\.*^$~[") == NULL)
+ id = syn_check_group(name + 1, (int)(end - p));
+ else
+ {
+ /*
+ * Handle match of regexp with group names.
+ */
+ *name = '^';
+ STRCAT(name, "$");
+ regmatch.regprog = vim_regcomp(name, RE_MAGIC);
+ if (regmatch.regprog == NULL)
+ {
+ failed = TRUE;
+ vim_free(name);
+ break;
+ }
+
+ regmatch.rm_ic = TRUE;
+ id = 0;
+ for (i = highlight_ga.ga_len; --i >= 0; )
+ {
+ if (vim_regexec(&regmatch, HL_TABLE()[i].sg_name,
+ (colnr_T)0))
+ {
+ if (round == 2)
+ {
+ /* Got more items than expected; can happen
+ * when adding items that match:
+ * "contains=a.*b,axb".
+ * Go back to first round */
+ if (count >= total_count)
+ {
+ vim_free(retval);
+ round = 1;
+ }
+ else
+ retval[count] = i + 1;
+ }
+ ++count;
+ id = -1; /* remember that we found one */
+ }
+ }
+ vim_regfree(regmatch.regprog);
+ }
+ }
+ vim_free(name);
+ if (id == 0)
+ {
+ semsg(_("E409: Unknown group name: %s"), p);
+ failed = TRUE;
+ break;
+ }
+ if (id > 0)
+ {
+ if (round == 2)
+ {
+ /* Got more items than expected, go back to first round */
+ if (count >= total_count)
+ {
+ vim_free(retval);
+ round = 1;
+ }
+ else
+ retval[count] = id;
+ }
+ ++count;
+ }
+ p = skipwhite(end);
+ if (*p != ',')
+ break;
+ p = skipwhite(p + 1); /* skip comma in between arguments */
+ }
+ if (failed)
+ break;
+ if (round == 1)
+ {
+ retval = (short *)alloc((unsigned)((count + 1) * sizeof(short)));
+ if (retval == NULL)
+ break;
+ retval[count] = 0; /* zero means end of the list */
+ total_count = count;
+ }
+ }
+
+ *arg = p;
+ if (failed || retval == NULL)
+ {
+ vim_free(retval);
+ return FAIL;
+ }
+
+ if (*list == NULL)
+ *list = retval;
+ else
+ vim_free(retval); /* list already found, don't overwrite it */
+
+ return OK;
+}
+
+/*
+ * Make a copy of an ID list.
+ */
+ static short *
+copy_id_list(short *list)
+{
+ int len;
+ int count;
+ short *retval;
+
+ if (list == NULL)
+ return NULL;
+
+ for (count = 0; list[count]; ++count)
+ ;
+ len = (count + 1) * sizeof(short);
+ retval = (short *)alloc((unsigned)len);
+ if (retval != NULL)
+ mch_memmove(retval, list, (size_t)len);
+
+ return retval;
+}
+
+/*
+ * Check if syntax group "ssp" is in the ID list "list" of "cur_si".
+ * "cur_si" can be NULL if not checking the "containedin" list.
+ * Used to check if a syntax item is in the "contains" or "nextgroup" list of
+ * the current item.
+ * This function is called very often, keep it fast!!
+ */
+ static int
+in_id_list(
+ stateitem_T *cur_si, /* current item or NULL */
+ short *list, /* id list */
+ struct sp_syn *ssp, /* group id and ":syn include" tag of group */
+ int contained) /* group id is contained */
+{
+ int retval;
+ short *scl_list;
+ short item;
+ short id = ssp->id;
+ static int depth = 0;
+ int r;
+
+ /* If ssp has a "containedin" list and "cur_si" is in it, return TRUE. */
+ if (cur_si != NULL && ssp->cont_in_list != NULL
+ && !(cur_si->si_flags & HL_MATCH))
+ {
+ /* Ignore transparent items without a contains argument. Double check
+ * that we don't go back past the first one. */
+ while ((cur_si->si_flags & HL_TRANS_CONT)
+ && cur_si > (stateitem_T *)(current_state.ga_data))
+ --cur_si;
+ /* cur_si->si_idx is -1 for keywords, these never contain anything. */
+ if (cur_si->si_idx >= 0 && in_id_list(NULL, ssp->cont_in_list,
+ &(SYN_ITEMS(syn_block)[cur_si->si_idx].sp_syn),
+ SYN_ITEMS(syn_block)[cur_si->si_idx].sp_flags & HL_CONTAINED))
+ return TRUE;
+ }
+
+ if (list == NULL)
+ return FALSE;
+
+ /*
+ * If list is ID_LIST_ALL, we are in a transparent item that isn't
+ * inside anything. Only allow not-contained groups.
+ */
+ if (list == ID_LIST_ALL)
+ return !contained;
+
+ /*
+ * If the first item is "ALLBUT", return TRUE if "id" is NOT in the
+ * contains list. We also require that "id" is at the same ":syn include"
+ * level as the list.
+ */
+ item = *list;
+ if (item >= SYNID_ALLBUT && item < SYNID_CLUSTER)
+ {
+ if (item < SYNID_TOP)
+ {
+ /* ALL or ALLBUT: accept all groups in the same file */
+ if (item - SYNID_ALLBUT != ssp->inc_tag)
+ return FALSE;
+ }
+ else if (item < SYNID_CONTAINED)
+ {
+ /* TOP: accept all not-contained groups in the same file */
+ if (item - SYNID_TOP != ssp->inc_tag || contained)
+ return FALSE;
+ }
+ else
+ {
+ /* CONTAINED: accept all contained groups in the same file */
+ if (item - SYNID_CONTAINED != ssp->inc_tag || !contained)
+ return FALSE;
+ }
+ item = *++list;
+ retval = FALSE;
+ }
+ else
+ retval = TRUE;
+
+ /*
+ * Return "retval" if id is in the contains list.
+ */
+ while (item != 0)
+ {
+ if (item == id)
+ return retval;
+ if (item >= SYNID_CLUSTER)
+ {
+ scl_list = SYN_CLSTR(syn_block)[item - SYNID_CLUSTER].scl_list;
+ /* restrict recursiveness to 30 to avoid an endless loop for a
+ * cluster that includes itself (indirectly) */
+ if (scl_list != NULL && depth < 30)
+ {
+ ++depth;
+ r = in_id_list(NULL, scl_list, ssp, contained);
+ --depth;
+ if (r)
+ return retval;
+ }
+ }
+ item = *++list;
+ }
+ return !retval;
+}
+
+struct subcommand
+{
+ char *name; /* subcommand name */
+ void (*func)(exarg_T *, int); /* function to call */
+};
+
+static struct subcommand subcommands[] =
+{
+ {"case", syn_cmd_case},
+ {"clear", syn_cmd_clear},
+ {"cluster", syn_cmd_cluster},
+ {"conceal", syn_cmd_conceal},
+ {"enable", syn_cmd_enable},
+ {"include", syn_cmd_include},
+ {"iskeyword", syn_cmd_iskeyword},
+ {"keyword", syn_cmd_keyword},
+ {"list", syn_cmd_list},
+ {"manual", syn_cmd_manual},
+ {"match", syn_cmd_match},
+ {"on", syn_cmd_on},
+ {"off", syn_cmd_off},
+ {"region", syn_cmd_region},
+ {"reset", syn_cmd_reset},
+ {"spell", syn_cmd_spell},
+ {"sync", syn_cmd_sync},
+ {"", syn_cmd_list},
+ {NULL, NULL}
+};
+
+/*
+ * ":syntax".
+ * This searches the subcommands[] table for the subcommand name, and calls a
+ * syntax_subcommand() function to do the rest.
+ */
+ void
+ex_syntax(exarg_T *eap)
+{
+ char_u *arg = eap->arg;
+ char_u *subcmd_end;
+ char_u *subcmd_name;
+ int i;
+
+ syn_cmdlinep = eap->cmdlinep;
+
+ /* isolate subcommand name */
+ for (subcmd_end = arg; ASCII_ISALPHA(*subcmd_end); ++subcmd_end)
+ ;
+ subcmd_name = vim_strnsave(arg, (int)(subcmd_end - arg));
+ if (subcmd_name != NULL)
+ {
+ if (eap->skip) /* skip error messages for all subcommands */
+ ++emsg_skip;
+ for (i = 0; ; ++i)
+ {
+ if (subcommands[i].name == NULL)
+ {
+ semsg(_("E410: Invalid :syntax subcommand: %s"), subcmd_name);
+ break;
+ }
+ if (STRCMP(subcmd_name, (char_u *)subcommands[i].name) == 0)
+ {
+ eap->arg = skipwhite(subcmd_end);
+ (subcommands[i].func)(eap, FALSE);
+ break;
+ }
+ }
+ vim_free(subcmd_name);
+ if (eap->skip)
+ --emsg_skip;
+ }
+}
+
+ void
+ex_ownsyntax(exarg_T *eap)
+{
+ char_u *old_value;
+ char_u *new_value;
+
+ if (curwin->w_s == &curwin->w_buffer->b_s)
+ {
+ curwin->w_s = (synblock_T *)alloc(sizeof(synblock_T));
+ memset(curwin->w_s, 0, sizeof(synblock_T));
+ hash_init(&curwin->w_s->b_keywtab);
+ hash_init(&curwin->w_s->b_keywtab_ic);
+#ifdef FEAT_SPELL
+ /* TODO: keep the spell checking as it was. */
+ curwin->w_p_spell = FALSE; /* No spell checking */
+ clear_string_option(&curwin->w_s->b_p_spc);
+ clear_string_option(&curwin->w_s->b_p_spf);
+ clear_string_option(&curwin->w_s->b_p_spl);
+#endif
+ clear_string_option(&curwin->w_s->b_syn_isk);
+ }
+
+ /* save value of b:current_syntax */
+ old_value = get_var_value((char_u *)"b:current_syntax");
+ if (old_value != NULL)
+ old_value = vim_strsave(old_value);
+
+ /* Apply the "syntax" autocommand event, this finds and loads the syntax
+ * file. */
+ apply_autocmds(EVENT_SYNTAX, eap->arg, curbuf->b_fname, TRUE, curbuf);
+
+ /* move value of b:current_syntax to w:current_syntax */
+ new_value = get_var_value((char_u *)"b:current_syntax");
+ if (new_value != NULL)
+ set_internal_string_var((char_u *)"w:current_syntax", new_value);
+
+ /* restore value of b:current_syntax */
+ if (old_value == NULL)
+ do_unlet((char_u *)"b:current_syntax", TRUE);
+ else
+ {
+ set_internal_string_var((char_u *)"b:current_syntax", old_value);
+ vim_free(old_value);
+ }
+}
+
+ int
+syntax_present(win_T *win)
+{
+ return (win->w_s->b_syn_patterns.ga_len != 0
+ || win->w_s->b_syn_clusters.ga_len != 0
+ || win->w_s->b_keywtab.ht_used > 0
+ || win->w_s->b_keywtab_ic.ht_used > 0);
+}
+
+#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
+
+static enum
+{
+ EXP_SUBCMD, /* expand ":syn" sub-commands */
+ EXP_CASE, /* expand ":syn case" arguments */
+ EXP_SPELL, /* expand ":syn spell" arguments */
+ EXP_SYNC /* expand ":syn sync" arguments */
+} expand_what;
+
+/*
+ * Reset include_link, include_default, include_none to 0.
+ * Called when we are done expanding.
+ */
+ void
+reset_expand_highlight(void)
+{
+ include_link = include_default = include_none = 0;
+}
+
+/*
+ * Handle command line completion for :match and :echohl command: Add "None"
+ * as highlight group.
+ */
+ void
+set_context_in_echohl_cmd(expand_T *xp, char_u *arg)
+{
+ xp->xp_context = EXPAND_HIGHLIGHT;
+ xp->xp_pattern = arg;
+ include_none = 1;
+}
+
+/*
+ * Handle command line completion for :syntax command.
+ */
+ void
+set_context_in_syntax_cmd(expand_T *xp, char_u *arg)
+{
+ char_u *p;
+
+ /* Default: expand subcommands */
+ xp->xp_context = EXPAND_SYNTAX;
+ expand_what = EXP_SUBCMD;
+ xp->xp_pattern = arg;
+ include_link = 0;
+ include_default = 0;
+
+ /* (part of) subcommand already typed */
+ if (*arg != NUL)
+ {
+ p = skiptowhite(arg);
+ if (*p != NUL) /* past first word */
+ {
+ xp->xp_pattern = skipwhite(p);
+ if (*skiptowhite(xp->xp_pattern) != NUL)
+ xp->xp_context = EXPAND_NOTHING;
+ else if (STRNICMP(arg, "case", p - arg) == 0)
+ expand_what = EXP_CASE;
+ else if (STRNICMP(arg, "spell", p - arg) == 0)
+ expand_what = EXP_SPELL;
+ else if (STRNICMP(arg, "sync", p - arg) == 0)
+ expand_what = EXP_SYNC;
+ else if ( STRNICMP(arg, "keyword", p - arg) == 0
+ || STRNICMP(arg, "region", p - arg) == 0
+ || STRNICMP(arg, "match", p - arg) == 0
+ || STRNICMP(arg, "list", p - arg) == 0)
+ xp->xp_context = EXPAND_HIGHLIGHT;
+ else
+ xp->xp_context = EXPAND_NOTHING;
+ }
+ }
+}
+
+/*
+ * Function given to ExpandGeneric() to obtain the list syntax names for
+ * expansion.
+ */
+ char_u *
+get_syntax_name(expand_T *xp UNUSED, int idx)
+{
+ switch (expand_what)
+ {
+ case EXP_SUBCMD:
+ return (char_u *)subcommands[idx].name;
+ case EXP_CASE:
+ {
+ static char *case_args[] = {"match", "ignore", NULL};
+ return (char_u *)case_args[idx];
+ }
+ case EXP_SPELL:
+ {
+ static char *spell_args[] =
+ {"toplevel", "notoplevel", "default", NULL};
+ return (char_u *)spell_args[idx];
+ }
+ case EXP_SYNC:
+ {
+ static char *sync_args[] =
+ {"ccomment", "clear", "fromstart",
+ "linebreaks=", "linecont", "lines=", "match",
+ "maxlines=", "minlines=", "region", NULL};
+ return (char_u *)sync_args[idx];
+ }
+ }
+ return NULL;
+}
+
+#endif /* FEAT_CMDL_COMPL */
+
+/*
+ * Function called for expression evaluation: get syntax ID at file position.
+ */
+ int
+syn_get_id(
+ win_T *wp,
+ long lnum,
+ colnr_T col,
+ int trans, /* remove transparency */
+ int *spellp, /* return: can do spell checking */
+ int keep_state) /* keep state of char at "col" */
+{
+ /* When the position is not after the current position and in the same
+ * line of the same buffer, need to restart parsing. */
+ if (wp->w_buffer != syn_buf
+ || lnum != current_lnum
+ || col < current_col)
+ syntax_start(wp, lnum);
+ else if (wp->w_buffer == syn_buf
+ && lnum == current_lnum
+ && col > current_col)
+ /* next_match may not be correct when moving around, e.g. with the
+ * "skip" expression in searchpair() */
+ next_match_idx = -1;
+
+ (void)get_syntax_attr(col, spellp, keep_state);
+
+ return (trans ? current_trans_id : current_id);
+}
+
+#if defined(FEAT_CONCEAL) || defined(PROTO)
+/*
+ * Get extra information about the syntax item. Must be called right after
+ * get_syntax_attr().
+ * Stores the current item sequence nr in "*seqnrp".
+ * Returns the current flags.
+ */
+ int
+get_syntax_info(int *seqnrp)
+{
+ *seqnrp = current_seqnr;
+ return current_flags;
+}
+
+/*
+ * Return conceal substitution character
+ */
+ int
+syn_get_sub_char(void)
+{
+ return current_sub_char;
+}
+#endif
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * Return the syntax ID at position "i" in the current stack.
+ * The caller must have called syn_get_id() before to fill the stack.
+ * Returns -1 when "i" is out of range.
+ */
+ int
+syn_get_stack_item(int i)
+{
+ if (i >= current_state.ga_len)
+ {
+ /* Need to invalidate the state, because we didn't properly finish it
+ * for the last character, "keep_state" was TRUE. */
+ invalidate_current_state();
+ current_col = MAXCOL;
+ return -1;
+ }
+ return CUR_STATE(i).si_id;
+}
+#endif
+
+#if defined(FEAT_FOLDING) || defined(PROTO)
+/*
+ * Function called to get folding level for line "lnum" in window "wp".
+ */
+ int
+syn_get_foldlevel(win_T *wp, long lnum)
+{
+ int level = 0;
+ int i;
+
+ /* Return quickly when there are no fold items at all. */
+ if (wp->w_s->b_syn_folditems != 0
+ && !wp->w_s->b_syn_error
+# ifdef SYN_TIME_LIMIT
+ && !wp->w_s->b_syn_slow
+# endif
+ )
+ {
+ syntax_start(wp, lnum);
+
+ for (i = 0; i < current_state.ga_len; ++i)
+ if (CUR_STATE(i).si_flags & HL_FOLD)
+ ++level;
+ }
+ if (level > wp->w_p_fdn)
+ {
+ level = wp->w_p_fdn;
+ if (level < 0)
+ level = 0;
+ }
+ return level;
+}
+#endif
+
+#if defined(FEAT_PROFILE) || defined(PROTO)
+/*
+ * ":syntime".
+ */
+ void
+ex_syntime(exarg_T *eap)
+{
+ if (STRCMP(eap->arg, "on") == 0)
+ syn_time_on = TRUE;
+ else if (STRCMP(eap->arg, "off") == 0)
+ syn_time_on = FALSE;
+ else if (STRCMP(eap->arg, "clear") == 0)
+ syntime_clear();
+ else if (STRCMP(eap->arg, "report") == 0)
+ syntime_report();
+ else
+ semsg(_(e_invarg2), eap->arg);
+}
+
+ static void
+syn_clear_time(syn_time_T *st)
+{
+ profile_zero(&st->total);
+ profile_zero(&st->slowest);
+ st->count = 0;
+ st->match = 0;
+}
+
+/*
+ * Clear the syntax timing for the current buffer.
+ */
+ static void
+syntime_clear(void)
+{
+ int idx;
+ synpat_T *spp;
+
+ if (!syntax_present(curwin))
+ {
+ msg(_(msg_no_items));
+ return;
+ }
+ for (idx = 0; idx < curwin->w_s->b_syn_patterns.ga_len; ++idx)
+ {
+ spp = &(SYN_ITEMS(curwin->w_s)[idx]);
+ syn_clear_time(&spp->sp_time);
+ }
+}
+
+#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
+/*
+ * Function given to ExpandGeneric() to obtain the possible arguments of the
+ * ":syntime {on,off,clear,report}" command.
+ */
+ char_u *
+get_syntime_arg(expand_T *xp UNUSED, int idx)
+{
+ switch (idx)
+ {
+ case 0: return (char_u *)"on";
+ case 1: return (char_u *)"off";
+ case 2: return (char_u *)"clear";
+ case 3: return (char_u *)"report";
+ }
+ return NULL;
+}
+#endif
+
+typedef struct
+{
+ proftime_T total;
+ int count;
+ int match;
+ proftime_T slowest;
+ proftime_T average;
+ int id;
+ char_u *pattern;
+} time_entry_T;
+
+ static int
+#ifdef __BORLANDC__
+_RTLENTRYF
+#endif
+syn_compare_syntime(const void *v1, const void *v2)
+{
+ const time_entry_T *s1 = v1;
+ const time_entry_T *s2 = v2;
+
+ return profile_cmp(&s1->total, &s2->total);
+}
+
+/*
+ * Clear the syntax timing for the current buffer.
+ */
+ static void
+syntime_report(void)
+{
+ int idx;
+ synpat_T *spp;
+# ifdef FEAT_FLOAT
+ proftime_T tm;
+# endif
+ int len;
+ proftime_T total_total;
+ int total_count = 0;
+ garray_T ga;
+ time_entry_T *p;
+
+ if (!syntax_present(curwin))
+ {
+ msg(_(msg_no_items));
+ return;
+ }
+
+ ga_init2(&ga, sizeof(time_entry_T), 50);
+ profile_zero(&total_total);
+ for (idx = 0; idx < curwin->w_s->b_syn_patterns.ga_len; ++idx)
+ {
+ spp = &(SYN_ITEMS(curwin->w_s)[idx]);
+ if (spp->sp_time.count > 0)
+ {
+ (void)ga_grow(&ga, 1);
+ p = ((time_entry_T *)ga.ga_data) + ga.ga_len;
+ p->total = spp->sp_time.total;
+ profile_add(&total_total, &spp->sp_time.total);
+ p->count = spp->sp_time.count;
+ p->match = spp->sp_time.match;
+ total_count += spp->sp_time.count;
+ p->slowest = spp->sp_time.slowest;
+# ifdef FEAT_FLOAT
+ profile_divide(&spp->sp_time.total, spp->sp_time.count, &tm);
+ p->average = tm;
+# endif
+ p->id = spp->sp_syn.id;
+ p->pattern = spp->sp_pattern;
+ ++ga.ga_len;
+ }
+ }
+
+ /* Sort on total time. Skip if there are no items to avoid passing NULL
+ * pointer to qsort(). */
+ if (ga.ga_len > 1)
+ qsort(ga.ga_data, (size_t)ga.ga_len, sizeof(time_entry_T),
+ syn_compare_syntime);
+
+ msg_puts_title(_(" TOTAL COUNT MATCH SLOWEST AVERAGE NAME PATTERN"));
+ msg_puts("\n");
+ for (idx = 0; idx < ga.ga_len && !got_int; ++idx)
+ {
+ p = ((time_entry_T *)ga.ga_data) + idx;
+
+ msg_puts(profile_msg(&p->total));
+ msg_puts(" "); /* make sure there is always a separating space */
+ msg_advance(13);
+ msg_outnum(p->count);
+ msg_puts(" ");
+ msg_advance(20);
+ msg_outnum(p->match);
+ msg_puts(" ");
+ msg_advance(26);
+ msg_puts(profile_msg(&p->slowest));
+ msg_puts(" ");
+ msg_advance(38);
+# ifdef FEAT_FLOAT
+ msg_puts(profile_msg(&p->average));
+ msg_puts(" ");
+# endif
+ msg_advance(50);
+ msg_outtrans(HL_TABLE()[p->id - 1].sg_name);
+ msg_puts(" ");
+
+ msg_advance(69);
+ if (Columns < 80)
+ len = 20; /* will wrap anyway */
+ else
+ len = Columns - 70;
+ if (len > (int)STRLEN(p->pattern))
+ len = (int)STRLEN(p->pattern);
+ msg_outtrans_len(p->pattern, len);
+ msg_puts("\n");
+ }
+ ga_clear(&ga);
+ if (!got_int)
+ {
+ msg_puts("\n");
+ msg_puts(profile_msg(&total_total));
+ msg_advance(13);
+ msg_outnum(total_count);
+ msg_puts("\n");
+ }
+}
+#endif
+
+#endif /* FEAT_SYN_HL */
+
+/**************************************
+ * Highlighting stuff *
+ **************************************/
+
+/*
+ * The default highlight groups. These are compiled-in for fast startup and
+ * they still work when the runtime files can't be found.
+ * When making changes here, also change runtime/colors/default.vim!
+ * The #ifdefs are needed to reduce the amount of static data. Helps to make
+ * the 16 bit DOS (museum) version compile.
+ */
+#if defined(FEAT_GUI) || defined(FEAT_EVAL)
+# define CENT(a, b) b
+#else
+# define CENT(a, b) a
+#endif
+static char *(highlight_init_both[]) = {
+ CENT("ErrorMsg term=standout ctermbg=DarkRed ctermfg=White",
+ "ErrorMsg term=standout ctermbg=DarkRed ctermfg=White guibg=Red guifg=White"),
+ CENT("IncSearch term=reverse cterm=reverse",
+ "IncSearch term=reverse cterm=reverse gui=reverse"),
+ CENT("ModeMsg term=bold cterm=bold",
+ "ModeMsg term=bold cterm=bold gui=bold"),
+ CENT("NonText term=bold ctermfg=Blue",
+ "NonText term=bold ctermfg=Blue gui=bold guifg=Blue"),
+ CENT("StatusLine term=reverse,bold cterm=reverse,bold",
+ "StatusLine term=reverse,bold cterm=reverse,bold gui=reverse,bold"),
+ CENT("StatusLineNC term=reverse cterm=reverse",
+ "StatusLineNC term=reverse cterm=reverse gui=reverse"),
+ "default link EndOfBuffer NonText",
+ CENT("VertSplit term=reverse cterm=reverse",
+ "VertSplit term=reverse cterm=reverse gui=reverse"),
+#ifdef FEAT_CLIPBOARD
+ CENT("VisualNOS term=underline,bold cterm=underline,bold",
+ "VisualNOS term=underline,bold cterm=underline,bold gui=underline,bold"),
+#endif
+#ifdef FEAT_DIFF
+ CENT("DiffText term=reverse cterm=bold ctermbg=Red",
+ "DiffText term=reverse cterm=bold ctermbg=Red gui=bold guibg=Red"),
+#endif
+#ifdef FEAT_INS_EXPAND
+ CENT("PmenuSbar ctermbg=Grey",
+ "PmenuSbar ctermbg=Grey guibg=Grey"),
+#endif
+ CENT("TabLineSel term=bold cterm=bold",
+ "TabLineSel term=bold cterm=bold gui=bold"),
+ CENT("TabLineFill term=reverse cterm=reverse",
+ "TabLineFill term=reverse cterm=reverse gui=reverse"),
+#ifdef FEAT_GUI
+ "Cursor guibg=fg guifg=bg",
+ "lCursor guibg=fg guifg=bg", /* should be different, but what? */
+#endif
+ "default link QuickFixLine Search",
+ NULL
+};
+
+/* Default colors only used with a light background. */
+static char *(highlight_init_light[]) = {
+ CENT("Directory term=bold ctermfg=DarkBlue",
+ "Directory term=bold ctermfg=DarkBlue guifg=Blue"),
+ CENT("LineNr term=underline ctermfg=Brown",
+ "LineNr term=underline ctermfg=Brown guifg=Brown"),
+ CENT("CursorLineNr term=bold ctermfg=Brown",
+ "CursorLineNr term=bold ctermfg=Brown gui=bold guifg=Brown"),
+ CENT("MoreMsg term=bold ctermfg=DarkGreen",
+ "MoreMsg term=bold ctermfg=DarkGreen gui=bold guifg=SeaGreen"),
+ CENT("Question term=standout ctermfg=DarkGreen",
+ "Question term=standout ctermfg=DarkGreen gui=bold guifg=SeaGreen"),
+ CENT("Search term=reverse ctermbg=Yellow ctermfg=NONE",
+ "Search term=reverse ctermbg=Yellow ctermfg=NONE guibg=Yellow guifg=NONE"),
+#ifdef FEAT_SPELL
+ CENT("SpellBad term=reverse ctermbg=LightRed",
+ "SpellBad term=reverse ctermbg=LightRed guisp=Red gui=undercurl"),
+ CENT("SpellCap term=reverse ctermbg=LightBlue",
+ "SpellCap term=reverse ctermbg=LightBlue guisp=Blue gui=undercurl"),
+ CENT("SpellRare term=reverse ctermbg=LightMagenta",
+ "SpellRare term=reverse ctermbg=LightMagenta guisp=Magenta gui=undercurl"),
+ CENT("SpellLocal term=underline ctermbg=Cyan",
+ "SpellLocal term=underline ctermbg=Cyan guisp=DarkCyan gui=undercurl"),
+#endif
+#ifdef FEAT_INS_EXPAND
+ CENT("PmenuThumb ctermbg=Black",
+ "PmenuThumb ctermbg=Black guibg=Black"),
+ CENT("Pmenu ctermbg=LightMagenta ctermfg=Black",
+ "Pmenu ctermbg=LightMagenta ctermfg=Black guibg=LightMagenta"),
+ CENT("PmenuSel ctermbg=LightGrey ctermfg=Black",
+ "PmenuSel ctermbg=LightGrey ctermfg=Black guibg=Grey"),
+#endif
+ CENT("SpecialKey term=bold ctermfg=DarkBlue",
+ "SpecialKey term=bold ctermfg=DarkBlue guifg=Blue"),
+ CENT("Title term=bold ctermfg=DarkMagenta",
+ "Title term=bold ctermfg=DarkMagenta gui=bold guifg=Magenta"),
+ CENT("WarningMsg term=standout ctermfg=DarkRed",
+ "WarningMsg term=standout ctermfg=DarkRed guifg=Red"),
+#ifdef FEAT_WILDMENU
+ CENT("WildMenu term=standout ctermbg=Yellow ctermfg=Black",
+ "WildMenu term=standout ctermbg=Yellow ctermfg=Black guibg=Yellow guifg=Black"),
+#endif
+#ifdef FEAT_FOLDING
+ CENT("Folded term=standout ctermbg=Grey ctermfg=DarkBlue",
+ "Folded term=standout ctermbg=Grey ctermfg=DarkBlue guibg=LightGrey guifg=DarkBlue"),
+ CENT("FoldColumn term=standout ctermbg=Grey ctermfg=DarkBlue",
+ "FoldColumn term=standout ctermbg=Grey ctermfg=DarkBlue guibg=Grey guifg=DarkBlue"),
+#endif
+#ifdef FEAT_SIGNS
+ CENT("SignColumn term=standout ctermbg=Grey ctermfg=DarkBlue",
+ "SignColumn term=standout ctermbg=Grey ctermfg=DarkBlue guibg=Grey guifg=DarkBlue"),
+#endif
+ CENT("Visual term=reverse",
+ "Visual term=reverse guibg=LightGrey"),
+#ifdef FEAT_DIFF
+ CENT("DiffAdd term=bold ctermbg=LightBlue",
+ "DiffAdd term=bold ctermbg=LightBlue guibg=LightBlue"),
+ CENT("DiffChange term=bold ctermbg=LightMagenta",
+ "DiffChange term=bold ctermbg=LightMagenta guibg=LightMagenta"),
+ CENT("DiffDelete term=bold ctermfg=Blue ctermbg=LightCyan",
+ "DiffDelete term=bold ctermfg=Blue ctermbg=LightCyan gui=bold guifg=Blue guibg=LightCyan"),
+#endif
+ CENT("TabLine term=underline cterm=underline ctermfg=black ctermbg=LightGrey",
+ "TabLine term=underline cterm=underline ctermfg=black ctermbg=LightGrey gui=underline guibg=LightGrey"),
+#ifdef FEAT_SYN_HL
+ CENT("CursorColumn term=reverse ctermbg=LightGrey",
+ "CursorColumn term=reverse ctermbg=LightGrey guibg=Grey90"),
+ CENT("CursorLine term=underline cterm=underline",
+ "CursorLine term=underline cterm=underline guibg=Grey90"),
+ CENT("ColorColumn term=reverse ctermbg=LightRed",
+ "ColorColumn term=reverse ctermbg=LightRed guibg=LightRed"),
+#endif
+#ifdef FEAT_CONCEAL
+ CENT("Conceal ctermbg=DarkGrey ctermfg=LightGrey",
+ "Conceal ctermbg=DarkGrey ctermfg=LightGrey guibg=DarkGrey guifg=LightGrey"),
+#endif
+ CENT("MatchParen term=reverse ctermbg=Cyan",
+ "MatchParen term=reverse ctermbg=Cyan guibg=Cyan"),
+#ifdef FEAT_GUI
+ "Normal gui=NONE",
+#endif
+#ifdef FEAT_TERMINAL
+ CENT("StatusLineTerm term=reverse,bold cterm=bold ctermfg=White ctermbg=DarkGreen",
+ "StatusLineTerm term=reverse,bold cterm=bold ctermfg=White ctermbg=DarkGreen gui=bold guifg=bg guibg=DarkGreen"),
+ CENT("StatusLineTermNC term=reverse ctermfg=White ctermbg=DarkGreen",
+ "StatusLineTermNC term=reverse ctermfg=White ctermbg=DarkGreen guifg=bg guibg=DarkGreen"),
+#endif
+#ifdef FEAT_MENU
+ CENT("ToolbarLine term=underline ctermbg=LightGrey",
+ "ToolbarLine term=underline ctermbg=LightGrey guibg=LightGrey"),
+ CENT("ToolbarButton cterm=bold ctermfg=White ctermbg=DarkGrey",
+ "ToolbarButton cterm=bold ctermfg=White ctermbg=DarkGrey gui=bold guifg=White guibg=Grey40"),
+#endif
+ NULL
+};
+
+/* Default colors only used with a dark background. */
+static char *(highlight_init_dark[]) = {
+ CENT("Directory term=bold ctermfg=LightCyan",
+ "Directory term=bold ctermfg=LightCyan guifg=Cyan"),
+ CENT("LineNr term=underline ctermfg=Yellow",
+ "LineNr term=underline ctermfg=Yellow guifg=Yellow"),
+ CENT("CursorLineNr term=bold ctermfg=Yellow",
+ "CursorLineNr term=bold ctermfg=Yellow gui=bold guifg=Yellow"),
+ CENT("MoreMsg term=bold ctermfg=LightGreen",
+ "MoreMsg term=bold ctermfg=LightGreen gui=bold guifg=SeaGreen"),
+ CENT("Question term=standout ctermfg=LightGreen",
+ "Question term=standout ctermfg=LightGreen gui=bold guifg=Green"),
+ CENT("Search term=reverse ctermbg=Yellow ctermfg=Black",
+ "Search term=reverse ctermbg=Yellow ctermfg=Black guibg=Yellow guifg=Black"),
+ CENT("SpecialKey term=bold ctermfg=LightBlue",
+ "SpecialKey term=bold ctermfg=LightBlue guifg=Cyan"),
+#ifdef FEAT_SPELL
+ CENT("SpellBad term=reverse ctermbg=Red",
+ "SpellBad term=reverse ctermbg=Red guisp=Red gui=undercurl"),
+ CENT("SpellCap term=reverse ctermbg=Blue",
+ "SpellCap term=reverse ctermbg=Blue guisp=Blue gui=undercurl"),
+ CENT("SpellRare term=reverse ctermbg=Magenta",
+ "SpellRare term=reverse ctermbg=Magenta guisp=Magenta gui=undercurl"),
+ CENT("SpellLocal term=underline ctermbg=Cyan",
+ "SpellLocal term=underline ctermbg=Cyan guisp=Cyan gui=undercurl"),
+#endif
+#ifdef FEAT_INS_EXPAND
+ CENT("PmenuThumb ctermbg=White",
+ "PmenuThumb ctermbg=White guibg=White"),
+ CENT("Pmenu ctermbg=Magenta ctermfg=Black",
+ "Pmenu ctermbg=Magenta ctermfg=Black guibg=Magenta"),
+ CENT("PmenuSel ctermbg=Black ctermfg=DarkGrey",
+ "PmenuSel ctermbg=Black ctermfg=DarkGrey guibg=DarkGrey"),
+#endif
+ CENT("Title term=bold ctermfg=LightMagenta",
+ "Title term=bold ctermfg=LightMagenta gui=bold guifg=Magenta"),
+ CENT("WarningMsg term=standout ctermfg=LightRed",
+ "WarningMsg term=standout ctermfg=LightRed guifg=Red"),
+#ifdef FEAT_WILDMENU
+ CENT("WildMenu term=standout ctermbg=Yellow ctermfg=Black",
+ "WildMenu term=standout ctermbg=Yellow ctermfg=Black guibg=Yellow guifg=Black"),
+#endif
+#ifdef FEAT_FOLDING
+ CENT("Folded term=standout ctermbg=DarkGrey ctermfg=Cyan",
+ "Folded term=standout ctermbg=DarkGrey ctermfg=Cyan guibg=DarkGrey guifg=Cyan"),
+ CENT("FoldColumn term=standout ctermbg=DarkGrey ctermfg=Cyan",
+ "FoldColumn term=standout ctermbg=DarkGrey ctermfg=Cyan guibg=Grey guifg=Cyan"),
+#endif
+#ifdef FEAT_SIGNS
+ CENT("SignColumn term=standout ctermbg=DarkGrey ctermfg=Cyan",
+ "SignColumn term=standout ctermbg=DarkGrey ctermfg=Cyan guibg=Grey guifg=Cyan"),
+#endif
+ CENT("Visual term=reverse",
+ "Visual term=reverse guibg=DarkGrey"),
+#ifdef FEAT_DIFF
+ CENT("DiffAdd term=bold ctermbg=DarkBlue",
+ "DiffAdd term=bold ctermbg=DarkBlue guibg=DarkBlue"),
+ CENT("DiffChange term=bold ctermbg=DarkMagenta",
+ "DiffChange term=bold ctermbg=DarkMagenta guibg=DarkMagenta"),
+ CENT("DiffDelete term=bold ctermfg=Blue ctermbg=DarkCyan",
+ "DiffDelete term=bold ctermfg=Blue ctermbg=DarkCyan gui=bold guifg=Blue guibg=DarkCyan"),
+#endif
+ CENT("TabLine term=underline cterm=underline ctermfg=white ctermbg=DarkGrey",
+ "TabLine term=underline cterm=underline ctermfg=white ctermbg=DarkGrey gui=underline guibg=DarkGrey"),
+#ifdef FEAT_SYN_HL
+ CENT("CursorColumn term=reverse ctermbg=DarkGrey",
+ "CursorColumn term=reverse ctermbg=DarkGrey guibg=Grey40"),
+ CENT("CursorLine term=underline cterm=underline",
+ "CursorLine term=underline cterm=underline guibg=Grey40"),
+ CENT("ColorColumn term=reverse ctermbg=DarkRed",
+ "ColorColumn term=reverse ctermbg=DarkRed guibg=DarkRed"),
+#endif
+ CENT("MatchParen term=reverse ctermbg=DarkCyan",
+ "MatchParen term=reverse ctermbg=DarkCyan guibg=DarkCyan"),
+#ifdef FEAT_CONCEAL
+ CENT("Conceal ctermbg=DarkGrey ctermfg=LightGrey",
+ "Conceal ctermbg=DarkGrey ctermfg=LightGrey guibg=DarkGrey guifg=LightGrey"),
+#endif
+#ifdef FEAT_GUI
+ "Normal gui=NONE",
+#endif
+#ifdef FEAT_TERMINAL
+ CENT("StatusLineTerm term=reverse,bold cterm=bold ctermfg=Black ctermbg=LightGreen",
+ "StatusLineTerm term=reverse,bold cterm=bold ctermfg=Black ctermbg=LightGreen gui=bold guifg=bg guibg=LightGreen"),
+ CENT("StatusLineTermNC term=reverse ctermfg=Black ctermbg=LightGreen",
+ "StatusLineTermNC term=reverse ctermfg=Black ctermbg=LightGreen guifg=bg guibg=LightGreen"),
+#endif
+#ifdef FEAT_MENU
+ CENT("ToolbarLine term=underline ctermbg=DarkGrey",
+ "ToolbarLine term=underline ctermbg=DarkGrey guibg=Grey50"),
+ CENT("ToolbarButton cterm=bold ctermfg=Black ctermbg=LightGrey",
+ "ToolbarButton cterm=bold ctermfg=Black ctermbg=LightGrey gui=bold guifg=Black guibg=LightGrey"),
+#endif
+ NULL
+};
+
+ void
+init_highlight(
+ int both, /* include groups where 'bg' doesn't matter */
+ int reset) /* clear group first */
+{
+ int i;
+ char **pp;
+ static int had_both = FALSE;
+#ifdef FEAT_EVAL
+ char_u *p;
+
+ /*
+ * Try finding the color scheme file. Used when a color file was loaded
+ * and 'background' or 't_Co' is changed.
+ */
+ p = get_var_value((char_u *)"g:colors_name");
+ if (p != NULL)
+ {
+ /* The value of g:colors_name could be freed when sourcing the script,
+ * making "p" invalid, so copy it. */
+ char_u *copy_p = vim_strsave(p);
+ int r;
+
+ if (copy_p != NULL)
+ {
+ r = load_colors(copy_p);
+ vim_free(copy_p);
+ if (r == OK)
+ return;
+ }
+ }
+
+#endif
+
+ /*
+ * Didn't use a color file, use the compiled-in colors.
+ */
+ if (both)
+ {
+ had_both = TRUE;
+ pp = highlight_init_both;
+ for (i = 0; pp[i] != NULL; ++i)
+ do_highlight((char_u *)pp[i], reset, TRUE);
+ }
+ else if (!had_both)
+ /* Don't do anything before the call with both == TRUE from main().
+ * Not everything has been setup then, and that call will overrule
+ * everything anyway. */
+ return;
+
+ if (*p_bg == 'l')
+ pp = highlight_init_light;
+ else
+ pp = highlight_init_dark;
+ for (i = 0; pp[i] != NULL; ++i)
+ do_highlight((char_u *)pp[i], reset, TRUE);
+
+ /* Reverse looks ugly, but grey may not work for 8 colors. Thus let it
+ * depend on the number of colors available.
+ * With 8 colors brown is equal to yellow, need to use black for Search fg
+ * to avoid Statement highlighted text disappears.
+ * Clear the attributes, needed when changing the t_Co value. */
+ if (t_colors > 8)
+ do_highlight((char_u *)(*p_bg == 'l'
+ ? "Visual cterm=NONE ctermbg=LightGrey"
+ : "Visual cterm=NONE ctermbg=DarkGrey"), FALSE, TRUE);
+ else
+ {
+ do_highlight((char_u *)"Visual cterm=reverse ctermbg=NONE",
+ FALSE, TRUE);
+ if (*p_bg == 'l')
+ do_highlight((char_u *)"Search ctermfg=black", FALSE, TRUE);
+ }
+
+#ifdef FEAT_SYN_HL
+ /*
+ * If syntax highlighting is enabled load the highlighting for it.
+ */
+ if (get_var_value((char_u *)"g:syntax_on") != NULL)
+ {
+ static int recursive = 0;
+
+ if (recursive >= 5)
+ emsg(_("E679: recursive loop loading syncolor.vim"));
+ else
+ {
+ ++recursive;
+ (void)source_runtime((char_u *)"syntax/syncolor.vim", DIP_ALL);
+ --recursive;
+ }
+ }
+#endif
+}
+
+/*
+ * Load color file "name".
+ * Return OK for success, FAIL for failure.
+ */
+ int
+load_colors(char_u *name)
+{
+ char_u *buf;
+ int retval = FAIL;
+ static int recursive = FALSE;
+
+ /* When being called recursively, this is probably because setting
+ * 'background' caused the highlighting to be reloaded. This means it is
+ * working, thus we should return OK. */
+ if (recursive)
+ return OK;
+
+ recursive = TRUE;
+ buf = alloc((unsigned)(STRLEN(name) + 12));
+ if (buf != NULL)
+ {
+ apply_autocmds(EVENT_COLORSCHEMEPRE, name,
+ curbuf->b_fname, FALSE, curbuf);
+ sprintf((char *)buf, "colors/%s.vim", name);
+ retval = source_runtime(buf, DIP_START + DIP_OPT);
+ vim_free(buf);
+ apply_autocmds(EVENT_COLORSCHEME, name, curbuf->b_fname, FALSE, curbuf);
+ }
+ recursive = FALSE;
+
+ return retval;
+}
+
+static char *(color_names[28]) = {
+ "Black", "DarkBlue", "DarkGreen", "DarkCyan",
+ "DarkRed", "DarkMagenta", "Brown", "DarkYellow",
+ "Gray", "Grey", "LightGray", "LightGrey",
+ "DarkGray", "DarkGrey",
+ "Blue", "LightBlue", "Green", "LightGreen",
+ "Cyan", "LightCyan", "Red", "LightRed", "Magenta",
+ "LightMagenta", "Yellow", "LightYellow", "White", "NONE"};
+ /* indices:
+ * 0, 1, 2, 3,
+ * 4, 5, 6, 7,
+ * 8, 9, 10, 11,
+ * 12, 13,
+ * 14, 15, 16, 17,
+ * 18, 19, 20, 21, 22,
+ * 23, 24, 25, 26, 27 */
+static int color_numbers_16[28] = {0, 1, 2, 3,
+ 4, 5, 6, 6,
+ 7, 7, 7, 7,
+ 8, 8,
+ 9, 9, 10, 10,
+ 11, 11, 12, 12, 13,
+ 13, 14, 14, 15, -1};
+/* for xterm with 88 colors... */
+static int color_numbers_88[28] = {0, 4, 2, 6,
+ 1, 5, 32, 72,
+ 84, 84, 7, 7,
+ 82, 82,
+ 12, 43, 10, 61,
+ 14, 63, 9, 74, 13,
+ 75, 11, 78, 15, -1};
+/* for xterm with 256 colors... */
+static int color_numbers_256[28] = {0, 4, 2, 6,
+ 1, 5, 130, 130,
+ 248, 248, 7, 7,
+ 242, 242,
+ 12, 81, 10, 121,
+ 14, 159, 9, 224, 13,
+ 225, 11, 229, 15, -1};
+/* for terminals with less than 16 colors... */
+static int color_numbers_8[28] = {0, 4, 2, 6,
+ 1, 5, 3, 3,
+ 7, 7, 7, 7,
+ 0+8, 0+8,
+ 4+8, 4+8, 2+8, 2+8,
+ 6+8, 6+8, 1+8, 1+8, 5+8,
+ 5+8, 3+8, 3+8, 7+8, -1};
+
+/*
+ * Lookup the "cterm" value to be used for color with index "idx" in
+ * color_names[].
+ * "boldp" will be set to TRUE or FALSE for a foreground color when using 8
+ * colors, otherwise it will be unchanged.
+ */
+ int
+lookup_color(int idx, int foreground, int *boldp)
+{
+ int color = color_numbers_16[idx];
+ char_u *p;
+
+ /* Use the _16 table to check if it's a valid color name. */
+ if (color < 0)
+ return -1;
+
+ if (t_colors == 8)
+ {
+ /* t_Co is 8: use the 8 colors table */
+#if defined(__QNXNTO__)
+ color = color_numbers_8_qansi[idx];
+#else
+ color = color_numbers_8[idx];
+#endif
+ if (foreground)
+ {
+ /* set/reset bold attribute to get light foreground
+ * colors (on some terminals, e.g. "linux") */
+ if (color & 8)
+ *boldp = TRUE;
+ else
+ *boldp = FALSE;
+ }
+ color &= 7; /* truncate to 8 colors */
+ }
+ else if (t_colors == 16 || t_colors == 88
+ || t_colors >= 256)
+ {
+ /*
+ * Guess: if the termcap entry ends in 'm', it is
+ * probably an xterm-like terminal. Use the changed
+ * order for colors.
+ */
+ if (*T_CAF != NUL)
+ p = T_CAF;
+ else
+ p = T_CSF;
+ if (*p != NUL && (t_colors > 256
+ || *(p + STRLEN(p) - 1) == 'm'))
+ {
+ if (t_colors == 88)
+ color = color_numbers_88[idx];
+ else if (t_colors >= 256)
+ color = color_numbers_256[idx];
+ else
+ color = color_numbers_8[idx];
+ }
+#ifdef FEAT_TERMRESPONSE
+ if (t_colors >= 256 && color == 15 && is_mac_terminal)
+ /* Terminal.app has a bug: 15 is light grey. Use white
+ * from the color cube instead. */
+ color = 231;
+#endif
+ }
+ return color;
+}
+
+/*
+ * Handle the ":highlight .." command.
+ * When using ":hi clear" this is called recursively for each group with
+ * "forceit" and "init" both TRUE.
+ */
+ void
+do_highlight(
+ char_u *line,
+ int forceit,
+ int init) /* TRUE when called for initializing */
+{
+ char_u *name_end;
+ char_u *p;
+ char_u *linep;
+ char_u *key_start;
+ char_u *arg_start;
+ char_u *key = NULL, *arg = NULL;
+ long i;
+ int off;
+ int len;
+ int attr;
+ int id;
+ int idx;
+ struct hl_group item_before;
+ int did_change = FALSE;
+ int dodefault = FALSE;
+ int doclear = FALSE;
+ int dolink = FALSE;
+ int error = FALSE;
+ int color;
+ int is_normal_group = FALSE; /* "Normal" group */
+#ifdef FEAT_TERMINAL
+ int is_terminal_group = FALSE; /* "Terminal" group */
+#endif
+#ifdef FEAT_GUI_X11
+ int is_menu_group = FALSE; /* "Menu" group */
+ int is_scrollbar_group = FALSE; /* "Scrollbar" group */
+ int is_tooltip_group = FALSE; /* "Tooltip" group */
+ int do_colors = FALSE; /* need to update colors? */
+#else
+# define is_menu_group 0
+# define is_tooltip_group 0
+#endif
+#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
+ int did_highlight_changed = FALSE;
+#endif
+
+ /*
+ * If no argument, list current highlighting.
+ */
+ if (ends_excmd(*line))
+ {
+ for (i = 1; i <= highlight_ga.ga_len && !got_int; ++i)
+ /* TODO: only call when the group has attributes set */
+ highlight_list_one((int)i);
+ return;
+ }
+
+ /*
+ * Isolate the name.
+ */
+ name_end = skiptowhite(line);
+ linep = skipwhite(name_end);
+
+ /*
+ * Check for "default" argument.
+ */
+ if (STRNCMP(line, "default", name_end - line) == 0)
+ {
+ dodefault = TRUE;
+ line = linep;
+ name_end = skiptowhite(line);
+ linep = skipwhite(name_end);
+ }
+
+ /*
+ * Check for "clear" or "link" argument.
+ */
+ if (STRNCMP(line, "clear", name_end - line) == 0)
+ doclear = TRUE;
+ if (STRNCMP(line, "link", name_end - line) == 0)
+ dolink = TRUE;
+
+ /*
+ * ":highlight {group-name}": list highlighting for one group.
+ */
+ if (!doclear && !dolink && ends_excmd(*linep))
+ {
+ id = syn_namen2id(line, (int)(name_end - line));
+ if (id == 0)
+ semsg(_("E411: highlight group not found: %s"), line);
+ else
+ highlight_list_one(id);
+ return;
+ }
+
+ /*
+ * Handle ":highlight link {from} {to}" command.
+ */
+ if (dolink)
+ {
+ char_u *from_start = linep;
+ char_u *from_end;
+ char_u *to_start;
+ char_u *to_end;
+ int from_id;
+ int to_id;
+
+ from_end = skiptowhite(from_start);
+ to_start = skipwhite(from_end);
+ to_end = skiptowhite(to_start);
+
+ if (ends_excmd(*from_start) || ends_excmd(*to_start))
+ {
+ semsg(_("E412: Not enough arguments: \":highlight link %s\""),
+ from_start);
+ return;
+ }
+
+ if (!ends_excmd(*skipwhite(to_end)))
+ {
+ semsg(_("E413: Too many arguments: \":highlight link %s\""), from_start);
+ return;
+ }
+
+ from_id = syn_check_group(from_start, (int)(from_end - from_start));
+ if (STRNCMP(to_start, "NONE", 4) == 0)
+ to_id = 0;
+ else
+ to_id = syn_check_group(to_start, (int)(to_end - to_start));
+
+ if (from_id > 0 && (!init || HL_TABLE()[from_id - 1].sg_set == 0))
+ {
+ /*
+ * Don't allow a link when there already is some highlighting
+ * for the group, unless '!' is used
+ */
+ if (to_id > 0 && !forceit && !init
+ && hl_has_settings(from_id - 1, dodefault))
+ {
+ if (sourcing_name == NULL && !dodefault)
+ emsg(_("E414: group has settings, highlight link ignored"));
+ }
+ else if (HL_TABLE()[from_id - 1].sg_link != to_id
+#ifdef FEAT_EVAL
+ || HL_TABLE()[from_id - 1].sg_script_ctx.sc_sid
+ != current_sctx.sc_sid
+#endif
+ || HL_TABLE()[from_id - 1].sg_cleared)
+ {
+ if (!init)
+ HL_TABLE()[from_id - 1].sg_set |= SG_LINK;
+ HL_TABLE()[from_id - 1].sg_link = to_id;
+#ifdef FEAT_EVAL
+ HL_TABLE()[from_id - 1].sg_script_ctx = current_sctx;
+ HL_TABLE()[from_id - 1].sg_script_ctx.sc_lnum += sourcing_lnum;
+#endif
+ HL_TABLE()[from_id - 1].sg_cleared = FALSE;
+ redraw_all_later(SOME_VALID);
+
+ /* Only call highlight_changed() once after multiple changes. */
+ need_highlight_changed = TRUE;
+ }
+ }
+
+ return;
+ }
+
+ if (doclear)
+ {
+ /*
+ * ":highlight clear [group]" command.
+ */
+ line = linep;
+ if (ends_excmd(*line))
+ {
+#ifdef FEAT_GUI
+ /* First, we do not destroy the old values, but allocate the new
+ * ones and update the display. THEN we destroy the old values.
+ * If we destroy the old values first, then the old values
+ * (such as GuiFont's or GuiFontset's) will still be displayed but
+ * invalid because they were free'd.
+ */
+ if (gui.in_use)
+ {
+# ifdef FEAT_BEVAL_TIP
+ gui_init_tooltip_font();
+# endif
+# if defined(FEAT_MENU) && (defined(FEAT_GUI_ATHENA) || defined(FEAT_GUI_MOTIF))
+ gui_init_menu_font();
+# endif
+ }
+# if defined(FEAT_GUI_MSWIN) || defined(FEAT_GUI_X11)
+ gui_mch_def_colors();
+# endif
+# ifdef FEAT_GUI_X11
+# ifdef FEAT_MENU
+
+ /* This only needs to be done when there is no Menu highlight
+ * group defined by default, which IS currently the case.
+ */
+ gui_mch_new_menu_colors();
+# endif
+ if (gui.in_use)
+ {
+ gui_new_scrollbar_colors();
+# ifdef FEAT_BEVAL_GUI
+ gui_mch_new_tooltip_colors();
+# endif
+# ifdef FEAT_MENU
+ gui_mch_new_menu_font();
+# endif
+ }
+# endif
+
+ /* Ok, we're done allocating the new default graphics items.
+ * The screen should already be refreshed at this point.
+ * It is now Ok to clear out the old data.
+ */
+#endif
+#ifdef FEAT_EVAL
+ do_unlet((char_u *)"colors_name", TRUE);
+#endif
+ restore_cterm_colors();
+
+ /*
+ * Clear all default highlight groups and load the defaults.
+ */
+ for (idx = 0; idx < highlight_ga.ga_len; ++idx)
+ highlight_clear(idx);
+ init_highlight(TRUE, TRUE);
+#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
+ if (USE_24BIT)
+ highlight_gui_started();
+ else
+#endif
+ highlight_changed();
+ redraw_later_clear();
+ return;
+ }
+ name_end = skiptowhite(line);
+ linep = skipwhite(name_end);
+ }
+
+ /*
+ * Find the group name in the table. If it does not exist yet, add it.
+ */
+ id = syn_check_group(line, (int)(name_end - line));
+ if (id == 0) /* failed (out of memory) */
+ return;
+ idx = id - 1; /* index is ID minus one */
+
+ /* Return if "default" was used and the group already has settings. */
+ if (dodefault && hl_has_settings(idx, TRUE))
+ return;
+
+ /* Make a copy so we can check if any attribute actually changed. */
+ item_before = HL_TABLE()[idx];
+
+ if (STRCMP(HL_TABLE()[idx].sg_name_u, "NORMAL") == 0)
+ is_normal_group = TRUE;
+#ifdef FEAT_TERMINAL
+ else if (STRCMP(HL_TABLE()[idx].sg_name_u, "TERMINAL") == 0)
+ is_terminal_group = TRUE;
+#endif
+#ifdef FEAT_GUI_X11
+ else if (STRCMP(HL_TABLE()[idx].sg_name_u, "MENU") == 0)
+ is_menu_group = TRUE;
+ else if (STRCMP(HL_TABLE()[idx].sg_name_u, "SCROLLBAR") == 0)
+ is_scrollbar_group = TRUE;
+ else if (STRCMP(HL_TABLE()[idx].sg_name_u, "TOOLTIP") == 0)
+ is_tooltip_group = TRUE;
+#endif
+
+ /* Clear the highlighting for ":hi clear {group}" and ":hi clear". */
+ if (doclear || (forceit && init))
+ {
+ highlight_clear(idx);
+ if (!doclear)
+ HL_TABLE()[idx].sg_set = 0;
+ }
+
+ if (!doclear)
+ while (!ends_excmd(*linep))
+ {
+ key_start = linep;
+ if (*linep == '=')
+ {
+ semsg(_("E415: unexpected equal sign: %s"), key_start);
+ error = TRUE;
+ break;
+ }
+
+ /*
+ * Isolate the key ("term", "ctermfg", "ctermbg", "font", "guifg" or
+ * "guibg").
+ */
+ while (*linep && !VIM_ISWHITE(*linep) && *linep != '=')
+ ++linep;
+ vim_free(key);
+ key = vim_strnsave_up(key_start, (int)(linep - key_start));
+ if (key == NULL)
+ {
+ error = TRUE;
+ break;
+ }
+ linep = skipwhite(linep);
+
+ if (STRCMP(key, "NONE") == 0)
+ {
+ if (!init || HL_TABLE()[idx].sg_set == 0)
+ {
+ if (!init)
+ HL_TABLE()[idx].sg_set |= SG_TERM+SG_CTERM+SG_GUI;
+ highlight_clear(idx);
+ }
+ continue;
+ }
+
+ /*
+ * Check for the equal sign.
+ */
+ if (*linep != '=')
+ {
+ semsg(_("E416: missing equal sign: %s"), key_start);
+ error = TRUE;
+ break;
+ }
+ ++linep;
+
+ /*
+ * Isolate the argument.
+ */
+ linep = skipwhite(linep);
+ if (*linep == '\'') /* guifg='color name' */
+ {
+ arg_start = ++linep;
+ linep = vim_strchr(linep, '\'');
+ if (linep == NULL)
+ {
+ semsg(_(e_invarg2), key_start);
+ error = TRUE;
+ break;
+ }
+ }
+ else
+ {
+ arg_start = linep;
+ linep = skiptowhite(linep);
+ }
+ if (linep == arg_start)
+ {
+ semsg(_("E417: missing argument: %s"), key_start);
+ error = TRUE;
+ break;
+ }
+ vim_free(arg);
+ arg = vim_strnsave(arg_start, (int)(linep - arg_start));
+ if (arg == NULL)
+ {
+ error = TRUE;
+ break;
+ }
+ if (*linep == '\'')
+ ++linep;
+
+ /*
+ * Store the argument.
+ */
+ if ( STRCMP(key, "TERM") == 0
+ || STRCMP(key, "CTERM") == 0
+ || STRCMP(key, "GUI") == 0)
+ {
+ attr = 0;
+ off = 0;
+ while (arg[off] != NUL)
+ {
+ for (i = sizeof(hl_attr_table) / sizeof(int); --i >= 0; )
+ {
+ len = (int)STRLEN(hl_name_table[i]);
+ if (STRNICMP(arg + off, hl_name_table[i], len) == 0)
+ {
+ attr |= hl_attr_table[i];
+ off += len;
+ break;
+ }
+ }
+ if (i < 0)
+ {
+ semsg(_("E418: Illegal value: %s"), arg);
+ error = TRUE;
+ break;
+ }
+ if (arg[off] == ',') /* another one follows */
+ ++off;
+ }
+ if (error)
+ break;
+ if (*key == 'T')
+ {
+ if (!init || !(HL_TABLE()[idx].sg_set & SG_TERM))
+ {
+ if (!init)
+ HL_TABLE()[idx].sg_set |= SG_TERM;
+ HL_TABLE()[idx].sg_term = attr;
+ }
+ }
+ else if (*key == 'C')
+ {
+ if (!init || !(HL_TABLE()[idx].sg_set & SG_CTERM))
+ {
+ if (!init)
+ HL_TABLE()[idx].sg_set |= SG_CTERM;
+ HL_TABLE()[idx].sg_cterm = attr;
+ HL_TABLE()[idx].sg_cterm_bold = FALSE;
+ }
+ }
+#if defined(FEAT_GUI) || defined(FEAT_EVAL)
+ else
+ {
+ if (!init || !(HL_TABLE()[idx].sg_set & SG_GUI))
+ {
+ if (!init)
+ HL_TABLE()[idx].sg_set |= SG_GUI;
+ HL_TABLE()[idx].sg_gui = attr;
+ }
+ }
+#endif
+ }
+ else if (STRCMP(key, "FONT") == 0)
+ {
+ /* in non-GUI fonts are simply ignored */
+#ifdef FEAT_GUI
+ if (HL_TABLE()[idx].sg_font_name != NULL
+ && STRCMP(HL_TABLE()[idx].sg_font_name, arg) == 0)
+ {
+ /* Font name didn't change, ignore. */
+ }
+ else if (!gui.shell_created)
+ {
+ /* GUI not started yet, always accept the name. */
+ vim_free(HL_TABLE()[idx].sg_font_name);
+ HL_TABLE()[idx].sg_font_name = vim_strsave(arg);
+ did_change = TRUE;
+ }
+ else
+ {
+ GuiFont temp_sg_font = HL_TABLE()[idx].sg_font;
+# ifdef FEAT_XFONTSET
+ GuiFontset temp_sg_fontset = HL_TABLE()[idx].sg_fontset;
+# endif
+ /* First, save the current font/fontset.
+ * Then try to allocate the font/fontset.
+ * If the allocation fails, HL_TABLE()[idx].sg_font OR
+ * sg_fontset will be set to NOFONT or NOFONTSET respectively.
+ */
+
+ HL_TABLE()[idx].sg_font = NOFONT;
+# ifdef FEAT_XFONTSET
+ HL_TABLE()[idx].sg_fontset = NOFONTSET;
+# endif
+ hl_do_font(idx, arg, is_normal_group, is_menu_group,
+ is_tooltip_group, FALSE);
+
+# ifdef FEAT_XFONTSET
+ if (HL_TABLE()[idx].sg_fontset != NOFONTSET)
+ {
+ /* New fontset was accepted. Free the old one, if there
+ * was one. */
+ gui_mch_free_fontset(temp_sg_fontset);
+ vim_free(HL_TABLE()[idx].sg_font_name);
+ HL_TABLE()[idx].sg_font_name = vim_strsave(arg);
+ did_change = TRUE;
+ }
+ else
+ HL_TABLE()[idx].sg_fontset = temp_sg_fontset;
+# endif
+ if (HL_TABLE()[idx].sg_font != NOFONT)
+ {
+ /* New font was accepted. Free the old one, if there was
+ * one. */
+ gui_mch_free_font(temp_sg_font);
+ vim_free(HL_TABLE()[idx].sg_font_name);
+ HL_TABLE()[idx].sg_font_name = vim_strsave(arg);
+ did_change = TRUE;
+ }
+ else
+ HL_TABLE()[idx].sg_font = temp_sg_font;
+ }
+#endif
+ }
+ else if (STRCMP(key, "CTERMFG") == 0 || STRCMP(key, "CTERMBG") == 0)
+ {
+ if (!init || !(HL_TABLE()[idx].sg_set & SG_CTERM))
+ {
+ if (!init)
+ HL_TABLE()[idx].sg_set |= SG_CTERM;
+
+ /* When setting the foreground color, and previously the "bold"
+ * flag was set for a light color, reset it now */
+ if (key[5] == 'F' && HL_TABLE()[idx].sg_cterm_bold)
+ {
+ HL_TABLE()[idx].sg_cterm &= ~HL_BOLD;
+ HL_TABLE()[idx].sg_cterm_bold = FALSE;
+ }
+
+ if (VIM_ISDIGIT(*arg))
+ color = atoi((char *)arg);
+ else if (STRICMP(arg, "fg") == 0)
+ {
+ if (cterm_normal_fg_color)
+ color = cterm_normal_fg_color - 1;
+ else
+ {
+ emsg(_("E419: FG color unknown"));
+ error = TRUE;
+ break;
+ }
+ }
+ else if (STRICMP(arg, "bg") == 0)
+ {
+ if (cterm_normal_bg_color > 0)
+ color = cterm_normal_bg_color - 1;
+ else
+ {
+ emsg(_("E420: BG color unknown"));
+ error = TRUE;
+ break;
+ }
+ }
+ else
+ {
+ int bold = MAYBE;
+
+#if defined(__QNXNTO__)
+ static int *color_numbers_8_qansi = color_numbers_8;
+ /* On qnx, the 8 & 16 color arrays are the same */
+ if (STRNCMP(T_NAME, "qansi", 5) == 0)
+ color_numbers_8_qansi = color_numbers_16;
+#endif
+
+ /* reduce calls to STRICMP a bit, it can be slow */
+ off = TOUPPER_ASC(*arg);
+ for (i = (sizeof(color_names) / sizeof(char *)); --i >= 0; )
+ if (off == color_names[i][0]
+ && STRICMP(arg + 1, color_names[i] + 1) == 0)
+ break;
+ if (i < 0)
+ {
+ semsg(_("E421: Color name or number not recognized: %s"), key_start);
+ error = TRUE;
+ break;
+ }
+
+ color = lookup_color(i, key[5] == 'F', &bold);
+
+ /* set/reset bold attribute to get light foreground
+ * colors (on some terminals, e.g. "linux") */
+ if (bold == TRUE)
+ {
+ HL_TABLE()[idx].sg_cterm |= HL_BOLD;
+ HL_TABLE()[idx].sg_cterm_bold = TRUE;
+ }
+ else if (bold == FALSE)
+ HL_TABLE()[idx].sg_cterm &= ~HL_BOLD;
+ }
+
+ /* Add one to the argument, to avoid zero. Zero is used for
+ * "NONE", then "color" is -1. */
+ if (key[5] == 'F')
+ {
+ HL_TABLE()[idx].sg_cterm_fg = color + 1;
+ if (is_normal_group)
+ {
+ cterm_normal_fg_color = color + 1;
+ cterm_normal_fg_bold = (HL_TABLE()[idx].sg_cterm & HL_BOLD);
+#ifdef FEAT_GUI
+ /* Don't do this if the GUI is used. */
+ if (!gui.in_use && !gui.starting)
+#endif
+ {
+ must_redraw = CLEAR;
+ if (termcap_active && color >= 0)
+ term_fg_color(color);
+ }
+ }
+ }
+ else
+ {
+ HL_TABLE()[idx].sg_cterm_bg = color + 1;
+ if (is_normal_group)
+ {
+ cterm_normal_bg_color = color + 1;
+#ifdef FEAT_GUI
+ /* Don't mess with 'background' if the GUI is used. */
+ if (!gui.in_use && !gui.starting)
+#endif
+ {
+ must_redraw = CLEAR;
+ if (color >= 0)
+ {
+ int dark = -1;
+
+ if (termcap_active)
+ term_bg_color(color);
+ if (t_colors < 16)
+ dark = (color == 0 || color == 4);
+ /* Limit the heuristic to the standard 16 colors */
+ else if (color < 16)
+ dark = (color < 7 || color == 8);
+ /* Set the 'background' option if the value is
+ * wrong. */
+ if (dark != -1
+ && dark != (*p_bg == 'd')
+ && !option_was_set((char_u *)"bg"))
+ {
+ set_option_value((char_u *)"bg", 0L,
+ (char_u *)(dark ? "dark" : "light"), 0);
+ reset_option_was_set((char_u *)"bg");
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (STRCMP(key, "GUIFG") == 0)
+ {
+#if defined(FEAT_GUI) || defined(FEAT_EVAL)
+ char_u **namep = &HL_TABLE()[idx].sg_gui_fg_name;
+
+ if (!init || !(HL_TABLE()[idx].sg_set & SG_GUI))
+ {
+ if (!init)
+ HL_TABLE()[idx].sg_set |= SG_GUI;
+
+# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
+ /* In GUI guifg colors are only used when recognized */
+ i = color_name2handle(arg);
+ if (i != INVALCOLOR || STRCMP(arg, "NONE") == 0 || !USE_24BIT)
+ {
+ HL_TABLE()[idx].sg_gui_fg = i;
+# endif
+ if (*namep == NULL || STRCMP(*namep, arg) != 0)
+ {
+ vim_free(*namep);
+ if (STRCMP(arg, "NONE") != 0)
+ *namep = vim_strsave(arg);
+ else
+ *namep = NULL;
+ did_change = TRUE;
+ }
+# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
+# ifdef FEAT_GUI_X11
+ if (is_menu_group && gui.menu_fg_pixel != i)
+ {
+ gui.menu_fg_pixel = i;
+ do_colors = TRUE;
+ }
+ if (is_scrollbar_group && gui.scroll_fg_pixel != i)
+ {
+ gui.scroll_fg_pixel = i;
+ do_colors = TRUE;
+ }
+# ifdef FEAT_BEVAL_GUI
+ if (is_tooltip_group && gui.tooltip_fg_pixel != i)
+ {
+ gui.tooltip_fg_pixel = i;
+ do_colors = TRUE;
+ }
+# endif
+# endif
+ }
+# endif
+ }
+#endif
+ }
+ else if (STRCMP(key, "GUIBG") == 0)
+ {
+#if defined(FEAT_GUI) || defined(FEAT_EVAL)
+ char_u **namep = &HL_TABLE()[idx].sg_gui_bg_name;
+
+ if (!init || !(HL_TABLE()[idx].sg_set & SG_GUI))
+ {
+ if (!init)
+ HL_TABLE()[idx].sg_set |= SG_GUI;
+
+# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
+ /* In GUI guifg colors are only used when recognized */
+ i = color_name2handle(arg);
+ if (i != INVALCOLOR || STRCMP(arg, "NONE") == 0 || !USE_24BIT)
+ {
+ HL_TABLE()[idx].sg_gui_bg = i;
+# endif
+ if (*namep == NULL || STRCMP(*namep, arg) != 0)
+ {
+ vim_free(*namep);
+ if (STRCMP(arg, "NONE") != 0)
+ *namep = vim_strsave(arg);
+ else
+ *namep = NULL;
+ did_change = TRUE;
+ }
+# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
+# ifdef FEAT_GUI_X11
+ if (is_menu_group && gui.menu_bg_pixel != i)
+ {
+ gui.menu_bg_pixel = i;
+ do_colors = TRUE;
+ }
+ if (is_scrollbar_group && gui.scroll_bg_pixel != i)
+ {
+ gui.scroll_bg_pixel = i;
+ do_colors = TRUE;
+ }
+# ifdef FEAT_BEVAL_GUI
+ if (is_tooltip_group && gui.tooltip_bg_pixel != i)
+ {
+ gui.tooltip_bg_pixel = i;
+ do_colors = TRUE;
+ }
+# endif
+# endif
+ }
+# endif
+ }
+#endif
+ }
+ else if (STRCMP(key, "GUISP") == 0)
+ {
+#if defined(FEAT_GUI) || defined(FEAT_EVAL)
+ char_u **namep = &HL_TABLE()[idx].sg_gui_sp_name;
+
+ if (!init || !(HL_TABLE()[idx].sg_set & SG_GUI))
+ {
+ if (!init)
+ HL_TABLE()[idx].sg_set |= SG_GUI;
+
+# ifdef FEAT_GUI
+ i = color_name2handle(arg);
+ if (i != INVALCOLOR || STRCMP(arg, "NONE") == 0 || !gui.in_use)
+ {
+ HL_TABLE()[idx].sg_gui_sp = i;
+# endif
+ if (*namep == NULL || STRCMP(*namep, arg) != 0)
+ {
+ vim_free(*namep);
+ if (STRCMP(arg, "NONE") != 0)
+ *namep = vim_strsave(arg);
+ else
+ *namep = NULL;
+ did_change = TRUE;
+ }
+# ifdef FEAT_GUI
+ }
+# endif
+ }
+#endif
+ }
+ else if (STRCMP(key, "START") == 0 || STRCMP(key, "STOP") == 0)
+ {
+ char_u buf[100];
+ char_u *tname;
+
+ if (!init)
+ HL_TABLE()[idx].sg_set |= SG_TERM;
+
+ /*
+ * The "start" and "stop" arguments can be a literal escape
+ * sequence, or a comma separated list of terminal codes.
+ */
+ if (STRNCMP(arg, "t_", 2) == 0)
+ {
+ off = 0;
+ buf[0] = 0;
+ while (arg[off] != NUL)
+ {
+ /* Isolate one termcap name */
+ for (len = 0; arg[off + len] &&
+ arg[off + len] != ','; ++len)
+ ;
+ tname = vim_strnsave(arg + off, len);
+ if (tname == NULL) /* out of memory */
+ {
+ error = TRUE;
+ break;
+ }
+ /* lookup the escape sequence for the item */
+ p = get_term_code(tname);
+ vim_free(tname);
+ if (p == NULL) /* ignore non-existing things */
+ p = (char_u *)"";
+
+ /* Append it to the already found stuff */
+ if ((int)(STRLEN(buf) + STRLEN(p)) >= 99)
+ {
+ semsg(_("E422: terminal code too long: %s"), arg);
+ error = TRUE;
+ break;
+ }
+ STRCAT(buf, p);
+
+ /* Advance to the next item */
+ off += len;
+ if (arg[off] == ',') /* another one follows */
+ ++off;
+ }
+ }
+ else
+ {
+ /*
+ * Copy characters from arg[] to buf[], translating <> codes.
+ */
+ for (p = arg, off = 0; off < 100 - 6 && *p; )
+ {
+ len = trans_special(&p, buf + off, FALSE, FALSE);
+ if (len > 0) /* recognized special char */
+ off += len;
+ else /* copy as normal char */
+ buf[off++] = *p++;
+ }
+ buf[off] = NUL;
+ }
+ if (error)
+ break;
+
+ if (STRCMP(buf, "NONE") == 0) /* resetting the value */
+ p = NULL;
+ else
+ p = vim_strsave(buf);
+ if (key[2] == 'A')
+ {
+ vim_free(HL_TABLE()[idx].sg_start);
+ HL_TABLE()[idx].sg_start = p;
+ }
+ else
+ {
+ vim_free(HL_TABLE()[idx].sg_stop);
+ HL_TABLE()[idx].sg_stop = p;
+ }
+ }
+ else
+ {
+ semsg(_("E423: Illegal argument: %s"), key_start);
+ error = TRUE;
+ break;
+ }
+ HL_TABLE()[idx].sg_cleared = FALSE;
+
+ /*
+ * When highlighting has been given for a group, don't link it.
+ */
+ if (!init || !(HL_TABLE()[idx].sg_set & SG_LINK))
+ HL_TABLE()[idx].sg_link = 0;
+
+ /*
+ * Continue with next argument.
+ */
+ linep = skipwhite(linep);
+ }
+
+ /*
+ * If there is an error, and it's a new entry, remove it from the table.
+ */
+ if (error && idx == highlight_ga.ga_len)
+ syn_unadd_group();
+ else
+ {
+ if (is_normal_group)
+ {
+ HL_TABLE()[idx].sg_term_attr = 0;
+ HL_TABLE()[idx].sg_cterm_attr = 0;
+#ifdef FEAT_GUI
+ HL_TABLE()[idx].sg_gui_attr = 0;
+ /*
+ * Need to update all groups, because they might be using "bg"
+ * and/or "fg", which have been changed now.
+ */
+#endif
+#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
+ if (USE_24BIT)
+ {
+ highlight_gui_started();
+ did_highlight_changed = TRUE;
+ redraw_all_later(NOT_VALID);
+ }
+#endif
+ }
+#ifdef FEAT_TERMINAL
+ else if (is_terminal_group)
+ set_terminal_default_colors(
+ HL_TABLE()[idx].sg_cterm_fg, HL_TABLE()[idx].sg_cterm_bg);
+#endif
+#ifdef FEAT_GUI_X11
+# ifdef FEAT_MENU
+ else if (is_menu_group)
+ {
+ if (gui.in_use && do_colors)
+ gui_mch_new_menu_colors();
+ }
+# endif
+ else if (is_scrollbar_group)
+ {
+ if (gui.in_use && do_colors)
+ gui_new_scrollbar_colors();
+ }
+# ifdef FEAT_BEVAL_GUI
+ else if (is_tooltip_group)
+ {
+ if (gui.in_use && do_colors)
+ gui_mch_new_tooltip_colors();
+ }
+# endif
+#endif
+ else
+ set_hl_attr(idx);
+#ifdef FEAT_EVAL
+ HL_TABLE()[idx].sg_script_ctx = current_sctx;
+ HL_TABLE()[idx].sg_script_ctx.sc_lnum += sourcing_lnum;
+#endif
+ }
+
+ vim_free(key);
+ vim_free(arg);
+
+ /* Only call highlight_changed() once, after a sequence of highlight
+ * commands, and only if an attribute actually changed. */
+ if ((did_change
+ || memcmp(&HL_TABLE()[idx], &item_before, sizeof(item_before)) != 0)
+#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
+ && !did_highlight_changed
+#endif
+ )
+ {
+ /* Do not trigger a redraw when highlighting is changed while
+ * redrawing. This may happen when evaluating 'statusline' changes the
+ * StatusLine group. */
+ if (!updating_screen)
+ redraw_all_later(NOT_VALID);
+ need_highlight_changed = TRUE;
+ }
+}
+
+#if defined(EXITFREE) || defined(PROTO)
+ void
+free_highlight(void)
+{
+ int i;
+
+ for (i = 0; i < highlight_ga.ga_len; ++i)
+ {
+ highlight_clear(i);
+ vim_free(HL_TABLE()[i].sg_name);
+ vim_free(HL_TABLE()[i].sg_name_u);
+ }
+ ga_clear(&highlight_ga);
+}
+#endif
+
+/*
+ * Reset the cterm colors to what they were before Vim was started, if
+ * possible. Otherwise reset them to zero.
+ */
+ void
+restore_cterm_colors(void)
+{
+#if defined(WIN3264) && !defined(FEAT_GUI_W32)
+ /* Since t_me has been set, this probably means that the user
+ * wants to use this as default colors. Need to reset default
+ * background/foreground colors. */
+ mch_set_normal_colors();
+#else
+ cterm_normal_fg_color = 0;
+ cterm_normal_fg_bold = 0;
+ cterm_normal_bg_color = 0;
+# ifdef FEAT_TERMGUICOLORS
+ cterm_normal_fg_gui_color = INVALCOLOR;
+ cterm_normal_bg_gui_color = INVALCOLOR;
+# endif
+#endif
+}
+
+/*
+ * Return TRUE if highlight group "idx" has any settings.
+ * When "check_link" is TRUE also check for an existing link.
+ */
+ static int
+hl_has_settings(int idx, int check_link)
+{
+ return ( HL_TABLE()[idx].sg_term_attr != 0
+ || HL_TABLE()[idx].sg_cterm_attr != 0
+ || HL_TABLE()[idx].sg_cterm_fg != 0
+ || HL_TABLE()[idx].sg_cterm_bg != 0
+#ifdef FEAT_GUI
+ || HL_TABLE()[idx].sg_gui_attr != 0
+ || HL_TABLE()[idx].sg_gui_fg_name != NULL
+ || HL_TABLE()[idx].sg_gui_bg_name != NULL
+ || HL_TABLE()[idx].sg_gui_sp_name != NULL
+ || HL_TABLE()[idx].sg_font_name != NULL
+#endif
+ || (check_link && (HL_TABLE()[idx].sg_set & SG_LINK)));
+}
+
+/*
+ * Clear highlighting for one group.
+ */
+ static void
+highlight_clear(int idx)
+{
+ HL_TABLE()[idx].sg_cleared = TRUE;
+
+ HL_TABLE()[idx].sg_term = 0;
+ VIM_CLEAR(HL_TABLE()[idx].sg_start);
+ VIM_CLEAR(HL_TABLE()[idx].sg_stop);
+ HL_TABLE()[idx].sg_term_attr = 0;
+ HL_TABLE()[idx].sg_cterm = 0;
+ HL_TABLE()[idx].sg_cterm_bold = FALSE;
+ HL_TABLE()[idx].sg_cterm_fg = 0;
+ HL_TABLE()[idx].sg_cterm_bg = 0;
+ HL_TABLE()[idx].sg_cterm_attr = 0;
+#if defined(FEAT_GUI) || defined(FEAT_EVAL)
+ HL_TABLE()[idx].sg_gui = 0;
+ VIM_CLEAR(HL_TABLE()[idx].sg_gui_fg_name);
+ VIM_CLEAR(HL_TABLE()[idx].sg_gui_bg_name);
+ VIM_CLEAR(HL_TABLE()[idx].sg_gui_sp_name);
+#endif
+#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
+ HL_TABLE()[idx].sg_gui_fg = INVALCOLOR;
+ HL_TABLE()[idx].sg_gui_bg = INVALCOLOR;
+#endif
+#ifdef FEAT_GUI
+ HL_TABLE()[idx].sg_gui_sp = INVALCOLOR;
+ gui_mch_free_font(HL_TABLE()[idx].sg_font);
+ HL_TABLE()[idx].sg_font = NOFONT;
+# ifdef FEAT_XFONTSET
+ gui_mch_free_fontset(HL_TABLE()[idx].sg_fontset);
+ HL_TABLE()[idx].sg_fontset = NOFONTSET;
+# endif
+ VIM_CLEAR(HL_TABLE()[idx].sg_font_name);
+ HL_TABLE()[idx].sg_gui_attr = 0;
+#endif
+#ifdef FEAT_EVAL
+ /* Clear the script ID only when there is no link, since that is not
+ * cleared. */
+ if (HL_TABLE()[idx].sg_link == 0)
+ {
+ HL_TABLE()[idx].sg_script_ctx.sc_sid = 0;
+ HL_TABLE()[idx].sg_script_ctx.sc_lnum = 0;
+ }
+#endif
+}
+
+#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS) || defined(PROTO)
+/*
+ * Set the normal foreground and background colors according to the "Normal"
+ * highlighting group. For X11 also set "Menu", "Scrollbar", and
+ * "Tooltip" colors.
+ */
+ void
+set_normal_colors(void)
+{
+# ifdef FEAT_GUI
+# ifdef FEAT_TERMGUICOLORS
+ if (gui.in_use)
+# endif
+ {
+ if (set_group_colors((char_u *)"Normal",
+ &gui.norm_pixel, &gui.back_pixel,
+ FALSE, TRUE, FALSE))
+ {
+ gui_mch_new_colors();
+ must_redraw = CLEAR;
+ }
+# ifdef FEAT_GUI_X11
+ if (set_group_colors((char_u *)"Menu",
+ &gui.menu_fg_pixel, &gui.menu_bg_pixel,
+ TRUE, FALSE, FALSE))
+ {
+# ifdef FEAT_MENU
+ gui_mch_new_menu_colors();
+# endif
+ must_redraw = CLEAR;
+ }
+# ifdef FEAT_BEVAL_GUI
+ if (set_group_colors((char_u *)"Tooltip",
+ &gui.tooltip_fg_pixel, &gui.tooltip_bg_pixel,
+ FALSE, FALSE, TRUE))
+ {
+# ifdef FEAT_TOOLBAR
+ gui_mch_new_tooltip_colors();
+# endif
+ must_redraw = CLEAR;
+ }
+# endif
+ if (set_group_colors((char_u *)"Scrollbar",
+ &gui.scroll_fg_pixel, &gui.scroll_bg_pixel,
+ FALSE, FALSE, FALSE))
+ {
+ gui_new_scrollbar_colors();
+ must_redraw = CLEAR;
+ }
+# endif
+ }
+# endif
+# ifdef FEAT_TERMGUICOLORS
+# ifdef FEAT_GUI
+ else
+# endif
+ {
+ int idx;
+
+ idx = syn_name2id((char_u *)"Normal") - 1;
+ if (idx >= 0)
+ {
+ gui_do_one_color(idx, FALSE, FALSE);
+
+ /* If the normal fg or bg color changed a complete redraw is
+ * required. */
+ if (cterm_normal_fg_gui_color != HL_TABLE()[idx].sg_gui_fg
+ || cterm_normal_bg_gui_color != HL_TABLE()[idx].sg_gui_bg)
+ {
+ /* if the GUI color is INVALCOLOR then we use the default cterm
+ * color */
+ cterm_normal_fg_gui_color = HL_TABLE()[idx].sg_gui_fg;
+ cterm_normal_bg_gui_color = HL_TABLE()[idx].sg_gui_bg;
+ must_redraw = CLEAR;
+ }
+ }
+ }
+# endif
+}
+#endif
+
+#if defined(FEAT_GUI) || defined(PROTO)
+/*
+ * Set the colors for "Normal", "Menu", "Tooltip" or "Scrollbar".
+ */
+ static int
+set_group_colors(
+ char_u *name,
+ guicolor_T *fgp,
+ guicolor_T *bgp,
+ int do_menu,
+ int use_norm,
+ int do_tooltip)
+{
+ int idx;
+
+ idx = syn_name2id(name) - 1;
+ if (idx >= 0)
+ {
+ gui_do_one_color(idx, do_menu, do_tooltip);
+
+ if (HL_TABLE()[idx].sg_gui_fg != INVALCOLOR)
+ *fgp = HL_TABLE()[idx].sg_gui_fg;
+ else if (use_norm)
+ *fgp = gui.def_norm_pixel;
+ if (HL_TABLE()[idx].sg_gui_bg != INVALCOLOR)
+ *bgp = HL_TABLE()[idx].sg_gui_bg;
+ else if (use_norm)
+ *bgp = gui.def_back_pixel;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * Get the font of the "Normal" group.
+ * Returns "" when it's not found or not set.
+ */
+ char_u *
+hl_get_font_name(void)
+{
+ int id;
+ char_u *s;
+
+ id = syn_name2id((char_u *)"Normal");
+ if (id > 0)
+ {
+ s = HL_TABLE()[id - 1].sg_font_name;
+ if (s != NULL)
+ return s;
+ }
+ return (char_u *)"";
+}
+
+/*
+ * Set font for "Normal" group. Called by gui_mch_init_font() when a font has
+ * actually chosen to be used.
+ */
+ void
+hl_set_font_name(char_u *font_name)
+{
+ int id;
+
+ id = syn_name2id((char_u *)"Normal");
+ if (id > 0)
+ {
+ vim_free(HL_TABLE()[id - 1].sg_font_name);
+ HL_TABLE()[id - 1].sg_font_name = vim_strsave(font_name);
+ }
+}
+
+/*
+ * Set background color for "Normal" group. Called by gui_set_bg_color()
+ * when the color is known.
+ */
+ void
+hl_set_bg_color_name(
+ char_u *name) /* must have been allocated */
+{
+ int id;
+
+ if (name != NULL)
+ {
+ id = syn_name2id((char_u *)"Normal");
+ if (id > 0)
+ {
+ vim_free(HL_TABLE()[id - 1].sg_gui_bg_name);
+ HL_TABLE()[id - 1].sg_gui_bg_name = name;
+ }
+ }
+}
+
+/*
+ * Set foreground color for "Normal" group. Called by gui_set_fg_color()
+ * when the color is known.
+ */
+ void
+hl_set_fg_color_name(
+ char_u *name) /* must have been allocated */
+{
+ int id;
+
+ if (name != NULL)
+ {
+ id = syn_name2id((char_u *)"Normal");
+ if (id > 0)
+ {
+ vim_free(HL_TABLE()[id - 1].sg_gui_fg_name);
+ HL_TABLE()[id - 1].sg_gui_fg_name = name;
+ }
+ }
+}
+
+/*
+ * Return the handle for a font name.
+ * Returns NOFONT when failed.
+ */
+ static GuiFont
+font_name2handle(char_u *name)
+{
+ if (STRCMP(name, "NONE") == 0)
+ return NOFONT;
+
+ return gui_mch_get_font(name, TRUE);
+}
+
+# ifdef FEAT_XFONTSET
+/*
+ * Return the handle for a fontset name.
+ * Returns NOFONTSET when failed.
+ */
+ static GuiFontset
+fontset_name2handle(char_u *name, int fixed_width)
+{
+ if (STRCMP(name, "NONE") == 0)
+ return NOFONTSET;
+
+ return gui_mch_get_fontset(name, TRUE, fixed_width);
+}
+# endif
+
+/*
+ * Get the font or fontset for one highlight group.
+ */
+ static void
+hl_do_font(
+ int idx,
+ char_u *arg,
+ int do_normal, /* set normal font */
+ int do_menu UNUSED, /* set menu font */
+ int do_tooltip UNUSED, /* set tooltip font */
+ int free_font) /* free current font/fontset */
+{
+# ifdef FEAT_XFONTSET
+ /* If 'guifontset' is not empty, first try using the name as a
+ * fontset. If that doesn't work, use it as a font name. */
+ if (*p_guifontset != NUL
+# ifdef FONTSET_ALWAYS
+ || do_menu
+# endif
+# ifdef FEAT_BEVAL_TIP
+ /* In Athena & Motif, the Tooltip highlight group is always a fontset */
+ || do_tooltip
+# endif
+ )
+ {
+ if (free_font)
+ gui_mch_free_fontset(HL_TABLE()[idx].sg_fontset);
+ HL_TABLE()[idx].sg_fontset = fontset_name2handle(arg, 0
+# ifdef FONTSET_ALWAYS
+ || do_menu
+# endif
+# ifdef FEAT_BEVAL_TIP
+ || do_tooltip
+# endif
+ );
+ }
+ if (HL_TABLE()[idx].sg_fontset != NOFONTSET)
+ {
+ /* If it worked and it's the Normal group, use it as the normal
+ * fontset. Same for the Menu group. */
+ if (do_normal)
+ gui_init_font(arg, TRUE);
+# if (defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA)) && defined(FEAT_MENU)
+ if (do_menu)
+ {
+# ifdef FONTSET_ALWAYS
+ gui.menu_fontset = HL_TABLE()[idx].sg_fontset;
+# else
+ /* YIKES! This is a bug waiting to crash the program */
+ gui.menu_font = HL_TABLE()[idx].sg_fontset;
+# endif
+ gui_mch_new_menu_font();
+ }
+# ifdef FEAT_BEVAL_GUI
+ if (do_tooltip)
+ {
+ /* The Athena widget set cannot currently handle switching between
+ * displaying a single font and a fontset.
+ * If the XtNinternational resource is set to True at widget
+ * creation, then a fontset is always used, otherwise an
+ * XFontStruct is used.
+ */
+ gui.tooltip_fontset = (XFontSet)HL_TABLE()[idx].sg_fontset;
+ gui_mch_new_tooltip_font();
+ }
+# endif
+# endif
+ }
+ else
+# endif
+ {
+ if (free_font)
+ gui_mch_free_font(HL_TABLE()[idx].sg_font);
+ HL_TABLE()[idx].sg_font = font_name2handle(arg);
+ /* If it worked and it's the Normal group, use it as the
+ * normal font. Same for the Menu group. */
+ if (HL_TABLE()[idx].sg_font != NOFONT)
+ {
+ if (do_normal)
+ gui_init_font(arg, FALSE);
+#ifndef FONTSET_ALWAYS
+# if (defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA)) && defined(FEAT_MENU)
+ if (do_menu)
+ {
+ gui.menu_font = HL_TABLE()[idx].sg_font;
+ gui_mch_new_menu_font();
+ }
+# endif
+#endif
+ }
+ }
+}
+
+#endif /* FEAT_GUI */
+
+#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS) || defined(PROTO)
+/*
+ * Return the handle for a color name.
+ * Returns INVALCOLOR when failed.
+ */
+ guicolor_T
+color_name2handle(char_u *name)
+{
+ if (STRCMP(name, "NONE") == 0)
+ return INVALCOLOR;
+
+ if (STRICMP(name, "fg") == 0 || STRICMP(name, "foreground") == 0)
+ {
+#if defined(FEAT_TERMGUICOLORS) && defined(FEAT_GUI)
+ if (gui.in_use)
+#endif
+#ifdef FEAT_GUI
+ return gui.norm_pixel;
+#endif
+#ifdef FEAT_TERMGUICOLORS
+ if (cterm_normal_fg_gui_color != INVALCOLOR)
+ return cterm_normal_fg_gui_color;
+ /* Guess that the foreground is black or white. */
+ return GUI_GET_COLOR((char_u *)(*p_bg == 'l' ? "black" : "white"));
+#endif
+ }
+ if (STRICMP(name, "bg") == 0 || STRICMP(name, "background") == 0)
+ {
+#if defined(FEAT_TERMGUICOLORS) && defined(FEAT_GUI)
+ if (gui.in_use)
+#endif
+#ifdef FEAT_GUI
+ return gui.back_pixel;
+#endif
+#ifdef FEAT_TERMGUICOLORS
+ if (cterm_normal_bg_gui_color != INVALCOLOR)
+ return cterm_normal_bg_gui_color;
+ /* Guess that the background is white or black. */
+ return GUI_GET_COLOR((char_u *)(*p_bg == 'l' ? "white" : "black"));
+#endif
+ }
+
+ return GUI_GET_COLOR(name);
+}
+#endif
+
+/*
+ * Table with the specifications for an attribute number.
+ * Note that this table is used by ALL buffers. This is required because the
+ * GUI can redraw at any time for any buffer.
+ */
+static garray_T term_attr_table = {0, 0, 0, 0, NULL};
+
+#define TERM_ATTR_ENTRY(idx) ((attrentry_T *)term_attr_table.ga_data)[idx]
+
+static garray_T cterm_attr_table = {0, 0, 0, 0, NULL};
+
+#define CTERM_ATTR_ENTRY(idx) ((attrentry_T *)cterm_attr_table.ga_data)[idx]
+
+#ifdef FEAT_GUI
+static garray_T gui_attr_table = {0, 0, 0, 0, NULL};
+
+#define GUI_ATTR_ENTRY(idx) ((attrentry_T *)gui_attr_table.ga_data)[idx]
+#endif
+
+/*
+ * Return the attr number for a set of colors and font.
+ * Add a new entry to the term_attr_table, cterm_attr_table or gui_attr_table
+ * if the combination is new.
+ * Return 0 for error (no more room).
+ */
+ static int
+get_attr_entry(garray_T *table, attrentry_T *aep)
+{
+ int i;
+ attrentry_T *taep;
+ static int recursive = FALSE;
+
+ /*
+ * Init the table, in case it wasn't done yet.
+ */
+ table->ga_itemsize = sizeof(attrentry_T);
+ table->ga_growsize = 7;
+
+ /*
+ * Try to find an entry with the same specifications.
+ */
+ for (i = 0; i < table->ga_len; ++i)
+ {
+ taep = &(((attrentry_T *)table->ga_data)[i]);
+ if ( aep->ae_attr == taep->ae_attr
+ && (
+#ifdef FEAT_GUI
+ (table == &gui_attr_table
+ && (aep->ae_u.gui.fg_color == taep->ae_u.gui.fg_color
+ && aep->ae_u.gui.bg_color
+ == taep->ae_u.gui.bg_color
+ && aep->ae_u.gui.sp_color
+ == taep->ae_u.gui.sp_color
+ && aep->ae_u.gui.font == taep->ae_u.gui.font
+# ifdef FEAT_XFONTSET
+ && aep->ae_u.gui.fontset == taep->ae_u.gui.fontset
+# endif
+ ))
+ ||
+#endif
+ (table == &term_attr_table
+ && (aep->ae_u.term.start == NULL)
+ == (taep->ae_u.term.start == NULL)
+ && (aep->ae_u.term.start == NULL
+ || STRCMP(aep->ae_u.term.start,
+ taep->ae_u.term.start) == 0)
+ && (aep->ae_u.term.stop == NULL)
+ == (taep->ae_u.term.stop == NULL)
+ && (aep->ae_u.term.stop == NULL
+ || STRCMP(aep->ae_u.term.stop,
+ taep->ae_u.term.stop) == 0))
+ || (table == &cterm_attr_table
+ && aep->ae_u.cterm.fg_color
+ == taep->ae_u.cterm.fg_color
+ && aep->ae_u.cterm.bg_color
+ == taep->ae_u.cterm.bg_color
+#ifdef FEAT_TERMGUICOLORS
+ && aep->ae_u.cterm.fg_rgb
+ == taep->ae_u.cterm.fg_rgb
+ && aep->ae_u.cterm.bg_rgb
+ == taep->ae_u.cterm.bg_rgb
+#endif
+ )))
+
+ return i + ATTR_OFF;
+ }
+
+ if (table->ga_len + ATTR_OFF > MAX_TYPENR)
+ {
+ /*
+ * Running out of attribute entries! remove all attributes, and
+ * compute new ones for all groups.
+ * When called recursively, we are really out of numbers.
+ */
+ if (recursive)
+ {
+ emsg(_("E424: Too many different highlighting attributes in use"));
+ return 0;
+ }
+ recursive = TRUE;
+
+ clear_hl_tables();
+
+ must_redraw = CLEAR;
+
+ for (i = 0; i < highlight_ga.ga_len; ++i)
+ set_hl_attr(i);
+
+ recursive = FALSE;
+ }
+
+ /*
+ * This is a new combination of colors and font, add an entry.
+ */
+ if (ga_grow(table, 1) == FAIL)
+ return 0;
+
+ taep = &(((attrentry_T *)table->ga_data)[table->ga_len]);
+ vim_memset(taep, 0, sizeof(attrentry_T));
+ taep->ae_attr = aep->ae_attr;
+#ifdef FEAT_GUI
+ if (table == &gui_attr_table)
+ {
+ taep->ae_u.gui.fg_color = aep->ae_u.gui.fg_color;
+ taep->ae_u.gui.bg_color = aep->ae_u.gui.bg_color;
+ taep->ae_u.gui.sp_color = aep->ae_u.gui.sp_color;
+ taep->ae_u.gui.font = aep->ae_u.gui.font;
+# ifdef FEAT_XFONTSET
+ taep->ae_u.gui.fontset = aep->ae_u.gui.fontset;
+# endif
+ }
+#endif
+ if (table == &term_attr_table)
+ {
+ if (aep->ae_u.term.start == NULL)
+ taep->ae_u.term.start = NULL;
+ else
+ taep->ae_u.term.start = vim_strsave(aep->ae_u.term.start);
+ if (aep->ae_u.term.stop == NULL)
+ taep->ae_u.term.stop = NULL;
+ else
+ taep->ae_u.term.stop = vim_strsave(aep->ae_u.term.stop);
+ }
+ else if (table == &cterm_attr_table)
+ {
+ taep->ae_u.cterm.fg_color = aep->ae_u.cterm.fg_color;
+ taep->ae_u.cterm.bg_color = aep->ae_u.cterm.bg_color;
+#ifdef FEAT_TERMGUICOLORS
+ taep->ae_u.cterm.fg_rgb = aep->ae_u.cterm.fg_rgb;
+ taep->ae_u.cterm.bg_rgb = aep->ae_u.cterm.bg_rgb;
+#endif
+ }
+ ++table->ga_len;
+ return (table->ga_len - 1 + ATTR_OFF);
+}
+
+#if defined(FEAT_TERMINAL) || defined(PROTO)
+/*
+ * Get an attribute index for a cterm entry.
+ * Uses an existing entry when possible or adds one when needed.
+ */
+ int
+get_cterm_attr_idx(int attr, int fg, int bg)
+{
+ attrentry_T at_en;
+
+ vim_memset(&at_en, 0, sizeof(attrentry_T));
+#ifdef FEAT_TERMGUICOLORS
+ at_en.ae_u.cterm.fg_rgb = INVALCOLOR;
+ at_en.ae_u.cterm.bg_rgb = INVALCOLOR;
+#endif
+ at_en.ae_attr = attr;
+ at_en.ae_u.cterm.fg_color = fg;
+ at_en.ae_u.cterm.bg_color = bg;
+ return get_attr_entry(&cterm_attr_table, &at_en);
+}
+#endif
+
+#if (defined(FEAT_TERMINAL) && defined(FEAT_TERMGUICOLORS)) || defined(PROTO)
+/*
+ * Get an attribute index for a 'termguicolors' entry.
+ * Uses an existing entry when possible or adds one when needed.
+ */
+ int
+get_tgc_attr_idx(int attr, guicolor_T fg, guicolor_T bg)
+{
+ attrentry_T at_en;
+
+ vim_memset(&at_en, 0, sizeof(attrentry_T));
+ at_en.ae_attr = attr;
+ if (fg == INVALCOLOR && bg == INVALCOLOR)
+ {
+ /* If both GUI colors are not set fall back to the cterm colors. Helps
+ * if the GUI only has an attribute, such as undercurl. */
+ at_en.ae_u.cterm.fg_rgb = CTERMCOLOR;
+ at_en.ae_u.cterm.bg_rgb = CTERMCOLOR;
+ }
+ else
+ {
+ at_en.ae_u.cterm.fg_rgb = fg;
+ at_en.ae_u.cterm.bg_rgb = bg;
+ }
+ return get_attr_entry(&cterm_attr_table, &at_en);
+}
+#endif
+
+#if (defined(FEAT_TERMINAL) && defined(FEAT_GUI)) || defined(PROTO)
+/*
+ * Get an attribute index for a cterm entry.
+ * Uses an existing entry when possible or adds one when needed.
+ */
+ int
+get_gui_attr_idx(int attr, guicolor_T fg, guicolor_T bg)
+{
+ attrentry_T at_en;
+
+ vim_memset(&at_en, 0, sizeof(attrentry_T));
+ at_en.ae_attr = attr;
+ at_en.ae_u.gui.fg_color = fg;
+ at_en.ae_u.gui.bg_color = bg;
+ return get_attr_entry(&gui_attr_table, &at_en);
+}
+#endif
+
+/*
+ * Clear all highlight tables.
+ */
+ void
+clear_hl_tables(void)
+{
+ int i;
+ attrentry_T *taep;
+
+#ifdef FEAT_GUI
+ ga_clear(&gui_attr_table);
+#endif
+ for (i = 0; i < term_attr_table.ga_len; ++i)
+ {
+ taep = &(((attrentry_T *)term_attr_table.ga_data)[i]);
+ vim_free(taep->ae_u.term.start);
+ vim_free(taep->ae_u.term.stop);
+ }
+ ga_clear(&term_attr_table);
+ ga_clear(&cterm_attr_table);
+}
+
+#if defined(FEAT_SYN_HL) || defined(FEAT_SPELL) || defined(PROTO)
+/*
+ * Combine special attributes (e.g., for spelling) with other attributes
+ * (e.g., for syntax highlighting).
+ * "prim_attr" overrules "char_attr".
+ * This creates a new group when required.
+ * Since we expect there to be few spelling mistakes we don't cache the
+ * result.
+ * Return the resulting attributes.
+ */
+ int
+hl_combine_attr(int char_attr, int prim_attr)
+{
+ attrentry_T *char_aep = NULL;
+ attrentry_T *spell_aep;
+ attrentry_T new_en;
+
+ if (char_attr == 0)
+ return prim_attr;
+ if (char_attr <= HL_ALL && prim_attr <= HL_ALL)
+ return ATTR_COMBINE(char_attr, prim_attr);
+#ifdef FEAT_GUI
+ if (gui.in_use)
+ {
+ if (char_attr > HL_ALL)
+ char_aep = syn_gui_attr2entry(char_attr);
+ if (char_aep != NULL)
+ new_en = *char_aep;
+ else
+ {
+ vim_memset(&new_en, 0, sizeof(new_en));
+ new_en.ae_u.gui.fg_color = INVALCOLOR;
+ new_en.ae_u.gui.bg_color = INVALCOLOR;
+ new_en.ae_u.gui.sp_color = INVALCOLOR;
+ if (char_attr <= HL_ALL)
+ new_en.ae_attr = char_attr;
+ }
+
+ if (prim_attr <= HL_ALL)
+ new_en.ae_attr = ATTR_COMBINE(new_en.ae_attr, prim_attr);
+ else
+ {
+ spell_aep = syn_gui_attr2entry(prim_attr);
+ if (spell_aep != NULL)
+ {
+ new_en.ae_attr = ATTR_COMBINE(new_en.ae_attr,
+ spell_aep->ae_attr);
+ if (spell_aep->ae_u.gui.fg_color != INVALCOLOR)
+ new_en.ae_u.gui.fg_color = spell_aep->ae_u.gui.fg_color;
+ if (spell_aep->ae_u.gui.bg_color != INVALCOLOR)
+ new_en.ae_u.gui.bg_color = spell_aep->ae_u.gui.bg_color;
+ if (spell_aep->ae_u.gui.sp_color != INVALCOLOR)
+ new_en.ae_u.gui.sp_color = spell_aep->ae_u.gui.sp_color;
+ if (spell_aep->ae_u.gui.font != NOFONT)
+ new_en.ae_u.gui.font = spell_aep->ae_u.gui.font;
+# ifdef FEAT_XFONTSET
+ if (spell_aep->ae_u.gui.fontset != NOFONTSET)
+ new_en.ae_u.gui.fontset = spell_aep->ae_u.gui.fontset;
+# endif
+ }
+ }
+ return get_attr_entry(&gui_attr_table, &new_en);
+ }
+#endif
+
+ if (IS_CTERM)
+ {
+ if (char_attr > HL_ALL)
+ char_aep = syn_cterm_attr2entry(char_attr);
+ if (char_aep != NULL)
+ new_en = *char_aep;
+ else
+ {
+ vim_memset(&new_en, 0, sizeof(new_en));
+#ifdef FEAT_TERMGUICOLORS
+ new_en.ae_u.cterm.bg_rgb = INVALCOLOR;
+ new_en.ae_u.cterm.fg_rgb = INVALCOLOR;
+#endif
+ if (char_attr <= HL_ALL)
+ new_en.ae_attr = char_attr;
+ }
+
+ if (prim_attr <= HL_ALL)
+ new_en.ae_attr = ATTR_COMBINE(new_en.ae_attr, prim_attr);
+ else
+ {
+ spell_aep = syn_cterm_attr2entry(prim_attr);
+ if (spell_aep != NULL)
+ {
+ new_en.ae_attr = ATTR_COMBINE(new_en.ae_attr,
+ spell_aep->ae_attr);
+ if (spell_aep->ae_u.cterm.fg_color > 0)
+ new_en.ae_u.cterm.fg_color = spell_aep->ae_u.cterm.fg_color;
+ if (spell_aep->ae_u.cterm.bg_color > 0)
+ new_en.ae_u.cterm.bg_color = spell_aep->ae_u.cterm.bg_color;
+#ifdef FEAT_TERMGUICOLORS
+ /* If both fg and bg are not set fall back to cterm colors.
+ * Helps for SpellBad which uses undercurl in the GUI. */
+ if (COLOR_INVALID(spell_aep->ae_u.cterm.fg_rgb)
+ && COLOR_INVALID(spell_aep->ae_u.cterm.bg_rgb))
+ {
+ if (spell_aep->ae_u.cterm.fg_color > 0)
+ new_en.ae_u.cterm.fg_rgb = CTERMCOLOR;
+ if (spell_aep->ae_u.cterm.bg_color > 0)
+ new_en.ae_u.cterm.bg_rgb = CTERMCOLOR;
+ }
+ else
+ {
+ if (spell_aep->ae_u.cterm.fg_rgb != INVALCOLOR)
+ new_en.ae_u.cterm.fg_rgb = spell_aep->ae_u.cterm.fg_rgb;
+ if (spell_aep->ae_u.cterm.bg_rgb != INVALCOLOR)
+ new_en.ae_u.cterm.bg_rgb = spell_aep->ae_u.cterm.bg_rgb;
+ }
+#endif
+ }
+ }
+ return get_attr_entry(&cterm_attr_table, &new_en);
+ }
+
+ if (char_attr > HL_ALL)
+ char_aep = syn_term_attr2entry(char_attr);
+ if (char_aep != NULL)
+ new_en = *char_aep;
+ else
+ {
+ vim_memset(&new_en, 0, sizeof(new_en));
+ if (char_attr <= HL_ALL)
+ new_en.ae_attr = char_attr;
+ }
+
+ if (prim_attr <= HL_ALL)
+ new_en.ae_attr = ATTR_COMBINE(new_en.ae_attr, prim_attr);
+ else
+ {
+ spell_aep = syn_term_attr2entry(prim_attr);
+ if (spell_aep != NULL)
+ {
+ new_en.ae_attr = ATTR_COMBINE(new_en.ae_attr, spell_aep->ae_attr);
+ if (spell_aep->ae_u.term.start != NULL)
+ {
+ new_en.ae_u.term.start = spell_aep->ae_u.term.start;
+ new_en.ae_u.term.stop = spell_aep->ae_u.term.stop;
+ }
+ }
+ }
+ return get_attr_entry(&term_attr_table, &new_en);
+}
+#endif
+
+#ifdef FEAT_GUI
+
+ attrentry_T *
+syn_gui_attr2entry(int attr)
+{
+ attr -= ATTR_OFF;
+ if (attr >= gui_attr_table.ga_len) /* did ":syntax clear" */
+ return NULL;
+ return &(GUI_ATTR_ENTRY(attr));
+}
+#endif /* FEAT_GUI */
+
+/*
+ * Get the highlight attributes (HL_BOLD etc.) from an attribute nr.
+ * Only to be used when "attr" > HL_ALL.
+ */
+ int
+syn_attr2attr(int attr)
+{
+ attrentry_T *aep;
+
+#ifdef FEAT_GUI
+ if (gui.in_use)
+ aep = syn_gui_attr2entry(attr);
+ else
+#endif
+ if (IS_CTERM)
+ aep = syn_cterm_attr2entry(attr);
+ else
+ aep = syn_term_attr2entry(attr);
+
+ if (aep == NULL) /* highlighting not set */
+ return 0;
+ return aep->ae_attr;
+}
+
+
+ attrentry_T *
+syn_term_attr2entry(int attr)
+{
+ attr -= ATTR_OFF;
+ if (attr >= term_attr_table.ga_len) /* did ":syntax clear" */
+ return NULL;
+ return &(TERM_ATTR_ENTRY(attr));
+}
+
+ attrentry_T *
+syn_cterm_attr2entry(int attr)
+{
+ attr -= ATTR_OFF;
+ if (attr >= cterm_attr_table.ga_len) /* did ":syntax clear" */
+ return NULL;
+ return &(CTERM_ATTR_ENTRY(attr));
+}
+
+#define LIST_ATTR 1
+#define LIST_STRING 2
+#define LIST_INT 3
+
+ static void
+highlight_list_one(int id)
+{
+ struct hl_group *sgp;
+ int didh = FALSE;
+
+ sgp = &HL_TABLE()[id - 1]; // index is ID minus one
+
+ if (message_filtered(sgp->sg_name))
+ return;
+
+ didh = highlight_list_arg(id, didh, LIST_ATTR,
+ sgp->sg_term, NULL, "term");
+ didh = highlight_list_arg(id, didh, LIST_STRING,
+ 0, sgp->sg_start, "start");
+ didh = highlight_list_arg(id, didh, LIST_STRING,
+ 0, sgp->sg_stop, "stop");
+
+ didh = highlight_list_arg(id, didh, LIST_ATTR,
+ sgp->sg_cterm, NULL, "cterm");
+ didh = highlight_list_arg(id, didh, LIST_INT,
+ sgp->sg_cterm_fg, NULL, "ctermfg");
+ didh = highlight_list_arg(id, didh, LIST_INT,
+ sgp->sg_cterm_bg, NULL, "ctermbg");
+
+#if defined(FEAT_GUI) || defined(FEAT_EVAL)
+ didh = highlight_list_arg(id, didh, LIST_ATTR,
+ sgp->sg_gui, NULL, "gui");
+ didh = highlight_list_arg(id, didh, LIST_STRING,
+ 0, sgp->sg_gui_fg_name, "guifg");
+ didh = highlight_list_arg(id, didh, LIST_STRING,
+ 0, sgp->sg_gui_bg_name, "guibg");
+ didh = highlight_list_arg(id, didh, LIST_STRING,
+ 0, sgp->sg_gui_sp_name, "guisp");
+#endif
+#ifdef FEAT_GUI
+ didh = highlight_list_arg(id, didh, LIST_STRING,
+ 0, sgp->sg_font_name, "font");
+#endif
+
+ if (sgp->sg_link && !got_int)
+ {
+ (void)syn_list_header(didh, 9999, id);
+ didh = TRUE;
+ msg_puts_attr("links to", HL_ATTR(HLF_D));
+ msg_putchar(' ');
+ msg_outtrans(HL_TABLE()[HL_TABLE()[id - 1].sg_link - 1].sg_name);
+ }
+
+ if (!didh)
+ highlight_list_arg(id, didh, LIST_STRING, 0, (char_u *)"cleared", "");
+#ifdef FEAT_EVAL
+ if (p_verbose > 0)
+ last_set_msg(sgp->sg_script_ctx);
+#endif
+}
+
+ static int
+highlight_list_arg(
+ int id,
+ int didh,
+ int type,
+ int iarg,
+ char_u *sarg,
+ char *name)
+{
+ char_u buf[100];
+ char_u *ts;
+ int i;
+
+ if (got_int)
+ return FALSE;
+ if (type == LIST_STRING ? (sarg != NULL) : (iarg != 0))
+ {
+ ts = buf;
+ if (type == LIST_INT)
+ sprintf((char *)buf, "%d", iarg - 1);
+ else if (type == LIST_STRING)
+ ts = sarg;
+ else /* type == LIST_ATTR */
+ {
+ buf[0] = NUL;
+ for (i = 0; hl_attr_table[i] != 0; ++i)
+ {
+ if (iarg & hl_attr_table[i])
+ {
+ if (buf[0] != NUL)
+ vim_strcat(buf, (char_u *)",", 100);
+ vim_strcat(buf, (char_u *)hl_name_table[i], 100);
+ iarg &= ~hl_attr_table[i]; /* don't want "inverse" */
+ }
+ }
+ }
+
+ (void)syn_list_header(didh,
+ (int)(vim_strsize(ts) + STRLEN(name) + 1), id);
+ didh = TRUE;
+ if (!got_int)
+ {
+ if (*name != NUL)
+ {
+ msg_puts_attr(name, HL_ATTR(HLF_D));
+ msg_puts_attr("=", HL_ATTR(HLF_D));
+ }
+ msg_outtrans(ts);
+ }
+ }
+ return didh;
+}
+
+#if (((defined(FEAT_EVAL) || defined(FEAT_PRINTER))) && defined(FEAT_SYN_HL)) || defined(PROTO)
+/*
+ * Return "1" if highlight group "id" has attribute "flag".
+ * Return NULL otherwise.
+ */
+ char_u *
+highlight_has_attr(
+ int id,
+ int flag,
+ int modec) /* 'g' for GUI, 'c' for cterm, 't' for term */
+{
+ int attr;
+
+ if (id <= 0 || id > highlight_ga.ga_len)
+ return NULL;
+
+#if defined(FEAT_GUI) || defined(FEAT_EVAL)
+ if (modec == 'g')
+ attr = HL_TABLE()[id - 1].sg_gui;
+ else
+#endif
+ if (modec == 'c')
+ attr = HL_TABLE()[id - 1].sg_cterm;
+ else
+ attr = HL_TABLE()[id - 1].sg_term;
+
+ if (attr & flag)
+ return (char_u *)"1";
+ return NULL;
+}
+#endif
+
+#if (defined(FEAT_SYN_HL) && defined(FEAT_EVAL)) || defined(PROTO)
+/*
+ * Return color name of highlight group "id".
+ */
+ char_u *
+highlight_color(
+ int id,
+ char_u *what, /* "font", "fg", "bg", "sp", "fg#", "bg#" or "sp#" */
+ int modec) /* 'g' for GUI, 'c' for cterm, 't' for term */
+{
+ static char_u name[20];
+ int n;
+ int fg = FALSE;
+ int sp = FALSE;
+ int font = FALSE;
+
+ if (id <= 0 || id > highlight_ga.ga_len)
+ return NULL;
+
+ if (TOLOWER_ASC(what[0]) == 'f' && TOLOWER_ASC(what[1]) == 'g')
+ fg = TRUE;
+ else if (TOLOWER_ASC(what[0]) == 'f' && TOLOWER_ASC(what[1]) == 'o'
+ && TOLOWER_ASC(what[2]) == 'n' && TOLOWER_ASC(what[3]) == 't')
+ font = TRUE;
+ else if (TOLOWER_ASC(what[0]) == 's' && TOLOWER_ASC(what[1]) == 'p')
+ sp = TRUE;
+ else if (!(TOLOWER_ASC(what[0]) == 'b' && TOLOWER_ASC(what[1]) == 'g'))
+ return NULL;
+ if (modec == 'g')
+ {
+# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
+# ifdef FEAT_GUI
+ /* return font name */
+ if (font)
+ return HL_TABLE()[id - 1].sg_font_name;
+# endif
+
+ /* return #RRGGBB form (only possible when GUI is running) */
+ if ((USE_24BIT) && what[2] == '#')
+ {
+ guicolor_T color;
+ long_u rgb;
+ static char_u buf[10];
+
+ if (fg)
+ color = HL_TABLE()[id - 1].sg_gui_fg;
+ else if (sp)
+# ifdef FEAT_GUI
+ color = HL_TABLE()[id - 1].sg_gui_sp;
+# else
+ color = INVALCOLOR;
+# endif
+ else
+ color = HL_TABLE()[id - 1].sg_gui_bg;
+ if (color == INVALCOLOR)
+ return NULL;
+ rgb = (long_u)GUI_MCH_GET_RGB(color);
+ sprintf((char *)buf, "#%02x%02x%02x",
+ (unsigned)(rgb >> 16),
+ (unsigned)(rgb >> 8) & 255,
+ (unsigned)rgb & 255);
+ return buf;
+ }
+# endif
+ if (fg)
+ return (HL_TABLE()[id - 1].sg_gui_fg_name);
+ if (sp)
+ return (HL_TABLE()[id - 1].sg_gui_sp_name);
+ return (HL_TABLE()[id - 1].sg_gui_bg_name);
+ }
+ if (font || sp)
+ return NULL;
+ if (modec == 'c')
+ {
+ if (fg)
+ n = HL_TABLE()[id - 1].sg_cterm_fg - 1;
+ else
+ n = HL_TABLE()[id - 1].sg_cterm_bg - 1;
+ if (n < 0)
+ return NULL;
+ sprintf((char *)name, "%d", n);
+ return name;
+ }
+ /* term doesn't have color */
+ return NULL;
+}
+#endif
+
+#if (defined(FEAT_SYN_HL) \
+ && (defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)) \
+ && defined(FEAT_PRINTER)) || defined(PROTO)
+/*
+ * Return color name of highlight group "id" as RGB value.
+ */
+ long_u
+highlight_gui_color_rgb(
+ int id,
+ int fg) /* TRUE = fg, FALSE = bg */
+{
+ guicolor_T color;
+
+ if (id <= 0 || id > highlight_ga.ga_len)
+ return 0L;
+
+ if (fg)
+ color = HL_TABLE()[id - 1].sg_gui_fg;
+ else
+ color = HL_TABLE()[id - 1].sg_gui_bg;
+
+ if (color == INVALCOLOR)
+ return 0L;
+
+ return GUI_MCH_GET_RGB(color);
+}
+#endif
+
+/*
+ * Output the syntax list header.
+ * Return TRUE when started a new line.
+ */
+ static int
+syn_list_header(
+ int did_header, /* did header already */
+ int outlen, /* length of string that comes */
+ int id) /* highlight group id */
+{
+ int endcol = 19;
+ int newline = TRUE;
+
+ if (!did_header)
+ {
+ msg_putchar('\n');
+ if (got_int)
+ return TRUE;
+ msg_outtrans(HL_TABLE()[id - 1].sg_name);
+ endcol = 15;
+ }
+ else if (msg_col + outlen + 1 >= Columns)
+ {
+ msg_putchar('\n');
+ if (got_int)
+ return TRUE;
+ }
+ else
+ {
+ if (msg_col >= endcol) /* wrap around is like starting a new line */
+ newline = FALSE;
+ }
+
+ if (msg_col >= endcol) /* output at least one space */
+ endcol = msg_col + 1;
+ if (Columns <= endcol) /* avoid hang for tiny window */
+ endcol = Columns - 1;
+
+ msg_advance(endcol);
+
+ /* Show "xxx" with the attributes. */
+ if (!did_header)
+ {
+ msg_puts_attr("xxx", syn_id2attr(id));
+ msg_putchar(' ');
+ }
+
+ return newline;
+}
+
+/*
+ * Set the attribute numbers for a highlight group.
+ * Called after one of the attributes has changed.
+ */
+ static void
+set_hl_attr(
+ int idx) /* index in array */
+{
+ attrentry_T at_en;
+ struct hl_group *sgp = HL_TABLE() + idx;
+
+ /* The "Normal" group doesn't need an attribute number */
+ if (sgp->sg_name_u != NULL && STRCMP(sgp->sg_name_u, "NORMAL") == 0)
+ return;
+
+#ifdef FEAT_GUI
+ /*
+ * For the GUI mode: If there are other than "normal" highlighting
+ * attributes, need to allocate an attr number.
+ */
+ if (sgp->sg_gui_fg == INVALCOLOR
+ && sgp->sg_gui_bg == INVALCOLOR
+ && sgp->sg_gui_sp == INVALCOLOR
+ && sgp->sg_font == NOFONT
+# ifdef FEAT_XFONTSET
+ && sgp->sg_fontset == NOFONTSET
+# endif
+ )
+ {
+ sgp->sg_gui_attr = sgp->sg_gui;
+ }
+ else
+ {
+ at_en.ae_attr = sgp->sg_gui;
+ at_en.ae_u.gui.fg_color = sgp->sg_gui_fg;
+ at_en.ae_u.gui.bg_color = sgp->sg_gui_bg;
+ at_en.ae_u.gui.sp_color = sgp->sg_gui_sp;
+ at_en.ae_u.gui.font = sgp->sg_font;
+# ifdef FEAT_XFONTSET
+ at_en.ae_u.gui.fontset = sgp->sg_fontset;
+# endif
+ sgp->sg_gui_attr = get_attr_entry(&gui_attr_table, &at_en);
+ }
+#endif
+ /*
+ * For the term mode: If there are other than "normal" highlighting
+ * attributes, need to allocate an attr number.
+ */
+ if (sgp->sg_start == NULL && sgp->sg_stop == NULL)
+ sgp->sg_term_attr = sgp->sg_term;
+ else
+ {
+ at_en.ae_attr = sgp->sg_term;
+ at_en.ae_u.term.start = sgp->sg_start;
+ at_en.ae_u.term.stop = sgp->sg_stop;
+ sgp->sg_term_attr = get_attr_entry(&term_attr_table, &at_en);
+ }
+
+ /*
+ * For the color term mode: If there are other than "normal"
+ * highlighting attributes, need to allocate an attr number.
+ */
+ if (sgp->sg_cterm_fg == 0 && sgp->sg_cterm_bg == 0
+# ifdef FEAT_TERMGUICOLORS
+ && sgp->sg_gui_fg == INVALCOLOR
+ && sgp->sg_gui_bg == INVALCOLOR
+# endif
+ )
+ sgp->sg_cterm_attr = sgp->sg_cterm;
+ else
+ {
+ at_en.ae_attr = sgp->sg_cterm;
+ at_en.ae_u.cterm.fg_color = sgp->sg_cterm_fg;
+ at_en.ae_u.cterm.bg_color = sgp->sg_cterm_bg;
+# ifdef FEAT_TERMGUICOLORS
+# ifdef WIN3264
+ {
+ int id;
+ guicolor_T fg, bg;
+
+ id = syn_name2id((char_u *)"Normal");
+ if (id > 0)
+ {
+ syn_id2colors(id, &fg, &bg);
+ if (sgp->sg_gui_fg == INVALCOLOR)
+ sgp->sg_gui_fg = fg;
+ if (sgp->sg_gui_bg == INVALCOLOR)
+ sgp->sg_gui_bg = bg;
+ }
+
+ }
+# endif
+ at_en.ae_u.cterm.fg_rgb = GUI_MCH_GET_RGB2(sgp->sg_gui_fg);
+ at_en.ae_u.cterm.bg_rgb = GUI_MCH_GET_RGB2(sgp->sg_gui_bg);
+ if (at_en.ae_u.cterm.fg_rgb == INVALCOLOR
+ && at_en.ae_u.cterm.bg_rgb == INVALCOLOR)
+ {
+ /* If both fg and bg are invalid fall back to the cterm colors.
+ * Helps when the GUI only uses an attribute, e.g. undercurl. */
+ at_en.ae_u.cterm.fg_rgb = CTERMCOLOR;
+ at_en.ae_u.cterm.bg_rgb = CTERMCOLOR;
+ }
+# endif
+ sgp->sg_cterm_attr = get_attr_entry(&cterm_attr_table, &at_en);
+ }
+}
+
+/*
+ * Lookup a highlight group name and return its ID.
+ * If it is not found, 0 is returned.
+ */
+ int
+syn_name2id(char_u *name)
+{
+ int i;
+ char_u name_u[200];
+
+ /* Avoid using stricmp() too much, it's slow on some systems */
+ /* Avoid alloc()/free(), these are slow too. ID names over 200 chars
+ * don't deserve to be found! */
+ vim_strncpy(name_u, name, 199);
+ vim_strup(name_u);
+ for (i = highlight_ga.ga_len; --i >= 0; )
+ if (HL_TABLE()[i].sg_name_u != NULL
+ && STRCMP(name_u, HL_TABLE()[i].sg_name_u) == 0)
+ break;
+ return i + 1;
+}
+
+/*
+ * Lookup a highlight group name and return its attributes.
+ * Return zero if not found.
+ */
+ int
+syn_name2attr(char_u *name)
+{
+ int id = syn_name2id(name);
+
+ if (id != 0)
+ return syn_id2attr(id);
+ return 0;
+}
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * Return TRUE if highlight group "name" exists.
+ */
+ int
+highlight_exists(char_u *name)
+{
+ return (syn_name2id(name) > 0);
+}
+
+# if defined(FEAT_SEARCH_EXTRA) || defined(PROTO)
+/*
+ * Return the name of highlight group "id".
+ * When not a valid ID return an empty string.
+ */
+ char_u *
+syn_id2name(int id)
+{
+ if (id <= 0 || id > highlight_ga.ga_len)
+ return (char_u *)"";
+ return HL_TABLE()[id - 1].sg_name;
+}
+# endif
+#endif
+
+/*
+ * Like syn_name2id(), but take a pointer + length argument.
+ */
+ int
+syn_namen2id(char_u *linep, int len)
+{
+ char_u *name;
+ int id = 0;
+
+ name = vim_strnsave(linep, len);
+ if (name != NULL)
+ {
+ id = syn_name2id(name);
+ vim_free(name);
+ }
+ return id;
+}
+
+/*
+ * Find highlight group name in the table and return its ID.
+ * The argument is a pointer to the name and the length of the name.
+ * If it doesn't exist yet, a new entry is created.
+ * Return 0 for failure.
+ */
+ int
+syn_check_group(char_u *pp, int len)
+{
+ int id;
+ char_u *name;
+
+ name = vim_strnsave(pp, len);
+ if (name == NULL)
+ return 0;
+
+ id = syn_name2id(name);
+ if (id == 0) /* doesn't exist yet */
+ id = syn_add_group(name);
+ else
+ vim_free(name);
+ return id;
+}
+
+/*
+ * Add new highlight group and return its ID.
+ * "name" must be an allocated string, it will be consumed.
+ * Return 0 for failure.
+ */
+ static int
+syn_add_group(char_u *name)
+{
+ char_u *p;
+
+ /* Check that the name is ASCII letters, digits and underscore. */
+ for (p = name; *p != NUL; ++p)
+ {
+ if (!vim_isprintc(*p))
+ {
+ emsg(_("E669: Unprintable character in group name"));
+ vim_free(name);
+ return 0;
+ }
+ else if (!ASCII_ISALNUM(*p) && *p != '_')
+ {
+ /* This is an error, but since there previously was no check only
+ * give a warning. */
+ msg_source(HL_ATTR(HLF_W));
+ msg(_("W18: Invalid character in group name"));
+ break;
+ }
+ }
+
+ /*
+ * First call for this growarray: init growing array.
+ */
+ if (highlight_ga.ga_data == NULL)
+ {
+ highlight_ga.ga_itemsize = sizeof(struct hl_group);
+ highlight_ga.ga_growsize = 10;
+ }
+
+ if (highlight_ga.ga_len >= MAX_HL_ID)
+ {
+ emsg(_("E849: Too many highlight and syntax groups"));
+ vim_free(name);
+ return 0;
+ }
+
+ /*
+ * Make room for at least one other syntax_highlight entry.
+ */
+ if (ga_grow(&highlight_ga, 1) == FAIL)
+ {
+ vim_free(name);
+ return 0;
+ }
+
+ vim_memset(&(HL_TABLE()[highlight_ga.ga_len]), 0, sizeof(struct hl_group));
+ HL_TABLE()[highlight_ga.ga_len].sg_name = name;
+ HL_TABLE()[highlight_ga.ga_len].sg_name_u = vim_strsave_up(name);
+#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
+ HL_TABLE()[highlight_ga.ga_len].sg_gui_bg = INVALCOLOR;
+ HL_TABLE()[highlight_ga.ga_len].sg_gui_fg = INVALCOLOR;
+# ifdef FEAT_GUI
+ HL_TABLE()[highlight_ga.ga_len].sg_gui_sp = INVALCOLOR;
+# endif
+#endif
+ ++highlight_ga.ga_len;
+
+ return highlight_ga.ga_len; /* ID is index plus one */
+}
+
+/*
+ * When, just after calling syn_add_group(), an error is discovered, this
+ * function deletes the new name.
+ */
+ static void
+syn_unadd_group(void)
+{
+ --highlight_ga.ga_len;
+ vim_free(HL_TABLE()[highlight_ga.ga_len].sg_name);
+ vim_free(HL_TABLE()[highlight_ga.ga_len].sg_name_u);
+}
+
+/*
+ * Translate a group ID to highlight attributes.
+ */
+ int
+syn_id2attr(int hl_id)
+{
+ int attr;
+ struct hl_group *sgp;
+
+ hl_id = syn_get_final_id(hl_id);
+ sgp = &HL_TABLE()[hl_id - 1]; /* index is ID minus one */
+
+#ifdef FEAT_GUI
+ /*
+ * Only use GUI attr when the GUI is being used.
+ */
+ if (gui.in_use)
+ attr = sgp->sg_gui_attr;
+ else
+#endif
+ if (IS_CTERM)
+ attr = sgp->sg_cterm_attr;
+ else
+ attr = sgp->sg_term_attr;
+
+ return attr;
+}
+
+#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS) || defined(PROTO)
+/*
+ * Get the GUI colors and attributes for a group ID.
+ * NOTE: the colors will be INVALCOLOR when not set, the color otherwise.
+ */
+ int
+syn_id2colors(int hl_id, guicolor_T *fgp, guicolor_T *bgp)
+{
+ struct hl_group *sgp;
+
+ hl_id = syn_get_final_id(hl_id);
+ sgp = &HL_TABLE()[hl_id - 1]; /* index is ID minus one */
+
+ *fgp = sgp->sg_gui_fg;
+ *bgp = sgp->sg_gui_bg;
+ return sgp->sg_gui;
+}
+#endif
+
+#if (defined(WIN3264) \
+ && !defined(FEAT_GUI_W32) \
+ && defined(FEAT_TERMGUICOLORS)) || defined(PROTO)
+ void
+syn_id2cterm_bg(int hl_id, int *fgp, int *bgp)
+{
+ struct hl_group *sgp;
+
+ hl_id = syn_get_final_id(hl_id);
+ sgp = &HL_TABLE()[hl_id - 1]; /* index is ID minus one */
+ *fgp = sgp->sg_cterm_fg - 1;
+ *bgp = sgp->sg_cterm_bg - 1;
+}
+#endif
+
+/*
+ * Translate a group ID to the final group ID (following links).
+ */
+ int
+syn_get_final_id(int hl_id)
+{
+ int count;
+ struct hl_group *sgp;
+
+ if (hl_id > highlight_ga.ga_len || hl_id < 1)
+ return 0; /* Can be called from eval!! */
+
+ /*
+ * Follow links until there is no more.
+ * Look out for loops! Break after 100 links.
+ */
+ for (count = 100; --count >= 0; )
+ {
+ sgp = &HL_TABLE()[hl_id - 1]; /* index is ID minus one */
+ if (sgp->sg_link == 0 || sgp->sg_link > highlight_ga.ga_len)
+ break;
+ hl_id = sgp->sg_link;
+ }
+
+ return hl_id;
+}
+
+#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS) || defined(PROTO)
+/*
+ * Call this function just after the GUI has started.
+ * Also called when 'termguicolors' was set, gui.in_use will be FALSE then.
+ * It finds the font and color handles for the highlighting groups.
+ */
+ void
+highlight_gui_started(void)
+{
+ int idx;
+
+ /* First get the colors from the "Normal" and "Menu" group, if set */
+ if (USE_24BIT)
+ set_normal_colors();
+
+ for (idx = 0; idx < highlight_ga.ga_len; ++idx)
+ gui_do_one_color(idx, FALSE, FALSE);
+
+ highlight_changed();
+}
+
+ static void
+gui_do_one_color(
+ int idx,
+ int do_menu UNUSED, /* TRUE: might set the menu font */
+ int do_tooltip UNUSED) /* TRUE: might set the tooltip font */
+{
+ int didit = FALSE;
+
+# ifdef FEAT_GUI
+# ifdef FEAT_TERMGUICOLORS
+ if (gui.in_use)
+# endif
+ if (HL_TABLE()[idx].sg_font_name != NULL)
+ {
+ hl_do_font(idx, HL_TABLE()[idx].sg_font_name, FALSE, do_menu,
+ do_tooltip, TRUE);
+ didit = TRUE;
+ }
+# endif
+ if (HL_TABLE()[idx].sg_gui_fg_name != NULL)
+ {
+ HL_TABLE()[idx].sg_gui_fg =
+ color_name2handle(HL_TABLE()[idx].sg_gui_fg_name);
+ didit = TRUE;
+ }
+ if (HL_TABLE()[idx].sg_gui_bg_name != NULL)
+ {
+ HL_TABLE()[idx].sg_gui_bg =
+ color_name2handle(HL_TABLE()[idx].sg_gui_bg_name);
+ didit = TRUE;
+ }
+# ifdef FEAT_GUI
+ if (HL_TABLE()[idx].sg_gui_sp_name != NULL)
+ {
+ HL_TABLE()[idx].sg_gui_sp =
+ color_name2handle(HL_TABLE()[idx].sg_gui_sp_name);
+ didit = TRUE;
+ }
+# endif
+ if (didit) /* need to get a new attr number */
+ set_hl_attr(idx);
+}
+#endif
+
+#if defined(USER_HIGHLIGHT) && defined(FEAT_STL_OPT)
+/*
+ * Apply difference between User[1-9] and HLF_S to HLF_SNC, HLF_ST or HLF_STNC.
+ */
+ static void
+combine_stl_hlt(
+ int id,
+ int id_S,
+ int id_alt,
+ int hlcnt,
+ int i,
+ int hlf,
+ int *table)
+{
+ struct hl_group *hlt = HL_TABLE();
+
+ if (id_alt == 0)
+ {
+ vim_memset(&hlt[hlcnt + i], 0, sizeof(struct hl_group));
+ hlt[hlcnt + i].sg_term = highlight_attr[hlf];
+ hlt[hlcnt + i].sg_cterm = highlight_attr[hlf];
+# if defined(FEAT_GUI) || defined(FEAT_EVAL)
+ hlt[hlcnt + i].sg_gui = highlight_attr[hlf];
+# endif
+ }
+ else
+ mch_memmove(&hlt[hlcnt + i],
+ &hlt[id_alt - 1],
+ sizeof(struct hl_group));
+ hlt[hlcnt + i].sg_link = 0;
+
+ hlt[hlcnt + i].sg_term ^=
+ hlt[id - 1].sg_term ^ hlt[id_S - 1].sg_term;
+ if (hlt[id - 1].sg_start != hlt[id_S - 1].sg_start)
+ hlt[hlcnt + i].sg_start = hlt[id - 1].sg_start;
+ if (hlt[id - 1].sg_stop != hlt[id_S - 1].sg_stop)
+ hlt[hlcnt + i].sg_stop = hlt[id - 1].sg_stop;
+ hlt[hlcnt + i].sg_cterm ^=
+ hlt[id - 1].sg_cterm ^ hlt[id_S - 1].sg_cterm;
+ if (hlt[id - 1].sg_cterm_fg != hlt[id_S - 1].sg_cterm_fg)
+ hlt[hlcnt + i].sg_cterm_fg = hlt[id - 1].sg_cterm_fg;
+ if (hlt[id - 1].sg_cterm_bg != hlt[id_S - 1].sg_cterm_bg)
+ hlt[hlcnt + i].sg_cterm_bg = hlt[id - 1].sg_cterm_bg;
+# if defined(FEAT_GUI) || defined(FEAT_EVAL)
+ hlt[hlcnt + i].sg_gui ^=
+ hlt[id - 1].sg_gui ^ hlt[id_S - 1].sg_gui;
+# endif
+# ifdef FEAT_GUI
+ if (hlt[id - 1].sg_gui_fg != hlt[id_S - 1].sg_gui_fg)
+ hlt[hlcnt + i].sg_gui_fg = hlt[id - 1].sg_gui_fg;
+ if (hlt[id - 1].sg_gui_bg != hlt[id_S - 1].sg_gui_bg)
+ hlt[hlcnt + i].sg_gui_bg = hlt[id - 1].sg_gui_bg;
+ if (hlt[id - 1].sg_gui_sp != hlt[id_S - 1].sg_gui_sp)
+ hlt[hlcnt + i].sg_gui_sp = hlt[id - 1].sg_gui_sp;
+ if (hlt[id - 1].sg_font != hlt[id_S - 1].sg_font)
+ hlt[hlcnt + i].sg_font = hlt[id - 1].sg_font;
+# ifdef FEAT_XFONTSET
+ if (hlt[id - 1].sg_fontset != hlt[id_S - 1].sg_fontset)
+ hlt[hlcnt + i].sg_fontset = hlt[id - 1].sg_fontset;
+# endif
+# endif
+ highlight_ga.ga_len = hlcnt + i + 1;
+ set_hl_attr(hlcnt + i); /* At long last we can apply */
+ table[i] = syn_id2attr(hlcnt + i + 1);
+}
+#endif
+
+/*
+ * Translate the 'highlight' option into attributes in highlight_attr[] and
+ * set up the user highlights User1..9. If FEAT_STL_OPT is in use, a set of
+ * corresponding highlights to use on top of HLF_SNC is computed.
+ * Called only when the 'highlight' option has been changed and upon first
+ * screen redraw after any :highlight command.
+ * Return FAIL when an invalid flag is found in 'highlight'. OK otherwise.
+ */
+ int
+highlight_changed(void)
+{
+ int hlf;
+ int i;
+ char_u *p;
+ int attr;
+ char_u *end;
+ int id;
+#ifdef USER_HIGHLIGHT
+ char_u userhl[10];
+# ifdef FEAT_STL_OPT
+ int id_S = -1;
+ int id_SNC = 0;
+# ifdef FEAT_TERMINAL
+ int id_ST = 0;
+ int id_STNC = 0;
+# endif
+ int hlcnt;
+# endif
+#endif
+ static int hl_flags[HLF_COUNT] = HL_FLAGS;
+
+ need_highlight_changed = FALSE;
+
+ /*
+ * Clear all attributes.
+ */
+ for (hlf = 0; hlf < (int)HLF_COUNT; ++hlf)
+ highlight_attr[hlf] = 0;
+
+ /*
+ * First set all attributes to their default value.
+ * Then use the attributes from the 'highlight' option.
+ */
+ for (i = 0; i < 2; ++i)
+ {
+ if (i)
+ p = p_hl;
+ else
+ p = get_highlight_default();
+ if (p == NULL) /* just in case */
+ continue;
+
+ while (*p)
+ {
+ for (hlf = 0; hlf < (int)HLF_COUNT; ++hlf)
+ if (hl_flags[hlf] == *p)
+ break;
+ ++p;
+ if (hlf == (int)HLF_COUNT || *p == NUL)
+ return FAIL;
+
+ /*
+ * Allow several hl_flags to be combined, like "bu" for
+ * bold-underlined.
+ */
+ attr = 0;
+ for ( ; *p && *p != ','; ++p) /* parse upto comma */
+ {
+ if (VIM_ISWHITE(*p)) /* ignore white space */
+ continue;
+
+ if (attr > HL_ALL) /* Combination with ':' is not allowed. */
+ return FAIL;
+
+ switch (*p)
+ {
+ case 'b': attr |= HL_BOLD;
+ break;
+ case 'i': attr |= HL_ITALIC;
+ break;
+ case '-':
+ case 'n': /* no highlighting */
+ break;
+ case 'r': attr |= HL_INVERSE;
+ break;
+ case 's': attr |= HL_STANDOUT;
+ break;
+ case 'u': attr |= HL_UNDERLINE;
+ break;
+ case 'c': attr |= HL_UNDERCURL;
+ break;
+ case 't': attr |= HL_STRIKETHROUGH;
+ break;
+ case ':': ++p; /* highlight group name */
+ if (attr || *p == NUL) /* no combinations */
+ return FAIL;
+ end = vim_strchr(p, ',');
+ if (end == NULL)
+ end = p + STRLEN(p);
+ id = syn_check_group(p, (int)(end - p));
+ if (id == 0)
+ return FAIL;
+ attr = syn_id2attr(id);
+ p = end - 1;
+#if defined(FEAT_STL_OPT) && defined(USER_HIGHLIGHT)
+ if (hlf == (int)HLF_SNC)
+ id_SNC = syn_get_final_id(id);
+# ifdef FEAT_TERMINAL
+ else if (hlf == (int)HLF_ST)
+ id_ST = syn_get_final_id(id);
+ else if (hlf == (int)HLF_STNC)
+ id_STNC = syn_get_final_id(id);
+# endif
+ else if (hlf == (int)HLF_S)
+ id_S = syn_get_final_id(id);
+#endif
+ break;
+ default: return FAIL;
+ }
+ }
+ highlight_attr[hlf] = attr;
+
+ p = skip_to_option_part(p); /* skip comma and spaces */
+ }
+ }
+
+#ifdef USER_HIGHLIGHT
+ /* Setup the user highlights
+ *
+ * Temporarily utilize 28 more hl entries:
+ * 9 for User1-User9 combined with StatusLineNC
+ * 9 for User1-User9 combined with StatusLineTerm
+ * 9 for User1-User9 combined with StatusLineTermNC
+ * 1 for StatusLine default
+ * Have to be in there simultaneously in case of table overflows in
+ * get_attr_entry()
+ */
+# ifdef FEAT_STL_OPT
+ if (ga_grow(&highlight_ga, 28) == FAIL)
+ return FAIL;
+ hlcnt = highlight_ga.ga_len;
+ if (id_S == -1)
+ {
+ /* Make sure id_S is always valid to simplify code below. Use the last
+ * entry. */
+ vim_memset(&HL_TABLE()[hlcnt + 27], 0, sizeof(struct hl_group));
+ HL_TABLE()[hlcnt + 18].sg_term = highlight_attr[HLF_S];
+ id_S = hlcnt + 19;
+ }
+# endif
+ for (i = 0; i < 9; i++)
+ {
+ sprintf((char *)userhl, "User%d", i + 1);
+ id = syn_name2id(userhl);
+ if (id == 0)
+ {
+ highlight_user[i] = 0;
+# ifdef FEAT_STL_OPT
+ highlight_stlnc[i] = 0;
+# ifdef FEAT_TERMINAL
+ highlight_stlterm[i] = 0;
+ highlight_stltermnc[i] = 0;
+# endif
+# endif
+ }
+ else
+ {
+ highlight_user[i] = syn_id2attr(id);
+# ifdef FEAT_STL_OPT
+ combine_stl_hlt(id, id_S, id_SNC, hlcnt, i,
+ HLF_SNC, highlight_stlnc);
+# ifdef FEAT_TERMINAL
+ combine_stl_hlt(id, id_S, id_ST, hlcnt + 9, i,
+ HLF_ST, highlight_stlterm);
+ combine_stl_hlt(id, id_S, id_STNC, hlcnt + 18, i,
+ HLF_STNC, highlight_stltermnc);
+# endif
+# endif
+ }
+ }
+# ifdef FEAT_STL_OPT
+ highlight_ga.ga_len = hlcnt;
+# endif
+
+#endif /* USER_HIGHLIGHT */
+
+ return OK;
+}
+
+#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
+
+static void highlight_list(void);
+static void highlight_list_two(int cnt, int attr);
+
+/*
+ * Handle command line completion for :highlight command.
+ */
+ void
+set_context_in_highlight_cmd(expand_T *xp, char_u *arg)
+{
+ char_u *p;
+
+ /* Default: expand group names */
+ xp->xp_context = EXPAND_HIGHLIGHT;
+ xp->xp_pattern = arg;
+ include_link = 2;
+ include_default = 1;
+
+ /* (part of) subcommand already typed */
+ if (*arg != NUL)
+ {
+ p = skiptowhite(arg);
+ if (*p != NUL) /* past "default" or group name */
+ {
+ include_default = 0;
+ if (STRNCMP("default", arg, p - arg) == 0)
+ {
+ arg = skipwhite(p);
+ xp->xp_pattern = arg;
+ p = skiptowhite(arg);
+ }
+ if (*p != NUL) /* past group name */
+ {
+ include_link = 0;
+ if (arg[1] == 'i' && arg[0] == 'N')
+ highlight_list();
+ if (STRNCMP("link", arg, p - arg) == 0
+ || STRNCMP("clear", arg, p - arg) == 0)
+ {
+ xp->xp_pattern = skipwhite(p);
+ p = skiptowhite(xp->xp_pattern);
+ if (*p != NUL) /* past first group name */
+ {
+ xp->xp_pattern = skipwhite(p);
+ p = skiptowhite(xp->xp_pattern);
+ }
+ }
+ if (*p != NUL) /* past group name(s) */
+ xp->xp_context = EXPAND_NOTHING;
+ }
+ }
+ }
+}
+
+/*
+ * List highlighting matches in a nice way.
+ */
+ static void
+highlight_list(void)
+{
+ int i;
+
+ for (i = 10; --i >= 0; )
+ highlight_list_two(i, HL_ATTR(HLF_D));
+ for (i = 40; --i >= 0; )
+ highlight_list_two(99, 0);
+}
+
+ static void
+highlight_list_two(int cnt, int attr)
+{
+ msg_puts_attr(&("N \bI \b! \b"[cnt / 11]), attr);
+ msg_clr_eos();
+ out_flush();
+ ui_delay(cnt == 99 ? 40L : (long)cnt * 50L, FALSE);
+}
+
+#endif /* FEAT_CMDL_COMPL */
+
+#if defined(FEAT_CMDL_COMPL) || (defined(FEAT_SYN_HL) && defined(FEAT_EVAL)) \
+ || defined(FEAT_SIGNS) || defined(PROTO)
+/*
+ * Function given to ExpandGeneric() to obtain the list of group names.
+ */
+ char_u *
+get_highlight_name(expand_T *xp UNUSED, int idx)
+{
+ return get_highlight_name_ext(xp, idx, TRUE);
+}
+
+/*
+ * Obtain a highlight group name.
+ * When "skip_cleared" is TRUE don't return a cleared entry.
+ */
+ char_u *
+get_highlight_name_ext(expand_T *xp UNUSED, int idx, int skip_cleared)
+{
+ if (idx < 0)
+ return NULL;
+
+ /* Items are never removed from the table, skip the ones that were
+ * cleared. */
+ if (skip_cleared && idx < highlight_ga.ga_len && HL_TABLE()[idx].sg_cleared)
+ return (char_u *)"";
+
+#ifdef FEAT_CMDL_COMPL
+ if (idx == highlight_ga.ga_len && include_none != 0)
+ return (char_u *)"none";
+ if (idx == highlight_ga.ga_len + include_none && include_default != 0)
+ return (char_u *)"default";
+ if (idx == highlight_ga.ga_len + include_none + include_default
+ && include_link != 0)
+ return (char_u *)"link";
+ if (idx == highlight_ga.ga_len + include_none + include_default + 1
+ && include_link != 0)
+ return (char_u *)"clear";
+#endif
+ if (idx >= highlight_ga.ga_len)
+ return NULL;
+ return HL_TABLE()[idx].sg_name;
+}
+#endif
+
+#if defined(FEAT_GUI) || defined(PROTO)
+/*
+ * Free all the highlight group fonts.
+ * Used when quitting for systems which need it.
+ */
+ void
+free_highlight_fonts(void)
+{
+ int idx;
+
+ for (idx = 0; idx < highlight_ga.ga_len; ++idx)
+ {
+ gui_mch_free_font(HL_TABLE()[idx].sg_font);
+ HL_TABLE()[idx].sg_font = NOFONT;
+# ifdef FEAT_XFONTSET
+ gui_mch_free_fontset(HL_TABLE()[idx].sg_fontset);
+ HL_TABLE()[idx].sg_fontset = NOFONTSET;
+# endif
+ }
+
+ gui_mch_free_font(gui.norm_font);
+# ifdef FEAT_XFONTSET
+ gui_mch_free_fontset(gui.fontset);
+# endif
+# ifndef FEAT_GUI_GTK
+ gui_mch_free_font(gui.bold_font);
+ gui_mch_free_font(gui.ital_font);
+ gui_mch_free_font(gui.boldital_font);
+# endif
+}
+#endif
+
+/**************************************
+ * End of Highlighting stuff *
+ **************************************/
diff --git a/src/tag.c b/src/tag.c
new file mode 100644
index 0000000..b1915e1
--- /dev/null
+++ b/src/tag.c
@@ -0,0 +1,4209 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * Code to handle tags and the tag stack
+ */
+
+#include "vim.h"
+
+/*
+ * Structure to hold pointers to various items in a tag line.
+ */
+typedef struct tag_pointers
+{
+ /* filled in by parse_tag_line(): */
+ char_u *tagname; /* start of tag name (skip "file:") */
+ char_u *tagname_end; /* char after tag name */
+ char_u *fname; /* first char of file name */
+ char_u *fname_end; /* char after file name */
+ char_u *command; /* first char of command */
+ /* filled in by parse_match(): */
+ char_u *command_end; /* first char after command */
+ char_u *tag_fname; /* file name of the tags file */
+#ifdef FEAT_EMACS_TAGS
+ int is_etag; /* TRUE for emacs tag */
+#endif
+ char_u *tagkind; /* "kind:" value */
+ char_u *tagkind_end; /* end of tagkind */
+} tagptrs_T;
+
+/*
+ * The matching tags are first stored in one of the hash tables. In
+ * which one depends on the priority of the match.
+ * ht_match[] is used to find duplicates, ga_match[] to keep them in sequence.
+ * At the end, all the matches from ga_match[] are concatenated, to make a list
+ * sorted on priority.
+ */
+#define MT_ST_CUR 0 /* static match in current file */
+#define MT_GL_CUR 1 /* global match in current file */
+#define MT_GL_OTH 2 /* global match in other file */
+#define MT_ST_OTH 3 /* static match in other file */
+#define MT_IC_OFF 4 /* add for icase match */
+#define MT_RE_OFF 8 /* add for regexp match */
+#define MT_MASK 7 /* mask for printing priority */
+#define MT_COUNT 16
+
+static char *mt_names[MT_COUNT/2] =
+ {"FSC", "F C", "F ", "FS ", " SC", " C", " ", " S "};
+
+#define NOTAGFILE 99 /* return value for jumpto_tag */
+static char_u *nofile_fname = NULL; /* fname for NOTAGFILE error */
+
+static void taglen_advance(int l);
+
+static int jumpto_tag(char_u *lbuf, int forceit, int keep_help);
+#ifdef FEAT_EMACS_TAGS
+static int parse_tag_line(char_u *lbuf, int is_etag, tagptrs_T *tagp);
+#else
+static int parse_tag_line(char_u *lbuf, tagptrs_T *tagp);
+#endif
+static int test_for_static(tagptrs_T *);
+static int parse_match(char_u *lbuf, tagptrs_T *tagp);
+static char_u *tag_full_fname(tagptrs_T *tagp);
+static char_u *expand_tag_fname(char_u *fname, char_u *tag_fname, int expand);
+#ifdef FEAT_EMACS_TAGS
+static int test_for_current(int, char_u *, char_u *, char_u *, char_u *);
+#else
+static int test_for_current(char_u *, char_u *, char_u *, char_u *);
+#endif
+static int find_extra(char_u **pp);
+
+static char_u *bottommsg = (char_u *)N_("E555: at bottom of tag stack");
+static char_u *topmsg = (char_u *)N_("E556: at top of tag stack");
+
+static char_u *tagmatchname = NULL; /* name of last used tag */
+
+#if defined(FEAT_QUICKFIX)
+/*
+ * Tag for preview window is remembered separately, to avoid messing up the
+ * normal tagstack.
+ */
+static taggy_T ptag_entry = {NULL, {{0, 0, 0}, 0}, 0, 0};
+#endif
+
+/*
+ * Jump to tag; handling of tag commands and tag stack
+ *
+ * *tag != NUL: ":tag {tag}", jump to new tag, add to tag stack
+ *
+ * type == DT_TAG: ":tag [tag]", jump to newer position or same tag again
+ * type == DT_HELP: like DT_TAG, but don't use regexp.
+ * type == DT_POP: ":pop" or CTRL-T, jump to old position
+ * type == DT_NEXT: jump to next match of same tag
+ * type == DT_PREV: jump to previous match of same tag
+ * type == DT_FIRST: jump to first match of same tag
+ * type == DT_LAST: jump to last match of same tag
+ * type == DT_SELECT: ":tselect [tag]", select tag from a list of all matches
+ * type == DT_JUMP: ":tjump [tag]", jump to tag or select tag from a list
+ * type == DT_CSCOPE: use cscope to find the tag
+ * type == DT_LTAG: use location list for displaying tag matches
+ * type == DT_FREE: free cached matches
+ *
+ * for cscope, returns TRUE if we jumped to tag or aborted, FALSE otherwise
+ */
+ int
+do_tag(
+ char_u *tag, /* tag (pattern) to jump to */
+ int type,
+ int count,
+ int forceit, /* :ta with ! */
+ int verbose) /* print "tag not found" message */
+{
+ taggy_T *tagstack = curwin->w_tagstack;
+ int tagstackidx = curwin->w_tagstackidx;
+ int tagstacklen = curwin->w_tagstacklen;
+ int cur_match = 0;
+ int cur_fnum = curbuf->b_fnum;
+ int oldtagstackidx = tagstackidx;
+ int prevtagstackidx = tagstackidx;
+ int prev_num_matches;
+ int new_tag = FALSE;
+ int other_name;
+ int i, j, k;
+ int idx;
+ int ic;
+ char_u *p;
+ char_u *name;
+ int no_regexp = FALSE;
+ int error_cur_match = 0;
+ char_u *command_end;
+ int save_pos = FALSE;
+ fmark_T saved_fmark;
+ int taglen;
+#ifdef FEAT_CSCOPE
+ int jumped_to_tag = FALSE;
+#endif
+ tagptrs_T tagp, tagp2;
+ int new_num_matches;
+ char_u **new_matches;
+ int attr;
+ int use_tagstack;
+ int skip_msg = FALSE;
+ char_u *buf_ffname = curbuf->b_ffname; /* name to use for
+ priority computation */
+
+ /* remember the matches for the last used tag */
+ static int num_matches = 0;
+ static int max_num_matches = 0; /* limit used for match search */
+ static char_u **matches = NULL;
+ static int flags;
+
+#ifdef EXITFREE
+ if (type == DT_FREE)
+ {
+ /* remove the list of matches */
+ FreeWild(num_matches, matches);
+# ifdef FEAT_CSCOPE
+ cs_free_tags();
+# endif
+ num_matches = 0;
+ return FALSE;
+ }
+#endif
+
+ if (type == DT_HELP)
+ {
+ type = DT_TAG;
+ no_regexp = TRUE;
+ }
+
+ prev_num_matches = num_matches;
+ free_string_option(nofile_fname);
+ nofile_fname = NULL;
+
+ CLEAR_POS(&saved_fmark.mark); /* shutup gcc 4.0 */
+ saved_fmark.fnum = 0;
+
+ /*
+ * Don't add a tag to the tagstack if 'tagstack' has been reset.
+ */
+ if ((!p_tgst && *tag != NUL))
+ {
+ use_tagstack = FALSE;
+ new_tag = TRUE;
+#if defined(FEAT_QUICKFIX)
+ if (g_do_tagpreview != 0)
+ {
+ vim_free(ptag_entry.tagname);
+ if ((ptag_entry.tagname = vim_strsave(tag)) == NULL)
+ goto end_do_tag;
+ }
+#endif
+ }
+ else
+ {
+#if defined(FEAT_QUICKFIX)
+ if (g_do_tagpreview != 0)
+ use_tagstack = FALSE;
+ else
+#endif
+ use_tagstack = TRUE;
+
+ /* new pattern, add to the tag stack */
+ if (*tag != NUL
+ && (type == DT_TAG || type == DT_SELECT || type == DT_JUMP
+#ifdef FEAT_QUICKFIX
+ || type == DT_LTAG
+#endif
+#ifdef FEAT_CSCOPE
+ || type == DT_CSCOPE
+#endif
+ ))
+ {
+#if defined(FEAT_QUICKFIX)
+ if (g_do_tagpreview != 0)
+ {
+ if (ptag_entry.tagname != NULL
+ && STRCMP(ptag_entry.tagname, tag) == 0)
+ {
+ /* Jumping to same tag: keep the current match, so that
+ * the CursorHold autocommand example works. */
+ cur_match = ptag_entry.cur_match;
+ cur_fnum = ptag_entry.cur_fnum;
+ }
+ else
+ {
+ vim_free(ptag_entry.tagname);
+ if ((ptag_entry.tagname = vim_strsave(tag)) == NULL)
+ goto end_do_tag;
+ }
+ }
+ else
+#endif
+ {
+ /*
+ * If the last used entry is not at the top, delete all tag
+ * stack entries above it.
+ */
+ while (tagstackidx < tagstacklen)
+ vim_free(tagstack[--tagstacklen].tagname);
+
+ /* if the tagstack is full: remove oldest entry */
+ if (++tagstacklen > TAGSTACKSIZE)
+ {
+ tagstacklen = TAGSTACKSIZE;
+ vim_free(tagstack[0].tagname);
+ for (i = 1; i < tagstacklen; ++i)
+ tagstack[i - 1] = tagstack[i];
+ --tagstackidx;
+ }
+
+ /*
+ * put the tag name in the tag stack
+ */
+ if ((tagstack[tagstackidx].tagname = vim_strsave(tag)) == NULL)
+ {
+ curwin->w_tagstacklen = tagstacklen - 1;
+ goto end_do_tag;
+ }
+ curwin->w_tagstacklen = tagstacklen;
+
+ save_pos = TRUE; /* save the cursor position below */
+ }
+
+ new_tag = TRUE;
+ }
+ else
+ {
+ if (
+#if defined(FEAT_QUICKFIX)
+ g_do_tagpreview != 0 ? ptag_entry.tagname == NULL :
+#endif
+ tagstacklen == 0)
+ {
+ /* empty stack */
+ emsg(_(e_tagstack));
+ goto end_do_tag;
+ }
+
+ if (type == DT_POP) /* go to older position */
+ {
+#ifdef FEAT_FOLDING
+ int old_KeyTyped = KeyTyped;
+#endif
+ if ((tagstackidx -= count) < 0)
+ {
+ emsg(_(bottommsg));
+ if (tagstackidx + count == 0)
+ {
+ /* We did [num]^T from the bottom of the stack */
+ tagstackidx = 0;
+ goto end_do_tag;
+ }
+ /* We weren't at the bottom of the stack, so jump all the
+ * way to the bottom now.
+ */
+ tagstackidx = 0;
+ }
+ else if (tagstackidx >= tagstacklen) /* count == 0? */
+ {
+ emsg(_(topmsg));
+ goto end_do_tag;
+ }
+
+ /* Make a copy of the fmark, autocommands may invalidate the
+ * tagstack before it's used. */
+ saved_fmark = tagstack[tagstackidx].fmark;
+ if (saved_fmark.fnum != curbuf->b_fnum)
+ {
+ /*
+ * Jump to other file. If this fails (e.g. because the
+ * file was changed) keep original position in tag stack.
+ */
+ if (buflist_getfile(saved_fmark.fnum, saved_fmark.mark.lnum,
+ GETF_SETMARK, forceit) == FAIL)
+ {
+ tagstackidx = oldtagstackidx; /* back to old posn */
+ goto end_do_tag;
+ }
+ /* An BufReadPost autocommand may jump to the '" mark, but
+ * we don't what that here. */
+ curwin->w_cursor.lnum = saved_fmark.mark.lnum;
+ }
+ else
+ {
+ setpcmark();
+ curwin->w_cursor.lnum = saved_fmark.mark.lnum;
+ }
+ curwin->w_cursor.col = saved_fmark.mark.col;
+ curwin->w_set_curswant = TRUE;
+ check_cursor();
+#ifdef FEAT_FOLDING
+ if ((fdo_flags & FDO_TAG) && old_KeyTyped)
+ foldOpenCursor();
+#endif
+
+ /* remove the old list of matches */
+ FreeWild(num_matches, matches);
+#ifdef FEAT_CSCOPE
+ cs_free_tags();
+#endif
+ num_matches = 0;
+ tag_freematch();
+ goto end_do_tag;
+ }
+
+ if (type == DT_TAG
+#if defined(FEAT_QUICKFIX)
+ || type == DT_LTAG
+#endif
+ )
+ {
+#if defined(FEAT_QUICKFIX)
+ if (g_do_tagpreview != 0)
+ {
+ cur_match = ptag_entry.cur_match;
+ cur_fnum = ptag_entry.cur_fnum;
+ }
+ else
+#endif
+ {
+ /* ":tag" (no argument): go to newer pattern */
+ save_pos = TRUE; /* save the cursor position below */
+ if ((tagstackidx += count - 1) >= tagstacklen)
+ {
+ /*
+ * Beyond the last one, just give an error message and
+ * go to the last one. Don't store the cursor
+ * position.
+ */
+ tagstackidx = tagstacklen - 1;
+ emsg(_(topmsg));
+ save_pos = FALSE;
+ }
+ else if (tagstackidx < 0) /* must have been count == 0 */
+ {
+ emsg(_(bottommsg));
+ tagstackidx = 0;
+ goto end_do_tag;
+ }
+ cur_match = tagstack[tagstackidx].cur_match;
+ cur_fnum = tagstack[tagstackidx].cur_fnum;
+ }
+ new_tag = TRUE;
+ }
+ else /* go to other matching tag */
+ {
+ /* Save index for when selection is cancelled. */
+ prevtagstackidx = tagstackidx;
+
+#if defined(FEAT_QUICKFIX)
+ if (g_do_tagpreview != 0)
+ {
+ cur_match = ptag_entry.cur_match;
+ cur_fnum = ptag_entry.cur_fnum;
+ }
+ else
+#endif
+ {
+ if (--tagstackidx < 0)
+ tagstackidx = 0;
+ cur_match = tagstack[tagstackidx].cur_match;
+ cur_fnum = tagstack[tagstackidx].cur_fnum;
+ }
+ switch (type)
+ {
+ case DT_FIRST: cur_match = count - 1; break;
+ case DT_SELECT:
+ case DT_JUMP:
+#ifdef FEAT_CSCOPE
+ case DT_CSCOPE:
+#endif
+ case DT_LAST: cur_match = MAXCOL - 1; break;
+ case DT_NEXT: cur_match += count; break;
+ case DT_PREV: cur_match -= count; break;
+ }
+ if (cur_match >= MAXCOL)
+ cur_match = MAXCOL - 1;
+ else if (cur_match < 0)
+ {
+ emsg(_("E425: Cannot go before first matching tag"));
+ skip_msg = TRUE;
+ cur_match = 0;
+ cur_fnum = curbuf->b_fnum;
+ }
+ }
+ }
+
+#if defined(FEAT_QUICKFIX)
+ if (g_do_tagpreview != 0)
+ {
+ if (type != DT_SELECT && type != DT_JUMP)
+ {
+ ptag_entry.cur_match = cur_match;
+ ptag_entry.cur_fnum = cur_fnum;
+ }
+ }
+ else
+#endif
+ {
+ /*
+ * For ":tag [arg]" or ":tselect" remember position before the jump.
+ */
+ saved_fmark = tagstack[tagstackidx].fmark;
+ if (save_pos)
+ {
+ tagstack[tagstackidx].fmark.mark = curwin->w_cursor;
+ tagstack[tagstackidx].fmark.fnum = curbuf->b_fnum;
+ }
+
+ /* Curwin will change in the call to jumpto_tag() if ":stag" was
+ * used or an autocommand jumps to another window; store value of
+ * tagstackidx now. */
+ curwin->w_tagstackidx = tagstackidx;
+ if (type != DT_SELECT && type != DT_JUMP)
+ {
+ curwin->w_tagstack[tagstackidx].cur_match = cur_match;
+ curwin->w_tagstack[tagstackidx].cur_fnum = cur_fnum;
+ }
+ }
+ }
+
+ /* When not using the current buffer get the name of buffer "cur_fnum".
+ * Makes sure that the tag order doesn't change when using a remembered
+ * position for "cur_match". */
+ if (cur_fnum != curbuf->b_fnum)
+ {
+ buf_T *buf = buflist_findnr(cur_fnum);
+
+ if (buf != NULL)
+ buf_ffname = buf->b_ffname;
+ }
+
+ /*
+ * Repeat searching for tags, when a file has not been found.
+ */
+ for (;;)
+ {
+ /*
+ * When desired match not found yet, try to find it (and others).
+ */
+ if (use_tagstack)
+ name = tagstack[tagstackidx].tagname;
+#if defined(FEAT_QUICKFIX)
+ else if (g_do_tagpreview != 0)
+ name = ptag_entry.tagname;
+#endif
+ else
+ name = tag;
+ other_name = (tagmatchname == NULL || STRCMP(tagmatchname, name) != 0);
+ if (new_tag
+ || (cur_match >= num_matches && max_num_matches != MAXCOL)
+ || other_name)
+ {
+ if (other_name)
+ {
+ vim_free(tagmatchname);
+ tagmatchname = vim_strsave(name);
+ }
+
+ if (type == DT_TAG || type == DT_SELECT || type == DT_JUMP
+#if defined(FEAT_QUICKFIX)
+ || type == DT_LTAG
+#endif
+ )
+ cur_match = MAXCOL - 1;
+ max_num_matches = cur_match + 1;
+
+ /* when the argument starts with '/', use it as a regexp */
+ if (!no_regexp && *name == '/')
+ {
+ flags = TAG_REGEXP;
+ ++name;
+ }
+ else
+ flags = TAG_NOIC;
+
+#ifdef FEAT_CSCOPE
+ if (type == DT_CSCOPE)
+ flags = TAG_CSCOPE;
+#endif
+ if (verbose)
+ flags |= TAG_VERBOSE;
+ if (find_tags(name, &new_num_matches, &new_matches, flags,
+ max_num_matches, buf_ffname) == OK
+ && new_num_matches < max_num_matches)
+ max_num_matches = MAXCOL; /* If less than max_num_matches
+ found: all matches found. */
+
+ /* If there already were some matches for the same name, move them
+ * to the start. Avoids that the order changes when using
+ * ":tnext" and jumping to another file. */
+ if (!new_tag && !other_name)
+ {
+ /* Find the position of each old match in the new list. Need
+ * to use parse_match() to find the tag line. */
+ idx = 0;
+ for (j = 0; j < num_matches; ++j)
+ {
+ parse_match(matches[j], &tagp);
+ for (i = idx; i < new_num_matches; ++i)
+ {
+ parse_match(new_matches[i], &tagp2);
+ if (STRCMP(tagp.tagname, tagp2.tagname) == 0)
+ {
+ p = new_matches[i];
+ for (k = i; k > idx; --k)
+ new_matches[k] = new_matches[k - 1];
+ new_matches[idx++] = p;
+ break;
+ }
+ }
+ }
+ }
+ FreeWild(num_matches, matches);
+ num_matches = new_num_matches;
+ matches = new_matches;
+ }
+
+ if (num_matches <= 0)
+ {
+ if (verbose)
+ semsg(_("E426: tag not found: %s"), name);
+#if defined(FEAT_QUICKFIX)
+ g_do_tagpreview = 0;
+#endif
+ }
+ else
+ {
+ int ask_for_selection = FALSE;
+
+#ifdef FEAT_CSCOPE
+ if (type == DT_CSCOPE && num_matches > 1)
+ {
+ cs_print_tags();
+ ask_for_selection = TRUE;
+ }
+ else
+#endif
+ if (type == DT_TAG)
+ /*
+ * If a count is supplied to the ":tag <name>" command, then
+ * jump to count'th matching tag.
+ */
+ cur_match = count > 0 ? count - 1 : 0;
+ else if (type == DT_SELECT || (type == DT_JUMP && num_matches > 1))
+ {
+ /*
+ * List all the matching tags.
+ * Assume that the first match indicates how long the tags can
+ * be, and align the file names to that.
+ */
+ parse_match(matches[0], &tagp);
+ taglen = (int)(tagp.tagname_end - tagp.tagname + 2);
+ if (taglen < 18)
+ taglen = 18;
+ if (taglen > Columns - 25)
+ taglen = MAXCOL;
+ if (msg_col == 0)
+ msg_didout = FALSE; /* overwrite previous message */
+ msg_start();
+ msg_puts_attr(_(" # pri kind tag"), HL_ATTR(HLF_T));
+ msg_clr_eos();
+ taglen_advance(taglen);
+ msg_puts_attr(_("file\n"), HL_ATTR(HLF_T));
+
+ for (i = 0; i < num_matches && !got_int; ++i)
+ {
+ parse_match(matches[i], &tagp);
+ if (!new_tag && (
+#if defined(FEAT_QUICKFIX)
+ (g_do_tagpreview != 0
+ && i == ptag_entry.cur_match) ||
+#endif
+ (use_tagstack
+ && i == tagstack[tagstackidx].cur_match)))
+ *IObuff = '>';
+ else
+ *IObuff = ' ';
+ vim_snprintf((char *)IObuff + 1, IOSIZE - 1,
+ "%2d %s ", i + 1,
+ mt_names[matches[i][0] & MT_MASK]);
+ msg_puts((char *)IObuff);
+ if (tagp.tagkind != NULL)
+ msg_outtrans_len(tagp.tagkind,
+ (int)(tagp.tagkind_end - tagp.tagkind));
+ msg_advance(13);
+ msg_outtrans_len_attr(tagp.tagname,
+ (int)(tagp.tagname_end - tagp.tagname),
+ HL_ATTR(HLF_T));
+ msg_putchar(' ');
+ taglen_advance(taglen);
+
+ /* Find out the actual file name. If it is long, truncate
+ * it and put "..." in the middle */
+ p = tag_full_fname(&tagp);
+ if (p != NULL)
+ {
+ msg_outtrans_long_attr(p, HL_ATTR(HLF_D));
+ vim_free(p);
+ }
+ if (msg_col > 0)
+ msg_putchar('\n');
+ if (got_int)
+ break;
+ msg_advance(15);
+
+ /* print any extra fields */
+ command_end = tagp.command_end;
+ if (command_end != NULL)
+ {
+ p = command_end + 3;
+ while (*p && *p != '\r' && *p != '\n')
+ {
+ while (*p == TAB)
+ ++p;
+
+ /* skip "file:" without a value (static tag) */
+ if (STRNCMP(p, "file:", 5) == 0
+ && vim_isspace(p[5]))
+ {
+ p += 5;
+ continue;
+ }
+ /* skip "kind:<kind>" and "<kind>" */
+ if (p == tagp.tagkind
+ || (p + 5 == tagp.tagkind
+ && STRNCMP(p, "kind:", 5) == 0))
+ {
+ p = tagp.tagkind_end;
+ continue;
+ }
+ /* print all other extra fields */
+ attr = HL_ATTR(HLF_CM);
+ while (*p && *p != '\r' && *p != '\n')
+ {
+ if (msg_col + ptr2cells(p) >= Columns)
+ {
+ msg_putchar('\n');
+ if (got_int)
+ break;
+ msg_advance(15);
+ }
+ p = msg_outtrans_one(p, attr);
+ if (*p == TAB)
+ {
+ msg_puts_attr(" ", attr);
+ break;
+ }
+ if (*p == ':')
+ attr = 0;
+ }
+ }
+ if (msg_col > 15)
+ {
+ msg_putchar('\n');
+ if (got_int)
+ break;
+ msg_advance(15);
+ }
+ }
+ else
+ {
+ for (p = tagp.command;
+ *p && *p != '\r' && *p != '\n'; ++p)
+ ;
+ command_end = p;
+ }
+
+ /*
+ * Put the info (in several lines) at column 15.
+ * Don't display "/^" and "?^".
+ */
+ p = tagp.command;
+ if (*p == '/' || *p == '?')
+ {
+ ++p;
+ if (*p == '^')
+ ++p;
+ }
+ /* Remove leading whitespace from pattern */
+ while (p != command_end && vim_isspace(*p))
+ ++p;
+
+ while (p != command_end)
+ {
+ if (msg_col + (*p == TAB ? 1 : ptr2cells(p)) > Columns)
+ msg_putchar('\n');
+ if (got_int)
+ break;
+ msg_advance(15);
+
+ /* skip backslash used for escaping a command char or
+ * a backslash */
+ if (*p == '\\' && (*(p + 1) == *tagp.command
+ || *(p + 1) == '\\'))
+ ++p;
+
+ if (*p == TAB)
+ {
+ msg_putchar(' ');
+ ++p;
+ }
+ else
+ p = msg_outtrans_one(p, 0);
+
+ /* don't display the "$/;\"" and "$?;\"" */
+ if (p == command_end - 2 && *p == '$'
+ && *(p + 1) == *tagp.command)
+ break;
+ /* don't display matching '/' or '?' */
+ if (p == command_end - 1 && *p == *tagp.command
+ && (*p == '/' || *p == '?'))
+ break;
+ }
+ if (msg_col)
+ msg_putchar('\n');
+ ui_breakcheck();
+ }
+ if (got_int)
+ got_int = FALSE; /* only stop the listing */
+ ask_for_selection = TRUE;
+ }
+#if defined(FEAT_QUICKFIX) && defined(FEAT_EVAL)
+ else if (type == DT_LTAG)
+ {
+ list_T *list;
+ char_u tag_name[128 + 1];
+ char_u *fname;
+ char_u *cmd;
+
+ /*
+ * Add the matching tags to the location list for the current
+ * window.
+ */
+
+ fname = alloc(MAXPATHL + 1);
+ cmd = alloc(CMDBUFFSIZE + 1);
+ list = list_alloc();
+ if (list == NULL || fname == NULL || cmd == NULL)
+ {
+ vim_free(cmd);
+ vim_free(fname);
+ if (list != NULL)
+ list_free(list);
+ goto end_do_tag;
+ }
+
+ for (i = 0; i < num_matches; ++i)
+ {
+ int len, cmd_len;
+ long lnum;
+ dict_T *dict;
+
+ parse_match(matches[i], &tagp);
+
+ /* Save the tag name */
+ len = (int)(tagp.tagname_end - tagp.tagname);
+ if (len > 128)
+ len = 128;
+ vim_strncpy(tag_name, tagp.tagname, len);
+ tag_name[len] = NUL;
+
+ /* Save the tag file name */
+ p = tag_full_fname(&tagp);
+ if (p == NULL)
+ continue;
+ vim_strncpy(fname, p, MAXPATHL);
+ vim_free(p);
+
+ /*
+ * Get the line number or the search pattern used to locate
+ * the tag.
+ */
+ lnum = 0;
+ if (isdigit(*tagp.command))
+ /* Line number is used to locate the tag */
+ lnum = atol((char *)tagp.command);
+ else
+ {
+ char_u *cmd_start, *cmd_end;
+
+ /* Search pattern is used to locate the tag */
+
+ /* Locate the end of the command */
+ cmd_start = tagp.command;
+ cmd_end = tagp.command_end;
+ if (cmd_end == NULL)
+ {
+ for (p = tagp.command;
+ *p && *p != '\r' && *p != '\n'; ++p)
+ ;
+ cmd_end = p;
+ }
+
+ /*
+ * Now, cmd_end points to the character after the
+ * command. Adjust it to point to the last
+ * character of the command.
+ */
+ cmd_end--;
+
+ /*
+ * Skip the '/' and '?' characters at the
+ * beginning and end of the search pattern.
+ */
+ if (*cmd_start == '/' || *cmd_start == '?')
+ cmd_start++;
+
+ if (*cmd_end == '/' || *cmd_end == '?')
+ cmd_end--;
+
+ len = 0;
+ cmd[0] = NUL;
+
+ /*
+ * If "^" is present in the tag search pattern, then
+ * copy it first.
+ */
+ if (*cmd_start == '^')
+ {
+ STRCPY(cmd, "^");
+ cmd_start++;
+ len++;
+ }
+
+ /*
+ * Precede the tag pattern with \V to make it very
+ * nomagic.
+ */
+ STRCAT(cmd, "\\V");
+ len += 2;
+
+ cmd_len = (int)(cmd_end - cmd_start + 1);
+ if (cmd_len > (CMDBUFFSIZE - 5))
+ cmd_len = CMDBUFFSIZE - 5;
+ STRNCAT(cmd, cmd_start, cmd_len);
+ len += cmd_len;
+
+ if (cmd[len - 1] == '$')
+ {
+ /*
+ * Replace '$' at the end of the search pattern
+ * with '\$'
+ */
+ cmd[len - 1] = '\\';
+ cmd[len] = '$';
+ len++;
+ }
+
+ cmd[len] = NUL;
+ }
+
+ if ((dict = dict_alloc()) == NULL)
+ continue;
+ if (list_append_dict(list, dict) == FAIL)
+ {
+ vim_free(dict);
+ continue;
+ }
+
+ dict_add_string(dict, "text", tag_name);
+ dict_add_string(dict, "filename", fname);
+ dict_add_number(dict, "lnum", lnum);
+ if (lnum == 0)
+ dict_add_string(dict, "pattern", cmd);
+ }
+
+ vim_snprintf((char *)IObuff, IOSIZE, "ltag %s", tag);
+ set_errorlist(curwin, list, ' ', IObuff, NULL);
+
+ list_free(list);
+ vim_free(fname);
+ vim_free(cmd);
+
+ cur_match = 0; /* Jump to the first tag */
+ }
+#endif
+
+ if (ask_for_selection == TRUE)
+ {
+ /*
+ * Ask to select a tag from the list.
+ */
+ i = prompt_for_number(NULL);
+ if (i <= 0 || i > num_matches || got_int)
+ {
+ /* no valid choice: don't change anything */
+ if (use_tagstack)
+ {
+ tagstack[tagstackidx].fmark = saved_fmark;
+ tagstackidx = prevtagstackidx;
+ }
+#ifdef FEAT_CSCOPE
+ cs_free_tags();
+ jumped_to_tag = TRUE;
+#endif
+ break;
+ }
+ cur_match = i - 1;
+ }
+
+ if (cur_match >= num_matches)
+ {
+ /* Avoid giving this error when a file wasn't found and we're
+ * looking for a match in another file, which wasn't found.
+ * There will be an emsg("file doesn't exist") below then. */
+ if ((type == DT_NEXT || type == DT_FIRST)
+ && nofile_fname == NULL)
+ {
+ if (num_matches == 1)
+ emsg(_("E427: There is only one matching tag"));
+ else
+ emsg(_("E428: Cannot go beyond last matching tag"));
+ skip_msg = TRUE;
+ }
+ cur_match = num_matches - 1;
+ }
+ if (use_tagstack)
+ {
+ tagstack[tagstackidx].cur_match = cur_match;
+ tagstack[tagstackidx].cur_fnum = cur_fnum;
+ ++tagstackidx;
+ }
+#if defined(FEAT_QUICKFIX)
+ else if (g_do_tagpreview != 0)
+ {
+ ptag_entry.cur_match = cur_match;
+ ptag_entry.cur_fnum = cur_fnum;
+ }
+#endif
+
+ /*
+ * Only when going to try the next match, report that the previous
+ * file didn't exist. Otherwise an emsg() is given below.
+ */
+ if (nofile_fname != NULL && error_cur_match != cur_match)
+ smsg(_("File \"%s\" does not exist"), nofile_fname);
+
+
+ ic = (matches[cur_match][0] & MT_IC_OFF);
+ if (type != DT_TAG && type != DT_SELECT && type != DT_JUMP
+#ifdef FEAT_CSCOPE
+ && type != DT_CSCOPE
+#endif
+ && (num_matches > 1 || ic)
+ && !skip_msg)
+ {
+ /* Give an indication of the number of matching tags */
+ sprintf((char *)IObuff, _("tag %d of %d%s"),
+ cur_match + 1,
+ num_matches,
+ max_num_matches != MAXCOL ? _(" or more") : "");
+ if (ic)
+ STRCAT(IObuff, _(" Using tag with different case!"));
+ if ((num_matches > prev_num_matches || new_tag)
+ && num_matches > 1)
+ {
+ if (ic)
+ msg_attr((char *)IObuff, HL_ATTR(HLF_W));
+ else
+ msg((char *)IObuff);
+ msg_scroll = TRUE; /* don't overwrite this message */
+ }
+ else
+ give_warning(IObuff, ic);
+ if (ic && !msg_scrolled && msg_silent == 0)
+ {
+ out_flush();
+ ui_delay(1000L, TRUE);
+ }
+ }
+
+#if defined(FEAT_EVAL)
+ /* Let the SwapExists event know what tag we are jumping to. */
+ vim_snprintf((char *)IObuff, IOSIZE, ":ta %s\r", name);
+ set_vim_var_string(VV_SWAPCOMMAND, IObuff, -1);
+#endif
+
+ /*
+ * Jump to the desired match.
+ */
+ i = jumpto_tag(matches[cur_match], forceit, type != DT_CSCOPE);
+
+#if defined(FEAT_EVAL)
+ set_vim_var_string(VV_SWAPCOMMAND, NULL, -1);
+#endif
+
+ if (i == NOTAGFILE)
+ {
+ /* File not found: try again with another matching tag */
+ if ((type == DT_PREV && cur_match > 0)
+ || ((type == DT_TAG || type == DT_NEXT
+ || type == DT_FIRST)
+ && (max_num_matches != MAXCOL
+ || cur_match < num_matches - 1)))
+ {
+ error_cur_match = cur_match;
+ if (use_tagstack)
+ --tagstackidx;
+ if (type == DT_PREV)
+ --cur_match;
+ else
+ {
+ type = DT_NEXT;
+ ++cur_match;
+ }
+ continue;
+ }
+ semsg(_("E429: File \"%s\" does not exist"), nofile_fname);
+ }
+ else
+ {
+ /* We may have jumped to another window, check that
+ * tagstackidx is still valid. */
+ if (use_tagstack && tagstackidx > curwin->w_tagstacklen)
+ tagstackidx = curwin->w_tagstackidx;
+#ifdef FEAT_CSCOPE
+ jumped_to_tag = TRUE;
+#endif
+ }
+ }
+ break;
+ }
+
+end_do_tag:
+ /* Only store the new index when using the tagstack and it's valid. */
+ if (use_tagstack && tagstackidx <= curwin->w_tagstacklen)
+ curwin->w_tagstackidx = tagstackidx;
+ postponed_split = 0; /* don't split next time */
+# ifdef FEAT_QUICKFIX
+ g_do_tagpreview = 0; /* don't do tag preview next time */
+# endif
+
+#ifdef FEAT_CSCOPE
+ return jumped_to_tag;
+#else
+ return FALSE;
+#endif
+}
+
+/*
+ * Free cached tags.
+ */
+ void
+tag_freematch(void)
+{
+ VIM_CLEAR(tagmatchname);
+}
+
+ static void
+taglen_advance(int l)
+{
+ if (l == MAXCOL)
+ {
+ msg_putchar('\n');
+ msg_advance(24);
+ }
+ else
+ msg_advance(13 + l);
+}
+
+/*
+ * Print the tag stack
+ */
+ void
+do_tags(exarg_T *eap UNUSED)
+{
+ int i;
+ char_u *name;
+ taggy_T *tagstack = curwin->w_tagstack;
+ int tagstackidx = curwin->w_tagstackidx;
+ int tagstacklen = curwin->w_tagstacklen;
+
+ /* Highlight title */
+ msg_puts_title(_("\n # TO tag FROM line in file/text"));
+ for (i = 0; i < tagstacklen; ++i)
+ {
+ if (tagstack[i].tagname != NULL)
+ {
+ name = fm_getname(&(tagstack[i].fmark), 30);
+ if (name == NULL) /* file name not available */
+ continue;
+
+ msg_putchar('\n');
+ vim_snprintf((char *)IObuff, IOSIZE, "%c%2d %2d %-15s %5ld ",
+ i == tagstackidx ? '>' : ' ',
+ i + 1,
+ tagstack[i].cur_match + 1,
+ tagstack[i].tagname,
+ tagstack[i].fmark.mark.lnum);
+ msg_outtrans(IObuff);
+ msg_outtrans_attr(name, tagstack[i].fmark.fnum == curbuf->b_fnum
+ ? HL_ATTR(HLF_D) : 0);
+ vim_free(name);
+ }
+ out_flush(); /* show one line at a time */
+ }
+ if (tagstackidx == tagstacklen) /* idx at top of stack */
+ msg_puts("\n>");
+}
+
+/* When not using a CR for line separator, use vim_fgets() to read tag lines.
+ * For the Mac use tag_fgets(). It can handle any line separator, but is much
+ * slower than vim_fgets().
+ */
+#ifndef USE_CR
+# define tag_fgets vim_fgets
+#endif
+
+#ifdef FEAT_TAG_BINS
+/*
+ * Compare two strings, for length "len", ignoring case the ASCII way.
+ * return 0 for match, < 0 for smaller, > 0 for bigger
+ * Make sure case is folded to uppercase in comparison (like for 'sort -f')
+ */
+ static int
+tag_strnicmp(char_u *s1, char_u *s2, size_t len)
+{
+ int i;
+
+ while (len > 0)
+ {
+ i = (int)TOUPPER_ASC(*s1) - (int)TOUPPER_ASC(*s2);
+ if (i != 0)
+ return i; /* this character different */
+ if (*s1 == NUL)
+ break; /* strings match until NUL */
+ ++s1;
+ ++s2;
+ --len;
+ }
+ return 0; /* strings match */
+}
+#endif
+
+/*
+ * Structure to hold info about the tag pattern being used.
+ */
+typedef struct
+{
+ char_u *pat; /* the pattern */
+ int len; /* length of pat[] */
+ char_u *head; /* start of pattern head */
+ int headlen; /* length of head[] */
+ regmatch_T regmatch; /* regexp program, may be NULL */
+} pat_T;
+
+/*
+ * Extract info from the tag search pattern "pats->pat".
+ */
+ static void
+prepare_pats(pat_T *pats, int has_re)
+{
+ pats->head = pats->pat;
+ pats->headlen = pats->len;
+ if (has_re)
+ {
+ /* When the pattern starts with '^' or "\\<", binary searching can be
+ * used (much faster). */
+ if (pats->pat[0] == '^')
+ pats->head = pats->pat + 1;
+ else if (pats->pat[0] == '\\' && pats->pat[1] == '<')
+ pats->head = pats->pat + 2;
+ if (pats->head == pats->pat)
+ pats->headlen = 0;
+ else
+ for (pats->headlen = 0; pats->head[pats->headlen] != NUL;
+ ++pats->headlen)
+ if (vim_strchr((char_u *)(p_magic ? ".[~*\\$" : "\\$"),
+ pats->head[pats->headlen]) != NULL)
+ break;
+ if (p_tl != 0 && pats->headlen > p_tl) /* adjust for 'taglength' */
+ pats->headlen = p_tl;
+ }
+
+ if (has_re)
+ pats->regmatch.regprog = vim_regcomp(pats->pat, p_magic ? RE_MAGIC : 0);
+ else
+ pats->regmatch.regprog = NULL;
+}
+
+/*
+ * find_tags() - search for tags in tags files
+ *
+ * Return FAIL if search completely failed (*num_matches will be 0, *matchesp
+ * will be NULL), OK otherwise.
+ *
+ * There is a priority in which type of tag is recognized.
+ *
+ * 6. A static or global tag with a full matching tag for the current file.
+ * 5. A global tag with a full matching tag for another file.
+ * 4. A static tag with a full matching tag for another file.
+ * 3. A static or global tag with an ignore-case matching tag for the
+ * current file.
+ * 2. A global tag with an ignore-case matching tag for another file.
+ * 1. A static tag with an ignore-case matching tag for another file.
+ *
+ * Tags in an emacs-style tags file are always global.
+ *
+ * flags:
+ * TAG_HELP only search for help tags
+ * TAG_NAMES only return name of tag
+ * TAG_REGEXP use "pat" as a regexp
+ * TAG_NOIC don't always ignore case
+ * TAG_KEEP_LANG keep language
+ * TAG_CSCOPE use cscope results for tags
+ */
+ int
+find_tags(
+ char_u *pat, /* pattern to search for */
+ int *num_matches, /* return: number of matches found */
+ char_u ***matchesp, /* return: array of matches found */
+ int flags,
+ int mincount, /* MAXCOL: find all matches
+ other: minimal number of matches */
+ char_u *buf_ffname) /* name of buffer for priority */
+{
+ FILE *fp;
+ char_u *lbuf; /* line buffer */
+ int lbuf_size = LSIZE; /* length of lbuf */
+ char_u *tag_fname; /* name of tag file */
+ tagname_T tn; /* info for get_tagfname() */
+ int first_file; /* trying first tag file */
+ tagptrs_T tagp;
+ int did_open = FALSE; /* did open a tag file */
+ int stop_searching = FALSE; /* stop when match found or error */
+ int retval = FAIL; /* return value */
+ int is_static; /* current tag line is static */
+ int is_current; /* file name matches */
+ int eof = FALSE; /* found end-of-file */
+ char_u *p;
+ char_u *s;
+ int i;
+#ifdef FEAT_TAG_BINS
+ int tag_file_sorted = NUL; /* !_TAG_FILE_SORTED value */
+ struct tag_search_info /* Binary search file offsets */
+ {
+ off_T low_offset; /* offset for first char of first line that
+ could match */
+ off_T high_offset; /* offset of char after last line that could
+ match */
+ off_T curr_offset; /* Current file offset in search range */
+ off_T curr_offset_used; /* curr_offset used when skipping back */
+ off_T match_offset; /* Where the binary search found a tag */
+ int low_char; /* first char at low_offset */
+ int high_char; /* first char at high_offset */
+ } search_info;
+ off_T filesize;
+ int tagcmp;
+ off_T offset;
+ int round;
+#endif
+ enum
+ {
+ TS_START, /* at start of file */
+ TS_LINEAR /* linear searching forward, till EOF */
+#ifdef FEAT_TAG_BINS
+ , TS_BINARY, /* binary searching */
+ TS_SKIP_BACK, /* skipping backwards */
+ TS_STEP_FORWARD /* stepping forwards */
+#endif
+ } state; /* Current search state */
+
+ int cmplen;
+ int match; /* matches */
+ int match_no_ic = 0;/* matches with rm_ic == FALSE */
+ int match_re; /* match with regexp */
+ int matchoff = 0;
+ int save_emsg_off;
+
+#ifdef FEAT_EMACS_TAGS
+ /*
+ * Stack for included emacs-tags file.
+ * It has a fixed size, to truncate cyclic includes. jw
+ */
+# define INCSTACK_SIZE 42
+ struct
+ {
+ FILE *fp;
+ char_u *etag_fname;
+ } incstack[INCSTACK_SIZE];
+
+ int incstack_idx = 0; /* index in incstack */
+ char_u *ebuf; /* additional buffer for etag fname */
+ int is_etag; /* current file is emaces style */
+#endif
+
+ char_u *mfp;
+ garray_T ga_match[MT_COUNT]; /* stores matches in sequence */
+ hashtab_T ht_match[MT_COUNT]; /* stores matches by key */
+ hash_T hash = 0;
+ int match_count = 0; /* number of matches found */
+ char_u **matches;
+ int mtt;
+ int help_save;
+#ifdef FEAT_MULTI_LANG
+ int help_pri = 0;
+ char_u *help_lang_find = NULL; /* lang to be found */
+ char_u help_lang[3]; /* lang of current tags file */
+ char_u *saved_pat = NULL; /* copy of pat[] */
+ int is_txt = FALSE; /* flag of file extension */
+#endif
+
+ pat_T orgpat; /* holds unconverted pattern info */
+ vimconv_T vimconv;
+
+#ifdef FEAT_TAG_BINS
+ int findall = (mincount == MAXCOL || mincount == TAG_MANY);
+ /* find all matching tags */
+ int sort_error = FALSE; /* tags file not sorted */
+ int linear; /* do a linear search */
+ int sortic = FALSE; /* tag file sorted in nocase */
+#endif
+ int line_error = FALSE; /* syntax error */
+ int has_re = (flags & TAG_REGEXP); /* regexp used */
+ int help_only = (flags & TAG_HELP);
+ int name_only = (flags & TAG_NAMES);
+ int noic = (flags & TAG_NOIC);
+ int get_it_again = FALSE;
+#ifdef FEAT_CSCOPE
+ int use_cscope = (flags & TAG_CSCOPE);
+#endif
+ int verbose = (flags & TAG_VERBOSE);
+ int save_p_ic = p_ic;
+
+ /*
+ * Change the value of 'ignorecase' according to 'tagcase' for the
+ * duration of this function.
+ */
+ switch (curbuf->b_tc_flags ? curbuf->b_tc_flags : tc_flags)
+ {
+ case TC_FOLLOWIC: break;
+ case TC_IGNORE: p_ic = TRUE; break;
+ case TC_MATCH: p_ic = FALSE; break;
+ case TC_FOLLOWSCS: p_ic = ignorecase(pat); break;
+ case TC_SMART: p_ic = ignorecase_opt(pat, TRUE, TRUE); break;
+ }
+
+ help_save = curbuf->b_help;
+ orgpat.pat = pat;
+ vimconv.vc_type = CONV_NONE;
+
+ /*
+ * Allocate memory for the buffers that are used
+ */
+ lbuf = alloc(lbuf_size);
+ tag_fname = alloc(MAXPATHL + 1);
+#ifdef FEAT_EMACS_TAGS
+ ebuf = alloc(LSIZE);
+#endif
+ for (mtt = 0; mtt < MT_COUNT; ++mtt)
+ {
+ ga_init2(&ga_match[mtt], (int)sizeof(char_u *), 100);
+ hash_init(&ht_match[mtt]);
+ }
+
+ /* check for out of memory situation */
+ if (lbuf == NULL || tag_fname == NULL
+#ifdef FEAT_EMACS_TAGS
+ || ebuf == NULL
+#endif
+ )
+ goto findtag_end;
+
+#ifdef FEAT_CSCOPE
+ STRCPY(tag_fname, "from cscope"); /* for error messages */
+#endif
+
+ /*
+ * Initialize a few variables
+ */
+ if (help_only) /* want tags from help file */
+ curbuf->b_help = TRUE; /* will be restored later */
+#ifdef FEAT_CSCOPE
+ else if (use_cscope)
+ {
+ /* Make sure we don't mix help and cscope, confuses Coverity. */
+ help_only = FALSE;
+ curbuf->b_help = FALSE;
+ }
+#endif
+
+ orgpat.len = (int)STRLEN(pat);
+#ifdef FEAT_MULTI_LANG
+ if (curbuf->b_help)
+ {
+ /* When "@ab" is specified use only the "ab" language, otherwise
+ * search all languages. */
+ if (orgpat.len > 3 && pat[orgpat.len - 3] == '@'
+ && ASCII_ISALPHA(pat[orgpat.len - 2])
+ && ASCII_ISALPHA(pat[orgpat.len - 1]))
+ {
+ saved_pat = vim_strnsave(pat, orgpat.len - 3);
+ if (saved_pat != NULL)
+ {
+ help_lang_find = &pat[orgpat.len - 2];
+ orgpat.pat = saved_pat;
+ orgpat.len -= 3;
+ }
+ }
+ }
+#endif
+ if (p_tl != 0 && orgpat.len > p_tl) /* adjust for 'taglength' */
+ orgpat.len = p_tl;
+
+ save_emsg_off = emsg_off;
+ emsg_off = TRUE; /* don't want error for invalid RE here */
+ prepare_pats(&orgpat, has_re);
+ emsg_off = save_emsg_off;
+ if (has_re && orgpat.regmatch.regprog == NULL)
+ goto findtag_end;
+
+#ifdef FEAT_TAG_BINS
+ /* This is only to avoid a compiler warning for using search_info
+ * uninitialised. */
+ vim_memset(&search_info, 0, (size_t)1);
+#endif
+
+ /*
+ * When finding a specified number of matches, first try with matching
+ * case, so binary search can be used, and try ignore-case matches in a
+ * second loop.
+ * When finding all matches, 'tagbsearch' is off, or there is no fixed
+ * string to look for, ignore case right away to avoid going though the
+ * tags files twice.
+ * When the tag file is case-fold sorted, it is either one or the other.
+ * Only ignore case when TAG_NOIC not used or 'ignorecase' set.
+ */
+#ifdef FEAT_MULTI_LANG
+ /* Set a flag if the file extension is .txt */
+ if ((flags & TAG_KEEP_LANG)
+ && help_lang_find == NULL
+ && curbuf->b_fname != NULL
+ && (i = (int)STRLEN(curbuf->b_fname)) > 4
+ && STRICMP(curbuf->b_fname + i - 4, ".txt") == 0)
+ is_txt = TRUE;
+#endif
+#ifdef FEAT_TAG_BINS
+ orgpat.regmatch.rm_ic = ((p_ic || !noic)
+ && (findall || orgpat.headlen == 0 || !p_tbs));
+ for (round = 1; round <= 2; ++round)
+ {
+ linear = (orgpat.headlen == 0 || !p_tbs || round == 2);
+#else
+ orgpat.regmatch.rm_ic = (p_ic || !noic);
+#endif
+
+ /*
+ * Try tag file names from tags option one by one.
+ */
+ for (first_file = TRUE;
+#ifdef FEAT_CSCOPE
+ use_cscope ||
+#endif
+ get_tagfname(&tn, first_file, tag_fname) == OK;
+ first_file = FALSE)
+ {
+ /*
+ * A file that doesn't exist is silently ignored. Only when not a
+ * single file is found, an error message is given (further on).
+ */
+#ifdef FEAT_CSCOPE
+ if (use_cscope)
+ fp = NULL; /* avoid GCC warning */
+ else
+#endif
+ {
+#ifdef FEAT_MULTI_LANG
+ if (curbuf->b_help)
+ {
+ /* Keep en if the file extension is .txt*/
+ if (is_txt)
+ STRCPY(help_lang, "en");
+ else
+ {
+ /* Prefer help tags according to 'helplang'. Put the
+ * two-letter language name in help_lang[]. */
+ i = (int)STRLEN(tag_fname);
+ if (i > 3 && tag_fname[i - 3] == '-')
+ STRCPY(help_lang, tag_fname + i - 2);
+ else
+ STRCPY(help_lang, "en");
+ }
+ /* When searching for a specific language skip tags files
+ * for other languages. */
+ if (help_lang_find != NULL
+ && STRICMP(help_lang, help_lang_find) != 0)
+ continue;
+
+ /* For CTRL-] in a help file prefer a match with the same
+ * language. */
+ if ((flags & TAG_KEEP_LANG)
+ && help_lang_find == NULL
+ && curbuf->b_fname != NULL
+ && (i = (int)STRLEN(curbuf->b_fname)) > 4
+ && curbuf->b_fname[i - 1] == 'x'
+ && curbuf->b_fname[i - 4] == '.'
+ && STRNICMP(curbuf->b_fname + i - 3, help_lang, 2) == 0)
+ help_pri = 0;
+ else
+ {
+ help_pri = 1;
+ for (s = p_hlg; *s != NUL; ++s)
+ {
+ if (STRNICMP(s, help_lang, 2) == 0)
+ break;
+ ++help_pri;
+ if ((s = vim_strchr(s, ',')) == NULL)
+ break;
+ }
+ if (s == NULL || *s == NUL)
+ {
+ /* Language not in 'helplang': use last, prefer English,
+ * unless found already. */
+ ++help_pri;
+ if (STRICMP(help_lang, "en") != 0)
+ ++help_pri;
+ }
+ }
+ }
+#endif
+
+ if ((fp = mch_fopen((char *)tag_fname, "r")) == NULL)
+ continue;
+
+ if (p_verbose >= 5)
+ {
+ verbose_enter();
+ smsg(_("Searching tags file %s"), tag_fname);
+ verbose_leave();
+ }
+ }
+ did_open = TRUE; /* remember that we found at least one file */
+
+ state = TS_START; /* we're at the start of the file */
+#ifdef FEAT_EMACS_TAGS
+ is_etag = 0; /* default is: not emacs style */
+#endif
+
+ /*
+ * Read and parse the lines in the file one by one
+ */
+ for (;;)
+ {
+#ifdef FEAT_TAG_BINS
+ /* check for CTRL-C typed, more often when jumping around */
+ if (state == TS_BINARY || state == TS_SKIP_BACK)
+ line_breakcheck();
+ else
+#endif
+ fast_breakcheck();
+#ifdef FEAT_INS_EXPAND
+ if ((flags & TAG_INS_COMP)) /* Double brackets for gcc */
+ ins_compl_check_keys(30, FALSE);
+ if (got_int || compl_interrupted)
+#else
+ if (got_int)
+#endif
+ {
+ stop_searching = TRUE;
+ break;
+ }
+ /* When mincount is TAG_MANY, stop when enough matches have been
+ * found (for completion). */
+ if (mincount == TAG_MANY && match_count >= TAG_MANY)
+ {
+ stop_searching = TRUE;
+ retval = OK;
+ break;
+ }
+ if (get_it_again)
+ goto line_read_in;
+#ifdef FEAT_TAG_BINS
+ /*
+ * For binary search: compute the next offset to use.
+ */
+ if (state == TS_BINARY)
+ {
+ offset = search_info.low_offset + ((search_info.high_offset
+ - search_info.low_offset) / 2);
+ if (offset == search_info.curr_offset)
+ break; /* End the binary search without a match. */
+ else
+ search_info.curr_offset = offset;
+ }
+
+ /*
+ * Skipping back (after a match during binary search).
+ */
+ else if (state == TS_SKIP_BACK)
+ {
+ search_info.curr_offset -= LSIZE * 2;
+ if (search_info.curr_offset < 0)
+ {
+ search_info.curr_offset = 0;
+ rewind(fp);
+ state = TS_STEP_FORWARD;
+ }
+ }
+
+ /*
+ * When jumping around in the file, first read a line to find the
+ * start of the next line.
+ */
+ if (state == TS_BINARY || state == TS_SKIP_BACK)
+ {
+ /* Adjust the search file offset to the correct position */
+ search_info.curr_offset_used = search_info.curr_offset;
+ vim_fseek(fp, search_info.curr_offset, SEEK_SET);
+ eof = tag_fgets(lbuf, LSIZE, fp);
+ if (!eof && search_info.curr_offset != 0)
+ {
+ /* The explicit cast is to work around a bug in gcc 3.4.2
+ * (repeated below). */
+ search_info.curr_offset = vim_ftell(fp);
+ if (search_info.curr_offset == search_info.high_offset)
+ {
+ /* oops, gone a bit too far; try from low offset */
+ vim_fseek(fp, search_info.low_offset, SEEK_SET);
+ search_info.curr_offset = search_info.low_offset;
+ }
+ eof = tag_fgets(lbuf, LSIZE, fp);
+ }
+ /* skip empty and blank lines */
+ while (!eof && vim_isblankline(lbuf))
+ {
+ search_info.curr_offset = vim_ftell(fp);
+ eof = tag_fgets(lbuf, LSIZE, fp);
+ }
+ if (eof)
+ {
+ /* Hit end of file. Skip backwards. */
+ state = TS_SKIP_BACK;
+ search_info.match_offset = vim_ftell(fp);
+ search_info.curr_offset = search_info.curr_offset_used;
+ continue;
+ }
+ }
+
+ /*
+ * Not jumping around in the file: Read the next line.
+ */
+ else
+#endif
+ {
+ /* skip empty and blank lines */
+ do
+ {
+#ifdef FEAT_CSCOPE
+ if (use_cscope)
+ eof = cs_fgets(lbuf, LSIZE);
+ else
+#endif
+ eof = tag_fgets(lbuf, LSIZE, fp);
+ } while (!eof && vim_isblankline(lbuf));
+
+ if (eof)
+ {
+#ifdef FEAT_EMACS_TAGS
+ if (incstack_idx) /* this was an included file */
+ {
+ --incstack_idx;
+ fclose(fp); /* end of this file ... */
+ fp = incstack[incstack_idx].fp;
+ STRCPY(tag_fname, incstack[incstack_idx].etag_fname);
+ vim_free(incstack[incstack_idx].etag_fname);
+ is_etag = 1; /* (only etags can include) */
+ continue; /* ... continue with parent file */
+ }
+ else
+#endif
+ break; /* end of file */
+ }
+ }
+line_read_in:
+
+ if (vimconv.vc_type != CONV_NONE)
+ {
+ char_u *conv_line;
+ int len;
+
+ /* Convert every line. Converting the pattern from 'enc' to
+ * the tags file encoding doesn't work, because characters are
+ * not recognized. */
+ conv_line = string_convert(&vimconv, lbuf, NULL);
+ if (conv_line != NULL)
+ {
+ /* Copy or swap lbuf and conv_line. */
+ len = (int)STRLEN(conv_line) + 1;
+ if (len > lbuf_size)
+ {
+ vim_free(lbuf);
+ lbuf = conv_line;
+ lbuf_size = len;
+ }
+ else
+ {
+ STRCPY(lbuf, conv_line);
+ vim_free(conv_line);
+ }
+ }
+ }
+
+
+#ifdef FEAT_EMACS_TAGS
+ /*
+ * Emacs tags line with CTRL-L: New file name on next line.
+ * The file name is followed by a ','.
+ * Remember etag file name in ebuf.
+ */
+ if (*lbuf == Ctrl_L
+# ifdef FEAT_CSCOPE
+ && !use_cscope
+# endif
+ )
+ {
+ is_etag = 1; /* in case at the start */
+ state = TS_LINEAR;
+ if (!tag_fgets(ebuf, LSIZE, fp))
+ {
+ for (p = ebuf; *p && *p != ','; p++)
+ ;
+ *p = NUL;
+
+ /*
+ * atoi(p+1) is the number of bytes before the next ^L
+ * unless it is an include statement.
+ */
+ if (STRNCMP(p + 1, "include", 7) == 0
+ && incstack_idx < INCSTACK_SIZE)
+ {
+ /* Save current "fp" and "tag_fname" in the stack. */
+ if ((incstack[incstack_idx].etag_fname =
+ vim_strsave(tag_fname)) != NULL)
+ {
+ char_u *fullpath_ebuf;
+
+ incstack[incstack_idx].fp = fp;
+ fp = NULL;
+
+ /* Figure out "tag_fname" and "fp" to use for
+ * included file. */
+ fullpath_ebuf = expand_tag_fname(ebuf,
+ tag_fname, FALSE);
+ if (fullpath_ebuf != NULL)
+ {
+ fp = mch_fopen((char *)fullpath_ebuf, "r");
+ if (fp != NULL)
+ {
+ if (STRLEN(fullpath_ebuf) > LSIZE)
+ semsg(_("E430: Tag file path truncated for %s\n"), ebuf);
+ vim_strncpy(tag_fname, fullpath_ebuf,
+ MAXPATHL);
+ ++incstack_idx;
+ is_etag = 0; /* we can include anything */
+ }
+ vim_free(fullpath_ebuf);
+ }
+ if (fp == NULL)
+ {
+ /* Can't open the included file, skip it and
+ * restore old value of "fp". */
+ fp = incstack[incstack_idx].fp;
+ vim_free(incstack[incstack_idx].etag_fname);
+ }
+ }
+ }
+ }
+ continue;
+ }
+#endif
+
+ /*
+ * When still at the start of the file, check for Emacs tags file
+ * format, and for "not sorted" flag.
+ */
+ if (state == TS_START)
+ {
+ /* The header ends when the line sorts below "!_TAG_". When
+ * case is folded lower case letters sort before "_". */
+ if (STRNCMP(lbuf, "!_TAG_", 6) <= 0
+ || (lbuf[0] == '!' && ASCII_ISLOWER(lbuf[1])))
+ {
+ if (STRNCMP(lbuf, "!_TAG_", 6) != 0)
+ /* Non-header item before the header, e.g. "!" itself.
+ */
+ goto parse_line;
+
+ /*
+ * Read header line.
+ */
+#ifdef FEAT_TAG_BINS
+ if (STRNCMP(lbuf, "!_TAG_FILE_SORTED\t", 18) == 0)
+ tag_file_sorted = lbuf[18];
+#endif
+ if (STRNCMP(lbuf, "!_TAG_FILE_ENCODING\t", 20) == 0)
+ {
+ /* Prepare to convert every line from the specified
+ * encoding to 'encoding'. */
+ for (p = lbuf + 20; *p > ' ' && *p < 127; ++p)
+ ;
+ *p = NUL;
+ convert_setup(&vimconv, lbuf + 20, p_enc);
+ }
+
+ /* Read the next line. Unrecognized flags are ignored. */
+ continue;
+ }
+
+ /* Headers ends. */
+
+#ifdef FEAT_TAG_BINS
+ /*
+ * When there is no tag head, or ignoring case, need to do a
+ * linear search.
+ * When no "!_TAG_" is found, default to binary search. If
+ * the tag file isn't sorted, the second loop will find it.
+ * When "!_TAG_FILE_SORTED" found: start binary search if
+ * flag set.
+ * For cscope, it's always linear.
+ */
+# ifdef FEAT_CSCOPE
+ if (linear || use_cscope)
+# else
+ if (linear)
+# endif
+ state = TS_LINEAR;
+ else if (tag_file_sorted == NUL)
+ state = TS_BINARY;
+ else if (tag_file_sorted == '1')
+ state = TS_BINARY;
+ else if (tag_file_sorted == '2')
+ {
+ state = TS_BINARY;
+ sortic = TRUE;
+ orgpat.regmatch.rm_ic = (p_ic || !noic);
+ }
+ else
+ state = TS_LINEAR;
+
+ if (state == TS_BINARY && orgpat.regmatch.rm_ic && !sortic)
+ {
+ /* Binary search won't work for ignoring case, use linear
+ * search. */
+ linear = TRUE;
+ state = TS_LINEAR;
+ }
+#else
+ state = TS_LINEAR;
+#endif
+
+#ifdef FEAT_TAG_BINS
+ /*
+ * When starting a binary search, get the size of the file and
+ * compute the first offset.
+ */
+ if (state == TS_BINARY)
+ {
+ /* Get the tag file size (don't use mch_fstat(), it's not
+ * portable). */
+ if ((filesize = vim_lseek(fileno(fp),
+ (off_T)0L, SEEK_END)) <= 0)
+ state = TS_LINEAR;
+ else
+ {
+ vim_lseek(fileno(fp), (off_T)0L, SEEK_SET);
+
+ /* Calculate the first read offset in the file. Start
+ * the search in the middle of the file. */
+ search_info.low_offset = 0;
+ search_info.low_char = 0;
+ search_info.high_offset = filesize;
+ search_info.curr_offset = 0;
+ search_info.high_char = 0xff;
+ }
+ continue;
+ }
+#endif
+ }
+
+parse_line:
+ /*
+ * Figure out where the different strings are in this line.
+ * For "normal" tags: Do a quick check if the tag matches.
+ * This speeds up tag searching a lot!
+ */
+ if (orgpat.headlen
+#ifdef FEAT_EMACS_TAGS
+ && !is_etag
+#endif
+ )
+ {
+ vim_memset(&tagp, 0, sizeof(tagp));
+ tagp.tagname = lbuf;
+#ifdef FEAT_TAG_ANYWHITE
+ tagp.tagname_end = skiptowhite(lbuf);
+ if (*tagp.tagname_end == NUL)
+#else
+ tagp.tagname_end = vim_strchr(lbuf, TAB);
+ if (tagp.tagname_end == NULL)
+#endif
+ {
+ if (vim_strchr(lbuf, NL) == NULL)
+ {
+ /* Truncated line, ignore it. Has been reported for
+ * Mozilla JS with extremely long names. */
+ if (p_verbose >= 5)
+ {
+ verbose_enter();
+ msg(_("Ignoring long line in tags file"));
+ verbose_leave();
+ }
+#ifdef FEAT_TAG_BINS
+ if (state != TS_LINEAR)
+ {
+ /* Avoid getting stuck. */
+ linear = TRUE;
+ state = TS_LINEAR;
+ vim_fseek(fp, search_info.low_offset, SEEK_SET);
+ }
+#endif
+ continue;
+ }
+
+ /* Corrupted tag line. */
+ line_error = TRUE;
+ break;
+ }
+
+#ifdef FEAT_TAG_OLDSTATIC
+ /*
+ * Check for old style static tag: "file:tag file .."
+ */
+ tagp.fname = NULL;
+ for (p = lbuf; p < tagp.tagname_end; ++p)
+ {
+ if (*p == ':')
+ {
+ if (tagp.fname == NULL)
+# ifdef FEAT_TAG_ANYWHITE
+ tagp.fname = skipwhite(tagp.tagname_end);
+# else
+ tagp.fname = tagp.tagname_end + 1;
+# endif
+ if ( fnamencmp(lbuf, tagp.fname, p - lbuf) == 0
+# ifdef FEAT_TAG_ANYWHITE
+ && VIM_ISWHITE(tagp.fname[p - lbuf])
+# else
+ && tagp.fname[p - lbuf] == TAB
+# endif
+ )
+ {
+ /* found one */
+ tagp.tagname = p + 1;
+ break;
+ }
+ }
+ }
+#endif
+
+ /*
+ * Skip this line if the length of the tag is different and
+ * there is no regexp, or the tag is too short.
+ */
+ cmplen = (int)(tagp.tagname_end - tagp.tagname);
+ if (p_tl != 0 && cmplen > p_tl) /* adjust for 'taglength' */
+ cmplen = p_tl;
+ if (has_re && orgpat.headlen < cmplen)
+ cmplen = orgpat.headlen;
+ else if (state == TS_LINEAR && orgpat.headlen != cmplen)
+ continue;
+
+#ifdef FEAT_TAG_BINS
+ if (state == TS_BINARY)
+ {
+ /*
+ * Simplistic check for unsorted tags file.
+ */
+ i = (int)tagp.tagname[0];
+ if (sortic)
+ i = (int)TOUPPER_ASC(tagp.tagname[0]);
+ if (i < search_info.low_char || i > search_info.high_char)
+ sort_error = TRUE;
+
+ /*
+ * Compare the current tag with the searched tag.
+ */
+ if (sortic)
+ tagcmp = tag_strnicmp(tagp.tagname, orgpat.head,
+ (size_t)cmplen);
+ else
+ tagcmp = STRNCMP(tagp.tagname, orgpat.head, cmplen);
+
+ /*
+ * A match with a shorter tag means to search forward.
+ * A match with a longer tag means to search backward.
+ */
+ if (tagcmp == 0)
+ {
+ if (cmplen < orgpat.headlen)
+ tagcmp = -1;
+ else if (cmplen > orgpat.headlen)
+ tagcmp = 1;
+ }
+
+ if (tagcmp == 0)
+ {
+ /* We've located the tag, now skip back and search
+ * forward until the first matching tag is found.
+ */
+ state = TS_SKIP_BACK;
+ search_info.match_offset = search_info.curr_offset;
+ continue;
+ }
+ if (tagcmp < 0)
+ {
+ search_info.curr_offset = vim_ftell(fp);
+ if (search_info.curr_offset < search_info.high_offset)
+ {
+ search_info.low_offset = search_info.curr_offset;
+ if (sortic)
+ search_info.low_char =
+ TOUPPER_ASC(tagp.tagname[0]);
+ else
+ search_info.low_char = tagp.tagname[0];
+ continue;
+ }
+ }
+ if (tagcmp > 0
+ && search_info.curr_offset != search_info.high_offset)
+ {
+ search_info.high_offset = search_info.curr_offset;
+ if (sortic)
+ search_info.high_char =
+ TOUPPER_ASC(tagp.tagname[0]);
+ else
+ search_info.high_char = tagp.tagname[0];
+ continue;
+ }
+
+ /* No match yet and are at the end of the binary search. */
+ break;
+ }
+ else if (state == TS_SKIP_BACK)
+ {
+ if (MB_STRNICMP(tagp.tagname, orgpat.head, cmplen) != 0)
+ state = TS_STEP_FORWARD;
+ else
+ /* Have to skip back more. Restore the curr_offset
+ * used, otherwise we get stuck at a long line. */
+ search_info.curr_offset = search_info.curr_offset_used;
+ continue;
+ }
+ else if (state == TS_STEP_FORWARD)
+ {
+ if (MB_STRNICMP(tagp.tagname, orgpat.head, cmplen) != 0)
+ {
+ if ((off_T)vim_ftell(fp) > search_info.match_offset)
+ break; /* past last match */
+ else
+ continue; /* before first match */
+ }
+ }
+ else
+#endif
+ /* skip this match if it can't match */
+ if (MB_STRNICMP(tagp.tagname, orgpat.head, cmplen) != 0)
+ continue;
+
+ /*
+ * Can be a matching tag, isolate the file name and command.
+ */
+#ifdef FEAT_TAG_OLDSTATIC
+ if (tagp.fname == NULL)
+#endif
+#ifdef FEAT_TAG_ANYWHITE
+ tagp.fname = skipwhite(tagp.tagname_end);
+#else
+ tagp.fname = tagp.tagname_end + 1;
+#endif
+#ifdef FEAT_TAG_ANYWHITE
+ tagp.fname_end = skiptowhite(tagp.fname);
+ tagp.command = skipwhite(tagp.fname_end);
+ if (*tagp.command == NUL)
+#else
+ tagp.fname_end = vim_strchr(tagp.fname, TAB);
+ tagp.command = tagp.fname_end + 1;
+ if (tagp.fname_end == NULL)
+#endif
+ i = FAIL;
+ else
+ i = OK;
+ }
+ else
+ i = parse_tag_line(lbuf,
+#ifdef FEAT_EMACS_TAGS
+ is_etag,
+#endif
+ &tagp);
+ if (i == FAIL)
+ {
+ line_error = TRUE;
+ break;
+ }
+
+#ifdef FEAT_EMACS_TAGS
+ if (is_etag)
+ tagp.fname = ebuf;
+#endif
+ /*
+ * First try matching with the pattern literally (also when it is
+ * a regexp).
+ */
+ cmplen = (int)(tagp.tagname_end - tagp.tagname);
+ if (p_tl != 0 && cmplen > p_tl) /* adjust for 'taglength' */
+ cmplen = p_tl;
+ /* if tag length does not match, don't try comparing */
+ if (orgpat.len != cmplen)
+ match = FALSE;
+ else
+ {
+ if (orgpat.regmatch.rm_ic)
+ {
+ match = (MB_STRNICMP(tagp.tagname, orgpat.pat, cmplen) == 0);
+ if (match)
+ match_no_ic = (STRNCMP(tagp.tagname, orgpat.pat,
+ cmplen) == 0);
+ }
+ else
+ match = (STRNCMP(tagp.tagname, orgpat.pat, cmplen) == 0);
+ }
+
+ /*
+ * Has a regexp: Also find tags matching regexp.
+ */
+ match_re = FALSE;
+ if (!match && orgpat.regmatch.regprog != NULL)
+ {
+ int cc;
+
+ cc = *tagp.tagname_end;
+ *tagp.tagname_end = NUL;
+ match = vim_regexec(&orgpat.regmatch, tagp.tagname, (colnr_T)0);
+ if (match)
+ {
+ matchoff = (int)(orgpat.regmatch.startp[0] - tagp.tagname);
+ if (orgpat.regmatch.rm_ic)
+ {
+ orgpat.regmatch.rm_ic = FALSE;
+ match_no_ic = vim_regexec(&orgpat.regmatch, tagp.tagname,
+ (colnr_T)0);
+ orgpat.regmatch.rm_ic = TRUE;
+ }
+ }
+ *tagp.tagname_end = cc;
+ match_re = TRUE;
+ }
+
+ /*
+ * If a match is found, add it to ht_match[] and ga_match[].
+ */
+ if (match)
+ {
+ int len = 0;
+
+#ifdef FEAT_CSCOPE
+ if (use_cscope)
+ {
+ /* Don't change the ordering, always use the same table. */
+ mtt = MT_GL_OTH;
+ }
+ else
+#endif
+ {
+ /* Decide in which array to store this match. */
+ is_current = test_for_current(
+#ifdef FEAT_EMACS_TAGS
+ is_etag,
+#endif
+ tagp.fname, tagp.fname_end, tag_fname,
+ buf_ffname);
+#ifdef FEAT_EMACS_TAGS
+ is_static = FALSE;
+ if (!is_etag) /* emacs tags are never static */
+#endif
+ {
+#ifdef FEAT_TAG_OLDSTATIC
+ if (tagp.tagname != lbuf)
+ is_static = TRUE; /* detected static tag before */
+ else
+#endif
+ is_static = test_for_static(&tagp);
+ }
+
+ /* decide in which of the sixteen tables to store this
+ * match */
+ if (is_static)
+ {
+ if (is_current)
+ mtt = MT_ST_CUR;
+ else
+ mtt = MT_ST_OTH;
+ }
+ else
+ {
+ if (is_current)
+ mtt = MT_GL_CUR;
+ else
+ mtt = MT_GL_OTH;
+ }
+ if (orgpat.regmatch.rm_ic && !match_no_ic)
+ mtt += MT_IC_OFF;
+ if (match_re)
+ mtt += MT_RE_OFF;
+ }
+
+ /*
+ * Add the found match in ht_match[mtt] and ga_match[mtt].
+ * Store the info we need later, which depends on the kind of
+ * tags we are dealing with.
+ */
+ if (help_only)
+ {
+#ifdef FEAT_MULTI_LANG
+# define ML_EXTRA 3
+#else
+# define ML_EXTRA 0
+#endif
+ /*
+ * Append the help-heuristic number after the tagname, for
+ * sorting it later. The heuristic is ignored for
+ * detecting duplicates.
+ * The format is {tagname}@{lang}NUL{heuristic}NUL
+ */
+ *tagp.tagname_end = NUL;
+ len = (int)(tagp.tagname_end - tagp.tagname);
+ mfp = (char_u *)alloc((int)sizeof(char_u)
+ + len + 10 + ML_EXTRA + 1);
+ if (mfp != NULL)
+ {
+ int heuristic;
+
+ p = mfp;
+ STRCPY(p, tagp.tagname);
+#ifdef FEAT_MULTI_LANG
+ p[len] = '@';
+ STRCPY(p + len + 1, help_lang);
+#endif
+
+ heuristic = help_heuristic(tagp.tagname,
+ match_re ? matchoff : 0, !match_no_ic);
+#ifdef FEAT_MULTI_LANG
+ heuristic += help_pri;
+#endif
+ sprintf((char *)p + len + 1 + ML_EXTRA, "%06d",
+ heuristic);
+ }
+ *tagp.tagname_end = TAB;
+ }
+ else if (name_only)
+ {
+ if (get_it_again)
+ {
+ char_u *temp_end = tagp.command;
+
+ if (*temp_end == '/')
+ while (*temp_end && *temp_end != '\r'
+ && *temp_end != '\n'
+ && *temp_end != '$')
+ temp_end++;
+
+ if (tagp.command + 2 < temp_end)
+ {
+ len = (int)(temp_end - tagp.command - 2);
+ mfp = (char_u *)alloc(len + 2);
+ if (mfp != NULL)
+ vim_strncpy(mfp, tagp.command + 2, len);
+ }
+ else
+ mfp = NULL;
+ get_it_again = FALSE;
+ }
+ else
+ {
+ len = (int)(tagp.tagname_end - tagp.tagname);
+ mfp = (char_u *)alloc((int)sizeof(char_u) + len + 1);
+ if (mfp != NULL)
+ vim_strncpy(mfp, tagp.tagname, len);
+
+ /* if wanted, re-read line to get long form too */
+ if (State & INSERT)
+ get_it_again = p_sft;
+ }
+ }
+ else
+ {
+#define TAG_SEP 0x02
+ size_t tag_fname_len = STRLEN(tag_fname);
+#ifdef FEAT_EMACS_TAGS
+ size_t ebuf_len = 0;
+#endif
+
+ /* Save the tag in a buffer.
+ * Use 0x02 to separate fields (Can't use NUL because the
+ * hash key is terminated by NUL, or Ctrl_A because that is
+ * part of some Emacs tag files -- see parse_tag_line).
+ * Emacs tag: <mtt><tag_fname><0x02><ebuf><0x02><lbuf><NUL>
+ * other tag: <mtt><tag_fname><0x02><0x02><lbuf><NUL>
+ * without Emacs tags: <mtt><tag_fname><0x02><lbuf><NUL>
+ * Here <mtt> is the "mtt" value plus 1 to avoid NUL.
+ */
+ len = (int)tag_fname_len + (int)STRLEN(lbuf) + 3;
+#ifdef FEAT_EMACS_TAGS
+ if (is_etag)
+ {
+ ebuf_len = STRLEN(ebuf);
+ len += (int)ebuf_len + 1;
+ }
+ else
+ ++len;
+#endif
+ mfp = (char_u *)alloc((int)sizeof(char_u) + len + 1);
+ if (mfp != NULL)
+ {
+ p = mfp;
+ p[0] = mtt + 1;
+ STRCPY(p + 1, tag_fname);
+#ifdef BACKSLASH_IN_FILENAME
+ /* Ignore differences in slashes, avoid adding
+ * both path/file and path\file. */
+ slash_adjust(p + 1);
+#endif
+ p[tag_fname_len + 1] = TAG_SEP;
+ s = p + 1 + tag_fname_len + 1;
+#ifdef FEAT_EMACS_TAGS
+ if (is_etag)
+ {
+ STRCPY(s, ebuf);
+ s[ebuf_len] = TAG_SEP;
+ s += ebuf_len + 1;
+ }
+ else
+ *s++ = TAG_SEP;
+#endif
+ STRCPY(s, lbuf);
+ }
+ }
+
+ if (mfp != NULL)
+ {
+ hashitem_T *hi;
+
+ /*
+ * Don't add identical matches.
+ * Add all cscope tags, because they are all listed.
+ * "mfp" is used as a hash key, there is a NUL byte to end
+ * the part matters for comparing, more bytes may follow
+ * after it. E.g. help tags store the priority after the
+ * NUL.
+ */
+#ifdef FEAT_CSCOPE
+ if (use_cscope)
+ hash++;
+ else
+#endif
+ hash = hash_hash(mfp);
+ hi = hash_lookup(&ht_match[mtt], mfp, hash);
+ if (HASHITEM_EMPTY(hi))
+ {
+ if (hash_add_item(&ht_match[mtt], hi, mfp, hash)
+ == FAIL
+ || ga_grow(&ga_match[mtt], 1) != OK)
+ {
+ /* Out of memory! Just forget about the rest. */
+ retval = OK;
+ stop_searching = TRUE;
+ break;
+ }
+ else
+ {
+ ((char_u **)(ga_match[mtt].ga_data))
+ [ga_match[mtt].ga_len++] = mfp;
+ ++match_count;
+ }
+ }
+ else
+ /* duplicate tag, drop it */
+ vim_free(mfp);
+ }
+ }
+#ifdef FEAT_CSCOPE
+ if (use_cscope && eof)
+ break;
+#endif
+ } /* forever */
+
+ if (line_error)
+ {
+ semsg(_("E431: Format error in tags file \"%s\""), tag_fname);
+#ifdef FEAT_CSCOPE
+ if (!use_cscope)
+#endif
+ semsg(_("Before byte %ld"), (long)vim_ftell(fp));
+ stop_searching = TRUE;
+ line_error = FALSE;
+ }
+
+#ifdef FEAT_CSCOPE
+ if (!use_cscope)
+#endif
+ fclose(fp);
+#ifdef FEAT_EMACS_TAGS
+ while (incstack_idx)
+ {
+ --incstack_idx;
+ fclose(incstack[incstack_idx].fp);
+ vim_free(incstack[incstack_idx].etag_fname);
+ }
+#endif
+ if (vimconv.vc_type != CONV_NONE)
+ convert_setup(&vimconv, NULL, NULL);
+
+#ifdef FEAT_TAG_BINS
+ tag_file_sorted = NUL;
+ if (sort_error)
+ {
+ semsg(_("E432: Tags file not sorted: %s"), tag_fname);
+ sort_error = FALSE;
+ }
+#endif
+
+ /*
+ * Stop searching if sufficient tags have been found.
+ */
+ if (match_count >= mincount)
+ {
+ retval = OK;
+ stop_searching = TRUE;
+ }
+
+#ifdef FEAT_CSCOPE
+ if (stop_searching || use_cscope)
+#else
+ if (stop_searching)
+#endif
+ break;
+
+ } /* end of for-each-file loop */
+
+#ifdef FEAT_CSCOPE
+ if (!use_cscope)
+#endif
+ tagname_free(&tn);
+
+#ifdef FEAT_TAG_BINS
+ /* stop searching when already did a linear search, or when TAG_NOIC
+ * used, and 'ignorecase' not set or already did case-ignore search */
+ if (stop_searching || linear || (!p_ic && noic) || orgpat.regmatch.rm_ic)
+ break;
+# ifdef FEAT_CSCOPE
+ if (use_cscope)
+ break;
+# endif
+ orgpat.regmatch.rm_ic = TRUE; /* try another time while ignoring case */
+ }
+#endif
+
+ if (!stop_searching)
+ {
+ if (!did_open && verbose) /* never opened any tags file */
+ emsg(_("E433: No tags file"));
+ retval = OK; /* It's OK even when no tag found */
+ }
+
+findtag_end:
+ vim_free(lbuf);
+ vim_regfree(orgpat.regmatch.regprog);
+ vim_free(tag_fname);
+#ifdef FEAT_EMACS_TAGS
+ vim_free(ebuf);
+#endif
+
+ /*
+ * Move the matches from the ga_match[] arrays into one list of
+ * matches. When retval == FAIL, free the matches.
+ */
+ if (retval == FAIL)
+ match_count = 0;
+
+ if (match_count > 0)
+ matches = (char_u **)lalloc((long_u)(match_count * sizeof(char_u *)),
+ TRUE);
+ else
+ matches = NULL;
+ match_count = 0;
+ for (mtt = 0; mtt < MT_COUNT; ++mtt)
+ {
+ for (i = 0; i < ga_match[mtt].ga_len; ++i)
+ {
+ mfp = ((char_u **)(ga_match[mtt].ga_data))[i];
+ if (matches == NULL)
+ vim_free(mfp);
+ else
+ {
+ if (!name_only)
+ {
+ /* Change mtt back to zero-based. */
+ *mfp = *mfp - 1;
+
+ /* change the TAG_SEP back to NUL */
+ for (p = mfp + 1; *p != NUL; ++p)
+ if (*p == TAG_SEP)
+ *p = NUL;
+ }
+ matches[match_count++] = (char_u *)mfp;
+ }
+ }
+
+ ga_clear(&ga_match[mtt]);
+ hash_clear(&ht_match[mtt]);
+ }
+
+ *matchesp = matches;
+ *num_matches = match_count;
+
+ curbuf->b_help = help_save;
+#ifdef FEAT_MULTI_LANG
+ vim_free(saved_pat);
+#endif
+
+ p_ic = save_p_ic;
+
+ return retval;
+}
+
+static garray_T tag_fnames = GA_EMPTY;
+
+/*
+ * Callback function for finding all "tags" and "tags-??" files in
+ * 'runtimepath' doc directories.
+ */
+ static void
+found_tagfile_cb(char_u *fname, void *cookie UNUSED)
+{
+ if (ga_grow(&tag_fnames, 1) == OK)
+ {
+ char_u *tag_fname = vim_strsave(fname);
+
+#ifdef BACKSLASH_IN_FILENAME
+ slash_adjust(tag_fname);
+#endif
+ simplify_filename(tag_fname);
+ ((char_u **)(tag_fnames.ga_data))[tag_fnames.ga_len++] = tag_fname;
+ }
+}
+
+#if defined(EXITFREE) || defined(PROTO)
+ void
+free_tag_stuff(void)
+{
+ ga_clear_strings(&tag_fnames);
+ do_tag(NULL, DT_FREE, 0, 0, 0);
+ tag_freematch();
+
+# if defined(FEAT_QUICKFIX)
+ if (ptag_entry.tagname)
+ VIM_CLEAR(ptag_entry.tagname);
+# endif
+}
+#endif
+
+/*
+ * Get the next name of a tag file from the tag file list.
+ * For help files, use "tags" file only.
+ *
+ * Return FAIL if no more tag file names, OK otherwise.
+ */
+ int
+get_tagfname(
+ tagname_T *tnp, /* holds status info */
+ int first, /* TRUE when first file name is wanted */
+ char_u *buf) /* pointer to buffer of MAXPATHL chars */
+{
+ char_u *fname = NULL;
+ char_u *r_ptr;
+ int i;
+
+ if (first)
+ vim_memset(tnp, 0, sizeof(tagname_T));
+
+ if (curbuf->b_help)
+ {
+ /*
+ * For help files it's done in a completely different way:
+ * Find "doc/tags" and "doc/tags-??" in all directories in
+ * 'runtimepath'.
+ */
+ if (first)
+ {
+ ga_clear_strings(&tag_fnames);
+ ga_init2(&tag_fnames, (int)sizeof(char_u *), 10);
+ do_in_runtimepath((char_u *)
+#ifdef FEAT_MULTI_LANG
+# ifdef VMS
+ /* Functions decc$to_vms() and decc$translate_vms() crash
+ * on some VMS systems with wildcards "??". Seems ECO
+ * patches do fix the problem in C RTL, but we can't use
+ * an #ifdef for that. */
+ "doc/tags doc/tags-*"
+# else
+ "doc/tags doc/tags-??"
+# endif
+#else
+ "doc/tags"
+#endif
+ , DIP_ALL, found_tagfile_cb, NULL);
+ }
+
+ if (tnp->tn_hf_idx >= tag_fnames.ga_len)
+ {
+ /* Not found in 'runtimepath', use 'helpfile', if it exists and
+ * wasn't used yet, replacing "help.txt" with "tags". */
+ if (tnp->tn_hf_idx > tag_fnames.ga_len || *p_hf == NUL)
+ return FAIL;
+ ++tnp->tn_hf_idx;
+ STRCPY(buf, p_hf);
+ STRCPY(gettail(buf), "tags");
+#ifdef BACKSLASH_IN_FILENAME
+ slash_adjust(buf);
+#endif
+ simplify_filename(buf);
+
+ for (i = 0; i < tag_fnames.ga_len; ++i)
+ if (STRCMP(buf, ((char_u **)(tag_fnames.ga_data))[i]) == 0)
+ return FAIL; // avoid duplicate file names
+ }
+ else
+ vim_strncpy(buf, ((char_u **)(tag_fnames.ga_data))[
+ tnp->tn_hf_idx++], MAXPATHL - 1);
+ return OK;
+ }
+
+ if (first)
+ {
+ /* Init. We make a copy of 'tags', because autocommands may change
+ * the value without notifying us. */
+ tnp->tn_tags = vim_strsave((*curbuf->b_p_tags != NUL)
+ ? curbuf->b_p_tags : p_tags);
+ if (tnp->tn_tags == NULL)
+ return FAIL;
+ tnp->tn_np = tnp->tn_tags;
+ }
+
+ /*
+ * Loop until we have found a file name that can be used.
+ * There are two states:
+ * tnp->tn_did_filefind_init == FALSE: setup for next part in 'tags'.
+ * tnp->tn_did_filefind_init == TRUE: find next file in this part.
+ */
+ for (;;)
+ {
+ if (tnp->tn_did_filefind_init)
+ {
+ fname = vim_findfile(tnp->tn_search_ctx);
+ if (fname != NULL)
+ break;
+
+ tnp->tn_did_filefind_init = FALSE;
+ }
+ else
+ {
+ char_u *filename = NULL;
+
+ /* Stop when used all parts of 'tags'. */
+ if (*tnp->tn_np == NUL)
+ {
+ vim_findfile_cleanup(tnp->tn_search_ctx);
+ tnp->tn_search_ctx = NULL;
+ return FAIL;
+ }
+
+ /*
+ * Copy next file name into buf.
+ */
+ buf[0] = NUL;
+ (void)copy_option_part(&tnp->tn_np, buf, MAXPATHL - 1, " ,");
+
+#ifdef FEAT_PATH_EXTRA
+ r_ptr = vim_findfile_stopdir(buf);
+#else
+ r_ptr = NULL;
+#endif
+ /* move the filename one char forward and truncate the
+ * filepath with a NUL */
+ filename = gettail(buf);
+ STRMOVE(filename + 1, filename);
+ *filename++ = NUL;
+
+ tnp->tn_search_ctx = vim_findfile_init(buf, filename,
+ r_ptr, 100,
+ FALSE, /* don't free visited list */
+ FINDFILE_FILE, /* we search for a file */
+ tnp->tn_search_ctx, TRUE, curbuf->b_ffname);
+ if (tnp->tn_search_ctx != NULL)
+ tnp->tn_did_filefind_init = TRUE;
+ }
+ }
+
+ STRCPY(buf, fname);
+ vim_free(fname);
+ return OK;
+}
+
+/*
+ * Free the contents of a tagname_T that was filled by get_tagfname().
+ */
+ void
+tagname_free(tagname_T *tnp)
+{
+ vim_free(tnp->tn_tags);
+ vim_findfile_cleanup(tnp->tn_search_ctx);
+ tnp->tn_search_ctx = NULL;
+ ga_clear_strings(&tag_fnames);
+}
+
+/*
+ * Parse one line from the tags file. Find start/end of tag name, start/end of
+ * file name and start of search pattern.
+ *
+ * If is_etag is TRUE, tagp->fname and tagp->fname_end are not set.
+ *
+ * Return FAIL if there is a format error in this line, OK otherwise.
+ */
+ static int
+parse_tag_line(
+ char_u *lbuf, /* line to be parsed */
+#ifdef FEAT_EMACS_TAGS
+ int is_etag,
+#endif
+ tagptrs_T *tagp)
+{
+ char_u *p;
+
+#ifdef FEAT_EMACS_TAGS
+ char_u *p_7f;
+
+ if (is_etag)
+ {
+ /*
+ * There are two formats for an emacs tag line:
+ * 1: struct EnvBase ^?EnvBase^A139,4627
+ * 2: #define ARPB_WILD_WORLD ^?153,5194
+ */
+ p_7f = vim_strchr(lbuf, 0x7f);
+ if (p_7f == NULL)
+ {
+etag_fail:
+ if (vim_strchr(lbuf, '\n') == NULL)
+ {
+ /* Truncated line. Ignore it. */
+ if (p_verbose >= 5)
+ {
+ verbose_enter();
+ msg(_("Ignoring long line in tags file"));
+ verbose_leave();
+ }
+ tagp->command = lbuf;
+ tagp->tagname = lbuf;
+ tagp->tagname_end = lbuf;
+ return OK;
+ }
+ return FAIL;
+ }
+
+ /* Find ^A. If not found the line number is after the 0x7f */
+ p = vim_strchr(p_7f, Ctrl_A);
+ if (p == NULL)
+ p = p_7f + 1;
+ else
+ ++p;
+
+ if (!VIM_ISDIGIT(*p)) /* check for start of line number */
+ goto etag_fail;
+ tagp->command = p;
+
+
+ if (p[-1] == Ctrl_A) /* first format: explicit tagname given */
+ {
+ tagp->tagname = p_7f + 1;
+ tagp->tagname_end = p - 1;
+ }
+ else /* second format: isolate tagname */
+ {
+ /* find end of tagname */
+ for (p = p_7f - 1; !vim_iswordc(*p); --p)
+ if (p == lbuf)
+ goto etag_fail;
+ tagp->tagname_end = p + 1;
+ while (p >= lbuf && vim_iswordc(*p))
+ --p;
+ tagp->tagname = p + 1;
+ }
+ }
+ else /* not an Emacs tag */
+ {
+#endif
+ /* Isolate the tagname, from lbuf up to the first white */
+ tagp->tagname = lbuf;
+#ifdef FEAT_TAG_ANYWHITE
+ p = skiptowhite(lbuf);
+#else
+ p = vim_strchr(lbuf, TAB);
+ if (p == NULL)
+ return FAIL;
+#endif
+ tagp->tagname_end = p;
+
+ /* Isolate file name, from first to second white space */
+#ifdef FEAT_TAG_ANYWHITE
+ p = skipwhite(p);
+#else
+ if (*p != NUL)
+ ++p;
+#endif
+ tagp->fname = p;
+#ifdef FEAT_TAG_ANYWHITE
+ p = skiptowhite(p);
+#else
+ p = vim_strchr(p, TAB);
+ if (p == NULL)
+ return FAIL;
+#endif
+ tagp->fname_end = p;
+
+ /* find start of search command, after second white space */
+#ifdef FEAT_TAG_ANYWHITE
+ p = skipwhite(p);
+#else
+ if (*p != NUL)
+ ++p;
+#endif
+ if (*p == NUL)
+ return FAIL;
+ tagp->command = p;
+#ifdef FEAT_EMACS_TAGS
+ }
+#endif
+
+ return OK;
+}
+
+/*
+ * Check if tagname is a static tag
+ *
+ * Static tags produced by the older ctags program have the format:
+ * 'file:tag file /pattern'.
+ * This is only recognized when both occurrence of 'file' are the same, to
+ * avoid recognizing "string::string" or ":exit".
+ *
+ * Static tags produced by the new ctags program have the format:
+ * 'tag file /pattern/;"<Tab>file:' "
+ *
+ * Return TRUE if it is a static tag and adjust *tagname to the real tag.
+ * Return FALSE if it is not a static tag.
+ */
+ static int
+test_for_static(tagptrs_T *tagp)
+{
+ char_u *p;
+
+#ifdef FEAT_TAG_OLDSTATIC
+ int len;
+
+ /*
+ * Check for old style static tag: "file:tag file .."
+ */
+ len = (int)(tagp->fname_end - tagp->fname);
+ p = tagp->tagname + len;
+ if ( p < tagp->tagname_end
+ && *p == ':'
+ && fnamencmp(tagp->tagname, tagp->fname, len) == 0)
+ {
+ tagp->tagname = p + 1;
+ return TRUE;
+ }
+#endif
+
+ /*
+ * Check for new style static tag ":...<Tab>file:[<Tab>...]"
+ */
+ p = tagp->command;
+ while ((p = vim_strchr(p, '\t')) != NULL)
+ {
+ ++p;
+ if (STRNCMP(p, "file:", 5) == 0)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/*
+ * Returns the length of a matching tag line.
+ */
+ static size_t
+matching_line_len(char_u *lbuf)
+{
+ char_u *p = lbuf + 1;
+
+ /* does the same thing as parse_match() */
+ p += STRLEN(p) + 1;
+#ifdef FEAT_EMACS_TAGS
+ p += STRLEN(p) + 1;
+#endif
+ return (p - lbuf) + STRLEN(p);
+}
+
+/*
+ * Parse a line from a matching tag. Does not change the line itself.
+ *
+ * The line that we get looks like this:
+ * Emacs tag: <mtt><tag_fname><NUL><ebuf><NUL><lbuf>
+ * other tag: <mtt><tag_fname><NUL><NUL><lbuf>
+ * without Emacs tags: <mtt><tag_fname><NUL><lbuf>
+ *
+ * Return OK or FAIL.
+ */
+ static int
+parse_match(
+ char_u *lbuf, /* input: matching line */
+ tagptrs_T *tagp) /* output: pointers into the line */
+{
+ int retval;
+ char_u *p;
+ char_u *pc, *pt;
+
+ tagp->tag_fname = lbuf + 1;
+ lbuf += STRLEN(tagp->tag_fname) + 2;
+#ifdef FEAT_EMACS_TAGS
+ if (*lbuf)
+ {
+ tagp->is_etag = TRUE;
+ tagp->fname = lbuf;
+ lbuf += STRLEN(lbuf);
+ tagp->fname_end = lbuf++;
+ }
+ else
+ {
+ tagp->is_etag = FALSE;
+ ++lbuf;
+ }
+#endif
+
+ /* Find search pattern and the file name for non-etags. */
+ retval = parse_tag_line(lbuf,
+#ifdef FEAT_EMACS_TAGS
+ tagp->is_etag,
+#endif
+ tagp);
+
+ tagp->tagkind = NULL;
+ tagp->command_end = NULL;
+
+ if (retval == OK)
+ {
+ /* Try to find a kind field: "kind:<kind>" or just "<kind>"*/
+ p = tagp->command;
+ if (find_extra(&p) == OK)
+ {
+ tagp->command_end = p;
+ p += 2; /* skip ";\"" */
+ if (*p++ == TAB)
+ while (ASCII_ISALPHA(*p))
+ {
+ if (STRNCMP(p, "kind:", 5) == 0)
+ {
+ tagp->tagkind = p + 5;
+ break;
+ }
+ pc = vim_strchr(p, ':');
+ pt = vim_strchr(p, '\t');
+ if (pc == NULL || (pt != NULL && pc > pt))
+ {
+ tagp->tagkind = p;
+ break;
+ }
+ if (pt == NULL)
+ break;
+ p = pt + 1;
+ }
+ }
+ if (tagp->tagkind != NULL)
+ {
+ for (p = tagp->tagkind;
+ *p && *p != '\t' && *p != '\r' && *p != '\n'; ++p)
+ ;
+ tagp->tagkind_end = p;
+ }
+ }
+ return retval;
+}
+
+/*
+ * Find out the actual file name of a tag. Concatenate the tags file name
+ * with the matching tag file name.
+ * Returns an allocated string or NULL (out of memory).
+ */
+ static char_u *
+tag_full_fname(tagptrs_T *tagp)
+{
+ char_u *fullname;
+ int c;
+
+#ifdef FEAT_EMACS_TAGS
+ if (tagp->is_etag)
+ c = 0; /* to shut up GCC */
+ else
+#endif
+ {
+ c = *tagp->fname_end;
+ *tagp->fname_end = NUL;
+ }
+ fullname = expand_tag_fname(tagp->fname, tagp->tag_fname, FALSE);
+
+#ifdef FEAT_EMACS_TAGS
+ if (!tagp->is_etag)
+#endif
+ *tagp->fname_end = c;
+
+ return fullname;
+}
+
+/*
+ * Jump to a tag that has been found in one of the tag files
+ *
+ * returns OK for success, NOTAGFILE when file not found, FAIL otherwise.
+ */
+ static int
+jumpto_tag(
+ char_u *lbuf_arg, /* line from the tags file for this tag */
+ int forceit, /* :ta with ! */
+ int keep_help) /* keep help flag (FALSE for cscope) */
+{
+ int save_secure;
+ int save_magic;
+ int save_p_ws, save_p_scs, save_p_ic;
+ linenr_T save_lnum;
+ char_u *str;
+ char_u *pbuf; /* search pattern buffer */
+ char_u *pbuf_end;
+ char_u *tofree_fname = NULL;
+ char_u *fname;
+ tagptrs_T tagp;
+ int retval = FAIL;
+ int getfile_result = GETFILE_UNUSED;
+ int search_options;
+#ifdef FEAT_SEARCH_EXTRA
+ int save_no_hlsearch;
+#endif
+#if defined(FEAT_QUICKFIX)
+ win_T *curwin_save = NULL;
+#endif
+ char_u *full_fname = NULL;
+#ifdef FEAT_FOLDING
+ int old_KeyTyped = KeyTyped; /* getting the file may reset it */
+#endif
+ size_t len;
+ char_u *lbuf;
+
+ /* Make a copy of the line, it can become invalid when an autocommand calls
+ * back here recursively. */
+ len = matching_line_len(lbuf_arg) + 1;
+ lbuf = alloc((int)len);
+ if (lbuf != NULL)
+ mch_memmove(lbuf, lbuf_arg, len);
+
+ pbuf = alloc(LSIZE);
+
+ /* parse the match line into the tagp structure */
+ if (pbuf == NULL || lbuf == NULL || parse_match(lbuf, &tagp) == FAIL)
+ {
+ tagp.fname_end = NULL;
+ goto erret;
+ }
+
+ /* truncate the file name, so it can be used as a string */
+ *tagp.fname_end = NUL;
+ fname = tagp.fname;
+
+ /* copy the command to pbuf[], remove trailing CR/NL */
+ str = tagp.command;
+ for (pbuf_end = pbuf; *str && *str != '\n' && *str != '\r'; )
+ {
+#ifdef FEAT_EMACS_TAGS
+ if (tagp.is_etag && *str == ',')/* stop at ',' after line number */
+ break;
+#endif
+ *pbuf_end++ = *str++;
+ }
+ *pbuf_end = NUL;
+
+#ifdef FEAT_EMACS_TAGS
+ if (!tagp.is_etag)
+#endif
+ {
+ /*
+ * Remove the "<Tab>fieldname:value" stuff; we don't need it here.
+ */
+ str = pbuf;
+ if (find_extra(&str) == OK)
+ {
+ pbuf_end = str;
+ *pbuf_end = NUL;
+ }
+ }
+
+ /*
+ * Expand file name, when needed (for environment variables).
+ * If 'tagrelative' option set, may change file name.
+ */
+ fname = expand_tag_fname(fname, tagp.tag_fname, TRUE);
+ if (fname == NULL)
+ goto erret;
+ tofree_fname = fname; /* free() it later */
+
+ /*
+ * Check if the file with the tag exists before abandoning the current
+ * file. Also accept a file name for which there is a matching BufReadCmd
+ * autocommand event (e.g., http://sys/file).
+ */
+ if (mch_getperm(fname) < 0 && !has_autocmd(EVENT_BUFREADCMD, fname, NULL))
+ {
+ retval = NOTAGFILE;
+ vim_free(nofile_fname);
+ nofile_fname = vim_strsave(fname);
+ if (nofile_fname == NULL)
+ nofile_fname = empty_option;
+ goto erret;
+ }
+
+ ++RedrawingDisabled;
+
+#ifdef FEAT_GUI
+ need_mouse_correct = TRUE;
+#endif
+
+#if defined(FEAT_QUICKFIX)
+ if (g_do_tagpreview != 0)
+ {
+ postponed_split = 0; /* don't split again below */
+ curwin_save = curwin; /* Save current window */
+
+ /*
+ * If we are reusing a window, we may change dir when
+ * entering it (autocommands) so turn the tag filename
+ * into a fullpath
+ */
+ if (!curwin->w_p_pvw)
+ {
+ full_fname = FullName_save(fname, FALSE);
+ fname = full_fname;
+
+ /*
+ * Make the preview window the current window.
+ * Open a preview window when needed.
+ */
+ prepare_tagpreview(TRUE);
+ }
+ }
+
+ /* If it was a CTRL-W CTRL-] command split window now. For ":tab tag"
+ * open a new tab page. */
+ if (postponed_split && (swb_flags & (SWB_USEOPEN | SWB_USETAB)))
+ {
+ buf_T *existing_buf = buflist_findname_exp(fname);
+
+ if (existing_buf != NULL)
+ {
+ win_T *wp = NULL;
+
+ if (swb_flags & SWB_USEOPEN)
+ wp = buf_jump_open_win(existing_buf);
+
+ /* If 'switchbuf' contains "usetab": jump to first window in any tab
+ * page containing "existing_buf" if one exists */
+ if (wp == NULL && (swb_flags & SWB_USETAB))
+ wp = buf_jump_open_tab(existing_buf);
+ /* We've switched to the buffer, the usual loading of the file must
+ * be skipped. */
+ if (wp != NULL)
+ getfile_result = GETFILE_SAME_FILE;
+ }
+ }
+ if (getfile_result == GETFILE_UNUSED
+ && (postponed_split || cmdmod.tab != 0))
+ {
+ if (win_split(postponed_split > 0 ? postponed_split : 0,
+ postponed_split_flags) == FAIL)
+ {
+ --RedrawingDisabled;
+ goto erret;
+ }
+ RESET_BINDING(curwin);
+ }
+#endif
+
+ if (keep_help)
+ {
+ /* A :ta from a help file will keep the b_help flag set. For ":ptag"
+ * we need to use the flag from the window where we came from. */
+#if defined(FEAT_QUICKFIX)
+ if (g_do_tagpreview != 0)
+ keep_help_flag = bt_help(curwin_save->w_buffer);
+ else
+#endif
+ keep_help_flag = curbuf->b_help;
+ }
+
+ if (getfile_result == GETFILE_UNUSED)
+ /* Careful: getfile() may trigger autocommands and call jumpto_tag()
+ * recursively. */
+ getfile_result = getfile(0, fname, NULL, TRUE, (linenr_T)0, forceit);
+ keep_help_flag = FALSE;
+
+ if (GETFILE_SUCCESS(getfile_result)) /* got to the right file */
+ {
+ curwin->w_set_curswant = TRUE;
+ postponed_split = 0;
+
+ save_secure = secure;
+ secure = 1;
+#ifdef HAVE_SANDBOX
+ ++sandbox;
+#endif
+ save_magic = p_magic;
+ p_magic = FALSE; /* always execute with 'nomagic' */
+#ifdef FEAT_SEARCH_EXTRA
+ /* Save value of no_hlsearch, jumping to a tag is not a real search */
+ save_no_hlsearch = no_hlsearch;
+#endif
+
+ /*
+ * If 'cpoptions' contains 't', store the search pattern for the "n"
+ * command. If 'cpoptions' does not contain 't', the search pattern
+ * is not stored.
+ */
+ if (vim_strchr(p_cpo, CPO_TAGPAT) != NULL)
+ search_options = 0;
+ else
+ search_options = SEARCH_KEEP;
+
+ /*
+ * If the command is a search, try here.
+ *
+ * Reset 'smartcase' for the search, since the search pattern was not
+ * typed by the user.
+ * Only use do_search() when there is a full search command, without
+ * anything following.
+ */
+ str = pbuf;
+ if (pbuf[0] == '/' || pbuf[0] == '?')
+ str = skip_regexp(pbuf + 1, pbuf[0], FALSE, NULL) + 1;
+ if (str > pbuf_end - 1) /* search command with nothing following */
+ {
+ save_p_ws = p_ws;
+ save_p_ic = p_ic;
+ save_p_scs = p_scs;
+ p_ws = TRUE; /* need 'wrapscan' for backward searches */
+ p_ic = FALSE; /* don't ignore case now */
+ p_scs = FALSE;
+#if 0 /* disabled for now */
+#ifdef FEAT_CMDHIST
+ /* put pattern in search history */
+ add_to_history(HIST_SEARCH, pbuf + 1, TRUE, pbuf[0]);
+#endif
+#endif
+ save_lnum = curwin->w_cursor.lnum;
+ curwin->w_cursor.lnum = 0; /* start search before first line */
+ if (do_search(NULL, pbuf[0], pbuf + 1, (long)1,
+ search_options, NULL, NULL))
+ retval = OK;
+ else
+ {
+ int found = 1;
+ int cc;
+
+ /*
+ * try again, ignore case now
+ */
+ p_ic = TRUE;
+ if (!do_search(NULL, pbuf[0], pbuf + 1, (long)1,
+ search_options, NULL, NULL))
+ {
+ /*
+ * Failed to find pattern, take a guess: "^func ("
+ */
+ found = 2;
+ (void)test_for_static(&tagp);
+ cc = *tagp.tagname_end;
+ *tagp.tagname_end = NUL;
+ sprintf((char *)pbuf, "^%s\\s\\*(", tagp.tagname);
+ if (!do_search(NULL, '/', pbuf, (long)1,
+ search_options, NULL, NULL))
+ {
+ /* Guess again: "^char * \<func (" */
+ sprintf((char *)pbuf, "^\\[#a-zA-Z_]\\.\\*\\<%s\\s\\*(",
+ tagp.tagname);
+ if (!do_search(NULL, '/', pbuf, (long)1,
+ search_options, NULL, NULL))
+ found = 0;
+ }
+ *tagp.tagname_end = cc;
+ }
+ if (found == 0)
+ {
+ emsg(_("E434: Can't find tag pattern"));
+ curwin->w_cursor.lnum = save_lnum;
+ }
+ else
+ {
+ /*
+ * Only give a message when really guessed, not when 'ic'
+ * is set and match found while ignoring case.
+ */
+ if (found == 2 || !save_p_ic)
+ {
+ msg(_("E435: Couldn't find tag, just guessing!"));
+ if (!msg_scrolled && msg_silent == 0)
+ {
+ out_flush();
+ ui_delay(1000L, TRUE);
+ }
+ }
+ retval = OK;
+ }
+ }
+ p_ws = save_p_ws;
+ p_ic = save_p_ic;
+ p_scs = save_p_scs;
+
+ /* A search command may have positioned the cursor beyond the end
+ * of the line. May need to correct that here. */
+ check_cursor();
+ }
+ else
+ {
+ curwin->w_cursor.lnum = 1; /* start command in line 1 */
+ do_cmdline_cmd(pbuf);
+ retval = OK;
+ }
+
+ /*
+ * When the command has done something that is not allowed make sure
+ * the error message can be seen.
+ */
+ if (secure == 2)
+ wait_return(TRUE);
+ secure = save_secure;
+ p_magic = save_magic;
+#ifdef HAVE_SANDBOX
+ --sandbox;
+#endif
+#ifdef FEAT_SEARCH_EXTRA
+ /* restore no_hlsearch when keeping the old search pattern */
+ if (search_options)
+ set_no_hlsearch(save_no_hlsearch);
+#endif
+
+ /* Return OK if jumped to another file (at least we found the file!). */
+ if (getfile_result == GETFILE_OPEN_OTHER)
+ retval = OK;
+
+ if (retval == OK)
+ {
+ /*
+ * For a help buffer: Put the cursor line at the top of the window,
+ * the help subject will be below it.
+ */
+ if (curbuf->b_help)
+ set_topline(curwin, curwin->w_cursor.lnum);
+#ifdef FEAT_FOLDING
+ if ((fdo_flags & FDO_TAG) && old_KeyTyped)
+ foldOpenCursor();
+#endif
+ }
+
+#if defined(FEAT_QUICKFIX)
+ if (g_do_tagpreview != 0
+ && curwin != curwin_save && win_valid(curwin_save))
+ {
+ /* Return cursor to where we were */
+ validate_cursor();
+ redraw_later(VALID);
+ win_enter(curwin_save, TRUE);
+ }
+#endif
+
+ --RedrawingDisabled;
+ }
+ else
+ {
+ --RedrawingDisabled;
+ if (postponed_split) /* close the window */
+ {
+ win_close(curwin, FALSE);
+ postponed_split = 0;
+ }
+ }
+
+erret:
+#if defined(FEAT_QUICKFIX)
+ g_do_tagpreview = 0; /* For next time */
+#endif
+ vim_free(lbuf);
+ vim_free(pbuf);
+ vim_free(tofree_fname);
+ vim_free(full_fname);
+
+ return retval;
+}
+
+/*
+ * If "expand" is TRUE, expand wildcards in fname.
+ * If 'tagrelative' option set, change fname (name of file containing tag)
+ * according to tag_fname (name of tag file containing fname).
+ * Returns a pointer to allocated memory (or NULL when out of memory).
+ */
+ static char_u *
+expand_tag_fname(char_u *fname, char_u *tag_fname, int expand)
+{
+ char_u *p;
+ char_u *retval;
+ char_u *expanded_fname = NULL;
+ expand_T xpc;
+
+ /*
+ * Expand file name (for environment variables) when needed.
+ */
+ if (expand && mch_has_wildcard(fname))
+ {
+ ExpandInit(&xpc);
+ xpc.xp_context = EXPAND_FILES;
+ expanded_fname = ExpandOne(&xpc, (char_u *)fname, NULL,
+ WILD_LIST_NOTFOUND|WILD_SILENT, WILD_EXPAND_FREE);
+ if (expanded_fname != NULL)
+ fname = expanded_fname;
+ }
+
+ if ((p_tr || curbuf->b_help)
+ && !vim_isAbsName(fname)
+ && (p = gettail(tag_fname)) != tag_fname)
+ {
+ retval = alloc(MAXPATHL);
+ if (retval != NULL)
+ {
+ STRCPY(retval, tag_fname);
+ vim_strncpy(retval + (p - tag_fname), fname,
+ MAXPATHL - (p - tag_fname) - 1);
+ /*
+ * Translate names like "src/a/../b/file.c" into "src/b/file.c".
+ */
+ simplify_filename(retval);
+ }
+ }
+ else
+ retval = vim_strsave(fname);
+
+ vim_free(expanded_fname);
+
+ return retval;
+}
+
+/*
+ * Converts a file name into a canonical form. It simplifies a file name into
+ * its simplest form by stripping out unneeded components, if any. The
+ * resulting file name is simplified in place and will either be the same
+ * length as that supplied, or shorter.
+ */
+ void
+simplify_filename(char_u *filename)
+{
+#ifndef AMIGA /* Amiga doesn't have "..", it uses "/" */
+ int components = 0;
+ char_u *p, *tail, *start;
+ int stripping_disabled = FALSE;
+ int relative = TRUE;
+
+ p = filename;
+#ifdef BACKSLASH_IN_FILENAME
+ if (p[1] == ':') /* skip "x:" */
+ p += 2;
+#endif
+
+ if (vim_ispathsep(*p))
+ {
+ relative = FALSE;
+ do
+ ++p;
+ while (vim_ispathsep(*p));
+ }
+ start = p; /* remember start after "c:/" or "/" or "///" */
+
+ do
+ {
+ /* At this point "p" is pointing to the char following a single "/"
+ * or "p" is at the "start" of the (absolute or relative) path name. */
+#ifdef VMS
+ /* VMS allows device:[path] - don't strip the [ in directory */
+ if ((*p == '[' || *p == '<') && p > filename && p[-1] == ':')
+ {
+ /* :[ or :< composition: vms directory component */
+ ++components;
+ p = getnextcomp(p + 1);
+ }
+ /* allow remote calls as host"user passwd"::device:[path] */
+ else if (p[0] == ':' && p[1] == ':' && p > filename && p[-1] == '"' )
+ {
+ /* ":: composition: vms host/passwd component */
+ ++components;
+ p = getnextcomp(p + 2);
+ }
+ else
+#endif
+ if (vim_ispathsep(*p))
+ STRMOVE(p, p + 1); /* remove duplicate "/" */
+ else if (p[0] == '.' && (vim_ispathsep(p[1]) || p[1] == NUL))
+ {
+ if (p == start && relative)
+ p += 1 + (p[1] != NUL); /* keep single "." or leading "./" */
+ else
+ {
+ /* Strip "./" or ".///". If we are at the end of the file name
+ * and there is no trailing path separator, either strip "/." if
+ * we are after "start", or strip "." if we are at the beginning
+ * of an absolute path name . */
+ tail = p + 1;
+ if (p[1] != NUL)
+ while (vim_ispathsep(*tail))
+ MB_PTR_ADV(tail);
+ else if (p > start)
+ --p; /* strip preceding path separator */
+ STRMOVE(p, tail);
+ }
+ }
+ else if (p[0] == '.' && p[1] == '.' &&
+ (vim_ispathsep(p[2]) || p[2] == NUL))
+ {
+ /* Skip to after ".." or "../" or "..///". */
+ tail = p + 2;
+ while (vim_ispathsep(*tail))
+ MB_PTR_ADV(tail);
+
+ if (components > 0) /* strip one preceding component */
+ {
+ int do_strip = FALSE;
+ char_u saved_char;
+ stat_T st;
+
+ /* Don't strip for an erroneous file name. */
+ if (!stripping_disabled)
+ {
+ /* If the preceding component does not exist in the file
+ * system, we strip it. On Unix, we don't accept a symbolic
+ * link that refers to a non-existent file. */
+ saved_char = p[-1];
+ p[-1] = NUL;
+#ifdef UNIX
+ if (mch_lstat((char *)filename, &st) < 0)
+#else
+ if (mch_stat((char *)filename, &st) < 0)
+#endif
+ do_strip = TRUE;
+ p[-1] = saved_char;
+
+ --p;
+ /* Skip back to after previous '/'. */
+ while (p > start && !after_pathsep(start, p))
+ MB_PTR_BACK(start, p);
+
+ if (!do_strip)
+ {
+ /* If the component exists in the file system, check
+ * that stripping it won't change the meaning of the
+ * file name. First get information about the
+ * unstripped file name. This may fail if the component
+ * to strip is not a searchable directory (but a regular
+ * file, for instance), since the trailing "/.." cannot
+ * be applied then. We don't strip it then since we
+ * don't want to replace an erroneous file name by
+ * a valid one, and we disable stripping of later
+ * components. */
+ saved_char = *tail;
+ *tail = NUL;
+ if (mch_stat((char *)filename, &st) >= 0)
+ do_strip = TRUE;
+ else
+ stripping_disabled = TRUE;
+ *tail = saved_char;
+#ifdef UNIX
+ if (do_strip)
+ {
+ stat_T new_st;
+
+ /* On Unix, the check for the unstripped file name
+ * above works also for a symbolic link pointing to
+ * a searchable directory. But then the parent of
+ * the directory pointed to by the link must be the
+ * same as the stripped file name. (The latter
+ * exists in the file system since it is the
+ * component's parent directory.) */
+ if (p == start && relative)
+ (void)mch_stat(".", &new_st);
+ else
+ {
+ saved_char = *p;
+ *p = NUL;
+ (void)mch_stat((char *)filename, &new_st);
+ *p = saved_char;
+ }
+
+ if (new_st.st_ino != st.st_ino ||
+ new_st.st_dev != st.st_dev)
+ {
+ do_strip = FALSE;
+ /* We don't disable stripping of later
+ * components since the unstripped path name is
+ * still valid. */
+ }
+ }
+#endif
+ }
+ }
+
+ if (!do_strip)
+ {
+ /* Skip the ".." or "../" and reset the counter for the
+ * components that might be stripped later on. */
+ p = tail;
+ components = 0;
+ }
+ else
+ {
+ /* Strip previous component. If the result would get empty
+ * and there is no trailing path separator, leave a single
+ * "." instead. If we are at the end of the file name and
+ * there is no trailing path separator and a preceding
+ * component is left after stripping, strip its trailing
+ * path separator as well. */
+ if (p == start && relative && tail[-1] == '.')
+ {
+ *p++ = '.';
+ *p = NUL;
+ }
+ else
+ {
+ if (p > start && tail[-1] == '.')
+ --p;
+ STRMOVE(p, tail); /* strip previous component */
+ }
+
+ --components;
+ }
+ }
+ else if (p == start && !relative) /* leading "/.." or "/../" */
+ STRMOVE(p, tail); /* strip ".." or "../" */
+ else
+ {
+ if (p == start + 2 && p[-2] == '.') /* leading "./../" */
+ {
+ STRMOVE(p - 2, p); /* strip leading "./" */
+ tail -= 2;
+ }
+ p = tail; /* skip to char after ".." or "../" */
+ }
+ }
+ else
+ {
+ ++components; /* simple path component */
+ p = getnextcomp(p);
+ }
+ } while (*p != NUL);
+#endif /* !AMIGA */
+}
+
+/*
+ * Check if we have a tag for the buffer with name "buf_ffname".
+ * This is a bit slow, because of the full path compare in fullpathcmp().
+ * Return TRUE if tag for file "fname" if tag file "tag_fname" is for current
+ * file.
+ */
+ static int
+test_for_current(
+#ifdef FEAT_EMACS_TAGS
+ int is_etag,
+#endif
+ char_u *fname,
+ char_u *fname_end,
+ char_u *tag_fname,
+ char_u *buf_ffname)
+{
+ int c;
+ int retval = FALSE;
+ char_u *fullname;
+
+ if (buf_ffname != NULL) /* if the buffer has a name */
+ {
+#ifdef FEAT_EMACS_TAGS
+ if (is_etag)
+ c = 0; /* to shut up GCC */
+ else
+#endif
+ {
+ c = *fname_end;
+ *fname_end = NUL;
+ }
+ fullname = expand_tag_fname(fname, tag_fname, TRUE);
+ if (fullname != NULL)
+ {
+ retval = (fullpathcmp(fullname, buf_ffname, TRUE) & FPC_SAME);
+ vim_free(fullname);
+ }
+#ifdef FEAT_EMACS_TAGS
+ if (!is_etag)
+#endif
+ *fname_end = c;
+ }
+
+ return retval;
+}
+
+/*
+ * Find the end of the tagaddress.
+ * Return OK if ";\"" is following, FAIL otherwise.
+ */
+ static int
+find_extra(char_u **pp)
+{
+ char_u *str = *pp;
+
+ /* Repeat for addresses separated with ';' */
+ for (;;)
+ {
+ if (VIM_ISDIGIT(*str))
+ str = skipdigits(str);
+ else if (*str == '/' || *str == '?')
+ {
+ str = skip_regexp(str + 1, *str, FALSE, NULL);
+ if (*str != **pp)
+ str = NULL;
+ else
+ ++str;
+ }
+ else
+ str = NULL;
+ if (str == NULL || *str != ';'
+ || !(VIM_ISDIGIT(str[1]) || str[1] == '/' || str[1] == '?'))
+ break;
+ ++str; /* skip ';' */
+ }
+
+ if (str != NULL && STRNCMP(str, ";\"", 2) == 0)
+ {
+ *pp = str;
+ return OK;
+ }
+ return FAIL;
+}
+
+#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
+ int
+expand_tags(
+ int tagnames, /* expand tag names */
+ char_u *pat,
+ int *num_file,
+ char_u ***file)
+{
+ int i;
+ int c;
+ int tagnmflag;
+ char_u tagnm[100];
+ tagptrs_T t_p;
+ int ret;
+
+ if (tagnames)
+ tagnmflag = TAG_NAMES;
+ else
+ tagnmflag = 0;
+ if (pat[0] == '/')
+ ret = find_tags(pat + 1, num_file, file,
+ TAG_REGEXP | tagnmflag | TAG_VERBOSE,
+ TAG_MANY, curbuf->b_ffname);
+ else
+ ret = find_tags(pat, num_file, file,
+ TAG_REGEXP | tagnmflag | TAG_VERBOSE | TAG_NOIC,
+ TAG_MANY, curbuf->b_ffname);
+ if (ret == OK && !tagnames)
+ {
+ /* Reorganize the tags for display and matching as strings of:
+ * "<tagname>\0<kind>\0<filename>\0"
+ */
+ for (i = 0; i < *num_file; i++)
+ {
+ parse_match((*file)[i], &t_p);
+ c = (int)(t_p.tagname_end - t_p.tagname);
+ mch_memmove(tagnm, t_p.tagname, (size_t)c);
+ tagnm[c++] = 0;
+ tagnm[c++] = (t_p.tagkind != NULL && *t_p.tagkind)
+ ? *t_p.tagkind : 'f';
+ tagnm[c++] = 0;
+ mch_memmove((*file)[i] + c, t_p.fname, t_p.fname_end - t_p.fname);
+ (*file)[i][c + (t_p.fname_end - t_p.fname)] = 0;
+ mch_memmove((*file)[i], tagnm, (size_t)c);
+ }
+ }
+ return ret;
+}
+#endif
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * Add a tag field to the dictionary "dict".
+ * Return OK or FAIL.
+ */
+ static int
+add_tag_field(
+ dict_T *dict,
+ char *field_name,
+ char_u *start, /* start of the value */
+ char_u *end) /* after the value; can be NULL */
+{
+ char_u *buf;
+ int len = 0;
+ int retval;
+
+ /* check that the field name doesn't exist yet */
+ if (dict_find(dict, (char_u *)field_name, -1) != NULL)
+ {
+ if (p_verbose > 0)
+ {
+ verbose_enter();
+ smsg(_("Duplicate field name: %s"), field_name);
+ verbose_leave();
+ }
+ return FAIL;
+ }
+ buf = alloc(MAXPATHL);
+ if (buf == NULL)
+ return FAIL;
+ if (start != NULL)
+ {
+ if (end == NULL)
+ {
+ end = start + STRLEN(start);
+ while (end > start && (end[-1] == '\r' || end[-1] == '\n'))
+ --end;
+ }
+ len = (int)(end - start);
+ if (len > MAXPATHL - 1)
+ len = MAXPATHL - 1;
+ vim_strncpy(buf, start, len);
+ }
+ buf[len] = NUL;
+ retval = dict_add_string(dict, field_name, buf);
+ vim_free(buf);
+ return retval;
+}
+
+/*
+ * Add the tags matching the specified pattern "pat" to the list "list"
+ * as a dictionary. Use "buf_fname" for priority, unless NULL.
+ */
+ int
+get_tags(list_T *list, char_u *pat, char_u *buf_fname)
+{
+ int num_matches, i, ret;
+ char_u **matches, *p;
+ char_u *full_fname;
+ dict_T *dict;
+ tagptrs_T tp;
+ long is_static;
+
+ ret = find_tags(pat, &num_matches, &matches,
+ TAG_REGEXP | TAG_NOIC, (int)MAXCOL, buf_fname);
+ if (ret == OK && num_matches > 0)
+ {
+ for (i = 0; i < num_matches; ++i)
+ {
+ parse_match(matches[i], &tp);
+ is_static = test_for_static(&tp);
+
+ /* Skip pseudo-tag lines. */
+ if (STRNCMP(tp.tagname, "!_TAG_", 6) == 0)
+ continue;
+
+ if ((dict = dict_alloc()) == NULL)
+ ret = FAIL;
+ if (list_append_dict(list, dict) == FAIL)
+ ret = FAIL;
+
+ full_fname = tag_full_fname(&tp);
+ if (add_tag_field(dict, "name", tp.tagname, tp.tagname_end) == FAIL
+ || add_tag_field(dict, "filename", full_fname,
+ NULL) == FAIL
+ || add_tag_field(dict, "cmd", tp.command,
+ tp.command_end) == FAIL
+ || add_tag_field(dict, "kind", tp.tagkind,
+ tp.tagkind_end) == FAIL
+ || dict_add_number(dict, "static", is_static) == FAIL)
+ ret = FAIL;
+
+ vim_free(full_fname);
+
+ if (tp.command_end != NULL)
+ {
+ for (p = tp.command_end + 3;
+ *p != NUL && *p != '\n' && *p != '\r'; ++p)
+ {
+ if (p == tp.tagkind || (p + 5 == tp.tagkind
+ && STRNCMP(p, "kind:", 5) == 0))
+ /* skip "kind:<kind>" and "<kind>" */
+ p = tp.tagkind_end - 1;
+ else if (STRNCMP(p, "file:", 5) == 0)
+ /* skip "file:" (static tag) */
+ p += 4;
+ else if (!VIM_ISWHITE(*p))
+ {
+ char_u *s, *n;
+ int len;
+
+ /* Add extra field as a dict entry. Fields are
+ * separated by Tabs. */
+ n = p;
+ while (*p != NUL && *p >= ' ' && *p < 127 && *p != ':')
+ ++p;
+ len = (int)(p - n);
+ if (*p == ':' && len > 0)
+ {
+ s = ++p;
+ while (*p != NUL && *p >= ' ')
+ ++p;
+ n[len] = NUL;
+ if (add_tag_field(dict, (char *)n, s, p) == FAIL)
+ ret = FAIL;
+ n[len] = ':';
+ }
+ else
+ /* Skip field without colon. */
+ while (*p != NUL && *p >= ' ')
+ ++p;
+ if (*p == NUL)
+ break;
+ }
+ }
+ }
+
+ vim_free(matches[i]);
+ }
+ vim_free(matches);
+ }
+ return ret;
+}
+
+/*
+ * Return information about 'tag' in dict 'retdict'.
+ */
+ static void
+get_tag_details(taggy_T *tag, dict_T *retdict)
+{
+ list_T *pos;
+ fmark_T *fmark;
+
+ dict_add_string(retdict, "tagname", tag->tagname);
+ dict_add_number(retdict, "matchnr", tag->cur_match + 1);
+ dict_add_number(retdict, "bufnr", tag->cur_fnum);
+
+ if ((pos = list_alloc_id(aid_tagstack_from)) == NULL)
+ return;
+ dict_add_list(retdict, "from", pos);
+
+ fmark = &tag->fmark;
+ list_append_number(pos,
+ (varnumber_T)(fmark->fnum != -1 ? fmark->fnum : 0));
+ list_append_number(pos, (varnumber_T)fmark->mark.lnum);
+ list_append_number(pos, (varnumber_T)(fmark->mark.col == MAXCOL ?
+ MAXCOL : fmark->mark.col + 1));
+ list_append_number(pos, (varnumber_T)fmark->mark.coladd);
+}
+
+/*
+ * Return the tag stack entries of the specified window 'wp' in dictionary
+ * 'retdict'.
+ */
+ void
+get_tagstack(win_T *wp, dict_T *retdict)
+{
+ list_T *l;
+ int i;
+ dict_T *d;
+
+ dict_add_number(retdict, "length", wp->w_tagstacklen);
+ dict_add_number(retdict, "curidx", wp->w_tagstackidx + 1);
+ l = list_alloc_id(aid_tagstack_items);
+ if (l == NULL)
+ return;
+ dict_add_list(retdict, "items", l);
+
+ for (i = 0; i < wp->w_tagstacklen; i++)
+ {
+ if ((d = dict_alloc_id(aid_tagstack_details)) == NULL)
+ return;
+ list_append_dict(l, d);
+
+ get_tag_details(&wp->w_tagstack[i], d);
+ }
+}
+
+/*
+ * Free all the entries in the tag stack of the specified window
+ */
+ static void
+tagstack_clear(win_T *wp)
+{
+ int i;
+
+ // Free the current tag stack
+ for (i = 0; i < wp->w_tagstacklen; ++i)
+ vim_free(wp->w_tagstack[i].tagname);
+ wp->w_tagstacklen = 0;
+ wp->w_tagstackidx = 0;
+}
+
+/*
+ * Remove the oldest entry from the tag stack and shift the rest of
+ * the entires to free up the top of the stack.
+ */
+ static void
+tagstack_shift(win_T *wp)
+{
+ taggy_T *tagstack = wp->w_tagstack;
+ int i;
+
+ vim_free(tagstack[0].tagname);
+ for (i = 1; i < wp->w_tagstacklen; ++i)
+ tagstack[i - 1] = tagstack[i];
+ wp->w_tagstacklen--;
+}
+
+/*
+ * Push a new item to the tag stack
+ */
+ static void
+tagstack_push_item(
+ win_T *wp,
+ char_u *tagname,
+ int cur_fnum,
+ int cur_match,
+ pos_T mark,
+ int fnum)
+{
+ taggy_T *tagstack = wp->w_tagstack;
+ int idx = wp->w_tagstacklen; // top of the stack
+
+ // if the tagstack is full: remove the oldest entry
+ if (idx >= TAGSTACKSIZE)
+ {
+ tagstack_shift(wp);
+ idx = TAGSTACKSIZE - 1;
+ }
+
+ wp->w_tagstacklen++;
+ tagstack[idx].tagname = tagname;
+ tagstack[idx].cur_fnum = cur_fnum;
+ tagstack[idx].cur_match = cur_match;
+ if (tagstack[idx].cur_match < 0)
+ tagstack[idx].cur_match = 0;
+ tagstack[idx].fmark.mark = mark;
+ tagstack[idx].fmark.fnum = fnum;
+}
+
+/*
+ * Add a list of items to the tag stack in the specified window
+ */
+ static void
+tagstack_push_items(win_T *wp, list_T *l)
+{
+ listitem_T *li;
+ dictitem_T *di;
+ dict_T *itemdict;
+ char_u *tagname;
+ pos_T mark;
+ int fnum;
+
+ // Add one entry at a time to the tag stack
+ for (li = l->lv_first; li != NULL; li = li->li_next)
+ {
+ if (li->li_tv.v_type != VAR_DICT || li->li_tv.vval.v_dict == NULL)
+ continue; // Skip non-dict items
+ itemdict = li->li_tv.vval.v_dict;
+
+ // parse 'from' for the cursor position before the tag jump
+ if ((di = dict_find(itemdict, (char_u *)"from", -1)) == NULL)
+ continue;
+ if (list2fpos(&di->di_tv, &mark, &fnum, NULL) != OK)
+ continue;
+ if ((tagname =
+ dict_get_string(itemdict, (char_u *)"tagname", TRUE)) == NULL)
+ continue;
+
+ if (mark.col > 0)
+ mark.col--;
+ tagstack_push_item(wp, tagname,
+ (int)dict_get_number(itemdict, (char_u *)"bufnr"),
+ (int)dict_get_number(itemdict, (char_u *)"matchnr") - 1,
+ mark, fnum);
+ }
+}
+
+/*
+ * Set the current index in the tag stack. Valid values are between 0
+ * and the stack length (inclusive).
+ */
+ static void
+tagstack_set_curidx(win_T *wp, int curidx)
+{
+ wp->w_tagstackidx = curidx;
+ if (wp->w_tagstackidx < 0) // sanity check
+ wp->w_tagstackidx = 0;
+ if (wp->w_tagstackidx > wp->w_tagstacklen)
+ wp->w_tagstackidx = wp->w_tagstacklen;
+}
+
+/*
+ * Set the tag stack entries of the specified window.
+ * 'action' is set to either 'a' for append or 'r' for replace.
+ */
+ int
+set_tagstack(win_T *wp, dict_T *d, int action)
+{
+ dictitem_T *di;
+ list_T *l;
+
+ if ((di = dict_find(d, (char_u *)"items", -1)) != NULL)
+ {
+ if (di->di_tv.v_type != VAR_LIST)
+ {
+ emsg(_(e_listreq));
+ return FAIL;
+ }
+ l = di->di_tv.vval.v_list;
+
+ if (action == 'r')
+ tagstack_clear(wp);
+
+ tagstack_push_items(wp, l);
+ }
+
+ if ((di = dict_find(d, (char_u *)"curidx", -1)) != NULL)
+ tagstack_set_curidx(wp, (int)tv_get_number(&di->di_tv) - 1);
+
+ return OK;
+}
+#endif
diff --git a/src/tearoff.bmp b/src/tearoff.bmp
new file mode 100644
index 0000000..8a4313b
--- /dev/null
+++ b/src/tearoff.bmp
Binary files differ
diff --git a/src/tee/Make_mvc.mak b/src/tee/Make_mvc.mak
new file mode 100644
index 0000000..950100d
--- /dev/null
+++ b/src/tee/Make_mvc.mak
@@ -0,0 +1,19 @@
+# A very (if not the most) simplistic Makefile for MSVC
+
+SUBSYSTEM = console
+!if "$(SUBSYSTEM_VER)" != ""
+SUBSYSTEM = $(SUBSYSTEM),$(SUBSYSTEM_VER)
+!endif
+
+CC=cl
+CFLAGS=/O2 /nologo
+
+tee.exe: tee.obj
+ $(CC) $(CFLAGS) /Fo$@ $** /link /subsystem:$(SUBSYSTEM)
+
+tee.obj: tee.c
+ $(CC) $(CFLAGS) /c $**
+
+clean:
+ - del tee.obj
+ - del tee.exe
diff --git a/src/tee/Makefile b/src/tee/Makefile
new file mode 100644
index 0000000..7419913
--- /dev/null
+++ b/src/tee/Makefile
@@ -0,0 +1,21 @@
+# A very (if not the most) simplistic Makefile for MS-Windows and OS/2
+
+CC=gcc
+CFLAGS=-O2 -fno-strength-reduce
+
+ifneq (sh.exe, $(SHELL))
+DEL = rm
+else
+DEL = del
+endif
+
+tee.exe: tee.o
+ $(CC) $(CFLAGS) -s -o $@ $<
+
+tee.o: tee.c
+ $(CC) $(CFLAGS) -c $<
+
+clean:
+ - $(DEL) tee.o
+ - $(DEL) tee.exe
+
diff --git a/src/tee/tee.c b/src/tee/tee.c
new file mode 100644
index 0000000..c668d2d
--- /dev/null
+++ b/src/tee/tee.c
@@ -0,0 +1,161 @@
+/* vim:set ts=4 sw=4:
+ *
+ * Copyright (c) 1996, Paul Slootman
+ *
+ * Author: Paul Slootman
+ * (paul@wurtel.hobby.nl, paul@murphy.nl, paulS@toecompst.nl)
+ * Modifications for MSVC: Yasuhiro Matsumoto
+ *
+ * This source code is released into the public domain. It is provided on an
+ * as-is basis and no responsibility is accepted for its failure to perform
+ * as expected. It is worth at least as much as you paid for it!
+ *
+ * tee.c - pipe fitting
+ *
+ * tee reads stdin, and writes what it reads to each of the specified
+ * files. The primary reason of existence for this version is a quick
+ * and dirty implementation to distribute with Vim, to make one of the
+ * most useful features of Vim possible on OS/2: quickfix.
+ *
+ * Of course, not using tee but instead redirecting make's output directly
+ * into a temp file and then processing that is possible, but if we have a
+ * system capable of correctly piping (unlike DOS, for example), why not
+ * use it as well as possible? This tee should also work on other systems,
+ * but it's not been tested there, only on OS/2.
+ *
+ * tee is also available in the GNU shellutils package, which is available
+ * precompiled for OS/2. That one probably works better.
+ */
+
+#ifndef _MSC_VER
+# include <unistd.h>
+#endif
+#include <malloc.h>
+#include <stdio.h>
+#include <fcntl.h>
+
+#ifdef _WIN32
+# define sysconf(x) -1
+#endif
+
+void usage(void)
+{
+ fprintf(stderr,
+"tee usage:\n\
+\ttee [-a] file ... file_n\n\
+\n\
+\t-a\tappend to files instead of truncating\n\
+\nTee reads its input, and writes to each of the specified files,\n\
+as well as to the standard output.\n\
+\n\
+This version supplied with Vim 4.2 to make ':make' possible.\n\
+For a more complete and stable version, consider getting\n\
+[a port of] the GNU shellutils package.\n\
+");
+}
+
+/*
+ * fread only returns when count is read or at EOF.
+ * We could use fgets, but I want to be able to handle binary blubber.
+ */
+
+int
+myfread(char *buf, int elsize /*ignored*/, int max, FILE *fp)
+{
+ int c;
+ int n = 0;
+
+ while ((n < max) && ((c = getchar()) != EOF))
+ {
+ *(buf++) = c;
+ n++;
+ if (c == '\n' || c == '\r')
+ break;
+ }
+ return n;
+}
+
+
+void
+main(int argc, char *argv[])
+{
+ int append = 0;
+ int numfiles;
+ int opt;
+ int maxfiles;
+ FILE **filepointers;
+ int i;
+ char buf[BUFSIZ];
+ int n;
+ int optind = 1;
+
+ for (i = 1; i < argc; i++)
+ {
+ if (argv[i][0] != '-')
+ break;
+ if (!strcmp(argv[i], "-a"))
+ append++;
+ else
+ usage();
+ optind++;
+ }
+
+ numfiles = argc - optind;
+
+ if (numfiles == 0)
+ {
+ fprintf(stderr, "doesn't make much sense using tee without any file name arguments...\n");
+ usage();
+ exit(2);
+ }
+
+ maxfiles = sysconf(_SC_OPEN_MAX); /* or fill in 10 or so */
+ if (maxfiles < 0)
+ maxfiles = 10;
+ if (numfiles + 3 > maxfiles) /* +3 accounts for stdin, out, err */
+ {
+ fprintf(stderr, "Sorry, there is a limit of max %d files.\n", maxfiles - 3);
+ exit(1);
+ }
+ filepointers = calloc(numfiles, sizeof(FILE *));
+ if (filepointers == NULL)
+ {
+ fprintf(stderr, "Error allocating memory for %d files\n", numfiles);
+ exit(1);
+ }
+ for (i = 0; i < numfiles; i++)
+ {
+ filepointers[i] = fopen(argv[i+optind], append ? "ab" : "wb");
+ if (filepointers[i] == NULL)
+ {
+ fprintf(stderr, "Can't open \"%s\"\n", argv[i+optind]);
+ exit(1);
+ }
+ }
+ setmode(fileno(stdin), O_BINARY);
+ fflush(stdout); /* needed for _fsetmode(stdout) */
+ setmode(fileno(stdout), O_BINARY);
+
+ while ((n = myfread(buf, sizeof(char), sizeof(buf), stdin)) > 0)
+ {
+ fwrite(buf, sizeof(char), n, stdout);
+ fflush(stdout);
+ for (i = 0; i < numfiles; i++)
+ {
+ if (filepointers[i] &&
+ fwrite(buf, sizeof(char), n, filepointers[i]) != n)
+ {
+ fprintf(stderr, "Error writing to file \"%s\"\n", argv[i+optind]);
+ fclose(filepointers[i]);
+ filepointers[i] = NULL;
+ }
+ }
+ }
+ for (i = 0; i < numfiles; i++)
+ {
+ if (filepointers[i])
+ fclose(filepointers[i]);
+ }
+
+ exit(0);
+}
diff --git a/src/term.c b/src/term.c
new file mode 100644
index 0000000..47d2bda
--- /dev/null
+++ b/src/term.c
@@ -0,0 +1,7152 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+/*
+ *
+ * term.c: functions for controlling the terminal
+ *
+ * primitive termcap support for Amiga and Win32 included
+ *
+ * NOTE: padding and variable substitution is not performed,
+ * when compiling without HAVE_TGETENT, we use tputs() and tgoto() dummies.
+ */
+
+/*
+ * Some systems have a prototype for tgetstr() with (char *) instead of
+ * (char **). This define removes that prototype. We include our own prototype
+ * below.
+ */
+
+#define tgetstr tgetstr_defined_wrong
+#include "vim.h"
+
+#ifdef HAVE_TGETENT
+# ifdef HAVE_TERMIOS_H
+# include <termios.h> /* seems to be required for some Linux */
+# endif
+# ifdef HAVE_TERMCAP_H
+# include <termcap.h>
+# endif
+
+/*
+ * A few linux systems define outfuntype in termcap.h to be used as the third
+ * argument for tputs().
+ */
+# ifdef VMS
+# define TPUTSFUNCAST
+# else
+# ifdef HAVE_OUTFUNTYPE
+# define TPUTSFUNCAST (outfuntype)
+# else
+# define TPUTSFUNCAST (int (*)())
+# endif
+# endif
+#endif
+
+#undef tgetstr
+
+/*
+ * Here are the builtin termcap entries. They are not stored as complete
+ * structures with all entries, as such a structure is too big.
+ *
+ * The entries are compact, therefore they normally are included even when
+ * HAVE_TGETENT is defined. When HAVE_TGETENT is defined, the builtin entries
+ * can be accessed with "builtin_amiga", "builtin_ansi", "builtin_debug", etc.
+ *
+ * Each termcap is a list of builtin_term structures. It always starts with
+ * KS_NAME, which separates the entries. See parse_builtin_tcap() for all
+ * details.
+ * bt_entry is either a KS_xxx code (>= 0), or a K_xxx code.
+ *
+ * Entries marked with "guessed" may be wrong.
+ */
+struct builtin_term
+{
+ int bt_entry;
+ char *bt_string;
+};
+
+/* start of keys that are not directly used by Vim but can be mapped */
+#define BT_EXTRA_KEYS 0x101
+
+static void parse_builtin_tcap(char_u *s);
+static void gather_termleader(void);
+#ifdef FEAT_TERMRESPONSE
+static void req_codes_from_term(void);
+static void req_more_codes_from_term(void);
+static void got_code_from_term(char_u *code, int len);
+static void check_for_codes_from_term(void);
+#endif
+#if defined(FEAT_GUI) \
+ || (defined(FEAT_MOUSE) && (!defined(UNIX) || defined(FEAT_MOUSE_XTERM) \
+ || defined(FEAT_MOUSE_GPM) || defined(FEAT_SYSMOUSE)))
+static int get_bytes_from_buf(char_u *, char_u *, int);
+#endif
+static void del_termcode_idx(int idx);
+static int term_is_builtin(char_u *name);
+static int term_7to8bit(char_u *p);
+
+#ifdef HAVE_TGETENT
+static char *tgetent_error(char_u *, char_u *);
+
+/*
+ * Here is our own prototype for tgetstr(), any prototypes from the include
+ * files have been disabled by the define at the start of this file.
+ */
+char *tgetstr(char *, char **);
+
+# ifdef FEAT_TERMRESPONSE
+ /* Change this to "if 1" to debug what happens with termresponse. */
+# if 0
+# define DEBUG_TERMRESPONSE
+static void log_tr(const char *fmt, ...);
+# define LOG_TR(msg) log_tr msg
+# else
+# define LOG_TR(msg) do { /**/ } while (0)
+# endif
+
+# define STATUS_GET 1 /* send request when switching to RAW mode */
+# define STATUS_SENT 2 /* did send request, waiting for response */
+# define STATUS_GOT 3 /* received response */
+
+/* Request Terminal Version status: */
+static int crv_status = STATUS_GET;
+
+/* Request Cursor position report: */
+static int u7_status = STATUS_GET;
+
+# ifdef FEAT_TERMINAL
+/* Request foreground color report: */
+static int rfg_status = STATUS_GET;
+static int fg_r = 0;
+static int fg_g = 0;
+static int fg_b = 0;
+static int bg_r = 255;
+static int bg_g = 255;
+static int bg_b = 255;
+# endif
+
+/* Request background color report: */
+static int rbg_status = STATUS_GET;
+
+/* Request cursor blinking mode report: */
+static int rbm_status = STATUS_GET;
+
+/* Request cursor style report: */
+static int rcs_status = STATUS_GET;
+
+/* Request windos position report: */
+static int winpos_status = STATUS_GET;
+# endif
+
+/*
+ * Don't declare these variables if termcap.h contains them.
+ * Autoconf checks if these variables should be declared extern (not all
+ * systems have them).
+ * Some versions define ospeed to be speed_t, but that is incompatible with
+ * BSD, where ospeed is short and speed_t is long.
+ */
+# ifndef HAVE_OSPEED
+# ifdef OSPEED_EXTERN
+extern short ospeed;
+# else
+short ospeed;
+# endif
+# endif
+# ifndef HAVE_UP_BC_PC
+# ifdef UP_BC_PC_EXTERN
+extern char *UP, *BC, PC;
+# else
+char *UP, *BC, PC;
+# endif
+# endif
+
+# define TGETSTR(s, p) vim_tgetstr((s), (p))
+# define TGETENT(b, t) tgetent((char *)(b), (char *)(t))
+static char_u *vim_tgetstr(char *s, char_u **pp);
+#endif /* HAVE_TGETENT */
+
+static int detected_8bit = FALSE; /* detected 8-bit terminal */
+
+#ifdef FEAT_TERMRESPONSE
+/* When the cursor shape was detected these values are used:
+ * 1: block, 2: underline, 3: vertical bar */
+static int initial_cursor_shape = 0;
+
+/* The blink flag from the style response may be inverted from the actual
+ * blinking state, xterm XORs the flags. */
+static int initial_cursor_shape_blink = FALSE;
+
+/* The blink flag from the blinking-cursor mode response */
+static int initial_cursor_blink = FALSE;
+#endif
+
+static struct builtin_term builtin_termcaps[] =
+{
+
+#if defined(FEAT_GUI)
+/*
+ * GUI pseudo term-cap.
+ */
+ {(int)KS_NAME, "gui"},
+ {(int)KS_CE, IF_EB("\033|$", ESC_STR "|$")},
+ {(int)KS_AL, IF_EB("\033|i", ESC_STR "|i")},
+# ifdef TERMINFO
+ {(int)KS_CAL, IF_EB("\033|%p1%dI", ESC_STR "|%p1%dI")},
+# else
+ {(int)KS_CAL, IF_EB("\033|%dI", ESC_STR "|%dI")},
+# endif
+ {(int)KS_DL, IF_EB("\033|d", ESC_STR "|d")},
+# ifdef TERMINFO
+ {(int)KS_CDL, IF_EB("\033|%p1%dD", ESC_STR "|%p1%dD")},
+ {(int)KS_CS, IF_EB("\033|%p1%d;%p2%dR", ESC_STR "|%p1%d;%p2%dR")},
+ {(int)KS_CSV, IF_EB("\033|%p1%d;%p2%dV", ESC_STR "|%p1%d;%p2%dV")},
+# else
+ {(int)KS_CDL, IF_EB("\033|%dD", ESC_STR "|%dD")},
+ {(int)KS_CS, IF_EB("\033|%d;%dR", ESC_STR "|%d;%dR")},
+ {(int)KS_CSV, IF_EB("\033|%d;%dV", ESC_STR "|%d;%dV")},
+# endif
+ {(int)KS_CL, IF_EB("\033|C", ESC_STR "|C")},
+ /* attributes switched on with 'h', off with * 'H' */
+ {(int)KS_ME, IF_EB("\033|31H", ESC_STR "|31H")}, /* HL_ALL */
+ {(int)KS_MR, IF_EB("\033|1h", ESC_STR "|1h")}, /* HL_INVERSE */
+ {(int)KS_MD, IF_EB("\033|2h", ESC_STR "|2h")}, /* HL_BOLD */
+ {(int)KS_SE, IF_EB("\033|16H", ESC_STR "|16H")}, /* HL_STANDOUT */
+ {(int)KS_SO, IF_EB("\033|16h", ESC_STR "|16h")}, /* HL_STANDOUT */
+ {(int)KS_UE, IF_EB("\033|8H", ESC_STR "|8H")}, /* HL_UNDERLINE */
+ {(int)KS_US, IF_EB("\033|8h", ESC_STR "|8h")}, /* HL_UNDERLINE */
+ {(int)KS_UCE, IF_EB("\033|8C", ESC_STR "|8C")}, /* HL_UNDERCURL */
+ {(int)KS_UCS, IF_EB("\033|8c", ESC_STR "|8c")}, /* HL_UNDERCURL */
+ {(int)KS_STE, IF_EB("\033|4C", ESC_STR "|4C")}, /* HL_STRIKETHROUGH */
+ {(int)KS_STS, IF_EB("\033|4c", ESC_STR "|4c")}, /* HL_STRIKETHROUGH */
+ {(int)KS_CZR, IF_EB("\033|4H", ESC_STR "|4H")}, /* HL_ITALIC */
+ {(int)KS_CZH, IF_EB("\033|4h", ESC_STR "|4h")}, /* HL_ITALIC */
+ {(int)KS_VB, IF_EB("\033|f", ESC_STR "|f")},
+ {(int)KS_MS, "y"},
+ {(int)KS_UT, "y"},
+ {(int)KS_XN, "y"},
+ {(int)KS_LE, "\b"}, /* cursor-left = BS */
+ {(int)KS_ND, "\014"}, /* cursor-right = CTRL-L */
+# ifdef TERMINFO
+ {(int)KS_CM, IF_EB("\033|%p1%d;%p2%dM", ESC_STR "|%p1%d;%p2%dM")},
+# else
+ {(int)KS_CM, IF_EB("\033|%d;%dM", ESC_STR "|%d;%dM")},
+# endif
+ /* there are no key sequences here, the GUI sequences are recognized
+ * in check_termcode() */
+#endif
+
+#ifndef NO_BUILTIN_TCAPS
+
+# if defined(AMIGA) || defined(ALL_BUILTIN_TCAPS)
+/*
+ * Amiga console window, default for Amiga
+ */
+ {(int)KS_NAME, "amiga"},
+ {(int)KS_CE, "\033[K"},
+ {(int)KS_CD, "\033[J"},
+ {(int)KS_AL, "\033[L"},
+# ifdef TERMINFO
+ {(int)KS_CAL, "\033[%p1%dL"},
+# else
+ {(int)KS_CAL, "\033[%dL"},
+# endif
+ {(int)KS_DL, "\033[M"},
+# ifdef TERMINFO
+ {(int)KS_CDL, "\033[%p1%dM"},
+# else
+ {(int)KS_CDL, "\033[%dM"},
+# endif
+ {(int)KS_CL, "\014"},
+ {(int)KS_VI, "\033[0 p"},
+ {(int)KS_VE, "\033[1 p"},
+ {(int)KS_ME, "\033[0m"},
+ {(int)KS_MR, "\033[7m"},
+ {(int)KS_MD, "\033[1m"},
+ {(int)KS_SE, "\033[0m"},
+ {(int)KS_SO, "\033[33m"},
+ {(int)KS_US, "\033[4m"},
+ {(int)KS_UE, "\033[0m"},
+ {(int)KS_CZH, "\033[3m"},
+ {(int)KS_CZR, "\033[0m"},
+#if defined(__MORPHOS__) || defined(__AROS__)
+ {(int)KS_CCO, "8"}, /* allow 8 colors */
+# ifdef TERMINFO
+ {(int)KS_CAB, "\033[4%p1%dm"},/* set background color */
+ {(int)KS_CAF, "\033[3%p1%dm"},/* set foreground color */
+# else
+ {(int)KS_CAB, "\033[4%dm"}, /* set background color */
+ {(int)KS_CAF, "\033[3%dm"}, /* set foreground color */
+# endif
+ {(int)KS_OP, "\033[m"}, /* reset colors */
+#endif
+ {(int)KS_MS, "y"},
+ {(int)KS_UT, "y"}, /* guessed */
+ {(int)KS_LE, "\b"},
+# ifdef TERMINFO
+ {(int)KS_CM, "\033[%i%p1%d;%p2%dH"},
+# else
+ {(int)KS_CM, "\033[%i%d;%dH"},
+# endif
+#if defined(__MORPHOS__)
+ {(int)KS_SR, "\033M"},
+#endif
+# ifdef TERMINFO
+ {(int)KS_CRI, "\033[%p1%dC"},
+# else
+ {(int)KS_CRI, "\033[%dC"},
+# endif
+ {K_UP, "\233A"},
+ {K_DOWN, "\233B"},
+ {K_LEFT, "\233D"},
+ {K_RIGHT, "\233C"},
+ {K_S_UP, "\233T"},
+ {K_S_DOWN, "\233S"},
+ {K_S_LEFT, "\233 A"},
+ {K_S_RIGHT, "\233 @"},
+ {K_S_TAB, "\233Z"},
+ {K_F1, "\233\060~"},/* some compilers don't dig "\2330" */
+ {K_F2, "\233\061~"},
+ {K_F3, "\233\062~"},
+ {K_F4, "\233\063~"},
+ {K_F5, "\233\064~"},
+ {K_F6, "\233\065~"},
+ {K_F7, "\233\066~"},
+ {K_F8, "\233\067~"},
+ {K_F9, "\233\070~"},
+ {K_F10, "\233\071~"},
+ {K_S_F1, "\233\061\060~"},
+ {K_S_F2, "\233\061\061~"},
+ {K_S_F3, "\233\061\062~"},
+ {K_S_F4, "\233\061\063~"},
+ {K_S_F5, "\233\061\064~"},
+ {K_S_F6, "\233\061\065~"},
+ {K_S_F7, "\233\061\066~"},
+ {K_S_F8, "\233\061\067~"},
+ {K_S_F9, "\233\061\070~"},
+ {K_S_F10, "\233\061\071~"},
+ {K_HELP, "\233?~"},
+ {K_INS, "\233\064\060~"}, /* 101 key keyboard */
+ {K_PAGEUP, "\233\064\061~"}, /* 101 key keyboard */
+ {K_PAGEDOWN, "\233\064\062~"}, /* 101 key keyboard */
+ {K_HOME, "\233\064\064~"}, /* 101 key keyboard */
+ {K_END, "\233\064\065~"}, /* 101 key keyboard */
+
+ {BT_EXTRA_KEYS, ""},
+ {TERMCAP2KEY('#', '2'), "\233\065\064~"}, /* shifted home key */
+ {TERMCAP2KEY('#', '3'), "\233\065\060~"}, /* shifted insert key */
+ {TERMCAP2KEY('*', '7'), "\233\065\065~"}, /* shifted end key */
+# endif
+
+# if defined(__BEOS__) || defined(ALL_BUILTIN_TCAPS)
+/*
+ * almost standard ANSI terminal, default for bebox
+ */
+ {(int)KS_NAME, "beos-ansi"},
+ {(int)KS_CE, "\033[K"},
+ {(int)KS_CD, "\033[J"},
+ {(int)KS_AL, "\033[L"},
+# ifdef TERMINFO
+ {(int)KS_CAL, "\033[%p1%dL"},
+# else
+ {(int)KS_CAL, "\033[%dL"},
+# endif
+ {(int)KS_DL, "\033[M"},
+# ifdef TERMINFO
+ {(int)KS_CDL, "\033[%p1%dM"},
+# else
+ {(int)KS_CDL, "\033[%dM"},
+# endif
+#ifdef BEOS_PR_OR_BETTER
+# ifdef TERMINFO
+ {(int)KS_CS, "\033[%i%p1%d;%p2%dr"},
+# else
+ {(int)KS_CS, "\033[%i%d;%dr"}, /* scroll region */
+# endif
+#endif
+ {(int)KS_CL, "\033[H\033[2J"},
+#ifdef notyet
+ {(int)KS_VI, "[VI]"}, /* cursor invisible, VT320: CSI ? 25 l */
+ {(int)KS_VE, "[VE]"}, /* cursor visible, VT320: CSI ? 25 h */
+#endif
+ {(int)KS_ME, "\033[m"}, /* normal mode */
+ {(int)KS_MR, "\033[7m"}, /* reverse */
+ {(int)KS_MD, "\033[1m"}, /* bold */
+ {(int)KS_SO, "\033[31m"}, /* standout mode: red */
+ {(int)KS_SE, "\033[m"}, /* standout end */
+ {(int)KS_CZH, "\033[35m"}, /* italic: purple */
+ {(int)KS_CZR, "\033[m"}, /* italic end */
+ {(int)KS_US, "\033[4m"}, /* underscore mode */
+ {(int)KS_UE, "\033[m"}, /* underscore end */
+ {(int)KS_CCO, "8"}, /* allow 8 colors */
+# ifdef TERMINFO
+ {(int)KS_CAB, "\033[4%p1%dm"},/* set background color */
+ {(int)KS_CAF, "\033[3%p1%dm"},/* set foreground color */
+# else
+ {(int)KS_CAB, "\033[4%dm"}, /* set background color */
+ {(int)KS_CAF, "\033[3%dm"}, /* set foreground color */
+# endif
+ {(int)KS_OP, "\033[m"}, /* reset colors */
+ {(int)KS_MS, "y"}, /* safe to move cur in reverse mode */
+ {(int)KS_UT, "y"}, /* guessed */
+ {(int)KS_LE, "\b"},
+# ifdef TERMINFO
+ {(int)KS_CM, "\033[%i%p1%d;%p2%dH"},
+# else
+ {(int)KS_CM, "\033[%i%d;%dH"},
+# endif
+ {(int)KS_SR, "\033M"},
+# ifdef TERMINFO
+ {(int)KS_CRI, "\033[%p1%dC"},
+# else
+ {(int)KS_CRI, "\033[%dC"},
+# endif
+# if defined(BEOS_DR8)
+ {(int)KS_DB, ""}, /* hack! see screen.c */
+# endif
+
+ {K_UP, "\033[A"},
+ {K_DOWN, "\033[B"},
+ {K_LEFT, "\033[D"},
+ {K_RIGHT, "\033[C"},
+# endif
+
+# if defined(UNIX) || defined(ALL_BUILTIN_TCAPS) || defined(SOME_BUILTIN_TCAPS)
+/*
+ * standard ANSI terminal, default for unix
+ */
+ {(int)KS_NAME, "ansi"},
+ {(int)KS_CE, IF_EB("\033[K", ESC_STR "[K")},
+ {(int)KS_AL, IF_EB("\033[L", ESC_STR "[L")},
+# ifdef TERMINFO
+ {(int)KS_CAL, IF_EB("\033[%p1%dL", ESC_STR "[%p1%dL")},
+# else
+ {(int)KS_CAL, IF_EB("\033[%dL", ESC_STR "[%dL")},
+# endif
+ {(int)KS_DL, IF_EB("\033[M", ESC_STR "[M")},
+# ifdef TERMINFO
+ {(int)KS_CDL, IF_EB("\033[%p1%dM", ESC_STR "[%p1%dM")},
+# else
+ {(int)KS_CDL, IF_EB("\033[%dM", ESC_STR "[%dM")},
+# endif
+ {(int)KS_CL, IF_EB("\033[H\033[2J", ESC_STR "[H" ESC_STR_nc "[2J")},
+ {(int)KS_ME, IF_EB("\033[0m", ESC_STR "[0m")},
+ {(int)KS_MR, IF_EB("\033[7m", ESC_STR "[7m")},
+ {(int)KS_MS, "y"},
+ {(int)KS_UT, "y"}, /* guessed */
+ {(int)KS_LE, "\b"},
+# ifdef TERMINFO
+ {(int)KS_CM, IF_EB("\033[%i%p1%d;%p2%dH", ESC_STR "[%i%p1%d;%p2%dH")},
+# else
+ {(int)KS_CM, IF_EB("\033[%i%d;%dH", ESC_STR "[%i%d;%dH")},
+# endif
+# ifdef TERMINFO
+ {(int)KS_CRI, IF_EB("\033[%p1%dC", ESC_STR "[%p1%dC")},
+# else
+ {(int)KS_CRI, IF_EB("\033[%dC", ESC_STR "[%dC")},
+# endif
+# endif
+
+# if defined(ALL_BUILTIN_TCAPS)
+/*
+ * These codes are valid when nansi.sys or equivalent has been installed.
+ * Function keys on a PC are preceded with a NUL. These are converted into
+ * K_NUL '\316' in mch_inchar(), because we cannot handle NULs in key codes.
+ * CTRL-arrow is used instead of SHIFT-arrow.
+ */
+ {(int)KS_NAME, "pcansi"},
+ {(int)KS_DL, "\033[M"},
+ {(int)KS_AL, "\033[L"},
+ {(int)KS_CE, "\033[K"},
+ {(int)KS_CL, "\033[2J"},
+ {(int)KS_ME, "\033[0m"},
+ {(int)KS_MR, "\033[5m"}, /* reverse: black on lightgrey */
+ {(int)KS_MD, "\033[1m"}, /* bold: white text */
+ {(int)KS_SE, "\033[0m"}, /* standout end */
+ {(int)KS_SO, "\033[31m"}, /* standout: white on blue */
+ {(int)KS_CZH, "\033[34;43m"}, /* italic mode: blue text on yellow */
+ {(int)KS_CZR, "\033[0m"}, /* italic mode end */
+ {(int)KS_US, "\033[36;41m"}, /* underscore mode: cyan text on red */
+ {(int)KS_UE, "\033[0m"}, /* underscore mode end */
+ {(int)KS_CCO, "8"}, /* allow 8 colors */
+# ifdef TERMINFO
+ {(int)KS_CAB, "\033[4%p1%dm"},/* set background color */
+ {(int)KS_CAF, "\033[3%p1%dm"},/* set foreground color */
+# else
+ {(int)KS_CAB, "\033[4%dm"}, /* set background color */
+ {(int)KS_CAF, "\033[3%dm"}, /* set foreground color */
+# endif
+ {(int)KS_OP, "\033[0m"}, /* reset colors */
+ {(int)KS_MS, "y"},
+ {(int)KS_UT, "y"}, /* guessed */
+ {(int)KS_LE, "\b"},
+# ifdef TERMINFO
+ {(int)KS_CM, "\033[%i%p1%d;%p2%dH"},
+# else
+ {(int)KS_CM, "\033[%i%d;%dH"},
+# endif
+# ifdef TERMINFO
+ {(int)KS_CRI, "\033[%p1%dC"},
+# else
+ {(int)KS_CRI, "\033[%dC"},
+# endif
+ {K_UP, "\316H"},
+ {K_DOWN, "\316P"},
+ {K_LEFT, "\316K"},
+ {K_RIGHT, "\316M"},
+ {K_S_LEFT, "\316s"},
+ {K_S_RIGHT, "\316t"},
+ {K_F1, "\316;"},
+ {K_F2, "\316<"},
+ {K_F3, "\316="},
+ {K_F4, "\316>"},
+ {K_F5, "\316?"},
+ {K_F6, "\316@"},
+ {K_F7, "\316A"},
+ {K_F8, "\316B"},
+ {K_F9, "\316C"},
+ {K_F10, "\316D"},
+ {K_F11, "\316\205"}, /* guessed */
+ {K_F12, "\316\206"}, /* guessed */
+ {K_S_F1, "\316T"},
+ {K_S_F2, "\316U"},
+ {K_S_F3, "\316V"},
+ {K_S_F4, "\316W"},
+ {K_S_F5, "\316X"},
+ {K_S_F6, "\316Y"},
+ {K_S_F7, "\316Z"},
+ {K_S_F8, "\316["},
+ {K_S_F9, "\316\\"},
+ {K_S_F10, "\316]"},
+ {K_S_F11, "\316\207"}, /* guessed */
+ {K_S_F12, "\316\210"}, /* guessed */
+ {K_INS, "\316R"},
+ {K_DEL, "\316S"},
+ {K_HOME, "\316G"},
+ {K_END, "\316O"},
+ {K_PAGEDOWN, "\316Q"},
+ {K_PAGEUP, "\316I"},
+# endif
+
+# if defined(WIN3264) || defined(ALL_BUILTIN_TCAPS)
+/*
+ * These codes are valid for the Win32 Console . The entries that start with
+ * ESC | are translated into console calls in os_win32.c. The function keys
+ * are also translated in os_win32.c.
+ */
+ {(int)KS_NAME, "win32"},
+ {(int)KS_CE, "\033|K"}, /* clear to end of line */
+ {(int)KS_AL, "\033|L"}, /* add new blank line */
+# ifdef TERMINFO
+ {(int)KS_CAL, "\033|%p1%dL"}, /* add number of new blank lines */
+# else
+ {(int)KS_CAL, "\033|%dL"}, /* add number of new blank lines */
+# endif
+ {(int)KS_DL, "\033|M"}, /* delete line */
+# ifdef TERMINFO
+ {(int)KS_CDL, "\033|%p1%dM"}, /* delete number of lines */
+# else
+ {(int)KS_CDL, "\033|%dM"}, /* delete number of lines */
+# endif
+ {(int)KS_CL, "\033|J"}, /* clear screen */
+ {(int)KS_CD, "\033|j"}, /* clear to end of display */
+ {(int)KS_VI, "\033|v"}, /* cursor invisible */
+ {(int)KS_VE, "\033|V"}, /* cursor visible */
+
+ {(int)KS_ME, "\033|0m"}, /* normal */
+ {(int)KS_MR, "\033|112m"}, /* reverse: black on lightgray */
+ {(int)KS_MD, "\033|15m"}, /* bold: white on black */
+#if 1
+ {(int)KS_SO, "\033|31m"}, /* standout: white on blue */
+ {(int)KS_SE, "\033|0m"}, /* standout end */
+#else
+ {(int)KS_SO, "\033|F"}, /* standout: high intensity */
+ {(int)KS_SE, "\033|f"}, /* standout end */
+#endif
+ {(int)KS_CZH, "\033|225m"}, /* italic: blue text on yellow */
+ {(int)KS_CZR, "\033|0m"}, /* italic end */
+ {(int)KS_US, "\033|67m"}, /* underscore: cyan text on red */
+ {(int)KS_UE, "\033|0m"}, /* underscore end */
+ {(int)KS_CCO, "16"}, /* allow 16 colors */
+# ifdef TERMINFO
+ {(int)KS_CAB, "\033|%p1%db"}, /* set background color */
+ {(int)KS_CAF, "\033|%p1%df"}, /* set foreground color */
+# else
+ {(int)KS_CAB, "\033|%db"}, /* set background color */
+ {(int)KS_CAF, "\033|%df"}, /* set foreground color */
+# endif
+
+ {(int)KS_MS, "y"}, /* save to move cur in reverse mode */
+ {(int)KS_UT, "y"},
+ {(int)KS_XN, "y"},
+ {(int)KS_LE, "\b"},
+# ifdef TERMINFO
+ {(int)KS_CM, "\033|%i%p1%d;%p2%dH"},/* cursor motion */
+# else
+ {(int)KS_CM, "\033|%i%d;%dH"},/* cursor motion */
+# endif
+ {(int)KS_VB, "\033|B"}, /* visual bell */
+ {(int)KS_TI, "\033|S"}, /* put terminal in termcap mode */
+ {(int)KS_TE, "\033|E"}, /* out of termcap mode */
+# ifdef TERMINFO
+ {(int)KS_CS, "\033|%i%p1%d;%p2%dr"},/* scroll region */
+# else
+ {(int)KS_CS, "\033|%i%d;%dr"},/* scroll region */
+# endif
+# ifdef FEAT_TERMGUICOLORS
+ {(int)KS_8F, "\033|38;2;%lu;%lu;%lum"},
+ {(int)KS_8B, "\033|48;2;%lu;%lu;%lum"},
+# endif
+
+ {K_UP, "\316H"},
+ {K_DOWN, "\316P"},
+ {K_LEFT, "\316K"},
+ {K_RIGHT, "\316M"},
+ {K_S_UP, "\316\304"},
+ {K_S_DOWN, "\316\317"},
+ {K_S_LEFT, "\316\311"},
+ {K_C_LEFT, "\316s"},
+ {K_S_RIGHT, "\316\313"},
+ {K_C_RIGHT, "\316t"},
+ {K_S_TAB, "\316\017"},
+ {K_F1, "\316;"},
+ {K_F2, "\316<"},
+ {K_F3, "\316="},
+ {K_F4, "\316>"},
+ {K_F5, "\316?"},
+ {K_F6, "\316@"},
+ {K_F7, "\316A"},
+ {K_F8, "\316B"},
+ {K_F9, "\316C"},
+ {K_F10, "\316D"},
+ {K_F11, "\316\205"},
+ {K_F12, "\316\206"},
+ {K_S_F1, "\316T"},
+ {K_S_F2, "\316U"},
+ {K_S_F3, "\316V"},
+ {K_S_F4, "\316W"},
+ {K_S_F5, "\316X"},
+ {K_S_F6, "\316Y"},
+ {K_S_F7, "\316Z"},
+ {K_S_F8, "\316["},
+ {K_S_F9, "\316\\"},
+ {K_S_F10, "\316]"},
+ {K_S_F11, "\316\207"},
+ {K_S_F12, "\316\210"},
+ {K_INS, "\316R"},
+ {K_DEL, "\316S"},
+ {K_HOME, "\316G"},
+ {K_S_HOME, "\316\302"},
+ {K_C_HOME, "\316w"},
+ {K_END, "\316O"},
+ {K_S_END, "\316\315"},
+ {K_C_END, "\316u"},
+ {K_PAGEDOWN, "\316Q"},
+ {K_PAGEUP, "\316I"},
+ {K_KPLUS, "\316N"},
+ {K_KMINUS, "\316J"},
+ {K_KMULTIPLY, "\316\067"},
+ {K_K0, "\316\332"},
+ {K_K1, "\316\336"},
+ {K_K2, "\316\342"},
+ {K_K3, "\316\346"},
+ {K_K4, "\316\352"},
+ {K_K5, "\316\356"},
+ {K_K6, "\316\362"},
+ {K_K7, "\316\366"},
+ {K_K8, "\316\372"},
+ {K_K9, "\316\376"},
+# endif
+
+# if defined(VMS) || defined(ALL_BUILTIN_TCAPS)
+/*
+ * VT320 is working as an ANSI terminal compatible DEC terminal.
+ * (it covers VT1x0, VT2x0 and VT3x0 up to VT320 on VMS as well)
+ * TODO:- rewrite ESC[ codes to CSI
+ * - keyboard languages (CSI ? 26 n)
+ */
+ {(int)KS_NAME, "vt320"},
+ {(int)KS_CE, IF_EB("\033[K", ESC_STR "[K")},
+ {(int)KS_AL, IF_EB("\033[L", ESC_STR "[L")},
+# ifdef TERMINFO
+ {(int)KS_CAL, IF_EB("\033[%p1%dL", ESC_STR "[%p1%dL")},
+# else
+ {(int)KS_CAL, IF_EB("\033[%dL", ESC_STR "[%dL")},
+# endif
+ {(int)KS_DL, IF_EB("\033[M", ESC_STR "[M")},
+# ifdef TERMINFO
+ {(int)KS_CDL, IF_EB("\033[%p1%dM", ESC_STR "[%p1%dM")},
+# else
+ {(int)KS_CDL, IF_EB("\033[%dM", ESC_STR "[%dM")},
+# endif
+ {(int)KS_CL, IF_EB("\033[H\033[2J", ESC_STR "[H" ESC_STR_nc "[2J")},
+ {(int)KS_CD, IF_EB("\033[J", ESC_STR "[J")},
+ {(int)KS_CCO, "8"}, /* allow 8 colors */
+ {(int)KS_ME, IF_EB("\033[0m", ESC_STR "[0m")},
+ {(int)KS_MR, IF_EB("\033[7m", ESC_STR "[7m")},
+ {(int)KS_MD, IF_EB("\033[1m", ESC_STR "[1m")}, /* bold mode */
+ {(int)KS_SE, IF_EB("\033[22m", ESC_STR "[22m")},/* normal mode */
+ {(int)KS_UE, IF_EB("\033[24m", ESC_STR "[24m")},/* exit underscore mode */
+ {(int)KS_US, IF_EB("\033[4m", ESC_STR "[4m")}, /* underscore mode */
+ {(int)KS_CZH, IF_EB("\033[34;43m", ESC_STR "[34;43m")}, /* italic mode: blue text on yellow */
+ {(int)KS_CZR, IF_EB("\033[0m", ESC_STR "[0m")}, /* italic mode end */
+ {(int)KS_CAB, IF_EB("\033[4%dm", ESC_STR "[4%dm")}, /* set background color (ANSI) */
+ {(int)KS_CAF, IF_EB("\033[3%dm", ESC_STR "[3%dm")}, /* set foreground color (ANSI) */
+ {(int)KS_CSB, IF_EB("\033[102;%dm", ESC_STR "[102;%dm")}, /* set screen background color */
+ {(int)KS_CSF, IF_EB("\033[101;%dm", ESC_STR "[101;%dm")}, /* set screen foreground color */
+ {(int)KS_MS, "y"},
+ {(int)KS_UT, "y"},
+ {(int)KS_XN, "y"},
+ {(int)KS_LE, "\b"},
+# ifdef TERMINFO
+ {(int)KS_CM, IF_EB("\033[%i%p1%d;%p2%dH",
+ ESC_STR "[%i%p1%d;%p2%dH")},
+# else
+ {(int)KS_CM, IF_EB("\033[%i%d;%dH", ESC_STR "[%i%d;%dH")},
+# endif
+# ifdef TERMINFO
+ {(int)KS_CRI, IF_EB("\033[%p1%dC", ESC_STR "[%p1%dC")},
+# else
+ {(int)KS_CRI, IF_EB("\033[%dC", ESC_STR "[%dC")},
+# endif
+ {K_UP, IF_EB("\033[A", ESC_STR "[A")},
+ {K_DOWN, IF_EB("\033[B", ESC_STR "[B")},
+ {K_RIGHT, IF_EB("\033[C", ESC_STR "[C")},
+ {K_LEFT, IF_EB("\033[D", ESC_STR "[D")},
+ // Note: cursor key sequences for application cursor mode are omitted,
+ // because they interfere with typed commands: <Esc>OA.
+ {K_F1, IF_EB("\033[11~", ESC_STR "[11~")},
+ {K_F2, IF_EB("\033[12~", ESC_STR "[12~")},
+ {K_F3, IF_EB("\033[13~", ESC_STR "[13~")},
+ {K_F4, IF_EB("\033[14~", ESC_STR "[14~")},
+ {K_F5, IF_EB("\033[15~", ESC_STR "[15~")},
+ {K_F6, IF_EB("\033[17~", ESC_STR "[17~")},
+ {K_F7, IF_EB("\033[18~", ESC_STR "[18~")},
+ {K_F8, IF_EB("\033[19~", ESC_STR "[19~")},
+ {K_F9, IF_EB("\033[20~", ESC_STR "[20~")},
+ {K_F10, IF_EB("\033[21~", ESC_STR "[21~")},
+ {K_F11, IF_EB("\033[23~", ESC_STR "[23~")},
+ {K_F12, IF_EB("\033[24~", ESC_STR "[24~")},
+ {K_F13, IF_EB("\033[25~", ESC_STR "[25~")},
+ {K_F14, IF_EB("\033[26~", ESC_STR "[26~")},
+ {K_F15, IF_EB("\033[28~", ESC_STR "[28~")}, /* Help */
+ {K_F16, IF_EB("\033[29~", ESC_STR "[29~")}, /* Select */
+ {K_F17, IF_EB("\033[31~", ESC_STR "[31~")},
+ {K_F18, IF_EB("\033[32~", ESC_STR "[32~")},
+ {K_F19, IF_EB("\033[33~", ESC_STR "[33~")},
+ {K_F20, IF_EB("\033[34~", ESC_STR "[34~")},
+ {K_INS, IF_EB("\033[2~", ESC_STR "[2~")},
+ {K_DEL, IF_EB("\033[3~", ESC_STR "[3~")},
+ {K_HOME, IF_EB("\033[1~", ESC_STR "[1~")},
+ {K_END, IF_EB("\033[4~", ESC_STR "[4~")},
+ {K_PAGEUP, IF_EB("\033[5~", ESC_STR "[5~")},
+ {K_PAGEDOWN, IF_EB("\033[6~", ESC_STR "[6~")},
+ // These sequences starting with <Esc> O may interfere with what the user
+ // is typing. Remove these if that bothers you.
+ {K_KPLUS, IF_EB("\033Ok", ESC_STR "Ok")}, /* keypad plus */
+ {K_KMINUS, IF_EB("\033Om", ESC_STR "Om")}, /* keypad minus */
+ {K_KDIVIDE, IF_EB("\033Oo", ESC_STR "Oo")}, /* keypad / */
+ {K_KMULTIPLY, IF_EB("\033Oj", ESC_STR "Oj")}, /* keypad * */
+ {K_KENTER, IF_EB("\033OM", ESC_STR "OM")}, /* keypad Enter */
+ {K_K0, IF_EB("\033Op", ESC_STR "Op")}, /* keypad 0 */
+ {K_K1, IF_EB("\033Oq", ESC_STR "Oq")}, /* keypad 1 */
+ {K_K2, IF_EB("\033Or", ESC_STR "Or")}, /* keypad 2 */
+ {K_K3, IF_EB("\033Os", ESC_STR "Os")}, /* keypad 3 */
+ {K_K4, IF_EB("\033Ot", ESC_STR "Ot")}, /* keypad 4 */
+ {K_K5, IF_EB("\033Ou", ESC_STR "Ou")}, /* keypad 5 */
+ {K_K6, IF_EB("\033Ov", ESC_STR "Ov")}, /* keypad 6 */
+ {K_K7, IF_EB("\033Ow", ESC_STR "Ow")}, /* keypad 7 */
+ {K_K8, IF_EB("\033Ox", ESC_STR "Ox")}, /* keypad 8 */
+ {K_K9, IF_EB("\033Oy", ESC_STR "Oy")}, /* keypad 9 */
+ {K_BS, "\x7f"}, /* for some reason 0177 doesn't work */
+# endif
+
+# if defined(ALL_BUILTIN_TCAPS) || defined(__MINT__)
+/*
+ * Ordinary vt52
+ */
+ {(int)KS_NAME, "vt52"},
+ {(int)KS_CE, IF_EB("\033K", ESC_STR "K")},
+ {(int)KS_CD, IF_EB("\033J", ESC_STR "J")},
+# ifdef TERMINFO
+ {(int)KS_CM, IF_EB("\033Y%p1%' '%+%c%p2%' '%+%c",
+ ESC_STR "Y%p1%' '%+%c%p2%' '%+%c")},
+# else
+ {(int)KS_CM, IF_EB("\033Y%+ %+ ", ESC_STR "Y%+ %+ ")},
+# endif
+ {(int)KS_LE, "\b"},
+ {(int)KS_SR, IF_EB("\033I", ESC_STR "I")},
+ {(int)KS_AL, IF_EB("\033L", ESC_STR "L")},
+ {(int)KS_DL, IF_EB("\033M", ESC_STR "M")},
+ {K_UP, IF_EB("\033A", ESC_STR "A")},
+ {K_DOWN, IF_EB("\033B", ESC_STR "B")},
+ {K_LEFT, IF_EB("\033D", ESC_STR "D")},
+ {K_RIGHT, IF_EB("\033C", ESC_STR "C")},
+ {K_F1, IF_EB("\033P", ESC_STR "P")},
+ {K_F2, IF_EB("\033Q", ESC_STR "Q")},
+ {K_F3, IF_EB("\033R", ESC_STR "R")},
+# ifdef __MINT__
+ {(int)KS_CL, IF_EB("\033E", ESC_STR "E")},
+ {(int)KS_VE, IF_EB("\033e", ESC_STR "e")},
+ {(int)KS_VI, IF_EB("\033f", ESC_STR "f")},
+ {(int)KS_SO, IF_EB("\033p", ESC_STR "p")},
+ {(int)KS_SE, IF_EB("\033q", ESC_STR "q")},
+ {K_S_UP, IF_EB("\033a", ESC_STR "a")},
+ {K_S_DOWN, IF_EB("\033b", ESC_STR "b")},
+ {K_S_LEFT, IF_EB("\033d", ESC_STR "d")},
+ {K_S_RIGHT, IF_EB("\033c", ESC_STR "c")},
+ {K_F4, IF_EB("\033S", ESC_STR "S")},
+ {K_F5, IF_EB("\033T", ESC_STR "T")},
+ {K_F6, IF_EB("\033U", ESC_STR "U")},
+ {K_F7, IF_EB("\033V", ESC_STR "V")},
+ {K_F8, IF_EB("\033W", ESC_STR "W")},
+ {K_F9, IF_EB("\033X", ESC_STR "X")},
+ {K_F10, IF_EB("\033Y", ESC_STR "Y")},
+ {K_S_F1, IF_EB("\033p", ESC_STR "p")},
+ {K_S_F2, IF_EB("\033q", ESC_STR "q")},
+ {K_S_F3, IF_EB("\033r", ESC_STR "r")},
+ {K_S_F4, IF_EB("\033s", ESC_STR "s")},
+ {K_S_F5, IF_EB("\033t", ESC_STR "t")},
+ {K_S_F6, IF_EB("\033u", ESC_STR "u")},
+ {K_S_F7, IF_EB("\033v", ESC_STR "v")},
+ {K_S_F8, IF_EB("\033w", ESC_STR "w")},
+ {K_S_F9, IF_EB("\033x", ESC_STR "x")},
+ {K_S_F10, IF_EB("\033y", ESC_STR "y")},
+ {K_INS, IF_EB("\033I", ESC_STR "I")},
+ {K_HOME, IF_EB("\033E", ESC_STR "E")},
+ {K_PAGEDOWN, IF_EB("\033b", ESC_STR "b")},
+ {K_PAGEUP, IF_EB("\033a", ESC_STR "a")},
+# else
+ {(int)KS_CL, IF_EB("\033H\033J", ESC_STR "H" ESC_STR_nc "J")},
+ {(int)KS_MS, "y"},
+# endif
+# endif
+
+# if defined(UNIX) || defined(ALL_BUILTIN_TCAPS) || defined(SOME_BUILTIN_TCAPS)
+ {(int)KS_NAME, "xterm"},
+ {(int)KS_CE, IF_EB("\033[K", ESC_STR "[K")},
+ {(int)KS_AL, IF_EB("\033[L", ESC_STR "[L")},
+# ifdef TERMINFO
+ {(int)KS_CAL, IF_EB("\033[%p1%dL", ESC_STR "[%p1%dL")},
+# else
+ {(int)KS_CAL, IF_EB("\033[%dL", ESC_STR "[%dL")},
+# endif
+ {(int)KS_DL, IF_EB("\033[M", ESC_STR "[M")},
+# ifdef TERMINFO
+ {(int)KS_CDL, IF_EB("\033[%p1%dM", ESC_STR "[%p1%dM")},
+# else
+ {(int)KS_CDL, IF_EB("\033[%dM", ESC_STR "[%dM")},
+# endif
+# ifdef TERMINFO
+ {(int)KS_CS, IF_EB("\033[%i%p1%d;%p2%dr",
+ ESC_STR "[%i%p1%d;%p2%dr")},
+# else
+ {(int)KS_CS, IF_EB("\033[%i%d;%dr", ESC_STR "[%i%d;%dr")},
+# endif
+ {(int)KS_CL, IF_EB("\033[H\033[2J", ESC_STR "[H" ESC_STR_nc "[2J")},
+ {(int)KS_CD, IF_EB("\033[J", ESC_STR "[J")},
+ {(int)KS_ME, IF_EB("\033[m", ESC_STR "[m")},
+ {(int)KS_MR, IF_EB("\033[7m", ESC_STR "[7m")},
+ {(int)KS_MD, IF_EB("\033[1m", ESC_STR "[1m")},
+ {(int)KS_UE, IF_EB("\033[m", ESC_STR "[m")},
+ {(int)KS_US, IF_EB("\033[4m", ESC_STR "[4m")},
+ {(int)KS_STE, IF_EB("\033[29m", ESC_STR "[29m")},
+ {(int)KS_STS, IF_EB("\033[9m", ESC_STR "[9m")},
+ {(int)KS_MS, "y"},
+ {(int)KS_UT, "y"},
+ {(int)KS_LE, "\b"},
+ {(int)KS_VI, IF_EB("\033[?25l", ESC_STR "[?25l")},
+ {(int)KS_VE, IF_EB("\033[?25h", ESC_STR "[?25h")},
+ {(int)KS_VS, IF_EB("\033[?12h", ESC_STR "[?12h")},
+ {(int)KS_CVS, IF_EB("\033[?12l", ESC_STR "[?12l")},
+# ifdef TERMINFO
+ {(int)KS_CSH, IF_EB("\033[%p1%d q", ESC_STR "[%p1%d q")},
+# else
+ {(int)KS_CSH, IF_EB("\033[%d q", ESC_STR "[%d q")},
+# endif
+ {(int)KS_CRC, IF_EB("\033[?12$p", ESC_STR "[?12$p")},
+ {(int)KS_CRS, IF_EB("\033P$q q\033\\", ESC_STR "P$q q" ESC_STR "\\")},
+# ifdef TERMINFO
+ {(int)KS_CM, IF_EB("\033[%i%p1%d;%p2%dH",
+ ESC_STR "[%i%p1%d;%p2%dH")},
+# else
+ {(int)KS_CM, IF_EB("\033[%i%d;%dH", ESC_STR "[%i%d;%dH")},
+# endif
+ {(int)KS_SR, IF_EB("\033M", ESC_STR "M")},
+# ifdef TERMINFO
+ {(int)KS_CRI, IF_EB("\033[%p1%dC", ESC_STR "[%p1%dC")},
+# else
+ {(int)KS_CRI, IF_EB("\033[%dC", ESC_STR "[%dC")},
+# endif
+ {(int)KS_KS, IF_EB("\033[?1h\033=", ESC_STR "[?1h" ESC_STR_nc "=")},
+ {(int)KS_KE, IF_EB("\033[?1l\033>", ESC_STR "[?1l" ESC_STR_nc ">")},
+# ifdef FEAT_XTERM_SAVE
+ {(int)KS_TI, IF_EB("\0337\033[?47h", ESC_STR "7" ESC_STR_nc "[?47h")},
+ {(int)KS_TE, IF_EB("\033[2J\033[?47l\0338",
+ ESC_STR "[2J" ESC_STR_nc "[?47l" ESC_STR_nc "8")},
+# endif
+ {(int)KS_CIS, IF_EB("\033]1;", ESC_STR "]1;")},
+ {(int)KS_CIE, "\007"},
+ {(int)KS_TS, IF_EB("\033]2;", ESC_STR "]2;")},
+ {(int)KS_FS, "\007"},
+ {(int)KS_CSC, IF_EB("\033]12;", ESC_STR "]12;")},
+ {(int)KS_CEC, "\007"},
+# ifdef TERMINFO
+ {(int)KS_CWS, IF_EB("\033[8;%p1%d;%p2%dt",
+ ESC_STR "[8;%p1%d;%p2%dt")},
+ {(int)KS_CWP, IF_EB("\033[3;%p1%d;%p2%dt",
+ ESC_STR "[3;%p1%d;%p2%dt")},
+ {(int)KS_CGP, IF_EB("\033[13t", ESC_STR "[13t")},
+# else
+ {(int)KS_CWS, IF_EB("\033[8;%d;%dt", ESC_STR "[8;%d;%dt")},
+ {(int)KS_CWP, IF_EB("\033[3;%d;%dt", ESC_STR "[3;%d;%dt")},
+ {(int)KS_CGP, IF_EB("\033[13t", ESC_STR "[13t")},
+# endif
+ {(int)KS_CRV, IF_EB("\033[>c", ESC_STR "[>c")},
+ {(int)KS_RFG, IF_EB("\033]10;?\007", ESC_STR "]10;?\007")},
+ {(int)KS_RBG, IF_EB("\033]11;?\007", ESC_STR "]11;?\007")},
+ {(int)KS_U7, IF_EB("\033[6n", ESC_STR "[6n")},
+# ifdef FEAT_TERMGUICOLORS
+ /* These are printf strings, not terminal codes. */
+ {(int)KS_8F, IF_EB("\033[38;2;%lu;%lu;%lum", ESC_STR "[38;2;%lu;%lu;%lum")},
+ {(int)KS_8B, IF_EB("\033[48;2;%lu;%lu;%lum", ESC_STR "[48;2;%lu;%lu;%lum")},
+# endif
+ {(int)KS_CBE, IF_EB("\033[?2004h", ESC_STR "[?2004h")},
+ {(int)KS_CBD, IF_EB("\033[?2004l", ESC_STR "[?2004l")},
+ {(int)KS_CST, IF_EB("\033[22;2t", ESC_STR "[22;2t")},
+ {(int)KS_CRT, IF_EB("\033[23;2t", ESC_STR "[23;2t")},
+ {(int)KS_SSI, IF_EB("\033[22;1t", ESC_STR "[22;1t")},
+ {(int)KS_SRI, IF_EB("\033[23;1t", ESC_STR "[23;1t")},
+
+ {K_UP, IF_EB("\033O*A", ESC_STR "O*A")},
+ {K_DOWN, IF_EB("\033O*B", ESC_STR "O*B")},
+ {K_RIGHT, IF_EB("\033O*C", ESC_STR "O*C")},
+ {K_LEFT, IF_EB("\033O*D", ESC_STR "O*D")},
+ /* An extra set of cursor keys for vt100 mode */
+ {K_XUP, IF_EB("\033[1;*A", ESC_STR "[1;*A")},
+ {K_XDOWN, IF_EB("\033[1;*B", ESC_STR "[1;*B")},
+ {K_XRIGHT, IF_EB("\033[1;*C", ESC_STR "[1;*C")},
+ {K_XLEFT, IF_EB("\033[1;*D", ESC_STR "[1;*D")},
+ /* An extra set of function keys for vt100 mode */
+ {K_XF1, IF_EB("\033O*P", ESC_STR "O*P")},
+ {K_XF2, IF_EB("\033O*Q", ESC_STR "O*Q")},
+ {K_XF3, IF_EB("\033O*R", ESC_STR "O*R")},
+ {K_XF4, IF_EB("\033O*S", ESC_STR "O*S")},
+ {K_F1, IF_EB("\033[11;*~", ESC_STR "[11;*~")},
+ {K_F2, IF_EB("\033[12;*~", ESC_STR "[12;*~")},
+ {K_F3, IF_EB("\033[13;*~", ESC_STR "[13;*~")},
+ {K_F4, IF_EB("\033[14;*~", ESC_STR "[14;*~")},
+ {K_F5, IF_EB("\033[15;*~", ESC_STR "[15;*~")},
+ {K_F6, IF_EB("\033[17;*~", ESC_STR "[17;*~")},
+ {K_F7, IF_EB("\033[18;*~", ESC_STR "[18;*~")},
+ {K_F8, IF_EB("\033[19;*~", ESC_STR "[19;*~")},
+ {K_F9, IF_EB("\033[20;*~", ESC_STR "[20;*~")},
+ {K_F10, IF_EB("\033[21;*~", ESC_STR "[21;*~")},
+ {K_F11, IF_EB("\033[23;*~", ESC_STR "[23;*~")},
+ {K_F12, IF_EB("\033[24;*~", ESC_STR "[24;*~")},
+ {K_S_TAB, IF_EB("\033[Z", ESC_STR "[Z")},
+ {K_HELP, IF_EB("\033[28;*~", ESC_STR "[28;*~")},
+ {K_UNDO, IF_EB("\033[26;*~", ESC_STR "[26;*~")},
+ {K_INS, IF_EB("\033[2;*~", ESC_STR "[2;*~")},
+ {K_HOME, IF_EB("\033[1;*H", ESC_STR "[1;*H")},
+ /* {K_S_HOME, IF_EB("\033O2H", ESC_STR "O2H")}, */
+ /* {K_C_HOME, IF_EB("\033O5H", ESC_STR "O5H")}, */
+ {K_KHOME, IF_EB("\033[1;*~", ESC_STR "[1;*~")},
+ {K_XHOME, IF_EB("\033O*H", ESC_STR "O*H")}, /* other Home */
+ {K_ZHOME, IF_EB("\033[7;*~", ESC_STR "[7;*~")}, /* other Home */
+ {K_END, IF_EB("\033[1;*F", ESC_STR "[1;*F")},
+ /* {K_S_END, IF_EB("\033O2F", ESC_STR "O2F")}, */
+ /* {K_C_END, IF_EB("\033O5F", ESC_STR "O5F")}, */
+ {K_KEND, IF_EB("\033[4;*~", ESC_STR "[4;*~")},
+ {K_XEND, IF_EB("\033O*F", ESC_STR "O*F")}, /* other End */
+ {K_ZEND, IF_EB("\033[8;*~", ESC_STR "[8;*~")},
+ {K_PAGEUP, IF_EB("\033[5;*~", ESC_STR "[5;*~")},
+ {K_PAGEDOWN, IF_EB("\033[6;*~", ESC_STR "[6;*~")},
+ {K_KPLUS, IF_EB("\033O*k", ESC_STR "O*k")}, /* keypad plus */
+ {K_KMINUS, IF_EB("\033O*m", ESC_STR "O*m")}, /* keypad minus */
+ {K_KDIVIDE, IF_EB("\033O*o", ESC_STR "O*o")}, /* keypad / */
+ {K_KMULTIPLY, IF_EB("\033O*j", ESC_STR "O*j")}, /* keypad * */
+ {K_KENTER, IF_EB("\033O*M", ESC_STR "O*M")}, /* keypad Enter */
+ {K_KPOINT, IF_EB("\033O*n", ESC_STR "O*n")}, /* keypad . */
+ {K_K0, IF_EB("\033O*p", ESC_STR "O*p")}, /* keypad 0 */
+ {K_K1, IF_EB("\033O*q", ESC_STR "O*q")}, /* keypad 1 */
+ {K_K2, IF_EB("\033O*r", ESC_STR "O*r")}, /* keypad 2 */
+ {K_K3, IF_EB("\033O*s", ESC_STR "O*s")}, /* keypad 3 */
+ {K_K4, IF_EB("\033O*t", ESC_STR "O*t")}, /* keypad 4 */
+ {K_K5, IF_EB("\033O*u", ESC_STR "O*u")}, /* keypad 5 */
+ {K_K6, IF_EB("\033O*v", ESC_STR "O*v")}, /* keypad 6 */
+ {K_K7, IF_EB("\033O*w", ESC_STR "O*w")}, /* keypad 7 */
+ {K_K8, IF_EB("\033O*x", ESC_STR "O*x")}, /* keypad 8 */
+ {K_K9, IF_EB("\033O*y", ESC_STR "O*y")}, /* keypad 9 */
+ {K_KDEL, IF_EB("\033[3;*~", ESC_STR "[3;*~")}, /* keypad Del */
+ {K_PS, IF_EB("\033[200~", ESC_STR "[200~")}, /* paste start */
+ {K_PE, IF_EB("\033[201~", ESC_STR "[201~")}, /* paste end */
+
+ {BT_EXTRA_KEYS, ""},
+ {TERMCAP2KEY('k', '0'), IF_EB("\033[10;*~", ESC_STR "[10;*~")}, /* F0 */
+ {TERMCAP2KEY('F', '3'), IF_EB("\033[25;*~", ESC_STR "[25;*~")}, /* F13 */
+ /* F14 and F15 are missing, because they send the same codes as the undo
+ * and help key, although they don't work on all keyboards. */
+ {TERMCAP2KEY('F', '6'), IF_EB("\033[29;*~", ESC_STR "[29;*~")}, /* F16 */
+ {TERMCAP2KEY('F', '7'), IF_EB("\033[31;*~", ESC_STR "[31;*~")}, /* F17 */
+ {TERMCAP2KEY('F', '8'), IF_EB("\033[32;*~", ESC_STR "[32;*~")}, /* F18 */
+ {TERMCAP2KEY('F', '9'), IF_EB("\033[33;*~", ESC_STR "[33;*~")}, /* F19 */
+ {TERMCAP2KEY('F', 'A'), IF_EB("\033[34;*~", ESC_STR "[34;*~")}, /* F20 */
+
+ {TERMCAP2KEY('F', 'B'), IF_EB("\033[42;*~", ESC_STR "[42;*~")}, /* F21 */
+ {TERMCAP2KEY('F', 'C'), IF_EB("\033[43;*~", ESC_STR "[43;*~")}, /* F22 */
+ {TERMCAP2KEY('F', 'D'), IF_EB("\033[44;*~", ESC_STR "[44;*~")}, /* F23 */
+ {TERMCAP2KEY('F', 'E'), IF_EB("\033[45;*~", ESC_STR "[45;*~")}, /* F24 */
+ {TERMCAP2KEY('F', 'F'), IF_EB("\033[46;*~", ESC_STR "[46;*~")}, /* F25 */
+ {TERMCAP2KEY('F', 'G'), IF_EB("\033[47;*~", ESC_STR "[47;*~")}, /* F26 */
+ {TERMCAP2KEY('F', 'H'), IF_EB("\033[48;*~", ESC_STR "[48;*~")}, /* F27 */
+ {TERMCAP2KEY('F', 'I'), IF_EB("\033[49;*~", ESC_STR "[49;*~")}, /* F28 */
+ {TERMCAP2KEY('F', 'J'), IF_EB("\033[50;*~", ESC_STR "[50;*~")}, /* F29 */
+ {TERMCAP2KEY('F', 'K'), IF_EB("\033[51;*~", ESC_STR "[51;*~")}, /* F30 */
+
+ {TERMCAP2KEY('F', 'L'), IF_EB("\033[52;*~", ESC_STR "[52;*~")}, /* F31 */
+ {TERMCAP2KEY('F', 'M'), IF_EB("\033[53;*~", ESC_STR "[53;*~")}, /* F32 */
+ {TERMCAP2KEY('F', 'N'), IF_EB("\033[54;*~", ESC_STR "[54;*~")}, /* F33 */
+ {TERMCAP2KEY('F', 'O'), IF_EB("\033[55;*~", ESC_STR "[55;*~")}, /* F34 */
+ {TERMCAP2KEY('F', 'P'), IF_EB("\033[56;*~", ESC_STR "[56;*~")}, /* F35 */
+ {TERMCAP2KEY('F', 'Q'), IF_EB("\033[57;*~", ESC_STR "[57;*~")}, /* F36 */
+ {TERMCAP2KEY('F', 'R'), IF_EB("\033[58;*~", ESC_STR "[58;*~")}, /* F37 */
+# endif
+
+# if defined(UNIX) || defined(ALL_BUILTIN_TCAPS)
+/*
+ * iris-ansi for Silicon Graphics machines.
+ */
+ {(int)KS_NAME, "iris-ansi"},
+ {(int)KS_CE, "\033[K"},
+ {(int)KS_CD, "\033[J"},
+ {(int)KS_AL, "\033[L"},
+# ifdef TERMINFO
+ {(int)KS_CAL, "\033[%p1%dL"},
+# else
+ {(int)KS_CAL, "\033[%dL"},
+# endif
+ {(int)KS_DL, "\033[M"},
+# ifdef TERMINFO
+ {(int)KS_CDL, "\033[%p1%dM"},
+# else
+ {(int)KS_CDL, "\033[%dM"},
+# endif
+#if 0 /* The scroll region is not working as Vim expects. */
+# ifdef TERMINFO
+ {(int)KS_CS, "\033[%i%p1%d;%p2%dr"},
+# else
+ {(int)KS_CS, "\033[%i%d;%dr"},
+# endif
+#endif
+ {(int)KS_CL, "\033[H\033[2J"},
+ {(int)KS_VE, "\033[9/y\033[12/y"}, /* These aren't documented */
+ {(int)KS_VS, "\033[10/y\033[=1h\033[=2l"}, /* These aren't documented */
+ {(int)KS_TI, "\033[=6h"},
+ {(int)KS_TE, "\033[=6l"},
+ {(int)KS_SE, "\033[21;27m"},
+ {(int)KS_SO, "\033[1;7m"},
+ {(int)KS_ME, "\033[m"},
+ {(int)KS_MR, "\033[7m"},
+ {(int)KS_MD, "\033[1m"},
+ {(int)KS_CCO, "8"}, /* allow 8 colors */
+ {(int)KS_CZH, "\033[3m"}, /* italic mode on */
+ {(int)KS_CZR, "\033[23m"}, /* italic mode off */
+ {(int)KS_US, "\033[4m"}, /* underline on */
+ {(int)KS_UE, "\033[24m"}, /* underline off */
+# ifdef TERMINFO
+ {(int)KS_CAB, "\033[4%p1%dm"}, /* set background color (ANSI) */
+ {(int)KS_CAF, "\033[3%p1%dm"}, /* set foreground color (ANSI) */
+ {(int)KS_CSB, "\033[102;%p1%dm"}, /* set screen background color */
+ {(int)KS_CSF, "\033[101;%p1%dm"}, /* set screen foreground color */
+# else
+ {(int)KS_CAB, "\033[4%dm"}, /* set background color (ANSI) */
+ {(int)KS_CAF, "\033[3%dm"}, /* set foreground color (ANSI) */
+ {(int)KS_CSB, "\033[102;%dm"}, /* set screen background color */
+ {(int)KS_CSF, "\033[101;%dm"}, /* set screen foreground color */
+# endif
+ {(int)KS_MS, "y"}, /* guessed */
+ {(int)KS_UT, "y"}, /* guessed */
+ {(int)KS_LE, "\b"},
+# ifdef TERMINFO
+ {(int)KS_CM, "\033[%i%p1%d;%p2%dH"},
+# else
+ {(int)KS_CM, "\033[%i%d;%dH"},
+# endif
+ {(int)KS_SR, "\033M"},
+# ifdef TERMINFO
+ {(int)KS_CRI, "\033[%p1%dC"},
+# else
+ {(int)KS_CRI, "\033[%dC"},
+# endif
+ {(int)KS_CIS, "\033P3.y"},
+ {(int)KS_CIE, "\234"}, /* ST "String Terminator" */
+ {(int)KS_TS, "\033P1.y"},
+ {(int)KS_FS, "\234"}, /* ST "String Terminator" */
+# ifdef TERMINFO
+ {(int)KS_CWS, "\033[203;%p1%d;%p2%d/y"},
+ {(int)KS_CWP, "\033[205;%p1%d;%p2%d/y"},
+# else
+ {(int)KS_CWS, "\033[203;%d;%d/y"},
+ {(int)KS_CWP, "\033[205;%d;%d/y"},
+# endif
+ {K_UP, "\033[A"},
+ {K_DOWN, "\033[B"},
+ {K_LEFT, "\033[D"},
+ {K_RIGHT, "\033[C"},
+ {K_S_UP, "\033[161q"},
+ {K_S_DOWN, "\033[164q"},
+ {K_S_LEFT, "\033[158q"},
+ {K_S_RIGHT, "\033[167q"},
+ {K_F1, "\033[001q"},
+ {K_F2, "\033[002q"},
+ {K_F3, "\033[003q"},
+ {K_F4, "\033[004q"},
+ {K_F5, "\033[005q"},
+ {K_F6, "\033[006q"},
+ {K_F7, "\033[007q"},
+ {K_F8, "\033[008q"},
+ {K_F9, "\033[009q"},
+ {K_F10, "\033[010q"},
+ {K_F11, "\033[011q"},
+ {K_F12, "\033[012q"},
+ {K_S_F1, "\033[013q"},
+ {K_S_F2, "\033[014q"},
+ {K_S_F3, "\033[015q"},
+ {K_S_F4, "\033[016q"},
+ {K_S_F5, "\033[017q"},
+ {K_S_F6, "\033[018q"},
+ {K_S_F7, "\033[019q"},
+ {K_S_F8, "\033[020q"},
+ {K_S_F9, "\033[021q"},
+ {K_S_F10, "\033[022q"},
+ {K_S_F11, "\033[023q"},
+ {K_S_F12, "\033[024q"},
+ {K_INS, "\033[139q"},
+ {K_HOME, "\033[H"},
+ {K_END, "\033[146q"},
+ {K_PAGEUP, "\033[150q"},
+ {K_PAGEDOWN, "\033[154q"},
+# endif
+
+# if defined(DEBUG) || defined(ALL_BUILTIN_TCAPS)
+/*
+ * for debugging
+ */
+ {(int)KS_NAME, "debug"},
+ {(int)KS_CE, "[CE]"},
+ {(int)KS_CD, "[CD]"},
+ {(int)KS_AL, "[AL]"},
+# ifdef TERMINFO
+ {(int)KS_CAL, "[CAL%p1%d]"},
+# else
+ {(int)KS_CAL, "[CAL%d]"},
+# endif
+ {(int)KS_DL, "[DL]"},
+# ifdef TERMINFO
+ {(int)KS_CDL, "[CDL%p1%d]"},
+# else
+ {(int)KS_CDL, "[CDL%d]"},
+# endif
+# ifdef TERMINFO
+ {(int)KS_CS, "[%p1%dCS%p2%d]"},
+# else
+ {(int)KS_CS, "[%dCS%d]"},
+# endif
+# ifdef TERMINFO
+ {(int)KS_CSV, "[%p1%dCSV%p2%d]"},
+# else
+ {(int)KS_CSV, "[%dCSV%d]"},
+# endif
+# ifdef TERMINFO
+ {(int)KS_CAB, "[CAB%p1%d]"},
+ {(int)KS_CAF, "[CAF%p1%d]"},
+ {(int)KS_CSB, "[CSB%p1%d]"},
+ {(int)KS_CSF, "[CSF%p1%d]"},
+# else
+ {(int)KS_CAB, "[CAB%d]"},
+ {(int)KS_CAF, "[CAF%d]"},
+ {(int)KS_CSB, "[CSB%d]"},
+ {(int)KS_CSF, "[CSF%d]"},
+# endif
+ {(int)KS_OP, "[OP]"},
+ {(int)KS_LE, "[LE]"},
+ {(int)KS_CL, "[CL]"},
+ {(int)KS_VI, "[VI]"},
+ {(int)KS_VE, "[VE]"},
+ {(int)KS_VS, "[VS]"},
+ {(int)KS_ME, "[ME]"},
+ {(int)KS_MR, "[MR]"},
+ {(int)KS_MB, "[MB]"},
+ {(int)KS_MD, "[MD]"},
+ {(int)KS_SE, "[SE]"},
+ {(int)KS_SO, "[SO]"},
+ {(int)KS_UE, "[UE]"},
+ {(int)KS_US, "[US]"},
+ {(int)KS_UCE, "[UCE]"},
+ {(int)KS_UCS, "[UCS]"},
+ {(int)KS_STE, "[STE]"},
+ {(int)KS_STS, "[STS]"},
+ {(int)KS_MS, "[MS]"},
+ {(int)KS_UT, "[UT]"},
+ {(int)KS_XN, "[XN]"},
+# ifdef TERMINFO
+ {(int)KS_CM, "[%p1%dCM%p2%d]"},
+# else
+ {(int)KS_CM, "[%dCM%d]"},
+# endif
+ {(int)KS_SR, "[SR]"},
+# ifdef TERMINFO
+ {(int)KS_CRI, "[CRI%p1%d]"},
+# else
+ {(int)KS_CRI, "[CRI%d]"},
+# endif
+ {(int)KS_VB, "[VB]"},
+ {(int)KS_KS, "[KS]"},
+ {(int)KS_KE, "[KE]"},
+ {(int)KS_TI, "[TI]"},
+ {(int)KS_TE, "[TE]"},
+ {(int)KS_CIS, "[CIS]"},
+ {(int)KS_CIE, "[CIE]"},
+ {(int)KS_CSC, "[CSC]"},
+ {(int)KS_CEC, "[CEC]"},
+ {(int)KS_TS, "[TS]"},
+ {(int)KS_FS, "[FS]"},
+# ifdef TERMINFO
+ {(int)KS_CWS, "[%p1%dCWS%p2%d]"},
+ {(int)KS_CWP, "[%p1%dCWP%p2%d]"},
+# else
+ {(int)KS_CWS, "[%dCWS%d]"},
+ {(int)KS_CWP, "[%dCWP%d]"},
+# endif
+ {(int)KS_CRV, "[CRV]"},
+ {(int)KS_U7, "[U7]"},
+ {(int)KS_RFG, "[RFG]"},
+ {(int)KS_RBG, "[RBG]"},
+ {K_UP, "[KU]"},
+ {K_DOWN, "[KD]"},
+ {K_LEFT, "[KL]"},
+ {K_RIGHT, "[KR]"},
+ {K_XUP, "[xKU]"},
+ {K_XDOWN, "[xKD]"},
+ {K_XLEFT, "[xKL]"},
+ {K_XRIGHT, "[xKR]"},
+ {K_S_UP, "[S-KU]"},
+ {K_S_DOWN, "[S-KD]"},
+ {K_S_LEFT, "[S-KL]"},
+ {K_C_LEFT, "[C-KL]"},
+ {K_S_RIGHT, "[S-KR]"},
+ {K_C_RIGHT, "[C-KR]"},
+ {K_F1, "[F1]"},
+ {K_XF1, "[xF1]"},
+ {K_F2, "[F2]"},
+ {K_XF2, "[xF2]"},
+ {K_F3, "[F3]"},
+ {K_XF3, "[xF3]"},
+ {K_F4, "[F4]"},
+ {K_XF4, "[xF4]"},
+ {K_F5, "[F5]"},
+ {K_F6, "[F6]"},
+ {K_F7, "[F7]"},
+ {K_F8, "[F8]"},
+ {K_F9, "[F9]"},
+ {K_F10, "[F10]"},
+ {K_F11, "[F11]"},
+ {K_F12, "[F12]"},
+ {K_S_F1, "[S-F1]"},
+ {K_S_XF1, "[S-xF1]"},
+ {K_S_F2, "[S-F2]"},
+ {K_S_XF2, "[S-xF2]"},
+ {K_S_F3, "[S-F3]"},
+ {K_S_XF3, "[S-xF3]"},
+ {K_S_F4, "[S-F4]"},
+ {K_S_XF4, "[S-xF4]"},
+ {K_S_F5, "[S-F5]"},
+ {K_S_F6, "[S-F6]"},
+ {K_S_F7, "[S-F7]"},
+ {K_S_F8, "[S-F8]"},
+ {K_S_F9, "[S-F9]"},
+ {K_S_F10, "[S-F10]"},
+ {K_S_F11, "[S-F11]"},
+ {K_S_F12, "[S-F12]"},
+ {K_HELP, "[HELP]"},
+ {K_UNDO, "[UNDO]"},
+ {K_BS, "[BS]"},
+ {K_INS, "[INS]"},
+ {K_KINS, "[KINS]"},
+ {K_DEL, "[DEL]"},
+ {K_KDEL, "[KDEL]"},
+ {K_HOME, "[HOME]"},
+ {K_S_HOME, "[C-HOME]"},
+ {K_C_HOME, "[C-HOME]"},
+ {K_KHOME, "[KHOME]"},
+ {K_XHOME, "[XHOME]"},
+ {K_ZHOME, "[ZHOME]"},
+ {K_END, "[END]"},
+ {K_S_END, "[C-END]"},
+ {K_C_END, "[C-END]"},
+ {K_KEND, "[KEND]"},
+ {K_XEND, "[XEND]"},
+ {K_ZEND, "[ZEND]"},
+ {K_PAGEUP, "[PAGEUP]"},
+ {K_PAGEDOWN, "[PAGEDOWN]"},
+ {K_KPAGEUP, "[KPAGEUP]"},
+ {K_KPAGEDOWN, "[KPAGEDOWN]"},
+ {K_MOUSE, "[MOUSE]"},
+ {K_KPLUS, "[KPLUS]"},
+ {K_KMINUS, "[KMINUS]"},
+ {K_KDIVIDE, "[KDIVIDE]"},
+ {K_KMULTIPLY, "[KMULTIPLY]"},
+ {K_KENTER, "[KENTER]"},
+ {K_KPOINT, "[KPOINT]"},
+ {K_PS, "[PASTE-START]"},
+ {K_PE, "[PASTE-END]"},
+ {K_K0, "[K0]"},
+ {K_K1, "[K1]"},
+ {K_K2, "[K2]"},
+ {K_K3, "[K3]"},
+ {K_K4, "[K4]"},
+ {K_K5, "[K5]"},
+ {K_K6, "[K6]"},
+ {K_K7, "[K7]"},
+ {K_K8, "[K8]"},
+ {K_K9, "[K9]"},
+# endif
+
+#endif /* NO_BUILTIN_TCAPS */
+
+/*
+ * The most minimal terminal: only clear screen and cursor positioning
+ * Always included.
+ */
+ {(int)KS_NAME, "dumb"},
+ {(int)KS_CL, "\014"},
+#ifdef TERMINFO
+ {(int)KS_CM, IF_EB("\033[%i%p1%d;%p2%dH",
+ ESC_STR "[%i%p1%d;%p2%dH")},
+#else
+ {(int)KS_CM, IF_EB("\033[%i%d;%dH", ESC_STR "[%i%d;%dH")},
+#endif
+
+/*
+ * end marker
+ */
+ {(int)KS_NAME, NULL}
+
+}; /* end of builtin_termcaps */
+
+#if defined(FEAT_TERMGUICOLORS) || defined(PROTO)
+ guicolor_T
+termgui_mch_get_color(char_u *name)
+{
+ return gui_get_color_cmn(name);
+}
+
+ guicolor_T
+termgui_get_color(char_u *name)
+{
+ guicolor_T t;
+
+ if (*name == NUL)
+ return INVALCOLOR;
+ t = termgui_mch_get_color(name);
+
+ if (t == INVALCOLOR)
+ semsg(_("E254: Cannot allocate color %s"), name);
+ return t;
+}
+
+ guicolor_T
+termgui_mch_get_rgb(guicolor_T color)
+{
+ return color;
+}
+#endif
+
+/*
+ * DEFAULT_TERM is used, when no terminal is specified with -T option or $TERM.
+ */
+#ifdef AMIGA
+# define DEFAULT_TERM (char_u *)"amiga"
+#endif
+
+#ifdef MSWIN
+# define DEFAULT_TERM (char_u *)"win32"
+#endif
+
+#if defined(UNIX) && !defined(__MINT__)
+# define DEFAULT_TERM (char_u *)"ansi"
+#endif
+
+#ifdef __MINT__
+# define DEFAULT_TERM (char_u *)"vt52"
+#endif
+
+#ifdef VMS
+# define DEFAULT_TERM (char_u *)"vt320"
+#endif
+
+#ifdef __BEOS__
+# undef DEFAULT_TERM
+# define DEFAULT_TERM (char_u *)"beos-ansi"
+#endif
+
+#ifndef DEFAULT_TERM
+# define DEFAULT_TERM (char_u *)"dumb"
+#endif
+
+/*
+ * Term_strings contains currently used terminal output strings.
+ * It is initialized with the default values by parse_builtin_tcap().
+ * The values can be changed by setting the option with the same name.
+ */
+char_u *(term_strings[(int)KS_LAST + 1]);
+
+static int need_gather = FALSE; /* need to fill termleader[] */
+static char_u termleader[256 + 1]; /* for check_termcode() */
+#ifdef FEAT_TERMRESPONSE
+static int check_for_codes = FALSE; /* check for key code response */
+static int is_not_xterm = FALSE; /* recognized not-really-xterm */
+#endif
+
+ static struct builtin_term *
+find_builtin_term(char_u *term)
+{
+ struct builtin_term *p;
+
+ p = builtin_termcaps;
+ while (p->bt_string != NULL)
+ {
+ if (p->bt_entry == (int)KS_NAME)
+ {
+#ifdef UNIX
+ if (STRCMP(p->bt_string, "iris-ansi") == 0 && vim_is_iris(term))
+ return p;
+ else if (STRCMP(p->bt_string, "xterm") == 0 && vim_is_xterm(term))
+ return p;
+ else
+#endif
+#ifdef VMS
+ if (STRCMP(p->bt_string, "vt320") == 0 && vim_is_vt300(term))
+ return p;
+ else
+#endif
+ if (STRCMP(term, p->bt_string) == 0)
+ return p;
+ }
+ ++p;
+ }
+ return p;
+}
+
+/*
+ * Parsing of the builtin termcap entries.
+ * Caller should check if 'name' is a valid builtin term.
+ * The terminal's name is not set, as this is already done in termcapinit().
+ */
+ static void
+parse_builtin_tcap(char_u *term)
+{
+ struct builtin_term *p;
+ char_u name[2];
+ int term_8bit;
+
+ p = find_builtin_term(term);
+ term_8bit = term_is_8bit(term);
+
+ /* Do not parse if builtin term not found */
+ if (p->bt_string == NULL)
+ return;
+
+ for (++p; p->bt_entry != (int)KS_NAME && p->bt_entry != BT_EXTRA_KEYS; ++p)
+ {
+ if ((int)p->bt_entry >= 0) /* KS_xx entry */
+ {
+ /* Only set the value if it wasn't set yet. */
+ if (term_strings[p->bt_entry] == NULL
+ || term_strings[p->bt_entry] == empty_option)
+ {
+#ifdef FEAT_EVAL
+ int opt_idx = -1;
+#endif
+ /* 8bit terminal: use CSI instead of <Esc>[ */
+ if (term_8bit && term_7to8bit((char_u *)p->bt_string) != 0)
+ {
+ char_u *s, *t;
+
+ s = vim_strsave((char_u *)p->bt_string);
+ if (s != NULL)
+ {
+ for (t = s; *t; ++t)
+ if (term_7to8bit(t))
+ {
+ *t = term_7to8bit(t);
+ STRMOVE(t + 1, t + 2);
+ }
+ term_strings[p->bt_entry] = s;
+#ifdef FEAT_EVAL
+ opt_idx =
+#endif
+ set_term_option_alloced(
+ &term_strings[p->bt_entry]);
+ }
+ }
+ else
+ {
+ term_strings[p->bt_entry] = (char_u *)p->bt_string;
+#ifdef FEAT_EVAL
+ opt_idx = get_term_opt_idx(&term_strings[p->bt_entry]);
+#endif
+ }
+#ifdef FEAT_EVAL
+ set_term_option_sctx_idx(NULL, opt_idx);
+#endif
+ }
+ }
+ else
+ {
+ name[0] = KEY2TERMCAP0((int)p->bt_entry);
+ name[1] = KEY2TERMCAP1((int)p->bt_entry);
+ if (find_termcode(name) == NULL)
+ add_termcode(name, (char_u *)p->bt_string, term_8bit);
+ }
+ }
+}
+
+/*
+ * Set number of colors.
+ * Store it as a number in t_colors.
+ * Store it as a string in T_CCO (using nr_colors[]).
+ */
+ static void
+set_color_count(int nr)
+{
+ char_u nr_colors[20]; /* string for number of colors */
+
+ t_colors = nr;
+ if (t_colors > 1)
+ sprintf((char *)nr_colors, "%d", t_colors);
+ else
+ *nr_colors = NUL;
+ set_string_option_direct((char_u *)"t_Co", -1, nr_colors, OPT_FREE, 0);
+}
+
+#if defined(FEAT_TERMRESPONSE)
+/*
+ * Set the color count to "val" and redraw if it changed.
+ */
+ static void
+may_adjust_color_count(int val)
+{
+ if (val != t_colors)
+ {
+ /* Nr of colors changed, initialize highlighting and
+ * redraw everything. This causes a redraw, which usually
+ * clears the message. Try keeping the message if it
+ * might work. */
+ set_keep_msg_from_hist();
+ set_color_count(val);
+ init_highlight(TRUE, FALSE);
+# ifdef DEBUG_TERMRESPONSE
+ {
+ int r = redraw_asap(CLEAR);
+
+ log_tr("Received t_Co, redraw_asap(): %d", r);
+ }
+#else
+ redraw_asap(CLEAR);
+#endif
+ }
+}
+#endif
+
+#ifdef HAVE_TGETENT
+static char *(key_names[]) =
+{
+#ifdef FEAT_TERMRESPONSE
+ /* Do this one first, it may cause a screen redraw. */
+ "Co",
+#endif
+ "ku", "kd", "kr", "kl",
+ "#2", "#4", "%i", "*7",
+ "k1", "k2", "k3", "k4", "k5", "k6",
+ "k7", "k8", "k9", "k;", "F1", "F2",
+ "%1", "&8", "kb", "kI", "kD", "kh",
+ "@7", "kP", "kN", "K1", "K3", "K4", "K5", "kB",
+ NULL
+};
+#endif
+
+#ifdef HAVE_TGETENT
+ static void
+get_term_entries(int *height, int *width)
+{
+ static struct {
+ enum SpecialKey dest; /* index in term_strings[] */
+ char *name; /* termcap name for string */
+ } string_names[] =
+ { {KS_CE, "ce"}, {KS_AL, "al"}, {KS_CAL,"AL"},
+ {KS_DL, "dl"}, {KS_CDL,"DL"}, {KS_CS, "cs"},
+ {KS_CL, "cl"}, {KS_CD, "cd"},
+ {KS_VI, "vi"}, {KS_VE, "ve"}, {KS_MB, "mb"},
+ {KS_ME, "me"}, {KS_MR, "mr"},
+ {KS_MD, "md"}, {KS_SE, "se"}, {KS_SO, "so"},
+ {KS_CZH,"ZH"}, {KS_CZR,"ZR"}, {KS_UE, "ue"},
+ {KS_US, "us"}, {KS_UCE, "Ce"}, {KS_UCS, "Cs"},
+ {KS_STE,"Te"}, {KS_STS,"Ts"},
+ {KS_CM, "cm"}, {KS_SR, "sr"},
+ {KS_CRI,"RI"}, {KS_VB, "vb"}, {KS_KS, "ks"},
+ {KS_KE, "ke"}, {KS_TI, "ti"}, {KS_TE, "te"},
+ {KS_BC, "bc"}, {KS_CSB,"Sb"}, {KS_CSF,"Sf"},
+ {KS_CAB,"AB"}, {KS_CAF,"AF"}, {KS_LE, "le"},
+ {KS_ND, "nd"}, {KS_OP, "op"}, {KS_CRV, "RV"},
+ {KS_VS, "vs"}, {KS_CVS, "VS"},
+ {KS_CIS, "IS"}, {KS_CIE, "IE"},
+ {KS_CSC, "SC"}, {KS_CEC, "EC"},
+ {KS_TS, "ts"}, {KS_FS, "fs"},
+ {KS_CWP, "WP"}, {KS_CWS, "WS"},
+ {KS_CSI, "SI"}, {KS_CEI, "EI"},
+ {KS_U7, "u7"}, {KS_RFG, "RF"}, {KS_RBG, "RB"},
+ {KS_8F, "8f"}, {KS_8B, "8b"},
+ {KS_CBE, "BE"}, {KS_CBD, "BD"},
+ {KS_CPS, "PS"}, {KS_CPE, "PE"},
+ {KS_CST, "ST"}, {KS_CRT, "RT"},
+ {KS_SSI, "Si"}, {KS_SRI, "Ri"},
+ {(enum SpecialKey)0, NULL}
+ };
+ int i;
+ char_u *p;
+ static char_u tstrbuf[TBUFSZ];
+ char_u *tp = tstrbuf;
+
+ /*
+ * get output strings
+ */
+ for (i = 0; string_names[i].name != NULL; ++i)
+ {
+ if (TERM_STR(string_names[i].dest) == NULL
+ || TERM_STR(string_names[i].dest) == empty_option)
+ {
+ TERM_STR(string_names[i].dest) = TGETSTR(string_names[i].name, &tp);
+#ifdef FEAT_EVAL
+ set_term_option_sctx_idx(string_names[i].name, -1);
+#endif
+ }
+ }
+
+ /* tgetflag() returns 1 if the flag is present, 0 if not and
+ * possibly -1 if the flag doesn't exist. */
+ if ((T_MS == NULL || T_MS == empty_option) && tgetflag("ms") > 0)
+ T_MS = (char_u *)"y";
+ if ((T_XS == NULL || T_XS == empty_option) && tgetflag("xs") > 0)
+ T_XS = (char_u *)"y";
+ if ((T_XN == NULL || T_XN == empty_option) && tgetflag("xn") > 0)
+ T_XN = (char_u *)"y";
+ if ((T_DB == NULL || T_DB == empty_option) && tgetflag("db") > 0)
+ T_DB = (char_u *)"y";
+ if ((T_DA == NULL || T_DA == empty_option) && tgetflag("da") > 0)
+ T_DA = (char_u *)"y";
+ if ((T_UT == NULL || T_UT == empty_option) && tgetflag("ut") > 0)
+ T_UT = (char_u *)"y";
+
+ /*
+ * get key codes
+ */
+ for (i = 0; key_names[i] != NULL; ++i)
+ if (find_termcode((char_u *)key_names[i]) == NULL)
+ {
+ p = TGETSTR(key_names[i], &tp);
+ /* if cursor-left == backspace, ignore it (televideo 925) */
+ if (p != NULL
+ && (*p != Ctrl_H
+ || key_names[i][0] != 'k'
+ || key_names[i][1] != 'l'))
+ add_termcode((char_u *)key_names[i], p, FALSE);
+ }
+
+ if (*height == 0)
+ *height = tgetnum("li");
+ if (*width == 0)
+ *width = tgetnum("co");
+
+ /*
+ * Get number of colors (if not done already).
+ */
+ if (TERM_STR(KS_CCO) == NULL || TERM_STR(KS_CCO) == empty_option)
+ {
+ set_color_count(tgetnum("Co"));
+#ifdef FEAT_EVAL
+ set_term_option_sctx_idx("Co", -1);
+#endif
+ }
+
+# ifndef hpux
+ BC = (char *)TGETSTR("bc", &tp);
+ UP = (char *)TGETSTR("up", &tp);
+ p = TGETSTR("pc", &tp);
+ if (p)
+ PC = *p;
+# endif
+}
+#endif
+
+ static void
+report_term_error(char *error_msg, char_u *term)
+{
+ struct builtin_term *termp;
+
+ mch_errmsg("\r\n");
+ if (error_msg != NULL)
+ {
+ mch_errmsg(error_msg);
+ mch_errmsg("\r\n");
+ }
+ mch_errmsg("'");
+ mch_errmsg((char *)term);
+ mch_errmsg(_("' not known. Available builtin terminals are:"));
+ mch_errmsg("\r\n");
+ for (termp = &(builtin_termcaps[0]); termp->bt_string != NULL; ++termp)
+ {
+ if (termp->bt_entry == (int)KS_NAME)
+ {
+#ifdef HAVE_TGETENT
+ mch_errmsg(" builtin_");
+#else
+ mch_errmsg(" ");
+#endif
+ mch_errmsg(termp->bt_string);
+ mch_errmsg("\r\n");
+ }
+ }
+}
+
+ static void
+report_default_term(char_u *term)
+{
+ mch_errmsg(_("defaulting to '"));
+ mch_errmsg((char *)term);
+ mch_errmsg("'\r\n");
+ if (emsg_silent == 0)
+ {
+ screen_start(); /* don't know where cursor is now */
+ out_flush();
+ if (!is_not_a_term())
+ ui_delay(2000L, TRUE);
+ }
+}
+
+/*
+ * Set terminal options for terminal "term".
+ * Return OK if terminal 'term' was found in a termcap, FAIL otherwise.
+ *
+ * While doing this, until ttest(), some options may be NULL, be careful.
+ */
+ int
+set_termname(char_u *term)
+{
+ struct builtin_term *termp;
+#ifdef HAVE_TGETENT
+ int builtin_first = p_tbi;
+ int try;
+ int termcap_cleared = FALSE;
+#endif
+ int width = 0, height = 0;
+ char *error_msg = NULL;
+ char_u *bs_p, *del_p;
+
+ /* In silect mode (ex -s) we don't use the 'term' option. */
+ if (silent_mode)
+ return OK;
+
+ detected_8bit = FALSE; /* reset 8-bit detection */
+
+ if (term_is_builtin(term))
+ {
+ term += 8;
+#ifdef HAVE_TGETENT
+ builtin_first = 1;
+#endif
+ }
+
+/*
+ * If HAVE_TGETENT is not defined, only the builtin termcap is used, otherwise:
+ * If builtin_first is TRUE:
+ * 0. try builtin termcap
+ * 1. try external termcap
+ * 2. if both fail default to a builtin terminal
+ * If builtin_first is FALSE:
+ * 1. try external termcap
+ * 2. try builtin termcap, if both fail default to a builtin terminal
+ */
+#ifdef HAVE_TGETENT
+ for (try = builtin_first ? 0 : 1; try < 3; ++try)
+ {
+ /*
+ * Use external termcap
+ */
+ if (try == 1)
+ {
+ char_u tbuf[TBUFSZ];
+
+ /*
+ * If the external termcap does not have a matching entry, try the
+ * builtin ones.
+ */
+ if ((error_msg = tgetent_error(tbuf, term)) == NULL)
+ {
+ if (!termcap_cleared)
+ {
+ clear_termoptions(); /* clear old options */
+ termcap_cleared = TRUE;
+ }
+
+ get_term_entries(&height, &width);
+ }
+ }
+ else /* try == 0 || try == 2 */
+#endif /* HAVE_TGETENT */
+ /*
+ * Use builtin termcap
+ */
+ {
+#ifdef HAVE_TGETENT
+ /*
+ * If builtin termcap was already used, there is no need to search
+ * for the builtin termcap again, quit now.
+ */
+ if (try == 2 && builtin_first && termcap_cleared)
+ break;
+#endif
+ /*
+ * search for 'term' in builtin_termcaps[]
+ */
+ termp = find_builtin_term(term);
+ if (termp->bt_string == NULL) /* did not find it */
+ {
+#ifdef HAVE_TGETENT
+ /*
+ * If try == 0, first try the external termcap. If that is not
+ * found we'll get back here with try == 2.
+ * If termcap_cleared is set we used the external termcap,
+ * don't complain about not finding the term in the builtin
+ * termcap.
+ */
+ if (try == 0) /* try external one */
+ continue;
+ if (termcap_cleared) /* found in external termcap */
+ break;
+#endif
+ report_term_error(error_msg, term);
+
+ /* when user typed :set term=xxx, quit here */
+ if (starting != NO_SCREEN)
+ {
+ screen_start(); /* don't know where cursor is now */
+ wait_return(TRUE);
+ return FAIL;
+ }
+ term = DEFAULT_TERM;
+ report_default_term(term);
+ set_string_option_direct((char_u *)"term", -1, term,
+ OPT_FREE, 0);
+ display_errors();
+ }
+ out_flush();
+#ifdef HAVE_TGETENT
+ if (!termcap_cleared)
+ {
+#endif
+ clear_termoptions(); /* clear old options */
+#ifdef HAVE_TGETENT
+ termcap_cleared = TRUE;
+ }
+#endif
+ parse_builtin_tcap(term);
+#ifdef FEAT_GUI
+ if (term_is_gui(term))
+ {
+ out_flush();
+ gui_init();
+ /* If starting the GUI failed, don't do any of the other
+ * things for this terminal */
+ if (!gui.in_use)
+ return FAIL;
+#ifdef HAVE_TGETENT
+ break; /* don't try using external termcap */
+#endif
+ }
+#endif /* FEAT_GUI */
+ }
+#ifdef HAVE_TGETENT
+ }
+#endif
+
+/*
+ * special: There is no info in the termcap about whether the cursor
+ * positioning is relative to the start of the screen or to the start of the
+ * scrolling region. We just guess here. Only msdos pcterm is known to do it
+ * relative.
+ */
+ if (STRCMP(term, "pcterm") == 0)
+ T_CCS = (char_u *)"yes";
+ else
+ T_CCS = empty_option;
+
+#ifdef UNIX
+/*
+ * Any "stty" settings override the default for t_kb from the termcap.
+ * This is in os_unix.c, because it depends a lot on the version of unix that
+ * is being used.
+ * Don't do this when the GUI is active, it uses "t_kb" and "t_kD" directly.
+ */
+# ifdef FEAT_GUI
+ if (!gui.in_use)
+# endif
+ get_stty();
+#endif
+
+/*
+ * If the termcap has no entry for 'bs' and/or 'del' and the ioctl() also
+ * didn't work, use the default CTRL-H
+ * The default for t_kD is DEL, unless t_kb is DEL.
+ * The vim_strsave'd strings are probably lost forever, well it's only two
+ * bytes. Don't do this when the GUI is active, it uses "t_kb" and "t_kD"
+ * directly.
+ */
+#ifdef FEAT_GUI
+ if (!gui.in_use)
+#endif
+ {
+ bs_p = find_termcode((char_u *)"kb");
+ del_p = find_termcode((char_u *)"kD");
+ if (bs_p == NULL || *bs_p == NUL)
+ add_termcode((char_u *)"kb", (bs_p = (char_u *)CTRL_H_STR), FALSE);
+ if ((del_p == NULL || *del_p == NUL) &&
+ (bs_p == NULL || *bs_p != DEL))
+ add_termcode((char_u *)"kD", (char_u *)DEL_STR, FALSE);
+ }
+
+#if defined(UNIX) || defined(VMS)
+ term_is_xterm = vim_is_xterm(term);
+#endif
+
+#ifdef FEAT_MOUSE
+# if defined(UNIX) || defined(VMS)
+# ifdef FEAT_MOUSE_TTY
+ /*
+ * For Unix, set the 'ttymouse' option to the type of mouse to be used.
+ * The termcode for the mouse is added as a side effect in option.c.
+ */
+ {
+ char_u *p = (char_u *)"";
+
+# ifdef FEAT_MOUSE_XTERM
+ if (use_xterm_like_mouse(term))
+ {
+ if (use_xterm_mouse())
+ p = NULL; /* keep existing value, might be "xterm2" */
+ else
+ p = (char_u *)"xterm";
+ }
+# endif
+ if (p != NULL)
+ {
+ set_option_value((char_u *)"ttym", 0L, p, 0);
+ /* Reset the WAS_SET flag, 'ttymouse' can be set to "sgr" or
+ * "xterm2" in check_termcode(). */
+ reset_option_was_set((char_u *)"ttym");
+ }
+ if (p == NULL
+# ifdef FEAT_GUI
+ || gui.in_use
+# endif
+ )
+ check_mouse_termcode(); /* set mouse termcode anyway */
+ }
+# endif
+# else
+ set_mouse_termcode(KS_MOUSE, (char_u *)"\233M");
+# endif
+#endif /* FEAT_MOUSE */
+
+#ifdef USE_TERM_CONSOLE
+ /* DEFAULT_TERM indicates that it is the machine console. */
+ if (STRCMP(term, DEFAULT_TERM) != 0)
+ term_console = FALSE;
+ else
+ {
+ term_console = TRUE;
+# ifdef AMIGA
+ win_resize_on(); /* enable window resizing reports */
+# endif
+ }
+#endif
+
+#if defined(UNIX) || defined(VMS)
+ /*
+ * 'ttyfast' is default on for xterm, iris-ansi and a few others.
+ */
+ if (vim_is_fastterm(term))
+ p_tf = TRUE;
+#endif
+#ifdef USE_TERM_CONSOLE
+ /*
+ * 'ttyfast' is default on consoles
+ */
+ if (term_console)
+ p_tf = TRUE;
+#endif
+
+ ttest(TRUE); /* make sure we have a valid set of terminal codes */
+
+ full_screen = TRUE; /* we can use termcap codes from now on */
+ set_term_defaults(); /* use current values as defaults */
+#ifdef FEAT_TERMRESPONSE
+ LOG_TR(("setting crv_status to STATUS_GET"));
+ crv_status = STATUS_GET; /* Get terminal version later */
+#endif
+
+ /*
+ * Initialize the terminal with the appropriate termcap codes.
+ * Set the mouse and window title if possible.
+ * Don't do this when starting, need to parse the .vimrc first, because it
+ * may redefine t_TI etc.
+ */
+ if (starting != NO_SCREEN)
+ {
+ starttermcap(); /* may change terminal mode */
+#ifdef FEAT_MOUSE
+ setmouse(); /* may start using the mouse */
+#endif
+#ifdef FEAT_TITLE
+ maketitle(); /* may display window title */
+#endif
+ }
+
+ /* display initial screen after ttest() checking. jw. */
+ if (width <= 0 || height <= 0)
+ {
+ /* termcap failed to report size */
+ /* set defaults, in case ui_get_shellsize() also fails */
+ width = 80;
+#if defined(WIN3264)
+ height = 25; /* console is often 25 lines */
+#else
+ height = 24; /* most terminals are 24 lines */
+#endif
+ }
+ set_shellsize(width, height, FALSE); /* may change Rows */
+ if (starting != NO_SCREEN)
+ {
+ if (scroll_region)
+ scroll_region_reset(); /* In case Rows changed */
+ check_map_keycodes(); /* check mappings for terminal codes used */
+
+ {
+ bufref_T old_curbuf;
+
+ /*
+ * Execute the TermChanged autocommands for each buffer that is
+ * loaded.
+ */
+ set_bufref(&old_curbuf, curbuf);
+ FOR_ALL_BUFFERS(curbuf)
+ {
+ if (curbuf->b_ml.ml_mfp != NULL)
+ apply_autocmds(EVENT_TERMCHANGED, NULL, NULL, FALSE,
+ curbuf);
+ }
+ if (bufref_valid(&old_curbuf))
+ curbuf = old_curbuf.br_buf;
+ }
+ }
+
+#ifdef FEAT_TERMRESPONSE
+ may_req_termresponse();
+#endif
+
+ return OK;
+}
+
+#if defined(FEAT_MOUSE) || defined(PROTO)
+
+# ifdef FEAT_MOUSE_TTY
+# define HMT_NORMAL 1
+# define HMT_NETTERM 2
+# define HMT_DEC 4
+# define HMT_JSBTERM 8
+# define HMT_PTERM 16
+# define HMT_URXVT 32
+# define HMT_SGR 64
+# define HMT_SGR_REL 128
+static int has_mouse_termcode = 0;
+# endif
+
+# if (!defined(UNIX) || defined(FEAT_MOUSE_TTY)) || defined(PROTO)
+ void
+set_mouse_termcode(
+ int n, /* KS_MOUSE, KS_NETTERM_MOUSE or KS_DEC_MOUSE */
+ char_u *s)
+{
+ char_u name[2];
+
+ name[0] = n;
+ name[1] = KE_FILLER;
+ add_termcode(name, s, FALSE);
+# ifdef FEAT_MOUSE_TTY
+# ifdef FEAT_MOUSE_JSB
+ if (n == KS_JSBTERM_MOUSE)
+ has_mouse_termcode |= HMT_JSBTERM;
+ else
+# endif
+# ifdef FEAT_MOUSE_NET
+ if (n == KS_NETTERM_MOUSE)
+ has_mouse_termcode |= HMT_NETTERM;
+ else
+# endif
+# ifdef FEAT_MOUSE_DEC
+ if (n == KS_DEC_MOUSE)
+ has_mouse_termcode |= HMT_DEC;
+ else
+# endif
+# ifdef FEAT_MOUSE_PTERM
+ if (n == KS_PTERM_MOUSE)
+ has_mouse_termcode |= HMT_PTERM;
+ else
+# endif
+# ifdef FEAT_MOUSE_URXVT
+ if (n == KS_URXVT_MOUSE)
+ has_mouse_termcode |= HMT_URXVT;
+ else
+# endif
+# ifdef FEAT_MOUSE_SGR
+ if (n == KS_SGR_MOUSE)
+ has_mouse_termcode |= HMT_SGR;
+ else if (n == KS_SGR_MOUSE_RELEASE)
+ has_mouse_termcode |= HMT_SGR_REL;
+ else
+# endif
+ has_mouse_termcode |= HMT_NORMAL;
+# endif
+}
+# endif
+
+# if ((defined(UNIX) || defined(VMS)) \
+ && defined(FEAT_MOUSE_TTY)) || defined(PROTO)
+ void
+del_mouse_termcode(
+ int n) /* KS_MOUSE, KS_NETTERM_MOUSE or KS_DEC_MOUSE */
+{
+ char_u name[2];
+
+ name[0] = n;
+ name[1] = KE_FILLER;
+ del_termcode(name);
+# ifdef FEAT_MOUSE_TTY
+# ifdef FEAT_MOUSE_JSB
+ if (n == KS_JSBTERM_MOUSE)
+ has_mouse_termcode &= ~HMT_JSBTERM;
+ else
+# endif
+# ifdef FEAT_MOUSE_NET
+ if (n == KS_NETTERM_MOUSE)
+ has_mouse_termcode &= ~HMT_NETTERM;
+ else
+# endif
+# ifdef FEAT_MOUSE_DEC
+ if (n == KS_DEC_MOUSE)
+ has_mouse_termcode &= ~HMT_DEC;
+ else
+# endif
+# ifdef FEAT_MOUSE_PTERM
+ if (n == KS_PTERM_MOUSE)
+ has_mouse_termcode &= ~HMT_PTERM;
+ else
+# endif
+# ifdef FEAT_MOUSE_URXVT
+ if (n == KS_URXVT_MOUSE)
+ has_mouse_termcode &= ~HMT_URXVT;
+ else
+# endif
+# ifdef FEAT_MOUSE_SGR
+ if (n == KS_SGR_MOUSE)
+ has_mouse_termcode &= ~HMT_SGR;
+ else if (n == KS_SGR_MOUSE_RELEASE)
+ has_mouse_termcode &= ~HMT_SGR_REL;
+ else
+# endif
+ has_mouse_termcode &= ~HMT_NORMAL;
+# endif
+}
+# endif
+#endif
+
+#ifdef HAVE_TGETENT
+/*
+ * Call tgetent()
+ * Return error message if it fails, NULL if it's OK.
+ */
+ static char *
+tgetent_error(char_u *tbuf, char_u *term)
+{
+ int i;
+
+ i = TGETENT(tbuf, term);
+ if (i < 0 /* -1 is always an error */
+# ifdef TGETENT_ZERO_ERR
+ || i == 0 /* sometimes zero is also an error */
+# endif
+ )
+ {
+ /* On FreeBSD tputs() gets a SEGV after a tgetent() which fails. Call
+ * tgetent() with the always existing "dumb" entry to avoid a crash or
+ * hang. */
+ (void)TGETENT(tbuf, "dumb");
+
+ if (i < 0)
+# ifdef TGETENT_ZERO_ERR
+ return _("E557: Cannot open termcap file");
+ if (i == 0)
+# endif
+#ifdef TERMINFO
+ return _("E558: Terminal entry not found in terminfo");
+#else
+ return _("E559: Terminal entry not found in termcap");
+#endif
+ }
+ return NULL;
+}
+
+/*
+ * Some versions of tgetstr() have been reported to return -1 instead of NULL.
+ * Fix that here.
+ */
+ static char_u *
+vim_tgetstr(char *s, char_u **pp)
+{
+ char *p;
+
+ p = tgetstr(s, (char **)pp);
+ if (p == (char *)-1)
+ p = NULL;
+ return (char_u *)p;
+}
+#endif /* HAVE_TGETENT */
+
+#if defined(HAVE_TGETENT) && (defined(UNIX) || defined(VMS) || defined(MACOS_X))
+/*
+ * Get Columns and Rows from the termcap. Used after a window signal if the
+ * ioctl() fails. It doesn't make sense to call tgetent each time if the "co"
+ * and "li" entries never change. But on some systems this works.
+ * Errors while getting the entries are ignored.
+ */
+ void
+getlinecol(
+ long *cp, /* pointer to columns */
+ long *rp) /* pointer to rows */
+{
+ char_u tbuf[TBUFSZ];
+
+ if (T_NAME != NULL && *T_NAME != NUL && tgetent_error(tbuf, T_NAME) == NULL)
+ {
+ if (*cp == 0)
+ *cp = tgetnum("co");
+ if (*rp == 0)
+ *rp = tgetnum("li");
+ }
+}
+#endif /* defined(HAVE_TGETENT) && defined(UNIX) */
+
+/*
+ * Get a string entry from the termcap and add it to the list of termcodes.
+ * Used for <t_xx> special keys.
+ * Give an error message for failure when not sourcing.
+ * If force given, replace an existing entry.
+ * Return FAIL if the entry was not found, OK if the entry was added.
+ */
+ int
+add_termcap_entry(char_u *name, int force)
+{
+ char_u *term;
+ int key;
+ struct builtin_term *termp;
+#ifdef HAVE_TGETENT
+ char_u *string;
+ int i;
+ int builtin_first;
+ char_u tbuf[TBUFSZ];
+ char_u tstrbuf[TBUFSZ];
+ char_u *tp = tstrbuf;
+ char *error_msg = NULL;
+#endif
+
+/*
+ * If the GUI is running or will start in a moment, we only support the keys
+ * that the GUI can produce.
+ */
+#ifdef FEAT_GUI
+ if (gui.in_use || gui.starting)
+ return gui_mch_haskey(name);
+#endif
+
+ if (!force && find_termcode(name) != NULL) /* it's already there */
+ return OK;
+
+ term = T_NAME;
+ if (term == NULL || *term == NUL) /* 'term' not defined yet */
+ return FAIL;
+
+ if (term_is_builtin(term)) /* name starts with "builtin_" */
+ {
+ term += 8;
+#ifdef HAVE_TGETENT
+ builtin_first = TRUE;
+#endif
+ }
+#ifdef HAVE_TGETENT
+ else
+ builtin_first = p_tbi;
+#endif
+
+#ifdef HAVE_TGETENT
+/*
+ * We can get the entry from the builtin termcap and from the external one.
+ * If 'ttybuiltin' is on or the terminal name starts with "builtin_", try
+ * builtin termcap first.
+ * If 'ttybuiltin' is off, try external termcap first.
+ */
+ for (i = 0; i < 2; ++i)
+ {
+ if ((!builtin_first) == i)
+#endif
+ /*
+ * Search in builtin termcap
+ */
+ {
+ termp = find_builtin_term(term);
+ if (termp->bt_string != NULL) /* found it */
+ {
+ key = TERMCAP2KEY(name[0], name[1]);
+ ++termp;
+ while (termp->bt_entry != (int)KS_NAME)
+ {
+ if ((int)termp->bt_entry == key)
+ {
+ add_termcode(name, (char_u *)termp->bt_string,
+ term_is_8bit(term));
+ return OK;
+ }
+ ++termp;
+ }
+ }
+ }
+#ifdef HAVE_TGETENT
+ else
+ /*
+ * Search in external termcap
+ */
+ {
+ error_msg = tgetent_error(tbuf, term);
+ if (error_msg == NULL)
+ {
+ string = TGETSTR((char *)name, &tp);
+ if (string != NULL && *string != NUL)
+ {
+ add_termcode(name, string, FALSE);
+ return OK;
+ }
+ }
+ }
+ }
+#endif
+
+ if (sourcing_name == NULL)
+ {
+#ifdef HAVE_TGETENT
+ if (error_msg != NULL)
+ emsg(error_msg);
+ else
+#endif
+ semsg(_("E436: No \"%s\" entry in termcap"), name);
+ }
+ return FAIL;
+}
+
+ static int
+term_is_builtin(char_u *name)
+{
+ return (STRNCMP(name, "builtin_", (size_t)8) == 0);
+}
+
+/*
+ * Return TRUE if terminal "name" uses CSI instead of <Esc>[.
+ * Assume that the terminal is using 8-bit controls when the name contains
+ * "8bit", like in "xterm-8bit".
+ */
+ int
+term_is_8bit(char_u *name)
+{
+ return (detected_8bit || strstr((char *)name, "8bit") != NULL);
+}
+
+/*
+ * Translate terminal control chars from 7-bit to 8-bit:
+ * <Esc>[ -> CSI <M_C_[>
+ * <Esc>] -> OSC <M-C-]>
+ * <Esc>O -> <M-C-O>
+ */
+ static int
+term_7to8bit(char_u *p)
+{
+ if (*p == ESC)
+ {
+ if (p[1] == '[')
+ return CSI;
+ if (p[1] == ']')
+ return OSC;
+ if (p[1] == 'O')
+ return 0x8f;
+ }
+ return 0;
+}
+
+#if defined(FEAT_GUI) || defined(PROTO)
+ int
+term_is_gui(char_u *name)
+{
+ return (STRCMP(name, "builtin_gui") == 0 || STRCMP(name, "gui") == 0);
+}
+#endif
+
+#if !defined(HAVE_TGETENT) || defined(AMIGA) || defined(PROTO)
+
+ char_u *
+tltoa(unsigned long i)
+{
+ static char_u buf[16];
+ char_u *p;
+
+ p = buf + 15;
+ *p = '\0';
+ do
+ {
+ --p;
+ *p = (char_u) (i % 10 + '0');
+ i /= 10;
+ }
+ while (i > 0 && p > buf);
+ return p;
+}
+#endif
+
+#ifndef HAVE_TGETENT
+
+/*
+ * minimal tgoto() implementation.
+ * no padding and we only parse for %i %d and %+char
+ */
+ static char *
+tgoto(char *cm, int x, int y)
+{
+ static char buf[30];
+ char *p, *s, *e;
+
+ if (!cm)
+ return "OOPS";
+ e = buf + 29;
+ for (s = buf; s < e && *cm; cm++)
+ {
+ if (*cm != '%')
+ {
+ *s++ = *cm;
+ continue;
+ }
+ switch (*++cm)
+ {
+ case 'd':
+ p = (char *)tltoa((unsigned long)y);
+ y = x;
+ while (*p)
+ *s++ = *p++;
+ break;
+ case 'i':
+ x++;
+ y++;
+ break;
+ case '+':
+ *s++ = (char)(*++cm + y);
+ y = x;
+ break;
+ case '%':
+ *s++ = *cm;
+ break;
+ default:
+ return "OOPS";
+ }
+ }
+ *s = '\0';
+ return buf;
+}
+
+#endif /* HAVE_TGETENT */
+
+/*
+ * Set the terminal name and initialize the terminal options.
+ * If "name" is NULL or empty, get the terminal name from the environment.
+ * If that fails, use the default terminal name.
+ */
+ void
+termcapinit(char_u *name)
+{
+ char_u *term;
+
+ if (name != NULL && *name == NUL)
+ name = NULL; /* empty name is equal to no name */
+ term = name;
+
+#ifdef __BEOS__
+ /*
+ * TERM environment variable is normally set to 'ansi' on the Bebox;
+ * Since the BeBox doesn't quite support full ANSI yet, we use our
+ * own custom 'ansi-beos' termcap instead, unless the -T option has
+ * been given on the command line.
+ */
+ if (term == NULL
+ && strcmp((char *)mch_getenv((char_u *)"TERM"), "ansi") == 0)
+ term = DEFAULT_TERM;
+#endif
+#ifndef MSWIN
+ if (term == NULL)
+ term = mch_getenv((char_u *)"TERM");
+#endif
+ if (term == NULL || *term == NUL)
+ term = DEFAULT_TERM;
+ set_string_option_direct((char_u *)"term", -1, term, OPT_FREE, 0);
+
+ /* Set the default terminal name. */
+ set_string_default("term", term);
+ set_string_default("ttytype", term);
+
+ /*
+ * Avoid using "term" here, because the next mch_getenv() may overwrite it.
+ */
+ set_termname(T_NAME != NULL ? T_NAME : term);
+}
+
+/*
+ * the number of calls to ui_write is reduced by using the buffer "out_buf"
+ */
+#define OUT_SIZE 2047
+ /* Add one to allow mch_write() in os_win32.c to append a NUL */
+static char_u out_buf[OUT_SIZE + 1];
+static int out_pos = 0; /* number of chars in out_buf */
+
+/*
+ * out_flush(): flush the output buffer
+ */
+ void
+out_flush(void)
+{
+ int len;
+
+ if (out_pos != 0)
+ {
+ /* set out_pos to 0 before ui_write, to avoid recursiveness */
+ len = out_pos;
+ out_pos = 0;
+ ui_write(out_buf, len);
+ }
+}
+
+/*
+ * out_flush_cursor(): flush the output buffer and redraw the cursor.
+ * Does not flush recursively in the GUI to avoid slow drawing.
+ */
+ void
+out_flush_cursor(
+ int force UNUSED, /* when TRUE, update cursor even when not moved */
+ int clear_selection UNUSED) /* clear selection under cursor */
+{
+ mch_disable_flush();
+ out_flush();
+ mch_enable_flush();
+#ifdef FEAT_GUI
+ if (gui.in_use)
+ {
+ gui_update_cursor(force, clear_selection);
+ gui_may_flush();
+ }
+#endif
+}
+
+
+/*
+ * Sometimes a byte out of a multi-byte character is written with out_char().
+ * To avoid flushing half of the character, call this function first.
+ */
+ void
+out_flush_check(void)
+{
+ if (enc_dbcs != 0 && out_pos >= OUT_SIZE - MB_MAXBYTES)
+ out_flush();
+}
+
+#ifdef FEAT_GUI
+/*
+ * out_trash(): Throw away the contents of the output buffer
+ */
+ void
+out_trash(void)
+{
+ out_pos = 0;
+}
+#endif
+
+/*
+ * out_char(c): put a byte into the output buffer.
+ * Flush it if it becomes full.
+ * This should not be used for outputting text on the screen (use functions
+ * like msg_puts() and screen_putchar() for that).
+ */
+ void
+out_char(unsigned c)
+{
+#if defined(UNIX) || defined(VMS) || defined(AMIGA) || defined(MACOS_X)
+ if (c == '\n') /* turn LF into CR-LF (CRMOD doesn't seem to do this) */
+ out_char('\r');
+#endif
+
+ out_buf[out_pos++] = c;
+
+ /* For testing we flush each time. */
+ if (out_pos >= OUT_SIZE || p_wd)
+ out_flush();
+}
+
+static void out_char_nf(unsigned);
+
+/*
+ * out_char_nf(c): like out_char(), but don't flush when p_wd is set
+ */
+ static void
+out_char_nf(unsigned c)
+{
+#if defined(UNIX) || defined(VMS) || defined(AMIGA) || defined(MACOS_X)
+ if (c == '\n') /* turn LF into CR-LF (CRMOD doesn't seem to do this) */
+ out_char_nf('\r');
+#endif
+
+ out_buf[out_pos++] = c;
+
+ if (out_pos >= OUT_SIZE)
+ out_flush();
+}
+
+#if defined(FEAT_TITLE) || defined(FEAT_MOUSE_TTY) || defined(FEAT_GUI) \
+ || defined(FEAT_TERMRESPONSE) || defined(PROTO)
+/*
+ * A never-padding out_str.
+ * use this whenever you don't want to run the string through tputs.
+ * tputs above is harmless, but tputs from the termcap library
+ * is likely to strip off leading digits, that it mistakes for padding
+ * information, and "%i", "%d", etc.
+ * This should only be used for writing terminal codes, not for outputting
+ * normal text (use functions like msg_puts() and screen_putchar() for that).
+ */
+ void
+out_str_nf(char_u *s)
+{
+ if (out_pos > OUT_SIZE - 20) /* avoid terminal strings being split up */
+ out_flush();
+ while (*s)
+ out_char_nf(*s++);
+
+ /* For testing we write one string at a time. */
+ if (p_wd)
+ out_flush();
+}
+#endif
+
+/*
+ * A conditional-flushing out_str, mainly for visualbell.
+ * Handles a delay internally, because termlib may not respect the delay or do
+ * it at the wrong time.
+ * Note: Only for terminal strings.
+ */
+ void
+out_str_cf(char_u *s)
+{
+ if (s != NULL && *s)
+ {
+#ifdef HAVE_TGETENT
+ char_u *p;
+#endif
+
+#ifdef FEAT_GUI
+ /* Don't use tputs() when GUI is used, ncurses crashes. */
+ if (gui.in_use)
+ {
+ out_str_nf(s);
+ return;
+ }
+#endif
+ if (out_pos > OUT_SIZE - 20)
+ out_flush();
+#ifdef HAVE_TGETENT
+ for (p = s; *s; ++s)
+ {
+ /* flush just before delay command */
+ if (*s == '$' && *(s + 1) == '<')
+ {
+ char_u save_c = *s;
+ int duration = atoi((char *)s + 2);
+
+ *s = NUL;
+ tputs((char *)p, 1, TPUTSFUNCAST out_char_nf);
+ *s = save_c;
+ out_flush();
+# ifdef ELAPSED_FUNC
+ /* Only sleep here if we can limit this happening in
+ * vim_beep(). */
+ p = vim_strchr(s, '>');
+ if (p == NULL || duration <= 0)
+ {
+ /* can't parse the time, don't sleep here */
+ p = s;
+ }
+ else
+ {
+ ++p;
+ do_sleep(duration);
+ }
+# else
+ /* Rely on the terminal library to sleep. */
+ p = s;
+# endif
+ break;
+ }
+ }
+ tputs((char *)p, 1, TPUTSFUNCAST out_char_nf);
+#else
+ while (*s)
+ out_char_nf(*s++);
+#endif
+
+ /* For testing we write one string at a time. */
+ if (p_wd)
+ out_flush();
+ }
+}
+
+/*
+ * out_str(s): Put a character string a byte at a time into the output buffer.
+ * If HAVE_TGETENT is defined use the termcap parser. (jw)
+ * This should only be used for writing terminal codes, not for outputting
+ * normal text (use functions like msg_puts() and screen_putchar() for that).
+ */
+ void
+out_str(char_u *s)
+{
+ if (s != NULL && *s)
+ {
+#ifdef FEAT_GUI
+ /* Don't use tputs() when GUI is used, ncurses crashes. */
+ if (gui.in_use)
+ {
+ out_str_nf(s);
+ return;
+ }
+#endif
+ /* avoid terminal strings being split up */
+ if (out_pos > OUT_SIZE - 20)
+ out_flush();
+#ifdef HAVE_TGETENT
+ tputs((char *)s, 1, TPUTSFUNCAST out_char_nf);
+#else
+ while (*s)
+ out_char_nf(*s++);
+#endif
+
+ /* For testing we write one string at a time. */
+ if (p_wd)
+ out_flush();
+ }
+}
+
+/*
+ * cursor positioning using termcap parser. (jw)
+ */
+ void
+term_windgoto(int row, int col)
+{
+ OUT_STR(tgoto((char *)T_CM, col, row));
+}
+
+ void
+term_cursor_right(int i)
+{
+ OUT_STR(tgoto((char *)T_CRI, 0, i));
+}
+
+ void
+term_append_lines(int line_count)
+{
+ OUT_STR(tgoto((char *)T_CAL, 0, line_count));
+}
+
+ void
+term_delete_lines(int line_count)
+{
+ OUT_STR(tgoto((char *)T_CDL, 0, line_count));
+}
+
+#if defined(HAVE_TGETENT) || defined(PROTO)
+ void
+term_set_winpos(int x, int y)
+{
+ /* Can't handle a negative value here */
+ if (x < 0)
+ x = 0;
+ if (y < 0)
+ y = 0;
+ OUT_STR(tgoto((char *)T_CWP, y, x));
+}
+
+# if defined(FEAT_TERMRESPONSE) || defined(PROTO)
+/*
+ * Return TRUE if we can request the terminal for a response.
+ */
+ static int
+can_get_termresponse()
+{
+ return cur_tmode == TMODE_RAW
+ && termcap_active
+# ifdef UNIX
+ && (is_not_a_term() || (isatty(1) && isatty(read_cmd_fd)))
+# endif
+ && p_ek;
+}
+
+static int winpos_x = -1;
+static int winpos_y = -1;
+static int did_request_winpos = 0;
+
+# if (defined(FEAT_EVAL) && defined(HAVE_TGETENT)) || defined(PROTO)
+/*
+ * Try getting the Vim window position from the terminal.
+ * Returns OK or FAIL.
+ */
+ int
+term_get_winpos(int *x, int *y, varnumber_T timeout)
+{
+ int count = 0;
+ int prev_winpos_x = winpos_x;
+ int prev_winpos_y = winpos_y;
+
+ if (*T_CGP == NUL || !can_get_termresponse())
+ return FAIL;
+ winpos_x = -1;
+ winpos_y = -1;
+ ++did_request_winpos;
+ winpos_status = STATUS_SENT;
+ OUT_STR(T_CGP);
+ out_flush();
+
+ /* Try reading the result for "timeout" msec. */
+ while (count++ <= timeout / 10 && !got_int)
+ {
+ (void)vpeekc_nomap();
+ if (winpos_x >= 0 && winpos_y >= 0)
+ {
+ *x = winpos_x;
+ *y = winpos_y;
+ return OK;
+ }
+ ui_delay(10, FALSE);
+ }
+ /* Do not reset "did_request_winpos", if we timed out the response might
+ * still come later and we must consume it. */
+
+ winpos_x = prev_winpos_x;
+ winpos_y = prev_winpos_y;
+ if (timeout < 10 && prev_winpos_y >= 0 && prev_winpos_x >= 0)
+ {
+ /* Polling: return previous values if we have them. */
+ *x = winpos_x;
+ *y = winpos_y;
+ return OK;
+ }
+
+ return FALSE;
+}
+# endif
+# endif
+
+ void
+term_set_winsize(int height, int width)
+{
+ OUT_STR(tgoto((char *)T_CWS, width, height));
+}
+#endif
+
+ static void
+term_color(char_u *s, int n)
+{
+ char buf[20];
+ int i = *s == CSI ? 1 : 2;
+ /* index in s[] just after <Esc>[ or CSI */
+
+ /* Special handling of 16 colors, because termcap can't handle it */
+ /* Also accept "\e[3%dm" for TERMINFO, it is sometimes used */
+ /* Also accept CSI instead of <Esc>[ */
+ if (n >= 8 && t_colors >= 16
+ && ((s[0] == ESC && s[1] == '[')
+#if defined(FEAT_VTP) && defined(FEAT_TERMGUICOLORS)
+ || (s[0] == ESC && s[1] == '|')
+#endif
+ || (s[0] == CSI && (i = 1) == 1))
+ && s[i] != NUL
+ && (STRCMP(s + i + 1, "%p1%dm") == 0
+ || STRCMP(s + i + 1, "%dm") == 0)
+ && (s[i] == '3' || s[i] == '4'))
+ {
+#ifdef TERMINFO
+ char *format = "%s%s%%p1%%dm";
+#else
+ char *format = "%s%s%%dm";
+#endif
+ char *lead = i == 2 ? (
+#if defined(FEAT_VTP) && defined(FEAT_TERMGUICOLORS)
+ s[1] == '|' ? IF_EB("\033|", ESC_STR "|") :
+#endif
+ IF_EB("\033[", ESC_STR "[")) : "\233";
+ char *tail = s[i] == '3' ? (n >= 16 ? "38;5;" : "9")
+ : (n >= 16 ? "48;5;" : "10");
+
+ sprintf(buf, format, lead, tail);
+ OUT_STR(tgoto(buf, 0, n >= 16 ? n : n - 8));
+ }
+ else
+ OUT_STR(tgoto((char *)s, 0, n));
+}
+
+ void
+term_fg_color(int n)
+{
+ /* Use "AF" termcap entry if present, "Sf" entry otherwise */
+ if (*T_CAF)
+ term_color(T_CAF, n);
+ else if (*T_CSF)
+ term_color(T_CSF, n);
+}
+
+ void
+term_bg_color(int n)
+{
+ /* Use "AB" termcap entry if present, "Sb" entry otherwise */
+ if (*T_CAB)
+ term_color(T_CAB, n);
+ else if (*T_CSB)
+ term_color(T_CSB, n);
+}
+
+#if defined(FEAT_TERMGUICOLORS) || defined(PROTO)
+
+#define RED(rgb) (((long_u)(rgb) >> 16) & 0xFF)
+#define GREEN(rgb) (((long_u)(rgb) >> 8) & 0xFF)
+#define BLUE(rgb) (((long_u)(rgb) ) & 0xFF)
+
+ static void
+term_rgb_color(char_u *s, guicolor_T rgb)
+{
+#define MAX_COLOR_STR_LEN 100
+ char buf[MAX_COLOR_STR_LEN];
+
+ vim_snprintf(buf, MAX_COLOR_STR_LEN,
+ (char *)s, RED(rgb), GREEN(rgb), BLUE(rgb));
+ OUT_STR(buf);
+}
+
+ void
+term_fg_rgb_color(guicolor_T rgb)
+{
+ term_rgb_color(T_8F, rgb);
+}
+
+ void
+term_bg_rgb_color(guicolor_T rgb)
+{
+ term_rgb_color(T_8B, rgb);
+}
+#endif
+
+#if (defined(FEAT_TITLE) && (defined(UNIX) || defined(VMS) \
+ || defined(MACOS_X))) || defined(PROTO)
+/*
+ * Generic function to set window title, using t_ts and t_fs.
+ */
+ void
+term_settitle(char_u *title)
+{
+ /* t_ts takes one argument: column in status line */
+ OUT_STR(tgoto((char *)T_TS, 0, 0)); /* set title start */
+ out_str_nf(title);
+ out_str(T_FS); /* set title end */
+ out_flush();
+}
+
+/*
+ * Tell the terminal to push (save) the title and/or icon, so that it can be
+ * popped (restored) later.
+ */
+ void
+term_push_title(int which)
+{
+ if ((which & SAVE_RESTORE_TITLE) && *T_CST != NUL)
+ {
+ OUT_STR(T_CST);
+ out_flush();
+ }
+
+ if ((which & SAVE_RESTORE_ICON) && *T_SSI != NUL)
+ {
+ OUT_STR(T_SSI);
+ out_flush();
+ }
+}
+
+/*
+ * Tell the terminal to pop the title and/or icon.
+ */
+ void
+term_pop_title(int which)
+{
+ if ((which & SAVE_RESTORE_TITLE) && *T_CRT != NUL)
+ {
+ OUT_STR(T_CRT);
+ out_flush();
+ }
+
+ if ((which & SAVE_RESTORE_ICON) && *T_SRI != NUL)
+ {
+ OUT_STR(T_SRI);
+ out_flush();
+ }
+}
+#endif
+
+/*
+ * Make sure we have a valid set or terminal options.
+ * Replace all entries that are NULL by empty_option
+ */
+ void
+ttest(int pairs)
+{
+ char_u *env_colors;
+
+ check_options(); /* make sure no options are NULL */
+
+ /*
+ * MUST have "cm": cursor motion.
+ */
+ if (*T_CM == NUL)
+ emsg(_("E437: terminal capability \"cm\" required"));
+
+ /*
+ * if "cs" defined, use a scroll region, it's faster.
+ */
+ if (*T_CS != NUL)
+ scroll_region = TRUE;
+ else
+ scroll_region = FALSE;
+
+ if (pairs)
+ {
+ /*
+ * optional pairs
+ */
+ /* TP goes to normal mode for TI (invert) and TB (bold) */
+ if (*T_ME == NUL)
+ T_ME = T_MR = T_MD = T_MB = empty_option;
+ if (*T_SO == NUL || *T_SE == NUL)
+ T_SO = T_SE = empty_option;
+ if (*T_US == NUL || *T_UE == NUL)
+ T_US = T_UE = empty_option;
+ if (*T_CZH == NUL || *T_CZR == NUL)
+ T_CZH = T_CZR = empty_option;
+
+ /* T_VE is needed even though T_VI is not defined */
+ if (*T_VE == NUL)
+ T_VI = empty_option;
+
+ /* if 'mr' or 'me' is not defined use 'so' and 'se' */
+ if (*T_ME == NUL)
+ {
+ T_ME = T_SE;
+ T_MR = T_SO;
+ T_MD = T_SO;
+ }
+
+ /* if 'so' or 'se' is not defined use 'mr' and 'me' */
+ if (*T_SO == NUL)
+ {
+ T_SE = T_ME;
+ if (*T_MR == NUL)
+ T_SO = T_MD;
+ else
+ T_SO = T_MR;
+ }
+
+ /* if 'ZH' or 'ZR' is not defined use 'mr' and 'me' */
+ if (*T_CZH == NUL)
+ {
+ T_CZR = T_ME;
+ if (*T_MR == NUL)
+ T_CZH = T_MD;
+ else
+ T_CZH = T_MR;
+ }
+
+ /* "Sb" and "Sf" come in pairs */
+ if (*T_CSB == NUL || *T_CSF == NUL)
+ {
+ T_CSB = empty_option;
+ T_CSF = empty_option;
+ }
+
+ /* "AB" and "AF" come in pairs */
+ if (*T_CAB == NUL || *T_CAF == NUL)
+ {
+ T_CAB = empty_option;
+ T_CAF = empty_option;
+ }
+
+ /* if 'Sb' and 'AB' are not defined, reset "Co" */
+ if (*T_CSB == NUL && *T_CAB == NUL)
+ free_one_termoption(T_CCO);
+
+ /* Set 'weirdinvert' according to value of 't_xs' */
+ p_wiv = (*T_XS != NUL);
+ }
+ need_gather = TRUE;
+
+ /* Set t_colors to the value of $COLORS or t_Co. */
+ t_colors = atoi((char *)T_CCO);
+ env_colors = mch_getenv((char_u *)"COLORS");
+ if (env_colors != NULL && isdigit(*env_colors))
+ {
+ int colors = atoi((char *)env_colors);
+
+ if (colors != t_colors)
+ set_color_count(colors);
+ }
+}
+
+#if (defined(FEAT_GUI) && (defined(FEAT_MENU) || !defined(USE_ON_FLY_SCROLL))) \
+ || defined(PROTO)
+/*
+ * Represent the given long_u as individual bytes, with the most significant
+ * byte first, and store them in dst.
+ */
+ void
+add_long_to_buf(long_u val, char_u *dst)
+{
+ int i;
+ int shift;
+
+ for (i = 1; i <= (int)sizeof(long_u); i++)
+ {
+ shift = 8 * (sizeof(long_u) - i);
+ dst[i - 1] = (char_u) ((val >> shift) & 0xff);
+ }
+}
+
+/*
+ * Interpret the next string of bytes in buf as a long integer, with the most
+ * significant byte first. Note that it is assumed that buf has been through
+ * inchar(), so that NUL and K_SPECIAL will be represented as three bytes each.
+ * Puts result in val, and returns the number of bytes read from buf
+ * (between sizeof(long_u) and 2 * sizeof(long_u)), or -1 if not enough bytes
+ * were present.
+ */
+ static int
+get_long_from_buf(char_u *buf, long_u *val)
+{
+ int len;
+ char_u bytes[sizeof(long_u)];
+ int i;
+ int shift;
+
+ *val = 0;
+ len = get_bytes_from_buf(buf, bytes, (int)sizeof(long_u));
+ if (len != -1)
+ {
+ for (i = 0; i < (int)sizeof(long_u); i++)
+ {
+ shift = 8 * (sizeof(long_u) - 1 - i);
+ *val += (long_u)bytes[i] << shift;
+ }
+ }
+ return len;
+}
+#endif
+
+#if defined(FEAT_GUI) \
+ || (defined(FEAT_MOUSE) && (!defined(UNIX) || defined(FEAT_MOUSE_XTERM) \
+ || defined(FEAT_MOUSE_GPM) || defined(FEAT_SYSMOUSE)))
+/*
+ * Read the next num_bytes bytes from buf, and store them in bytes. Assume
+ * that buf has been through inchar(). Returns the actual number of bytes used
+ * from buf (between num_bytes and num_bytes*2), or -1 if not enough bytes were
+ * available.
+ */
+ static int
+get_bytes_from_buf(char_u *buf, char_u *bytes, int num_bytes)
+{
+ int len = 0;
+ int i;
+ char_u c;
+
+ for (i = 0; i < num_bytes; i++)
+ {
+ if ((c = buf[len++]) == NUL)
+ return -1;
+ if (c == K_SPECIAL)
+ {
+ if (buf[len] == NUL || buf[len + 1] == NUL) /* cannot happen? */
+ return -1;
+ if (buf[len++] == (int)KS_ZERO)
+ c = NUL;
+ /* else it should be KS_SPECIAL; when followed by KE_FILLER c is
+ * K_SPECIAL, or followed by KE_CSI and c must be CSI. */
+ if (buf[len++] == (int)KE_CSI)
+ c = CSI;
+ }
+ else if (c == CSI && buf[len] == KS_EXTRA
+ && buf[len + 1] == (int)KE_CSI)
+ /* CSI is stored as CSI KS_SPECIAL KE_CSI to avoid confusion with
+ * the start of a special key, see add_to_input_buf_csi(). */
+ len += 2;
+ bytes[i] = c;
+ }
+ return len;
+}
+#endif
+
+/*
+ * Check if the new shell size is valid, correct it if it's too small or way
+ * too big.
+ */
+ void
+check_shellsize(void)
+{
+ if (Rows < min_rows()) /* need room for one window and command line */
+ Rows = min_rows();
+ limit_screen_size();
+}
+
+/*
+ * Limit Rows and Columns to avoid an overflow in Rows * Columns.
+ */
+ void
+limit_screen_size(void)
+{
+ if (Columns < MIN_COLUMNS)
+ Columns = MIN_COLUMNS;
+ else if (Columns > 10000)
+ Columns = 10000;
+ if (Rows > 1000)
+ Rows = 1000;
+}
+
+/*
+ * Invoked just before the screen structures are going to be (re)allocated.
+ */
+ void
+win_new_shellsize(void)
+{
+ static int old_Rows = 0;
+ static int old_Columns = 0;
+
+ if (old_Rows != Rows || old_Columns != Columns)
+ ui_new_shellsize();
+ if (old_Rows != Rows)
+ {
+ /* if 'window' uses the whole screen, keep it using that */
+ if (p_window == old_Rows - 1 || old_Rows == 0)
+ p_window = Rows - 1;
+ old_Rows = Rows;
+ shell_new_rows(); /* update window sizes */
+ }
+ if (old_Columns != Columns)
+ {
+ old_Columns = Columns;
+ shell_new_columns(); /* update window sizes */
+ }
+}
+
+/*
+ * Call this function when the Vim shell has been resized in any way.
+ * Will obtain the current size and redraw (also when size didn't change).
+ */
+ void
+shell_resized(void)
+{
+ set_shellsize(0, 0, FALSE);
+}
+
+/*
+ * Check if the shell size changed. Handle a resize.
+ * When the size didn't change, nothing happens.
+ */
+ void
+shell_resized_check(void)
+{
+ int old_Rows = Rows;
+ int old_Columns = Columns;
+
+ if (!exiting
+#ifdef FEAT_GUI
+ /* Do not get the size when executing a shell command during
+ * startup. */
+ && !gui.starting
+#endif
+ )
+ {
+ (void)ui_get_shellsize();
+ check_shellsize();
+ if (old_Rows != Rows || old_Columns != Columns)
+ shell_resized();
+ }
+}
+
+/*
+ * Set size of the Vim shell.
+ * If 'mustset' is TRUE, we must set Rows and Columns, do not get the real
+ * window size (this is used for the :win command).
+ * If 'mustset' is FALSE, we may try to get the real window size and if
+ * it fails use 'width' and 'height'.
+ */
+ void
+set_shellsize(int width, int height, int mustset)
+{
+ static int busy = FALSE;
+
+ /*
+ * Avoid recursiveness, can happen when setting the window size causes
+ * another window-changed signal.
+ */
+ if (busy)
+ return;
+
+ if (width < 0 || height < 0) /* just checking... */
+ return;
+
+ if (State == HITRETURN || State == SETWSIZE)
+ {
+ /* postpone the resizing */
+ State = SETWSIZE;
+ return;
+ }
+
+ /* curwin->w_buffer can be NULL when we are closing a window and the
+ * buffer has already been closed and removing a scrollbar causes a resize
+ * event. Don't resize then, it will happen after entering another buffer.
+ */
+ if (curwin->w_buffer == NULL)
+ return;
+
+ ++busy;
+
+#ifdef AMIGA
+ out_flush(); /* must do this before mch_get_shellsize() for
+ some obscure reason */
+#endif
+
+ if (mustset || (ui_get_shellsize() == FAIL && height != 0))
+ {
+ Rows = height;
+ Columns = width;
+ check_shellsize();
+ ui_set_shellsize(mustset);
+ }
+ else
+ check_shellsize();
+
+ /* The window layout used to be adjusted here, but it now happens in
+ * screenalloc() (also invoked from screenclear()). That is because the
+ * "busy" check above may skip this, but not screenalloc(). */
+
+ if (State != ASKMORE && State != EXTERNCMD && State != CONFIRM)
+ screenclear();
+ else
+ screen_start(); /* don't know where cursor is now */
+
+ if (starting != NO_SCREEN)
+ {
+#ifdef FEAT_TITLE
+ maketitle();
+#endif
+ changed_line_abv_curs();
+ invalidate_botline();
+
+ /*
+ * We only redraw when it's needed:
+ * - While at the more prompt or executing an external command, don't
+ * redraw, but position the cursor.
+ * - While editing the command line, only redraw that.
+ * - in Ex mode, don't redraw anything.
+ * - Otherwise, redraw right now, and position the cursor.
+ * Always need to call update_screen() or screenalloc(), to make
+ * sure Rows/Columns and the size of ScreenLines[] is correct!
+ */
+ if (State == ASKMORE || State == EXTERNCMD || State == CONFIRM
+ || exmode_active)
+ {
+ screenalloc(FALSE);
+ repeat_message();
+ }
+ else
+ {
+ if (curwin->w_p_scb)
+ do_check_scrollbind(TRUE);
+ if (State & CMDLINE)
+ {
+ update_screen(NOT_VALID);
+ redrawcmdline();
+ }
+ else
+ {
+ update_topline();
+#if defined(FEAT_INS_EXPAND)
+ if (pum_visible())
+ {
+ redraw_later(NOT_VALID);
+ ins_compl_show_pum();
+ }
+#endif
+ update_screen(NOT_VALID);
+ if (redrawing())
+ setcursor();
+ }
+ }
+ cursor_on(); /* redrawing may have switched it off */
+ }
+ out_flush();
+ --busy;
+}
+
+/*
+ * Set the terminal to TMODE_RAW (for Normal mode) or TMODE_COOK (for external
+ * commands and Ex mode).
+ */
+ void
+settmode(int tmode)
+{
+#ifdef FEAT_GUI
+ /* don't set the term where gvim was started to any mode */
+ if (gui.in_use)
+ return;
+#endif
+
+ if (full_screen)
+ {
+ /*
+ * When returning after calling a shell we want to really set the
+ * terminal to raw mode, even though we think it already is, because
+ * the shell program may have reset the terminal mode.
+ * When we think the terminal is normal, don't try to set it to
+ * normal again, because that causes problems (logout!) on some
+ * machines.
+ */
+ if (tmode != TMODE_COOK || cur_tmode != TMODE_COOK)
+ {
+#ifdef FEAT_TERMRESPONSE
+# ifdef FEAT_GUI
+ if (!gui.in_use && !gui.starting)
+# endif
+ {
+ /* May need to check for T_CRV response and termcodes, it
+ * doesn't work in Cooked mode, an external program may get
+ * them. */
+ if (tmode != TMODE_RAW && (crv_status == STATUS_SENT
+ || u7_status == STATUS_SENT
+#ifdef FEAT_TERMINAL
+ || rfg_status == STATUS_SENT
+#endif
+ || rbg_status == STATUS_SENT
+ || rbm_status == STATUS_SENT
+ || rcs_status == STATUS_SENT
+ || winpos_status == STATUS_SENT))
+ (void)vpeekc_nomap();
+ check_for_codes_from_term();
+ }
+#endif
+#ifdef FEAT_MOUSE_TTY
+ if (tmode != TMODE_RAW)
+ mch_setmouse(FALSE); /* switch mouse off */
+#endif
+ if (tmode != TMODE_RAW)
+ out_str(T_BD); /* disable bracketed paste mode */
+ out_flush();
+ mch_settmode(tmode); /* machine specific function */
+ cur_tmode = tmode;
+#ifdef FEAT_MOUSE
+ if (tmode == TMODE_RAW)
+ setmouse(); /* may switch mouse on */
+#endif
+ if (tmode == TMODE_RAW)
+ out_str(T_BE); /* enable bracketed paste mode */
+ out_flush();
+ }
+#ifdef FEAT_TERMRESPONSE
+ may_req_termresponse();
+#endif
+ }
+}
+
+ void
+starttermcap(void)
+{
+ if (full_screen && !termcap_active)
+ {
+ out_str(T_TI); /* start termcap mode */
+ out_str(T_KS); /* start "keypad transmit" mode */
+ out_str(T_BE); /* enable bracketed paste mode */
+ out_flush();
+ termcap_active = TRUE;
+ screen_start(); /* don't know where cursor is now */
+#ifdef FEAT_TERMRESPONSE
+# ifdef FEAT_GUI
+ if (!gui.in_use && !gui.starting)
+# endif
+ {
+ may_req_termresponse();
+ /* Immediately check for a response. If t_Co changes, we don't
+ * want to redraw with wrong colors first. */
+ if (crv_status == STATUS_SENT)
+ check_for_codes_from_term();
+ }
+#endif
+ }
+}
+
+ void
+stoptermcap(void)
+{
+ screen_stop_highlight();
+ reset_cterm_colors();
+ if (termcap_active)
+ {
+#ifdef FEAT_TERMRESPONSE
+# ifdef FEAT_GUI
+ if (!gui.in_use && !gui.starting)
+# endif
+ {
+ /* May need to discard T_CRV, T_U7 or T_RBG response. */
+ if (crv_status == STATUS_SENT
+ || u7_status == STATUS_SENT
+# ifdef FEAT_TERMINAL
+ || rfg_status == STATUS_SENT
+# endif
+ || rbg_status == STATUS_SENT
+ || rbm_status == STATUS_SENT
+ || rcs_status == STATUS_SENT
+ || winpos_status == STATUS_SENT)
+ {
+# ifdef UNIX
+ /* Give the terminal a chance to respond. */
+ mch_delay(100L, FALSE);
+# endif
+# ifdef TCIFLUSH
+ /* Discard data received but not read. */
+ if (exiting)
+ tcflush(fileno(stdin), TCIFLUSH);
+# endif
+ }
+ /* Check for termcodes first, otherwise an external program may
+ * get them. */
+ check_for_codes_from_term();
+ }
+#endif
+ out_str(T_BD); /* disable bracketed paste mode */
+ out_str(T_KE); /* stop "keypad transmit" mode */
+ out_flush();
+ termcap_active = FALSE;
+ cursor_on(); /* just in case it is still off */
+ out_str(T_TE); /* stop termcap mode */
+ screen_start(); /* don't know where cursor is now */
+ out_flush();
+ }
+}
+
+#if defined(FEAT_TERMRESPONSE) || defined(PROTO)
+/*
+ * Request version string (for xterm) when needed.
+ * Only do this after switching to raw mode, otherwise the result will be
+ * echoed.
+ * Only do this after startup has finished, to avoid that the response comes
+ * while executing "-c !cmd" or even after "-c quit".
+ * Only do this after termcap mode has been started, otherwise the codes for
+ * the cursor keys may be wrong.
+ * Only do this when 'esckeys' is on, otherwise the response causes trouble in
+ * Insert mode.
+ * On Unix only do it when both output and input are a tty (avoid writing
+ * request to terminal while reading from a file).
+ * The result is caught in check_termcode().
+ */
+ void
+may_req_termresponse(void)
+{
+ if (crv_status == STATUS_GET
+ && can_get_termresponse()
+ && starting == 0
+ && *T_CRV != NUL)
+ {
+ LOG_TR(("Sending CRV request"));
+ out_str(T_CRV);
+ crv_status = STATUS_SENT;
+ /* check for the characters now, otherwise they might be eaten by
+ * get_keystroke() */
+ out_flush();
+ (void)vpeekc_nomap();
+ }
+}
+
+/*
+ * Check how the terminal treats ambiguous character width (UAX #11).
+ * First, we move the cursor to (1, 0) and print a test ambiguous character
+ * \u25bd (WHITE DOWN-POINTING TRIANGLE) and query current cursor position.
+ * If the terminal treats \u25bd as single width, the position is (1, 1),
+ * or if it is treated as double width, that will be (1, 2).
+ * This function has the side effect that changes cursor position, so
+ * it must be called immediately after entering termcap mode.
+ */
+ void
+may_req_ambiguous_char_width(void)
+{
+ if (u7_status == STATUS_GET
+ && can_get_termresponse()
+ && starting == 0
+ && *T_U7 != NUL
+ && !option_was_set((char_u *)"ambiwidth"))
+ {
+ char_u buf[16];
+
+ LOG_TR(("Sending U7 request"));
+ /* Do this in the second row. In the first row the returned sequence
+ * may be CSI 1;2R, which is the same as <S-F3>. */
+ term_windgoto(1, 0);
+ buf[mb_char2bytes(0x25bd, buf)] = 0;
+ out_str(buf);
+ out_str(T_U7);
+ u7_status = STATUS_SENT;
+ out_flush();
+
+ /* This overwrites a few characters on the screen, a redraw is needed
+ * after this. Clear them out for now. */
+ term_windgoto(1, 0);
+ out_str((char_u *)" ");
+ term_windgoto(0, 0);
+
+ /* Need to reset the known cursor position. */
+ screen_start();
+
+ /* check for the characters now, otherwise they might be eaten by
+ * get_keystroke() */
+ out_flush();
+ (void)vpeekc_nomap();
+ }
+}
+
+/*
+ * Similar to requesting the version string: Request the terminal background
+ * color when it is the right moment.
+ */
+ void
+may_req_bg_color(void)
+{
+ if (can_get_termresponse() && starting == 0)
+ {
+ int didit = FALSE;
+
+# ifdef FEAT_TERMINAL
+ /* Only request foreground if t_RF is set. */
+ if (rfg_status == STATUS_GET && *T_RFG != NUL)
+ {
+ LOG_TR(("Sending FG request"));
+ out_str(T_RFG);
+ rfg_status = STATUS_SENT;
+ didit = TRUE;
+ }
+# endif
+
+ /* Only request background if t_RB is set. */
+ if (rbg_status == STATUS_GET && *T_RBG != NUL)
+ {
+ LOG_TR(("Sending BG request"));
+ out_str(T_RBG);
+ rbg_status = STATUS_SENT;
+ didit = TRUE;
+ }
+
+ if (didit)
+ {
+ /* check for the characters now, otherwise they might be eaten by
+ * get_keystroke() */
+ out_flush();
+ (void)vpeekc_nomap();
+ }
+ }
+}
+
+# ifdef DEBUG_TERMRESPONSE
+ static void
+log_tr(const char *fmt, ...)
+{
+ static FILE *fd_tr = NULL;
+ static proftime_T start;
+ proftime_T now;
+ va_list ap;
+
+ if (fd_tr == NULL)
+ {
+ fd_tr = fopen("termresponse.log", "w");
+ profile_start(&start);
+ }
+ now = start;
+ profile_end(&now);
+ fprintf(fd_tr, "%s: %s ", profile_msg(&now),
+ must_redraw == NOT_VALID ? "NV"
+ : must_redraw == CLEAR ? "CL" : " ");
+ va_start(ap, fmt);
+ vfprintf(fd_tr, fmt, ap);
+ va_end(ap);
+ fputc('\n', fd_tr);
+ fflush(fd_tr);
+}
+# endif
+#endif
+
+/*
+ * Return TRUE when saving and restoring the screen.
+ */
+ int
+swapping_screen(void)
+{
+ return (full_screen && *T_TI != NUL);
+}
+
+#if defined(FEAT_MOUSE) || defined(PROTO)
+/*
+ * setmouse() - switch mouse on/off depending on current mode and 'mouse'
+ */
+ void
+setmouse(void)
+{
+# ifdef FEAT_MOUSE_TTY
+ int checkfor;
+# endif
+
+# ifdef FEAT_MOUSESHAPE
+ update_mouseshape(-1);
+# endif
+
+# ifdef FEAT_MOUSE_TTY /* Should be outside proc, but may break MOUSESHAPE */
+# ifdef FEAT_GUI
+ /* In the GUI the mouse is always enabled. */
+ if (gui.in_use)
+ return;
+# endif
+ /* be quick when mouse is off */
+ if (*p_mouse == NUL || has_mouse_termcode == 0)
+ return;
+
+ /* don't switch mouse on when not in raw mode (Ex mode) */
+ if (cur_tmode != TMODE_RAW)
+ {
+ mch_setmouse(FALSE);
+ return;
+ }
+
+ if (VIsual_active)
+ checkfor = MOUSE_VISUAL;
+ else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE)
+ checkfor = MOUSE_RETURN;
+ else if (State & INSERT)
+ checkfor = MOUSE_INSERT;
+ else if (State & CMDLINE)
+ checkfor = MOUSE_COMMAND;
+ else if (State == CONFIRM || State == EXTERNCMD)
+ checkfor = ' '; /* don't use mouse for ":confirm" or ":!cmd" */
+ else
+ checkfor = MOUSE_NORMAL; /* assume normal mode */
+
+ if (mouse_has(checkfor))
+ mch_setmouse(TRUE);
+ else
+ mch_setmouse(FALSE);
+# endif
+}
+
+/*
+ * Return TRUE if
+ * - "c" is in 'mouse', or
+ * - 'a' is in 'mouse' and "c" is in MOUSE_A, or
+ * - the current buffer is a help file and 'h' is in 'mouse' and we are in a
+ * normal editing mode (not at hit-return message).
+ */
+ int
+mouse_has(int c)
+{
+ char_u *p;
+
+ for (p = p_mouse; *p; ++p)
+ switch (*p)
+ {
+ case 'a': if (vim_strchr((char_u *)MOUSE_A, c) != NULL)
+ return TRUE;
+ break;
+ case MOUSE_HELP: if (c != MOUSE_RETURN && curbuf->b_help)
+ return TRUE;
+ break;
+ default: if (c == *p) return TRUE; break;
+ }
+ return FALSE;
+}
+
+/*
+ * Return TRUE when 'mousemodel' is set to "popup" or "popup_setpos".
+ */
+ int
+mouse_model_popup(void)
+{
+ return (p_mousem[0] == 'p');
+}
+#endif
+
+/*
+ * By outputting the 'cursor very visible' termcap code, for some windowed
+ * terminals this makes the screen scrolled to the correct position.
+ * Used when starting Vim or returning from a shell.
+ */
+ void
+scroll_start(void)
+{
+ if (*T_VS != NUL && *T_CVS != NUL)
+ {
+ out_str(T_VS);
+ out_str(T_CVS);
+ screen_start(); /* don't know where cursor is now */
+ }
+}
+
+static int cursor_is_off = FALSE;
+
+/*
+ * Enable the cursor without checking if it's already enabled.
+ */
+ void
+cursor_on_force(void)
+{
+ out_str(T_VE);
+ cursor_is_off = FALSE;
+}
+
+/*
+ * Enable the cursor if it's currently off.
+ */
+ void
+cursor_on(void)
+{
+ if (cursor_is_off)
+ cursor_on_force();
+}
+
+/*
+ * Disable the cursor.
+ */
+ void
+cursor_off(void)
+{
+ if (full_screen && !cursor_is_off)
+ {
+ out_str(T_VI); /* disable cursor */
+ cursor_is_off = TRUE;
+ }
+}
+
+#if defined(CURSOR_SHAPE) || defined(PROTO)
+/*
+ * Set cursor shape to match Insert or Replace mode.
+ */
+ void
+term_cursor_mode(int forced)
+{
+ static int showing_mode = -1;
+ char_u *p;
+
+ /* Only do something when redrawing the screen and we can restore the
+ * mode. */
+ if (!full_screen || *T_CEI == NUL)
+ {
+# ifdef FEAT_TERMRESPONSE
+ if (forced && initial_cursor_shape > 0)
+ /* Restore to initial values. */
+ term_cursor_shape(initial_cursor_shape, initial_cursor_blink);
+# endif
+ return;
+ }
+
+ if ((State & REPLACE) == REPLACE)
+ {
+ if (forced || showing_mode != REPLACE)
+ {
+ if (*T_CSR != NUL)
+ p = T_CSR; /* Replace mode cursor */
+ else
+ p = T_CSI; /* fall back to Insert mode cursor */
+ if (*p != NUL)
+ {
+ out_str(p);
+ showing_mode = REPLACE;
+ }
+ }
+ }
+ else if (State & INSERT)
+ {
+ if ((forced || showing_mode != INSERT) && *T_CSI != NUL)
+ {
+ out_str(T_CSI); /* Insert mode cursor */
+ showing_mode = INSERT;
+ }
+ }
+ else if (forced || showing_mode != NORMAL)
+ {
+ out_str(T_CEI); /* non-Insert mode cursor */
+ showing_mode = NORMAL;
+ }
+}
+
+# if defined(FEAT_TERMINAL) || defined(PROTO)
+ void
+term_cursor_color(char_u *color)
+{
+ if (*T_CSC != NUL)
+ {
+ out_str(T_CSC); /* set cursor color start */
+ out_str_nf(color);
+ out_str(T_CEC); /* set cursor color end */
+ out_flush();
+ }
+}
+# endif
+
+ int
+blink_state_is_inverted()
+{
+#ifdef FEAT_TERMRESPONSE
+ return rbm_status == STATUS_GOT && rcs_status == STATUS_GOT
+ && initial_cursor_blink != initial_cursor_shape_blink;
+#else
+ return FALSE;
+#endif
+}
+
+/*
+ * "shape": 1 = block, 2 = underline, 3 = vertical bar
+ */
+ void
+term_cursor_shape(int shape, int blink)
+{
+ if (*T_CSH != NUL)
+ {
+ OUT_STR(tgoto((char *)T_CSH, 0, shape * 2 - blink));
+ out_flush();
+ }
+ else
+ {
+ int do_blink = blink;
+
+ /* t_SH is empty: try setting just the blink state.
+ * The blink flags are XORed together, if the initial blinking from
+ * style and shape differs, we need to invert the flag here. */
+ if (blink_state_is_inverted())
+ do_blink = !blink;
+
+ if (do_blink && *T_VS != NUL)
+ {
+ out_str(T_VS);
+ out_flush();
+ }
+ else if (!do_blink && *T_CVS != NUL)
+ {
+ out_str(T_CVS);
+ out_flush();
+ }
+ }
+}
+#endif
+
+/*
+ * Set scrolling region for window 'wp'.
+ * The region starts 'off' lines from the start of the window.
+ * Also set the vertical scroll region for a vertically split window. Always
+ * the full width of the window, excluding the vertical separator.
+ */
+ void
+scroll_region_set(win_T *wp, int off)
+{
+ OUT_STR(tgoto((char *)T_CS, W_WINROW(wp) + wp->w_height - 1,
+ W_WINROW(wp) + off));
+ if (*T_CSV != NUL && wp->w_width != Columns)
+ OUT_STR(tgoto((char *)T_CSV, wp->w_wincol + wp->w_width - 1,
+ wp->w_wincol));
+ screen_start(); /* don't know where cursor is now */
+}
+
+/*
+ * Reset scrolling region to the whole screen.
+ */
+ void
+scroll_region_reset(void)
+{
+ OUT_STR(tgoto((char *)T_CS, (int)Rows - 1, 0));
+ if (*T_CSV != NUL)
+ OUT_STR(tgoto((char *)T_CSV, (int)Columns - 1, 0));
+ screen_start(); /* don't know where cursor is now */
+}
+
+
+/*
+ * List of terminal codes that are currently recognized.
+ */
+
+static struct termcode
+{
+ char_u name[2]; /* termcap name of entry */
+ char_u *code; /* terminal code (in allocated memory) */
+ int len; /* STRLEN(code) */
+ int modlen; /* length of part before ";*~". */
+} *termcodes = NULL;
+
+static int tc_max_len = 0; /* number of entries that termcodes[] can hold */
+static int tc_len = 0; /* current number of entries in termcodes[] */
+
+static int termcode_star(char_u *code, int len);
+
+ void
+clear_termcodes(void)
+{
+ while (tc_len > 0)
+ vim_free(termcodes[--tc_len].code);
+ VIM_CLEAR(termcodes);
+ tc_max_len = 0;
+
+#ifdef HAVE_TGETENT
+ BC = (char *)empty_option;
+ UP = (char *)empty_option;
+ PC = NUL; /* set pad character to NUL */
+ ospeed = 0;
+#endif
+
+ need_gather = TRUE; /* need to fill termleader[] */
+}
+
+#define ATC_FROM_TERM 55
+
+/*
+ * Add a new entry to the list of terminal codes.
+ * The list is kept alphabetical for ":set termcap"
+ * "flags" is TRUE when replacing 7-bit by 8-bit controls is desired.
+ * "flags" can also be ATC_FROM_TERM for got_code_from_term().
+ */
+ void
+add_termcode(char_u *name, char_u *string, int flags)
+{
+ struct termcode *new_tc;
+ int i, j;
+ char_u *s;
+ int len;
+
+ if (string == NULL || *string == NUL)
+ {
+ del_termcode(name);
+ return;
+ }
+
+#if defined(WIN3264) && !defined(FEAT_GUI)
+ s = vim_strnsave(string, (int)STRLEN(string) + 1);
+#else
+ s = vim_strsave(string);
+#endif
+ if (s == NULL)
+ return;
+
+ /* Change leading <Esc>[ to CSI, change <Esc>O to <M-O>. */
+ if (flags != 0 && flags != ATC_FROM_TERM && term_7to8bit(string) != 0)
+ {
+ STRMOVE(s, s + 1);
+ s[0] = term_7to8bit(string);
+ }
+
+#if defined(WIN3264) && !defined(FEAT_GUI)
+ if (s[0] == K_NUL)
+ {
+ STRMOVE(s + 1, s);
+ s[1] = 3;
+ }
+#endif
+
+ len = (int)STRLEN(s);
+
+ need_gather = TRUE; /* need to fill termleader[] */
+
+ /*
+ * need to make space for more entries
+ */
+ if (tc_len == tc_max_len)
+ {
+ tc_max_len += 20;
+ new_tc = (struct termcode *)alloc(
+ (unsigned)(tc_max_len * sizeof(struct termcode)));
+ if (new_tc == NULL)
+ {
+ tc_max_len -= 20;
+ return;
+ }
+ for (i = 0; i < tc_len; ++i)
+ new_tc[i] = termcodes[i];
+ vim_free(termcodes);
+ termcodes = new_tc;
+ }
+
+ /*
+ * Look for existing entry with the same name, it is replaced.
+ * Look for an existing entry that is alphabetical higher, the new entry
+ * is inserted in front of it.
+ */
+ for (i = 0; i < tc_len; ++i)
+ {
+ if (termcodes[i].name[0] < name[0])
+ continue;
+ if (termcodes[i].name[0] == name[0])
+ {
+ if (termcodes[i].name[1] < name[1])
+ continue;
+ /*
+ * Exact match: May replace old code.
+ */
+ if (termcodes[i].name[1] == name[1])
+ {
+ if (flags == ATC_FROM_TERM && (j = termcode_star(
+ termcodes[i].code, termcodes[i].len)) > 0)
+ {
+ /* Don't replace ESC[123;*X or ESC O*X with another when
+ * invoked from got_code_from_term(). */
+ if (len == termcodes[i].len - j
+ && STRNCMP(s, termcodes[i].code, len - 1) == 0
+ && s[len - 1]
+ == termcodes[i].code[termcodes[i].len - 1])
+ {
+ /* They are equal but for the ";*": don't add it. */
+ vim_free(s);
+ return;
+ }
+ }
+ else
+ {
+ /* Replace old code. */
+ vim_free(termcodes[i].code);
+ --tc_len;
+ break;
+ }
+ }
+ }
+ /*
+ * Found alphabetical larger entry, move rest to insert new entry
+ */
+ for (j = tc_len; j > i; --j)
+ termcodes[j] = termcodes[j - 1];
+ break;
+ }
+
+ termcodes[i].name[0] = name[0];
+ termcodes[i].name[1] = name[1];
+ termcodes[i].code = s;
+ termcodes[i].len = len;
+
+ /* For xterm we recognize special codes like "ESC[42;*X" and "ESC O*X" that
+ * accept modifiers. */
+ termcodes[i].modlen = 0;
+ j = termcode_star(s, len);
+ if (j > 0)
+ termcodes[i].modlen = len - 1 - j;
+ ++tc_len;
+}
+
+/*
+ * Check termcode "code[len]" for ending in ;*X or *X.
+ * The "X" can be any character.
+ * Return 0 if not found, 2 for ;*X and 1 for *X.
+ */
+ static int
+termcode_star(char_u *code, int len)
+{
+ /* Shortest is <M-O>*X. With ; shortest is <CSI>1;*X */
+ if (len >= 3 && code[len - 2] == '*')
+ {
+ if (len >= 5 && code[len - 3] == ';')
+ return 2;
+ else
+ return 1;
+ }
+ return 0;
+}
+
+ char_u *
+find_termcode(char_u *name)
+{
+ int i;
+
+ for (i = 0; i < tc_len; ++i)
+ if (termcodes[i].name[0] == name[0] && termcodes[i].name[1] == name[1])
+ return termcodes[i].code;
+ return NULL;
+}
+
+#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
+ char_u *
+get_termcode(int i)
+{
+ if (i >= tc_len)
+ return NULL;
+ return &termcodes[i].name[0];
+}
+#endif
+
+ void
+del_termcode(char_u *name)
+{
+ int i;
+
+ if (termcodes == NULL) /* nothing there yet */
+ return;
+
+ need_gather = TRUE; /* need to fill termleader[] */
+
+ for (i = 0; i < tc_len; ++i)
+ if (termcodes[i].name[0] == name[0] && termcodes[i].name[1] == name[1])
+ {
+ del_termcode_idx(i);
+ return;
+ }
+ /* not found. Give error message? */
+}
+
+ static void
+del_termcode_idx(int idx)
+{
+ int i;
+
+ vim_free(termcodes[idx].code);
+ --tc_len;
+ for (i = idx; i < tc_len; ++i)
+ termcodes[i] = termcodes[i + 1];
+}
+
+#ifdef FEAT_TERMRESPONSE
+/*
+ * Called when detected that the terminal sends 8-bit codes.
+ * Convert all 7-bit codes to their 8-bit equivalent.
+ */
+ static void
+switch_to_8bit(void)
+{
+ int i;
+ int c;
+
+ /* Only need to do something when not already using 8-bit codes. */
+ if (!term_is_8bit(T_NAME))
+ {
+ for (i = 0; i < tc_len; ++i)
+ {
+ c = term_7to8bit(termcodes[i].code);
+ if (c != 0)
+ {
+ STRMOVE(termcodes[i].code + 1, termcodes[i].code + 2);
+ termcodes[i].code[0] = c;
+ }
+ }
+ need_gather = TRUE; /* need to fill termleader[] */
+ }
+ detected_8bit = TRUE;
+ LOG_TR(("Switching to 8 bit"));
+}
+#endif
+
+#ifdef CHECK_DOUBLE_CLICK
+static linenr_T orig_topline = 0;
+# ifdef FEAT_DIFF
+static int orig_topfill = 0;
+# endif
+#endif
+#if defined(CHECK_DOUBLE_CLICK) || defined(PROTO)
+/*
+ * Checking for double clicks ourselves.
+ * "orig_topline" is used to avoid detecting a double-click when the window
+ * contents scrolled (e.g., when 'scrolloff' is non-zero).
+ */
+/*
+ * Set orig_topline. Used when jumping to another window, so that a double
+ * click still works.
+ */
+ void
+set_mouse_topline(win_T *wp)
+{
+ orig_topline = wp->w_topline;
+# ifdef FEAT_DIFF
+ orig_topfill = wp->w_topfill;
+# endif
+}
+#endif
+
+/*
+ * Check if typebuf.tb_buf[] contains a terminal key code.
+ * Check from typebuf.tb_buf[typebuf.tb_off] to typebuf.tb_buf[typebuf.tb_off
+ * + max_offset].
+ * Return 0 for no match, -1 for partial match, > 0 for full match.
+ * Return KEYLEN_REMOVED when a key code was deleted.
+ * With a match, the match is removed, the replacement code is inserted in
+ * typebuf.tb_buf[] and the number of characters in typebuf.tb_buf[] is
+ * returned.
+ * When "buf" is not NULL, buf[bufsize] is used instead of typebuf.tb_buf[].
+ * "buflen" is then the length of the string in buf[] and is updated for
+ * inserts and deletes.
+ */
+ int
+check_termcode(
+ int max_offset,
+ char_u *buf,
+ int bufsize,
+ int *buflen)
+{
+ char_u *tp;
+ char_u *p;
+ int slen = 0; /* init for GCC */
+ int modslen;
+ int len;
+ int retval = 0;
+ int offset;
+ char_u key_name[2];
+ int modifiers;
+ char_u *modifiers_start = NULL;
+ int key;
+ int new_slen;
+ int extra;
+ char_u string[MAX_KEY_CODE_LEN + 1];
+ int i, j;
+ int idx = 0;
+#ifdef FEAT_MOUSE
+# if !defined(UNIX) || defined(FEAT_MOUSE_XTERM) || defined(FEAT_GUI) \
+ || defined(FEAT_MOUSE_GPM) || defined(FEAT_SYSMOUSE)
+ char_u bytes[6];
+ int num_bytes;
+# endif
+ int mouse_code = 0; /* init for GCC */
+ int is_click, is_drag;
+ int wheel_code = 0;
+ int current_button;
+ static int held_button = MOUSE_RELEASE;
+ static int orig_num_clicks = 1;
+ static int orig_mouse_code = 0x0;
+# ifdef CHECK_DOUBLE_CLICK
+ static int orig_mouse_col = 0;
+ static int orig_mouse_row = 0;
+ static struct timeval orig_mouse_time = {0, 0};
+ /* time of previous mouse click */
+ struct timeval mouse_time; /* time of current mouse click */
+ long timediff; /* elapsed time in msec */
+# endif
+#endif
+ int cpo_koffset;
+#ifdef FEAT_MOUSE_GPM
+ extern int gpm_flag; /* gpm library variable */
+#endif
+
+ cpo_koffset = (vim_strchr(p_cpo, CPO_KOFFSET) != NULL);
+
+ /*
+ * Speed up the checks for terminal codes by gathering all first bytes
+ * used in termleader[]. Often this is just a single <Esc>.
+ */
+ if (need_gather)
+ gather_termleader();
+
+ /*
+ * Check at several positions in typebuf.tb_buf[], to catch something like
+ * "x<Up>" that can be mapped. Stop at max_offset, because characters
+ * after that cannot be used for mapping, and with @r commands
+ * typebuf.tb_buf[] can become very long.
+ * This is used often, KEEP IT FAST!
+ */
+ for (offset = 0; offset < max_offset; ++offset)
+ {
+ if (buf == NULL)
+ {
+ if (offset >= typebuf.tb_len)
+ break;
+ tp = typebuf.tb_buf + typebuf.tb_off + offset;
+ len = typebuf.tb_len - offset; /* length of the input */
+ }
+ else
+ {
+ if (offset >= *buflen)
+ break;
+ tp = buf + offset;
+ len = *buflen - offset;
+ }
+
+ /*
+ * Don't check characters after K_SPECIAL, those are already
+ * translated terminal chars (avoid translating ~@^Hx).
+ */
+ if (*tp == K_SPECIAL)
+ {
+ offset += 2; /* there are always 2 extra characters */
+ continue;
+ }
+
+ /*
+ * Skip this position if the character does not appear as the first
+ * character in term_strings. This speeds up a lot, since most
+ * termcodes start with the same character (ESC or CSI).
+ */
+ i = *tp;
+ for (p = termleader; *p && *p != i; ++p)
+ ;
+ if (*p == NUL)
+ continue;
+
+ /*
+ * Skip this position if p_ek is not set and tp[0] is an ESC and we
+ * are in Insert mode.
+ */
+ if (*tp == ESC && !p_ek && (State & INSERT))
+ continue;
+
+ key_name[0] = NUL; /* no key name found yet */
+ key_name[1] = NUL; /* no key name found yet */
+ modifiers = 0; /* no modifiers yet */
+
+#ifdef FEAT_GUI
+ if (gui.in_use)
+ {
+ /*
+ * GUI special key codes are all of the form [CSI xx].
+ */
+ if (*tp == CSI) /* Special key from GUI */
+ {
+ if (len < 3)
+ return -1; /* Shouldn't happen */
+ slen = 3;
+ key_name[0] = tp[1];
+ key_name[1] = tp[2];
+ }
+ }
+ else
+#endif /* FEAT_GUI */
+ {
+ for (idx = 0; idx < tc_len; ++idx)
+ {
+ /*
+ * Ignore the entry if we are not at the start of
+ * typebuf.tb_buf[]
+ * and there are not enough characters to make a match.
+ * But only when the 'K' flag is in 'cpoptions'.
+ */
+ slen = termcodes[idx].len;
+ modifiers_start = NULL;
+ if (cpo_koffset && offset && len < slen)
+ continue;
+ if (STRNCMP(termcodes[idx].code, tp,
+ (size_t)(slen > len ? len : slen)) == 0)
+ {
+ if (len < slen) /* got a partial sequence */
+ return -1; /* need to get more chars */
+
+ /*
+ * When found a keypad key, check if there is another key
+ * that matches and use that one. This makes <Home> to be
+ * found instead of <kHome> when they produce the same
+ * key code.
+ */
+ if (termcodes[idx].name[0] == 'K'
+ && VIM_ISDIGIT(termcodes[idx].name[1]))
+ {
+ for (j = idx + 1; j < tc_len; ++j)
+ if (termcodes[j].len == slen &&
+ STRNCMP(termcodes[idx].code,
+ termcodes[j].code, slen) == 0)
+ {
+ idx = j;
+ break;
+ }
+ }
+
+ key_name[0] = termcodes[idx].name[0];
+ key_name[1] = termcodes[idx].name[1];
+ break;
+ }
+
+ /*
+ * Check for code with modifier, like xterm uses:
+ * <Esc>[123;*X (modslen == slen - 3)
+ * Also <Esc>O*X and <M-O>*X (modslen == slen - 2).
+ * When there is a modifier the * matches a number.
+ * When there is no modifier the ;* or * is omitted.
+ */
+ if (termcodes[idx].modlen > 0)
+ {
+ modslen = termcodes[idx].modlen;
+ if (cpo_koffset && offset && len < modslen)
+ continue;
+ if (STRNCMP(termcodes[idx].code, tp,
+ (size_t)(modslen > len ? len : modslen)) == 0)
+ {
+ int n;
+
+ if (len <= modslen) /* got a partial sequence */
+ return -1; /* need to get more chars */
+
+ if (tp[modslen] == termcodes[idx].code[slen - 1])
+ slen = modslen + 1; /* no modifiers */
+ else if (tp[modslen] != ';' && modslen == slen - 3)
+ continue; /* no match */
+ else
+ {
+ /* Skip over the digits, the final char must
+ * follow. */
+ for (j = slen - 2; j < len && (isdigit(tp[j])
+ || tp[j] == ';'); ++j)
+ ;
+ ++j;
+ if (len < j) /* got a partial sequence */
+ return -1; /* need to get more chars */
+ if (tp[j - 1] != termcodes[idx].code[slen - 1])
+ continue; /* no match */
+
+ modifiers_start = tp + slen - 2;
+
+ /* Match! Convert modifier bits. */
+ n = atoi((char *)modifiers_start) - 1;
+ if (n & 1)
+ modifiers |= MOD_MASK_SHIFT;
+ if (n & 2)
+ modifiers |= MOD_MASK_ALT;
+ if (n & 4)
+ modifiers |= MOD_MASK_CTRL;
+ if (n & 8)
+ modifiers |= MOD_MASK_META;
+
+ slen = j;
+ }
+ key_name[0] = termcodes[idx].name[0];
+ key_name[1] = termcodes[idx].name[1];
+ break;
+ }
+ }
+ }
+ }
+
+#ifdef FEAT_TERMRESPONSE
+ if (key_name[0] == NUL
+ /* Mouse codes of DEC and pterm start with <ESC>[. When
+ * detecting the start of these mouse codes they might as well be
+ * another key code or terminal response. */
+# ifdef FEAT_MOUSE_DEC
+ || key_name[0] == KS_DEC_MOUSE
+# endif
+# ifdef FEAT_MOUSE_PTERM
+ || key_name[0] == KS_PTERM_MOUSE
+# endif
+ )
+ {
+ /* Check for some responses from the terminal starting with
+ * "<Esc>[" or CSI:
+ *
+ * - Xterm version string: <Esc>[>{x};{vers};{y}c
+ * Libvterm returns {x} == 0, {vers} == 100, {y} == 0.
+ * Also eat other possible responses to t_RV, rxvt returns
+ * "<Esc>[?1;2c". Also accept CSI instead of <Esc>[.
+ * mrxvt has been reported to have "+" in the version. Assume
+ * the escape sequence ends with a letter or one of "{|}~".
+ *
+ * - Cursor position report: <Esc>[{row};{col}R
+ * The final byte must be 'R'. It is used for checking the
+ * ambiguous-width character state.
+ *
+ * - window position reply: <Esc>[3;{x};{y}t
+ */
+ char_u *argp = tp[0] == ESC ? tp + 2 : tp + 1;
+
+ if ((*T_CRV != NUL || *T_U7 != NUL || did_request_winpos)
+ && ((tp[0] == ESC && len >= 3 && tp[1] == '[')
+ || (tp[0] == CSI && len >= 2))
+ && (VIM_ISDIGIT(*argp) || *argp == '>' || *argp == '?'))
+ {
+ int col = 0;
+ int semicols = 0;
+ int row_char = NUL;
+
+ extra = 0;
+ for (i = 2 + (tp[0] != CSI); i < len
+ && !(tp[i] >= '{' && tp[i] <= '~')
+ && !ASCII_ISALPHA(tp[i]); ++i)
+ if (tp[i] == ';' && ++semicols == 1)
+ {
+ extra = i + 1;
+ row_char = tp[i - 1];
+ }
+ if (i == len)
+ {
+ LOG_TR(("Not enough characters for CRV"));
+ return -1;
+ }
+ if (extra > 0)
+ col = atoi((char *)tp + extra);
+
+ /* Eat it when it has 2 arguments and ends in 'R'. Also when
+ * u7_status is not "sent", it may be from a previous Vim that
+ * just exited. But not for <S-F3>, it sends something
+ * similar, check for row and column to make sense. */
+ if (semicols == 1 && tp[i] == 'R')
+ {
+ if (row_char == '2' && col >= 2)
+ {
+ char *aw = NULL;
+
+ LOG_TR(("Received U7 status: %s", tp));
+ u7_status = STATUS_GOT;
+ did_cursorhold = TRUE;
+ if (col == 2)
+ aw = "single";
+ else if (col == 3)
+ aw = "double";
+ if (aw != NULL && STRCMP(aw, p_ambw) != 0)
+ {
+ /* Setting the option causes a screen redraw. Do
+ * that right away if possible, keeping any
+ * messages. */
+ set_option_value((char_u *)"ambw", 0L,
+ (char_u *)aw, 0);
+# ifdef DEBUG_TERMRESPONSE
+ {
+ int r = redraw_asap(CLEAR);
+
+ log_tr("set 'ambiwidth', redraw_asap(): %d", r);
+ }
+# else
+ redraw_asap(CLEAR);
+# endif
+ }
+ }
+ key_name[0] = (int)KS_EXTRA;
+ key_name[1] = (int)KE_IGNORE;
+ slen = i + 1;
+# ifdef FEAT_EVAL
+ set_vim_var_string(VV_TERMU7RESP, tp, slen);
+# endif
+ }
+ /* eat it when at least one digit and ending in 'c' */
+ else if (*T_CRV != NUL && i > 2 + (tp[0] != CSI)
+ && tp[i] == 'c')
+ {
+ int version = col;
+
+ LOG_TR(("Received CRV response: %s", tp));
+ crv_status = STATUS_GOT;
+ did_cursorhold = TRUE;
+
+ /* If this code starts with CSI, you can bet that the
+ * terminal uses 8-bit codes. */
+ if (tp[0] == CSI)
+ switch_to_8bit();
+
+ /* rxvt sends its version number: "20703" is 2.7.3.
+ * Screen sends 40500.
+ * Ignore it for when the user has set 'term' to xterm,
+ * even though it's an rxvt. */
+ if (version > 20000)
+ version = 0;
+
+ if (tp[1 + (tp[0] != CSI)] == '>' && semicols == 2)
+ {
+ int need_flush = FALSE;
+# ifdef FEAT_MOUSE_SGR
+ int is_iterm2 = FALSE;
+ int is_mintty = FALSE;
+
+ // mintty 2.9.5 sends 77;20905;0c.
+ // (77 is ASCII 'M' for mintty.)
+ if (STRNCMP(tp + extra - 3, "77;", 3) == 0)
+ is_mintty = TRUE;
+# endif
+
+ /* if xterm version >= 141 try to get termcap codes */
+ if (version >= 141)
+ {
+ LOG_TR(("Enable checking for XT codes"));
+ check_for_codes = TRUE;
+ need_gather = TRUE;
+ req_codes_from_term();
+ }
+
+ /* libvterm sends 0;100;0 */
+ if (version == 100
+ && STRNCMP(tp + extra - 2, "0;100;0c", 8) == 0)
+ {
+ /* If run from Vim $COLORS is set to the number of
+ * colors the terminal supports. Otherwise assume
+ * 256, libvterm supports even more. */
+ if (mch_getenv((char_u *)"COLORS") == NULL)
+ may_adjust_color_count(256);
+# ifdef FEAT_MOUSE_SGR
+ /* Libvterm can handle SGR mouse reporting. */
+ if (!option_was_set((char_u *)"ttym"))
+ set_option_value((char_u *)"ttym", 0L,
+ (char_u *)"sgr", 0);
+# endif
+ }
+
+ if (version == 95)
+ {
+ // Mac Terminal.app sends 1;95;0
+ if (STRNCMP(tp + extra - 2, "1;95;0c", 7) == 0)
+ {
+ is_not_xterm = TRUE;
+ is_mac_terminal = TRUE;
+ }
+# ifdef FEAT_MOUSE_SGR
+ // iTerm2 sends 0;95;0
+ if (STRNCMP(tp + extra - 2, "0;95;0c", 7) == 0)
+ is_iterm2 = TRUE;
+ else
+# endif
+ // old iTerm2 sends 0;95;
+ if (STRNCMP(tp + extra - 2, "0;95;c", 6) == 0)
+ is_not_xterm = TRUE;
+ }
+
+ /* Only set 'ttymouse' automatically if it was not set
+ * by the user already. */
+ if (!option_was_set((char_u *)"ttym"))
+ {
+# ifdef FEAT_MOUSE_SGR
+ /* Xterm version 277 supports SGR. Also support
+ * Terminal.app, iTerm2 and mintty. */
+ if (version >= 277 || is_iterm2 || is_mac_terminal
+ || is_mintty)
+ set_option_value((char_u *)"ttym", 0L,
+ (char_u *)"sgr", 0);
+ else
+# endif
+ /* if xterm version >= 95 use mouse dragging */
+ if (version >= 95)
+ set_option_value((char_u *)"ttym", 0L,
+ (char_u *)"xterm2", 0);
+ }
+
+ /* Detect terminals that set $TERM to something like
+ * "xterm-256colors" but are not fully xterm
+ * compatible. */
+
+ /* Gnome terminal sends 1;3801;0, 1;4402;0 or 1;2501;0.
+ * xfce4-terminal sends 1;2802;0.
+ * screen sends 83;40500;0
+ * Assuming any version number over 2500 is not an
+ * xterm (without the limit for rxvt and screen). */
+ if (col >= 2500)
+ is_not_xterm = TRUE;
+
+ /* PuTTY sends 0;136;0
+ * vandyke SecureCRT sends 1;136;0 */
+ if (version == 136
+ && STRNCMP(tp + extra - 1, ";136;0c", 7) == 0)
+ is_not_xterm = TRUE;
+
+ /* Konsole sends 0;115;0 */
+ if (version == 115
+ && STRNCMP(tp + extra - 2, "0;115;0c", 8) == 0)
+ is_not_xterm = TRUE;
+
+ // Xterm first responded to this request at patch level
+ // 95, so assume anything below 95 is not xterm.
+ if (version < 95)
+ is_not_xterm = TRUE;
+
+ /* Only request the cursor style if t_SH and t_RS are
+ * set. Only supported properly by xterm since version
+ * 279 (otherwise it returns 0x18).
+ * Not for Terminal.app, it can't handle t_RS, it
+ * echoes the characters to the screen. */
+ if (rcs_status == STATUS_GET
+ && version >= 279
+ && !is_not_xterm
+ && *T_CSH != NUL
+ && *T_CRS != NUL)
+ {
+ LOG_TR(("Sending cursor style request"));
+ out_str(T_CRS);
+ rcs_status = STATUS_SENT;
+ need_flush = TRUE;
+ }
+
+ /* Only request the cursor blink mode if t_RC set. Not
+ * for Gnome terminal, it can't handle t_RC, it
+ * echoes the characters to the screen. */
+ if (rbm_status == STATUS_GET
+ && !is_not_xterm
+ && *T_CRC != NUL)
+ {
+ LOG_TR(("Sending cursor blink mode request"));
+ out_str(T_CRC);
+ rbm_status = STATUS_SENT;
+ need_flush = TRUE;
+ }
+
+ if (need_flush)
+ out_flush();
+ }
+ slen = i + 1;
+# ifdef FEAT_EVAL
+ set_vim_var_string(VV_TERMRESPONSE, tp, slen);
+# endif
+ apply_autocmds(EVENT_TERMRESPONSE,
+ NULL, NULL, FALSE, curbuf);
+ key_name[0] = (int)KS_EXTRA;
+ key_name[1] = (int)KE_IGNORE;
+ }
+
+ /* Check blinking cursor from xterm:
+ * {lead}?12;1$y set
+ * {lead}?12;2$y not set
+ *
+ * {lead} can be <Esc>[ or CSI
+ */
+ else if (rbm_status == STATUS_SENT
+ && tp[(j = 1 + (tp[0] == ESC))] == '?'
+ && i == j + 6
+ && tp[j + 1] == '1'
+ && tp[j + 2] == '2'
+ && tp[j + 3] == ';'
+ && tp[i - 1] == '$'
+ && tp[i] == 'y')
+ {
+ initial_cursor_blink = (tp[j + 4] == '1');
+ rbm_status = STATUS_GOT;
+ LOG_TR(("Received cursor blinking mode response: %s", tp));
+ key_name[0] = (int)KS_EXTRA;
+ key_name[1] = (int)KE_IGNORE;
+ slen = i + 1;
+# ifdef FEAT_EVAL
+ set_vim_var_string(VV_TERMBLINKRESP, tp, slen);
+# endif
+ }
+
+ /*
+ * Check for a window position response from the terminal:
+ * {lead}3;{x}:{y}t
+ */
+ else if (did_request_winpos
+ && ((len >= 4 && tp[0] == ESC && tp[1] == '[')
+ || (len >= 3 && tp[0] == CSI))
+ && tp[(j = 1 + (tp[0] == ESC))] == '3'
+ && tp[j + 1] == ';')
+ {
+ j += 2;
+ for (i = j; i < len && vim_isdigit(tp[i]); ++i)
+ ;
+ if (i < len && tp[i] == ';')
+ {
+ winpos_x = atoi((char *)tp + j);
+ j = i + 1;
+ for (i = j; i < len && vim_isdigit(tp[i]); ++i)
+ ;
+ if (i < len && tp[i] == 't')
+ {
+ winpos_y = atoi((char *)tp + j);
+ /* got finished code: consume it */
+ key_name[0] = (int)KS_EXTRA;
+ key_name[1] = (int)KE_IGNORE;
+ slen = i + 1;
+
+ if (--did_request_winpos <= 0)
+ winpos_status = STATUS_GOT;
+ }
+ }
+ if (i == len)
+ {
+ LOG_TR(("not enough characters for winpos"));
+ return -1;
+ }
+ }
+ }
+
+ /* Check for fore/background color response from the terminal:
+ *
+ * {lead}{code};rgb:{rrrr}/{gggg}/{bbbb}{tail}
+ *
+ * {code} is 10 for foreground, 11 for background
+ * {lead} can be <Esc>] or OSC
+ * {tail} can be '\007', <Esc>\ or STERM.
+ *
+ * Consume any code that starts with "{lead}11;", it's also
+ * possible that "rgba" is following.
+ */
+ else if ((*T_RBG != NUL || *T_RFG != NUL)
+ && ((tp[0] == ESC && len >= 2 && tp[1] == ']')
+ || tp[0] == OSC))
+ {
+ j = 1 + (tp[0] == ESC);
+ if (len >= j + 3 && (argp[0] != '1'
+ || (argp[1] != '1' && argp[1] != '0')
+ || argp[2] != ';'))
+ i = 0; /* no match */
+ else
+ for (i = j; i < len; ++i)
+ if (tp[i] == '\007' || (tp[0] == OSC ? tp[i] == STERM
+ : (tp[i] == ESC && i + 1 < len && tp[i + 1] == '\\')))
+ {
+ int is_bg = argp[1] == '1';
+
+ if (i - j >= 21 && STRNCMP(tp + j + 3, "rgb:", 4) == 0
+ && tp[j + 11] == '/' && tp[j + 16] == '/')
+ {
+#ifdef FEAT_TERMINAL
+ int rval = hexhex2nr(tp + j + 7);
+ int gval = hexhex2nr(tp + j + 12);
+ int bval = hexhex2nr(tp + j + 17);
+#endif
+ if (is_bg)
+ {
+ char *newval = (3 * '6' < tp[j+7] + tp[j+12]
+ + tp[j+17]) ? "light" : "dark";
+
+ LOG_TR(("Received RBG response: %s", tp));
+ rbg_status = STATUS_GOT;
+#ifdef FEAT_TERMINAL
+ bg_r = rval;
+ bg_g = gval;
+ bg_b = bval;
+#endif
+ if (!option_was_set((char_u *)"bg")
+ && STRCMP(p_bg, newval) != 0)
+ {
+ /* value differs, apply it */
+ set_option_value((char_u *)"bg", 0L,
+ (char_u *)newval, 0);
+ reset_option_was_set((char_u *)"bg");
+ redraw_asap(CLEAR);
+ }
+ }
+#ifdef FEAT_TERMINAL
+ else
+ {
+ LOG_TR(("Received RFG response: %s", tp));
+ rfg_status = STATUS_GOT;
+ fg_r = rval;
+ fg_g = gval;
+ fg_b = bval;
+ }
+#endif
+ }
+
+ /* got finished code: consume it */
+ key_name[0] = (int)KS_EXTRA;
+ key_name[1] = (int)KE_IGNORE;
+ slen = i + 1 + (tp[i] == ESC);
+# ifdef FEAT_EVAL
+ set_vim_var_string(is_bg ? VV_TERMRBGRESP
+ : VV_TERMRFGRESP, tp, slen);
+# endif
+ break;
+ }
+ if (i == len)
+ {
+ LOG_TR(("not enough characters for RB"));
+ return -1;
+ }
+ }
+
+ /* Check for key code response from xterm:
+ * {lead}{flag}+r<hex bytes><{tail}
+ *
+ * {lead} can be <Esc>P or DCS
+ * {flag} can be '0' or '1'
+ * {tail} can be Esc>\ or STERM
+ *
+ * Check for cursor shape response from xterm:
+ * {lead}1$r<digit> q{tail}
+ *
+ * {lead} can be <Esc>P or DCS
+ * {tail} can be Esc>\ or STERM
+ *
+ * Consume any code that starts with "{lead}.+r" or "{lead}.$r".
+ */
+ else if ((check_for_codes || rcs_status == STATUS_SENT)
+ && ((tp[0] == ESC && len >= 2 && tp[1] == 'P')
+ || tp[0] == DCS))
+ {
+ j = 1 + (tp[0] == ESC);
+ if (len < j + 3)
+ i = len; /* need more chars */
+ else if ((argp[1] != '+' && argp[1] != '$') || argp[2] != 'r')
+ i = 0; /* no match */
+ else if (argp[1] == '+')
+ /* key code response */
+ for (i = j; i < len; ++i)
+ {
+ if ((tp[i] == ESC && i + 1 < len && tp[i + 1] == '\\')
+ || tp[i] == STERM)
+ {
+ if (i - j >= 3)
+ got_code_from_term(tp + j, i);
+ key_name[0] = (int)KS_EXTRA;
+ key_name[1] = (int)KE_IGNORE;
+ slen = i + 1 + (tp[i] == ESC);
+ break;
+ }
+ }
+ else
+ {
+ /* Probably the cursor shape response. Make sure that "i"
+ * is equal to "len" when there are not sufficient
+ * characters. */
+ for (i = j + 3; i < len; ++i)
+ {
+ if (i - j == 3 && !isdigit(tp[i]))
+ break;
+ if (i - j == 4 && tp[i] != ' ')
+ break;
+ if (i - j == 5 && tp[i] != 'q')
+ break;
+ if (i - j == 6 && tp[i] != ESC && tp[i] != STERM)
+ break;
+ if ((i - j == 6 && tp[i] == STERM)
+ || (i - j == 7 && tp[i] == '\\'))
+ {
+ int number = argp[3] - '0';
+
+ /* 0, 1 = block blink, 2 = block
+ * 3 = underline blink, 4 = underline
+ * 5 = vertical bar blink, 6 = vertical bar */
+ number = number == 0 ? 1 : number;
+ initial_cursor_shape = (number + 1) / 2;
+ /* The blink flag is actually inverted, compared to
+ * the value set with T_SH. */
+ initial_cursor_shape_blink =
+ (number & 1) ? FALSE : TRUE;
+ rcs_status = STATUS_GOT;
+ LOG_TR(("Received cursor shape response: %s", tp));
+
+ key_name[0] = (int)KS_EXTRA;
+ key_name[1] = (int)KE_IGNORE;
+ slen = i + 1;
+# ifdef FEAT_EVAL
+ set_vim_var_string(VV_TERMSTYLERESP, tp, slen);
+# endif
+ break;
+ }
+ }
+ }
+
+ if (i == len)
+ {
+ /* These codes arrive many together, each code can be
+ * truncated at any point. */
+ LOG_TR(("not enough characters for XT"));
+ return -1;
+ }
+ }
+ }
+#endif
+
+ if (key_name[0] == NUL)
+ continue; /* No match at this position, try next one */
+
+ /* We only get here when we have a complete termcode match */
+
+#ifdef FEAT_MOUSE
+# ifdef FEAT_GUI
+ /*
+ * Only in the GUI: Fetch the pointer coordinates of the scroll event
+ * so that we know which window to scroll later.
+ */
+ if (gui.in_use
+ && key_name[0] == (int)KS_EXTRA
+ && (key_name[1] == (int)KE_X1MOUSE
+ || key_name[1] == (int)KE_X2MOUSE
+ || key_name[1] == (int)KE_MOUSELEFT
+ || key_name[1] == (int)KE_MOUSERIGHT
+ || key_name[1] == (int)KE_MOUSEDOWN
+ || key_name[1] == (int)KE_MOUSEUP))
+ {
+ num_bytes = get_bytes_from_buf(tp + slen, bytes, 4);
+ if (num_bytes == -1) /* not enough coordinates */
+ return -1;
+ mouse_col = 128 * (bytes[0] - ' ' - 1) + bytes[1] - ' ' - 1;
+ mouse_row = 128 * (bytes[2] - ' ' - 1) + bytes[3] - ' ' - 1;
+ slen += num_bytes;
+ }
+ else
+# endif
+ /*
+ * If it is a mouse click, get the coordinates.
+ */
+ if (key_name[0] == KS_MOUSE
+# ifdef FEAT_MOUSE_JSB
+ || key_name[0] == KS_JSBTERM_MOUSE
+# endif
+# ifdef FEAT_MOUSE_NET
+ || key_name[0] == KS_NETTERM_MOUSE
+# endif
+# ifdef FEAT_MOUSE_DEC
+ || key_name[0] == KS_DEC_MOUSE
+# endif
+# ifdef FEAT_MOUSE_PTERM
+ || key_name[0] == KS_PTERM_MOUSE
+# endif
+# ifdef FEAT_MOUSE_URXVT
+ || key_name[0] == KS_URXVT_MOUSE
+# endif
+# ifdef FEAT_MOUSE_SGR
+ || key_name[0] == KS_SGR_MOUSE
+ || key_name[0] == KS_SGR_MOUSE_RELEASE
+# endif
+ )
+ {
+ is_click = is_drag = FALSE;
+
+# if !defined(UNIX) || defined(FEAT_MOUSE_XTERM) || defined(FEAT_GUI) \
+ || defined(FEAT_MOUSE_GPM) || defined(FEAT_SYSMOUSE)
+ if (key_name[0] == (int)KS_MOUSE)
+ {
+ /*
+ * For xterm we get "<t_mouse>scr", where
+ * s == encoded button state:
+ * 0x20 = left button down
+ * 0x21 = middle button down
+ * 0x22 = right button down
+ * 0x23 = any button release
+ * 0x60 = button 4 down (scroll wheel down)
+ * 0x61 = button 5 down (scroll wheel up)
+ * add 0x04 for SHIFT
+ * add 0x08 for ALT
+ * add 0x10 for CTRL
+ * add 0x20 for mouse drag (0x40 is drag with left button)
+ * add 0x40 for mouse move (0x80 is move, 0x81 too)
+ * 0x43 (drag + release) is also move
+ * c == column + ' ' + 1 == column + 33
+ * r == row + ' ' + 1 == row + 33
+ *
+ * The coordinates are passed on through global variables.
+ * Ugly, but this avoids trouble with mouse clicks at an
+ * unexpected moment and allows for mapping them.
+ */
+ for (;;)
+ {
+#ifdef FEAT_GUI
+ if (gui.in_use)
+ {
+ /* GUI uses more bits for columns > 223 */
+ num_bytes = get_bytes_from_buf(tp + slen, bytes, 5);
+ if (num_bytes == -1) /* not enough coordinates */
+ return -1;
+ mouse_code = bytes[0];
+ mouse_col = 128 * (bytes[1] - ' ' - 1)
+ + bytes[2] - ' ' - 1;
+ mouse_row = 128 * (bytes[3] - ' ' - 1)
+ + bytes[4] - ' ' - 1;
+ }
+ else
+#endif
+ {
+ num_bytes = get_bytes_from_buf(tp + slen, bytes, 3);
+ if (num_bytes == -1) /* not enough coordinates */
+ return -1;
+ mouse_code = bytes[0];
+ mouse_col = bytes[1] - ' ' - 1;
+ mouse_row = bytes[2] - ' ' - 1;
+ }
+ slen += num_bytes;
+
+ /* If the following bytes is also a mouse code and it has
+ * the same code, dump this one and get the next. This
+ * makes dragging a whole lot faster. */
+#ifdef FEAT_GUI
+ if (gui.in_use)
+ j = 3;
+ else
+#endif
+ j = termcodes[idx].len;
+ if (STRNCMP(tp, tp + slen, (size_t)j) == 0
+ && tp[slen + j] == mouse_code
+ && tp[slen + j + 1] != NUL
+ && tp[slen + j + 2] != NUL
+#ifdef FEAT_GUI
+ && (!gui.in_use
+ || (tp[slen + j + 3] != NUL
+ && tp[slen + j + 4] != NUL))
+#endif
+ )
+ slen += j;
+ else
+ break;
+ }
+ }
+
+# if defined(FEAT_MOUSE_URXVT) || defined(FEAT_MOUSE_SGR)
+ if (key_name[0] == KS_URXVT_MOUSE
+ || key_name[0] == KS_SGR_MOUSE
+ || key_name[0] == KS_SGR_MOUSE_RELEASE)
+ {
+ /* URXVT 1015 mouse reporting mode:
+ * Almost identical to xterm mouse mode, except the values
+ * are decimal instead of bytes.
+ *
+ * \033[%d;%d;%dM
+ * ^-- row
+ * ^----- column
+ * ^-------- code
+ *
+ * SGR 1006 mouse reporting mode:
+ * Almost identical to xterm mouse mode, except the values
+ * are decimal instead of bytes.
+ *
+ * \033[<%d;%d;%dM
+ * ^-- row
+ * ^----- column
+ * ^-------- code
+ *
+ * \033[<%d;%d;%dm : mouse release event
+ * ^-- row
+ * ^----- column
+ * ^-------- code
+ */
+ p = modifiers_start;
+ if (p == NULL)
+ return -1;
+
+ mouse_code = getdigits(&p);
+ if (*p++ != ';')
+ return -1;
+
+ /* when mouse reporting is SGR, add 32 to mouse code */
+ if (key_name[0] == KS_SGR_MOUSE
+ || key_name[0] == KS_SGR_MOUSE_RELEASE)
+ mouse_code += 32;
+
+ if (key_name[0] == KS_SGR_MOUSE_RELEASE)
+ mouse_code |= MOUSE_RELEASE;
+
+ mouse_col = getdigits(&p) - 1;
+ if (*p++ != ';')
+ return -1;
+
+ mouse_row = getdigits(&p) - 1;
+
+ /* The modifiers were the mouse coordinates, not the
+ * modifier keys (alt/shift/ctrl/meta) state. */
+ modifiers = 0;
+ }
+# endif
+
+ if (key_name[0] == (int)KS_MOUSE
+#ifdef FEAT_MOUSE_URXVT
+ || key_name[0] == (int)KS_URXVT_MOUSE
+#endif
+#ifdef FEAT_MOUSE_SGR
+ || key_name[0] == KS_SGR_MOUSE
+ || key_name[0] == KS_SGR_MOUSE_RELEASE
+#endif
+ )
+ {
+# if !defined(MSWIN)
+ /*
+ * Handle mouse events.
+ * Recognize the xterm mouse wheel, but not in the GUI, the
+ * Linux console with GPM and the MS-DOS or Win32 console
+ * (multi-clicks use >= 0x60).
+ */
+ if (mouse_code >= MOUSEWHEEL_LOW
+# ifdef FEAT_GUI
+ && !gui.in_use
+# endif
+# ifdef FEAT_MOUSE_GPM
+ && gpm_flag == 0
+# endif
+ )
+ {
+# if defined(UNIX) && defined(FEAT_MOUSE_TTY)
+ if (use_xterm_mouse() > 1 && mouse_code >= 0x80)
+ /* mouse-move event, using MOUSE_DRAG works */
+ mouse_code = MOUSE_DRAG;
+ else
+# endif
+ /* Keep the mouse_code before it's changed, so that we
+ * remember that it was a mouse wheel click. */
+ wheel_code = mouse_code;
+ }
+# ifdef FEAT_MOUSE_XTERM
+ else if (held_button == MOUSE_RELEASE
+# ifdef FEAT_GUI
+ && !gui.in_use
+# endif
+ && (mouse_code == 0x23 || mouse_code == 0x24
+ || mouse_code == 0x40 || mouse_code == 0x41))
+ {
+ /* Apparently 0x23 and 0x24 are used by rxvt scroll wheel.
+ * And 0x40 and 0x41 are used by some xterm emulator. */
+ wheel_code = mouse_code - (mouse_code >= 0x40 ? 0x40 : 0x23)
+ + MOUSEWHEEL_LOW;
+ }
+# endif
+
+# if defined(UNIX) && defined(FEAT_MOUSE_TTY)
+ else if (use_xterm_mouse() > 1)
+ {
+ if (mouse_code & MOUSE_DRAG_XTERM)
+ mouse_code |= MOUSE_DRAG;
+ }
+# endif
+# ifdef FEAT_XCLIPBOARD
+ else if (!(mouse_code & MOUSE_DRAG & ~MOUSE_CLICK_MASK))
+ {
+ if ((mouse_code & MOUSE_RELEASE) == MOUSE_RELEASE)
+ stop_xterm_trace();
+ else
+ start_xterm_trace(mouse_code);
+ }
+# endif
+# endif
+ }
+# endif /* !UNIX || FEAT_MOUSE_XTERM */
+# ifdef FEAT_MOUSE_NET
+ if (key_name[0] == (int)KS_NETTERM_MOUSE)
+ {
+ int mc, mr;
+
+ /* expect a rather limited sequence like: balancing {
+ * \033}6,45\r
+ * '6' is the row, 45 is the column
+ */
+ p = tp + slen;
+ mr = getdigits(&p);
+ if (*p++ != ',')
+ return -1;
+ mc = getdigits(&p);
+ if (*p++ != '\r')
+ return -1;
+
+ mouse_col = mc - 1;
+ mouse_row = mr - 1;
+ mouse_code = MOUSE_LEFT;
+ slen += (int)(p - (tp + slen));
+ }
+# endif /* FEAT_MOUSE_NET */
+# ifdef FEAT_MOUSE_JSB
+ if (key_name[0] == (int)KS_JSBTERM_MOUSE)
+ {
+ int mult, val, iter, button, status;
+
+ /* JSBTERM Input Model
+ * \033[0~zw uniq escape sequence
+ * (L-x) Left button pressed - not pressed x not reporting
+ * (M-x) Middle button pressed - not pressed x not reporting
+ * (R-x) Right button pressed - not pressed x not reporting
+ * (SDmdu) Single , Double click, m mouse move d button down
+ * u button up
+ * ### X cursor position padded to 3 digits
+ * ### Y cursor position padded to 3 digits
+ * (s-x) SHIFT key pressed - not pressed x not reporting
+ * (c-x) CTRL key pressed - not pressed x not reporting
+ * \033\\ terminating sequence
+ */
+
+ p = tp + slen;
+ button = mouse_code = 0;
+ switch (*p++)
+ {
+ case 'L': button = 1; break;
+ case '-': break;
+ case 'x': break; /* ignore sequence */
+ default: return -1; /* Unknown Result */
+ }
+ switch (*p++)
+ {
+ case 'M': button |= 2; break;
+ case '-': break;
+ case 'x': break; /* ignore sequence */
+ default: return -1; /* Unknown Result */
+ }
+ switch (*p++)
+ {
+ case 'R': button |= 4; break;
+ case '-': break;
+ case 'x': break; /* ignore sequence */
+ default: return -1; /* Unknown Result */
+ }
+ status = *p++;
+ for (val = 0, mult = 100, iter = 0; iter < 3; iter++,
+ mult /= 10, p++)
+ if (*p >= '0' && *p <= '9')
+ val += (*p - '0') * mult;
+ else
+ return -1;
+ mouse_col = val;
+ for (val = 0, mult = 100, iter = 0; iter < 3; iter++,
+ mult /= 10, p++)
+ if (*p >= '0' && *p <= '9')
+ val += (*p - '0') * mult;
+ else
+ return -1;
+ mouse_row = val;
+ switch (*p++)
+ {
+ case 's': button |= 8; break; /* SHIFT key Pressed */
+ case '-': break; /* Not Pressed */
+ case 'x': break; /* Not Reporting */
+ default: return -1; /* Unknown Result */
+ }
+ switch (*p++)
+ {
+ case 'c': button |= 16; break; /* CTRL key Pressed */
+ case '-': break; /* Not Pressed */
+ case 'x': break; /* Not Reporting */
+ default: return -1; /* Unknown Result */
+ }
+ if (*p++ != '\033')
+ return -1;
+ if (*p++ != '\\')
+ return -1;
+ switch (status)
+ {
+ case 'D': /* Double Click */
+ case 'S': /* Single Click */
+ if (button & 1) mouse_code |= MOUSE_LEFT;
+ if (button & 2) mouse_code |= MOUSE_MIDDLE;
+ if (button & 4) mouse_code |= MOUSE_RIGHT;
+ if (button & 8) mouse_code |= MOUSE_SHIFT;
+ if (button & 16) mouse_code |= MOUSE_CTRL;
+ break;
+ case 'm': /* Mouse move */
+ if (button & 1) mouse_code |= MOUSE_LEFT;
+ if (button & 2) mouse_code |= MOUSE_MIDDLE;
+ if (button & 4) mouse_code |= MOUSE_RIGHT;
+ if (button & 8) mouse_code |= MOUSE_SHIFT;
+ if (button & 16) mouse_code |= MOUSE_CTRL;
+ if ((button & 7) != 0)
+ {
+ held_button = mouse_code;
+ mouse_code |= MOUSE_DRAG;
+ }
+ is_drag = TRUE;
+ showmode();
+ break;
+ case 'd': /* Button Down */
+ if (button & 1) mouse_code |= MOUSE_LEFT;
+ if (button & 2) mouse_code |= MOUSE_MIDDLE;
+ if (button & 4) mouse_code |= MOUSE_RIGHT;
+ if (button & 8) mouse_code |= MOUSE_SHIFT;
+ if (button & 16) mouse_code |= MOUSE_CTRL;
+ break;
+ case 'u': /* Button Up */
+ if (button & 1)
+ mouse_code |= MOUSE_LEFT | MOUSE_RELEASE;
+ if (button & 2)
+ mouse_code |= MOUSE_MIDDLE | MOUSE_RELEASE;
+ if (button & 4)
+ mouse_code |= MOUSE_RIGHT | MOUSE_RELEASE;
+ if (button & 8)
+ mouse_code |= MOUSE_SHIFT;
+ if (button & 16)
+ mouse_code |= MOUSE_CTRL;
+ break;
+ default: return -1; /* Unknown Result */
+ }
+
+ slen += (p - (tp + slen));
+ }
+# endif /* FEAT_MOUSE_JSB */
+# ifdef FEAT_MOUSE_DEC
+ if (key_name[0] == (int)KS_DEC_MOUSE)
+ {
+ /* The DEC Locator Input Model
+ * Netterm delivers the code sequence:
+ * \033[2;4;24;80&w (left button down)
+ * \033[3;0;24;80&w (left button up)
+ * \033[6;1;24;80&w (right button down)
+ * \033[7;0;24;80&w (right button up)
+ * CSI Pe ; Pb ; Pr ; Pc ; Pp & w
+ * Pe is the event code
+ * Pb is the button code
+ * Pr is the row coordinate
+ * Pc is the column coordinate
+ * Pp is the third coordinate (page number)
+ * Pe, the event code indicates what event caused this report
+ * The following event codes are defined:
+ * 0 - request, the terminal received an explicit request
+ * for a locator report, but the locator is unavailable
+ * 1 - request, the terminal received an explicit request
+ * for a locator report
+ * 2 - left button down
+ * 3 - left button up
+ * 4 - middle button down
+ * 5 - middle button up
+ * 6 - right button down
+ * 7 - right button up
+ * 8 - fourth button down
+ * 9 - fourth button up
+ * 10 - locator outside filter rectangle
+ * Pb, the button code, ASCII decimal 0-15 indicating which
+ * buttons are down if any. The state of the four buttons
+ * on the locator correspond to the low four bits of the
+ * decimal value,
+ * "1" means button depressed
+ * 0 - no buttons down,
+ * 1 - right,
+ * 2 - middle,
+ * 4 - left,
+ * 8 - fourth
+ * Pr is the row coordinate of the locator position in the page,
+ * encoded as an ASCII decimal value.
+ * If Pr is omitted, the locator position is undefined
+ * (outside the terminal window for example).
+ * Pc is the column coordinate of the locator position in the
+ * page, encoded as an ASCII decimal value.
+ * If Pc is omitted, the locator position is undefined
+ * (outside the terminal window for example).
+ * Pp is the page coordinate of the locator position
+ * encoded as an ASCII decimal value.
+ * The page coordinate may be omitted if the locator is on
+ * page one (the default). We ignore it anyway.
+ */
+ int Pe, Pb, Pr, Pc;
+
+ p = tp + slen;
+
+ /* get event status */
+ Pe = getdigits(&p);
+ if (*p++ != ';')
+ return -1;
+
+ /* get button status */
+ Pb = getdigits(&p);
+ if (*p++ != ';')
+ return -1;
+
+ /* get row status */
+ Pr = getdigits(&p);
+ if (*p++ != ';')
+ return -1;
+
+ /* get column status */
+ Pc = getdigits(&p);
+
+ /* the page parameter is optional */
+ if (*p == ';')
+ {
+ p++;
+ (void)getdigits(&p);
+ }
+ if (*p++ != '&')
+ return -1;
+ if (*p++ != 'w')
+ return -1;
+
+ mouse_code = 0;
+ switch (Pe)
+ {
+ case 0: return -1; /* position request while unavailable */
+ case 1: /* a response to a locator position request includes
+ the status of all buttons */
+ Pb &= 7; /* mask off and ignore fourth button */
+ if (Pb & 4)
+ mouse_code = MOUSE_LEFT;
+ if (Pb & 2)
+ mouse_code = MOUSE_MIDDLE;
+ if (Pb & 1)
+ mouse_code = MOUSE_RIGHT;
+ if (Pb)
+ {
+ held_button = mouse_code;
+ mouse_code |= MOUSE_DRAG;
+ WantQueryMouse = TRUE;
+ }
+ is_drag = TRUE;
+ showmode();
+ break;
+ case 2: mouse_code = MOUSE_LEFT;
+ WantQueryMouse = TRUE;
+ break;
+ case 3: mouse_code = MOUSE_RELEASE | MOUSE_LEFT;
+ break;
+ case 4: mouse_code = MOUSE_MIDDLE;
+ WantQueryMouse = TRUE;
+ break;
+ case 5: mouse_code = MOUSE_RELEASE | MOUSE_MIDDLE;
+ break;
+ case 6: mouse_code = MOUSE_RIGHT;
+ WantQueryMouse = TRUE;
+ break;
+ case 7: mouse_code = MOUSE_RELEASE | MOUSE_RIGHT;
+ break;
+ case 8: return -1; /* fourth button down */
+ case 9: return -1; /* fourth button up */
+ case 10: return -1; /* mouse outside of filter rectangle */
+ default: return -1; /* should never occur */
+ }
+
+ mouse_col = Pc - 1;
+ mouse_row = Pr - 1;
+
+ slen += (int)(p - (tp + slen));
+ }
+# endif /* FEAT_MOUSE_DEC */
+# ifdef FEAT_MOUSE_PTERM
+ if (key_name[0] == (int)KS_PTERM_MOUSE)
+ {
+ int button, num_clicks, action;
+
+ p = tp + slen;
+
+ action = getdigits(&p);
+ if (*p++ != ';')
+ return -1;
+
+ mouse_row = getdigits(&p);
+ if (*p++ != ';')
+ return -1;
+ mouse_col = getdigits(&p);
+ if (*p++ != ';')
+ return -1;
+
+ button = getdigits(&p);
+ mouse_code = 0;
+
+ switch (button)
+ {
+ case 4: mouse_code = MOUSE_LEFT; break;
+ case 1: mouse_code = MOUSE_RIGHT; break;
+ case 2: mouse_code = MOUSE_MIDDLE; break;
+ default: return -1;
+ }
+
+ switch (action)
+ {
+ case 31: /* Initial press */
+ if (*p++ != ';')
+ return -1;
+
+ num_clicks = getdigits(&p); /* Not used */
+ break;
+
+ case 32: /* Release */
+ mouse_code |= MOUSE_RELEASE;
+ break;
+
+ case 33: /* Drag */
+ held_button = mouse_code;
+ mouse_code |= MOUSE_DRAG;
+ break;
+
+ default:
+ return -1;
+ }
+
+ if (*p++ != 't')
+ return -1;
+
+ slen += (p - (tp + slen));
+ }
+# endif /* FEAT_MOUSE_PTERM */
+
+ /* Interpret the mouse code */
+ current_button = (mouse_code & MOUSE_CLICK_MASK);
+ if (current_button == MOUSE_RELEASE
+# ifdef FEAT_MOUSE_XTERM
+ && wheel_code == 0
+# endif
+ )
+ {
+ /*
+ * If we get a mouse drag or release event when
+ * there is no mouse button held down (held_button ==
+ * MOUSE_RELEASE), produce a K_IGNORE below.
+ * (can happen when you hold down two buttons
+ * and then let them go, or click in the menu bar, but not
+ * on a menu, and drag into the text).
+ */
+ if ((mouse_code & MOUSE_DRAG) == MOUSE_DRAG)
+ is_drag = TRUE;
+ current_button = held_button;
+ }
+ else if (wheel_code == 0)
+ {
+# ifdef CHECK_DOUBLE_CLICK
+# ifdef FEAT_MOUSE_GPM
+# ifdef FEAT_GUI
+ /*
+ * Only for Unix, when GUI or gpm is not active, we handle
+ * multi-clicks here.
+ */
+ if (gpm_flag == 0 && !gui.in_use)
+# else
+ if (gpm_flag == 0)
+# endif
+# else
+# ifdef FEAT_GUI
+ if (!gui.in_use)
+# endif
+# endif
+ {
+ /*
+ * Compute the time elapsed since the previous mouse click.
+ */
+ gettimeofday(&mouse_time, NULL);
+ if (orig_mouse_time.tv_sec == 0)
+ {
+ /*
+ * Avoid computing the difference between mouse_time
+ * and orig_mouse_time for the first click, as the
+ * difference would be huge and would cause
+ * multiplication overflow.
+ */
+ timediff = p_mouset;
+ }
+ else
+ {
+ timediff = (mouse_time.tv_usec
+ - orig_mouse_time.tv_usec) / 1000;
+ if (timediff < 0)
+ --orig_mouse_time.tv_sec;
+ timediff += (mouse_time.tv_sec
+ - orig_mouse_time.tv_sec) * 1000;
+ }
+ orig_mouse_time = mouse_time;
+ if (mouse_code == orig_mouse_code
+ && timediff < p_mouset
+ && orig_num_clicks != 4
+ && orig_mouse_col == mouse_col
+ && orig_mouse_row == mouse_row
+ && ((orig_topline == curwin->w_topline
+#ifdef FEAT_DIFF
+ && orig_topfill == curwin->w_topfill
+#endif
+ )
+ /* Double click in tab pages line also works
+ * when window contents changes. */
+ || (mouse_row == 0 && firstwin->w_winrow > 0))
+ )
+ ++orig_num_clicks;
+ else
+ orig_num_clicks = 1;
+ orig_mouse_col = mouse_col;
+ orig_mouse_row = mouse_row;
+ orig_topline = curwin->w_topline;
+#ifdef FEAT_DIFF
+ orig_topfill = curwin->w_topfill;
+#endif
+ }
+# if defined(FEAT_GUI) || defined(FEAT_MOUSE_GPM)
+ else
+ orig_num_clicks = NUM_MOUSE_CLICKS(mouse_code);
+# endif
+# else
+ orig_num_clicks = NUM_MOUSE_CLICKS(mouse_code);
+# endif
+ is_click = TRUE;
+ orig_mouse_code = mouse_code;
+ }
+ if (!is_drag)
+ held_button = mouse_code & MOUSE_CLICK_MASK;
+
+ /*
+ * Translate the actual mouse event into a pseudo mouse event.
+ * First work out what modifiers are to be used.
+ */
+ if (orig_mouse_code & MOUSE_SHIFT)
+ modifiers |= MOD_MASK_SHIFT;
+ if (orig_mouse_code & MOUSE_CTRL)
+ modifiers |= MOD_MASK_CTRL;
+ if (orig_mouse_code & MOUSE_ALT)
+ modifiers |= MOD_MASK_ALT;
+ if (orig_num_clicks == 2)
+ modifiers |= MOD_MASK_2CLICK;
+ else if (orig_num_clicks == 3)
+ modifiers |= MOD_MASK_3CLICK;
+ else if (orig_num_clicks == 4)
+ modifiers |= MOD_MASK_4CLICK;
+
+ /* Work out our pseudo mouse event. Note that MOUSE_RELEASE gets
+ * added, then it's not mouse up/down. */
+ key_name[0] = (int)KS_EXTRA;
+ if (wheel_code != 0
+ && (wheel_code & MOUSE_RELEASE) != MOUSE_RELEASE)
+ {
+ if (wheel_code & MOUSE_CTRL)
+ modifiers |= MOD_MASK_CTRL;
+ if (wheel_code & MOUSE_ALT)
+ modifiers |= MOD_MASK_ALT;
+ key_name[1] = (wheel_code & 1)
+ ? (int)KE_MOUSEUP : (int)KE_MOUSEDOWN;
+ held_button = MOUSE_RELEASE;
+ }
+ else
+ key_name[1] = get_pseudo_mouse_code(current_button,
+ is_click, is_drag);
+
+ /* Make sure the mouse position is valid. Some terminals may
+ * return weird values. */
+ if (mouse_col >= Columns)
+ mouse_col = Columns - 1;
+ if (mouse_row >= Rows)
+ mouse_row = Rows - 1;
+ }
+#endif /* FEAT_MOUSE */
+
+#ifdef FEAT_GUI
+ /*
+ * If using the GUI, then we get menu and scrollbar events.
+ *
+ * A menu event is encoded as K_SPECIAL, KS_MENU, KE_FILLER followed by
+ * four bytes which are to be taken as a pointer to the vimmenu_T
+ * structure.
+ *
+ * A tab line event is encoded as K_SPECIAL KS_TABLINE nr, where "nr"
+ * is one byte with the tab index.
+ *
+ * A scrollbar event is K_SPECIAL, KS_VER_SCROLLBAR, KE_FILLER followed
+ * by one byte representing the scrollbar number, and then four bytes
+ * representing a long_u which is the new value of the scrollbar.
+ *
+ * A horizontal scrollbar event is K_SPECIAL, KS_HOR_SCROLLBAR,
+ * KE_FILLER followed by four bytes representing a long_u which is the
+ * new value of the scrollbar.
+ */
+# ifdef FEAT_MENU
+ else if (key_name[0] == (int)KS_MENU)
+ {
+ long_u val;
+
+ num_bytes = get_long_from_buf(tp + slen, &val);
+ if (num_bytes == -1)
+ return -1;
+ current_menu = (vimmenu_T *)val;
+ slen += num_bytes;
+
+ /* The menu may have been deleted right after it was used, check
+ * for that. */
+ if (check_menu_pointer(root_menu, current_menu) == FAIL)
+ {
+ key_name[0] = KS_EXTRA;
+ key_name[1] = (int)KE_IGNORE;
+ }
+ }
+# endif
+# ifdef FEAT_GUI_TABLINE
+ else if (key_name[0] == (int)KS_TABLINE)
+ {
+ /* Selecting tabline tab or using its menu. */
+ num_bytes = get_bytes_from_buf(tp + slen, bytes, 1);
+ if (num_bytes == -1)
+ return -1;
+ current_tab = (int)bytes[0];
+ if (current_tab == 255) /* -1 in a byte gives 255 */
+ current_tab = -1;
+ slen += num_bytes;
+ }
+ else if (key_name[0] == (int)KS_TABMENU)
+ {
+ /* Selecting tabline tab or using its menu. */
+ num_bytes = get_bytes_from_buf(tp + slen, bytes, 2);
+ if (num_bytes == -1)
+ return -1;
+ current_tab = (int)bytes[0];
+ current_tabmenu = (int)bytes[1];
+ slen += num_bytes;
+ }
+# endif
+# ifndef USE_ON_FLY_SCROLL
+ else if (key_name[0] == (int)KS_VER_SCROLLBAR)
+ {
+ long_u val;
+
+ /* Get the last scrollbar event in the queue of the same type */
+ j = 0;
+ for (i = 0; tp[j] == CSI && tp[j + 1] == KS_VER_SCROLLBAR
+ && tp[j + 2] != NUL; ++i)
+ {
+ j += 3;
+ num_bytes = get_bytes_from_buf(tp + j, bytes, 1);
+ if (num_bytes == -1)
+ break;
+ if (i == 0)
+ current_scrollbar = (int)bytes[0];
+ else if (current_scrollbar != (int)bytes[0])
+ break;
+ j += num_bytes;
+ num_bytes = get_long_from_buf(tp + j, &val);
+ if (num_bytes == -1)
+ break;
+ scrollbar_value = val;
+ j += num_bytes;
+ slen = j;
+ }
+ if (i == 0) /* not enough characters to make one */
+ return -1;
+ }
+ else if (key_name[0] == (int)KS_HOR_SCROLLBAR)
+ {
+ long_u val;
+
+ /* Get the last horiz. scrollbar event in the queue */
+ j = 0;
+ for (i = 0; tp[j] == CSI && tp[j + 1] == KS_HOR_SCROLLBAR
+ && tp[j + 2] != NUL; ++i)
+ {
+ j += 3;
+ num_bytes = get_long_from_buf(tp + j, &val);
+ if (num_bytes == -1)
+ break;
+ scrollbar_value = val;
+ j += num_bytes;
+ slen = j;
+ }
+ if (i == 0) /* not enough characters to make one */
+ return -1;
+ }
+# endif /* !USE_ON_FLY_SCROLL */
+#endif /* FEAT_GUI */
+
+ /*
+ * Change <xHome> to <Home>, <xUp> to <Up>, etc.
+ */
+ key = handle_x_keys(TERMCAP2KEY(key_name[0], key_name[1]));
+
+ /*
+ * Add any modifier codes to our string.
+ */
+ new_slen = 0; /* Length of what will replace the termcode */
+ if (modifiers != 0)
+ {
+ /* Some keys have the modifier included. Need to handle that here
+ * to make mappings work. */
+ key = simplify_key(key, &modifiers);
+ if (modifiers != 0)
+ {
+ string[new_slen++] = K_SPECIAL;
+ string[new_slen++] = (int)KS_MODIFIER;
+ string[new_slen++] = modifiers;
+ }
+ }
+
+ /* Finally, add the special key code to our string */
+ key_name[0] = KEY2TERMCAP0(key);
+ key_name[1] = KEY2TERMCAP1(key);
+ if (key_name[0] == KS_KEY)
+ {
+ /* from ":set <M-b>=xx" */
+ if (has_mbyte)
+ new_slen += (*mb_char2bytes)(key_name[1], string + new_slen);
+ else
+ string[new_slen++] = key_name[1];
+ }
+ else if (new_slen == 0 && key_name[0] == KS_EXTRA
+ && key_name[1] == KE_IGNORE)
+ {
+ /* Do not put K_IGNORE into the buffer, do return KEYLEN_REMOVED
+ * to indicate what happened. */
+ retval = KEYLEN_REMOVED;
+ }
+ else
+ {
+ string[new_slen++] = K_SPECIAL;
+ string[new_slen++] = key_name[0];
+ string[new_slen++] = key_name[1];
+ }
+ string[new_slen] = NUL;
+ extra = new_slen - slen;
+ if (buf == NULL)
+ {
+ if (extra < 0)
+ /* remove matched chars, taking care of noremap */
+ del_typebuf(-extra, offset);
+ else if (extra > 0)
+ /* insert the extra space we need */
+ ins_typebuf(string + slen, REMAP_YES, offset, FALSE, FALSE);
+
+ /*
+ * Careful: del_typebuf() and ins_typebuf() may have reallocated
+ * typebuf.tb_buf[]!
+ */
+ mch_memmove(typebuf.tb_buf + typebuf.tb_off + offset, string,
+ (size_t)new_slen);
+ }
+ else
+ {
+ if (extra < 0)
+ /* remove matched characters */
+ mch_memmove(buf + offset, buf + offset - extra,
+ (size_t)(*buflen + offset + extra));
+ else if (extra > 0)
+ {
+ /* Insert the extra space we need. If there is insufficient
+ * space return -1. */
+ if (*buflen + extra + new_slen >= bufsize)
+ return -1;
+ mch_memmove(buf + offset + extra, buf + offset,
+ (size_t)(*buflen - offset));
+ }
+ mch_memmove(buf + offset, string, (size_t)new_slen);
+ *buflen = *buflen + extra + new_slen;
+ }
+ return retval == 0 ? (len + extra + offset) : retval;
+ }
+
+#ifdef FEAT_TERMRESPONSE
+ LOG_TR(("normal character"));
+#endif
+
+ return 0; /* no match found */
+}
+
+#if (defined(FEAT_TERMINAL) && defined(FEAT_TERMRESPONSE)) || defined(PROTO)
+/*
+ * Get the text foreground color, if known.
+ */
+ void
+term_get_fg_color(char_u *r, char_u *g, char_u *b)
+{
+ if (rfg_status == STATUS_GOT)
+ {
+ *r = fg_r;
+ *g = fg_g;
+ *b = fg_b;
+ }
+}
+
+/*
+ * Get the text background color, if known.
+ */
+ void
+term_get_bg_color(char_u *r, char_u *g, char_u *b)
+{
+ if (rbg_status == STATUS_GOT)
+ {
+ *r = bg_r;
+ *g = bg_g;
+ *b = bg_b;
+ }
+}
+#endif
+
+/*
+ * Replace any terminal code strings in from[] with the equivalent internal
+ * vim representation. This is used for the "from" and "to" part of a
+ * mapping, and the "to" part of a menu command.
+ * Any strings like "<C-UP>" are also replaced, unless 'cpoptions' contains
+ * '<'.
+ * K_SPECIAL by itself is replaced by K_SPECIAL KS_SPECIAL KE_FILLER.
+ *
+ * The replacement is done in result[] and finally copied into allocated
+ * memory. If this all works well *bufp is set to the allocated memory and a
+ * pointer to it is returned. If something fails *bufp is set to NULL and from
+ * is returned.
+ *
+ * CTRL-V characters are removed. When "from_part" is TRUE, a trailing CTRL-V
+ * is included, otherwise it is removed (for ":map xx ^V", maps xx to
+ * nothing). When 'cpoptions' does not contain 'B', a backslash can be used
+ * instead of a CTRL-V.
+ */
+ char_u *
+replace_termcodes(
+ char_u *from,
+ char_u **bufp,
+ int from_part,
+ int do_lt, /* also translate <lt> */
+ int special) /* always accept <key> notation */
+{
+ int i;
+ int slen;
+ int key;
+ int dlen = 0;
+ char_u *src;
+ int do_backslash; /* backslash is a special character */
+ int do_special; /* recognize <> key codes */
+ int do_key_code; /* recognize raw key codes */
+ char_u *result; /* buffer for resulting string */
+
+ do_backslash = (vim_strchr(p_cpo, CPO_BSLASH) == NULL);
+ do_special = (vim_strchr(p_cpo, CPO_SPECI) == NULL) || special;
+ do_key_code = (vim_strchr(p_cpo, CPO_KEYCODE) == NULL);
+
+ /*
+ * Allocate space for the translation. Worst case a single character is
+ * replaced by 6 bytes (shifted special key), plus a NUL at the end.
+ */
+ result = alloc((unsigned)STRLEN(from) * 6 + 1);
+ if (result == NULL) /* out of memory */
+ {
+ *bufp = NULL;
+ return from;
+ }
+
+ src = from;
+
+ /*
+ * Check for #n at start only: function key n
+ */
+ if (from_part && src[0] == '#' && VIM_ISDIGIT(src[1])) /* function key */
+ {
+ result[dlen++] = K_SPECIAL;
+ result[dlen++] = 'k';
+ if (src[1] == '0')
+ result[dlen++] = ';'; /* #0 is F10 is "k;" */
+ else
+ result[dlen++] = src[1]; /* #3 is F3 is "k3" */
+ src += 2;
+ }
+
+ /*
+ * Copy each byte from *from to result[dlen]
+ */
+ while (*src != NUL)
+ {
+ /*
+ * If 'cpoptions' does not contain '<', check for special key codes,
+ * like "<C-S-LeftMouse>"
+ */
+ if (do_special && (do_lt || STRNCMP(src, "<lt>", 4) != 0))
+ {
+#ifdef FEAT_EVAL
+ /*
+ * Replace <SID> by K_SNR <script-nr> _.
+ * (room: 5 * 6 = 30 bytes; needed: 3 + <nr> + 1 <= 14)
+ */
+ if (STRNICMP(src, "<SID>", 5) == 0)
+ {
+ if (current_sctx.sc_sid <= 0)
+ emsg(_(e_usingsid));
+ else
+ {
+ src += 5;
+ result[dlen++] = K_SPECIAL;
+ result[dlen++] = (int)KS_EXTRA;
+ result[dlen++] = (int)KE_SNR;
+ sprintf((char *)result + dlen, "%ld",
+ (long)current_sctx.sc_sid);
+ dlen += (int)STRLEN(result + dlen);
+ result[dlen++] = '_';
+ continue;
+ }
+ }
+#endif
+
+ slen = trans_special(&src, result + dlen, TRUE, FALSE);
+ if (slen)
+ {
+ dlen += slen;
+ continue;
+ }
+ }
+
+ /*
+ * If 'cpoptions' does not contain 'k', see if it's an actual key-code.
+ * Note that this is also checked after replacing the <> form.
+ * Single character codes are NOT replaced (e.g. ^H or DEL), because
+ * it could be a character in the file.
+ */
+ if (do_key_code)
+ {
+ i = find_term_bykeys(src);
+ if (i >= 0)
+ {
+ result[dlen++] = K_SPECIAL;
+ result[dlen++] = termcodes[i].name[0];
+ result[dlen++] = termcodes[i].name[1];
+ src += termcodes[i].len;
+ /* If terminal code matched, continue after it. */
+ continue;
+ }
+ }
+
+#ifdef FEAT_EVAL
+ if (do_special)
+ {
+ char_u *p, *s, len;
+
+ /*
+ * Replace <Leader> by the value of "mapleader".
+ * Replace <LocalLeader> by the value of "maplocalleader".
+ * If "mapleader" or "maplocalleader" isn't set use a backslash.
+ */
+ if (STRNICMP(src, "<Leader>", 8) == 0)
+ {
+ len = 8;
+ p = get_var_value((char_u *)"g:mapleader");
+ }
+ else if (STRNICMP(src, "<LocalLeader>", 13) == 0)
+ {
+ len = 13;
+ p = get_var_value((char_u *)"g:maplocalleader");
+ }
+ else
+ {
+ len = 0;
+ p = NULL;
+ }
+ if (len != 0)
+ {
+ /* Allow up to 8 * 6 characters for "mapleader". */
+ if (p == NULL || *p == NUL || STRLEN(p) > 8 * 6)
+ s = (char_u *)"\\";
+ else
+ s = p;
+ while (*s != NUL)
+ result[dlen++] = *s++;
+ src += len;
+ continue;
+ }
+ }
+#endif
+
+ /*
+ * Remove CTRL-V and ignore the next character.
+ * For "from" side the CTRL-V at the end is included, for the "to"
+ * part it is removed.
+ * If 'cpoptions' does not contain 'B', also accept a backslash.
+ */
+ key = *src;
+ if (key == Ctrl_V || (do_backslash && key == '\\'))
+ {
+ ++src; /* skip CTRL-V or backslash */
+ if (*src == NUL)
+ {
+ if (from_part)
+ result[dlen++] = key;
+ break;
+ }
+ }
+
+ /* skip multibyte char correctly */
+ for (i = (*mb_ptr2len)(src); i > 0; --i)
+ {
+ /*
+ * If the character is K_SPECIAL, replace it with K_SPECIAL
+ * KS_SPECIAL KE_FILLER.
+ * If compiled with the GUI replace CSI with K_CSI.
+ */
+ if (*src == K_SPECIAL)
+ {
+ result[dlen++] = K_SPECIAL;
+ result[dlen++] = KS_SPECIAL;
+ result[dlen++] = KE_FILLER;
+ }
+# ifdef FEAT_GUI
+ else if (*src == CSI)
+ {
+ result[dlen++] = K_SPECIAL;
+ result[dlen++] = KS_EXTRA;
+ result[dlen++] = (int)KE_CSI;
+ }
+# endif
+ else
+ result[dlen++] = *src;
+ ++src;
+ }
+ }
+ result[dlen] = NUL;
+
+ /*
+ * Copy the new string to allocated memory.
+ * If this fails, just return from.
+ */
+ if ((*bufp = vim_strsave(result)) != NULL)
+ from = *bufp;
+ vim_free(result);
+ return from;
+}
+
+/*
+ * Find a termcode with keys 'src' (must be NUL terminated).
+ * Return the index in termcodes[], or -1 if not found.
+ */
+ int
+find_term_bykeys(char_u *src)
+{
+ int i;
+ int slen = (int)STRLEN(src);
+
+ for (i = 0; i < tc_len; ++i)
+ {
+ if (slen == termcodes[i].len
+ && STRNCMP(termcodes[i].code, src, (size_t)slen) == 0)
+ return i;
+ }
+ return -1;
+}
+
+/*
+ * Gather the first characters in the terminal key codes into a string.
+ * Used to speed up check_termcode().
+ */
+ static void
+gather_termleader(void)
+{
+ int i;
+ int len = 0;
+
+#ifdef FEAT_GUI
+ if (gui.in_use)
+ termleader[len++] = CSI; /* the GUI codes are not in termcodes[] */
+#endif
+#ifdef FEAT_TERMRESPONSE
+ if (check_for_codes || *T_CRS != NUL)
+ termleader[len++] = DCS; /* the termcode response starts with DCS
+ in 8-bit mode */
+#endif
+ termleader[len] = NUL;
+
+ for (i = 0; i < tc_len; ++i)
+ if (vim_strchr(termleader, termcodes[i].code[0]) == NULL)
+ {
+ termleader[len++] = termcodes[i].code[0];
+ termleader[len] = NUL;
+ }
+
+ need_gather = FALSE;
+}
+
+/*
+ * Show all termcodes (for ":set termcap")
+ * This code looks a lot like showoptions(), but is different.
+ */
+ void
+show_termcodes(void)
+{
+ int col;
+ int *items;
+ int item_count;
+ int run;
+ int row, rows;
+ int cols;
+ int i;
+ int len;
+
+#define INC3 27 /* try to make three columns */
+#define INC2 40 /* try to make two columns */
+#define GAP 2 /* spaces between columns */
+
+ if (tc_len == 0) /* no terminal codes (must be GUI) */
+ return;
+ items = (int *)alloc((unsigned)(sizeof(int) * tc_len));
+ if (items == NULL)
+ return;
+
+ /* Highlight title */
+ msg_puts_title(_("\n--- Terminal keys ---"));
+
+ /*
+ * do the loop two times:
+ * 1. display the short items (non-strings and short strings)
+ * 2. display the medium items (medium length strings)
+ * 3. display the long items (remaining strings)
+ */
+ for (run = 1; run <= 3 && !got_int; ++run)
+ {
+ /*
+ * collect the items in items[]
+ */
+ item_count = 0;
+ for (i = 0; i < tc_len; i++)
+ {
+ len = show_one_termcode(termcodes[i].name,
+ termcodes[i].code, FALSE);
+ if (len <= INC3 - GAP ? run == 1
+ : len <= INC2 - GAP ? run == 2
+ : run == 3)
+ items[item_count++] = i;
+ }
+
+ /*
+ * display the items
+ */
+ if (run <= 2)
+ {
+ cols = (Columns + GAP) / (run == 1 ? INC3 : INC2);
+ if (cols == 0)
+ cols = 1;
+ rows = (item_count + cols - 1) / cols;
+ }
+ else /* run == 3 */
+ rows = item_count;
+ for (row = 0; row < rows && !got_int; ++row)
+ {
+ msg_putchar('\n'); /* go to next line */
+ if (got_int) /* 'q' typed in more */
+ break;
+ col = 0;
+ for (i = row; i < item_count; i += rows)
+ {
+ msg_col = col; /* make columns */
+ show_one_termcode(termcodes[items[i]].name,
+ termcodes[items[i]].code, TRUE);
+ if (run == 2)
+ col += INC2;
+ else
+ col += INC3;
+ }
+ out_flush();
+ ui_breakcheck();
+ }
+ }
+ vim_free(items);
+}
+
+/*
+ * Show one termcode entry.
+ * Output goes into IObuff[]
+ */
+ int
+show_one_termcode(char_u *name, char_u *code, int printit)
+{
+ char_u *p;
+ int len;
+
+ if (name[0] > '~')
+ {
+ IObuff[0] = ' ';
+ IObuff[1] = ' ';
+ IObuff[2] = ' ';
+ IObuff[3] = ' ';
+ }
+ else
+ {
+ IObuff[0] = 't';
+ IObuff[1] = '_';
+ IObuff[2] = name[0];
+ IObuff[3] = name[1];
+ }
+ IObuff[4] = ' ';
+
+ p = get_special_key_name(TERMCAP2KEY(name[0], name[1]), 0);
+ if (p[1] != 't')
+ STRCPY(IObuff + 5, p);
+ else
+ IObuff[5] = NUL;
+ len = (int)STRLEN(IObuff);
+ do
+ IObuff[len++] = ' ';
+ while (len < 17);
+ IObuff[len] = NUL;
+ if (code == NULL)
+ len += 4;
+ else
+ len += vim_strsize(code);
+
+ if (printit)
+ {
+ msg_puts((char *)IObuff);
+ if (code == NULL)
+ msg_puts("NULL");
+ else
+ msg_outtrans(code);
+ }
+ return len;
+}
+
+#if defined(FEAT_TERMRESPONSE) || defined(PROTO)
+/*
+ * For Xterm >= 140 compiled with OPT_TCAP_QUERY: Obtain the actually used
+ * termcap codes from the terminal itself.
+ * We get them one by one to avoid a very long response string.
+ */
+static int xt_index_in = 0;
+static int xt_index_out = 0;
+
+ static void
+req_codes_from_term(void)
+{
+ xt_index_out = 0;
+ xt_index_in = 0;
+ req_more_codes_from_term();
+}
+
+ static void
+req_more_codes_from_term(void)
+{
+ char buf[11];
+ int old_idx = xt_index_out;
+
+ /* Don't do anything when going to exit. */
+ if (exiting)
+ return;
+
+ /* Send up to 10 more requests out than we received. Avoid sending too
+ * many, there can be a buffer overflow somewhere. */
+ while (xt_index_out < xt_index_in + 10 && key_names[xt_index_out] != NULL)
+ {
+ char *key_name = key_names[xt_index_out];
+
+ LOG_TR(("Requesting XT %d: %s", xt_index_out, key_name));
+ sprintf(buf, "\033P+q%02x%02x\033\\", key_name[0], key_name[1]);
+ out_str_nf((char_u *)buf);
+ ++xt_index_out;
+ }
+
+ /* Send the codes out right away. */
+ if (xt_index_out != old_idx)
+ out_flush();
+}
+
+/*
+ * Decode key code response from xterm: '<Esc>P1+r<name>=<string><Esc>\'.
+ * A "0" instead of the "1" indicates a code that isn't supported.
+ * Both <name> and <string> are encoded in hex.
+ * "code" points to the "0" or "1".
+ */
+ static void
+got_code_from_term(char_u *code, int len)
+{
+#define XT_LEN 100
+ char_u name[3];
+ char_u str[XT_LEN];
+ int i;
+ int j = 0;
+ int c;
+
+ /* A '1' means the code is supported, a '0' means it isn't.
+ * When half the length is > XT_LEN we can't use it.
+ * Our names are currently all 2 characters. */
+ if (code[0] == '1' && code[7] == '=' && len / 2 < XT_LEN)
+ {
+ /* Get the name from the response and find it in the table. */
+ name[0] = hexhex2nr(code + 3);
+ name[1] = hexhex2nr(code + 5);
+ name[2] = NUL;
+ for (i = 0; key_names[i] != NULL; ++i)
+ {
+ if (STRCMP(key_names[i], name) == 0)
+ {
+ xt_index_in = i;
+ break;
+ }
+ }
+
+ LOG_TR(("Received XT %d: %s", xt_index_in, (char *)name));
+
+ if (key_names[i] != NULL)
+ {
+ for (i = 8; (c = hexhex2nr(code + i)) >= 0; i += 2)
+ str[j++] = c;
+ str[j] = NUL;
+ if (name[0] == 'C' && name[1] == 'o')
+ {
+ /* Color count is not a key code. */
+ i = atoi((char *)str);
+ may_adjust_color_count(i);
+ }
+ else
+ {
+ /* First delete any existing entry with the same code. */
+ i = find_term_bykeys(str);
+ if (i >= 0)
+ del_termcode_idx(i);
+ add_termcode(name, str, ATC_FROM_TERM);
+ }
+ }
+ }
+
+ /* May request more codes now that we received one. */
+ ++xt_index_in;
+ req_more_codes_from_term();
+}
+
+/*
+ * Check if there are any unanswered requests and deal with them.
+ * This is called before starting an external program or getting direct
+ * keyboard input. We don't want responses to be send to that program or
+ * handled as typed text.
+ */
+ static void
+check_for_codes_from_term(void)
+{
+ int c;
+
+ /* If no codes requested or all are answered, no need to wait. */
+ if (xt_index_out == 0 || xt_index_out == xt_index_in)
+ return;
+
+ /* Vgetc() will check for and handle any response.
+ * Keep calling vpeekc() until we don't get any responses. */
+ ++no_mapping;
+ ++allow_keys;
+ for (;;)
+ {
+ c = vpeekc();
+ if (c == NUL) /* nothing available */
+ break;
+
+ /* If a response is recognized it's replaced with K_IGNORE, must read
+ * it from the input stream. If there is no K_IGNORE we can't do
+ * anything, break here (there might be some responses further on, but
+ * we don't want to throw away any typed chars). */
+ if (c != K_SPECIAL && c != K_IGNORE)
+ break;
+ c = vgetc();
+ if (c != K_IGNORE)
+ {
+ vungetc(c);
+ break;
+ }
+ }
+ --no_mapping;
+ --allow_keys;
+}
+#endif
+
+#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
+/*
+ * Translate an internal mapping/abbreviation representation into the
+ * corresponding external one recognized by :map/:abbrev commands;
+ * respects the current B/k/< settings of 'cpoption'.
+ *
+ * This function is called when expanding mappings/abbreviations on the
+ * command-line, and for building the "Ambiguous mapping..." error message.
+ *
+ * It uses a growarray to build the translation string since the
+ * latter can be wider than the original description. The caller has to
+ * free the string afterwards.
+ *
+ * Returns NULL when there is a problem.
+ */
+ char_u *
+translate_mapping(
+ char_u *str,
+ int expmap) /* TRUE when expanding mappings on command-line */
+{
+ garray_T ga;
+ int c;
+ int modifiers;
+ int cpo_bslash;
+ int cpo_special;
+ int cpo_keycode;
+
+ ga_init(&ga);
+ ga.ga_itemsize = 1;
+ ga.ga_growsize = 40;
+
+ cpo_bslash = (vim_strchr(p_cpo, CPO_BSLASH) != NULL);
+ cpo_special = (vim_strchr(p_cpo, CPO_SPECI) != NULL);
+ cpo_keycode = (vim_strchr(p_cpo, CPO_KEYCODE) == NULL);
+
+ for (; *str; ++str)
+ {
+ c = *str;
+ if (c == K_SPECIAL && str[1] != NUL && str[2] != NUL)
+ {
+ modifiers = 0;
+ if (str[1] == KS_MODIFIER)
+ {
+ str++;
+ modifiers = *++str;
+ c = *++str;
+ }
+ if (cpo_special && cpo_keycode && c == K_SPECIAL && !modifiers)
+ {
+ int i;
+
+ /* try to find special key in termcodes */
+ for (i = 0; i < tc_len; ++i)
+ if (termcodes[i].name[0] == str[1]
+ && termcodes[i].name[1] == str[2])
+ break;
+ if (i < tc_len)
+ {
+ ga_concat(&ga, termcodes[i].code);
+ str += 2;
+ continue; /* for (str) */
+ }
+ }
+ if (c == K_SPECIAL && str[1] != NUL && str[2] != NUL)
+ {
+ if (expmap && cpo_special)
+ {
+ ga_clear(&ga);
+ return NULL;
+ }
+ c = TO_SPECIAL(str[1], str[2]);
+ if (c == K_ZERO) /* display <Nul> as ^@ */
+ c = NUL;
+ str += 2;
+ }
+ if (IS_SPECIAL(c) || modifiers) /* special key */
+ {
+ if (expmap && cpo_special)
+ {
+ ga_clear(&ga);
+ return NULL;
+ }
+ ga_concat(&ga, get_special_key_name(c, modifiers));
+ continue; /* for (str) */
+ }
+ }
+ if (c == ' ' || c == '\t' || c == Ctrl_J || c == Ctrl_V
+ || (c == '<' && !cpo_special) || (c == '\\' && !cpo_bslash))
+ ga_append(&ga, cpo_bslash ? Ctrl_V : '\\');
+ if (c)
+ ga_append(&ga, c);
+ }
+ ga_append(&ga, NUL);
+ return (char_u *)(ga.ga_data);
+}
+#endif
+
+#if (defined(WIN3264) && !defined(FEAT_GUI)) || defined(PROTO)
+static char ksme_str[20];
+static char ksmr_str[20];
+static char ksmd_str[20];
+
+/*
+ * For Win32 console: update termcap codes for existing console attributes.
+ */
+ void
+update_tcap(int attr)
+{
+ struct builtin_term *p;
+
+ p = find_builtin_term(DEFAULT_TERM);
+ sprintf(ksme_str, IF_EB("\033|%dm", ESC_STR "|%dm"), attr);
+ sprintf(ksmd_str, IF_EB("\033|%dm", ESC_STR "|%dm"),
+ attr | 0x08); /* FOREGROUND_INTENSITY */
+ sprintf(ksmr_str, IF_EB("\033|%dm", ESC_STR "|%dm"),
+ ((attr & 0x0F) << 4) | ((attr & 0xF0) >> 4));
+
+ while (p->bt_string != NULL)
+ {
+ if (p->bt_entry == (int)KS_ME)
+ p->bt_string = &ksme_str[0];
+ else if (p->bt_entry == (int)KS_MR)
+ p->bt_string = &ksmr_str[0];
+ else if (p->bt_entry == (int)KS_MD)
+ p->bt_string = &ksmd_str[0];
+ ++p;
+ }
+}
+
+# ifdef FEAT_TERMGUICOLORS
+# define KSSIZE 20
+struct ks_tbl_s
+{
+ int code; // value of KS_
+ char *vtp; // code in vtp mode
+ char *vtp2; // code in vtp2 mode
+ char buf[KSSIZE]; // save buffer in non-vtp mode
+ char vbuf[KSSIZE]; // save buffer in vtp mode
+ char v2buf[KSSIZE]; // save buffer in vtp2 mode
+ char arr[KSSIZE]; // real buffer
+};
+
+static struct ks_tbl_s ks_tbl[] =
+{
+ {(int)KS_ME, "\033|0m", "\033|0m"}, // normal
+ {(int)KS_MR, "\033|7m", "\033|7m"}, // reverse
+ {(int)KS_MD, "\033|1m", "\033|1m"}, // bold
+ {(int)KS_SO, "\033|91m", "\033|91m"}, // standout: bright red text
+ {(int)KS_SE, "\033|39m", "\033|39m"}, // standout end: default color
+ {(int)KS_CZH, "\033|95m", "\033|95m"}, // italic: bright magenta text
+ {(int)KS_CZR, "\033|0m", "\033|0m"}, // italic end
+ {(int)KS_US, "\033|4m", "\033|4m"}, // underscore
+ {(int)KS_UE, "\033|24m", "\033|24m"}, // underscore end
+# ifdef TERMINFO
+ {(int)KS_CAB, "\033|%p1%db", "\033|%p14%dm"}, // set background color
+ {(int)KS_CAF, "\033|%p1%df", "\033|%p13%dm"}, // set foreground color
+# else
+ {(int)KS_CAB, "\033|%db", "\033|4%dm"}, // set background color
+ {(int)KS_CAF, "\033|%df", "\033|3%dm"}, // set foreground color
+# endif
+ {(int)KS_CCO, "256", "256"}, // colors
+ {(int)KS_NAME} // terminator
+};
+
+ static struct builtin_term *
+find_first_tcap(
+ char_u *name,
+ int code)
+{
+ struct builtin_term *p;
+
+ for (p = find_builtin_term(name); p->bt_string != NULL; ++p)
+ if (p->bt_entry == code)
+ return p;
+ return NULL;
+}
+# endif
+
+/*
+ * For Win32 console: replace the sequence immediately after termguicolors.
+ */
+ void
+swap_tcap(void)
+{
+# ifdef FEAT_TERMGUICOLORS
+ static int init_done = FALSE;
+ static int curr_mode;
+ struct ks_tbl_s *ks;
+ struct builtin_term *bt;
+ int mode;
+ enum
+ {
+ CMODEINDEX,
+ CMODE24,
+ CMODE256
+ };
+
+ /* buffer initialization */
+ if (!init_done)
+ {
+ for (ks = ks_tbl; ks->code != (int)KS_NAME; ks++)
+ {
+ bt = find_first_tcap(DEFAULT_TERM, ks->code);
+ if (bt != NULL)
+ {
+ STRNCPY(ks->buf, bt->bt_string, KSSIZE);
+ STRNCPY(ks->vbuf, ks->vtp, KSSIZE);
+ STRNCPY(ks->v2buf, ks->vtp2, KSSIZE);
+
+ STRNCPY(ks->arr, bt->bt_string, KSSIZE);
+ bt->bt_string = &ks->arr[0];
+ }
+ }
+ init_done = TRUE;
+ curr_mode = CMODEINDEX;
+ }
+
+ if (p_tgc)
+ mode = CMODE24;
+ else if (t_colors >= 256)
+ mode = CMODE256;
+ else
+ mode = CMODEINDEX;
+
+ for (ks = ks_tbl; ks->code != (int)KS_NAME; ks++)
+ {
+ bt = find_first_tcap(DEFAULT_TERM, ks->code);
+ if (bt != NULL)
+ {
+ switch (curr_mode)
+ {
+ case CMODEINDEX:
+ STRNCPY(&ks->buf[0], bt->bt_string, KSSIZE);
+ break;
+ case CMODE24:
+ STRNCPY(&ks->vbuf[0], bt->bt_string, KSSIZE);
+ break;
+ default:
+ STRNCPY(&ks->v2buf[0], bt->bt_string, KSSIZE);
+ }
+ }
+ }
+
+ if (mode != curr_mode)
+ {
+ for (ks = ks_tbl; ks->code != (int)KS_NAME; ks++)
+ {
+ bt = find_first_tcap(DEFAULT_TERM, ks->code);
+ if (bt != NULL)
+ {
+ switch (mode)
+ {
+ case CMODEINDEX:
+ STRNCPY(bt->bt_string, &ks->buf[0], KSSIZE);
+ break;
+ case CMODE24:
+ STRNCPY(bt->bt_string, &ks->vbuf[0], KSSIZE);
+ break;
+ default:
+ STRNCPY(bt->bt_string, &ks->v2buf[0], KSSIZE);
+ }
+ }
+ }
+
+ curr_mode = mode;
+ }
+# endif
+}
+
+#endif
+
+#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS) || defined(PROTO)
+ static int
+hex_digit(int c)
+{
+ if (isdigit(c))
+ return c - '0';
+ c = TOLOWER_ASC(c);
+ if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ return 0x1ffffff;
+}
+
+ guicolor_T
+gui_get_color_cmn(char_u *name)
+{
+ /* On MS-Windows an RGB macro is available and it produces 0x00bbggrr color
+ * values as used by the MS-Windows GDI api. It should be used only for
+ * MS-Windows GDI builds. */
+# if defined(RGB) && defined(WIN32) && !defined(FEAT_GUI)
+# undef RGB
+# endif
+# ifndef RGB
+# define RGB(r, g, b) ((r<<16) | (g<<8) | (b))
+# endif
+# define LINE_LEN 100
+ FILE *fd;
+ char line[LINE_LEN];
+ char_u *fname;
+ int r, g, b, i;
+ guicolor_T color;
+
+ struct rgbcolor_table_S {
+ char_u *color_name;
+ guicolor_T color;
+ };
+
+ /* Only non X11 colors (not present in rgb.txt) and colors in
+ * color_names[], useful when $VIMRUNTIME is not found,. */
+ static struct rgbcolor_table_S rgb_table[] = {
+ {(char_u *)"black", RGB(0x00, 0x00, 0x00)},
+ {(char_u *)"blue", RGB(0x00, 0x00, 0xFF)},
+ {(char_u *)"brown", RGB(0xA5, 0x2A, 0x2A)},
+ {(char_u *)"cyan", RGB(0x00, 0xFF, 0xFF)},
+ {(char_u *)"darkblue", RGB(0x00, 0x00, 0x8B)},
+ {(char_u *)"darkcyan", RGB(0x00, 0x8B, 0x8B)},
+ {(char_u *)"darkgray", RGB(0xA9, 0xA9, 0xA9)},
+ {(char_u *)"darkgreen", RGB(0x00, 0x64, 0x00)},
+ {(char_u *)"darkgrey", RGB(0xA9, 0xA9, 0xA9)},
+ {(char_u *)"darkmagenta", RGB(0x8B, 0x00, 0x8B)},
+ {(char_u *)"darkred", RGB(0x8B, 0x00, 0x00)},
+ {(char_u *)"darkyellow", RGB(0x8B, 0x8B, 0x00)}, /* No X11 */
+ {(char_u *)"gray", RGB(0xBE, 0xBE, 0xBE)},
+ {(char_u *)"green", RGB(0x00, 0xFF, 0x00)},
+ {(char_u *)"grey", RGB(0xBE, 0xBE, 0xBE)},
+ {(char_u *)"grey40", RGB(0x66, 0x66, 0x66)},
+ {(char_u *)"grey50", RGB(0x7F, 0x7F, 0x7F)},
+ {(char_u *)"grey90", RGB(0xE5, 0xE5, 0xE5)},
+ {(char_u *)"lightblue", RGB(0xAD, 0xD8, 0xE6)},
+ {(char_u *)"lightcyan", RGB(0xE0, 0xFF, 0xFF)},
+ {(char_u *)"lightgray", RGB(0xD3, 0xD3, 0xD3)},
+ {(char_u *)"lightgreen", RGB(0x90, 0xEE, 0x90)},
+ {(char_u *)"lightgrey", RGB(0xD3, 0xD3, 0xD3)},
+ {(char_u *)"lightmagenta", RGB(0xFF, 0x8B, 0xFF)}, /* No X11 */
+ {(char_u *)"lightred", RGB(0xFF, 0x8B, 0x8B)}, /* No X11 */
+ {(char_u *)"lightyellow", RGB(0xFF, 0xFF, 0xE0)},
+ {(char_u *)"magenta", RGB(0xFF, 0x00, 0xFF)},
+ {(char_u *)"red", RGB(0xFF, 0x00, 0x00)},
+ {(char_u *)"seagreen", RGB(0x2E, 0x8B, 0x57)},
+ {(char_u *)"white", RGB(0xFF, 0xFF, 0xFF)},
+ {(char_u *)"yellow", RGB(0xFF, 0xFF, 0x00)},
+ };
+
+ static struct rgbcolor_table_S *colornames_table;
+ static int size = 0;
+
+ if (name[0] == '#' && STRLEN(name) == 7)
+ {
+ /* Name is in "#rrggbb" format */
+ color = RGB(((hex_digit(name[1]) << 4) + hex_digit(name[2])),
+ ((hex_digit(name[3]) << 4) + hex_digit(name[4])),
+ ((hex_digit(name[5]) << 4) + hex_digit(name[6])));
+ if (color > 0xffffff)
+ return INVALCOLOR;
+ return color;
+ }
+
+ /* Check if the name is one of the colors we know */
+ for (i = 0; i < (int)(sizeof(rgb_table) / sizeof(rgb_table[0])); i++)
+ if (STRICMP(name, rgb_table[i].color_name) == 0)
+ return rgb_table[i].color;
+
+ /*
+ * Last attempt. Look in the file "$VIM/rgb.txt".
+ */
+ if (size == 0)
+ {
+ int counting;
+
+ /* colornames_table not yet initialized */
+ fname = expand_env_save((char_u *)"$VIMRUNTIME/rgb.txt");
+ if (fname == NULL)
+ return INVALCOLOR;
+
+ fd = fopen((char *)fname, "rt");
+ vim_free(fname);
+ if (fd == NULL)
+ {
+ if (p_verbose > 1)
+ verb_msg(_("Cannot open $VIMRUNTIME/rgb.txt"));
+ return INVALCOLOR;
+ }
+
+ for (counting = 1; counting >= 0; --counting)
+ {
+ if (!counting)
+ {
+ colornames_table = (struct rgbcolor_table_S *)alloc(
+ (unsigned)(sizeof(struct rgbcolor_table_S) * size));
+ if (colornames_table == NULL)
+ {
+ fclose(fd);
+ return INVALCOLOR;
+ }
+ rewind(fd);
+ }
+ size = 0;
+
+ while (!feof(fd))
+ {
+ size_t len;
+ int pos;
+
+ vim_ignoredp = fgets(line, LINE_LEN, fd);
+ len = strlen(line);
+
+ if (len <= 1 || line[len - 1] != '\n')
+ continue;
+
+ line[len - 1] = '\0';
+
+ i = sscanf(line, "%d %d %d %n", &r, &g, &b, &pos);
+ if (i != 3)
+ continue;
+
+ if (!counting)
+ {
+ char_u *s = vim_strsave((char_u *)line + pos);
+
+ if (s == NULL)
+ {
+ fclose(fd);
+ return INVALCOLOR;
+ }
+ colornames_table[size].color_name = s;
+ colornames_table[size].color = (guicolor_T)RGB(r, g, b);
+ }
+ size++;
+ }
+ }
+ fclose(fd);
+ }
+
+ for (i = 0; i < size; i++)
+ if (STRICMP(name, colornames_table[i].color_name) == 0)
+ return colornames_table[i].color;
+
+ return INVALCOLOR;
+}
+
+ guicolor_T
+gui_get_rgb_color_cmn(int r, int g, int b)
+{
+ guicolor_T color = RGB(r, g, b);
+
+ if (color > 0xffffff)
+ return INVALCOLOR;
+ return color;
+}
+#endif
+
+#if (defined(WIN3264) && !defined(FEAT_GUI_W32)) || defined(FEAT_TERMINAL) \
+ || defined(PROTO)
+static int cube_value[] = {
+ 0x00, 0x5F, 0x87, 0xAF, 0xD7, 0xFF
+};
+
+static int grey_ramp[] = {
+ 0x08, 0x12, 0x1C, 0x26, 0x30, 0x3A, 0x44, 0x4E, 0x58, 0x62, 0x6C, 0x76,
+ 0x80, 0x8A, 0x94, 0x9E, 0xA8, 0xB2, 0xBC, 0xC6, 0xD0, 0xDA, 0xE4, 0xEE
+};
+
+# ifdef FEAT_TERMINAL
+# include "libvterm/include/vterm.h" // for VTERM_ANSI_INDEX_NONE
+# else
+# define VTERM_ANSI_INDEX_NONE 0
+# endif
+
+static char_u ansi_table[16][4] = {
+// R G B idx
+ { 0, 0, 0, 1}, // black
+ {224, 0, 0, 2}, // dark red
+ { 0, 224, 0, 3}, // dark green
+ {224, 224, 0, 4}, // dark yellow / brown
+ { 0, 0, 224, 5}, // dark blue
+ {224, 0, 224, 6}, // dark magenta
+ { 0, 224, 224, 7}, // dark cyan
+ {224, 224, 224, 8}, // light grey
+
+ {128, 128, 128, 9}, // dark grey
+ {255, 64, 64, 10}, // light red
+ { 64, 255, 64, 11}, // light green
+ {255, 255, 64, 12}, // yellow
+ { 64, 64, 255, 13}, // light blue
+ {255, 64, 255, 14}, // light magenta
+ { 64, 255, 255, 15}, // light cyan
+ {255, 255, 255, 16}, // white
+};
+
+ void
+cterm_color2rgb(int nr, char_u *r, char_u *g, char_u *b, char_u *ansi_idx)
+{
+ int idx;
+
+ if (nr < 16)
+ {
+ *r = ansi_table[nr][0];
+ *g = ansi_table[nr][1];
+ *b = ansi_table[nr][2];
+ *ansi_idx = ansi_table[nr][3];
+ }
+ else if (nr < 232)
+ {
+ /* 216 color cube */
+ idx = nr - 16;
+ *r = cube_value[idx / 36 % 6];
+ *g = cube_value[idx / 6 % 6];
+ *b = cube_value[idx % 6];
+ *ansi_idx = VTERM_ANSI_INDEX_NONE;
+ }
+ else if (nr < 256)
+ {
+ /* 24 grey scale ramp */
+ idx = nr - 232;
+ *r = grey_ramp[idx];
+ *g = grey_ramp[idx];
+ *b = grey_ramp[idx];
+ *ansi_idx = VTERM_ANSI_INDEX_NONE;
+ }
+ else
+ {
+ *r = 0;
+ *g = 0;
+ *b = 0;
+ *ansi_idx = 0;
+ }
+}
+#endif
diff --git a/src/term.h b/src/term.h
new file mode 100644
index 0000000..219a208
--- /dev/null
+++ b/src/term.h
@@ -0,0 +1,210 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * Do ":help uganda" in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ */
+
+/*
+ * This file contains the defines for the machine dependent escape sequences
+ * that the editor needs to perform various operations. All of the sequences
+ * here are optional, except "cm" (cursor motion).
+ */
+
+#if defined(SASC) && SASC < 658
+/*
+ * The SAS C compiler has a bug that makes typedefs being forgot in include
+ * files. Has been fixed in version 6.58.
+ */
+typedef unsigned char char_u;
+#endif
+
+/*
+ * Index of the termcap codes in the term_strings array.
+ */
+enum SpecialKey
+{
+ KS_NAME = 0,/* name of this terminal entry */
+ KS_CE, /* clear to end of line */
+ KS_AL, /* add new blank line */
+ KS_CAL, /* add number of blank lines */
+ KS_DL, /* delete line */
+ KS_CDL, /* delete number of lines */
+ KS_CS, /* scroll region */
+ KS_CL, /* clear screen */
+ KS_CD, /* clear to end of display */
+ KS_UT, /* clearing uses current background color */
+ KS_DA, /* text may be scrolled down from up */
+ KS_DB, /* text may be scrolled up from down */
+ KS_VI, /* cursor invisible */
+ KS_VE, /* cursor visible */
+ KS_VS, /* cursor very visible (blink) */
+ KS_CVS, /* cursor normally visible (no blink) */
+ KS_CSH, /* cursor shape */
+ KS_CRC, /* request cursor blinking */
+ KS_CRS, /* request cursor style */
+ KS_ME, /* normal mode */
+ KS_MR, /* reverse mode */
+ KS_MD, /* bold mode */
+ KS_SE, /* normal mode */
+ KS_SO, /* standout mode */
+ KS_CZH, /* italic mode start */
+ KS_CZR, /* italic mode end */
+ KS_UE, /* exit underscore (underline) mode */
+ KS_US, /* underscore (underline) mode */
+ KS_UCE, /* exit undercurl mode */
+ KS_UCS, /* undercurl mode */
+ KS_STE, /* exit strikethrough mode */
+ KS_STS, /* strikethrough mode */
+ KS_MS, /* save to move cur in reverse mode */
+ KS_CM, /* cursor motion */
+ KS_SR, /* scroll reverse (backward) */
+ KS_CRI, /* cursor number of chars right */
+ KS_VB, /* visual bell */
+ KS_KS, /* put term in "keypad transmit" mode */
+ KS_KE, /* out of "keypad transmit" mode */
+ KS_TI, /* put terminal in termcap mode */
+ KS_TE, /* out of termcap mode */
+ KS_BC, /* backspace character (cursor left) */
+ KS_CCS, /* cur is relative to scroll region */
+ KS_CCO, /* number of colors */
+ KS_CSF, /* set foreground color */
+ KS_CSB, /* set background color */
+ KS_XS, /* standout not erased by overwriting (hpterm) */
+ KS_XN, /* newline glitch */
+ KS_MB, /* blink mode */
+ KS_CAF, /* set foreground color (ANSI) */
+ KS_CAB, /* set background color (ANSI) */
+ KS_LE, /* cursor left (mostly backspace) */
+ KS_ND, /* cursor right */
+ KS_CIS, /* set icon text start */
+ KS_CIE, /* set icon text end */
+ KS_CSC, /* set cursor color start */
+ KS_CEC, /* set cursor color end */
+ KS_TS, /* set window title start (to status line)*/
+ KS_FS, /* set window title end (from status line) */
+ KS_CWP, /* set window position in pixels */
+ KS_CGP, /* get window position */
+ KS_CWS, /* set window size in characters */
+ KS_CRV, /* request version string */
+ KS_RFG, /* request foreground color */
+ KS_RBG, /* request background color */
+ KS_CSI, /* start insert mode (bar cursor) */
+ KS_CEI, /* end insert mode (block cursor) */
+ KS_CSR, /* start replace mode (underline cursor) */
+ KS_CSV, /* scroll region vertical */
+ KS_OP, /* original color pair */
+ KS_U7, /* request cursor position */
+ KS_8F, /* set foreground color (RGB) */
+ KS_8B, /* set background color (RGB) */
+ KS_CBE, /* enable bracketed paste mode */
+ KS_CBD, /* disable bracketed paste mode */
+ KS_CPS, /* start of bracketed paste */
+ KS_CPE, /* end of bracketed paste */
+ KS_CST, /* save window title */
+ KS_CRT, /* restore window title */
+ KS_SSI, /* save icon text */
+ KS_SRI /* restore icon text */
+};
+
+#define KS_LAST KS_SRI
+
+/*
+ * the terminal capabilities are stored in this array
+ * IMPORTANT: When making changes, note the following:
+ * - there should be an entry for each code in the builtin termcaps
+ * - there should be an option for each code in option.c
+ * - there should be code in term.c to obtain the value from the termcap
+ */
+
+extern char_u *(term_strings[]); /* current terminal strings */
+
+/*
+ * strings used for terminal
+ */
+#define T_NAME (TERM_STR(KS_NAME)) /* terminal name */
+#define T_CE (TERM_STR(KS_CE)) /* clear to end of line */
+#define T_AL (TERM_STR(KS_AL)) /* add new blank line */
+#define T_CAL (TERM_STR(KS_CAL)) /* add number of blank lines */
+#define T_DL (TERM_STR(KS_DL)) /* delete line */
+#define T_CDL (TERM_STR(KS_CDL)) /* delete number of lines */
+#define T_CS (TERM_STR(KS_CS)) /* scroll region */
+#define T_CSV (TERM_STR(KS_CSV)) /* scroll region vertical */
+#define T_CL (TERM_STR(KS_CL)) /* clear screen */
+#define T_CD (TERM_STR(KS_CD)) /* clear to end of display */
+#define T_UT (TERM_STR(KS_UT)) /* clearing uses background color */
+#define T_DA (TERM_STR(KS_DA)) /* text may be scrolled down from up */
+#define T_DB (TERM_STR(KS_DB)) /* text may be scrolled up from down */
+#define T_VI (TERM_STR(KS_VI)) /* cursor invisible */
+#define T_VE (TERM_STR(KS_VE)) /* cursor visible */
+#define T_VS (TERM_STR(KS_VS)) /* cursor very visible (blink) */
+#define T_CVS (TERM_STR(KS_CVS)) /* cursor normally visible (no blink) */
+#define T_CSH (TERM_STR(KS_CSH)) /* cursor shape */
+#define T_CRC (TERM_STR(KS_CRC)) /* request cursor blinking */
+#define T_CRS (TERM_STR(KS_CRS)) /* request cursor style */
+#define T_ME (TERM_STR(KS_ME)) /* normal mode */
+#define T_MR (TERM_STR(KS_MR)) /* reverse mode */
+#define T_MD (TERM_STR(KS_MD)) /* bold mode */
+#define T_SE (TERM_STR(KS_SE)) /* normal mode */
+#define T_SO (TERM_STR(KS_SO)) /* standout mode */
+#define T_CZH (TERM_STR(KS_CZH)) /* italic mode start */
+#define T_CZR (TERM_STR(KS_CZR)) /* italic mode end */
+#define T_UE (TERM_STR(KS_UE)) /* exit underscore (underline) mode */
+#define T_US (TERM_STR(KS_US)) /* underscore (underline) mode */
+#define T_UCE (TERM_STR(KS_UCE)) /* exit undercurl mode */
+#define T_UCS (TERM_STR(KS_UCS)) /* undercurl mode */
+#define T_STE (TERM_STR(KS_STE)) /* exit strikethrough mode */
+#define T_STS (TERM_STR(KS_STS)) /* strikethrough mode */
+#define T_MS (TERM_STR(KS_MS)) /* save to move cur in reverse mode */
+#define T_CM (TERM_STR(KS_CM)) /* cursor motion */
+#define T_SR (TERM_STR(KS_SR)) /* scroll reverse (backward) */
+#define T_CRI (TERM_STR(KS_CRI)) /* cursor number of chars right */
+#define T_VB (TERM_STR(KS_VB)) /* visual bell */
+#define T_KS (TERM_STR(KS_KS)) /* put term in "keypad transmit" mode */
+#define T_KE (TERM_STR(KS_KE)) /* out of "keypad transmit" mode */
+#define T_TI (TERM_STR(KS_TI)) /* put terminal in termcap mode */
+#define T_TE (TERM_STR(KS_TE)) /* out of termcap mode */
+#define T_BC (TERM_STR(KS_BC)) /* backspace character */
+#define T_CCS (TERM_STR(KS_CCS)) /* cur is relative to scroll region */
+#define T_CCO (TERM_STR(KS_CCO)) /* number of colors */
+#define T_CSF (TERM_STR(KS_CSF)) /* set foreground color */
+#define T_CSB (TERM_STR(KS_CSB)) /* set background color */
+#define T_XS (TERM_STR(KS_XS)) /* standout not erased by overwriting */
+#define T_XN (TERM_STR(KS_XN)) /* newline glitch */
+#define T_MB (TERM_STR(KS_MB)) /* blink mode */
+#define T_CAF (TERM_STR(KS_CAF)) /* set foreground color (ANSI) */
+#define T_CAB (TERM_STR(KS_CAB)) /* set background color (ANSI) */
+#define T_LE (TERM_STR(KS_LE)) /* cursor left */
+#define T_ND (TERM_STR(KS_ND)) /* cursor right */
+#define T_CIS (TERM_STR(KS_CIS)) /* set icon text start */
+#define T_CIE (TERM_STR(KS_CIE)) /* set icon text end */
+#define T_TS (TERM_STR(KS_TS)) /* set window title start */
+#define T_FS (TERM_STR(KS_FS)) /* set window title end */
+#define T_CSC (TERM_STR(KS_CSC)) /* set cursor color start */
+#define T_CEC (TERM_STR(KS_CEC)) /* set cursor color end */
+#define T_CWP (TERM_STR(KS_CWP)) /* set window position */
+#define T_CGP (TERM_STR(KS_CGP)) /* get window position */
+#define T_CWS (TERM_STR(KS_CWS)) /* window size */
+#define T_CSI (TERM_STR(KS_CSI)) /* start insert mode */
+#define T_CEI (TERM_STR(KS_CEI)) /* end insert mode */
+#define T_CSR (TERM_STR(KS_CSR)) /* start replace mode */
+#define T_CRV (TERM_STR(KS_CRV)) /* request version string */
+#define T_RFG (TERM_STR(KS_RFG)) /* request foreground RGB */
+#define T_RBG (TERM_STR(KS_RBG)) /* request background RGB */
+#define T_OP (TERM_STR(KS_OP)) /* original color pair */
+#define T_U7 (TERM_STR(KS_U7)) /* request cursor position */
+#define T_8F (TERM_STR(KS_8F)) /* set foreground color (RGB) */
+#define T_8B (TERM_STR(KS_8B)) /* set background color (RGB) */
+#define T_BE (TERM_STR(KS_CBE)) /* enable bracketed paste mode */
+#define T_BD (TERM_STR(KS_CBD)) /* disable bracketed paste mode */
+#define T_PS (TERM_STR(KS_CPS)) /* start of bracketed paste */
+#define T_PE (TERM_STR(KS_CPE)) /* end of bracketed paste */
+#define T_CST (TERM_STR(KS_CST)) /* save window title */
+#define T_CRT (TERM_STR(KS_CRT)) /* restore window title */
+#define T_SSI (TERM_STR(KS_SSI)) /* save icon text */
+#define T_SRI (TERM_STR(KS_SRI)) /* restore icon text */
+
+#define TMODE_COOK 0 /* terminal mode for external cmds and Ex mode */
+#define TMODE_SLEEP 1 /* terminal mode for sleeping (cooked but no echo) */
+#define TMODE_RAW 2 /* terminal mode for Normal and Insert mode */
diff --git a/src/terminal.c b/src/terminal.c
new file mode 100644
index 0000000..41cd5c9
--- /dev/null
+++ b/src/terminal.c
@@ -0,0 +1,6370 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * Terminal window support, see ":help :terminal".
+ *
+ * There are three parts:
+ * 1. Generic code for all systems.
+ * Uses libvterm for the terminal emulator.
+ * 2. The MS-Windows implementation.
+ * Uses winpty.
+ * 3. The Unix-like implementation.
+ * Uses pseudo-tty's (pty's).
+ *
+ * For each terminal one VTerm is constructed. This uses libvterm. A copy of
+ * this library is in the libvterm directory.
+ *
+ * When a terminal window is opened, a job is started that will be connected to
+ * the terminal emulator.
+ *
+ * If the terminal window has keyboard focus, typed keys are converted to the
+ * terminal encoding and writing to the job over a channel.
+ *
+ * If the job produces output, it is written to the terminal emulator. The
+ * terminal emulator invokes callbacks when its screen content changes. The
+ * line range is stored in tl_dirty_row_start and tl_dirty_row_end. Once in a
+ * while, if the terminal window is visible, the screen contents is drawn.
+ *
+ * When the job ends the text is put in a buffer. Redrawing then happens from
+ * that buffer, attributes come from the scrollback buffer tl_scrollback.
+ * When the buffer is changed it is turned into a normal buffer, the attributes
+ * in tl_scrollback are no longer used.
+ */
+
+#include "vim.h"
+
+#if defined(FEAT_TERMINAL) || defined(PROTO)
+
+#ifndef MIN
+# define MIN(x,y) ((x) < (y) ? (x) : (y))
+#endif
+#ifndef MAX
+# define MAX(x,y) ((x) > (y) ? (x) : (y))
+#endif
+
+#include "libvterm/include/vterm.h"
+
+/* This is VTermScreenCell without the characters, thus much smaller. */
+typedef struct {
+ VTermScreenCellAttrs attrs;
+ char width;
+ VTermColor fg;
+ VTermColor bg;
+} cellattr_T;
+
+typedef struct sb_line_S {
+ int sb_cols; /* can differ per line */
+ cellattr_T *sb_cells; /* allocated */
+ cellattr_T sb_fill_attr; /* for short line */
+} sb_line_T;
+
+#ifdef WIN3264
+# ifndef HPCON
+# define HPCON VOID*
+# endif
+# ifndef EXTENDED_STARTUPINFO_PRESENT
+# define EXTENDED_STARTUPINFO_PRESENT 0x00080000
+# endif
+# ifndef PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE
+# define PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE 0x00020016
+# endif
+typedef struct _DYN_STARTUPINFOEXW
+{
+ STARTUPINFOW StartupInfo;
+ LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList;
+} DYN_STARTUPINFOEXW, *PDYN_STARTUPINFOEXW;
+#endif
+
+/* typedef term_T in structs.h */
+struct terminal_S {
+ term_T *tl_next;
+
+ VTerm *tl_vterm;
+ job_T *tl_job;
+ buf_T *tl_buffer;
+#if defined(FEAT_GUI)
+ int tl_system; /* when non-zero used for :!cmd output */
+ int tl_toprow; /* row with first line of system terminal */
+#endif
+
+ /* Set when setting the size of a vterm, reset after redrawing. */
+ int tl_vterm_size_changed;
+
+ int tl_normal_mode; /* TRUE: Terminal-Normal mode */
+ int tl_channel_closed;
+ int tl_channel_recently_closed; // still need to handle tl_finish
+
+ int tl_finish;
+#define TL_FINISH_UNSET NUL
+#define TL_FINISH_CLOSE 'c' /* ++close or :terminal without argument */
+#define TL_FINISH_NOCLOSE 'n' /* ++noclose */
+#define TL_FINISH_OPEN 'o' /* ++open */
+ char_u *tl_opencmd;
+ char_u *tl_eof_chars;
+
+ char_u *tl_arg0_cmd; // To format the status bar
+
+#ifdef WIN3264
+ void *tl_winpty_config;
+ void *tl_winpty;
+
+ HPCON tl_conpty;
+ DYN_STARTUPINFOEXW tl_siex; // Structure that always needs to be hold
+
+ FILE *tl_out_fd;
+#endif
+#if defined(FEAT_SESSION)
+ char_u *tl_command;
+#endif
+ char_u *tl_kill;
+
+ /* last known vterm size */
+ int tl_rows;
+ int tl_cols;
+
+ char_u *tl_title; /* NULL or allocated */
+ char_u *tl_status_text; /* NULL or allocated */
+
+ /* Range of screen rows to update. Zero based. */
+ int tl_dirty_row_start; /* MAX_ROW if nothing dirty */
+ int tl_dirty_row_end; /* row below last one to update */
+ int tl_dirty_snapshot; /* text updated after making snapshot */
+#ifdef FEAT_TIMERS
+ int tl_timer_set;
+ proftime_T tl_timer_due;
+#endif
+ int tl_postponed_scroll; /* to be scrolled up */
+
+ garray_T tl_scrollback;
+ int tl_scrollback_scrolled;
+ cellattr_T tl_default_color;
+
+ linenr_T tl_top_diff_rows; /* rows of top diff file or zero */
+ linenr_T tl_bot_diff_rows; /* rows of bottom diff file */
+
+ VTermPos tl_cursor_pos;
+ int tl_cursor_visible;
+ int tl_cursor_blink;
+ int tl_cursor_shape; /* 1: block, 2: underline, 3: bar */
+ char_u *tl_cursor_color; /* NULL or allocated */
+
+ int tl_using_altscreen;
+};
+
+#define TMODE_ONCE 1 /* CTRL-\ CTRL-N used */
+#define TMODE_LOOP 2 /* CTRL-W N used */
+
+/*
+ * List of all active terminals.
+ */
+static term_T *first_term = NULL;
+
+/* Terminal active in terminal_loop(). */
+static term_T *in_terminal_loop = NULL;
+
+#ifdef WIN3264
+static BOOL has_winpty = FALSE;
+static BOOL has_conpty = FALSE;
+#endif
+
+#define MAX_ROW 999999 /* used for tl_dirty_row_end to update all rows */
+#define KEY_BUF_LEN 200
+
+/*
+ * Functions with separate implementation for MS-Windows and Unix-like systems.
+ */
+static int term_and_job_init(term_T *term, typval_T *argvar, char **argv, jobopt_T *opt, jobopt_T *orig_opt);
+static int create_pty_only(term_T *term, jobopt_T *opt);
+static void term_report_winsize(term_T *term, int rows, int cols);
+static void term_free_vterm(term_T *term);
+#ifdef FEAT_GUI
+static void update_system_term(term_T *term);
+#endif
+
+/* The character that we know (or assume) that the terminal expects for the
+ * backspace key. */
+static int term_backspace_char = BS;
+
+/* "Terminal" highlight group colors. */
+static int term_default_cterm_fg = -1;
+static int term_default_cterm_bg = -1;
+
+/* Store the last set and the desired cursor properties, so that we only update
+ * them when needed. Doing it unnecessary may result in flicker. */
+static char_u *last_set_cursor_color = NULL;
+static char_u *desired_cursor_color = NULL;
+static int last_set_cursor_shape = -1;
+static int desired_cursor_shape = -1;
+static int last_set_cursor_blink = -1;
+static int desired_cursor_blink = -1;
+
+
+/**************************************
+ * 1. Generic code for all systems.
+ */
+
+ static int
+cursor_color_equal(char_u *lhs_color, char_u *rhs_color)
+{
+ if (lhs_color != NULL && rhs_color != NULL)
+ return STRCMP(lhs_color, rhs_color) == 0;
+ return lhs_color == NULL && rhs_color == NULL;
+}
+
+ static void
+cursor_color_copy(char_u **to_color, char_u *from_color)
+{
+ // Avoid a free & alloc if the value is already right.
+ if (cursor_color_equal(*to_color, from_color))
+ return;
+ vim_free(*to_color);
+ *to_color = (from_color == NULL) ? NULL : vim_strsave(from_color);
+}
+
+ static char_u *
+cursor_color_get(char_u *color)
+{
+ return (color == NULL) ? (char_u *)"" : color;
+}
+
+
+/*
+ * Parse 'termwinsize' and set "rows" and "cols" for the terminal size in the
+ * current window.
+ * Sets "rows" and/or "cols" to zero when it should follow the window size.
+ * Return TRUE if the size is the minimum size: "24*80".
+ */
+ static int
+parse_termwinsize(win_T *wp, int *rows, int *cols)
+{
+ int minsize = FALSE;
+
+ *rows = 0;
+ *cols = 0;
+
+ if (*wp->w_p_tws != NUL)
+ {
+ char_u *p = vim_strchr(wp->w_p_tws, 'x');
+
+ /* Syntax of value was already checked when it's set. */
+ if (p == NULL)
+ {
+ minsize = TRUE;
+ p = vim_strchr(wp->w_p_tws, '*');
+ }
+ *rows = atoi((char *)wp->w_p_tws);
+ *cols = atoi((char *)p + 1);
+ }
+ return minsize;
+}
+
+/*
+ * Determine the terminal size from 'termwinsize' and the current window.
+ */
+ static void
+set_term_and_win_size(term_T *term)
+{
+#ifdef FEAT_GUI
+ if (term->tl_system)
+ {
+ /* Use the whole screen for the system command. However, it will start
+ * at the command line and scroll up as needed, using tl_toprow. */
+ term->tl_rows = Rows;
+ term->tl_cols = Columns;
+ return;
+ }
+#endif
+ if (parse_termwinsize(curwin, &term->tl_rows, &term->tl_cols))
+ {
+ if (term->tl_rows != 0)
+ term->tl_rows = MAX(term->tl_rows, curwin->w_height);
+ if (term->tl_cols != 0)
+ term->tl_cols = MAX(term->tl_cols, curwin->w_width);
+ }
+ if (term->tl_rows == 0)
+ term->tl_rows = curwin->w_height;
+ else
+ win_setheight_win(term->tl_rows, curwin);
+ if (term->tl_cols == 0)
+ term->tl_cols = curwin->w_width;
+ else
+ win_setwidth_win(term->tl_cols, curwin);
+}
+
+/*
+ * Initialize job options for a terminal job.
+ * Caller may overrule some of them.
+ */
+ void
+init_job_options(jobopt_T *opt)
+{
+ clear_job_options(opt);
+
+ opt->jo_mode = MODE_RAW;
+ opt->jo_out_mode = MODE_RAW;
+ opt->jo_err_mode = MODE_RAW;
+ opt->jo_set = JO_MODE | JO_OUT_MODE | JO_ERR_MODE;
+}
+
+/*
+ * Set job options mandatory for a terminal job.
+ */
+ static void
+setup_job_options(jobopt_T *opt, int rows, int cols)
+{
+#ifndef WIN3264
+ /* Win32: Redirecting the job output won't work, thus always connect stdout
+ * here. */
+ if (!(opt->jo_set & JO_OUT_IO))
+#endif
+ {
+ /* Connect stdout to the terminal. */
+ opt->jo_io[PART_OUT] = JIO_BUFFER;
+ opt->jo_io_buf[PART_OUT] = curbuf->b_fnum;
+ opt->jo_modifiable[PART_OUT] = 0;
+ opt->jo_set |= JO_OUT_IO + JO_OUT_BUF + JO_OUT_MODIFIABLE;
+ }
+
+#ifndef WIN3264
+ /* Win32: Redirecting the job output won't work, thus always connect stderr
+ * here. */
+ if (!(opt->jo_set & JO_ERR_IO))
+#endif
+ {
+ /* Connect stderr to the terminal. */
+ opt->jo_io[PART_ERR] = JIO_BUFFER;
+ opt->jo_io_buf[PART_ERR] = curbuf->b_fnum;
+ opt->jo_modifiable[PART_ERR] = 0;
+ opt->jo_set |= JO_ERR_IO + JO_ERR_BUF + JO_ERR_MODIFIABLE;
+ }
+
+ opt->jo_pty = TRUE;
+ if ((opt->jo_set2 & JO2_TERM_ROWS) == 0)
+ opt->jo_term_rows = rows;
+ if ((opt->jo_set2 & JO2_TERM_COLS) == 0)
+ opt->jo_term_cols = cols;
+}
+
+/*
+ * Close a terminal buffer (and its window). Used when creating the terminal
+ * fails.
+ */
+ static void
+term_close_buffer(buf_T *buf, buf_T *old_curbuf)
+{
+ free_terminal(buf);
+ if (old_curbuf != NULL)
+ {
+ --curbuf->b_nwindows;
+ curbuf = old_curbuf;
+ curwin->w_buffer = curbuf;
+ ++curbuf->b_nwindows;
+ }
+
+ /* Wiping out the buffer will also close the window and call
+ * free_terminal(). */
+ do_buffer(DOBUF_WIPE, DOBUF_FIRST, FORWARD, buf->b_fnum, TRUE);
+}
+
+/*
+ * Start a terminal window and return its buffer.
+ * Use either "argvar" or "argv", the other must be NULL.
+ * When "flags" has TERM_START_NOJOB only create the buffer, b_term and open
+ * the window.
+ * Returns NULL when failed.
+ */
+ buf_T *
+term_start(
+ typval_T *argvar,
+ char **argv,
+ jobopt_T *opt,
+ int flags)
+{
+ exarg_T split_ea;
+ win_T *old_curwin = curwin;
+ term_T *term;
+ buf_T *old_curbuf = NULL;
+ int res;
+ buf_T *newbuf;
+ int vertical = opt->jo_vertical || (cmdmod.split & WSP_VERT);
+ jobopt_T orig_opt; // only partly filled
+
+ if (check_restricted() || check_secure())
+ return NULL;
+
+ if ((opt->jo_set & (JO_IN_IO + JO_OUT_IO + JO_ERR_IO))
+ == (JO_IN_IO + JO_OUT_IO + JO_ERR_IO)
+ || (!(opt->jo_set & JO_OUT_IO) && (opt->jo_set & JO_OUT_BUF))
+ || (!(opt->jo_set & JO_ERR_IO) && (opt->jo_set & JO_ERR_BUF)))
+ {
+ emsg(_(e_invarg));
+ return NULL;
+ }
+
+ term = (term_T *)alloc_clear(sizeof(term_T));
+ if (term == NULL)
+ return NULL;
+ term->tl_dirty_row_end = MAX_ROW;
+ term->tl_cursor_visible = TRUE;
+ term->tl_cursor_shape = VTERM_PROP_CURSORSHAPE_BLOCK;
+ term->tl_finish = opt->jo_term_finish;
+#ifdef FEAT_GUI
+ term->tl_system = (flags & TERM_START_SYSTEM);
+#endif
+ ga_init2(&term->tl_scrollback, sizeof(sb_line_T), 300);
+
+ vim_memset(&split_ea, 0, sizeof(split_ea));
+ if (opt->jo_curwin)
+ {
+ /* Create a new buffer in the current window. */
+ if (!can_abandon(curbuf, flags & TERM_START_FORCEIT))
+ {
+ no_write_message();
+ vim_free(term);
+ return NULL;
+ }
+ if (do_ecmd(0, NULL, NULL, &split_ea, ECMD_ONE,
+ ECMD_HIDE
+ + ((flags & TERM_START_FORCEIT) ? ECMD_FORCEIT : 0),
+ curwin) == FAIL)
+ {
+ vim_free(term);
+ return NULL;
+ }
+ }
+ else if (opt->jo_hidden || (flags & TERM_START_SYSTEM))
+ {
+ buf_T *buf;
+
+ /* Create a new buffer without a window. Make it the current buffer for
+ * a moment to be able to do the initialisations. */
+ buf = buflist_new((char_u *)"", NULL, (linenr_T)0,
+ BLN_NEW | BLN_LISTED);
+ if (buf == NULL || ml_open(buf) == FAIL)
+ {
+ vim_free(term);
+ return NULL;
+ }
+ old_curbuf = curbuf;
+ --curbuf->b_nwindows;
+ curbuf = buf;
+ curwin->w_buffer = buf;
+ ++curbuf->b_nwindows;
+ }
+ else
+ {
+ /* Open a new window or tab. */
+ split_ea.cmdidx = CMD_new;
+ split_ea.cmd = (char_u *)"new";
+ split_ea.arg = (char_u *)"";
+ if (opt->jo_term_rows > 0 && !vertical)
+ {
+ split_ea.line2 = opt->jo_term_rows;
+ split_ea.addr_count = 1;
+ }
+ if (opt->jo_term_cols > 0 && vertical)
+ {
+ split_ea.line2 = opt->jo_term_cols;
+ split_ea.addr_count = 1;
+ }
+
+ if (vertical)
+ cmdmod.split |= WSP_VERT;
+ ex_splitview(&split_ea);
+ if (curwin == old_curwin)
+ {
+ /* split failed */
+ vim_free(term);
+ return NULL;
+ }
+ }
+ term->tl_buffer = curbuf;
+ curbuf->b_term = term;
+
+ if (!opt->jo_hidden)
+ {
+ /* Only one size was taken care of with :new, do the other one. With
+ * "curwin" both need to be done. */
+ if (opt->jo_term_rows > 0 && (opt->jo_curwin || vertical))
+ win_setheight(opt->jo_term_rows);
+ if (opt->jo_term_cols > 0 && (opt->jo_curwin || !vertical))
+ win_setwidth(opt->jo_term_cols);
+ }
+
+ /* Link the new terminal in the list of active terminals. */
+ term->tl_next = first_term;
+ first_term = term;
+
+ if (opt->jo_term_name != NULL)
+ curbuf->b_ffname = vim_strsave(opt->jo_term_name);
+ else if (argv != NULL)
+ curbuf->b_ffname = vim_strsave((char_u *)"!system");
+ else
+ {
+ int i;
+ size_t len;
+ char_u *cmd, *p;
+
+ if (argvar->v_type == VAR_STRING)
+ {
+ cmd = argvar->vval.v_string;
+ if (cmd == NULL)
+ cmd = (char_u *)"";
+ else if (STRCMP(cmd, "NONE") == 0)
+ cmd = (char_u *)"pty";
+ }
+ else if (argvar->v_type != VAR_LIST
+ || argvar->vval.v_list == NULL
+ || argvar->vval.v_list->lv_len < 1
+ || (cmd = tv_get_string_chk(
+ &argvar->vval.v_list->lv_first->li_tv)) == NULL)
+ cmd = (char_u*)"";
+
+ len = STRLEN(cmd) + 10;
+ p = alloc((int)len);
+
+ for (i = 0; p != NULL; ++i)
+ {
+ /* Prepend a ! to the command name to avoid the buffer name equals
+ * the executable, otherwise ":w!" would overwrite it. */
+ if (i == 0)
+ vim_snprintf((char *)p, len, "!%s", cmd);
+ else
+ vim_snprintf((char *)p, len, "!%s (%d)", cmd, i);
+ if (buflist_findname(p) == NULL)
+ {
+ vim_free(curbuf->b_ffname);
+ curbuf->b_ffname = p;
+ break;
+ }
+ }
+ }
+ curbuf->b_fname = curbuf->b_ffname;
+
+ if (opt->jo_term_opencmd != NULL)
+ term->tl_opencmd = vim_strsave(opt->jo_term_opencmd);
+
+ if (opt->jo_eof_chars != NULL)
+ term->tl_eof_chars = vim_strsave(opt->jo_eof_chars);
+
+ set_string_option_direct((char_u *)"buftype", -1,
+ (char_u *)"terminal", OPT_FREE|OPT_LOCAL, 0);
+ // Avoid that 'buftype' is reset when this buffer is entered.
+ curbuf->b_p_initialized = TRUE;
+
+ /* Mark the buffer as not modifiable. It can only be made modifiable after
+ * the job finished. */
+ curbuf->b_p_ma = FALSE;
+
+ set_term_and_win_size(term);
+#ifdef WIN3264
+ mch_memmove(orig_opt.jo_io, opt->jo_io, sizeof(orig_opt.jo_io));
+#endif
+ setup_job_options(opt, term->tl_rows, term->tl_cols);
+
+ if (flags & TERM_START_NOJOB)
+ return curbuf;
+
+#if defined(FEAT_SESSION)
+ /* Remember the command for the session file. */
+ if (opt->jo_term_norestore || argv != NULL)
+ {
+ term->tl_command = vim_strsave((char_u *)"NONE");
+ }
+ else if (argvar->v_type == VAR_STRING)
+ {
+ char_u *cmd = argvar->vval.v_string;
+
+ if (cmd != NULL && STRCMP(cmd, p_sh) != 0)
+ term->tl_command = vim_strsave(cmd);
+ }
+ else if (argvar->v_type == VAR_LIST
+ && argvar->vval.v_list != NULL
+ && argvar->vval.v_list->lv_len > 0)
+ {
+ garray_T ga;
+ listitem_T *item;
+
+ ga_init2(&ga, 1, 100);
+ for (item = argvar->vval.v_list->lv_first;
+ item != NULL; item = item->li_next)
+ {
+ char_u *s = tv_get_string_chk(&item->li_tv);
+ char_u *p;
+
+ if (s == NULL)
+ break;
+ p = vim_strsave_fnameescape(s, FALSE);
+ if (p == NULL)
+ break;
+ ga_concat(&ga, p);
+ vim_free(p);
+ ga_append(&ga, ' ');
+ }
+ if (item == NULL)
+ {
+ ga_append(&ga, NUL);
+ term->tl_command = ga.ga_data;
+ }
+ else
+ ga_clear(&ga);
+ }
+#endif
+
+ if (opt->jo_term_kill != NULL)
+ {
+ char_u *p = skiptowhite(opt->jo_term_kill);
+
+ term->tl_kill = vim_strnsave(opt->jo_term_kill, p - opt->jo_term_kill);
+ }
+
+ /* System dependent: setup the vterm and maybe start the job in it. */
+ if (argv == NULL
+ && argvar->v_type == VAR_STRING
+ && argvar->vval.v_string != NULL
+ && STRCMP(argvar->vval.v_string, "NONE") == 0)
+ res = create_pty_only(term, opt);
+ else
+ res = term_and_job_init(term, argvar, argv, opt, &orig_opt);
+
+ newbuf = curbuf;
+ if (res == OK)
+ {
+ /* Get and remember the size we ended up with. Update the pty. */
+ vterm_get_size(term->tl_vterm, &term->tl_rows, &term->tl_cols);
+ term_report_winsize(term, term->tl_rows, term->tl_cols);
+#ifdef FEAT_GUI
+ if (term->tl_system)
+ {
+ /* display first line below typed command */
+ term->tl_toprow = msg_row + 1;
+ term->tl_dirty_row_end = 0;
+ }
+#endif
+
+ /* Make sure we don't get stuck on sending keys to the job, it leads to
+ * a deadlock if the job is waiting for Vim to read. */
+ channel_set_nonblock(term->tl_job->jv_channel, PART_IN);
+
+ if (old_curbuf != NULL)
+ {
+ --curbuf->b_nwindows;
+ curbuf = old_curbuf;
+ curwin->w_buffer = curbuf;
+ ++curbuf->b_nwindows;
+ }
+ }
+ else
+ {
+ term_close_buffer(curbuf, old_curbuf);
+ return NULL;
+ }
+
+ apply_autocmds(EVENT_TERMINALOPEN, NULL, NULL, FALSE, newbuf);
+ return newbuf;
+}
+
+/*
+ * ":terminal": open a terminal window and execute a job in it.
+ */
+ void
+ex_terminal(exarg_T *eap)
+{
+ typval_T argvar[2];
+ jobopt_T opt;
+ char_u *cmd;
+ char_u *tofree = NULL;
+
+ init_job_options(&opt);
+
+ cmd = eap->arg;
+ while (*cmd == '+' && *(cmd + 1) == '+')
+ {
+ char_u *p, *ep;
+
+ cmd += 2;
+ p = skiptowhite(cmd);
+ ep = vim_strchr(cmd, '=');
+ if (ep != NULL && ep < p)
+ p = ep;
+
+ if ((int)(p - cmd) == 5 && STRNICMP(cmd, "close", 5) == 0)
+ opt.jo_term_finish = 'c';
+ else if ((int)(p - cmd) == 7 && STRNICMP(cmd, "noclose", 7) == 0)
+ opt.jo_term_finish = 'n';
+ else if ((int)(p - cmd) == 4 && STRNICMP(cmd, "open", 4) == 0)
+ opt.jo_term_finish = 'o';
+ else if ((int)(p - cmd) == 6 && STRNICMP(cmd, "curwin", 6) == 0)
+ opt.jo_curwin = 1;
+ else if ((int)(p - cmd) == 6 && STRNICMP(cmd, "hidden", 6) == 0)
+ opt.jo_hidden = 1;
+ else if ((int)(p - cmd) == 9 && STRNICMP(cmd, "norestore", 9) == 0)
+ opt.jo_term_norestore = 1;
+ else if ((int)(p - cmd) == 4 && STRNICMP(cmd, "kill", 4) == 0
+ && ep != NULL)
+ {
+ opt.jo_set2 |= JO2_TERM_KILL;
+ opt.jo_term_kill = ep + 1;
+ p = skiptowhite(cmd);
+ }
+ else if ((int)(p - cmd) == 4 && STRNICMP(cmd, "rows", 4) == 0
+ && ep != NULL && isdigit(ep[1]))
+ {
+ opt.jo_set2 |= JO2_TERM_ROWS;
+ opt.jo_term_rows = atoi((char *)ep + 1);
+ p = skiptowhite(cmd);
+ }
+ else if ((int)(p - cmd) == 4 && STRNICMP(cmd, "cols", 4) == 0
+ && ep != NULL && isdigit(ep[1]))
+ {
+ opt.jo_set2 |= JO2_TERM_COLS;
+ opt.jo_term_cols = atoi((char *)ep + 1);
+ p = skiptowhite(cmd);
+ }
+ else if ((int)(p - cmd) == 3 && STRNICMP(cmd, "eof", 3) == 0
+ && ep != NULL)
+ {
+ char_u *buf = NULL;
+ char_u *keys;
+
+ p = skiptowhite(cmd);
+ *p = NUL;
+ keys = replace_termcodes(ep + 1, &buf, TRUE, TRUE, TRUE);
+ opt.jo_set2 |= JO2_EOF_CHARS;
+ opt.jo_eof_chars = vim_strsave(keys);
+ vim_free(buf);
+ *p = ' ';
+ }
+ else if ((int)(p - cmd) == 6 && STRNICMP(cmd, "winpty", 6) == 0)
+ {
+ opt.jo_set2 |= JO2_TERM_MODE;
+ opt.jo_term_mode = 'w';
+ }
+ else if ((int)(p - cmd) == 6 && STRNICMP(cmd, "conpty", 6) == 0)
+ {
+ opt.jo_set2 |= JO2_TERM_MODE;
+ opt.jo_term_mode = 'c';
+ }
+ else
+ {
+ if (*p)
+ *p = NUL;
+ semsg(_("E181: Invalid attribute: %s"), cmd);
+ goto theend;
+ }
+ cmd = skipwhite(p);
+ }
+ if (*cmd == NUL)
+ {
+ /* Make a copy of 'shell', an autocommand may change the option. */
+ tofree = cmd = vim_strsave(p_sh);
+
+ /* default to close when the shell exits */
+ if (opt.jo_term_finish == NUL)
+ opt.jo_term_finish = 'c';
+ }
+
+ if (eap->addr_count > 0)
+ {
+ /* Write lines from current buffer to the job. */
+ opt.jo_set |= JO_IN_IO | JO_IN_BUF | JO_IN_TOP | JO_IN_BOT;
+ opt.jo_io[PART_IN] = JIO_BUFFER;
+ opt.jo_io_buf[PART_IN] = curbuf->b_fnum;
+ opt.jo_in_top = eap->line1;
+ opt.jo_in_bot = eap->line2;
+ }
+
+ argvar[0].v_type = VAR_STRING;
+ argvar[0].vval.v_string = cmd;
+ argvar[1].v_type = VAR_UNKNOWN;
+ term_start(argvar, NULL, &opt, eap->forceit ? TERM_START_FORCEIT : 0);
+ vim_free(tofree);
+
+theend:
+ vim_free(opt.jo_eof_chars);
+}
+
+#if defined(FEAT_SESSION) || defined(PROTO)
+/*
+ * Write a :terminal command to the session file to restore the terminal in
+ * window "wp".
+ * Return FAIL if writing fails.
+ */
+ int
+term_write_session(FILE *fd, win_T *wp)
+{
+ term_T *term = wp->w_buffer->b_term;
+
+ /* Create the terminal and run the command. This is not without
+ * risk, but let's assume the user only creates a session when this
+ * will be OK. */
+ if (fprintf(fd, "terminal ++curwin ++cols=%d ++rows=%d ",
+ term->tl_cols, term->tl_rows) < 0)
+ return FAIL;
+#ifdef WIN3264
+ if (*wp->w_p_tmod != NUL)
+ if (fprintf(fd, "++%s ", wp->w_p_tmod) < 0)
+ return FAIL;
+#endif
+ if (term->tl_command != NULL && fputs((char *)term->tl_command, fd) < 0)
+ return FAIL;
+
+ return put_eol(fd);
+}
+
+/*
+ * Return TRUE if "buf" has a terminal that should be restored.
+ */
+ int
+term_should_restore(buf_T *buf)
+{
+ term_T *term = buf->b_term;
+
+ return term != NULL && (term->tl_command == NULL
+ || STRCMP(term->tl_command, "NONE") != 0);
+}
+#endif
+
+/*
+ * Free the scrollback buffer for "term".
+ */
+ static void
+free_scrollback(term_T *term)
+{
+ int i;
+
+ for (i = 0; i < term->tl_scrollback.ga_len; ++i)
+ vim_free(((sb_line_T *)term->tl_scrollback.ga_data + i)->sb_cells);
+ ga_clear(&term->tl_scrollback);
+}
+
+
+// Terminals that need to be freed soon.
+term_T *terminals_to_free = NULL;
+
+/*
+ * Free a terminal and everything it refers to.
+ * Kills the job if there is one.
+ * Called when wiping out a buffer.
+ * The actual terminal structure is freed later in free_unused_terminals(),
+ * because callbacks may wipe out a buffer while the terminal is still
+ * referenced.
+ */
+ void
+free_terminal(buf_T *buf)
+{
+ term_T *term = buf->b_term;
+ term_T *tp;
+
+ if (term == NULL)
+ return;
+
+ // Unlink the terminal form the list of terminals.
+ if (first_term == term)
+ first_term = term->tl_next;
+ else
+ for (tp = first_term; tp->tl_next != NULL; tp = tp->tl_next)
+ if (tp->tl_next == term)
+ {
+ tp->tl_next = term->tl_next;
+ break;
+ }
+
+ if (term->tl_job != NULL)
+ {
+ if (term->tl_job->jv_status != JOB_ENDED
+ && term->tl_job->jv_status != JOB_FINISHED
+ && term->tl_job->jv_status != JOB_FAILED)
+ job_stop(term->tl_job, NULL, "kill");
+ job_unref(term->tl_job);
+ }
+ term->tl_next = terminals_to_free;
+ terminals_to_free = term;
+
+ buf->b_term = NULL;
+ if (in_terminal_loop == term)
+ in_terminal_loop = NULL;
+}
+
+ void
+free_unused_terminals()
+{
+ while (terminals_to_free != NULL)
+ {
+ term_T *term = terminals_to_free;
+
+ terminals_to_free = term->tl_next;
+
+ free_scrollback(term);
+
+ term_free_vterm(term);
+ vim_free(term->tl_title);
+#ifdef FEAT_SESSION
+ vim_free(term->tl_command);
+#endif
+ vim_free(term->tl_kill);
+ vim_free(term->tl_status_text);
+ vim_free(term->tl_opencmd);
+ vim_free(term->tl_eof_chars);
+ vim_free(term->tl_arg0_cmd);
+#ifdef WIN3264
+ if (term->tl_out_fd != NULL)
+ fclose(term->tl_out_fd);
+#endif
+ vim_free(term->tl_cursor_color);
+ vim_free(term);
+ }
+}
+
+/*
+ * Get the part that is connected to the tty. Normally this is PART_IN, but
+ * when writing buffer lines to the job it can be another. This makes it
+ * possible to do "1,5term vim -".
+ */
+ static ch_part_T
+get_tty_part(term_T *term)
+{
+#ifdef UNIX
+ ch_part_T parts[3] = {PART_IN, PART_OUT, PART_ERR};
+ int i;
+
+ for (i = 0; i < 3; ++i)
+ {
+ int fd = term->tl_job->jv_channel->ch_part[parts[i]].ch_fd;
+
+ if (mch_isatty(fd))
+ return parts[i];
+ }
+#endif
+ return PART_IN;
+}
+
+/*
+ * Write job output "msg[len]" to the vterm.
+ */
+ static void
+term_write_job_output(term_T *term, char_u *msg, size_t len)
+{
+ VTerm *vterm = term->tl_vterm;
+ size_t prevlen = vterm_output_get_buffer_current(vterm);
+
+ vterm_input_write(vterm, (char *)msg, len);
+
+ /* flush vterm buffer when vterm responded to control sequence */
+ if (prevlen != vterm_output_get_buffer_current(vterm))
+ {
+ char buf[KEY_BUF_LEN];
+ size_t curlen = vterm_output_read(vterm, buf, KEY_BUF_LEN);
+
+ if (curlen > 0)
+ channel_send(term->tl_job->jv_channel, get_tty_part(term),
+ (char_u *)buf, (int)curlen, NULL);
+ }
+
+ /* this invokes the damage callbacks */
+ vterm_screen_flush_damage(vterm_obtain_screen(vterm));
+}
+
+ static void
+update_cursor(term_T *term, int redraw)
+{
+ if (term->tl_normal_mode)
+ return;
+#ifdef FEAT_GUI
+ if (term->tl_system)
+ windgoto(term->tl_cursor_pos.row + term->tl_toprow,
+ term->tl_cursor_pos.col);
+ else
+#endif
+ setcursor();
+ if (redraw)
+ {
+ if (term->tl_buffer == curbuf && term->tl_cursor_visible)
+ cursor_on();
+ out_flush();
+#ifdef FEAT_GUI
+ if (gui.in_use)
+ {
+ gui_update_cursor(FALSE, FALSE);
+ gui_mch_flush();
+ }
+#endif
+ }
+}
+
+/*
+ * Invoked when "msg" output from a job was received. Write it to the terminal
+ * of "buffer".
+ */
+ void
+write_to_term(buf_T *buffer, char_u *msg, channel_T *channel)
+{
+ size_t len = STRLEN(msg);
+ term_T *term = buffer->b_term;
+
+#ifdef WIN3264
+ /* Win32: Cannot redirect output of the job, intercept it here and write to
+ * the file. */
+ if (term->tl_out_fd != NULL)
+ {
+ ch_log(channel, "Writing %d bytes to output file", (int)len);
+ fwrite(msg, len, 1, term->tl_out_fd);
+ return;
+ }
+#endif
+
+ if (term->tl_vterm == NULL)
+ {
+ ch_log(channel, "NOT writing %d bytes to terminal", (int)len);
+ return;
+ }
+ ch_log(channel, "writing %d bytes to terminal", (int)len);
+ term_write_job_output(term, msg, len);
+
+#ifdef FEAT_GUI
+ if (term->tl_system)
+ {
+ /* show system output, scrolling up the screen as needed */
+ update_system_term(term);
+ update_cursor(term, TRUE);
+ }
+ else
+#endif
+ /* In Terminal-Normal mode we are displaying the buffer, not the terminal
+ * contents, thus no screen update is needed. */
+ if (!term->tl_normal_mode)
+ {
+ // Don't use update_screen() when editing the command line, it gets
+ // cleared.
+ // TODO: only update once in a while.
+ ch_log(term->tl_job->jv_channel, "updating screen");
+ if (buffer == curbuf && (State & CMDLINE) == 0)
+ {
+ update_screen(VALID_NO_UPDATE);
+ /* update_screen() can be slow, check the terminal wasn't closed
+ * already */
+ if (buffer == curbuf && curbuf->b_term != NULL)
+ update_cursor(curbuf->b_term, TRUE);
+ }
+ else
+ redraw_after_callback(TRUE);
+ }
+}
+
+/*
+ * Send a mouse position and click to the vterm
+ */
+ static int
+term_send_mouse(VTerm *vterm, int button, int pressed)
+{
+ VTermModifier mod = VTERM_MOD_NONE;
+
+ vterm_mouse_move(vterm, mouse_row - W_WINROW(curwin),
+ mouse_col - curwin->w_wincol, mod);
+ if (button != 0)
+ vterm_mouse_button(vterm, button, pressed, mod);
+ return TRUE;
+}
+
+static int enter_mouse_col = -1;
+static int enter_mouse_row = -1;
+
+/*
+ * Handle a mouse click, drag or release.
+ * Return TRUE when a mouse event is sent to the terminal.
+ */
+ static int
+term_mouse_click(VTerm *vterm, int key)
+{
+#if defined(FEAT_CLIPBOARD)
+ /* For modeless selection mouse drag and release events are ignored, unless
+ * they are preceded with a mouse down event */
+ static int ignore_drag_release = TRUE;
+ VTermMouseState mouse_state;
+
+ vterm_state_get_mousestate(vterm_obtain_state(vterm), &mouse_state);
+ if (mouse_state.flags == 0)
+ {
+ /* Terminal is not using the mouse, use modeless selection. */
+ switch (key)
+ {
+ case K_LEFTDRAG:
+ case K_LEFTRELEASE:
+ case K_RIGHTDRAG:
+ case K_RIGHTRELEASE:
+ /* Ignore drag and release events when the button-down wasn't
+ * seen before. */
+ if (ignore_drag_release)
+ {
+ int save_mouse_col, save_mouse_row;
+
+ if (enter_mouse_col < 0)
+ break;
+
+ /* mouse click in the window gave us focus, handle that
+ * click now */
+ save_mouse_col = mouse_col;
+ save_mouse_row = mouse_row;
+ mouse_col = enter_mouse_col;
+ mouse_row = enter_mouse_row;
+ clip_modeless(MOUSE_LEFT, TRUE, FALSE);
+ mouse_col = save_mouse_col;
+ mouse_row = save_mouse_row;
+ }
+ /* FALLTHROUGH */
+ case K_LEFTMOUSE:
+ case K_RIGHTMOUSE:
+ if (key == K_LEFTRELEASE || key == K_RIGHTRELEASE)
+ ignore_drag_release = TRUE;
+ else
+ ignore_drag_release = FALSE;
+ /* Should we call mouse_has() here? */
+ if (clip_star.available)
+ {
+ int button, is_click, is_drag;
+
+ button = get_mouse_button(KEY2TERMCAP1(key),
+ &is_click, &is_drag);
+ if (mouse_model_popup() && button == MOUSE_LEFT
+ && (mod_mask & MOD_MASK_SHIFT))
+ {
+ /* Translate shift-left to right button. */
+ button = MOUSE_RIGHT;
+ mod_mask &= ~MOD_MASK_SHIFT;
+ }
+ clip_modeless(button, is_click, is_drag);
+ }
+ break;
+
+ case K_MIDDLEMOUSE:
+ if (clip_star.available)
+ insert_reg('*', TRUE);
+ break;
+ }
+ enter_mouse_col = -1;
+ return FALSE;
+ }
+#endif
+ enter_mouse_col = -1;
+
+ switch (key)
+ {
+ case K_LEFTMOUSE:
+ case K_LEFTMOUSE_NM: term_send_mouse(vterm, 1, 1); break;
+ case K_LEFTDRAG: term_send_mouse(vterm, 1, 1); break;
+ case K_LEFTRELEASE:
+ case K_LEFTRELEASE_NM: term_send_mouse(vterm, 1, 0); break;
+ case K_MOUSEMOVE: term_send_mouse(vterm, 0, 0); break;
+ case K_MIDDLEMOUSE: term_send_mouse(vterm, 2, 1); break;
+ case K_MIDDLEDRAG: term_send_mouse(vterm, 2, 1); break;
+ case K_MIDDLERELEASE: term_send_mouse(vterm, 2, 0); break;
+ case K_RIGHTMOUSE: term_send_mouse(vterm, 3, 1); break;
+ case K_RIGHTDRAG: term_send_mouse(vterm, 3, 1); break;
+ case K_RIGHTRELEASE: term_send_mouse(vterm, 3, 0); break;
+ }
+ return TRUE;
+}
+
+/*
+ * Convert typed key "c" into bytes to send to the job.
+ * Return the number of bytes in "buf".
+ */
+ static int
+term_convert_key(term_T *term, int c, char *buf)
+{
+ VTerm *vterm = term->tl_vterm;
+ VTermKey key = VTERM_KEY_NONE;
+ VTermModifier mod = VTERM_MOD_NONE;
+ int other = FALSE;
+
+ switch (c)
+ {
+ /* don't use VTERM_KEY_ENTER, it may do an unwanted conversion */
+
+ /* don't use VTERM_KEY_BACKSPACE, it always
+ * becomes 0x7f DEL */
+ case K_BS: c = term_backspace_char; break;
+
+ case ESC: key = VTERM_KEY_ESCAPE; break;
+ case K_DEL: key = VTERM_KEY_DEL; break;
+ case K_DOWN: key = VTERM_KEY_DOWN; break;
+ case K_S_DOWN: mod = VTERM_MOD_SHIFT;
+ key = VTERM_KEY_DOWN; break;
+ case K_END: key = VTERM_KEY_END; break;
+ case K_S_END: mod = VTERM_MOD_SHIFT;
+ key = VTERM_KEY_END; break;
+ case K_C_END: mod = VTERM_MOD_CTRL;
+ key = VTERM_KEY_END; break;
+ case K_F10: key = VTERM_KEY_FUNCTION(10); break;
+ case K_F11: key = VTERM_KEY_FUNCTION(11); break;
+ case K_F12: key = VTERM_KEY_FUNCTION(12); break;
+ case K_F1: key = VTERM_KEY_FUNCTION(1); break;
+ case K_F2: key = VTERM_KEY_FUNCTION(2); break;
+ case K_F3: key = VTERM_KEY_FUNCTION(3); break;
+ case K_F4: key = VTERM_KEY_FUNCTION(4); break;
+ case K_F5: key = VTERM_KEY_FUNCTION(5); break;
+ case K_F6: key = VTERM_KEY_FUNCTION(6); break;
+ case K_F7: key = VTERM_KEY_FUNCTION(7); break;
+ case K_F8: key = VTERM_KEY_FUNCTION(8); break;
+ case K_F9: key = VTERM_KEY_FUNCTION(9); break;
+ case K_HOME: key = VTERM_KEY_HOME; break;
+ case K_S_HOME: mod = VTERM_MOD_SHIFT;
+ key = VTERM_KEY_HOME; break;
+ case K_C_HOME: mod = VTERM_MOD_CTRL;
+ key = VTERM_KEY_HOME; break;
+ case K_INS: key = VTERM_KEY_INS; break;
+ case K_K0: key = VTERM_KEY_KP_0; break;
+ case K_K1: key = VTERM_KEY_KP_1; break;
+ case K_K2: key = VTERM_KEY_KP_2; break;
+ case K_K3: key = VTERM_KEY_KP_3; break;
+ case K_K4: key = VTERM_KEY_KP_4; break;
+ case K_K5: key = VTERM_KEY_KP_5; break;
+ case K_K6: key = VTERM_KEY_KP_6; break;
+ case K_K7: key = VTERM_KEY_KP_7; break;
+ case K_K8: key = VTERM_KEY_KP_8; break;
+ case K_K9: key = VTERM_KEY_KP_9; break;
+ case K_KDEL: key = VTERM_KEY_DEL; break; /* TODO */
+ case K_KDIVIDE: key = VTERM_KEY_KP_DIVIDE; break;
+ case K_KEND: key = VTERM_KEY_KP_1; break; /* TODO */
+ case K_KENTER: key = VTERM_KEY_KP_ENTER; break;
+ case K_KHOME: key = VTERM_KEY_KP_7; break; /* TODO */
+ case K_KINS: key = VTERM_KEY_KP_0; break; /* TODO */
+ case K_KMINUS: key = VTERM_KEY_KP_MINUS; break;
+ case K_KMULTIPLY: key = VTERM_KEY_KP_MULT; break;
+ case K_KPAGEDOWN: key = VTERM_KEY_KP_3; break; /* TODO */
+ case K_KPAGEUP: key = VTERM_KEY_KP_9; break; /* TODO */
+ case K_KPLUS: key = VTERM_KEY_KP_PLUS; break;
+ case K_KPOINT: key = VTERM_KEY_KP_PERIOD; break;
+ case K_LEFT: key = VTERM_KEY_LEFT; break;
+ case K_S_LEFT: mod = VTERM_MOD_SHIFT;
+ key = VTERM_KEY_LEFT; break;
+ case K_C_LEFT: mod = VTERM_MOD_CTRL;
+ key = VTERM_KEY_LEFT; break;
+ case K_PAGEDOWN: key = VTERM_KEY_PAGEDOWN; break;
+ case K_PAGEUP: key = VTERM_KEY_PAGEUP; break;
+ case K_RIGHT: key = VTERM_KEY_RIGHT; break;
+ case K_S_RIGHT: mod = VTERM_MOD_SHIFT;
+ key = VTERM_KEY_RIGHT; break;
+ case K_C_RIGHT: mod = VTERM_MOD_CTRL;
+ key = VTERM_KEY_RIGHT; break;
+ case K_UP: key = VTERM_KEY_UP; break;
+ case K_S_UP: mod = VTERM_MOD_SHIFT;
+ key = VTERM_KEY_UP; break;
+ case TAB: key = VTERM_KEY_TAB; break;
+ case K_S_TAB: mod = VTERM_MOD_SHIFT;
+ key = VTERM_KEY_TAB; break;
+
+ case K_MOUSEUP: other = term_send_mouse(vterm, 5, 1); break;
+ case K_MOUSEDOWN: other = term_send_mouse(vterm, 4, 1); break;
+ case K_MOUSELEFT: /* TODO */ return 0;
+ case K_MOUSERIGHT: /* TODO */ return 0;
+
+ case K_LEFTMOUSE:
+ case K_LEFTMOUSE_NM:
+ case K_LEFTDRAG:
+ case K_LEFTRELEASE:
+ case K_LEFTRELEASE_NM:
+ case K_MOUSEMOVE:
+ case K_MIDDLEMOUSE:
+ case K_MIDDLEDRAG:
+ case K_MIDDLERELEASE:
+ case K_RIGHTMOUSE:
+ case K_RIGHTDRAG:
+ case K_RIGHTRELEASE: if (!term_mouse_click(vterm, c))
+ return 0;
+ other = TRUE;
+ break;
+
+ case K_X1MOUSE: /* TODO */ return 0;
+ case K_X1DRAG: /* TODO */ return 0;
+ case K_X1RELEASE: /* TODO */ return 0;
+ case K_X2MOUSE: /* TODO */ return 0;
+ case K_X2DRAG: /* TODO */ return 0;
+ case K_X2RELEASE: /* TODO */ return 0;
+
+ case K_IGNORE: return 0;
+ case K_NOP: return 0;
+ case K_UNDO: return 0;
+ case K_HELP: return 0;
+ case K_XF1: key = VTERM_KEY_FUNCTION(1); break;
+ case K_XF2: key = VTERM_KEY_FUNCTION(2); break;
+ case K_XF3: key = VTERM_KEY_FUNCTION(3); break;
+ case K_XF4: key = VTERM_KEY_FUNCTION(4); break;
+ case K_SELECT: return 0;
+#ifdef FEAT_GUI
+ case K_VER_SCROLLBAR: return 0;
+ case K_HOR_SCROLLBAR: return 0;
+#endif
+#ifdef FEAT_GUI_TABLINE
+ case K_TABLINE: return 0;
+ case K_TABMENU: return 0;
+#endif
+#ifdef FEAT_NETBEANS_INTG
+ case K_F21: key = VTERM_KEY_FUNCTION(21); break;
+#endif
+#ifdef FEAT_DND
+ case K_DROP: return 0;
+#endif
+ case K_CURSORHOLD: return 0;
+ case K_PS: vterm_keyboard_start_paste(vterm);
+ other = TRUE;
+ break;
+ case K_PE: vterm_keyboard_end_paste(vterm);
+ other = TRUE;
+ break;
+ }
+
+ /*
+ * Convert special keys to vterm keys:
+ * - Write keys to vterm: vterm_keyboard_key()
+ * - Write output to channel.
+ * TODO: use mod_mask
+ */
+ if (key != VTERM_KEY_NONE)
+ /* Special key, let vterm convert it. */
+ vterm_keyboard_key(vterm, key, mod);
+ else if (!other)
+ /* Normal character, let vterm convert it. */
+ vterm_keyboard_unichar(vterm, c, mod);
+
+ /* Read back the converted escape sequence. */
+ return (int)vterm_output_read(vterm, buf, KEY_BUF_LEN);
+}
+
+/*
+ * Return TRUE if the job for "term" is still running.
+ * If "check_job_status" is TRUE update the job status.
+ * NOTE: "term" may be freed by callbacks.
+ */
+ static int
+term_job_running_check(term_T *term, int check_job_status)
+{
+ /* Also consider the job finished when the channel is closed, to avoid a
+ * race condition when updating the title. */
+ if (term != NULL
+ && term->tl_job != NULL
+ && channel_is_open(term->tl_job->jv_channel))
+ {
+ job_T *job = term->tl_job;
+
+ // Careful: Checking the job status may invoked callbacks, which close
+ // the buffer and terminate "term". However, "job" will not be freed
+ // yet.
+ if (check_job_status)
+ job_status(job);
+ return (job->jv_status == JOB_STARTED
+ || (job->jv_channel != NULL && job->jv_channel->ch_keep_open));
+ }
+ return FALSE;
+}
+
+/*
+ * Return TRUE if the job for "term" is still running.
+ */
+ int
+term_job_running(term_T *term)
+{
+ return term_job_running_check(term, FALSE);
+}
+
+/*
+ * Return TRUE if "term" has an active channel and used ":term NONE".
+ */
+ int
+term_none_open(term_T *term)
+{
+ /* Also consider the job finished when the channel is closed, to avoid a
+ * race condition when updating the title. */
+ return term != NULL
+ && term->tl_job != NULL
+ && channel_is_open(term->tl_job->jv_channel)
+ && term->tl_job->jv_channel->ch_keep_open;
+}
+
+/*
+ * Used when exiting: kill the job in "buf" if so desired.
+ * Return OK when the job finished.
+ * Return FAIL when the job is still running.
+ */
+ int
+term_try_stop_job(buf_T *buf)
+{
+ int count;
+ char *how = (char *)buf->b_term->tl_kill;
+
+#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
+ if ((how == NULL || *how == NUL) && (p_confirm || cmdmod.confirm))
+ {
+ char_u buff[DIALOG_MSG_SIZE];
+ int ret;
+
+ dialog_msg(buff, _("Kill job in \"%s\"?"), buf->b_fname);
+ ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
+ if (ret == VIM_YES)
+ how = "kill";
+ else if (ret == VIM_CANCEL)
+ return FAIL;
+ }
+#endif
+ if (how == NULL || *how == NUL)
+ return FAIL;
+
+ job_stop(buf->b_term->tl_job, NULL, how);
+
+ // wait for up to a second for the job to die
+ for (count = 0; count < 100; ++count)
+ {
+ job_T *job;
+
+ // buffer, terminal and job may be cleaned up while waiting
+ if (!buf_valid(buf)
+ || buf->b_term == NULL
+ || buf->b_term->tl_job == NULL)
+ return OK;
+ job = buf->b_term->tl_job;
+
+ // Call job_status() to update jv_status. It may cause the job to be
+ // cleaned up but it won't be freed.
+ job_status(job);
+ if (job->jv_status >= JOB_ENDED)
+ return OK;
+
+ ui_delay(10L, FALSE);
+ mch_check_messages();
+ parse_queued_messages();
+ }
+ return FAIL;
+}
+
+/*
+ * Add the last line of the scrollback buffer to the buffer in the window.
+ */
+ static void
+add_scrollback_line_to_buffer(term_T *term, char_u *text, int len)
+{
+ buf_T *buf = term->tl_buffer;
+ int empty = (buf->b_ml.ml_flags & ML_EMPTY);
+ linenr_T lnum = buf->b_ml.ml_line_count;
+
+#ifdef WIN3264
+ if (!enc_utf8 && enc_codepage > 0)
+ {
+ WCHAR *ret = NULL;
+ int length = 0;
+
+ MultiByteToWideChar_alloc(CP_UTF8, 0, (char*)text, len + 1,
+ &ret, &length);
+ if (ret != NULL)
+ {
+ WideCharToMultiByte_alloc(enc_codepage, 0,
+ ret, length, (char **)&text, &len, 0, 0);
+ vim_free(ret);
+ ml_append_buf(term->tl_buffer, lnum, text, len, FALSE);
+ vim_free(text);
+ }
+ }
+ else
+#endif
+ ml_append_buf(term->tl_buffer, lnum, text, len + 1, FALSE);
+ if (empty)
+ {
+ /* Delete the empty line that was in the empty buffer. */
+ curbuf = buf;
+ ml_delete(1, FALSE);
+ curbuf = curwin->w_buffer;
+ }
+}
+
+ static void
+cell2cellattr(const VTermScreenCell *cell, cellattr_T *attr)
+{
+ attr->width = cell->width;
+ attr->attrs = cell->attrs;
+ attr->fg = cell->fg;
+ attr->bg = cell->bg;
+}
+
+ static int
+equal_celattr(cellattr_T *a, cellattr_T *b)
+{
+ /* Comparing the colors should be sufficient. */
+ return a->fg.red == b->fg.red
+ && a->fg.green == b->fg.green
+ && a->fg.blue == b->fg.blue
+ && a->bg.red == b->bg.red
+ && a->bg.green == b->bg.green
+ && a->bg.blue == b->bg.blue;
+}
+
+/*
+ * Add an empty scrollback line to "term". When "lnum" is not zero, add the
+ * line at this position. Otherwise at the end.
+ */
+ static int
+add_empty_scrollback(term_T *term, cellattr_T *fill_attr, int lnum)
+{
+ if (ga_grow(&term->tl_scrollback, 1) == OK)
+ {
+ sb_line_T *line = (sb_line_T *)term->tl_scrollback.ga_data
+ + term->tl_scrollback.ga_len;
+
+ if (lnum > 0)
+ {
+ int i;
+
+ for (i = 0; i < term->tl_scrollback.ga_len - lnum; ++i)
+ {
+ *line = *(line - 1);
+ --line;
+ }
+ }
+ line->sb_cols = 0;
+ line->sb_cells = NULL;
+ line->sb_fill_attr = *fill_attr;
+ ++term->tl_scrollback.ga_len;
+ return OK;
+ }
+ return FALSE;
+}
+
+/*
+ * Remove the terminal contents from the scrollback and the buffer.
+ * Used before adding a new scrollback line or updating the buffer for lines
+ * displayed in the terminal.
+ */
+ static void
+cleanup_scrollback(term_T *term)
+{
+ sb_line_T *line;
+ garray_T *gap;
+
+ curbuf = term->tl_buffer;
+ gap = &term->tl_scrollback;
+ while (curbuf->b_ml.ml_line_count > term->tl_scrollback_scrolled
+ && gap->ga_len > 0)
+ {
+ ml_delete(curbuf->b_ml.ml_line_count, FALSE);
+ line = (sb_line_T *)gap->ga_data + gap->ga_len - 1;
+ vim_free(line->sb_cells);
+ --gap->ga_len;
+ }
+ curbuf = curwin->w_buffer;
+ if (curbuf == term->tl_buffer)
+ check_cursor();
+}
+
+/*
+ * Add the current lines of the terminal to scrollback and to the buffer.
+ */
+ static void
+update_snapshot(term_T *term)
+{
+ VTermScreen *screen;
+ int len;
+ int lines_skipped = 0;
+ VTermPos pos;
+ VTermScreenCell cell;
+ cellattr_T fill_attr, new_fill_attr;
+ cellattr_T *p;
+
+ ch_log(term->tl_job == NULL ? NULL : term->tl_job->jv_channel,
+ "Adding terminal window snapshot to buffer");
+
+ /* First remove the lines that were appended before, they might be
+ * outdated. */
+ cleanup_scrollback(term);
+
+ screen = vterm_obtain_screen(term->tl_vterm);
+ fill_attr = new_fill_attr = term->tl_default_color;
+ for (pos.row = 0; pos.row < term->tl_rows; ++pos.row)
+ {
+ len = 0;
+ for (pos.col = 0; pos.col < term->tl_cols; ++pos.col)
+ if (vterm_screen_get_cell(screen, pos, &cell) != 0
+ && cell.chars[0] != NUL)
+ {
+ len = pos.col + 1;
+ new_fill_attr = term->tl_default_color;
+ }
+ else
+ /* Assume the last attr is the filler attr. */
+ cell2cellattr(&cell, &new_fill_attr);
+
+ if (len == 0 && equal_celattr(&new_fill_attr, &fill_attr))
+ ++lines_skipped;
+ else
+ {
+ while (lines_skipped > 0)
+ {
+ /* Line was skipped, add an empty line. */
+ --lines_skipped;
+ if (add_empty_scrollback(term, &fill_attr, 0) == OK)
+ add_scrollback_line_to_buffer(term, (char_u *)"", 0);
+ }
+
+ if (len == 0)
+ p = NULL;
+ else
+ p = (cellattr_T *)alloc((int)sizeof(cellattr_T) * len);
+ if ((p != NULL || len == 0)
+ && ga_grow(&term->tl_scrollback, 1) == OK)
+ {
+ garray_T ga;
+ int width;
+ sb_line_T *line = (sb_line_T *)term->tl_scrollback.ga_data
+ + term->tl_scrollback.ga_len;
+
+ ga_init2(&ga, 1, 100);
+ for (pos.col = 0; pos.col < len; pos.col += width)
+ {
+ if (vterm_screen_get_cell(screen, pos, &cell) == 0)
+ {
+ width = 1;
+ vim_memset(p + pos.col, 0, sizeof(cellattr_T));
+ if (ga_grow(&ga, 1) == OK)
+ ga.ga_len += utf_char2bytes(' ',
+ (char_u *)ga.ga_data + ga.ga_len);
+ }
+ else
+ {
+ width = cell.width;
+
+ cell2cellattr(&cell, &p[pos.col]);
+
+ // Each character can be up to 6 bytes.
+ if (ga_grow(&ga, VTERM_MAX_CHARS_PER_CELL * 6) == OK)
+ {
+ int i;
+ int c;
+
+ for (i = 0; (c = cell.chars[i]) > 0 || i == 0; ++i)
+ ga.ga_len += utf_char2bytes(c == NUL ? ' ' : c,
+ (char_u *)ga.ga_data + ga.ga_len);
+ }
+ }
+ }
+ line->sb_cols = len;
+ line->sb_cells = p;
+ line->sb_fill_attr = new_fill_attr;
+ fill_attr = new_fill_attr;
+ ++term->tl_scrollback.ga_len;
+
+ if (ga_grow(&ga, 1) == FAIL)
+ add_scrollback_line_to_buffer(term, (char_u *)"", 0);
+ else
+ {
+ *((char_u *)ga.ga_data + ga.ga_len) = NUL;
+ add_scrollback_line_to_buffer(term, ga.ga_data, ga.ga_len);
+ }
+ ga_clear(&ga);
+ }
+ else
+ vim_free(p);
+ }
+ }
+
+ // Add trailing empty lines.
+ for (pos.row = term->tl_scrollback.ga_len;
+ pos.row < term->tl_scrollback_scrolled + term->tl_cursor_pos.row;
+ ++pos.row)
+ {
+ if (add_empty_scrollback(term, &fill_attr, 0) == OK)
+ add_scrollback_line_to_buffer(term, (char_u *)"", 0);
+ }
+
+ term->tl_dirty_snapshot = FALSE;
+#ifdef FEAT_TIMERS
+ term->tl_timer_set = FALSE;
+#endif
+}
+
+/*
+ * If needed, add the current lines of the terminal to scrollback and to the
+ * buffer. Called after the job has ended and when switching to
+ * Terminal-Normal mode.
+ * When "redraw" is TRUE redraw the windows that show the terminal.
+ */
+ static void
+may_move_terminal_to_buffer(term_T *term, int redraw)
+{
+ win_T *wp;
+
+ if (term->tl_vterm == NULL)
+ return;
+
+ /* Update the snapshot only if something changes or the buffer does not
+ * have all the lines. */
+ if (term->tl_dirty_snapshot || term->tl_buffer->b_ml.ml_line_count
+ <= term->tl_scrollback_scrolled)
+ update_snapshot(term);
+
+ /* Obtain the current background color. */
+ vterm_state_get_default_colors(vterm_obtain_state(term->tl_vterm),
+ &term->tl_default_color.fg, &term->tl_default_color.bg);
+
+ if (redraw)
+ FOR_ALL_WINDOWS(wp)
+ {
+ if (wp->w_buffer == term->tl_buffer)
+ {
+ wp->w_cursor.lnum = term->tl_buffer->b_ml.ml_line_count;
+ wp->w_cursor.col = 0;
+ wp->w_valid = 0;
+ if (wp->w_cursor.lnum >= wp->w_height)
+ {
+ linenr_T min_topline = wp->w_cursor.lnum - wp->w_height + 1;
+
+ if (wp->w_topline < min_topline)
+ wp->w_topline = min_topline;
+ }
+ redraw_win_later(wp, NOT_VALID);
+ }
+ }
+}
+
+#if defined(FEAT_TIMERS) || defined(PROTO)
+/*
+ * Check if any terminal timer expired. If so, copy text from the terminal to
+ * the buffer.
+ * Return the time until the next timer will expire.
+ */
+ int
+term_check_timers(int next_due_arg, proftime_T *now)
+{
+ term_T *term;
+ int next_due = next_due_arg;
+
+ for (term = first_term; term != NULL; term = term->tl_next)
+ {
+ if (term->tl_timer_set && !term->tl_normal_mode)
+ {
+ long this_due = proftime_time_left(&term->tl_timer_due, now);
+
+ if (this_due <= 1)
+ {
+ term->tl_timer_set = FALSE;
+ may_move_terminal_to_buffer(term, FALSE);
+ }
+ else if (next_due == -1 || next_due > this_due)
+ next_due = this_due;
+ }
+ }
+
+ return next_due;
+}
+#endif
+
+ static void
+set_terminal_mode(term_T *term, int normal_mode)
+{
+ term->tl_normal_mode = normal_mode;
+ VIM_CLEAR(term->tl_status_text);
+ if (term->tl_buffer == curbuf)
+ maketitle();
+}
+
+/*
+ * Called after the job if finished and Terminal mode is not active:
+ * Move the vterm contents into the scrollback buffer and free the vterm.
+ */
+ static void
+cleanup_vterm(term_T *term)
+{
+ if (term->tl_finish != TL_FINISH_CLOSE)
+ may_move_terminal_to_buffer(term, TRUE);
+ term_free_vterm(term);
+ set_terminal_mode(term, FALSE);
+}
+
+/*
+ * Switch from Terminal-Job mode to Terminal-Normal mode.
+ * Suspends updating the terminal window.
+ */
+ static void
+term_enter_normal_mode(void)
+{
+ term_T *term = curbuf->b_term;
+
+ set_terminal_mode(term, TRUE);
+
+ /* Append the current terminal contents to the buffer. */
+ may_move_terminal_to_buffer(term, TRUE);
+
+ /* Move the window cursor to the position of the cursor in the
+ * terminal. */
+ curwin->w_cursor.lnum = term->tl_scrollback_scrolled
+ + term->tl_cursor_pos.row + 1;
+ check_cursor();
+ if (coladvance(term->tl_cursor_pos.col) == FAIL)
+ coladvance(MAXCOL);
+
+ /* Display the same lines as in the terminal. */
+ curwin->w_topline = term->tl_scrollback_scrolled + 1;
+}
+
+/*
+ * Returns TRUE if the current window contains a terminal and we are in
+ * Terminal-Normal mode.
+ */
+ int
+term_in_normal_mode(void)
+{
+ term_T *term = curbuf->b_term;
+
+ return term != NULL && term->tl_normal_mode;
+}
+
+/*
+ * Switch from Terminal-Normal mode to Terminal-Job mode.
+ * Restores updating the terminal window.
+ */
+ void
+term_enter_job_mode()
+{
+ term_T *term = curbuf->b_term;
+
+ set_terminal_mode(term, FALSE);
+
+ if (term->tl_channel_closed)
+ cleanup_vterm(term);
+ redraw_buf_and_status_later(curbuf, NOT_VALID);
+}
+
+/*
+ * Get a key from the user with terminal mode mappings.
+ * Note: while waiting a terminal may be closed and freed if the channel is
+ * closed and ++close was used.
+ */
+ static int
+term_vgetc()
+{
+ int c;
+ int save_State = State;
+
+ State = TERMINAL;
+ got_int = FALSE;
+#ifdef WIN3264
+ ctrl_break_was_pressed = FALSE;
+#endif
+ c = vgetc();
+ got_int = FALSE;
+ State = save_State;
+ return c;
+}
+
+static int mouse_was_outside = FALSE;
+
+/*
+ * Send keys to terminal.
+ * Return FAIL when the key needs to be handled in Normal mode.
+ * Return OK when the key was dropped or sent to the terminal.
+ */
+ int
+send_keys_to_term(term_T *term, int c, int typed)
+{
+ char msg[KEY_BUF_LEN];
+ size_t len;
+ int dragging_outside = FALSE;
+
+ /* Catch keys that need to be handled as in Normal mode. */
+ switch (c)
+ {
+ case NUL:
+ case K_ZERO:
+ if (typed)
+ stuffcharReadbuff(c);
+ return FAIL;
+
+ case K_TABLINE:
+ stuffcharReadbuff(c);
+ return FAIL;
+
+ case K_IGNORE:
+ case K_CANCEL: // used for :normal when running out of chars
+ return FAIL;
+
+ case K_LEFTDRAG:
+ case K_MIDDLEDRAG:
+ case K_RIGHTDRAG:
+ case K_X1DRAG:
+ case K_X2DRAG:
+ dragging_outside = mouse_was_outside;
+ /* FALLTHROUGH */
+ case K_LEFTMOUSE:
+ case K_LEFTMOUSE_NM:
+ case K_LEFTRELEASE:
+ case K_LEFTRELEASE_NM:
+ case K_MOUSEMOVE:
+ case K_MIDDLEMOUSE:
+ case K_MIDDLERELEASE:
+ case K_RIGHTMOUSE:
+ case K_RIGHTRELEASE:
+ case K_X1MOUSE:
+ case K_X1RELEASE:
+ case K_X2MOUSE:
+ case K_X2RELEASE:
+
+ case K_MOUSEUP:
+ case K_MOUSEDOWN:
+ case K_MOUSELEFT:
+ case K_MOUSERIGHT:
+ if (mouse_row < W_WINROW(curwin)
+ || mouse_row >= (W_WINROW(curwin) + curwin->w_height)
+ || mouse_col < curwin->w_wincol
+ || mouse_col >= W_ENDCOL(curwin)
+ || dragging_outside)
+ {
+ /* click or scroll outside the current window or on status line
+ * or vertical separator */
+ if (typed)
+ {
+ stuffcharReadbuff(c);
+ mouse_was_outside = TRUE;
+ }
+ return FAIL;
+ }
+ }
+ if (typed)
+ mouse_was_outside = FALSE;
+
+ /* Convert the typed key to a sequence of bytes for the job. */
+ len = term_convert_key(term, c, msg);
+ if (len > 0)
+ /* TODO: if FAIL is returned, stop? */
+ channel_send(term->tl_job->jv_channel, get_tty_part(term),
+ (char_u *)msg, (int)len, NULL);
+
+ return OK;
+}
+
+ static void
+position_cursor(win_T *wp, VTermPos *pos)
+{
+ wp->w_wrow = MIN(pos->row, MAX(0, wp->w_height - 1));
+ wp->w_wcol = MIN(pos->col, MAX(0, wp->w_width - 1));
+ wp->w_valid |= (VALID_WCOL|VALID_WROW);
+}
+
+/*
+ * Handle CTRL-W "": send register contents to the job.
+ */
+ static void
+term_paste_register(int prev_c UNUSED)
+{
+ int c;
+ list_T *l;
+ listitem_T *item;
+ long reglen = 0;
+ int type;
+
+#ifdef FEAT_CMDL_INFO
+ if (add_to_showcmd(prev_c))
+ if (add_to_showcmd('"'))
+ out_flush();
+#endif
+ c = term_vgetc();
+#ifdef FEAT_CMDL_INFO
+ clear_showcmd();
+#endif
+ if (!term_use_loop())
+ /* job finished while waiting for a character */
+ return;
+
+ /* CTRL-W "= prompt for expression to evaluate. */
+ if (c == '=' && get_expr_register() != '=')
+ return;
+ if (!term_use_loop())
+ /* job finished while waiting for a character */
+ return;
+
+ l = (list_T *)get_reg_contents(c, GREG_LIST);
+ if (l != NULL)
+ {
+ type = get_reg_type(c, &reglen);
+ for (item = l->lv_first; item != NULL; item = item->li_next)
+ {
+ char_u *s = tv_get_string(&item->li_tv);
+#ifdef WIN3264
+ char_u *tmp = s;
+
+ if (!enc_utf8 && enc_codepage > 0)
+ {
+ WCHAR *ret = NULL;
+ int length = 0;
+
+ MultiByteToWideChar_alloc(enc_codepage, 0, (char *)s,
+ (int)STRLEN(s), &ret, &length);
+ if (ret != NULL)
+ {
+ WideCharToMultiByte_alloc(CP_UTF8, 0,
+ ret, length, (char **)&s, &length, 0, 0);
+ vim_free(ret);
+ }
+ }
+#endif
+ channel_send(curbuf->b_term->tl_job->jv_channel, PART_IN,
+ s, (int)STRLEN(s), NULL);
+#ifdef WIN3264
+ if (tmp != s)
+ vim_free(s);
+#endif
+
+ if (item->li_next != NULL || type == MLINE)
+ channel_send(curbuf->b_term->tl_job->jv_channel, PART_IN,
+ (char_u *)"\r", 1, NULL);
+ }
+ list_free(l);
+ }
+}
+
+/*
+ * Return TRUE when waiting for a character in the terminal, the cursor of the
+ * terminal should be displayed.
+ */
+ int
+terminal_is_active()
+{
+ return in_terminal_loop != NULL;
+}
+
+#if defined(FEAT_GUI) || defined(PROTO)
+ cursorentry_T *
+term_get_cursor_shape(guicolor_T *fg, guicolor_T *bg)
+{
+ term_T *term = in_terminal_loop;
+ static cursorentry_T entry;
+ int id;
+ guicolor_T term_fg, term_bg;
+
+ vim_memset(&entry, 0, sizeof(entry));
+ entry.shape = entry.mshape =
+ term->tl_cursor_shape == VTERM_PROP_CURSORSHAPE_UNDERLINE ? SHAPE_HOR :
+ term->tl_cursor_shape == VTERM_PROP_CURSORSHAPE_BAR_LEFT ? SHAPE_VER :
+ SHAPE_BLOCK;
+ entry.percentage = 20;
+ if (term->tl_cursor_blink)
+ {
+ entry.blinkwait = 700;
+ entry.blinkon = 400;
+ entry.blinkoff = 250;
+ }
+
+ /* The "Terminal" highlight group overrules the defaults. */
+ id = syn_name2id((char_u *)"Terminal");
+ if (id != 0)
+ {
+ syn_id2colors(id, &term_fg, &term_bg);
+ *fg = term_bg;
+ }
+ else
+ *fg = gui.back_pixel;
+
+ if (term->tl_cursor_color == NULL)
+ {
+ if (id != 0)
+ *bg = term_fg;
+ else
+ *bg = gui.norm_pixel;
+ }
+ else
+ *bg = color_name2handle(term->tl_cursor_color);
+ entry.name = "n";
+ entry.used_for = SHAPE_CURSOR;
+
+ return &entry;
+}
+#endif
+
+ static void
+may_output_cursor_props(void)
+{
+ if (!cursor_color_equal(last_set_cursor_color, desired_cursor_color)
+ || last_set_cursor_shape != desired_cursor_shape
+ || last_set_cursor_blink != desired_cursor_blink)
+ {
+ cursor_color_copy(&last_set_cursor_color, desired_cursor_color);
+ last_set_cursor_shape = desired_cursor_shape;
+ last_set_cursor_blink = desired_cursor_blink;
+ term_cursor_color(cursor_color_get(desired_cursor_color));
+ if (desired_cursor_shape == -1 || desired_cursor_blink == -1)
+ /* this will restore the initial cursor style, if possible */
+ ui_cursor_shape_forced(TRUE);
+ else
+ term_cursor_shape(desired_cursor_shape, desired_cursor_blink);
+ }
+}
+
+/*
+ * Set the cursor color and shape, if not last set to these.
+ */
+ static void
+may_set_cursor_props(term_T *term)
+{
+#ifdef FEAT_GUI
+ /* For the GUI the cursor properties are obtained with
+ * term_get_cursor_shape(). */
+ if (gui.in_use)
+ return;
+#endif
+ if (in_terminal_loop == term)
+ {
+ cursor_color_copy(&desired_cursor_color, term->tl_cursor_color);
+ desired_cursor_shape = term->tl_cursor_shape;
+ desired_cursor_blink = term->tl_cursor_blink;
+ may_output_cursor_props();
+ }
+}
+
+/*
+ * Reset the desired cursor properties and restore them when needed.
+ */
+ static void
+prepare_restore_cursor_props(void)
+{
+#ifdef FEAT_GUI
+ if (gui.in_use)
+ return;
+#endif
+ cursor_color_copy(&desired_cursor_color, NULL);
+ desired_cursor_shape = -1;
+ desired_cursor_blink = -1;
+ may_output_cursor_props();
+}
+
+/*
+ * Returns TRUE if the current window contains a terminal and we are sending
+ * keys to the job.
+ * If "check_job_status" is TRUE update the job status.
+ */
+ static int
+term_use_loop_check(int check_job_status)
+{
+ term_T *term = curbuf->b_term;
+
+ return term != NULL
+ && !term->tl_normal_mode
+ && term->tl_vterm != NULL
+ && term_job_running_check(term, check_job_status);
+}
+
+/*
+ * Returns TRUE if the current window contains a terminal and we are sending
+ * keys to the job.
+ */
+ int
+term_use_loop(void)
+{
+ return term_use_loop_check(FALSE);
+}
+
+/*
+ * Called when entering a window with the mouse. If this is a terminal window
+ * we may want to change state.
+ */
+ void
+term_win_entered()
+{
+ term_T *term = curbuf->b_term;
+
+ if (term != NULL)
+ {
+ if (term_use_loop_check(TRUE))
+ {
+ reset_VIsual_and_resel();
+ if (State & INSERT)
+ stop_insert_mode = TRUE;
+ }
+ mouse_was_outside = FALSE;
+ enter_mouse_col = mouse_col;
+ enter_mouse_row = mouse_row;
+ }
+}
+
+/*
+ * Wait for input and send it to the job.
+ * When "blocking" is TRUE wait for a character to be typed. Otherwise return
+ * when there is no more typahead.
+ * Return when the start of a CTRL-W command is typed or anything else that
+ * should be handled as a Normal mode command.
+ * Returns OK if a typed character is to be handled in Normal mode, FAIL if
+ * the terminal was closed.
+ */
+ int
+terminal_loop(int blocking)
+{
+ int c;
+ int termwinkey = 0;
+ int ret;
+#ifdef UNIX
+ int tty_fd = curbuf->b_term->tl_job->jv_channel
+ ->ch_part[get_tty_part(curbuf->b_term)].ch_fd;
+#endif
+ int restore_cursor = FALSE;
+
+ /* Remember the terminal we are sending keys to. However, the terminal
+ * might be closed while waiting for a character, e.g. typing "exit" in a
+ * shell and ++close was used. Therefore use curbuf->b_term instead of a
+ * stored reference. */
+ in_terminal_loop = curbuf->b_term;
+
+ if (*curwin->w_p_twk != NUL)
+ {
+ termwinkey = string_to_key(curwin->w_p_twk, TRUE);
+ if (termwinkey == Ctrl_W)
+ termwinkey = 0;
+ }
+ position_cursor(curwin, &curbuf->b_term->tl_cursor_pos);
+ may_set_cursor_props(curbuf->b_term);
+
+ while (blocking || vpeekc_nomap() != NUL)
+ {
+#ifdef FEAT_GUI
+ if (!curbuf->b_term->tl_system)
+#endif
+ // TODO: skip screen update when handling a sequence of keys.
+ // Repeat redrawing in case a message is received while redrawing.
+ while (must_redraw != 0)
+ if (update_screen(0) == FAIL)
+ break;
+ if (!term_use_loop_check(TRUE) || in_terminal_loop != curbuf->b_term)
+ /* job finished while redrawing */
+ break;
+
+ update_cursor(curbuf->b_term, FALSE);
+ restore_cursor = TRUE;
+
+ c = term_vgetc();
+ if (!term_use_loop_check(TRUE) || in_terminal_loop != curbuf->b_term)
+ {
+ /* Job finished while waiting for a character. Push back the
+ * received character. */
+ if (c != K_IGNORE)
+ vungetc(c);
+ break;
+ }
+ if (c == K_IGNORE)
+ continue;
+
+#ifdef UNIX
+ /*
+ * The shell or another program may change the tty settings. Getting
+ * them for every typed character is a bit of overhead, but it's needed
+ * for the first character typed, e.g. when Vim starts in a shell.
+ */
+ if (mch_isatty(tty_fd))
+ {
+ ttyinfo_T info;
+
+ /* Get the current backspace character of the pty. */
+ if (get_tty_info(tty_fd, &info) == OK)
+ term_backspace_char = info.backspace;
+ }
+#endif
+
+#ifdef WIN3264
+ /* On Windows winpty handles CTRL-C, don't send a CTRL_C_EVENT.
+ * Use CTRL-BREAK to kill the job. */
+ if (ctrl_break_was_pressed)
+ mch_signal_job(curbuf->b_term->tl_job, (char_u *)"kill");
+#endif
+ /* Was either CTRL-W (termwinkey) or CTRL-\ pressed?
+ * Not in a system terminal. */
+ if ((c == (termwinkey == 0 ? Ctrl_W : termwinkey) || c == Ctrl_BSL)
+#ifdef FEAT_GUI
+ && !curbuf->b_term->tl_system
+#endif
+ )
+ {
+ int prev_c = c;
+
+#ifdef FEAT_CMDL_INFO
+ if (add_to_showcmd(c))
+ out_flush();
+#endif
+ c = term_vgetc();
+#ifdef FEAT_CMDL_INFO
+ clear_showcmd();
+#endif
+ if (!term_use_loop_check(TRUE)
+ || in_terminal_loop != curbuf->b_term)
+ /* job finished while waiting for a character */
+ break;
+
+ if (prev_c == Ctrl_BSL)
+ {
+ if (c == Ctrl_N)
+ {
+ /* CTRL-\ CTRL-N : go to Terminal-Normal mode. */
+ term_enter_normal_mode();
+ ret = FAIL;
+ goto theend;
+ }
+ /* Send both keys to the terminal. */
+ send_keys_to_term(curbuf->b_term, prev_c, TRUE);
+ }
+ else if (c == Ctrl_C)
+ {
+ /* "CTRL-W CTRL-C" or 'termwinkey' CTRL-C: end the job */
+ mch_signal_job(curbuf->b_term->tl_job, (char_u *)"kill");
+ }
+ else if (c == '.')
+ {
+ /* "CTRL-W .": send CTRL-W to the job */
+ /* "'termwinkey' .": send 'termwinkey' to the job */
+ c = termwinkey == 0 ? Ctrl_W : termwinkey;
+ }
+ else if (c == Ctrl_BSL)
+ {
+ /* "CTRL-W CTRL-\": send CTRL-\ to the job */
+ c = Ctrl_BSL;
+ }
+ else if (c == 'N')
+ {
+ /* CTRL-W N : go to Terminal-Normal mode. */
+ term_enter_normal_mode();
+ ret = FAIL;
+ goto theend;
+ }
+ else if (c == '"')
+ {
+ term_paste_register(prev_c);
+ continue;
+ }
+ else if (termwinkey == 0 || c != termwinkey)
+ {
+ stuffcharReadbuff(Ctrl_W);
+ stuffcharReadbuff(c);
+ ret = OK;
+ goto theend;
+ }
+ }
+# ifdef WIN3264
+ if (!enc_utf8 && has_mbyte && c >= 0x80)
+ {
+ WCHAR wc;
+ char_u mb[3];
+
+ mb[0] = (unsigned)c >> 8;
+ mb[1] = c;
+ if (MultiByteToWideChar(GetACP(), 0, (char*)mb, 2, &wc, 1) > 0)
+ c = wc;
+ }
+# endif
+ if (send_keys_to_term(curbuf->b_term, c, TRUE) != OK)
+ {
+ if (c == K_MOUSEMOVE)
+ /* We are sure to come back here, don't reset the cursor color
+ * and shape to avoid flickering. */
+ restore_cursor = FALSE;
+
+ ret = OK;
+ goto theend;
+ }
+ }
+ ret = FAIL;
+
+theend:
+ in_terminal_loop = NULL;
+ if (restore_cursor)
+ prepare_restore_cursor_props();
+
+ /* Move a snapshot of the screen contents to the buffer, so that completion
+ * works in other buffers. */
+ if (curbuf->b_term != NULL && !curbuf->b_term->tl_normal_mode)
+ may_move_terminal_to_buffer(curbuf->b_term, FALSE);
+
+ return ret;
+}
+
+ static void
+may_toggle_cursor(term_T *term)
+{
+ if (in_terminal_loop == term)
+ {
+ if (term->tl_cursor_visible)
+ cursor_on();
+ else
+ cursor_off();
+ }
+}
+
+/*
+ * Reverse engineer the RGB value into a cterm color index.
+ * First color is 1. Return 0 if no match found (default color).
+ */
+ static int
+color2index(VTermColor *color, int fg, int *boldp)
+{
+ int red = color->red;
+ int blue = color->blue;
+ int green = color->green;
+
+ if (color->ansi_index != VTERM_ANSI_INDEX_NONE)
+ {
+ /* First 16 colors and default: use the ANSI index, because these
+ * colors can be redefined. */
+ if (t_colors >= 16)
+ return color->ansi_index;
+ switch (color->ansi_index)
+ {
+ case 0: return 0;
+ case 1: return lookup_color( 0, fg, boldp) + 1; /* black */
+ case 2: return lookup_color( 4, fg, boldp) + 1; /* dark red */
+ case 3: return lookup_color( 2, fg, boldp) + 1; /* dark green */
+ case 4: return lookup_color( 6, fg, boldp) + 1; /* brown */
+ case 5: return lookup_color( 1, fg, boldp) + 1; /* dark blue */
+ case 6: return lookup_color( 5, fg, boldp) + 1; /* dark magenta */
+ case 7: return lookup_color( 3, fg, boldp) + 1; /* dark cyan */
+ case 8: return lookup_color( 8, fg, boldp) + 1; /* light grey */
+ case 9: return lookup_color(12, fg, boldp) + 1; /* dark grey */
+ case 10: return lookup_color(20, fg, boldp) + 1; /* red */
+ case 11: return lookup_color(16, fg, boldp) + 1; /* green */
+ case 12: return lookup_color(24, fg, boldp) + 1; /* yellow */
+ case 13: return lookup_color(14, fg, boldp) + 1; /* blue */
+ case 14: return lookup_color(22, fg, boldp) + 1; /* magenta */
+ case 15: return lookup_color(18, fg, boldp) + 1; /* cyan */
+ case 16: return lookup_color(26, fg, boldp) + 1; /* white */
+ }
+ }
+
+ if (t_colors >= 256)
+ {
+ if (red == blue && red == green)
+ {
+ /* 24-color greyscale plus white and black */
+ static int cutoff[23] = {
+ 0x0D, 0x17, 0x21, 0x2B, 0x35, 0x3F, 0x49, 0x53, 0x5D, 0x67,
+ 0x71, 0x7B, 0x85, 0x8F, 0x99, 0xA3, 0xAD, 0xB7, 0xC1, 0xCB,
+ 0xD5, 0xDF, 0xE9};
+ int i;
+
+ if (red < 5)
+ return 17; /* 00/00/00 */
+ if (red > 245) /* ff/ff/ff */
+ return 232;
+ for (i = 0; i < 23; ++i)
+ if (red < cutoff[i])
+ return i + 233;
+ return 256;
+ }
+ {
+ static int cutoff[5] = {0x2F, 0x73, 0x9B, 0xC3, 0xEB};
+ int ri, gi, bi;
+
+ /* 216-color cube */
+ for (ri = 0; ri < 5; ++ri)
+ if (red < cutoff[ri])
+ break;
+ for (gi = 0; gi < 5; ++gi)
+ if (green < cutoff[gi])
+ break;
+ for (bi = 0; bi < 5; ++bi)
+ if (blue < cutoff[bi])
+ break;
+ return 17 + ri * 36 + gi * 6 + bi;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Convert Vterm attributes to highlight flags.
+ */
+ static int
+vtermAttr2hl(VTermScreenCellAttrs cellattrs)
+{
+ int attr = 0;
+
+ if (cellattrs.bold)
+ attr |= HL_BOLD;
+ if (cellattrs.underline)
+ attr |= HL_UNDERLINE;
+ if (cellattrs.italic)
+ attr |= HL_ITALIC;
+ if (cellattrs.strike)
+ attr |= HL_STRIKETHROUGH;
+ if (cellattrs.reverse)
+ attr |= HL_INVERSE;
+ return attr;
+}
+
+/*
+ * Store Vterm attributes in "cell" from highlight flags.
+ */
+ static void
+hl2vtermAttr(int attr, cellattr_T *cell)
+{
+ vim_memset(&cell->attrs, 0, sizeof(VTermScreenCellAttrs));
+ if (attr & HL_BOLD)
+ cell->attrs.bold = 1;
+ if (attr & HL_UNDERLINE)
+ cell->attrs.underline = 1;
+ if (attr & HL_ITALIC)
+ cell->attrs.italic = 1;
+ if (attr & HL_STRIKETHROUGH)
+ cell->attrs.strike = 1;
+ if (attr & HL_INVERSE)
+ cell->attrs.reverse = 1;
+}
+
+/*
+ * Convert the attributes of a vterm cell into an attribute index.
+ */
+ static int
+cell2attr(VTermScreenCellAttrs cellattrs, VTermColor cellfg, VTermColor cellbg)
+{
+ int attr = vtermAttr2hl(cellattrs);
+
+#ifdef FEAT_GUI
+ if (gui.in_use)
+ {
+ guicolor_T fg, bg;
+
+ fg = gui_mch_get_rgb_color(cellfg.red, cellfg.green, cellfg.blue);
+ bg = gui_mch_get_rgb_color(cellbg.red, cellbg.green, cellbg.blue);
+ return get_gui_attr_idx(attr, fg, bg);
+ }
+ else
+#endif
+#ifdef FEAT_TERMGUICOLORS
+ if (p_tgc)
+ {
+ guicolor_T fg, bg;
+
+ fg = gui_get_rgb_color_cmn(cellfg.red, cellfg.green, cellfg.blue);
+ bg = gui_get_rgb_color_cmn(cellbg.red, cellbg.green, cellbg.blue);
+
+ return get_tgc_attr_idx(attr, fg, bg);
+ }
+ else
+#endif
+ {
+ int bold = MAYBE;
+ int fg = color2index(&cellfg, TRUE, &bold);
+ int bg = color2index(&cellbg, FALSE, &bold);
+
+ /* Use the "Terminal" highlighting for the default colors. */
+ if ((fg == 0 || bg == 0) && t_colors >= 16)
+ {
+ if (fg == 0 && term_default_cterm_fg >= 0)
+ fg = term_default_cterm_fg + 1;
+ if (bg == 0 && term_default_cterm_bg >= 0)
+ bg = term_default_cterm_bg + 1;
+ }
+
+ /* with 8 colors set the bold attribute to get a bright foreground */
+ if (bold == TRUE)
+ attr |= HL_BOLD;
+ return get_cterm_attr_idx(attr, fg, bg);
+ }
+ return 0;
+}
+
+ static void
+set_dirty_snapshot(term_T *term)
+{
+ term->tl_dirty_snapshot = TRUE;
+#ifdef FEAT_TIMERS
+ if (!term->tl_normal_mode)
+ {
+ /* Update the snapshot after 100 msec of not getting updates. */
+ profile_setlimit(100L, &term->tl_timer_due);
+ term->tl_timer_set = TRUE;
+ }
+#endif
+}
+
+ static int
+handle_damage(VTermRect rect, void *user)
+{
+ term_T *term = (term_T *)user;
+
+ term->tl_dirty_row_start = MIN(term->tl_dirty_row_start, rect.start_row);
+ term->tl_dirty_row_end = MAX(term->tl_dirty_row_end, rect.end_row);
+ set_dirty_snapshot(term);
+ redraw_buf_later(term->tl_buffer, SOME_VALID);
+ return 1;
+}
+
+ static void
+term_scroll_up(term_T *term, int start_row, int count)
+{
+ win_T *wp;
+ VTermColor fg, bg;
+ VTermScreenCellAttrs attr;
+ int clear_attr;
+
+ /* Set the color to clear lines with. */
+ vterm_state_get_default_colors(vterm_obtain_state(term->tl_vterm),
+ &fg, &bg);
+ vim_memset(&attr, 0, sizeof(attr));
+ clear_attr = cell2attr(attr, fg, bg);
+
+ FOR_ALL_WINDOWS(wp)
+ {
+ if (wp->w_buffer == term->tl_buffer)
+ win_del_lines(wp, start_row, count, FALSE, FALSE, clear_attr);
+ }
+}
+
+ static int
+handle_moverect(VTermRect dest, VTermRect src, void *user)
+{
+ term_T *term = (term_T *)user;
+ int count = src.start_row - dest.start_row;
+
+ /* Scrolling up is done much more efficiently by deleting lines instead of
+ * redrawing the text. But avoid doing this multiple times, postpone until
+ * the redraw happens. */
+ if (dest.start_col == src.start_col
+ && dest.end_col == src.end_col
+ && dest.start_row < src.start_row)
+ {
+ if (dest.start_row == 0)
+ term->tl_postponed_scroll += count;
+ else
+ term_scroll_up(term, dest.start_row, count);
+ }
+
+ term->tl_dirty_row_start = MIN(term->tl_dirty_row_start, dest.start_row);
+ term->tl_dirty_row_end = MIN(term->tl_dirty_row_end, dest.end_row);
+ set_dirty_snapshot(term);
+
+ /* Note sure if the scrolling will work correctly, let's do a complete
+ * redraw later. */
+ redraw_buf_later(term->tl_buffer, NOT_VALID);
+ return 1;
+}
+
+ static int
+handle_movecursor(
+ VTermPos pos,
+ VTermPos oldpos UNUSED,
+ int visible,
+ void *user)
+{
+ term_T *term = (term_T *)user;
+ win_T *wp;
+
+ term->tl_cursor_pos = pos;
+ term->tl_cursor_visible = visible;
+
+ FOR_ALL_WINDOWS(wp)
+ {
+ if (wp->w_buffer == term->tl_buffer)
+ position_cursor(wp, &pos);
+ }
+ if (term->tl_buffer == curbuf && !term->tl_normal_mode)
+ {
+ may_toggle_cursor(term);
+ update_cursor(term, term->tl_cursor_visible);
+ }
+
+ return 1;
+}
+
+ static int
+handle_settermprop(
+ VTermProp prop,
+ VTermValue *value,
+ void *user)
+{
+ term_T *term = (term_T *)user;
+
+ switch (prop)
+ {
+ case VTERM_PROP_TITLE:
+ vim_free(term->tl_title);
+ // a blank title isn't useful, make it empty, so that "running" is
+ // displayed
+ if (*skipwhite((char_u *)value->string) == NUL)
+ term->tl_title = NULL;
+ // Same as blank
+ else if (term->tl_arg0_cmd != NULL
+ && STRNCMP(term->tl_arg0_cmd, (char_u *)value->string,
+ (int)STRLEN(term->tl_arg0_cmd)) == 0)
+ term->tl_title = NULL;
+ // Empty corrupted data of winpty
+ else if (STRNCMP(" - ", (char_u *)value->string, 4) == 0)
+ term->tl_title = NULL;
+#ifdef WIN3264
+ else if (!enc_utf8 && enc_codepage > 0)
+ {
+ WCHAR *ret = NULL;
+ int length = 0;
+
+ MultiByteToWideChar_alloc(CP_UTF8, 0,
+ (char*)value->string, (int)STRLEN(value->string),
+ &ret, &length);
+ if (ret != NULL)
+ {
+ WideCharToMultiByte_alloc(enc_codepage, 0,
+ ret, length, (char**)&term->tl_title,
+ &length, 0, 0);
+ vim_free(ret);
+ }
+ }
+#endif
+ else
+ term->tl_title = vim_strsave((char_u *)value->string);
+ VIM_CLEAR(term->tl_status_text);
+ if (term == curbuf->b_term)
+ maketitle();
+ break;
+
+ case VTERM_PROP_CURSORVISIBLE:
+ term->tl_cursor_visible = value->boolean;
+ may_toggle_cursor(term);
+ out_flush();
+ break;
+
+ case VTERM_PROP_CURSORBLINK:
+ term->tl_cursor_blink = value->boolean;
+ may_set_cursor_props(term);
+ break;
+
+ case VTERM_PROP_CURSORSHAPE:
+ term->tl_cursor_shape = value->number;
+ may_set_cursor_props(term);
+ break;
+
+ case VTERM_PROP_CURSORCOLOR:
+ cursor_color_copy(&term->tl_cursor_color, (char_u*)value->string);
+ may_set_cursor_props(term);
+ break;
+
+ case VTERM_PROP_ALTSCREEN:
+ /* TODO: do anything else? */
+ term->tl_using_altscreen = value->boolean;
+ break;
+
+ default:
+ break;
+ }
+ /* Always return 1, otherwise vterm doesn't store the value internally. */
+ return 1;
+}
+
+/*
+ * The job running in the terminal resized the terminal.
+ */
+ static int
+handle_resize(int rows, int cols, void *user)
+{
+ term_T *term = (term_T *)user;
+ win_T *wp;
+
+ term->tl_rows = rows;
+ term->tl_cols = cols;
+ if (term->tl_vterm_size_changed)
+ /* Size was set by vterm_set_size(), don't set the window size. */
+ term->tl_vterm_size_changed = FALSE;
+ else
+ {
+ FOR_ALL_WINDOWS(wp)
+ {
+ if (wp->w_buffer == term->tl_buffer)
+ {
+ win_setheight_win(rows, wp);
+ win_setwidth_win(cols, wp);
+ }
+ }
+ redraw_buf_later(term->tl_buffer, NOT_VALID);
+ }
+ return 1;
+}
+
+/*
+ * Handle a line that is pushed off the top of the screen.
+ */
+ static int
+handle_pushline(int cols, const VTermScreenCell *cells, void *user)
+{
+ term_T *term = (term_T *)user;
+
+ /* First remove the lines that were appended before, the pushed line goes
+ * above it. */
+ cleanup_scrollback(term);
+
+ /* If the number of lines that are stored goes over 'termscrollback' then
+ * delete the first 10%. */
+ if (term->tl_scrollback.ga_len >= term->tl_buffer->b_p_twsl)
+ {
+ int todo = term->tl_buffer->b_p_twsl / 10;
+ int i;
+
+ curbuf = term->tl_buffer;
+ for (i = 0; i < todo; ++i)
+ {
+ vim_free(((sb_line_T *)term->tl_scrollback.ga_data + i)->sb_cells);
+ ml_delete(1, FALSE);
+ }
+ curbuf = curwin->w_buffer;
+
+ term->tl_scrollback.ga_len -= todo;
+ mch_memmove(term->tl_scrollback.ga_data,
+ (sb_line_T *)term->tl_scrollback.ga_data + todo,
+ sizeof(sb_line_T) * term->tl_scrollback.ga_len);
+ term->tl_scrollback_scrolled -= todo;
+ }
+
+ if (ga_grow(&term->tl_scrollback, 1) == OK)
+ {
+ cellattr_T *p = NULL;
+ int len = 0;
+ int i;
+ int c;
+ int col;
+ sb_line_T *line;
+ garray_T ga;
+ cellattr_T fill_attr = term->tl_default_color;
+
+ /* do not store empty cells at the end */
+ for (i = 0; i < cols; ++i)
+ if (cells[i].chars[0] != 0)
+ len = i + 1;
+ else
+ cell2cellattr(&cells[i], &fill_attr);
+
+ ga_init2(&ga, 1, 100);
+ if (len > 0)
+ p = (cellattr_T *)alloc((int)sizeof(cellattr_T) * len);
+ if (p != NULL)
+ {
+ for (col = 0; col < len; col += cells[col].width)
+ {
+ if (ga_grow(&ga, MB_MAXBYTES) == FAIL)
+ {
+ ga.ga_len = 0;
+ break;
+ }
+ for (i = 0; (c = cells[col].chars[i]) > 0 || i == 0; ++i)
+ ga.ga_len += utf_char2bytes(c == NUL ? ' ' : c,
+ (char_u *)ga.ga_data + ga.ga_len);
+ cell2cellattr(&cells[col], &p[col]);
+ }
+ }
+ if (ga_grow(&ga, 1) == FAIL)
+ add_scrollback_line_to_buffer(term, (char_u *)"", 0);
+ else
+ {
+ *((char_u *)ga.ga_data + ga.ga_len) = NUL;
+ add_scrollback_line_to_buffer(term, ga.ga_data, ga.ga_len);
+ }
+ ga_clear(&ga);
+
+ line = (sb_line_T *)term->tl_scrollback.ga_data
+ + term->tl_scrollback.ga_len;
+ line->sb_cols = len;
+ line->sb_cells = p;
+ line->sb_fill_attr = fill_attr;
+ ++term->tl_scrollback.ga_len;
+ ++term->tl_scrollback_scrolled;
+ }
+ return 0; /* ignored */
+}
+
+static VTermScreenCallbacks screen_callbacks = {
+ handle_damage, /* damage */
+ handle_moverect, /* moverect */
+ handle_movecursor, /* movecursor */
+ handle_settermprop, /* settermprop */
+ NULL, /* bell */
+ handle_resize, /* resize */
+ handle_pushline, /* sb_pushline */
+ NULL /* sb_popline */
+};
+
+/*
+ * Do the work after the channel of a terminal was closed.
+ * Must be called only when updating_screen is FALSE.
+ * Returns TRUE when a buffer was closed (list of terminals may have changed).
+ */
+ static int
+term_after_channel_closed(term_T *term)
+{
+ /* Unless in Terminal-Normal mode: clear the vterm. */
+ if (!term->tl_normal_mode)
+ {
+ int fnum = term->tl_buffer->b_fnum;
+
+ cleanup_vterm(term);
+
+ if (term->tl_finish == TL_FINISH_CLOSE)
+ {
+ aco_save_T aco;
+ int do_set_w_closing = term->tl_buffer->b_nwindows == 0;
+
+ // ++close or term_finish == "close"
+ ch_log(NULL, "terminal job finished, closing window");
+ aucmd_prepbuf(&aco, term->tl_buffer);
+ // Avoid closing the window if we temporarily use it.
+ if (do_set_w_closing)
+ curwin->w_closing = TRUE;
+ do_bufdel(DOBUF_WIPE, (char_u *)"", 1, fnum, fnum, FALSE);
+ if (do_set_w_closing)
+ curwin->w_closing = FALSE;
+ aucmd_restbuf(&aco);
+ return TRUE;
+ }
+ if (term->tl_finish == TL_FINISH_OPEN
+ && term->tl_buffer->b_nwindows == 0)
+ {
+ char buf[50];
+
+ /* TODO: use term_opencmd */
+ ch_log(NULL, "terminal job finished, opening window");
+ vim_snprintf(buf, sizeof(buf),
+ term->tl_opencmd == NULL
+ ? "botright sbuf %d"
+ : (char *)term->tl_opencmd, fnum);
+ do_cmdline_cmd((char_u *)buf);
+ }
+ else
+ ch_log(NULL, "terminal job finished");
+ }
+
+ redraw_buf_and_status_later(term->tl_buffer, NOT_VALID);
+ return FALSE;
+}
+
+/*
+ * Called when a channel has been closed.
+ * If this was a channel for a terminal window then finish it up.
+ */
+ void
+term_channel_closed(channel_T *ch)
+{
+ term_T *term;
+ term_T *next_term;
+ int did_one = FALSE;
+
+ for (term = first_term; term != NULL; term = next_term)
+ {
+ next_term = term->tl_next;
+ if (term->tl_job == ch->ch_job)
+ {
+ term->tl_channel_closed = TRUE;
+ did_one = TRUE;
+
+ VIM_CLEAR(term->tl_title);
+ VIM_CLEAR(term->tl_status_text);
+#ifdef WIN3264
+ if (term->tl_out_fd != NULL)
+ {
+ fclose(term->tl_out_fd);
+ term->tl_out_fd = NULL;
+ }
+#endif
+
+ if (updating_screen)
+ {
+ /* Cannot open or close windows now. Can happen when
+ * 'lazyredraw' is set. */
+ term->tl_channel_recently_closed = TRUE;
+ continue;
+ }
+
+ if (term_after_channel_closed(term))
+ next_term = first_term;
+ }
+ }
+
+ if (did_one)
+ {
+ redraw_statuslines();
+
+ /* Need to break out of vgetc(). */
+ ins_char_typebuf(K_IGNORE);
+ typebuf_was_filled = TRUE;
+
+ term = curbuf->b_term;
+ if (term != NULL)
+ {
+ if (term->tl_job == ch->ch_job)
+ maketitle();
+ update_cursor(term, term->tl_cursor_visible);
+ }
+ }
+}
+
+/*
+ * To be called after resetting updating_screen: handle any terminal where the
+ * channel was closed.
+ */
+ void
+term_check_channel_closed_recently()
+{
+ term_T *term;
+ term_T *next_term;
+
+ for (term = first_term; term != NULL; term = next_term)
+ {
+ next_term = term->tl_next;
+ if (term->tl_channel_recently_closed)
+ {
+ term->tl_channel_recently_closed = FALSE;
+ if (term_after_channel_closed(term))
+ // start over, the list may have changed
+ next_term = first_term;
+ }
+ }
+}
+
+/*
+ * Fill one screen line from a line of the terminal.
+ * Advances "pos" to past the last column.
+ */
+ static void
+term_line2screenline(VTermScreen *screen, VTermPos *pos, int max_col)
+{
+ int off = screen_get_current_line_off();
+
+ for (pos->col = 0; pos->col < max_col; )
+ {
+ VTermScreenCell cell;
+ int c;
+
+ if (vterm_screen_get_cell(screen, *pos, &cell) == 0)
+ vim_memset(&cell, 0, sizeof(cell));
+
+ c = cell.chars[0];
+ if (c == NUL)
+ {
+ ScreenLines[off] = ' ';
+ if (enc_utf8)
+ ScreenLinesUC[off] = NUL;
+ }
+ else
+ {
+ if (enc_utf8)
+ {
+ int i;
+
+ /* composing chars */
+ for (i = 0; i < Screen_mco
+ && i + 1 < VTERM_MAX_CHARS_PER_CELL; ++i)
+ {
+ ScreenLinesC[i][off] = cell.chars[i + 1];
+ if (cell.chars[i + 1] == 0)
+ break;
+ }
+ if (c >= 0x80 || (Screen_mco > 0
+ && ScreenLinesC[0][off] != 0))
+ {
+ ScreenLines[off] = ' ';
+ ScreenLinesUC[off] = c;
+ }
+ else
+ {
+ ScreenLines[off] = c;
+ ScreenLinesUC[off] = NUL;
+ }
+ }
+#ifdef WIN3264
+ else if (has_mbyte && c >= 0x80)
+ {
+ char_u mb[MB_MAXBYTES+1];
+ WCHAR wc = c;
+
+ if (WideCharToMultiByte(GetACP(), 0, &wc, 1,
+ (char*)mb, 2, 0, 0) > 1)
+ {
+ ScreenLines[off] = mb[0];
+ ScreenLines[off + 1] = mb[1];
+ cell.width = mb_ptr2cells(mb);
+ }
+ else
+ ScreenLines[off] = c;
+ }
+#endif
+ else
+ ScreenLines[off] = c;
+ }
+ ScreenAttrs[off] = cell2attr(cell.attrs, cell.fg, cell.bg);
+
+ ++pos->col;
+ ++off;
+ if (cell.width == 2)
+ {
+ if (enc_utf8)
+ ScreenLinesUC[off] = NUL;
+
+ /* don't set the second byte to NUL for a DBCS encoding, it
+ * has been set above */
+ if (enc_utf8 || !has_mbyte)
+ ScreenLines[off] = NUL;
+
+ ++pos->col;
+ ++off;
+ }
+ }
+}
+
+#if defined(FEAT_GUI)
+ static void
+update_system_term(term_T *term)
+{
+ VTermPos pos;
+ VTermScreen *screen;
+
+ if (term->tl_vterm == NULL)
+ return;
+ screen = vterm_obtain_screen(term->tl_vterm);
+
+ /* Scroll up to make more room for terminal lines if needed. */
+ while (term->tl_toprow > 0
+ && (Rows - term->tl_toprow) < term->tl_dirty_row_end)
+ {
+ int save_p_more = p_more;
+
+ p_more = FALSE;
+ msg_row = Rows - 1;
+ msg_puts("\n");
+ p_more = save_p_more;
+ --term->tl_toprow;
+ }
+
+ for (pos.row = term->tl_dirty_row_start; pos.row < term->tl_dirty_row_end
+ && pos.row < Rows; ++pos.row)
+ {
+ if (pos.row < term->tl_rows)
+ {
+ int max_col = MIN(Columns, term->tl_cols);
+
+ term_line2screenline(screen, &pos, max_col);
+ }
+ else
+ pos.col = 0;
+
+ screen_line(term->tl_toprow + pos.row, 0, pos.col, Columns, FALSE);
+ }
+
+ term->tl_dirty_row_start = MAX_ROW;
+ term->tl_dirty_row_end = 0;
+ update_cursor(term, TRUE);
+}
+#endif
+
+/*
+ * Return TRUE if window "wp" is to be redrawn with term_update_window().
+ * Returns FALSE when there is no terminal running in this window or it is in
+ * Terminal-Normal mode.
+ */
+ int
+term_do_update_window(win_T *wp)
+{
+ term_T *term = wp->w_buffer->b_term;
+
+ return term != NULL && term->tl_vterm != NULL && !term->tl_normal_mode;
+}
+
+/*
+ * Called to update a window that contains an active terminal.
+ */
+ void
+term_update_window(win_T *wp)
+{
+ term_T *term = wp->w_buffer->b_term;
+ VTerm *vterm;
+ VTermScreen *screen;
+ VTermState *state;
+ VTermPos pos;
+ int rows, cols;
+ int newrows, newcols;
+ int minsize;
+ win_T *twp;
+
+ vterm = term->tl_vterm;
+ screen = vterm_obtain_screen(vterm);
+ state = vterm_obtain_state(vterm);
+
+ /* We use NOT_VALID on a resize or scroll, redraw everything then. With
+ * SOME_VALID only redraw what was marked dirty. */
+ if (wp->w_redr_type > SOME_VALID)
+ {
+ term->tl_dirty_row_start = 0;
+ term->tl_dirty_row_end = MAX_ROW;
+
+ if (term->tl_postponed_scroll > 0
+ && term->tl_postponed_scroll < term->tl_rows / 3)
+ /* Scrolling is usually faster than redrawing, when there are only
+ * a few lines to scroll. */
+ term_scroll_up(term, 0, term->tl_postponed_scroll);
+ term->tl_postponed_scroll = 0;
+ }
+
+ /*
+ * If the window was resized a redraw will be triggered and we get here.
+ * Adjust the size of the vterm unless 'termwinsize' specifies a fixed size.
+ */
+ minsize = parse_termwinsize(wp, &rows, &cols);
+
+ newrows = 99999;
+ newcols = 99999;
+ FOR_ALL_WINDOWS(twp)
+ {
+ /* When more than one window shows the same terminal, use the
+ * smallest size. */
+ if (twp->w_buffer == term->tl_buffer)
+ {
+ newrows = MIN(newrows, twp->w_height);
+ newcols = MIN(newcols, twp->w_width);
+ }
+ }
+ newrows = rows == 0 ? newrows : minsize ? MAX(rows, newrows) : rows;
+ newcols = cols == 0 ? newcols : minsize ? MAX(cols, newcols) : cols;
+
+ if (term->tl_rows != newrows || term->tl_cols != newcols)
+ {
+ term->tl_vterm_size_changed = TRUE;
+ vterm_set_size(vterm, newrows, newcols);
+ ch_log(term->tl_job->jv_channel, "Resizing terminal to %d lines",
+ newrows);
+ term_report_winsize(term, newrows, newcols);
+
+ // Updating the terminal size will cause the snapshot to be cleared.
+ // When not in terminal_loop() we need to restore it.
+ if (term != in_terminal_loop)
+ may_move_terminal_to_buffer(term, FALSE);
+ }
+
+ /* The cursor may have been moved when resizing. */
+ vterm_state_get_cursorpos(state, &pos);
+ position_cursor(wp, &pos);
+
+ for (pos.row = term->tl_dirty_row_start; pos.row < term->tl_dirty_row_end
+ && pos.row < wp->w_height; ++pos.row)
+ {
+ if (pos.row < term->tl_rows)
+ {
+ int max_col = MIN(wp->w_width, term->tl_cols);
+
+ term_line2screenline(screen, &pos, max_col);
+ }
+ else
+ pos.col = 0;
+
+ screen_line(wp->w_winrow + pos.row
+#ifdef FEAT_MENU
+ + winbar_height(wp)
+#endif
+ , wp->w_wincol, pos.col, wp->w_width, FALSE);
+ }
+ term->tl_dirty_row_start = MAX_ROW;
+ term->tl_dirty_row_end = 0;
+}
+
+/*
+ * Return TRUE if "wp" is a terminal window where the job has finished.
+ */
+ int
+term_is_finished(buf_T *buf)
+{
+ return buf->b_term != NULL && buf->b_term->tl_vterm == NULL;
+}
+
+/*
+ * Return TRUE if "wp" is a terminal window where the job has finished or we
+ * are in Terminal-Normal mode, thus we show the buffer contents.
+ */
+ int
+term_show_buffer(buf_T *buf)
+{
+ term_T *term = buf->b_term;
+
+ return term != NULL && (term->tl_vterm == NULL || term->tl_normal_mode);
+}
+
+/*
+ * The current buffer is going to be changed. If there is terminal
+ * highlighting remove it now.
+ */
+ void
+term_change_in_curbuf(void)
+{
+ term_T *term = curbuf->b_term;
+
+ if (term_is_finished(curbuf) && term->tl_scrollback.ga_len > 0)
+ {
+ free_scrollback(term);
+ redraw_buf_later(term->tl_buffer, NOT_VALID);
+
+ /* The buffer is now like a normal buffer, it cannot be easily
+ * abandoned when changed. */
+ set_string_option_direct((char_u *)"buftype", -1,
+ (char_u *)"", OPT_FREE|OPT_LOCAL, 0);
+ }
+}
+
+/*
+ * Get the screen attribute for a position in the buffer.
+ * Use a negative "col" to get the filler background color.
+ */
+ int
+term_get_attr(buf_T *buf, linenr_T lnum, int col)
+{
+ term_T *term = buf->b_term;
+ sb_line_T *line;
+ cellattr_T *cellattr;
+
+ if (lnum > term->tl_scrollback.ga_len)
+ cellattr = &term->tl_default_color;
+ else
+ {
+ line = (sb_line_T *)term->tl_scrollback.ga_data + lnum - 1;
+ if (col < 0 || col >= line->sb_cols)
+ cellattr = &line->sb_fill_attr;
+ else
+ cellattr = line->sb_cells + col;
+ }
+ return cell2attr(cellattr->attrs, cellattr->fg, cellattr->bg);
+}
+
+/*
+ * Convert a cterm color number 0 - 255 to RGB.
+ * This is compatible with xterm.
+ */
+ static void
+cterm_color2vterm(int nr, VTermColor *rgb)
+{
+ cterm_color2rgb(nr, &rgb->red, &rgb->green, &rgb->blue, &rgb->ansi_index);
+}
+
+/*
+ * Initialize term->tl_default_color from the environment.
+ */
+ static void
+init_default_colors(term_T *term)
+{
+ VTermColor *fg, *bg;
+ int fgval, bgval;
+ int id;
+
+ vim_memset(&term->tl_default_color.attrs, 0, sizeof(VTermScreenCellAttrs));
+ term->tl_default_color.width = 1;
+ fg = &term->tl_default_color.fg;
+ bg = &term->tl_default_color.bg;
+
+ /* Vterm uses a default black background. Set it to white when
+ * 'background' is "light". */
+ if (*p_bg == 'l')
+ {
+ fgval = 0;
+ bgval = 255;
+ }
+ else
+ {
+ fgval = 255;
+ bgval = 0;
+ }
+ fg->red = fg->green = fg->blue = fgval;
+ bg->red = bg->green = bg->blue = bgval;
+ fg->ansi_index = bg->ansi_index = VTERM_ANSI_INDEX_DEFAULT;
+
+ /* The "Terminal" highlight group overrules the defaults. */
+ id = syn_name2id((char_u *)"Terminal");
+
+ /* Use the actual color for the GUI and when 'termguicolors' is set. */
+#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
+ if (0
+# ifdef FEAT_GUI
+ || gui.in_use
+# endif
+# ifdef FEAT_TERMGUICOLORS
+ || p_tgc
+# ifdef FEAT_VTP
+ /* Finally get INVALCOLOR on this execution path */
+ || (!p_tgc && t_colors >= 256)
+# endif
+# endif
+ )
+ {
+ guicolor_T fg_rgb = INVALCOLOR;
+ guicolor_T bg_rgb = INVALCOLOR;
+
+ if (id != 0)
+ syn_id2colors(id, &fg_rgb, &bg_rgb);
+
+# ifdef FEAT_GUI
+ if (gui.in_use)
+ {
+ if (fg_rgb == INVALCOLOR)
+ fg_rgb = gui.norm_pixel;
+ if (bg_rgb == INVALCOLOR)
+ bg_rgb = gui.back_pixel;
+ }
+# ifdef FEAT_TERMGUICOLORS
+ else
+# endif
+# endif
+# ifdef FEAT_TERMGUICOLORS
+ {
+ if (fg_rgb == INVALCOLOR)
+ fg_rgb = cterm_normal_fg_gui_color;
+ if (bg_rgb == INVALCOLOR)
+ bg_rgb = cterm_normal_bg_gui_color;
+ }
+# endif
+ if (fg_rgb != INVALCOLOR)
+ {
+ long_u rgb = GUI_MCH_GET_RGB(fg_rgb);
+
+ fg->red = (unsigned)(rgb >> 16);
+ fg->green = (unsigned)(rgb >> 8) & 255;
+ fg->blue = (unsigned)rgb & 255;
+ }
+ if (bg_rgb != INVALCOLOR)
+ {
+ long_u rgb = GUI_MCH_GET_RGB(bg_rgb);
+
+ bg->red = (unsigned)(rgb >> 16);
+ bg->green = (unsigned)(rgb >> 8) & 255;
+ bg->blue = (unsigned)rgb & 255;
+ }
+ }
+ else
+#endif
+ if (id != 0 && t_colors >= 16)
+ {
+ if (term_default_cterm_fg >= 0)
+ cterm_color2vterm(term_default_cterm_fg, fg);
+ if (term_default_cterm_bg >= 0)
+ cterm_color2vterm(term_default_cterm_bg, bg);
+ }
+ else
+ {
+#if defined(WIN3264) && !defined(FEAT_GUI_W32)
+ int tmp;
+#endif
+
+ /* In an MS-Windows console we know the normal colors. */
+ if (cterm_normal_fg_color > 0)
+ {
+ cterm_color2vterm(cterm_normal_fg_color - 1, fg);
+# if defined(WIN3264) && !defined(FEAT_GUI_W32)
+ tmp = fg->red;
+ fg->red = fg->blue;
+ fg->blue = tmp;
+# endif
+ }
+# ifdef FEAT_TERMRESPONSE
+ else
+ term_get_fg_color(&fg->red, &fg->green, &fg->blue);
+# endif
+
+ if (cterm_normal_bg_color > 0)
+ {
+ cterm_color2vterm(cterm_normal_bg_color - 1, bg);
+# if defined(WIN3264) && !defined(FEAT_GUI_W32)
+ tmp = bg->red;
+ bg->red = bg->blue;
+ bg->blue = tmp;
+# endif
+ }
+# ifdef FEAT_TERMRESPONSE
+ else
+ term_get_bg_color(&bg->red, &bg->green, &bg->blue);
+# endif
+ }
+}
+
+#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
+/*
+ * Set the 16 ANSI colors from array of RGB values
+ */
+ static void
+set_vterm_palette(VTerm *vterm, long_u *rgb)
+{
+ int index = 0;
+ VTermState *state = vterm_obtain_state(vterm);
+
+ for (; index < 16; index++)
+ {
+ VTermColor color;
+ color.red = (unsigned)(rgb[index] >> 16);
+ color.green = (unsigned)(rgb[index] >> 8) & 255;
+ color.blue = (unsigned)rgb[index] & 255;
+ vterm_state_set_palette_color(state, index, &color);
+ }
+}
+
+/*
+ * Set the ANSI color palette from a list of colors
+ */
+ static int
+set_ansi_colors_list(VTerm *vterm, list_T *list)
+{
+ int n = 0;
+ long_u rgb[16];
+ listitem_T *li = list->lv_first;
+
+ for (; li != NULL && n < 16; li = li->li_next, n++)
+ {
+ char_u *color_name;
+ guicolor_T guicolor;
+
+ color_name = tv_get_string_chk(&li->li_tv);
+ if (color_name == NULL)
+ return FAIL;
+
+ guicolor = GUI_GET_COLOR(color_name);
+ if (guicolor == INVALCOLOR)
+ return FAIL;
+
+ rgb[n] = GUI_MCH_GET_RGB(guicolor);
+ }
+
+ if (n != 16 || li != NULL)
+ return FAIL;
+
+ set_vterm_palette(vterm, rgb);
+
+ return OK;
+}
+
+/*
+ * Initialize the ANSI color palette from g:terminal_ansi_colors[0:15]
+ */
+ static void
+init_vterm_ansi_colors(VTerm *vterm)
+{
+ dictitem_T *var = find_var((char_u *)"g:terminal_ansi_colors", NULL, TRUE);
+
+ if (var != NULL
+ && (var->di_tv.v_type != VAR_LIST
+ || var->di_tv.vval.v_list == NULL
+ || set_ansi_colors_list(vterm, var->di_tv.vval.v_list) == FAIL))
+ semsg(_(e_invarg2), "g:terminal_ansi_colors");
+}
+#endif
+
+/*
+ * Handles a "drop" command from the job in the terminal.
+ * "item" is the file name, "item->li_next" may have options.
+ */
+ static void
+handle_drop_command(listitem_T *item)
+{
+ char_u *fname = tv_get_string(&item->li_tv);
+ listitem_T *opt_item = item->li_next;
+ int bufnr;
+ win_T *wp;
+ tabpage_T *tp;
+ exarg_T ea;
+ char_u *tofree = NULL;
+
+ bufnr = buflist_add(fname, BLN_LISTED | BLN_NOOPT);
+ FOR_ALL_TAB_WINDOWS(tp, wp)
+ {
+ if (wp->w_buffer->b_fnum == bufnr)
+ {
+ /* buffer is in a window already, go there */
+ goto_tabpage_win(tp, wp);
+ return;
+ }
+ }
+
+ vim_memset(&ea, 0, sizeof(ea));
+
+ if (opt_item != NULL && opt_item->li_tv.v_type == VAR_DICT
+ && opt_item->li_tv.vval.v_dict != NULL)
+ {
+ dict_T *dict = opt_item->li_tv.vval.v_dict;
+ char_u *p;
+
+ p = dict_get_string(dict, (char_u *)"ff", FALSE);
+ if (p == NULL)
+ p = dict_get_string(dict, (char_u *)"fileformat", FALSE);
+ if (p != NULL)
+ {
+ if (check_ff_value(p) == FAIL)
+ ch_log(NULL, "Invalid ff argument to drop: %s", p);
+ else
+ ea.force_ff = *p;
+ }
+ p = dict_get_string(dict, (char_u *)"enc", FALSE);
+ if (p == NULL)
+ p = dict_get_string(dict, (char_u *)"encoding", FALSE);
+ if (p != NULL)
+ {
+ ea.cmd = alloc((int)STRLEN(p) + 12);
+ if (ea.cmd != NULL)
+ {
+ sprintf((char *)ea.cmd, "sbuf ++enc=%s", p);
+ ea.force_enc = 11;
+ tofree = ea.cmd;
+ }
+ }
+
+ p = dict_get_string(dict, (char_u *)"bad", FALSE);
+ if (p != NULL)
+ get_bad_opt(p, &ea);
+
+ if (dict_find(dict, (char_u *)"bin", -1) != NULL)
+ ea.force_bin = FORCE_BIN;
+ if (dict_find(dict, (char_u *)"binary", -1) != NULL)
+ ea.force_bin = FORCE_BIN;
+ if (dict_find(dict, (char_u *)"nobin", -1) != NULL)
+ ea.force_bin = FORCE_NOBIN;
+ if (dict_find(dict, (char_u *)"nobinary", -1) != NULL)
+ ea.force_bin = FORCE_NOBIN;
+ }
+
+ /* open in new window, like ":split fname" */
+ if (ea.cmd == NULL)
+ ea.cmd = (char_u *)"split";
+ ea.arg = fname;
+ ea.cmdidx = CMD_split;
+ ex_splitview(&ea);
+
+ vim_free(tofree);
+}
+
+/*
+ * Handles a function call from the job running in a terminal.
+ * "item" is the function name, "item->li_next" has the arguments.
+ */
+ static void
+handle_call_command(term_T *term, channel_T *channel, listitem_T *item)
+{
+ char_u *func;
+ typval_T argvars[2];
+ typval_T rettv;
+ int doesrange;
+
+ if (item->li_next == NULL)
+ {
+ ch_log(channel, "Missing function arguments for call");
+ return;
+ }
+ func = tv_get_string(&item->li_tv);
+
+ if (STRNCMP(func, "Tapi_", 5) != 0)
+ {
+ ch_log(channel, "Invalid function name: %s", func);
+ return;
+ }
+
+ argvars[0].v_type = VAR_NUMBER;
+ argvars[0].vval.v_number = term->tl_buffer->b_fnum;
+ argvars[1] = item->li_next->li_tv;
+ if (call_func(func, (int)STRLEN(func), &rettv,
+ 2, argvars, /* argv_func */ NULL,
+ /* firstline */ 1, /* lastline */ 1,
+ &doesrange, /* evaluate */ TRUE,
+ /* partial */ NULL, /* selfdict */ NULL) == OK)
+ {
+ clear_tv(&rettv);
+ ch_log(channel, "Function %s called", func);
+ }
+ else
+ ch_log(channel, "Calling function %s failed", func);
+}
+
+/*
+ * Called by libvterm when it cannot recognize an OSC sequence.
+ * We recognize a terminal API command.
+ */
+ static int
+parse_osc(const char *command, size_t cmdlen, void *user)
+{
+ term_T *term = (term_T *)user;
+ js_read_T reader;
+ typval_T tv;
+ channel_T *channel = term->tl_job == NULL ? NULL
+ : term->tl_job->jv_channel;
+
+ /* We recognize only OSC 5 1 ; {command} */
+ if (cmdlen < 3 || STRNCMP(command, "51;", 3) != 0)
+ return 0; /* not handled */
+
+ reader.js_buf = vim_strnsave((char_u *)command + 3, (int)(cmdlen - 3));
+ if (reader.js_buf == NULL)
+ return 1;
+ reader.js_fill = NULL;
+ reader.js_used = 0;
+ if (json_decode(&reader, &tv, 0) == OK
+ && tv.v_type == VAR_LIST
+ && tv.vval.v_list != NULL)
+ {
+ listitem_T *item = tv.vval.v_list->lv_first;
+
+ if (item == NULL)
+ ch_log(channel, "Missing command");
+ else
+ {
+ char_u *cmd = tv_get_string(&item->li_tv);
+
+ /* Make sure an invoked command doesn't delete the buffer (and the
+ * terminal) under our fingers. */
+ ++term->tl_buffer->b_locked;
+
+ item = item->li_next;
+ if (item == NULL)
+ ch_log(channel, "Missing argument for %s", cmd);
+ else if (STRCMP(cmd, "drop") == 0)
+ handle_drop_command(item);
+ else if (STRCMP(cmd, "call") == 0)
+ handle_call_command(term, channel, item);
+ else
+ ch_log(channel, "Invalid command received: %s", cmd);
+ --term->tl_buffer->b_locked;
+ }
+ }
+ else
+ ch_log(channel, "Invalid JSON received");
+
+ vim_free(reader.js_buf);
+ clear_tv(&tv);
+ return 1;
+}
+
+static VTermParserCallbacks parser_fallbacks = {
+ NULL, /* text */
+ NULL, /* control */
+ NULL, /* escape */
+ NULL, /* csi */
+ parse_osc, /* osc */
+ NULL, /* dcs */
+ NULL /* resize */
+};
+
+/*
+ * Use Vim's allocation functions for vterm so profiling works.
+ */
+ static void *
+vterm_malloc(size_t size, void *data UNUSED)
+{
+ return alloc_clear((unsigned) size);
+}
+
+ static void
+vterm_memfree(void *ptr, void *data UNUSED)
+{
+ vim_free(ptr);
+}
+
+static VTermAllocatorFunctions vterm_allocator = {
+ &vterm_malloc,
+ &vterm_memfree
+};
+
+/*
+ * Create a new vterm and initialize it.
+ * Return FAIL when out of memory.
+ */
+ static int
+create_vterm(term_T *term, int rows, int cols)
+{
+ VTerm *vterm;
+ VTermScreen *screen;
+ VTermState *state;
+ VTermValue value;
+
+ vterm = vterm_new_with_allocator(rows, cols, &vterm_allocator, NULL);
+ term->tl_vterm = vterm;
+ if (vterm == NULL)
+ return FAIL;
+
+ // Allocate screen and state here, so we can bail out if that fails.
+ state = vterm_obtain_state(vterm);
+ screen = vterm_obtain_screen(vterm);
+ if (state == NULL || screen == NULL)
+ {
+ vterm_free(vterm);
+ return FAIL;
+ }
+
+ vterm_screen_set_callbacks(screen, &screen_callbacks, term);
+ /* TODO: depends on 'encoding'. */
+ vterm_set_utf8(vterm, 1);
+
+ init_default_colors(term);
+
+ vterm_state_set_default_colors(
+ state,
+ &term->tl_default_color.fg,
+ &term->tl_default_color.bg);
+
+ if (t_colors >= 16)
+ vterm_state_set_bold_highbright(vterm_obtain_state(vterm), 1);
+
+ /* Required to initialize most things. */
+ vterm_screen_reset(screen, 1 /* hard */);
+
+ /* Allow using alternate screen. */
+ vterm_screen_enable_altscreen(screen, 1);
+
+ /* For unix do not use a blinking cursor. In an xterm this causes the
+ * cursor to blink if it's blinking in the xterm.
+ * For Windows we respect the system wide setting. */
+#ifdef WIN3264
+ if (GetCaretBlinkTime() == INFINITE)
+ value.boolean = 0;
+ else
+ value.boolean = 1;
+#else
+ value.boolean = 0;
+#endif
+ vterm_state_set_termprop(state, VTERM_PROP_CURSORBLINK, &value);
+ vterm_state_set_unrecognised_fallbacks(state, &parser_fallbacks, term);
+
+ return OK;
+}
+
+/*
+ * Return the text to show for the buffer name and status.
+ */
+ char_u *
+term_get_status_text(term_T *term)
+{
+ if (term->tl_status_text == NULL)
+ {
+ char_u *txt;
+ size_t len;
+
+ if (term->tl_normal_mode)
+ {
+ if (term_job_running(term))
+ txt = (char_u *)_("Terminal");
+ else
+ txt = (char_u *)_("Terminal-finished");
+ }
+ else if (term->tl_title != NULL)
+ txt = term->tl_title;
+ else if (term_none_open(term))
+ txt = (char_u *)_("active");
+ else if (term_job_running(term))
+ txt = (char_u *)_("running");
+ else
+ txt = (char_u *)_("finished");
+ len = 9 + STRLEN(term->tl_buffer->b_fname) + STRLEN(txt);
+ term->tl_status_text = alloc((int)len);
+ if (term->tl_status_text != NULL)
+ vim_snprintf((char *)term->tl_status_text, len, "%s [%s]",
+ term->tl_buffer->b_fname, txt);
+ }
+ return term->tl_status_text;
+}
+
+/*
+ * Mark references in jobs of terminals.
+ */
+ int
+set_ref_in_term(int copyID)
+{
+ int abort = FALSE;
+ term_T *term;
+ typval_T tv;
+
+ for (term = first_term; term != NULL; term = term->tl_next)
+ if (term->tl_job != NULL)
+ {
+ tv.v_type = VAR_JOB;
+ tv.vval.v_job = term->tl_job;
+ abort = abort || set_ref_in_item(&tv, copyID, NULL, NULL);
+ }
+ return abort;
+}
+
+/*
+ * Cache "Terminal" highlight group colors.
+ */
+ void
+set_terminal_default_colors(int cterm_fg, int cterm_bg)
+{
+ term_default_cterm_fg = cterm_fg - 1;
+ term_default_cterm_bg = cterm_bg - 1;
+}
+
+/*
+ * Get the buffer from the first argument in "argvars".
+ * Returns NULL when the buffer is not for a terminal window and logs a message
+ * with "where".
+ */
+ static buf_T *
+term_get_buf(typval_T *argvars, char *where)
+{
+ buf_T *buf;
+
+ (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
+ ++emsg_off;
+ buf = tv_get_buf(&argvars[0], FALSE);
+ --emsg_off;
+ if (buf == NULL || buf->b_term == NULL)
+ {
+ ch_log(NULL, "%s: invalid buffer argument", where);
+ return NULL;
+ }
+ return buf;
+}
+
+ static int
+same_color(VTermColor *a, VTermColor *b)
+{
+ return a->red == b->red
+ && a->green == b->green
+ && a->blue == b->blue
+ && a->ansi_index == b->ansi_index;
+}
+
+ static void
+dump_term_color(FILE *fd, VTermColor *color)
+{
+ fprintf(fd, "%02x%02x%02x%d",
+ (int)color->red, (int)color->green, (int)color->blue,
+ (int)color->ansi_index);
+}
+
+/*
+ * "term_dumpwrite(buf, filename, options)" function
+ *
+ * Each screen cell in full is:
+ * |{characters}+{attributes}#{fg-color}{color-idx}#{bg-color}{color-idx}
+ * {characters} is a space for an empty cell
+ * For a double-width character "+" is changed to "*" and the next cell is
+ * skipped.
+ * {attributes} is the decimal value of HL_BOLD + HL_UNDERLINE, etc.
+ * when "&" use the same as the previous cell.
+ * {fg-color} is hex RGB, when "&" use the same as the previous cell.
+ * {bg-color} is hex RGB, when "&" use the same as the previous cell.
+ * {color-idx} is a number from 0 to 255
+ *
+ * Screen cell with same width, attributes and color as the previous one:
+ * |{characters}
+ *
+ * To use the color of the previous cell, use "&" instead of {color}-{idx}.
+ *
+ * Repeating the previous screen cell:
+ * @{count}
+ */
+ void
+f_term_dumpwrite(typval_T *argvars, typval_T *rettv UNUSED)
+{
+ buf_T *buf = term_get_buf(argvars, "term_dumpwrite()");
+ term_T *term;
+ char_u *fname;
+ int max_height = 0;
+ int max_width = 0;
+ stat_T st;
+ FILE *fd;
+ VTermPos pos;
+ VTermScreen *screen;
+ VTermScreenCell prev_cell;
+ VTermState *state;
+ VTermPos cursor_pos;
+
+ if (check_restricted() || check_secure())
+ return;
+ if (buf == NULL)
+ return;
+ term = buf->b_term;
+ if (term->tl_vterm == NULL)
+ {
+ emsg(_("E958: Job already finished"));
+ return;
+ }
+
+ if (argvars[2].v_type != VAR_UNKNOWN)
+ {
+ dict_T *d;
+
+ if (argvars[2].v_type != VAR_DICT)
+ {
+ emsg(_(e_dictreq));
+ return;
+ }
+ d = argvars[2].vval.v_dict;
+ if (d != NULL)
+ {
+ max_height = dict_get_number(d, (char_u *)"rows");
+ max_width = dict_get_number(d, (char_u *)"columns");
+ }
+ }
+
+ fname = tv_get_string_chk(&argvars[1]);
+ if (fname == NULL)
+ return;
+ if (mch_stat((char *)fname, &st) >= 0)
+ {
+ semsg(_("E953: File exists: %s"), fname);
+ return;
+ }
+
+ if (*fname == NUL || (fd = mch_fopen((char *)fname, WRITEBIN)) == NULL)
+ {
+ semsg(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
+ return;
+ }
+
+ vim_memset(&prev_cell, 0, sizeof(prev_cell));
+
+ screen = vterm_obtain_screen(term->tl_vterm);
+ state = vterm_obtain_state(term->tl_vterm);
+ vterm_state_get_cursorpos(state, &cursor_pos);
+
+ for (pos.row = 0; (max_height == 0 || pos.row < max_height)
+ && pos.row < term->tl_rows; ++pos.row)
+ {
+ int repeat = 0;
+
+ for (pos.col = 0; (max_width == 0 || pos.col < max_width)
+ && pos.col < term->tl_cols; ++pos.col)
+ {
+ VTermScreenCell cell;
+ int same_attr;
+ int same_chars = TRUE;
+ int i;
+ int is_cursor_pos = (pos.col == cursor_pos.col
+ && pos.row == cursor_pos.row);
+
+ if (vterm_screen_get_cell(screen, pos, &cell) == 0)
+ vim_memset(&cell, 0, sizeof(cell));
+
+ for (i = 0; i < VTERM_MAX_CHARS_PER_CELL; ++i)
+ {
+ int c = cell.chars[i];
+ int pc = prev_cell.chars[i];
+
+ /* For the first character NUL is the same as space. */
+ if (i == 0)
+ {
+ c = (c == NUL) ? ' ' : c;
+ pc = (pc == NUL) ? ' ' : pc;
+ }
+ if (c != pc)
+ same_chars = FALSE;
+ if (c == NUL || pc == NUL)
+ break;
+ }
+ same_attr = vtermAttr2hl(cell.attrs)
+ == vtermAttr2hl(prev_cell.attrs)
+ && same_color(&cell.fg, &prev_cell.fg)
+ && same_color(&cell.bg, &prev_cell.bg);
+ if (same_chars && cell.width == prev_cell.width && same_attr
+ && !is_cursor_pos)
+ {
+ ++repeat;
+ }
+ else
+ {
+ if (repeat > 0)
+ {
+ fprintf(fd, "@%d", repeat);
+ repeat = 0;
+ }
+ fputs(is_cursor_pos ? ">" : "|", fd);
+
+ if (cell.chars[0] == NUL)
+ fputs(" ", fd);
+ else
+ {
+ char_u charbuf[10];
+ int len;
+
+ for (i = 0; i < VTERM_MAX_CHARS_PER_CELL
+ && cell.chars[i] != NUL; ++i)
+ {
+ len = utf_char2bytes(cell.chars[i], charbuf);
+ fwrite(charbuf, len, 1, fd);
+ }
+ }
+
+ /* When only the characters differ we don't write anything, the
+ * following "|", "@" or NL will indicate using the same
+ * attributes. */
+ if (cell.width != prev_cell.width || !same_attr)
+ {
+ if (cell.width == 2)
+ {
+ fputs("*", fd);
+ }
+ else
+ fputs("+", fd);
+
+ if (same_attr)
+ {
+ fputs("&", fd);
+ }
+ else
+ {
+ fprintf(fd, "%d", vtermAttr2hl(cell.attrs));
+ if (same_color(&cell.fg, &prev_cell.fg))
+ fputs("&", fd);
+ else
+ {
+ fputs("#", fd);
+ dump_term_color(fd, &cell.fg);
+ }
+ if (same_color(&cell.bg, &prev_cell.bg))
+ fputs("&", fd);
+ else
+ {
+ fputs("#", fd);
+ dump_term_color(fd, &cell.bg);
+ }
+ }
+ }
+
+ prev_cell = cell;
+ }
+
+ if (cell.width == 2)
+ ++pos.col;
+ }
+ if (repeat > 0)
+ fprintf(fd, "@%d", repeat);
+ fputs("\n", fd);
+ }
+
+ fclose(fd);
+}
+
+/*
+ * Called when a dump is corrupted. Put a breakpoint here when debugging.
+ */
+ static void
+dump_is_corrupt(garray_T *gap)
+{
+ ga_concat(gap, (char_u *)"CORRUPT");
+}
+
+ static void
+append_cell(garray_T *gap, cellattr_T *cell)
+{
+ if (ga_grow(gap, 1) == OK)
+ {
+ *(((cellattr_T *)gap->ga_data) + gap->ga_len) = *cell;
+ ++gap->ga_len;
+ }
+}
+
+/*
+ * Read the dump file from "fd" and append lines to the current buffer.
+ * Return the cell width of the longest line.
+ */
+ static int
+read_dump_file(FILE *fd, VTermPos *cursor_pos)
+{
+ int c;
+ garray_T ga_text;
+ garray_T ga_cell;
+ char_u *prev_char = NULL;
+ int attr = 0;
+ cellattr_T cell;
+ cellattr_T empty_cell;
+ term_T *term = curbuf->b_term;
+ int max_cells = 0;
+ int start_row = term->tl_scrollback.ga_len;
+
+ ga_init2(&ga_text, 1, 90);
+ ga_init2(&ga_cell, sizeof(cellattr_T), 90);
+ vim_memset(&cell, 0, sizeof(cell));
+ vim_memset(&empty_cell, 0, sizeof(empty_cell));
+ cursor_pos->row = -1;
+ cursor_pos->col = -1;
+
+ c = fgetc(fd);
+ for (;;)
+ {
+ if (c == EOF)
+ break;
+ if (c == '\r')
+ {
+ // DOS line endings? Ignore.
+ c = fgetc(fd);
+ }
+ else if (c == '\n')
+ {
+ /* End of a line: append it to the buffer. */
+ if (ga_text.ga_data == NULL)
+ dump_is_corrupt(&ga_text);
+ if (ga_grow(&term->tl_scrollback, 1) == OK)
+ {
+ sb_line_T *line = (sb_line_T *)term->tl_scrollback.ga_data
+ + term->tl_scrollback.ga_len;
+
+ if (max_cells < ga_cell.ga_len)
+ max_cells = ga_cell.ga_len;
+ line->sb_cols = ga_cell.ga_len;
+ line->sb_cells = ga_cell.ga_data;
+ line->sb_fill_attr = term->tl_default_color;
+ ++term->tl_scrollback.ga_len;
+ ga_init(&ga_cell);
+
+ ga_append(&ga_text, NUL);
+ ml_append(curbuf->b_ml.ml_line_count, ga_text.ga_data,
+ ga_text.ga_len, FALSE);
+ }
+ else
+ ga_clear(&ga_cell);
+ ga_text.ga_len = 0;
+
+ c = fgetc(fd);
+ }
+ else if (c == '|' || c == '>')
+ {
+ int prev_len = ga_text.ga_len;
+
+ if (c == '>')
+ {
+ if (cursor_pos->row != -1)
+ dump_is_corrupt(&ga_text); /* duplicate cursor */
+ cursor_pos->row = term->tl_scrollback.ga_len - start_row;
+ cursor_pos->col = ga_cell.ga_len;
+ }
+
+ /* normal character(s) followed by "+", "*", "|", "@" or NL */
+ c = fgetc(fd);
+ if (c != EOF)
+ ga_append(&ga_text, c);
+ for (;;)
+ {
+ c = fgetc(fd);
+ if (c == '+' || c == '*' || c == '|' || c == '>' || c == '@'
+ || c == EOF || c == '\n')
+ break;
+ ga_append(&ga_text, c);
+ }
+
+ /* save the character for repeating it */
+ vim_free(prev_char);
+ if (ga_text.ga_data != NULL)
+ prev_char = vim_strnsave(((char_u *)ga_text.ga_data) + prev_len,
+ ga_text.ga_len - prev_len);
+
+ if (c == '@' || c == '|' || c == '>' || c == '\n')
+ {
+ /* use all attributes from previous cell */
+ }
+ else if (c == '+' || c == '*')
+ {
+ int is_bg;
+
+ cell.width = c == '+' ? 1 : 2;
+
+ c = fgetc(fd);
+ if (c == '&')
+ {
+ /* use same attr as previous cell */
+ c = fgetc(fd);
+ }
+ else if (isdigit(c))
+ {
+ /* get the decimal attribute */
+ attr = 0;
+ while (isdigit(c))
+ {
+ attr = attr * 10 + (c - '0');
+ c = fgetc(fd);
+ }
+ hl2vtermAttr(attr, &cell);
+
+ /* is_bg == 0: fg, is_bg == 1: bg */
+ for (is_bg = 0; is_bg <= 1; ++is_bg)
+ {
+ if (c == '&')
+ {
+ /* use same color as previous cell */
+ c = fgetc(fd);
+ }
+ else if (c == '#')
+ {
+ int red, green, blue, index = 0;
+
+ c = fgetc(fd);
+ red = hex2nr(c);
+ c = fgetc(fd);
+ red = (red << 4) + hex2nr(c);
+ c = fgetc(fd);
+ green = hex2nr(c);
+ c = fgetc(fd);
+ green = (green << 4) + hex2nr(c);
+ c = fgetc(fd);
+ blue = hex2nr(c);
+ c = fgetc(fd);
+ blue = (blue << 4) + hex2nr(c);
+ c = fgetc(fd);
+ if (!isdigit(c))
+ dump_is_corrupt(&ga_text);
+ while (isdigit(c))
+ {
+ index = index * 10 + (c - '0');
+ c = fgetc(fd);
+ }
+
+ if (is_bg)
+ {
+ cell.bg.red = red;
+ cell.bg.green = green;
+ cell.bg.blue = blue;
+ cell.bg.ansi_index = index;
+ }
+ else
+ {
+ cell.fg.red = red;
+ cell.fg.green = green;
+ cell.fg.blue = blue;
+ cell.fg.ansi_index = index;
+ }
+ }
+ else
+ dump_is_corrupt(&ga_text);
+ }
+ }
+ else
+ dump_is_corrupt(&ga_text);
+ }
+ else
+ dump_is_corrupt(&ga_text);
+
+ append_cell(&ga_cell, &cell);
+ if (cell.width == 2)
+ append_cell(&ga_cell, &empty_cell);
+ }
+ else if (c == '@')
+ {
+ if (prev_char == NULL)
+ dump_is_corrupt(&ga_text);
+ else
+ {
+ int count = 0;
+
+ /* repeat previous character, get the count */
+ for (;;)
+ {
+ c = fgetc(fd);
+ if (!isdigit(c))
+ break;
+ count = count * 10 + (c - '0');
+ }
+
+ while (count-- > 0)
+ {
+ ga_concat(&ga_text, prev_char);
+ append_cell(&ga_cell, &cell);
+ }
+ }
+ }
+ else
+ {
+ dump_is_corrupt(&ga_text);
+ c = fgetc(fd);
+ }
+ }
+
+ if (ga_text.ga_len > 0)
+ {
+ /* trailing characters after last NL */
+ dump_is_corrupt(&ga_text);
+ ga_append(&ga_text, NUL);
+ ml_append(curbuf->b_ml.ml_line_count, ga_text.ga_data,
+ ga_text.ga_len, FALSE);
+ }
+
+ ga_clear(&ga_text);
+ vim_free(prev_char);
+
+ return max_cells;
+}
+
+/*
+ * Return an allocated string with at least "text_width" "=" characters and
+ * "fname" inserted in the middle.
+ */
+ static char_u *
+get_separator(int text_width, char_u *fname)
+{
+ int width = MAX(text_width, curwin->w_width);
+ char_u *textline;
+ int fname_size;
+ char_u *p = fname;
+ int i;
+ size_t off;
+
+ textline = alloc(width + (int)STRLEN(fname) + 1);
+ if (textline == NULL)
+ return NULL;
+
+ fname_size = vim_strsize(fname);
+ if (fname_size < width - 8)
+ {
+ /* enough room, don't use the full window width */
+ width = MAX(text_width, fname_size + 8);
+ }
+ else if (fname_size > width - 8)
+ {
+ /* full name doesn't fit, use only the tail */
+ p = gettail(fname);
+ fname_size = vim_strsize(p);
+ }
+ /* skip characters until the name fits */
+ while (fname_size > width - 8)
+ {
+ p += (*mb_ptr2len)(p);
+ fname_size = vim_strsize(p);
+ }
+
+ for (i = 0; i < (width - fname_size) / 2 - 1; ++i)
+ textline[i] = '=';
+ textline[i++] = ' ';
+
+ STRCPY(textline + i, p);
+ off = STRLEN(textline);
+ textline[off] = ' ';
+ for (i = 1; i < (width - fname_size) / 2; ++i)
+ textline[off + i] = '=';
+ textline[off + i] = NUL;
+
+ return textline;
+}
+
+/*
+ * Common for "term_dumpdiff()" and "term_dumpload()".
+ */
+ static void
+term_load_dump(typval_T *argvars, typval_T *rettv, int do_diff)
+{
+ jobopt_T opt;
+ buf_T *buf;
+ char_u buf1[NUMBUFLEN];
+ char_u buf2[NUMBUFLEN];
+ char_u *fname1;
+ char_u *fname2 = NULL;
+ char_u *fname_tofree = NULL;
+ FILE *fd1;
+ FILE *fd2 = NULL;
+ char_u *textline = NULL;
+
+ /* First open the files. If this fails bail out. */
+ fname1 = tv_get_string_buf_chk(&argvars[0], buf1);
+ if (do_diff)
+ fname2 = tv_get_string_buf_chk(&argvars[1], buf2);
+ if (fname1 == NULL || (do_diff && fname2 == NULL))
+ {
+ emsg(_(e_invarg));
+ return;
+ }
+ fd1 = mch_fopen((char *)fname1, READBIN);
+ if (fd1 == NULL)
+ {
+ semsg(_(e_notread), fname1);
+ return;
+ }
+ if (do_diff)
+ {
+ fd2 = mch_fopen((char *)fname2, READBIN);
+ if (fd2 == NULL)
+ {
+ fclose(fd1);
+ semsg(_(e_notread), fname2);
+ return;
+ }
+ }
+
+ init_job_options(&opt);
+ if (argvars[do_diff ? 2 : 1].v_type != VAR_UNKNOWN
+ && get_job_options(&argvars[do_diff ? 2 : 1], &opt, 0,
+ JO2_TERM_NAME + JO2_TERM_COLS + JO2_TERM_ROWS
+ + JO2_VERTICAL + JO2_CURWIN + JO2_NORESTORE) == FAIL)
+ goto theend;
+
+ if (opt.jo_term_name == NULL)
+ {
+ size_t len = STRLEN(fname1) + 12;
+
+ fname_tofree = alloc((int)len);
+ if (fname_tofree != NULL)
+ {
+ vim_snprintf((char *)fname_tofree, len, "dump diff %s", fname1);
+ opt.jo_term_name = fname_tofree;
+ }
+ }
+
+ buf = term_start(&argvars[0], NULL, &opt, TERM_START_NOJOB);
+ if (buf != NULL && buf->b_term != NULL)
+ {
+ int i;
+ linenr_T bot_lnum;
+ linenr_T lnum;
+ term_T *term = buf->b_term;
+ int width;
+ int width2;
+ VTermPos cursor_pos1;
+ VTermPos cursor_pos2;
+
+ init_default_colors(term);
+
+ rettv->vval.v_number = buf->b_fnum;
+
+ /* read the files, fill the buffer with the diff */
+ width = read_dump_file(fd1, &cursor_pos1);
+
+ /* position the cursor */
+ if (cursor_pos1.row >= 0)
+ {
+ curwin->w_cursor.lnum = cursor_pos1.row + 1;
+ coladvance(cursor_pos1.col);
+ }
+
+ /* Delete the empty line that was in the empty buffer. */
+ ml_delete(1, FALSE);
+
+ /* For term_dumpload() we are done here. */
+ if (!do_diff)
+ goto theend;
+
+ term->tl_top_diff_rows = curbuf->b_ml.ml_line_count;
+
+ textline = get_separator(width, fname1);
+ if (textline == NULL)
+ goto theend;
+ if (add_empty_scrollback(term, &term->tl_default_color, 0) == OK)
+ ml_append(curbuf->b_ml.ml_line_count, textline, 0, FALSE);
+ vim_free(textline);
+
+ textline = get_separator(width, fname2);
+ if (textline == NULL)
+ goto theend;
+ if (add_empty_scrollback(term, &term->tl_default_color, 0) == OK)
+ ml_append(curbuf->b_ml.ml_line_count, textline, 0, FALSE);
+ textline[width] = NUL;
+
+ bot_lnum = curbuf->b_ml.ml_line_count;
+ width2 = read_dump_file(fd2, &cursor_pos2);
+ if (width2 > width)
+ {
+ vim_free(textline);
+ textline = alloc(width2 + 1);
+ if (textline == NULL)
+ goto theend;
+ width = width2;
+ textline[width] = NUL;
+ }
+ term->tl_bot_diff_rows = curbuf->b_ml.ml_line_count - bot_lnum;
+
+ for (lnum = 1; lnum <= term->tl_top_diff_rows; ++lnum)
+ {
+ if (lnum + bot_lnum > curbuf->b_ml.ml_line_count)
+ {
+ /* bottom part has fewer rows, fill with "-" */
+ for (i = 0; i < width; ++i)
+ textline[i] = '-';
+ }
+ else
+ {
+ char_u *line1;
+ char_u *line2;
+ char_u *p1;
+ char_u *p2;
+ int col;
+ sb_line_T *sb_line = (sb_line_T *)term->tl_scrollback.ga_data;
+ cellattr_T *cellattr1 = (sb_line + lnum - 1)->sb_cells;
+ cellattr_T *cellattr2 = (sb_line + lnum + bot_lnum - 1)
+ ->sb_cells;
+
+ /* Make a copy, getting the second line will invalidate it. */
+ line1 = vim_strsave(ml_get(lnum));
+ if (line1 == NULL)
+ break;
+ p1 = line1;
+
+ line2 = ml_get(lnum + bot_lnum);
+ p2 = line2;
+ for (col = 0; col < width && *p1 != NUL && *p2 != NUL; ++col)
+ {
+ int len1 = utfc_ptr2len(p1);
+ int len2 = utfc_ptr2len(p2);
+
+ textline[col] = ' ';
+ if (len1 != len2 || STRNCMP(p1, p2, len1) != 0)
+ /* text differs */
+ textline[col] = 'X';
+ else if (lnum == cursor_pos1.row + 1
+ && col == cursor_pos1.col
+ && (cursor_pos1.row != cursor_pos2.row
+ || cursor_pos1.col != cursor_pos2.col))
+ /* cursor in first but not in second */
+ textline[col] = '>';
+ else if (lnum == cursor_pos2.row + 1
+ && col == cursor_pos2.col
+ && (cursor_pos1.row != cursor_pos2.row
+ || cursor_pos1.col != cursor_pos2.col))
+ /* cursor in second but not in first */
+ textline[col] = '<';
+ else if (cellattr1 != NULL && cellattr2 != NULL)
+ {
+ if ((cellattr1 + col)->width
+ != (cellattr2 + col)->width)
+ textline[col] = 'w';
+ else if (!same_color(&(cellattr1 + col)->fg,
+ &(cellattr2 + col)->fg))
+ textline[col] = 'f';
+ else if (!same_color(&(cellattr1 + col)->bg,
+ &(cellattr2 + col)->bg))
+ textline[col] = 'b';
+ else if (vtermAttr2hl((cellattr1 + col)->attrs)
+ != vtermAttr2hl(((cellattr2 + col)->attrs)))
+ textline[col] = 'a';
+ }
+ p1 += len1;
+ p2 += len2;
+ /* TODO: handle different width */
+ }
+ vim_free(line1);
+
+ while (col < width)
+ {
+ if (*p1 == NUL && *p2 == NUL)
+ textline[col] = '?';
+ else if (*p1 == NUL)
+ {
+ textline[col] = '+';
+ p2 += utfc_ptr2len(p2);
+ }
+ else
+ {
+ textline[col] = '-';
+ p1 += utfc_ptr2len(p1);
+ }
+ ++col;
+ }
+ }
+ if (add_empty_scrollback(term, &term->tl_default_color,
+ term->tl_top_diff_rows) == OK)
+ ml_append(term->tl_top_diff_rows + lnum, textline, 0, FALSE);
+ ++bot_lnum;
+ }
+
+ while (lnum + bot_lnum <= curbuf->b_ml.ml_line_count)
+ {
+ /* bottom part has more rows, fill with "+" */
+ for (i = 0; i < width; ++i)
+ textline[i] = '+';
+ if (add_empty_scrollback(term, &term->tl_default_color,
+ term->tl_top_diff_rows) == OK)
+ ml_append(term->tl_top_diff_rows + lnum, textline, 0, FALSE);
+ ++lnum;
+ ++bot_lnum;
+ }
+
+ term->tl_cols = width;
+
+ /* looks better without wrapping */
+ curwin->w_p_wrap = 0;
+ }
+
+theend:
+ vim_free(textline);
+ vim_free(fname_tofree);
+ fclose(fd1);
+ if (fd2 != NULL)
+ fclose(fd2);
+}
+
+/*
+ * If the current buffer shows the output of term_dumpdiff(), swap the top and
+ * bottom files.
+ * Return FAIL when this is not possible.
+ */
+ int
+term_swap_diff()
+{
+ term_T *term = curbuf->b_term;
+ linenr_T line_count;
+ linenr_T top_rows;
+ linenr_T bot_rows;
+ linenr_T bot_start;
+ linenr_T lnum;
+ char_u *p;
+ sb_line_T *sb_line;
+
+ if (term == NULL
+ || !term_is_finished(curbuf)
+ || term->tl_top_diff_rows == 0
+ || term->tl_scrollback.ga_len == 0)
+ return FAIL;
+
+ line_count = curbuf->b_ml.ml_line_count;
+ top_rows = term->tl_top_diff_rows;
+ bot_rows = term->tl_bot_diff_rows;
+ bot_start = line_count - bot_rows;
+ sb_line = (sb_line_T *)term->tl_scrollback.ga_data;
+
+ /* move lines from top to above the bottom part */
+ for (lnum = 1; lnum <= top_rows; ++lnum)
+ {
+ p = vim_strsave(ml_get(1));
+ if (p == NULL)
+ return OK;
+ ml_append(bot_start, p, 0, FALSE);
+ ml_delete(1, FALSE);
+ vim_free(p);
+ }
+
+ /* move lines from bottom to the top */
+ for (lnum = 1; lnum <= bot_rows; ++lnum)
+ {
+ p = vim_strsave(ml_get(bot_start + lnum));
+ if (p == NULL)
+ return OK;
+ ml_delete(bot_start + lnum, FALSE);
+ ml_append(lnum - 1, p, 0, FALSE);
+ vim_free(p);
+ }
+
+ if (top_rows == bot_rows)
+ {
+ /* rows counts are equal, can swap cell properties */
+ for (lnum = 0; lnum < top_rows; ++lnum)
+ {
+ sb_line_T temp;
+
+ temp = *(sb_line + lnum);
+ *(sb_line + lnum) = *(sb_line + bot_start + lnum);
+ *(sb_line + bot_start + lnum) = temp;
+ }
+ }
+ else
+ {
+ size_t size = sizeof(sb_line_T) * term->tl_scrollback.ga_len;
+ sb_line_T *temp = (sb_line_T *)alloc((int)size);
+
+ /* need to copy cell properties into temp memory */
+ if (temp != NULL)
+ {
+ mch_memmove(temp, term->tl_scrollback.ga_data, size);
+ mch_memmove(term->tl_scrollback.ga_data,
+ temp + bot_start,
+ sizeof(sb_line_T) * bot_rows);
+ mch_memmove((sb_line_T *)term->tl_scrollback.ga_data + bot_rows,
+ temp + top_rows,
+ sizeof(sb_line_T) * (line_count - top_rows - bot_rows));
+ mch_memmove((sb_line_T *)term->tl_scrollback.ga_data
+ + line_count - top_rows,
+ temp,
+ sizeof(sb_line_T) * top_rows);
+ vim_free(temp);
+ }
+ }
+
+ term->tl_top_diff_rows = bot_rows;
+ term->tl_bot_diff_rows = top_rows;
+
+ update_screen(NOT_VALID);
+ return OK;
+}
+
+/*
+ * "term_dumpdiff(filename, filename, options)" function
+ */
+ void
+f_term_dumpdiff(typval_T *argvars, typval_T *rettv)
+{
+ term_load_dump(argvars, rettv, TRUE);
+}
+
+/*
+ * "term_dumpload(filename, options)" function
+ */
+ void
+f_term_dumpload(typval_T *argvars, typval_T *rettv)
+{
+ term_load_dump(argvars, rettv, FALSE);
+}
+
+/*
+ * "term_getaltscreen(buf)" function
+ */
+ void
+f_term_getaltscreen(typval_T *argvars, typval_T *rettv)
+{
+ buf_T *buf = term_get_buf(argvars, "term_getaltscreen()");
+
+ if (buf == NULL)
+ return;
+ rettv->vval.v_number = buf->b_term->tl_using_altscreen;
+}
+
+/*
+ * "term_getattr(attr, name)" function
+ */
+ void
+f_term_getattr(typval_T *argvars, typval_T *rettv)
+{
+ int attr;
+ size_t i;
+ char_u *name;
+
+ static struct {
+ char *name;
+ int attr;
+ } attrs[] = {
+ {"bold", HL_BOLD},
+ {"italic", HL_ITALIC},
+ {"underline", HL_UNDERLINE},
+ {"strike", HL_STRIKETHROUGH},
+ {"reverse", HL_INVERSE},
+ };
+
+ attr = tv_get_number(&argvars[0]);
+ name = tv_get_string_chk(&argvars[1]);
+ if (name == NULL)
+ return;
+
+ for (i = 0; i < sizeof(attrs)/sizeof(attrs[0]); ++i)
+ if (STRCMP(name, attrs[i].name) == 0)
+ {
+ rettv->vval.v_number = (attr & attrs[i].attr) != 0 ? 1 : 0;
+ break;
+ }
+}
+
+/*
+ * "term_getcursor(buf)" function
+ */
+ void
+f_term_getcursor(typval_T *argvars, typval_T *rettv)
+{
+ buf_T *buf = term_get_buf(argvars, "term_getcursor()");
+ term_T *term;
+ list_T *l;
+ dict_T *d;
+
+ if (rettv_list_alloc(rettv) == FAIL)
+ return;
+ if (buf == NULL)
+ return;
+ term = buf->b_term;
+
+ l = rettv->vval.v_list;
+ list_append_number(l, term->tl_cursor_pos.row + 1);
+ list_append_number(l, term->tl_cursor_pos.col + 1);
+
+ d = dict_alloc();
+ if (d != NULL)
+ {
+ dict_add_number(d, "visible", term->tl_cursor_visible);
+ dict_add_number(d, "blink", blink_state_is_inverted()
+ ? !term->tl_cursor_blink : term->tl_cursor_blink);
+ dict_add_number(d, "shape", term->tl_cursor_shape);
+ dict_add_string(d, "color", cursor_color_get(term->tl_cursor_color));
+ list_append_dict(l, d);
+ }
+}
+
+/*
+ * "term_getjob(buf)" function
+ */
+ void
+f_term_getjob(typval_T *argvars, typval_T *rettv)
+{
+ buf_T *buf = term_get_buf(argvars, "term_getjob()");
+
+ if (buf == NULL)
+ {
+ rettv->v_type = VAR_SPECIAL;
+ rettv->vval.v_number = VVAL_NULL;
+ return;
+ }
+
+ rettv->v_type = VAR_JOB;
+ rettv->vval.v_job = buf->b_term->tl_job;
+ if (rettv->vval.v_job != NULL)
+ ++rettv->vval.v_job->jv_refcount;
+}
+
+ static int
+get_row_number(typval_T *tv, term_T *term)
+{
+ if (tv->v_type == VAR_STRING
+ && tv->vval.v_string != NULL
+ && STRCMP(tv->vval.v_string, ".") == 0)
+ return term->tl_cursor_pos.row;
+ return (int)tv_get_number(tv) - 1;
+}
+
+/*
+ * "term_getline(buf, row)" function
+ */
+ void
+f_term_getline(typval_T *argvars, typval_T *rettv)
+{
+ buf_T *buf = term_get_buf(argvars, "term_getline()");
+ term_T *term;
+ int row;
+
+ rettv->v_type = VAR_STRING;
+ if (buf == NULL)
+ return;
+ term = buf->b_term;
+ row = get_row_number(&argvars[1], term);
+
+ if (term->tl_vterm == NULL)
+ {
+ linenr_T lnum = row + term->tl_scrollback_scrolled + 1;
+
+ /* vterm is finished, get the text from the buffer */
+ if (lnum > 0 && lnum <= buf->b_ml.ml_line_count)
+ rettv->vval.v_string = vim_strsave(ml_get_buf(buf, lnum, FALSE));
+ }
+ else
+ {
+ VTermScreen *screen = vterm_obtain_screen(term->tl_vterm);
+ VTermRect rect;
+ int len;
+ char_u *p;
+
+ if (row < 0 || row >= term->tl_rows)
+ return;
+ len = term->tl_cols * MB_MAXBYTES + 1;
+ p = alloc(len);
+ if (p == NULL)
+ return;
+ rettv->vval.v_string = p;
+
+ rect.start_col = 0;
+ rect.end_col = term->tl_cols;
+ rect.start_row = row;
+ rect.end_row = row + 1;
+ p[vterm_screen_get_text(screen, (char *)p, len, rect)] = NUL;
+ }
+}
+
+/*
+ * "term_getscrolled(buf)" function
+ */
+ void
+f_term_getscrolled(typval_T *argvars, typval_T *rettv)
+{
+ buf_T *buf = term_get_buf(argvars, "term_getscrolled()");
+
+ if (buf == NULL)
+ return;
+ rettv->vval.v_number = buf->b_term->tl_scrollback_scrolled;
+}
+
+/*
+ * "term_getsize(buf)" function
+ */
+ void
+f_term_getsize(typval_T *argvars, typval_T *rettv)
+{
+ buf_T *buf = term_get_buf(argvars, "term_getsize()");
+ list_T *l;
+
+ if (rettv_list_alloc(rettv) == FAIL)
+ return;
+ if (buf == NULL)
+ return;
+
+ l = rettv->vval.v_list;
+ list_append_number(l, buf->b_term->tl_rows);
+ list_append_number(l, buf->b_term->tl_cols);
+}
+
+/*
+ * "term_setsize(buf, rows, cols)" function
+ */
+ void
+f_term_setsize(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
+{
+ buf_T *buf = term_get_buf(argvars, "term_setsize()");
+ term_T *term;
+ varnumber_T rows, cols;
+
+ if (buf == NULL)
+ {
+ emsg(_("E955: Not a terminal buffer"));
+ return;
+ }
+ if (buf->b_term->tl_vterm == NULL)
+ return;
+ term = buf->b_term;
+ rows = tv_get_number(&argvars[1]);
+ rows = rows <= 0 ? term->tl_rows : rows;
+ cols = tv_get_number(&argvars[2]);
+ cols = cols <= 0 ? term->tl_cols : cols;
+ vterm_set_size(term->tl_vterm, rows, cols);
+ /* handle_resize() will resize the windows */
+
+ /* Get and remember the size we ended up with. Update the pty. */
+ vterm_get_size(term->tl_vterm, &term->tl_rows, &term->tl_cols);
+ term_report_winsize(term, term->tl_rows, term->tl_cols);
+}
+
+/*
+ * "term_getstatus(buf)" function
+ */
+ void
+f_term_getstatus(typval_T *argvars, typval_T *rettv)
+{
+ buf_T *buf = term_get_buf(argvars, "term_getstatus()");
+ term_T *term;
+ char_u val[100];
+
+ rettv->v_type = VAR_STRING;
+ if (buf == NULL)
+ return;
+ term = buf->b_term;
+
+ if (term_job_running(term))
+ STRCPY(val, "running");
+ else
+ STRCPY(val, "finished");
+ if (term->tl_normal_mode)
+ STRCAT(val, ",normal");
+ rettv->vval.v_string = vim_strsave(val);
+}
+
+/*
+ * "term_gettitle(buf)" function
+ */
+ void
+f_term_gettitle(typval_T *argvars, typval_T *rettv)
+{
+ buf_T *buf = term_get_buf(argvars, "term_gettitle()");
+
+ rettv->v_type = VAR_STRING;
+ if (buf == NULL)
+ return;
+
+ if (buf->b_term->tl_title != NULL)
+ rettv->vval.v_string = vim_strsave(buf->b_term->tl_title);
+}
+
+/*
+ * "term_gettty(buf)" function
+ */
+ void
+f_term_gettty(typval_T *argvars, typval_T *rettv)
+{
+ buf_T *buf = term_get_buf(argvars, "term_gettty()");
+ char_u *p = NULL;
+ int num = 0;
+
+ rettv->v_type = VAR_STRING;
+ if (buf == NULL)
+ return;
+ if (argvars[1].v_type != VAR_UNKNOWN)
+ num = tv_get_number(&argvars[1]);
+
+ switch (num)
+ {
+ case 0:
+ if (buf->b_term->tl_job != NULL)
+ p = buf->b_term->tl_job->jv_tty_out;
+ break;
+ case 1:
+ if (buf->b_term->tl_job != NULL)
+ p = buf->b_term->tl_job->jv_tty_in;
+ break;
+ default:
+ semsg(_(e_invarg2), tv_get_string(&argvars[1]));
+ return;
+ }
+ if (p != NULL)
+ rettv->vval.v_string = vim_strsave(p);
+}
+
+/*
+ * "term_list()" function
+ */
+ void
+f_term_list(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ term_T *tp;
+ list_T *l;
+
+ if (rettv_list_alloc(rettv) == FAIL || first_term == NULL)
+ return;
+
+ l = rettv->vval.v_list;
+ for (tp = first_term; tp != NULL; tp = tp->tl_next)
+ if (tp != NULL && tp->tl_buffer != NULL)
+ if (list_append_number(l,
+ (varnumber_T)tp->tl_buffer->b_fnum) == FAIL)
+ return;
+}
+
+/*
+ * "term_scrape(buf, row)" function
+ */
+ void
+f_term_scrape(typval_T *argvars, typval_T *rettv)
+{
+ buf_T *buf = term_get_buf(argvars, "term_scrape()");
+ VTermScreen *screen = NULL;
+ VTermPos pos;
+ list_T *l;
+ term_T *term;
+ char_u *p;
+ sb_line_T *line;
+
+ if (rettv_list_alloc(rettv) == FAIL)
+ return;
+ if (buf == NULL)
+ return;
+ term = buf->b_term;
+
+ l = rettv->vval.v_list;
+ pos.row = get_row_number(&argvars[1], term);
+
+ if (term->tl_vterm != NULL)
+ {
+ screen = vterm_obtain_screen(term->tl_vterm);
+ if (screen == NULL) // can't really happen
+ return;
+ p = NULL;
+ line = NULL;
+ }
+ else
+ {
+ linenr_T lnum = pos.row + term->tl_scrollback_scrolled;
+
+ if (lnum < 0 || lnum >= term->tl_scrollback.ga_len)
+ return;
+ p = ml_get_buf(buf, lnum + 1, FALSE);
+ line = (sb_line_T *)term->tl_scrollback.ga_data + lnum;
+ }
+
+ for (pos.col = 0; pos.col < term->tl_cols; )
+ {
+ dict_T *dcell;
+ int width;
+ VTermScreenCellAttrs attrs;
+ VTermColor fg, bg;
+ char_u rgb[8];
+ char_u mbs[MB_MAXBYTES * VTERM_MAX_CHARS_PER_CELL + 1];
+ int off = 0;
+ int i;
+
+ if (screen == NULL)
+ {
+ cellattr_T *cellattr;
+ int len;
+
+ /* vterm has finished, get the cell from scrollback */
+ if (pos.col >= line->sb_cols)
+ break;
+ cellattr = line->sb_cells + pos.col;
+ width = cellattr->width;
+ attrs = cellattr->attrs;
+ fg = cellattr->fg;
+ bg = cellattr->bg;
+ len = MB_PTR2LEN(p);
+ mch_memmove(mbs, p, len);
+ mbs[len] = NUL;
+ p += len;
+ }
+ else
+ {
+ VTermScreenCell cell;
+ if (vterm_screen_get_cell(screen, pos, &cell) == 0)
+ break;
+ for (i = 0; i < VTERM_MAX_CHARS_PER_CELL; ++i)
+ {
+ if (cell.chars[i] == 0)
+ break;
+ off += (*utf_char2bytes)((int)cell.chars[i], mbs + off);
+ }
+ mbs[off] = NUL;
+ width = cell.width;
+ attrs = cell.attrs;
+ fg = cell.fg;
+ bg = cell.bg;
+ }
+ dcell = dict_alloc();
+ if (dcell == NULL)
+ break;
+ list_append_dict(l, dcell);
+
+ dict_add_string(dcell, "chars", mbs);
+
+ vim_snprintf((char *)rgb, 8, "#%02x%02x%02x",
+ fg.red, fg.green, fg.blue);
+ dict_add_string(dcell, "fg", rgb);
+ vim_snprintf((char *)rgb, 8, "#%02x%02x%02x",
+ bg.red, bg.green, bg.blue);
+ dict_add_string(dcell, "bg", rgb);
+
+ dict_add_number(dcell, "attr", cell2attr(attrs, fg, bg));
+ dict_add_number(dcell, "width", width);
+
+ ++pos.col;
+ if (width == 2)
+ ++pos.col;
+ }
+}
+
+/*
+ * "term_sendkeys(buf, keys)" function
+ */
+ void
+f_term_sendkeys(typval_T *argvars, typval_T *rettv)
+{
+ buf_T *buf = term_get_buf(argvars, "term_sendkeys()");
+ char_u *msg;
+ term_T *term;
+
+ rettv->v_type = VAR_UNKNOWN;
+ if (buf == NULL)
+ return;
+
+ msg = tv_get_string_chk(&argvars[1]);
+ if (msg == NULL)
+ return;
+ term = buf->b_term;
+ if (term->tl_vterm == NULL)
+ return;
+
+ while (*msg != NUL)
+ {
+ int c;
+
+ if (*msg == K_SPECIAL && msg[1] != NUL && msg[2] != NUL)
+ {
+ c = TO_SPECIAL(msg[1], msg[2]);
+ msg += 3;
+ }
+ else
+ {
+ c = PTR2CHAR(msg);
+ msg += MB_CPTR2LEN(msg);
+ }
+ send_keys_to_term(term, c, FALSE);
+ }
+}
+
+#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS) || defined(PROTO)
+/*
+ * "term_getansicolors(buf)" function
+ */
+ void
+f_term_getansicolors(typval_T *argvars, typval_T *rettv)
+{
+ buf_T *buf = term_get_buf(argvars, "term_getansicolors()");
+ term_T *term;
+ VTermState *state;
+ VTermColor color;
+ char_u hexbuf[10];
+ int index;
+ list_T *list;
+
+ if (rettv_list_alloc(rettv) == FAIL)
+ return;
+
+ if (buf == NULL)
+ return;
+ term = buf->b_term;
+ if (term->tl_vterm == NULL)
+ return;
+
+ list = rettv->vval.v_list;
+ state = vterm_obtain_state(term->tl_vterm);
+ for (index = 0; index < 16; index++)
+ {
+ vterm_state_get_palette_color(state, index, &color);
+ sprintf((char *)hexbuf, "#%02x%02x%02x",
+ color.red, color.green, color.blue);
+ if (list_append_string(list, hexbuf, 7) == FAIL)
+ return;
+ }
+}
+
+/*
+ * "term_setansicolors(buf, list)" function
+ */
+ void
+f_term_setansicolors(typval_T *argvars, typval_T *rettv UNUSED)
+{
+ buf_T *buf = term_get_buf(argvars, "term_setansicolors()");
+ term_T *term;
+
+ if (buf == NULL)
+ return;
+ term = buf->b_term;
+ if (term->tl_vterm == NULL)
+ return;
+
+ if (argvars[1].v_type != VAR_LIST || argvars[1].vval.v_list == NULL)
+ {
+ emsg(_(e_listreq));
+ return;
+ }
+
+ if (set_ansi_colors_list(term->tl_vterm, argvars[1].vval.v_list) == FAIL)
+ emsg(_(e_invarg));
+}
+#endif
+
+/*
+ * "term_setrestore(buf, command)" function
+ */
+ void
+f_term_setrestore(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
+{
+#if defined(FEAT_SESSION)
+ buf_T *buf = term_get_buf(argvars, "term_setrestore()");
+ term_T *term;
+ char_u *cmd;
+
+ if (buf == NULL)
+ return;
+ term = buf->b_term;
+ vim_free(term->tl_command);
+ cmd = tv_get_string_chk(&argvars[1]);
+ if (cmd != NULL)
+ term->tl_command = vim_strsave(cmd);
+ else
+ term->tl_command = NULL;
+#endif
+}
+
+/*
+ * "term_setkill(buf, how)" function
+ */
+ void
+f_term_setkill(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
+{
+ buf_T *buf = term_get_buf(argvars, "term_setkill()");
+ term_T *term;
+ char_u *how;
+
+ if (buf == NULL)
+ return;
+ term = buf->b_term;
+ vim_free(term->tl_kill);
+ how = tv_get_string_chk(&argvars[1]);
+ if (how != NULL)
+ term->tl_kill = vim_strsave(how);
+ else
+ term->tl_kill = NULL;
+}
+
+/*
+ * "term_start(command, options)" function
+ */
+ void
+f_term_start(typval_T *argvars, typval_T *rettv)
+{
+ jobopt_T opt;
+ buf_T *buf;
+
+ init_job_options(&opt);
+ if (argvars[1].v_type != VAR_UNKNOWN
+ && get_job_options(&argvars[1], &opt,
+ JO_TIMEOUT_ALL + JO_STOPONEXIT
+ + JO_CALLBACK + JO_OUT_CALLBACK + JO_ERR_CALLBACK
+ + JO_EXIT_CB + JO_CLOSE_CALLBACK + JO_OUT_IO,
+ JO2_TERM_NAME + JO2_TERM_FINISH + JO2_HIDDEN + JO2_TERM_OPENCMD
+ + JO2_TERM_COLS + JO2_TERM_ROWS + JO2_VERTICAL + JO2_CURWIN
+ + JO2_CWD + JO2_ENV + JO2_EOF_CHARS
+ + JO2_NORESTORE + JO2_TERM_KILL
+ + JO2_ANSI_COLORS + JO2_TERM_MODE) == FAIL)
+ return;
+
+ buf = term_start(&argvars[0], NULL, &opt, 0);
+
+ if (buf != NULL && buf->b_term != NULL)
+ rettv->vval.v_number = buf->b_fnum;
+}
+
+/*
+ * "term_wait" function
+ */
+ void
+f_term_wait(typval_T *argvars, typval_T *rettv UNUSED)
+{
+ buf_T *buf = term_get_buf(argvars, "term_wait()");
+
+ if (buf == NULL)
+ return;
+ if (buf->b_term->tl_job == NULL)
+ {
+ ch_log(NULL, "term_wait(): no job to wait for");
+ return;
+ }
+ if (buf->b_term->tl_job->jv_channel == NULL)
+ /* channel is closed, nothing to do */
+ return;
+
+ /* Get the job status, this will detect a job that finished. */
+ if (!buf->b_term->tl_job->jv_channel->ch_keep_open
+ && STRCMP(job_status(buf->b_term->tl_job), "dead") == 0)
+ {
+ /* The job is dead, keep reading channel I/O until the channel is
+ * closed. buf->b_term may become NULL if the terminal was closed while
+ * waiting. */
+ ch_log(NULL, "term_wait(): waiting for channel to close");
+ while (buf->b_term != NULL && !buf->b_term->tl_channel_closed)
+ {
+ mch_check_messages();
+ parse_queued_messages();
+ ui_delay(10L, FALSE);
+ if (!buf_valid(buf))
+ /* If the terminal is closed when the channel is closed the
+ * buffer disappears. */
+ break;
+ }
+ mch_check_messages();
+ parse_queued_messages();
+ }
+ else
+ {
+ long wait = 10L;
+
+ mch_check_messages();
+ parse_queued_messages();
+
+ /* Wait for some time for any channel I/O. */
+ if (argvars[1].v_type != VAR_UNKNOWN)
+ wait = tv_get_number(&argvars[1]);
+ ui_delay(wait, TRUE);
+ mch_check_messages();
+
+ /* Flushing messages on channels is hopefully sufficient.
+ * TODO: is there a better way? */
+ parse_queued_messages();
+ }
+}
+
+/*
+ * Called when a channel has sent all the lines to a terminal.
+ * Send a CTRL-D to mark the end of the text.
+ */
+ void
+term_send_eof(channel_T *ch)
+{
+ term_T *term;
+
+ for (term = first_term; term != NULL; term = term->tl_next)
+ if (term->tl_job == ch->ch_job)
+ {
+ if (term->tl_eof_chars != NULL)
+ {
+ channel_send(ch, PART_IN, term->tl_eof_chars,
+ (int)STRLEN(term->tl_eof_chars), NULL);
+ channel_send(ch, PART_IN, (char_u *)"\r", 1, NULL);
+ }
+# ifdef WIN3264
+ else
+ /* Default: CTRL-D */
+ channel_send(ch, PART_IN, (char_u *)"\004\r", 2, NULL);
+# endif
+ }
+}
+
+#if defined(FEAT_GUI) || defined(PROTO)
+ job_T *
+term_getjob(term_T *term)
+{
+ return term != NULL ? term->tl_job : NULL;
+}
+#endif
+
+# if defined(WIN3264) || defined(PROTO)
+
+/**************************************
+ * 2. MS-Windows implementation.
+ */
+
+HRESULT (WINAPI *pCreatePseudoConsole)(COORD, HANDLE, HANDLE, DWORD, HPCON*);
+HRESULT (WINAPI *pResizePseudoConsole)(HPCON, COORD);
+HRESULT (WINAPI *pClosePseudoConsole)(HPCON);
+BOOL (*pInitializeProcThreadAttributeList)(LPPROC_THREAD_ATTRIBUTE_LIST, DWORD, DWORD, PSIZE_T);
+BOOL (*pUpdateProcThreadAttribute)(LPPROC_THREAD_ATTRIBUTE_LIST, DWORD, DWORD_PTR, PVOID, SIZE_T, PVOID, PSIZE_T);
+void (*pDeleteProcThreadAttributeList)(LPPROC_THREAD_ATTRIBUTE_LIST);
+
+ static int
+dyn_conpty_init(int verbose)
+{
+ static BOOL handled = FALSE;
+ static int result;
+ HMODULE hKerneldll;
+ int i;
+ static struct
+ {
+ char *name;
+ FARPROC *ptr;
+ } conpty_entry[] =
+ {
+ {"CreatePseudoConsole", (FARPROC*)&pCreatePseudoConsole},
+ {"ResizePseudoConsole", (FARPROC*)&pResizePseudoConsole},
+ {"ClosePseudoConsole", (FARPROC*)&pClosePseudoConsole},
+ {"InitializeProcThreadAttributeList",
+ (FARPROC*)&pInitializeProcThreadAttributeList},
+ {"UpdateProcThreadAttribute",
+ (FARPROC*)&pUpdateProcThreadAttribute},
+ {"DeleteProcThreadAttributeList",
+ (FARPROC*)&pDeleteProcThreadAttributeList},
+ {NULL, NULL}
+ };
+
+ if (handled)
+ return result;
+
+ if (!has_vtp_working())
+ {
+ handled = TRUE;
+ result = FAIL;
+ return FAIL;
+ }
+
+ hKerneldll = vimLoadLib("kernel32.dll");
+ for (i = 0; conpty_entry[i].name != NULL
+ && conpty_entry[i].ptr != NULL; ++i)
+ {
+ if ((*conpty_entry[i].ptr = (FARPROC)GetProcAddress(hKerneldll,
+ conpty_entry[i].name)) == NULL)
+ {
+ if (verbose)
+ semsg(_(e_loadfunc), conpty_entry[i].name);
+ return FAIL;
+ }
+ }
+
+ handled = TRUE;
+ result = OK;
+ return OK;
+}
+
+ static int
+conpty_term_and_job_init(
+ term_T *term,
+ typval_T *argvar,
+ char **argv,
+ jobopt_T *opt,
+ jobopt_T *orig_opt)
+{
+ WCHAR *cmd_wchar = NULL;
+ WCHAR *cmd_wchar_copy = NULL;
+ WCHAR *cwd_wchar = NULL;
+ WCHAR *env_wchar = NULL;
+ channel_T *channel = NULL;
+ job_T *job = NULL;
+ HANDLE jo = NULL;
+ garray_T ga_cmd, ga_env;
+ char_u *cmd = NULL;
+ HRESULT hr;
+ COORD consize;
+ SIZE_T breq;
+ PROCESS_INFORMATION proc_info;
+ HANDLE i_theirs = NULL;
+ HANDLE o_theirs = NULL;
+ HANDLE i_ours = NULL;
+ HANDLE o_ours = NULL;
+
+ ga_init2(&ga_cmd, (int)sizeof(char*), 20);
+ ga_init2(&ga_env, (int)sizeof(char*), 20);
+
+ if (argvar->v_type == VAR_STRING)
+ {
+ cmd = argvar->vval.v_string;
+ }
+ else if (argvar->v_type == VAR_LIST)
+ {
+ if (win32_build_cmd(argvar->vval.v_list, &ga_cmd) == FAIL)
+ goto failed;
+ cmd = ga_cmd.ga_data;
+ }
+ if (cmd == NULL || *cmd == NUL)
+ {
+ emsg(_(e_invarg));
+ goto failed;
+ }
+
+ term->tl_arg0_cmd = vim_strsave(cmd);
+
+ cmd_wchar = enc_to_utf16(cmd, NULL);
+
+ if (cmd_wchar != NULL)
+ {
+ /* Request by CreateProcessW */
+ breq = wcslen(cmd_wchar) + 1 + 1; /* Addition of NUL by API */
+ cmd_wchar_copy = (PWSTR)alloc((int)(breq * sizeof(WCHAR)));
+ wcsncpy(cmd_wchar_copy, cmd_wchar, breq - 1);
+ }
+
+ ga_clear(&ga_cmd);
+ if (cmd_wchar == NULL)
+ goto failed;
+ if (opt->jo_cwd != NULL)
+ cwd_wchar = enc_to_utf16(opt->jo_cwd, NULL);
+
+ win32_build_env(opt->jo_env, &ga_env, TRUE);
+ env_wchar = ga_env.ga_data;
+
+ if (!CreatePipe(&i_theirs, &i_ours, NULL, 0))
+ goto failed;
+ if (!CreatePipe(&o_ours, &o_theirs, NULL, 0))
+ goto failed;
+
+ consize.X = term->tl_cols;
+ consize.Y = term->tl_rows;
+ hr = pCreatePseudoConsole(consize, i_theirs, o_theirs, 0,
+ &term->tl_conpty);
+ if (FAILED(hr))
+ goto failed;
+
+ term->tl_siex.StartupInfo.cb = sizeof(term->tl_siex);
+
+ /* Set up pipe inheritance safely: Vista or later. */
+ pInitializeProcThreadAttributeList(NULL, 1, 0, &breq);
+ term->tl_siex.lpAttributeList =
+ (PPROC_THREAD_ATTRIBUTE_LIST)alloc((int)breq);
+ if (!term->tl_siex.lpAttributeList)
+ goto failed;
+ if (!pInitializeProcThreadAttributeList(term->tl_siex.lpAttributeList, 1,
+ 0, &breq))
+ goto failed;
+ if (!pUpdateProcThreadAttribute(
+ term->tl_siex.lpAttributeList, 0,
+ PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE, term->tl_conpty,
+ sizeof(HPCON), NULL, NULL))
+ goto failed;
+
+ channel = add_channel();
+ if (channel == NULL)
+ goto failed;
+
+ job = job_alloc();
+ if (job == NULL)
+ goto failed;
+ if (argvar->v_type == VAR_STRING)
+ {
+ int argc;
+
+ build_argv_from_string(cmd, &job->jv_argv, &argc);
+ }
+ else
+ {
+ int argc;
+
+ build_argv_from_list(argvar->vval.v_list, &job->jv_argv, &argc);
+ }
+
+ if (opt->jo_set & JO_IN_BUF)
+ job->jv_in_buf = buflist_findnr(opt->jo_io_buf[PART_IN]);
+
+ if (!CreateProcessW(NULL, cmd_wchar_copy, NULL, NULL, FALSE,
+ EXTENDED_STARTUPINFO_PRESENT | CREATE_UNICODE_ENVIRONMENT
+ | CREATE_SUSPENDED | CREATE_NEW_PROCESS_GROUP
+ | CREATE_DEFAULT_ERROR_MODE,
+ env_wchar, cwd_wchar,
+ &term->tl_siex.StartupInfo, &proc_info))
+ goto failed;
+
+ CloseHandle(i_theirs);
+ CloseHandle(o_theirs);
+
+ channel_set_pipes(channel,
+ (sock_T)i_ours,
+ (sock_T)o_ours,
+ (sock_T)o_ours);
+
+ /* Write lines with CR instead of NL. */
+ channel->ch_write_text_mode = TRUE;
+
+ /* Use to explicitly delete anonymous pipe handle. */
+ channel->ch_anonymous_pipe = TRUE;
+
+ jo = CreateJobObject(NULL, NULL);
+ if (jo == NULL)
+ goto failed;
+
+ if (!AssignProcessToJobObject(jo, proc_info.hProcess))
+ {
+ /* Failed, switch the way to terminate process with TerminateProcess. */
+ CloseHandle(jo);
+ jo = NULL;
+ }
+
+ ResumeThread(proc_info.hThread);
+ CloseHandle(proc_info.hThread);
+
+ vim_free(cmd_wchar);
+ vim_free(cmd_wchar_copy);
+ vim_free(cwd_wchar);
+ vim_free(env_wchar);
+
+ if (create_vterm(term, term->tl_rows, term->tl_cols) == FAIL)
+ goto failed;
+
+#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
+ if (opt->jo_set2 & JO2_ANSI_COLORS)
+ set_vterm_palette(term->tl_vterm, opt->jo_ansi_colors);
+ else
+ init_vterm_ansi_colors(term->tl_vterm);
+#endif
+
+ channel_set_job(channel, job, opt);
+ job_set_options(job, opt);
+
+ job->jv_channel = channel;
+ job->jv_proc_info = proc_info;
+ job->jv_job_object = jo;
+ job->jv_status = JOB_STARTED;
+ ++job->jv_refcount;
+ term->tl_job = job;
+
+ /* Redirecting stdout and stderr doesn't work at the job level. Instead
+ * open the file here and handle it in. opt->jo_io was changed in
+ * setup_job_options(), use the original flags here. */
+ if (orig_opt->jo_io[PART_OUT] == JIO_FILE)
+ {
+ char_u *fname = opt->jo_io_name[PART_OUT];
+
+ ch_log(channel, "Opening output file %s", fname);
+ term->tl_out_fd = mch_fopen((char *)fname, WRITEBIN);
+ if (term->tl_out_fd == NULL)
+ semsg(_(e_notopen), fname);
+ }
+
+ return OK;
+
+failed:
+ ga_clear(&ga_cmd);
+ ga_clear(&ga_env);
+ vim_free(cmd_wchar);
+ vim_free(cmd_wchar_copy);
+ vim_free(cwd_wchar);
+ if (channel != NULL)
+ channel_clear(channel);
+ if (job != NULL)
+ {
+ job->jv_channel = NULL;
+ job_cleanup(job);
+ }
+ term->tl_job = NULL;
+ if (jo != NULL)
+ CloseHandle(jo);
+
+ if (term->tl_siex.lpAttributeList != NULL)
+ {
+ pDeleteProcThreadAttributeList(term->tl_siex.lpAttributeList);
+ vim_free(term->tl_siex.lpAttributeList);
+ }
+ term->tl_siex.lpAttributeList = NULL;
+ if (o_theirs != NULL)
+ CloseHandle(o_theirs);
+ if (o_ours != NULL)
+ CloseHandle(o_ours);
+ if (i_ours != NULL)
+ CloseHandle(i_ours);
+ if (i_theirs != NULL)
+ CloseHandle(i_theirs);
+ if (term->tl_conpty != NULL)
+ pClosePseudoConsole(term->tl_conpty);
+ term->tl_conpty = NULL;
+ return FAIL;
+}
+
+ static void
+conpty_term_report_winsize(term_T *term, int rows, int cols)
+{
+ COORD consize;
+
+ consize.X = cols;
+ consize.Y = rows;
+ pResizePseudoConsole(term->tl_conpty, consize);
+}
+
+ void
+term_free_conpty(term_T *term)
+{
+ if (term->tl_siex.lpAttributeList != NULL)
+ {
+ pDeleteProcThreadAttributeList(term->tl_siex.lpAttributeList);
+ vim_free(term->tl_siex.lpAttributeList);
+ }
+ term->tl_siex.lpAttributeList = NULL;
+ if (term->tl_conpty != NULL)
+ pClosePseudoConsole(term->tl_conpty);
+ term->tl_conpty = NULL;
+}
+
+ int
+use_conpty(void)
+{
+ return has_conpty;
+}
+
+# ifndef PROTO
+
+#define WINPTY_SPAWN_FLAG_AUTO_SHUTDOWN 1ul
+#define WINPTY_SPAWN_FLAG_EXIT_AFTER_SHUTDOWN 2ull
+#define WINPTY_MOUSE_MODE_FORCE 2
+
+void* (*winpty_config_new)(UINT64, void*);
+void* (*winpty_open)(void*, void*);
+void* (*winpty_spawn_config_new)(UINT64, void*, LPCWSTR, void*, void*, void*);
+BOOL (*winpty_spawn)(void*, void*, HANDLE*, HANDLE*, DWORD*, void*);
+void (*winpty_config_set_mouse_mode)(void*, int);
+void (*winpty_config_set_initial_size)(void*, int, int);
+LPCWSTR (*winpty_conin_name)(void*);
+LPCWSTR (*winpty_conout_name)(void*);
+LPCWSTR (*winpty_conerr_name)(void*);
+void (*winpty_free)(void*);
+void (*winpty_config_free)(void*);
+void (*winpty_spawn_config_free)(void*);
+void (*winpty_error_free)(void*);
+LPCWSTR (*winpty_error_msg)(void*);
+BOOL (*winpty_set_size)(void*, int, int, void*);
+HANDLE (*winpty_agent_process)(void*);
+
+#define WINPTY_DLL "winpty.dll"
+
+static HINSTANCE hWinPtyDLL = NULL;
+# endif
+
+ static int
+dyn_winpty_init(int verbose)
+{
+ int i;
+ static struct
+ {
+ char *name;
+ FARPROC *ptr;
+ } winpty_entry[] =
+ {
+ {"winpty_conerr_name", (FARPROC*)&winpty_conerr_name},
+ {"winpty_config_free", (FARPROC*)&winpty_config_free},
+ {"winpty_config_new", (FARPROC*)&winpty_config_new},
+ {"winpty_config_set_mouse_mode",
+ (FARPROC*)&winpty_config_set_mouse_mode},
+ {"winpty_config_set_initial_size",
+ (FARPROC*)&winpty_config_set_initial_size},
+ {"winpty_conin_name", (FARPROC*)&winpty_conin_name},
+ {"winpty_conout_name", (FARPROC*)&winpty_conout_name},
+ {"winpty_error_free", (FARPROC*)&winpty_error_free},
+ {"winpty_free", (FARPROC*)&winpty_free},
+ {"winpty_open", (FARPROC*)&winpty_open},
+ {"winpty_spawn", (FARPROC*)&winpty_spawn},
+ {"winpty_spawn_config_free", (FARPROC*)&winpty_spawn_config_free},
+ {"winpty_spawn_config_new", (FARPROC*)&winpty_spawn_config_new},
+ {"winpty_error_msg", (FARPROC*)&winpty_error_msg},
+ {"winpty_set_size", (FARPROC*)&winpty_set_size},
+ {"winpty_agent_process", (FARPROC*)&winpty_agent_process},
+ {NULL, NULL}
+ };
+
+ /* No need to initialize twice. */
+ if (hWinPtyDLL)
+ return OK;
+ /* Load winpty.dll, prefer using the 'winptydll' option, fall back to just
+ * winpty.dll. */
+ if (*p_winptydll != NUL)
+ hWinPtyDLL = vimLoadLib((char *)p_winptydll);
+ if (!hWinPtyDLL)
+ hWinPtyDLL = vimLoadLib(WINPTY_DLL);
+ if (!hWinPtyDLL)
+ {
+ if (verbose)
+ semsg(_(e_loadlib), *p_winptydll != NUL ? p_winptydll
+ : (char_u *)WINPTY_DLL);
+ return FAIL;
+ }
+ for (i = 0; winpty_entry[i].name != NULL
+ && winpty_entry[i].ptr != NULL; ++i)
+ {
+ if ((*winpty_entry[i].ptr = (FARPROC)GetProcAddress(hWinPtyDLL,
+ winpty_entry[i].name)) == NULL)
+ {
+ if (verbose)
+ semsg(_(e_loadfunc), winpty_entry[i].name);
+ return FAIL;
+ }
+ }
+
+ return OK;
+}
+
+ static int
+winpty_term_and_job_init(
+ term_T *term,
+ typval_T *argvar,
+ char **argv,
+ jobopt_T *opt,
+ jobopt_T *orig_opt)
+{
+ WCHAR *cmd_wchar = NULL;
+ WCHAR *cwd_wchar = NULL;
+ WCHAR *env_wchar = NULL;
+ channel_T *channel = NULL;
+ job_T *job = NULL;
+ DWORD error;
+ HANDLE jo = NULL;
+ HANDLE child_process_handle;
+ HANDLE child_thread_handle;
+ void *winpty_err = NULL;
+ void *spawn_config = NULL;
+ garray_T ga_cmd, ga_env;
+ char_u *cmd = NULL;
+
+ ga_init2(&ga_cmd, (int)sizeof(char*), 20);
+ ga_init2(&ga_env, (int)sizeof(char*), 20);
+
+ if (argvar->v_type == VAR_STRING)
+ {
+ cmd = argvar->vval.v_string;
+ }
+ else if (argvar->v_type == VAR_LIST)
+ {
+ if (win32_build_cmd(argvar->vval.v_list, &ga_cmd) == FAIL)
+ goto failed;
+ cmd = ga_cmd.ga_data;
+ }
+ if (cmd == NULL || *cmd == NUL)
+ {
+ emsg(_(e_invarg));
+ goto failed;
+ }
+
+ term->tl_arg0_cmd = vim_strsave(cmd);
+
+ cmd_wchar = enc_to_utf16(cmd, NULL);
+ ga_clear(&ga_cmd);
+ if (cmd_wchar == NULL)
+ goto failed;
+ if (opt->jo_cwd != NULL)
+ cwd_wchar = enc_to_utf16(opt->jo_cwd, NULL);
+
+ win32_build_env(opt->jo_env, &ga_env, TRUE);
+ env_wchar = ga_env.ga_data;
+
+ term->tl_winpty_config = winpty_config_new(0, &winpty_err);
+ if (term->tl_winpty_config == NULL)
+ goto failed;
+
+ winpty_config_set_mouse_mode(term->tl_winpty_config,
+ WINPTY_MOUSE_MODE_FORCE);
+ winpty_config_set_initial_size(term->tl_winpty_config,
+ term->tl_cols, term->tl_rows);
+ term->tl_winpty = winpty_open(term->tl_winpty_config, &winpty_err);
+ if (term->tl_winpty == NULL)
+ goto failed;
+
+ spawn_config = winpty_spawn_config_new(
+ WINPTY_SPAWN_FLAG_AUTO_SHUTDOWN |
+ WINPTY_SPAWN_FLAG_EXIT_AFTER_SHUTDOWN,
+ NULL,
+ cmd_wchar,
+ cwd_wchar,
+ env_wchar,
+ &winpty_err);
+ if (spawn_config == NULL)
+ goto failed;
+
+ channel = add_channel();
+ if (channel == NULL)
+ goto failed;
+
+ job = job_alloc();
+ if (job == NULL)
+ goto failed;
+ if (argvar->v_type == VAR_STRING)
+ {
+ int argc;
+
+ build_argv_from_string(cmd, &job->jv_argv, &argc);
+ }
+ else
+ {
+ int argc;
+
+ build_argv_from_list(argvar->vval.v_list, &job->jv_argv, &argc);
+ }
+
+ if (opt->jo_set & JO_IN_BUF)
+ job->jv_in_buf = buflist_findnr(opt->jo_io_buf[PART_IN]);
+
+ if (!winpty_spawn(term->tl_winpty, spawn_config, &child_process_handle,
+ &child_thread_handle, &error, &winpty_err))
+ goto failed;
+
+ channel_set_pipes(channel,
+ (sock_T)CreateFileW(
+ winpty_conin_name(term->tl_winpty),
+ GENERIC_WRITE, 0, NULL,
+ OPEN_EXISTING, 0, NULL),
+ (sock_T)CreateFileW(
+ winpty_conout_name(term->tl_winpty),
+ GENERIC_READ, 0, NULL,
+ OPEN_EXISTING, 0, NULL),
+ (sock_T)CreateFileW(
+ winpty_conerr_name(term->tl_winpty),
+ GENERIC_READ, 0, NULL,
+ OPEN_EXISTING, 0, NULL));
+
+ /* Write lines with CR instead of NL. */
+ channel->ch_write_text_mode = TRUE;
+
+ jo = CreateJobObject(NULL, NULL);
+ if (jo == NULL)
+ goto failed;
+
+ if (!AssignProcessToJobObject(jo, child_process_handle))
+ {
+ /* Failed, switch the way to terminate process with TerminateProcess. */
+ CloseHandle(jo);
+ jo = NULL;
+ }
+
+ winpty_spawn_config_free(spawn_config);
+ vim_free(cmd_wchar);
+ vim_free(cwd_wchar);
+ vim_free(env_wchar);
+
+ if (create_vterm(term, term->tl_rows, term->tl_cols) == FAIL)
+ goto failed;
+
+#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
+ if (opt->jo_set2 & JO2_ANSI_COLORS)
+ set_vterm_palette(term->tl_vterm, opt->jo_ansi_colors);
+ else
+ init_vterm_ansi_colors(term->tl_vterm);
+#endif
+
+ channel_set_job(channel, job, opt);
+ job_set_options(job, opt);
+
+ job->jv_channel = channel;
+ job->jv_proc_info.hProcess = child_process_handle;
+ job->jv_proc_info.dwProcessId = GetProcessId(child_process_handle);
+ job->jv_job_object = jo;
+ job->jv_status = JOB_STARTED;
+ job->jv_tty_in = utf16_to_enc(
+ (short_u *)winpty_conin_name(term->tl_winpty), NULL);
+ job->jv_tty_out = utf16_to_enc(
+ (short_u *)winpty_conout_name(term->tl_winpty), NULL);
+ ++job->jv_refcount;
+ term->tl_job = job;
+
+ /* Redirecting stdout and stderr doesn't work at the job level. Instead
+ * open the file here and handle it in. opt->jo_io was changed in
+ * setup_job_options(), use the original flags here. */
+ if (orig_opt->jo_io[PART_OUT] == JIO_FILE)
+ {
+ char_u *fname = opt->jo_io_name[PART_OUT];
+
+ ch_log(channel, "Opening output file %s", fname);
+ term->tl_out_fd = mch_fopen((char *)fname, WRITEBIN);
+ if (term->tl_out_fd == NULL)
+ semsg(_(e_notopen), fname);
+ }
+
+ return OK;
+
+failed:
+ ga_clear(&ga_cmd);
+ ga_clear(&ga_env);
+ vim_free(cmd_wchar);
+ vim_free(cwd_wchar);
+ if (spawn_config != NULL)
+ winpty_spawn_config_free(spawn_config);
+ if (channel != NULL)
+ channel_clear(channel);
+ if (job != NULL)
+ {
+ job->jv_channel = NULL;
+ job_cleanup(job);
+ }
+ term->tl_job = NULL;
+ if (jo != NULL)
+ CloseHandle(jo);
+ if (term->tl_winpty != NULL)
+ winpty_free(term->tl_winpty);
+ term->tl_winpty = NULL;
+ if (term->tl_winpty_config != NULL)
+ winpty_config_free(term->tl_winpty_config);
+ term->tl_winpty_config = NULL;
+ if (winpty_err != NULL)
+ {
+ char *msg = (char *)utf16_to_enc(
+ (short_u *)winpty_error_msg(winpty_err), NULL);
+
+ emsg(msg);
+ winpty_error_free(winpty_err);
+ }
+ return FAIL;
+}
+
+/*
+ * Create a new terminal of "rows" by "cols" cells.
+ * Store a reference in "term".
+ * Return OK or FAIL.
+ */
+ static int
+term_and_job_init(
+ term_T *term,
+ typval_T *argvar,
+ char **argv UNUSED,
+ jobopt_T *opt,
+ jobopt_T *orig_opt)
+{
+ int use_winpty = FALSE;
+ int use_conpty = FALSE;
+
+ has_winpty = dyn_winpty_init(FALSE) != FAIL ? TRUE : FALSE;
+ has_conpty = dyn_conpty_init(FALSE) != FAIL ? TRUE : FALSE;
+
+ if (!has_winpty && !has_conpty)
+ // If neither is available give the errors for winpty, since when
+ // conpty is not available it can't be installed either.
+ return dyn_winpty_init(TRUE);
+
+ if (opt->jo_term_mode == 'w')
+ set_string_option_direct((char_u *)"tmod", -1, (char_u *)"winpty",
+ OPT_FREE|OPT_LOCAL, 0);
+ if (opt->jo_term_mode == 'c')
+ set_string_option_direct((char_u *)"tmod", -1, (char_u *)"conpty",
+ OPT_FREE|OPT_LOCAL, 0);
+
+ if (curwin->w_p_tmod == NULL || *curwin->w_p_tmod == NUL)
+ {
+ if (has_conpty)
+ use_conpty = TRUE;
+ else if (has_winpty)
+ use_winpty = TRUE;
+ // else: error
+ }
+ else if (STRICMP(curwin->w_p_tmod, "winpty") == 0)
+ {
+ if (has_winpty)
+ use_winpty = TRUE;
+ }
+ else if (STRICMP(curwin->w_p_tmod, "conpty") == 0)
+ {
+ if (has_conpty)
+ use_conpty = TRUE;
+ else
+ return dyn_conpty_init(TRUE);
+ }
+
+ if (use_conpty)
+ {
+ set_string_option_direct((char_u *)"tmod", -1, (char_u *)"conpty",
+ OPT_FREE|OPT_LOCAL, 0);
+ return conpty_term_and_job_init(term, argvar, argv, opt, orig_opt);
+ }
+
+ if (use_winpty)
+ {
+ set_string_option_direct((char_u *)"tmod", -1, (char_u *)"winpty",
+ OPT_FREE|OPT_LOCAL, 0);
+ return winpty_term_and_job_init(term, argvar, argv, opt, orig_opt);
+ }
+
+ // error
+ return dyn_winpty_init(TRUE);
+}
+
+ static int
+create_pty_only(term_T *term, jobopt_T *options)
+{
+ HANDLE hPipeIn = INVALID_HANDLE_VALUE;
+ HANDLE hPipeOut = INVALID_HANDLE_VALUE;
+ char in_name[80], out_name[80];
+ channel_T *channel = NULL;
+
+ if (create_vterm(term, term->tl_rows, term->tl_cols) == FAIL)
+ return FAIL;
+
+ vim_snprintf(in_name, sizeof(in_name), "\\\\.\\pipe\\vim-%d-in-%d",
+ GetCurrentProcessId(),
+ curbuf->b_fnum);
+ hPipeIn = CreateNamedPipe(in_name, PIPE_ACCESS_OUTBOUND,
+ PIPE_TYPE_MESSAGE | PIPE_NOWAIT,
+ PIPE_UNLIMITED_INSTANCES,
+ 0, 0, NMPWAIT_NOWAIT, NULL);
+ if (hPipeIn == INVALID_HANDLE_VALUE)
+ goto failed;
+
+ vim_snprintf(out_name, sizeof(out_name), "\\\\.\\pipe\\vim-%d-out-%d",
+ GetCurrentProcessId(),
+ curbuf->b_fnum);
+ hPipeOut = CreateNamedPipe(out_name, PIPE_ACCESS_INBOUND,
+ PIPE_TYPE_MESSAGE | PIPE_NOWAIT,
+ PIPE_UNLIMITED_INSTANCES,
+ 0, 0, 0, NULL);
+ if (hPipeOut == INVALID_HANDLE_VALUE)
+ goto failed;
+
+ ConnectNamedPipe(hPipeIn, NULL);
+ ConnectNamedPipe(hPipeOut, NULL);
+
+ term->tl_job = job_alloc();
+ if (term->tl_job == NULL)
+ goto failed;
+ ++term->tl_job->jv_refcount;
+
+ /* behave like the job is already finished */
+ term->tl_job->jv_status = JOB_FINISHED;
+
+ channel = add_channel();
+ if (channel == NULL)
+ goto failed;
+ term->tl_job->jv_channel = channel;
+ channel->ch_keep_open = TRUE;
+ channel->ch_named_pipe = TRUE;
+
+ channel_set_pipes(channel,
+ (sock_T)hPipeIn,
+ (sock_T)hPipeOut,
+ (sock_T)hPipeOut);
+ channel_set_job(channel, term->tl_job, options);
+ term->tl_job->jv_tty_in = vim_strsave((char_u*)in_name);
+ term->tl_job->jv_tty_out = vim_strsave((char_u*)out_name);
+
+ return OK;
+
+failed:
+ if (hPipeIn != NULL)
+ CloseHandle(hPipeIn);
+ if (hPipeOut != NULL)
+ CloseHandle(hPipeOut);
+ return FAIL;
+}
+
+/*
+ * Free the terminal emulator part of "term".
+ */
+ static void
+term_free_vterm(term_T *term)
+{
+ term_free_conpty(term);
+ if (term->tl_winpty != NULL)
+ winpty_free(term->tl_winpty);
+ term->tl_winpty = NULL;
+ if (term->tl_winpty_config != NULL)
+ winpty_config_free(term->tl_winpty_config);
+ term->tl_winpty_config = NULL;
+ if (term->tl_vterm != NULL)
+ vterm_free(term->tl_vterm);
+ term->tl_vterm = NULL;
+}
+
+/*
+ * Report the size to the terminal.
+ */
+ static void
+term_report_winsize(term_T *term, int rows, int cols)
+{
+ if (term->tl_conpty)
+ conpty_term_report_winsize(term, rows, cols);
+ if (term->tl_winpty)
+ winpty_set_size(term->tl_winpty, cols, rows, NULL);
+}
+
+ int
+terminal_enabled(void)
+{
+ return dyn_winpty_init(FALSE) == OK || dyn_conpty_init(FALSE) == OK;
+}
+
+# else
+
+/**************************************
+ * 3. Unix-like implementation.
+ */
+
+/*
+ * Create a new terminal of "rows" by "cols" cells.
+ * Start job for "cmd".
+ * Store the pointers in "term".
+ * When "argv" is not NULL then "argvar" is not used.
+ * Return OK or FAIL.
+ */
+ static int
+term_and_job_init(
+ term_T *term,
+ typval_T *argvar,
+ char **argv,
+ jobopt_T *opt,
+ jobopt_T *orig_opt UNUSED)
+{
+ term->tl_arg0_cmd = NULL;
+
+ if (create_vterm(term, term->tl_rows, term->tl_cols) == FAIL)
+ return FAIL;
+
+#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
+ if (opt->jo_set2 & JO2_ANSI_COLORS)
+ set_vterm_palette(term->tl_vterm, opt->jo_ansi_colors);
+ else
+ init_vterm_ansi_colors(term->tl_vterm);
+#endif
+
+ /* This may change a string in "argvar". */
+ term->tl_job = job_start(argvar, argv, opt, TRUE);
+ if (term->tl_job != NULL)
+ ++term->tl_job->jv_refcount;
+
+ return term->tl_job != NULL
+ && term->tl_job->jv_channel != NULL
+ && term->tl_job->jv_status != JOB_FAILED ? OK : FAIL;
+}
+
+ static int
+create_pty_only(term_T *term, jobopt_T *opt)
+{
+ if (create_vterm(term, term->tl_rows, term->tl_cols) == FAIL)
+ return FAIL;
+
+ term->tl_job = job_alloc();
+ if (term->tl_job == NULL)
+ return FAIL;
+ ++term->tl_job->jv_refcount;
+
+ /* behave like the job is already finished */
+ term->tl_job->jv_status = JOB_FINISHED;
+
+ return mch_create_pty_channel(term->tl_job, opt);
+}
+
+/*
+ * Free the terminal emulator part of "term".
+ */
+ static void
+term_free_vterm(term_T *term)
+{
+ if (term->tl_vterm != NULL)
+ vterm_free(term->tl_vterm);
+ term->tl_vterm = NULL;
+}
+
+/*
+ * Report the size to the terminal.
+ */
+ static void
+term_report_winsize(term_T *term, int rows, int cols)
+{
+ /* Use an ioctl() to report the new window size to the job. */
+ if (term->tl_job != NULL && term->tl_job->jv_channel != NULL)
+ {
+ int fd = -1;
+ int part;
+
+ for (part = PART_OUT; part < PART_COUNT; ++part)
+ {
+ fd = term->tl_job->jv_channel->ch_part[part].ch_fd;
+ if (mch_isatty(fd))
+ break;
+ }
+ if (part < PART_COUNT && mch_report_winsize(fd, rows, cols) == OK)
+ mch_signal_job(term->tl_job, (char_u *)"winch");
+ }
+}
+
+# endif
+
+#endif /* FEAT_TERMINAL */
diff --git a/src/termlib.c b/src/termlib.c
new file mode 100644
index 0000000..0dc5894
--- /dev/null
+++ b/src/termlib.c
@@ -0,0 +1,618 @@
+/* vi:set ts=8 sts=4 sw=4 noet: */
+/*
+ * The following software is (C) 1984 Peter da Silva, the Mad Australian, in
+ * the public domain. It may be re-distributed for any purpose with the
+ * inclusion of this notice.
+ */
+
+/* Modified by Bram Moolenaar for use with VIM - Vi Improved. */
+/* A few bugs removed by Olaf 'Rhialto' Seibert. */
+
+/* TERMLIB: Terminal independent database. */
+
+#include "vim.h"
+#include "termlib.pro"
+
+#if !defined(AMIGA) && !defined(VMS)
+# include <sgtty.h>
+#endif
+
+static int getent(char *, char *, FILE *, int);
+static int nextent(char *, FILE *, int);
+static int _match(char *, char *);
+static char *_addfmt(char *, char *, int);
+static char *_find(char *, char *);
+
+/*
+ * Global variables for termlib
+ */
+
+char *tent; /* Pointer to terminal entry, set by tgetent */
+char PC = 0; /* Pad character, default NULL */
+char *UP = 0, *BC = 0; /* Pointers to UP and BC strings from database */
+short ospeed; /* Baud rate (1-16, 1=300, 16=19200), as in stty */
+
+/*
+ * Module: tgetent
+ *
+ * Purpose: Get termcap entry for <term> into buffer at <tbuf>.
+ *
+ * Calling conventions: char tbuf[TBUFSZ+], term=canonical name for terminal.
+ *
+ * Returned values: 1 = success, -1 = can't open file,
+ * 0 = can't find terminal.
+ *
+ * Notes:
+ * - Should probably supply static buffer.
+ * - Uses environment variables "TERM" and "TERMCAP". If TERM = term (that is,
+ * if the argument matches the environment) then it looks at TERMCAP.
+ * - If TERMCAP begins with a slash, then it assumes this is the file to
+ * search rather than /etc/termcap.
+ * - If TERMCAP does not begin with a slash, and it matches TERM, then this is
+ * used as the entry.
+ * - This could be simplified considerably for non-UNIX systems.
+ */
+
+#ifndef TERMCAPFILE
+# ifdef AMIGA
+# define TERMCAPFILE "s:termcap"
+# else
+# ifdef VMS
+# define TERMCAPFILE "VIMRUNTIME:termcap"
+# else
+# define TERMCAPFILE "/etc/termcap"
+# endif
+# endif
+#endif
+
+ int
+tgetent(
+ char *tbuf, /* Buffer to hold termcap entry, TBUFSZ bytes max */
+ char *term) /* Name of terminal */
+{
+ char tcbuf[32]; /* Temp buffer to handle */
+ char *tcptr = tcbuf; /* extended entries */
+ char *tcap = TERMCAPFILE; /* Default termcap file */
+ char *tmp;
+ FILE *termcap;
+ int retval = 0;
+ int len;
+
+ if ((tmp = (char *)mch_getenv((char_u *)"TERMCAP")) != NULL)
+ {
+ if (*tmp == '/') /* TERMCAP = name of termcap file */
+ {
+ tcap = tmp ;
+#if defined(AMIGA)
+ /* Convert /usr/share/lib/termcap to usr:share/lib/termcap */
+ tcap++;
+ tmp = strchr(tcap, '/');
+ if (tmp)
+ *tmp = ':';
+#endif
+ }
+ else /* TERMCAP = termcap entry itself */
+ {
+ int tlen = strlen(term);
+
+ while (*tmp && *tmp != ':') /* Check if TERM matches */
+ {
+ char *nexttmp;
+
+ while (*tmp == '|')
+ tmp++;
+ nexttmp = _find(tmp, ":|"); /* Rhialto */
+ if (tmp+tlen == nexttmp && _match(tmp, term) == tlen)
+ {
+ strcpy(tbuf, tmp);
+ tent = tbuf;
+ return 1;
+ }
+ else
+ tmp = nexttmp;
+ }
+ }
+ }
+ if (!(termcap = mch_fopen(tcap, "r")))
+ {
+ strcpy(tbuf, tcap);
+ return -1;
+ }
+
+ len = 0;
+ while (getent(tbuf + len, term, termcap, TBUFSZ - len))
+ {
+ tcptr = tcbuf; /* Rhialto */
+ if ((term = tgetstr("tc", &tcptr))) /* extended entry */
+ {
+ rewind(termcap);
+ len = strlen(tbuf);
+ }
+ else
+ {
+ retval = 1;
+ tent = tbuf; /* reset it back to the beginning */
+ break;
+ }
+ }
+ fclose(termcap);
+ return retval;
+}
+
+ static int
+getent(char *tbuf, char *term, FILE *termcap, int buflen)
+{
+ char *tptr;
+ int tlen = strlen(term);
+
+ while (nextent(tbuf, termcap, buflen)) /* For each possible entry */
+ {
+ tptr = tbuf;
+ while (*tptr && *tptr != ':') /* : terminates name field */
+ {
+ char *nexttptr;
+
+ while (*tptr == '|') /* | separates names */
+ tptr++;
+ nexttptr = _find(tptr, ":|"); /* Rhialto */
+ if (tptr + tlen == nexttptr &&
+ _match(tptr, term) == tlen) /* FOUND! */
+ {
+ tent = tbuf;
+ return 1;
+ }
+ else /* Look for next name */
+ tptr = nexttptr;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Read 1 entry from TERMCAP file.
+ */
+ static int
+nextent(char *tbuf, FILE *termcap, int buflen)
+{
+ char *lbuf = tbuf; /* lbuf=line buffer */
+ /* read lines straight into buffer */
+
+ while (lbuf < tbuf+buflen && /* There's room and */
+ fgets(lbuf, (int)(tbuf+buflen-lbuf), termcap)) /* another line */
+ {
+ int llen = strlen(lbuf);
+
+ if (*lbuf == '#') /* eat comments */
+ continue;
+ if (lbuf[-1] == ':' && /* and whitespace */
+ lbuf[0] == '\t' &&
+ lbuf[1] == ':')
+ {
+ STRMOVE(lbuf, lbuf + 2);
+ llen -= 2;
+ }
+ if (lbuf[llen-2] == '\\') /* and continuations */
+ lbuf += llen-2;
+ else
+ {
+ lbuf[llen-1]=0; /* no continuation, return */
+ return 1;
+ }
+ }
+
+ return 0; /* ran into end of file */
+}
+
+/*
+ * Module: tgetflag
+ *
+ * Purpose: returns flag true or false as to the existence of a given entry.
+ * used with 'bs', 'am', etc...
+ *
+ * Calling conventions: id is the 2 character capability id.
+ *
+ * Returned values: 1 for success, 0 for failure.
+ */
+
+ int
+tgetflag(char *id)
+{
+ char buf[256], *ptr = buf;
+
+ return tgetstr(id, &ptr) ? 1 : 0;
+}
+
+/*
+ * Module: tgetnum
+ *
+ * Purpose: get numeric value such as 'li' or 'co' from termcap.
+ *
+ * Calling conventions: id = 2 character id.
+ *
+ * Returned values: -1 for failure, else numerical value.
+ */
+
+ int
+tgetnum(char *id)
+{
+ char *ptr, buf[256];
+ ptr = buf;
+
+ if (tgetstr(id, &ptr))
+ return atoi(buf);
+ else
+ return 0;
+}
+
+/*
+ * Module: tgetstr
+ *
+ * Purpose: get terminal capability string from database.
+ *
+ * Calling conventions: id is the two character capability id.
+ * (*buf) points into a hold buffer for the
+ * id. the capability is copied into the buffer
+ * and (*buf) is advanced to point to the next
+ * free byte in the buffer.
+ *
+ * Returned values: 0 = no such entry, otherwise returns original
+ * (*buf) (now a pointer to the string).
+ *
+ * Notes
+ * It also decodes certain escape sequences in the buffer.
+ * they should be obvious from the code:
+ * \E = escape.
+ * \n, \r, \t, \f, \b match the 'c' escapes.
+ * ^x matches control-x (^@...^_).
+ * \nnn matches nnn octal.
+ * \x, where x is anything else, matches x. I differ
+ * from the standard library here, in that I allow ^: to match
+ * :.
+ *
+ */
+
+ char *
+tgetstr(char *id, char **buf)
+{
+ int len = strlen(id);
+ char *tmp=tent;
+ char *hold;
+ int i;
+
+ do {
+ tmp = _find(tmp, ":"); /* For each field */
+ while (*tmp == ':') /* skip empty fields */
+ tmp++;
+ if (!*tmp)
+ break;
+
+ if (_match(id, tmp) == len) {
+ tmp += len; /* find '=' '@' or '#' */
+ if (*tmp == '@') /* :xx@: entry for tc */
+ return 0; /* deleted entry */
+ hold= *buf;
+ while (*++tmp && *tmp != ':') { /* not at end of field */
+ switch(*tmp) {
+ case '\\': /* Expand escapes here */
+ switch(*++tmp) {
+ case 0: /* ignore backslashes */
+ tmp--; /* at end of entry */
+ break; /* shouldn't happen */
+ case 'e':
+ case 'E': /* ESC */
+ *(*buf)++ = ESC;
+ break;
+ case 'n': /* \n */
+ *(*buf)++ = '\n';
+ break;
+ case 'r': /* \r */
+ *(*buf)++ = '\r';
+ break;
+ case 't': /* \t */
+ *(*buf)++ = '\t';
+ break;
+ case 'b': /* \b */
+ *(*buf)++ = '\b';
+ break;
+ case 'f': /* \f */
+ *(*buf)++ = '\f';
+ break;
+ case '0': /* \nnn */
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ **buf = 0;
+ /* get up to three digits */
+ for (i = 0; i < 3 && VIM_ISDIGIT(*tmp); ++i)
+ **buf = **buf * 8 + *tmp++ - '0';
+ (*buf)++;
+ tmp--;
+ break;
+ default: /* \x, for all other x */
+ *(*buf)++= *tmp;
+ }
+ break;
+ case '^': /* control characters */
+ ++tmp;
+ *(*buf)++ = Ctrl_chr(*tmp);
+ break;
+ default:
+ *(*buf)++ = *tmp;
+ }
+ }
+ *(*buf)++ = 0;
+ return hold;
+ }
+ } while (*tmp);
+
+ return 0;
+}
+
+/*
+ * Module: tgoto
+ *
+ * Purpose: decode cm cursor motion string.
+ *
+ * Calling conventions: cm is cursor motion string. line, col, are the
+ * desired destination.
+ *
+ * Returned values: a string pointing to the decoded string, or "OOPS" if it
+ * cannot be decoded.
+ *
+ * Notes
+ * The accepted escapes are:
+ * %d as in printf, 0 origin.
+ * %2, %3 like %02d, %03d in printf.
+ * %. like %c
+ * %+x adds <x> to value, then %.
+ * %>xy if value>x, adds y. No output.
+ * %i increments line& col, no output.
+ * %r reverses order of line&col. No output.
+ * %% prints as a single %.
+ * %n exclusive or row & col with 0140.
+ * %B BCD, no output.
+ * %D reverse coding (x-2*(x%16)), no output.
+ */
+
+ char *
+tgoto(
+ char *cm, /* cm string, from termcap */
+ int col, /* column, x position */
+ int line) /* line, y position */
+{
+ char gx, gy, /* x, y */
+ *ptr, /* pointer in 'cm' */
+ reverse = 0, /* reverse flag */
+ *bufp, /* pointer in returned string */
+ addup = 0, /* add upline */
+ addbak = 0, /* add backup */
+ c;
+ static char buffer[32];
+
+ if (!cm)
+ return "OOPS"; /* Kludge, but standard */
+
+ bufp = buffer;
+ ptr = cm;
+
+ while (*ptr) {
+ if ((c = *ptr++) != '%') { /* normal char */
+ *bufp++ = c;
+ } else { /* % escape */
+ switch(c = *ptr++) {
+ case 'd': /* decimal */
+ bufp = _addfmt(bufp, "%d", line);
+ line = col;
+ break;
+ case '2': /* 2 digit decimal */
+ bufp = _addfmt(bufp, "%02d", line);
+ line = col;
+ break;
+ case '3': /* 3 digit decimal */
+ bufp = _addfmt(bufp, "%03d", line);
+ line = col;
+ break;
+ case '>': /* %>xy: if >x, add y */
+ gx = *ptr++;
+ gy = *ptr++;
+ if (col>gx) col += gy;
+ if (line>gx) line += gy;
+ break;
+ case '+': /* %+c: add c */
+ line += *ptr++;
+ case '.': /* print x/y */
+ if (line == '\t' || /* these are */
+ line == '\n' || /* chars that */
+ line == '\004' || /* UNIX hates */
+ line == '\0') {
+ line++; /* so go to next pos */
+ if (reverse == (line == col))
+ addup=1; /* and mark UP */
+ else
+ addbak=1; /* or BC */
+ }
+ *bufp++=line;
+ line = col;
+ break;
+ case 'r': /* r: reverse */
+ gx = line;
+ line = col;
+ col = gx;
+ reverse = 1;
+ break;
+ case 'i': /* increment (1-origin screen) */
+ col++;
+ line++;
+ break;
+ case '%': /* %%=% literally */
+ *bufp++='%';
+ break;
+ case 'n': /* magic DM2500 code */
+ line ^= 0140;
+ col ^= 0140;
+ break;
+ case 'B': /* bcd encoding */
+ line = line/10<<4+line%10;
+ col = col/10<<4+col%10;
+ break;
+ case 'D': /* magic Delta Data code */
+ line = line-2*(line&15);
+ col = col-2*(col&15);
+ break;
+ default: /* Unknown escape */
+ return "OOPS";
+ }
+ }
+ }
+
+ if (addup) /* add upline */
+ if (UP) {
+ ptr=UP;
+ while (VIM_ISDIGIT(*ptr) || *ptr == '.')
+ ptr++;
+ if (*ptr == '*')
+ ptr++;
+ while (*ptr)
+ *bufp++ = *ptr++;
+ }
+
+ if (addbak) /* add backspace */
+ if (BC) {
+ ptr=BC;
+ while (VIM_ISDIGIT(*ptr) || *ptr == '.')
+ ptr++;
+ if (*ptr == '*')
+ ptr++;
+ while (*ptr)
+ *bufp++ = *ptr++;
+ }
+ else
+ *bufp++='\b';
+
+ *bufp = 0;
+
+ return(buffer);
+}
+
+/*
+ * Module: tputs
+ *
+ * Purpose: decode padding information
+ *
+ * Calling conventions: cp = string to be padded, affcnt = # of items affected
+ * (lines, characters, whatever), outc = routine to output 1 character.
+ *
+ * Returned values: none
+ *
+ * Notes
+ * cp has padding information ahead of it, in the form
+ * nnnTEXT or nnn*TEXT. nnn is the number of milliseconds to delay,
+ * and may be a decimal (nnn.mmm). If the asterisk is given, then
+ * the delay is multiplied by afcnt. The delay is produced by outputting
+ * a number of nulls (or other padding char) after printing the
+ * TEXT.
+ *
+ */
+
+long _bauds[16]={
+ 0, 50, 75, 110,
+ 134, 150, 200, 300,
+ 600, 1200, 1800, 2400,
+ 4800, 9600, 19200, 19200 };
+
+ int
+tputs(
+ char *cp, /* string to print */
+ int affcnt, /* Number of lines affected */
+ void (*outc)(unsigned int)) /* routine to output 1 character */
+{
+ long frac, /* 10^(#digits after decimal point) */
+ counter, /* digits */
+ atol(const char *);
+
+ if (VIM_ISDIGIT(*cp)) {
+ counter = 0;
+ frac = 1000;
+ while (VIM_ISDIGIT(*cp))
+ counter = counter * 10L + (long)(*cp++ - '0');
+ if (*cp == '.')
+ while (VIM_ISDIGIT(*++cp)) {
+ counter = counter * 10L + (long)(*cp++ - '0');
+ frac = frac * 10;
+ }
+ if (*cp!='*') { /* multiply by affected lines */
+ if (affcnt>1) affcnt = 1;
+ }
+ else
+ cp++;
+
+ /* Calculate number of characters for padding counter/frac ms delay */
+ if (ospeed)
+ counter = (counter * _bauds[ospeed] * (long)affcnt) / frac;
+
+ while (*cp) /* output string */
+ (*outc)(*cp++);
+ if (ospeed)
+ while (counter--) /* followed by pad characters */
+ (*outc)(PC);
+ }
+ else
+ while (*cp)
+ (*outc)(*cp++);
+ return 0;
+}
+
+/*
+ * Module: tutil.c
+ *
+ * Purpose: Utility routines for TERMLIB functions.
+ * Returns length of text common to s1 and s2.
+ */
+ static int
+_match(char *s1, char *s2)
+{
+ int i = 0;
+
+ while (s1[i] && s1[i] == s2[i])
+ i++;
+
+ return i;
+}
+
+/*
+ * finds next c in s that's a member of set, returns pointer
+ */
+ static char *
+_find(char *s, char *set)
+{
+ for(; *s; s++)
+ {
+ char *ptr = set;
+
+ while (*ptr && *s != *ptr)
+ ptr++;
+
+ if (*ptr)
+ return s;
+ }
+
+ return s;
+}
+
+/*
+ * add val to buf according to format fmt
+ */
+ static char *
+_addfmt(char *buf, char *fmt, int val)
+{
+ sprintf(buf, fmt, val);
+ while (*buf)
+ buf++;
+ return buf;
+}
diff --git a/src/testdir/Make_all.mak b/src/testdir/Make_all.mak
new file mode 100644
index 0000000..5857a22
--- /dev/null
+++ b/src/testdir/Make_all.mak
@@ -0,0 +1,418 @@
+#
+# Common Makefile, defines the list of tests to run.
+#
+
+# Options for protecting the tests against undesirable interaction with the
+# environment
+NO_PLUGINS = --noplugin --not-a-term
+NO_INITS = -U NONE $(NO_PLUGINS)
+
+# The first script creates small.vim.
+SCRIPTS_FIRST = \
+ test1.out
+
+# Tests that run on all systems.
+SCRIPTS_ALL = \
+ test3.out \
+ test14.out \
+ test29.out \
+ test37.out \
+ test39.out \
+ test42.out \
+ test44.out \
+ test48.out \
+ test64.out \
+ test69.out \
+ test70.out \
+ test88.out \
+ test94.out \
+ test95.out \
+ test99.out \
+ test108.out \
+ test_eval.out
+
+
+# Tests that run on most systems, but not on Amiga.
+SCRIPTS_MORE1 = \
+ test11.out \
+ test52.out \
+ test86.out \
+ test87.out
+
+
+# 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 = \
+ test17.out \
+ test30.out \
+ test59.out \
+ test72.out \
+
+
+# Tests specifically for MS-Windows.
+SCRIPTS_WIN32 =
+
+
+# Tests for the GUI.
+SCRIPTS_GUI =
+
+# Individual tests, including the ones part of test_alot.
+# Please keep sorted up to test_alot.
+NEW_TESTS = \
+ test_arglist \
+ test_arabic \
+ test_assert \
+ test_assign \
+ test_autochdir \
+ test_autocmd \
+ test_autoload \
+ test_backspace_opt \
+ test_backup \
+ test_behave \
+ test_blob \
+ test_blockedit \
+ test_breakindent \
+ test_bufline \
+ test_bufwintabinfo \
+ test_cd \
+ test_cdo \
+ test_changedtick \
+ test_changelist \
+ test_channel \
+ test_charsearch \
+ test_charsearch_utf8 \
+ test_cindent \
+ test_clientserver \
+ test_close_count \
+ test_cmdline \
+ test_command_count \
+ test_comparators \
+ test_compiler \
+ test_conceal \
+ test_crypt \
+ test_cscope \
+ test_cursor_func \
+ test_curswant \
+ test_delete \
+ test_diffmode \
+ test_digraph \
+ test_display \
+ test_edit \
+ test_erasebackword \
+ test_escaped_glob \
+ test_eval_stuff \
+ test_ex_equal \
+ test_ex_undo \
+ test_ex_z \
+ test_exit \
+ test_exec_while_if \
+ test_execute_func \
+ test_exists \
+ test_exists_autocmd \
+ test_expand \
+ test_expand_dllpath \
+ test_expand_func \
+ test_expr \
+ test_expr_utf8 \
+ test_farsi \
+ test_feedkeys \
+ test_file_perm \
+ test_file_size \
+ test_filechanged \
+ test_fileformat \
+ test_filetype \
+ test_filter_cmd \
+ test_filter_map \
+ test_find_complete \
+ test_findfile \
+ test_fixeol \
+ test_float_func \
+ test_fnameescape \
+ test_fnamemodify \
+ test_fold \
+ test_functions \
+ test_ga \
+ test_getcwd \
+ test_getvar \
+ test_gf \
+ test_glob2regpat \
+ test_global \
+ test_gn \
+ test_goto \
+ test_gui \
+ test_gui_init \
+ test_hardcopy \
+ test_help \
+ test_help_tagjump \
+ test_hide \
+ test_highlight \
+ test_history \
+ test_hlsearch \
+ test_iminsert \
+ test_increment \
+ test_increment_dbcs \
+ test_ins_complete \
+ test_job_fails \
+ test_join \
+ test_json \
+ test_jumplist \
+ test_jumps \
+ test_lambda \
+ test_langmap \
+ test_largefile \
+ test_let \
+ test_lineending \
+ test_lispwords \
+ test_listchars \
+ test_listdict \
+ test_listlbr \
+ test_listlbr_utf8 \
+ test_lua \
+ test_makeencoding \
+ test_man \
+ test_maparg \
+ test_mapping \
+ test_marks \
+ test_match \
+ test_matchadd_conceal \
+ test_matchadd_conceal_utf8 \
+ test_menu \
+ test_messages \
+ test_mksession \
+ test_mksession_utf8 \
+ test_modeline \
+ test_move \
+ test_nested_function \
+ test_netbeans \
+ test_normal \
+ test_number \
+ test_options \
+ test_packadd \
+ test_partial \
+ test_paste \
+ test_perl \
+ test_plus_arg_edit \
+ test_popup \
+ test_preview \
+ test_profile \
+ test_prompt_buffer \
+ test_put \
+ test_python2 \
+ test_python3 \
+ test_pyx2 \
+ test_pyx3 \
+ test_quickfix \
+ test_quotestar \
+ test_recover \
+ test_regex_char_classes \
+ test_regexp_latin \
+ test_regexp_utf8 \
+ test_registers \
+ test_reltime \
+ test_retab \
+ test_ruby \
+ test_scriptnames \
+ test_scroll_opt \
+ test_scrollbind \
+ test_search \
+ test_searchpos \
+ test_set \
+ test_sha256 \
+ test_signs \
+ test_smartindent \
+ test_sort \
+ test_source \
+ test_source_utf8 \
+ test_spell \
+ test_startup \
+ test_startup_utf8 \
+ test_stat \
+ test_statusline \
+ test_substitute \
+ test_suspend \
+ test_swap \
+ test_syn_attr \
+ test_syntax \
+ test_system \
+ test_tab \
+ test_tabline \
+ test_tabpage \
+ test_tagcase \
+ test_tagjump \
+ test_taglist \
+ test_tcl \
+ test_termencoding \
+ test_terminal \
+ test_terminal_fail \
+ test_textformat \
+ test_textobjects \
+ test_textprop \
+ test_timers \
+ test_true_false \
+ test_undo \
+ test_unlet \
+ test_usercommands \
+ test_utf8 \
+ test_utf8_comparisons \
+ test_vartabs \
+ test_viminfo \
+ test_vimscript \
+ test_virtualedit \
+ test_visual \
+ test_winbar \
+ test_winbuf_close \
+ test_window_cmd \
+ test_window_id \
+ test_windows_home \
+ test_wordcount \
+ test_writefile \
+ test_xxd \
+ test_alot_latin \
+ test_alot_utf8 \
+ test_alot
+
+
+# Test targets that use runtest.vim.
+# Keep test_alot*.res as the last one, sort the others.
+# test_largefile.res is omitted, it uses too much resources to run on CI.
+NEW_TESTS_RES = \
+ test_arabic.res \
+ test_arglist.res \
+ test_assert.res \
+ test_autochdir.res \
+ test_autocmd.res \
+ test_autoload.res \
+ test_backspace_opt.res \
+ test_blob.res \
+ test_blockedit.res \
+ test_breakindent.res \
+ test_bufwintabinfo.res \
+ test_cdo.res \
+ test_changelist.res \
+ test_channel.res \
+ test_charsearch.res \
+ test_cindent.res \
+ test_clientserver.res \
+ test_close_count.res \
+ test_cmdline.res \
+ test_command_count.res \
+ test_comparators.res \
+ test_conceal.res \
+ test_crypt.res \
+ test_cscope.res \
+ test_curswant.res \
+ test_diffmode.res \
+ test_digraph.res \
+ test_display.res \
+ test_edit.res \
+ test_erasebackword.res \
+ test_escaped_glob.res \
+ test_eval_stuff.res \
+ test_exec_while_if.res \
+ test_exists.res \
+ test_exists_autocmd.res \
+ test_exit.res \
+ test_farsi.res \
+ test_file_size.res \
+ test_filechanged.res \
+ test_find_complete.res \
+ test_fixeol.res \
+ test_fnameescape.res \
+ test_fold.res \
+ test_getcwd.res \
+ test_getvar.res \
+ test_gf.res \
+ test_gn.res \
+ test_gui.res \
+ test_gui_init.res \
+ test_hardcopy.res \
+ test_help.res \
+ test_hide.res \
+ test_highlight.res \
+ test_history.res \
+ test_hlsearch.res \
+ test_iminsert.res \
+ test_increment.res \
+ test_increment_dbcs.res \
+ test_ins_complete.res \
+ test_job_fails.res \
+ test_json.res \
+ test_jumplist.res \
+ test_langmap.res \
+ test_let.res \
+ test_lineending.res \
+ test_listchars.res \
+ test_listdict.res \
+ test_listlbr.res \
+ test_lua.res \
+ test_makeencoding.res \
+ test_man.res \
+ test_maparg.res \
+ test_marks.res \
+ test_matchadd_conceal.res \
+ test_mksession.res \
+ test_nested_function.res \
+ test_netbeans.res \
+ test_normal.res \
+ test_number.res \
+ test_options.res \
+ test_packadd.res \
+ test_paste.res \
+ test_perl.res \
+ test_plus_arg_edit.res \
+ test_preview.res \
+ test_profile.res \
+ test_prompt_buffer.res \
+ test_python2.res \
+ test_python3.res \
+ test_pyx2.res \
+ test_pyx3.res \
+ test_quickfix.res \
+ test_quotestar.res \
+ test_regex_char_classes.res \
+ test_registers.res \
+ test_retab.res \
+ test_ruby.res \
+ test_scriptnames.res \
+ test_scrollbind.res \
+ test_search.res \
+ test_shortpathname.res \
+ test_signs.res \
+ test_smartindent.res \
+ test_source.res \
+ test_spell.res \
+ test_startup.res \
+ test_stat.res \
+ test_substitute.res \
+ test_swap.res \
+ test_syntax.res \
+ test_system.res \
+ test_tab.res \
+ test_tcl.res \
+ test_termencoding.res \
+ test_terminal.res \
+ test_terminal_fail.res \
+ test_textformat.res \
+ test_textobjects.res \
+ test_textprop.res \
+ test_undo.res \
+ test_user_func.res \
+ test_usercommands.res \
+ test_vartabs.res \
+ test_viminfo.res \
+ test_vimscript.res \
+ test_visual.res \
+ test_winbar.res \
+ test_winbuf_close.res \
+ test_window_id.res \
+ test_windows_home.res \
+ test_wordcount.res \
+ test_writefile.res \
+ test_xxd.res \
+ test_alot_latin.res \
+ test_alot_utf8.res \
+ test_alot.res
diff --git a/src/testdir/Make_amiga.mak b/src/testdir/Make_amiga.mak
new file mode 100644
index 0000000..b71b220
--- /dev/null
+++ b/src/testdir/Make_amiga.mak
@@ -0,0 +1,45 @@
+#
+# Makefile to run all tests for Vim, on Amiga
+#
+# Requires "rm", "csh" and "diff"!
+
+VIMPROG = /vim
+
+default: nongui
+
+include Make_all.mak
+
+# These tests don't work (yet):
+# test2 "\\tmp" doesn't work
+# test10 'errorformat' is different
+# test11 "cat" doesn't work properly
+# test52 only for Win32
+# test86, 87 no Python interface
+
+SCRIPTS = $(SCRIPTS_ALL) $(SCRIPTS_MORE4)
+
+# Must run test1 first to create small.vim.
+$(SCRIPTS) $(SCRIPTS_GUI) $(NEW_TESTS_RES): $(SCRIPTS_FIRST)
+
+.SUFFIXES: .in .out
+
+nongui: /tmp $(SCRIPTS_FIRST) $(SCRIPTS)
+ csh -c echo ALL DONE
+
+clean:
+ csh -c \rm -rf *.out /tmp/* Xdotest small.vim tiny.vim mbyte.vim test.ok viminfo
+
+.in.out:
+ copy $*.ok test.ok
+ $(VIMPROG) -u amiga.vim -U NONE --noplugin --not-a-term -s dotest.in $*.in
+ diff test.out $*.ok
+ rename test.out $*.out
+ -delete X#? ALL QUIET
+ -delete test.ok
+
+# Create a directory for temp files
+/tmp:
+ makedir /tmp
+
+# Manx requires all dependencies, but we stopped updating them.
+# Delete the .out file(s) to run test(s).
diff --git a/src/testdir/Make_dos.mak b/src/testdir/Make_dos.mak
new file mode 100644
index 0000000..5776a79
--- /dev/null
+++ b/src/testdir/Make_dos.mak
@@ -0,0 +1,138 @@
+#
+# Makefile to run all tests for Vim, on Dos-like machines.
+#
+# Requires a set of Unix tools: echo, diff, etc.
+
+VIMPROG = ..\\vim
+
+default: nongui
+
+!include Make_all.mak
+
+# Omitted:
+# test2 "\\tmp" doesn't work.
+# test10 'errorformat' is different
+# test49 fails in various ways
+# test97 \{ and \$ are not escaped characters.
+
+SCRIPTS = $(SCRIPTS_ALL) $(SCRIPTS_MORE1) $(SCRIPTS_MORE4)
+
+TEST_OUTFILES = $(SCRIPTS_FIRST) $(SCRIPTS) $(SCRIPTS_WIN32) $(SCRIPTS_GUI)
+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
+
+small: nolog report
+
+gui: nolog $(SCRIPTS_FIRST) $(SCRIPTS) $(SCRIPTS_GUI) newtests report
+
+win32: nolog $(SCRIPTS_FIRST) $(SCRIPTS) $(SCRIPTS_WIN32) newtests report
+
+# Copy the input files to dostmp, changing the fileformat to dos.
+$(DOSTMP_INFILES): $(*B).in
+ if not exist $(DOSTMP)\NUL md $(DOSTMP)
+ if exist $@ del $@
+ $(VIMPROG) -u dos.vim $(NO_INITS) "+set ff=dos|f $@|wq" $(*B).in
+
+# For each input file dostmp/test99.in run the tests.
+# This moves test99.in to test99.in.bak temporarily.
+$(TEST_OUTFILES): $(DOSTMP)\$(*B).in
+ -@if exist test.out DEL test.out
+ -@if exist $(DOSTMP)\$(*B).out DEL $(DOSTMP)\$(*B).out
+ move $(*B).in $(*B).in.bak > nul
+ copy $(DOSTMP)\$(*B).in $(*B).in > nul
+ copy $(*B).ok test.ok > nul
+ $(VIMPROG) -u dos.vim $(NO_INITS) -s dotest.in $(*B).in
+ -@if exist test.out MOVE /y test.out $(DOSTMP)\$(*B).out > nul
+ -@if exist $(*B).in.bak move /y $(*B).in.bak $(*B).in > nul
+ -@if exist test.ok del test.ok
+ -@if exist Xdir1 rd /s /q Xdir1
+ -@if exist Xfind rd /s /q Xfind
+ -@if exist XfakeHOME rd /s /q XfakeHOME
+ -@del X*
+ -@if exist viminfo del viminfo
+ $(VIMPROG) -u dos.vim $(NO_INITS) "+set ff=unix|f test.out|wq" \
+ $(DOSTMP)\$(*B).out
+ @diff test.out $*.ok & if errorlevel 1 \
+ ( move /y test.out $*.failed > nul \
+ & del $(DOSTMP)\$(*B).out \
+ & echo $* FAILED >> test.log ) \
+ else ( move /y test.out $*.out > nul )
+
+# Must run test1 first to create small.vim.
+# This rule must come after the one that copies the input files to dostmp to
+# allow for running an individual test.
+$(SCRIPTS) $(SCRIPTS_GUI) $(SCRIPTS_WIN32) $(NEW_TESTS_RES): $(SCRIPTS_FIRST)
+
+report:
+ @echo ""
+ @echo Test results:
+ @if exist test.log ( type test.log & echo TEST FAILURE & exit /b 1 ) \
+ else ( echo ALL DONE )
+
+clean:
+ -del *.out
+ -del *.failed
+ -del *.res
+ -if exist $(DOSTMP) rd /s /q $(DOSTMP)
+ -if exist test.in del test.in
+ -if exist test.ok del test.ok
+ -if exist small.vim del small.vim
+ -if exist tiny.vim del tiny.vim
+ -if exist mbyte.vim del mbyte.vim
+ -if exist mzscheme.vim del mzscheme.vim
+ -if exist Xdir1 rd /s /q Xdir1
+ -if exist Xfind rd /s /q Xfind
+ -if exist XfakeHOME rd /s /q XfakeHOME
+ -del X*
+ -for /d %i in (X*) do @rmdir /s/q %i
+ -if exist viminfo del viminfo
+ -if exist test.log del test.log
+ -if exist messages del messages
+ -if exist benchmark.out del benchmark.out
+ -if exist opt_test.vim del opt_test.vim
+
+nolog:
+ -if exist test.log del test.log
+ -if exist messages del messages
+
+benchmark:
+ bench_re_freeze.out
+
+bench_re_freeze.out: bench_re_freeze.vim
+ -if exist benchmark.out del benchmark.out
+ $(VIMPROG) -u dos.vim $(NO_INITS) $*.in
+ @IF EXIST benchmark.out ( type benchmark.out )
+
+# New style of tests uses Vim script with assert calls. These are easier
+# to write and a lot easier to read and debug.
+# Limitation: Only works with the +eval feature.
+
+newtests: newtestssilent
+ @if exist messages (findstr "SKIPPED FAILED" messages > nul) && type messages
+
+newtestssilent: $(NEW_TESTS_RES)
+
+.vim.res:
+ @echo $(VIMPROG) > vimcmd
+ $(VIMPROG) -u NONE $(NO_INITS) -S runtest.vim $*.vim
+ @del vimcmd
+
+test_gui.res: test_gui.vim
+ @echo $(VIMPROG) > vimcmd
+ $(VIMPROG) -u NONE $(NO_INITS) -S runtest.vim $*.vim
+ @del vimcmd
+
+test_gui_init.res: test_gui_init.vim
+ @echo $(VIMPROG) > vimcmd
+ $(VIMPROG) -u gui_preinit.vim -U gui_init.vim $(NO_PLUGINS) -S runtest.vim $*.vim
+ @del vimcmd
+
+test_options.res test_alot.res: opt_test.vim
+
+opt_test.vim: ../option.c gen_opt_test.vim
+ $(VIMPROG) -u NONE -S gen_opt_test.vim --noplugin --not-a-term ../option.c
diff --git a/src/testdir/Make_ming.mak b/src/testdir/Make_ming.mak
new file mode 100644
index 0000000..2ad34b9
--- /dev/null
+++ b/src/testdir/Make_ming.mak
@@ -0,0 +1,142 @@
+#
+# Makefile to run all tests for Vim, on Dos-like machines
+# with sh.exe or zsh.exe in the path or not.
+#
+# Author: Bill McCarthy
+#
+# Requires a set of Unix tools: echo, diff, etc.
+
+ifneq (sh.exe, $(SHELL))
+DEL = rm -f
+DELDIR = rm -rf
+MV = mv
+CP = cp
+CAT = cat
+DIRSLASH = /
+else
+DEL = del
+DELDIR = rd /s /q
+MV = rename
+CP = copy
+CAT = type
+DIRSLASH = \\
+endif
+
+VIMPROG = ..$(DIRSLASH)vim
+
+default: vimall
+
+include Make_all.mak
+
+# Omitted:
+# test2 "\\tmp" doesn't work.
+# test10 'errorformat' is different
+# test97 \{ and \$ are not escaped characters
+
+SCRIPTS = $(SCRIPTS_ALL) $(SCRIPTS_MORE1) $(SCRIPTS_MORE4) $(SCRIPTS_WIN32)
+
+SCRIPTS_BENCH = bench_re_freeze.out
+
+# Must run test1 first to create small.vim.
+$(SCRIPTS) $(SCRIPTS_GUI) $(SCRIPTS_WIN32) $(NEW_TESTS_RES): $(SCRIPTS_FIRST)
+
+.SUFFIXES: .in .out .res .vim
+
+vimall: fixff $(SCRIPTS_FIRST) $(SCRIPTS) $(SCRIPTS_GUI) $(SCRIPTS_WIN32) newtests
+ @echo ALL DONE
+
+nongui: fixff nolog $(SCRIPTS_FIRST) $(SCRIPTS) newtests
+ @echo ALL DONE
+
+benchmark: $(SCRIPTS_BENCH)
+
+small: nolog
+ @echo ALL DONE
+
+gui: fixff nolog $(SCRIPTS_FIRST) $(SCRIPTS) $(SCRIPTS_GUI) newtests
+ @echo ALL DONE
+
+win32: fixff nolog $(SCRIPTS_FIRST) $(SCRIPTS) $(SCRIPTS_WIN32) newtests
+ @echo ALL DONE
+
+# TODO: find a way to avoid changing the distributed files.
+fixff:
+ -$(VIMPROG) -u dos.vim $(NO_INITS) "+argdo set ff=dos|upd" +q *.in *.ok
+ -$(VIMPROG) -u dos.vim $(NO_INITS) "+argdo set ff=unix|upd" +q \
+ dotest.in
+
+clean:
+ -@if exist *.out $(DEL) *.out
+ -@if exist *.failed $(DEL) *.failed
+ -@if exist *.res $(DEL) *.res
+ -@if exist test.in $(DEL) test.in
+ -@if exist test.ok $(DEL) test.ok
+ -@if exist small.vim $(DEL) small.vim
+ -@if exist tiny.vim $(DEL) tiny.vim
+ -@if exist mbyte.vim $(DEL) mbyte.vim
+ -@if exist mzscheme.vim $(DEL) mzscheme.vim
+ -@if exist Xdir1 $(DELDIR) Xdir1
+ -@if exist Xfind $(DELDIR) Xfind
+ -@if exist XfakeHOME $(DELDIR) XfakeHOME
+ -@if exist X* $(DEL) X*
+ -@if exist viminfo $(DEL) viminfo
+ -@if exist test.log $(DEL) test.log
+ -@if exist messages $(DEL) messages
+ -@if exist opt_test.vim $(DEL) opt_test.vim
+
+test1.out: test1.in
+ -@if exist wrongtermsize $(DEL) wrongtermsize
+ $(VIMPROG) -u dos.vim $(NO_INITS) -s dotest.in test1.in
+ -@if exist wrongtermsize ( \
+ echo Vim window too small- must be 80x25 or larger && exit 1 \
+ )
+ -@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
+
+bench_re_freeze.out: bench_re_freeze.vim
+ -$(DEL) benchmark.out
+ $(VIMPROG) -u dos.vim $(NO_INITS) $*.in
+ $(CAT) benchmark.out
+
+# New style of tests uses Vim script with assert calls. These are easier
+# to write and a lot easier to read and debug.
+# Limitation: Only works with the +eval feature.
+
+newtests: $(NEW_TESTS_RES)
+
+.vim.res:
+ @echo $(VIMPROG) > vimcmd
+ $(VIMPROG) -u NONE $(NO_INITS) -S runtest.vim $*.vim
+ @$(DEL) vimcmd
+
+test_gui.res: test_gui.vim
+ @echo $(VIMPROG) > vimcmd
+ $(VIMPROG) -u NONE $(NO_INITS) -S runtest.vim $<
+ @$(DEL) vimcmd
+
+test_gui_init.res: test_gui_init.vim
+ @echo $(VIMPROG) > vimcmd
+ $(VIMPROG) -u gui_preinit.vim -U gui_init.vim $(NO_PLUGINS) -S runtest.vim $<
+ @$(DEL) vimcmd
+
+test_options.res test_alot.res: opt_test.vim
+
+opt_test.vim: ../option.c gen_opt_test.vim
+ $(VIMPROG) -u NONE -S gen_opt_test.vim --noplugin --not-a-term ../option.c
diff --git a/src/testdir/Make_vms.mms b/src/testdir/Make_vms.mms
new file mode 100644
index 0000000..f14f6bc
--- /dev/null
+++ b/src/testdir/Make_vms.mms
@@ -0,0 +1,212 @@
+#
+# Makefile to run all tests for Vim on VMS
+#
+# Authors: Zoltan Arpadffy, <arpadffy@polarhome.com>
+# Sandor Kopanyi, <sandor.kopanyi@mailbox.hu>
+#
+# Last change: 2016 Nov 04
+#
+# This has been tested on VMS 6.2 to 8.3 on DEC Alpha, VAX and IA64.
+# Edit the lines in the Configuration section below to select.
+#
+# Execute with:
+# mms/descrip=Make_vms.mms
+# Cleanup with:
+# mms/descrip=Make_vms.mms clean
+#
+# Make files are MMK compatible.
+#
+# NOTE: You can run this script just in X/Window environment. It will
+# create a new terminals, therefore you have to set up your DISPLAY
+# logical. More info in VMS documentation or with: help set disp.
+#
+#######################################################################
+# Configuration section.
+#######################################################################
+
+# 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 want to run Win32 specific tests as well, but please
+# be aware, that on OpenVMS will fail, because of cat, rm, etc commands
+# and directory handling.
+# WANT_WIN = YES
+
+# Comment out if you want to run spell checker tests.
+# They fail because VMS does not support file names.
+# WANT_SPELL = YES
+
+# Comment out if you want to run mzschema tests.
+# It fails because VMS does not support this feature yet.
+# WANT_MZSCH = YES
+
+# Comment out if you have ODS-5 file system
+# HAVE_ODS5 = 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.
+#
+# Please, do not change anything below without programming experience.
+#######################################################################
+
+VIMPROG = <->vim.exe
+
+.SUFFIXES : .out .in
+
+SCRIPT = test1.out test3.out \
+ test14.out \
+ test29.out \
+ test30.out test37.out test39.out \
+ test42.out test44.out test48.out test49.out \
+ test64.out test69.out \
+ test72.out test77a.out test88.out \
+ test94.out test95.out test99.out test108.out \
+ test_eval.out
+
+# Known problems:
+# test17: ?
+#
+# test30: bug, most probably - a problem around mac format
+#
+# test59: Failed/Hangs - VMS does not support spell files (file names
+# with too many dots).
+#
+# test72: bug - Vim hangs at :rename (while rename works well otherwise)
+# test78: bug - Vim dies at :recover Xtest
+# test89: bug - findfile() does not work on VMS (just in the current directory)
+# test102: Just ODS-5 supports space and special chars in the filename.
+# On ODS-2 tests fail.
+
+.IFDEF WANT_GUI
+SCRIPT_GUI = test16.out
+GUI_OPTION = -g
+.ENDIF
+
+.IFDEF WANT_UNIX
+SCRIPT_UNIX = test10.out test17.out test27.out test49.out
+.ENDIF
+
+.IFDEF WANT_WIN
+SCRIPT_WIN = test52.out
+.ENDIF
+
+.IFDEF WANT_SPELL
+SCRIPT_SPELL = test59.out
+.ENDIF
+
+.IFDEF WANT_MZSCH
+SCRIPT_MZSCH = test70.out
+.ENDIF
+
+.IFDEF HAVE_ODS5
+SCRIPT_ODS5 = test102.out
+.ENDIF
+
+.IFDEF HAVE_GZIP
+SCRIPT_GZIP = test11.out
+.ENDIF
+
+.IFDEF HAVE_GDIFF
+SCRIPT_GDIFF = test47.out
+.ENDIF
+
+.IFDEF HAVE_PYTHON
+SCRIPT_PYTHON = test86.out test87.out
+.ENDIF
+
+.in.out :
+ -@ !clean up before doing the test
+ -@ if "''F$SEARCH("test.out.*")'" .NES. "" then delete/noconfirm/nolog test.out.*
+ -@ if "''F$SEARCH("$*.out.*")'" .NES. "" then delete/noconfirm/nolog $*.out.*
+ -@ ! define TMP if not set - some tests use it
+ -@ if "''F$TRNLNM("TMP")'" .EQS. "" then define/nolog TMP []
+ -@ write sys$output " "
+ -@ write sys$output "-----------------------------------------------"
+ -@ write sys$output " "$*" "
+ -@ write sys$output "-----------------------------------------------"
+ -@ !run the test
+ -@ create/term/wait/nodetach mcr $(VIMPROG) $(GUI_OPTION) -u vms.vim --noplugin -s dotest.in $*.in
+ -@ !analyse the result
+ -@ directory /size/date test.out
+ -@ if "''F$SEARCH("test.out.*")'" .NES. "" then rename/nolog test.out $*.out
+ -@ if "''F$SEARCH("$*.out.*")'" .NES. "" then differences /par $*.out $*.ok;
+ -@ !clean up after the test
+ -@ 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_GUI) $(SCRIPT_UNIX) $(SCRIPT_WIN) $(SCRIPT_SPELL) $(SCRIPT_ODS5) $(SCRIPT_GZIP) \
+ $(SCRIPT_GDIFF) $(SCRIPT_MZSCH) $(SCRIPT_LUA) $(SCRIPT_PYTHON) nolog
+ -@ write sys$output " "
+ -@ write sys$output "-----------------------------------------------"
+ -@ write sys$output " All done"
+ -@ write sys$output "-----------------------------------------------"
+ -@ deassign sys$output
+ -@ delete/noconfirm/nolog x*.*.*
+ -@ type test.log
+
+nolog :
+ -@ define sys$output test.log
+ -@ write sys$output "-----------------------------------------------"
+ -@ write sys$output " Standard VIM test cases"
+ -@ write sys$output "-----------------------------------------------"
+ -@ write sys$output " OpenVMS version: ''F$GETSYI("VERSION")'"
+ -@ write sys$output " Vim version:"
+ -@ mcr $(VIMPROG) --version
+ -@ write sys$output " Test date:"
+ -@ show time
+ -@ write sys$output "-----------------------------------------------"
+ -@ write sys$output " Test results:"
+ -@ 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 " WANT_WIN = ""$(WANT_WIN)"" "
+ -@ write sys$output " WANT_SPELL = ""$(WANT_SPELL)"" "
+ -@ write sys$output " WANT_MZSCH = ""$(WANT_MZSCH)"" "
+ -@ write sys$output " HAVE_ODS5 = ""$(HAVE_ODS5)"" "
+ -@ 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
+
+clean :
+ -@ if "''F$SEARCH("*.out")'" .NES. "" then delete/noconfirm/nolog *.out.*
+ -@ if "''F$SEARCH("test.log")'" .NES. "" then delete/noconfirm/nolog test.log.*
+ -@ if "''F$SEARCH("test.ok")'" .NES. "" then delete/noconfirm/nolog test.ok.*
+ -@ if "''F$SEARCH("Xdotest.*")'" .NES. "" then delete/noconfirm/nolog Xdotest.*.*
+ -@ if "''F$SEARCH("Xtest*.*")'" .NES. "" then delete/noconfirm/nolog Xtest*.*.*
+ -@ if "''F$SEARCH("XX*.*")'" .NES. "" then delete/noconfirm/nolog XX*.*.*
+ -@ if "''F$SEARCH("_un_*.*")'" .NES. "" then delete/noconfirm/nolog _un_*.*.*
+ -@ if "''F$SEARCH("*.*_sw*")'" .NES. "" then delete/noconfirm/nolog *.*_sw*.*
+ -@ if "''F$SEARCH("*.failed")'" .NES. "" then delete/noconfirm/nolog *.failed.*
+ -@ if "''F$SEARCH("*.rej")'" .NES. "" then delete/noconfirm/nolog *.rej.*
+ -@ if "''F$SEARCH("tiny.vim")'" .NES. "" then delete/noconfirm/nolog tiny.vim.*
+ -@ if "''F$SEARCH("small.vim")'" .NES. "" then delete/noconfirm/nolog small.vim.*
+ -@ if "''F$SEARCH("mbyte.vim")'" .NES. "" then delete/noconfirm/nolog mbyte.vim.*
+ -@ if "''F$SEARCH("mzscheme.vim")'" .NES. "" then delete/noconfirm/nolog mzscheme.vim.*
+ -@ if "''F$SEARCH("viminfo.*")'" .NES. "" then delete/noconfirm/nolog viminfo.*.*
+
diff --git a/src/testdir/Makefile b/src/testdir/Makefile
new file mode 100644
index 0000000..c3ba8ab
--- /dev/null
+++ b/src/testdir/Makefile
@@ -0,0 +1,173 @@
+#
+# Makefile to run all tests for Vim
+#
+
+# Use console or GUI.
+VIMPROG = ../vim
+XXDPROG = ../xxd/xxd
+# VIMPROG = ../gvim
+
+SCRIPTSOURCE = ../../runtime
+
+# Comment out this line to see the verbose output of tests.
+#
+# Catches SwapExists to avoid hanging at the ATTENTION prompt.
+REDIR_TEST_TO_NULL = --cmd 'au SwapExists * let v:swapchoice = "e"' > /dev/null
+
+# Uncomment this line to use valgrind for memory leaks and extra warnings.
+# The output goes into a file "valgrind.testN"
+# Vim should be compiled with EXITFREE to avoid false warnings.
+# This will make testing about 10 times as slow.
+# VALGRIND = valgrind --tool=memcheck --leak-check=yes --num-callers=25 --log-file=valgrind.$*
+
+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.
+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 = bench_re_freeze.out
+
+.SUFFIXES: .in .out .res .vim
+
+nongui: nolog $(SCRIPTS_FIRST) $(SCRIPTS) newtests report
+
+gui: nolog $(SCRIPTS_FIRST) $(SCRIPTS) $(SCRIPTS_GUI) newtests report
+
+benchmark: $(SCRIPTS_BENCH)
+
+report:
+ @echo
+ @echo 'Test results:'
+ @/bin/sh -c "if test -f test.log; \
+ then cat test.log; echo TEST FAILURE; exit 1; \
+ else echo ALL DONE; \
+ fi"
+
+$(SCRIPTS_FIRST) $(SCRIPTS) $(SCRIPTS_GUI) $(NEW_TESTS_RES): $(VIMPROG)
+
+# Must run test1 first to create small.vim.
+$(SCRIPTS) $(SCRIPTS_GUI) $(NEW_TESTS_RES): $(SCRIPTS_FIRST)
+
+
+# Execute an individual new style test, e.g.:
+# make test_largefile
+$(NEW_TESTS):
+ rm -f $@.res test.log messages
+ $(MAKE) -f Makefile $@.res
+ @if test -f test.log; then \
+ cat test.log; \
+ fi
+ cat messages
+
+RM_ON_RUN = test.out X* viminfo
+RM_ON_START = tiny.vim small.vim mbyte.vim mzscheme.vim test.ok benchmark.out
+RUN_VIM = VIMRUNTIME=$(SCRIPTSOURCE); export VIMRUNTIME; $(VALGRIND) $(VIMPROG) -f $(GUI_FLAG) -u unix.vim $(NO_INITS) -s dotest.in
+
+clean:
+ -rm -rf *.out *.failed *.res *.rej *.orig opt_test.vim test.log messages $(RM_ON_RUN) $(RM_ON_START) valgrind.*
+
+test1.out: test1.in
+ -rm -rf $*.failed $(RM_ON_RUN) $(RM_ON_START) wrongtermsize
+ $(RUN_VIM) $*.in $(REDIR_TEST_TO_NULL)
+ @/bin/sh -c "if test -f wrongtermsize; \
+ then echo; \
+ echo test1 FAILED - terminal size must be 80x24 or larger; \
+ echo; exit 1; \
+ elif diff test.out $*.ok; \
+ then mv -f test.out $*.out; \
+ else echo; \
+ echo test1 FAILED - Something basic is wrong; \
+ 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
+
+bench_re_freeze.out: bench_re_freeze.vim
+ -rm -rf benchmark.out $(RM_ON_RUN)
+ # 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)
+ @/bin/sh -c "if test -f benchmark.out; then cat benchmark.out; fi"
+
+nolog:
+ -rm -f test.log messages
+
+
+# New style of tests uses Vim script with assert calls. These are easier
+# to write and a lot easier to read and debug.
+# Limitation: Only works with the +eval feature.
+RUN_VIMTEST = VIMRUNTIME=$(SCRIPTSOURCE); export VIMRUNTIME; $(VALGRIND) $(VIMPROG) -f $(GUI_FLAG) -u unix.vim
+
+newtests: newtestssilent
+ @/bin/sh -c "if test -f messages && grep -q 'SKIPPED\|FAILED' messages; then cat messages; fi"
+
+newtestssilent: $(NEW_TESTS_RES)
+
+
+.vim.res: writevimcmd
+ @echo "$(VIMPROG)" > vimcmd
+ @echo "$(RUN_VIMTEST)" >> vimcmd
+ $(RUN_VIMTEST) $(NO_INITS) -S runtest.vim $*.vim $(REDIR_TEST_TO_NULL)
+ @rm vimcmd
+
+test_gui.res: test_gui.vim
+ @echo "$(VIMPROG)" > vimcmd
+ @echo "$(RUN_GVIMTEST)" >> vimcmd
+ $(RUN_VIMTEST) -u NONE $(NO_INITS) -S runtest.vim $<
+ @rm vimcmd
+
+test_gui_init.res: test_gui_init.vim
+ @echo "$(VIMPROG)" > vimcmd
+ @echo "$(RUN_GVIMTEST_WITH_GVIMRC)" >> vimcmd
+ $(RUN_VIMTEST) -u gui_preinit.vim -U gui_init.vim $(NO_PLUGINS) -S runtest.vim $<
+ @rm vimcmd
+
+opt_test.vim: ../option.c gen_opt_test.vim
+ $(VIMPROG) -u NONE -S gen_opt_test.vim --noplugin --not-a-term ../option.c
+
+test_xxd.res:
+ XXD=$(XXDPROG); export XXD; $(RUN_VIMTEST) $(NO_INITS) -S runtest.vim test_xxd.vim
diff --git a/src/testdir/README.txt b/src/testdir/README.txt
new file mode 100644
index 0000000..f4486e3
--- /dev/null
+++ b/src/testdir/README.txt
@@ -0,0 +1,73 @@
+This directory contains tests for various Vim features.
+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_<subject>.vim file.
+2) Add test_<subject>.res to NEW_TESTS_RES in Make_all.mak in alphabetical
+ order.
+3) Also add an entry "test_<subject>" to NEW_TESTS in Make_all.mak.
+4) Use make test_<subject> to run a single test.
+
+At 2), instead of running the test separately, it can be included in
+"test_alot". Do this for quick tests without side effects. The test runs a
+bit faster, because Vim doesn't have to be started, one Vim instance runs many
+tests.
+
+
+What you can use (see test_assert.vim for an example):
+
+- Call assert_equal(), assert_true(), assert_false(), etc.
+
+- Use assert_fails() to check for expected errors.
+
+- Use try/catch to avoid an exception aborts the test.
+
+- Use alloc_fail() to have memory allocation fail. This makes it possible to
+ check memory allocation failures are handled gracefully. You need to change
+
+- the source code to add an ID to the allocation. Update LAST_ID_USED above
+ alloc_id() to the highest ID used.
+
+- Use test_override() to make Vim behave differently, e.g. if char_avail()
+ must return FALSE for a while. E.g. to trigger the CursorMovedI autocommand
+ event.
+
+- See test_cursor_func.vim for an example.
+
+- If the bug that is being tested isn't fixed yet, you can throw an exception
+ with "Skipped" so that it's clear this still needs work. E.g.: throw
+ "Skipped: Bug with <c-e> and popupmenu not fixed yet"
+
+- See the start of runtest.vim for more help.
+
+
+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_<subject>.in and test_<subject>.ok files.
+2) Add test_<subject>.out to SCRIPTS_ALL in Make_all.mak in alphabetical order.
+3) Use make test_<subject>.out to run a single test in src/testdir/.
+ Use make test_<subject> 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/amiga.vim b/src/testdir/amiga.vim
new file mode 100644
index 0000000..79956d7
--- /dev/null
+++ b/src/testdir/amiga.vim
@@ -0,0 +1,6 @@
+" Settings for test script execution
+set shell=csh
+map! /tmp t:
+cmap !rm !Delete all
+
+source setup.vim
diff --git a/src/testdir/bench_re_freeze.in b/src/testdir/bench_re_freeze.in
new file mode 100644
index 0000000..7b1bfa3
--- /dev/null
+++ b/src/testdir/bench_re_freeze.in
@@ -0,0 +1,13 @@
+Test for Benchmarking RE engine
+
+STARTTEST
+:so small.vim
+:if !has("reltime") | qa! | endif
+:set nocp cpo&vim
+:so bench_re_freeze.vim
+:call Measure('samples/re.freeze.txt', '\s\+\%#\@<!$', '+5')
+:/^" Benchmark/,$w! benchmark.out
+:qa!
+ENDTEST
+
+" Benchmark_results:
diff --git a/src/testdir/bench_re_freeze.vim b/src/testdir/bench_re_freeze.vim
new file mode 100644
index 0000000..ee84438
--- /dev/null
+++ b/src/testdir/bench_re_freeze.vim
@@ -0,0 +1,13 @@
+"Test for benchmarking the RE engine
+
+so small.vim
+if !has("reltime") | finish | endif
+func! Measure(file, pattern, arg)
+ for re in range(3)
+ let sstart=reltime()
+ let cmd=printf("../vim -u NONE -N --cmd ':set re=%d'".
+ \ " -c 'call search(\"%s\", \"\", \"\", 10000)' -c ':q!' %s", re, escape(a:pattern, '\\'), empty(a:arg) ? '' : a:arg)
+ call system(cmd. ' '. a:file)
+ $put =printf('file: %s, re: %d, time: %s', a:file, re, reltimestr(reltime(sstart)))
+ endfor
+endfunc
diff --git a/src/testdir/color_ramp.vim b/src/testdir/color_ramp.vim
new file mode 100644
index 0000000..0219f3f
--- /dev/null
+++ b/src/testdir/color_ramp.vim
@@ -0,0 +1,41 @@
+" Script to generate a file that shows al 256 xterm colors
+
+new
+call setline(1, 'ANSI')
+
+" ANSI colors
+let s = ''
+for nr in range(0, 7)
+ let s .= "\033[4" . nr . "m "
+endfor
+for nr in range(8, 15)
+ let s .= "\033[10" . (nr - 8) . "m "
+endfor
+" Add | in original color pair to see white background.
+let s .= "\033[m|"
+call setline(2, s)
+
+" 6 x 6 x 6 color cube
+call setline(3, 'color cube')
+for high in range(0, 5)
+ let s = ''
+ for low in range(0, 35)
+ let nr = low + high * 36
+ let s .= "\033[48;5;" . (nr + 16) . "m "
+ endfor
+ let s .= "\033[m|"
+ call setline(high + 4, s)
+endfor
+
+" 24 shades of grey
+call setline(10, 'grey ramp')
+let s = ''
+for nr in range(0, 23)
+ let s .= "\033[48;5;" . (nr + 232) . "m "
+endfor
+let s .= "\033[m|"
+call setline(11, s)
+
+set binary
+write! <sfile>:h/color_ramp.txt
+quit
diff --git a/src/testdir/dos.vim b/src/testdir/dos.vim
new file mode 100644
index 0000000..3ea6ab2
--- /dev/null
+++ b/src/testdir/dos.vim
@@ -0,0 +1,9 @@
+" Settings for test script execution
+" Always use "COMMAND.COM", don't use the value of "$SHELL".
+set shell=c:\COMMAND.COM shellquote= shellxquote= shellcmdflag=/c shellredir=>
+" This is used only when the +eval feature is available.
+if executable("cmd.exe")
+ set shell=cmd.exe
+endif
+
+source setup.vim
diff --git a/src/testdir/dotest.in b/src/testdir/dotest.in
new file mode 100644
index 0000000..b2a0e1a
--- /dev/null
+++ b/src/testdir/dotest.in
@@ -0,0 +1,3 @@
+:set cp
+:map dotest /^STARTTEST j:set ff=unix cpo-=A :.,/ENDTEST/-1w! Xdotest :set ff& cpo+=A nj0:so! Xdotest dotest
+dotest
diff --git a/src/testdir/dumps/Test_conceal_cul_01.dump b/src/testdir/dumps/Test_conceal_cul_01.dump
new file mode 100644
index 0000000..6d698d1
--- /dev/null
+++ b/src/testdir/dumps/Test_conceal_cul_01.dump
@@ -0,0 +1,20 @@
+|o+0&#ffffff0|n|e| @71
+|t|w|o| @71
+>t+8&&|h|r|e@1| @69
+|f+0&&|o|u|r| @70
+|f|i|v|e| @70
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|[+3#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|3|,|1| @11|A|l@1
+| +0&&@74
+|t+8&&|h|i|s| |i|s| |a| |t|e|s|t| @60
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|[+1#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|2|,|1|4| @10|A|l@1
+| +0&&@74
diff --git a/src/testdir/dumps/Test_conceal_cul_02.dump b/src/testdir/dumps/Test_conceal_cul_02.dump
new file mode 100644
index 0000000..46b296c
--- /dev/null
+++ b/src/testdir/dumps/Test_conceal_cul_02.dump
@@ -0,0 +1,20 @@
+|o+0&#ffffff0|n|e| @71
+|t|w|o| @71
+|t+8&&|h|r|e@1| @69
+|f+0&&|o|u|r| @70
+|f|i|v|e| @70
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|[+1#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|3|,|1| @11|A|l@1
+| +0&&@74
+|t+8&&|h|i|s| |i|s| |a| |t|e|s>t| @60
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|[+3#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|2|,|1|4| @10|A|l@1
+|:+0&&|w|i|n|c|m|d| |w| @65
diff --git a/src/testdir/dumps/Test_conceal_cul_03.dump b/src/testdir/dumps/Test_conceal_cul_03.dump
new file mode 100644
index 0000000..275f35c
--- /dev/null
+++ b/src/testdir/dumps/Test_conceal_cul_03.dump
@@ -0,0 +1,20 @@
+|o+0&#ffffff0|n|e| @71
+|t|w|o| @71
+|t+8&&|h|r|e@1| @69
+|f+0&&|o|u|r| @70
+|f|i|v|e| @70
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|[+1#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|3|,|1| @11|A|l@1
+> +8&&@74
+|t+0&&|h|i|s| |i|s| |a| |t|e|s|t| @60
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|[+3#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|1|,|0|-|1| @9|A|l@1
+|:+0&&|w|i|n|c|m|d| |w| @65
diff --git a/src/testdir/dumps/Test_conceal_two_windows_01.dump b/src/testdir/dumps/Test_conceal_two_windows_01.dump
new file mode 100644
index 0000000..0a70677
--- /dev/null
+++ b/src/testdir/dumps/Test_conceal_two_windows_01.dump
@@ -0,0 +1,20 @@
+|o+0&#ffffff0|n|e| |o|n|e| |o|n|e| |o|n|e| |o|n|e| @55
+|t|w|o| @1>h|e|r|e| @65
+|t|h|r|e@1| @1|t|h|r|e@1| @62
+|S|e|c|o|n|d| |w|i|n|d|o|w| @61
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|[+3#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|2|,|1|4| @10|A|l@1
+|o+0&&|n|e| |o|n|e| |o|n|e| |o|n|e| |o|n|e| @55
+|t|w|o| @1|h|e|r|e| @65
+|t|h|r|e@1| @1|t|h|r|e@1| @62
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|[+1#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|2|,|1|4| @10|A|l@1
+|/+0&&|h|e|r|e| @69
diff --git a/src/testdir/dumps/Test_conceal_two_windows_02.dump b/src/testdir/dumps/Test_conceal_two_windows_02.dump
new file mode 100644
index 0000000..367149f
--- /dev/null
+++ b/src/testdir/dumps/Test_conceal_two_windows_02.dump
@@ -0,0 +1,20 @@
+|o+0&#ffffff0|n|e| |o|n|e| |o|n|e| |o>n|e| |o|n|e| @55
+|t|w|o| @1|h|e|r|e| @65
+|t|h|r|e@1| @1|t|h|r|e@1| @62
+|S|e|c|o|n|d| |w|i|n|d|o|w| @61
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|[+3#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|1|,|1|4| @10|A|l@1
+|o+0&&|n|e| |o|n|e| |o|n|e| |o|n|e| |o|n|e| @55
+|t|w|o| @1|h|e|r|e| @65
+|t|h|r|e@1| @1|t|h|r|e@1| @62
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|[+1#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|2|,|1|4| @10|A|l@1
+|/+0&&|h|e|r|e| @69
diff --git a/src/testdir/dumps/Test_conceal_two_windows_03.dump b/src/testdir/dumps/Test_conceal_two_windows_03.dump
new file mode 100644
index 0000000..27242eb
--- /dev/null
+++ b/src/testdir/dumps/Test_conceal_two_windows_03.dump
@@ -0,0 +1,20 @@
+|o+0&#ffffff0|n|e| |o|n|e| |o|n|e| |o|n|e| |o|n|e| @55
+|t|w|o| |||h|i|d@1|e|n||| >h|e|r|e| @57
+|t|h|r|e@1| @1|t|h|r|e@1| @62
+|S|e|c|o|n|d| |w|i|n|d|o|w| @61
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|[+3#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|2|,|1|4| @10|A|l@1
+|o+0&&|n|e| |o|n|e| |o|n|e| |o|n|e| |o|n|e| @55
+|t|w|o| @1|h|e|r|e| @65
+|t|h|r|e@1| @1|t|h|r|e@1| @62
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|[+1#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|2|,|1|4| @10|A|l@1
+|:+0&&|s|e|t| |c|o|n|c|e|a|l|c|u|r|s|o|r|=| @55
diff --git a/src/testdir/dumps/Test_conceal_two_windows_04.dump b/src/testdir/dumps/Test_conceal_two_windows_04.dump
new file mode 100644
index 0000000..ff52320
--- /dev/null
+++ b/src/testdir/dumps/Test_conceal_two_windows_04.dump
@@ -0,0 +1,20 @@
+|o+0&#ffffff0|n|e| |o|n|e| |o|n|e| |o|n|e| |o|n|e| @55
+|t|w|o| @1|h|e|r|e| @65
+|t|h|r|e@1| |||h|i|d@1|e|n>|| |t|h|r|e@1| @54
+|S|e|c|o|n|d| |w|i|n|d|o|w| @61
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|[+3#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|3|,|1|4| @10|A|l@1
+|o+0&&|n|e| |o|n|e| |o|n|e| |o|n|e| |o|n|e| @55
+|t|w|o| @1|h|e|r|e| @65
+|t|h|r|e@1| @1|t|h|r|e@1| @62
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|[+1#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|2|,|1|4| @10|A|l@1
+|:+0&&|s|e|t| |c|o|n|c|e|a|l|c|u|r|s|o|r|=| @55
diff --git a/src/testdir/dumps/Test_conceal_two_windows_05.dump b/src/testdir/dumps/Test_conceal_two_windows_05.dump
new file mode 100644
index 0000000..68904d0
--- /dev/null
+++ b/src/testdir/dumps/Test_conceal_two_windows_05.dump
@@ -0,0 +1,20 @@
+|o+0&#ffffff0|n|e| |o|n|e| |o|n|e| |o|n|e| |o|n|e| @55
+|t|w|o| @1|h|e|r|e| @65
+|t|h|r|e@1| @1|t|h|r|e@1| @62
+|S|e|c|o|n|d| |w|i|n|d|o|w| @61
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|[+1#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|3|,|1|4| @10|A|l@1
+|o+0&&|n|e| |o|n|e| |o|n|e| |o|n|e| |o|n|e| @55
+|t|w|o| |||h|i|d@1|e|n||| >h|e|r|e| @57
+|t|h|r|e@1| @1|t|h|r|e@1| @62
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|[+3#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|2|,|1|4| @10|A|l@1
+|:+0&&|s|e|t| |c|o|n|c|e|a|l|c|u|r|s|o|r|=| @55
diff --git a/src/testdir/dumps/Test_conceal_two_windows_06c.dump b/src/testdir/dumps/Test_conceal_two_windows_06c.dump
new file mode 100644
index 0000000..b3869f9
--- /dev/null
+++ b/src/testdir/dumps/Test_conceal_two_windows_06c.dump
@@ -0,0 +1,20 @@
+|o+0&#ffffff0|n|e| |o|n|e| |o|n|e| |o|n|e| |o|n|e| @55
+|t|w|o| @1|h|e|r|e| @65
+|t|h|r|e@1| @1|t|h|r|e@1| @62
+|S|e|c|o|n|d| |w|i|n|d|o|w| @61
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|[+1#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|3|,|1|4| @10|A|l@1
+|o+0&&|n|e| |o|n|e| |o|n|e| |o|n|e| |o|n|e| @55
+|t|w|o| |||h|i|d@1|e|n||| |h|e+1&&|r+0&&|e| @57
+|t|h|r|e@1| @1|t|h|r|e@1| @62
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|[+3#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|2|,|1|5| @10|A|l@1
+|/+0&&|e> @72
diff --git a/src/testdir/dumps/Test_conceal_two_windows_06i.dump b/src/testdir/dumps/Test_conceal_two_windows_06i.dump
new file mode 100644
index 0000000..c2325b9
--- /dev/null
+++ b/src/testdir/dumps/Test_conceal_two_windows_06i.dump
@@ -0,0 +1,20 @@
+|o+0&#ffffff0|n|e| |o|n|e| |o|n|e| |o|n|e| |o|n|e| @55
+|t|w|o| @1|h|e|r|e| @65
+|t|h|r|e@1| @1|t|h|r|e@1| @62
+|S|e|c|o|n|d| |w|i|n|d|o|w| @61
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|[+1#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|3|,|1|4| @10|A|l@1
+|o+0&&|n|e| |o|n|e| |o|n|e| |o|n|e| |o|n|e| @55
+|t|w|o| |||h|i|d@1|e|n||| |h>e|r|e| @57
+|t|h|r|e@1| @1|t|h|r|e@1| @62
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|[+3#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|2|,|1|5| @10|A|l@1
+|-+2&&@1| |I|N|S|E|R|T| |-@1| +0&&@62
diff --git a/src/testdir/dumps/Test_conceal_two_windows_06n.dump b/src/testdir/dumps/Test_conceal_two_windows_06n.dump
new file mode 100644
index 0000000..a147249
--- /dev/null
+++ b/src/testdir/dumps/Test_conceal_two_windows_06n.dump
@@ -0,0 +1,20 @@
+|o+0&#ffffff0|n|e| |o|n|e| |o|n|e| |o|n|e| |o|n|e| @55
+|t|w|o| @1|h|e|r|e| @65
+|t|h|r|e@1| @1|t|h|r|e@1| @62
+|S|e|c|o|n|d| |w|i|n|d|o|w| @61
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|[+1#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|3|,|1|4| @10|A|l@1
+|o+0&&|n|e| |o|n|e| |o|n|e| |o|n|e| |o|n|e| @55
+|t|w|o| @1>h|e|r|e| @65
+|t|h|r|e@1| @1|t|h|r|e@1| @62
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|[+3#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|2|,|1|4| @10|A|l@1
+|:+0&&|s|e|t| |c|o|n|c|e|a|l|c|u|r|s|o|r|=|n| @54
diff --git a/src/testdir/dumps/Test_conceal_two_windows_06v.dump b/src/testdir/dumps/Test_conceal_two_windows_06v.dump
new file mode 100644
index 0000000..7456625
--- /dev/null
+++ b/src/testdir/dumps/Test_conceal_two_windows_06v.dump
@@ -0,0 +1,20 @@
+|o+0&#ffffff0|n|e| |o|n|e| |o|n|e| |o|n|e| |o|n|e| @55
+|t|w|o| @1|h|e|r|e| @65
+|t|h|r|e@1| @1|t|h|r|e@1| @62
+|S|e|c|o|n|d| |w|i|n|d|o|w| @61
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|[+1#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|3|,|1|4| @10|A|l@1
+|o+0&&|n|e| |o|n|e| |o|n|e| |o|n|e| |o|n|e| @55
+|t|w|o| |||h|i|d@1|e|n||| >h|e|r|e| @57
+|t|h|r|e@1| @1|t|h|r|e@1| @62
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|[+3#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|2|,|1|4| @10|A|l@1
+|-+2&&@1| |V|I|S|U|A|L| |-@1| +0&&@51|1| @9
diff --git a/src/testdir/dumps/Test_conceal_two_windows_07c.dump b/src/testdir/dumps/Test_conceal_two_windows_07c.dump
new file mode 100644
index 0000000..b3869f9
--- /dev/null
+++ b/src/testdir/dumps/Test_conceal_two_windows_07c.dump
@@ -0,0 +1,20 @@
+|o+0&#ffffff0|n|e| |o|n|e| |o|n|e| |o|n|e| |o|n|e| @55
+|t|w|o| @1|h|e|r|e| @65
+|t|h|r|e@1| @1|t|h|r|e@1| @62
+|S|e|c|o|n|d| |w|i|n|d|o|w| @61
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|[+1#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|3|,|1|4| @10|A|l@1
+|o+0&&|n|e| |o|n|e| |o|n|e| |o|n|e| |o|n|e| @55
+|t|w|o| |||h|i|d@1|e|n||| |h|e+1&&|r+0&&|e| @57
+|t|h|r|e@1| @1|t|h|r|e@1| @62
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|[+3#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|2|,|1|5| @10|A|l@1
+|/+0&&|e> @72
diff --git a/src/testdir/dumps/Test_conceal_two_windows_07i.dump b/src/testdir/dumps/Test_conceal_two_windows_07i.dump
new file mode 100644
index 0000000..f1cd232
--- /dev/null
+++ b/src/testdir/dumps/Test_conceal_two_windows_07i.dump
@@ -0,0 +1,20 @@
+|o+0&#ffffff0|n|e| |o|n|e| |o|n|e| |o|n|e| |o|n|e| @55
+|t|w|o| @1|h|e|r|e| @65
+|t|h|r|e@1| @1|t|h|r|e@1| @62
+|S|e|c|o|n|d| |w|i|n|d|o|w| @61
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|[+1#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|3|,|1|4| @10|A|l@1
+|o+0&&|n|e| |o|n|e| |o|n|e| |o|n|e| |o|n|e| @55
+|t|w|o| @1|h>e|r|e| @65
+|t|h|r|e@1| @1|t|h|r|e@1| @62
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|[+3#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|2|,|1|5| @10|A|l@1
+|-+2&&@1| |I|N|S|E|R|T| |-@1| +0&&@62
diff --git a/src/testdir/dumps/Test_conceal_two_windows_07n.dump b/src/testdir/dumps/Test_conceal_two_windows_07n.dump
new file mode 100644
index 0000000..9ed71a6
--- /dev/null
+++ b/src/testdir/dumps/Test_conceal_two_windows_07n.dump
@@ -0,0 +1,20 @@
+|o+0&#ffffff0|n|e| |o|n|e| |o|n|e| |o|n|e| |o|n|e| @55
+|t|w|o| @1|h|e|r|e| @65
+|t|h|r|e@1| @1|t|h|r|e@1| @62
+|S|e|c|o|n|d| |w|i|n|d|o|w| @61
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|[+1#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|3|,|1|4| @10|A|l@1
+|o+0&&|n|e| |o|n|e| |o|n|e| |o|n|e| |o|n|e| @55
+|t|w|o| |||h|i|d@1|e|n||| >h|e|r|e| @57
+|t|h|r|e@1| @1|t|h|r|e@1| @62
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|[+3#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|2|,|1|4| @10|A|l@1
+|:+0&&|s|e|t| |c|o|n|c|e|a|l|c|u|r|s|o|r|=|i| @54
diff --git a/src/testdir/dumps/Test_conceal_two_windows_07v.dump b/src/testdir/dumps/Test_conceal_two_windows_07v.dump
new file mode 100644
index 0000000..7456625
--- /dev/null
+++ b/src/testdir/dumps/Test_conceal_two_windows_07v.dump
@@ -0,0 +1,20 @@
+|o+0&#ffffff0|n|e| |o|n|e| |o|n|e| |o|n|e| |o|n|e| @55
+|t|w|o| @1|h|e|r|e| @65
+|t|h|r|e@1| @1|t|h|r|e@1| @62
+|S|e|c|o|n|d| |w|i|n|d|o|w| @61
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|[+1#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|3|,|1|4| @10|A|l@1
+|o+0&&|n|e| |o|n|e| |o|n|e| |o|n|e| |o|n|e| @55
+|t|w|o| |||h|i|d@1|e|n||| >h|e|r|e| @57
+|t|h|r|e@1| @1|t|h|r|e@1| @62
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|[+3#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|2|,|1|4| @10|A|l@1
+|-+2&&@1| |V|I|S|U|A|L| |-@1| +0&&@51|1| @9
diff --git a/src/testdir/dumps/Test_conceal_two_windows_08c.dump b/src/testdir/dumps/Test_conceal_two_windows_08c.dump
new file mode 100644
index 0000000..2d12a9c
--- /dev/null
+++ b/src/testdir/dumps/Test_conceal_two_windows_08c.dump
@@ -0,0 +1,20 @@
+|o+0&#ffffff0|n|e| |o|n|e| |o|n|e| |o|n|e| |o|n|e| @55
+|t|w|o| @1|h|e|r|e| @65
+|t|h|r|e@1| @1|t|h|r|e@1| @62
+|S|e|c|o|n|d| |w|i|n|d|o|w| @61
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|[+1#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|3|,|1|4| @10|A|l@1
+|o+0&&|n|e| |o|n|e| |o|n|e| |o|n|e| |o|n|e| @55
+|t|w|o| @1|h|e+1&&|r+0&&|e| @65
+|t|h|r|e@1| @1|t|h|r|e@1| @62
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|[+3#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|2|,|1|5| @10|A|l@1
+|/+0&&|e> @72
diff --git a/src/testdir/dumps/Test_conceal_two_windows_08i.dump b/src/testdir/dumps/Test_conceal_two_windows_08i.dump
new file mode 100644
index 0000000..c2325b9
--- /dev/null
+++ b/src/testdir/dumps/Test_conceal_two_windows_08i.dump
@@ -0,0 +1,20 @@
+|o+0&#ffffff0|n|e| |o|n|e| |o|n|e| |o|n|e| |o|n|e| @55
+|t|w|o| @1|h|e|r|e| @65
+|t|h|r|e@1| @1|t|h|r|e@1| @62
+|S|e|c|o|n|d| |w|i|n|d|o|w| @61
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|[+1#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|3|,|1|4| @10|A|l@1
+|o+0&&|n|e| |o|n|e| |o|n|e| |o|n|e| |o|n|e| @55
+|t|w|o| |||h|i|d@1|e|n||| |h>e|r|e| @57
+|t|h|r|e@1| @1|t|h|r|e@1| @62
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|[+3#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|2|,|1|5| @10|A|l@1
+|-+2&&@1| |I|N|S|E|R|T| |-@1| +0&&@62
diff --git a/src/testdir/dumps/Test_conceal_two_windows_08n.dump b/src/testdir/dumps/Test_conceal_two_windows_08n.dump
new file mode 100644
index 0000000..13e8141
--- /dev/null
+++ b/src/testdir/dumps/Test_conceal_two_windows_08n.dump
@@ -0,0 +1,20 @@
+|o+0&#ffffff0|n|e| |o|n|e| |o|n|e| |o|n|e| |o|n|e| @55
+|t|w|o| @1|h|e|r|e| @65
+|t|h|r|e@1| @1|t|h|r|e@1| @62
+|S|e|c|o|n|d| |w|i|n|d|o|w| @61
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|[+1#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|3|,|1|4| @10|A|l@1
+|o+0&&|n|e| |o|n|e| |o|n|e| |o|n|e| |o|n|e| @55
+|t|w|o| |||h|i|d@1|e|n||| >h|e|r|e| @57
+|t|h|r|e@1| @1|t|h|r|e@1| @62
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|[+3#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|2|,|1|4| @10|A|l@1
+|:+0&&|s|e|t| |c|o|n|c|e|a|l|c|u|r|s|o|r|=|c| @54
diff --git a/src/testdir/dumps/Test_conceal_two_windows_08v.dump b/src/testdir/dumps/Test_conceal_two_windows_08v.dump
new file mode 100644
index 0000000..7456625
--- /dev/null
+++ b/src/testdir/dumps/Test_conceal_two_windows_08v.dump
@@ -0,0 +1,20 @@
+|o+0&#ffffff0|n|e| |o|n|e| |o|n|e| |o|n|e| |o|n|e| @55
+|t|w|o| @1|h|e|r|e| @65
+|t|h|r|e@1| @1|t|h|r|e@1| @62
+|S|e|c|o|n|d| |w|i|n|d|o|w| @61
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|[+1#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|3|,|1|4| @10|A|l@1
+|o+0&&|n|e| |o|n|e| |o|n|e| |o|n|e| |o|n|e| @55
+|t|w|o| |||h|i|d@1|e|n||| >h|e|r|e| @57
+|t|h|r|e@1| @1|t|h|r|e@1| @62
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|[+3#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|2|,|1|4| @10|A|l@1
+|-+2&&@1| |V|I|S|U|A|L| |-@1| +0&&@51|1| @9
diff --git a/src/testdir/dumps/Test_conceal_two_windows_09c.dump b/src/testdir/dumps/Test_conceal_two_windows_09c.dump
new file mode 100644
index 0000000..b3869f9
--- /dev/null
+++ b/src/testdir/dumps/Test_conceal_two_windows_09c.dump
@@ -0,0 +1,20 @@
+|o+0&#ffffff0|n|e| |o|n|e| |o|n|e| |o|n|e| |o|n|e| @55
+|t|w|o| @1|h|e|r|e| @65
+|t|h|r|e@1| @1|t|h|r|e@1| @62
+|S|e|c|o|n|d| |w|i|n|d|o|w| @61
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|[+1#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|3|,|1|4| @10|A|l@1
+|o+0&&|n|e| |o|n|e| |o|n|e| |o|n|e| |o|n|e| @55
+|t|w|o| |||h|i|d@1|e|n||| |h|e+1&&|r+0&&|e| @57
+|t|h|r|e@1| @1|t|h|r|e@1| @62
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|[+3#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|2|,|1|5| @10|A|l@1
+|/+0&&|e> @72
diff --git a/src/testdir/dumps/Test_conceal_two_windows_09i.dump b/src/testdir/dumps/Test_conceal_two_windows_09i.dump
new file mode 100644
index 0000000..c2325b9
--- /dev/null
+++ b/src/testdir/dumps/Test_conceal_two_windows_09i.dump
@@ -0,0 +1,20 @@
+|o+0&#ffffff0|n|e| |o|n|e| |o|n|e| |o|n|e| |o|n|e| @55
+|t|w|o| @1|h|e|r|e| @65
+|t|h|r|e@1| @1|t|h|r|e@1| @62
+|S|e|c|o|n|d| |w|i|n|d|o|w| @61
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|[+1#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|3|,|1|4| @10|A|l@1
+|o+0&&|n|e| |o|n|e| |o|n|e| |o|n|e| |o|n|e| @55
+|t|w|o| |||h|i|d@1|e|n||| |h>e|r|e| @57
+|t|h|r|e@1| @1|t|h|r|e@1| @62
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|[+3#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|2|,|1|5| @10|A|l@1
+|-+2&&@1| |I|N|S|E|R|T| |-@1| +0&&@62
diff --git a/src/testdir/dumps/Test_conceal_two_windows_09n.dump b/src/testdir/dumps/Test_conceal_two_windows_09n.dump
new file mode 100644
index 0000000..e00c814
--- /dev/null
+++ b/src/testdir/dumps/Test_conceal_two_windows_09n.dump
@@ -0,0 +1,20 @@
+|o+0&#ffffff0|n|e| |o|n|e| |o|n|e| |o|n|e| |o|n|e| @55
+|t|w|o| @1|h|e|r|e| @65
+|t|h|r|e@1| @1|t|h|r|e@1| @62
+|S|e|c|o|n|d| |w|i|n|d|o|w| @61
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|[+1#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|3|,|1|4| @10|A|l@1
+|o+0&&|n|e| |o|n|e| |o|n|e| |o|n|e| |o|n|e| @55
+|t|w|o| |||h|i|d@1|e|n||| >h|e|r|e| @57
+|t|h|r|e@1| @1|t|h|r|e@1| @62
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|[+3#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|2|,|1|4| @10|A|l@1
+|:+0&&|s|e|t| |c|o|n|c|e|a|l|c|u|r|s|o|r|=|v| @54
diff --git a/src/testdir/dumps/Test_conceal_two_windows_09v.dump b/src/testdir/dumps/Test_conceal_two_windows_09v.dump
new file mode 100644
index 0000000..8d6cb4b
--- /dev/null
+++ b/src/testdir/dumps/Test_conceal_two_windows_09v.dump
@@ -0,0 +1,20 @@
+|o+0&#ffffff0|n|e| |o|n|e| |o|n|e| |o|n|e| |o|n|e| @55
+|t|w|o| @1|h|e|r|e| @65
+|t|h|r|e@1| @1|t|h|r|e@1| @62
+|S|e|c|o|n|d| |w|i|n|d|o|w| @61
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|[+1#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|3|,|1|4| @10|A|l@1
+|o+0&&|n|e| |o|n|e| |o|n|e| |o|n|e| |o|n|e| @55
+|t|w|o| @1>h|e|r|e| @65
+|t|h|r|e@1| @1|t|h|r|e@1| @62
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|[+3#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|2|,|1|4| @10|A|l@1
+|-+2&&@1| |V|I|S|U|A|L| |-@1| +0&&@51|1| @9
diff --git a/src/testdir/dumps/Test_conceal_two_windows_10.dump b/src/testdir/dumps/Test_conceal_two_windows_10.dump
new file mode 100644
index 0000000..c2325b9
--- /dev/null
+++ b/src/testdir/dumps/Test_conceal_two_windows_10.dump
@@ -0,0 +1,20 @@
+|o+0&#ffffff0|n|e| |o|n|e| |o|n|e| |o|n|e| |o|n|e| @55
+|t|w|o| @1|h|e|r|e| @65
+|t|h|r|e@1| @1|t|h|r|e@1| @62
+|S|e|c|o|n|d| |w|i|n|d|o|w| @61
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|[+1#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|3|,|1|4| @10|A|l@1
+|o+0&&|n|e| |o|n|e| |o|n|e| |o|n|e| |o|n|e| @55
+|t|w|o| |||h|i|d@1|e|n||| |h>e|r|e| @57
+|t|h|r|e@1| @1|t|h|r|e@1| @62
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|[+3#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|2|,|1|5| @10|A|l@1
+|-+2&&@1| |I|N|S|E|R|T| |-@1| +0&&@62
diff --git a/src/testdir/dumps/Test_conceal_two_windows_11.dump b/src/testdir/dumps/Test_conceal_two_windows_11.dump
new file mode 100644
index 0000000..42a3fd5
--- /dev/null
+++ b/src/testdir/dumps/Test_conceal_two_windows_11.dump
@@ -0,0 +1,20 @@
+|o+0&#ffffff0|n|e| |o|n|e| |o|n|e| |o|n|e| |o|n|e| @55
+|t|w|o| @1|h|e|r|e| @65
+|t|h|r|e@1| @1|t|h|r|e@1| @62
+|S|e|c|o|n|d| |w|i|n|d|o|w| @61
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|[+1#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|3|,|1|4| @10|A|l@1
+|o+0&&|n|e| |o|n|e| |o|n|e| |o|n|e| |o|n|e| @55
+|t|w|o| @1|h|e|r|e| @65
+|t|h|r|e@1| |||h|i|d@1|e|n||> |t|h|r|e@1| @54
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|[+3#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|3|,|1|5| @10|A|l@1
+|-+2&&@1| |I|N|S|E|R|T| |-@1| +0&&@62
diff --git a/src/testdir/dumps/Test_conceal_two_windows_12.dump b/src/testdir/dumps/Test_conceal_two_windows_12.dump
new file mode 100644
index 0000000..63861a1
--- /dev/null
+++ b/src/testdir/dumps/Test_conceal_two_windows_12.dump
@@ -0,0 +1,20 @@
+|o+0&#ffffff0|n|e| |o|n|e| |o|n|e| |o|n|e| |o|n|e| @55
+|t|w|o| @1|h|e|r|e| @65
+|t|h|r|e@1| @1|t|h|r|e@1| @62
+|S|e|c|o|n|d| |w|i|n|d|o|w| @61
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|[+1#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|3|,|1|4| @10|A|l@1
+|o+0&&|n|e| |o|n|e| |o|n|e| |o|n|e| |o|n|e| @55
+|t|w|o| @1|h|e|r|e| @65
+|t|h|r|e@1| |||h|i|d@1|e|n>|| |t|h|r|e@1| @54
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|[+3#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|3|,|1|4| @10|A|l@1
+| +0&&@74
diff --git a/src/testdir/dumps/Test_conceal_two_windows_13.dump b/src/testdir/dumps/Test_conceal_two_windows_13.dump
new file mode 100644
index 0000000..2f93e31
--- /dev/null
+++ b/src/testdir/dumps/Test_conceal_two_windows_13.dump
@@ -0,0 +1,20 @@
+|o+0&#ffffff0|n|e| |o|n|e| |o|n|e| |o|n|e| |o|n|e| @55
+|t|w|o| @1|h|e|r|e| @65
+|t|h|r|e@1| @1|t|h|r|e@1| @62
+|S|e|c|o|n|d| |w|i|n|d|o|w| @61
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|[+1#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|3|,|1|4| @10|A|l@1
+|o+0&&|n|e| |o|n|e| |o|n|e| |o|n|e| |o|n|e| @55
+|t|w|o| @1|h|e|r|e| @65
+|t|h|r|e@1| @1|t|h|r|e@1| @62
+> @74
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|[+3#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|4|,|1| @11|A|l@1
+|-+2&&@1| |I|N|S|E|R|T| |-@1| +0&&@62
diff --git a/src/testdir/dumps/Test_cursorline_yank_01.dump b/src/testdir/dumps/Test_cursorline_yank_01.dump
new file mode 100644
index 0000000..3de1bff
--- /dev/null
+++ b/src/testdir/dumps/Test_cursorline_yank_01.dump
@@ -0,0 +1,8 @@
+| +0#af5f00255#ffffff0@1|3| | +0#0000000&@70
+| +0#af5f00255&@1|2| |1+0#0000000&| @69
+| +0#af5f00255&@1|1| |2+0#0000000&| @69
+| +0#af5f00255&@1|0| >3+8#0000000&| @69
+| +0#af5f00255&@1|1| | +0#0000000&@70
+|~+0#4040ff13&| @73
+|~| @73
+|4+0#0000000&| |l|i|n|e|s| |y|a|n|k|e|d| @42|4|,|1| @10|A|l@1|
diff --git a/src/testdir/dumps/Test_diff_01.dump b/src/testdir/dumps/Test_diff_01.dump
new file mode 100644
index 0000000..0dbce1f
--- /dev/null
+++ b/src/testdir/dumps/Test_diff_01.dump
@@ -0,0 +1,20 @@
+| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34||+1#0000000#ffffff0| +0#0000e05#a8a8a8255@1|0+0#0000000#5fd7ff255| @33
+| +0#0000e05#a8a8a8255@1|1+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|1+0#0000000#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|2+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|2+0#0000000#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|3+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|3+0#0000000#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|4+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|4+0#0000000#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|5+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|5+0#0000000#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|6+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|6+0#0000000#ffffff0| @33
+|++0#0000e05#a8a8a8255| |+|-@1| @1|4| |l|i|n|e|s|:| |7|-@19||+1#0000000#ffffff0|++0#0000e05#a8a8a8255| |+|-@1| @1|4| |l|i|n|e|s|:| |7|-@19
+| @1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+|X+3#0000000&|f|i|l|e|1| @12|1|,|1| @11|A|l@1| |X+1&&|f|i|l|e|2| @12|1|,|1| @11|A|l@1
+|:+0&&> @73
diff --git a/src/testdir/dumps/Test_diff_02.dump b/src/testdir/dumps/Test_diff_02.dump
new file mode 100644
index 0000000..78f7978
--- /dev/null
+++ b/src/testdir/dumps/Test_diff_02.dump
@@ -0,0 +1,20 @@
+| +0#0000e05#a8a8a8255@1|0+0#0000000#5fd7ff255| @33||+1&#ffffff0| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34
+| +0#0000e05#a8a8a8255@1|1+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|1+0#0000000#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|2+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|2+0#0000000#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|3+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|3+0#0000000#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|4+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|4+0#0000000#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|5+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|5+0#0000000#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|6+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|6+0#0000000#ffffff0| @33
+|++0#0000e05#a8a8a8255| |+|-@1| @1|4| |l|i|n|e|s|:| |7|-@19||+1#0000000#ffffff0|++0#0000e05#a8a8a8255| |+|-@1| @1|4| |l|i|n|e|s|:| |7|-@19
+| @1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+|X+3#0000000&|f|i|l|e|1| @12|1|,|1| @11|A|l@1| |X+1&&|f|i|l|e|2| @12|1|,|1| @11|A|l@1
+|:+0&&> @73
diff --git a/src/testdir/dumps/Test_diff_03.dump b/src/testdir/dumps/Test_diff_03.dump
new file mode 100644
index 0000000..60916a8
--- /dev/null
+++ b/src/testdir/dumps/Test_diff_03.dump
@@ -0,0 +1,20 @@
+|++0#0000e05#a8a8a8255| |+|-@1| @1|4| |l|i|n|e|s|:| |1|-@19||+1#0000000#ffffff0|++0#0000e05#a8a8a8255| |+|-@1| @1|4| |l|i|n|e|s|:| |1|-@19
+| @1|5+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|5+0#0000000#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|6+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|6+0#0000000#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|7+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|7+0#0000000#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|8+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|8+0#0000000#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|9+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|9+0#0000000#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|1+0#0000000#ffffff0|0| @32||+1&&| +0#0000e05#a8a8a8255@1|1+0#0000000#ffffff0|0| @32
+| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34||+1#0000000#ffffff0| +0#0000e05#a8a8a8255@1|1+0#0000000#5fd7ff255@1| @32
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+|X+3#0000000&|f|i|l|e|1| @12|1|,|1| @11|A|l@1| |X+1&&|f|i|l|e|2| @12|1|,|1| @11|A|l@1
+|:+0&&> @73
diff --git a/src/testdir/dumps/Test_diff_04.dump b/src/testdir/dumps/Test_diff_04.dump
new file mode 100644
index 0000000..ba9cdd8
--- /dev/null
+++ b/src/testdir/dumps/Test_diff_04.dump
@@ -0,0 +1,20 @@
+|++0#0000e05#a8a8a8255| |+|-@1| @1|4| |l|i|n|e|s|:| |1|-@19||+1#0000000#ffffff0|++0#0000e05#a8a8a8255| |+|-@1| @1|4| |l|i|n|e|s|:| |1|-@19
+| @1|5+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|5+0#0000000#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|6+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|6+0#0000000#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|7+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|7+0#0000000#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|8+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|8+0#0000000#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|9+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|9+0#0000000#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|1+0#0000000#ffffff0|0| @32||+1&&| +0#0000e05#a8a8a8255@1|1+0#0000000#ffffff0|0| @32
+| +0#0000e05#a8a8a8255@1|1+0#0000000#5fd7ff255@1| @32||+1&#ffffff0| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+|X+3#0000000&|f|i|l|e|1| @12|1|,|1| @11|A|l@1| |X+1&&|f|i|l|e|2| @12|1|,|1| @11|A|l@1
+|:+0&&> @73
diff --git a/src/testdir/dumps/Test_diff_05.dump b/src/testdir/dumps/Test_diff_05.dump
new file mode 100644
index 0000000..7a5d540
--- /dev/null
+++ b/src/testdir/dumps/Test_diff_05.dump
@@ -0,0 +1,20 @@
+| +0#0000e05#a8a8a8255@1|1+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|1+0#0000000#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|2+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|2+0#0000000#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|3+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|3+0#0000000#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|4+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|4+0#0000000#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34||+1#0000000#ffffff0| +0#0000e05#a8a8a8255@1|4+0#0000000#5fd7ff255| @33
+| +0#0000e05#a8a8a8255@1|5+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|5+0#0000000#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|6+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|6+0#0000000#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|7+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|7+0#0000000#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|8+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|8+0#0000000#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|9+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|9+0#0000000#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|1+0#0000000#ffffff0|0| @32||+1&&| +0#0000e05#a8a8a8255@1|1+0#0000000#ffffff0|0| @32
+| +0#0000e05#a8a8a8255@1|1+0#0000000#5fd7ff255@1| @32||+1&#ffffff0| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+|X+3#0000000&|f|i|l|e|1| @12|1|,|1| @11|A|l@1| |X+1&&|f|i|l|e|2| @12|1|,|1| @11|A|l@1
+|:+0&&> @73
diff --git a/src/testdir/dumps/Test_diff_06.dump b/src/testdir/dumps/Test_diff_06.dump
new file mode 100644
index 0000000..8cd68fd
--- /dev/null
+++ b/src/testdir/dumps/Test_diff_06.dump
@@ -0,0 +1,20 @@
+| +0#0000e05#a8a8a8255@1|1+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|1+0#0000000#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|2+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|2+0#0000000#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|3+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|3+0#0000000#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|4+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|4+0#0000000#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|4+0#0000000#5fd7ff255| @33||+1&#ffffff0| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34
+| +0#0000e05#a8a8a8255@1|5+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|5+0#0000000#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|6+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|6+0#0000000#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|7+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|7+0#0000000#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|8+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|8+0#0000000#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|9+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|9+0#0000000#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|1+0#0000000#ffffff0|0| @32||+1&&| +0#0000e05#a8a8a8255@1|1+0#0000000#ffffff0|0| @32
+| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34||+1#0000000#ffffff0| +0#0000e05#a8a8a8255@1|1+0#0000000#5fd7ff255@1| @32
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+|X+3#0000000&|f|i|l|e|1| @12|1|,|1| @11|A|l@1| |X+1&&|f|i|l|e|2| @12|1|,|1| @11|A|l@1
+|:+0&&> @73
diff --git a/src/testdir/dumps/Test_diff_07.dump b/src/testdir/dumps/Test_diff_07.dump
new file mode 100644
index 0000000..97864c6
--- /dev/null
+++ b/src/testdir/dumps/Test_diff_07.dump
@@ -0,0 +1,20 @@
+| +0#0000e05#a8a8a8255@1>#+0#0000000#ffffff0|i|n|c|l|u|d|e| |<|s|t|d|i|o|.|h|>| @16||+1&&| +0#0000e05#a8a8a8255@1|#+0#0000000#ffffff0|i|n|c|l|u|d|e| |<|s|t|d|i|o|.|h|>| @16
+| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@34||+1&&| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@34
+| +0#0000e05#a8a8a8255@1|/+2#0000000#ff404010@1| |F|r|o|b|s| |f|o@1| |h|e|a|r|t|i|l|y| +0&#ffd7ff255@13||+1&#ffffff0| +0#0000e05#a8a8a8255@1|i+2#0000000#ff404010|n|t| |f|i|b|(|i|n|t| |n|)| +0&#ffd7ff255@20
+| +0#0000e05#a8a8a8255@1|i+0#0000000#5fd7ff255|n|t| |f|r|o|b|n|i|t|z|(|i|n|t| |f|o@1|)| @13||+1&#ffffff0| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34
+| +0#0000e05#a8a8a8255@1|{+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|{+0#0000000#ffffff0| @33
+| +0#0000e05#a8a8a8255@1| +0#0000000#ffd7ff255@3|i|n+2&#ff404010|t| |i|;| +0&#ffd7ff255@24||+1&#ffffff0| +0#0000e05#a8a8a8255@1| +0#0000000#ffd7ff255@3|i|f+2&#ff404010|(|n| |>| |2|)| +0&#ffd7ff255@21
+| +0#0000e05#a8a8a8255@1| +0#0000000#5fd7ff255@3|f|o|r|(|i| |=| |0|;| |i| |<| |1|0|;| |i|+@1|)| @7||+1&#ffffff0| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34
+| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@3|{| @29||+1&&| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@3|{| @29
+| +0#0000e05#a8a8a8255@1| +0#0000000#ffd7ff255@7|p+2&#ff404010|r|i|n|t|f|(|"|Y|o|u|r| |a|n|s|w|e|r| |i|s|:| |"|)+0&#ffd7ff255|;||+1&#ffffff0| +0#0000e05#a8a8a8255@1| +0#0000000#ffd7ff255@7|r+2&#ff404010|e|t|u|r|n| |f|i|b|(|n|-|1|)| |+| |f|i|b|(|n|-|2|)+0&#ffd7ff255|;
+| +0#0000e05#a8a8a8255@1| +0#0000000#5fd7ff255@7|p|r|i|n|t|f|(|"|%|d|\|n|"|,| |f|o@1|)|;| @6||+1&#ffffff0| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34
+| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@3|}| @29||+1&&| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@3|}| @29
+| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34||+1#0000000#ffffff0| +0#0000e05#a8a8a8255@1| +0#0000000#5fd7ff255@3|r|e|t|u|r|n| |1|;| @21
+| +0#0000e05#a8a8a8255@1|}+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|}+0#0000000#ffffff0| @33
+| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@34||+1&&| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@34
+| +0#0000e05#a8a8a8255@1|i+2#0000000#ff404010|n|t| |f|a|c|t|(|i|n|t| |n|)| +0&#ffd7ff255@19||+1&#ffffff0| +0#0000e05#a8a8a8255@1|/+2#0000000#ff404010@1| |F|r|o|b|s| |f|o@1| |h|e|a|r|t|i|l|y| +0&#ffd7ff255@13
+| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34||+1#0000000#ffffff0| +0#0000e05#a8a8a8255@1|i+0#0000000#5fd7ff255|n|t| |f|r|o|b|n|i|t|z|(|i|n|t| |f|o@1|)| @13
+| +0#0000e05#a8a8a8255@1|{+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|{+0#0000000#ffffff0| @33
+| +0#0000e05#a8a8a8255@1| +0#0000000#ffd7ff255@3|i|f+2&#ff404010|(|n| |>| |1|)| +0&#ffd7ff255@21||+1&#ffffff0| +0#0000e05#a8a8a8255@1| +0#0000000#ffd7ff255@3|i|n+2&#ff404010|t| |i|;| +0&#ffd7ff255@24
+|X+3&#ffffff0|f|i|l|e|1| @12|1|,|1| @11|T|o|p| |X+1&&|f|i|l|e|2| @12|1|,|1| @11|T|o|p
+|:+0&&|s|e|t| |d|i|f@1|o|p|t|+|=|i|n|t|e|r|n|a|l| @52
diff --git a/src/testdir/dumps/Test_diff_08.dump b/src/testdir/dumps/Test_diff_08.dump
new file mode 100644
index 0000000..6445a57
--- /dev/null
+++ b/src/testdir/dumps/Test_diff_08.dump
@@ -0,0 +1,20 @@
+| +0#0000e05#a8a8a8255@1>#+0#0000000#ffffff0|i|n|c|l|u|d|e| |<|s|t|d|i|o|.|h|>| @16||+1&&| +0#0000e05#a8a8a8255@1|#+0#0000000#ffffff0|i|n|c|l|u|d|e| |<|s|t|d|i|o|.|h|>| @16
+| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@34||+1&&| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@34
+| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34||+1#0000000#ffffff0| +0#0000e05#a8a8a8255@1|i+0#0000000#5fd7ff255|n|t| |f|i|b|(|i|n|t| |n|)| @20
+| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34||+1#0000000#ffffff0| +0#0000e05#a8a8a8255@1|{+0#0000000#5fd7ff255| @33
+| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34||+1#0000000#ffffff0| +0#0000e05#a8a8a8255@1| +0#0000000#5fd7ff255@3|i|f|(|n| |>| |2|)| @21
+| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34||+1#0000000#ffffff0| +0#0000e05#a8a8a8255@1| +0#0000000#5fd7ff255@3|{| @29
+| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34||+1#0000000#ffffff0| +0#0000e05#a8a8a8255@1| +0#0000000#5fd7ff255@7|r|e|t|u|r|n| |f|i|b|(|n|-|1|)| |+| |f|i|b|(|n|-|2|)|;
+| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34||+1#0000000#ffffff0| +0#0000e05#a8a8a8255@1| +0#0000000#5fd7ff255@3|}| @29
+| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34||+1#0000000#ffffff0| +0#0000e05#a8a8a8255@1| +0#0000000#5fd7ff255@3|r|e|t|u|r|n| |1|;| @21
+| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34||+1#0000000#ffffff0| +0#0000e05#a8a8a8255@1|}+0#0000000#5fd7ff255| @33
+| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34||+1#0000000#ffffff0| +0#0000e05#a8a8a8255@1| +0#0000000#5fd7ff255@34
+| +0#0000e05#a8a8a8255@1|/+0#0000000#ffffff0@1| |F|r|o|b|s| |f|o@1| |h|e|a|r|t|i|l|y| @13||+1&&| +0#0000e05#a8a8a8255@1|/+0#0000000#ffffff0@1| |F|r|o|b|s| |f|o@1| |h|e|a|r|t|i|l|y| @13
+| +0#0000e05#a8a8a8255@1|i+0#0000000#ffffff0|n|t| |f|r|o|b|n|i|t|z|(|i|n|t| |f|o@1|)| @13||+1&&| +0#0000e05#a8a8a8255@1|i+0#0000000#ffffff0|n|t| |f|r|o|b|n|i|t|z|(|i|n|t| |f|o@1|)| @13
+| +0#0000e05#a8a8a8255@1|{+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|{+0#0000000#ffffff0| @33
+| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@3|i|n|t| |i|;| @24||+1&&| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@3|i|n|t| |i|;| @24
+| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@3|f|o|r|(|i| |=| |0|;| |i| |<| |1|0|;| |i|+@1|)| @7||+1&&| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@3|f|o|r|(|i| |=| |0|;| |i| |<| |1|0|;| |i|+@1|)| @7
+| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@3|{| @29||+1&&| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@3|{| @29
+| +0#0000e05#a8a8a8255@1| +0#0000000#5fd7ff255@7|p|r|i|n|t|f|(|"|Y|o|u|r| |a|n|s|w|e|r| |i|s|:| |"|)|;||+1&#ffffff0| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34
+|X+3#0000000#ffffff0|f|i|l|e|1| @12|1|,|1| @11|T|o|p| |X+1&&|f|i|l|e|2| @12|1|,|1| @11|T|o|p
+|:+0&&|s|e|t| |d|i|f@1|o|p|t|+|=|a|l|g|o|r|i|t|h|m|:|p|a|t|i|e|n|c|e| @42
diff --git a/src/testdir/dumps/Test_diff_09.dump b/src/testdir/dumps/Test_diff_09.dump
new file mode 100644
index 0000000..95692b6
--- /dev/null
+++ b/src/testdir/dumps/Test_diff_09.dump
@@ -0,0 +1,20 @@
+| +0#0000e05#a8a8a8255@1>#+0#0000000#ffffff0|i|n|c|l|u|d|e| |<|s|t|d|i|o|.|h|>| @16||+1&&| +0#0000e05#a8a8a8255@1|#+0#0000000#ffffff0|i|n|c|l|u|d|e| |<|s|t|d|i|o|.|h|>| @16
+| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@34||+1&&| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@34
+| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34||+1#0000000#ffffff0| +0#0000e05#a8a8a8255@1|i+0#0000000#5fd7ff255|n|t| |f|i|b|(|i|n|t| |n|)| @20
+| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34||+1#0000000#ffffff0| +0#0000e05#a8a8a8255@1|{+0#0000000#5fd7ff255| @33
+| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34||+1#0000000#ffffff0| +0#0000e05#a8a8a8255@1| +0#0000000#5fd7ff255@3|i|f|(|n| |>| |2|)| @21
+| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34||+1#0000000#ffffff0| +0#0000e05#a8a8a8255@1| +0#0000000#5fd7ff255@3|{| @29
+| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34||+1#0000000#ffffff0| +0#0000e05#a8a8a8255@1| +0#0000000#5fd7ff255@7|r|e|t|u|r|n| |f|i|b|(|n|-|1|)| |+| |f|i|b|(|n|-|2|)|;
+| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34||+1#0000000#ffffff0| +0#0000e05#a8a8a8255@1| +0#0000000#5fd7ff255@3|}| @29
+| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34||+1#0000000#ffffff0| +0#0000e05#a8a8a8255@1| +0#0000000#5fd7ff255@3|r|e|t|u|r|n| |1|;| @21
+| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34||+1#0000000#ffffff0| +0#0000e05#a8a8a8255@1|}+0#0000000#5fd7ff255| @33
+| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34||+1#0000000#ffffff0| +0#0000e05#a8a8a8255@1| +0#0000000#5fd7ff255@34
+| +0#0000e05#a8a8a8255@1|/+0#0000000#ffffff0@1| |F|r|o|b|s| |f|o@1| |h|e|a|r|t|i|l|y| @13||+1&&| +0#0000e05#a8a8a8255@1|/+0#0000000#ffffff0@1| |F|r|o|b|s| |f|o@1| |h|e|a|r|t|i|l|y| @13
+| +0#0000e05#a8a8a8255@1|i+0#0000000#ffffff0|n|t| |f|r|o|b|n|i|t|z|(|i|n|t| |f|o@1|)| @13||+1&&| +0#0000e05#a8a8a8255@1|i+0#0000000#ffffff0|n|t| |f|r|o|b|n|i|t|z|(|i|n|t| |f|o@1|)| @13
+| +0#0000e05#a8a8a8255@1|{+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|{+0#0000000#ffffff0| @33
+| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@3|i|n|t| |i|;| @24||+1&&| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@3|i|n|t| |i|;| @24
+| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@3|f|o|r|(|i| |=| |0|;| |i| |<| |1|0|;| |i|+@1|)| @7||+1&&| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@3|f|o|r|(|i| |=| |0|;| |i| |<| |1|0|;| |i|+@1|)| @7
+| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@3|{| @29||+1&&| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@3|{| @29
+| +0#0000e05#a8a8a8255@1| +0#0000000#5fd7ff255@7|p|r|i|n|t|f|(|"|Y|o|u|r| |a|n|s|w|e|r| |i|s|:| |"|)|;||+1&#ffffff0| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34
+|X+3#0000000#ffffff0|f|i|l|e|1| @12|1|,|1| @11|T|o|p| |X+1&&|f|i|l|e|2| @12|1|,|1| @11|T|o|p
+|:+0&&|s|e|t| |d|i|f@1|o|p|t|+|=|a|l|g|o|r|i|t|h|m|:|h|i|s|t|o|g|r|a|m| @41
diff --git a/src/testdir/dumps/Test_diff_10.dump b/src/testdir/dumps/Test_diff_10.dump
new file mode 100644
index 0000000..70b9c82
--- /dev/null
+++ b/src/testdir/dumps/Test_diff_10.dump
@@ -0,0 +1,20 @@
+| +0#0000e05#a8a8a8255@1> +0#0000000#ffffff0@34||+1&&| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@34
+| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@1|d|e|f| |f|i|n|a|l|i|z|e|(|v|a|l|u|e|s|)| @12||+1&&| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@1|d|e|f| |f|i|n|a|l|i|z|e|(|v|a|l|u|e|s|)| @12
+| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@34||+1&&| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@34
+| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@3|v|a|l|u|e|s|.|e|a|c|h| |d|o| |||v||| @12||+1&&| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@3|v|a|l|u|e|s|.|e|a|c|h| |d|o| |||v||| @12
+| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34||+1#0000000#ffffff0| +0#0000e05#a8a8a8255@1| +0#0000000#5fd7ff255@5|v|.|p|r|e|p|a|r|e| @19
+| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34||+1#0000000#ffffff0| +0#0000e05#a8a8a8255@1| +0#0000000#5fd7ff255@3|e|n|d| @27
+| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34||+1#0000000#ffffff0| +0#0000e05#a8a8a8255@1| +0#0000000#5fd7ff255@34
+| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34||+1#0000000#ffffff0| +0#0000e05#a8a8a8255@1| +0#0000000#5fd7ff255@3|v|a|l|u|e|s|.|e|a|c|h| |d|o| |||v||| @12
+| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@5|v|.|f|i|n|a|l|i|z|e| @18||+1&&| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@5|v|.|f|i|n|a|l|i|z|e| @18
+| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@3|e|n|d| @27||+1&&| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@3|e|n|d| @27
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+|X+3#0000000&|f|i|l|e|1| @12|1|,|0|-|1| @9|A|l@1| |X+1&&|f|i|l|e|2| @12|1|,|0|-|1| @9|A|l@1
+|:+0&&|s|e|t| |d|i|f@1|o|p|t|+|=|i|n|t|e|r|n|a|l| @52
diff --git a/src/testdir/dumps/Test_diff_11.dump b/src/testdir/dumps/Test_diff_11.dump
new file mode 100644
index 0000000..3b24ebb
--- /dev/null
+++ b/src/testdir/dumps/Test_diff_11.dump
@@ -0,0 +1,20 @@
+| +0#0000e05#a8a8a8255@1> +0#0000000#ffffff0@34||+1&&| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@34
+| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@1|d|e|f| |f|i|n|a|l|i|z|e|(|v|a|l|u|e|s|)| @12||+1&&| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@1|d|e|f| |f|i|n|a|l|i|z|e|(|v|a|l|u|e|s|)| @12
+| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@34||+1&&| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@34
+| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34||+1#0000000#ffffff0| +0#0000e05#a8a8a8255@1| +0#0000000#5fd7ff255@3|v|a|l|u|e|s|.|e|a|c|h| |d|o| |||v||| @12
+| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34||+1#0000000#ffffff0| +0#0000e05#a8a8a8255@1| +0#0000000#5fd7ff255@5|v|.|p|r|e|p|a|r|e| @19
+| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34||+1#0000000#ffffff0| +0#0000e05#a8a8a8255@1| +0#0000000#5fd7ff255@3|e|n|d| @27
+| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34||+1#0000000#ffffff0| +0#0000e05#a8a8a8255@1| +0#0000000#5fd7ff255@34
+| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@3|v|a|l|u|e|s|.|e|a|c|h| |d|o| |||v||| @12||+1&&| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@3|v|a|l|u|e|s|.|e|a|c|h| |d|o| |||v||| @12
+| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@5|v|.|f|i|n|a|l|i|z|e| @18||+1&&| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@5|v|.|f|i|n|a|l|i|z|e| @18
+| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@3|e|n|d| @27||+1&&| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@3|e|n|d| @27
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+|X+3#0000000&|f|i|l|e|1| @12|1|,|0|-|1| @9|A|l@1| |X+1&&|f|i|l|e|2| @12|1|,|0|-|1| @9|A|l@1
+|:+0&&| @73
diff --git a/src/testdir/dumps/Test_diff_12.dump b/src/testdir/dumps/Test_diff_12.dump
new file mode 100644
index 0000000..0ed4f91
--- /dev/null
+++ b/src/testdir/dumps/Test_diff_12.dump
@@ -0,0 +1,20 @@
+|++0#0000e05#a8a8a8255| |+|-@1| |1|0| |l|i|n|e|s|:| |1|-@19||+1#0000000#ffffff0|++0#0000e05#a8a8a8255| |+|-@1| |1|0| |l|i|n|e|s|:| |1|-@19
+| @1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+|X+3#0000000&|f|i|l|e|1| @12|1|,|1| @11|A|l@1| |X+1&&|f|i|l|e|2| @12|1|,|1| @11|A|l@1
+|:+0&&> @73
diff --git a/src/testdir/dumps/Test_diff_13.dump b/src/testdir/dumps/Test_diff_13.dump
new file mode 100644
index 0000000..cc1f1ad
--- /dev/null
+++ b/src/testdir/dumps/Test_diff_13.dump
@@ -0,0 +1,20 @@
+|-+0#0000e05#a8a8a8255| | +0#0000000#ffffff0@34||+1&&|-+0#0000e05#a8a8a8255| | +0#0000000#ffffff0@34
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+|X+3#0000000&|f|i|l|e|1| @12|0|,|0|-|1| @9|A|l@1| |X+1&&|f|i|l|e|2| @12|0|,|0|-|1| @9|A|l@1
+|:+0&&> @73
diff --git a/src/testdir/dumps/Test_diff_14.dump b/src/testdir/dumps/Test_diff_14.dump
new file mode 100644
index 0000000..5f9b75f
--- /dev/null
+++ b/src/testdir/dumps/Test_diff_14.dump
@@ -0,0 +1,20 @@
+| +0#0000e05#a8a8a8255@1|a+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|A+0#0000000#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|b+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|b+0#0000000#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|c+0#0000000#ffd7ff255|d| @32||+1&#ffffff0| +0#0000e05#a8a8a8255@1|c+0#0000000#ffd7ff255|D|e+2&#ff404010| +0&#ffd7ff255@31
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+|X+3#0000000&|f|i|l|e|1| @12|1|,|1| @11|A|l@1| |X+1&&|f|i|l|e|2| @12|1|,|1| @11|A|l@1
+|:+0&&> @73
diff --git a/src/testdir/dumps/Test_diff_15.dump b/src/testdir/dumps/Test_diff_15.dump
new file mode 100644
index 0000000..0eb1813
--- /dev/null
+++ b/src/testdir/dumps/Test_diff_15.dump
@@ -0,0 +1,20 @@
+| +0#0000e05#a8a8a8255@1>i+0#0000000#ffffff0|n|t| |m|a|i|n|(|)| @24||+1&&| +0#0000e05#a8a8a8255@1|i+0#0000000#ffffff0|n|t| |m|a|i|n|(|)| @24
+| +0#0000e05#a8a8a8255@1|{+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|{+0#0000000#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34||+1#0000000#ffffff0| +0#0000e05#a8a8a8255@1| +0#0000000#5fd7ff255@2|i|f| |(|0|)| @25
+| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34||+1#0000000#ffffff0| +0#0000e05#a8a8a8255@1| +0#0000000#5fd7ff255@2|{| @30
+| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@2|p|r|i|n|t|f|(|"|H|e|l@1|o|,| |W|o|r|l|d|!|"|)|;| @7||+1&&| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@5|p|r|i|n|t|f|(|"|H|e|l@1|o|,| |W|o|r|l|d|!|"|)|;| @4
+| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@2|r|e|t|u|r|n| |0|;| @22||+1&&| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@5|r|e|t|u|r|n| |0|;| @19
+| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34||+1#0000000#ffffff0| +0#0000e05#a8a8a8255@1| +0#0000000#5fd7ff255@2|}| @30
+| +0#0000e05#a8a8a8255@1|}+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|}+0#0000000#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+|X+3#0000000&|f|i|l|e|1| @12|1|,|1| @11|A|l@1| |X+1&&|f|i|l|e|2| @12|1|,|1| @11|A|l@1
+|:+0&&|s|e|t| |d|i|f@1|o|p|t|&|v|i|m| |d|i|f@1|o|p|t|+|=|f|i|l@1|e|r| |d|i|f@1|o|p|t|+|=|i|w|h|i|t|e| @26
diff --git a/src/testdir/dumps/Test_diff_16.dump b/src/testdir/dumps/Test_diff_16.dump
new file mode 100644
index 0000000..74ad5b6
--- /dev/null
+++ b/src/testdir/dumps/Test_diff_16.dump
@@ -0,0 +1,20 @@
+| +0#0000e05#a8a8a8255@1>i+0#0000000#ffffff0|n|t| |m|a|i|n|(|)| @24||+1&&| +0#0000e05#a8a8a8255@1|i+0#0000000#ffffff0|n|t| |m|a|i|n|(|)| @24
+| +0#0000e05#a8a8a8255@1|{+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|{+0#0000000#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34||+1#0000000#ffffff0| +0#0000e05#a8a8a8255@1| +0#0000000#5fd7ff255@2|i|f| |(|0|)| @25
+| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34||+1#0000000#ffffff0| +0#0000e05#a8a8a8255@1| +0#0000000#5fd7ff255@2|{| @30
+| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@2|p|r|i|n|t|f|(|"|H|e|l@1|o|,| |W|o|r|l|d|!|"|)|;| @7||+1&&| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@5|p|r|i|n|t|f|(|"|H|e|l@1|o|,| |W|o|r|l|d|!|"|)|;| @4
+| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@2|r|e|t|u|r|n| |0|;| @22||+1&&| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@5|r|e|t|u|r|n| |0|;| @19
+| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34||+1#0000000#ffffff0| +0#0000e05#a8a8a8255@1| +0#0000000#5fd7ff255@2|}| @30
+| +0#0000e05#a8a8a8255@1|}+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|}+0#0000000#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+|X+3#0000000&|f|i|l|e|1| @12|1|,|1| @11|A|l@1| |X+1&&|f|i|l|e|2| @12|1|,|1| @11|A|l@1
+|:+0&&|s|e|t| |d|i|f@1|o|p|t|+|=|i|n|t|e|r|n|a|l| @52
diff --git a/src/testdir/dumps/Test_diff_17.dump b/src/testdir/dumps/Test_diff_17.dump
new file mode 100644
index 0000000..101df35
--- /dev/null
+++ b/src/testdir/dumps/Test_diff_17.dump
@@ -0,0 +1,20 @@
+| +0#0000e05#a8a8a8255@1|a+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|a+0#0000000#ffffff0| @33
+| +0#0000e05#a8a8a8255@1| +0#0000000#5fd7ff255@34||+1&#ffffff0| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34
+| +0#0000e05#a8a8a8255@1|c+0#0000000#ffffff0|d| @32||+1&&| +0#0000e05#a8a8a8255@1|c+0#0000000#ffffff0|d| @32
+| +0#0000e05#a8a8a8255@1|e+0#0000000#ffffff0|f| @32||+1&&| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@34
+| +0#0000e05#a8a8a8255@1|x+2#0000000#ff404010@2| +0&#ffd7ff255@31||+1&#ffffff0| +0#0000e05#a8a8a8255@1|e+0#0000000#ffffff0|f| @32
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|y+2#0000000#ff404010@2| +0&#ffd7ff255@31
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+|X+3#0000000&|f|i|l|e|1| @12|1|,|1| @11|A|l@1| |X+1&&|f|i|l|e|2| @12|1|,|1| @11|A|l@1
+|:+0&&> @73
diff --git a/src/testdir/dumps/Test_diff_18.dump b/src/testdir/dumps/Test_diff_18.dump
new file mode 100644
index 0000000..7f17531
--- /dev/null
+++ b/src/testdir/dumps/Test_diff_18.dump
@@ -0,0 +1,20 @@
+| +0#0000e05#a8a8a8255@1|a+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|a+0#0000000#ffffff0| @33
+| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@34||+1&&| +0#0000e05#a8a8a8255@1|c+0#0000000#ffffff0|d| @32
+| +0#0000e05#a8a8a8255@1|c+0#0000000#ffffff0|d| @32||+1&&| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@34
+| +0#0000e05#a8a8a8255@1|e+0#0000000#ffffff0|f| @32||+1&&| +0#0000e05#a8a8a8255@1|e+0#0000000#ffffff0|f| @32
+| +0#0000e05#a8a8a8255@1|x+2#0000000#ff404010@2| +0&#ffd7ff255@31||+1&#ffffff0| +0#0000e05#a8a8a8255@1|y+2#0000000#ff404010@2| +0&#ffd7ff255@31
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+|X+3#0000000&|f|i|l|e|1| @12|1|,|1| @11|A|l@1| |X+1&&|f|i|l|e|2| @12|1|,|1| @11|A|l@1
+|:+0&&> @73
diff --git a/src/testdir/dumps/Test_diff_19.dump b/src/testdir/dumps/Test_diff_19.dump
new file mode 100644
index 0000000..f2d0611
--- /dev/null
+++ b/src/testdir/dumps/Test_diff_19.dump
@@ -0,0 +1,20 @@
+| +0#0000e05#a8a8a8255@1|a+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|a+0#0000000#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|x+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|x+0#0000000#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|c+0#0000000#ffd7ff255|d| @32||+1&#ffffff0| +0#0000e05#a8a8a8255@1|c+0#0000000#ffd7ff255| +2&#ff404010|d+0&#ffd7ff255| @31
+| +0#0000e05#a8a8a8255@1|e+0#0000000#ffd7ff255|f| @32||+1&#ffffff0| +0#0000e05#a8a8a8255@1| +2#0000000#ff404010|e+0&#ffd7ff255|f| @31
+| +0#0000e05#a8a8a8255@1|x+0#0000000#ffd7ff255@1| | +2&#ff404010|x+0&#ffd7ff255@1| @28||+1&#ffffff0| +0#0000e05#a8a8a8255@1|x+0#0000000#ffd7ff255@1| |x@1| @29
+| +0#0000e05#a8a8a8255@1|f+0#0000000#ffffff0|o@1| @31||+1&&| +0#0000e05#a8a8a8255@1|f+0#0000000#ffffff0|o@1| @31
+| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34||+1#0000000#ffffff0| +0#0000e05#a8a8a8255@1| +0#0000000#5fd7ff255@34
+| +0#0000e05#a8a8a8255@1|b+0#0000000#ffffff0|a|r| @31||+1&&| +0#0000e05#a8a8a8255@1|b+0#0000000#ffffff0|a|r| @31
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+|X+3#0000000&|f|i|l|e|1| @12|1|,|1| @11|A|l@1| |X+1&&|f|i|l|e|2| @12|1|,|1| @11|A|l@1
+|:+0&&> @73
diff --git a/src/testdir/dumps/Test_diff_20.dump b/src/testdir/dumps/Test_diff_20.dump
new file mode 100644
index 0000000..1dbd07c
--- /dev/null
+++ b/src/testdir/dumps/Test_diff_20.dump
@@ -0,0 +1,20 @@
+| +0#0000e05#a8a8a8255@1|a+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|a+0#0000000#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|x+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|x+0#0000000#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|c+0#0000000#ffffff0|d| @32||+1&&| +0#0000e05#a8a8a8255@1|c+0#0000000#ffffff0| |d| @31
+| +0#0000e05#a8a8a8255@1|e+0#0000000#ffffff0|f| @32||+1&&| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0|e|f| @31
+| +0#0000e05#a8a8a8255@1|x+0#0000000#ffffff0@1| @1|x@1| @28||+1&&| +0#0000e05#a8a8a8255@1|x+0#0000000#ffffff0@1| |x@1| @29
+| +0#0000e05#a8a8a8255@1|f+0#0000000#ffffff0|o@1| @31||+1&&| +0#0000e05#a8a8a8255@1|f+0#0000000#ffffff0|o@1| @31
+| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34||+1#0000000#ffffff0| +0#0000e05#a8a8a8255@1| +0#0000000#5fd7ff255@34
+| +0#0000e05#a8a8a8255@1|b+0#0000000#ffffff0|a|r| @31||+1&&| +0#0000e05#a8a8a8255@1|b+0#0000000#ffffff0|a|r| @31
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+|X+3#0000000&|f|i|l|e|1| @12|1|,|1| @11|A|l@1| |X+1&&|f|i|l|e|2| @12|1|,|1| @11|A|l@1
+|:+0&&> @73
diff --git a/src/testdir/dumps/Test_diff_of_diff_01.dump b/src/testdir/dumps/Test_diff_of_diff_01.dump
new file mode 100644
index 0000000..0e47a86
--- /dev/null
+++ b/src/testdir/dumps/Test_diff_of_diff_01.dump
@@ -0,0 +1,20 @@
+| +0#0000e05#a8a8a8255@1|a+0#0000000#ffffff0@1| @32||+1&&| +0#0000e05#a8a8a8255@1>a+0#0000000#ffffff0@1| @32
+| +0#0000e05#a8a8a8255@1|b+0#0000000#ffffff0@1| @32||+1&&| +0#0000e05#a8a8a8255@1|b+0#0000000#ffffff0@1| @32
+| +0#0000e05#a8a8a8255@1|c+0#0000000#ffffff0@1| @32||+1&&| +0#0000e05#a8a8a8255@1|c+0#0000000#ffffff0@1| @32
+| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34||+1#0000000#ffffff0| +0#0000e05#a8a8a8255@1|@+0#0000000#5fd7ff255@1| |-|3|,|2| |+|5|,|7| |@@1| @19
+| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34||+1#0000000#ffffff0| +0#0000e05#a8a8a8255@1|d+0#0000000#5fd7ff255@1| @32
+| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34||+1#0000000#ffffff0| +0#0000e05#a8a8a8255@1|e+0#0000000#5fd7ff255@1| @32
+| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34||+1#0000000#ffffff0| +0#0000e05#a8a8a8255@1|f+0#0000000#5fd7ff255@1| @32
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+|[+1#0000000&|N|o| |N|a|m|e|]| |[|+|]| @5|1|,|1| @11|A|l@1| |[+3&&|N|o| |N|a|m|e|]| |[|+|]| @5|1|,|1| @11|A|l@1
+| +0&&@74
diff --git a/src/testdir/dumps/Test_diff_with_cursorline_01.dump b/src/testdir/dumps/Test_diff_with_cursorline_01.dump
new file mode 100644
index 0000000..96fa357
--- /dev/null
+++ b/src/testdir/dumps/Test_diff_with_cursorline_01.dump
@@ -0,0 +1,20 @@
+| +0#0000e05#a8a8a8255@1|b+8#ffffff16#ff404010|e@1| @31||+1#0000000#ffffff0| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34
+| +0#0000e05#a8a8a8255@1|f+0#0000000#ffffff0|o@1| @31||+1&&| +0#0000e05#a8a8a8255@1>f+8#ffffff16#ff404010|o@1| @31
+| +0#0000e05#a8a8a8255@1|f+0#0000000#ffffff0|o@1| @31||+1&&| +0#0000e05#a8a8a8255@1|f+0#0000000#ffffff0|o@1| @31
+| +0#0000e05#a8a8a8255@1|b+2#0000000#ff404010|a|z| +0&#ffd7ff255@31||+1&#ffffff0| +0#0000e05#a8a8a8255@1|f+2#0000000#ff404010|o@1| +0&#ffd7ff255@31
+| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34||+1#0000000#ffffff0| +0#0000e05#a8a8a8255@1|b+0#0000000#5fd7ff255|a|r| @31
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+|[+1#0000000&|N|o| |N|a|m|e|]| |[|+|]| @5|1|,|1| @11|A|l@1| |[+3&&|N|o| |N|a|m|e|]| |[|+|]| @5|1|,|1| @11|A|l@1
+| +0&&@74
diff --git a/src/testdir/dumps/Test_diff_with_cursorline_02.dump b/src/testdir/dumps/Test_diff_with_cursorline_02.dump
new file mode 100644
index 0000000..1ba44e6
--- /dev/null
+++ b/src/testdir/dumps/Test_diff_with_cursorline_02.dump
@@ -0,0 +1,20 @@
+| +0#0000e05#a8a8a8255@1|b+0#0000000#5fd7ff255|e@1| @31||+1&#ffffff0| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34
+| +0#0000e05#a8a8a8255@1|f+0#0000000#ffffff0|o@1| @31||+1&&| +0#0000e05#a8a8a8255@1|f+0#0000000#ffffff0|o@1| @31
+| +0#0000e05#a8a8a8255@1|f+8#ffffff16#ff404010|o@1| @31||+1#0000000#ffffff0| +0#0000e05#a8a8a8255@1>f+8#ffffff16#ff404010|o@1| @31
+| +0#0000e05#a8a8a8255@1|b+2#0000000#ff404010|a|z| +0&#ffd7ff255@31||+1&#ffffff0| +0#0000e05#a8a8a8255@1|f+2#0000000#ff404010|o@1| +0&#ffd7ff255@31
+| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34||+1#0000000#ffffff0| +0#0000e05#a8a8a8255@1|b+0#0000000#5fd7ff255|a|r| @31
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+|[+1#0000000&|N|o| |N|a|m|e|]| |[|+|]| @5|3|,|1| @11|A|l@1| |[+3&&|N|o| |N|a|m|e|]| |[|+|]| @5|2|,|1| @11|A|l@1
+| +0&&@74
diff --git a/src/testdir/dumps/Test_diff_with_cursorline_03.dump b/src/testdir/dumps/Test_diff_with_cursorline_03.dump
new file mode 100644
index 0000000..8dbb414
--- /dev/null
+++ b/src/testdir/dumps/Test_diff_with_cursorline_03.dump
@@ -0,0 +1,20 @@
+| +0#0000e05#a8a8a8255@1|b+0#0000000#5fd7ff255|e@1| @31||+1&#ffffff0| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34
+| +0#0000e05#a8a8a8255@1|f+0#0000000#ffffff0|o@1| @31||+1&&| +0#0000e05#a8a8a8255@1|f+0#0000000#ffffff0|o@1| @31
+| +0#0000e05#a8a8a8255@1|f+0#0000000#ffffff0|o@1| @31||+1&&| +0#0000e05#a8a8a8255@1|f+0#0000000#ffffff0|o@1| @31
+| +0#0000e05#a8a8a8255@1|b+10#ffffff16#ff404010|a|z| +8&&@31||+1#0000000#ffffff0| +0#0000e05#a8a8a8255@1>f+10#ffffff16#ff404010|o@1| +8&&@31
+| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34||+1#0000000#ffffff0| +0#0000e05#a8a8a8255@1|b+0#0000000#5fd7ff255|a|r| @31
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33||+1#0000000&| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @33
+|[+1#0000000&|N|o| |N|a|m|e|]| |[|+|]| @5|4|,|1| @11|A|l@1| |[+3&&|N|o| |N|a|m|e|]| |[|+|]| @5|3|,|1| @11|A|l@1
+| +0&&@74
diff --git a/src/testdir/dumps/Test_folds_with_rnu_01.dump b/src/testdir/dumps/Test_folds_with_rnu_01.dump
new file mode 100644
index 0000000..15a44d1
--- /dev/null
+++ b/src/testdir/dumps/Test_folds_with_rnu_01.dump
@@ -0,0 +1,20 @@
+|++0#0000e05#a8a8a8255| @2|0| >+|-@1| @1|2| |l|i|n|e|s|:| |-@54
+|+| @2|1| |+|-@1| @1|2| |l|i|n|e|s|:| |-@54
+| @1|~+0#4040ff13#ffffff0| @71
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @71
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @71
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @71
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @71
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @71
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @71
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @71
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @71
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @71
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @71
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @71
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @71
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @71
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @71
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @71
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @71
+| +0#0000000&@56|1|,|1| @10|A|l@1|
diff --git a/src/testdir/dumps/Test_folds_with_rnu_02.dump b/src/testdir/dumps/Test_folds_with_rnu_02.dump
new file mode 100644
index 0000000..60d4eb3
--- /dev/null
+++ b/src/testdir/dumps/Test_folds_with_rnu_02.dump
@@ -0,0 +1,20 @@
+|++0#0000e05#a8a8a8255| @2|1| |+|-@1| @1|2| |l|i|n|e|s|:| |-@54
+|+| @2|0| >+|-@1| @1|2| |l|i|n|e|s|:| |-@54
+| @1|~+0#4040ff13#ffffff0| @71
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @71
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @71
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @71
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @71
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @71
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @71
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @71
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @71
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @71
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @71
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @71
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @71
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @71
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @71
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @71
+| +0#0000e05#a8a8a8255@1|~+0#4040ff13#ffffff0| @71
+| +0#0000000&@56|3|,|1| @10|A|l@1|
diff --git a/src/testdir/dumps/Test_incsearch_scrolling_01.dump b/src/testdir/dumps/Test_incsearch_scrolling_01.dump
new file mode 100644
index 0000000..c133d5f
--- /dev/null
+++ b/src/testdir/dumps/Test_incsearch_scrolling_01.dump
@@ -0,0 +1,9 @@
+|.+0&#ffffff0@69
+@50| @19
+|.@69
+@50| @19
+@70
+|t+1&&|a|r|g|e+0&&|t| @63
+|@+0#4040ff13&@2| @66
+|/+0#0000000&|t|a|r|g> @64
+@70
diff --git a/src/testdir/dumps/Test_incsearch_search_01.dump b/src/testdir/dumps/Test_incsearch_search_01.dump
new file mode 100644
index 0000000..324abfe
--- /dev/null
+++ b/src/testdir/dumps/Test_incsearch_search_01.dump
@@ -0,0 +1,9 @@
+|f+0&#ffff4012|o|o+0&#ffffff0| |1| @64
+|f+0&#ffff4012|o|o+0&#ffffff0| |2| @64
+|f+0&#ffff4012|o|o+0&#ffffff0| |3| @64
+|f+1&&|o|o+0&&| |4| @64
+|f+0&#ffff4012|o|o+0&#ffffff0| |5| @64
+|f+0&#ffff4012|o|o+0&#ffffff0| |6| @64
+|f+0&#ffff4012|o|o+0&#ffffff0| |7| @64
+|f+0&#ffff4012|o|o+0&#ffffff0| |8| @64
+|/|f|o> @66
diff --git a/src/testdir/dumps/Test_incsearch_search_02.dump b/src/testdir/dumps/Test_incsearch_search_02.dump
new file mode 100644
index 0000000..6c1b743
--- /dev/null
+++ b/src/testdir/dumps/Test_incsearch_search_02.dump
@@ -0,0 +1,9 @@
+|f+0&#ffffff0|o@1| |1| @64
+|f|o@1| |2| @64
+|f|o+1&&|o+0&&| |3| @64
+|f|o@1| |4| @64
+|f|o@1| |5| @64
+|f|o@1| |6| @64
+|f|o@1| |7| @64
+|f|o@1| |8| @64
+|/|\|v> @66
diff --git a/src/testdir/dumps/Test_incsearch_sort_01.dump b/src/testdir/dumps/Test_incsearch_sort_01.dump
new file mode 100644
index 0000000..6c003af
--- /dev/null
+++ b/src/testdir/dumps/Test_incsearch_sort_01.dump
@@ -0,0 +1,9 @@
+|a+0&#ffffff0|n|o|t|h|e|r| |o+1&&|n|e+0&&| |2| @56
+|t|h|a|t| |o+0&#ffff4012|n|e+0&#ffffff0| |3| @59
+|t|h|e| |o+0&#ffff4012|n|e+0&#ffffff0| |1| @60
+|~+0#4040ff13&| @68
+|~| @68
+|~| @68
+|~| @68
+|~| @68
+|:+0#0000000&|s|o|r|t| |n|i| |u| |/|o|n> @55
diff --git a/src/testdir/dumps/Test_incsearch_substitute_01.dump b/src/testdir/dumps/Test_incsearch_substitute_01.dump
new file mode 100644
index 0000000..63886f5
--- /dev/null
+++ b/src/testdir/dumps/Test_incsearch_substitute_01.dump
@@ -0,0 +1,9 @@
+|f+0&#ffffff0|o@1| |1| @64
+|f|o@1| |2| @64
+|f+1&&|o@1| +0&&|3| @64
+|f+0&#ffff4012|o@1| +0&#ffffff0|4| @64
+|f+0&#ffff4012|o@1| +0&#ffffff0|5| @64
+|f|o@1| |6| @64
+|f|o@1| |7| @64
+|f|o@1| |8| @64
+|:|.|,|.|+|2|s|/|f|o@1> @58
diff --git a/src/testdir/dumps/Test_incsearch_substitute_02.dump b/src/testdir/dumps/Test_incsearch_substitute_02.dump
new file mode 100644
index 0000000..fd1f912
--- /dev/null
+++ b/src/testdir/dumps/Test_incsearch_substitute_02.dump
@@ -0,0 +1,9 @@
+|f+0&#ffffff0|o@1| |1| @64
+|f|o@1| |2| @64
+|f|o@1| |3| @64
+|f+1&&|o@1| +0&&|4| @64
+|f+0&#ffff4012|o@1| +0&#ffffff0|5| @64
+|f+0&#ffff4012|o@1| +0&#ffffff0|6| @64
+|f|o@1| |7| @64
+|f|o@1| |8| @64
+|:|.|,|.|+|2|s|/@1> @60
diff --git a/src/testdir/dumps/Test_incsearch_substitute_03.dump b/src/testdir/dumps/Test_incsearch_substitute_03.dump
new file mode 100644
index 0000000..5d7afa0
--- /dev/null
+++ b/src/testdir/dumps/Test_incsearch_substitute_03.dump
@@ -0,0 +1,9 @@
+|f+0&#ffff4012|o@1| +0&#ffffff0|1| @64
+|f+0&#ffff4012|o@1| +0&#ffffff0|2| @64
+|f+0&#ffff4012|o@1| +0&#ffffff0|3| @64
+|f+0&#ffff4012|o@1| +0&#ffffff0|4| @64
+|f+0&#ffff4012|o@1| +0&#ffffff0|5| @64
+|f+0&#ffff4012|o@1| +0&#ffffff0|6| @64
+|f+0&#ffff4012|o@1| +0&#ffffff0|7| @64
+|f+0&#ffff4012|o@1| +0&#ffffff0|8| @64
+|:|.|,|.|+|2|s|/> @61
diff --git a/src/testdir/dumps/Test_incsearch_substitute_04.dump b/src/testdir/dumps/Test_incsearch_substitute_04.dump
new file mode 100644
index 0000000..bae6c7b
--- /dev/null
+++ b/src/testdir/dumps/Test_incsearch_substitute_04.dump
@@ -0,0 +1,9 @@
+|f+0&#ffffff0|o@1| |1| @64
+|f+1&&|o@1| +0&&|2| @64
+|f+0&#ffff4012|o@1| +0&#ffffff0|3| @64
+|f+0&#ffff4012|o@1| +0&#ffffff0|4| @64
+|f+0&#ffff4012|o@1| +0&#ffffff0|5| @64
+|f|o@1| |6| @64
+|f|o@1| |7| @64
+|f|o@1| |8| @64
+|:|5|,|2|s|/|f|o@1> @60
diff --git a/src/testdir/dumps/Test_incsearch_substitute_05.dump b/src/testdir/dumps/Test_incsearch_substitute_05.dump
new file mode 100644
index 0000000..6ec8ea3
--- /dev/null
+++ b/src/testdir/dumps/Test_incsearch_substitute_05.dump
@@ -0,0 +1,9 @@
+|f+0&#ffffff0|o@1| |1| @64
+|f+1&&|o|o+0&&| |2| @64
+|f+0&#ffff4012|o|o+0&#ffffff0| |3| @64
+|f|o@1| |4| @64
+|f|o@1| |5| @64
+|f|o@1| |6| @64
+|f|o@1| |7| @64
+|f|o@1| |8| @64
+|:|2|,|3|s|u|b| @1|/|f|o> @57
diff --git a/src/testdir/dumps/Test_incsearch_substitute_06.dump b/src/testdir/dumps/Test_incsearch_substitute_06.dump
new file mode 100644
index 0000000..8a66620
--- /dev/null
+++ b/src/testdir/dumps/Test_incsearch_substitute_06.dump
@@ -0,0 +1,9 @@
+|f+0&#ffffff0|o@1| |3| @64
+|f+1&&|o@1| +0&&|4| @64
+|f+0&#ffff4012|o@1| +0&#ffffff0|5| @64
+|f|o@1| |6| @64
+|f|o@1| |7| @64
+|f|o@1| |8| @64
+|:|a|b|o|v|e| |b|e|l|o|w| |b|r|o|w|s|e| |b|o|t|r| |c|o|n|f|i|r|m| |k|e@1|p|m|a|r| |k|e@1|p|a|l|t| |k|e@1|p@1|a|t| |k|e@1|p|j|u|m| |f|i|l|t|e
+|r| |x@2| |h|i|d|e| |l|o|c|k|m| |l|e|f|t|a|b|o|v|e| |n|o|a|u| |n|o|s|w|a|p| |r|i|g|h|t|b|e|l| |s|a|n|d|b|o|x| |s|i|l|e|n|t| |s|i|l|e|n|t|!
+| |$|t|a|b| |t|o|p| |u|n|s|i|l| |v|e|r|t| |v|e|r|b|o|s|e| |4|,|5|s|/|f|o|.> @32
diff --git a/src/testdir/dumps/Test_incsearch_substitute_07.dump b/src/testdir/dumps/Test_incsearch_substitute_07.dump
new file mode 100644
index 0000000..7b4dc6e
--- /dev/null
+++ b/src/testdir/dumps/Test_incsearch_substitute_07.dump
@@ -0,0 +1,9 @@
+|f+0&#ffffff0|o@1| |4| @64
+|f|o@1| |5| @64
+|f|o@1| |6| @64
+|f|o@1| |7| @64
+|f|o@1| |8| @64
+|f|o@1| |9| @64
+|f|o@1| |1|0| @63
+|b+9&&|a|r| +8&&|1@1| @63
+|:+0&&|9|,|1@1|s|/|b|a|r> @59
diff --git a/src/testdir/dumps/Test_incsearch_substitute_08.dump b/src/testdir/dumps/Test_incsearch_substitute_08.dump
new file mode 100644
index 0000000..d87e507
--- /dev/null
+++ b/src/testdir/dumps/Test_incsearch_substitute_08.dump
@@ -0,0 +1,9 @@
+|f+0&#ffffff0|o@1| |4| @64
+|f|o@1| |5| @64
+|f|o@1| |6| @64
+|f|o@1| |7| @64
+|f|o@1| |8| @64
+|f+8&&|o@1| |9| @64
+|f+0&&|o@1| |1|0| @63
+|b|a|r| |1@1| @63
+|:|9|,|1|0|s|/|b|a|r> @59
diff --git a/src/testdir/dumps/Test_incsearch_substitute_09.dump b/src/testdir/dumps/Test_incsearch_substitute_09.dump
new file mode 100644
index 0000000..633e7d8
--- /dev/null
+++ b/src/testdir/dumps/Test_incsearch_substitute_09.dump
@@ -0,0 +1,9 @@
+|f+0&#ffffff0|o@1| |3| @64
+|f+8&&|o@1| |4| @64
+|f+0&&|o@1| |5| @64
+|f|o@1| |6| @64
+|f|o@1| |7| @64
+|f|o@1| |8| @64
+|f|o@1| |9| @64
+|f|o@1| |1|0| @63
+|:|6|,|7|s|/|\|v> @61
diff --git a/src/testdir/dumps/Test_incsearch_substitute_10.dump b/src/testdir/dumps/Test_incsearch_substitute_10.dump
new file mode 100644
index 0000000..f98e046
--- /dev/null
+++ b/src/testdir/dumps/Test_incsearch_substitute_10.dump
@@ -0,0 +1,9 @@
+|f+0&#ffff4012|o@1| +0&#ffffff0|1| @64
+>f+0&#ffff4012|o@1| +0&#ffffff0|2| @64
+|f+0&#ffff4012|o@1| +0&#ffffff0|3| @64
+|f+0&#ffff4012|o@1| +0&#ffffff0|4| @64
+|f+0&#ffff4012|o@1| +0&#ffffff0|5| @64
+|f+0&#ffff4012|o@1| +0&#ffffff0|6| @64
+|f+0&#ffff4012|o@1| +0&#ffffff0|7| @64
+|f+0&#ffff4012|o@1| +0&#ffffff0|8| @64
+@52|2|,|1| @10|T|o|p|
diff --git a/src/testdir/dumps/Test_incsearch_substitute_11.dump b/src/testdir/dumps/Test_incsearch_substitute_11.dump
new file mode 100644
index 0000000..0ec409f
--- /dev/null
+++ b/src/testdir/dumps/Test_incsearch_substitute_11.dump
@@ -0,0 +1,9 @@
+|f+1&#ffffff0|o+0&#ffff4012@1| |1| +0&#ffffff0@64
+|f+0&#ffff4012|o@1| |2| +0&#ffffff0@64
+|f+0&#ffff4012|o@1| |3| +0&#ffffff0@64
+|[+3&&|N|o| |N|a|m|e|]| |[|+|]| @38|1|,|1| @11|T|o|p
+|f+0&#ffff4012|o@1| |1| +0&#ffffff0@64
+|f+0&#ffff4012|o@1| |2| +0&#ffffff0@64
+|f+0&#ffff4012|o@1| |3| +0&#ffffff0@64
+|[+1&&|N|o| |N|a|m|e|]| |[|+|]| @38|2|,|1| @11|T|o|p
+|:+0&&|%|s|/|.> @64
diff --git a/src/testdir/dumps/Test_incsearch_substitute_12.dump b/src/testdir/dumps/Test_incsearch_substitute_12.dump
new file mode 100644
index 0000000..02b7335
--- /dev/null
+++ b/src/testdir/dumps/Test_incsearch_substitute_12.dump
@@ -0,0 +1,9 @@
+|f+0&#ffffff0|o@1| |1| @64
+|f|o@1| |2| @64
+|f|o@1| |3| @64
+|[+3&&|N|o| |N|a|m|e|]| |[|+|]| @38|1|,|1| @11|T|o|p
+|f+0&&|o@1| |1| @64
+|f|o@1| |2| @64
+|f|o@1| |3| @64
+|[+1&&|N|o| |N|a|m|e|]| |[|+|]| @38|2|,|1| @11|T|o|p
+|:+0&&|%|s|/> @65
diff --git a/src/testdir/dumps/Test_incsearch_substitute_13.dump b/src/testdir/dumps/Test_incsearch_substitute_13.dump
new file mode 100644
index 0000000..be3abb7
--- /dev/null
+++ b/src/testdir/dumps/Test_incsearch_substitute_13.dump
@@ -0,0 +1,9 @@
+|f+0&#ffffff0|o@1| |1| @64
+>f|o@1| |2| @64
+|f|o@1| |3| @64
+|[+3&&|N|o| |N|a|m|e|]| |[|+|]| @38|2|,|1| @11|T|o|p
+|f+0&&|o@1| |1| @64
+|f|o@1| |2| @64
+|f|o@1| |3| @64
+|[+1&&|N|o| |N|a|m|e|]| |[|+|]| @38|2|,|1| @11|T|o|p
+| +0&&@69
diff --git a/src/testdir/dumps/Test_incsearch_vimgrep_01.dump b/src/testdir/dumps/Test_incsearch_vimgrep_01.dump
new file mode 100644
index 0000000..955d030
--- /dev/null
+++ b/src/testdir/dumps/Test_incsearch_vimgrep_01.dump
@@ -0,0 +1,9 @@
+|a+0&#ffffff0|n|o|t|h|e|r| |o+1&&|n|e+0&&| |2| @56
+|t|h|a|t| |o+0&#ffff4012|n|e+0&#ffffff0| |3| @59
+|t|h|e| |o+0&#ffff4012|n|e+0&#ffffff0| |1| @60
+|~+0#4040ff13&| @68
+|~| @68
+|~| @68
+|~| @68
+|~| @68
+|:+0#0000000&|v|i|m|g|r|e|p| |o|n> @58
diff --git a/src/testdir/dumps/Test_incsearch_vimgrep_02.dump b/src/testdir/dumps/Test_incsearch_vimgrep_02.dump
new file mode 100644
index 0000000..a5d94ea
--- /dev/null
+++ b/src/testdir/dumps/Test_incsearch_vimgrep_02.dump
@@ -0,0 +1,9 @@
+|a+0&#ffffff0|n|o|t|h|e|r| |o+1&&|n|e+0&&| |2| @56
+|t|h|a|t| |o+0&#ffff4012|n|e+0&#ffffff0| |3| @59
+|t|h|e| |o+0&#ffff4012|n|e+0&#ffffff0| |1| @60
+|~+0#4040ff13&| @68
+|~| @68
+|~| @68
+|~| @68
+|~| @68
+|:+0#0000000&|v|i|m|g| |/|o|n|/| |*|.|t|x|t> @53
diff --git a/src/testdir/dumps/Test_incsearch_vimgrep_03.dump b/src/testdir/dumps/Test_incsearch_vimgrep_03.dump
new file mode 100644
index 0000000..038ceb9
--- /dev/null
+++ b/src/testdir/dumps/Test_incsearch_vimgrep_03.dump
@@ -0,0 +1,9 @@
+|a+0&#ffffff0|n|o|t|h|e|r| |o+1&&|n|e+0&&| |2| @56
+|t|h|a|t| |o+0&#ffff4012|n|e+0&#ffffff0| |3| @59
+|t|h|e| |o+0&#ffff4012|n|e+0&#ffffff0| |1| @60
+|~+0#4040ff13&| @68
+|~| @68
+|~| @68
+|~| @68
+|~| @68
+|:+0#0000000&|v|i|m|g|r|e|p|a|d@1| |"|\|<|o|n> @52
diff --git a/src/testdir/dumps/Test_incsearch_vimgrep_04.dump b/src/testdir/dumps/Test_incsearch_vimgrep_04.dump
new file mode 100644
index 0000000..92dd78d
--- /dev/null
+++ b/src/testdir/dumps/Test_incsearch_vimgrep_04.dump
@@ -0,0 +1,9 @@
+|a+0&#ffffff0|n|o|t|h|e|r| |o|n|e| |2| @56
+|t+1&&|h|a|t+0&&| |o|n|e| |3| @59
+|t|h|e| |o|n|e| |1| @60
+|~+0#4040ff13&| @68
+|~| @68
+|~| @68
+|~| @68
+|~| @68
+|:+0#0000000&|l|v| |"|t|h|a> @61
diff --git a/src/testdir/dumps/Test_incsearch_vimgrep_05.dump b/src/testdir/dumps/Test_incsearch_vimgrep_05.dump
new file mode 100644
index 0000000..e11ff57
--- /dev/null
+++ b/src/testdir/dumps/Test_incsearch_vimgrep_05.dump
@@ -0,0 +1,9 @@
+|a+0&#ffffff0|n|o|t+1&&|h|e|r+0&&| |o|n|e| |2| @56
+|t|h|a|t| |o|n|e| |3| @59
+|t+0&#ffff4012|h|e| +0&#ffffff0|o|n|e| |1| @60
+|~+0#4040ff13&| @68
+|~| @68
+|~| @68
+|~| @68
+|~| @68
+|:+0#0000000&|l|v|i|m|g|r|e|p|a| |"|t|h|e|"| |*@1|/|*|.|t|x|t> @44
diff --git a/src/testdir/dumps/Test_popup_and_previewwindow_01.dump b/src/testdir/dumps/Test_popup_and_previewwindow_01.dump
new file mode 100644
index 0000000..71ff399
--- /dev/null
+++ b/src/testdir/dumps/Test_popup_and_previewwindow_01.dump
@@ -0,0 +1,20 @@
+|a+0&#ffffff0|b|0| @71
+|a|b|1| @71
+|a|b|2| @71
+|a|b|3| @71
+|a|b|4| @71
+|a|b|5| @71
+|a|b|6| @71
+|a|b|7| @71
+|a|b|8| @71
+|a+0#0000001#e0e0e08|b|0| @11| +0#0000000#0000001|e+1&#ffffff0|w|]|[|+|]| @34|1|,|1| @11|T|o|p
+|a+0#0000001#ffd7ff255|b|1| @11| +0#0000000#0000001| +0&#ffffff0@58
+|a+0#0000001#ffd7ff255|b|2| @11| +0#0000000#0000001| +0&#ffffff0@58
+|a+0#0000001#ffd7ff255|b|3| @11| +0#0000000#0000001| +0&#ffffff0@58
+|a+0#0000001#ffd7ff255|b|4| @11| +0#0000000#a8a8a8255| +0&#ffffff0@58
+|a+0#0000001#ffd7ff255|b|5| @11| +0#0000000#a8a8a8255| +0&#ffffff0@58
+|a+0#0000001#ffd7ff255|b|6| @11| +0#0000000#a8a8a8255| +0&#ffffff0@58
+|a|b|0> @71
+|~+0#4040ff13&| @73
+|[+3#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|1|0|,|1| @10|B|o|t
+|-+2&&@1| |K|e|y|w|o|r|d| |L|o|c|a|l| |c|o|m|p|l|e|t|i|o|n| |(|^|N|^|P|)| |m+0#00e0003&|a|t|c|h| |1| |o|f| |1|0| +0#0000000&@26
diff --git a/src/testdir/dumps/Test_popup_command_01.dump b/src/testdir/dumps/Test_popup_command_01.dump
new file mode 100644
index 0000000..8d0cd9c
--- /dev/null
+++ b/src/testdir/dumps/Test_popup_command_01.dump
@@ -0,0 +1,20 @@
+|o+0&#ffffff0|n|e| |t|w|o| |t|h|r|e@1| |f|o|u|r| |f|i|v|e| @51
+|a|n|d| |o|n|e| |t|w|o| >X|t|h|r|e@1| |f|o|u|r| |f|i|v|e| @46
+|o|n|e| |m|o|r|e| |t|w| +0#0000001#ffd7ff255|U|n|d|o| @12| +0#0000000#ffffff0@45
+|~+0#4040ff13&| @9| +0#0000001#ffd7ff255@17| +0#4040ff13#ffffff0@45
+|~| @9| +0#0000001#ffd7ff255|P|a|s|t|e| @11| +0#4040ff13#ffffff0@45
+|~| @9| +0#0000001#ffd7ff255@17| +0#4040ff13#ffffff0@45
+|~| @9| +0#0000001#ffd7ff255|S|e|l|e|c|t| |W|o|r|d| @5| +0#4040ff13#ffffff0@45
+|~| @9| +0#0000001#ffd7ff255|S|e|l|e|c|t| |S|e|n|t|e|n|c|e| @1| +0#4040ff13#ffffff0@45
+|~| @9| +0#0000001#ffd7ff255|S|e|l|e|c|t| |P|a|r|a|g|r|a|p|h| | +0#4040ff13#ffffff0@45
+|~| @9| +0#0000001#ffd7ff255|S|e|l|e|c|t| |L|i|n|e| @5| +0#4040ff13#ffffff0@45
+|~| @9| +0#0000001#ffd7ff255|S|e|l|e|c|t| |B|l|o|c|k| @4| +0#4040ff13#ffffff0@45
+|~| @9| +0#0000001#ffd7ff255|S|e|l|e|c|t| |A|l@1| @6| +0#4040ff13#ffffff0@45
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|:+0#0000000&|p|o|p|u|p| |P|o|p|U|p| @62
diff --git a/src/testdir/dumps/Test_popup_command_02.dump b/src/testdir/dumps/Test_popup_command_02.dump
new file mode 100644
index 0000000..e33ea4d
--- /dev/null
+++ b/src/testdir/dumps/Test_popup_command_02.dump
@@ -0,0 +1,20 @@
+|o+0&#ffffff0|n|e| |t|w|o| |t|h|r|e@1| |f|o|u|r| |f|i|v|e| @51
+|a|n|d| |o|n|e| |t|w|o| >X|t|h|r|e@1| |f|o|u|r| |f|i|v|e| @46
+|o|n|e| |m|o|r|e| |t|w| +0#0000001#ffd7ff255|U|n|d|o| @12| +0#0000000#ffffff0@45
+|~+0#4040ff13&| @9| +0#0000001#ffd7ff255@17| +0#4040ff13#ffffff0@45
+|~| @9| +0#0000001#e0e0e08|P|a|s|t|e| @11| +0#4040ff13#ffffff0@45
+|~| @9| +0#0000001#ffd7ff255@17| +0#4040ff13#ffffff0@45
+|~| @9| +0#0000001#ffd7ff255|S|e|l|e|c|t| |W|o|r|d| @5| +0#4040ff13#ffffff0@45
+|~| @9| +0#0000001#ffd7ff255|S|e|l|e|c|t| |S|e|n|t|e|n|c|e| @1| +0#4040ff13#ffffff0@45
+|~| @9| +0#0000001#ffd7ff255|S|e|l|e|c|t| |P|a|r|a|g|r|a|p|h| | +0#4040ff13#ffffff0@45
+|~| @9| +0#0000001#ffd7ff255|S|e|l|e|c|t| |L|i|n|e| @5| +0#4040ff13#ffffff0@45
+|~| @9| +0#0000001#ffd7ff255|S|e|l|e|c|t| |B|l|o|c|k| @4| +0#4040ff13#ffffff0@45
+|~| @9| +0#0000001#ffd7ff255|S|e|l|e|c|t| |A|l@1| @6| +0#4040ff13#ffffff0@45
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|:+0#0000000&|p|o|p|u|p| |P|o|p|U|p| @62
diff --git a/src/testdir/dumps/Test_popup_command_03.dump b/src/testdir/dumps/Test_popup_command_03.dump
new file mode 100644
index 0000000..fa2ac70
--- /dev/null
+++ b/src/testdir/dumps/Test_popup_command_03.dump
@@ -0,0 +1,20 @@
+|o+0&#ffffff0|n|e| |t|w|o| |t|h|r|e@1| |f|o|u|r| |f|i|v|e| @51
+|a|n|d| |o|n|e| |t|w|o| |X+0&#e0e0e08|t|h|r|e@1> +0&#ffffff0|f|o|u|r| |f|i|v|e| @46
+|o|n|e| |m|o|r|e| |t|w|o| |t|h|r|e@1| |f|o|u|r| |f|i|v|e| @46
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|-+2#0000000&@1| |V|I|S|U|A|L| |-@1| +0&&@34|7| @8|2|,|1|9| @9|A|l@1|
diff --git a/src/testdir/dumps/Test_popup_position_01.dump b/src/testdir/dumps/Test_popup_position_01.dump
new file mode 100644
index 0000000..43900fb
--- /dev/null
+++ b/src/testdir/dumps/Test_popup_position_01.dump
@@ -0,0 +1,8 @@
+|1+0&#ffffff0|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7|8|9|_|a| @5||+1&&|1+0&&|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7|8|9|_|a| @5
+|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7|8|9|_|b| @5||+1&&|1+0&&|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7|8|9|_|b| @5
+@12|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5||+1&&| +0&&@11|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5
+|6|7|8|9|_|a> @30||+1&&|6+0&&|7|8|9|_|a| @30
+|~+0#4040ff13&| @9| +0#0000001#e0e0e08|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7|8|9|_|a| | +0#4040ff13#ffffff0@30
+|~| @9| +0#0000001#ffd7ff255|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7|8|9|_|b| | +0#4040ff13#ffffff0@30
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
diff --git a/src/testdir/dumps/Test_popup_position_02.dump b/src/testdir/dumps/Test_popup_position_02.dump
new file mode 100644
index 0000000..c3613c3
--- /dev/null
+++ b/src/testdir/dumps/Test_popup_position_02.dump
@@ -0,0 +1,8 @@
+|1+0&#ffffff0|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7|8|9|_|a| @5||+1&&|1+0&&|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7|8|9|_|a| @5
+|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7|8|9|_|b| @5||+1&&|1+0&&|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7|8|9|_|b| @5
+@12|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5||+1&&| +0&&@11|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5
+|6|7|8|9|_|a| @30||+1&&|6+0&&|7|8|9|_|a> @30
+|~+0#4040ff13&| @35||+1#0000000&|~+0#4040ff13&| @9| +0#0000001#e0e0e08|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5
+|~+0#4040ff13#ffffff0| @35||+1#0000000&|~+0#4040ff13&| @9| +0#0000001#ffd7ff255|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5
+|~+0#4040ff13#ffffff0| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
diff --git a/src/testdir/dumps/Test_popup_position_03.dump b/src/testdir/dumps/Test_popup_position_03.dump
new file mode 100644
index 0000000..650cb7f
--- /dev/null
+++ b/src/testdir/dumps/Test_popup_position_03.dump
@@ -0,0 +1,8 @@
+|1+0&#ffffff0|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7|8|9|_|a| @5||+1&&|1+0&&|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7|8|9|_|a| @5
+|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7|8|9|_|b| @5||+1&&|1+0&&|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7|8|9|_|b| @5
+@12|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5||+1&&| +0&&@11|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5
+|6|7|8|9|_|a| @30||+1&&|6+0&&|7|8|9|_|a> @30
+|~+0#4040ff13&| @35||+1#0000000&|~+0#4040ff13&| @4| +0#0000001#e0e0e08|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7|8|9|_
+|~+0#4040ff13#ffffff0| @35||+1#0000000&|~+0#4040ff13&| @4| +0#0000001#ffd7ff255|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7|8|9|_
+|~+0#4040ff13#ffffff0| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
diff --git a/src/testdir/dumps/Test_popup_position_04.dump b/src/testdir/dumps/Test_popup_position_04.dump
new file mode 100644
index 0000000..1793b23
--- /dev/null
+++ b/src/testdir/dumps/Test_popup_position_04.dump
@@ -0,0 +1,10 @@
+|1+0&#ffffff0|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7||+1&&|1+0&&|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7
+|8|9|_|a| @32||+1&&|8+0&&|9|_|a| @32
+|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7||+1&&|1+0&&|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7
+|8|9|_|b| @32||+1&&|8+0&&|9|_|b| @32
+@12|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5||+1&&| +0&&@11|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5
+|6|7|8|9|_|1|2|3|4|5|6|7|8|9|_|a| @20||+1&&|6+0&&|7|8|9|_|1|2|3|4|5|6|7|8|9|_|a> @20
+|~+0#4040ff13&| @35||+1#0000000&|~+0#4040ff13&| @9| +0#0000001#e0e0e08|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5
+|~+0#4040ff13#ffffff0| @35||+1#0000000&|~+0#4040ff13&| @9| +0#0000001#ffd7ff255|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5
+|~+0#4040ff13#ffffff0| @35||+1#0000000&|~+0#4040ff13&| @35
+|~| @35||+1#0000000&|~+0#4040ff13&| @35
diff --git a/src/testdir/dumps/Test_syntax_c_01.dump b/src/testdir/dumps/Test_syntax_c_01.dump
new file mode 100644
index 0000000..2fea5d6
--- /dev/null
+++ b/src/testdir/dumps/Test_syntax_c_01.dump
@@ -0,0 +1,20 @@
+>/+0#0000e05#ffffff0|*| |c|o|m@1|e|n|t| |l|i|n|e| |a|t| |t|h|e| |t|o|p| |*|/| +0#0000000&@45
+@2|i+0#00e0003&|n|t| +0#0000000&@69
+|m|a|i|n|(|i+0#00e0003&|n|t| +0#0000000&|a|r|g|c|,| |c+0#00e0003&|h|a|r| +0#0000000&|*@1|a|r|g|v|)|/+0#0000e05&@1| |a|n|o|t|h|e|r| |c|o|m@1|e|n|t| +0#0000000&@29
+|{| @73
+|#+0#e000e06&|i|f| |0| +0#0000000&@69
+| +0#0000e05&@2|i|n|t| @2|n|o|t|_|u|s|e|d|;| +0#0000000&@56
+|#+0#e000e06&|e|l|s|e| +0#0000000&@69
+@3|i+0#00e0003&|n|t| +0#0000000&@2|u|s|e|d|;| @60
+|#+0#e000e06&|e|n|d|i|f| +0#0000000&@68
+@3|p|r|i|n|t|f|(|"+0#e000002&|J|u|s|t| |a|n| |e|x|a|m|p|l|e| |p|i|e|c|e| |o|f| |C| |c|o|d|e|\+0#e000e06&|n|"+0#e000002&|)+0#0000000&|;| @27
+@3|r+0#af5f00255&|e|t|u|r|n| +0#0000000&|0+0#e000002&|x|0|f@1|;+0#0000000&| @58
+|}| @73
+@3|s+0#00e0003&|t|a|t|i|c| +0#0000000&|v+0#00e0003&|o|i|d| +0#0000000&@60
+|m|y|F|u|n|c|t|i|o|n|(|c+0#00e0003&|o|n|s|t| +0#0000000&|d+0#00e0003&|o|u|b|l|e| +0#0000000&|c|o|u|n|t|,| |s+0#00e0003&|t|r|u|c|t| +0#0000000&|n|o|t|h|i|n|g|,| |l+0#00e0003&|o|n|g| +0#0000000&|t|h|e|r|e|)| |{| @14
+@2|/+0#0000e05&@1| |1+0#e000002&|2|3|:+0#0000e05&| |n|o|t|h|i|n|g| |t|o| |r|e|a|d| |h|e|r|e| +0#0000000&@44
+@2|f+0#af5f00255&|o|r| +0#0000000&|(|i+0#00e0003&|n|t| +0#0000000&|i| |=| |0+0#e000002&|;+0#0000000&| |i| |<| |c|o|u|n|t|;| |+@1|i|)| |{| @39
+@4|b+0#af5f00255&|r|e|a|k|;+0#0000000&| @64
+@2|}| @71
+|}| @73
+|"|X|t|e|s|t|.|c|"| |1|9|L|,| |3|6|4|C| @37|1|,|1| @10|A|l@1|
diff --git a/src/testdir/dumps/Test_tenc_euc_jp_01.dump b/src/testdir/dumps/Test_tenc_euc_jp_01.dump
new file mode 100644
index 0000000..14a4313
--- /dev/null
+++ b/src/testdir/dumps/Test_tenc_euc_jp_01.dump
@@ -0,0 +1,10 @@
+>E+0&#ffffff0|8|9|:| |ãƒ*&|ッ|フ|ã‚¡| +&|%|l|d| |ã®*&|変|æ›´|ã¯|ä¿|å­˜|ã•|ã‚Œ|ã¦|ã„|ã¾|ã›|ã‚“| +&|(|!| |ã§*&|変|æ›´|ã‚’|ç ´|棄|)+&| @13
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|X+3#0000000&|e|u|c|_|j|p|.|t|x|t| @45|1|,|1| @11|A|l@1
+|E+0&&|8|3|:| |ãƒ*&|ッ|フ|ã‚¡|ã‚’|作|æˆ|ã§|ã|ãª|ã„|ã®|ã§|ã€|ä»–|ã®|ã‚’|使|用|ã—|ã¾|ã™|.+&@2| @22
+|~+0#4040ff13&| @73
+|~| @73
+|[+1#0000000&|N|o| |N|a|m|e|]| |[|+|]| @43|1|,|5|2| @10|A|l@1
+| +0&&@74
diff --git a/src/testdir/dumps/Test_textprop_01.dump b/src/testdir/dumps/Test_textprop_01.dump
new file mode 100644
index 0000000..8687a0a
--- /dev/null
+++ b/src/testdir/dumps/Test_textprop_01.dump
@@ -0,0 +1,6 @@
+| +0#af5f00255#ffffff0@1|1| |O+0#0000000&|n|e| +0&#ffff4012|t|w|o| +0&#ffffff0@63
+| +0#af5f00255&@1|2| |N+0#0000000#ffff4012|u|m|b|é|r| |1+0#4040ff13&|2|3| +0#0000000&|ä|n|d| |t|h|œ|n| |4+0#4040ff13&|¾|7|.+0#0000000&| +0&#ffffff0@46
+| +0#af5f00255&@1|3| >-+0#0000000#ffff4012|x+0&#ffffff0|a+0#4040ff13&@1|x+0#0000000&|-@1|x+0#4040ff13&|b@1|x+0#0000000&|-@1|x|c+0#4040ff13&@1|x|-+0#0000000&@1|x+0#4040ff13&|d@1|x|-+0#0000000&@1| @45
+|~+0#4040ff13&| @73
+|~| @73
+| +0#0000000&@56|3|,|1| @10|A|l@1|
diff --git a/src/testdir/gen_opt_test.vim b/src/testdir/gen_opt_test.vim
new file mode 100644
index 0000000..8c75d37
--- /dev/null
+++ b/src/testdir/gen_opt_test.vim
@@ -0,0 +1,226 @@
+" Script to generate testdir/opt_test.vim from option.c
+
+set cpo=&vim
+
+" Only do this when build with the +eval feature.
+if 1
+
+set nomore
+
+" The terminal size is restored at the end.
+" Clear out t_WS, we don't want to resize the actual terminal.
+let script = [
+ \ 'let save_columns = &columns',
+ \ 'let save_lines = &lines',
+ \ 'let save_term = &term',
+ \ 'set t_WS=',
+ \ ]
+
+/#define p_term
+let end = line('.')
+
+" font name that works everywhere (hopefully)
+let fontname = has('win32') ? 'fixedsys' : 'fixed'
+
+" Two lists with values: values that work and values that fail.
+" When not listed, "othernum" or "otherstring" is used.
+let test_values = {
+ \ 'cmdheight': [[1, 2, 10], [-1, 0]],
+ \ 'cmdwinheight': [[1, 2, 10], [-1, 0]],
+ \ 'columns': [[12, 80], [-1, 0, 10]],
+ \ 'conceallevel': [[0, 1, 2, 3], [-1, 4, 99]],
+ \ 'foldcolumn': [[0, 1, 4, 12], [-1, 13, 999]],
+ \ 'helpheight': [[0, 10, 100], [-1]],
+ \ 'history': [[0, 1, 100], [-1, 10001]],
+ \ 'iminsert': [[0, 1], [-1, 3, 999]],
+ \ 'imsearch': [[-1, 0, 1], [-2, 3, 999]],
+ \ 'imstyle': [[0, 1], [-1, 2, 999]],
+ \ 'lines': [[2, 24], [-1, 0, 1]],
+ \ 'linespace': [[0, 2, 4], ['']],
+ \ 'numberwidth': [[1, 4, 8, 10], [-1, 0, 11]],
+ \ 'regexpengine': [[0, 1, 2], [-1, 3, 999]],
+ \ 'report': [[0, 1, 2, 9999], [-1]],
+ \ 'scroll': [[0, 1, 2, 20], [-1]],
+ \ 'scrolljump': [[-50, -1, 0, 1, 2, 20], [999]],
+ \ 'scrolloff': [[0, 1, 2, 20], [-1]],
+ \ 'shiftwidth': [[0, 1, 8, 999], [-1]],
+ \ 'sidescroll': [[0, 1, 8, 999], [-1]],
+ \ 'sidescrolloff': [[0, 1, 8, 999], [-1]],
+ \ 'tabstop': [[1, 4, 8, 12], [-1, 0]],
+ \ 'textwidth': [[0, 1, 8, 99], [-1]],
+ \ 'timeoutlen': [[0, 8, 99999], [-1]],
+ \ 'titlelen': [[0, 1, 8, 9999], [-1]],
+ \ 'updatecount': [[0, 1, 8, 9999], [-1]],
+ \ 'updatetime': [[0, 1, 8, 9999], [-1]],
+ \ 'verbose': [[-1, 0, 1, 8, 9999], []],
+ \ 'wildcharm': [[-1, 0, 100], []],
+ \ 'winheight': [[1, 10, 999], [-1, 0]],
+ \ 'winminheight': [[0, 1], [-1]],
+ \ 'winminwidth': [[0, 1, 10], [-1]],
+ \ 'winwidth': [[1, 10, 999], [-1, 0]],
+ \
+ \ 'ambiwidth': [['', 'single'], ['xxx']],
+ \ 'background': [['', 'light', 'dark'], ['xxx']],
+ \ 'backspace': [[0, 2, '', 'eol', 'eol,start'], ['xxx']],
+ \ 'backupcopy': [['yes', 'auto'], ['', 'xxx', 'yes,no']],
+ \ 'backupext': [['xxx'], ['']],
+ \ 'belloff': [['', 'all', 'copy,error'], ['xxx']],
+ \ 'breakindentopt': [['', 'min:3', 'sbr'], ['xxx', 'min', 'min:x']],
+ \ 'browsedir': [['', 'last', '/'], ['xxx']],
+ \ 'bufhidden': [['', 'hide', 'wipe'], ['xxx', 'hide,wipe']],
+ \ 'buftype': [['', 'help', 'nofile'], ['xxx', 'help,nofile']],
+ \ 'casemap': [['', 'internal'], ['xxx']],
+ \ 'cedit': [['', '\<Esc>'], ['xxx', 'f']],
+ \ 'clipboard': [['', 'unnamed', 'autoselect,unnamed'], ['xxx']],
+ \ 'colorcolumn': [['', '8', '+2'], ['xxx']],
+ \ 'comments': [['', 'b:#'], ['xxx']],
+ \ 'commentstring': [['', '/*%s*/'], ['xxx']],
+ \ 'complete': [['', 'w,b'], ['xxx']],
+ \ 'concealcursor': [['', 'n', 'nvic'], ['xxx']],
+ \ 'completeopt': [['', 'menu', 'menu,longest'], ['xxx', 'menu,,,longest,']],
+ \ 'cryptmethod': [['', 'zip'], ['xxx']],
+ \ 'cscopequickfix': [['', 's-', 's-,c+,e0'], ['xxx', 's,g,d']],
+ \ 'debug': [['', 'msg', 'msg', 'beep'], ['xxx']],
+ \ 'diffopt': [['', 'filler', 'icase,iwhite'], ['xxx', 'algorithm:xxx', 'algorithm:']],
+ \ 'display': [['', 'lastline', 'lastline,uhex'], ['xxx']],
+ \ 'eadirection': [['', 'both', 'ver'], ['xxx', 'ver,hor']],
+ \ 'encoding': [['latin1'], ['xxx', '']],
+ \ 'eventignore': [['', 'WinEnter', 'WinLeave,winenter'], ['xxx']],
+ \ 'fileencoding': [['', 'latin1', 'xxx'], []],
+ \ 'fileformat': [['', 'dos', 'unix'], ['xxx']],
+ \ 'fileformats': [['', 'dos', 'dos,unix'], ['xxx']],
+ \ 'fillchars': [['', 'vert:x'], ['xxx']],
+ \ 'foldclose': [['', 'all'], ['xxx']],
+ \ 'foldmethod': [['manual', 'indent'], ['', 'xxx', 'expr,diff']],
+ \ 'foldopen': [['', 'all', 'hor,jump'], ['xxx']],
+ \ 'foldmarker': [['((,))'], ['', 'xxx']],
+ \ 'formatoptions': [['', 'vt', 'v,t'], ['xxx']],
+ \ 'guicursor': [['', 'n:block-Cursor'], ['xxx']],
+ \ 'guifont': [['', fontname], []],
+ \ 'guifontwide': [['', fontname], []],
+ \ 'guifontset': [['', fontname], []],
+ \ 'helplang': [['', 'de', 'de,it'], ['xxx']],
+ \ 'highlight': [['', 'e:Error'], ['xxx']],
+ \ 'imactivatekey': [['', 'S-space'], ['xxx']],
+ \ 'isfname': [['', '@', '@,48-52'], ['xxx', '@48']],
+ \ 'isident': [['', '@', '@,48-52'], ['xxx', '@48']],
+ \ 'iskeyword': [['', '@', '@,48-52'], ['xxx', '@48']],
+ \ 'isprint': [['', '@', '@,48-52'], ['xxx', '@48']],
+ \ 'keymap': [['', 'accents'], ['xxx']],
+ \ 'keymodel': [['', 'startsel', 'startsel,stopsel'], ['xxx']],
+ \ 'langmap': [['', 'xX', 'aA,bB'], ['xxx']],
+ \ 'listchars': [['', 'eol:x', 'eol:x,space:y'], ['xxx']],
+ \ 'matchpairs': [['', '(:)', '(:),<:>'], ['xxx']],
+ \ 'mkspellmem': [['10000,100,12'], ['', 'xxx']],
+ \ 'mouse': [['', 'a', 'nvi'], ['xxx', 'n,v,i']],
+ \ 'mousemodel': [['', 'popup'], ['xxx']],
+ \ 'mouseshape': [['', 'n:arrow'], ['xxx']],
+ \ 'nrformats': [['', 'alpha', 'alpha,hex,bin'], ['xxx']],
+ \ 'printmbfont': [['', 'r:some', 'b:Bold,c:yes'], ['xxx']],
+ \ 'printoptions': [['', 'header:0', 'left:10pc,top:5pc'], ['xxx']],
+ \ 'scrollopt': [['', 'ver', 'ver,hor'], ['xxx']],
+ \ 'renderoptions': [['', 'type:directx'], ['xxx']],
+ \ 'selection': [['old', 'inclusive'], ['', 'xxx']],
+ \ 'selectmode': [['', 'mouse', 'key,cmd'], ['xxx']],
+ \ 'sessionoptions': [['', 'blank', 'help,options,slash'], ['xxx']],
+ \ 'signcolumn': [['', 'auto', 'no'], ['xxx', 'no,yes']],
+ \ 'spellfile': [['', 'file.en.add'], ['xxx', '/tmp/file']],
+ \ 'spellsuggest': [['', 'best', 'double,33'], ['xxx']],
+ \ 'switchbuf': [['', 'useopen', 'split,newtab'], ['xxx']],
+ \ 'tagcase': [['smart', 'match'], ['', 'xxx', 'smart,match']],
+ \ 'term': [[], []],
+ \ 'termguicolors': [[], []],
+ \ 'termencoding': [has('gui_gtk') ? [] : ['', 'utf-8'], ['xxx']],
+ \ 'termmode': [['', 'winpty', 'conpty'], ['xxx']],
+ \ 'termwinsize': [['', '24x80', '0x80', '32x0', '0x0'], ['xxx', '80', '8ax9', '24x80b']],
+ \ 'toolbar': [['', 'icons', 'text'], ['xxx']],
+ \ 'toolbariconsize': [['', 'tiny', 'huge'], ['xxx']],
+ \ 'ttymouse': [['', 'xterm'], ['xxx']],
+ \ 'ttytype': [[], []],
+ \ 'varsofttabstop': [['8', '4,8,16,32'], ['xxx', '-1', '4,-1,20']],
+ \ 'vartabstop': [['8', '4,8,16,32'], ['xxx', '-1', '4,-1,20']],
+ \ 'viewoptions': [['', 'cursor', 'unix,slash'], ['xxx']],
+ \ 'viminfo': [['', '''50', '"30'], ['xxx']],
+ \ 'virtualedit': [['', 'all', 'all,block'], ['xxx']],
+ \ 'whichwrap': [['', 'b,s', 'bs'], ['xxx']],
+ \ 'wildmode': [['', 'full', 'list:full', 'full,longest'], ['xxx']],
+ \ 'wildoptions': [['', 'tagfile'], ['xxx']],
+ \ 'winaltkeys': [['menu', 'no'], ['', 'xxx']],
+ \
+ \ 'luadll': [[], []],
+ \ 'perldll': [[], []],
+ \ 'pythondll': [[], []],
+ \ 'pythonthreedll': [[], []],
+ \ 'pyxversion': [[], []],
+ \ 'rubydll': [[], []],
+ \ 'tcldll': [[], []],
+ \
+ \ 'othernum': [[-1, 0, 100], ['']],
+ \ 'otherstring': [['', 'xxx'], []],
+ \}
+
+1
+/struct vimoption options
+while 1
+ /{"
+ if line('.') > end
+ break
+ endif
+ let line = getline('.')
+ let name = substitute(line, '.*{"\([^"]*\)".*', '\1', '')
+ let shortname = substitute(line, '.*"\([^"]*\)".*', '\1', '')
+
+ if has_key(test_values, name)
+ let a = test_values[name]
+ elseif line =~ 'P_NUM'
+ let a = test_values['othernum']
+ else
+ let a = test_values['otherstring']
+ endif
+ if len(a[0]) > 0 || len(a[1]) > 0
+ if line =~ 'P_BOOL'
+ call add(script, 'set ' . name)
+ call add(script, 'set ' . shortname)
+ call add(script, 'set no' . name)
+ call add(script, 'set no' . shortname)
+ else
+ for val in a[0]
+ call add(script, 'set ' . name . '=' . val)
+ call add(script, 'set ' . shortname . '=' . val)
+ endfor
+
+ " setting an option can only fail when it's implemented.
+ call add(script, "if exists('+" . name . "')")
+ for val in a[1]
+ call add(script, "call assert_fails('set " . name . "=" . val . "')")
+ call add(script, "call assert_fails('set " . shortname . "=" . val . "')")
+ endfor
+ call add(script, "endif")
+ endif
+
+ " cannot change 'termencoding' in GTK
+ if name != 'termencoding' || !has('gui_gtk')
+ call add(script, 'set ' . name . '&')
+ call add(script, 'set ' . shortname . '&')
+ endif
+ if name == 'verbosefile'
+ call add(script, 'call delete("xxx")')
+ endif
+
+ if name == 'more'
+ call add(script, 'set nomore')
+ elseif name == 'lines'
+ call add(script, 'let &lines = save_lines')
+ endif
+ endif
+endwhile
+
+call add(script, 'let &term = save_term')
+call add(script, 'let &columns = save_columns')
+call add(script, 'let &lines = save_lines')
+
+call writefile(script, 'opt_test.vim')
+
+endif
+
+qa!
diff --git a/src/testdir/gui_init.vim b/src/testdir/gui_init.vim
new file mode 100644
index 0000000..42b2bca
--- /dev/null
+++ b/src/testdir/gui_init.vim
@@ -0,0 +1,6 @@
+" gvimrc for test_gui_init.vim
+
+if has('gui_athena') || has('gui_motif') || has('gui_gtk2') || has('gui_gtk3')
+ set guiheadroom=0
+ set guioptions+=p
+endif
diff --git a/src/testdir/gui_preinit.vim b/src/testdir/gui_preinit.vim
new file mode 100644
index 0000000..c351b72
--- /dev/null
+++ b/src/testdir/gui_preinit.vim
@@ -0,0 +1,7 @@
+" vimrc for test_gui_init.vim
+
+" Note that this flag must be added in the .vimrc file, before switching on
+" syntax or filetype recognition (when the |gvimrc| file is sourced the system
+" menu has already been loaded; the ":syntax on" and ":filetype on" commands
+" load the menu too).
+set guioptions+=M
diff --git a/src/testdir/if_ver-1.vim b/src/testdir/if_ver-1.vim
new file mode 100644
index 0000000..3c94c9e
--- /dev/null
+++ b/src/testdir/if_ver-1.vim
@@ -0,0 +1,26 @@
+" Print all interface versions and write the result into if_ver.txt.
+" For Ubuntu. Part 1.
+
+redir! > if_ver.txt
+if 1
+ echo "*** Interface versions ***"
+ echo "\nLua:"
+ lua print(_VERSION)
+ " echo "\nLuaJIT:"
+ " lua print(jit.version)
+ if has('mzscheme')
+ echo "\nMzScheme:"
+ mzscheme (display (version))
+ endif
+ echo "\nPerl:"
+ perl print $^V
+ echo "\nRuby:"
+ ruby print RUBY_VERSION
+ if has('tcl')
+ echo "\nTcl:"
+ tcl puts [info patchlevel]
+ endif
+ echo "\nPython 2:"
+ python import sys; print sys.version
+endif
+redir END
diff --git a/src/testdir/if_ver-2.vim b/src/testdir/if_ver-2.vim
new file mode 100644
index 0000000..a6fedb5
--- /dev/null
+++ b/src/testdir/if_ver-2.vim
@@ -0,0 +1,10 @@
+" Print py3 interface version and write the result into if_ver.txt.
+" For Ubuntu. Part 2.
+
+redir! >> if_ver.txt
+if 1
+ echo "\nPython 3:"
+ python3 import sys; print(sys.version)
+ echo "\n"
+endif
+redir END
diff --git a/src/testdir/lsan-suppress.txt b/src/testdir/lsan-suppress.txt
new file mode 100644
index 0000000..5166fbf
--- /dev/null
+++ b/src/testdir/lsan-suppress.txt
@@ -0,0 +1,3 @@
+# Suppress leaks from X libraries on Ubuntu trusty.
+leak:libX11.so.6
+leak:libXt.so.6
diff --git a/src/testdir/python2/module.py b/src/testdir/python2/module.py
new file mode 100644
index 0000000..e90106a
--- /dev/null
+++ b/src/testdir/python2/module.py
@@ -0,0 +1,2 @@
+import before_1
+dir = '2'
diff --git a/src/testdir/python3/module.py b/src/testdir/python3/module.py
new file mode 100644
index 0000000..24bd036
--- /dev/null
+++ b/src/testdir/python3/module.py
@@ -0,0 +1,2 @@
+import before_1
+dir = '3'
diff --git a/src/testdir/python_after/after.py b/src/testdir/python_after/after.py
new file mode 100644
index 0000000..5cf8fa4
--- /dev/null
+++ b/src/testdir/python_after/after.py
@@ -0,0 +1,2 @@
+import before_2
+dir = "after"
diff --git a/src/testdir/python_before/before.py b/src/testdir/python_before/before.py
new file mode 100644
index 0000000..531e81a
--- /dev/null
+++ b/src/testdir/python_before/before.py
@@ -0,0 +1 @@
+dir = "before"
diff --git a/src/testdir/python_before/before_1.py b/src/testdir/python_before/before_1.py
new file mode 100644
index 0000000..fa81ada
--- /dev/null
+++ b/src/testdir/python_before/before_1.py
@@ -0,0 +1 @@
+# empty file
diff --git a/src/testdir/python_before/before_2.py b/src/testdir/python_before/before_2.py
new file mode 100644
index 0000000..fa81ada
--- /dev/null
+++ b/src/testdir/python_before/before_2.py
@@ -0,0 +1 @@
+# empty file
diff --git a/src/testdir/pythonx/failing.py b/src/testdir/pythonx/failing.py
new file mode 100644
index 0000000..30e73a0
--- /dev/null
+++ b/src/testdir/pythonx/failing.py
@@ -0,0 +1 @@
+raise NotImplementedError
diff --git a/src/testdir/pythonx/failing_import.py b/src/testdir/pythonx/failing_import.py
new file mode 100644
index 0000000..511cae7
--- /dev/null
+++ b/src/testdir/pythonx/failing_import.py
@@ -0,0 +1 @@
+raise ImportError
diff --git a/src/testdir/pythonx/module.py b/src/testdir/pythonx/module.py
new file mode 100644
index 0000000..6bf5a64
--- /dev/null
+++ b/src/testdir/pythonx/module.py
@@ -0,0 +1 @@
+dir = 'x'
diff --git a/src/testdir/pythonx/modulex.py b/src/testdir/pythonx/modulex.py
new file mode 100644
index 0000000..ec6a706
--- /dev/null
+++ b/src/testdir/pythonx/modulex.py
@@ -0,0 +1 @@
+ddir = 'xx'
diff --git a/src/testdir/pythonx/topmodule/__init__.py b/src/testdir/pythonx/topmodule/__init__.py
new file mode 100644
index 0000000..792d600
--- /dev/null
+++ b/src/testdir/pythonx/topmodule/__init__.py
@@ -0,0 +1 @@
+#
diff --git a/src/testdir/pythonx/topmodule/submodule/__init__.py b/src/testdir/pythonx/topmodule/submodule/__init__.py
new file mode 100644
index 0000000..792d600
--- /dev/null
+++ b/src/testdir/pythonx/topmodule/submodule/__init__.py
@@ -0,0 +1 @@
+#
diff --git a/src/testdir/pythonx/topmodule/submodule/subsubmodule/__init__.py b/src/testdir/pythonx/topmodule/submodule/subsubmodule/__init__.py
new file mode 100644
index 0000000..792d600
--- /dev/null
+++ b/src/testdir/pythonx/topmodule/submodule/subsubmodule/__init__.py
@@ -0,0 +1 @@
+#
diff --git a/src/testdir/pythonx/topmodule/submodule/subsubmodule/subsubsubmodule.py b/src/testdir/pythonx/topmodule/submodule/subsubmodule/subsubsubmodule.py
new file mode 100644
index 0000000..792d600
--- /dev/null
+++ b/src/testdir/pythonx/topmodule/submodule/subsubmodule/subsubsubmodule.py
@@ -0,0 +1 @@
+#
diff --git a/src/testdir/pyxfile/py2_magic.py b/src/testdir/pyxfile/py2_magic.py
new file mode 100644
index 0000000..819892f
--- /dev/null
+++ b/src/testdir/pyxfile/py2_magic.py
@@ -0,0 +1,4 @@
+# requires python 2.x
+
+import sys
+print(sys.version)
diff --git a/src/testdir/pyxfile/py2_shebang.py b/src/testdir/pyxfile/py2_shebang.py
new file mode 100644
index 0000000..13bfc49
--- /dev/null
+++ b/src/testdir/pyxfile/py2_shebang.py
@@ -0,0 +1,4 @@
+#!/usr/bin/python2
+
+import sys
+print(sys.version)
diff --git a/src/testdir/pyxfile/py3_magic.py b/src/testdir/pyxfile/py3_magic.py
new file mode 100644
index 0000000..d4b7ee0
--- /dev/null
+++ b/src/testdir/pyxfile/py3_magic.py
@@ -0,0 +1,4 @@
+# requires python 3.x
+
+import sys
+print(sys.version)
diff --git a/src/testdir/pyxfile/py3_shebang.py b/src/testdir/pyxfile/py3_shebang.py
new file mode 100644
index 0000000..ec05808
--- /dev/null
+++ b/src/testdir/pyxfile/py3_shebang.py
@@ -0,0 +1,4 @@
+#!/usr/bin/python3
+
+import sys
+print(sys.version)
diff --git a/src/testdir/pyxfile/pyx.py b/src/testdir/pyxfile/pyx.py
new file mode 100644
index 0000000..261a651
--- /dev/null
+++ b/src/testdir/pyxfile/pyx.py
@@ -0,0 +1,2 @@
+import sys
+print(sys.version)
diff --git a/src/testdir/runtest.vim b/src/testdir/runtest.vim
new file mode 100644
index 0000000..3f49ccb
--- /dev/null
+++ b/src/testdir/runtest.vim
@@ -0,0 +1,401 @@
+" This script is sourced while editing the .vim file with the tests.
+" When the script is successful the .res file will be created.
+" Errors are appended to the test.log file.
+"
+" To execute only specific test functions, add a second argument. It will be
+" matched against the names of the Test_ funtion. E.g.:
+" ../vim -u NONE -S runtest.vim test_channel.vim open_delay
+" The output can be found in the "messages" file.
+"
+" The test script may contain anything, only functions that start with
+" "Test_" are special. These will be invoked and should contain assert
+" functions. See test_assert.vim for an example.
+"
+" It is possible to source other files that contain "Test_" functions. This
+" can speed up testing, since Vim does not need to restart. But be careful
+" that the tests do not interfere with each other.
+"
+" If an error cannot be detected properly with an assert function add the
+" error to the v:errors list:
+" call add(v:errors, 'test foo failed: Cannot find xyz')
+"
+" If preparation for each Test_ function is needed, define a SetUp function.
+" It will be called before each Test_ function.
+"
+" If cleanup after each Test_ function is needed, define a TearDown function.
+" It will be called after each Test_ function.
+"
+" When debugging a test it can be useful to add messages to v:errors:
+" call add(v:errors, "this happened")
+
+
+" Without the +eval feature we can't run these tests, bail out.
+so small.vim
+
+" Check that the screen size is at least 24 x 80 characters.
+if &lines < 24 || &columns < 80
+ let error = 'Screen size too small! Tests require at least 24 lines with 80 characters'
+ echoerr error
+ split test.log
+ $put =error
+ w
+ cquit
+endif
+
+" Common with all tests on all systems.
+source setup.vim
+
+" For consistency run all tests with 'nocompatible' set.
+" This also enables use of line continuation.
+set nocp viminfo+=nviminfo
+
+" Use utf-8 by default, instead of whatever the system default happens to be.
+" Individual tests can overrule this at the top of the file.
+set encoding=utf-8
+
+" REDIR_TEST_TO_NULL has a very permissive SwapExists autocommand which is for
+" the test_name.vim file itself. Replace it here with a more restrictive one,
+" so we still catch mistakes.
+let s:test_script_fname = expand('%')
+au! SwapExists * call HandleSwapExists()
+func HandleSwapExists()
+ " Only ignore finding a swap file for the test script (the user might be
+ " editing it and do ":make test_name") and the output file.
+ if expand('<afile>') == 'messages' || expand('<afile>') =~ s:test_script_fname
+ let v:swapchoice = 'e'
+ endif
+endfunc
+
+" Avoid stopping at the "hit enter" prompt
+set nomore
+
+" Output all messages in English.
+lang mess C
+
+" Always use forward slashes.
+set shellslash
+
+let s:srcdir = expand('%:p:h:h')
+
+" Prepare for calling test_garbagecollect_now().
+let v:testing = 1
+
+" Support function: get the alloc ID by name.
+function GetAllocId(name)
+ exe 'split ' . s:srcdir . '/alloc.h'
+ let top = search('typedef enum')
+ if top == 0
+ call add(v:errors, 'typedef not found in alloc.h')
+ endif
+ let lnum = search('aid_' . a:name . ',')
+ if lnum == 0
+ call add(v:errors, 'Alloc ID ' . a:name . ' not defined')
+ endif
+ close
+ return lnum - top - 1
+endfunc
+
+func RunTheTest(test)
+ echo 'Executing ' . a:test
+
+ " Avoid stopping at the "hit enter" prompt
+ set nomore
+
+ " Avoid a three second wait when a message is about to be overwritten by the
+ " mode message.
+ set noshowmode
+
+ " Clear any overrides.
+ call test_override('ALL', 0)
+
+ " Some tests wipe out buffers. To be consistent, always wipe out all
+ " buffers.
+ %bwipe!
+
+ " The test may change the current directory. Save and restore the
+ " directory after executing the test.
+ let save_cwd = getcwd()
+
+ if exists("*SetUp")
+ try
+ call SetUp()
+ catch
+ call add(v:errors, 'Caught exception in SetUp() before ' . a:test . ': ' . v:exception . ' @ ' . v:throwpoint)
+ endtry
+ endif
+
+ call add(s:messages, 'Executing ' . a:test)
+ let s:done += 1
+
+ if a:test =~ 'Test_nocatch_'
+ " Function handles errors itself. This avoids skipping commands after the
+ " error.
+ exe 'call ' . a:test
+ else
+ try
+ let s:test = a:test
+ au VimLeavePre * call EarlyExit(s:test)
+ exe 'call ' . a:test
+ au! VimLeavePre
+ catch /^\cskipped/
+ call add(s:messages, ' Skipped')
+ call add(s:skipped, 'SKIPPED ' . a:test . ': ' . substitute(v:exception, '^\S*\s\+', '', ''))
+ catch
+ call add(v:errors, 'Caught exception in ' . a:test . ': ' . v:exception . ' @ ' . v:throwpoint)
+ endtry
+ endif
+
+ " In case 'insertmode' was set and something went wrong, make sure it is
+ " reset to avoid trouble with anything else.
+ set noinsertmode
+
+ if exists("*TearDown")
+ try
+ call TearDown()
+ catch
+ call add(v:errors, 'Caught exception in TearDown() after ' . a:test . ': ' . v:exception . ' @ ' . v:throwpoint)
+ endtry
+ endif
+
+ " Clear any autocommands
+ au!
+ au SwapExists * call HandleSwapExists()
+
+ " Close any extra tab pages and windows and make the current one not modified.
+ while tabpagenr('$') > 1
+ quit!
+ endwhile
+
+ while 1
+ let wincount = winnr('$')
+ if wincount == 1
+ break
+ endif
+ bwipe!
+ if wincount == winnr('$')
+ " Did not manage to close a window.
+ only!
+ break
+ endif
+ endwhile
+
+ exe 'cd ' . save_cwd
+endfunc
+
+func AfterTheTest()
+ if len(v:errors) > 0
+ let s:fail += 1
+ call add(s:errors, 'Found errors in ' . s:test . ':')
+ call extend(s:errors, v:errors)
+ let v:errors = []
+ endif
+endfunc
+
+func EarlyExit(test)
+ " It's OK for the test we use to test the quit detection.
+ if a:test != 'Test_zz_quit_detected()'
+ call add(v:errors, 'Test caused Vim to exit: ' . a:test)
+ endif
+
+ call FinishTesting()
+endfunc
+
+" This function can be called by a test if it wants to abort testing.
+func FinishTesting()
+ call AfterTheTest()
+
+ " Don't write viminfo on exit.
+ set viminfo=
+
+ " Clean up files created by setup.vim
+ call delete('XfakeHOME', 'rf')
+
+ if s:fail == 0
+ " Success, create the .res file so that make knows it's done.
+ exe 'split ' . fnamemodify(g:testname, ':r') . '.res'
+ write
+ endif
+
+ if len(s:errors) > 0
+ " Append errors to test.log
+ split test.log
+ call append(line('$'), '')
+ call append(line('$'), 'From ' . g:testname . ':')
+ call append(line('$'), s:errors)
+ write
+ endif
+
+ if s:done == 0
+ let message = 'NO tests executed'
+ else
+ let message = 'Executed ' . s:done . (s:done > 1 ? ' tests' : ' test')
+ endif
+ echo message
+ call add(s:messages, message)
+ if s:fail > 0
+ let message = s:fail . ' FAILED:'
+ echo message
+ call add(s:messages, message)
+ call extend(s:messages, s:errors)
+ endif
+
+ " Add SKIPPED messages
+ call extend(s:messages, s:skipped)
+
+ " Append messages to the file "messages"
+ split messages
+ call append(line('$'), '')
+ call append(line('$'), 'From ' . g:testname . ':')
+ call append(line('$'), s:messages)
+ write
+
+ qall!
+endfunc
+
+" Source the test script. First grab the file name, in case the script
+" navigates away. g:testname can be used by the tests.
+let g:testname = expand('%')
+let s:done = 0
+let s:fail = 0
+let s:errors = []
+let s:messages = []
+let s:skipped = []
+if expand('%') =~ 'test_vimscript.vim'
+ " this test has intentional s:errors, don't use try/catch.
+ source %
+else
+ try
+ source %
+ catch
+ let s:fail += 1
+ call add(s:errors, 'Caught exception: ' . v:exception . ' @ ' . v:throwpoint)
+ endtry
+endif
+
+" Names of flaky tests.
+let s:flaky_tests = [
+ \ 'Test_call()',
+ \ 'Test_channel_handler()',
+ \ 'Test_client_server()',
+ \ 'Test_close_and_exit_cb()',
+ \ 'Test_close_callback()',
+ \ 'Test_close_handle()',
+ \ 'Test_close_lambda()',
+ \ 'Test_close_output_buffer()',
+ \ 'Test_close_partial()',
+ \ 'Test_collapse_buffers()',
+ \ 'Test_communicate()',
+ \ 'Test_cwd()',
+ \ 'Test_diff_screen()',
+ \ 'Test_exit_callback()',
+ \ 'Test_exit_callback_interval()',
+ \ 'Test_nb_basic()',
+ \ 'Test_oneshot()',
+ \ 'Test_open_delay()',
+ \ 'Test_out_cb()',
+ \ 'Test_paused()',
+ \ 'Test_pipe_through_sort_all()',
+ \ 'Test_pipe_through_sort_some()',
+ \ 'Test_popup_and_window_resize()',
+ \ 'Test_quoteplus()',
+ \ 'Test_quotestar()',
+ \ 'Test_raw_one_time_callback()',
+ \ 'Test_reltime()',
+ \ 'Test_repeat_three()',
+ \ 'Test_server_crash()',
+ \ 'Test_terminal_ansicolors_default()',
+ \ 'Test_terminal_ansicolors_func()',
+ \ 'Test_terminal_ansicolors_global()',
+ \ 'Test_terminal_composing_unicode()',
+ \ 'Test_terminal_env()',
+ \ 'Test_terminal_hide_buffer()',
+ \ 'Test_terminal_make_change()',
+ \ 'Test_terminal_noblock()',
+ \ 'Test_terminal_redir_file()',
+ \ 'Test_terminal_response_to_control_sequence()',
+ \ 'Test_terminal_scrollback()',
+ \ 'Test_terminal_split_quit()',
+ \ 'Test_terminal_termwinkey()',
+ \ 'Test_terminal_termwinsize_mininmum()',
+ \ 'Test_terminal_termwinsize_option_fixed()',
+ \ 'Test_terminal_termwinsize_option_zero()',
+ \ 'Test_terminal_tmap()',
+ \ 'Test_terminal_wall()',
+ \ 'Test_terminal_wipe_buffer()',
+ \ 'Test_terminal_wqall()',
+ \ 'Test_two_channels()',
+ \ 'Test_unlet_handle()',
+ \ 'Test_with_partial_callback()',
+ \ 'Test_zero_reply()',
+ \ 'Test_zz1_terminal_in_gui()',
+ \ ]
+
+" Pattern indicating a common flaky test failure.
+let s:flaky_errors_re = 'StopVimInTerminal\|VerifyScreenDump'
+
+" Locate Test_ functions and execute them.
+redir @q
+silent function /^Test_
+redir END
+let s:tests = split(substitute(@q, 'function \(\k*()\)', '\1', 'g'))
+
+" If there is an extra argument filter the function names against it.
+if argc() > 1
+ let s:tests = filter(s:tests, 'v:val =~ argv(1)')
+endif
+
+" Execute the tests in alphabetical order.
+for s:test in sort(s:tests)
+ " Silence, please!
+ set belloff=all
+ let prev_error = ''
+ let total_errors = []
+ let run_nr = 1
+
+ call RunTheTest(s:test)
+
+ " Repeat a flaky test. Give up when:
+ " - it fails again with the same message
+ " - it fails five times (with a different mesage)
+ if len(v:errors) > 0
+ \ && (index(s:flaky_tests, s:test) >= 0
+ \ || v:errors[0] =~ s:flaky_errors_re)
+ while 1
+ call add(s:messages, 'Found errors in ' . s:test . ':')
+ call extend(s:messages, v:errors)
+
+ call add(total_errors, 'Run ' . run_nr . ':')
+ call extend(total_errors, v:errors)
+
+ if run_nr == 5 || prev_error == v:errors[0]
+ call add(total_errors, 'Flaky test failed too often, giving up')
+ let v:errors = total_errors
+ break
+ endif
+
+ call add(s:messages, 'Flaky test failed, running it again')
+
+ " Flakiness is often caused by the system being very busy. Sleep a
+ " couple of seconds to have a higher chance of succeeding the second
+ " time.
+ sleep 2
+
+ let prev_error = v:errors[0]
+ let v:errors = []
+ let run_nr += 1
+
+ call RunTheTest(s:test)
+
+ if len(v:errors) == 0
+ " Test passed on rerun.
+ break
+ endif
+ endwhile
+ endif
+
+ call AfterTheTest()
+endfor
+
+call FinishTesting()
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/samples/quickfix.txt b/src/testdir/samples/quickfix.txt
new file mode 100644
index 0000000..2de3835
--- /dev/null
+++ b/src/testdir/samples/quickfix.txt
@@ -0,0 +1,4 @@
+samples/quickfix.txt:1:1:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+samples/quickfix.txt:2:1:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
+samples/quickfix.txt:3:1:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
+samples/quickfix.txt:4:1:dddddddddd
diff --git a/src/testdir/samples/re.freeze.txt b/src/testdir/samples/re.freeze.txt
new file mode 100644
index 0000000..d768c23
--- /dev/null
+++ b/src/testdir/samples/re.freeze.txt
@@ -0,0 +1,6 @@
+:set re=0 or 2
+Search for the pattern: /\s\+\%#\@<!$/
+vim should not freeze.
+
+<td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td>
+
diff --git a/src/testdir/samples/test000 b/src/testdir/samples/test000
new file mode 100644
index 0000000..af8abe9
--- /dev/null
+++ b/src/testdir/samples/test000
Binary files differ
diff --git a/src/testdir/sautest/autoload/Test104.vim b/src/testdir/sautest/autoload/Test104.vim
new file mode 100644
index 0000000..d1e0e17
--- /dev/null
+++ b/src/testdir/sautest/autoload/Test104.vim
@@ -0,0 +1 @@
+let Test104#numvar = 123
diff --git a/src/testdir/sautest/autoload/foo.vim b/src/testdir/sautest/autoload/foo.vim
new file mode 100644
index 0000000..d7dcd5c
--- /dev/null
+++ b/src/testdir/sautest/autoload/foo.vim
@@ -0,0 +1,7 @@
+let g:loaded_foo_vim += 1
+
+let foo#bar = {}
+
+func foo#bar.echo()
+ let g:called_foo_bar_echo += 1
+endfunc
diff --git a/src/testdir/sautest/autoload/footest.vim b/src/testdir/sautest/autoload/footest.vim
new file mode 100644
index 0000000..1e78963
--- /dev/null
+++ b/src/testdir/sautest/autoload/footest.vim
@@ -0,0 +1,5 @@
+" Autoload script used by test_listdict.vim, test_exists.vim and test_let.vim
+let footest#x = 1
+func footest#F()
+ return 0
+endfunc
diff --git a/src/testdir/sautest/autoload/globone.vim b/src/testdir/sautest/autoload/globone.vim
new file mode 100644
index 0000000..98c9a10
--- /dev/null
+++ b/src/testdir/sautest/autoload/globone.vim
@@ -0,0 +1 @@
+" used by Test_globpath()
diff --git a/src/testdir/sautest/autoload/globtwo.vim b/src/testdir/sautest/autoload/globtwo.vim
new file mode 100644
index 0000000..98c9a10
--- /dev/null
+++ b/src/testdir/sautest/autoload/globtwo.vim
@@ -0,0 +1 @@
+" used by Test_globpath()
diff --git a/src/testdir/sautest/autoload/sourced.vim b/src/testdir/sautest/autoload/sourced.vim
new file mode 100644
index 0000000..f69f00c
--- /dev/null
+++ b/src/testdir/sautest/autoload/sourced.vim
@@ -0,0 +1,3 @@
+let g:loaded_sourced_vim += 1
+func! sourced#something()
+endfunc
diff --git a/src/testdir/screendump.vim b/src/testdir/screendump.vim
new file mode 100644
index 0000000..b46a477
--- /dev/null
+++ b/src/testdir/screendump.vim
@@ -0,0 +1,130 @@
+" Functions shared by tests making screen dumps.
+
+" Only load this script once.
+if exists('*CanRunVimInTerminal')
+ finish
+endif
+
+" For most tests we need to be able to run terminal Vim with 256 colors. On
+" MS-Windows the console only has 16 colors and the GUI can't run in a
+" terminal.
+func CanRunVimInTerminal()
+ return has('terminal') && !has('win32')
+endfunc
+
+" Skip the rest if there is no terminal feature at all.
+if !has('terminal')
+ finish
+endif
+
+source shared.vim
+
+" Run Vim with "arguments" in a new terminal window.
+" By default uses a size of 20 lines and 75 columns.
+" Returns the buffer number of the terminal.
+"
+" Options is a dictionary, these items are recognized:
+" "rows" - height of the terminal window (max. 20)
+" "cols" - width of the terminal window (max. 78)
+func RunVimInTerminal(arguments, options)
+ " If Vim doesn't exit a swap file remains, causing other tests to fail.
+ " Remove it here.
+ call delete(".swp")
+
+ if exists('$COLORFGBG')
+ " Clear $COLORFGBG to avoid 'background' being set to "dark", which will
+ " only be corrected if the response to t_RB is received, which may be too
+ " late.
+ let $COLORFGBG = ''
+ endif
+
+ " Make a horizontal and vertical split, so that we can get exactly the right
+ " size terminal window. Works only when the current window is full width.
+ call assert_equal(&columns, winwidth(0))
+ split
+ vsplit
+
+ " Always do this with 256 colors and a light background.
+ set t_Co=256 background=light
+ hi Normal ctermfg=NONE ctermbg=NONE
+
+ " Make the window 20 lines high and 75 columns, unless told otherwise.
+ let rows = get(a:options, 'rows', 20)
+ let cols = get(a:options, 'cols', 75)
+
+ let cmd = GetVimCommandClean()
+
+ " Add -v to have gvim run in the terminal (if possible)
+ let cmd .= ' -v ' . a:arguments
+ let buf = term_start(cmd, {'curwin': 1, 'term_rows': rows, 'term_cols': cols})
+ if &termwinsize == ''
+ " in the GUI we may end up with a different size, try to set it.
+ if term_getsize(buf) != [rows, cols]
+ call term_setsize(buf, rows, cols)
+ endif
+ call assert_equal([rows, cols], term_getsize(buf))
+ else
+ let rows = term_getsize(buf)[0]
+ let cols = term_getsize(buf)[1]
+ endif
+
+ " Wait for "All" or "Top" of the ruler to be shown in the last line or in
+ " the status line of the last window. This can be quite slow (e.g. when
+ " using valgrind).
+ " If it fails then show the terminal contents for debugging.
+ try
+ call WaitFor({-> len(term_getline(buf, rows)) >= cols - 1 || len(term_getline(buf, rows - 1)) >= cols - 1})
+ catch /timed out after/
+ let lines = map(range(1, rows), {key, val -> term_getline(buf, val)})
+ call assert_report('RunVimInTerminal() failed, screen contents: ' . join(lines, "<NL>"))
+ endtry
+
+ return buf
+endfunc
+
+" Stop a Vim running in terminal buffer "buf".
+func StopVimInTerminal(buf)
+ call assert_equal("running", term_getstatus(a:buf))
+
+ " CTRL-O : works both in Normal mode and Insert mode to start a command line.
+ " In Command-line it's inserted, the CTRL-U removes it again.
+ call term_sendkeys(a:buf, "\<C-O>:\<C-U>qa!\<cr>")
+
+ call WaitForAssert({-> assert_equal("finished", term_getstatus(a:buf))})
+ only!
+endfunc
+
+" Verify that Vim running in terminal buffer "buf" matches the screen dump.
+" "options" is passed to term_dumpwrite().
+" The file name used is "dumps/{filename}.dump".
+" Optionally an extra argument can be passed which is prepended to the error
+" message. Use this when using the same dump file with different options.
+" Will wait for up to a second for the screen dump to match.
+" Returns non-zero when verification fails.
+func VerifyScreenDump(buf, filename, options, ...)
+ let reference = 'dumps/' . a:filename . '.dump'
+ let testfile = a:filename . '.dump.failed'
+
+ let i = 0
+ while 1
+ " leave some time for updating the original window
+ sleep 10m
+ call delete(testfile)
+ call term_dumpwrite(a:buf, testfile, a:options)
+ if readfile(reference) == readfile(testfile)
+ call delete(testfile)
+ break
+ endif
+ if i == 100
+ " Leave the test file around for inspection.
+ let msg = 'See dump file difference: call term_dumpdiff("' . testfile . '", "' . reference . '")'
+ if a:0 == 1
+ let msg = a:1 . ': ' . msg
+ endif
+ call assert_report(msg)
+ return 1
+ endif
+ let i += 1
+ endwhile
+ return 0
+endfunc
diff --git a/src/testdir/setup.vim b/src/testdir/setup.vim
new file mode 100644
index 0000000..fca5194
--- /dev/null
+++ b/src/testdir/setup.vim
@@ -0,0 +1,33 @@
+" Common preparations for running tests.
+
+" Only load this once.
+if 1
+ if exists('s:did_load')
+ finish
+ endif
+ let s:did_load = 1
+endif
+
+" Make sure 'runtimepath' and 'packpath' does not include $HOME.
+set rtp=$VIM/vimfiles,$VIMRUNTIME,$VIM/vimfiles/after
+if has('packages')
+ let &packpath = &rtp
+endif
+
+" Only when the +eval feature is present.
+if 1
+ " Make sure the .Xauthority file can be found after changing $HOME.
+ if $XAUTHORITY == ''
+ let $XAUTHORITY = $HOME . '/.Xauthority'
+ endif
+
+ " Avoid storing shell history.
+ let $HISTFILE = ""
+
+ " Make sure $HOME does not get read or written.
+ " It must exist, gnome tries to create $HOME/.gnome2
+ let $HOME = getcwd() . '/XfakeHOME'
+ if !isdirectory($HOME)
+ call mkdir($HOME)
+ endif
+endif
diff --git a/src/testdir/setup_gui.vim b/src/testdir/setup_gui.vim
new file mode 100644
index 0000000..90ef1f1
--- /dev/null
+++ b/src/testdir/setup_gui.vim
@@ -0,0 +1,32 @@
+" Common preparations for running GUI tests.
+
+let g:x11_based_gui = has('gui_athena') || has('gui_motif')
+ \ || has('gui_gtk2') || has('gui_gnome') || has('gui_gtk3')
+
+" Reasons for 'skipped'.
+let g:not_supported = "Skipped: Feature/Option not supported by this GUI: "
+let g:not_implemented = "Skipped: Test not implemented yet for this GUI"
+let g:not_hosted = "Skipped: Test not hosted by the system/environment"
+
+" For KDE set a font, empty 'guifont' may cause a hang.
+func GUISetUpCommon()
+ if has("gui_kde")
+ set guifont=Courier\ 10\ Pitch/8/-1/5/50/0/0/0/0/0
+ endif
+
+ " Gnome insists on creating $HOME/.gnome2/, set $HOME to avoid changing the
+ " actual home directory. But avoid triggering fontconfig by setting the
+ " cache directory. Only needed for Unix.
+ if $XDG_CACHE_HOME == '' && exists('g:tester_HOME')
+ let $XDG_CACHE_HOME = g:tester_HOME . '/.cache'
+ endif
+ call mkdir('Xhome')
+ let $HOME = fnamemodify('Xhome', ':p')
+endfunc
+
+func GUITearDownCommon()
+ call delete('Xhome', 'rf')
+endfunc
+
+" Ignore the "failed to create input context" error.
+call test_ignore_error('E285')
diff --git a/src/testdir/shared.vim b/src/testdir/shared.vim
new file mode 100644
index 0000000..4546be7
--- /dev/null
+++ b/src/testdir/shared.vim
@@ -0,0 +1,357 @@
+" Functions shared by several tests.
+
+" Only load this script once.
+if exists('*WaitFor')
+ finish
+endif
+
+" Get the name of the Python executable.
+" Also keeps it in s:python.
+func PythonProg()
+ " This test requires the Python command to run the test server.
+ " This most likely only works on Unix and Windows.
+ if has('unix')
+ " We also need the job feature or the pkill command to make sure the server
+ " can be stopped.
+ if !(executable('python') && (has('job') || executable('pkill')))
+ return ''
+ endif
+ let s:python = 'python'
+ elseif has('win32')
+ " Use Python Launcher for Windows (py.exe) if available.
+ if executable('py.exe')
+ let s:python = 'py.exe'
+ elseif executable('python.exe')
+ let s:python = 'python.exe'
+ else
+ return ''
+ endif
+ else
+ return ''
+ endif
+ return s:python
+endfunc
+
+" Run "cmd". Returns the job if using a job.
+func RunCommand(cmd)
+ let job = 0
+ if has('job')
+ let job = job_start(a:cmd, {"stoponexit": "hup"})
+ call job_setoptions(job, {"stoponexit": "kill"})
+ elseif has('win32')
+ exe 'silent !start cmd /c start "test_channel" ' . a:cmd
+ else
+ exe 'silent !' . a:cmd . '&'
+ endif
+ return job
+endfunc
+
+" Read the port number from the Xportnr file.
+func GetPort()
+ let l = []
+ " with 200 it sometimes failed
+ for i in range(400)
+ try
+ let l = readfile("Xportnr")
+ catch
+ endtry
+ if len(l) >= 1
+ break
+ endif
+ sleep 10m
+ endfor
+ call delete("Xportnr")
+
+ if len(l) == 0
+ " Can't make the connection, give up.
+ return 0
+ endif
+ return l[0]
+endfunc
+
+" Run a Python server for "cmd" and call "testfunc".
+" Always kills the server before returning.
+func RunServer(cmd, testfunc, args)
+ " The Python program writes the port number in Xportnr.
+ call delete("Xportnr")
+
+ if len(a:args) == 1
+ let arg = ' ' . a:args[0]
+ else
+ let arg = ''
+ endif
+ let pycmd = s:python . " " . a:cmd . arg
+
+ try
+ let g:currentJob = RunCommand(pycmd)
+
+ " Wait for up to 2 seconds for the port number to be there.
+ let port = GetPort()
+ if port == 0
+ call assert_false(1, "Can't start " . a:cmd)
+ return
+ endif
+
+ call call(function(a:testfunc), [port])
+ catch
+ call assert_false(1, 'Caught exception: "' . v:exception . '" in ' . v:throwpoint)
+ finally
+ call s:kill_server(a:cmd)
+ endtry
+endfunc
+
+func s:kill_server(cmd)
+ if has('job')
+ if exists('g:currentJob')
+ call job_stop(g:currentJob)
+ unlet g:currentJob
+ endif
+ elseif has('win32')
+ let cmd = substitute(a:cmd, ".py", '', '')
+ call system('taskkill /IM ' . s:python . ' /T /F /FI "WINDOWTITLE eq ' . cmd . '"')
+ else
+ call system("pkill -f " . a:cmd)
+ endif
+endfunc
+
+" Wait for up to five seconds for "expr" to become true. "expr" can be a
+" stringified expression to evaluate, or a funcref without arguments.
+" Using a lambda works best. Example:
+" call WaitFor({-> status == "ok"})
+"
+" A second argument can be used to specify a different timeout in msec.
+"
+" When successful the time slept is returned.
+" When running into the timeout an exception is thrown, thus the function does
+" not return.
+func WaitFor(expr, ...)
+ let timeout = get(a:000, 0, 5000)
+ let slept = s:WaitForCommon(a:expr, v:null, timeout)
+ if slept < 0
+ throw 'WaitFor() timed out after ' . timeout . ' msec'
+ endif
+ return slept
+endfunc
+
+" Wait for up to five seconds for "assert" to return zero. "assert" must be a
+" (lambda) function containing one assert function. Example:
+" call WaitForAssert({-> assert_equal("dead", job_status(job)})
+"
+" A second argument can be used to specify a different timeout in msec.
+"
+" Return zero for success, one for failure (like the assert function).
+func WaitForAssert(assert, ...)
+ let timeout = get(a:000, 0, 5000)
+ if s:WaitForCommon(v:null, a:assert, timeout) < 0
+ return 1
+ endif
+ return 0
+endfunc
+
+" Common implementation of WaitFor() and WaitForAssert().
+" Either "expr" or "assert" is not v:null
+" Return the waiting time for success, -1 for failure.
+func s:WaitForCommon(expr, assert, timeout)
+ " using reltime() is more accurate, but not always available
+ let slept = 0
+ if has('reltime')
+ let start = reltime()
+ endif
+
+ while 1
+ if type(a:expr) == v:t_func
+ let success = a:expr()
+ elseif type(a:assert) == v:t_func
+ let success = a:assert() == 0
+ else
+ let success = eval(a:expr)
+ endif
+ if success
+ return slept
+ endif
+
+ if slept >= a:timeout
+ break
+ endif
+ if type(a:assert) == v:t_func
+ " Remove the error added by the assert function.
+ call remove(v:errors, -1)
+ endif
+
+ sleep 10m
+ if has('reltime')
+ let slept = float2nr(reltimefloat(reltime(start)) * 1000)
+ else
+ let slept += 10
+ endif
+ endwhile
+
+ return -1 " timed out
+endfunc
+
+
+" Wait for up to a given milliseconds.
+" With the +timers feature this waits for key-input by getchar(), Resume()
+" feeds key-input and resumes process. Return time waited in milliseconds.
+" Without +timers it uses simply :sleep.
+func Standby(msec)
+ if has('timers')
+ let start = reltime()
+ let g:_standby_timer = timer_start(a:msec, function('s:feedkeys'))
+ call getchar()
+ return float2nr(reltimefloat(reltime(start)) * 1000)
+ else
+ execute 'sleep ' a:msec . 'm'
+ return a:msec
+ endif
+endfunc
+
+func Resume()
+ if exists('g:_standby_timer')
+ call timer_stop(g:_standby_timer)
+ call s:feedkeys(0)
+ unlet g:_standby_timer
+ endif
+endfunc
+
+func s:feedkeys(timer)
+ call feedkeys('x', 'nt')
+endfunc
+
+" Get $VIMPROG to run Vim executable.
+" The Makefile writes it as the first line in the "vimcmd" file.
+func GetVimProg()
+ if !filereadable('vimcmd')
+ " Assume the script was sourced instead of running "make".
+ return '../vim'
+ endif
+ return readfile('vimcmd')[0]
+endfunc
+
+let g:valgrind_cnt = 1
+
+" Get the command to run Vim, with -u NONE and --not-a-term arguments.
+" If there is an argument use it instead of "NONE".
+func GetVimCommand(...)
+ if !filereadable('vimcmd')
+ echo 'Cannot read the "vimcmd" file, falling back to ../vim.'
+ let lines = ['../vim']
+ else
+ let lines = readfile('vimcmd')
+ endif
+ if a:0 == 0
+ let name = 'NONE'
+ else
+ let name = a:1
+ endif
+ " For Unix Makefile writes the command to use in the second line of the
+ " "vimcmd" file, including environment options.
+ " Other Makefiles just write the executable in the first line, so fall back
+ " to that if there is no second line or it is empty.
+ if len(lines) > 1 && lines[1] != ''
+ let cmd = lines[1]
+ else
+ let cmd = lines[0]
+ endif
+
+ let cmd = substitute(cmd, '-u \f\+', '-u ' . name, '')
+ if cmd !~ '-u '. name
+ let cmd = cmd . ' -u ' . name
+ endif
+ let cmd .= ' --not-a-term'
+ let cmd = substitute(cmd, 'VIMRUNTIME=.*VIMRUNTIME;', '', '')
+
+ " If using valgrind, make sure every run uses a different log file.
+ if cmd =~ 'valgrind.*--log-file='
+ let cmd = substitute(cmd, '--log-file=\(^\s*\)', '--log-file=\1.' . g:valgrind_cnt, '')
+ let g:valgrind_cnt += 1
+ endif
+
+ return cmd
+endfunc
+
+" Get the command to run Vim, with --clean.
+func GetVimCommandClean()
+ let cmd = GetVimCommand()
+ let cmd = substitute(cmd, '-u NONE', '--clean', '')
+ let cmd = substitute(cmd, '--not-a-term', '', '')
+
+ " Optionally run Vim under valgrind
+ " let cmd = 'valgrind --tool=memcheck --leak-check=yes --num-callers=25 --log-file=valgrind ' . cmd
+
+ return cmd
+endfunc
+
+" Run Vim, using the "vimcmd" file and "-u NORC".
+" "before" is a list of Vim commands to be executed before loading plugins.
+" "after" is a list of Vim commands to be executed after loading plugins.
+" Plugins are not loaded, unless 'loadplugins' is set in "before".
+" Return 1 if Vim could be executed.
+func RunVim(before, after, arguments)
+ return RunVimPiped(a:before, a:after, a:arguments, '')
+endfunc
+
+func RunVimPiped(before, after, arguments, pipecmd)
+ let cmd = GetVimCommand()
+ let args = ''
+ if len(a:before) > 0
+ call writefile(a:before, 'Xbefore.vim')
+ let args .= ' --cmd "so Xbefore.vim"'
+ endif
+ if len(a:after) > 0
+ call writefile(a:after, 'Xafter.vim')
+ let args .= ' -S Xafter.vim'
+ endif
+
+ exe "silent !" . a:pipecmd . cmd . args . ' ' . a:arguments
+
+ if len(a:before) > 0
+ call delete('Xbefore.vim')
+ endif
+ if len(a:after) > 0
+ call delete('Xafter.vim')
+ endif
+ return 1
+endfunc
+
+func CanRunGui()
+ return has('gui') && ($DISPLAY != "" || has('gui_running'))
+endfunc
+
+func WorkingClipboard()
+ if !has('clipboard')
+ return 0
+ endif
+ if has('x11')
+ return $DISPLAY != ""
+ endif
+ return 1
+endfunc
+
+" Get line "lnum" as displayed on the screen.
+" Trailing white space is trimmed.
+func! Screenline(lnum)
+ let chars = []
+ for c in range(1, winwidth(0))
+ call add(chars, nr2char(screenchar(a:lnum, c)))
+ endfor
+ let line = join(chars, '')
+ return matchstr(line, '^.\{-}\ze\s*$')
+endfunc
+
+" Stops the shell running in terminal "buf".
+func Stop_shell_in_terminal(buf)
+ call term_sendkeys(a:buf, "exit\r")
+ let job = term_getjob(a:buf)
+ call WaitFor({-> job_status(job) == "dead"})
+endfunc
+
+" Gets the text of a terminal line, using term_scrape()
+func Get_terminal_text(bufnr, row)
+ let list = term_scrape(a:bufnr, a:row)
+ let text = ''
+ for item in list
+ let text .= item.chars
+ endfor
+ return text
+endfunc
diff --git a/src/testdir/test1.in b/src/testdir/test1.in
new file mode 100644
index 0000000..8c0219e
--- /dev/null
+++ b/src/testdir/test1.in
@@ -0,0 +1,52 @@
+
+First a simple test to check if the test script works.
+
+If Vim was not compiled with the +eval feature, the small.vim script will be
+set to copy the test.ok file to test.out, so that it looks like the test
+succeeded. Otherwise an empty small.vim is written. small.vim is sourced by
+tests that require the +eval feature or other features that are missing in the
+small version.
+
+If Vim was not compiled with the +windows feature, the tiny.vim script will be
+set like small.vim above. tiny.vim is sourced by tests that require the
++windows feature or other features that are missing in the tiny version.
+
+If Vim was not compiled with the +multi_byte feature, the mbyte.vim script will
+be set like small.vim above. mbyte.vim is sourced by tests that require the
++multi_byte feature.
+Similar logic is applied to the +mzscheme feature, using mzscheme.vim.
+
+STARTTEST
+:" If columns or lines are too small, create wrongtermsize.
+:" (Some tests will fail. When columns and/or lines are small)
+:if &lines < 24 || &columns < 80 | sp another | w! wrongtermsize | qa! | endif
+:"
+:" Write a single line to test.out to check if testing works at all.
+:%d
+athis is a test:w! test.out
+:" Create small.vim and tiny.vim empty, create mbyte.vim to skip the test.
+0D:w! small.vim
+:w! tiny.vim
+ae! test.ok
+w! test.out
+qa!
+:w! mbyte.vim
+:w! mzscheme.vim
+:"
+:" If +multi_byte feature supported, make mbyte.vim empty.
+:if has("multi_byte") | sp another | w! mbyte.vim | q | endif
+:"
+:" If +mzscheme feature supported, make mzscheme.vim empty.
+:if has("mzscheme") | sp another | w! mzscheme.vim | q | endif
+:"
+:" If +eval feature supported quit here, leaving tiny.vim and small.vim empty.
+:" Otherwise write small.vim to skip the test.
+:if 1 | q! | endif
+:w! small.vim
+:" If +windows feature not supported :sp will fail and tiny.vim will be
+:" written to skip the test.
+:sp another
+:wq! tiny.vim
+:qa!
+ENDTEST
+
diff --git a/src/testdir/test1.ok b/src/testdir/test1.ok
new file mode 100644
index 0000000..90bfcb5
--- /dev/null
+++ b/src/testdir/test1.ok
@@ -0,0 +1 @@
+this is a test
diff --git a/src/testdir/test108.in b/src/testdir/test108.in
new file mode 100644
index 0000000..59c4dfc
--- /dev/null
+++ b/src/testdir/test108.in
@@ -0,0 +1,88 @@
+Tests for backtrace debug commands. vim: set ft=vim :
+
+STARTTEST
+:so small.vim
+:lang mess C
+:function! Foo()
+: let var1 = 1
+: let var2 = Bar(var1) + 9
+: return var2
+:endfunction
+:
+:function! Bar(var)
+: let var1 = 2 + a:var
+: let var2 = Bazz(var1) + 4
+: return var2
+:endfunction
+:
+:function! Bazz(var)
+: let var1 = 3 + a:var
+: let var3 = "another var"
+: return var1
+:endfunction
+:new
+:debuggreedy
+:redir => out
+:debug echo Foo()
+step
+step
+step
+step
+step
+step
+echo "- show backtrace:\n"
+backtrace
+echo "\nshow variables on different levels:\n"
+echo var1
+up
+back
+echo var1
+u
+bt
+echo var1
+echo "\n- undefined vars:\n"
+step
+frame 2
+echo "undefined var3 on former level:"
+echo var3
+fr 0
+echo "here var3 is defined with \"another var\":"
+echo var3
+step
+step
+step
+up
+echo "\nundefined var2 on former level"
+echo var2
+down
+echo "here var2 is defined with 10:"
+echo var2
+echo "\n- backtrace movements:\n"
+b
+echo "\nnext command cannot go down, we are on bottom\n"
+down
+up
+echo "\nnext command cannot go up, we are on top\n"
+up
+b
+echo "fil is not frame or finish, it is file"
+fil
+echo "\n- relative backtrace movement\n"
+fr -1
+frame
+fra +1
+fram
+echo "\n- go beyond limits does not crash\n"
+fr 100
+fra
+frame -40
+fram
+echo "\n- final result 19:"
+cont
+:0debuggreedy
+:redir END
+:$put =out
+:w! test.out
+:qa!
+ENDTEST
+
diff --git a/src/testdir/test108.ok b/src/testdir/test108.ok
new file mode 100644
index 0000000..7a531dd
--- /dev/null
+++ b/src/testdir/test108.ok
@@ -0,0 +1,82 @@
+
+
+
+- show backtrace:
+
+ 2 function Foo[2]
+ 1 Bar[2]
+->0 Bazz
+line 2: let var3 = "another var"
+
+show variables on different levels:
+
+6
+ 2 function Foo[2]
+->1 Bar[2]
+ 0 Bazz
+line 2: let var3 = "another var"
+3
+->2 function Foo[2]
+ 1 Bar[2]
+ 0 Bazz
+line 2: let var3 = "another var"
+1
+
+- undefined vars:
+
+undefined var3 on former level:
+Error detected while processing function Foo[2]..Bar[2]..Bazz:
+line 3:
+E121: Undefined variable: var3
+here var3 is defined with "another var":
+another var
+
+undefined var2 on former level
+Error detected while processing function Foo[2]..Bar:
+line 3:
+E121: Undefined variable: var2
+here var2 is defined with 10:
+10
+
+- backtrace movements:
+
+ 1 function Foo[2]
+->0 Bar
+line 3: End of function
+
+next command cannot go down, we are on bottom
+
+frame is zero
+
+next command cannot go up, we are on top
+
+frame at highest level: 1
+->1 function Foo[2]
+ 0 Bar
+line 3: End of function
+fil is not frame or finish, it is file
+"[No Name]" --No lines in buffer--
+
+- relative backtrace movement
+
+ 1 function Foo[2]
+->0 Bar
+line 3: End of function
+->1 function Foo[2]
+ 0 Bar
+line 3: End of function
+
+- go beyond limits does not crash
+
+frame at highest level: 1
+->1 function Foo[2]
+ 0 Bar
+line 3: End of function
+frame is zero
+ 1 function Foo[2]
+->0 Bar
+line 3: End of function
+
+- final result 19:
+19
+
diff --git a/src/testdir/test11.in b/src/testdir/test11.in
new file mode 100644
index 0000000..9e9e257
--- /dev/null
+++ b/src/testdir/test11.in
@@ -0,0 +1,84 @@
+Tests for autocommands:
+- FileWritePre writing a compressed file
+- FileReadPost reading a compressed file
+- BufNewFile reading a file template
+- BufReadPre decompressing the file to be read
+- FilterReadPre substituting characters in the temp file
+- FilterReadPost substituting characters after filtering
+- FileReadPre set options for decompression
+- FileReadPost decompress the file
+
+Note: This test is skipped if "gzip" is not available.
+$GZIP is made empty, "-v" would cause trouble.
+Use a FileChangedShell autocommand to avoid a prompt for "Xtestfile.gz" being
+modified outside of Vim (noticed on Solaris).
+
+STARTTEST
+:so small.vim
+:" drop out when there is no gzip program
+:if !executable("gzip")
+: e! test.ok
+: w! test.out
+: qa!
+:endif
+:let $GZIP = ""
+:au FileChangedShell * echo "caught FileChangedShell"
+:set bin
+:au FileWritePre *.gz '[,']!gzip
+:au FileWritePost *.gz undo
+:/^start of testfile/,/^end of testfile/w! Xtestfile.gz
+:au FileReadPost *.gz '[,']!gzip -d
+:$r Xtestfile.gz " Read and decompress the testfile
+:?startstart?,$w! test.out " Write contents of this file
+:au BufNewFile *.c read Xtest.c
+:/^start of test.c/+1,/^end of test.c/-1w! Xtest.c
+:e! foo.c " Will load Xtest.c
+:au FileAppendPre *.out '[,']s/new/NEW/
+:au FileAppendPost *.out !cat Xtest.c >>test.out
+:w>>test.out " Append it to the output file
+:au! FileAppendPre
+:" setup autocommands to decompress before reading and re-compress afterwards
+:au BufReadPre *.gz exe '!gzip -d ' . shellescape(expand("<afile>"))
+:au BufReadPre *.gz call rename(expand("<afile>:r"), expand("<afile>"))
+:au BufReadPost *.gz call rename(expand("<afile>"), expand("<afile>:r"))
+:au BufReadPost *.gz exe '!gzip ' . shellescape(expand("<afile>:r"))
+:e! Xtestfile.gz " Edit compressed file
+:w>>test.out " Append it to the output file
+:set shelltemp " need temp files here
+:au FilterReadPre *.out call rename(expand("<afile>"), expand("<afile>") . ".t")
+:au FilterReadPre *.out exe 'silent !sed s/e/E/ ' . shellescape(expand("<afile>")) . ".t >" . shellescape(expand("<afile>"))
+:au FilterReadPre *.out exe 'silent !rm ' . shellescape(expand("<afile>")) . '.t'
+:au FilterReadPost *.out '[,']s/x/X/g
+:e! test.out " Edit the output file
+:23,$!cat
+:23,$s/\r$// " remove CR for when sed adds them
+:au! FileReadPre *.gz exe 'silent !gzip -d ' . shellescape(expand("<afile>"))
+:au FileReadPre *.gz call rename(expand("<afile>:r"), expand("<afile>"))
+:au! FileReadPost *.gz '[,']s/l/L/
+:$r Xtestfile.gz " Read compressed file
+:w " write it, after filtering
+:au! " remove all autocommands
+:e " Edit test.out again
+:set nobin ff& " use the default fileformat for writing
+:w
+:qa!
+ENDTEST
+
+startstart
+start of testfile
+line 2 Abcdefghijklmnopqrstuvwxyz
+line 3 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+line 4 Abcdefghijklmnopqrstuvwxyz
+line 5 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+line 6 Abcdefghijklmnopqrstuvwxyz
+line 7 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+line 8 Abcdefghijklmnopqrstuvwxyz
+line 9 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+line 10 Abcdefghijklmnopqrstuvwxyz
+end of testfile
+
+start of test.c
+/*
+ * Here is a new .c file
+ */
+end of test.c
diff --git a/src/testdir/test11.ok b/src/testdir/test11.ok
new file mode 100644
index 0000000..af8c5ce
--- /dev/null
+++ b/src/testdir/test11.ok
@@ -0,0 +1,61 @@
+startstart
+start of testfile
+line 2 Abcdefghijklmnopqrstuvwxyz
+line 3 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+line 4 Abcdefghijklmnopqrstuvwxyz
+line 5 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+line 6 Abcdefghijklmnopqrstuvwxyz
+line 7 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+line 8 Abcdefghijklmnopqrstuvwxyz
+line 9 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+line 10 Abcdefghijklmnopqrstuvwxyz
+end of testfile
+
+start of test.c
+/*
+ * Here is a new .c file
+ */
+end of test.c
+start of testfile
+line 2 Abcdefghijklmnopqrstuvwxyz
+line 3 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+line 4 Abcdefghijklmnopqrstuvwxyz
+linE 5 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+linE 6 AbcdefghijklmnopqrstuvwXyz
+linE 7 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+linE 8 AbcdefghijklmnopqrstuvwXyz
+linE 9 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+linE 10 AbcdefghijklmnopqrstuvwXyz
+End of testfile
+
+/*
+ * HEre is a NEW .c file
+ */
+/*
+ * HEre is a new .c file
+ */
+start of tEstfile
+linE 2 AbcdefghijklmnopqrstuvwXyz
+linE 3 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+linE 4 AbcdefghijklmnopqrstuvwXyz
+linE 5 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+linE 6 AbcdefghijklmnopqrstuvwXyz
+linE 7 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+linE 8 AbcdefghijklmnopqrstuvwXyz
+linE 9 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+linE 10 AbcdefghijklmnopqrstuvwXyz
+End of testfile
+/*
+ * HEre is a new .c file
+ */
+start of testfiLe
+Line 2 Abcdefghijklmnopqrstuvwxyz
+Line 3 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+Line 4 Abcdefghijklmnopqrstuvwxyz
+Line 5 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+Line 6 Abcdefghijklmnopqrstuvwxyz
+Line 7 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+Line 8 Abcdefghijklmnopqrstuvwxyz
+Line 9 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+Line 10 Abcdefghijklmnopqrstuvwxyz
+end of testfiLe
diff --git a/src/testdir/test14.in b/src/testdir/test14.in
new file mode 100644
index 0000000..3fc39fe
--- /dev/null
+++ b/src/testdir/test14.in
@@ -0,0 +1,100 @@
+Tests for "vaBiB", end could be wrong.
+Also test ":s/pat/sub/" with different ~s in sub.
+Also test for ^Vxff and ^Vo123 in Insert mode.
+Also test "[m", "]m", "[M" and "]M"
+Also test search()
+
+STARTTEST
+:so small.vim
+:set belloff=all
+/Start cursor here
+vaBiBD:?Bug?,/Piece/-2w! test.out
+/^- Bug
+:s/u/~u~/
+:s/i/~u~/
+:s/o/~~~/
+:.w >>test.out
+:if has("ebcdic")
+: let tt = "o\<C-V>193\<C-V>xc2\<C-V>o303 \<C-V>90a\<C-V>xfg\<C-V>o578\<Esc>"
+:else
+: let tt = "o\<C-V>65\<C-V>x42\<C-V>o103 \<C-V>33a\<C-V>xfg\<C-V>o78\<Esc>"
+:endif
+:exe "normal " . tt
+:unlet tt
+:.w >>test.out
+:set vb
+/^Piece
+2]maA:.w >>test.out
+j]maB:.w >>test.out
+]maC:.w >>test.out
+[maD:.w >>test.out
+k2[maE:.w >>test.out
+3[maF:.w >>test.out
+]MaG:.w >>test.out
+j2]MaH:.w >>test.out
+]M]MaI:.w >>test.out
+2[MaJ:.w >>test.out
+k[MaK:.w >>test.out
+3[MaL:.w >>test.out
+:"
+/^foobar
+:let startline = line('.')
+:call search('foobar', 'c')
+:call append(line('$'), line('.') - startline)
+j:call search('^$', 'c')
+:call append(line('$'), line('.') - startline)
+:call search('^$', 'bc')
+:call append(line('$'), line('.') - startline)
+/two
+:call search('.', 'c')
+:call append(line('$'), getline('.')[col('.') - 1:])
+:"
+/^substitute
+:s/foo/bar/
+:$put =@/
+/^substitute
+:keeppatterns s/asdf/xyz/
+:$put =@/
+/^substitute
+Y:$put =@0
+/bar /e
+:$put =@0
+-:keeppatterns /xyz
+0dn:/^search()/,$w >>test.out
+:qa!
+ENDTEST
+
+- Bug in "vPPPP" on this text (Webb):
+ {
+ cmd;
+ {
+ cmd; /* <-- Start cursor here */
+ {
+ }
+ }
+ }
+
+Piece of Java
+{
+ tt m1 {
+ t1;
+ } e1
+
+ tt m2 {
+ t2;
+ } e2
+
+ tt m3 {
+ if (x)
+ {
+ t3;
+ }
+ } e3
+}
+
+foobar
+
+substitute foo asdf
+
+one two
+search()
diff --git a/src/testdir/test14.ok b/src/testdir/test14.ok
new file mode 100644
index 0000000..0aa2db3
--- /dev/null
+++ b/src/testdir/test14.ok
@@ -0,0 +1,26 @@
+- Bug in "vPPPP" on this text (Webb):
+ {
+ }
+- Bug uuun "vPPPP" uuuuuuuuun this text (Webb):
+ABC !ag8
+ tt m1 {A
+ tt m2 {B
+ tt m3 {C
+ tt m3 {DC
+ tt m1 {EA
+{F
+ }G e1
+ }H e3
+}I
+ }JH e3
+ }K e2
+{LF
+search()
+0
+1
+1
+two
+foo
+^substitute
+substitute bar xyz
+xyz
diff --git a/src/testdir/test17.in b/src/testdir/test17.in
new file mode 100644
index 0000000..59b57c2
--- /dev/null
+++ b/src/testdir/test17.in
@@ -0,0 +1,135 @@
+Tests for:
+- "gf" on ${VAR},
+- ":checkpath!" with various 'include' settings.
+
+STARTTEST
+:so small.vim
+:if has("ebcdic")
+: set isfname=@,240-249,/,.,-,_,+,,,$,:,~,{,}
+:else
+: set isfname=@,48-57,/,.,-,_,+,,,$,:,~,{,}
+:endif
+:"
+:if has("unix")
+:let $CDIR = "."
+/CDIR
+:else
+:if has("amiga")
+:let $TDIR = "/testdir"
+:else
+:let $TDIR = "."
+:endif
+/TDIR
+:endif
+:" Dummy writing for making that sure gf doesn't fail even if the current
+:" file is modified. It can be occurred when executing the following command
+:" directly on Windows without fixing the 'fileformat':
+:" > nmake -f Make_dos.mak test17.out
+:w! test.out
+gf
+:set ff=unix
+:w! test.out
+:brewind
+ENDTEST
+
+ ${CDIR}/test17a.in
+ $TDIR/test17a.in
+
+STARTTEST
+:" check for 'include' without \zs or \ze
+:lang C
+:call delete("./Xbase.a")
+:call delete("Xdir1", "rf")
+:!mkdir Xdir1
+:!mkdir "Xdir1/dir2"
+:e! Xdir1/dir2/foo.a
+i#include "bar.a":
+:w
+:e Xdir1/dir2/bar.a
+i#include "baz.a":
+:w
+:e Xdir1/dir2/baz.a
+i#include "foo.a":
+:w
+:e Xbase.a
+:set path=Xdir1/dir2
+i#include <foo.a>:
+:w
+:redir! >>test.out
+:checkpath!
+:redir END
+:brewind
+ENDTEST
+
+STARTTEST
+:" check for 'include' with \zs and \ze
+:call delete("./Xbase.b")
+:call delete("Xdir1", "rf")
+:!mkdir Xdir1
+:!mkdir "Xdir1/dir2"
+:let &include='^\s*%inc\s*/\zs[^/]\+\ze'
+:function! DotsToSlashes()
+: return substitute(v:fname, '\.', '/', 'g') . '.b'
+:endfunction
+:let &includeexpr='DotsToSlashes()'
+:e! Xdir1/dir2/foo.b
+i%inc /bar/:
+:w
+:e Xdir1/dir2/bar.b
+i%inc /baz/:
+:w
+:e Xdir1/dir2/baz.b
+i%inc /foo/:
+:w
+:e Xbase.b
+:set path=Xdir1/dir2
+i%inc /foo/:
+:w
+:redir! >>test.out
+:checkpath!
+:redir END
+:brewind
+ENDTEST
+
+STARTTEST
+:" check for 'include' with \zs and no \ze
+:call delete("./Xbase.c")
+:call delete("Xdir1", "rf")
+:!mkdir Xdir1
+:!mkdir "Xdir1/dir2"
+:let &include='^\s*%inc\s*\%([[:upper:]][^[:space:]]*\s\+\)\?\zs\S\+\ze'
+:function! StripNewlineChar()
+: if v:fname =~ '\n$'
+: return v:fname[:-2]
+: endif
+: return v:fname
+:endfunction
+:let &includeexpr='StripNewlineChar()'
+:e! Xdir1/dir2/foo.c
+i%inc bar.c:
+:w
+:e Xdir1/dir2/bar.c
+i%inc baz.c:
+:w
+:e Xdir1/dir2/baz.c
+i%inc foo.c:
+:w
+:e Xdir1/dir2/FALSE.c
+i%inc foo.c:
+:w
+:e Xbase.c
+:set path=Xdir1/dir2
+i%inc FALSE.c foo.c:
+:w
+:redir! >>test.out
+:checkpath!
+:redir END
+:brewind
+:" change "\" to "/" for Windows and fix 'fileformat'
+:e test.out
+:%s#\\#/#g
+:set ff&
+:w
+:q
+ENDTEST
+
diff --git a/src/testdir/test17.ok b/src/testdir/test17.ok
new file mode 100644
index 0000000..b2a66d5
--- /dev/null
+++ b/src/testdir/test17.ok
@@ -0,0 +1,33 @@
+This file is just to test "gf" in test 17.
+The contents is not important.
+Just testing!
+
+
+--- Included files in path ---
+Xdir1/dir2/foo.a
+Xdir1/dir2/foo.a -->
+ Xdir1/dir2/bar.a
+ Xdir1/dir2/bar.a -->
+ Xdir1/dir2/baz.a
+ Xdir1/dir2/baz.a -->
+ "foo.a" (Already listed)
+
+
+--- Included files in path ---
+Xdir1/dir2/foo.b
+Xdir1/dir2/foo.b -->
+ Xdir1/dir2/bar.b
+ Xdir1/dir2/bar.b -->
+ Xdir1/dir2/baz.b
+ Xdir1/dir2/baz.b -->
+ foo (Already listed)
+
+
+--- Included files in path ---
+Xdir1/dir2/foo.c
+Xdir1/dir2/foo.c -->
+ Xdir1/dir2/bar.c
+ Xdir1/dir2/bar.c -->
+ Xdir1/dir2/baz.c
+ Xdir1/dir2/baz.c -->
+ foo.c (Already listed)
diff --git a/src/testdir/test17a.in b/src/testdir/test17a.in
new file mode 100644
index 0000000..7e89364
--- /dev/null
+++ b/src/testdir/test17a.in
@@ -0,0 +1,3 @@
+This file is just to test "gf" in test 17.
+The contents is not important.
+Just testing!
diff --git a/src/testdir/test29.in b/src/testdir/test29.in
new file mode 100644
index 0000000..366a551
--- /dev/null
+++ b/src/testdir/test29.in
@@ -0,0 +1,231 @@
+Test for joining lines and marks in them
+ in compatible and nocompatible modes
+ and with 'joinspaces' set or not
+ and with 'cpoptions' flag 'j' set or not
+
+STARTTEST
+:so small.vim
+:set nocompatible viminfo+=nviminfo
+:set nojoinspaces
+:set cpoptions-=j
+/firstline/
+j"td/^STARTTEST/-1
+PJjJjJjJjJjJjJjJjJjJjJjJjJjJj05lmx2j06lmy2k4Jy3l$p`xyl$p`yy2l$p:set cpoptions+=j
+j05lmx2j06lmy2k4Jy3l$p`xyl$p`yy2l$p:set cpoptions-=j joinspaces
+j"tpJjJjJjJjJjJjJjJjJjJjJjJjJjJj05lmx2j06lmy2k4Jy3l$p`xyl$p`yy2l$p:set cpoptions+=j
+j05lmx2j06lmy2k4Jy3l$p`xyl$p`yy2l$p:set cpoptions-=j nojoinspaces compatible
+j"tpJjJjJjJjJjJjJjJjJjJjJjJjJjJj4Jy3l$pjd/STARTTEST/-2
+ENDTEST
+
+firstline
+asdfasdf.
+asdf
+asdfasdf.
+asdf
+asdfasdf.
+asdf
+asdfasdf.
+asdf
+asdfasdf.
+asdf
+asdfasdf.
+asdf
+asdfasdf.
+asdf
+asdfasdf
+asdf
+asdfasdf
+asdf
+asdfasdf
+asdf
+asdfasdf
+asdf
+asdfasdf
+asdf
+asdfasdf
+asdf
+asdfasdf
+asdf
+zx cvn.
+as dfg?
+hjkl iop!
+ert
+zx cvn.
+as dfg?
+hjkl iop!
+ert
+
+STARTTEST
+/^{/+1
+:set comments=s1:/*,mb:*,ex:*/,://
+:set nojoinspaces fo=j
+:set backspace=eol,start
+:.,+3join
+j4J
+:.,+2join
+j3J
+:.,+2join
+j3J
+:.,+2join
+jj3J
+ENDTEST
+
+{
+
+/*
+ * Make sure the previous comment leader is not removed.
+ */
+
+/*
+ * Make sure the previous comment leader is not removed.
+ */
+
+// Should the next comment leader be left alone?
+// Yes.
+
+// Should the next comment leader be left alone?
+// Yes.
+
+/* Here the comment leader should be left intact. */
+// And so should this one.
+
+/* Here the comment leader should be left intact. */
+// And so should this one.
+
+if (condition) // Remove the next comment leader!
+ // OK, I will.
+ action();
+
+if (condition) // Remove the next comment leader!
+ // OK, I will.
+ action();
+}
+
+STARTTEST
+:" Test with backspace set to the non-compatible setting
+:set belloff=all
+/^\d\+ this
+:set cp bs=2
+Avim1
+Avim2u
+:set cpo-=<
+:inoremap <c-u> <left><c-u>
+Avim3
+:iunmap <c-u>
+Avim4
+:" Test with backspace set to the compatible setting
+:set backspace= visualbell
+A vim5A
+A vim6Azweiu
+:inoremap <c-u> <left><c-u>
+A vim7
+:set compatible novisualbell
+ENDTEST
+1 this shouldn't be deleted
+2 this shouldn't be deleted
+3 this shouldn't be deleted
+4 this should be deleted
+5 this shouldn't be deleted
+6 this shouldn't be deleted
+7 this shouldn't be deleted
+8 this shouldn't be deleted (not touched yet)
+
+STARTTEST
+/^{/+1
+:set comments=sO:*\ -,mO:*\ \ ,exO:*/
+:set comments+=s1:/*,mb:*,ex:*/,://
+:set comments+=s1:>#,mb:#,ex:#<,:<
+:set cpoptions-=j joinspaces fo=j
+:set backspace=eol,start
+:.,+3join
+j4J
+:.,+8join
+j9J
+:.,+2join
+j3J
+:.,+2join
+j3J
+:.,+2join
+jj3J
+j:.,+2join
+jj3J
+j:.,+5join
+j6J
+oSome code! // Make sure backspacing does not remove this comment leader.0i
+ENDTEST
+
+{
+
+/*
+ * Make sure the previous comment leader is not removed.
+ */
+
+/*
+ * Make sure the previous comment leader is not removed.
+ */
+
+/* List:
+ * - item1
+ * foo bar baz
+ * foo bar baz
+ * - item2
+ * foo bar baz
+ * foo bar baz
+ */
+
+/* List:
+ * - item1
+ * foo bar baz
+ * foo bar baz
+ * - item2
+ * foo bar baz
+ * foo bar baz
+ */
+
+// Should the next comment leader be left alone?
+// Yes.
+
+// Should the next comment leader be left alone?
+// Yes.
+
+/* Here the comment leader should be left intact. */
+// And so should this one.
+
+/* Here the comment leader should be left intact. */
+// And so should this one.
+
+if (condition) // Remove the next comment leader!
+ // OK, I will.
+ action();
+
+if (condition) // Remove the next comment leader!
+ // OK, I will.
+ action();
+
+int i = 7 /* foo *// 3
+ // comment
+ ;
+
+int i = 7 /* foo *// 3
+ // comment
+ ;
+
+># Note that the last character of the ending comment leader (left angle
+ # bracket) is a comment leader itself. Make sure that this comment leader is
+ # not removed from the next line #<
+< On this line a new comment is opened which spans 2 lines. This comment should
+< retain its comment leader.
+
+># Note that the last character of the ending comment leader (left angle
+ # bracket) is a comment leader itself. Make sure that this comment leader is
+ # not removed from the next line #<
+< On this line a new comment is opened which spans 2 lines. This comment should
+< retain its comment leader.
+
+}
+
+STARTTEST
+:g/^STARTTEST/.,/^ENDTEST/d
+:?firstline?+1,$w! test.out
+:qa!
+ENDTEST
diff --git a/src/testdir/test29.ok b/src/testdir/test29.ok
new file mode 100644
index 0000000..9dc07ed
--- /dev/null
+++ b/src/testdir/test29.ok
@@ -0,0 +1,97 @@
+asdfasdf. asdf
+asdfasdf. asdf
+asdfasdf. asdf
+asdfasdf. asdf
+asdfasdf. asdf
+asdfasdf. asdf
+asdfasdf. asdf
+asdfasdf asdf
+asdfasdf asdf
+asdfasdf asdf
+asdfasdf asdf
+asdfasdf asdf
+asdfasdf asdf
+asdfasdf asdf
+zx cvn. as dfg? hjkl iop! ert ernop
+zx cvn. as dfg? hjkl iop! ert ernop
+
+asdfasdf. asdf
+asdfasdf. asdf
+asdfasdf. asdf
+asdfasdf. asdf
+asdfasdf. asdf
+asdfasdf. asdf
+asdfasdf. asdf
+asdfasdf asdf
+asdfasdf asdf
+asdfasdf asdf
+asdfasdf asdf
+asdfasdf asdf
+asdfasdf asdf
+asdfasdf asdf
+zx cvn. as dfg? hjkl iop! ert enop
+zx cvn. as dfg? hjkl iop! ert ernop
+
+asdfasdf. asdf
+asdfasdf. asdf
+asdfasdf. asdf
+asdfasdf. asdf
+asdfasdf. asdf
+asdfasdf. asdf
+asdfasdf. asdf
+asdfasdf asdf
+asdfasdf asdf
+asdfasdf asdf
+asdfasdf asdf
+asdfasdf asdf
+asdfasdf asdf
+asdfasdf asdf
+zx cvn. as dfg? hjkl iop! ert a
+
+
+{
+/* Make sure the previous comment leader is not removed. */
+/* Make sure the previous comment leader is not removed. */
+// Should the next comment leader be left alone? Yes.
+// Should the next comment leader be left alone? Yes.
+/* Here the comment leader should be left intact. */ // And so should this one.
+/* Here the comment leader should be left intact. */ // And so should this one.
+if (condition) // Remove the next comment leader! OK, I will.
+ action();
+if (condition) // Remove the next comment leader! OK, I will.
+ action();
+}
+
+1 this shouldn't be deleted
+2 this shouldn't be deleted
+3 this shouldn't be deleted
+4 this should be deleted3
+
+6 this shouldn't be deleted vim5
+7 this shouldn't be deleted vim6
+8 this shouldn't be deleted (not touched yet) vim7
+
+
+{
+/* Make sure the previous comment leader is not removed. */
+/* Make sure the previous comment leader is not removed. */
+/* List: item1 foo bar baz foo bar baz item2 foo bar baz foo bar baz */
+/* List: item1 foo bar baz foo bar baz item2 foo bar baz foo bar baz */
+// Should the next comment leader be left alone? Yes.
+// Should the next comment leader be left alone? Yes.
+/* Here the comment leader should be left intact. */ // And so should this one.
+/* Here the comment leader should be left intact. */ // And so should this one.
+if (condition) // Remove the next comment leader! OK, I will.
+ action();
+if (condition) // Remove the next comment leader! OK, I will.
+ action();
+int i = 7 /* foo *// 3 // comment
+ ;
+int i = 7 /* foo *// 3 // comment
+ ;
+># Note that the last character of the ending comment leader (left angle bracket) is a comment leader itself. Make sure that this comment leader is not removed from the next line #< < On this line a new comment is opened which spans 2 lines. This comment should retain its comment leader.
+># Note that the last character of the ending comment leader (left angle bracket) is a comment leader itself. Make sure that this comment leader is not removed from the next line #< < On this line a new comment is opened which spans 2 lines. This comment should retain its comment leader.
+
+Some code!// Make sure backspacing does not remove this comment leader.
+}
+
diff --git a/src/testdir/test3.in b/src/testdir/test3.in
new file mode 100644
index 0000000..646fbb3
--- /dev/null
+++ b/src/testdir/test3.in
@@ -0,0 +1,2354 @@
+/* vim: set cin ts=4 sw=4 : */
+
+Test for 'cindent'.
+For new tests, consider putting them in test_cindent.vim.
+
+STARTTEST
+:so small.vim
+:set nocompatible viminfo+=nviminfo modeline
+:edit " read modeline
+/start of AUTO
+=/end of AUTO
+ENDTEST
+
+/* start of AUTO matically checked vim: set ts=4 : */
+{
+ if (test)
+ cmd1;
+ cmd2;
+}
+
+{
+ if (test)
+ cmd1;
+ else
+ cmd2;
+}
+
+{
+ if (test)
+ {
+ cmd1;
+ cmd2;
+ }
+}
+
+{
+ if (test)
+ {
+ cmd1;
+ else
+ }
+}
+
+{
+ while (this)
+ if (test)
+ cmd1;
+ cmd2;
+}
+
+{
+ while (this)
+ if (test)
+ cmd1;
+ else
+ cmd2;
+}
+
+{
+ if (test)
+ {
+ cmd;
+ }
+
+ if (test)
+ cmd;
+}
+
+{
+ if (test) {
+ cmd;
+ }
+
+ if (test) cmd;
+}
+
+{
+ cmd1;
+ for (blah)
+ while (this)
+ if (test)
+ cmd2;
+ cmd3;
+}
+
+{
+ cmd1;
+ for (blah)
+ while (this)
+ if (test)
+ cmd2;
+ cmd3;
+
+ if (test)
+ {
+ cmd1;
+ cmd2;
+ cmd3;
+ }
+}
+
+
+/* Test for 'cindent' do/while mixed with if/else: */
+
+{
+ do
+ if (asdf)
+ asdfasd;
+ while (cond);
+
+ do
+ if (asdf)
+ while (asdf)
+ asdf;
+ while (asdf);
+}
+
+/* Test for 'cindent' with two ) on a continuation line */
+{
+ if (asdfasdf;asldkfj asdlkfj as;ldkfj sal;d
+ aal;sdkjf ( ;asldfkja;sldfk
+ al;sdjfka ;slkdf ) sa;ldkjfsa dlk;)
+ line up here;
+}
+
+
+/* C++ tests: */
+
+// foo() these three lines should remain in column 0
+// {
+// }
+
+/* Test for continuation and unterminated lines: */
+{
+ i = 99 + 14325 +
+ 21345 +
+ 21345 +
+ 21345 + ( 21345 +
+ 21345) +
+ 2345 +
+ 1234;
+ c = 1;
+}
+
+/*
+ testje for indent with empty line
+
+ here */
+
+{
+ if (testing &&
+ not a joke ||
+ line up here)
+ hay;
+ if (testing &&
+ (not a joke || testing
+ )line up here)
+ hay;
+ if (testing &&
+ (not a joke || testing
+ line up here))
+ hay;
+}
+
+
+{
+ switch (c)
+ {
+ case xx:
+ do
+ if (asdf)
+ do
+ asdfasdf;
+ while (asdf);
+ else
+ asdfasdf;
+ while (cond);
+ case yy:
+ case xx:
+ case zz:
+ testing;
+ }
+}
+
+{
+ if (cond) {
+ foo;
+ }
+ else
+ {
+ bar;
+ }
+}
+
+{
+ if (alskdfj ;alsdkfjal;skdjf (;sadlkfsa ;dlkf j;alksdfj ;alskdjf
+ alsdkfj (asldk;fj
+ awith cino=(0 ;lf this one goes to below the paren with ==
+ ;laksjfd ;lsakdjf ;alskdf asd)
+ asdfasdf;)))
+ asdfasdf;
+}
+
+ int
+func(a, b)
+ int a;
+ int c;
+{
+ if (c1 && (c2 ||
+ c3))
+ foo;
+ if (c1 &&
+ (c2 || c3)
+ )
+}
+
+{
+ while (asd)
+ {
+ if (asdf)
+ if (test)
+ if (that)
+ {
+ if (asdf)
+ do
+ cdasd;
+ while (as
+ df);
+ }
+ else
+ if (asdf)
+ asdf;
+ else
+ asdf;
+ asdf;
+ }
+}
+
+{
+ s = "/*"; b = ';'
+ s = "/*"; b = ';';
+ a = b;
+}
+
+{
+ switch (a)
+ {
+ case a:
+ switch (t)
+ {
+ case 1:
+ cmd;
+ break;
+ case 2:
+ cmd;
+ break;
+ }
+ cmd;
+ break;
+ case b:
+ {
+ int i;
+ cmd;
+ }
+ break;
+ case c: {
+ int i;
+ cmd;
+ }
+ case d: if (cond &&
+ test) { /* this line doesn't work right */
+ int i;
+ cmd;
+ }
+ break;
+ }
+}
+
+{
+ if (!(vim_strchr(p_cpo, CPO_BUFOPTGLOB) != NULL && entering) &&
+ (bp_to->b_p_initialized ||
+ (!entering && vim_strchr(p_cpo, CPO_BUFOPT) != NULL)))
+ return;
+label :
+ asdf = asdf ?
+ asdf : asdf;
+ asdf = asdf ?
+ asdf: asdf;
+}
+
+/* Special Comments : This function has the added complexity (compared */
+/* : to addtolist) of having to check for a detail */
+/* : texture and add that to the list first. */
+
+char *(array[100]) = {
+ "testje",
+ "foo",
+ "bar",
+}
+
+enum soppie
+{
+yes = 0,
+no,
+maybe
+};
+
+typedef enum soppie
+{
+yes = 0,
+no,
+maybe
+};
+
+static enum
+{
+yes = 0,
+no,
+maybe
+} soppie;
+
+public static enum
+{
+yes = 0,
+no,
+maybe
+} soppie;
+
+static private enum
+{
+yes = 0,
+no,
+maybe
+} soppie;
+
+{
+ int a,
+ b;
+}
+
+{
+ struct Type
+ {
+ int i;
+ char *str;
+ } var[] =
+ {
+ 0, "zero",
+ 1, "one",
+ 2, "two",
+ 3, "three"
+ };
+
+ float matrix[3][3] =
+ {
+ {
+ 0,
+ 1,
+ 2
+ },
+ {
+ 3,
+ 4,
+ 5
+ },
+ {
+ 6,
+ 7,
+ 8
+ }
+ };
+}
+
+{
+ /* blah ( blah */
+ /* where does this go? */
+
+ /* blah ( blah */
+ cmd;
+
+ func(arg1,
+ /* comment */
+ arg2);
+ a;
+ {
+ b;
+ {
+ c; /* Hey, NOW it indents?! */
+ }
+ }
+
+ {
+ func(arg1,
+ arg2,
+ arg3);
+ /* Hey, what am I doing here? Is this coz of the ","? */
+ }
+}
+
+main ()
+{
+ if (cond)
+ {
+ a = b;
+ }
+ if (cond) {
+ a = c;
+ }
+ if (cond)
+ a = d;
+ return;
+}
+
+{
+ case 2: if (asdf &&
+ asdfasdf)
+ aasdf;
+ a = 9;
+ case 3: if (asdf)
+ aasdf;
+ a = 9;
+ case 4: x = 1;
+ y = 2;
+
+label: if (asdf)
+ here;
+
+label: if (asdf &&
+ asdfasdf)
+ {
+ }
+
+label: if (asdf &&
+ asdfasdf) {
+ there;
+ }
+
+label: if (asdf &&
+ asdfasdf)
+ there;
+}
+
+{
+ /*
+ hello with ":set comments= cino=c5"
+ */
+
+ /*
+ hello with ":set comments= cino="
+ */
+}
+
+
+{
+ if (a < b) {
+ a = a + 1;
+ } else
+ a = a + 2;
+
+ if (a)
+ do {
+ testing;
+ } while (asdfasdf);
+ a = b + 1;
+ asdfasdf
+}
+
+{
+for ( int i = 0;
+ i < 10; i++ )
+{
+}
+ i = 0;
+}
+
+class bob
+{
+ int foo() {return 1;}
+ int bar;
+}
+
+main()
+{
+while(1)
+if (foo)
+{
+bar;
+}
+else {
+asdf;
+}
+misplacedline;
+}
+
+{
+ if (clipboard.state == SELECT_DONE
+ && ((row == clipboard.start.lnum
+ && col >= clipboard.start.col)
+ || row > clipboard.start.lnum))
+}
+
+{
+if (1) {i += 4;}
+where_am_i;
+return 0;
+}
+
+{
+{
+} // sdf(asdf
+if (asdf)
+asd;
+}
+
+{
+label1:
+label2:
+}
+
+{
+int fooRet = foo(pBar1, false /*fKB*/,
+ true /*fPTB*/, 3 /*nT*/, false /*fDF*/);
+f() {
+for ( i = 0;
+ i < m;
+ /* c */ i++ ) {
+a = b;
+}
+}
+}
+
+{
+ f1(/*comment*/);
+ f2();
+}
+
+{
+do {
+if (foo) {
+} else
+;
+} while (foo);
+foo(); // was wrong
+}
+
+int x; // no extra indent because of the ;
+void func()
+{
+}
+
+char *tab[] = {"aaa",
+ "};", /* }; */ NULL}
+ int indented;
+{}
+
+char *a[] = {"aaa", "bbb",
+ "ccc", NULL};
+// here
+
+char *tab[] = {"aaa",
+ "xx", /* xx */}; /* asdf */
+int not_indented;
+
+{
+ do {
+ switch (bla)
+ {
+ case 1: if (foo)
+ bar;
+ }
+ } while (boo);
+ wrong;
+}
+
+int foo,
+ bar;
+int foo;
+
+#if defined(foo) \
+ && defined(bar)
+char * xx = "asdf\
+ foo\
+ bor";
+int x;
+
+char *foo = "asdf\
+ asdf\
+ asdf",
+ *bar;
+
+void f()
+{
+#if defined(foo) \
+ && defined(bar)
+char *foo = "asdf\
+ asdf\
+ asdf",
+ *bar;
+ {
+ int i;
+char *foo = "asdf\
+ asdf\
+ asdf",
+ *bar;
+ }
+#endif
+}
+#endif
+
+int y; // comment
+ // comment
+
+ // comment
+
+{
+ Constructor(int a,
+ int b ) : BaseClass(a)
+ {
+ }
+}
+
+void foo()
+{
+ char one,
+ two;
+ struct bla piet,
+ jan;
+ enum foo kees,
+ jannie;
+ static unsigned sdf,
+ krap;
+ unsigned int piet,
+ jan;
+ int
+ kees,
+ jan;
+}
+
+{
+ t(int f,
+ int d); // )
+ d();
+}
+
+Constructor::Constructor(int a,
+ int b
+ ) :
+ BaseClass(a,
+ b,
+ c),
+ mMember(b),
+{
+}
+
+Constructor::Constructor(int a,
+ int b ) :
+ BaseClass(a)
+{
+}
+
+Constructor::Constructor(int a,
+ int b ) /*x*/ : /*x*/ BaseClass(a),
+ member(b)
+{
+}
+
+A::A(int a, int b)
+: aa(a),
+bb(b),
+cc(c)
+{
+}
+
+class CAbc :
+ public BaseClass1,
+ protected BaseClass2
+{
+ int Test() { return FALSE; }
+ int Test1() { return TRUE; }
+
+ CAbc(int a, int b ) :
+ BaseClass(a)
+ {
+ switch(xxx)
+ {
+ case abc:
+ asdf();
+ break;
+
+ case 999:
+ baer();
+ break;
+ }
+ }
+
+public: // <-- this was incoreectly indented before!!
+ void testfall();
+protected:
+ void testfall();
+};
+
+class CAbc : public BaseClass1,
+ protected BaseClass2
+{
+};
+
+static struct
+{
+ int a;
+ int b;
+} variable[COUNT] =
+{
+ {
+ 123,
+ 456
+ },
+ {
+ 123,
+ 456
+ }
+};
+
+static struct
+{
+ int a;
+ int b;
+} variable[COUNT] =
+{
+ { 123, 456 },
+ { 123, 456 }
+};
+
+void asdf() /* ind_maxparen may cause trouble here */
+{
+ if ((0
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1)) break;
+}
+
+foo()
+{
+ a = cond ? foo() : asdf
+ + asdf;
+
+ a = cond ?
+ foo() : asdf
+ + asdf;
+}
+
+int main(void)
+{
+ if (a)
+ if (b)
+ 2;
+ else 3;
+ next_line_of_code();
+}
+
+barry()
+{
+ Foo::Foo (int one,
+ int two)
+ : something(4)
+ {}
+}
+
+barry()
+{
+ Foo::Foo (int one, int two)
+ : something(4)
+ {}
+}
+
+Constructor::Constructor(int a,
+ int b
+ ) :
+ BaseClass(a,
+ b,
+ c),
+ mMember(b)
+{
+}
+ int main ()
+ {
+ if (lala)
+ do
+ ++(*lolo);
+ while (lili
+ && lele);
+ lulu;
+ }
+
+int main ()
+{
+switch (c)
+{
+case 'c': if (cond)
+{
+}
+}
+}
+
+main()
+{
+ (void) MyFancyFuasdfadsfnction(
+ argument);
+}
+
+main()
+{
+ char foo[] = "/*";
+ /* as
+ df */
+ hello
+}
+
+/* valid namespaces with normal indent */
+namespace
+{
+{
+ 111111111111;
+}
+}
+namespace /* test */
+{
+ 11111111111111111;
+}
+namespace // test
+{
+ 111111111111111111;
+}
+namespace
+{
+ 111111111111111111;
+}
+namespace test
+{
+ 111111111111111111;
+}
+namespace{
+ 111111111111111111;
+}
+namespace test{
+ 111111111111111111;
+}
+namespace {
+ 111111111111111111;
+}
+namespace test {
+ 111111111111111111;
+namespace test2 {
+ 22222222222222222;
+}
+}
+
+/* invalid namespaces use block indent */
+namespace test test2 {
+ 111111111111111111111;
+}
+namespace11111111111 {
+ 111111111111;
+}
+namespace() {
+ 1111111111111;
+}
+namespace()
+{
+ 111111111111111111;
+}
+namespace test test2
+{
+ 1111111111111111111;
+}
+namespace111111111
+{
+ 111111111111111111;
+}
+
+void getstring() {
+/* Raw strings */
+const char* s = R"(
+ test {
+ # comment
+ field: 123
+ }
+ )";
+ }
+
+void getstring() {
+const char* s = R"foo(
+ test {
+ # comment
+ field: 123
+ }
+ )foo";
+ }
+
+{
+int a[4] = {
+[0] = 0,
+[1] = 1,
+[2] = 2,
+[3] = 3,
+};
+}
+
+{
+a = b[2]
++ 3;
+}
+
+{
+if (1)
+/* aaaaa
+* bbbbb
+*/
+a = 1;
+}
+
+void func()
+{
+switch (foo)
+{
+case (bar):
+if (baz())
+quux();
+break;
+case (shmoo):
+if (!bar)
+{
+}
+case (foo1):
+switch (bar)
+{
+case baz:
+baz_f();
+break;
+}
+break;
+default:
+baz();
+baz();
+break;
+}
+}
+
+/* end of AUTO */
+
+STARTTEST
+:set tw=0 noai fo=croq
+:let &wm = &columns - 20
+/serious/e
+a about life, the universe, and the rest
+ENDTEST
+
+{
+
+/* this is
+ * a real serious important big
+ * comment
+ */
+ /* insert " about life, the universe, and the rest" after "serious" */
+}
+
+STARTTEST
+:set nocin
+/comments
+joabout life/happens
+jothere/below
+oline/this
+Ohello
+ENDTEST
+
+{
+ /*
+ * Testing for comments, without 'cin' set
+ */
+
+/*
+* what happens here?
+*/
+
+ /*
+ the end of the comment, try inserting a line below */
+
+ /* how about
+ this one */
+}
+
+STARTTEST
+:set cin
+/vec2
+==
+ENDTEST
+
+{
+ var = this + that + vec[0] * vec[0]
+ + vec[1] * vec[1]
+ + vec2[2] * vec[2];
+}
+
+STARTTEST
+:set cin
+:set cino=}4
+/testing1
+k2==/testing2
+k2==
+ENDTEST
+
+{
+ asdf asdflkajds f;
+ if (tes & ting) {
+ asdf asdf asdf ;
+ asdfa sdf asdf;
+ }
+ testing1;
+ if (tes & ting)
+ {
+ asdf asdf asdf ;
+ asdfa sdf asdf;
+ }
+ testing2;
+}
+
+STARTTEST
+:set cin
+:set cino=(0,)20
+/main
+=][
+ENDTEST
+
+main ( int first_par, /*
+ * Comment for
+ * first par
+ */
+ int second_par /*
+ * Comment for
+ * second par
+ */
+ )
+{
+ func( first_par, /*
+ * Comment for
+ * first par
+ */
+ second_par /*
+ * Comment for
+ * second par
+ */
+ );
+
+}
+
+STARTTEST
+:set cin
+:set cino=es,n0s
+/main
+=][
+ENDTEST
+
+main(void)
+{
+ /* Make sure that cino=X0s is not parsed like cino=Xs. */
+ if (cond)
+ foo();
+ else
+ {
+ bar();
+ }
+}
+
+STARTTEST
+:set cin
+:set cino=
+]]=][
+ENDTEST
+
+{
+ do
+ {
+ if ()
+ {
+ if ()
+ asdf;
+ else
+ asdf;
+ }
+ } while ();
+ cmd; /* this should go under the } */
+}
+
+STARTTEST
+]]=][
+ENDTEST
+
+void f()
+{
+ if ( k() ) {
+ l();
+
+ } else { /* Start (two words) end */
+ m();
+ }
+
+ n();
+}
+
+STARTTEST
+:set cino={s,e-s
+]]=][
+ENDTEST
+
+void f()
+{
+ if ( k() )
+ {
+ l();
+ } else { /* Start (two words) end */
+ m();
+ }
+ n(); /* should be under the if () */
+}
+
+STARTTEST
+:set cino={s,fs
+]]=/ foo
+ENDTEST
+
+void bar(void)
+{
+ static array[2][2] =
+ {
+ { 1, 2 },
+ { 3, 4 },
+ }
+
+ while (a)
+ {
+ foo(&a);
+ }
+
+ {
+ int a;
+ {
+ a = a + 1;
+ }
+ }
+ b = a;
+ }
+
+void func(void)
+ {
+ a = 1;
+ {
+ b = 2;
+ }
+ c = 3;
+ d = 4;
+ }
+/* foo */
+
+STARTTEST
+:set cino=
+/while
+ohere
+ENDTEST
+
+a()
+{
+ do {
+ a = a +
+ a;
+ } while ( a ); /* add text under this line */
+ if ( a )
+ a;
+}
+
+STARTTEST
+:set cino= com=
+/comment
+olabel2: b(); label3 /* post */: /* pre */ label4: f(/*com*/); if (/*com*/) cmd();
+ENDTEST
+
+a()
+{
+label1:
+ /* hmm */
+ // comment
+}
+
+STARTTEST
+:set comments& comments^=s:/*,m:**,ex:*/
+/simple
+=5j
+ENDTEST
+
+/*
+ * A simple comment
+ */
+
+/*
+ ** A different comment
+ */
+
+STARTTEST
+:set cino=c0
+:set comments& comments-=s1:/* comments^=s0:/*
+2kdd]]=][
+ENDTEST
+
+void f()
+{
+
+ /*********
+ A comment.
+*********/
+}
+
+STARTTEST
+:set cino=c0,C1
+:set comments& comments-=s1:/* comments^=s0:/*
+2kdd]]=][
+ENDTEST
+
+void f()
+{
+
+ /*********
+ A comment.
+*********/
+}
+
+STARTTEST
+:set cino=
+]]=][
+ENDTEST
+
+void f()
+{
+ c = c1 &&
+ (
+ c2 ||
+ c3
+ ) && c4;
+}
+
+STARTTEST
+:set cino=(s
+2kdd]]=][
+ENDTEST
+
+void f()
+{
+ c = c1 &&
+ (
+ c2 ||
+ c3
+ ) && c4;
+}
+
+STARTTEST
+:set cino=(s,U1
+2kdd]]=][
+ENDTEST
+
+void f()
+{
+ c = c1 &&
+ (
+ c2 ||
+ c3
+ ) && c4;
+}
+
+STARTTEST
+:set cino=(0
+2kdd]]=][
+ENDTEST
+
+void f()
+{
+ if ( c1
+ && ( c2
+ || c3))
+ foo;
+}
+
+STARTTEST
+:set cino=(0,w1
+2kdd]]=][
+ENDTEST
+
+void f()
+{
+ if ( c1
+ && ( c2
+ || c3))
+ foo;
+}
+
+STARTTEST
+:set cino=(s
+2kdd]]=][
+ENDTEST
+
+void f()
+{
+ c = c1 && (
+ c2 ||
+ c3
+ ) && c4;
+ if (
+ c1 && c2
+ )
+ foo;
+}
+
+STARTTEST
+:set cino=(s,m1
+2kdd]]=][
+ENDTEST
+
+void f()
+{
+ c = c1 && (
+ c2 ||
+ c3
+ ) && c4;
+ if (
+ c1 && c2
+ )
+ foo;
+}
+
+STARTTEST
+:set cino=b1
+2kdd]]=][
+ENDTEST
+
+void f()
+{
+ switch (x)
+ {
+ case 1:
+ a = b;
+ break;
+ default:
+ a = 0;
+ break;
+ }
+}
+
+STARTTEST
+:set cino=(0,W5
+2kdd]]=][
+ENDTEST
+
+void f()
+{
+ invokeme(
+ argu,
+ ment);
+ invokeme(
+ argu,
+ ment
+ );
+ invokeme(argu,
+ ment
+ );
+}
+
+STARTTEST
+:set cino=/6
+2kdd]]=][
+ENDTEST
+
+void f()
+{
+ statement;
+ // comment 1
+ // comment 2
+}
+
+STARTTEST
+:set cino=
+2kdd]]/comment 1/+1
+==
+ENDTEST
+
+void f()
+{
+ statement;
+ // comment 1
+ // comment 2
+}
+
+STARTTEST
+:set cino=g0
+2kdd]]=][
+ENDTEST
+
+class CAbc
+{
+ int Test() { return FALSE; }
+
+public: // comment
+ void testfall();
+protected:
+ void testfall();
+};
+
+STARTTEST
+:set cino=(0,gs,hs
+2kdd]]=][
+ENDTEST
+
+class Foo : public Bar
+{
+public:
+virtual void method1(void) = 0;
+virtual void method2(int arg1,
+int arg2,
+int arg3) = 0;
+};
+
+STARTTEST
+:set cino=+20
+2kdd]]=][
+ENDTEST
+
+ void
+foo()
+{
+ if (a)
+ {
+ } else
+ asdf;
+}
+
+STARTTEST
+:set cino=(0,W2s
+2kdd]]=][
+ENDTEST
+
+{
+ averylongfunctionnamelongfunctionnameaverylongfunctionname()->asd(
+ asdasdf,
+ func(asdf,
+ asdfadsf),
+ asdfasdf
+ );
+
+ /* those are ugly, but consequent */
+
+ func()->asd(asdasdf,
+ averylongfunctionname(
+ abc,
+ dec)->averylongfunctionname(
+ asdfadsf,
+ asdfasdf,
+ asdfasdf,
+ ),
+ func(asdfadf,
+ asdfasdf
+ ),
+ asdasdf
+ );
+
+ averylongfunctionnameaverylongfunctionnameavery()->asd(fasdf(
+ abc,
+ dec)->asdfasdfasdf(
+ asdfadsf,
+ asdfasdf,
+ asdfasdf,
+ ),
+ func(asdfadf,
+ asdfasdf),
+ asdasdf
+ );
+}
+
+STARTTEST
+:set cino=M1
+2kdd]]=][
+ENDTEST
+
+int main ()
+{
+ if (cond1 &&
+ cond2
+ )
+ foo;
+}
+
+STARTTEST
+:set cino=(0,ts
+2kdd2j=][
+ENDTEST
+
+void func(int a
+#if defined(FOO)
+ , int b
+ , int c
+#endif
+ )
+{
+}
+
+STARTTEST
+:set cino=(0
+2kdd2j=][
+ENDTEST
+
+void
+func(int a
+#if defined(FOO)
+ , int b
+ , int c
+#endif
+ )
+{
+}
+
+STARTTEST
+:set cino&
+2kdd2j=7][
+ENDTEST
+
+void func(void)
+{
+ if(x==y)
+ if(y==z)
+ foo=1;
+ else { bar=1;
+ baz=2;
+ }
+ printf("Foo!\n");
+}
+
+void func1(void)
+{
+ char* tab[] = {"foo", "bar",
+ "baz", "quux",
+ "this line used", "to be indented incorrectly"};
+ foo();
+}
+
+void func2(void)
+{
+ int tab[] =
+ {1, 2,
+ 3, 4,
+ 5, 6};
+
+ printf("This line used to be indented incorrectly.\n");
+}
+
+int foo[]
+#ifdef BAR
+
+= { 1, 2, 3,
+ 4, 5, 6 }
+
+#endif
+;
+ int baz;
+
+void func3(void)
+{
+ int tab[] = {
+ 1, 2,
+ 3, 4,
+ 5, 6};
+
+printf("Don't you dare indent this line incorrectly!\n");
+}
+
+void
+func4(a, b,
+ c)
+int a;
+int b;
+int c;
+{
+}
+
+void
+func5(
+ int a,
+ int b)
+{
+}
+
+void
+func6(
+ int a)
+{
+}
+
+STARTTEST
+:set cino&
+:set cino+=l1
+2kdd2j=][
+ENDTEST
+
+void func(void)
+{
+ int tab[] =
+ {
+ 1, 2, 3,
+ 4, 5, 6};
+
+ printf("Indent this line correctly!\n");
+
+ switch (foo)
+ {
+ case bar:
+ printf("bar");
+ break;
+ case baz: {
+ printf("baz");
+ break;
+ }
+ case quux:
+printf("But don't break the indentation of this instruction\n");
+break;
+ }
+}
+
+STARTTEST
+:set cino&
+2kdd2j=][
+ENDTEST
+
+void func(void)
+{
+ cout << "a"
+ << "b"
+ << ") :"
+ << "c";
+}
+
+STARTTEST
+:set com=s1:/*,m:*,ex:*/
+]]3jofoo();
+ENDTEST
+
+void func(void)
+{
+ /*
+ * This is a comment.
+ */
+}
+
+STARTTEST
+:set cino&
+2kdd2j=][
+ENDTEST
+
+void func(void)
+{
+ for (int i = 0; i < 10; ++i)
+ if (i & 1) {
+ foo(1);
+ } else
+ foo(0);
+baz();
+}
+
+STARTTEST
+:set cino=k2s,(0
+2kdd3j=][
+ENDTEST
+
+void func(void)
+{
+ if (condition1
+ && condition2)
+ action();
+ function(argument1
+ && argument2);
+
+ if (c1 && (c2 ||
+ c3))
+ foo;
+ if (c1 &&
+ (c2 || c3))
+ {
+ }
+
+ if ( c1
+ && ( c2
+ || c3))
+ foo;
+ func( c1
+ && ( c2
+ || c3))
+ foo;
+}
+
+STARTTEST
+:set cino=k2s,(s
+2kdd3j=][
+ENDTEST
+
+void func(void)
+{
+ if (condition1
+ && condition2)
+ action();
+ function(argument1
+ && argument2);
+
+ if (c1 && (c2 ||
+ c3))
+ foo;
+ if (c1 &&
+ (c2 || c3))
+ {
+ }
+
+ if ( c1
+ && ( c2
+ || c3))
+ foo;
+ func( c1
+ && ( c2
+ || c3))
+ foo;
+}
+
+STARTTEST
+:set cino=k2s,(s,U1
+2kdd3j=][
+ENDTEST
+
+void func(void)
+{
+ if (condition1
+ && condition2)
+ action();
+ function(argument1
+ && argument2);
+
+ if (c1 && (c2 ||
+ c3))
+ foo;
+ if (c1 &&
+ (c2 || c3))
+ {
+ }
+ if (c123456789
+ && (c22345
+ || c3))
+ printf("foo\n");
+
+ c = c1 &&
+ (
+ c2 ||
+ c3
+ ) && c4;
+}
+
+STARTTEST
+:set cino=k2s,(0,W4
+2kdd3j=][
+ENDTEST
+
+void func(void)
+{
+ if (condition1
+ && condition2)
+ action();
+ function(argument1
+ && argument2);
+
+ if (c1 && (c2 ||
+ c3))
+ foo;
+ if (c1 &&
+ (c2 || c3))
+ {
+ }
+ if (c123456789
+ && (c22345
+ || c3))
+ printf("foo\n");
+
+ if ( c1
+ && ( c2
+ || c3))
+ foo;
+
+ a_long_line(
+ argument,
+ argument);
+ a_short_line(argument,
+ argument);
+}
+
+STARTTEST
+:set cino=k2s,u2
+2kdd3j=][
+ENDTEST
+
+void func(void)
+{
+ if (condition1
+ && condition2)
+ action();
+ function(argument1
+ && argument2);
+
+ if (c1 && (c2 ||
+ c3))
+ foo;
+ if (c1 &&
+ (c2 || c3))
+ {
+ }
+ if (c123456789
+ && (c22345
+ || c3))
+ printf("foo\n");
+}
+
+STARTTEST
+:set cino=k2s,(0,w1
+2kdd3j=][
+ENDTEST
+
+void func(void)
+{
+ if (condition1
+ && condition2)
+ action();
+ function(argument1
+ && argument2);
+
+ if (c1 && (c2 ||
+ c3))
+ foo;
+ if (c1 &&
+ (c2 || c3))
+ {
+ }
+ if (c123456789
+ && (c22345
+ || c3))
+ printf("foo\n");
+
+ if ( c1
+ && ( c2
+ || c3))
+ foo;
+ func( c1
+ && ( c2
+ || c3))
+ foo;
+}
+
+STARTTEST
+:set cino=k2,(s
+2kdd3j=][
+ENDTEST
+
+void func(void)
+{
+ if (condition1
+ && condition2)
+ action();
+ function(argument1
+ && argument2);
+
+ if (c1 && (c2 ||
+ c3))
+ foo;
+ if (c1 &&
+ (c2 || c3))
+ {
+ }
+}
+
+STARTTEST
+:set cino=N-s
+/^NAMESPACESTART
+=/^NAMESPACEEND
+ENDTEST
+
+NAMESPACESTART
+/* valid namespaces with normal indent */
+namespace
+{
+ {
+ 111111111111;
+}
+}
+namespace /* test */
+{
+ 11111111111111111;
+}
+namespace // test
+{
+ 111111111111111111;
+}
+namespace
+{
+ 111111111111111111;
+}
+namespace test
+{
+ 111111111111111111;
+}
+namespace test::cpp17
+{
+ 111111111111111111;
+}
+namespace ::incorrectcpp17
+{
+ 111111111111111111;
+}
+namespace test::incorrectcpp17::
+{
+ 111111111111111111;
+}
+namespace test:incorrectcpp17
+{
+ 111111111111111111;
+}
+namespace test:::incorrectcpp17
+{
+ 111111111111111111;
+}
+namespace{
+ 111111111111111111;
+}
+namespace test{
+ 111111111111111111;
+}
+namespace {
+ 111111111111111111;
+}
+namespace test {
+ 111111111111111111;
+namespace test2 {
+ 22222222222222222;
+}
+}
+
+/* invalid namespaces use block indent */
+namespace test test2 {
+ 111111111111111111111;
+}
+namespace11111111111 {
+ 111111111111;
+}
+namespace() {
+ 1111111111111;
+}
+namespace()
+{
+ 111111111111111111;
+}
+namespace test test2
+{
+ 1111111111111111111;
+}
+namespace111111111
+{
+ 111111111111111111;
+}
+NAMESPACEEND
+
+
+STARTTEST
+:set cino=j1,J1
+/^JSSTART
+=/^JSEND
+ENDTEST
+
+JSSTART
+var bar = {
+foo: {
+that: this,
+some: ok,
+},
+"bar":{
+a : 2,
+b: "123abc",
+x: 4,
+"y": 5
+}
+}
+JSEND
+
+STARTTEST
+:set cino=j1,J1
+/^JSSTART
+=/^JSEND
+ENDTEST
+
+JSSTART
+var foo = [
+1,
+2,
+3
+];
+JSEND
+
+STARTTEST
+:set cino=j1,J1
+/^JSSTART
+=/^JSEND
+ENDTEST
+
+JSSTART
+function bar() {
+var foo = [
+1,
+2,
+3
+];
+}
+JSEND
+
+STARTTEST
+:set cino=j1,J1
+/^JSSTART
+=/^JSEND
+ENDTEST
+
+JSSTART
+(function($){
+
+if (cond &&
+cond) {
+stmt;
+}
+window.something.left =
+(width - 50 + offset) + "px";
+var class_name='myclass';
+
+function private_method() {
+}
+
+var public_method={
+method: function(options,args){
+private_method();
+}
+}
+
+function init(options) {
+
+$(this).data(class_name+'_public',$.extend({},{
+foo: 'bar',
+bar: 2,
+foobar: [
+1,
+2,
+3
+],
+callback: function(){
+return true;
+}
+}, options||{}));
+}
+
+$.fn[class_name]=function() {
+
+var _arguments=arguments;
+return this.each(function(){
+
+var options=$(this).data(class_name+'_public');
+if (!options) {
+init.apply(this,_arguments);
+
+} else {
+var method=public_method[_arguments[0]];
+
+if (typeof(method)!='function') {
+console.log(class_name+' has no method "'+_arguments[0]+'"');
+return false;
+}
+_arguments[0]=options;
+method.apply(this,_arguments);
+}
+});
+}
+
+})(jQuery);
+JSEND
+
+STARTTEST
+:set cino=j1,J1
+/^JSSTART
+=/^JSEND
+ENDTEST
+
+JSSTART
+function init(options) {
+$(this).data(class_name+'_public',$.extend({},{
+foo: 'bar',
+bar: 2,
+foobar: [
+1,
+2,
+3
+],
+callback: function(){
+return true;
+}
+}, options||{}));
+}
+JSEND
+
+STARTTEST
+:set cino=j1,J1
+/^JSSTART
+=/^JSEND
+ENDTEST
+
+JSSTART
+(function($){
+function init(options) {
+$(this).data(class_name+'_public',$.extend({},{
+foo: 'bar',
+bar: 2,
+foobar: [
+1,
+2,
+3
+],
+callback: function(){
+return true;
+}
+}, options||{}));
+}
+})(jQuery);
+JSEND
+
+STARTTEST
+:set cino=j1,J1,+2
+/^JSSTART
+=/^JSEND
+ENDTEST
+
+JSSTART
+// Results of JavaScript indent
+// 1
+(function(){
+var a = [
+'a',
+'b',
+'c',
+'d',
+'e',
+'f',
+'g',
+'h',
+'i'
+];
+}())
+
+// 2
+(function(){
+var a = [
+0 +
+5 *
+9 *
+'a',
+'b',
+0 +
+5 *
+9 *
+'c',
+'d',
+'e',
+'f',
+'g',
+'h',
+'i'
+];
+}())
+
+// 3
+(function(){
+var a = [
+0 +
+// comment 1
+5 *
+/* comment 2 */
+9 *
+'a',
+'b',
+0 +
+5 *
+9 *
+'c',
+'d',
+'e',
+'f',
+'g',
+'h',
+'i'
+];
+}())
+
+// 4
+{
+var a = [
+0,
+1
+];
+var b;
+var c;
+}
+
+// 5
+{
+var a = [
+[
+0
+],
+2,
+3
+];
+}
+
+// 6
+{
+var a = [
+[
+0,
+1
+],
+2,
+3
+];
+}
+
+// 7
+{
+var a = [
+// [
+0,
+// 1
+// ],
+2,
+3
+];
+}
+
+// 8
+var x = [
+(function(){
+var a,
+b,
+c,
+d,
+e,
+f,
+g,
+h,
+i;
+})
+];
+
+// 9
+var a = [
+0 +
+5 *
+9 *
+'a',
+'b',
+0 +
+5 *
+9 *
+'c',
+'d',
+'e',
+'f',
+'g',
+'h',
+'i'
+];
+
+// 10
+var a,
+b,
+c,
+d,
+e,
+f,
+g,
+h,
+i;
+JSEND
+
+STARTTEST
+:set cin cino&
+/start of define
+=/end of define
+ENDTEST
+
+/* start of define */
+{
+}
+#define AAA \
+BBB\
+CCC
+
+#define CNT \
+1 + \
+2 + \
+4
+/* end of define */
+
+STARTTEST
+:set cin cino&
+/a = second
+ox
+ENDTEST
+
+{
+ a = second/*bug*/*line;
+}
+
+STARTTEST
+:g/^STARTTEST/.,/^ENDTEST/d
+:1;/start of AUTO/,$wq! test.out
+ENDTEST
diff --git a/src/testdir/test3.ok b/src/testdir/test3.ok
new file mode 100644
index 0000000..035ea39
--- /dev/null
+++ b/src/testdir/test3.ok
@@ -0,0 +1,2102 @@
+/* start of AUTO matically checked vim: set ts=4 : */
+{
+ if (test)
+ cmd1;
+ cmd2;
+}
+
+{
+ if (test)
+ cmd1;
+ else
+ cmd2;
+}
+
+{
+ if (test)
+ {
+ cmd1;
+ cmd2;
+ }
+}
+
+{
+ if (test)
+ {
+ cmd1;
+ else
+ }
+}
+
+{
+ while (this)
+ if (test)
+ cmd1;
+ cmd2;
+}
+
+{
+ while (this)
+ if (test)
+ cmd1;
+ else
+ cmd2;
+}
+
+{
+ if (test)
+ {
+ cmd;
+ }
+
+ if (test)
+ cmd;
+}
+
+{
+ if (test) {
+ cmd;
+ }
+
+ if (test) cmd;
+}
+
+{
+ cmd1;
+ for (blah)
+ while (this)
+ if (test)
+ cmd2;
+ cmd3;
+}
+
+{
+ cmd1;
+ for (blah)
+ while (this)
+ if (test)
+ cmd2;
+ cmd3;
+
+ if (test)
+ {
+ cmd1;
+ cmd2;
+ cmd3;
+ }
+}
+
+
+/* Test for 'cindent' do/while mixed with if/else: */
+
+{
+ do
+ if (asdf)
+ asdfasd;
+ while (cond);
+
+ do
+ if (asdf)
+ while (asdf)
+ asdf;
+ while (asdf);
+}
+
+/* Test for 'cindent' with two ) on a continuation line */
+{
+ if (asdfasdf;asldkfj asdlkfj as;ldkfj sal;d
+ aal;sdkjf ( ;asldfkja;sldfk
+ al;sdjfka ;slkdf ) sa;ldkjfsa dlk;)
+ line up here;
+}
+
+
+/* C++ tests: */
+
+// foo() these three lines should remain in column 0
+// {
+// }
+
+/* Test for continuation and unterminated lines: */
+{
+ i = 99 + 14325 +
+ 21345 +
+ 21345 +
+ 21345 + ( 21345 +
+ 21345) +
+ 2345 +
+ 1234;
+ c = 1;
+}
+
+/*
+ testje for indent with empty line
+
+ here */
+
+{
+ if (testing &&
+ not a joke ||
+ line up here)
+ hay;
+ if (testing &&
+ (not a joke || testing
+ )line up here)
+ hay;
+ if (testing &&
+ (not a joke || testing
+ line up here))
+ hay;
+}
+
+
+{
+ switch (c)
+ {
+ case xx:
+ do
+ if (asdf)
+ do
+ asdfasdf;
+ while (asdf);
+ else
+ asdfasdf;
+ while (cond);
+ case yy:
+ case xx:
+ case zz:
+ testing;
+ }
+}
+
+{
+ if (cond) {
+ foo;
+ }
+ else
+ {
+ bar;
+ }
+}
+
+{
+ if (alskdfj ;alsdkfjal;skdjf (;sadlkfsa ;dlkf j;alksdfj ;alskdjf
+ alsdkfj (asldk;fj
+ awith cino=(0 ;lf this one goes to below the paren with ==
+ ;laksjfd ;lsakdjf ;alskdf asd)
+ asdfasdf;)))
+ asdfasdf;
+}
+
+ int
+func(a, b)
+ int a;
+ int c;
+{
+ if (c1 && (c2 ||
+ c3))
+ foo;
+ if (c1 &&
+ (c2 || c3)
+ )
+}
+
+{
+ while (asd)
+ {
+ if (asdf)
+ if (test)
+ if (that)
+ {
+ if (asdf)
+ do
+ cdasd;
+ while (as
+ df);
+ }
+ else
+ if (asdf)
+ asdf;
+ else
+ asdf;
+ asdf;
+ }
+}
+
+{
+ s = "/*"; b = ';'
+ s = "/*"; b = ';';
+ a = b;
+}
+
+{
+ switch (a)
+ {
+ case a:
+ switch (t)
+ {
+ case 1:
+ cmd;
+ break;
+ case 2:
+ cmd;
+ break;
+ }
+ cmd;
+ break;
+ case b:
+ {
+ int i;
+ cmd;
+ }
+ break;
+ case c: {
+ int i;
+ cmd;
+ }
+ case d: if (cond &&
+ test) { /* this line doesn't work right */
+ int i;
+ cmd;
+ }
+ break;
+ }
+}
+
+{
+ if (!(vim_strchr(p_cpo, CPO_BUFOPTGLOB) != NULL && entering) &&
+ (bp_to->b_p_initialized ||
+ (!entering && vim_strchr(p_cpo, CPO_BUFOPT) != NULL)))
+ return;
+label :
+ asdf = asdf ?
+ asdf : asdf;
+ asdf = asdf ?
+ asdf: asdf;
+}
+
+/* Special Comments : This function has the added complexity (compared */
+/* : to addtolist) of having to check for a detail */
+/* : texture and add that to the list first. */
+
+char *(array[100]) = {
+ "testje",
+ "foo",
+ "bar",
+}
+
+enum soppie
+{
+ yes = 0,
+ no,
+ maybe
+};
+
+typedef enum soppie
+{
+ yes = 0,
+ no,
+ maybe
+};
+
+static enum
+{
+ yes = 0,
+ no,
+ maybe
+} soppie;
+
+public static enum
+{
+ yes = 0,
+ no,
+ maybe
+} soppie;
+
+static private enum
+{
+ yes = 0,
+ no,
+ maybe
+} soppie;
+
+{
+ int a,
+ b;
+}
+
+{
+ struct Type
+ {
+ int i;
+ char *str;
+ } var[] =
+ {
+ 0, "zero",
+ 1, "one",
+ 2, "two",
+ 3, "three"
+ };
+
+ float matrix[3][3] =
+ {
+ {
+ 0,
+ 1,
+ 2
+ },
+ {
+ 3,
+ 4,
+ 5
+ },
+ {
+ 6,
+ 7,
+ 8
+ }
+ };
+}
+
+{
+ /* blah ( blah */
+ /* where does this go? */
+
+ /* blah ( blah */
+ cmd;
+
+ func(arg1,
+ /* comment */
+ arg2);
+ a;
+ {
+ b;
+ {
+ c; /* Hey, NOW it indents?! */
+ }
+ }
+
+ {
+ func(arg1,
+ arg2,
+ arg3);
+ /* Hey, what am I doing here? Is this coz of the ","? */
+ }
+}
+
+main ()
+{
+ if (cond)
+ {
+ a = b;
+ }
+ if (cond) {
+ a = c;
+ }
+ if (cond)
+ a = d;
+ return;
+}
+
+{
+ case 2: if (asdf &&
+ asdfasdf)
+ aasdf;
+ a = 9;
+ case 3: if (asdf)
+ aasdf;
+ a = 9;
+ case 4: x = 1;
+ y = 2;
+
+label: if (asdf)
+ here;
+
+label: if (asdf &&
+ asdfasdf)
+ {
+ }
+
+label: if (asdf &&
+ asdfasdf) {
+ there;
+ }
+
+label: if (asdf &&
+ asdfasdf)
+ there;
+}
+
+{
+ /*
+ hello with ":set comments= cino=c5"
+ */
+
+ /*
+ hello with ":set comments= cino="
+ */
+}
+
+
+{
+ if (a < b) {
+ a = a + 1;
+ } else
+ a = a + 2;
+
+ if (a)
+ do {
+ testing;
+ } while (asdfasdf);
+ a = b + 1;
+ asdfasdf
+}
+
+{
+ for ( int i = 0;
+ i < 10; i++ )
+ {
+ }
+ i = 0;
+}
+
+class bob
+{
+ int foo() {return 1;}
+ int bar;
+}
+
+main()
+{
+ while(1)
+ if (foo)
+ {
+ bar;
+ }
+ else {
+ asdf;
+ }
+ misplacedline;
+}
+
+{
+ if (clipboard.state == SELECT_DONE
+ && ((row == clipboard.start.lnum
+ && col >= clipboard.start.col)
+ || row > clipboard.start.lnum))
+}
+
+{
+ if (1) {i += 4;}
+ where_am_i;
+ return 0;
+}
+
+{
+ {
+ } // sdf(asdf
+ if (asdf)
+ asd;
+}
+
+{
+label1:
+label2:
+}
+
+{
+ int fooRet = foo(pBar1, false /*fKB*/,
+ true /*fPTB*/, 3 /*nT*/, false /*fDF*/);
+ f() {
+ for ( i = 0;
+ i < m;
+ /* c */ i++ ) {
+ a = b;
+ }
+ }
+}
+
+{
+ f1(/*comment*/);
+ f2();
+}
+
+{
+ do {
+ if (foo) {
+ } else
+ ;
+ } while (foo);
+ foo(); // was wrong
+}
+
+int x; // no extra indent because of the ;
+void func()
+{
+}
+
+char *tab[] = {"aaa",
+ "};", /* }; */ NULL}
+ int indented;
+{}
+
+char *a[] = {"aaa", "bbb",
+ "ccc", NULL};
+// here
+
+char *tab[] = {"aaa",
+ "xx", /* xx */}; /* asdf */
+int not_indented;
+
+{
+ do {
+ switch (bla)
+ {
+ case 1: if (foo)
+ bar;
+ }
+ } while (boo);
+ wrong;
+}
+
+int foo,
+ bar;
+int foo;
+
+#if defined(foo) \
+ && defined(bar)
+char * xx = "asdf\
+ foo\
+ bor";
+int x;
+
+char *foo = "asdf\
+ asdf\
+ asdf",
+ *bar;
+
+void f()
+{
+#if defined(foo) \
+ && defined(bar)
+ char *foo = "asdf\
+ asdf\
+ asdf",
+ *bar;
+ {
+ int i;
+ char *foo = "asdf\
+ asdf\
+ asdf",
+ *bar;
+ }
+#endif
+}
+#endif
+
+int y; // comment
+// comment
+
+// comment
+
+{
+ Constructor(int a,
+ int b ) : BaseClass(a)
+ {
+ }
+}
+
+void foo()
+{
+ char one,
+ two;
+ struct bla piet,
+ jan;
+ enum foo kees,
+ jannie;
+ static unsigned sdf,
+ krap;
+ unsigned int piet,
+ jan;
+ int
+ kees,
+ jan;
+}
+
+{
+ t(int f,
+ int d); // )
+ d();
+}
+
+Constructor::Constructor(int a,
+ int b
+ ) :
+ BaseClass(a,
+ b,
+ c),
+ mMember(b),
+{
+}
+
+Constructor::Constructor(int a,
+ int b ) :
+ BaseClass(a)
+{
+}
+
+Constructor::Constructor(int a,
+ int b ) /*x*/ : /*x*/ BaseClass(a),
+ member(b)
+{
+}
+
+A::A(int a, int b)
+ : aa(a),
+ bb(b),
+ cc(c)
+{
+}
+
+class CAbc :
+ public BaseClass1,
+ protected BaseClass2
+{
+ int Test() { return FALSE; }
+ int Test1() { return TRUE; }
+
+ CAbc(int a, int b ) :
+ BaseClass(a)
+ {
+ switch(xxx)
+ {
+ case abc:
+ asdf();
+ break;
+
+ case 999:
+ baer();
+ break;
+ }
+ }
+
+ public: // <-- this was incoreectly indented before!!
+ void testfall();
+ protected:
+ void testfall();
+};
+
+class CAbc : public BaseClass1,
+ protected BaseClass2
+{
+};
+
+static struct
+{
+ int a;
+ int b;
+} variable[COUNT] =
+{
+ {
+ 123,
+ 456
+ },
+ {
+ 123,
+ 456
+ }
+};
+
+static struct
+{
+ int a;
+ int b;
+} variable[COUNT] =
+{
+ { 123, 456 },
+ { 123, 456 }
+};
+
+void asdf() /* ind_maxparen may cause trouble here */
+{
+ if ((0
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1)) break;
+}
+
+foo()
+{
+ a = cond ? foo() : asdf
+ + asdf;
+
+ a = cond ?
+ foo() : asdf
+ + asdf;
+}
+
+int main(void)
+{
+ if (a)
+ if (b)
+ 2;
+ else 3;
+ next_line_of_code();
+}
+
+barry()
+{
+ Foo::Foo (int one,
+ int two)
+ : something(4)
+ {}
+}
+
+barry()
+{
+ Foo::Foo (int one, int two)
+ : something(4)
+ {}
+}
+
+Constructor::Constructor(int a,
+ int b
+ ) :
+ BaseClass(a,
+ b,
+ c),
+ mMember(b)
+{
+}
+int main ()
+{
+ if (lala)
+ do
+ ++(*lolo);
+ while (lili
+ && lele);
+ lulu;
+}
+
+int main ()
+{
+ switch (c)
+ {
+ case 'c': if (cond)
+ {
+ }
+ }
+}
+
+main()
+{
+ (void) MyFancyFuasdfadsfnction(
+ argument);
+}
+
+main()
+{
+ char foo[] = "/*";
+ /* as
+ df */
+ hello
+}
+
+/* valid namespaces with normal indent */
+namespace
+{
+ {
+ 111111111111;
+ }
+}
+namespace /* test */
+{
+ 11111111111111111;
+}
+namespace // test
+{
+ 111111111111111111;
+}
+namespace
+{
+ 111111111111111111;
+}
+namespace test
+{
+ 111111111111111111;
+}
+namespace{
+ 111111111111111111;
+}
+namespace test{
+ 111111111111111111;
+}
+namespace {
+ 111111111111111111;
+}
+namespace test {
+ 111111111111111111;
+ namespace test2 {
+ 22222222222222222;
+ }
+}
+
+/* invalid namespaces use block indent */
+namespace test test2 {
+ 111111111111111111111;
+}
+namespace11111111111 {
+ 111111111111;
+}
+namespace() {
+ 1111111111111;
+}
+namespace()
+{
+ 111111111111111111;
+}
+namespace test test2
+{
+ 1111111111111111111;
+}
+namespace111111111
+{
+ 111111111111111111;
+}
+
+void getstring() {
+ /* Raw strings */
+ const char* s = R"(
+ test {
+ # comment
+ field: 123
+ }
+ )";
+}
+
+void getstring() {
+ const char* s = R"foo(
+ test {
+ # comment
+ field: 123
+ }
+ )foo";
+}
+
+{
+ int a[4] = {
+ [0] = 0,
+ [1] = 1,
+ [2] = 2,
+ [3] = 3,
+ };
+}
+
+{
+ a = b[2]
+ + 3;
+}
+
+{
+ if (1)
+ /* aaaaa
+ * bbbbb
+ */
+ a = 1;
+}
+
+void func()
+{
+ switch (foo)
+ {
+ case (bar):
+ if (baz())
+ quux();
+ break;
+ case (shmoo):
+ if (!bar)
+ {
+ }
+ case (foo1):
+ switch (bar)
+ {
+ case baz:
+ baz_f();
+ break;
+ }
+ break;
+ default:
+ baz();
+ baz();
+ break;
+ }
+}
+
+/* end of AUTO */
+
+
+{
+
+/* this is
+ * a real serious
+ * about life, the
+ * universe, and the
+ * rest important big
+ * comment
+ */
+ /* insert " about life, the universe, and the rest" after "serious" */
+}
+
+
+{
+ /*
+ * Testing for comments, without 'cin' set
+ */
+about life
+
+/*
+* what happens here?
+*/
+there
+
+ /*
+ the end of the comment, try inserting a line below */
+line
+
+ /* how about
+hello
+ this one */
+}
+
+
+{
+ var = this + that + vec[0] * vec[0]
+ + vec[1] * vec[1]
+ + vec2[2] * vec[2];
+}
+
+
+{
+ asdf asdflkajds f;
+ if (tes & ting) {
+ asdf asdf asdf ;
+ asdfa sdf asdf;
+ }
+ testing1;
+ if (tes & ting)
+ {
+ asdf asdf asdf ;
+ asdfa sdf asdf;
+ }
+ testing2;
+}
+
+
+main ( int first_par, /*
+ * Comment for
+ * first par
+ */
+ int second_par /*
+ * Comment for
+ * second par
+ */
+ )
+{
+ func( first_par, /*
+ * Comment for
+ * first par
+ */
+ second_par /*
+ * Comment for
+ * second par
+ */
+ );
+
+}
+
+
+main(void)
+{
+ /* Make sure that cino=X0s is not parsed like cino=Xs. */
+ if (cond)
+ foo();
+ else
+ {
+ bar();
+ }
+}
+
+
+{
+ do
+ {
+ if ()
+ {
+ if ()
+ asdf;
+ else
+ asdf;
+ }
+ } while ();
+ cmd; /* this should go under the } */
+}
+
+
+void f()
+{
+ if ( k() ) {
+ l();
+
+ } else { /* Start (two words) end */
+ m();
+ }
+
+ n();
+}
+
+
+void f()
+ {
+ if ( k() )
+ {
+ l();
+ } else { /* Start (two words) end */
+ m();
+ }
+ n(); /* should be under the if () */
+}
+
+
+void bar(void)
+ {
+ static array[2][2] =
+ {
+ { 1, 2 },
+ { 3, 4 },
+ }
+
+ while (a)
+ {
+ foo(&a);
+ }
+
+ {
+ int a;
+ {
+ a = a + 1;
+ }
+ }
+ b = a;
+ }
+
+void func(void)
+ {
+ a = 1;
+ {
+ b = 2;
+ }
+ c = 3;
+ d = 4;
+ }
+/* foo */
+
+
+a()
+{
+ do {
+ a = a +
+ a;
+ } while ( a ); /* add text under this line */
+ here
+ if ( a )
+ a;
+}
+
+
+a()
+{
+label1:
+ /* hmm */
+ // comment
+label2: b();
+label3 /* post */:
+/* pre */ label4:
+ f(/*com*/);
+ if (/*com*/)
+ cmd();
+}
+
+
+/*
+ * A simple comment
+ */
+
+/*
+** A different comment
+*/
+
+
+void f()
+{
+
+ /*********
+ A comment.
+ *********/
+}
+
+
+void f()
+{
+
+ /*********
+ A comment.
+ *********/
+}
+
+
+void f()
+{
+ c = c1 &&
+ (
+ c2 ||
+ c3
+ ) && c4;
+}
+
+
+void f()
+{
+ c = c1 &&
+ (
+ c2 ||
+ c3
+ ) && c4;
+}
+
+
+void f()
+{
+ c = c1 &&
+ (
+ c2 ||
+ c3
+ ) && c4;
+}
+
+
+void f()
+{
+ if ( c1
+ && ( c2
+ || c3))
+ foo;
+}
+
+
+void f()
+{
+ if ( c1
+ && ( c2
+ || c3))
+ foo;
+}
+
+
+void f()
+{
+ c = c1 && (
+ c2 ||
+ c3
+ ) && c4;
+ if (
+ c1 && c2
+ )
+ foo;
+}
+
+
+void f()
+{
+ c = c1 && (
+ c2 ||
+ c3
+ ) && c4;
+ if (
+ c1 && c2
+ )
+ foo;
+}
+
+
+void f()
+{
+ switch (x)
+ {
+ case 1:
+ a = b;
+ break;
+ default:
+ a = 0;
+ break;
+ }
+}
+
+
+void f()
+{
+ invokeme(
+ argu,
+ ment);
+ invokeme(
+ argu,
+ ment
+ );
+ invokeme(argu,
+ ment
+ );
+}
+
+
+void f()
+{
+ statement;
+ // comment 1
+ // comment 2
+}
+
+
+void f()
+{
+ statement;
+ // comment 1
+ // comment 2
+}
+
+
+class CAbc
+{
+ int Test() { return FALSE; }
+
+public: // comment
+ void testfall();
+protected:
+ void testfall();
+};
+
+
+class Foo : public Bar
+{
+ public:
+ virtual void method1(void) = 0;
+ virtual void method2(int arg1,
+ int arg2,
+ int arg3) = 0;
+};
+
+
+ void
+foo()
+{
+ if (a)
+ {
+ } else
+ asdf;
+}
+
+
+{
+ averylongfunctionnamelongfunctionnameaverylongfunctionname()->asd(
+ asdasdf,
+ func(asdf,
+ asdfadsf),
+ asdfasdf
+ );
+
+ /* those are ugly, but consequent */
+
+ func()->asd(asdasdf,
+ averylongfunctionname(
+ abc,
+ dec)->averylongfunctionname(
+ asdfadsf,
+ asdfasdf,
+ asdfasdf,
+ ),
+ func(asdfadf,
+ asdfasdf
+ ),
+ asdasdf
+ );
+
+ averylongfunctionnameaverylongfunctionnameavery()->asd(fasdf(
+ abc,
+ dec)->asdfasdfasdf(
+ asdfadsf,
+ asdfasdf,
+ asdfasdf,
+ ),
+ func(asdfadf,
+ asdfasdf),
+ asdasdf
+ );
+}
+
+
+int main ()
+{
+ if (cond1 &&
+ cond2
+ )
+ foo;
+}
+
+
+void func(int a
+#if defined(FOO)
+ , int b
+ , int c
+#endif
+ )
+{
+}
+
+
+ void
+func(int a
+#if defined(FOO)
+ , int b
+ , int c
+#endif
+ )
+{
+}
+
+
+void func(void)
+{
+ if(x==y)
+ if(y==z)
+ foo=1;
+ else { bar=1;
+ baz=2;
+ }
+ printf("Foo!\n");
+}
+
+void func1(void)
+{
+ char* tab[] = {"foo", "bar",
+ "baz", "quux",
+ "this line used", "to be indented incorrectly"};
+ foo();
+}
+
+void func2(void)
+{
+ int tab[] =
+ {1, 2,
+ 3, 4,
+ 5, 6};
+
+ printf("This line used to be indented incorrectly.\n");
+}
+
+int foo[]
+#ifdef BAR
+
+= { 1, 2, 3,
+ 4, 5, 6 }
+
+#endif
+ ;
+int baz;
+
+void func3(void)
+{
+ int tab[] = {
+ 1, 2,
+ 3, 4,
+ 5, 6};
+
+ printf("Don't you dare indent this line incorrectly!\n");
+}
+
+ void
+func4(a, b,
+ c)
+ int a;
+ int b;
+ int c;
+{
+}
+
+ void
+func5(
+ int a,
+ int b)
+{
+}
+
+ void
+func6(
+ int a)
+{
+}
+
+
+void func(void)
+{
+ int tab[] =
+ {
+ 1, 2, 3,
+ 4, 5, 6};
+
+ printf("Indent this line correctly!\n");
+
+ switch (foo)
+ {
+ case bar:
+ printf("bar");
+ break;
+ case baz: {
+ printf("baz");
+ break;
+ }
+ case quux:
+ printf("But don't break the indentation of this instruction\n");
+ break;
+ }
+}
+
+
+void func(void)
+{
+ cout << "a"
+ << "b"
+ << ") :"
+ << "c";
+}
+
+
+void func(void)
+{
+ /*
+ * This is a comment.
+ */
+ foo();
+}
+
+
+void func(void)
+{
+ for (int i = 0; i < 10; ++i)
+ if (i & 1) {
+ foo(1);
+ } else
+ foo(0);
+ baz();
+}
+
+
+void func(void)
+{
+ if (condition1
+ && condition2)
+ action();
+ function(argument1
+ && argument2);
+
+ if (c1 && (c2 ||
+ c3))
+ foo;
+ if (c1 &&
+ (c2 || c3))
+ {
+ }
+
+ if ( c1
+ && ( c2
+ || c3))
+ foo;
+ func( c1
+ && ( c2
+ || c3))
+ foo;
+}
+
+
+void func(void)
+{
+ if (condition1
+ && condition2)
+ action();
+ function(argument1
+ && argument2);
+
+ if (c1 && (c2 ||
+ c3))
+ foo;
+ if (c1 &&
+ (c2 || c3))
+ {
+ }
+
+ if ( c1
+ && ( c2
+ || c3))
+ foo;
+ func( c1
+ && ( c2
+ || c3))
+ foo;
+}
+
+
+void func(void)
+{
+ if (condition1
+ && condition2)
+ action();
+ function(argument1
+ && argument2);
+
+ if (c1 && (c2 ||
+ c3))
+ foo;
+ if (c1 &&
+ (c2 || c3))
+ {
+ }
+ if (c123456789
+ && (c22345
+ || c3))
+ printf("foo\n");
+
+ c = c1 &&
+ (
+ c2 ||
+ c3
+ ) && c4;
+}
+
+
+void func(void)
+{
+ if (condition1
+ && condition2)
+ action();
+ function(argument1
+ && argument2);
+
+ if (c1 && (c2 ||
+ c3))
+ foo;
+ if (c1 &&
+ (c2 || c3))
+ {
+ }
+ if (c123456789
+ && (c22345
+ || c3))
+ printf("foo\n");
+
+ if ( c1
+ && ( c2
+ || c3))
+ foo;
+
+ a_long_line(
+ argument,
+ argument);
+ a_short_line(argument,
+ argument);
+}
+
+
+void func(void)
+{
+ if (condition1
+ && condition2)
+ action();
+ function(argument1
+ && argument2);
+
+ if (c1 && (c2 ||
+ c3))
+ foo;
+ if (c1 &&
+ (c2 || c3))
+ {
+ }
+ if (c123456789
+ && (c22345
+ || c3))
+ printf("foo\n");
+}
+
+
+void func(void)
+{
+ if (condition1
+ && condition2)
+ action();
+ function(argument1
+ && argument2);
+
+ if (c1 && (c2 ||
+ c3))
+ foo;
+ if (c1 &&
+ (c2 || c3))
+ {
+ }
+ if (c123456789
+ && (c22345
+ || c3))
+ printf("foo\n");
+
+ if ( c1
+ && ( c2
+ || c3))
+ foo;
+ func( c1
+ && ( c2
+ || c3))
+ foo;
+}
+
+
+void func(void)
+{
+ if (condition1
+ && condition2)
+ action();
+ function(argument1
+ && argument2);
+
+ if (c1 && (c2 ||
+ c3))
+ foo;
+ if (c1 &&
+ (c2 || c3))
+ {
+ }
+}
+
+
+NAMESPACESTART
+/* valid namespaces with normal indent */
+namespace
+{
+{
+ 111111111111;
+}
+}
+namespace /* test */
+{
+11111111111111111;
+}
+namespace // test
+{
+111111111111111111;
+}
+namespace
+{
+111111111111111111;
+}
+namespace test
+{
+111111111111111111;
+}
+namespace test::cpp17
+{
+111111111111111111;
+}
+namespace ::incorrectcpp17
+{
+ 111111111111111111;
+}
+namespace test::incorrectcpp17::
+{
+ 111111111111111111;
+}
+namespace test:incorrectcpp17
+{
+ 111111111111111111;
+}
+namespace test:::incorrectcpp17
+{
+ 111111111111111111;
+}
+namespace{
+111111111111111111;
+}
+namespace test{
+111111111111111111;
+}
+namespace {
+111111111111111111;
+}
+namespace test {
+111111111111111111;
+namespace test2 {
+22222222222222222;
+}
+}
+
+/* invalid namespaces use block indent */
+namespace test test2 {
+ 111111111111111111111;
+}
+namespace11111111111 {
+ 111111111111;
+}
+namespace() {
+ 1111111111111;
+}
+namespace()
+{
+ 111111111111111111;
+}
+namespace test test2
+{
+ 1111111111111111111;
+}
+namespace111111111
+{
+ 111111111111111111;
+}
+NAMESPACEEND
+
+
+
+JSSTART
+var bar = {
+ foo: {
+ that: this,
+ some: ok,
+ },
+ "bar":{
+ a : 2,
+ b: "123abc",
+ x: 4,
+ "y": 5
+ }
+}
+JSEND
+
+
+JSSTART
+var foo = [
+ 1,
+ 2,
+ 3
+];
+JSEND
+
+
+JSSTART
+function bar() {
+ var foo = [
+ 1,
+ 2,
+ 3
+ ];
+}
+JSEND
+
+
+JSSTART
+(function($){
+
+ if (cond &&
+ cond) {
+ stmt;
+ }
+ window.something.left =
+ (width - 50 + offset) + "px";
+ var class_name='myclass';
+
+ function private_method() {
+ }
+
+ var public_method={
+ method: function(options,args){
+ private_method();
+ }
+ }
+
+ function init(options) {
+
+ $(this).data(class_name+'_public',$.extend({},{
+ foo: 'bar',
+ bar: 2,
+ foobar: [
+ 1,
+ 2,
+ 3
+ ],
+ callback: function(){
+ return true;
+ }
+ }, options||{}));
+ }
+
+ $.fn[class_name]=function() {
+
+ var _arguments=arguments;
+ return this.each(function(){
+
+ var options=$(this).data(class_name+'_public');
+ if (!options) {
+ init.apply(this,_arguments);
+
+ } else {
+ var method=public_method[_arguments[0]];
+
+ if (typeof(method)!='function') {
+ console.log(class_name+' has no method "'+_arguments[0]+'"');
+ return false;
+ }
+ _arguments[0]=options;
+ method.apply(this,_arguments);
+ }
+ });
+ }
+
+})(jQuery);
+JSEND
+
+
+JSSTART
+function init(options) {
+ $(this).data(class_name+'_public',$.extend({},{
+ foo: 'bar',
+ bar: 2,
+ foobar: [
+ 1,
+ 2,
+ 3
+ ],
+ callback: function(){
+ return true;
+ }
+ }, options||{}));
+}
+JSEND
+
+
+JSSTART
+(function($){
+ function init(options) {
+ $(this).data(class_name+'_public',$.extend({},{
+ foo: 'bar',
+ bar: 2,
+ foobar: [
+ 1,
+ 2,
+ 3
+ ],
+ callback: function(){
+ return true;
+ }
+ }, options||{}));
+ }
+})(jQuery);
+JSEND
+
+
+JSSTART
+// Results of JavaScript indent
+// 1
+(function(){
+ var a = [
+ 'a',
+ 'b',
+ 'c',
+ 'd',
+ 'e',
+ 'f',
+ 'g',
+ 'h',
+ 'i'
+ ];
+}())
+
+// 2
+(function(){
+ var a = [
+ 0 +
+ 5 *
+ 9 *
+ 'a',
+ 'b',
+ 0 +
+ 5 *
+ 9 *
+ 'c',
+ 'd',
+ 'e',
+ 'f',
+ 'g',
+ 'h',
+ 'i'
+ ];
+}())
+
+// 3
+(function(){
+ var a = [
+ 0 +
+ // comment 1
+ 5 *
+ /* comment 2 */
+ 9 *
+ 'a',
+ 'b',
+ 0 +
+ 5 *
+ 9 *
+ 'c',
+ 'd',
+ 'e',
+ 'f',
+ 'g',
+ 'h',
+ 'i'
+ ];
+}())
+
+// 4
+{
+ var a = [
+ 0,
+ 1
+ ];
+ var b;
+ var c;
+}
+
+// 5
+{
+ var a = [
+ [
+ 0
+ ],
+ 2,
+ 3
+ ];
+}
+
+// 6
+{
+ var a = [
+ [
+ 0,
+ 1
+ ],
+ 2,
+ 3
+ ];
+}
+
+// 7
+{
+ var a = [
+ // [
+ 0,
+ // 1
+ // ],
+ 2,
+ 3
+ ];
+}
+
+// 8
+var x = [
+ (function(){
+ var a,
+ b,
+ c,
+ d,
+ e,
+ f,
+ g,
+ h,
+ i;
+ })
+];
+
+// 9
+var a = [
+ 0 +
+ 5 *
+ 9 *
+ 'a',
+ 'b',
+ 0 +
+ 5 *
+ 9 *
+ 'c',
+ 'd',
+ 'e',
+ 'f',
+ 'g',
+ 'h',
+ 'i'
+];
+
+// 10
+var a,
+ b,
+ c,
+ d,
+ e,
+ f,
+ g,
+ h,
+ i;
+JSEND
+
+
+/* start of define */
+{
+}
+#define AAA \
+ BBB\
+ CCC
+
+#define CNT \
+ 1 + \
+ 2 + \
+ 4
+/* end of define */
+
+
+{
+ a = second/*bug*/*line;
+ x
+}
+
diff --git a/src/testdir/test30.in b/src/testdir/test30.in
new file mode 100644
index 0000000..df49404
--- /dev/null
+++ b/src/testdir/test30.in
@@ -0,0 +1,238 @@
+Test for a lot of variations of the 'fileformats' option
+
+Note: This test will fail if "cat" is not available.
+
+STARTTEST
+:so small.vim
+:set belloff=all
+:" first write three test files, one in each format
+:set fileformat=unix
+:set fileformats=
+:/^unix/;/eof/-1w! XXUnix
+:/^dos/;/eof/-1w! XXDos
+:set bin noeol
+:$w! XXMac
+Gonoeol
+:$w! XXEol
+:set nobin eol
+:enew!
+:bwipe XXUnix XXDos XXMac
+:" create mixed format files
+:if has("vms")
+: !copy XXUnix,XXDos XXUxDs.
+: !copy XXUnix,XXMac XXUxMac.
+: !copy XXDos,XXMac XXDosMac.
+: !copy XXMac,XXEol XXMacEol.
+: !copy XXUnix,XXDos,XXMac XXUxDsMc.
+:elseif has("win32")
+: !copy /b XXUnix+XXDos XXUxDs
+: !copy /b XXUnix+XXMac XXUxMac
+: !copy /b XXDos+XXMac XXDosMac
+: !copy /b XXMac+XXEol XXMacEol
+: !copy /b XXUnix+XXDos+XXMac XXUxDsMc
+:else
+: !cat XXUnix XXDos >XXUxDs
+: !cat XXUnix XXMac >XXUxMac
+: !cat XXDos XXMac >XXDosMac
+: !cat XXMac XXEol >XXMacEol
+: !cat XXUnix XXDos XXMac >XXUxDsMc
+:endif
+:"
+:" try reading and writing with 'fileformats' empty
+:set fileformat=unix
+:e! XXUnix
+:w! test.out
+:e! XXDos
+:w! XXtt01
+:e! XXMac
+:w! XXtt02
+:bwipe XXUnix XXDos XXMac
+:set fileformat=dos
+:e! XXUnix
+:w! XXtt11
+:e! XXDos
+:w! XXtt12
+:e! XXMac
+:w! XXtt13
+:bwipe XXUnix XXDos XXMac
+:set fileformat=mac
+:e! XXUnix
+:w! XXtt21
+:e! XXDos
+:w! XXtt22
+:e! XXMac
+:w! XXtt23
+:bwipe XXUnix XXDos XXMac
+:"
+:" try reading and writing with 'fileformats' set to one format
+:set fileformats=unix
+:e! XXUxDsMc
+:w! XXtt31
+:bwipe XXUxDsMc
+:set fileformats=dos
+:e! XXUxDsMc
+:w! XXtt32
+:bwipe XXUxDsMc
+:set fileformats=mac
+:e! XXUxDsMc
+:w! XXtt33
+:bwipe XXUxDsMc
+:"
+:" try reading and writing with 'fileformats' set to two formats
+:set fileformats=unix,dos
+:e! XXUxDsMc
+:w! XXtt41
+:bwipe XXUxDsMc
+:e! XXUxMac
+:w! XXtt42
+:bwipe XXUxMac
+:e! XXDosMac
+:w! XXtt43
+:bwipe XXDosMac
+:set fileformats=unix,mac
+:e! XXUxDs
+:w! XXtt51
+:bwipe XXUxDs
+:e! XXUxDsMc
+:w! XXtt52
+:bwipe XXUxDsMc
+:e! XXDosMac
+:w! XXtt53
+:bwipe XXDosMac
+:e! XXEol
+ggO=&ffs
+:=&ff
+:w! XXtt54
+:bwipe XXEol
+:set fileformats=dos,mac
+:e! XXUxDs
+:w! XXtt61
+:bwipe XXUxDs
+:e! XXUxMac
+ggO=&ffs
+:=&ff
+:w! XXtt62
+:bwipe XXUxMac
+:e! XXUxDsMc
+:w! XXtt63
+:bwipe XXUxDsMc
+:e! XXMacEol
+ggO=&ffs
+:=&ff
+:w! XXtt64
+:bwipe XXMacEol
+:"
+:" try reading and writing with 'fileformats' set to three formats
+:set fileformats=unix,dos,mac
+:e! XXUxDsMc
+:w! XXtt71
+:bwipe XXUxDsMc
+:e! XXEol
+ggO=&ffs
+:=&ff
+:w! XXtt72
+:bwipe XXEol
+:set fileformats=mac,dos,unix
+:e! XXUxDsMc
+:w! XXtt81
+:bwipe XXUxDsMc
+:e! XXEol
+ggO=&ffs
+:=&ff
+:w! XXtt82
+:bwipe XXEol
+:" try with 'binary' set
+:set fileformats=mac,unix,dos
+:set binary
+:e! XXUxDsMc
+:w! XXtt91
+:bwipe XXUxDsMc
+:set fileformats=mac
+:e! XXUxDsMc
+:w! XXtt92
+:bwipe XXUxDsMc
+:set fileformats=dos
+:e! XXUxDsMc
+:w! XXtt93
+:"
+:" Append "END" to each file so that we can see what the last written char was.
+:set fileformat=unix nobin
+ggdGaEND:w >>XXtt01
+:w >>XXtt02
+:w >>XXtt11
+:w >>XXtt12
+:w >>XXtt13
+:w >>XXtt21
+:w >>XXtt22
+:w >>XXtt23
+:w >>XXtt31
+:w >>XXtt32
+:w >>XXtt33
+:w >>XXtt41
+:w >>XXtt42
+:w >>XXtt43
+:w >>XXtt51
+:w >>XXtt52
+:w >>XXtt53
+:w >>XXtt54
+:w >>XXtt61
+:w >>XXtt62
+:w >>XXtt63
+:w >>XXtt64
+:w >>XXtt71
+:w >>XXtt72
+:w >>XXtt81
+:w >>XXtt82
+:w >>XXtt91
+:w >>XXtt92
+:w >>XXtt93
+:"
+:" Concatenate the results.
+:" Make fileformat of test.out the native fileformat.
+:" Add a newline at the end.
+:set binary
+:e! test.out
+:$r XXtt01
+:$r XXtt02
+Go1:$r XXtt11
+:$r XXtt12
+:$r XXtt13
+Go2:$r XXtt21
+:$r XXtt22
+:$r XXtt23
+Go3:$r XXtt31
+:$r XXtt32
+:$r XXtt33
+Go4:$r XXtt41
+:$r XXtt42
+:$r XXtt43
+Go5:$r XXtt51
+:$r XXtt52
+:$r XXtt53
+:$r XXtt54
+Go6:$r XXtt61
+:$r XXtt62
+:$r XXtt63
+:$r XXtt64
+Go7:$r XXtt71
+:$r XXtt72
+Go8:$r XXtt81
+:$r XXtt82
+Go9:$r XXtt91
+:$r XXtt92
+:$r XXtt93
+Go10:$r XXUnix
+:set nobinary ff&
+:w
+:qa!
+ENDTEST
+
+unix
+unix
+eof
+
+dos
+dos
+eof
+
+mac mac
diff --git a/src/testdir/test30.ok b/src/testdir/test30.ok
new file mode 100644
index 0000000..b35f4f5
--- /dev/null
+++ b/src/testdir/test30.ok
@@ -0,0 +1,130 @@
+unix
+unix
+dos
+dos
+END
+mac mac
+END
+1
+unix
+unix
+END
+dos
+dos
+END
+mac mac
+END
+2
+unix
+unix
+ END
+dos
+dos
+ END
+mac mac END
+3
+unix
+unix
+dos
+dos
+mac mac
+END
+unix
+unix
+dos
+dos
+mac mac
+END
+unix
+unix
+dos
+dos
+mac mac END
+4
+unix
+unix
+dos
+dos
+mac mac
+END
+unix
+unix
+mac mac
+END
+dos
+dos
+mac mac
+END
+5
+unix
+unix
+dos
+dos
+END
+unix
+unix
+dos
+dos
+mac mac
+END
+dos
+dos
+mac mac END
+unix,mac:unix
+noeol
+END
+6
+unix
+unix
+dos
+dos
+END
+dos,mac:dos
+unix
+unix
+mac mac
+END
+unix
+unix
+dos
+dos
+mac mac
+END
+dos,mac:mac mac mac noeol END
+7
+unix
+unix
+dos
+dos
+mac mac
+END
+unix,dos,mac:unix
+noeol
+END
+8
+unix
+unix
+dos
+dos
+mac mac
+END
+mac,dos,unix:mac noeol END
+9
+unix
+unix
+dos
+dos
+mac mac END
+unix
+unix
+dos
+dos
+mac mac END
+unix
+unix
+dos
+dos
+mac mac END
+10
+unix
+unix
diff --git a/src/testdir/test37.in b/src/testdir/test37.in
new file mode 100644
index 0000000..8ca1125
--- /dev/null
+++ b/src/testdir/test37.in
@@ -0,0 +1,116 @@
+Test for 'scrollbind'. <eralston@computer.org> Do not add a line below!
+STARTTEST
+:so small.vim
+:set noscrollbind
+:set scrollopt=ver,jump
+:set scrolloff=2
+:set nowrap
+:set noequalalways
+:set splitbelow
+:" TEST using two windows open to one buffer, one extra empty window
+:split
+:new
+t:
+:resize 8
+/^start of window 1$/
+zt:
+:set scrollbind
+j:
+:resize 7
+/^start of window 2$/
+zt:
+:set scrollbind
+:" -- start of tests --
+:" TEST scrolling down
+L5jHyybpr0tHyybpr1tL6jHyybpr2kHyybpr3:
+:" TEST scrolling up
+tH4kjHtHyybpr4kHyybpr5k3ktHjHyybpr6tHyybpr7:
+:" TEST horizontal scrolling
+:set scrollopt+=hor
+gg"zyyG"zpGt015zly$bp"zpGky$bp"zpG:
+k10jH7zhg0y$bp"zpGtHg0y$bp"zpG:
+:set scrollopt-=hor
+:" ****** tests using two different buffers *****
+tj:
+:close
+t:
+:set noscrollbind
+:/^start of window 2$/,/^end of window 2$/y
+:new
+tj4"zpGp:
+t/^start of window 1$/
+zt:
+:set scrollbind
+j:
+/^start of window 2$/
+zt:
+:set scrollbind
+:" -- start of tests --
+:" TEST scrolling down
+L5jHyybpr0tHyybpr1tL6jHyybpr2kHyybpr3:
+:" TEST scrolling up
+tH4kjHtHyybpr4kHyybpr5k3ktHjHyybpr6tHyybpr7:
+:" TEST horizontal scrolling
+:set scrollopt+=hor
+gg"zyyG"zpGt015zly$bp"zpGky$bp"zpG:
+k10jH7zhg0y$bp"zpGtHg0y$bp"zpG:
+:set scrollopt-=hor
+:" TEST syncbind
+t:set noscb
+ggLj:set noscb
+ggL:set scb
+t:set scb
+GjG:syncbind
+HktHjHyybptyybp:
+t:set noscb
+ggLj:set noscb
+ggL:set scb
+t:set scb
+tGjGt:syncbind
+HkjHtHyybptjyybp:
+tH3kjHtHyybptjyybp:
+:" ***** done with tests *****
+:w! test.out " Write contents of this file
+:qa!
+ENDTEST
+
+
+start of window 1
+. line 01 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ 01
+. line 02 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ 02
+. line 03 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ 03
+. line 04 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ 04
+. line 05 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ 05
+. line 06 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ 06
+. line 07 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ 07
+. line 08 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ 08
+. line 09 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ 09
+. line 10 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ 10
+. line 11 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ 11
+. line 12 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ 12
+. line 13 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ 13
+. line 14 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ 14
+. line 15 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ 15
+end of window 1
+
+
+start of window 2
+. line 01 ZYXWVUTSRQPONMLKJIHGREDCBA9876543210 01
+. line 02 ZYXWVUTSRQPONMLKJIHGREDCBA9876543210 02
+. line 03 ZYXWVUTSRQPONMLKJIHGREDCBA9876543210 03
+. line 04 ZYXWVUTSRQPONMLKJIHGREDCBA9876543210 04
+. line 05 ZYXWVUTSRQPONMLKJIHGREDCBA9876543210 05
+. line 06 ZYXWVUTSRQPONMLKJIHGREDCBA9876543210 06
+. line 07 ZYXWVUTSRQPONMLKJIHGREDCBA9876543210 07
+. line 08 ZYXWVUTSRQPONMLKJIHGREDCBA9876543210 08
+. line 09 ZYXWVUTSRQPONMLKJIHGREDCBA9876543210 09
+. line 10 ZYXWVUTSRQPONMLKJIHGREDCBA9876543210 10
+. line 11 ZYXWVUTSRQPONMLKJIHGREDCBA9876543210 11
+. line 12 ZYXWVUTSRQPONMLKJIHGREDCBA9876543210 12
+. line 13 ZYXWVUTSRQPONMLKJIHGREDCBA9876543210 13
+. line 14 ZYXWVUTSRQPONMLKJIHGREDCBA9876543210 14
+. line 15 ZYXWVUTSRQPONMLKJIHGREDCBA9876543210 15
+. line 16 ZYXWVUTSRQPONMLKJIHGREDCBA9876543210 16
+end of window 2
+
+end of test37.in (please don't delete this line)
diff --git a/src/testdir/test37.ok b/src/testdir/test37.ok
new file mode 100644
index 0000000..d0b7485
--- /dev/null
+++ b/src/testdir/test37.ok
@@ -0,0 +1,33 @@
+
+0 line 05 ZYXWVUTSRQPONMLKJIHGREDCBA9876543210 05
+1 line 05 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ 05
+2 line 11 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ 11
+3 line 11 ZYXWVUTSRQPONMLKJIHGREDCBA9876543210 11
+4 line 06 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ 06
+5 line 06 ZYXWVUTSRQPONMLKJIHGREDCBA9876543210 06
+6 line 02 ZYXWVUTSRQPONMLKJIHGREDCBA9876543210 02
+7 line 02 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ 02
+56789ABCDEFGHIJKLMNOPQRSTUVWXYZ 02
+UTSRQPONMLKJIHGREDCBA9876543210 02
+. line 11 ZYXWVUTSRQPONMLKJIHGREDCBA9876543210 11
+. line 11 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ 11
+
+0 line 05 ZYXWVUTSRQPONMLKJIHGREDCBA9876543210 05
+1 line 05 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ 05
+2 line 11 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ 11
+3 line 11 ZYXWVUTSRQPONMLKJIHGREDCBA9876543210 11
+4 line 06 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ 06
+5 line 06 ZYXWVUTSRQPONMLKJIHGREDCBA9876543210 06
+6 line 02 ZYXWVUTSRQPONMLKJIHGREDCBA9876543210 02
+7 line 02 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ 02
+56789ABCDEFGHIJKLMNOPQRSTUVWXYZ 02
+UTSRQPONMLKJIHGREDCBA9876543210 02
+. line 11 ZYXWVUTSRQPONMLKJIHGREDCBA9876543210 11
+. line 11 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ 11
+
+. line 16 ZYXWVUTSRQPONMLKJIHGREDCBA9876543210 16
+:set scrollbind
+:set scrollbind
+. line 16 ZYXWVUTSRQPONMLKJIHGREDCBA9876543210 16
+j:
+. line 12 ZYXWVUTSRQPONMLKJIHGREDCBA9876543210 12
diff --git a/src/testdir/test39.in b/src/testdir/test39.in
new file mode 100644
index 0000000..fcb935d
--- /dev/null
+++ b/src/testdir/test39.in
@@ -0,0 +1,118 @@
+
+Test Visual block mode commands
+And test "U" in Visual mode, also on German sharp S.
+
+#define BO_ALL 0x0001
+#define BO_BS 0x0002
+#define BO_CRSR 0x0004
+
+STARTTEST
+:so small.vim
+:so mbyte.vim
+:" This only works when 'encoding' is "latin1", don't depend on the environment
+:set enc=latin1
+/^abcde
+:" Test shift-right of a block
+jlllljj>wlljlll>
+:" Test shift-left of a block
+G$hhhhkk<
+:" Test block-insert
+GklkkkIxyz
+:" Test block-replace
+Gllllkkklllrq
+:" Test block-change
+G$khhhhhkkcmno
+:$-4,$w! test.out
+:" Test block-insert using cursor keys for movement
+/^aaaa/
+:exe ":norm! l\<C-V>jjjlllI\<Right>\<Right> \<Esc>"
+:/^aa/,/^$/w >> test.out
+/xaaa$/
+:exe ":norm! \<C-V>jjjI<>\<Left>p\<Esc>"
+:/xaaa$/,/^$/w >> test.out
+:" Test for Visual block was created with the last <C-v>$
+/^A23$/
+:exe ":norm! l\<C-V>j$Aab\<Esc>"
+:.,/^$/w >> test.out
+:" Test for Visual block was created with the middle <C-v>$ (1)
+/^B23$/
+:exe ":norm! l\<C-V>j$hAab\<Esc>"
+:.,/^$/w >> test.out
+:" Test for Visual block was created with the middle <C-v>$ (2)
+/^C23$/
+:exe ":norm! l\<C-V>j$hhAab\<Esc>"
+:.,/^$/w >> test.out
+:" Test for Visual block insert when virtualedit=all and utf-8 encoding
+:set ve=all enc=utf-8
+:/\t\tline
+:exe ":norm! 07l\<C-V>jjIx\<Esc>"
+:.,/^$/w >> test.out
+:" Test for Visual block append when virtualedit=all
+:exe ":norm! 012l\<C-v>jjAx\<Esc>"
+:set ve= enc=latin1
+:.,/^$/w >> test.out
+:" gUe must uppercase a whole word, also when ß changes to SS
+Gothe youtußeuu endYpk0wgUe
+:" gUfx must uppercase until x, inclusive.
+O- youßtußexu -0fogUfx
+:" VU must uppercase a whole line
+YpkVU
+:" same, when it's the last line in the buffer
+YPGi111VUddP
+:" Uppercase two lines
+Oblah di
+doh dutVkUj
+:" Uppercase part of two lines
+ddppi333k0i222fyllvjfuUk
+:" visual replace using Enter or NL
+G3o1234567892k05l2jr G3o987652k02l2jr
+G3o1234567892k05l2jr
+G3o987652k02l2jr
+:"
+:" Test cursor position. When ve=block and Visual block mode and $gj
+:set ve=block
+:exe ":norm! 2k\<C-V>$gj\<Esc>"
+:let cpos=getpos("'>")
+:$put ='col:'.cpos[2].' off:'.cpos[3]
+:"
+:" block_insert when replacing spaces in front of the block with tabs
+:set ts=8 sts=4 sw=4
+:4,7y
+Gp
+:exe ":norm! f0\<C-V>2jI\<tab>\<esc>"
+:/^the/,$w >> test.out
+:qa!
+ENDTEST
+
+ line1
+ line2
+ line3
+
+aaaaaa
+bbbbbb
+cccccc
+dddddd
+
+xaaa
+bbbb
+cccc
+dddd
+
+yaaa
+¿¿¿
+bbb
+
+A23
+4567
+
+B23
+4567
+
+C23
+4567
+
+abcdefghijklm
+abcdefghijklm
+abcdefghijklm
+abcdefghijklm
+abcdefghijklm
diff --git a/src/testdir/test39.ok b/src/testdir/test39.ok
new file mode 100644
index 0000000..349d67f
--- /dev/null
+++ b/src/testdir/test39.ok
Binary files differ
diff --git a/src/testdir/test42.in b/src/testdir/test42.in
new file mode 100644
index 0000000..c35569a
--- /dev/null
+++ b/src/testdir/test42.in
Binary files differ
diff --git a/src/testdir/test42.ok b/src/testdir/test42.ok
new file mode 100644
index 0000000..183430d
--- /dev/null
+++ b/src/testdir/test42.ok
Binary files differ
diff --git a/src/testdir/test44.in b/src/testdir/test44.in
new file mode 100644
index 0000000..7126392
--- /dev/null
+++ b/src/testdir/test44.in
@@ -0,0 +1,81 @@
+Tests for regexp with multi-byte encoding and various magic settings.
+Test matchstr() with a count and multi-byte chars.
+See test99 for exactly the same test with re=2.
+
+STARTTEST
+:so mbyte.vim
+:set nocompatible encoding=utf-8 termencoding=latin1 viminfo+=nviminfo
+:set re=1
+/^1
+/a*b\{2}c\+/e
+x/\Md\*e\{2}f\+/e
+x:set nomagic
+/g\*h\{2}i\+/e
+x/\mj*k\{2}l\+/e
+x/\vm*n{2}o+/e
+x/\V^aa$
+x:set magic
+/\v(a)(b)\2\1\1/e
+x/\V[ab]\(\[xy]\)\1
+x:" Now search for multi-byte without composing char
+/ม
+x:" Now search for multi-byte with composing char
+/ม่
+x:" find word by change of word class
+/ã¡\<カヨ\>ã¯
+x:" Test \%u, [\u] and friends
+:" c
+/\%u20ac
+x:" d
+/[\u4f7f\u5929]\+
+x:" e
+/\%U12345678
+x:" f
+/[\U1234abcd\u1234\uabcd]
+x:" g
+/\%d21879b
+x:" j Test backwards search from a multi-byte char
+/x
+x?.
+x:" k
+:let @w=':%s#comb[i]nations#Å“Ì„á¹£Ìm̥̄ᾱ̆Ì#g'
+:@w
+:"
+:" l Test what 7.3.192 fixed
+/^l
+:s/ \?/ /g
+:?^1?,$w! test.out
+:e! test.out
+G:put =matchstr(\"×בגד\", \".\", 0, 2) " ב
+:put =matchstr(\"×בגד\", \"..\", 0, 2) " בג
+:put =matchstr(\"×בגד\", \".\", 0, 0) " ×
+:put =matchstr(\"×בגד\", \".\", 4, -1) " ×’
+:new
+:$put =['dog(a', 'cat(']
+/(/e+
+"ayn:bd!
+:$put =''
+G"ap
+:w!
+:qa!
+ENDTEST
+
+1 a aa abb abbccc
+2 d dd dee deefff
+3 g gg ghh ghhiii
+4 j jj jkk jkklll
+5 m mm mnn mnnooo
+6 x ^aa$ x
+7 (a)(b) abbaa
+8 axx [ab]xx
+9 หม่x อมx
+a อมx หม่x
+b ã¡ã‚«ãƒ¨ã¯
+c x ¬€x
+d 天使x
+e ü’…™¸y
+f ü’Š¯z
+g aå•·bb
+j 0123â¤x
+k combinations
+l äö üᾱ̆Ì
diff --git a/src/testdir/test44.ok b/src/testdir/test44.ok
new file mode 100644
index 0000000..45774d7
--- /dev/null
+++ b/src/testdir/test44.ok
@@ -0,0 +1,25 @@
+1 a aa abb abbcc
+2 d dd dee deeff
+3 g gg ghh ghhii
+4 j jj jkk jkkll
+5 m mm mnn mnnoo
+6 x aa$ x
+7 (a)(b) abba
+8 axx ab]xx
+9 หม่x อx
+a อมx หx
+b カヨã¯
+c x ¬x
+d 使x
+e y
+f z
+g abb
+j 012â¤
+k Å“Ì„á¹£Ìm̥̄ᾱ̆Ì
+ l ä ö ü ᾱ̆Ì
+ב
+בג
+×’
+a
+cat(
diff --git a/src/testdir/test48.in b/src/testdir/test48.in
new file mode 100644
index 0000000..d480f8c
--- /dev/null
+++ b/src/testdir/test48.in
@@ -0,0 +1,83 @@
+This is a test of 'virtualedit'.
+
+STARTTEST
+:so small.vim
+:set noswf
+:set ve=all
+-dgg
+:"
+:" Insert "keyword keyw", ESC, C CTRL-N, shows "keyword ykeyword".
+:" Repeating CTRL-N fixes it. (Mary Ellen Foster)
+2/w
+C
+:"
+:" Using "C" then then <CR> moves the last remaining character to the next
+:" line. (Mary Ellen Foster)
+j^/are
+C are belong to vim
+:"
+:" When past the end of a line that ends in a single character "b" skips
+:" that word.
+^$15lbC7
+:"
+:" Make sure 'i' works
+$4li<-- should be 3 ' '
+:"
+:" Make sure 'C' works
+$4lC<-- should be 3 ' '
+:"
+:" Make sure 'a' works
+$4la<-- should be 4 ' '
+:"
+:" Make sure 'A' works
+$4lA<-- should be 0 ' '
+:"
+:" Make sure 'D' works
+$4lDi<-- 'D' should be intact
+:"
+:" Test for yank bug reported by Mark Waggoner.
+:set ve=block
+^2w3jyGp
+:"
+:" Test "r" beyond the end of the line
+:set ve=all
+/^"r"
+$5lrxa<-- should be 'x'
+:"
+:" Test "r" on a tab
+:" Note that for this test, 'ts' must be 8 (the default).
+^5lrxA<-- should be ' x '
+:"
+:" Test to make sure 'x' can delete control characters
+:set display=uhex
+^xxxxxxi[This line should contain only the text between the brackets.]
+:set display=
+:"
+:" Test for ^Y/^E due to bad w_virtcol value, reported by
+:" Roy <royl@netropolis.net>.
+^O3li4li4li <-- should show the name of a noted text editor
+^o4li4li4li <-- and its version number-dd
+:"
+:" Test for yanking and pasting using the small delete register
+gg/^foo
+dewve"-p
+:wq! test.out
+ENDTEST
+foo, bar
+keyword keyw
+all your base are belong to us
+1 2 3 4 5 6
+'i'
+'C'
+'a'
+'A'
+'D'
+this is a test
+this is a test
+this is a test
+"r"
+"r"
+ab sd
+abcv6efi.him0kl
+
+
diff --git a/src/testdir/test48.ok b/src/testdir/test48.ok
new file mode 100644
index 0000000..14cd9b1
--- /dev/null
+++ b/src/testdir/test48.ok
@@ -0,0 +1,23 @@
+, foo
+keyword keyword
+all your base
+are belong to vim
+1 2 3 4 5 7
+'i' <-- should be 3 ' '
+'C' <-- should be 3 ' '
+'a' <-- should be 4 ' '
+'A'<-- should be 0 ' '
+'D' <-- 'D' should be intact
+this is a test
+this is a test
+this is a test
+"r" x<-- should be 'x'
+"r" x <-- should be ' x '
+[This line should contain only the text between the brackets.]
+ v i m <-- should show the name of a noted text editor
+ 6 . 0 <-- and its version number
+
+a
+a
+a
+
diff --git a/src/testdir/test49.in b/src/testdir/test49.in
new file mode 100644
index 0000000..79f13f6
--- /dev/null
+++ b/src/testdir/test49.in
@@ -0,0 +1,32 @@
+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
new file mode 100644
index 0000000..50fc5d2
--- /dev/null
+++ b/src/testdir/test49.ok
@@ -0,0 +1,84 @@
+Results of test49.vim:
+*** Test 16: OK (8722)
+*** Test 17: OK (285127993)
+*** Test 18: OK (67224583)
+*** Test 19: OK (69275973)
+*** Test 20: OK (1874575085)
+*** Test 21: OK (147932225)
+*** Test 22: OK (4161)
+*** Test 23: OK (49)
+*** Test 24: OK (41)
+*** Test 25: OK (260177811)
+*** Test 26: OK (1681500476)
+*** Test 27: OK (1996459)
+*** Test 28: OK (1996459)
+*** Test 29: OK (170428555)
+*** Test 30: OK (190905173)
+*** Test 31: OK (190905173)
+*** Test 32: OK (354833067)
+--- Test 33: sum = 178275600 (ok)
+*** Test 33: OK (1216907538)
+*** Test 34: OK (2146584868)
+*** Test 35: OK (2146584868)
+*** Test 36: OK (1071644672)
+*** Test 37: OK (1071644672)
+*** Test 38: OK (357908480)
+*** Test 39: OK (357908480)
+*** Test 40: OK (357908480)
+*** Test 41: OK (3076095)
+*** Test 42: OK (1505155949)
+*** Test 43: OK (1157763329)
+*** Test 44: OK (1031761407)
+*** Test 45: OK (1157763329)
+*** Test 46: OK (739407)
+*** Test 47: OK (371213935)
+*** Test 48: OK (756255461)
+*** Test 49: OK (179000669)
+*** Test 50: OK (363550045)
+*** Test 51: OK (40744667)
+*** Test 52: OK (1247112011)
+*** Test 53: OK (131071)
+*** Test 54: OK (2047)
+*** Test 55: OK (1023)
+*** Test 56: OK (511)
+*** Test 57: OK (2147450880)
+*** Test 58: OK (624945)
+*** Test 59: OK (2038431743)
+*** Test 60: OK (311511339)
+*** Test 61: OK (374889517)
+*** Test 62: OK (286331153)
+*** Test 63: OK (236978127)
+*** Test 64: OK (1499645335)
+*** Test 65: OK (70187)
+*** Test 66: OK (5464)
+*** Test 67: OK (212514423)
+*** Test 68: OK (212514423)
+*** Test 69: OK (8995471)
+*** Test 70: OK (69544277)
+*** Test 71: OK (34886997)
+*** Test 72: OK (1789569365)
+*** Test 73: OK (9032615)
+*** Test 74: OK (224907669)
+*** Test 75: OK (2000403408)
+*** 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 87: 3
+--- Test 87: 5
+--- Test 87: abcdefghijk
+--- Test 87: Successfully executed funcref Add2
+*** Test 87: 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
new file mode 100644
index 0000000..97088f0
--- /dev/null
+++ b/src/testdir/test49.vim
@@ -0,0 +1,9009 @@
+" Vim script language tests
+" Author: Servatius Brandt <Servatius.Brandt@fujitsu-siemens.com>
+" Last Change: 2019 Jan 13
+
+"-------------------------------------------------------------------------------
+" 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<Space><C-R>=Xcheck()<CR><C-O>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<Space><C-R>=Xloop()<CR><C-O>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 "<C-O>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<Space><C-R>=Xpath(0)<CR><C-O>x
+ iab XloopINIT XloopINIT<Space><C-R>=Xpath(1)<CR><C-O>x
+
+ " Also useful (see ExtraVim below):
+ aug ExtraVim
+ au!
+ au BufEnter <sfile> syn region ExtraVim
+ \ start=+^if\s\+ExtraVim(.*)+ end=+^endif+
+ \ transparent keepend
+ au BufEnter <sfile> syn match ExtraComment /^"/
+ \ contained containedin=ExtraVim
+ au BufEnter <sfile> hi link ExtraComment vimComment
+ aug END
+
+ aug Xpath
+ au BufEnter <sfile> syn keyword Xpath
+ \ XpathINIT Xpath XloopINIT Xloop XloopNEXT Xcheck Xout
+ au BufEnter <sfile> hi link Xpath Special
+ aug END
+
+ do BufEnter <sfile>
+
+ " 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
+" ommitted (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 <C-P>.) At the end of the
+" test, just type "Xcheck" and press <Esc>.
+"
+" - 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 <count> >>" . g:ExtraVimResult
+else
+ com! -count -bar Xpath let g:Xpath = g:Xpath + <count>
+endif
+
+com! -count -nargs=1 -bang
+ \ XloopINIT let g:Xnext = <count> |
+ \ let g:Xfactor = <args> |
+ \ let g:Xskip = strlen("<bang>")
+
+if exists("g:ExtraVimResult")
+ com! -count=1 -bar Xloop exec "!echo " . (g:Xnext * <count>) . " >>" .
+ \ g:ExtraVimResult
+else
+ com! -count=1 -bar Xloop let g:Xpath = g:Xpath + g:Xnext * <count>
+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==<count>) ? "OK (".Xpath.")" :
+ \ "FAIL (".Xpath." instead of <count>)"
+ \ ) |
+ \ let @R = Xresult . "\n" |
+ \ echo Xresult |
+ \ let Xtest = Xtest + 1
+
+if exists("g:ExtraVimResult")
+ com! -nargs=+ Xoutq exec "!echo @R:'" .
+ \ substitute(substitute(<q-args>,
+ \ "'", '&\\&&', "g"), "\n", "@NL@", "g")
+ \ . "' >>" . g:ExtraVimResult
+else
+ com! -nargs=+ Xoutq let @R = "--- Test " .
+ \ (g:Xtest<10?" ":g:Xtest<100?" ":"") .
+ \ g:Xtest . ": " . substitute(<q-args>,
+ \ "\n", "&\t ", "g") . "\n"
+endif
+com! -nargs=+ Xout exec 'Xoutq' <args>
+
+" 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 <number> Xcheck <number>
+"
+" 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("<sfile>")
+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*\)\@<!\%(\u\|s:\)\w*\s*(\|'
+ \ . 'ExecAsScript\s\+\%(\u\|s:\)\w*',
+ \ "W") > 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' | ../vim -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 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/\<a:\(\h\w*\)/g:\1/ge
+ normal gg0
+ let cnt = 0
+ while search('\<call\s*\%(\u\|s:\)\w*\s*(.*)', 'W') > 0
+ let cnt = cnt + 1
+ s/\<call\s*\%(\u\|s:\)\w*\s*(.*)/\='source ' . a:{cnt}/
+ endwhile
+ g/^\s*$/d
+ write
+ bwipeout
+ return script
+endfunction
+" EXTRA_VIM_STOP - do not change or remove this line.
+
+
+" ExecAsScript - Source a temporary script made from a function. {{{2
+"
+" Make a temporary script file from the function a:funcname, ":source" it, and
+" delete it afterwards.
+"
+" When inside ":if ExtraVim()", add a file breakpoint for each INTERRUPT
+" location specified in the function.
+"
+" EXTRA_VIM_START - do not change or remove this line.
+function ExecAsScript(funcname)
+ " Make a script from the function passed as argument.
+ let script = MakeScript(a:funcname)
+
+ " When running in an extra Vim process, add a file breakpoint for each
+ " function breakpoint set when the extra Vim process was invoked by
+ " ExtraVim().
+ if exists("g:ExtraVimResult")
+ let bplist = tempname()
+ execute "redir! >" . 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(<f-args>)
+" EXTRA_VIM_STOP - do not change or remove this line.
+
+
+" END_OF_TEST_ENVIRONMENT - do not change or remove this line.
+
+
+" Tests 1 to 15 were moved to test_vimscript.vim
+let Xtest = 16
+
+"-------------------------------------------------------------------------------
+" Test 16: Double :else or :elseif after :else {{{1
+"
+" Multiple :elses or an :elseif after an :else are forbidden.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+function! F() abort
+ if 0
+ Xpath 1 " X: 0
+ else
+ Xpath 2 " X: 2
+ else " aborts function
+ Xpath 4 " X: 0
+ endif
+endfunction
+
+function! G() abort
+ if 0
+ Xpath 8 " X: 0
+ else
+ Xpath 16 " X: 16
+ elseif 1 " aborts function
+ Xpath 32 " X: 0
+ else
+ Xpath 64 " X: 0
+ endif
+endfunction
+
+function! H() abort
+ if 0
+ Xpath 128 " X: 0
+ elseif 0
+ Xpath 256 " X: 0
+ else
+ Xpath 512 " X: 512
+ else " aborts function
+ Xpath 1024 " X: 0
+ endif
+endfunction
+
+function! I() abort
+ if 0
+ Xpath 2048 " X: 0
+ elseif 0
+ Xpath 4096 " X: 0
+ else
+ Xpath 8192 " X: 8192
+ elseif 1 " aborts function
+ Xpath 16384 " X: 0
+ else
+ Xpath 32768 " X: 0
+ endif
+endfunction
+
+call F()
+call G()
+call H()
+call I()
+
+delfunction F
+delfunction G
+delfunction H
+delfunction I
+
+Xcheck 8722
+
+
+"-------------------------------------------------------------------------------
+" Test 17: Nesting of unmatched :if or :endif inside a :while {{{1
+"
+" The :while/:endwhile takes precedence in nesting over an unclosed
+" :if or an unopened :endif.
+"-------------------------------------------------------------------------------
+
+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 messages = ""
+
+" While loops inside a function are continued on error.
+function! F()
+ let v:errmsg = ""
+ XloopINIT 1 16
+ let loops = 3
+ while loops > 0
+ let loops = loops - 1 " 2: 1: 0:
+ Xloop 1 " X: 1 + 1*16 + 1*16*16
+ if (loops == 1)
+ Xloop 2 " X: 2*16
+ XloopNEXT
+ continue
+ elseif (loops == 0)
+ Xloop 4 " X: 4*16*16
+ break
+ elseif 1
+ Xloop 8 " X: 8
+ XloopNEXT
+ " endif missing!
+ endwhile " :endwhile after :if 1
+ Xpath 4096 " X: 16*16*16
+ if MSG('E171', "Missing :endif")
+ let g:messages = g:messages . "A"
+ endif
+
+ let v:errmsg = ""
+ XloopINIT! 8192 4
+ let loops = 2
+ while loops > 0 " 2: 1:
+ XloopNEXT
+ let loops = loops - 1
+ Xloop 1 " X: 8192 + 8192*4
+ if 0
+ Xloop 2 " X: 0
+ " endif missing
+ endwhile " :endwhile after :if 0
+ Xpath 131072 " X: 8192*4*4
+ if MSG('E171', "Missing :endif")
+ let g:messages = g:messages . "B"
+ endif
+
+ let v:errmsg = ""
+ XloopINIT 262144 4
+ let loops = 2
+ while loops > 0 " 2: 1:
+ let loops = loops - 1
+ Xloop 1 " X: 262144 + 262144 * 4
+ " if missing!
+ endif " :endif without :if in while
+ Xloop 2 " X: 524288 + 524288 * 4
+ XloopNEXT
+ endwhile
+ Xpath 4194304 " X: 262144*4*4
+ if MSG('E580', ":endif without :if")
+ let g:messages = g:messages . "C"
+ endif
+endfunction
+
+call F()
+
+" Error continuation outside a function is at the outermost :endwhile or :endif.
+let v:errmsg = ""
+XloopINIT! 8388608 4
+let loops = 2
+while loops > 0 " 2: 1:
+ XloopNEXT
+ let loops = loops - 1
+ Xloop 1 " X: 8388608 + 0 * 4
+ if 0
+ Xloop 2 " X: 0
+ " endif missing! Following :endwhile fails.
+endwhile | Xpath 134217728 " X: 0
+Xpath 268435456 " X: 2*8388608*4*4
+if MSG('E171', "Missing :endif")
+ let messages = g:messages . "D"
+endif
+
+if messages != "ABCD"
+ Xpath 536870912 " X: 0
+ Xout "messages is" messages "instead of ABCD"
+endif
+
+unlet loops messages
+delfunction F
+delfunction MSG
+
+Xcheck 285127993
+
+
+"-------------------------------------------------------------------------------
+" Test 18: Interrupt (Ctrl-C pressed) {{{1
+"
+" On an interrupt, the script processing is terminated immediately.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+if ExtraVim()
+ if 1
+ Xpath 1 " X: 1
+ while 1
+ Xpath 2 " X: 2
+ if 1
+ Xpath 4 " X: 4
+ "INTERRUPT
+ Xpath 8 " X: 0
+ break
+ finish
+ endif | Xpath 16 " X: 0
+ Xpath 32 " X: 0
+ endwhile | Xpath 64 " X: 0
+ Xpath 128 " X: 0
+ endif | Xpath 256 " X: 0
+ Xpath 512 " X: 0
+endif
+
+if ExtraVim()
+ try
+ Xpath 1024 " X: 1024
+ "INTERRUPT
+ Xpath 2048 " X: 0
+ endtry | Xpath 4096 " X: 0
+ Xpath 8192 " X: 0
+endif
+
+if ExtraVim()
+ function! F()
+ if 1
+ Xpath 16384 " X: 16384
+ while 1
+ Xpath 32768 " X: 32768
+ if 1
+ Xpath 65536 " X: 65536
+ "INTERRUPT
+ Xpath 131072 " X: 0
+ break
+ return
+ endif | Xpath 262144 " X: 0
+ Xpath Xpath 524288 " X: 0
+ endwhile | Xpath 1048576 " X: 0
+ Xpath Xpath 2097152 " X: 0
+ endif | Xpath Xpath 4194304 " X: 0
+ Xpath Xpath 8388608 " X: 0
+ endfunction
+
+ call F() | Xpath 16777216 " X: 0
+ Xpath 33554432 " X: 0
+endif
+
+if ExtraVim()
+ function! G()
+ try
+ Xpath 67108864 " X: 67108864
+ "INTERRUPT
+ Xpath 134217728 " X: 0
+ endtry | Xpath 268435456 " X: 0
+ Xpath 536870912 " X: 0
+ endfunction
+
+ call G() | Xpath 1073741824 " X: 0
+ " The Xpath command does not accept 2^31 (negative); display explicitly:
+ exec "!echo 2147483648 >>" . g:ExtraVimResult
+ " X: 0
+endif
+
+Xcheck 67224583
+
+
+"-------------------------------------------------------------------------------
+" Test 19: Aborting on errors inside :try/:endtry {{{1
+"
+" An error in a command dynamically enclosed in a :try/:endtry region
+" aborts script processing immediately. It does not matter whether
+" the failing command is outside or inside a function and whether a
+" function has an "abort" attribute.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+if ExtraVim()
+ function! F() abort
+ Xpath 1 " X: 1
+ asdf
+ Xpath 2 " X: 0
+ endfunction
+
+ try
+ Xpath 4 " X: 4
+ call F()
+ Xpath 8 " X: 0
+ endtry | Xpath 16 " X: 0
+ Xpath 32 " X: 0
+endif
+
+if ExtraVim()
+ function! G()
+ Xpath 64 " X: 64
+ asdf
+ Xpath 128 " X: 0
+ endfunction
+
+ try
+ Xpath 256 " X: 256
+ call G()
+ Xpath 512 " X: 0
+ endtry | Xpath 1024 " X: 0
+ Xpath 2048 " X: 0
+endif
+
+if ExtraVim()
+ try
+ Xpath 4096 " X: 4096
+ asdf
+ Xpath 8192 " X: 0
+ endtry | Xpath 16384 " X: 0
+ Xpath 32768 " X: 0
+endif
+
+if ExtraVim()
+ if 1
+ try
+ Xpath 65536 " X: 65536
+ asdf
+ Xpath 131072 " X: 0
+ endtry | Xpath 262144 " X: 0
+ endif | Xpath 524288 " X: 0
+ Xpath 1048576 " X: 0
+endif
+
+if ExtraVim()
+ let p = 1
+ while p
+ let p = 0
+ try
+ Xpath 2097152 " X: 2097152
+ asdf
+ Xpath 4194304 " X: 0
+ endtry | Xpath 8388608 " X: 0
+ endwhile | Xpath 16777216 " X: 0
+ Xpath 33554432 " X: 0
+endif
+
+if ExtraVim()
+ let p = 1
+ while p
+ let p = 0
+" try
+ Xpath 67108864 " X: 67108864
+ endwhile | Xpath 134217728 " X: 0
+ Xpath 268435456 " X: 0
+endif
+
+Xcheck 69275973
+"-------------------------------------------------------------------------------
+" Test 20: Aborting on errors after :try/:endtry {{{1
+"
+" When an error occurs after the last active :try/:endtry region has
+" been left, termination behavior is as if no :try/:endtry has been
+" seen.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+if ExtraVim()
+ let p = 1
+ while p
+ let p = 0
+ try
+ Xpath 1 " X: 1
+ endtry
+ asdf
+ endwhile | Xpath 2 " X: 0
+ Xpath 4 " X: 4
+endif
+
+if ExtraVim()
+ while 1
+ try
+ Xpath 8 " X: 8
+ break
+ Xpath 16 " X: 0
+ endtry
+ endwhile
+ Xpath 32 " X: 32
+ asdf
+ Xpath 64 " X: 64
+endif
+
+if ExtraVim()
+ while 1
+ try
+ Xpath 128 " X: 128
+ break
+ Xpath 256 " X: 0
+ finally
+ Xpath 512 " X: 512
+ endtry
+ endwhile
+ Xpath 1024 " X: 1024
+ asdf
+ Xpath 2048 " X: 2048
+endif
+
+if ExtraVim()
+ while 1
+ try
+ Xpath 4096 " X: 4096
+ finally
+ Xpath 8192 " X: 8192
+ break
+ Xpath 16384 " X: 0
+ endtry
+ endwhile
+ Xpath 32768 " X: 32768
+ asdf
+ Xpath 65536 " X: 65536
+endif
+
+if ExtraVim()
+ let p = 1
+ while p
+ let p = 0
+ try
+ Xpath 131072 " X: 131072
+ continue
+ Xpath 262144 " X: 0
+ endtry
+ endwhile
+ Xpath 524288 " X: 524288
+ asdf
+ Xpath 1048576 " X: 1048576
+endif
+
+if ExtraVim()
+ let p = 1
+ while p
+ let p = 0
+ try
+ Xpath 2097152 " X: 2097152
+ continue
+ Xpath 4194304 " X: 0
+ finally
+ Xpath 8388608 " X: 8388608
+ endtry
+ endwhile
+ Xpath 16777216 " X: 16777216
+ asdf
+ Xpath 33554432 " X: 33554432
+endif
+
+if ExtraVim()
+ let p = 1
+ while p
+ let p = 0
+ try
+ Xpath 67108864 " X: 67108864
+ finally
+ Xpath 134217728 " X: 134217728
+ continue
+ Xpath 268435456 " X: 0
+ endtry
+ endwhile
+ Xpath 536870912 " X: 536870912
+ asdf
+ Xpath 1073741824 " X: 1073741824
+endif
+
+Xcheck 1874575085
+
+
+"-------------------------------------------------------------------------------
+" Test 21: :finally for :try after :continue/:break/:return/:finish {{{1
+"
+" If a :try conditional stays inactive due to a preceding :continue,
+" :break, :return, or :finish, its :finally clause should not be
+" executed.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+if ExtraVim()
+ function F()
+ let loops = 2
+ XloopINIT! 1 256
+ while loops > 0
+ XloopNEXT
+ let loops = loops - 1
+ try
+ if loops == 1
+ Xloop 1 " X: 1
+ continue
+ Xloop 2 " X: 0
+ elseif loops == 0
+ Xloop 4 " X: 4*256
+ break
+ Xloop 8 " X: 0
+ endif
+
+ try " inactive
+ Xloop 16 " X: 0
+ finally
+ Xloop 32 " X: 0
+ endtry
+ finally
+ Xloop 64 " X: 64 + 64*256
+ endtry
+ Xloop 128 " X: 0
+ endwhile
+
+ try
+ Xpath 65536 " X: 65536
+ return
+ Xpath 131072 " X: 0
+ try " inactive
+ Xpath 262144 " X: 0
+ finally
+ Xpath 524288 " X: 0
+ endtry
+ finally
+ Xpath 1048576 " X: 1048576
+ endtry
+ Xpath 2097152 " X: 0
+ endfunction
+
+ try
+ Xpath 4194304 " X: 4194304
+ call F()
+ Xpath 8388608 " X: 8388608
+ finish
+ Xpath 16777216 " X: 0
+ try " inactive
+ Xpath 33554432 " X: 0
+ finally
+ Xpath 67108864 " X: 0
+ endtry
+ finally
+ Xpath 134217728 " X: 134217728
+ endtry
+ Xpath 268435456 " X: 0
+endif
+
+Xcheck 147932225
+
+
+"-------------------------------------------------------------------------------
+" Test 22: :finally for a :try after an error/interrupt/:throw {{{1
+"
+" If a :try conditional stays inactive due to a preceding error or
+" interrupt or :throw, its :finally clause should not be executed.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+if ExtraVim()
+ function! Error()
+ try
+ asdf " aborting error, triggering error exception
+ endtry
+ endfunction
+
+ Xpath 1 " X: 1
+ call Error()
+ Xpath 2 " X: 0
+
+ if 1 " not active due to error
+ try " not active since :if inactive
+ Xpath 4 " X: 0
+ finally
+ Xpath 8 " X: 0
+ endtry
+ endif
+
+ try " not active due to error
+ Xpath 16 " X: 0
+ finally
+ Xpath 32 " X: 0
+ endtry
+endif
+
+if ExtraVim()
+ function! Interrupt()
+ try
+ "INTERRUPT " triggering interrupt exception
+ endtry
+ endfunction
+
+ Xpath 64 " X: 64
+ call Interrupt()
+ Xpath 128 " X: 0
+
+ if 1 " not active due to interrupt
+ try " not active since :if inactive
+ Xpath 256 " X: 0
+ finally
+ Xpath 512 " X: 0
+ endtry
+ endif
+
+ try " not active due to interrupt
+ Xpath 1024 " X: 0
+ finally
+ Xpath 2048 " X: 0
+ endtry
+endif
+
+if ExtraVim()
+ function! Throw()
+ throw "xyz"
+ endfunction
+
+ Xpath 4096 " X: 4096
+ call Throw()
+ Xpath 8192 " X: 0
+
+ if 1 " not active due to :throw
+ try " not active since :if inactive
+ Xpath 16384 " X: 0
+ finally
+ Xpath 32768 " X: 0
+ endtry
+ endif
+
+ try " not active due to :throw
+ Xpath 65536 " X: 0
+ finally
+ Xpath 131072 " X: 0
+ endtry
+endif
+
+Xcheck 4161
+
+
+"-------------------------------------------------------------------------------
+" Test 23: :catch clauses for a :try after a :throw {{{1
+"
+" If a :try conditional stays inactive due to a preceding :throw,
+" none of its :catch clauses should be executed.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+if ExtraVim()
+ try
+ Xpath 1 " X: 1
+ throw "xyz"
+ Xpath 2 " X: 0
+
+ if 1 " not active due to :throw
+ try " not active since :if inactive
+ Xpath 4 " X: 0
+ catch /xyz/
+ Xpath 8 " X: 0
+ endtry
+ endif
+ catch /xyz/
+ Xpath 16 " X: 16
+ endtry
+
+ Xpath 32 " X: 32
+ throw "abc"
+ Xpath 64 " X: 0
+
+ try " not active due to :throw
+ Xpath 128 " X: 0
+ catch /abc/
+ Xpath 256 " X: 0
+ endtry
+endif
+
+Xcheck 49
+
+
+"-------------------------------------------------------------------------------
+" Test 24: :endtry for a :try after a :throw {{{1
+"
+" If a :try conditional stays inactive due to a preceding :throw,
+" its :endtry should not rethrow the exception to the next surrounding
+" active :try conditional.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+if ExtraVim()
+ try " try 1
+ try " try 2
+ Xpath 1 " X: 1
+ throw "xyz" " makes try 2 inactive
+ Xpath 2 " X: 0
+
+ try " try 3
+ Xpath 4 " X: 0
+ endtry " no rethrow to try 1
+ catch /xyz/ " should catch although try 2 inactive
+ Xpath 8 " X: 8
+ endtry
+ catch /xyz/ " try 1 active, but exception already caught
+ Xpath 16 " X: 0
+ endtry
+ Xpath 32 " X: 32
+endif
+
+Xcheck 41
+
+
+"-------------------------------------------------------------------------------
+" Test 25: Executing :finally clauses on normal control flow {{{1
+"
+" Control flow in a :try conditional should always fall through to its
+" :finally clause. A :finally clause of a :try conditional inside an
+" inactive conditional should never be executed.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+function! F()
+ let loops = 3
+ XloopINIT 1 256
+ while loops > 0 " 3: 2: 1:
+ Xloop 1 " X: 1 + 1*256 + 1*256*256
+ if loops >= 2
+ try
+ Xloop 2 " X: 2 + 2*256
+ if loops == 2
+ try
+ Xloop 4 " X: 4*256
+ finally
+ Xloop 8 " X: 8*256
+ endtry
+ endif
+ finally
+ Xloop 16 " X: 16 + 16*256
+ if loops == 2
+ try
+ Xloop 32 " X: 32*256
+ finally
+ Xloop 64 " X: 64*256
+ endtry
+ endif
+ endtry
+ endif
+ Xloop 128 " X: 128 + 128*256 + 128*256*256
+ let loops = loops - 1
+ XloopNEXT
+ endwhile
+ Xpath 16777216 " X: 16777216
+endfunction
+
+if 1
+ try
+ Xpath 33554432 " X: 33554432
+ call F()
+ Xpath 67108864 " X: 67108864
+ finally
+ Xpath 134217728 " X: 134217728
+ endtry
+else
+ try
+ Xpath 268435456 " X: 0
+ finally
+ Xpath 536870912 " X: 0
+ endtry
+endif
+
+delfunction F
+
+Xcheck 260177811
+
+
+"-------------------------------------------------------------------------------
+" Test 26: Executing :finally clauses after :continue or :break {{{1
+"
+" For a :continue or :break dynamically enclosed in a :try/:endtry
+" region inside the next surrounding :while/:endwhile, if the
+" :continue/:break is before the :finally, the :finally clause is
+" executed first. If the :continue/:break is after the :finally, the
+" :finally clause is broken (like an :if/:endif region).
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+try
+ let loops = 3
+ XloopINIT! 1 32
+ while loops > 0
+ XloopNEXT
+ try
+ try
+ if loops == 2 " 3: 2: 1:
+ Xloop 1 " X: 1*32
+ let loops = loops - 1
+ continue
+ elseif loops == 1
+ Xloop 2 " X: 2*32*32
+ break
+ finish
+ endif
+ Xloop 4 " X: 4
+ endtry
+ finally
+ Xloop 8 " X: 8 + 8*32 + 8*32*32
+ endtry
+ Xloop 16 " X: 16
+ let loops = loops - 1
+ endwhile
+ Xpath 32768 " X: 32768
+finally
+ Xpath 65536 " X: 65536
+ let loops = 3
+ XloopINIT 131072 16
+ while loops > 0
+ try
+ finally
+ try
+ if loops == 2
+ Xloop 1 " X: 131072*16
+ let loops = loops - 1
+ XloopNEXT
+ continue
+ elseif loops == 1
+ Xloop 2 " X: 131072*2*16*16
+ break
+ finish
+ endif
+ endtry
+ Xloop 4 " X: 131072*4
+ endtry
+ Xloop 8 " X: 131072*8
+ let loops = loops - 1
+ XloopNEXT
+ endwhile
+ Xpath 536870912 " X: 536870912
+endtry
+Xpath 1073741824 " X: 1073741824
+
+unlet loops
+
+Xcheck 1681500476
+
+
+"-------------------------------------------------------------------------------
+" Test 27: Executing :finally clauses after :return {{{1
+"
+" For a :return command dynamically enclosed in a :try/:endtry region,
+" :finally clauses are executed and the called function is ended.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+function! F()
+ try
+ Xpath 1 " X: 1
+ try
+ Xpath 2 " X: 2
+ return
+ Xpath 4 " X: 0
+ finally
+ Xpath 8 " X: 8
+ endtry
+ Xpath 16 " X: 0
+ finally
+ Xpath 32 " X: 32
+ endtry
+ Xpath 64 " X: 0
+endfunction
+
+function! G()
+ try
+ Xpath 128 " X: 128
+ return
+ Xpath 256 " X: 0
+ finally
+ Xpath 512 " X: 512
+ call F()
+ Xpath 1024 " X: 1024
+ endtry
+ Xpath 2048 " X: 0
+endfunction
+
+function! H()
+ try
+ Xpath 4096 " X: 4096
+ call G()
+ Xpath 8192 " X: 8192
+ finally
+ Xpath 16384 " X: 16384
+ return
+ Xpath 32768 " X: 0
+ endtry
+ Xpath 65536 " X: 0
+endfunction
+
+try
+ Xpath 131072 " X: 131072
+ call H()
+ Xpath 262144 " X: 262144
+finally
+ Xpath 524288 " X: 524288
+endtry
+Xpath 1048576 " X: 1048576
+
+Xcheck 1996459
+
+" Leave F, G, and H for execution as scripts in the next test.
+
+
+"-------------------------------------------------------------------------------
+" Test 28: Executing :finally clauses after :finish {{{1
+"
+" For a :finish command dynamically enclosed in a :try/:endtry region,
+" :finally clauses are executed and the sourced file is finished.
+"
+" This test executes the bodies of the functions F, G, and H from the
+" previous test as script files (:return replaced by :finish).
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+let scriptF = MakeScript("F") " X: 1 + 2 + 8 + 32
+let scriptG = MakeScript("G", scriptF) " X: 128 + 512 + 1024
+let scriptH = MakeScript("H", scriptG) " X: 4096 + 8192 + 16384
+
+try
+ Xpath 131072 " X: 131072
+ exec "source" scriptH
+ Xpath 262144 " X: 262144
+finally
+ Xpath 524288 " X: 524288
+endtry
+Xpath 1048576 " X: 1048576
+
+call delete(scriptF)
+call delete(scriptG)
+call delete(scriptH)
+unlet scriptF scriptG scriptH
+delfunction F
+delfunction G
+delfunction H
+
+Xcheck 1996459
+
+
+"-------------------------------------------------------------------------------
+" Test 29: Executing :finally clauses on errors {{{1
+"
+" After an error in a command dynamically enclosed in a :try/:endtry
+" region, :finally clauses are executed and the script processing is
+" terminated.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+if ExtraVim()
+ function! F()
+ while 1
+ try
+ Xpath 1 " X: 1
+ while 1
+ try
+ Xpath 2 " X: 2
+ asdf " error
+ Xpath 4 " X: 0
+ finally
+ Xpath 8 " X: 8
+ endtry | Xpath 16 " X: 0
+ Xpath 32 " X: 0
+ break
+ endwhile
+ Xpath 64 " X: 0
+ finally
+ Xpath 128 " X: 128
+ endtry | Xpath 256 " X: 0
+ Xpath 512 " X: 0
+ break
+ endwhile
+ Xpath 1024 " X: 0
+ endfunction
+
+ while 1
+ try
+ Xpath 2048 " X: 2048
+ while 1
+ call F()
+ Xpath 4096 " X: 0
+ break
+ endwhile | Xpath 8192 " X: 0
+ Xpath 16384 " X: 0
+ finally
+ Xpath 32768 " X: 32768
+ endtry | Xpath 65536 " X: 0
+ endwhile | Xpath 131072 " X: 0
+ Xpath 262144 " X: 0
+endif
+
+if ExtraVim()
+ function! G() abort
+ if 1
+ try
+ Xpath 524288 " X: 524288
+ asdf " error
+ Xpath 1048576 " X: 0
+ finally
+ Xpath 2097152 " X: 2097152
+ endtry | Xpath 4194304 " X: 0
+ endif | Xpath 8388608 " X: 0
+ Xpath 16777216 " X: 0
+ endfunction
+
+ if 1
+ try
+ Xpath 33554432 " X: 33554432
+ call G()
+ Xpath 67108864 " X: 0
+ finally
+ Xpath 134217728 " X: 134217728
+ endtry | Xpath 268435456 " X: 0
+ endif | Xpath 536870912 " X: 0
+ Xpath 1073741824 " X: 0
+endif
+
+Xcheck 170428555
+
+
+"-------------------------------------------------------------------------------
+" Test 30: Executing :finally clauses on interrupt {{{1
+"
+" After an interrupt in a command dynamically enclosed in
+" a :try/:endtry region, :finally clauses are executed and the
+" script processing is terminated.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+if ExtraVim()
+ XloopINIT 1 16
+
+ function! F()
+ try
+ Xloop 1 " X: 1 + 1*16
+ "INTERRUPT
+ Xloop 2 " X: 0
+ finally
+ Xloop 4 " X: 4 + 4*16
+ endtry
+ Xloop 8 " X: 0
+ endfunction
+
+ try
+ Xpath 256 " X: 256
+ try
+ Xpath 512 " X: 512
+ "INTERRUPT
+ Xpath 1024 " X: 0
+ finally
+ Xpath 2048 " X: 2048
+ try
+ Xpath 4096 " X: 4096
+ try
+ Xpath 8192 " X: 8192
+ finally
+ Xpath 16384 " X: 16384
+ try
+ Xpath 32768 " X: 32768
+ "INTERRUPT
+ Xpath 65536 " X: 0
+ endtry
+ Xpath 131072 " X: 0
+ endtry
+ Xpath 262144 " X: 0
+ endtry
+ Xpath 524288 " X: 0
+ endtry
+ Xpath 1048576 " X: 0
+ finally
+ Xpath 2097152 " X: 2097152
+ try
+ Xpath 4194304 " X: 4194304
+ call F()
+ Xpath 8388608 " X: 0
+ finally
+ Xpath 16777216 " X: 16777216
+ try
+ Xpath 33554432 " X: 33554432
+ XloopNEXT
+ ExecAsScript F
+ Xpath 67108864 " X: 0
+ finally
+ Xpath 134217728 " X: 134217728
+ endtry
+ Xpath 268435456 " X: 0
+ endtry
+ Xpath 536870912 " X: 0
+ endtry
+ Xpath 1073741824 " X: 0
+endif
+
+Xcheck 190905173
+
+
+"-------------------------------------------------------------------------------
+" Test 31: Executing :finally clauses after :throw {{{1
+"
+" After a :throw dynamically enclosed in a :try/:endtry region,
+" :finally clauses are executed and the script processing is
+" terminated.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+if ExtraVim()
+ XloopINIT 1 16
+
+ function! F()
+ try
+ Xloop 1 " X: 1 + 1*16
+ throw "exception"
+ Xloop 2 " X: 0
+ finally
+ Xloop 4 " X: 4 + 4*16
+ endtry
+ Xloop 8 " X: 0
+ endfunction
+
+ try
+ Xpath 256 " X: 256
+ try
+ Xpath 512 " X: 512
+ throw "exception"
+ Xpath 1024 " X: 0
+ finally
+ Xpath 2048 " X: 2048
+ try
+ Xpath 4096 " X: 4096
+ try
+ Xpath 8192 " X: 8192
+ finally
+ Xpath 16384 " X: 16384
+ try
+ Xpath 32768 " X: 32768
+ throw "exception"
+ Xpath 65536 " X: 0
+ endtry
+ Xpath 131072 " X: 0
+ endtry
+ Xpath 262144 " X: 0
+ endtry
+ Xpath 524288 " X: 0
+ endtry
+ Xpath 1048576 " X: 0
+ finally
+ Xpath 2097152 " X: 2097152
+ try
+ Xpath 4194304 " X: 4194304
+ call F()
+ Xpath 8388608 " X: 0
+ finally
+ Xpath 16777216 " X: 16777216
+ try
+ Xpath 33554432 " X: 33554432
+ XloopNEXT
+ ExecAsScript F
+ Xpath 67108864 " X: 0
+ finally
+ Xpath 134217728 " X: 134217728
+ endtry
+ Xpath 268435456 " X: 0
+ endtry
+ Xpath 536870912 " X: 0
+ endtry
+ Xpath 1073741824 " X: 0
+endif
+
+Xcheck 190905173
+
+
+"-------------------------------------------------------------------------------
+" Test 32: Remembering the :return value on :finally {{{1
+"
+" If a :finally clause is executed due to a :return specifying
+" a value, this is the value visible to the caller if not overwritten
+" by a new :return in the :finally clause. A :return without a value
+" in the :finally clause overwrites with value 0.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+function! F()
+ try
+ Xpath 1 " X: 1
+ try
+ Xpath 2 " X: 2
+ return "ABCD"
+ Xpath 4 " X: 0
+ finally
+ Xpath 8 " X: 8
+ endtry
+ Xpath 16 " X: 0
+ finally
+ Xpath 32 " X: 32
+ endtry
+ Xpath 64 " X: 0
+endfunction
+
+function! G()
+ try
+ Xpath 128 " X: 128
+ return 8
+ Xpath 256 " X: 0
+ finally
+ Xpath 512 " X: 512
+ return 16 + strlen(F())
+ Xpath 1024 " X: 0
+ endtry
+ Xpath 2048 " X: 0
+endfunction
+
+function! H()
+ try
+ Xpath 4096 " X: 4096
+ return 32
+ Xpath 8192 " X: 0
+ finally
+ Xpath 16384 " X: 16384
+ return
+ Xpath 32768 " X: 0
+ endtry
+ Xpath 65536 " X: 0
+endfunction
+
+function! I()
+ try
+ Xpath 131072 " X: 131072
+ finally
+ Xpath 262144 " X: 262144
+ return G() + H() + 64
+ Xpath 524288 " X: 0
+ endtry
+ Xpath 1048576 " X: 0
+endfunction
+
+let retcode = I()
+Xpath 2097152 " X: 2097152
+
+if retcode < 0
+ Xpath 4194304 " X: 0
+endif
+if retcode % 4
+ Xpath 8388608 " X: 0
+endif
+if (retcode/4) % 2
+ Xpath 16777216 " X: 16777216
+endif
+if (retcode/8) % 2
+ Xpath 33554432 " X: 0
+endif
+if (retcode/16) % 2
+ Xpath 67108864 " X: 67108864
+endif
+if (retcode/32) % 2
+ Xpath 134217728 " X: 0
+endif
+if (retcode/64) % 2
+ Xpath 268435456 " X: 268435456
+endif
+if retcode/128
+ Xpath 536870912 " X: 0
+endif
+
+unlet retcode
+delfunction F
+delfunction G
+delfunction H
+delfunction I
+
+Xcheck 354833067
+
+
+"-------------------------------------------------------------------------------
+" Test 33: :return under :execute or user command and :finally {{{1
+"
+" A :return command may be executed under an ":execute" or from
+" a user command. Executing of :finally clauses and passing through
+" the return code works also then.
+"-------------------------------------------------------------------------------
+XpathINIT
+
+command! -nargs=? RETURN
+ \ try | return <args> | finally | return <args> * 2 | endtry
+
+function! F()
+ try
+ RETURN 8
+ Xpath 1 " X: 0
+ finally
+ Xpath 2 " X: 2
+ endtry
+ Xpath 4 " X: 0
+endfunction
+
+function! G()
+ try
+ RETURN 32
+ Xpath 8 " X: 0
+ finally
+ Xpath 16 " X: 16
+ RETURN 128
+ Xpath 32 " X: 0
+ endtry
+ Xpath 64 " X: 0
+endfunction
+
+function! H()
+ try
+ execute "try | return 512 | finally | return 1024 | endtry"
+ Xpath 128 " X: 0
+ finally
+ Xpath 256 " X: 256
+ endtry
+ Xpath 512 " X: 0
+endfunction
+
+function! I()
+ try
+ execute "try | return 2048 | finally | return 4096 | endtry"
+ Xpath 1024 " X: 0
+ finally
+ Xpath 2048 " X: 2048
+ execute "try | return 8192 | finally | return 16384 | endtry"
+ Xpath 4096 " X: 0
+ endtry
+ Xpath 8192 " X: 0
+endfunction
+
+function! J()
+ try
+ RETURN 32768
+ Xpath 16384 " X: 0
+ finally
+ Xpath 32768 " X: 32768
+ return
+ Xpath 65536 " X: 0
+ endtry
+ Xpath 131072 " X: 0
+endfunction
+
+function! K()
+ try
+ execute "try | return 131072 | finally | return 262144 | endtry"
+ Xpath 262144 " X: 0
+ finally
+ Xpath 524288 " X: 524288
+ execute "try | return 524288 | finally | return | endtry"
+ Xpath 1048576 " X: 0
+ endtry
+ Xpath 2097152 " X: 0
+endfunction
+
+function! L()
+ try
+ return
+ Xpath 4194304 " X: 0
+ finally
+ Xpath 8388608 " X: 8388608
+ RETURN 1048576
+ Xpath 16777216 " X: 0
+ endtry
+ Xpath 33554432 " X: 0
+endfunction
+
+function! M()
+ try
+ return
+ Xpath 67108864 " X: 0
+ finally
+ Xpath 134217728 " X: 134217728
+ execute "try | return 4194304 | finally | return 8388608 | endtry"
+ Xpath 268435456 " X: 0
+ endtry
+ Xpath 536870912 " X: 0
+endfunction
+
+function! N()
+ RETURN 16777216
+endfunction
+
+function! O()
+ execute "try | return 67108864 | finally | return 134217728 | endtry"
+endfunction
+
+let sum = F() + G() + H() + I() + J() + K() + L() + M()
+let expected = 16 + 256 + 1024 + 16384 + 0 + 0 + 2097152 + 8388608
+let sum = sum + N() + O()
+let expected = expected + 33554432 + 134217728
+
+if sum == expected
+ Xout "sum = " . sum . " (ok)"
+else
+ Xout "sum = " . sum . ", expected: " . expected
+endif
+
+Xpath 1073741824 " X: 1073741824
+
+if sum != expected
+ " The Xpath command does not accept 2^31 (negative); add explicitly:
+ let Xpath = Xpath + 2147483648 " X: 0
+endif
+
+unlet sum expected
+delfunction F
+delfunction G
+delfunction H
+delfunction I
+delfunction J
+delfunction K
+delfunction L
+delfunction M
+delfunction N
+delfunction O
+
+Xcheck 1216907538
+
+
+"-------------------------------------------------------------------------------
+" Test 34: :finally reason discarded by :continue {{{1
+"
+" When a :finally clause is executed due to a :continue, :break,
+" :return, :finish, error, interrupt or :throw, the jump reason is
+" discarded by a :continue in the finally clause.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+if ExtraVim()
+
+ XloopINIT! 1 8
+
+ function! C(jump)
+ XloopNEXT
+ let loop = 0
+ while loop < 2
+ let loop = loop + 1
+ if loop == 1
+ try
+ if a:jump == "continue"
+ continue
+ elseif a:jump == "break"
+ break
+ elseif a:jump == "return" || a:jump == "finish"
+ return
+ elseif a:jump == "error"
+ asdf
+ elseif a:jump == "interrupt"
+ "INTERRUPT
+ let dummy = 0
+ elseif a:jump == "throw"
+ throw "abc"
+ endif
+ finally
+ continue " discards jump that caused the :finally
+ Xloop 1 " X: 0
+ endtry
+ Xloop 2 " X: 0
+ elseif loop == 2
+ Xloop 4 " X: 4*(1+8+64+512+4096+32768+262144)
+ endif
+ endwhile
+ endfunction
+
+ call C("continue")
+ Xpath 2097152 " X: 2097152
+ call C("break")
+ Xpath 4194304 " X: 4194304
+ call C("return")
+ Xpath 8388608 " X: 8388608
+ let g:jump = "finish"
+ ExecAsScript C
+ unlet g:jump
+ Xpath 16777216 " X: 16777216
+ try
+ call C("error")
+ Xpath 33554432 " X: 33554432
+ finally
+ Xpath 67108864 " X: 67108864
+ try
+ call C("interrupt")
+ Xpath 134217728 " X: 134217728
+ finally
+ Xpath 268435456 " X: 268435456
+ call C("throw")
+ Xpath 536870912 " X: 536870912
+ endtry
+ endtry
+ Xpath 1073741824 " X: 1073741824
+
+ delfunction C
+
+endif
+
+Xcheck 2146584868
+
+
+"-------------------------------------------------------------------------------
+" Test 35: :finally reason discarded by :break {{{1
+"
+" When a :finally clause is executed due to a :continue, :break,
+" :return, :finish, error, interrupt or :throw, the jump reason is
+" discarded by a :break in the finally clause.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+if ExtraVim()
+
+ XloopINIT! 1 8
+
+ function! B(jump)
+ XloopNEXT
+ let loop = 0
+ while loop < 2
+ let loop = loop + 1
+ if loop == 1
+ try
+ if a:jump == "continue"
+ continue
+ elseif a:jump == "break"
+ break
+ elseif a:jump == "return" || a:jump == "finish"
+ return
+ elseif a:jump == "error"
+ asdf
+ elseif a:jump == "interrupt"
+ "INTERRUPT
+ let dummy = 0
+ elseif a:jump == "throw"
+ throw "abc"
+ endif
+ finally
+ break " discards jump that caused the :finally
+ Xloop 1 " X: 0
+ endtry
+ elseif loop == 2
+ Xloop 2 " X: 0
+ endif
+ endwhile
+ Xloop 4 " X: 4*(1+8+64+512+4096+32768+262144)
+ endfunction
+
+ call B("continue")
+ Xpath 2097152 " X: 2097152
+ call B("break")
+ Xpath 4194304 " X: 4194304
+ call B("return")
+ Xpath 8388608 " X: 8388608
+ let g:jump = "finish"
+ ExecAsScript B
+ unlet g:jump
+ Xpath 16777216 " X: 16777216
+ try
+ call B("error")
+ Xpath 33554432 " X: 33554432
+ finally
+ Xpath 67108864 " X: 67108864
+ try
+ call B("interrupt")
+ Xpath 134217728 " X: 134217728
+ finally
+ Xpath 268435456 " X: 268435456
+ call B("throw")
+ Xpath 536870912 " X: 536870912
+ endtry
+ endtry
+ Xpath 1073741824 " X: 1073741824
+
+ delfunction B
+
+endif
+
+Xcheck 2146584868
+
+
+"-------------------------------------------------------------------------------
+" Test 36: :finally reason discarded by :return {{{1
+"
+" When a :finally clause is executed due to a :continue, :break,
+" :return, :finish, error, interrupt or :throw, the jump reason is
+" discarded by a :return in the finally clause.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+if ExtraVim()
+
+ XloopINIT! 1 8
+
+ function! R(jump, retval) abort
+ XloopNEXT
+ let loop = 0
+ while loop < 2
+ let loop = loop + 1
+ if loop == 1
+ try
+ if a:jump == "continue"
+ continue
+ elseif a:jump == "break"
+ break
+ elseif a:jump == "return"
+ return
+ elseif a:jump == "error"
+ asdf
+ elseif a:jump == "interrupt"
+ "INTERRUPT
+ let dummy = 0
+ elseif a:jump == "throw"
+ throw "abc"
+ endif
+ finally
+ return a:retval " discards jump that caused the :finally
+ Xloop 1 " X: 0
+ endtry
+ elseif loop == 2
+ Xloop 2 " X: 0
+ endif
+ endwhile
+ Xloop 4 " X: 0
+ endfunction
+
+ let sum = -R("continue", -8)
+ Xpath 2097152 " X: 2097152
+ let sum = sum - R("break", -16)
+ Xpath 4194304 " X: 4194304
+ let sum = sum - R("return", -32)
+ Xpath 8388608 " X: 8388608
+ try
+ let sum = sum - R("error", -64)
+ Xpath 16777216 " X: 16777216
+ finally
+ Xpath 33554432 " X: 33554432
+ try
+ let sum = sum - R("interrupt", -128)
+ Xpath 67108864 " X: 67108864
+ finally
+ Xpath 134217728 " X: 134217728
+ let sum = sum - R("throw", -256)
+ Xpath 268435456 " X: 268435456
+ endtry
+ endtry
+ Xpath 536870912 " X: 536870912
+
+ let expected = 8 + 16 + 32 + 64 + 128 + 256
+ if sum != expected
+ Xpath 1073741824 " X: 0
+ Xout "sum =" . sum . ", expected: " . expected
+ endif
+
+ unlet sum expected
+ delfunction R
+
+endif
+
+Xcheck 1071644672
+
+
+"-------------------------------------------------------------------------------
+" Test 37: :finally reason discarded by :finish {{{1
+"
+" When a :finally clause is executed due to a :continue, :break,
+" :return, :finish, error, interrupt or :throw, the jump reason is
+" discarded by a :finish in the finally clause.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+if ExtraVim()
+
+ XloopINIT! 1 8
+
+ function! F(jump) " not executed as function, transformed to a script
+ XloopNEXT
+ let loop = 0
+ while loop < 2
+ let loop = loop + 1
+ if loop == 1
+ try
+ if a:jump == "continue"
+ continue
+ elseif a:jump == "break"
+ break
+ elseif a:jump == "finish"
+ finish
+ elseif a:jump == "error"
+ asdf
+ elseif a:jump == "interrupt"
+ "INTERRUPT
+ let dummy = 0
+ elseif a:jump == "throw"
+ throw "abc"
+ endif
+ finally
+ finish " discards jump that caused the :finally
+ Xloop 1 " X: 0
+ endtry
+ elseif loop == 2
+ Xloop 2 " X: 0
+ endif
+ endwhile
+ Xloop 4 " X: 0
+ endfunction
+
+ let scriptF = MakeScript("F")
+ delfunction F
+
+ let g:jump = "continue"
+ exec "source" scriptF
+ Xpath 2097152 " X: 2097152
+ let g:jump = "break"
+ exec "source" scriptF
+ Xpath 4194304 " X: 4194304
+ let g:jump = "finish"
+ exec "source" scriptF
+ Xpath 8388608 " X: 8388608
+ try
+ let g:jump = "error"
+ exec "source" scriptF
+ Xpath 16777216 " X: 16777216
+ finally
+ Xpath 33554432 " X: 33554432
+ try
+ let g:jump = "interrupt"
+ exec "source" scriptF
+ Xpath 67108864 " X: 67108864
+ finally
+ Xpath 134217728 " X: 134217728
+ try
+ let g:jump = "throw"
+ exec "source" scriptF
+ Xpath 268435456 " X: 268435456
+ finally
+ Xpath 536870912 " X: 536870912
+ endtry
+ endtry
+ endtry
+ unlet g:jump
+
+ call delete(scriptF)
+ unlet scriptF
+
+endif
+
+Xcheck 1071644672
+
+
+"-------------------------------------------------------------------------------
+" Test 38: :finally reason discarded by an error {{{1
+"
+" When a :finally clause is executed due to a :continue, :break,
+" :return, :finish, error, interrupt or :throw, the jump reason is
+" discarded by an error in the finally clause.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+if ExtraVim()
+
+ XloopINIT! 1 4
+
+ function! E(jump)
+ XloopNEXT
+ let loop = 0
+ while loop < 2
+ let loop = loop + 1
+ if loop == 1
+ try
+ if a:jump == "continue"
+ continue
+ elseif a:jump == "break"
+ break
+ elseif a:jump == "return" || a:jump == "finish"
+ return
+ elseif a:jump == "error"
+ asdf
+ elseif a:jump == "interrupt"
+ "INTERRUPT
+ let dummy = 0
+ elseif a:jump == "throw"
+ throw "abc"
+ endif
+ finally
+ asdf " error; discards jump that caused the :finally
+ endtry
+ elseif loop == 2
+ Xloop 1 " X: 0
+ endif
+ endwhile
+ Xloop 2 " X: 0
+ endfunction
+
+ try
+ Xpath 16384 " X: 16384
+ call E("continue")
+ Xpath 32768 " X: 0
+ finally
+ try
+ Xpath 65536 " X: 65536
+ call E("break")
+ Xpath 131072 " X: 0
+ finally
+ try
+ Xpath 262144 " X: 262144
+ call E("return")
+ Xpath 524288 " X: 0
+ finally
+ try
+ Xpath 1048576 " X: 1048576
+ let g:jump = "finish"
+ ExecAsScript E
+ Xpath 2097152 " X: 0
+ finally
+ unlet g:jump
+ try
+ Xpath 4194304 " X: 4194304
+ call E("error")
+ Xpath 8388608 " X: 0
+ finally
+ try
+ Xpath 16777216 " X: 16777216
+ call E("interrupt")
+ Xpath 33554432 " X: 0
+ finally
+ try
+ Xpath 67108864 " X: 67108864
+ call E("throw")
+ Xpath 134217728 " X: 0
+ finally
+ Xpath 268435456 " X: 268435456
+ delfunction E
+ endtry
+ endtry
+ endtry
+ endtry
+ endtry
+ endtry
+ endtry
+ Xpath 536870912 " X: 0
+
+endif
+
+Xcheck 357908480
+
+
+"-------------------------------------------------------------------------------
+" Test 39: :finally reason discarded by an interrupt {{{1
+"
+" When a :finally clause is executed due to a :continue, :break,
+" :return, :finish, error, interrupt or :throw, the jump reason is
+" discarded by an interrupt in the finally clause.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+if ExtraVim()
+
+ XloopINIT! 1 4
+
+ function! I(jump)
+ XloopNEXT
+ let loop = 0
+ while loop < 2
+ let loop = loop + 1
+ if loop == 1
+ try
+ if a:jump == "continue"
+ continue
+ elseif a:jump == "break"
+ break
+ elseif a:jump == "return" || a:jump == "finish"
+ return
+ elseif a:jump == "error"
+ asdf
+ elseif a:jump == "interrupt"
+ "INTERRUPT
+ let dummy = 0
+ elseif a:jump == "throw"
+ throw "abc"
+ endif
+ finally
+ "INTERRUPT - discards jump that caused the :finally
+ let dummy = 0
+ endtry
+ elseif loop == 2
+ Xloop 1 " X: 0
+ endif
+ endwhile
+ Xloop 2 " X: 0
+ endfunction
+
+ try
+ Xpath 16384 " X: 16384
+ call I("continue")
+ Xpath 32768 " X: 0
+ finally
+ try
+ Xpath 65536 " X: 65536
+ call I("break")
+ Xpath 131072 " X: 0
+ finally
+ try
+ Xpath 262144 " X: 262144
+ call I("return")
+ Xpath 524288 " X: 0
+ finally
+ try
+ Xpath 1048576 " X: 1048576
+ let g:jump = "finish"
+ ExecAsScript I
+ Xpath 2097152 " X: 0
+ finally
+ unlet g:jump
+ try
+ Xpath 4194304 " X: 4194304
+ call I("error")
+ Xpath 8388608 " X: 0
+ finally
+ try
+ Xpath 16777216 " X: 16777216
+ call I("interrupt")
+ Xpath 33554432 " X: 0
+ finally
+ try
+ Xpath 67108864 " X: 67108864
+ call I("throw")
+ Xpath 134217728 " X: 0
+ finally
+ Xpath 268435456 " X: 268435456
+ delfunction I
+ endtry
+ endtry
+ endtry
+ endtry
+ endtry
+ endtry
+ endtry
+ Xpath 536870912 " X: 0
+
+endif
+
+Xcheck 357908480
+
+
+"-------------------------------------------------------------------------------
+" Test 40: :finally reason discarded by :throw {{{1
+"
+" When a :finally clause is executed due to a :continue, :break,
+" :return, :finish, error, interrupt or :throw, the jump reason is
+" discarded by a :throw in the finally clause.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+if ExtraVim()
+
+ XloopINIT! 1 4
+
+ function! T(jump)
+ XloopNEXT
+ let loop = 0
+ while loop < 2
+ let loop = loop + 1
+ if loop == 1
+ try
+ if a:jump == "continue"
+ continue
+ elseif a:jump == "break"
+ break
+ elseif a:jump == "return" || a:jump == "finish"
+ return
+ elseif a:jump == "error"
+ asdf
+ elseif a:jump == "interrupt"
+ "INTERRUPT
+ let dummy = 0
+ elseif a:jump == "throw"
+ throw "abc"
+ endif
+ finally
+ throw "xyz" " discards jump that caused the :finally
+ endtry
+ elseif loop == 2
+ Xloop 1 " X: 0
+ endif
+ endwhile
+ Xloop 2 " X: 0
+ endfunction
+
+ try
+ Xpath 16384 " X: 16384
+ call T("continue")
+ Xpath 32768 " X: 0
+ finally
+ try
+ Xpath 65536 " X: 65536
+ call T("break")
+ Xpath 131072 " X: 0
+ finally
+ try
+ Xpath 262144 " X: 262144
+ call T("return")
+ Xpath 524288 " X: 0
+ finally
+ try
+ Xpath 1048576 " X: 1048576
+ let g:jump = "finish"
+ ExecAsScript T
+ Xpath 2097152 " X: 0
+ finally
+ unlet g:jump
+ try
+ Xpath 4194304 " X: 4194304
+ call T("error")
+ Xpath 8388608 " X: 0
+ finally
+ try
+ Xpath 16777216 " X: 16777216
+ call T("interrupt")
+ Xpath 33554432 " X: 0
+ finally
+ try
+ Xpath 67108864 " X: 67108864
+ call T("throw")
+ Xpath 134217728 " X: 0
+ finally
+ Xpath 268435456 " X: 268435456
+ delfunction T
+ endtry
+ endtry
+ endtry
+ endtry
+ endtry
+ endtry
+ endtry
+ Xpath 536870912 " X: 0
+
+endif
+
+Xcheck 357908480
+
+
+"-------------------------------------------------------------------------------
+" Test 41: Skipped :throw finding next command {{{1
+"
+" A :throw in an inactive conditional must not hide a following
+" command.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+function! F()
+ Xpath 1 " X: 1
+ if 0 | throw "never" | endif | Xpath 2 " X: 2
+ Xpath 4 " X: 4
+endfunction
+
+function! G()
+ Xpath 8 " X: 8
+ while 0 | throw "never" | endwhile | Xpath 16 " X: 16
+ Xpath 32 " X: 32
+endfunction
+
+function H()
+ Xpath 64 " X: 64
+ if 0 | try | throw "never" | endtry | endif | Xpath 128 " X: 128
+ Xpath 256 " X: 256
+endfunction
+
+Xpath 512 " X: 512
+
+try
+ Xpath 1024 " X: 1024
+ call F()
+ Xpath 2048 " X: 2048
+catch /.*/
+ Xpath 4096 " X: 0
+ Xout v:exception "in" v:throwpoint
+endtry
+
+Xpath 8192 " X: 8192
+
+try
+ Xpath 16384 " X: 16384
+ call G()
+ Xpath 32768 " X: 32768
+catch /.*/
+ Xpath 65536 " X: 0
+ Xout v:exception "in" v:throwpoint
+endtry
+
+Xpath 131072 " X: 131072
+
+try
+ Xpath 262144 " X: 262144
+ call H()
+ Xpath 524288 " X: 524288
+catch /.*/
+ Xpath 1048576 " X: 0
+ Xout v:exception "in" v:throwpoint
+endtry
+
+Xpath 2097152 " X: 2097152
+
+delfunction F
+delfunction G
+delfunction H
+
+Xcheck 3076095
+
+
+"-------------------------------------------------------------------------------
+" Test 42: Catching number and string exceptions {{{1
+"
+" When a number is thrown, it is converted to a string exception.
+" Numbers and strings may be caught by specifying a regular exception
+" as argument to the :catch command.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+try
+
+ try
+ Xpath 1 " X: 1
+ throw 4711
+ Xpath 2 " X: 0
+ catch /4711/
+ Xpath 4 " X: 4
+ endtry
+
+ try
+ Xpath 8 " X: 8
+ throw 4711
+ Xpath 16 " X: 0
+ catch /^4711$/
+ Xpath 32 " X: 32
+ endtry
+
+ try
+ Xpath 64 " X: 64
+ throw 4711
+ Xpath 128 " X: 0
+ catch /\d/
+ Xpath 256 " X: 256
+ endtry
+
+ try
+ Xpath 512 " X: 512
+ throw 4711
+ Xpath 1024 " X: 0
+ catch /^\d\+$/
+ Xpath 2048 " X: 2048
+ endtry
+
+ try
+ Xpath 4096 " X: 4096
+ throw "arrgh"
+ Xpath 8192 " X: 0
+ catch /arrgh/
+ Xpath 16384 " X: 16384
+ endtry
+
+ try
+ Xpath 32768 " X: 32768
+ throw "arrgh"
+ Xpath 65536 " X: 0
+ catch /^arrgh$/
+ Xpath 131072 " X: 131072
+ endtry
+
+ try
+ Xpath 262144 " X: 262144
+ throw "arrgh"
+ Xpath 524288 " X: 0
+ catch /\l/
+ Xpath 1048576 " X: 1048576
+ endtry
+
+ try
+ Xpath 2097152 " X: 2097152
+ throw "arrgh"
+ Xpath 4194304 " X: 0
+ catch /^\l\+$/
+ Xpath 8388608 " X: 8388608
+ endtry
+
+ try
+ try
+ Xpath 16777216 " X: 16777216
+ throw "ARRGH"
+ Xpath 33554432 " X: 0
+ catch /^arrgh$/
+ Xpath 67108864 " X: 0
+ endtry
+ catch /^\carrgh$/
+ Xpath 134217728 " X: 134217728
+ endtry
+
+ try
+ Xpath 268435456 " X: 268435456
+ throw ""
+ Xpath 536870912 " X: 0
+ catch /^$/
+ Xpath 1073741824 " X: 1073741824
+ endtry
+
+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
+
+Xcheck 1505155949
+
+
+"-------------------------------------------------------------------------------
+" Test 43: Selecting the correct :catch clause {{{1
+"
+" When an exception is thrown and there are multiple :catch clauses,
+" the first matching one is taken.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+XloopINIT 1 1024
+let loops = 3
+while loops > 0
+ try
+ if loops == 3
+ Xloop 1 " X: 1
+ throw "a"
+ Xloop 2 " X: 0
+ elseif loops == 2
+ Xloop 4 " X: 4*1024
+ throw "ab"
+ Xloop 8 " X: 0
+ elseif loops == 1
+ Xloop 16 " X: 16*1024*1024
+ throw "abc"
+ Xloop 32 " X: 0
+ endif
+ catch /abc/
+ Xloop 64 " X: 64*1024*1024
+ catch /ab/
+ Xloop 128 " X: 128*1024
+ catch /.*/
+ Xloop 256 " X: 256
+ catch /a/
+ Xloop 512 " X: 0
+ endtry
+
+ let loops = loops - 1
+ XloopNEXT
+endwhile
+Xpath 1073741824 " X: 1073741824
+
+unlet loops
+
+Xcheck 1157763329
+
+
+"-------------------------------------------------------------------------------
+" Test 44: Missing or empty :catch patterns {{{1
+"
+" A missing or empty :catch pattern means the same as /.*/, that is,
+" catches everything. To catch only empty exceptions, /^$/ must be
+" used. A :catch with missing, empty, or /.*/ argument also works
+" when followed by another command separated by a bar on the same
+" line. :catch patterns cannot be specified between ||. But other
+" pattern separators can be used instead of //.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+try
+ try
+ Xpath 1 " X: 1
+ throw ""
+ catch /^$/
+ Xpath 2 " X: 2
+ endtry
+
+ try
+ Xpath 4 " X: 4
+ throw ""
+ catch /.*/
+ Xpath 8 " X: 8
+ endtry
+
+ try
+ Xpath 16 " X: 16
+ throw ""
+ catch //
+ Xpath 32 " X: 32
+ endtry
+
+ try
+ Xpath 64 " X: 64
+ throw ""
+ catch
+ Xpath 128 " X: 128
+ endtry
+
+ try
+ Xpath 256 " X: 256
+ throw "oops"
+ catch /^$/
+ Xpath 512 " X: 0
+ catch /.*/
+ Xpath 1024 " X: 1024
+ endtry
+
+ try
+ Xpath 2048 " X: 2048
+ throw "arrgh"
+ catch /^$/
+ Xpath 4096 " X: 0
+ catch //
+ Xpath 8192 " X: 8192
+ endtry
+
+ try
+ Xpath 16384 " X: 16384
+ throw "brrr"
+ catch /^$/
+ Xpath 32768 " X: 0
+ catch
+ Xpath 65536 " X: 65536
+ endtry
+
+ try | Xpath 131072 | throw "x" | catch /.*/ | Xpath 262144 | endtry
+ " X: 131072 + 262144
+
+ try | Xpath 524288 | throw "y" | catch // | Xpath 1048576 | endtry
+ " X: 524288 + 1048576
+
+ while 1
+ try
+ let caught = 0
+ let v:errmsg = ""
+ " Extra try level: if ":catch" without arguments below raises
+ " a syntax error because it misinterprets the "Xpath" as a pattern,
+ " let it be caught by the ":catch /.*/" below.
+ try
+ try | Xpath 2097152 | throw "z" | catch | Xpath 4194304 | :
+ endtry " X: 2097152 + 4194304
+ endtry
+ catch /.*/
+ let caught = 1
+ Xout v:exception "in" v:throwpoint
+ finally
+ if $VIMNOERRTHROW && v:errmsg != ""
+ Xout v:errmsg
+ endif
+ if caught || $VIMNOERRTHROW && v:errmsg != ""
+ Xpath 8388608 " X: 0
+ endif
+ break " discard error for $VIMNOERRTHROW
+ endtry
+ endwhile
+
+ let cologne = 4711
+ try
+ try
+ Xpath 16777216 " X: 16777216
+ throw "throw cologne"
+ " Next lines catches all and throws 4711:
+ catch |throw cologne|
+ Xpath 33554432 " X: 0
+ endtry
+ catch /4711/
+ Xpath 67108864 " X: 67108864
+ endtry
+
+ try
+ Xpath 134217728 " X: 134217728
+ throw "plus"
+ catch +plus+
+ Xpath 268435456 " X: 268435456
+ endtry
+
+ Xpath 536870912 " X: 536870912
+catch /.*/
+ Xpath 1073741824 " X: 0
+ Xout v:exception "in" v:throwpoint
+endtry
+
+unlet! caught cologne
+
+Xcheck 1031761407
+
+
+"-------------------------------------------------------------------------------
+" Test 45: Catching exceptions from nested :try blocks {{{1
+"
+" When :try blocks are nested, an exception is caught by the innermost
+" try conditional that has a matching :catch clause.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+XloopINIT 1 1024
+let loops = 3
+while loops > 0
+ try
+ try
+ try
+ try
+ if loops == 3
+ Xloop 1 " X: 1
+ throw "a"
+ Xloop 2 " X: 0
+ elseif loops == 2
+ Xloop 4 " X: 4*1024
+ throw "ab"
+ Xloop 8 " X: 0
+ elseif loops == 1
+ Xloop 16 " X: 16*1024*1024
+ throw "abc"
+ Xloop 32 " X: 0
+ endif
+ catch /abc/
+ Xloop 64 " X: 64*1024*1024
+ endtry
+ catch /ab/
+ Xloop 128 " X: 128*1024
+ endtry
+ catch /.*/
+ Xloop 256 " X: 256
+ endtry
+ catch /a/
+ Xloop 512 " X: 0
+ endtry
+
+ let loops = loops - 1
+ XloopNEXT
+endwhile
+Xpath 1073741824 " X: 1073741824
+
+unlet loops
+
+Xcheck 1157763329
+
+
+"-------------------------------------------------------------------------------
+" Test 46: Executing :finally after a :throw in nested :try {{{1
+"
+" When an exception is thrown from within nested :try blocks, the
+" :finally clauses of the non-catching try conditionals should be
+" executed before the matching :catch of the next surrounding :try
+" gets the control. If this also has a :finally clause, it is
+" executed afterwards.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+let sum = 0
+
+try
+ Xpath 1 " X: 1
+ try
+ Xpath 2 " X: 2
+ try
+ Xpath 4 " X: 4
+ try
+ Xpath 8 " X: 8
+ throw "ABC"
+ Xpath 16 " X: 0
+ catch /xyz/
+ Xpath 32 " X: 0
+ finally
+ Xpath 64 " X: 64
+ if sum != 0
+ Xpath 128 " X: 0
+ endif
+ let sum = sum + 1
+ endtry
+ Xpath 256 " X: 0
+ catch /123/
+ Xpath 512 " X: 0
+ catch /321/
+ Xpath 1024 " X: 0
+ finally
+ Xpath 2048 " X: 2048
+ if sum != 1
+ Xpath 4096 " X: 0
+ endif
+ let sum = sum + 2
+ endtry
+ Xpath 8192 " X: 0
+ finally
+ Xpath 16384 " X: 16384
+ if sum != 3
+ Xpath 32768 " X: 0
+ endif
+ let sum = sum + 4
+ endtry
+ Xpath 65536 " X: 0
+catch /ABC/
+ Xpath 131072 " X: 131072
+ if sum != 7
+ Xpath 262144 " X: 0
+ endif
+ let sum = sum + 8
+finally
+ Xpath 524288 " X: 524288
+ if sum != 15
+ Xpath 1048576 " X: 0
+ endif
+ let sum = sum + 16
+endtry
+Xpath 65536 " X: 65536
+if sum != 31
+ Xpath 131072 " X: 0
+endif
+
+unlet sum
+
+Xcheck 739407
+
+
+"-------------------------------------------------------------------------------
+" Test 47: Throwing exceptions from a :catch clause {{{1
+"
+" When an exception is thrown from a :catch clause, it should not be
+" caught by a :catch of the same :try conditional. After executing
+" the :finally clause (if present), surrounding try conditionals
+" should be checked for a matching :catch.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+Xpath 1 " X: 1
+try
+ Xpath 2 " X: 2
+ try
+ Xpath 4 " X: 4
+ try
+ Xpath 8 " X: 8
+ throw "x1"
+ Xpath 16 " X: 0
+ catch /x1/
+ Xpath 32 " X: 32
+ try
+ Xpath 64 " X: 64
+ throw "x2"
+ Xpath 128 " X: 0
+ catch /x1/
+ Xpath 256 " X: 0
+ catch /x2/
+ Xpath 512 " X: 512
+ try
+ Xpath 1024 " X: 1024
+ throw "x3"
+ Xpath 2048 " X: 0
+ catch /x1/
+ Xpath 4096 " X: 0
+ catch /x2/
+ Xpath 8192 " X: 0
+ finally
+ Xpath 16384 " X: 16384
+ endtry
+ Xpath 32768 " X: 0
+ catch /x3/
+ Xpath 65536 " X: 0
+ endtry
+ Xpath 131072 " X: 0
+ catch /x1/
+ Xpath 262144 " X: 0
+ catch /x2/
+ Xpath 524288 " X: 0
+ catch /x3/
+ Xpath 1048576 " X: 0
+ finally
+ Xpath 2097152 " X: 2097152
+ endtry
+ Xpath 4194304 " X: 0
+ catch /x1/
+ Xpath 8388608 " X: 0
+ catch /x2/
+ Xpath 16777216 " X: 0
+ catch /x3/
+ Xpath 33554432 " X: 33554432
+ endtry
+ Xpath 67108864 " X: 67108864
+catch /.*/
+ Xpath 134217728 " X: 0
+ Xout v:exception "in" v:throwpoint
+endtry
+Xpath 268435456 " X: 268435456
+
+Xcheck 371213935
+
+
+"-------------------------------------------------------------------------------
+" Test 48: Throwing exceptions from a :finally clause {{{1
+"
+" When an exception is thrown from a :finally clause, it should not be
+" caught by a :catch of the same :try conditional. Surrounding try
+" conditionals should be checked for a matching :catch. A previously
+" thrown exception is discarded.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+try
+
+ try
+ try
+ Xpath 1 " X: 1
+ catch /x1/
+ Xpath 2 " X: 0
+ finally
+ Xpath 4 " X: 4
+ throw "x1"
+ Xpath 8 " X: 0
+ endtry
+ Xpath 16 " X: 0
+ catch /x1/
+ Xpath 32 " X: 32
+ endtry
+ Xpath 64 " X: 64
+
+ try
+ try
+ Xpath 128 " X: 128
+ throw "x2"
+ Xpath 256 " X: 0
+ catch /x2/
+ Xpath 512 " X: 512
+ catch /x3/
+ Xpath 1024 " X: 0
+ finally
+ Xpath 2048 " X: 2048
+ throw "x3"
+ Xpath 4096 " X: 0
+ endtry
+ Xpath 8192 " X: 0
+ catch /x2/
+ Xpath 16384 " X: 0
+ catch /x3/
+ Xpath 32768 " X: 32768
+ endtry
+ Xpath 65536 " X: 65536
+
+ try
+ try
+ try
+ Xpath 131072 " X: 131072
+ throw "x4"
+ Xpath 262144 " X: 0
+ catch /x5/
+ Xpath 524288 " X: 0
+ finally
+ Xpath 1048576 " X: 1048576
+ throw "x5" " discards "x4"
+ Xpath 2097152 " X: 0
+ endtry
+ Xpath 4194304 " X: 0
+ catch /x4/
+ Xpath 8388608 " X: 0
+ finally
+ Xpath 16777216 " X: 16777216
+ endtry
+ Xpath 33554432 " X: 0
+ catch /x5/
+ Xpath 67108864 " X: 67108864
+ endtry
+ Xpath 134217728 " X: 134217728
+
+catch /.*/
+ Xpath 268435456 " X: 0
+ Xout v:exception "in" v:throwpoint
+endtry
+Xpath 536870912 " X: 536870912
+
+Xcheck 756255461
+
+
+"-------------------------------------------------------------------------------
+" Test 49: Throwing exceptions across functions {{{1
+"
+" When an exception is thrown but not caught inside a function, the
+" caller is checked for a matching :catch clause.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+function! C()
+ try
+ Xpath 1 " X: 1
+ throw "arrgh"
+ Xpath 2 " X: 0
+ catch /arrgh/
+ Xpath 4 " X: 4
+ endtry
+ Xpath 8 " X: 8
+endfunction
+
+XloopINIT! 16 16
+
+function! T1()
+ XloopNEXT
+ try
+ Xloop 1 " X: 16 + 16*16
+ throw "arrgh"
+ Xloop 2 " X: 0
+ finally
+ Xloop 4 " X: 64 + 64*16
+ endtry
+ Xloop 8 " X: 0
+endfunction
+
+function! T2()
+ try
+ Xpath 4096 " X: 4096
+ call T1()
+ Xpath 8192 " X: 0
+ finally
+ Xpath 16384 " X: 16384
+ endtry
+ Xpath 32768 " X: 0
+endfunction
+
+try
+ Xpath 65536 " X: 65536
+ call C() " throw and catch
+ Xpath 131072 " X: 131072
+catch /.*/
+ Xpath 262144 " X: 0
+ Xout v:exception "in" v:throwpoint
+endtry
+
+try
+ Xpath 524288 " X: 524288
+ call T1() " throw, one level
+ Xpath 1048576 " X: 0
+catch /arrgh/
+ Xpath 2097152 " X: 2097152
+catch /.*/
+ Xpath 4194304 " X: 0
+ Xout v:exception "in" v:throwpoint
+endtry
+
+try
+ Xpath 8388608 " X: 8388608
+ call T2() " throw, two levels
+ Xpath 16777216 " X: 0
+catch /arrgh/
+ Xpath 33554432 " X: 33554432
+catch /.*/
+ Xpath 67108864 " X: 0
+ Xout v:exception "in" v:throwpoint
+endtry
+Xpath 134217728 " X: 134217728
+
+Xcheck 179000669
+
+" Leave C, T1, and T2 for execution as scripts in the next test.
+
+
+"-------------------------------------------------------------------------------
+" Test 50: Throwing exceptions across script files {{{1
+"
+" When an exception is thrown but not caught inside a script file,
+" the sourcing script or function is checked for a matching :catch
+" clause.
+"
+" This test executes the bodies of the functions C, T1, and T2 from
+" the previous test as script files (:return replaced by :finish).
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+let scriptC = MakeScript("C") " X: 1 + 4 + 8
+delfunction C
+
+XloopINIT! 16 16
+
+let scriptT1 = MakeScript("T1") " X: 16 + 64 + 16*16 + 64*16
+delfunction T1
+
+let scriptT2 = MakeScript("T2", scriptT1) " X: 4096 + 16384
+delfunction T2
+
+function! F()
+ try
+ Xpath 65536 " X: 65536
+ exec "source" g:scriptC
+ Xpath 131072 " X: 131072
+ catch /.*/
+ Xpath 262144 " X: 0
+ Xout v:exception "in" v:throwpoint
+ endtry
+
+ try
+ Xpath 524288 " X: 524288
+ exec "source" g:scriptT1
+ Xpath 1048576 " X: 0
+ catch /arrgh/
+ Xpath 2097152 " X: 2097152
+ catch /.*/
+ Xpath 4194304 " X: 0
+ Xout v:exception "in" v:throwpoint
+ endtry
+endfunction
+
+try
+ Xpath 8388608 " X: 8388608
+ call F()
+ Xpath 16777216 " X: 16777216
+ exec "source" scriptT2
+ Xpath 33554432 " X: 0
+catch /arrgh/
+ Xpath 67108864 " X: 67108864
+catch /.*/
+ Xpath 134217728 " X: 0
+ Xout v:exception "in" v:throwpoint
+endtry
+Xpath 268435456 " X: 268435456
+
+call delete(scriptC)
+call delete(scriptT1)
+call delete(scriptT2)
+unlet scriptC scriptT1 scriptT2
+delfunction F
+
+Xcheck 363550045
+
+
+"-------------------------------------------------------------------------------
+" Test 51: Throwing exceptions across :execute and user commands {{{1
+"
+" A :throw command may be executed under an ":execute" or from
+" a user command.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+command! -nargs=? THROW1 throw <args> | throw 1
+command! -nargs=? THROW2 try | throw <args> | endtry | throw 2
+command! -nargs=? THROW3 try | throw 3 | catch /3/ | throw <args> | endtry
+command! -nargs=? THROW4 try | throw 4 | finally | throw <args> | endtry
+
+try
+
+ try
+ try
+ Xpath 1 " X: 1
+ THROW1 "A"
+ catch /A/
+ Xpath 2 " X: 2
+ endtry
+ catch /1/
+ Xpath 4 " X: 0
+ endtry
+
+ try
+ try
+ Xpath 8 " X: 8
+ THROW2 "B"
+ catch /B/
+ Xpath 16 " X: 16
+ endtry
+ catch /2/
+ Xpath 32 " X: 0
+ endtry
+
+ try
+ try
+ Xpath 64 " X: 64
+ THROW3 "C"
+ catch /C/
+ Xpath 128 " X: 128
+ endtry
+ catch /3/
+ Xpath 256 " X: 0
+ endtry
+
+ try
+ try
+ Xpath 512 " X: 512
+ THROW4 "D"
+ catch /D/
+ Xpath 1024 " X: 1024
+ endtry
+ catch /4/
+ Xpath 2048 " X: 0
+ endtry
+
+ try
+ try
+ Xpath 4096 " X: 4096
+ execute 'throw "E" | throw 5'
+ catch /E/
+ Xpath 8192 " X: 8192
+ endtry
+ catch /5/
+ Xpath 16384 " X: 0
+ endtry
+
+ try
+ try
+ Xpath 32768 " X: 32768
+ execute 'try | throw "F" | endtry | throw 6'
+ catch /F/
+ Xpath 65536 " X: 65536
+ endtry
+ catch /6/
+ Xpath 131072 " X: 0
+ endtry
+
+ try
+ try
+ Xpath 262144 " X: 262144
+ execute'try | throw 7 | catch /7/ | throw "G" | endtry'
+ catch /G/
+ Xpath 524288 " X: 524288
+ endtry
+ catch /7/
+ Xpath 1048576 " X: 0
+ endtry
+
+ try
+ try
+ Xpath 2097152 " X: 2097152
+ execute 'try | throw 8 | finally | throw "H" | endtry'
+ catch /H/
+ Xpath 4194304 " X: 4194304
+ endtry
+ catch /8/
+ Xpath 8388608 " X: 0
+ endtry
+
+catch /.*/
+ Xpath 16777216 " X: 0
+ Xout v:exception "in" v:throwpoint
+endtry
+
+Xpath 33554432 " X: 33554432
+
+delcommand THROW1
+delcommand THROW2
+delcommand THROW3
+delcommand THROW4
+
+Xcheck 40744667
+
+
+"-------------------------------------------------------------------------------
+" Test 52: Uncaught exceptions {{{1
+"
+" When an exception is thrown but not caught, an error message is
+" displayed when the script is terminated. In case of an interrupt
+" or error exception, the normal interrupt or error message(s) are
+" displayed.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+let msgfile = tempname()
+
+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
+
+if ExtraVim(msgfile)
+ Xpath 1 " X: 1
+ throw "arrgh"
+endif
+
+Xpath 2 " X: 2
+if !MESSAGES('E605', "Exception not caught")
+ Xpath 4 " X: 0
+endif
+
+if ExtraVim(msgfile)
+ try
+ Xpath 8 " X: 8
+ throw "oops"
+ catch /arrgh/
+ Xpath 16 " X: 0
+ endtry
+ Xpath 32 " X: 0
+endif
+
+Xpath 64 " X: 64
+if !MESSAGES('E605', "Exception not caught")
+ Xpath 128 " X: 0
+endif
+
+if ExtraVim(msgfile)
+ function! T()
+ throw "brrr"
+ endfunction
+
+ try
+ Xpath 256 " X: 256
+ throw "arrgh"
+ catch /.*/
+ Xpath 512 " X: 512
+ call T()
+ endtry
+ Xpath 1024 " X: 0
+endif
+
+Xpath 2048 " X: 2048
+if !MESSAGES('E605', "Exception not caught")
+ Xpath 4096 " X: 0
+endif
+
+if ExtraVim(msgfile)
+ try
+ Xpath 8192 " X: 8192
+ throw "arrgh"
+ finally
+ Xpath 16384 " X: 16384
+ throw "brrr"
+ endtry
+ Xpath 32768 " X: 0
+endif
+
+Xpath 65536 " X: 65536
+if !MESSAGES('E605', "Exception not caught")
+ Xpath 131072 " X: 0
+endif
+
+if ExtraVim(msgfile)
+ try
+ Xpath 262144 " X: 262144
+ "INTERRUPT
+ endtry
+ Xpath 524288 " X: 0
+endif
+
+Xpath 1048576 " X: 1048576
+if !MESSAGES('INT', "Interrupted")
+ Xpath 2097152 " X: 0
+endif
+
+if ExtraVim(msgfile)
+ try
+ Xpath 4194304 " X: 4194304
+ let x = novar " error E121; exception: E121
+ catch /E15:/ " should not catch
+ Xpath 8388608 " X: 0
+ endtry
+ Xpath 16777216 " X: 0
+endif
+
+Xpath 33554432 " X: 33554432
+if !MESSAGES('E121', "Undefined variable")
+ Xpath 67108864 " X: 0
+endif
+
+if ExtraVim(msgfile)
+ try
+ Xpath 134217728 " X: 134217728
+" unlet novar # " error E108/E488; exception: E488
+ catch /E108:/ " should not catch
+ Xpath 268435456 " X: 0
+ endtry
+ Xpath 536870912 " X: 0
+endif
+
+Xpath 1073741824 " X: 1073741824
+if !MESSAGES('E108', "No such variable", 'E488', "Trailing characters")
+ " The Xpath command does not accept 2^31 (negative); add explicitly:
+ let Xpath = Xpath + 2147483648 " X: 0
+endif
+
+call delete(msgfile)
+unlet msgfile
+
+Xcheck 1247112011
+
+" Leave MESSAGES() for the next tests.
+
+
+"-------------------------------------------------------------------------------
+" Test 53: Nesting errors: :endif/:else/:elseif {{{1
+"
+" For nesting errors of :if conditionals the correct error messages
+" should be given.
+"
+" This test reuses the function MESSAGES() from the previous test.
+" This functions checks the messages in g:msgfile.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+let msgfile = tempname()
+
+if ExtraVim(msgfile)
+" endif
+endif
+if MESSAGES('E580', ":endif without :if")
+ Xpath 1 " X: 1
+endif
+
+if ExtraVim(msgfile)
+" while 1
+" endif
+" endwhile
+endif
+if MESSAGES('E580', ":endif without :if")
+ Xpath 2 " X: 2
+endif
+
+if ExtraVim(msgfile)
+" try
+" finally
+" endif
+" endtry
+endif
+if MESSAGES('E580', ":endif without :if")
+ Xpath 4 " X: 4
+endif
+
+if ExtraVim(msgfile)
+" try
+" endif
+" endtry
+endif
+if MESSAGES('E580', ":endif without :if")
+ Xpath 8 " X: 8
+endif
+
+if ExtraVim(msgfile)
+" try
+" throw "a"
+" catch /a/
+" endif
+" endtry
+endif
+if MESSAGES('E580', ":endif without :if")
+ Xpath 16 " X: 16
+endif
+
+if ExtraVim(msgfile)
+" else
+endif
+if MESSAGES('E581', ":else without :if")
+ Xpath 32 " X: 32
+endif
+
+if ExtraVim(msgfile)
+" while 1
+" else
+" endwhile
+endif
+if MESSAGES('E581', ":else without :if")
+ Xpath 64 " X: 64
+endif
+
+if ExtraVim(msgfile)
+" try
+" finally
+" else
+" endtry
+endif
+if MESSAGES('E581', ":else without :if")
+ Xpath 128 " X: 128
+endif
+
+if ExtraVim(msgfile)
+" try
+" else
+" endtry
+endif
+if MESSAGES('E581', ":else without :if")
+ Xpath 256 " X: 256
+endif
+
+if ExtraVim(msgfile)
+" try
+" throw "a"
+" catch /a/
+" else
+" endtry
+endif
+if MESSAGES('E581', ":else without :if")
+ Xpath 512 " X: 512
+endif
+
+if ExtraVim(msgfile)
+" elseif
+endif
+if MESSAGES('E582', ":elseif without :if")
+ Xpath 1024 " X: 1024
+endif
+
+if ExtraVim(msgfile)
+" while 1
+" elseif
+" endwhile
+endif
+if MESSAGES('E582', ":elseif without :if")
+ Xpath 2048 " X: 2048
+endif
+
+if ExtraVim(msgfile)
+" try
+" finally
+" elseif
+" endtry
+endif
+if MESSAGES('E582', ":elseif without :if")
+ Xpath 4096 " X: 4096
+endif
+
+if ExtraVim(msgfile)
+" try
+" elseif
+" endtry
+endif
+if MESSAGES('E582', ":elseif without :if")
+ Xpath 8192 " X: 8192
+endif
+
+if ExtraVim(msgfile)
+" try
+" throw "a"
+" catch /a/
+" elseif
+" endtry
+endif
+if MESSAGES('E582', ":elseif without :if")
+ Xpath 16384 " X: 16384
+endif
+
+if ExtraVim(msgfile)
+" if 1
+" else
+" else
+" endif
+endif
+if MESSAGES('E583', "multiple :else")
+ Xpath 32768 " X: 32768
+endif
+
+if ExtraVim(msgfile)
+" if 1
+" else
+" elseif 1
+" endif
+endif
+if MESSAGES('E584', ":elseif after :else")
+ Xpath 65536 " X: 65536
+endif
+
+call delete(msgfile)
+unlet msgfile
+
+Xcheck 131071
+
+" Leave MESSAGES() for the next test.
+
+
+"-------------------------------------------------------------------------------
+" Test 54: Nesting errors: :while/:endwhile {{{1
+"
+" For nesting errors of :while conditionals the correct error messages
+" should be given.
+"
+" This test reuses the function MESSAGES() from the previous test.
+" This functions checks the messages in g:msgfile.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+let msgfile = tempname()
+
+if ExtraVim(msgfile)
+" endwhile
+endif
+if MESSAGES('E588', ":endwhile without :while")
+ Xpath 1 " X: 1
+endif
+
+if ExtraVim(msgfile)
+" if 1
+" endwhile
+" endif
+endif
+if MESSAGES('E588', ":endwhile without :while")
+ Xpath 2 " X: 2
+endif
+
+if ExtraVim(msgfile)
+" while 1
+" if 1
+" endwhile
+endif
+if MESSAGES('E171', "Missing :endif")
+ Xpath 4 " X: 4
+endif
+
+if ExtraVim(msgfile)
+" try
+" finally
+" endwhile
+" endtry
+endif
+if MESSAGES('E588', ":endwhile without :while")
+ Xpath 8 " X: 8
+endif
+
+if ExtraVim(msgfile)
+" while 1
+" try
+" finally
+" endwhile
+endif
+if MESSAGES('E600', "Missing :endtry")
+ Xpath 16 " X: 16
+endif
+
+if ExtraVim(msgfile)
+" while 1
+" if 1
+" try
+" finally
+" endwhile
+endif
+if MESSAGES('E600', "Missing :endtry")
+ Xpath 32 " X: 32
+endif
+
+if ExtraVim(msgfile)
+" while 1
+" try
+" finally
+" if 1
+" endwhile
+endif
+if MESSAGES('E171', "Missing :endif")
+ Xpath 64 " X: 64
+endif
+
+if ExtraVim(msgfile)
+" try
+" endwhile
+" endtry
+endif
+if MESSAGES('E588', ":endwhile without :while")
+ Xpath 128 " X: 128
+endif
+
+if ExtraVim(msgfile)
+" while 1
+" try
+" endwhile
+" endtry
+" endwhile
+endif
+if MESSAGES('E588', ":endwhile without :while")
+ Xpath 256 " X: 256
+endif
+
+if ExtraVim(msgfile)
+" try
+" throw "a"
+" catch /a/
+" endwhile
+" endtry
+endif
+if MESSAGES('E588', ":endwhile without :while")
+ Xpath 512 " X: 512
+endif
+
+if ExtraVim(msgfile)
+" while 1
+" try
+" throw "a"
+" catch /a/
+" endwhile
+" endtry
+" endwhile
+endif
+if MESSAGES('E588', ":endwhile without :while")
+ Xpath 1024 " X: 1024
+endif
+
+
+call delete(msgfile)
+unlet msgfile
+
+Xcheck 2047
+
+" Leave MESSAGES() for the next test.
+
+
+"-------------------------------------------------------------------------------
+" Test 55: Nesting errors: :continue/:break {{{1
+"
+" For nesting errors of :continue and :break commands the correct
+" error messages should be given.
+"
+" This test reuses the function MESSAGES() from the previous test.
+" This functions checks the messages in g:msgfile.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+let msgfile = tempname()
+
+if ExtraVim(msgfile)
+" continue
+endif
+if MESSAGES('E586', ":continue without :while")
+ Xpath 1 " X: 1
+endif
+
+if ExtraVim(msgfile)
+" if 1
+" continue
+" endif
+endif
+if MESSAGES('E586', ":continue without :while")
+ Xpath 2 " X: 2
+endif
+
+if ExtraVim(msgfile)
+" try
+" finally
+" continue
+" endtry
+endif
+if MESSAGES('E586', ":continue without :while")
+ Xpath 4 " X: 4
+endif
+
+if ExtraVim(msgfile)
+" try
+" continue
+" endtry
+endif
+if MESSAGES('E586', ":continue without :while")
+ Xpath 8 " X: 8
+endif
+
+if ExtraVim(msgfile)
+" try
+" throw "a"
+" catch /a/
+" continue
+" endtry
+endif
+if MESSAGES('E586', ":continue without :while")
+ Xpath 16 " X: 16
+endif
+
+if ExtraVim(msgfile)
+" break
+endif
+if MESSAGES('E587', ":break without :while")
+ Xpath 32 " X: 32
+endif
+
+if ExtraVim(msgfile)
+" if 1
+" break
+" endif
+endif
+if MESSAGES('E587', ":break without :while")
+ Xpath 64 " X: 64
+endif
+
+if ExtraVim(msgfile)
+" try
+" finally
+" break
+" endtry
+endif
+if MESSAGES('E587', ":break without :while")
+ Xpath 128 " X: 128
+endif
+
+if ExtraVim(msgfile)
+" try
+" break
+" endtry
+endif
+if MESSAGES('E587', ":break without :while")
+ Xpath 256 " X: 256
+endif
+
+if ExtraVim(msgfile)
+" try
+" throw "a"
+" catch /a/
+" break
+" endtry
+endif
+if MESSAGES('E587', ":break without :while")
+ Xpath 512 " X: 512
+endif
+
+call delete(msgfile)
+unlet msgfile
+
+Xcheck 1023
+
+" Leave MESSAGES() for the next test.
+
+
+"-------------------------------------------------------------------------------
+" Test 56: Nesting errors: :endtry {{{1
+"
+" For nesting errors of :try conditionals the correct error messages
+" should be given.
+"
+" This test reuses the function MESSAGES() from the previous test.
+" This functions checks the messages in g:msgfile.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+let msgfile = tempname()
+
+if ExtraVim(msgfile)
+" endtry
+endif
+if MESSAGES('E602', ":endtry without :try")
+ Xpath 1 " X: 1
+endif
+
+if ExtraVim(msgfile)
+" if 1
+" endtry
+" endif
+endif
+if MESSAGES('E602', ":endtry without :try")
+ Xpath 2 " X: 2
+endif
+
+if ExtraVim(msgfile)
+" while 1
+" endtry
+" endwhile
+endif
+if MESSAGES('E602', ":endtry without :try")
+ Xpath 4 " X: 4
+endif
+
+if ExtraVim(msgfile)
+" try
+" if 1
+" endtry
+endif
+if MESSAGES('E171', "Missing :endif")
+ Xpath 8 " X: 8
+endif
+
+if ExtraVim(msgfile)
+" try
+" while 1
+" endtry
+endif
+if MESSAGES('E170', "Missing :endwhile")
+ Xpath 16 " X: 16
+endif
+
+if ExtraVim(msgfile)
+" try
+" finally
+" if 1
+" endtry
+endif
+if MESSAGES('E171', "Missing :endif")
+ Xpath 32 " X: 32
+endif
+
+if ExtraVim(msgfile)
+" try
+" finally
+" while 1
+" endtry
+endif
+if MESSAGES('E170', "Missing :endwhile")
+ Xpath 64 " X: 64
+endif
+
+if ExtraVim(msgfile)
+" try
+" throw "a"
+" catch /a/
+" if 1
+" endtry
+endif
+if MESSAGES('E171', "Missing :endif")
+ Xpath 128 " X: 128
+endif
+
+if ExtraVim(msgfile)
+" try
+" throw "a"
+" catch /a/
+" while 1
+" endtry
+endif
+if MESSAGES('E170', "Missing :endwhile")
+ Xpath 256 " X: 256
+endif
+
+call delete(msgfile)
+unlet msgfile
+
+delfunction MESSAGES
+
+Xcheck 511
+
+
+"-------------------------------------------------------------------------------
+" Test 57: v:exception and v:throwpoint for user exceptions {{{1
+"
+" v:exception evaluates to the value of the exception that was caught
+" most recently and is not finished. (A caught exception is finished
+" when the next ":catch", ":finally", or ":endtry" is reached.)
+" v:throwpoint evaluates to the script/function name and line number
+" where that exception has been thrown.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+function! FuncException()
+ let g:exception = v:exception
+endfunction
+
+function! FuncThrowpoint()
+ let g:throwpoint = v:throwpoint
+endfunction
+
+let scriptException = MakeScript("FuncException")
+let scriptThrowPoint = MakeScript("FuncThrowpoint")
+
+command! CmdException let g:exception = v:exception
+command! CmdThrowpoint let g:throwpoint = v:throwpoint
+
+XloopINIT! 1 2
+
+function! CHECK(n, exception, throwname, throwline)
+ XloopNEXT
+ let error = 0
+ if v:exception != a:exception
+ Xout a:n.": v:exception is" v:exception "instead of" a:exception
+ let error = 1
+ endif
+ if v:throwpoint !~ a:throwname
+ let name = escape(a:throwname, '\')
+ Xout a:n.": v:throwpoint (".v:throwpoint.") does not match" name
+ let error = 1
+ endif
+ if v:throwpoint !~ a:throwline
+ let line = escape(a:throwline, '\')
+ Xout a:n.": v:throwpoint (".v:throwpoint.") does not match" line
+ let error = 1
+ endif
+ if error
+ Xloop 1 " X: 0
+ endif
+endfunction
+
+function! T(arg, line)
+ if a:line == 2
+ throw a:arg " in line 2
+ elseif a:line == 4
+ throw a:arg " in line 4
+ elseif a:line == 6
+ throw a:arg " in line 6
+ elseif a:line == 8
+ throw a:arg " in line 8
+ endif
+endfunction
+
+function! G(arg, line)
+ call T(a:arg, a:line)
+endfunction
+
+function! F(arg, line)
+ call G(a:arg, a:line)
+endfunction
+
+let scriptT = MakeScript("T")
+let scriptG = MakeScript("G", scriptT)
+let scriptF = MakeScript("F", scriptG)
+
+try
+ Xpath 32768 " X: 32768
+ call F("oops", 2)
+catch /.*/
+ Xpath 65536 " X: 65536
+ let exception = v:exception
+ let throwpoint = v:throwpoint
+ call CHECK(1, "oops", '\<F\[1]\.\.G\[1]\.\.T\>', '\<2\>')
+ exec "let exception = v:exception"
+ exec "let throwpoint = v:throwpoint"
+ call CHECK(2, "oops", '\<F\[1]\.\.G\[1]\.\.T\>', '\<2\>')
+ CmdException
+ CmdThrowpoint
+ call CHECK(3, "oops", '\<F\[1]\.\.G\[1]\.\.T\>', '\<2\>')
+ call FuncException()
+ call FuncThrowpoint()
+ call CHECK(4, "oops", '\<F\[1]\.\.G\[1]\.\.T\>', '\<2\>')
+ exec "source" scriptException
+ exec "source" scriptThrowPoint
+ call CHECK(5, "oops", '\<F\[1]\.\.G\[1]\.\.T\>', '\<2\>')
+ try
+ Xpath 131072 " X: 131072
+ call G("arrgh", 4)
+ catch /.*/
+ Xpath 262144 " X: 262144
+ let exception = v:exception
+ let throwpoint = v:throwpoint
+ call CHECK(6, "arrgh", '\<G\[1]\.\.T\>', '\<4\>')
+ try
+ Xpath 524288 " X: 524288
+ let g:arg = "autsch"
+ let g:line = 6
+ exec "source" scriptF
+ catch /.*/
+ Xpath 1048576 " X: 1048576
+ let exception = v:exception
+ let throwpoint = v:throwpoint
+ " Symbolic links in tempname()s are not resolved, whereas resolving
+ " is done for v:throwpoint. Resolve the temporary file name for
+ " scriptT, so that it can be matched against v:throwpoint.
+ call CHECK(7, "autsch", resolve(scriptT), '\<6\>')
+ finally
+ Xpath 2097152 " X: 2097152
+ let exception = v:exception
+ let throwpoint = v:throwpoint
+ call CHECK(8, "arrgh", '\<G\[1]\.\.T\>', '\<4\>')
+ try
+ Xpath 4194304 " X: 4194304
+ let g:arg = "brrrr"
+ let g:line = 8
+ exec "source" scriptG
+ catch /.*/
+ Xpath 8388608 " X: 8388608
+ let exception = v:exception
+ let throwpoint = v:throwpoint
+ " Resolve scriptT for matching it against v:throwpoint.
+ call CHECK(9, "brrrr", resolve(scriptT), '\<8\>')
+ finally
+ Xpath 16777216 " X: 16777216
+ let exception = v:exception
+ let throwpoint = v:throwpoint
+ call CHECK(10, "arrgh", '\<G\[1]\.\.T\>', '\<4\>')
+ endtry
+ Xpath 33554432 " X: 33554432
+ let exception = v:exception
+ let throwpoint = v:throwpoint
+ call CHECK(11, "arrgh", '\<G\[1]\.\.T\>', '\<4\>')
+ endtry
+ Xpath 67108864 " X: 67108864
+ let exception = v:exception
+ let throwpoint = v:throwpoint
+ call CHECK(12, "arrgh", '\<G\[1]\.\.T\>', '\<4\>')
+ finally
+ Xpath 134217728 " X: 134217728
+ let exception = v:exception
+ let throwpoint = v:throwpoint
+ call CHECK(13, "oops", '\<F\[1]\.\.G\[1]\.\.T\>', '\<2\>')
+ endtry
+ Xpath 268435456 " X: 268435456
+ let exception = v:exception
+ let throwpoint = v:throwpoint
+ call CHECK(14, "oops", '\<F\[1]\.\.G\[1]\.\.T\>', '\<2\>')
+finally
+ Xpath 536870912 " X: 536870912
+ let exception = v:exception
+ let throwpoint = v:throwpoint
+ call CHECK(15, "", '^$', '^$')
+endtry
+
+Xpath 1073741824 " X: 1073741824
+
+unlet exception throwpoint
+delfunction FuncException
+delfunction FuncThrowpoint
+call delete(scriptException)
+call delete(scriptThrowPoint)
+unlet scriptException scriptThrowPoint
+delcommand CmdException
+delcommand CmdThrowpoint
+delfunction T
+delfunction G
+delfunction F
+call delete(scriptT)
+call delete(scriptG)
+call delete(scriptF)
+unlet scriptT scriptG scriptF
+
+Xcheck 2147450880
+
+
+"-------------------------------------------------------------------------------
+"
+" Test 58: v:exception and v:throwpoint for error/interrupt exceptions {{{1
+"
+" v:exception and v:throwpoint work also for error and interrupt
+" exceptions.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+if ExtraVim()
+
+ function! T(line)
+ if a:line == 2
+ delfunction T " error (function in use) in line 2
+ elseif a:line == 4
+ let dummy = 0 " INTERRUPT1 - interrupt in line 4
+ endif
+ endfunction
+
+ while 1
+ try
+ Xpath 1 " X: 1
+ let caught = 0
+ call T(2)
+ catch /.*/
+ let caught = 1
+ if v:exception !~ 'Vim(delfunction):'
+ Xpath 2 " X: 0
+ endif
+ if v:throwpoint !~ '\<T\>'
+ Xpath 4 " X: 0
+ endif
+ if v:throwpoint !~ '\<2\>'
+ Xpath 8 " X: 0
+ endif
+ finally
+ Xpath 16 " X: 16
+ if caught || $VIMNOERRTHROW
+ Xpath 32 " X: 32
+ endif
+ if v:exception != ""
+ Xpath 64 " X: 0
+ endif
+ if v:throwpoint != ""
+ Xpath 128 " X: 0
+ endif
+ break " discard error for $VIMNOERRTHROW
+ endtry
+ endwhile
+
+ Xpath 256 " X: 256
+ if v:exception != ""
+ Xpath 512 " X: 0
+ endif
+ if v:throwpoint != ""
+ Xpath 1024 " X: 0
+ endif
+
+ while 1
+ try
+ Xpath 2048 " X: 2048
+ let caught = 0
+ call T(4)
+ catch /.*/
+ let caught = 1
+ if v:exception != 'Vim:Interrupt'
+ Xpath 4096 " X: 0
+ endif
+ if v:throwpoint !~ '\<T\>'
+ Xpath 8192 " X: 0
+ endif
+ if v:throwpoint !~ '\<4\>'
+ Xpath 16384 " X: 0
+ endif
+ finally
+ Xpath 32768 " X: 32768
+ if caught || $VIMNOINTTHROW
+ Xpath 65536 " X: 65536
+ endif
+ if v:exception != ""
+ Xpath 131072 " X: 0
+ endif
+ if v:throwpoint != ""
+ Xpath 262144 " X: 0
+ endif
+ break " discard error for $VIMNOERRTHROW
+ endtry
+ endwhile
+
+ Xpath 524288 " X: 524288
+ if v:exception != ""
+ Xpath 1048576 " X: 0
+ endif
+ if v:throwpoint != ""
+ Xpath 2097152 " X: 0
+ endif
+
+endif
+
+Xcheck 624945
+
+
+"-------------------------------------------------------------------------------
+"
+" 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("<sfile>")
+
+ function! LineNumber()
+ return substitute(substitute(v:throwpoint, g:sfile, '', ""),
+ \ '\D*\(\d*\).*', '\1', "")
+ endfunction
+
+ command! -nargs=1 SetLineNumber
+ \ try | throw "line" | catch /.*/ | let <args> = 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: Catching interrupt exceptions {{{1
+"
+" When an interrupt occurs inside a :try/:endtry region, an
+" interrupt exception is thrown and can be caught. Its value is
+" "Vim:Interrupt". If the interrupt occurs after an error or a :throw
+" but before a matching :catch is reached, all following :catches of
+" that try block are ignored, but the interrupt exception can be
+" caught by the next surrounding try conditional. An interrupt is
+" ignored when there is a previous interrupt that has not been caught
+" or causes a :finally clause to be executed.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+if ExtraVim()
+
+ while 1
+ try
+ try
+ Xpath 1 " X: 1
+ let caught = 0
+ "INTERRUPT
+ Xpath 2 " X: 0
+ catch /^Vim:Interrupt$/
+ let caught = 1
+ finally
+ Xpath 4 " X: 4
+ if caught || $VIMNOINTTHROW
+ Xpath 8 " X: 8
+ endif
+ endtry
+ catch /.*/
+ Xpath 16 " X: 0
+ Xout v:exception "in" v:throwpoint
+ finally
+ break " discard interrupt for $VIMNOINTTHROW
+ endtry
+ endwhile
+
+ while 1
+ try
+ try
+ let caught = 0
+ try
+ Xpath 32 " X: 32
+ asdf
+ Xpath 64 " X: 0
+ catch /do_not_catch/
+ Xpath 128 " X: 0
+ catch /.*/ "INTERRUPT - throw interrupt if !$VIMNOERRTHROW
+ Xpath 256 " X: 0
+ catch /.*/
+ Xpath 512 " X: 0
+ finally "INTERRUPT - throw interrupt if $VIMNOERRTHROW
+ Xpath 1024 " X: 1024
+ endtry
+ catch /^Vim:Interrupt$/
+ let caught = 1
+ finally
+ Xpath 2048 " X: 2048
+ if caught || $VIMNOINTTHROW
+ Xpath 4096 " X: 4096
+ endif
+ endtry
+ catch /.*/
+ Xpath 8192 " X: 0
+ Xout v:exception "in" v:throwpoint
+ finally
+ break " discard interrupt for $VIMNOINTTHROW
+ endtry
+ endwhile
+
+ while 1
+ try
+ try
+ let caught = 0
+ try
+ Xpath 16384 " X: 16384
+ throw "x"
+ Xpath 32768 " X: 0
+ catch /do_not_catch/
+ Xpath 65536 " X: 0
+ catch /x/ "INTERRUPT
+ Xpath 131072 " X: 0
+ catch /.*/
+ Xpath 262144 " X: 0
+ endtry
+ catch /^Vim:Interrupt$/
+ let caught = 1
+ finally
+ Xpath 524288 " X: 524288
+ if caught || $VIMNOINTTHROW
+ Xpath 1048576 " X: 1048576
+ endif
+ endtry
+ catch /.*/
+ Xpath 2097152 " X: 0
+ Xout v:exception "in" v:throwpoint
+ finally
+ break " discard interrupt for $VIMNOINTTHROW
+ endtry
+ endwhile
+
+ while 1
+ try
+ let caught = 0
+ try
+ Xpath 4194304 " X: 4194304
+ "INTERRUPT
+ Xpath 8388608 " X: 0
+ catch /do_not_catch/ "INTERRUPT
+ Xpath 16777216 " X: 0
+ catch /^Vim:Interrupt$/
+ let caught = 1
+ finally
+ Xpath 33554432 " X: 33554432
+ if caught || $VIMNOINTTHROW
+ Xpath 67108864 " X: 67108864
+ endif
+ endtry
+ catch /.*/
+ Xpath 134217728 " X: 0
+ Xout v:exception "in" v:throwpoint
+ finally
+ break " discard interrupt for $VIMNOINTTHROW
+ endtry
+ endwhile
+
+ Xpath 268435456 " X: 268435456
+
+endif
+
+Xcheck 374889517
+
+
+"-------------------------------------------------------------------------------
+" 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: Errors in the /pattern/ argument of a :catch {{{1
+"
+" On an error in the /pattern/ argument of a :catch, the :catch does
+" not match. Any following :catches of the same :try/:endtry don't
+" match either. Finally clauses are executed.
+"-------------------------------------------------------------------------------
+
+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
+
+try
+ try
+ Xpath 1 " X: 1
+ throw "oops"
+ catch /^oops$/
+ Xpath 2 " X: 2
+ catch /\)/ " not checked; exception has already been caught
+ Xpath 4 " X: 0
+ endtry
+ Xpath 8 " X: 8
+catch /.*/
+ Xpath 16 " X: 0
+ Xout v:exception "in" v:throwpoint
+endtry
+
+function! F()
+ try
+ let caught = 0
+ try
+ try
+ Xpath 32 " X: 32
+ throw "ab"
+ catch /abc/ " does not catch
+ Xpath 64 " X: 0
+ catch /\)/ " error; discards exception
+ Xpath 128 " X: 0
+ catch /.*/ " not checked
+ Xpath 256 " X: 0
+ finally
+ Xpath 512 " X: 512
+ endtry
+ Xpath 1024 " X: 0
+ catch /^ab$/ " checked, but original exception is discarded
+ Xpath 2048 " X: 0
+ catch /^Vim(catch):/
+ let caught = 1
+ let v:errmsg = substitute(v:exception, '^Vim(catch):', '', "")
+ finally
+ Xpath 4096 " X: 4096
+ if !caught && !$VIMNOERRTHROW
+ Xpath 8192 " X: 0
+ endif
+ if !MSG('E475', "Invalid argument")
+ Xpath 16384 " X: 0
+ endif
+ if !caught
+ return | " discard error
+ endif
+ endtry
+ catch /.*/
+ Xpath 32768 " X: 0
+ Xout v:exception "in" v:throwpoint
+ endtry
+endfunction
+
+call F()
+Xpath 65536 " X: 65536
+
+delfunction MSG
+delfunction F
+unlet! caught
+
+Xcheck 70187
+
+
+"-------------------------------------------------------------------------------
+" 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
+
+
+"-------------------------------------------------------------------------------
+" Test 69: :throw across :if, :elseif, :while {{{1
+"
+" On an :if, :elseif, or :while command, an exception might be thrown
+" during evaluation of the expression to test. The exception can be
+" caught by the script.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+XloopINIT! 1 2
+
+function! THROW(x)
+ XloopNEXT
+ Xloop 1 " X: 1 + 2 + 4
+ throw a:x
+endfunction
+
+try
+
+ try
+ Xpath 8 " X: 8
+ if 4711 == THROW("if") + 111
+ Xpath 16 " X: 0
+ else
+ Xpath 32 " X: 0
+ endif
+ Xpath 64 " X: 0
+ catch /^if$/
+ Xpath 128 " X: 128
+ catch /.*/
+ Xpath 256 " X: 0
+ Xout "if:" v:exception "in" v:throwpoint
+ endtry
+
+ try
+ Xpath 512 " X: 512
+ if 4711 == 4 + 7 + 1 + 1
+ Xpath 1024 " X: 0
+ elseif 4711 == THROW("elseif") + 222
+ Xpath 2048 " X: 0
+ else
+ Xpath 4096 " X: 0
+ endif
+ Xpath 8192 " X: 0
+ catch /^elseif$/
+ Xpath 16384 " X: 16384
+ catch /.*/
+ Xpath 32768 " X: 0
+ Xout "elseif:" v:exception "in" v:throwpoint
+ endtry
+
+ try
+ Xpath 65536 " X: 65536
+ while 4711 == THROW("while") + 4711
+ Xpath 131072 " X: 0
+ break
+ endwhile
+ Xpath 262144 " X: 0
+ catch /^while$/
+ Xpath 524288 " X: 524288
+ catch /.*/
+ Xpath 1048576 " X: 0
+ Xout "while:" v:exception "in" v:throwpoint
+ endtry
+
+catch /^0$/ " default return value
+ Xpath 2097152 " X: 0
+ Xout v:throwpoint
+catch /.*/
+ Xout v:exception "in" v:throwpoint
+ Xpath 4194304 " X: 0
+endtry
+
+Xpath 8388608 " X: 8388608
+
+delfunction THROW
+
+Xcheck 8995471
+
+
+"-------------------------------------------------------------------------------
+" Test 70: :throw across :return or :throw {{{1
+"
+" On a :return or :throw command, an exception might be thrown during
+" evaluation of the expression to return or throw, respectively. The
+" exception can be caught by the script.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+let taken = ""
+
+function! THROW(x, n)
+ let g:taken = g:taken . "T" . a:n
+ throw a:x
+endfunction
+
+function! F(x, y, n)
+ let g:taken = g:taken . "F" . a:n
+ return a:x + THROW(a:y, a:n)
+endfunction
+
+function! G(x, y, n)
+ let g:taken = g:taken . "G" . a:n
+ throw a:x . THROW(a:y, a:n)
+ return a:x
+endfunction
+
+try
+ try
+ Xpath 1 " X: 1
+ call F(4711, "return", 1)
+ Xpath 2 " X: 0
+ catch /^return$/
+ Xpath 4 " X: 4
+ catch /.*/
+ Xpath 8 " X: 0
+ Xout "return:" v:exception "in" v:throwpoint
+ endtry
+
+ try
+ Xpath 16 " X: 16
+ let var = F(4712, "return-var", 2)
+ Xpath 32 " X: 0
+ catch /^return-var$/
+ Xpath 64 " X: 64
+ catch /.*/
+ Xpath 128 " X: 0
+ Xout "return-var:" v:exception "in" v:throwpoint
+ finally
+ unlet! var
+ endtry
+
+ try
+ Xpath 256 " X: 256
+ throw "except1" . THROW("throw1", 3)
+ Xpath 512 " X: 0
+ catch /^except1/
+ Xpath 1024 " X: 0
+ catch /^throw1$/
+ Xpath 2048 " X: 2048
+ catch /.*/
+ Xpath 4096 " X: 0
+ Xout "throw1:" v:exception "in" v:throwpoint
+ endtry
+
+ try
+ Xpath 8192 " X: 8192
+ call G("except2", "throw2", 4)
+ Xpath 16384 " X: 0
+ catch /^except2/
+ Xpath 32768 " X: 0
+ catch /^throw2$/
+ Xpath 65536 " X: 65536
+ catch /.*/
+ Xpath 131072 " X: 0
+ Xout "throw2:" v:exception "in" v:throwpoint
+ endtry
+
+ try
+ Xpath 262144 " X: 262144
+ let var = G("except3", "throw3", 5)
+ Xpath 524288 " X: 0
+ catch /^except3/
+ Xpath 1048576 " X: 0
+ catch /^throw3$/
+ Xpath 2097152 " X: 2097152
+ catch /.*/
+ Xpath 4194304 " X: 0
+ Xout "throw3:" v:exception "in" v:throwpoint
+ finally
+ unlet! var
+ endtry
+
+ let expected = "F1T1F2T2T3G4T4G5T5"
+ if taken != expected
+ Xpath 8388608 " X: 0
+ Xout "'taken' is" taken "instead of" expected
+ endif
+
+catch /^0$/ " default return value
+ Xpath 16777216 " X: 0
+ Xout v:throwpoint
+catch /.*/
+ Xpath 33554432 " X: 0
+ Xout v:exception "in" v:throwpoint
+endtry
+
+Xpath 67108864 " X: 67108864
+
+unlet taken expected
+delfunction THROW
+delfunction F
+delfunction G
+
+Xcheck 69544277
+
+
+"-------------------------------------------------------------------------------
+" Test 71: :throw across :echo variants and :execute {{{1
+"
+" On an :echo, :echon, :echomsg, :echoerr, or :execute command, an
+" exception might be thrown during evaluation of the arguments to
+" be displayed or executed as a command, respectively. Any following
+" arguments are not evaluated, then. The exception can be caught by
+" the script.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+let taken = ""
+
+function! THROW(x, n)
+ let g:taken = g:taken . "T" . a:n
+ throw a:x
+endfunction
+
+function! F(n)
+ let g:taken = g:taken . "F" . a:n
+ return "F" . a:n
+endfunction
+
+try
+ try
+ Xpath 1 " X: 1
+ echo "echo" . THROW("echo-except", 1) F(1)
+ Xpath 2 " X: 0
+ catch /^echo-except$/
+ Xpath 4 " X: 4
+ catch /.*/
+ Xpath 8 " X: 0
+ Xout "echo:" v:exception "in" v:throwpoint
+ endtry
+
+ try
+ Xpath 16 " X: 16
+ echon "echon" . THROW("echon-except", 2) F(2)
+ Xpath 32 " X: 0
+ catch /^echon-except$/
+ Xpath 64 " X: 64
+ catch /.*/
+ Xpath 128 " X: 0
+ Xout "echon:" v:exception "in" v:throwpoint
+ endtry
+
+ try
+ Xpath 256 " X: 256
+ echomsg "echomsg" . THROW("echomsg-except", 3) F(3)
+ Xpath 512 " X: 0
+ catch /^echomsg-except$/
+ Xpath 1024 " X: 1024
+ catch /.*/
+ Xpath 2048 " X: 0
+ Xout "echomsg:" v:exception "in" v:throwpoint
+ endtry
+
+ try
+ Xpath 4096 " X: 4096
+ echoerr "echoerr" . THROW("echoerr-except", 4) F(4)
+ Xpath 8192 " X: 0
+ catch /^echoerr-except$/
+ Xpath 16384 " X: 16384
+ catch /Vim/
+ Xpath 32768 " X: 0
+ catch /echoerr/
+ Xpath 65536 " X: 0
+ catch /.*/
+ Xpath 131072 " X: 0
+ Xout "echoerr:" v:exception "in" v:throwpoint
+ endtry
+
+ try
+ Xpath 262144 " X: 262144
+ execute "echo 'execute" . THROW("execute-except", 5) F(5) "'"
+ Xpath 524288 " X: 0
+ catch /^execute-except$/
+ Xpath 1048576 " X: 1048576
+ catch /.*/
+ Xpath 2097152 " X: 0
+ Xout "execute:" v:exception "in" v:throwpoint
+ endtry
+
+ let expected = "T1T2T3T4T5"
+ if taken != expected
+ Xpath 4194304 " X: 0
+ Xout "'taken' is" taken "instead of" expected
+ endif
+
+catch /^0$/ " default return value
+ Xpath 8388608 " X: 0
+ Xout v:throwpoint
+catch /.*/
+ Xpath 16777216 " X: 0
+ Xout v:exception "in" v:throwpoint
+endtry
+
+Xpath 33554432 " X: 33554432
+
+unlet taken expected
+delfunction THROW
+delfunction F
+
+Xcheck 34886997
+
+
+"-------------------------------------------------------------------------------
+" Test 72: :throw across :let or :unlet {{{1
+"
+" On a :let command, an exception might be thrown during evaluation
+" of the expression to assign. On an :let or :unlet command, the
+" evaluation of the name of the variable to be assigned or list or
+" deleted, respectively, may throw an exception. Any following
+" arguments are not evaluated, then. The exception can be caught by
+" the script.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+let throwcount = 0
+
+function! THROW(x)
+ let g:throwcount = g:throwcount + 1
+ throw a:x
+endfunction
+
+try
+ try
+ let $VAR = "old_value"
+ Xpath 1 " X: 1
+ let $VAR = "let(" . THROW("var") . ")"
+ Xpath 2 " X: 0
+ catch /^var$/
+ Xpath 4 " X: 4
+ finally
+ if $VAR != "old_value"
+ Xpath 8 " X: 0
+ endif
+ endtry
+
+ try
+ let @a = "old_value"
+ Xpath 16 " X: 16
+ let @a = "let(" . THROW("reg") . ")"
+ Xpath 32 " X: 0
+ catch /^reg$/
+ try
+ Xpath 64 " X: 64
+ let @A = "let(" . THROW("REG") . ")"
+ Xpath 128 " X: 0
+ catch /^REG$/
+ Xpath 256 " X: 256
+ endtry
+ finally
+ if @a != "old_value"
+ Xpath 512 " X: 0
+ endif
+ if @A != "old_value"
+ Xpath 1024 " X: 0
+ endif
+ endtry
+
+ try
+ let saved_gpath = &g:path
+ let saved_lpath = &l:path
+ Xpath 2048 " X: 2048
+ let &path = "let(" . THROW("opt") . ")"
+ Xpath 4096 " X: 0
+ catch /^opt$/
+ try
+ Xpath 8192 " X: 8192
+ let &g:path = "let(" . THROW("gopt") . ")"
+ Xpath 16384 " X: 0
+ catch /^gopt$/
+ try
+ Xpath 32768 " X: 32768
+ let &l:path = "let(" . THROW("lopt") . ")"
+ Xpath 65536 " X: 0
+ catch /^lopt$/
+ Xpath 131072 " X: 131072
+ endtry
+ endtry
+ finally
+ if &g:path != saved_gpath || &l:path != saved_lpath
+ Xpath 262144 " X: 0
+ endif
+ let &g:path = saved_gpath
+ let &l:path = saved_lpath
+ endtry
+
+ unlet! var1 var2 var3
+
+ try
+ Xpath 524288 " X: 524288
+ let var1 = "let(" . THROW("var1") . ")"
+ Xpath 1048576 " X: 0
+ catch /^var1$/
+ Xpath 2097152 " X: 2097152
+ finally
+ if exists("var1")
+ Xpath 4194304 " X: 0
+ endif
+ endtry
+
+ try
+ let var2 = "old_value"
+ Xpath 8388608 " X: 8388608
+ let var2 = "let(" . THROW("var2"). ")"
+ Xpath 16777216 " X: 0
+ catch /^var2$/
+ Xpath 33554432 " X: 33554432
+ finally
+ if var2 != "old_value"
+ Xpath 67108864 " X: 0
+ endif
+ endtry
+
+ try
+ Xpath 134217728 " X: 134217728
+ let var{THROW("var3")} = 4711
+ Xpath 268435456 " X: 0
+ catch /^var3$/
+ Xpath 536870912 " X: 536870912
+ endtry
+
+ let addpath = ""
+
+ function ADDPATH(p)
+ let g:addpath = g:addpath . a:p
+ endfunction
+
+ try
+ call ADDPATH("T1")
+ let var{THROW("var4")} var{ADDPATH("T2")} | call ADDPATH("T3")
+ call ADDPATH("T4")
+ catch /^var4$/
+ call ADDPATH("T5")
+ endtry
+
+ try
+ call ADDPATH("T6")
+ unlet var{THROW("var5")} var{ADDPATH("T7")} | call ADDPATH("T8")
+ call ADDPATH("T9")
+ catch /^var5$/
+ call ADDPATH("T10")
+ endtry
+
+ if addpath != "T1T5T6T10" || throwcount != 11
+ throw "addpath: " . addpath . ", throwcount: " . throwcount
+ endif
+
+ Xpath 1073741824 " X: 1073741824
+
+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! var1 var2 var3 addpath throwcount
+delfunction THROW
+
+Xcheck 1789569365
+
+
+"-------------------------------------------------------------------------------
+" Test 73: :throw across :function, :delfunction {{{1
+"
+" The :function and :delfunction commands may cause an expression
+" specified in braces to be evaluated. During evaluation, an
+" exception might be thrown. The exception can be caught by the
+" script.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+let taken = ""
+
+function! THROW(x, n)
+ let g:taken = g:taken . "T" . a:n
+ throw a:x
+endfunction
+
+function! EXPR(x, n)
+ let g:taken = g:taken . "E" . a:n
+ if a:n % 2 == 0
+ call THROW(a:x, a:n)
+ endif
+ return 2 - a:n % 2
+endfunction
+
+try
+ try
+ " Define function.
+ Xpath 1 " X: 1
+ function! F0()
+ endfunction
+ Xpath 2 " X: 2
+ function! F{EXPR("function-def-ok", 1)}()
+ endfunction
+ Xpath 4 " X: 4
+ function! F{EXPR("function-def", 2)}()
+ endfunction
+ Xpath 8 " X: 0
+ catch /^function-def-ok$/
+ Xpath 16 " X: 0
+ catch /^function-def$/
+ Xpath 32 " X: 32
+ catch /.*/
+ Xpath 64 " X: 0
+ Xout "def:" v:exception "in" v:throwpoint
+ endtry
+
+ try
+ " List function.
+ Xpath 128 " X: 128
+ function F0
+ Xpath 256 " X: 256
+ function F{EXPR("function-lst-ok", 3)}
+ Xpath 512 " X: 512
+ function F{EXPR("function-lst", 4)}
+ Xpath 1024 " X: 0
+ catch /^function-lst-ok$/
+ Xpath 2048 " X: 0
+ catch /^function-lst$/
+ Xpath 4096 " X: 4096
+ catch /.*/
+ Xpath 8192 " X: 0
+ Xout "lst:" v:exception "in" v:throwpoint
+ endtry
+
+ try
+ " Delete function
+ Xpath 16384 " X: 16384
+ delfunction F0
+ Xpath 32768 " X: 32768
+ delfunction F{EXPR("function-del-ok", 5)}
+ Xpath 65536 " X: 65536
+ delfunction F{EXPR("function-del", 6)}
+ Xpath 131072 " X: 0
+ catch /^function-del-ok$/
+ Xpath 262144 " X: 0
+ catch /^function-del$/
+ Xpath 524288 " X: 524288
+ catch /.*/
+ Xpath 1048576 " X: 0
+ Xout "del:" v:exception "in" v:throwpoint
+ endtry
+
+ let expected = "E1E2T2E3E4T4E5E6T6"
+ if taken != expected
+ Xpath 2097152 " X: 0
+ Xout "'taken' is" taken "instead of" expected
+ endif
+
+catch /.*/
+ Xpath 4194304 " X: 0
+ Xout v:exception "in" v:throwpoint
+endtry
+
+Xpath 8388608 " X: 8388608
+
+unlet taken expected
+delfunction THROW
+delfunction EXPR
+
+Xcheck 9032615
+
+
+"-------------------------------------------------------------------------------
+" Test 74: :throw across builtin functions and commands {{{1
+"
+" Some functions like exists(), searchpair() take expression
+" arguments, other functions or commands like substitute() or
+" :substitute cause an expression (specified in the regular
+" expression) to be evaluated. During evaluation an exception
+" might be thrown. The exception can be caught by the script.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+let taken = ""
+
+function! THROW(x, n)
+ let g:taken = g:taken . "T" . a:n
+ throw a:x
+endfunction
+
+function! EXPR(x, n)
+ let g:taken = g:taken . "E" . a:n
+ call THROW(a:x . a:n, a:n)
+ return "EXPR"
+endfunction
+
+function! SKIP(x, n)
+ let g:taken = g:taken . "S" . a:n . "(" . line(".")
+ let theline = getline(".")
+ if theline =~ "skip"
+ let g:taken = g:taken . "s)"
+ return 1
+ elseif theline =~ "throw"
+ let g:taken = g:taken . "t)"
+ call THROW(a:x . a:n, a:n)
+ else
+ let g:taken = g:taken . ")"
+ return 0
+ endif
+endfunction
+
+function! SUBST(x, n)
+ let g:taken = g:taken . "U" . a:n . "(" . line(".")
+ let theline = getline(".")
+ if theline =~ "not" " SUBST() should not be called for this line
+ let g:taken = g:taken . "n)"
+ call THROW(a:x . a:n, a:n)
+ elseif theline =~ "throw"
+ let g:taken = g:taken . "t)"
+ call THROW(a:x . a:n, a:n)
+ else
+ let g:taken = g:taken . ")"
+ return "replaced"
+ endif
+endfunction
+
+try
+ try
+ Xpath 1 " X: 1
+ let result = exists('*{EXPR("exists", 1)}')
+ Xpath 2 " X: 0
+ catch /^exists1$/
+ Xpath 4 " X: 4
+ try
+ let result = exists('{EXPR("exists", 2)}')
+ Xpath 8 " X: 0
+ catch /^exists2$/
+ Xpath 16 " X: 16
+ catch /.*/
+ Xpath 32 " X: 0
+ Xout "exists2:" v:exception "in" v:throwpoint
+ endtry
+ catch /.*/
+ Xpath 64 " X: 0
+ Xout "exists1:" v:exception "in" v:throwpoint
+ endtry
+
+ try
+ let file = tempname()
+ exec "edit" file
+ insert
+begin
+ xx
+middle 3
+ xx
+middle 5 skip
+ xx
+middle 7 throw
+ xx
+end
+.
+ normal! gg
+ Xpath 128 " X: 128
+ let result =
+ \ searchpair("begin", "middle", "end", '', 'SKIP("searchpair", 3)')
+ Xpath 256 " X: 256
+ let result =
+ \ searchpair("begin", "middle", "end", '', 'SKIP("searchpair", 4)')
+ Xpath 512 " X: 0
+ let result =
+ \ searchpair("begin", "middle", "end", '', 'SKIP("searchpair", 5)')
+ Xpath 1024 " X: 0
+ catch /^searchpair[35]$/
+ Xpath 2048 " X: 0
+ catch /^searchpair4$/
+ Xpath 4096 " X: 4096
+ catch /.*/
+ Xpath 8192 " X: 0
+ Xout "searchpair:" v:exception "in" v:throwpoint
+ finally
+ bwipeout!
+ call delete(file)
+ endtry
+
+ try
+ let file = tempname()
+ exec "edit" file
+ insert
+subst 1
+subst 2
+not
+subst 4
+subst throw
+subst 6
+.
+ normal! gg
+ Xpath 16384 " X: 16384
+ 1,2substitute/subst/\=SUBST("substitute", 6)/
+ try
+ Xpath 32768 " X: 32768
+ try
+ let v:errmsg = ""
+ 3substitute/subst/\=SUBST("substitute", 7)/
+ finally
+ if v:errmsg != ""
+ " If exceptions are not thrown on errors, fake the error
+ " exception in order to get the same execution path.
+ throw "faked Vim(substitute)"
+ endif
+ endtry
+ catch /Vim(substitute)/ " Pattern not found ('e' flag missing)
+ Xpath 65536 " X: 65536
+ 3substitute/subst/\=SUBST("substitute", 8)/e
+ Xpath 131072 " X: 131072
+ endtry
+ Xpath 262144 " X: 262144
+ 4,6substitute/subst/\=SUBST("substitute", 9)/
+ Xpath 524288 " X: 0
+ catch /^substitute[678]/
+ Xpath 1048576 " X: 0
+ catch /^substitute9/
+ Xpath 2097152 " X: 2097152
+ finally
+ bwipeout!
+ call delete(file)
+ endtry
+
+ try
+ Xpath 4194304 " X: 4194304
+ let var = substitute("sub", "sub", '\=THROW("substitute()y", 10)', '')
+ Xpath 8388608 " X: 0
+ catch /substitute()y/
+ Xpath 16777216 " X: 16777216
+ catch /.*/
+ Xpath 33554432 " X: 0
+ Xout "substitute()y:" v:exception "in" v:throwpoint
+ endtry
+
+ try
+ Xpath 67108864 " X: 67108864
+ let var = substitute("not", "sub", '\=THROW("substitute()n", 11)', '')
+ Xpath 134217728 " X: 134217728
+ catch /substitute()n/
+ Xpath 268435456 " X: 0
+ catch /.*/
+ Xpath 536870912 " X: 0
+ Xout "substitute()n:" v:exception "in" v:throwpoint
+ endtry
+
+ let expected = "E1T1E2T2S3(3)S4(5s)S4(7t)T4U6(1)U6(2)U9(4)U9(5t)T9T10"
+ if taken != expected
+ Xpath 1073741824 " X: 0
+ Xout "'taken' is" taken "instead of" expected
+ endif
+
+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 result var taken expected
+delfunction THROW
+delfunction EXPR
+delfunction SKIP
+delfunction SUBST
+
+Xcheck 224907669
+
+
+"-------------------------------------------------------------------------------
+" Test 75: Errors in builtin functions. {{{1
+"
+" On an error in a builtin function called inside a :try/:endtry
+" region, the evaluation of the expression calling that function and
+" the command containing that expression are abandoned. The error can
+" be caught as an exception.
+"
+" A simple :call of the builtin function is a trivial case. If the
+" builtin function is called in the argument list of another function,
+" no further arguments are evaluated, and the other function is not
+" executed. If the builtin function is called from the argument of
+" a :return command, the :return command is not executed. If the
+" builtin function is called from the argument of a :throw command,
+" the :throw command is not executed. The evaluation of the
+" expression calling the builtin function is abandoned.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+function! F1(arg1)
+ Xpath 1 " X: 0
+endfunction
+
+function! F2(arg1, arg2)
+ Xpath 2 " X: 0
+endfunction
+
+function! G()
+ Xpath 4 " X: 0
+endfunction
+
+function! H()
+ Xpath 8 " X: 0
+endfunction
+
+function! R()
+ while 1
+ try
+ let caught = 0
+ let v:errmsg = ""
+ Xpath 16 " X: 16
+ return append(1, "s")
+ catch /E21/
+ let caught = 1
+ catch /.*/
+ Xpath 32 " X: 0
+ finally
+ Xpath 64 " X: 64
+ if caught || $VIMNOERRTHROW && v:errmsg =~ 'E21'
+ Xpath 128 " X: 128
+ endif
+ break " discard error for $VIMNOERRTHROW
+ endtry
+ endwhile
+ Xpath 256 " X: 256
+endfunction
+
+try
+ set noma " let append() fail with "E21"
+
+ while 1
+ try
+ let caught = 0
+ let v:errmsg = ""
+ Xpath 512 " X: 512
+ call append(1, "s")
+ catch /E21/
+ let caught = 1
+ catch /.*/
+ Xpath 1024 " X: 0
+ finally
+ Xpath 2048 " X: 2048
+ if caught || $VIMNOERRTHROW && v:errmsg =~ 'E21'
+ Xpath 4096 " X: 4096
+ endif
+ break " discard error for $VIMNOERRTHROW
+ endtry
+ endwhile
+
+ while 1
+ try
+ let caught = 0
+ let v:errmsg = ""
+ Xpath 8192 " X: 8192
+ call F1('x' . append(1, "s"))
+ catch /E21/
+ let caught = 1
+ catch /.*/
+ Xpath 16384 " X: 0
+ finally
+ Xpath 32768 " X: 32768
+ if caught || $VIMNOERRTHROW && v:errmsg =~ 'E21'
+ Xpath 65536 " X: 65536
+ endif
+ break " discard error for $VIMNOERRTHROW
+ endtry
+ endwhile
+
+ while 1
+ try
+ let caught = 0
+ let v:errmsg = ""
+ Xpath 131072 " X: 131072
+ call F2('x' . append(1, "s"), G())
+ catch /E21/
+ let caught = 1
+ catch /.*/
+ Xpath 262144 " X: 0
+ finally
+ Xpath 524288 " X: 524288
+ if caught || $VIMNOERRTHROW && v:errmsg =~ 'E21'
+ Xpath 1048576 " X: 1048576
+ endif
+ break " discard error for $VIMNOERRTHROW
+ endtry
+ endwhile
+
+ call R()
+
+ while 1
+ try
+ let caught = 0
+ let v:errmsg = ""
+ Xpath 2097152 " X: 2097152
+ throw "T" . append(1, "s")
+ catch /E21/
+ let caught = 1
+ catch /^T.*/
+ Xpath 4194304 " X: 0
+ catch /.*/
+ Xpath 8388608 " X: 0
+ finally
+ Xpath 16777216 " X: 16777216
+ if caught || $VIMNOERRTHROW && v:errmsg =~ 'E21'
+ Xpath 33554432 " X: 33554432
+ endif
+ break " discard error for $VIMNOERRTHROW
+ endtry
+ endwhile
+
+ while 1
+ try
+ let caught = 0
+ let v:errmsg = ""
+ Xpath 67108864 " X: 67108864
+ let x = "a"
+ let x = x . "b" . append(1, "s") . H()
+ catch /E21/
+ let caught = 1
+ catch /.*/
+ Xpath 134217728 " X: 0
+ finally
+ Xpath 268435456 " X: 268435456
+ if caught || $VIMNOERRTHROW && v:errmsg =~ 'E21'
+ Xpath 536870912 " X: 536870912
+ endif
+ if x == "a"
+ Xpath 1073741824 " X: 1073741824
+ endif
+ break " discard error for $VIMNOERRTHROW
+ 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
+finally
+ set ma&
+endtry
+
+unlet! caught x
+delfunction F1
+delfunction F2
+delfunction G
+delfunction H
+delfunction R
+
+Xcheck 2000403408
+
+
+"-------------------------------------------------------------------------------
+" 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 using (expr) ? funcref : funcref {{{1
+"
+" Vim needs to correctly parse the funcref and even when it does
+" not execute the funcref, it needs to consume the trailing ()
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+func Add2(x1, x2)
+ return a:x1 + a:x2
+endfu
+
+func GetStr()
+ return "abcdefghijklmnopqrstuvwxyp"
+endfu
+
+echo function('Add2')(2,3)
+
+Xout 1 ? function('Add2')(1,2) : function('Add2')(2,3)
+Xout 0 ? function('Add2')(1,2) : function('Add2')(2,3)
+" Make sure, GetStr() still works.
+Xout GetStr()[0:10]
+
+
+delfunction GetStr
+delfunction Add2
+Xout "Successfully executed funcref Add2"
+
+Xcheck 0
+
+"-------------------------------------------------------------------------------
+" 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
+" vim: fdt=substitute(substitute(foldtext(),\ '\\%(^+--\\)\\@<=\\(\\s*\\)\\(.\\{-}\\)\:\ \\%(\"\ \\)\\=\\(Test\ \\d*\\)\:\\s*',\ '\\3\ (\\2)\:\ \\1',\ \"\"),\ '\\(Test\\s*\\)\\(\\d\\)\\D\\@=',\ '\\1\ \\2',\ "")
+"-------------------------------------------------------------------------------
diff --git a/src/testdir/test52.in b/src/testdir/test52.in
new file mode 100644
index 0000000..206b65a
--- /dev/null
+++ b/src/testdir/test52.in
@@ -0,0 +1,65 @@
+Tests for reading and writing files with conversion for Win32.
+
+STARTTEST
+:so mbyte.vim
+:" make this a dummy test for non-Win32 systems
+:if !has("win32") | e! test.ok | wq! test.out | endif
+:"
+:" write tests:
+:" combine three values for 'encoding' with three values for 'fileencoding'
+:" also write files for read tests
+/^1
+:set encoding=utf-8
+:.w! ++enc=utf-8 test.out
+:.w ++enc=cp1251 >>test.out
+:.w ++enc=cp866 >>test.out
+:.w! ++enc=utf-8 Xutf8
+/^2
+:set encoding=cp1251
+:.w ++enc=utf-8 >>test.out
+:.w ++enc=cp1251 >>test.out
+:.w ++enc=cp866 >>test.out
+:.w! ++enc=cp1251 Xcp1251
+/^3
+:set encoding=cp866
+:.w ++enc=utf-8 >>test.out
+:.w ++enc=cp1251 >>test.out
+:.w ++enc=cp866 >>test.out
+:.w! ++enc=cp866 Xcp866
+:"
+:" read three 'fileencoding's with utf-8 'encoding'
+:set encoding=utf-8 fencs=utf-8,cp1251
+:e Xutf8
+:.w ++enc=utf-8 >>test.out
+:e Xcp1251
+:.w ++enc=utf-8 >>test.out
+:set fencs=utf-8,cp866
+:e Xcp866
+:.w ++enc=utf-8 >>test.out
+:"
+:" read three 'fileencoding's with cp1251 'encoding'
+:set encoding=utf-8 fencs=utf-8,cp1251
+:e Xutf8
+:.w ++enc=cp1251 >>test.out
+:e Xcp1251
+:.w ++enc=cp1251 >>test.out
+:set fencs=utf-8,cp866
+:e Xcp866
+:.w ++enc=cp1251 >>test.out
+:"
+:" read three 'fileencoding's with cp866 'encoding'
+:set encoding=cp866 fencs=utf-8,cp1251
+:e Xutf8
+:.w ++enc=cp866 >>test.out
+:e Xcp1251
+:.w ++enc=cp866 >>test.out
+:set fencs=utf-8,cp866
+:e Xcp866
+:.w ++enc=cp866 >>test.out
+:"
+:qa!
+ENDTEST
+
+1 utf-8 text: Ð”Ð»Ñ Vim version 6.2. ПоÑледнее изменение: 1970 Jan 01
+2 cp1251 text: Äëÿ Vim version 6.2. Ïîñëåäíåå èçìåíåíèå: 1970 Jan 01
+3 cp866 text: „«ï Vim version 6.2. ®á«¥¤­¥¥ ¨§¬¥­¥­¨¥: 1970 Jan 01
diff --git a/src/testdir/test52.ok b/src/testdir/test52.ok
new file mode 100644
index 0000000..90b5165
--- /dev/null
+++ b/src/testdir/test52.ok
@@ -0,0 +1,18 @@
+1 utf-8 text: Ð”Ð»Ñ Vim version 6.2. ПоÑледнее изменение: 1970 Jan 01
+1 utf-8 text: Äëÿ Vim version 6.2. Ïîñëåäíåå èçìåíåíèå: 1970 Jan 01
+1 utf-8 text: „«ï Vim version 6.2. ®á«¥¤­¥¥ ¨§¬¥­¥­¨¥: 1970 Jan 01
+2 cp1251 text: Ð”Ð»Ñ Vim version 6.2. ПоÑледнее изменение: 1970 Jan 01
+2 cp1251 text: Äëÿ Vim version 6.2. Ïîñëåäíåå èçìåíåíèå: 1970 Jan 01
+2 cp1251 text: „«ï Vim version 6.2. ®á«¥¤­¥¥ ¨§¬¥­¥­¨¥: 1970 Jan 01
+3 cp866 text: Ð”Ð»Ñ Vim version 6.2. ПоÑледнее изменение: 1970 Jan 01
+3 cp866 text: Äëÿ Vim version 6.2. Ïîñëåäíåå èçìåíåíèå: 1970 Jan 01
+3 cp866 text: „«ï Vim version 6.2. ®á«¥¤­¥¥ ¨§¬¥­¥­¨¥: 1970 Jan 01
+1 utf-8 text: Ð”Ð»Ñ Vim version 6.2. ПоÑледнее изменение: 1970 Jan 01
+2 cp1251 text: Ð”Ð»Ñ Vim version 6.2. ПоÑледнее изменение: 1970 Jan 01
+3 cp866 text: Ð”Ð»Ñ Vim version 6.2. ПоÑледнее изменение: 1970 Jan 01
+1 utf-8 text: Äëÿ Vim version 6.2. Ïîñëåäíåå èçìåíåíèå: 1970 Jan 01
+2 cp1251 text: Äëÿ Vim version 6.2. Ïîñëåäíåå èçìåíåíèå: 1970 Jan 01
+3 cp866 text: Äëÿ Vim version 6.2. Ïîñëåäíåå èçìåíåíèå: 1970 Jan 01
+1 utf-8 text: „«ï Vim version 6.2. ®á«¥¤­¥¥ ¨§¬¥­¥­¨¥: 1970 Jan 01
+2 cp1251 text: „«ï Vim version 6.2. ®á«¥¤­¥¥ ¨§¬¥­¥­¨¥: 1970 Jan 01
+3 cp866 text: „«ï Vim version 6.2. ®á«¥¤­¥¥ ¨§¬¥­¥­¨¥: 1970 Jan 01
diff --git a/src/testdir/test59.in b/src/testdir/test59.in
new file mode 100644
index 0000000..dcdb62b
--- /dev/null
+++ b/src/testdir/test59.in
@@ -0,0 +1,626 @@
+Tests for spell checking with 'encoding' set to "utf-8". vim: set ft=vim :
+
+STARTTEST
+:so small.vim
+:so mbyte.vim
+:"
+:" Don't want to depend on the locale from the environment. The .aff and .dic
+:" text is in latin1, the test text is utf-8.
+:set enc=latin1
+:e!
+:set enc=utf-8
+:set fenc=
+:"
+:" Function to test .aff/.dic with list of good and bad words.
+:func TestOne(aff, dic)
+ set spellfile=
+ $put =''
+ $put ='test '. a:aff . '-' . a:dic
+ " Generate a .spl file from a .dic and .aff file.
+ exe '1;/^' . a:aff . 'affstart/+1,/^' . a:aff . 'affend/-1w! Xtest.aff'
+ exe '1;/^' . a:dic . 'dicstart/+1,/^' . a:dic . 'dicend/-1w! Xtest.dic'
+ mkspell! Xtest Xtest
+ " use that spell file
+ set spl=Xtest.utf-8.spl spell
+ " list all valid words
+ spelldump
+ %yank
+ quit
+ $put
+ $put ='-------'
+ " find all bad words and suggestions for them
+ exe '1;/^' . a:aff . 'good:'
+ normal 0f:]s
+ let prevbad = ''
+ while 1
+ let [bad, a] = spellbadword()
+ if bad == '' || bad == prevbad || bad == 'badend'
+ break
+ endif
+ let prevbad = bad
+ let lst = spellsuggest(bad, 3)
+ normal mm
+ $put =bad
+ $put =string(lst)
+ normal `m]s
+ endwhile
+endfunc
+:"
+:call TestOne('1', '1')
+:$put =soundfold('goobledygoook')
+:$put =soundfold('kóopërÿnôven')
+:$put =soundfold('oeverloos gezwets edale')
+:"
+:"
+:" and now with SAL instead of SOFO items; test automatic reloading
+gg:/^affstart_sal/+1,/^affend_sal/-1w! Xtest.aff
+:mkspell! Xtest Xtest
+:$put =soundfold('goobledygoook')
+:$put =soundfold('kóopërÿnôven')
+:$put =soundfold('oeverloos gezwets edale')
+:"
+:" also use an addition file
+gg:/^addstart/+1,/^addend/-1w! Xtest.utf-8.add
+:mkspell! Xtest.utf-8.add.spl Xtest.utf-8.add
+:set spellfile=Xtest.utf-8.add
+/^test2:
+]s:let [str, a] = spellbadword()
+:$put =str
+:set spl=Xtest_us.utf-8.spl
+/^test2:
+]smm:let [str, a] = spellbadword()
+:$put =str
+`m]s:let [str, a] = spellbadword()
+:$put =str
+:set spl=Xtest_gb.utf-8.spl
+/^test2:
+]smm:let [str, a] = spellbadword()
+:$put =str
+`m]s:let [str, a] = spellbadword()
+:$put =str
+:set spl=Xtest_nz.utf-8.spl
+/^test2:
+]smm:let [str, a] = spellbadword()
+:$put =str
+`m]s:let [str, a] = spellbadword()
+:$put =str
+:set spl=Xtest_ca.utf-8.spl
+/^test2:
+]smm:let [str, a] = spellbadword()
+:$put =str
+`m]s:let [str, a] = spellbadword()
+:$put =str
+:unlet str a
+:"
+:" Postponed prefixes
+:call TestOne('2', '1')
+:"
+:" Compound words
+:call TestOne('3', '3')
+:call TestOne('4', '4')
+:call TestOne('5', '5')
+:call TestOne('6', '6')
+:call TestOne('7', '7')
+:"
+:" clean up for valgrind
+:delfunc TestOne
+:set spl= enc=latin1
+:"
+gg:/^test output:/,$wq! test.out
+ENDTEST
+
+1affstart
+SET ISO8859-1
+TRY esianrtolcdugmphbyfvkwjkqxz-ëéèêïîäàâöüû'ESIANRTOLCDUGMPHBYFVKWJKQXZ
+
+FOL àáâãäåæçèéêëìíîïðñòóôõöøùúûüýþßÿ
+LOW àáâãäåæçèéêëìíîïðñòóôõöøùúûüýþßÿ
+UPP ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßÿ
+
+SOFOFROM abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþßÿÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ¿
+SOFOTO ebctefghejklnnepkrstevvkesebctefghejklnnepkrstevvkeseeeeeeeceeeeeeeedneeeeeeeeeeepseeeeeeeeceeeeeeeedneeeeeeeeeeep?
+
+MIDWORD '-
+
+KEP =
+RAR ?
+BAD !
+
+#NOSPLITSUGS
+
+PFX I N 1
+PFX I 0 in .
+
+PFX O Y 1
+PFX O 0 out .
+
+SFX S Y 2
+SFX S 0 s [^s]
+SFX S 0 es s
+
+SFX N N 3
+SFX N 0 en [^n]
+SFX N 0 nen n
+SFX N 0 n .
+
+REP 3
+REP g ch
+REP ch g
+REP svp s.v.p.
+
+MAP 9
+MAP aàáâãäå
+MAP eèéêë
+MAP iìíîï
+MAP oòóôõö
+MAP uùúûü
+MAP nñ
+MAP cç
+MAP yÿý
+MAP sß
+1affend
+
+affstart_sal
+SET ISO8859-1
+TRY esianrtolcdugmphbyfvkwjkqxz-ëéèêïîäàâöüû'ESIANRTOLCDUGMPHBYFVKWJKQXZ
+
+FOL àáâãäåæçèéêëìíîïðñòóôõöøùúûüýþßÿ
+LOW àáâãäåæçèéêëìíîïðñòóôõöøùúûüýþßÿ
+UPP ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßÿ
+
+MIDWORD '-
+
+KEP =
+RAR ?
+BAD !
+
+#NOSPLITSUGS
+
+PFX I N 1
+PFX I 0 in .
+
+PFX O Y 1
+PFX O 0 out .
+
+SFX S Y 2
+SFX S 0 s [^s]
+SFX S 0 es s
+
+SFX N N 3
+SFX N 0 en [^n]
+SFX N 0 nen n
+SFX N 0 n .
+
+REP 3
+REP g ch
+REP ch g
+REP svp s.v.p.
+
+MAP 9
+MAP aàáâãäå
+MAP eèéêë
+MAP iìíîï
+MAP oòóôõö
+MAP uùúûü
+MAP nñ
+MAP cç
+MAP yÿý
+MAP sß
+
+SAL AH(AEIOUY)-^ *H
+SAL AR(AEIOUY)-^ *R
+SAL A(HR)^ *
+SAL A^ *
+SAL AH(AEIOUY)- H
+SAL AR(AEIOUY)- R
+SAL A(HR) _
+SAL À^ *
+SAL Å^ *
+SAL BB- _
+SAL B B
+SAL CQ- _
+SAL CIA X
+SAL CH X
+SAL C(EIY)- S
+SAL CK K
+SAL COUGH^ KF
+SAL CC< C
+SAL C K
+SAL DG(EIY) K
+SAL DD- _
+SAL D T
+SAL É< E
+SAL EH(AEIOUY)-^ *H
+SAL ER(AEIOUY)-^ *R
+SAL E(HR)^ *
+SAL ENOUGH^$ *NF
+SAL E^ *
+SAL EH(AEIOUY)- H
+SAL ER(AEIOUY)- R
+SAL E(HR) _
+SAL FF- _
+SAL F F
+SAL GN^ N
+SAL GN$ N
+SAL GNS$ NS
+SAL GNED$ N
+SAL GH(AEIOUY)- K
+SAL GH _
+SAL GG9 K
+SAL G K
+SAL H H
+SAL IH(AEIOUY)-^ *H
+SAL IR(AEIOUY)-^ *R
+SAL I(HR)^ *
+SAL I^ *
+SAL ING6 N
+SAL IH(AEIOUY)- H
+SAL IR(AEIOUY)- R
+SAL I(HR) _
+SAL J K
+SAL KN^ N
+SAL KK- _
+SAL K K
+SAL LAUGH^ LF
+SAL LL- _
+SAL L L
+SAL MB$ M
+SAL MM M
+SAL M M
+SAL NN- _
+SAL N N
+SAL OH(AEIOUY)-^ *H
+SAL OR(AEIOUY)-^ *R
+SAL O(HR)^ *
+SAL O^ *
+SAL OH(AEIOUY)- H
+SAL OR(AEIOUY)- R
+SAL O(HR) _
+SAL PH F
+SAL PN^ N
+SAL PP- _
+SAL P P
+SAL Q K
+SAL RH^ R
+SAL ROUGH^ RF
+SAL RR- _
+SAL R R
+SAL SCH(EOU)- SK
+SAL SC(IEY)- S
+SAL SH X
+SAL SI(AO)- X
+SAL SS- _
+SAL S S
+SAL TI(AO)- X
+SAL TH @
+SAL TCH-- _
+SAL TOUGH^ TF
+SAL TT- _
+SAL T T
+SAL UH(AEIOUY)-^ *H
+SAL UR(AEIOUY)-^ *R
+SAL U(HR)^ *
+SAL U^ *
+SAL UH(AEIOUY)- H
+SAL UR(AEIOUY)- R
+SAL U(HR) _
+SAL V^ W
+SAL V F
+SAL WR^ R
+SAL WH^ W
+SAL W(AEIOU)- W
+SAL X^ S
+SAL X KS
+SAL Y(AEIOU)- Y
+SAL ZZ- _
+SAL Z S
+affend_sal
+
+2affstart
+SET ISO8859-1
+
+FOL àáâãäåæçèéêëìíîïðñòóôõöøùúûüýþßÿ
+LOW àáâãäåæçèéêëìíîïðñòóôõöøùúûüýþßÿ
+UPP ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßÿ
+
+PFXPOSTPONE
+
+MIDWORD '-
+
+KEP =
+RAR ?
+BAD !
+
+#NOSPLITSUGS
+
+PFX I N 1
+PFX I 0 in .
+
+PFX O Y 1
+PFX O 0 out [a-z]
+
+SFX S Y 2
+SFX S 0 s [^s]
+SFX S 0 es s
+
+SFX N N 3
+SFX N 0 en [^n]
+SFX N 0 nen n
+SFX N 0 n .
+
+REP 3
+REP g ch
+REP ch g
+REP svp s.v.p.
+
+MAP 9
+MAP aàáâãäå
+MAP eèéêë
+MAP iìíîï
+MAP oòóôõö
+MAP uùúûü
+MAP nñ
+MAP cç
+MAP yÿý
+MAP sß
+2affend
+
+1dicstart
+123456
+test/NO
+# comment
+wrong
+Comment
+OK
+uk
+put/ISO
+the end
+deol
+déôr
+1dicend
+
+addstart
+/regions=usgbnz
+elequint/2
+elekwint/3
+addend
+
+1good: wrong OK puts. Test the end
+bad: inputs comment ok Ok. test déôl end the
+badend
+
+2good: puts
+bad: inputs comment ok Ok end the. test déôl
+badend
+
+Test rules for compounding.
+
+3affstart
+SET ISO8859-1
+
+COMPOUNDMIN 3
+COMPOUNDRULE m*
+NEEDCOMPOUND x
+3affend
+
+3dicstart
+1234
+foo/m
+bar/mx
+mï/m
+la/mx
+3dicend
+
+3good: foo mï foobar foofoobar barfoo barbarfoo
+bad: bar la foomï barmï mïfoo mïbar mïmï lala mïla lamï foola labar
+badend
+
+
+Tests for compounding.
+
+4affstart
+SET ISO8859-1
+
+FOL àáâãäåæçèéêëìíîïðñòóôõöøùúûüýþßÿ
+LOW àáâãäåæçèéêëìíîïðñòóôõöøùúûüýþßÿ
+UPP ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßÿ
+
+COMPOUNDRULE m+
+COMPOUNDRULE sm*e
+COMPOUNDRULE sm+
+COMPOUNDMIN 3
+COMPOUNDWORDMAX 3
+COMPOUNDFORBIDFLAG t
+
+COMPOUNDSYLMAX 5
+SYLLABLE aáeéiíoóöõuúüûy/aa/au/ea/ee/ei/ie/oa/oe/oo/ou/uu/ui
+
+MAP 9
+MAP aàáâãäå
+MAP eèéêë
+MAP iìíîï
+MAP oòóôõö
+MAP uùúûü
+MAP nñ
+MAP cç
+MAP yÿý
+MAP sß
+
+NEEDAFFIX x
+
+PFXPOSTPONE
+
+MIDWORD '-
+
+SFX q N 1
+SFX q 0 -ok .
+
+SFX a Y 2
+SFX a 0 s .
+SFX a 0 ize/t .
+
+PFX p N 1
+PFX p 0 pre .
+
+PFX P N 1
+PFX P 0 nou .
+4affend
+
+4dicstart
+1234
+word/mP
+util/am
+pro/xq
+tomato/m
+bork/mp
+start/s
+end/e
+4dicend
+
+4good: word util bork prebork start end wordutil wordutils pro-ok
+ bork borkbork borkborkbork borkborkborkbork borkborkborkborkbork
+ tomato tomatotomato startend startword startwordword startwordend
+ startwordwordend startwordwordwordend prebork preborkbork
+ preborkborkbork
+ nouword
+bad: wordutilize pro borkborkborkborkborkbork tomatotomatotomato
+ endstart endend startstart wordend wordstart
+ preborkprebork preborkpreborkbork
+ startwordwordwordwordend borkpreborkpreborkbork
+ utilsbork startnouword
+badend
+
+test2:
+elequint test elekwint test elekwent asdf
+
+Test affix flags with two characters
+
+5affstart
+SET ISO8859-1
+
+FLAG long
+
+NEEDAFFIX !!
+
+COMPOUNDRULE ssmm*ee
+
+NEEDCOMPOUND xx
+COMPOUNDPERMITFLAG pp
+
+SFX 13 Y 1
+SFX 13 0 bork .
+
+SFX a1 Y 1
+SFX a1 0 a1 .
+
+SFX aé Y 1
+SFX aé 0 aé .
+
+PFX zz Y 1
+PFX zz 0 pre/pp .
+
+PFX yy Y 1
+PFX yy 0 nou .
+5affend
+
+5dicstart
+1234
+foo/a1aé!!
+bar/zz13ee
+start/ss
+end/eeyy
+middle/mmxx
+5dicend
+
+5good: fooa1 fooaé bar prebar barbork prebarbork startprebar
+ start end startend startmiddleend nouend
+bad: foo fooa2 prabar probarbirk middle startmiddle middleend endstart
+ startprobar startnouend
+badend
+
+6affstart
+SET ISO8859-1
+
+FLAG caplong
+
+NEEDAFFIX A!
+
+COMPOUNDRULE sMm*Ee
+
+NEEDCOMPOUND Xx
+
+COMPOUNDPERMITFLAG p
+
+SFX N3 Y 1
+SFX N3 0 bork .
+
+SFX A1 Y 1
+SFX A1 0 a1 .
+
+SFX Aé Y 1
+SFX Aé 0 aé .
+
+PFX Zz Y 1
+PFX Zz 0 pre/p .
+6affend
+
+6dicstart
+1234
+mee/A1AéA!
+bar/ZzN3Ee
+lead/s
+end/Ee
+middle/MmXx
+6dicend
+
+6good: meea1 meeaé bar prebar barbork prebarbork leadprebar
+ lead end leadend leadmiddleend
+bad: mee meea2 prabar probarbirk middle leadmiddle middleend endlead
+ leadprobar
+badend
+
+7affstart
+SET ISO8859-1
+
+FOL àáâãäåæçèéêëìíîïðñòóôõöøùúûüýþßÿ
+LOW àáâãäåæçèéêëìíîïðñòóôõöøùúûüýþßÿ
+UPP ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßÿ
+
+FLAG num
+
+NEEDAFFIX 9999
+
+COMPOUNDRULE 2,77*123
+
+NEEDCOMPOUND 1
+COMPOUNDPERMITFLAG 432
+
+SFX 61003 Y 1
+SFX 61003 0 meat .
+
+SFX 391 Y 1
+SFX 391 0 a1 .
+
+SFX 111 Y 1
+SFX 111 0 aé .
+
+PFX 17 Y 1
+PFX 17 0 pre/432 .
+7affend
+
+7dicstart
+1234
+mee/391,111,9999
+bar/17,61003,123
+lead/2
+tail/123
+middle/77,1
+7dicend
+
+7good: meea1 meeaé bar prebar barmeat prebarmeat leadprebar
+ lead tail leadtail leadmiddletail
+bad: mee meea2 prabar probarmaat middle leadmiddle middletail taillead
+ leadprobar
+badend
+
+test output:
diff --git a/src/testdir/test59.ok b/src/testdir/test59.ok
new file mode 100644
index 0000000..931cdd9
--- /dev/null
+++ b/src/testdir/test59.ok
@@ -0,0 +1,270 @@
+test output:
+
+test 1-1
+# file: Xtest.utf-8.spl
+Comment
+deol
+déôr
+input
+OK
+output
+outputs
+outtest
+put
+puts
+test
+testen
+testn
+the end
+uk
+wrong
+-------
+bad
+['put', 'uk', 'OK']
+inputs
+['input', 'puts', 'outputs']
+comment
+['Comment', 'outtest', 'the end']
+ok
+['OK', 'uk', 'put']
+Ok
+['OK', 'Uk', 'Put']
+test
+['Test', 'testn', 'testen']
+déôl
+['deol', 'déôr', 'test']
+end
+['put', 'uk', 'test']
+the
+['put', 'uk', 'test']
+gebletegek
+kepereneven
+everles gesvets etele
+kbltykk
+kprnfn
+*fls kswts tl
+elekwent
+elequint
+elekwint
+elekwint
+elekwent
+elequint
+elekwent
+elequint
+elekwint
+
+test 2-1
+# file: Xtest.utf-8.spl
+Comment
+deol
+déôr
+OK
+put
+input
+output
+puts
+outputs
+test
+outtest
+testen
+testn
+the end
+uk
+wrong
+-------
+bad
+['put', 'uk', 'OK']
+inputs
+['input', 'puts', 'outputs']
+comment
+['Comment']
+ok
+['OK', 'uk', 'put']
+Ok
+['OK', 'Uk', 'Put']
+end
+['put', 'uk', 'deol']
+the
+['put', 'uk', 'test']
+test
+['Test', 'testn', 'testen']
+déôl
+['deol', 'déôr', 'test']
+
+test 3-3
+# file: Xtest.utf-8.spl
+foo
+mï
+-------
+bad
+['foo', 'mï']
+bar
+['barfoo', 'foobar', 'foo']
+la
+['mï', 'foo']
+foomï
+['foo mï', 'foo', 'foofoo']
+barmï
+['barfoo', 'mï', 'barbar']
+mïfoo
+['mï foo', 'foo', 'foofoo']
+mïbar
+['foobar', 'barbar', 'mï']
+mïmï
+['mï mï', 'mï']
+lala
+[]
+mïla
+['mï', 'mï mï']
+lamï
+['mï', 'mï mï']
+foola
+['foo', 'foobar', 'foofoo']
+labar
+['barbar', 'foobar']
+
+test 4-4
+# file: Xtest.utf-8.spl
+bork
+prebork
+end
+pro-ok
+start
+tomato
+util
+utilize
+utils
+word
+nouword
+-------
+bad
+['end', 'bork', 'word']
+wordutilize
+['word utilize', 'wordutils', 'wordutil']
+pro
+['bork', 'word', 'end']
+borkborkborkborkborkbork
+['bork borkborkborkborkbork', 'borkbork borkborkborkbork', 'borkborkbork borkborkbork']
+tomatotomatotomato
+['tomato tomatotomato', 'tomatotomato tomato', 'tomato tomato tomato']
+endstart
+['end start', 'start']
+endend
+['end end', 'end']
+startstart
+['start start']
+wordend
+['word end', 'word', 'wordword']
+wordstart
+['word start', 'bork start']
+preborkprebork
+['prebork prebork', 'preborkbork', 'preborkborkbork']
+preborkpreborkbork
+['prebork preborkbork', 'preborkborkbork', 'preborkborkborkbork']
+startwordwordwordwordend
+['startwordwordwordword end', 'startwordwordwordword', 'start wordwordwordword end']
+borkpreborkpreborkbork
+['bork preborkpreborkbork', 'bork prebork preborkbork', 'bork preborkprebork bork']
+utilsbork
+['utilbork', 'utils bork', 'util bork']
+startnouword
+['start nouword', 'startword', 'startborkword']
+
+test 5-5
+# file: Xtest.utf-8.spl
+bar
+barbork
+end
+fooa1
+fooaé
+nouend
+prebar
+prebarbork
+start
+-------
+bad
+['bar', 'end', 'fooa1']
+foo
+['fooa1', 'fooaé', 'bar']
+fooa2
+['fooa1', 'fooaé', 'bar']
+prabar
+['prebar', 'bar', 'bar bar']
+probarbirk
+['prebarbork']
+middle
+[]
+startmiddle
+['startmiddleend', 'startmiddlebar']
+middleend
+[]
+endstart
+['end start', 'start']
+startprobar
+['startprebar', 'start prebar', 'startbar']
+startnouend
+['start nouend', 'startend']
+
+test 6-6
+# file: Xtest.utf-8.spl
+bar
+barbork
+end
+lead
+meea1
+meeaé
+prebar
+prebarbork
+-------
+bad
+['bar', 'end', 'lead']
+mee
+['meea1', 'meeaé', 'bar']
+meea2
+['meea1', 'meeaé', 'lead']
+prabar
+['prebar', 'bar', 'leadbar']
+probarbirk
+['prebarbork']
+middle
+[]
+leadmiddle
+['leadmiddleend', 'leadmiddlebar']
+middleend
+[]
+endlead
+['end lead', 'lead', 'end end']
+leadprobar
+['leadprebar', 'lead prebar', 'leadbar']
+
+test 7-7
+# file: Xtest.utf-8.spl
+bar
+barmeat
+lead
+meea1
+meeaé
+prebar
+prebarmeat
+tail
+-------
+bad
+['bar', 'lead', 'tail']
+mee
+['meea1', 'meeaé', 'bar']
+meea2
+['meea1', 'meeaé', 'lead']
+prabar
+['prebar', 'bar', 'leadbar']
+probarmaat
+['prebarmeat']
+middle
+[]
+leadmiddle
+['leadmiddlebar']
+middletail
+[]
+taillead
+['tail lead', 'tail']
+leadprobar
+['leadprebar', 'lead prebar', 'leadbar']
diff --git a/src/testdir/test64.in b/src/testdir/test64.in
new file mode 100644
index 0000000..360418c
--- /dev/null
+++ b/src/testdir/test64.in
@@ -0,0 +1,654 @@
+Test for regexp patterns without multi-byte support.
+See test95 for multi-byte tests.
+
+A pattern that gives the expected result produces OK, so that we know it was
+actually tried.
+
+STARTTEST
+:so small.vim
+:" tl is a List of Lists with:
+:" regexp engine
+:" regexp pattern
+:" text to test the pattern on
+:" expected match (optional)
+:" expected submatch 1 (optional)
+:" expected submatch 2 (optional)
+:" etc.
+:" When there is no match use only the first two items.
+:let tl = []
+:"
+:""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+:"""" Previously written tests """"""""""""""""""""""""""""""""
+:""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+:"
+:call add(tl, [2, 'ab', 'aab', 'ab'])
+:call add(tl, [2, 'b', 'abcdef', 'b'])
+:call add(tl, [2, 'bc*', 'abccccdef', 'bcccc'])
+:call add(tl, [2, 'bc\{-}', 'abccccdef', 'b'])
+:call add(tl, [2, 'bc\{-}\(d\)', 'abccccdef', 'bccccd', 'd'])
+:call add(tl, [2, 'bc*', 'abbdef', 'b'])
+:call add(tl, [2, 'c*', 'ccc', 'ccc'])
+:call add(tl, [2, 'bc*', 'abdef', 'b'])
+:call add(tl, [2, 'c*', 'abdef', ''])
+:call add(tl, [2, 'bc\+', 'abccccdef', 'bcccc'])
+:call add(tl, [2, 'bc\+', 'abdef']) "no match
+:"
+:"operator \|
+:call add(tl, [2, 'a\|ab', 'cabd', 'a']) "alternation is ordered
+:"
+:call add(tl, [2, 'c\?', 'ccb', 'c'])
+:call add(tl, [2, 'bc\?', 'abd', 'b'])
+:call add(tl, [2, 'bc\?', 'abccd', 'bc'])
+:"
+:call add(tl, [2, '\va{1}', 'ab', 'a'])
+:"
+:call add(tl, [2, '\va{2}', 'aa', 'aa'])
+:call add(tl, [2, '\va{2}', 'caad', 'aa'])
+:call add(tl, [2, '\va{2}', 'aba'])
+:call add(tl, [2, '\va{2}', 'ab'])
+:call add(tl, [2, '\va{2}', 'abaa', 'aa'])
+:call add(tl, [2, '\va{2}', 'aaa', 'aa'])
+:"
+:call add(tl, [2, '\vb{1}', 'abca', 'b'])
+:call add(tl, [2, '\vba{2}', 'abaa', 'baa'])
+:call add(tl, [2, '\vba{3}', 'aabaac'])
+:"
+:call add(tl, [2, '\v(ab){1}', 'ab', 'ab', 'ab'])
+:call add(tl, [2, '\v(ab){1}', 'dabc', 'ab', 'ab'])
+:call add(tl, [2, '\v(ab){1}', 'acb'])
+:"
+:call add(tl, [2, '\v(ab){0,2}', 'acb', "", ""])
+:call add(tl, [2, '\v(ab){0,2}', 'ab', 'ab', 'ab'])
+:call add(tl, [2, '\v(ab){1,2}', 'ab', 'ab', 'ab'])
+:call add(tl, [2, '\v(ab){1,2}', 'ababc', 'abab', 'ab'])
+:call add(tl, [2, '\v(ab){2,4}', 'ababcab', 'abab', 'ab'])
+:call add(tl, [2, '\v(ab){2,4}', 'abcababa', 'abab', 'ab'])
+:"
+:call add(tl, [2, '\v(ab){2}', 'abab', 'abab', 'ab'])
+:call add(tl, [2, '\v(ab){2}', 'cdababe', 'abab', 'ab'])
+:call add(tl, [2, '\v(ab){2}', 'abac'])
+:call add(tl, [2, '\v(ab){2}', 'abacabab', 'abab', 'ab'])
+:call add(tl, [2, '\v((ab){2}){2}', 'abababab', 'abababab', 'abab', 'ab'])
+:call add(tl, [2, '\v((ab){2}){2}', 'abacabababab', 'abababab', 'abab', 'ab'])
+:"
+:call add(tl, [2, '\v(a{1}){1}', 'a', 'a', 'a'])
+:call add(tl, [2, '\v(a{2}){1}', 'aa', 'aa', 'aa'])
+:call add(tl, [2, '\v(a{2}){1}', 'aaac', 'aa', 'aa'])
+:call add(tl, [2, '\v(a{2}){1}', 'daaac', 'aa', 'aa'])
+:call add(tl, [2, '\v(a{1}){2}', 'daaac', 'aa', 'a'])
+:call add(tl, [2, '\v(a{1}){2}', 'aaa', 'aa', 'a'])
+:call add(tl, [2, '\v(a{2})+', 'adaac', 'aa', 'aa'])
+:call add(tl, [2, '\v(a{2})+', 'aa', 'aa', 'aa'])
+:call add(tl, [2, '\v(a{2}){1}', 'aa', 'aa', 'aa'])
+:call add(tl, [2, '\v(a{1}){2}', 'aa', 'aa', 'a'])
+:call add(tl, [2, '\v(a{1}){1}', 'a', 'a', 'a'])
+:call add(tl, [2, '\v(a{2}){2}', 'aaaa', 'aaaa', 'aa'])
+:call add(tl, [2, '\v(a{2}){2}', 'aaabaaaa', 'aaaa', 'aa'])
+:"
+:call add(tl, [2, '\v(a+){2}', 'dadaac', 'aa', 'a'])
+:call add(tl, [2, '\v(a{3}){2}', 'aaaaaaa', 'aaaaaa', 'aaa'])
+:"
+:call add(tl, [2, '\v(a{1,2}){2}', 'daaac', 'aaa', 'a'])
+:call add(tl, [2, '\v(a{1,3}){2}', 'daaaac', 'aaaa', 'a'])
+:call add(tl, [2, '\v(a{1,3}){2}', 'daaaaac', 'aaaaa', 'aa'])
+:call add(tl, [2, '\v(a{1,3}){3}', 'daac'])
+:call add(tl, [2, '\v(a{1,2}){2}', 'dac'])
+:call add(tl, [2, '\v(a+)+', 'daac', 'aa', 'aa'])
+:call add(tl, [2, '\v(a+)+', 'aaa', 'aaa', 'aaa'])
+:call add(tl, [2, '\v(a+){1,2}', 'aaa', 'aaa', 'aaa'])
+:call add(tl, [2, '\v(a+)(a+)', 'aaa', 'aaa', 'aa', 'a'])
+:call add(tl, [2, '\v(a{3})+', 'daaaac', 'aaa', 'aaa'])
+:call add(tl, [2, '\v(a|b|c)+', 'aacb', 'aacb', 'b'])
+:call add(tl, [2, '\v(a|b|c){2}', 'abcb', 'ab', 'b'])
+:call add(tl, [2, '\v(abc){2}', 'abcabd', ])
+:call add(tl, [2, '\v(abc){2}', 'abdabcabc','abcabc', 'abc'])
+:"
+:call add(tl, [2, 'a*', 'cc', ''])
+:call add(tl, [2, '\v(a*)+', 'cc', ''])
+:call add(tl, [2, '\v((ab)+)+', 'ab', 'ab', 'ab', 'ab'])
+:call add(tl, [2, '\v(((ab)+)+)+', 'ab', 'ab', 'ab', 'ab', 'ab'])
+:call add(tl, [2, '\v(((ab)+)+)+', 'dababc', 'abab', 'abab', 'abab', 'ab'])
+:call add(tl, [2, '\v(a{0,2})+', 'cc', ''])
+:call add(tl, [2, '\v(a*)+', '', ''])
+:call add(tl, [2, '\v((a*)+)+', '', ''])
+:call add(tl, [2, '\v((ab)*)+', '', ''])
+:call add(tl, [2, '\va{1,3}', 'aab', 'aa'])
+:call add(tl, [2, '\va{2,3}', 'abaa', 'aa'])
+:"
+:call add(tl, [2, '\v((ab)+|c*)+', 'abcccaba', 'abcccab', '', 'ab'])
+:call add(tl, [2, '\v(a{2})|(b{3})', 'bbabbbb', 'bbb', '', 'bbb'])
+:call add(tl, [2, '\va{2}|b{2}', 'abab'])
+:call add(tl, [2, '\v(a)+|(c)+', 'bbacbaacbbb', 'a', 'a'])
+:call add(tl, [2, '\vab{2,3}c', 'aabbccccccccccccc', 'abbc'])
+:call add(tl, [2, '\vab{2,3}c', 'aabbbccccccccccccc', 'abbbc'])
+:call add(tl, [2, '\vab{2,3}cd{2,3}e', 'aabbbcddee', 'abbbcdde'])
+:call add(tl, [2, '\va(bc){2}d', 'aabcbfbc' ])
+:call add(tl, [2, '\va*a{2}', 'a', ])
+:call add(tl, [2, '\va*a{2}', 'aa', 'aa' ])
+:call add(tl, [2, '\va*a{2}', 'aaa', 'aaa' ])
+:call add(tl, [2, '\va*a{2}', 'bbbabcc', ])
+:call add(tl, [2, '\va*b*|a*c*', 'a', 'a'])
+:call add(tl, [2, '\va{1}b{1}|a{1}b{1}', ''])
+:"
+:"submatches
+:call add(tl, [2, '\v(a)', 'ab', 'a', 'a'])
+:call add(tl, [2, '\v(a)(b)', 'ab', 'ab', 'a', 'b'])
+:call add(tl, [2, '\v(ab)(b)(c)', 'abbc', 'abbc', 'ab', 'b', 'c'])
+:call add(tl, [2, '\v((a)(b))', 'ab', 'ab', 'ab', 'a', 'b'])
+:call add(tl, [2, '\v(a)|(b)', 'ab', 'a', 'a'])
+:"
+:call add(tl, [2, '\v(a*)+', 'aaaa', 'aaaa', ''])
+:call add(tl, [2, 'x', 'abcdef'])
+:"
+:""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+:""""" Simple tests """""""""""""""""""""""""""""""""""""""""""
+:""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+:"
+:" Search single groups
+:call add(tl, [2, 'ab', 'aab', 'ab'])
+:call add(tl, [2, 'ab', 'baced'])
+:call add(tl, [2, 'ab', ' ab ', 'ab'])
+:"
+:" Search multi-modifiers
+:call add(tl, [2, 'x*', 'xcd', 'x'])
+:call add(tl, [2, 'x*', 'xxxxxxxxxxxxxxxxsofijiojgf', 'xxxxxxxxxxxxxxxx'])
+:" empty match is good
+:call add(tl, [2, 'x*', 'abcdoij', ''])
+:" no match here
+:call add(tl, [2, 'x\+', 'abcdoin'])
+:call add(tl, [2, 'x\+', 'abcdeoijdfxxiuhfij', 'xx'])
+:call add(tl, [2, 'x\+', 'xxxxx', 'xxxxx'])
+:call add(tl, [2, 'x\+', 'abc x siufhiush xxxxxxxxx', 'x'])
+:call add(tl, [2, 'x\=', 'x sdfoij', 'x'])
+:call add(tl, [2, 'x\=', 'abc sfoij', '']) " empty match is good
+:call add(tl, [2, 'x\=', 'xxxxxxxxx c', 'x'])
+:call add(tl, [2, 'x\?', 'x sdfoij', 'x'])
+:" empty match is good
+:call add(tl, [2, 'x\?', 'abc sfoij', ''])
+:call add(tl, [2, 'x\?', 'xxxxxxxxxx c', 'x'])
+:"
+:call add(tl, [2, 'a\{0,0}', 'abcdfdoij', ''])
+:" same thing as 'a?'
+:call add(tl, [2, 'a\{0,1}', 'asiubid axxxaaa', 'a'])
+:" same thing as 'a\{0,1}'
+:call add(tl, [2, 'a\{1,0}', 'asiubid axxxaaa', 'a'])
+:call add(tl, [2, 'a\{3,6}', 'aa siofuh'])
+:call add(tl, [2, 'a\{3,6}', 'aaaaa asfoij afaa', 'aaaaa'])
+:call add(tl, [2, 'a\{3,6}', 'aaaaaaaa', 'aaaaaa'])
+:call add(tl, [2, 'a\{0}', 'asoiuj', ''])
+:call add(tl, [2, 'a\{2}', 'aaaa', 'aa'])
+:call add(tl, [2, 'a\{2}', 'iuash fiusahfliusah fiushfilushfi uhsaifuh askfj nasfvius afg aaaa sfiuhuhiushf', 'aa'])
+:call add(tl, [2, 'a\{2}', 'abcdefghijklmnopqrestuvwxyz1234567890'])
+:" same thing as 'a*'
+:call add(tl, [2, 'a\{0,}', 'oij sdigfusnf', ''])
+:call add(tl, [2, 'a\{0,}', 'aaaaa aa', 'aaaaa'])
+:call add(tl, [2, 'a\{2,}', 'sdfiougjdsafg'])
+:call add(tl, [2, 'a\{2,}', 'aaaaasfoij ', 'aaaaa'])
+:call add(tl, [2, 'a\{5,}', 'xxaaaaxxx '])
+:call add(tl, [2, 'a\{5,}', 'xxaaaaaxxx ', 'aaaaa'])
+:call add(tl, [2, 'a\{,0}', 'oidfguih iuhi hiu aaaa', ''])
+:call add(tl, [2, 'a\{,5}', 'abcd', 'a'])
+:call add(tl, [2, 'a\{,5}', 'aaaaaaaaaa', 'aaaaa'])
+:" leading star as normal char when \{} follows
+:call add(tl, [2, '^*\{4,}$', '***'])
+:call add(tl, [2, '^*\{4,}$', '****', '****'])
+:call add(tl, [2, '^*\{4,}$', '*****', '*****'])
+:" same thing as 'a*'
+:call add(tl, [2, 'a\{}', 'bbbcddiuhfcd', ''])
+:call add(tl, [2, 'a\{}', 'aaaaioudfh coisf jda', 'aaaa'])
+:"
+:call add(tl, [2, 'a\{-0,0}', 'abcdfdoij', ''])
+:" anti-greedy version of 'a?'
+:call add(tl, [2, 'a\{-0,1}', 'asiubid axxxaaa', ''])
+:call add(tl, [2, 'a\{-3,6}', 'aa siofuh'])
+:call add(tl, [2, 'a\{-3,6}', 'aaaaa asfoij afaa', 'aaa'])
+:call add(tl, [2, 'a\{-3,6}', 'aaaaaaaa', 'aaa'])
+:call add(tl, [2, 'a\{-0}', 'asoiuj', ''])
+:call add(tl, [2, 'a\{-2}', 'aaaa', 'aa'])
+:call add(tl, [2, 'a\{-2}', 'abcdefghijklmnopqrestuvwxyz1234567890'])
+:call add(tl, [2, 'a\{-0,}', 'oij sdigfusnf', ''])
+:call add(tl, [2, 'a\{-0,}', 'aaaaa aa', ''])
+:call add(tl, [2, 'a\{-2,}', 'sdfiougjdsafg'])
+:call add(tl, [2, 'a\{-2,}', 'aaaaasfoij ', 'aa'])
+:call add(tl, [2, 'a\{-,0}', 'oidfguih iuhi hiu aaaa', ''])
+:call add(tl, [2, 'a\{-,5}', 'abcd', ''])
+:call add(tl, [2, 'a\{-,5}', 'aaaaaaaaaa', ''])
+:" anti-greedy version of 'a*'
+:call add(tl, [2, 'a\{-}', 'bbbcddiuhfcd', ''])
+:call add(tl, [2, 'a\{-}', 'aaaaioudfh coisf jda', ''])
+:"
+:" Test groups of characters and submatches
+:call add(tl, [2, '\(abc\)*', 'abcabcabc', 'abcabcabc', 'abc'])
+:call add(tl, [2, '\(ab\)\+', 'abababaaaaa', 'ababab', 'ab'])
+:call add(tl, [2, '\(abaaaaa\)*cd', 'cd', 'cd', ''])
+:call add(tl, [2, '\(test1\)\? \(test2\)\?', 'test1 test3', 'test1 ', 'test1', ''])
+:call add(tl, [2, '\(test1\)\= \(test2\) \(test4443\)\=', ' test2 test4443 yupiiiiiiiiiii', ' test2 test4443', '', 'test2', 'test4443'])
+:call add(tl, [2, '\(\(sub1\) hello \(sub 2\)\)', 'asterix sub1 hello sub 2 obelix', 'sub1 hello sub 2', 'sub1 hello sub 2', 'sub1', 'sub 2'])
+:call add(tl, [2, '\(\(\(yyxxzz\)\)\)', 'abcdddsfiusfyyzzxxyyxxzz', 'yyxxzz', 'yyxxzz', 'yyxxzz', 'yyxxzz'])
+:call add(tl, [2, '\v((ab)+|c+)+', 'abcccaba', 'abcccab', 'ab', 'ab'])
+:call add(tl, [2, '\v((ab)|c*)+', 'abcccaba', 'abcccab', '', 'ab'])
+:call add(tl, [2, '\v(a(c*)+b)+', 'acbababaaa', 'acbabab', 'ab', ''])
+:call add(tl, [2, '\v(a|b*)+', 'aaaa', 'aaaa', ''])
+:call add(tl, [2, '\p*', 'aá ', 'aá '])
+:"
+:" Test greedy-ness and lazy-ness
+:call add(tl, [2, 'a\{-2,7}','aaaaaaaaaaaaa', 'aa'])
+:call add(tl, [2, 'a\{-2,7}x','aaaaaaaaax', 'aaaaaaax'])
+:call add(tl, [2, 'a\{2,7}','aaaaaaaaaaaaaaaaaaaa', 'aaaaaaa'])
+:call add(tl, [2, 'a\{2,7}x','aaaaaaaaax', 'aaaaaaax'])
+:call add(tl, [2, '\vx(.{-,8})yz(.*)','xayxayzxayzxayz','xayxayzxayzxayz','ayxa','xayzxayz'])
+:call add(tl, [2, '\vx(.*)yz(.*)','xayxayzxayzxayz','xayxayzxayzxayz', 'ayxayzxayzxa',''])
+:call add(tl, [2, '\v(a{1,2}){-2,3}','aaaaaaa','aaaa','aa'])
+:call add(tl, [2, '\v(a{-1,3})+', 'aa', 'aa', 'a'])
+:call add(tl, [2, '^\s\{-}\zs\( x\|x$\)', ' x', ' x', ' x'])
+:call add(tl, [2, '^\s\{-}\zs\(x\| x$\)', ' x', ' x', ' x'])
+:call add(tl, [2, '^\s\{-}\ze\(x\| x$\)', ' x', '', ' x'])
+:call add(tl, [2, '^\(\s\{-}\)\(x\| x$\)', ' x', ' x', '', ' x'])
+:"
+:" Test Character classes
+:call add(tl, [2, '\d\+e\d\d','test 10e23 fd','10e23'])
+:"
+:" Test collections and character range []
+:call add(tl, [2, '\v[a]', 'abcd', 'a'])
+:call add(tl, [2, 'a[bcd]', 'abcd', 'ab'])
+:call add(tl, [2, 'a[b-d]', 'acbd', 'ac'])
+:call add(tl, [2, '[a-d][e-f][x-x]d', 'cexdxx', 'cexd'])
+:call add(tl, [2, '\v[[:alpha:]]+', 'abcdefghijklmnopqrstuvwxyz6','abcdefghijklmnopqrstuvwxyz'])
+:call add(tl, [2, '[[:alpha:]\+]', '6x8','x'])
+:call add(tl, [2, '[^abc]\+','abcabcabc'])
+:call add(tl, [2, '[^abc]','defghiasijvoinasoiunbvb','d'])
+:call add(tl, [2, '[^abc]\+','ddddddda','ddddddd'])
+:call add(tl, [2, '[^a-d]\+','aaaAAAZIHFNCddd','AAAZIHFNC'])
+:call add(tl, [2, '[a-f]*','iiiiiiii',''])
+:call add(tl, [2, '[a-f]*','abcdefgh','abcdef'])
+:call add(tl, [2, '[^a-f]\+','abcdefgh','gh'])
+:call add(tl, [2, '[a-c]\{-3,6}','abcabc','abc'])
+:call add(tl, [2, '[^[:alpha:]]\+','abcccadfoij7787ysf287yrnccdu','7787'])
+:call add(tl, [2, '[-a]', '-', '-'])
+:call add(tl, [2, '[a-]', '-', '-'])
+:call add(tl, [2, '[a-f]*\c','ABCDEFGH','ABCDEF'])
+:call add(tl, [2, '[abc][xyz]\c','-af-AF-BY--','BY'])
+:" filename regexp
+:call add(tl, [2, '[-./[:alnum:]_~]\+', 'log13.file', 'log13.file'])
+:" special chars
+:call add(tl, [2, '[\]\^\-\\]\+', '\^\\\-\---^', '\^\\\-\---^'])
+:" collation elem
+:call add(tl, [2, '[[.a.]]\+', 'aa', 'aa'])
+:" middle of regexp
+:call add(tl, [2, 'abc[0-9]*ddd', 'siuhabc ii'])
+:call add(tl, [2, 'abc[0-9]*ddd', 'adf abc44482ddd oijs', 'abc44482ddd'])
+:call add(tl, [2, '\_[0-9]\+', 'asfi9888u', '9888'])
+:call add(tl, [2, '[0-9\n]\+', 'asfi9888u', '9888'])
+:call add(tl, [2, '\_[0-9]\+', "asfi\n9888u", "\n9888"])
+:call add(tl, [2, '\_f', " \na ", "\n"])
+:call add(tl, [2, '\_f\+', " \na ", "\na"])
+:call add(tl, [2, '[0-9A-Za-z-_.]\+', " @0_a.A-{ ", "0_a.A-"])
+:"
+:"""" Test start/end of line, start/end of file
+:call add(tl, [2, '^a.', "a_\nb ", "a_"])
+:call add(tl, [2, '^a.', "b a \na_"])
+:call add(tl, [2, '.a$', " a\n "])
+:call add(tl, [2, '.a$', " a b\n_a", "_a"])
+:call add(tl, [2, '\%^a.', "a a\na", "a "])
+:call add(tl, [2, '\%^a', " a \na "])
+:call add(tl, [2, '.a\%$', " a\n "])
+:call add(tl, [2, '.a\%$', " a\n_a", "_a"])
+:"
+:"""" Test recognition of character classes
+:call add(tl, [2, '[0-7]\+', 'x0123456789x', '01234567'])
+:call add(tl, [2, '[^0-7]\+', '0a;X+% 897', 'a;X+% 89'])
+:call add(tl, [2, '[0-9]\+', 'x0123456789x', '0123456789'])
+:call add(tl, [2, '[^0-9]\+', '0a;X+% 9', 'a;X+% '])
+:call add(tl, [2, '[0-9a-fA-F]\+', 'x0189abcdefg', '0189abcdef'])
+:call add(tl, [2, '[^0-9A-Fa-f]\+', '0189g;X+% ab', 'g;X+% '])
+:call add(tl, [2, '[a-z_A-Z0-9]\+', ';+aso_SfOij ', 'aso_SfOij'])
+:call add(tl, [2, '[^a-z_A-Z0-9]\+', 'aSo_;+% sfOij', ';+% '])
+:call add(tl, [2, '[a-z_A-Z]\+', '0abyz_ABYZ;', 'abyz_ABYZ'])
+:call add(tl, [2, '[^a-z_A-Z]\+', 'abAB_09;+% yzYZ', '09;+% '])
+:call add(tl, [2, '[a-z]\+', '0abcxyz1', 'abcxyz'])
+:call add(tl, [2, '[a-z]\+', 'AabxyzZ', 'abxyz'])
+:call add(tl, [2, '[^a-z]\+', 'a;X09+% x', ';X09+% '])
+:call add(tl, [2, '[^a-z]\+', 'abX0;%yz', 'X0;%'])
+:call add(tl, [2, '[a-zA-Z]\+', '0abABxzXZ9', 'abABxzXZ'])
+:call add(tl, [2, '[^a-zA-Z]\+', 'ab09_;+ XZ', '09_;+ '])
+:call add(tl, [2, '[A-Z]\+', 'aABXYZz', 'ABXYZ'])
+:call add(tl, [2, '[^A-Z]\+', 'ABx0;%YZ', 'x0;%'])
+:call add(tl, [2, '[a-z]\+\c', '0abxyzABXYZ;', 'abxyzABXYZ'])
+:call add(tl, [2, '[A-Z]\+\c', '0abABxzXZ9', 'abABxzXZ'])
+:call add(tl, [2, '\c[^a-z]\+', 'ab09_;+ XZ', '09_;+ '])
+:call add(tl, [2, '\c[^A-Z]\+', 'ab09_;+ XZ', '09_;+ '])
+:call add(tl, [2, '\C[^A-Z]\+', 'ABCOIJDEOIFNSD jsfoij sa', ' jsfoij sa'])
+:"
+:"""" Tests for \z features
+:" match ends at \ze
+:call add(tl, [2, 'xx \ze test', 'xx '])
+:call add(tl, [2, 'abc\zeend', 'oij abcend', 'abc'])
+:call add(tl, [2, 'aa\zebb\|aaxx', ' aabb ', 'aa'])
+:call add(tl, [2, 'aa\zebb\|aaxx', ' aaxx ', 'aaxx'])
+:call add(tl, [2, 'aabb\|aa\zebb', ' aabb ', 'aabb'])
+:call add(tl, [2, 'aa\zebb\|aaebb', ' aabb ', 'aa'])
+:" match starts at \zs
+:call add(tl, [2, 'abc\zsdd', 'ddabcddxyzt', 'dd'])
+:call add(tl, [2, 'aa \zsax', ' ax'])
+:call add(tl, [2, 'abc \zsmatch\ze abc', 'abc abc abc match abc abc', 'match'])
+:call add(tl, [2, '\v(a \zsif .*){2}', 'a if then a if last', 'if last', 'a if last'])
+:call add(tl, [2, '\>\zs.', 'aword. ', '.'])
+:call add(tl, [2, '\s\+\ze\[/\|\s\zs\s\+', 'is [a t', ' '])
+:"
+:"""" Tests for \@= and \& features
+:call add(tl, [2, 'abc\@=', 'abc', 'ab'])
+:call add(tl, [2, 'abc\@=cd', 'abcd', 'abcd'])
+:call add(tl, [2, 'abc\@=', 'ababc', 'ab'])
+:" will never match, no matter the input text
+:call add(tl, [2, 'abcd\@=e', 'abcd'])
+:" will never match
+:call add(tl, [2, 'abcd\@=e', 'any text in here ... '])
+:call add(tl, [2, '\v(abc)@=..', 'xabcd', 'ab', 'abc'])
+:call add(tl, [2, '\(.*John\)\@=.*Bob', 'here is John, and here is B'])
+:call add(tl, [2, '\(John.*\)\@=.*Bob', 'John is Bobs friend', 'John is Bob', 'John is Bobs friend'])
+:call add(tl, [2, '\<\S\+\())\)\@=', '$((i=i+1))', 'i=i+1', '))'])
+:call add(tl, [2, '.*John\&.*Bob', 'here is John, and here is B'])
+:call add(tl, [2, '.*John\&.*Bob', 'John is Bobs friend', 'John is Bob'])
+:call add(tl, [2, '\v(test1)@=.*yep', 'this is a test1, yep it is', 'test1, yep', 'test1'])
+:call add(tl, [2, 'foo\(bar\)\@!', 'foobar'])
+:call add(tl, [2, 'foo\(bar\)\@!', 'foo bar', 'foo'])
+:call add(tl, [2, 'if \(\(then\)\@!.\)*$', ' if then else'])
+:call add(tl, [2, 'if \(\(then\)\@!.\)*$', ' if else ', 'if else ', ' '])
+:call add(tl, [2, '\(foo\)\@!bar', 'foobar', 'bar'])
+:call add(tl, [2, '\(foo\)\@!...bar', 'foobar'])
+:call add(tl, [2, '^\%(.*bar\)\@!.*\zsfoo', ' bar foo '])
+:call add(tl, [2, '^\%(.*bar\)\@!.*\zsfoo', ' foo bar '])
+:call add(tl, [2, '^\%(.*bar\)\@!.*\zsfoo', ' foo xxx ', 'foo'])
+:call add(tl, [2, '[ ]\@!\p\%([ ]\@!\p\)*:', 'implicit mappings:', 'mappings:'])
+:call add(tl, [2, '[ ]\@!\p\([ ]\@!\p\)*:', 'implicit mappings:', 'mappings:', 's'])
+:call add(tl, [2, 'm\k\+_\@=\%(_\@!\k\)\@<=\k\+e', 'mx__xe', 'mx__xe'])
+:call add(tl, [2, '\%(\U\@<=S\k*\|S\l\)R', 'SuR', 'SuR'])
+:"
+:"""" Combining different tests and features
+:call add(tl, [2, '[[:alpha:]]\{-2,6}', '787abcdiuhsasiuhb4', 'ab'])
+:call add(tl, [2, '', 'abcd', ''])
+:call add(tl, [2, '\v(())', 'any possible text', ''])
+:call add(tl, [2, '\v%(ab(xyz)c)', ' abxyzc ', 'abxyzc', 'xyz'])
+:call add(tl, [2, '\v(test|)empty', 'tesempty', 'empty', ''])
+:call add(tl, [2, '\v(a|aa)(a|aa)', 'aaa', 'aa', 'a', 'a'])
+:"
+:"""" \%u and friends
+:call add(tl, [2, '\%d32', 'yes no', ' '])
+:call add(tl, [2, '\%o40', 'yes no', ' '])
+:call add(tl, [2, '\%x20', 'yes no', ' '])
+:call add(tl, [2, '\%u0020', 'yes no', ' '])
+:call add(tl, [2, '\%U00000020', 'yes no', ' '])
+:call add(tl, [2, '\%d0', "yes\x0ano", "\x0a"])
+:"
+:""""" \%[abc]
+:call add(tl, [2, 'foo\%[bar]', 'fobar'])
+:call add(tl, [2, 'foo\%[bar]', 'foobar', 'foobar'])
+:call add(tl, [2, 'foo\%[bar]', 'fooxx', 'foo'])
+:call add(tl, [2, 'foo\%[bar]', 'foobxx', 'foob'])
+:call add(tl, [2, 'foo\%[bar]', 'foobaxx', 'fooba'])
+:call add(tl, [2, 'foo\%[bar]', 'foobarxx', 'foobar'])
+:call add(tl, [2, 'foo\%[bar]x', 'foobxx', 'foobx'])
+:call add(tl, [2, 'foo\%[bar]x', 'foobarxx', 'foobarx'])
+:call add(tl, [2, '\%[bar]x', 'barxx', 'barx'])
+:call add(tl, [2, '\%[bar]x', 'bxx', 'bx'])
+:call add(tl, [2, '\%[bar]x', 'xxx', 'x'])
+:call add(tl, [2, 'b\%[[ao]r]', 'bar bor', 'bar'])
+:call add(tl, [2, 'b\%[[]]r]', 'b]r bor', 'b]r'])
+:call add(tl, [2, '@\%[\w\-]*', '<http://john.net/pandoc/>[@pandoc]', '@pandoc'])
+:"
+:"""" Alternatives, must use first longest match
+:call add(tl, [2, 'goo\|go', 'google', 'goo'])
+:call add(tl, [2, '\<goo\|\<go', 'google', 'goo'])
+:call add(tl, [2, '\<goo\|go', 'google', 'goo'])
+:"
+:"""" Back references
+:call add(tl, [2, '\(\i\+\) \1', ' abc abc', 'abc abc', 'abc'])
+:call add(tl, [2, '\(\i\+\) \1', 'xgoo goox', 'goo goo', 'goo'])
+:call add(tl, [2, '\(a\)\(b\)\(c\)\(dd\)\(e\)\(f\)\(g\)\(h\)\(i\)\1\2\3\4\5\6\7\8\9', 'xabcddefghiabcddefghix', 'abcddefghiabcddefghi', 'a', 'b', 'c', 'dd', 'e', 'f', 'g', 'h', 'i'])
+:call add(tl, [2, '\(\d*\)a \1b', ' a b ', 'a b', ''])
+:call add(tl, [2, '^.\(.\).\_..\1.', "aaa\naaa\nb", "aaa\naaa", 'a'])
+:call add(tl, [2, '^.*\.\(.*\)/.\+\(\1\)\@<!$', 'foo.bat/foo.com', 'foo.bat/foo.com', 'bat'])
+:call add(tl, [2, '^.*\.\(.*\)/.\+\(\1\)\@<!$', 'foo.bat/foo.bat'])
+:call add(tl, [2, '^.*\.\(.*\)/.\+\(\1\)\@<=$', 'foo.bat/foo.bat', 'foo.bat/foo.bat', 'bat', 'bat'])
+:call add(tl, [2, '\\\@<!\${\(\d\+\%(:.\{-}\)\?\\\@<!\)}', '2013-06-27${0}', '${0}', '0'])
+:call add(tl, [2, '^\(a*\)\1$', 'aaaaaaaa', 'aaaaaaaa', 'aaaa'])
+:call add(tl, [2, '^\(a\{-2,}\)\1\+$', 'aaaaaaaaa', 'aaaaaaaaa', 'aaa'])
+:"
+:"""" Look-behind with limit
+:call add(tl, [2, '<\@<=span.', 'xxspanxx<spanyyy', 'spany'])
+:call add(tl, [2, '<\@1<=span.', 'xxspanxx<spanyyy', 'spany'])
+:call add(tl, [2, '<\@2<=span.', 'xxspanxx<spanyyy', 'spany'])
+:call add(tl, [2, '\(<<\)\@<=span.', 'xxspanxxxx<spanxx<<spanyyy', 'spany', '<<'])
+:call add(tl, [2, '\(<<\)\@1<=span.', 'xxspanxxxx<spanxx<<spanyyy'])
+:call add(tl, [2, '\(<<\)\@2<=span.', 'xxspanxxxx<spanxx<<spanyyy', 'spany', '<<'])
+:call add(tl, [2, '\(foo\)\@<!bar.', 'xx foobar1 xbar2 xx', 'bar2'])
+:"
+:" look-behind match in front of a zero-width item
+:call add(tl, [2, '\v\C%(<Last Changed:\s+)@<=.*$', '" test header'])
+:call add(tl, [2, '\v\C%(<Last Changed:\s+)@<=.*$', '" Last Changed: 1970', '1970'])
+:call add(tl, [2, '\(foo\)\@<=\>', 'foobar'])
+:call add(tl, [2, '\(foo\)\@<=\>', 'barfoo', '', 'foo'])
+:call add(tl, [2, '\(foo\)\@<=.*', 'foobar', 'bar', 'foo'])
+:"
+:" complicated look-behind match
+:call add(tl, [2, '\(r\@<=\|\w\@<!\)\/', 'x = /word/;', '/'])
+:call add(tl, [2, '^[a-z]\+\ze \&\(asdf\)\@<!', 'foo bar', 'foo'])
+:"
+:""""" \@>
+:call add(tl, [2, '\(a*\)\@>a', 'aaaa'])
+:call add(tl, [2, '\(a*\)\@>b', 'aaab', 'aaab', 'aaa'])
+:call add(tl, [2, '^\(.\{-}b\)\@>.', ' abcbd', ' abc', ' ab'])
+:call add(tl, [2, '\(.\{-}\)\(\)\@>$', 'abc', 'abc', 'abc', ''])
+:" TODO: BT engine does not restore submatch after failure
+:call add(tl, [1, '\(a*\)\@>a\|a\+', 'aaaa', 'aaaa'])
+:"
+:"""" "\_" prepended negated collection matches EOL
+:call add(tl, [2, '\_[^8-9]\+', "asfi\n9888", "asfi\n"])
+:call add(tl, [2, '\_[^a]\+', "asfi\n9888", "sfi\n9888"])
+:"
+:"""" Requiring lots of states.
+:call add(tl, [2, '[0-9a-zA-Z]\{8}-\([0-9a-zA-Z]\{4}-\)\{3}[0-9a-zA-Z]\{12}', " 12345678-1234-1234-1234-123456789012 ", "12345678-1234-1234-1234-123456789012", "1234-"])
+:"
+:"""" Skip adding state twice
+:call add(tl, [2, '^\%(\%(^\s*#\s*if\>\|#\s*if\)\)\(\%>1c.*$\)\@=', "#if FOO", "#if", ' FOO'])
+:"
+:""" Test \%V atom
+:call add(tl, [2, '\%>70vGesamt', 'Jean-Michel Charlier & Victor Hubinon\Gesamtausgabe [Salleck] Buck Danny {Jean-Michel Charlier & Victor Hubinon}\Gesamtausgabe', 'Gesamt'])
+:"
+:"""" Run the tests
+:"
+:for t in tl
+: let re = t[0]
+: let pat = t[1]
+: let text = t[2]
+: let matchidx = 3
+: for engine in [0, 1, 2]
+: if engine == 2 && re == 0 || engine == 1 && re == 1
+: continue
+: endif
+: let &regexpengine = engine
+: try
+: let l = matchlist(text, pat)
+: catch
+: $put ='ERROR ' . engine . ': pat: \"' . pat . '\", text: \"' . text . '\", caused an exception: \"' . v:exception . '\"'
+: endtry
+:" check the match itself
+: if len(l) == 0 && len(t) > matchidx
+: $put ='ERROR ' . engine . ': pat: \"' . pat . '\", text: \"' . text . '\", did not match, expected: \"' . t[matchidx] . '\"'
+: elseif len(l) > 0 && len(t) == matchidx
+: $put ='ERROR ' . engine . ': pat: \"' . pat . '\", text: \"' . text . '\", match: \"' . l[0] . '\", expected no match'
+: elseif len(t) > matchidx && l[0] != t[matchidx]
+: $put ='ERROR ' . engine . ': pat: \"' . pat . '\", text: \"' . text . '\", match: \"' . l[0] . '\", expected: \"' . t[matchidx] . '\"'
+: else
+: $put ='OK ' . engine . ' - ' . pat
+: endif
+: if len(l) > 0
+:" check all the nine submatches
+: for i in range(1, 9)
+: if len(t) <= matchidx + i
+: let e = ''
+: else
+: let e = t[matchidx + i]
+: endif
+: if l[i] != e
+: $put ='ERROR ' . engine . ': pat: \"' . pat . '\", text: \"' . text . '\", submatch ' . i . ': \"' . l[i] . '\", expected: \"' . e . '\"'
+: endif
+: endfor
+: unlet i
+: endif
+: endfor
+:endfor
+:unlet t tl e l
+:"
+:"""""" multi-line tests """"""""""""""""""""
+:let tl = []
+:"
+:"""" back references
+:call add(tl, [2, '^.\(.\).\_..\1.', ['aaa', 'aaa', 'b'], ['XX', 'b']])
+:call add(tl, [2, '\v.*\/(.*)\n.*\/\1$', ['./Dir1/Dir2/zyxwvuts.txt', './Dir1/Dir2/abcdefgh.bat', '', './Dir1/Dir2/file1.txt', './OtherDir1/OtherDir2/file1.txt'], ['./Dir1/Dir2/zyxwvuts.txt', './Dir1/Dir2/abcdefgh.bat', '', 'XX']])
+:"
+:"""" line breaks
+:call add(tl, [2, '\S.*\nx', ['abc', 'def', 'ghi', 'xjk', 'lmn'], ['abc', 'def', 'XXjk', 'lmn']])
+:"
+:" Check that \_[0-9] matching EOL does not break a following \>
+:call add(tl, [2, '\<\(\(25\_[0-5]\|2\_[0-4]\_[0-9]\|\_[01]\?\_[0-9]\_[0-9]\?\)\.\)\{3\}\(25\_[0-5]\|2\_[0-4]\_[0-9]\|\_[01]\?\_[0-9]\_[0-9]\?\)\>', ['', 'localnet/192.168.0.1', ''], ['', 'localnet/XX', '']])
+:"
+:" Check a pattern with a line break and ^ and $
+:call add(tl, [2, 'a\n^b$\n^c', ['a', 'b', 'c'], ['XX']])
+:"
+:call add(tl, [2, '\(^.\+\n\)\1', [' dog', ' dog', 'asdf'], ['XXasdf']])
+:"
+:"""" Run the multi-line tests
+:"
+:$put ='multi-line tests'
+:for t in tl
+: let re = t[0]
+: let pat = t[1]
+: let before = t[2]
+: let after = t[3]
+: for engine in [0, 1, 2]
+: if engine == 2 && re == 0 || engine == 1 && re ==1
+: continue
+: endif
+: let &regexpengine = engine
+: new
+: call setline(1, before)
+: exe '%s/' . pat . '/XX/'
+: let result = getline(1, '$')
+: q!
+: if result != after
+: $put ='ERROR: pat: \"' . pat . '\", text: \"' . string(before) . '\", expected: \"' . string(after) . '\", got: \"' . string(result) . '\"'
+: else
+: $put ='OK ' . engine . ' - ' . pat
+: endif
+: endfor
+:endfor
+:unlet t tl
+:"
+:" Check that using a pattern on two lines doesn't get messed up by using
+:" matchstr() with \ze in between.
+:set re=0
+/^Substitute here
+:.+1,.+2s/""/\='"'.matchstr(getline("."), '\d\+\ze<').'"'
+/^Substitute here
+:.+1,.+2yank
+Gop:"
+:"
+:" Check a pattern with a look beind crossing a line boundary
+/^Behind:
+/\(<\_[xy]\+\)\@3<=start
+:.yank
+Gop:"
+:"
+:" Check matching Visual area
+/^Visual:
+jfxvfx:s/\%Ve/E/g
+jV:s/\%Va/A/g
+jfxfxj:s/\%Vo/O/g
+:/^Visual/+1,/^Visual/+4yank
+Gop:"
+:"
+:" Check matching marks
+/^Marks:
+jfSmsfEme:.-4,.+6s/.\%>'s.*\%<'e../here/
+jfSmsj0fEme:.-4,.+6s/.\%>'s\_.*\%<'e../again/
+:/^Marks:/+1,/^Marks:/+3yank
+Gop:"
+:"
+:" Check patterns matching cursor position.
+:func! Postest()
+ new
+ call setline(1, ['ffooooo', 'boboooo', 'zoooooo', 'koooooo', 'moooooo', "\t\t\tfoo", 'abababababababfoo', 'bababababababafoo', '********_', ' xxxxxxxxxxxx xxxx xxxxxx xxxxxxx x xxxxxxxxx xx xxxxxx xxxxxx xxxxx xxxxxxx xx xxxx xxxxxxxx xxxx xxxxxxxxxxx xxx xxxxxxx xxxxxxxxx xx xxxxxx xx xxxxxxx xxxxxxxxxxxxxxxx xxxxxxxxx xxx xxxxxxxx xxxxxxxxx xxxx xxx xxxx xxx xxx xxxxx xxxxxxxxxxxx xxxx xxxxxxxxx xxxxxxxxxxx xx xxxxx xxx xxxxxxxx xxxxxx xxx xxx xxxxxxxxx xxxxxxx x xxxxxxxxx xx xxxxxx xxxxxxx xxxxxxxxxxxxxxxxxx xxxxxxx xxxxxxx xxx xxx xxxxxxxx xxxxxxx xxxx xxx xxxxxx xxxxx xxxxx xx xxxxxx xxxxxxx xxx xxxxxxxxxxxx xxxx xxxxxxxxx xxxxxx xxxxxx xxxxx xxx xxxxxxx xxxxxxxxxxxxxxxx xxxxxxxxx xxxxxxxxxx xxxx xx xxxxxxxx xxx xxxxxxxxxxx xxxxx'])
+ call setpos('.', [0, 1, 0, 0])
+ s/\%>3c.//g
+ call setpos('.', [0, 2, 4, 0])
+ s/\%#.*$//g
+ call setpos('.', [0, 3, 0, 0])
+ s/\%<3c./_/g
+ %s/\%4l\%>5c./_/g
+ %s/\%6l\%>25v./_/g
+ %s/\%>6l\%3c./!/g
+ %s/\%>7l\%12c./?/g
+ %s/\%>7l\%<9l\%>5v\%<8v./#/g
+ $s/\%(|\u.*\)\@<=[^|\t]\+$//ge
+ 1,$yank
+ quit!
+endfunc
+Go-0-:set re=0
+:call Postest()
+:put
+o-1-:set re=1
+:call Postest()
+:put
+o-2-:set re=2
+:call Postest()
+:put
+:"
+:" start and end of buffer
+/\%^
+yeGop:"
+50%/\%^..
+yeGopA END:"
+50%/\%$
+"ayb20gg/..\%$
+"bybGo"apo"bp:"
+:"
+:" Check for detecting error
+:set regexpengine=2
+:for pat in [' \ze*', ' \zs*']
+: try
+: let l = matchlist('x x', pat)
+: $put ='E888 NOT detected for ' . pat
+: catch
+: $put ='E888 detected for ' . pat
+: endtry
+:endfor
+:"
+:""""" Write the results """""""""""""
+:/\%#=1^Results/,$wq! test.out
+ENDTEST
+
+Substitute here:
+<T="">Ta 5</Title>
+<T="">Ac 7</Title>
+
+Behind:
+asdfasd<yyy
+xxstart1
+asdfasd<yy
+xxxstart2
+asdfasd<yy
+xxstart3
+
+Visual:
+thexe the thexethe
+andaxand andaxand
+oooxofor foroxooo
+oooxofor foroxooo
+
+Marks:
+asdfSasdfsadfEasdf
+asdfSas
+dfsadfEasdf
+
+Results of test64:
diff --git a/src/testdir/test64.ok b/src/testdir/test64.ok
new file mode 100644
index 0000000..c218f8e
--- /dev/null
+++ b/src/testdir/test64.ok
@@ -0,0 +1,1107 @@
+Results of test64:
+OK 0 - ab
+OK 1 - ab
+OK 2 - ab
+OK 0 - b
+OK 1 - b
+OK 2 - b
+OK 0 - bc*
+OK 1 - bc*
+OK 2 - bc*
+OK 0 - bc\{-}
+OK 1 - bc\{-}
+OK 2 - bc\{-}
+OK 0 - bc\{-}\(d\)
+OK 1 - bc\{-}\(d\)
+OK 2 - bc\{-}\(d\)
+OK 0 - bc*
+OK 1 - bc*
+OK 2 - bc*
+OK 0 - c*
+OK 1 - c*
+OK 2 - c*
+OK 0 - bc*
+OK 1 - bc*
+OK 2 - bc*
+OK 0 - c*
+OK 1 - c*
+OK 2 - c*
+OK 0 - bc\+
+OK 1 - bc\+
+OK 2 - bc\+
+OK 0 - bc\+
+OK 1 - bc\+
+OK 2 - bc\+
+OK 0 - a\|ab
+OK 1 - a\|ab
+OK 2 - a\|ab
+OK 0 - c\?
+OK 1 - c\?
+OK 2 - c\?
+OK 0 - bc\?
+OK 1 - bc\?
+OK 2 - bc\?
+OK 0 - bc\?
+OK 1 - bc\?
+OK 2 - bc\?
+OK 0 - \va{1}
+OK 1 - \va{1}
+OK 2 - \va{1}
+OK 0 - \va{2}
+OK 1 - \va{2}
+OK 2 - \va{2}
+OK 0 - \va{2}
+OK 1 - \va{2}
+OK 2 - \va{2}
+OK 0 - \va{2}
+OK 1 - \va{2}
+OK 2 - \va{2}
+OK 0 - \va{2}
+OK 1 - \va{2}
+OK 2 - \va{2}
+OK 0 - \va{2}
+OK 1 - \va{2}
+OK 2 - \va{2}
+OK 0 - \va{2}
+OK 1 - \va{2}
+OK 2 - \va{2}
+OK 0 - \vb{1}
+OK 1 - \vb{1}
+OK 2 - \vb{1}
+OK 0 - \vba{2}
+OK 1 - \vba{2}
+OK 2 - \vba{2}
+OK 0 - \vba{3}
+OK 1 - \vba{3}
+OK 2 - \vba{3}
+OK 0 - \v(ab){1}
+OK 1 - \v(ab){1}
+OK 2 - \v(ab){1}
+OK 0 - \v(ab){1}
+OK 1 - \v(ab){1}
+OK 2 - \v(ab){1}
+OK 0 - \v(ab){1}
+OK 1 - \v(ab){1}
+OK 2 - \v(ab){1}
+OK 0 - \v(ab){0,2}
+OK 1 - \v(ab){0,2}
+OK 2 - \v(ab){0,2}
+OK 0 - \v(ab){0,2}
+OK 1 - \v(ab){0,2}
+OK 2 - \v(ab){0,2}
+OK 0 - \v(ab){1,2}
+OK 1 - \v(ab){1,2}
+OK 2 - \v(ab){1,2}
+OK 0 - \v(ab){1,2}
+OK 1 - \v(ab){1,2}
+OK 2 - \v(ab){1,2}
+OK 0 - \v(ab){2,4}
+OK 1 - \v(ab){2,4}
+OK 2 - \v(ab){2,4}
+OK 0 - \v(ab){2,4}
+OK 1 - \v(ab){2,4}
+OK 2 - \v(ab){2,4}
+OK 0 - \v(ab){2}
+OK 1 - \v(ab){2}
+OK 2 - \v(ab){2}
+OK 0 - \v(ab){2}
+OK 1 - \v(ab){2}
+OK 2 - \v(ab){2}
+OK 0 - \v(ab){2}
+OK 1 - \v(ab){2}
+OK 2 - \v(ab){2}
+OK 0 - \v(ab){2}
+OK 1 - \v(ab){2}
+OK 2 - \v(ab){2}
+OK 0 - \v((ab){2}){2}
+OK 1 - \v((ab){2}){2}
+OK 2 - \v((ab){2}){2}
+OK 0 - \v((ab){2}){2}
+OK 1 - \v((ab){2}){2}
+OK 2 - \v((ab){2}){2}
+OK 0 - \v(a{1}){1}
+OK 1 - \v(a{1}){1}
+OK 2 - \v(a{1}){1}
+OK 0 - \v(a{2}){1}
+OK 1 - \v(a{2}){1}
+OK 2 - \v(a{2}){1}
+OK 0 - \v(a{2}){1}
+OK 1 - \v(a{2}){1}
+OK 2 - \v(a{2}){1}
+OK 0 - \v(a{2}){1}
+OK 1 - \v(a{2}){1}
+OK 2 - \v(a{2}){1}
+OK 0 - \v(a{1}){2}
+OK 1 - \v(a{1}){2}
+OK 2 - \v(a{1}){2}
+OK 0 - \v(a{1}){2}
+OK 1 - \v(a{1}){2}
+OK 2 - \v(a{1}){2}
+OK 0 - \v(a{2})+
+OK 1 - \v(a{2})+
+OK 2 - \v(a{2})+
+OK 0 - \v(a{2})+
+OK 1 - \v(a{2})+
+OK 2 - \v(a{2})+
+OK 0 - \v(a{2}){1}
+OK 1 - \v(a{2}){1}
+OK 2 - \v(a{2}){1}
+OK 0 - \v(a{1}){2}
+OK 1 - \v(a{1}){2}
+OK 2 - \v(a{1}){2}
+OK 0 - \v(a{1}){1}
+OK 1 - \v(a{1}){1}
+OK 2 - \v(a{1}){1}
+OK 0 - \v(a{2}){2}
+OK 1 - \v(a{2}){2}
+OK 2 - \v(a{2}){2}
+OK 0 - \v(a{2}){2}
+OK 1 - \v(a{2}){2}
+OK 2 - \v(a{2}){2}
+OK 0 - \v(a+){2}
+OK 1 - \v(a+){2}
+OK 2 - \v(a+){2}
+OK 0 - \v(a{3}){2}
+OK 1 - \v(a{3}){2}
+OK 2 - \v(a{3}){2}
+OK 0 - \v(a{1,2}){2}
+OK 1 - \v(a{1,2}){2}
+OK 2 - \v(a{1,2}){2}
+OK 0 - \v(a{1,3}){2}
+OK 1 - \v(a{1,3}){2}
+OK 2 - \v(a{1,3}){2}
+OK 0 - \v(a{1,3}){2}
+OK 1 - \v(a{1,3}){2}
+OK 2 - \v(a{1,3}){2}
+OK 0 - \v(a{1,3}){3}
+OK 1 - \v(a{1,3}){3}
+OK 2 - \v(a{1,3}){3}
+OK 0 - \v(a{1,2}){2}
+OK 1 - \v(a{1,2}){2}
+OK 2 - \v(a{1,2}){2}
+OK 0 - \v(a+)+
+OK 1 - \v(a+)+
+OK 2 - \v(a+)+
+OK 0 - \v(a+)+
+OK 1 - \v(a+)+
+OK 2 - \v(a+)+
+OK 0 - \v(a+){1,2}
+OK 1 - \v(a+){1,2}
+OK 2 - \v(a+){1,2}
+OK 0 - \v(a+)(a+)
+OK 1 - \v(a+)(a+)
+OK 2 - \v(a+)(a+)
+OK 0 - \v(a{3})+
+OK 1 - \v(a{3})+
+OK 2 - \v(a{3})+
+OK 0 - \v(a|b|c)+
+OK 1 - \v(a|b|c)+
+OK 2 - \v(a|b|c)+
+OK 0 - \v(a|b|c){2}
+OK 1 - \v(a|b|c){2}
+OK 2 - \v(a|b|c){2}
+OK 0 - \v(abc){2}
+OK 1 - \v(abc){2}
+OK 2 - \v(abc){2}
+OK 0 - \v(abc){2}
+OK 1 - \v(abc){2}
+OK 2 - \v(abc){2}
+OK 0 - a*
+OK 1 - a*
+OK 2 - a*
+OK 0 - \v(a*)+
+OK 1 - \v(a*)+
+OK 2 - \v(a*)+
+OK 0 - \v((ab)+)+
+OK 1 - \v((ab)+)+
+OK 2 - \v((ab)+)+
+OK 0 - \v(((ab)+)+)+
+OK 1 - \v(((ab)+)+)+
+OK 2 - \v(((ab)+)+)+
+OK 0 - \v(((ab)+)+)+
+OK 1 - \v(((ab)+)+)+
+OK 2 - \v(((ab)+)+)+
+OK 0 - \v(a{0,2})+
+OK 1 - \v(a{0,2})+
+OK 2 - \v(a{0,2})+
+OK 0 - \v(a*)+
+OK 1 - \v(a*)+
+OK 2 - \v(a*)+
+OK 0 - \v((a*)+)+
+OK 1 - \v((a*)+)+
+OK 2 - \v((a*)+)+
+OK 0 - \v((ab)*)+
+OK 1 - \v((ab)*)+
+OK 2 - \v((ab)*)+
+OK 0 - \va{1,3}
+OK 1 - \va{1,3}
+OK 2 - \va{1,3}
+OK 0 - \va{2,3}
+OK 1 - \va{2,3}
+OK 2 - \va{2,3}
+OK 0 - \v((ab)+|c*)+
+OK 1 - \v((ab)+|c*)+
+OK 2 - \v((ab)+|c*)+
+OK 0 - \v(a{2})|(b{3})
+OK 1 - \v(a{2})|(b{3})
+OK 2 - \v(a{2})|(b{3})
+OK 0 - \va{2}|b{2}
+OK 1 - \va{2}|b{2}
+OK 2 - \va{2}|b{2}
+OK 0 - \v(a)+|(c)+
+OK 1 - \v(a)+|(c)+
+OK 2 - \v(a)+|(c)+
+OK 0 - \vab{2,3}c
+OK 1 - \vab{2,3}c
+OK 2 - \vab{2,3}c
+OK 0 - \vab{2,3}c
+OK 1 - \vab{2,3}c
+OK 2 - \vab{2,3}c
+OK 0 - \vab{2,3}cd{2,3}e
+OK 1 - \vab{2,3}cd{2,3}e
+OK 2 - \vab{2,3}cd{2,3}e
+OK 0 - \va(bc){2}d
+OK 1 - \va(bc){2}d
+OK 2 - \va(bc){2}d
+OK 0 - \va*a{2}
+OK 1 - \va*a{2}
+OK 2 - \va*a{2}
+OK 0 - \va*a{2}
+OK 1 - \va*a{2}
+OK 2 - \va*a{2}
+OK 0 - \va*a{2}
+OK 1 - \va*a{2}
+OK 2 - \va*a{2}
+OK 0 - \va*a{2}
+OK 1 - \va*a{2}
+OK 2 - \va*a{2}
+OK 0 - \va*b*|a*c*
+OK 1 - \va*b*|a*c*
+OK 2 - \va*b*|a*c*
+OK 0 - \va{1}b{1}|a{1}b{1}
+OK 1 - \va{1}b{1}|a{1}b{1}
+OK 2 - \va{1}b{1}|a{1}b{1}
+OK 0 - \v(a)
+OK 1 - \v(a)
+OK 2 - \v(a)
+OK 0 - \v(a)(b)
+OK 1 - \v(a)(b)
+OK 2 - \v(a)(b)
+OK 0 - \v(ab)(b)(c)
+OK 1 - \v(ab)(b)(c)
+OK 2 - \v(ab)(b)(c)
+OK 0 - \v((a)(b))
+OK 1 - \v((a)(b))
+OK 2 - \v((a)(b))
+OK 0 - \v(a)|(b)
+OK 1 - \v(a)|(b)
+OK 2 - \v(a)|(b)
+OK 0 - \v(a*)+
+OK 1 - \v(a*)+
+OK 2 - \v(a*)+
+OK 0 - x
+OK 1 - x
+OK 2 - x
+OK 0 - ab
+OK 1 - ab
+OK 2 - ab
+OK 0 - ab
+OK 1 - ab
+OK 2 - ab
+OK 0 - ab
+OK 1 - ab
+OK 2 - ab
+OK 0 - x*
+OK 1 - x*
+OK 2 - x*
+OK 0 - x*
+OK 1 - x*
+OK 2 - x*
+OK 0 - x*
+OK 1 - x*
+OK 2 - x*
+OK 0 - x\+
+OK 1 - x\+
+OK 2 - x\+
+OK 0 - x\+
+OK 1 - x\+
+OK 2 - x\+
+OK 0 - x\+
+OK 1 - x\+
+OK 2 - x\+
+OK 0 - x\+
+OK 1 - x\+
+OK 2 - x\+
+OK 0 - x\=
+OK 1 - x\=
+OK 2 - x\=
+OK 0 - x\=
+OK 1 - x\=
+OK 2 - x\=
+OK 0 - x\=
+OK 1 - x\=
+OK 2 - x\=
+OK 0 - x\?
+OK 1 - x\?
+OK 2 - x\?
+OK 0 - x\?
+OK 1 - x\?
+OK 2 - x\?
+OK 0 - x\?
+OK 1 - x\?
+OK 2 - x\?
+OK 0 - a\{0,0}
+OK 1 - a\{0,0}
+OK 2 - a\{0,0}
+OK 0 - a\{0,1}
+OK 1 - a\{0,1}
+OK 2 - a\{0,1}
+OK 0 - a\{1,0}
+OK 1 - a\{1,0}
+OK 2 - a\{1,0}
+OK 0 - a\{3,6}
+OK 1 - a\{3,6}
+OK 2 - a\{3,6}
+OK 0 - a\{3,6}
+OK 1 - a\{3,6}
+OK 2 - a\{3,6}
+OK 0 - a\{3,6}
+OK 1 - a\{3,6}
+OK 2 - a\{3,6}
+OK 0 - a\{0}
+OK 1 - a\{0}
+OK 2 - a\{0}
+OK 0 - a\{2}
+OK 1 - a\{2}
+OK 2 - a\{2}
+OK 0 - a\{2}
+OK 1 - a\{2}
+OK 2 - a\{2}
+OK 0 - a\{2}
+OK 1 - a\{2}
+OK 2 - a\{2}
+OK 0 - a\{0,}
+OK 1 - a\{0,}
+OK 2 - a\{0,}
+OK 0 - a\{0,}
+OK 1 - a\{0,}
+OK 2 - a\{0,}
+OK 0 - a\{2,}
+OK 1 - a\{2,}
+OK 2 - a\{2,}
+OK 0 - a\{2,}
+OK 1 - a\{2,}
+OK 2 - a\{2,}
+OK 0 - a\{5,}
+OK 1 - a\{5,}
+OK 2 - a\{5,}
+OK 0 - a\{5,}
+OK 1 - a\{5,}
+OK 2 - a\{5,}
+OK 0 - a\{,0}
+OK 1 - a\{,0}
+OK 2 - a\{,0}
+OK 0 - a\{,5}
+OK 1 - a\{,5}
+OK 2 - a\{,5}
+OK 0 - a\{,5}
+OK 1 - a\{,5}
+OK 2 - a\{,5}
+OK 0 - ^*\{4,}$
+OK 1 - ^*\{4,}$
+OK 2 - ^*\{4,}$
+OK 0 - ^*\{4,}$
+OK 1 - ^*\{4,}$
+OK 2 - ^*\{4,}$
+OK 0 - ^*\{4,}$
+OK 1 - ^*\{4,}$
+OK 2 - ^*\{4,}$
+OK 0 - a\{}
+OK 1 - a\{}
+OK 2 - a\{}
+OK 0 - a\{}
+OK 1 - a\{}
+OK 2 - a\{}
+OK 0 - a\{-0,0}
+OK 1 - a\{-0,0}
+OK 2 - a\{-0,0}
+OK 0 - a\{-0,1}
+OK 1 - a\{-0,1}
+OK 2 - a\{-0,1}
+OK 0 - a\{-3,6}
+OK 1 - a\{-3,6}
+OK 2 - a\{-3,6}
+OK 0 - a\{-3,6}
+OK 1 - a\{-3,6}
+OK 2 - a\{-3,6}
+OK 0 - a\{-3,6}
+OK 1 - a\{-3,6}
+OK 2 - a\{-3,6}
+OK 0 - a\{-0}
+OK 1 - a\{-0}
+OK 2 - a\{-0}
+OK 0 - a\{-2}
+OK 1 - a\{-2}
+OK 2 - a\{-2}
+OK 0 - a\{-2}
+OK 1 - a\{-2}
+OK 2 - a\{-2}
+OK 0 - a\{-0,}
+OK 1 - a\{-0,}
+OK 2 - a\{-0,}
+OK 0 - a\{-0,}
+OK 1 - a\{-0,}
+OK 2 - a\{-0,}
+OK 0 - a\{-2,}
+OK 1 - a\{-2,}
+OK 2 - a\{-2,}
+OK 0 - a\{-2,}
+OK 1 - a\{-2,}
+OK 2 - a\{-2,}
+OK 0 - a\{-,0}
+OK 1 - a\{-,0}
+OK 2 - a\{-,0}
+OK 0 - a\{-,5}
+OK 1 - a\{-,5}
+OK 2 - a\{-,5}
+OK 0 - a\{-,5}
+OK 1 - a\{-,5}
+OK 2 - a\{-,5}
+OK 0 - a\{-}
+OK 1 - a\{-}
+OK 2 - a\{-}
+OK 0 - a\{-}
+OK 1 - a\{-}
+OK 2 - a\{-}
+OK 0 - \(abc\)*
+OK 1 - \(abc\)*
+OK 2 - \(abc\)*
+OK 0 - \(ab\)\+
+OK 1 - \(ab\)\+
+OK 2 - \(ab\)\+
+OK 0 - \(abaaaaa\)*cd
+OK 1 - \(abaaaaa\)*cd
+OK 2 - \(abaaaaa\)*cd
+OK 0 - \(test1\)\? \(test2\)\?
+OK 1 - \(test1\)\? \(test2\)\?
+OK 2 - \(test1\)\? \(test2\)\?
+OK 0 - \(test1\)\= \(test2\) \(test4443\)\=
+OK 1 - \(test1\)\= \(test2\) \(test4443\)\=
+OK 2 - \(test1\)\= \(test2\) \(test4443\)\=
+OK 0 - \(\(sub1\) hello \(sub 2\)\)
+OK 1 - \(\(sub1\) hello \(sub 2\)\)
+OK 2 - \(\(sub1\) hello \(sub 2\)\)
+OK 0 - \(\(\(yyxxzz\)\)\)
+OK 1 - \(\(\(yyxxzz\)\)\)
+OK 2 - \(\(\(yyxxzz\)\)\)
+OK 0 - \v((ab)+|c+)+
+OK 1 - \v((ab)+|c+)+
+OK 2 - \v((ab)+|c+)+
+OK 0 - \v((ab)|c*)+
+OK 1 - \v((ab)|c*)+
+OK 2 - \v((ab)|c*)+
+OK 0 - \v(a(c*)+b)+
+OK 1 - \v(a(c*)+b)+
+OK 2 - \v(a(c*)+b)+
+OK 0 - \v(a|b*)+
+OK 1 - \v(a|b*)+
+OK 2 - \v(a|b*)+
+OK 0 - \p*
+OK 1 - \p*
+OK 2 - \p*
+OK 0 - a\{-2,7}
+OK 1 - a\{-2,7}
+OK 2 - a\{-2,7}
+OK 0 - a\{-2,7}x
+OK 1 - a\{-2,7}x
+OK 2 - a\{-2,7}x
+OK 0 - a\{2,7}
+OK 1 - a\{2,7}
+OK 2 - a\{2,7}
+OK 0 - a\{2,7}x
+OK 1 - a\{2,7}x
+OK 2 - a\{2,7}x
+OK 0 - \vx(.{-,8})yz(.*)
+OK 1 - \vx(.{-,8})yz(.*)
+OK 2 - \vx(.{-,8})yz(.*)
+OK 0 - \vx(.*)yz(.*)
+OK 1 - \vx(.*)yz(.*)
+OK 2 - \vx(.*)yz(.*)
+OK 0 - \v(a{1,2}){-2,3}
+OK 1 - \v(a{1,2}){-2,3}
+OK 2 - \v(a{1,2}){-2,3}
+OK 0 - \v(a{-1,3})+
+OK 1 - \v(a{-1,3})+
+OK 2 - \v(a{-1,3})+
+OK 0 - ^\s\{-}\zs\( x\|x$\)
+OK 1 - ^\s\{-}\zs\( x\|x$\)
+OK 2 - ^\s\{-}\zs\( x\|x$\)
+OK 0 - ^\s\{-}\zs\(x\| x$\)
+OK 1 - ^\s\{-}\zs\(x\| x$\)
+OK 2 - ^\s\{-}\zs\(x\| x$\)
+OK 0 - ^\s\{-}\ze\(x\| x$\)
+OK 1 - ^\s\{-}\ze\(x\| x$\)
+OK 2 - ^\s\{-}\ze\(x\| x$\)
+OK 0 - ^\(\s\{-}\)\(x\| x$\)
+OK 1 - ^\(\s\{-}\)\(x\| x$\)
+OK 2 - ^\(\s\{-}\)\(x\| x$\)
+OK 0 - \d\+e\d\d
+OK 1 - \d\+e\d\d
+OK 2 - \d\+e\d\d
+OK 0 - \v[a]
+OK 1 - \v[a]
+OK 2 - \v[a]
+OK 0 - a[bcd]
+OK 1 - a[bcd]
+OK 2 - a[bcd]
+OK 0 - a[b-d]
+OK 1 - a[b-d]
+OK 2 - a[b-d]
+OK 0 - [a-d][e-f][x-x]d
+OK 1 - [a-d][e-f][x-x]d
+OK 2 - [a-d][e-f][x-x]d
+OK 0 - \v[[:alpha:]]+
+OK 1 - \v[[:alpha:]]+
+OK 2 - \v[[:alpha:]]+
+OK 0 - [[:alpha:]\+]
+OK 1 - [[:alpha:]\+]
+OK 2 - [[:alpha:]\+]
+OK 0 - [^abc]\+
+OK 1 - [^abc]\+
+OK 2 - [^abc]\+
+OK 0 - [^abc]
+OK 1 - [^abc]
+OK 2 - [^abc]
+OK 0 - [^abc]\+
+OK 1 - [^abc]\+
+OK 2 - [^abc]\+
+OK 0 - [^a-d]\+
+OK 1 - [^a-d]\+
+OK 2 - [^a-d]\+
+OK 0 - [a-f]*
+OK 1 - [a-f]*
+OK 2 - [a-f]*
+OK 0 - [a-f]*
+OK 1 - [a-f]*
+OK 2 - [a-f]*
+OK 0 - [^a-f]\+
+OK 1 - [^a-f]\+
+OK 2 - [^a-f]\+
+OK 0 - [a-c]\{-3,6}
+OK 1 - [a-c]\{-3,6}
+OK 2 - [a-c]\{-3,6}
+OK 0 - [^[:alpha:]]\+
+OK 1 - [^[:alpha:]]\+
+OK 2 - [^[:alpha:]]\+
+OK 0 - [-a]
+OK 1 - [-a]
+OK 2 - [-a]
+OK 0 - [a-]
+OK 1 - [a-]
+OK 2 - [a-]
+OK 0 - [a-f]*\c
+OK 1 - [a-f]*\c
+OK 2 - [a-f]*\c
+OK 0 - [abc][xyz]\c
+OK 1 - [abc][xyz]\c
+OK 2 - [abc][xyz]\c
+OK 0 - [-./[:alnum:]_~]\+
+OK 1 - [-./[:alnum:]_~]\+
+OK 2 - [-./[:alnum:]_~]\+
+OK 0 - [\]\^\-\\]\+
+OK 1 - [\]\^\-\\]\+
+OK 2 - [\]\^\-\\]\+
+OK 0 - [[.a.]]\+
+OK 1 - [[.a.]]\+
+OK 2 - [[.a.]]\+
+OK 0 - abc[0-9]*ddd
+OK 1 - abc[0-9]*ddd
+OK 2 - abc[0-9]*ddd
+OK 0 - abc[0-9]*ddd
+OK 1 - abc[0-9]*ddd
+OK 2 - abc[0-9]*ddd
+OK 0 - \_[0-9]\+
+OK 1 - \_[0-9]\+
+OK 2 - \_[0-9]\+
+OK 0 - [0-9\n]\+
+OK 1 - [0-9\n]\+
+OK 2 - [0-9\n]\+
+OK 0 - \_[0-9]\+
+OK 1 - \_[0-9]\+
+OK 2 - \_[0-9]\+
+OK 0 - \_f
+OK 1 - \_f
+OK 2 - \_f
+OK 0 - \_f\+
+OK 1 - \_f\+
+OK 2 - \_f\+
+OK 0 - [0-9A-Za-z-_.]\+
+OK 1 - [0-9A-Za-z-_.]\+
+OK 2 - [0-9A-Za-z-_.]\+
+OK 0 - ^a.
+OK 1 - ^a.
+OK 2 - ^a.
+OK 0 - ^a.
+OK 1 - ^a.
+OK 2 - ^a.
+OK 0 - .a$
+OK 1 - .a$
+OK 2 - .a$
+OK 0 - .a$
+OK 1 - .a$
+OK 2 - .a$
+OK 0 - \%^a.
+OK 1 - \%^a.
+OK 2 - \%^a.
+OK 0 - \%^a
+OK 1 - \%^a
+OK 2 - \%^a
+OK 0 - .a\%$
+OK 1 - .a\%$
+OK 2 - .a\%$
+OK 0 - .a\%$
+OK 1 - .a\%$
+OK 2 - .a\%$
+OK 0 - [0-7]\+
+OK 1 - [0-7]\+
+OK 2 - [0-7]\+
+OK 0 - [^0-7]\+
+OK 1 - [^0-7]\+
+OK 2 - [^0-7]\+
+OK 0 - [0-9]\+
+OK 1 - [0-9]\+
+OK 2 - [0-9]\+
+OK 0 - [^0-9]\+
+OK 1 - [^0-9]\+
+OK 2 - [^0-9]\+
+OK 0 - [0-9a-fA-F]\+
+OK 1 - [0-9a-fA-F]\+
+OK 2 - [0-9a-fA-F]\+
+OK 0 - [^0-9A-Fa-f]\+
+OK 1 - [^0-9A-Fa-f]\+
+OK 2 - [^0-9A-Fa-f]\+
+OK 0 - [a-z_A-Z0-9]\+
+OK 1 - [a-z_A-Z0-9]\+
+OK 2 - [a-z_A-Z0-9]\+
+OK 0 - [^a-z_A-Z0-9]\+
+OK 1 - [^a-z_A-Z0-9]\+
+OK 2 - [^a-z_A-Z0-9]\+
+OK 0 - [a-z_A-Z]\+
+OK 1 - [a-z_A-Z]\+
+OK 2 - [a-z_A-Z]\+
+OK 0 - [^a-z_A-Z]\+
+OK 1 - [^a-z_A-Z]\+
+OK 2 - [^a-z_A-Z]\+
+OK 0 - [a-z]\+
+OK 1 - [a-z]\+
+OK 2 - [a-z]\+
+OK 0 - [a-z]\+
+OK 1 - [a-z]\+
+OK 2 - [a-z]\+
+OK 0 - [^a-z]\+
+OK 1 - [^a-z]\+
+OK 2 - [^a-z]\+
+OK 0 - [^a-z]\+
+OK 1 - [^a-z]\+
+OK 2 - [^a-z]\+
+OK 0 - [a-zA-Z]\+
+OK 1 - [a-zA-Z]\+
+OK 2 - [a-zA-Z]\+
+OK 0 - [^a-zA-Z]\+
+OK 1 - [^a-zA-Z]\+
+OK 2 - [^a-zA-Z]\+
+OK 0 - [A-Z]\+
+OK 1 - [A-Z]\+
+OK 2 - [A-Z]\+
+OK 0 - [^A-Z]\+
+OK 1 - [^A-Z]\+
+OK 2 - [^A-Z]\+
+OK 0 - [a-z]\+\c
+OK 1 - [a-z]\+\c
+OK 2 - [a-z]\+\c
+OK 0 - [A-Z]\+\c
+OK 1 - [A-Z]\+\c
+OK 2 - [A-Z]\+\c
+OK 0 - \c[^a-z]\+
+OK 1 - \c[^a-z]\+
+OK 2 - \c[^a-z]\+
+OK 0 - \c[^A-Z]\+
+OK 1 - \c[^A-Z]\+
+OK 2 - \c[^A-Z]\+
+OK 0 - \C[^A-Z]\+
+OK 1 - \C[^A-Z]\+
+OK 2 - \C[^A-Z]\+
+OK 0 - xx \ze test
+OK 1 - xx \ze test
+OK 2 - xx \ze test
+OK 0 - abc\zeend
+OK 1 - abc\zeend
+OK 2 - abc\zeend
+OK 0 - aa\zebb\|aaxx
+OK 1 - aa\zebb\|aaxx
+OK 2 - aa\zebb\|aaxx
+OK 0 - aa\zebb\|aaxx
+OK 1 - aa\zebb\|aaxx
+OK 2 - aa\zebb\|aaxx
+OK 0 - aabb\|aa\zebb
+OK 1 - aabb\|aa\zebb
+OK 2 - aabb\|aa\zebb
+OK 0 - aa\zebb\|aaebb
+OK 1 - aa\zebb\|aaebb
+OK 2 - aa\zebb\|aaebb
+OK 0 - abc\zsdd
+OK 1 - abc\zsdd
+OK 2 - abc\zsdd
+OK 0 - aa \zsax
+OK 1 - aa \zsax
+OK 2 - aa \zsax
+OK 0 - abc \zsmatch\ze abc
+OK 1 - abc \zsmatch\ze abc
+OK 2 - abc \zsmatch\ze abc
+OK 0 - \v(a \zsif .*){2}
+OK 1 - \v(a \zsif .*){2}
+OK 2 - \v(a \zsif .*){2}
+OK 0 - \>\zs.
+OK 1 - \>\zs.
+OK 2 - \>\zs.
+OK 0 - \s\+\ze\[/\|\s\zs\s\+
+OK 1 - \s\+\ze\[/\|\s\zs\s\+
+OK 2 - \s\+\ze\[/\|\s\zs\s\+
+OK 0 - abc\@=
+OK 1 - abc\@=
+OK 2 - abc\@=
+OK 0 - abc\@=cd
+OK 1 - abc\@=cd
+OK 2 - abc\@=cd
+OK 0 - abc\@=
+OK 1 - abc\@=
+OK 2 - abc\@=
+OK 0 - abcd\@=e
+OK 1 - abcd\@=e
+OK 2 - abcd\@=e
+OK 0 - abcd\@=e
+OK 1 - abcd\@=e
+OK 2 - abcd\@=e
+OK 0 - \v(abc)@=..
+OK 1 - \v(abc)@=..
+OK 2 - \v(abc)@=..
+OK 0 - \(.*John\)\@=.*Bob
+OK 1 - \(.*John\)\@=.*Bob
+OK 2 - \(.*John\)\@=.*Bob
+OK 0 - \(John.*\)\@=.*Bob
+OK 1 - \(John.*\)\@=.*Bob
+OK 2 - \(John.*\)\@=.*Bob
+OK 0 - \<\S\+\())\)\@=
+OK 1 - \<\S\+\())\)\@=
+OK 2 - \<\S\+\())\)\@=
+OK 0 - .*John\&.*Bob
+OK 1 - .*John\&.*Bob
+OK 2 - .*John\&.*Bob
+OK 0 - .*John\&.*Bob
+OK 1 - .*John\&.*Bob
+OK 2 - .*John\&.*Bob
+OK 0 - \v(test1)@=.*yep
+OK 1 - \v(test1)@=.*yep
+OK 2 - \v(test1)@=.*yep
+OK 0 - foo\(bar\)\@!
+OK 1 - foo\(bar\)\@!
+OK 2 - foo\(bar\)\@!
+OK 0 - foo\(bar\)\@!
+OK 1 - foo\(bar\)\@!
+OK 2 - foo\(bar\)\@!
+OK 0 - if \(\(then\)\@!.\)*$
+OK 1 - if \(\(then\)\@!.\)*$
+OK 2 - if \(\(then\)\@!.\)*$
+OK 0 - if \(\(then\)\@!.\)*$
+OK 1 - if \(\(then\)\@!.\)*$
+OK 2 - if \(\(then\)\@!.\)*$
+OK 0 - \(foo\)\@!bar
+OK 1 - \(foo\)\@!bar
+OK 2 - \(foo\)\@!bar
+OK 0 - \(foo\)\@!...bar
+OK 1 - \(foo\)\@!...bar
+OK 2 - \(foo\)\@!...bar
+OK 0 - ^\%(.*bar\)\@!.*\zsfoo
+OK 1 - ^\%(.*bar\)\@!.*\zsfoo
+OK 2 - ^\%(.*bar\)\@!.*\zsfoo
+OK 0 - ^\%(.*bar\)\@!.*\zsfoo
+OK 1 - ^\%(.*bar\)\@!.*\zsfoo
+OK 2 - ^\%(.*bar\)\@!.*\zsfoo
+OK 0 - ^\%(.*bar\)\@!.*\zsfoo
+OK 1 - ^\%(.*bar\)\@!.*\zsfoo
+OK 2 - ^\%(.*bar\)\@!.*\zsfoo
+OK 0 - [ ]\@!\p\%([ ]\@!\p\)*:
+OK 1 - [ ]\@!\p\%([ ]\@!\p\)*:
+OK 2 - [ ]\@!\p\%([ ]\@!\p\)*:
+OK 0 - [ ]\@!\p\([ ]\@!\p\)*:
+OK 1 - [ ]\@!\p\([ ]\@!\p\)*:
+OK 2 - [ ]\@!\p\([ ]\@!\p\)*:
+OK 0 - m\k\+_\@=\%(_\@!\k\)\@<=\k\+e
+OK 1 - m\k\+_\@=\%(_\@!\k\)\@<=\k\+e
+OK 2 - m\k\+_\@=\%(_\@!\k\)\@<=\k\+e
+OK 0 - \%(\U\@<=S\k*\|S\l\)R
+OK 1 - \%(\U\@<=S\k*\|S\l\)R
+OK 2 - \%(\U\@<=S\k*\|S\l\)R
+OK 0 - [[:alpha:]]\{-2,6}
+OK 1 - [[:alpha:]]\{-2,6}
+OK 2 - [[:alpha:]]\{-2,6}
+OK 0 -
+OK 1 -
+OK 2 -
+OK 0 - \v(())
+OK 1 - \v(())
+OK 2 - \v(())
+OK 0 - \v%(ab(xyz)c)
+OK 1 - \v%(ab(xyz)c)
+OK 2 - \v%(ab(xyz)c)
+OK 0 - \v(test|)empty
+OK 1 - \v(test|)empty
+OK 2 - \v(test|)empty
+OK 0 - \v(a|aa)(a|aa)
+OK 1 - \v(a|aa)(a|aa)
+OK 2 - \v(a|aa)(a|aa)
+OK 0 - \%d32
+OK 1 - \%d32
+OK 2 - \%d32
+OK 0 - \%o40
+OK 1 - \%o40
+OK 2 - \%o40
+OK 0 - \%x20
+OK 1 - \%x20
+OK 2 - \%x20
+OK 0 - \%u0020
+OK 1 - \%u0020
+OK 2 - \%u0020
+OK 0 - \%U00000020
+OK 1 - \%U00000020
+OK 2 - \%U00000020
+OK 0 - \%d0
+OK 1 - \%d0
+OK 2 - \%d0
+OK 0 - foo\%[bar]
+OK 1 - foo\%[bar]
+OK 2 - foo\%[bar]
+OK 0 - foo\%[bar]
+OK 1 - foo\%[bar]
+OK 2 - foo\%[bar]
+OK 0 - foo\%[bar]
+OK 1 - foo\%[bar]
+OK 2 - foo\%[bar]
+OK 0 - foo\%[bar]
+OK 1 - foo\%[bar]
+OK 2 - foo\%[bar]
+OK 0 - foo\%[bar]
+OK 1 - foo\%[bar]
+OK 2 - foo\%[bar]
+OK 0 - foo\%[bar]
+OK 1 - foo\%[bar]
+OK 2 - foo\%[bar]
+OK 0 - foo\%[bar]x
+OK 1 - foo\%[bar]x
+OK 2 - foo\%[bar]x
+OK 0 - foo\%[bar]x
+OK 1 - foo\%[bar]x
+OK 2 - foo\%[bar]x
+OK 0 - \%[bar]x
+OK 1 - \%[bar]x
+OK 2 - \%[bar]x
+OK 0 - \%[bar]x
+OK 1 - \%[bar]x
+OK 2 - \%[bar]x
+OK 0 - \%[bar]x
+OK 1 - \%[bar]x
+OK 2 - \%[bar]x
+OK 0 - b\%[[ao]r]
+OK 1 - b\%[[ao]r]
+OK 2 - b\%[[ao]r]
+OK 0 - b\%[[]]r]
+OK 1 - b\%[[]]r]
+OK 2 - b\%[[]]r]
+OK 0 - @\%[\w\-]*
+OK 1 - @\%[\w\-]*
+OK 2 - @\%[\w\-]*
+OK 0 - goo\|go
+OK 1 - goo\|go
+OK 2 - goo\|go
+OK 0 - \<goo\|\<go
+OK 1 - \<goo\|\<go
+OK 2 - \<goo\|\<go
+OK 0 - \<goo\|go
+OK 1 - \<goo\|go
+OK 2 - \<goo\|go
+OK 0 - \(\i\+\) \1
+OK 1 - \(\i\+\) \1
+OK 2 - \(\i\+\) \1
+OK 0 - \(\i\+\) \1
+OK 1 - \(\i\+\) \1
+OK 2 - \(\i\+\) \1
+OK 0 - \(a\)\(b\)\(c\)\(dd\)\(e\)\(f\)\(g\)\(h\)\(i\)\1\2\3\4\5\6\7\8\9
+OK 1 - \(a\)\(b\)\(c\)\(dd\)\(e\)\(f\)\(g\)\(h\)\(i\)\1\2\3\4\5\6\7\8\9
+OK 2 - \(a\)\(b\)\(c\)\(dd\)\(e\)\(f\)\(g\)\(h\)\(i\)\1\2\3\4\5\6\7\8\9
+OK 0 - \(\d*\)a \1b
+OK 1 - \(\d*\)a \1b
+OK 2 - \(\d*\)a \1b
+OK 0 - ^.\(.\).\_..\1.
+OK 1 - ^.\(.\).\_..\1.
+OK 2 - ^.\(.\).\_..\1.
+OK 0 - ^.*\.\(.*\)/.\+\(\1\)\@<!$
+OK 1 - ^.*\.\(.*\)/.\+\(\1\)\@<!$
+OK 2 - ^.*\.\(.*\)/.\+\(\1\)\@<!$
+OK 0 - ^.*\.\(.*\)/.\+\(\1\)\@<!$
+OK 1 - ^.*\.\(.*\)/.\+\(\1\)\@<!$
+OK 2 - ^.*\.\(.*\)/.\+\(\1\)\@<!$
+OK 0 - ^.*\.\(.*\)/.\+\(\1\)\@<=$
+OK 1 - ^.*\.\(.*\)/.\+\(\1\)\@<=$
+OK 2 - ^.*\.\(.*\)/.\+\(\1\)\@<=$
+OK 0 - \\\@<!\${\(\d\+\%(:.\{-}\)\?\\\@<!\)}
+OK 1 - \\\@<!\${\(\d\+\%(:.\{-}\)\?\\\@<!\)}
+OK 2 - \\\@<!\${\(\d\+\%(:.\{-}\)\?\\\@<!\)}
+OK 0 - ^\(a*\)\1$
+OK 1 - ^\(a*\)\1$
+OK 2 - ^\(a*\)\1$
+OK 0 - ^\(a\{-2,}\)\1\+$
+OK 1 - ^\(a\{-2,}\)\1\+$
+OK 2 - ^\(a\{-2,}\)\1\+$
+OK 0 - <\@<=span.
+OK 1 - <\@<=span.
+OK 2 - <\@<=span.
+OK 0 - <\@1<=span.
+OK 1 - <\@1<=span.
+OK 2 - <\@1<=span.
+OK 0 - <\@2<=span.
+OK 1 - <\@2<=span.
+OK 2 - <\@2<=span.
+OK 0 - \(<<\)\@<=span.
+OK 1 - \(<<\)\@<=span.
+OK 2 - \(<<\)\@<=span.
+OK 0 - \(<<\)\@1<=span.
+OK 1 - \(<<\)\@1<=span.
+OK 2 - \(<<\)\@1<=span.
+OK 0 - \(<<\)\@2<=span.
+OK 1 - \(<<\)\@2<=span.
+OK 2 - \(<<\)\@2<=span.
+OK 0 - \(foo\)\@<!bar.
+OK 1 - \(foo\)\@<!bar.
+OK 2 - \(foo\)\@<!bar.
+OK 0 - \v\C%(<Last Changed:\s+)@<=.*$
+OK 1 - \v\C%(<Last Changed:\s+)@<=.*$
+OK 2 - \v\C%(<Last Changed:\s+)@<=.*$
+OK 0 - \v\C%(<Last Changed:\s+)@<=.*$
+OK 1 - \v\C%(<Last Changed:\s+)@<=.*$
+OK 2 - \v\C%(<Last Changed:\s+)@<=.*$
+OK 0 - \(foo\)\@<=\>
+OK 1 - \(foo\)\@<=\>
+OK 2 - \(foo\)\@<=\>
+OK 0 - \(foo\)\@<=\>
+OK 1 - \(foo\)\@<=\>
+OK 2 - \(foo\)\@<=\>
+OK 0 - \(foo\)\@<=.*
+OK 1 - \(foo\)\@<=.*
+OK 2 - \(foo\)\@<=.*
+OK 0 - \(r\@<=\|\w\@<!\)\/
+OK 1 - \(r\@<=\|\w\@<!\)\/
+OK 2 - \(r\@<=\|\w\@<!\)\/
+OK 0 - ^[a-z]\+\ze \&\(asdf\)\@<!
+OK 1 - ^[a-z]\+\ze \&\(asdf\)\@<!
+OK 2 - ^[a-z]\+\ze \&\(asdf\)\@<!
+OK 0 - \(a*\)\@>a
+OK 1 - \(a*\)\@>a
+OK 2 - \(a*\)\@>a
+OK 0 - \(a*\)\@>b
+OK 1 - \(a*\)\@>b
+OK 2 - \(a*\)\@>b
+OK 0 - ^\(.\{-}b\)\@>.
+OK 1 - ^\(.\{-}b\)\@>.
+OK 2 - ^\(.\{-}b\)\@>.
+OK 0 - \(.\{-}\)\(\)\@>$
+OK 1 - \(.\{-}\)\(\)\@>$
+OK 2 - \(.\{-}\)\(\)\@>$
+OK 0 - \(a*\)\@>a\|a\+
+OK 2 - \(a*\)\@>a\|a\+
+OK 0 - \_[^8-9]\+
+OK 1 - \_[^8-9]\+
+OK 2 - \_[^8-9]\+
+OK 0 - \_[^a]\+
+OK 1 - \_[^a]\+
+OK 2 - \_[^a]\+
+OK 0 - [0-9a-zA-Z]\{8}-\([0-9a-zA-Z]\{4}-\)\{3}[0-9a-zA-Z]\{12}
+OK 1 - [0-9a-zA-Z]\{8}-\([0-9a-zA-Z]\{4}-\)\{3}[0-9a-zA-Z]\{12}
+OK 2 - [0-9a-zA-Z]\{8}-\([0-9a-zA-Z]\{4}-\)\{3}[0-9a-zA-Z]\{12}
+OK 0 - ^\%(\%(^\s*#\s*if\>\|#\s*if\)\)\(\%>1c.*$\)\@=
+OK 1 - ^\%(\%(^\s*#\s*if\>\|#\s*if\)\)\(\%>1c.*$\)\@=
+OK 2 - ^\%(\%(^\s*#\s*if\>\|#\s*if\)\)\(\%>1c.*$\)\@=
+OK 0 - \%>70vGesamt
+OK 1 - \%>70vGesamt
+OK 2 - \%>70vGesamt
+multi-line tests
+OK 0 - ^.\(.\).\_..\1.
+OK 1 - ^.\(.\).\_..\1.
+OK 2 - ^.\(.\).\_..\1.
+OK 0 - \v.*\/(.*)\n.*\/\1$
+OK 1 - \v.*\/(.*)\n.*\/\1$
+OK 2 - \v.*\/(.*)\n.*\/\1$
+OK 0 - \S.*\nx
+OK 1 - \S.*\nx
+OK 2 - \S.*\nx
+OK 0 - \<\(\(25\_[0-5]\|2\_[0-4]\_[0-9]\|\_[01]\?\_[0-9]\_[0-9]\?\)\.\)\{3\}\(25\_[0-5]\|2\_[0-4]\_[0-9]\|\_[01]\?\_[0-9]\_[0-9]\?\)\>
+OK 1 - \<\(\(25\_[0-5]\|2\_[0-4]\_[0-9]\|\_[01]\?\_[0-9]\_[0-9]\?\)\.\)\{3\}\(25\_[0-5]\|2\_[0-4]\_[0-9]\|\_[01]\?\_[0-9]\_[0-9]\?\)\>
+OK 2 - \<\(\(25\_[0-5]\|2\_[0-4]\_[0-9]\|\_[01]\?\_[0-9]\_[0-9]\?\)\.\)\{3\}\(25\_[0-5]\|2\_[0-4]\_[0-9]\|\_[01]\?\_[0-9]\_[0-9]\?\)\>
+OK 0 - a\n^b$\n^c
+OK 1 - a\n^b$\n^c
+OK 2 - a\n^b$\n^c
+OK 0 - \(^.\+\n\)\1
+OK 1 - \(^.\+\n\)\1
+OK 2 - \(^.\+\n\)\1
+
+<T="5">Ta 5</Title>
+<T="7">Ac 7</Title>
+
+xxstart3
+
+thexE thE thExethe
+AndAxAnd AndAxAnd
+oooxOfOr fOrOxooo
+oooxOfOr fOrOxooo
+
+asdfhereasdf
+asdfagainasdf
+
+-0-
+ffo
+bob
+__ooooo
+koooo__
+moooooo
+ f__
+ab!babababababfoo
+ba!ab##abab?bafoo
+**!*****_
+ ! xxx?xxxxxxxx xxxx xxxxxx xxxxxxx x xxxxxxxxx xx xxxxxx xxxxxx xxxxx xxxxxxx xx xxxx xxxxxxxx xxxx xxxxxxxxxxx xxx xxxxxxx xxxxxxxxx xx xxxxxx xx xxxxxxx xxxxxxxxxxxxxxxx xxxxxxxxx xxx xxxxxxxx xxxxxxxxx xxxx xxx xxxx xxx xxx xxxxx xxxxxxxxxxxx xxxx xxxxxxxxx xxxxxxxxxxx xx xxxxx xxx xxxxxxxx xxxxxx xxx xxx xxxxxxxxx xxxxxxx x xxxxxxxxx xx xxxxxx xxxxxxx xxxxxxxxxxxxxxxxxx xxxxxxx xxxxxxx xxx xxx xxxxxxxx xxxxxxx xxxx xxx xxxxxx xxxxx xxxxx xx xxxxxx xxxxxxx xxx xxxxxxxxxxxx xxxx xxxxxxxxx xxxxxx xxxxxx xxxxx xxx xxxxxxx xxxxxxxxxxxxxxxx xxxxxxxxx xxxxxxxxxx xxxx xx xxxxxxxx xxx xxxxxxxxxxx xxxxx
+-1-
+ffo
+bob
+__ooooo
+koooo__
+moooooo
+ f__
+ab!babababababfoo
+ba!ab##abab?bafoo
+**!*****_
+ ! xxx?xxxxxxxx xxxx xxxxxx xxxxxxx x xxxxxxxxx xx xxxxxx xxxxxx xxxxx xxxxxxx xx xxxx xxxxxxxx xxxx xxxxxxxxxxx xxx xxxxxxx xxxxxxxxx xx xxxxxx xx xxxxxxx xxxxxxxxxxxxxxxx xxxxxxxxx xxx xxxxxxxx xxxxxxxxx xxxx xxx xxxx xxx xxx xxxxx xxxxxxxxxxxx xxxx xxxxxxxxx xxxxxxxxxxx xx xxxxx xxx xxxxxxxx xxxxxx xxx xxx xxxxxxxxx xxxxxxx x xxxxxxxxx xx xxxxxx xxxxxxx xxxxxxxxxxxxxxxxxx xxxxxxx xxxxxxx xxx xxx xxxxxxxx xxxxxxx xxxx xxx xxxxxx xxxxx xxxxx xx xxxxxx xxxxxxx xxx xxxxxxxxxxxx xxxx xxxxxxxxx xxxxxx xxxxxx xxxxx xxx xxxxxxx xxxxxxxxxxxxxxxx xxxxxxxxx xxxxxxxxxx xxxx xx xxxxxxxx xxx xxxxxxxxxxx xxxxx
+-2-
+ffo
+bob
+__ooooo
+koooo__
+moooooo
+ f__
+ab!babababababfoo
+ba!ab##abab?bafoo
+**!*****_
+ ! xxx?xxxxxxxx xxxx xxxxxx xxxxxxx x xxxxxxxxx xx xxxxxx xxxxxx xxxxx xxxxxxx xx xxxx xxxxxxxx xxxx xxxxxxxxxxx xxx xxxxxxx xxxxxxxxx xx xxxxxx xx xxxxxxx xxxxxxxxxxxxxxxx xxxxxxxxx xxx xxxxxxxx xxxxxxxxx xxxx xxx xxxx xxx xxx xxxxx xxxxxxxxxxxx xxxx xxxxxxxxx xxxxxxxxxxx xx xxxxx xxx xxxxxxxx xxxxxx xxx xxx xxxxxxxxx xxxxxxx x xxxxxxxxx xx xxxxxx xxxxxxx xxxxxxxxxxxxxxxxxx xxxxxxx xxxxxxx xxx xxx xxxxxxxx xxxxxxx xxxx xxx xxxxxx xxxxx xxxxx xx xxxxxx xxxxxxx xxx xxxxxxxxxxxx xxxx xxxxxxxxx xxxxxx xxxxxx xxxxx xxx xxxxxxx xxxxxxxxxxxxxxxx xxxxxxxxx xxxxxxxxxx xxxx xx xxxxxxxx xxx xxxxxxxxxxx xxxxx
+Test
+Test END
+EN
+E
+E888 detected for \ze*
+E888 detected for \zs*
diff --git a/src/testdir/test69.in b/src/testdir/test69.in
new file mode 100644
index 0000000..2510c12
--- /dev/null
+++ b/src/testdir/test69.in
@@ -0,0 +1,192 @@
+Test for multi-byte text formatting.
+Also test, that 'mps' with multibyte chars works.
+And test "ra" on multi-byte characters.
+Also test byteidx() and byteidxcomp()
+
+STARTTEST
+:so mbyte.vim
+:set encoding=utf-8
+ENDTEST
+
+Results of test69:
+
+STARTTEST
+/^{/+1
+:set tw=2 fo=t
+gqgqjgqgqo
+XYZ
+abc XYZ
+ENDTEST
+
+{
+XYZ
+abc XYZ
+}
+
+STARTTEST
+/^{/+1
+:set tw=1 fo=tm
+gqgqjgqgqjgqgqjgqgqjgqgqo
+X
+Xa
+X a
+XY
+X Y
+ENDTEST
+
+{
+X
+Xa
+X a
+XY
+X Y
+}
+
+STARTTEST
+/^{/+1
+:set tw=2 fo=tm
+gqgqjgqgqjgqgqjgqgqjgqgqjgqgqjgqgqjgqgqjgqgqjgqgqo
+X
+Xa
+X a
+XY
+X Y
+aX
+abX
+abcX
+abX c
+abXY
+ENDTEST
+
+{
+X
+Xa
+X a
+XY
+X Y
+aX
+abX
+abcX
+abX c
+abXY
+}
+
+STARTTEST
+/^{/+1
+:set ai tw=2 fo=tm
+gqgqjgqgqo
+X
+Xa
+ENDTEST
+
+{
+ X
+ Xa
+}
+
+STARTTEST
+/^{/+1
+:set noai tw=2 fo=tm
+gqgqjgqgqo
+ X
+ Xa
+ENDTEST
+
+{
+ X
+ Xa
+}
+
+STARTTEST
+/^{/+1
+:set tw=2 fo=cqm comments=n:X
+gqgqjgqgqjgqgqjgqgqjgqgqjgqgqjgqgqjgqgqjgqgqjgqgqo
+X
+Xa
+XaY
+XY
+XYZ
+X Y
+X YZ
+XX
+XXa
+XXY
+ENDTEST
+
+{
+X
+Xa
+XaY
+XY
+XYZ
+X Y
+X YZ
+XX
+XXa
+XXY
+}
+
+STARTTEST
+/^{/+1
+:set tw=2 fo=tm
+RXa
+ENDTEST
+
+{
+
+}
+
+STARTTEST
+/^{/+1
+:set mps+=u2018:u2019
+d%
+ENDTEST
+
+{
+‘ two three ’ four
+}
+STARTTEST
+/^ra test
+jVjra
+ENDTEST
+
+ra test
+ï½bbï½
+ï½ï½b
+
+STARTTEST
+:set whichwrap+=h
+/^x
+dh
+:set whichwrap-=h
+ENDTEST
+
+á
+x
+
+STARTTEST
+:let a = '.é.' " one char of two bytes
+:let b = '.eÌ.' " normal e with composing char
+/^byteidx
+:put =string([byteidx(a, 0), byteidx(a, 1), byteidx(a, 2), byteidx(a, 3), byteidx(a, 4)])
+:put =string([byteidx(b, 0), byteidx(b, 1), byteidx(b, 2), byteidx(b, 3), byteidx(b, 4)])
+/^byteidxcomp
+:put =string([byteidxcomp(a, 0), byteidxcomp(a, 1), byteidxcomp(a, 2), byteidxcomp(a, 3), byteidxcomp(a, 4)])
+:let b = '.eÌ.'
+:put =string([byteidxcomp(b, 0), byteidxcomp(b, 1), byteidxcomp(b, 2), byteidxcomp(b, 3), byteidxcomp(b, 4), byteidxcomp(b, 5)])
+ENDTEST
+
+byteidx
+byteidxcomp
+
+STARTTEST
+/^substitute
+:let y = substitute('123', '\zs', 'a', 'g') | put =y
+ENDTEST
+
+substitute
+
+STARTTEST
+:g/^STARTTEST/.,/^ENDTEST/d
+:1;/^Results/,$wq! test.out
+ENDTEST
diff --git a/src/testdir/test69.ok b/src/testdir/test69.ok
new file mode 100644
index 0000000..af8befb
--- /dev/null
+++ b/src/testdir/test69.ok
@@ -0,0 +1,166 @@
+Results of test69:
+
+
+{
+XYZ
+abc
+XYZ
+
+XYZ
+abc
+XYZ
+}
+
+
+{
+X
+X
+a
+X
+a
+X
+ï¼¹
+X
+ï¼¹
+
+X
+X
+a
+X
+a
+X
+ï¼¹
+X
+ï¼¹
+}
+
+
+{
+X
+X
+a
+X
+a
+X
+ï¼¹
+X
+ï¼¹
+a
+X
+ab
+X
+abc
+X
+ab
+X
+c
+ab
+X
+ï¼¹
+
+X
+X
+a
+X
+a
+X
+ï¼¹
+X
+ï¼¹
+a
+X
+ab
+X
+abc
+X
+ab
+X
+c
+ab
+X
+ï¼¹
+}
+
+
+{
+ X
+ X
+ a
+
+ X
+ X
+ a
+}
+
+
+{
+ X
+ X
+a
+
+ X
+ X
+a
+}
+
+
+{
+X
+Xa
+Xa
+XY
+XY
+XY
+XZ
+X Y
+X Y
+X Z
+XX
+XXa
+XXY
+
+X
+Xa
+Xa
+XY
+XY
+XY
+XZ
+X Y
+X Y
+X Z
+XX
+XXa
+XXY
+}
+
+
+{
+X
+a
+}
+
+
+{
+ four
+}
+
+ra test
+aaaa
+aaa
+
+
+áx
+
+
+byteidx
+[0, 1, 3, 4, -1]
+[0, 1, 4, 5, -1]
+byteidxcomp
+[0, 1, 3, 4, -1]
+[0, 1, 2, 4, 5, -1]
+
+
+substitute
+a1a2a3a
+
diff --git a/src/testdir/test70.in b/src/testdir/test70.in
new file mode 100644
index 0000000..9fbe818
--- /dev/null
+++ b/src/testdir/test70.in
@@ -0,0 +1,63 @@
+Smoke test for MzScheme interface and mzeval() function
+
+STARTTEST
+:so mzscheme.vim
+:set nocompatible viminfo+=nviminfo
+:function! MzRequire()
+:redir => l:mzversion
+:mz (version)
+:redir END
+:if strpart(l:mzversion, 1, 1) < "4"
+:" MzScheme versions < 4.x:
+:mz (require (prefix vim- vimext))
+:else
+:" newer versions:
+:mz (require (prefix-in vim- 'vimext))
+:mz (require r5rs)
+:endif
+:endfunction
+:silent call MzRequire()
+:mz (define l '("item0" "dictionary with list OK" "item2"))
+:mz (define h (make-hash))
+:mz (hash-set! h "list" l)
+/^1
+:" change buffer contents
+:mz (vim-set-buff-line (vim-eval "line('.')") "1 changed line 1")
+:" scalar test
+:let tmp_string = mzeval('"string"')
+:let tmp_1000 = mzeval('1000')
+:if tmp_string . tmp_1000 == "string1000"
+:let scalar_res = "OK"
+:else
+:let scalar_res = "FAILED"
+:endif
+:call append(search("^1"), "scalar test " . scalar_res)
+:" dictionary containing a list
+:let tmp = mzeval("h")["list"][1]
+:/^2/put =tmp
+:" circular list (at the same time test lists containing lists)
+:mz (set-car! (cddr l) l)
+:let l2 = mzeval("h")["list"]
+:if l2[2] == l2
+:let res = "OK"
+:else
+:let res = "FAILED: " . l2[2]
+:endif
+:call setline(search("^3"), "circular test " . res)
+:" funcrefs
+:mz (define vim:max (vim-eval "function('max')"))
+:mz (define m (vim:max '(1 100 8)))
+:let m = mzeval('m')
+:if m == 100
+:let fref_res = "OK"
+:else
+:let fref_res = "FAILED: " . m
+:end
+:call append(line('$'), 'funcrefs '. fref_res)
+:?^1?,$w! test.out
+:qa!
+ENDTEST
+
+1 line 1
+2 line 2
+3 line 3
diff --git a/src/testdir/test70.ok b/src/testdir/test70.ok
new file mode 100644
index 0000000..9c82a86
--- /dev/null
+++ b/src/testdir/test70.ok
@@ -0,0 +1,6 @@
+1 changed line 1
+scalar test OK
+2 line 2
+dictionary with list OK
+circular test OK
+funcrefs OK
diff --git a/src/testdir/test72.in b/src/testdir/test72.in
new file mode 100644
index 0000000..961df4c
--- /dev/null
+++ b/src/testdir/test72.in
@@ -0,0 +1,146 @@
+Tests for undo file.
+Since this script is sourced we need to explicitly break changes up in
+undo-able pieces. Do that by setting 'undolevels'.
+
+STARTTEST
+:so small.vim
+:set belloff=all
+:"
+:" Test 'undofile': first a simple one-line change.
+:set nocompatible viminfo+=nviminfo visualbell
+:set ul=100 undofile nomore
+:e! Xtestfile
+ggdGithis is one line:set ul=100
+:s/one/ONE/
+:set ul=100
+:w
+:bwipe!
+:e Xtestfile
+u:.w! test.out
+:"
+:" Test 'undofile', change in original file fails check
+:set noundofile
+:e! Xtestfile
+:s/line/Line/
+:w
+:set undofile
+:bwipe!
+:e Xtestfile
+u:.w >>test.out
+:"
+:" Test 'undofile', add 10 lines, delete 6 lines, undo 3
+:set undofile
+ggdGione
+two
+three
+four
+five
+six
+seven
+eight
+nine
+ten:set ul=100
+3Gdd:set ul=100
+dd:set ul=100
+dd:set ul=100
+dd:set ul=100
+dd:set ul=100
+dd:set ul=100
+:w
+:bwipe!
+:e Xtestfile
+uuu:w >>test.out
+:"
+:" Test that reading the undofiles when setting undofile works
+:set noundofile ul=0
+i
+u:e! Xtestfile
+:set undofile ul=100
+uuuuuu:w >>test.out
+:" And now with encryption, cryptmethod=zip
+:e! Xtestfile
+:set undofile cm=zip
+ggdGimonday
+tuesday
+wednesday
+thursday
+friday:set ul=100
+kkkdd:set ul=100
+dd:set ul=100
+dd:set ul=100
+:X
+foobar
+foobar
+:w!
+:bwipe!
+:e Xtestfile
+foobar
+:set key=
+uu:w >>test.out
+:"
+:"
+:" With encryption, cryptmethod=blowfish
+:e! Xtestfile
+rubbish
+:set undofile cm=blowfish ff&
+ggdGijan
+feb
+mar
+apr
+jun:set ul=100
+kk0ifoo :set ul=100
+dd:set ul=100
+ibar :set ul=100
+:X
+foobar
+foobar
+:w!
+:bwipe!
+:e Xtestfile
+foobar
+:set key=
+/bar
+:.w >>test.out
+u:.w >>test.out
+u:.w >>test.out
+u:.w >>test.out
+:"
+:" With encryption, cryptmethod=blowfish2
+:e! Xtestfile
+rubbish
+:set undofile cm=blowfish2 ff&
+ggdGijan
+feb
+mar
+apr
+jun:set ul=100
+kk0ifoo :set ul=100
+dd:set ul=100
+ibar :set ul=100
+:X
+foo2bar
+foo2bar
+:w!
+:bwipe!
+:e Xtestfile
+foo2bar
+:set key=
+/bar
+:.w >>test.out
+u:.w >>test.out
+u:.w >>test.out
+u:.w >>test.out
+:"
+:" Rename the undo file so that it gets cleaned up.
+:if has("vms")
+: call rename("_un_Xtestfile", "Xtestundo")
+:else
+: call rename(".Xtestfile.un~", "Xtestundo")
+:endif
+:qa!
+ENDTEST
+
+1111 -----
+2222 -----
+
+123456789
diff --git a/src/testdir/test72.ok b/src/testdir/test72.ok
new file mode 100644
index 0000000..8d30ba1
--- /dev/null
+++ b/src/testdir/test72.ok
@@ -0,0 +1,31 @@
+this is one line
+this is ONE Line
+one
+two
+six
+seven
+eight
+nine
+ten
+one
+two
+three
+four
+five
+six
+seven
+eight
+nine
+ten
+monday
+wednesday
+thursday
+friday
+bar apr
+apr
+foo mar
+mar
+bar apr
+apr
+foo mar
+mar
diff --git a/src/testdir/test77a.com b/src/testdir/test77a.com
new file mode 100644
index 0000000..ef74a4c
--- /dev/null
+++ b/src/testdir/test77a.com
@@ -0,0 +1,8 @@
+$! test77a - help file creating checksum on VMS
+$! Created by Zoltan Arpadffy
+$
+$ IF P1 .NES. ""
+$ THEN
+$ checksum 'P1'
+$ show symb CHECKSUM$CHECKSUM
+$ ENDIF
diff --git a/src/testdir/test77a.in b/src/testdir/test77a.in
new file mode 100644
index 0000000..052e29a
--- /dev/null
+++ b/src/testdir/test77a.in
@@ -0,0 +1,31 @@
+Inserts 2 million lines with consecutive integers starting from 1
+(essentially, the output of GNU's seq 1 2000000), writes them to Xtest
+and writes its cksum to test.out.
+
+We need 2 million lines to trigger a call to mf_hash_grow(). If it would mess
+up the lines the checksum would differ.
+
+cksum is part of POSIX and so should be available on most Unixes.
+If it isn't available then the test will be skipped.
+
+VMS does not have CKSUM but has a built in CHECKSUM - it should be used
+STARTTEST
+:so small.vim
+:if !has("vms")
+: e! test.ok
+: w! test.out
+: qa!
+:endif
+:set fileformat=unix undolevels=-1
+ggdG
+:let i = 1
+:while i <= 2000000 | call append(i, range(i, i + 99)) | let i += 100 | endwhile
+ggdd
+:w! Xtest.
+:r !@test77a.com Xtest.
+:s/\s/ /g
+:set fileformat&
+:.w! test.out
+:qa!
+ENDTEST
+
diff --git a/src/testdir/test77a.ok b/src/testdir/test77a.ok
new file mode 100644
index 0000000..41ec157
--- /dev/null
+++ b/src/testdir/test77a.ok
@@ -0,0 +1 @@
+ CHECKSUM$CHECKSUM = "844110470"
diff --git a/src/testdir/test83-tags2 b/src/testdir/test83-tags2
new file mode 100644
index 0000000..7f9f21b
--- /dev/null
+++ b/src/testdir/test83-tags2
@@ -0,0 +1,2 @@
+!_TAG_FILE_ENCODING cp932 //
+‚`‚a‚b Xtags2.txt /‚`‚a‚b
diff --git a/src/testdir/test83-tags3 b/src/testdir/test83-tags3
new file mode 100644
index 0000000..0cb6591
--- /dev/null
+++ b/src/testdir/test83-tags3
@@ -0,0 +1,102 @@
+!_TAG_FILE_SORTED 1 //
+!_TAG_FILE_ENCODING cp932 //
+abc1 Xtags3.txt /‚`‚a‚b
+abc2 Xtags3.txt /‚`‚a‚b
+abc3 Xtags3.txt /‚`‚a‚b
+abc4 Xtags3.txt /‚`‚a‚b
+abc5 Xtags3.txt /‚`‚a‚b
+abc6 Xtags3.txt /‚`‚a‚b
+abc7 Xtags3.txt /‚`‚a‚b
+abc8 Xtags3.txt /‚`‚a‚b
+abc9 Xtags3.txt /‚`‚a‚b
+abc10 Xtags3.txt /‚`‚a‚b
+abc11 Xtags3.txt /‚`‚a‚b
+abc12 Xtags3.txt /‚`‚a‚b
+abc13 Xtags3.txt /‚`‚a‚b
+abc14 Xtags3.txt /‚`‚a‚b
+abc15 Xtags3.txt /‚`‚a‚b
+abc16 Xtags3.txt /‚`‚a‚b
+abc17 Xtags3.txt /‚`‚a‚b
+abc18 Xtags3.txt /‚`‚a‚b
+abc19 Xtags3.txt /‚`‚a‚b
+abc20 Xtags3.txt /‚`‚a‚b
+abc21 Xtags3.txt /‚`‚a‚b
+abc22 Xtags3.txt /‚`‚a‚b
+abc23 Xtags3.txt /‚`‚a‚b
+abc24 Xtags3.txt /‚`‚a‚b
+abc25 Xtags3.txt /‚`‚a‚b
+abc26 Xtags3.txt /‚`‚a‚b
+abc27 Xtags3.txt /‚`‚a‚b
+abc28 Xtags3.txt /‚`‚a‚b
+abc29 Xtags3.txt /‚`‚a‚b
+abc30 Xtags3.txt /‚`‚a‚b
+abc31 Xtags3.txt /‚`‚a‚b
+abc32 Xtags3.txt /‚`‚a‚b
+abc33 Xtags3.txt /‚`‚a‚b
+abc34 Xtags3.txt /‚`‚a‚b
+abc35 Xtags3.txt /‚`‚a‚b
+abc36 Xtags3.txt /‚`‚a‚b
+abc37 Xtags3.txt /‚`‚a‚b
+abc38 Xtags3.txt /‚`‚a‚b
+abc39 Xtags3.txt /‚`‚a‚b
+abc40 Xtags3.txt /‚`‚a‚b
+abc41 Xtags3.txt /‚`‚a‚b
+abc42 Xtags3.txt /‚`‚a‚b
+abc43 Xtags3.txt /‚`‚a‚b
+abc44 Xtags3.txt /‚`‚a‚b
+abc45 Xtags3.txt /‚`‚a‚b
+abc46 Xtags3.txt /‚`‚a‚b
+abc47 Xtags3.txt /‚`‚a‚b
+abc48 Xtags3.txt /‚`‚a‚b
+abc49 Xtags3.txt /‚`‚a‚b
+abc50 Xtags3.txt /‚`‚a‚b
+abc51 Xtags3.txt /‚`‚a‚b
+abc52 Xtags3.txt /‚`‚a‚b
+abc53 Xtags3.txt /‚`‚a‚b
+abc54 Xtags3.txt /‚`‚a‚b
+abc55 Xtags3.txt /‚`‚a‚b
+abc56 Xtags3.txt /‚`‚a‚b
+abc57 Xtags3.txt /‚`‚a‚b
+abc58 Xtags3.txt /‚`‚a‚b
+abc59 Xtags3.txt /‚`‚a‚b
+abc60 Xtags3.txt /‚`‚a‚b
+abc61 Xtags3.txt /‚`‚a‚b
+abc62 Xtags3.txt /‚`‚a‚b
+abc63 Xtags3.txt /‚`‚a‚b
+abc64 Xtags3.txt /‚`‚a‚b
+abc65 Xtags3.txt /‚`‚a‚b
+abc66 Xtags3.txt /‚`‚a‚b
+abc67 Xtags3.txt /‚`‚a‚b
+abc68 Xtags3.txt /‚`‚a‚b
+abc69 Xtags3.txt /‚`‚a‚b
+abc70 Xtags3.txt /‚`‚a‚b
+abc71 Xtags3.txt /‚`‚a‚b
+abc72 Xtags3.txt /‚`‚a‚b
+abc73 Xtags3.txt /‚`‚a‚b
+abc74 Xtags3.txt /‚`‚a‚b
+abc75 Xtags3.txt /‚`‚a‚b
+abc76 Xtags3.txt /‚`‚a‚b
+abc77 Xtags3.txt /‚`‚a‚b
+abc78 Xtags3.txt /‚`‚a‚b
+abc79 Xtags3.txt /‚`‚a‚b
+abc80 Xtags3.txt /‚`‚a‚b
+abc81 Xtags3.txt /‚`‚a‚b
+abc82 Xtags3.txt /‚`‚a‚b
+abc83 Xtags3.txt /‚`‚a‚b
+abc84 Xtags3.txt /‚`‚a‚b
+abc85 Xtags3.txt /‚`‚a‚b
+abc86 Xtags3.txt /‚`‚a‚b
+abc87 Xtags3.txt /‚`‚a‚b
+abc88 Xtags3.txt /‚`‚a‚b
+abc89 Xtags3.txt /‚`‚a‚b
+abc90 Xtags3.txt /‚`‚a‚b
+abc91 Xtags3.txt /‚`‚a‚b
+abc92 Xtags3.txt /‚`‚a‚b
+abc93 Xtags3.txt /‚`‚a‚b
+abc94 Xtags3.txt /‚`‚a‚b
+abc95 Xtags3.txt /‚`‚a‚b
+abc96 Xtags3.txt /‚`‚a‚b
+abc97 Xtags3.txt /‚`‚a‚b
+abc98 Xtags3.txt /‚`‚a‚b
+abc99 Xtags3.txt /‚`‚a‚b
+abc100 Xtags3.txt /‚`‚a‚b
diff --git a/src/testdir/test85.ok b/src/testdir/test85.ok
new file mode 100644
index 0000000..4753483
--- /dev/null
+++ b/src/testdir/test85.ok
@@ -0,0 +1,7 @@
+1 changed line 1
+scalar test OK
+2 line 2
+dictionary with list OK
+circular test OK
+[123.0, 'abc', [1, 2, 3], {'a': 1, 'b': 2, 'c': 3}]
+{'4': 123.0, '5': 'abc', '6': [1, 2, 3], '7': {'a': 1, 'b': 2, 'c': 3}}
diff --git a/src/testdir/test86.in b/src/testdir/test86.in
new file mode 100644
index 0000000..71dd9f1
--- /dev/null
+++ b/src/testdir/test86.in
@@ -0,0 +1,1711 @@
+Tests for various python features. vim: set ft=vim :
+
+NOTE: This will cause errors when run under valgrind.
+This would require recompiling Python with:
+ ./configure --without-pymalloc
+See http://svn.python.org/view/python/trunk/Misc/README.valgrind?view=markup
+
+STARTTEST
+:so small.vim
+:set encoding=latin1
+:set noswapfile
+:if !has('python') | e! test.ok | wq! test.out | endif
+:lang C
+:fun Test()
+:py import vim
+:py cb = vim.current.buffer
+:let l = []
+:py l=vim.bindeval('l')
+:py f=vim.bindeval('function("strlen")')
+:" Extending List directly with different types
+:py l.extend([1, "as'd", [1, 2, f, {'a': 1}]])
+:$put =string(l)
+:$put =string(l[-1])
+:try
+: $put =string(l[-4])
+:catch
+: $put =v:exception[:13]
+:endtry
+:" List assignment
+:py l[0]=0
+:$put =string(l)
+:py l[-2]=f
+:$put =string(l)
+:"
+:" Extending Dictionary directly with different types
+:let d = {}
+:fun d.f()
+: return 1
+:endfun
+py << EOF
+d=vim.bindeval('d')
+d['1']='asd'
+d.update() # Must not do anything, including throwing errors
+d.update(b=[1, 2, f])
+d.update((('-1', {'a': 1}),))
+d.update({'0': -1})
+dk = d.keys()
+dv = d.values()
+di = d.items()
+cmpfun = lambda a, b: cmp(repr(a), repr(b))
+dk.sort(cmpfun)
+dv.sort(cmpfun)
+di.sort(cmpfun)
+EOF
+:$put =pyeval('d[''f''](self={})')
+:$put =pyeval('repr(dk)')
+:$put =substitute(pyeval('repr(dv)'),'0x\x\+','','g')
+:$put =substitute(pyeval('repr(di)'),'0x\x\+','','g')
+:for [key, Val] in sort(items(d))
+: $put =string(key) . ' : ' . string(Val)
+: unlet key Val
+:endfor
+:py del dk
+:py del di
+:py del dv
+:"
+:" removing items with del
+:py del l[2]
+:$put =string(l)
+:let l = range(8)
+:py l=vim.bindeval('l')
+:try
+: py del l[:3]
+: py del l[1:]
+:catch
+: $put =v:exception
+:endtry
+:$put =string(l)
+:"
+:py del d['-1']
+:py del d['f']
+:$put =string(pyeval('d.get(''b'', 1)'))
+:$put =string(pyeval('d.pop(''b'')'))
+:$put =string(pyeval('d.get(''b'', 1)'))
+:$put =string(pyeval('d.pop(''1'', 2)'))
+:$put =string(pyeval('d.pop(''1'', 2)'))
+:$put =pyeval('repr(d.has_key(''0''))')
+:$put =pyeval('repr(d.has_key(''1''))')
+:$put =pyeval('repr(''0'' in d)')
+:$put =pyeval('repr(''1'' in d)')
+:$put =pyeval('repr(list(iter(d)))')
+:$put =string(d)
+:$put =pyeval('repr(d.popitem())')
+:$put =pyeval('repr(d.get(''0''))')
+:$put =pyeval('repr(list(iter(d)))')
+:"
+:" removing items out of range: silently skip items that don't exist
+:let l = [0, 1, 2, 3]
+:py l=vim.bindeval('l')
+:" The following two ranges delete nothing as they match empty list:
+:py del l[2:1]
+:$put =string(l)
+:py del l[2:2]
+:$put =string(l)
+:py del l[2:3]
+:$put =string(l)
+:let l = [0, 1, 2, 3]
+:py l=vim.bindeval('l')
+:py del l[2:4]
+:$put =string(l)
+:let l = [0, 1, 2, 3]
+:py l=vim.bindeval('l')
+:py del l[2:5]
+:$put =string(l)
+:let l = [0, 1, 2, 3]
+:py l=vim.bindeval('l')
+:py del l[2:6]
+:$put =string(l)
+:let l = [0, 1, 2, 3]
+:py l=vim.bindeval('l')
+:" The following two ranges delete nothing as they match empty list:
+:py del l[-1:2]
+:$put =string(l)
+:py del l[-2:2]
+:$put =string(l)
+:py del l[-3:2]
+:$put =string(l)
+:let l = [0, 1, 2, 3]
+:py l=vim.bindeval('l')
+:py del l[-4:2]
+:$put =string(l)
+:let l = [0, 1, 2, 3]
+:py l=vim.bindeval('l')
+:py del l[-5:2]
+:$put =string(l)
+:let l = [0, 1, 2, 3]
+:py l=vim.bindeval('l')
+:py del l[-6:2]
+:$put =string(l)
+:let l = [0, 1, 2, 3]
+:py l=vim.bindeval('l')
+:py del l[::2]
+:$put =string(l)
+:let l = [0, 1, 2, 3]
+:py l=vim.bindeval('l')
+:py del l[3:0:-2]
+:$put =string(l)
+:let l = [0, 1, 2, 3]
+:py l=vim.bindeval('l')
+:py del l[2:4:-2]
+:$put =string(l)
+:"
+:" Slice assignment to a list
+:let l = [0, 1, 2, 3]
+:py l=vim.bindeval('l')
+:py l[0:0]=['a']
+:$put =string(l)
+:let l = [0, 1, 2, 3]
+:py l=vim.bindeval('l')
+:py l[1:2]=['b']
+:$put =string(l)
+:let l = [0, 1, 2, 3]
+:py l=vim.bindeval('l')
+:py l[2:4]=['c']
+:$put =string(l)
+:let l = [0, 1, 2, 3]
+:py l=vim.bindeval('l')
+:py l[4:4]=['d']
+:$put =string(l)
+:let l = [0, 1, 2, 3]
+:py l=vim.bindeval('l')
+:py l[-1:2]=['e']
+:$put =string(l)
+:let l = [0, 1, 2, 3]
+:py l=vim.bindeval('l')
+:py l[-10:2]=['f']
+:$put =string(l)
+:let l = [0, 1, 2, 3]
+:py l=vim.bindeval('l')
+:py l[2:-10]=['g']
+:$put =string(l)
+:let l = []
+:py l=vim.bindeval('l')
+:py l[0:0]=['h']
+:$put =string(l)
+:let l = range(8)
+:py l=vim.bindeval('l')
+:py l[2:6:2] = [10, 20]
+:$put =string(l)
+:let l = range(8)
+:py l=vim.bindeval('l')
+:py l[6:2:-2] = [10, 20]
+:$put =string(l)
+:let l = range(8)
+:py l=vim.bindeval('l')
+:py l[6:2] = ()
+:$put =string(l)
+:let l = range(8)
+:py l=vim.bindeval('l')
+:py l[6:2:1] = ()
+:$put =string(l)
+:let l = range(8)
+:py l=vim.bindeval('l')
+:py l[2:2:1] = ()
+:$put =string(l)
+:"
+:" Locked variables
+:let l = [0, 1, 2, 3]
+:py l=vim.bindeval('l')
+:lockvar! l
+py << EOF
+def emsg(ei):
+ return ei[0].__name__ + ':' + repr(ei[1].args)
+
+try:
+ l[2]='i'
+except vim.error:
+ cb.append('l[2] threw vim.error: ' + emsg(sys.exc_info()))
+EOF
+:$put =string(l)
+:unlockvar! l
+:"
+:" Function calls
+py << EOF
+import sys
+def ee(expr, g=globals(), l=locals()):
+ try:
+ exec(expr, g, l)
+ except:
+ ei = sys.exc_info()
+ msg = emsg(ei)
+ msg = msg.replace('TypeError:(\'argument 1 ', 'TypeError:(\'')
+ if expr.find('None') > -1:
+ msg = msg.replace('TypeError:(\'iteration over non-sequence\',)',
+ 'TypeError:("\'NoneType\' object is not iterable",)')
+ if expr.find('FailingNumber') > -1:
+ msg = msg.replace(', not \'FailingNumber\'', '').replace('"', '\'')
+ msg = msg.replace('TypeError:(\'iteration over non-sequence\',)',
+ 'TypeError:("\'FailingNumber\' object is not iterable",)')
+ if msg.find('(\'\'') > -1 or msg.find('(\'can\'t') > -1:
+ msg = msg.replace('(\'', '("').replace('\',)', '",)')
+ # Some Python versions say can't, others cannot.
+ if msg.find('can\'t') > -1:
+ msg = msg.replace('can\'t', 'cannot')
+ # Some Python versions use single quote, some double quote
+ if msg.find('"cannot ') > -1:
+ msg = msg.replace('"cannot ', '\'cannot ')
+ if msg.find(' attributes"') > -1:
+ msg = msg.replace(' attributes"', ' attributes\'')
+ if expr == 'fd(self=[])':
+ # HACK: PyMapping_Check changed meaning
+ msg = msg.replace('AttributeError:(\'keys\',)',
+ 'TypeError:(\'unable to convert list to vim dictionary\',)')
+ vim.current.buffer.append(expr + ':' + msg)
+ else:
+ vim.current.buffer.append(expr + ':NOT FAILED')
+EOF
+:fun New(...)
+: return ['NewStart']+a:000+['NewEnd']
+:endfun
+:fun DictNew(...) dict
+: return ['DictNewStart']+a:000+['DictNewEnd', self]
+:endfun
+:let l=[function('New'), function('DictNew')]
+:py l=vim.bindeval('l')
+:py l.extend(list(l[0](1, 2, 3)))
+:$put =string(l)
+:py l.extend(list(l[1](1, 2, 3, self={'a': 'b'})))
+:$put =string(l)
+:py l.extend([l[0].name])
+:$put =string(l)
+:py ee('l[1](1, 2, 3)')
+:py f=l[0]
+:delfunction New
+:py ee('f(1, 2, 3)')
+:if has('float')
+: let l=[0.0]
+: py l=vim.bindeval('l')
+: py l.extend([0.0])
+: $put =string(l)
+:else
+: $put ='[0.0, 0.0]'
+:endif
+:let messages=[]
+:delfunction DictNew
+py <<EOF
+d=vim.bindeval('{}')
+m=vim.bindeval('messages')
+def em(expr, g=globals(), l=locals()):
+ try:
+ exec(expr, g, l)
+ except:
+ m.extend([sys.exc_type.__name__])
+
+em('d["abc1"]')
+em('d["abc1"]="\\0"')
+em('d["abc1"]=vim')
+em('d[""]=1')
+em('d["a\\0b"]=1')
+em('d[u"a\\0b"]=1')
+
+em('d.pop("abc1")')
+em('d.popitem()')
+del em
+del m
+EOF
+:$put =messages
+:unlet messages
+:" locked and scope attributes
+:let d={} | let dl={} | lockvar dl
+:for s in split("d dl v: g:")
+: let name=tr(s, ':', 's')
+: execute 'py '.name.'=vim.bindeval("'.s.'")'
+: let toput=s.' : '.join(map(['locked', 'scope'], 'v:val.":".pyeval(name.".".v:val)'), ';')
+: $put =toput
+:endfor
+:silent! let d.abc2=1
+:silent! let dl.abc3=1
+:py d.locked=True
+:py dl.locked=False
+:silent! let d.def=1
+:silent! let dl.def=1
+:put ='d:'.string(d)
+:put ='dl:'.string(dl)
+:unlet d dl
+:
+:let l=[] | let ll=[] | lockvar ll
+:for s in split("l ll")
+: let name=tr(s, ':', 's')
+: execute 'py '.name.'=vim.bindeval("'.s.'")'
+: let toput=s.' : locked:'.pyeval(name.'.locked')
+: $put =toput
+:endfor
+:silent! call extend(l, [0])
+:silent! call extend(ll, [0])
+:py l.locked=True
+:py ll.locked=False
+:silent! call extend(l, [1])
+:silent! call extend(ll, [1])
+:put ='l:'.string(l)
+:put ='ll:'.string(ll)
+:unlet l ll
+:"
+:" pyeval()
+:let l=pyeval('range(3)')
+:$put =string(l)
+:let d=pyeval('{"a": "b", "c": 1, "d": ["e"]}')
+:$put =sort(items(d))
+:let v:errmsg = ''
+:$put ='pyeval(\"None\") = ' . pyeval('None') . v:errmsg
+:if has('float')
+: let f=pyeval('0.0')
+: $put =string(f)
+:else
+: $put ='0.0'
+:endif
+:" Invalid values:
+:for e in ['"\0"', '{"\0": 1}', 'undefined_name', 'vim']
+: try
+: let v=pyeval(e)
+: catch
+: let toput=e.":\t".v:exception[:13]
+: $put =toput
+: endtry
+:endfor
+:"
+:" threading
+:let l = [0]
+:py l=vim.bindeval('l')
+py <<EOF
+import threading
+import time
+
+class T(threading.Thread):
+ def __init__(self):
+ threading.Thread.__init__(self)
+ self.t = 0
+ self.running = True
+
+ def run(self):
+ while self.running:
+ self.t += 1
+ time.sleep(0.1)
+
+t = T()
+del T
+t.start()
+EOF
+:sleep 1
+:py t.running = False
+:py t.join()
+:" Check if the background thread is working. Count should be 10, but on a
+:" busy system (AppVeyor) it can be much lower.
+:py l[0] = t.t > 4
+:py del time
+:py del threading
+:py del t
+:$put =string(l)
+:"
+:" settrace
+:let l = []
+:py l=vim.bindeval('l')
+py <<EOF
+import sys
+
+def traceit(frame, event, arg):
+ global l
+ if event == "line":
+ l.extend([frame.f_lineno])
+ return traceit
+
+def trace_main():
+ for i in range(5):
+ pass
+EOF
+:py sys.settrace(traceit)
+:py trace_main()
+:py sys.settrace(None)
+:py del traceit
+:py del trace_main
+:$put =string(l)
+:"
+:" Slice
+:py ll = vim.bindeval('[0, 1, 2, 3, 4, 5]')
+:py l = ll[:4]
+:$put =string(pyeval('l'))
+:py l = ll[2:]
+:$put =string(pyeval('l'))
+:py l = ll[:-4]
+:$put =string(pyeval('l'))
+:py l = ll[-2:]
+:$put =string(pyeval('l'))
+:py l = ll[2:4]
+:$put =string(pyeval('l'))
+:py l = ll[4:2]
+:$put =string(pyeval('l'))
+:py l = ll[-4:-2]
+:$put =string(pyeval('l'))
+:py l = ll[-2:-4]
+:$put =string(pyeval('l'))
+:py l = ll[:]
+:$put =string(pyeval('l'))
+:py l = ll[0:6]
+:$put =string(pyeval('l'))
+:py l = ll[-10:10]
+:$put =string(pyeval('l'))
+:py l = ll[4:2:-1]
+:$put =string(pyeval('l'))
+:py l = ll[::2]
+:$put =string(pyeval('l'))
+:py l = ll[4:2:1]
+:$put =string(pyeval('l'))
+:py del l
+:"
+:" Vars
+:let g:foo = 'bac'
+:let w:abc3 = 'def'
+:let b:baz = 'bar'
+:let t:bar = 'jkl'
+:try
+: throw "Abc"
+:catch
+: put =pyeval('vim.vvars[''exception'']')
+:endtry
+:put =pyeval('vim.vars[''foo'']')
+:put =pyeval('vim.current.window.vars[''abc3'']')
+:put =pyeval('vim.current.buffer.vars[''baz'']')
+:put =pyeval('vim.current.tabpage.vars[''bar'']')
+:"
+:" Options
+:" paste: boolean, global
+:" previewheight number, global
+:" operatorfunc: string, global
+:" number: boolean, window-local
+:" numberwidth: number, window-local
+:" colorcolumn: string, window-local
+:" statusline: string, window-local/global
+:" autoindent: boolean, buffer-local
+:" shiftwidth: number, buffer-local
+:" omnifunc: string, buffer-local
+:" preserveindent: boolean, buffer-local/global
+:" path: string, buffer-local/global
+:let g:bufs=[bufnr('%')]
+:new
+:let g:bufs+=[bufnr('%')]
+:vnew
+:let g:bufs+=[bufnr('%')]
+:wincmd j
+:vnew
+:let g:bufs+=[bufnr('%')]
+:wincmd l
+:fun RecVars(opt)
+: let gval =string(eval('&g:'.a:opt))
+: let wvals=join(map(range(1, 4), 'v:val.":".string(getwinvar(v:val, "&".a:opt))'))
+: let bvals=join(map(copy(g:bufs), 'v:val.":".string(getbufvar(v:val, "&".a:opt))'))
+: put =' G: '.gval
+: put =' W: '.wvals
+: put =' B: '.wvals
+:endfun
+py << EOF
+def e(s, g=globals(), l=locals()):
+ try:
+ exec(s, g, l)
+ except:
+ vim.command('return ' + repr(sys.exc_type.__name__))
+
+def ev(s, g=globals(), l=locals()):
+ try:
+ return eval(s, g, l)
+ except:
+ vim.command('let exc=' + repr(sys.exc_type.__name__))
+ return 0
+EOF
+:fun E(s)
+: python e(vim.eval('a:s'))
+:endfun
+:fun Ev(s)
+: let r=pyeval('ev(vim.eval("a:s"))')
+: if exists('exc')
+: throw exc
+: endif
+: return r
+:endfun
+:py gopts1=vim.options
+:py wopts1=vim.windows[2].options
+:py wopts2=vim.windows[0].options
+:py wopts3=vim.windows[1].options
+:py bopts1=vim.buffers[vim.bindeval("g:bufs")[2]].options
+:py bopts2=vim.buffers[vim.bindeval("g:bufs")[1]].options
+:py bopts3=vim.buffers[vim.bindeval("g:bufs")[0]].options
+:$put ='wopts iters equal: '.pyeval('list(wopts1) == list(wopts2)')
+:$put ='bopts iters equal: '.pyeval('list(bopts1) == list(bopts2)')
+:py gset=set(iter(gopts1))
+:py wset=set(iter(wopts1))
+:py bset=set(iter(bopts1))
+:set path=.,..,,
+:let lst=[]
+:let lst+=[['paste', 1, 0, 1, 2, 1, 1, 0 ]]
+:let lst+=[['previewheight', 5, 1, 6, 'a', 0, 1, 0 ]]
+:let lst+=[['operatorfunc', 'A', 'B', 'C', 2, 0, 1, 0 ]]
+:let lst+=[['number', 0, 1, 1, 0, 1, 0, 1 ]]
+:let lst+=[['numberwidth', 2, 3, 5, -100, 0, 0, 1 ]]
+:let lst+=[['colorcolumn', '+1', '+2', '+3', 'abc4', 0, 0, 1 ]]
+:let lst+=[['statusline', '1', '2', '4', 0, 0, 1, 1 ]]
+:let lst+=[['autoindent', 0, 1, 1, 2, 1, 0, 2 ]]
+:let lst+=[['shiftwidth', 0, 2, 1, 3, 0, 0, 2 ]]
+:let lst+=[['omnifunc', 'A', 'B', 'C', 1, 0, 0, 2 ]]
+:let lst+=[['preserveindent', 0, 1, 1, 2, 1, 1, 2 ]]
+:let lst+=[['path', '.,,', ',,', '.', 0, 0, 1, 2 ]]
+:for [oname, oval1, oval2, oval3, invval, bool, global, local] in lst
+: py oname=vim.eval('oname')
+: py oval1=vim.bindeval('oval1')
+: py oval2=vim.bindeval('oval2')
+: py oval3=vim.bindeval('oval3')
+: if invval is 0 || invval is 1
+: py invval=bool(vim.bindeval('invval'))
+: else
+: py invval=vim.bindeval('invval')
+: endif
+: if bool
+: py oval1=bool(oval1)
+: py oval2=bool(oval2)
+: py oval3=bool(oval3)
+: endif
+: put ='>>> '.oname
+: $put =' g/w/b:'.pyeval('oname in gset').'/'.pyeval('oname in wset').'/'.pyeval('oname in bset')
+: $put =' g/w/b (in):'.pyeval('oname in gopts1').'/'.pyeval('oname in wopts1').'/'.pyeval('oname in bopts1')
+: for v in ['gopts1', 'wopts1', 'bopts1']
+: try
+: put =' p/'.v.': '.Ev('repr('.v.'['''.oname.'''])')
+: catch
+: put =' p/'.v.'! '.v:exception
+: endtry
+: let r=E(v.'['''.oname.''']=invval')
+: if r isnot 0
+: put =' inv: '.string(invval).'! '.r
+: endif
+: for vv in (v is# 'gopts1' ? [v] : [v, v[:-2].'2', v[:-2].'3'])
+: let val=substitute(vv, '^.opts', 'oval', '')
+: let r=E(vv.'['''.oname.''']='.val)
+: if r isnot 0
+: put =' '.vv.'! '.r
+: endif
+: endfor
+: endfor
+: call RecVars(oname)
+: for v in ['wopts3', 'bopts3']
+: let r=E('del '.v.'["'.oname.'"]')
+: if r isnot 0
+: put =' del '.v.'! '.r
+: endif
+: endfor
+: call RecVars(oname)
+:endfor
+:delfunction RecVars
+:delfunction E
+:delfunction Ev
+:py del ev
+:py del e
+:only
+:for buf in g:bufs[1:]
+: execute 'bwipeout!' buf
+:endfor
+:py del gopts1
+:py del wopts1
+:py del wopts2
+:py del wopts3
+:py del bopts1
+:py del bopts2
+:py del bopts3
+:py del oval1
+:py del oval2
+:py del oval3
+:py del oname
+:py del invval
+:"
+:" Test buffer object
+:vnew
+:put ='First line'
+:put ='Second line'
+:put ='Third line'
+:1 delete _
+:py b=vim.current.buffer
+:wincmd w
+:mark a
+:augroup BUFS
+: autocmd BufFilePost * python cb.append(vim.eval('expand("<abuf>")') + ':BufFilePost:' + vim.eval('bufnr("%")'))
+: autocmd BufFilePre * python cb.append(vim.eval('expand("<abuf>")') + ':BufFilePre:' + vim.eval('bufnr("%")'))
+:augroup END
+py << EOF
+# Tests BufferAppend and BufferItem
+cb.append(b[0])
+# Tests BufferSlice and BufferAssSlice
+cb.append('abc5') # Will be overwritten
+cb[-1:] = b[:-2]
+# Test BufferLength and BufferAssSlice
+cb.append('def') # Will not be overwritten
+cb[len(cb):] = b[:]
+# Test BufferAssItem and BufferMark
+cb.append('ghi') # Will be overwritten
+cb[-1] = repr((len(cb) - cb.mark('a')[0], cb.mark('a')[1]))
+# Test BufferRepr
+cb.append(repr(cb) + repr(b))
+# Modify foreign buffer
+b.append('foo')
+b[0]='bar'
+b[0:0]=['baz']
+vim.command('call append("$", getbufline(%i, 1, "$"))' % b.number)
+# Test assigning to name property
+import os
+old_name = cb.name
+cb.name = 'foo'
+cb.append(cb.name[-11:].replace(os.path.sep, '/'))
+b.name = 'bar'
+cb.append(b.name[-11:].replace(os.path.sep, '/'))
+cb.name = old_name
+cb.append(cb.name[-17:].replace(os.path.sep, '/'))
+del old_name
+# Test CheckBuffer
+for _b in vim.buffers:
+ if _b is not cb:
+ vim.command('bwipeout! ' + str(_b.number))
+del _b
+cb.append('valid: b:%s, cb:%s' % (repr(b.valid), repr(cb.valid)))
+for expr in ('b[1]','b[:] = ["A", "B"]','b[:]','b.append("abc6")', 'b.name = "!"'):
+ try:
+ exec(expr)
+ except vim.error:
+ pass
+ else:
+ # Usually a SEGV here
+ # Should not happen in any case
+ cb.append('No exception for ' + expr)
+vim.command('cd .')
+del b
+EOF
+:augroup BUFS
+: autocmd!
+:augroup END
+:augroup! BUFS
+:"
+:" Test vim.buffers object
+:set hidden
+:edit a
+:buffer #
+:edit b
+:buffer #
+:edit c
+:buffer #
+py << EOF
+try:
+ from __builtin__ import next
+except ImportError:
+ next = lambda o: o.next()
+# Check GCing iterator that was not fully exhausted
+i = iter(vim.buffers)
+cb.append('i:' + str(next(i)))
+# and also check creating more than one iterator at a time
+i2 = iter(vim.buffers)
+cb.append('i2:' + str(next(i2)))
+cb.append('i:' + str(next(i)))
+# The following should trigger GC and not cause any problems
+del i
+del i2
+i3 = iter(vim.buffers)
+cb.append('i3:' + str(next(i3)))
+del i3
+
+prevnum = 0
+for b in vim.buffers:
+ # Check buffer order
+ if prevnum >= b.number:
+ cb.append('!!! Buffer numbers not in strictly ascending order')
+ # Check indexing: vim.buffers[number].number == number
+ cb.append(str(b.number) + ':' + repr(vim.buffers[b.number]) + '=' + repr(b))
+ prevnum = b.number
+del prevnum
+
+cb.append(str(len(vim.buffers)))
+
+bnums = list(map(lambda b: b.number, vim.buffers))[1:]
+
+# Test wiping out buffer with existing iterator
+i4 = iter(vim.buffers)
+cb.append('i4:' + str(next(i4)))
+vim.command('bwipeout! ' + str(bnums.pop(0)))
+try:
+ next(i4)
+except vim.error:
+ pass
+else:
+ cb.append('!!!! No vim.error')
+i4 = iter(vim.buffers)
+vim.command('bwipeout! ' + str(bnums.pop(-1)))
+vim.command('bwipeout! ' + str(bnums.pop(-1)))
+cb.append('i4:' + str(next(i4)))
+try:
+ next(i4)
+except StopIteration:
+ cb.append('StopIteration')
+del i4
+del bnums
+EOF
+:"
+:" Test vim.{tabpage,window}list and vim.{tabpage,window} objects
+:tabnew 0
+:tabnew 1
+:vnew a.1
+:tabnew 2
+:vnew a.2
+:vnew b.2
+:vnew c.2
+py << EOF
+cb.append('Number of tabs: ' + str(len(vim.tabpages)))
+cb.append('Current tab pages:')
+def W(w):
+ if repr(w).find('(unknown)') != -1:
+ return '<window object (unknown)>'
+ else:
+ return repr(w)
+
+start = len(cb)
+
+def Cursor(w):
+ if w.buffer is cb:
+ return repr((start - w.cursor[0], w.cursor[1]))
+ else:
+ return repr(w.cursor)
+
+for t in vim.tabpages:
+ cb.append(' ' + repr(t) + '(' + str(t.number) + ')' + ': ' + str(len(t.windows)) + ' windows, current is ' + W(t.window))
+ cb.append(' Windows:')
+ for w in t.windows:
+ cb.append(' ' + W(w) + '(' + str(w.number) + ')' + ': displays buffer ' + repr(w.buffer) + '; cursor is at ' + Cursor(w))
+ # Other values depend on the size of the terminal, so they are checked partly:
+ for attr in ('height', 'row', 'width', 'col'):
+ try:
+ aval = getattr(w, attr)
+ if type(aval) is not long:
+ raise TypeError
+ if aval < 0:
+ raise ValueError
+ except Exception:
+ cb.append('!!!!!! Error while getting attribute ' + attr + ': ' + sys.exc_type.__name__)
+ del aval
+ del attr
+ w.cursor = (len(w.buffer), 0)
+del W
+del Cursor
+cb.append('Number of windows in current tab page: ' + str(len(vim.windows)))
+if list(vim.windows) != list(vim.current.tabpage.windows):
+ cb.append('!!!!!! Windows differ')
+EOF
+:"
+:" Test vim.current
+py << EOF
+def H(o):
+ return repr(o)
+cb.append('Current tab page: ' + repr(vim.current.tabpage))
+cb.append('Current window: ' + repr(vim.current.window) + ': ' + H(vim.current.window) + ' is ' + H(vim.current.tabpage.window))
+cb.append('Current buffer: ' + repr(vim.current.buffer) + ': ' + H(vim.current.buffer) + ' is ' + H(vim.current.window.buffer)+ ' is ' + H(vim.current.tabpage.window.buffer))
+del H
+# Assigning: fails
+try:
+ vim.current.window = vim.tabpages[0].window
+except ValueError:
+ cb.append('ValueError at assigning foreign tab window')
+
+for attr in ('window', 'tabpage', 'buffer'):
+ try:
+ setattr(vim.current, attr, None)
+ except TypeError:
+ cb.append('Type error at assigning None to vim.current.' + attr)
+del attr
+
+# Assigning: success
+vim.current.tabpage = vim.tabpages[-2]
+vim.current.buffer = cb
+vim.current.window = vim.windows[0]
+vim.current.window.cursor = (len(vim.current.buffer), 0)
+cb.append('Current tab page: ' + repr(vim.current.tabpage))
+cb.append('Current window: ' + repr(vim.current.window))
+cb.append('Current buffer: ' + repr(vim.current.buffer))
+cb.append('Current line: ' + repr(vim.current.line))
+ws = list(vim.windows)
+ts = list(vim.tabpages)
+for b in vim.buffers:
+ if b is not cb:
+ vim.command('bwipeout! ' + str(b.number))
+del b
+cb.append('w.valid: ' + repr([w.valid for w in ws]))
+cb.append('t.valid: ' + repr([t.valid for t in ts]))
+del w
+del t
+del ts
+del ws
+EOF
+:tabonly!
+:only!
+:"
+:" Test types
+py << EOF
+for expr, attr in (
+ ('vim.vars', 'Dictionary'),
+ ('vim.options', 'Options'),
+ ('vim.bindeval("{}")', 'Dictionary'),
+ ('vim.bindeval("[]")', 'List'),
+ ('vim.bindeval("function(\'tr\')")', 'Function'),
+ ('vim.current.buffer', 'Buffer'),
+ ('vim.current.range', 'Range'),
+ ('vim.current.window', 'Window'),
+ ('vim.current.tabpage', 'TabPage'),
+):
+ cb.append(expr + ':' + attr + ':' + repr(type(eval(expr)) is getattr(vim, attr)))
+del expr
+del attr
+EOF
+:"
+:" Test __dir__() method
+py << EOF
+for name, o in (
+ ('current', vim.current),
+ ('buffer', vim.current.buffer),
+ ('window', vim.current.window),
+ ('tabpage', vim.current.tabpage),
+ ('range', vim.current.range),
+ ('dictionary', vim.bindeval('{}')),
+ ('list', vim.bindeval('[]')),
+ ('function', vim.bindeval('function("tr")')),
+ ('output', sys.stdout),
+ ):
+ cb.append(name + ':' + ','.join(dir(o)))
+del name
+del o
+EOF
+:"
+:" Test vim.*.__new__
+:$put =string(pyeval('vim.Dictionary({})'))
+:$put =string(pyeval('vim.Dictionary(a=1)'))
+:$put =string(pyeval('vim.Dictionary(((''a'', 1),))'))
+:$put =string(pyeval('vim.List()'))
+:$put =string(pyeval('vim.List(iter(''abc7''))'))
+:$put =string(pyeval('vim.Function(''tr'')'))
+:$put =string(pyeval('vim.Function(''tr'', args=[123, 3, 4])'))
+:$put =string(pyeval('vim.Function(''tr'', args=[])'))
+:$put =string(pyeval('vim.Function(''tr'', self={})'))
+:$put =string(pyeval('vim.Function(''tr'', args=[123, 3, 4], self={})'))
+:$put ='auto_rebind'
+:$put =string(pyeval('vim.Function(''tr'', auto_rebind=False)'))
+:$put =string(pyeval('vim.Function(''tr'', args=[123, 3, 4], auto_rebind=False)'))
+:$put =string(pyeval('vim.Function(''tr'', args=[], auto_rebind=False)'))
+:$put =string(pyeval('vim.Function(''tr'', self={}, auto_rebind=False)'))
+:$put =string(pyeval('vim.Function(''tr'', args=[123, 3, 4], self={}, auto_rebind=False)'))
+:"
+:" Test vim.Function
+:function Args(...)
+: return a:000
+:endfunction
+:function SelfArgs(...) dict
+: return [a:000, self]
+:endfunction
+:" The following four lines should not crash
+:let Pt = function('tr', [[]], {'l': []})
+:py Pt = vim.bindeval('Pt')
+:unlet Pt
+:py del Pt
+py << EOF
+def ecall(out_prefix, func, *args, **kwargs):
+ line = out_prefix + ': '
+ try:
+ ret = func(*args, **kwargs)
+ except Exception:
+ line += '!exception: ' + emsg(sys.exc_info())
+ else:
+ line += '!result: ' + vim.Function('string')(ret)
+ cb.append(line)
+a = vim.Function('Args')
+pa1 = vim.Function('Args', args=['abcArgsPA1'])
+pa2 = vim.Function('Args', args=[])
+pa3 = vim.Function('Args', args=['abcArgsPA3'], self={'abcSelfPA3': 'abcSelfPA3Val'})
+pa4 = vim.Function('Args', self={'abcSelfPA4': 'abcSelfPA4Val'})
+cb.append('a: ' + repr(a))
+cb.append('pa1: ' + repr(pa1))
+cb.append('pa2: ' + repr(pa2))
+cb.append('pa3: ' + repr(pa3))
+cb.append('pa4: ' + repr(pa4))
+sa = vim.Function('SelfArgs')
+psa1 = vim.Function('SelfArgs', args=['abcArgsPSA1'])
+psa2 = vim.Function('SelfArgs', args=[])
+psa3 = vim.Function('SelfArgs', args=['abcArgsPSA3'], self={'abcSelfPSA3': 'abcSelfPSA3Val'})
+psa4 = vim.Function('SelfArgs', self={'abcSelfPSA4': 'abcSelfPSA4Val'})
+psa5 = vim.Function('SelfArgs', self={'abcSelfPSA5': 'abcSelfPSA5Val'}, auto_rebind=0)
+psa6 = vim.Function('SelfArgs', args=['abcArgsPSA6'], self={'abcSelfPSA6': 'abcSelfPSA6Val'}, auto_rebind=())
+psa7 = vim.Function('SelfArgs', args=['abcArgsPSA7'], auto_rebind=[])
+psa8 = vim.Function('SelfArgs', auto_rebind=False)
+psa9 = vim.Function('SelfArgs', self={'abcSelfPSA9': 'abcSelfPSA9Val'}, auto_rebind=True)
+psaA = vim.Function('SelfArgs', args=['abcArgsPSAA'], self={'abcSelfPSAA': 'abcSelfPSAAVal'}, auto_rebind=1)
+psaB = vim.Function('SelfArgs', args=['abcArgsPSAB'], auto_rebind={'abcARPSAB': 'abcARPSABVal'})
+psaC = vim.Function('SelfArgs', auto_rebind=['abcARPSAC'])
+cb.append('sa: ' + repr(sa))
+cb.append('psa1: ' + repr(psa1))
+cb.append('psa2: ' + repr(psa2))
+cb.append('psa3: ' + repr(psa3))
+cb.append('psa4: ' + repr(psa4))
+cb.append('psa5: ' + repr(psa5))
+cb.append('psa6: ' + repr(psa6))
+cb.append('psa7: ' + repr(psa7))
+cb.append('psa8: ' + repr(psa8))
+cb.append('psa9: ' + repr(psa9))
+cb.append('psaA: ' + repr(psaA))
+cb.append('psaB: ' + repr(psaB))
+cb.append('psaC: ' + repr(psaC))
+
+psar = vim.Function('SelfArgs', args=[{'abcArgsPSAr': 'abcArgsPSArVal'}], self={'abcSelfPSAr': 'abcSelfPSArVal'})
+psar.args[0]['abcArgsPSAr2'] = [psar.self, psar.args[0]]
+psar.self['rec'] = psar
+psar.self['self'] = psar.self
+psar.self['args'] = psar.args
+
+try:
+ cb.append('psar: ' + repr(psar))
+except Exception:
+ cb.append('!!!!!!!! Caught exception: ' + emsg(sys.exc_info()))
+EOF
+:$put ='s(a): '.string(pyeval('a'))
+:$put ='s(pa1): '.string(pyeval('pa1'))
+:$put ='s(pa2): '.string(pyeval('pa2'))
+:$put ='s(pa3): '.string(pyeval('pa3'))
+:$put ='s(pa4): '.string(pyeval('pa4'))
+:$put ='s(sa): '.string(pyeval('sa'))
+:$put ='s(psa1): '.string(pyeval('psa1'))
+:$put ='s(psa2): '.string(pyeval('psa2'))
+:$put ='s(psa3): '.string(pyeval('psa3'))
+:$put ='s(psa4): '.string(pyeval('psa4'))
+:$put ='s(psa5): '.string(pyeval('psa5'))
+:$put ='s(psa6): '.string(pyeval('psa6'))
+:$put ='s(psa7): '.string(pyeval('psa7'))
+:$put ='s(psa8): '.string(pyeval('psa8'))
+:$put ='s(psa9): '.string(pyeval('psa9'))
+:$put ='s(psaA): '.string(pyeval('psaA'))
+:$put ='s(psaB): '.string(pyeval('psaB'))
+:$put ='s(psaC): '.string(pyeval('psaC'))
+:
+:for v in ['sa', 'psa1', 'psa2', 'psa3', 'psa4', 'psa5', 'psa6', 'psa7', 'psa8', 'psa9', 'psaA', 'psaB', 'psaC']
+: let d = {'f': pyeval(v)}
+: $put ='d.'.v.'(): '.string(d.f())
+:endfor
+:
+:py ecall('a()', a, )
+:py ecall('pa1()', pa1, )
+:py ecall('pa2()', pa2, )
+:py ecall('pa3()', pa3, )
+:py ecall('pa4()', pa4, )
+:py ecall('sa()', sa, )
+:py ecall('psa1()', psa1, )
+:py ecall('psa2()', psa2, )
+:py ecall('psa3()', psa3, )
+:py ecall('psa4()', psa4, )
+:
+:py ecall('a(42, 43)', a, 42, 43)
+:py ecall('pa1(42, 43)', pa1, 42, 43)
+:py ecall('pa2(42, 43)', pa2, 42, 43)
+:py ecall('pa3(42, 43)', pa3, 42, 43)
+:py ecall('pa4(42, 43)', pa4, 42, 43)
+:py ecall('sa(42, 43)', sa, 42, 43)
+:py ecall('psa1(42, 43)', psa1, 42, 43)
+:py ecall('psa2(42, 43)', psa2, 42, 43)
+:py ecall('psa3(42, 43)', psa3, 42, 43)
+:py ecall('psa4(42, 43)', psa4, 42, 43)
+:
+:py ecall('a(42, self={"20": 1})', a, 42, self={'20': 1})
+:py ecall('pa1(42, self={"20": 1})', pa1, 42, self={'20': 1})
+:py ecall('pa2(42, self={"20": 1})', pa2, 42, self={'20': 1})
+:py ecall('pa3(42, self={"20": 1})', pa3, 42, self={'20': 1})
+:py ecall('pa4(42, self={"20": 1})', pa4, 42, self={'20': 1})
+:py ecall('sa(42, self={"20": 1})', sa, 42, self={'20': 1})
+:py ecall('psa1(42, self={"20": 1})', psa1, 42, self={'20': 1})
+:py ecall('psa2(42, self={"20": 1})', psa2, 42, self={'20': 1})
+:py ecall('psa3(42, self={"20": 1})', psa3, 42, self={'20': 1})
+:py ecall('psa4(42, self={"20": 1})', psa4, 42, self={'20': 1})
+:
+:py ecall('a(self={"20": 1})', a, self={'20': 1})
+:py ecall('pa1(self={"20": 1})', pa1, self={'20': 1})
+:py ecall('pa2(self={"20": 1})', pa2, self={'20': 1})
+:py ecall('pa3(self={"20": 1})', pa3, self={'20': 1})
+:py ecall('pa4(self={"20": 1})', pa4, self={'20': 1})
+:py ecall('sa(self={"20": 1})', sa, self={'20': 1})
+:py ecall('psa1(self={"20": 1})', psa1, self={'20': 1})
+:py ecall('psa2(self={"20": 1})', psa2, self={'20': 1})
+:py ecall('psa3(self={"20": 1})', psa3, self={'20': 1})
+:py ecall('psa4(self={"20": 1})', psa4, self={'20': 1})
+py << EOF
+def s(v):
+ if v is None:
+ return repr(v)
+ else:
+ return vim.Function('string')(v)
+
+cb.append('a.args: ' + s(a.args))
+cb.append('pa1.args: ' + s(pa1.args))
+cb.append('pa2.args: ' + s(pa2.args))
+cb.append('pa3.args: ' + s(pa3.args))
+cb.append('pa4.args: ' + s(pa4.args))
+cb.append('sa.args: ' + s(sa.args))
+cb.append('psa1.args: ' + s(psa1.args))
+cb.append('psa2.args: ' + s(psa2.args))
+cb.append('psa3.args: ' + s(psa3.args))
+cb.append('psa4.args: ' + s(psa4.args))
+
+cb.append('a.self: ' + s(a.self))
+cb.append('pa1.self: ' + s(pa1.self))
+cb.append('pa2.self: ' + s(pa2.self))
+cb.append('pa3.self: ' + s(pa3.self))
+cb.append('pa4.self: ' + s(pa4.self))
+cb.append('sa.self: ' + s(sa.self))
+cb.append('psa1.self: ' + s(psa1.self))
+cb.append('psa2.self: ' + s(psa2.self))
+cb.append('psa3.self: ' + s(psa3.self))
+cb.append('psa4.self: ' + s(psa4.self))
+
+cb.append('a.name: ' + s(a.name))
+cb.append('pa1.name: ' + s(pa1.name))
+cb.append('pa2.name: ' + s(pa2.name))
+cb.append('pa3.name: ' + s(pa3.name))
+cb.append('pa4.name: ' + s(pa4.name))
+cb.append('sa.name: ' + s(sa.name))
+cb.append('psa1.name: ' + s(psa1.name))
+cb.append('psa2.name: ' + s(psa2.name))
+cb.append('psa3.name: ' + s(psa3.name))
+cb.append('psa4.name: ' + s(psa4.name))
+
+cb.append('a.auto_rebind: ' + s(a.auto_rebind))
+cb.append('pa1.auto_rebind: ' + s(pa1.auto_rebind))
+cb.append('pa2.auto_rebind: ' + s(pa2.auto_rebind))
+cb.append('pa3.auto_rebind: ' + s(pa3.auto_rebind))
+cb.append('pa4.auto_rebind: ' + s(pa4.auto_rebind))
+cb.append('sa.auto_rebind: ' + s(sa.auto_rebind))
+cb.append('psa1.auto_rebind: ' + s(psa1.auto_rebind))
+cb.append('psa2.auto_rebind: ' + s(psa2.auto_rebind))
+cb.append('psa3.auto_rebind: ' + s(psa3.auto_rebind))
+cb.append('psa4.auto_rebind: ' + s(psa4.auto_rebind))
+cb.append('psa5.auto_rebind: ' + s(psa5.auto_rebind))
+cb.append('psa6.auto_rebind: ' + s(psa6.auto_rebind))
+cb.append('psa7.auto_rebind: ' + s(psa7.auto_rebind))
+cb.append('psa8.auto_rebind: ' + s(psa8.auto_rebind))
+cb.append('psa9.auto_rebind: ' + s(psa9.auto_rebind))
+cb.append('psaA.auto_rebind: ' + s(psaA.auto_rebind))
+cb.append('psaB.auto_rebind: ' + s(psaB.auto_rebind))
+cb.append('psaC.auto_rebind: ' + s(psaC.auto_rebind))
+
+del s
+
+del a
+del pa1
+del pa2
+del pa3
+del pa4
+del sa
+del psa1
+del psa2
+del psa3
+del psa4
+del psa5
+del psa6
+del psa7
+del psa8
+del psa9
+del psaA
+del psaB
+del psaC
+del psar
+
+del ecall
+EOF
+:"
+:" Test stdout/stderr
+:redir => messages
+:py sys.stdout.write('abc8') ; sys.stdout.write('def')
+:py sys.stderr.write('abc9') ; sys.stderr.write('def')
+:py sys.stdout.writelines(iter('abcA'))
+:py sys.stderr.writelines(iter('abcB'))
+:redir END
+:$put =string(substitute(messages, '\d\+', '', 'g'))
+:" Test subclassing
+:fun Put(...)
+: $put =string(a:000)
+: return a:000
+:endfun
+py << EOF
+class DupDict(vim.Dictionary):
+ def __setitem__(self, key, value):
+ super(DupDict, self).__setitem__(key, value)
+ super(DupDict, self).__setitem__('dup_' + key, value)
+dd = DupDict()
+dd['a'] = 'b'
+
+class DupList(vim.List):
+ def __getitem__(self, idx):
+ return [super(DupList, self).__getitem__(idx)] * 2
+
+dl = DupList()
+dl2 = DupList(iter('abcC'))
+dl.extend(dl2[0])
+
+class DupFun(vim.Function):
+ def __call__(self, arg):
+ return super(DupFun, self).__call__(arg, arg)
+
+df = DupFun('Put')
+EOF
+:$put =string(sort(keys(pyeval('dd'))))
+:$put =string(pyeval('dl'))
+:$put =string(pyeval('dl2'))
+:$put =string(pyeval('df(2)'))
+:$put =string(pyeval('dl') is# pyeval('dl'))
+:$put =string(pyeval('dd') is# pyeval('dd'))
+:$put =string(pyeval('df'))
+:delfunction Put
+py << EOF
+del DupDict
+del DupList
+del DupFun
+del dd
+del dl
+del dl2
+del df
+EOF
+:"
+:" Test chdir
+py << EOF
+import os
+fnamemodify = vim.Function('fnamemodify')
+cb.append(fnamemodify('.', ':p:h:t'))
+cb.append(vim.eval('@%'))
+os.chdir('..')
+path = fnamemodify('.', ':p:h:t')
+if path != 'src':
+ # Running tests from a shadow directory, so move up another level
+ # This will result in @% looking like shadow/testdir/test86.in, hence the
+ # extra fnamemodify
+ os.chdir('..')
+ cb.append(fnamemodify('.', ':p:h:t'))
+ cb.append(fnamemodify(vim.eval('@%'), ':s?^%s.??' % path).replace(os.path.sep, '/'))
+ os.chdir(path)
+ del path
+else:
+ cb.append(fnamemodify('.', ':p:h:t'))
+ cb.append(vim.eval('@%').replace(os.path.sep, '/'))
+os.chdir('testdir')
+cb.append(fnamemodify('.', ':p:h:t'))
+cb.append(vim.eval('@%'))
+del fnamemodify
+EOF
+:"
+:" Test errors
+:fun F() dict
+:endfun
+:fun D()
+:endfun
+py << EOF
+d = vim.Dictionary()
+ned = vim.Dictionary(foo='bar', baz='abcD')
+dl = vim.Dictionary(a=1)
+dl.locked = True
+l = vim.List()
+ll = vim.List('abcE')
+ll.locked = True
+nel = vim.List('abcO')
+f = vim.Function('string')
+fd = vim.Function('F')
+fdel = vim.Function('D')
+vim.command('delfunction D')
+
+def subexpr_test(expr, name, subexprs):
+ cb.append('>>> Testing %s using %s' % (name, expr))
+ for subexpr in subexprs:
+ ee(expr % subexpr)
+ cb.append('<<< Finished')
+
+def stringtochars_test(expr):
+ return subexpr_test(expr, 'StringToChars', (
+ '1', # Fail type checks
+ 'u"\\0"', # Fail PyString_AsStringAndSize(bytes, , NULL) check
+ '"\\0"', # Fail PyString_AsStringAndSize(object, , NULL) check
+ ))
+
+class Mapping(object):
+ def __init__(self, d):
+ self.d = d
+
+ def __getitem__(self, key):
+ return self.d[key]
+
+ def keys(self):
+ return self.d.keys()
+
+ def items(self):
+ return self.d.items()
+
+def convertfrompyobject_test(expr, recurse=True):
+ # pydict_to_tv
+ stringtochars_test(expr % '{%s : 1}')
+ if recurse:
+ convertfrompyobject_test(expr % '{"abcF" : %s}', False)
+ # pymap_to_tv
+ stringtochars_test(expr % 'Mapping({%s : 1})')
+ if recurse:
+ convertfrompyobject_test(expr % 'Mapping({"abcG" : %s})', False)
+ # pyseq_to_tv
+ iter_test(expr)
+ return subexpr_test(expr, 'ConvertFromPyObject', (
+ 'None', # Not conversible
+ '{"": 1}', # Empty key not allowed
+ '{u"": 1}', # Same, but with unicode object
+ 'FailingMapping()', #
+ 'FailingMappingKey()', #
+ 'FailingNumber()', #
+ ))
+
+def convertfrompymapping_test(expr):
+ convertfrompyobject_test(expr)
+ return subexpr_test(expr, 'ConvertFromPyMapping', (
+ '[]',
+ ))
+
+def iter_test(expr):
+ return subexpr_test(expr, '*Iter*', (
+ 'FailingIter()',
+ 'FailingIterNext()',
+ ))
+
+def number_test(expr, natural=False, unsigned=False):
+ if natural:
+ unsigned = True
+ return subexpr_test(expr, 'NumberToLong', (
+ '[]',
+ 'None',
+ ) + (unsigned and ('-1',) or ())
+ + (natural and ('0',) or ()))
+
+class FailingTrue(object):
+ def __nonzero__(self):
+ raise NotImplementedError('bool')
+
+class FailingIter(object):
+ def __iter__(self):
+ raise NotImplementedError('iter')
+
+class FailingIterNext(object):
+ def __iter__(self):
+ return self
+
+ def next(self):
+ raise NotImplementedError('next')
+
+class FailingIterNextN(object):
+ def __init__(self, n):
+ self.n = n
+
+ def __iter__(self):
+ return self
+
+ def next(self):
+ if self.n:
+ self.n -= 1
+ return 1
+ else:
+ raise NotImplementedError('next N')
+
+class FailingMappingKey(object):
+ def __getitem__(self, item):
+ raise NotImplementedError('getitem:mappingkey')
+
+ def keys(self):
+ return list("abcH")
+
+class FailingMapping(object):
+ def __getitem__(self):
+ raise NotImplementedError('getitem:mapping')
+
+ def keys(self):
+ raise NotImplementedError('keys')
+
+class FailingList(list):
+ def __getitem__(self, idx):
+ if i == 2:
+ raise NotImplementedError('getitem:list')
+ else:
+ return super(FailingList, self).__getitem__(idx)
+
+class NoArgsCall(object):
+ def __call__(self):
+ pass
+
+class FailingCall(object):
+ def __call__(self, path):
+ raise NotImplementedError('call')
+
+class FailingNumber(object):
+ def __int__(self):
+ raise NotImplementedError('int')
+
+cb.append("> Output")
+cb.append(">> OutputSetattr")
+ee('del sys.stdout.softspace')
+number_test('sys.stdout.softspace = %s', unsigned=True)
+number_test('sys.stderr.softspace = %s', unsigned=True)
+ee('assert sys.stdout.isatty()==False')
+ee('assert sys.stdout.seekable()==False')
+ee('sys.stdout.close()')
+ee('sys.stdout.flush()')
+ee('assert sys.stderr.isatty()==False')
+ee('assert sys.stderr.seekable()==False')
+ee('sys.stderr.close()')
+ee('sys.stderr.flush()')
+ee('sys.stdout.attr = None')
+cb.append(">> OutputWrite")
+ee('assert sys.stdout.writable()==True')
+ee('assert sys.stdout.readable()==False')
+ee('assert sys.stderr.writable()==True')
+ee('assert sys.stderr.readable()==False')
+ee('assert sys.stdout.closed()==False')
+ee('assert sys.stderr.closed()==False')
+ee('assert sys.stdout.errors=="strict"')
+ee('assert sys.stderr.errors=="strict"')
+ee('assert sys.stdout.encoding==sys.stderr.encoding')
+ee('sys.stdout.write(None)')
+cb.append(">> OutputWriteLines")
+ee('sys.stdout.writelines(None)')
+ee('sys.stdout.writelines([1])')
+iter_test('sys.stdout.writelines(%s)')
+cb.append("> VimCommand")
+stringtochars_test('vim.command(%s)')
+ee('vim.command("", 2)')
+#! Not checked: vim->python exceptions translating: checked later
+cb.append("> VimToPython")
+#! Not checked: everything: needs errors in internal python functions
+cb.append("> VimEval")
+stringtochars_test('vim.eval(%s)')
+ee('vim.eval("", FailingTrue())')
+#! Not checked: everything: needs errors in internal python functions
+cb.append("> VimEvalPy")
+stringtochars_test('vim.bindeval(%s)')
+ee('vim.eval("", 2)')
+#! Not checked: vim->python exceptions translating: checked later
+cb.append("> VimStrwidth")
+stringtochars_test('vim.strwidth(%s)')
+cb.append("> VimForeachRTP")
+ee('vim.foreach_rtp(None)')
+ee('vim.foreach_rtp(NoArgsCall())')
+ee('vim.foreach_rtp(FailingCall())')
+ee('vim.foreach_rtp(int, 2)')
+cb.append('> import')
+old_rtp = vim.options['rtp']
+vim.options['rtp'] = os.getcwd().replace('\\', '\\\\').replace(',', '\\,')
+ee('import xxx_no_such_module_xxx')
+ee('import failing_import')
+ee('import failing')
+vim.options['rtp'] = old_rtp
+del old_rtp
+cb.append("> Options")
+cb.append(">> OptionsItem")
+ee('vim.options["abcQ"]')
+ee('vim.options[""]')
+stringtochars_test('vim.options[%s]')
+cb.append(">> OptionsContains")
+stringtochars_test('%s in vim.options')
+cb.append("> Dictionary")
+cb.append(">> DictionaryConstructor")
+ee('vim.Dictionary("abcI")')
+##! Not checked: py_dict_alloc failure
+cb.append(">> DictionarySetattr")
+ee('del d.locked')
+ee('d.locked = FailingTrue()')
+ee('vim.vvars.locked = False')
+ee('d.scope = True')
+ee('d.xxx = True')
+cb.append(">> _DictionaryItem")
+ee('d.get("a", 2, 3)')
+stringtochars_test('d.get(%s)')
+ee('d.pop("a")')
+ee('dl.pop("a")')
+cb.append(">> DictionaryContains")
+ee('"" in d')
+ee('0 in d')
+cb.append(">> DictionaryIterNext")
+ee('for i in ned: ned["a"] = 1')
+del i
+cb.append(">> DictionaryAssItem")
+ee('dl["b"] = 1')
+stringtochars_test('d[%s] = 1')
+convertfrompyobject_test('d["a"] = %s')
+cb.append(">> DictionaryUpdate")
+cb.append(">>> kwargs")
+cb.append(">>> iter")
+ee('d.update(FailingMapping())')
+ee('d.update([FailingIterNext()])')
+ee('d.update([FailingIterNextN(1)])')
+iter_test('d.update(%s)')
+convertfrompyobject_test('d.update(%s)')
+stringtochars_test('d.update(((%s, 0),))')
+convertfrompyobject_test('d.update((("a", %s),))')
+cb.append(">> DictionaryPopItem")
+ee('d.popitem(1, 2)')
+cb.append(">> DictionaryHasKey")
+ee('d.has_key()')
+cb.append("> List")
+cb.append(">> ListConstructor")
+ee('vim.List(1, 2)')
+ee('vim.List(a=1)')
+iter_test('vim.List(%s)')
+convertfrompyobject_test('vim.List([%s])')
+cb.append(">> ListItem")
+ee('l[1000]')
+cb.append(">> ListAssItem")
+ee('ll[1] = 2')
+ee('l[1000] = 3')
+cb.append(">> ListAssSlice")
+ee('ll[1:100] = "abcJ"')
+iter_test('l[:] = %s')
+ee('nel[1:10:2] = "abcK"')
+cb.append(repr(tuple(nel)))
+ee('nel[1:10:2] = "a"')
+cb.append(repr(tuple(nel)))
+ee('nel[1:1:-1] = "a"')
+cb.append(repr(tuple(nel)))
+ee('nel[:] = FailingIterNextN(2)')
+cb.append(repr(tuple(nel)))
+convertfrompyobject_test('l[:] = [%s]')
+cb.append(">> ListConcatInPlace")
+iter_test('l.extend(%s)')
+convertfrompyobject_test('l.extend([%s])')
+cb.append(">> ListSetattr")
+ee('del l.locked')
+ee('l.locked = FailingTrue()')
+ee('l.xxx = True')
+cb.append("> Function")
+cb.append(">> FunctionConstructor")
+cb.append(">>> FunctionConstructor")
+ee('vim.Function("123")')
+ee('vim.Function("xxx_non_existent_function_xxx")')
+ee('vim.Function("xxx#non#existent#function#xxx")')
+ee('vim.Function("xxx_non_existent_function_xxx2", args=[])')
+ee('vim.Function("xxx_non_existent_function_xxx3", self={})')
+ee('vim.Function("xxx_non_existent_function_xxx4", args=[], self={})')
+cb.append(">>> FunctionNew")
+ee('vim.Function("tr", self="abcFuncSelf")')
+ee('vim.Function("tr", args=427423)')
+ee('vim.Function("tr", self="abcFuncSelf2", args="abcFuncArgs2")')
+ee('vim.Function(self="abcFuncSelf2", args="abcFuncArgs2")')
+ee('vim.Function("tr", "", self="abcFuncSelf2", args="abcFuncArgs2")')
+ee('vim.Function("tr", "")')
+cb.append(">> FunctionCall")
+convertfrompyobject_test('f(%s)')
+convertfrompymapping_test('fd(self=%s)')
+cb.append("> TabPage")
+cb.append(">> TabPageAttr")
+ee('vim.current.tabpage.xxx')
+cb.append("> TabList")
+cb.append(">> TabListItem")
+ee('vim.tabpages[1000]')
+cb.append("> Window")
+cb.append(">> WindowAttr")
+ee('vim.current.window.xxx')
+cb.append(">> WindowSetattr")
+ee('vim.current.window.buffer = 0')
+ee('vim.current.window.cursor = (100000000, 100000000)')
+ee('vim.current.window.cursor = True')
+number_test('vim.current.window.height = %s', unsigned=True)
+number_test('vim.current.window.width = %s', unsigned=True)
+ee('vim.current.window.xxxxxx = True')
+cb.append("> WinList")
+cb.append(">> WinListItem")
+ee('vim.windows[1000]')
+cb.append("> Buffer")
+cb.append(">> StringToLine (indirect)")
+ee('vim.current.buffer[0] = u"\\na"')
+ee('vim.current.buffer[0] = "\\na"')
+cb.append(">> SetBufferLine (indirect)")
+ee('vim.current.buffer[0] = True')
+cb.append(">> SetBufferLineList (indirect)")
+ee('vim.current.buffer[:] = True')
+ee('vim.current.buffer[:] = ["\\na", "bc"]')
+cb.append(">> InsertBufferLines (indirect)")
+ee('vim.current.buffer.append(None)')
+ee('vim.current.buffer.append(["\\na", "bc"])')
+ee('vim.current.buffer.append("\\nbc")')
+cb.append(">> RBItem")
+ee('vim.current.buffer[100000000]')
+cb.append(">> RBAsItem")
+ee('vim.current.buffer[100000000] = ""')
+cb.append(">> BufferAttr")
+ee('vim.current.buffer.xxx')
+cb.append(">> BufferSetattr")
+ee('vim.current.buffer.name = True')
+ee('vim.current.buffer.xxx = True')
+cb.append(">> BufferMark")
+ee('vim.current.buffer.mark(0)')
+ee('vim.current.buffer.mark("abcM")')
+ee('vim.current.buffer.mark("!")')
+cb.append(">> BufferRange")
+ee('vim.current.buffer.range(1, 2, 3)')
+cb.append("> BufMap")
+cb.append(">> BufMapItem")
+ee('vim.buffers[100000000]')
+number_test('vim.buffers[%s]', natural=True)
+cb.append("> Current")
+cb.append(">> CurrentGetattr")
+ee('vim.current.xxx')
+cb.append(">> CurrentSetattr")
+ee('vim.current.line = True')
+ee('vim.current.buffer = True')
+ee('vim.current.window = True')
+ee('vim.current.tabpage = True')
+ee('vim.current.xxx = True')
+del d
+del ned
+del dl
+del l
+del ll
+del nel
+del f
+del fd
+del fdel
+del subexpr_test
+del stringtochars_test
+del Mapping
+del convertfrompyobject_test
+del convertfrompymapping_test
+del iter_test
+del number_test
+del FailingTrue
+del FailingIter
+del FailingIterNext
+del FailingIterNextN
+del FailingMapping
+del FailingMappingKey
+del FailingList
+del NoArgsCall
+del FailingCall
+del FailingNumber
+EOF
+:delfunction F
+:"
+:" Test import
+py << EOF
+sys.path.insert(0, os.path.join(os.getcwd(), 'python_before'))
+sys.path.append(os.path.join(os.getcwd(), 'python_after'))
+vim.options['rtp'] = os.getcwd().replace(',', '\\,').replace('\\', '\\\\')
+l = []
+def callback(path):
+ l.append(path[-len('/testdir'):].replace(os.path.sep, '/'))
+vim.foreach_rtp(callback)
+cb.append(repr(l))
+del l
+def callback(path):
+ return path[-len('/testdir'):].replace(os.path.sep, '/')
+cb.append(repr(vim.foreach_rtp(callback)))
+del callback
+from module import dir as d
+from modulex import ddir
+cb.append(d + ',' + ddir)
+import before
+cb.append(before.dir)
+import after
+cb.append(after.dir)
+import topmodule as tm
+import topmodule.submodule as tms
+import topmodule.submodule.subsubmodule.subsubsubmodule as tmsss
+cb.append(tm.__file__.replace('.pyc', '.py').replace(os.path.sep, '/')[-len('modulex/topmodule/__init__.py'):])
+cb.append(tms.__file__.replace('.pyc', '.py').replace(os.path.sep, '/')[-len('modulex/topmodule/submodule/__init__.py'):])
+cb.append(tmsss.__file__.replace('.pyc', '.py').replace(os.path.sep, '/')[-len('modulex/topmodule/submodule/subsubmodule/subsubsubmodule.py'):])
+del before
+del after
+del d
+del ddir
+del tm
+del tms
+del tmsss
+EOF
+:"
+:" Test exceptions
+:fun Exe(e)
+: execute a:e
+:endfun
+py << EOF
+Exe = vim.bindeval('function("Exe")')
+ee('vim.command("throw \'abcN\'")')
+ee('Exe("throw \'def\'")')
+ee('vim.eval("Exe(\'throw \'\'ghi\'\'\')")')
+ee('vim.eval("Exe(\'echoerr \'\'jkl\'\'\')")')
+ee('vim.eval("Exe(\'xxx_non_existent_command_xxx\')")')
+ee('vim.eval("xxx_unknown_function_xxx()")')
+ee('vim.bindeval("Exe(\'xxx_non_existent_command_xxx\')")')
+del Exe
+EOF
+:delfunction Exe
+:"
+:" Regression: interrupting vim.command propagates to next vim.command
+py << EOF
+def test_keyboard_interrupt():
+ try:
+ vim.command('while 1 | endwhile')
+ except KeyboardInterrupt:
+ cb.append('Caught KeyboardInterrupt')
+ except Exception:
+ cb.append('!!!!!!!! Caught exception: ' + emsg(sys.exc_info()))
+ else:
+ cb.append('!!!!!!!! No exception')
+ try:
+ vim.command('$ put =\'Running :put\'')
+ except KeyboardInterrupt:
+ cb.append('!!!!!!!! Caught KeyboardInterrupt')
+ except Exception:
+ cb.append('!!!!!!!! Caught exception: ' + emsg(sys.exc_info()))
+ else:
+ cb.append('No exception')
+EOF
+:debuggreedy
+:call inputsave()
+:call feedkeys("s\ns\ns\ns\nq\n")
+:redir => output
+:debug silent! py test_keyboard_interrupt()
+:redir END
+:0 debuggreedy
+:call inputrestore()
+:silent $put =output
+:unlet output
+:py del test_keyboard_interrupt
+:"
+:" Cleanup
+py << EOF
+del cb
+del ee
+del emsg
+del sys
+del os
+del vim
+EOF
+:endfun
+:"
+:fun RunTest()
+:let checkrefs = !empty($PYTHONDUMPREFS)
+:let start = getline(1, '$')
+:for i in range(checkrefs ? 10 : 1)
+: if i != 0
+: %d _
+: call setline(1, start)
+: endif
+: call Test()
+: if i == 0
+: let result = getline(1, '$')
+: endif
+:endfor
+:if checkrefs
+: %d _
+: call setline(1, result)
+:endif
+:endfun
+:"
+:call RunTest()
+:delfunction RunTest
+:delfunction Test
+:call garbagecollect(1)
+:"
+:/^start:/,$wq! test.out
+:" vim: et ts=4 isk-=\:
+:while getchar(0) isnot 0|endwhile
+ENDTEST
+
+start:
diff --git a/src/testdir/test86.ok b/src/testdir/test86.ok
new file mode 100644
index 0000000..24d3fd4
--- /dev/null
+++ b/src/testdir/test86.ok
@@ -0,0 +1,1445 @@
+start:
+[1, 'as''d', [1, 2, function('strlen'), {'a': 1}]]
+[1, 2, function('strlen'), {'a': 1}]
+Vim(put):E684:
+[0, 'as''d', [1, 2, function('strlen'), {'a': 1}]]
+[0, function('strlen'), [1, 2, function('strlen'), {'a': 1}]]
+1
+['-1', '0', '1', 'b', 'f']
+['asd', -1L, <vim.Function '1'>, <vim.dictionary object at >, <vim.list object at >]
+[('-1', <vim.dictionary object at >), ('0', -1L), ('1', 'asd'), ('b', <vim.list object at >), ('f', <vim.Function '1'>)]
+'-1' : {'a': 1}
+'0' : -1
+'1' : 'asd'
+'b' : [1, 2, function('strlen')]
+'f' : function('1')
+[0, function('strlen')]
+[3]
+[1, 2, function('strlen')]
+[1, 2, function('strlen')]
+1
+'asd'
+2
+True
+False
+True
+False
+['0']
+{'0': -1}
+('0', -1L)
+None
+[]
+[0, 1, 2, 3]
+[0, 1, 2, 3]
+[0, 1, 3]
+[0, 1]
+[0, 1]
+[0, 1]
+[0, 1, 2, 3]
+[0, 1, 2, 3]
+[0, 2, 3]
+[2, 3]
+[2, 3]
+[2, 3]
+[1, 3]
+[0, 2]
+[0, 1, 2, 3]
+['a', 0, 1, 2, 3]
+[0, 'b', 2, 3]
+[0, 1, 'c']
+[0, 1, 2, 3, 'd']
+[0, 1, 2, 'e', 3]
+['f', 2, 3]
+[0, 1, 'g', 2, 3]
+['h']
+[0, 1, 10, 3, 20, 5, 6, 7]
+[0, 1, 2, 3, 20, 5, 10, 7]
+[0, 1, 2, 3, 4, 5, 6, 7]
+[0, 1, 2, 3, 4, 5, 6, 7]
+[0, 1, 2, 3, 4, 5, 6, 7]
+l[2] threw vim.error: error:('list is locked',)
+[0, 1, 2, 3]
+[function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd']
+[function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd', 'DictNewStart', 1, 2, 3, 'DictNewEnd', {'a': 'b'}]
+[function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd', 'DictNewStart', 1, 2, 3, 'DictNewEnd', {'a': 'b'}, 'New']
+l[1](1, 2, 3):error:('Vim:E725: Calling dict function without Dictionary: DictNew',)
+f(1, 2, 3):error:('Vim:E117: Unknown function: New',)
+[0.0, 0.0]
+KeyError
+TypeError
+TypeError
+ValueError
+TypeError
+TypeError
+KeyError
+KeyError
+d : locked:0;scope:0
+dl : locked:1;scope:0
+v: : locked:2;scope:1
+g: : locked:0;scope:2
+d:{'abc2': 1}
+dl:{'def': 1}
+l : locked:0
+ll : locked:1
+l:[0]
+ll:[1]
+[0, 1, 2]
+['a', 'b']
+['c', 1]
+['d', ['e']]
+pyeval("None") = v:none
+0.0
+"\0": Vim(let):E859:
+{"\0": 1}: Vim(let):E859:
+undefined_name: Vim(let):Trace
+vim: Vim(let):E859:
+[1]
+[1, 10, 11, 10, 11, 10, 11, 10, 11, 10, 11, 10, 1]
+[0, 1, 2, 3]
+[2, 3, 4, 5]
+[0, 1]
+[4, 5]
+[2, 3]
+[]
+[2, 3]
+[]
+[0, 1, 2, 3, 4, 5]
+[0, 1, 2, 3, 4, 5]
+[0, 1, 2, 3, 4, 5]
+[4, 3]
+[0, 2, 4]
+[]
+Abc
+bac
+def
+bar
+jkl
+wopts iters equal: 1
+bopts iters equal: 1
+>>> paste
+ g/w/b:1/0/0
+ g/w/b (in):1/0/0
+ p/gopts1: False
+ p/wopts1! KeyError
+ inv: 2! KeyError
+ wopts1! KeyError
+ wopts2! KeyError
+ wopts3! KeyError
+ p/bopts1! KeyError
+ inv: 2! KeyError
+ bopts1! KeyError
+ bopts2! KeyError
+ bopts3! KeyError
+ G: 1
+ W: 1:1 2:1 3:1 4:1
+ B: 1:1 2:1 3:1 4:1
+ del wopts3! KeyError
+ del bopts3! KeyError
+ G: 1
+ W: 1:1 2:1 3:1 4:1
+ B: 1:1 2:1 3:1 4:1
+>>> previewheight
+ g/w/b:1/0/0
+ g/w/b (in):1/0/0
+ p/gopts1: 12
+ inv: 'a'! TypeError
+ p/wopts1! KeyError
+ inv: 'a'! KeyError
+ wopts1! KeyError
+ wopts2! KeyError
+ wopts3! KeyError
+ p/bopts1! KeyError
+ inv: 'a'! KeyError
+ bopts1! KeyError
+ bopts2! KeyError
+ bopts3! KeyError
+ G: 5
+ W: 1:5 2:5 3:5 4:5
+ B: 1:5 2:5 3:5 4:5
+ del wopts3! KeyError
+ del bopts3! KeyError
+ G: 5
+ W: 1:5 2:5 3:5 4:5
+ B: 1:5 2:5 3:5 4:5
+>>> operatorfunc
+ g/w/b:1/0/0
+ g/w/b (in):1/0/0
+ p/gopts1: ''
+ inv: 2! TypeError
+ p/wopts1! KeyError
+ inv: 2! KeyError
+ wopts1! KeyError
+ wopts2! KeyError
+ wopts3! KeyError
+ p/bopts1! KeyError
+ inv: 2! KeyError
+ bopts1! KeyError
+ bopts2! KeyError
+ bopts3! KeyError
+ G: 'A'
+ W: 1:'A' 2:'A' 3:'A' 4:'A'
+ B: 1:'A' 2:'A' 3:'A' 4:'A'
+ del wopts3! KeyError
+ del bopts3! KeyError
+ G: 'A'
+ W: 1:'A' 2:'A' 3:'A' 4:'A'
+ B: 1:'A' 2:'A' 3:'A' 4:'A'
+>>> number
+ g/w/b:0/1/0
+ g/w/b (in):0/1/0
+ p/gopts1! KeyError
+ inv: 0! KeyError
+ gopts1! KeyError
+ p/wopts1: False
+ p/bopts1! KeyError
+ inv: 0! KeyError
+ bopts1! KeyError
+ bopts2! KeyError
+ bopts3! KeyError
+ G: 0
+ W: 1:1 2:1 3:0 4:0
+ B: 1:1 2:1 3:0 4:0
+ del wopts3! ValueError
+ del bopts3! KeyError
+ G: 0
+ W: 1:1 2:1 3:0 4:0
+ B: 1:1 2:1 3:0 4:0
+>>> numberwidth
+ g/w/b:0/1/0
+ g/w/b (in):0/1/0
+ p/gopts1! KeyError
+ inv: -100! KeyError
+ gopts1! KeyError
+ p/wopts1: 8
+ inv: -100! error
+ p/bopts1! KeyError
+ inv: -100! KeyError
+ bopts1! KeyError
+ bopts2! KeyError
+ bopts3! KeyError
+ G: 8
+ W: 1:3 2:5 3:2 4:8
+ B: 1:3 2:5 3:2 4:8
+ del wopts3! ValueError
+ del bopts3! KeyError
+ G: 8
+ W: 1:3 2:5 3:2 4:8
+ B: 1:3 2:5 3:2 4:8
+>>> colorcolumn
+ g/w/b:0/1/0
+ g/w/b (in):0/1/0
+ p/gopts1! KeyError
+ inv: 'abc4'! KeyError
+ gopts1! KeyError
+ p/wopts1: ''
+ inv: 'abc4'! error
+ p/bopts1! KeyError
+ inv: 'abc4'! KeyError
+ bopts1! KeyError
+ bopts2! KeyError
+ bopts3! KeyError
+ G: ''
+ W: 1:'+2' 2:'+3' 3:'+1' 4:''
+ B: 1:'+2' 2:'+3' 3:'+1' 4:''
+ del wopts3! ValueError
+ del bopts3! KeyError
+ G: ''
+ W: 1:'+2' 2:'+3' 3:'+1' 4:''
+ B: 1:'+2' 2:'+3' 3:'+1' 4:''
+>>> statusline
+ g/w/b:1/1/0
+ g/w/b (in):1/1/0
+ p/gopts1: ''
+ inv: 0! TypeError
+ p/wopts1: None
+ inv: 0! TypeError
+ p/bopts1! KeyError
+ inv: 0! KeyError
+ bopts1! KeyError
+ bopts2! KeyError
+ bopts3! KeyError
+ G: '1'
+ W: 1:'2' 2:'4' 3:'1' 4:'1'
+ B: 1:'2' 2:'4' 3:'1' 4:'1'
+ del bopts3! KeyError
+ G: '1'
+ W: 1:'2' 2:'1' 3:'1' 4:'1'
+ B: 1:'2' 2:'1' 3:'1' 4:'1'
+>>> autoindent
+ g/w/b:0/0/1
+ g/w/b (in):0/0/1
+ p/gopts1! KeyError
+ inv: 2! KeyError
+ gopts1! KeyError
+ p/wopts1! KeyError
+ inv: 2! KeyError
+ wopts1! KeyError
+ wopts2! KeyError
+ wopts3! KeyError
+ p/bopts1: False
+ G: 0
+ W: 1:0 2:1 3:0 4:1
+ B: 1:0 2:1 3:0 4:1
+ del wopts3! KeyError
+ del bopts3! ValueError
+ G: 0
+ W: 1:0 2:1 3:0 4:1
+ B: 1:0 2:1 3:0 4:1
+>>> shiftwidth
+ g/w/b:0/0/1
+ g/w/b (in):0/0/1
+ p/gopts1! KeyError
+ inv: 3! KeyError
+ gopts1! KeyError
+ p/wopts1! KeyError
+ inv: 3! KeyError
+ wopts1! KeyError
+ wopts2! KeyError
+ wopts3! KeyError
+ p/bopts1: 8
+ G: 8
+ W: 1:0 2:2 3:8 4:1
+ B: 1:0 2:2 3:8 4:1
+ del wopts3! KeyError
+ del bopts3! ValueError
+ G: 8
+ W: 1:0 2:2 3:8 4:1
+ B: 1:0 2:2 3:8 4:1
+>>> omnifunc
+ g/w/b:0/0/1
+ g/w/b (in):0/0/1
+ p/gopts1! KeyError
+ inv: 1! KeyError
+ gopts1! KeyError
+ p/wopts1! KeyError
+ inv: 1! KeyError
+ wopts1! KeyError
+ wopts2! KeyError
+ wopts3! KeyError
+ p/bopts1: ''
+ inv: 1! TypeError
+ G: ''
+ W: 1:'A' 2:'B' 3:'' 4:'C'
+ B: 1:'A' 2:'B' 3:'' 4:'C'
+ del wopts3! KeyError
+ del bopts3! ValueError
+ G: ''
+ W: 1:'A' 2:'B' 3:'' 4:'C'
+ B: 1:'A' 2:'B' 3:'' 4:'C'
+>>> preserveindent
+ g/w/b:0/0/1
+ g/w/b (in):0/0/1
+ p/gopts1! KeyError
+ inv: 2! KeyError
+ gopts1! KeyError
+ p/wopts1! KeyError
+ inv: 2! KeyError
+ wopts1! KeyError
+ wopts2! KeyError
+ wopts3! KeyError
+ p/bopts1: False
+ G: 0
+ W: 1:0 2:1 3:0 4:1
+ B: 1:0 2:1 3:0 4:1
+ del wopts3! KeyError
+ del bopts3! ValueError
+ G: 0
+ W: 1:0 2:1 3:0 4:1
+ B: 1:0 2:1 3:0 4:1
+>>> path
+ g/w/b:1/0/1
+ g/w/b (in):1/0/1
+ p/gopts1: '.,..,,'
+ inv: 0! TypeError
+ p/wopts1! KeyError
+ inv: 0! KeyError
+ wopts1! KeyError
+ wopts2! KeyError
+ wopts3! KeyError
+ p/bopts1: None
+ inv: 0! TypeError
+ G: '.,,'
+ W: 1:'.,,' 2:',,' 3:'.,,' 4:'.'
+ B: 1:'.,,' 2:',,' 3:'.,,' 4:'.'
+ del wopts3! KeyError
+ G: '.,,'
+ W: 1:'.,,' 2:',,' 3:'.,,' 4:'.,,'
+ B: 1:'.,,' 2:',,' 3:'.,,' 4:'.,,'
+First line
+First line
+def
+First line
+Second line
+Third line
+(7, 2)
+<buffer test86.in><buffer >
+baz
+bar
+Second line
+Third line
+foo
+1:BufFilePre:1
+1:BufFilePost:1
+testdir/foo
+5:BufFilePre:5
+5:BufFilePost:5
+testdir/bar
+1:BufFilePre:1
+1:BufFilePost:1
+testdir/test86.in
+valid: b:False, cb:True
+i:<buffer test86.in>
+i2:<buffer test86.in>
+i:<buffer a>
+i3:<buffer test86.in>
+1:<buffer test86.in>=<buffer test86.in>
+8:<buffer a>=<buffer a>
+9:<buffer b>=<buffer b>
+10:<buffer c>=<buffer c>
+4
+i4:<buffer test86.in>
+i4:<buffer test86.in>
+StopIteration
+Number of tabs: 4
+Current tab pages:
+ <tabpage 0>(1): 1 windows, current is <window object (unknown)>
+ Windows:
+ <window object (unknown)>(1): displays buffer <buffer test86.in>; cursor is at (37, 0)
+ <tabpage 1>(2): 1 windows, current is <window object (unknown)>
+ Windows:
+ <window object (unknown)>(1): displays buffer <buffer 0>; cursor is at (1, 0)
+ <tabpage 2>(3): 2 windows, current is <window object (unknown)>
+ Windows:
+ <window object (unknown)>(1): displays buffer <buffer a.1>; cursor is at (1, 0)
+ <window object (unknown)>(2): displays buffer <buffer 1>; cursor is at (1, 0)
+ <tabpage 3>(4): 4 windows, current is <window 0>
+ Windows:
+ <window 0>(1): displays buffer <buffer c.2>; cursor is at (1, 0)
+ <window 1>(2): displays buffer <buffer b.2>; cursor is at (1, 0)
+ <window 2>(3): displays buffer <buffer a.2>; cursor is at (1, 0)
+ <window 3>(4): displays buffer <buffer 2>; cursor is at (1, 0)
+Number of windows in current tab page: 4
+Current tab page: <tabpage 3>
+Current window: <window 0>: <window 0> is <window 0>
+Current buffer: <buffer c.2>: <buffer c.2> is <buffer c.2> is <buffer c.2>
+ValueError at assigning foreign tab window
+Type error at assigning None to vim.current.window
+Type error at assigning None to vim.current.tabpage
+Type error at assigning None to vim.current.buffer
+Current tab page: <tabpage 2>
+Current window: <window 0>
+Current buffer: <buffer test86.in>
+Current line: 'Type error at assigning None to vim.current.buffer'
+w.valid: [True, False]
+t.valid: [True, False, True, False]
+vim.vars:Dictionary:True
+vim.options:Options:True
+vim.bindeval("{}"):Dictionary:True
+vim.bindeval("[]"):List:True
+vim.bindeval("function('tr')"):Function:True
+vim.current.buffer:Buffer:True
+vim.current.range:Range:True
+vim.current.window:Window:True
+vim.current.tabpage:TabPage:True
+current:__dir__,__members__,buffer,line,range,tabpage,window
+buffer:__dir__,__members__,append,mark,name,number,options,range,valid,vars
+window:__dir__,__members__,buffer,col,cursor,height,number,options,row,tabpage,valid,vars,width
+tabpage:__dir__,__members__,number,valid,vars,window,windows
+range:__dir__,__members__,append,end,start
+dictionary:__dir__,__members__,get,has_key,items,keys,locked,pop,popitem,scope,update,values
+list:__dir__,__members__,extend,locked
+function:__dir__,__members__,args,auto_rebind,self,softspace
+output:__dir__,__members__,close,closed,flush,isatty,readable,seekable,softspace,writable,write,writelines
+{}
+{'a': 1}
+{'a': 1}
+[]
+['a', 'b', 'c', '7']
+function('tr')
+function('tr', [123, 3, 4])
+function('tr')
+function('tr', {})
+function('tr', [123, 3, 4], {})
+auto_rebind
+function('tr')
+function('tr', [123, 3, 4])
+function('tr')
+function('tr', {})
+function('tr', [123, 3, 4], {})
+a: <vim.Function 'Args'>
+pa1: <vim.Function 'Args', args=['abcArgsPA1']>
+pa2: <vim.Function 'Args'>
+pa3: <vim.Function 'Args', args=['abcArgsPA3'], self={'abcSelfPA3': 'abcSelfPA3Val'}>
+pa4: <vim.Function 'Args', self={'abcSelfPA4': 'abcSelfPA4Val'}>
+sa: <vim.Function 'SelfArgs'>
+psa1: <vim.Function 'SelfArgs', args=['abcArgsPSA1']>
+psa2: <vim.Function 'SelfArgs'>
+psa3: <vim.Function 'SelfArgs', args=['abcArgsPSA3'], self={'abcSelfPSA3': 'abcSelfPSA3Val'}>
+psa4: <vim.Function 'SelfArgs', self={'abcSelfPSA4': 'abcSelfPSA4Val'}>
+psa5: <vim.Function 'SelfArgs', self={'abcSelfPSA5': 'abcSelfPSA5Val'}>
+psa6: <vim.Function 'SelfArgs', args=['abcArgsPSA6'], self={'abcSelfPSA6': 'abcSelfPSA6Val'}>
+psa7: <vim.Function 'SelfArgs', args=['abcArgsPSA7']>
+psa8: <vim.Function 'SelfArgs'>
+psa9: <vim.Function 'SelfArgs', self={'abcSelfPSA9': 'abcSelfPSA9Val'}, auto_rebind=True>
+psaA: <vim.Function 'SelfArgs', args=['abcArgsPSAA'], self={'abcSelfPSAA': 'abcSelfPSAAVal'}, auto_rebind=True>
+psaB: <vim.Function 'SelfArgs', args=['abcArgsPSAB']>
+psaC: <vim.Function 'SelfArgs'>
+psar: <vim.Function 'SelfArgs', args=[{'abcArgsPSAr2': [{'rec': function('SelfArgs', [{...}], {...}), 'self': {...}, 'abcSelfPSAr': 'abcSelfPSArVal', 'args': [{...}]}, {...}], 'abcArgsPSAr': 'abcArgsPSArVal'}], self={'rec': function('SelfArgs', [{'abcArgsPSAr2': [{...}, {...}], 'abcArgsPSAr': 'abcArgsPSArVal'}], {...}), 'self': {...}, 'abcSelfPSAr': 'abcSelfPSArVal', 'args': [{'abcArgsPSAr2': [{...}, {...}], 'abcArgsPSAr': 'abcArgsPSArVal'}]}>
+s(a): function('Args')
+s(pa1): function('Args', ['abcArgsPA1'])
+s(pa2): function('Args')
+s(pa3): function('Args', ['abcArgsPA3'], {'abcSelfPA3': 'abcSelfPA3Val'})
+s(pa4): function('Args', {'abcSelfPA4': 'abcSelfPA4Val'})
+s(sa): function('SelfArgs')
+s(psa1): function('SelfArgs', ['abcArgsPSA1'])
+s(psa2): function('SelfArgs')
+s(psa3): function('SelfArgs', ['abcArgsPSA3'], {'abcSelfPSA3': 'abcSelfPSA3Val'})
+s(psa4): function('SelfArgs', {'abcSelfPSA4': 'abcSelfPSA4Val'})
+s(psa5): function('SelfArgs', {'abcSelfPSA5': 'abcSelfPSA5Val'})
+s(psa6): function('SelfArgs', ['abcArgsPSA6'], {'abcSelfPSA6': 'abcSelfPSA6Val'})
+s(psa7): function('SelfArgs', ['abcArgsPSA7'])
+s(psa8): function('SelfArgs')
+s(psa9): function('SelfArgs', {'abcSelfPSA9': 'abcSelfPSA9Val'})
+s(psaA): function('SelfArgs', ['abcArgsPSAA'], {'abcSelfPSAA': 'abcSelfPSAAVal'})
+s(psaB): function('SelfArgs', ['abcArgsPSAB'])
+s(psaC): function('SelfArgs')
+d.sa(): [[], {'f': function('SelfArgs')}]
+d.psa1(): [['abcArgsPSA1'], {'f': function('SelfArgs', ['abcArgsPSA1'])}]
+d.psa2(): [[], {'f': function('SelfArgs')}]
+d.psa3(): [['abcArgsPSA3'], {'abcSelfPSA3': 'abcSelfPSA3Val'}]
+d.psa4(): [[], {'abcSelfPSA4': 'abcSelfPSA4Val'}]
+d.psa5(): [[], {'abcSelfPSA5': 'abcSelfPSA5Val'}]
+d.psa6(): [['abcArgsPSA6'], {'abcSelfPSA6': 'abcSelfPSA6Val'}]
+d.psa7(): [['abcArgsPSA7'], {'f': function('SelfArgs', ['abcArgsPSA7'])}]
+d.psa8(): [[], {'f': function('SelfArgs')}]
+d.psa9(): [[], {'f': function('SelfArgs', {'abcSelfPSA9': 'abcSelfPSA9Val'})}]
+d.psaA(): [['abcArgsPSAA'], {'f': function('SelfArgs', ['abcArgsPSAA'], {'abcSelfPSAA': 'abcSelfPSAAVal'})}]
+d.psaB(): [['abcArgsPSAB'], {'f': function('SelfArgs', ['abcArgsPSAB'])}]
+d.psaC(): [[], {'f': function('SelfArgs')}]
+a(): !result: []
+pa1(): !result: ['abcArgsPA1']
+pa2(): !result: []
+pa3(): !result: ['abcArgsPA3']
+pa4(): !result: []
+sa(): !exception: error:('Vim:E725: Calling dict function without Dictionary: SelfArgs',)
+psa1(): !exception: error:('Vim:E725: Calling dict function without Dictionary: SelfArgs',)
+psa2(): !exception: error:('Vim:E725: Calling dict function without Dictionary: SelfArgs',)
+psa3(): !result: [['abcArgsPSA3'], {'abcSelfPSA3': 'abcSelfPSA3Val'}]
+psa4(): !result: [[], {'abcSelfPSA4': 'abcSelfPSA4Val'}]
+a(42, 43): !result: [42, 43]
+pa1(42, 43): !result: ['abcArgsPA1', 42, 43]
+pa2(42, 43): !result: [42, 43]
+pa3(42, 43): !result: ['abcArgsPA3', 42, 43]
+pa4(42, 43): !result: [42, 43]
+sa(42, 43): !exception: error:('Vim:E725: Calling dict function without Dictionary: SelfArgs',)
+psa1(42, 43): !exception: error:('Vim:E725: Calling dict function without Dictionary: SelfArgs',)
+psa2(42, 43): !exception: error:('Vim:E725: Calling dict function without Dictionary: SelfArgs',)
+psa3(42, 43): !result: [['abcArgsPSA3', 42, 43], {'abcSelfPSA3': 'abcSelfPSA3Val'}]
+psa4(42, 43): !result: [[42, 43], {'abcSelfPSA4': 'abcSelfPSA4Val'}]
+a(42, self={"20": 1}): !result: [42]
+pa1(42, self={"20": 1}): !result: ['abcArgsPA1', 42]
+pa2(42, self={"20": 1}): !result: [42]
+pa3(42, self={"20": 1}): !result: ['abcArgsPA3', 42]
+pa4(42, self={"20": 1}): !result: [42]
+sa(42, self={"20": 1}): !result: [[42], {'20': 1}]
+psa1(42, self={"20": 1}): !result: [['abcArgsPSA1', 42], {'20': 1}]
+psa2(42, self={"20": 1}): !result: [[42], {'20': 1}]
+psa3(42, self={"20": 1}): !result: [['abcArgsPSA3', 42], {'20': 1}]
+psa4(42, self={"20": 1}): !result: [[42], {'20': 1}]
+a(self={"20": 1}): !result: []
+pa1(self={"20": 1}): !result: ['abcArgsPA1']
+pa2(self={"20": 1}): !result: []
+pa3(self={"20": 1}): !result: ['abcArgsPA3']
+pa4(self={"20": 1}): !result: []
+sa(self={"20": 1}): !result: [[], {'20': 1}]
+psa1(self={"20": 1}): !result: [['abcArgsPSA1'], {'20': 1}]
+psa2(self={"20": 1}): !result: [[], {'20': 1}]
+psa3(self={"20": 1}): !result: [['abcArgsPSA3'], {'20': 1}]
+psa4(self={"20": 1}): !result: [[], {'20': 1}]
+a.args: None
+pa1.args: ['abcArgsPA1']
+pa2.args: None
+pa3.args: ['abcArgsPA3']
+pa4.args: None
+sa.args: None
+psa1.args: ['abcArgsPSA1']
+psa2.args: None
+psa3.args: ['abcArgsPSA3']
+psa4.args: None
+a.self: None
+pa1.self: None
+pa2.self: None
+pa3.self: {'abcSelfPA3': 'abcSelfPA3Val'}
+pa4.self: {'abcSelfPA4': 'abcSelfPA4Val'}
+sa.self: None
+psa1.self: None
+psa2.self: None
+psa3.self: {'abcSelfPSA3': 'abcSelfPSA3Val'}
+psa4.self: {'abcSelfPSA4': 'abcSelfPSA4Val'}
+a.name: 'Args'
+pa1.name: 'Args'
+pa2.name: 'Args'
+pa3.name: 'Args'
+pa4.name: 'Args'
+sa.name: 'SelfArgs'
+psa1.name: 'SelfArgs'
+psa2.name: 'SelfArgs'
+psa3.name: 'SelfArgs'
+psa4.name: 'SelfArgs'
+a.auto_rebind: 1
+pa1.auto_rebind: 1
+pa2.auto_rebind: 1
+pa3.auto_rebind: 0
+pa4.auto_rebind: 0
+sa.auto_rebind: 1
+psa1.auto_rebind: 1
+psa2.auto_rebind: 1
+psa3.auto_rebind: 0
+psa4.auto_rebind: 0
+psa5.auto_rebind: 0
+psa6.auto_rebind: 0
+psa7.auto_rebind: 1
+psa8.auto_rebind: 1
+psa9.auto_rebind: 1
+psaA.auto_rebind: 1
+psaB.auto_rebind: 1
+psaC.auto_rebind: 1
+'
+abcdef
+Error detected while processing function RunTest[]..Test:
+line :
+abcdef
+abcA
+line :
+abcB'
+['a', 'dup_a']
+['a', 'a']
+['a', 'b', 'c', 'C']
+[2, 2]
+[2, 2]
+1
+1
+function('Put')
+testdir
+test86.in
+src
+testdir/test86.in
+testdir
+test86.in
+> Output
+>> OutputSetattr
+del sys.stdout.softspace:AttributeError:('cannot delete OutputObject attributes',)
+>>> Testing NumberToLong using sys.stdout.softspace = %s
+sys.stdout.softspace = []:TypeError:('expected int(), long() or something supporting coercing to long(), but got list',)
+sys.stdout.softspace = None:TypeError:('expected int(), long() or something supporting coercing to long(), but got NoneType',)
+sys.stdout.softspace = -1:ValueError:('number must be greater or equal to zero',)
+<<< Finished
+>>> Testing NumberToLong using sys.stderr.softspace = %s
+sys.stderr.softspace = []:TypeError:('expected int(), long() or something supporting coercing to long(), but got list',)
+sys.stderr.softspace = None:TypeError:('expected int(), long() or something supporting coercing to long(), but got NoneType',)
+sys.stderr.softspace = -1:ValueError:('number must be greater or equal to zero',)
+<<< Finished
+assert sys.stdout.isatty()==False:NOT FAILED
+assert sys.stdout.seekable()==False:NOT FAILED
+sys.stdout.close():NOT FAILED
+sys.stdout.flush():NOT FAILED
+assert sys.stderr.isatty()==False:NOT FAILED
+assert sys.stderr.seekable()==False:NOT FAILED
+sys.stderr.close():NOT FAILED
+sys.stderr.flush():NOT FAILED
+sys.stdout.attr = None:AttributeError:('invalid attribute: attr',)
+>> OutputWrite
+assert sys.stdout.writable()==True:NOT FAILED
+assert sys.stdout.readable()==False:NOT FAILED
+assert sys.stderr.writable()==True:NOT FAILED
+assert sys.stderr.readable()==False:NOT FAILED
+assert sys.stdout.closed()==False:NOT FAILED
+assert sys.stderr.closed()==False:NOT FAILED
+assert sys.stdout.errors=="strict":NOT FAILED
+assert sys.stderr.errors=="strict":NOT FAILED
+assert sys.stdout.encoding==sys.stderr.encoding:NOT FAILED
+sys.stdout.write(None):TypeError:('coercing to Unicode: need string or buffer, NoneType found',)
+>> OutputWriteLines
+sys.stdout.writelines(None):TypeError:("'NoneType' object is not iterable",)
+sys.stdout.writelines([1]):TypeError:('coercing to Unicode: need string or buffer, int found',)
+>>> Testing *Iter* using sys.stdout.writelines(%s)
+sys.stdout.writelines(FailingIter()):NotImplementedError:('iter',)
+sys.stdout.writelines(FailingIterNext()):NotImplementedError:('next',)
+<<< Finished
+> VimCommand
+>>> Testing StringToChars using vim.command(%s)
+vim.command(1):TypeError:('expected str() or unicode() instance, but got int',)
+vim.command(u"\0"):TypeError:('expected string without null bytes',)
+vim.command("\0"):TypeError:('expected string without null bytes',)
+<<< Finished
+vim.command("", 2):TypeError:('command() takes exactly one argument (2 given)',)
+> VimToPython
+> VimEval
+>>> Testing StringToChars using vim.eval(%s)
+vim.eval(1):TypeError:('expected str() or unicode() instance, but got int',)
+vim.eval(u"\0"):TypeError:('expected string without null bytes',)
+vim.eval("\0"):TypeError:('expected string without null bytes',)
+<<< Finished
+vim.eval("", FailingTrue()):TypeError:('function takes exactly 1 argument (2 given)',)
+> VimEvalPy
+>>> Testing StringToChars using vim.bindeval(%s)
+vim.bindeval(1):TypeError:('expected str() or unicode() instance, but got int',)
+vim.bindeval(u"\0"):TypeError:('expected string without null bytes',)
+vim.bindeval("\0"):TypeError:('expected string without null bytes',)
+<<< Finished
+vim.eval("", 2):TypeError:('function takes exactly 1 argument (2 given)',)
+> VimStrwidth
+>>> Testing StringToChars using vim.strwidth(%s)
+vim.strwidth(1):TypeError:('expected str() or unicode() instance, but got int',)
+vim.strwidth(u"\0"):TypeError:('expected string without null bytes',)
+vim.strwidth("\0"):TypeError:('expected string without null bytes',)
+<<< Finished
+> VimForeachRTP
+vim.foreach_rtp(None):TypeError:("'NoneType' object is not callable",)
+vim.foreach_rtp(NoArgsCall()):TypeError:('__call__() takes exactly 1 argument (2 given)',)
+vim.foreach_rtp(FailingCall()):NotImplementedError:('call',)
+vim.foreach_rtp(int, 2):TypeError:('foreach_rtp() takes exactly one argument (2 given)',)
+> import
+import xxx_no_such_module_xxx:ImportError:('No module named xxx_no_such_module_xxx',)
+import failing_import:ImportError:()
+import failing:NotImplementedError:()
+> Options
+>> OptionsItem
+vim.options["abcQ"]:KeyError:('abcQ',)
+vim.options[""]:ValueError:('empty keys are not allowed',)
+>>> Testing StringToChars using vim.options[%s]
+vim.options[1]:TypeError:('expected str() or unicode() instance, but got int',)
+vim.options[u"\0"]:TypeError:('expected string without null bytes',)
+vim.options["\0"]:TypeError:('expected string without null bytes',)
+<<< Finished
+>> OptionsContains
+>>> Testing StringToChars using %s in vim.options
+1 in vim.options:TypeError:('expected str() or unicode() instance, but got int',)
+u"\0" in vim.options:TypeError:('expected string without null bytes',)
+"\0" in vim.options:TypeError:('expected string without null bytes',)
+<<< Finished
+> Dictionary
+>> DictionaryConstructor
+vim.Dictionary("abcI"):ValueError:('expected sequence element of size 2, but got sequence of size 1',)
+>> DictionarySetattr
+del d.locked:AttributeError:('cannot delete vim.Dictionary attributes',)
+d.locked = FailingTrue():NotImplementedError:('bool',)
+vim.vvars.locked = False:TypeError:('cannot modify fixed dictionary',)
+d.scope = True:AttributeError:('cannot set attribute scope',)
+d.xxx = True:AttributeError:('cannot set attribute xxx',)
+>> _DictionaryItem
+d.get("a", 2, 3):TypeError:('function takes at most 2 arguments (3 given)',)
+>>> Testing StringToChars using d.get(%s)
+d.get(1):TypeError:('expected str() or unicode() instance, but got int',)
+d.get(u"\0"):TypeError:('expected string without null bytes',)
+d.get("\0"):TypeError:('expected string without null bytes',)
+<<< Finished
+d.pop("a"):KeyError:('a',)
+dl.pop("a"):error:('dictionary is locked',)
+>> DictionaryContains
+"" in d:ValueError:('empty keys are not allowed',)
+0 in d:TypeError:('expected str() or unicode() instance, but got int',)
+>> DictionaryIterNext
+for i in ned: ned["a"] = 1:RuntimeError:('hashtab changed during iteration',)
+>> DictionaryAssItem
+dl["b"] = 1:error:('dictionary is locked',)
+>>> Testing StringToChars using d[%s] = 1
+d[1] = 1:TypeError:('expected str() or unicode() instance, but got int',)
+d[u"\0"] = 1:TypeError:('expected string without null bytes',)
+d["\0"] = 1:TypeError:('expected string without null bytes',)
+<<< Finished
+>>> Testing StringToChars using d["a"] = {%s : 1}
+d["a"] = {1 : 1}:TypeError:('expected str() or unicode() instance, but got int',)
+d["a"] = {u"\0" : 1}:TypeError:('expected string without null bytes',)
+d["a"] = {"\0" : 1}:TypeError:('expected string without null bytes',)
+<<< Finished
+>>> Testing StringToChars using d["a"] = {"abcF" : {%s : 1}}
+d["a"] = {"abcF" : {1 : 1}}:TypeError:('expected str() or unicode() instance, but got int',)
+d["a"] = {"abcF" : {u"\0" : 1}}:TypeError:('expected string without null bytes',)
+d["a"] = {"abcF" : {"\0" : 1}}:TypeError:('expected string without null bytes',)
+<<< Finished
+>>> Testing StringToChars using d["a"] = {"abcF" : Mapping({%s : 1})}
+d["a"] = {"abcF" : Mapping({1 : 1})}:TypeError:('expected str() or unicode() instance, but got int',)
+d["a"] = {"abcF" : Mapping({u"\0" : 1})}:TypeError:('expected string without null bytes',)
+d["a"] = {"abcF" : Mapping({"\0" : 1})}:TypeError:('expected string without null bytes',)
+<<< Finished
+>>> Testing *Iter* using d["a"] = {"abcF" : %s}
+d["a"] = {"abcF" : FailingIter()}:TypeError:('unable to convert FailingIter to vim structure',)
+d["a"] = {"abcF" : FailingIterNext()}:NotImplementedError:('next',)
+<<< Finished
+>>> Testing ConvertFromPyObject using d["a"] = {"abcF" : %s}
+d["a"] = {"abcF" : None}:NOT FAILED
+d["a"] = {"abcF" : {"": 1}}:ValueError:('empty keys are not allowed',)
+d["a"] = {"abcF" : {u"": 1}}:ValueError:('empty keys are not allowed',)
+d["a"] = {"abcF" : FailingMapping()}:NotImplementedError:('keys',)
+d["a"] = {"abcF" : FailingMappingKey()}:NotImplementedError:('getitem:mappingkey',)
+d["a"] = {"abcF" : FailingNumber()}:TypeError:('long() argument must be a string or a number',)
+<<< Finished
+>>> Testing StringToChars using d["a"] = Mapping({%s : 1})
+d["a"] = Mapping({1 : 1}):TypeError:('expected str() or unicode() instance, but got int',)
+d["a"] = Mapping({u"\0" : 1}):TypeError:('expected string without null bytes',)
+d["a"] = Mapping({"\0" : 1}):TypeError:('expected string without null bytes',)
+<<< Finished
+>>> Testing StringToChars using d["a"] = Mapping({"abcG" : {%s : 1}})
+d["a"] = Mapping({"abcG" : {1 : 1}}):TypeError:('expected str() or unicode() instance, but got int',)
+d["a"] = Mapping({"abcG" : {u"\0" : 1}}):TypeError:('expected string without null bytes',)
+d["a"] = Mapping({"abcG" : {"\0" : 1}}):TypeError:('expected string without null bytes',)
+<<< Finished
+>>> Testing StringToChars using d["a"] = Mapping({"abcG" : Mapping({%s : 1})})
+d["a"] = Mapping({"abcG" : Mapping({1 : 1})}):TypeError:('expected str() or unicode() instance, but got int',)
+d["a"] = Mapping({"abcG" : Mapping({u"\0" : 1})}):TypeError:('expected string without null bytes',)
+d["a"] = Mapping({"abcG" : Mapping({"\0" : 1})}):TypeError:('expected string without null bytes',)
+<<< Finished
+>>> Testing *Iter* using d["a"] = Mapping({"abcG" : %s})
+d["a"] = Mapping({"abcG" : FailingIter()}):TypeError:('unable to convert FailingIter to vim structure',)
+d["a"] = Mapping({"abcG" : FailingIterNext()}):NotImplementedError:('next',)
+<<< Finished
+>>> Testing ConvertFromPyObject using d["a"] = Mapping({"abcG" : %s})
+d["a"] = Mapping({"abcG" : None}):NOT FAILED
+d["a"] = Mapping({"abcG" : {"": 1}}):ValueError:('empty keys are not allowed',)
+d["a"] = Mapping({"abcG" : {u"": 1}}):ValueError:('empty keys are not allowed',)
+d["a"] = Mapping({"abcG" : FailingMapping()}):NotImplementedError:('keys',)
+d["a"] = Mapping({"abcG" : FailingMappingKey()}):NotImplementedError:('getitem:mappingkey',)
+d["a"] = Mapping({"abcG" : FailingNumber()}):TypeError:('long() argument must be a string or a number',)
+<<< Finished
+>>> Testing *Iter* using d["a"] = %s
+d["a"] = FailingIter():TypeError:('unable to convert FailingIter to vim structure',)
+d["a"] = FailingIterNext():NotImplementedError:('next',)
+<<< Finished
+>>> Testing ConvertFromPyObject using d["a"] = %s
+d["a"] = None:NOT FAILED
+d["a"] = {"": 1}:ValueError:('empty keys are not allowed',)
+d["a"] = {u"": 1}:ValueError:('empty keys are not allowed',)
+d["a"] = FailingMapping():NotImplementedError:('keys',)
+d["a"] = FailingMappingKey():NotImplementedError:('getitem:mappingkey',)
+d["a"] = FailingNumber():TypeError:('long() argument must be a string or a number',)
+<<< Finished
+>> DictionaryUpdate
+>>> kwargs
+>>> iter
+d.update(FailingMapping()):NotImplementedError:('keys',)
+d.update([FailingIterNext()]):NotImplementedError:('next',)
+d.update([FailingIterNextN(1)]):NotImplementedError:('next N',)
+>>> Testing *Iter* using d.update(%s)
+d.update(FailingIter()):NotImplementedError:('iter',)
+d.update(FailingIterNext()):NotImplementedError:('next',)
+<<< Finished
+>>> Testing StringToChars using d.update({%s : 1})
+d.update({1 : 1}):TypeError:('expected str() or unicode() instance, but got int',)
+d.update({u"\0" : 1}):TypeError:('expected string without null bytes',)
+d.update({"\0" : 1}):TypeError:('expected string without null bytes',)
+<<< Finished
+>>> Testing StringToChars using d.update({"abcF" : {%s : 1}})
+d.update({"abcF" : {1 : 1}}):TypeError:('expected str() or unicode() instance, but got int',)
+d.update({"abcF" : {u"\0" : 1}}):TypeError:('expected string without null bytes',)
+d.update({"abcF" : {"\0" : 1}}):TypeError:('expected string without null bytes',)
+<<< Finished
+>>> Testing StringToChars using d.update({"abcF" : Mapping({%s : 1})})
+d.update({"abcF" : Mapping({1 : 1})}):TypeError:('expected str() or unicode() instance, but got int',)
+d.update({"abcF" : Mapping({u"\0" : 1})}):TypeError:('expected string without null bytes',)
+d.update({"abcF" : Mapping({"\0" : 1})}):TypeError:('expected string without null bytes',)
+<<< Finished
+>>> Testing *Iter* using d.update({"abcF" : %s})
+d.update({"abcF" : FailingIter()}):TypeError:('unable to convert FailingIter to vim structure',)
+d.update({"abcF" : FailingIterNext()}):NotImplementedError:('next',)
+<<< Finished
+>>> Testing ConvertFromPyObject using d.update({"abcF" : %s})
+d.update({"abcF" : None}):NOT FAILED
+d.update({"abcF" : {"": 1}}):ValueError:('empty keys are not allowed',)
+d.update({"abcF" : {u"": 1}}):ValueError:('empty keys are not allowed',)
+d.update({"abcF" : FailingMapping()}):NotImplementedError:('keys',)
+d.update({"abcF" : FailingMappingKey()}):NotImplementedError:('getitem:mappingkey',)
+d.update({"abcF" : FailingNumber()}):TypeError:('long() argument must be a string or a number',)
+<<< Finished
+>>> Testing StringToChars using d.update(Mapping({%s : 1}))
+d.update(Mapping({1 : 1})):TypeError:('expected str() or unicode() instance, but got int',)
+d.update(Mapping({u"\0" : 1})):TypeError:('expected string without null bytes',)
+d.update(Mapping({"\0" : 1})):TypeError:('expected string without null bytes',)
+<<< Finished
+>>> Testing StringToChars using d.update(Mapping({"abcG" : {%s : 1}}))
+d.update(Mapping({"abcG" : {1 : 1}})):TypeError:('expected str() or unicode() instance, but got int',)
+d.update(Mapping({"abcG" : {u"\0" : 1}})):TypeError:('expected string without null bytes',)
+d.update(Mapping({"abcG" : {"\0" : 1}})):TypeError:('expected string without null bytes',)
+<<< Finished
+>>> Testing StringToChars using d.update(Mapping({"abcG" : Mapping({%s : 1})}))
+d.update(Mapping({"abcG" : Mapping({1 : 1})})):TypeError:('expected str() or unicode() instance, but got int',)
+d.update(Mapping({"abcG" : Mapping({u"\0" : 1})})):TypeError:('expected string without null bytes',)
+d.update(Mapping({"abcG" : Mapping({"\0" : 1})})):TypeError:('expected string without null bytes',)
+<<< Finished
+>>> Testing *Iter* using d.update(Mapping({"abcG" : %s}))
+d.update(Mapping({"abcG" : FailingIter()})):TypeError:('unable to convert FailingIter to vim structure',)
+d.update(Mapping({"abcG" : FailingIterNext()})):NotImplementedError:('next',)
+<<< Finished
+>>> Testing ConvertFromPyObject using d.update(Mapping({"abcG" : %s}))
+d.update(Mapping({"abcG" : None})):NOT FAILED
+d.update(Mapping({"abcG" : {"": 1}})):ValueError:('empty keys are not allowed',)
+d.update(Mapping({"abcG" : {u"": 1}})):ValueError:('empty keys are not allowed',)
+d.update(Mapping({"abcG" : FailingMapping()})):NotImplementedError:('keys',)
+d.update(Mapping({"abcG" : FailingMappingKey()})):NotImplementedError:('getitem:mappingkey',)
+d.update(Mapping({"abcG" : FailingNumber()})):TypeError:('long() argument must be a string or a number',)
+<<< Finished
+>>> Testing *Iter* using d.update(%s)
+d.update(FailingIter()):NotImplementedError:('iter',)
+d.update(FailingIterNext()):NotImplementedError:('next',)
+<<< Finished
+>>> Testing ConvertFromPyObject using d.update(%s)
+d.update(None):TypeError:("'NoneType' object is not iterable",)
+d.update({"": 1}):ValueError:('empty keys are not allowed',)
+d.update({u"": 1}):ValueError:('empty keys are not allowed',)
+d.update(FailingMapping()):NotImplementedError:('keys',)
+d.update(FailingMappingKey()):NotImplementedError:('getitem:mappingkey',)
+d.update(FailingNumber()):TypeError:("'FailingNumber' object is not iterable",)
+<<< Finished
+>>> Testing StringToChars using d.update(((%s, 0),))
+d.update(((1, 0),)):TypeError:('expected str() or unicode() instance, but got int',)
+d.update(((u"\0", 0),)):TypeError:('expected string without null bytes',)
+d.update((("\0", 0),)):TypeError:('expected string without null bytes',)
+<<< Finished
+>>> Testing StringToChars using d.update((("a", {%s : 1}),))
+d.update((("a", {1 : 1}),)):TypeError:('expected str() or unicode() instance, but got int',)
+d.update((("a", {u"\0" : 1}),)):TypeError:('expected string without null bytes',)
+d.update((("a", {"\0" : 1}),)):TypeError:('expected string without null bytes',)
+<<< Finished
+>>> Testing StringToChars using d.update((("a", {"abcF" : {%s : 1}}),))
+d.update((("a", {"abcF" : {1 : 1}}),)):TypeError:('expected str() or unicode() instance, but got int',)
+d.update((("a", {"abcF" : {u"\0" : 1}}),)):TypeError:('expected string without null bytes',)
+d.update((("a", {"abcF" : {"\0" : 1}}),)):TypeError:('expected string without null bytes',)
+<<< Finished
+>>> Testing StringToChars using d.update((("a", {"abcF" : Mapping({%s : 1})}),))
+d.update((("a", {"abcF" : Mapping({1 : 1})}),)):TypeError:('expected str() or unicode() instance, but got int',)
+d.update((("a", {"abcF" : Mapping({u"\0" : 1})}),)):TypeError:('expected string without null bytes',)
+d.update((("a", {"abcF" : Mapping({"\0" : 1})}),)):TypeError:('expected string without null bytes',)
+<<< Finished
+>>> Testing *Iter* using d.update((("a", {"abcF" : %s}),))
+d.update((("a", {"abcF" : FailingIter()}),)):TypeError:('unable to convert FailingIter to vim structure',)
+d.update((("a", {"abcF" : FailingIterNext()}),)):NotImplementedError:('next',)
+<<< Finished
+>>> Testing ConvertFromPyObject using d.update((("a", {"abcF" : %s}),))
+d.update((("a", {"abcF" : None}),)):error:("failed to add key 'a' to dictionary",)
+d.update((("a", {"abcF" : {"": 1}}),)):ValueError:('empty keys are not allowed',)
+d.update((("a", {"abcF" : {u"": 1}}),)):ValueError:('empty keys are not allowed',)
+d.update((("a", {"abcF" : FailingMapping()}),)):NotImplementedError:('keys',)
+d.update((("a", {"abcF" : FailingMappingKey()}),)):NotImplementedError:('getitem:mappingkey',)
+d.update((("a", {"abcF" : FailingNumber()}),)):TypeError:('long() argument must be a string or a number',)
+<<< Finished
+>>> Testing StringToChars using d.update((("a", Mapping({%s : 1})),))
+d.update((("a", Mapping({1 : 1})),)):TypeError:('expected str() or unicode() instance, but got int',)
+d.update((("a", Mapping({u"\0" : 1})),)):TypeError:('expected string without null bytes',)
+d.update((("a", Mapping({"\0" : 1})),)):TypeError:('expected string without null bytes',)
+<<< Finished
+>>> Testing StringToChars using d.update((("a", Mapping({"abcG" : {%s : 1}})),))
+d.update((("a", Mapping({"abcG" : {1 : 1}})),)):TypeError:('expected str() or unicode() instance, but got int',)
+d.update((("a", Mapping({"abcG" : {u"\0" : 1}})),)):TypeError:('expected string without null bytes',)
+d.update((("a", Mapping({"abcG" : {"\0" : 1}})),)):TypeError:('expected string without null bytes',)
+<<< Finished
+>>> Testing StringToChars using d.update((("a", Mapping({"abcG" : Mapping({%s : 1})})),))
+d.update((("a", Mapping({"abcG" : Mapping({1 : 1})})),)):TypeError:('expected str() or unicode() instance, but got int',)
+d.update((("a", Mapping({"abcG" : Mapping({u"\0" : 1})})),)):TypeError:('expected string without null bytes',)
+d.update((("a", Mapping({"abcG" : Mapping({"\0" : 1})})),)):TypeError:('expected string without null bytes',)
+<<< Finished
+>>> Testing *Iter* using d.update((("a", Mapping({"abcG" : %s})),))
+d.update((("a", Mapping({"abcG" : FailingIter()})),)):TypeError:('unable to convert FailingIter to vim structure',)
+d.update((("a", Mapping({"abcG" : FailingIterNext()})),)):NotImplementedError:('next',)
+<<< Finished
+>>> Testing ConvertFromPyObject using d.update((("a", Mapping({"abcG" : %s})),))
+d.update((("a", Mapping({"abcG" : None})),)):error:("failed to add key 'a' to dictionary",)
+d.update((("a", Mapping({"abcG" : {"": 1}})),)):ValueError:('empty keys are not allowed',)
+d.update((("a", Mapping({"abcG" : {u"": 1}})),)):ValueError:('empty keys are not allowed',)
+d.update((("a", Mapping({"abcG" : FailingMapping()})),)):NotImplementedError:('keys',)
+d.update((("a", Mapping({"abcG" : FailingMappingKey()})),)):NotImplementedError:('getitem:mappingkey',)
+d.update((("a", Mapping({"abcG" : FailingNumber()})),)):TypeError:('long() argument must be a string or a number',)
+<<< Finished
+>>> Testing *Iter* using d.update((("a", %s),))
+d.update((("a", FailingIter()),)):TypeError:('unable to convert FailingIter to vim structure',)
+d.update((("a", FailingIterNext()),)):NotImplementedError:('next',)
+<<< Finished
+>>> Testing ConvertFromPyObject using d.update((("a", %s),))
+d.update((("a", None),)):error:("failed to add key 'a' to dictionary",)
+d.update((("a", {"": 1}),)):ValueError:('empty keys are not allowed',)
+d.update((("a", {u"": 1}),)):ValueError:('empty keys are not allowed',)
+d.update((("a", FailingMapping()),)):NotImplementedError:('keys',)
+d.update((("a", FailingMappingKey()),)):NotImplementedError:('getitem:mappingkey',)
+d.update((("a", FailingNumber()),)):TypeError:('long() argument must be a string or a number',)
+<<< Finished
+>> DictionaryPopItem
+d.popitem(1, 2):TypeError:('popitem() takes no arguments (2 given)',)
+>> DictionaryHasKey
+d.has_key():TypeError:('has_key() takes exactly one argument (0 given)',)
+> List
+>> ListConstructor
+vim.List(1, 2):TypeError:('function takes at most 1 argument (2 given)',)
+vim.List(a=1):TypeError:('list constructor does not accept keyword arguments',)
+>>> Testing *Iter* using vim.List(%s)
+vim.List(FailingIter()):NotImplementedError:('iter',)
+vim.List(FailingIterNext()):NotImplementedError:('next',)
+<<< Finished
+>>> Testing StringToChars using vim.List([{%s : 1}])
+vim.List([{1 : 1}]):TypeError:('expected str() or unicode() instance, but got int',)
+vim.List([{u"\0" : 1}]):TypeError:('expected string without null bytes',)
+vim.List([{"\0" : 1}]):TypeError:('expected string without null bytes',)
+<<< Finished
+>>> Testing StringToChars using vim.List([{"abcF" : {%s : 1}}])
+vim.List([{"abcF" : {1 : 1}}]):TypeError:('expected str() or unicode() instance, but got int',)
+vim.List([{"abcF" : {u"\0" : 1}}]):TypeError:('expected string without null bytes',)
+vim.List([{"abcF" : {"\0" : 1}}]):TypeError:('expected string without null bytes',)
+<<< Finished
+>>> Testing StringToChars using vim.List([{"abcF" : Mapping({%s : 1})}])
+vim.List([{"abcF" : Mapping({1 : 1})}]):TypeError:('expected str() or unicode() instance, but got int',)
+vim.List([{"abcF" : Mapping({u"\0" : 1})}]):TypeError:('expected string without null bytes',)
+vim.List([{"abcF" : Mapping({"\0" : 1})}]):TypeError:('expected string without null bytes',)
+<<< Finished
+>>> Testing *Iter* using vim.List([{"abcF" : %s}])
+vim.List([{"abcF" : FailingIter()}]):TypeError:('unable to convert FailingIter to vim structure',)
+vim.List([{"abcF" : FailingIterNext()}]):NotImplementedError:('next',)
+<<< Finished
+>>> Testing ConvertFromPyObject using vim.List([{"abcF" : %s}])
+vim.List([{"abcF" : None}]):NOT FAILED
+vim.List([{"abcF" : {"": 1}}]):ValueError:('empty keys are not allowed',)
+vim.List([{"abcF" : {u"": 1}}]):ValueError:('empty keys are not allowed',)
+vim.List([{"abcF" : FailingMapping()}]):NotImplementedError:('keys',)
+vim.List([{"abcF" : FailingMappingKey()}]):NotImplementedError:('getitem:mappingkey',)
+vim.List([{"abcF" : FailingNumber()}]):TypeError:('long() argument must be a string or a number',)
+<<< Finished
+>>> Testing StringToChars using vim.List([Mapping({%s : 1})])
+vim.List([Mapping({1 : 1})]):TypeError:('expected str() or unicode() instance, but got int',)
+vim.List([Mapping({u"\0" : 1})]):TypeError:('expected string without null bytes',)
+vim.List([Mapping({"\0" : 1})]):TypeError:('expected string without null bytes',)
+<<< Finished
+>>> Testing StringToChars using vim.List([Mapping({"abcG" : {%s : 1}})])
+vim.List([Mapping({"abcG" : {1 : 1}})]):TypeError:('expected str() or unicode() instance, but got int',)
+vim.List([Mapping({"abcG" : {u"\0" : 1}})]):TypeError:('expected string without null bytes',)
+vim.List([Mapping({"abcG" : {"\0" : 1}})]):TypeError:('expected string without null bytes',)
+<<< Finished
+>>> Testing StringToChars using vim.List([Mapping({"abcG" : Mapping({%s : 1})})])
+vim.List([Mapping({"abcG" : Mapping({1 : 1})})]):TypeError:('expected str() or unicode() instance, but got int',)
+vim.List([Mapping({"abcG" : Mapping({u"\0" : 1})})]):TypeError:('expected string without null bytes',)
+vim.List([Mapping({"abcG" : Mapping({"\0" : 1})})]):TypeError:('expected string without null bytes',)
+<<< Finished
+>>> Testing *Iter* using vim.List([Mapping({"abcG" : %s})])
+vim.List([Mapping({"abcG" : FailingIter()})]):TypeError:('unable to convert FailingIter to vim structure',)
+vim.List([Mapping({"abcG" : FailingIterNext()})]):NotImplementedError:('next',)
+<<< Finished
+>>> Testing ConvertFromPyObject using vim.List([Mapping({"abcG" : %s})])
+vim.List([Mapping({"abcG" : None})]):NOT FAILED
+vim.List([Mapping({"abcG" : {"": 1}})]):ValueError:('empty keys are not allowed',)
+vim.List([Mapping({"abcG" : {u"": 1}})]):ValueError:('empty keys are not allowed',)
+vim.List([Mapping({"abcG" : FailingMapping()})]):NotImplementedError:('keys',)
+vim.List([Mapping({"abcG" : FailingMappingKey()})]):NotImplementedError:('getitem:mappingkey',)
+vim.List([Mapping({"abcG" : FailingNumber()})]):TypeError:('long() argument must be a string or a number',)
+<<< Finished
+>>> Testing *Iter* using vim.List([%s])
+vim.List([FailingIter()]):TypeError:('unable to convert FailingIter to vim structure',)
+vim.List([FailingIterNext()]):NotImplementedError:('next',)
+<<< Finished
+>>> Testing ConvertFromPyObject using vim.List([%s])
+vim.List([None]):NOT FAILED
+vim.List([{"": 1}]):ValueError:('empty keys are not allowed',)
+vim.List([{u"": 1}]):ValueError:('empty keys are not allowed',)
+vim.List([FailingMapping()]):NotImplementedError:('keys',)
+vim.List([FailingMappingKey()]):NotImplementedError:('getitem:mappingkey',)
+vim.List([FailingNumber()]):TypeError:('long() argument must be a string or a number',)
+<<< Finished
+>> ListItem
+l[1000]:IndexError:('list index out of range',)
+>> ListAssItem
+ll[1] = 2:error:('list is locked',)
+l[1000] = 3:IndexError:('list index out of range',)
+>> ListAssSlice
+ll[1:100] = "abcJ":error:('list is locked',)
+>>> Testing *Iter* using l[:] = %s
+l[:] = FailingIter():NotImplementedError:('iter',)
+l[:] = FailingIterNext():NotImplementedError:('next',)
+<<< Finished
+nel[1:10:2] = "abcK":ValueError:('attempt to assign sequence of size greater than 2 to extended slice',)
+('a', 'b', 'c', 'O')
+nel[1:10:2] = "a":ValueError:('attempt to assign sequence of size 1 to extended slice of size 2',)
+('a', 'b', 'c', 'O')
+nel[1:1:-1] = "a":ValueError:('attempt to assign sequence of size greater than 0 to extended slice',)
+('a', 'b', 'c', 'O')
+nel[:] = FailingIterNextN(2):NotImplementedError:('next N',)
+('a', 'b', 'c', 'O')
+>>> Testing StringToChars using l[:] = [{%s : 1}]
+l[:] = [{1 : 1}]:TypeError:('expected str() or unicode() instance, but got int',)
+l[:] = [{u"\0" : 1}]:TypeError:('expected string without null bytes',)
+l[:] = [{"\0" : 1}]:TypeError:('expected string without null bytes',)
+<<< Finished
+>>> Testing StringToChars using l[:] = [{"abcF" : {%s : 1}}]
+l[:] = [{"abcF" : {1 : 1}}]:TypeError:('expected str() or unicode() instance, but got int',)
+l[:] = [{"abcF" : {u"\0" : 1}}]:TypeError:('expected string without null bytes',)
+l[:] = [{"abcF" : {"\0" : 1}}]:TypeError:('expected string without null bytes',)
+<<< Finished
+>>> Testing StringToChars using l[:] = [{"abcF" : Mapping({%s : 1})}]
+l[:] = [{"abcF" : Mapping({1 : 1})}]:TypeError:('expected str() or unicode() instance, but got int',)
+l[:] = [{"abcF" : Mapping({u"\0" : 1})}]:TypeError:('expected string without null bytes',)
+l[:] = [{"abcF" : Mapping({"\0" : 1})}]:TypeError:('expected string without null bytes',)
+<<< Finished
+>>> Testing *Iter* using l[:] = [{"abcF" : %s}]
+l[:] = [{"abcF" : FailingIter()}]:TypeError:('unable to convert FailingIter to vim structure',)
+l[:] = [{"abcF" : FailingIterNext()}]:NotImplementedError:('next',)
+<<< Finished
+>>> Testing ConvertFromPyObject using l[:] = [{"abcF" : %s}]
+l[:] = [{"abcF" : None}]:NOT FAILED
+l[:] = [{"abcF" : {"": 1}}]:ValueError:('empty keys are not allowed',)
+l[:] = [{"abcF" : {u"": 1}}]:ValueError:('empty keys are not allowed',)
+l[:] = [{"abcF" : FailingMapping()}]:NotImplementedError:('keys',)
+l[:] = [{"abcF" : FailingMappingKey()}]:NotImplementedError:('getitem:mappingkey',)
+l[:] = [{"abcF" : FailingNumber()}]:TypeError:('long() argument must be a string or a number',)
+<<< Finished
+>>> Testing StringToChars using l[:] = [Mapping({%s : 1})]
+l[:] = [Mapping({1 : 1})]:TypeError:('expected str() or unicode() instance, but got int',)
+l[:] = [Mapping({u"\0" : 1})]:TypeError:('expected string without null bytes',)
+l[:] = [Mapping({"\0" : 1})]:TypeError:('expected string without null bytes',)
+<<< Finished
+>>> Testing StringToChars using l[:] = [Mapping({"abcG" : {%s : 1}})]
+l[:] = [Mapping({"abcG" : {1 : 1}})]:TypeError:('expected str() or unicode() instance, but got int',)
+l[:] = [Mapping({"abcG" : {u"\0" : 1}})]:TypeError:('expected string without null bytes',)
+l[:] = [Mapping({"abcG" : {"\0" : 1}})]:TypeError:('expected string without null bytes',)
+<<< Finished
+>>> Testing StringToChars using l[:] = [Mapping({"abcG" : Mapping({%s : 1})})]
+l[:] = [Mapping({"abcG" : Mapping({1 : 1})})]:TypeError:('expected str() or unicode() instance, but got int',)
+l[:] = [Mapping({"abcG" : Mapping({u"\0" : 1})})]:TypeError:('expected string without null bytes',)
+l[:] = [Mapping({"abcG" : Mapping({"\0" : 1})})]:TypeError:('expected string without null bytes',)
+<<< Finished
+>>> Testing *Iter* using l[:] = [Mapping({"abcG" : %s})]
+l[:] = [Mapping({"abcG" : FailingIter()})]:TypeError:('unable to convert FailingIter to vim structure',)
+l[:] = [Mapping({"abcG" : FailingIterNext()})]:NotImplementedError:('next',)
+<<< Finished
+>>> Testing ConvertFromPyObject using l[:] = [Mapping({"abcG" : %s})]
+l[:] = [Mapping({"abcG" : None})]:NOT FAILED
+l[:] = [Mapping({"abcG" : {"": 1}})]:ValueError:('empty keys are not allowed',)
+l[:] = [Mapping({"abcG" : {u"": 1}})]:ValueError:('empty keys are not allowed',)
+l[:] = [Mapping({"abcG" : FailingMapping()})]:NotImplementedError:('keys',)
+l[:] = [Mapping({"abcG" : FailingMappingKey()})]:NotImplementedError:('getitem:mappingkey',)
+l[:] = [Mapping({"abcG" : FailingNumber()})]:TypeError:('long() argument must be a string or a number',)
+<<< Finished
+>>> Testing *Iter* using l[:] = [%s]
+l[:] = [FailingIter()]:TypeError:('unable to convert FailingIter to vim structure',)
+l[:] = [FailingIterNext()]:NotImplementedError:('next',)
+<<< Finished
+>>> Testing ConvertFromPyObject using l[:] = [%s]
+l[:] = [None]:NOT FAILED
+l[:] = [{"": 1}]:ValueError:('empty keys are not allowed',)
+l[:] = [{u"": 1}]:ValueError:('empty keys are not allowed',)
+l[:] = [FailingMapping()]:NotImplementedError:('keys',)
+l[:] = [FailingMappingKey()]:NotImplementedError:('getitem:mappingkey',)
+l[:] = [FailingNumber()]:TypeError:('long() argument must be a string or a number',)
+<<< Finished
+>> ListConcatInPlace
+>>> Testing *Iter* using l.extend(%s)
+l.extend(FailingIter()):NotImplementedError:('iter',)
+l.extend(FailingIterNext()):NotImplementedError:('next',)
+<<< Finished
+>>> Testing StringToChars using l.extend([{%s : 1}])
+l.extend([{1 : 1}]):TypeError:('expected str() or unicode() instance, but got int',)
+l.extend([{u"\0" : 1}]):TypeError:('expected string without null bytes',)
+l.extend([{"\0" : 1}]):TypeError:('expected string without null bytes',)
+<<< Finished
+>>> Testing StringToChars using l.extend([{"abcF" : {%s : 1}}])
+l.extend([{"abcF" : {1 : 1}}]):TypeError:('expected str() or unicode() instance, but got int',)
+l.extend([{"abcF" : {u"\0" : 1}}]):TypeError:('expected string without null bytes',)
+l.extend([{"abcF" : {"\0" : 1}}]):TypeError:('expected string without null bytes',)
+<<< Finished
+>>> Testing StringToChars using l.extend([{"abcF" : Mapping({%s : 1})}])
+l.extend([{"abcF" : Mapping({1 : 1})}]):TypeError:('expected str() or unicode() instance, but got int',)
+l.extend([{"abcF" : Mapping({u"\0" : 1})}]):TypeError:('expected string without null bytes',)
+l.extend([{"abcF" : Mapping({"\0" : 1})}]):TypeError:('expected string without null bytes',)
+<<< Finished
+>>> Testing *Iter* using l.extend([{"abcF" : %s}])
+l.extend([{"abcF" : FailingIter()}]):TypeError:('unable to convert FailingIter to vim structure',)
+l.extend([{"abcF" : FailingIterNext()}]):NotImplementedError:('next',)
+<<< Finished
+>>> Testing ConvertFromPyObject using l.extend([{"abcF" : %s}])
+l.extend([{"abcF" : None}]):NOT FAILED
+l.extend([{"abcF" : {"": 1}}]):ValueError:('empty keys are not allowed',)
+l.extend([{"abcF" : {u"": 1}}]):ValueError:('empty keys are not allowed',)
+l.extend([{"abcF" : FailingMapping()}]):NotImplementedError:('keys',)
+l.extend([{"abcF" : FailingMappingKey()}]):NotImplementedError:('getitem:mappingkey',)
+l.extend([{"abcF" : FailingNumber()}]):TypeError:('long() argument must be a string or a number',)
+<<< Finished
+>>> Testing StringToChars using l.extend([Mapping({%s : 1})])
+l.extend([Mapping({1 : 1})]):TypeError:('expected str() or unicode() instance, but got int',)
+l.extend([Mapping({u"\0" : 1})]):TypeError:('expected string without null bytes',)
+l.extend([Mapping({"\0" : 1})]):TypeError:('expected string without null bytes',)
+<<< Finished
+>>> Testing StringToChars using l.extend([Mapping({"abcG" : {%s : 1}})])
+l.extend([Mapping({"abcG" : {1 : 1}})]):TypeError:('expected str() or unicode() instance, but got int',)
+l.extend([Mapping({"abcG" : {u"\0" : 1}})]):TypeError:('expected string without null bytes',)
+l.extend([Mapping({"abcG" : {"\0" : 1}})]):TypeError:('expected string without null bytes',)
+<<< Finished
+>>> Testing StringToChars using l.extend([Mapping({"abcG" : Mapping({%s : 1})})])
+l.extend([Mapping({"abcG" : Mapping({1 : 1})})]):TypeError:('expected str() or unicode() instance, but got int',)
+l.extend([Mapping({"abcG" : Mapping({u"\0" : 1})})]):TypeError:('expected string without null bytes',)
+l.extend([Mapping({"abcG" : Mapping({"\0" : 1})})]):TypeError:('expected string without null bytes',)
+<<< Finished
+>>> Testing *Iter* using l.extend([Mapping({"abcG" : %s})])
+l.extend([Mapping({"abcG" : FailingIter()})]):TypeError:('unable to convert FailingIter to vim structure',)
+l.extend([Mapping({"abcG" : FailingIterNext()})]):NotImplementedError:('next',)
+<<< Finished
+>>> Testing ConvertFromPyObject using l.extend([Mapping({"abcG" : %s})])
+l.extend([Mapping({"abcG" : None})]):NOT FAILED
+l.extend([Mapping({"abcG" : {"": 1}})]):ValueError:('empty keys are not allowed',)
+l.extend([Mapping({"abcG" : {u"": 1}})]):ValueError:('empty keys are not allowed',)
+l.extend([Mapping({"abcG" : FailingMapping()})]):NotImplementedError:('keys',)
+l.extend([Mapping({"abcG" : FailingMappingKey()})]):NotImplementedError:('getitem:mappingkey',)
+l.extend([Mapping({"abcG" : FailingNumber()})]):TypeError:('long() argument must be a string or a number',)
+<<< Finished
+>>> Testing *Iter* using l.extend([%s])
+l.extend([FailingIter()]):TypeError:('unable to convert FailingIter to vim structure',)
+l.extend([FailingIterNext()]):NotImplementedError:('next',)
+<<< Finished
+>>> Testing ConvertFromPyObject using l.extend([%s])
+l.extend([None]):NOT FAILED
+l.extend([{"": 1}]):ValueError:('empty keys are not allowed',)
+l.extend([{u"": 1}]):ValueError:('empty keys are not allowed',)
+l.extend([FailingMapping()]):NotImplementedError:('keys',)
+l.extend([FailingMappingKey()]):NotImplementedError:('getitem:mappingkey',)
+l.extend([FailingNumber()]):TypeError:('long() argument must be a string or a number',)
+<<< Finished
+>> ListSetattr
+del l.locked:AttributeError:('cannot delete vim.List attributes',)
+l.locked = FailingTrue():NotImplementedError:('bool',)
+l.xxx = True:AttributeError:('cannot set attribute xxx',)
+> Function
+>> FunctionConstructor
+>>> FunctionConstructor
+vim.Function("123"):ValueError:('unnamed function 123 does not exist',)
+vim.Function("xxx_non_existent_function_xxx"):ValueError:('function xxx_non_existent_function_xxx does not exist',)
+vim.Function("xxx#non#existent#function#xxx"):NOT FAILED
+vim.Function("xxx_non_existent_function_xxx2", args=[]):ValueError:('function xxx_non_existent_function_xxx2 does not exist',)
+vim.Function("xxx_non_existent_function_xxx3", self={}):ValueError:('function xxx_non_existent_function_xxx3 does not exist',)
+vim.Function("xxx_non_existent_function_xxx4", args=[], self={}):ValueError:('function xxx_non_existent_function_xxx4 does not exist',)
+>>> FunctionNew
+vim.Function("tr", self="abcFuncSelf"):TypeError:('unable to convert str to vim dictionary',)
+vim.Function("tr", args=427423):TypeError:('unable to convert int to vim list',)
+vim.Function("tr", self="abcFuncSelf2", args="abcFuncArgs2"):TypeError:('unable to convert str to vim dictionary',)
+vim.Function(self="abcFuncSelf2", args="abcFuncArgs2"):TypeError:('unable to convert str to vim dictionary',)
+vim.Function("tr", "", self="abcFuncSelf2", args="abcFuncArgs2"):TypeError:('unable to convert str to vim dictionary',)
+vim.Function("tr", ""):TypeError:('function takes exactly 1 argument (2 given)',)
+>> FunctionCall
+>>> Testing StringToChars using f({%s : 1})
+f({1 : 1}):TypeError:('expected str() or unicode() instance, but got int',)
+f({u"\0" : 1}):TypeError:('expected string without null bytes',)
+f({"\0" : 1}):TypeError:('expected string without null bytes',)
+<<< Finished
+>>> Testing StringToChars using f({"abcF" : {%s : 1}})
+f({"abcF" : {1 : 1}}):TypeError:('expected str() or unicode() instance, but got int',)
+f({"abcF" : {u"\0" : 1}}):TypeError:('expected string without null bytes',)
+f({"abcF" : {"\0" : 1}}):TypeError:('expected string without null bytes',)
+<<< Finished
+>>> Testing StringToChars using f({"abcF" : Mapping({%s : 1})})
+f({"abcF" : Mapping({1 : 1})}):TypeError:('expected str() or unicode() instance, but got int',)
+f({"abcF" : Mapping({u"\0" : 1})}):TypeError:('expected string without null bytes',)
+f({"abcF" : Mapping({"\0" : 1})}):TypeError:('expected string without null bytes',)
+<<< Finished
+>>> Testing *Iter* using f({"abcF" : %s})
+f({"abcF" : FailingIter()}):TypeError:('unable to convert FailingIter to vim structure',)
+f({"abcF" : FailingIterNext()}):NotImplementedError:('next',)
+<<< Finished
+>>> Testing ConvertFromPyObject using f({"abcF" : %s})
+f({"abcF" : None}):NOT FAILED
+f({"abcF" : {"": 1}}):ValueError:('empty keys are not allowed',)
+f({"abcF" : {u"": 1}}):ValueError:('empty keys are not allowed',)
+f({"abcF" : FailingMapping()}):NotImplementedError:('keys',)
+f({"abcF" : FailingMappingKey()}):NotImplementedError:('getitem:mappingkey',)
+f({"abcF" : FailingNumber()}):TypeError:('long() argument must be a string or a number',)
+<<< Finished
+>>> Testing StringToChars using f(Mapping({%s : 1}))
+f(Mapping({1 : 1})):TypeError:('expected str() or unicode() instance, but got int',)
+f(Mapping({u"\0" : 1})):TypeError:('expected string without null bytes',)
+f(Mapping({"\0" : 1})):TypeError:('expected string without null bytes',)
+<<< Finished
+>>> Testing StringToChars using f(Mapping({"abcG" : {%s : 1}}))
+f(Mapping({"abcG" : {1 : 1}})):TypeError:('expected str() or unicode() instance, but got int',)
+f(Mapping({"abcG" : {u"\0" : 1}})):TypeError:('expected string without null bytes',)
+f(Mapping({"abcG" : {"\0" : 1}})):TypeError:('expected string without null bytes',)
+<<< Finished
+>>> Testing StringToChars using f(Mapping({"abcG" : Mapping({%s : 1})}))
+f(Mapping({"abcG" : Mapping({1 : 1})})):TypeError:('expected str() or unicode() instance, but got int',)
+f(Mapping({"abcG" : Mapping({u"\0" : 1})})):TypeError:('expected string without null bytes',)
+f(Mapping({"abcG" : Mapping({"\0" : 1})})):TypeError:('expected string without null bytes',)
+<<< Finished
+>>> Testing *Iter* using f(Mapping({"abcG" : %s}))
+f(Mapping({"abcG" : FailingIter()})):TypeError:('unable to convert FailingIter to vim structure',)
+f(Mapping({"abcG" : FailingIterNext()})):NotImplementedError:('next',)
+<<< Finished
+>>> Testing ConvertFromPyObject using f(Mapping({"abcG" : %s}))
+f(Mapping({"abcG" : None})):NOT FAILED
+f(Mapping({"abcG" : {"": 1}})):ValueError:('empty keys are not allowed',)
+f(Mapping({"abcG" : {u"": 1}})):ValueError:('empty keys are not allowed',)
+f(Mapping({"abcG" : FailingMapping()})):NotImplementedError:('keys',)
+f(Mapping({"abcG" : FailingMappingKey()})):NotImplementedError:('getitem:mappingkey',)
+f(Mapping({"abcG" : FailingNumber()})):TypeError:('long() argument must be a string or a number',)
+<<< Finished
+>>> Testing *Iter* using f(%s)
+f(FailingIter()):TypeError:('unable to convert FailingIter to vim structure',)
+f(FailingIterNext()):NotImplementedError:('next',)
+<<< Finished
+>>> Testing ConvertFromPyObject using f(%s)
+f(None):NOT FAILED
+f({"": 1}):ValueError:('empty keys are not allowed',)
+f({u"": 1}):ValueError:('empty keys are not allowed',)
+f(FailingMapping()):NotImplementedError:('keys',)
+f(FailingMappingKey()):NotImplementedError:('getitem:mappingkey',)
+f(FailingNumber()):TypeError:('long() argument must be a string or a number',)
+<<< Finished
+>>> Testing StringToChars using fd(self={%s : 1})
+fd(self={1 : 1}):TypeError:('expected str() or unicode() instance, but got int',)
+fd(self={u"\0" : 1}):TypeError:('expected string without null bytes',)
+fd(self={"\0" : 1}):TypeError:('expected string without null bytes',)
+<<< Finished
+>>> Testing StringToChars using fd(self={"abcF" : {%s : 1}})
+fd(self={"abcF" : {1 : 1}}):TypeError:('expected str() or unicode() instance, but got int',)
+fd(self={"abcF" : {u"\0" : 1}}):TypeError:('expected string without null bytes',)
+fd(self={"abcF" : {"\0" : 1}}):TypeError:('expected string without null bytes',)
+<<< Finished
+>>> Testing StringToChars using fd(self={"abcF" : Mapping({%s : 1})})
+fd(self={"abcF" : Mapping({1 : 1})}):TypeError:('expected str() or unicode() instance, but got int',)
+fd(self={"abcF" : Mapping({u"\0" : 1})}):TypeError:('expected string without null bytes',)
+fd(self={"abcF" : Mapping({"\0" : 1})}):TypeError:('expected string without null bytes',)
+<<< Finished
+>>> Testing *Iter* using fd(self={"abcF" : %s})
+fd(self={"abcF" : FailingIter()}):TypeError:('unable to convert FailingIter to vim structure',)
+fd(self={"abcF" : FailingIterNext()}):NotImplementedError:('next',)
+<<< Finished
+>>> Testing ConvertFromPyObject using fd(self={"abcF" : %s})
+fd(self={"abcF" : None}):NOT FAILED
+fd(self={"abcF" : {"": 1}}):ValueError:('empty keys are not allowed',)
+fd(self={"abcF" : {u"": 1}}):ValueError:('empty keys are not allowed',)
+fd(self={"abcF" : FailingMapping()}):NotImplementedError:('keys',)
+fd(self={"abcF" : FailingMappingKey()}):NotImplementedError:('getitem:mappingkey',)
+fd(self={"abcF" : FailingNumber()}):TypeError:('long() argument must be a string or a number',)
+<<< Finished
+>>> Testing StringToChars using fd(self=Mapping({%s : 1}))
+fd(self=Mapping({1 : 1})):TypeError:('expected str() or unicode() instance, but got int',)
+fd(self=Mapping({u"\0" : 1})):TypeError:('expected string without null bytes',)
+fd(self=Mapping({"\0" : 1})):TypeError:('expected string without null bytes',)
+<<< Finished
+>>> Testing StringToChars using fd(self=Mapping({"abcG" : {%s : 1}}))
+fd(self=Mapping({"abcG" : {1 : 1}})):TypeError:('expected str() or unicode() instance, but got int',)
+fd(self=Mapping({"abcG" : {u"\0" : 1}})):TypeError:('expected string without null bytes',)
+fd(self=Mapping({"abcG" : {"\0" : 1}})):TypeError:('expected string without null bytes',)
+<<< Finished
+>>> Testing StringToChars using fd(self=Mapping({"abcG" : Mapping({%s : 1})}))
+fd(self=Mapping({"abcG" : Mapping({1 : 1})})):TypeError:('expected str() or unicode() instance, but got int',)
+fd(self=Mapping({"abcG" : Mapping({u"\0" : 1})})):TypeError:('expected string without null bytes',)
+fd(self=Mapping({"abcG" : Mapping({"\0" : 1})})):TypeError:('expected string without null bytes',)
+<<< Finished
+>>> Testing *Iter* using fd(self=Mapping({"abcG" : %s}))
+fd(self=Mapping({"abcG" : FailingIter()})):TypeError:('unable to convert FailingIter to vim structure',)
+fd(self=Mapping({"abcG" : FailingIterNext()})):NotImplementedError:('next',)
+<<< Finished
+>>> Testing ConvertFromPyObject using fd(self=Mapping({"abcG" : %s}))
+fd(self=Mapping({"abcG" : None})):NOT FAILED
+fd(self=Mapping({"abcG" : {"": 1}})):ValueError:('empty keys are not allowed',)
+fd(self=Mapping({"abcG" : {u"": 1}})):ValueError:('empty keys are not allowed',)
+fd(self=Mapping({"abcG" : FailingMapping()})):NotImplementedError:('keys',)
+fd(self=Mapping({"abcG" : FailingMappingKey()})):NotImplementedError:('getitem:mappingkey',)
+fd(self=Mapping({"abcG" : FailingNumber()})):TypeError:('long() argument must be a string or a number',)
+<<< Finished
+>>> Testing *Iter* using fd(self=%s)
+fd(self=FailingIter()):TypeError:('unable to convert FailingIter to vim dictionary',)
+fd(self=FailingIterNext()):TypeError:('unable to convert FailingIterNext to vim dictionary',)
+<<< Finished
+>>> Testing ConvertFromPyObject using fd(self=%s)
+fd(self=None):TypeError:('unable to convert NoneType to vim dictionary',)
+fd(self={"": 1}):ValueError:('empty keys are not allowed',)
+fd(self={u"": 1}):ValueError:('empty keys are not allowed',)
+fd(self=FailingMapping()):NotImplementedError:('keys',)
+fd(self=FailingMappingKey()):NotImplementedError:('getitem:mappingkey',)
+fd(self=FailingNumber()):TypeError:('unable to convert FailingNumber to vim dictionary',)
+<<< Finished
+>>> Testing ConvertFromPyMapping using fd(self=%s)
+fd(self=[]):TypeError:('unable to convert list to vim dictionary',)
+<<< Finished
+> TabPage
+>> TabPageAttr
+vim.current.tabpage.xxx:AttributeError:('xxx',)
+> TabList
+>> TabListItem
+vim.tabpages[1000]:IndexError:('no such tab page',)
+> Window
+>> WindowAttr
+vim.current.window.xxx:AttributeError:('xxx',)
+>> WindowSetattr
+vim.current.window.buffer = 0:TypeError:('readonly attribute: buffer',)
+vim.current.window.cursor = (100000000, 100000000):error:('cursor position outside buffer',)
+vim.current.window.cursor = True:TypeError:('argument must be 2-item sequence, not bool',)
+>>> Testing NumberToLong using vim.current.window.height = %s
+vim.current.window.height = []:TypeError:('expected int(), long() or something supporting coercing to long(), but got list',)
+vim.current.window.height = None:TypeError:('expected int(), long() or something supporting coercing to long(), but got NoneType',)
+vim.current.window.height = -1:ValueError:('number must be greater or equal to zero',)
+<<< Finished
+>>> Testing NumberToLong using vim.current.window.width = %s
+vim.current.window.width = []:TypeError:('expected int(), long() or something supporting coercing to long(), but got list',)
+vim.current.window.width = None:TypeError:('expected int(), long() or something supporting coercing to long(), but got NoneType',)
+vim.current.window.width = -1:ValueError:('number must be greater or equal to zero',)
+<<< Finished
+vim.current.window.xxxxxx = True:AttributeError:('xxxxxx',)
+> WinList
+>> WinListItem
+vim.windows[1000]:IndexError:('no such window',)
+> Buffer
+>> StringToLine (indirect)
+vim.current.buffer[0] = u"\na":error:('string cannot contain newlines',)
+vim.current.buffer[0] = "\na":error:('string cannot contain newlines',)
+>> SetBufferLine (indirect)
+vim.current.buffer[0] = True:TypeError:('bad argument type for built-in operation',)
+>> SetBufferLineList (indirect)
+vim.current.buffer[:] = True:TypeError:('bad argument type for built-in operation',)
+vim.current.buffer[:] = ["\na", "bc"]:error:('string cannot contain newlines',)
+>> InsertBufferLines (indirect)
+vim.current.buffer.append(None):TypeError:('bad argument type for built-in operation',)
+vim.current.buffer.append(["\na", "bc"]):error:('string cannot contain newlines',)
+vim.current.buffer.append("\nbc"):error:('string cannot contain newlines',)
+>> RBItem
+vim.current.buffer[100000000]:IndexError:('line number out of range',)
+>> RBAsItem
+vim.current.buffer[100000000] = "":IndexError:('line number out of range',)
+>> BufferAttr
+vim.current.buffer.xxx:AttributeError:('xxx',)
+>> BufferSetattr
+vim.current.buffer.name = True:TypeError:('expected str() or unicode() instance, but got bool',)
+vim.current.buffer.xxx = True:AttributeError:('xxx',)
+>> BufferMark
+vim.current.buffer.mark(0):TypeError:('expected str() or unicode() instance, but got int',)
+vim.current.buffer.mark("abcM"):ValueError:('mark name must be a single character',)
+vim.current.buffer.mark("!"):error:('invalid mark name',)
+>> BufferRange
+vim.current.buffer.range(1, 2, 3):TypeError:('function takes exactly 2 arguments (3 given)',)
+> BufMap
+>> BufMapItem
+vim.buffers[100000000]:KeyError:(100000000,)
+>>> Testing NumberToLong using vim.buffers[%s]
+vim.buffers[[]]:TypeError:('expected int(), long() or something supporting coercing to long(), but got list',)
+vim.buffers[None]:TypeError:('expected int(), long() or something supporting coercing to long(), but got NoneType',)
+vim.buffers[-1]:ValueError:('number must be greater than zero',)
+vim.buffers[0]:ValueError:('number must be greater than zero',)
+<<< Finished
+> Current
+>> CurrentGetattr
+vim.current.xxx:AttributeError:('xxx',)
+>> CurrentSetattr
+vim.current.line = True:TypeError:('bad argument type for built-in operation',)
+vim.current.buffer = True:TypeError:('expected vim.Buffer object, but got bool',)
+vim.current.window = True:TypeError:('expected vim.Window object, but got bool',)
+vim.current.tabpage = True:TypeError:('expected vim.TabPage object, but got bool',)
+vim.current.xxx = True:AttributeError:('xxx',)
+['/testdir']
+'/testdir'
+2,xx
+before
+after
+pythonx/topmodule/__init__.py
+pythonx/topmodule/submodule/__init__.py
+pythonx/topmodule/submodule/subsubmodule/subsubsubmodule.py
+vim.command("throw 'abcN'"):error:('abcN',)
+Exe("throw 'def'"):error:('def',)
+vim.eval("Exe('throw ''ghi''')"):error:('ghi',)
+vim.eval("Exe('echoerr ''jkl''')"):error:('Vim(echoerr):jkl',)
+vim.eval("Exe('xxx_non_existent_command_xxx')"):error:('Vim:E492: Not an editor command: xxx_non_existent_command_xxx',)
+vim.eval("xxx_unknown_function_xxx()"):error:('Vim:E117: Unknown function: xxx_unknown_function_xxx',)
+vim.bindeval("Exe('xxx_non_existent_command_xxx')"):error:('Vim:E492: Not an editor command: xxx_non_existent_command_xxx',)
+Caught KeyboardInterrupt
+Running :put
+No exception
+
diff --git a/src/testdir/test87.in b/src/testdir/test87.in
new file mode 100644
index 0000000..31de37b
--- /dev/null
+++ b/src/testdir/test87.in
@@ -0,0 +1,1725 @@
+Tests for various python features. vim: set ft=vim :
+
+STARTTEST
+:so small.vim
+:set noswapfile
+:if !has('python3') | e! test.ok | wq! test.out | endif
+:lang C
+:fun Test()
+:py3 import vim
+:py3 cb = vim.current.buffer
+:let l = []
+:py3 l=vim.bindeval('l')
+:py3 f=vim.bindeval('function("strlen")')
+:" Extending List directly with different types
+:py3 l+=[1, "as'd", [1, 2, f, {'a': 1}]]
+:$put =string(l)
+:$put =string(l[-1])
+:try
+: $put =string(l[-4])
+:catch
+: $put =v:exception[:13]
+:endtry
+:" List assignment
+:py3 l[0]=0
+:$put =string(l)
+:py3 l[-2]=f
+:$put =string(l)
+:"
+:" Extending Dictionary directly with different types
+:let d = {}
+:fun d.f()
+: return 1
+:endfun
+py3 << EOF
+d=vim.bindeval('d')
+d['1']='asd'
+d.update() # Must not do anything, including throwing errors
+d.update(b=[1, 2, f])
+d.update((('-1', {'a': 1}),))
+d.update({'0': -1})
+dk = d.keys()
+dv = d.values()
+di = d.items()
+dk.sort(key=repr)
+dv.sort(key=repr)
+di.sort(key=repr)
+EOF
+:$put =py3eval('d[''f''](self={})')
+:$put =py3eval('repr(dk)')
+:$put =substitute(py3eval('repr(dv)'),'0x\x\+','','g')
+:$put =substitute(py3eval('repr(di)'),'0x\x\+','','g')
+:for [key, Val] in sort(items(d))
+: $put =string(key) . ' : ' . string(Val)
+: unlet key Val
+:endfor
+:py3 del dk
+:py3 del di
+:py3 del dv
+:"
+:" removing items with del
+:py3 del l[2]
+:$put =string(l)
+:let l = range(8)
+:py3 l=vim.bindeval('l')
+:try
+: py3 del l[:3]
+: py3 del l[1:]
+:catch
+: $put =v:exception
+:endtry
+:$put =string(l)
+:"
+:py3 del d['-1']
+:py3 del d['f']
+:$put =string(py3eval('d.get(''b'', 1)'))
+:$put =string(py3eval('d.pop(''b'')'))
+:$put =string(py3eval('d.get(''b'', 1)'))
+:$put =string(py3eval('d.pop(''1'', 2)'))
+:$put =string(py3eval('d.pop(''1'', 2)'))
+:$put =py3eval('repr(d.has_key(''0''))')
+:$put =py3eval('repr(d.has_key(''1''))')
+:$put =py3eval('repr(''0'' in d)')
+:$put =py3eval('repr(''1'' in d)')
+:$put =py3eval('repr(list(iter(d)))')
+:$put =string(d)
+:$put =py3eval('repr(d.popitem())')
+:$put =py3eval('repr(d.get(''0''))')
+:$put =py3eval('repr(list(iter(d)))')
+:"
+:" removing items out of range: silently skip items that don't exist
+:let l = [0, 1, 2, 3]
+:py3 l=vim.bindeval('l')
+:" The following two ranges delete nothing as they match empty list:
+:py3 del l[2:1]
+:$put =string(l)
+:py3 del l[2:2]
+:$put =string(l)
+:py3 del l[2:3]
+:$put =string(l)
+:let l = [0, 1, 2, 3]
+:py3 l=vim.bindeval('l')
+:py3 del l[2:4]
+:$put =string(l)
+:let l = [0, 1, 2, 3]
+:py3 l=vim.bindeval('l')
+:py3 del l[2:5]
+:$put =string(l)
+:let l = [0, 1, 2, 3]
+:py3 l=vim.bindeval('l')
+:py3 del l[2:6]
+:$put =string(l)
+:let l = [0, 1, 2, 3]
+:py3 l=vim.bindeval('l')
+:" The following two ranges delete nothing as they match empty list:
+:py3 del l[-1:2]
+:$put =string(l)
+:py3 del l[-2:2]
+:$put =string(l)
+:py3 del l[-3:2]
+:$put =string(l)
+:let l = [0, 1, 2, 3]
+:py3 l=vim.bindeval('l')
+:py3 del l[-4:2]
+:$put =string(l)
+:let l = [0, 1, 2, 3]
+:py3 l=vim.bindeval('l')
+:py3 del l[-5:2]
+:$put =string(l)
+:let l = [0, 1, 2, 3]
+:py3 l=vim.bindeval('l')
+:py3 del l[-6:2]
+:$put =string(l)
+:let l = [0, 1, 2, 3]
+:py3 l=vim.bindeval('l')
+:py3 del l[::2]
+:$put =string(l)
+:let l = [0, 1, 2, 3]
+:py3 l=vim.bindeval('l')
+:py3 del l[3:0:-2]
+:$put =string(l)
+:let l = [0, 1, 2, 3]
+:py3 l=vim.bindeval('l')
+:py3 del l[2:4:-2]
+:$put =string(l)
+:"
+:" Slice assignment to a list
+:let l = [0, 1, 2, 3]
+:py3 l=vim.bindeval('l')
+:py3 l[0:0]=['a']
+:$put =string(l)
+:let l = [0, 1, 2, 3]
+:py3 l=vim.bindeval('l')
+:py3 l[1:2]=['b']
+:$put =string(l)
+:let l = [0, 1, 2, 3]
+:py3 l=vim.bindeval('l')
+:py3 l[2:4]=['c']
+:$put =string(l)
+:let l = [0, 1, 2, 3]
+:py3 l=vim.bindeval('l')
+:py3 l[4:4]=['d']
+:$put =string(l)
+:let l = [0, 1, 2, 3]
+:py3 l=vim.bindeval('l')
+:py3 l[-1:2]=['e']
+:$put =string(l)
+:let l = [0, 1, 2, 3]
+:py3 l=vim.bindeval('l')
+:py3 l[-10:2]=['f']
+:$put =string(l)
+:let l = [0, 1, 2, 3]
+:py3 l=vim.bindeval('l')
+:py3 l[2:-10]=['g']
+:$put =string(l)
+:let l = []
+:py3 l=vim.bindeval('l')
+:py3 l[0:0]=['h']
+:$put =string(l)
+:let l = range(8)
+:py3 l=vim.bindeval('l')
+:py3 l[2:6:2] = [10, 20]
+:$put =string(l)
+:let l = range(8)
+:py3 l=vim.bindeval('l')
+:py3 l[6:2:-2] = [10, 20]
+:$put =string(l)
+:let l = range(8)
+:py3 l=vim.bindeval('l')
+:py3 l[6:2] = ()
+:$put =string(l)
+:let l = range(8)
+:py3 l=vim.bindeval('l')
+:py3 l[6:2:1] = ()
+:$put =string(l)
+:let l = range(8)
+:py3 l=vim.bindeval('l')
+:py3 l[2:2:1] = ()
+:$put =string(l)
+:"
+:" Locked variables
+:let l = [0, 1, 2, 3]
+:py3 l=vim.bindeval('l')
+:lockvar! l
+py3 << EOF
+def emsg(ei):
+ return ei[0].__name__ + ':' + repr(ei[1].args)
+
+try:
+ l[2]='i'
+except vim.error:
+ cb.append('l[2] threw vim.error: ' + emsg(sys.exc_info()))
+EOF
+:$put =string(l)
+:unlockvar! l
+:"
+:" Function calls
+py3 << EOF
+import sys
+import re
+
+py33_type_error_pattern = re.compile('^__call__\(\) takes (\d+) positional argument but (\d+) were given$')
+py37_exception_repr = re.compile(r'([^\(\),])(\)+)$')
+
+def ee(expr, g=globals(), l=locals()):
+ cb = vim.current.buffer
+ try:
+ try:
+ exec(expr, g, l)
+ except Exception as e:
+ if sys.version_info >= (3, 3) and e.__class__ is AttributeError and str(e).find('has no attribute')>=0 and not str(e).startswith("'vim."):
+ msg = repr((e.__class__, AttributeError(str(e)[str(e).rfind(" '") + 2:-1])))
+ elif sys.version_info >= (3, 3) and e.__class__ is ImportError and str(e).find('No module named \'') >= 0:
+ msg = repr((e.__class__, ImportError(str(e).replace("'", ''))))
+ elif sys.version_info >= (3, 6) and e.__class__ is ModuleNotFoundError:
+ # Python 3.6 gives ModuleNotFoundError, change it to an ImportError
+ msg = repr((ImportError, ImportError(str(e).replace("'", ''))))
+ elif sys.version_info >= (3, 3) and e.__class__ is TypeError:
+ m = py33_type_error_pattern.search(str(e))
+ if m:
+ msg = '__call__() takes exactly {0} positional argument ({1} given)'.format(m.group(1), m.group(2))
+ msg = repr((e.__class__, TypeError(msg)))
+ else:
+ msg = repr((e.__class__, e))
+ # Messages changed with Python 3.6, change new to old.
+ newmsg1 = """'argument must be str, bytes or bytearray, not None'"""
+ oldmsg1 = '''"Can't convert 'NoneType' object to str implicitly"'''
+ if msg.find(newmsg1) > -1:
+ msg = msg.replace(newmsg1, oldmsg1)
+ newmsg2 = """'argument must be str, bytes or bytearray, not int'"""
+ oldmsg2 = '''"Can't convert 'int' object to str implicitly"'''
+ if msg.find(newmsg2) > -1:
+ msg = msg.replace(newmsg2, oldmsg2)
+ elif sys.version_info >= (3, 5) and e.__class__ is ValueError and str(e) == 'embedded null byte':
+ msg = repr((TypeError, TypeError('expected bytes with no null')))
+ else:
+ msg = repr((e.__class__, e))
+ # Some Python versions say can't, others cannot.
+ if msg.find('can\'t') > -1:
+ msg = msg.replace('can\'t', 'cannot')
+ # Some Python versions use single quote, some double quote
+ if msg.find('"cannot ') > -1:
+ msg = msg.replace('"cannot ', '\'cannot ')
+ if msg.find(' attributes"') > -1:
+ msg = msg.replace(' attributes"', ' attributes\'')
+ if sys.version_info >= (3, 7):
+ msg = py37_exception_repr.sub(r'\1,\2', msg)
+ cb.append(expr + ':' + msg)
+ else:
+ cb.append(expr + ':NOT FAILED')
+ except Exception as e:
+ msg = repr((e.__class__, e))
+ if sys.version_info >= (3, 7):
+ msg = py37_exception_repr.sub(r'\1,\2', msg)
+ cb.append(expr + '::' + msg)
+EOF
+:fun New(...)
+: return ['NewStart']+a:000+['NewEnd']
+:endfun
+:fun DictNew(...) dict
+: return ['DictNewStart']+a:000+['DictNewEnd', self]
+:endfun
+:let l=[function('New'), function('DictNew')]
+:py3 l=vim.bindeval('l')
+:py3 l.extend(list(l[0](1, 2, 3)))
+:$put =string(l)
+:py3 l.extend(list(l[1](1, 2, 3, self={'a': 'b'})))
+:$put =string(l)
+:py3 l+=[l[0].name]
+:$put =string(l)
+:py3 ee('l[1](1, 2, 3)')
+:py3 f=l[0]
+:delfunction New
+:py3 ee('f(1, 2, 3)')
+:if has('float')
+: let l=[0.0]
+: py3 l=vim.bindeval('l')
+: py3 l.extend([0.0])
+: $put =string(l)
+:else
+: $put ='[0.0, 0.0]'
+:endif
+:let messages=[]
+:delfunction DictNew
+py3 <<EOF
+import sys
+d=vim.bindeval('{}')
+m=vim.bindeval('messages')
+def em(expr, g=globals(), l=locals()):
+ try:
+ exec(expr, g, l)
+ except Exception as e:
+ if sys.version_info >= (3, 5) and e.__class__ is ValueError and str(e) == 'embedded null byte':
+ m.extend([TypeError.__name__])
+ else:
+ m.extend([e.__class__.__name__])
+
+em('d["abc1"]')
+em('d["abc1"]="\\0"')
+em('d["abc1"]=vim')
+em('d[""]=1')
+em('d["a\\0b"]=1')
+em('d[b"a\\0b"]=1')
+
+em('d.pop("abc1")')
+em('d.popitem()')
+del em
+del m
+EOF
+:$put =messages
+:unlet messages
+:" locked and scope attributes
+:let d={} | let dl={} | lockvar dl
+:for s in split("d dl v: g:")
+: let name=tr(s, ':', 's')
+: execute 'py3 '.name.'=vim.bindeval("'.s.'")'
+: let toput=s.' : '.join(map(['locked', 'scope'], 'v:val.":".py3eval(name.".".v:val)'), ';')
+: $put =toput
+:endfor
+:silent! let d.abc2=1
+:silent! let dl.abc3=1
+:py3 d.locked=True
+:py3 dl.locked=False
+:silent! let d.def=1
+:silent! let dl.def=1
+:put ='d:'.string(d)
+:put ='dl:'.string(dl)
+:unlet d dl
+:
+:let l=[] | let ll=[] | lockvar ll
+:for s in split("l ll")
+: let name=tr(s, ':', 's')
+: execute 'py3 '.name.'=vim.bindeval("'.s.'")'
+: let toput=s.' : locked:'.py3eval(name.'.locked')
+: $put =toput
+:endfor
+:silent! call extend(l, [0])
+:silent! call extend(ll, [0])
+:py3 l.locked=True
+:py3 ll.locked=False
+:silent! call extend(l, [1])
+:silent! call extend(ll, [1])
+:put ='l:'.string(l)
+:put ='ll:'.string(ll)
+:unlet l ll
+:"
+:" py3eval()
+:let l=py3eval('[0, 1, 2]')
+:$put =string(l)
+:let d=py3eval('{"a": "b", "c": 1, "d": ["e"]}')
+:$put =sort(items(d))
+:let v:errmsg = ''
+:$put ='py3eval(\"None\") = ' . py3eval('None') . v:errmsg
+:if has('float')
+: let f=py3eval('0.0')
+: $put =string(f)
+:else
+: $put ='0.0'
+:endif
+:" Invalid values:
+:for e in ['"\0"', '{"\0": 1}', 'undefined_name', 'vim']
+: try
+: let v=py3eval(e)
+: catch
+: let toput=e.":\t".v:exception[:13]
+: $put =toput
+: endtry
+:endfor
+:"
+:" threading
+:let l = [0]
+:py3 l=vim.bindeval('l')
+py3 <<EOF
+import threading
+import time
+
+class T(threading.Thread):
+ def __init__(self):
+ threading.Thread.__init__(self)
+ self.t = 0
+ self.running = True
+
+ def run(self):
+ while self.running:
+ self.t += 1
+ time.sleep(0.1)
+
+t = T()
+del T
+t.start()
+EOF
+:sleep 1
+:py3 t.running = False
+:py3 t.join()
+:" Check if the background thread is working. Count should be 10, but on a
+:" busy system (AppVeyor) it can be much lower.
+:py3 l[0] = t.t > 4
+:py3 del time
+:py3 del threading
+:py3 del t
+:$put =string(l)
+:"
+:" settrace
+:let l = []
+:py3 l=vim.bindeval('l')
+py3 <<EOF
+import sys
+
+def traceit(frame, event, arg):
+ global l
+ if event == "line":
+ l += [frame.f_lineno]
+ return traceit
+
+def trace_main():
+ for i in range(5):
+ pass
+EOF
+:py3 sys.settrace(traceit)
+:py3 trace_main()
+:py3 sys.settrace(None)
+:py3 del traceit
+:py3 del trace_main
+:$put =string(l)
+:"
+:" Slice
+:py3 ll = vim.bindeval('[0, 1, 2, 3, 4, 5]')
+:py3 l = ll[:4]
+:$put =string(py3eval('l'))
+:py3 l = ll[2:]
+:$put =string(py3eval('l'))
+:py3 l = ll[:-4]
+:$put =string(py3eval('l'))
+:py3 l = ll[-2:]
+:$put =string(py3eval('l'))
+:py3 l = ll[2:4]
+:$put =string(py3eval('l'))
+:py3 l = ll[4:2]
+:$put =string(py3eval('l'))
+:py3 l = ll[-4:-2]
+:$put =string(py3eval('l'))
+:py3 l = ll[-2:-4]
+:$put =string(py3eval('l'))
+:py3 l = ll[:]
+:$put =string(py3eval('l'))
+:py3 l = ll[0:6]
+:$put =string(py3eval('l'))
+:py3 l = ll[-10:10]
+:$put =string(py3eval('l'))
+:py3 l = ll[4:2:-1]
+:$put =string(py3eval('l'))
+:py3 l = ll[::2]
+:$put =string(py3eval('l'))
+:py3 l = ll[4:2:1]
+:$put =string(py3eval('l'))
+:py3 del l
+:"
+:" Vars
+:let g:foo = 'bac'
+:let w:abc3 = 'def'
+:let b:baz = 'bar'
+:let t:bar = 'jkl'
+:try
+: throw "Abc"
+:catch
+: put =py3eval('vim.vvars[''exception'']')
+:endtry
+:put =py3eval('vim.vars[''foo'']')
+:put =py3eval('vim.current.window.vars[''abc3'']')
+:put =py3eval('vim.current.buffer.vars[''baz'']')
+:put =py3eval('vim.current.tabpage.vars[''bar'']')
+:"
+:" Options
+:" paste: boolean, global
+:" previewheight number, global
+:" operatorfunc: string, global
+:" number: boolean, window-local
+:" numberwidth: number, window-local
+:" colorcolumn: string, window-local
+:" statusline: string, window-local/global
+:" autoindent: boolean, buffer-local
+:" shiftwidth: number, buffer-local
+:" omnifunc: string, buffer-local
+:" preserveindent: boolean, buffer-local/global
+:" path: string, buffer-local/global
+:let g:bufs=[bufnr('%')]
+:new
+:let g:bufs+=[bufnr('%')]
+:vnew
+:let g:bufs+=[bufnr('%')]
+:wincmd j
+:vnew
+:let g:bufs+=[bufnr('%')]
+:wincmd l
+:fun RecVars(opt)
+: let gval =string(eval('&g:'.a:opt))
+: let wvals=join(map(range(1, 4), 'v:val.":".string(getwinvar(v:val, "&".a:opt))'))
+: let bvals=join(map(copy(g:bufs), 'v:val.":".string(getbufvar(v:val, "&".a:opt))'))
+: put =' G: '.gval
+: put =' W: '.wvals
+: put =' B: '.wvals
+:endfun
+py3 << EOF
+def e(s, g=globals(), l=locals()):
+ try:
+ exec(s, g, l)
+ except Exception as e:
+ vim.command('return ' + repr(e.__class__.__name__))
+
+def ev(s, g=globals(), l=locals()):
+ try:
+ return eval(s, g, l)
+ except Exception as e:
+ vim.command('let exc=' + repr(e.__class__.__name__))
+ return 0
+EOF
+:fun E(s)
+: python3 e(vim.eval('a:s'))
+:endfun
+:fun Ev(s)
+: let r=py3eval('ev(vim.eval("a:s"))')
+: if exists('exc')
+: throw exc
+: endif
+: return r
+:endfun
+:py3 gopts1=vim.options
+:py3 wopts1=vim.windows[2].options
+:py3 wopts2=vim.windows[0].options
+:py3 wopts3=vim.windows[1].options
+:py3 bopts1=vim.buffers[vim.bindeval("g:bufs")[2]].options
+:py3 bopts2=vim.buffers[vim.bindeval("g:bufs")[1]].options
+:py3 bopts3=vim.buffers[vim.bindeval("g:bufs")[0]].options
+:$put ='wopts iters equal: '.py3eval('list(wopts1) == list(wopts2)')
+:$put ='bopts iters equal: '.py3eval('list(bopts1) == list(bopts2)')
+:py3 gset=set(iter(gopts1))
+:py3 wset=set(iter(wopts1))
+:py3 bset=set(iter(bopts1))
+:set path=.,..,,
+:let lst=[]
+:let lst+=[['paste', 1, 0, 1, 2, 1, 1, 0 ]]
+:let lst+=[['previewheight', 5, 1, 6, 'a', 0, 1, 0 ]]
+:let lst+=[['operatorfunc', 'A', 'B', 'C', 2, 0, 1, 0 ]]
+:let lst+=[['number', 0, 1, 1, 0, 1, 0, 1 ]]
+:let lst+=[['numberwidth', 2, 3, 5, -100, 0, 0, 1 ]]
+:let lst+=[['colorcolumn', '+1', '+2', '+3', 'abc4', 0, 0, 1 ]]
+:let lst+=[['statusline', '1', '2', '4', 0, 0, 1, 1 ]]
+:let lst+=[['autoindent', 0, 1, 1, 2, 1, 0, 2 ]]
+:let lst+=[['shiftwidth', 0, 2, 1, 3, 0, 0, 2 ]]
+:let lst+=[['omnifunc', 'A', 'B', 'C', 1, 0, 0, 2 ]]
+:let lst+=[['preserveindent', 0, 1, 1, 2, 1, 1, 2 ]]
+:let lst+=[['path', '.,,', ',,', '.', 0, 0, 1, 2 ]]
+:for [oname, oval1, oval2, oval3, invval, bool, global, local] in lst
+: py3 oname=vim.eval('oname')
+: py3 oval1=vim.bindeval('oval1')
+: py3 oval2=vim.bindeval('oval2')
+: py3 oval3=vim.bindeval('oval3')
+: if invval is 0 || invval is 1
+: py3 invval=bool(vim.bindeval('invval'))
+: else
+: py3 invval=vim.bindeval('invval')
+: endif
+: if bool
+: py3 oval1=bool(oval1)
+: py3 oval2=bool(oval2)
+: py3 oval3=bool(oval3)
+: endif
+: put ='>>> '.oname
+: $put =' g/w/b:'.py3eval('oname in gset').'/'.py3eval('oname in wset').'/'.py3eval('oname in bset')
+: $put =' g/w/b (in):'.py3eval('oname in gopts1').'/'.py3eval('oname in wopts1').'/'.py3eval('oname in bopts1')
+: for v in ['gopts1', 'wopts1', 'bopts1']
+: try
+: put =' p/'.v.': '.Ev('repr('.v.'['''.oname.'''])')
+: catch
+: put =' p/'.v.'! '.v:exception
+: endtry
+: let r=E(v.'['''.oname.''']=invval')
+: if r isnot 0
+: put =' inv: '.string(invval).'! '.r
+: endif
+: for vv in (v is# 'gopts1' ? [v] : [v, v[:-2].'2', v[:-2].'3'])
+: let val=substitute(vv, '^.opts', 'oval', '')
+: let r=E(vv.'['''.oname.''']='.val)
+: if r isnot 0
+: put =' '.vv.'! '.r
+: endif
+: endfor
+: endfor
+: call RecVars(oname)
+: for v in ['wopts3', 'bopts3']
+: let r=E('del '.v.'["'.oname.'"]')
+: if r isnot 0
+: put =' del '.v.'! '.r
+: endif
+: endfor
+: call RecVars(oname)
+:endfor
+:delfunction RecVars
+:delfunction E
+:delfunction Ev
+:py3 del ev
+:py3 del e
+:only
+:for buf in g:bufs[1:]
+: execute 'bwipeout!' buf
+:endfor
+:py3 del gopts1
+:py3 del wopts1
+:py3 del wopts2
+:py3 del wopts3
+:py3 del bopts1
+:py3 del bopts2
+:py3 del bopts3
+:py3 del oval1
+:py3 del oval2
+:py3 del oval3
+:py3 del oname
+:py3 del invval
+:"
+:" Test buffer object
+:vnew
+:put ='First line'
+:put ='Second line'
+:put ='Third line'
+:1 delete _
+:py3 b=vim.current.buffer
+:wincmd w
+:mark a
+:augroup BUFS
+: autocmd BufFilePost * python3 cb.append(vim.eval('expand("<abuf>")') + ':BufFilePost:' + vim.eval('bufnr("%")'))
+: autocmd BufFilePre * python3 cb.append(vim.eval('expand("<abuf>")') + ':BufFilePre:' + vim.eval('bufnr("%")'))
+:augroup END
+py3 << EOF
+# Tests BufferAppend and BufferItem
+cb.append(b[0])
+# Tests BufferSlice and BufferAssSlice
+cb.append('abc5') # Will be overwritten
+cb[-1:] = b[:-2]
+# Test BufferLength and BufferAssSlice
+cb.append('def') # Will not be overwritten
+cb[len(cb):] = b[:]
+# Test BufferAssItem and BufferMark
+cb.append('ghi') # Will be overwritten
+cb[-1] = repr((len(cb) - cb.mark('a')[0], cb.mark('a')[1]))
+# Test BufferRepr
+cb.append(repr(cb) + repr(b))
+# Modify foreign buffer
+b.append('foo')
+b[0]='bar'
+b[0:0]=['baz']
+vim.command('call append("$", getbufline(%i, 1, "$"))' % b.number)
+# Test assigning to name property
+import os
+old_name = cb.name
+cb.name = 'foo'
+cb.append(cb.name[-11:].replace(os.path.sep, '/'))
+b.name = 'bar'
+cb.append(b.name[-11:].replace(os.path.sep, '/'))
+cb.name = old_name
+cb.append(cb.name[-17:].replace(os.path.sep, '/'))
+del old_name
+# Test CheckBuffer
+for _b in vim.buffers:
+ if _b is not cb:
+ vim.command('bwipeout! ' + str(_b.number))
+del _b
+cb.append('valid: b:%s, cb:%s' % (repr(b.valid), repr(cb.valid)))
+for expr in ('b[1]','b[:] = ["A", "B"]','b[:]','b.append("abc6")'):
+ try:
+ exec(expr)
+ except vim.error:
+ pass
+ else:
+ # Usually a SEGV here
+ # Should not happen in any case
+ cb.append('No exception for ' + expr)
+vim.command('cd .')
+del b
+EOF
+:"
+:" Test vim.buffers object
+:set hidden
+:edit a
+:buffer #
+:edit b
+:buffer #
+:edit c
+:buffer #
+py3 << EOF
+# Check GCing iterator that was not fully exhausted
+i = iter(vim.buffers)
+cb.append('i:' + str(next(i)))
+# and also check creating more than one iterator at a time
+i2 = iter(vim.buffers)
+cb.append('i2:' + str(next(i2)))
+cb.append('i:' + str(next(i)))
+# The following should trigger GC and not cause any problems
+del i
+del i2
+i3 = iter(vim.buffers)
+cb.append('i3:' + str(next(i3)))
+del i3
+
+prevnum = 0
+for b in vim.buffers:
+ # Check buffer order
+ if prevnum >= b.number:
+ cb.append('!!! Buffer numbers not in strictly ascending order')
+ # Check indexing: vim.buffers[number].number == number
+ cb.append(str(b.number) + ':' + repr(vim.buffers[b.number]) + '=' + repr(b))
+ prevnum = b.number
+del prevnum
+
+cb.append(str(len(vim.buffers)))
+
+bnums = list(map(lambda b: b.number, vim.buffers))[1:]
+
+# Test wiping out buffer with existing iterator
+i4 = iter(vim.buffers)
+cb.append('i4:' + str(next(i4)))
+vim.command('bwipeout! ' + str(bnums.pop(0)))
+try:
+ next(i4)
+except vim.error:
+ pass
+else:
+ cb.append('!!!! No vim.error')
+i4 = iter(vim.buffers)
+vim.command('bwipeout! ' + str(bnums.pop(-1)))
+vim.command('bwipeout! ' + str(bnums.pop(-1)))
+cb.append('i4:' + str(next(i4)))
+try:
+ next(i4)
+except StopIteration:
+ cb.append('StopIteration')
+del i4
+del bnums
+EOF
+:"
+:" Test vim.{tabpage,window}list and vim.{tabpage,window} objects
+:tabnew 0
+:tabnew 1
+:vnew a.1
+:tabnew 2
+:vnew a.2
+:vnew b.2
+:vnew c.2
+py3 << EOF
+cb.append('Number of tabs: ' + str(len(vim.tabpages)))
+cb.append('Current tab pages:')
+
+def W(w):
+ if '(unknown)' in repr(w):
+ return '<window object (unknown)>'
+ else:
+ return repr(w)
+
+def Cursor(w, start=len(cb)):
+ if w.buffer is cb:
+ return repr((start - w.cursor[0], w.cursor[1]))
+ else:
+ return repr(w.cursor)
+
+for t in vim.tabpages:
+ cb.append(' ' + repr(t) + '(' + str(t.number) + ')' + ': ' + str(len(t.windows)) + ' windows, current is ' + W(t.window))
+ cb.append(' Windows:')
+ for w in t.windows:
+ cb.append(' ' + W(w) + '(' + str(w.number) + ')' + ': displays buffer ' + repr(w.buffer) + '; cursor is at ' + Cursor(w))
+ # Other values depend on the size of the terminal, so they are checked partly:
+ for attr in ('height', 'row', 'width', 'col'):
+ try:
+ aval = getattr(w, attr)
+ if type(aval) is not int:
+ raise TypeError
+ if aval < 0:
+ raise ValueError
+ except Exception as e:
+ cb.append('!!!!!! Error while getting attribute ' + attr + ': ' + e.__class__.__name__)
+ del aval
+ del attr
+ w.cursor = (len(w.buffer), 0)
+del W
+del Cursor
+cb.append('Number of windows in current tab page: ' + str(len(vim.windows)))
+if list(vim.windows) != list(vim.current.tabpage.windows):
+ cb.append('!!!!!! Windows differ')
+EOF
+:"
+:" Test vim.current
+py3 << EOF
+def H(o):
+ return repr(o)
+cb.append('Current tab page: ' + repr(vim.current.tabpage))
+cb.append('Current window: ' + repr(vim.current.window) + ': ' + H(vim.current.window) + ' is ' + H(vim.current.tabpage.window))
+cb.append('Current buffer: ' + repr(vim.current.buffer) + ': ' + H(vim.current.buffer) + ' is ' + H(vim.current.window.buffer)+ ' is ' + H(vim.current.tabpage.window.buffer))
+del H
+# Assigning: fails
+try:
+ vim.current.window = vim.tabpages[0].window
+except ValueError:
+ cb.append('ValueError at assigning foreign tab window')
+
+for attr in ('window', 'tabpage', 'buffer'):
+ try:
+ setattr(vim.current, attr, None)
+ except TypeError:
+ cb.append('Type error at assigning None to vim.current.' + attr)
+del attr
+
+# Assigning: success
+vim.current.tabpage = vim.tabpages[-2]
+vim.current.buffer = cb
+vim.current.window = vim.windows[0]
+vim.current.window.cursor = (len(vim.current.buffer), 0)
+cb.append('Current tab page: ' + repr(vim.current.tabpage))
+cb.append('Current window: ' + repr(vim.current.window))
+cb.append('Current buffer: ' + repr(vim.current.buffer))
+cb.append('Current line: ' + repr(vim.current.line))
+ws = list(vim.windows)
+ts = list(vim.tabpages)
+for b in vim.buffers:
+ if b is not cb:
+ vim.command('bwipeout! ' + str(b.number))
+del b
+cb.append('w.valid: ' + repr([w.valid for w in ws]))
+cb.append('t.valid: ' + repr([t.valid for t in ts]))
+del w
+del t
+del ts
+del ws
+EOF
+:tabonly!
+:only!
+:"
+:" Test types
+py3 << EOF
+for expr, attr in (
+ ('vim.vars', 'Dictionary'),
+ ('vim.options', 'Options'),
+ ('vim.bindeval("{}")', 'Dictionary'),
+ ('vim.bindeval("[]")', 'List'),
+ ('vim.bindeval("function(\'tr\')")', 'Function'),
+ ('vim.current.buffer', 'Buffer'),
+ ('vim.current.range', 'Range'),
+ ('vim.current.window', 'Window'),
+ ('vim.current.tabpage', 'TabPage'),
+):
+ cb.append(expr + ':' + attr + ':' + repr(type(eval(expr)) is getattr(vim, attr)))
+del expr
+del attr
+EOF
+:"
+:" Test __dir__() method
+py3 << EOF
+for name, o in (
+ ('current', vim.current),
+ ('buffer', vim.current.buffer),
+ ('window', vim.current.window),
+ ('tabpage', vim.current.tabpage),
+ ('range', vim.current.range),
+ ('dictionary', vim.bindeval('{}')),
+ ('list', vim.bindeval('[]')),
+ ('function', vim.bindeval('function("tr")')),
+ ('output', sys.stdout),
+ ):
+ cb.append(name + ':' + ','.join(dir(o)))
+del name
+del o
+EOF
+:"
+:" Test vim.*.__new__
+:$put =string(py3eval('vim.Dictionary({})'))
+:$put =string(py3eval('vim.Dictionary(a=1)'))
+:$put =string(py3eval('vim.Dictionary(((''a'', 1),))'))
+:$put =string(py3eval('vim.List()'))
+:$put =string(py3eval('vim.List(iter(''abc7''))'))
+:$put =string(py3eval('vim.Function(''tr'')'))
+:$put =string(py3eval('vim.Function(''tr'', args=[123, 3, 4])'))
+:$put =string(py3eval('vim.Function(''tr'', args=[])'))
+:$put =string(py3eval('vim.Function(''tr'', self={})'))
+:$put =string(py3eval('vim.Function(''tr'', args=[123, 3, 4], self={})'))
+:$put ='auto_rebind'
+:$put =string(py3eval('vim.Function(''tr'', auto_rebind=False)'))
+:$put =string(py3eval('vim.Function(''tr'', args=[123, 3, 4], auto_rebind=False)'))
+:$put =string(py3eval('vim.Function(''tr'', args=[], auto_rebind=False)'))
+:$put =string(py3eval('vim.Function(''tr'', self={}, auto_rebind=False)'))
+:$put =string(py3eval('vim.Function(''tr'', args=[123, 3, 4], self={}, auto_rebind=False)'))
+:"
+:" Test vim.Function
+:function Args(...)
+: return a:000
+:endfunction
+:function SelfArgs(...) dict
+: return [a:000, self]
+:endfunction
+:" The following four lines should not crash
+:let Pt = function('tr', [[]], {'l': []})
+:py3 Pt = vim.bindeval('Pt')
+:unlet Pt
+:py3 del Pt
+py3 << EOF
+def ecall(out_prefix, func, *args, **kwargs):
+ line = out_prefix + ': '
+ try:
+ ret = func(*args, **kwargs)
+ except Exception:
+ line += '!exception: ' + emsg(sys.exc_info())
+ else:
+ line += '!result: ' + str(vim.Function('string')(ret), 'utf-8')
+ cb.append(line)
+a = vim.Function('Args')
+pa1 = vim.Function('Args', args=['abcArgsPA1'])
+pa2 = vim.Function('Args', args=[])
+pa3 = vim.Function('Args', args=['abcArgsPA3'], self={'abcSelfPA3': 'abcSelfPA3Val'})
+pa4 = vim.Function('Args', self={'abcSelfPA4': 'abcSelfPA4Val'})
+cb.append('a: ' + repr(a))
+cb.append('pa1: ' + repr(pa1))
+cb.append('pa2: ' + repr(pa2))
+cb.append('pa3: ' + repr(pa3))
+cb.append('pa4: ' + repr(pa4))
+sa = vim.Function('SelfArgs')
+psa1 = vim.Function('SelfArgs', args=['abcArgsPSA1'])
+psa2 = vim.Function('SelfArgs', args=[])
+psa3 = vim.Function('SelfArgs', args=['abcArgsPSA3'], self={'abcSelfPSA3': 'abcSelfPSA3Val'})
+psa4 = vim.Function('SelfArgs', self={'abcSelfPSA4': 'abcSelfPSA4Val'})
+psa5 = vim.Function('SelfArgs', self={'abcSelfPSA5': 'abcSelfPSA5Val'}, auto_rebind=0)
+psa6 = vim.Function('SelfArgs', args=['abcArgsPSA6'], self={'abcSelfPSA6': 'abcSelfPSA6Val'}, auto_rebind=())
+psa7 = vim.Function('SelfArgs', args=['abcArgsPSA7'], auto_rebind=[])
+psa8 = vim.Function('SelfArgs', auto_rebind=False)
+psa9 = vim.Function('SelfArgs', self={'abcSelfPSA9': 'abcSelfPSA9Val'}, auto_rebind=True)
+psaA = vim.Function('SelfArgs', args=['abcArgsPSAA'], self={'abcSelfPSAA': 'abcSelfPSAAVal'}, auto_rebind=1)
+psaB = vim.Function('SelfArgs', args=['abcArgsPSAB'], auto_rebind={'abcARPSAB': 'abcARPSABVal'})
+psaC = vim.Function('SelfArgs', auto_rebind=['abcARPSAC'])
+cb.append('sa: ' + repr(sa))
+cb.append('psa1: ' + repr(psa1))
+cb.append('psa2: ' + repr(psa2))
+cb.append('psa3: ' + repr(psa3))
+cb.append('psa4: ' + repr(psa4))
+cb.append('psa5: ' + repr(psa5))
+cb.append('psa6: ' + repr(psa6))
+cb.append('psa7: ' + repr(psa7))
+cb.append('psa8: ' + repr(psa8))
+cb.append('psa9: ' + repr(psa9))
+cb.append('psaA: ' + repr(psaA))
+cb.append('psaB: ' + repr(psaB))
+cb.append('psaC: ' + repr(psaC))
+
+psar = vim.Function('SelfArgs', args=[{'abcArgsPSAr': 'abcArgsPSArVal'}], self={'abcSelfPSAr': 'abcSelfPSArVal'})
+psar.args[0]['abcArgsPSAr2'] = [psar.self, psar.args[0]]
+psar.self['rec'] = psar
+psar.self['self'] = psar.self
+psar.self['args'] = psar.args
+
+try:
+ cb.append('psar: ' + repr(psar))
+except Exception:
+ cb.append('!!!!!!!! Caught exception: ' + emsg(sys.exc_info()))
+EOF
+:$put ='s(a): '.string(py3eval('a'))
+:$put ='s(pa1): '.string(py3eval('pa1'))
+:$put ='s(pa2): '.string(py3eval('pa2'))
+:$put ='s(pa3): '.string(py3eval('pa3'))
+:$put ='s(pa4): '.string(py3eval('pa4'))
+:$put ='s(sa): '.string(py3eval('sa'))
+:$put ='s(psa1): '.string(py3eval('psa1'))
+:$put ='s(psa2): '.string(py3eval('psa2'))
+:$put ='s(psa3): '.string(py3eval('psa3'))
+:$put ='s(psa4): '.string(py3eval('psa4'))
+:$put ='s(psa5): '.string(py3eval('psa5'))
+:$put ='s(psa6): '.string(py3eval('psa6'))
+:$put ='s(psa7): '.string(py3eval('psa7'))
+:$put ='s(psa8): '.string(py3eval('psa8'))
+:$put ='s(psa9): '.string(py3eval('psa9'))
+:$put ='s(psaA): '.string(py3eval('psaA'))
+:$put ='s(psaB): '.string(py3eval('psaB'))
+:$put ='s(psaC): '.string(py3eval('psaC'))
+:
+:for v in ['sa', 'psa1', 'psa2', 'psa3', 'psa4', 'psa5', 'psa6', 'psa7', 'psa8', 'psa9', 'psaA', 'psaB', 'psaC']
+: let d = {'f': py3eval(v)}
+: $put ='d.'.v.'(): '.string(d.f())
+:endfor
+:
+:py3 ecall('a()', a, )
+:py3 ecall('pa1()', pa1, )
+:py3 ecall('pa2()', pa2, )
+:py3 ecall('pa3()', pa3, )
+:py3 ecall('pa4()', pa4, )
+:py3 ecall('sa()', sa, )
+:py3 ecall('psa1()', psa1, )
+:py3 ecall('psa2()', psa2, )
+:py3 ecall('psa3()', psa3, )
+:py3 ecall('psa4()', psa4, )
+:
+:py3 ecall('a(42, 43)', a, 42, 43)
+:py3 ecall('pa1(42, 43)', pa1, 42, 43)
+:py3 ecall('pa2(42, 43)', pa2, 42, 43)
+:py3 ecall('pa3(42, 43)', pa3, 42, 43)
+:py3 ecall('pa4(42, 43)', pa4, 42, 43)
+:py3 ecall('sa(42, 43)', sa, 42, 43)
+:py3 ecall('psa1(42, 43)', psa1, 42, 43)
+:py3 ecall('psa2(42, 43)', psa2, 42, 43)
+:py3 ecall('psa3(42, 43)', psa3, 42, 43)
+:py3 ecall('psa4(42, 43)', psa4, 42, 43)
+:
+:py3 ecall('a(42, self={"20": 1})', a, 42, self={'20': 1})
+:py3 ecall('pa1(42, self={"20": 1})', pa1, 42, self={'20': 1})
+:py3 ecall('pa2(42, self={"20": 1})', pa2, 42, self={'20': 1})
+:py3 ecall('pa3(42, self={"20": 1})', pa3, 42, self={'20': 1})
+:py3 ecall('pa4(42, self={"20": 1})', pa4, 42, self={'20': 1})
+:py3 ecall('sa(42, self={"20": 1})', sa, 42, self={'20': 1})
+:py3 ecall('psa1(42, self={"20": 1})', psa1, 42, self={'20': 1})
+:py3 ecall('psa2(42, self={"20": 1})', psa2, 42, self={'20': 1})
+:py3 ecall('psa3(42, self={"20": 1})', psa3, 42, self={'20': 1})
+:py3 ecall('psa4(42, self={"20": 1})', psa4, 42, self={'20': 1})
+:
+:py3 ecall('a(self={"20": 1})', a, self={'20': 1})
+:py3 ecall('pa1(self={"20": 1})', pa1, self={'20': 1})
+:py3 ecall('pa2(self={"20": 1})', pa2, self={'20': 1})
+:py3 ecall('pa3(self={"20": 1})', pa3, self={'20': 1})
+:py3 ecall('pa4(self={"20": 1})', pa4, self={'20': 1})
+:py3 ecall('sa(self={"20": 1})', sa, self={'20': 1})
+:py3 ecall('psa1(self={"20": 1})', psa1, self={'20': 1})
+:py3 ecall('psa2(self={"20": 1})', psa2, self={'20': 1})
+:py3 ecall('psa3(self={"20": 1})', psa3, self={'20': 1})
+:py3 ecall('psa4(self={"20": 1})', psa4, self={'20': 1})
+py3 << EOF
+def s(v):
+ if v is None:
+ return repr(v)
+ else:
+ return str(vim.Function('string')(v), 'utf-8')
+
+cb.append('a.args: ' + s(a.args))
+cb.append('pa1.args: ' + s(pa1.args))
+cb.append('pa2.args: ' + s(pa2.args))
+cb.append('pa3.args: ' + s(pa3.args))
+cb.append('pa4.args: ' + s(pa4.args))
+cb.append('sa.args: ' + s(sa.args))
+cb.append('psa1.args: ' + s(psa1.args))
+cb.append('psa2.args: ' + s(psa2.args))
+cb.append('psa3.args: ' + s(psa3.args))
+cb.append('psa4.args: ' + s(psa4.args))
+
+cb.append('a.self: ' + s(a.self))
+cb.append('pa1.self: ' + s(pa1.self))
+cb.append('pa2.self: ' + s(pa2.self))
+cb.append('pa3.self: ' + s(pa3.self))
+cb.append('pa4.self: ' + s(pa4.self))
+cb.append('sa.self: ' + s(sa.self))
+cb.append('psa1.self: ' + s(psa1.self))
+cb.append('psa2.self: ' + s(psa2.self))
+cb.append('psa3.self: ' + s(psa3.self))
+cb.append('psa4.self: ' + s(psa4.self))
+
+cb.append('a.name: ' + s(a.name))
+cb.append('pa1.name: ' + s(pa1.name))
+cb.append('pa2.name: ' + s(pa2.name))
+cb.append('pa3.name: ' + s(pa3.name))
+cb.append('pa4.name: ' + s(pa4.name))
+cb.append('sa.name: ' + s(sa.name))
+cb.append('psa1.name: ' + s(psa1.name))
+cb.append('psa2.name: ' + s(psa2.name))
+cb.append('psa3.name: ' + s(psa3.name))
+cb.append('psa4.name: ' + s(psa4.name))
+
+cb.append('a.auto_rebind: ' + s(a.auto_rebind))
+cb.append('pa1.auto_rebind: ' + s(pa1.auto_rebind))
+cb.append('pa2.auto_rebind: ' + s(pa2.auto_rebind))
+cb.append('pa3.auto_rebind: ' + s(pa3.auto_rebind))
+cb.append('pa4.auto_rebind: ' + s(pa4.auto_rebind))
+cb.append('sa.auto_rebind: ' + s(sa.auto_rebind))
+cb.append('psa1.auto_rebind: ' + s(psa1.auto_rebind))
+cb.append('psa2.auto_rebind: ' + s(psa2.auto_rebind))
+cb.append('psa3.auto_rebind: ' + s(psa3.auto_rebind))
+cb.append('psa4.auto_rebind: ' + s(psa4.auto_rebind))
+cb.append('psa5.auto_rebind: ' + s(psa5.auto_rebind))
+cb.append('psa6.auto_rebind: ' + s(psa6.auto_rebind))
+cb.append('psa7.auto_rebind: ' + s(psa7.auto_rebind))
+cb.append('psa8.auto_rebind: ' + s(psa8.auto_rebind))
+cb.append('psa9.auto_rebind: ' + s(psa9.auto_rebind))
+cb.append('psaA.auto_rebind: ' + s(psaA.auto_rebind))
+cb.append('psaB.auto_rebind: ' + s(psaB.auto_rebind))
+cb.append('psaC.auto_rebind: ' + s(psaC.auto_rebind))
+
+del s
+
+del a
+del pa1
+del pa2
+del pa3
+del pa4
+del sa
+del psa1
+del psa2
+del psa3
+del psa4
+del psa5
+del psa6
+del psa7
+del psa8
+del psa9
+del psaA
+del psaB
+del psaC
+del psar
+
+del ecall
+EOF
+:"
+:" Test stdout/stderr
+:redir => messages
+:py3 sys.stdout.write('abc8') ; sys.stdout.write('def')
+:py3 sys.stderr.write('abc9') ; sys.stderr.write('def')
+:py3 sys.stdout.writelines(iter('abcA'))
+:py3 sys.stderr.writelines(iter('abcB'))
+:redir END
+:$put =string(substitute(messages, '\d\+', '', 'g'))
+:" Test subclassing
+:fun Put(...)
+: $put =string(a:000)
+: return a:000
+:endfun
+py3 << EOF
+class DupDict(vim.Dictionary):
+ def __setitem__(self, key, value):
+ super(DupDict, self).__setitem__(key, value)
+ super(DupDict, self).__setitem__('dup_' + key, value)
+dd = DupDict()
+dd['a'] = 'b'
+
+class DupList(vim.List):
+ def __getitem__(self, idx):
+ return [super(DupList, self).__getitem__(idx)] * 2
+
+dl = DupList()
+dl2 = DupList(iter('abcC'))
+dl.extend(dl2[0])
+
+class DupFun(vim.Function):
+ def __call__(self, arg):
+ return super(DupFun, self).__call__(arg, arg)
+
+df = DupFun('Put')
+EOF
+:$put =string(sort(keys(py3eval('dd'))))
+:$put =string(py3eval('dl'))
+:$put =string(py3eval('dl2'))
+:$put =string(py3eval('df(2)'))
+:$put =string(py3eval('dl') is# py3eval('dl'))
+:$put =string(py3eval('dd') is# py3eval('dd'))
+:$put =string(py3eval('df'))
+:delfunction Put
+py3 << EOF
+del DupDict
+del DupList
+del DupFun
+del dd
+del dl
+del dl2
+del df
+EOF
+:"
+:" Test chdir
+py3 << EOF
+import os
+fnamemodify = vim.Function('fnamemodify')
+cb.append(str(fnamemodify('.', ':p:h:t')))
+cb.append(vim.eval('@%'))
+os.chdir('..')
+path = fnamemodify('.', ':p:h:t')
+if path != b'src':
+ # Running tests from a shadow directory, so move up another level
+ # This will result in @% looking like shadow/testdir/test87.in, hence the
+ # slicing to remove the leading path and path separator
+ os.chdir('..')
+ cb.append(str(fnamemodify('.', ':p:h:t')))
+ cb.append(vim.eval('@%')[len(path)+1:].replace(os.path.sep, '/'))
+ os.chdir(path)
+else:
+ cb.append(str(fnamemodify('.', ':p:h:t')))
+ cb.append(vim.eval('@%').replace(os.path.sep, '/'))
+del path
+os.chdir('testdir')
+cb.append(str(fnamemodify('.', ':p:h:t')))
+cb.append(vim.eval('@%'))
+del fnamemodify
+EOF
+:"
+:" Test errors
+:fun F() dict
+:endfun
+:fun D()
+:endfun
+py3 << EOF
+d = vim.Dictionary()
+ned = vim.Dictionary(foo='bar', baz='abcD')
+dl = vim.Dictionary(a=1)
+dl.locked = True
+l = vim.List()
+ll = vim.List('abcE')
+ll.locked = True
+nel = vim.List('abcO')
+f = vim.Function('string')
+fd = vim.Function('F')
+fdel = vim.Function('D')
+vim.command('delfunction D')
+
+def subexpr_test(expr, name, subexprs):
+ cb.append('>>> Testing %s using %s' % (name, expr))
+ for subexpr in subexprs:
+ ee(expr % subexpr)
+ cb.append('<<< Finished')
+
+def stringtochars_test(expr):
+ return subexpr_test(expr, 'StringToChars', (
+ '1', # Fail type checks
+ 'b"\\0"', # Fail PyString_AsStringAndSize(object, , NULL) check
+ '"\\0"', # Fail PyString_AsStringAndSize(bytes, , NULL) check
+ ))
+
+class Mapping(object):
+ def __init__(self, d):
+ self.d = d
+
+ def __getitem__(self, key):
+ return self.d[key]
+
+ def keys(self):
+ return self.d.keys()
+
+ def items(self):
+ return self.d.items()
+
+def convertfrompyobject_test(expr, recurse=True):
+ # pydict_to_tv
+ stringtochars_test(expr % '{%s : 1}')
+ if recurse:
+ convertfrompyobject_test(expr % '{"abcF" : %s}', False)
+ # pymap_to_tv
+ stringtochars_test(expr % 'Mapping({%s : 1})')
+ if recurse:
+ convertfrompyobject_test(expr % 'Mapping({"abcG" : %s})', False)
+ # pyseq_to_tv
+ iter_test(expr)
+ return subexpr_test(expr, 'ConvertFromPyObject', (
+ 'None', # Not conversible
+ '{b"": 1}', # Empty key not allowed
+ '{"": 1}', # Same, but with unicode object
+ 'FailingMapping()', #
+ 'FailingMappingKey()', #
+ 'FailingNumber()', #
+ ))
+
+def convertfrompymapping_test(expr):
+ convertfrompyobject_test(expr)
+ return subexpr_test(expr, 'ConvertFromPyMapping', (
+ '[]',
+ ))
+
+def iter_test(expr):
+ return subexpr_test(expr, '*Iter*', (
+ 'FailingIter()',
+ 'FailingIterNext()',
+ ))
+
+def number_test(expr, natural=False, unsigned=False):
+ if natural:
+ unsigned = True
+ return subexpr_test(expr, 'NumberToLong', (
+ '[]',
+ 'None',
+ ) + (('-1',) if unsigned else ())
+ + (('0',) if natural else ()))
+
+class FailingTrue(object):
+ def __bool__(self):
+ raise NotImplementedError('bool')
+
+class FailingIter(object):
+ def __iter__(self):
+ raise NotImplementedError('iter')
+
+class FailingIterNext(object):
+ def __iter__(self):
+ return self
+
+ def __next__(self):
+ raise NotImplementedError('next')
+
+class FailingIterNextN(object):
+ def __init__(self, n):
+ self.n = n
+
+ def __iter__(self):
+ return self
+
+ def __next__(self):
+ if self.n:
+ self.n -= 1
+ return 1
+ else:
+ raise NotImplementedError('next N')
+
+class FailingMappingKey(object):
+ def __getitem__(self, item):
+ raise NotImplementedError('getitem:mappingkey')
+
+ def keys(self):
+ return list("abcH")
+
+class FailingMapping(object):
+ def __getitem__(self):
+ raise NotImplementedError('getitem:mapping')
+
+ def keys(self):
+ raise NotImplementedError('keys')
+
+class FailingList(list):
+ def __getitem__(self, idx):
+ if i == 2:
+ raise NotImplementedError('getitem:list')
+ else:
+ return super(FailingList, self).__getitem__(idx)
+
+class NoArgsCall(object):
+ def __call__(self):
+ pass
+
+class FailingCall(object):
+ def __call__(self, path):
+ raise NotImplementedError('call')
+
+class FailingNumber(object):
+ def __int__(self):
+ raise NotImplementedError('int')
+
+cb.append("> Output")
+cb.append(">> OutputSetattr")
+ee('del sys.stdout.softspace')
+number_test('sys.stdout.softspace = %s', unsigned=True)
+number_test('sys.stderr.softspace = %s', unsigned=True)
+ee('assert sys.stdout.isatty()==False')
+ee('assert sys.stdout.seekable()==False')
+ee('sys.stdout.close()')
+ee('sys.stdout.flush()')
+ee('assert sys.stderr.isatty()==False')
+ee('assert sys.stderr.seekable()==False')
+ee('sys.stderr.close()')
+ee('sys.stderr.flush()')
+ee('sys.stdout.attr = None')
+cb.append(">> OutputWrite")
+ee('assert sys.stdout.writable()==True')
+ee('assert sys.stdout.readable()==False')
+ee('assert sys.stderr.writable()==True')
+ee('assert sys.stderr.readable()==False')
+ee('assert sys.stdout.closed()==False')
+ee('assert sys.stderr.closed()==False')
+ee('assert sys.stdout.errors=="strict"')
+ee('assert sys.stderr.errors=="strict"')
+ee('assert sys.stdout.encoding==sys.stderr.encoding')
+ee('sys.stdout.write(None)')
+cb.append(">> OutputWriteLines")
+ee('sys.stdout.writelines(None)')
+ee('sys.stdout.writelines([1])')
+iter_test('sys.stdout.writelines(%s)')
+cb.append("> VimCommand")
+stringtochars_test('vim.command(%s)')
+ee('vim.command("", 2)')
+#! Not checked: vim->python exceptions translating: checked later
+cb.append("> VimToPython")
+#! Not checked: everything: needs errors in internal python functions
+cb.append("> VimEval")
+stringtochars_test('vim.eval(%s)')
+ee('vim.eval("", FailingTrue())')
+#! Not checked: everything: needs errors in internal python functions
+cb.append("> VimEvalPy")
+stringtochars_test('vim.bindeval(%s)')
+ee('vim.eval("", 2)')
+#! Not checked: vim->python exceptions translating: checked later
+cb.append("> VimStrwidth")
+stringtochars_test('vim.strwidth(%s)')
+cb.append("> VimForeachRTP")
+ee('vim.foreach_rtp(None)')
+ee('vim.foreach_rtp(NoArgsCall())')
+ee('vim.foreach_rtp(FailingCall())')
+ee('vim.foreach_rtp(int, 2)')
+cb.append('> import')
+old_rtp = vim.options['rtp']
+vim.options['rtp'] = os.getcwd().replace('\\', '\\\\').replace(',', '\\,')
+ee('import xxx_no_such_module_xxx')
+ee('import failing_import')
+ee('import failing')
+vim.options['rtp'] = old_rtp
+del old_rtp
+cb.append("> Options")
+cb.append(">> OptionsItem")
+ee('vim.options["abcQ"]')
+ee('vim.options[""]')
+stringtochars_test('vim.options[%s]')
+cb.append(">> OptionsContains")
+stringtochars_test('%s in vim.options')
+cb.append("> Dictionary")
+cb.append(">> DictionaryConstructor")
+ee('vim.Dictionary("abcI")')
+##! Not checked: py_dict_alloc failure
+cb.append(">> DictionarySetattr")
+ee('del d.locked')
+ee('d.locked = FailingTrue()')
+ee('vim.vvars.locked = False')
+ee('d.scope = True')
+ee('d.xxx = True')
+cb.append(">> _DictionaryItem")
+ee('d.get("a", 2, 3)')
+stringtochars_test('d.get(%s)')
+ee('d.pop("a")')
+ee('dl.pop("a")')
+cb.append(">> DictionaryContains")
+ee('"" in d')
+ee('0 in d')
+cb.append(">> DictionaryIterNext")
+ee('for i in ned: ned["a"] = 1')
+del i
+cb.append(">> DictionaryAssItem")
+ee('dl["b"] = 1')
+stringtochars_test('d[%s] = 1')
+convertfrompyobject_test('d["a"] = %s')
+cb.append(">> DictionaryUpdate")
+cb.append(">>> kwargs")
+cb.append(">>> iter")
+ee('d.update(FailingMapping())')
+ee('d.update([FailingIterNext()])')
+ee('d.update([FailingIterNextN(1)])')
+iter_test('d.update(%s)')
+convertfrompyobject_test('d.update(%s)')
+stringtochars_test('d.update(((%s, 0),))')
+convertfrompyobject_test('d.update((("a", %s),))')
+cb.append(">> DictionaryPopItem")
+ee('d.popitem(1, 2)')
+cb.append(">> DictionaryHasKey")
+ee('d.has_key()')
+cb.append("> List")
+cb.append(">> ListConstructor")
+ee('vim.List(1, 2)')
+ee('vim.List(a=1)')
+iter_test('vim.List(%s)')
+convertfrompyobject_test('vim.List([%s])')
+cb.append(">> ListItem")
+ee('l[1000]')
+cb.append(">> ListAssItem")
+ee('ll[1] = 2')
+ee('l[1000] = 3')
+cb.append(">> ListAssSlice")
+ee('ll[1:100] = "abcJ"')
+iter_test('l[:] = %s')
+ee('nel[1:10:2] = "abcK"')
+cb.append(repr(tuple(nel)))
+ee('nel[1:10:2] = "a"')
+cb.append(repr(tuple(nel)))
+ee('nel[1:1:-1] = "a"')
+cb.append(repr(tuple(nel)))
+ee('nel[:] = FailingIterNextN(2)')
+cb.append(repr(tuple(nel)))
+convertfrompyobject_test('l[:] = [%s]')
+cb.append(">> ListConcatInPlace")
+iter_test('l.extend(%s)')
+convertfrompyobject_test('l.extend([%s])')
+cb.append(">> ListSetattr")
+ee('del l.locked')
+ee('l.locked = FailingTrue()')
+ee('l.xxx = True')
+cb.append("> Function")
+cb.append(">> FunctionConstructor")
+cb.append(">>> FunctionConstructor")
+ee('vim.Function("123")')
+ee('vim.Function("xxx_non_existent_function_xxx")')
+ee('vim.Function("xxx#non#existent#function#xxx")')
+ee('vim.Function("xxx_non_existent_function_xxx2", args=[])')
+ee('vim.Function("xxx_non_existent_function_xxx3", self={})')
+ee('vim.Function("xxx_non_existent_function_xxx4", args=[], self={})')
+cb.append(">>> FunctionNew")
+ee('vim.Function("tr", self="abcFuncSelf")')
+ee('vim.Function("tr", args=427423)')
+ee('vim.Function("tr", self="abcFuncSelf2", args="abcFuncArgs2")')
+ee('vim.Function(self="abcFuncSelf2", args="abcFuncArgs2")')
+ee('vim.Function("tr", "", self="abcFuncSelf2", args="abcFuncArgs2")')
+ee('vim.Function("tr", "")')
+cb.append(">> FunctionCall")
+convertfrompyobject_test('f(%s)')
+convertfrompymapping_test('fd(self=%s)')
+cb.append("> TabPage")
+cb.append(">> TabPageAttr")
+ee('vim.current.tabpage.xxx')
+cb.append("> TabList")
+cb.append(">> TabListItem")
+ee('vim.tabpages[1000]')
+cb.append("> Window")
+cb.append(">> WindowAttr")
+ee('vim.current.window.xxx')
+cb.append(">> WindowSetattr")
+ee('vim.current.window.buffer = 0')
+ee('vim.current.window.cursor = (100000000, 100000000)')
+ee('vim.current.window.cursor = True')
+number_test('vim.current.window.height = %s', unsigned=True)
+number_test('vim.current.window.width = %s', unsigned=True)
+ee('vim.current.window.xxxxxx = True')
+cb.append("> WinList")
+cb.append(">> WinListItem")
+ee('vim.windows[1000]')
+cb.append("> Buffer")
+cb.append(">> StringToLine (indirect)")
+ee('vim.current.buffer[0] = "\\na"')
+ee('vim.current.buffer[0] = b"\\na"')
+cb.append(">> SetBufferLine (indirect)")
+ee('vim.current.buffer[0] = True')
+cb.append(">> SetBufferLineList (indirect)")
+ee('vim.current.buffer[:] = True')
+ee('vim.current.buffer[:] = ["\\na", "bc"]')
+cb.append(">> InsertBufferLines (indirect)")
+ee('vim.current.buffer.append(None)')
+ee('vim.current.buffer.append(["\\na", "bc"])')
+ee('vim.current.buffer.append("\\nbc")')
+cb.append(">> RBItem")
+ee('vim.current.buffer[100000000]')
+cb.append(">> RBAsItem")
+ee('vim.current.buffer[100000000] = ""')
+cb.append(">> BufferAttr")
+ee('vim.current.buffer.xxx')
+cb.append(">> BufferSetattr")
+ee('vim.current.buffer.name = True')
+ee('vim.current.buffer.xxx = True')
+cb.append(">> BufferMark")
+ee('vim.current.buffer.mark(0)')
+ee('vim.current.buffer.mark("abcM")')
+ee('vim.current.buffer.mark("!")')
+cb.append(">> BufferRange")
+ee('vim.current.buffer.range(1, 2, 3)')
+cb.append("> BufMap")
+cb.append(">> BufMapItem")
+ee('vim.buffers[100000000]')
+number_test('vim.buffers[%s]', natural=True)
+cb.append("> Current")
+cb.append(">> CurrentGetattr")
+ee('vim.current.xxx')
+cb.append(">> CurrentSetattr")
+ee('vim.current.line = True')
+ee('vim.current.buffer = True')
+ee('vim.current.window = True')
+ee('vim.current.tabpage = True')
+ee('vim.current.xxx = True')
+del d
+del ned
+del dl
+del l
+del ll
+del nel
+del f
+del fd
+del fdel
+del subexpr_test
+del stringtochars_test
+del Mapping
+del convertfrompyobject_test
+del convertfrompymapping_test
+del iter_test
+del number_test
+del FailingTrue
+del FailingIter
+del FailingIterNext
+del FailingIterNextN
+del FailingMapping
+del FailingMappingKey
+del FailingList
+del NoArgsCall
+del FailingCall
+del FailingNumber
+EOF
+:delfunction F
+:"
+:" Test import
+py3 << EOF
+sys.path.insert(0, os.path.join(os.getcwd(), 'python_before'))
+sys.path.append(os.path.join(os.getcwd(), 'python_after'))
+vim.options['rtp'] = os.getcwd().replace(',', '\\,').replace('\\', '\\\\')
+l = []
+def callback(path):
+ l.append(os.path.relpath(path))
+vim.foreach_rtp(callback)
+cb.append(repr(l))
+del l
+def callback(path):
+ return os.path.relpath(path)
+cb.append(repr(vim.foreach_rtp(callback)))
+del callback
+from module import dir as d
+from modulex import ddir
+cb.append(d + ',' + ddir)
+import before
+cb.append(before.dir)
+import after
+cb.append(after.dir)
+import topmodule as tm
+import topmodule.submodule as tms
+import topmodule.submodule.subsubmodule.subsubsubmodule as tmsss
+cb.append(tm.__file__.replace(os.path.sep, '/')[-len('modulex/topmodule/__init__.py'):])
+cb.append(tms.__file__.replace(os.path.sep, '/')[-len('modulex/topmodule/submodule/__init__.py'):])
+cb.append(tmsss.__file__.replace(os.path.sep, '/')[-len('modulex/topmodule/submodule/subsubmodule/subsubsubmodule.py'):])
+del before
+del after
+del d
+del ddir
+del tm
+del tms
+del tmsss
+EOF
+:"
+:" Test exceptions
+:fun Exe(e)
+: execute a:e
+:endfun
+py3 << EOF
+Exe = vim.bindeval('function("Exe")')
+ee('vim.command("throw \'abcN\'")')
+ee('Exe("throw \'def\'")')
+ee('vim.eval("Exe(\'throw \'\'ghi\'\'\')")')
+ee('vim.eval("Exe(\'echoerr \'\'jkl\'\'\')")')
+ee('vim.eval("Exe(\'xxx_non_existent_command_xxx\')")')
+ee('vim.eval("xxx_unknown_function_xxx()")')
+ee('vim.bindeval("Exe(\'xxx_non_existent_command_xxx\')")')
+del Exe
+EOF
+:delfunction Exe
+:"
+:" Regression: interrupting vim.command propagates to next vim.command
+py3 << EOF
+def test_keyboard_interrupt():
+ try:
+ vim.command('while 1 | endwhile')
+ except KeyboardInterrupt:
+ cb.append('Caught KeyboardInterrupt')
+ except Exception:
+ cb.append('!!!!!!!! Caught exception: ' + emsg(sys.exc_info()))
+ else:
+ cb.append('!!!!!!!! No exception')
+ try:
+ vim.command('$ put =\'Running :put\'')
+ except KeyboardInterrupt:
+ cb.append('!!!!!!!! Caught KeyboardInterrupt')
+ except Exception:
+ cb.append('!!!!!!!! Caught exception: ' + emsg(sys.exc_info()))
+ else:
+ cb.append('No exception')
+EOF
+:debuggreedy
+:call inputsave()
+:call feedkeys("s\ns\ns\ns\nq\n")
+:redir => output
+:debug silent! py3 test_keyboard_interrupt()
+:redir END
+:0 debuggreedy
+:call inputrestore()
+:silent $put =output
+:unlet output
+:py3 del test_keyboard_interrupt
+:"
+:" Cleanup
+py3 << EOF
+del cb
+del ee
+del emsg
+del sys
+del os
+del vim
+EOF
+:endfun
+:"
+:fun RunTest()
+:let checkrefs = !empty($PYTHONDUMPREFS)
+:let start = getline(1, '$')
+:for i in range(checkrefs ? 10 : 1)
+: if i != 0
+: %d _
+: call setline(1, start)
+: endif
+: call Test()
+: if i == 0
+: let result = getline(1, '$')
+: endif
+:endfor
+:if checkrefs
+: %d _
+: call setline(1, result)
+:endif
+:endfun
+:"
+:call RunTest()
+:delfunction RunTest
+:delfunction Test
+:call garbagecollect(1)
+:"
+:/^start:/,$wq! test.out
+:/^start:/,$w! test.out
+:" vim: et ts=4 isk-=\:
+:while getchar(0) isnot 0|endwhile
+ENDTEST
+
+start:
diff --git a/src/testdir/test87.ok b/src/testdir/test87.ok
new file mode 100644
index 0000000..a7d4f64
--- /dev/null
+++ b/src/testdir/test87.ok
@@ -0,0 +1,1445 @@
+start:
+[1, 'as''d', [1, 2, function('strlen'), {'a': 1}]]
+[1, 2, function('strlen'), {'a': 1}]
+Vim(put):E684:
+[0, 'as''d', [1, 2, function('strlen'), {'a': 1}]]
+[0, function('strlen'), [1, 2, function('strlen'), {'a': 1}]]
+1
+[b'-1', b'0', b'1', b'b', b'f']
+[-1, <vim.Function '1'>, <vim.dictionary object at >, <vim.list object at >, b'asd']
+[(b'-1', <vim.dictionary object at >), (b'0', -1), (b'1', b'asd'), (b'b', <vim.list object at >), (b'f', <vim.Function '1'>)]
+'-1' : {'a': 1}
+'0' : -1
+'1' : 'asd'
+'b' : [1, 2, function('strlen')]
+'f' : function('1')
+[0, function('strlen')]
+[3]
+[1, 2, function('strlen')]
+[1, 2, function('strlen')]
+1
+'asd'
+2
+True
+False
+True
+False
+[b'0']
+{'0': -1}
+(b'0', -1)
+None
+[]
+[0, 1, 2, 3]
+[0, 1, 2, 3]
+[0, 1, 3]
+[0, 1]
+[0, 1]
+[0, 1]
+[0, 1, 2, 3]
+[0, 1, 2, 3]
+[0, 2, 3]
+[2, 3]
+[2, 3]
+[2, 3]
+[1, 3]
+[0, 2]
+[0, 1, 2, 3]
+['a', 0, 1, 2, 3]
+[0, 'b', 2, 3]
+[0, 1, 'c']
+[0, 1, 2, 3, 'd']
+[0, 1, 2, 'e', 3]
+['f', 2, 3]
+[0, 1, 'g', 2, 3]
+['h']
+[0, 1, 10, 3, 20, 5, 6, 7]
+[0, 1, 2, 3, 20, 5, 10, 7]
+[0, 1, 2, 3, 4, 5, 6, 7]
+[0, 1, 2, 3, 4, 5, 6, 7]
+[0, 1, 2, 3, 4, 5, 6, 7]
+l[2] threw vim.error: error:('list is locked',)
+[0, 1, 2, 3]
+[function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd']
+[function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd', 'DictNewStart', 1, 2, 3, 'DictNewEnd', {'a': 'b'}]
+[function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd', 'DictNewStart', 1, 2, 3, 'DictNewEnd', {'a': 'b'}, 'New']
+l[1](1, 2, 3):(<class 'vim.error'>, error('Vim:E725: Calling dict function without Dictionary: DictNew',))
+f(1, 2, 3):(<class 'vim.error'>, error('Vim:E117: Unknown function: New',))
+[0.0, 0.0]
+KeyError
+TypeError
+TypeError
+ValueError
+TypeError
+TypeError
+KeyError
+KeyError
+d : locked:0;scope:0
+dl : locked:1;scope:0
+v: : locked:2;scope:1
+g: : locked:0;scope:2
+d:{'abc2': 1}
+dl:{'def': 1}
+l : locked:0
+ll : locked:1
+l:[0]
+ll:[1]
+[0, 1, 2]
+['a', 'b']
+['c', 1]
+['d', ['e']]
+py3eval("None") = v:none
+0.0
+"\0": Vim(let):E859:
+{"\0": 1}: Vim(let):E859:
+undefined_name: Vim(let):Trace
+vim: Vim(let):E859:
+[1]
+[1, 10, 11, 10, 11, 10, 11, 10, 11, 10, 11, 10, 1]
+[0, 1, 2, 3]
+[2, 3, 4, 5]
+[0, 1]
+[4, 5]
+[2, 3]
+[]
+[2, 3]
+[]
+[0, 1, 2, 3, 4, 5]
+[0, 1, 2, 3, 4, 5]
+[0, 1, 2, 3, 4, 5]
+[4, 3]
+[0, 2, 4]
+[]
+Abc
+bac
+def
+bar
+jkl
+wopts iters equal: 1
+bopts iters equal: 1
+>>> paste
+ g/w/b:1/0/0
+ g/w/b (in):1/0/0
+ p/gopts1: False
+ p/wopts1! KeyError
+ inv: 2! KeyError
+ wopts1! KeyError
+ wopts2! KeyError
+ wopts3! KeyError
+ p/bopts1! KeyError
+ inv: 2! KeyError
+ bopts1! KeyError
+ bopts2! KeyError
+ bopts3! KeyError
+ G: 1
+ W: 1:1 2:1 3:1 4:1
+ B: 1:1 2:1 3:1 4:1
+ del wopts3! KeyError
+ del bopts3! KeyError
+ G: 1
+ W: 1:1 2:1 3:1 4:1
+ B: 1:1 2:1 3:1 4:1
+>>> previewheight
+ g/w/b:1/0/0
+ g/w/b (in):1/0/0
+ p/gopts1: 12
+ inv: 'a'! TypeError
+ p/wopts1! KeyError
+ inv: 'a'! KeyError
+ wopts1! KeyError
+ wopts2! KeyError
+ wopts3! KeyError
+ p/bopts1! KeyError
+ inv: 'a'! KeyError
+ bopts1! KeyError
+ bopts2! KeyError
+ bopts3! KeyError
+ G: 5
+ W: 1:5 2:5 3:5 4:5
+ B: 1:5 2:5 3:5 4:5
+ del wopts3! KeyError
+ del bopts3! KeyError
+ G: 5
+ W: 1:5 2:5 3:5 4:5
+ B: 1:5 2:5 3:5 4:5
+>>> operatorfunc
+ g/w/b:1/0/0
+ g/w/b (in):1/0/0
+ p/gopts1: b''
+ inv: 2! TypeError
+ p/wopts1! KeyError
+ inv: 2! KeyError
+ wopts1! KeyError
+ wopts2! KeyError
+ wopts3! KeyError
+ p/bopts1! KeyError
+ inv: 2! KeyError
+ bopts1! KeyError
+ bopts2! KeyError
+ bopts3! KeyError
+ G: 'A'
+ W: 1:'A' 2:'A' 3:'A' 4:'A'
+ B: 1:'A' 2:'A' 3:'A' 4:'A'
+ del wopts3! KeyError
+ del bopts3! KeyError
+ G: 'A'
+ W: 1:'A' 2:'A' 3:'A' 4:'A'
+ B: 1:'A' 2:'A' 3:'A' 4:'A'
+>>> number
+ g/w/b:0/1/0
+ g/w/b (in):0/1/0
+ p/gopts1! KeyError
+ inv: 0! KeyError
+ gopts1! KeyError
+ p/wopts1: False
+ p/bopts1! KeyError
+ inv: 0! KeyError
+ bopts1! KeyError
+ bopts2! KeyError
+ bopts3! KeyError
+ G: 0
+ W: 1:1 2:1 3:0 4:0
+ B: 1:1 2:1 3:0 4:0
+ del wopts3! ValueError
+ del bopts3! KeyError
+ G: 0
+ W: 1:1 2:1 3:0 4:0
+ B: 1:1 2:1 3:0 4:0
+>>> numberwidth
+ g/w/b:0/1/0
+ g/w/b (in):0/1/0
+ p/gopts1! KeyError
+ inv: -100! KeyError
+ gopts1! KeyError
+ p/wopts1: 8
+ inv: -100! error
+ p/bopts1! KeyError
+ inv: -100! KeyError
+ bopts1! KeyError
+ bopts2! KeyError
+ bopts3! KeyError
+ G: 8
+ W: 1:3 2:5 3:2 4:8
+ B: 1:3 2:5 3:2 4:8
+ del wopts3! ValueError
+ del bopts3! KeyError
+ G: 8
+ W: 1:3 2:5 3:2 4:8
+ B: 1:3 2:5 3:2 4:8
+>>> colorcolumn
+ g/w/b:0/1/0
+ g/w/b (in):0/1/0
+ p/gopts1! KeyError
+ inv: 'abc4'! KeyError
+ gopts1! KeyError
+ p/wopts1: b''
+ inv: 'abc4'! error
+ p/bopts1! KeyError
+ inv: 'abc4'! KeyError
+ bopts1! KeyError
+ bopts2! KeyError
+ bopts3! KeyError
+ G: ''
+ W: 1:'+2' 2:'+3' 3:'+1' 4:''
+ B: 1:'+2' 2:'+3' 3:'+1' 4:''
+ del wopts3! ValueError
+ del bopts3! KeyError
+ G: ''
+ W: 1:'+2' 2:'+3' 3:'+1' 4:''
+ B: 1:'+2' 2:'+3' 3:'+1' 4:''
+>>> statusline
+ g/w/b:1/1/0
+ g/w/b (in):1/1/0
+ p/gopts1: b''
+ inv: 0! TypeError
+ p/wopts1: None
+ inv: 0! TypeError
+ p/bopts1! KeyError
+ inv: 0! KeyError
+ bopts1! KeyError
+ bopts2! KeyError
+ bopts3! KeyError
+ G: '1'
+ W: 1:'2' 2:'4' 3:'1' 4:'1'
+ B: 1:'2' 2:'4' 3:'1' 4:'1'
+ del bopts3! KeyError
+ G: '1'
+ W: 1:'2' 2:'1' 3:'1' 4:'1'
+ B: 1:'2' 2:'1' 3:'1' 4:'1'
+>>> autoindent
+ g/w/b:0/0/1
+ g/w/b (in):0/0/1
+ p/gopts1! KeyError
+ inv: 2! KeyError
+ gopts1! KeyError
+ p/wopts1! KeyError
+ inv: 2! KeyError
+ wopts1! KeyError
+ wopts2! KeyError
+ wopts3! KeyError
+ p/bopts1: False
+ G: 0
+ W: 1:0 2:1 3:0 4:1
+ B: 1:0 2:1 3:0 4:1
+ del wopts3! KeyError
+ del bopts3! ValueError
+ G: 0
+ W: 1:0 2:1 3:0 4:1
+ B: 1:0 2:1 3:0 4:1
+>>> shiftwidth
+ g/w/b:0/0/1
+ g/w/b (in):0/0/1
+ p/gopts1! KeyError
+ inv: 3! KeyError
+ gopts1! KeyError
+ p/wopts1! KeyError
+ inv: 3! KeyError
+ wopts1! KeyError
+ wopts2! KeyError
+ wopts3! KeyError
+ p/bopts1: 8
+ G: 8
+ W: 1:0 2:2 3:8 4:1
+ B: 1:0 2:2 3:8 4:1
+ del wopts3! KeyError
+ del bopts3! ValueError
+ G: 8
+ W: 1:0 2:2 3:8 4:1
+ B: 1:0 2:2 3:8 4:1
+>>> omnifunc
+ g/w/b:0/0/1
+ g/w/b (in):0/0/1
+ p/gopts1! KeyError
+ inv: 1! KeyError
+ gopts1! KeyError
+ p/wopts1! KeyError
+ inv: 1! KeyError
+ wopts1! KeyError
+ wopts2! KeyError
+ wopts3! KeyError
+ p/bopts1: b''
+ inv: 1! TypeError
+ G: ''
+ W: 1:'A' 2:'B' 3:'' 4:'C'
+ B: 1:'A' 2:'B' 3:'' 4:'C'
+ del wopts3! KeyError
+ del bopts3! ValueError
+ G: ''
+ W: 1:'A' 2:'B' 3:'' 4:'C'
+ B: 1:'A' 2:'B' 3:'' 4:'C'
+>>> preserveindent
+ g/w/b:0/0/1
+ g/w/b (in):0/0/1
+ p/gopts1! KeyError
+ inv: 2! KeyError
+ gopts1! KeyError
+ p/wopts1! KeyError
+ inv: 2! KeyError
+ wopts1! KeyError
+ wopts2! KeyError
+ wopts3! KeyError
+ p/bopts1: False
+ G: 0
+ W: 1:0 2:1 3:0 4:1
+ B: 1:0 2:1 3:0 4:1
+ del wopts3! KeyError
+ del bopts3! ValueError
+ G: 0
+ W: 1:0 2:1 3:0 4:1
+ B: 1:0 2:1 3:0 4:1
+>>> path
+ g/w/b:1/0/1
+ g/w/b (in):1/0/1
+ p/gopts1: b'.,..,,'
+ inv: 0! TypeError
+ p/wopts1! KeyError
+ inv: 0! KeyError
+ wopts1! KeyError
+ wopts2! KeyError
+ wopts3! KeyError
+ p/bopts1: None
+ inv: 0! TypeError
+ G: '.,,'
+ W: 1:'.,,' 2:',,' 3:'.,,' 4:'.'
+ B: 1:'.,,' 2:',,' 3:'.,,' 4:'.'
+ del wopts3! KeyError
+ G: '.,,'
+ W: 1:'.,,' 2:',,' 3:'.,,' 4:'.,,'
+ B: 1:'.,,' 2:',,' 3:'.,,' 4:'.,,'
+First line
+First line
+def
+First line
+Second line
+Third line
+(7, 2)
+<buffer test87.in><buffer >
+baz
+bar
+Second line
+Third line
+foo
+1:BufFilePre:1
+1:BufFilePost:1
+testdir/foo
+5:BufFilePre:5
+5:BufFilePost:5
+testdir/bar
+1:BufFilePre:1
+1:BufFilePost:1
+testdir/test87.in
+valid: b:False, cb:True
+i:<buffer test87.in>
+i2:<buffer test87.in>
+i:<buffer a>
+i3:<buffer test87.in>
+1:<buffer test87.in>=<buffer test87.in>
+8:<buffer a>=<buffer a>
+9:<buffer b>=<buffer b>
+10:<buffer c>=<buffer c>
+4
+i4:<buffer test87.in>
+i4:<buffer test87.in>
+StopIteration
+Number of tabs: 4
+Current tab pages:
+ <tabpage 0>(1): 1 windows, current is <window object (unknown)>
+ Windows:
+ <window object (unknown)>(1): displays buffer <buffer test87.in>; cursor is at (37, 0)
+ <tabpage 1>(2): 1 windows, current is <window object (unknown)>
+ Windows:
+ <window object (unknown)>(1): displays buffer <buffer 0>; cursor is at (1, 0)
+ <tabpage 2>(3): 2 windows, current is <window object (unknown)>
+ Windows:
+ <window object (unknown)>(1): displays buffer <buffer a.1>; cursor is at (1, 0)
+ <window object (unknown)>(2): displays buffer <buffer 1>; cursor is at (1, 0)
+ <tabpage 3>(4): 4 windows, current is <window 0>
+ Windows:
+ <window 0>(1): displays buffer <buffer c.2>; cursor is at (1, 0)
+ <window 1>(2): displays buffer <buffer b.2>; cursor is at (1, 0)
+ <window 2>(3): displays buffer <buffer a.2>; cursor is at (1, 0)
+ <window 3>(4): displays buffer <buffer 2>; cursor is at (1, 0)
+Number of windows in current tab page: 4
+Current tab page: <tabpage 3>
+Current window: <window 0>: <window 0> is <window 0>
+Current buffer: <buffer c.2>: <buffer c.2> is <buffer c.2> is <buffer c.2>
+ValueError at assigning foreign tab window
+Type error at assigning None to vim.current.window
+Type error at assigning None to vim.current.tabpage
+Type error at assigning None to vim.current.buffer
+Current tab page: <tabpage 2>
+Current window: <window 0>
+Current buffer: <buffer test87.in>
+Current line: 'Type error at assigning None to vim.current.buffer'
+w.valid: [True, False]
+t.valid: [True, False, True, False]
+vim.vars:Dictionary:True
+vim.options:Options:True
+vim.bindeval("{}"):Dictionary:True
+vim.bindeval("[]"):List:True
+vim.bindeval("function('tr')"):Function:True
+vim.current.buffer:Buffer:True
+vim.current.range:Range:True
+vim.current.window:Window:True
+vim.current.tabpage:TabPage:True
+current:__dir__,buffer,line,range,tabpage,window
+buffer:__dir__,append,mark,name,number,options,range,valid,vars
+window:__dir__,buffer,col,cursor,height,number,options,row,tabpage,valid,vars,width
+tabpage:__dir__,number,valid,vars,window,windows
+range:__dir__,append,end,start
+dictionary:__dir__,get,has_key,items,keys,locked,pop,popitem,scope,update,values
+list:__dir__,extend,locked
+function:__dir__,args,auto_rebind,self,softspace
+output:__dir__,close,closed,flush,isatty,readable,seekable,softspace,writable,write,writelines
+{}
+{'a': 1}
+{'a': 1}
+[]
+['a', 'b', 'c', '7']
+function('tr')
+function('tr', [123, 3, 4])
+function('tr')
+function('tr', {})
+function('tr', [123, 3, 4], {})
+auto_rebind
+function('tr')
+function('tr', [123, 3, 4])
+function('tr')
+function('tr', {})
+function('tr', [123, 3, 4], {})
+a: <vim.Function 'Args'>
+pa1: <vim.Function 'Args', args=['abcArgsPA1']>
+pa2: <vim.Function 'Args'>
+pa3: <vim.Function 'Args', args=['abcArgsPA3'], self={'abcSelfPA3': 'abcSelfPA3Val'}>
+pa4: <vim.Function 'Args', self={'abcSelfPA4': 'abcSelfPA4Val'}>
+sa: <vim.Function 'SelfArgs'>
+psa1: <vim.Function 'SelfArgs', args=['abcArgsPSA1']>
+psa2: <vim.Function 'SelfArgs'>
+psa3: <vim.Function 'SelfArgs', args=['abcArgsPSA3'], self={'abcSelfPSA3': 'abcSelfPSA3Val'}>
+psa4: <vim.Function 'SelfArgs', self={'abcSelfPSA4': 'abcSelfPSA4Val'}>
+psa5: <vim.Function 'SelfArgs', self={'abcSelfPSA5': 'abcSelfPSA5Val'}>
+psa6: <vim.Function 'SelfArgs', args=['abcArgsPSA6'], self={'abcSelfPSA6': 'abcSelfPSA6Val'}>
+psa7: <vim.Function 'SelfArgs', args=['abcArgsPSA7']>
+psa8: <vim.Function 'SelfArgs'>
+psa9: <vim.Function 'SelfArgs', self={'abcSelfPSA9': 'abcSelfPSA9Val'}, auto_rebind=True>
+psaA: <vim.Function 'SelfArgs', args=['abcArgsPSAA'], self={'abcSelfPSAA': 'abcSelfPSAAVal'}, auto_rebind=True>
+psaB: <vim.Function 'SelfArgs', args=['abcArgsPSAB']>
+psaC: <vim.Function 'SelfArgs'>
+psar: <vim.Function 'SelfArgs', args=[{'abcArgsPSAr2': [{'rec': function('SelfArgs', [{...}], {...}), 'self': {...}, 'abcSelfPSAr': 'abcSelfPSArVal', 'args': [{...}]}, {...}], 'abcArgsPSAr': 'abcArgsPSArVal'}], self={'rec': function('SelfArgs', [{'abcArgsPSAr2': [{...}, {...}], 'abcArgsPSAr': 'abcArgsPSArVal'}], {...}), 'self': {...}, 'abcSelfPSAr': 'abcSelfPSArVal', 'args': [{'abcArgsPSAr2': [{...}, {...}], 'abcArgsPSAr': 'abcArgsPSArVal'}]}>
+s(a): function('Args')
+s(pa1): function('Args', ['abcArgsPA1'])
+s(pa2): function('Args')
+s(pa3): function('Args', ['abcArgsPA3'], {'abcSelfPA3': 'abcSelfPA3Val'})
+s(pa4): function('Args', {'abcSelfPA4': 'abcSelfPA4Val'})
+s(sa): function('SelfArgs')
+s(psa1): function('SelfArgs', ['abcArgsPSA1'])
+s(psa2): function('SelfArgs')
+s(psa3): function('SelfArgs', ['abcArgsPSA3'], {'abcSelfPSA3': 'abcSelfPSA3Val'})
+s(psa4): function('SelfArgs', {'abcSelfPSA4': 'abcSelfPSA4Val'})
+s(psa5): function('SelfArgs', {'abcSelfPSA5': 'abcSelfPSA5Val'})
+s(psa6): function('SelfArgs', ['abcArgsPSA6'], {'abcSelfPSA6': 'abcSelfPSA6Val'})
+s(psa7): function('SelfArgs', ['abcArgsPSA7'])
+s(psa8): function('SelfArgs')
+s(psa9): function('SelfArgs', {'abcSelfPSA9': 'abcSelfPSA9Val'})
+s(psaA): function('SelfArgs', ['abcArgsPSAA'], {'abcSelfPSAA': 'abcSelfPSAAVal'})
+s(psaB): function('SelfArgs', ['abcArgsPSAB'])
+s(psaC): function('SelfArgs')
+d.sa(): [[], {'f': function('SelfArgs')}]
+d.psa1(): [['abcArgsPSA1'], {'f': function('SelfArgs', ['abcArgsPSA1'])}]
+d.psa2(): [[], {'f': function('SelfArgs')}]
+d.psa3(): [['abcArgsPSA3'], {'abcSelfPSA3': 'abcSelfPSA3Val'}]
+d.psa4(): [[], {'abcSelfPSA4': 'abcSelfPSA4Val'}]
+d.psa5(): [[], {'abcSelfPSA5': 'abcSelfPSA5Val'}]
+d.psa6(): [['abcArgsPSA6'], {'abcSelfPSA6': 'abcSelfPSA6Val'}]
+d.psa7(): [['abcArgsPSA7'], {'f': function('SelfArgs', ['abcArgsPSA7'])}]
+d.psa8(): [[], {'f': function('SelfArgs')}]
+d.psa9(): [[], {'f': function('SelfArgs', {'abcSelfPSA9': 'abcSelfPSA9Val'})}]
+d.psaA(): [['abcArgsPSAA'], {'f': function('SelfArgs', ['abcArgsPSAA'], {'abcSelfPSAA': 'abcSelfPSAAVal'})}]
+d.psaB(): [['abcArgsPSAB'], {'f': function('SelfArgs', ['abcArgsPSAB'])}]
+d.psaC(): [[], {'f': function('SelfArgs')}]
+a(): !result: []
+pa1(): !result: ['abcArgsPA1']
+pa2(): !result: []
+pa3(): !result: ['abcArgsPA3']
+pa4(): !result: []
+sa(): !exception: error:('Vim:E725: Calling dict function without Dictionary: SelfArgs',)
+psa1(): !exception: error:('Vim:E725: Calling dict function without Dictionary: SelfArgs',)
+psa2(): !exception: error:('Vim:E725: Calling dict function without Dictionary: SelfArgs',)
+psa3(): !result: [['abcArgsPSA3'], {'abcSelfPSA3': 'abcSelfPSA3Val'}]
+psa4(): !result: [[], {'abcSelfPSA4': 'abcSelfPSA4Val'}]
+a(42, 43): !result: [42, 43]
+pa1(42, 43): !result: ['abcArgsPA1', 42, 43]
+pa2(42, 43): !result: [42, 43]
+pa3(42, 43): !result: ['abcArgsPA3', 42, 43]
+pa4(42, 43): !result: [42, 43]
+sa(42, 43): !exception: error:('Vim:E725: Calling dict function without Dictionary: SelfArgs',)
+psa1(42, 43): !exception: error:('Vim:E725: Calling dict function without Dictionary: SelfArgs',)
+psa2(42, 43): !exception: error:('Vim:E725: Calling dict function without Dictionary: SelfArgs',)
+psa3(42, 43): !result: [['abcArgsPSA3', 42, 43], {'abcSelfPSA3': 'abcSelfPSA3Val'}]
+psa4(42, 43): !result: [[42, 43], {'abcSelfPSA4': 'abcSelfPSA4Val'}]
+a(42, self={"20": 1}): !result: [42]
+pa1(42, self={"20": 1}): !result: ['abcArgsPA1', 42]
+pa2(42, self={"20": 1}): !result: [42]
+pa3(42, self={"20": 1}): !result: ['abcArgsPA3', 42]
+pa4(42, self={"20": 1}): !result: [42]
+sa(42, self={"20": 1}): !result: [[42], {'20': 1}]
+psa1(42, self={"20": 1}): !result: [['abcArgsPSA1', 42], {'20': 1}]
+psa2(42, self={"20": 1}): !result: [[42], {'20': 1}]
+psa3(42, self={"20": 1}): !result: [['abcArgsPSA3', 42], {'20': 1}]
+psa4(42, self={"20": 1}): !result: [[42], {'20': 1}]
+a(self={"20": 1}): !result: []
+pa1(self={"20": 1}): !result: ['abcArgsPA1']
+pa2(self={"20": 1}): !result: []
+pa3(self={"20": 1}): !result: ['abcArgsPA3']
+pa4(self={"20": 1}): !result: []
+sa(self={"20": 1}): !result: [[], {'20': 1}]
+psa1(self={"20": 1}): !result: [['abcArgsPSA1'], {'20': 1}]
+psa2(self={"20": 1}): !result: [[], {'20': 1}]
+psa3(self={"20": 1}): !result: [['abcArgsPSA3'], {'20': 1}]
+psa4(self={"20": 1}): !result: [[], {'20': 1}]
+a.args: None
+pa1.args: ['abcArgsPA1']
+pa2.args: None
+pa3.args: ['abcArgsPA3']
+pa4.args: None
+sa.args: None
+psa1.args: ['abcArgsPSA1']
+psa2.args: None
+psa3.args: ['abcArgsPSA3']
+psa4.args: None
+a.self: None
+pa1.self: None
+pa2.self: None
+pa3.self: {'abcSelfPA3': 'abcSelfPA3Val'}
+pa4.self: {'abcSelfPA4': 'abcSelfPA4Val'}
+sa.self: None
+psa1.self: None
+psa2.self: None
+psa3.self: {'abcSelfPSA3': 'abcSelfPSA3Val'}
+psa4.self: {'abcSelfPSA4': 'abcSelfPSA4Val'}
+a.name: 'Args'
+pa1.name: 'Args'
+pa2.name: 'Args'
+pa3.name: 'Args'
+pa4.name: 'Args'
+sa.name: 'SelfArgs'
+psa1.name: 'SelfArgs'
+psa2.name: 'SelfArgs'
+psa3.name: 'SelfArgs'
+psa4.name: 'SelfArgs'
+a.auto_rebind: 1
+pa1.auto_rebind: 1
+pa2.auto_rebind: 1
+pa3.auto_rebind: 0
+pa4.auto_rebind: 0
+sa.auto_rebind: 1
+psa1.auto_rebind: 1
+psa2.auto_rebind: 1
+psa3.auto_rebind: 0
+psa4.auto_rebind: 0
+psa5.auto_rebind: 0
+psa6.auto_rebind: 0
+psa7.auto_rebind: 1
+psa8.auto_rebind: 1
+psa9.auto_rebind: 1
+psaA.auto_rebind: 1
+psaB.auto_rebind: 1
+psaC.auto_rebind: 1
+'
+abcdef
+Error detected while processing function RunTest[]..Test:
+line :
+abcdef
+abcA
+line :
+abcB'
+['a', 'dup_a']
+['a', 'a']
+['a', 'b', 'c', 'C']
+[2, 2]
+[2, 2]
+1
+1
+function('Put')
+b'testdir'
+test87.in
+b'src'
+testdir/test87.in
+b'testdir'
+test87.in
+> Output
+>> OutputSetattr
+del sys.stdout.softspace:(<class 'AttributeError'>, AttributeError('cannot delete OutputObject attributes',))
+>>> Testing NumberToLong using sys.stdout.softspace = %s
+sys.stdout.softspace = []:(<class 'TypeError'>, TypeError('expected int() or something supporting coercing to int(), but got list',))
+sys.stdout.softspace = None:(<class 'TypeError'>, TypeError('expected int() or something supporting coercing to int(), but got NoneType',))
+sys.stdout.softspace = -1:(<class 'ValueError'>, ValueError('number must be greater or equal to zero',))
+<<< Finished
+>>> Testing NumberToLong using sys.stderr.softspace = %s
+sys.stderr.softspace = []:(<class 'TypeError'>, TypeError('expected int() or something supporting coercing to int(), but got list',))
+sys.stderr.softspace = None:(<class 'TypeError'>, TypeError('expected int() or something supporting coercing to int(), but got NoneType',))
+sys.stderr.softspace = -1:(<class 'ValueError'>, ValueError('number must be greater or equal to zero',))
+<<< Finished
+assert sys.stdout.isatty()==False:NOT FAILED
+assert sys.stdout.seekable()==False:NOT FAILED
+sys.stdout.close():NOT FAILED
+sys.stdout.flush():NOT FAILED
+assert sys.stderr.isatty()==False:NOT FAILED
+assert sys.stderr.seekable()==False:NOT FAILED
+sys.stderr.close():NOT FAILED
+sys.stderr.flush():NOT FAILED
+sys.stdout.attr = None:(<class 'AttributeError'>, AttributeError('invalid attribute: attr',))
+>> OutputWrite
+assert sys.stdout.writable()==True:NOT FAILED
+assert sys.stdout.readable()==False:NOT FAILED
+assert sys.stderr.writable()==True:NOT FAILED
+assert sys.stderr.readable()==False:NOT FAILED
+assert sys.stdout.closed()==False:NOT FAILED
+assert sys.stderr.closed()==False:NOT FAILED
+assert sys.stdout.errors=="strict":NOT FAILED
+assert sys.stderr.errors=="strict":NOT FAILED
+assert sys.stdout.encoding==sys.stderr.encoding:NOT FAILED
+sys.stdout.write(None):(<class 'TypeError'>, TypeError("Can't convert 'NoneType' object to str implicitly",))
+>> OutputWriteLines
+sys.stdout.writelines(None):(<class 'TypeError'>, TypeError("'NoneType' object is not iterable",))
+sys.stdout.writelines([1]):(<class 'TypeError'>, TypeError("Can't convert 'int' object to str implicitly",))
+>>> Testing *Iter* using sys.stdout.writelines(%s)
+sys.stdout.writelines(FailingIter()):(<class 'NotImplementedError'>, NotImplementedError('iter',))
+sys.stdout.writelines(FailingIterNext()):(<class 'NotImplementedError'>, NotImplementedError('next',))
+<<< Finished
+> VimCommand
+>>> Testing StringToChars using vim.command(%s)
+vim.command(1):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+vim.command(b"\0"):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+vim.command("\0"):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+vim.command("", 2):(<class 'TypeError'>, TypeError('command() takes exactly one argument (2 given)',))
+> VimToPython
+> VimEval
+>>> Testing StringToChars using vim.eval(%s)
+vim.eval(1):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+vim.eval(b"\0"):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+vim.eval("\0"):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+vim.eval("", FailingTrue()):(<class 'TypeError'>, TypeError('function takes exactly 1 argument (2 given)',))
+> VimEvalPy
+>>> Testing StringToChars using vim.bindeval(%s)
+vim.bindeval(1):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+vim.bindeval(b"\0"):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+vim.bindeval("\0"):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+vim.eval("", 2):(<class 'TypeError'>, TypeError('function takes exactly 1 argument (2 given)',))
+> VimStrwidth
+>>> Testing StringToChars using vim.strwidth(%s)
+vim.strwidth(1):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+vim.strwidth(b"\0"):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+vim.strwidth("\0"):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+> VimForeachRTP
+vim.foreach_rtp(None):(<class 'TypeError'>, TypeError("'NoneType' object is not callable",))
+vim.foreach_rtp(NoArgsCall()):(<class 'TypeError'>, TypeError('__call__() takes exactly 1 positional argument (2 given)',))
+vim.foreach_rtp(FailingCall()):(<class 'NotImplementedError'>, NotImplementedError('call',))
+vim.foreach_rtp(int, 2):(<class 'TypeError'>, TypeError('foreach_rtp() takes exactly one argument (2 given)',))
+> import
+import xxx_no_such_module_xxx:(<class 'ImportError'>, ImportError('No module named xxx_no_such_module_xxx',))
+import failing_import:(<class 'ImportError'>, ImportError())
+import failing:(<class 'NotImplementedError'>, NotImplementedError())
+> Options
+>> OptionsItem
+vim.options["abcQ"]:(<class 'KeyError'>, KeyError('abcQ',))
+vim.options[""]:(<class 'ValueError'>, ValueError('empty keys are not allowed',))
+>>> Testing StringToChars using vim.options[%s]
+vim.options[1]:(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+vim.options[b"\0"]:(<class 'TypeError'>, TypeError('expected bytes with no null',))
+vim.options["\0"]:(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+>> OptionsContains
+>>> Testing StringToChars using %s in vim.options
+1 in vim.options:(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+b"\0" in vim.options:(<class 'TypeError'>, TypeError('expected bytes with no null',))
+"\0" in vim.options:(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+> Dictionary
+>> DictionaryConstructor
+vim.Dictionary("abcI"):(<class 'ValueError'>, ValueError('expected sequence element of size 2, but got sequence of size 1',))
+>> DictionarySetattr
+del d.locked:(<class 'AttributeError'>, AttributeError('cannot delete vim.Dictionary attributes',))
+d.locked = FailingTrue():(<class 'NotImplementedError'>, NotImplementedError('bool',))
+vim.vvars.locked = False:(<class 'TypeError'>, TypeError('cannot modify fixed dictionary',))
+d.scope = True:(<class 'AttributeError'>, AttributeError('cannot set attribute scope',))
+d.xxx = True:(<class 'AttributeError'>, AttributeError('cannot set attribute xxx',))
+>> _DictionaryItem
+d.get("a", 2, 3):(<class 'TypeError'>, TypeError('function takes at most 2 arguments (3 given)',))
+>>> Testing StringToChars using d.get(%s)
+d.get(1):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+d.get(b"\0"):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+d.get("\0"):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+d.pop("a"):(<class 'KeyError'>, KeyError('a',))
+dl.pop("a"):(<class 'vim.error'>, error('dictionary is locked',))
+>> DictionaryContains
+"" in d:(<class 'ValueError'>, ValueError('empty keys are not allowed',))
+0 in d:(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+>> DictionaryIterNext
+for i in ned: ned["a"] = 1:(<class 'RuntimeError'>, RuntimeError('hashtab changed during iteration',))
+>> DictionaryAssItem
+dl["b"] = 1:(<class 'vim.error'>, error('dictionary is locked',))
+>>> Testing StringToChars using d[%s] = 1
+d[1] = 1:(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+d[b"\0"] = 1:(<class 'TypeError'>, TypeError('expected bytes with no null',))
+d["\0"] = 1:(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+>>> Testing StringToChars using d["a"] = {%s : 1}
+d["a"] = {1 : 1}:(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+d["a"] = {b"\0" : 1}:(<class 'TypeError'>, TypeError('expected bytes with no null',))
+d["a"] = {"\0" : 1}:(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+>>> Testing StringToChars using d["a"] = {"abcF" : {%s : 1}}
+d["a"] = {"abcF" : {1 : 1}}:(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+d["a"] = {"abcF" : {b"\0" : 1}}:(<class 'TypeError'>, TypeError('expected bytes with no null',))
+d["a"] = {"abcF" : {"\0" : 1}}:(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+>>> Testing StringToChars using d["a"] = {"abcF" : Mapping({%s : 1})}
+d["a"] = {"abcF" : Mapping({1 : 1})}:(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+d["a"] = {"abcF" : Mapping({b"\0" : 1})}:(<class 'TypeError'>, TypeError('expected bytes with no null',))
+d["a"] = {"abcF" : Mapping({"\0" : 1})}:(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+>>> Testing *Iter* using d["a"] = {"abcF" : %s}
+d["a"] = {"abcF" : FailingIter()}:(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',))
+d["a"] = {"abcF" : FailingIterNext()}:(<class 'NotImplementedError'>, NotImplementedError('next',))
+<<< Finished
+>>> Testing ConvertFromPyObject using d["a"] = {"abcF" : %s}
+d["a"] = {"abcF" : None}:NOT FAILED
+d["a"] = {"abcF" : {b"": 1}}:(<class 'ValueError'>, ValueError('empty keys are not allowed',))
+d["a"] = {"abcF" : {"": 1}}:(<class 'ValueError'>, ValueError('empty keys are not allowed',))
+d["a"] = {"abcF" : FailingMapping()}:(<class 'NotImplementedError'>, NotImplementedError('keys',))
+d["a"] = {"abcF" : FailingMappingKey()}:(<class 'NotImplementedError'>, NotImplementedError('getitem:mappingkey',))
+d["a"] = {"abcF" : FailingNumber()}:(<class 'NotImplementedError'>, NotImplementedError('int',))
+<<< Finished
+>>> Testing StringToChars using d["a"] = Mapping({%s : 1})
+d["a"] = Mapping({1 : 1}):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+d["a"] = Mapping({b"\0" : 1}):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+d["a"] = Mapping({"\0" : 1}):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+>>> Testing StringToChars using d["a"] = Mapping({"abcG" : {%s : 1}})
+d["a"] = Mapping({"abcG" : {1 : 1}}):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+d["a"] = Mapping({"abcG" : {b"\0" : 1}}):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+d["a"] = Mapping({"abcG" : {"\0" : 1}}):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+>>> Testing StringToChars using d["a"] = Mapping({"abcG" : Mapping({%s : 1})})
+d["a"] = Mapping({"abcG" : Mapping({1 : 1})}):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+d["a"] = Mapping({"abcG" : Mapping({b"\0" : 1})}):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+d["a"] = Mapping({"abcG" : Mapping({"\0" : 1})}):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+>>> Testing *Iter* using d["a"] = Mapping({"abcG" : %s})
+d["a"] = Mapping({"abcG" : FailingIter()}):(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',))
+d["a"] = Mapping({"abcG" : FailingIterNext()}):(<class 'NotImplementedError'>, NotImplementedError('next',))
+<<< Finished
+>>> Testing ConvertFromPyObject using d["a"] = Mapping({"abcG" : %s})
+d["a"] = Mapping({"abcG" : None}):NOT FAILED
+d["a"] = Mapping({"abcG" : {b"": 1}}):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
+d["a"] = Mapping({"abcG" : {"": 1}}):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
+d["a"] = Mapping({"abcG" : FailingMapping()}):(<class 'NotImplementedError'>, NotImplementedError('keys',))
+d["a"] = Mapping({"abcG" : FailingMappingKey()}):(<class 'NotImplementedError'>, NotImplementedError('getitem:mappingkey',))
+d["a"] = Mapping({"abcG" : FailingNumber()}):(<class 'NotImplementedError'>, NotImplementedError('int',))
+<<< Finished
+>>> Testing *Iter* using d["a"] = %s
+d["a"] = FailingIter():(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',))
+d["a"] = FailingIterNext():(<class 'NotImplementedError'>, NotImplementedError('next',))
+<<< Finished
+>>> Testing ConvertFromPyObject using d["a"] = %s
+d["a"] = None:NOT FAILED
+d["a"] = {b"": 1}:(<class 'ValueError'>, ValueError('empty keys are not allowed',))
+d["a"] = {"": 1}:(<class 'ValueError'>, ValueError('empty keys are not allowed',))
+d["a"] = FailingMapping():(<class 'NotImplementedError'>, NotImplementedError('keys',))
+d["a"] = FailingMappingKey():(<class 'NotImplementedError'>, NotImplementedError('getitem:mappingkey',))
+d["a"] = FailingNumber():(<class 'NotImplementedError'>, NotImplementedError('int',))
+<<< Finished
+>> DictionaryUpdate
+>>> kwargs
+>>> iter
+d.update(FailingMapping()):(<class 'NotImplementedError'>, NotImplementedError('keys',))
+d.update([FailingIterNext()]):(<class 'NotImplementedError'>, NotImplementedError('next',))
+d.update([FailingIterNextN(1)]):(<class 'NotImplementedError'>, NotImplementedError('next N',))
+>>> Testing *Iter* using d.update(%s)
+d.update(FailingIter()):(<class 'NotImplementedError'>, NotImplementedError('iter',))
+d.update(FailingIterNext()):(<class 'NotImplementedError'>, NotImplementedError('next',))
+<<< Finished
+>>> Testing StringToChars using d.update({%s : 1})
+d.update({1 : 1}):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+d.update({b"\0" : 1}):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+d.update({"\0" : 1}):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+>>> Testing StringToChars using d.update({"abcF" : {%s : 1}})
+d.update({"abcF" : {1 : 1}}):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+d.update({"abcF" : {b"\0" : 1}}):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+d.update({"abcF" : {"\0" : 1}}):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+>>> Testing StringToChars using d.update({"abcF" : Mapping({%s : 1})})
+d.update({"abcF" : Mapping({1 : 1})}):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+d.update({"abcF" : Mapping({b"\0" : 1})}):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+d.update({"abcF" : Mapping({"\0" : 1})}):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+>>> Testing *Iter* using d.update({"abcF" : %s})
+d.update({"abcF" : FailingIter()}):(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',))
+d.update({"abcF" : FailingIterNext()}):(<class 'NotImplementedError'>, NotImplementedError('next',))
+<<< Finished
+>>> Testing ConvertFromPyObject using d.update({"abcF" : %s})
+d.update({"abcF" : None}):NOT FAILED
+d.update({"abcF" : {b"": 1}}):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
+d.update({"abcF" : {"": 1}}):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
+d.update({"abcF" : FailingMapping()}):(<class 'NotImplementedError'>, NotImplementedError('keys',))
+d.update({"abcF" : FailingMappingKey()}):(<class 'NotImplementedError'>, NotImplementedError('getitem:mappingkey',))
+d.update({"abcF" : FailingNumber()}):(<class 'NotImplementedError'>, NotImplementedError('int',))
+<<< Finished
+>>> Testing StringToChars using d.update(Mapping({%s : 1}))
+d.update(Mapping({1 : 1})):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+d.update(Mapping({b"\0" : 1})):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+d.update(Mapping({"\0" : 1})):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+>>> Testing StringToChars using d.update(Mapping({"abcG" : {%s : 1}}))
+d.update(Mapping({"abcG" : {1 : 1}})):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+d.update(Mapping({"abcG" : {b"\0" : 1}})):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+d.update(Mapping({"abcG" : {"\0" : 1}})):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+>>> Testing StringToChars using d.update(Mapping({"abcG" : Mapping({%s : 1})}))
+d.update(Mapping({"abcG" : Mapping({1 : 1})})):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+d.update(Mapping({"abcG" : Mapping({b"\0" : 1})})):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+d.update(Mapping({"abcG" : Mapping({"\0" : 1})})):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+>>> Testing *Iter* using d.update(Mapping({"abcG" : %s}))
+d.update(Mapping({"abcG" : FailingIter()})):(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',))
+d.update(Mapping({"abcG" : FailingIterNext()})):(<class 'NotImplementedError'>, NotImplementedError('next',))
+<<< Finished
+>>> Testing ConvertFromPyObject using d.update(Mapping({"abcG" : %s}))
+d.update(Mapping({"abcG" : None})):NOT FAILED
+d.update(Mapping({"abcG" : {b"": 1}})):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
+d.update(Mapping({"abcG" : {"": 1}})):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
+d.update(Mapping({"abcG" : FailingMapping()})):(<class 'NotImplementedError'>, NotImplementedError('keys',))
+d.update(Mapping({"abcG" : FailingMappingKey()})):(<class 'NotImplementedError'>, NotImplementedError('getitem:mappingkey',))
+d.update(Mapping({"abcG" : FailingNumber()})):(<class 'NotImplementedError'>, NotImplementedError('int',))
+<<< Finished
+>>> Testing *Iter* using d.update(%s)
+d.update(FailingIter()):(<class 'NotImplementedError'>, NotImplementedError('iter',))
+d.update(FailingIterNext()):(<class 'NotImplementedError'>, NotImplementedError('next',))
+<<< Finished
+>>> Testing ConvertFromPyObject using d.update(%s)
+d.update(None):(<class 'TypeError'>, TypeError("'NoneType' object is not iterable",))
+d.update({b"": 1}):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
+d.update({"": 1}):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
+d.update(FailingMapping()):(<class 'NotImplementedError'>, NotImplementedError('keys',))
+d.update(FailingMappingKey()):(<class 'NotImplementedError'>, NotImplementedError('getitem:mappingkey',))
+d.update(FailingNumber()):(<class 'TypeError'>, TypeError("'FailingNumber' object is not iterable",))
+<<< Finished
+>>> Testing StringToChars using d.update(((%s, 0),))
+d.update(((1, 0),)):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+d.update(((b"\0", 0),)):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+d.update((("\0", 0),)):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+>>> Testing StringToChars using d.update((("a", {%s : 1}),))
+d.update((("a", {1 : 1}),)):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+d.update((("a", {b"\0" : 1}),)):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+d.update((("a", {"\0" : 1}),)):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+>>> Testing StringToChars using d.update((("a", {"abcF" : {%s : 1}}),))
+d.update((("a", {"abcF" : {1 : 1}}),)):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+d.update((("a", {"abcF" : {b"\0" : 1}}),)):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+d.update((("a", {"abcF" : {"\0" : 1}}),)):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+>>> Testing StringToChars using d.update((("a", {"abcF" : Mapping({%s : 1})}),))
+d.update((("a", {"abcF" : Mapping({1 : 1})}),)):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+d.update((("a", {"abcF" : Mapping({b"\0" : 1})}),)):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+d.update((("a", {"abcF" : Mapping({"\0" : 1})}),)):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+>>> Testing *Iter* using d.update((("a", {"abcF" : %s}),))
+d.update((("a", {"abcF" : FailingIter()}),)):(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',))
+d.update((("a", {"abcF" : FailingIterNext()}),)):(<class 'NotImplementedError'>, NotImplementedError('next',))
+<<< Finished
+>>> Testing ConvertFromPyObject using d.update((("a", {"abcF" : %s}),))
+d.update((("a", {"abcF" : None}),)):(<class 'vim.error'>, error("failed to add key 'a' to dictionary",))
+d.update((("a", {"abcF" : {b"": 1}}),)):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
+d.update((("a", {"abcF" : {"": 1}}),)):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
+d.update((("a", {"abcF" : FailingMapping()}),)):(<class 'NotImplementedError'>, NotImplementedError('keys',))
+d.update((("a", {"abcF" : FailingMappingKey()}),)):(<class 'NotImplementedError'>, NotImplementedError('getitem:mappingkey',))
+d.update((("a", {"abcF" : FailingNumber()}),)):(<class 'NotImplementedError'>, NotImplementedError('int',))
+<<< Finished
+>>> Testing StringToChars using d.update((("a", Mapping({%s : 1})),))
+d.update((("a", Mapping({1 : 1})),)):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+d.update((("a", Mapping({b"\0" : 1})),)):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+d.update((("a", Mapping({"\0" : 1})),)):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+>>> Testing StringToChars using d.update((("a", Mapping({"abcG" : {%s : 1}})),))
+d.update((("a", Mapping({"abcG" : {1 : 1}})),)):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+d.update((("a", Mapping({"abcG" : {b"\0" : 1}})),)):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+d.update((("a", Mapping({"abcG" : {"\0" : 1}})),)):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+>>> Testing StringToChars using d.update((("a", Mapping({"abcG" : Mapping({%s : 1})})),))
+d.update((("a", Mapping({"abcG" : Mapping({1 : 1})})),)):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+d.update((("a", Mapping({"abcG" : Mapping({b"\0" : 1})})),)):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+d.update((("a", Mapping({"abcG" : Mapping({"\0" : 1})})),)):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+>>> Testing *Iter* using d.update((("a", Mapping({"abcG" : %s})),))
+d.update((("a", Mapping({"abcG" : FailingIter()})),)):(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',))
+d.update((("a", Mapping({"abcG" : FailingIterNext()})),)):(<class 'NotImplementedError'>, NotImplementedError('next',))
+<<< Finished
+>>> Testing ConvertFromPyObject using d.update((("a", Mapping({"abcG" : %s})),))
+d.update((("a", Mapping({"abcG" : None})),)):(<class 'vim.error'>, error("failed to add key 'a' to dictionary",))
+d.update((("a", Mapping({"abcG" : {b"": 1}})),)):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
+d.update((("a", Mapping({"abcG" : {"": 1}})),)):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
+d.update((("a", Mapping({"abcG" : FailingMapping()})),)):(<class 'NotImplementedError'>, NotImplementedError('keys',))
+d.update((("a", Mapping({"abcG" : FailingMappingKey()})),)):(<class 'NotImplementedError'>, NotImplementedError('getitem:mappingkey',))
+d.update((("a", Mapping({"abcG" : FailingNumber()})),)):(<class 'NotImplementedError'>, NotImplementedError('int',))
+<<< Finished
+>>> Testing *Iter* using d.update((("a", %s),))
+d.update((("a", FailingIter()),)):(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',))
+d.update((("a", FailingIterNext()),)):(<class 'NotImplementedError'>, NotImplementedError('next',))
+<<< Finished
+>>> Testing ConvertFromPyObject using d.update((("a", %s),))
+d.update((("a", None),)):(<class 'vim.error'>, error("failed to add key 'a' to dictionary",))
+d.update((("a", {b"": 1}),)):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
+d.update((("a", {"": 1}),)):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
+d.update((("a", FailingMapping()),)):(<class 'NotImplementedError'>, NotImplementedError('keys',))
+d.update((("a", FailingMappingKey()),)):(<class 'NotImplementedError'>, NotImplementedError('getitem:mappingkey',))
+d.update((("a", FailingNumber()),)):(<class 'NotImplementedError'>, NotImplementedError('int',))
+<<< Finished
+>> DictionaryPopItem
+d.popitem(1, 2):(<class 'TypeError'>, TypeError('popitem() takes no arguments (2 given)',))
+>> DictionaryHasKey
+d.has_key():(<class 'TypeError'>, TypeError('has_key() takes exactly one argument (0 given)',))
+> List
+>> ListConstructor
+vim.List(1, 2):(<class 'TypeError'>, TypeError('function takes at most 1 argument (2 given)',))
+vim.List(a=1):(<class 'TypeError'>, TypeError('list constructor does not accept keyword arguments',))
+>>> Testing *Iter* using vim.List(%s)
+vim.List(FailingIter()):(<class 'NotImplementedError'>, NotImplementedError('iter',))
+vim.List(FailingIterNext()):(<class 'NotImplementedError'>, NotImplementedError('next',))
+<<< Finished
+>>> Testing StringToChars using vim.List([{%s : 1}])
+vim.List([{1 : 1}]):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+vim.List([{b"\0" : 1}]):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+vim.List([{"\0" : 1}]):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+>>> Testing StringToChars using vim.List([{"abcF" : {%s : 1}}])
+vim.List([{"abcF" : {1 : 1}}]):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+vim.List([{"abcF" : {b"\0" : 1}}]):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+vim.List([{"abcF" : {"\0" : 1}}]):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+>>> Testing StringToChars using vim.List([{"abcF" : Mapping({%s : 1})}])
+vim.List([{"abcF" : Mapping({1 : 1})}]):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+vim.List([{"abcF" : Mapping({b"\0" : 1})}]):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+vim.List([{"abcF" : Mapping({"\0" : 1})}]):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+>>> Testing *Iter* using vim.List([{"abcF" : %s}])
+vim.List([{"abcF" : FailingIter()}]):(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',))
+vim.List([{"abcF" : FailingIterNext()}]):(<class 'NotImplementedError'>, NotImplementedError('next',))
+<<< Finished
+>>> Testing ConvertFromPyObject using vim.List([{"abcF" : %s}])
+vim.List([{"abcF" : None}]):NOT FAILED
+vim.List([{"abcF" : {b"": 1}}]):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
+vim.List([{"abcF" : {"": 1}}]):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
+vim.List([{"abcF" : FailingMapping()}]):(<class 'NotImplementedError'>, NotImplementedError('keys',))
+vim.List([{"abcF" : FailingMappingKey()}]):(<class 'NotImplementedError'>, NotImplementedError('getitem:mappingkey',))
+vim.List([{"abcF" : FailingNumber()}]):(<class 'NotImplementedError'>, NotImplementedError('int',))
+<<< Finished
+>>> Testing StringToChars using vim.List([Mapping({%s : 1})])
+vim.List([Mapping({1 : 1})]):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+vim.List([Mapping({b"\0" : 1})]):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+vim.List([Mapping({"\0" : 1})]):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+>>> Testing StringToChars using vim.List([Mapping({"abcG" : {%s : 1}})])
+vim.List([Mapping({"abcG" : {1 : 1}})]):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+vim.List([Mapping({"abcG" : {b"\0" : 1}})]):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+vim.List([Mapping({"abcG" : {"\0" : 1}})]):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+>>> Testing StringToChars using vim.List([Mapping({"abcG" : Mapping({%s : 1})})])
+vim.List([Mapping({"abcG" : Mapping({1 : 1})})]):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+vim.List([Mapping({"abcG" : Mapping({b"\0" : 1})})]):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+vim.List([Mapping({"abcG" : Mapping({"\0" : 1})})]):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+>>> Testing *Iter* using vim.List([Mapping({"abcG" : %s})])
+vim.List([Mapping({"abcG" : FailingIter()})]):(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',))
+vim.List([Mapping({"abcG" : FailingIterNext()})]):(<class 'NotImplementedError'>, NotImplementedError('next',))
+<<< Finished
+>>> Testing ConvertFromPyObject using vim.List([Mapping({"abcG" : %s})])
+vim.List([Mapping({"abcG" : None})]):NOT FAILED
+vim.List([Mapping({"abcG" : {b"": 1}})]):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
+vim.List([Mapping({"abcG" : {"": 1}})]):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
+vim.List([Mapping({"abcG" : FailingMapping()})]):(<class 'NotImplementedError'>, NotImplementedError('keys',))
+vim.List([Mapping({"abcG" : FailingMappingKey()})]):(<class 'NotImplementedError'>, NotImplementedError('getitem:mappingkey',))
+vim.List([Mapping({"abcG" : FailingNumber()})]):(<class 'NotImplementedError'>, NotImplementedError('int',))
+<<< Finished
+>>> Testing *Iter* using vim.List([%s])
+vim.List([FailingIter()]):(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',))
+vim.List([FailingIterNext()]):(<class 'NotImplementedError'>, NotImplementedError('next',))
+<<< Finished
+>>> Testing ConvertFromPyObject using vim.List([%s])
+vim.List([None]):NOT FAILED
+vim.List([{b"": 1}]):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
+vim.List([{"": 1}]):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
+vim.List([FailingMapping()]):(<class 'NotImplementedError'>, NotImplementedError('keys',))
+vim.List([FailingMappingKey()]):(<class 'NotImplementedError'>, NotImplementedError('getitem:mappingkey',))
+vim.List([FailingNumber()]):(<class 'NotImplementedError'>, NotImplementedError('int',))
+<<< Finished
+>> ListItem
+l[1000]:(<class 'IndexError'>, IndexError('list index out of range',))
+>> ListAssItem
+ll[1] = 2:(<class 'vim.error'>, error('list is locked',))
+l[1000] = 3:(<class 'IndexError'>, IndexError('list index out of range',))
+>> ListAssSlice
+ll[1:100] = "abcJ":(<class 'vim.error'>, error('list is locked',))
+>>> Testing *Iter* using l[:] = %s
+l[:] = FailingIter():(<class 'NotImplementedError'>, NotImplementedError('iter',))
+l[:] = FailingIterNext():(<class 'NotImplementedError'>, NotImplementedError('next',))
+<<< Finished
+nel[1:10:2] = "abcK":(<class 'ValueError'>, ValueError('attempt to assign sequence of size greater than 2 to extended slice',))
+(b'a', b'b', b'c', b'O')
+nel[1:10:2] = "a":(<class 'ValueError'>, ValueError('attempt to assign sequence of size 1 to extended slice of size 2',))
+(b'a', b'b', b'c', b'O')
+nel[1:1:-1] = "a":(<class 'ValueError'>, ValueError('attempt to assign sequence of size greater than 0 to extended slice',))
+(b'a', b'b', b'c', b'O')
+nel[:] = FailingIterNextN(2):(<class 'NotImplementedError'>, NotImplementedError('next N',))
+(b'a', b'b', b'c', b'O')
+>>> Testing StringToChars using l[:] = [{%s : 1}]
+l[:] = [{1 : 1}]:(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+l[:] = [{b"\0" : 1}]:(<class 'TypeError'>, TypeError('expected bytes with no null',))
+l[:] = [{"\0" : 1}]:(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+>>> Testing StringToChars using l[:] = [{"abcF" : {%s : 1}}]
+l[:] = [{"abcF" : {1 : 1}}]:(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+l[:] = [{"abcF" : {b"\0" : 1}}]:(<class 'TypeError'>, TypeError('expected bytes with no null',))
+l[:] = [{"abcF" : {"\0" : 1}}]:(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+>>> Testing StringToChars using l[:] = [{"abcF" : Mapping({%s : 1})}]
+l[:] = [{"abcF" : Mapping({1 : 1})}]:(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+l[:] = [{"abcF" : Mapping({b"\0" : 1})}]:(<class 'TypeError'>, TypeError('expected bytes with no null',))
+l[:] = [{"abcF" : Mapping({"\0" : 1})}]:(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+>>> Testing *Iter* using l[:] = [{"abcF" : %s}]
+l[:] = [{"abcF" : FailingIter()}]:(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',))
+l[:] = [{"abcF" : FailingIterNext()}]:(<class 'NotImplementedError'>, NotImplementedError('next',))
+<<< Finished
+>>> Testing ConvertFromPyObject using l[:] = [{"abcF" : %s}]
+l[:] = [{"abcF" : None}]:NOT FAILED
+l[:] = [{"abcF" : {b"": 1}}]:(<class 'ValueError'>, ValueError('empty keys are not allowed',))
+l[:] = [{"abcF" : {"": 1}}]:(<class 'ValueError'>, ValueError('empty keys are not allowed',))
+l[:] = [{"abcF" : FailingMapping()}]:(<class 'NotImplementedError'>, NotImplementedError('keys',))
+l[:] = [{"abcF" : FailingMappingKey()}]:(<class 'NotImplementedError'>, NotImplementedError('getitem:mappingkey',))
+l[:] = [{"abcF" : FailingNumber()}]:(<class 'NotImplementedError'>, NotImplementedError('int',))
+<<< Finished
+>>> Testing StringToChars using l[:] = [Mapping({%s : 1})]
+l[:] = [Mapping({1 : 1})]:(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+l[:] = [Mapping({b"\0" : 1})]:(<class 'TypeError'>, TypeError('expected bytes with no null',))
+l[:] = [Mapping({"\0" : 1})]:(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+>>> Testing StringToChars using l[:] = [Mapping({"abcG" : {%s : 1}})]
+l[:] = [Mapping({"abcG" : {1 : 1}})]:(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+l[:] = [Mapping({"abcG" : {b"\0" : 1}})]:(<class 'TypeError'>, TypeError('expected bytes with no null',))
+l[:] = [Mapping({"abcG" : {"\0" : 1}})]:(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+>>> Testing StringToChars using l[:] = [Mapping({"abcG" : Mapping({%s : 1})})]
+l[:] = [Mapping({"abcG" : Mapping({1 : 1})})]:(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+l[:] = [Mapping({"abcG" : Mapping({b"\0" : 1})})]:(<class 'TypeError'>, TypeError('expected bytes with no null',))
+l[:] = [Mapping({"abcG" : Mapping({"\0" : 1})})]:(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+>>> Testing *Iter* using l[:] = [Mapping({"abcG" : %s})]
+l[:] = [Mapping({"abcG" : FailingIter()})]:(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',))
+l[:] = [Mapping({"abcG" : FailingIterNext()})]:(<class 'NotImplementedError'>, NotImplementedError('next',))
+<<< Finished
+>>> Testing ConvertFromPyObject using l[:] = [Mapping({"abcG" : %s})]
+l[:] = [Mapping({"abcG" : None})]:NOT FAILED
+l[:] = [Mapping({"abcG" : {b"": 1}})]:(<class 'ValueError'>, ValueError('empty keys are not allowed',))
+l[:] = [Mapping({"abcG" : {"": 1}})]:(<class 'ValueError'>, ValueError('empty keys are not allowed',))
+l[:] = [Mapping({"abcG" : FailingMapping()})]:(<class 'NotImplementedError'>, NotImplementedError('keys',))
+l[:] = [Mapping({"abcG" : FailingMappingKey()})]:(<class 'NotImplementedError'>, NotImplementedError('getitem:mappingkey',))
+l[:] = [Mapping({"abcG" : FailingNumber()})]:(<class 'NotImplementedError'>, NotImplementedError('int',))
+<<< Finished
+>>> Testing *Iter* using l[:] = [%s]
+l[:] = [FailingIter()]:(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',))
+l[:] = [FailingIterNext()]:(<class 'NotImplementedError'>, NotImplementedError('next',))
+<<< Finished
+>>> Testing ConvertFromPyObject using l[:] = [%s]
+l[:] = [None]:NOT FAILED
+l[:] = [{b"": 1}]:(<class 'ValueError'>, ValueError('empty keys are not allowed',))
+l[:] = [{"": 1}]:(<class 'ValueError'>, ValueError('empty keys are not allowed',))
+l[:] = [FailingMapping()]:(<class 'NotImplementedError'>, NotImplementedError('keys',))
+l[:] = [FailingMappingKey()]:(<class 'NotImplementedError'>, NotImplementedError('getitem:mappingkey',))
+l[:] = [FailingNumber()]:(<class 'NotImplementedError'>, NotImplementedError('int',))
+<<< Finished
+>> ListConcatInPlace
+>>> Testing *Iter* using l.extend(%s)
+l.extend(FailingIter()):(<class 'NotImplementedError'>, NotImplementedError('iter',))
+l.extend(FailingIterNext()):(<class 'NotImplementedError'>, NotImplementedError('next',))
+<<< Finished
+>>> Testing StringToChars using l.extend([{%s : 1}])
+l.extend([{1 : 1}]):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+l.extend([{b"\0" : 1}]):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+l.extend([{"\0" : 1}]):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+>>> Testing StringToChars using l.extend([{"abcF" : {%s : 1}}])
+l.extend([{"abcF" : {1 : 1}}]):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+l.extend([{"abcF" : {b"\0" : 1}}]):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+l.extend([{"abcF" : {"\0" : 1}}]):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+>>> Testing StringToChars using l.extend([{"abcF" : Mapping({%s : 1})}])
+l.extend([{"abcF" : Mapping({1 : 1})}]):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+l.extend([{"abcF" : Mapping({b"\0" : 1})}]):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+l.extend([{"abcF" : Mapping({"\0" : 1})}]):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+>>> Testing *Iter* using l.extend([{"abcF" : %s}])
+l.extend([{"abcF" : FailingIter()}]):(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',))
+l.extend([{"abcF" : FailingIterNext()}]):(<class 'NotImplementedError'>, NotImplementedError('next',))
+<<< Finished
+>>> Testing ConvertFromPyObject using l.extend([{"abcF" : %s}])
+l.extend([{"abcF" : None}]):NOT FAILED
+l.extend([{"abcF" : {b"": 1}}]):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
+l.extend([{"abcF" : {"": 1}}]):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
+l.extend([{"abcF" : FailingMapping()}]):(<class 'NotImplementedError'>, NotImplementedError('keys',))
+l.extend([{"abcF" : FailingMappingKey()}]):(<class 'NotImplementedError'>, NotImplementedError('getitem:mappingkey',))
+l.extend([{"abcF" : FailingNumber()}]):(<class 'NotImplementedError'>, NotImplementedError('int',))
+<<< Finished
+>>> Testing StringToChars using l.extend([Mapping({%s : 1})])
+l.extend([Mapping({1 : 1})]):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+l.extend([Mapping({b"\0" : 1})]):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+l.extend([Mapping({"\0" : 1})]):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+>>> Testing StringToChars using l.extend([Mapping({"abcG" : {%s : 1}})])
+l.extend([Mapping({"abcG" : {1 : 1}})]):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+l.extend([Mapping({"abcG" : {b"\0" : 1}})]):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+l.extend([Mapping({"abcG" : {"\0" : 1}})]):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+>>> Testing StringToChars using l.extend([Mapping({"abcG" : Mapping({%s : 1})})])
+l.extend([Mapping({"abcG" : Mapping({1 : 1})})]):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+l.extend([Mapping({"abcG" : Mapping({b"\0" : 1})})]):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+l.extend([Mapping({"abcG" : Mapping({"\0" : 1})})]):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+>>> Testing *Iter* using l.extend([Mapping({"abcG" : %s})])
+l.extend([Mapping({"abcG" : FailingIter()})]):(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',))
+l.extend([Mapping({"abcG" : FailingIterNext()})]):(<class 'NotImplementedError'>, NotImplementedError('next',))
+<<< Finished
+>>> Testing ConvertFromPyObject using l.extend([Mapping({"abcG" : %s})])
+l.extend([Mapping({"abcG" : None})]):NOT FAILED
+l.extend([Mapping({"abcG" : {b"": 1}})]):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
+l.extend([Mapping({"abcG" : {"": 1}})]):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
+l.extend([Mapping({"abcG" : FailingMapping()})]):(<class 'NotImplementedError'>, NotImplementedError('keys',))
+l.extend([Mapping({"abcG" : FailingMappingKey()})]):(<class 'NotImplementedError'>, NotImplementedError('getitem:mappingkey',))
+l.extend([Mapping({"abcG" : FailingNumber()})]):(<class 'NotImplementedError'>, NotImplementedError('int',))
+<<< Finished
+>>> Testing *Iter* using l.extend([%s])
+l.extend([FailingIter()]):(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',))
+l.extend([FailingIterNext()]):(<class 'NotImplementedError'>, NotImplementedError('next',))
+<<< Finished
+>>> Testing ConvertFromPyObject using l.extend([%s])
+l.extend([None]):NOT FAILED
+l.extend([{b"": 1}]):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
+l.extend([{"": 1}]):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
+l.extend([FailingMapping()]):(<class 'NotImplementedError'>, NotImplementedError('keys',))
+l.extend([FailingMappingKey()]):(<class 'NotImplementedError'>, NotImplementedError('getitem:mappingkey',))
+l.extend([FailingNumber()]):(<class 'NotImplementedError'>, NotImplementedError('int',))
+<<< Finished
+>> ListSetattr
+del l.locked:(<class 'AttributeError'>, AttributeError('cannot delete vim.List attributes',))
+l.locked = FailingTrue():(<class 'NotImplementedError'>, NotImplementedError('bool',))
+l.xxx = True:(<class 'AttributeError'>, AttributeError('cannot set attribute xxx',))
+> Function
+>> FunctionConstructor
+>>> FunctionConstructor
+vim.Function("123"):(<class 'ValueError'>, ValueError('unnamed function 123 does not exist',))
+vim.Function("xxx_non_existent_function_xxx"):(<class 'ValueError'>, ValueError('function xxx_non_existent_function_xxx does not exist',))
+vim.Function("xxx#non#existent#function#xxx"):NOT FAILED
+vim.Function("xxx_non_existent_function_xxx2", args=[]):(<class 'ValueError'>, ValueError('function xxx_non_existent_function_xxx2 does not exist',))
+vim.Function("xxx_non_existent_function_xxx3", self={}):(<class 'ValueError'>, ValueError('function xxx_non_existent_function_xxx3 does not exist',))
+vim.Function("xxx_non_existent_function_xxx4", args=[], self={}):(<class 'ValueError'>, ValueError('function xxx_non_existent_function_xxx4 does not exist',))
+>>> FunctionNew
+vim.Function("tr", self="abcFuncSelf"):(<class 'AttributeError'>, AttributeError('keys',))
+vim.Function("tr", args=427423):(<class 'TypeError'>, TypeError('unable to convert int to vim list',))
+vim.Function("tr", self="abcFuncSelf2", args="abcFuncArgs2"):(<class 'AttributeError'>, AttributeError('keys',))
+vim.Function(self="abcFuncSelf2", args="abcFuncArgs2"):(<class 'AttributeError'>, AttributeError('keys',))
+vim.Function("tr", "", self="abcFuncSelf2", args="abcFuncArgs2"):(<class 'AttributeError'>, AttributeError('keys',))
+vim.Function("tr", ""):(<class 'TypeError'>, TypeError('function takes exactly 1 argument (2 given)',))
+>> FunctionCall
+>>> Testing StringToChars using f({%s : 1})
+f({1 : 1}):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+f({b"\0" : 1}):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+f({"\0" : 1}):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+>>> Testing StringToChars using f({"abcF" : {%s : 1}})
+f({"abcF" : {1 : 1}}):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+f({"abcF" : {b"\0" : 1}}):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+f({"abcF" : {"\0" : 1}}):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+>>> Testing StringToChars using f({"abcF" : Mapping({%s : 1})})
+f({"abcF" : Mapping({1 : 1})}):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+f({"abcF" : Mapping({b"\0" : 1})}):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+f({"abcF" : Mapping({"\0" : 1})}):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+>>> Testing *Iter* using f({"abcF" : %s})
+f({"abcF" : FailingIter()}):(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',))
+f({"abcF" : FailingIterNext()}):(<class 'NotImplementedError'>, NotImplementedError('next',))
+<<< Finished
+>>> Testing ConvertFromPyObject using f({"abcF" : %s})
+f({"abcF" : None}):NOT FAILED
+f({"abcF" : {b"": 1}}):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
+f({"abcF" : {"": 1}}):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
+f({"abcF" : FailingMapping()}):(<class 'NotImplementedError'>, NotImplementedError('keys',))
+f({"abcF" : FailingMappingKey()}):(<class 'NotImplementedError'>, NotImplementedError('getitem:mappingkey',))
+f({"abcF" : FailingNumber()}):(<class 'NotImplementedError'>, NotImplementedError('int',))
+<<< Finished
+>>> Testing StringToChars using f(Mapping({%s : 1}))
+f(Mapping({1 : 1})):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+f(Mapping({b"\0" : 1})):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+f(Mapping({"\0" : 1})):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+>>> Testing StringToChars using f(Mapping({"abcG" : {%s : 1}}))
+f(Mapping({"abcG" : {1 : 1}})):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+f(Mapping({"abcG" : {b"\0" : 1}})):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+f(Mapping({"abcG" : {"\0" : 1}})):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+>>> Testing StringToChars using f(Mapping({"abcG" : Mapping({%s : 1})}))
+f(Mapping({"abcG" : Mapping({1 : 1})})):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+f(Mapping({"abcG" : Mapping({b"\0" : 1})})):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+f(Mapping({"abcG" : Mapping({"\0" : 1})})):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+>>> Testing *Iter* using f(Mapping({"abcG" : %s}))
+f(Mapping({"abcG" : FailingIter()})):(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',))
+f(Mapping({"abcG" : FailingIterNext()})):(<class 'NotImplementedError'>, NotImplementedError('next',))
+<<< Finished
+>>> Testing ConvertFromPyObject using f(Mapping({"abcG" : %s}))
+f(Mapping({"abcG" : None})):NOT FAILED
+f(Mapping({"abcG" : {b"": 1}})):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
+f(Mapping({"abcG" : {"": 1}})):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
+f(Mapping({"abcG" : FailingMapping()})):(<class 'NotImplementedError'>, NotImplementedError('keys',))
+f(Mapping({"abcG" : FailingMappingKey()})):(<class 'NotImplementedError'>, NotImplementedError('getitem:mappingkey',))
+f(Mapping({"abcG" : FailingNumber()})):(<class 'NotImplementedError'>, NotImplementedError('int',))
+<<< Finished
+>>> Testing *Iter* using f(%s)
+f(FailingIter()):(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',))
+f(FailingIterNext()):(<class 'NotImplementedError'>, NotImplementedError('next',))
+<<< Finished
+>>> Testing ConvertFromPyObject using f(%s)
+f(None):NOT FAILED
+f({b"": 1}):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
+f({"": 1}):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
+f(FailingMapping()):(<class 'NotImplementedError'>, NotImplementedError('keys',))
+f(FailingMappingKey()):(<class 'NotImplementedError'>, NotImplementedError('getitem:mappingkey',))
+f(FailingNumber()):(<class 'NotImplementedError'>, NotImplementedError('int',))
+<<< Finished
+>>> Testing StringToChars using fd(self={%s : 1})
+fd(self={1 : 1}):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+fd(self={b"\0" : 1}):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+fd(self={"\0" : 1}):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+>>> Testing StringToChars using fd(self={"abcF" : {%s : 1}})
+fd(self={"abcF" : {1 : 1}}):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+fd(self={"abcF" : {b"\0" : 1}}):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+fd(self={"abcF" : {"\0" : 1}}):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+>>> Testing StringToChars using fd(self={"abcF" : Mapping({%s : 1})})
+fd(self={"abcF" : Mapping({1 : 1})}):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+fd(self={"abcF" : Mapping({b"\0" : 1})}):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+fd(self={"abcF" : Mapping({"\0" : 1})}):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+>>> Testing *Iter* using fd(self={"abcF" : %s})
+fd(self={"abcF" : FailingIter()}):(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',))
+fd(self={"abcF" : FailingIterNext()}):(<class 'NotImplementedError'>, NotImplementedError('next',))
+<<< Finished
+>>> Testing ConvertFromPyObject using fd(self={"abcF" : %s})
+fd(self={"abcF" : None}):NOT FAILED
+fd(self={"abcF" : {b"": 1}}):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
+fd(self={"abcF" : {"": 1}}):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
+fd(self={"abcF" : FailingMapping()}):(<class 'NotImplementedError'>, NotImplementedError('keys',))
+fd(self={"abcF" : FailingMappingKey()}):(<class 'NotImplementedError'>, NotImplementedError('getitem:mappingkey',))
+fd(self={"abcF" : FailingNumber()}):(<class 'NotImplementedError'>, NotImplementedError('int',))
+<<< Finished
+>>> Testing StringToChars using fd(self=Mapping({%s : 1}))
+fd(self=Mapping({1 : 1})):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+fd(self=Mapping({b"\0" : 1})):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+fd(self=Mapping({"\0" : 1})):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+>>> Testing StringToChars using fd(self=Mapping({"abcG" : {%s : 1}}))
+fd(self=Mapping({"abcG" : {1 : 1}})):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+fd(self=Mapping({"abcG" : {b"\0" : 1}})):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+fd(self=Mapping({"abcG" : {"\0" : 1}})):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+>>> Testing StringToChars using fd(self=Mapping({"abcG" : Mapping({%s : 1})}))
+fd(self=Mapping({"abcG" : Mapping({1 : 1})})):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+fd(self=Mapping({"abcG" : Mapping({b"\0" : 1})})):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+fd(self=Mapping({"abcG" : Mapping({"\0" : 1})})):(<class 'TypeError'>, TypeError('expected bytes with no null',))
+<<< Finished
+>>> Testing *Iter* using fd(self=Mapping({"abcG" : %s}))
+fd(self=Mapping({"abcG" : FailingIter()})):(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',))
+fd(self=Mapping({"abcG" : FailingIterNext()})):(<class 'NotImplementedError'>, NotImplementedError('next',))
+<<< Finished
+>>> Testing ConvertFromPyObject using fd(self=Mapping({"abcG" : %s}))
+fd(self=Mapping({"abcG" : None})):NOT FAILED
+fd(self=Mapping({"abcG" : {b"": 1}})):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
+fd(self=Mapping({"abcG" : {"": 1}})):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
+fd(self=Mapping({"abcG" : FailingMapping()})):(<class 'NotImplementedError'>, NotImplementedError('keys',))
+fd(self=Mapping({"abcG" : FailingMappingKey()})):(<class 'NotImplementedError'>, NotImplementedError('getitem:mappingkey',))
+fd(self=Mapping({"abcG" : FailingNumber()})):(<class 'NotImplementedError'>, NotImplementedError('int',))
+<<< Finished
+>>> Testing *Iter* using fd(self=%s)
+fd(self=FailingIter()):(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim dictionary',))
+fd(self=FailingIterNext()):(<class 'TypeError'>, TypeError('unable to convert FailingIterNext to vim dictionary',))
+<<< Finished
+>>> Testing ConvertFromPyObject using fd(self=%s)
+fd(self=None):(<class 'TypeError'>, TypeError('unable to convert NoneType to vim dictionary',))
+fd(self={b"": 1}):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
+fd(self={"": 1}):(<class 'ValueError'>, ValueError('empty keys are not allowed',))
+fd(self=FailingMapping()):(<class 'NotImplementedError'>, NotImplementedError('keys',))
+fd(self=FailingMappingKey()):(<class 'NotImplementedError'>, NotImplementedError('getitem:mappingkey',))
+fd(self=FailingNumber()):(<class 'TypeError'>, TypeError('unable to convert FailingNumber to vim dictionary',))
+<<< Finished
+>>> Testing ConvertFromPyMapping using fd(self=%s)
+fd(self=[]):(<class 'AttributeError'>, AttributeError('keys',))
+<<< Finished
+> TabPage
+>> TabPageAttr
+vim.current.tabpage.xxx:(<class 'AttributeError'>, AttributeError("'vim.tabpage' object has no attribute 'xxx'",))
+> TabList
+>> TabListItem
+vim.tabpages[1000]:(<class 'IndexError'>, IndexError('no such tab page',))
+> Window
+>> WindowAttr
+vim.current.window.xxx:(<class 'AttributeError'>, AttributeError("'vim.window' object has no attribute 'xxx'",))
+>> WindowSetattr
+vim.current.window.buffer = 0:(<class 'TypeError'>, TypeError('readonly attribute: buffer',))
+vim.current.window.cursor = (100000000, 100000000):(<class 'vim.error'>, error('cursor position outside buffer',))
+vim.current.window.cursor = True:(<class 'TypeError'>, TypeError('argument must be 2-item sequence, not bool',))
+>>> Testing NumberToLong using vim.current.window.height = %s
+vim.current.window.height = []:(<class 'TypeError'>, TypeError('expected int() or something supporting coercing to int(), but got list',))
+vim.current.window.height = None:(<class 'TypeError'>, TypeError('expected int() or something supporting coercing to int(), but got NoneType',))
+vim.current.window.height = -1:(<class 'ValueError'>, ValueError('number must be greater or equal to zero',))
+<<< Finished
+>>> Testing NumberToLong using vim.current.window.width = %s
+vim.current.window.width = []:(<class 'TypeError'>, TypeError('expected int() or something supporting coercing to int(), but got list',))
+vim.current.window.width = None:(<class 'TypeError'>, TypeError('expected int() or something supporting coercing to int(), but got NoneType',))
+vim.current.window.width = -1:(<class 'ValueError'>, ValueError('number must be greater or equal to zero',))
+<<< Finished
+vim.current.window.xxxxxx = True:(<class 'AttributeError'>, AttributeError('xxxxxx',))
+> WinList
+>> WinListItem
+vim.windows[1000]:(<class 'IndexError'>, IndexError('no such window',))
+> Buffer
+>> StringToLine (indirect)
+vim.current.buffer[0] = "\na":(<class 'vim.error'>, error('string cannot contain newlines',))
+vim.current.buffer[0] = b"\na":(<class 'vim.error'>, error('string cannot contain newlines',))
+>> SetBufferLine (indirect)
+vim.current.buffer[0] = True:(<class 'TypeError'>, TypeError('bad argument type for built-in operation',))
+>> SetBufferLineList (indirect)
+vim.current.buffer[:] = True:(<class 'TypeError'>, TypeError('bad argument type for built-in operation',))
+vim.current.buffer[:] = ["\na", "bc"]:(<class 'vim.error'>, error('string cannot contain newlines',))
+>> InsertBufferLines (indirect)
+vim.current.buffer.append(None):(<class 'TypeError'>, TypeError('bad argument type for built-in operation',))
+vim.current.buffer.append(["\na", "bc"]):(<class 'vim.error'>, error('string cannot contain newlines',))
+vim.current.buffer.append("\nbc"):(<class 'vim.error'>, error('string cannot contain newlines',))
+>> RBItem
+vim.current.buffer[100000000]:(<class 'IndexError'>, IndexError('line number out of range',))
+>> RBAsItem
+vim.current.buffer[100000000] = "":(<class 'IndexError'>, IndexError('line number out of range',))
+>> BufferAttr
+vim.current.buffer.xxx:(<class 'AttributeError'>, AttributeError("'vim.buffer' object has no attribute 'xxx'",))
+>> BufferSetattr
+vim.current.buffer.name = True:(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got bool',))
+vim.current.buffer.xxx = True:(<class 'AttributeError'>, AttributeError('xxx',))
+>> BufferMark
+vim.current.buffer.mark(0):(<class 'TypeError'>, TypeError('expected bytes() or str() instance, but got int',))
+vim.current.buffer.mark("abcM"):(<class 'ValueError'>, ValueError('mark name must be a single character',))
+vim.current.buffer.mark("!"):(<class 'vim.error'>, error('invalid mark name',))
+>> BufferRange
+vim.current.buffer.range(1, 2, 3):(<class 'TypeError'>, TypeError('function takes exactly 2 arguments (3 given)',))
+> BufMap
+>> BufMapItem
+vim.buffers[100000000]:(<class 'KeyError'>, KeyError(100000000,))
+>>> Testing NumberToLong using vim.buffers[%s]
+vim.buffers[[]]:(<class 'TypeError'>, TypeError('expected int() or something supporting coercing to int(), but got list',))
+vim.buffers[None]:(<class 'TypeError'>, TypeError('expected int() or something supporting coercing to int(), but got NoneType',))
+vim.buffers[-1]:(<class 'ValueError'>, ValueError('number must be greater than zero',))
+vim.buffers[0]:(<class 'ValueError'>, ValueError('number must be greater than zero',))
+<<< Finished
+> Current
+>> CurrentGetattr
+vim.current.xxx:(<class 'AttributeError'>, AttributeError("'vim.currentdata' object has no attribute 'xxx'",))
+>> CurrentSetattr
+vim.current.line = True:(<class 'TypeError'>, TypeError('bad argument type for built-in operation',))
+vim.current.buffer = True:(<class 'TypeError'>, TypeError('expected vim.Buffer object, but got bool',))
+vim.current.window = True:(<class 'TypeError'>, TypeError('expected vim.Window object, but got bool',))
+vim.current.tabpage = True:(<class 'TypeError'>, TypeError('expected vim.TabPage object, but got bool',))
+vim.current.xxx = True:(<class 'AttributeError'>, AttributeError('xxx',))
+['.']
+'.'
+3,xx
+before
+after
+pythonx/topmodule/__init__.py
+pythonx/topmodule/submodule/__init__.py
+pythonx/topmodule/submodule/subsubmodule/subsubsubmodule.py
+vim.command("throw 'abcN'"):(<class 'vim.error'>, error('abcN',))
+Exe("throw 'def'"):(<class 'vim.error'>, error('def',))
+vim.eval("Exe('throw ''ghi''')"):(<class 'vim.error'>, error('ghi',))
+vim.eval("Exe('echoerr ''jkl''')"):(<class 'vim.error'>, error('Vim(echoerr):jkl',))
+vim.eval("Exe('xxx_non_existent_command_xxx')"):(<class 'vim.error'>, error('Vim:E492: Not an editor command: xxx_non_existent_command_xxx',))
+vim.eval("xxx_unknown_function_xxx()"):(<class 'vim.error'>, error('Vim:E117: Unknown function: xxx_unknown_function_xxx',))
+vim.bindeval("Exe('xxx_non_existent_command_xxx')"):(<class 'vim.error'>, error('Vim:E492: Not an editor command: xxx_non_existent_command_xxx',))
+Caught KeyboardInterrupt
+Running :put
+No exception
+
diff --git a/src/testdir/test88.in b/src/testdir/test88.in
new file mode 100644
index 0000000..9e43f70
--- /dev/null
+++ b/src/testdir/test88.in
@@ -0,0 +1,99 @@
+vim: set ft=vim
+
+Tests for correct display (cursor column position) with +conceal and
+tabulators.
+
+STARTTEST
+:so small.vim
+:if !has('conceal')
+ e! test.ok
+ wq! test.out
+:endif
+:" Conceal settings.
+:set conceallevel=2
+:set concealcursor=nc
+:syntax match test /|/ conceal
+:" Save current cursor position. Only works in <expr> mode, can't be used
+:" with :normal because it moves the cursor to the command line. Thanks to ZyX
+:" <zyx.vim@gmail.com> for the idea to use an <expr> mapping.
+:let positions = []
+:nnoremap <expr> GG ":let positions += ['".screenrow().":".screencol()."']\n"
+:" Start test.
+/^start:
+:normal ztj
+GGk
+:" We should end up in the same column when running these commands on the two
+:" lines.
+:normal ft
+GGk
+:normal $
+GGk
+:normal 0j
+GGk
+:normal ft
+GGk
+:normal $
+GGk
+:normal 0j0j
+GGk
+:" Same for next test block.
+:normal ft
+GGk
+:normal $
+GGk
+:normal 0j
+GGk
+:normal ft
+GGk
+:normal $
+GGk
+:normal 0j0j
+GGk
+:" And check W with multiple tabs and conceals in a line.
+:normal W
+GGk
+:normal W
+GGk
+:normal W
+GGk
+:normal $
+GGk
+:normal 0j
+GGk
+:normal W
+GGk
+:normal W
+GGk
+:normal W
+GGk
+:normal $
+GGk
+:set lbr
+:normal $
+GGk
+:set list listchars=tab:>-
+:normal 0
+GGk
+:normal W
+GGk
+:normal W
+GGk
+:normal W
+GGk
+:normal $
+GGk
+:" Display result.
+:call append('$', 'end:')
+:call append('$', positions)
+:/^end/,$wq! test.out
+ENDTEST
+
+start:
+.concealed. text
+|concealed| text
+
+ .concealed. text
+ |concealed| text
+
+.a. .b. .c. .d.
+|a| |b| |c| |d|
diff --git a/src/testdir/test88.ok b/src/testdir/test88.ok
new file mode 100644
index 0000000..12949f2
--- /dev/null
+++ b/src/testdir/test88.ok
@@ -0,0 +1,29 @@
+end:
+2:1
+2:17
+2:20
+3:1
+3:17
+3:20
+5:8
+5:25
+5:28
+6:8
+6:25
+6:28
+8:1
+8:9
+8:17
+8:25
+8:27
+9:1
+9:9
+9:17
+9:25
+9:26
+9:26
+9:1
+9:9
+9:17
+9:25
+9:26
diff --git a/src/testdir/test94.in b/src/testdir/test94.in
new file mode 100644
index 0000000..447fd2b
--- /dev/null
+++ b/src/testdir/test94.in
@@ -0,0 +1,257 @@
+Test for Visual mode and operators
+
+Tests for the two kinds of operations: Those executed with Visual mode
+followed by an operator and those executed via Operator-pending mode. Also
+part of the test are mappings, counts, and repetition with the . command.
+
+Test cases:
+- Visual modes (v V CTRL-V) followed by an operator; count; repeating
+- Visual mode maps; count; repeating
+ - Simple
+ - With an Ex command (custom text object)
+- Operator-pending mode maps
+ - Simple
+ - With Ex command moving the cursor
+ - With Ex command and Visual selection (custom text object)
+- Patch 7.3.879: Properly abort Ex command in Operator-pending mode
+
+STARTTEST
+:so small.vim
+:set belloff=all
+:set enc=utf-8 nocp viminfo+=nviminfo
+:
+:" User functions
+:function MoveToCap()
+: call search('\u', 'W')
+:endfunction
+:function SelectInCaps()
+: let [line1, col1] = searchpos('\u', 'bcnW')
+: let [line2, col2] = searchpos('.\u', 'nW')
+: call setpos("'<", [0, line1, col1, 0])
+: call setpos("'>", [0, line2, col2, 0])
+: normal! gv
+:endfunction
+:
+:" Visual modes followed by operator
+/^apple
+lvld.l3vd.:
+/^line 1
+Vcnewlinej.j2Vd.:
+/^xxxx
+jlc l.l2c----l.:
+:
+:" Visual mode maps (movement and text object)
+:vnoremap W /\u/s-1<CR>
+:vnoremap iW :<C-U>call SelectInCaps()<CR>
+/^Kiwi
+vWcNol.fD2vd.:
+/^Jambu
+llviWc-l.l2vdl.:
+:
+:" Operator-pending mode maps (movement and text object)
+:onoremap W /\u/<CR>
+:onoremap <Leader>W :<C-U>call MoveToCap()<CR>
+:onoremap iW :<C-U>call SelectInCaps()<CR>
+/^Pineapple
+cW-l.l2.l.:
+/^Juniper
+g?\WfD.:
+/^Lemon
+yiWPlciWNewfr.:
+:
+:" Patch 7.3.879: Properly abort Operator-pending mode for "dv:<Esc>" etc.
+/^zzzz
+dV: dv: :set noma | let v:errmsg = ''
+d: :set ma | put = v:errmsg =~# '^E21' ? 'ok' : 'failed'
+dv:dV::set noma | let v:errmsg = ''
+d::set ma | put = v:errmsg =~# '^E21' ? 'failed' : 'ok'
+:
+:$put =''
+:$put ='characterwise visual mode: replace last line'
+:$put ='a'
+:let @" = 'x'
+:let v:errmsg = ''
+v$p
+:$put ='---'
+:$put ='v:errmsg='.v:errmsg
+:
+:$put =''
+:$put ='characterwise visual mode: delete middle line'
+:$put ='a'
+:$put ='b'
+:$put ='c'
+kkv$d
+:$put ='---'
+:
+:$put =''
+:$put ='characterwise visual mode: delete middle two line'
+:$put ='a'
+:$put ='b'
+:$put ='c'
+kkvj$d
+:$put ='---'
+:
+:$put =''
+:$put ='characterwise visual mode: delete last line'
+:$put ='a'
+:$put ='b'
+:$put ='c'
+v$d
+:$put ='---'
+:
+:$put =''
+:$put ='characterwise visual mode: delete last two line'
+:$put ='a'
+:$put ='b'
+:$put ='c'
+kvj$d
+:$put ='---'
+:
+:" Select mode maps
+:snoremap <lt>End> <End>
+:snoremap <lt>Down> <Down>
+:snoremap <lt>Del> <Del>
+:
+:$put =''
+:$put ='characterwise select mode: delete middle line'
+:$put ='a'
+:$put ='b'
+:$put ='c'
+kkgh<End><Del>
+:$put ='---'
+:
+:$put =''
+:$put ='characterwise select mode: delete middle two line'
+:$put ='a'
+:$put ='b'
+:$put ='c'
+kkgh<Down><End><Del>
+:$put ='---'
+:
+:$put =''
+:$put ='characterwise select mode: delete last line'
+:$put ='a'
+:$put ='b'
+:$put ='c'
+gh<End><Del>
+:$put ='---'
+:
+:$put =''
+:$put ='characterwise select mode: delete last two line'
+:$put ='a'
+:$put ='b'
+:$put ='c'
+kgh<Down><End><Del>
+:$put ='---'
+:
+:$put =''
+:$put ='linewise select mode: delete middle line'
+:$put ='a'
+:$put ='b'
+:$put ='c'
+kkgH<Del>
+:$put ='---'
+:
+:$put =''
+:$put ='linewise select mode: delete middle two line'
+:$put ='a'
+:$put ='b'
+:$put ='c'
+kkgH<Down><Del>
+:$put ='---'
+:
+:$put =''
+:$put ='linewise select mode: delete last line'
+:$put ='a'
+:$put ='b'
+:$put ='c'
+gH<Del>
+:$put ='---'
+:
+:$put =''
+:$put ='linewise select mode: delete last two line'
+:$put ='a'
+:$put ='b'
+:$put ='c'
+kgH<Down><Del>
+:$put ='---'
+:
+:$put =''
+:$put ='v_p: replace last character with line register at middle line'
+:$put ='aaa'
+:$put ='bbb'
+:$put ='ccc'
+:-2yank
+k$vp
+:$put ='---'
+:
+:$put =''
+:$put ='v_p: replace last character with line register at middle line selecting newline'
+:$put ='aaa'
+:$put ='bbb'
+:$put ='ccc'
+:-2yank
+k$v$p
+:$put ='---'
+:
+:$put =''
+:$put ='v_p: replace last character with line register at last line'
+:$put ='aaa'
+:$put ='bbb'
+:$put ='ccc'
+:-2yank
+$vp
+:$put ='---'
+:
+:$put =''
+:$put ='v_p: replace last character with line register at last line selecting newline'
+:$put ='aaa'
+:$put ='bbb'
+:$put ='ccc'
+:-2yank
+$v$p
+:$put ='---'
+:
+:$put =''
+:$put ='gv in exclusive select mode after operation'
+:$put ='zzz '
+:$put ='äà '
+:set selection=exclusive
+kv3lyjv3lpgvcxxx
+:$put ='---'
+:
+:$put =''
+:$put ='gv in exclusive select mode without operation'
+:$put ='zzz '
+:set selection=exclusive
+0v3lgvcxxx
+:$put ='---'
+:/^start:/+2,$w! test.out
+:q!
+ENDTEST
+
+start:
+
+apple banana cherry
+
+line 1 line 1
+line 2 line 2
+line 3 line 3
+line 4 line 4
+line 5 line 5
+line 6 line 6
+
+xxxxxxxxxxxxx
+xxxxxxxxxxxxx
+xxxxxxxxxxxxx
+xxxxxxxxxxxxx
+
+KiwiRaspberryDateWatermelonPeach
+JambuRambutanBananaTangerineMango
+
+PineappleQuinceLoganberryOrangeGrapefruitKiwiZ
+JuniperDurianZ
+LemonNectarineZ
+
+zzzz
+zzzz
diff --git a/src/testdir/test94.ok b/src/testdir/test94.ok
new file mode 100644
index 0000000..c023922
--- /dev/null
+++ b/src/testdir/test94.ok
@@ -0,0 +1,123 @@
+a y
+
+newline
+newline
+
+ --------x
+ --------x
+xxxx--------x
+xxxx--------x
+
+NoNoberryach
+--ago
+
+----Z
+WhavcreQhevnaZ
+LemonNewNewZ
+
+zzz
+ok
+ok
+
+characterwise visual mode: replace last line
+x
+---
+v:errmsg=
+
+characterwise visual mode: delete middle line
+b
+c
+---
+
+characterwise visual mode: delete middle two line
+c
+---
+
+characterwise visual mode: delete last line
+a
+b
+
+---
+
+characterwise visual mode: delete last two line
+a
+
+---
+
+characterwise select mode: delete middle line
+b
+c
+---
+
+characterwise select mode: delete middle two line
+c
+---
+
+characterwise select mode: delete last line
+a
+b
+
+---
+
+characterwise select mode: delete last two line
+a
+
+---
+
+linewise select mode: delete middle line
+b
+c
+---
+
+linewise select mode: delete middle two line
+c
+---
+
+linewise select mode: delete last line
+a
+b
+---
+
+linewise select mode: delete last two line
+a
+---
+
+v_p: replace last character with line register at middle line
+aaa
+bb
+aaa
+
+ccc
+---
+
+v_p: replace last character with line register at middle line selecting newline
+aaa
+bb
+aaa
+ccc
+---
+
+v_p: replace last character with line register at last line
+aaa
+bbb
+cc
+aaa
+
+---
+
+v_p: replace last character with line register at last line selecting newline
+aaa
+bbb
+cc
+aaa
+
+---
+
+gv in exclusive select mode after operation
+zzz
+xxx
+---
+
+gv in exclusive select mode without operation
+xxx
+---
diff --git a/src/testdir/test95.in b/src/testdir/test95.in
new file mode 100644
index 0000000..934afde
--- /dev/null
+++ b/src/testdir/test95.in
@@ -0,0 +1,141 @@
+Test for regexp patterns with multi-byte support, using utf-8.
+See test64 for the non-multi-byte tests.
+
+A pattern that gives the expected result produces OK, so that we know it was
+actually tried.
+
+STARTTEST
+:so small.vim
+:so mbyte.vim
+:set nocp encoding=utf-8 viminfo+=nviminfo nomore
+:" tl is a List of Lists with:
+:" 2: test auto/old/new 0: test auto/old 1: test auto/new
+:" regexp pattern
+:" text to test the pattern on
+:" expected match (optional)
+:" expected submatch 1 (optional)
+:" expected submatch 2 (optional)
+:" etc.
+:" When there is no match use only the first two items.
+:let tl = []
+:
+:"""" Multi-byte character tests. These will fail unless vim is compiled
+:"""" with Multibyte (FEAT_MBYTE) or BIG/HUGE features.
+:call add(tl, [2, '[[:alpha:][=a=]]\+', '879 aiaãâaiuvna ', 'aiaãâaiuvna'])
+:call add(tl, [2, '[[=a=]]\+', 'ddaãâbcd', 'aãâ']) " equivalence classes
+:call add(tl, [2, '[^ม ]\+', 'มม oijasoifjos ifjoisj f osij j มมมมม abcd', 'oijasoifjos'])
+:call add(tl, [2, ' [^ ]\+', 'start มabcdม ', ' มabcdม'])
+:call add(tl, [2, '[ม[:alpha:][=a=]]\+', '879 aiaãมâมaiuvna ', 'aiaãมâมaiuvna'])
+:
+:" this is not a normal "i" but 0xec
+:call add(tl, [2, '\p\+', 'ìa', 'ìa'])
+:call add(tl, [2, '\p*', 'aã‚', 'aã‚'])
+:
+:"""" Test recognition of some character classes
+:call add(tl, [2, '\i\+', '&*¨xx ', 'xx'])
+:call add(tl, [2, '\f\+', '&*Ÿfname ', 'fname'])
+:
+:"""" Test composing character matching
+:call add(tl, [2, '.ม', 'xม่x yมy', 'yม'])
+:call add(tl, [2, '.ม่', 'xม่x yมy', 'xม่'])
+:call add(tl, [2, "\u05b9", " x\u05b9 ", "x\u05b9"])
+:call add(tl, [2, ".\u05b9", " x\u05b9 ", "x\u05b9"])
+:call add(tl, [2, "\u05b9\u05bb", " x\u05b9\u05bb ", "x\u05b9\u05bb"])
+:call add(tl, [2, ".\u05b9\u05bb", " x\u05b9\u05bb ", "x\u05b9\u05bb"])
+:call add(tl, [2, "\u05bb\u05b9", " x\u05b9\u05bb ", "x\u05b9\u05bb"])
+:call add(tl, [2, ".\u05bb\u05b9", " x\u05b9\u05bb ", "x\u05b9\u05bb"])
+:call add(tl, [2, "\u05b9", " y\u05bb x\u05b9 ", "x\u05b9"])
+:call add(tl, [2, ".\u05b9", " y\u05bb x\u05b9 ", "x\u05b9"])
+:call add(tl, [2, "\u05b9", " y\u05bb\u05b9 x\u05b9 ", "y\u05bb\u05b9"])
+:call add(tl, [2, ".\u05b9", " y\u05bb\u05b9 x\u05b9 ", "y\u05bb\u05b9"])
+:call add(tl, [1, "\u05b9\u05bb", " y\u05b9 x\u05b9\u05bb ", "x\u05b9\u05bb"])
+:call add(tl, [2, ".\u05b9\u05bb", " y\u05bb x\u05b9\u05bb ", "x\u05b9\u05bb"])
+:call add(tl, [2, "a", "ca\u0300t"])
+:call add(tl, [2, "ca", "ca\u0300t"])
+:call add(tl, [2, "a\u0300", "ca\u0300t", "a\u0300"])
+:call add(tl, [2, 'a\%C', "ca\u0300t", "a\u0300"])
+:call add(tl, [2, 'ca\%C', "ca\u0300t", "ca\u0300"])
+:call add(tl, [2, 'ca\%Ct', "ca\u0300t", "ca\u0300t"])
+:
+:
+:"""" Test \Z
+:call add(tl, [2, 'ú\Z', 'x'])
+:call add(tl, [2, 'יהוה\Z', 'יהוה', 'יהוה'])
+:call add(tl, [2, 'יְהוָה\Z', 'יהוה', 'יהוה'])
+:call add(tl, [2, 'יהוה\Z', 'יְהוָה', 'יְהוָה'])
+:call add(tl, [2, 'יְהוָה\Z', 'יְהוָה', 'יְהוָה'])
+:call add(tl, [2, 'יְ\Z', 'וְיַ', 'יַ'])
+:call add(tl, [2, "ק\u200d\u05b9x\\Z", "xק\u200d\u05b9xy", "ק\u200d\u05b9x"])
+:call add(tl, [2, "ק\u200d\u05b9x\\Z", "xק\u200dxy", "ק\u200dx"])
+:call add(tl, [2, "ק\u200dx\\Z", "xק\u200d\u05b9xy", "ק\u200d\u05b9x"])
+:call add(tl, [2, "ק\u200dx\\Z", "xק\u200dxy", "ק\u200dx"])
+:call add(tl, [2, "\u05b9\\Z", "xyz"])
+:call add(tl, [2, "\\Z\u05b9", "xyz"])
+:call add(tl, [2, "\u05b9\\Z", "xy\u05b9z", "y\u05b9"])
+:call add(tl, [2, "\\Z\u05b9", "xy\u05b9z", "y\u05b9"])
+:call add(tl, [1, "\u05b9\\+\\Z", "xy\u05b9z\u05b9 ", "y\u05b9z\u05b9"])
+:call add(tl, [1, "\\Z\u05b9\\+", "xy\u05b9z\u05b9 ", "y\u05b9z\u05b9"])
+:
+:"""" Combining different tests and features
+:call add(tl, [2, '[^[=a=]]\+', 'ddaãâbcd', 'dd'])
+:
+:"""" Run the tests
+:
+:"
+:for t in tl
+: let re = t[0]
+: let pat = t[1]
+: let text = t[2]
+: let matchidx = 3
+: for engine in [0, 1, 2]
+: if engine == 2 && re == 0 || engine == 1 && re == 1
+: continue
+: endif
+: let &regexpengine = engine
+: try
+: let l = matchlist(text, pat)
+: catch
+: $put ='ERROR ' . engine . ': pat: \"' . pat . '\", text: \"' . text . '\", caused an exception: \"' . v:exception . '\"'
+: endtry
+:" check the match itself
+: if len(l) == 0 && len(t) > matchidx
+: $put ='ERROR ' . engine . ': pat: \"' . pat . '\", text: \"' . text . '\", did not match, expected: \"' . t[matchidx] . '\"'
+: elseif len(l) > 0 && len(t) == matchidx
+: $put ='ERROR ' . engine . ': pat: \"' . pat . '\", text: \"' . text . '\", match: \"' . l[0] . '\", expected no match'
+: elseif len(t) > matchidx && l[0] != t[matchidx]
+: $put ='ERROR ' . engine . ': pat: \"' . pat . '\", text: \"' . text . '\", match: \"' . l[0] . '\", expected: \"' . t[matchidx] . '\"'
+: else
+: $put ='OK ' . engine . ' - ' . pat
+: endif
+: if len(l) > 0
+:" check all the nine submatches
+: for i in range(1, 9)
+: if len(t) <= matchidx + i
+: let e = ''
+: else
+: let e = t[matchidx + i]
+: endif
+: if l[i] != e
+: $put ='ERROR ' . engine . ': pat: \"' . pat . '\", text: \"' . text . '\", submatch ' . i . ': \"' . l[i] . '\", expected: \"' . e . '\"'
+: endif
+: endfor
+: unlet i
+: endif
+: endfor
+:endfor
+:unlet t tl e l
+:
+:" check that 'ambiwidth' does not change the meaning of \p
+:set regexpengine=1 ambiwidth=single
+:$put ='eng 1 ambi single: ' . match(\"\u00EC\", '\p')
+:set regexpengine=1 ambiwidth=double
+:$put ='eng 1 ambi double: ' . match(\"\u00EC\", '\p')
+:set regexpengine=2 ambiwidth=single
+:$put ='eng 2 ambi single: ' . match(\"\u00EC\", '\p')
+:set regexpengine=2 ambiwidth=double
+:$put ='eng 2 ambi double: ' . match(\"\u00EC\", '\p')
+:
+:/\%#=1^Results/,$wq! test.out
+ENDTEST
+
+Results of test95:
diff --git a/src/testdir/test95.ok b/src/testdir/test95.ok
new file mode 100644
index 0000000..6762994
--- /dev/null
+++ b/src/testdir/test95.ok
@@ -0,0 +1,140 @@
+Results of test95:
+OK 0 - [[:alpha:][=a=]]\+
+OK 1 - [[:alpha:][=a=]]\+
+OK 2 - [[:alpha:][=a=]]\+
+OK 0 - [[=a=]]\+
+OK 1 - [[=a=]]\+
+OK 2 - [[=a=]]\+
+OK 0 - [^ม ]\+
+OK 1 - [^ม ]\+
+OK 2 - [^ม ]\+
+OK 0 - [^ ]\+
+OK 1 - [^ ]\+
+OK 2 - [^ ]\+
+OK 0 - [ม[:alpha:][=a=]]\+
+OK 1 - [ม[:alpha:][=a=]]\+
+OK 2 - [ม[:alpha:][=a=]]\+
+OK 0 - \p\+
+OK 1 - \p\+
+OK 2 - \p\+
+OK 0 - \p*
+OK 1 - \p*
+OK 2 - \p*
+OK 0 - \i\+
+OK 1 - \i\+
+OK 2 - \i\+
+OK 0 - \f\+
+OK 1 - \f\+
+OK 2 - \f\+
+OK 0 - .ม
+OK 1 - .ม
+OK 2 - .ม
+OK 0 - .ม่
+OK 1 - .ม่
+OK 2 - .ม่
+OK 0 - Ö¹
+OK 1 - Ö¹
+OK 2 - Ö¹
+OK 0 - .Ö¹
+OK 1 - .Ö¹
+OK 2 - .Ö¹
+OK 0 - Ö¹Ö»
+OK 1 - Ö¹Ö»
+OK 2 - Ö¹Ö»
+OK 0 - .Ö¹Ö»
+OK 1 - .Ö¹Ö»
+OK 2 - .Ö¹Ö»
+OK 0 - Ö»Ö¹
+OK 1 - Ö»Ö¹
+OK 2 - Ö»Ö¹
+OK 0 - .Ö»Ö¹
+OK 1 - .Ö»Ö¹
+OK 2 - .Ö»Ö¹
+OK 0 - Ö¹
+OK 1 - Ö¹
+OK 2 - Ö¹
+OK 0 - .Ö¹
+OK 1 - .Ö¹
+OK 2 - .Ö¹
+OK 0 - Ö¹
+OK 1 - Ö¹
+OK 2 - Ö¹
+OK 0 - .Ö¹
+OK 1 - .Ö¹
+OK 2 - .Ö¹
+OK 0 - Ö¹Ö»
+OK 2 - Ö¹Ö»
+OK 0 - .Ö¹Ö»
+OK 1 - .Ö¹Ö»
+OK 2 - .Ö¹Ö»
+OK 0 - a
+OK 1 - a
+OK 2 - a
+OK 0 - ca
+OK 1 - ca
+OK 2 - ca
+OK 0 - à
+OK 1 - à
+OK 2 - à
+OK 0 - a\%C
+OK 1 - a\%C
+OK 2 - a\%C
+OK 0 - ca\%C
+OK 1 - ca\%C
+OK 2 - ca\%C
+OK 0 - ca\%Ct
+OK 1 - ca\%Ct
+OK 2 - ca\%Ct
+OK 0 - ú\Z
+OK 1 - ú\Z
+OK 2 - ú\Z
+OK 0 - יהוה\Z
+OK 1 - יהוה\Z
+OK 2 - יהוה\Z
+OK 0 - יְהוָה\Z
+OK 1 - יְהוָה\Z
+OK 2 - יְהוָה\Z
+OK 0 - יהוה\Z
+OK 1 - יהוה\Z
+OK 2 - יהוה\Z
+OK 0 - יְהוָה\Z
+OK 1 - יְהוָה\Z
+OK 2 - יְהוָה\Z
+OK 0 - ×™Ö°\Z
+OK 1 - ×™Ö°\Z
+OK 2 - ×™Ö°\Z
+OK 0 - קâ€Ö¹x\Z
+OK 1 - קâ€Ö¹x\Z
+OK 2 - קâ€Ö¹x\Z
+OK 0 - קâ€Ö¹x\Z
+OK 1 - קâ€Ö¹x\Z
+OK 2 - קâ€Ö¹x\Z
+OK 0 - קâ€x\Z
+OK 1 - קâ€x\Z
+OK 2 - קâ€x\Z
+OK 0 - קâ€x\Z
+OK 1 - קâ€x\Z
+OK 2 - קâ€x\Z
+OK 0 - Ö¹\Z
+OK 1 - Ö¹\Z
+OK 2 - Ö¹\Z
+OK 0 - \ZÖ¹
+OK 1 - \ZÖ¹
+OK 2 - \ZÖ¹
+OK 0 - Ö¹\Z
+OK 1 - Ö¹\Z
+OK 2 - Ö¹\Z
+OK 0 - \ZÖ¹
+OK 1 - \ZÖ¹
+OK 2 - \ZÖ¹
+OK 0 - Ö¹\+\Z
+OK 2 - Ö¹\+\Z
+OK 0 - \ZÖ¹\+
+OK 2 - \ZÖ¹\+
+OK 0 - [^[=a=]]\+
+OK 1 - [^[=a=]]\+
+OK 2 - [^[=a=]]\+
+eng 1 ambi single: 0
+eng 1 ambi double: 0
+eng 2 ambi single: 0
+eng 2 ambi double: 0
diff --git a/src/testdir/test99.in b/src/testdir/test99.in
new file mode 100644
index 0000000..3961244
--- /dev/null
+++ b/src/testdir/test99.in
@@ -0,0 +1,69 @@
+Tests for regexp with multi-byte encoding and various magic settings.
+Test matchstr() with a count and multi-byte chars.
+See test44 for exactly the same test with re=1.
+
+STARTTEST
+:so mbyte.vim
+:set nocompatible encoding=utf-8 termencoding=latin1 viminfo+=nviminfo
+:set re=2
+/^1
+/a*b\{2}c\+/e
+x/\Md\*e\{2}f\+/e
+x:set nomagic
+/g\*h\{2}i\+/e
+x/\mj*k\{2}l\+/e
+x/\vm*n{2}o+/e
+x/\V^aa$
+x:set magic
+/\v(a)(b)\2\1\1/e
+x/\V[ab]\(\[xy]\)\1
+x:" Now search for multi-byte without composing char
+/ม
+x:" Now search for multi-byte with composing char
+/ม่
+x:" find word by change of word class
+/ã¡\<カヨ\>ã¯
+x:" Test \%u, [\u] and friends
+/\%u20ac
+x/[\u4f7f\u5929]\+
+x/\%U12345678
+x/[\U1234abcd\u1234\uabcd]
+x/\%d21879b
+x:" Test backwards search from a multi-byte char
+/x
+x?.
+x:let @w=':%s#comb[i]nations#Å“Ì„á¹£Ìm̥̄ᾱ̆Ì#g'
+:@w
+:"
+:" l Test what 7.3.192 fixed
+/^l
+:s/ \?/ /g
+:?^1?,$w! test.out
+:e! test.out
+G:put =matchstr(\"×בגד\", \".\", 0, 2) " ב
+:put =matchstr(\"×בגד\", \"..\", 0, 2) " בג
+:put =matchstr(\"×בגד\", \".\", 0, 0) " ×
+:put =matchstr(\"×בגד\", \".\", 4, -1) " ×’
+:w!
+:qa!
+ENDTEST
+
+1 a aa abb abbccc
+2 d dd dee deefff
+3 g gg ghh ghhiii
+4 j jj jkk jkklll
+5 m mm mnn mnnooo
+6 x ^aa$ x
+7 (a)(b) abbaa
+8 axx [ab]xx
+9 หม่x อมx
+a อมx หม่x
+b ã¡ã‚«ãƒ¨ã¯
+c x ¬€x
+d 天使x
+e ü’…™¸y
+f ü’Š¯z
+g aå•·bb
+j 0123â¤x
+k combinations
+l äö üᾱ̆Ì
diff --git a/src/testdir/test99.ok b/src/testdir/test99.ok
new file mode 100644
index 0000000..dea3665
--- /dev/null
+++ b/src/testdir/test99.ok
@@ -0,0 +1,23 @@
+1 a aa abb abbcc
+2 d dd dee deeff
+3 g gg ghh ghhii
+4 j jj jkk jkkll
+5 m mm mnn mnnoo
+6 x aa$ x
+7 (a)(b) abba
+8 axx ab]xx
+9 หม่x อx
+a อมx หx
+b カヨã¯
+c x ¬x
+d 使x
+e y
+f z
+g abb
+j 012â¤
+k Å“Ì„á¹£Ìm̥̄ᾱ̆Ì
+ l ä ö ü ᾱ̆Ì
+ב
+בג
+×’
diff --git a/src/testdir/test_alot.vim b/src/testdir/test_alot.vim
new file mode 100644
index 0000000..81873af
--- /dev/null
+++ b/src/testdir/test_alot.vim
@@ -0,0 +1,68 @@
+" A series of tests that can run in one Vim invocation.
+" This makes testing go faster, since Vim doesn't need to restart.
+
+source test_assign.vim
+source test_backup.vim
+source test_behave.vim
+source test_bufline.vim
+source test_cd.vim
+source test_changedtick.vim
+source test_compiler.vim
+source test_cursor_func.vim
+source test_delete.vim
+source test_ex_equal.vim
+source test_ex_undo.vim
+source test_ex_z.vim
+source test_execute_func.vim
+source test_expand.vim
+source test_expand_dllpath.vim
+source test_expand_func.vim
+source test_expr.vim
+source test_feedkeys.vim
+source test_file_perm.vim
+source test_fileformat.vim
+source test_filetype.vim
+source test_filter_cmd.vim
+source test_filter_map.vim
+source test_findfile.vim
+source test_float_func.vim
+source test_fnamemodify.vim
+source test_functions.vim
+source test_ga.vim
+source test_glob2regpat.vim
+source test_global.vim
+source test_goto.vim
+source test_help_tagjump.vim
+source test_join.vim
+source test_jumps.vim
+source test_lambda.vim
+source test_lispwords.vim
+source test_mapping.vim
+source test_match.vim
+source test_menu.vim
+source test_messages.vim
+source test_modeline.vim
+source test_move.vim
+source test_partial.vim
+source test_popup.vim
+source test_put.vim
+source test_recover.vim
+source test_reltime.vim
+source test_scroll_opt.vim
+source test_searchpos.vim
+source test_set.vim
+source test_sort.vim
+source test_sha256.vim
+source test_statusline.vim
+source test_suspend.vim
+source test_syn_attr.vim
+source test_tabline.vim
+source test_tabpage.vim
+source test_tagcase.vim
+source test_tagjump.vim
+source test_taglist.vim
+source test_timers.vim
+source test_true_false.vim
+source test_unlet.vim
+source test_virtualedit.vim
+source test_window_cmd.vim
diff --git a/src/testdir/test_alot_latin.vim b/src/testdir/test_alot_latin.vim
new file mode 100644
index 0000000..23a404c
--- /dev/null
+++ b/src/testdir/test_alot_latin.vim
@@ -0,0 +1,7 @@
+" A series of tests that can run in one Vim invocation.
+" This makes testing go faster, since Vim doesn't need to restart.
+
+" These tests use latin1 'encoding'. Setting 'encoding' is in the individual
+" files, so that they can be run by themselves.
+
+source test_regexp_latin.vim
diff --git a/src/testdir/test_alot_utf8.vim b/src/testdir/test_alot_utf8.vim
new file mode 100644
index 0000000..be0bd01
--- /dev/null
+++ b/src/testdir/test_alot_utf8.vim
@@ -0,0 +1,16 @@
+" A series of tests that can run in one Vim invocation.
+" This makes testing go faster, since Vim doesn't need to restart.
+
+" These tests use utf8 'encoding'. Setting 'encoding' is already done in
+" runtest.vim.
+
+source test_charsearch_utf8.vim
+source test_expr_utf8.vim
+source test_listlbr_utf8.vim
+source test_matchadd_conceal_utf8.vim
+source test_mksession_utf8.vim
+source test_regexp_utf8.vim
+source test_source_utf8.vim
+source test_startup_utf8.vim
+source test_utf8.vim
+source test_utf8_comparisons.vim
diff --git a/src/testdir/test_arabic.vim b/src/testdir/test_arabic.vim
new file mode 100644
index 0000000..bc31db7
--- /dev/null
+++ b/src/testdir/test_arabic.vim
@@ -0,0 +1,613 @@
+" Simplistic testing of Arabic mode.
+" NOTE: This just checks if the code works. If you know Arabic please add
+" functional tests that check the shaping works with real text.
+
+if !has('arabic')
+ finish
+endif
+
+source view_util.vim
+
+" Return list of Unicode characters at line lnum.
+" Combining characters are treated as a single item.
+func s:get_chars(lnum)
+ call cursor(a:lnum, 1)
+ let chars = []
+ let numchars = strchars(getline('.'), 1)
+ for i in range(1, numchars)
+ exe 'norm ' i . '|'
+ let c = execute('ascii')
+ let c = substitute(c, '\n\?<.\{-}Hex\s*', 'U+', 'g')
+ let c = substitute(c, ',\s*Oct\(al\)\=\s\d*\(, Digr ..\)\=', '', 'g')
+ call add(chars, c)
+ endfor
+ return chars
+endfunc
+
+func Test_arabic_toggle()
+ set arabic
+ call assert_equal(1, &rightleft)
+ call assert_equal(1, &arabicshape)
+ call assert_equal('arabic', &keymap)
+ call assert_equal(1, &delcombine)
+
+ set iminsert=1 imsearch=1
+ set arabic&
+ call assert_equal(0, &rightleft)
+ call assert_equal(1, &arabicshape)
+ call assert_equal('arabic', &keymap)
+ call assert_equal(1, &delcombine)
+ call assert_equal(0, &iminsert)
+ call assert_equal(-1, &imsearch)
+
+ set arabicshape& keymap= delcombine&
+endfunc
+
+func Test_arabic_input()
+ new
+ set arabic
+ " Typing sghl in Arabic insert mode should show the
+ " Arabic word 'Salaam' i.e. 'peace', spelled:
+ " SEEN, LAM, ALEF, MEEM.
+ " See: https://www.mediawiki.org/wiki/VisualEditor/Typing/Right-to-left
+ call feedkeys('isghl!', 'tx')
+ call assert_match("^ *!\uFEE1\uFEFC\uFEB3$", ScreenLines(1, &columns)[0])
+ call assert_equal([
+ \ 'U+0633',
+ \ 'U+0644 U+0627',
+ \ 'U+0645',
+ \ 'U+21'], s:get_chars(1))
+
+ " Without shaping, it should give individual Arabic letters.
+ set noarabicshape
+ call assert_match("^ *!\u0645\u0627\u0644\u0633$", ScreenLines(1, &columns)[0])
+ call assert_equal([
+ \ 'U+0633',
+ \ 'U+0644',
+ \ 'U+0627',
+ \ 'U+0645',
+ \ 'U+21'], s:get_chars(1))
+
+ set arabic& arabicshape&
+ bwipe!
+endfunc
+
+func Test_arabic_toggle_keymap()
+ new
+ set arabic
+ call feedkeys("i12\<C-^>12\<C-^>12", 'tx')
+ call assert_match("^ *٢١21٢١$", ScreenLines(1, &columns)[0])
+ call assert_equal('١٢12١٢', getline('.'))
+ set arabic&
+ bwipe!
+endfunc
+
+func Test_delcombine()
+ new
+ set arabic
+ call feedkeys("isghl\<BS>\<BS>", 'tx')
+ call assert_match("^ *\uFEDE\uFEB3$", ScreenLines(1, &columns)[0])
+ call assert_equal(['U+0633', 'U+0644'], s:get_chars(1))
+
+ " Now the same with 'nodelcombine'
+ set nodelcombine
+ %d
+ call feedkeys("isghl\<BS>\<BS>", 'tx')
+ call assert_match("^ *\uFEB1$", ScreenLines(1, &columns)[0])
+ call assert_equal(['U+0633'], s:get_chars(1))
+ set arabic&
+ bwipe!
+endfunc
+
+" Values from src/arabic.h (not all used yet)
+let s:a_COMMA = "\u060C"
+let s:a_SEMICOLON = "\u061B"
+let s:a_QUESTION = "\u061F"
+let s:a_HAMZA = "\u0621"
+let s:a_ALEF_MADDA = "\u0622"
+let s:a_ALEF_HAMZA_ABOVE = "\u0623"
+let s:a_WAW_HAMZA = "\u0624"
+let s:a_ALEF_HAMZA_BELOW = "\u0625"
+let s:a_YEH_HAMZA = "\u0626"
+let s:a_ALEF = "\u0627"
+let s:a_BEH = "\u0628"
+let s:a_TEH_MARBUTA = "\u0629"
+let s:a_TEH = "\u062a"
+let s:a_THEH = "\u062b"
+let s:a_JEEM = "\u062c"
+let s:a_HAH = "\u062d"
+let s:a_KHAH = "\u062e"
+let s:a_DAL = "\u062f"
+let s:a_THAL = "\u0630"
+let s:a_REH = "\u0631"
+let s:a_ZAIN = "\u0632"
+let s:a_SEEN = "\u0633"
+let s:a_SHEEN = "\u0634"
+let s:a_SAD = "\u0635"
+let s:a_DAD = "\u0636"
+let s:a_TAH = "\u0637"
+let s:a_ZAH = "\u0638"
+let s:a_AIN = "\u0639"
+let s:a_GHAIN = "\u063a"
+let s:a_TATWEEL = "\u0640"
+let s:a_FEH = "\u0641"
+let s:a_QAF = "\u0642"
+let s:a_KAF = "\u0643"
+let s:a_LAM = "\u0644"
+let s:a_MEEM = "\u0645"
+let s:a_NOON = "\u0646"
+let s:a_HEH = "\u0647"
+let s:a_WAW = "\u0648"
+let s:a_ALEF_MAKSURA = "\u0649"
+let s:a_YEH = "\u064a"
+
+let s:a_FATHATAN = "\u064b"
+let s:a_DAMMATAN = "\u064c"
+let s:a_KASRATAN = "\u064d"
+let s:a_FATHA = "\u064e"
+let s:a_DAMMA = "\u064f"
+let s:a_KASRA = "\u0650"
+let s:a_SHADDA = "\u0651"
+let s:a_SUKUN = "\u0652"
+
+let s:a_MADDA_ABOVE = "\u0653"
+let s:a_HAMZA_ABOVE = "\u0654"
+let s:a_HAMZA_BELOW = "\u0655"
+
+let s:a_ZERO = "\u0660"
+let s:a_ONE = "\u0661"
+let s:a_TWO = "\u0662"
+let s:a_THREE = "\u0663"
+let s:a_FOUR = "\u0664"
+let s:a_FIVE = "\u0665"
+let s:a_SIX = "\u0666"
+let s:a_SEVEN = "\u0667"
+let s:a_EIGHT = "\u0668"
+let s:a_NINE = "\u0669"
+let s:a_PERCENT = "\u066a"
+let s:a_DECIMAL = "\u066b"
+let s:a_THOUSANDS = "\u066c"
+let s:a_STAR = "\u066d"
+let s:a_MINI_ALEF = "\u0670"
+
+let s:a_s_FATHATAN = "\ufe70"
+let s:a_m_TATWEEL_FATHATAN = "\ufe71"
+let s:a_s_DAMMATAN = "\ufe72"
+
+let s:a_s_KASRATAN = "\ufe74"
+
+let s:a_s_FATHA = "\ufe76"
+let s:a_m_FATHA = "\ufe77"
+let s:a_s_DAMMA = "\ufe78"
+let s:a_m_DAMMA = "\ufe79"
+let s:a_s_KASRA = "\ufe7a"
+let s:a_m_KASRA = "\ufe7b"
+let s:a_s_SHADDA = "\ufe7c"
+let s:a_m_SHADDA = "\ufe7d"
+let s:a_s_SUKUN = "\ufe7e"
+let s:a_m_SUKUN = "\ufe7f"
+
+let s:a_s_HAMZA = "\ufe80"
+let s:a_s_ALEF_MADDA = "\ufe81"
+let s:a_f_ALEF_MADDA = "\ufe82"
+let s:a_s_ALEF_HAMZA_ABOVE = "\ufe83"
+let s:a_f_ALEF_HAMZA_ABOVE = "\ufe84"
+let s:a_s_WAW_HAMZA = "\ufe85"
+let s:a_f_WAW_HAMZA = "\ufe86"
+let s:a_s_ALEF_HAMZA_BELOW = "\ufe87"
+let s:a_f_ALEF_HAMZA_BELOW = "\ufe88"
+let s:a_s_YEH_HAMZA = "\ufe89"
+let s:a_f_YEH_HAMZA = "\ufe8a"
+let s:a_i_YEH_HAMZA = "\ufe8b"
+let s:a_m_YEH_HAMZA = "\ufe8c"
+let s:a_s_ALEF = "\ufe8d"
+let s:a_f_ALEF = "\ufe8e"
+let s:a_s_BEH = "\ufe8f"
+let s:a_f_BEH = "\ufe90"
+let s:a_i_BEH = "\ufe91"
+let s:a_m_BEH = "\ufe92"
+let s:a_s_TEH_MARBUTA = "\ufe93"
+let s:a_f_TEH_MARBUTA = "\ufe94"
+let s:a_s_TEH = "\ufe95"
+let s:a_f_TEH = "\ufe96"
+let s:a_i_TEH = "\ufe97"
+let s:a_m_TEH = "\ufe98"
+let s:a_s_THEH = "\ufe99"
+let s:a_f_THEH = "\ufe9a"
+let s:a_i_THEH = "\ufe9b"
+let s:a_m_THEH = "\ufe9c"
+let s:a_s_JEEM = "\ufe9d"
+let s:a_f_JEEM = "\ufe9e"
+let s:a_i_JEEM = "\ufe9f"
+let s:a_m_JEEM = "\ufea0"
+let s:a_s_HAH = "\ufea1"
+let s:a_f_HAH = "\ufea2"
+let s:a_i_HAH = "\ufea3"
+let s:a_m_HAH = "\ufea4"
+let s:a_s_KHAH = "\ufea5"
+let s:a_f_KHAH = "\ufea6"
+let s:a_i_KHAH = "\ufea7"
+let s:a_m_KHAH = "\ufea8"
+let s:a_s_DAL = "\ufea9"
+let s:a_f_DAL = "\ufeaa"
+let s:a_s_THAL = "\ufeab"
+let s:a_f_THAL = "\ufeac"
+let s:a_s_REH = "\ufead"
+let s:a_f_REH = "\ufeae"
+let s:a_s_ZAIN = "\ufeaf"
+let s:a_f_ZAIN = "\ufeb0"
+let s:a_s_SEEN = "\ufeb1"
+let s:a_f_SEEN = "\ufeb2"
+let s:a_i_SEEN = "\ufeb3"
+let s:a_m_SEEN = "\ufeb4"
+let s:a_s_SHEEN = "\ufeb5"
+let s:a_f_SHEEN = "\ufeb6"
+let s:a_i_SHEEN = "\ufeb7"
+let s:a_m_SHEEN = "\ufeb8"
+let s:a_s_SAD = "\ufeb9"
+let s:a_f_SAD = "\ufeba"
+let s:a_i_SAD = "\ufebb"
+let s:a_m_SAD = "\ufebc"
+let s:a_s_DAD = "\ufebd"
+let s:a_f_DAD = "\ufebe"
+let s:a_i_DAD = "\ufebf"
+let s:a_m_DAD = "\ufec0"
+let s:a_s_TAH = "\ufec1"
+let s:a_f_TAH = "\ufec2"
+let s:a_i_TAH = "\ufec3"
+let s:a_m_TAH = "\ufec4"
+let s:a_s_ZAH = "\ufec5"
+let s:a_f_ZAH = "\ufec6"
+let s:a_i_ZAH = "\ufec7"
+let s:a_m_ZAH = "\ufec8"
+let s:a_s_AIN = "\ufec9"
+let s:a_f_AIN = "\ufeca"
+let s:a_i_AIN = "\ufecb"
+let s:a_m_AIN = "\ufecc"
+let s:a_s_GHAIN = "\ufecd"
+let s:a_f_GHAIN = "\ufece"
+let s:a_i_GHAIN = "\ufecf"
+let s:a_m_GHAIN = "\ufed0"
+let s:a_s_FEH = "\ufed1"
+let s:a_f_FEH = "\ufed2"
+let s:a_i_FEH = "\ufed3"
+let s:a_m_FEH = "\ufed4"
+let s:a_s_QAF = "\ufed5"
+let s:a_f_QAF = "\ufed6"
+let s:a_i_QAF = "\ufed7"
+let s:a_m_QAF = "\ufed8"
+let s:a_s_KAF = "\ufed9"
+let s:a_f_KAF = "\ufeda"
+let s:a_i_KAF = "\ufedb"
+let s:a_m_KAF = "\ufedc"
+let s:a_s_LAM = "\ufedd"
+let s:a_f_LAM = "\ufede"
+let s:a_i_LAM = "\ufedf"
+let s:a_m_LAM = "\ufee0"
+let s:a_s_MEEM = "\ufee1"
+let s:a_f_MEEM = "\ufee2"
+let s:a_i_MEEM = "\ufee3"
+let s:a_m_MEEM = "\ufee4"
+let s:a_s_NOON = "\ufee5"
+let s:a_f_NOON = "\ufee6"
+let s:a_i_NOON = "\ufee7"
+let s:a_m_NOON = "\ufee8"
+let s:a_s_HEH = "\ufee9"
+let s:a_f_HEH = "\ufeea"
+let s:a_i_HEH = "\ufeeb"
+let s:a_m_HEH = "\ufeec"
+let s:a_s_WAW = "\ufeed"
+let s:a_f_WAW = "\ufeee"
+let s:a_s_ALEF_MAKSURA = "\ufeef"
+let s:a_f_ALEF_MAKSURA = "\ufef0"
+let s:a_s_YEH = "\ufef1"
+let s:a_f_YEH = "\ufef2"
+let s:a_i_YEH = "\ufef3"
+let s:a_m_YEH = "\ufef4"
+let s:a_s_LAM_ALEF_MADDA_ABOVE = "\ufef5"
+let s:a_f_LAM_ALEF_MADDA_ABOVE = "\ufef6"
+let s:a_s_LAM_ALEF_HAMZA_ABOVE = "\ufef7"
+let s:a_f_LAM_ALEF_HAMZA_ABOVE = "\ufef8"
+let s:a_s_LAM_ALEF_HAMZA_BELOW = "\ufef9"
+let s:a_f_LAM_ALEF_HAMZA_BELOW = "\ufefa"
+let s:a_s_LAM_ALEF = "\ufefb"
+let s:a_f_LAM_ALEF = "\ufefc"
+
+let s:a_BYTE_ORDER_MARK = "\ufeff"
+
+func Test_shape_initial()
+ new
+ set arabicshape
+
+ " Shaping arabic {testchar} non-arabic Tests chg_c_a2i().
+ " pair[0] = testchar, pair[1] = next-result, pair[2] = current-result
+ for pair in [[s:a_YEH_HAMZA, s:a_f_GHAIN, s:a_i_YEH_HAMZA],
+ \ [s:a_HAMZA, s:a_s_GHAIN, s:a_s_HAMZA],
+ \ [s:a_ALEF_MADDA, s:a_s_GHAIN, s:a_s_ALEF_MADDA],
+ \ [s:a_ALEF_HAMZA_ABOVE, s:a_s_GHAIN, s:a_s_ALEF_HAMZA_ABOVE],
+ \ [s:a_WAW_HAMZA, s:a_s_GHAIN, s:a_s_WAW_HAMZA],
+ \ [s:a_ALEF_HAMZA_BELOW, s:a_s_GHAIN, s:a_s_ALEF_HAMZA_BELOW],
+ \ [s:a_ALEF, s:a_s_GHAIN, s:a_s_ALEF],
+ \ [s:a_TEH_MARBUTA, s:a_s_GHAIN, s:a_s_TEH_MARBUTA],
+ \ [s:a_DAL, s:a_s_GHAIN, s:a_s_DAL],
+ \ [s:a_THAL, s:a_s_GHAIN, s:a_s_THAL],
+ \ [s:a_REH, s:a_s_GHAIN, s:a_s_REH],
+ \ [s:a_ZAIN, s:a_s_GHAIN, s:a_s_ZAIN],
+ \ [s:a_TATWEEL, s:a_f_GHAIN, s:a_TATWEEL],
+ \ [s:a_WAW, s:a_s_GHAIN, s:a_s_WAW],
+ \ [s:a_ALEF_MAKSURA, s:a_s_GHAIN, s:a_s_ALEF_MAKSURA],
+ \ [s:a_BEH, s:a_f_GHAIN, s:a_i_BEH],
+ \ [s:a_TEH, s:a_f_GHAIN, s:a_i_TEH],
+ \ [s:a_THEH, s:a_f_GHAIN, s:a_i_THEH],
+ \ [s:a_JEEM, s:a_f_GHAIN, s:a_i_JEEM],
+ \ [s:a_HAH, s:a_f_GHAIN, s:a_i_HAH],
+ \ [s:a_KHAH, s:a_f_GHAIN, s:a_i_KHAH],
+ \ [s:a_SEEN, s:a_f_GHAIN, s:a_i_SEEN],
+ \ [s:a_SHEEN, s:a_f_GHAIN, s:a_i_SHEEN],
+ \ [s:a_SAD, s:a_f_GHAIN, s:a_i_SAD],
+ \ [s:a_DAD, s:a_f_GHAIN, s:a_i_DAD],
+ \ [s:a_TAH, s:a_f_GHAIN, s:a_i_TAH],
+ \ [s:a_ZAH, s:a_f_GHAIN, s:a_i_ZAH],
+ \ [s:a_AIN, s:a_f_GHAIN, s:a_i_AIN],
+ \ [s:a_GHAIN, s:a_f_GHAIN, s:a_i_GHAIN],
+ \ [s:a_FEH, s:a_f_GHAIN, s:a_i_FEH],
+ \ [s:a_QAF, s:a_f_GHAIN, s:a_i_QAF],
+ \ [s:a_KAF, s:a_f_GHAIN, s:a_i_KAF],
+ \ [s:a_LAM, s:a_f_GHAIN, s:a_i_LAM],
+ \ [s:a_MEEM, s:a_f_GHAIN, s:a_i_MEEM],
+ \ [s:a_NOON, s:a_f_GHAIN, s:a_i_NOON],
+ \ [s:a_HEH, s:a_f_GHAIN, s:a_i_HEH],
+ \ [s:a_YEH, s:a_f_GHAIN, s:a_i_YEH],
+ \ ]
+ call setline(1, s:a_GHAIN . pair[0] . ' ')
+ call assert_equal([pair[1] . pair[2] . ' '], ScreenLines(1, 3))
+ endfor
+
+ set arabicshape&
+ bwipe!
+endfunc
+
+func Test_shape_isolated()
+ new
+ set arabicshape
+
+ " Shaping non-arabic {testchar} non-arabic Tests chg_c_a2s().
+ " pair[0] = testchar, pair[1] = current-result
+ for pair in [[s:a_HAMZA, s:a_s_HAMZA],
+ \ [s:a_ALEF_MADDA, s:a_s_ALEF_MADDA],
+ \ [s:a_ALEF_HAMZA_ABOVE, s:a_s_ALEF_HAMZA_ABOVE],
+ \ [s:a_WAW_HAMZA, s:a_s_WAW_HAMZA],
+ \ [s:a_ALEF_HAMZA_BELOW, s:a_s_ALEF_HAMZA_BELOW],
+ \ [s:a_YEH_HAMZA, s:a_s_YEH_HAMZA],
+ \ [s:a_ALEF, s:a_s_ALEF],
+ \ [s:a_TEH_MARBUTA, s:a_s_TEH_MARBUTA],
+ \ [s:a_DAL, s:a_s_DAL],
+ \ [s:a_THAL, s:a_s_THAL],
+ \ [s:a_REH, s:a_s_REH],
+ \ [s:a_ZAIN, s:a_s_ZAIN],
+ \ [s:a_TATWEEL, s:a_TATWEEL],
+ \ [s:a_WAW, s:a_s_WAW],
+ \ [s:a_ALEF_MAKSURA, s:a_s_ALEF_MAKSURA],
+ \ [s:a_BEH, s:a_s_BEH],
+ \ [s:a_TEH, s:a_s_TEH],
+ \ [s:a_THEH, s:a_s_THEH],
+ \ [s:a_JEEM, s:a_s_JEEM],
+ \ [s:a_HAH, s:a_s_HAH],
+ \ [s:a_KHAH, s:a_s_KHAH],
+ \ [s:a_SEEN, s:a_s_SEEN],
+ \ [s:a_SHEEN, s:a_s_SHEEN],
+ \ [s:a_SAD, s:a_s_SAD],
+ \ [s:a_DAD, s:a_s_DAD],
+ \ [s:a_TAH, s:a_s_TAH],
+ \ [s:a_ZAH, s:a_s_ZAH],
+ \ [s:a_AIN, s:a_s_AIN],
+ \ [s:a_GHAIN, s:a_s_GHAIN],
+ \ [s:a_FEH, s:a_s_FEH],
+ \ [s:a_QAF, s:a_s_QAF],
+ \ [s:a_KAF, s:a_s_KAF],
+ \ [s:a_LAM, s:a_s_LAM],
+ \ [s:a_MEEM, s:a_s_MEEM],
+ \ [s:a_NOON, s:a_s_NOON],
+ \ [s:a_HEH, s:a_s_HEH],
+ \ [s:a_YEH, s:a_s_YEH],
+ \ ]
+ call setline(1, ' ' . pair[0] . ' ')
+ call assert_equal([' ' . pair[1] . ' '], ScreenLines(1, 3))
+ endfor
+
+ set arabicshape&
+ bwipe!
+endfunc
+
+func Test_shape_iso_to_medial()
+ new
+ set arabicshape
+
+ " Shaping arabic {testchar} arabic Tests chg_c_a2m().
+ " pair[0] = testchar, pair[1] = next-result, pair[2] = current-result,
+ " pair[3] = previous-result
+ for pair in [[s:a_HAMZA, s:a_s_GHAIN, s:a_s_HAMZA, s:a_s_BEH],
+ \[s:a_ALEF_MADDA, s:a_s_GHAIN, s:a_f_ALEF_MADDA, s:a_i_BEH],
+ \[s:a_ALEF_HAMZA_ABOVE, s:a_s_GHAIN, s:a_f_ALEF_HAMZA_ABOVE, s:a_i_BEH],
+ \[s:a_WAW_HAMZA, s:a_s_GHAIN, s:a_f_WAW_HAMZA, s:a_i_BEH],
+ \[s:a_ALEF_HAMZA_BELOW, s:a_s_GHAIN, s:a_f_ALEF_HAMZA_BELOW, s:a_i_BEH],
+ \[s:a_YEH_HAMZA, s:a_f_GHAIN, s:a_m_YEH_HAMZA, s:a_i_BEH],
+ \[s:a_ALEF, s:a_s_GHAIN, s:a_f_ALEF, s:a_i_BEH],
+ \[s:a_BEH, s:a_f_GHAIN, s:a_m_BEH, s:a_i_BEH],
+ \[s:a_TEH_MARBUTA, s:a_s_GHAIN, s:a_f_TEH_MARBUTA, s:a_i_BEH],
+ \[s:a_TEH, s:a_f_GHAIN, s:a_m_TEH, s:a_i_BEH],
+ \[s:a_THEH, s:a_f_GHAIN, s:a_m_THEH, s:a_i_BEH],
+ \[s:a_JEEM, s:a_f_GHAIN, s:a_m_JEEM, s:a_i_BEH],
+ \[s:a_HAH, s:a_f_GHAIN, s:a_m_HAH, s:a_i_BEH],
+ \[s:a_KHAH, s:a_f_GHAIN, s:a_m_KHAH, s:a_i_BEH],
+ \[s:a_DAL, s:a_s_GHAIN, s:a_f_DAL, s:a_i_BEH],
+ \[s:a_THAL, s:a_s_GHAIN, s:a_f_THAL, s:a_i_BEH],
+ \[s:a_REH, s:a_s_GHAIN, s:a_f_REH, s:a_i_BEH],
+ \[s:a_ZAIN, s:a_s_GHAIN, s:a_f_ZAIN, s:a_i_BEH],
+ \[s:a_SEEN, s:a_f_GHAIN, s:a_m_SEEN, s:a_i_BEH],
+ \[s:a_SHEEN, s:a_f_GHAIN, s:a_m_SHEEN, s:a_i_BEH],
+ \[s:a_SAD, s:a_f_GHAIN, s:a_m_SAD, s:a_i_BEH],
+ \[s:a_DAD, s:a_f_GHAIN, s:a_m_DAD, s:a_i_BEH],
+ \[s:a_TAH, s:a_f_GHAIN, s:a_m_TAH, s:a_i_BEH],
+ \[s:a_ZAH, s:a_f_GHAIN, s:a_m_ZAH, s:a_i_BEH],
+ \[s:a_AIN, s:a_f_GHAIN, s:a_m_AIN, s:a_i_BEH],
+ \[s:a_GHAIN, s:a_f_GHAIN, s:a_m_GHAIN, s:a_i_BEH],
+ \[s:a_TATWEEL, s:a_f_GHAIN, s:a_TATWEEL, s:a_i_BEH],
+ \[s:a_FEH, s:a_f_GHAIN, s:a_m_FEH, s:a_i_BEH],
+ \[s:a_QAF, s:a_f_GHAIN, s:a_m_QAF, s:a_i_BEH],
+ \[s:a_KAF, s:a_f_GHAIN, s:a_m_KAF, s:a_i_BEH],
+ \[s:a_LAM, s:a_f_GHAIN, s:a_m_LAM, s:a_i_BEH],
+ \[s:a_MEEM, s:a_f_GHAIN, s:a_m_MEEM, s:a_i_BEH],
+ \[s:a_NOON, s:a_f_GHAIN, s:a_m_NOON, s:a_i_BEH],
+ \[s:a_HEH, s:a_f_GHAIN, s:a_m_HEH, s:a_i_BEH],
+ \[s:a_WAW, s:a_s_GHAIN, s:a_f_WAW, s:a_i_BEH],
+ \[s:a_ALEF_MAKSURA, s:a_s_GHAIN, s:a_f_ALEF_MAKSURA, s:a_i_BEH],
+ \[s:a_YEH, s:a_f_GHAIN, s:a_m_YEH, s:a_i_BEH],
+ \ ]
+ call setline(1, s:a_GHAIN . pair[0] . s:a_BEH)
+ call assert_equal([pair[1] . pair[2] . pair[3]], ScreenLines(1, 3))
+ endfor
+
+ set arabicshape&
+ bwipe!
+endfunc
+
+func Test_shape_final()
+ new
+ set arabicshape
+
+ " Shaping arabic {testchar} arabic Tests chg_c_a2f().
+ " pair[0] = testchar, pair[1] = current-result, pair[2] = previous-result
+ for pair in [[s:a_HAMZA, s:a_s_HAMZA, s:a_s_BEH],
+ \[s:a_ALEF_MADDA, s:a_f_ALEF_MADDA, s:a_i_BEH],
+ \[s:a_ALEF_HAMZA_ABOVE, s:a_f_ALEF_HAMZA_ABOVE, s:a_i_BEH],
+ \[s:a_WAW_HAMZA, s:a_f_WAW_HAMZA, s:a_i_BEH],
+ \[s:a_ALEF_HAMZA_BELOW, s:a_f_ALEF_HAMZA_BELOW, s:a_i_BEH],
+ \[s:a_YEH_HAMZA, s:a_f_YEH_HAMZA, s:a_i_BEH],
+ \[s:a_ALEF, s:a_f_ALEF, s:a_i_BEH],
+ \[s:a_BEH, s:a_f_BEH, s:a_i_BEH],
+ \[s:a_TEH_MARBUTA, s:a_f_TEH_MARBUTA, s:a_i_BEH],
+ \[s:a_TEH, s:a_f_TEH, s:a_i_BEH],
+ \[s:a_THEH, s:a_f_THEH, s:a_i_BEH],
+ \[s:a_JEEM, s:a_f_JEEM, s:a_i_BEH],
+ \[s:a_HAH, s:a_f_HAH, s:a_i_BEH],
+ \[s:a_KHAH, s:a_f_KHAH, s:a_i_BEH],
+ \[s:a_DAL, s:a_f_DAL, s:a_i_BEH],
+ \[s:a_THAL, s:a_f_THAL, s:a_i_BEH],
+ \[s:a_REH, s:a_f_REH, s:a_i_BEH],
+ \[s:a_ZAIN, s:a_f_ZAIN, s:a_i_BEH],
+ \[s:a_SEEN, s:a_f_SEEN, s:a_i_BEH],
+ \[s:a_SHEEN, s:a_f_SHEEN, s:a_i_BEH],
+ \[s:a_SAD, s:a_f_SAD, s:a_i_BEH],
+ \[s:a_DAD, s:a_f_DAD, s:a_i_BEH],
+ \[s:a_TAH, s:a_f_TAH, s:a_i_BEH],
+ \[s:a_ZAH, s:a_f_ZAH, s:a_i_BEH],
+ \[s:a_AIN, s:a_f_AIN, s:a_i_BEH],
+ \[s:a_GHAIN, s:a_f_GHAIN, s:a_i_BEH],
+ \[s:a_TATWEEL, s:a_TATWEEL, s:a_i_BEH],
+ \[s:a_FEH, s:a_f_FEH, s:a_i_BEH],
+ \[s:a_QAF, s:a_f_QAF, s:a_i_BEH],
+ \[s:a_KAF, s:a_f_KAF, s:a_i_BEH],
+ \[s:a_LAM, s:a_f_LAM, s:a_i_BEH],
+ \[s:a_MEEM, s:a_f_MEEM, s:a_i_BEH],
+ \[s:a_NOON, s:a_f_NOON, s:a_i_BEH],
+ \[s:a_HEH, s:a_f_HEH, s:a_i_BEH],
+ \[s:a_WAW, s:a_f_WAW, s:a_i_BEH],
+ \[s:a_ALEF_MAKSURA, s:a_f_ALEF_MAKSURA, s:a_i_BEH],
+ \[s:a_YEH, s:a_f_YEH, s:a_i_BEH],
+ \ ]
+ call setline(1, ' ' . pair[0] . s:a_BEH)
+ call assert_equal([' ' . pair[1] . pair[2]], ScreenLines(1, 3))
+ endfor
+
+ set arabicshape&
+ bwipe!
+endfunc
+
+func Test_shape_final_to_medial()
+ new
+ set arabicshape
+
+ " Shaping arabic {testchar} arabic Tests chg_c_f2m().
+ " This does not test much...
+ " pair[0] = testchar, pair[1] = current-result
+ for pair in [[s:a_f_YEH_HAMZA, s:a_f_BEH],
+ \[s:a_f_WAW_HAMZA, s:a_s_BEH],
+ \[s:a_f_ALEF, s:a_s_BEH],
+ \[s:a_f_TEH_MARBUTA, s:a_s_BEH],
+ \[s:a_f_DAL, s:a_s_BEH],
+ \[s:a_f_THAL, s:a_s_BEH],
+ \[s:a_f_REH, s:a_s_BEH],
+ \[s:a_f_ZAIN, s:a_s_BEH],
+ \[s:a_f_WAW, s:a_s_BEH],
+ \[s:a_f_ALEF_MAKSURA, s:a_s_BEH],
+ \[s:a_f_BEH, s:a_f_BEH],
+ \[s:a_f_TEH, s:a_f_BEH],
+ \[s:a_f_THEH, s:a_f_BEH],
+ \[s:a_f_JEEM, s:a_f_BEH],
+ \[s:a_f_HAH, s:a_f_BEH],
+ \[s:a_f_KHAH, s:a_f_BEH],
+ \[s:a_f_SEEN, s:a_f_BEH],
+ \[s:a_f_SHEEN, s:a_f_BEH],
+ \[s:a_f_SAD, s:a_f_BEH],
+ \[s:a_f_DAD, s:a_f_BEH],
+ \[s:a_f_TAH, s:a_f_BEH],
+ \[s:a_f_ZAH, s:a_f_BEH],
+ \[s:a_f_AIN, s:a_f_BEH],
+ \[s:a_f_GHAIN, s:a_f_BEH],
+ \[s:a_f_FEH, s:a_f_BEH],
+ \[s:a_f_QAF, s:a_f_BEH],
+ \[s:a_f_KAF, s:a_f_BEH],
+ \[s:a_f_LAM, s:a_f_BEH],
+ \[s:a_f_MEEM, s:a_f_BEH],
+ \[s:a_f_NOON, s:a_f_BEH],
+ \[s:a_f_HEH, s:a_f_BEH],
+ \[s:a_f_YEH, s:a_f_BEH],
+ \ ]
+ call setline(1, ' ' . s:a_BEH . pair[0])
+ call assert_equal([' ' . pair[1] . pair[0]], ScreenLines(1, 3))
+ endfor
+
+ set arabicshape&
+ bwipe!
+endfunc
+
+func Test_shape_combination_final()
+ new
+ set arabicshape
+
+ " Shaping arabic {testchar} arabic Tests chg_c_laa2f().
+ " pair[0] = testchar, pair[1] = current-result
+ for pair in [[s:a_ALEF_MADDA, s:a_f_LAM_ALEF_MADDA_ABOVE],
+ \ [s:a_ALEF_HAMZA_ABOVE, s:a_f_LAM_ALEF_HAMZA_ABOVE],
+ \ [s:a_ALEF_HAMZA_BELOW, s:a_f_LAM_ALEF_HAMZA_BELOW],
+ \ [s:a_ALEF, s:a_f_LAM_ALEF],
+ \ ]
+ " The test char is a composing char, put on s:a_LAM.
+ call setline(1, ' ' . s:a_LAM . pair[0] . s:a_BEH)
+ call assert_equal([' ' . pair[1] . s:a_i_BEH], ScreenLines(1, 3))
+ endfor
+
+ set arabicshape&
+ bwipe!
+endfunc
+
+func Test_shape_combination_isolated()
+ new
+ set arabicshape
+
+ " Shaping arabic {testchar} arabic Tests chg_c_laa2i().
+ " pair[0] = testchar, pair[1] = current-result
+ for pair in [[s:a_ALEF_MADDA, s:a_s_LAM_ALEF_MADDA_ABOVE],
+ \ [s:a_ALEF_HAMZA_ABOVE, s:a_s_LAM_ALEF_HAMZA_ABOVE],
+ \ [s:a_ALEF_HAMZA_BELOW, s:a_s_LAM_ALEF_HAMZA_BELOW],
+ \ [s:a_ALEF, s:a_s_LAM_ALEF],
+ \ ]
+ " The test char is a composing char, put on s:a_LAM.
+ call setline(1, ' ' . s:a_LAM . pair[0] . ' ')
+ call assert_equal([' ' . pair[1] . ' '], ScreenLines(1, 3))
+ endfor
+
+ set arabicshape&
+ bwipe!
+endfunc
diff --git a/src/testdir/test_arglist.vim b/src/testdir/test_arglist.vim
new file mode 100644
index 0000000..ad44a85
--- /dev/null
+++ b/src/testdir/test_arglist.vim
@@ -0,0 +1,482 @@
+" Test argument list commands
+
+func Test_argidx()
+ args a b c
+ last
+ call assert_equal(2, argidx())
+ %argdelete
+ call assert_equal(0, argidx())
+ " doing it again doesn't result in an error
+ %argdelete
+ call assert_equal(0, argidx())
+ call assert_fails('2argdelete', 'E16:')
+
+ args a b c
+ call assert_equal(0, argidx())
+ next
+ call assert_equal(1, argidx())
+ next
+ call assert_equal(2, argidx())
+ 1argdelete
+ call assert_equal(1, argidx())
+ 1argdelete
+ call assert_equal(0, argidx())
+ 1argdelete
+ call assert_equal(0, argidx())
+endfunc
+
+func Test_argadd()
+ %argdelete
+ argadd a b c
+ call assert_equal(0, argidx())
+
+ %argdelete
+ argadd a
+ call assert_equal(0, argidx())
+ argadd b c d
+ call assert_equal(0, argidx())
+
+ call Init_abc()
+ argadd x
+ call Assert_argc(['a', 'b', 'x', 'c'])
+ call assert_equal(1, argidx())
+
+ call Init_abc()
+ 0argadd x
+ call Assert_argc(['x', 'a', 'b', 'c'])
+ call assert_equal(2, argidx())
+
+ call Init_abc()
+ 1argadd x
+ call Assert_argc(['a', 'x', 'b', 'c'])
+ call assert_equal(2, argidx())
+
+ call Init_abc()
+ $argadd x
+ call Assert_argc(['a', 'b', 'c', 'x'])
+ call assert_equal(1, argidx())
+
+ call Init_abc()
+ $argadd x
+ +2argadd y
+ call Assert_argc(['a', 'b', 'c', 'x', 'y'])
+ call assert_equal(1, argidx())
+
+ %argd
+ edit d
+ arga
+ call assert_equal(1, len(argv()))
+ call assert_equal('d', get(argv(), 0, ''))
+
+ %argd
+ edit some\ file
+ arga
+ call assert_equal(1, len(argv()))
+ call assert_equal('some file', get(argv(), 0, ''))
+
+ %argd
+ new
+ arga
+ call assert_equal(0, len(argv()))
+endfunc
+
+func Test_argadd_empty_curbuf()
+ new
+ let curbuf = bufnr('%')
+ call writefile(['test', 'Xargadd'], 'Xargadd')
+ " must not re-use the current buffer.
+ argadd Xargadd
+ call assert_equal(curbuf, bufnr('%'))
+ call assert_equal('', bufname('%'))
+ call assert_equal(1, line('$'))
+ rew
+ call assert_notequal(curbuf, bufnr('%'))
+ call assert_equal('Xargadd', bufname('%'))
+ call assert_equal(2, line('$'))
+
+ call delete('Xargadd')
+ %argd
+ bwipe!
+endfunc
+
+func Init_abc()
+ args a b c
+ next
+endfunc
+
+func Assert_argc(l)
+ call assert_equal(len(a:l), argc())
+ let i = 0
+ while i < len(a:l) && i < argc()
+ call assert_equal(a:l[i], argv(i))
+ let i += 1
+ endwhile
+endfunc
+
+" Test for [count]argument and [count]argdelete commands
+" Ported from the test_argument_count.in test script
+func Test_argument()
+ " Clean the argument list
+ arga a | %argd
+
+ let save_hidden = &hidden
+ set hidden
+
+ let g:buffers = []
+ augroup TEST
+ au BufEnter * call add(buffers, expand('%:t'))
+ augroup END
+
+ argadd a b c d
+ $argu
+ $-argu
+ -argu
+ 1argu
+ +2argu
+
+ augroup TEST
+ au!
+ augroup END
+
+ call assert_equal(['d', 'c', 'b', 'a', 'c'], g:buffers)
+
+ redir => result
+ args
+ redir END
+ call assert_equal('a b [c] d', trim(result))
+
+ .argd
+ call assert_equal(['a', 'b', 'd'], argv())
+
+ -argd
+ call assert_equal(['a', 'd'], argv())
+
+ $argd
+ call assert_equal(['a'], argv())
+
+ 1arga c
+ 1arga b
+ $argu
+ $arga x
+ call assert_equal(['a', 'b', 'c', 'x'], argv())
+
+ 0arga y
+ call assert_equal(['y', 'a', 'b', 'c', 'x'], argv())
+
+ %argd
+ call assert_equal([], argv())
+
+ arga a b c d e f
+ 2,$-argd
+ call assert_equal(['a', 'f'], argv())
+
+ let &hidden = save_hidden
+
+ " Setting argument list should fail when the current buffer has unsaved
+ " changes
+ %argd
+ enew!
+ set modified
+ call assert_fails('args x y z', 'E37:')
+ args! x y z
+ call assert_equal(['x', 'y', 'z'], argv())
+ call assert_equal('x', expand('%:t'))
+
+ last | enew | argu
+ call assert_equal('z', expand('%:t'))
+
+ %argdelete
+ call assert_fails('argument', 'E163:')
+endfunc
+
+func Test_list_arguments()
+ " Clean the argument list
+ arga a | %argd
+
+ " four args half the screen width makes two lines with two columns
+ let aarg = repeat('a', &columns / 2 - 4)
+ let barg = repeat('b', &columns / 2 - 4)
+ let carg = repeat('c', &columns / 2 - 4)
+ let darg = repeat('d', &columns / 2 - 4)
+ exe 'argadd ' aarg barg carg darg
+
+ redir => result
+ args
+ redir END
+ call assert_match('\[' . aarg . '] \+' . carg . '\n' . barg . ' \+' . darg, trim(result))
+
+ " if one arg is longer than half the screen make one column
+ exe 'argdel' aarg
+ let aarg = repeat('a', &columns / 2 + 2)
+ exe '0argadd' aarg
+ redir => result
+ args
+ redir END
+ call assert_match(aarg . '\n\[' . barg . ']\n' . carg . '\n' . darg, trim(result))
+
+ %argdelete
+endfunc
+
+func Test_args_with_quote()
+ " Only on Unix can a file name include a double quote.
+ if has('unix')
+ args \"foobar
+ call assert_equal('"foobar', argv(0))
+ %argdelete
+ endif
+endfunc
+
+" Test for 0argadd and 0argedit
+" Ported from the test_argument_0count.in test script
+func Test_zero_argadd()
+ " Clean the argument list
+ arga a | %argd
+
+ arga a b c d
+ 2argu
+ 0arga added
+ call assert_equal(['added', 'a', 'b', 'c', 'd'], argv())
+
+ 2argu
+ arga third
+ call assert_equal(['added', 'a', 'third', 'b', 'c', 'd'], argv())
+
+ %argd
+ arga a b c d
+ 2argu
+ 0arge edited
+ call assert_equal(['edited', 'a', 'b', 'c', 'd'], argv())
+
+ 2argu
+ arga third
+ call assert_equal(['edited', 'a', 'third', 'b', 'c', 'd'], argv())
+
+ 2argu
+ argedit file\ with\ spaces another file
+ call assert_equal(['edited', 'a', 'file with spaces', 'another', 'file', 'third', 'b', 'c', 'd'], argv())
+ call assert_equal('file with spaces', expand('%'))
+endfunc
+
+func Reset_arglist()
+ args a | %argd
+endfunc
+
+" Test for argc()
+func Test_argc()
+ call Reset_arglist()
+ call assert_equal(0, argc())
+ argadd a b
+ call assert_equal(2, argc())
+endfunc
+
+" Test for arglistid()
+func Test_arglistid()
+ call Reset_arglist()
+ arga a b
+ call assert_equal(0, arglistid())
+ split
+ arglocal
+ call assert_equal(1, arglistid())
+ tabnew | tabfirst
+ call assert_equal(0, arglistid(2))
+ call assert_equal(1, arglistid(1, 1))
+ call assert_equal(0, arglistid(2, 1))
+ call assert_equal(1, arglistid(1, 2))
+ tabonly | only | enew!
+ argglobal
+ call assert_equal(0, arglistid())
+endfunc
+
+" Tests for argv() and argc()
+func Test_argv()
+ call Reset_arglist()
+ call assert_equal([], argv())
+ call assert_equal("", argv(2))
+ call assert_equal(0, argc())
+ argadd a b c d
+ call assert_equal(4, argc())
+ call assert_equal('c', argv(2))
+
+ let w1_id = win_getid()
+ split
+ let w2_id = win_getid()
+ arglocal
+ args e f g
+ tabnew
+ let w3_id = win_getid()
+ split
+ let w4_id = win_getid()
+ argglobal
+ tabfirst
+ call assert_equal(4, argc(w1_id))
+ call assert_equal('b', argv(1, w1_id))
+ call assert_equal(['a', 'b', 'c', 'd'], argv(-1, w1_id))
+
+ call assert_equal(3, argc(w2_id))
+ call assert_equal('f', argv(1, w2_id))
+ call assert_equal(['e', 'f', 'g'], argv(-1, w2_id))
+
+ call assert_equal(3, argc(w3_id))
+ call assert_equal('e', argv(0, w3_id))
+ call assert_equal(['e', 'f', 'g'], argv(-1, w3_id))
+
+ call assert_equal(4, argc(w4_id))
+ call assert_equal('c', argv(2, w4_id))
+ call assert_equal(['a', 'b', 'c', 'd'], argv(-1, w4_id))
+
+ call assert_equal(4, argc(-1))
+ call assert_equal(3, argc())
+ call assert_equal('d', argv(3, -1))
+ call assert_equal(['a', 'b', 'c', 'd'], argv(-1, -1))
+ tabonly | only | enew!
+ " Negative test cases
+ call assert_equal(-1, argc(100))
+ call assert_equal('', argv(1, 100))
+ call assert_equal([], argv(-1, 100))
+ call assert_equal('', argv(10, -1))
+endfunc
+
+" Test for the :argedit command
+func Test_argedit()
+ call Reset_arglist()
+ argedit a
+ call assert_equal(['a'], argv())
+ call assert_equal('a', expand('%:t'))
+ argedit b
+ call assert_equal(['a', 'b'], argv())
+ call assert_equal('b', expand('%:t'))
+ argedit a
+ call assert_equal(['a', 'b', 'a'], argv())
+ call assert_equal('a', expand('%:t'))
+ " When file name case is ignored, an existing buffer with only case
+ " difference is re-used.
+ argedit C D
+ call assert_equal('C', expand('%:t'))
+ call assert_equal(['a', 'b', 'a', 'C', 'D'], argv())
+ argedit c
+ if has('fname_case')
+ call assert_equal(['a', 'b', 'a', 'C', 'c', 'D'], argv())
+ else
+ call assert_equal(['a', 'b', 'a', 'C', 'C', 'D'], argv())
+ endif
+ 0argedit x
+ if has('fname_case')
+ call assert_equal(['x', 'a', 'b', 'a', 'C', 'c', 'D'], argv())
+ else
+ call assert_equal(['x', 'a', 'b', 'a', 'C', 'C', 'D'], argv())
+ endif
+ enew! | set modified
+ call assert_fails('argedit y', 'E37:')
+ argedit! y
+ if has('fname_case')
+ call assert_equal(['x', 'y', 'y', 'a', 'b', 'a', 'C', 'c', 'D'], argv())
+ else
+ call assert_equal(['x', 'y', 'y', 'a', 'b', 'a', 'C', 'C', 'D'], argv())
+ endif
+ %argd
+ bwipe! C
+ bwipe! D
+
+ " :argedit reuses the current buffer if it is empty
+ %argd
+ " make sure to use a new buffer number for x when it is loaded
+ bw! x
+ new
+ let a = bufnr('')
+ argedit x
+ call assert_equal(a, bufnr(''))
+ call assert_equal('x', bufname(''))
+ %argd
+ bw! x
+endfunc
+
+" Test for the :argdelete command
+func Test_argdelete()
+ call Reset_arglist()
+ args aa a aaa b bb
+ argdelete a*
+ call assert_equal(['b', 'bb'], argv())
+ call assert_equal('aa', expand('%:t'))
+ last
+ argdelete %
+ call assert_equal(['b'], argv())
+ call assert_fails('argdelete', 'E471:')
+ call assert_fails('1,100argdelete', 'E16:')
+ %argd
+endfunc
+
+func Test_argdelete_completion()
+ args foo bar
+
+ call feedkeys(":argdelete \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"argdelete bar foo', @:)
+
+ call feedkeys(":argdelete x \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"argdelete x bar foo', @:)
+
+ %argd
+endfunc
+
+" Tests for the :next, :prev, :first, :last, :rewind commands
+func Test_argpos()
+ call Reset_arglist()
+ args a b c d
+ last
+ call assert_equal(3, argidx())
+ call assert_fails('next', 'E165:')
+ prev
+ call assert_equal(2, argidx())
+ Next
+ call assert_equal(1, argidx())
+ first
+ call assert_equal(0, argidx())
+ call assert_fails('prev', 'E164:')
+ 3next
+ call assert_equal(3, argidx())
+ rewind
+ call assert_equal(0, argidx())
+ %argd
+endfunc
+
+" Test for autocommand that redefines the argument list, when doing ":all".
+func Test_arglist_autocmd()
+ autocmd BufReadPost Xxx2 next Xxx2 Xxx1
+ call writefile(['test file Xxx1'], 'Xxx1')
+ call writefile(['test file Xxx2'], 'Xxx2')
+ call writefile(['test file Xxx3'], 'Xxx3')
+
+ new
+ " redefine arglist; go to Xxx1
+ next! Xxx1 Xxx2 Xxx3
+ " open window for all args
+ all
+ call assert_equal('test file Xxx1', getline(1))
+ wincmd w
+ wincmd w
+ call assert_equal('test file Xxx1', getline(1))
+ " should now be in Xxx2
+ rewind
+ call assert_equal('test file Xxx2', getline(1))
+
+ autocmd! BufReadPost Xxx2
+ enew! | only
+ call delete('Xxx1')
+ call delete('Xxx2')
+ call delete('Xxx3')
+ argdelete Xxx*
+ bwipe! Xxx1 Xxx2 Xxx3
+endfunc
+
+func Test_arg_all_expand()
+ call writefile(['test file Xxx1'], 'Xx x')
+ next notexist Xx\ x runtest.vim
+ call assert_equal('notexist Xx\ x runtest.vim', expand('##'))
+ call delete('Xx x')
+endfunc
+
+func Test_large_arg()
+ " Argument longer or equal to the number of columns used to cause
+ " access to invalid memory.
+ exe 'argadd ' .repeat('x', &columns)
+ args
+endfunc
diff --git a/src/testdir/test_assert.vim b/src/testdir/test_assert.vim
new file mode 100644
index 0000000..298a6db
--- /dev/null
+++ b/src/testdir/test_assert.vim
@@ -0,0 +1,218 @@
+" Test that the methods used for testing work.
+
+func Test_assert_false()
+ call assert_equal(0, assert_false(0))
+ call assert_equal(0, assert_false(v:false))
+
+ call assert_equal(1, assert_false(123))
+ call assert_match("Expected False but got 123", v:errors[0])
+ call remove(v:errors, 0)
+endfunc
+
+func Test_assert_true()
+ call assert_equal(0, assert_true(1))
+ call assert_equal(0, assert_true(123))
+ call assert_equal(0, assert_true(v:true))
+
+ call assert_equal(1, assert_true(0))
+ call assert_match("Expected True but got 0", v:errors[0])
+ call remove(v:errors, 0)
+endfunc
+
+func Test_assert_equal()
+ let s = 'foo'
+ call assert_equal(0, assert_equal('foo', s))
+ let n = 4
+ call assert_equal(0, assert_equal(4, n))
+ let l = [1, 2, 3]
+ call assert_equal(0, assert_equal([1, 2, 3], l))
+
+ let s = 'foo'
+ call assert_equal(1, assert_equal('bar', s))
+ call assert_match("Expected 'bar' but got 'foo'", v:errors[0])
+ call remove(v:errors, 0)
+
+ call assert_equal('XxxxxxxxxxxxxxxxxxxxxxX', 'XyyyyyyyyyyyyyyyyyyyyyyyyyX')
+ call assert_match("Expected 'X\\\\\\[x occurs 21 times]X' but got 'X\\\\\\[y occurs 25 times]X'", v:errors[0])
+ call remove(v:errors, 0)
+endfunc
+
+func Test_assert_equalfile()
+ call assert_equal(1, assert_equalfile('abcabc', 'xyzxyz'))
+ call assert_match("E485: Can't read file abcabc", v:errors[0])
+ call remove(v:errors, 0)
+
+ let goodtext = ["one", "two", "three"]
+ call writefile(goodtext, 'Xone')
+ call assert_equal(1, assert_equalfile('Xone', 'xyzxyz'))
+ call assert_match("E485: Can't read file xyzxyz", v:errors[0])
+ call remove(v:errors, 0)
+
+ call writefile(goodtext, 'Xtwo')
+ call assert_equal(0, assert_equalfile('Xone', 'Xtwo'))
+
+ call writefile([goodtext[0]], 'Xone')
+ call assert_equal(1, assert_equalfile('Xone', 'Xtwo'))
+ call assert_match("first file is shorter", v:errors[0])
+ call remove(v:errors, 0)
+
+ call writefile(goodtext, 'Xone')
+ call writefile([goodtext[0]], 'Xtwo')
+ call assert_equal(1, assert_equalfile('Xone', 'Xtwo'))
+ call assert_match("second file is shorter", v:errors[0])
+ call remove(v:errors, 0)
+
+ call writefile(['1234X89'], 'Xone')
+ call writefile(['1234Y89'], 'Xtwo')
+ call assert_equal(1, assert_equalfile('Xone', 'Xtwo'))
+ call assert_match("difference at byte 4", v:errors[0])
+ call remove(v:errors, 0)
+
+ call delete('Xone')
+ call delete('Xtwo')
+endfunc
+
+func Test_assert_notequal()
+ let n = 4
+ call assert_equal(0, assert_notequal('foo', n))
+ let s = 'foo'
+ call assert_equal(0, assert_notequal([1, 2, 3], s))
+
+ call assert_equal(1, assert_notequal('foo', s))
+ call assert_match("Expected not equal to 'foo'", v:errors[0])
+ call remove(v:errors, 0)
+endfunc
+
+func Test_assert_report()
+ call assert_equal(1, assert_report('something is wrong'))
+ call assert_match('something is wrong', v:errors[0])
+ call remove(v:errors, 0)
+endfunc
+
+func Test_assert_exception()
+ try
+ nocommand
+ catch
+ call assert_equal(0, assert_exception('E492:'))
+ endtry
+
+ try
+ nocommand
+ catch
+ try
+ " illegal argument, get NULL for error
+ call assert_equal(1, assert_exception([]))
+ catch
+ call assert_equal(0, assert_exception('E730:'))
+ endtry
+ endtry
+endfunc
+
+func Test_wrong_error_type()
+ let save_verrors = v:errors
+ let v:['errors'] = {'foo': 3}
+ call assert_equal('yes', 'no')
+ let verrors = v:errors
+ let v:errors = save_verrors
+ call assert_equal(type([]), type(verrors))
+endfunc
+
+func Test_compare_fail()
+ let s:v = {}
+ let s:x = {"a": s:v}
+ let s:v["b"] = s:x
+ let s:w = {"c": s:x, "d": ''}
+ try
+ call assert_equal(s:w, '')
+ catch
+ call assert_equal(0, assert_exception('E724:'))
+ call assert_match("Expected NULL but got ''", v:errors[0])
+ call remove(v:errors, 0)
+ endtry
+endfunc
+
+func Test_match()
+ call assert_equal(0, assert_match('^f.*b.*r$', 'foobar'))
+
+ call assert_equal(1, assert_match('bar.*foo', 'foobar'))
+ call assert_match("Pattern 'bar.*foo' does not match 'foobar'", v:errors[0])
+ call remove(v:errors, 0)
+
+ call assert_equal(1, assert_match('bar.*foo', 'foobar', 'wrong'))
+ call assert_match('wrong', v:errors[0])
+ call remove(v:errors, 0)
+endfunc
+
+func Test_notmatch()
+ call assert_equal(0, assert_notmatch('foo', 'bar'))
+ call assert_equal(0, assert_notmatch('^foobar$', 'foobars'))
+
+ call assert_equal(1, assert_notmatch('foo', 'foobar'))
+ call assert_match("Pattern 'foo' does match 'foobar'", v:errors[0])
+ call remove(v:errors, 0)
+endfunc
+
+func Test_assert_fail_fails()
+ call assert_equal(1, assert_fails('xxx', {}))
+ call assert_match("Expected {} but got 'E731:", v:errors[0])
+ call remove(v:errors, 0)
+
+ call assert_equal(1, assert_fails('xxx', {}, 'stupid'))
+ call assert_match("stupid: Expected {} but got 'E731:", v:errors[0])
+ call remove(v:errors, 0)
+
+ call assert_equal(1, assert_fails('echo', '', 'echo command'))
+ call assert_match("command did not fail: echo command", v:errors[0])
+ call remove(v:errors, 0)
+endfunc
+
+func Test_assert_beeps()
+ new
+ call assert_equal(0, assert_beeps('normal h'))
+
+ call assert_equal(1, assert_beeps('normal 0'))
+ call assert_match("command did not beep: normal 0", v:errors[0])
+ call remove(v:errors, 0)
+ bwipe
+endfunc
+
+func Test_assert_inrange()
+ call assert_equal(0, assert_inrange(7, 7, 7))
+ call assert_equal(0, assert_inrange(5, 7, 5))
+ call assert_equal(0, assert_inrange(5, 7, 6))
+ call assert_equal(0, assert_inrange(5, 7, 7))
+
+ call assert_equal(1, assert_inrange(5, 7, 4))
+ call assert_match("Expected range 5 - 7, but got 4", v:errors[0])
+ call remove(v:errors, 0)
+ call assert_equal(1, assert_inrange(5, 7, 8))
+ call assert_match("Expected range 5 - 7, but got 8", v:errors[0])
+ call remove(v:errors, 0)
+
+ call assert_fails('call assert_inrange(1, 1)', 'E119:')
+endfunc
+
+func Test_assert_with_msg()
+ call assert_equal('foo', 'bar', 'testing')
+ call assert_match("testing: Expected 'foo' but got 'bar'", v:errors[0])
+ call remove(v:errors, 0)
+endfunc
+
+func Test_override()
+ call test_override('char_avail', 1)
+ call test_override('redraw', 1)
+ call test_override('ALL', 0)
+ call assert_fails("call test_override('xxx', 1)", 'E475')
+ call assert_fails("call test_override('redraw', 'yes')", 'E474')
+endfunc
+
+func Test_user_is_happy()
+ smile
+ sleep 300m
+endfunc
+
+" Must be last.
+func Test_zz_quit_detected()
+ " Verify that if a test function ends Vim the test script detects this.
+ quit
+endfunc
diff --git a/src/testdir/test_assign.vim b/src/testdir/test_assign.vim
new file mode 100644
index 0000000..1715a3f
--- /dev/null
+++ b/src/testdir/test_assign.vim
@@ -0,0 +1,53 @@
+" Test for assignment
+
+func Test_no_type_checking()
+ let v = 1
+ let v = [1,2,3]
+ let v = {'a': 1, 'b': 2}
+ let v = 3.4
+ let v = 'hello'
+endfunc
+
+func Test_let_termcap()
+ " Terminal code
+ let old_t_te = &t_te
+ let &t_te = "\<Esc>[yes;"
+ call assert_match('t_te.*^[[yes;', execute("set termcap"))
+ let &t_te = old_t_te
+
+ if exists("+t_k1")
+ " Key code
+ let old_t_k1 = &t_k1
+ let &t_k1 = "that"
+ call assert_match('t_k1.*that', execute("set termcap"))
+ let &t_k1 = old_t_k1
+ endif
+
+ call assert_fails('let x = &t_xx', 'E113')
+ let &t_xx = "yes"
+ call assert_equal("yes", &t_xx)
+ let &t_xx = ""
+ call assert_fails('let x = &t_xx', 'E113')
+endfunc
+
+func Test_let_option_error()
+ let _w = &tw
+ let &tw = 80
+ call assert_fails('let &tw .= 1', 'E734')
+ call assert_equal(80, &tw)
+ let &tw = _w
+
+ let _w = &fillchars
+ let &fillchars = "vert:|"
+ call assert_fails('let &fillchars += "diff:-"', 'E734')
+ call assert_equal("vert:|", &fillchars)
+ let &fillchars = _w
+endfunc
+
+func Test_let_errors()
+ let s = 'abcd'
+ call assert_fails('let s[1] = 5', 'E689:')
+
+ let l = [1, 2, 3]
+ call assert_fails('let l[:] = 5', 'E709:')
+endfunc
diff --git a/src/testdir/test_autochdir.vim b/src/testdir/test_autochdir.vim
new file mode 100644
index 0000000..90538fb
--- /dev/null
+++ b/src/testdir/test_autochdir.vim
@@ -0,0 +1,27 @@
+" Test 'autochdir' behavior
+
+if !exists("+autochdir")
+ finish
+endif
+
+func Test_set_filename()
+ let cwd = getcwd()
+ call test_autochdir()
+ set acd
+
+ let s:li = []
+ autocmd DirChanged auto call add(s:li, "autocd")
+ autocmd DirChanged auto call add(s:li, expand("<afile>"))
+
+ new
+ w samples/Xtest
+ call assert_equal("Xtest", expand('%'))
+ call assert_equal("samples", substitute(getcwd(), '.*/\(\k*\)', '\1', ''))
+ call assert_equal(["autocd", getcwd()], s:li)
+
+ bwipe!
+ au! DirChanged
+ set noacd
+ exe 'cd ' . cwd
+ call delete('samples/Xtest')
+endfunc
diff --git a/src/testdir/test_autocmd.vim b/src/testdir/test_autocmd.vim
new file mode 100644
index 0000000..71df515
--- /dev/null
+++ b/src/testdir/test_autocmd.vim
@@ -0,0 +1,1418 @@
+" Tests for autocommands
+
+source shared.vim
+
+func s:cleanup_buffers() abort
+ for bnr in range(1, bufnr('$'))
+ if bufloaded(bnr) && bufnr('%') != bnr
+ execute 'bd! ' . bnr
+ endif
+ endfor
+endfunc
+
+func Test_vim_did_enter()
+ call assert_false(v:vim_did_enter)
+
+ " This script will never reach the main loop, can't check if v:vim_did_enter
+ " becomes one.
+endfunc
+
+if has('timers')
+ func ExitInsertMode(id)
+ call feedkeys("\<Esc>")
+ endfunc
+
+ func Test_cursorhold_insert()
+ " Need to move the cursor.
+ call feedkeys("ggG", "xt")
+
+ let g:triggered = 0
+ au CursorHoldI * let g:triggered += 1
+ set updatetime=20
+ call timer_start(100, 'ExitInsertMode')
+ call feedkeys('a', 'x!')
+ call assert_equal(1, g:triggered)
+ unlet g:triggered
+ au! CursorHoldI
+ set updatetime&
+ endfunc
+
+ func Test_cursorhold_insert_with_timer_interrupt()
+ if !has('job')
+ return
+ endif
+ " Need to move the cursor.
+ call feedkeys("ggG", "xt")
+
+ " Confirm the timer invoked in exit_cb of the job doesn't disturb
+ " CursorHoldI event.
+ let g:triggered = 0
+ au CursorHoldI * let g:triggered += 1
+ set updatetime=500
+ call job_start(has('win32') ? 'cmd /c echo:' : 'echo',
+ \ {'exit_cb': {-> timer_start(1000, 'ExitInsertMode')}})
+ call feedkeys('a', 'x!')
+ call assert_equal(1, g:triggered)
+ unlet g:triggered
+ au! CursorHoldI
+ set updatetime&
+ endfunc
+
+ func Test_cursorhold_insert_ctrl_x()
+ let g:triggered = 0
+ au CursorHoldI * let g:triggered += 1
+ set updatetime=20
+ call timer_start(100, 'ExitInsertMode')
+ " CursorHoldI does not trigger after CTRL-X
+ call feedkeys("a\<C-X>", 'x!')
+ call assert_equal(0, g:triggered)
+ unlet g:triggered
+ au! CursorHoldI
+ set updatetime&
+ endfunc
+endif
+
+func Test_bufunload()
+ augroup test_bufunload_group
+ autocmd!
+ autocmd BufUnload * call add(s:li, "bufunload")
+ autocmd BufDelete * call add(s:li, "bufdelete")
+ autocmd BufWipeout * call add(s:li, "bufwipeout")
+ augroup END
+
+ let s:li=[]
+ new
+ setlocal bufhidden=
+ bunload
+ call assert_equal(["bufunload", "bufdelete"], s:li)
+
+ let s:li=[]
+ new
+ setlocal bufhidden=delete
+ bunload
+ call assert_equal(["bufunload", "bufdelete"], s:li)
+
+ let s:li=[]
+ new
+ setlocal bufhidden=unload
+ bwipeout
+ call assert_equal(["bufunload", "bufdelete", "bufwipeout"], s:li)
+
+ au! test_bufunload_group
+ augroup! test_bufunload_group
+endfunc
+
+" SEGV occurs in older versions. (At least 7.4.2005 or older)
+func Test_autocmd_bufunload_with_tabnext()
+ tabedit
+ tabfirst
+
+ augroup test_autocmd_bufunload_with_tabnext_group
+ autocmd!
+ autocmd BufUnload <buffer> tabnext
+ augroup END
+
+ quit
+ call assert_equal(2, tabpagenr('$'))
+
+ autocmd! test_autocmd_bufunload_with_tabnext_group
+ augroup! test_autocmd_bufunload_with_tabnext_group
+ tablast
+ quit
+endfunc
+
+func Test_autocmd_bufwinleave_with_tabfirst()
+ tabedit
+ augroup sample
+ autocmd!
+ autocmd BufWinLeave <buffer> tabfirst
+ augroup END
+ call setline(1, ['a', 'b', 'c'])
+ edit! a.txt
+ tabclose
+endfunc
+
+" SEGV occurs in older versions. (At least 7.4.2321 or older)
+func Test_autocmd_bufunload_avoiding_SEGV_01()
+ split aa.txt
+ let lastbuf = bufnr('$')
+
+ augroup test_autocmd_bufunload
+ autocmd!
+ exe 'autocmd BufUnload <buffer> ' . (lastbuf + 1) . 'bwipeout!'
+ augroup END
+
+ " Todo: check for E937 generated first
+ " call assert_fails('edit bb.txt', 'E937:')
+ call assert_fails('edit bb.txt', 'E517:')
+
+ autocmd! test_autocmd_bufunload
+ augroup! test_autocmd_bufunload
+ bwipe! aa.txt
+ bwipe! bb.txt
+endfunc
+
+" SEGV occurs in older versions. (At least 7.4.2321 or older)
+func Test_autocmd_bufunload_avoiding_SEGV_02()
+ setlocal buftype=nowrite
+ let lastbuf = bufnr('$')
+
+ augroup test_autocmd_bufunload
+ autocmd!
+ exe 'autocmd BufUnload <buffer> ' . (lastbuf + 1) . 'bwipeout!'
+ augroup END
+
+ normal! i1
+ call assert_fails('edit a.txt', 'E517:')
+ call feedkeys("\<CR>")
+
+ autocmd! test_autocmd_bufunload
+ augroup! test_autocmd_bufunload
+ bwipe! a.txt
+endfunc
+
+func Test_win_tab_autocmd()
+ let g:record = []
+
+ augroup testing
+ au WinNew * call add(g:record, 'WinNew')
+ au WinEnter * call add(g:record, 'WinEnter')
+ au WinLeave * call add(g:record, 'WinLeave')
+ au TabNew * call add(g:record, 'TabNew')
+ au TabClosed * call add(g:record, 'TabClosed')
+ au TabEnter * call add(g:record, 'TabEnter')
+ au TabLeave * call add(g:record, 'TabLeave')
+ augroup END
+
+ split
+ tabnew
+ close
+ close
+
+ call assert_equal([
+ \ 'WinLeave', 'WinNew', 'WinEnter',
+ \ 'WinLeave', 'TabLeave', 'WinNew', 'WinEnter', 'TabNew', 'TabEnter',
+ \ 'WinLeave', 'TabLeave', 'TabClosed', 'WinEnter', 'TabEnter',
+ \ 'WinLeave', 'WinEnter'
+ \ ], g:record)
+
+ let g:record = []
+ tabnew somefile
+ tabnext
+ bwipe somefile
+
+ call assert_equal([
+ \ 'WinLeave', 'TabLeave', 'WinNew', 'WinEnter', 'TabNew', 'TabEnter',
+ \ 'WinLeave', 'TabLeave', 'WinEnter', 'TabEnter',
+ \ 'TabClosed'
+ \ ], g:record)
+
+ augroup testing
+ au!
+ augroup END
+ unlet g:record
+endfunc
+
+func s:AddAnAutocmd()
+ augroup vimBarTest
+ au BufReadCmd * echo 'hello'
+ augroup END
+ call assert_equal(3, len(split(execute('au vimBarTest'), "\n")))
+endfunc
+
+func Test_early_bar()
+ " test that a bar is recognized before the {event}
+ call s:AddAnAutocmd()
+ augroup vimBarTest | au! | augroup END
+ call assert_equal(1, len(split(execute('au vimBarTest'), "\n")))
+
+ call s:AddAnAutocmd()
+ augroup vimBarTest| au!| augroup END
+ call assert_equal(1, len(split(execute('au vimBarTest'), "\n")))
+
+ " test that a bar is recognized after the {event}
+ call s:AddAnAutocmd()
+ augroup vimBarTest| au!BufReadCmd| augroup END
+ call assert_equal(1, len(split(execute('au vimBarTest'), "\n")))
+
+ " test that a bar is recognized after the {group}
+ call s:AddAnAutocmd()
+ au! vimBarTest|echo 'hello'
+ call assert_equal(1, len(split(execute('au vimBarTest'), "\n")))
+endfunc
+
+func RemoveGroup()
+ autocmd! StartOK
+ augroup! StartOK
+endfunc
+
+func Test_augroup_warning()
+ augroup TheWarning
+ au VimEnter * echo 'entering'
+ augroup END
+ call assert_true(match(execute('au VimEnter'), "TheWarning.*VimEnter") >= 0)
+ redir => res
+ augroup! TheWarning
+ redir END
+ call assert_true(match(res, "W19:") >= 0)
+ call assert_true(match(execute('au VimEnter'), "-Deleted-.*VimEnter") >= 0)
+
+ " check "Another" does not take the pace of the deleted entry
+ augroup Another
+ augroup END
+ call assert_true(match(execute('au VimEnter'), "-Deleted-.*VimEnter") >= 0)
+ augroup! Another
+
+ " no warning for postpone aucmd delete
+ augroup StartOK
+ au VimEnter * call RemoveGroup()
+ augroup END
+ call assert_true(match(execute('au VimEnter'), "StartOK.*VimEnter") >= 0)
+ redir => res
+ doautocmd VimEnter
+ redir END
+ call assert_true(match(res, "W19:") < 0)
+ au! VimEnter
+endfunc
+
+func Test_BufReadCmdHelp()
+ " This used to cause access to free memory
+ au BufReadCmd * e +h
+ help
+
+ au! BufReadCmd
+endfunc
+
+func Test_BufReadCmdHelpJump()
+ " This used to cause access to free memory
+ au BufReadCmd * e +h{
+ " } to fix highlighting
+ call assert_fails('help', 'E434:')
+
+ au! BufReadCmd
+endfunc
+
+func Test_augroup_deleted()
+ " This caused a crash before E936 was introduced
+ augroup x
+ call assert_fails('augroup! x', 'E936:')
+ au VimEnter * echo
+ augroup end
+ augroup! x
+ call assert_true(match(execute('au VimEnter'), "-Deleted-.*VimEnter") >= 0)
+ au! VimEnter
+endfunc
+
+" Tests for autocommands on :close command.
+" This used to be in test13.
+func Test_three_windows()
+ " Clean up buffers, because in some cases this function fails.
+ call s:cleanup_buffers()
+
+ " Write three files and open them, each in a window.
+ " Then go to next window, with autocommand that deletes the previous one.
+ " Do this twice, writing the file.
+ e! Xtestje1
+ call setline(1, 'testje1')
+ w
+ sp Xtestje2
+ call setline(1, 'testje2')
+ w
+ sp Xtestje3
+ call setline(1, 'testje3')
+ w
+ wincmd w
+ au WinLeave Xtestje2 bwipe
+ wincmd w
+ call assert_equal('Xtestje1', expand('%'))
+
+ au WinLeave Xtestje1 bwipe Xtestje3
+ close
+ call assert_equal('Xtestje1', expand('%'))
+
+ " Test deleting the buffer on a Unload event. If this goes wrong there
+ " will be the ATTENTION prompt.
+ e Xtestje1
+ au!
+ au! BufUnload Xtestje1 bwipe
+ call assert_fails('e Xtestje3', 'E937:')
+ call assert_equal('Xtestje3', expand('%'))
+
+ e Xtestje2
+ sp Xtestje1
+ call assert_fails('e', 'E937:')
+ call assert_equal('Xtestje1', expand('%'))
+
+ " Test changing buffers in a BufWipeout autocommand. If this goes wrong
+ " there are ml_line errors and/or a Crash.
+ au!
+ only
+ e Xanother
+ e Xtestje1
+ bwipe Xtestje2
+ bwipe Xtestje3
+ au BufWipeout Xtestje1 buf Xtestje1
+ bwipe
+ call assert_equal('Xanother', expand('%'))
+
+ only
+ help
+ wincmd w
+ 1quit
+ call assert_equal('Xanother', expand('%'))
+
+ au!
+ enew
+ call delete('Xtestje1')
+ call delete('Xtestje2')
+ call delete('Xtestje3')
+endfunc
+
+func Test_BufEnter()
+ au! BufEnter
+ au Bufenter * let val = val . '+'
+ let g:val = ''
+ split NewFile
+ call assert_equal('+', g:val)
+ bwipe!
+ call assert_equal('++', g:val)
+
+ " Also get BufEnter when editing a directory
+ call mkdir('Xdir')
+ split Xdir
+ call assert_equal('+++', g:val)
+
+ " On MS-Windows we can't edit the directory, make sure we wipe the right
+ " buffer.
+ bwipe! Xdir
+
+ call delete('Xdir', 'd')
+ au! BufEnter
+endfunc
+
+" Closing a window might cause an endless loop
+" E814 for older Vims
+func Test_autocmd_bufwipe_in_SessLoadPost()
+ edit Xtest
+ tabnew
+ file Xsomething
+ set noswapfile
+ mksession!
+
+ let content = ['set nocp noswapfile',
+ \ 'let v:swapchoice="e"',
+ \ 'augroup test_autocmd_sessionload',
+ \ 'autocmd!',
+ \ 'autocmd SessionLoadPost * exe bufnr("Xsomething") . "bw!"',
+ \ 'augroup END',
+ \ '',
+ \ 'func WriteErrors()',
+ \ ' call writefile([execute("messages")], "Xerrors")',
+ \ 'endfunc',
+ \ 'au VimLeave * call WriteErrors()',
+ \ ]
+ call writefile(content, 'Xvimrc')
+ call system(v:progpath. ' -u Xvimrc --not-a-term --noplugins -S Session.vim -c cq')
+ let errors = join(readfile('Xerrors'))
+ call assert_match('E814', errors)
+
+ set swapfile
+ for file in ['Session.vim', 'Xvimrc', 'Xerrors']
+ call delete(file)
+ endfor
+endfunc
+
+" SEGV occurs in older versions.
+func Test_autocmd_bufwipe_in_SessLoadPost2()
+ tabnew
+ set noswapfile
+ mksession!
+
+ let content = ['set nocp noswapfile',
+ \ 'function! DeleteInactiveBufs()',
+ \ ' tabfirst',
+ \ ' let tabblist = []',
+ \ ' for i in range(1, tabpagenr(''$''))',
+ \ ' call extend(tabblist, tabpagebuflist(i))',
+ \ ' endfor',
+ \ ' for b in range(1, bufnr(''$''))',
+ \ ' if bufexists(b) && buflisted(b) && (index(tabblist, b) == -1 || bufname(b) =~# ''^$'')',
+ \ ' exec ''bwipeout '' . b',
+ \ ' endif',
+ \ ' endfor',
+ \ ' echomsg "SessionLoadPost DONE"',
+ \ 'endfunction',
+ \ 'au SessionLoadPost * call DeleteInactiveBufs()',
+ \ '',
+ \ 'func WriteErrors()',
+ \ ' call writefile([execute("messages")], "Xerrors")',
+ \ 'endfunc',
+ \ 'au VimLeave * call WriteErrors()',
+ \ ]
+ call writefile(content, 'Xvimrc')
+ call system(v:progpath. ' -u Xvimrc --not-a-term --noplugins -S Session.vim -c cq')
+ let errors = join(readfile('Xerrors'))
+ " This probably only ever matches on unix.
+ call assert_notmatch('Caught deadly signal SEGV', errors)
+ call assert_match('SessionLoadPost DONE', errors)
+
+ set swapfile
+ for file in ['Session.vim', 'Xvimrc', 'Xerrors']
+ call delete(file)
+ endfor
+endfunc
+
+func Test_empty_doau()
+ doau \|
+endfunc
+
+func s:AutoCommandOptionSet(match)
+ let item = remove(g:options, 0)
+ let expected = printf("Option: <%s>, Oldval: <%s>, NewVal: <%s>, Scope: <%s>\n", item[0], item[1], item[2], item[3])
+ let actual = printf("Option: <%s>, Oldval: <%s>, NewVal: <%s>, Scope: <%s>\n", a:match, v:option_old, v:option_new, v:option_type)
+ let g:opt = [expected, actual]
+ "call assert_equal(expected, actual)
+endfunc
+
+func Test_OptionSet()
+ if !has("eval") || !exists("+autochdir")
+ return
+ endif
+
+ badd test_autocmd.vim
+
+ call test_override('starting', 1)
+ set nocp
+ au OptionSet * :call s:AutoCommandOptionSet(expand("<amatch>"))
+
+ " 1: Setting number option"
+ let g:options=[['number', 0, 1, 'global']]
+ set nu
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 2: Setting local number option"
+ let g:options=[['number', 1, 0, 'local']]
+ setlocal nonu
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 3: Setting global number option"
+ let g:options=[['number', 1, 0, 'global']]
+ setglobal nonu
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 4: Setting local autoindent option"
+ let g:options=[['autoindent', 0, 1, 'local']]
+ setlocal ai
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 5: Setting global autoindent option"
+ let g:options=[['autoindent', 0, 1, 'global']]
+ setglobal ai
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 6: Setting global autoindent option"
+ let g:options=[['autoindent', 1, 0, 'global']]
+ set ai!
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " Should not print anything, use :noa
+ " 7: don't trigger OptionSet"
+ let g:options=[['invalid', 1, 1, 'invalid']]
+ noa set nonu
+ call assert_equal([['invalid', 1, 1, 'invalid']], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 8: Setting several global list and number option"
+ let g:options=[['list', 0, 1, 'global'], ['number', 0, 1, 'global']]
+ set list nu
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 9: don't trigger OptionSet"
+ let g:options=[['invalid', 1, 1, 'invalid'], ['invalid', 1, 1, 'invalid']]
+ noa set nolist nonu
+ call assert_equal([['invalid', 1, 1, 'invalid'], ['invalid', 1, 1, 'invalid']], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 10: Setting global acd"
+ let g:options=[['autochdir', 0, 1, 'local']]
+ setlocal acd
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 11: Setting global autoread (also sets local value)"
+ let g:options=[['autoread', 0, 1, 'global']]
+ set ar
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 12: Setting local autoread"
+ let g:options=[['autoread', 1, 1, 'local']]
+ setlocal ar
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 13: Setting global autoread"
+ let g:options=[['autoread', 1, 0, 'global']]
+ setglobal invar
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 14: Setting option backspace through :let"
+ let g:options=[['backspace', '', 'eol,indent,start', 'global']]
+ let &bs="eol,indent,start"
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 15: Setting option backspace through setbufvar()"
+ let g:options=[['backup', 0, 1, 'local']]
+ " try twice, first time, shouldn't trigger because option name is invalid,
+ " second time, it should trigger
+ let bnum = bufnr('%')
+ call assert_fails("call setbufvar(bnum, '&l:bk', 1)", "E355")
+ " should trigger, use correct option name
+ call setbufvar(bnum, '&backup', 1)
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 16: Setting number option using setwinvar"
+ let g:options=[['number', 0, 1, 'local']]
+ call setwinvar(0, '&number', 1)
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 17: Setting key option, shouldn't trigger"
+ let g:options=[['key', 'invalid', 'invalid1', 'invalid']]
+ setlocal key=blah
+ setlocal key=
+ call assert_equal([['key', 'invalid', 'invalid1', 'invalid']], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 18: Setting string option"
+ let oldval = &tags
+ let g:options=[['tags', oldval, 'tagpath', 'global']]
+ set tags=tagpath
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 1l: Resetting string option"
+ let g:options=[['tags', 'tagpath', oldval, 'global']]
+ set tags&
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " Cleanup
+ au! OptionSet
+ for opt in ['nu', 'ai', 'acd', 'ar', 'bs', 'backup', 'cul', 'cp']
+ exe printf(":set %s&vim", opt)
+ endfor
+ call test_override('starting', 0)
+ delfunc! AutoCommandOptionSet
+endfunc
+
+func Test_OptionSet_diffmode()
+ call test_override('starting', 1)
+ " 18: Changing an option when entering diff mode
+ new
+ au OptionSet diff :let &l:cul=v:option_new
+
+ call setline(1, ['buffer 1', 'line2', 'line3', 'line4'])
+ call assert_equal(0, &l:cul)
+ diffthis
+ call assert_equal(1, &l:cul)
+
+ vnew
+ call setline(1, ['buffer 2', 'line 2', 'line 3', 'line4'])
+ call assert_equal(0, &l:cul)
+ diffthis
+ call assert_equal(1, &l:cul)
+
+ diffoff
+ call assert_equal(0, &l:cul)
+ call assert_equal(1, getwinvar(2, '&l:cul'))
+ bw!
+
+ call assert_equal(1, &l:cul)
+ diffoff!
+ call assert_equal(0, &l:cul)
+ call assert_equal(0, getwinvar(1, '&l:cul'))
+ bw!
+
+ " Cleanup
+ au! OptionSet
+ call test_override('starting', 0)
+endfunc
+
+func Test_OptionSet_diffmode_close()
+ call test_override('starting', 1)
+ " 19: Try to close the current window when entering diff mode
+ " should not segfault
+ new
+ au OptionSet diff close
+
+ call setline(1, ['buffer 1', 'line2', 'line3', 'line4'])
+ call assert_fails(':diffthis', 'E788')
+ call assert_equal(1, &diff)
+ vnew
+ call setline(1, ['buffer 2', 'line 2', 'line 3', 'line4'])
+ call assert_fails(':diffthis', 'E788')
+ call assert_equal(1, &diff)
+ bw!
+ call assert_fails(':diffoff!', 'E788')
+ bw!
+
+ " Cleanup
+ au! OptionSet
+ call test_override('starting', 0)
+ "delfunc! AutoCommandOptionSet
+endfunc
+
+func Test_OptionSet_modeline()
+ call test_override('starting', 1)
+ au! OptionSet
+ augroup set_tabstop
+ au OptionSet tabstop call timer_start(1, {-> execute("echo 'Handler called'", "")})
+ augroup END
+ call writefile(['vim: set ts=7 sw=5 :', 'something'], 'XoptionsetModeline')
+ set modeline
+ let v:errmsg = ''
+ call assert_fails('split XoptionsetModeline', 'E12:')
+ call assert_equal(7, &ts)
+ call assert_equal('', v:errmsg)
+
+ augroup set_tabstop
+ au!
+ augroup END
+ bwipe!
+ set ts&
+ call delete('XoptionsetModeline')
+ call test_override('starting', 0)
+endfunc
+
+" Test for Bufleave autocommand that deletes the buffer we are about to edit.
+func Test_BufleaveWithDelete()
+ new | edit Xfile1
+
+ augroup test_bufleavewithdelete
+ autocmd!
+ autocmd BufLeave Xfile1 bwipe Xfile2
+ augroup END
+
+ call assert_fails('edit Xfile2', 'E143:')
+ call assert_equal('Xfile1', bufname('%'))
+
+ autocmd! test_bufleavewithdelete BufLeave Xfile1
+ augroup! test_bufleavewithdelete
+
+ new
+ bwipe! Xfile1
+endfunc
+
+" Test for autocommand that changes the buffer list, when doing ":ball".
+func Test_Acmd_BufAll()
+ enew!
+ %bwipe!
+ call writefile(['Test file Xxx1'], 'Xxx1')
+ call writefile(['Test file Xxx2'], 'Xxx2')
+ call writefile(['Test file Xxx3'], 'Xxx3')
+
+ " Add three files to the buffer list
+ split Xxx1
+ close
+ split Xxx2
+ close
+ split Xxx3
+ close
+
+ " Wipe the buffer when the buffer is opened
+ au BufReadPost Xxx2 bwipe
+
+ call append(0, 'Test file Xxx4')
+ ball
+
+ call assert_equal(2, winnr('$'))
+ call assert_equal('Xxx1', bufname(winbufnr(winnr('$'))))
+ wincmd t
+
+ au! BufReadPost
+ %bwipe!
+ call delete('Xxx1')
+ call delete('Xxx2')
+ call delete('Xxx3')
+ enew! | only
+endfunc
+
+" Test for autocommand that changes current buffer on BufEnter event.
+" Check if modelines are interpreted for the correct buffer.
+func Test_Acmd_BufEnter()
+ %bwipe!
+ call writefile(['start of test file Xxx1',
+ \ "\<Tab>this is a test",
+ \ 'end of test file Xxx1'], 'Xxx1')
+ call writefile(['start of test file Xxx2',
+ \ 'vim: set noai :',
+ \ "\<Tab>this is a test",
+ \ 'end of test file Xxx2'], 'Xxx2')
+
+ au BufEnter Xxx2 brew
+ set ai modeline modelines=3
+ edit Xxx1
+ " edit Xxx2, autocmd will do :brew
+ edit Xxx2
+ exe "normal G?this is a\<CR>"
+ " Append text with autoindent to this file
+ normal othis should be auto-indented
+ call assert_equal("\<Tab>this should be auto-indented", getline('.'))
+ call assert_equal(3, line('.'))
+ " Remove autocmd and edit Xxx2 again
+ au! BufEnter Xxx2
+ buf! Xxx2
+ exe "normal G?this is a\<CR>"
+ " append text without autoindent to Xxx
+ normal othis should be in column 1
+ call assert_equal("this should be in column 1", getline('.'))
+ call assert_equal(4, line('.'))
+
+ %bwipe!
+ call delete('Xxx1')
+ call delete('Xxx2')
+ set ai&vim modeline&vim modelines&vim
+endfunc
+
+" Test for issue #57
+" do not move cursor on <c-o> when autoindent is set
+func Test_ai_CTRL_O()
+ enew!
+ set ai
+ let save_fo = &fo
+ set fo+=r
+ exe "normal o# abcdef\<Esc>2hi\<CR>\<C-O>d0\<Esc>"
+ exe "normal o# abcdef\<Esc>2hi\<C-O>d0\<Esc>"
+ call assert_equal(['# abc', 'def', 'def'], getline(2, 4))
+
+ set ai&vim
+ let &fo = save_fo
+ enew!
+endfunc
+
+" Test for autocommand that deletes the current buffer on BufLeave event.
+" Also test deleting the last buffer, should give a new, empty buffer.
+func Test_BufLeave_Wipe()
+ %bwipe!
+ let content = ['start of test file Xxx',
+ \ 'this is a test',
+ \ 'end of test file Xxx']
+ call writefile(content, 'Xxx1')
+ call writefile(content, 'Xxx2')
+
+ au BufLeave Xxx2 bwipe
+ edit Xxx1
+ split Xxx2
+ " delete buffer Xxx2, we should be back to Xxx1
+ bwipe
+ call assert_equal('Xxx1', bufname('%'))
+ call assert_equal(1, winnr('$'))
+
+ " Create an alternate buffer
+ %write! test.out
+ call assert_equal('test.out', bufname('#'))
+ " delete alternate buffer
+ bwipe test.out
+ call assert_equal('Xxx1', bufname('%'))
+ call assert_equal('', bufname('#'))
+
+ au BufLeave Xxx1 bwipe
+ " delete current buffer, get an empty one
+ bwipe!
+ call assert_equal(1, line('$'))
+ call assert_equal('', bufname('%'))
+ let g:bufinfo = getbufinfo()
+ call assert_equal(1, len(g:bufinfo))
+
+ call delete('Xxx1')
+ call delete('Xxx2')
+ call delete('test.out')
+ %bwipe
+ au! BufLeave
+
+ " check that bufinfo doesn't contain a pointer to freed memory
+ call test_garbagecollect_now()
+endfunc
+
+func Test_QuitPre()
+ edit Xfoo
+ let winid = win_getid(winnr())
+ split Xbar
+ au! QuitPre * let g:afile = expand('<afile>')
+ " Close the other window, <afile> should be correct.
+ exe win_id2win(winid) . 'q'
+ call assert_equal('Xfoo', g:afile)
+
+ unlet g:afile
+ bwipe Xfoo
+ bwipe Xbar
+endfunc
+
+func Test_Cmdline()
+ au! CmdlineChanged : let g:text = getcmdline()
+ let g:text = 0
+ call feedkeys(":echom 'hello'\<CR>", 'xt')
+ call assert_equal("echom 'hello'", g:text)
+ au! CmdlineChanged
+
+ au! CmdlineChanged : let g:entered = expand('<afile>')
+ let g:entered = 0
+ call feedkeys(":echom 'hello'\<CR>", 'xt')
+ call assert_equal(':', g:entered)
+ au! CmdlineChanged
+
+ au! CmdlineEnter : let g:entered = expand('<afile>')
+ au! CmdlineLeave : let g:left = expand('<afile>')
+ let g:entered = 0
+ let g:left = 0
+ call feedkeys(":echo 'hello'\<CR>", 'xt')
+ call assert_equal(':', g:entered)
+ call assert_equal(':', g:left)
+ au! CmdlineEnter
+ au! CmdlineLeave
+
+ let save_shellslash = &shellslash
+ set noshellslash
+ au! CmdlineEnter / let g:entered = expand('<afile>')
+ au! CmdlineLeave / let g:left = expand('<afile>')
+ let g:entered = 0
+ let g:left = 0
+ new
+ call setline(1, 'hello')
+ call feedkeys("/hello\<CR>", 'xt')
+ call assert_equal('/', g:entered)
+ call assert_equal('/', g:left)
+ bwipe!
+ au! CmdlineEnter
+ au! CmdlineLeave
+ let &shellslash = save_shellslash
+endfunc
+
+" Test for BufWritePre autocommand that deletes or unloads the buffer.
+func Test_BufWritePre()
+ %bwipe
+ au BufWritePre Xxx1 bunload
+ au BufWritePre Xxx2 bwipe
+
+ call writefile(['start of Xxx1', 'test', 'end of Xxx1'], 'Xxx1')
+ call writefile(['start of Xxx2', 'test', 'end of Xxx2'], 'Xxx2')
+
+ edit Xtest
+ e! Xxx2
+ bdel Xtest
+ e Xxx1
+ " write it, will unload it and give an error msg
+ call assert_fails('w', 'E203')
+ call assert_equal('Xxx2', bufname('%'))
+ edit Xtest
+ e! Xxx2
+ bwipe Xtest
+ " write it, will delete the buffer and give an error msg
+ call assert_fails('w', 'E203')
+ call assert_equal('Xxx1', bufname('%'))
+ au! BufWritePre
+ call delete('Xxx1')
+ call delete('Xxx2')
+endfunc
+
+" Test for BufUnload autocommand that unloads all the other buffers
+func Test_bufunload_all()
+ call writefile(['Test file Xxx1'], 'Xxx1')"
+ call writefile(['Test file Xxx2'], 'Xxx2')"
+
+ let content = [
+ \ "func UnloadAllBufs()",
+ \ " let i = 1",
+ \ " while i <= bufnr('$')",
+ \ " if i != bufnr('%') && bufloaded(i)",
+ \ " exe i . 'bunload'",
+ \ " endif",
+ \ " let i += 1",
+ \ " endwhile",
+ \ "endfunc",
+ \ "au BufUnload * call UnloadAllBufs()",
+ \ "au VimLeave * call writefile(['Test Finished'], 'Xout')",
+ \ "edit Xxx1",
+ \ "split Xxx2",
+ \ "q"]
+ call writefile(content, 'Xtest')
+
+ call delete('Xout')
+ call system(v:progpath. ' --clean -N --not-a-term -S Xtest')
+ call assert_true(filereadable('Xout'))
+
+ call delete('Xxx1')
+ call delete('Xxx2')
+ call delete('Xtest')
+ call delete('Xout')
+endfunc
+
+" Some tests for buffer-local autocommands
+func Test_buflocal_autocmd()
+ let g:bname = ''
+ edit xx
+ au BufLeave <buffer> let g:bname = expand("%")
+ " here, autocommand for xx should trigger.
+ " but autocommand shall not apply to buffer named <buffer>.
+ edit somefile
+ call assert_equal('xx', g:bname)
+ let g:bname = ''
+ " here, autocommand shall be auto-deleted
+ bwipe xx
+ " autocmd should not trigger
+ edit xx
+ call assert_equal('', g:bname)
+ " autocmd should not trigger
+ edit somefile
+ call assert_equal('', g:bname)
+ enew
+ unlet g:bname
+endfunc
+
+" Test for "*Cmd" autocommands
+func Test_Cmd_Autocmds()
+ call writefile(['start of Xxx', "\tabc2", 'end of Xxx'], 'Xxx')
+
+ enew!
+ au BufReadCmd XtestA 0r Xxx|$del
+ edit XtestA " will read text of Xxd instead
+ call assert_equal('start of Xxx', getline(1))
+
+ au BufWriteCmd XtestA call append(line("$"), "write")
+ write " will append a line to the file
+ call assert_equal('write', getline('$'))
+ call assert_fails('read XtestA', 'E484') " should not read anything
+ call assert_equal('write', getline(4))
+
+ " now we have:
+ " 1 start of Xxx
+ " 2 abc2
+ " 3 end of Xxx
+ " 4 write
+
+ au FileReadCmd XtestB '[r Xxx
+ 2r XtestB " will read Xxx below line 2 instead
+ call assert_equal('start of Xxx', getline(3))
+
+ " now we have:
+ " 1 start of Xxx
+ " 2 abc2
+ " 3 start of Xxx
+ " 4 abc2
+ " 5 end of Xxx
+ " 6 end of Xxx
+ " 7 write
+
+ au FileWriteCmd XtestC '[,']copy $
+ normal 4GA1
+ 4,5w XtestC " will copy lines 4 and 5 to the end
+ call assert_equal("\tabc21", getline(8))
+ call assert_fails('r XtestC', 'E484') " should not read anything
+ call assert_equal("end of Xxx", getline(9))
+
+ " now we have:
+ " 1 start of Xxx
+ " 2 abc2
+ " 3 start of Xxx
+ " 4 abc21
+ " 5 end of Xxx
+ " 6 end of Xxx
+ " 7 write
+ " 8 abc21
+ " 9 end of Xxx
+
+ let g:lines = []
+ au FileAppendCmd XtestD call extend(g:lines, getline(line("'["), line("']")))
+ w >>XtestD " will add lines to 'lines'
+ call assert_equal(9, len(g:lines))
+ call assert_fails('$r XtestD', 'E484') " should not read anything
+ call assert_equal(9, line('$'))
+ call assert_equal('end of Xxx', getline('$'))
+
+ au BufReadCmd XtestE 0r Xxx|$del
+ sp XtestE " split window with test.out
+ call assert_equal('end of Xxx', getline(3))
+
+ let g:lines = []
+ exe "normal 2Goasdf\<Esc>\<C-W>\<C-W>"
+ au BufWriteCmd XtestE call extend(g:lines, getline(0, '$'))
+ wall " will write other window to 'lines'
+ call assert_equal(4, len(g:lines), g:lines)
+ call assert_equal('asdf', g:lines[2])
+
+ au! BufReadCmd
+ au! BufWriteCmd
+ au! FileReadCmd
+ au! FileWriteCmd
+ au! FileAppendCmd
+ %bwipe!
+ call delete('Xxx')
+ enew!
+endfunc
+
+func SetChangeMarks(start, end)
+ exe a:start. 'mark ['
+ exe a:end. 'mark ]'
+endfunc
+
+" Verify the effects of autocmds on '[ and ']
+func Test_change_mark_in_autocmds()
+ edit! Xtest
+ call feedkeys("ia\<CR>b\<CR>c\<CR>d\<C-g>u", 'xtn')
+
+ call SetChangeMarks(2, 3)
+ write
+ call assert_equal([1, 4], [line("'["), line("']")])
+
+ call SetChangeMarks(2, 3)
+ au BufWritePre * call assert_equal([1, 4], [line("'["), line("']")])
+ write
+ au! BufWritePre
+
+ if executable('cat')
+ write XtestFilter
+ write >> XtestFilter
+
+ call SetChangeMarks(2, 3)
+ " Marks are set to the entire range of the write
+ au FilterWritePre * call assert_equal([1, 4], [line("'["), line("']")])
+ " '[ is adjusted to just before the line that will receive the filtered
+ " data
+ au FilterReadPre * call assert_equal([4, 4], [line("'["), line("']")])
+ " The filtered data is read into the buffer, and the source lines are
+ " still present, so the range is after the source lines
+ au FilterReadPost * call assert_equal([5, 12], [line("'["), line("']")])
+ %!cat XtestFilter
+ " After the filtered data is read, the original lines are deleted
+ call assert_equal([1, 8], [line("'["), line("']")])
+ au! FilterWritePre,FilterReadPre,FilterReadPost
+ undo
+
+ call SetChangeMarks(1, 4)
+ au FilterWritePre * call assert_equal([2, 3], [line("'["), line("']")])
+ au FilterReadPre * call assert_equal([3, 3], [line("'["), line("']")])
+ au FilterReadPost * call assert_equal([4, 11], [line("'["), line("']")])
+ 2,3!cat XtestFilter
+ call assert_equal([2, 9], [line("'["), line("']")])
+ au! FilterWritePre,FilterReadPre,FilterReadPost
+ undo
+
+ call delete('XtestFilter')
+ endif
+
+ call SetChangeMarks(1, 4)
+ au FileWritePre * call assert_equal([2, 3], [line("'["), line("']")])
+ 2,3write Xtest2
+ au! FileWritePre
+
+ call SetChangeMarks(2, 3)
+ au FileAppendPre * call assert_equal([1, 4], [line("'["), line("']")])
+ write >> Xtest2
+ au! FileAppendPre
+
+ call SetChangeMarks(1, 4)
+ au FileAppendPre * call assert_equal([2, 3], [line("'["), line("']")])
+ 2,3write >> Xtest2
+ au! FileAppendPre
+
+ call SetChangeMarks(1, 1)
+ au FileReadPre * call assert_equal([3, 1], [line("'["), line("']")])
+ au FileReadPost * call assert_equal([4, 11], [line("'["), line("']")])
+ 3read Xtest2
+ au! FileReadPre,FileReadPost
+ undo
+
+ call SetChangeMarks(4, 4)
+ " When the line is 0, it's adjusted to 1
+ au FileReadPre * call assert_equal([1, 4], [line("'["), line("']")])
+ au FileReadPost * call assert_equal([1, 8], [line("'["), line("']")])
+ 0read Xtest2
+ au! FileReadPre,FileReadPost
+ undo
+
+ call SetChangeMarks(4, 4)
+ " When the line is 0, it's adjusted to 1
+ au FileReadPre * call assert_equal([1, 4], [line("'["), line("']")])
+ au FileReadPost * call assert_equal([2, 9], [line("'["), line("']")])
+ 1read Xtest2
+ au! FileReadPre,FileReadPost
+ undo
+
+ bwipe!
+ call delete('Xtest')
+ call delete('Xtest2')
+endfunc
+
+func Test_Filter_noshelltemp()
+ if !executable('cat')
+ return
+ endif
+
+ enew!
+ call setline(1, ['a', 'b', 'c', 'd'])
+
+ let shelltemp = &shelltemp
+ set shelltemp
+
+ let g:filter_au = 0
+ au FilterWritePre * let g:filter_au += 1
+ au FilterReadPre * let g:filter_au += 1
+ au FilterReadPost * let g:filter_au += 1
+ %!cat
+ call assert_equal(3, g:filter_au)
+
+ if has('filterpipe')
+ set noshelltemp
+
+ let g:filter_au = 0
+ au FilterWritePre * let g:filter_au += 1
+ au FilterReadPre * let g:filter_au += 1
+ au FilterReadPost * let g:filter_au += 1
+ %!cat
+ call assert_equal(0, g:filter_au)
+ endif
+
+ au! FilterWritePre,FilterReadPre,FilterReadPost
+ let &shelltemp = shelltemp
+ bwipe!
+endfunc
+
+func Test_TextYankPost()
+ enew!
+ call setline(1, ['foo'])
+
+ let g:event = []
+ au TextYankPost * let g:event = copy(v:event)
+
+ call assert_equal({}, v:event)
+ call assert_fails('let v:event = {}', 'E46:')
+ call assert_fails('let v:event.mykey = 0', 'E742:')
+
+ norm "ayiw
+ call assert_equal(
+ \{'regcontents': ['foo'], 'regname': 'a', 'operator': 'y', 'regtype': 'v'},
+ \g:event)
+ norm y_
+ call assert_equal(
+ \{'regcontents': ['foo'], 'regname': '', 'operator': 'y', 'regtype': 'V'},
+ \g:event)
+ call feedkeys("\<C-V>y", 'x')
+ call assert_equal(
+ \{'regcontents': ['f'], 'regname': '', 'operator': 'y', 'regtype': "\x161"},
+ \g:event)
+ norm "xciwbar
+ call assert_equal(
+ \{'regcontents': ['foo'], 'regname': 'x', 'operator': 'c', 'regtype': 'v'},
+ \g:event)
+ norm "bdiw
+ call assert_equal(
+ \{'regcontents': ['bar'], 'regname': 'b', 'operator': 'd', 'regtype': 'v'},
+ \g:event)
+
+ call assert_equal({}, v:event)
+
+ au! TextYankPost
+ unlet g:event
+ bwipe!
+endfunc
+
+func Test_nocatch_wipe_all_buffers()
+ " Real nasty autocommand: wipe all buffers on any event.
+ au * * bwipe *
+ " Get E93 first?
+ " call assert_fails('next x', 'E93:')
+ call assert_fails('next x', 'E517:')
+ bwipe
+ au!
+endfunc
+
+func Test_nocatch_wipe_dummy_buffer()
+ " Nasty autocommand: wipe buffer on any event.
+ au * x bwipe
+ call assert_fails('lv½ /x', 'E480')
+ au!
+endfunc
+
+function s:Before_test_dirchanged()
+ augroup test_dirchanged
+ autocmd!
+ augroup END
+ let s:li = []
+ let s:dir_this = getcwd()
+ let s:dir_foo = s:dir_this . '/foo'
+ call mkdir(s:dir_foo)
+ let s:dir_bar = s:dir_this . '/bar'
+ call mkdir(s:dir_bar)
+endfunc
+
+function s:After_test_dirchanged()
+ exe 'cd' s:dir_this
+ call delete(s:dir_foo, 'd')
+ call delete(s:dir_bar, 'd')
+ augroup test_dirchanged
+ autocmd!
+ augroup END
+endfunc
+
+function Test_dirchanged_global()
+ call s:Before_test_dirchanged()
+ autocmd test_dirchanged DirChanged global call add(s:li, "cd:")
+ autocmd test_dirchanged DirChanged global call add(s:li, expand("<afile>"))
+ exe 'cd' s:dir_foo
+ call assert_equal(["cd:", s:dir_foo], s:li)
+ exe 'cd' s:dir_foo
+ call assert_equal(["cd:", s:dir_foo], s:li)
+ exe 'lcd' s:dir_bar
+ call assert_equal(["cd:", s:dir_foo], s:li)
+ call s:After_test_dirchanged()
+endfunc
+
+function Test_dirchanged_local()
+ call s:Before_test_dirchanged()
+ autocmd test_dirchanged DirChanged window call add(s:li, "lcd:")
+ autocmd test_dirchanged DirChanged window call add(s:li, expand("<afile>"))
+ exe 'cd' s:dir_foo
+ call assert_equal([], s:li)
+ exe 'lcd' s:dir_bar
+ call assert_equal(["lcd:", s:dir_bar], s:li)
+ exe 'lcd' s:dir_bar
+ call assert_equal(["lcd:", s:dir_bar], s:li)
+ call s:After_test_dirchanged()
+endfunc
+
+function Test_dirchanged_auto()
+ if !exists('+autochdir')
+ return
+ endif
+ call s:Before_test_dirchanged()
+ call test_autochdir()
+ autocmd test_dirchanged DirChanged auto call add(s:li, "auto:")
+ autocmd test_dirchanged DirChanged auto call add(s:li, expand("<afile>"))
+ set acd
+ exe 'cd ..'
+ call assert_equal([], s:li)
+ exe 'edit ' . s:dir_foo . '/Xfile'
+ call assert_equal(s:dir_foo, getcwd())
+ call assert_equal(["auto:", s:dir_foo], s:li)
+ set noacd
+ bwipe!
+ call s:After_test_dirchanged()
+endfunc
+
+" Test TextChangedI and TextChangedP
+func Test_ChangedP()
+ new
+ call setline(1, ['foo', 'bar', 'foobar'])
+ call test_override("char_avail", 1)
+ set complete=. completeopt=menuone
+
+ func! TextChangedAutocmd(char)
+ let g:autocmd .= a:char
+ endfunc
+
+ au! TextChanged <buffer> :call TextChangedAutocmd('N')
+ au! TextChangedI <buffer> :call TextChangedAutocmd('I')
+ au! TextChangedP <buffer> :call TextChangedAutocmd('P')
+
+ call cursor(3, 1)
+ let g:autocmd = ''
+ call feedkeys("o\<esc>", 'tnix')
+ call assert_equal('I', g:autocmd)
+
+ let g:autocmd = ''
+ call feedkeys("Sf", 'tnix')
+ call assert_equal('II', g:autocmd)
+
+ let g:autocmd = ''
+ call feedkeys("Sf\<C-N>", 'tnix')
+ call assert_equal('IIP', g:autocmd)
+
+ let g:autocmd = ''
+ call feedkeys("Sf\<C-N>\<C-N>", 'tnix')
+ call assert_equal('IIPP', g:autocmd)
+
+ let g:autocmd = ''
+ call feedkeys("Sf\<C-N>\<C-N>\<C-N>", 'tnix')
+ call assert_equal('IIPPP', g:autocmd)
+
+ let g:autocmd = ''
+ call feedkeys("Sf\<C-N>\<C-N>\<C-N>\<C-N>", 'tnix')
+ call assert_equal('IIPPPP', g:autocmd)
+
+ call assert_equal(['foo', 'bar', 'foobar', 'foo'], getline(1, '$'))
+ " TODO: how should it handle completeopt=noinsert,noselect?
+
+ " CleanUp
+ call test_override("char_avail", 0)
+ au! TextChanged
+ au! TextChangedI
+ au! TextChangedP
+ delfu TextChangedAutocmd
+ unlet! g:autocmd
+ set complete&vim completeopt&vim
+
+ bw!
+endfunc
+
+let g:setline_handled = v:false
+func SetLineOne()
+ if !g:setline_handled
+ call setline(1, "(x)")
+ let g:setline_handled = v:true
+ endif
+endfunc
+
+func Test_TextChangedI_with_setline()
+ new
+ call test_override('char_avail', 1)
+ autocmd TextChangedI <buffer> call SetLineOne()
+ call feedkeys("i(\<CR>\<Esc>", 'tx')
+ call assert_equal('(', getline(1))
+ call assert_equal('x)', getline(2))
+ undo
+ call assert_equal('', getline(1))
+ call assert_equal('', getline(2))
+
+ call test_override('starting', 0)
+ bwipe!
+endfunc
+
+func Test_Changed_FirstTime()
+ if !has('terminal') || has('gui_running')
+ return
+ endif
+ " Prepare file for TextChanged event.
+ call writefile([''], 'Xchanged.txt')
+ let buf = term_start([GetVimProg(), '--clean', '-c', 'set noswapfile'], {'term_rows': 3})
+ call assert_equal('running', term_getstatus(buf))
+ " Wait for the ruler (in the status line) to be shown.
+ " In ConPTY, there is additional character which is drawn up to the width of
+ " the screen.
+ if has('conpty')
+ call WaitForAssert({-> assert_match('\<All.*$', term_getline(buf, 3))})
+ else
+ call WaitForAssert({-> assert_match('\<All$', term_getline(buf, 3))})
+ endif
+ " It's only adding autocmd, so that no event occurs.
+ call term_sendkeys(buf, ":au! TextChanged <buffer> call writefile(['No'], 'Xchanged.txt')\<cr>")
+ call term_sendkeys(buf, "\<C-\\>\<C-N>:qa!\<cr>")
+ call WaitForAssert({-> assert_equal('finished', term_getstatus(buf))})
+ call assert_equal([''], readfile('Xchanged.txt'))
+
+ " clean up
+ call delete('Xchanged.txt')
+ bwipe!
+endfunc
+
+" FileChangedShell tested in test_filechanged.vim
diff --git a/src/testdir/test_autoload.vim b/src/testdir/test_autoload.vim
new file mode 100644
index 0000000..7396c22
--- /dev/null
+++ b/src/testdir/test_autoload.vim
@@ -0,0 +1,17 @@
+" Tests for autoload
+
+set runtimepath=./sautest
+
+func Test_autoload_dict_func()
+ let g:loaded_foo_vim = 0
+ let g:called_foo_bar_echo = 0
+ call g:foo#bar.echo()
+ call assert_equal(1, g:loaded_foo_vim)
+ call assert_equal(1, g:called_foo_bar_echo)
+endfunc
+
+func Test_source_autoload()
+ let g:loaded_sourced_vim = 0
+ source sautest/autoload/sourced.vim
+ call assert_equal(1, g:loaded_sourced_vim)
+endfunc
diff --git a/src/testdir/test_backspace_opt.vim b/src/testdir/test_backspace_opt.vim
new file mode 100644
index 0000000..fd81f42
--- /dev/null
+++ b/src/testdir/test_backspace_opt.vim
@@ -0,0 +1,59 @@
+" Tests for 'backspace' settings
+
+:func Exec(expr)
+ let str=''
+ try
+ exec a:expr
+ catch /.*/
+ let str=v:exception
+ endtry
+ return str
+:endfunc
+
+func Test_backspace_option()
+ set backspace=
+ call assert_equal('', &backspace)
+ set backspace=indent
+ call assert_equal('indent', &backspace)
+ set backspace=eol
+ call assert_equal('eol', &backspace)
+ set backspace=start
+ call assert_equal('start', &backspace)
+ " Add the value
+ set backspace=
+ set backspace=indent
+ call assert_equal('indent', &backspace)
+ set backspace+=eol
+ call assert_equal('indent,eol', &backspace)
+ set backspace+=start
+ call assert_equal('indent,eol,start', &backspace)
+ " Delete the value
+ set backspace-=indent
+ call assert_equal('eol,start', &backspace)
+ set backspace-=start
+ call assert_equal('eol', &backspace)
+ set backspace-=eol
+ call assert_equal('', &backspace)
+ " Check the error
+ call assert_equal(0, match(Exec('set backspace=ABC'), '.*E474'))
+ call assert_equal(0, match(Exec('set backspace+=def'), '.*E474'))
+ " NOTE: Vim doesn't check following error...
+ "call assert_equal(0, match(Exec('set backspace-=ghi'), '.*E474'))
+
+ " Check backwards compatibility with version 5.4 and earlier
+ set backspace=0
+ call assert_equal('0', &backspace)
+ set backspace=1
+ call assert_equal('1', &backspace)
+ set backspace=2
+ call assert_equal('2', &backspace)
+ call assert_false(match(Exec('set backspace=3'), '.*E474'))
+ call assert_false(match(Exec('set backspace=10'), '.*E474'))
+
+ " Cleared when 'compatible' is set
+ set compatible
+ call assert_equal('', &backspace)
+ set nocompatible viminfo+=nviminfo
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/test_backup.vim b/src/testdir/test_backup.vim
new file mode 100644
index 0000000..ce2bfe7
--- /dev/null
+++ b/src/testdir/test_backup.vim
@@ -0,0 +1,58 @@
+" Tests for the backup function
+
+func Test_backup()
+ set backup backupdir=. backupskip=
+ new
+ call setline(1, ['line1', 'line2'])
+ :f Xbackup.txt
+ :w! Xbackup.txt
+ " backup file is only created after
+ " writing a second time (before overwriting)
+ :w! Xbackup.txt
+ let l = readfile('Xbackup.txt~')
+ call assert_equal(['line1', 'line2'], l)
+ bw!
+ set backup&vim backupdir&vim backupskip&vim
+ call delete('Xbackup.txt')
+ call delete('Xbackup.txt~')
+endfunc
+
+func Test_backup2()
+ set backup backupdir=.// backupskip=
+ new
+ call setline(1, ['line1', 'line2', 'line3'])
+ :f Xbackup.txt
+ :w! Xbackup.txt
+ " backup file is only created after
+ " writing a second time (before overwriting)
+ :w! Xbackup.txt
+ sp *Xbackup.txt~
+ call assert_equal(['line1', 'line2', 'line3'], getline(1,'$'))
+ let f=expand('%')
+ call assert_match('%testdir%Xbackup.txt\~', f)
+ bw!
+ bw!
+ call delete('Xbackup.txt')
+ call delete(f)
+ set backup&vim backupdir&vim backupskip&vim
+endfunc
+
+func Test_backup2_backupcopy()
+ set backup backupdir=.// backupcopy=yes backupskip=
+ new
+ call setline(1, ['line1', 'line2', 'line3'])
+ :f Xbackup.txt
+ :w! Xbackup.txt
+ " backup file is only created after
+ " writing a second time (before overwriting)
+ :w! Xbackup.txt
+ sp *Xbackup.txt~
+ call assert_equal(['line1', 'line2', 'line3'], getline(1,'$'))
+ let f=expand('%')
+ call assert_match('%testdir%Xbackup.txt\~', f)
+ bw!
+ bw!
+ call delete('Xbackup.txt')
+ call delete(f)
+ set backup&vim backupdir&vim backupcopy&vim backupskip&vim
+endfunc
diff --git a/src/testdir/test_behave.vim b/src/testdir/test_behave.vim
new file mode 100644
index 0000000..c26bfe7
--- /dev/null
+++ b/src/testdir/test_behave.vim
@@ -0,0 +1,29 @@
+" Test the :behave command
+
+func Test_behave()
+ behave mswin
+ call assert_equal('mouse,key', &selectmode)
+ call assert_equal('popup', &mousemodel)
+ call assert_equal('startsel,stopsel', &keymodel)
+ call assert_equal('exclusive', &selection)
+
+ behave xterm
+ call assert_equal('', &selectmode)
+ call assert_equal('extend', &mousemodel)
+ call assert_equal('', &keymodel)
+ call assert_equal('inclusive', &selection)
+
+ set selection&
+ set mousemodel&
+ set keymodel&
+ set selection&
+endfunc
+
+func Test_behave_completion()
+ call feedkeys(":behave \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"behave mswin xterm', @:)
+endfunc
+
+func Test_behave_error()
+ call assert_fails('behave x', 'E475:')
+endfunc
diff --git a/src/testdir/test_blob.vim b/src/testdir/test_blob.vim
new file mode 100644
index 0000000..b01e11b
--- /dev/null
+++ b/src/testdir/test_blob.vim
@@ -0,0 +1,320 @@
+" Tests for the Blob types
+
+func TearDown()
+ " Run garbage collection after every test
+ call test_garbagecollect_now()
+endfunc
+
+" Tests for Blob type
+
+" Blob creation from constant
+func Test_blob_create()
+ let b = 0zDEADBEEF
+ call assert_equal(v:t_blob, type(b))
+ call assert_equal(4, len(b))
+ call assert_equal(0xDE, b[0])
+ call assert_equal(0xAD, b[1])
+ call assert_equal(0xBE, b[2])
+ call assert_equal(0xEF, b[3])
+ call assert_fails('let x = b[4]')
+
+ call assert_equal(0xDE, get(b, 0))
+ call assert_equal(0xEF, get(b, 3))
+
+ call assert_fails('let b = 0z1', 'E973:')
+ call assert_fails('let b = 0z1x', 'E973:')
+ call assert_fails('let b = 0z12345', 'E973:')
+
+ call assert_equal(0z, test_null_blob())
+
+ let b = 0z001122.33445566.778899.aabbcc.dd
+ call assert_equal(0z00112233445566778899aabbccdd, b)
+ call assert_fails('let b = 0z1.1')
+ call assert_fails('let b = 0z.')
+ call assert_fails('let b = 0z001122.')
+ call assert_fails('call get("", 1)', 'E896:')
+endfunc
+
+" assignment to a blob
+func Test_blob_assign()
+ let b = 0zDEADBEEF
+ let b2 = b[1:2]
+ call assert_equal(0zADBE, b2)
+
+ let bcopy = b[:]
+ call assert_equal(b, bcopy)
+ call assert_false(b is bcopy)
+
+ let b = 0zDEADBEEF
+ let b2 = b
+ call assert_true(b is b2)
+ let b[:] = 0z11223344
+ call assert_equal(0z11223344, b)
+ call assert_equal(0z11223344, b2)
+ call assert_true(b is b2)
+
+ let b = 0zDEADBEEF
+ let b[3:] = 0z66
+ call assert_equal(0zDEADBE66, b)
+ let b[:1] = 0z8899
+ call assert_equal(0z8899BE66, b)
+
+ call assert_fails('let b[2:3] = 0z112233', 'E972:')
+ call assert_fails('let b[2:3] = 0z11', 'E972:')
+ call assert_fails('let b[3:2] = 0z', 'E979:')
+
+ let b = 0zDEADBEEF
+ let b += 0z99
+ call assert_equal(0zDEADBEEF99, b)
+
+ call assert_fails('let b .= 0z33', 'E734:')
+ call assert_fails('let b .= "xx"', 'E734:')
+ call assert_fails('let b += "xx"', 'E734:')
+ call assert_fails('let b[1:1] .= 0z55', 'E734:')
+endfunc
+
+func Test_blob_get_range()
+ let b = 0z0011223344
+ call assert_equal(0z2233, b[2:3])
+ call assert_equal(0z223344, b[2:-1])
+ call assert_equal(0z00, b[0:-5])
+ call assert_equal(0z, b[0:-11])
+ call assert_equal(0z44, b[-1:])
+ call assert_equal(0z0011223344, b[:])
+ call assert_equal(0z0011223344, b[:-1])
+ call assert_equal(0z, b[5:6])
+endfunc
+
+func Test_blob_get()
+ let b = 0z0011223344
+ call assert_equal(0x00, get(b, 0))
+ call assert_equal(0x22, get(b, 2, 999))
+ call assert_equal(0x44, get(b, 4))
+ call assert_equal(0x44, get(b, -1))
+ call assert_equal(-1, get(b, 5))
+ call assert_equal(999, get(b, 5, 999))
+ call assert_equal(-1, get(b, -8))
+ call assert_equal(999, get(b, -8, 999))
+
+ call assert_equal(0x00, b[0])
+ call assert_equal(0x22, b[2])
+ call assert_equal(0x44, b[4])
+ call assert_equal(0x44, b[-1])
+ call assert_fails('echo b[5]', 'E979:')
+ call assert_fails('echo b[-8]', 'E979:')
+endfunc
+
+func Test_blob_to_string()
+ let b = 0z00112233445566778899aabbccdd
+ call assert_equal('0z00112233.44556677.8899AABB.CCDD', string(b))
+ call assert_equal(b, eval(string(b)))
+ call remove(b, 4, -1)
+ call assert_equal('0z00112233', string(b))
+ call remove(b, 0, 3)
+ call assert_equal('0z', string(b))
+endfunc
+
+func Test_blob_compare()
+ let b1 = 0z0011
+ let b2 = 0z1100
+ let b3 = 0z001122
+ call assert_true(b1 == b1)
+ call assert_false(b1 == b2)
+ call assert_false(b1 == b3)
+ call assert_true(b1 != b2)
+ call assert_true(b1 != b3)
+ call assert_true(b1 == 0z0011)
+ call assert_fails('echo b1 == 9', 'E977:')
+ call assert_fails('echo b1 != 9', 'E977:')
+
+ call assert_false(b1 is b2)
+ let b2 = b1
+ call assert_true(b1 == b2)
+ call assert_true(b1 is b2)
+ let b2 = copy(b1)
+ call assert_true(b1 == b2)
+ call assert_false(b1 is b2)
+ let b2 = b1[:]
+ call assert_true(b1 == b2)
+ call assert_false(b1 is b2)
+
+ call assert_fails('let x = b1 > b2')
+ call assert_fails('let x = b1 < b2')
+ call assert_fails('let x = b1 - b2')
+ call assert_fails('let x = b1 / b2')
+ call assert_fails('let x = b1 * b2')
+endfunc
+
+" test for range assign
+func Test_blob_range_assign()
+ let b = 0z00
+ let b[1] = 0x11
+ let b[2] = 0x22
+ call assert_equal(0z001122, b)
+ call assert_fails('let b[4] = 0x33', 'E979:')
+endfunc
+
+func Test_blob_for_loop()
+ let blob = 0z00010203
+ let i = 0
+ for byte in blob
+ call assert_equal(i, byte)
+ let i += 1
+ endfor
+ call assert_equal(4, i)
+
+ let blob = 0z00
+ call remove(blob, 0)
+ call assert_equal(0, len(blob))
+ for byte in blob
+ call assert_error('loop over empty blob')
+ endfor
+
+ let blob = 0z0001020304
+ let i = 0
+ for byte in blob
+ call assert_equal(i, byte)
+ if i == 1
+ call remove(blob, 0)
+ elseif i == 3
+ call remove(blob, 3)
+ endif
+ let i += 1
+ endfor
+ call assert_equal(5, i)
+endfunc
+
+func Test_blob_concatenate()
+ let b = 0z0011
+ let b += 0z2233
+ call assert_equal(0z00112233, b)
+
+ call assert_fails('let b += "a"')
+ call assert_fails('let b += 88')
+
+ let b = 0zDEAD + 0zBEEF
+ call assert_equal(0zDEADBEEF, b)
+endfunc
+
+func Test_blob_add()
+ let b = 0z0011
+ call add(b, 0x22)
+ call assert_equal(0z001122, b)
+ call add(b, '51')
+ call assert_equal(0z00112233, b)
+
+ call assert_fails('call add(b, [9])', 'E745:')
+ call assert_fails('call add("", 0x01)', 'E897:')
+endfunc
+
+func Test_blob_empty()
+ call assert_false(empty(0z001122))
+ call assert_true(empty(0z))
+ call assert_true(empty(test_null_blob()))
+endfunc
+
+" Test removing items in blob
+func Test_blob_func_remove()
+ " Test removing 1 element
+ let b = 0zDEADBEEF
+ call assert_equal(0xDE, remove(b, 0))
+ call assert_equal(0zADBEEF, b)
+
+ let b = 0zDEADBEEF
+ call assert_equal(0xEF, remove(b, -1))
+ call assert_equal(0zDEADBE, b)
+
+ let b = 0zDEADBEEF
+ call assert_equal(0xAD, remove(b, 1))
+ call assert_equal(0zDEBEEF, b)
+
+ " Test removing range of element(s)
+ let b = 0zDEADBEEF
+ call assert_equal(0zBE, remove(b, 2, 2))
+ call assert_equal(0zDEADEF, b)
+
+ let b = 0zDEADBEEF
+ call assert_equal(0zADBE, remove(b, 1, 2))
+ call assert_equal(0zDEEF, b)
+
+ " Test invalid cases
+ let b = 0zDEADBEEF
+ call assert_fails("call remove(b, 5)", 'E979:')
+ call assert_fails("call remove(b, 1, 5)", 'E979:')
+ call assert_fails("call remove(b, 3, 2)", 'E979:')
+ call assert_fails("call remove(1, 0)", 'E896:')
+ call assert_fails("call remove(b, b)", 'E974:')
+endfunc
+
+func Test_blob_read_write()
+ let b = 0zDEADBEEF
+ call writefile(b, 'Xblob')
+ let br = readfile('Xblob', 'B')
+ call assert_equal(b, br)
+ call delete('Xblob')
+endfunc
+
+" filter() item in blob
+func Test_blob_filter()
+ let b = 0zDEADBEEF
+ call filter(b, 'v:val != 0xEF')
+ call assert_equal(0zDEADBE, b)
+endfunc
+
+" map() item in blob
+func Test_blob_map()
+ let b = 0zDEADBEEF
+ call map(b, 'v:val + 1')
+ call assert_equal(0zDFAEBFF0, b)
+
+ call assert_fails("call map(b, '[9]')", 'E978:')
+endfunc
+
+func Test_blob_index()
+ call assert_equal(2, index(0zDEADBEEF, 0xBE))
+ call assert_equal(-1, index(0zDEADBEEF, 0))
+ call assert_equal(2, index(0z11111111, 0x11, 2))
+ call assert_equal(3, index(0z11110111, 0x11, 2))
+ call assert_equal(2, index(0z11111111, 0x11, -2))
+ call assert_equal(3, index(0z11110111, 0x11, -2))
+
+ call assert_fails('call index("asdf", 0)', 'E897:')
+endfunc
+
+func Test_blob_insert()
+ let b = 0zDEADBEEF
+ call insert(b, 0x33)
+ call assert_equal(0z33DEADBEEF, b)
+
+ let b = 0zDEADBEEF
+ call insert(b, 0x33, 2)
+ call assert_equal(0zDEAD33BEEF, b)
+
+ call assert_fails('call insert(b, -1)', 'E475:')
+ call assert_fails('call insert(b, 257)', 'E475:')
+ call assert_fails('call insert(b, 0, [9])', 'E745:')
+endfunc
+
+func Test_blob_reverse()
+ call assert_equal(0zEFBEADDE, reverse(0zDEADBEEF))
+ call assert_equal(0zBEADDE, reverse(0zDEADBE))
+ call assert_equal(0zADDE, reverse(0zDEAD))
+ call assert_equal(0zDE, reverse(0zDE))
+endfunc
+
+func Test_blob_json_encode()
+ call assert_equal('[222,173,190,239]', json_encode(0zDEADBEEF))
+ call assert_equal('[]', json_encode(0z))
+endfunc
+
+func Test_blob_lock()
+ let b = 0z112233
+ lockvar b
+ call assert_fails('let b = 0z44', 'E741:')
+ unlockvar b
+ let b = 0z44
+endfunc
+
+func Test_blob_sort()
+ call assert_fails('call sort([1.0, 0z11], "f")', 'E975:')
+endfunc
diff --git a/src/testdir/test_blockedit.vim b/src/testdir/test_blockedit.vim
new file mode 100644
index 0000000..527224c
--- /dev/null
+++ b/src/testdir/test_blockedit.vim
@@ -0,0 +1,33 @@
+" Test for block inserting
+"
+" TODO: rewrite test39.in into this new style test
+
+func Test_blockinsert_indent()
+ new
+ filetype plugin indent on
+ setlocal sw=2 et ft=vim
+ call setline(1, ['let a=[', ' ''eins'',', ' ''zwei'',', ' ''drei'']'])
+ call cursor(2, 3)
+ exe "norm! \<c-v>2jI\\ \<esc>"
+ call assert_equal(['let a=[', ' \ ''eins'',', ' \ ''zwei'',', ' \ ''drei'']'],
+ \ getline(1,'$'))
+ " reset to sane state
+ filetype off
+ bwipe!
+endfunc
+
+func Test_blockinsert_delete()
+ new
+ let _bs = &bs
+ set bs=2
+ call setline(1, ['case Arg is ', ' when Name_Async,', ' when Name_Num_Gangs,', 'end if;'])
+ exe "norm! ggjVj\<c-v>$o$A\<bs>\<esc>"
+ "call feedkeys("Vj\<c-v>$o$A\<bs>\<esc>", 'ti')
+ call assert_equal(["case Arg is ", " when Name_Async", " when Name_Num_Gangs,", "end if;"],
+ \ getline(1,'$'))
+ " reset to sane state
+ let &bs = _bs
+ bwipe!
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/test_breakindent.vim b/src/testdir/test_breakindent.vim
new file mode 100644
index 0000000..ae05479
--- /dev/null
+++ b/src/testdir/test_breakindent.vim
@@ -0,0 +1,617 @@
+" Test for breakindent
+"
+" Note: if you get strange failures when adding new tests, it might be that
+" while the test is run, the breakindent cacheing gets in its way.
+" It helps to change the tabstop setting and force a redraw (e.g. see
+" Test_breakindent08())
+if !exists('+breakindent')
+ finish
+endif
+
+source view_util.vim
+
+let s:input ="\tabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP"
+
+func s:screen_lines(lnum, width) abort
+ return ScreenLines([a:lnum, a:lnum + 2], a:width)
+endfunc
+
+func s:compare_lines(expect, actual)
+ call assert_equal(join(a:expect, "\n"), join(a:actual, "\n"))
+endfunc
+
+func s:test_windows(...)
+ call NewWindow(10, 20)
+ setl ts=4 sw=4 sts=4 breakindent
+ put =s:input
+ exe get(a:000, 0, '')
+endfunc
+
+func s:close_windows(...)
+ call CloseWindow()
+ exe get(a:000, 0, '')
+endfunc
+
+func Test_breakindent01()
+ " simple breakindent test
+ call s:test_windows('setl briopt=min:0')
+ let lines = s:screen_lines(line('.'),8)
+ let expect = [
+ \ " abcd",
+ \ " qrst",
+ \ " GHIJ",
+ \ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows()
+endfunc
+
+func Test_breakindent01_vartabs()
+ " like 01 but with vartabs feature
+ if !has("vartabs")
+ return
+ endif
+ call s:test_windows('setl briopt=min:0 vts=4')
+ let lines = s:screen_lines(line('.'),8)
+ let expect = [
+ \ " abcd",
+ \ " qrst",
+ \ " GHIJ",
+ \ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows('set vts&')
+endfunc
+
+func Test_breakindent02()
+ " simple breakindent test with showbreak set
+ call s:test_windows('setl briopt=min:0 sbr=>>')
+ let lines = s:screen_lines(line('.'),8)
+ let expect = [
+ \ " abcd",
+ \ " >>qr",
+ \ " >>EF",
+ \ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows('set sbr=')
+endfunc
+
+func Test_breakindent02_vartabs()
+ if !has("vartabs")
+ return
+ endif
+ " simple breakindent test with showbreak set
+ call s:test_windows('setl briopt=min:0 sbr=>> vts=4')
+ let lines = s:screen_lines(line('.'),8)
+ let expect = [
+ \ " abcd",
+ \ " >>qr",
+ \ " >>EF",
+ \ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows('set sbr= vts&')
+endfunc
+
+func Test_breakindent03()
+ " simple breakindent test with showbreak set and briopt including sbr
+ call s:test_windows('setl briopt=sbr,min:0 sbr=++')
+ let lines = s:screen_lines(line('.'),8)
+ let expect = [
+ \ " abcd",
+ \ "++ qrst",
+ \ "++ GHIJ",
+ \ ]
+ call s:compare_lines(expect, lines)
+ " clean up
+ call s:close_windows('set sbr=')
+endfunc
+
+func Test_breakindent03_vartabs()
+ " simple breakindent test with showbreak set and briopt including sbr
+ if !has("vartabs")
+ return
+ endif
+ call s:test_windows('setl briopt=sbr,min:0 sbr=++ vts=4')
+ let lines = s:screen_lines(line('.'),8)
+ let expect = [
+ \ " abcd",
+ \ "++ qrst",
+ \ "++ GHIJ",
+ \ ]
+ call s:compare_lines(expect, lines)
+ " clean up
+ call s:close_windows('set sbr= vts&')
+endfunc
+
+func Test_breakindent04()
+ " breakindent set with min width 18
+ call s:test_windows('setl sbr= briopt=min:18')
+ let lines = s:screen_lines(line('.'),8)
+ let expect = [
+ \ " abcd",
+ \ " qrstuv",
+ \ " IJKLMN",
+ \ ]
+ call s:compare_lines(expect, lines)
+ " clean up
+ call s:close_windows('set sbr=')
+endfunc
+
+func Test_breakindent04_vartabs()
+ " breakindent set with min width 18
+ if !has("vartabs")
+ return
+ endif
+ call s:test_windows('setl sbr= briopt=min:18 vts=4')
+ let lines = s:screen_lines(line('.'),8)
+ let expect = [
+ \ " abcd",
+ \ " qrstuv",
+ \ " IJKLMN",
+ \ ]
+ call s:compare_lines(expect, lines)
+ " clean up
+ call s:close_windows('set sbr= vts&')
+endfunc
+
+func Test_breakindent05()
+ " breakindent set and shift by 2
+ call s:test_windows('setl briopt=shift:2,min:0')
+ let lines = s:screen_lines(line('.'),8)
+ let expect = [
+ \ " abcd",
+ \ " qr",
+ \ " EF",
+ \ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows()
+endfunc
+
+func Test_breakindent05_vartabs()
+ " breakindent set and shift by 2
+ if !has("vartabs")
+ return
+ endif
+ call s:test_windows('setl briopt=shift:2,min:0 vts=4')
+ let lines = s:screen_lines(line('.'),8)
+ let expect = [
+ \ " abcd",
+ \ " qr",
+ \ " EF",
+ \ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows('set vts&')
+endfunc
+
+func Test_breakindent06()
+ " breakindent set and shift by -1
+ call s:test_windows('setl briopt=shift:-1,min:0')
+ let lines = s:screen_lines(line('.'),8)
+ let expect = [
+ \ " abcd",
+ \ " qrstu",
+ \ " HIJKL",
+ \ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows()
+endfunc
+
+func Test_breakindent06_vartabs()
+ " breakindent set and shift by -1
+ if !has("vartabs")
+ return
+ endif
+ call s:test_windows('setl briopt=shift:-1,min:0 vts=4')
+ let lines = s:screen_lines(line('.'),8)
+ let expect = [
+ \ " abcd",
+ \ " qrstu",
+ \ " HIJKL",
+ \ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows('set vts&')
+endfunc
+
+func Test_breakindent07()
+ " breakindent set and shift by 1, Number set sbr=? and briopt:sbr
+ call s:test_windows('setl briopt=shift:1,sbr,min:0 nu sbr=? nuw=4 cpo+=n')
+ let lines = s:screen_lines(line('.'),10)
+ let expect = [
+ \ " 2 ab",
+ \ "? m",
+ \ "? x",
+ \ ]
+ call s:compare_lines(expect, lines)
+ " clean up
+ call s:close_windows('set sbr= cpo-=n')
+endfunc
+
+func Test_breakindent07_vartabs()
+ if !has("vartabs")
+ return
+ endif
+ " breakindent set and shift by 1, Number set sbr=? and briopt:sbr
+ call s:test_windows('setl briopt=shift:1,sbr,min:0 nu sbr=? nuw=4 cpo+=n vts=4')
+ let lines = s:screen_lines(line('.'),10)
+ let expect = [
+ \ " 2 ab",
+ \ "? m",
+ \ "? x",
+ \ ]
+ call s:compare_lines(expect, lines)
+ " clean up
+ call s:close_windows('set sbr= cpo-=n vts&')
+endfunc
+
+func Test_breakindent07a()
+ " breakindent set and shift by 1, Number set sbr=? and briopt:sbr
+ call s:test_windows('setl briopt=shift:1,sbr,min:0 nu sbr=? nuw=4')
+ let lines = s:screen_lines(line('.'),10)
+ let expect = [
+ \ " 2 ab",
+ \ " ? m",
+ \ " ? x",
+ \ ]
+ call s:compare_lines(expect, lines)
+ " clean up
+ call s:close_windows('set sbr=')
+endfunc
+
+func Test_breakindent07a_vartabs()
+ if !has("vartabs")
+ return
+ endif
+ " breakindent set and shift by 1, Number set sbr=? and briopt:sbr
+ call s:test_windows('setl briopt=shift:1,sbr,min:0 nu sbr=? nuw=4 vts=4')
+ let lines = s:screen_lines(line('.'),10)
+ let expect = [
+ \ " 2 ab",
+ \ " ? m",
+ \ " ? x",
+ \ ]
+ call s:compare_lines(expect, lines)
+ " clean up
+ call s:close_windows('set sbr= vts&')
+endfunc
+
+func Test_breakindent08()
+ " breakindent set and shift by 1, Number and list set sbr=# and briopt:sbr
+ call s:test_windows('setl briopt=shift:1,sbr,min:0 nu nuw=4 sbr=# list cpo+=n ts=4')
+ " make sure, cache is invalidated!
+ set ts=8
+ redraw!
+ set ts=4
+ redraw!
+ let lines = s:screen_lines(line('.'),10)
+ let expect = [
+ \ " 2 ^Iabcd",
+ \ "# opq",
+ \ "# BCD",
+ \ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows('set sbr= cpo-=n')
+endfunc
+
+func Test_breakindent08_vartabs()
+ if !has("vartabs")
+ return
+ endif
+ " breakindent set and shift by 1, Number and list set sbr=# and briopt:sbr
+ call s:test_windows('setl briopt=shift:1,sbr,min:0 nu nuw=4 sbr=# list cpo+=n ts=4 vts=4')
+ " make sure, cache is invalidated!
+ set ts=8
+ redraw!
+ set ts=4
+ redraw!
+ let lines = s:screen_lines(line('.'),10)
+ let expect = [
+ \ " 2 ^Iabcd",
+ \ "# opq",
+ \ "# BCD",
+ \ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows('set sbr= cpo-=n vts&')
+endfunc
+
+func Test_breakindent08a()
+ " breakindent set and shift by 1, Number and list set sbr=# and briopt:sbr
+ call s:test_windows('setl briopt=shift:1,sbr,min:0 nu nuw=4 sbr=# list')
+ let lines = s:screen_lines(line('.'),10)
+ let expect = [
+ \ " 2 ^Iabcd",
+ \ " # opq",
+ \ " # BCD",
+ \ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows('set sbr=')
+endfunc
+
+func Test_breakindent08a_vartabs()
+ if !has("vartabs")
+ return
+ endif
+ " breakindent set and shift by 1, Number and list set sbr=# and briopt:sbr
+ call s:test_windows('setl briopt=shift:1,sbr,min:0 nu nuw=4 sbr=# list vts=4')
+ let lines = s:screen_lines(line('.'),10)
+ let expect = [
+ \ " 2 ^Iabcd",
+ \ " # opq",
+ \ " # BCD",
+ \ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows('set sbr= vts&')
+endfunc
+
+func Test_breakindent09()
+ " breakindent set and shift by 1, Number and list set sbr=#
+ call s:test_windows('setl briopt=shift:1,min:0 nu nuw=4 sbr=# list')
+ let lines = s:screen_lines(line('.'),10)
+ let expect = [
+ \ " 2 ^Iabcd",
+ \ " #op",
+ \ " #AB",
+ \ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows('set sbr=')
+endfunc
+
+func Test_breakindent09_vartabs()
+ if !has("vartabs")
+ return
+ endif
+ " breakindent set and shift by 1, Number and list set sbr=#
+ call s:test_windows('setl briopt=shift:1,min:0 nu nuw=4 sbr=# list vts=4')
+ let lines = s:screen_lines(line('.'),10)
+ let expect = [
+ \ " 2 ^Iabcd",
+ \ " #op",
+ \ " #AB",
+ \ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows('set sbr= vts&')
+endfunc
+
+func Test_breakindent10()
+ " breakindent set, Number set sbr=~
+ call s:test_windows('setl cpo+=n sbr=~ nu nuw=4 nolist briopt=sbr,min:0')
+ " make sure, cache is invalidated!
+ set ts=8
+ redraw!
+ set ts=4
+ redraw!
+ let lines = s:screen_lines(line('.'),10)
+ let expect = [
+ \ " 2 ab",
+ \ "~ mn",
+ \ "~ yz",
+ \ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows('set sbr= cpo-=n')
+endfunc
+
+func Test_breakindent10_vartabs()
+ if !has("vartabs")
+ return
+ endif
+ " breakindent set, Number set sbr=~
+ call s:test_windows('setl cpo+=n sbr=~ nu nuw=4 nolist briopt=sbr,min:0 vts=4')
+ " make sure, cache is invalidated!
+ set ts=8
+ redraw!
+ set ts=4
+ redraw!
+ let lines = s:screen_lines(line('.'),10)
+ let expect = [
+ \ " 2 ab",
+ \ "~ mn",
+ \ "~ yz",
+ \ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows('set sbr= cpo-=n vts&')
+endfunc
+
+func Test_breakindent11()
+ " test strdisplaywidth()
+ call s:test_windows('setl cpo-=n sbr=>> nu nuw=4 nolist briopt= ts=4')
+ let text = getline(2)
+ let width = strlen(text[1:])+indent(2)+strlen(&sbr)*3 " text wraps 3 times
+ call assert_equal(width, strdisplaywidth(text))
+ call s:close_windows('set sbr=')
+endfunc
+
+func Test_breakindent11_vartabs()
+ if !has("vartabs")
+ return
+ endif
+ " test strdisplaywidth()
+ call s:test_windows('setl cpo-=n sbr=>> nu nuw=4 nolist briopt= ts=4 vts=4')
+ let text = getline(2)
+ let width = strlen(text[1:])+indent(2)+strlen(&sbr)*3 " text wraps 3 times
+ call assert_equal(width, strdisplaywidth(text))
+ call s:close_windows('set sbr= vts&')
+endfunc
+
+func Test_breakindent12()
+ " test breakindent with long indent
+ let s:input = "\t\t\t\t\t{"
+ call s:test_windows('setl breakindent linebreak briopt=min:10 nu numberwidth=3 ts=4 list listchars=tab:>-')
+ let lines = s:screen_lines(2,16)
+ let expect = [
+ \ " 2 >--->--->--->",
+ \ " ---{ ",
+ \ "~ ",
+ \ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows('set nuw=4 listchars=')
+endfunc
+
+func Test_breakindent12_vartabs()
+ if !has("vartabs")
+ return
+ endif
+ " test breakindent with long indent
+ let s:input = "\t\t\t\t\t{"
+ call s:test_windows('setl breakindent linebreak briopt=min:10 nu numberwidth=3 ts=4 list listchars=tab:>- vts=4')
+ let lines = s:screen_lines(2,16)
+ let expect = [
+ \ " 2 >--->--->--->",
+ \ " ---{ ",
+ \ "~ ",
+ \ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows('set nuw=4 listchars= vts&')
+endfunc
+
+func Test_breakindent13()
+ let s:input = ""
+ call s:test_windows('setl breakindent briopt=min:10 ts=8')
+ vert resize 20
+ call setline(1, [" a\tb\tc\td\te", " z y x w v"])
+ 1
+ norm! fbgj"ayl
+ 2
+ norm! fygj"byl
+ call assert_equal('d', @a)
+ call assert_equal('w', @b)
+ call s:close_windows()
+endfunc
+
+func Test_breakindent13_vartabs()
+ if !has("vartabs")
+ return
+ endif
+ let s:input = ""
+ call s:test_windows('setl breakindent briopt=min:10 ts=8 vts=8')
+ vert resize 20
+ call setline(1, [" a\tb\tc\td\te", " z y x w v"])
+ 1
+ norm! fbgj"ayl
+ 2
+ norm! fygj"byl
+ call assert_equal('d', @a)
+ call assert_equal('w', @b)
+ call s:close_windows('set vts&')
+endfunc
+
+func Test_breakindent14()
+ let s:input = ""
+ call s:test_windows('setl breakindent briopt= ts=8')
+ vert resize 30
+ norm! 3a1234567890
+ norm! a abcde
+ exec "norm! 0\<C-V>tex"
+ let lines = s:screen_lines(line('.'),8)
+ let expect = [
+ \ "e ",
+ \ "~ ",
+ \ "~ ",
+ \ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows()
+endfunc
+
+func Test_breakindent14_vartabs()
+ if !has("vartabs")
+ return
+ endif
+ let s:input = ""
+ call s:test_windows('setl breakindent briopt= ts=8 vts=8')
+ vert resize 30
+ norm! 3a1234567890
+ norm! a abcde
+ exec "norm! 0\<C-V>tex"
+ let lines = s:screen_lines(line('.'),8)
+ let expect = [
+ \ "e ",
+ \ "~ ",
+ \ "~ ",
+ \ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows('set vts&')
+endfunc
+
+func Test_breakindent15()
+ let s:input = ""
+ call s:test_windows('setl breakindent briopt= ts=8 sw=8')
+ vert resize 30
+ norm! 4a1234567890
+ exe "normal! >>\<C-V>3f0x"
+ let lines = s:screen_lines(line('.'),20)
+ let expect = [
+ \ " 1234567890 ",
+ \ "~ ",
+ \ "~ ",
+ \ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows()
+endfunc
+
+func Test_breakindent15_vartabs()
+ if !has("vartabs")
+ return
+ endif
+ let s:input = ""
+ call s:test_windows('setl breakindent briopt= ts=8 sw=8 vts=8')
+ vert resize 30
+ norm! 4a1234567890
+ exe "normal! >>\<C-V>3f0x"
+ let lines = s:screen_lines(line('.'),20)
+ let expect = [
+ \ " 1234567890 ",
+ \ "~ ",
+ \ "~ ",
+ \ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows('set vts&')
+endfunc
+
+func Test_breakindent16()
+ " Check that overlong lines are indented correctly.
+ let s:input = ""
+ call s:test_windows('setl breakindent briopt=min:0 ts=4')
+ call setline(1, "\t".repeat("1234567890", 10))
+ resize 6
+ norm! 1gg$
+ redraw!
+ let lines = s:screen_lines(1,10)
+ let expect = [
+ \ " 789012",
+ \ " 345678",
+ \ " 901234",
+ \ ]
+ call s:compare_lines(expect, lines)
+ let lines = s:screen_lines(4,10)
+ let expect = [
+ \ " 567890",
+ \ " 123456",
+ \ " 7890 ",
+ \ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows()
+endfunc
+
+func Test_breakindent16_vartabs()
+ if !has("vartabs")
+ return
+ endif
+ " Check that overlong lines are indented correctly.
+ let s:input = ""
+ call s:test_windows('setl breakindent briopt=min:0 ts=4 vts=4')
+ call setline(1, "\t".repeat("1234567890", 10))
+ resize 6
+ norm! 1gg$
+ redraw!
+ let lines = s:screen_lines(1,10)
+ let expect = [
+ \ " 789012",
+ \ " 345678",
+ \ " 901234",
+ \ ]
+ call s:compare_lines(expect, lines)
+ let lines = s:screen_lines(4,10)
+ let expect = [
+ \ " 567890",
+ \ " 123456",
+ \ " 7890 ",
+ \ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows('set vts&')
+endfunc
diff --git a/src/testdir/test_bufline.vim b/src/testdir/test_bufline.vim
new file mode 100644
index 0000000..524144d
--- /dev/null
+++ b/src/testdir/test_bufline.vim
@@ -0,0 +1,141 @@
+" Tests for setbufline(), getbufline(), appendbufline(), deletebufline()
+
+source shared.vim
+
+func Test_setbufline_getbufline()
+ new
+ let b = bufnr('%')
+ hide
+ call assert_equal(0, setbufline(b, 1, ['foo', 'bar']))
+ call assert_equal(['foo'], getbufline(b, 1))
+ call assert_equal(['bar'], getbufline(b, 2))
+ call assert_equal(['foo', 'bar'], getbufline(b, 1, 2))
+ exe "bd!" b
+ call assert_equal([], getbufline(b, 1, 2))
+
+ split Xtest
+ call setline(1, ['a', 'b', 'c'])
+ let b = bufnr('%')
+ wincmd w
+ call assert_equal(1, setbufline(b, 5, ['x']))
+ call assert_equal(1, setbufline(1234, 1, ['x']))
+ call assert_equal(0, setbufline(b, 4, ['d', 'e']))
+ call assert_equal(['c'], getbufline(b, 3))
+ call assert_equal(['d'], getbufline(b, 4))
+ call assert_equal(['e'], getbufline(b, 5))
+ call assert_equal([], getbufline(b, 6))
+ exe "bwipe! " . b
+endfunc
+
+func Test_setbufline_getbufline_fold()
+ split Xtest
+ setlocal foldmethod=expr foldexpr=0
+ let b = bufnr('%')
+ new
+ call assert_equal(0, setbufline(b, 1, ['foo', 'bar']))
+ call assert_equal(['foo'], getbufline(b, 1))
+ call assert_equal(['bar'], getbufline(b, 2))
+ call assert_equal(['foo', 'bar'], getbufline(b, 1, 2))
+ exe "bwipe!" b
+ bwipe!
+endfunc
+
+func Test_setbufline_getbufline_fold_tab()
+ split Xtest
+ setlocal foldmethod=expr foldexpr=0
+ let b = bufnr('%')
+ tab new
+ call assert_equal(0, setbufline(b, 1, ['foo', 'bar']))
+ call assert_equal(['foo'], getbufline(b, 1))
+ call assert_equal(['bar'], getbufline(b, 2))
+ call assert_equal(['foo', 'bar'], getbufline(b, 1, 2))
+ exe "bwipe!" b
+ bwipe!
+endfunc
+
+func Test_setline_startup()
+ let cmd = GetVimCommand('Xscript')
+ if cmd == ''
+ return
+ endif
+ call writefile(['call setline(1, "Hello")', 'silent w Xtest', 'q!'], 'Xscript')
+ call system(cmd)
+ call assert_equal(['Hello'], readfile('Xtest'))
+
+ call delete('Xscript')
+ call delete('Xtest')
+endfunc
+
+func Test_appendbufline()
+ new
+ let b = bufnr('%')
+ hide
+ call assert_equal(0, appendbufline(b, 0, ['foo', 'bar']))
+ call assert_equal(['foo'], getbufline(b, 1))
+ call assert_equal(['bar'], getbufline(b, 2))
+ call assert_equal(['foo', 'bar'], getbufline(b, 1, 2))
+ exe "bd!" b
+ call assert_equal([], getbufline(b, 1, 2))
+
+ split Xtest
+ call setline(1, ['a', 'b', 'c'])
+ let b = bufnr('%')
+ wincmd w
+ call assert_equal(1, appendbufline(b, 4, ['x']))
+ call assert_equal(1, appendbufline(1234, 1, ['x']))
+ call assert_equal(0, appendbufline(b, 3, ['d', 'e']))
+ call assert_equal(['c'], getbufline(b, 3))
+ call assert_equal(['d'], getbufline(b, 4))
+ call assert_equal(['e'], getbufline(b, 5))
+ call assert_equal([], getbufline(b, 6))
+ exe "bwipe! " . b
+endfunc
+
+func Test_appendbufline_no_E315()
+ let after = [
+ \ 'set stl=%f ls=2',
+ \ 'new',
+ \ 'let buf = bufnr("%")',
+ \ 'quit',
+ \ 'vsp',
+ \ 'exec "buffer" buf',
+ \ 'wincmd w',
+ \ 'call appendbufline(buf, 0, "abc")',
+ \ 'redraw',
+ \ 'while getbufline(buf, 1)[0] =~ "^\\s*$"',
+ \ ' sleep 10m',
+ \ 'endwhile',
+ \ 'au VimLeavePre * call writefile([v:errmsg], "Xerror")',
+ \ 'au VimLeavePre * call writefile(["done"], "Xdone")',
+ \ 'qall!',
+ \ ]
+ if !RunVim([], after, '--clean')
+ return
+ endif
+ call assert_notmatch("^E315:", readfile("Xerror")[0])
+ call assert_equal("done", readfile("Xdone")[0])
+ call delete("Xerror")
+ call delete("Xdone")
+endfunc
+
+func Test_deletebufline()
+ new
+ let b = bufnr('%')
+ call setline(1, ['aaa', 'bbb', 'ccc'])
+ hide
+ call assert_equal(0, deletebufline(b, 2))
+ call assert_equal(['aaa', 'ccc'], getbufline(b, 1, 2))
+ call assert_equal(0, deletebufline(b, 2, 8))
+ call assert_equal(['aaa'], getbufline(b, 1, 2))
+ exe "bd!" b
+ call assert_equal(1, deletebufline(b, 1))
+
+ split Xtest
+ call setline(1, ['a', 'b', 'c'])
+ let b = bufnr('%')
+ wincmd w
+ call assert_equal(1, deletebufline(b, 4))
+ call assert_equal(0, deletebufline(b, 1))
+ call assert_equal(['b', 'c'], getbufline(b, 1, 2))
+ exe "bwipe! " . b
+endfunc
diff --git a/src/testdir/test_bufwintabinfo.vim b/src/testdir/test_bufwintabinfo.vim
new file mode 100644
index 0000000..0e8c7d1
--- /dev/null
+++ b/src/testdir/test_bufwintabinfo.vim
@@ -0,0 +1,141 @@
+" Tests for the getbufinfo(), getwininfo() and gettabinfo() functions
+
+function Test_getbufwintabinfo()
+ edit Xtestfile1
+ edit Xtestfile2
+ let buflist = getbufinfo()
+ call assert_equal(2, len(buflist))
+ call assert_match('Xtestfile1', buflist[0].name)
+ call assert_match('Xtestfile2', getbufinfo('Xtestfile2')[0].name)
+ call assert_equal([], getbufinfo(2016))
+ edit Xtestfile1
+ hide edit Xtestfile2
+ hide enew
+ call assert_equal(3, len(getbufinfo({'bufloaded':1})))
+
+ set tabstop&vim
+ let b:editor = 'vim'
+ let l = getbufinfo('%')
+ call assert_equal(bufnr('%'), l[0].bufnr)
+ call assert_equal('vim', l[0].variables.editor)
+ call assert_notequal(-1, index(l[0].windows, bufwinid('%')))
+
+ " Test for getbufinfo() with 'bufmodified'
+ call assert_equal(0, len(getbufinfo({'bufmodified' : 1})))
+ call setbufline('Xtestfile1', 1, ["Line1"])
+ let l = getbufinfo({'bufmodified' : 1})
+ call assert_equal(1, len(l))
+ call assert_equal(bufnr('Xtestfile1'), l[0].bufnr)
+
+ if has('signs')
+ call append(0, ['Linux', 'Windows', 'Mac'])
+ sign define Mark text=>> texthl=Search
+ exe "sign place 2 line=3 name=Mark buffer=" . bufnr('%')
+ let l = getbufinfo('%')
+ call assert_equal(2, l[0].signs[0].id)
+ call assert_equal(3, l[0].signs[0].lnum)
+ call assert_equal('Mark', l[0].signs[0].name)
+ sign unplace *
+ sign undefine Mark
+ enew!
+ endif
+
+ only
+ let w1_id = win_getid()
+ new
+ let w2_id = win_getid()
+ tabnew | let w3_id = win_getid()
+ new | let w4_id = win_getid()
+ vert new | let w5_id = win_getid()
+ call setwinvar(0, 'signal', 'green')
+ tabfirst
+ let winlist = getwininfo()
+ call assert_equal(5, len(winlist))
+ call assert_equal(winwidth(1), winlist[0].width)
+ call assert_equal(1, winlist[0].wincol)
+ " tabline adds one row in terminal, not in GUI
+ let tablineheight = winlist[0].winrow == 2 ? 1 : 0
+ call assert_equal(tablineheight + 1, winlist[0].winrow)
+
+ call assert_equal(winbufnr(2), winlist[1].bufnr)
+ call assert_equal(winheight(2), winlist[1].height)
+ call assert_equal(1, winlist[1].wincol)
+ call assert_equal(tablineheight + winheight(1) + 2, winlist[1].winrow)
+
+ call assert_equal(1, winlist[2].winnr)
+ call assert_equal(tablineheight + 1, winlist[2].winrow)
+ call assert_equal(1, winlist[2].wincol)
+
+ call assert_equal(winlist[2].width + 2, winlist[3].wincol)
+ call assert_equal(1, winlist[4].wincol)
+
+ call assert_equal(1, winlist[0].tabnr)
+ call assert_equal(1, winlist[1].tabnr)
+ call assert_equal(2, winlist[2].tabnr)
+ call assert_equal(2, winlist[3].tabnr)
+ call assert_equal(2, winlist[4].tabnr)
+
+ call assert_equal('green', winlist[2].variables.signal)
+ call assert_equal(w4_id, winlist[3].winid)
+ let winfo = getwininfo(w5_id)[0]
+ call assert_equal(2, winfo.tabnr)
+ call assert_equal([], getwininfo(3))
+
+ call settabvar(1, 'space', 'build')
+ let tablist = gettabinfo()
+ call assert_equal(2, len(tablist))
+ call assert_equal(3, len(tablist[1].windows))
+ call assert_equal(2, tablist[1].tabnr)
+ call assert_equal('build', tablist[0].variables.space)
+ call assert_equal(w2_id, tablist[0].windows[0])
+ call assert_equal([], gettabinfo(3))
+
+ tabonly | only
+
+ lexpr ''
+ lopen
+ copen
+ let winlist = getwininfo()
+ call assert_false(winlist[0].quickfix)
+ call assert_false(winlist[0].loclist)
+ call assert_true(winlist[1].quickfix)
+ call assert_true(winlist[1].loclist)
+ call assert_true(winlist[2].quickfix)
+ call assert_false(winlist[2].loclist)
+ wincmd t | only
+endfunction
+
+function Test_get_buf_options()
+ let opts = getbufvar(bufnr('%'), '&')
+ call assert_equal(v:t_dict, type(opts))
+ call assert_equal(8, opts.tabstop)
+endfunc
+
+function Test_get_win_options()
+ if has('folding')
+ set foldlevel=999
+ endif
+ set list
+ let opts = getwinvar(1, '&')
+ call assert_equal(v:t_dict, type(opts))
+ call assert_equal(0, opts.linebreak)
+ call assert_equal(1, opts.list)
+ if has('folding')
+ call assert_equal(999, opts.foldlevel)
+ endif
+ if has('signs')
+ call assert_equal('auto', opts.signcolumn)
+ endif
+
+ let opts = gettabwinvar(1, 1, '&')
+ call assert_equal(v:t_dict, type(opts))
+ call assert_equal(0, opts.linebreak)
+ call assert_equal(1, opts.list)
+ if has('signs')
+ call assert_equal('auto', opts.signcolumn)
+ endif
+ set list&
+ if has('folding')
+ set foldlevel=0
+ endif
+endfunc
diff --git a/src/testdir/test_cd.vim b/src/testdir/test_cd.vim
new file mode 100644
index 0000000..c63f006
--- /dev/null
+++ b/src/testdir/test_cd.vim
@@ -0,0 +1,67 @@
+" Test for :cd
+
+func Test_cd_large_path()
+ " This used to crash with a heap write overflow.
+ call assert_fails('cd ' . repeat('x', 5000), 'E472:')
+endfunc
+
+func Test_cd_up_and_down()
+ let path = getcwd()
+ cd ..
+ call assert_notequal(path, getcwd())
+ exe 'cd ' . path
+ call assert_equal(path, getcwd())
+endfunc
+
+func Test_cd_no_arg()
+ if has('unix')
+ " Test that cd without argument goes to $HOME directory on Unix systems.
+ let path = getcwd()
+ cd
+ call assert_equal($HOME, getcwd())
+ call assert_notequal(path, getcwd())
+ exe 'cd ' . path
+ call assert_equal(path, getcwd())
+ else
+ " Test that cd without argument echoes cwd on non-Unix systems.
+ call assert_match(getcwd(), execute('cd'))
+ endif
+endfunc
+
+func Test_cd_minus()
+ " Test the :cd - goes back to the previous directory.
+ let path = getcwd()
+ cd ..
+ let path_dotdot = getcwd()
+ call assert_notequal(path, path_dotdot)
+ cd -
+ call assert_equal(path, getcwd())
+ cd -
+ call assert_equal(path_dotdot, getcwd())
+ cd -
+ call assert_equal(path, getcwd())
+endfunc
+
+func Test_cd_with_cpo_chdir()
+ e Xfoo
+ call setline(1, 'foo')
+ let path = getcwd()
+ set cpo+=.
+
+ " :cd should fail when buffer is modified and 'cpo' contains dot.
+ call assert_fails('cd ..', 'E747:')
+ call assert_equal(path, getcwd())
+
+ " :cd with exclamation mark should succeed.
+ cd! ..
+ call assert_notequal(path, getcwd())
+
+ " :cd should succeed when buffer has been written.
+ w!
+ exe 'cd ' . path
+ call assert_equal(path, getcwd())
+
+ call delete('Xfoo')
+ set cpo&
+ bw!
+endfunc
diff --git a/src/testdir/test_cdo.vim b/src/testdir/test_cdo.vim
new file mode 100644
index 0000000..988de1d
--- /dev/null
+++ b/src/testdir/test_cdo.vim
@@ -0,0 +1,205 @@
+" Tests for the :cdo, :cfdo, :ldo and :lfdo commands
+
+if !has('quickfix')
+ finish
+endif
+
+" Create the files used by the tests
+function SetUp()
+ call writefile(["Line1", "Line2", "Line3"], 'Xtestfile1')
+ call writefile(["Line1", "Line2", "Line3"], 'Xtestfile2')
+ call writefile(["Line1", "Line2", "Line3"], 'Xtestfile3')
+endfunction
+
+" Remove the files used by the tests
+function TearDown()
+ call delete('Xtestfile1')
+ call delete('Xtestfile2')
+ call delete('Xtestfile3')
+endfunction
+
+" Returns the current line in '<filename> <linenum>L <column>C' format
+function GetRuler()
+ return expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C'
+endfunction
+
+" Tests for the :cdo and :ldo commands
+function XdoTests(cchar)
+ enew
+
+ " Shortcuts for calling the cdo and ldo commands
+ let Xdo = a:cchar . 'do'
+ let Xgetexpr = a:cchar . 'getexpr'
+ let Xprev = a:cchar. 'prev'
+ let XdoCmd = Xdo . ' call add(l, GetRuler())'
+
+ " Try with an empty list
+ let l = []
+ exe XdoCmd
+ call assert_equal([], l)
+
+ " Populate the list and then try
+ exe Xgetexpr . " ['non-error 1', 'Xtestfile1:1:3:Line1', 'non-error 2', 'Xtestfile2:2:2:Line2', 'non-error 3', 'Xtestfile3:3:1:Line3']"
+
+ let l = []
+ exe XdoCmd
+ call assert_equal(['Xtestfile1 1L 3C', 'Xtestfile2 2L 2C', 'Xtestfile3 3L 1C'], l)
+
+ " Run command only on selected error lines
+ let l = []
+ enew
+ exe "2,3" . XdoCmd
+ call assert_equal(['Xtestfile2 2L 2C', 'Xtestfile3 3L 1C'], l)
+
+ " Boundary condition tests
+ let l = []
+ enew
+ exe "1,1" . XdoCmd
+ call assert_equal(['Xtestfile1 1L 3C'], l)
+
+ let l = []
+ enew
+ exe "3" . XdoCmd
+ call assert_equal(['Xtestfile3 3L 1C'], l)
+
+ " Range test commands
+ let l = []
+ enew
+ exe "%" . XdoCmd
+ call assert_equal(['Xtestfile1 1L 3C', 'Xtestfile2 2L 2C', 'Xtestfile3 3L 1C'], l)
+
+ let l = []
+ enew
+ exe "1,$" . XdoCmd
+ call assert_equal(['Xtestfile1 1L 3C', 'Xtestfile2 2L 2C', 'Xtestfile3 3L 1C'], l)
+
+ let l = []
+ enew
+ exe Xprev
+ exe "." . XdoCmd
+ call assert_equal(['Xtestfile2 2L 2C'], l)
+
+ let l = []
+ enew
+ exe "+" . XdoCmd
+ call assert_equal(['Xtestfile3 3L 1C'], l)
+
+ " Invalid error lines test
+ let l = []
+ enew
+ exe "silent! 27" . XdoCmd
+ exe "silent! 4,5" . XdoCmd
+ call assert_equal([], l)
+
+ " Run commands from an unsaved buffer
+ let v:errmsg=''
+ let l = []
+ enew
+ setlocal modified
+ exe "silent! 2,2" . XdoCmd
+ if v:errmsg !~# 'No write since last change'
+ call add(v:errors, 'Unsaved file change test failed')
+ endif
+
+ " If the executed command fails, then the operation should be aborted
+ enew!
+ let subst_count = 0
+ exe "silent!" . Xdo . " s/Line/xLine/ | let subst_count += 1"
+ if subst_count != 1 || getline('.') != 'xLine1'
+ call add(v:errors, 'Abort command on error test failed')
+ endif
+
+ let l = []
+ exe "2,2" . Xdo . "! call add(l, GetRuler())"
+ call assert_equal(['Xtestfile2 2L 2C'], l)
+
+ " List with no valid error entries
+ let l = []
+ edit! +2 Xtestfile1
+ exe Xgetexpr . " ['non-error 1', 'non-error 2', 'non-error 3']"
+ exe XdoCmd
+ call assert_equal([], l)
+ exe "silent! 2" . XdoCmd
+ call assert_equal([], l)
+ let v:errmsg=''
+ exe "%" . XdoCmd
+ exe "1,$" . XdoCmd
+ exe "." . XdoCmd
+ call assert_equal('', v:errmsg)
+
+ " List with only one valid entry
+ let l = []
+ exe Xgetexpr . " ['Xtestfile3:3:1:Line3']"
+ exe XdoCmd
+ call assert_equal(['Xtestfile3 3L 1C'], l)
+
+endfunction
+
+" Tests for the :cfdo and :lfdo commands
+function XfdoTests(cchar)
+ enew
+
+ " Shortcuts for calling the cfdo and lfdo commands
+ let Xfdo = a:cchar . 'fdo'
+ let Xgetexpr = a:cchar . 'getexpr'
+ let XfdoCmd = Xfdo . ' call add(l, GetRuler())'
+ let Xpfile = a:cchar. 'pfile'
+
+ " Clear the quickfix/location list
+ exe Xgetexpr . " []"
+
+ " Try with an empty list
+ let l = []
+ exe XfdoCmd
+ call assert_equal([], l)
+
+ " Populate the list and then try
+ exe Xgetexpr . " ['non-error 1', 'Xtestfile1:1:3:Line1', 'Xtestfile1:2:1:Line2', 'non-error 2', 'Xtestfile2:2:2:Line2', 'non-error 3', 'Xtestfile3:2:3:Line2', 'Xtestfile3:3:1:Line3']"
+
+ let l = []
+ exe XfdoCmd
+ call assert_equal(['Xtestfile1 1L 3C', 'Xtestfile2 2L 2C', 'Xtestfile3 2L 3C'], l)
+
+ " Run command only on selected error lines
+ let l = []
+ exe "2,3" . XfdoCmd
+ call assert_equal(['Xtestfile2 2L 2C', 'Xtestfile3 2L 3C'], l)
+
+ " Boundary condition tests
+ let l = []
+ exe "3" . XfdoCmd
+ call assert_equal(['Xtestfile3 2L 3C'], l)
+
+ " Range test commands
+ let l = []
+ exe "%" . XfdoCmd
+ call assert_equal(['Xtestfile1 1L 3C', 'Xtestfile2 2L 2C', 'Xtestfile3 2L 3C'], l)
+
+ let l = []
+ exe "1,$" . XfdoCmd
+ call assert_equal(['Xtestfile1 1L 3C', 'Xtestfile2 2L 2C', 'Xtestfile3 2L 3C'], l)
+
+ let l = []
+ exe Xpfile
+ exe "." . XfdoCmd
+ call assert_equal(['Xtestfile2 2L 2C'], l)
+
+ " List with only one valid entry
+ let l = []
+ exe Xgetexpr . " ['Xtestfile2:2:5:Line2']"
+ exe XfdoCmd
+ call assert_equal(['Xtestfile2 2L 5C'], l)
+
+endfunction
+
+" Tests for cdo and cfdo
+function Test_cdo()
+ call XdoTests('c')
+ call XfdoTests('c')
+endfunction
+
+" Tests for ldo and lfdo
+function Test_ldo()
+ call XdoTests('l')
+ call XfdoTests('l')
+endfunction
diff --git a/src/testdir/test_changedtick.vim b/src/testdir/test_changedtick.vim
new file mode 100644
index 0000000..3a91bb5
--- /dev/null
+++ b/src/testdir/test_changedtick.vim
@@ -0,0 +1,57 @@
+" Tests for b:changedtick
+
+func Test_changedtick_increments()
+ new
+ " New buffer has an empty line, tick starts at 2.
+ let expected = 2
+ call assert_equal(expected, b:changedtick)
+ call assert_equal(expected, b:['changedtick'])
+ call setline(1, 'hello')
+ let expected += 1
+ call assert_equal(expected, b:changedtick)
+ call assert_equal(expected, b:['changedtick'])
+ undo
+ " Somehow undo counts as two changes.
+ let expected += 2
+ call assert_equal(expected, b:changedtick)
+ call assert_equal(expected, b:['changedtick'])
+ bwipe!
+endfunc
+
+func Test_changedtick_dict_entry()
+ let d = b:
+ call assert_equal(b:changedtick, d['changedtick'])
+endfunc
+
+func Test_changedtick_bdel()
+ new
+ let bnr = bufnr('%')
+ let v = b:changedtick
+ bdel
+ " Delete counts as a change too.
+ call assert_equal(v + 1, getbufvar(bnr, 'changedtick'))
+endfunc
+
+func Test_changedtick_islocked()
+ call assert_equal(0, islocked('b:changedtick'))
+ let d = b:
+ call assert_equal(0, islocked('d.changedtick'))
+endfunc
+
+func Test_changedtick_fixed()
+ call assert_fails('let b:changedtick = 4', 'E46:')
+ call assert_fails('let b:["changedtick"] = 4', 'E46:')
+
+ call assert_fails('lockvar b:changedtick', 'E940:')
+ call assert_fails('lockvar b:["changedtick"]', 'E46:')
+ call assert_fails('unlockvar b:changedtick', 'E940:')
+ call assert_fails('unlockvar b:["changedtick"]', 'E46:')
+ call assert_fails('unlet b:changedtick', 'E795:')
+ call assert_fails('unlet b:["changedtick"]', 'E46:')
+
+ let d = b:
+ call assert_fails('lockvar d["changedtick"]', 'E46:')
+ call assert_fails('unlockvar d["changedtick"]', 'E46:')
+ call assert_fails('unlet d["changedtick"]', 'E46:')
+
+endfunc
diff --git a/src/testdir/test_changelist.vim b/src/testdir/test_changelist.vim
new file mode 100644
index 0000000..dd6ea96
--- /dev/null
+++ b/src/testdir/test_changelist.vim
@@ -0,0 +1,48 @@
+" Tests for the changelist functionality
+
+" Tests for the getchangelist() function
+func Test_getchangelist()
+ if !has("jumplist")
+ return
+ endif
+
+ bwipe!
+ enew
+ call assert_equal([], getchangelist(10))
+ call assert_equal([[], 0], getchangelist('%'))
+
+ call writefile(['line1', 'line2', 'line3'], 'Xfile1.txt')
+ call writefile(['line1', 'line2', 'line3'], 'Xfile2.txt')
+
+ edit Xfile1.txt
+ exe "normal 1Goline\<C-G>u1.1"
+ exe "normal 3Goline\<C-G>u2.1"
+ exe "normal 5Goline\<C-G>u3.1"
+ normal g;
+ call assert_equal([[
+ \ {'lnum' : 2, 'col' : 4, 'coladd' : 0},
+ \ {'lnum' : 4, 'col' : 4, 'coladd' : 0},
+ \ {'lnum' : 6, 'col' : 4, 'coladd' : 0}], 2],
+ \ getchangelist('%'))
+
+ hide edit Xfile2.txt
+ exe "normal 1GOline\<C-G>u1.0"
+ exe "normal 2Goline\<C-G>u2.0"
+ call assert_equal([[
+ \ {'lnum' : 1, 'col' : 6, 'coladd' : 0},
+ \ {'lnum' : 3, 'col' : 6, 'coladd' : 0}], 2],
+ \ getchangelist('%'))
+ hide enew
+
+ call assert_equal([[
+ \ {'lnum' : 2, 'col' : 4, 'coladd' : 0},
+ \ {'lnum' : 4, 'col' : 4, 'coladd' : 0},
+ \ {'lnum' : 6, 'col' : 4, 'coladd' : 0}], 3], getchangelist(2))
+ call assert_equal([[
+ \ {'lnum' : 1, 'col' : 6, 'coladd' : 0},
+ \ {'lnum' : 3, 'col' : 6, 'coladd' : 0}], 2], getchangelist(3))
+
+ bwipe!
+ call delete('Xfile1.txt')
+ call delete('Xfile2.txt')
+endfunc
diff --git a/src/testdir/test_channel.py b/src/testdir/test_channel.py
new file mode 100644
index 0000000..bafa9db
--- /dev/null
+++ b/src/testdir/test_channel.py
@@ -0,0 +1,269 @@
+#!/usr/bin/python
+#
+# Server that will accept connections from a Vim channel.
+# Used by test_channel.vim.
+#
+# This requires Python 2.6 or later.
+
+from __future__ import print_function
+import json
+import socket
+import sys
+import time
+import threading
+
+try:
+ # Python 3
+ import socketserver
+except ImportError:
+ # Python 2
+ import SocketServer as socketserver
+
+class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
+
+ def handle(self):
+ print("=== socket opened ===")
+ while True:
+ try:
+ received = self.request.recv(4096).decode('utf-8')
+ except socket.error:
+ print("=== socket error ===")
+ break
+ except IOError:
+ print("=== socket closed ===")
+ break
+ if received == '':
+ print("=== socket closed ===")
+ break
+ print("received: {0}".format(received))
+
+ # We may receive two messages at once. Take the part up to the
+ # newline, which should be after the matching "]".
+ todo = received
+ while todo != '':
+ splitidx = todo.find('\n')
+ if splitidx < 0:
+ used = todo
+ todo = ''
+ else:
+ used = todo[:splitidx]
+ todo = todo[splitidx + 1:]
+ if used != received:
+ print("using: {0}".format(used))
+
+ try:
+ decoded = json.loads(used)
+ except ValueError:
+ print("json decoding failed")
+ decoded = [-1, '']
+
+ # Send a response if the sequence number is positive.
+ if decoded[0] >= 0:
+ if decoded[1] == 'hello!':
+ # simply send back a string
+ response = "got it"
+ elif decoded[1] == 'malformed1':
+ cmd = '["ex",":"]wrong!["ex","smi"]'
+ print("sending: {0}".format(cmd))
+ self.request.sendall(cmd.encode('utf-8'))
+ response = "ok"
+ # Need to wait for Vim to give up, otherwise it
+ # sometimes fails on OS X.
+ time.sleep(0.2)
+ elif decoded[1] == 'malformed2':
+ cmd = '"unterminated string'
+ print("sending: {0}".format(cmd))
+ self.request.sendall(cmd.encode('utf-8'))
+ response = "ok"
+ # Need to wait for Vim to give up, otherwise the double
+ # quote in the "ok" response terminates the string.
+ time.sleep(0.2)
+ elif decoded[1] == 'malformed3':
+ cmd = '["ex","missing ]"'
+ print("sending: {0}".format(cmd))
+ self.request.sendall(cmd.encode('utf-8'))
+ response = "ok"
+ # Need to wait for Vim to give up, otherwise the ]
+ # in the "ok" response terminates the list.
+ time.sleep(0.2)
+ elif decoded[1] == 'split':
+ cmd = '["ex","let '
+ print("sending: {0}".format(cmd))
+ self.request.sendall(cmd.encode('utf-8'))
+ time.sleep(0.01)
+ cmd = 'g:split = 123"]'
+ print("sending: {0}".format(cmd))
+ self.request.sendall(cmd.encode('utf-8'))
+ response = "ok"
+ elif decoded[1].startswith("echo "):
+ # send back the argument
+ response = decoded[1][5:]
+ elif decoded[1] == 'make change':
+ # Send two ex commands at the same time, before
+ # replying to the request.
+ cmd = '["ex","call append(\\"$\\",\\"added1\\")"]'
+ cmd += '["ex","call append(\\"$\\",\\"added2\\")"]'
+ print("sending: {0}".format(cmd))
+ self.request.sendall(cmd.encode('utf-8'))
+ response = "ok"
+ elif decoded[1] == 'bad command':
+ cmd = '["ex","foo bar"]'
+ print("sending: {0}".format(cmd))
+ self.request.sendall(cmd.encode('utf-8'))
+ response = "ok"
+ elif decoded[1] == 'do normal':
+ # Send a normal command.
+ cmd = '["normal","G$s more\u001b"]'
+ print("sending: {0}".format(cmd))
+ self.request.sendall(cmd.encode('utf-8'))
+ response = "ok"
+ elif decoded[1] == 'eval-works':
+ # Send an eval request. We ignore the response.
+ cmd = '["expr","\\"foo\\" . 123", -1]'
+ print("sending: {0}".format(cmd))
+ self.request.sendall(cmd.encode('utf-8'))
+ response = "ok"
+ elif decoded[1] == 'eval-special':
+ # Send an eval request. We ignore the response.
+ cmd = '["expr","\\"foo\x7f\x10\x01bar\\"", -2]'
+ print("sending: {0}".format(cmd))
+ self.request.sendall(cmd.encode('utf-8'))
+ response = "ok"
+ elif decoded[1] == 'eval-getline':
+ # Send an eval request. We ignore the response.
+ cmd = '["expr","getline(3)", -3]'
+ print("sending: {0}".format(cmd))
+ self.request.sendall(cmd.encode('utf-8'))
+ response = "ok"
+ elif decoded[1] == 'eval-fails':
+ # Send an eval request that will fail.
+ cmd = '["expr","xxx", -4]'
+ print("sending: {0}".format(cmd))
+ self.request.sendall(cmd.encode('utf-8'))
+ response = "ok"
+ elif decoded[1] == 'eval-error':
+ # Send an eval request that works but the result can't
+ # be encoded.
+ cmd = '["expr","function(\\"tr\\")", -5]'
+ print("sending: {0}".format(cmd))
+ self.request.sendall(cmd.encode('utf-8'))
+ response = "ok"
+ elif decoded[1] == 'eval-bad':
+ # Send an eval request missing the third argument.
+ cmd = '["expr","xxx"]'
+ print("sending: {0}".format(cmd))
+ self.request.sendall(cmd.encode('utf-8'))
+ response = "ok"
+ elif decoded[1] == 'an expr':
+ # Send an expr request.
+ cmd = '["expr","setline(\\"$\\", [\\"one\\",\\"two\\",\\"three\\"])"]'
+ print("sending: {0}".format(cmd))
+ self.request.sendall(cmd.encode('utf-8'))
+ response = "ok"
+ elif decoded[1] == 'call-func':
+ cmd = '["call","MyFunction",[1,2,3], 0]'
+ print("sending: {0}".format(cmd))
+ self.request.sendall(cmd.encode('utf-8'))
+ response = "ok"
+ elif decoded[1] == 'redraw':
+ cmd = '["redraw",""]'
+ print("sending: {0}".format(cmd))
+ self.request.sendall(cmd.encode('utf-8'))
+ response = "ok"
+ elif decoded[1] == 'redraw!':
+ cmd = '["redraw","force"]'
+ print("sending: {0}".format(cmd))
+ self.request.sendall(cmd.encode('utf-8'))
+ response = "ok"
+ elif decoded[1] == 'empty-request':
+ cmd = '[]'
+ print("sending: {0}".format(cmd))
+ self.request.sendall(cmd.encode('utf-8'))
+ response = "ok"
+ elif decoded[1] == 'eval-result':
+ # Send back the last received eval result.
+ response = last_eval
+ elif decoded[1] == 'call me':
+ cmd = '[0,"we called you"]'
+ print("sending: {0}".format(cmd))
+ self.request.sendall(cmd.encode('utf-8'))
+ response = "ok"
+ elif decoded[1] == 'call me again':
+ cmd = '[0,"we did call you"]'
+ print("sending: {0}".format(cmd))
+ self.request.sendall(cmd.encode('utf-8'))
+ response = ""
+ elif decoded[1] == 'send zero':
+ cmd = '[0,"zero index"]'
+ print("sending: {0}".format(cmd))
+ self.request.sendall(cmd.encode('utf-8'))
+ response = "sent zero"
+ elif decoded[1] == 'close me':
+ print("closing")
+ self.request.close()
+ response = ""
+ elif decoded[1] == 'wait a bit':
+ time.sleep(0.2)
+ response = "waited"
+ elif decoded[1] == '!quit!':
+ # we're done
+ self.server.shutdown()
+ return
+ elif decoded[1] == '!crash!':
+ # Crash!
+ 42 / 0
+ else:
+ response = "what?"
+
+ if response == "":
+ print("no response")
+ else:
+ encoded = json.dumps([decoded[0], response])
+ print("sending: {0}".format(encoded))
+ self.request.sendall(encoded.encode('utf-8'))
+
+ # Negative numbers are used for "eval" responses.
+ elif decoded[0] < 0:
+ last_eval = decoded
+
+class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
+ pass
+
+def writePortInFile(port):
+ # Write the port number in Xportnr, so that the test knows it.
+ f = open("Xportnr", "w")
+ f.write("{0}".format(port))
+ f.close()
+
+if __name__ == "__main__":
+ HOST, PORT = "localhost", 0
+
+ # Wait half a second before opening the port to test waittime in ch_open().
+ # We do want to get the port number, get that first. We cannot open the
+ # socket, guess a port is free.
+ if len(sys.argv) >= 2 and sys.argv[1] == 'delay':
+ PORT = 13684
+ writePortInFile(PORT)
+
+ print("Wait for it...")
+ time.sleep(0.5)
+
+ server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)
+ ip, port = server.server_address
+
+ # Start a thread with the server. That thread will then start a new thread
+ # for each connection.
+ server_thread = threading.Thread(target=server.serve_forever)
+ server_thread.start()
+
+ writePortInFile(port)
+
+ print("Listening on port {0}".format(port))
+
+ # Main thread terminates, but the server continues running
+ # until server.shutdown() is called.
+ try:
+ while server_thread.isAlive():
+ server_thread.join(1)
+ except (KeyboardInterrupt, SystemExit):
+ server.shutdown()
diff --git a/src/testdir/test_channel.vim b/src/testdir/test_channel.vim
new file mode 100644
index 0000000..2aef3e1
--- /dev/null
+++ b/src/testdir/test_channel.vim
@@ -0,0 +1,2028 @@
+" Test for channel functions.
+
+if !has('channel')
+ finish
+endif
+
+source shared.vim
+
+let s:python = PythonProg()
+if s:python == ''
+ " Can't run this test without Python.
+ finish
+endif
+
+" Uncomment the next line to see what happens. Output is in
+" src/testdir/channellog.
+" call ch_logfile('channellog', 'w')
+
+let s:chopt = {}
+
+" Run "testfunc" after sarting the server and stop the server afterwards.
+func s:run_server(testfunc, ...)
+ call RunServer('test_channel.py', a:testfunc, a:000)
+endfunc
+
+" Return a list of open files.
+" Can be used to make sure no resources leaked.
+" Returns an empty list on systems where this is not supported.
+func s:get_resources()
+ let pid = getpid()
+
+ if executable('lsof')
+ return systemlist('lsof -p ' . pid . ' | awk ''$4~/^[0-9]*[rwu]$/&&$5=="REG"{print$NF}''')
+ elseif isdirectory('/proc/' . pid . '/fd/')
+ return systemlist('readlink /proc/' . pid . '/fd/* | grep -v ''^/dev/''')
+ else
+ return []
+ endif
+endfunc
+
+let g:Ch_responseMsg = ''
+func Ch_requestHandler(handle, msg)
+ let g:Ch_responseHandle = a:handle
+ let g:Ch_responseMsg = a:msg
+endfunc
+
+func Ch_communicate(port)
+ " Avoid dropping messages, since we don't use a callback here.
+ let s:chopt.drop = 'never'
+ " Also add the noblock flag to try it out.
+ let s:chopt.noblock = 1
+ let handle = ch_open('localhost:' . a:port, s:chopt)
+ unlet s:chopt.drop
+ unlet s:chopt.noblock
+ if ch_status(handle) == "fail"
+ call assert_report("Can't open channel")
+ return
+ endif
+ if has('job')
+ " check that getjob without a job is handled correctly
+ call assert_equal('no process', string(ch_getjob(handle)))
+ endif
+ let dict = ch_info(handle)
+ call assert_true(dict.id != 0)
+ call assert_equal('open', dict.status)
+ call assert_equal(a:port, string(dict.port))
+ call assert_equal('open', dict.sock_status)
+ call assert_equal('socket', dict.sock_io)
+
+ " Simple string request and reply.
+ call assert_equal('got it', ch_evalexpr(handle, 'hello!'))
+
+ " Malformed command should be ignored.
+ call assert_equal('ok', ch_evalexpr(handle, 'malformed1'))
+ call assert_equal('ok', ch_evalexpr(handle, 'malformed2'))
+ call assert_equal('ok', ch_evalexpr(handle, 'malformed3'))
+
+ " split command should work
+ call assert_equal('ok', ch_evalexpr(handle, 'split'))
+ call WaitFor('exists("g:split")')
+ call assert_equal(123, g:split)
+
+ " string with ][ should work
+ call assert_equal('this][that', ch_evalexpr(handle, 'echo this][that'))
+
+ " nothing to read now
+ call assert_equal(0, ch_canread(handle))
+
+ " sending three messages quickly then reading should work
+ for i in range(3)
+ call ch_sendexpr(handle, 'echo hello ' . i)
+ endfor
+ call assert_equal('hello 0', ch_read(handle)[1])
+ call assert_equal('hello 1', ch_read(handle)[1])
+ call assert_equal('hello 2', ch_read(handle)[1])
+
+ " Request that triggers sending two ex commands. These will usually be
+ " handled before getting the response, but it's not guaranteed, thus wait a
+ " tiny bit for the commands to get executed.
+ call assert_equal('ok', ch_evalexpr(handle, 'make change'))
+ call WaitForAssert({-> assert_equal("added2", getline("$"))})
+ call assert_equal('added1', getline(line('$') - 1))
+
+ " Request command "foo bar", which fails silently.
+ call assert_equal('ok', ch_evalexpr(handle, 'bad command'))
+ call WaitForAssert({-> assert_match("E492:.*foo bar", v:errmsg)})
+
+ call assert_equal('ok', ch_evalexpr(handle, 'do normal', {'timeout': 100}))
+ call WaitForAssert({-> assert_equal('added more', getline('$'))})
+
+ " Send a request with a specific handler.
+ call ch_sendexpr(handle, 'hello!', {'callback': 'Ch_requestHandler'})
+ call WaitFor('exists("g:Ch_responseHandle")')
+ if !exists('g:Ch_responseHandle')
+ call assert_report('g:Ch_responseHandle was not set')
+ else
+ call assert_equal(handle, g:Ch_responseHandle)
+ unlet g:Ch_responseHandle
+ endif
+ call assert_equal('got it', g:Ch_responseMsg)
+
+ let g:Ch_responseMsg = ''
+ call ch_sendexpr(handle, 'hello!', {'callback': function('Ch_requestHandler')})
+ call WaitFor('exists("g:Ch_responseHandle")')
+ if !exists('g:Ch_responseHandle')
+ call assert_report('g:Ch_responseHandle was not set')
+ else
+ call assert_equal(handle, g:Ch_responseHandle)
+ unlet g:Ch_responseHandle
+ endif
+ call assert_equal('got it', g:Ch_responseMsg)
+
+ " Using lambda.
+ let g:Ch_responseMsg = ''
+ call ch_sendexpr(handle, 'hello!', {'callback': {a, b -> Ch_requestHandler(a, b)}})
+ call WaitFor('exists("g:Ch_responseHandle")')
+ if !exists('g:Ch_responseHandle')
+ call assert_report('g:Ch_responseHandle was not set')
+ else
+ call assert_equal(handle, g:Ch_responseHandle)
+ unlet g:Ch_responseHandle
+ endif
+ call assert_equal('got it', g:Ch_responseMsg)
+
+ " Collect garbage, tests that our handle isn't collected.
+ call test_garbagecollect_now()
+
+ " check setting options (without testing the effect)
+ call ch_setoptions(handle, {'callback': 's:NotUsed'})
+ call ch_setoptions(handle, {'timeout': 1111})
+ call ch_setoptions(handle, {'mode': 'json'})
+ call assert_fails("call ch_setoptions(handle, {'waittime': 111})", "E475")
+ call ch_setoptions(handle, {'callback': ''})
+ call ch_setoptions(handle, {'drop': 'never'})
+ call ch_setoptions(handle, {'drop': 'auto'})
+ call assert_fails("call ch_setoptions(handle, {'drop': 'bad'})", "E475")
+
+ " Send an eval request that works.
+ call assert_equal('ok', ch_evalexpr(handle, 'eval-works'))
+ sleep 10m
+ call assert_equal([-1, 'foo123'], ch_evalexpr(handle, 'eval-result'))
+
+ " Send an eval request with special characters.
+ call assert_equal('ok', ch_evalexpr(handle, 'eval-special'))
+ sleep 10m
+ call assert_equal([-2, "foo\x7f\x10\x01bar"], ch_evalexpr(handle, 'eval-result'))
+
+ " Send an eval request to get a line with special characters.
+ call setline(3, "a\nb\<CR>c\x01d\x7fe")
+ call assert_equal('ok', ch_evalexpr(handle, 'eval-getline'))
+ sleep 10m
+ call assert_equal([-3, "a\nb\<CR>c\x01d\x7fe"], ch_evalexpr(handle, 'eval-result'))
+
+ " Send an eval request that fails.
+ call assert_equal('ok', ch_evalexpr(handle, 'eval-fails'))
+ sleep 10m
+ call assert_equal([-4, 'ERROR'], ch_evalexpr(handle, 'eval-result'))
+
+ " Send an eval request that works but can't be encoded.
+ call assert_equal('ok', ch_evalexpr(handle, 'eval-error'))
+ sleep 10m
+ call assert_equal([-5, 'ERROR'], ch_evalexpr(handle, 'eval-result'))
+
+ " Send a bad eval request. There will be no response.
+ call assert_equal('ok', ch_evalexpr(handle, 'eval-bad'))
+ sleep 10m
+ call assert_equal([-5, 'ERROR'], ch_evalexpr(handle, 'eval-result'))
+
+ " Send an expr request
+ call assert_equal('ok', ch_evalexpr(handle, 'an expr'))
+ call WaitForAssert({-> assert_equal('three', getline('$'))})
+ call assert_equal('one', getline(line('$') - 2))
+ call assert_equal('two', getline(line('$') - 1))
+
+ " Request a redraw, we don't check for the effect.
+ call assert_equal('ok', ch_evalexpr(handle, 'redraw'))
+ call assert_equal('ok', ch_evalexpr(handle, 'redraw!'))
+
+ call assert_equal('ok', ch_evalexpr(handle, 'empty-request'))
+
+ " Reading while there is nothing available.
+ call assert_equal(v:none, ch_read(handle, {'timeout': 0}))
+ let start = reltime()
+ call assert_equal(v:none, ch_read(handle, {'timeout': 333}))
+ let elapsed = reltime(start)
+ call assert_true(reltimefloat(elapsed) > 0.3)
+ call assert_true(reltimefloat(elapsed) < 0.6)
+
+ " Send without waiting for a response, then wait for a response.
+ call ch_sendexpr(handle, 'wait a bit')
+ let resp = ch_read(handle)
+ call assert_equal(type([]), type(resp))
+ call assert_equal(type(11), type(resp[0]))
+ call assert_equal('waited', resp[1])
+
+ " make the server quit, can't check if this works, should not hang.
+ call ch_sendexpr(handle, '!quit!')
+endfunc
+
+func Test_communicate()
+ call ch_log('Test_communicate()')
+ call s:run_server('Ch_communicate')
+endfunc
+
+" Test that we can open two channels.
+func Ch_two_channels(port)
+ let handle = ch_open('localhost:' . a:port, s:chopt)
+ call assert_equal(v:t_channel, type(handle))
+ if ch_status(handle) == "fail"
+ call assert_report("Can't open channel")
+ return
+ endif
+
+ call assert_equal('got it', ch_evalexpr(handle, 'hello!'))
+
+ let newhandle = ch_open('localhost:' . a:port, s:chopt)
+ if ch_status(newhandle) == "fail"
+ call assert_report("Can't open second channel")
+ return
+ endif
+ call assert_equal('got it', ch_evalexpr(newhandle, 'hello!'))
+ call assert_equal('got it', ch_evalexpr(handle, 'hello!'))
+
+ call ch_close(handle)
+ call assert_equal('got it', ch_evalexpr(newhandle, 'hello!'))
+
+ call ch_close(newhandle)
+endfunc
+
+func Test_two_channels()
+ call ch_log('Test_two_channels()')
+ call s:run_server('Ch_two_channels')
+endfunc
+
+" Test that a server crash is handled gracefully.
+func Ch_server_crash(port)
+ let handle = ch_open('localhost:' . a:port, s:chopt)
+ if ch_status(handle) == "fail"
+ call assert_report("Can't open channel")
+ return
+ endif
+
+ call ch_evalexpr(handle, '!crash!')
+
+ sleep 10m
+endfunc
+
+func Test_server_crash()
+ call ch_log('Test_server_crash()')
+ call s:run_server('Ch_server_crash')
+endfunc
+
+"""""""""
+
+func Ch_handler(chan, msg)
+ call ch_log('Ch_handler()')
+ unlet g:Ch_reply
+ let g:Ch_reply = a:msg
+endfunc
+
+func Ch_channel_handler(port)
+ let handle = ch_open('localhost:' . a:port, s:chopt)
+ if ch_status(handle) == "fail"
+ call assert_report("Can't open channel")
+ return
+ endif
+
+ " Test that it works while waiting on a numbered message.
+ call assert_equal('ok', ch_evalexpr(handle, 'call me'))
+ call WaitForAssert({-> assert_equal('we called you', g:Ch_reply)})
+
+ " Test that it works while not waiting on a numbered message.
+ call ch_sendexpr(handle, 'call me again')
+ call WaitForAssert({-> assert_equal('we did call you', g:Ch_reply)})
+endfunc
+
+func Test_channel_handler()
+ call ch_log('Test_channel_handler()')
+ let g:Ch_reply = ""
+ let s:chopt.callback = 'Ch_handler'
+ call s:run_server('Ch_channel_handler')
+ let g:Ch_reply = ""
+ let s:chopt.callback = function('Ch_handler')
+ call s:run_server('Ch_channel_handler')
+ unlet s:chopt.callback
+endfunc
+
+"""""""""
+
+let g:Ch_reply = ''
+func Ch_zeroHandler(chan, msg)
+ unlet g:Ch_reply
+ let g:Ch_reply = a:msg
+endfunc
+
+let g:Ch_zero_reply = ''
+func Ch_oneHandler(chan, msg)
+ unlet g:Ch_zero_reply
+ let g:Ch_zero_reply = a:msg
+endfunc
+
+func Ch_channel_zero(port)
+ let handle = ch_open('localhost:' . a:port, s:chopt)
+ if ch_status(handle) == "fail"
+ call assert_report("Can't open channel")
+ return
+ endif
+
+ " Check that eval works.
+ call assert_equal('got it', ch_evalexpr(handle, 'hello!'))
+
+ " Check that eval works if a zero id message is sent back.
+ let g:Ch_reply = ''
+ call assert_equal('sent zero', ch_evalexpr(handle, 'send zero'))
+ if s:has_handler
+ call WaitForAssert({-> assert_equal('zero index', g:Ch_reply)})
+ else
+ sleep 20m
+ call assert_equal('', g:Ch_reply)
+ endif
+
+ " Check that handler works if a zero id message is sent back.
+ let g:Ch_reply = ''
+ let g:Ch_zero_reply = ''
+ call ch_sendexpr(handle, 'send zero', {'callback': 'Ch_oneHandler'})
+ call WaitForAssert({-> assert_equal('sent zero', g:Ch_zero_reply)})
+ if s:has_handler
+ call assert_equal('zero index', g:Ch_reply)
+ else
+ call assert_equal('', g:Ch_reply)
+ endif
+endfunc
+
+func Test_zero_reply()
+ call ch_log('Test_zero_reply()')
+ " Run with channel handler
+ let s:has_handler = 1
+ let s:chopt.callback = 'Ch_zeroHandler'
+ call s:run_server('Ch_channel_zero')
+ unlet s:chopt.callback
+
+ " Run without channel handler
+ let s:has_handler = 0
+ call s:run_server('Ch_channel_zero')
+endfunc
+
+"""""""""
+
+let g:Ch_reply1 = ""
+func Ch_handleRaw1(chan, msg)
+ unlet g:Ch_reply1
+ let g:Ch_reply1 = a:msg
+endfunc
+
+let g:Ch_reply2 = ""
+func Ch_handleRaw2(chan, msg)
+ unlet g:Ch_reply2
+ let g:Ch_reply2 = a:msg
+endfunc
+
+let g:Ch_reply3 = ""
+func Ch_handleRaw3(chan, msg)
+ unlet g:Ch_reply3
+ let g:Ch_reply3 = a:msg
+endfunc
+
+func Ch_raw_one_time_callback(port)
+ let handle = ch_open('localhost:' . a:port, s:chopt)
+ if ch_status(handle) == "fail"
+ call assert_report("Can't open channel")
+ return
+ endif
+ call ch_setoptions(handle, {'mode': 'raw'})
+
+ " The messages are sent raw, we do our own JSON strings here.
+ call ch_sendraw(handle, "[1, \"hello!\"]\n", {'callback': 'Ch_handleRaw1'})
+ call WaitForAssert({-> assert_equal("[1, \"got it\"]", g:Ch_reply1)})
+ call ch_sendraw(handle, "[2, \"echo something\"]\n", {'callback': 'Ch_handleRaw2'})
+ call ch_sendraw(handle, "[3, \"wait a bit\"]\n", {'callback': 'Ch_handleRaw3'})
+ call WaitForAssert({-> assert_equal("[2, \"something\"]", g:Ch_reply2)})
+ " wait for the 200 msec delayed reply
+ call WaitForAssert({-> assert_equal("[3, \"waited\"]", g:Ch_reply3)})
+endfunc
+
+func Test_raw_one_time_callback()
+ call ch_log('Test_raw_one_time_callback()')
+ call s:run_server('Ch_raw_one_time_callback')
+endfunc
+
+"""""""""
+
+" Test that trying to connect to a non-existing port fails quickly.
+func Test_connect_waittime()
+ call ch_log('Test_connect_waittime()')
+ let start = reltime()
+ let handle = ch_open('localhost:9876', s:chopt)
+ if ch_status(handle) != "fail"
+ " Oops, port does exists.
+ call ch_close(handle)
+ else
+ let elapsed = reltime(start)
+ call assert_true(reltimefloat(elapsed) < 1.0)
+ endif
+
+ " We intend to use a socket that doesn't exist and wait for half a second
+ " before giving up. If the socket does exist it can fail in various ways.
+ " Check for "Connection reset by peer" to avoid flakyness.
+ let start = reltime()
+ try
+ let handle = ch_open('localhost:9867', {'waittime': 500})
+ if ch_status(handle) != "fail"
+ " Oops, port does exists.
+ call ch_close(handle)
+ else
+ " Failed connection should wait about 500 msec. Can be longer if the
+ " computer is busy with other things.
+ let elapsed = reltime(start)
+ call assert_true(reltimefloat(elapsed) > 0.3)
+ call assert_true(reltimefloat(elapsed) < 1.5)
+ endif
+ catch
+ if v:exception !~ 'Connection reset by peer'
+ call assert_report("Caught exception: " . v:exception)
+ endif
+ endtry
+endfunc
+
+"""""""""
+
+func Test_raw_pipe()
+ if !has('job')
+ return
+ endif
+ call ch_log('Test_raw_pipe()')
+ " Add a dummy close callback to avoid that messages are dropped when calling
+ " ch_canread().
+ " Also test the non-blocking option.
+ let job = job_start(s:python . " test_channel_pipe.py",
+ \ {'mode': 'raw', 'drop': 'never', 'noblock': 1})
+ call assert_equal(v:t_job, type(job))
+ call assert_equal("run", job_status(job))
+
+ call assert_equal("open", ch_status(job))
+ call assert_equal("open", ch_status(job), {"part": "out"})
+ call assert_equal("open", ch_status(job), {"part": "err"})
+ call assert_fails('call ch_status(job, {"in_mode": "raw"})', 'E475:')
+ call assert_fails('call ch_status(job, {"part": "in"})', 'E475:')
+
+ let dict = ch_info(job)
+ call assert_true(dict.id != 0)
+ call assert_equal('open', dict.status)
+ call assert_equal('open', dict.out_status)
+ call assert_equal('RAW', dict.out_mode)
+ call assert_equal('pipe', dict.out_io)
+ call assert_equal('open', dict.err_status)
+ call assert_equal('RAW', dict.err_mode)
+ call assert_equal('pipe', dict.err_io)
+
+ try
+ " For a change use the job where a channel is expected.
+ call ch_sendraw(job, "echo something\n")
+ let msg = ch_readraw(job)
+ call assert_equal("something\n", substitute(msg, "\r", "", 'g'))
+
+ call ch_sendraw(job, "double this\n")
+ let g:handle = job_getchannel(job)
+ call WaitFor('ch_canread(g:handle)')
+ unlet g:handle
+ let msg = ch_readraw(job)
+ call assert_equal("this\nAND this\n", substitute(msg, "\r", "", 'g'))
+
+ let g:Ch_reply = ""
+ call ch_sendraw(job, "double this\n", {'callback': 'Ch_handler'})
+ call WaitForAssert({-> assert_equal("this\nAND this\n", substitute(g:Ch_reply, "\r", "", 'g'))})
+
+ let reply = ch_evalraw(job, "quit\n", {'timeout': 100})
+ call assert_equal("Goodbye!\n", substitute(reply, "\r", "", 'g'))
+ finally
+ call job_stop(job)
+ endtry
+
+ let g:Ch_job = job
+ call WaitForAssert({-> assert_equal("dead", job_status(g:Ch_job))})
+ let info = job_info(job)
+ call assert_equal("dead", info.status)
+ call assert_equal("term", info.stoponexit)
+ call assert_equal(2, len(info.cmd))
+ call assert_equal("test_channel_pipe.py", info.cmd[1])
+
+ let found = 0
+ for j in job_info()
+ if j == job
+ let found += 1
+ endif
+ endfor
+ call assert_equal(1, found)
+endfunc
+
+func Test_raw_pipe_blob()
+ if !has('job')
+ return
+ endif
+ call ch_log('Test_raw_pipe_blob()')
+ " Add a dummy close callback to avoid that messages are dropped when calling
+ " ch_canread().
+ " Also test the non-blocking option.
+ let job = job_start(s:python . " test_channel_pipe.py",
+ \ {'mode': 'raw', 'drop': 'never', 'noblock': 1})
+ call assert_equal(v:t_job, type(job))
+ call assert_equal("run", job_status(job))
+
+ call assert_equal("open", ch_status(job))
+ call assert_equal("open", ch_status(job), {"part": "out"})
+
+ try
+ " Create a blob with the echo command and write it.
+ let blob = 0z00
+ let cmd = "echo something\n"
+ for i in range(0, len(cmd) - 1)
+ let blob[i] = char2nr(cmd[i])
+ endfor
+ call assert_equal(len(cmd), len(blob))
+ call ch_sendraw(job, blob)
+
+ " Read a blob with the reply.
+ let msg = ch_readblob(job)
+ let expected = 'something'
+ for i in range(0, len(expected) - 1)
+ call assert_equal(char2nr(expected[i]), msg[i])
+ endfor
+
+ let reply = ch_evalraw(job, "quit\n", {'timeout': 100})
+ call assert_equal("Goodbye!\n", substitute(reply, "\r", "", 'g'))
+ finally
+ call job_stop(job)
+ endtry
+
+ let g:Ch_job = job
+ call WaitForAssert({-> assert_equal("dead", job_status(g:Ch_job))})
+ let info = job_info(job)
+ call assert_equal("dead", info.status)
+endfunc
+
+func Test_nl_pipe()
+ if !has('job')
+ return
+ endif
+ call ch_log('Test_nl_pipe()')
+ let job = job_start([s:python, "test_channel_pipe.py"])
+ call assert_equal("run", job_status(job))
+ try
+ let handle = job_getchannel(job)
+ call ch_sendraw(handle, "echo something\n")
+ call assert_equal("something", ch_readraw(handle))
+
+ call ch_sendraw(handle, "echoerr wrong\n")
+ call assert_equal("wrong", ch_readraw(handle, {'part': 'err'}))
+
+ call ch_sendraw(handle, "double this\n")
+ call assert_equal("this", ch_readraw(handle))
+ call assert_equal("AND this", ch_readraw(handle))
+
+ call ch_sendraw(handle, "split this line\n")
+ call assert_equal("this linethis linethis line", ch_read(handle))
+
+ let reply = ch_evalraw(handle, "quit\n")
+ call assert_equal("Goodbye!", reply)
+ finally
+ call job_stop(job)
+ endtry
+endfunc
+
+func Test_nl_err_to_out_pipe()
+ if !has('job')
+ return
+ endif
+ call ch_logfile('Xlog')
+ call ch_log('Test_nl_err_to_out_pipe()')
+ let job = job_start(s:python . " test_channel_pipe.py", {'err_io': 'out'})
+ call assert_equal("run", job_status(job))
+ try
+ let handle = job_getchannel(job)
+ call ch_sendraw(handle, "echo something\n")
+ call assert_equal("something", ch_readraw(handle))
+
+ call ch_sendraw(handle, "echoerr wrong\n")
+ call assert_equal("wrong", ch_readraw(handle))
+ finally
+ call job_stop(job)
+ call ch_logfile('')
+ let loglines = readfile('Xlog')
+ call assert_true(len(loglines) > 10)
+ let found_test = 0
+ let found_send = 0
+ let found_recv = 0
+ let found_stop = 0
+ for l in loglines
+ if l =~ 'Test_nl_err_to_out_pipe'
+ let found_test = 1
+ endif
+ if l =~ 'SEND on.*echo something'
+ let found_send = 1
+ endif
+ if l =~ 'RECV on.*something'
+ let found_recv = 1
+ endif
+ if l =~ 'Stopping job with'
+ let found_stop = 1
+ endif
+ endfor
+ call assert_equal(1, found_test)
+ call assert_equal(1, found_send)
+ call assert_equal(1, found_recv)
+ call assert_equal(1, found_stop)
+ " On MS-Windows need to sleep for a moment to be able to delete the file.
+ sleep 10m
+ call delete('Xlog')
+ endtry
+endfunc
+
+func Stop_g_job()
+ call job_stop(g:job)
+ if has('win32')
+ " On MS-Windows the server must close the file handle before we are able
+ " to delete the file.
+ call WaitForAssert({-> assert_equal('dead', job_status(g:job))})
+ sleep 10m
+ endif
+endfunc
+
+func Test_nl_read_file()
+ if !has('job')
+ return
+ endif
+ call ch_log('Test_nl_read_file()')
+ call writefile(['echo something', 'echoerr wrong', 'double this'], 'Xinput')
+ let g:job = job_start(s:python . " test_channel_pipe.py",
+ \ {'in_io': 'file', 'in_name': 'Xinput'})
+ call assert_equal("run", job_status(g:job))
+ try
+ let handle = job_getchannel(g:job)
+ call assert_equal("something", ch_readraw(handle))
+ call assert_equal("wrong", ch_readraw(handle, {'part': 'err'}))
+ call assert_equal("this", ch_readraw(handle))
+ call assert_equal("AND this", ch_readraw(handle))
+ finally
+ call Stop_g_job()
+ call delete('Xinput')
+ endtry
+endfunc
+
+func Test_nl_write_out_file()
+ if !has('job')
+ return
+ endif
+ call ch_log('Test_nl_write_out_file()')
+ let g:job = job_start(s:python . " test_channel_pipe.py",
+ \ {'out_io': 'file', 'out_name': 'Xoutput'})
+ call assert_equal("run", job_status(g:job))
+ try
+ let handle = job_getchannel(g:job)
+ call ch_sendraw(handle, "echo line one\n")
+ call ch_sendraw(handle, "echo line two\n")
+ call ch_sendraw(handle, "double this\n")
+ call WaitForAssert({-> assert_equal(['line one', 'line two', 'this', 'AND this'], readfile('Xoutput'))})
+ finally
+ call Stop_g_job()
+ call assert_equal(-1, match(s:get_resources(), '\(^\|/\)Xoutput$'))
+ call delete('Xoutput')
+ endtry
+endfunc
+
+func Test_nl_write_err_file()
+ if !has('job')
+ return
+ endif
+ call ch_log('Test_nl_write_err_file()')
+ let g:job = job_start(s:python . " test_channel_pipe.py",
+ \ {'err_io': 'file', 'err_name': 'Xoutput'})
+ call assert_equal("run", job_status(g:job))
+ try
+ let handle = job_getchannel(g:job)
+ call ch_sendraw(handle, "echoerr line one\n")
+ call ch_sendraw(handle, "echoerr line two\n")
+ call ch_sendraw(handle, "doubleerr this\n")
+ call WaitForAssert({-> assert_equal(['line one', 'line two', 'this', 'AND this'], readfile('Xoutput'))})
+ finally
+ call Stop_g_job()
+ call delete('Xoutput')
+ endtry
+endfunc
+
+func Test_nl_write_both_file()
+ if !has('job')
+ return
+ endif
+ call ch_log('Test_nl_write_both_file()')
+ let g:job = job_start(s:python . " test_channel_pipe.py",
+ \ {'out_io': 'file', 'out_name': 'Xoutput', 'err_io': 'out'})
+ call assert_equal("run", job_status(g:job))
+ try
+ let handle = job_getchannel(g:job)
+ call ch_sendraw(handle, "echoerr line one\n")
+ call ch_sendraw(handle, "echo line two\n")
+ call ch_sendraw(handle, "double this\n")
+ call ch_sendraw(handle, "doubleerr that\n")
+ call WaitForAssert({-> assert_equal(['line one', 'line two', 'this', 'AND this', 'that', 'AND that'], readfile('Xoutput'))})
+ finally
+ call Stop_g_job()
+ call assert_equal(-1, match(s:get_resources(), '\(^\|/\)Xoutput$'))
+ call delete('Xoutput')
+ endtry
+endfunc
+
+func BufCloseCb(ch)
+ let g:Ch_bufClosed = 'yes'
+endfunc
+
+func Run_test_pipe_to_buffer(use_name, nomod, do_msg)
+ if !has('job')
+ return
+ endif
+ call ch_log('Test_pipe_to_buffer()')
+ let g:Ch_bufClosed = 'no'
+ let options = {'out_io': 'buffer', 'close_cb': 'BufCloseCb'}
+ let expected = ['', 'line one', 'line two', 'this', 'AND this', 'Goodbye!']
+ if a:use_name
+ let options['out_name'] = 'pipe-output'
+ if a:do_msg
+ let expected[0] = 'Reading from channel output...'
+ else
+ let options['out_msg'] = 0
+ call remove(expected, 0)
+ endif
+ else
+ sp pipe-output
+ let options['out_buf'] = bufnr('%')
+ quit
+ call remove(expected, 0)
+ endif
+ if a:nomod
+ let options['out_modifiable'] = 0
+ endif
+ let job = job_start(s:python . " test_channel_pipe.py", options)
+ call assert_equal("run", job_status(job))
+ try
+ let handle = job_getchannel(job)
+ call ch_sendraw(handle, "echo line one\n")
+ call ch_sendraw(handle, "echo line two\n")
+ call ch_sendraw(handle, "double this\n")
+ call ch_sendraw(handle, "quit\n")
+ sp pipe-output
+ call WaitFor('line("$") == ' . len(expected) . ' && g:Ch_bufClosed == "yes"')
+ call assert_equal(expected, getline(1, '$'))
+ if a:nomod
+ call assert_equal(0, &modifiable)
+ else
+ call assert_equal(1, &modifiable)
+ endif
+ call assert_equal('yes', g:Ch_bufClosed)
+ bwipe!
+ finally
+ call job_stop(job)
+ endtry
+endfunc
+
+func Test_pipe_to_buffer_name()
+ call Run_test_pipe_to_buffer(1, 0, 1)
+endfunc
+
+func Test_pipe_to_buffer_nr()
+ call Run_test_pipe_to_buffer(0, 0, 1)
+endfunc
+
+func Test_pipe_to_buffer_name_nomod()
+ call Run_test_pipe_to_buffer(1, 1, 1)
+endfunc
+
+func Test_pipe_to_buffer_name_nomsg()
+ call Run_test_pipe_to_buffer(1, 0, 1)
+endfunc
+
+func Test_close_output_buffer()
+ if !has('job')
+ return
+ endif
+ enew!
+ let test_lines = ['one', 'two']
+ call setline(1, test_lines)
+ call ch_log('Test_close_output_buffer()')
+ let options = {'out_io': 'buffer'}
+ let options['out_name'] = 'buffer-output'
+ let options['out_msg'] = 0
+ split buffer-output
+ let job = job_start(s:python . " test_channel_write.py", options)
+ call assert_equal("run", job_status(job))
+ try
+ call WaitForAssert({-> assert_equal(3, line('$'))})
+ quit!
+ sleep 100m
+ " Make sure the write didn't happen to the wrong buffer.
+ call assert_equal(test_lines, getline(1, line('$')))
+ call assert_equal(-1, bufwinnr('buffer-output'))
+ sbuf buffer-output
+ call assert_notequal(-1, bufwinnr('buffer-output'))
+ sleep 100m
+ close " no more writes
+ bwipe!
+ finally
+ call job_stop(job)
+ endtry
+endfunc
+
+func Run_test_pipe_err_to_buffer(use_name, nomod, do_msg)
+ if !has('job')
+ return
+ endif
+ call ch_log('Test_pipe_err_to_buffer()')
+ let options = {'err_io': 'buffer'}
+ let expected = ['', 'line one', 'line two', 'this', 'AND this']
+ if a:use_name
+ let options['err_name'] = 'pipe-err'
+ if a:do_msg
+ let expected[0] = 'Reading from channel error...'
+ else
+ let options['err_msg'] = 0
+ call remove(expected, 0)
+ endif
+ else
+ sp pipe-err
+ let options['err_buf'] = bufnr('%')
+ quit
+ call remove(expected, 0)
+ endif
+ if a:nomod
+ let options['err_modifiable'] = 0
+ endif
+ let job = job_start(s:python . " test_channel_pipe.py", options)
+ call assert_equal("run", job_status(job))
+ try
+ let handle = job_getchannel(job)
+ call ch_sendraw(handle, "echoerr line one\n")
+ call ch_sendraw(handle, "echoerr line two\n")
+ call ch_sendraw(handle, "doubleerr this\n")
+ call ch_sendraw(handle, "quit\n")
+ sp pipe-err
+ call WaitForAssert({-> assert_equal(expected, getline(1, '$'))})
+ if a:nomod
+ call assert_equal(0, &modifiable)
+ else
+ call assert_equal(1, &modifiable)
+ endif
+ bwipe!
+ finally
+ call job_stop(job)
+ endtry
+endfunc
+
+func Test_pipe_err_to_buffer_name()
+ call Run_test_pipe_err_to_buffer(1, 0, 1)
+endfunc
+
+func Test_pipe_err_to_buffer_nr()
+ call Run_test_pipe_err_to_buffer(0, 0, 1)
+endfunc
+
+func Test_pipe_err_to_buffer_name_nomod()
+ call Run_test_pipe_err_to_buffer(1, 1, 1)
+endfunc
+
+func Test_pipe_err_to_buffer_name_nomsg()
+ call Run_test_pipe_err_to_buffer(1, 0, 0)
+endfunc
+
+func Test_pipe_both_to_buffer()
+ if !has('job')
+ return
+ endif
+ call ch_log('Test_pipe_both_to_buffer()')
+ let job = job_start(s:python . " test_channel_pipe.py",
+ \ {'out_io': 'buffer', 'out_name': 'pipe-err', 'err_io': 'out'})
+ call assert_equal("run", job_status(job))
+ try
+ let handle = job_getchannel(job)
+ call ch_sendraw(handle, "echo line one\n")
+ call ch_sendraw(handle, "echoerr line two\n")
+ call ch_sendraw(handle, "double this\n")
+ call ch_sendraw(handle, "doubleerr that\n")
+ call ch_sendraw(handle, "quit\n")
+ sp pipe-err
+ call WaitForAssert({-> assert_equal(['Reading from channel output...', 'line one', 'line two', 'this', 'AND this', 'that', 'AND that', 'Goodbye!'], getline(1, '$'))})
+ bwipe!
+ finally
+ call job_stop(job)
+ endtry
+endfunc
+
+func Run_test_pipe_from_buffer(use_name)
+ if !has('job')
+ return
+ endif
+ call ch_log('Test_pipe_from_buffer()')
+
+ sp pipe-input
+ call setline(1, ['echo one', 'echo two', 'echo three'])
+ let options = {'in_io': 'buffer', 'block_write': 1}
+ if a:use_name
+ let options['in_name'] = 'pipe-input'
+ else
+ let options['in_buf'] = bufnr('%')
+ endif
+
+ let job = job_start(s:python . " test_channel_pipe.py", options)
+ call assert_equal("run", job_status(job))
+ try
+ let handle = job_getchannel(job)
+ call assert_equal('one', ch_read(handle))
+ call assert_equal('two', ch_read(handle))
+ call assert_equal('three', ch_read(handle))
+ bwipe!
+ finally
+ call job_stop(job)
+ endtry
+endfunc
+
+func Test_pipe_from_buffer_name()
+ call Run_test_pipe_from_buffer(1)
+endfunc
+
+func Test_pipe_from_buffer_nr()
+ call Run_test_pipe_from_buffer(0)
+endfunc
+
+func Run_pipe_through_sort(all, use_buffer)
+ if !executable('sort') || !has('job')
+ return
+ endif
+ let options = {'out_io': 'buffer', 'out_name': 'sortout'}
+ if a:use_buffer
+ split sortin
+ call setline(1, ['ccc', 'aaa', 'ddd', 'bbb', 'eee'])
+ let options.in_io = 'buffer'
+ let options.in_name = 'sortin'
+ endif
+ if !a:all
+ let options.in_top = 2
+ let options.in_bot = 4
+ endif
+ let job = job_start('sort', options)
+
+ if !a:use_buffer
+ call assert_equal("run", job_status(job))
+ call ch_sendraw(job, "ccc\naaa\nddd\nbbb\neee\n")
+ call ch_close_in(job)
+ endif
+
+ call WaitForAssert({-> assert_equal("dead", job_status(job))})
+
+ sp sortout
+ call WaitFor('line("$") > 3')
+ call assert_equal('Reading from channel output...', getline(1))
+ if a:all
+ call assert_equal(['aaa', 'bbb', 'ccc', 'ddd', 'eee'], getline(2, 6))
+ else
+ call assert_equal(['aaa', 'bbb', 'ddd'], getline(2, 4))
+ endif
+
+ call job_stop(job)
+ if a:use_buffer
+ bwipe! sortin
+ endif
+ bwipe! sortout
+endfunc
+
+func Test_pipe_through_sort_all()
+ call ch_log('Test_pipe_through_sort_all()')
+ call Run_pipe_through_sort(1, 1)
+endfunc
+
+func Test_pipe_through_sort_some()
+ call ch_log('Test_pipe_through_sort_some()')
+ call Run_pipe_through_sort(0, 1)
+endfunc
+
+func Test_pipe_through_sort_feed()
+ call ch_log('Test_pipe_through_sort_feed()')
+ call Run_pipe_through_sort(1, 0)
+endfunc
+
+func Test_pipe_to_nameless_buffer()
+ if !has('job')
+ return
+ endif
+ call ch_log('Test_pipe_to_nameless_buffer()')
+ let job = job_start(s:python . " test_channel_pipe.py",
+ \ {'out_io': 'buffer'})
+ call assert_equal("run", job_status(job))
+ try
+ let handle = job_getchannel(job)
+ call ch_sendraw(handle, "echo line one\n")
+ call ch_sendraw(handle, "echo line two\n")
+ exe ch_getbufnr(handle, "out") . 'sbuf'
+ call WaitFor('line("$") >= 3')
+ call assert_equal(['Reading from channel output...', 'line one', 'line two'], getline(1, '$'))
+ bwipe!
+ finally
+ call job_stop(job)
+ endtry
+endfunc
+
+func Test_pipe_to_buffer_json()
+ if !has('job')
+ return
+ endif
+ call ch_log('Test_pipe_to_buffer_json()')
+ let job = job_start(s:python . " test_channel_pipe.py",
+ \ {'out_io': 'buffer', 'out_mode': 'json'})
+ call assert_equal("run", job_status(job))
+ try
+ let handle = job_getchannel(job)
+ call ch_sendraw(handle, "echo [0, \"hello\"]\n")
+ call ch_sendraw(handle, "echo [-2, 12.34]\n")
+ exe ch_getbufnr(handle, "out") . 'sbuf'
+ call WaitFor('line("$") >= 3')
+ call assert_equal(['Reading from channel output...', '[0,"hello"]', '[-2,12.34]'], getline(1, '$'))
+ bwipe!
+ finally
+ call job_stop(job)
+ endtry
+endfunc
+
+" Wait a little while for the last line, minus "offset", to equal "line".
+func s:wait_for_last_line(line, offset)
+ for i in range(100)
+ if getline(line('$') - a:offset) == a:line
+ break
+ endif
+ sleep 10m
+ endfor
+endfunc
+
+func Test_pipe_io_two_buffers()
+ if !has('job')
+ return
+ endif
+ call ch_log('Test_pipe_io_two_buffers()')
+
+ " Create two buffers, one to read from and one to write to.
+ split pipe-output
+ set buftype=nofile
+ split pipe-input
+ set buftype=nofile
+
+ let job = job_start(s:python . " test_channel_pipe.py",
+ \ {'in_io': 'buffer', 'in_name': 'pipe-input', 'in_top': 0,
+ \ 'out_io': 'buffer', 'out_name': 'pipe-output',
+ \ 'block_write': 1})
+ call assert_equal("run", job_status(job))
+ try
+ exe "normal Gaecho hello\<CR>"
+ exe bufwinnr('pipe-output') . "wincmd w"
+ call s:wait_for_last_line('hello', 0)
+ call assert_equal('hello', getline('$'))
+
+ exe bufwinnr('pipe-input') . "wincmd w"
+ exe "normal Gadouble this\<CR>"
+ exe bufwinnr('pipe-output') . "wincmd w"
+ call s:wait_for_last_line('AND this', 0)
+ call assert_equal('this', getline(line('$') - 1))
+ call assert_equal('AND this', getline('$'))
+
+ bwipe!
+ exe bufwinnr('pipe-input') . "wincmd w"
+ bwipe!
+ finally
+ call job_stop(job)
+ endtry
+endfunc
+
+func Test_pipe_io_one_buffer()
+ if !has('job')
+ return
+ endif
+ call ch_log('Test_pipe_io_one_buffer()')
+
+ " Create one buffer to read from and to write to.
+ split pipe-io
+ set buftype=nofile
+
+ let job = job_start(s:python . " test_channel_pipe.py",
+ \ {'in_io': 'buffer', 'in_name': 'pipe-io', 'in_top': 0,
+ \ 'out_io': 'buffer', 'out_name': 'pipe-io',
+ \ 'block_write': 1})
+ call assert_equal("run", job_status(job))
+ try
+ exe "normal Goecho hello\<CR>"
+ call s:wait_for_last_line('hello', 1)
+ call assert_equal('hello', getline(line('$') - 1))
+
+ exe "normal Gadouble this\<CR>"
+ call s:wait_for_last_line('AND this', 1)
+ call assert_equal('this', getline(line('$') - 2))
+ call assert_equal('AND this', getline(line('$') - 1))
+
+ bwipe!
+ finally
+ call job_stop(job)
+ endtry
+endfunc
+
+func Test_pipe_null()
+ if !has('job')
+ return
+ endif
+ call ch_log('Test_pipe_null()')
+
+ " We cannot check that no I/O works, we only check that the job starts
+ " properly.
+ let job = job_start(s:python . " test_channel_pipe.py something",
+ \ {'in_io': 'null'})
+ call assert_equal("run", job_status(job))
+ try
+ call assert_equal('something', ch_read(job))
+ finally
+ call job_stop(job)
+ endtry
+
+ let job = job_start(s:python . " test_channel_pipe.py err-out",
+ \ {'out_io': 'null'})
+ call assert_equal("run", job_status(job))
+ try
+ call assert_equal('err-out', ch_read(job, {"part": "err"}))
+ finally
+ call job_stop(job)
+ endtry
+
+ let job = job_start(s:python . " test_channel_pipe.py something",
+ \ {'err_io': 'null'})
+ call assert_equal("run", job_status(job))
+ try
+ call assert_equal('something', ch_read(job))
+ finally
+ call job_stop(job)
+ endtry
+
+ let job = job_start(s:python . " test_channel_pipe.py something",
+ \ {'out_io': 'null', 'err_io': 'out'})
+ call assert_equal("run", job_status(job))
+ call job_stop(job)
+
+ let job = job_start(s:python . " test_channel_pipe.py something",
+ \ {'in_io': 'null', 'out_io': 'null', 'err_io': 'null'})
+ call assert_equal("run", job_status(job))
+ call assert_equal('channel fail', string(job_getchannel(job)))
+ call assert_equal('fail', ch_status(job))
+ call job_stop(job)
+endfunc
+
+func Test_pipe_to_buffer_raw()
+ if !has('job')
+ return
+ endif
+ call ch_log('Test_raw_pipe_to_buffer()')
+ let options = {'out_mode': 'raw', 'out_io': 'buffer', 'out_name': 'testout'}
+ split testout
+ let job = job_start([s:python, '-c',
+ \ 'import sys; [sys.stdout.write(".") and sys.stdout.flush() for _ in range(10000)]'], options)
+ " the job may be done quickly, also accept "dead"
+ call assert_match('^\%(dead\|run\)$', job_status(job))
+ call WaitFor('len(join(getline(1, "$"), "")) >= 10000')
+ try
+ let totlen = 0
+ for line in getline(1, '$')
+ call assert_equal('', substitute(line, '^\.*', '', ''))
+ let totlen += len(line)
+ endfor
+ call assert_equal(10000, totlen)
+ finally
+ call job_stop(job)
+ bwipe!
+ endtry
+endfunc
+
+func Test_reuse_channel()
+ if !has('job')
+ return
+ endif
+ call ch_log('Test_reuse_channel()')
+
+ let job = job_start(s:python . " test_channel_pipe.py")
+ call assert_equal("run", job_status(job))
+ let handle = job_getchannel(job)
+ try
+ call ch_sendraw(handle, "echo something\n")
+ call assert_equal("something", ch_readraw(handle))
+ finally
+ call job_stop(job)
+ endtry
+
+ let job = job_start(s:python . " test_channel_pipe.py", {'channel': handle})
+ call assert_equal("run", job_status(job))
+ let handle = job_getchannel(job)
+ try
+ call ch_sendraw(handle, "echo again\n")
+ call assert_equal("again", ch_readraw(handle))
+ finally
+ call job_stop(job)
+ endtry
+endfunc
+
+func Test_out_cb()
+ if !has('job')
+ return
+ endif
+ call ch_log('Test_out_cb()')
+
+ let dict = {'thisis': 'dict: '}
+ func dict.outHandler(chan, msg) dict
+ if type(a:msg) == v:t_string
+ let g:Ch_outmsg = self.thisis . a:msg
+ else
+ let g:Ch_outobj = a:msg
+ endif
+ endfunc
+ func dict.errHandler(chan, msg) dict
+ let g:Ch_errmsg = self.thisis . a:msg
+ endfunc
+ let job = job_start(s:python . " test_channel_pipe.py",
+ \ {'out_cb': dict.outHandler,
+ \ 'out_mode': 'json',
+ \ 'err_cb': dict.errHandler,
+ \ 'err_mode': 'json'})
+ call assert_equal("run", job_status(job))
+ try
+ let g:Ch_outmsg = ''
+ let g:Ch_errmsg = ''
+ call ch_sendraw(job, "echo [0, \"hello\"]\n")
+ call ch_sendraw(job, "echoerr [0, \"there\"]\n")
+ call WaitForAssert({-> assert_equal("dict: hello", g:Ch_outmsg)})
+ call WaitForAssert({-> assert_equal("dict: there", g:Ch_errmsg)})
+
+ " Receive a json object split in pieces
+ unlet! g:Ch_outobj
+ call ch_sendraw(job, "echosplit [0, {\"one\": 1,| \"tw|o\": 2, \"three\": 3|}]\n")
+ let g:Ch_outobj = ''
+ call WaitForAssert({-> assert_equal({'one': 1, 'two': 2, 'three': 3}, g:Ch_outobj)})
+ finally
+ call job_stop(job)
+ endtry
+endfunc
+
+func Test_out_close_cb()
+ if !has('job')
+ return
+ endif
+ call ch_log('Test_out_close_cb()')
+
+ let s:counter = 1
+ let g:Ch_msg1 = ''
+ let g:Ch_closemsg = 0
+ func! OutHandler(chan, msg)
+ if s:counter == 1
+ let g:Ch_msg1 = a:msg
+ endif
+ let s:counter += 1
+ endfunc
+ func! CloseHandler(chan)
+ let g:Ch_closemsg = s:counter
+ let s:counter += 1
+ endfunc
+ let job = job_start(s:python . " test_channel_pipe.py quit now",
+ \ {'out_cb': 'OutHandler',
+ \ 'close_cb': 'CloseHandler'})
+ " the job may be done quickly, also accept "dead"
+ call assert_match('^\%(dead\|run\)$', job_status(job))
+ try
+ call WaitForAssert({-> assert_equal('quit', g:Ch_msg1)})
+ call WaitForAssert({-> assert_equal(2, g:Ch_closemsg)})
+ finally
+ call job_stop(job)
+ delfunc OutHandler
+ delfunc CloseHandler
+ endtry
+endfunc
+
+func Test_read_in_close_cb()
+ if !has('job')
+ return
+ endif
+ call ch_log('Test_read_in_close_cb()')
+
+ let g:Ch_received = ''
+ func! CloseHandler(chan)
+ let g:Ch_received = ch_read(a:chan)
+ endfunc
+ let job = job_start(s:python . " test_channel_pipe.py quit now",
+ \ {'close_cb': 'CloseHandler'})
+ " the job may be done quickly, also accept "dead"
+ call assert_match('^\%(dead\|run\)$', job_status(job))
+ try
+ call WaitForAssert({-> assert_equal('quit', g:Ch_received)})
+ finally
+ call job_stop(job)
+ delfunc CloseHandler
+ endtry
+endfunc
+
+" Use channel in NL mode but received text does not end in NL.
+func Test_read_in_close_cb_incomplete()
+ if !has('job')
+ return
+ endif
+ call ch_log('Test_read_in_close_cb_incomplete()')
+
+ let g:Ch_received = ''
+ func! CloseHandler(chan)
+ while ch_status(a:chan, {'part': 'out'}) == 'buffered'
+ let g:Ch_received .= ch_read(a:chan)
+ endwhile
+ endfunc
+ let job = job_start(s:python . " test_channel_pipe.py incomplete",
+ \ {'close_cb': 'CloseHandler'})
+ " the job may be done quickly, also accept "dead"
+ call assert_match('^\%(dead\|run\)$', job_status(job))
+ try
+ call WaitForAssert({-> assert_equal('incomplete', g:Ch_received)})
+ finally
+ call job_stop(job)
+ delfunc CloseHandler
+ endtry
+endfunc
+
+func Test_out_cb_lambda()
+ if !has('job')
+ return
+ endif
+ call ch_log('Test_out_cb_lambda()')
+
+ let job = job_start(s:python . " test_channel_pipe.py",
+ \ {'out_cb': {ch, msg -> execute("let g:Ch_outmsg = 'lambda: ' . msg")},
+ \ 'out_mode': 'json',
+ \ 'err_cb': {ch, msg -> execute(":let g:Ch_errmsg = 'lambda: ' . msg")},
+ \ 'err_mode': 'json'})
+ call assert_equal("run", job_status(job))
+ try
+ let g:Ch_outmsg = ''
+ let g:Ch_errmsg = ''
+ call ch_sendraw(job, "echo [0, \"hello\"]\n")
+ call ch_sendraw(job, "echoerr [0, \"there\"]\n")
+ call WaitForAssert({-> assert_equal("lambda: hello", g:Ch_outmsg)})
+ call WaitForAssert({-> assert_equal("lambda: there", g:Ch_errmsg)})
+ finally
+ call job_stop(job)
+ endtry
+endfunc
+
+func Test_close_and_exit_cb()
+ if !has('job')
+ return
+ endif
+ call ch_log('Test_close_and_exit_cb')
+
+ let g:retdict = {'ret': {}}
+ func g:retdict.close_cb(ch) dict
+ let self.ret['close_cb'] = job_status(ch_getjob(a:ch))
+ endfunc
+ func g:retdict.exit_cb(job, status) dict
+ let self.ret['exit_cb'] = job_status(a:job)
+ endfunc
+
+ let job = job_start([&shell, &shellcmdflag, 'echo'],
+ \ {'close_cb': g:retdict.close_cb,
+ \ 'exit_cb': g:retdict.exit_cb})
+ " the job may be done quickly, also accept "dead"
+ call assert_match('^\%(dead\|run\)$', job_status(job))
+ call WaitForAssert({-> assert_equal(2, len(g:retdict.ret))})
+ call assert_match('^\%(dead\|run\)$', g:retdict.ret['close_cb'])
+ call assert_equal('dead', g:retdict.ret['exit_cb'])
+ unlet g:retdict
+endfunc
+
+""""""""""
+
+function ExitCbWipe(job, status)
+ exe g:wipe_buf 'bw!'
+endfunction
+
+" This caused a crash, because messages were handled while peeking for a
+" character.
+func Test_exit_cb_wipes_buf()
+ if !has('timers')
+ return
+ endif
+ set cursorline lazyredraw
+ call test_override('redraw_flag', 1)
+ new
+ let g:wipe_buf = bufnr('')
+
+ let job = job_start(has('win32') ? 'cmd /c echo:' : ['true'],
+ \ {'exit_cb': 'ExitCbWipe'})
+ let timer = timer_start(300, {-> feedkeys("\<Esc>", 'nt')}, {'repeat': 5})
+ call feedkeys(repeat('g', 1000) . 'o', 'ntx!')
+ call WaitForAssert({-> assert_equal("dead", job_status(job))})
+ call timer_stop(timer)
+
+ set nocursorline nolazyredraw
+ unlet g:wipe_buf
+ call test_override('ALL', 0)
+endfunc
+
+""""""""""
+
+let g:Ch_unletResponse = ''
+func s:UnletHandler(handle, msg)
+ let g:Ch_unletResponse = a:msg
+ unlet s:channelfd
+endfunc
+
+" Test that "unlet handle" in a handler doesn't crash Vim.
+func Ch_unlet_handle(port)
+ let s:channelfd = ch_open('localhost:' . a:port, s:chopt)
+ call ch_sendexpr(s:channelfd, "test", {'callback': function('s:UnletHandler')})
+ call WaitForAssert({-> assert_equal('what?', g:Ch_unletResponse)})
+endfunc
+
+func Test_unlet_handle()
+ call ch_log('Test_unlet_handle()')
+ call s:run_server('Ch_unlet_handle')
+endfunc
+
+""""""""""
+
+let g:Ch_unletResponse = ''
+func Ch_CloseHandler(handle, msg)
+ let g:Ch_unletResponse = a:msg
+ call ch_close(s:channelfd)
+endfunc
+
+" Test that "unlet handle" in a handler doesn't crash Vim.
+func Ch_close_handle(port)
+ let s:channelfd = ch_open('localhost:' . a:port, s:chopt)
+ call ch_sendexpr(s:channelfd, "test", {'callback': function('Ch_CloseHandler')})
+ call WaitForAssert({-> assert_equal('what?', g:Ch_unletResponse)})
+endfunc
+
+func Test_close_handle()
+ call ch_log('Test_close_handle()')
+ call s:run_server('Ch_close_handle')
+endfunc
+
+""""""""""
+
+func Test_open_fail()
+ call ch_log('Test_open_fail()')
+ silent! let ch = ch_open("noserver")
+ echo ch
+ let d = ch
+endfunc
+
+""""""""""
+
+func Ch_open_delay(port)
+ " Wait up to a second for the port to open.
+ let s:chopt.waittime = 1000
+ let channel = ch_open('localhost:' . a:port, s:chopt)
+ unlet s:chopt.waittime
+ if ch_status(channel) == "fail"
+ call assert_report("Can't open channel")
+ return
+ endif
+ call assert_equal('got it', ch_evalexpr(channel, 'hello!'))
+ call ch_close(channel)
+endfunc
+
+func Test_open_delay()
+ call ch_log('Test_open_delay()')
+ " The server will wait half a second before creating the port.
+ call s:run_server('Ch_open_delay', 'delay')
+endfunc
+
+"""""""""
+
+function MyFunction(a,b,c)
+ let g:Ch_call_ret = [a:a, a:b, a:c]
+endfunc
+
+function Ch_test_call(port)
+ let handle = ch_open('localhost:' . a:port, s:chopt)
+ if ch_status(handle) == "fail"
+ call assert_report("Can't open channel")
+ return
+ endif
+
+ let g:Ch_call_ret = []
+ call assert_equal('ok', ch_evalexpr(handle, 'call-func'))
+ call WaitForAssert({-> assert_equal([1, 2, 3], g:Ch_call_ret)})
+endfunc
+
+func Test_call()
+ call ch_log('Test_call()')
+ call s:run_server('Ch_test_call')
+endfunc
+
+"""""""""
+
+let g:Ch_job_exit_ret = 'not yet'
+function MyExitCb(job, status)
+ let g:Ch_job_exit_ret = 'done'
+endfunc
+
+function Ch_test_exit_callback(port)
+ call job_setoptions(g:currentJob, {'exit_cb': 'MyExitCb'})
+ let g:Ch_exit_job = g:currentJob
+ call assert_equal('MyExitCb', job_info(g:currentJob)['exit_cb'])
+endfunc
+
+func Test_exit_callback()
+ if has('job')
+ call ch_log('Test_exit_callback()')
+ call s:run_server('Ch_test_exit_callback')
+
+ " wait up to a second for the job to exit
+ for i in range(100)
+ if g:Ch_job_exit_ret == 'done'
+ break
+ endif
+ sleep 10m
+ " calling job_status() triggers the callback
+ call job_status(g:Ch_exit_job)
+ endfor
+
+ call assert_equal('done', g:Ch_job_exit_ret)
+ call assert_equal('dead', job_info(g:Ch_exit_job).status)
+ unlet g:Ch_exit_job
+ endif
+endfunc
+
+function MyExitTimeCb(job, status)
+ if job_info(a:job).process == g:exit_cb_val.process
+ let g:exit_cb_val.end = reltime(g:exit_cb_val.start)
+ endif
+ call Resume()
+endfunction
+
+func Test_exit_callback_interval()
+ if !has('job')
+ return
+ endif
+
+ let g:exit_cb_val = {'start': reltime(), 'end': 0, 'process': 0}
+ let job = job_start([s:python, '-c', 'import time;time.sleep(0.5)'], {'exit_cb': 'MyExitTimeCb'})
+ let g:exit_cb_val.process = job_info(job).process
+ call WaitFor('type(g:exit_cb_val.end) != v:t_number || g:exit_cb_val.end != 0')
+ let elapsed = reltimefloat(g:exit_cb_val.end)
+ call assert_true(elapsed > 0.5)
+ call assert_true(elapsed < 1.0)
+
+ " case: unreferenced job, using timer
+ if !has('timers')
+ return
+ endif
+
+ let g:exit_cb_val = {'start': reltime(), 'end': 0, 'process': 0}
+ let g:job = job_start([s:python, '-c', 'import time;time.sleep(0.5)'], {'exit_cb': 'MyExitTimeCb'})
+ let g:exit_cb_val.process = job_info(g:job).process
+ unlet g:job
+ call Standby(1000)
+ if type(g:exit_cb_val.end) != v:t_number || g:exit_cb_val.end != 0
+ let elapsed = reltimefloat(g:exit_cb_val.end)
+ else
+ let elapsed = 1.0
+ endif
+ call assert_true(elapsed > 0.5)
+ call assert_true(elapsed < 1.0)
+endfunc
+
+"""""""""
+
+let g:Ch_close_ret = 'alive'
+function MyCloseCb(ch)
+ let g:Ch_close_ret = 'closed'
+endfunc
+
+function Ch_test_close_callback(port)
+ let handle = ch_open('localhost:' . a:port, s:chopt)
+ if ch_status(handle) == "fail"
+ call assert_report("Can't open channel")
+ return
+ endif
+ call ch_setoptions(handle, {'close_cb': 'MyCloseCb'})
+
+ call assert_equal('', ch_evalexpr(handle, 'close me'))
+ call WaitForAssert({-> assert_equal('closed', g:Ch_close_ret)})
+endfunc
+
+func Test_close_callback()
+ call ch_log('Test_close_callback()')
+ call s:run_server('Ch_test_close_callback')
+endfunc
+
+function Ch_test_close_partial(port)
+ let handle = ch_open('localhost:' . a:port, s:chopt)
+ if ch_status(handle) == "fail"
+ call assert_report("Can't open channel")
+ return
+ endif
+ let g:Ch_d = {}
+ func g:Ch_d.closeCb(ch) dict
+ let self.close_ret = 'closed'
+ endfunc
+ call ch_setoptions(handle, {'close_cb': g:Ch_d.closeCb})
+
+ call assert_equal('', ch_evalexpr(handle, 'close me'))
+ call WaitForAssert({-> assert_equal('closed', g:Ch_d.close_ret)})
+ unlet g:Ch_d
+endfunc
+
+func Test_close_partial()
+ call ch_log('Test_close_partial()')
+ call s:run_server('Ch_test_close_partial')
+endfunc
+
+func Test_job_start_invalid()
+ call assert_fails('call job_start($x)', 'E474:')
+ call assert_fails('call job_start("")', 'E474:')
+endfunc
+
+func Test_job_stop_immediately()
+ if !has('job')
+ return
+ endif
+
+ let g:job = job_start([s:python, '-c', 'import time;time.sleep(10)'])
+ try
+ call job_stop(g:job)
+ call WaitForAssert({-> assert_equal('dead', job_status(g:job))})
+ finally
+ call job_stop(g:job, 'kill')
+ unlet g:job
+ endtry
+endfunc
+
+" This was leaking memory.
+func Test_partial_in_channel_cycle()
+ let d = {}
+ let d.a = function('string', [d])
+ try
+ let d.b = ch_open('nowhere:123', {'close_cb': d.a})
+ catch
+ call assert_exception('E901:')
+ endtry
+ unlet d
+endfunc
+
+func Test_using_freed_memory()
+ let g:a = job_start(['ls'])
+ sleep 10m
+ call test_garbagecollect_now()
+endfunc
+
+func Test_collapse_buffers()
+ if !executable('cat') || !has('job')
+ return
+ endif
+ sp test_channel.vim
+ let g:linecount = line('$')
+ close
+ split testout
+ 1,$delete
+ call job_start('cat test_channel.vim', {'out_io': 'buffer', 'out_name': 'testout'})
+ call WaitForAssert({-> assert_inrange(g:linecount, g:linecount + 1, line('$'))})
+ bwipe!
+endfunc
+
+func Test_write_to_deleted_buffer()
+ if !executable('echo') || !has('job')
+ return
+ endif
+ let job = job_start('echo hello', {'out_io': 'buffer', 'out_name': 'test_buffer', 'out_msg': 0})
+ let bufnr = bufnr('test_buffer')
+ call WaitForAssert({-> assert_equal(['hello'], getbufline(bufnr, 1, '$'))})
+ call assert_equal('nofile', getbufvar(bufnr, '&buftype'))
+ call assert_equal('hide', getbufvar(bufnr, '&bufhidden'))
+
+ bdel test_buffer
+ call assert_equal([], getbufline(bufnr, 1, '$'))
+
+ let job = job_start('echo hello', {'out_io': 'buffer', 'out_name': 'test_buffer', 'out_msg': 0})
+ call WaitForAssert({-> assert_equal(['hello'], getbufline(bufnr, 1, '$'))})
+ call assert_equal('nofile', getbufvar(bufnr, '&buftype'))
+ call assert_equal('hide', getbufvar(bufnr, '&bufhidden'))
+
+ bwipe! test_buffer
+endfunc
+
+func Test_cmd_parsing()
+ if !has('unix')
+ return
+ endif
+ call assert_false(filereadable("file with space"))
+ let job = job_start('touch "file with space"')
+ call WaitForAssert({-> assert_true(filereadable("file with space"))})
+ call delete("file with space")
+
+ let job = job_start('touch file\ with\ space')
+ call WaitForAssert({-> assert_true(filereadable("file with space"))})
+ call delete("file with space")
+endfunc
+
+func Test_raw_passes_nul()
+ if !executable('cat') || !has('job')
+ return
+ endif
+
+ " Test lines from the job containing NUL are stored correctly in a buffer.
+ new
+ call setline(1, ["asdf\nasdf", "xxx\n", "\nyyy"])
+ w! Xtestread
+ bwipe!
+ split testout
+ 1,$delete
+ call job_start('cat Xtestread', {'out_io': 'buffer', 'out_name': 'testout'})
+ call WaitFor('line("$") > 2')
+ call assert_equal("asdf\nasdf", getline(1))
+ call assert_equal("xxx\n", getline(2))
+ call assert_equal("\nyyy", getline(3))
+
+ call delete('Xtestread')
+ bwipe!
+
+ " Test lines from a buffer with NUL bytes are written correctly to the job.
+ new mybuffer
+ call setline(1, ["asdf\nasdf", "xxx\n", "\nyyy"])
+ let g:Ch_job = job_start('cat', {'in_io': 'buffer', 'in_name': 'mybuffer', 'out_io': 'file', 'out_name': 'Xtestwrite'})
+ call WaitForAssert({-> assert_equal("dead", job_status(g:Ch_job))})
+ bwipe!
+ split Xtestwrite
+ call assert_equal("asdf\nasdf", getline(1))
+ call assert_equal("xxx\n", getline(2))
+ call assert_equal("\nyyy", getline(3))
+ call assert_equal(-1, match(s:get_resources(), '\(^\|/\)Xtestwrite$'))
+
+ call delete('Xtestwrite')
+ bwipe!
+endfunc
+
+func MyLineCountCb(ch, msg)
+ let g:linecount += 1
+endfunc
+
+func Test_read_nonl_line()
+ if !has('job')
+ return
+ endif
+
+ let g:linecount = 0
+ let arg = 'import sys;sys.stdout.write("1\n2\n3")'
+ call job_start([s:python, '-c', arg], {'callback': 'MyLineCountCb'})
+ call WaitForAssert({-> assert_equal(3, g:linecount)})
+endfunc
+
+func Test_read_from_terminated_job()
+ if !has('job')
+ return
+ endif
+
+ let g:linecount = 0
+ let arg = 'import os,sys;os.close(1);sys.stderr.write("test\n")'
+ call job_start([s:python, '-c', arg], {'callback': 'MyLineCountCb'})
+ call WaitForAssert({-> assert_equal(1, g:linecount)})
+endfunc
+
+func Test_job_start_windows()
+ if !has('job') || !has('win32')
+ return
+ endif
+
+ " Check that backslash in $COMSPEC is handled properly.
+ let g:echostr = ''
+ let cmd = $COMSPEC . ' /c echo 123'
+ let job = job_start(cmd, {'callback': {ch,msg -> execute(":let g:echostr .= msg")}})
+ let info = job_info(job)
+ call assert_equal([$COMSPEC, '/c', 'echo', '123'], info.cmd)
+
+ call WaitForAssert({-> assert_equal("123", g:echostr)})
+ unlet g:echostr
+endfunc
+
+func Test_env()
+ if !has('job')
+ return
+ endif
+
+ let g:envstr = ''
+ if has('win32')
+ let cmd = ['cmd', '/c', 'echo %FOO%']
+ else
+ let cmd = [&shell, &shellcmdflag, 'echo $FOO']
+ endif
+ call assert_fails('call job_start(cmd, {"env": 1})', 'E475:')
+ call job_start(cmd, {'callback': {ch,msg -> execute(":let g:envstr .= msg")}, 'env': {'FOO': 'bar'}})
+ call WaitForAssert({-> assert_equal("bar", g:envstr)})
+ unlet g:envstr
+endfunc
+
+func Test_cwd()
+ if !has('job')
+ return
+ endif
+
+ let g:envstr = ''
+ if has('win32')
+ let expect = $TEMP
+ let cmd = ['cmd', '/c', 'echo %CD%']
+ else
+ let expect = $HOME
+ let cmd = ['pwd']
+ endif
+ let job = job_start(cmd, {'callback': {ch,msg -> execute(":let g:envstr .= msg")}, 'cwd': expect})
+ try
+ call WaitForAssert({-> assert_notequal("", g:envstr)})
+ let expect = substitute(expect, '[/\\]$', '', '')
+ let g:envstr = substitute(g:envstr, '[/\\]$', '', '')
+ if $CI != '' && stridx(g:envstr, '/private/') == 0
+ let g:envstr = g:envstr[8:]
+ endif
+ call assert_equal(expect, g:envstr)
+ finally
+ call job_stop(job)
+ unlet g:envstr
+ endtry
+endfunc
+
+function Ch_test_close_lambda(port)
+ let handle = ch_open('localhost:' . a:port, s:chopt)
+ if ch_status(handle) == "fail"
+ call assert_report("Can't open channel")
+ return
+ endif
+ let g:Ch_close_ret = ''
+ call ch_setoptions(handle, {'close_cb': {ch -> execute("let g:Ch_close_ret = 'closed'")}})
+
+ call assert_equal('', ch_evalexpr(handle, 'close me'))
+ call WaitForAssert({-> assert_equal('closed', g:Ch_close_ret)})
+endfunc
+
+func Test_close_lambda()
+ call ch_log('Test_close_lambda()')
+ call s:run_server('Ch_test_close_lambda')
+endfunc
+
+func s:test_list_args(cmd, out, remove_lf)
+ try
+ let g:out = ''
+ let job = job_start([s:python, '-c', a:cmd], {'callback': {ch, msg -> execute('let g:out .= msg')}, 'out_mode': 'raw'})
+ call WaitFor('"" != g:out')
+ if has('win32')
+ let g:out = substitute(g:out, '\r', '', 'g')
+ endif
+ if a:remove_lf
+ let g:out = substitute(g:out, '\n$', '', 'g')
+ endif
+ call assert_equal(a:out, g:out)
+ finally
+ call job_stop(job)
+ unlet g:out
+ endtry
+endfunc
+
+func Test_list_args()
+ if !has('job')
+ return
+ endif
+
+ call s:test_list_args('import sys;sys.stdout.write("hello world")', "hello world", 0)
+ call s:test_list_args('import sys;sys.stdout.write("hello\nworld")', "hello\nworld", 0)
+ call s:test_list_args('import sys;sys.stdout.write(''hello\nworld'')', "hello\nworld", 0)
+ call s:test_list_args('import sys;sys.stdout.write(''hello"world'')', "hello\"world", 0)
+ call s:test_list_args('import sys;sys.stdout.write(''hello^world'')', "hello^world", 0)
+ call s:test_list_args('import sys;sys.stdout.write("hello&&world")', "hello&&world", 0)
+ call s:test_list_args('import sys;sys.stdout.write(''hello\\world'')', "hello\\world", 0)
+ call s:test_list_args('import sys;sys.stdout.write(''hello\\\\world'')', "hello\\\\world", 0)
+ call s:test_list_args('import sys;sys.stdout.write("hello\"world\"")', 'hello"world"', 0)
+ call s:test_list_args('import sys;sys.stdout.write("h\"ello worl\"d")', 'h"ello worl"d', 0)
+ call s:test_list_args('import sys;sys.stdout.write("h\"e\\\"llo wor\\\"l\"d")', 'h"e\"llo wor\"l"d', 0)
+ call s:test_list_args('import sys;sys.stdout.write("h\"e\\\"llo world")', 'h"e\"llo world', 0)
+ call s:test_list_args('import sys;sys.stdout.write("hello\tworld")', "hello\tworld", 0)
+
+ " tests which not contain spaces in the argument
+ call s:test_list_args('print("hello\nworld")', "hello\nworld", 1)
+ call s:test_list_args('print(''hello\nworld'')', "hello\nworld", 1)
+ call s:test_list_args('print(''hello"world'')', "hello\"world", 1)
+ call s:test_list_args('print(''hello^world'')', "hello^world", 1)
+ call s:test_list_args('print("hello&&world")', "hello&&world", 1)
+ call s:test_list_args('print(''hello\\world'')', "hello\\world", 1)
+ call s:test_list_args('print(''hello\\\\world'')', "hello\\\\world", 1)
+ call s:test_list_args('print("hello\"world\"")', 'hello"world"', 1)
+ call s:test_list_args('print("hello\tworld")', "hello\tworld", 1)
+endfunc
+
+" Do this last, it stops any channel log.
+func Test_zz_ch_log()
+ call ch_logfile('Xlog', 'w')
+ call ch_log('hello there')
+ call ch_log('%s%s')
+ call ch_logfile('')
+ let text = readfile('Xlog')
+ call assert_match("hello there", text[1])
+ call assert_match("%s%s", text[2])
+ call delete('Xlog')
+endfunc
+
+func Test_keep_pty_open()
+ if !has('unix')
+ return
+ endif
+
+ let job = job_start(s:python . ' -c "import time;time.sleep(0.2)"',
+ \ {'out_io': 'null', 'err_io': 'null', 'pty': 1})
+ let elapsed = WaitFor({-> job_status(job) ==# 'dead'})
+ call assert_inrange(200, 1000, elapsed)
+ call job_stop(job)
+endfunc
+
+func Test_job_start_in_timer()
+ if !has('job') || !has('timers')
+ return
+ endif
+
+ func OutCb(chan, msg)
+ let g:val += 1
+ endfunc
+
+ func ExitCb(job, status)
+ let g:val += 1
+ call Resume()
+ endfunc
+
+ func TimerCb(timer)
+ if has('win32')
+ let cmd = ['cmd', '/c', 'echo.']
+ else
+ let cmd = ['echo']
+ endif
+ let g:job = job_start(cmd, {'out_cb': 'OutCb', 'exit_cb': 'ExitCb'})
+ call substitute(repeat('a', 100000), '.', '', 'g')
+ endfunc
+
+ " We should be interrupted before 'updatetime' elapsed.
+ let g:val = 0
+ call timer_start(1, 'TimerCb')
+ let elapsed = Standby(&ut)
+ call assert_inrange(1, &ut / 2, elapsed)
+
+ " Wait for both OutCb() and ExitCb() to have been called before deleting
+ " them.
+ call WaitForAssert({-> assert_equal(2, g:val)})
+ call job_stop(g:job)
+
+ delfunc OutCb
+ delfunc ExitCb
+ delfunc TimerCb
+ unlet! g:val
+ unlet! g:job
+endfunc
+
+func Test_raw_large_data()
+ try
+ let g:out = ''
+ let job = job_start(s:python . " test_channel_pipe.py",
+ \ {'mode': 'raw', 'drop': 'never', 'noblock': 1,
+ \ 'callback': {ch, msg -> execute('let g:out .= msg')}})
+
+ let outlen = 79999
+ let want = repeat('X', outlen) . "\n"
+ call ch_sendraw(job, want)
+ call WaitFor({-> len(g:out) >= outlen}, 10000)
+ call WaitForAssert({-> assert_equal("dead", job_status(job))})
+ call assert_equal(want, substitute(g:out, '\r', '', 'g'))
+ finally
+ call job_stop(job)
+ unlet g:out
+ endtry
+endfunc
+
+func Test_job_exitval_and_termsig()
+ if !has('unix')
+ return
+ endif
+
+ " Terminate job normally
+ let cmd = ['echo']
+ let job = job_start(cmd)
+ call WaitForAssert({-> assert_equal("dead", job_status(job))})
+ let info = job_info(job)
+ call assert_equal(0, info.exitval)
+ call assert_equal("", info.termsig)
+
+ " Terminate job by signal
+ let cmd = ['sleep', '10']
+ let job = job_start(cmd)
+ sleep 10m
+ call job_stop(job)
+ call WaitForAssert({-> assert_equal("dead", job_status(job))})
+ let info = job_info(job)
+ call assert_equal(-1, info.exitval)
+ call assert_equal("term", info.termsig)
+endfunc
diff --git a/src/testdir/test_channel_pipe.py b/src/testdir/test_channel_pipe.py
new file mode 100644
index 0000000..810a8e3
--- /dev/null
+++ b/src/testdir/test_channel_pipe.py
@@ -0,0 +1,63 @@
+#!/usr/bin/python
+#
+# Server that will communicate over stdin/stderr
+#
+# This requires Python 2.6 or later.
+
+from __future__ import print_function
+import sys
+import time
+
+if __name__ == "__main__":
+
+ if len(sys.argv) > 1:
+ if sys.argv[1].startswith("err"):
+ print(sys.argv[1], file=sys.stderr)
+ sys.stderr.flush()
+ elif sys.argv[1].startswith("incomplete"):
+ print(sys.argv[1], end='')
+ sys.stdout.flush()
+ sys.exit(0)
+ else:
+ print(sys.argv[1])
+ sys.stdout.flush()
+ if sys.argv[1].startswith("quit"):
+ sys.exit(0)
+
+ while True:
+ typed = sys.stdin.readline()
+ if typed.startswith("quit"):
+ print("Goodbye!")
+ sys.stdout.flush()
+ break
+ if typed.startswith("echo "):
+ print(typed[5:-1])
+ sys.stdout.flush()
+ if typed.startswith("echosplit "):
+ for part in typed[10:-1].split('|'):
+ sys.stdout.write(part)
+ sys.stdout.flush()
+ time.sleep(0.05)
+ if typed.startswith("double "):
+ print(typed[7:-1] + "\nAND " + typed[7:-1])
+ sys.stdout.flush()
+ if typed.startswith("split "):
+ print(typed[6:-1], end='')
+ sys.stdout.flush()
+ time.sleep(0.05)
+ print(typed[6:-1], end='')
+ sys.stdout.flush()
+ time.sleep(0.05)
+ print(typed[6:-1])
+ sys.stdout.flush()
+ if typed.startswith("echoerr "):
+ print(typed[8:-1], file=sys.stderr)
+ sys.stderr.flush()
+ if typed.startswith("doubleerr "):
+ print(typed[10:-1] + "\nAND " + typed[10:-1], file=sys.stderr)
+ sys.stderr.flush()
+ if typed.startswith("XXX"):
+ print(typed, end='')
+ sys.stderr.flush()
+ break
+
diff --git a/src/testdir/test_channel_write.py b/src/testdir/test_channel_write.py
new file mode 100644
index 0000000..9c8813b
--- /dev/null
+++ b/src/testdir/test_channel_write.py
@@ -0,0 +1,18 @@
+#!/usr/bin/python
+#
+# Program that writes a number to stdout repeatedly
+#
+# This requires Python 2.6 or later.
+
+from __future__ import print_function
+import sys
+import time
+
+if __name__ == "__main__":
+
+ done = 0
+ while done < 10:
+ done = done + 1
+ print(done)
+ sys.stdout.flush()
+ time.sleep(0.05) # sleep 50 msec
diff --git a/src/testdir/test_charsearch.vim b/src/testdir/test_charsearch.vim
new file mode 100644
index 0000000..17a49e0
--- /dev/null
+++ b/src/testdir/test_charsearch.vim
@@ -0,0 +1,62 @@
+
+func Test_charsearch()
+ enew!
+ call append(0, ['Xabcdefghijkemnopqretuvwxyz',
+ \ 'Yabcdefghijkemnopqretuvwxyz',
+ \ 'Zabcdefghijkemnokqretkvwxyz'])
+ " check that "fe" and ";" work
+ 1
+ normal! ylfep;;p,,p
+ call assert_equal('XabcdeXfghijkeXmnopqreXtuvwxyz', getline(1))
+ " check that save/restore works
+ 2
+ normal! ylfep
+ let csave = getcharsearch()
+ normal! fip
+ call setcharsearch(csave)
+ normal! ;p;p
+ call assert_equal('YabcdeYfghiYjkeYmnopqreYtuvwxyz', getline(2))
+
+ " check that setcharsearch() changes the settings.
+ 3
+ normal! ylfep
+ call setcharsearch({'char': 'k'})
+ normal! ;p
+ call setcharsearch({'forward': 0})
+ normal! $;p
+ call setcharsearch({'until': 1})
+ set cpo-=;
+ normal! ;;p
+ call assert_equal('ZabcdeZfghijkZZemnokqretkZvwxyz', getline(3))
+ enew!
+endfunc
+
+" Test for t,f,F,T movement commands and 'cpo-;' setting
+func Test_search_cmds()
+ enew!
+ call append(0, ["aaa two three four", " zzz", "yyy ",
+ \ "bbb yee yoo four", "ccc two three four",
+ \ "ddd yee yoo four"])
+ set cpo-=;
+ 1
+ normal! 0tt;D
+ 2
+ normal! 0fz;D
+ 3
+ normal! $Fy;D
+ 4
+ normal! $Ty;D
+ set cpo+=;
+ 5
+ normal! 0tt;;D
+ 6
+ normal! $Ty;;D
+
+ call assert_equal('aaa two', getline(1))
+ call assert_equal(' z', getline(2))
+ call assert_equal('y', getline(3))
+ call assert_equal('bbb y', getline(4))
+ call assert_equal('ccc', getline(5))
+ call assert_equal('ddd yee y', getline(6))
+ enew!
+endfunc
diff --git a/src/testdir/test_charsearch_utf8.vim b/src/testdir/test_charsearch_utf8.vim
new file mode 100644
index 0000000..82a807a
--- /dev/null
+++ b/src/testdir/test_charsearch_utf8.vim
@@ -0,0 +1,19 @@
+" Tests for related f{char} and t{char} using utf-8.
+
+" Test for t,f,F,T movement commands
+func Test_search_cmds()
+ new!
+ call setline(1, "・最åˆã‹ã‚‰æœ€å¾Œã¾ã§æœ€å¼·ã®Vimã¯æœ€é«˜")
+ 1
+ normal! f最
+ call assert_equal([0, 1, 4, 0], getpos('.'))
+ normal! ;
+ call assert_equal([0, 1, 16, 0], getpos('.'))
+ normal! 2;
+ call assert_equal([0, 1, 43, 0], getpos('.'))
+ normal! ,
+ call assert_equal([0, 1, 28, 0], getpos('.'))
+ bw!
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/test_cindent.vim b/src/testdir/test_cindent.vim
new file mode 100644
index 0000000..7c2c5e3
--- /dev/null
+++ b/src/testdir/test_cindent.vim
@@ -0,0 +1,105 @@
+" Test for cinoptions and cindent
+"
+" TODO: rewrite test3.in into this new style test
+
+func Test_cino_hash()
+ " Test that curbuf->b_ind_hash_comment is correctly reset
+ new
+ setlocal cindent cinoptions=#1
+ setlocal cinoptions=
+ call setline(1, ["#include <iostream>"])
+ call cursor(1, 1)
+ norm! o#include
+ "call feedkeys("o#include\<esc>", 't')
+ call assert_equal(["#include <iostream>", "#include"], getline(1,2))
+ bwipe!
+endfunc
+
+func Test_cino_extern_c()
+ " Test for cino-E
+
+ let without_ind = [
+ \ '#ifdef __cplusplus',
+ \ 'extern "C" {',
+ \ '#endif',
+ \ 'int func_a(void);',
+ \ '#ifdef __cplusplus',
+ \ '}',
+ \ '#endif'
+ \ ]
+
+ let with_ind = [
+ \ '#ifdef __cplusplus',
+ \ 'extern "C" {',
+ \ '#endif',
+ \ "\tint func_a(void);",
+ \ '#ifdef __cplusplus',
+ \ '}',
+ \ '#endif'
+ \ ]
+ new
+ setlocal cindent cinoptions=E0
+ call setline(1, without_ind)
+ call feedkeys("gg=G", 'tx')
+ call assert_equal(with_ind, getline(1, '$'))
+
+ setlocal cinoptions=E-s
+ call setline(1, with_ind)
+ call feedkeys("gg=G", 'tx')
+ call assert_equal(without_ind, getline(1, '$'))
+
+ setlocal cinoptions=Es
+ let tests = [
+ \ ['recognized', ['extern "C" {'], "\t\t;"],
+ \ ['recognized', ['extern "C++" {'], "\t\t;"],
+ \ ['recognized', ['extern /* com */ "C"{'], "\t\t;"],
+ \ ['recognized', ['extern"C"{'], "\t\t;"],
+ \ ['recognized', ['extern "C"', '{'], "\t\t;"],
+ \ ['not recognized', ['extern {'], "\t;"],
+ \ ['not recognized', ['extern /*"C"*/{'], "\t;"],
+ \ ['not recognized', ['extern "C" //{'], ";"],
+ \ ['not recognized', ['extern "C" /*{*/'], ";"],
+ \ ]
+
+ for pair in tests
+ let lines = pair[1]
+ call setline(1, lines)
+ call feedkeys(len(lines) . "Go;", 'tx')
+ call assert_equal(pair[2], getline(len(lines) + 1), 'Failed for "' . string(lines) . '"')
+ endfor
+
+ bwipe!
+endfunc
+
+func Test_cindent_rawstring()
+ new
+ setl cindent
+ call feedkeys("i" .
+ \ "int main() {\<CR>" .
+ \ "R\"(\<CR>" .
+ \ ")\";\<CR>" .
+ \ "statement;\<Esc>", "x")
+ call assert_equal("\tstatement;", getline(line('.')))
+ bw!
+endfunc
+
+func Test_cindent_expr()
+ new
+ func! MyIndentFunction()
+ return v:lnum == 1 ? shiftwidth() : 0
+ endfunc
+ setl expandtab sw=8 indentkeys+=; indentexpr=MyIndentFunction()
+ call setline(1, ['var_a = something()', 'b = something()'])
+ call cursor(1, 1)
+ call feedkeys("^\<c-v>j$A;\<esc>", 'tnix')
+ call assert_equal([' var_a = something();', 'b = something();'], getline(1, '$'))
+
+ %d
+ call setline(1, [' var_a = something()', ' b = something()'])
+ call cursor(1, 1)
+ call feedkeys("^\<c-v>j$A;\<esc>", 'tnix')
+ call assert_equal([' var_a = something();', ' b = something()'], getline(1, '$'))
+ bw!
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/test_clientserver.vim b/src/testdir/test_clientserver.vim
new file mode 100644
index 0000000..5c01ac4
--- /dev/null
+++ b/src/testdir/test_clientserver.vim
@@ -0,0 +1,104 @@
+" Tests for the +clientserver feature.
+
+if !has('job') || !has('clientserver')
+ finish
+endif
+
+source shared.vim
+
+func Test_client_server()
+ let cmd = GetVimCommand()
+ if cmd == ''
+ return
+ endif
+ if has('x11')
+ if empty($DISPLAY)
+ throw 'Skipped: $DISPLAY is not set'
+ endif
+ try
+ call remote_send('xxx', '')
+ catch
+ if v:exception =~ 'E240:'
+ throw 'Skipped: no connection to the X server'
+ endif
+ " ignore other errors
+ endtry
+ endif
+
+ let name = 'XVIMTEST'
+ let cmd .= ' --servername ' . name
+ let job = job_start(cmd, {'stoponexit': 'kill', 'out_io': 'null'})
+ call WaitForAssert({-> assert_equal("run", job_status(job))})
+
+ " Takes a short while for the server to be active.
+ " When using valgrind it takes much longer.
+ call WaitForAssert({-> assert_match(name, serverlist())})
+
+ call remote_foreground(name)
+
+ call remote_send(name, ":let testvar = 'yes'\<CR>")
+ call WaitFor('remote_expr("' . name . '", "exists(\"testvar\") ? testvar : \"\"", "", 1) == "yes"')
+ call assert_equal('yes', remote_expr(name, "testvar", "", 2))
+
+ if has('unix') && has('gui') && !has('gui_running')
+ " Running in a terminal and the GUI is available: Tell the server to open
+ " the GUI and check that the remote command still works.
+ " Need to wait for the GUI to start up, otherwise the send hangs in trying
+ " to send to the terminal window.
+ if has('gui_athena') || has('gui_motif')
+ " For those GUIs, ignore the 'failed to create input context' error.
+ call remote_send(name, ":call test_ignore_error('E285') | gui -f\<CR>")
+ else
+ call remote_send(name, ":gui -f\<CR>")
+ endif
+ " Wait for the server to be up and answering requests.
+ sleep 100m
+ call WaitForAssert({-> assert_true(remote_expr(name, "v:version", "", 1) != "")})
+
+ call remote_send(name, ":let testvar = 'maybe'\<CR>")
+ call WaitForAssert({-> assert_equal('maybe', remote_expr(name, "testvar", "", 2))})
+ endif
+
+ call assert_fails('call remote_send("XXX", ":let testvar = ''yes''\<CR>")', 'E241')
+
+ " Expression evaluated locally.
+ if v:servername == ''
+ call remote_startserver('MYSELF')
+ " May get MYSELF1 when running the test again.
+ call assert_match('MYSELF', v:servername)
+ endif
+ let g:testvar = 'myself'
+ call assert_equal('myself', remote_expr(v:servername, 'testvar'))
+
+ call remote_send(name, ":call server2client(expand('<client>'), 'got it')\<CR>", 'g:myserverid')
+ call assert_equal('got it', remote_read(g:myserverid, 2))
+
+ call remote_send(name, ":call server2client(expand('<client>'), 'another')\<CR>", 'g:myserverid')
+ let peek_result = 'nothing'
+ let r = remote_peek(g:myserverid, 'peek_result')
+ " unpredictable whether the result is already available.
+ if r > 0
+ call assert_equal('another', peek_result)
+ elseif r == 0
+ call assert_equal('nothing', peek_result)
+ else
+ call assert_report('remote_peek() failed')
+ endif
+ let g:peek_result = 'empty'
+ call WaitFor('remote_peek(g:myserverid, "g:peek_result") > 0')
+ call assert_equal('another', g:peek_result)
+ call assert_equal('another', remote_read(g:myserverid, 2))
+
+ call remote_send(name, ":qa!\<CR>")
+ try
+ call WaitForAssert({-> assert_equal("dead", job_status(job))})
+ finally
+ if job_status(job) != 'dead'
+ call assert_report('Server did not exit')
+ call job_stop(job, 'kill')
+ endif
+ endtry
+endfunc
+
+" Uncomment this line to get a debugging log
+" call ch_logfile('channellog', 'w')
diff --git a/src/testdir/test_close_count.vim b/src/testdir/test_close_count.vim
new file mode 100644
index 0000000..1f9adba
--- /dev/null
+++ b/src/testdir/test_close_count.vim
@@ -0,0 +1,174 @@
+
+" Tests for :[count]close! command
+func Test_close_count()
+ enew! | only
+
+ let wids = [win_getid()]
+ for i in range(5)
+ new
+ call add(wids, win_getid())
+ endfor
+
+ 4wincmd w
+ close!
+ let ids = []
+ windo call add(ids, win_getid())
+ call assert_equal([wids[5], wids[4], wids[3], wids[1], wids[0]], ids)
+
+ 1close!
+ let ids = []
+ windo call add(ids, win_getid())
+ call assert_equal([wids[4], wids[3], wids[1], wids[0]], ids)
+
+ $close!
+ let ids = []
+ windo call add(ids, win_getid())
+ call assert_equal([wids[4], wids[3], wids[1]], ids)
+
+ 1wincmd w
+ 2close!
+ let ids = []
+ windo call add(ids, win_getid())
+ call assert_equal([wids[4], wids[1]], ids)
+
+ 1wincmd w
+ new
+ call add(wids, win_getid())
+ new
+ call add(wids, win_getid())
+ 2wincmd w
+ -1close!
+ let ids = []
+ windo call add(ids, win_getid())
+ call assert_equal([wids[6], wids[4], wids[1]], ids)
+
+ 2wincmd w
+ +1close!
+ let ids = []
+ windo call add(ids, win_getid())
+ call assert_equal([wids[6], wids[4]], ids)
+
+ only!
+endfunc
+
+" Tests for :[count]hide command
+func Test_hide_count()
+ enew! | only
+
+ let wids = [win_getid()]
+ for i in range(5)
+ new
+ call add(wids, win_getid())
+ endfor
+
+ 4wincmd w
+ .hide
+ let ids = []
+ windo call add(ids, win_getid())
+ call assert_equal([wids[5], wids[4], wids[3], wids[1], wids[0]], ids)
+
+ 1hide
+ let ids = []
+ windo call add(ids, win_getid())
+ call assert_equal([wids[4], wids[3], wids[1], wids[0]], ids)
+
+ $hide
+ let ids = []
+ windo call add(ids, win_getid())
+ call assert_equal([wids[4], wids[3], wids[1]], ids)
+
+ 1wincmd w
+ 2hide
+ let ids = []
+ windo call add(ids, win_getid())
+ call assert_equal([wids[4], wids[1]], ids)
+
+ 1wincmd w
+ new
+ call add(wids, win_getid())
+ new
+ call add(wids, win_getid())
+ 3wincmd w
+ -hide
+ let ids = []
+ windo call add(ids, win_getid())
+ call assert_equal([wids[7], wids[4], wids[1]], ids)
+
+ 2wincmd w
+ +hide
+ let ids = []
+ windo call add(ids, win_getid())
+ call assert_equal([wids[7], wids[4]], ids)
+
+ only!
+endfunc
+
+" Tests for :[count]close! command with 'hidden'
+func Test_hidden_close_count()
+ enew! | only
+
+ let wids = [win_getid()]
+ for i in range(5)
+ new
+ call add(wids, win_getid())
+ endfor
+
+ set hidden
+
+ $ hide
+ let ids = []
+ windo call add(ids, win_getid())
+ call assert_equal([wids[5], wids[4], wids[3], wids[2], wids[1]], ids)
+
+ $-1 close!
+ let ids = []
+ windo call add(ids, win_getid())
+ call assert_equal([wids[5], wids[4], wids[3], wids[1]], ids)
+
+ 1wincmd w
+ .+close!
+ let ids = []
+ windo call add(ids, win_getid())
+ call assert_equal([wids[5], wids[3], wids[1]], ids)
+
+ set nohidden
+ only!
+endfunc
+
+" Tests for 'CTRL-W c' command to close windows.
+func Test_winclose_command()
+ enew! | only
+
+ let wids = [win_getid()]
+ for i in range(5)
+ new
+ call add(wids, win_getid())
+ endfor
+
+ set hidden
+
+ 4wincmd w
+ exe "normal \<C-W>c"
+ let ids = []
+ windo call add(ids, win_getid())
+ call assert_equal([wids[5], wids[4], wids[3], wids[1], wids[0]], ids)
+
+ exe "normal 1\<C-W>c"
+ let ids = []
+ windo call add(ids, win_getid())
+ call assert_equal([wids[4], wids[3], wids[1], wids[0]], ids)
+
+ exe "normal 9\<C-W>c"
+ let ids = []
+ windo call add(ids, win_getid())
+ call assert_equal([wids[4], wids[3], wids[1]], ids)
+
+ 1wincmd w
+ exe "normal 2\<C-W>c"
+ let ids = []
+ windo call add(ids, win_getid())
+ call assert_equal([wids[4], wids[1]], ids)
+
+ set nohidden
+ only!
+endfunc
diff --git a/src/testdir/test_cmdline.vim b/src/testdir/test_cmdline.vim
new file mode 100644
index 0000000..02eeb6b
--- /dev/null
+++ b/src/testdir/test_cmdline.vim
@@ -0,0 +1,612 @@
+" Tests for editing the command line.
+
+func Test_complete_tab()
+ call writefile(['testfile'], 'Xtestfile')
+ call feedkeys(":e Xtest\t\r", "tx")
+ call assert_equal('testfile', getline(1))
+ call delete('Xtestfile')
+endfunc
+
+func Test_complete_list()
+ " We can't see the output, but at least we check the code runs properly.
+ call feedkeys(":e test\<C-D>\r", "tx")
+ call assert_equal('test', expand('%:t'))
+endfunc
+
+func Test_complete_wildmenu()
+ call writefile(['testfile1'], 'Xtestfile1')
+ call writefile(['testfile2'], 'Xtestfile2')
+ set wildmenu
+ call feedkeys(":e Xtest\t\t\r", "tx")
+ call assert_equal('testfile2', getline(1))
+
+ call delete('Xtestfile1')
+ call delete('Xtestfile2')
+ set nowildmenu
+endfunc
+
+func Test_map_completion()
+ if !has('cmdline_compl')
+ return
+ endif
+ call feedkeys(":map <unique> <si\<Tab>\<Home>\"\<CR>", 'xt')
+ call assert_equal('"map <unique> <silent>', getreg(':'))
+ call feedkeys(":map <script> <un\<Tab>\<Home>\"\<CR>", 'xt')
+ call assert_equal('"map <script> <unique>', getreg(':'))
+ call feedkeys(":map <expr> <sc\<Tab>\<Home>\"\<CR>", 'xt')
+ call assert_equal('"map <expr> <script>', getreg(':'))
+ call feedkeys(":map <buffer> <e\<Tab>\<Home>\"\<CR>", 'xt')
+ call assert_equal('"map <buffer> <expr>', getreg(':'))
+ call feedkeys(":map <nowait> <b\<Tab>\<Home>\"\<CR>", 'xt')
+ call assert_equal('"map <nowait> <buffer>', getreg(':'))
+ call feedkeys(":map <special> <no\<Tab>\<Home>\"\<CR>", 'xt')
+ call assert_equal('"map <special> <nowait>', getreg(':'))
+ call feedkeys(":map <silent> <sp\<Tab>\<Home>\"\<CR>", 'xt')
+ call assert_equal('"map <silent> <special>', getreg(':'))
+endfunc
+
+func Test_match_completion()
+ if !has('cmdline_compl')
+ return
+ endif
+ hi Aardig ctermfg=green
+ call feedkeys(":match \<Tab>\<Home>\"\<CR>", 'xt')
+ call assert_equal('"match Aardig', getreg(':'))
+ call feedkeys(":match \<S-Tab>\<Home>\"\<CR>", 'xt')
+ call assert_equal('"match none', getreg(':'))
+endfunc
+
+func Test_highlight_completion()
+ if !has('cmdline_compl')
+ return
+ endif
+ hi Aardig ctermfg=green
+ call feedkeys(":hi \<Tab>\<Home>\"\<CR>", 'xt')
+ call assert_equal('"hi Aardig', getreg(':'))
+ call feedkeys(":hi default \<Tab>\<Home>\"\<CR>", 'xt')
+ call assert_equal('"hi default Aardig', getreg(':'))
+ call feedkeys(":hi clear Aa\<Tab>\<Home>\"\<CR>", 'xt')
+ call assert_equal('"hi clear Aardig', getreg(':'))
+ call feedkeys(":hi li\<S-Tab>\<Home>\"\<CR>", 'xt')
+ call assert_equal('"hi link', getreg(':'))
+ call feedkeys(":hi d\<S-Tab>\<Home>\"\<CR>", 'xt')
+ call assert_equal('"hi default', getreg(':'))
+ call feedkeys(":hi c\<S-Tab>\<Home>\"\<CR>", 'xt')
+ call assert_equal('"hi clear', getreg(':'))
+
+ " A cleared group does not show up in completions.
+ hi Anders ctermfg=green
+ call assert_equal(['Aardig', 'Anders'], getcompletion('A', 'highlight'))
+ hi clear Aardig
+ call assert_equal(['Anders'], getcompletion('A', 'highlight'))
+ hi clear Anders
+ call assert_equal([], getcompletion('A', 'highlight'))
+endfunc
+
+func Test_expr_completion()
+ if !has('cmdline_compl')
+ return
+ endif
+ for cmd in [
+ \ 'let a = ',
+ \ 'if',
+ \ 'elseif',
+ \ 'while',
+ \ 'for',
+ \ 'echo',
+ \ 'echon',
+ \ 'execute',
+ \ 'echomsg',
+ \ 'echoerr',
+ \ 'call',
+ \ 'return',
+ \ 'cexpr',
+ \ 'caddexpr',
+ \ 'cgetexpr',
+ \ 'lexpr',
+ \ 'laddexpr',
+ \ 'lgetexpr']
+ call feedkeys(":" . cmd . " getl\<Tab>\<Home>\"\<CR>", 'xt')
+ call assert_equal('"' . cmd . ' getline(', getreg(':'))
+ endfor
+endfunc
+
+func Test_getcompletion()
+ if !has('cmdline_compl')
+ return
+ endif
+ let groupcount = len(getcompletion('', 'event'))
+ call assert_true(groupcount > 0)
+ let matchcount = len(getcompletion('File', 'event'))
+ call assert_true(matchcount > 0)
+ call assert_true(groupcount > matchcount)
+
+ if has('menu')
+ source $VIMRUNTIME/menu.vim
+ let matchcount = len(getcompletion('', 'menu'))
+ call assert_true(matchcount > 0)
+ call assert_equal(['File.'], getcompletion('File', 'menu'))
+ call assert_true(matchcount > 0)
+ let matchcount = len(getcompletion('File.', 'menu'))
+ call assert_true(matchcount > 0)
+ endif
+
+ let l = getcompletion('v:n', 'var')
+ call assert_true(index(l, 'v:null') >= 0)
+ let l = getcompletion('v:notexists', 'var')
+ call assert_equal([], l)
+
+ args a.c b.c
+ let l = getcompletion('', 'arglist')
+ call assert_equal(['a.c', 'b.c'], l)
+ %argdelete
+
+ let l = getcompletion('', 'augroup')
+ call assert_true(index(l, 'END') >= 0)
+ let l = getcompletion('blahblah', 'augroup')
+ call assert_equal([], l)
+
+ let l = getcompletion('', 'behave')
+ call assert_true(index(l, 'mswin') >= 0)
+ let l = getcompletion('not', 'behave')
+ call assert_equal([], l)
+
+ let l = getcompletion('', 'color')
+ call assert_true(index(l, 'default') >= 0)
+ let l = getcompletion('dirty', 'color')
+ call assert_equal([], l)
+
+ let l = getcompletion('', 'command')
+ call assert_true(index(l, 'sleep') >= 0)
+ let l = getcompletion('awake', 'command')
+ call assert_equal([], l)
+
+ let l = getcompletion('', 'dir')
+ call assert_true(index(l, 'samples/') >= 0)
+ let l = getcompletion('NoMatch', 'dir')
+ call assert_equal([], l)
+
+ let l = getcompletion('exe', 'expression')
+ call assert_true(index(l, 'executable(') >= 0)
+ let l = getcompletion('kill', 'expression')
+ call assert_equal([], l)
+
+ let l = getcompletion('tag', 'function')
+ call assert_true(index(l, 'taglist(') >= 0)
+ let l = getcompletion('paint', 'function')
+ call assert_equal([], l)
+
+ let Flambda = {-> 'hello'}
+ let l = getcompletion('', 'function')
+ let l = filter(l, {i, v -> v =~ 'lambda'})
+ call assert_equal([], l)
+
+ let l = getcompletion('run', 'file')
+ call assert_true(index(l, 'runtest.vim') >= 0)
+ let l = getcompletion('walk', 'file')
+ call assert_equal([], l)
+ set wildignore=*.vim
+ let l = getcompletion('run', 'file', 1)
+ call assert_true(index(l, 'runtest.vim') < 0)
+ set wildignore&
+
+ let l = getcompletion('ha', 'filetype')
+ call assert_true(index(l, 'hamster') >= 0)
+ let l = getcompletion('horse', 'filetype')
+ call assert_equal([], l)
+
+ let l = getcompletion('z', 'syntax')
+ call assert_true(index(l, 'zimbu') >= 0)
+ let l = getcompletion('emacs', 'syntax')
+ call assert_equal([], l)
+
+ let l = getcompletion('jikes', 'compiler')
+ call assert_true(index(l, 'jikes') >= 0)
+ let l = getcompletion('break', 'compiler')
+ call assert_equal([], l)
+
+ let l = getcompletion('last', 'help')
+ call assert_true(index(l, ':tablast') >= 0)
+ let l = getcompletion('giveup', 'help')
+ call assert_equal([], l)
+
+ let l = getcompletion('time', 'option')
+ call assert_true(index(l, 'timeoutlen') >= 0)
+ let l = getcompletion('space', 'option')
+ call assert_equal([], l)
+
+ let l = getcompletion('er', 'highlight')
+ call assert_true(index(l, 'ErrorMsg') >= 0)
+ let l = getcompletion('dark', 'highlight')
+ call assert_equal([], l)
+
+ let l = getcompletion('', 'messages')
+ call assert_true(index(l, 'clear') >= 0)
+ let l = getcompletion('not', 'messages')
+ call assert_equal([], l)
+
+ let l = getcompletion('', 'mapclear')
+ call assert_true(index(l, '<buffer>') >= 0)
+ let l = getcompletion('not', 'mapclear')
+ call assert_equal([], l)
+
+ let l = getcompletion('.', 'shellcmd')
+ call assert_equal(['./', '../'], filter(l, 'v:val =~ "\\./"'))
+ call assert_equal(-1, match(l[2:], '^\.\.\?/$'))
+ let root = has('win32') ? 'C:\\' : '/'
+ let l = getcompletion(root, 'shellcmd')
+ let expected = map(filter(glob(root . '*', 0, 1),
+ \ 'isdirectory(v:val) || executable(v:val)'), 'isdirectory(v:val) ? v:val . ''/'' : v:val')
+ call assert_equal(expected, l)
+
+ if has('cscope')
+ let l = getcompletion('', 'cscope')
+ let cmds = ['add', 'find', 'help', 'kill', 'reset', 'show']
+ call assert_equal(cmds, l)
+ " using cmdline completion must not change the result
+ call feedkeys(":cscope find \<c-d>\<c-c>", 'xt')
+ let l = getcompletion('', 'cscope')
+ call assert_equal(cmds, l)
+ let keys = ['a', 'c', 'd', 'e', 'f', 'g', 'i', 's', 't']
+ let l = getcompletion('find ', 'cscope')
+ call assert_equal(keys, l)
+ endif
+
+ if has('signs')
+ sign define Testing linehl=Comment
+ let l = getcompletion('', 'sign')
+ let cmds = ['define', 'jump', 'list', 'place', 'undefine', 'unplace']
+ call assert_equal(cmds, l)
+ " using cmdline completion must not change the result
+ call feedkeys(":sign list \<c-d>\<c-c>", 'xt')
+ let l = getcompletion('', 'sign')
+ call assert_equal(cmds, l)
+ let l = getcompletion('list ', 'sign')
+ call assert_equal(['Testing'], l)
+ endif
+
+ " For others test if the name is recognized.
+ let names = ['buffer', 'environment', 'file_in_path', 'mapping', 'tag', 'tag_listfiles', 'user']
+ if has('cmdline_hist')
+ call add(names, 'history')
+ endif
+ if has('gettext')
+ call add(names, 'locale')
+ endif
+ if has('profile')
+ call add(names, 'syntime')
+ endif
+
+ set tags=Xtags
+ call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//", "word\tfile\tcmd"], 'Xtags')
+
+ for name in names
+ let matchcount = len(getcompletion('', name))
+ call assert_true(matchcount >= 0, 'No matches for ' . name)
+ endfor
+
+ call delete('Xtags')
+
+ call assert_fails('call getcompletion("", "burp")', 'E475:')
+endfunc
+
+func Test_shellcmd_completion()
+ let save_path = $PATH
+
+ call mkdir('Xpathdir/Xpathsubdir', 'p')
+ call writefile([''], 'Xpathdir/Xfile.exe')
+ call setfperm('Xpathdir/Xfile.exe', 'rwx------')
+
+ " Set PATH to example directory without trailing slash.
+ let $PATH = getcwd() . '/Xpathdir'
+
+ " Test for the ":!<TAB>" case. Previously, this would include subdirs of
+ " dirs in the PATH, even though they won't be executed. We check that only
+ " subdirs of the PWD and executables from the PATH are included in the
+ " suggestions.
+ let actual = getcompletion('X', 'shellcmd')
+ let expected = map(filter(glob('*', 0, 1), 'isdirectory(v:val) && v:val[0] == "X"'), 'v:val . "/"')
+ call insert(expected, 'Xfile.exe')
+ call assert_equal(expected, actual)
+
+ call delete('Xpathdir', 'rf')
+ let $PATH = save_path
+endfunc
+
+func Test_expand_star_star()
+ call mkdir('a/b', 'p')
+ call writefile(['asdfasdf'], 'a/b/fileXname')
+ call feedkeys(":find **/fileXname\<Tab>\<CR>", 'xt')
+ call assert_equal('find a/b/fileXname', getreg(':'))
+ bwipe!
+ call delete('a', 'rf')
+endfunc
+
+func Test_paste_in_cmdline()
+ let @a = "def"
+ call feedkeys(":abc \<C-R>a ghi\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"abc def ghi', @:)
+
+ new
+ call setline(1, 'asdf.x /tmp/some verylongword a;b-c*d ')
+
+ call feedkeys(":aaa \<C-R>\<C-W> bbb\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"aaa asdf bbb', @:)
+
+ call feedkeys("ft:aaa \<C-R>\<C-F> bbb\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"aaa /tmp/some bbb', @:)
+
+ call feedkeys(":aaa \<C-R>\<C-L> bbb\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"aaa '.getline(1).' bbb', @:)
+
+ set incsearch
+ call feedkeys("fy:aaa veryl\<C-R>\<C-W> bbb\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"aaa verylongword bbb', @:)
+
+ call feedkeys("f;:aaa \<C-R>\<C-A> bbb\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"aaa a;b-c*d bbb', @:)
+
+ call feedkeys(":\<C-\>etoupper(getline(1))\<CR>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"ASDF.X /TMP/SOME VERYLONGWORD A;B-C*D ', @:)
+ bwipe!
+
+ " Error while typing a command used to cause that it was not executed
+ " in the end.
+ new
+ try
+ call feedkeys(":file \<C-R>%Xtestfile\<CR>", 'tx')
+ catch /^Vim\%((\a\+)\)\=:E32/
+ " ignore error E32
+ endtry
+ call assert_equal("Xtestfile", bufname("%"))
+ bwipe!
+endfunc
+
+func Test_remove_char_in_cmdline()
+ call feedkeys(":abc def\<S-Left>\<Del>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"abc ef', @:)
+
+ call feedkeys(":abc def\<S-Left>\<BS>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"abcdef', @:)
+
+ call feedkeys(":abc def ghi\<S-Left>\<C-W>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"abc ghi', @:)
+
+ call feedkeys(":abc def\<S-Left>\<C-U>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"def', @:)
+endfunc
+
+func Test_illegal_address1()
+ new
+ 2;'(
+ 2;')
+ quit
+endfunc
+
+func Test_illegal_address2()
+ call writefile(['c', 'x', ' x', '.', '1;y'], 'Xtest.vim')
+ new
+ source Xtest.vim
+ " Trigger calling validate_cursor()
+ diffsp Xtest.vim
+ quit!
+ bwipe!
+ call delete('Xtest.vim')
+endfunc
+
+func Test_cmdline_complete_wildoptions()
+ help
+ call feedkeys(":tag /\<c-a>\<c-b>\"\<cr>", 'tx')
+ let a = join(sort(split(@:)),' ')
+ set wildoptions=tagfile
+ call feedkeys(":tag /\<c-a>\<c-b>\"\<cr>", 'tx')
+ let b = join(sort(split(@:)),' ')
+ call assert_equal(a, b)
+ bw!
+endfunc
+
+func Test_cmdline_complete_user_cmd()
+ command! -complete=color -nargs=1 Foo :
+ call feedkeys(":Foo \<Tab>\<Home>\"\<cr>", 'tx')
+ call assert_equal('"Foo blue', @:)
+ call feedkeys(":Foo b\<Tab>\<Home>\"\<cr>", 'tx')
+ call assert_equal('"Foo blue', @:)
+ delcommand Foo
+endfunc
+
+func Test_cmdline_complete_user_names()
+ if has('unix') && executable('whoami')
+ let whoami = systemlist('whoami')[0]
+ let first_letter = whoami[0]
+ if len(first_letter) > 0
+ " Trying completion of :e ~x where x is the first letter of
+ " the user name should complete to at least the user name.
+ call feedkeys(':e ~' . first_letter . "\<c-a>\<c-B>\"\<cr>", 'tx')
+ call assert_match('^"e \~.*\<' . whoami . '\>', @:)
+ endif
+ endif
+ if has('win32')
+ " Just in case: check that the system has an Administrator account.
+ let names = system('net user')
+ if names =~ 'Administrator'
+ " Trying completion of :e ~A should complete to Administrator.
+ " There could be other names starting with "A" before Administrator.
+ call feedkeys(':e ~A' . "\<c-a>\<c-B>\"\<cr>", 'tx')
+ call assert_match('^"e \~.*Administrator', @:)
+ endif
+ endif
+endfunc
+
+funct Test_cmdline_complete_languages()
+ let lang = substitute(execute('language messages'), '.*"\(.*\)"$', '\1', '')
+
+ call feedkeys(":language \<c-a>\<c-b>\"\<cr>", 'tx')
+ call assert_match('^"language .*\<ctype\>.*\<messages\>.*\<time\>', @:)
+
+ if has('unix')
+ " TODO: these tests don't work on Windows. lang appears to be 'C'
+ " but C does not appear in the completion. Why?
+ call assert_match('^"language .*\<' . lang . '\>', @:)
+
+ call feedkeys(":language messages \<c-a>\<c-b>\"\<cr>", 'tx')
+ call assert_match('^"language .*\<' . lang . '\>', @:)
+
+ call feedkeys(":language ctype \<c-a>\<c-b>\"\<cr>", 'tx')
+ call assert_match('^"language .*\<' . lang . '\>', @:)
+
+ call feedkeys(":language time \<c-a>\<c-b>\"\<cr>", 'tx')
+ call assert_match('^"language .*\<' . lang . '\>', @:)
+ endif
+endfunc
+
+func Test_cmdline_write_alternatefile()
+ new
+ call setline('.', ['one', 'two'])
+ f foo.txt
+ new
+ f #-A
+ call assert_equal('foo.txt-A', expand('%'))
+ f #<-B.txt
+ call assert_equal('foo-B.txt', expand('%'))
+ f %<
+ call assert_equal('foo-B', expand('%'))
+ new
+ call assert_fails('f #<', 'E95')
+ bw!
+ f foo-B.txt
+ f %<-A
+ call assert_equal('foo-B-A', expand('%'))
+ bw!
+ bw!
+endfunc
+
+" using a leading backslash here
+set cpo+=C
+
+func Test_cmdline_search_range()
+ new
+ call setline(1, ['a', 'b', 'c', 'd'])
+ /d
+ 1,\/s/b/B/
+ call assert_equal('B', getline(2))
+
+ /a
+ $
+ \?,4s/c/C/
+ call assert_equal('C', getline(3))
+
+ call setline(1, ['a', 'b', 'c', 'd'])
+ %s/c/c/
+ 1,\&s/b/B/
+ call assert_equal('B', getline(2))
+
+ bwipe!
+endfunc
+
+" Tests for getcmdline(), getcmdpos() and getcmdtype()
+func Check_cmdline(cmdtype)
+ call assert_equal('MyCmd a', getcmdline())
+ call assert_equal(8, getcmdpos())
+ call assert_equal(a:cmdtype, getcmdtype())
+ return ''
+endfunc
+
+func Test_getcmdtype()
+ call feedkeys(":MyCmd a\<C-R>=Check_cmdline(':')\<CR>\<Esc>", "xt")
+
+ let cmdtype = ''
+ debuggreedy
+ call feedkeys(":debug echo 'test'\<CR>", "t")
+ call feedkeys("let cmdtype = \<C-R>=string(getcmdtype())\<CR>\<CR>", "t")
+ call feedkeys("cont\<CR>", "xt")
+ 0debuggreedy
+ call assert_equal('>', cmdtype)
+
+ call feedkeys("/MyCmd a\<C-R>=Check_cmdline('/')\<CR>\<Esc>", "xt")
+ call feedkeys("?MyCmd a\<C-R>=Check_cmdline('?')\<CR>\<Esc>", "xt")
+
+ call feedkeys(":call input('Answer?')\<CR>", "t")
+ call feedkeys("MyCmd a\<C-R>=Check_cmdline('@')\<CR>\<C-C>", "xt")
+
+ call feedkeys(":insert\<CR>MyCmd a\<C-R>=Check_cmdline('-')\<CR>\<Esc>", "xt")
+
+ cnoremap <expr> <F6> Check_cmdline('=')
+ call feedkeys("a\<C-R>=MyCmd a\<F6>\<Esc>\<Esc>", "xt")
+ cunmap <F6>
+endfunc
+
+func Test_getcmdwintype()
+ call feedkeys("q/:let a = getcmdwintype()\<CR>:q\<CR>", 'x!')
+ call assert_equal('/', a)
+
+ call feedkeys("q?:let a = getcmdwintype()\<CR>:q\<CR>", 'x!')
+ call assert_equal('?', a)
+
+ call feedkeys("q::let a = getcmdwintype()\<CR>:q\<CR>", 'x!')
+ call assert_equal(':', a)
+
+ call feedkeys(":\<C-F>:let a = getcmdwintype()\<CR>:q\<CR>", 'x!')
+ call assert_equal(':', a)
+
+ call assert_equal('', getcmdwintype())
+endfunc
+
+func Test_verbosefile()
+ set verbosefile=Xlog
+ echomsg 'foo'
+ echomsg 'bar'
+ set verbosefile=
+ let log = readfile('Xlog')
+ call assert_match("foo\nbar", join(log, "\n"))
+ call delete('Xlog')
+endfunc
+
+func Test_setcmdpos()
+ func InsertTextAtPos(text, pos)
+ call assert_equal(0, setcmdpos(a:pos))
+ return a:text
+ endfunc
+
+ " setcmdpos() with position in the middle of the command line.
+ call feedkeys(":\"12\<C-R>=InsertTextAtPos('a', 3)\<CR>b\<CR>", 'xt')
+ call assert_equal('"1ab2', @:)
+
+ call feedkeys(":\"12\<C-R>\<C-R>=InsertTextAtPos('a', 3)\<CR>b\<CR>", 'xt')
+ call assert_equal('"1b2a', @:)
+
+ " setcmdpos() with position beyond the end of the command line.
+ call feedkeys(":\"12\<C-B>\<C-R>=InsertTextAtPos('a', 10)\<CR>b\<CR>", 'xt')
+ call assert_equal('"12ab', @:)
+
+ " setcmdpos() returns 1 when not editing the command line.
+ call assert_equal(1, setcmdpos(3))
+endfunc
+
+func Test_cmdline_overstrike()
+ let encodings = ['latin1', 'utf8']
+ let encoding_save = &encoding
+
+ for e in encodings
+ exe 'set encoding=' . e
+
+ " Test overstrike in the middle of the command line.
+ call feedkeys(":\"01234\<home>\<right>\<right>ab\<right>\<insert>cd\<enter>", 'xt')
+ call assert_equal('"0ab1cd4', @:)
+
+ " Test overstrike going beyond end of command line.
+ call feedkeys(":\"01234\<home>\<right>\<right>ab\<right>\<insert>cdefgh\<enter>", 'xt')
+ call assert_equal('"0ab1cdefgh', @:)
+
+ " Test toggling insert/overstrike a few times.
+ call feedkeys(":\"01234\<home>\<right>ab\<right>\<insert>cd\<right>\<insert>ef\<enter>", 'xt')
+ call assert_equal('"ab0cd3ef4', @:)
+ endfor
+
+ " Test overstrike with multi-byte characters.
+ call feedkeys(":\"テキストエディタ\<home>\<right>\<right>ab\<right>\<insert>cd\<enter>", 'xt')
+ call assert_equal('"テabキcdエディタ', @:)
+
+ let &encoding = encoding_save
+endfunc
+
+set cpo&
diff --git a/src/testdir/test_command_count.vim b/src/testdir/test_command_count.vim
new file mode 100644
index 0000000..55b2303
--- /dev/null
+++ b/src/testdir/test_command_count.vim
@@ -0,0 +1,196 @@
+" Test for user command counts.
+
+func Test_command_count_0()
+ let bufnr = bufnr('%')
+ set hidden
+ set noswapfile
+
+ split DoesNotExistEver
+ let lastbuf = bufnr('$')
+ call setline(1, 'asdf')
+ quit!
+
+ command! -range -addr=loaded_buffers RangeLoadedBuffers :let lines = [<line1>, <line2>]
+ command! -range=% -addr=loaded_buffers RangeLoadedBuffersAll :let lines = [<line1>, <line2>]
+ command! -range -addr=buffers RangeBuffers :let lines = [<line1>, <line2>]
+ command! -range=% -addr=buffers RangeBuffersAll :let lines = [<line1>, <line2>]
+
+ .,$RangeLoadedBuffers
+ call assert_equal([bufnr, bufnr], lines)
+ %RangeLoadedBuffers
+ call assert_equal([bufnr, bufnr], lines)
+ RangeLoadedBuffersAll
+ call assert_equal([bufnr, bufnr], lines)
+ .,$RangeBuffers
+ call assert_equal([bufnr, lastbuf], lines)
+ %RangeBuffers
+ call assert_equal([bufnr, lastbuf], lines)
+ RangeBuffersAll
+ call assert_equal([bufnr, lastbuf], lines)
+
+ delcommand RangeLoadedBuffers
+ delcommand RangeLoadedBuffersAll
+ delcommand RangeBuffers
+ delcommand RangeBuffersAll
+
+ set hidden&
+ set swapfile&
+endfunc
+
+func Test_command_count_1()
+ silent! %argd
+ arga a b c d e
+ argdo echo "loading buffers"
+ argu 3
+ command! -range -addr=arguments RangeArguments :let lines = [<line1>, <line2>]
+ command! -range=% -addr=arguments RangeArgumentsAll :let lines = [<line1>, <line2>]
+ .-,$-RangeArguments
+ call assert_equal([2, 4], lines)
+ %RangeArguments
+ call assert_equal([1, 5], lines)
+ RangeArgumentsAll
+ call assert_equal([1, 5], lines)
+ N
+ .RangeArguments
+ call assert_equal([2, 2], lines)
+ delcommand RangeArguments
+ delcommand RangeArgumentsAll
+
+ split|split|split|split
+ 3wincmd w
+ command! -range -addr=windows RangeWindows :let lines = [<line1>, <line2>]
+ .,$RangeWindows
+ call assert_equal([3, 5], lines)
+ %RangeWindows
+ call assert_equal([1, 5], lines)
+ delcommand RangeWindows
+
+ command! -range=% -addr=windows RangeWindowsAll :let lines = [<line1>, <line2>]
+ RangeWindowsAll
+ call assert_equal([1, 5], lines)
+ delcommand RangeWindowsAll
+ only
+ blast|bd
+
+ tabe|tabe|tabe|tabe
+ normal 2gt
+ command! -range -addr=tabs RangeTabs :let lines = [<line1>, <line2>]
+ .,$RangeTabs
+ call assert_equal([2, 5], lines)
+ %RangeTabs
+ call assert_equal([1, 5], lines)
+ delcommand RangeTabs
+
+ command! -range=% -addr=tabs RangeTabsAll :let lines = [<line1>, <line2>]
+ RangeTabsAll
+ call assert_equal([1, 5], lines)
+ delcommand RangeTabsAll
+ 1tabonly
+
+ s/\n/\r\r\r\r\r/
+ 2ma<
+ $-ma>
+ command! -range=% RangeLines :let lines = [<line1>, <line2>]
+ '<,'>RangeLines
+ call assert_equal([2, 5], lines)
+ delcommand RangeLines
+
+ command! -range=% -buffer LocalRangeLines :let lines = [<line1>, <line2>]
+ '<,'>LocalRangeLines
+ call assert_equal([2, 5], lines)
+ delcommand LocalRangeLines
+endfunc
+
+func Test_command_count_2()
+ silent! %argd
+ arga a b c d
+ call assert_fails('5argu', 'E16:')
+
+ $argu
+ call assert_equal('d', expand('%:t'))
+
+ 1argu
+ call assert_equal('a', expand('%:t'))
+
+ call assert_fails('300b', 'E16:')
+
+ split|split|split|split
+ 0close
+
+ $wincmd w
+ $close
+ call assert_equal(3, winnr())
+
+ call assert_fails('$+close', 'E16:')
+
+ $tabe
+ call assert_equal(2, tabpagenr())
+
+ call assert_fails('$+tabe', 'E16:')
+
+ only!
+ e x
+ 0tabm
+ normal 1gt
+ call assert_equal('x', expand('%:t'))
+
+ tabonly!
+ only!
+endfunc
+
+func Test_command_count_3()
+ let bufnr = bufnr('%')
+ se nohidden
+ e aaa
+ let buf_aaa = bufnr('%')
+ e bbb
+ let buf_bbb = bufnr('%')
+ e ccc
+ let buf_ccc = bufnr('%')
+ exe bufnr . 'buf'
+ call assert_equal([1, 1, 1], [buflisted(buf_aaa), buflisted(buf_bbb), buflisted(buf_ccc)])
+ exe buf_bbb . "," . buf_ccc . "bdelete"
+ call assert_equal([1, 0, 0], [buflisted(buf_aaa), buflisted(buf_bbb), buflisted(buf_ccc)])
+ exe buf_aaa . "bdelete"
+ call assert_equal([0, 0, 0], [buflisted(buf_aaa), buflisted(buf_bbb), buflisted(buf_ccc)])
+endfunc
+
+func Test_command_count_4()
+ %argd
+ let bufnr = bufnr('$')
+ next aa bb cc dd ee ff
+ call assert_equal(bufnr, bufnr('%'))
+
+ 3argu
+ let args = []
+ .,$-argdo call add(args, expand('%'))
+ call assert_equal(['cc', 'dd', 'ee'], args)
+
+ " create windows to get 5
+ split|split|split|split
+ 2wincmd w
+ let windows = []
+ .,$-windo call add(windows, winnr())
+ call assert_equal([2, 3, 4], windows)
+ only!
+
+ exe bufnr . 'buf'
+ let bufnr = bufnr('%')
+ let buffers = []
+ .,$-bufdo call add(buffers, bufnr('%'))
+ call assert_equal([bufnr, bufnr + 1, bufnr + 2, bufnr + 3, bufnr + 4], buffers)
+
+ exe (bufnr + 3) . 'bdel'
+ let buffers = []
+ exe (bufnr + 2) . ',' . (bufnr + 5) . "bufdo call add(buffers, bufnr('%'))"
+ call assert_equal([bufnr + 2, bufnr + 4, bufnr + 5], buffers)
+
+ " create tabpages to get 5
+ tabe|tabe|tabe|tabe
+ normal! 2gt
+ let tabpages = []
+ .,$-tabdo call add(tabpages, tabpagenr())
+ call assert_equal([2, 3, 4], tabpages)
+ tabonly!
+ bwipe!
+endfunc
diff --git a/src/testdir/test_comparators.vim b/src/testdir/test_comparators.vim
new file mode 100644
index 0000000..87be006
--- /dev/null
+++ b/src/testdir/test_comparators.vim
@@ -0,0 +1,9 @@
+function Test_Comparators()
+ try
+ let oldisident=&isident
+ set isident+=#
+ call assert_equal(1, 1 is#1)
+ finally
+ let &isident=oldisident
+ endtry
+endfunction
diff --git a/src/testdir/test_compiler.vim b/src/testdir/test_compiler.vim
new file mode 100644
index 0000000..46c14d8
--- /dev/null
+++ b/src/testdir/test_compiler.vim
@@ -0,0 +1,54 @@
+" Test the :compiler command
+
+func Test_compiler()
+ if !executable('perl')
+ return
+ endif
+
+ " $LANG changes the output of Perl.
+ if $LANG != ''
+ unlet $LANG
+ endif
+
+ e Xfoo.pl
+ compiler perl
+ call assert_equal('perl', b:current_compiler)
+ call assert_fails('let g:current_compiler', 'E121:')
+
+ call setline(1, ['#!/usr/bin/perl -w', 'use strict;', 'my $foo=1'])
+ w!
+ call feedkeys(":make\<CR>\<CR>", 'tx')
+ call assert_fails('clist', 'E42:')
+
+ call setline(1, ['#!/usr/bin/perl -w', 'use strict;', '$foo=1'])
+ w!
+ call feedkeys(":make\<CR>\<CR>", 'tx')
+ let a=execute('clist')
+ call assert_match("\n 1 Xfoo.pl:3: Global symbol \"\$foo\" "
+ \ . "requires explicit package name", a)
+
+ call delete('Xfoo.pl')
+ bw!
+endfunc
+
+func Test_compiler_without_arg()
+ let a=split(execute('compiler'))
+ call assert_match('^.*runtime/compiler/ant.vim$', a[0])
+ call assert_match('^.*runtime/compiler/bcc.vim$', a[1])
+ call assert_match('^.*runtime/compiler/xmlwf.vim$', a[-1])
+endfunc
+
+func Test_compiler_completion()
+ call feedkeys(":compiler \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_match('^"compiler ant bcc .* xmlwf$', @:)
+
+ call feedkeys(":compiler p\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"compiler pbx perl php pylint pyunit', @:)
+
+ call feedkeys(":compiler! p\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"compiler! pbx perl php pylint pyunit', @:)
+endfunc
+
+func Test_compiler_error()
+ call assert_fails('compiler doesnotexist', 'E666:')
+endfunc
diff --git a/src/testdir/test_conceal.vim b/src/testdir/test_conceal.vim
new file mode 100644
index 0000000..685c891
--- /dev/null
+++ b/src/testdir/test_conceal.vim
@@ -0,0 +1,136 @@
+" Tests for 'conceal'.
+" Also see test88.in (should be converted to a test function here).
+
+if !has('conceal')
+ finish
+endif
+
+source screendump.vim
+if !CanRunVimInTerminal()
+ finish
+endif
+
+func Test_conceal_two_windows()
+ call writefile([
+ \ 'let lines = ["one one one one one", "two |hidden| here", "three |hidden| three"]',
+ \ 'call setline(1, lines)',
+ \ 'syntax match test /|hidden|/ conceal',
+ \ 'set conceallevel=2',
+ \ 'set concealcursor=',
+ \ 'exe "normal /here\r"',
+ \ 'new',
+ \ 'call setline(1, lines)',
+ \ 'call setline(4, "Second window")',
+ \ 'syntax match test /|hidden|/ conceal',
+ \ 'set conceallevel=2',
+ \ 'set concealcursor=nc',
+ \ 'exe "normal /here\r"',
+ \ ], 'XTest_conceal')
+ " Check that cursor line is concealed
+ let buf = RunVimInTerminal('-S XTest_conceal', {})
+ call VerifyScreenDump(buf, 'Test_conceal_two_windows_01', {})
+
+ " Check that with concealed text vertical cursor movement is correct.
+ call term_sendkeys(buf, "k")
+ call VerifyScreenDump(buf, 'Test_conceal_two_windows_02', {})
+
+ " Check that with cursor line is not concealed
+ call term_sendkeys(buf, "j")
+ call term_sendkeys(buf, ":set concealcursor=\r")
+ call VerifyScreenDump(buf, 'Test_conceal_two_windows_03', {})
+
+ " Check that with cursor line is not concealed when moving cursor down
+ call term_sendkeys(buf, "j")
+ call VerifyScreenDump(buf, 'Test_conceal_two_windows_04', {})
+
+ " Check that with cursor line is not concealed when switching windows
+ call term_sendkeys(buf, "\<C-W>\<C-W>")
+ call VerifyScreenDump(buf, 'Test_conceal_two_windows_05', {})
+
+ " Check that with cursor line is only concealed in Normal mode
+ call term_sendkeys(buf, ":set concealcursor=n\r")
+ call VerifyScreenDump(buf, 'Test_conceal_two_windows_06n', {})
+ call term_sendkeys(buf, "a")
+ call VerifyScreenDump(buf, 'Test_conceal_two_windows_06i', {})
+ call term_sendkeys(buf, "\<Esc>/e")
+ call VerifyScreenDump(buf, 'Test_conceal_two_windows_06c', {})
+ call term_sendkeys(buf, "\<Esc>v")
+ call VerifyScreenDump(buf, 'Test_conceal_two_windows_06v', {})
+ call term_sendkeys(buf, "\<Esc>")
+
+ " Check that with cursor line is only concealed in Insert mode
+ call term_sendkeys(buf, ":set concealcursor=i\r")
+ call VerifyScreenDump(buf, 'Test_conceal_two_windows_07n', {})
+ call term_sendkeys(buf, "a")
+ call VerifyScreenDump(buf, 'Test_conceal_two_windows_07i', {})
+ call term_sendkeys(buf, "\<Esc>/e")
+ call VerifyScreenDump(buf, 'Test_conceal_two_windows_07c', {})
+ call term_sendkeys(buf, "\<Esc>v")
+ call VerifyScreenDump(buf, 'Test_conceal_two_windows_07v', {})
+ call term_sendkeys(buf, "\<Esc>")
+
+ " Check that with cursor line is only concealed in Command mode
+ call term_sendkeys(buf, ":set concealcursor=c\r")
+ call VerifyScreenDump(buf, 'Test_conceal_two_windows_08n', {})
+ call term_sendkeys(buf, "a")
+ call VerifyScreenDump(buf, 'Test_conceal_two_windows_08i', {})
+ call term_sendkeys(buf, "\<Esc>/e")
+ call VerifyScreenDump(buf, 'Test_conceal_two_windows_08c', {})
+ call term_sendkeys(buf, "\<Esc>v")
+ call VerifyScreenDump(buf, 'Test_conceal_two_windows_08v', {})
+ call term_sendkeys(buf, "\<Esc>")
+
+ " Check that with cursor line is only concealed in Visual mode
+ call term_sendkeys(buf, ":set concealcursor=v\r")
+ call VerifyScreenDump(buf, 'Test_conceal_two_windows_09n', {})
+ call term_sendkeys(buf, "a")
+ call VerifyScreenDump(buf, 'Test_conceal_two_windows_09i', {})
+ call term_sendkeys(buf, "\<Esc>/e")
+ call VerifyScreenDump(buf, 'Test_conceal_two_windows_09c', {})
+ call term_sendkeys(buf, "\<Esc>v")
+ call VerifyScreenDump(buf, 'Test_conceal_two_windows_09v', {})
+ call term_sendkeys(buf, "\<Esc>")
+
+ " Check moving the cursor while in insert mode.
+ call term_sendkeys(buf, ":set concealcursor=\r")
+ call term_sendkeys(buf, "a")
+ call VerifyScreenDump(buf, 'Test_conceal_two_windows_10', {})
+ call term_sendkeys(buf, "\<Down>")
+ call VerifyScreenDump(buf, 'Test_conceal_two_windows_11', {})
+ call term_sendkeys(buf, "\<Esc>")
+
+ " Check the "o" command
+ call VerifyScreenDump(buf, 'Test_conceal_two_windows_12', {})
+ call term_sendkeys(buf, "o")
+ call VerifyScreenDump(buf, 'Test_conceal_two_windows_13', {})
+ call term_sendkeys(buf, "\<Esc>")
+
+ " clean up
+ call StopVimInTerminal(buf)
+ call delete('XTest_conceal')
+endfunc
+
+func Test_conceal_with_cursorline()
+ " Opens a help window, where 'conceal' is set, switches to the other window
+ " where 'cursorline' needs to be updated when the cursor moves.
+ call writefile([
+ \ 'set cursorline',
+ \ 'normal othis is a test',
+ \ 'new',
+ \ 'call setline(1, ["one", "two", "three", "four", "five"])',
+ \ 'set ft=help',
+ \ 'normal M',
+ \ ], 'XTest_conceal_cul')
+ let buf = RunVimInTerminal('-S XTest_conceal_cul', {})
+ call VerifyScreenDump(buf, 'Test_conceal_cul_01', {})
+
+ call term_sendkeys(buf, ":wincmd w\r")
+ call VerifyScreenDump(buf, 'Test_conceal_cul_02', {})
+
+ call term_sendkeys(buf, "k")
+ call VerifyScreenDump(buf, 'Test_conceal_cul_03', {})
+
+ " clean up
+ call StopVimInTerminal(buf)
+ call delete('XTest_conceal_cul')
+endfunc
diff --git a/src/testdir/test_crypt.vim b/src/testdir/test_crypt.vim
new file mode 100644
index 0000000..bf1a511
--- /dev/null
+++ b/src/testdir/test_crypt.vim
@@ -0,0 +1,113 @@
+" Tests for encryption.
+
+if !has('cryptv')
+ finish
+endif
+
+func Common_head_only(text)
+ " This was crashing Vim
+ split Xtest.txt
+ call setline(1, a:text)
+ wq
+ call feedkeys(":split Xtest.txt\<CR>foobar\<CR>", "tx")
+ call delete('Xtest.txt')
+ call assert_match('VimCrypt', getline(1))
+ bwipe!
+endfunc
+
+func Test_head_only_2()
+ call Common_head_only('VimCrypt~02!abc')
+endfunc
+
+func Test_head_only_3()
+ call Common_head_only('VimCrypt~03!abc')
+endfunc
+
+func Crypt_uncrypt(method)
+ exe "set cryptmethod=" . a:method
+ " If the blowfish test fails 'cryptmethod' will be 'zip' now.
+ call assert_equal(a:method, &cryptmethod)
+
+ split Xtest.txt
+ let text = ['01234567890123456789012345678901234567',
+ \ 'line 2 foo bar blah',
+ \ 'line 3 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx']
+ call setline(1, text)
+ call feedkeys(":X\<CR>foobar\<CR>foobar\<CR>", 'xt')
+ call assert_equal('*****', &key)
+ w!
+ bwipe!
+ call feedkeys(":split Xtest.txt\<CR>foobar\<CR>", 'xt')
+ call assert_equal(text, getline(1, 3))
+ set key= cryptmethod&
+ bwipe!
+ call delete('Xtest.txt')
+endfunc
+
+func Test_crypt_zip()
+ call Crypt_uncrypt('zip')
+endfunc
+
+func Test_crypt_blowfish()
+ call Crypt_uncrypt('blowfish')
+endfunc
+
+func Test_crypt_blowfish2()
+ call Crypt_uncrypt('blowfish2')
+endfunc
+
+func Uncrypt_stable(method, crypted_text, key, uncrypted_text)
+ split Xtest.txt
+ set bin noeol key= fenc=latin1
+ exe "set cryptmethod=" . a:method
+ call setline(1, a:crypted_text)
+ w!
+ bwipe!
+ set nobin
+ call feedkeys(":split Xtest.txt\<CR>" . a:key . "\<CR>", 'xt')
+ call assert_equal(a:uncrypted_text, getline(1, len(a:uncrypted_text)))
+ bwipe!
+ call delete('Xtest.txt')
+ set key=
+endfunc
+
+func Test_uncrypt_zip()
+ call Uncrypt_stable('zip', "VimCrypt~01!\u0006\u001clV'\u00de}Mg\u00a0\u00ea\u00a3V\u00a9\u00e7\u0007E#3\u008e2U\u00e9\u0097", "foofoo", ["1234567890", "aábbccddeëff"])
+endfunc
+
+func Test_uncrypt_blowfish()
+ call Uncrypt_stable('blowfish', "VimCrypt~02!k)\u00be\u0017\u0097#\u0016\u00ddS\u009c\u00f5=\u00ba\u00e0\u00c8#\u00a5M\u00b4\u0086J\u00c3A\u00cd\u00a5M\u00b4\u0086!\u0080\u0015\u009b\u00f5\u000f\u00e1\u00d2\u0019\u0082\u0016\u0098\u00f7\u000d\u00da", "barbar", ["asdfasdfasdf", "0001112223333"])
+endfunc
+
+func Test_uncrypt_blowfish2()
+ call Uncrypt_stable('blowfish', "VimCrypt~03!\u001e\u00d1N\u00e3;\u00d3\u00c0\u00a0^C)\u0004\u00f7\u007f.\u00b6\u00abF\u000eS\u0019\u00e0\u008b6\u00d2[T\u00cb\u00a7\u0085\u00d8\u00be9\u000b\u00812\u000bQ\u00b3\u00cc@\u0097\u000f\u00df\u009a\u00adIv\u00aa.\u00d8\u00c9\u00ee\u009e`\u00bd$\u00af%\u00d0", "barburp", ["abcdefghijklmnopqrstuvwxyz", "!@#$%^&*()_+=-`~"])
+endfunc
+
+func Test_uncrypt_unknown_method()
+ split Xuncrypt_unknown.txt
+ set bin noeol key= fenc=latin1
+ call setline(1, "VimCrypt~93!\u001e\u00d1")
+ w!
+ bwipe!
+ set nobin
+ call assert_fails(":split Xuncrypt_unknown.txt", 'E821:')
+
+ bwipe!
+ call delete('Xuncrypt_unknown.txt')
+ set key=
+endfunc
+
+func Test_crypt_key_mismatch()
+ set cryptmethod=blowfish
+
+ split Xtest.txt
+ call setline(1, 'nothing')
+ call feedkeys(":X\<CR>foobar\<CR>nothing\<CR>", 'xt')
+ call assert_match("Keys don't match!", execute(':2messages'))
+ call assert_equal('', &key)
+ call feedkeys("\<CR>\<CR>", 'xt')
+
+ set cryptmethod&
+ bwipe!
+endfunc
+
diff --git a/src/testdir/test_cscope.vim b/src/testdir/test_cscope.vim
new file mode 100644
index 0000000..63f2c18
--- /dev/null
+++ b/src/testdir/test_cscope.vim
@@ -0,0 +1,302 @@
+" Test for cscope commands.
+
+if !has('cscope') || !executable('cscope') || !has('quickfix')
+ finish
+endif
+
+func CscopeSetupOrClean(setup)
+ if a:setup
+ noa sp ../memfile_test.c
+ saveas! Xmemfile_test.c
+ call system('cscope -bk -fXcscope.out Xmemfile_test.c')
+ call system('cscope -bk -fXcscope2.out Xmemfile_test.c')
+ cscope add Xcscope.out
+ set cscopequickfix=s-,g-,d-,c-,t-,e-,f-,i-,a-
+ else
+ cscope kill -1
+ for file in ['Xcscope.out', 'Xcscope2.out', 'Xmemfile_test.c']
+ call delete(file)
+ endfo
+ endif
+endfunc
+
+func Test_cscopeWithCscopeConnections()
+ call CscopeSetupOrClean(1)
+ " Test 0: E568: duplicate cscope database not added
+ try
+ set nocscopeverbose
+ cscope add Xcscope.out
+ set cscopeverbose
+ catch
+ call assert_report('exception thrown')
+ endtry
+ call assert_fails('cscope add', 'E560')
+ call assert_fails('cscope add Xcscope.out', 'E568')
+ call assert_fails('cscope add doesnotexist.out', 'E563')
+
+ " Test 1: Find this C-Symbol
+ for cmd in ['cs find s main', 'cs find 0 main']
+ let a = execute(cmd)
+ " Test 1.1 test where it moves the cursor
+ call assert_equal('main(void)', getline('.'))
+ " Test 1.2 test the output of the :cs command
+ call assert_match('\n(1 of 1): <<main>> main(void )', a)
+ endfor
+
+ " Test 2: Find this definition
+ for cmd in ['cs find g test_mf_hash', 'cs find 1 test_mf_hash']
+ exe cmd
+ call assert_equal(['', '/*', ' * Test mf_hash_*() functions.', ' */', ' static void', 'test_mf_hash(void)', '{'], getline(line('.')-5, line('.')+1))
+ endfor
+
+ " Test 3: Find functions called by this function
+ for cmd in ['cs find d test_mf_hash', 'cs find 2 test_mf_hash']
+ let a = execute(cmd)
+ call assert_match('\n(1 of 42): <<mf_hash_init>> mf_hash_init(&ht);', a)
+ call assert_equal(' mf_hash_init(&ht);', getline('.'))
+ endfor
+
+ " Test 4: Find functions calling this function
+ for cmd in ['cs find c test_mf_hash', 'cs find 3 test_mf_hash']
+ let a = execute(cmd)
+ call assert_match('\n(1 of 1): <<main>> test_mf_hash();', a)
+ call assert_equal(' test_mf_hash();', getline('.'))
+ endfor
+
+ " Test 5: Find this text string
+ for cmd in ['cs find t Bram', 'cs find 4 Bram']
+ let a = execute(cmd)
+ call assert_match('(1 of 1): <<<unknown>>> \* VIM - Vi IMproved^Iby Bram Moolenaar', a)
+ call assert_equal(' * VIM - Vi IMproved by Bram Moolenaar', getline('.'))
+ endfor
+
+ " Test 6: Find this egrep pattern
+ " test all matches returned by cscope
+ for cmd in ['cs find e ^\#includ.', 'cs find 6 ^\#includ.']
+ let a = execute(cmd)
+ call assert_match('\n(1 of 3): <<<unknown>>> #include <assert.h>', a)
+ call assert_equal('#include <assert.h>', getline('.'))
+ cnext
+ call assert_equal('#include "main.c"', getline('.'))
+ cnext
+ call assert_equal('#include "memfile.c"', getline('.'))
+ call assert_fails('cnext', 'E553:')
+ endfor
+
+ " Test 7: Find the same egrep pattern using lcscope this time.
+ let a = execute('lcs find e ^\#includ.')
+ call assert_match('\n(1 of 3): <<<unknown>>> #include <assert.h>', a)
+ call assert_equal('#include <assert.h>', getline('.'))
+ lnext
+ call assert_equal('#include "main.c"', getline('.'))
+ lnext
+ call assert_equal('#include "memfile.c"', getline('.'))
+ call assert_fails('lnext', 'E553:')
+
+ " Test 8: Find this file
+ for cmd in ['cs find f Xmemfile_test.c', 'cs find 7 Xmemfile_test.c']
+ enew
+ let a = execute(cmd)
+ call assert_true(a =~ '"Xmemfile_test.c" \d\+L, \d\+C')
+ call assert_equal('Xmemfile_test.c', @%)
+ endfor
+
+ " Test 9: Find files #including this file
+ for cmd in ['cs find i assert.h', 'cs find 8 assert.h']
+ enew
+ let a = execute(cmd)
+ let alines = split(a, '\n', 1)
+ call assert_equal('', alines[0])
+ call assert_true(alines[1] =~ '"Xmemfile_test.c" \d\+L, \d\+C')
+ call assert_equal('(1 of 1): <<global>> #include <assert.h>', alines[2])
+ call assert_equal('#include <assert.h>', getline('.'))
+ endfor
+
+ " Test 10: Invalid find command
+ call assert_fails('cs find x', 'E560:')
+
+ " Test 11: Find places where this symbol is assigned a value
+ " this needs a cscope >= 15.8
+ " unfortunately, Travis has cscope version 15.7
+ let cscope_version = systemlist('cscope --version')[0]
+ let cs_version = str2float(matchstr(cscope_version, '\d\+\(\.\d\+\)\?'))
+ if cs_version >= 15.8
+ for cmd in ['cs find a item', 'cs find 9 item']
+ let a = execute(cmd)
+ call assert_equal(['', '(1 of 4): <<test_mf_hash>> item = (mf_hashitem_T *)lalloc_clear(sizeof(mf_hashtab_T), FALSE);'], split(a, '\n', 1))
+ call assert_equal(' item = (mf_hashitem_T *)lalloc_clear(sizeof(mf_hashtab_T), FALSE);', getline('.'))
+ cnext
+ call assert_equal(' item = mf_hash_find(&ht, key);', getline('.'))
+ cnext
+ call assert_equal(' item = mf_hash_find(&ht, key);', getline('.'))
+ cnext
+ call assert_equal(' item = mf_hash_find(&ht, key);', getline('.'))
+ endfor
+ endif
+
+ " Test 12: leading whitespace is not removed for cscope find text
+ let a = execute('cscope find t test_mf_hash')
+ call assert_equal(['', '(1 of 1): <<<unknown>>> test_mf_hash();'], split(a, '\n', 1))
+ call assert_equal(' test_mf_hash();', getline('.'))
+
+ " Test 13: test with scscope
+ let a = execute('scs find t Bram')
+ call assert_match('(1 of 1): <<<unknown>>> \* VIM - Vi IMproved^Iby Bram Moolenaar', a)
+ call assert_equal(' * VIM - Vi IMproved by Bram Moolenaar', getline('.'))
+
+ " Test 14: cscope help
+ for cmd in ['cs', 'cs help', 'cs xxx']
+ let a = execute(cmd)
+ call assert_match('^cscope commands:\n', a)
+ call assert_match('\nadd :', a)
+ call assert_match('\nfind :', a)
+ call assert_match('\nhelp : Show this message', a)
+ call assert_match('\nkill : Kill a connection', a)
+ call assert_match('\nreset: Reinit all connections', a)
+ call assert_match('\nshow : Show connections', a)
+ endfor
+ let a = execute('scscope help')
+ call assert_match('This cscope command does not support splitting the window\.', a)
+
+ " Test 15: reset connections
+ let a = execute('cscope reset')
+ call assert_match('\nAdded cscope database.*Xcscope.out (#0)', a)
+ call assert_match('\nAll cscope databases reset', a)
+
+ " Test 16: cscope show
+ let a = execute('cscope show')
+ call assert_match('\n 0 \d\+.*Xcscope.out\s*<none>', a)
+
+ " Test 17: cstag and 'csto' option
+ set csto=0
+ let a = execute('cstag TEST_COUNT')
+ call assert_match('(1 of 1): <<TEST_COUNT>> #define TEST_COUNT 50000', a)
+ call assert_equal('#define TEST_COUNT 50000', getline('.'))
+ set csto=1
+ let a = execute('cstag index_to_key')
+ call assert_match('(1 of 1): <<index_to_key>> #define index_to_key(i) ((i) ^ 15167)', a)
+ call assert_equal('#define index_to_key(i) ((i) ^ 15167)', getline('.'))
+ call assert_fails('cstag xxx', 'E257:')
+ call assert_fails('cstag', 'E562:')
+
+ " Test 18: 'cst' option
+ set nocst
+ call assert_fails('tag TEST_COUNT', 'E426:')
+ set cst
+ let a = execute('tag TEST_COUNT')
+ call assert_match('(1 of 1): <<TEST_COUNT>> #define TEST_COUNT 50000', a)
+ call assert_equal('#define TEST_COUNT 50000', getline('.'))
+ let a = execute('tags')
+ call assert_match('1 1 TEST_COUNT\s\+\d\+\s\+#define index_to_key', a)
+
+ " Test 19: this should trigger call to cs_print_tags()
+ " Unclear how to check result though, we just exercise the code.
+ set cst cscopequickfix=s0
+ call feedkeys(":cs find s main\<CR>", 't')
+
+ " Test 20: cscope kill
+ call assert_fails('cscope kill 2', 'E261:')
+ call assert_fails('cscope kill xxx', 'E261:')
+
+ let a = execute('cscope kill 0')
+ call assert_match('cscope connection 0 closed', a)
+
+ cscope add Xcscope.out
+ let a = execute('cscope kill Xcscope.out')
+ call assert_match('cscope connection Xcscope.out closed', a)
+
+ cscope add Xcscope.out .
+ let a = execute('cscope kill -1')
+ call assert_match('cscope connection .*Xcscope.out closed', a)
+ let a = execute('cscope kill -1')
+ call assert_equal('', a)
+
+ " Test 21: 'csprg' option
+ call assert_equal('cscope', &csprg)
+ set csprg=doesnotexist
+ call assert_fails('cscope add Xcscope2.out', 'E609:')
+ set csprg=cscope
+
+ " Test 22: multiple cscope connections
+ cscope add Xcscope.out
+ cscope add Xcscope2.out . -C
+ let a = execute('cscope show')
+ call assert_match('\n 0 \d\+.*Xcscope.out\s*<none>', a)
+ call assert_match('\n 1 \d\+.*Xcscope2.out\s*\.', a)
+
+ " Test 23: test Ex command line completion
+ call feedkeys(":cs \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"cs add find help kill reset show', @:)
+
+ call feedkeys(":scs \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"scs find', @:)
+
+ call feedkeys(":cs find \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"cs find a c d e f g i s t', @:)
+
+ call feedkeys(":cs kill \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"cs kill -1 0 1', @:)
+
+ call feedkeys(":cs add Xcscope\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"cs add Xcscope.out Xcscope2.out', @:)
+
+ " Test 24: cscope_connection()
+ call assert_equal(cscope_connection(), 1)
+ call assert_equal(cscope_connection(0, 'out'), 1)
+ call assert_equal(cscope_connection(0, 'xxx'), 1)
+ call assert_equal(cscope_connection(1, 'out'), 1)
+ call assert_equal(cscope_connection(1, 'xxx'), 0)
+ call assert_equal(cscope_connection(2, 'out'), 0)
+ call assert_equal(cscope_connection(3, 'xxx', '..'), 0)
+ call assert_equal(cscope_connection(3, 'out', 'xxx'), 0)
+ call assert_equal(cscope_connection(3, 'out', '.'), 1)
+ call assert_equal(cscope_connection(4, 'out', '.'), 0)
+
+ " CleanUp
+ call CscopeSetupOrClean(0)
+endfunc
+
+" Test ":cs add {dir}" (add the {dir}/cscope.out database)
+func Test_cscope_add_dir()
+ call mkdir('Xcscopedir', 'p')
+
+ " Cscope doesn't handle symlinks, so this needs to be resolved in case a
+ " shadow directory is being used.
+ let memfile = resolve('../memfile_test.c')
+ call system('cscope -bk -fXcscopedir/cscope.out ' . memfile)
+
+ cs add Xcscopedir
+ let a = execute('cscope show')
+ let lines = split(a, "\n", 1)
+ call assert_equal(3, len(lines))
+ call assert_equal(' # pid database name prepend path', lines[0])
+ call assert_equal('', lines[1])
+ call assert_match('^ 0 \d\+.*Xcscopedir/cscope.out\s\+<none>$', lines[2])
+
+ cs kill -1
+ call delete('Xcscopedir/cscope.out')
+ call assert_fails('cs add Xcscopedir', 'E563:')
+
+ call delete('Xcscopedir', 'd')
+endfunc
+
+func Test_cscopequickfix()
+ set cscopequickfix=s-,g-,d+,c-,t+,e-,f0,i-,a-
+ call assert_equal('s-,g-,d+,c-,t+,e-,f0,i-,a-', &cscopequickfix)
+
+ call assert_fails('set cscopequickfix=x-', 'E474:')
+ call assert_fails('set cscopequickfix=s', 'E474:')
+ call assert_fails('set cscopequickfix=s7', 'E474:')
+ call assert_fails('set cscopequickfix=s-a', 'E474:')
+endfunc
+
+func Test_withoutCscopeConnection()
+ call assert_equal(cscope_connection(), 0)
+
+ call assert_fails('cscope find s main', 'E567:')
+ let a = execute('cscope show')
+ call assert_match('no cscope connections', a)
+endfunc
+
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/test_cursor_func.vim b/src/testdir/test_cursor_func.vim
new file mode 100644
index 0000000..a41cc7d
--- /dev/null
+++ b/src/testdir/test_cursor_func.vim
@@ -0,0 +1,68 @@
+" Tests for cursor().
+
+func Test_wrong_arguments()
+ call assert_fails('call cursor(1. 3)', 'E474:')
+endfunc
+
+func Test_move_cursor()
+ new
+ call setline(1, ['aaa', 'bbb', 'ccc', 'ddd'])
+
+ call cursor([1, 1, 0, 1])
+ call assert_equal([1, 1, 0, 1], getcurpos()[1:])
+ call cursor([4, 3, 0, 3])
+ call assert_equal([4, 3, 0, 3], getcurpos()[1:])
+
+ call cursor(2, 2)
+ call assert_equal([2, 2, 0, 2], getcurpos()[1:])
+ " line number zero keeps the line number
+ call cursor(0, 1)
+ call assert_equal([2, 1, 0, 1], getcurpos()[1:])
+ " col number zero keeps the column
+ call cursor(3, 0)
+ call assert_equal([3, 1, 0, 1], getcurpos()[1:])
+ " below last line goes to last line
+ call cursor(9, 1)
+ call assert_equal([4, 1, 0, 1], getcurpos()[1:])
+
+ quit!
+endfunc
+
+" Very short version of what matchparen does.
+function s:Highlight_Matching_Pair()
+ let save_cursor = getcurpos()
+ call setpos('.', save_cursor)
+endfunc
+
+func Test_curswant_with_autocommand()
+ new
+ call setline(1, ['func()', '{', '}', '----'])
+ autocmd! CursorMovedI * call s:Highlight_Matching_Pair()
+ call test_override("char_avail", 1)
+ exe "normal! 3Ga\<Down>X\<Esc>"
+ call test_override("char_avail", 0)
+ call assert_equal('-X---', getline(4))
+ autocmd! CursorMovedI *
+ quit!
+endfunc
+
+" Tests for behavior of curswant with cursorcolumn/line
+func Test_curswant_with_cursorcolumn()
+ new
+ call setline(1, ['01234567', ''])
+ exe "normal! ggf6j"
+ call assert_equal(6, winsaveview().curswant)
+ set cursorcolumn
+ call assert_equal(6, winsaveview().curswant)
+ quit!
+endfunc
+
+func Test_curswant_with_cursorline()
+ new
+ call setline(1, ['01234567', ''])
+ exe "normal! ggf6j"
+ call assert_equal(6, winsaveview().curswant)
+ set cursorline
+ call assert_equal(6, winsaveview().curswant)
+ quit!
+endfunc
diff --git a/src/testdir/test_curswant.vim b/src/testdir/test_curswant.vim
new file mode 100644
index 0000000..e54cd4b
--- /dev/null
+++ b/src/testdir/test_curswant.vim
@@ -0,0 +1,23 @@
+" Tests for curswant not changing when setting an option
+
+func Test_curswant()
+ new
+ call append(0, ['1234567890', '12345'])
+
+ normal! ggf8j
+ call assert_equal(7, winsaveview().curswant)
+ let &tabstop=&tabstop
+ call assert_equal(4, winsaveview().curswant)
+
+ normal! ggf8j
+ call assert_equal(7, winsaveview().curswant)
+ let &timeoutlen=&timeoutlen
+ call assert_equal(7, winsaveview().curswant)
+
+ normal! ggf8j
+ call assert_equal(7, winsaveview().curswant)
+ let &ttimeoutlen=&ttimeoutlen
+ call assert_equal(7, winsaveview().curswant)
+
+ enew!
+endfunc
diff --git a/src/testdir/test_delete.vim b/src/testdir/test_delete.vim
new file mode 100644
index 0000000..4686a0d
--- /dev/null
+++ b/src/testdir/test_delete.vim
@@ -0,0 +1,107 @@
+" Test for delete().
+
+func Test_file_delete()
+ split Xfile
+ call setline(1, ['a', 'b'])
+ wq
+ call assert_equal(['a', 'b'], readfile('Xfile'))
+ call assert_equal(0, delete('Xfile'))
+ call assert_fails('call readfile("Xfile")', 'E484:')
+ call assert_equal(-1, delete('Xfile'))
+ bwipe Xfile
+endfunc
+
+func Test_dir_delete()
+ call mkdir('Xdir1')
+ call assert_true(isdirectory('Xdir1'))
+ call assert_equal(0, delete('Xdir1', 'd'))
+ call assert_false(isdirectory('Xdir1'))
+ call assert_equal(-1, delete('Xdir1', 'd'))
+endfunc
+
+func Test_recursive_delete()
+ call mkdir('Xdir1')
+ call mkdir('Xdir1/subdir')
+ call mkdir('Xdir1/empty')
+ split Xdir1/Xfile
+ call setline(1, ['a', 'b'])
+ w
+ w Xdir1/subdir/Xfile
+ close
+ call assert_true(isdirectory('Xdir1'))
+ call assert_equal(['a', 'b'], readfile('Xdir1/Xfile'))
+ call assert_true(isdirectory('Xdir1/subdir'))
+ call assert_equal(['a', 'b'], readfile('Xdir1/subdir/Xfile'))
+ call assert_true(isdirectory('Xdir1/empty'))
+ call assert_equal(0, delete('Xdir1', 'rf'))
+ call assert_false(isdirectory('Xdir1'))
+ call assert_equal(-1, delete('Xdir1', 'd'))
+ bwipe Xdir1/Xfile
+ bwipe Xdir1/subdir/Xfile
+endfunc
+
+func Test_symlink_delete()
+ if !has('unix')
+ return
+ endif
+ split Xfile
+ call setline(1, ['a', 'b'])
+ wq
+ silent !ln -s Xfile Xlink
+ " Delete the link, not the file
+ call assert_equal(0, delete('Xlink'))
+ call assert_equal(-1, delete('Xlink'))
+ call assert_equal(0, delete('Xfile'))
+ bwipe Xfile
+endfunc
+
+func Test_symlink_dir_delete()
+ if !has('unix')
+ return
+ endif
+ call mkdir('Xdir1')
+ silent !ln -s Xdir1 Xlink
+ call assert_true(isdirectory('Xdir1'))
+ call assert_true(isdirectory('Xlink'))
+ " Delete the link, not the directory
+ call assert_equal(0, delete('Xlink'))
+ call assert_equal(-1, delete('Xlink'))
+ call assert_equal(0, delete('Xdir1', 'd'))
+endfunc
+
+func Test_symlink_recursive_delete()
+ if !has('unix')
+ return
+ endif
+ call mkdir('Xdir3')
+ call mkdir('Xdir3/subdir')
+ call mkdir('Xdir4')
+ split Xdir3/Xfile
+ call setline(1, ['a', 'b'])
+ w
+ w Xdir3/subdir/Xfile
+ w Xdir4/Xfile
+ close
+ silent !ln -s ../Xdir4 Xdir3/Xlink
+
+ call assert_true(isdirectory('Xdir3'))
+ call assert_equal(['a', 'b'], readfile('Xdir3/Xfile'))
+ call assert_true(isdirectory('Xdir3/subdir'))
+ call assert_equal(['a', 'b'], readfile('Xdir3/subdir/Xfile'))
+ call assert_true(isdirectory('Xdir4'))
+ call assert_true(isdirectory('Xdir3/Xlink'))
+ call assert_equal(['a', 'b'], readfile('Xdir4/Xfile'))
+
+ call assert_equal(0, delete('Xdir3', 'rf'))
+ call assert_false(isdirectory('Xdir3'))
+ call assert_equal(-1, delete('Xdir3', 'd'))
+ " symlink is deleted, not the directory it points to
+ call assert_true(isdirectory('Xdir4'))
+ call assert_equal(['a', 'b'], readfile('Xdir4/Xfile'))
+ call assert_equal(0, delete('Xdir4/Xfile'))
+ call assert_equal(0, delete('Xdir4', 'd'))
+
+ bwipe Xdir3/Xfile
+ bwipe Xdir3/subdir/Xfile
+ bwipe Xdir4/Xfile
+endfunc
diff --git a/src/testdir/test_diffmode.vim b/src/testdir/test_diffmode.vim
new file mode 100644
index 0000000..84fb451
--- /dev/null
+++ b/src/testdir/test_diffmode.vim
@@ -0,0 +1,915 @@
+" Tests for diff mode
+source shared.vim
+source screendump.vim
+
+func Test_diff_fold_sync()
+ enew!
+ let g:update_count = 0
+ au DiffUpdated * let g:update_count += 1
+
+ let l = range(50)
+ call setline(1, l)
+ diffthis
+ let winone = win_getid()
+ new
+ let l[25] = 'diff'
+ call setline(1, l)
+ diffthis
+ let wintwo = win_getid()
+ " line 15 is inside the closed fold
+ call assert_equal(19, foldclosedend(10))
+ call win_gotoid(winone)
+ call assert_equal(19, foldclosedend(10))
+ " open the fold
+ normal zv
+ call assert_equal(-1, foldclosedend(10))
+ " fold in other window must have opened too
+ call win_gotoid(wintwo)
+ call assert_equal(-1, foldclosedend(10))
+
+ " cursor position is in sync
+ normal 23G
+ call win_gotoid(winone)
+ call assert_equal(23, getcurpos()[1])
+
+ call assert_equal(1, g:update_count)
+ au! DiffUpdated
+
+ windo diffoff
+ close!
+ set nomodified
+endfunc
+
+func Test_vert_split()
+ set diffopt=filler
+ call Common_vert_split()
+ set diffopt&
+endfunc
+
+func Test_vert_split_internal()
+ set diffopt=internal,filler
+ call Common_vert_split()
+ set diffopt&
+endfunc
+
+func Common_vert_split()
+ " Disable the title to avoid xterm keeping the wrong one.
+ set notitle noicon
+ new
+ let l = ['1 aa', '2 bb', '3 cc', '4 dd', '5 ee']
+ call setline(1, l)
+ w! Xtest
+ normal dd
+ $
+ put
+ normal kkrXoxxx
+ w! Xtest2
+ file Nop
+ normal ggoyyyjjjozzzz
+ set foldmethod=marker foldcolumn=4
+ call assert_equal(0, &diff)
+ call assert_equal('marker', &foldmethod)
+ call assert_equal(4, &foldcolumn)
+ call assert_equal(0, &scrollbind)
+ call assert_equal(0, &cursorbind)
+ call assert_equal(1, &wrap)
+
+ vert diffsplit Xtest
+ vert diffsplit Xtest2
+ call assert_equal(1, &diff)
+ call assert_equal('diff', &foldmethod)
+ call assert_equal(2, &foldcolumn)
+ call assert_equal(1, &scrollbind)
+ call assert_equal(1, &cursorbind)
+ call assert_equal(0, &wrap)
+
+ let diff_fdm = &fdm
+ let diff_fdc = &fdc
+ " repeat entering diff mode here to see if this saves the wrong settings
+ diffthis
+ " jump to second window for a moment to have filler line appear at start of
+ " first window
+ wincmd w
+ normal gg
+ wincmd p
+ normal gg
+ call assert_equal(2, winline())
+ normal j
+ call assert_equal(4, winline())
+ normal j
+ call assert_equal(5, winline())
+ normal j
+ call assert_equal(6, winline())
+ normal j
+ call assert_equal(8, winline())
+ normal j
+ call assert_equal(9, winline())
+
+ wincmd w
+ normal gg
+ call assert_equal(1, winline())
+ normal j
+ call assert_equal(2, winline())
+ normal j
+ call assert_equal(4, winline())
+ normal j
+ call assert_equal(5, winline())
+ normal j
+ call assert_equal(8, winline())
+
+ wincmd w
+ normal gg
+ call assert_equal(2, winline())
+ normal j
+ call assert_equal(3, winline())
+ normal j
+ call assert_equal(4, winline())
+ normal j
+ call assert_equal(5, winline())
+ normal j
+ call assert_equal(6, winline())
+ normal j
+ call assert_equal(7, winline())
+ normal j
+ call assert_equal(8, winline())
+
+ " Test diffoff
+ diffoff!
+ 1wincmd 2
+ let &diff = 1
+ let &fdm = diff_fdm
+ let &fdc = diff_fdc
+ 4wincmd w
+ diffoff!
+ 1wincmd w
+ call assert_equal(0, &diff)
+ call assert_equal('marker', &foldmethod)
+ call assert_equal(4, &foldcolumn)
+ call assert_equal(0, &scrollbind)
+ call assert_equal(0, &cursorbind)
+ call assert_equal(1, &wrap)
+
+ wincmd w
+ call assert_equal(0, &diff)
+ call assert_equal('marker', &foldmethod)
+ call assert_equal(4, &foldcolumn)
+ call assert_equal(0, &scrollbind)
+ call assert_equal(0, &cursorbind)
+ call assert_equal(1, &wrap)
+
+ wincmd w
+ call assert_equal(0, &diff)
+ call assert_equal('marker', &foldmethod)
+ call assert_equal(4, &foldcolumn)
+ call assert_equal(0, &scrollbind)
+ call assert_equal(0, &cursorbind)
+ call assert_equal(1, &wrap)
+
+ call delete('Xtest')
+ call delete('Xtest2')
+ windo bw!
+endfunc
+
+func Test_filler_lines()
+ " Test that diffing shows correct filler lines
+ enew!
+ put =range(4,10)
+ 1d _
+ vnew
+ put =range(1,10)
+ 1d _
+ windo diffthis
+ wincmd h
+ call assert_equal(1, line('w0'))
+ unlet! diff_fdm diff_fdc
+ windo diffoff
+ bwipe!
+ enew!
+endfunc
+
+func Test_diffget_diffput()
+ enew!
+ let l = range(50)
+ call setline(1, l)
+ call assert_fails('diffget', 'E99:')
+ diffthis
+ call assert_fails('diffget', 'E100:')
+ new
+ let l[10] = 'one'
+ let l[20] = 'two'
+ let l[30] = 'three'
+ let l[40] = 'four'
+ call setline(1, l)
+ diffthis
+ call assert_equal('one', getline(11))
+ 11diffget
+ call assert_equal('10', getline(11))
+ 21diffput
+ wincmd w
+ call assert_equal('two', getline(21))
+ normal 31Gdo
+ call assert_equal('three', getline(31))
+ call assert_equal('40', getline(41))
+ normal 41Gdp
+ wincmd w
+ call assert_equal('40', getline(41))
+ new
+ diffthis
+ call assert_fails('diffget', 'E101:')
+
+ windo diffoff
+ %bwipe!
+endfunc
+
+" Test putting two changes from one buffer to another
+func Test_diffput_two()
+ new a
+ let win_a = win_getid()
+ call setline(1, range(1, 10))
+ diffthis
+ new b
+ let win_b = win_getid()
+ call setline(1, range(1, 10))
+ 8del
+ 5del
+ diffthis
+ call win_gotoid(win_a)
+ %diffput
+ call win_gotoid(win_b)
+ call assert_equal(map(range(1, 10), 'string(v:val)'), getline(1, '$'))
+ bwipe! a
+ bwipe! b
+endfunc
+
+func Test_dp_do_buffer()
+ e! one
+ let bn1=bufnr('%')
+ let l = range(60)
+ call setline(1, l)
+ diffthis
+
+ new two
+ let l[10] = 'one'
+ let l[20] = 'two'
+ let l[30] = 'three'
+ let l[40] = 'four'
+ let l[50] = 'five'
+ call setline(1, l)
+ diffthis
+
+ " dp and do with invalid buffer number.
+ 11
+ call assert_fails('norm 99999dp', 'E102:')
+ call assert_fails('norm 99999do', 'E102:')
+ call assert_fails('diffput non_existing_buffer', 'E94:')
+ call assert_fails('diffget non_existing_buffer', 'E94:')
+
+ " dp and do with valid buffer number.
+ call assert_equal('one', getline('.'))
+ exe 'norm ' . bn1 . 'do'
+ call assert_equal('10', getline('.'))
+ 21
+ call assert_equal('two', getline('.'))
+ diffget one
+ call assert_equal('20', getline('.'))
+
+ 31
+ exe 'norm ' . bn1 . 'dp'
+ 41
+ diffput one
+ wincmd w
+ 31
+ call assert_equal('three', getline('.'))
+ 41
+ call assert_equal('four', getline('.'))
+
+ " dp and do with buffer number which is not in diff mode.
+ new not_in_diff_mode
+ let bn3=bufnr('%')
+ wincmd w
+ 51
+ call assert_fails('exe "norm" . bn3 . "dp"', 'E103:')
+ call assert_fails('exe "norm" . bn3 . "do"', 'E103:')
+ call assert_fails('diffput not_in_diff_mode', 'E94:')
+ call assert_fails('diffget not_in_diff_mode', 'E94:')
+
+ windo diffoff
+ %bwipe!
+endfunc
+
+func Test_do_lastline()
+ e! one
+ call setline(1, ['1','2','3','4','5','6'])
+ diffthis
+
+ new two
+ call setline(1, ['2','4','5'])
+ diffthis
+
+ 1
+ norm dp]c
+ norm dp]c
+ wincmd w
+ call assert_equal(4, line('$'))
+ norm G
+ norm do
+ call assert_equal(3, line('$'))
+
+ windo diffoff
+ %bwipe!
+endfunc
+
+func Test_diffoff()
+ enew!
+ call setline(1, ['Two', 'Three'])
+ redraw
+ let normattr = screenattr(1, 1)
+ diffthis
+ botright vert new
+ call setline(1, ['One', '', 'Two', 'Three'])
+ diffthis
+ redraw
+ call assert_notequal(normattr, screenattr(1, 1))
+ diffoff!
+ redraw
+ call assert_equal(normattr, screenattr(1, 1))
+ bwipe!
+ bwipe!
+endfunc
+
+func Common_icase_test()
+ edit one
+ call setline(1, ['One', 'Two', 'Three', 'Four', 'Fi#ve'])
+ redraw
+ let normattr = screenattr(1, 1)
+ diffthis
+
+ botright vert new two
+ call setline(1, ['one', 'TWO', 'Three ', 'Four', 'fI=VE'])
+ diffthis
+
+ redraw
+ call assert_equal(normattr, screenattr(1, 1))
+ call assert_equal(normattr, screenattr(2, 1))
+ call assert_notequal(normattr, screenattr(3, 1))
+ call assert_equal(normattr, screenattr(4, 1))
+
+ let dtextattr = screenattr(5, 3)
+ call assert_notequal(dtextattr, screenattr(5, 1))
+ call assert_notequal(dtextattr, screenattr(5, 5))
+
+ diffoff!
+ %bwipe!
+endfunc
+
+func Test_diffopt_icase()
+ set diffopt=icase,foldcolumn:0
+ call Common_icase_test()
+ set diffopt&
+endfunc
+
+func Test_diffopt_icase_internal()
+ set diffopt=icase,foldcolumn:0,internal
+ call Common_icase_test()
+ set diffopt&
+endfunc
+
+func Common_iwhite_test()
+ edit one
+ " Difference in trailing spaces and amount of spaces should be ignored,
+ " but not other space differences.
+ call setline(1, ["One \t", 'Two', 'Three', 'one two', 'one two', 'Four'])
+ redraw
+ let normattr = screenattr(1, 1)
+ diffthis
+
+ botright vert new two
+ call setline(1, ["One\t ", "Two\t ", 'Three', 'one two', 'onetwo', ' Four'])
+ diffthis
+
+ redraw
+ call assert_equal(normattr, screenattr(1, 1))
+ call assert_equal(normattr, screenattr(2, 1))
+ call assert_equal(normattr, screenattr(3, 1))
+ call assert_equal(normattr, screenattr(4, 1))
+ call assert_notequal(normattr, screenattr(5, 1))
+ call assert_notequal(normattr, screenattr(6, 1))
+
+ diffoff!
+ %bwipe!
+endfunc
+
+func Test_diffopt_iwhite()
+ set diffopt=iwhite,foldcolumn:0
+ call Common_iwhite_test()
+ set diffopt&
+endfunc
+
+func Test_diffopt_iwhite_internal()
+ set diffopt=internal,iwhite,foldcolumn:0
+ call Common_iwhite_test()
+ set diffopt&
+endfunc
+
+func Test_diffopt_context()
+ enew!
+ call setline(1, ['1', '2', '3', '4', '5', '6', '7'])
+ diffthis
+ new
+ call setline(1, ['1', '2', '3', '4', '5x', '6', '7'])
+ diffthis
+
+ set diffopt=context:2
+ call assert_equal('+-- 2 lines: 1', foldtextresult(1))
+ set diffopt=internal,context:2
+ call assert_equal('+-- 2 lines: 1', foldtextresult(1))
+
+ set diffopt=context:1
+ call assert_equal('+-- 3 lines: 1', foldtextresult(1))
+ set diffopt=internal,context:1
+ call assert_equal('+-- 3 lines: 1', foldtextresult(1))
+
+ diffoff!
+ %bwipe!
+ set diffopt&
+endfunc
+
+func Test_diffopt_horizontal()
+ set diffopt=internal,horizontal
+ diffsplit
+
+ call assert_equal(&columns, winwidth(1))
+ call assert_equal(&columns, winwidth(2))
+ call assert_equal(&lines, winheight(1) + winheight(2) + 3)
+ call assert_inrange(0, 1, winheight(1) - winheight(2))
+
+ set diffopt&
+ diffoff!
+ %bwipe
+endfunc
+
+func Test_diffopt_vertical()
+ set diffopt=internal,vertical
+ diffsplit
+
+ call assert_equal(&lines - 2, winheight(1))
+ call assert_equal(&lines - 2, winheight(2))
+ call assert_equal(&columns, winwidth(1) + winwidth(2) + 1)
+ call assert_inrange(0, 1, winwidth(1) - winwidth(2))
+
+ set diffopt&
+ diffoff!
+ %bwipe
+endfunc
+
+func Test_diffopt_hiddenoff()
+ set diffopt=internal,filler,foldcolumn:0,hiddenoff
+ e! one
+ call setline(1, ['Two', 'Three'])
+ redraw
+ let normattr = screenattr(1, 1)
+ diffthis
+ botright vert new two
+ call setline(1, ['One', 'Four'])
+ diffthis
+ redraw
+ call assert_notequal(normattr, screenattr(1, 1))
+ set hidden
+ close
+ redraw
+ " should not diffing with hidden buffer two while 'hiddenoff' is enabled
+ call assert_equal(normattr, screenattr(1, 1))
+
+ bwipe!
+ bwipe!
+ set hidden& diffopt&
+endfunc
+
+func Test_diffoff_hidden()
+ set diffopt=internal,filler,foldcolumn:0
+ e! one
+ call setline(1, ['Two', 'Three'])
+ redraw
+ let normattr = screenattr(1, 1)
+ diffthis
+ botright vert new two
+ call setline(1, ['One', 'Four'])
+ diffthis
+ redraw
+ call assert_notequal(normattr, screenattr(1, 1))
+ set hidden
+ close
+ redraw
+ " diffing with hidden buffer two
+ call assert_notequal(normattr, screenattr(1, 1))
+ diffoff
+ redraw
+ call assert_equal(normattr, screenattr(1, 1))
+ diffthis
+ redraw
+ " still diffing with hidden buffer two
+ call assert_notequal(normattr, screenattr(1, 1))
+ diffoff!
+ redraw
+ call assert_equal(normattr, screenattr(1, 1))
+ diffthis
+ redraw
+ " no longer diffing with hidden buffer two
+ call assert_equal(normattr, screenattr(1, 1))
+
+ bwipe!
+ bwipe!
+ set hidden& diffopt&
+endfunc
+
+func Test_setting_cursor()
+ new Xtest1
+ put =range(1,90)
+ wq
+ new Xtest2
+ put =range(1,100)
+ wq
+
+ tabe Xtest2
+ $
+ diffsp Xtest1
+ tabclose
+
+ call delete('Xtest1')
+ call delete('Xtest2')
+endfunc
+
+func Test_diff_move_to()
+ new
+ call setline(1, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
+ diffthis
+ vnew
+ call setline(1, [1, '2x', 3, 4, 4, 5, '6x', 7, '8x', 9, '10x'])
+ diffthis
+ norm ]c
+ call assert_equal(2, line('.'))
+ norm 3]c
+ call assert_equal(9, line('.'))
+ norm 10]c
+ call assert_equal(11, line('.'))
+ norm [c
+ call assert_equal(9, line('.'))
+ norm 2[c
+ call assert_equal(5, line('.'))
+ norm 10[c
+ call assert_equal(2, line('.'))
+ %bwipe!
+endfunc
+
+func Test_diffexpr()
+ if !executable('diff')
+ return
+ endif
+
+ func DiffExpr()
+ " Prepent some text to check diff type detection
+ call writefile(['warning', ' message'], v:fname_out)
+ silent exe '!diff ' . v:fname_in . ' ' . v:fname_new . '>>' . v:fname_out
+ endfunc
+ set diffexpr=DiffExpr()
+ set diffopt=foldcolumn:0
+
+ enew!
+ call setline(1, ['one', 'two', 'three'])
+ redraw
+ let normattr = screenattr(1, 1)
+ diffthis
+
+ botright vert new
+ call setline(1, ['one', 'two', 'three.'])
+ diffthis
+
+ redraw
+ call assert_equal(normattr, screenattr(1, 1))
+ call assert_equal(normattr, screenattr(2, 1))
+ call assert_notequal(normattr, screenattr(3, 1))
+
+ diffoff!
+ %bwipe!
+ set diffexpr& diffopt&
+endfunc
+
+func Test_diffpatch()
+ " The patch program on MS-Windows may fail or hang.
+ if !executable('patch') || !has('unix')
+ return
+ endif
+ new
+ insert
+***************
+*** 1,3 ****
+ 1
+! 2
+ 3
+--- 1,4 ----
+ 1
+! 2x
+ 3
++ 4
+.
+ saveas! Xpatch
+ bwipe!
+ new
+ call assert_fails('diffpatch Xpatch', 'E816:')
+
+ for name in ['Xpatch', 'Xpatch$HOME', 'Xpa''tch']
+ call setline(1, ['1', '2', '3'])
+ if name != 'Xpatch'
+ call rename('Xpatch', name)
+ endif
+ exe 'diffpatch ' . escape(name, '$')
+ call assert_equal(['1', '2x', '3', '4'], getline(1, '$'))
+ if name != 'Xpatch'
+ call rename(name, 'Xpatch')
+ endif
+ bwipe!
+ endfor
+
+ call delete('Xpatch')
+ bwipe!
+endfunc
+
+func Test_diff_too_many_buffers()
+ for i in range(1, 8)
+ exe "new Xtest" . i
+ diffthis
+ endfor
+ new Xtest9
+ call assert_fails('diffthis', 'E96:')
+ %bwipe!
+endfunc
+
+func Test_diff_nomodifiable()
+ new
+ call setline(1, [1, 2, 3, 4])
+ setl nomodifiable
+ diffthis
+ vnew
+ call setline(1, ['1x', 2, 3, 3, 4])
+ diffthis
+ call assert_fails('norm dp', 'E793:')
+ setl nomodifiable
+ call assert_fails('norm do', 'E21:')
+ %bwipe!
+endfunc
+
+func Test_diff_hlID()
+ new
+ call setline(1, [1, 2, 3])
+ diffthis
+ vnew
+ call setline(1, ['1x', 2, 'x', 3])
+ diffthis
+ redraw
+
+ call assert_equal(synIDattr(diff_hlID(-1, 1), "name"), "")
+
+ call assert_equal(synIDattr(diff_hlID(1, 1), "name"), "DiffChange")
+ call assert_equal(synIDattr(diff_hlID(1, 2), "name"), "DiffText")
+ call assert_equal(synIDattr(diff_hlID(2, 1), "name"), "")
+ call assert_equal(synIDattr(diff_hlID(3, 1), "name"), "DiffAdd")
+ call assert_equal(synIDattr(diff_hlID(4, 1), "name"), "")
+
+ wincmd w
+ call assert_equal(synIDattr(diff_hlID(1, 1), "name"), "DiffChange")
+ call assert_equal(synIDattr(diff_hlID(2, 1), "name"), "")
+ call assert_equal(synIDattr(diff_hlID(3, 1), "name"), "")
+
+ %bwipe!
+endfunc
+
+func Test_diff_filler()
+ new
+ call setline(1, [1, 2, 3, 'x', 4])
+ diffthis
+ vnew
+ call setline(1, [1, 2, 'y', 'y', 3, 4])
+ diffthis
+ redraw
+
+ call assert_equal([0, 0, 0, 0, 0, 0, 0, 1, 0], map(range(-1, 7), 'diff_filler(v:val)'))
+ wincmd w
+ call assert_equal([0, 0, 0, 0, 2, 0, 0, 0], map(range(-1, 6), 'diff_filler(v:val)'))
+
+ %bwipe!
+endfunc
+
+func Test_diff_lastline()
+ enew!
+ only!
+ call setline(1, ['This is a ', 'line with five ', 'rows'])
+ diffthis
+ botright vert new
+ call setline(1, ['This is', 'a line with ', 'four rows'])
+ diffthis
+ 1
+ call feedkeys("Je a\<CR>", 'tx')
+ call feedkeys("Je a\<CR>", 'tx')
+ let w1lines = winline()
+ wincmd w
+ $
+ let w2lines = winline()
+ call assert_equal(w2lines, w1lines)
+ bwipe!
+ bwipe!
+endfunc
+
+func WriteDiffFiles(buf, list1, list2)
+ call writefile(a:list1, 'Xfile1')
+ call writefile(a:list2, 'Xfile2')
+ if a:buf
+ call term_sendkeys(a:buf, ":checktime\<CR>")
+ endif
+endfunc
+
+" Verify a screendump with both the internal and external diff.
+func VerifyBoth(buf, dumpfile, extra)
+ " trailing : for leaving the cursor on the command line
+ for cmd in [":set diffopt=filler" . a:extra . "\<CR>:", ":set diffopt+=internal\<CR>:"]
+ call term_sendkeys(a:buf, cmd)
+ if VerifyScreenDump(a:buf, a:dumpfile, {}, cmd =~ 'internal' ? 'internal' : 'external')
+ break " don't let the next iteration overwrite the "failed" file.
+ endif
+ endfor
+endfunc
+
+" Verify a screendump with the internal diff only.
+func VerifyInternal(buf, dumpfile, extra)
+ call term_sendkeys(a:buf, ":diffupdate!\<CR>")
+ " trailing : for leaving the cursor on the command line
+ call term_sendkeys(a:buf, ":set diffopt=internal,filler" . a:extra . "\<CR>:")
+ call VerifyScreenDump(a:buf, a:dumpfile, {})
+endfunc
+
+func Test_diff_screen()
+ if !CanRunVimInTerminal() || !has('menu')
+ return
+ endif
+ " clean up already existing swap files, just in case
+ call delete('.Xfile1.swp')
+ call delete('.Xfile2.swp')
+
+ " Test 1: Add a line in beginning of file 2
+ call WriteDiffFiles(0, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
+ let buf = RunVimInTerminal('-d Xfile1 Xfile2', {})
+ " Set autoread mode, ,so that Vim won't complain once we re-write the test
+ " files
+ call term_sendkeys(buf, ":set autoread\<CR>\<c-w>w:set autoread\<CR>\<c-w>w")
+
+ call VerifyBoth(buf, 'Test_diff_01', '')
+
+ " Test 2: Add a line in beginning of file 1
+ call WriteDiffFiles(buf, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
+ call VerifyBoth(buf, 'Test_diff_02', '')
+
+ " Test 3: Add a line at the end of file 2
+ call WriteDiffFiles(buf, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
+ call VerifyBoth(buf, 'Test_diff_03', '')
+
+ " Test 4: Add a line at the end of file 1
+ call WriteDiffFiles(buf, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
+ call VerifyBoth(buf, 'Test_diff_04', '')
+
+ " Test 5: Add a line in the middle of file 2, remove on at the end of file 1
+ call WriteDiffFiles(buf, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], [1, 2, 3, 4, 4, 5, 6, 7, 8, 9, 10])
+ call VerifyBoth(buf, 'Test_diff_05', '')
+
+ " Test 6: Add a line in the middle of file 1, remove on at the end of file 2
+ call WriteDiffFiles(buf, [1, 2, 3, 4, 4, 5, 6, 7, 8, 9, 10], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
+ call VerifyBoth(buf, 'Test_diff_06', '')
+
+ " Test 7 - 9: Test normal/patience/histogram diff algorithm
+ call WriteDiffFiles(buf, ['#include <stdio.h>', '', '// Frobs foo heartily', 'int frobnitz(int foo)', '{',
+ \ ' int i;', ' for(i = 0; i < 10; i++)', ' {', ' printf("Your answer is: ");',
+ \ ' printf("%d\n", foo);', ' }', '}', '', 'int fact(int n)', '{', ' if(n > 1)', ' {',
+ \ ' return fact(n-1) * n;', ' }', ' return 1;', '}', '', 'int main(int argc, char **argv)',
+ \ '{', ' frobnitz(fact(10));', '}'],
+ \ ['#include <stdio.h>', '', 'int fib(int n)', '{', ' if(n > 2)', ' {',
+ \ ' return fib(n-1) + fib(n-2);', ' }', ' return 1;', '}', '', '// Frobs foo heartily',
+ \ 'int frobnitz(int foo)', '{', ' int i;', ' for(i = 0; i < 10; i++)', ' {',
+ \ ' printf("%d\n", foo);', ' }', '}', '',
+ \ 'int main(int argc, char **argv)', '{', ' frobnitz(fib(10));', '}'])
+ call term_sendkeys(buf, ":diffupdate!\<cr>")
+ call term_sendkeys(buf, ":set diffopt+=internal\<cr>")
+ call VerifyScreenDump(buf, 'Test_diff_07', {})
+
+ call term_sendkeys(buf, ":set diffopt+=algorithm:patience\<cr>")
+ call VerifyScreenDump(buf, 'Test_diff_08', {})
+
+ call term_sendkeys(buf, ":set diffopt+=algorithm:histogram\<cr>")
+ call VerifyScreenDump(buf, 'Test_diff_09', {})
+
+ " Test 10-11: normal/indent-heuristic
+ call term_sendkeys(buf, ":set diffopt&vim\<cr>")
+ call WriteDiffFiles(buf, ['', ' def finalize(values)', '', ' values.each do |v|', ' v.finalize', ' end'],
+ \ ['', ' def finalize(values)', '', ' values.each do |v|', ' v.prepare', ' end', '',
+ \ ' values.each do |v|', ' v.finalize', ' end'])
+ call term_sendkeys(buf, ":diffupdate!\<cr>")
+ call term_sendkeys(buf, ":set diffopt+=internal\<cr>")
+ call VerifyScreenDump(buf, 'Test_diff_10', {})
+
+ " Leave trailing : at commandline!
+ call term_sendkeys(buf, ":set diffopt+=indent-heuristic\<cr>:\<cr>")
+ call VerifyScreenDump(buf, 'Test_diff_11', {}, 'one')
+ " shouldn't matter, if indent-algorithm comes before or after the algorithm
+ call term_sendkeys(buf, ":set diffopt&\<cr>")
+ call term_sendkeys(buf, ":set diffopt+=indent-heuristic,algorithm:patience\<cr>:\<cr>")
+ call VerifyScreenDump(buf, 'Test_diff_11', {}, 'two')
+ call term_sendkeys(buf, ":set diffopt&\<cr>")
+ call term_sendkeys(buf, ":set diffopt+=algorithm:patience,indent-heuristic\<cr>:\<cr>")
+ call VerifyScreenDump(buf, 'Test_diff_11', {}, 'three')
+
+ " Test 12: diff the same file
+ call WriteDiffFiles(buf, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
+ call VerifyBoth(buf, 'Test_diff_12', '')
+
+ " Test 13: diff an empty file
+ call WriteDiffFiles(buf, [], [])
+ call VerifyBoth(buf, 'Test_diff_13', '')
+
+ " Test 14: test diffopt+=icase
+ call WriteDiffFiles(buf, ['a', 'b', 'cd'], ['A', 'b', 'cDe'])
+ call VerifyBoth(buf, 'Test_diff_14', " diffopt+=filler diffopt+=icase")
+
+ " Test 15-16: test diffopt+=iwhite
+ call WriteDiffFiles(buf, ['int main()', '{', ' printf("Hello, World!");', ' return 0;', '}'],
+ \ ['int main()', '{', ' if (0)', ' {', ' printf("Hello, World!");', ' return 0;', ' }', '}'])
+ call term_sendkeys(buf, ":diffupdate!\<cr>")
+ call term_sendkeys(buf, ":set diffopt&vim diffopt+=filler diffopt+=iwhite\<cr>")
+ call VerifyScreenDump(buf, 'Test_diff_15', {})
+ call term_sendkeys(buf, ":set diffopt+=internal\<cr>")
+ call VerifyScreenDump(buf, 'Test_diff_16', {})
+
+ " Test 17: test diffopt+=iblank
+ call WriteDiffFiles(buf, ['a', ' ', 'cd', 'ef', 'xxx'], ['a', 'cd', '', 'ef', 'yyy'])
+ call VerifyInternal(buf, 'Test_diff_17', " diffopt+=iblank")
+
+ " Test 18: test diffopt+=iblank,iwhite / iwhiteall / iwhiteeol
+ call VerifyInternal(buf, 'Test_diff_18', " diffopt+=iblank,iwhite")
+ call VerifyInternal(buf, 'Test_diff_18', " diffopt+=iblank,iwhiteall")
+ call VerifyInternal(buf, 'Test_diff_18', " diffopt+=iblank,iwhiteeol")
+
+ " Test 19: test diffopt+=iwhiteeol
+ call WriteDiffFiles(buf, ['a ', 'x', 'cd', 'ef', 'xx xx', 'foo', 'bar'], ['a', 'x', 'c d', ' ef', 'xx xx', 'foo', '', 'bar'])
+ call VerifyInternal(buf, 'Test_diff_19', " diffopt+=iwhiteeol")
+
+ " Test 19: test diffopt+=iwhiteall
+ call VerifyInternal(buf, 'Test_diff_20', " diffopt+=iwhiteall")
+
+ " clean up
+ call StopVimInTerminal(buf)
+ call delete('Xfile1')
+ call delete('Xfile2')
+endfunc
+
+func Test_diff_with_cursorline()
+ if !CanRunVimInTerminal()
+ return
+ endif
+
+ call writefile([
+ \ 'hi CursorLine ctermbg=red ctermfg=white',
+ \ 'set cursorline',
+ \ 'call setline(1, ["foo","foo","foo","bar"])',
+ \ 'vnew',
+ \ 'call setline(1, ["bee","foo","foo","baz"])',
+ \ 'windo diffthis',
+ \ '2wincmd w',
+ \ ], 'Xtest_diff_cursorline')
+ let buf = RunVimInTerminal('-S Xtest_diff_cursorline', {})
+
+ call VerifyScreenDump(buf, 'Test_diff_with_cursorline_01', {})
+ call term_sendkeys(buf, "j")
+ call VerifyScreenDump(buf, 'Test_diff_with_cursorline_02', {})
+ call term_sendkeys(buf, "j")
+ call VerifyScreenDump(buf, 'Test_diff_with_cursorline_03', {})
+
+ " clean up
+ call StopVimInTerminal(buf)
+ call delete('Xtest_diff_cursorline')
+endfunc
+
+func Test_diff_of_diff()
+ if !CanRunVimInTerminal()
+ return
+ endif
+
+ call writefile([
+ \ 'call setline(1, ["aa","bb","cc","@@ -3,2 +5,7 @@","dd","ee","ff"])',
+ \ 'vnew',
+ \ 'call setline(1, ["aa","bb","cc"])',
+ \ 'windo diffthis',
+ \ ], 'Xtest_diff_diff')
+ let buf = RunVimInTerminal('-S Xtest_diff_diff', {})
+
+ call VerifyScreenDump(buf, 'Test_diff_of_diff_01', {})
+
+ " clean up
+ call StopVimInTerminal(buf)
+ call delete('Xtest_diff_diff')
+endfunc
diff --git a/src/testdir/test_digraph.vim b/src/testdir/test_digraph.vim
new file mode 100644
index 0000000..8d56a1a
--- /dev/null
+++ b/src/testdir/test_digraph.vim
@@ -0,0 +1,477 @@
+" Tests for digraphs
+
+if !has("digraphs")
+ finish
+endif
+
+func Put_Dig(chars)
+ exe "norm! o\<c-k>".a:chars
+endfu
+
+func Put_Dig_BS(char1, char2)
+ exe "norm! o".a:char1."\<bs>".a:char2
+endfu
+
+func Test_digraphs()
+ new
+ call Put_Dig("00")
+ call assert_equal("∞", getline('.'))
+ " not a digraph
+ call Put_Dig("el")
+ call assert_equal("l", getline('.'))
+ call Put_Dig("ht")
+ call assert_equal("þ", getline('.'))
+ " digraph "ab" is the same as "ba"
+ call Put_Dig("ab")
+ call Put_Dig("ba")
+ call assert_equal(["ã°","ã°"], getline(line('.')-1,line('.')))
+ " Euro sign
+ call Put_Dig("e=")
+ call Put_Dig("=e")
+ call Put_Dig("Eu")
+ call Put_Dig("uE")
+ call assert_equal(['е']+repeat(["€"],3), getline(line('.')-3,line('.')))
+ " Rouble sign
+ call Put_Dig("R=")
+ call Put_Dig("=R")
+ call Put_Dig("=P")
+ call Put_Dig("P=")
+ call assert_equal(['Р']+repeat(["₽"],2)+['П'], getline(line('.')-3,line('.')))
+ " Not a digraph
+ call Put_Dig("a\<bs>")
+ call Put_Dig("\<bs>a")
+ call assert_equal(["<BS>", "<BS>a"], getline(line('.')-1,line('.')))
+ " Grave
+ call Put_Dig("a!")
+ call Put_Dig("!e")
+ call Put_Dig("b!") " not defined
+ call assert_equal(["à", "è", "!"], getline(line('.')-2,line('.')))
+ " Acute accent
+ call Put_Dig("a'")
+ call Put_Dig("'e")
+ call Put_Dig("b'") " not defined
+ call assert_equal(["á", "é", "'"], getline(line('.')-2,line('.')))
+ " Cicumflex
+ call Put_Dig("a>")
+ call Put_Dig(">e")
+ call Put_Dig("b>") " not defined
+ call assert_equal(['â', 'ê', '>'], getline(line('.')-2,line('.')))
+ " Tilde
+ call Put_Dig("o~")
+ call Put_Dig("~u") " not defined
+ call Put_Dig("z~") " not defined
+ call assert_equal(['õ', 'u', '~'], getline(line('.')-2,line('.')))
+ " Tilde
+ call Put_Dig("o?")
+ call Put_Dig("?u")
+ call Put_Dig("z?") " not defined
+ call assert_equal(['õ', 'ũ', '?'], getline(line('.')-2,line('.')))
+ " Macron
+ call Put_Dig("o-")
+ call Put_Dig("-u")
+ call Put_Dig("z-") " not defined
+ call assert_equal(['Å', 'Å«', '-'], getline(line('.')-2,line('.')))
+ " Breve
+ call Put_Dig("o(")
+ call Put_Dig("(u")
+ call Put_Dig("z(") " not defined
+ call assert_equal(['Å', 'Å­', '('], getline(line('.')-2,line('.')))
+ " Dot above
+ call Put_Dig("b.")
+ call Put_Dig(".e")
+ call Put_Dig("a.") " not defined
+ call assert_equal(['ḃ', 'ė', '.'], getline(line('.')-2,line('.')))
+ " Diaresis
+ call Put_Dig("a:")
+ call Put_Dig(":u")
+ call Put_Dig("b:") " not defined
+ call assert_equal(['ä', 'ü', ':'], getline(line('.')-2,line('.')))
+ " Cedilla
+ call Put_Dig("',")
+ call Put_Dig(",C")
+ call Put_Dig("b,") " not defined
+ call assert_equal(['¸', 'Ç', ','], getline(line('.')-2,line('.')))
+ " Underline
+ call Put_Dig("B_")
+ call Put_Dig("_t")
+ call Put_Dig("a_") " not defined
+ call assert_equal(['Ḇ', 'ṯ', '_'], getline(line('.')-2,line('.')))
+ " Stroke
+ call Put_Dig("j/")
+ call Put_Dig("/l")
+ call Put_Dig("b/") " not defined
+ call assert_equal(['/', 'Å‚', '/'], getline(line('.')-2,line('.')))
+ " Double acute
+ call Put_Dig('O"')
+ call Put_Dig('"y')
+ call Put_Dig('b"') " not defined
+ call assert_equal(['Å', 'ÿ', '"'], getline(line('.')-2,line('.')))
+ " Ogonek
+ call Put_Dig('u;')
+ call Put_Dig(';E')
+ call Put_Dig('b;') " not defined
+ call assert_equal(['ų', 'Ę', ';'], getline(line('.')-2,line('.')))
+ " Caron
+ call Put_Dig('u<')
+ call Put_Dig('<E')
+ call Put_Dig('b<') " not defined
+ call assert_equal(['Ç”', 'Äš', '<'], getline(line('.')-2,line('.')))
+ " Ring above
+ call Put_Dig('u0')
+ call Put_Dig('0E') " not defined
+ call Put_Dig('b0') " not defined
+ call assert_equal(['ů', 'E', '0'], getline(line('.')-2,line('.')))
+ " Hook
+ call Put_Dig('u2')
+ call Put_Dig('2E')
+ call Put_Dig('b2') " not defined
+ call assert_equal(['ủ', 'Ẻ', '2'], getline(line('.')-2,line('.')))
+ " Horn
+ call Put_Dig('u9')
+ call Put_Dig('9E') " not defined
+ call Put_Dig('b9') " not defined
+ call assert_equal(['Æ°', 'E', '9'], getline(line('.')-2,line('.')))
+ " Cyrillic
+ call Put_Dig('u=')
+ call Put_Dig('=b')
+ call Put_Dig('=_')
+ call assert_equal(['у', 'б', '〓'], getline(line('.')-2,line('.')))
+ " Greek
+ call Put_Dig('u*')
+ call Put_Dig('*b')
+ call Put_Dig('*_')
+ call assert_equal(['υ', 'β', '々'], getline(line('.')-2,line('.')))
+ " Greek/Cyrillic special
+ call Put_Dig('u%')
+ call Put_Dig('%b') " not defined
+ call Put_Dig('%_') " not defined
+ call assert_equal(['Ï', 'b', '_'], getline(line('.')-2,line('.')))
+ " Arabic
+ call Put_Dig('u+')
+ call Put_Dig('+b')
+ call Put_Dig('+_') " japanese industrial symbol
+ call assert_equal(['+', 'ب', '〄'], getline(line('.')-2,line('.')))
+ " Hebrew
+ call Put_Dig('Q+')
+ call Put_Dig('+B')
+ call Put_Dig('+X')
+ call assert_equal(['ק', 'ב', 'ח'], getline(line('.')-2,line('.')))
+ " Latin
+ call Put_Dig('a3')
+ call Put_Dig('A3')
+ call Put_Dig('3X')
+ call assert_equal(['Ç£', 'Ç¢', 'X'], getline(line('.')-2,line('.')))
+ " Bopomofo
+ call Put_Dig('a4')
+ call Put_Dig('A4')
+ call Put_Dig('4X')
+ call assert_equal(['ã„š', '4', 'X'], getline(line('.')-2,line('.')))
+ " Hiragana
+ call Put_Dig('a5')
+ call Put_Dig('A5')
+ call Put_Dig('5X')
+ call assert_equal(['ã‚', 'ã', 'X'], getline(line('.')-2,line('.')))
+ " Katakana
+ call Put_Dig('a6')
+ call Put_Dig('A6')
+ call Put_Dig('6X')
+ call assert_equal(['ã‚¡', 'ã‚¢', 'X'], getline(line('.')-2,line('.')))
+ " Superscripts
+ call Put_Dig('1S')
+ call Put_Dig('2S')
+ call Put_Dig('3S')
+ call assert_equal(['¹', '²', '³'], getline(line('.')-2,line('.')))
+ " Subscripts
+ call Put_Dig('1s')
+ call Put_Dig('2s')
+ call Put_Dig('3s')
+ call assert_equal(['â‚', 'â‚‚', '₃'], getline(line('.')-2,line('.')))
+ " Eszet (only lowercase)
+ call Put_Dig("ss")
+ call Put_Dig("SS") " start of string
+ call assert_equal(["ß", "˜"], getline(line('.')-1,line('.')))
+ " High bit set
+ call Put_Dig("a ")
+ call Put_Dig(" A")
+ call assert_equal(['á', 'Ã'], getline(line('.')-1,line('.')))
+ " Escape is not part of a digraph
+ call Put_Dig("a\<esc>")
+ call Put_Dig("\<esc>A")
+ call assert_equal(['', 'A'], getline(line('.')-1,line('.')))
+ " define some custom digraphs
+ " old: 00 ∞
+ " old: el l
+ digraph 00 9216
+ digraph el 0252
+ call Put_Dig("00")
+ call Put_Dig("el")
+ " Reset digraphs
+ digraph 00 8734
+ digraph el 108
+ call Put_Dig("00")
+ call Put_Dig("el")
+ call assert_equal(['â€', 'ü', '∞', 'l'], getline(line('.')-3,line('.')))
+ bw!
+endfunc
+
+func Test_digraphs_option()
+ " reset whichwrap option, so that testing <esc><bs>A works,
+ " without moving up a line
+ set digraph ww=
+ new
+ call Put_Dig_BS("0","0")
+ call assert_equal("∞", getline('.'))
+ " not a digraph
+ call Put_Dig_BS("e","l")
+ call assert_equal("l", getline('.'))
+ call Put_Dig_BS("h","t")
+ call assert_equal("þ", getline('.'))
+ " digraph "ab" is the same as "ba"
+ call Put_Dig_BS("a","b")
+ call Put_Dig_BS("b","a")
+ call assert_equal(["ã°","ã°"], getline(line('.')-1,line('.')))
+ " Euro sign
+ call Put_Dig_BS("e","=")
+ call Put_Dig_BS("=","e")
+ call Put_Dig_BS("E","u")
+ call Put_Dig_BS("u","E")
+ call assert_equal(['е']+repeat(["€"],3), getline(line('.')-3,line('.')))
+ " Rouble sign
+ call Put_Dig_BS("R","=")
+ call Put_Dig_BS("=","R")
+ call Put_Dig_BS("=","P")
+ call Put_Dig_BS("P","=")
+ call assert_equal(['Р']+repeat(["₽"],2)+['П'], getline(line('.')-3,line('.')))
+ " Not a digraph: this is different from <c-k>!
+ call Put_Dig_BS("a","\<bs>")
+ call Put_Dig_BS("\<bs>","a")
+ call assert_equal(['','a'], getline(line('.')-1,line('.')))
+ " Grave
+ call Put_Dig_BS("a","!")
+ call Put_Dig_BS("!","e")
+ call Put_Dig_BS("b","!") " not defined
+ call assert_equal(["à", "è", "!"], getline(line('.')-2,line('.')))
+ " Acute accent
+ call Put_Dig_BS("a","'")
+ call Put_Dig_BS("'","e")
+ call Put_Dig_BS("b","'") " not defined
+ call assert_equal(["á", "é", "'"], getline(line('.')-2,line('.')))
+ " Cicumflex
+ call Put_Dig_BS("a",">")
+ call Put_Dig_BS(">","e")
+ call Put_Dig_BS("b",">") " not defined
+ call assert_equal(['â', 'ê', '>'], getline(line('.')-2,line('.')))
+ " Tilde
+ call Put_Dig_BS("o","~")
+ call Put_Dig_BS("~","u") " not defined
+ call Put_Dig_BS("z","~") " not defined
+ call assert_equal(['õ', 'u', '~'], getline(line('.')-2,line('.')))
+ " Tilde
+ call Put_Dig_BS("o","?")
+ call Put_Dig_BS("?","u")
+ call Put_Dig_BS("z","?") " not defined
+ call assert_equal(['õ', 'ũ', '?'], getline(line('.')-2,line('.')))
+ " Macron
+ call Put_Dig_BS("o","-")
+ call Put_Dig_BS("-","u")
+ call Put_Dig_BS("z","-") " not defined
+ call assert_equal(['Å', 'Å«', '-'], getline(line('.')-2,line('.')))
+ " Breve
+ call Put_Dig_BS("o","(")
+ call Put_Dig_BS("(","u")
+ call Put_Dig_BS("z","(") " not defined
+ call assert_equal(['Å', 'Å­', '('], getline(line('.')-2,line('.')))
+ " Dot above
+ call Put_Dig_BS("b",".")
+ call Put_Dig_BS(".","e")
+ call Put_Dig_BS("a",".") " not defined
+ call assert_equal(['ḃ', 'ė', '.'], getline(line('.')-2,line('.')))
+ " Diaresis
+ call Put_Dig_BS("a",":")
+ call Put_Dig_BS(":","u")
+ call Put_Dig_BS("b",":") " not defined
+ call assert_equal(['ä', 'ü', ':'], getline(line('.')-2,line('.')))
+ " Cedilla
+ call Put_Dig_BS("'",",")
+ call Put_Dig_BS(",","C")
+ call Put_Dig_BS("b",",") " not defined
+ call assert_equal(['¸', 'Ç', ','], getline(line('.')-2,line('.')))
+ " Underline
+ call Put_Dig_BS("B","_")
+ call Put_Dig_BS("_","t")
+ call Put_Dig_BS("a","_") " not defined
+ call assert_equal(['Ḇ', 'ṯ', '_'], getline(line('.')-2,line('.')))
+ " Stroke
+ call Put_Dig_BS("j","/")
+ call Put_Dig_BS("/","l")
+ call Put_Dig_BS("b","/") " not defined
+ call assert_equal(['/', 'Å‚', '/'], getline(line('.')-2,line('.')))
+ " Double acute
+ call Put_Dig_BS('O','"')
+ call Put_Dig_BS('"','y')
+ call Put_Dig_BS('b','"') " not defined
+ call assert_equal(['Å', 'ÿ', '"'], getline(line('.')-2,line('.')))
+ " Ogonek
+ call Put_Dig_BS('u',';')
+ call Put_Dig_BS(';','E')
+ call Put_Dig_BS('b',';') " not defined
+ call assert_equal(['ų', 'Ę', ';'], getline(line('.')-2,line('.')))
+ " Caron
+ call Put_Dig_BS('u','<')
+ call Put_Dig_BS('<','E')
+ call Put_Dig_BS('b','<') " not defined
+ call assert_equal(['Ç”', 'Äš', '<'], getline(line('.')-2,line('.')))
+ " Ring above
+ call Put_Dig_BS('u','0')
+ call Put_Dig_BS('0','E') " not defined
+ call Put_Dig_BS('b','0') " not defined
+ call assert_equal(['ů', 'E', '0'], getline(line('.')-2,line('.')))
+ " Hook
+ call Put_Dig_BS('u','2')
+ call Put_Dig_BS('2','E')
+ call Put_Dig_BS('b','2') " not defined
+ call assert_equal(['ủ', 'Ẻ', '2'], getline(line('.')-2,line('.')))
+ " Horn
+ call Put_Dig_BS('u','9')
+ call Put_Dig_BS('9','E') " not defined
+ call Put_Dig_BS('b','9') " not defined
+ call assert_equal(['Æ°', 'E', '9'], getline(line('.')-2,line('.')))
+ " Cyrillic
+ call Put_Dig_BS('u','=')
+ call Put_Dig_BS('=','b')
+ call Put_Dig_BS('=','_')
+ call assert_equal(['у', 'б', '〓'], getline(line('.')-2,line('.')))
+ " Greek
+ call Put_Dig_BS('u','*')
+ call Put_Dig_BS('*','b')
+ call Put_Dig_BS('*','_')
+ call assert_equal(['υ', 'β', '々'], getline(line('.')-2,line('.')))
+ " Greek/Cyrillic special
+ call Put_Dig_BS('u','%')
+ call Put_Dig_BS('%','b') " not defined
+ call Put_Dig_BS('%','_') " not defined
+ call assert_equal(['Ï', 'b', '_'], getline(line('.')-2,line('.')))
+ " Arabic
+ call Put_Dig_BS('u','+')
+ call Put_Dig_BS('+','b')
+ call Put_Dig_BS('+','_') " japanese industrial symbol
+ call assert_equal(['+', 'ب', '〄'], getline(line('.')-2,line('.')))
+ " Hebrew
+ call Put_Dig_BS('Q','+')
+ call Put_Dig_BS('+','B')
+ call Put_Dig_BS('+','X')
+ call assert_equal(['ק', 'ב', 'ח'], getline(line('.')-2,line('.')))
+ " Latin
+ call Put_Dig_BS('a','3')
+ call Put_Dig_BS('A','3')
+ call Put_Dig_BS('3','X')
+ call assert_equal(['Ç£', 'Ç¢', 'X'], getline(line('.')-2,line('.')))
+ " Bopomofo
+ call Put_Dig_BS('a','4')
+ call Put_Dig_BS('A','4')
+ call Put_Dig_BS('4','X')
+ call assert_equal(['ã„š', '4', 'X'], getline(line('.')-2,line('.')))
+ " Hiragana
+ call Put_Dig_BS('a','5')
+ call Put_Dig_BS('A','5')
+ call Put_Dig_BS('5','X')
+ call assert_equal(['ã‚', 'ã', 'X'], getline(line('.')-2,line('.')))
+ " Katakana
+ call Put_Dig_BS('a','6')
+ call Put_Dig_BS('A','6')
+ call Put_Dig_BS('6','X')
+ call assert_equal(['ã‚¡', 'ã‚¢', 'X'], getline(line('.')-2,line('.')))
+ " Superscripts
+ call Put_Dig_BS('1','S')
+ call Put_Dig_BS('2','S')
+ call Put_Dig_BS('3','S')
+ call assert_equal(['¹', '²', '³'], getline(line('.')-2,line('.')))
+ " Subscripts
+ call Put_Dig_BS('1','s')
+ call Put_Dig_BS('2','s')
+ call Put_Dig_BS('3','s')
+ call assert_equal(['â‚', 'â‚‚', '₃'], getline(line('.')-2,line('.')))
+ " Eszet (only lowercase)
+ call Put_Dig_BS("s","s")
+ call Put_Dig_BS("S","S") " start of string
+ call assert_equal(["ß", "˜"], getline(line('.')-1,line('.')))
+ " High bit set (different from <c-k>)
+ call Put_Dig_BS("a"," ")
+ call Put_Dig_BS(" ","A")
+ call assert_equal([' ', 'A'], getline(line('.')-1,line('.')))
+ " Escape is not part of a digraph (different from <c-k>)
+ call Put_Dig_BS("a","\<esc>")
+ call Put_Dig_BS("\<esc>","A")
+ call assert_equal(['', ''], getline(line('.')-1,line('.')))
+ " define some custom digraphs
+ " old: 00 ∞
+ " old: el l
+ digraph 00 9216
+ digraph el 0252
+ call Put_Dig_BS("0","0")
+ call Put_Dig_BS("e","l")
+ " Reset digraphs
+ digraph 00 8734
+ digraph el 108
+ call Put_Dig_BS("0","0")
+ call Put_Dig_BS("e","l")
+ call assert_equal(['â€', 'ü', '∞', 'l'], getline(line('.')-3,line('.')))
+ set nodigraph ww&vim
+ bw!
+endfunc
+
+func Test_digraphs_output()
+ new
+ let out = execute(':digraph')
+ call assert_equal('Eu € 8364', matchstr(out, '\C\<Eu\D*8364\>'))
+ call assert_equal('=e € 8364', matchstr(out, '\C=e\D*8364\>'))
+ call assert_equal('=R ₽ 8381', matchstr(out, '\C=R\D*8381\>'))
+ call assert_equal('=P ₽ 8381', matchstr(out, '\C=P\D*8381\>'))
+ call assert_equal('o: ö 246', matchstr(out, '\C\<o:\D*246\>'))
+ call assert_equal('v4 ㄪ 12586', matchstr(out, '\C\<v4\D*12586\>'))
+ call assert_equal("'0 Ëš 730", matchstr(out, '\C''0\D*730\>'))
+ call assert_equal('Z% Ж 1046', matchstr(out, '\C\<Z%\D*1046\>'))
+ call assert_equal('u- Å« 363', matchstr(out, '\C\<u-\D*363\>'))
+ call assert_equal('SH ^A 1', matchstr(out, '\C\<SH\D*1\>'))
+ bw!
+endfunc
+
+func Test_loadkeymap()
+ if !has('keymap')
+ return
+ endif
+ new
+ set keymap=czech
+ set iminsert=0
+ call feedkeys("o|\<c-^>|01234567890|\<esc>", 'tx')
+ call assert_equal("|'é+ěšÄřžýáíé'", getline('.'))
+ " reset keymap and encoding option
+ set keymap=
+ bw!
+endfunc
+
+func Test_digraph_cmndline()
+ " Create digraph on commandline
+ " This is a hack, to let Vim create the digraph in commandline mode
+ let s = ''
+ exe "sil! norm! :let s.='\<c-k>Eu'\<cr>"
+ call assert_equal("€", s)
+endfunc
+
+func Test_show_digraph()
+ new
+ call Put_Dig("e=")
+ call assert_equal("\n<е> 1077, Hex 0435, Oct 2065, Digr e=", execute('ascii'))
+ bwipe!
+endfunc
+
+func Test_show_digraph_cp1251()
+ new
+ set encoding=cp1251
+ call Put_Dig("='")
+ call assert_equal("\n<\xfa> <|z> <M-z> 250, Hex fa, Oct 372, Digr ='", execute('ascii'))
+ set encoding=utf-8
+ bwipe!
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/test_display.vim b/src/testdir/test_display.vim
new file mode 100644
index 0000000..81ffb2c
--- /dev/null
+++ b/src/testdir/test_display.vim
@@ -0,0 +1,69 @@
+" Test for displaying stuff
+if !has('gui_running') && has('unix')
+ set term=ansi
+endif
+
+source view_util.vim
+
+func Test_display_foldcolumn()
+ if !has("folding")
+ return
+ endif
+ new
+ vnew
+ vert resize 25
+ call assert_equal(25, winwidth(winnr()))
+ set isprint=@
+
+ 1put='e more noise blah blah‚ more stuff here'
+
+ let expect = [
+ \ "e more noise blah blah<82",
+ \ "> more stuff here "
+ \ ]
+
+ call cursor(2, 1)
+ norm! zt
+ let lines=ScreenLines([1,2], winwidth(0))
+ call assert_equal(expect, lines)
+ set fdc=2
+ let lines=ScreenLines([1,2], winwidth(0))
+ let expect = [
+ \ " e more noise blah blah<",
+ \ " 82> more stuff here "
+ \ ]
+ call assert_equal(expect, lines)
+
+ quit!
+ quit!
+endfunc
+
+func Test_display_foldtext_mbyte()
+ if !has("folding")
+ return
+ endif
+ call NewWindow(10, 40)
+ call append(0, range(1,20))
+ exe "set foldmethod=manual foldtext=foldtext() fillchars=fold:\u2500,vert:\u2502 fdc=2"
+ call cursor(2, 1)
+ norm! zf13G
+ let lines=ScreenLines([1,3], winwidth(0)+1)
+ let expect=[
+ \ " 1 \u2502",
+ \ "+ +-- 12 lines: 2". repeat("\u2500", 23). "\u2502",
+ \ " 14 \u2502",
+ \ ]
+ call assert_equal(expect, lines)
+
+ set fillchars=fold:-,vert:\|
+ let lines=ScreenLines([1,3], winwidth(0)+1)
+ let expect=[
+ \ " 1 |",
+ \ "+ +-- 12 lines: 2". repeat("-", 23). "|",
+ \ " 14 |",
+ \ ]
+ call assert_equal(expect, lines)
+
+ set foldtext& fillchars& foldmethod& fdc&
+ bw!
+endfunc
diff --git a/src/testdir/test_edit.vim b/src/testdir/test_edit.vim
new file mode 100644
index 0000000..9a60d01
--- /dev/null
+++ b/src/testdir/test_edit.vim
@@ -0,0 +1,1438 @@
+" Test for edit functions
+"
+if exists("+t_kD")
+ let &t_kD="[3;*~"
+endif
+
+" Needed for testing basic rightleft: Test_edit_rightleft
+source view_util.vim
+
+" Needs to come first until the bug in getchar() is
+" fixed: https://groups.google.com/d/msg/vim_dev/fXL9yme4H4c/bOR-U6_bAQAJ
+func Test_edit_00b()
+ new
+ call setline(1, ['abc '])
+ inoreabbr <buffer> h here some more
+ call cursor(1, 4)
+ " <c-l> expands the abbreviation and ends insertmode
+ call feedkeys(":set im\<cr> h\<c-l>:set noim\<cr>", 'tix')
+ call assert_equal(['abc here some more '], getline(1,'$'))
+ iunabbr <buffer> h
+ bw!
+endfunc
+
+func Test_edit_01()
+ " set for Travis CI?
+ " set nocp noesckeys
+ new
+ " 1) empty buffer
+ call assert_equal([''], getline(1,'$'))
+ " 2) delete in an empty line
+ call feedkeys("i\<del>\<esc>", 'tnix')
+ call assert_equal([''], getline(1,'$'))
+ %d
+ " 3) delete one character
+ call setline(1, 'a')
+ call feedkeys("i\<del>\<esc>", 'tnix')
+ call assert_equal([''], getline(1,'$'))
+ %d
+ " 4) delete a multibyte character
+ call setline(1, "\u0401")
+ call feedkeys("i\<del>\<esc>", 'tnix')
+ call assert_equal([''], getline(1,'$'))
+ %d
+ " 5.1) delete linebreak with 'bs' option containing eol
+ let _bs=&bs
+ set bs=eol
+ call setline(1, ["abc def", "ghi jkl"])
+ call cursor(1, 1)
+ call feedkeys("A\<del>\<esc>", 'tnix')
+ call assert_equal(['abc defghi jkl'], getline(1, 2))
+ %d
+ " 5.2) delete linebreak with backspace option w/out eol
+ set bs=
+ call setline(1, ["abc def", "ghi jkl"])
+ call cursor(1, 1)
+ call feedkeys("A\<del>\<esc>", 'tnix')
+ call assert_equal(["abc def", "ghi jkl"], getline(1, 2))
+ let &bs=_bs
+ bw!
+endfunc
+
+func Test_edit_02()
+ " Change cursor position in InsertCharPre command
+ new
+ call setline(1, 'abc')
+ call cursor(1, 1)
+ fu! DoIt(...)
+ call cursor(1, 4)
+ if len(a:000)
+ let v:char=a:1
+ endif
+ endfu
+ au InsertCharPre <buffer> :call DoIt('y')
+ call feedkeys("ix\<esc>", 'tnix')
+ call assert_equal(['abcy'], getline(1, '$'))
+ " Setting <Enter> in InsertCharPre
+ au! InsertCharPre <buffer> :call DoIt("\n")
+ call setline(1, 'abc')
+ call cursor(1, 1)
+ call feedkeys("ix\<esc>", 'tnix')
+ call assert_equal(['abc', ''], getline(1, '$'))
+ %d
+ au! InsertCharPre
+ " Change cursor position in InsertEnter command
+ " 1) when setting v:char, keeps changed cursor position
+ au! InsertEnter <buffer> :call DoIt('y')
+ call setline(1, 'abc')
+ call cursor(1, 1)
+ call feedkeys("ix\<esc>", 'tnix')
+ call assert_equal(['abxc'], getline(1, '$'))
+ " 2) when not setting v:char, restores changed cursor position
+ au! InsertEnter <buffer> :call DoIt()
+ call setline(1, 'abc')
+ call cursor(1, 1)
+ call feedkeys("ix\<esc>", 'tnix')
+ call assert_equal(['xabc'], getline(1, '$'))
+ au! InsertEnter
+ delfu DoIt
+ bw!
+endfunc
+
+func Test_edit_03()
+ " Change cursor after <c-o> command to end of line
+ new
+ call setline(1, 'abc')
+ call cursor(1, 1)
+ call feedkeys("i\<c-o>$y\<esc>", 'tnix')
+ call assert_equal(['abcy'], getline(1, '$'))
+ %d
+ call setline(1, 'abc')
+ call cursor(1, 1)
+ call feedkeys("i\<c-o>80|y\<esc>", 'tnix')
+ call assert_equal(['abcy'], getline(1, '$'))
+ %d
+ call setline(1, 'abc')
+ call feedkeys("Ad\<c-o>:s/$/efg/\<cr>hij", 'tnix')
+ call assert_equal(['hijabcdefg'], getline(1, '$'))
+ bw!
+endfunc
+
+func Test_edit_04()
+ " test for :stopinsert
+ new
+ call setline(1, 'abc')
+ call cursor(1, 1)
+ call feedkeys("i\<c-o>:stopinsert\<cr>$", 'tnix')
+ call feedkeys("aX\<esc>", 'tnix')
+ call assert_equal(['abcX'], getline(1, '$'))
+ %d
+ bw!
+endfunc
+
+func Test_edit_05()
+ " test for folds being opened
+ new
+ call setline(1, ['abcX', 'abcX', 'zzzZ'])
+ call cursor(1, 1)
+ set foldmethod=manual foldopen+=insert
+ " create fold for those two lines
+ norm! Vjzf
+ call feedkeys("$ay\<esc>", 'tnix')
+ call assert_equal(['abcXy', 'abcX', 'zzzZ'], getline(1, '$'))
+ %d
+ call setline(1, ['abcX', 'abcX', 'zzzZ'])
+ call cursor(1, 1)
+ set foldmethod=manual foldopen-=insert
+ " create fold for those two lines
+ norm! Vjzf
+ call feedkeys("$ay\<esc>", 'tnix')
+ call assert_equal(['abcXy', 'abcX', 'zzzZ'], getline(1, '$'))
+ %d
+ bw!
+endfunc
+
+func Test_edit_06()
+ " Test in diff mode
+ if !has("diff") || !executable("diff")
+ return
+ endif
+ new
+ call setline(1, ['abc', 'xxx', 'yyy'])
+ vnew
+ call setline(1, ['abc', 'zzz', 'xxx', 'yyy'])
+ wincmd p
+ diffthis
+ wincmd p
+ diffthis
+ wincmd p
+ call cursor(2, 1)
+ norm! zt
+ call feedkeys("Ozzz\<esc>", 'tnix')
+ call assert_equal(['abc', 'zzz', 'xxx', 'yyy'], getline(1,'$'))
+ bw!
+ bw!
+endfunc
+
+func Test_edit_07()
+ " 1) Test with completion <c-l> when popupmenu is visible
+ new
+ call setline(1, 'J')
+
+ func! ListMonths()
+ call complete(col('.')-1, ['January', 'February', 'March',
+ \ 'April', 'May', 'June', 'July', 'August', 'September',
+ \ 'October', 'November', 'December'])
+ return ''
+ endfunc
+ inoremap <buffer> <F5> <C-R>=ListMonths()<CR>
+
+ call feedkeys("A\<f5>\<c-p>". repeat("\<down>", 6)."\<c-l>\<down>\<c-l>\<cr>", 'tx')
+ call assert_equal(['July'], getline(1,'$'))
+ " 1) Test completion when InsertCharPre kicks in
+ %d
+ call setline(1, 'J')
+ fu! DoIt()
+ if v:char=='u'
+ let v:char='an'
+ endif
+ endfu
+ au InsertCharPre <buffer> :call DoIt()
+ call feedkeys("A\<f5>\<c-p>u\<cr>\<c-l>\<cr>", 'tx')
+ call assert_equal(["Jan\<c-l>",''], getline(1,'$'))
+ %d
+ call setline(1, 'J')
+ call feedkeys("A\<f5>\<c-p>u\<down>\<c-l>\<cr>", 'tx')
+ call assert_equal(["January"], getline(1,'$'))
+
+ delfu ListMonths
+ delfu DoIt
+ iunmap <buffer> <f5>
+ bw!
+endfunc
+
+func Test_edit_08()
+ " reset insertmode from i_ctrl-r_=
+ let g:bufnr = bufnr('%')
+ new
+ call setline(1, ['abc'])
+ call cursor(1, 4)
+ call feedkeys(":set im\<cr>ZZZ\<c-r>=setbufvar(g:bufnr,'&im', 0)\<cr>",'tnix')
+ call assert_equal(['abZZZc'], getline(1,'$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+ call assert_false(0, '&im')
+ bw!
+ unlet g:bufnr
+endfunc
+
+func Test_edit_09()
+ " test i_CTRL-\ combinations
+ new
+ call setline(1, ['abc', 'def', 'ghi'])
+ call cursor(1, 1)
+ " 1) CTRL-\ CTLR-N
+ call feedkeys(":set im\<cr>\<c-\>\<c-n>ccABC\<c-l>", 'txin')
+ call assert_equal(['ABC', 'def', 'ghi'], getline(1,'$'))
+ call setline(1, ['ABC', 'def', 'ghi'])
+ " 2) CTRL-\ CTLR-G
+ call feedkeys("j0\<c-\>\<c-g>ZZZ\<cr>\<c-l>", 'txin')
+ call assert_equal(['ABC', 'ZZZ', 'def', 'ghi'], getline(1,'$'))
+ call feedkeys("I\<c-\>\<c-g>YYY\<c-l>", 'txin')
+ call assert_equal(['ABC', 'ZZZ', 'YYYdef', 'ghi'], getline(1,'$'))
+ set noinsertmode
+ " 3) CTRL-\ CTRL-O
+ call setline(1, ['ABC', 'ZZZ', 'def', 'ghi'])
+ call cursor(1, 1)
+ call feedkeys("A\<c-o>ix", 'txin')
+ call assert_equal(['ABxC', 'ZZZ', 'def', 'ghi'], getline(1,'$'))
+ call feedkeys("A\<c-\>\<c-o>ix", 'txin')
+ call assert_equal(['ABxCx', 'ZZZ', 'def', 'ghi'], getline(1,'$'))
+ " 4) CTRL-\ a (should be inserted literally, not special after <c-\>
+ call setline(1, ['ABC', 'ZZZ', 'def', 'ghi'])
+ call cursor(1, 1)
+ call feedkeys("A\<c-\>a", 'txin')
+ call assert_equal(["ABC\<c-\>a", 'ZZZ', 'def', 'ghi'], getline(1, '$'))
+ bw!
+endfunc
+
+func Test_edit_10()
+ " Test for starting selectmode
+ new
+ set selectmode=key keymodel=startsel
+ call setline(1, ['abc', 'def', 'ghi'])
+ call cursor(1, 4)
+ call feedkeys("A\<s-home>start\<esc>", 'txin')
+ call assert_equal(['startdef', 'ghi'], getline(1, '$'))
+ set selectmode= keymodel=
+ bw!
+endfunc
+
+func Test_edit_11()
+ " Test that indenting kicks in
+ new
+ set cindent
+ call setline(1, ['{', '', ''])
+ call cursor(2, 1)
+ call feedkeys("i\<c-f>int c;\<esc>", 'tnix')
+ call cursor(3, 1)
+ call feedkeys("i/* comment */", 'tnix')
+ call assert_equal(['{', "\<tab>int c;", "/* comment */"], getline(1, '$'))
+ " added changed cindentkeys slightly
+ set cindent cinkeys+=*/
+ call setline(1, ['{', '', ''])
+ call cursor(2, 1)
+ call feedkeys("i\<c-f>int c;\<esc>", 'tnix')
+ call cursor(3, 1)
+ call feedkeys("i/* comment */", 'tnix')
+ call assert_equal(['{', "\<tab>int c;", "\<tab>/* comment */"], getline(1, '$'))
+ set cindent cinkeys+==end
+ call feedkeys("oend\<cr>\<esc>", 'tnix')
+ call assert_equal(['{', "\<tab>int c;", "\<tab>/* comment */", "\tend", ''], getline(1, '$'))
+ set cinkeys-==end
+ %d
+ " Use indentexpr instead of cindenting
+ func! Do_Indent()
+ if v:lnum == 3
+ return 3*shiftwidth()
+ else
+ return 2*shiftwidth()
+ endif
+ endfunc
+ setl indentexpr=Do_Indent() indentkeys+=*/
+ call setline(1, ['{', '', ''])
+ call cursor(2, 1)
+ call feedkeys("i\<c-f>int c;\<esc>", 'tnix')
+ call cursor(3, 1)
+ call feedkeys("i/* comment */", 'tnix')
+ call assert_equal(['{', "\<tab>\<tab>int c;", "\<tab>\<tab>\<tab>/* comment */"], getline(1, '$'))
+ set cinkeys&vim indentkeys&vim
+ set nocindent indentexpr=
+ delfu Do_Indent
+ bw!
+endfunc
+
+func Test_edit_11_indentexpr()
+ " Test that indenting kicks in
+ new
+ " Use indentexpr instead of cindenting
+ func! Do_Indent()
+ let pline=prevnonblank(v:lnum)
+ if empty(getline(v:lnum))
+ if getline(pline) =~ 'if\|then'
+ return shiftwidth()
+ else
+ return 0
+ endif
+ else
+ return 0
+ endif
+ endfunc
+ setl indentexpr=Do_Indent() indentkeys+=0=then,0=fi
+ call setline(1, ['if [ $this ]'])
+ call cursor(1, 1)
+ call feedkeys("othen\<cr>that\<cr>fi", 'tnix')
+ call assert_equal(['if [ $this ]', "then", "\<tab>that", "fi"], getline(1, '$'))
+ set cinkeys&vim indentkeys&vim
+ set nocindent indentexpr=
+ delfu Do_Indent
+ bw!
+endfunc
+
+func Test_edit_12()
+ " Test changing indent in replace mode
+ new
+ call setline(1, ["\tabc", "\tdef"])
+ call cursor(2, 4)
+ call feedkeys("R^\<c-d>", 'tnix')
+ call assert_equal(["\tabc", "def"], getline(1, '$'))
+ call assert_equal([0, 2, 2, 0], getpos('.'))
+ %d
+ call setline(1, ["\tabc", "\t\tdef"])
+ call cursor(2, 2)
+ call feedkeys("R^\<c-d>", 'tnix')
+ call assert_equal(["\tabc", "def"], getline(1, '$'))
+ call assert_equal([0, 2, 1, 0], getpos('.'))
+ %d
+ call setline(1, ["\tabc", "\t\tdef"])
+ call cursor(2, 2)
+ call feedkeys("R\<c-t>", 'tnix')
+ call assert_equal(["\tabc", "\t\t\tdef"], getline(1, '$'))
+ call assert_equal([0, 2, 2, 0], getpos('.'))
+ bw!
+ 10vnew
+ call setline(1, ["\tabc", "\t\tdef"])
+ call cursor(2, 2)
+ call feedkeys("R\<c-t>", 'tnix')
+ call assert_equal(["\tabc", "\t\t\tdef"], getline(1, '$'))
+ call assert_equal([0, 2, 2, 0], getpos('.'))
+ %d
+ set sw=4
+ call setline(1, ["\tabc", "\t\tdef"])
+ call cursor(2, 2)
+ call feedkeys("R\<c-t>\<c-t>", 'tnix')
+ call assert_equal(["\tabc", "\t\t\tdef"], getline(1, '$'))
+ call assert_equal([0, 2, 2, 0], getpos('.'))
+ %d
+ call setline(1, ["\tabc", "\t\tdef"])
+ call cursor(2, 2)
+ call feedkeys("R\<c-t>\<c-t>", 'tnix')
+ call assert_equal(["\tabc", "\t\t\tdef"], getline(1, '$'))
+ call assert_equal([0, 2, 2, 0], getpos('.'))
+ set et
+ set sw& et&
+ %d
+ call setline(1, ["\t/*"])
+ set formatoptions=croql
+ call cursor(1, 3)
+ call feedkeys("A\<cr>\<cr>/", 'tnix')
+ call assert_equal(["\t/*", " *", " */"], getline(1, '$'))
+ set formatoptions&
+ bw!
+endfunc
+
+func Test_edit_13()
+ " Test smartindenting
+ if exists("+smartindent")
+ new
+ set smartindent autoindent
+ call setline(1, ["\tabc"])
+ call feedkeys("A {\<cr>more\<cr>}\<esc>", 'tnix')
+ call assert_equal(["\tabc {", "\t\tmore", "\t}"], getline(1, '$'))
+ set smartindent& autoindent&
+ bw!
+ endif
+endfunc
+
+func Test_edit_CR()
+ " Test for <CR> in insert mode
+ " basically only in quickfix mode ist tested, the rest
+ " has been taken care of by other tests
+ if !has("quickfix")
+ return
+ endif
+ botright new
+ call writefile(range(1, 10), 'Xqflist.txt')
+ call setqflist([{'filename': 'Xqflist.txt', 'lnum': 2}])
+ copen
+ set modifiable
+ call feedkeys("A\<cr>", 'tnix')
+ call assert_equal('Xqflist.txt', bufname(''))
+ call assert_equal(2, line('.'))
+ cclose
+ botright new
+ call setloclist(0, [{'filename': 'Xqflist.txt', 'lnum': 10}])
+ lopen
+ set modifiable
+ call feedkeys("A\<cr>", 'tnix')
+ call assert_equal('Xqflist.txt', bufname(''))
+ call assert_equal(10, line('.'))
+ call feedkeys("A\<Enter>", 'tnix')
+ call feedkeys("A\<kEnter>", 'tnix')
+ call feedkeys("A\n", 'tnix')
+ call feedkeys("A\r", 'tnix')
+ call assert_equal(map(range(1, 10), 'string(v:val)') + ['', '', '', ''], getline(1, '$'))
+ bw!
+ lclose
+ call delete('Xqflist.txt')
+endfunc
+
+func Test_edit_CTRL_()
+ " disabled for Windows builds, why?
+ if !has("rightleft") || has("win32")
+ return
+ endif
+ let _encoding=&encoding
+ set encoding=utf-8
+ " Test for CTRL-_
+ new
+ call setline(1, ['abc'])
+ call cursor(1, 1)
+ call feedkeys("i\<c-_>xyz\<esc>", 'tnix')
+ call assert_equal(["\<C-_>xyzabc"], getline(1, '$'))
+ call assert_false(&revins)
+ set ari
+ call setline(1, ['abc'])
+ call cursor(1, 1)
+ call feedkeys("i\<c-_>xyz\<esc>", 'tnix')
+ call assert_equal(["æèñabc"], getline(1, '$'))
+ call assert_true(&revins)
+ call setline(1, ['abc'])
+ call cursor(1, 1)
+ call feedkeys("i\<c-_>xyz\<esc>", 'tnix')
+ call assert_equal(["xyzabc"], getline(1, '$'))
+ call assert_false(&revins)
+ set noari
+ let &encoding=_encoding
+ bw!
+endfunc
+
+" needs to come first, to have the @. register empty
+func Test_edit_00a_CTRL_A()
+ " Test pressing CTRL-A
+ new
+ call setline(1, repeat([''], 5))
+ call cursor(1, 1)
+ try
+ call feedkeys("A\<NUL>", 'tnix')
+ catch /^Vim\%((\a\+)\)\=:E29/
+ call assert_true(1, 'E29 error caught')
+ endtry
+ call cursor(1, 1)
+ call feedkeys("Afoobar \<esc>", 'tnix')
+ call cursor(2, 1)
+ call feedkeys("A\<c-a>more\<esc>", 'tnix')
+ call cursor(3, 1)
+ call feedkeys("A\<NUL>and more\<esc>", 'tnix')
+ call assert_equal(['foobar ', 'foobar more', 'foobar morend more', '', ''], getline(1, '$'))
+ bw!
+endfunc
+
+func Test_edit_CTRL_EY()
+ " Ctrl-E/ Ctrl-Y in insert mode completion to scroll
+ 10new
+ call setline(1, range(1, 100))
+ call cursor(30, 1)
+ norm! z.
+ call feedkeys("A\<c-x>\<c-e>\<c-e>\<c-e>\<c-e>\<c-e>", 'tnix')
+ call assert_equal(30, winsaveview()['topline'])
+ call assert_equal([0, 30, 2, 0], getpos('.'))
+ call feedkeys("A\<c-x>\<c-e>\<c-e>\<c-e>\<c-e>\<c-e>", 'tnix')
+ call feedkeys("A\<c-x>".repeat("\<c-y>", 10), 'tnix')
+ call assert_equal(21, winsaveview()['topline'])
+ call assert_equal([0, 30, 2, 0], getpos('.'))
+ bw!
+endfunc
+
+func Test_edit_CTRL_G()
+ new
+ call setline(1, ['foobar', 'foobar', 'foobar'])
+ call cursor(2, 4)
+ call feedkeys("ioooooooo\<c-g>k\<c-r>.\<esc>", 'tnix')
+ call assert_equal(['foooooooooobar', 'foooooooooobar', 'foobar'], getline(1, '$'))
+ call assert_equal([0, 1, 11, 0], getpos('.'))
+ call feedkeys("i\<c-g>k\<esc>", 'tnix')
+ call assert_equal([0, 1, 10, 0], getpos('.'))
+ call cursor(2, 4)
+ call feedkeys("i\<c-g>jzzzz\<esc>", 'tnix')
+ call assert_equal(['foooooooooobar', 'foooooooooobar', 'foozzzzbar'], getline(1, '$'))
+ call assert_equal([0, 3, 7, 0], getpos('.'))
+ call feedkeys("i\<c-g>j\<esc>", 'tnix')
+ call assert_equal([0, 3, 6, 0], getpos('.'))
+ bw!
+endfunc
+
+func Test_edit_CTRL_I()
+ " Tab in completion mode
+ let path=expand("%:p:h")
+ new
+ call setline(1, [path. "/", ''])
+ call feedkeys("Arunt\<c-x>\<c-f>\<tab>\<cr>\<esc>", 'tnix')
+ call assert_match('runtest\.vim', getline(1))
+ %d
+ call writefile(['one', 'two', 'three'], 'Xinclude.txt')
+ let include='#include Xinclude.txt'
+ call setline(1, [include, ''])
+ call cursor(2, 1)
+ call feedkeys("A\<c-x>\<tab>\<cr>\<esc>", 'tnix')
+ call assert_equal([include, 'one', ''], getline(1, '$'))
+ call feedkeys("2ggC\<c-x>\<tab>\<down>\<cr>\<esc>", 'tnix')
+ call assert_equal([include, 'two', ''], getline(1, '$'))
+ call feedkeys("2ggC\<c-x>\<tab>\<down>\<down>\<cr>\<esc>", 'tnix')
+ call assert_equal([include, 'three', ''], getline(1, '$'))
+ call feedkeys("2ggC\<c-x>\<tab>\<down>\<down>\<down>\<cr>\<esc>", 'tnix')
+ call assert_equal([include, '', ''], getline(1, '$'))
+ call delete("Xinclude.txt")
+ bw!
+endfunc
+
+func Test_edit_CTRL_K()
+ " Test pressing CTRL-K (basically only dictionary completion and digraphs
+ " the rest is already covered
+ call writefile(['A', 'AA', 'AAA', 'AAAA'], 'Xdictionary.txt')
+ set dictionary=Xdictionary.txt
+ new
+ call setline(1, 'A')
+ call cursor(1, 1)
+ call feedkeys("A\<c-x>\<c-k>\<cr>\<esc>", 'tnix')
+ call assert_equal(['AA', ''], getline(1, '$'))
+ %d
+ call setline(1, 'A')
+ call cursor(1, 1)
+ call feedkeys("A\<c-x>\<c-k>\<down>\<cr>\<esc>", 'tnix')
+ call assert_equal(['AAA'], getline(1, '$'))
+ %d
+ call setline(1, 'A')
+ call cursor(1, 1)
+ call feedkeys("A\<c-x>\<c-k>\<down>\<down>\<cr>\<esc>", 'tnix')
+ call assert_equal(['AAAA'], getline(1, '$'))
+ %d
+ call setline(1, 'A')
+ call cursor(1, 1)
+ call feedkeys("A\<c-x>\<c-k>\<down>\<down>\<down>\<cr>\<esc>", 'tnix')
+ call assert_equal(['A'], getline(1, '$'))
+ %d
+ call setline(1, 'A')
+ call cursor(1, 1)
+ call feedkeys("A\<c-x>\<c-k>\<down>\<down>\<down>\<down>\<cr>\<esc>", 'tnix')
+ call assert_equal(['AA'], getline(1, '$'))
+
+ " press an unexecpted key after dictionary completion
+ %d
+ call setline(1, 'A')
+ call cursor(1, 1)
+ call feedkeys("A\<c-x>\<c-k>\<c-]>\<cr>\<esc>", 'tnix')
+ call assert_equal(['AA', ''], getline(1, '$'))
+ %d
+ call setline(1, 'A')
+ call cursor(1, 1)
+ call feedkeys("A\<c-x>\<c-k>\<c-s>\<cr>\<esc>", 'tnix')
+ call assert_equal(["AA\<c-s>", ''], getline(1, '$'))
+ %d
+ call setline(1, 'A')
+ call cursor(1, 1)
+ call feedkeys("A\<c-x>\<c-k>\<c-f>\<cr>\<esc>", 'tnix')
+ call assert_equal(["AA\<c-f>", ''], getline(1, '$'))
+
+ set dictionary=
+ %d
+ call setline(1, 'A')
+ call cursor(1, 1)
+ let v:testing = 1
+ try
+ call feedkeys("A\<c-x>\<c-k>\<esc>", 'tnix')
+ catch
+ " error sleeps 2 seconds, when v:testing is not set
+ let v:testing = 0
+ endtry
+ call delete('Xdictionary.txt')
+
+ call test_override("char_avail", 1)
+ set showcmd
+ %d
+ call feedkeys("A\<c-k>a:\<esc>", 'tnix')
+ call assert_equal(['ä'], getline(1, '$'))
+ call test_override("char_avail", 0)
+ set noshowcmd
+
+ bw!
+endfunc
+
+func Test_edit_CTRL_L()
+ " Test Ctrl-X Ctrl-L (line completion)
+ new
+ set complete=.
+ call setline(1, ['one', 'two', 'three', '', '', '', ''])
+ call cursor(4, 1)
+ call feedkeys("A\<c-x>\<c-l>\<esc>", 'tnix')
+ call assert_equal(['one', 'two', 'three', 'three', '', '', ''], getline(1, '$'))
+ call feedkeys("cct\<c-x>\<c-l>\<c-n>\<esc>", 'tnix')
+ call assert_equal(['one', 'two', 'three', 't', '', '', ''], getline(1, '$'))
+ call feedkeys("cct\<c-x>\<c-l>\<c-n>\<c-n>\<esc>", 'tnix')
+ call assert_equal(['one', 'two', 'three', 'two', '', '', ''], getline(1, '$'))
+ call feedkeys("cct\<c-x>\<c-l>\<c-n>\<c-n>\<c-n>\<esc>", 'tnix')
+ call assert_equal(['one', 'two', 'three', 'three', '', '', ''], getline(1, '$'))
+ call feedkeys("cct\<c-x>\<c-l>\<c-n>\<c-n>\<c-n>\<c-n>\<esc>", 'tnix')
+ call assert_equal(['one', 'two', 'three', 't', '', '', ''], getline(1, '$'))
+ call feedkeys("cct\<c-x>\<c-l>\<c-p>\<esc>", 'tnix')
+ call assert_equal(['one', 'two', 'three', 'two', '', '', ''], getline(1, '$'))
+ call feedkeys("cct\<c-x>\<c-l>\<c-p>\<c-p>\<esc>", 'tnix')
+ call assert_equal(['one', 'two', 'three', 't', '', '', ''], getline(1, '$'))
+ call feedkeys("cct\<c-x>\<c-l>\<c-p>\<c-p>\<c-p>\<esc>", 'tnix')
+ call assert_equal(['one', 'two', 'three', 'three', '', '', ''], getline(1, '$'))
+ set complete=
+ call cursor(5, 1)
+ call feedkeys("A\<c-x>\<c-l>\<c-p>\<c-n>\<esc>", 'tnix')
+ call assert_equal(['one', 'two', 'three', 'three', "\<c-l>\<c-p>\<c-n>", '', ''], getline(1, '$'))
+ set complete&
+ %d
+ if has("conceal") && has("syntax")
+ call setline(1, ['foo', 'bar', 'foobar'])
+ call test_override("char_avail", 1)
+ set conceallevel=2 concealcursor=n
+ syn on
+ syn match ErrorMsg "^bar"
+ call matchadd("Conceal", 'oo', 10, -1, {'conceal': 'X'})
+ func! DoIt()
+ let g:change=1
+ endfunc
+ au! TextChangedI <buffer> :call DoIt()
+
+ call cursor(2, 1)
+ call assert_false(exists("g:change"))
+ call feedkeys("A \<esc>", 'tnix')
+ call assert_equal(['foo', 'bar ', 'foobar'], getline(1, '$'))
+ call assert_equal(1, g:change)
+
+ call test_override("char_avail", 0)
+ call clearmatches()
+ syn off
+ au! TextChangedI
+ delfu DoIt
+ unlet! g:change
+ endif
+ bw!
+endfunc
+
+func Test_edit_CTRL_N()
+ " Check keyword completion
+ new
+ set complete=.
+ call setline(1, ['INFER', 'loWER', '', '', ])
+ call cursor(3, 1)
+ call feedkeys("Ai\<c-n>\<cr>\<esc>", "tnix")
+ call feedkeys("ILO\<c-n>\<cr>\<esc>", 'tnix')
+ call assert_equal(['INFER', 'loWER', 'i', 'LO', '', ''], getline(1, '$'))
+ %d
+ call setline(1, ['INFER', 'loWER', '', '', ])
+ call cursor(3, 1)
+ set ignorecase infercase
+ call feedkeys("Ii\<c-n>\<cr>\<esc>", "tnix")
+ call feedkeys("ILO\<c-n>\<cr>\<esc>", 'tnix')
+ call assert_equal(['INFER', 'loWER', 'infer', 'LOWER', '', ''], getline(1, '$'))
+
+ set noignorecase noinfercase complete&
+ bw!
+endfunc
+
+func Test_edit_CTRL_O()
+ " Check for CTRL-O in insert mode
+ new
+ inoreabbr <buffer> h here some more
+ call setline(1, ['abc', 'def'])
+ call cursor(1, 1)
+ " Ctrl-O after an abbreviation
+ exe "norm A h\<c-o>:set nu\<cr> text"
+ call assert_equal(['abc here some more text', 'def'], getline(1, '$'))
+ call assert_true(&nu)
+ set nonu
+ iunabbr <buffer> h
+ " Ctrl-O at end of line with 've'=onemore
+ call cursor(1, 1)
+ call feedkeys("A\<c-o>:let g:a=getpos('.')\<cr>\<esc>", 'tnix')
+ call assert_equal([0, 1, 23, 0], g:a)
+ call cursor(1, 1)
+ set ve=onemore
+ call feedkeys("A\<c-o>:let g:a=getpos('.')\<cr>\<esc>", 'tnix')
+ call assert_equal([0, 1, 24, 0], g:a)
+ set ve=
+ unlet! g:a
+ bw!
+endfunc
+
+func Test_edit_CTRL_R()
+ " Insert Register
+ new
+ call test_override("ALL", 1)
+ set showcmd
+ call feedkeys("AFOOBAR eins zwei\<esc>", 'tnix')
+ call feedkeys("O\<c-r>.", 'tnix')
+ call feedkeys("O\<c-r>=10*500\<cr>\<esc>", 'tnix')
+ call feedkeys("O\<c-r>=getreg('=', 1)\<cr>\<esc>", 'tnix')
+ call assert_equal(["getreg('=', 1)", '5000', "FOOBAR eins zwei", "FOOBAR eins zwei"], getline(1, '$'))
+ call test_override("ALL", 0)
+ set noshowcmd
+ bw!
+endfunc
+
+func Test_edit_CTRL_S()
+ " Test pressing CTRL-S (basically only spellfile completion)
+ " the rest is already covered
+ new
+ if !has("spell")
+ call setline(1, 'vim')
+ call feedkeys("A\<c-x>ss\<cr>\<esc>", 'tnix')
+ call assert_equal(['vims', ''], getline(1, '$'))
+ bw!
+ return
+ endif
+ call setline(1, 'vim')
+ " spell option not yet set
+ try
+ call feedkeys("A\<c-x>\<c-s>\<cr>\<esc>", 'tnix')
+ catch /^Vim\%((\a\+)\)\=:E756/
+ call assert_true(1, 'error caught')
+ endtry
+ call assert_equal(['vim', ''], getline(1, '$'))
+ %d
+ setl spell spelllang=en
+ call setline(1, 'vim')
+ call cursor(1, 1)
+ call feedkeys("A\<c-x>\<c-s>\<cr>\<esc>", 'tnix')
+ call assert_equal(['Vim', ''], getline(1, '$'))
+ %d
+ call setline(1, 'vim')
+ call cursor(1, 1)
+ call feedkeys("A\<c-x>\<c-s>\<down>\<cr>\<esc>", 'tnix')
+ call assert_equal(['Aim'], getline(1, '$'))
+ %d
+ call setline(1, 'vim')
+ call cursor(1, 1)
+ call feedkeys("A\<c-x>\<c-s>\<c-p>\<cr>\<esc>", 'tnix')
+ call assert_equal(['vim', ''], getline(1, '$'))
+ %d
+ " empty buffer
+ call cursor(1, 1)
+ call feedkeys("A\<c-x>\<c-s>\<c-p>\<cr>\<esc>", 'tnix')
+ call assert_equal(['', ''], getline(1, '$'))
+ setl nospell
+ bw!
+endfunc
+
+func Test_edit_CTRL_T()
+ " Check for CTRL-T and CTRL-X CTRL-T in insert mode
+ " 1) increase indent
+ new
+ call setline(1, "abc")
+ call cursor(1, 1)
+ call feedkeys("A\<c-t>xyz", 'tnix')
+ call assert_equal(["\<tab>abcxyz"], getline(1, '$'))
+ " 2) also when paste option is set
+ set paste
+ call setline(1, "abc")
+ call cursor(1, 1)
+ call feedkeys("A\<c-t>xyz", 'tnix')
+ call assert_equal(["\<tab>abcxyz"], getline(1, '$'))
+ set nopaste
+ " CTRL-X CTRL-T (thesaurus complete)
+ call writefile(['angry furious mad enraged'], 'Xthesaurus')
+ set thesaurus=Xthesaurus
+ call setline(1, 'mad')
+ call cursor(1, 1)
+ call feedkeys("A\<c-x>\<c-t>\<cr>\<esc>", 'tnix')
+ call assert_equal(['mad', ''], getline(1, '$'))
+ %d
+ call setline(1, 'mad')
+ call cursor(1, 1)
+ call feedkeys("A\<c-x>\<c-t>\<c-n>\<cr>\<esc>", 'tnix')
+ call assert_equal(['angry', ''], getline(1, '$'))
+ %d
+ call setline(1, 'mad')
+ call cursor(1, 1)
+ call feedkeys("A\<c-x>\<c-t>\<c-n>\<c-n>\<cr>\<esc>", 'tnix')
+ call assert_equal(['furious', ''], getline(1, '$'))
+ %d
+ call setline(1, 'mad')
+ call cursor(1, 1)
+ call feedkeys("A\<c-x>\<c-t>\<c-n>\<c-n>\<c-n>\<cr>\<esc>", 'tnix')
+ call assert_equal(['enraged', ''], getline(1, '$'))
+ %d
+ call setline(1, 'mad')
+ call cursor(1, 1)
+ call feedkeys("A\<c-x>\<c-t>\<c-n>\<c-n>\<c-n>\<c-n>\<cr>\<esc>", 'tnix')
+ call assert_equal(['mad', ''], getline(1, '$'))
+ %d
+ call setline(1, 'mad')
+ call cursor(1, 1)
+ call feedkeys("A\<c-x>\<c-t>\<c-n>\<c-n>\<c-n>\<c-n>\<c-n>\<cr>\<esc>", 'tnix')
+ call assert_equal(['mad', ''], getline(1, '$'))
+ " Using <c-p> <c-n> when 'complete' is empty
+ set complete=
+ %d
+ call setline(1, 'mad')
+ call cursor(1, 1)
+ call feedkeys("A\<c-x>\<c-t>\<c-n>\<cr>\<esc>", 'tnix')
+ call assert_equal(['angry', ''], getline(1, '$'))
+ %d
+ call setline(1, 'mad')
+ call cursor(1, 1)
+ call feedkeys("A\<c-x>\<c-t>\<c-p>\<cr>\<esc>", 'tnix')
+ call assert_equal(['mad', ''], getline(1, '$'))
+ set complete&
+
+ set thesaurus=
+ %d
+ call setline(1, 'mad')
+ call cursor(1, 1)
+ let v:testing = 1
+ try
+ call feedkeys("A\<c-x>\<c-t>\<esc>", 'tnix')
+ catch
+ " error sleeps 2 seconds, when v:testing is not set
+ let v:testing = 0
+ endtry
+ call assert_equal(['mad'], getline(1, '$'))
+ call delete('Xthesaurus')
+ bw!
+endfunc
+
+func Test_edit_CTRL_U()
+ " Test 'completefunc'
+ new
+ " -1, -2 and -3 are special return values
+ let g:special=0
+ fun! CompleteMonths(findstart, base)
+ if a:findstart
+ " locate the start of the word
+ return g:special
+ else
+ " find months matching with "a:base"
+ let res = []
+ for m in split("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec")
+ if m =~ '^\c'.a:base
+ call add(res, {'word': m, 'abbr': m.' Month', 'icase': 0})
+ endif
+ endfor
+ return {'words': res, 'refresh': 'always'}
+ endif
+ endfun
+ set completefunc=CompleteMonths
+ call setline(1, ['', ''])
+ call cursor(1, 1)
+ call feedkeys("AX\<c-x>\<c-u>\<cr>\<esc>", 'tnix')
+ call assert_equal(['X', '', ''], getline(1, '$'))
+ %d
+ let g:special=-1
+ call feedkeys("AX\<c-x>\<c-u>\<cr>\<esc>", 'tnix')
+ call assert_equal(['XJan', ''], getline(1, '$'))
+ %d
+ let g:special=-2
+ call feedkeys("AX\<c-x>\<c-u>\<cr>\<esc>", 'tnix')
+ call assert_equal(['X', ''], getline(1, '$'))
+ %d
+ let g:special=-3
+ call feedkeys("AX\<c-x>\<c-u>\<cr>\<esc>", 'tnix')
+ call assert_equal(['X', ''], getline(1, '$'))
+ %d
+ let g:special=0
+ call feedkeys("AM\<c-x>\<c-u>\<cr>\<esc>", 'tnix')
+ call assert_equal(['Mar', ''], getline(1, '$'))
+ %d
+ call feedkeys("AM\<c-x>\<c-u>\<c-n>\<cr>\<esc>", 'tnix')
+ call assert_equal(['May', ''], getline(1, '$'))
+ %d
+ call feedkeys("AM\<c-x>\<c-u>\<c-n>\<c-n>\<cr>\<esc>", 'tnix')
+ call assert_equal(['M', ''], getline(1, '$'))
+ delfu CompleteMonths
+ %d
+ try
+ call feedkeys("A\<c-x>\<c-u>", 'tnix')
+ call assert_fails(1, 'unknown completion function')
+ catch /^Vim\%((\a\+)\)\=:E117/
+ call assert_true(1, 'E117 error caught')
+ endtry
+ set completefunc=
+ bw!
+endfunc
+
+func Test_edit_CTRL_Z()
+ " Ctrl-Z when insertmode is not set inserts it literally
+ new
+ call setline(1, 'abc')
+ call feedkeys("A\<c-z>\<esc>", 'tnix')
+ call assert_equal(["abc\<c-z>"], getline(1,'$'))
+ bw!
+ " TODO: How to Test Ctrl-Z in insert mode, e.g. suspend?
+endfunc
+
+func Test_edit_DROP()
+ if !has("dnd")
+ return
+ endif
+ new
+ call setline(1, ['abc def ghi'])
+ call cursor(1, 1)
+ try
+ call feedkeys("i\<Drop>\<Esc>", 'tnix')
+ call assert_fails(1, 'Invalid register name')
+ catch /^Vim\%((\a\+)\)\=:E353/
+ call assert_true(1, 'error caught')
+ endtry
+ bw!
+endfunc
+
+func Test_edit_CTRL_V()
+ if has("ebcdic")
+ return
+ endif
+ new
+ call setline(1, ['abc'])
+ call cursor(2, 1)
+ " force some redraws
+ set showmode showcmd
+ "call test_override_char_avail(1)
+ call test_override('ALL', 1)
+ call feedkeys("A\<c-v>\<c-n>\<c-v>\<c-l>\<c-v>\<c-b>\<esc>", 'tnix')
+ call assert_equal(["abc\x0e\x0c\x02"], getline(1, '$'))
+
+ if has("rightleft") && exists("+rl")
+ set rl
+ call setline(1, ['abc'])
+ call cursor(2, 1)
+ call feedkeys("A\<c-v>\<c-n>\<c-v>\<c-l>\<c-v>\<c-b>\<esc>", 'tnix')
+ call assert_equal(["abc\x0e\x0c\x02"], getline(1, '$'))
+ set norl
+ endif
+
+ call test_override('ALL', 0)
+ set noshowmode showcmd
+ bw!
+endfunc
+
+func Test_edit_F1()
+ " Pressing <f1>
+ new
+ call feedkeys(":set im\<cr>\<f1>\<c-l>", 'tnix')
+ set noinsertmode
+ call assert_equal('help', &buftype)
+ bw
+ bw
+endfunc
+
+func Test_edit_F21()
+ " Pressing <f21>
+ " sends a netbeans command
+ if has("netbeans_intg")
+ new
+ " I have no idea what this is supposed to do :)
+ call feedkeys("A\<F21>\<F1>\<esc>", 'tnix')
+ bw
+ endif
+endfunc
+
+func Test_edit_HOME_END()
+ " Test Home/End Keys
+ new
+ set foldopen+=hor
+ call setline(1, ['abc', 'def'])
+ call cursor(1, 1)
+ call feedkeys("AX\<Home>Y\<esc>", 'tnix')
+ call cursor(2, 1)
+ call feedkeys("iZ\<End>Y\<esc>", 'tnix')
+ call assert_equal(['YabcX', 'ZdefY'], getline(1, '$'))
+
+ set foldopen-=hor
+ bw!
+endfunc
+
+func Test_edit_INS()
+ " Test for Pressing <Insert>
+ new
+ call setline(1, ['abc', 'def'])
+ call cursor(1, 1)
+ call feedkeys("i\<Insert>ZYX>", 'tnix')
+ call assert_equal(['ZYX>', 'def'], getline(1, '$'))
+ call setline(1, ['abc', 'def'])
+ call cursor(1, 1)
+ call feedkeys("i\<Insert>Z\<Insert>YX>", 'tnix')
+ call assert_equal(['ZYX>bc', 'def'], getline(1, '$'))
+ bw!
+endfunc
+
+func Test_edit_LEFT_RIGHT()
+ " Left, Shift-Left, Right, Shift-Right
+ new
+ call setline(1, ['abc def ghi', 'ABC DEF GHI', 'ZZZ YYY XXX'])
+ let _ww=&ww
+ set ww=
+ call cursor(2, 1)
+ call feedkeys("i\<left>\<esc>", 'tnix')
+ call assert_equal([0, 2, 1, 0], getpos('.'))
+ " Is this a bug, <s-left> does not respect whichwrap option
+ call feedkeys("i\<s-left>\<esc>", 'tnix')
+ call assert_equal([0, 1, 8, 0], getpos('.'))
+ call feedkeys("i". repeat("\<s-left>", 3). "\<esc>", 'tnix')
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+ call feedkeys("i\<right>\<esc>", 'tnix')
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+ call feedkeys("i\<right>\<right>\<esc>", 'tnix')
+ call assert_equal([0, 1, 2, 0], getpos('.'))
+ call feedkeys("A\<right>\<esc>", 'tnix')
+ call assert_equal([0, 1, 11, 0], getpos('.'))
+ call feedkeys("A\<s-right>\<esc>", 'tnix')
+ call assert_equal([0, 2, 1, 0], getpos('.'))
+ call feedkeys("i\<s-right>\<esc>", 'tnix')
+ call assert_equal([0, 2, 4, 0], getpos('.'))
+ call cursor(3, 11)
+ call feedkeys("A\<right>\<esc>", 'tnix')
+ call feedkeys("A\<s-right>\<esc>", 'tnix')
+ call assert_equal([0, 3, 11, 0], getpos('.'))
+ call cursor(2, 11)
+ " <S-Right> does not respect 'whichwrap' option
+ call feedkeys("A\<s-right>\<esc>", 'tnix')
+ call assert_equal([0, 3, 1, 0], getpos('.'))
+ " Check motion when 'whichwrap' contains cursor keys for insert mode
+ set ww+=[,]
+ call cursor(2, 1)
+ call feedkeys("i\<left>\<esc>", 'tnix')
+ call assert_equal([0, 1, 11, 0], getpos('.'))
+ call cursor(2, 11)
+ call feedkeys("A\<right>\<esc>", 'tnix')
+ call assert_equal([0, 3, 1, 0], getpos('.'))
+ call cursor(2, 11)
+ call feedkeys("A\<s-right>\<esc>", 'tnix')
+ call assert_equal([0, 3, 1, 0], getpos('.'))
+ let &ww = _ww
+ bw!
+endfunc
+
+func Test_edit_MOUSE()
+ " This is a simple test, since we not really using the mouse here
+ if !has("mouse")
+ return
+ endif
+ 10new
+ call setline(1, range(1, 100))
+ call cursor(1, 1)
+ set mouse=a
+ call feedkeys("A\<ScrollWheelDown>\<esc>", 'tnix')
+ call assert_equal([0, 4, 1, 0], getpos('.'))
+ " This should move by one pageDown, but only moves
+ " by one line when the test is run...
+ call feedkeys("A\<S-ScrollWheelDown>\<esc>", 'tnix')
+ call assert_equal([0, 5, 1, 0], getpos('.'))
+ set nostartofline
+ call feedkeys("A\<C-ScrollWheelDown>\<esc>", 'tnix')
+ call assert_equal([0, 6, 1, 0], getpos('.'))
+ call feedkeys("A\<LeftMouse>\<esc>", 'tnix')
+ call assert_equal([0, 6, 1, 0], getpos('.'))
+ call feedkeys("A\<RightMouse>\<esc>", 'tnix')
+ call assert_equal([0, 6, 1, 0], getpos('.'))
+ call cursor(1, 100)
+ norm! zt
+ " this should move by a screen up, but when the test
+ " is run, it moves up to the top of the buffer...
+ call feedkeys("A\<ScrollWheelUp>\<esc>", 'tnix')
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+ call cursor(1, 30)
+ norm! zt
+ call feedkeys("A\<S-ScrollWheelUp>\<esc>", 'tnix')
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+ call cursor(1, 30)
+ norm! zt
+ call feedkeys("A\<C-ScrollWheelUp>\<esc>", 'tnix')
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+ %d
+ call setline(1, repeat(["12345678901234567890"], 100))
+ call cursor(2, 1)
+ call feedkeys("A\<ScrollWheelRight>\<esc>", 'tnix')
+ call assert_equal([0, 2, 20, 0], getpos('.'))
+ call feedkeys("A\<ScrollWheelLeft>\<esc>", 'tnix')
+ call assert_equal([0, 2, 20, 0], getpos('.'))
+ call feedkeys("A\<S-ScrollWheelRight>\<esc>", 'tnix')
+ call assert_equal([0, 2, 20, 0], getpos('.'))
+ call feedkeys("A\<S-ScrollWheelLeft>\<esc>", 'tnix')
+ call assert_equal([0, 2, 20, 0], getpos('.'))
+ call feedkeys("A\<C-ScrollWheelRight>\<esc>", 'tnix')
+ call assert_equal([0, 2, 20, 0], getpos('.'))
+ call feedkeys("A\<C-ScrollWheelLeft>\<esc>", 'tnix')
+ call assert_equal([0, 2, 20, 0], getpos('.'))
+ set mouse& startofline
+ bw!
+endfunc
+
+func Test_edit_PAGEUP_PAGEDOWN()
+ 10new
+ call setline(1, repeat(['abc def ghi'], 30))
+ call cursor(1, 1)
+ call feedkeys("i\<PageDown>\<esc>", 'tnix')
+ call assert_equal([0, 9, 1, 0], getpos('.'))
+ call feedkeys("i\<PageDown>\<esc>", 'tnix')
+ call assert_equal([0, 17, 1, 0], getpos('.'))
+ call feedkeys("i\<PageDown>\<esc>", 'tnix')
+ call assert_equal([0, 25, 1, 0], getpos('.'))
+ call feedkeys("i\<PageDown>\<esc>", 'tnix')
+ call assert_equal([0, 30, 1, 0], getpos('.'))
+ call feedkeys("i\<PageDown>\<esc>", 'tnix')
+ call assert_equal([0, 30, 1, 0], getpos('.'))
+ call feedkeys("A\<PageUp>\<esc>", 'tnix')
+ call assert_equal([0, 29, 1, 0], getpos('.'))
+ call feedkeys("A\<PageUp>\<esc>", 'tnix')
+ call assert_equal([0, 21, 1, 0], getpos('.'))
+ call feedkeys("A\<PageUp>\<esc>", 'tnix')
+ call assert_equal([0, 13, 1, 0], getpos('.'))
+ call feedkeys("A\<PageUp>\<esc>", 'tnix')
+ call assert_equal([0, 5, 1, 0], getpos('.'))
+ call feedkeys("A\<PageUp>\<esc>", 'tnix')
+ call assert_equal([0, 5, 11, 0], getpos('.'))
+ " <S-Up> is the same as <PageUp>
+ " <S-Down> is the same as <PageDown>
+ call cursor(1, 1)
+ call feedkeys("i\<S-Down>\<esc>", 'tnix')
+ call assert_equal([0, 9, 1, 0], getpos('.'))
+ call feedkeys("i\<S-Down>\<esc>", 'tnix')
+ call assert_equal([0, 17, 1, 0], getpos('.'))
+ call feedkeys("i\<S-Down>\<esc>", 'tnix')
+ call assert_equal([0, 25, 1, 0], getpos('.'))
+ call feedkeys("i\<S-Down>\<esc>", 'tnix')
+ call assert_equal([0, 30, 1, 0], getpos('.'))
+ call feedkeys("i\<S-Down>\<esc>", 'tnix')
+ call assert_equal([0, 30, 1, 0], getpos('.'))
+ call feedkeys("A\<S-Up>\<esc>", 'tnix')
+ call assert_equal([0, 29, 1, 0], getpos('.'))
+ call feedkeys("A\<S-Up>\<esc>", 'tnix')
+ call assert_equal([0, 21, 1, 0], getpos('.'))
+ call feedkeys("A\<S-Up>\<esc>", 'tnix')
+ call assert_equal([0, 13, 1, 0], getpos('.'))
+ call feedkeys("A\<S-Up>\<esc>", 'tnix')
+ call assert_equal([0, 5, 1, 0], getpos('.'))
+ call feedkeys("A\<S-Up>\<esc>", 'tnix')
+ call assert_equal([0, 5, 11, 0], getpos('.'))
+ set nostartofline
+ call cursor(30, 11)
+ norm! zt
+ call feedkeys("A\<PageUp>\<esc>", 'tnix')
+ call assert_equal([0, 29, 11, 0], getpos('.'))
+ call feedkeys("A\<PageUp>\<esc>", 'tnix')
+ call assert_equal([0, 21, 11, 0], getpos('.'))
+ call feedkeys("A\<PageUp>\<esc>", 'tnix')
+ call assert_equal([0, 13, 11, 0], getpos('.'))
+ call feedkeys("A\<PageUp>\<esc>", 'tnix')
+ call assert_equal([0, 5, 11, 0], getpos('.'))
+ call feedkeys("A\<PageUp>\<esc>", 'tnix')
+ call assert_equal([0, 5, 11, 0], getpos('.'))
+ call cursor(1, 1)
+ call feedkeys("A\<PageDown>\<esc>", 'tnix')
+ call assert_equal([0, 9, 11, 0], getpos('.'))
+ call feedkeys("A\<PageDown>\<esc>", 'tnix')
+ call assert_equal([0, 17, 11, 0], getpos('.'))
+ call feedkeys("A\<PageDown>\<esc>", 'tnix')
+ call assert_equal([0, 25, 11, 0], getpos('.'))
+ call feedkeys("A\<PageDown>\<esc>", 'tnix')
+ call assert_equal([0, 30, 11, 0], getpos('.'))
+ call feedkeys("A\<PageDown>\<esc>", 'tnix')
+ call assert_equal([0, 30, 11, 0], getpos('.'))
+ " <S-Up> is the same as <PageUp>
+ " <S-Down> is the same as <PageDown>
+ call cursor(30, 11)
+ norm! zt
+ call feedkeys("A\<S-Up>\<esc>", 'tnix')
+ call assert_equal([0, 29, 11, 0], getpos('.'))
+ call feedkeys("A\<S-Up>\<esc>", 'tnix')
+ call assert_equal([0, 21, 11, 0], getpos('.'))
+ call feedkeys("A\<S-Up>\<esc>", 'tnix')
+ call assert_equal([0, 13, 11, 0], getpos('.'))
+ call feedkeys("A\<S-Up>\<esc>", 'tnix')
+ call assert_equal([0, 5, 11, 0], getpos('.'))
+ call feedkeys("A\<S-Up>\<esc>", 'tnix')
+ call assert_equal([0, 5, 11, 0], getpos('.'))
+ call cursor(1, 1)
+ call feedkeys("A\<S-Down>\<esc>", 'tnix')
+ call assert_equal([0, 9, 11, 0], getpos('.'))
+ call feedkeys("A\<S-Down>\<esc>", 'tnix')
+ call assert_equal([0, 17, 11, 0], getpos('.'))
+ call feedkeys("A\<S-Down>\<esc>", 'tnix')
+ call assert_equal([0, 25, 11, 0], getpos('.'))
+ call feedkeys("A\<S-Down>\<esc>", 'tnix')
+ call assert_equal([0, 30, 11, 0], getpos('.'))
+ call feedkeys("A\<S-Down>\<esc>", 'tnix')
+ call assert_equal([0, 30, 11, 0], getpos('.'))
+ bw!
+endfunc
+
+func Test_edit_forbidden()
+ new
+ " 1) edit in the sandbox is not allowed
+ call setline(1, 'a')
+ com! Sandbox :sandbox call feedkeys("i\<del>\<esc>", 'tnix')
+ call assert_fails(':Sandbox', 'E48:')
+ com! Sandbox :sandbox exe "norm! i\<del>"
+ call assert_fails(':Sandbox', 'E48:')
+ delcom Sandbox
+ call assert_equal(['a'], getline(1,'$'))
+ " 2) edit with textlock set
+ fu! DoIt()
+ call feedkeys("i\<del>\<esc>", 'tnix')
+ endfu
+ au InsertCharPre <buffer> :call DoIt()
+ try
+ call feedkeys("ix\<esc>", 'tnix')
+ call assert_fails(1, 'textlock')
+ catch /^Vim\%((\a\+)\)\=:E523/ " catch E523: not allowed here
+ endtry
+ " TODO: Might be a bug: should x really be inserted here
+ call assert_equal(['xa'], getline(1, '$'))
+ delfu DoIt
+ try
+ call feedkeys("ix\<esc>", 'tnix')
+ call assert_fails(1, 'unknown function')
+ catch /^Vim\%((\a\+)\)\=:E117/ " catch E117: unknown function
+ endtry
+ au! InsertCharPre
+ " 3) edit when completion is shown
+ fun! Complete(findstart, base)
+ if a:findstart
+ return col('.')
+ else
+ call feedkeys("i\<del>\<esc>", 'tnix')
+ return []
+ endif
+ endfun
+ set completefunc=Complete
+ try
+ call feedkeys("i\<c-x>\<c-u>\<esc>", 'tnix')
+ call assert_fails(1, 'change in complete function')
+ catch /^Vim\%((\a\+)\)\=:E523/ " catch E523
+ endtry
+ delfu Complete
+ set completefunc=
+ if has("rightleft") && exists("+fkmap")
+ " 4) 'R' when 'fkmap' and 'revins' is set.
+ set revins fkmap
+ try
+ normal Ri
+ call assert_fails(1, "R with 'fkmap' and 'ri' set")
+ catch
+ finally
+ set norevins nofkmap
+ endtry
+ endif
+ bw!
+endfunc
+
+func Test_edit_rightleft()
+ " Cursor in rightleft mode moves differently
+ if !exists("+rightleft")
+ return
+ endif
+ call NewWindow(10, 20)
+ call setline(1, ['abc', 'def', 'ghi'])
+ call cursor(1, 2)
+ set rightleft
+ " Screen looks as expected
+ let lines = ScreenLines([1, 4], winwidth(0))
+ let expect = [
+ \" cba",
+ \" fed",
+ \" ihg",
+ \" ~"]
+ call assert_equal(join(expect, "\n"), join(lines, "\n"))
+ " 2) right moves to the left
+ call feedkeys("i\<right>\<esc>x", 'txin')
+ call assert_equal(['bc', 'def', 'ghi'], getline(1,'$'))
+ call cursor(1, 2)
+ call feedkeys("i\<s-right>\<esc>", 'txin')
+ call cursor(1, 2)
+ call feedkeys("i\<c-right>\<esc>", 'txin')
+ " Screen looks as expected
+ let lines = ScreenLines([1, 4], winwidth(0))
+ let expect = [
+ \" cb",
+ \" fed",
+ \" ihg",
+ \" ~"]
+ call assert_equal(join(expect, "\n"), join(lines, "\n"))
+ " 2) left moves to the right
+ call setline(1, ['abc', 'def', 'ghi'])
+ call cursor(1, 2)
+ call feedkeys("i\<left>\<esc>x", 'txin')
+ call assert_equal(['ac', 'def', 'ghi'], getline(1,'$'))
+ call cursor(1, 2)
+ call feedkeys("i\<s-left>\<esc>", 'txin')
+ call cursor(1, 2)
+ call feedkeys("i\<c-left>\<esc>", 'txin')
+ " Screen looks as expected
+ let lines = ScreenLines([1, 4], winwidth(0))
+ let expect = [
+ \" ca",
+ \" fed",
+ \" ihg",
+ \" ~"]
+ call assert_equal(join(expect, "\n"), join(lines, "\n"))
+ set norightleft
+ bw!
+endfunc
+
+func Test_edit_complete_very_long_name()
+ if !has('unix')
+ " Long directory names only work on Unix.
+ return
+ endif
+
+ let dirname = getcwd() . "/Xdir"
+ let longdirname = dirname . repeat('/' . repeat('d', 255), 4)
+ try
+ call mkdir(longdirname, 'p')
+ catch /E739:/
+ " Long directory name probably not supported.
+ call delete(dirname, 'rf')
+ return
+ endtry
+
+ " Try to get the Vim window position before setting 'columns'.
+ let winposx = getwinposx()
+ let winposy = getwinposy()
+ let save_columns = &columns
+ " Need at least about 1100 columns to reproduce the problem.
+ set columns=2000
+ set noswapfile
+
+ let longfilename = longdirname . '/' . repeat('a', 255)
+ call writefile(['Totum', 'Table'], longfilename)
+ new
+ exe "next Xfile " . longfilename
+ exe "normal iT\<C-N>"
+
+ bwipe!
+ exe 'bwipe! ' . longfilename
+ call delete(dirname, 'rf')
+ let &columns = save_columns
+ if winposx >= 0 && winposy >= 0
+ exe 'winpos ' . winposx . ' ' . winposy
+ endif
+ set swapfile&
+endfunc
+
+func Test_edit_backtick()
+ next a\`b c
+ call assert_equal('a`b', expand('%'))
+ next
+ call assert_equal('c', expand('%'))
+ call assert_equal('a\`b c', expand('##'))
+endfunc
+
+func Test_edit_quit()
+ edit foo.txt
+ split
+ new
+ call setline(1, 'hello')
+ 3wincmd w
+ redraw!
+ call assert_fails('1q', 'E37:')
+ bwipe! foo.txt
+ only
+endfunc
+
+func Test_edit_alt()
+ " Keeping the cursor line didn't happen when the first line has indent.
+ new
+ call setline(1, [' one', 'two', 'three'])
+ w XAltFile
+ $
+ call assert_equal(3, line('.'))
+ e Xother
+ e #
+ call assert_equal(3, line('.'))
+
+ bwipe XAltFile
+ call delete('XAltFile')
+endfunc
+
+func Test_leave_insert_autocmd()
+ new
+ au InsertLeave * let g:did_au = 1
+ let g:did_au = 0
+ call feedkeys("afoo\<Esc>", 'tx')
+ call assert_equal(1, g:did_au)
+ call assert_equal('foo', getline(1))
+
+ let g:did_au = 0
+ call feedkeys("Sbar\<C-C>", 'tx')
+ call assert_equal(0, g:did_au)
+ call assert_equal('bar', getline(1))
+
+ inoremap x xx<Esc>
+ let g:did_au = 0
+ call feedkeys("Saax", 'tx')
+ call assert_equal(1, g:did_au)
+ call assert_equal('aaxx', getline(1))
+
+ inoremap x xx<C-C>
+ let g:did_au = 0
+ call feedkeys("Sbbx", 'tx')
+ call assert_equal(0, g:did_au)
+ call assert_equal('bbxx', getline(1))
+
+ bwipe!
+ au! InsertLeave
+ iunmap x
+endfunc
diff --git a/src/testdir/test_erasebackword.vim b/src/testdir/test_erasebackword.vim
new file mode 100644
index 0000000..9522ec2
--- /dev/null
+++ b/src/testdir/test_erasebackword.vim
@@ -0,0 +1,19 @@
+
+func Test_erasebackword()
+ enew
+
+ exe "normal o wwwã“ã‚“ã«ã¡ã‚世界ワールドvim \<C-W>"
+ call assert_equal(' wwwã“ã‚“ã«ã¡ã‚世界ワールド', getline('.'))
+ exe "normal o wwwã“ã‚“ã«ã¡ã‚世界ワールドvim \<C-W>\<C-W>"
+ call assert_equal(' wwwã“ã‚“ã«ã¡ã‚世界', getline('.'))
+ exe "normal o wwwã“ã‚“ã«ã¡ã‚世界ワールドvim \<C-W>\<C-W>\<C-W>"
+ call assert_equal(' wwwã“ã‚“ã«ã¡ã‚', getline('.'))
+ exe "normal o wwwã“ã‚“ã«ã¡ã‚世界ワールドvim \<C-W>\<C-W>\<C-W>\<C-W>"
+ call assert_equal(' www', getline('.'))
+ exe "normal o wwwã“ã‚“ã«ã¡ã‚世界ワールドvim \<C-W>\<C-W>\<C-W>\<C-W>\<C-W>"
+ call assert_equal(' ', getline('.'))
+ exe "normal o wwwã“ã‚“ã«ã¡ã‚世界ワールドvim \<C-W>\<C-W>\<C-W>\<C-W>\<C-W>\<C-W>"
+ call assert_equal('', getline('.'))
+
+ enew!
+endfunc
diff --git a/src/testdir/test_escaped_glob.vim b/src/testdir/test_escaped_glob.vim
new file mode 100644
index 0000000..880f32e
--- /dev/null
+++ b/src/testdir/test_escaped_glob.vim
@@ -0,0 +1,33 @@
+" Test whether glob()/globpath() return correct results with certain escaped
+" characters.
+
+function SetUp()
+ " consistent sorting of file names
+ set nofileignorecase
+endfunction
+
+function Test_glob()
+ if !has('unix')
+ " This test fails on Windows because of the special characters in the
+ " filenames. Disable the test on non-Unix systems for now.
+ return
+ endif
+
+ " Execute these commands in the sandbox, so that using the shell fails.
+ " Setting 'shell' to an invalid name causes a memory leak.
+ sandbox call assert_equal("", glob('Xxx\{'))
+ sandbox call assert_equal("", glob('Xxx\$'))
+ w! Xxx{
+ w! Xxx\$
+ sandbox call assert_equal("Xxx{", glob('Xxx\{'))
+ sandbox call assert_equal("Xxx$", glob('Xxx\$'))
+ call delete('Xxx{')
+ call delete('Xxx$')
+endfunction
+
+function Test_globpath()
+ sandbox call assert_equal("sautest/autoload/globone.vim\nsautest/autoload/globtwo.vim",
+ \ globpath('sautest/autoload', 'glob*.vim'))
+ sandbox call assert_equal(['sautest/autoload/globone.vim', 'sautest/autoload/globtwo.vim'],
+ \ globpath('sautest/autoload', 'glob*.vim', 0, 1))
+endfunction
diff --git a/src/testdir/test_eval.in b/src/testdir/test_eval.in
new file mode 100644
index 0000000..3b61442
--- /dev/null
+++ b/src/testdir/test_eval.in
@@ -0,0 +1,249 @@
+Test for various eval features. vim: set ft=vim :
+
+NOTE: Do not add more here, use new style test test_eval_stuff.vim
+
+Note: system clipboard is saved, changed and restored.
+
+clipboard contents
+something else
+
+STARTTEST
+:so small.vim
+:set encoding=latin1
+:set noswapfile
+:lang C
+:fun AppendRegContents(reg)
+ call AppendRegParts(a:reg, getregtype(a:reg), getreg(a:reg), string(getreg(a:reg, 0, 1)), getreg(a:reg, 1), string(getreg(a:reg, 1, 1)))
+:endfun
+:fun AppendRegParts(reg, type, cont, strcont, cont1, strcont1)
+ call append('$', printf('%s: type %s; value: %s (%s), expr: %s (%s)', a:reg, a:type, a:cont, a:strcont, a:cont1, a:strcont1))
+endfun
+:command -nargs=? AR :call AppendRegContents(<q-args>)
+:fun SetReg(...)
+ call call('setreg', a:000)
+ call append('$', printf('{{{2 setreg(%s)', string(a:000)[1:-2]))
+ call AppendRegContents(a:1)
+ if a:1 isnot# '='
+ execute "silent normal! Go==\n==\e\"".a:1."P"
+ endif
+endfun
+:fun ErrExe(str)
+ call append('$', 'Executing '.a:str)
+ try
+ execute a:str
+ catch
+ $put =v:exception
+ endtry
+endfun
+:fun Test()
+$put ='{{{1 let tests'
+let @" = 'abc'
+AR "
+let @" = "abc\n"
+AR "
+let @" = "abc\<C-m>"
+AR "
+let @= = '"abc"'
+AR =
+
+$put ='{{{1 Basic setreg tests'
+call SetReg('a', 'abcA', 'c')
+call SetReg('b', 'abcB', 'v')
+call SetReg('c', 'abcC', 'l')
+call SetReg('d', 'abcD', 'V')
+call SetReg('e', 'abcE', 'b')
+call SetReg('f', 'abcF', "\<C-v>")
+call SetReg('g', 'abcG', 'b10')
+call SetReg('h', 'abcH', "\<C-v>10")
+call SetReg('I', 'abcI')
+
+$put ='{{{1 Appending single lines with setreg()'
+call SetReg('A', 'abcAc', 'c')
+call SetReg('A', 'abcAl', 'l')
+call SetReg('A', 'abcAc2','c')
+call SetReg('b', 'abcBc', 'ca')
+call SetReg('b', 'abcBb', 'ba')
+call SetReg('b', 'abcBc2','ca')
+call SetReg('b', 'abcBb2','b50a')
+
+call SetReg('C', 'abcCl', 'l')
+call SetReg('C', 'abcCc', 'c')
+call SetReg('D', 'abcDb', 'b')
+
+call SetReg('E', 'abcEb', 'b')
+call SetReg('E', 'abcEl', 'l')
+call SetReg('F', 'abcFc', 'c')
+
+$put ='{{{1 Appending NL with setreg()'
+call setreg('a', 'abcA2', 'c')
+call setreg('b', 'abcB2', 'v')
+call setreg('c', 'abcC2', 'l')
+call setreg('d', 'abcD2', 'V')
+call setreg('e', 'abcE2', 'b')
+call setreg('f', 'abcF2', "\<C-v>")
+call setreg('g', 'abcG2', 'b10')
+call setreg('h', 'abcH2', "\<C-v>10")
+call setreg('I', 'abcI2')
+
+call SetReg('A', "\n")
+call SetReg('B', "\n", 'c')
+call SetReg('C', "\n")
+call SetReg('D', "\n", 'l')
+call SetReg('E', "\n")
+call SetReg('F', "\n", 'b')
+
+$put ='{{{1 Setting lists with setreg()'
+call SetReg('a', ['abcA3'], 'c')
+call SetReg('b', ['abcB3'], 'l')
+call SetReg('c', ['abcC3'], 'b')
+call SetReg('d', ['abcD3'])
+call SetReg('e', [1, 2, 'abc', 3])
+call SetReg('f', [1, 2, 3])
+
+$put ='{{{1 Appending lists with setreg()'
+call SetReg('A', ['abcA3c'], 'c')
+call SetReg('b', ['abcB3l'], 'la')
+call SetReg('C', ['abcC3b'], 'lb')
+call SetReg('D', ['abcD32'])
+
+call SetReg('A', ['abcA32'])
+call SetReg('B', ['abcB3c'], 'c')
+call SetReg('C', ['abcC3l'], 'l')
+call SetReg('D', ['abcD3b'], 'b')
+
+$put ='{{{1 Appending lists with NL with setreg()'
+call SetReg('A', ["\n", 'abcA3l2'], 'l')
+call SetReg('B', ["\n", 'abcB3c2'], 'c')
+call SetReg('C', ["\n", 'abcC3b2'], 'b')
+call SetReg('D', ["\n", 'abcD3b50'],'b50')
+
+$put ='{{{1 Setting lists with NLs with setreg()'
+call SetReg('a', ['abcA4-0', "\n", "abcA4-2\n", "\nabcA4-3", "abcA4-4\nabcA4-4-2"])
+call SetReg('b', ['abcB4c-0', "\n", "abcB4c-2\n", "\nabcB4c-3", "abcB4c-4\nabcB4c-4-2"], 'c')
+call SetReg('c', ['abcC4l-0', "\n", "abcC4l-2\n", "\nabcC4l-3", "abcC4l-4\nabcC4l-4-2"], 'l')
+call SetReg('d', ['abcD4b-0', "\n", "abcD4b-2\n", "\nabcD4b-3", "abcD4b-4\nabcD4b-4-2"], 'b')
+call SetReg('e', ['abcE4b10-0', "\n", "abcE4b10-2\n", "\nabcE4b10-3", "abcE4b10-4\nabcE4b10-4-2"], 'b10')
+
+$put ='{{{1 Search and expressions'
+call SetReg('/', ['abc/'])
+call SetReg('/', ["abc/\n"])
+call SetReg('=', ['"abc/"'])
+call SetReg('=', ["\"abc/\n\""])
+$put ='{{{1 System clipboard'
+if has('clipboard')
+" Save and restore system clipboard.
+" If no connection to X-Server is possible, test should succeed.
+let _clipreg = ['*', getreg('*'), getregtype('*')]
+let _clipopt = &cb
+let &cb='unnamed'
+7y
+AR *
+tabdo :windo :echo "hi"
+8y
+AR *
+let &cb=_clipopt
+call call('setreg', _clipreg)
+else
+ call AppendRegParts('*', 'V', "clipboard contents\n", "['clipboard contents']", "clipboard contents\n", "['clipboard contents']")
+ call AppendRegParts('*', 'V', "something else\n", "['something else']", "something else\n", "['something else']")
+endif
+$put ='{{{1 Errors'
+call ErrExe('call setreg()')
+call ErrExe('call setreg(1)')
+call ErrExe('call setreg(1, 2, 3, 4)')
+call ErrExe('call setreg([], 2)')
+call ErrExe('call setreg(1, {})')
+call ErrExe('call setreg(1, 2, [])')
+call ErrExe('call setreg("/", ["1", "2"])')
+call ErrExe('call setreg("=", ["1", "2"])')
+call ErrExe('call setreg(1, ["", "", [], ""])')
+endfun
+:"
+:call Test()
+:"
+:delfunction SetReg
+:delfunction AppendRegContents
+:delfunction ErrExe
+:delfunction Test
+:delcommand AR
+:call garbagecollect(1)
+:"
+:" function name not starting with capital
+:try
+:func! g:test()
+:echo "test"
+:endfunc
+:catch
+:$put =v:exception
+:endtry
+:"
+:" function name includes a colon
+:try
+:func! b:test()
+:echo "test"
+:endfunc
+:catch
+:$put =v:exception
+:endtry
+:"
+:" function name folowed by #
+:try
+:func! test2() "#
+:echo "test2"
+:endfunc
+:catch
+:$put =v:exception
+:endtry
+:"
+:" function name starting with/without "g:", buffer-local funcref.
+:function! g:Foo(n)
+: $put ='called Foo(' . a:n . ')'
+:endfunction
+:let b:my_func = function('Foo')
+:call b:my_func(1)
+:echo g:Foo(2)
+:echo Foo(3)
+:"
+:" script-local function used in Funcref must exist.
+:so test_eval_func.vim
+:"
+:" Using $ instead of '$' must give an error
+:try
+: call append($, 'foobar')
+:catch
+:$put =v:exception
+:endtry
+:"
+:$put ='{{{1 getcurpos/setpos'
+/^012345678
+6l:let sp = getcurpos()
+0:call setpos('.', sp)
+jyl:$put
+:"
+:" substring and variable name
+:let str = 'abcdef'
+:let n = 3
+:$put =str[n:]
+:$put =str[:n]
+:$put =str[n:n]
+:unlet n
+:let nn = 3
+:$put =str[nn:]
+:$put =str[:nn]
+:$put =str[nn:nn]
+:unlet nn
+:let b:nn = 4
+:$put =str[b:nn:]
+:$put =str[:b:nn]
+:$put =str[b:nn:b:nn]
+:unlet b:nn
+:"
+:/^start:/+1,$wq! test.out
+:" vim: et ts=4 isk-=\: fmr=???,???
+:call getchar()
+ENDTEST
+
+012345678
+012345678
+
+start:
diff --git a/src/testdir/test_eval.ok b/src/testdir/test_eval.ok
new file mode 100644
index 0000000..9ffa541
--- /dev/null
+++ b/src/testdir/test_eval.ok
Binary files differ
diff --git a/src/testdir/test_eval_func.vim b/src/testdir/test_eval_func.vim
new file mode 100644
index 0000000..09d2f62
--- /dev/null
+++ b/src/testdir/test_eval_func.vim
@@ -0,0 +1,10 @@
+" Vim script used in test_eval.in. Needed for script-local function.
+
+func s:Testje()
+ return "foo"
+endfunc
+let Bar = function('s:Testje')
+$put ='s:Testje exists: ' . exists('s:Testje')
+$put ='func s:Testje exists: ' . exists('*s:Testje')
+$put ='Bar exists: ' . exists('Bar')
+$put ='func Bar exists: ' . exists('*Bar')
diff --git a/src/testdir/test_eval_stuff.vim b/src/testdir/test_eval_stuff.vim
new file mode 100644
index 0000000..f4b3598
--- /dev/null
+++ b/src/testdir/test_eval_stuff.vim
@@ -0,0 +1,96 @@
+" Tests for various eval things.
+
+function s:foo() abort
+ try
+ return [] == 0
+ catch
+ return 1
+ endtry
+endfunction
+
+func Test_catch_return_with_error()
+ call assert_equal(1, s:foo())
+endfunc
+
+func Test_nocatch_restore_silent_emsg()
+ silent! try
+ throw 1
+ catch
+ endtry
+ echoerr 'wrong'
+ let c1 = nr2char(screenchar(&lines, 1))
+ let c2 = nr2char(screenchar(&lines, 2))
+ let c3 = nr2char(screenchar(&lines, 3))
+ let c4 = nr2char(screenchar(&lines, 4))
+ let c5 = nr2char(screenchar(&lines, 5))
+ call assert_equal('wrong', c1 . c2 . c3 . c4 . c5)
+endfunc
+
+func Test_mkdir_p()
+ call mkdir('Xmkdir/nested', 'p')
+ call assert_true(isdirectory('Xmkdir/nested'))
+ try
+ " Trying to make existing directories doesn't error
+ call mkdir('Xmkdir', 'p')
+ call mkdir('Xmkdir/nested', 'p')
+ catch /E739:/
+ call assert_report('mkdir(..., "p") failed for an existing directory')
+ endtry
+ " 'p' doesn't suppress real errors
+ call writefile([], 'Xfile')
+ call assert_fails('call mkdir("Xfile", "p")', 'E739')
+ call delete('Xfile')
+ call delete('Xmkdir', 'rf')
+endfunc
+
+func Test_line_continuation()
+ let array = [5,
+ "\ ignore this
+ \ 6,
+ "\ more to ignore
+ "\ more moreto ignore
+ \ ]
+ "\ and some more
+ call assert_equal([5, 6], array)
+endfunc
+
+func Test_E963()
+ " These commands used to cause an internal error prior to vim 8.1.0563
+ let v_e = v:errors
+ let v_o = v:oldfiles
+ call assert_fails("let v:errors=''", 'E963:')
+ call assert_equal(v_e, v:errors)
+ call assert_fails("let v:oldfiles=''", 'E963:')
+ call assert_equal(v_o, v:oldfiles)
+endfunc
+
+func Test_for_invalid()
+ call assert_fails("for x in 99", 'E714:')
+ call assert_fails("for x in 'asdf'", 'E714:')
+ call assert_fails("for x in {'a': 9}", 'E714:')
+endfunc
+
+func Test_readfile_binary()
+ new
+ call setline(1, ['one', 'two', 'three'])
+ setlocal ff=dos
+ write XReadfile
+ let lines = readfile('XReadfile')
+ call assert_equal(['one', 'two', 'three'], lines)
+ let lines = readfile('XReadfile', '', 2)
+ call assert_equal(['one', 'two'], lines)
+ let lines = readfile('XReadfile', 'b')
+ call assert_equal(["one\r", "two\r", "three\r", ""], lines)
+ let lines = readfile('XReadfile', 'b', 2)
+ call assert_equal(["one\r", "two\r"], lines)
+
+ bwipe!
+ call delete('XReadfile')
+endfunc
+
+func Test_let_errmsg()
+ call assert_fails('let v:errmsg = []', 'E730:')
+ let v:errmsg = ''
+ call assert_fails('let v:errmsg = []', 'E730:')
+ let v:errmsg = ''
+endfunc
diff --git a/src/testdir/test_ex_equal.vim b/src/testdir/test_ex_equal.vim
new file mode 100644
index 0000000..05ad276
--- /dev/null
+++ b/src/testdir/test_ex_equal.vim
@@ -0,0 +1,32 @@
+" Test Ex := command.
+
+func Test_ex_equal()
+ new
+ call setline(1, ["foo\tbar", "bar\tfoo"])
+
+ let a = execute('=')
+ call assert_equal("\n2", a)
+
+ let a = execute('=#')
+ call assert_equal("\n2\n 1 foo bar", a)
+
+ let a = execute('=l')
+ call assert_equal("\n2\nfoo^Ibar$", a)
+
+ let a = execute('=p')
+ call assert_equal("\n2\nfoo bar", a)
+
+ let a = execute('=l#')
+ call assert_equal("\n2\n 1 foo^Ibar$", a)
+
+ let a = execute('=p#')
+ call assert_equal("\n2\n 1 foo bar", a)
+
+ let a = execute('.=')
+ call assert_equal("\n1", a)
+
+ call assert_fails('3=', 'E16:')
+ call assert_fails('=x', 'E488:')
+
+ bwipe!
+endfunc
diff --git a/src/testdir/test_ex_undo.vim b/src/testdir/test_ex_undo.vim
new file mode 100644
index 0000000..44feb36
--- /dev/null
+++ b/src/testdir/test_ex_undo.vim
@@ -0,0 +1,19 @@
+" Tests for :undo
+
+func Test_ex_undo()
+ new ex-undo
+ setlocal ul=10
+ exe "normal ione\n\<Esc>"
+ setlocal ul=10
+ exe "normal itwo\n\<Esc>"
+ setlocal ul=10
+ exe "normal ithree\n\<Esc>"
+ call assert_equal(4, line('$'))
+ undo
+ call assert_equal(3, line('$'))
+ undo 1
+ call assert_equal(2, line('$'))
+ undo 0
+ call assert_equal(1, line('$'))
+ quit!
+endfunc
diff --git a/src/testdir/test_ex_z.vim b/src/testdir/test_ex_z.vim
new file mode 100644
index 0000000..6e03b0b
--- /dev/null
+++ b/src/testdir/test_ex_z.vim
@@ -0,0 +1,85 @@
+" Test :z
+
+func Test_z()
+ call setline(1, range(1, 100))
+
+ let a = execute('20z3')
+ call assert_equal("\n20\n21\n22", a)
+ call assert_equal(22, line('.'))
+ " 'window' should be set to the {count} value.
+ call assert_equal(3, &window)
+
+ " If there is only one window, then twice the amount of 'scroll' is used.
+ set scroll=2
+ let a = execute('20z')
+ call assert_equal("\n20\n21\n22\n23", a)
+ call assert_equal(23, line('.'))
+
+ let a = execute('20z+3')
+ " FIXME: I would expect the same result as '20z3' but it
+ " gives "\n21\n22\n23" instead. Bug in Vim or in ":help :z"?
+ "call assert_equal("\n20\n21\n22", a)
+ "call assert_equal(22, line('.'))
+
+ let a = execute('20z-3')
+ call assert_equal("\n18\n19\n20", a)
+ call assert_equal(20, line('.'))
+
+ let a = execute('20z=3')
+ call assert_match("^\n18\n19\n-\\+\n20\n-\\+\n21\n22$", a)
+ call assert_equal(20, line('.'))
+
+ let a = execute('20z^3')
+ call assert_equal("\n14\n15\n16\n17", a)
+ call assert_equal(17, line('.'))
+
+ let a = execute('20z.3')
+ call assert_equal("\n19\n20\n21", a)
+ call assert_equal(21, line('.'))
+
+ let a = execute('20z#3')
+ call assert_equal("\n 20 20\n 21 21\n 22 22", a)
+ call assert_equal(22, line('.'))
+
+ let a = execute('20z#-3')
+ call assert_equal("\n 18 18\n 19 19\n 20 20", a)
+ call assert_equal(20, line('.'))
+
+ let a = execute('20z#=3')
+ call assert_match("^\n 18 18\n 19 19\n-\\+\n 20 20\n-\\+\n 21 21\n 22 22$", a)
+ call assert_equal(20, line('.'))
+
+ " Test with {count} bigger than the number of lines in buffer.
+ let a = execute('20z1000')
+ call assert_match("^\n20\n21\n.*\n99\n100$", a)
+ call assert_equal(100, line('.'))
+
+ let a = execute('20z-1000')
+ call assert_match("^\n1\n2\n.*\n19\n20$", a)
+ call assert_equal(20, line('.'))
+
+ let a = execute('20z=1000')
+ call assert_match("^\n1\n.*\n-\\+\n20\n-\\\+\n.*\n100$", a)
+ call assert_equal(20, line('.'))
+
+ call assert_fails('20z=a', 'E144:')
+
+ set window& scroll&
+ bw!
+endfunc
+
+func Test_z_overflow()
+ " This used to access invalid memory as a result of an integer overflow
+ " and freeze vim.
+ normal ox
+ normal Heat
+ z777777776666666
+ ')
+endfunc
+
+func Test_z_negative_lnum()
+ new
+ z^
+ call assert_equal(1, line('.'))
+ bwipe!
+endfunc
diff --git a/src/testdir/test_exec_while_if.vim b/src/testdir/test_exec_while_if.vim
new file mode 100644
index 0000000..d6afabf
--- /dev/null
+++ b/src/testdir/test_exec_while_if.vim
@@ -0,0 +1,53 @@
+" Test for :execute, :while and :if
+
+function Test_exec_while_if()
+ new
+
+ let i = 0
+ while i < 12
+ let i = i + 1
+ if has("ebcdic")
+ execute "normal o" . i . "\047"
+ else
+ execute "normal o" . i . "\033"
+ endif
+ if i % 2
+ normal Ax
+ if i == 9
+ break
+ endif
+ if i == 5
+ continue
+ else
+ let j = 9
+ while j > 0
+ if has("ebcdic")
+ execute "normal" j . "a" . j . "\x27"
+ else
+ execute "normal" j . "a" . j . "\x1b"
+ endif
+ let j = j - 1
+ endwhile
+ endif
+ endif
+ if i == 9
+ if has("ebcdic")
+ execute "normal Az\047"
+ else
+ execute "normal Az\033"
+ endif
+ endif
+ endwhile
+ unlet i j
+
+ call assert_equal(["",
+ \ "1x999999999888888887777777666666555554444333221",
+ \ "2",
+ \ "3x999999999888888887777777666666555554444333221",
+ \ "4",
+ \ "5x",
+ \ "6",
+ \ "7x999999999888888887777777666666555554444333221",
+ \ "8",
+ \ "9x"], getline(1, 10))
+endfunction
diff --git a/src/testdir/test_execute_func.vim b/src/testdir/test_execute_func.vim
new file mode 100644
index 0000000..b84fbeb
--- /dev/null
+++ b/src/testdir/test_execute_func.vim
@@ -0,0 +1,80 @@
+" test execute()
+
+func NestedEval()
+ let nested = execute('echo "nested\nlines"')
+ echo 'got: "' . nested . '"'
+endfunc
+
+func NestedRedir()
+ redir => var
+ echo 'broken'
+ redir END
+endfunc
+
+func Test_execute_string()
+ call assert_equal("\nnocompatible", execute('set compatible?'))
+ call assert_equal("\nsomething\nnice", execute('echo "something\nnice"'))
+ call assert_equal("noendofline", execute('echon "noendofline"'))
+ call assert_equal("", execute(123))
+
+ call assert_equal("\ngot: \"\nnested\nlines\"", execute('call NestedEval()'))
+ redir => redired
+ echo 'this'
+ let evaled = execute('echo "that"')
+ echo 'theend'
+ redir END
+ call assert_equal("\nthis\ntheend", redired)
+ call assert_equal("\nthat", evaled)
+
+ call assert_fails('call execute("doesnotexist")', 'E492:')
+ call assert_fails('call execute(3.4)', 'E806:')
+ call assert_fails('call execute("call NestedRedir()")', 'E930:')
+
+ call assert_equal("\nsomething", execute('echo "something"', ''))
+ call assert_equal("\nsomething", execute('echo "something"', 'silent'))
+ call assert_equal("\nsomething", execute('echo "something"', 'silent!'))
+ call assert_equal("", execute('burp', 'silent!'))
+ call assert_fails('call execute("echo \"x\"", 3.4)', 'E806:')
+
+ call assert_equal("", execute(test_null_string()))
+endfunc
+
+func Test_execute_list()
+ call assert_equal("\nsomething\nnice", execute(['echo "something"', 'echo "nice"']))
+ let l = ['for n in range(0, 3)',
+ \ 'echo n',
+ \ 'endfor']
+ call assert_equal("\n0\n1\n2\n3", execute(l))
+
+ call assert_equal("", execute([]))
+ call assert_equal("", execute(test_null_list()))
+endfunc
+
+func Test_execute_does_not_change_col()
+ echo ''
+ echon 'abcd'
+ let x = execute('silent echo 234343')
+ echon 'xyz'
+ let text = ''
+ for col in range(1, 7)
+ let text .= nr2char(screenchar(&lines, col))
+ endfor
+ call assert_equal('abcdxyz', text)
+endfunc
+
+func Test_execute_not_silent()
+ echo ''
+ echon 'abcd'
+ let x = execute('echon 234', '')
+ echo 'xyz'
+ let text1 = ''
+ for col in range(1, 8)
+ let text1 .= nr2char(screenchar(&lines - 1, col))
+ endfor
+ call assert_equal('abcd234 ', text1)
+ let text2 = ''
+ for col in range(1, 4)
+ let text2 .= nr2char(screenchar(&lines, col))
+ endfor
+ call assert_equal('xyz ', text2)
+endfunc
diff --git a/src/testdir/test_exists.vim b/src/testdir/test_exists.vim
new file mode 100644
index 0000000..fd34be8
--- /dev/null
+++ b/src/testdir/test_exists.vim
@@ -0,0 +1,321 @@
+" Tests for the exists() function
+func Test_exists()
+ augroup myagroup
+ autocmd! BufEnter *.my echo "myfile edited"
+ autocmd! FuncUndefined UndefFun exec "fu UndefFun()\nendfu"
+ augroup END
+ set rtp+=./sautest
+
+ " valid autocmd group
+ call assert_equal(1, exists('#myagroup'))
+ " valid autocmd group with garbage
+ call assert_equal(0, exists('#myagroup+b'))
+ " Valid autocmd group and event
+ call assert_equal(1, exists('#myagroup#BufEnter'))
+ " Valid autocmd group, event and pattern
+ call assert_equal(1, exists('#myagroup#BufEnter#*.my'))
+ " Valid autocmd event
+ call assert_equal(1, exists('#BufEnter'))
+ " Valid autocmd event and pattern
+ call assert_equal(1, exists('#BufEnter#*.my'))
+ " Non-existing autocmd group or event
+ call assert_equal(0, exists('#xyzagroup'))
+ " Non-existing autocmd group and valid autocmd event
+ call assert_equal(0, exists('#xyzagroup#BufEnter'))
+ " Valid autocmd group and event with no matching pattern
+ call assert_equal(0, exists('#myagroup#CmdwinEnter'))
+ " Valid autocmd group and non-existing autocmd event
+ call assert_equal(0, exists('#myagroup#xyzacmd'))
+ " Valid autocmd group and event and non-matching pattern
+ call assert_equal(0, exists('#myagroup#BufEnter#xyzpat'))
+ " Valid autocmd event and non-matching pattern
+ call assert_equal(0, exists('#BufEnter#xyzpat'))
+ " Empty autocmd group, event and pattern
+ call assert_equal(0, exists('###'))
+ " Empty autocmd group and event or empty event and pattern
+ call assert_equal(0, exists('##'))
+ " Valid autocmd event
+ call assert_equal(1, exists('##FileReadCmd'))
+ " Non-existing autocmd event
+ call assert_equal(0, exists('##MySpecialCmd'))
+
+ " Existing and working option (long form)
+ call assert_equal(1, exists('&textwidth'))
+ " Existing and working option (short form)
+ call assert_equal(1, exists('&tw'))
+ " Existing and working option with garbage
+ call assert_equal(0, exists('&tw-'))
+ " Global option
+ call assert_equal(1, exists('&g:errorformat'))
+ " Local option
+ call assert_equal(1, exists('&l:errorformat'))
+ " Negative form of existing and working option (long form)
+ call assert_equal(0, exists('&nojoinspaces'))
+ " Negative form of existing and working option (short form)
+ call assert_equal(0, exists('&nojs'))
+ " Non-existing option
+ call assert_equal(0, exists('&myxyzoption'))
+
+ " Existing and working option (long form)
+ call assert_equal(1, exists('+incsearch'))
+ " Existing and working option with garbage
+ call assert_equal(0, exists('+incsearch!1'))
+ " Existing and working option (short form)
+ call assert_equal(1, exists('+is'))
+ " Existing option that is hidden.
+ call assert_equal(0, exists('+autoprint'))
+
+ " Existing environment variable
+ let $EDITOR_NAME = 'Vim Editor'
+ call assert_equal(1, exists('$EDITOR_NAME'))
+ " Non-existing environment variable
+ call assert_equal(0, exists('$NON_ENV_VAR'))
+
+ " Valid internal function
+ call assert_equal(1, exists('*bufnr'))
+ " Valid internal function with ()
+ call assert_equal(1, exists('*bufnr()'))
+ " Non-existing internal function
+ call assert_equal(0, exists('*myxyzfunc'))
+ " Valid internal function with garbage
+ call assert_equal(0, exists('*bufnr&6'))
+ " Valid user defined function
+ call assert_equal(1, exists('*Test_exists'))
+ " Non-existing user defined function
+ call assert_equal(0, exists('*MyxyzFunc'))
+ " Function that may be created by FuncUndefined event
+ call assert_equal(0, exists('*UndefFun'))
+ " Function that may be created by script autoloading
+ call assert_equal(0, exists('*footest#F'))
+
+ " Valid internal command (full match)
+ call assert_equal(2, exists(':edit'))
+ " Valid internal command (full match) with garbage
+ call assert_equal(0, exists(':edit/a'))
+ " Valid internal command (partial match)
+ call assert_equal(1, exists(':q'))
+ " Non-existing internal command
+ call assert_equal(0, exists(':invalidcmd'))
+
+ " User defined command (full match)
+ command! MyCmd :echo 'My command'
+ call assert_equal(2, exists(':MyCmd'))
+ " User defined command (partial match)
+ command! MyOtherCmd :echo 'Another command'
+ call assert_equal(3, exists(':My'))
+
+ " Command modifier
+ call assert_equal(2, exists(':rightbelow'))
+
+ " Non-existing user defined command (full match)
+ delcommand MyCmd
+ call assert_equal(0, exists(':MyCmd'))
+
+ " Non-existing user defined command (partial match)
+ delcommand MyOtherCmd
+ call assert_equal(0, exists(':My'))
+
+ " Valid local variable
+ let local_var = 1
+ call assert_equal(1, exists('local_var'))
+ " Valid local variable with garbage
+ call assert_equal(0, exists('local_var%n'))
+ " Non-existing local variable
+ unlet local_var
+ call assert_equal(0, exists('local_var'))
+
+ " Non-existing autoload variable that may be autoloaded
+ call assert_equal(0, exists('footest#x'))
+
+ " Valid local list
+ let local_list = ["blue", "orange"]
+ call assert_equal(1, exists('local_list'))
+ " Valid local list item
+ call assert_equal(1, exists('local_list[1]'))
+ " Valid local list item with garbage
+ call assert_equal(0, exists('local_list[1]+5'))
+ " Invalid local list item
+ call assert_equal(0, exists('local_list[2]'))
+ " Non-existing local list
+ unlet local_list
+ call assert_equal(0, exists('local_list'))
+ " Valid local dictionary
+ let local_dict = {"xcord":100, "ycord":2}
+ call assert_equal(1, exists('local_dict'))
+ " Non-existing local dictionary
+ unlet local_dict
+ call assert_equal(0, exists('local_dict'))
+ " Existing local curly-brace variable
+ let str = "local"
+ let curly_{str}_var = 1
+ call assert_equal(1, exists('curly_{str}_var'))
+ " Non-existing local curly-brace variable
+ unlet curly_{str}_var
+ call assert_equal(0, exists('curly_{str}_var'))
+
+ " Existing global variable
+ let g:global_var = 1
+ call assert_equal(1, exists('g:global_var'))
+ " Existing global variable with garbage
+ call assert_equal(0, exists('g:global_var-n'))
+ " Non-existing global variable
+ unlet g:global_var
+ call assert_equal(0, exists('g:global_var'))
+ " Existing global list
+ let g:global_list = ["blue", "orange"]
+ call assert_equal(1, exists('g:global_list'))
+ " Non-existing global list
+ unlet g:global_list
+ call assert_equal(0, exists('g:global_list'))
+ " Existing global dictionary
+ let g:global_dict = {"xcord":100, "ycord":2}
+ call assert_equal(1, exists('g:global_dict'))
+ " Non-existing global dictionary
+ unlet g:global_dict
+ call assert_equal(0, exists('g:global_dict'))
+ " Existing global curly-brace variable
+ let str = "global"
+ let g:curly_{str}_var = 1
+ call assert_equal(1, exists('g:curly_{str}_var'))
+ " Non-existing global curly-brace variable
+ unlet g:curly_{str}_var
+ call assert_equal(0, exists('g:curly_{str}_var'))
+
+ " Existing window variable
+ let w:window_var = 1
+ call assert_equal(1, exists('w:window_var'))
+ " Non-existing window variable
+ unlet w:window_var
+ call assert_equal(0, exists('w:window_var'))
+ " Existing window list
+ let w:window_list = ["blue", "orange"]
+ call assert_equal(1, exists('w:window_list'))
+ " Non-existing window list
+ unlet w:window_list
+ call assert_equal(0, exists('w:window_list'))
+ " Existing window dictionary
+ let w:window_dict = {"xcord":100, "ycord":2}
+ call assert_equal(1, exists('w:window_dict'))
+ " Non-existing window dictionary
+ unlet w:window_dict
+ call assert_equal(0, exists('w:window_dict'))
+ " Existing window curly-brace variable
+ let str = "window"
+ let w:curly_{str}_var = 1
+ call assert_equal(1, exists('w:curly_{str}_var'))
+ " Non-existing window curly-brace variable
+ unlet w:curly_{str}_var
+ call assert_equal(0, exists('w:curly_{str}_var'))
+
+ " Existing tab variable
+ let t:tab_var = 1
+ call assert_equal(1, exists('t:tab_var'))
+ " Non-existing tab variable
+ unlet t:tab_var
+ call assert_equal(0, exists('t:tab_var'))
+ " Existing tab list
+ let t:tab_list = ["blue", "orange"]
+ call assert_equal(1, exists('t:tab_list'))
+ " Non-existing tab list
+ unlet t:tab_list
+ call assert_equal(0, exists('t:tab_list'))
+ " Existing tab dictionary
+ let t:tab_dict = {"xcord":100, "ycord":2}
+ call assert_equal(1, exists('t:tab_dict'))
+ " Non-existing tab dictionary
+ unlet t:tab_dict
+ call assert_equal(0, exists('t:tab_dict'))
+ " Existing tab curly-brace variable
+ let str = "tab"
+ let t:curly_{str}_var = 1
+ call assert_equal(1, exists('t:curly_{str}_var'))
+ " Non-existing tab curly-brace variable
+ unlet t:curly_{str}_var
+ call assert_equal(0, exists('t:curly_{str}_var'))
+
+ " Existing buffer variable
+ let b:buffer_var = 1
+ call assert_equal(1, exists('b:buffer_var'))
+ " Non-existing buffer variable
+ unlet b:buffer_var
+ call assert_equal(0, exists('b:buffer_var'))
+ " Existing buffer list
+ let b:buffer_list = ["blue", "orange"]
+ call assert_equal(1, exists('b:buffer_list'))
+ " Non-existing buffer list
+ unlet b:buffer_list
+ call assert_equal(0, exists('b:buffer_list'))
+ " Existing buffer dictionary
+ let b:buffer_dict = {"xcord":100, "ycord":2}
+ call assert_equal(1, exists('b:buffer_dict'))
+ " Non-existing buffer dictionary
+ unlet b:buffer_dict
+ call assert_equal(0, exists('b:buffer_dict'))
+ " Existing buffer curly-brace variable
+ let str = "buffer"
+ let b:curly_{str}_var = 1
+ call assert_equal(1, exists('b:curly_{str}_var'))
+ " Non-existing buffer curly-brace variable
+ unlet b:curly_{str}_var
+ call assert_equal(0, exists('b:curly_{str}_var'))
+
+ " Existing Vim internal variable
+ call assert_equal(1, exists('v:version'))
+ " Non-existing Vim internal variable
+ call assert_equal(0, exists('v:non_exists_var'))
+
+ " Existing script-local variable
+ let s:script_var = 1
+ call assert_equal(1, exists('s:script_var'))
+ " Non-existing script-local variable
+ unlet s:script_var
+ call assert_equal(0, exists('s:script_var'))
+ " Existing script-local list
+ let s:script_list = ["blue", "orange"]
+ call assert_equal(1, exists('s:script_list'))
+ " Non-existing script-local list
+ unlet s:script_list
+ call assert_equal(0, exists('s:script_list'))
+ " Existing script-local dictionary
+ let s:script_dict = {"xcord":100, "ycord":2}
+ call assert_equal(1, exists('s:script_dict'))
+ " Non-existing script-local dictionary
+ unlet s:script_dict
+ call assert_equal(0, exists('s:script_dict'))
+ " Existing script curly-brace variable
+ let str = "script"
+ let s:curly_{str}_var = 1
+ call assert_equal(1, exists('s:curly_{str}_var'))
+ " Non-existing script-local curly-brace variable
+ unlet s:curly_{str}_var
+ call assert_equal(0, exists('s:curly_{str}_var'))
+
+ " Existing script-local function
+ function! s:my_script_func()
+ endfunction
+
+ echo '*s:my_script_func: 1'
+ call assert_equal(1, exists('*s:my_script_func'))
+
+ " Non-existing script-local function
+ delfunction s:my_script_func
+
+ call assert_equal(0, exists('*s:my_script_func'))
+ unlet str
+
+ call assert_equal(1, g:footest#x)
+ call assert_equal(0, footest#F())
+ call assert_equal(0, UndefFun())
+endfunc
+
+" exists() test for Function arguments
+func FuncArg_Tests(func_arg, ...)
+ call assert_equal(1, exists('a:func_arg'))
+ call assert_equal(0, exists('a:non_exists_arg'))
+ call assert_equal(1, exists('a:1'))
+ call assert_equal(0, exists('a:2'))
+endfunc
+
+func Test_exists_funcarg()
+ call FuncArg_Tests("arg1", "arg2")
+endfunc
diff --git a/src/testdir/test_exists_autocmd.vim b/src/testdir/test_exists_autocmd.vim
new file mode 100644
index 0000000..7e44a72
--- /dev/null
+++ b/src/testdir/test_exists_autocmd.vim
@@ -0,0 +1,26 @@
+" Test that groups and patterns are tested correctly when calling exists() for
+" autocommands.
+
+function Test_AutoCommands()
+ let results=[]
+ augroup auexists
+ augroup END
+ call assert_true(exists("##BufEnter"))
+ call assert_false(exists("#BufEnter"))
+ au BufEnter * let g:entered=1
+ call assert_true(exists("#BufEnter"))
+ call assert_false(exists("#auexists#BufEnter"))
+ augroup auexists
+ au BufEnter * let g:entered=1
+ augroup END
+ call assert_true(exists("#auexists#BufEnter"))
+ call assert_false(exists("#BufEnter#*.test"))
+ au BufEnter *.test let g:entered=1
+ call assert_true(exists("#BufEnter#*.test"))
+ edit testfile.test
+ call assert_false(exists("#BufEnter#<buffer>"))
+ au BufEnter <buffer> let g:entered=1
+ call assert_true(exists("#BufEnter#<buffer>"))
+ edit testfile2.test
+ call assert_false(exists("#BufEnter#<buffer>"))
+endfunction
diff --git a/src/testdir/test_exit.vim b/src/testdir/test_exit.vim
new file mode 100644
index 0000000..8f02fd2
--- /dev/null
+++ b/src/testdir/test_exit.vim
@@ -0,0 +1,57 @@
+" Tests for exiting Vim.
+
+source shared.vim
+
+func Test_exiting()
+ let after = [
+ \ 'au QuitPre * call writefile(["QuitPre"], "Xtestout")',
+ \ 'au ExitPre * call writefile(["ExitPre"], "Xtestout", "a")',
+ \ 'quit',
+ \ ]
+ if RunVim([], after, '')
+ call assert_equal(['QuitPre', 'ExitPre'], readfile('Xtestout'))
+ endif
+ call delete('Xtestout')
+
+ let after = [
+ \ 'au QuitPre * call writefile(["QuitPre"], "Xtestout")',
+ \ 'au ExitPre * call writefile(["ExitPre"], "Xtestout", "a")',
+ \ 'help',
+ \ 'wincmd w',
+ \ 'quit',
+ \ ]
+ if RunVim([], after, '')
+ call assert_equal(['QuitPre', 'ExitPre'], readfile('Xtestout'))
+ endif
+ call delete('Xtestout')
+
+ let after = [
+ \ 'au QuitPre * call writefile(["QuitPre"], "Xtestout")',
+ \ 'au ExitPre * call writefile(["ExitPre"], "Xtestout", "a")',
+ \ 'split',
+ \ 'new',
+ \ 'qall',
+ \ ]
+ if RunVim([], after, '')
+ call assert_equal(['QuitPre', 'ExitPre'], readfile('Xtestout'))
+ endif
+ call delete('Xtestout')
+
+ let after = [
+ \ 'au QuitPre * call writefile(["QuitPre"], "Xtestout", "a")',
+ \ 'au ExitPre * call writefile(["ExitPre"], "Xtestout", "a")',
+ \ 'augroup nasty',
+ \ ' au ExitPre * split',
+ \ 'augroup END',
+ \ 'quit',
+ \ 'augroup nasty',
+ \ ' au! ExitPre',
+ \ 'augroup END',
+ \ 'quit',
+ \ ]
+ if RunVim([], after, '')
+ call assert_equal(['QuitPre', 'ExitPre', 'QuitPre', 'ExitPre'],
+ \ readfile('Xtestout'))
+ endif
+ call delete('Xtestout')
+endfunc
diff --git a/src/testdir/test_expand.vim b/src/testdir/test_expand.vim
new file mode 100644
index 0000000..b4f1363
--- /dev/null
+++ b/src/testdir/test_expand.vim
@@ -0,0 +1,49 @@
+" Test for expanding file names
+
+func Test_with_directories()
+ call mkdir('Xdir1')
+ call mkdir('Xdir2')
+ call mkdir('Xdir3')
+ cd Xdir3
+ call mkdir('Xdir4')
+ cd ..
+
+ split Xdir1/file
+ call setline(1, ['a', 'b'])
+ w
+ w Xdir3/Xdir4/file
+ close
+
+ next Xdir?/*/file
+ call assert_equal('Xdir3/Xdir4/file', expand('%'))
+ if has('unix')
+ next! Xdir?/*/nofile
+ call assert_equal('Xdir?/*/nofile', expand('%'))
+ endif
+ " Edit another file, on MS-Windows the swap file would be in use and can't
+ " be deleted.
+ edit foo
+
+ call assert_equal(0, delete('Xdir1', 'rf'))
+ call assert_equal(0, delete('Xdir2', 'rf'))
+ call assert_equal(0, delete('Xdir3', 'rf'))
+endfunc
+
+func Test_with_tilde()
+ let dir = getcwd()
+ call mkdir('Xdir ~ dir')
+ call assert_true(isdirectory('Xdir ~ dir'))
+ cd Xdir\ ~\ dir
+ call assert_true(getcwd() =~ 'Xdir \~ dir')
+ exe 'cd ' . fnameescape(dir)
+ call delete('Xdir ~ dir', 'd')
+ call assert_false(isdirectory('Xdir ~ dir'))
+endfunc
+
+func Test_expand_tilde_filename()
+ split ~
+ call assert_equal('~', expand('%'))
+ call assert_notequal(expand('%:p'), expand('~/'))
+ call assert_match('\~', expand('%:p'))
+ bwipe!
+endfunc
diff --git a/src/testdir/test_expand_dllpath.vim b/src/testdir/test_expand_dllpath.vim
new file mode 100644
index 0000000..1542095
--- /dev/null
+++ b/src/testdir/test_expand_dllpath.vim
@@ -0,0 +1,32 @@
+func s:test_expand_dllpath(optname)
+ let $TEST_EXPAND_DLLPATH = '/dllpath/lib' . substitute(a:optname, '\zedll$', '.', '')
+ execute 'let dllpath_save = &' . a:optname
+ try
+ execute 'set ' . a:optname . '=$TEST_EXPAND_DLLPATH'
+ execute 'call assert_equal("' . $TEST_EXPAND_DLLPATH . '", &' . a:optname . ')'
+
+ execute 'set ' . a:optname . '=~' . $TEST_EXPAND_DLLPATH
+ let home = substitute($HOME, '\\', '/', 'g')
+ execute 'call assert_equal("' . home . $TEST_EXPAND_DLLPATH . '", &' . a:optname . ')'
+ finally
+ execute 'let &' . a:optname . ' = dllpath_save'
+ let $TEST_EXPAND_DLLPATH = ''
+ endtry
+endfunc
+
+func s:generate_test_if_exists(optname)
+ if exists('+' . a:optname)
+ execute join([
+ \ 'func Test_expand_' . a:optname . '()',
+ \ ' call s:test_expand_dllpath("' . a:optname . '")',
+ \ 'endfunc'
+ \ ], "\n")
+ endif
+endfunc
+
+call s:generate_test_if_exists('luadll')
+call s:generate_test_if_exists('perldll')
+call s:generate_test_if_exists('pythondll')
+call s:generate_test_if_exists('pythonthreedll')
+call s:generate_test_if_exists('rubydll')
+call s:generate_test_if_exists('tcldll')
diff --git a/src/testdir/test_expand_func.vim b/src/testdir/test_expand_func.vim
new file mode 100644
index 0000000..fb29c3e
--- /dev/null
+++ b/src/testdir/test_expand_func.vim
@@ -0,0 +1,66 @@
+" Tests for expand()
+
+let s:sfile = expand('<sfile>')
+let s:slnum = str2nr(expand('<slnum>'))
+let s:sflnum = str2nr(expand('<sflnum>'))
+
+func s:expand_sfile()
+ return expand('<sfile>')
+endfunc
+
+func s:expand_slnum()
+ return str2nr(expand('<slnum>'))
+endfunc
+
+func s:expand_sflnum()
+ return str2nr(expand('<sflnum>'))
+endfunc
+
+func Test_expand_sfile()
+ call assert_match('test_expand_func\.vim$', s:sfile)
+ call assert_match('^function .*\.\.Test_expand_sfile$', expand('<sfile>'))
+
+ " Call in script-local function
+ call assert_match('^function .*\.\.Test_expand_sfile\[5\]\.\.<SNR>\d\+_expand_sfile$', s:expand_sfile())
+
+ " Call in command
+ command Sfile echo expand('<sfile>')
+ call assert_match('^function .*\.\.Test_expand_sfile$', trim(execute('Sfile')))
+ delcommand Sfile
+endfunc
+
+func Test_expand_slnum()
+ call assert_equal(4, s:slnum)
+ call assert_equal(2, str2nr(expand('<slnum>')))
+
+ " Line-continuation
+ call assert_equal(
+ \ 5,
+ \ str2nr(expand('<slnum>')))
+
+ " Call in script-local function
+ call assert_equal(1, s:expand_slnum())
+
+ " Call in command
+ command Slnum echo expand('<slnum>')
+ call assert_equal(14, str2nr(trim(execute('Slnum'))))
+ delcommand Slnum
+endfunc
+
+func Test_expand_sflnum()
+ call assert_equal(5, s:sflnum)
+ call assert_equal(52, str2nr(expand('<sflnum>')))
+
+ " Line-continuation
+ call assert_equal(
+ \ 55,
+ \ str2nr(expand('<sflnum>')))
+
+ " Call in script-local function
+ call assert_equal(16, s:expand_sflnum())
+
+ " Call in command
+ command Flnum echo expand('<sflnum>')
+ call assert_equal(64, str2nr(trim(execute('Flnum'))))
+ delcommand Flnum
+endfunc
diff --git a/src/testdir/test_expr.vim b/src/testdir/test_expr.vim
new file mode 100644
index 0000000..216a00f
--- /dev/null
+++ b/src/testdir/test_expr.vim
@@ -0,0 +1,514 @@
+" Tests for expressions.
+
+func Test_equal()
+ let base = {}
+ func base.method()
+ return 1
+ endfunc
+ func base.other() dict
+ return 1
+ endfunc
+ let instance = copy(base)
+ call assert_true(base.method == instance.method)
+ call assert_true([base.method] == [instance.method])
+ call assert_true(base.other == instance.other)
+ call assert_true([base.other] == [instance.other])
+
+ call assert_false(base.method == base.other)
+ call assert_false([base.method] == [base.other])
+ call assert_false(base.method == instance.other)
+ call assert_false([base.method] == [instance.other])
+
+ call assert_fails('echo base.method > instance.method')
+endfunc
+
+func Test_version()
+ call assert_true(has('patch-7.4.001'))
+ call assert_true(has('patch-7.4.01'))
+ call assert_true(has('patch-7.4.1'))
+ call assert_true(has('patch-6.9.999'))
+ call assert_true(has('patch-7.1.999'))
+ call assert_true(has('patch-7.4.123'))
+
+ call assert_false(has('patch-7'))
+ call assert_false(has('patch-7.4'))
+ call assert_false(has('patch-7.4.'))
+ call assert_false(has('patch-9.1.0'))
+ call assert_false(has('patch-9.9.1'))
+endfunc
+
+func Test_dict()
+ let d = {'': 'empty', 'a': 'a', 0: 'zero'}
+ call assert_equal('empty', d[''])
+ call assert_equal('a', d['a'])
+ call assert_equal('zero', d[0])
+ call assert_true(has_key(d, ''))
+ call assert_true(has_key(d, 'a'))
+
+ let d[''] = 'none'
+ let d['a'] = 'aaa'
+ call assert_equal('none', d[''])
+ call assert_equal('aaa', d['a'])
+endfunc
+
+func Test_strgetchar()
+ call assert_equal(char2nr('a'), strgetchar('axb', 0))
+ call assert_equal(char2nr('x'), strgetchar('axb', 1))
+ call assert_equal(char2nr('b'), strgetchar('axb', 2))
+
+ call assert_equal(-1, strgetchar('axb', -1))
+ call assert_equal(-1, strgetchar('axb', 3))
+ call assert_equal(-1, strgetchar('', 0))
+endfunc
+
+func Test_strcharpart()
+ call assert_equal('a', strcharpart('axb', 0, 1))
+ call assert_equal('x', strcharpart('axb', 1, 1))
+ call assert_equal('b', strcharpart('axb', 2, 1))
+ call assert_equal('xb', strcharpart('axb', 1))
+
+ call assert_equal('', strcharpart('axb', 1, 0))
+ call assert_equal('', strcharpart('axb', 1, -1))
+ call assert_equal('', strcharpart('axb', -1, 1))
+ call assert_equal('', strcharpart('axb', -2, 2))
+
+ call assert_equal('a', strcharpart('axb', -1, 2))
+endfunc
+
+func Test_getreg_empty_list()
+ call assert_equal('', getreg('x'))
+ call assert_equal([], getreg('x', 1, 1))
+ let x = getreg('x', 1, 1)
+ let y = x
+ call add(x, 'foo')
+ call assert_equal(['foo'], y)
+endfunc
+
+func Test_loop_over_null_list()
+ let null_list = test_null_list()
+ for i in null_list
+ call assert_report('should not get here')
+ endfor
+endfunc
+
+func Test_compare_null_dict()
+ call assert_fails('let x = test_null_dict()[10]')
+ call assert_equal({}, {})
+ call assert_equal(test_null_dict(), test_null_dict())
+ call assert_notequal({}, test_null_dict())
+endfunc
+
+func Test_set_reg_null_list()
+ call setreg('x', test_null_list())
+endfunc
+
+func Test_special_char()
+ " The failure is only visible using valgrind.
+ call assert_fails('echo "\<C-">')
+endfunc
+
+func Test_option_value()
+ " boolean
+ set bri
+ call assert_equal(1, &bri)
+ set nobri
+ call assert_equal(0, &bri)
+
+ " number
+ set ts=1
+ call assert_equal(1, &ts)
+ set ts=8
+ call assert_equal(8, &ts)
+
+ " string
+ exe "set cedit=\<Esc>"
+ call assert_equal("\<Esc>", &cedit)
+ set cpo=
+ call assert_equal("", &cpo)
+ set cpo=abcdefgi
+ call assert_equal("abcdefgi", &cpo)
+ set cpo&vim
+endfunc
+
+function Test_printf_misc()
+ call assert_equal('123', printf('123'))
+ call assert_fails("call printf('123', 3)", "E767:")
+
+ call assert_equal('123', printf('%d', 123))
+ call assert_equal('123', printf('%i', 123))
+ call assert_equal('123', printf('%D', 123))
+ call assert_equal('123', printf('%U', 123))
+ call assert_equal('173', printf('%o', 123))
+ call assert_equal('173', printf('%O', 123))
+ call assert_equal('7b', printf('%x', 123))
+ call assert_equal('7B', printf('%X', 123))
+
+ call assert_equal('123', printf('%hd', 123))
+ call assert_equal('-123', printf('%hd', -123))
+ call assert_equal('-1', printf('%hd', 0xFFFF))
+ call assert_equal('-1', printf('%hd', 0x1FFFFF))
+
+ call assert_equal('123', printf('%hu', 123))
+ call assert_equal('65413', printf('%hu', -123))
+ call assert_equal('65535', printf('%hu', 0xFFFF))
+ call assert_equal('65535', printf('%hu', 0x1FFFFF))
+
+ call assert_equal('123', printf('%ld', 123))
+ call assert_equal('-123', printf('%ld', -123))
+ call assert_equal('65535', printf('%ld', 0xFFFF))
+ call assert_equal('131071', printf('%ld', 0x1FFFF))
+
+ if has('ebcdic')
+ call assert_equal('#', printf('%c', 123))
+ else
+ call assert_equal('{', printf('%c', 123))
+ endif
+ call assert_equal('abc', printf('%s', 'abc'))
+ call assert_equal('abc', printf('%S', 'abc'))
+
+ call assert_equal('+123', printf('%+d', 123))
+ call assert_equal('-123', printf('%+d', -123))
+ call assert_equal('+123', printf('%+ d', 123))
+ call assert_equal(' 123', printf('% d', 123))
+ call assert_equal(' 123', printf('% d', 123))
+ call assert_equal('-123', printf('% d', -123))
+
+ call assert_equal('123', printf('%2d', 123))
+ call assert_equal(' 123', printf('%6d', 123))
+ call assert_equal('000123', printf('%06d', 123))
+ call assert_equal('+00123', printf('%+06d', 123))
+ call assert_equal(' 00123', printf('% 06d', 123))
+ call assert_equal(' +123', printf('%+6d', 123))
+ call assert_equal(' 123', printf('% 6d', 123))
+ call assert_equal(' -123', printf('% 6d', -123))
+
+ " Test left adjusted.
+ call assert_equal('123 ', printf('%-6d', 123))
+ call assert_equal('+123 ', printf('%-+6d', 123))
+ call assert_equal(' 123 ', printf('%- 6d', 123))
+ call assert_equal('-123 ', printf('%- 6d', -123))
+
+ call assert_equal(' 00123', printf('%7.5d', 123))
+ call assert_equal(' -00123', printf('%7.5d', -123))
+ call assert_equal(' +00123', printf('%+7.5d', 123))
+ " Precision field should not be used when combined with %0
+ call assert_equal(' 00123', printf('%07.5d', 123))
+ call assert_equal(' -00123', printf('%07.5d', -123))
+
+ call assert_equal(' 123', printf('%*d', 5, 123))
+ call assert_equal('123 ', printf('%*d', -5, 123))
+ call assert_equal('00123', printf('%.*d', 5, 123))
+ call assert_equal(' 123', printf('% *d', 5, 123))
+ call assert_equal(' +123', printf('%+ *d', 5, 123))
+
+ call assert_equal('foobar', printf('%.*s', 9, 'foobar'))
+ call assert_equal('foo', printf('%.*s', 3, 'foobar'))
+ call assert_equal('', printf('%.*s', 0, 'foobar'))
+ call assert_equal('foobar', printf('%.*s', -1, 'foobar'))
+
+ " Simple quote (thousand grouping char) is ignored.
+ call assert_equal('+00123456', printf("%+'09d", 123456))
+
+ " Unrecognized format specifier kept as-is.
+ call assert_equal('_123', printf("%_%d", 123))
+
+ " Test alternate forms.
+ call assert_equal('0x7b', printf('%#x', 123))
+ call assert_equal('0X7B', printf('%#X', 123))
+ call assert_equal('0173', printf('%#o', 123))
+ call assert_equal('0173', printf('%#O', 123))
+ call assert_equal('abc', printf('%#s', 'abc'))
+ call assert_equal('abc', printf('%#S', 'abc'))
+ call assert_equal(' 0173', printf('%#6o', 123))
+ call assert_equal(' 00173', printf('%#6.5o', 123))
+ call assert_equal(' 0173', printf('%#6.2o', 123))
+ call assert_equal(' 0173', printf('%#6.2o', 123))
+ call assert_equal('0173', printf('%#2.2o', 123))
+
+ call assert_equal(' 00123', printf('%6.5d', 123))
+ call assert_equal(' 0007b', printf('%6.5x', 123))
+
+ call assert_equal('123', printf('%.2d', 123))
+ call assert_equal('0123', printf('%.4d', 123))
+ call assert_equal('0000000123', printf('%.10d', 123))
+ call assert_equal('123', printf('%.0d', 123))
+
+ call assert_equal('abc', printf('%2s', 'abc'))
+ call assert_equal('abc', printf('%2S', 'abc'))
+ call assert_equal('abc', printf('%.4s', 'abc'))
+ call assert_equal('abc', printf('%.4S', 'abc'))
+ call assert_equal('ab', printf('%.2s', 'abc'))
+ call assert_equal('ab', printf('%.2S', 'abc'))
+ call assert_equal('', printf('%.0s', 'abc'))
+ call assert_equal('', printf('%.s', 'abc'))
+ call assert_equal(' abc', printf('%4s', 'abc'))
+ call assert_equal(' abc', printf('%4S', 'abc'))
+ call assert_equal('0abc', printf('%04s', 'abc'))
+ call assert_equal('0abc', printf('%04S', 'abc'))
+ call assert_equal('abc ', printf('%-4s', 'abc'))
+ call assert_equal('abc ', printf('%-4S', 'abc'))
+
+ call assert_equal('1%', printf('%d%%', 1))
+endfunc
+
+function Test_printf_float()
+ if has('float')
+ call assert_equal('1.000000', printf('%f', 1))
+ call assert_equal('1.230000', printf('%f', 1.23))
+ call assert_equal('1.230000', printf('%F', 1.23))
+ call assert_equal('9999999.9', printf('%g', 9999999.9))
+ call assert_equal('9999999.9', printf('%G', 9999999.9))
+ call assert_equal('1.00000001e7', printf('%.8g', 10000000.1))
+ call assert_equal('1.00000001E7', printf('%.8G', 10000000.1))
+ call assert_equal('1.230000e+00', printf('%e', 1.23))
+ call assert_equal('1.230000E+00', printf('%E', 1.23))
+ call assert_equal('1.200000e-02', printf('%e', 0.012))
+ call assert_equal('-1.200000e-02', printf('%e', -0.012))
+ call assert_equal('0.33', printf('%.2f', 1.0/3.0))
+ call assert_equal(' 0.33', printf('%6.2f', 1.0/3.0))
+ call assert_equal(' -0.33', printf('%6.2f', -1.0/3.0))
+ call assert_equal('000.33', printf('%06.2f', 1.0/3.0))
+ call assert_equal('-00.33', printf('%06.2f', -1.0/3.0))
+ call assert_equal('-00.33', printf('%+06.2f', -1.0/3.0))
+ call assert_equal('+00.33', printf('%+06.2f', 1.0/3.0))
+ call assert_equal(' 00.33', printf('% 06.2f', 1.0/3.0))
+ call assert_equal('000.33', printf('%06.2g', 1.0/3.0))
+ call assert_equal('-00.33', printf('%06.2g', -1.0/3.0))
+ call assert_equal('0.33', printf('%3.2f', 1.0/3.0))
+ call assert_equal('003.33e-01', printf('%010.2e', 1.0/3.0))
+ call assert_equal(' 03.33e-01', printf('% 010.2e', 1.0/3.0))
+ call assert_equal('+03.33e-01', printf('%+010.2e', 1.0/3.0))
+ call assert_equal('-03.33e-01', printf('%010.2e', -1.0/3.0))
+
+ " When precision is 0, the dot should be omitted.
+ call assert_equal(' 2', printf('%3.f', 7.0/3.0))
+ call assert_equal(' 2', printf('%3.g', 7.0/3.0))
+ call assert_equal(' 2e+00', printf('%7.e', 7.0/3.0))
+
+ " Float zero can be signed.
+ call assert_equal('+0.000000', printf('%+f', 0.0))
+ call assert_equal('0.000000', printf('%f', 1.0/(1.0/0.0)))
+ call assert_equal('-0.000000', printf('%f', 1.0/(-1.0/0.0)))
+ call assert_equal('0.0', printf('%s', 1.0/(1.0/0.0)))
+ call assert_equal('-0.0', printf('%s', 1.0/(-1.0/0.0)))
+ call assert_equal('0.0', printf('%S', 1.0/(1.0/0.0)))
+ call assert_equal('-0.0', printf('%S', 1.0/(-1.0/0.0)))
+
+ " Float infinity can be signed.
+ call assert_equal('inf', printf('%f', 1.0/0.0))
+ call assert_equal('-inf', printf('%f', -1.0/0.0))
+ call assert_equal('inf', printf('%g', 1.0/0.0))
+ call assert_equal('-inf', printf('%g', -1.0/0.0))
+ call assert_equal('inf', printf('%e', 1.0/0.0))
+ call assert_equal('-inf', printf('%e', -1.0/0.0))
+ call assert_equal('INF', printf('%F', 1.0/0.0))
+ call assert_equal('-INF', printf('%F', -1.0/0.0))
+ call assert_equal('INF', printf('%E', 1.0/0.0))
+ call assert_equal('-INF', printf('%E', -1.0/0.0))
+ call assert_equal('INF', printf('%E', 1.0/0.0))
+ call assert_equal('-INF', printf('%G', -1.0/0.0))
+ call assert_equal('+inf', printf('%+f', 1.0/0.0))
+ call assert_equal('-inf', printf('%+f', -1.0/0.0))
+ call assert_equal(' inf', printf('% f', 1.0/0.0))
+ call assert_equal(' inf', printf('%6f', 1.0/0.0))
+ call assert_equal(' -inf', printf('%6f', -1.0/0.0))
+ call assert_equal(' inf', printf('%6g', 1.0/0.0))
+ call assert_equal(' -inf', printf('%6g', -1.0/0.0))
+ call assert_equal(' +inf', printf('%+6f', 1.0/0.0))
+ call assert_equal(' inf', printf('% 6f', 1.0/0.0))
+ call assert_equal(' +inf', printf('%+06f', 1.0/0.0))
+ call assert_equal('inf ', printf('%-6f', 1.0/0.0))
+ call assert_equal('-inf ', printf('%-6f', -1.0/0.0))
+ call assert_equal('+inf ', printf('%-+6f', 1.0/0.0))
+ call assert_equal(' inf ', printf('%- 6f', 1.0/0.0))
+ call assert_equal('-INF ', printf('%-6F', -1.0/0.0))
+ call assert_equal('+INF ', printf('%-+6F', 1.0/0.0))
+ call assert_equal(' INF ', printf('%- 6F', 1.0/0.0))
+ call assert_equal('INF ', printf('%-6G', 1.0/0.0))
+ call assert_equal('-INF ', printf('%-6G', -1.0/0.0))
+ call assert_equal('INF ', printf('%-6E', 1.0/0.0))
+ call assert_equal('-INF ', printf('%-6E', -1.0/0.0))
+ call assert_equal('inf', printf('%s', 1.0/0.0))
+ call assert_equal('-inf', printf('%s', -1.0/0.0))
+
+ " Test special case where max precision is truncated at 340.
+ call assert_equal('1.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', printf('%.330f', 1.0))
+ call assert_equal('1.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', printf('%.340f', 1.0))
+ call assert_equal('1.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', printf('%.350f', 1.0))
+
+ " Float nan (not a number) has no sign.
+ call assert_equal('nan', printf('%f', sqrt(-1.0)))
+ call assert_equal('nan', printf('%f', 0.0/0.0))
+ call assert_equal('nan', printf('%f', -0.0/0.0))
+ call assert_equal('nan', printf('%g', 0.0/0.0))
+ call assert_equal('nan', printf('%e', 0.0/0.0))
+ call assert_equal('NAN', printf('%F', 0.0/0.0))
+ call assert_equal('NAN', printf('%G', 0.0/0.0))
+ call assert_equal('NAN', printf('%E', 0.0/0.0))
+ call assert_equal('NAN', printf('%F', -0.0/0.0))
+ call assert_equal('NAN', printf('%G', -0.0/0.0))
+ call assert_equal('NAN', printf('%E', -0.0/0.0))
+ call assert_equal(' nan', printf('%6f', 0.0/0.0))
+ call assert_equal(' nan', printf('%06f', 0.0/0.0))
+ call assert_equal('nan ', printf('%-6f', 0.0/0.0))
+ call assert_equal('nan ', printf('%- 6f', 0.0/0.0))
+ call assert_equal('nan', printf('%s', 0.0/0.0))
+ call assert_equal('nan', printf('%s', -0.0/0.0))
+ call assert_equal('nan', printf('%S', 0.0/0.0))
+ call assert_equal('nan', printf('%S', -0.0/0.0))
+
+ call assert_fails('echo printf("%f", "a")', 'E807:')
+ endif
+endfunc
+
+function Test_printf_errors()
+ call assert_fails('echo printf("%d", {})', 'E728:')
+ call assert_fails('echo printf("%d", [])', 'E745:')
+ call assert_fails('echo printf("%d", 1, 2)', 'E767:')
+ call assert_fails('echo printf("%*d", 1)', 'E766:')
+ call assert_fails('echo printf("%d", 1.2)', 'E805:')
+endfunc
+
+function Test_max_min_errors()
+ call assert_fails('call max(v:true)', 'E712:')
+ call assert_fails('call max(v:true)', 'max()')
+ call assert_fails('call min(v:true)', 'E712:')
+ call assert_fails('call min(v:true)', 'min()')
+endfunc
+
+function Test_printf_64bit()
+ if has('num64')
+ call assert_equal("123456789012345", printf('%d', 123456789012345))
+ endif
+endfunc
+
+function Test_printf_spec_s()
+ " number
+ call assert_equal("1234567890", printf('%s', 1234567890))
+
+ " string
+ call assert_equal("abcdefgi", printf('%s', "abcdefgi"))
+
+ " float
+ if has('float')
+ call assert_equal("1.23", printf('%s', 1.23))
+ endif
+
+ " list
+ let value = [1, 'two', ['three', 4]]
+ call assert_equal(string(value), printf('%s', value))
+
+ " dict
+ let value = {'key1' : 'value1', 'key2' : ['list', 'value'], 'key3' : {'dict' : 'value'}}
+ call assert_equal(string(value), printf('%s', value))
+
+ " funcref
+ call assert_equal('printf', printf('%s', function('printf')))
+
+ " partial
+ call assert_equal(string(function('printf', ['%s'])), printf('%s', function('printf', ['%s'])))
+endfunc
+
+function Test_printf_spec_b()
+ call assert_equal("0", printf('%b', 0))
+ call assert_equal("00001100", printf('%08b', 12))
+ call assert_equal("11111111", printf('%08b', 0xff))
+ call assert_equal(" 1111011", printf('%10b', 123))
+ call assert_equal("0001111011", printf('%010b', 123))
+ call assert_equal(" 0b1111011", printf('%#10b', 123))
+ call assert_equal("0B01111011", printf('%#010B', 123))
+ call assert_equal("1001001100101100000001011010010", printf('%b', 1234567890))
+ if has('num64')
+ call assert_equal("11100000100100010000110000011011101111101111001", printf('%b', 123456789012345))
+ call assert_equal("1111111111111111111111111111111111111111111111111111111111111111", printf('%b', -1))
+ else
+ call assert_equal("11111111111111111111111111111111", printf('%b', -1))
+ endif
+endfunc
+
+func Test_substitute_expr()
+ let g:val = 'XXX'
+ call assert_equal('XXX', substitute('yyy', 'y*', '\=g:val', ''))
+ call assert_equal('XXX', substitute('yyy', 'y*', {-> g:val}, ''))
+ call assert_equal("-\u1b \uf2-", substitute("-%1b %f2-", '%\(\x\x\)',
+ \ '\=nr2char("0x" . submatch(1))', 'g'))
+ call assert_equal("-\u1b \uf2-", substitute("-%1b %f2-", '%\(\x\x\)',
+ \ {-> nr2char("0x" . submatch(1))}, 'g'))
+
+ call assert_equal('231', substitute('123', '\(.\)\(.\)\(.\)',
+ \ {-> submatch(2) . submatch(3) . submatch(1)}, ''))
+
+ func Recurse()
+ return substitute('yyy', 'y\(.\)y', {-> submatch(1)}, '')
+ endfunc
+ " recursive call works
+ call assert_equal('-y-x-', substitute('xxx', 'x\(.\)x', {-> '-' . Recurse() . '-' . submatch(1) . '-'}, ''))
+endfunc
+
+func Test_invalid_submatch()
+ " This was causing invalid memory access in Vim-7.4.2232 and older
+ call assert_fails("call substitute('x', '.', {-> submatch(10)}, '')", 'E935:')
+endfunc
+
+func Test_substitute_expr_arg()
+ call assert_equal('123456789-123456789=', substitute('123456789',
+ \ '\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)',
+ \ {m -> m[0] . '-' . m[1] . m[2] . m[3] . m[4] . m[5] . m[6] . m[7] . m[8] . m[9] . '='}, ''))
+
+ call assert_equal('123456-123456=789', substitute('123456789',
+ \ '\(.\)\(.\)\(.\)\(a*\)\(n*\)\(.\)\(.\)\(.\)\(x*\)',
+ \ {m -> m[0] . '-' . m[1] . m[2] . m[3] . m[4] . m[5] . m[6] . m[7] . m[8] . m[9] . '='}, ''))
+
+ call assert_equal('123456789-123456789x=', substitute('123456789',
+ \ '\(.\)\(.\)\(.*\)',
+ \ {m -> m[0] . '-' . m[1] . m[2] . m[3] . 'x' . m[4] . m[5] . m[6] . m[7] . m[8] . m[9] . '='}, ''))
+
+ call assert_fails("call substitute('xxx', '.', {m -> string(add(m, 'x'))}, '')", 'E742:')
+ call assert_fails("call substitute('xxx', '.', {m -> string(insert(m, 'x'))}, '')", 'E742:')
+ call assert_fails("call substitute('xxx', '.', {m -> string(extend(m, ['x']))}, '')", 'E742:')
+ call assert_fails("call substitute('xxx', '.', {m -> string(remove(m, 1))}, '')", 'E742:')
+endfunc
+
+func Test_function_with_funcref()
+ let s:f = function('type')
+ let s:fref = function(s:f)
+ call assert_equal(v:t_string, s:fref('x'))
+ call assert_fails("call function('s:f')", 'E700:')
+
+ call assert_fails("call function('foo()')", 'E475:')
+ call assert_fails("call function('foo()')", 'foo()')
+endfunc
+
+func Test_funcref()
+ func! One()
+ return 1
+ endfunc
+ let OneByName = function('One')
+ let OneByRef = funcref('One')
+ func! One()
+ return 2
+ endfunc
+ call assert_equal(2, OneByName())
+ call assert_equal(1, OneByRef())
+ let OneByRef = funcref('One')
+ call assert_equal(2, OneByRef())
+ call assert_fails('echo funcref("{")', 'E475:')
+endfunc
+
+func Test_setmatches()
+ hi def link 1 Comment
+ hi def link 2 PreProc
+ let set = [{"group": 1, "pattern": 2, "id": 3, "priority": 4}]
+ let exp = [{"group": '1', "pattern": '2', "id": 3, "priority": 4}]
+ if has('conceal')
+ let set[0]['conceal'] = 5
+ let exp[0]['conceal'] = '5'
+ endif
+ call setmatches(set)
+ call assert_equal(exp, getmatches())
+endfunc
+
+func Test_empty_concatenate()
+ call assert_equal('b', 'a'[4:0] . 'b')
+ call assert_equal('b', 'b' . 'a'[4:0])
+endfunc
diff --git a/src/testdir/test_expr_utf8.vim b/src/testdir/test_expr_utf8.vim
new file mode 100644
index 0000000..fad725d
--- /dev/null
+++ b/src/testdir/test_expr_utf8.vim
@@ -0,0 +1,34 @@
+" Tests for expressions using utf-8.
+
+func Test_strgetchar()
+ call assert_equal(char2nr('á'), strgetchar('áxb', 0))
+ call assert_equal(char2nr('x'), strgetchar('áxb', 1))
+
+ call assert_equal(char2nr('a'), strgetchar('àxb', 0))
+ call assert_equal(char2nr('̀'), strgetchar('àxb', 1))
+ call assert_equal(char2nr('x'), strgetchar('àxb', 2))
+
+ call assert_equal(char2nr('ã‚'), strgetchar('ã‚aã„', 0))
+ call assert_equal(char2nr('a'), strgetchar('ã‚aã„', 1))
+ call assert_equal(char2nr('ã„'), strgetchar('ã‚aã„', 2))
+endfunc
+
+func Test_strcharpart()
+ call assert_equal('áxb', strcharpart('áxb', 0))
+ call assert_equal('á', strcharpart('áxb', 0, 1))
+ call assert_equal('x', strcharpart('áxb', 1, 1))
+
+ call assert_equal('ã„ã†eãŠ', strcharpart('ã‚ã„ã†eãŠ', 1))
+ call assert_equal('ã„', strcharpart('ã‚ã„ã†eãŠ', 1, 1))
+ call assert_equal('ã„ã†', strcharpart('ã‚ã„ã†eãŠ', 1, 2))
+ call assert_equal('ã„ã†e', strcharpart('ã‚ã„ã†eãŠ', 1, 3))
+ call assert_equal('ã„ã†eãŠ', strcharpart('ã‚ã„ã†eãŠ', 1, 4))
+ call assert_equal('eãŠ', strcharpart('ã‚ã„ã†eãŠ', 3))
+ call assert_equal('e', strcharpart('ã‚ã„ã†eãŠ', 3, 1))
+
+ call assert_equal('ã‚', strcharpart('ã‚ã„ã†eãŠ', -3, 4))
+
+ call assert_equal('a', strcharpart('àxb', 0, 1))
+ call assert_equal('̀', strcharpart('àxb', 1, 1))
+ call assert_equal('x', strcharpart('àxb', 2, 1))
+endfunc
diff --git a/src/testdir/test_farsi.vim b/src/testdir/test_farsi.vim
new file mode 100644
index 0000000..dcfa024
--- /dev/null
+++ b/src/testdir/test_farsi.vim
@@ -0,0 +1,133 @@
+" Simplistic testing of Farsi mode.
+" Note: must be edited with latin1 encoding.
+
+if !has('farsi')
+ finish
+endif
+" Farsi uses a single byte encoding.
+set enc=latin1
+
+func Test_farsi_toggle()
+ new
+
+ set altkeymap
+ call assert_equal(0, &fkmap)
+ call assert_equal(0, &rl)
+ call feedkeys("\<F8>", 'x')
+ call assert_equal(1, &fkmap)
+ call assert_equal(1, &rl)
+ call feedkeys("\<F8>", 'x')
+ call assert_equal(0, &fkmap)
+ call assert_equal(0, &rl)
+
+ set rl
+ " conversion from Farsi 3342 to Farsi VIM.
+ call setline(1, join(map(range(0x80, 0xff), 'nr2char(v:val)'), ''))
+ call feedkeys("\<F9>", 'x')
+ let exp = [0xfc, 0xf8, 0xc1, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ \ 0xc8, 0xc9, 0xca, 0xd0, 0xd1, 0xd2, 0xd3, 0xd6,
+ \ 0xd6, 0xd6, 0xd7, 0xd7, 0xd7, 0xd8, 0xd9, 0xda,
+ \ 0xdb, 0xdc, 0xdc, 0xc1, 0xdd, 0xde, 0xe0, 0xe0,
+ \ 0xe1, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6,
+ \ 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae,
+ \ 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
+ \ 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe,
+ \ 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6,
+ \ 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce,
+ \ 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6,
+ \ 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde,
+ \ 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6,
+ \ 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xfb, 0xfb, 0xfe,
+ \ 0xfe, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6,
+ \ 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xe1,
+ \ ]
+ call assert_equal(join(map(exp, 'nr2char(v:val)'), ''), getline(1))
+
+ " conversion from Farsi VIM to Farsi 3342.
+ call setline(1, join(map(range(0x80, 0xff), 'nr2char(v:val)'), ''))
+ call feedkeys("\<F9>", 'x')
+ let exp = [0xfc, 0xf8, 0xc1, 0x83, 0x84, 0x85, 0x86, 0x87,
+ \ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x90,
+ \ 0x90, 0x90, 0x92, 0x93, 0x93, 0x95, 0x96, 0x97,
+ \ 0x98, 0xdc, 0x9a, 0x9b, 0x9c, 0x9e, 0x9e, 0xff,
+ \ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ \ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ \ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+ \ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+ \ 0xc0, 0xc1, 0xc2, 0x83, 0x84, 0x85, 0x86, 0x87,
+ \ 0x88, 0x89, 0x8a, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+ \ 0x8b, 0x8c, 0x8d, 0x8e, 0xd4, 0xd5, 0x90, 0x93,
+ \ 0x95, 0x96, 0x97, 0x98, 0x99, 0x9b, 0x9c, 0xdf,
+ \ 0x9d, 0xff, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+ \ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xec, 0xee, 0xef,
+ \ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ \ 0xf8, 0xf9, 0xfa, 0xec, 0x80, 0xfd, 0xee, 0xff,
+ \ ]
+ call assert_equal(join(map(exp, 'nr2char(v:val)'), ''), getline(1))
+
+ bwipe!
+endfunc
+
+func Test_farsi_map()
+ new
+
+ set altkeymap
+ set rl
+ " RHS of mapping is reversed.
+ imap xyz abc
+ call feedkeys("axyz\<Esc>", 'tx')
+ call assert_equal('cba', getline(1))
+
+ set norl
+ iunmap xyz
+ set noaltkeymap
+ bwipe!
+endfunc
+
+func Test_input_farsi()
+ new
+ setlocal rightleft fkmap
+ " numbers switch input direction
+ call feedkeys("aabc0123456789.+-^%#=xyz\<Esc>", 'tx')
+ call assert_equal("\x8cÌν®¥ª­«¦¹¸·¶µ´³²±°Ô\x93Õ", getline('.'))
+
+ " all non-number special chars with spaces
+ call feedkeys("oB E F H I K L M O P Q R T U W Y ` ! @ # $ % ^ & * () - _ = + \\ | : \" . / < > ? \<Esc>", 'tx')
+ call assert_equal("¡ ô ú À ö æ ç Â [ ] ÷ ó ò ð õ ñ ¢ £  § ® ¤ ¥ ª ¬ è ¨© ­ é ½ « ë ê º » ¦  ¯ ¾ ¼ ¿ ", getline('.'))
+
+ " all non-number special chars without spaces
+ call feedkeys("oBEFHIKLMOPQRTUWY`!@#$%^&*()-_=+\\|:\"./<>?\<Esc>",'tx')
+ call assert_equal("¡ôúÀöæçÂ[]÷óòðõñ¢£§®¤¥ª¬è¨©­é½«ë꺻¦¯¾¼¿", getline('.'))
+
+ " all letter chars with spaces
+ call feedkeys("oa A b c C d D e f g G h i j J k l m n N o p q r s S t u v V w x X y z Z ; \ , [ ] \<Esc>", 'tx')
+ call assert_equal("Ñ ù Ì Î Ï á þ Æ Ã Ü ø Á à Å ü Þ Ý Ä Ë Ë Ê É Ó Ù Ð û Ø Ö Í Í Ò Ô Ô × Õ ý Ú  ß Ç È ", getline('.'))
+
+ " all letter chars without spaces
+ call feedkeys("oaAbcCdDefgGhijJklmnNopqrsStuvVwxXyzZ;\,[]\<Esc>", 'tx')
+ call assert_equal("\x8cùÌÎÏ\x9fî\x86\x83ÜøÁ\x9d\x85\x80\x9c\x9b\x84ËË\x8a\x89\x8e\x96\x8bì\x95\x90ÍÍ\x8dÔÔ\x93Õý\x97ß\x87\x88", getline('.'))
+
+ bwipe!
+endfunc
+
+func Test_command_line_farsi()
+ set allowrevins altkeymap
+
+ " letter characters with spaces
+ call feedkeys(":\"\<C-_>a A b c C d D e f g G h i j J k l m n N o p q r s S t u v V w x X y z Z ; \\ , [ ]\<CR>", 'tx')
+ call assert_equal("\"\x88 Ç ß ë Ú Õ Õ × Ô Ô Ò Í Í Ö Ø û Ð Ù Ó É Ê Ë Ë Ä Ý Þ ü Å à Á ø Ü Ã Æ þ á Ï Î Ì ù Ñ", getreg(':'))
+
+ " letter characters without spaces
+ call feedkeys(":\"\<C-_>aAbcCdDefgGhijJklmnNopqrsStuvVwxXyzZ;\\,[]\<CR>", 'tx')
+ call assert_equal("\"\x88\x87ßëÚÕÕ\x93ÔÔ\x8dÍÍ\x90\x95ì\x8b\x96\x8e\x89\x8aËË\x84\x9b\x9c\x80\x85\x9dÁøÜ\x83\x86î\x9fÏÎÌù\x8c", getreg(':'))
+
+ " other characters with spaces
+ call feedkeys(":\"\<C-_>0 1 2 3 4 5 6 7 8 9 ` . ! \" $ % ^ & / () = \\ ? + - _ * : # ~ @ < > { } | B E F H I K L M O P Q R T U W Y\<CR>", 'tx')
+ call assert_equal("\"ñ õ ð ò ó ÷ ] [ Â ç æ ö À ú ô ¡ ê } { ¼ ¾ § ~ ® º è é ­ «  ¿ ë ½ ©¨ ¯ ¬ ª ¥ ¤ »  £  ¦ ¢ ¹ ¸ · ¶ µ ´ ³ ² ± °", getreg(':'))
+
+ " other characters without spaces
+ call feedkeys(":\"\<C-_>0123456789`.!\"$%^&/()=\\?+-_*:#~@<>{}|BEFHIKLMOPQRTUWY\<CR>", 'tx')
+ call assert_equal("\"ñõðòó÷][ÂçæöÀúô¡ê}{¼¾§~®ºèé­«¿ë½©¨¯¬ª¥¤»£¦¢¹¸·¶µ´³²±°", getreg(':'))
+
+ set noallowrevins noaltkeymap
+endfunc
diff --git a/src/testdir/test_feedkeys.vim b/src/testdir/test_feedkeys.vim
new file mode 100644
index 0000000..70500f2
--- /dev/null
+++ b/src/testdir/test_feedkeys.vim
@@ -0,0 +1,14 @@
+" Test feedkeys() function.
+
+func Test_feedkeys_x_with_empty_string()
+ new
+ call feedkeys("ifoo\<Esc>")
+ call assert_equal('', getline('.'))
+ call feedkeys('', 'x')
+ call assert_equal('foo', getline('.'))
+
+ " check it goes back to normal mode immediately.
+ call feedkeys('i', 'x')
+ call assert_equal('foo', getline('.'))
+ quit!
+endfunc
diff --git a/src/testdir/test_file_perm.vim b/src/testdir/test_file_perm.vim
new file mode 100644
index 0000000..0dba6a7
--- /dev/null
+++ b/src/testdir/test_file_perm.vim
@@ -0,0 +1,24 @@
+" Test getting and setting file permissions.
+
+func Test_file_perm()
+ call assert_equal('', getfperm('Xtest'))
+ call assert_equal(0, setfperm('Xtest', 'r--------'))
+
+ call writefile(['one'], 'Xtest')
+ call assert_true(len(getfperm('Xtest')) == 9)
+
+ call assert_equal(1, setfperm('Xtest', 'rwx------'))
+ if has('win32')
+ call assert_equal('rw-rw-rw-', getfperm('Xtest'))
+ else
+ call assert_equal('rwx------', getfperm('Xtest'))
+ endif
+
+ call assert_equal(1, setfperm('Xtest', 'r--r--r--'))
+ call assert_equal('r--r--r--', getfperm('Xtest'))
+
+ call assert_fails("setfperm('Xtest', '---')")
+
+ call assert_equal(1, setfperm('Xtest', 'rwx------'))
+ call delete('Xtest')
+endfunc
diff --git a/src/testdir/test_file_size.vim b/src/testdir/test_file_size.vim
new file mode 100644
index 0000000..3e78a7b
--- /dev/null
+++ b/src/testdir/test_file_size.vim
@@ -0,0 +1,58 @@
+" Inserts 2 million lines with consecutive integers starting from 1
+" (essentially, the output of GNU's seq 1 2000000), writes them to Xtest
+" and writes its cksum to test.out.
+"
+" We need 2 million lines to trigger a call to mf_hash_grow(). If it would mess
+" up the lines the checksum would differ.
+"
+" cksum is part of POSIX and so should be available on most Unixes.
+" If it isn't available then the test will be skipped.
+func Test_File_Size()
+ if !executable('cksum')
+ return
+ endif
+
+ new
+ set fileformat=unix undolevels=-1
+ for i in range(1, 2000000, 100)
+ call append(i, range(i, i + 99))
+ endfor
+
+ 1delete
+ w! Xtest
+ let res = systemlist('cksum Xtest')[0]
+ let res = substitute(res, "\r", "", "")
+ call assert_equal('3678979763 14888896 Xtest', res)
+
+ enew!
+ call delete('Xtest')
+ set fileformat& undolevels&
+endfunc
+
+" Test for writing and reading a file of over 100 Kbyte
+func Test_File_Read_Write()
+ enew!
+
+ " Create a file with the following contents
+ " 1 line: "This is the start"
+ " 3001 lines: "This is the leader"
+ " 1 line: "This is the middle"
+ " 3001 lines: "This is the trailer"
+ " 1 line: "This is the end"
+ call append(0, "This is the start")
+ call append(1, repeat(["This is the leader"], 3001))
+ call append(3002, "This is the middle")
+ call append(3003, repeat(["This is the trailer"], 3001))
+ call append(6004, "This is the end")
+
+ write! Xtest
+ enew!
+ edit! Xtest
+
+ call assert_equal("This is the start", getline(1))
+ call assert_equal("This is the middle", getline(3003))
+ call assert_equal("This is the end", getline(6005))
+
+ enew!
+ call delete("Xtest")
+endfunc
diff --git a/src/testdir/test_filechanged.vim b/src/testdir/test_filechanged.vim
new file mode 100644
index 0000000..43f752d
--- /dev/null
+++ b/src/testdir/test_filechanged.vim
@@ -0,0 +1,146 @@
+" Tests for when a file was changed outside of Vim.
+
+func Test_FileChangedShell_reload()
+ if !has('unix')
+ return
+ endif
+ augroup testreload
+ au FileChangedShell Xchanged_r let g:reason = v:fcs_reason | let v:fcs_choice = 'reload'
+ augroup END
+ new Xchanged_r
+ call setline(1, 'reload this')
+ write
+ " Need to wait until the timestamp would change by at least a second.
+ sleep 2
+ silent !echo 'extra line' >>Xchanged_r
+ checktime
+ call assert_equal('changed', g:reason)
+ call assert_equal(2, line('$'))
+ call assert_equal('extra line', getline(2))
+
+ " Only triggers once
+ let g:reason = ''
+ checktime
+ call assert_equal('', g:reason)
+
+ " When deleted buffer is not reloaded
+ silent !rm Xchanged_r
+ let g:reason = ''
+ checktime
+ call assert_equal('deleted', g:reason)
+ call assert_equal(2, line('$'))
+ call assert_equal('extra line', getline(2))
+
+ " When recreated buffer is reloaded
+ call setline(1, 'buffer is changed')
+ silent !echo 'new line' >>Xchanged_r
+ let g:reason = ''
+ checktime
+ call assert_equal('conflict', g:reason)
+ call assert_equal(1, line('$'))
+ call assert_equal('new line', getline(1))
+
+ " Only mode changed
+ silent !chmod +x Xchanged_r
+ let g:reason = ''
+ checktime
+ call assert_equal('mode', g:reason)
+ call assert_equal(1, line('$'))
+ call assert_equal('new line', getline(1))
+
+ " Only time changed
+ sleep 2
+ silent !touch Xchanged_r
+ let g:reason = ''
+ checktime
+ call assert_equal('time', g:reason)
+ call assert_equal(1, line('$'))
+ call assert_equal('new line', getline(1))
+
+ if has('persistent_undo')
+ " With an undo file the reload can be undone and a change before the
+ " reload.
+ set undofile
+ call setline(2, 'before write')
+ write
+ call setline(2, 'after write')
+ sleep 2
+ silent !echo 'different line' >>Xchanged_r
+ let g:reason = ''
+ checktime
+ call assert_equal('conflict', g:reason)
+ call assert_equal(3, line('$'))
+ call assert_equal('before write', getline(2))
+ call assert_equal('different line', getline(3))
+ " undo the reload
+ undo
+ call assert_equal(2, line('$'))
+ call assert_equal('after write', getline(2))
+ " undo the change before reload
+ undo
+ call assert_equal(2, line('$'))
+ call assert_equal('before write', getline(2))
+
+ set noundofile
+ endif
+
+ au! testreload
+ bwipe!
+ call delete('Xchanged_r')
+endfunc
+
+func Test_file_changed_dialog()
+ if !has('unix') || has('gui_running')
+ return
+ endif
+ au! FileChangedShell
+
+ new Xchanged_d
+ call setline(1, 'reload this')
+ write
+ " Need to wait until the timestamp would change by at least a second.
+ sleep 2
+ silent !echo 'extra line' >>Xchanged_d
+ call feedkeys('L', 'L')
+ checktime
+ call assert_match('W11:', v:warningmsg)
+ call assert_equal(2, line('$'))
+ call assert_equal('reload this', getline(1))
+ call assert_equal('extra line', getline(2))
+
+ " delete buffer, only shows an error, no prompt
+ silent !rm Xchanged_d
+ checktime
+ call assert_match('E211:', v:warningmsg)
+ call assert_equal(2, line('$'))
+ call assert_equal('extra line', getline(2))
+
+ " Recreate buffer and reload
+ call setline(1, 'buffer is changed')
+ silent !echo 'new line' >Xchanged_d
+ call feedkeys('L', 'L')
+ checktime
+ call assert_match('W12:', v:warningmsg)
+ call assert_equal(1, line('$'))
+ call assert_equal('new line', getline(1))
+
+ " Only mode changed, reload
+ silent !chmod +x Xchanged_d
+ call feedkeys('L', 'L')
+ checktime
+ call assert_match('W16:', v:warningmsg)
+ call assert_equal(1, line('$'))
+ call assert_equal('new line', getline(1))
+
+ " Only time changed, no prompt
+ sleep 2
+ silent !touch Xchanged_d
+ let v:warningmsg = ''
+ checktime
+ call assert_equal('', v:warningmsg)
+ call assert_equal(1, line('$'))
+ call assert_equal('new line', getline(1))
+
+ bwipe!
+ call delete('Xchanged_d')
+endfunc
diff --git a/src/testdir/test_fileformat.vim b/src/testdir/test_fileformat.vim
new file mode 100644
index 0000000..8dc25f6
--- /dev/null
+++ b/src/testdir/test_fileformat.vim
@@ -0,0 +1,33 @@
+" Test behavior of fileformat after bwipeout of last buffer
+
+func Test_fileformat_after_bw()
+ bwipeout
+ set fileformat&
+ if &fileformat == 'dos'
+ let test_fileformats = 'unix'
+ elseif &fileformat == 'unix'
+ let test_fileformats = 'mac'
+ else " must be mac
+ let test_fileformats = 'dos'
+ endif
+ exec 'set fileformats='.test_fileformats
+ bwipeout!
+ call assert_equal(test_fileformats, &fileformat)
+ set fileformats&
+endfunc
+
+func Test_fileformat_autocommand()
+ let filecnt = ["", "foobar\<CR>", "eins\<CR>", "\<CR>", "zwei\<CR>", "drei", "vier", "fünf", ""]
+ let ffs = &ffs
+ call writefile(filecnt, 'Xfile', 'b')
+ au BufReadPre Xfile set ffs=dos ff=dos
+ new Xfile
+ call assert_equal('dos', &l:ff)
+ call assert_equal('dos', &ffs)
+
+ " cleanup
+ call delete('Xfile')
+ let &ffs = ffs
+ au! BufReadPre Xfile
+ bw!
+endfunc
diff --git a/src/testdir/test_filetype.vim b/src/testdir/test_filetype.vim
new file mode 100644
index 0000000..fd2f383
--- /dev/null
+++ b/src/testdir/test_filetype.vim
@@ -0,0 +1,603 @@
+" Test :setfiletype
+
+func Test_detection()
+ filetype on
+ augroup filetypedetect
+ au BufNewFile,BufRead * call assert_equal(1, did_filetype())
+ augroup END
+ new something.vim
+ call assert_equal('vim', &filetype)
+
+ bwipe!
+ filetype off
+endfunc
+
+func Test_conf_type()
+ filetype on
+ call writefile(['# some comment', 'must be conf'], 'Xfile')
+ augroup filetypedetect
+ au BufNewFile,BufRead * call assert_equal(0, did_filetype())
+ augroup END
+ split Xfile
+ call assert_equal('conf', &filetype)
+
+ bwipe!
+ call delete('Xfile')
+ filetype off
+endfunc
+
+func Test_other_type()
+ filetype on
+ augroup filetypedetect
+ au BufNewFile,BufRead * call assert_equal(0, did_filetype())
+ au BufNewFile,BufRead Xfile setf testfile
+ au BufNewFile,BufRead * call assert_equal(1, did_filetype())
+ augroup END
+ call writefile(['# some comment', 'must be conf'], 'Xfile')
+ split Xfile
+ call assert_equal('testfile', &filetype)
+
+ bwipe!
+ call delete('Xfile')
+ filetype off
+endfunc
+
+" Filetypes detected just from matching the file name.
+let s:filename_checks = {
+ \ 'a2ps': ['/etc/a2ps.cfg', '/etc/a2ps/file.cfg', 'a2psrc', '.a2psrc'],
+ \ 'a65': ['file.a65'],
+ \ 'abap': ['file.abap'],
+ \ 'abc': ['file.abc'],
+ \ 'abel': ['file.abl'],
+ \ 'acedb': ['file.wrm'],
+ \ 'ada': ['file.adb', 'file.ads', 'file.ada', 'file.gpr'],
+ \ 'ahdl': ['file.tdf'],
+ \ 'alsaconf': ['.asoundrc', '/usr/share/alsa/alsa.conf', '/etc/asound.conf'],
+ \ 'aml': ['file.aml'],
+ \ 'ampl': ['file.run'],
+ \ 'ant': ['build.xml'],
+ \ 'apache': ['.htaccess', '/etc/httpd/file.conf'],
+ \ 'applescript': ['file.scpt'],
+ \ 'aptconf': ['apt.conf', '/.aptitude/config'],
+ \ 'arch': ['.arch-inventory'],
+ \ 'arduino': ['file.ino', 'file.pde'],
+ \ 'art': ['file.art'],
+ \ 'asciidoc': ['file.asciidoc', 'file.adoc'],
+ \ 'asn': ['file.asn', 'file.asn1'],
+ \ 'atlas': ['file.atl', 'file.as'],
+ \ 'autohotkey': ['file.ahk'],
+ \ 'autoit': ['file.au3'],
+ \ 'automake': ['GNUmakefile.am'],
+ \ 'ave': ['file.ave'],
+ \ 'awk': ['file.awk'],
+ \ 'b': ['file.mch', 'file.ref', 'file.imp'],
+ \ 'bc': ['file.bc'],
+ \ 'bdf': ['file.bdf'],
+ \ 'bib': ['file.bib'],
+ \ 'bindzone': ['named.root'],
+ \ 'blank': ['file.bl'],
+ \ 'bst': ['file.bst'],
+ \ 'bzr': ['bzr_log.any'],
+ \ 'c': ['enlightenment/file.cfg', 'file.qc', 'file.c'],
+ \ 'cabal': ['file.cabal'],
+ \ 'calendar': ['calendar'],
+ \ 'catalog': ['catalog'],
+ \ 'cdl': ['file.cdl'],
+ \ 'cdrdaoconf': ['/etc/cdrdao.conf', '/etc/defaults/cdrdao', '/etc/default/cdrdao', '.cdrdao'],
+ \ 'cdrtoc': ['file.toc'],
+ \ 'cf': ['file.cfm', 'file.cfi', 'file.cfc'],
+ \ 'cfengine': ['cfengine.conf'],
+ \ 'cfg': ['file.cfg', 'file.hgrc', 'filehgrc'],
+ \ 'ch': ['file.chf'],
+ \ 'chaiscript': ['file.chai'],
+ \ 'chaskell': ['file.chs'],
+ \ 'chill': ['file..ch'],
+ \ 'chordpro': ['file.chopro', 'file.crd', 'file.cho', 'file.crdpro', 'file.chordpro'],
+ \ 'cl': ['file.eni'],
+ \ 'clean': ['file.dcl', 'file.icl'],
+ \ 'clojure': ['file.clj', 'file.cljs', 'file.cljx', 'file.cljc'],
+ \ 'cmake': ['CMakeLists.txt', 'file.cmake', 'file.cmake.in'],
+ \ 'cmusrc': ['any/.cmus/autosave', 'any/.cmus/rc', 'any/.cmus/command-history', 'any/.cmus/file.theme', 'any/cmus/rc', 'any/cmus/file.theme'],
+ \ 'cobol': ['file.cbl', 'file.cob', 'file.lib'],
+ \ 'coco': ['file.atg'],
+ \ 'conaryrecipe': ['file.recipe'],
+ \ 'conf': ['auto.master'],
+ \ 'config': ['configure.in', 'configure.ac'],
+ \ 'context': ['tex/context/any/file.tex', 'file.mkii', 'file.mkiv', 'file.mkvi'],
+ \ 'cpp': ['file.cxx', 'file.c++', 'file.hh', 'file.hxx', 'file.hpp', 'file.ipp', 'file.moc', 'file.tcc', 'file.inl', 'file.tlh'],
+ \ 'crm': ['file.crm'],
+ \ 'cs': ['file.cs'],
+ \ 'csc': ['file.csc'],
+ \ 'csdl': ['file.csdl'],
+ \ 'csp': ['file.csp', 'file.fdr'],
+ \ 'css': ['file.css'],
+ \ 'cterm': ['file.con'],
+ \ 'cucumber': ['file.feature'],
+ \ 'cuda': ['file.cu'],
+ \ 'cupl': ['file.pld'],
+ \ 'cuplsim': ['file.si'],
+ \ 'cvs': ['cvs123'],
+ \ 'cvsrc': ['.cvsrc'],
+ \ 'cynpp': ['file.cyn'],
+ \ 'datascript': ['file.ds'],
+ \ 'dcd': ['file.dcd'],
+ \ 'debcontrol': ['/debian/control'],
+ \ 'debsources': ['/etc/apt/sources.list', '/etc/apt/sources.list.d/file.list'],
+ \ 'def': ['file.def'],
+ \ 'denyhosts': ['denyhosts.conf'],
+ \ 'desc': ['file.desc'],
+ \ 'desktop': ['file.desktop', '.directory'],
+ \ 'dictconf': ['dict.conf', '.dictrc'],
+ \ 'dictdconf': ['dictd.conf'],
+ \ 'diff': ['file.diff', 'file.rej'],
+ \ 'dircolors': ['.dir_colors', '.dircolors', '/etc/DIR_COLORS'],
+ \ 'dnsmasq': ['/etc/dnsmasq.conf'],
+ \ 'dockerfile': ['Dockerfile', 'file.Dockerfile'],
+ \ 'dosbatch': ['file.bat', 'file.sys'],
+ \ 'dosini': ['.editorconfig', '/etc/yum.conf', 'file.ini'],
+ \ 'dot': ['file.dot'],
+ \ 'dracula': ['file.drac', 'file.drc', 'filelvs', 'filelpe'],
+ \ 'dsl': ['file.dsl'],
+ \ 'dtd': ['file.dtd'],
+ \ 'dts': ['file.dts', 'file.dtsi'],
+ \ 'dylan': ['file.dylan'],
+ \ 'dylanintr': ['file.intr'],
+ \ 'dylanlid': ['file.lid'],
+ \ 'ecd': ['file.ecd'],
+ \ 'edif': ['file.edf', 'file.edif', 'file.edo'],
+ \ 'elinks': ['/etc/elinks.conf', '/.elinks/elinks.conf'],
+ \ 'elmfilt': ['filter-rules'],
+ \ 'erlang': ['file.erl', 'file.hrl', 'file.yaws'],
+ \ 'eruby': ['file.erb', 'file.rhtml'],
+ \ 'esmtprc': ['anyesmtprc'],
+ \ 'esqlc': ['file.ec', 'file.EC'],
+ \ 'esterel': ['file.strl'],
+ \ 'eterm': ['anyEterm/file.cfg'],
+ \ 'exim': ['exim.conf'],
+ \ 'expect': ['file.exp'],
+ \ 'exports': ['exports'],
+ \ 'factor': ['file.factor'],
+ \ 'falcon': ['file.fal'],
+ \ 'fan': ['file.fan', 'file.fwt'],
+ \ 'fetchmail': ['.fetchmailrc'],
+ \ 'fgl': ['file.4gl', 'file.4gh', 'file.m4gl'],
+ \ 'focexec': ['file.fex', 'file.focexec'],
+ \ 'forth': ['file.fs', 'file.ft', 'file.fth'],
+ \ 'fortran': ['file.f', 'file.for', 'file.fortran', 'file.fpp', 'file.ftn', 'file.f77', 'file.f90', 'file.f95', 'file.f03', 'file.f08'],
+ \ 'framescript': ['file.fsl'],
+ \ 'freebasic': ['file.fb', 'file.bi'],
+ \ 'fstab': ['fstab', 'mtab'],
+ \ 'gdb': ['.gdbinit'],
+ \ 'gdmo': ['file.mo', 'file.gdmo'],
+ \ 'gedcom': ['file.ged', 'lltxxxxx.txt'],
+ \ 'gitcommit': ['COMMIT_EDITMSG', 'MERGE_MSG', 'TAG_EDITMSG'],
+ \ 'gitconfig': ['file.git/config', '.gitconfig', '.gitmodules', 'file.git/modules//config', '/.config/git/config', '/etc/gitconfig'],
+ \ 'gitolite': ['gitolite.conf'],
+ \ 'gitrebase': ['git-rebase-todo'],
+ \ 'gitsendemail': ['.gitsendemail.msg.xxxxxx'],
+ \ 'gkrellmrc': ['gkrellmrc', 'gkrellmrc_x'],
+ \ 'gnash': ['gnashrc', '.gnashrc', 'gnashpluginrc', '.gnashpluginrc'],
+ \ 'gnuplot': ['file.gpi'],
+ \ 'go': ['file.go'],
+ \ 'gp': ['file.gp', '.gprc'],
+ \ 'gpg': ['/.gnupg/options', '/.gnupg/gpg.conf', '/usr/any/gnupg/options.skel'],
+ \ 'grads': ['file.gs'],
+ \ 'gretl': ['file.gretl'],
+ \ 'groovy': ['file.gradle', 'file.groovy'],
+ \ 'group': ['any/etc/group', 'any/etc/group-', 'any/etc/group.edit', 'any/etc/gshadow', 'any/etc/gshadow-', 'any/etc/gshadow.edit', 'any/var/backups/group.bak', 'any/var/backups/gshadow.bak'],
+ \ 'grub': ['/boot/grub/menu.lst', '/boot/grub/grub.conf', '/etc/grub.conf'],
+ \ 'gsp': ['file.gsp'],
+ \ 'gtkrc': ['.gtkrc', 'gtkrc'],
+ \ 'haml': ['file.haml'],
+ \ 'hamster': ['file.hsc', 'file.hsm'],
+ \ 'haskell': ['file.hs', 'file.hs-boot'],
+ \ 'haste': ['file.ht'],
+ \ 'hastepreproc': ['file.htpp'],
+ \ 'hb': ['file.hb'],
+ \ 'hercules': ['file.vc', 'file.ev', 'file.sum', 'file.errsum'],
+ \ 'hex': ['file.hex', 'file.h32'],
+ \ 'hgcommit': ['hg-editor-file.txt'],
+ \ 'hog': ['file.hog', 'snort.conf', 'vision.conf'],
+ \ 'hostconf': ['/etc/host.conf'],
+ \ 'hostsaccess': ['/etc/hosts.allow', '/etc/hosts.deny'],
+ \ 'htmlcheetah': ['file.tmpl'],
+ \ 'htmlm4': ['file.html.m4'],
+ \ 'httest': ['file.htt', 'file.htb'],
+ \ 'ibasic': ['file.iba', 'file.ibi'],
+ \ 'icemenu': ['/.icewm/menu'],
+ \ 'icon': ['file.icn'],
+ \ 'indent': ['.indent.pro', 'indentrc'],
+ \ 'inform': ['file.inf', 'file.INF'],
+ \ 'initng': ['/etc/initng/any/file.i', 'file.ii'],
+ \ 'inittab': ['inittab'],
+ \ 'ipfilter': ['ipf.conf', 'ipf6.conf', 'ipf.rules'],
+ \ 'iss': ['file.iss'],
+ \ 'ist': ['file.ist', 'file.mst'],
+ \ 'j': ['file.ijs'],
+ \ 'jal': ['file.jal', 'file.JAL'],
+ \ 'jam': ['file.jpl', 'file.jpr'],
+ \ 'java': ['file.java', 'file.jav'],
+ \ 'javacc': ['file.jj', 'file.jjt'],
+ \ 'javascript': ['file.js', 'file.javascript', 'file.es', 'file.jsx', 'file.mjs'],
+ \ 'jess': ['file.clp'],
+ \ 'jgraph': ['file.jgr'],
+ \ 'jovial': ['file.jov', 'file.j73', 'file.jovial'],
+ \ 'jproperties': ['file.properties', 'file.properties_xx', 'file.properties_xx_xx'],
+ \ 'json': ['file.json', 'file.jsonp', 'file.webmanifest'],
+ \ 'jsp': ['file.jsp'],
+ \ 'kconfig': ['Kconfig', 'Kconfig.debug'],
+ \ 'kivy': ['file.kv'],
+ \ 'kix': ['file.kix'],
+ \ 'kscript': ['file.ks'],
+ \ 'kwt': ['file.k'],
+ \ 'lace': ['file.ace', 'file.ACE'],
+ \ 'latte': ['file.latte', 'file.lte'],
+ \ 'ld': ['file.ld'],
+ \ 'ldif': ['file.ldif'],
+ \ 'less': ['file.less'],
+ \ 'lex': ['file.lex', 'file.l', 'file.lxx', 'file.l++'],
+ \ 'lftp': ['lftp.conf', '.lftprc', 'anylftp/rc'],
+ \ 'lhaskell': ['file.lhs'],
+ \ 'libao': ['/etc/libao.conf', '/.libao'],
+ \ 'lifelines': ['file.ll'],
+ \ 'lilo': ['lilo.conf'],
+ \ 'limits': ['/etc/limits', '/etc/anylimits.conf', '/etc/anylimits.d/file.conf'],
+ \ 'liquid': ['file.liquid'],
+ \ 'lisp': ['sbclrc', '.sbclrc'],
+ \ 'lite': ['file.lite', 'file.lt'],
+ \ 'litestep': ['/LiteStep/any/file.rc'],
+ \ 'loginaccess': ['/etc/login.access'],
+ \ 'logindefs': ['/etc/login.defs'],
+ \ 'logtalk': ['file.lgt'],
+ \ 'lotos': ['file.lot', 'file.lotos'],
+ \ 'lout': ['file.lou', 'file.lout'],
+ \ 'lprolog': ['file.sig'],
+ \ 'lsl': ['file.lsl'],
+ \ 'lss': ['file.lss'],
+ \ 'lua': ['file.lua', 'file.rockspec', 'file.nse'],
+ \ 'lynx': ['lynx.cfg'],
+ \ 'm4': ['file.at'],
+ \ 'mail': ['snd.123', '.letter', '.letter.123', '.followup', '.article', '.article.123', 'pico.123', 'mutt-xx-xxx', 'muttng-xx-xxx', 'ae123.txt', 'file.eml'],
+ \ 'mailaliases': ['/etc/mail/aliases', '/etc/aliases'],
+ \ 'mailcap': ['.mailcap', 'mailcap'],
+ \ 'make': ['file.mk', 'file.mak', 'file.dsp'],
+ \ 'mallard': ['file.page'],
+ \ 'man': ['file.man'],
+ \ 'manconf': ['/etc/man.conf', 'man.config'],
+ \ 'map': ['file.map'],
+ \ 'maple': ['file.mv', 'file.mpl', 'file.mws'],
+ \ 'markdown': ['file.markdown', 'file.mdown', 'file.mkd', 'file.mkdn', 'file.mdwn', 'file.md'],
+ \ 'mason': ['file.mason', 'file.mhtml', 'file.comp'],
+ \ 'master': ['file.mas', 'file.master'],
+ \ 'mel': ['file.mel'],
+ \ 'messages': ['/log/auth', '/log/cron', '/log/daemon', '/log/debug', '/log/kern', '/log/lpr', '/log/mail', '/log/messages', '/log/news/news', '/log/syslog', '/log/user',
+ \ '/log/auth.log', '/log/cron.log', '/log/daemon.log', '/log/debug.log', '/log/kern.log', '/log/lpr.log', '/log/mail.log', '/log/messages.log', '/log/news/news.log', '/log/syslog.log', '/log/user.log',
+ \ '/log/auth.err', '/log/cron.err', '/log/daemon.err', '/log/debug.err', '/log/kern.err', '/log/lpr.err', '/log/mail.err', '/log/messages.err', '/log/news/news.err', '/log/syslog.err', '/log/user.err',
+ \ '/log/auth.info', '/log/cron.info', '/log/daemon.info', '/log/debug.info', '/log/kern.info', '/log/lpr.info', '/log/mail.info', '/log/messages.info', '/log/news/news.info', '/log/syslog.info', '/log/user.info',
+ \ '/log/auth.warn', '/log/cron.warn', '/log/daemon.warn', '/log/debug.warn', '/log/kern.warn', '/log/lpr.warn', '/log/mail.warn', '/log/messages.warn', '/log/news/news.warn', '/log/syslog.warn', '/log/user.warn',
+ \ '/log/auth.crit', '/log/cron.crit', '/log/daemon.crit', '/log/debug.crit', '/log/kern.crit', '/log/lpr.crit', '/log/mail.crit', '/log/messages.crit', '/log/news/news.crit', '/log/syslog.crit', '/log/user.crit',
+ \ '/log/auth.notice', '/log/cron.notice', '/log/daemon.notice', '/log/debug.notice', '/log/kern.notice', '/log/lpr.notice', '/log/mail.notice', '/log/messages.notice', '/log/news/news.notice', '/log/syslog.notice', '/log/user.notice'],
+ \ 'mf': ['file.mf'],
+ \ 'mgl': ['file.mgl'],
+ \ 'mgp': ['file.mgp'],
+ \ 'mib': ['file.mib', 'file.my'],
+ \ 'mix': ['file.mix', 'file.mixal'],
+ \ 'mma': ['file.nb'],
+ \ 'mmp': ['file.mmp'],
+ \ 'modconf': ['/etc/modules.conf', '/etc/modules', '/etc/conf.modules'],
+ \ 'modula2': ['file.m2', 'file.mi'],
+ \ 'monk': ['file.isc', 'file.monk', 'file.ssc', 'file.tsc'],
+ \ 'moo': ['file.moo'],
+ \ 'mp': ['file.mp'],
+ \ 'mplayerconf': ['mplayer.conf', '/.mplayer/config'],
+ \ 'mrxvtrc': ['mrxvtrc', '.mrxvtrc'],
+ \ 'msidl': ['file.odl', 'file.mof'],
+ \ 'msql': ['file.msql'],
+ \ 'mupad': ['file.mu'],
+ \ 'mush': ['file.mush'],
+ \ 'muttrc': ['Muttngrc', 'Muttrc'],
+ \ 'mysql': ['file.mysql'],
+ \ 'n1ql': ['file.n1ql', 'file.nql'],
+ \ 'named': ['namedfile.conf', 'rndcfile.conf'],
+ \ 'nanorc': ['/etc/nanorc', 'file.nanorc'],
+ \ 'ncf': ['file.ncf'],
+ \ 'netrc': ['.netrc'],
+ \ 'ninja': ['file.ninja'],
+ \ 'nqc': ['file.nqc'],
+ \ 'nroff': ['file.tr', 'file.nr', 'file.roff', 'file.tmac', 'file.mom'],
+ \ 'nsis': ['file.nsi', 'file.nsh'],
+ \ 'obj': ['file.obj'],
+ \ 'ocaml': ['file.ml', 'file.mli', 'file.mll', 'file.mly', '.ocamlinit'],
+ \ 'occam': ['file.occ'],
+ \ 'omnimark': ['file.xom', 'file.xin'],
+ \ 'openroad': ['file.or'],
+ \ 'ora': ['file.ora'],
+ \ 'pamconf': ['/etc/pam.conf'],
+ \ 'papp': ['file.papp', 'file.pxml', 'file.pxsl'],
+ \ 'pascal': ['file.pas', 'file.dpr'],
+ \ 'passwd': ['any/etc/passwd', 'any/etc/passwd-', 'any/etc/passwd.edit', 'any/etc/shadow', 'any/etc/shadow-', 'any/etc/shadow.edit', 'any/var/backups/passwd.bak', 'any/var/backups/shadow.bak'],
+ \ 'pccts': ['file.g'],
+ \ 'pdf': ['file.pdf'],
+ \ 'perl': ['file.plx', 'file.al', 'file.psgi', 'gitolite.rc', '.gitolite.rc', 'example.gitolite.rc'],
+ \ 'perl6': ['file.p6', 'file.pm6', 'file.pl6'],
+ \ 'pf': ['pf.conf'],
+ \ 'pfmain': ['main.cf'],
+ \ 'php': ['file.php', 'file.php9', 'file.phtml', 'file.ctp'],
+ \ 'lpc': ['file.lpc', 'file.ulpc'],
+ \ 'pike': ['file.pike', 'file.pmod'],
+ \ 'cmod': ['file.cmod'],
+ \ 'pilrc': ['file.rcp'],
+ \ 'pine': ['.pinerc', 'pinerc', '.pinercex', 'pinercex'],
+ \ 'pinfo': ['/etc/pinforc', '/.pinforc'],
+ \ 'pli': ['file.pli', 'file.pl1'],
+ \ 'plm': ['file.plm', 'file.p36', 'file.pac'],
+ \ 'plp': ['file.plp'],
+ \ 'plsql': ['file.pls', 'file.plsql'],
+ \ 'po': ['file.po', 'file.pot'],
+ \ 'pod': ['file.pod'],
+ \ 'pod6': ['file.pod6'],
+ \ 'postscr': ['file.ps', 'file.pfa', 'file.afm', 'file.eps', 'file.epsf', 'file.epsi', 'file.ai'],
+ \ 'pov': ['file.pov'],
+ \ 'povini': ['.povrayrc'],
+ \ 'ppd': ['file.ppd'],
+ \ 'ppwiz': ['file.it', 'file.ih'],
+ \ 'privoxy': ['file.action'],
+ \ 'proc': ['file.pc'],
+ \ 'procmail': ['.procmail', '.procmailrc'],
+ \ 'prolog': ['file.pdb'],
+ \ 'promela': ['file.pml'],
+ \ 'proto': ['file.proto'],
+ \ 'protocols': ['/etc/protocols'],
+ \ 'psf': ['file.psf'],
+ \ 'pyrex': ['file.pyx', 'file.pxd'],
+ \ 'python': ['file.py', 'file.pyw', '.pythonstartup', '.pythonrc', 'file.ptl', 'file.pyi'],
+ \ 'quake': ['anybaseq2/file.cfg', 'anyid1/file.cfg', 'quake3/file.cfg'],
+ \ 'radiance': ['file.rad', 'file.mat'],
+ \ 'ratpoison': ['.ratpoisonrc', 'ratpoisonrc'],
+ \ 'rc': ['file.rc', 'file.rch'],
+ \ 'rcs': ['file,v'],
+ \ 'readline': ['.inputrc', 'inputrc'],
+ \ 'remind': ['.reminders', 'file.remind', 'file.rem'],
+ \ 'resolv': ['resolv.conf'],
+ \ 'reva': ['file.frt'],
+ \ 'rexx': ['file.rex', 'file.orx', 'file.rxo', 'file.rxj', 'file.jrexx', 'file.rexxj', 'file.rexx', 'file.testGroup', 'file.testUnit'],
+ \ 'rib': ['file.rib'],
+ \ 'rnc': ['file.rnc'],
+ \ 'rng': ['file.rng'],
+ \ 'robots': ['robots.txt'],
+ \ 'rpcgen': ['file.x'],
+ \ 'rpl': ['file.rpl'],
+ \ 'rst': ['file.rst'],
+ \ 'rtf': ['file.rtf'],
+ \ 'ruby': ['.irbrc', 'irbrc', 'file.rb', 'file.rbw', 'file.gemspec', 'file.ru', 'Gemfile', 'file.builder', 'file.rxml', 'file.rjs', 'file.rant', 'file.rake'],
+ \ 'rust': ['file.rs'],
+ \ 'samba': ['smb.conf'],
+ \ 'sas': ['file.sas'],
+ \ 'sass': ['file.sass'],
+ \ 'sather': ['file.sa'],
+ \ 'sbt': ['file.sbt'],
+ \ 'scala': ['file.scala'],
+ \ 'scheme': ['file.scm', 'file.ss', 'file.rkt'],
+ \ 'scilab': ['file.sci', 'file.sce'],
+ \ 'screen': ['.screenrc', 'screenrc'],
+ \ 'scss': ['file.scss'],
+ \ 'sd': ['file.sd'],
+ \ 'sdc': ['file.sdc'],
+ \ 'sdl': ['file.sdl', 'file.pr'],
+ \ 'sed': ['file.sed'],
+ \ 'sensors': ['/etc/sensors.conf', '/etc/sensors3.conf'],
+ \ 'services': ['/etc/services'],
+ \ 'setserial': ['/etc/serial.conf'],
+ \ 'sh': ['/etc/udev/cdsymlinks.conf'],
+ \ 'sieve': ['file.siv', 'file.sieve'],
+ \ 'simula': ['file.sim'],
+ \ 'sinda': ['file.sin', 'file.s85'],
+ \ 'sisu': ['file.sst', 'file.ssm', 'file.ssi', 'file.-sst', 'file._sst', 'file.sst.meta', 'file.-sst.meta', 'file._sst.meta'],
+ \ 'skill': ['file.il', 'file.ils', 'file.cdf'],
+ \ 'slang': ['file.sl'],
+ \ 'slice': ['file.ice'],
+ \ 'slpconf': ['/etc/slp.conf'],
+ \ 'slpreg': ['/etc/slp.reg'],
+ \ 'slpspi': ['/etc/slp.spi'],
+ \ 'slrnrc': ['.slrnrc'],
+ \ 'slrnsc': ['file.score'],
+ \ 'sm': ['sendmail.cf'],
+ \ 'smarty': ['file.tpl'],
+ \ 'smcl': ['file.hlp', 'file.ihlp', 'file.smcl'],
+ \ 'smith': ['file.smt', 'file.smith'],
+ \ 'sml': ['file.sml'],
+ \ 'snobol4': ['file.sno', 'file.spt'],
+ \ 'spec': ['file.spec'],
+ \ 'spice': ['file.sp', 'file.spice'],
+ \ 'spup': ['file.speedup', 'file.spdata', 'file.spd'],
+ \ 'spyce': ['file.spy', 'file.spi'],
+ \ 'sql': ['file.tyb', 'file.typ', 'file.tyc', 'file.pkb', 'file.pks'],
+ \ 'sqlj': ['file.sqlj'],
+ \ 'sqr': ['file.sqr', 'file.sqi'],
+ \ 'squid': ['squid.conf'],
+ \ 'srec': ['file.s19', 'file.s28', 'file.s37', 'file.mot', 'file.srec'],
+ \ 'sshconfig': ['ssh_config', '/.ssh/config'],
+ \ 'sshdconfig': ['sshd_config'],
+ \ 'st': ['file.st'],
+ \ 'stata': ['file.ado', 'file.do', 'file.imata', 'file.mata'],
+ \ 'stp': ['file.stp'],
+ \ 'sudoers': ['any/etc/sudoers', 'sudoers.tmp'],
+ \ 'svg': ['file.svg'],
+ \ 'svn': ['svn-commitfile.tmp'],
+ \ 'sysctl': ['/etc/sysctl.conf', '/etc/sysctl.d/file.conf'],
+ \ 'systemd': ['any/systemd/file.automount', 'any/systemd/file.mount', 'any/systemd/file.path', 'any/systemd/file.service', 'any/systemd/file.socket', 'any/systemd/file.swap', 'any/systemd/file.target', 'any/systemd/file.timer'],
+ \ 'systemverilog': ['file.sv', 'file.svh'],
+ \ 'tags': ['tags'],
+ \ 'tak': ['file.tak'],
+ \ 'taskdata': ['pending.data', 'completed.data', 'undo.data'],
+ \ 'taskedit': ['file.task'],
+ \ 'tcl': ['file.tcl', 'file.tk', 'file.itcl', 'file.itk', 'file.jacl'],
+ \ 'teraterm': ['file.ttl'],
+ \ 'terminfo': ['file.ti'],
+ \ 'tex': ['file.latex', 'file.sty', 'file.dtx', 'file.ltx', 'file.bbl'],
+ \ 'texinfo': ['file.texinfo', 'file.texi', 'file.txi'],
+ \ 'texmf': ['texmf.cnf'],
+ \ 'text': ['file.text', 'README'],
+ \ 'tf': ['file.tf', '.tfrc', 'tfrc'],
+ \ 'tidy': ['.tidyrc', 'tidyrc'],
+ \ 'tilde': ['file.t.html'],
+ \ 'tli': ['file.tli'],
+ \ 'tmux': ['tmuxfile.conf', '.tmuxfile.conf'],
+ \ 'tpp': ['file.tpp'],
+ \ 'treetop': ['file.treetop'],
+ \ 'trustees': ['trustees.conf'],
+ \ 'tsalt': ['file.slt'],
+ \ 'tsscl': ['file.tsscl'],
+ \ 'tssgm': ['file.tssgm'],
+ \ 'tssop': ['file.tssop'],
+ \ 'twig': ['file.twig'],
+ \ 'uc': ['file.uc'],
+ \ 'udevconf': ['/etc/udev/udev.conf'],
+ \ 'udevperm': ['/etc/udev/permissions.d/file.permissions'],
+ \ 'uil': ['file.uit', 'file.uil'],
+ \ 'updatedb': ['/etc/updatedb.conf'],
+ \ 'upstart': ['/usr/share/upstart/file.conf', '/usr/share/upstart/file.override', '/etc/init/file.conf', '/etc/init/file.override', '/.init/file.conf', '/.init/file.override', '/.config/upstart/file.conf', '/.config/upstart/file.override'],
+ \ 'upstreamdat': ['upstream.dat', 'UPSTREAM.DAT', 'upstream.file.dat', 'UPSTREAM.FILE.DAT', 'file.upstream.dat', 'FILE.UPSTREAM.DAT'],
+ \ 'upstreaminstalllog': ['upstreaminstall.log', 'UPSTREAMINSTALL.LOG', 'upstreaminstall.file.log', 'UPSTREAMINSTALL.FILE.LOG', 'file.upstreaminstall.log', 'FILE.UPSTREAMINSTALL.LOG'],
+ \ 'upstreamlog': ['fdrupstream.log', 'upstream.log', 'UPSTREAM.LOG', 'upstream.file.log', 'UPSTREAM.FILE.LOG', 'file.upstream.log', 'FILE.UPSTREAM.LOG', 'UPSTREAM-file.log', 'UPSTREAM-FILE.LOG'],
+ \ 'usserverlog': ['usserver.log', 'USSERVER.LOG', 'usserver.file.log', 'USSERVER.FILE.LOG', 'file.usserver.log', 'FILE.USSERVER.LOG'],
+ \ 'usw2kagtlog': ['usw2kagt.log', 'USW2KAGT.LOG', 'usw2kagt.file.log', 'USW2KAGT.FILE.LOG', 'file.usw2kagt.log', 'FILE.USW2KAGT.LOG'],
+ \ 'vb': ['file.sba', 'file.vb', 'file.vbs', 'file.dsm', 'file.ctl'],
+ \ 'vera': ['file.vr', 'file.vri', 'file.vrh'],
+ \ 'verilog': ['file.v'],
+ \ 'verilogams': ['file.va', 'file.vams'],
+ \ 'vgrindefs': ['vgrindefs'],
+ \ 'vhdl': ['file.hdl', 'file.vhd', 'file.vhdl', 'file.vbe', 'file.vst'],
+ \ 'vim': ['file.vim', 'file.vba', '.exrc', '_exrc'],
+ \ 'viminfo': ['.viminfo', '_viminfo'],
+ \ 'vmasm': ['file.mar'],
+ \ 'voscm': ['file.cm'],
+ \ 'vrml': ['file.wrl'],
+ \ 'vroom': ['file.vroom'],
+ \ 'wast': ['file.wast', 'file.wat'],
+ \ 'webmacro': ['file.wm'],
+ \ 'wget': ['.wgetrc', 'wgetrc'],
+ \ 'winbatch': ['file.wbt'],
+ \ 'wml': ['file.wml'],
+ \ 'wsml': ['file.wsml'],
+ \ 'wvdial': ['wvdial.conf', '.wvdialrc'],
+ \ 'xdefaults': ['.Xdefaults', '.Xpdefaults', '.Xresources', 'xdm-config', 'file.ad'],
+ \ 'xhtml': ['file.xhtml', 'file.xht'],
+ \ 'xinetd': ['/etc/xinetd.conf'],
+ \ 'xmath': ['file.msc', 'file.msf'],
+ \ 'xml': ['/etc/blkid.tab', '/etc/blkid.tab.old', 'file.xmi', 'file.csproj', 'file.csproj.user', 'file.ts', 'file.ui', 'file.tpm', '/etc/xdg/menus/file.menu', 'fglrxrc', 'file.xlf', 'file.xliff', 'file.xul', 'file.wsdl'],
+ \ 'xmodmap': ['anyXmodmap'],
+ \ 'xf86conf': ['xorg.conf', 'xorg.conf-4'],
+ \ 'xpm2': ['file.xpm2'],
+ \ 'xquery': ['file.xq', 'file.xql', 'file.xqm', 'file.xquery', 'file.xqy'],
+ \ 'xs': ['file.xs'],
+ \ 'xsd': ['file.xsd'],
+ \ 'xslt': ['file.xsl', 'file.xslt'],
+ \ 'yacc': ['file.yy', 'file.yxx', 'file.y++'],
+ \ 'yaml': ['file.yaml', 'file.yml'],
+ \ 'raml': ['file.raml'],
+ \ 'z8a': ['file.z8a'],
+ \ 'zimbu': ['file.zu'],
+ \ 'zimbutempl': ['file.zut'],
+ \ 'zsh': ['.zprofile', '/etc/zprofile', '.zfbfmarks', 'file.zsh'],
+ \
+ \ 'aap': ['file.aap'],
+ \ 'help': [$VIMRUNTIME . '/doc/help.txt'],
+ \ 'xpm': ['file.xpm'],
+ \ }
+
+let s:filename_case_checks = {
+ \ 'modula2': ['file.DEF', 'file.MOD'],
+ \ }
+
+func CheckItems(checks)
+ for [ft, names] in items(a:checks)
+ for i in range(0, len(names) - 1)
+ new
+ try
+ exe 'edit ' . names[i]
+ catch
+ call assert_report('cannot edit "' . names[i] . '": ' . v:errmsg)
+ endtry
+ call assert_equal(ft, &filetype, 'with file name: ' . names[i])
+ bwipe!
+ endfor
+ endfor
+endfunc
+
+func Test_filetype_detection()
+ filetype on
+ call CheckItems(s:filename_checks)
+ if has('fname_case')
+ call CheckItems(s:filename_case_checks)
+ endif
+ filetype off
+endfunc
+
+" Filetypes detected from the file contents by scripts.vim
+let s:script_checks = {
+ \ 'virata': [['% Virata'],
+ \ ['', '% Virata'],
+ \ ['', '', '% Virata'],
+ \ ['', '', '', '% Virata'],
+ \ ['', '', '', '', '% Virata']],
+ \ 'strace': [['execve("/usr/bin/pstree", ["pstree"], 0x7ff0 /* 63 vars */) = 0'],
+ \ ['15:17:47 execve("/usr/bin/pstree", ["pstree"], ... "_=/usr/bin/strace"]) = 0'],
+ \ ['__libc_start_main and something']],
+ \ 'clojure': [['#!/path/clojure']],
+ \ 'scala': [['#!/path/scala']],
+ \ 'tcsh': [['#!/path/tcsh']],
+ \ 'zsh': [['#!/path/zsh']],
+ \ 'tcl': [['#!/path/tclsh'],
+ \ ['#!/path/wish'],
+ \ ['#!/path/expectk'],
+ \ ['#!/path/itclsh'],
+ \ ['#!/path/itkwish']],
+ \ 'expect': [['#!/path/expect']],
+ \ 'gnuplot': [['#!/path/gnuplot']],
+ \ 'make': [['#!/path/make']],
+ \ 'pike': [['#!/path/pike'],
+ \ ['#!/path/pike0'],
+ \ ['#!/path/pike9']],
+ \ 'lua': [['#!/path/lua']],
+ \ 'perl6': [['#!/path/perl6']],
+ \ 'perl': [['#!/path/perl']],
+ \ 'php': [['#!/path/php']],
+ \ 'python': [['#!/path/python'],
+ \ ['#!/path/python2'],
+ \ ['#!/path/python3']],
+ \ 'groovy': [['#!/path/groovy']],
+ \ 'ruby': [['#!/path/ruby']],
+ \ 'javascript': [['#!/path/node'],
+ \ ['#!/path/js'],
+ \ ['#!/path/nodejs'],
+ \ ['#!/path/rhino']],
+ \ 'bc': [['#!/path/bc']],
+ \ 'sed': [['#!/path/sed']],
+ \ 'ocaml': [['#!/path/ocaml']],
+ \ 'awk': [['#!/path/awk']],
+ \ 'wml': [['#!/path/wml']],
+ \ 'scheme': [['#!/path/scheme']],
+ \ 'cfengine': [['#!/path/cfengine']],
+ \ 'erlang': [['#!/path/escript']],
+ \ 'haskell': [['#!/path/haskell']],
+ \ }
+
+func Test_script_detection()
+ filetype on
+ for [ft, files] in items(s:script_checks)
+ for file in files
+ call writefile(file, 'Xtest')
+ split Xtest
+ call assert_equal(ft, &filetype, 'for text: ' . string(file))
+ bwipe!
+ endfor
+ endfor
+ call delete('Xtest')
+ filetype off
+endfunc
+
+func Test_setfiletype_completion()
+ call feedkeys(":setfiletype java\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"setfiletype java javacc javascript', @:)
+endfunc
diff --git a/src/testdir/test_filter_cmd.vim b/src/testdir/test_filter_cmd.vim
new file mode 100644
index 0000000..6f40a90
--- /dev/null
+++ b/src/testdir/test_filter_cmd.vim
@@ -0,0 +1,132 @@
+" Test the :filter command modifier
+
+func Test_filter()
+ edit Xdoesnotmatch
+ edit Xwillmatch
+ call assert_equal('"Xwillmatch"', substitute(execute('filter willma ls'), '[^"]*\(".*"\)[^"]*', '\1', ''))
+ bwipe Xdoesnotmatch
+ bwipe Xwillmatch
+
+ new
+ call setline(1, ['foo1', 'foo2', 'foo3', 'foo4', 'foo5'])
+ call assert_equal("\nfoo2\nfoo4", execute('filter /foo[24]/ 1,$print'))
+ call assert_equal("\n 2 foo2\n 4 foo4", execute('filter /foo[24]/ 1,$number'))
+ call assert_equal("\nfoo2$\nfoo4$", execute('filter /foo[24]/ 1,$list'))
+
+ call assert_equal("\nfoo1$\nfoo3$\nfoo5$", execute('filter! /foo[24]/ 1,$list'))
+ bwipe!
+
+ command XTryThis echo 'this'
+ command XTryThat echo 'that'
+ command XDoThat echo 'that'
+ let lines = split(execute('filter XTry command'), "\n")
+ call assert_equal(3, len(lines))
+ call assert_match("XTryThat", lines[1])
+ call assert_match("XTryThis", lines[2])
+ delcommand XTryThis
+ delcommand XTryThat
+ delcommand XDoThat
+
+ map f1 the first key
+ map f2 the second key
+ map f3 not a key
+ let lines = split(execute('filter the map f'), "\n")
+ call assert_equal(2, len(lines))
+ call assert_match("f2", lines[0])
+ call assert_match("f1", lines[1])
+ unmap f1
+ unmap f2
+ unmap f3
+endfunc
+
+func Test_filter_fails()
+ call assert_fails('filter', 'E471:')
+ call assert_fails('filter pat', 'E476:')
+ call assert_fails('filter /pat', 'E476:')
+ call assert_fails('filter /pat/', 'E476:')
+ call assert_fails('filter /pat/ asdf', 'E492:')
+
+ call assert_fails('filter!', 'E471:')
+ call assert_fails('filter! pat', 'E476:')
+ call assert_fails('filter! /pat', 'E476:')
+ call assert_fails('filter! /pat/', 'E476:')
+ call assert_fails('filter! /pat/ asdf', 'E492:')
+endfunc
+
+function s:complete_filter_cmd(filtcmd)
+ let keystroke = "\<TAB>\<C-R>=execute('let cmdline = getcmdline()')\<CR>\<C-C>"
+ let cmdline = ''
+ call feedkeys(':' . a:filtcmd . keystroke, 'ntx')
+ return cmdline
+endfunction
+
+func Test_filter_cmd_completion()
+ " Do not complete pattern
+ call assert_equal("filter \t", s:complete_filter_cmd('filter '))
+ call assert_equal("filter pat\t", s:complete_filter_cmd('filter pat'))
+ call assert_equal("filter /pat\t", s:complete_filter_cmd('filter /pat'))
+ call assert_equal("filter /pat/\t", s:complete_filter_cmd('filter /pat/'))
+
+ " Complete after string pattern
+ call assert_equal('filter pat print', s:complete_filter_cmd('filter pat pri'))
+
+ " Complete after regexp pattern
+ call assert_equal('filter /pat/ print', s:complete_filter_cmd('filter /pat/ pri'))
+ call assert_equal('filter #pat# print', s:complete_filter_cmd('filter #pat# pri'))
+endfunc
+
+func Test_filter_cmd_with_filter()
+ new
+ set shelltemp
+ %!echo "a|b"
+ let out = getline(1)
+ bw!
+ if has('win32')
+ let out = trim(out, '" ')
+ endif
+ call assert_equal('a|b', out)
+ set shelltemp&
+endfunction
+
+func Test_filter_commands()
+ let g:test_filter_a = 1
+ let b:test_filter_b = 2
+ let test_filter_c = 3
+
+ " Test filtering :let command
+ let res = split(execute("filter /^test_filter/ let"), "\n")
+ call assert_equal(["test_filter_a #1"], res)
+
+ let res = split(execute("filter /\\v^(b:)?test_filter/ let"), "\n")
+ call assert_equal(["test_filter_a #1", "b:test_filter_b #2"], res)
+
+ unlet g:test_filter_a
+ unlet b:test_filter_b
+ unlet test_filter_c
+
+ " Test filtering :set command
+ let helplang=&helplang
+ set helplang=en
+ let res = join(split(execute("filter /^help/ set"), "\n")[1:], " ")
+ call assert_match('^\s*helplang=\w*$', res)
+ let &helplang=helplang
+
+ " Test filtering :llist command
+ call setloclist(0, [{"filename": "/path/vim.c"}, {"filename": "/path/vim.h"}, {"module": "Main.Test"}])
+ let res = split(execute("filter /\\.c$/ llist"), "\n")
+ call assert_equal([" 1 /path/vim.c: "], res)
+
+ let res = split(execute("filter /\\.Test$/ llist"), "\n")
+ call assert_equal([" 3 Main.Test: "], res)
+
+ " Test filtering :jump command
+ e file.c
+ e file.h
+ e file.hs
+ let res = split(execute("filter /\.c$/ jumps"), "\n")[1:]
+ call assert_equal([" 2 1 0 file.c", ">"], res)
+
+ bwipe file.c
+ bwipe file.h
+ bwipe file.hs
+endfunc
diff --git a/src/testdir/test_filter_map.vim b/src/testdir/test_filter_map.vim
new file mode 100644
index 0000000..1dd3a5b
--- /dev/null
+++ b/src/testdir/test_filter_map.vim
@@ -0,0 +1,86 @@
+" Test filter() and map()
+
+" list with expression string
+func Test_filter_map_list_expr_string()
+ " filter()
+ call assert_equal([2, 3, 4], filter([1, 2, 3, 4], 'v:val > 1'))
+ call assert_equal([3, 4], filter([1, 2, 3, 4], 'v:key > 1'))
+ call assert_equal([], filter([1, 2, 3, 4], 0))
+
+ " map()
+ call assert_equal([2, 4, 6, 8], map([1, 2, 3, 4], 'v:val * 2'))
+ call assert_equal([0, 2, 4, 6], map([1, 2, 3, 4], 'v:key * 2'))
+ call assert_equal([9, 9, 9, 9], map([1, 2, 3, 4], 9))
+endfunc
+
+" dict with expression string
+func Test_filter_map_dict_expr_string()
+ let dict = {"foo": 1, "bar": 2, "baz": 3}
+
+ " filter()
+ call assert_equal({"bar": 2, "baz": 3}, filter(copy(dict), 'v:val > 1'))
+ call assert_equal({"foo": 1, "baz": 3}, filter(copy(dict), 'v:key > "bar"'))
+ call assert_equal({}, filter(copy(dict), 0))
+
+ " map()
+ call assert_equal({"foo": 2, "bar": 4, "baz": 6}, map(copy(dict), 'v:val * 2'))
+ call assert_equal({"foo": "f", "bar": "b", "baz": "b"}, map(copy(dict), 'v:key[0]'))
+ call assert_equal({"foo": 9, "bar": 9, "baz": 9}, map(copy(dict), 9))
+endfunc
+
+" list with funcref
+func Test_filter_map_list_expr_funcref()
+ " filter()
+ func! s:filter1(index, val) abort
+ return a:val > 1
+ endfunc
+ call assert_equal([2, 3, 4], filter([1, 2, 3, 4], function('s:filter1')))
+
+ func! s:filter2(index, val) abort
+ return a:index > 1
+ endfunc
+ call assert_equal([3, 4], filter([1, 2, 3, 4], function('s:filter2')))
+
+ " map()
+ func! s:filter3(index, val) abort
+ return a:val * 2
+ endfunc
+ call assert_equal([2, 4, 6, 8], map([1, 2, 3, 4], function('s:filter3')))
+
+ func! s:filter4(index, val) abort
+ return a:index * 2
+ endfunc
+ call assert_equal([0, 2, 4, 6], map([1, 2, 3, 4], function('s:filter4')))
+endfunc
+
+" dict with funcref
+func Test_filter_map_dict_expr_funcref()
+ let dict = {"foo": 1, "bar": 2, "baz": 3}
+
+ " filter()
+ func! s:filter1(key, val) abort
+ return a:val > 1
+ endfunc
+ call assert_equal({"bar": 2, "baz": 3}, filter(copy(dict), function('s:filter1')))
+
+ func! s:filter2(key, val) abort
+ return a:key > "bar"
+ endfunc
+ call assert_equal({"foo": 1, "baz": 3}, filter(copy(dict), function('s:filter2')))
+
+ " map()
+ func! s:filter3(key, val) abort
+ return a:val * 2
+ endfunc
+ call assert_equal({"foo": 2, "bar": 4, "baz": 6}, map(copy(dict), function('s:filter3')))
+
+ func! s:filter4(key, val) abort
+ return a:key[0]
+ endfunc
+ call assert_equal({"foo": "f", "bar": "b", "baz": "b"}, map(copy(dict), function('s:filter4')))
+endfunc
+
+func Test_map_fails()
+ call assert_fails('call map([1], "42 +")', 'E15:')
+ call assert_fails('call filter([1], "42 +")', 'E15:')
+endfunc
diff --git a/src/testdir/test_find_complete.vim b/src/testdir/test_find_complete.vim
new file mode 100644
index 0000000..a7bc135
--- /dev/null
+++ b/src/testdir/test_find_complete.vim
@@ -0,0 +1,163 @@
+" Tests for the 'find' command completion.
+
+" Do all the tests in a separate window to avoid E211 when we recursively
+" delete the Xfind directory during cleanup
+func Test_find_complete()
+ set belloff=all
+
+ " On windows a stale "Xfind" directory may exist, remove it so that
+ " we start from a clean state.
+ call delete("Xfind", "rf")
+ let cwd = getcwd()
+ let test_out = cwd . '/test.out'
+ call mkdir('Xfind')
+ cd Xfind
+
+ new
+ set path=
+ call assert_fails('call feedkeys(":find\t\n", "xt")', 'E345:')
+ close
+
+ new
+ set path=.
+ call assert_fails('call feedkeys(":find\t\n", "xt")', 'E32:')
+ close
+
+ new
+ set path=.,,
+ call assert_fails('call feedkeys(":find\t\n", "xt")', 'E32:')
+ close
+
+ new
+ set path=./**
+ call assert_fails('call feedkeys(":find\t\n", "xt")', 'E32:')
+ close
+
+ " We shouldn't find any file till this point
+
+ call mkdir('in/path', 'p')
+ exe 'cd ' . cwd
+ call writefile(['Holy Grail'], 'Xfind/file.txt')
+ call writefile(['Jimmy Hoffa'], 'Xfind/in/file.txt')
+ call writefile(['Another Holy Grail'], 'Xfind/in/stuff.txt')
+ call writefile(['E.T.'], 'Xfind/in/path/file.txt')
+
+ new
+ set path=Xfind/**
+ call feedkeys(":find file\t\n", "xt")
+ call assert_equal('Holy Grail', getline(1))
+ call feedkeys(":find file\t\t\n", "xt")
+ call assert_equal('Jimmy Hoffa', getline(1))
+ call feedkeys(":find file\t\t\t\n", "xt")
+ call assert_equal('E.T.', getline(1))
+
+ " Rerun the previous three find completions, using fullpath in 'path'
+ exec "set path=" . cwd . "/Xfind/**"
+
+ call feedkeys(":find file\t\n", "xt")
+ call assert_equal('Holy Grail', getline(1))
+ call feedkeys(":find file\t\t\n", "xt")
+ call assert_equal('Jimmy Hoffa', getline(1))
+ call feedkeys(":find file\t\t\t\n", "xt")
+ call assert_equal('E.T.', getline(1))
+
+ " Same steps again, using relative and fullpath items that point to the same
+ " recursive location.
+ " This is to test that there are no duplicates in the completion list.
+ set path+=Xfind/**
+ call feedkeys(":find file\t\n", "xt")
+ call assert_equal('Holy Grail', getline(1))
+ call feedkeys(":find file\t\t\n", "xt")
+ call assert_equal('Jimmy Hoffa', getline(1))
+ call feedkeys(":find file\t\t\t\n", "xt")
+ call assert_equal('E.T.', getline(1))
+ call feedkeys(":find file\t\t\n", "xt")
+
+ " Test find completion for directory of current buffer, which at this point
+ " is Xfind/in/file.txt.
+ set path=.
+ call feedkeys(":find st\t\n", "xt")
+ call assert_equal('Another Holy Grail', getline(1))
+
+ " Test find completion for empty path item ",," which is the current
+ " directory
+ cd Xfind
+ set path=,,
+ call feedkeys(":find f\t\n", "xt")
+ call assert_equal('Holy Grail', getline(1))
+
+ " Test that find completion on directory appends a slash
+ call feedkeys(":find in/pa\tfile.txt\n", "xt")
+ call assert_equal('E.T.', getline(1))
+ call feedkeys(":find ./i\tstuff.txt\n", "xt")
+ call assert_equal('Another Holy Grail', getline(1))
+
+ " Test shortening of
+ "
+ " foo/x/bar/voyager.txt
+ " foo/y/bar/voyager.txt
+ "
+ " When current directory is above foo/ they should be shortened to (in order
+ " of appearance):
+ "
+ " x/bar/voyager.txt
+ " y/bar/voyager.txt
+ call mkdir('foo/x/bar', 'p')
+ call mkdir('foo/y/bar', 'p')
+ call writefile(['Voyager 1'], 'foo/x/bar/voyager.txt')
+ call writefile(['Voyager 2'], 'foo/y/bar/voyager.txt')
+
+ exec "set path=" . cwd . "/Xfind/**"
+ call feedkeys(":find voyager\t\n", "xt")
+ call assert_equal('Voyager 1', getline(1))
+ call feedkeys(":find voyager\t\t\n", "xt")
+ call assert_equal('Voyager 2', getline(1))
+
+ "
+ " When current directory is .../foo/y/bar they should be shortened to (in
+ " order of appearance):
+ "
+ " ./voyager.txt
+ " x/bar/voyager.txt
+ cd foo/y/bar
+ call feedkeys(":find voyager\t\n", "xt")
+ call assert_equal('Voyager 2', getline(1))
+ call feedkeys(":find voyager\t\t\n", "xt")
+ call assert_equal('Voyager 1', getline(1))
+
+ " Check the opposite too:
+ cd ../../x/bar
+ call feedkeys(":find voyager\t\n", "xt")
+ call assert_equal('Voyager 1', getline(1))
+ call feedkeys(":find voyager\t\t\n", "xt")
+ call assert_equal('Voyager 2', getline(1))
+
+ " Check for correct handling of shorten_fname()'s behavior on windows
+ exec "cd " . cwd . "/Xfind/in"
+ call feedkeys(":find file\t\n", "xt")
+ call assert_equal('Jimmy Hoffa', getline(1))
+
+ " Test for relative to current buffer 'path' item
+ exec "cd " . cwd . "/Xfind/"
+ set path=./path
+ " Open the file where Jimmy Hoffa is found
+ e in/file.txt
+ " Find the file containing 'E.T.' in the Xfind/in/path directory
+ call feedkeys(":find file\t\n", "xt")
+ call assert_equal('E.T.', getline(1))
+
+ " Test that completion works when path=.,,
+ set path=.,,
+ " Open Jimmy Hoffa file
+ e in/file.txt
+ call assert_equal('Jimmy Hoffa', getline(1))
+
+ " Search for the file containing Holy Grail in same directory as in/path.txt
+ call feedkeys(":find stu\t\n", "xt")
+ call assert_equal('Another Holy Grail', getline(1))
+
+ enew | only
+ exe 'cd ' . cwd
+ call delete('Xfind', 'rf')
+ set path&
+endfunc
diff --git a/src/testdir/test_findfile.vim b/src/testdir/test_findfile.vim
new file mode 100644
index 0000000..0bae161
--- /dev/null
+++ b/src/testdir/test_findfile.vim
@@ -0,0 +1,185 @@
+" Test findfile() and finddir()
+
+let s:files = [ 'Xdir1/foo',
+ \ 'Xdir1/bar',
+ \ 'Xdir1/Xdir2/foo',
+ \ 'Xdir1/Xdir2/foobar',
+ \ 'Xdir1/Xdir2/Xdir3/bar',
+ \ 'Xdir1/Xdir2/Xdir3/barfoo' ]
+
+func CreateFiles()
+ call mkdir('Xdir1/Xdir2/Xdir3/Xdir2', 'p')
+ for f in s:files
+ call writefile([], f)
+ endfor
+endfunc
+
+func CleanFiles()
+ " Safer to delete each file even if it's more verbose
+ " than doing a recursive delete('Xdir1', 'rf').
+ for f in s:files
+ call delete(f)
+ endfor
+
+ call delete('Xdir1/Xdir2/Xdir3/Xdir2', 'd')
+ call delete('Xdir1/Xdir2/Xdir3', 'd')
+ call delete('Xdir1/Xdir2', 'd')
+ call delete('Xdir1', 'd')
+endfunc
+
+" Test findfile({name} [, {path} [, {count}]])
+func Test_findfile()
+ let save_path = &path
+ let save_shellslash = &shellslash
+ let save_dir = getcwd()
+ set shellslash
+ call CreateFiles()
+ cd Xdir1
+ e Xdir2/foo
+
+ " With ,, in path, findfile() searches in current directory.
+ set path=,,
+ call assert_equal('foo', findfile('foo'))
+ call assert_equal('bar', findfile('bar'))
+ call assert_equal('', findfile('foobar'))
+
+ " Directories should not be found (finddir() finds them).
+ call assert_equal('', findfile('Xdir2'))
+
+ " With . in 'path', findfile() searches relatively to current file.
+ set path=.
+ call assert_equal('Xdir2/foo', findfile('foo'))
+ call assert_equal('', findfile('bar'))
+ call assert_equal('Xdir2/foobar', findfile('foobar'))
+
+ " Empty {path} 2nd argument is the same as no 2nd argument.
+ call assert_equal('Xdir2/foo', findfile('foo', ''))
+ call assert_equal('', findfile('bar', ''))
+
+ " Test with *
+ call assert_equal('Xdir2/foo', findfile('foo', '*'))
+ call assert_equal('', findfile('bar', '*'))
+ call assert_equal('Xdir2/Xdir3/bar', findfile('bar', '*/*'))
+ call assert_equal('Xdir2/Xdir3/bar', findfile('bar', 'Xdir2/*'))
+ call assert_equal('Xdir2/Xdir3/bar', findfile('bar', 'Xdir*/Xdir3'))
+ call assert_equal('Xdir2/Xdir3/bar', findfile('bar', '*2/*3'))
+
+ " Test with **
+ call assert_equal('bar', findfile('bar', '**'))
+ call assert_equal('Xdir2/Xdir3/bar', findfile('bar', '**/Xdir3'))
+ call assert_equal('Xdir2/Xdir3/bar', findfile('bar', 'Xdir2/**'))
+
+ call assert_equal('Xdir2/Xdir3/barfoo', findfile('barfoo', '**2'))
+ call assert_equal('', findfile('barfoo', '**1'))
+ call assert_equal('Xdir2/foobar', findfile('foobar', '**1'))
+
+ " Test with {count} 3rd argument.
+ call assert_equal('bar', findfile('bar', '**', 0))
+ call assert_equal('bar', findfile('bar', '**', 1))
+ call assert_equal('Xdir2/Xdir3/bar', findfile('bar', '**', 2))
+ call assert_equal('', findfile('bar', '**', 3))
+ call assert_equal(['bar', 'Xdir2/Xdir3/bar'], findfile('bar', '**', -1))
+
+ " Test upwards search.
+ cd Xdir2/Xdir3
+ call assert_equal('bar', findfile('bar', ';'))
+ call assert_match('.*/Xdir1/Xdir2/foo', findfile('foo', ';'))
+ call assert_match('.*/Xdir1/Xdir2/foo', findfile('foo', ';', 1))
+ call assert_match('.*/Xdir1/foo', findfile('foo', ';', 2))
+ call assert_match('.*/Xdir1/foo', findfile('foo', ';', 2))
+ call assert_match('.*/Xdir1/Xdir2/foo', findfile('foo', 'Xdir2;', 1))
+ call assert_equal('', findfile('foo', 'Xdir2;', 2))
+
+ " List l should have at least 2 values (possibly more if foo file
+ " happens to be found upwards above Xdir1).
+ let l = findfile('foo', ';', -1)
+ call assert_match('.*/Xdir1/Xdir2/foo', l[0])
+ call assert_match('.*/Xdir1/foo', l[1])
+
+ " Test upwards search with stop-directory.
+ cd Xdir2
+ let l = findfile('bar', ';' . save_dir . '/Xdir1/Xdir2/', -1)
+ call assert_equal(1, len(l))
+ call assert_match('.*/Xdir1/Xdir2/Xdir3/bar', l[0])
+
+ let l = findfile('bar', ';' . save_dir . '/Xdir1/', -1)
+ call assert_equal(2, len(l))
+ call assert_match('.*/Xdir1/Xdir2/Xdir3/bar', l[0])
+ call assert_match('.*/Xdir1/bar', l[1])
+
+ " Test combined downwards and upwards search from Xdir2/.
+ cd ../..
+ call assert_equal('Xdir3/bar', findfile('bar', '**;', 1))
+ call assert_match('.*/Xdir1/bar', findfile('bar', '**;', 2))
+
+ bwipe!
+ exe 'cd ' . save_dir
+ call CleanFiles()
+ let &path = save_path
+ let &shellslash = save_shellslash
+endfunc
+
+func Test_findfile_error()
+ call assert_fails('call findfile([])', 'E730:')
+ call assert_fails('call findfile("x", [])', 'E730:')
+ call assert_fails('call findfile("x", "", [])', 'E745:')
+ call assert_fails('call findfile("x", "**x")', 'E343:')
+ call assert_fails('call findfile("x", repeat("x", 5000))', 'E854:')
+endfunc
+
+" Test finddir({name} [, {path} [, {count}]])
+func Test_finddir()
+ let save_path = &path
+ let save_shellslash = &shellslash
+ let save_dir = getcwd()
+ set path=,,
+ call CreateFiles()
+ cd Xdir1
+
+ call assert_equal('Xdir2', finddir('Xdir2'))
+ call assert_equal('', finddir('Xdir3'))
+
+ " Files should not be found (findfile() finds them).
+ call assert_equal('', finddir('foo'))
+
+ call assert_equal('Xdir2', finddir('Xdir2', '**'))
+ call assert_equal('Xdir2/Xdir3', finddir('Xdir3', '**'))
+
+ call assert_equal('Xdir2', finddir('Xdir2', '**', 1))
+ call assert_equal('Xdir2/Xdir3/Xdir2', finddir('Xdir2', '**', 2))
+ call assert_equal(['Xdir2',
+ \ 'Xdir2/Xdir3/Xdir2'], finddir('Xdir2', '**', -1))
+
+ call assert_equal('Xdir2', finddir('Xdir2', '**1'))
+ call assert_equal('Xdir2', finddir('Xdir2', '**0'))
+ call assert_equal('Xdir2/Xdir3', finddir('Xdir3', '**1'))
+ call assert_equal('', finddir('Xdir3', '**0'))
+
+ " Test upwards dir search.
+ cd Xdir2/Xdir3
+ call assert_match('.*/Xdir1', finddir('Xdir1', ';'))
+
+ " Test upwards search with stop-directory.
+ call assert_match('.*/Xdir1', finddir('Xdir1', ';' . save_dir . '/'))
+ call assert_equal('', finddir('Xdir1', ';' . save_dir . '/Xdir1/'))
+
+ " Test combined downwards and upwards dir search from Xdir2/.
+ cd ..
+ call assert_match('.*/Xdir1', finddir('Xdir1', '**;', 1))
+ call assert_equal('Xdir3/Xdir2', finddir('Xdir2', '**;', 1))
+ call assert_match('.*/Xdir1/Xdir2', finddir('Xdir2', '**;', 2))
+ call assert_equal('Xdir3', finddir('Xdir3', '**;', 1))
+
+ exe 'cd ' . save_dir
+ call CleanFiles()
+ let &path = save_path
+ let &shellslash = save_shellslash
+endfunc
+
+func Test_finddir_error()
+ call assert_fails('call finddir([])', 'E730:')
+ call assert_fails('call finddir("x", [])', 'E730:')
+ call assert_fails('call finddir("x", "", [])', 'E745:')
+ call assert_fails('call finddir("x", "**x")', 'E343:')
+ call assert_fails('call finddir("x", repeat("x", 5000))', 'E854:')
+endfunc
diff --git a/src/testdir/test_fixeol.vim b/src/testdir/test_fixeol.vim
new file mode 100644
index 0000000..32cb059
--- /dev/null
+++ b/src/testdir/test_fixeol.vim
@@ -0,0 +1,48 @@
+" Tests for 'fixeol' and 'eol'
+func Test_fixeol()
+ " first write two test files – with and without trailing EOL
+ " use Unix fileformat for consistency
+ set ff=unix
+ enew!
+ call setline('.', 'with eol')
+ w! XXEol
+ enew!
+ set noeol nofixeol
+ call setline('.', 'without eol')
+ w! XXNoEol
+ set eol fixeol
+ bwipe XXEol XXNoEol
+
+ " try editing files with 'fixeol' disabled
+ e! XXEol
+ normal ostays eol
+ set nofixeol
+ w! XXTestEol
+ e! XXNoEol
+ normal ostays without
+ set nofixeol
+ w! XXTestNoEol
+ bwipe! XXEol XXNoEol XXTestEol XXTestNoEol
+ set fixeol
+
+ " Append "END" to each file so that we can see what the last written char
+ " was.
+ normal ggdGaEND
+ w >>XXEol
+ w >>XXNoEol
+ w >>XXTestEol
+ w >>XXTestNoEol
+
+ call assert_equal(['with eol', 'END'], readfile('XXEol'))
+ call assert_equal(['without eolEND'], readfile('XXNoEol'))
+ call assert_equal(['with eol', 'stays eol', 'END'], readfile('XXTestEol'))
+ call assert_equal(['without eol', 'stays withoutEND'],
+ \ readfile('XXTestNoEol'))
+
+ call delete('XXEol')
+ call delete('XXNoEol')
+ call delete('XXTestEol')
+ call delete('XXTestNoEol')
+ set ff& fixeol& eol&
+ enew!
+endfunc
diff --git a/src/testdir/test_float_func.vim b/src/testdir/test_float_func.vim
new file mode 100644
index 0000000..32b985e
--- /dev/null
+++ b/src/testdir/test_float_func.vim
@@ -0,0 +1,331 @@
+" test float functions
+
+if !has('float')
+ finish
+end
+
+func Test_abs()
+ call assert_equal('1.23', string(abs(1.23)))
+ call assert_equal('1.23', string(abs(-1.23)))
+ call assert_equal('0.0', string(abs(0.0)))
+ call assert_equal('0.0', string(abs(1.0/(1.0/0.0))))
+ call assert_equal('0.0', string(abs(-1.0/(1.0/0.0))))
+ call assert_equal('inf', string(abs(1.0/0.0)))
+ call assert_equal('inf', string(abs(-1.0/0.0)))
+ call assert_equal('nan', string(abs(0.0/0.0)))
+ call assert_equal('12', string(abs('-12abc')))
+ call assert_fails("call abs([])", 'E745:')
+ call assert_fails("call abs({})", 'E728:')
+ call assert_fails("call abs(function('string'))", 'E703:')
+endfunc
+
+func Test_sqrt()
+ call assert_equal('0.0', string(sqrt(0.0)))
+ call assert_equal('1.414214', string(sqrt(2.0)))
+ call assert_equal('inf', string(sqrt(1.0/0.0)))
+ call assert_equal('nan', string(sqrt(-1.0)))
+ call assert_equal('nan', string(sqrt(0.0/0.0)))
+ call assert_fails('call sqrt("")', 'E808:')
+endfunc
+
+func Test_log()
+ call assert_equal('0.0', string(log(1.0)))
+ call assert_equal('-0.693147', string(log(0.5)))
+ call assert_equal('-inf', string(log(0.0)))
+ call assert_equal('nan', string(log(-1.0)))
+ call assert_equal('inf', string(log(1.0/0.0)))
+ call assert_equal('nan', string(log(0.0/0.0)))
+ call assert_fails('call log("")', 'E808:')
+endfunc
+
+func Test_log10()
+ call assert_equal('0.0', string(log10(1.0)))
+ call assert_equal('2.0', string(log10(100.0)))
+ call assert_equal('2.079181', string(log10(120.0)))
+ call assert_equal('-inf', string(log10(0.0)))
+ call assert_equal('nan', string(log10(-1.0)))
+ call assert_equal('inf', string(log10(1.0/0.0)))
+ call assert_equal('nan', string(log10(0.0/0.0)))
+ call assert_fails('call log10("")', 'E808:')
+endfunc
+
+func Test_exp()
+ call assert_equal('1.0', string(exp(0.0)))
+ call assert_equal('7.389056', string(exp(2.0)))
+ call assert_equal('0.367879', string(exp(-1.0)))
+ call assert_equal('inf', string(exp(1.0/0.0)))
+ call assert_equal('0.0', string(exp(-1.0/0.0)))
+ call assert_equal('nan', string(exp(0.0/0.0)))
+ call assert_fails('call exp("")', 'E808:')
+endfunc
+
+func Test_sin()
+ call assert_equal('0.0', string(sin(0.0)))
+ call assert_equal('0.841471', string(sin(1.0)))
+ call assert_equal('-0.479426', string(sin(-0.5)))
+ call assert_equal('nan', string(sin(0.0/0.0)))
+ call assert_equal('nan', string(sin(1.0/0.0)))
+ call assert_equal('0.0', string(sin(1.0/(1.0/0.0))))
+ call assert_equal('-0.0', string(sin(-1.0/(1.0/0.0))))
+ call assert_fails('call sin("")', 'E808:')
+endfunc
+
+func Test_asin()
+ call assert_equal('0.0', string(asin(0.0)))
+ call assert_equal('1.570796', string(asin(1.0)))
+ call assert_equal('-0.523599', string(asin(-0.5)))
+ call assert_equal('nan', string(asin(1.1)))
+ call assert_equal('nan', string(asin(1.0/0.0)))
+ call assert_equal('nan', string(asin(0.0/0.0)))
+ call assert_fails('call asin("")', 'E808:')
+endfunc
+
+func Test_sinh()
+ call assert_equal('0.0', string(sinh(0.0)))
+ call assert_equal('0.521095', string(sinh(0.5)))
+ call assert_equal('-1.026517', string(sinh(-0.9)))
+ call assert_equal('inf', string(sinh(1.0/0.0)))
+ call assert_equal('-inf', string(sinh(-1.0/0.0)))
+ call assert_equal('nan', string(sinh(0.0/0.0)))
+ call assert_fails('call sinh("")', 'E808:')
+endfunc
+
+func Test_cos()
+ call assert_equal('1.0', string(cos(0.0)))
+ call assert_equal('0.540302', string(cos(1.0)))
+ call assert_equal('0.877583', string(cos(-0.5)))
+ call assert_equal('nan', string(cos(0.0/0.0)))
+ call assert_equal('nan', string(cos(1.0/0.0)))
+ call assert_fails('call cos("")', 'E808:')
+endfunc
+
+func Test_acos()
+ call assert_equal('1.570796', string(acos(0.0)))
+ call assert_equal('0.0', string(acos(1.0)))
+ call assert_equal('3.141593', string(acos(-1.0)))
+ call assert_equal('2.094395', string(acos(-0.5)))
+ call assert_equal('nan', string(acos(1.1)))
+ call assert_equal('nan', string(acos(1.0/0.0)))
+ call assert_equal('nan', string(acos(0.0/0.0)))
+ call assert_fails('call acos("")', 'E808:')
+endfunc
+
+func Test_cosh()
+ call assert_equal('1.0', string(cosh(0.0)))
+ call assert_equal('1.127626', string(cosh(0.5)))
+ call assert_equal('inf', string(cosh(1.0/0.0)))
+ call assert_equal('inf', string(cosh(-1.0/0.0)))
+ call assert_equal('nan', string(cosh(0.0/0.0)))
+ call assert_fails('call cosh("")', 'E808:')
+endfunc
+
+func Test_tan()
+ call assert_equal('0.0', string(tan(0.0)))
+ call assert_equal('0.546302', string(tan(0.5)))
+ call assert_equal('-0.546302', string(tan(-0.5)))
+ call assert_equal('nan', string(tan(1.0/0.0)))
+ call assert_equal('nan', string(cos(0.0/0.0)))
+ call assert_equal('0.0', string(tan(1.0/(1.0/0.0))))
+ call assert_equal('-0.0', string(tan(-1.0/(1.0/0.0))))
+ call assert_fails('call tan("")', 'E808:')
+endfunc
+
+func Test_atan()
+ call assert_equal('0.0', string(atan(0.0)))
+ call assert_equal('0.463648', string(atan(0.5)))
+ call assert_equal('-0.785398', string(atan(-1.0)))
+ call assert_equal('1.570796', string(atan(1.0/0.0)))
+ call assert_equal('-1.570796', string(atan(-1.0/0.0)))
+ call assert_equal('nan', string(atan(0.0/0.0)))
+ call assert_fails('call atan("")', 'E808:')
+endfunc
+
+func Test_atan2()
+ call assert_equal('-2.356194', string(atan2(-1, -1)))
+ call assert_equal('2.356194', string(atan2(1, -1)))
+ call assert_equal('0.0', string(atan2(1.0, 1.0/0.0)))
+ call assert_equal('1.570796', string(atan2(1.0/0.0, 1.0)))
+ call assert_equal('nan', string(atan2(0.0/0.0, 1.0)))
+ call assert_fails('call atan2("", -1)', 'E808:')
+ call assert_fails('call atan2(-1, "")', 'E808:')
+endfunc
+
+func Test_tanh()
+ call assert_equal('0.0', string(tanh(0.0)))
+ call assert_equal('0.462117', string(tanh(0.5)))
+ call assert_equal('-0.761594', string(tanh(-1.0)))
+ call assert_equal('1.0', string(tanh(1.0/0.0)))
+ call assert_equal('-1.0', string(tanh(-1.0/0.0)))
+ call assert_equal('nan', string(tanh(0.0/0.0)))
+ call assert_fails('call tanh("")', 'E808:')
+endfunc
+
+func Test_fmod()
+ call assert_equal('0.13', string(fmod(12.33, 1.22)))
+ call assert_equal('-0.13', string(fmod(-12.33, 1.22)))
+ call assert_equal('nan', string(fmod(1.0/0.0, 1.0)))
+ " On Windows we get "nan" instead of 1.0, accept both.
+ let res = string(fmod(1.0, 1.0/0.0))
+ if res != 'nan'
+ call assert_equal('1.0', res)
+ endif
+ call assert_equal('nan', string(fmod(1.0, 0.0)))
+ call assert_fails("call fmod('', 1.22)", 'E808:')
+ call assert_fails("call fmod(12.33, '')", 'E808:')
+endfunc
+
+func Test_pow()
+ call assert_equal('1.0', string(pow(0.0, 0.0)))
+ call assert_equal('8.0', string(pow(2.0, 3.0)))
+ call assert_equal('nan', string(pow(2.0, 0.0/0.0)))
+ call assert_equal('nan', string(pow(0.0/0.0, 3.0)))
+ call assert_equal('nan', string(pow(0.0/0.0, 3.0)))
+ call assert_equal('inf', string(pow(2.0, 1.0/0.0)))
+ call assert_equal('inf', string(pow(1.0/0.0, 3.0)))
+ call assert_fails("call pow('', 2.0)", 'E808:')
+ call assert_fails("call pow(2.0, '')", 'E808:')
+endfunc
+
+func Test_str2float()
+ call assert_equal('1.0', string(str2float('1')))
+ call assert_equal('1.0', string(str2float(' 1 ')))
+ call assert_equal('1.0', string(str2float(' 1.0 ')))
+ call assert_equal('1.23', string(str2float('1.23')))
+ call assert_equal('1.23', string(str2float('1.23abc')))
+ call assert_equal('1.0e40', string(str2float('1e40')))
+ call assert_equal('-1.23', string(str2float('-1.23')))
+ call assert_equal('1.23', string(str2float(' + 1.23 ')))
+
+ call assert_equal('1.0', string(str2float('+1')))
+ call assert_equal('1.0', string(str2float('+1')))
+ call assert_equal('1.0', string(str2float(' +1 ')))
+ call assert_equal('1.0', string(str2float(' + 1 ')))
+
+ call assert_equal('-1.0', string(str2float('-1')))
+ call assert_equal('-1.0', string(str2float('-1')))
+ call assert_equal('-1.0', string(str2float(' -1 ')))
+ call assert_equal('-1.0', string(str2float(' - 1 ')))
+
+ call assert_equal('0.0', string(str2float('+0.0')))
+ call assert_equal('-0.0', string(str2float('-0.0')))
+ call assert_equal('inf', string(str2float('1e1000')))
+ call assert_equal('inf', string(str2float('inf')))
+ call assert_equal('-inf', string(str2float('-inf')))
+ call assert_equal('inf', string(str2float('+inf')))
+ call assert_equal('inf', string(str2float('Inf')))
+ call assert_equal('inf', string(str2float(' +inf ')))
+ call assert_equal('nan', string(str2float('nan')))
+ call assert_equal('nan', string(str2float('NaN')))
+ call assert_equal('nan', string(str2float(' nan ')))
+
+ call assert_fails("call str2float(1.2)", 'E806:')
+ call assert_fails("call str2float([])", 'E730:')
+ call assert_fails("call str2float({})", 'E731:')
+ call assert_fails("call str2float(function('string'))", 'E729:')
+endfunc
+
+func Test_float2nr()
+ call assert_equal(1, float2nr(1.234))
+ call assert_equal(123, float2nr(1.234e2))
+ call assert_equal(12, float2nr(123.4e-1))
+ let max_number = 1/0
+ let min_number = -max_number
+ call assert_equal(max_number/2+1, float2nr(pow(2, 62)))
+ call assert_equal(max_number, float2nr(pow(2, 63)))
+ call assert_equal(max_number, float2nr(pow(2, 64)))
+ call assert_equal(min_number/2-1, float2nr(-pow(2, 62)))
+ call assert_equal(min_number, float2nr(-pow(2, 63)))
+ call assert_equal(min_number, float2nr(-pow(2, 64)))
+endfunc
+
+func Test_floor()
+ call assert_equal('2.0', string(floor(2.0)))
+ call assert_equal('2.0', string(floor(2.11)))
+ call assert_equal('2.0', string(floor(2.99)))
+ call assert_equal('-3.0', string(floor(-2.11)))
+ call assert_equal('-3.0', string(floor(-2.99)))
+ call assert_equal('nan', string(floor(0.0/0.0)))
+ call assert_equal('inf', string(floor(1.0/0.0)))
+ call assert_equal('-inf', string(floor(-1.0/0.0)))
+ call assert_fails("call floor('')", 'E808:')
+endfunc
+
+func Test_ceil()
+ call assert_equal('2.0', string(ceil(2.0)))
+ call assert_equal('3.0', string(ceil(2.11)))
+ call assert_equal('3.0', string(ceil(2.99)))
+ call assert_equal('-2.0', string(ceil(-2.11)))
+ call assert_equal('-2.0', string(ceil(-2.99)))
+ call assert_equal('nan', string(ceil(0.0/0.0)))
+ call assert_equal('inf', string(ceil(1.0/0.0)))
+ call assert_equal('-inf', string(ceil(-1.0/0.0)))
+ call assert_fails("call ceil('')", 'E808:')
+endfunc
+
+func Test_round()
+ call assert_equal('2.0', string(round(2.1)))
+ call assert_equal('3.0', string(round(2.5)))
+ call assert_equal('3.0', string(round(2.9)))
+ call assert_equal('-2.0', string(round(-2.1)))
+ call assert_equal('-3.0', string(round(-2.5)))
+ call assert_equal('-3.0', string(round(-2.9)))
+ call assert_equal('nan', string(round(0.0/0.0)))
+ call assert_equal('inf', string(round(1.0/0.0)))
+ call assert_equal('-inf', string(round(-1.0/0.0)))
+ call assert_fails("call round('')", 'E808:')
+endfunc
+
+func Test_trunc()
+ call assert_equal('2.0', string(trunc(2.1)))
+ call assert_equal('2.0', string(trunc(2.5)))
+ call assert_equal('2.0', string(trunc(2.9)))
+ call assert_equal('-2.0', string(trunc(-2.1)))
+ call assert_equal('-2.0', string(trunc(-2.5)))
+ call assert_equal('-2.0', string(trunc(-2.9)))
+ call assert_equal('nan', string(trunc(0.0/0.0)))
+ call assert_equal('inf', string(trunc(1.0/0.0)))
+ call assert_equal('-inf', string(trunc(-1.0/0.0)))
+ call assert_fails("call trunc('')", 'E808:')
+endfunc
+
+func Test_isnan()
+ call assert_equal(0, isnan(1.0))
+ call assert_equal(1, isnan(0.0/0.0))
+ call assert_equal(0, isnan(1.0/0.0))
+ call assert_equal(0, isnan('a'))
+ call assert_equal(0, isnan([]))
+ call assert_equal(0, isnan({}))
+endfunc
+
+" This was converted from test65
+func Test_float_misc()
+ call assert_equal('123.456000', printf('%f', 123.456))
+ call assert_equal('1.234560e+02', printf('%e', 123.456))
+ call assert_equal('123.456', printf('%g', 123.456))
+ " +=
+ let v = 1.234
+ let v += 6.543
+ call assert_equal('7.777', printf('%g', v))
+ let v = 1.234
+ let v += 5
+ call assert_equal('6.234', printf('%g', v))
+ let v = 5
+ let v += 3.333
+ call assert_equal('8.333', string(v))
+ " ==
+ let v = 1.234
+ call assert_true(v == 1.234)
+ call assert_false(v == 1.2341)
+ " add-subtract
+ call assert_equal('5.234', printf('%g', 4 + 1.234))
+ call assert_equal('-6.766', printf('%g', 1.234 - 8))
+ " mult-div
+ call assert_equal('4.936', printf('%g', 4 * 1.234))
+ call assert_equal('0.003241', printf('%g', 4.0 / 1234))
+ " dict
+ call assert_equal("{'x': 1.234, 'y': -2.0e20}", string({'x': 1.234, 'y': -2.0e20}))
+ " list
+ call assert_equal('[-123.4, 2.0e-20]', string([-123.4, 2.0e-20]))
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/test_fnameescape.vim b/src/testdir/test_fnameescape.vim
new file mode 100644
index 0000000..5382b89
--- /dev/null
+++ b/src/testdir/test_fnameescape.vim
@@ -0,0 +1,21 @@
+
+" Test if fnameescape is correct for special chars like !
+func Test_fnameescape()
+ let fname = 'Xspa ce'
+ let status = v:false
+ try
+ exe "w! " . fnameescape(fname)
+ let status = v:true
+ endtry
+ call assert_true(status, "Space")
+ call delete(fname)
+
+ let fname = 'Xemark!'
+ let status = v:false
+ try
+ exe "w! " . fnameescape(fname)
+ let status = v:true
+ endtry
+ call assert_true(status, "ExclamationMark")
+ call delete(fname)
+endfunc
diff --git a/src/testdir/test_fnamemodify.vim b/src/testdir/test_fnamemodify.vim
new file mode 100644
index 0000000..768d311
--- /dev/null
+++ b/src/testdir/test_fnamemodify.vim
@@ -0,0 +1,53 @@
+" Test filename modifiers.
+
+func Test_fnamemodify()
+ let save_home = $HOME
+ let save_shell = &shell
+ let $HOME = fnamemodify('.', ':p:h:h')
+ set shell=sh
+
+ call assert_equal('/', fnamemodify('.', ':p')[-1:])
+ call assert_equal('r', fnamemodify('.', ':p:h')[-1:])
+ call assert_equal('t', fnamemodify('test.out', ':p')[-1:])
+ call assert_equal('test.out', fnamemodify('test.out', ':.'))
+ call assert_equal('a', fnamemodify('../testdir/a', ':.'))
+ call assert_equal('~/testdir/test.out', fnamemodify('test.out', ':~'))
+ call assert_equal('~/testdir/a', fnamemodify('../testdir/a', ':~'))
+ call assert_equal('a', fnamemodify('../testdir/a', ':t'))
+ call assert_equal('', fnamemodify('.', ':p:t'))
+ call assert_equal('test.out', fnamemodify('test.out', ':p:t'))
+ call assert_equal('out', fnamemodify('test.out', ':p:e'))
+ call assert_equal('out', fnamemodify('test.out', ':p:t:e'))
+ call assert_equal('abc.fb2.tar', fnamemodify('abc.fb2.tar.gz', ':r'))
+ call assert_equal('abc.fb2', fnamemodify('abc.fb2.tar.gz', ':r:r'))
+ call assert_equal('abc', fnamemodify('abc.fb2.tar.gz', ':r:r:r'))
+ call assert_equal('testdir/abc.fb2', substitute(fnamemodify('abc.fb2.tar.gz', ':p:r:r'), '.*\(testdir/.*\)', '\1', ''))
+ call assert_equal('gz', fnamemodify('abc.fb2.tar.gz', ':e'))
+ call assert_equal('tar.gz', fnamemodify('abc.fb2.tar.gz', ':e:e'))
+ call assert_equal('fb2.tar.gz', fnamemodify('abc.fb2.tar.gz', ':e:e:e'))
+ call assert_equal('fb2.tar.gz', fnamemodify('abc.fb2.tar.gz', ':e:e:e:e'))
+ call assert_equal('tar', fnamemodify('abc.fb2.tar.gz', ':e:e:r'))
+
+ call assert_equal('''abc def''', fnamemodify('abc def', ':S'))
+ call assert_equal('''abc" "def''', fnamemodify('abc" "def', ':S'))
+ call assert_equal('''abc"%"def''', fnamemodify('abc"%"def', ':S'))
+ call assert_equal('''abc''\'''' ''\''''def''', fnamemodify('abc'' ''def', ':S'))
+ call assert_equal('''abc''\''''%''\''''def''', fnamemodify('abc''%''def', ':S'))
+ sp test_alot.vim
+ call assert_equal(expand('%:r:S'), shellescape(expand('%:r')))
+ call assert_equal('test_alot,''test_alot'',test_alot.vim', join([expand('%:r'), expand('%:r:S'), expand('%')], ','))
+ quit
+
+ call assert_equal("'abc\ndef'", fnamemodify("abc\ndef", ':S'))
+ set shell=tcsh
+ call assert_equal("'abc\\\ndef'", fnamemodify("abc\ndef", ':S'))
+
+ let $HOME = save_home
+ let &shell = save_shell
+endfunc
+
+func Test_expand()
+ new
+ call assert_equal("", expand('%:S'))
+ quit
+endfunc
diff --git a/src/testdir/test_fold.vim b/src/testdir/test_fold.vim
new file mode 100644
index 0000000..67e5a48
--- /dev/null
+++ b/src/testdir/test_fold.vim
@@ -0,0 +1,743 @@
+" Test for folding
+
+source view_util.vim
+source screendump.vim
+
+func PrepIndent(arg)
+ return [a:arg] + repeat(["\t".a:arg], 5)
+endfu
+
+func Test_address_fold()
+ new
+ call setline(1, ['int FuncName() {/*{{{*/', 1, 2, 3, 4, 5, '}/*}}}*/',
+ \ 'after fold 1', 'after fold 2', 'after fold 3'])
+ setl fen fdm=marker
+ " The next commands should all copy the same part of the buffer,
+ " regardless of the addressing type, since the part to be copied
+ " is folded away
+ :1y
+ call assert_equal(['int FuncName() {/*{{{*/', '1', '2', '3', '4', '5', '}/*}}}*/'], getreg(0,1,1))
+ :.y
+ call assert_equal(['int FuncName() {/*{{{*/', '1', '2', '3', '4', '5', '}/*}}}*/'], getreg(0,1,1))
+ :.+y
+ call assert_equal(['int FuncName() {/*{{{*/', '1', '2', '3', '4', '5', '}/*}}}*/'], getreg(0,1,1))
+ :.,.y
+ call assert_equal(['int FuncName() {/*{{{*/', '1', '2', '3', '4', '5', '}/*}}}*/'], getreg(0,1,1))
+ :sil .1,.y
+ call assert_equal(['int FuncName() {/*{{{*/', '1', '2', '3', '4', '5', '}/*}}}*/'], getreg(0,1,1))
+ " use silent to make E493 go away
+ :sil .+,.y
+ call assert_equal(['int FuncName() {/*{{{*/', '1', '2', '3', '4', '5', '}/*}}}*/'], getreg(0,1,1))
+ :,y
+ call assert_equal(['int FuncName() {/*{{{*/', '1', '2', '3', '4', '5', '}/*}}}*/'], getreg(0,1,1))
+ :,+y
+ call assert_equal(['int FuncName() {/*{{{*/', '1', '2', '3', '4', '5', '}/*}}}*/','after fold 1'], getreg(0,1,1))
+ " using .+3 as second address should copy the whole folded line + the next 3
+ " lines
+ :.,+3y
+ call assert_equal(['int FuncName() {/*{{{*/', '1', '2', '3', '4', '5', '}/*}}}*/',
+ \ 'after fold 1', 'after fold 2', 'after fold 3'], getreg(0,1,1))
+ :sil .,-2y
+ call assert_equal(['int FuncName() {/*{{{*/', '1', '2', '3', '4', '5', '}/*}}}*/'], getreg(0,1,1))
+
+ " now test again with folding disabled
+ set nofoldenable
+ :1y
+ call assert_equal(['int FuncName() {/*{{{*/'], getreg(0,1,1))
+ :.y
+ call assert_equal(['int FuncName() {/*{{{*/'], getreg(0,1,1))
+ :.+y
+ call assert_equal(['1'], getreg(0,1,1))
+ :.,.y
+ call assert_equal(['int FuncName() {/*{{{*/'], getreg(0,1,1))
+ " use silent to make E493 go away
+ :sil .1,.y
+ call assert_equal(['int FuncName() {/*{{{*/', '1'], getreg(0,1,1))
+ " use silent to make E493 go away
+ :sil .+,.y
+ call assert_equal(['int FuncName() {/*{{{*/', '1'], getreg(0,1,1))
+ :,y
+ call assert_equal(['int FuncName() {/*{{{*/'], getreg(0,1,1))
+ :,+y
+ call assert_equal(['int FuncName() {/*{{{*/', '1'], getreg(0,1,1))
+ " using .+3 as second address should copy the whole folded line + the next 3
+ " lines
+ :.,+3y
+ call assert_equal(['int FuncName() {/*{{{*/', '1', '2', '3'], getreg(0,1,1))
+ :7
+ :sil .,-2y
+ call assert_equal(['4', '5', '}/*}}}*/'], getreg(0,1,1))
+
+ quit!
+endfunc
+
+func Test_indent_fold()
+ new
+ call setline(1, ['', 'a', ' b', ' c'])
+ setl fen fdm=indent
+ 2
+ norm! >>
+ let a=map(range(1,4), 'foldclosed(v:val)')
+ call assert_equal([-1,-1,-1,-1], a)
+ bw!
+endfunc
+
+func Test_indent_fold2()
+ new
+ call setline(1, ['', '{{{', '}}}', '{{{', '}}}'])
+ setl fen fdm=marker
+ 2
+ norm! >>
+ let a=map(range(1,5), 'foldclosed(v:val)')
+ call assert_equal([-1,-1,-1,4,4], a)
+ bw!
+endfunc
+
+func Test_manual_fold_with_filter()
+ if !executable('cat')
+ return
+ endif
+ for type in ['manual', 'marker']
+ exe 'set foldmethod=' . type
+ new
+ call setline(1, range(1, 20))
+ 4,$fold
+ %foldopen
+ 10,$fold
+ %foldopen
+ " This filter command should not have an effect
+ 1,8! cat
+ call feedkeys('5ggzdzMGdd', 'xt')
+ call assert_equal(['1', '2', '3', '4', '5', '6', '7', '8', '9'], getline(1, '$'))
+
+ bwipe!
+ set foldmethod&
+ endfor
+endfunc
+
+func Test_indent_fold_with_read()
+ new
+ set foldmethod=indent
+ call setline(1, repeat(["\<Tab>a"], 4))
+ for n in range(1, 4)
+ call assert_equal(1, foldlevel(n))
+ endfor
+
+ call writefile(["a", "", "\<Tab>a"], 'Xfile')
+ foldopen
+ 2read Xfile
+ %foldclose
+ call assert_equal(1, foldlevel(1))
+ call assert_equal(2, foldclosedend(1))
+ call assert_equal(0, foldlevel(3))
+ call assert_equal(0, foldlevel(4))
+ call assert_equal(1, foldlevel(5))
+ call assert_equal(7, foldclosedend(5))
+
+ bwipe!
+ set foldmethod&
+ call delete('Xfile')
+endfunc
+
+func Test_combining_folds_indent()
+ new
+ let one = "\<Tab>a"
+ let zero = 'a'
+ call setline(1, [one, one, zero, zero, zero, one, one, one])
+ set foldmethod=indent
+ 3,5d
+ %foldclose
+ call assert_equal(5, foldclosedend(1))
+
+ set foldmethod&
+ bwipe!
+endfunc
+
+func Test_combining_folds_marker()
+ new
+ call setline(1, ['{{{', '}}}', '', '', '', '{{{', '', '}}}'])
+ set foldmethod=marker
+ 3,5d
+ %foldclose
+ call assert_equal(2, foldclosedend(1))
+
+ set foldmethod&
+ bwipe!
+endfunc
+
+func Test_folds_marker_in_comment()
+ new
+ call setline(1, ['" foo', 'bar', 'baz'])
+ setl fen fdm=marker
+ setl com=sO:\"\ -,mO:\"\ \ ,eO:\"\",:\" cms=\"%s
+ norm! zf2j
+ setl nofen
+ :1y
+ call assert_equal(['" foo{{{'], getreg(0,1,1))
+ :+2y
+ call assert_equal(['baz"}}}'], getreg(0,1,1))
+
+ set foldmethod&
+ bwipe!
+endfunc
+
+func s:TestFoldExpr(lnum)
+ let thisline = getline(a:lnum)
+ if thisline == 'a'
+ return 1
+ elseif thisline == 'b'
+ return 0
+ elseif thisline == 'c'
+ return '<1'
+ elseif thisline == 'd'
+ return '>1'
+ endif
+ return 0
+endfunction
+
+func Test_update_folds_expr_read()
+ new
+ call setline(1, ['a', 'a', 'a', 'a', 'a', 'a'])
+ set foldmethod=expr
+ set foldexpr=s:TestFoldExpr(v:lnum)
+ 2
+ foldopen
+ call writefile(['b', 'b', 'a', 'a', 'd', 'a', 'a', 'c'], 'Xfile')
+ read Xfile
+ %foldclose
+ call assert_equal(2, foldclosedend(1))
+ call assert_equal(0, foldlevel(3))
+ call assert_equal(0, foldlevel(4))
+ call assert_equal(6, foldclosedend(5))
+ call assert_equal(10, foldclosedend(7))
+ call assert_equal(14, foldclosedend(11))
+
+ call delete('Xfile')
+ bwipe!
+ set foldmethod& foldexpr&
+endfunc
+
+func Check_foldlevels(expected)
+ call assert_equal(a:expected, map(range(1, line('$')), 'foldlevel(v:val)'))
+endfunc
+
+func Test_move_folds_around_manual()
+ new
+ let input = PrepIndent("a") + PrepIndent("b") + PrepIndent("c")
+ call setline(1, PrepIndent("a") + PrepIndent("b") + PrepIndent("c"))
+ let folds=[-1, 2, 2, 2, 2, 2, -1, 8, 8, 8, 8, 8, -1, 14, 14, 14, 14, 14]
+ " all folds closed
+ set foldenable foldlevel=0 fdm=indent
+ " needs a forced redraw
+ redraw!
+ set fdm=manual
+ call assert_equal(folds, map(range(1, line('$')), 'foldclosed(v:val)'))
+ call assert_equal(input, getline(1, '$'))
+ 7,12m0
+ call assert_equal(PrepIndent("b") + PrepIndent("a") + PrepIndent("c"), getline(1, '$'))
+ call assert_equal(folds, map(range(1, line('$')), 'foldclosed(v:val)'))
+ 10,12m0
+ call assert_equal(PrepIndent("a")[1:] + PrepIndent("b") + ["a"] + PrepIndent("c"), getline(1, '$'))
+ call assert_equal([1, 1, 1, 1, 1, -1, 7, 7, 7, 7, 7, -1, -1, 14, 14, 14, 14, 14], map(range(1, line('$')), 'foldclosed(v:val)'))
+ " moving should not close the folds
+ %d
+ call setline(1, PrepIndent("a") + PrepIndent("b") + PrepIndent("c"))
+ set fdm=indent
+ redraw!
+ set fdm=manual
+ call cursor(2, 1)
+ %foldopen
+ 7,12m0
+ let folds=repeat([-1], 18)
+ call assert_equal(PrepIndent("b") + PrepIndent("a") + PrepIndent("c"), getline(1, '$'))
+ call assert_equal(folds, map(range(1, line('$')), 'foldclosed(v:val)'))
+ norm! zM
+ " folds are not corrupted and all have been closed
+ call assert_equal([-1, 2, 2, 2, 2, 2, -1, 8, 8, 8, 8, 8, -1, 14, 14, 14, 14, 14], map(range(1, line('$')), 'foldclosed(v:val)'))
+ %d
+ call setline(1, ["a", "\tb", "\tc", "\td", "\te"])
+ set fdm=indent
+ redraw!
+ set fdm=manual
+ %foldopen
+ 3m4
+ %foldclose
+ call assert_equal(["a", "\tb", "\td", "\tc", "\te"], getline(1, '$'))
+ call assert_equal([-1, 5, 5, 5, 5], map(range(1, line('$')), 'foldclosedend(v:val)'))
+ %d
+ call setline(1, ["a", "\tb", "\tc", "\td", "\te", "z", "\ty", "\tx", "\tw", "\tv"])
+ set fdm=indent foldlevel=0
+ set fdm=manual
+ %foldopen
+ 3m1
+ %foldclose
+ call assert_equal(["a", "\tc", "\tb", "\td", "\te", "z", "\ty", "\tx", "\tw", "\tv"], getline(1, '$'))
+ call assert_equal(0, foldlevel(2))
+ call assert_equal(5, foldclosedend(3))
+ call assert_equal([-1, -1, 3, 3, 3, -1, 7, 7, 7, 7], map(range(1, line('$')), 'foldclosed(v:val)'))
+ 2,6m$
+ %foldclose
+ call assert_equal(5, foldclosedend(2))
+ call assert_equal(0, foldlevel(6))
+ call assert_equal(9, foldclosedend(7))
+ call assert_equal([-1, 2, 2, 2, 2, -1, 7, 7, 7, -1], map(range(1, line('$')), 'foldclosed(v:val)'))
+
+ %d
+ " Ensure moving around the edges still works.
+ call setline(1, PrepIndent("a") + repeat(["a"], 3) + ["\ta"])
+ set fdm=indent foldlevel=0
+ set fdm=manual
+ %foldopen
+ 6m$
+ " The first fold has been truncated to the 5'th line.
+ " Second fold has been moved up because the moved line is now below it.
+ call Check_foldlevels([0, 1, 1, 1, 1, 0, 0, 0, 1, 0])
+
+ %delete
+ set fdm=indent foldlevel=0
+ call setline(1, [
+ \ "a",
+ \ "\ta",
+ \ "\t\ta",
+ \ "\t\ta",
+ \ "\t\ta",
+ \ "a",
+ \ "a"])
+ set fdm=manual
+ %foldopen!
+ 4,5m6
+ call Check_foldlevels([0, 1, 2, 0, 0, 0, 0])
+
+ %delete
+ set fdm=indent
+ call setline(1, [
+ \ "\ta",
+ \ "\t\ta",
+ \ "\t\ta",
+ \ "\t\ta",
+ \ "\ta",
+ \ "\t\ta",
+ \ "\t\ta",
+ \ "\t\ta",
+ \ "\ta",
+ \ "\t\ta",
+ \ "\t\ta",
+ \ "\t\ta",
+ \ "\t\ta",
+ \ "\ta",
+ \ "a"])
+ set fdm=manual
+ %foldopen!
+ 13m7
+ call Check_foldlevels([1, 2, 2, 2, 1, 2, 2, 1, 1, 1, 2, 2, 2, 1, 0])
+
+ bw!
+endfunc
+
+func Test_move_folds_around_indent()
+ new
+ let input = PrepIndent("a") + PrepIndent("b") + PrepIndent("c")
+ call setline(1, PrepIndent("a") + PrepIndent("b") + PrepIndent("c"))
+ let folds=[-1, 2, 2, 2, 2, 2, -1, 8, 8, 8, 8, 8, -1, 14, 14, 14, 14, 14]
+ " all folds closed
+ set fdm=indent
+ call assert_equal(folds, map(range(1, line('$')), 'foldclosed(v:val)'))
+ call assert_equal(input, getline(1, '$'))
+ 7,12m0
+ call assert_equal(PrepIndent("b") + PrepIndent("a") + PrepIndent("c"), getline(1, '$'))
+ call assert_equal(folds, map(range(1, line('$')), 'foldclosed(v:val)'))
+ 10,12m0
+ call assert_equal(PrepIndent("a")[1:] + PrepIndent("b") + ["a"] + PrepIndent("c"), getline(1, '$'))
+ call assert_equal([1, 1, 1, 1, 1, -1, 7, 7, 7, 7, 7, -1, -1, 14, 14, 14, 14, 14], map(range(1, line('$')), 'foldclosed(v:val)'))
+ " moving should not close the folds
+ %d
+ call setline(1, PrepIndent("a") + PrepIndent("b") + PrepIndent("c"))
+ set fdm=indent
+ call cursor(2, 1)
+ %foldopen
+ 7,12m0
+ let folds=repeat([-1], 18)
+ call assert_equal(PrepIndent("b") + PrepIndent("a") + PrepIndent("c"), getline(1, '$'))
+ call assert_equal(folds, map(range(1, line('$')), 'foldclosed(v:val)'))
+ norm! zM
+ " folds are not corrupted and all have been closed
+ call assert_equal([-1, 2, 2, 2, 2, 2, -1, 8, 8, 8, 8, 8, -1, 14, 14, 14, 14, 14], map(range(1, line('$')), 'foldclosed(v:val)'))
+ %d
+ call setline(1, ["a", "\tb", "\tc", "\td", "\te"])
+ set fdm=indent
+ %foldopen
+ 3m4
+ %foldclose
+ call assert_equal(["a", "\tb", "\td", "\tc", "\te"], getline(1, '$'))
+ call assert_equal([-1, 5, 5, 5, 5], map(range(1, line('$')), 'foldclosedend(v:val)'))
+ %d
+ call setline(1, ["a", "\tb", "\tc", "\td", "\te", "z", "\ty", "\tx", "\tw", "\tv"])
+ set fdm=indent foldlevel=0
+ %foldopen
+ 3m1
+ %foldclose
+ call assert_equal(["a", "\tc", "\tb", "\td", "\te", "z", "\ty", "\tx", "\tw", "\tv"], getline(1, '$'))
+ call assert_equal(1, foldlevel(2))
+ call assert_equal(5, foldclosedend(3))
+ call assert_equal([-1, 2, 2, 2, 2, -1, 7, 7, 7, 7], map(range(1, line('$')), 'foldclosed(v:val)'))
+ 2,6m$
+ %foldclose
+ call assert_equal(9, foldclosedend(2))
+ call assert_equal(1, foldlevel(6))
+ call assert_equal(9, foldclosedend(7))
+ call assert_equal([-1, 2, 2, 2, 2, 2, 2, 2, 2, -1], map(range(1, line('$')), 'foldclosed(v:val)'))
+ " Ensure moving around the edges still works.
+ %d
+ call setline(1, PrepIndent("a") + repeat(["a"], 3) + ["\ta"])
+ set fdm=indent foldlevel=0
+ %foldopen
+ 6m$
+ " The first fold has been truncated to the 5'th line.
+ " Second fold has been moved up because the moved line is now below it.
+ call Check_foldlevels([0, 1, 1, 1, 1, 0, 0, 0, 1, 1])
+ bw!
+endfunc
+
+func Test_folddoopen_folddoclosed()
+ new
+ call setline(1, range(1, 9))
+ set foldmethod=manual
+ 1,3 fold
+ 6,8 fold
+
+ " Test without range.
+ folddoopen s/$/o/
+ folddoclosed s/$/c/
+ call assert_equal(['1c', '2c', '3c',
+ \ '4o', '5o',
+ \ '6c', '7c', '8c',
+ \ '9o'], getline(1, '$'))
+
+ " Test with range.
+ call setline(1, range(1, 9))
+ 1,8 folddoopen s/$/o/
+ 4,$ folddoclosed s/$/c/
+ call assert_equal(['1', '2', '3',
+ \ '4o', '5o',
+ \ '6c', '7c', '8c',
+ \ '9'], getline(1, '$'))
+
+ set foldmethod&
+ bw!
+endfunc
+
+func Test_fold_error()
+ new
+ call setline(1, [1, 2])
+
+ for fm in ['indent', 'expr', 'syntax', 'diff']
+ exe 'set foldmethod=' . fm
+ call assert_fails('norm zf', 'E350:')
+ call assert_fails('norm zd', 'E351:')
+ call assert_fails('norm zE', 'E352:')
+ endfor
+
+ set foldmethod=manual
+ call assert_fails('norm zd', 'E490:')
+ call assert_fails('norm zo', 'E490:')
+ call assert_fails('3fold', 'E16:')
+
+ set foldmethod=marker
+ set nomodifiable
+ call assert_fails('1,2fold', 'E21:')
+
+ set modifiable&
+ set foldmethod&
+ bw!
+endfunc
+
+func Test_foldtext_recursive()
+ new
+ call setline(1, ['{{{', 'some text', '}}}'])
+ setlocal foldenable foldmethod=marker foldtext=foldtextresult(v\:foldstart)
+ " This was crashing because of endless recursion.
+ 2foldclose
+ redraw
+ call assert_equal(1, foldlevel(2))
+ call assert_equal(1, foldclosed(2))
+ call assert_equal(3, foldclosedend(2))
+ bwipe!
+endfunc
+
+" Various fold related tests
+
+" Basic test if a fold can be created, opened, moving to the end and closed
+func Test_fold_manual()
+ enew!
+ set fdm=manual
+
+ let content = ['1 aa', '2 bb', '3 cc']
+ call append(0, content)
+ call cursor(1, 1)
+ normal zf2j
+ call assert_equal('1 aa', getline(foldclosed('.')))
+ normal zo
+ call assert_equal(-1, foldclosed('.'))
+ normal ]z
+ call assert_equal('3 cc', getline('.'))
+ normal zc
+ call assert_equal('1 aa', getline(foldclosed('.')))
+
+ set fdm&
+ enew!
+endfunc
+
+" test folding with markers.
+func Test_fold_marker()
+ enew!
+ set fdm=marker fdl=1 fdc=3
+
+ let content = ['4 dd {{{', '5 ee {{{ }}}', '6 ff }}}']
+ call append(0, content)
+ call cursor(2, 1)
+ call assert_equal(2, foldlevel('.'))
+ normal [z
+ call assert_equal(1, foldlevel('.'))
+ exe "normal jo{{ \<Esc>r{jj"
+ call assert_equal(1, foldlevel('.'))
+ normal kYpj
+ call assert_equal(0, foldlevel('.'))
+
+ set fdm& fdl& fdc&
+ enew!
+endfunc
+
+" test create fold markers with C filetype
+func Test_fold_create_marker_in_C()
+ enew!
+ set fdm=marker fdl=9
+ set filetype=c
+
+ let content = [
+ \ '/*',
+ \ ' * comment',
+ \ ' * ',
+ \ ' *',
+ \ ' */',
+ \ 'int f(int* p) {',
+ \ ' *p = 3;',
+ \ ' return 0;',
+ \ '}'
+ \]
+ for c in range(len(content) - 1)
+ bw!
+ call append(0, content)
+ call cursor(c + 1, 1)
+ norm! zfG
+ call assert_equal(content[c] . (c < 4 ? '{{{' : '/*{{{*/'), getline(c + 1))
+ endfor
+
+ set fdm& fdl&
+ enew!
+endfunc
+
+" test folding with indent
+func Test_fold_indent()
+ enew!
+ set fdm=indent sw=2
+
+ let content = ['1 aa', '2 bb', '3 cc']
+ call append(0, content)
+ call cursor(2, 1)
+ exe "normal i \<Esc>jI "
+ call assert_equal(2, foldlevel('.'))
+ normal k
+ call assert_equal(1, foldlevel('.'))
+
+ set fdm& sw&
+ enew!
+endfunc
+
+" test syntax folding
+func Test_fold_syntax()
+ if !has('syntax')
+ return
+ endif
+
+ enew!
+ set fdm=syntax fdl=0
+
+ syn region Hup start="dd" end="ii" fold contains=Fd1,Fd2,Fd3
+ syn region Fd1 start="ee" end="ff" fold contained
+ syn region Fd2 start="gg" end="hh" fold contained
+ syn region Fd3 start="commentstart" end="commentend" fold contained
+ let content = ['3 cc', '4 dd {{{', '5 ee {{{ }}}', '{{{{', '6 ff }}}',
+ \ '6 ff }}}', '7 gg', '8 hh', '9 ii']
+ call append(0, content)
+ normal Gzk
+ call assert_equal('9 ii', getline('.'))
+ normal k
+ call assert_equal('3 cc', getline('.'))
+ exe "normal jAcommentstart \<Esc>Acommentend"
+ set fdl=1
+ normal 3j
+ call assert_equal('7 gg', getline('.'))
+ set fdl=0
+ exe "normal zO\<C-L>j"
+ call assert_equal('8 hh', getline('.'))
+ syn clear Fd1 Fd2 Fd3 Hup
+
+ set fdm& fdl&
+ enew!
+endfunc
+
+func Flvl()
+ let l = getline(v:lnum)
+ if l =~ "bb$"
+ return 2
+ elseif l =~ "gg$"
+ return "s1"
+ elseif l =~ "ii$"
+ return ">2"
+ elseif l =~ "kk$"
+ return "0"
+ endif
+ return "="
+endfun
+
+" test expression folding
+func Test_fold_expr()
+ enew!
+ set fdm=expr fde=Flvl()
+
+ let content = ['1 aa',
+ \ '2 bb',
+ \ '3 cc',
+ \ '4 dd {{{commentstart commentend',
+ \ '5 ee {{{ }}}',
+ \ '{{{',
+ \ '6 ff }}}',
+ \ '6 ff }}}',
+ \ ' 7 gg',
+ \ ' 8 hh',
+ \ '9 ii',
+ \ 'a jj',
+ \ 'b kk']
+ call append(0, content)
+ call cursor(1, 1)
+ exe "normal /bb$\<CR>"
+ call assert_equal(2, foldlevel('.'))
+ exe "normal /hh$\<CR>"
+ call assert_equal(1, foldlevel('.'))
+ exe "normal /ii$\<CR>"
+ call assert_equal(2, foldlevel('.'))
+ exe "normal /kk$\<CR>"
+ call assert_equal(0, foldlevel('.'))
+
+ set fdm& fde&
+ enew!
+endfunc
+
+" Bug with fdm=indent and moving folds
+" Moving a fold a few times, messes up the folds below the moved fold.
+" Fixed by 7.4.700
+func Test_fold_move()
+ enew!
+ set fdm=indent sw=2 fdl=0
+
+ let content = ['', '', 'Line1', ' Line2', ' Line3',
+ \ 'Line4', ' Line5', ' Line6',
+ \ 'Line7', ' Line8', ' Line9']
+ call append(0, content)
+ normal zM
+ call cursor(4, 1)
+ move 2
+ move 1
+ call assert_equal(7, foldclosed(7))
+ call assert_equal(8, foldclosedend(7))
+ call assert_equal(0, foldlevel(9))
+ call assert_equal(10, foldclosed(10))
+ call assert_equal(11, foldclosedend(10))
+ call assert_equal('+-- 2 lines: Line2', foldtextresult(2))
+ call assert_equal('+-- 2 lines: Line8', foldtextresult(10))
+
+ set fdm& sw& fdl&
+ enew!
+endfunc
+
+" test for patch 7.3.637
+" Cannot catch the error caused by a foldopen when there is no fold.
+func Test_foldopen_exception()
+ enew!
+ let a = 'No error caught'
+ try
+ foldopen
+ catch
+ let a = matchstr(v:exception,'^[^ ]*')
+ endtry
+ call assert_equal('Vim(foldopen):E490:', a)
+
+ let a = 'No error caught'
+ try
+ foobar
+ catch
+ let a = matchstr(v:exception,'^[^ ]*')
+ endtry
+ call assert_match('E492:', a)
+endfunc
+
+func Test_fold_last_line_with_pagedown()
+ enew!
+ set fdm=manual
+
+ let expect = '+-- 11 lines: 9---'
+ let content = range(1,19)
+ call append(0, content)
+ normal dd9G
+ normal zfG
+ normal zt
+ call assert_equal('9', getline(foldclosed('.')))
+ call assert_equal('19', getline(foldclosedend('.')))
+ call assert_equal(expect, ScreenLines(1, len(expect))[0])
+ call feedkeys("\<C-F>", 'xt')
+ call assert_equal(expect, ScreenLines(1, len(expect))[0])
+ call feedkeys("\<C-F>", 'xt')
+ call assert_equal(expect, ScreenLines(1, len(expect))[0])
+ call feedkeys("\<C-B>\<C-F>\<C-F>", 'xt')
+ call assert_equal(expect, ScreenLines(1, len(expect))[0])
+
+ set fdm&
+ enew!
+endfunc
+
+func Test_folds_with_rnu()
+ if !CanRunVimInTerminal()
+ return
+ endif
+
+ call writefile([
+ \ 'set fdm=marker rnu foldcolumn=2',
+ \ 'call setline(1, ["{{{1", "nline 1", "{{{1", "line 2"])',
+ \ ], 'Xtest_folds_with_rnu')
+ let buf = RunVimInTerminal('-S Xtest_folds_with_rnu', {})
+
+ call VerifyScreenDump(buf, 'Test_folds_with_rnu_01', {})
+ call term_sendkeys(buf, "j")
+ call VerifyScreenDump(buf, 'Test_folds_with_rnu_02', {})
+
+ " clean up
+ call StopVimInTerminal(buf)
+ call delete('Xtest_folds_with_rnu')
+endfunc
+
+func Test_folds_marker_in_comment2()
+ new
+ call setline(1, ['Lorem ipsum dolor sit', 'Lorem ipsum dolor sit', 'Lorem ipsum dolor sit'])
+ setl fen fdm=marker
+ setl commentstring=<!--%s-->
+ setl comments=s:<!--,m:\ \ \ \ ,e:-->
+ norm! zf2j
+ setl nofen
+ :1y
+ call assert_equal(['Lorem ipsum dolor sit<!--{{{-->'], getreg(0,1,1))
+ :+2y
+ call assert_equal(['Lorem ipsum dolor sit<!--}}}-->'], getreg(0,1,1))
+
+ set foldmethod&
+ bwipe!
+endfunc
diff --git a/src/testdir/test_functions.vim b/src/testdir/test_functions.vim
new file mode 100644
index 0000000..b08d9aa
--- /dev/null
+++ b/src/testdir/test_functions.vim
@@ -0,0 +1,1248 @@
+" Tests for various functions.
+source shared.vim
+
+" Must be done first, since the alternate buffer must be unset.
+func Test_00_bufexists()
+ call assert_equal(0, bufexists('does_not_exist'))
+ call assert_equal(1, bufexists(bufnr('%')))
+ call assert_equal(0, bufexists(0))
+ new Xfoo
+ let bn = bufnr('%')
+ call assert_equal(1, bufexists(bn))
+ call assert_equal(1, bufexists('Xfoo'))
+ call assert_equal(1, bufexists(getcwd() . '/Xfoo'))
+ call assert_equal(1, bufexists(0))
+ bw
+ call assert_equal(0, bufexists(bn))
+ call assert_equal(0, bufexists('Xfoo'))
+endfunc
+
+func Test_empty()
+ call assert_equal(1, empty(''))
+ call assert_equal(0, empty('a'))
+
+ call assert_equal(1, empty(0))
+ call assert_equal(1, empty(-0))
+ call assert_equal(0, empty(1))
+ call assert_equal(0, empty(-1))
+
+ call assert_equal(1, empty(0.0))
+ call assert_equal(1, empty(-0.0))
+ call assert_equal(0, empty(1.0))
+ call assert_equal(0, empty(-1.0))
+ call assert_equal(0, empty(1.0/0.0))
+ call assert_equal(0, empty(0.0/0.0))
+
+ call assert_equal(1, empty([]))
+ call assert_equal(0, empty(['a']))
+
+ call assert_equal(1, empty({}))
+ call assert_equal(0, empty({'a':1}))
+
+ call assert_equal(1, empty(v:null))
+ call assert_equal(1, empty(v:none))
+ call assert_equal(1, empty(v:false))
+ call assert_equal(0, empty(v:true))
+
+ if has('channel')
+ call assert_equal(1, empty(test_null_channel()))
+ endif
+ if has('job')
+ call assert_equal(1, empty(test_null_job()))
+ endif
+
+ call assert_equal(0, empty(function('Test_empty')))
+endfunc
+
+func Test_len()
+ call assert_equal(1, len(0))
+ call assert_equal(2, len(12))
+
+ call assert_equal(0, len(''))
+ call assert_equal(2, len('ab'))
+
+ call assert_equal(0, len([]))
+ call assert_equal(2, len([2, 1]))
+
+ call assert_equal(0, len({}))
+ call assert_equal(2, len({'a': 1, 'b': 2}))
+
+ call assert_fails('call len(v:none)', 'E701:')
+ call assert_fails('call len({-> 0})', 'E701:')
+endfunc
+
+func Test_max()
+ call assert_equal(0, max([]))
+ call assert_equal(2, max([2]))
+ call assert_equal(2, max([1, 2]))
+ call assert_equal(2, max([1, 2, v:null]))
+
+ call assert_equal(0, max({}))
+ call assert_equal(2, max({'a':1, 'b':2}))
+
+ call assert_fails('call max(1)', 'E712:')
+ call assert_fails('call max(v:none)', 'E712:')
+endfunc
+
+func Test_min()
+ call assert_equal(0, min([]))
+ call assert_equal(2, min([2]))
+ call assert_equal(1, min([1, 2]))
+ call assert_equal(0, min([1, 2, v:null]))
+
+ call assert_equal(0, min({}))
+ call assert_equal(1, min({'a':1, 'b':2}))
+
+ call assert_fails('call min(1)', 'E712:')
+ call assert_fails('call min(v:none)', 'E712:')
+endfunc
+
+func Test_strwidth()
+ for aw in ['single', 'double']
+ exe 'set ambiwidth=' . aw
+ call assert_equal(0, strwidth(''))
+ call assert_equal(1, strwidth("\t"))
+ call assert_equal(3, strwidth('Vim'))
+ call assert_equal(4, strwidth(1234))
+ call assert_equal(5, strwidth(-1234))
+
+ call assert_equal(2, strwidth('😉'))
+ call assert_equal(17, strwidth('EÄ¥oÅanÄo ĉiuĵaÅ­de'))
+ call assert_equal((aw == 'single') ? 6 : 7, strwidth('Straße'))
+
+ call assert_fails('call strwidth({->0})', 'E729:')
+ call assert_fails('call strwidth([])', 'E730:')
+ call assert_fails('call strwidth({})', 'E731:')
+ call assert_fails('call strwidth(1.2)', 'E806:')
+ endfor
+
+ set ambiwidth&
+endfunc
+
+func Test_str2nr()
+ call assert_equal(0, str2nr(''))
+ call assert_equal(1, str2nr('1'))
+ call assert_equal(1, str2nr(' 1 '))
+
+ call assert_equal(1, str2nr('+1'))
+ call assert_equal(1, str2nr('+ 1'))
+ call assert_equal(1, str2nr(' + 1 '))
+
+ call assert_equal(-1, str2nr('-1'))
+ call assert_equal(-1, str2nr('- 1'))
+ call assert_equal(-1, str2nr(' - 1 '))
+
+ call assert_equal(123456789, str2nr('123456789'))
+ call assert_equal(-123456789, str2nr('-123456789'))
+
+ call assert_equal(5, str2nr('101', 2))
+ call assert_equal(5, str2nr('0b101', 2))
+ call assert_equal(5, str2nr('0B101', 2))
+ call assert_equal(-5, str2nr('-101', 2))
+ call assert_equal(-5, str2nr('-0b101', 2))
+ call assert_equal(-5, str2nr('-0B101', 2))
+
+ call assert_equal(65, str2nr('101', 8))
+ call assert_equal(65, str2nr('0101', 8))
+ call assert_equal(-65, str2nr('-101', 8))
+ call assert_equal(-65, str2nr('-0101', 8))
+
+ call assert_equal(11259375, str2nr('abcdef', 16))
+ call assert_equal(11259375, str2nr('ABCDEF', 16))
+ call assert_equal(-11259375, str2nr('-ABCDEF', 16))
+ call assert_equal(11259375, str2nr('0xabcdef', 16))
+ call assert_equal(11259375, str2nr('0Xabcdef', 16))
+ call assert_equal(11259375, str2nr('0XABCDEF', 16))
+ call assert_equal(-11259375, str2nr('-0xABCDEF', 16))
+
+ call assert_equal(0, str2nr('0x10'))
+ call assert_equal(0, str2nr('0b10'))
+ call assert_equal(1, str2nr('12', 2))
+ call assert_equal(1, str2nr('18', 8))
+ call assert_equal(1, str2nr('1g', 16))
+
+ call assert_equal(0, str2nr(v:null))
+ call assert_equal(0, str2nr(v:none))
+
+ call assert_fails('call str2nr([])', 'E730:')
+ call assert_fails('call str2nr({->2})', 'E729:')
+ call assert_fails('call str2nr(1.2)', 'E806:')
+ call assert_fails('call str2nr(10, [])', 'E474:')
+endfunc
+
+func Test_strftime()
+ if !exists('*strftime')
+ return
+ endif
+ " Format of strftime() depends on system. We assume
+ " that basic formats tested here are available and
+ " identical on all systems which support strftime().
+ "
+ " The 2nd parameter of strftime() is a local time, so the output day
+ " of strftime() can be 17 or 18, depending on timezone.
+ call assert_match('^2017-01-1[78]$', strftime('%Y-%m-%d', 1484695512))
+ "
+ call assert_match('^\d\d\d\d-\(0\d\|1[012]\)-\([012]\d\|3[01]\) \([01]\d\|2[0-3]\):[0-5]\d:\([0-5]\d\|60\)$', strftime('%Y-%m-%d %H:%M:%S'))
+
+ call assert_fails('call strftime([])', 'E730:')
+ call assert_fails('call strftime("%Y", [])', 'E745:')
+endfunc
+
+func Test_resolve()
+ if !has('unix')
+ return
+ endif
+
+ " Xlink1 -> Xlink2
+ " Xlink2 -> Xlink3
+ silent !ln -s -f Xlink2 Xlink1
+ silent !ln -s -f Xlink3 Xlink2
+ call assert_equal('Xlink3', resolve('Xlink1'))
+ call assert_equal('./Xlink3', resolve('./Xlink1'))
+ call assert_equal('Xlink3/', resolve('Xlink2/'))
+ " FIXME: these tests result in things like "Xlink2/" instead of "Xlink3/"?!
+ "call assert_equal('Xlink3/', resolve('Xlink1/'))
+ "call assert_equal('./Xlink3/', resolve('./Xlink1/'))
+ "call assert_equal(getcwd() . '/Xlink3/', resolve(getcwd() . '/Xlink1/'))
+ call assert_equal(getcwd() . '/Xlink3', resolve(getcwd() . '/Xlink1'))
+
+ " Test resolve() with a symlink cycle.
+ " Xlink1 -> Xlink2
+ " Xlink2 -> Xlink3
+ " Xlink3 -> Xlink1
+ silent !ln -s -f Xlink1 Xlink3
+ call assert_fails('call resolve("Xlink1")', 'E655:')
+ call assert_fails('call resolve("./Xlink1")', 'E655:')
+ call assert_fails('call resolve("Xlink2")', 'E655:')
+ call assert_fails('call resolve("Xlink3")', 'E655:')
+ call delete('Xlink1')
+ call delete('Xlink2')
+ call delete('Xlink3')
+
+ silent !ln -s -f Xdir//Xfile Xlink
+ call assert_equal('Xdir/Xfile', resolve('Xlink'))
+ call delete('Xlink')
+
+ silent !ln -s -f Xlink2/ Xlink1
+ call assert_equal('Xlink2', resolve('Xlink1'))
+ call assert_equal('Xlink2/', resolve('Xlink1/'))
+ call delete('Xlink1')
+
+ silent !ln -s -f ./Xlink2 Xlink1
+ call assert_equal('Xlink2', resolve('Xlink1'))
+ call assert_equal('./Xlink2', resolve('./Xlink1'))
+ call delete('Xlink1')
+endfunc
+
+func Test_simplify()
+ call assert_equal('', simplify(''))
+ call assert_equal('/', simplify('/'))
+ call assert_equal('/', simplify('/.'))
+ call assert_equal('/', simplify('/..'))
+ call assert_equal('/...', simplify('/...'))
+ call assert_equal('./dir/file', simplify('./dir/file'))
+ call assert_equal('./dir/file', simplify('.///dir//file'))
+ call assert_equal('./dir/file', simplify('./dir/./file'))
+ call assert_equal('./file', simplify('./dir/../file'))
+ call assert_equal('../dir/file', simplify('dir/../../dir/file'))
+ call assert_equal('./file', simplify('dir/.././file'))
+
+ call assert_fails('call simplify({->0})', 'E729:')
+ call assert_fails('call simplify([])', 'E730:')
+ call assert_fails('call simplify({})', 'E731:')
+ call assert_fails('call simplify(1.2)', 'E806:')
+endfunc
+
+func Test_pathshorten()
+ call assert_equal('', pathshorten(''))
+ call assert_equal('foo', pathshorten('foo'))
+ call assert_equal('/foo', pathshorten('/foo'))
+ call assert_equal('f/', pathshorten('foo/'))
+ call assert_equal('f/bar', pathshorten('foo/bar'))
+ call assert_equal('f/b/foobar', pathshorten('foo/bar/foobar'))
+ call assert_equal('/f/b/foobar', pathshorten('/foo/bar/foobar'))
+ call assert_equal('.f/bar', pathshorten('.foo/bar'))
+ call assert_equal('~f/bar', pathshorten('~foo/bar'))
+ call assert_equal('~.f/bar', pathshorten('~.foo/bar'))
+ call assert_equal('.~f/bar', pathshorten('.~foo/bar'))
+ call assert_equal('~/f/bar', pathshorten('~/foo/bar'))
+endfunc
+
+func Test_strpart()
+ call assert_equal('de', strpart('abcdefg', 3, 2))
+ call assert_equal('ab', strpart('abcdefg', -2, 4))
+ call assert_equal('abcdefg', strpart('abcdefg', -2))
+ call assert_equal('fg', strpart('abcdefg', 5, 4))
+ call assert_equal('defg', strpart('abcdefg', 3))
+
+ call assert_equal('lép', strpart('éléphant', 2, 4))
+ call assert_equal('léphant', strpart('éléphant', 2))
+endfunc
+
+func Test_tolower()
+ call assert_equal("", tolower(""))
+
+ " Test with all printable ASCII characters.
+ call assert_equal(' !"#$%&''()*+,-./0123456789:;<=>?@abcdefghijklmnopqrstuvwxyz[\]^_`abcdefghijklmnopqrstuvwxyz{|}~',
+ \ tolower(' !"#$%&''()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~'))
+
+ " Test with a few uppercase diacritics.
+ call assert_equal("aàáâãäåÄăąǎǟǡả", tolower("AÀÃÂÃÄÅĀĂĄÇǞǠẢ"))
+ call assert_equal("bḃḇ", tolower("BḂḆ"))
+ call assert_equal("cçćĉċÄ", tolower("CÇĆĈĊČ"))
+ call assert_equal("dÄđḋá¸á¸‘", tolower("DÄŽÄḊḎá¸"))
+ call assert_equal("eèéêëēĕėęěẻẽ", tolower("EÈÉÊËĒĔĖĘĚẺẼ"))
+ call assert_equal("fḟ ", tolower("FḞ "))
+ call assert_equal("gÄğġģǥǧǵḡ", tolower("GĜĞĠĢǤǦǴḠ"))
+ call assert_equal("hĥħḣḧḩ", tolower("HĤĦḢḦḨ"))
+ call assert_equal("iìíîïĩīĭįiÇỉ", tolower("IÃŒÃÃŽÃĨĪĬĮİÇỈ"))
+ call assert_equal("jĵ", tolower("JĴ"))
+ call assert_equal("kķǩḱḵ", tolower("KĶǨḰḴ"))
+ call assert_equal("lĺļľŀłḻ", tolower("LĹĻĽĿÅḺ"))
+ call assert_equal("mḿá¹", tolower("MḾṀ"))
+ call assert_equal("nñńņňṅṉ", tolower("NÑŃŅŇṄṈ"))
+ call assert_equal("oòóôõöøÅÅÅ‘Æ¡Ç’Ç«Ç­á»", tolower("OÒÓÔÕÖØŌŎÅƠǑǪǬỎ"))
+ call assert_equal("pṕṗ", tolower("PṔṖ"))
+ call assert_equal("q", tolower("Q"))
+ call assert_equal("rŕŗřṙṟ", tolower("RŔŖŘṘṞ"))
+ call assert_equal("sÅ›Åşšṡ", tolower("SŚŜŞŠṠ"))
+ call assert_equal("tţťŧṫṯ", tolower("TŢŤŦṪṮ"))
+ call assert_equal("uùúûüũūŭůűųưǔủ", tolower("UÙÚÛÜŨŪŬŮŰŲƯǓỦ"))
+ call assert_equal("vá¹½", tolower("Vá¹¼"))
+ call assert_equal("wŵáºáºƒáº…ẇ", tolower("WŴẀẂẄẆ"))
+ call assert_equal("xẋáº", tolower("XẊẌ"))
+ call assert_equal("yýŷÿáºá»³á»·á»¹", tolower("YÃŶŸẎỲỶỸ"))
+ call assert_equal("zźżžƶẑẕ", tolower("ZŹŻŽƵáºáº”"))
+
+ " Test with a few lowercase diacritics, which should remain unchanged.
+ call assert_equal("aàáâãäåÄăąǎǟǡả", tolower("aàáâãäåÄăąǎǟǡả"))
+ call assert_equal("bḃḇ", tolower("bḃḇ"))
+ call assert_equal("cçćĉċÄ", tolower("cçćĉċÄ"))
+ call assert_equal("dÄđḋá¸á¸‘", tolower("dÄđḋá¸á¸‘"))
+ call assert_equal("eèéêëēĕėęěẻẽ", tolower("eèéêëēĕėęěẻẽ"))
+ call assert_equal("fḟ", tolower("fḟ"))
+ call assert_equal("gÄğġģǥǧǵḡ", tolower("gÄğġģǥǧǵḡ"))
+ call assert_equal("hĥħḣḧḩẖ", tolower("hĥħḣḧḩẖ"))
+ call assert_equal("iìíîïĩīĭįÇỉ", tolower("iìíîïĩīĭįÇỉ"))
+ call assert_equal("jĵǰ", tolower("jĵǰ"))
+ call assert_equal("kķǩḱḵ", tolower("kķǩḱḵ"))
+ call assert_equal("lĺļľŀłḻ", tolower("lĺļľŀłḻ"))
+ call assert_equal("mḿṠ", tolower("mḿṠ"))
+ call assert_equal("nñńņňʼnṅṉ", tolower("nñńņňʼnṅṉ"))
+ call assert_equal("oòóôõöøÅÅÅ‘Æ¡Ç’Ç«Ç­á»", tolower("oòóôõöøÅÅÅ‘Æ¡Ç’Ç«Ç­á»"))
+ call assert_equal("pṕṗ", tolower("pṕṗ"))
+ call assert_equal("q", tolower("q"))
+ call assert_equal("rŕŗřṙṟ", tolower("rŕŗřṙṟ"))
+ call assert_equal("sÅ›Åşšṡ", tolower("sÅ›Åşšṡ"))
+ call assert_equal("tţťŧṫṯẗ", tolower("tţťŧṫṯẗ"))
+ call assert_equal("uùúûüũūŭůűųưǔủ", tolower("uùúûüũūŭůűųưǔủ"))
+ call assert_equal("vá¹½", tolower("vá¹½"))
+ call assert_equal("wŵáºáºƒáº…ẇẘ", tolower("wŵáºáºƒáº…ẇẘ"))
+ call assert_equal("ẋáº", tolower("ẋáº"))
+ call assert_equal("yýÿŷáºáº™á»³á»·á»¹", tolower("yýÿŷáºáº™á»³á»·á»¹"))
+ call assert_equal("zźżžƶẑẕ", tolower("zźżžƶẑẕ"))
+
+ " According to https://twitter.com/jifa/status/625776454479970304
+ " Ⱥ (U+023A) and Ⱦ (U+023E) are the *only* code points to increase
+ " in length (2 to 3 bytes) when lowercased. So let's test them.
+ call assert_equal("ⱥ ⱦ", tolower("Ⱥ Ⱦ"))
+
+ " This call to tolower with invalid utf8 sequence used to cause access to
+ " invalid memory.
+ call tolower("\xC0\x80\xC0")
+ call tolower("123\xC0\x80\xC0")
+endfunc
+
+func Test_toupper()
+ call assert_equal("", toupper(""))
+
+ " Test with all printable ASCII characters.
+ call assert_equal(' !"#$%&''()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`ABCDEFGHIJKLMNOPQRSTUVWXYZ{|}~',
+ \ toupper(' !"#$%&''()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~'))
+
+ " Test with a few lowercase diacritics.
+ call assert_equal("AÀÃÂÃÄÅĀĂĄÇǞǠẢ", toupper("aàáâãäåÄăąǎǟǡả"))
+ call assert_equal("BḂḆ", toupper("bḃḇ"))
+ call assert_equal("CÇĆĈĊČ", toupper("cçćĉċÄ"))
+ call assert_equal("DÄŽÄḊḎá¸", toupper("dÄđḋá¸á¸‘"))
+ call assert_equal("EÈÉÊËĒĔĖĘĚẺẼ", toupper("eèéêëēĕėęěẻẽ"))
+ call assert_equal("FḞ", toupper("fḟ"))
+ call assert_equal("GĜĞĠĢǤǦǴḠ", toupper("gÄğġģǥǧǵḡ"))
+ call assert_equal("HĤĦḢḦḨẖ", toupper("hĥħḣḧḩẖ"))
+ call assert_equal("IÃŒÃÃŽÃĨĪĬĮÇỈ", toupper("iìíîïĩīĭįÇỉ"))
+ call assert_equal("JĴǰ", toupper("jĵǰ"))
+ call assert_equal("KĶǨḰḴ", toupper("kķǩḱḵ"))
+ call assert_equal("LĹĻĽĿÅḺ", toupper("lĺļľŀłḻ"))
+ call assert_equal("MḾṀ ", toupper("mḿṠ"))
+ call assert_equal("NÑŃŅŇʼnṄṈ", toupper("nñńņňʼnṅṉ"))
+ call assert_equal("OÒÓÔÕÖØŌŎÅƠǑǪǬỎ", toupper("oòóôõöøÅÅÅ‘Æ¡Ç’Ç«Ç­á»"))
+ call assert_equal("PṔṖ", toupper("pṕṗ"))
+ call assert_equal("Q", toupper("q"))
+ call assert_equal("RŔŖŘṘṞ", toupper("rŕŗřṙṟ"))
+ call assert_equal("SŚŜŞŠṠ", toupper("sÅ›Åşšṡ"))
+ call assert_equal("TŢŤŦṪṮẗ", toupper("tţťŧṫṯẗ"))
+ call assert_equal("UÙÚÛÜŨŪŬŮŰŲƯǓỦ", toupper("uùúûüũūŭůűųưǔủ"))
+ call assert_equal("Vá¹¼", toupper("vá¹½"))
+ call assert_equal("WŴẀẂẄẆẘ", toupper("wŵáºáºƒáº…ẇẘ"))
+ call assert_equal("ẊẌ", toupper("ẋáº"))
+ call assert_equal("YßŶẎẙỲỶỸ", toupper("yýÿŷáºáº™á»³á»·á»¹"))
+ call assert_equal("ZŹŻŽƵáºáº”", toupper("zźżžƶẑẕ"))
+
+ " Test that uppercase diacritics, which should remain unchanged.
+ call assert_equal("AÀÃÂÃÄÅĀĂĄÇǞǠẢ", toupper("AÀÃÂÃÄÅĀĂĄÇǞǠẢ"))
+ call assert_equal("BḂḆ", toupper("BḂḆ"))
+ call assert_equal("CÇĆĈĊČ", toupper("CÇĆĈĊČ"))
+ call assert_equal("DÄŽÄḊḎá¸", toupper("DÄŽÄḊḎá¸"))
+ call assert_equal("EÈÉÊËĒĔĖĘĚẺẼ", toupper("EÈÉÊËĒĔĖĘĚẺẼ"))
+ call assert_equal("FḞ ", toupper("FḞ "))
+ call assert_equal("GĜĞĠĢǤǦǴḠ", toupper("GĜĞĠĢǤǦǴḠ"))
+ call assert_equal("HĤĦḢḦḨ", toupper("HĤĦḢḦḨ"))
+ call assert_equal("IÃŒÃÃŽÃĨĪĬĮİÇỈ", toupper("IÃŒÃÃŽÃĨĪĬĮİÇỈ"))
+ call assert_equal("JÄ´", toupper("JÄ´"))
+ call assert_equal("KĶǨḰḴ", toupper("KĶǨḰḴ"))
+ call assert_equal("LĹĻĽĿÅḺ", toupper("LĹĻĽĿÅḺ"))
+ call assert_equal("MḾṀ", toupper("MḾṀ"))
+ call assert_equal("NÑŃŅŇṄṈ", toupper("NÑŃŅŇṄṈ"))
+ call assert_equal("OÒÓÔÕÖØŌŎÅƠǑǪǬỎ", toupper("OÒÓÔÕÖØŌŎÅƠǑǪǬỎ"))
+ call assert_equal("PṔṖ", toupper("PṔṖ"))
+ call assert_equal("Q", toupper("Q"))
+ call assert_equal("RŔŖŘṘṞ", toupper("RŔŖŘṘṞ"))
+ call assert_equal("SŚŜŞŠṠ", toupper("SŚŜŞŠṠ"))
+ call assert_equal("TŢŤŦṪṮ", toupper("TŢŤŦṪṮ"))
+ call assert_equal("UÙÚÛÜŨŪŬŮŰŲƯǓỦ", toupper("UÙÚÛÜŨŪŬŮŰŲƯǓỦ"))
+ call assert_equal("Vá¹¼", toupper("Vá¹¼"))
+ call assert_equal("WŴẀẂẄẆ", toupper("WŴẀẂẄẆ"))
+ call assert_equal("XẊẌ", toupper("XẊẌ"))
+ call assert_equal("YÃŶŸẎỲỶỸ", toupper("YÃŶŸẎỲỶỸ"))
+ call assert_equal("ZŹŻŽƵáºáº”", toupper("ZŹŻŽƵáºáº”"))
+
+ call assert_equal("Ⱥ Ⱦ", toupper("ⱥ ⱦ"))
+
+ " This call to toupper with invalid utf8 sequence used to cause access to
+ " invalid memory.
+ call toupper("\xC0\x80\xC0")
+ call toupper("123\xC0\x80\xC0")
+endfunc
+
+" Tests for the mode() function
+let current_modes = ''
+func Save_mode()
+ let g:current_modes = mode(0) . '-' . mode(1)
+ return ''
+endfunc
+
+func Test_mode()
+ new
+ call append(0, ["Blue Ball Black", "Brown Band Bowl", ""])
+
+ " Only complete from the current buffer.
+ set complete=.
+
+ inoremap <F2> <C-R>=Save_mode()<CR>
+
+ normal! 3G
+ exe "normal i\<F2>\<Esc>"
+ call assert_equal('i-i', g:current_modes)
+ " i_CTRL-P: Multiple matches
+ exe "normal i\<C-G>uBa\<C-P>\<F2>\<Esc>u"
+ call assert_equal('i-ic', g:current_modes)
+ " i_CTRL-P: Single match
+ exe "normal iBro\<C-P>\<F2>\<Esc>u"
+ call assert_equal('i-ic', g:current_modes)
+ " i_CTRL-X
+ exe "normal iBa\<C-X>\<F2>\<Esc>u"
+ call assert_equal('i-ix', g:current_modes)
+ " i_CTRL-X CTRL-P: Multiple matches
+ exe "normal iBa\<C-X>\<C-P>\<F2>\<Esc>u"
+ call assert_equal('i-ic', g:current_modes)
+ " i_CTRL-X CTRL-P: Single match
+ exe "normal iBro\<C-X>\<C-P>\<F2>\<Esc>u"
+ call assert_equal('i-ic', g:current_modes)
+ " i_CTRL-X CTRL-P + CTRL-P: Single match
+ exe "normal iBro\<C-X>\<C-P>\<C-P>\<F2>\<Esc>u"
+ call assert_equal('i-ic', g:current_modes)
+ " i_CTRL-X CTRL-L: Multiple matches
+ exe "normal i\<C-X>\<C-L>\<F2>\<Esc>u"
+ call assert_equal('i-ic', g:current_modes)
+ " i_CTRL-X CTRL-L: Single match
+ exe "normal iBlu\<C-X>\<C-L>\<F2>\<Esc>u"
+ call assert_equal('i-ic', g:current_modes)
+ " i_CTRL-P: No match
+ exe "normal iCom\<C-P>\<F2>\<Esc>u"
+ call assert_equal('i-ic', g:current_modes)
+ " i_CTRL-X CTRL-P: No match
+ exe "normal iCom\<C-X>\<C-P>\<F2>\<Esc>u"
+ call assert_equal('i-ic', g:current_modes)
+ " i_CTRL-X CTRL-L: No match
+ exe "normal iabc\<C-X>\<C-L>\<F2>\<Esc>u"
+ call assert_equal('i-ic', g:current_modes)
+
+ " R_CTRL-P: Multiple matches
+ exe "normal RBa\<C-P>\<F2>\<Esc>u"
+ call assert_equal('R-Rc', g:current_modes)
+ " R_CTRL-P: Single match
+ exe "normal RBro\<C-P>\<F2>\<Esc>u"
+ call assert_equal('R-Rc', g:current_modes)
+ " R_CTRL-X
+ exe "normal RBa\<C-X>\<F2>\<Esc>u"
+ call assert_equal('R-Rx', g:current_modes)
+ " R_CTRL-X CTRL-P: Multiple matches
+ exe "normal RBa\<C-X>\<C-P>\<F2>\<Esc>u"
+ call assert_equal('R-Rc', g:current_modes)
+ " R_CTRL-X CTRL-P: Single match
+ exe "normal RBro\<C-X>\<C-P>\<F2>\<Esc>u"
+ call assert_equal('R-Rc', g:current_modes)
+ " R_CTRL-X CTRL-P + CTRL-P: Single match
+ exe "normal RBro\<C-X>\<C-P>\<C-P>\<F2>\<Esc>u"
+ call assert_equal('R-Rc', g:current_modes)
+ " R_CTRL-X CTRL-L: Multiple matches
+ exe "normal R\<C-X>\<C-L>\<F2>\<Esc>u"
+ call assert_equal('R-Rc', g:current_modes)
+ " R_CTRL-X CTRL-L: Single match
+ exe "normal RBlu\<C-X>\<C-L>\<F2>\<Esc>u"
+ call assert_equal('R-Rc', g:current_modes)
+ " R_CTRL-P: No match
+ exe "normal RCom\<C-P>\<F2>\<Esc>u"
+ call assert_equal('R-Rc', g:current_modes)
+ " R_CTRL-X CTRL-P: No match
+ exe "normal RCom\<C-X>\<C-P>\<F2>\<Esc>u"
+ call assert_equal('R-Rc', g:current_modes)
+ " R_CTRL-X CTRL-L: No match
+ exe "normal Rabc\<C-X>\<C-L>\<F2>\<Esc>u"
+ call assert_equal('R-Rc', g:current_modes)
+
+ call assert_equal('n', mode(0))
+ call assert_equal('n', mode(1))
+
+ " i_CTRL-O
+ exe "normal i\<C-O>:call Save_mode()\<Cr>\<Esc>"
+ call assert_equal("n-niI", g:current_modes)
+
+ " R_CTRL-O
+ exe "normal R\<C-O>:call Save_mode()\<Cr>\<Esc>"
+ call assert_equal("n-niR", g:current_modes)
+
+ " gR_CTRL-O
+ exe "normal gR\<C-O>:call Save_mode()\<Cr>\<Esc>"
+ call assert_equal("n-niV", g:current_modes)
+
+ " How to test operator-pending mode?
+
+ call feedkeys("v", 'xt')
+ call assert_equal('v', mode())
+ call assert_equal('v', mode(1))
+ call feedkeys("\<Esc>V", 'xt')
+ call assert_equal('V', mode())
+ call assert_equal('V', mode(1))
+ call feedkeys("\<Esc>\<C-V>", 'xt')
+ call assert_equal("\<C-V>", mode())
+ call assert_equal("\<C-V>", mode(1))
+ call feedkeys("\<Esc>", 'xt')
+
+ call feedkeys("gh", 'xt')
+ call assert_equal('s', mode())
+ call assert_equal('s', mode(1))
+ call feedkeys("\<Esc>gH", 'xt')
+ call assert_equal('S', mode())
+ call assert_equal('S', mode(1))
+ call feedkeys("\<Esc>g\<C-H>", 'xt')
+ call assert_equal("\<C-S>", mode())
+ call assert_equal("\<C-S>", mode(1))
+ call feedkeys("\<Esc>", 'xt')
+
+ call feedkeys(":echo \<C-R>=Save_mode()\<C-U>\<CR>", 'xt')
+ call assert_equal('c-c', g:current_modes)
+ call feedkeys("gQecho \<C-R>=Save_mode()\<CR>\<CR>vi\<CR>", 'xt')
+ call assert_equal('c-cv', g:current_modes)
+ " How to test Ex mode?
+
+ bwipe!
+ iunmap <F2>
+ set complete&
+endfunc
+
+func Test_getbufvar()
+ let bnr = bufnr('%')
+ let b:var_num = '1234'
+ let def_num = '5678'
+ call assert_equal('1234', getbufvar(bnr, 'var_num'))
+ call assert_equal('1234', getbufvar(bnr, 'var_num', def_num))
+
+ let bd = getbufvar(bnr, '')
+ call assert_equal('1234', bd['var_num'])
+ call assert_true(exists("bd['changedtick']"))
+ call assert_equal(2, len(bd))
+
+ let bd2 = getbufvar(bnr, '', def_num)
+ call assert_equal(bd, bd2)
+
+ unlet b:var_num
+ call assert_equal(def_num, getbufvar(bnr, 'var_num', def_num))
+ call assert_equal('', getbufvar(bnr, 'var_num'))
+
+ let bd = getbufvar(bnr, '')
+ call assert_equal(1, len(bd))
+ let bd = getbufvar(bnr, '',def_num)
+ call assert_equal(1, len(bd))
+
+ call assert_equal('', getbufvar(9999, ''))
+ call assert_equal(def_num, getbufvar(9999, '', def_num))
+ unlet def_num
+
+ call assert_equal(0, getbufvar(bnr, '&autoindent'))
+ call assert_equal(0, getbufvar(bnr, '&autoindent', 1))
+
+ " Open new window with forced option values
+ set fileformats=unix,dos
+ new ++ff=dos ++bin ++enc=iso-8859-2
+ call assert_equal('dos', getbufvar(bufnr('%'), '&fileformat'))
+ call assert_equal(1, getbufvar(bufnr('%'), '&bin'))
+ call assert_equal('iso-8859-2', getbufvar(bufnr('%'), '&fenc'))
+ close
+
+ set fileformats&
+endfunc
+
+func Test_last_buffer_nr()
+ call assert_equal(bufnr('$'), last_buffer_nr())
+endfunc
+
+func Test_stridx()
+ call assert_equal(-1, stridx('', 'l'))
+ call assert_equal(0, stridx('', ''))
+ call assert_equal(0, stridx('hello', ''))
+ call assert_equal(-1, stridx('hello', 'L'))
+ call assert_equal(2, stridx('hello', 'l', -1))
+ call assert_equal(2, stridx('hello', 'l', 0))
+ call assert_equal(2, stridx('hello', 'l', 1))
+ call assert_equal(3, stridx('hello', 'l', 3))
+ call assert_equal(-1, stridx('hello', 'l', 4))
+ call assert_equal(-1, stridx('hello', 'l', 10))
+ call assert_equal(2, stridx('hello', 'll'))
+ call assert_equal(-1, stridx('hello', 'hello world'))
+endfunc
+
+func Test_strridx()
+ call assert_equal(-1, strridx('', 'l'))
+ call assert_equal(0, strridx('', ''))
+ call assert_equal(5, strridx('hello', ''))
+ call assert_equal(-1, strridx('hello', 'L'))
+ call assert_equal(3, strridx('hello', 'l'))
+ call assert_equal(3, strridx('hello', 'l', 10))
+ call assert_equal(3, strridx('hello', 'l', 3))
+ call assert_equal(2, strridx('hello', 'l', 2))
+ call assert_equal(-1, strridx('hello', 'l', 1))
+ call assert_equal(-1, strridx('hello', 'l', 0))
+ call assert_equal(-1, strridx('hello', 'l', -1))
+ call assert_equal(2, strridx('hello', 'll'))
+ call assert_equal(-1, strridx('hello', 'hello world'))
+endfunc
+
+func Test_match_func()
+ call assert_equal(4, match('testing', 'ing'))
+ call assert_equal(4, match('testing', 'ing', 2))
+ call assert_equal(-1, match('testing', 'ing', 5))
+ call assert_equal(-1, match('testing', 'ing', 8))
+ call assert_equal(1, match(['vim', 'testing', 'execute'], 'ing'))
+ call assert_equal(-1, match(['vim', 'testing', 'execute'], 'img'))
+endfunc
+
+func Test_matchend()
+ call assert_equal(7, matchend('testing', 'ing'))
+ call assert_equal(7, matchend('testing', 'ing', 2))
+ call assert_equal(-1, matchend('testing', 'ing', 5))
+ call assert_equal(-1, matchend('testing', 'ing', 8))
+ call assert_equal(match(['vim', 'testing', 'execute'], 'ing'), matchend(['vim', 'testing', 'execute'], 'ing'))
+ call assert_equal(match(['vim', 'testing', 'execute'], 'img'), matchend(['vim', 'testing', 'execute'], 'img'))
+endfunc
+
+func Test_matchlist()
+ call assert_equal(['acd', 'a', '', 'c', 'd', '', '', '', '', ''], matchlist('acd', '\(a\)\?\(b\)\?\(c\)\?\(.*\)'))
+ call assert_equal(['d', '', '', '', 'd', '', '', '', '', ''], matchlist('acd', '\(a\)\?\(b\)\?\(c\)\?\(.*\)', 2))
+ call assert_equal([], matchlist('acd', '\(a\)\?\(b\)\?\(c\)\?\(.*\)', 4))
+endfunc
+
+func Test_matchstr()
+ call assert_equal('ing', matchstr('testing', 'ing'))
+ call assert_equal('ing', matchstr('testing', 'ing', 2))
+ call assert_equal('', matchstr('testing', 'ing', 5))
+ call assert_equal('', matchstr('testing', 'ing', 8))
+ call assert_equal('testing', matchstr(['vim', 'testing', 'execute'], 'ing'))
+ call assert_equal('', matchstr(['vim', 'testing', 'execute'], 'img'))
+endfunc
+
+func Test_matchstrpos()
+ call assert_equal(['ing', 4, 7], matchstrpos('testing', 'ing'))
+ call assert_equal(['ing', 4, 7], matchstrpos('testing', 'ing', 2))
+ call assert_equal(['', -1, -1], matchstrpos('testing', 'ing', 5))
+ call assert_equal(['', -1, -1], matchstrpos('testing', 'ing', 8))
+ call assert_equal(['ing', 1, 4, 7], matchstrpos(['vim', 'testing', 'execute'], 'ing'))
+ call assert_equal(['', -1, -1, -1], matchstrpos(['vim', 'testing', 'execute'], 'img'))
+endfunc
+
+func Test_nextnonblank_prevnonblank()
+ new
+insert
+This
+
+
+is
+
+a
+Test
+.
+ call assert_equal(0, nextnonblank(-1))
+ call assert_equal(0, nextnonblank(0))
+ call assert_equal(1, nextnonblank(1))
+ call assert_equal(4, nextnonblank(2))
+ call assert_equal(4, nextnonblank(3))
+ call assert_equal(4, nextnonblank(4))
+ call assert_equal(6, nextnonblank(5))
+ call assert_equal(6, nextnonblank(6))
+ call assert_equal(7, nextnonblank(7))
+ call assert_equal(0, nextnonblank(8))
+
+ call assert_equal(0, prevnonblank(-1))
+ call assert_equal(0, prevnonblank(0))
+ call assert_equal(1, prevnonblank(1))
+ call assert_equal(1, prevnonblank(2))
+ call assert_equal(1, prevnonblank(3))
+ call assert_equal(4, prevnonblank(4))
+ call assert_equal(4, prevnonblank(5))
+ call assert_equal(6, prevnonblank(6))
+ call assert_equal(7, prevnonblank(7))
+ call assert_equal(0, prevnonblank(8))
+ bw!
+endfunc
+
+func Test_byte2line_line2byte()
+ new
+ set endofline
+ call setline(1, ['a', 'bc', 'd'])
+
+ set fileformat=unix
+ call assert_equal([-1, -1, 1, 1, 2, 2, 2, 3, 3, -1],
+ \ map(range(-1, 8), 'byte2line(v:val)'))
+ call assert_equal([-1, -1, 1, 3, 6, 8, -1],
+ \ map(range(-1, 5), 'line2byte(v:val)'))
+
+ set fileformat=mac
+ call assert_equal([-1, -1, 1, 1, 2, 2, 2, 3, 3, -1],
+ \ map(range(-1, 8), 'byte2line(v:val)'))
+ call assert_equal([-1, -1, 1, 3, 6, 8, -1],
+ \ map(range(-1, 5), 'line2byte(v:val)'))
+
+ set fileformat=dos
+ call assert_equal([-1, -1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, -1],
+ \ map(range(-1, 11), 'byte2line(v:val)'))
+ call assert_equal([-1, -1, 1, 4, 8, 11, -1],
+ \ map(range(-1, 5), 'line2byte(v:val)'))
+
+ bw!
+ set noendofline nofixendofline
+ normal a-
+ for ff in ["unix", "mac", "dos"]
+ let &fileformat = ff
+ call assert_equal(1, line2byte(1))
+ call assert_equal(2, line2byte(2)) " line2byte(line("$") + 1) is the buffer size plus one (as per :help line2byte).
+ endfor
+
+ set endofline& fixendofline& fileformat&
+ bw!
+endfunc
+
+func Test_count()
+ let l = ['a', 'a', 'A', 'b']
+ call assert_equal(2, count(l, 'a'))
+ call assert_equal(1, count(l, 'A'))
+ call assert_equal(1, count(l, 'b'))
+ call assert_equal(0, count(l, 'B'))
+
+ call assert_equal(2, count(l, 'a', 0))
+ call assert_equal(1, count(l, 'A', 0))
+ call assert_equal(1, count(l, 'b', 0))
+ call assert_equal(0, count(l, 'B', 0))
+
+ call assert_equal(3, count(l, 'a', 1))
+ call assert_equal(3, count(l, 'A', 1))
+ call assert_equal(1, count(l, 'b', 1))
+ call assert_equal(1, count(l, 'B', 1))
+ call assert_equal(0, count(l, 'c', 1))
+
+ call assert_equal(1, count(l, 'a', 0, 1))
+ call assert_equal(2, count(l, 'a', 1, 1))
+ call assert_fails('call count(l, "a", 0, 10)', 'E684:')
+
+ let d = {1: 'a', 2: 'a', 3: 'A', 4: 'b'}
+ call assert_equal(2, count(d, 'a'))
+ call assert_equal(1, count(d, 'A'))
+ call assert_equal(1, count(d, 'b'))
+ call assert_equal(0, count(d, 'B'))
+
+ call assert_equal(2, count(d, 'a', 0))
+ call assert_equal(1, count(d, 'A', 0))
+ call assert_equal(1, count(d, 'b', 0))
+ call assert_equal(0, count(d, 'B', 0))
+
+ call assert_equal(3, count(d, 'a', 1))
+ call assert_equal(3, count(d, 'A', 1))
+ call assert_equal(1, count(d, 'b', 1))
+ call assert_equal(1, count(d, 'B', 1))
+ call assert_equal(0, count(d, 'c', 1))
+
+ call assert_fails('call count(d, "a", 0, 1)', 'E474:')
+
+ call assert_equal(0, count("foo", "bar"))
+ call assert_equal(1, count("foo", "oo"))
+ call assert_equal(2, count("foo", "o"))
+ call assert_equal(0, count("foo", "O"))
+ call assert_equal(2, count("foo", "O", 1))
+ call assert_equal(2, count("fooooo", "oo"))
+ call assert_equal(0, count("foo", ""))
+endfunc
+
+func Test_changenr()
+ new Xchangenr
+ call assert_equal(0, changenr())
+ norm ifoo
+ call assert_equal(1, changenr())
+ set undolevels=10
+ norm Sbar
+ call assert_equal(2, changenr())
+ undo
+ call assert_equal(1, changenr())
+ redo
+ call assert_equal(2, changenr())
+ bw!
+ set undolevels&
+endfunc
+
+func Test_filewritable()
+ new Xfilewritable
+ write!
+ call assert_equal(1, filewritable('Xfilewritable'))
+
+ call assert_notequal(0, setfperm('Xfilewritable', 'r--r-----'))
+ call assert_equal(0, filewritable('Xfilewritable'))
+
+ call assert_notequal(0, setfperm('Xfilewritable', 'rw-r-----'))
+ call assert_equal(1, filewritable('Xfilewritable'))
+
+ call assert_equal(0, filewritable('doesnotexist'))
+
+ call delete('Xfilewritable')
+ bw!
+endfunc
+
+func Test_Executable()
+ if has('win32')
+ call assert_equal(1, executable('notepad'))
+ call assert_equal(1, executable('notepad.exe'))
+ call assert_equal(0, executable('notepad.exe.exe'))
+ call assert_equal(0, executable('shell32.dll'))
+ call assert_equal(0, executable('win.ini'))
+ elseif has('unix')
+ call assert_equal(1, executable('cat'))
+ call assert_equal(0, executable('nodogshere'))
+ endif
+endfunc
+
+func Test_hostname()
+ let hostname_vim = hostname()
+ if has('unix')
+ let hostname_system = systemlist('uname -n')[0]
+ call assert_equal(hostname_vim, hostname_system)
+ endif
+endfunc
+
+func Test_getpid()
+ " getpid() always returns the same value within a vim instance.
+ call assert_equal(getpid(), getpid())
+ if has('unix')
+ call assert_equal(systemlist('echo $PPID')[0], string(getpid()))
+ endif
+endfunc
+
+func Test_hlexists()
+ call assert_equal(0, hlexists('does_not_exist'))
+ call assert_equal(0, hlexists('Number'))
+ call assert_equal(0, highlight_exists('does_not_exist'))
+ call assert_equal(0, highlight_exists('Number'))
+ syntax on
+ call assert_equal(0, hlexists('does_not_exist'))
+ call assert_equal(1, hlexists('Number'))
+ call assert_equal(0, highlight_exists('does_not_exist'))
+ call assert_equal(1, highlight_exists('Number'))
+ syntax off
+endfunc
+
+func Test_col()
+ new
+ call setline(1, 'abcdef')
+ norm gg4|mx6|mY2|
+ call assert_equal(2, col('.'))
+ call assert_equal(7, col('$'))
+ call assert_equal(4, col("'x"))
+ call assert_equal(6, col("'Y"))
+ call assert_equal(2, col([1, 2]))
+ call assert_equal(7, col([1, '$']))
+
+ call assert_equal(0, col(''))
+ call assert_equal(0, col('x'))
+ call assert_equal(0, col([2, '$']))
+ call assert_equal(0, col([1, 100]))
+ call assert_equal(0, col([1]))
+ bw!
+endfunc
+
+func Test_inputlist()
+ call feedkeys(":let c = inputlist(['Select color:', '1. red', '2. green', '3. blue'])\<cr>1\<cr>", 'tx')
+ call assert_equal(1, c)
+ call feedkeys(":let c = inputlist(['Select color:', '1. red', '2. green', '3. blue'])\<cr>2\<cr>", 'tx')
+ call assert_equal(2, c)
+ call feedkeys(":let c = inputlist(['Select color:', '1. red', '2. green', '3. blue'])\<cr>3\<cr>", 'tx')
+ call assert_equal(3, c)
+
+ call assert_fails('call inputlist("")', 'E686:')
+endfunc
+
+func Test_balloon_show()
+ if has('balloon_eval')
+ " This won't do anything but must not crash either.
+ call balloon_show('hi!')
+ endif
+endfunc
+
+func Test_setbufvar_options()
+ " This tests that aucmd_prepbuf() and aucmd_restbuf() properly restore the
+ " window layout.
+ call assert_equal(1, winnr('$'))
+ split dummy_preview
+ resize 2
+ set winfixheight winfixwidth
+ let prev_id = win_getid()
+
+ wincmd j
+ let wh = winheight('.')
+ let dummy_buf = bufnr('dummy_buf1', v:true)
+ call setbufvar(dummy_buf, '&buftype', 'nofile')
+ execute 'belowright vertical split #' . dummy_buf
+ call assert_equal(wh, winheight('.'))
+ let dum1_id = win_getid()
+
+ wincmd h
+ let wh = winheight('.')
+ let dummy_buf = bufnr('dummy_buf2', v:true)
+ call setbufvar(dummy_buf, '&buftype', 'nofile')
+ execute 'belowright vertical split #' . dummy_buf
+ call assert_equal(wh, winheight('.'))
+
+ bwipe!
+ call win_gotoid(prev_id)
+ bwipe!
+ call win_gotoid(dum1_id)
+ bwipe!
+endfunc
+
+func Test_redo_in_nested_functions()
+ nnoremap g. :set opfunc=Operator<CR>g@
+ function Operator( type, ... )
+ let @x = 'XXX'
+ execute 'normal! g`[' . (a:type ==# 'line' ? 'V' : 'v') . 'g`]' . '"xp'
+ endfunction
+
+ function! Apply()
+ 5,6normal! .
+ endfunction
+
+ new
+ call setline(1, repeat(['some "quoted" text', 'more "quoted" text'], 3))
+ 1normal g.i"
+ call assert_equal('some "XXX" text', getline(1))
+ 3,4normal .
+ call assert_equal('some "XXX" text', getline(3))
+ call assert_equal('more "XXX" text', getline(4))
+ call Apply()
+ call assert_equal('some "XXX" text', getline(5))
+ call assert_equal('more "XXX" text', getline(6))
+ bwipe!
+
+ nunmap g.
+ delfunc Operator
+ delfunc Apply
+endfunc
+
+func Test_shellescape()
+ let save_shell = &shell
+ set shell=bash
+ call assert_equal("'text'", shellescape('text'))
+ call assert_equal("'te\"xt'", shellescape('te"xt'))
+ call assert_equal("'te'\\''xt'", shellescape("te'xt"))
+
+ call assert_equal("'te%xt'", shellescape("te%xt"))
+ call assert_equal("'te\\%xt'", shellescape("te%xt", 1))
+ call assert_equal("'te#xt'", shellescape("te#xt"))
+ call assert_equal("'te\\#xt'", shellescape("te#xt", 1))
+ call assert_equal("'te!xt'", shellescape("te!xt"))
+ call assert_equal("'te\\!xt'", shellescape("te!xt", 1))
+
+ call assert_equal("'te\nxt'", shellescape("te\nxt"))
+ call assert_equal("'te\\\nxt'", shellescape("te\nxt", 1))
+ set shell=tcsh
+ call assert_equal("'te\\!xt'", shellescape("te!xt"))
+ call assert_equal("'te\\\\!xt'", shellescape("te!xt", 1))
+ call assert_equal("'te\\\nxt'", shellescape("te\nxt"))
+ call assert_equal("'te\\\\\nxt'", shellescape("te\nxt", 1))
+
+ let &shell = save_shell
+endfunc
+
+func Test_trim()
+ call assert_equal("Testing", trim(" \t\r\r\x0BTesting \t\n\r\n\t\x0B\x0B"))
+ call assert_equal("Testing", trim(" \t \r\r\n\n\x0BTesting \t\n\r\n\t\x0B\x0B"))
+ call assert_equal("RESERVE", trim("xyz \twwRESERVEzyww \t\t", " wxyz\t"))
+ call assert_equal("wRE \tSERVEzyww", trim("wRE \tSERVEzyww"))
+ call assert_equal("abcd\t xxxx tail", trim(" \tabcd\t xxxx tail"))
+ call assert_equal("\tabcd\t xxxx tail", trim(" \tabcd\t xxxx tail", " "))
+ call assert_equal(" \tabcd\t xxxx tail", trim(" \tabcd\t xxxx tail", "abx"))
+ call assert_equal("RESERVE", trim("你RESERVE好", "你好"))
+ call assert_equal("您R E SER V E早", trim("你好您R E SER V E早好你你", "你好"))
+ call assert_equal("你好您R E SER V E早好你你", trim(" \n\r\r 你好您R E SER V E早好你你 \t \x0B", ))
+ call assert_equal("您R E SER V E早好你你 \t \x0B", trim(" 你好您R E SER V E早好你你 \t \x0B", " 你好"))
+ call assert_equal("您R E SER V E早好你你 \t \x0B", trim(" tteesstttt你好您R E SER V E早好你你 \t \x0B ttestt", " 你好tes"))
+ call assert_equal("您R E SER V E早好你你 \t \x0B", trim(" tteesstttt你好您R E SER V E早好你你 \t \x0B ttestt", " 你你你好好好tttsses"))
+ call assert_equal("留下", trim("这些些ä¸è¦è¿™äº›ç•™ä¸‹è¿™äº›", "这些ä¸è¦"))
+ call assert_equal("", trim("", ""))
+ call assert_equal("a", trim("a", ""))
+ call assert_equal("", trim("", "a"))
+
+ let chars = join(map(range(1, 0x20) + [0xa0], {n -> nr2char(n)}), '')
+ call assert_equal("x", trim(chars . "x" . chars))
+endfunc
+
+" Test for reg_recording() and reg_executing()
+func Test_reg_executing_and_recording()
+ let s:reg_stat = ''
+ func s:save_reg_stat()
+ let s:reg_stat = reg_recording() . ':' . reg_executing()
+ return ''
+ endfunc
+
+ new
+ call s:save_reg_stat()
+ call assert_equal(':', s:reg_stat)
+ call feedkeys("qa\"=s:save_reg_stat()\<CR>pq", 'xt')
+ call assert_equal('a:', s:reg_stat)
+ call feedkeys("@a", 'xt')
+ call assert_equal(':a', s:reg_stat)
+ call feedkeys("qb@aq", 'xt')
+ call assert_equal('b:a', s:reg_stat)
+ call feedkeys("q\"\"=s:save_reg_stat()\<CR>pq", 'xt')
+ call assert_equal('":', s:reg_stat)
+
+ bwipe!
+ delfunc s:save_reg_stat
+ unlet s:reg_stat
+endfunc
+
+func Test_libcall_libcallnr()
+ if !has('libcall')
+ return
+ endif
+
+ if has('win32')
+ let libc = 'msvcrt.dll'
+ elseif has('mac')
+ let libc = 'libSystem.B.dylib'
+ elseif executable('ldd')
+ let libc = matchstr(split(system('ldd ' . GetVimProg())), '/libc\.so\>')
+ endif
+ if get(l:, 'libc', '') ==# ''
+ " On Unix, libc.so can be in various places.
+ if has('linux')
+ " There is not documented but regarding the 1st argument of glibc's
+ " dlopen an empty string and nullptr are equivalent, so using an empty
+ " string for the 1st argument of libcall allows to call functions.
+ let libc = ''
+ elseif has('sun')
+ " Set the path to libc.so according to the architecture.
+ let test_bits = system('file ' . GetVimProg())
+ let test_arch = system('uname -p')
+ if test_bits =~ '64-bit' && test_arch =~ 'sparc'
+ let libc = '/usr/lib/sparcv9/libc.so'
+ elseif test_bits =~ '64-bit' && test_arch =~ 'i386'
+ let libc = '/usr/lib/amd64/libc.so'
+ else
+ let libc = '/usr/lib/libc.so'
+ endif
+ else
+ " Unfortunately skip this test until a good way is found.
+ return
+ endif
+ endif
+
+ if has('win32')
+ call assert_equal($USERPROFILE, libcall(libc, 'getenv', 'USERPROFILE'))
+ else
+ call assert_equal($HOME, libcall(libc, 'getenv', 'HOME'))
+ endif
+
+ " If function returns NULL, libcall() should return an empty string.
+ call assert_equal('', libcall(libc, 'getenv', 'X_ENV_DOES_NOT_EXIT'))
+
+ " Test libcallnr() with string and integer argument.
+ call assert_equal(4, libcallnr(libc, 'strlen', 'abcd'))
+ call assert_equal(char2nr('A'), libcallnr(libc, 'toupper', char2nr('a')))
+
+ call assert_fails("call libcall(libc, 'Xdoesnotexist_', '')", 'E364:')
+ call assert_fails("call libcallnr(libc, 'Xdoesnotexist_', '')", 'E364:')
+
+ call assert_fails("call libcall('Xdoesnotexist_', 'getenv', 'HOME')", 'E364:')
+ call assert_fails("call libcallnr('Xdoesnotexist_', 'strlen', 'abcd')", 'E364:')
+endfunc
+
+sandbox function Fsandbox()
+ normal ix
+endfunc
+
+func Test_func_sandbox()
+ sandbox let F = {-> 'hello'}
+ call assert_equal('hello', F())
+
+ sandbox let F = {-> execute("normal ix\<Esc>")}
+ call assert_fails('call F()', 'E48:')
+ unlet F
+
+ call assert_fails('call Fsandbox()', 'E48:')
+ delfunc Fsandbox
+endfunc
+
+func EditAnotherFile()
+ let word = expand('<cword>')
+ edit Xfuncrange2
+endfunc
+
+func Test_func_range_with_edit()
+ " Define a function that edits another buffer, then call it with a range that
+ " is invalid in that buffer.
+ call writefile(['just one line'], 'Xfuncrange2')
+ new
+ call setline(1, range(10))
+ write Xfuncrange1
+ call assert_fails('5,8call EditAnotherFile()', 'E16:')
+
+ call delete('Xfuncrange1')
+ call delete('Xfuncrange2')
+ bwipe!
+endfunc
+
+func Test_func_exists_on_reload()
+ call writefile(['func ExistingFunction()', 'echo "yes"', 'endfunc'], 'Xfuncexists')
+ call assert_equal(0, exists('*ExistingFunction'))
+ source Xfuncexists
+ call assert_equal(1, exists('*ExistingFunction'))
+ " Redefining a function when reloading a script is OK.
+ source Xfuncexists
+ call assert_equal(1, exists('*ExistingFunction'))
+
+ " But redefining in another script is not OK.
+ call writefile(['func ExistingFunction()', 'echo "yes"', 'endfunc'], 'Xfuncexists2')
+ call assert_fails('source Xfuncexists2', 'E122:')
+
+ delfunc ExistingFunction
+ call assert_equal(0, exists('*ExistingFunction'))
+ call writefile([
+ \ 'func ExistingFunction()', 'echo "yes"', 'endfunc',
+ \ 'func ExistingFunction()', 'echo "no"', 'endfunc',
+ \ ], 'Xfuncexists')
+ call assert_fails('source Xfuncexists', 'E122:')
+ call assert_equal(1, exists('*ExistingFunction'))
+
+ call delete('Xfuncexists2')
+ call delete('Xfuncexists')
+ delfunc ExistingFunction
+endfunc
+
+" Test confirm({msg} [, {choices} [, {default} [, {type}]]])
+func Test_confirm()
+ if !has('unix') || has('gui_running')
+ return
+ endif
+
+ call feedkeys('o', 'L')
+ let a = confirm('Press O to proceed')
+ call assert_equal(1, a)
+
+ call feedkeys('y', 'L')
+ let a = confirm('Are you sure?', "&Yes\n&No")
+ call assert_equal(1, a)
+
+ call feedkeys('n', 'L')
+ let a = confirm('Are you sure?', "&Yes\n&No")
+ call assert_equal(2, a)
+
+ " confirm() should return 0 when pressing CTRL-C.
+ call feedkeys("\<C-c>", 'L')
+ let a = confirm('Are you sure?', "&Yes\n&No")
+ call assert_equal(0, a)
+
+ " <Esc> requires another character to avoid it being seen as the start of an
+ " escape sequence. Zero should be harmless.
+ call feedkeys("\<Esc>0", 'L')
+ let a = confirm('Are you sure?', "&Yes\n&No")
+ call assert_equal(0, a)
+
+ " Default choice is returned when pressing <CR>.
+ call feedkeys("\<CR>", 'L')
+ let a = confirm('Are you sure?', "&Yes\n&No")
+ call assert_equal(1, a)
+
+ call feedkeys("\<CR>", 'L')
+ let a = confirm('Are you sure?', "&Yes\n&No", 2)
+ call assert_equal(2, a)
+
+ call feedkeys("\<CR>", 'L')
+ let a = confirm('Are you sure?', "&Yes\n&No", 0)
+ call assert_equal(0, a)
+
+ " Test with the {type} 4th argument
+ for type in ['Error', 'Question', 'Info', 'Warning', 'Generic']
+ call feedkeys('y', 'L')
+ let a = confirm('Are you sure?', "&Yes\n&No\n", 1, type)
+ call assert_equal(1, a)
+ endfor
+
+ call assert_fails('call confirm([])', 'E730:')
+ call assert_fails('call confirm("Are you sure?", [])', 'E730:')
+ call assert_fails('call confirm("Are you sure?", "&Yes\n&No\n", [])', 'E745:')
+ call assert_fails('call confirm("Are you sure?", "&Yes\n&No\n", 0, [])', 'E730:')
+endfunc
+
+func Test_platform_name()
+ " The system matches at most only one name.
+ let names = ['amiga', 'beos', 'bsd', 'hpux', 'linux', 'mac', 'qnx', 'sun', 'vms', 'win32', 'win32unix']
+ call assert_inrange(0, 1, len(filter(copy(names), 'has(v:val)')))
+
+ " Is Unix?
+ call assert_equal(has('beos'), has('beos') && has('unix'))
+ call assert_equal(has('bsd'), has('bsd') && has('unix'))
+ call assert_equal(has('hpux'), has('hpux') && has('unix'))
+ call assert_equal(has('linux'), has('linux') && has('unix'))
+ call assert_equal(has('mac'), has('mac') && has('unix'))
+ call assert_equal(has('qnx'), has('qnx') && has('unix'))
+ call assert_equal(has('sun'), has('sun') && has('unix'))
+ call assert_equal(has('win32'), has('win32') && !has('unix'))
+ call assert_equal(has('win32unix'), has('win32unix') && has('unix'))
+
+ if has('unix') && executable('uname')
+ let uname = system('uname')
+ call assert_equal(uname =~? 'BeOS', has('beos'))
+ call assert_equal(uname =~? 'BSD\|DragonFly', has('bsd'))
+ call assert_equal(uname =~? 'HP-UX', has('hpux'))
+ call assert_equal(uname =~? 'Linux', has('linux'))
+ call assert_equal(uname =~? 'Darwin', has('mac'))
+ call assert_equal(uname =~? 'QNX', has('qnx'))
+ call assert_equal(uname =~? 'SunOS', has('sun'))
+ call assert_equal(uname =~? 'CYGWIN\|MSYS', has('win32unix'))
+ endif
+endfunc
diff --git a/src/testdir/test_ga.vim b/src/testdir/test_ga.vim
new file mode 100644
index 0000000..ea3d211
--- /dev/null
+++ b/src/testdir/test_ga.vim
@@ -0,0 +1,33 @@
+" Test ga normal command, and :ascii Ex command.
+func Do_ga(c)
+ call setline(1, a:c)
+ let l:a = execute("norm 1goga")
+ let l:b = execute("ascii")
+ call assert_equal(l:a, l:b)
+ return l:a
+endfunc
+
+func Test_ga_command()
+ new
+ set display=uhex
+ call assert_equal("\nNUL", Do_ga(''))
+ call assert_equal("\n<<01>> 1, Hex 01, Oct 001, Digr SH", Do_ga("\x01"))
+ call assert_equal("\n<<09>> 9, Hex 09, Oct 011, Digr HT", Do_ga("\t"))
+
+ set display=
+ call assert_equal("\nNUL", Do_ga(''))
+ call assert_equal("\n<^A> 1, Hex 01, Oct 001, Digr SH", Do_ga("\x01"))
+ call assert_equal("\n<^I> 9, Hex 09, Oct 011, Digr HT", Do_ga("\t"))
+
+ call assert_equal("\n<e> 101, Hex 65, Octal 145", Do_ga('e'))
+
+ " Test a few multi-bytes characters.
+ call assert_equal("\n<é> 233, Hex 00e9, Oct 351, Digr e'", Do_ga('é'))
+ call assert_equal("\n<ẻ> 7867, Hex 1ebb, Oct 17273, Digr e2", Do_ga('ẻ'))
+
+ " Test with combining characters.
+ call assert_equal("\n<e> 101, Hex 65, Octal 145 < Ì> 769, Hex 0301, Octal 1401", Do_ga("e\u0301"))
+ call assert_equal("\n<e> 101, Hex 65, Octal 145 < Ì> 769, Hex 0301, Octal 1401 < ̱> 817, Hex 0331, Octal 1461", Do_ga("e\u0301\u0331"))
+ call assert_equal("\n<e> 101, Hex 65, Octal 145 < Ì> 769, Hex 0301, Octal 1401 < ̱> 817, Hex 0331, Octal 1461 < ̸> 824, Hex 0338, Octal 1470", Do_ga("e\u0301\u0331\u0338"))
+ bwipe!
+endfunc
diff --git a/src/testdir/test_getcwd.vim b/src/testdir/test_getcwd.vim
new file mode 100644
index 0000000..ca09878
--- /dev/null
+++ b/src/testdir/test_getcwd.vim
@@ -0,0 +1,112 @@
+func GetCwdInfo(win, tab)
+ let tab_changed = 0
+ let mod = ":t"
+ if a:tab > 0 && a:tab != tabpagenr()
+ let tab_changed = 1
+ exec "tabnext " . a:tab
+ endif
+ let bufname = fnamemodify(bufname(winbufnr(a:win)), mod)
+ if tab_changed
+ tabprevious
+ endif
+ if a:win == 0 && a:tab == 0
+ let dirname = fnamemodify(getcwd(), mod)
+ let lflag = haslocaldir()
+ elseif a:tab == 0
+ let dirname = fnamemodify(getcwd(a:win), mod)
+ let lflag = haslocaldir(a:win)
+ else
+ let dirname = fnamemodify(getcwd(a:win, a:tab), mod)
+ let lflag = haslocaldir(a:win, a:tab)
+ endif
+ return bufname . ' ' . dirname . ' ' . lflag
+endfunc
+
+" Do all test in a separate window to avoid E211 when we recursively
+" delete the Xtopdir directory during cleanup
+function SetUp()
+ set visualbell
+ set nocp viminfo+=nviminfo
+
+ " On windows a swapfile in Xtopdir prevents it from being cleaned up.
+ set noswapfile
+
+ " On windows a stale "Xtopdir" directory may exist, remove it so that
+ " we start from a clean state.
+ call delete("Xtopdir", "rf")
+ new
+ call mkdir('Xtopdir')
+ cd Xtopdir
+ let g:topdir = getcwd()
+ call mkdir('Xdir1')
+ call mkdir('Xdir2')
+ call mkdir('Xdir3')
+endfunction
+
+let g:cwd=getcwd()
+function TearDown()
+ q
+ exec "cd " . g:cwd
+ call delete("Xtopdir", "rf")
+endfunction
+
+function Test_GetCwd()
+ new a
+ new b
+ new c
+ 3wincmd w
+ lcd Xdir1
+ call assert_equal("a Xdir1 1", GetCwdInfo(0, 0))
+ call assert_equal(g:topdir, getcwd(-1))
+ wincmd W
+ call assert_equal("b Xtopdir 0", GetCwdInfo(0, 0))
+ call assert_equal(g:topdir, getcwd(-1))
+ wincmd W
+ lcd Xdir3
+ call assert_equal("c Xdir3 1", GetCwdInfo(0, 0))
+ call assert_equal("a Xdir1 1", GetCwdInfo(bufwinnr("a"), 0))
+ call assert_equal("b Xtopdir 0", GetCwdInfo(bufwinnr("b"), 0))
+ call assert_equal("c Xdir3 1", GetCwdInfo(bufwinnr("c"), 0))
+ call assert_equal(g:topdir, getcwd(-1))
+ wincmd W
+ call assert_equal("a Xdir1 1", GetCwdInfo(bufwinnr("a"), tabpagenr()))
+ call assert_equal("b Xtopdir 0", GetCwdInfo(bufwinnr("b"), tabpagenr()))
+ call assert_equal("c Xdir3 1", GetCwdInfo(bufwinnr("c"), tabpagenr()))
+ call assert_equal(g:topdir, getcwd(-1))
+
+ tabnew x
+ new y
+ new z
+ 3wincmd w
+ call assert_equal("x Xtopdir 0", GetCwdInfo(0, 0))
+ call assert_equal(g:topdir, getcwd(-1))
+ wincmd W
+ lcd Xdir2
+ call assert_equal("y Xdir2 1", GetCwdInfo(0, 0))
+ call assert_equal(g:topdir, getcwd(-1))
+ wincmd W
+ lcd Xdir3
+ call assert_equal("z Xdir3 1", GetCwdInfo(0, 0))
+ call assert_equal("x Xtopdir 0", GetCwdInfo(bufwinnr("x"), 0))
+ call assert_equal("y Xdir2 1", GetCwdInfo(bufwinnr("y"), 0))
+ call assert_equal("z Xdir3 1", GetCwdInfo(bufwinnr("z"), 0))
+ call assert_equal(g:topdir, getcwd(-1))
+ let tp_nr = tabpagenr()
+ tabrewind
+ call assert_equal("x Xtopdir 0", GetCwdInfo(3, tp_nr))
+ call assert_equal("y Xdir2 1", GetCwdInfo(2, tp_nr))
+ call assert_equal("z Xdir3 1", GetCwdInfo(1, tp_nr))
+ call assert_equal(g:topdir, getcwd(-1))
+endfunc
+
+function Test_GetCwd_lcd_shellslash()
+ new
+ let root = fnamemodify('/', ':p')
+ exe 'lcd '.root
+ let cwd = getcwd()
+ if !exists('+shellslash') || &shellslash
+ call assert_equal(cwd[-1:], '/')
+ else
+ call assert_equal(cwd[-1:], '\')
+ endif
+endfunc
diff --git a/src/testdir/test_getvar.vim b/src/testdir/test_getvar.vim
new file mode 100644
index 0000000..d6b6b69
--- /dev/null
+++ b/src/testdir/test_getvar.vim
@@ -0,0 +1,104 @@
+" Tests for getwinvar(), gettabvar() and gettabwinvar().
+func Test_var()
+ " Use strings to test for memory leaks. First, check that in an empty
+ " window, gettabvar() returns the correct value
+ let t:testvar='abcd'
+ call assert_equal('abcd', gettabvar(1, 'testvar'))
+ call assert_equal('abcd', gettabvar(1, 'testvar'))
+
+ " test for getwinvar()
+ let w:var_str = "Dance"
+ let def_str = "Chance"
+ call assert_equal('Dance', getwinvar(1, 'var_str'))
+ call assert_equal('Dance', getwinvar(1, 'var_str', def_str))
+ call assert_equal({'var_str': 'Dance'}, getwinvar(1, ''))
+ call assert_equal({'var_str': 'Dance'}, getwinvar(1, '', def_str))
+ unlet w:var_str
+ call assert_equal('Chance', getwinvar(1, 'var_str', def_str))
+ call assert_equal({}, getwinvar(1, ''))
+ call assert_equal({}, getwinvar(1, '', def_str))
+ call assert_equal('', getwinvar(9, ''))
+ call assert_equal('Chance', getwinvar(9, '', def_str))
+ call assert_equal(0, getwinvar(1, '&nu'))
+ call assert_equal(0, getwinvar(1, '&nu', 1))
+ unlet def_str
+
+ " test for gettabvar()
+ tabnew
+ tabnew
+ let t:var_list = [1, 2, 3]
+ let t:other = 777
+ let def_list = [4, 5, 6, 7]
+ tabrewind
+ call assert_equal([1, 2, 3], gettabvar(3, 'var_list'))
+ call assert_equal([1, 2, 3], gettabvar(3, 'var_list', def_list))
+ call assert_equal({'var_list': [1, 2, 3], 'other': 777}, gettabvar(3, ''))
+ call assert_equal({'var_list': [1, 2, 3], 'other': 777},
+ \ gettabvar(3, '', def_list))
+
+ tablast
+ unlet t:var_list
+ tabrewind
+ call assert_equal([4, 5, 6, 7], gettabvar(3, 'var_list', def_list))
+ call assert_equal('', gettabvar(9, ''))
+ call assert_equal([4, 5, 6, 7], gettabvar(9, '', def_list))
+ call assert_equal('', gettabvar(3, '&nu'))
+ call assert_equal([4, 5, 6, 7], gettabvar(3, '&nu', def_list))
+ unlet def_list
+ tabonly
+
+ " test for gettabwinvar()
+ tabnew
+ tabnew
+ tabprev
+ split
+ split
+ wincmd w
+ vert split
+ wincmd w
+ let w:var_dict = {'dict': 'tabwin'}
+ let def_dict = {'dict2': 'newval'}
+ wincmd b
+ tabrewind
+ call assert_equal({'dict': 'tabwin'}, gettabwinvar(2, 3, 'var_dict'))
+ call assert_equal({'dict': 'tabwin'},
+ \ gettabwinvar(2, 3, 'var_dict', def_dict))
+ call assert_equal({'var_dict': {'dict': 'tabwin'}}, gettabwinvar(2, 3, ''))
+ call assert_equal({'var_dict': {'dict': 'tabwin'}},
+ \ gettabwinvar(2, 3, '', def_dict))
+
+ tabnext
+ 3wincmd w
+ unlet w:var_dict
+ tabrewind
+ call assert_equal({'dict2': 'newval'},
+ \ gettabwinvar(2, 3, 'var_dict', def_dict))
+ call assert_equal({}, gettabwinvar(2, 3, ''))
+ call assert_equal({}, gettabwinvar(2, 3, '', def_dict))
+ call assert_equal("", gettabwinvar(2, 9, ''))
+ call assert_equal({'dict2': 'newval'}, gettabwinvar(2, 9, '', def_dict))
+ call assert_equal('', gettabwinvar(9, 3, ''))
+ call assert_equal({'dict2': 'newval'}, gettabwinvar(9, 3, '', def_dict))
+
+ unlet def_dict
+
+ call assert_equal('', gettabwinvar(2, 3, '&nux'))
+ call assert_equal(1, gettabwinvar(2, 3, '&nux', 1))
+ tabonly
+endfunc
+
+" It was discovered that "gettabvar()" would fail if called from within the
+" tabline when the user closed a window. This test confirms the fix.
+func Test_gettabvar_in_tabline()
+ let t:var_str = 'value'
+
+ set tabline=%{assert_equal('value',gettabvar(1,'var_str'))}
+ set showtabline=2
+
+ " Simulate the user opening a split (which becomes window #1) and then
+ " closing the split, which triggers the redrawing of the tabline.
+ leftabove split
+ redrawstatus!
+ close
+ redrawstatus!
+endfunc
diff --git a/src/testdir/test_gf.vim b/src/testdir/test_gf.vim
new file mode 100644
index 0000000..c352379
--- /dev/null
+++ b/src/testdir/test_gf.vim
@@ -0,0 +1,61 @@
+
+" This is a test if a URL is recognized by "gf", with the cursor before and
+" after the "://". Also test ":\\".
+func Test_gf_url()
+ enew!
+ call append(0, [
+ \ "first test for URL://machine.name/tmp/vimtest2a and other text",
+ \ "second test for URL://machine.name/tmp/vimtest2b. And other text",
+ \ "third test for URL:\\\\machine.name\\vimtest2c and other text",
+ \ "fourth test for URL:\\\\machine.name\\tmp\\vimtest2d, and other text",
+ \ "fifth test for URL://machine.name/tmp?q=vim&opt=yes and other text",
+ \ ])
+ call cursor(1,1)
+ call search("^first")
+ call search("tmp")
+ call assert_equal("URL://machine.name/tmp/vimtest2a", expand("<cfile>"))
+ call search("^second")
+ call search("URL")
+ call assert_equal("URL://machine.name/tmp/vimtest2b", expand("<cfile>"))
+ if has("ebcdic")
+ set isf=@,240-249,/,.,-,_,+,,,$,:,~,\
+ else
+ set isf=@,48-57,/,.,-,_,+,,,$,:,~,\
+ endif
+ call search("^third")
+ call search("name")
+ call assert_equal("URL:\\\\machine.name\\vimtest2c", expand("<cfile>"))
+ call search("^fourth")
+ call search("URL")
+ call assert_equal("URL:\\\\machine.name\\tmp\\vimtest2d", expand("<cfile>"))
+
+ call search("^fifth")
+ call search("URL")
+ call assert_equal("URL://machine.name/tmp?q=vim&opt=yes", expand("<cfile>"))
+
+ set isf&vim
+ enew!
+endfunc
+
+func Test_gF()
+ new
+ call setline(1, ['111', '222', '333', '444'])
+ w! Xfile
+ close
+ new
+ set isfname-=:
+ call setline(1, ['one', 'Xfile:3', 'three'])
+ 2
+ call assert_fails('normal gF', 'E37:')
+ call assert_equal(2, getcurpos()[1])
+ w! Xfile2
+ normal gF
+ call assert_equal('Xfile', bufname('%'))
+ call assert_equal(3, getcurpos()[1])
+
+ set isfname&
+ call delete('Xfile')
+ call delete('Xfile2')
+ bwipe Xfile
+ bwipe Xfile2
+endfunc
diff --git a/src/testdir/test_glob2regpat.vim b/src/testdir/test_glob2regpat.vim
new file mode 100644
index 0000000..e6e41f1
--- /dev/null
+++ b/src/testdir/test_glob2regpat.vim
@@ -0,0 +1,30 @@
+" Test glob2regpat()
+
+func Test_glob2regpat_invalid()
+ call assert_fails('call glob2regpat(1.33)', 'E806:')
+ call assert_fails('call glob2regpat("}")', 'E219:')
+ call assert_fails('call glob2regpat("{")', 'E220:')
+endfunc
+
+func Test_glob2regpat_valid()
+ call assert_equal('^foo\.', glob2regpat('foo.*'))
+ call assert_equal('^foo.$', glob2regpat('foo?'))
+ call assert_equal('\.vim$', glob2regpat('*.vim'))
+ call assert_equal('^[abc]$', glob2regpat('[abc]'))
+ call assert_equal('^foo bar$', glob2regpat('foo\ bar'))
+ call assert_equal('^foo,bar$', glob2regpat('foo,bar'))
+ call assert_equal('^\(foo\|bar\)$', glob2regpat('{foo,bar}'))
+ call assert_equal('.*', glob2regpat('**'))
+
+ if exists('+shellslash')
+ call assert_equal('^foo[\/].$', glob2regpat('foo\?'))
+ call assert_equal('^\(foo[\/]\|bar\|foobar\)$', glob2regpat('{foo\,bar,foobar}'))
+ call assert_equal('^[\/]\(foo\|bar[\/]\)$', glob2regpat('\{foo,bar\}'))
+ call assert_equal('^[\/][\/]\(foo\|bar[\/][\/]\)$', glob2regpat('\\{foo,bar\\}'))
+ else
+ call assert_equal('^foo?$', glob2regpat('foo\?'))
+ call assert_equal('^\(foo,bar\|foobar\)$', glob2regpat('{foo\,bar,foobar}'))
+ call assert_equal('^{foo,bar}$', glob2regpat('\{foo,bar\}'))
+ call assert_equal('^\\\(foo\|bar\\\)$', glob2regpat('\\{foo,bar\\}'))
+ endif
+endfunc
diff --git a/src/testdir/test_global.vim b/src/testdir/test_global.vim
new file mode 100644
index 0000000..bdeaf8e
--- /dev/null
+++ b/src/testdir/test_global.vim
@@ -0,0 +1,20 @@
+
+func Test_yank_put_clipboard()
+ new
+ call setline(1, ['a', 'b', 'c'])
+ set clipboard=unnamed
+ g/^/normal yyp
+ call assert_equal(['a', 'a', 'b', 'b', 'c', 'c'], getline(1, 6))
+
+ set clipboard&
+ bwipe!
+endfunc
+
+func Test_nested_global()
+ new
+ call setline(1, ['nothing', 'found', 'found bad', 'bad'])
+ call assert_fails('g/found/3v/bad/s/^/++/', 'E147')
+ g/found/v/bad/s/^/++/
+ call assert_equal(['nothing', '++found', 'found bad', 'bad'], getline(1, 4))
+ bwipe!
+endfunc
diff --git a/src/testdir/test_gn.vim b/src/testdir/test_gn.vim
new file mode 100644
index 0000000..d0fdafc
--- /dev/null
+++ b/src/testdir/test_gn.vim
@@ -0,0 +1,153 @@
+" Test for gn command
+
+func Test_gn_command()
+ noautocmd new
+ " replace a single char by itsself quoted:
+ call setline('.', 'abc x def x ghi x jkl')
+ let @/ = 'x'
+ exe "norm! cgn'x'\<esc>.."
+ call assert_equal("abc 'x' def 'x' ghi 'x' jkl", getline('.'))
+ sil! %d_
+
+ " simple search match
+ call setline('.', 'foobar')
+ let @/ = 'foobar'
+ exe "norm! gncsearchmatch"
+ call assert_equal('searchmatch', getline('.'))
+ sil! %d _
+
+ " replace a multi-line match
+ call setline('.', ['', 'one', 'two'])
+ let @/ = 'one\_s*two\_s'
+ exe "norm! gnceins\<CR>zwei"
+ call assert_equal(['','eins','zwei'], getline(1,'$'))
+ sil! %d _
+
+ " test count argument
+ call setline('.', ['', 'abcdx | abcdx | abcdx'])
+ let @/ = '[a]bcdx'
+ exe "norm! 2gnd"
+ call assert_equal(['','abcdx | | abcdx'], getline(1,'$'))
+ sil! %d _
+
+ " join lines
+ call setline('.', ['join ', 'lines'])
+ let @/ = '$'
+ exe "norm! 0gnd"
+ call assert_equal(['join lines'], getline(1,'$'))
+ sil! %d _
+
+ " zero-width match
+ call setline('.', ['', 'zero width pattern'])
+ let @/ = '\>\zs'
+ exe "norm! 0gnd"
+ call assert_equal(['', 'zerowidth pattern'], getline(1,'$'))
+ sil! %d _
+
+ " delete first and last chars
+ call setline('.', ['delete first and last chars'])
+ let @/ = '^'
+ exe "norm! 0gnd$"
+ let @/ = '\zs'
+ exe "norm! gnd"
+ call assert_equal(['elete first and last char'], getline(1,'$'))
+ sil! %d _
+
+ " using visual mode
+ call setline('.', ['', 'uniquepattern uniquepattern'])
+ exe "norm! /[u]niquepattern/s\<cr>vlgnd"
+ call assert_equal(['', ' uniquepattern'], getline(1,'$'))
+ sil! %d _
+
+ " backwards search
+ call setline('.', ['my very excellent mother just served us nachos'])
+ let @/ = 'mother'
+ exe "norm! $cgNmongoose"
+ call assert_equal(['my very excellent mongoose just served us nachos'], getline(1,'$'))
+ sil! %d _
+
+ " search for single char
+ call setline('.', ['','for (i=0; i<=10; i++)'])
+ let @/ = 'i'
+ exe "norm! cgnj"
+ call assert_equal(['','for (j=0; i<=10; i++)'], getline(1,'$'))
+ sil! %d _
+
+ " search hex char
+ call setline('.', ['','Y'])
+ set noignorecase
+ let @/ = '\%x59'
+ exe "norm! gnd"
+ call assert_equal(['',''], getline(1,'$'))
+ sil! %d _
+
+ " test repeating gdn
+ call setline('.', ['', '1', 'Johnny', '2', 'Johnny', '3'])
+ let @/ = 'Johnny'
+ exe "norm! dgn."
+ call assert_equal(['','1', '', '2', '', '3'], getline(1,'$'))
+ sil! %d _
+
+ " test repeating gUgn
+ call setline('.', ['', '1', 'Depp', '2', 'Depp', '3'])
+ let @/ = 'Depp'
+ exe "norm! gUgn."
+ call assert_equal(['', '1', 'DEPP', '2', 'DEPP', '3'], getline(1,'$'))
+ sil! %d _
+
+ " test using look-ahead assertions
+ call setline('.', ['a:10', '', 'a:1', '', 'a:20'])
+ let @/ = 'a:0\@!\zs\d\+'
+ exe "norm! 2nygno\<esc>p"
+ call assert_equal(['a:10', '', 'a:1', '1', '', 'a:20'], getline(1,'$'))
+ sil! %d _
+
+ " test using nowrapscan
+ set nowrapscan
+ call setline(1, 'foo bar baz')
+ exe "norm! /bar/e\<cr>"
+ exe "norm! gnd"
+ call assert_equal(['foo baz'], getline(1,'$'))
+ sil! %d_
+
+ " search upwards with nowrapscan set
+ call setline('.', ['foo', 'bar', 'foo', 'baz'])
+ set nowrapscan
+ let @/ = 'foo'
+ $
+ norm! dgN
+ call assert_equal(['foo', 'bar', '', 'baz'], getline(1,'$'))
+ sil! %d_
+
+ " search using the \zs atom
+ call setline(1, [' nnoremap', '' , 'nnoremap'])
+ set wrapscan&vim
+ let @/ = '\_s\zsnnoremap'
+ $
+ norm! cgnmatch
+ call assert_equal([' nnoremap', '', 'match'], getline(1,'$'))
+ sil! %d_
+
+ set wrapscan&vim
+endfu
+
+func Test_gn_multi_line()
+ new
+ call setline(1, [
+ \ 'func Tm1()',
+ \ ' echo "one"',
+ \ 'endfunc',
+ \ 'func Tm2()',
+ \ ' echo "two"',
+ \ 'endfunc',
+ \ 'func Tm3()',
+ \ ' echo "three"',
+ \ 'endfunc',
+ \])
+ /\v^func Tm\d\(\)\n.*\zs".*"\ze$
+ normal jgnrx
+ call assert_equal(' echo xxxxx', getline(5))
+ bwipe!
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/test_goto.vim b/src/testdir/test_goto.vim
new file mode 100644
index 0000000..c0235b1
--- /dev/null
+++ b/src/testdir/test_goto.vim
@@ -0,0 +1,373 @@
+" Test commands that jump somewhere.
+
+" Create a new buffer using "lines" and place the cursor on the word after the
+" first occurrence of return and invoke "cmd". The cursor should now be
+" positioned at the given line and col.
+func XTest_goto_decl(cmd, lines, line, col)
+ new
+ call setline(1, a:lines)
+ /return/
+ normal! W
+ execute 'norm! ' . a:cmd
+ call assert_equal(a:line, line('.'))
+ call assert_equal(a:col, col('.'))
+ quit!
+endfunc
+
+func Test_gD()
+ let lines = [
+ \ 'int x;',
+ \ '',
+ \ 'int func(void)',
+ \ '{',
+ \ ' return x;',
+ \ '}',
+ \ ]
+ call XTest_goto_decl('gD', lines, 1, 5)
+endfunc
+
+func Test_gD_too()
+ let lines = [
+ \ 'Filename x;',
+ \ '',
+ \ 'int Filename',
+ \ 'int func() {',
+ \ ' Filename x;',
+ \ ' return x;',
+ \ ]
+ call XTest_goto_decl('gD', lines, 1, 10)
+endfunc
+
+func Test_gD_comment()
+ let lines = [
+ \ '/* int x; */',
+ \ 'int x;',
+ \ '',
+ \ 'int func(void)',
+ \ '{',
+ \ ' return x;',
+ \ '}',
+ \ ]
+ call XTest_goto_decl('gD', lines, 2, 5)
+endfunc
+
+func Test_gD_inline_comment()
+ let lines = [
+ \ 'int y /* , x */;',
+ \ 'int x;',
+ \ '',
+ \ 'int func(void)',
+ \ '{',
+ \ ' return x;',
+ \ '}',
+ \ ]
+ call XTest_goto_decl('gD', lines, 2, 5)
+endfunc
+
+func Test_gD_string()
+ let lines = [
+ \ 'char *s[] = "x";',
+ \ 'int x = 1;',
+ \ '',
+ \ 'int func(void)',
+ \ '{',
+ \ ' return x;',
+ \ '}',
+ \ ]
+ call XTest_goto_decl('gD', lines, 2, 5)
+endfunc
+
+func Test_gD_string_same_line()
+ let lines = [
+ \ 'char *s[] = "x", int x = 1;',
+ \ '',
+ \ 'int func(void)',
+ \ '{',
+ \ ' return x;',
+ \ '}',
+ \ ]
+ call XTest_goto_decl('gD', lines, 1, 22)
+endfunc
+
+func Test_gD_char()
+ let lines = [
+ \ "char c = 'x';",
+ \ 'int x = 1;',
+ \ '',
+ \ 'int func(void)',
+ \ '{',
+ \ ' return x;',
+ \ '}',
+ \ ]
+ call XTest_goto_decl('gD', lines, 2, 5)
+endfunc
+
+func Test_gd()
+ let lines = [
+ \ 'int x;',
+ \ '',
+ \ 'int func(int x)',
+ \ '{',
+ \ ' return x;',
+ \ '}',
+ \ ]
+ call XTest_goto_decl('gd', lines, 3, 14)
+endfunc
+
+func Test_gd_not_local()
+ let lines = [
+ \ 'int func1(void)',
+ \ '{',
+ \ ' return x;',
+ \ '}',
+ \ '',
+ \ 'int func2(int x)',
+ \ '{',
+ \ ' return x;',
+ \ '}',
+ \ ]
+ call XTest_goto_decl('gd', lines, 3, 10)
+endfunc
+
+func Test_gd_kr_style()
+ let lines = [
+ \ 'int func(x)',
+ \ ' int x;',
+ \ '{',
+ \ ' return x;',
+ \ '}',
+ \ ]
+ call XTest_goto_decl('gd', lines, 2, 7)
+endfunc
+
+func Test_gd_missing_braces()
+ let lines = [
+ \ 'def func1(a)',
+ \ ' a + 1',
+ \ 'end',
+ \ '',
+ \ 'a = 1',
+ \ '',
+ \ 'def func2()',
+ \ ' return a',
+ \ 'end',
+ \ ]
+ call XTest_goto_decl('gd', lines, 1, 11)
+endfunc
+
+func Test_gd_comment()
+ let lines = [
+ \ 'int func(void)',
+ \ '{',
+ \ ' /* int x; */',
+ \ ' int x;',
+ \ ' return x;',
+ \ '}',
+ \]
+ call XTest_goto_decl('gd', lines, 4, 7)
+endfunc
+
+func Test_gd_comment_in_string()
+ let lines = [
+ \ 'int func(void)',
+ \ '{',
+ \ ' char *s ="//"; int x;',
+ \ ' int x;',
+ \ ' return x;',
+ \ '}',
+ \]
+ call XTest_goto_decl('gd', lines, 3, 22)
+endfunc
+
+func Test_gd_string_in_comment()
+ set comments=
+ let lines = [
+ \ 'int func(void)',
+ \ '{',
+ \ ' /* " */ int x;',
+ \ ' int x;',
+ \ ' return x;',
+ \ '}',
+ \]
+ call XTest_goto_decl('gd', lines, 3, 15)
+ set comments&
+endfunc
+
+func Test_gd_inline_comment()
+ let lines = [
+ \ 'int func(/* x is an int */ int x)',
+ \ '{',
+ \ ' return x;',
+ \ '}',
+ \ ]
+ call XTest_goto_decl('gd', lines, 1, 32)
+endfunc
+
+func Test_gd_inline_comment_only()
+ let lines = [
+ \ 'int func(void) /* one lonely x */',
+ \ '{',
+ \ ' return x;',
+ \ '}',
+ \ ]
+ call XTest_goto_decl('gd', lines, 3, 10)
+endfunc
+
+func Test_gd_inline_comment_body()
+ let lines = [
+ \ 'int func(void)',
+ \ '{',
+ \ ' int y /* , x */;',
+ \ '',
+ \ ' for (/* int x = 0 */; y < 2; y++);',
+ \ '',
+ \ ' int x = 0;',
+ \ '',
+ \ ' return x;',
+ \ '}',
+ \ ]
+ call XTest_goto_decl('gd', lines, 7, 7)
+endfunc
+
+func Test_gd_trailing_multiline_comment()
+ let lines = [
+ \ 'int func(int x) /* x is an int */',
+ \ '{',
+ \ ' return x;',
+ \ '}',
+ \ ]
+ call XTest_goto_decl('gd', lines, 1, 14)
+endfunc
+
+func Test_gd_trailing_comment()
+ let lines = [
+ \ 'int func(int x) // x is an int',
+ \ '{',
+ \ ' return x;',
+ \ '}',
+ \ ]
+ call XTest_goto_decl('gd', lines, 1, 14)
+endfunc
+
+func Test_gd_string()
+ let lines = [
+ \ 'int func(void)',
+ \ '{',
+ \ ' char *s = "x";',
+ \ ' int x = 1;',
+ \ '',
+ \ ' return x;',
+ \ '}',
+ \ ]
+ call XTest_goto_decl('gd', lines, 4, 7)
+endfunc
+
+func Test_gd_string_only()
+ let lines = [
+ \ 'int func(void)',
+ \ '{',
+ \ ' char *s = "x";',
+ \ '',
+ \ ' return x;',
+ \ '}',
+ \ ]
+ call XTest_goto_decl('gd', lines, 5, 10)
+endfunc
+
+" Check that setting 'cursorline' does not change curswant
+func Test_cursorline_keep_col()
+ new
+ call setline(1, ['long long long line', 'short line'])
+ normal ggfi
+ let pos = getcurpos()
+ normal j
+ set cursorline
+ normal k
+ call assert_equal(pos, getcurpos())
+ bwipe!
+ set nocursorline
+endfunc
+
+func Test_gd_local_block()
+ let lines = [
+ \ ' int main()',
+ \ '{',
+ \ ' char *a = "NOT NULL";',
+ \ ' if(a)',
+ \ ' {',
+ \ ' char *b = a;',
+ \ ' printf("%s\n", b);',
+ \ ' }',
+ \ ' else',
+ \ ' {',
+ \ ' char *b = "NULL";',
+ \ ' return b;',
+ \ ' }',
+ \ '',
+ \ ' return 0;',
+ \ '}',
+ \ ]
+ call XTest_goto_decl('1gd', lines, 11, 11)
+endfunc
+
+func Test_motion_if_elif_else_endif()
+ new
+ a
+/* Test pressing % on #if, #else #elsif and #endif,
+ * with nested #if
+ */
+#if FOO
+/* ... */
+# if BAR
+/* ... */
+# endif
+#elif BAR
+/* ... */
+#else
+/* ... */
+#endif
+.
+ /#if FOO
+ norm %
+ call assert_equal([9, 1], getpos('.')[1:2])
+ norm %
+ call assert_equal([11, 1], getpos('.')[1:2])
+ norm %
+ call assert_equal([13, 1], getpos('.')[1:2])
+ norm %
+ call assert_equal([4, 1], getpos('.')[1:2])
+ /# if BAR
+ norm $%
+ call assert_equal([8, 1], getpos('.')[1:2])
+ norm $%
+ call assert_equal([6, 1], getpos('.')[1:2])
+
+ bw!
+endfunc
+
+func Test_motion_c_comment()
+ new
+ a
+/*
+ * Test pressing % on beginning/end
+ * of C comments.
+ */
+/* Another comment */
+.
+ norm gg0%
+ call assert_equal([4, 3], getpos('.')[1:2])
+ norm %
+ call assert_equal([1, 1], getpos('.')[1:2])
+ norm gg0l%
+ call assert_equal([4, 3], getpos('.')[1:2])
+ norm h%
+ call assert_equal([1, 1], getpos('.')[1:2])
+
+ norm G^
+ norm %
+ call assert_equal([5, 21], getpos('.')[1:2])
+ norm %
+ call assert_equal([5, 1], getpos('.')[1:2])
+
+ bw!
+endfunc
diff --git a/src/testdir/test_gui.vim b/src/testdir/test_gui.vim
new file mode 100644
index 0000000..7874fff
--- /dev/null
+++ b/src/testdir/test_gui.vim
@@ -0,0 +1,779 @@
+" Tests specifically for the GUI
+
+source shared.vim
+if !CanRunGui()
+ finish
+endif
+
+source setup_gui.vim
+
+func Setup()
+ call GUISetUpCommon()
+endfunc
+
+func TearDown()
+ call GUITearDownCommon()
+endfunc
+
+" Test for resetting "secure" flag after GUI has started.
+" Must be run first, since it starts the GUI on Unix.
+func Test_1_set_secure()
+ set exrc secure
+ gui -f
+ call assert_equal(1, has('gui_running'))
+endfunc
+
+" As for non-GUI, a balloon_show() test was already added with patch 8.0.0401
+func Test_balloon_show()
+ if has('balloon_eval')
+ " This won't do anything but must not crash either.
+ call balloon_show('hi!')
+ endif
+endfunc
+
+func Test_colorscheme()
+ let colorscheme_saved = exists('g:colors_name') ? g:colors_name : 'default'
+ let g:color_count = 0
+ augroup TestColors
+ au!
+ au ColorScheme * let g:color_count += 1| let g:after_colors = g:color_count
+ au ColorSchemePre * let g:color_count += 1 |let g:before_colors = g:color_count
+ augroup END
+
+ colorscheme torte
+ redraw!
+ call assert_equal('dark', &background)
+ call assert_equal(1, g:before_colors)
+ call assert_equal(2, g:after_colors)
+ call assert_equal("\ntorte", execute('colorscheme'))
+
+ let a = substitute(execute('hi Search'), "\n\\s\\+", ' ', 'g')
+ call assert_match("\nSearch xxx term=reverse ctermfg=0 ctermbg=12 gui=bold guifg=Black guibg=Red", a)
+
+ call assert_fails('colorscheme does_not_exist', 'E185:')
+
+ exec 'colorscheme' colorscheme_saved
+ augroup TestColors
+ au!
+ augroup END
+ unlet g:color_count g:after_colors g:before_colors
+ redraw!
+endfunc
+
+func Test_getfontname_with_arg()
+ let skipped = ''
+
+ if !g:x11_based_gui
+ let skipped = g:not_implemented
+ elseif has('gui_athena') || has('gui_motif')
+ " Invalid font name. The result should be an empty string.
+ call assert_equal('', getfontname('notexist'))
+
+ " Valid font name. This is usually the real name of 7x13 by default.
+ let fname = '-Misc-Fixed-Medium-R-Normal--13-120-75-75-C-70-ISO8859-1'
+ call assert_match(fname, getfontname(fname))
+
+ elseif has('gui_gtk2') || has('gui_gnome') || has('gui_gtk3')
+ " Invalid font name. The result should be the name plus the default size.
+ call assert_equal('notexist 10', getfontname('notexist'))
+
+ " Valid font name. This is usually the real name of Monospace by default.
+ let fname = 'Bitstream Vera Sans Mono 12'
+ call assert_equal(fname, getfontname(fname))
+ endif
+
+ if !empty(skipped)
+ throw skipped
+ endif
+endfunc
+
+func Test_getfontname_without_arg()
+ let skipped = ''
+
+ let fname = getfontname()
+
+ if !g:x11_based_gui
+ let skipped = g:not_implemented
+ elseif has('gui_kde')
+ " 'expected' is the value specified by SetUp() above.
+ call assert_equal('Courier 10 Pitch/8/-1/5/50/0/0/0/0/0', fname)
+ elseif has('gui_athena') || has('gui_motif')
+ " 'expected' is DFLT_FONT of gui_x11.c or its real name.
+ let pat = '\(7x13\)\|\(\c-Misc-Fixed-Medium-R-Normal--13-120-75-75-C-70-ISO8859-1\)'
+ call assert_match(pat, fname)
+ elseif has('gui_gtk2') || has('gui_gnome') || has('gui_gtk3')
+ " 'expected' is DEFAULT_FONT of gui_gtk_x11.c.
+ call assert_equal('Monospace 10', fname)
+ endif
+
+ if !empty(skipped)
+ throw skipped
+ endif
+endfunc
+
+func Test_getwinpos()
+ call assert_match('Window position: X \d\+, Y \d\+', execute('winpos'))
+ call assert_true(getwinposx() >= 0)
+ call assert_true(getwinposy() >= 0)
+ call assert_equal([getwinposx(), getwinposy()], getwinpos())
+endfunc
+
+func Test_quoteplus()
+ let skipped = ''
+
+ if !g:x11_based_gui
+ let skipped = g:not_supported . 'quoteplus'
+ else
+ let quoteplus_saved = @+
+
+ let test_call = 'Can you hear me?'
+ let test_response = 'Yes, I can.'
+ let vim_exe = exepath(v:progpath)
+ let testee = 'VIMRUNTIME=' . $VIMRUNTIME . '; export VIMRUNTIME;'
+ \ . vim_exe
+ \ . ' -u NONE -U NONE --noplugin --not-a-term -c ''%s'''
+ " Ignore the "failed to create input context" error.
+ let cmd = 'call test_ignore_error("E285") | '
+ \ . 'gui -f | '
+ \ . 'call feedkeys("'
+ \ . '\"+p'
+ \ . ':s/' . test_call . '/' . test_response . '/\<CR>'
+ \ . '\"+yis'
+ \ . ':q!\<CR>", "tx")'
+ let run_vimtest = printf(testee, cmd)
+
+ " Set the quoteplus register to test_call, and another gvim will launched.
+ " Then, it first tries to paste the content of its own quotedplus register
+ " onto it. Second, it tries to substitute test_response for the pasted
+ " sentence. If the sentence is identical to test_call, the substitution
+ " should succeed. Third, it tries to yank the result of the substitution
+ " to its own quoteplus register, and last it quits. When system()
+ " returns, the content of the quoteplus register should be identical to
+ " test_response if those quoteplus registers are synchronized properly
+ " with/through the X11 clipboard.
+ let @+ = test_call
+ call system(run_vimtest)
+ call assert_equal(test_response, @+)
+
+ let @+ = quoteplus_saved
+ endif
+
+ if !empty(skipped)
+ throw skipped
+ endif
+endfunc
+
+func Test_set_background()
+ let background_saved = &background
+
+ set background&
+ call assert_equal('light', &background)
+
+ set background=dark
+ call assert_equal('dark', &background)
+
+ let &background = background_saved
+endfunc
+
+func Test_set_balloondelay()
+ if !exists('+balloondelay')
+ return
+ endif
+
+ let balloondelay_saved = &balloondelay
+
+ " Check if the default value is identical to that described in the manual.
+ set balloondelay&
+ call assert_equal(600, &balloondelay)
+
+ " Edge cases
+
+ " XXX This fact should be hidden so that people won't be tempted to write
+ " plugin/TimeMachine.vim. TODO Add reasonable range checks to the source
+ " code.
+ set balloondelay=-1
+ call assert_equal(-1, &balloondelay)
+
+ " Though it's possible to interpret the zero delay to be 'as soon as
+ " possible' or even 'indefinite', its actual meaning depends on the GUI
+ " toolkit in use after all.
+ set balloondelay=0
+ call assert_equal(0, &balloondelay)
+
+ set balloondelay=1
+ call assert_equal(1, &balloondelay)
+
+ " Since p_bdelay is of type long currently, the upper bound can be
+ " impractically huge and machine-dependent. Practically, it's sufficient
+ " to check if balloondelay works with 0x7fffffff (32 bits) for now.
+ set balloondelay=2147483647
+ call assert_equal(2147483647, &balloondelay)
+
+ let &balloondelay = balloondelay_saved
+endfunc
+
+func Test_set_ballooneval()
+ if !exists('+ballooneval')
+ return
+ endif
+
+ let ballooneval_saved = &ballooneval
+
+ set ballooneval&
+ call assert_equal(0, &ballooneval)
+
+ set ballooneval
+ call assert_notequal(0, &ballooneval)
+
+ set noballooneval
+ call assert_equal(0, &ballooneval)
+
+ let &ballooneval = ballooneval_saved
+endfunc
+
+func Test_set_balloonexpr()
+ if !exists('+balloonexpr')
+ return
+ endif
+
+ let balloonexpr_saved = &balloonexpr
+
+ " Default value
+ set balloonexpr&
+ call assert_equal('', &balloonexpr)
+
+ " User-defined function
+ new
+ func MyBalloonExpr()
+ return 'Cursor is at line ' . v:beval_lnum .
+ \', column ' . v:beval_col .
+ \ ' of file ' . bufname(v:beval_bufnr) .
+ \ ' on word "' . v:beval_text . '"' .
+ \ ' in window ' . v:beval_winid . ' (#' . v:beval_winnr . ')'
+ endfunc
+ setl balloonexpr=MyBalloonExpr()
+ setl ballooneval
+ call assert_equal('MyBalloonExpr()', &balloonexpr)
+ " TODO Read non-empty text, place the pointer at a character of a word,
+ " and check if the content of the balloon is the same as what is expected.
+ " Also, check if textlock works as expected.
+ setl balloonexpr&
+ call assert_equal('', &balloonexpr)
+ delfunc MyBalloonExpr
+ bwipe!
+
+ " Multiline support
+ if has('balloon_multiline')
+ " Multiline balloon using NL
+ new
+ func MyBalloonFuncForMultilineUsingNL()
+ return "Multiline\nSuppported\nBalloon\nusing NL"
+ endfunc
+ setl balloonexpr=MyBalloonFuncForMultilineUsingNL()
+ setl ballooneval
+ call assert_equal('MyBalloonFuncForMultilineUsingNL()', &balloonexpr)
+ " TODO Read non-empty text, place the pointer at a character of a word,
+ " and check if the content of the balloon is the same as what is
+ " expected. Also, check if textlock works as expected.
+ setl balloonexpr&
+ delfunc MyBalloonFuncForMultilineUsingNL
+ bwipe!
+
+ " Multiline balloon using List
+ new
+ func MyBalloonFuncForMultilineUsingList()
+ return [ 'Multiline', 'Suppported', 'Balloon', 'using List' ]
+ endfunc
+ setl balloonexpr=MyBalloonFuncForMultilineUsingList()
+ setl ballooneval
+ call assert_equal('MyBalloonFuncForMultilineUsingList()', &balloonexpr)
+ " TODO Read non-empty text, place the pointer at a character of a word,
+ " and check if the content of the balloon is the same as what is
+ " expected. Also, check if textlock works as expected.
+ setl balloonexpr&
+ delfunc MyBalloonFuncForMultilineUsingList
+ bwipe!
+ endif
+
+ let &balloonexpr = balloonexpr_saved
+endfunc
+
+" Invalid arguments are tested with test_options in conjunction with segfaults
+" caused by them (Patch 8.0.0357, 24922ec233).
+func Test_set_guicursor()
+ let guicursor_saved = &guicursor
+
+ let default = [
+ \ "n-v-c:block-Cursor/lCursor",
+ \ "ve:ver35-Cursor",
+ \ "o:hor50-Cursor",
+ \ "i-ci:ver25-Cursor/lCursor",
+ \ "r-cr:hor20-Cursor/lCursor",
+ \ "sm:block-Cursor-blinkwait175-blinkoff150-blinkon175"
+ \ ]
+
+ " Default Value
+ set guicursor&
+ call assert_equal(join(default, ','), &guicursor)
+
+ " Argument List Example 1
+ let opt_list = copy(default)
+ let opt_list[0] = "n-c-v:block-nCursor"
+ exec "set guicursor=" . join(opt_list, ',')
+ call assert_equal(join(opt_list, ','), &guicursor)
+ unlet opt_list
+
+ " Argument List Example 2
+ let opt_list = copy(default)
+ let opt_list[3] = "i-ci:ver30-iCursor-blinkwait300-blinkon200-blinkoff150"
+ exec "set guicursor=" . join(opt_list, ',')
+ call assert_equal(join(opt_list, ','), &guicursor)
+ unlet opt_list
+
+ " 'a' Mode
+ set guicursor&
+ let &guicursor .= ',a:blinkon0'
+ call assert_equal(join(default, ',') . ",a:blinkon0", &guicursor)
+
+ let &guicursor = guicursor_saved
+endfunc
+
+func Test_set_guifont()
+ let skipped = ''
+
+ let guifont_saved = &guifont
+ if has('xfontset')
+ " Prevent 'guifontset' from canceling 'guifont'.
+ let guifontset_saved = &guifontset
+ set guifontset=
+ endif
+
+ if !g:x11_based_gui
+ let skipped = g:not_implemented
+ elseif has('gui_athena') || has('gui_motif')
+ " Non-empty font list with invalid font names.
+ "
+ " This test is twofold: (1) It checks if the command fails as expected
+ " when there are no loadable fonts found in the list. (2) It checks if
+ " 'guifont' remains the same after the command loads none of the fonts
+ " listed.
+ let flist = &guifont
+ call assert_fails('set guifont=-notexist1-*,-notexist2-*')
+ call assert_equal(flist, &guifont)
+
+ " Non-empty font list with a valid font name. Should pick up the first
+ " valid font.
+ set guifont=-notexist1-*,fixed,-notexist2-*
+ let pat = '\(fixed\)\|\(\c-Misc-Fixed-Medium-R-SemiCondensed--13-120-75-75-C-60-ISO8859-1\)'
+ call assert_match(pat, getfontname())
+
+ " Empty list. Should fallback to the built-in default.
+ set guifont=
+ let pat = '\(7x13\)\|\(\c-Misc-Fixed-Medium-R-Normal--13-120-75-75-C-70-ISO8859-1\)'
+ call assert_match(pat, getfontname())
+
+ elseif has('gui_gtk2') || has('gui_gnome') || has('gui_gtk3')
+ " For GTK, what we refer to as 'font names' in our manual are actually
+ " 'initial font patterns'. A valid font which matches the 'canonical font
+ " pattern' constructed from a given 'initial pattern' is to be looked up
+ " and loaded. That explains why the GTK GUIs appear to accept 'invalid
+ " font names'.
+ "
+ " Non-empty list. Should always pick up the first element, no matter how
+ " strange it is, as explained above.
+ set guifont=(´・ω・`)\ 12,Courier\ 12
+ call assert_equal('(´・ω・`) 12', getfontname())
+
+ " Empty list. Should fallback to the built-in default.
+ set guifont=
+ call assert_equal('Monospace 10', getfontname())
+ endif
+
+ if has('xfontset')
+ let &guifontset = guifontset_saved
+ endif
+ let &guifont = guifont_saved
+
+ if !empty(skipped)
+ throw skipped
+ endif
+endfunc
+
+func Test_set_guifontset()
+ let skipped = ''
+
+ if !has('xfontset')
+ let skipped = g:not_supported . 'xfontset'
+ else
+ let ctype_saved = v:ctype
+
+ " First, since XCreateFontSet(3) is very sensitive to locale, fonts must
+ " be chosen meticulously.
+ let font_head = '-misc-fixed-medium-r-normal--14'
+
+ let font_aw70 = font_head . '-130-75-75-c-70'
+ let font_aw140 = font_head . '-130-75-75-c-140'
+
+ let font_jisx0201 = font_aw70 . '-jisx0201.1976-0'
+ let font_jisx0208 = font_aw140 . '-jisx0208.1983-0'
+
+ let full_XLFDs = join([ font_jisx0208, font_jisx0201 ], ',')
+ let short_XLFDs = join([ font_aw140, font_aw70 ], ',')
+ let singleton = font_head . '-*'
+ let aliases = 'k14,r14'
+
+ " Second, among 'locales', look up such a locale that gets 'set
+ " guifontset=' to work successfully with every fontset specified with
+ " 'fontsets'.
+ let locales = [ 'ja_JP.UTF-8', 'ja_JP.eucJP', 'ja_JP.SJIS' ]
+ let fontsets = [ full_XLFDs, short_XLFDs, singleton, aliases ]
+
+ let feasible = 0
+ for locale in locales
+ try
+ exec 'language ctype' locale
+ catch /^Vim\%((\a\+)\)\=:E197/
+ continue
+ endtry
+ let done = 0
+ for fontset in fontsets
+ try
+ exec 'set guifontset=' . fontset
+ catch /^Vim\%((\a\+)\)\=:E\%(250\|252\|234\|597\|598\)/
+ break
+ endtry
+ let done += 1
+ endfor
+ if done == len(fontsets)
+ let feasible = 1
+ break
+ endif
+ endfor
+
+ " Third, give a set of tests if it is found feasible.
+ if !feasible
+ let skipped = g:not_hosted
+ else
+ " N.B. 'v:ctype' has already been set to an appropriate value in the
+ " previous loop.
+ for fontset in fontsets
+ exec 'set guifontset=' . fontset
+ call assert_equal(fontset, &guifontset)
+ endfor
+ endif
+
+ " Finally, restore ctype.
+ exec 'language ctype' ctype_saved
+ endif
+
+ if !empty(skipped)
+ throw skipped
+ endif
+endfunc
+
+func Test_set_guifontwide()
+ let skipped = ''
+
+ if !g:x11_based_gui
+ let skipped = g:not_implemented
+ elseif has('gui_gtk')
+ let guifont_saved = &guifont
+ let guifontwide_saved = &guifontwide
+
+ let fc_match = exepath('fc-match')
+ if empty(fc_match)
+ let skipped = g:not_hosted
+ else
+ let &guifont = system('fc-match -f "%{family[0]} %{size}" monospace:size=10:lang=en')
+ let wide = system('fc-match -f "%{family[0]} %{size}" monospace:size=10:lang=ja')
+ exec 'set guifontwide=' . fnameescape(wide)
+ call assert_equal(wide, &guifontwide)
+ endif
+
+ let &guifontwide = guifontwide_saved
+ let &guifont = guifont_saved
+
+ elseif has('gui_athena') || has('gui_motif')
+ " guifontwide is premised upon the xfontset feature.
+ if !has('xfontset')
+ let skipped = g:not_supported . 'xfontset'
+ else
+ let encoding_saved = &encoding
+ let guifont_saved = &guifont
+ let guifontset_saved = &guifontset
+ let guifontwide_saved = &guifontwide
+
+ let nfont = '-misc-fixed-medium-r-normal-*-18-120-100-100-c-90-iso10646-1'
+ let wfont = '-misc-fixed-medium-r-normal-*-18-120-100-100-c-180-iso10646-1'
+
+ set encoding=utf-8
+
+ " Case 1: guifontset is empty
+ set guifontset=
+
+ " Case 1-1: Automatic selection
+ set guifontwide=
+ exec 'set guifont=' . nfont
+ call assert_equal(wfont, &guifontwide)
+
+ " Case 1-2: Manual selection
+ exec 'set guifontwide=' . wfont
+ exec 'set guifont=' . nfont
+ call assert_equal(wfont, &guifontwide)
+
+ " Case 2: guifontset is invalid
+ try
+ set guifontset=-*-notexist-*
+ call assert_report("'set guifontset=-*-notexist-*' should have failed")
+ catch
+ call assert_exception('E598')
+ endtry
+ " Set it to an invalid value brutally for preparation.
+ let &guifontset = '-*-notexist-*'
+
+ " Case 2-1: Automatic selection
+ set guifontwide=
+ exec 'set guifont=' . nfont
+ call assert_equal(wfont, &guifontwide)
+
+ " Case 2-2: Manual selection
+ exec 'set guifontwide=' . wfont
+ exec 'set guifont=' . nfont
+ call assert_equal(wfont, &guifontwide)
+
+ let &guifontwide = guifontwide_saved
+ let &guifontset = guifontset_saved
+ let &guifont = guifont_saved
+ let &encoding = encoding_saved
+ endif
+ endif
+
+ if !empty(skipped)
+ throw skipped
+ endif
+endfunc
+
+func Test_set_guiheadroom()
+ let skipped = ''
+
+ if !g:x11_based_gui
+ let skipped = g:not_supported . 'guiheadroom'
+ else
+ " Since this script is to be read together with '-U NONE', the default
+ " value must be preserved.
+ call assert_equal(50, &guiheadroom)
+ endif
+
+ if !empty(skipped)
+ throw skipped
+ endif
+endfunc
+
+func Test_set_guioptions()
+ let guioptions_saved = &guioptions
+ let duration = '200m'
+
+ if has('win32')
+ " Default Value
+ set guioptions&
+ call assert_equal('egmrLtT', &guioptions)
+
+ else
+ " Default Value
+ set guioptions&
+ call assert_equal('aegimrLtT', &guioptions)
+
+ " To activate scrollbars of type 'L' or 'R'.
+ wincmd v
+ redraw!
+
+ " Remove all default GUI ornaments
+ set guioptions-=T
+ exec 'sleep' . duration
+ call assert_equal('aegimrLt', &guioptions)
+ set guioptions-=t
+ exec 'sleep' . duration
+ call assert_equal('aegimrL', &guioptions)
+ set guioptions-=L
+ exec 'sleep' . duration
+ call assert_equal('aegimr', &guioptions)
+ set guioptions-=r
+ exec 'sleep' . duration
+ call assert_equal('aegim', &guioptions)
+ set guioptions-=m
+ exec 'sleep' . duration
+ call assert_equal('aegi', &guioptions)
+
+ " Try non-default GUI ornaments
+ set guioptions+=l
+ exec 'sleep' . duration
+ call assert_equal('aegil', &guioptions)
+ set guioptions-=l
+ exec 'sleep' . duration
+ call assert_equal('aegi', &guioptions)
+
+ set guioptions+=R
+ exec 'sleep' . duration
+ call assert_equal('aegiR', &guioptions)
+ set guioptions-=R
+ exec 'sleep' . duration
+ call assert_equal('aegi', &guioptions)
+
+ set guioptions+=b
+ exec 'sleep' . duration
+ call assert_equal('aegib', &guioptions)
+ set guioptions+=h
+ exec 'sleep' . duration
+ call assert_equal('aegibh', &guioptions)
+ set guioptions-=h
+ exec 'sleep' . duration
+ call assert_equal('aegib', &guioptions)
+ set guioptions-=b
+ exec 'sleep' . duration
+ call assert_equal('aegi', &guioptions)
+
+ set guioptions+=v
+ exec 'sleep' . duration
+ call assert_equal('aegiv', &guioptions)
+ set guioptions-=v
+ exec 'sleep' . duration
+ call assert_equal('aegi', &guioptions)
+
+ if has('gui_motif')
+ set guioptions+=F
+ exec 'sleep' . duration
+ call assert_equal('aegiF', &guioptions)
+ set guioptions-=F
+ exec 'sleep' . duration
+ call assert_equal('aegi', &guioptions)
+ endif
+
+ " Restore GUI ornaments to the default state.
+ set guioptions+=m
+ exec 'sleep' . duration
+ call assert_equal('aegim', &guioptions)
+ set guioptions+=r
+ exec 'sleep' . duration
+ call assert_equal('aegimr', &guioptions)
+ set guioptions+=L
+ exec 'sleep' . duration
+ call assert_equal('aegimrL', &guioptions)
+ set guioptions+=t
+ exec 'sleep' . duration
+ call assert_equal('aegimrLt', &guioptions)
+ set guioptions+=T
+ exec 'sleep' . duration
+ call assert_equal("aegimrLtT", &guioptions)
+
+ wincmd o
+ redraw!
+ endif
+
+ let &guioptions = guioptions_saved
+endfunc
+
+func Test_scrollbars()
+ new
+ " buffer with 200 lines
+ call setline(1, repeat(['one', 'two'], 100))
+ set guioptions+=rlb
+
+ " scroll to move line 11 at top, moves the cursor there
+ call test_scrollbar('left', 10, 0)
+ redraw
+ call assert_equal(1, winline())
+ call assert_equal(11, line('.'))
+
+ " scroll to move line 1 at top, cursor stays in line 11
+ call test_scrollbar('right', 0, 0)
+ redraw
+ call assert_equal(11, winline())
+ call assert_equal(11, line('.'))
+
+ set nowrap
+ call setline(11, repeat('x', 150))
+ redraw
+ call assert_equal(1, wincol())
+ call assert_equal(1, col('.'))
+
+ " scroll to character 11, cursor is moved
+ call test_scrollbar('hor', 10, 0)
+ redraw
+ call assert_equal(1, wincol())
+ call assert_equal(11, col('.'))
+
+ set guioptions&
+ set wrap&
+ bwipe!
+endfunc
+
+func Test_set_guipty()
+ let guipty_saved = &guipty
+
+ " Default Value
+ set guipty&
+ call assert_equal(1, &guipty)
+
+ set noguipty
+ call assert_equal(0, &guipty)
+
+ let &guipty = guipty_saved
+endfunc
+
+func Test_shell_command()
+ new
+ r !echo hello
+ call assert_equal('hello', substitute(getline(2), '\W', '', 'g'))
+ bwipe!
+endfunc
+
+func Test_syntax_colortest()
+ runtime syntax/colortest.vim
+ redraw!
+ sleep 200m
+ bwipe!
+endfunc
+
+func Test_set_term()
+ " It's enough to check the current value since setting 'term' to anything
+ " other than builtin_gui makes no sense at all.
+ call assert_equal('builtin_gui', &term)
+endfunc
+
+func Test_windowid_variable()
+ if g:x11_based_gui || has('win32')
+ call assert_true(v:windowid > 0)
+ else
+ call assert_equal(0, v:windowid)
+ endif
+endfunc
+
+" Test "vim -g" and also the GUIEnter autocommand.
+func Test_gui_dash_g()
+ let cmd = GetVimCommand('Xscriptgui')
+ call writefile([""], "Xtestgui")
+ call writefile([
+ \ 'au GUIEnter * call writefile(["insertmode: " . &insertmode], "Xtestgui")',
+ \ 'au GUIEnter * qall',
+ \ ], 'Xscriptgui')
+ call system(cmd . ' -g')
+ call WaitForAssert({-> assert_equal(['insertmode: 0'], readfile('Xtestgui'))})
+
+ call delete('Xscriptgui')
+ call delete('Xtestgui')
+endfunc
+
+" Test "vim -7" and also the GUIEnter autocommand.
+func Test_gui_dash_y()
+ let cmd = GetVimCommand('Xscriptgui')
+ call writefile([""], "Xtestgui")
+ call writefile([
+ \ 'au GUIEnter * call writefile(["insertmode: " . &insertmode], "Xtestgui")',
+ \ 'au GUIEnter * qall',
+ \ ], 'Xscriptgui')
+ call system(cmd . ' -y')
+ call WaitForAssert({-> assert_equal(['insertmode: 1'], readfile('Xtestgui'))})
+
+ call delete('Xscriptgui')
+ call delete('Xtestgui')
+endfunc
diff --git a/src/testdir/test_gui_init.vim b/src/testdir/test_gui_init.vim
new file mode 100644
index 0000000..638708f
--- /dev/null
+++ b/src/testdir/test_gui_init.vim
@@ -0,0 +1,61 @@
+" Tests specifically for the GUI features/options that need to be set up at
+" startup to take effect at runtime.
+
+source shared.vim
+if !CanRunGui()
+ finish
+endif
+
+source setup_gui.vim
+
+func Setup()
+ call GUISetUpCommon()
+endfunc
+
+func TearDown()
+ call GUITearDownCommon()
+endfunc
+
+" Ignore the "failed to create input context" error.
+call test_ignore_error('E285:')
+
+" Start the GUI now, in the foreground.
+gui -f
+
+func Test_set_guiheadroom()
+ let skipped = ''
+
+ if !g:x11_based_gui
+ let skipped = g:not_supported . 'guiheadroom'
+ else
+ " The 'expected' value must be consistent with the value specified with
+ " gui_init.vim.
+ call assert_equal(0, &guiheadroom)
+ endif
+
+ if !empty(skipped)
+ throw skipped
+ endif
+endfunc
+
+func Test_set_guioptions_for_M()
+ sleep 200ms
+ " Check if the 'M' option is included.
+ call assert_match('.*M.*', &guioptions)
+endfunc
+
+func Test_set_guioptions_for_p()
+ let skipped = ''
+
+ if !g:x11_based_gui
+ let skipped = g:not_supported . '''p'' of guioptions'
+ else
+ sleep 200ms
+ " Check if the 'p' option is included.
+ call assert_match('.*p.*', &guioptions)
+ endif
+
+ if !empty(skipped)
+ throw skipped
+ endif
+endfunc
diff --git a/src/testdir/test_hardcopy.vim b/src/testdir/test_hardcopy.vim
new file mode 100644
index 0000000..ced13b1
--- /dev/null
+++ b/src/testdir/test_hardcopy.vim
@@ -0,0 +1,89 @@
+" Test :hardcopy
+
+func Test_printoptions_parsing()
+ " Only test that this doesn't throw an error.
+ set printoptions=left:5in,right:10pt,top:8mm,bottom:2pc
+ set printoptions=left:2in,top:30pt,right:16mm,bottom:3pc
+ set printoptions=header:3,syntax:y,number:7,wrap:n
+ set printoptions=duplex:short,collate:n,jobsplit:y,portrait:n
+ set printoptions=paper:10x14
+ set printoptions=paper:A3
+ set printoptions=paper:A4
+ set printoptions=paper:A5
+ set printoptions=paper:B4
+ set printoptions=paper:B5
+ set printoptions=paper:executive
+ set printoptions=paper:folio
+ set printoptions=paper:ledger
+ set printoptions=paper:legal
+ set printoptions=paper:letter
+ set printoptions=paper:quarto
+ set printoptions=paper:statement
+ set printoptions=paper:tabloid
+ set printoptions=formfeed:y
+ set printoptions=
+ set printoptions&
+
+ call assert_fails('set printoptions=paper', 'E550:')
+ call assert_fails('set printoptions=shredder:on', 'E551:')
+ call assert_fails('set printoptions=left:no', 'E552:')
+endfunc
+
+func Test_printmbfont_parsing()
+ " Only test that this doesn't throw an error.
+ set printmbfont=r:WadaMin-Regular,b:WadaMin-Bold,i:WadaMin-Italic,o:WadaMin-Bold-Italic,c:yes,a:no
+ set printmbfont=
+ set printmbfont&
+endfunc
+
+func Test_printheader_parsing()
+ " Only test that this doesn't throw an error.
+ set printheader=%<%f\ %h%m%r%=%-14.(%l,%c%V%)\ %P
+ set printheader=%<%f%h%m%r%=%b\ 0x%B\ \ %l,%c%V\ %P
+ set printheader=%<%f%=\ [%1*%M%*%n%R%H]\ %-19(%3l,%02c%03V%)%O'%02b'
+ set printheader=...%r%{VarExists('b:gzflag','\ [GZ]')}%h...
+ set printheader=
+ set printheader&
+endfunc
+
+" Test that :hardcopy produces a non-empty file.
+" We don't check much of the contents.
+func Test_with_syntax()
+ if has('postscript')
+ edit test_hardcopy.vim
+ set printoptions=syntax:y
+ syn on
+ hardcopy > Xhardcopy
+ let lines = readfile('Xhardcopy')
+ call assert_true(len(lines) > 20)
+ call assert_true(lines[0] =~ 'PS-Adobe')
+ call delete('Xhardcopy')
+ set printoptions&
+ endif
+endfunc
+
+func Test_fname_with_spaces()
+ if !has('postscript')
+ return
+ endif
+ split t\ e\ s\ t.txt
+ call setline(1, ['just', 'some', 'text'])
+ hardcopy > %.ps
+ call assert_true(filereadable('t e s t.txt.ps'))
+ call delete('t e s t.txt.ps')
+ bwipe!
+endfunc
+
+func Test_illegal_byte()
+ if !has('postscript') || &enc != 'utf-8'
+ return
+ endif
+ new
+ " conversion of 0xff will fail, this used to cause a crash
+ call setline(1, "\xff")
+ hardcopy >Xpstest
+
+ bwipe!
+ call delete('Xpstest')
+endfunc
+
diff --git a/src/testdir/test_help.vim b/src/testdir/test_help.vim
new file mode 100644
index 0000000..c550ff0
--- /dev/null
+++ b/src/testdir/test_help.vim
@@ -0,0 +1,51 @@
+" Tests for :help
+
+func Test_help_restore_snapshot()
+ help
+ set buftype=
+ help
+ edit x
+ help
+ helpclose
+endfunc
+
+func Test_help_errors()
+ call assert_fails('help doesnotexist', 'E149:')
+ call assert_fails('help!', 'E478:')
+
+ new
+ set keywordprg=:help
+ call setline(1, " ")
+ call assert_fails('normal VK', 'E349:')
+ bwipe!
+endfunc
+
+func Test_help_keyword()
+ new
+ set keywordprg=:help
+ call setline(1, " Visual ")
+ normal VK
+ call assert_match('^Visual mode', getline('.'))
+ call assert_equal('help', &ft)
+ close
+ bwipe!
+endfunc
+
+func Test_help_local_additions()
+ call mkdir('Xruntime/doc', 'p')
+ call writefile(['*mydoc.txt* my awesome doc'], 'Xruntime/doc/mydoc.txt')
+ call writefile(['*mydoc-ext.txt* my extended awesome doc'], 'Xruntime/doc/mydoc-ext.txt')
+ let rtp_save = &rtp
+ set rtp+=./Xruntime
+ help
+ 1
+ call search('mydoc.txt')
+ call assert_equal('|mydoc.txt| my awesome doc', getline('.'))
+ 1
+ call search('mydoc-ext.txt')
+ call assert_equal('|mydoc-ext.txt| my extended awesome doc', getline('.'))
+ close
+
+ call delete('Xruntime', 'rf')
+ let &rtp = rtp_save
+endfunc
diff --git a/src/testdir/test_help_tagjump.vim b/src/testdir/test_help_tagjump.vim
new file mode 100644
index 0000000..46aa6a1
--- /dev/null
+++ b/src/testdir/test_help_tagjump.vim
@@ -0,0 +1,260 @@
+" Tests for :help! {subject}
+
+func Test_help_tagjump()
+ help
+ call assert_equal("help", &filetype)
+ call assert_true(getline('.') =~ '\*help.txt\*')
+ helpclose
+
+ help |
+ call assert_equal("help", &filetype)
+ call assert_true(getline('.') =~ '\*bar\*')
+ helpclose
+
+ help "*
+ call assert_equal("help", &filetype)
+ call assert_true(getline('.') =~ '\*quotestar\*')
+ helpclose
+
+ help sm?le
+ call assert_equal("help", &filetype)
+ call assert_true(getline('.') =~ '\*:smile\*')
+ helpclose
+
+ help :?
+ call assert_equal("help", &filetype)
+ call assert_true(getline('.') =~ '\*:?\*')
+ helpclose
+
+ help q?
+ call assert_equal("help", &filetype)
+ call assert_true(getline('.') =~ '\*q?\*')
+ call assert_true(expand('<cword>') == 'q?')
+ helpclose
+
+ help -?
+ call assert_equal("help", &filetype)
+ call assert_true(getline('.') =~ '\*-?\*')
+ helpclose
+
+ help v_g?
+ call assert_equal("help", &filetype)
+ call assert_true(getline('.') =~ '\*v_g?\*')
+ helpclose
+
+ help expr-!=?
+ call assert_equal("help", &filetype)
+ call assert_true(getline('.') =~ '\*expr-!=?\*')
+ call assert_true(expand('<cword>') == 'expr-!=?')
+ helpclose
+
+ help expr-isnot?
+ call assert_equal("help", &filetype)
+ call assert_true(getline('.') =~ '\*expr-isnot?\*')
+ call assert_true(expand('<cword>') == 'expr-isnot?')
+ helpclose
+
+ help FileW*Post
+ call assert_equal("help", &filetype)
+ call assert_true(getline('.') =~ '\*FileWritePost\*')
+ helpclose
+
+ help `ls`
+ call assert_equal("help", &filetype)
+ call assert_true(getline('.') =~ '\*:ls\*')
+ helpclose
+
+ help ^X
+ call assert_equal("help", &filetype)
+ call assert_true(getline('.') =~ '\*CTRL-X\*')
+ helpclose
+
+ help i_^_CTRL-D
+ call assert_equal("help", &filetype)
+ call assert_true(getline('.') =~ '\*i_^_CTRL-D\*')
+ helpclose
+
+ exec "help \<C-V>"
+ call assert_equal("help", &filetype)
+ call assert_true(getline('.') =~ '\*CTRL-V\*')
+ helpclose
+
+
+ exec "help! ('textwidth'"
+ call assert_equal("help", &filetype)
+ call assert_true(getline('.') =~ "\\*'textwidth'\\*")
+ helpclose
+
+ exec "help! ('buflisted'),"
+ call assert_equal("help", &filetype)
+ call assert_true(getline('.') =~ "\\*'buflisted'\\*")
+ helpclose
+
+ exec "help! abs({expr})"
+ call assert_equal("help", &filetype)
+ call assert_true(getline('.') =~ '\*abs()\*')
+ helpclose
+
+ exec "help! arglistid([{winnr}"
+ call assert_equal("help", &filetype)
+ call assert_true(getline('.') =~ '\*arglistid()\*')
+ helpclose
+
+ exec "help! 'autoindent'."
+ call assert_equal("help", &filetype)
+ call assert_true(getline('.') =~ "\\*'autoindent'\\*")
+ helpclose
+
+ exec "help! {address}."
+ call assert_equal("help", &filetype)
+ call assert_true(getline('.') =~ '\*{address}\*')
+ helpclose
+
+ exusage
+ call assert_equal("help", &filetype)
+ call assert_true(getline('.') =~ '\*:index\*')
+ helpclose
+
+ viusage
+ call assert_equal("help", &filetype)
+ call assert_true(getline('.') =~ '\*normal-index\*')
+ helpclose
+endfunc
+
+let s:langs = ['en', 'ab', 'ja']
+
+func s:doc_config_setup()
+ let s:helpfile_save = &helpfile
+ let &helpfile="Xdir1/doc-en/doc/testdoc.txt"
+ let s:rtp_save = &rtp
+ let &rtp="Xdir1/doc-en"
+ if has('multi_lang')
+ let s:helplang_save=&helplang
+ endif
+
+ call delete('Xdir1', 'rf')
+
+ for lang in s:langs
+ if lang ==# 'en'
+ let tagfname = 'tags'
+ let docfname = 'testdoc.txt'
+ else
+ let tagfname = 'tags-' . lang
+ let docfname = 'testdoc.' . lang . 'x'
+ endif
+ let docdir = "Xdir1/doc-" . lang . "/doc"
+ call mkdir(docdir, "p")
+ call writefile(["\t*test-char*", "\t*test-col*"], docdir . '/' . docfname)
+ call writefile(["test-char\t" . docfname . "\t/*test-char*",
+ \ "test-col\t" . docfname . "\t/*test-col*"],
+ \ docdir . '/' . tagfname)
+ endfor
+endfunc
+
+func s:doc_config_teardown()
+ call delete('Xdir1', 'rf')
+
+ let &helpfile = s:helpfile_save
+ let &rtp = s:rtp_save
+ if has('multi_lang')
+ let &helplang = s:helplang_save
+ endif
+endfunc
+
+func s:get_help_compl_list(cmd)
+ return getcompletion(a:cmd, 'help')
+endfunc
+
+func Test_help_complete()
+ try
+ let list = []
+ call s:doc_config_setup()
+
+ " 'helplang=' and help file lang is 'en'
+ if has('multi_lang')
+ set helplang=
+ endif
+ let list = s:get_help_compl_list("test")
+ call assert_equal(['test-col', 'test-char'], list)
+
+ if has('multi_lang')
+ " 'helplang=ab' and help file lang is 'en'
+ set helplang=ab
+ let list = s:get_help_compl_list("test")
+ call assert_equal(['test-col', 'test-char'], list)
+
+ " 'helplang=' and help file lang is 'en' and 'ab'
+ set rtp+=Xdir1/doc-ab
+ set helplang=
+ let list = s:get_help_compl_list("test")
+ call assert_equal(sort(['test-col@en', 'test-col@ab',
+ \ 'test-char@en', 'test-char@ab']), sort(list))
+
+ " 'helplang=ab' and help file lang is 'en' and 'ab'
+ set helplang=ab
+ let list = s:get_help_compl_list("test")
+ call assert_equal(sort(['test-col', 'test-col@en',
+ \ 'test-char', 'test-char@en']), sort(list))
+
+ " 'helplang=' and help file lang is 'en', 'ab' and 'ja'
+ set rtp+=Xdir1/doc-ja
+ set helplang=
+ let list = s:get_help_compl_list("test")
+ call assert_equal(sort(['test-col@en', 'test-col@ab',
+ \ 'test-col@ja', 'test-char@en',
+ \ 'test-char@ab', 'test-char@ja']), sort(list))
+
+ " 'helplang=ab' and help file lang is 'en', 'ab' and 'ja'
+ set helplang=ab
+ let list = s:get_help_compl_list("test")
+ call assert_equal(sort(['test-col', 'test-col@en',
+ \ 'test-col@ja', 'test-char',
+ \ 'test-char@en', 'test-char@ja']), sort(list))
+
+ " 'helplang=ab,ja' and help file lang is 'en', 'ab' and 'ja'
+ set helplang=ab,ja
+ let list = s:get_help_compl_list("test")
+ call assert_equal(sort(['test-col', 'test-col@ja',
+ \ 'test-col@en', 'test-char',
+ \ 'test-char@ja', 'test-char@en']), sort(list))
+ endif
+ catch
+ call assert_exception('X')
+ finally
+ call s:doc_config_teardown()
+ endtry
+endfunc
+
+func Test_help_respect_current_file_lang()
+ try
+ let list = []
+ call s:doc_config_setup()
+
+ if has('multi_lang')
+ function s:check_help_file_ext(help_keyword, ext)
+ exec 'help ' . a:help_keyword
+ call assert_equal(a:ext, expand('%:e'))
+ call feedkeys("\<C-]>", 'tx')
+ call assert_equal(a:ext, expand('%:e'))
+ pop
+ helpclose
+ endfunc
+
+ set rtp+=Xdir1/doc-ab
+ set rtp+=Xdir1/doc-ja
+
+ set helplang=ab
+ call s:check_help_file_ext('test-char', 'abx')
+ call s:check_help_file_ext('test-char@ja', 'jax')
+ set helplang=ab,ja
+ call s:check_help_file_ext('test-char@ja', 'jax')
+ call s:check_help_file_ext('test-char@en', 'txt')
+ endif
+ catch
+ call assert_exception('X')
+ finally
+ call s:doc_config_teardown()
+ endtry
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/test_hide.vim b/src/testdir/test_hide.vim
new file mode 100644
index 0000000..128b8ff
--- /dev/null
+++ b/src/testdir/test_hide.vim
@@ -0,0 +1,97 @@
+" Tests for :hide command/modifier and 'hidden' option
+
+function SetUp()
+ let s:save_hidden = &hidden
+ let s:save_bufhidden = &bufhidden
+ let s:save_autowrite = &autowrite
+ set nohidden
+ set bufhidden=
+ set noautowrite
+endfunc
+
+function TearDown()
+ let &hidden = s:save_hidden
+ let &bufhidden = s:save_bufhidden
+ let &autowrite = s:save_autowrite
+endfunc
+
+function Test_hide()
+ let orig_bname = bufname('')
+ let orig_winnr = winnr('$')
+
+ new Xf1
+ set modified
+ call assert_fails('edit Xf2')
+ bwipeout! Xf1
+
+ new Xf1
+ set modified
+ edit! Xf2
+ call assert_equal(['Xf2', 2], [bufname(''), winnr('$')])
+ call assert_equal([1, 0], [buflisted('Xf1'), bufloaded('Xf1')])
+ bwipeout! Xf1
+ bwipeout! Xf2
+
+ new Xf1
+ set modified
+ " :hide as a command
+ hide
+ call assert_equal([orig_bname, orig_winnr], [bufname(''), winnr('$')])
+ call assert_equal([1, 1], [buflisted('Xf1'), bufloaded('Xf1')])
+ bwipeout! Xf1
+
+ new Xf1
+ set modified
+ " :hide as a command with trailing comment
+ hide " comment
+ call assert_equal([orig_bname, orig_winnr], [bufname(''), winnr('$')])
+ call assert_equal([1, 1], [buflisted('Xf1'), bufloaded('Xf1')])
+ bwipeout! Xf1
+
+ new Xf1
+ set modified
+ " :hide as a command with bar
+ hide | new Xf2 " comment
+ call assert_equal(['Xf2', 2], [bufname(''), winnr('$')])
+ call assert_equal([1, 1], [buflisted('Xf1'), bufloaded('Xf1')])
+ bwipeout! Xf1
+ bwipeout! Xf2
+
+ new Xf1
+ set modified
+ " :hide as a modifier with trailing comment
+ hide edit Xf2 " comment
+ call assert_equal(['Xf2', 2], [bufname(''), winnr('$')])
+ call assert_equal([1, 1], [buflisted('Xf1'), bufloaded('Xf1')])
+ bwipeout! Xf1
+ bwipeout! Xf2
+
+ new Xf1
+ set modified
+ " To check that the bar is not recognized to separate commands
+ hide echo "one|two"
+ call assert_equal(['Xf1', 2], [bufname(''), winnr('$')])
+ call assert_equal([1, 1], [buflisted('Xf1'), bufloaded('Xf1')])
+ bwipeout! Xf1
+
+ " set hidden
+ new Xf1
+ set hidden
+ set modified
+ edit Xf2 " comment
+ call assert_equal(['Xf2', 2], [bufname(''), winnr('$')])
+ call assert_equal([1, 1], [buflisted('Xf1'), bufloaded('Xf1')])
+ bwipeout! Xf1
+ bwipeout! Xf2
+
+ " set hidden bufhidden=wipe
+ new Xf1
+ set bufhidden=wipe
+ set modified
+ hide edit! Xf2 " comment
+ call assert_equal(['Xf2', 2], [bufname(''), winnr('$')])
+ call assert_equal([0, 0], [buflisted('Xf1'), bufloaded('Xf1')])
+ bwipeout! Xf2
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/test_highlight.vim b/src/testdir/test_highlight.vim
new file mode 100644
index 0000000..b37684c
--- /dev/null
+++ b/src/testdir/test_highlight.vim
@@ -0,0 +1,554 @@
+" Tests for ":highlight" and highlighting.
+
+source view_util.vim
+source screendump.vim
+
+func Test_highlight()
+ " basic test if ":highlight" doesn't crash
+ highlight
+ hi Search
+
+ " test setting colors.
+ " test clearing one color and all doesn't generate error or warning
+ silent! hi NewGroup term=bold cterm=italic ctermfg=DarkBlue ctermbg=Grey gui= guifg=#00ff00 guibg=Cyan
+ silent! hi Group2 term= cterm=
+ hi Group3 term=underline cterm=bold
+
+ let res = split(execute("hi NewGroup"), "\n")[0]
+ " filter ctermfg and ctermbg, the numbers depend on the terminal
+ let res = substitute(res, 'ctermfg=\d*', 'ctermfg=2', '')
+ let res = substitute(res, 'ctermbg=\d*', 'ctermbg=3', '')
+ call assert_equal("NewGroup xxx term=bold cterm=italic ctermfg=2 ctermbg=3",
+ \ res)
+ call assert_equal("Group2 xxx cleared",
+ \ split(execute("hi Group2"), "\n")[0])
+ call assert_equal("Group3 xxx term=underline cterm=bold",
+ \ split(execute("hi Group3"), "\n")[0])
+
+ hi clear NewGroup
+ call assert_equal("NewGroup xxx cleared",
+ \ split(execute("hi NewGroup"), "\n")[0])
+ call assert_equal("Group2 xxx cleared",
+ \ split(execute("hi Group2"), "\n")[0])
+ hi Group2 NONE
+ call assert_equal("Group2 xxx cleared",
+ \ split(execute("hi Group2"), "\n")[0])
+ hi clear
+ call assert_equal("Group3 xxx cleared",
+ \ split(execute("hi Group3"), "\n")[0])
+ call assert_fails("hi Crash term='asdf", "E475:")
+endfunc
+
+func HighlightArgs(name)
+ return 'hi ' . substitute(split(execute('hi ' . a:name), '\n')[0], '\<xxx\>', '', '')
+endfunc
+
+func IsColorable()
+ return has('gui_running') || str2nr(&t_Co) >= 8
+endfunc
+
+func HiCursorLine()
+ let hiCursorLine = HighlightArgs('CursorLine')
+ if has('gui_running')
+ let guibg = matchstr(hiCursorLine, 'guibg=\w\+')
+ let hi_ul = 'hi CursorLine gui=underline guibg=NONE'
+ let hi_bg = 'hi CursorLine gui=NONE ' . guibg
+ else
+ let hi_ul = 'hi CursorLine cterm=underline ctermbg=NONE'
+ let hi_bg = 'hi CursorLine cterm=NONE ctermbg=Gray'
+ endif
+ return [hiCursorLine, hi_ul, hi_bg]
+endfunc
+
+func Check_lcs_eol_attrs(attrs, row, col)
+ let save_lcs = &lcs
+ set list
+
+ call assert_equal(a:attrs, ScreenAttrs(a:row, a:col)[0])
+
+ set nolist
+ let &lcs = save_lcs
+endfunc
+
+func Test_highlight_eol_with_cursorline()
+ let [hiCursorLine, hi_ul, hi_bg] = HiCursorLine()
+
+ call NewWindow('topleft 5', 20)
+ call setline(1, 'abcd')
+ call matchadd('Search', '\n')
+
+ " expected:
+ " 'abcd '
+ " ^^^^ ^^^^^ no highlight
+ " ^ 'Search' highlight
+ let attrs0 = ScreenAttrs(1, 10)[0]
+ call assert_equal(repeat([attrs0[0]], 4), attrs0[0:3])
+ call assert_equal(repeat([attrs0[0]], 5), attrs0[5:9])
+ call assert_notequal(attrs0[0], attrs0[4])
+
+ setlocal cursorline
+
+ " underline
+ exe hi_ul
+
+ " expected:
+ " 'abcd '
+ " ^^^^ underline
+ " ^ 'Search' highlight with underline
+ " ^^^^^ underline
+ let attrs = ScreenAttrs(1, 10)[0]
+ call assert_equal(repeat([attrs[0]], 4), attrs[0:3])
+ call assert_equal([attrs[4]] + repeat([attrs[5]], 5), attrs[4:9])
+ call assert_notequal(attrs[0], attrs[4])
+ call assert_notequal(attrs[4], attrs[5])
+ call assert_notequal(attrs0[0], attrs[0])
+ call assert_notequal(attrs0[4], attrs[4])
+ call Check_lcs_eol_attrs(attrs, 1, 10)
+
+ if IsColorable()
+ " bg-color
+ exe hi_bg
+
+ " expected:
+ " 'abcd '
+ " ^^^^ bg-color of 'CursorLine'
+ " ^ 'Search' highlight
+ " ^^^^^ bg-color of 'CursorLine'
+ let attrs = ScreenAttrs(1, 10)[0]
+ call assert_equal(repeat([attrs[0]], 4), attrs[0:3])
+ call assert_equal(repeat([attrs[5]], 5), attrs[5:9])
+ call assert_equal(attrs0[4], attrs[4])
+ call assert_notequal(attrs[0], attrs[4])
+ call assert_notequal(attrs[4], attrs[5])
+ call assert_notequal(attrs0[0], attrs[0])
+ call assert_notequal(attrs0[5], attrs[5])
+ call Check_lcs_eol_attrs(attrs, 1, 10)
+ endif
+
+ call CloseWindow()
+ exe hiCursorLine
+endfunc
+
+func Test_highlight_eol_with_cursorline_vertsplit()
+ let [hiCursorLine, hi_ul, hi_bg] = HiCursorLine()
+
+ call NewWindow('topleft 5', 5)
+ call setline(1, 'abcd')
+ call matchadd('Search', '\n')
+
+ let expected = "abcd |abcd "
+ let actual = ScreenLines(1, 15)[0]
+ call assert_equal(expected, actual)
+
+ " expected:
+ " 'abcd |abcd '
+ " ^^^^ ^^^^^^^^^ no highlight
+ " ^ 'Search' highlight
+ " ^ 'VertSplit' highlight
+ let attrs0 = ScreenAttrs(1, 15)[0]
+ call assert_equal(repeat([attrs0[0]], 4), attrs0[0:3])
+ call assert_equal(repeat([attrs0[0]], 9), attrs0[6:14])
+ call assert_notequal(attrs0[0], attrs0[4])
+ call assert_notequal(attrs0[0], attrs0[5])
+ call assert_notequal(attrs0[4], attrs0[5])
+
+ setlocal cursorline
+
+ " expected:
+ " 'abcd |abcd '
+ " ^^^^ underline
+ " ^ 'Search' highlight with underline
+ " ^ 'VertSplit' highlight
+ " ^^^^^^^^^ no highlight
+
+ " underline
+ exe hi_ul
+
+ let actual = ScreenLines(1, 15)[0]
+ call assert_equal(expected, actual)
+
+ let attrs = ScreenAttrs(1, 15)[0]
+ call assert_equal(repeat([attrs[0]], 4), attrs[0:3])
+ call assert_equal(repeat([attrs[6]], 9), attrs[6:14])
+ call assert_equal(attrs0[5:14], attrs[5:14])
+ call assert_notequal(attrs[0], attrs[4])
+ call assert_notequal(attrs[0], attrs[5])
+ call assert_notequal(attrs[0], attrs[6])
+ call assert_notequal(attrs[4], attrs[5])
+ call assert_notequal(attrs[5], attrs[6])
+ call assert_notequal(attrs0[0], attrs[0])
+ call assert_notequal(attrs0[4], attrs[4])
+ call Check_lcs_eol_attrs(attrs, 1, 15)
+
+ if IsColorable()
+ " bg-color
+ exe hi_bg
+
+ let actual = ScreenLines(1, 15)[0]
+ call assert_equal(expected, actual)
+
+ let attrs = ScreenAttrs(1, 15)[0]
+ call assert_equal(repeat([attrs[0]], 4), attrs[0:3])
+ call assert_equal(repeat([attrs[6]], 9), attrs[6:14])
+ call assert_equal(attrs0[5:14], attrs[5:14])
+ call assert_notequal(attrs[0], attrs[4])
+ call assert_notequal(attrs[0], attrs[5])
+ call assert_notequal(attrs[0], attrs[6])
+ call assert_notequal(attrs[4], attrs[5])
+ call assert_notequal(attrs[5], attrs[6])
+ call assert_notequal(attrs0[0], attrs[0])
+ call assert_equal(attrs0[4], attrs[4])
+ call Check_lcs_eol_attrs(attrs, 1, 15)
+ endif
+
+ call CloseWindow()
+ exe hiCursorLine
+endfunc
+
+func Test_highlight_eol_with_cursorline_rightleft()
+ if !has('rightleft')
+ return
+ endif
+
+ let [hiCursorLine, hi_ul, hi_bg] = HiCursorLine()
+
+ call NewWindow('topleft 5', 10)
+ setlocal rightleft
+ call setline(1, 'abcd')
+ call matchadd('Search', '\n')
+ let attrs0 = ScreenAttrs(1, 10)[0]
+
+ setlocal cursorline
+
+ " underline
+ exe hi_ul
+
+ " expected:
+ " ' dcba'
+ " ^^^^ underline
+ " ^ 'Search' highlight with underline
+ " ^^^^^ underline
+ let attrs = ScreenAttrs(1, 10)[0]
+ call assert_equal(repeat([attrs[9]], 4), attrs[6:9])
+ call assert_equal(repeat([attrs[4]], 5) + [attrs[5]], attrs[0:5])
+ call assert_notequal(attrs[9], attrs[5])
+ call assert_notequal(attrs[4], attrs[5])
+ call assert_notequal(attrs0[9], attrs[9])
+ call assert_notequal(attrs0[5], attrs[5])
+ call Check_lcs_eol_attrs(attrs, 1, 10)
+
+ if IsColorable()
+ " bg-color
+ exe hi_bg
+
+ " expected:
+ " ' dcba'
+ " ^^^^ bg-color of 'CursorLine'
+ " ^ 'Search' highlight
+ " ^^^^^ bg-color of 'CursorLine'
+ let attrs = ScreenAttrs(1, 10)[0]
+ call assert_equal(repeat([attrs[9]], 4), attrs[6:9])
+ call assert_equal(repeat([attrs[4]], 5), attrs[0:4])
+ call assert_equal(attrs0[5], attrs[5])
+ call assert_notequal(attrs[9], attrs[5])
+ call assert_notequal(attrs[5], attrs[4])
+ call assert_notequal(attrs0[9], attrs[9])
+ call assert_notequal(attrs0[4], attrs[4])
+ call Check_lcs_eol_attrs(attrs, 1, 10)
+ endif
+
+ call CloseWindow()
+ exe hiCursorLine
+endfunc
+
+func Test_highlight_eol_with_cursorline_linewrap()
+ let [hiCursorLine, hi_ul, hi_bg] = HiCursorLine()
+
+ call NewWindow('topleft 5', 10)
+ call setline(1, [repeat('a', 51) . 'bcd', ''])
+ call matchadd('Search', '\n')
+
+ setlocal wrap
+ normal! gg$
+ let attrs0 = ScreenAttrs(5, 10)[0]
+ setlocal cursorline
+
+ " underline
+ exe hi_ul
+
+ " expected:
+ " 'abcd '
+ " ^^^^ underline
+ " ^ 'Search' highlight with underline
+ " ^^^^^ underline
+ let attrs = ScreenAttrs(5, 10)[0]
+ call assert_equal(repeat([attrs[0]], 4), attrs[0:3])
+ call assert_equal([attrs[4]] + repeat([attrs[5]], 5), attrs[4:9])
+ call assert_notequal(attrs[0], attrs[4])
+ call assert_notequal(attrs[4], attrs[5])
+ call assert_notequal(attrs0[0], attrs[0])
+ call assert_notequal(attrs0[4], attrs[4])
+ call Check_lcs_eol_attrs(attrs, 5, 10)
+
+ if IsColorable()
+ " bg-color
+ exe hi_bg
+
+ " expected:
+ " 'abcd '
+ " ^^^^ bg-color of 'CursorLine'
+ " ^ 'Search' highlight
+ " ^^^^^ bg-color of 'CursorLine'
+ let attrs = ScreenAttrs(5, 10)[0]
+ call assert_equal(repeat([attrs[0]], 4), attrs[0:3])
+ call assert_equal(repeat([attrs[5]], 5), attrs[5:9])
+ call assert_equal(attrs0[4], attrs[4])
+ call assert_notequal(attrs[0], attrs[4])
+ call assert_notequal(attrs[4], attrs[5])
+ call assert_notequal(attrs0[0], attrs[0])
+ call assert_notequal(attrs0[5], attrs[5])
+ call Check_lcs_eol_attrs(attrs, 5, 10)
+ endif
+
+ setlocal nocursorline nowrap
+ normal! gg$
+ let attrs0 = ScreenAttrs(1, 10)[0]
+ setlocal cursorline
+
+ " underline
+ exe hi_ul
+
+ " expected:
+ " 'aaabcd '
+ " ^^^^^^ underline
+ " ^ 'Search' highlight with underline
+ " ^^^ underline
+ let attrs = ScreenAttrs(1, 10)[0]
+ call assert_equal(repeat([attrs[0]], 6), attrs[0:5])
+ call assert_equal([attrs[6]] + repeat([attrs[7]], 3), attrs[6:9])
+ call assert_notequal(attrs[0], attrs[6])
+ call assert_notequal(attrs[6], attrs[7])
+ call assert_notequal(attrs0[0], attrs[0])
+ call assert_notequal(attrs0[6], attrs[6])
+ call Check_lcs_eol_attrs(attrs, 1, 10)
+
+ if IsColorable()
+ " bg-color
+ exe hi_bg
+
+ " expected:
+ " 'aaabcd '
+ " ^^^^^^ bg-color of 'CursorLine'
+ " ^ 'Search' highlight
+ " ^^^ bg-color of 'CursorLine'
+ let attrs = ScreenAttrs(1, 10)[0]
+ call assert_equal(repeat([attrs[0]], 6), attrs[0:5])
+ call assert_equal(repeat([attrs[7]], 3), attrs[7:9])
+ call assert_equal(attrs0[6], attrs[6])
+ call assert_notequal(attrs[0], attrs[6])
+ call assert_notequal(attrs[6], attrs[7])
+ call assert_notequal(attrs0[0], attrs[0])
+ call assert_notequal(attrs0[7], attrs[7])
+ call Check_lcs_eol_attrs(attrs, 1, 10)
+ endif
+
+ call CloseWindow()
+ exe hiCursorLine
+endfunc
+
+func Test_highlight_eol_with_cursorline_sign()
+ if !has('signs')
+ return
+ endif
+
+ let [hiCursorLine, hi_ul, hi_bg] = HiCursorLine()
+
+ call NewWindow('topleft 5', 10)
+ call setline(1, 'abcd')
+ call matchadd('Search', '\n')
+
+ sign define Sign text=>>
+ exe 'sign place 1 line=1 name=Sign buffer=' . bufnr('')
+ let attrs0 = ScreenAttrs(1, 10)[0]
+ setlocal cursorline
+
+ " underline
+ exe hi_ul
+
+ " expected:
+ " '>>abcd '
+ " ^^ sign
+ " ^^^^ underline
+ " ^ 'Search' highlight with underline
+ " ^^^ underline
+ let attrs = ScreenAttrs(1, 10)[0]
+ call assert_equal(repeat([attrs[2]], 4), attrs[2:5])
+ call assert_equal([attrs[6]] + repeat([attrs[7]], 3), attrs[6:9])
+ call assert_notequal(attrs[2], attrs[6])
+ call assert_notequal(attrs[6], attrs[7])
+ call assert_notequal(attrs0[2], attrs[2])
+ call assert_notequal(attrs0[6], attrs[6])
+ call Check_lcs_eol_attrs(attrs, 1, 10)
+
+ if IsColorable()
+ " bg-color
+ exe hi_bg
+
+ " expected:
+ " '>>abcd '
+ " ^^ sign
+ " ^^^^ bg-color of 'CursorLine'
+ " ^ 'Search' highlight
+ " ^^^ bg-color of 'CursorLine'
+ let attrs = ScreenAttrs(1, 10)[0]
+ call assert_equal(repeat([attrs[2]], 4), attrs[2:5])
+ call assert_equal(repeat([attrs[7]], 3), attrs[7:9])
+ call assert_equal(attrs0[6], attrs[6])
+ call assert_notequal(attrs[2], attrs[6])
+ call assert_notequal(attrs[6], attrs[7])
+ call assert_notequal(attrs0[2], attrs[2])
+ call assert_notequal(attrs0[7], attrs[7])
+ call Check_lcs_eol_attrs(attrs, 1, 10)
+ endif
+
+ sign unplace 1
+ call CloseWindow()
+ exe hiCursorLine
+endfunc
+
+func Test_highlight_eol_with_cursorline_breakindent()
+ if !has('linebreak')
+ return
+ endif
+
+ let [hiCursorLine, hi_ul, hi_bg] = HiCursorLine()
+
+ call NewWindow('topleft 5', 10)
+ setlocal breakindent breakindentopt=min:0,shift:1 showbreak=>
+ call setline(1, ' ' . repeat('a', 9) . 'bcd')
+ call matchadd('Search', '\n')
+ let attrs0 = ScreenAttrs(2, 10)[0]
+ setlocal cursorline
+
+ " underline
+ exe hi_ul
+
+ " expected:
+ " ' >bcd '
+ " ^^^ breakindent and showbreak
+ " ^^^ underline
+ " ^ 'Search' highlight with underline
+ " ^^^ underline
+ let attrs = ScreenAttrs(2, 10)[0]
+ call assert_equal(repeat([attrs[0]], 2), attrs[0:1])
+ call assert_equal(repeat([attrs[3]], 3), attrs[3:5])
+ call assert_equal([attrs[6]] + repeat([attrs[7]], 3), attrs[6:9])
+ call assert_equal(attrs0[0], attrs[0])
+ call assert_notequal(attrs[0], attrs[2])
+ call assert_notequal(attrs[2], attrs[3])
+ call assert_notequal(attrs[3], attrs[6])
+ call assert_notequal(attrs[6], attrs[7])
+ call assert_notequal(attrs0[2], attrs[2])
+ call assert_notequal(attrs0[3], attrs[3])
+ call assert_notequal(attrs0[6], attrs[6])
+ call Check_lcs_eol_attrs(attrs, 2, 10)
+
+ if IsColorable()
+ " bg-color
+ exe hi_bg
+
+ " expected:
+ " ' >bcd '
+ " ^^^ breakindent and showbreak
+ " ^^^ bg-color of 'CursorLine'
+ " ^ 'Search' highlight
+ " ^^^ bg-color of 'CursorLine'
+ let attrs = ScreenAttrs(2, 10)[0]
+ call assert_equal(repeat([attrs[0]], 2), attrs[0:1])
+ call assert_equal(repeat([attrs[3]], 3), attrs[3:5])
+ call assert_equal(repeat([attrs[7]], 3), attrs[7:9])
+ call assert_equal(attrs0[0], attrs[0])
+ call assert_equal(attrs0[6], attrs[6])
+ call assert_notequal(attrs[0], attrs[2])
+ call assert_notequal(attrs[2], attrs[3])
+ call assert_notequal(attrs[3], attrs[6])
+ call assert_notequal(attrs[6], attrs[7])
+ call assert_notequal(attrs0[2], attrs[2])
+ call assert_notequal(attrs0[3], attrs[3])
+ call assert_notequal(attrs0[7], attrs[7])
+ call Check_lcs_eol_attrs(attrs, 2, 10)
+ endif
+
+ call CloseWindow()
+ set showbreak=
+ exe hiCursorLine
+endfunc
+
+func Test_highlight_eol_on_diff()
+ call setline(1, ['abcd', ''])
+ call matchadd('Search', '\n')
+ let attrs0 = ScreenAttrs(1, 10)[0]
+
+ diffthis
+ botright new
+ diffthis
+
+ " expected:
+ " ' abcd '
+ " ^^ sign
+ " ^^^^ ^^^ 'DiffAdd' highlight
+ " ^ 'Search' highlight
+ let attrs = ScreenAttrs(1, 10)[0]
+ call assert_equal(repeat([attrs[0]], 2), attrs[0:1])
+ call assert_equal(repeat([attrs[2]], 4), attrs[2:5])
+ call assert_equal(repeat([attrs[2]], 3), attrs[7:9])
+ call assert_equal(attrs0[4], attrs[6])
+ call assert_notequal(attrs[0], attrs[2])
+ call assert_notequal(attrs[0], attrs[6])
+ call assert_notequal(attrs[2], attrs[6])
+ call Check_lcs_eol_attrs(attrs, 1, 10)
+
+ bwipe!
+ diffoff
+endfunc
+
+func Test_termguicolors()
+ if !exists('+termguicolors')
+ return
+ endif
+ if has('vtp') && !has('vcon')
+ " Win32: 'guicolors' doesn't work without virtual console.
+ call assert_fails('set termguicolors', 'E954:')
+ return
+ endif
+
+ " Basic test that setting 'termguicolors' works with one color.
+ set termguicolors
+ redraw
+ set t_Co=1
+ redraw
+ set t_Co=0
+ redraw
+endfunc
+
+func Test_cursorline_after_yank()
+ if !CanRunVimInTerminal()
+ return
+ endif
+
+ call writefile([
+ \ 'set cul rnu',
+ \ 'call setline(1, ["","1","2","3",""])',
+ \ ], 'Xtest_cursorline_yank')
+ let buf = RunVimInTerminal('-S Xtest_cursorline_yank', {'rows': 8})
+ call term_wait(buf)
+ call term_sendkeys(buf, "Gy3k")
+ call term_wait(buf)
+ call term_sendkeys(buf, "jj")
+
+ call VerifyScreenDump(buf, 'Test_cursorline_yank_01', {})
+
+ " clean up
+ call StopVimInTerminal(buf)
+ call delete('Xtest_cursorline_yank')
+endfunc
diff --git a/src/testdir/test_history.vim b/src/testdir/test_history.vim
new file mode 100644
index 0000000..16aad98
--- /dev/null
+++ b/src/testdir/test_history.vim
@@ -0,0 +1,111 @@
+" Tests for the history functions
+
+if !has('cmdline_hist')
+ finish
+endif
+
+set history=7
+
+function History_Tests(hist)
+ " First clear the history
+ call histadd(a:hist, 'dummy')
+ call assert_true(histdel(a:hist))
+ call assert_equal(-1, histnr(a:hist))
+ call assert_equal('', histget(a:hist))
+
+ call assert_true(histadd(a:hist, 'ls'))
+ call assert_true(histadd(a:hist, 'buffers'))
+ call assert_equal('buffers', histget(a:hist))
+ call assert_equal('ls', histget(a:hist, -2))
+ call assert_equal('ls', histget(a:hist, 1))
+ call assert_equal('', histget(a:hist, 5))
+ call assert_equal('', histget(a:hist, -5))
+ call assert_equal(2, histnr(a:hist))
+ call assert_true(histdel(a:hist, 2))
+ call assert_false(histdel(a:hist, 7))
+ call assert_equal(1, histnr(a:hist))
+ call assert_equal('ls', histget(a:hist, -1))
+
+ call assert_true(histadd(a:hist, 'buffers'))
+ call assert_true(histadd(a:hist, 'ls'))
+ call assert_equal('ls', histget(a:hist, -1))
+ call assert_equal(4, histnr(a:hist))
+
+ let a=execute('history ' . a:hist)
+ call assert_match("^\n # \\S* history\n 3 buffers\n> 4 ls$", a)
+ let a=execute('history all')
+ call assert_match("^\n # .* history\n 3 buffers\n> 4 ls", a)
+
+ if len(a:hist) > 0
+ let a=execute('history ' . a:hist . ' 2')
+ call assert_match("^\n # \\S* history$", a)
+ let a=execute('history ' . a:hist . ' 3')
+ call assert_match("^\n # \\S* history\n 3 buffers$", a)
+ let a=execute('history ' . a:hist . ' 4')
+ call assert_match("^\n # \\S* history\n> 4 ls$", a)
+ let a=execute('history ' . a:hist . ' 3,4')
+ call assert_match("^\n # \\S* history\n 3 buffers\n> 4 ls$", a)
+ let a=execute('history ' . a:hist . ' -1')
+ call assert_match("^\n # \\S* history\n> 4 ls$", a)
+ let a=execute('history ' . a:hist . ' -2')
+ call assert_match("^\n # \\S* history\n 3 buffers$", a)
+ let a=execute('history ' . a:hist . ' -2,')
+ call assert_match("^\n # \\S* history\n 3 buffers\n> 4 ls$", a)
+ let a=execute('history ' . a:hist . ' -3')
+ call assert_match("^\n # \\S* history$", a)
+ endif
+
+ " Test for removing entries matching a pattern
+ for i in range(1, 3)
+ call histadd(a:hist, 'text_' . i)
+ endfor
+ call assert_true(histdel(a:hist, 'text_\d\+'))
+ call assert_equal('ls', histget(a:hist, -1))
+
+ " Test for freeing the entire history list
+ for i in range(1, 7)
+ call histadd(a:hist, 'text_' . i)
+ endfor
+ call histdel(a:hist)
+ for i in range(1, 7)
+ call assert_equal('', histget(a:hist, i))
+ call assert_equal('', histget(a:hist, i - 7 - 1))
+ endfor
+endfunction
+
+function Test_History()
+ for h in ['cmd', ':', '', 'search', '/', '?', 'expr', '=', 'input', '@', 'debug', '>']
+ call History_Tests(h)
+ endfor
+
+ " Negative tests
+ call assert_false(histdel('abc'))
+ call assert_equal('', histget('abc'))
+ call assert_fails('call histdel([])', 'E730:')
+ call assert_equal('', histget(10))
+ call assert_fails('call histget([])', 'E730:')
+ call assert_equal(-1, histnr('abc'))
+ call assert_fails('call histnr([])', 'E730:')
+endfunction
+
+function Test_Search_history_window()
+ new
+ call setline(1, ['a', 'b', 'a', 'b'])
+ 1
+ call feedkeys("/a\<CR>", 'xt')
+ call assert_equal('a', getline('.'))
+ 1
+ call feedkeys("/b\<CR>", 'xt')
+ call assert_equal('b', getline('.'))
+ 1
+ " select the previous /a command
+ call feedkeys("q/kk\<CR>", 'x!')
+ call assert_equal('a', getline('.'))
+ call assert_equal('a', @/)
+ bwipe!
+endfunc
+
+function Test_history_completion()
+ call feedkeys(":history \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"history / : = > ? @ all cmd debug expr input search', @:)
+endfunc
diff --git a/src/testdir/test_hlsearch.vim b/src/testdir/test_hlsearch.vim
new file mode 100644
index 0000000..d4db4b7
--- /dev/null
+++ b/src/testdir/test_hlsearch.vim
@@ -0,0 +1,65 @@
+" Test for v:hlsearch
+
+func Test_hlsearch()
+ new
+ call setline(1, repeat(['aaa'], 10))
+ set hlsearch nolazyredraw
+ " redraw is needed to make hlsearch highlight the matches
+ exe "normal! /aaa\<CR>" | redraw
+ let r1 = screenattr(1, 1)
+ nohlsearch | redraw
+ call assert_notequal(r1, screenattr(1,1))
+ let v:hlsearch=1 | redraw
+ call assert_equal(r1, screenattr(1,1))
+ let v:hlsearch=0 | redraw
+ call assert_notequal(r1, screenattr(1,1))
+ set hlsearch | redraw
+ call assert_equal(r1, screenattr(1,1))
+ let v:hlsearch=0 | redraw
+ call assert_notequal(r1, screenattr(1,1))
+ exe "normal! n" | redraw
+ call assert_equal(r1, screenattr(1,1))
+ let v:hlsearch=0 | redraw
+ call assert_notequal(r1, screenattr(1,1))
+ exe "normal! /\<CR>" | redraw
+ call assert_equal(r1, screenattr(1,1))
+ set nohls
+ exe "normal! /\<CR>" | redraw
+ call assert_notequal(r1, screenattr(1,1))
+ call assert_fails('let v:hlsearch=[]', 'E745')
+ call garbagecollect(1)
+ call getchar(1)
+ enew!
+endfunc
+
+func Test_hlsearch_hangs()
+ if !has('reltime') || !has('float')
+ return
+ endif
+
+ " This pattern takes a long time to match, it should timeout.
+ new
+ call setline(1, ['aaa', repeat('abc ', 1000), 'ccc'])
+ let start = reltime()
+ set hlsearch nolazyredraw redrawtime=101
+ let @/ = '\%#=1a*.*X\@<=b*'
+ redraw
+ let elapsed = reltimefloat(reltime(start))
+ call assert_true(elapsed > 0.1)
+ call assert_true(elapsed < 1.0)
+ set nohlsearch redrawtime&
+ bwipe!
+endfunc
+
+func Test_hlsearch_eol_highlight()
+ new
+ call append(1, repeat([''], 9))
+ set hlsearch nolazyredraw
+ exe "normal! /$\<CR>" | redraw
+ let attr = screenattr(1, 1)
+ for row in range(2, 10)
+ call assert_equal(attr, screenattr(row, 1), 'in line ' . row)
+ endfor
+ set nohlsearch
+ bwipe!
+endfunc
diff --git a/src/testdir/test_iminsert.vim b/src/testdir/test_iminsert.vim
new file mode 100644
index 0000000..1a8e4c8
--- /dev/null
+++ b/src/testdir/test_iminsert.vim
@@ -0,0 +1,27 @@
+source view_util.vim
+
+let s:imactivatefunc_called = 0
+let s:imstatusfunc_called = 0
+
+func IM_activatefunc(active)
+ let s:imactivatefunc_called = 1
+endfunc
+
+func IM_statusfunc()
+ let s:imstatusfunc_called = 1
+ return 0
+endfunc
+
+func Test_iminsert2()
+ set imactivatefunc=IM_activatefunc
+ set imstatusfunc=IM_statusfunc
+ set iminsert=2
+ normal! i
+ set iminsert=0
+ set imactivatefunc=
+ set imstatusfunc=
+
+ let expected = has('gui_running') ? 0 : 1
+ call assert_equal(expected, s:imactivatefunc_called)
+ call assert_equal(expected, s:imstatusfunc_called)
+endfunc
diff --git a/src/testdir/test_increment.vim b/src/testdir/test_increment.vim
new file mode 100644
index 0000000..ad355dc
--- /dev/null
+++ b/src/testdir/test_increment.vim
@@ -0,0 +1,781 @@
+" Tests for using Ctrl-A/Ctrl-X on visual selections
+
+func SetUp()
+ new dummy
+ set nrformats&vim
+endfunc
+
+func TearDown()
+ bwipe!
+endfunc
+
+" 1) Ctrl-A on visually selected number
+" Text:
+" foobar-10
+" Expected:
+" 1) Ctrl-A on start of line:
+" foobar-9
+" 2) Ctrl-A on visually selected "-10":
+" foobar-9
+" 3) Ctrl-A on visually selected "10":
+" foobar-11
+" 4) Ctrl-X on visually selected "-10"
+" foobar-11
+" 5) Ctrl-X on visually selected "10"
+" foobar-9
+func Test_visual_increment_01()
+ call setline(1, repeat(["foobaar-10"], 5))
+
+ call cursor(1, 1)
+ exec "norm! \<C-A>"
+ call assert_equal("foobaar-9", getline('.'))
+ call assert_equal([0, 1, 9, 0], getpos('.'))
+
+ call cursor(2, 1)
+ exec "norm! f-v$\<C-A>"
+ call assert_equal("foobaar-9", getline('.'))
+ call assert_equal([0, 2, 8, 0], getpos('.'))
+
+ call cursor(3, 1)
+ exec "norm! f1v$\<C-A>"
+ call assert_equal("foobaar-11", getline('.'))
+ call assert_equal([0, 3, 9, 0], getpos('.'))
+
+ call cursor(4, 1)
+ exec "norm! f-v$\<C-X>"
+ call assert_equal("foobaar-11", getline('.'))
+ call assert_equal([0, 4, 8, 0], getpos('.'))
+
+ call cursor(5, 1)
+ exec "norm! f1v$\<C-X>"
+ call assert_equal("foobaar-9", getline('.'))
+ call assert_equal([0, 5, 9, 0], getpos('.'))
+endfunc
+
+" 2) Ctrl-A on visually selected lines
+" Text:
+" 10
+" 20
+" 30
+" 40
+"
+" Expected:
+" 1) Ctrl-A on visually selected lines:
+" 11
+" 21
+" 31
+" 41
+"
+" 2) Ctrl-X on visually selected lines:
+" 9
+" 19
+" 29
+" 39
+func Test_visual_increment_02()
+ call setline(1, ["10", "20", "30", "40"])
+ exec "norm! GV3k$\<C-A>"
+ call assert_equal(["11", "21", "31", "41"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+
+ call setline(1, ["10", "20", "30", "40"])
+ exec "norm! GV3k$\<C-X>"
+ call assert_equal(["9", "19", "29", "39"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+endfunc
+
+" 3) g Ctrl-A on visually selected lines, with non-numbers in between
+" Text:
+" 10
+"
+" 20
+"
+" 30
+"
+" 40
+"
+" Expected:
+" 1) 2 g Ctrl-A on visually selected lines:
+" 12
+"
+" 24
+"
+" 36
+"
+" 48
+" 2) 2 g Ctrl-X on visually selected lines
+" 8
+"
+" 16
+"
+" 24
+"
+" 32
+func Test_visual_increment_03()
+ call setline(1, ["10", "", "20", "", "30", "", "40"])
+ exec "norm! GV6k2g\<C-A>"
+ call assert_equal(["12", "", "24", "", "36", "", "48"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+
+ call setline(1, ["10", "", "20", "", "30", "", "40"])
+ exec "norm! GV6k2g\<C-X>"
+ call assert_equal(["8", "", "16", "", "24", "", "32"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+endfunc
+
+" 4) Ctrl-A on non-number
+" Text:
+" foobar-10
+" Expected:
+" 1) visually select foobar:
+" foobar-10
+func Test_visual_increment_04()
+ call setline(1, ["foobar-10"])
+ exec "norm! vf-\<C-A>"
+ call assert_equal(["foobar-10"], getline(1, '$'))
+ " NOTE: I think this is correct behavior...
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+endfunc
+
+" 5) g<Ctrl-A> on letter
+" Test:
+" a
+" a
+" a
+" a
+" Expected:
+" 1) g Ctrl-A on visually selected lines
+" b
+" c
+" d
+" e
+func Test_visual_increment_05()
+ set nrformats+=alpha
+ call setline(1, repeat(["a"], 4))
+ exec "norm! GV3kg\<C-A>"
+ call assert_equal(["b", "c", "d", "e"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+endfunc
+
+" 6) g<Ctrl-A> on letter
+" Test:
+" z
+" z
+" z
+" z
+" Expected:
+" 1) g Ctrl-X on visually selected lines
+" y
+" x
+" w
+" v
+func Test_visual_increment_06()
+ set nrformats+=alpha
+ call setline(1, repeat(["z"], 4))
+ exec "norm! GV3kg\<C-X>"
+ call assert_equal(["y", "x", "w", "v"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+endfunc
+
+" 7) <Ctrl-A> on letter
+" Test:
+" 2
+" 1
+" 0
+" -1
+" -2
+"
+" Expected:
+" 1) Ctrl-A on visually selected lines
+" 3
+" 2
+" 1
+" 0
+" -1
+"
+" 2) Ctrl-X on visually selected lines
+" 1
+" 0
+" -1
+" -2
+" -3
+func Test_visual_increment_07()
+ call setline(1, ["2", "1", "0", "-1", "-2"])
+ exec "norm! GV4k\<C-A>"
+ call assert_equal(["3", "2", "1", "0", "-1"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+
+ call setline(1, ["2", "1", "0", "-1", "-2"])
+ exec "norm! GV4k\<C-X>"
+ call assert_equal(["1", "0", "-1", "-2", "-3"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+endfunc
+
+" 8) Block increment on 0x9
+" Text:
+" 0x9
+" 0x9
+" Expected:
+" 1) Ctrl-A on visually block selected region (cursor at beginning):
+" 0xa
+" 0xa
+" 2) Ctrl-A on visually block selected region (cursor at end)
+" 0xa
+" 0xa
+func Test_visual_increment_08()
+ call setline(1, repeat(["0x9"], 2))
+ exec "norm! \<C-V>j$\<C-A>"
+ call assert_equal(["0xa", "0xa"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+
+ call setline(1, repeat(["0x9"], 2))
+ exec "norm! gg$\<C-V>+\<C-A>"
+ call assert_equal(["0xa", "0xa"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+endfunc
+
+" 9) Increment and redo
+" Text:
+" 2
+" 2
+"
+" 3
+" 3
+"
+" Expected:
+" 1) 2 Ctrl-A on first 2 visually selected lines
+" 4
+" 4
+" 2) redo (.) on 3
+" 5
+" 5
+func Test_visual_increment_09()
+ call setline(1, ["2", "2", "", "3", "3", ""])
+ exec "norm! ggVj2\<C-A>"
+ call assert_equal(["4", "4", "", "3", "3", ""], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+
+ exec "norm! 3j."
+ call assert_equal(["4", "4", "", "5", "5", ""], getline(1, '$'))
+ call assert_equal([0, 4, 1, 0], getpos('.'))
+endfunc
+
+" 10) sequentially decrement 1
+" Text:
+" 1
+" 1
+" 1
+" 1
+" Expected:
+" 1) g Ctrl-X on visually selected lines
+" 0
+" -1
+" -2
+" -3
+func Test_visual_increment_10()
+ call setline(1, repeat(["1"], 4))
+ exec "norm! GV3kg\<C-X>"
+ call assert_equal(["0", "-1", "-2", "-3"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+endfunc
+
+" 11) visually block selected indented lines
+" Text:
+" 1
+" 1
+" 1
+" 1
+" Expexted:
+" 1) g Ctrl-A on block selected indented lines
+" 2
+" 1
+" 3
+" 4
+func Test_visual_increment_11()
+ call setline(1, [" 1", "1", " 1", " 1"])
+ exec "norm! f1\<C-V>3jg\<C-A>"
+ call assert_equal([" 2", "1", " 3", " 4"], getline(1, '$'))
+ call assert_equal([0, 1, 5, 0], getpos('.'))
+endfunc
+
+" 12) visually selected several columns
+" Text:
+" 0 0
+" 0 0
+" 0 0
+" Expected:
+" 1) 'v' select last zero and first zeroes
+" 0 1
+" 1 0
+" 1 0
+func Test_visual_increment_12()
+ call setline(1, repeat(["0 0"], 3))
+ exec "norm! $v++\<C-A>"
+ call assert_equal(["0 1", "1 0", "1 0"], getline(1, '$'))
+ call assert_equal([0, 1, 3, 0], getpos('.'))
+endfunc
+
+" 13) visually selected part of columns
+" Text:
+" max: 100px
+" max: 200px
+" max: 300px
+" max: 400px
+" Expected:
+" 1) 'v' on first two numbers Ctrl-A
+" max: 110px
+" max: 220px
+" max: 330px
+" max: 400px
+" 2) 'v' on first two numbers Ctrl-X
+" max: 90px
+" max: 190px
+" max: 290px
+" max: 400px
+func Test_visual_increment_13()
+ call setline(1, ["max: 100px", "max: 200px", "max: 300px", "max: 400px"])
+ exec "norm! f1\<C-V>l2j\<C-A>"
+ call assert_equal(["max: 110px", "max: 210px", "max: 310px", "max: 400px"], getline(1, '$'))
+ call assert_equal([0, 1, 6, 0], getpos('.'))
+
+ call setline(1, ["max: 100px", "max: 200px", "max: 300px", "max: 400px"])
+ exec "norm! ggf1\<C-V>l2j\<C-X>"
+ call assert_equal(["max: 90px", "max: 190px", "max: 290px", "max: 400px"], getline(1, '$'))
+ call assert_equal([0, 1, 6, 0], getpos('.'))
+endfunc
+
+" 14) redo in block mode
+" Text:
+" 1 1
+" 1 1
+" Expected:
+" 1) Ctrl-a on first column, redo on second column
+" 2 2
+" 2 2
+func Test_visual_increment_14()
+ call setline(1, repeat(["1 1"], 2))
+ exec "norm! G\<C-V>k\<C-A>w."
+ call assert_equal(["2 2", "2 2"], getline(1, '$'))
+ call assert_equal([0, 1, 3, 0], getpos('.'))
+endfunc
+
+" 15) block select single numbers
+" Text:
+" 101
+" Expected:
+" 1) Ctrl-a on visually selected zero
+" 111
+"
+" Also: 019 with "01" selected increments to "029".
+func Test_visual_increment_15()
+ call setline(1, ["101"])
+ exec "norm! lv\<C-A>"
+ call assert_equal(["111"], getline(1, '$'))
+ call assert_equal([0, 1, 2, 0], getpos('.'))
+
+ call setline(1, ["019"])
+ exec "norm! 0vl\<C-A>"
+ call assert_equal("029", getline(1))
+
+ call setline(1, ["01239"])
+ exec "norm! 0vlll\<C-A>"
+ call assert_equal("01249", getline(1))
+
+ call setline(1, ["01299"])
+ exec "norm! 0vlll\<C-A>"
+ call assert_equal("1309", getline(1))
+endfunc
+
+" 16) increment right aligned numbers
+" Text:
+" 1
+" 19
+" 119
+" Expected:
+" 1) Ctrl-a on line selected region
+" 2
+" 20
+" 120
+func Test_visual_increment_16()
+ call setline(1, [" 1", " 19", " 119"])
+ exec "norm! VG\<C-A>"
+ call assert_equal([" 2", " 20", " 120"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+endfunc
+
+" 17) block-wise increment and redo
+" Text:
+" 100
+" 1
+"
+" 100
+" 1
+"
+" Expected:
+" 1) Ctrl-V j $ on first block, afterwards '.' on second
+" 101
+" 2
+"
+" 101
+" 2
+func Test_visual_increment_17()
+ call setline(1, [" 100", " 1", "", " 100", " 1"])
+ exec "norm! \<C-V>j$\<C-A>2j."
+ call assert_equal([" 101", " 2", "", " 101", " 1"], getline(1, '$'))
+ call assert_equal([0, 3, 1, 0], getpos('.'))
+endfunc
+
+" 18) repeat of g<Ctrl-a>
+" Text:
+" 0
+" 0
+" 0
+" 0
+"
+" Expected:
+" 1) V 4j g<ctrl-a>, repeat twice afterwards with .
+" 3
+" 6
+" 9
+" 12
+func Test_visual_increment_18()
+ call setline(1, repeat(["0"], 4))
+ exec "norm! GV3kg\<C-A>"
+ exec "norm! .."
+ call assert_equal(["3", "6", "9", "12"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+endfunc
+
+" 19) increment on number with nrformat including alpha
+" Text:
+" 1
+" 1a
+"
+" Expected:
+" 1) <Ctrl-V>j$ <ctrl-a>
+" 2
+" 2a
+func Test_visual_increment_19()
+ set nrformats+=alpha
+ call setline(1, ["1", "1a"])
+ exec "norm! \<C-V>G$\<C-A>"
+ call assert_equal(["2", "2a"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+endfunc
+
+" 20) increment a single letter
+" Text:
+" a
+"
+" Expected:
+" 1) <Ctrl-a> and cursor is on a
+" b
+func Test_visual_increment_20()
+ set nrformats+=alpha
+ call setline(1, ["a"])
+ exec "norm! \<C-A>"
+ call assert_equal(["b"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+endfunc
+
+" 21) block-wise increment on part of hexadecimal
+" Text:
+" 0x123456
+"
+" Expected:
+" 1) Ctrl-V f3 <ctrl-a>
+" 0x124456
+func Test_visual_increment_21()
+ call setline(1, ["0x123456"])
+ exec "norm! \<C-V>f3\<C-A>"
+ call assert_equal(["0x124456"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+endfunc
+
+" 22) Block increment on 0b0
+" Text:
+" 0b1
+" 0b1
+" Expected:
+" 1) Ctrl-A on visually block selected region (cursor at beginning):
+" 0b10
+" 0b10
+" 2) Ctrl-A on visually block selected region (cursor at end)
+" 0b10
+" 0b10
+func Test_visual_increment_22()
+ call setline(1, repeat(["0b1"], 2))
+ exec "norm! \<C-V>j$\<C-A>"
+ call assert_equal(repeat(["0b10"], 2), getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+
+ call setline(1, repeat(["0b1"], 2))
+ exec "norm! $\<C-V>+\<C-A>"
+ call assert_equal(repeat(["0b10"], 2), getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+endfunc
+
+" 23) block-wise increment on part of binary
+" Text:
+" 0b1001
+"
+" Expected:
+" 1) Ctrl-V 5l <ctrl-a>
+" 0b1011
+func Test_visual_increment_23()
+ call setline(1, ["0b1001"])
+ exec "norm! \<C-V>4l\<C-A>"
+ call assert_equal(["0b1011"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+endfunc
+
+" 24) increment hexadecimal
+" Text:
+" 0x0b1001
+"
+" Expected:
+" 1) <ctrl-a>
+" 0x0b1002
+func Test_visual_increment_24()
+ call setline(1, ["0x0b1001"])
+ exec "norm! \<C-V>$\<C-A>"
+ call assert_equal(["0x0b1002"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+endfunc
+
+" 25) increment binary with nrformats including alpha
+" Text:
+" 0b1001a
+"
+" Expected:
+" 1) <ctrl-a>
+" 0b1010a
+func Test_visual_increment_25()
+ set nrformats+=alpha
+ call setline(1, ["0b1001a"])
+ exec "norm! \<C-V>$\<C-A>"
+ call assert_equal(["0b1010a"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+endfunc
+
+" 26) increment binary with 32 bits
+" Text:
+" 0b11111111111111111111111111111110
+"
+" Expected:
+" 1) <ctrl-a>
+" 0b11111111111111111111111111111111
+func Test_visual_increment_26()
+ set nrformats+=alpha
+ call setline(1, ["0b11111111111111111111111111111110"])
+ exec "norm! \<C-V>$\<C-A>"
+ call assert_equal(["0b11111111111111111111111111111111"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+ set nrformats-=alpha
+endfunc
+
+" 27) increment with 'rightreft', if supported
+func Test_visual_increment_27()
+ if exists('+rightleft')
+ set rightleft
+ call setline(1, ["1234 56"])
+
+ exec "norm! $\<C-A>"
+ call assert_equal(["1234 57"], getline(1, '$'))
+ call assert_equal([0, 1, 7, 0], getpos('.'))
+
+ exec "norm! \<C-A>"
+ call assert_equal(["1234 58"], getline(1, '$'))
+ call assert_equal([0, 1, 7, 0], getpos('.'))
+ set norightleft
+ endif
+endfunc
+
+" Tab code and linewise-visual inc/dec
+func Test_visual_increment_28()
+ call setline(1, ["x\<TAB>10", "\<TAB>-1"])
+ exec "norm! Vj\<C-A>"
+ call assert_equal(["x\<TAB>11", "\<TAB>0"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+
+ call setline(1, ["x\<TAB>10", "\<TAB>-1"])
+ exec "norm! ggVj\<C-X>"
+ call assert_equal(["x\<TAB>9", "\<TAB>-2"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+endfunc
+
+" Tab code and linewise-visual inc/dec with 'nrformats'+=alpha
+func Test_visual_increment_29()
+ set nrformats+=alpha
+ call setline(1, ["x\<TAB>10", "\<TAB>-1"])
+ exec "norm! Vj\<C-A>"
+ call assert_equal(["y\<TAB>10", "\<TAB>0"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+
+ call setline(1, ["x\<TAB>10", "\<TAB>-1"])
+ exec "norm! ggVj\<C-X>"
+ call assert_equal(["w\<TAB>10", "\<TAB>-2"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+endfunc
+
+" Tab code and character-visual inc/dec
+func Test_visual_increment_30()
+ call setline(1, ["x\<TAB>10", "\<TAB>-1"])
+ exec "norm! f1vjf1\<C-A>"
+ call assert_equal(["x\<TAB>11", "\<TAB>0"], getline(1, '$'))
+ call assert_equal([0, 1, 3, 0], getpos('.'))
+
+ call setline(1, ["x\<TAB>10", "\<TAB>-1"])
+ exec "norm! ggf1vjf1\<C-X>"
+ call assert_equal(["x\<TAB>9", "\<TAB>-2"], getline(1, '$'))
+ call assert_equal([0, 1, 3, 0], getpos('.'))
+endfunc
+
+" Tab code and blockwise-visual inc/dec
+func Test_visual_increment_31()
+ call setline(1, ["x\<TAB>10", "\<TAB>-1"])
+ exec "norm! f1\<C-V>jl\<C-A>"
+ call assert_equal(["x\<TAB>11", "\<TAB>0"], getline(1, '$'))
+ call assert_equal([0, 1, 3, 0], getpos('.'))
+
+ call setline(1, ["x\<TAB>10", "\<TAB>-1"])
+ exec "norm! ggf1\<C-V>jl\<C-X>"
+ call assert_equal(["x\<TAB>9", "\<TAB>-2"], getline(1, '$'))
+ call assert_equal([0, 1, 3, 0], getpos('.'))
+endfunc
+
+" Tab code and blockwise-visual decrement with 'linebreak' and 'showbreak'
+func Test_visual_increment_32()
+ 28vnew dummy_31
+ set linebreak showbreak=+
+ call setline(1, ["x\<TAB>\<TAB>\<TAB>10", "\<TAB>\<TAB>\<TAB>\<TAB>-1"])
+ exec "norm! ggf0\<C-V>jg_\<C-X>"
+ call assert_equal(["x\<TAB>\<TAB>\<TAB>1-1", "\<TAB>\<TAB>\<TAB>\<TAB>-2"], getline(1, '$'))
+ call assert_equal([0, 1, 6, 0], getpos('.'))
+ bwipe!
+endfunc
+
+" Tab code and blockwise-visual increment with $
+func Test_visual_increment_33()
+ call setline(1, ["\<TAB>123", "456"])
+ exec "norm! gg0\<C-V>j$\<C-A>"
+ call assert_equal(["\<TAB>124", "457"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+endfunc
+
+" Tab code and blockwise-visual increment and redo
+func Test_visual_increment_34()
+ call setline(1, ["\<TAB>123", " 456789"])
+ exec "norm! gg0\<C-V>j\<C-A>"
+ call assert_equal(["\<TAB>123", " 457789"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+
+ exec "norm! .."
+ call assert_equal(["\<TAB>123", " 459789"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+endfunc
+
+" Tab code, spaces and character-visual increment and redo
+func Test_visual_increment_35()
+ call setline(1, ["\<TAB>123", " 123", "\<TAB>123", "\<TAB>123"])
+ exec "norm! ggvjf3\<C-A>..."
+ call assert_equal(["\<TAB>127", " 127", "\<TAB>123", "\<TAB>123"], getline(1, '$'))
+ call assert_equal([0, 1, 2, 0], getpos('.'))
+endfunc
+
+" Tab code, spaces and blockwise-visual increment and redo
+func Test_visual_increment_36()
+ call setline(1, [" 123", "\<TAB>456789"])
+ exec "norm! G0\<C-V>kl\<C-A>"
+ call assert_equal([" 123", "\<TAB>556789"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+
+ exec "norm! ..."
+ call assert_equal([" 123", "\<TAB>856789"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+endfunc
+
+" block-wise increment and dot-repeat
+" Text:
+" 1 23
+" 4 56
+"
+" Expected:
+" 1) f2 Ctrl-V jl <ctrl-a>, repeat twice afterwards with .
+" 1 26
+" 4 59
+"
+" Try with and without indent.
+func Test_visual_increment_37()
+ call setline(1, [" 1 23", " 4 56"])
+ exec "norm! ggf2\<C-V>jl\<C-A>.."
+ call assert_equal([" 1 26", " 4 59"], getline(1, 2))
+
+ call setline(1, ["1 23", "4 56"])
+ exec "norm! ggf2\<C-V>jl\<C-A>.."
+ call assert_equal(["1 26", "4 59"], getline(1, 2))
+endfunc
+
+" Check redo after the normal mode increment
+func Test_visual_increment_38()
+ exec "norm! i10\<ESC>5\<C-A>."
+ call assert_equal(["20"], getline(1, '$'))
+ call assert_equal([0, 1, 2, 0], getpos('.'))
+endfunc
+
+" Test what patch 7.3.414 fixed. Ctrl-A on "000" drops the leading zeros.
+func Test_normal_increment_01()
+ call setline(1, "000")
+ exec "norm! gg0\<C-A>"
+ call assert_equal("001", getline(1))
+
+ call setline(1, "000")
+ exec "norm! gg$\<C-A>"
+ call assert_equal("001", getline(1))
+
+ call setline(1, "001")
+ exec "norm! gg0\<C-A>"
+ call assert_equal("002", getline(1))
+
+ call setline(1, "001")
+ exec "norm! gg$\<C-A>"
+ call assert_equal("002", getline(1))
+endfunc
+
+" Test a regression of patch 7.4.1087 fixed.
+func Test_normal_increment_02()
+ call setline(1, ["hello 10", "world"])
+ exec "norm! ggl\<C-A>jx"
+ call assert_equal(["hello 11", "worl"], getline(1, '$'))
+ call assert_equal([0, 2, 4, 0], getpos('.'))
+endfunc
+
+" The test35 unified to this file.
+func Test_normal_increment_03()
+ call setline(1, ["100 0x100 077 0",
+ \ "100 0x100 077 ",
+ \ "100 0x100 077 0xfF 0xFf",
+ \ "100 0x100 077 "])
+ set nrformats=octal,hex
+ exec "norm! gg\<C-A>102\<C-X>\<C-A>l\<C-X>l\<C-A>64\<C-A>128\<C-X>$\<C-X>"
+ set nrformats=octal
+ exec "norm! j0\<C-A>102\<C-X>\<C-A>l\<C-X>2\<C-A>w65\<C-A>129\<C-X>blx6lD"
+ set nrformats=hex
+ exec "norm! j0101\<C-X>l257\<C-X>\<C-A>Txldt \<C-A> \<C-X> \<C-X>"
+ set nrformats=
+ exec "norm! j0200\<C-X>l100\<C-X>w78\<C-X>\<C-A>k"
+ call assert_equal(["0 0x0ff 0000 -1",
+ \ "0 1x100 0777777",
+ \ "-1 0x0 078 0xFE 0xfe",
+ \ "-100 -100x100 000 "], getline(1, '$'))
+ call assert_equal([0, 3, 25, 0], getpos('.'))
+endfunc
+
+func Test_increment_empty_line()
+ new
+ call setline(1, ['0', '0', '0', '0', '0', '0', ''])
+ exe "normal Gvgg\<C-A>"
+ call assert_equal(['1', '1', '1', '1', '1', '1', ''], getline(1, 7))
+ bwipe!
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/test_increment_dbcs.vim b/src/testdir/test_increment_dbcs.vim
new file mode 100644
index 0000000..80b81ac
--- /dev/null
+++ b/src/testdir/test_increment_dbcs.vim
@@ -0,0 +1,27 @@
+" Tests for using Ctrl-A/Ctrl-X using DBCS.
+set encoding=cp932
+scriptencoding cp932
+
+func SetUp()
+ new
+ set nrformats&
+endfunc
+
+func TearDown()
+ bwipe!
+endfunc
+
+func Test_increment_dbcs_1()
+ set nrformats+=alpha
+ call setline(1, ["ŽR1"])
+ exec "norm! 0\<C-A>"
+ call assert_equal(["ŽR2"], getline(1, '$'))
+ call assert_equal([0, 1, 3, 0], getpos('.'))
+
+ call setline(1, ["‚`‚a‚b0xDE‚e"])
+ exec "norm! 0\<C-X>"
+ call assert_equal(["‚`‚a‚b0xDD‚e"], getline(1, '$'))
+ call assert_equal([0, 1, 10, 0], getpos('.'))
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/test_ins_complete.vim b/src/testdir/test_ins_complete.vim
new file mode 100644
index 0000000..6fb6e79
--- /dev/null
+++ b/src/testdir/test_ins_complete.vim
@@ -0,0 +1,312 @@
+
+" Test for insert expansion
+func Test_ins_complete()
+ edit test_ins_complete.vim
+ " The files in the current directory interferes with the files
+ " used by this test. So use a separate directory for the test.
+ call mkdir('Xdir')
+ cd Xdir
+
+ set ff=unix
+ call writefile(["test11\t36Gepeto\t/Tag/",
+ \ "asd\ttest11file\t36G",
+ \ "Makefile\tto\trun"], 'Xtestfile')
+ call writefile(['', 'start of testfile',
+ \ 'ru',
+ \ 'run1',
+ \ 'run2',
+ \ 'STARTTEST',
+ \ 'ENDTEST',
+ \ 'end of testfile'], 'Xtestdata')
+ set ff&
+
+ enew!
+ edit Xtestdata
+ new
+ call append(0, ['#include "Xtestfile"', ''])
+ call cursor(2, 1)
+
+ set cot=
+ set cpt=.,w
+ " add-expands (word from next line) from other window
+ exe "normal iru\<C-N>\<C-N>\<C-X>\<C-N>\<Esc>\<C-A>"
+ call assert_equal('run1 run3', getline('.'))
+ " add-expands (current buffer first)
+ exe "normal o\<C-P>\<C-X>\<C-N>"
+ call assert_equal('run3 run3', getline('.'))
+ " Local expansion, ends in an empty line (unless it becomes a global
+ " expansion)
+ exe "normal o\<C-X>\<C-P>\<C-P>\<C-P>\<C-P>\<C-P>"
+ call assert_equal('', getline('.'))
+ " starts Local and switches to global add-expansion
+ exe "normal o\<C-X>\<C-P>\<C-P>\<C-X>\<C-X>\<C-N>\<C-X>\<C-N>\<C-N>"
+ call assert_equal('run1 run2', getline('.'))
+
+ set cpt=.,w,i
+ " i-add-expands and switches to local
+ exe "normal OM\<C-N>\<C-X>\<C-N>\<C-X>\<C-N>\<C-X>\<C-X>\<C-X>\<C-P>"
+ call assert_equal("Makefile\tto\trun3", getline('.'))
+ " add-expands lines (it would end in an empty line if it didn't ignored
+ " itself)
+ exe "normal o\<C-X>\<C-L>\<C-X>\<C-L>\<C-P>\<C-P>"
+ call assert_equal("Makefile\tto\trun3", getline('.'))
+ call assert_equal("Makefile\tto\trun3", getline(line('.') - 1))
+
+ set cpt=kXtestfile
+ " checks k-expansion, and file expansion (use Xtest11 instead of test11,
+ " because TEST11.OUT may match first on DOS)
+ write Xtest11.one
+ write Xtest11.two
+ exe "normal o\<C-N>\<Esc>IX\<Esc>A\<C-X>\<C-F>\<C-N>"
+ call assert_equal('Xtest11.two', getline('.'))
+
+ " use CTRL-X CTRL-F to complete Xtest11.one, remove it and then use CTRL-X
+ " CTRL-F again to verify this doesn't cause trouble.
+ exe "normal oXt\<C-X>\<C-F>\<BS>\<BS>\<BS>\<BS>\<BS>\<BS>\<BS>\<BS>\<C-X>\<C-F>"
+ call assert_equal('Xtest11.one', getline('.'))
+ normal ddk
+
+ set cpt=w
+ " checks make_cyclic in other window
+ exe "normal oST\<C-N>\<C-P>\<C-P>\<C-P>\<C-P>"
+ call assert_equal('STARTTEST', getline('.'))
+
+ set cpt=u nohid
+ " checks unloaded buffer expansion
+ only
+ exe "normal oEN\<C-N>"
+ call assert_equal('ENDTEST', getline('.'))
+ " checks adding mode abortion
+ exe "normal ounl\<C-N>\<C-X>\<C-X>\<C-P>"
+ call assert_equal('unless', getline('.'))
+
+ set cpt=t,d def=^\\k* tags=Xtestfile notagbsearch
+ " tag expansion, define add-expansion interrupted
+ exe "normal o\<C-X>\<C-]>\<C-X>\<C-D>\<C-X>\<C-D>\<C-X>\<C-X>\<C-D>\<C-X>\<C-D>\<C-X>\<C-D>\<C-X>\<C-D>"
+ call assert_equal('test11file 36Gepeto /Tag/ asd', getline('.'))
+ " t-expansion
+ exe "normal oa\<C-N>\<Esc>"
+ call assert_equal('asd', getline('.'))
+
+ %bw!
+ call delete('Xtestfile')
+ call delete('Xtest11.one')
+ call delete('Xtest11.two')
+ call delete('Xtestdata')
+ set cpt& cot& def& tags& tagbsearch& hidden&
+ cd ..
+ call delete('Xdir', 'rf')
+endfunc
+
+func Test_omni_dash()
+ func Omni(findstart, base)
+ if a:findstart
+ return 5
+ else
+ echom a:base
+ return ['-help', '-v']
+ endif
+ endfunc
+ set omnifunc=Omni
+ new
+ exe "normal Gofind -\<C-x>\<C-o>"
+ call assert_equal("\n-\nmatch 1 of 2", execute(':2mess'))
+
+ bwipe!
+ delfunc Omni
+ set omnifunc=
+endfunc
+
+func Test_completefunc_args()
+ let s:args = []
+ func! CompleteFunc(findstart, base)
+ let s:args += [[a:findstart, empty(a:base)]]
+ endfunc
+ new
+
+ set completefunc=CompleteFunc
+ call feedkeys("i\<C-X>\<C-U>\<Esc>", 'x')
+ call assert_equal([1, 1], s:args[0])
+ call assert_equal(0, s:args[1][0])
+ set completefunc=
+
+ let s:args = []
+ set omnifunc=CompleteFunc
+ call feedkeys("i\<C-X>\<C-O>\<Esc>", 'x')
+ call assert_equal([1, 1], s:args[0])
+ call assert_equal(0, s:args[1][0])
+ set omnifunc=
+
+ bwipe!
+ unlet s:args
+ delfunc CompleteFunc
+endfunc
+
+func s:CompleteDone_CompleteFuncNone( findstart, base )
+ if a:findstart
+ return 0
+ endif
+
+ return v:none
+endfunc
+
+func s:CompleteDone_CompleteFuncDict( findstart, base )
+ if a:findstart
+ return 0
+ endif
+
+ return {
+ \ 'words': [
+ \ {
+ \ 'word': 'aword',
+ \ 'abbr': 'wrd',
+ \ 'menu': 'extra text',
+ \ 'info': 'words are cool',
+ \ 'kind': 'W',
+ \ 'user_data': 'test'
+ \ }
+ \ ]
+ \ }
+endfunc
+
+func s:CompleteDone_CheckCompletedItemNone()
+ let s:called_completedone = 1
+endfunc
+
+func s:CompleteDone_CheckCompletedItemDict()
+ call assert_equal( 'aword', v:completed_item[ 'word' ] )
+ call assert_equal( 'wrd', v:completed_item[ 'abbr' ] )
+ call assert_equal( 'extra text', v:completed_item[ 'menu' ] )
+ call assert_equal( 'words are cool', v:completed_item[ 'info' ] )
+ call assert_equal( 'W', v:completed_item[ 'kind' ] )
+ call assert_equal( 'test', v:completed_item[ 'user_data' ] )
+
+ let s:called_completedone = 1
+endfunc
+
+func Test_CompleteDoneNone()
+ au CompleteDone * :call <SID>CompleteDone_CheckCompletedItemNone()
+
+ set completefunc=<SID>CompleteDone_CompleteFuncNone
+ execute "normal a\<C-X>\<C-U>\<C-Y>"
+ set completefunc&
+
+ call assert_true(s:called_completedone)
+
+ let s:called_completedone = 0
+ au! CompleteDone
+endfunc
+
+func Test_CompleteDoneDict()
+ au CompleteDone * :call <SID>CompleteDone_CheckCompletedItemDict()
+
+ set completefunc=<SID>CompleteDone_CompleteFuncDict
+ execute "normal a\<C-X>\<C-U>\<C-Y>"
+ set completefunc&
+
+ call assert_equal('test', v:completed_item[ 'user_data' ])
+ call assert_true(s:called_completedone)
+
+ let s:called_completedone = 0
+ au! CompleteDone
+endfunc
+
+func s:CompleteDone_CompleteFuncDictNoUserData(findstart, base)
+ if a:findstart
+ return 0
+ endif
+
+ return {
+ \ 'words': [
+ \ {
+ \ 'word': 'aword',
+ \ 'abbr': 'wrd',
+ \ 'menu': 'extra text',
+ \ 'info': 'words are cool',
+ \ 'kind': 'W'
+ \ }
+ \ ]
+ \ }
+endfunc
+
+func s:CompleteDone_CheckCompletedItemDictNoUserData()
+ call assert_equal( 'aword', v:completed_item[ 'word' ] )
+ call assert_equal( 'wrd', v:completed_item[ 'abbr' ] )
+ call assert_equal( 'extra text', v:completed_item[ 'menu' ] )
+ call assert_equal( 'words are cool', v:completed_item[ 'info' ] )
+ call assert_equal( 'W', v:completed_item[ 'kind' ] )
+ call assert_equal( '', v:completed_item[ 'user_data' ] )
+
+ let s:called_completedone = 1
+endfunc
+
+func Test_CompleteDoneDictNoUserData()
+ au CompleteDone * :call <SID>CompleteDone_CheckCompletedItemDictNoUserData()
+
+ set completefunc=<SID>CompleteDone_CompleteFuncDictNoUserData
+ execute "normal a\<C-X>\<C-U>\<C-Y>"
+ set completefunc&
+
+ call assert_equal('', v:completed_item[ 'user_data' ])
+ call assert_true(s:called_completedone)
+
+ let s:called_completedone = 0
+ au! CompleteDone
+endfunc
+
+func s:CompleteDone_CompleteFuncList(findstart, base)
+ if a:findstart
+ return 0
+ endif
+
+ return [ 'aword' ]
+endfunc
+
+func s:CompleteDone_CheckCompletedItemList()
+ call assert_equal( 'aword', v:completed_item[ 'word' ] )
+ call assert_equal( '', v:completed_item[ 'abbr' ] )
+ call assert_equal( '', v:completed_item[ 'menu' ] )
+ call assert_equal( '', v:completed_item[ 'info' ] )
+ call assert_equal( '', v:completed_item[ 'kind' ] )
+ call assert_equal( '', v:completed_item[ 'user_data' ] )
+
+ let s:called_completedone = 1
+endfunc
+
+func Test_CompleteDoneList()
+ au CompleteDone * :call <SID>CompleteDone_CheckCompletedItemList()
+
+ set completefunc=<SID>CompleteDone_CompleteFuncList
+ execute "normal a\<C-X>\<C-U>\<C-Y>"
+ set completefunc&
+
+ call assert_equal('', v:completed_item[ 'user_data' ])
+ call assert_true(s:called_completedone)
+
+ let s:called_completedone = 0
+ au! CompleteDone
+endfunc
+
+func Test_CompleteDone_undo()
+ au CompleteDone * call append(0, "prepend1")
+ new
+ call setline(1, ["line1", "line2"])
+ call feedkeys("Go\<C-X>\<C-N>\<CR>\<ESC>", "tx")
+ call assert_equal(["prepend1", "line1", "line2", "line1", ""],
+ \ getline(1, '$'))
+ undo
+ call assert_equal(["line1", "line2"], getline(1, '$'))
+ bwipe!
+ au! CompleteDone
+endfunc
+
+" Check that when using feedkeys() typeahead does not interrupt searching for
+" completions.
+func Test_compl_feedkeys()
+ new
+ set completeopt=menuone,noselect
+ call feedkeys("ajump ju\<C-X>\<C-N>\<C-P>\<ESC>", "tx")
+ call assert_equal("jump jump", getline(1))
+ bwipe!
+ set completeopt&
+endfunc
diff --git a/src/testdir/test_job_fails.vim b/src/testdir/test_job_fails.vim
new file mode 100644
index 0000000..affcb7d
--- /dev/null
+++ b/src/testdir/test_job_fails.vim
@@ -0,0 +1,16 @@
+" This test is in a separate file, because it usually causes reports for memory
+" leaks under valgrind. That is because when fork/exec fails memory is not
+" freed. Since the process exists right away it's not a real leak.
+
+source shared.vim
+
+func Test_job_start_fails()
+ if has('job')
+ let job = job_start('axdfxsdf')
+ if has('unix')
+ call WaitForAssert({-> assert_equal("dead", job_status(job))})
+ else
+ call WaitForAssert({-> assert_equal("fail", job_status(job))})
+ endif
+ endif
+endfunc
diff --git a/src/testdir/test_join.vim b/src/testdir/test_join.vim
new file mode 100644
index 0000000..1c97414
--- /dev/null
+++ b/src/testdir/test_join.vim
@@ -0,0 +1,35 @@
+" Test for joining lines.
+
+func Test_join_with_count()
+ new
+ call setline(1, ['one', 'two', 'three', 'four'])
+ normal J
+ call assert_equal('one two', getline(1))
+ %del
+ call setline(1, ['one', 'two', 'three', 'four'])
+ normal 10J
+ call assert_equal('one two three four', getline(1))
+ quit!
+endfunc
+
+" Tests for setting the '[,'] marks when joining lines.
+func Test_join_marks()
+ enew
+ call append(0, [
+ \ "\t\tO sodales, ludite, vos qui",
+ \ "attamen consulite per voster honur. Tua pulchra " .
+ \ "facies me fay planszer milies",
+ \ "",
+ \ "This line.",
+ \ "Should be joined with the next line",
+ \ "and with this line"])
+
+ normal gg0gqj
+ call assert_equal([0, 1, 1, 0], getpos("'["))
+ call assert_equal([0, 2, 1, 0], getpos("']"))
+
+ /^This line/;'}-join
+ call assert_equal([0, 4, 11, 0], getpos("'["))
+ call assert_equal([0, 4, 67, 0], getpos("']"))
+ enew!
+endfunc
diff --git a/src/testdir/test_json.vim b/src/testdir/test_json.vim
new file mode 100644
index 0000000..fb3d992
--- /dev/null
+++ b/src/testdir/test_json.vim
@@ -0,0 +1,291 @@
+" Test for JSON functions.
+
+let s:json1 = '"str\"in\\g"'
+let s:var1 = "str\"in\\g"
+let s:json2 = '"\u0001\u0002\u0003\u0004\u0005\u0006\u0007"'
+let s:var2 = "\x01\x02\x03\x04\x05\x06\x07"
+let s:json3 = '"\b\t\n\u000b\f\r\u000e\u000f"'
+let s:var3 = "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+let s:json4 = '"\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017"'
+let s:var4 = "\x10\x11\x12\x13\x14\x15\x16\x17"
+let s:json5 = '"\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f"'
+let s:var5 = "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+
+" surrogate pair
+let s:jsonsp1 = '"\ud83c\udf63"'
+let s:varsp1 = "\xf0\x9f\x8d\xa3"
+let s:jsonsp2 = '"\ud83c\u00a0"'
+let s:varsp2 = "\ud83c\u00a0"
+
+let s:jsonmb = '"s¢cĴgё"'
+let s:varmb = "s¢cĴgё"
+let s:jsonnr = '1234'
+let s:varnr = 1234
+if has('float')
+ let s:jsonfl = '12.34'
+ let s:varfl = 12.34
+ let s:jsonneginf = '-Infinity'
+ let s:jsonposinf = 'Infinity'
+ let s:varneginf = -1.0 / 0.0
+ let s:varposinf = 1.0 / 0.0
+ let s:jsonnan = 'NaN'
+ let s:varnan = 0.0 / 0.0
+endif
+
+let s:jsonl1 = '[1,"a",3]'
+let s:varl1 = [1, "a", 3]
+let s:jsonl2 = '[1,["a",[],"c"],3]'
+let s:jsonl2s = " [\r1 , [ \"a\" , [ ] , \"c\" ] , 3\<Tab>]\r\n"
+let s:varl2 = [1, 2, 3]
+let l2 = ['a', s:varl2, 'c']
+let s:varl2[1] = l2
+let s:varl2x = [1, ["a", [], "c"], 3]
+let s:jsonl3 = '[[1,2],[1,2]]'
+let l3 = [1, 2]
+let s:varl3 = [l3, l3]
+
+let s:jsond1 = '{"a":1,"b":"bee","c":[1,2]}'
+let s:jsd1 = '{a:1,b:"bee",c:[1,2]}'
+let s:vard1 = {"a": 1, "b": "bee","c": [1,2]}
+let s:jsond2 = '{"1":1,"2":{"a":"aa","b":{},"c":"cc"},"3":3}'
+let s:jsd2 = '{"1":1,"2":{a:"aa",b:{},c:"cc"},"3":3}'
+let s:jsond2s = " { \"1\" : 1 , \"2\" :\n{ \"a\"\r: \"aa\" , \"b\" : {\<Tab>} , \"c\" : \"cc\" } , \"3\" : 3 }\r\n"
+let s:jsd2s = " { \"1\" : 1 , \"2\" :\n{ a\r: \"aa\" , b : {\<Tab>} , c : \"cc\" } , \"3\" : 3 }\r\n"
+let s:vard2 = {"1": 1, "2": 2, "3": 3}
+let d2 = {"a": "aa", "b": s:vard2, "c": "cc"}
+let s:vard2["2"] = d2
+let s:vard2x = {"1": 1, "2": {"a": "aa", "b": {}, "c": "cc"}, "3": 3}
+let d3 = {"a": 1, "b": 2}
+let s:vard3 = {"x": d3, "y": d3}
+let s:jsond3 = '{"x":{"a":1,"b":2},"y":{"a":1,"b":2}}'
+let s:jsd3 = '{x:{a:1,b:2},y:{a:1,b:2}}'
+let s:vard4 = {"key": v:none}
+let s:vard4x = {"key": v:null}
+let s:jsond4 = '{"key":null}'
+let s:jsd4 = '{key:null}'
+
+let s:jsonvals = '[true,false,null,null]'
+let s:varvals = [v:true, v:false, v:null, v:null]
+
+func Test_json_encode()
+ call assert_equal(s:json1, json_encode(s:var1))
+ call assert_equal(s:json2, json_encode(s:var2))
+ call assert_equal(s:json3, json_encode(s:var3))
+ call assert_equal(s:json4, json_encode(s:var4))
+ call assert_equal(s:json5, json_encode(s:var5))
+
+ call assert_equal(s:jsonmb, json_encode(s:varmb))
+ " no test for surrogate pair, json_encode() doesn't create them.
+
+ call assert_equal(s:jsonnr, json_encode(s:varnr))
+ if has('float')
+ call assert_equal(s:jsonfl, json_encode(s:varfl))
+ call assert_equal(s:jsonneginf, json_encode(s:varneginf))
+ call assert_equal(s:jsonposinf, json_encode(s:varposinf))
+ call assert_equal(s:jsonnan, json_encode(s:varnan))
+ endif
+
+ call assert_equal(s:jsonl1, json_encode(s:varl1))
+ call assert_equal(s:jsonl2, json_encode(s:varl2))
+ call assert_equal(s:jsonl3, json_encode(s:varl3))
+
+ call assert_equal(s:jsond1, json_encode(s:vard1))
+ call assert_equal(s:jsond2, json_encode(s:vard2))
+ call assert_equal(s:jsond3, json_encode(s:vard3))
+ call assert_equal(s:jsond4, json_encode(s:vard4))
+
+ call assert_equal(s:jsonvals, json_encode(s:varvals))
+
+ call assert_fails('echo json_encode(function("tr"))', 'E474:')
+ call assert_fails('echo json_encode([function("tr")])', 'E474:')
+
+ call assert_equal('{"a":""}', json_encode({'a': test_null_string()}))
+ call assert_equal('{"a":[]}', json_encode({"a": test_null_list()}))
+ call assert_equal('{"a":{}}', json_encode({"a": test_null_dict()}))
+
+ silent! let res = json_encode(function("tr"))
+ call assert_equal("", res)
+endfunc
+
+func Test_json_decode()
+ call assert_equal(s:var1, json_decode(s:json1))
+ call assert_equal(s:var2, json_decode(s:json2))
+ call assert_equal(s:var3, json_decode(s:json3))
+ call assert_equal(s:var4, json_decode(s:json4))
+ call assert_equal(s:var5, json_decode(s:json5))
+
+ call assert_equal(s:varmb, json_decode(s:jsonmb))
+ call assert_equal(s:varsp1, json_decode(s:jsonsp1))
+ call assert_equal(s:varsp2, json_decode(s:jsonsp2))
+
+ call assert_equal(s:varnr, json_decode(s:jsonnr))
+ if has('float')
+ call assert_equal(s:varfl, json_decode(s:jsonfl))
+ endif
+
+ call assert_equal(s:varl1, json_decode(s:jsonl1))
+ call assert_equal(s:varl2x, json_decode(s:jsonl2))
+ call assert_equal(s:varl2x, json_decode(s:jsonl2s))
+ call assert_equal(s:varl3, json_decode(s:jsonl3))
+
+ call assert_equal(s:vard1, json_decode(s:jsond1))
+ call assert_equal(s:vard2x, json_decode(s:jsond2))
+ call assert_equal(s:vard2x, json_decode(s:jsond2s))
+ call assert_equal(s:vard3, json_decode(s:jsond3))
+ call assert_equal(s:vard4x, json_decode(s:jsond4))
+
+ call assert_equal(s:varvals, json_decode(s:jsonvals))
+
+ call assert_equal(v:true, json_decode('true'))
+ call assert_equal(type(v:true), type(json_decode('true')))
+ call assert_equal(v:none, json_decode(''))
+ call assert_equal(type(v:none), type(json_decode('')))
+ call assert_equal("", json_decode('""'))
+
+ " empty key is OK
+ call assert_equal({'': 'ok'}, json_decode('{"": "ok"}'))
+ " but not twice
+ call assert_fails("call json_decode('{\"\": \"ok\", \"\": \"bad\"}')", 'E938:')
+
+ call assert_equal({'n': 1}, json_decode('{"n":1,}'))
+ call assert_fails("call json_decode(\"{'n':'1',}\")", 'E474:')
+ call assert_fails("call json_decode(\"'n'\")", 'E474:')
+
+ call assert_fails('call json_decode("\"")', "E474:")
+ call assert_fails('call json_decode("blah")', "E474:")
+ call assert_fails('call json_decode("true blah")', "E488:")
+ call assert_fails('call json_decode("<foobar>")', "E474:")
+ call assert_fails('call json_decode("{\"a\":1,\"a\":2}")', "E938:")
+
+ call assert_fails('call json_decode("{")', "E474:")
+ call assert_fails('call json_decode("{foobar}")', "E474:")
+ call assert_fails('call json_decode("{\"n\",")', "E474:")
+ call assert_fails('call json_decode("{\"n\":")', "E474:")
+ call assert_fails('call json_decode("{\"n\":1")', "E474:")
+ call assert_fails('call json_decode("{\"n\":1,")', "E474:")
+ call assert_fails('call json_decode("{\"n\",1}")', "E474:")
+ call assert_fails('call json_decode("{-}")', "E474:")
+
+ call assert_fails('call json_decode("[foobar]")', "E474:")
+ call assert_fails('call json_decode("[")', "E474:")
+ call assert_fails('call json_decode("[1")', "E474:")
+ call assert_fails('call json_decode("[1,")', "E474:")
+ call assert_fails('call json_decode("[1 2]")', "E474:")
+
+ call assert_fails('call json_decode("[1,,2]")', "E474:")
+
+ call assert_fails('call json_decode("{{}:42}")', "E474:")
+ call assert_fails('call json_decode("{[]:42}")', "E474:")
+endfunc
+
+let s:jsl5 = '[7,,,]'
+let s:varl5 = [7, v:none, v:none]
+
+func Test_js_encode()
+ call assert_equal(s:json1, js_encode(s:var1))
+ call assert_equal(s:json2, js_encode(s:var2))
+ call assert_equal(s:json3, js_encode(s:var3))
+ call assert_equal(s:json4, js_encode(s:var4))
+ call assert_equal(s:json5, js_encode(s:var5))
+
+ call assert_equal(s:jsonmb, js_encode(s:varmb))
+ " no test for surrogate pair, js_encode() doesn't create them.
+
+ call assert_equal(s:jsonnr, js_encode(s:varnr))
+ if has('float')
+ call assert_equal(s:jsonfl, js_encode(s:varfl))
+ call assert_equal(s:jsonneginf, js_encode(s:varneginf))
+ call assert_equal(s:jsonposinf, js_encode(s:varposinf))
+ call assert_equal(s:jsonnan, js_encode(s:varnan))
+ endif
+
+ call assert_equal(s:jsonl1, js_encode(s:varl1))
+ call assert_equal(s:jsonl2, js_encode(s:varl2))
+ call assert_equal(s:jsonl3, js_encode(s:varl3))
+
+ call assert_equal(s:jsd1, js_encode(s:vard1))
+ call assert_equal(s:jsd2, js_encode(s:vard2))
+ call assert_equal(s:jsd3, js_encode(s:vard3))
+ call assert_equal(s:jsd4, js_encode(s:vard4))
+
+ call assert_equal(s:jsonvals, js_encode(s:varvals))
+
+ call assert_fails('echo js_encode(function("tr"))', 'E474:')
+ call assert_fails('echo js_encode([function("tr")])', 'E474:')
+
+ silent! let res = js_encode(function("tr"))
+ call assert_equal("", res)
+
+ call assert_equal(s:jsl5, js_encode(s:varl5))
+endfunc
+
+func Test_js_decode()
+ call assert_equal(s:var1, js_decode(s:json1))
+ call assert_equal(s:var2, js_decode(s:json2))
+ call assert_equal(s:var3, js_decode(s:json3))
+ call assert_equal(s:var4, js_decode(s:json4))
+ call assert_equal(s:var5, js_decode(s:json5))
+
+ call assert_equal(s:varmb, js_decode(s:jsonmb))
+ call assert_equal(s:varsp1, js_decode(s:jsonsp1))
+ call assert_equal(s:varsp2, js_decode(s:jsonsp2))
+
+ call assert_equal(s:varnr, js_decode(s:jsonnr))
+ if has('float')
+ call assert_equal(s:varfl, js_decode(s:jsonfl))
+ call assert_equal(s:varneginf, js_decode(s:jsonneginf))
+ call assert_equal(s:varposinf, js_decode(s:jsonposinf))
+ call assert_true(isnan(js_decode(s:jsonnan)))
+ endif
+
+ call assert_equal(s:varl1, js_decode(s:jsonl1))
+ call assert_equal(s:varl2x, js_decode(s:jsonl2))
+ call assert_equal(s:varl2x, js_decode(s:jsonl2s))
+ call assert_equal(s:varl3, js_decode(s:jsonl3))
+
+ call assert_equal(s:vard1, js_decode(s:jsond1))
+ call assert_equal(s:vard1, js_decode(s:jsd1))
+ call assert_equal(s:vard2x, js_decode(s:jsond2))
+ call assert_equal(s:vard2x, js_decode(s:jsd2))
+ call assert_equal(s:vard2x, js_decode(s:jsond2s))
+ call assert_equal(s:vard2x, js_decode(s:jsd2s))
+ call assert_equal(s:vard3, js_decode(s:jsond3))
+ call assert_equal(s:vard3, js_decode(s:jsd3))
+ call assert_equal(s:vard4x, js_decode(s:jsond4))
+ call assert_equal(s:vard4x, js_decode(s:jsd4))
+
+ call assert_equal(s:varvals, js_decode(s:jsonvals))
+
+ call assert_equal(v:true, js_decode('true'))
+ call assert_equal(type(v:true), type(js_decode('true')))
+ call assert_equal(v:none, js_decode(''))
+ call assert_equal(type(v:none), type(js_decode('')))
+ call assert_equal("", js_decode('""'))
+ call assert_equal("", js_decode("''"))
+
+ call assert_equal('n', js_decode("'n'"))
+ call assert_equal({'n': 1}, js_decode('{"n":1,}'))
+ call assert_equal({'n': '1'}, js_decode("{'n':'1',}"))
+
+ call assert_fails('call js_decode("\"")', "E474:")
+ call assert_fails('call js_decode("blah")', "E474:")
+ call assert_fails('call js_decode("true blah")', "E474:")
+ call assert_fails('call js_decode("<foobar>")', "E474:")
+
+ call assert_fails('call js_decode("{")', "E474:")
+ call assert_fails('call js_decode("{foobar}")', "E474:")
+ call assert_fails('call js_decode("{\"n\",")', "E474:")
+ call assert_fails('call js_decode("{\"n\":")', "E474:")
+ call assert_fails('call js_decode("{\"n\":1")', "E474:")
+ call assert_fails('call js_decode("{\"n\":1,")', "E474:")
+ call assert_fails('call js_decode("{\"n\",1}")', "E474:")
+ call assert_fails('call js_decode("{-}")', "E474:")
+
+ call assert_fails('call js_decode("[foobar]")', "E474:")
+ call assert_fails('call js_decode("[")', "E474:")
+ call assert_fails('call js_decode("[1")', "E474:")
+ call assert_fails('call js_decode("[1,")', "E474:")
+ call assert_fails('call js_decode("[1 2]")', "E474:")
+
+ call assert_equal(s:varl5, js_decode(s:jsl5))
+endfunc
diff --git a/src/testdir/test_jumplist.vim b/src/testdir/test_jumplist.vim
new file mode 100644
index 0000000..02dbd76
--- /dev/null
+++ b/src/testdir/test_jumplist.vim
@@ -0,0 +1,62 @@
+" Tests for the jumplist functionality
+
+" Tests for the getjumplist() function
+func Test_getjumplist()
+ if !has("jumplist")
+ return
+ endif
+
+ %bwipe
+ clearjumps
+ call assert_equal([[], 0], getjumplist())
+ call assert_equal([[], 0], getjumplist(1))
+ call assert_equal([[], 0], getjumplist(1, 1))
+
+ call assert_equal([], getjumplist(100))
+ call assert_equal([], getjumplist(1, 100))
+
+ let lines = []
+ for i in range(1, 100)
+ call add(lines, "Line " . i)
+ endfor
+ call writefile(lines, "Xtest")
+
+ " Jump around and create a jump list
+ edit Xtest
+ let bnr = bufnr('%')
+ normal 50%
+ normal G
+ normal gg
+
+ call assert_equal([[
+ \ {'lnum': 1, 'bufnr': bnr, 'col': 0, 'coladd': 0},
+ \ {'lnum': 50, 'bufnr': bnr, 'col': 0, 'coladd': 0},
+ \ {'lnum': 100, 'bufnr': bnr, 'col': 0, 'coladd': 0}], 4],
+ \ getjumplist())
+
+ " Traverse the jump list and verify the results
+ 5
+ exe "normal \<C-O>"
+ call assert_equal(2, getjumplist(1)[1])
+ exe "normal 2\<C-O>"
+ call assert_equal(0, getjumplist(1, 1)[1])
+ exe "normal 3\<C-I>"
+ call assert_equal(3, getjumplist()[1])
+ exe "normal \<C-O>"
+ normal 20%
+ call assert_equal([[
+ \ {'lnum': 1, 'bufnr': bnr, 'col': 0, 'coladd': 0},
+ \ {'lnum': 50, 'bufnr': bnr, 'col': 0, 'coladd': 0},
+ \ {'lnum': 5, 'bufnr': bnr, 'col': 0, 'coladd': 0},
+ \ {'lnum': 100, 'bufnr': bnr, 'col': 0, 'coladd': 0}], 5],
+ \ getjumplist())
+
+ let l = getjumplist()
+ call test_garbagecollect_now()
+ call assert_equal(4, l[1])
+ clearjumps
+ call test_garbagecollect_now()
+ call assert_equal(4, l[1])
+
+ call delete("Xtest")
+endfunc
diff --git a/src/testdir/test_jumps.vim b/src/testdir/test_jumps.vim
new file mode 100644
index 0000000..5a3717d
--- /dev/null
+++ b/src/testdir/test_jumps.vim
@@ -0,0 +1,11 @@
+func Test_empty_buffer()
+ new
+ insert
+a
+b
+c
+d
+.
+ call assert_equal(1, line("''"))
+ bwipe!
+endfunc
diff --git a/src/testdir/test_lambda.vim b/src/testdir/test_lambda.vim
new file mode 100644
index 0000000..4ff3e20
--- /dev/null
+++ b/src/testdir/test_lambda.vim
@@ -0,0 +1,292 @@
+" Test for lambda and closure
+
+func Test_lambda_feature()
+ call assert_equal(1, has('lambda'))
+endfunc
+
+func Test_lambda_with_filter()
+ let s:x = 2
+ call assert_equal([2, 3], filter([1, 2, 3], {i, v -> v >= s:x}))
+endfunc
+
+func Test_lambda_with_map()
+ let s:x = 1
+ call assert_equal([2, 3, 4], map([1, 2, 3], {i, v -> v + s:x}))
+endfunc
+
+func Test_lambda_with_sort()
+ call assert_equal([1, 2, 3, 4, 7], sort([3,7,2,1,4], {a, b -> a - b}))
+endfunc
+
+func Test_lambda_with_timer()
+ if !has('timers')
+ return
+ endif
+
+ let s:n = 0
+ let s:timer_id = 0
+ func! s:Foo()
+ "let n = 0
+ let s:timer_id = timer_start(50, {-> execute("let s:n += 1 | echo s:n", "")}, {"repeat": -1})
+ endfunc
+
+ call s:Foo()
+ sleep 200ms
+ " do not collect lambda
+ call test_garbagecollect_now()
+ let m = s:n
+ sleep 200ms
+ call timer_stop(s:timer_id)
+ call assert_true(m > 1)
+ call assert_true(s:n > m + 1)
+ call assert_true(s:n < 9)
+endfunc
+
+func Test_lambda_with_partial()
+ let l:Cb = function({... -> ['zero', a:1, a:2, a:3]}, ['one', 'two'])
+ call assert_equal(['zero', 'one', 'two', 'three'], l:Cb('three'))
+endfunc
+
+function Test_lambda_fails()
+ call assert_equal(3, {a, b -> a + b}(1, 2))
+ call assert_fails('echo {a, a -> a + a}(1, 2)', 'E853:')
+ call assert_fails('echo {a, b -> a + b)}(1, 2)', 'E15:')
+endfunc
+
+func Test_not_lamda()
+ let x = {'>' : 'foo'}
+ call assert_equal('foo', x['>'])
+endfunc
+
+func Test_lambda_capture_by_reference()
+ let v = 1
+ let l:F = {x -> x + v}
+ let v = 2
+ call assert_equal(12, l:F(10))
+endfunc
+
+func Test_lambda_side_effect()
+ func! s:update_and_return(arr)
+ let a:arr[1] = 5
+ return a:arr
+ endfunc
+
+ func! s:foo(arr)
+ return {-> s:update_and_return(a:arr)}
+ endfunc
+
+ let arr = [3,2,1]
+ call assert_equal([3, 5, 1], s:foo(arr)())
+endfunc
+
+func Test_lambda_refer_local_variable_from_other_scope()
+ func! s:foo(X)
+ return a:X() " refer l:x in s:bar()
+ endfunc
+
+ func! s:bar()
+ let x = 123
+ return s:foo({-> x})
+ endfunc
+
+ call assert_equal(123, s:bar())
+endfunc
+
+func Test_lambda_do_not_share_local_variable()
+ func! s:define_funcs()
+ let l:One = {-> split(execute("let a = 'abc' | echo a"))[0]}
+ let l:Two = {-> exists("a") ? a : "no"}
+ return [l:One, l:Two]
+ endfunc
+
+ let l:F = s:define_funcs()
+
+ call assert_equal('no', l:F[1]())
+ call assert_equal('abc', l:F[0]())
+ call assert_equal('no', l:F[1]())
+endfunc
+
+func Test_lambda_closure_counter()
+ func! s:foo()
+ let x = 0
+ return {-> [execute("let x += 1"), x][-1]}
+ endfunc
+
+ let l:F = s:foo()
+ call test_garbagecollect_now()
+ call assert_equal(1, l:F())
+ call assert_equal(2, l:F())
+ call assert_equal(3, l:F())
+ call assert_equal(4, l:F())
+endfunc
+
+func Test_lambda_with_a_var()
+ func! s:foo()
+ let x = 2
+ return {... -> a:000 + [x]}
+ endfunc
+ func! s:bar()
+ return s:foo()(1)
+ endfunc
+
+ call assert_equal([1, 2], s:bar())
+endfunc
+
+func Test_lambda_call_lambda_from_lambda()
+ func! s:foo(x)
+ let l:F1 = {-> {-> a:x}}
+ return {-> l:F1()}
+ endfunc
+
+ let l:F = s:foo(1)
+ call assert_equal(1, l:F()())
+endfunc
+
+func Test_lambda_delfunc()
+ func! s:gen()
+ let pl = l:
+ let l:Foo = {-> get(pl, "Foo", get(pl, "Bar", {-> 0}))}
+ let l:Bar = l:Foo
+ delfunction l:Foo
+ return l:Bar
+ endfunc
+
+ let l:F = s:gen()
+ call assert_fails(':call l:F()', 'E933:')
+endfunc
+
+func Test_lambda_scope()
+ func! s:NewCounter()
+ let c = 0
+ return {-> [execute('let c += 1'), c][-1]}
+ endfunc
+
+ func! s:NewCounter2()
+ return {-> [execute('let c += 100'), c][-1]}
+ endfunc
+
+ let l:C = s:NewCounter()
+ let l:D = s:NewCounter2()
+
+ call assert_equal(1, l:C())
+ call assert_fails(':call l:D()', 'E121:')
+ call assert_equal(2, l:C())
+endfunc
+
+func Test_lambda_share_scope()
+ func! s:New()
+ let c = 0
+ let l:Inc0 = {-> [execute('let c += 1'), c][-1]}
+ let l:Dec0 = {-> [execute('let c -= 1'), c][-1]}
+ return [l:Inc0, l:Dec0]
+ endfunc
+
+ let [l:Inc, l:Dec] = s:New()
+
+ call assert_equal(1, l:Inc())
+ call assert_equal(2, l:Inc())
+ call assert_equal(1, l:Dec())
+endfunc
+
+func Test_lambda_circular_reference()
+ func! s:Foo()
+ let d = {}
+ let d.f = {-> d}
+ return d.f
+ endfunc
+
+ call s:Foo()
+ call test_garbagecollect_now()
+ let i = 0 | while i < 10000 | call s:Foo() | let i+= 1 | endwhile
+ call test_garbagecollect_now()
+endfunc
+
+func Test_lambda_combination()
+ call assert_equal(2, {x -> {x -> x}}(1)(2))
+ call assert_equal(10, {y -> {x -> x(y)(10)}({y -> y})}({z -> z}))
+ call assert_equal(5.0, {x -> {y -> x / y}}(10)(2.0))
+ call assert_equal(6, {x -> {y -> {z -> x + y + z}}}(1)(2)(3))
+
+ call assert_equal(6, {x -> {f -> f(x)}}(3)({x -> x * 2}))
+ call assert_equal(6, {f -> {x -> f(x)}}({x -> x * 2})(3))
+
+ " Z combinator
+ let Z = {f -> {x -> f({y -> x(x)(y)})}({x -> f({y -> x(x)(y)})})}
+ let Fact = {f -> {x -> x == 0 ? 1 : x * f(x - 1)}}
+ call assert_equal(120, Z(Fact)(5))
+endfunc
+
+func Test_closure_counter()
+ func! s:foo()
+ let x = 0
+ func! s:bar() closure
+ let x += 1
+ return x
+ endfunc
+ return function('s:bar')
+ endfunc
+
+ let l:F = s:foo()
+ call test_garbagecollect_now()
+ call assert_equal(1, l:F())
+ call assert_equal(2, l:F())
+ call assert_equal(3, l:F())
+ call assert_equal(4, l:F())
+endfunc
+
+func Test_closure_unlet()
+ func! s:foo()
+ let x = 1
+ func! s:bar() closure
+ unlet x
+ endfunc
+ call s:bar()
+ return l:
+ endfunc
+
+ call assert_false(has_key(s:foo(), 'x'))
+ call test_garbagecollect_now()
+endfunc
+
+func LambdaFoo()
+ let x = 0
+ func! LambdaBar() closure
+ let x += 1
+ return x
+ endfunc
+ return function('LambdaBar')
+endfunc
+
+func Test_closure_refcount()
+ let g:Count = LambdaFoo()
+ call test_garbagecollect_now()
+ call assert_equal(1, g:Count())
+ let g:Count2 = LambdaFoo()
+ call test_garbagecollect_now()
+ call assert_equal(1, g:Count2())
+ call assert_equal(2, g:Count())
+ call assert_equal(3, g:Count2())
+
+ delfunc LambdaFoo
+ delfunc LambdaBar
+endfunc
+
+func Test_named_function_closure()
+ func! Afoo()
+ let x = 14
+ func! s:Abar() closure
+ return x
+ endfunc
+ call assert_equal(14, s:Abar())
+ endfunc
+ call Afoo()
+ call assert_equal(14, s:Abar())
+ call test_garbagecollect_now()
+ call assert_equal(14, s:Abar())
+endfunc
+
+func Test_lambda_with_index()
+ let List = {x -> [x]}
+ let Extract = {-> function(List, ['foobar'])()[0]}
+ call assert_equal('foobar', Extract())
+endfunc
diff --git a/src/testdir/test_langmap.vim b/src/testdir/test_langmap.vim
new file mode 100644
index 0000000..572fad7
--- /dev/null
+++ b/src/testdir/test_langmap.vim
@@ -0,0 +1,28 @@
+" tests for 'langmap'
+
+if !has('langmap')
+ finish
+endif
+
+func Test_langmap()
+ new
+ set langmap=}l,^x,%v
+
+ call setline(1, ['abc'])
+ call feedkeys('gg0}^', 'tx')
+ call assert_equal('ac', getline(1))
+
+ " in Replace mode
+ " need silent! to avoid a delay when entering Insert mode
+ call setline(1, ['abcde'])
+ silent! call feedkeys("gg0lR%{z\<Esc>00", 'tx')
+ call assert_equal('a%{ze', getline(1))
+
+ " in Select mode
+ " need silent! to avoid a delay when entering Insert mode
+ call setline(1, ['abcde'])
+ silent! call feedkeys("gg0}%}\<C-G>}^\<Esc>00", 'tx')
+ call assert_equal('a}^de', getline(1))
+
+ quit!
+endfunc
diff --git a/src/testdir/test_largefile.vim b/src/testdir/test_largefile.vim
new file mode 100644
index 0000000..1b3e02a
--- /dev/null
+++ b/src/testdir/test_largefile.vim
@@ -0,0 +1,34 @@
+" Tests for large files
+" This is only executed manually: "make test_largefile".
+" This is not run as part of "make test".
+
+func Test_largefile()
+ let fname = 'Xlarge.txt'
+
+ call delete(fname)
+ exe "e" fname
+ " Make sure that a line break is 1 byte (LF).
+ set ff=unix
+ set undolevels=-1
+ " Input 99 'A's. The line becomes 100 bytes including a line break.
+ exe "normal 99iA\<Esc>"
+ yank
+ " Put 39,999,999 times. The file becomes 4,000,000,000 bytes.
+ normal 39999999p
+ " Moving around in the file randomly.
+ normal G
+ normal 10%
+ normal 90%
+ normal 50%
+ normal gg
+ w
+ " Check if the file size is 4,000,000,000 bytes.
+ let fsize=getfsize(fname)
+ if has('num64')
+ call assert_true(fsize == 4000000000)
+ else
+ " getfsize() returns -2 if a Number is 32 bits.
+ call assert_true(fsize == -2)
+ endif
+ call delete(fname)
+endfunc
diff --git a/src/testdir/test_let.vim b/src/testdir/test_let.vim
new file mode 100644
index 0000000..24c6ef5
--- /dev/null
+++ b/src/testdir/test_let.vim
@@ -0,0 +1,27 @@
+" Tests for the :let command.
+
+func Test_let()
+ " Test to not autoload when assigning. It causes internal error.
+ set runtimepath+=./sautest
+ let Test104#numvar = function('tr')
+ call assert_equal("function('tr')", string(Test104#numvar))
+
+ let a = 1
+ let b = 2
+
+ let out = execute('let a b')
+ let s = "\na #1\nb #2"
+ call assert_equal(s, out)
+
+ let out = execute('let {0 == 1 ? "a" : "b"}')
+ let s = "\nb #2"
+ call assert_equal(s, out)
+
+ let out = execute('let {0 == 1 ? "a" : "b"} a')
+ let s = "\nb #2\na #1"
+ call assert_equal(s, out)
+
+ let out = execute('let a {0 == 1 ? "a" : "b"}')
+ let s = "\na #1\nb #2"
+ call assert_equal(s, out)
+endfunc
diff --git a/src/testdir/test_lineending.vim b/src/testdir/test_lineending.vim
new file mode 100644
index 0000000..d531b74
--- /dev/null
+++ b/src/testdir/test_lineending.vim
@@ -0,0 +1,19 @@
+" Tests for saving/loading a file with some lines ending in
+" CTRL-M, some not
+func Test_lineending()
+ let l = ["this line ends in a\<CR>",
+ \ "this one doesn't",
+ \ "this one does\<CR>",
+ \ "and the last one doesn't"]
+ set ta tx
+ enew!
+ call append(0, l)
+ $delete
+ write Xfile1
+ bwipe Xfile1
+ edit Xfile1
+ let t = getline(1, '$')
+ call assert_equal(l, t)
+ new | only
+ call delete('Xfile1')
+endfunc
diff --git a/src/testdir/test_lispwords.vim b/src/testdir/test_lispwords.vim
new file mode 100644
index 0000000..4c05504
--- /dev/null
+++ b/src/testdir/test_lispwords.vim
@@ -0,0 +1,82 @@
+" Tests for 'lispwords' settings being global-local
+
+set nocompatible viminfo+=nviminfo
+
+func Test_global_local_lispwords()
+ setglobal lispwords=foo,bar,baz
+ setlocal lispwords-=foo | setlocal lispwords+=quux
+ call assert_equal('foo,bar,baz', &g:lispwords)
+ call assert_equal('bar,baz,quux', &l:lispwords)
+ call assert_equal('bar,baz,quux', &lispwords)
+
+ setlocal lispwords<
+ call assert_equal('foo,bar,baz', &g:lispwords)
+ call assert_equal('foo,bar,baz', &l:lispwords)
+ call assert_equal('foo,bar,baz', &lispwords)
+endfunc
+
+func Test_lisp_indent()
+ enew!
+
+ call append(0, [
+ \ '(defun html-file (base)',
+ \ '(format nil "~(~A~).html" base))',
+ \ '',
+ \ '(defmacro page (name title &rest body)',
+ \ '(let ((ti (gensym)))',
+ \ '`(with-open-file (*standard-output*',
+ \ '(html-file ,name)',
+ \ ':direction :output',
+ \ ':if-exists :supersede)',
+ \ '(let ((,ti ,title))',
+ \ '(as title ,ti)',
+ \ '(with center ',
+ \ '(as h2 (string-upcase ,ti)))',
+ \ '(brs 3)',
+ \ ',@body))))',
+ \ '',
+ \ ';;; Utilities for generating links',
+ \ '',
+ \ '(defmacro with-link (dest &rest body)',
+ \ '`(progn',
+ \ '(format t "<a href=\"~A\">" (html-file ,dest))',
+ \ ',@body',
+ \ '(princ "</a>")))'
+ \ ])
+ set lisp
+ set lispwords&
+ let save_copt = &cpoptions
+ set cpoptions+=p
+ normal 1G=G
+
+ call assert_equal([
+ \ '(defun html-file (base)',
+ \ ' (format nil "~(~A~).html" base))',
+ \ '',
+ \ '(defmacro page (name title &rest body)',
+ \ ' (let ((ti (gensym)))',
+ \ ' `(with-open-file (*standard-output*',
+ \ ' (html-file ,name)',
+ \ ' :direction :output',
+ \ ' :if-exists :supersede)',
+ \ ' (let ((,ti ,title))',
+ \ ' (as title ,ti)',
+ \ ' (with center ',
+ \ ' (as h2 (string-upcase ,ti)))',
+ \ ' (brs 3)',
+ \ ' ,@body))))',
+ \ '',
+ \ ';;; Utilities for generating links',
+ \ '',
+ \ '(defmacro with-link (dest &rest body)',
+ \ ' `(progn',
+ \ ' (format t "<a href=\"~A\">" (html-file ,dest))',
+ \ ' ,@body',
+ \ ' (princ "</a>")))',
+ \ ''
+ \ ], getline(1, "$"))
+
+ enew!
+ let &cpoptions=save_copt
+ set nolisp
+endfunc
diff --git a/src/testdir/test_listchars.vim b/src/testdir/test_listchars.vim
new file mode 100644
index 0000000..2870f2d
--- /dev/null
+++ b/src/testdir/test_listchars.vim
@@ -0,0 +1,115 @@
+" Tests for 'listchars' display with 'list' and :list
+
+source view_util.vim
+
+func Test_listchars()
+ enew!
+ set ff=unix
+ set list
+
+ set listchars+=tab:>-,space:.,trail:<
+ call append(0, [
+ \ ' aa ',
+ \ ' bb ',
+ \ ' cccc ',
+ \ 'dd ee ',
+ \ ' '
+ \ ])
+ let expected = [
+ \ '>-------aa>-----$',
+ \ '..bb>---<<$',
+ \ '...cccc><$',
+ \ 'dd........ee<<>-$',
+ \ '<$'
+ \ ]
+ redraw!
+ for i in range(1, 5)
+ call cursor(i, 1)
+ call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$')))
+ endfor
+
+ set listchars-=trail:<
+ let expected = [
+ \ '>-------aa>-----$',
+ \ '..bb>---..$',
+ \ '...cccc>.$',
+ \ 'dd........ee..>-$',
+ \ '.$'
+ \ ]
+ redraw!
+ for i in range(1, 5)
+ call cursor(i, 1)
+ call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$')))
+ endfor
+
+ " tab with 3rd character.
+ set listchars-=tab:>-
+ set listchars+=tab:<=>,trail:-
+ let expected = [
+ \ '<======>aa<====>$',
+ \ '..bb<==>--$',
+ \ '...cccc>-$',
+ \ 'dd........ee--<>$',
+ \ '-$'
+ \ ]
+ redraw!
+ for i in range(1, 5)
+ call cursor(i, 1)
+ call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$')))
+ endfor
+
+ set listchars-=trail:-
+ let expected = [
+ \ '<======>aa<====>$',
+ \ '..bb<==>..$',
+ \ '...cccc>.$',
+ \ 'dd........ee..<>$',
+ \ '.$'
+ \ ]
+ redraw!
+ for i in range(1, 5)
+ call cursor(i, 1)
+ call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$')))
+ endfor
+
+ set listchars-=tab:<=>
+ set listchars+=tab:>-
+ set listchars+=trail:<
+ set nolist
+ normal ggdG
+ call append(0, [
+ \ ' fff ',
+ \ ' gg ',
+ \ ' h ',
+ \ 'iii ',
+ \ ])
+ let l = split(execute("%list"), "\n")
+ call assert_equal([
+ \ '..fff>--<<$',
+ \ '>-------gg>-----$',
+ \ '.....h>-$',
+ \ 'iii<<<<><<$', '$'], l)
+
+
+ " test nbsp
+ normal ggdG
+ set listchars=nbsp:X,trail:Y
+ set list
+ " Non-breaking space
+ let nbsp = nr2char(0xa0)
+ call append(0, [ ">".nbsp."<" ])
+
+ let expected = '>X< '
+
+ redraw!
+ call cursor(1, 1)
+ call assert_equal([expected], ScreenLines(1, virtcol('$')))
+
+ set listchars=nbsp:X
+ redraw!
+ call cursor(1, 1)
+ call assert_equal([expected], ScreenLines(1, virtcol('$')))
+
+ enew!
+ set listchars& ff&
+endfunc
diff --git a/src/testdir/test_listdict.vim b/src/testdir/test_listdict.vim
new file mode 100644
index 0000000..1af47d9
--- /dev/null
+++ b/src/testdir/test_listdict.vim
@@ -0,0 +1,653 @@
+" Tests for the List and Dict types
+
+func TearDown()
+ " Run garbage collection after every test
+ call test_garbagecollect_now()
+endfunc
+
+" Tests for List type
+
+" List creation
+func Test_list_create()
+ " Creating List directly with different types
+ let l = [1, 'as''d', [1, 2, function("strlen")], {'a': 1},]
+ call assert_equal("[1, 'as''d', [1, 2, function('strlen')], {'a': 1}]", string(l))
+ call assert_equal({'a' : 1}, l[-1])
+ call assert_equal(1, l[-4])
+ let x = 10
+ try
+ let x = l[-5]
+ catch
+ call assert_match('E684:', v:exception)
+ endtry
+ call assert_equal(10, x)
+endfunc
+
+" List slices
+func Test_list_slice()
+ let l = [1, 'as''d', [1, 2, function("strlen")], {'a': 1},]
+ call assert_equal([1, 'as''d', [1, 2, function('strlen')], {'a': 1}], l[:])
+ call assert_equal(['as''d', [1, 2, function('strlen')], {'a': 1}], l[1:])
+ call assert_equal([1, 'as''d', [1, 2, function('strlen')]], l[:-2])
+ call assert_equal([1, 'as''d', [1, 2, function('strlen')], {'a': 1}], l[0:8])
+ call assert_equal([], l[8:-1])
+endfunc
+
+" List identity
+func Test_list_identity()
+ let l = [1, 'as''d', [1, 2, function("strlen")], {'a': 1},]
+ let ll = l
+ let lx = copy(l)
+ call assert_true(l == ll)
+ call assert_false(l isnot ll)
+ call assert_true(l is ll)
+ call assert_true(l == lx)
+ call assert_false(l is lx)
+ call assert_true(l isnot lx)
+endfunc
+
+" removing items with :unlet
+func Test_list_unlet()
+ let l = [1, 'as''d', [1, 2, function("strlen")], {'a': 1},]
+ unlet l[2]
+ call assert_equal([1, 'as''d', {'a': 1}], l)
+ let l = range(8)
+ unlet l[:3]
+ unlet l[1:]
+ call assert_equal([4], l)
+
+ " removing items out of range: silently skip items that don't exist
+ let l = [0, 1, 2, 3]
+ call assert_fails('unlet l[2:1]', 'E684')
+ let l = [0, 1, 2, 3]
+ unlet l[2:2]
+ call assert_equal([0, 1, 3], l)
+ let l = [0, 1, 2, 3]
+ unlet l[2:3]
+ call assert_equal([0, 1], l)
+ let l = [0, 1, 2, 3]
+ unlet l[2:4]
+ call assert_equal([0, 1], l)
+ let l = [0, 1, 2, 3]
+ unlet l[2:5]
+ call assert_equal([0, 1], l)
+ let l = [0, 1, 2, 3]
+ call assert_fails('unlet l[-1:2]', 'E684')
+ let l = [0, 1, 2, 3]
+ unlet l[-2:2]
+ call assert_equal([0, 1, 3], l)
+ let l = [0, 1, 2, 3]
+ unlet l[-3:2]
+ call assert_equal([0, 3], l)
+ let l = [0, 1, 2, 3]
+ unlet l[-4:2]
+ call assert_equal([3], l)
+ let l = [0, 1, 2, 3]
+ unlet l[-5:2]
+ call assert_equal([3], l)
+ let l = [0, 1, 2, 3]
+ unlet l[-6:2]
+ call assert_equal([3], l)
+endfunc
+
+" assignment to a list
+func Test_list_assign()
+ let l = [0, 1, 2, 3]
+ let [va, vb] = l[2:3]
+ call assert_equal([2, 3], [va, vb])
+ call assert_fails('let [va, vb] = l', 'E687')
+ call assert_fails('let [va, vb] = l[1:1]', 'E688')
+endfunc
+
+" test for range assign
+func Test_list_range_assign()
+ let l = [0]
+ let l[:] = [1, 2]
+ call assert_equal([1, 2], l)
+endfunc
+
+" Test removing items in list
+func Test_list_func_remove()
+ " Test removing 1 element
+ let l = [1, 2, 3, 4]
+ call assert_equal(1, remove(l, 0))
+ call assert_equal([2, 3, 4], l)
+
+ let l = [1, 2, 3, 4]
+ call assert_equal(2, remove(l, 1))
+ call assert_equal([1, 3, 4], l)
+
+ let l = [1, 2, 3, 4]
+ call assert_equal(4, remove(l, -1))
+ call assert_equal([1, 2, 3], l)
+
+ " Test removing range of element(s)
+ let l = [1, 2, 3, 4]
+ call assert_equal([3], remove(l, 2, 2))
+ call assert_equal([1, 2, 4], l)
+
+ let l = [1, 2, 3, 4]
+ call assert_equal([2, 3], remove(l, 1, 2))
+ call assert_equal([1, 4], l)
+
+ let l = [1, 2, 3, 4]
+ call assert_equal([2, 3], remove(l, -3, -2))
+ call assert_equal([1, 4], l)
+
+ " Test invalid cases
+ let l = [1, 2, 3, 4]
+ call assert_fails("call remove(l, 5)", 'E684:')
+ call assert_fails("call remove(l, 1, 5)", 'E684:')
+ call assert_fails("call remove(l, 3, 2)", 'E16:')
+ call assert_fails("call remove(1, 0)", 'E896:')
+ call assert_fails("call remove(l, l)", 'E745:')
+endfunc
+
+" Tests for Dictionary type
+
+func Test_dict()
+ " Creating Dictionary directly with different types
+ let d = {001: 'asd', 'b': [1, 2, function('strlen')], -1: {'a': 1},}
+ call assert_equal("{'1': 'asd', 'b': [1, 2, function('strlen')], '-1': {'a': 1}}", string(d))
+ call assert_equal('asd', d.1)
+ call assert_equal(['-1', '1', 'b'], sort(keys(d)))
+ call assert_equal(['asd', [1, 2, function('strlen')], {'a': 1}], values(d))
+ let v = []
+ for [key, val] in items(d)
+ call extend(v, [key, val])
+ unlet key val
+ endfor
+ call assert_equal(['1','asd','b',[1, 2, function('strlen')],'-1',{'a': 1}], v)
+
+ call extend(d, {3:33, 1:99})
+ call extend(d, {'b':'bbb', 'c':'ccc'}, "keep")
+ call assert_fails("call extend(d, {3:333,4:444}, 'error')", 'E737')
+ call assert_equal({'c': 'ccc', '1': 99, 'b': [1, 2, function('strlen')], '3': 33, '-1': {'a': 1}}, d)
+ call filter(d, 'v:key =~ ''[ac391]''')
+ call assert_equal({'c': 'ccc', '1': 99, '3': 33, '-1': {'a': 1}}, d)
+endfunc
+
+" Dictionary identity
+func Test_dict_identity()
+ let d = {001: 'asd', 'b': [1, 2, function('strlen')], -1: {'a': 1},}
+ let dd = d
+ let dx = copy(d)
+ call assert_true(d == dd)
+ call assert_false(d isnot dd)
+ call assert_true(d is dd)
+ call assert_true(d == dx)
+ call assert_false(d is dx)
+ call assert_true(d isnot dx)
+endfunc
+
+" removing items with :unlet
+func Test_dict_unlet()
+ let d = {'b':'bbb', '1': 99, '3': 33, '-1': {'a': 1}}
+ unlet d.b
+ unlet d[-1]
+ call assert_equal({'1': 99, '3': 33}, d)
+endfunc
+
+" manipulating a big Dictionary (hashtable.c has a border of 1000 entries)
+func Test_dict_big()
+ let d = {}
+ for i in range(1500)
+ let d[i] = 3000 - i
+ endfor
+ call assert_equal([3000, 2900, 2001, 1600, 1501], [d[0], d[100], d[999], d[1400], d[1499]])
+ let str = ''
+ try
+ let n = d[1500]
+ catch
+ let str=substitute(v:exception, '\v(.{14}).*( \d{4}).*', '\1\2', '')
+ endtry
+ call assert_equal('Vim(let):E716: 1500', str)
+
+ " lookup each items
+ for i in range(1500)
+ call assert_equal(3000 - i, d[i])
+ endfor
+ let i += 1
+
+ " delete even items
+ while i >= 2
+ let i -= 2
+ unlet d[i]
+ endwhile
+ call assert_equal('NONE', get(d, 1500 - 100, 'NONE'))
+ call assert_equal(2999, d[1])
+
+ " delete odd items, checking value, one intentionally wrong
+ let d[33] = 999
+ let i = 1
+ while i < 1500
+ if i != 33
+ call assert_equal(3000 - i, d[i])
+ else
+ call assert_equal(999, d[i])
+ endif
+ unlet d[i]
+ let i += 2
+ endwhile
+ call assert_equal({}, d)
+ unlet d
+endfunc
+
+" Dictionary function
+func Test_dict_func()
+ let d = {}
+ func d.func(a) dict
+ return a:a . len(self.data)
+ endfunc
+ let d.data = [1,2,3]
+ call assert_equal('len: 3', d.func('len: '))
+ let x = d.func('again: ')
+ call assert_equal('again: 3', x)
+ let Fn = d.func
+ call assert_equal('xxx3', Fn('xxx'))
+endfunc
+
+" Function in script-local List or Dict
+func Test_script_local_dict_func()
+ let g:dict = {}
+ function g:dict.func() dict
+ return 'g:dict.func' . self.foo[1] . self.foo[0]('asdf')
+ endfunc
+ let g:dict.foo = ['-', 2, 3]
+ call insert(g:dict.foo, function('strlen'))
+ call assert_equal('g:dict.func-4', g:dict.func())
+ unlet g:dict
+endfunc
+
+" Test removing items in la dictionary
+func Test_dict_func_remove()
+ let d = {1:'a', 2:'b', 3:'c'}
+ call assert_equal('b', remove(d, 2))
+ call assert_equal({1:'a', 3:'c'}, d)
+
+ call assert_fails("call remove(d, 1, 2)", 'E118:')
+ call assert_fails("call remove(d, 'a')", 'E716:')
+ call assert_fails("call remove(d, [])", 'E730:')
+endfunc
+
+" Nasty: remove func from Dict that's being called (works)
+func Test_dict_func_remove_in_use()
+ let d = {1:1}
+ func d.func(a)
+ return "a:" . a:a
+ endfunc
+ let expected = 'a:' . string(get(d, 'func'))
+ call assert_equal(expected, d.func(string(remove(d, 'func'))))
+endfunc
+
+" Nasty: deepcopy() dict that refers to itself (fails when noref used)
+func Test_dict_deepcopy()
+ let d = {1:1, 2:2}
+ let l = [4, d, 6]
+ let d[3] = l
+ let dc = deepcopy(d)
+ call assert_fails('call deepcopy(d, 1)', 'E698')
+ let l2 = [0, l, l, 3]
+ let l[1] = l2
+ let l3 = deepcopy(l2)
+ call assert_true(l3[1] is l3[2])
+endfunc
+
+" Locked variables
+func Test_list_locked_var()
+ let expected = [
+ \ [['0000-000', 'ppppppp'],
+ \ ['0000-000', 'ppppppp'],
+ \ ['0000-000', 'ppppppp']],
+ \ [['1000-000', 'ppppppF'],
+ \ ['0000-000', 'ppppppp'],
+ \ ['0000-000', 'ppppppp']],
+ \ [['1100-100', 'ppFppFF'],
+ \ ['0000-000', 'ppppppp'],
+ \ ['0000-000', 'ppppppp']],
+ \ [['1110-110', 'pFFpFFF'],
+ \ ['0010-010', 'pFppFpp'],
+ \ ['0000-000', 'ppppppp']],
+ \ [['1111-111', 'FFFFFFF'],
+ \ ['0011-011', 'FFpFFpp'],
+ \ ['0000-000', 'ppppppp']]
+ \ ]
+ for depth in range(5)
+ for u in range(3)
+ unlet! l
+ let l = [0, [1, [2, 3]], {4: 5, 6: {7: 8}}]
+ exe "lockvar " . depth . " l"
+ if u == 1
+ exe "unlockvar l"
+ elseif u == 2
+ exe "unlockvar " . depth . " l"
+ endif
+ let ps = islocked("l").islocked("l[1]").islocked("l[1][1]").islocked("l[1][1][0]").'-'.islocked("l[2]").islocked("l[2]['6']").islocked("l[2]['6'][7]")
+ call assert_equal(expected[depth][u][0], ps)
+ let ps = ''
+ try
+ let l[1][1][0] = 99
+ let ps .= 'p'
+ catch
+ let ps .= 'F'
+ endtry
+ try
+ let l[1][1] = [99]
+ let ps .= 'p'
+ catch
+ let ps .= 'F'
+ endtry
+ try
+ let l[1] = [99]
+ let ps .= 'p'
+ catch
+ let ps .= 'F'
+ endtry
+ try
+ let l[2]['6'][7] = 99
+ let ps .= 'p'
+ catch
+ let ps .= 'F'
+ endtry
+ try
+ let l[2][6] = {99: 99}
+ let ps .= 'p'
+ catch
+ let ps .= 'F'
+ endtry
+ try
+ let l[2] = {99: 99}
+ let ps .= 'p'
+ catch
+ let ps .= 'F'
+ endtry
+ try
+ let l = [99]
+ let ps .= 'p'
+ catch
+ let ps .= 'F'
+ endtry
+ call assert_equal(expected[depth][u][1], ps)
+ endfor
+ endfor
+endfunc
+
+" Unletting locked variables
+func Test_list_locked_var_unlet()
+ let expected = [
+ \ [['0000-000', 'ppppppp'],
+ \ ['0000-000', 'ppppppp'],
+ \ ['0000-000', 'ppppppp']],
+ \ [['1000-000', 'ppFppFp'],
+ \ ['0000-000', 'ppppppp'],
+ \ ['0000-000', 'ppppppp']],
+ \ [['1100-100', 'pFFpFFp'],
+ \ ['0000-000', 'ppppppp'],
+ \ ['0000-000', 'ppppppp']],
+ \ [['1110-110', 'FFFFFFp'],
+ \ ['0010-010', 'FppFppp'],
+ \ ['0000-000', 'ppppppp']],
+ \ [['1111-111', 'FFFFFFp'],
+ \ ['0011-011', 'FppFppp'],
+ \ ['0000-000', 'ppppppp']]
+ \ ]
+
+ for depth in range(5)
+ for u in range(3)
+ unlet! l
+ let l = [0, [1, [2, 3]], {4: 5, 6: {7: 8}}]
+ exe "lockvar " . depth . " l"
+ if u == 1
+ exe "unlockvar l"
+ elseif u == 2
+ exe "unlockvar " . depth . " l"
+ endif
+ let ps = islocked("l").islocked("l[1]").islocked("l[1][1]").islocked("l[1][1][0]").'-'.islocked("l[2]").islocked("l[2]['6']").islocked("l[2]['6'][7]")
+ call assert_equal(expected[depth][u][0], ps)
+ let ps = ''
+ try
+ unlet l[2]['6'][7]
+ let ps .= 'p'
+ catch
+ let ps .= 'F'
+ endtry
+ try
+ unlet l[2][6]
+ let ps .= 'p'
+ catch
+ let ps .= 'F'
+ endtry
+ try
+ unlet l[2]
+ let ps .= 'p'
+ catch
+ let ps .= 'F'
+ endtry
+ try
+ unlet l[1][1][0]
+ let ps .= 'p'
+ catch
+ let ps .= 'F'
+ endtry
+ try
+ unlet l[1][1]
+ let ps .= 'p'
+ catch
+ let ps .= 'F'
+ endtry
+ try
+ unlet l[1]
+ let ps .= 'p'
+ catch
+ let ps .= 'F'
+ endtry
+ try
+ unlet l
+ let ps .= 'p'
+ catch
+ let ps .= 'F'
+ endtry
+ call assert_equal(expected[depth][u][1], ps)
+ endfor
+ endfor
+endfunc
+
+" Locked variables and :unlet or list / dict functions
+
+" No :unlet after lock on dict:
+func Test_dict_lock_unlet()
+ unlet! d
+ let d = {'a': 99, 'b': 100}
+ lockvar 1 d
+ call assert_fails('unlet d.a', 'E741')
+endfunc
+
+" unlet after lock on dict item
+func Test_dict_item_lock_unlet()
+ unlet! d
+ let d = {'a': 99, 'b': 100}
+ lockvar d.a
+ unlet d.a
+ call assert_equal({'b' : 100}, d)
+endfunc
+
+" filter() after lock on dict item
+func Test_dict_lock_filter()
+ unlet! d
+ let d = {'a': 99, 'b': 100}
+ lockvar d.a
+ call filter(d, 'v:key != "a"')
+ call assert_equal({'b' : 100}, d)
+endfunc
+
+" map() after lock on dict
+func Test_dict_lock_map()
+ unlet! d
+ let d = {'a': 99, 'b': 100}
+ lockvar 1 d
+ call map(d, 'v:val + 200')
+ call assert_equal({'a' : 299, 'b' : 300}, d)
+endfunc
+
+" No extend() after lock on dict item
+func Test_dict_lock_extend()
+ unlet! d
+ let d = {'a': 99, 'b': 100}
+ lockvar d.a
+ call assert_fails("call extend(d, {'a' : 123})", 'E741')
+ call assert_equal({'a': 99, 'b': 100}, d)
+endfunc
+
+" No remove() of write-protected scope-level variable
+func Tfunc1(this_is_a_long_parameter_name)
+ call assert_fails("call remove(a:, 'this_is_a_long_parameter_name')", 'E795')
+endfunc
+func Test_dict_scope_var_remove()
+ call Tfunc1('testval')
+endfunc
+
+" No extend() of write-protected scope-level variable
+func Tfunc2(this_is_a_long_parameter_name)
+ call assert_fails("call extend(a:, {'this_is_a_long_parameter_name': 1234})", 'E742')
+endfunc
+func Test_dict_scope_var_extend()
+ call Tfunc2('testval')
+endfunc
+
+" No :unlet of variable in locked scope
+func Test_lock_var_unlet()
+ let b:testvar = 123
+ lockvar 1 b:
+ call assert_fails('unlet b:testvar', 'E741:')
+ unlockvar 1 b:
+ unlet! b:testvar
+endfunc
+
+" No :let += of locked list variable
+func Test_let_lock_list()
+ let l = ['a', 'b', 3]
+ lockvar 1 l
+ call assert_fails("let l += ['x']", 'E741:')
+ call assert_equal(['a', 'b', 3], l)
+
+ unlet l
+ let l = [1, 2, 3, 4]
+ lockvar! l
+ call assert_equal([1, 2, 3, 4], l)
+ unlockvar l[1]
+ call assert_fails('unlet l[0:1]', 'E741:')
+ call assert_equal([1, 2, 3, 4], l)
+ call assert_fails('unlet l[1:2]', 'E741:')
+ call assert_equal([1, 2, 3, 4], l)
+ unlockvar l[1]
+ call assert_fails('let l[0:1] = [0, 1]', 'E741:')
+ call assert_equal([1, 2, 3, 4], l)
+ call assert_fails('let l[1:2] = [0, 1]', 'E741:')
+ call assert_equal([1, 2, 3, 4], l)
+ unlet l
+endfunc
+
+" lockvar/islocked() triggering script autoloading
+func Test_lockvar_script_autoload()
+ let old_rtp = &rtp
+ set rtp+=./sautest
+ lockvar g:footest#x
+ unlockvar g:footest#x
+ call assert_equal(-1, islocked('g:footest#x'))
+ call assert_equal(0, exists('g:footest#x'))
+ call assert_equal(1, g:footest#x)
+ let &rtp = old_rtp
+endfunc
+
+" a:000 function argument test
+func s:arg_list_test(...)
+ call assert_fails('let a:000 = [1, 2]', 'E46:')
+ call assert_fails('let a:000[0] = 9', 'E742:')
+ call assert_fails('let a:000[2] = [9, 10]', 'E742:')
+ call assert_fails('let a:000[3] = {9 : 10}', 'E742:')
+
+ " now the tests that should pass
+ let a:000[2][1] = 9
+ call extend(a:000[2], [5, 6])
+ let a:000[3][5] = 8
+ let a:000[3]['a'] = 12
+ call assert_equal([1, 2, [3, 9, 5, 6], {'a': 12, '5': 8}], a:000)
+endfunc
+
+func Test_func_arg_list()
+ call s:arg_list_test(1, 2, [3, 4], {5: 6})
+endfunc
+
+" Tests for reverse(), sort(), uniq()
+func Test_reverse_sort_uniq()
+ let l = ['-0', 'A11', 2, 2, 'xaaa', 4, 'foo', 'foo6', 'foo', [0, 1, 2], 'x8', [0, 1, 2], 1.5]
+ call assert_equal(['-0', 'A11', 2, 'xaaa', 4, 'foo', 'foo6', 'foo', [0, 1, 2], 'x8', [0, 1, 2], 1.5], uniq(copy(l)))
+ call assert_equal([1.5, [0, 1, 2], 'x8', [0, 1, 2], 'foo', 'foo6', 'foo', 4, 'xaaa', 2, 2, 'A11', '-0'], reverse(l))
+ call assert_equal([1.5, [0, 1, 2], 'x8', [0, 1, 2], 'foo', 'foo6', 'foo', 4, 'xaaa', 2, 2, 'A11', '-0'], reverse(reverse(l)))
+ call assert_equal(['-0', 'A11', 'foo', 'foo', 'foo6', 'x8', 'xaaa', 1.5, 2, 2, 4, [0, 1, 2], [0, 1, 2]], sort(l))
+ call assert_equal([[0, 1, 2], [0, 1, 2], 4, 2, 2, 1.5, 'xaaa', 'x8', 'foo6', 'foo', 'foo', 'A11', '-0'], reverse(sort(l)))
+ call assert_equal(['-0', 'A11', 'foo', 'foo', 'foo6', 'x8', 'xaaa', 1.5, 2, 2, 4, [0, 1, 2], [0, 1, 2]], sort(reverse(sort(l))))
+ call assert_equal(['-0', 'A11', 'foo', 'foo6', 'x8', 'xaaa', 1.5, 2, 4, [0, 1, 2]], uniq(sort(l)))
+
+ let l=[7, 9, 'one', 18, 12, 22, 'two', 10.0e-16, -1, 'three', 0xff, 0.22, 'four']
+ call assert_equal([-1, 'one', 'two', 'three', 'four', 1.0e-15, 0.22, 7, 9, 12, 18, 22, 255], sort(copy(l), 'n'))
+
+ let l=[7, 9, 18, 12, 22, 10.0e-16, -1, 0xff, 0, -0, 0.22, 'bar', 'BAR', 'Bar', 'Foo', 'FOO', 'foo', 'FOOBAR', {}, []]
+ call assert_equal(['bar', 'BAR', 'Bar', 'Foo', 'FOO', 'foo', 'FOOBAR', -1, 0, 0, 0.22, 1.0e-15, 12, 18, 22, 255, 7, 9, [], {}], sort(copy(l), 1))
+ call assert_equal(['bar', 'BAR', 'Bar', 'Foo', 'FOO', 'foo', 'FOOBAR', -1, 0, 0, 0.22, 1.0e-15, 12, 18, 22, 255, 7, 9, [], {}], sort(copy(l), 'i'))
+ call assert_equal(['BAR', 'Bar', 'FOO', 'FOOBAR', 'Foo', 'bar', 'foo', -1, 0, 0, 0.22, 1.0e-15, 12, 18, 22, 255, 7, 9, [], {}], sort(copy(l)))
+
+ call assert_fails('call reverse("")', 'E899:')
+endfunc
+
+" splitting a string to a List
+func Test_str_split()
+ call assert_equal(['aa', 'bb'], split(' aa bb '))
+ call assert_equal(['aa', 'bb'], split(' aa bb ', '\W\+', 0))
+ call assert_equal(['', 'aa', 'bb', ''], split(' aa bb ', '\W\+', 1))
+ call assert_equal(['', '', 'aa', '', 'bb', '', ''], split(' aa bb ', '\W', 1))
+ call assert_equal(['aa', '', 'bb'], split(':aa::bb:', ':', 0))
+ call assert_equal(['', 'aa', '', 'bb', ''], split(':aa::bb:', ':', 1))
+ call assert_equal(['aa', '', 'bb', 'cc', ''], split('aa,,bb, cc,', ',\s*', 1))
+ call assert_equal(['a', 'b', 'c'], split('abc', '\zs'))
+ call assert_equal(['', 'a', '', 'b', '', 'c', ''], split('abc', '\zs', 1))
+endfunc
+
+" compare recursively linked list and dict
+func Test_listdict_compare()
+ let l = [1, 2, 3, 4]
+ let d = {'1': 1, '2': l, '3': 3}
+ let l[1] = d
+ call assert_true(l == l)
+ call assert_true(d == d)
+ call assert_false(l != deepcopy(l))
+ call assert_false(d != deepcopy(d))
+endfunc
+
+ " compare complex recursively linked list and dict
+func Test_listdict_compare_complex()
+ let l = []
+ call add(l, l)
+ let dict4 = {"l": l}
+ call add(dict4.l, dict4)
+ let lcopy = deepcopy(l)
+ let dict4copy = deepcopy(dict4)
+ call assert_true(l == lcopy)
+ call assert_true(dict4 == dict4copy)
+endfunc
+
+func Test_listdict_extend()
+ " Pass the same List to extend()
+ let l = [1, 2, 3, 4, 5]
+ call extend(l, l)
+ call assert_equal([1, 2, 3, 4, 5, 1, 2, 3, 4, 5], l)
+
+ " Pass the same Dict to extend()
+ let d = { 'a': {'b': 'B'}}
+ call extend(d, d)
+ call assert_equal({'a': {'b': 'B'}}, d)
+
+ " Pass the same Dict to extend() with "error"
+ call assert_fails("call extend(d, d, 'error')", 'E737:')
+ call assert_equal({'a': {'b': 'B'}}, d)
+endfunc
diff --git a/src/testdir/test_listlbr.vim b/src/testdir/test_listlbr.vim
new file mode 100644
index 0000000..29e797d
--- /dev/null
+++ b/src/testdir/test_listlbr.vim
@@ -0,0 +1,235 @@
+" Test for linebreak and list option (non-utf8)
+
+set encoding=latin1
+scriptencoding latin1
+
+if !exists("+linebreak") || !has("conceal")
+ finish
+endif
+
+source view_util.vim
+
+function s:screen_lines(lnum, width) abort
+ return ScreenLines(a:lnum, a:width)
+endfunction
+
+func s:compare_lines(expect, actual)
+ call assert_equal(join(a:expect, "\n"), join(a:actual, "\n"))
+endfunc
+
+function s:test_windows(...)
+ call NewWindow(10, 20)
+ setl ts=8 sw=4 sts=4 linebreak sbr= wrap
+ exe get(a:000, 0, '')
+endfunction
+
+function s:close_windows(...)
+ call CloseWindow()
+ exe get(a:000, 0, '')
+endfunction
+
+func Test_set_linebreak()
+ call s:test_windows('setl ts=4 sbr=+')
+ call setline(1, "\tabcdef hijklmn\tpqrstuvwxyz_1060ABCDEFGHIJKLMNOP ")
+ let lines = s:screen_lines([1, 4], winwidth(0))
+ let expect = [
+\ " abcdef ",
+\ "+hijklmn ",
+\ "+pqrstuvwxyz_1060ABC",
+\ "+DEFGHIJKLMNOP ",
+\ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows()
+endfunc
+
+func Test_linebreak_with_list()
+ call s:test_windows('setl ts=4 sbr=+ list listchars=')
+ call setline(1, "\tabcdef hijklmn\tpqrstuvwxyz_1060ABCDEFGHIJKLMNOP ")
+ let lines = s:screen_lines([1, 4], winwidth(0))
+ let expect = [
+\ "^Iabcdef hijklmn^I ",
+\ "+pqrstuvwxyz_1060ABC",
+\ "+DEFGHIJKLMNOP ",
+\ "~ ",
+\ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows()
+endfunc
+
+func Test_linebreak_with_nolist()
+ call s:test_windows('setl ts=4 sbr=+ nolist')
+ call setline(1, "\tabcdef hijklmn\tpqrstuvwxyz_1060ABCDEFGHIJKLMNOP ")
+ let lines = s:screen_lines([1, 4], winwidth(0))
+ let expect = [
+\ " abcdef ",
+\ "+hijklmn ",
+\ "+pqrstuvwxyz_1060ABC",
+\ "+DEFGHIJKLMNOP ",
+\ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows()
+endfunc
+
+func Test_should_break()
+ call s:test_windows('setl sbr=+ nolist')
+ call setline(1, "1\t" . repeat('a', winwidth(0)-2))
+ let lines = s:screen_lines([1, 4], winwidth(0))
+ let expect = [
+\ "1 ",
+\ "+aaaaaaaaaaaaaaaaaa ",
+\ "~ ",
+\ "~ ",
+\ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows()
+endfunc
+
+func Test_linebreak_with_conceal()
+ call s:test_windows('setl cpo&vim sbr=+ list conceallevel=2 concealcursor=nv listchars=tab:ab')
+ call setline(1, "_S_\t bla")
+ syn match ConcealVar contained /_/ conceal
+ syn match All /.*/ contains=ConcealVar
+ let lines = s:screen_lines([1, 4], winwidth(0))
+ let expect = [
+\ "Sabbbbbb bla ",
+\ "~ ",
+\ "~ ",
+\ "~ ",
+\ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows()
+endfunc
+
+func Test_virtual_block()
+ call s:test_windows('setl sbr=+')
+ call setline(1, [
+\ "REMOVE: this not",
+\ "REMOVE: aaaaaaaaaaaaa",
+\ ])
+ exe "norm! 1/^REMOVE:"
+ exe "norm! 0\<C-V>jf x"
+ $put
+ let lines = s:screen_lines([1, 4], winwidth(0))
+ let expect = [
+\ "this not ",
+\ "aaaaaaaaaaaaa ",
+\ "REMOVE: ",
+\ "REMOVE: ",
+\ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows()
+endfunc
+
+func Test_virtual_block_and_vbA()
+ call s:test_windows()
+ call setline(1, "long line: " . repeat("foobar ", 40) . "TARGET at end")
+ exe "norm! $3B\<C-v>eAx\<Esc>"
+ let lines = s:screen_lines([1, 10], winwidth(0))
+ let expect = [
+\ "foobar foobar ",
+\ "foobar foobar ",
+\ "foobar foobar ",
+\ "foobar foobar ",
+\ "foobar foobar ",
+\ "foobar foobar ",
+\ "foobar foobar ",
+\ "foobar foobar ",
+\ "foobar foobar ",
+\ "foobar TARGETx at ",
+\ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows()
+endfunc
+
+func Test_virtual_char_and_block()
+ call s:test_windows()
+ call setline(1, "1111-1111-1111-11-1111-1111-1111")
+ exe "norm! 0f-lv3lc2222\<Esc>bgj."
+ let lines = s:screen_lines([1, 2], winwidth(0))
+ let expect = [
+\ "1111-2222-1111-11- ",
+\ "1111-2222-1111 ",
+\ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows()
+endfunc
+
+func Test_undo_after_block_visual()
+ call s:test_windows()
+ call setline(1, ["aaa", "aaa", "a"])
+ exe "norm! gg\<C-V>2j~e."
+ let lines = s:screen_lines([1, 3], winwidth(0))
+ let expect = [
+\ "AaA ",
+\ "AaA ",
+\ "A ",
+\ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows()
+endfunc
+
+func Test_norm_after_block_visual()
+ call s:test_windows()
+ call setline(1, ["abcd{ef", "ghijklm", "no}pgrs"])
+ exe "norm! ggf{\<C-V>\<C-V>c%"
+ let lines = s:screen_lines([1, 3], winwidth(0))
+ let expect = [
+\ "abcdpgrs ",
+\ "~ ",
+\ "~ ",
+\ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows()
+endfunc
+
+func Test_block_replace_after_wrapping()
+ call s:test_windows()
+ call setline(1, repeat("a", 150))
+ exe "norm! 0yypk147|\<C-V>jr0"
+ call assert_equal(repeat("a", 146) . "0aaa", getline(1))
+ call assert_equal(repeat("a", 146) . "0aaa", getline(2))
+ let lines = s:screen_lines([1, 10], winwidth(0))
+ let expect = [
+\ "aaaaaaaaaaaaaaaaaaaa",
+\ "aaaaaaaaaaaaaaaaaaaa",
+\ "aaaaaaaaaaaaaaaaaaaa",
+\ "aaaaaaaaaaaaaaaaaaaa",
+\ "aaaaaaaaaaaaaaaaaaaa",
+\ "aaaaaaaaaaaaaaaaaaaa",
+\ "aaaaaaaaaaaaaaaaaaaa",
+\ "aaaaaa0aaa ",
+\ "@ ",
+\ "@ ",
+\ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows()
+endfunc
+
+func Test_list_with_listchars()
+ call s:test_windows('setl list listchars=space:_,trail:-,tab:>-,eol:$')
+ call setline(1, "a aaaaaaaaaaaaaaaaaaaaaa\ta ")
+ let lines = s:screen_lines([1, 3], winwidth(0))
+ let expect = [
+\ "a_ ",
+\ "aaaaaaaaaaaaaaaaaaaa",
+\ "aa>-----a-$ ",
+\ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows()
+endfunc
+
+func Test_list_with_tab_and_skipping_first_chars()
+ call s:test_windows('setl list listchars=tab:>- ts=70 nowrap')
+ call setline(1, ["iiiiiiiiiiiiiiii\taaaaaaaaaaaaaaaaaa", "iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii\taaaaaaaaaaaaaaaaaa", "iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii\taaaaaaaaaaaaaaaaaa", "iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii\taaaaaaaaaaaaaaaaaa"])
+ call cursor(4,64)
+ norm! 2zl
+ let lines = s:screen_lines([1, 4], winwidth(0))
+ let expect = [
+\ "---------------aaaaa",
+\ "---------------aaaaa",
+\ "---------------aaaaa",
+\ "iiiiiiiii>-----aaaaa",
+\ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows()
+endfu
diff --git a/src/testdir/test_listlbr_utf8.vim b/src/testdir/test_listlbr_utf8.vim
new file mode 100644
index 0000000..c38e0c5
--- /dev/null
+++ b/src/testdir/test_listlbr_utf8.vim
@@ -0,0 +1,271 @@
+" Test for linebreak and list option in utf-8 mode
+
+set encoding=utf-8
+scriptencoding utf-8
+
+if !exists("+linebreak") || !has("conceal") || !has("signs")
+ finish
+endif
+
+source view_util.vim
+
+func s:screen_lines(lnum, width) abort
+ return ScreenLines(a:lnum, a:width)
+endfunc
+
+func s:compare_lines(expect, actual)
+ call assert_equal(a:expect, a:actual)
+endfunc
+
+func s:screen_attr(lnum, chars, ...) abort
+ let line = getline(a:lnum)
+ let attr = []
+ let prefix = get(a:000, 0, 0)
+ for i in range(a:chars[0], a:chars[1])
+ let scol = strdisplaywidth(strcharpart(line, 0, i-1)) + 1
+ let attr += [screenattr(a:lnum, scol + prefix)]
+ endfor
+ return attr
+endfunc
+
+func s:test_windows(...)
+ call NewWindow(10, 20)
+ setl ts=4 sw=4 sts=4 linebreak sbr=+ wrap
+ exe get(a:000, 0, '')
+endfunc
+
+func s:close_windows(...)
+ call CloseWindow()
+ exe get(a:000, 0, '')
+endfunc
+
+func Test_linebreak_with_fancy_listchars()
+ call s:test_windows("setl list listchars=nbsp:\u2423,tab:\u2595\u2014,trail:\u02d1,eol:\ub6")
+ call setline(1, "\tabcdef hijklmn\tpqrstuvwxyz\u00a01060ABCDEFGHIJKLMNOP ")
+ redraw!
+ let lines = s:screen_lines([1, 4], winwidth(0))
+ let expect = [
+\ "▕———abcdef ",
+\ "+hijklmn▕——— ",
+\ "+pqrstuvwxyzâ£1060ABC",
+\ "+DEFGHIJKLMNOPˑ¶ ",
+\ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows()
+endfunc
+
+func Test_nolinebreak_with_list()
+ call s:test_windows("setl nolinebreak list listchars=nbsp:\u2423,tab:\u2595\u2014,trail:\u02d1,eol:\ub6")
+ call setline(1, "\tabcdef hijklmn\tpqrstuvwxyz\u00a01060ABCDEFGHIJKLMNOP ")
+ redraw!
+ let lines = s:screen_lines([1, 4], winwidth(0))
+ let expect = [
+\ "▕———abcdef hijklmn▕—",
+\ "+pqrstuvwxyzâ£1060ABC",
+\ "+DEFGHIJKLMNOPˑ¶ ",
+\ "~ ",
+\ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows()
+endfunc
+
+func Test_linebreak_with_nolist()
+ call s:test_windows('setl nolist')
+ call setline(1, "\t*mask = nil;")
+ redraw!
+ let lines = s:screen_lines([1, 4], winwidth(0))
+ let expect = [
+\ " *mask = nil; ",
+\ "~ ",
+\ "~ ",
+\ "~ ",
+\ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows()
+endfunc
+
+func Test_list_and_concealing1()
+ call s:test_windows('setl list listchars=tab:>- cole=1')
+ call setline(1, [
+\ "#define ABCDE\t\t1",
+\ "#define ABCDEF\t\t1",
+\ "#define ABCDEFG\t\t1",
+\ "#define ABCDEFGH\t1",
+\ "#define MSG_MODE_FILE\t\t\t1",
+\ "#define MSG_MODE_CONSOLE\t\t2",
+\ "#define MSG_MODE_FILE_AND_CONSOLE\t3",
+\ "#define MSG_MODE_FILE_THEN_CONSOLE\t4",
+\ ])
+ vert resize 40
+ syn match Conceal conceal cchar=>'AB\|MSG_MODE'
+ redraw!
+ let lines = s:screen_lines([1, 7], winwidth(0))
+ let expect = [
+\ "#define ABCDE>-->---1 ",
+\ "#define >CDEF>-->---1 ",
+\ "#define >CDEFG>->---1 ",
+\ "#define >CDEFGH>----1 ",
+\ "#define >_FILE>--------->--->---1 ",
+\ "#define >_CONSOLE>---------->---2 ",
+\ "#define >_FILE_AND_CONSOLE>---------3 ",
+\ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows()
+endfunc
+
+func Test_list_and_concealing2()
+ call s:test_windows('setl nowrap ts=2 list listchars=tab:>- cole=2 concealcursor=n')
+ call setline(1, "bbeeeeee\t\t;\tsome text")
+ vert resize 40
+ syn clear
+ syn match meaning /;\s*\zs.*/
+ syn match hasword /^\x\{8}/ contains=word
+ syn match word /\<\x\{8}\>/ contains=beginword,endword contained
+ syn match beginword /\<\x\x/ contained conceal
+ syn match endword /\x\{6}\>/ contained
+ hi meaning guibg=blue
+ hi beginword guibg=green
+ hi endword guibg=red
+ redraw!
+ let lines = s:screen_lines([1, 1], winwidth(0))
+ let expect = [
+\ "eeeeee>--->-;>some text ",
+\ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows()
+endfunc
+
+func Test_screenattr_for_comment()
+ call s:test_windows("setl ft=c ts=7 list listchars=nbsp:\u2423,tab:\u2595\u2014,trail:\u02d1,eol:\ub6")
+ call setline(1, " /*\t\t and some more */")
+ norm! gg0
+ syntax on
+ hi SpecialKey term=underline ctermfg=red guifg=red
+ redraw!
+ let line = getline(1)
+ let attr = s:screen_attr(1, [1, 6])
+ call assert_notequal(attr[0], attr[1])
+ call assert_notequal(attr[1], attr[3])
+ call assert_notequal(attr[3], attr[5])
+ call s:close_windows()
+endfunc
+
+func Test_visual_block_and_selection_exclusive()
+ call s:test_windows('setl selection=exclusive')
+ call setline(1, "long line: " . repeat("foobar ", 40) . "TARGETÃ' at end")
+ exe "norm! $3B\<C-v>eAx\<Esc>"
+ let lines = s:screen_lines([1, 10], winwidth(0))
+ let expect = [
+\ "+foobar foobar ",
+\ "+foobar foobar ",
+\ "+foobar foobar ",
+\ "+foobar foobar ",
+\ "+foobar foobar ",
+\ "+foobar foobar ",
+\ "+foobar foobar ",
+\ "+foobar foobar ",
+\ "+foobar foobar ",
+\ "+foobar TARGETÃx' ",
+\ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows()
+endfunc
+
+func Test_multibyte_sign_and_colorcolumn()
+ call s:test_windows("setl nolinebreak cc=3 list listchars=nbsp:\u2423,tab:\u2595\u2014,trail:\u02d1,eol:\ub6")
+ call setline(1, ["", "a b c", "a b c"])
+ exe "sign define foo text=\uff0b"
+ exe "sign place 1 name=foo line=2 buffer=" . bufnr('%')
+ redraw!
+ norm! ggj0
+ let signwidth = strdisplaywidth("\uff0b")
+ let attr1 = s:screen_attr(2, [1, 3], signwidth)
+ let attr2 = s:screen_attr(3, [1, 3], signwidth)
+ call assert_equal(attr1[0], attr2[0])
+ call assert_equal(attr1[1], attr2[1])
+ call assert_equal(attr1[2], attr2[2])
+ let lines = s:screen_lines([1, 3], winwidth(0))
+ let expect = [
+\ " ¶ ",
+\ "+a b c¶ ",
+\ " a b c¶ ",
+\ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows()
+endfunc
+
+func Test_colorcolumn_priority()
+ call s:test_windows('setl cc=4 cuc hls')
+ call setline(1, ["xxyy", ""])
+ norm! gg
+ exe "normal! /xxyy\<CR>"
+ norm! G
+ redraw!
+ let line_attr = s:screen_attr(1, [1, &cc])
+ " Search wins over CursorColumn
+ call assert_equal(line_attr[1], line_attr[0])
+ " Search wins over Colorcolumn
+ call assert_equal(line_attr[2], line_attr[3])
+ call s:close_windows('setl hls&vim')
+endfunc
+
+func Test_illegal_byte_and_breakat()
+ call s:test_windows("setl sbr= brk+=<")
+ vert resize 18
+ call setline(1, repeat("\x80", 6))
+ redraw!
+ let lines = s:screen_lines([1, 2], winwidth(0))
+ let expect = [
+\ "<80><80><80><80><8",
+\ "0><80> ",
+\ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows('setl brk&vim')
+endfunc
+
+func Test_multibyte_wrap_and_breakat()
+ call s:test_windows("setl sbr= brk+=>")
+ call setline(1, repeat('a', 17) . repeat('ã‚', 2))
+ redraw!
+ let lines = s:screen_lines([1, 2], winwidth(0))
+ let expect = [
+\ "aaaaaaaaaaaaaaaaaã‚>",
+\ "ã‚ ",
+\ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows('setl brk&vim')
+endfunc
+
+func Test_chinese_char_on_wrap_column()
+ call s:test_windows("setl nolbr wrap sbr=")
+ syntax off
+ call setline(1, [
+\ 'aaaaaaaaaaaaaaaaaaa中'.
+\ 'aaaaaaaaaaaaaaaaa中'.
+\ 'aaaaaaaaaaaaaaaaa中'.
+\ 'aaaaaaaaaaaaaaaaa中'.
+\ 'aaaaaaaaaaaaaaaaa中'.
+\ 'aaaaaaaaaaaaaaaaa中'.
+\ 'aaaaaaaaaaaaaaaaa中'.
+\ 'aaaaaaaaaaaaaaaaa中'.
+\ 'aaaaaaaaaaaaaaaaa中'.
+\ 'aaaaaaaaaaaaaaaaa中'.
+\ 'hello'])
+ call cursor(1,1)
+ norm! $
+ redraw!
+ let expect=[
+\ '中aaaaaaaaaaaaaaaaa>',
+\ '中aaaaaaaaaaaaaaaaa>',
+\ '中aaaaaaaaaaaaaaaaa>',
+\ '中aaaaaaaaaaaaaaaaa>',
+\ '中aaaaaaaaaaaaaaaaa>',
+\ '中aaaaaaaaaaaaaaaaa>',
+\ '中aaaaaaaaaaaaaaaaa>',
+\ '中aaaaaaaaaaaaaaaaa>',
+\ '中aaaaaaaaaaaaaaaaa>',
+\ '中hello ']
+ let lines = s:screen_lines([1, 10], winwidth(0))
+ call s:compare_lines(expect, lines)
+ call s:close_windows()
+endfu
diff --git a/src/testdir/test_lua.vim b/src/testdir/test_lua.vim
new file mode 100644
index 0000000..1a5c74f
--- /dev/null
+++ b/src/testdir/test_lua.vim
@@ -0,0 +1,575 @@
+" Tests for Lua.
+
+if !has('lua')
+ finish
+endif
+
+" Check that switching to another buffer does not trigger ml_get error.
+func Test_command_new_no_ml_get_error()
+ new
+ let wincount = winnr('$')
+ call setline(1, ['one', 'two', 'three'])
+ luado vim.command("new")
+ call assert_equal(wincount + 1, winnr('$'))
+ %bwipe!
+endfunc
+
+" Test vim.command()
+func Test_command()
+ new
+ call setline(1, ['one', 'two', 'three'])
+ luado vim.command("1,2d_")
+ call assert_equal(['three'], getline(1, '$'))
+ bwipe!
+endfunc
+
+" Test vim.eval()
+func Test_eval()
+ " lua.eval with a number
+ lua v = vim.eval('123')
+ call assert_equal('number', luaeval('vim.type(v)'))
+ call assert_equal(123.0, luaeval('v'))
+
+ " lua.eval with a string
+ lua v = vim.eval('"abc"')
+ call assert_equal('string', luaeval('vim.type(v)'))
+ call assert_equal('abc', luaeval('v'))
+
+ " lua.eval with a list
+ lua v = vim.eval("['a']")
+ call assert_equal('list', luaeval('vim.type(v)'))
+ call assert_equal(['a'], luaeval('v'))
+
+ " lua.eval with a dict
+ lua v = vim.eval("{'a':'b'}")
+ call assert_equal('dict', luaeval('vim.type(v)'))
+ call assert_equal({'a':'b'}, luaeval('v'))
+
+ call assert_fails('lua v = vim.eval(nil)',
+ \ "[string \"vim chunk\"]:1: bad argument #1 to 'eval' (string expected, got nil)")
+ call assert_fails('lua v = vim.eval(true)',
+ \ "[string \"vim chunk\"]:1: bad argument #1 to 'eval' (string expected, got boolean)")
+ call assert_fails('lua v = vim.eval({})',
+ \ "[string \"vim chunk\"]:1: bad argument #1 to 'eval' (string expected, got table)")
+ call assert_fails('lua v = vim.eval(print)',
+ \ "[string \"vim chunk\"]:1: bad argument #1 to 'eval' (string expected, got function)")
+ call assert_fails('lua v = vim.eval(vim.buffer())',
+ \ "[string \"vim chunk\"]:1: bad argument #1 to 'eval' (string expected, got userdata)")
+
+ lua v = nil
+endfunc
+
+" Test vim.window()
+func Test_window()
+ e Xfoo2
+ new Xfoo1
+
+ " Window 1 (top window) contains Xfoo1
+ " Window 2 (bottom window) contains Xfoo2
+ call assert_equal('Xfoo1', luaeval('vim.window(1):buffer().name'))
+ call assert_equal('Xfoo2', luaeval('vim.window(2):buffer().name'))
+
+ " Window 3 does not exist so vim.window(3) should return nil
+ call assert_equal('nil', luaeval('tostring(vim.window(3))'))
+
+ %bwipe!
+endfunc
+
+" Test vim.window().height
+func Test_window_height()
+ new
+ lua vim.window().height = 2
+ call assert_equal(2, winheight(0))
+ lua vim.window().height = vim.window().height + 1
+ call assert_equal(3, winheight(0))
+ bwipe!
+endfunc
+
+" Test vim.window().width
+func Test_window_width()
+ vert new
+ lua vim.window().width = 2
+ call assert_equal(2, winwidth(0))
+ lua vim.window().width = vim.window().width + 1
+ call assert_equal(3, winwidth(0))
+ bwipe!
+endfunc
+
+" Test vim.window().line and vim.window.col
+func Test_window_line_col()
+ new
+ call setline(1, ['line1', 'line2', 'line3'])
+ lua vim.window().line = 2
+ lua vim.window().col = 4
+ call assert_equal([0, 2, 4, 0], getpos('.'))
+ lua vim.window().line = vim.window().line + 1
+ lua vim.window().col = vim.window().col - 1
+ call assert_equal([0, 3, 3, 0], getpos('.'))
+
+ call assert_fails('lua vim.window().line = 10',
+ \ '[string "vim chunk"]:1: line out of range')
+ bwipe!
+endfunc
+
+" Test setting the current window
+func Test_window_set_current()
+ new Xfoo1
+ lua w1 = vim.window()
+ new Xfoo2
+ lua w2 = vim.window()
+
+ call assert_equal('Xfoo2', bufname('%'))
+ lua w1()
+ call assert_equal('Xfoo1', bufname('%'))
+ lua w2()
+ call assert_equal('Xfoo2', bufname('%'))
+
+ lua w1, w2 = nil
+ %bwipe!
+endfunc
+
+" Test vim.window().buffer
+func Test_window_buffer()
+ new Xfoo1
+ lua w1 = vim.window()
+ lua b1 = w1.buffer()
+ new Xfoo2
+ lua w2 = vim.window()
+ lua b2 = w2.buffer()
+
+ lua b1()
+ call assert_equal('Xfoo1', bufname('%'))
+ lua b2()
+ call assert_equal('Xfoo2', bufname('%'))
+
+ lua b1, b2, w1, w2 = nil
+ %bwipe!
+endfunc
+
+" Test vim.window():previous() and vim.window():next()
+func Test_window_next_previous()
+ new Xfoo1
+ new Xfoo2
+ new Xfoo3
+ wincmd j
+
+ call assert_equal('Xfoo2', luaeval('vim.window().buffer().name'))
+ call assert_equal('Xfoo1', luaeval('vim.window():next():buffer().name'))
+ call assert_equal('Xfoo3', luaeval('vim.window():previous():buffer().name'))
+
+ %bwipe!
+endfunc
+
+" Test vim.window():isvalid()
+func Test_window_isvalid()
+ new Xfoo
+ lua w = vim.window()
+ call assert_true(luaeval('w:isvalid()'))
+
+ " FIXME: how to test the case when isvalid() returns v:false?
+ " isvalid() gives errors when the window is deleted. Is it a bug?
+
+ lua w = nil
+ bwipe!
+endfunc
+
+" Test vim.buffer() with and without argument
+func Test_buffer()
+ new Xfoo1
+ let bn1 = bufnr('%')
+ new Xfoo2
+ let bn2 = bufnr('%')
+
+ " Test vim.buffer() without argument.
+ call assert_equal('Xfoo2', luaeval("vim.buffer().name"))
+
+ " Test vim.buffer() with string argument.
+ call assert_equal('Xfoo1', luaeval("vim.buffer('Xfoo1').name"))
+ call assert_equal('Xfoo2', luaeval("vim.buffer('Xfoo2').name"))
+
+ " Test vim.buffer() with integer argument.
+ call assert_equal('Xfoo1', luaeval("vim.buffer(" . bn1 . ").name"))
+ call assert_equal('Xfoo2', luaeval("vim.buffer(" . bn2 . ").name"))
+
+ lua bn1, bn2 = nil
+ %bwipe!
+endfunc
+
+" Test vim.buffer().name and vim.buffer().fname
+func Test_buffer_name()
+ new
+ call assert_equal('', luaeval('vim.buffer().name'))
+ call assert_equal('', luaeval('vim.buffer().fname'))
+ bwipe!
+
+ new Xfoo
+ call assert_equal('Xfoo', luaeval('vim.buffer().name'))
+ call assert_equal(expand('%:p'), luaeval('vim.buffer().fname'))
+ bwipe!
+endfunc
+
+" Test vim.buffer().number
+func Test_buffer_number()
+ " All numbers in Lua are floating points number (no integers).
+ call assert_equal(bufnr('%'), float2nr(luaeval('vim.buffer().number')))
+endfunc
+
+" Test inserting lines in buffer.
+func Test_buffer_insert()
+ new
+ lua vim.buffer()[1] = '3'
+ lua vim.buffer():insert('1', 0)
+ lua vim.buffer():insert('2', 1)
+ lua vim.buffer():insert('4', 10)
+
+ call assert_equal(['1', '2', '3', '4'], getline(1, '$'))
+ bwipe!
+endfunc
+
+" Test deleting line in buffer
+func Test_buffer_delete()
+ new
+ call setline(1, ['1', '2', '3'])
+ lua vim.buffer()[2] = nil
+ call assert_equal(['1', '3'], getline(1, '$'))
+
+ call assert_fails('lua vim.buffer()[3] = nil',
+ \ '[string "vim chunk"]:1: invalid line number')
+ bwipe!
+endfunc
+
+" Test #vim.buffer() i.e. number of lines in buffer
+func Test_buffer_number_lines()
+ new
+ call setline(1, ['a', 'b', 'c'])
+ call assert_equal(3.0, luaeval('#vim.buffer()'))
+ bwipe!
+endfunc
+
+" Test vim.buffer():next() and vim.buffer():previous()
+" Note that these functions get the next or previous buffers
+" but do not switch buffer.
+func Test_buffer_next_previous()
+ new Xfoo1
+ new Xfoo2
+ new Xfoo3
+ b Xfoo2
+
+ lua bn = vim.buffer():next()
+ lua bp = vim.buffer():previous()
+
+ call assert_equal('Xfoo2', luaeval('vim.buffer().name'))
+ call assert_equal('Xfoo1', luaeval('bp.name'))
+ call assert_equal('Xfoo3', luaeval('bn.name'))
+
+ call assert_equal('Xfoo2', bufname('%'))
+
+ lua bn()
+ call assert_equal('Xfoo3', luaeval('vim.buffer().name'))
+ call assert_equal('Xfoo3', bufname('%'))
+
+ lua bp()
+ call assert_equal('Xfoo1', luaeval('vim.buffer().name'))
+ call assert_equal('Xfoo1', bufname('%'))
+
+ lua bn, bp = nil
+ %bwipe!
+endfunc
+
+" Test vim.buffer():isvalid()
+func Test_buffer_isvalid()
+ new Xfoo
+ lua b = vim.buffer()
+ call assert_true(luaeval('b:isvalid()'))
+
+ " FIXME: how to test the case when isvalid() returns v:false?
+ " isvalid() gives errors when the buffer is wiped. Is it a bug?
+
+ lua b = nil
+ bwipe!
+endfunc
+
+func Test_list()
+ call assert_equal([], luaeval('vim.list()'))
+
+ let l = []
+ lua l = vim.eval('l')
+ lua l:add(123)
+ lua l:add('abc')
+ lua l:add(true)
+ lua l:add(false)
+ lua l:add(nil)
+ lua l:add(vim.eval("[1, 2, 3]"))
+ lua l:add(vim.eval("{'a':1, 'b':2, 'c':3}"))
+ call assert_equal([123.0, 'abc', v:true, v:false, v:null, [1, 2, 3], {'a': 1, 'b': 2, 'c': 3}], l)
+ call assert_equal(7.0, luaeval('#l'))
+ call assert_match('^list: \%(0x\)\?\x\+$', luaeval('tostring(l)'))
+
+ lua l[0] = 124
+ lua l[5] = nil
+ lua l:insert('first')
+ lua l:insert('xx', 3)
+ call assert_equal(['first', 124.0, 'abc', 'xx', v:true, v:false, v:null, {'a': 1, 'b': 2, 'c': 3}], l)
+
+ lockvar 1 l
+ call assert_fails('lua l:add("x")', '[string "vim chunk"]:1: list is locked')
+
+ lua l = nil
+endfunc
+
+func Test_list_table()
+ " See :help lua-vim
+ " Non-numeric keys should not be used to initialize the list
+ " so say = 'hi' should be ignored.
+ lua t = {3.14, 'hello', false, true, say = 'hi'}
+ call assert_equal([3.14, 'hello', v:false, v:true], luaeval('vim.list(t)'))
+ lua t = nil
+
+ call assert_fails('lua vim.list(1)', '[string "vim chunk"]:1: table expected, got number')
+ call assert_fails('lua vim.list("x")', '[string "vim chunk"]:1: table expected, got string')
+ call assert_fails('lua vim.list(print)', '[string "vim chunk"]:1: table expected, got function')
+ call assert_fails('lua vim.list(true)', '[string "vim chunk"]:1: table expected, got boolean')
+endfunc
+
+" Test l() i.e. iterator on list
+func Test_list_iter()
+ lua l = vim.list():add('foo'):add('bar')
+ lua str = ''
+ lua for v in l() do str = str .. v end
+ call assert_equal('foobar', luaeval('str'))
+
+ lua str, l = nil
+endfunc
+
+func Test_recursive_list()
+ lua l = vim.list():add(1):add(2)
+ lua l = l:add(l)
+
+ call assert_equal(1.0, luaeval('l[0]'))
+ call assert_equal(2.0, luaeval('l[1]'))
+
+ call assert_equal(1.0, luaeval('l[2][0]'))
+ call assert_equal(2.0, luaeval('l[2][1]'))
+
+ call assert_equal(1.0, luaeval('l[2][2][0]'))
+ call assert_equal(2.0, luaeval('l[2][2][1]'))
+
+ call assert_equal('[1.0, 2.0, [...]]', string(luaeval('l')))
+
+ call assert_match('^list: \%(0x\)\?\x\+$', luaeval('tostring(l)'))
+ call assert_equal(luaeval('tostring(l)'), luaeval('tostring(l[2])'))
+
+ call assert_equal(luaeval('l'), luaeval('l[2]'))
+ call assert_equal(luaeval('l'), luaeval('l[2][2]'))
+
+ lua l = nil
+endfunc
+
+func Test_dict()
+ call assert_equal({}, luaeval('vim.dict()'))
+
+ let d = {}
+ lua d = vim.eval('d')
+ lua d[0] = 123
+ lua d[1] = "abc"
+ lua d[2] = true
+ lua d[3] = false
+ lua d[4] = vim.eval("[1, 2, 3]")
+ lua d[5] = vim.eval("{'a':1, 'b':2, 'c':3}")
+ call assert_equal({'0':123.0, '1':'abc', '2':v:true, '3':v:false, '4': [1, 2, 3], '5': {'a':1, 'b':2, 'c':3}}, d)
+ call assert_equal(6.0, luaeval('#d'))
+ call assert_match('^dict: \%(0x\)\?\x\+$', luaeval('tostring(d)'))
+
+ call assert_equal('abc', luaeval('d[1]'))
+
+ lua d[0] = 124
+ lua d[4] = nil
+ call assert_equal({'0':124.0, '1':'abc', '2':v:true, '3':v:false, '5': {'a':1, 'b':2, 'c':3}}, d)
+
+ lockvar 1 d
+ call assert_fails('lua d[6] = 1', '[string "vim chunk"]:1: dict is locked')
+
+ lua d = nil
+endfunc
+
+func Test_dict_table()
+ lua t = {key1 = 'x', key2 = 3.14, key3 = true, key4 = false}
+ call assert_equal({'key1': 'x', 'key2': 3.14, 'key3': v:true, 'key4': v:false},
+ \ luaeval('vim.dict(t)'))
+
+ " Same example as in :help lua-vim.
+ lua t = {math.pi, false, say = 'hi'}
+ " FIXME: commented out as it currently does not work as documented:
+ " Expected {'say': 'hi'}
+ " but got {'1': 3.141593, '2': v:false, 'say': 'hi'}
+ " Is the documentation or the code wrong?
+ "call assert_equal({'say' : 'hi'}, luaeval('vim.dict(t)'))
+ lua t = nil
+
+ call assert_fails('lua vim.dict(1)', '[string "vim chunk"]:1: table expected, got number')
+ call assert_fails('lua vim.dict("x")', '[string "vim chunk"]:1: table expected, got string')
+ call assert_fails('lua vim.dict(print)', '[string "vim chunk"]:1: table expected, got function')
+ call assert_fails('lua vim.dict(true)', '[string "vim chunk"]:1: table expected, got boolean')
+endfunc
+
+" Test d() i.e. iterator on dictionary
+func Test_dict_iter()
+ let d = {'a': 1, 'b':2}
+ lua d = vim.eval('d')
+ lua str = ''
+ lua for k,v in d() do str = str .. k ..':' .. v .. ',' end
+ call assert_equal('a:1,b:2,', luaeval('str'))
+
+ lua str, d = nil
+endfunc
+
+func Test_funcref()
+ function I(x)
+ return a:x
+ endfunction
+ let R = function('I')
+ lua i1 = vim.funcref"I"
+ lua i2 = vim.eval"R"
+ lua msg = "funcref|test|" .. (#i2(i1) == #i1(i2) and "OK" or "FAIL")
+ lua msg = vim.funcref"tr"(msg, "|", " ")
+ call assert_equal("funcref test OK", luaeval('msg'))
+
+ " dict funcref
+ function Mylen() dict
+ return len(self.data)
+ endfunction
+ let l = [0, 1, 2, 3]
+ let mydict = {'data': l}
+ lua d = vim.eval"mydict"
+ lua d.len = vim.funcref"Mylen" -- assign d as 'self'
+ lua res = (d.len() == vim.funcref"len"(vim.eval"l")) and "OK" or "FAIL"
+ call assert_equal("OK", luaeval('res'))
+
+ lua i1, i2, msg, d, res = nil
+endfunc
+
+" Test vim.type()
+func Test_type()
+ " The following values are identical to Lua's type function.
+ call assert_equal('string', luaeval('vim.type("foo")'))
+ call assert_equal('number', luaeval('vim.type(1)'))
+ call assert_equal('number', luaeval('vim.type(1.2)'))
+ call assert_equal('function', luaeval('vim.type(print)'))
+ call assert_equal('table', luaeval('vim.type({})'))
+ call assert_equal('boolean', luaeval('vim.type(true)'))
+ call assert_equal('boolean', luaeval('vim.type(false)'))
+ call assert_equal('nil', luaeval('vim.type(nil)'))
+
+ " The following values are specific to Vim.
+ call assert_equal('window', luaeval('vim.type(vim.window())'))
+ call assert_equal('buffer', luaeval('vim.type(vim.buffer())'))
+ call assert_equal('list', luaeval('vim.type(vim.list())'))
+ call assert_equal('dict', luaeval('vim.type(vim.dict())'))
+ call assert_equal('funcref', luaeval('vim.type(vim.funcref("Test_type"))'))
+endfunc
+
+" Test vim.open()
+func Test_open()
+ call assert_notmatch('XOpen', execute('ls'))
+
+ " Open a buffer XOpen1, but do not jump to it.
+ lua b = vim.open('XOpen1')
+ call assert_equal('XOpen1', luaeval('b.name'))
+ call assert_equal('', bufname('%'))
+
+ call assert_match('XOpen1', execute('ls'))
+ call assert_notequal('XOpen2', bufname('%'))
+
+ " Open a buffer XOpen2 and jump to it.
+ lua b = vim.open('XOpen2')()
+ call assert_equal('XOpen2', luaeval('b.name'))
+ call assert_equal('XOpen2', bufname('%'))
+
+ lua b = nil
+ %bwipe!
+endfunc
+
+" Test vim.line()
+func Test_line()
+ new
+ call setline(1, ['first line', 'second line'])
+ 1
+ call assert_equal('first line', luaeval('vim.line()'))
+ 2
+ call assert_equal('second line', luaeval('vim.line()'))
+ bwipe!
+endfunc
+
+" Test vim.beep()
+func Test_beep()
+ call assert_beeps('lua vim.beep()')
+endfunc
+
+" Test errors in luaeval()
+func Test_luaeval_error()
+ " Compile error
+ call assert_fails("call luaeval('-nil')",
+ \ '[string "luaeval"]:1: attempt to perform arithmetic on a nil value')
+ call assert_fails("call luaeval(']')",
+ \ "[string \"luaeval\"]:1: unexpected symbol near ']'")
+endfunc
+
+" Test :luafile foo.lua
+func Test_luafile()
+ call delete('Xlua_file')
+ call writefile(["str = 'hello'", "num = 123.0" ], 'Xlua_file')
+ call setfperm('Xlua_file', 'r-xr-xr-x')
+
+ luafile Xlua_file
+ call assert_equal('hello', luaeval('str'))
+ call assert_equal(123.0, luaeval('num'))
+
+ lua str, num = nil
+ call delete('Xlua_file')
+endfunc
+
+" Test :luafile %
+func Test_luafile_percent()
+ new Xlua_file
+ append
+ str, num = 'foo', 321.0
+ print(string.format('str=%s, num=%d', str, num))
+.
+ w!
+ luafile %
+ let msg = split(execute('message'), "\n")[-1]
+ call assert_equal('str=foo, num=321', msg)
+
+ lua str, num = nil
+ call delete('Xlua_file')
+ bwipe!
+endfunc
+
+" Test :luafile with syntax error
+func Test_luafile_error()
+ new Xlua_file
+ call writefile(['nil = 0' ], 'Xlua_file')
+ call setfperm('Xlua_file', 'r-xr-xr-x')
+
+ call assert_fails('luafile Xlua_file', "Xlua_file:1: unexpected symbol near 'nil'")
+
+ call delete('Xlua_file')
+ bwipe!
+endfunc
+
+func Test_set_cursor()
+ " Check that setting the cursor position works.
+ new
+ call setline(1, ['first line', 'second line'])
+ normal gg
+ lua << EOF
+w = vim.window()
+w.line = 1
+w.col = 5
+EOF
+ call assert_equal([1, 5], [line('.'), col('.')])
+
+ " Check that movement after setting cursor position keeps current column.
+ normal j
+ call assert_equal([2, 5], [line('.'), col('.')])
+endfunc
diff --git a/src/testdir/test_makeencoding.py b/src/testdir/test_makeencoding.py
new file mode 100644
index 0000000..041edad
--- /dev/null
+++ b/src/testdir/test_makeencoding.py
@@ -0,0 +1,67 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Test program for :make, :grep and :cgetfile.
+
+from __future__ import print_function, unicode_literals
+import locale
+import io
+import sys
+
+def set_output_encoding(enc=None):
+ """Set the encoding of stdout and stderr
+
+ arguments:
+ enc -- Encoding name.
+ If omitted, locale.getpreferredencoding() is used.
+ """
+ if enc is None:
+ enc = locale.getpreferredencoding()
+
+ def get_text_writer(fo, **kwargs):
+ kw = dict(kwargs)
+ kw.setdefault('errors', 'backslashreplace') # use \uXXXX style
+ kw.setdefault('closefd', False)
+
+ if sys.version_info[0] < 3:
+ # Work around for Python 2.x
+ # New line conversion isn't needed here. Done in somewhere else.
+ writer = io.open(fo.fileno(), mode='w', newline='', **kw)
+ write = writer.write # save the original write() function
+ enc = locale.getpreferredencoding()
+ def convwrite(s):
+ if isinstance(s, bytes):
+ write(s.decode(enc)) # convert to unistr
+ else:
+ write(s)
+ try:
+ writer.flush() # needed on Windows
+ except IOError:
+ pass
+ writer.write = convwrite
+ else:
+ writer = io.open(fo.fileno(), mode='w', **kw)
+ return writer
+
+ sys.stdout = get_text_writer(sys.stdout, encoding=enc)
+ sys.stderr = get_text_writer(sys.stderr, encoding=enc)
+
+
+def main():
+ enc = 'utf-8'
+ if len(sys.argv) > 1:
+ enc = sys.argv[1]
+ set_output_encoding(enc)
+
+ message_tbl = {
+ 'utf-8': 'ÀÈÌÒÙ ã“ã‚“ã«ã¡ã¯ 你好',
+ 'latin1': 'ÀÈÌÒÙ',
+ 'cp932': 'ã“ã‚“ã«ã¡ã¯',
+ 'cp936': '你好',
+ }
+
+ print('Xfoobar.c(10) : %s (%s)' % (message_tbl[enc], enc))
+
+
+if __name__ == "__main__":
+ main()
diff --git a/src/testdir/test_makeencoding.vim b/src/testdir/test_makeencoding.vim
new file mode 100644
index 0000000..d18b3b6
--- /dev/null
+++ b/src/testdir/test_makeencoding.vim
@@ -0,0 +1,103 @@
+" Tests for 'makeencoding'.
+
+source shared.vim
+
+let s:python = PythonProg()
+if s:python == ''
+ " Can't run this test.
+ finish
+endif
+
+let s:script = 'test_makeencoding.py'
+
+let s:message_tbl = {
+ \ 'utf-8': 'ÀÈÌÒÙ ã“ã‚“ã«ã¡ã¯ 你好',
+ \ 'latin1': 'ÀÈÌÒÙ',
+ \ 'cp932': 'ã“ã‚“ã«ã¡ã¯',
+ \ 'cp936': '你好',
+ \}
+
+
+" Tests for :cgetfile and :lgetfile.
+func Test_getfile()
+ set errorfile=Xerror.txt
+ set errorformat=%f(%l)\ :\ %m
+
+ " :cgetfile
+ for enc in keys(s:message_tbl)
+ let &makeencoding = enc
+ exec "silent !" . s:python . " " . s:script . " " . enc . " > " . &errorfile
+ cgetfile
+ copen
+ call assert_equal("Xfoobar.c|10| " . s:message_tbl[enc] . " (" . enc . ")",
+ \ getline('.'))
+ cclose
+ endfor
+
+ " :lgetfile
+ for enc in keys(s:message_tbl)
+ let &makeencoding = enc
+ exec "silent !" . s:python . " " . s:script . " " . enc . " > " . &errorfile
+ lgetfile
+ lopen
+ call assert_equal("Xfoobar.c|10| " . s:message_tbl[enc] . " (" . enc . ")",
+ \ getline('.'))
+ lclose
+ endfor
+
+ call delete(&errorfile)
+endfunc
+
+
+" Tests for :grep and :lgrep.
+func Test_grep()
+ let &grepprg = s:python
+ set grepformat=%f(%l)\ :\ %m
+
+ " :grep
+ for enc in keys(s:message_tbl)
+ let &makeencoding = enc
+ exec "silent grep! " . s:script . " " . enc
+ copen
+ call assert_equal("Xfoobar.c|10| " . s:message_tbl[enc] . " (" . enc . ")",
+ \ getline('.'))
+ cclose
+ endfor
+
+ " :lgrep
+ for enc in keys(s:message_tbl)
+ let &makeencoding = enc
+ exec "silent lgrep! " . s:script . " " . enc
+ lopen
+ call assert_equal("Xfoobar.c|10| " . s:message_tbl[enc] . " (" . enc . ")",
+ \ getline('.'))
+ lclose
+ endfor
+endfunc
+
+
+" Tests for :make and :lmake.
+func Test_make()
+ let &makeprg = s:python
+ set errorformat=%f(%l)\ :\ %m
+
+ " :make
+ for enc in keys(s:message_tbl)
+ let &makeencoding = enc
+ exec "silent make! " . s:script . " " . enc
+ copen
+ call assert_equal("Xfoobar.c|10| " . s:message_tbl[enc] . " (" . enc . ")",
+ \ getline('.'))
+ cclose
+ endfor
+
+ " :lmake
+ for enc in keys(s:message_tbl)
+ let &makeencoding = enc
+ exec "silent lmake! " . s:script . " " . enc
+ lopen
+ call assert_equal("Xfoobar.c|10| " . s:message_tbl[enc] . " (" . enc . ")",
+ \ getline('.'))
+ lclose
+ endfor
+endfunc
diff --git a/src/testdir/test_man.vim b/src/testdir/test_man.vim
new file mode 100644
index 0000000..1485ec3
--- /dev/null
+++ b/src/testdir/test_man.vim
@@ -0,0 +1,60 @@
+runtime ftplugin/man.vim
+
+function Test_g_ft_man_open_mode()
+ vnew
+ let l:h = winheight(1)
+ q
+ let l:w = winwidth(1)
+
+ " split horizontally
+ let wincnt = winnr('$')
+ Man vim
+ if wincnt == winnr('$')
+ " Vim manual page cannot be found.
+ return
+ endif
+
+ call assert_inrange(l:w - 2, l:w + 2, winwidth(1))
+ call assert_true(l:h > winheight(1))
+ call assert_equal(1, tabpagenr('$'))
+ call assert_equal(1, tabpagenr())
+ q
+
+ " split horizontally
+ let g:ft_man_open_mode = "horz"
+ Man vim
+ call assert_inrange(l:w - 2, l:w + 2, winwidth(1))
+ call assert_true(l:h > winheight(1))
+ call assert_equal(1, tabpagenr('$'))
+ call assert_equal(1, tabpagenr())
+ q
+
+ " split vertically
+ let g:ft_man_open_mode = "vert"
+ Man vim
+ call assert_true(l:w > winwidth(1))
+ call assert_equal(l:h, winheight(1))
+ call assert_equal(1, tabpagenr('$'))
+ call assert_equal(1, tabpagenr())
+ q
+
+ " separate tab
+ let g:ft_man_open_mode = "tab"
+ Man vim
+ call assert_inrange(l:w - 2, l:w + 2, winwidth(1))
+ call assert_inrange(l:h - 1, l:h + 1, winheight(1))
+ call assert_equal(2, tabpagenr('$'))
+ call assert_equal(2, tabpagenr())
+ q
+endfunction
+
+function Test_nomodifiable()
+ let wincnt = winnr('$')
+ Man vim
+ if wincnt == winnr('$')
+ " Vim manual page cannot be found.
+ return
+ endif
+ call assert_false(&l:modifiable)
+ q
+endfunction
diff --git a/src/testdir/test_maparg.vim b/src/testdir/test_maparg.vim
new file mode 100644
index 0000000..86e046b
--- /dev/null
+++ b/src/testdir/test_maparg.vim
@@ -0,0 +1,58 @@
+" Tests for maparg().
+" Also test utf8 map with a 0x80 byte.
+
+function s:SID()
+ return str2nr(matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze_SID$'))
+endfun
+
+function Test_maparg()
+ new
+ set cpo-=<
+ set encoding=utf8
+ " Test maparg() with a string result
+ let sid = s:SID()
+ let lnum = expand('<sflnum>')
+ map foo<C-V> is<F4>foo
+ vnoremap <script> <buffer> <expr> <silent> bar isbar
+ call assert_equal("is<F4>foo", maparg('foo<C-V>'))
+ call assert_equal({'silent': 0, 'noremap': 0, 'lhs': 'foo<C-V>',
+ \ 'mode': ' ', 'nowait': 0, 'expr': 0, 'sid': sid, 'lnum': lnum + 1,
+ \ 'rhs': 'is<F4>foo', 'buffer': 0},
+ \ maparg('foo<C-V>', '', 0, 1))
+ call assert_equal({'silent': 1, 'noremap': 1, 'lhs': 'bar', 'mode': 'v',
+ \ 'nowait': 0, 'expr': 1, 'sid': sid, 'lnum': lnum + 2,
+ \ 'rhs': 'isbar', 'buffer': 1},
+ \ maparg('bar', '', 0, 1))
+ let lnum = expand('<sflnum>')
+ map <buffer> <nowait> foo bar
+ call assert_equal({'silent': 0, 'noremap': 0, 'lhs': 'foo', 'mode': ' ',
+ \ 'nowait': 1, 'expr': 0, 'sid': sid, 'lnum': lnum + 1, 'rhs': 'bar',
+ \ 'buffer': 1},
+ \ maparg('foo', '', 0, 1))
+
+ map abc x<char-114>x
+ call assert_equal("xrx", maparg('abc'))
+ map abc y<S-char-114>y
+ call assert_equal("yRy", maparg('abc'))
+
+ map abc <Nop>
+ call assert_equal("<Nop>", maparg('abc'))
+ unmap abc
+endfunction
+
+function Test_range_map()
+ new
+ " Outside of the range, minimum
+ inoremap <Char-0x1040> a
+ execute "normal a\u1040\<Esc>"
+ " Inside of the range, minimum
+ inoremap <Char-0x103f> b
+ execute "normal a\u103f\<Esc>"
+ " Inside of the range, maximum
+ inoremap <Char-0xf03f> c
+ execute "normal a\uf03f\<Esc>"
+ " Outside of the range, maximum
+ inoremap <Char-0xf040> d
+ execute "normal a\uf040\<Esc>"
+ call assert_equal("abcd", getline(1))
+endfunction
diff --git a/src/testdir/test_mapping.vim b/src/testdir/test_mapping.vim
new file mode 100644
index 0000000..c454fc0
--- /dev/null
+++ b/src/testdir/test_mapping.vim
@@ -0,0 +1,320 @@
+" Tests for mappings and abbreviations
+
+source shared.vim
+
+func Test_abbreviation()
+ " abbreviation with 0x80 should work
+ inoreab чкпр vim
+ call feedkeys("Goчкпр \<Esc>", "xt")
+ call assert_equal('vim ', getline('$'))
+ iunab чкпр
+ set nomodified
+endfunc
+
+func Test_map_ctrl_c_insert()
+ " mapping of ctrl-c in Insert mode
+ set cpo-=< cpo-=k
+ inoremap <c-c> <ctrl-c>
+ cnoremap <c-c> dummy
+ cunmap <c-c>
+ call feedkeys("GoTEST2: CTRL-C |\<C-C>A|\<Esc>", "xt")
+ call assert_equal('TEST2: CTRL-C |<ctrl-c>A|', getline('$'))
+ unmap! <c-c>
+ set nomodified
+endfunc
+
+func Test_map_ctrl_c_visual()
+ " mapping of ctrl-c in Visual mode
+ vnoremap <c-c> :<C-u>$put ='vmap works'
+ call feedkeys("GV\<C-C>\<CR>", "xt")
+ call assert_equal('vmap works', getline('$'))
+ vunmap <c-c>
+ set nomodified
+endfunc
+
+func Test_map_langmap()
+ if !has('langmap')
+ return
+ endif
+
+ " check langmap applies in normal mode
+ set langmap=+- nolangremap
+ new
+ call setline(1, ['a', 'b', 'c'])
+ 2
+ call assert_equal('b', getline('.'))
+ call feedkeys("+", "xt")
+ call assert_equal('a', getline('.'))
+
+ " check no remapping
+ map x +
+ 2
+ call feedkeys("x", "xt")
+ call assert_equal('c', getline('.'))
+
+ " check with remapping
+ set langremap
+ 2
+ call feedkeys("x", "xt")
+ call assert_equal('a', getline('.'))
+
+ unmap x
+ bwipe!
+
+ " 'langnoremap' follows 'langremap' and vise versa
+ set langremap
+ set langnoremap
+ call assert_equal(0, &langremap)
+ set langremap
+ call assert_equal(0, &langnoremap)
+ set nolangremap
+ call assert_equal(1, &langnoremap)
+
+ " check default values
+ set langnoremap&
+ call assert_equal(0, &langnoremap)
+ call assert_equal(1, &langremap)
+ set langremap&
+ call assert_equal(0, &langnoremap)
+ call assert_equal(1, &langremap)
+
+ " langmap should not apply in insert mode, 'langremap' doesn't matter
+ set langmap=+{ nolangremap
+ call feedkeys("Go+\<Esc>", "xt")
+ call assert_equal('+', getline('$'))
+ set langmap=+{ langremap
+ call feedkeys("Go+\<Esc>", "xt")
+ call assert_equal('+', getline('$'))
+
+ " langmap used for register name in insert mode.
+ call setreg('a', 'aaaa')
+ call setreg('b', 'bbbb')
+ call setreg('c', 'cccc')
+ set langmap=ab langremap
+ call feedkeys("Go\<C-R>a\<Esc>", "xt")
+ call assert_equal('bbbb', getline('$'))
+ call feedkeys("Go\<C-R>\<C-R>a\<Esc>", "xt")
+ call assert_equal('bbbb', getline('$'))
+ " mapping does not apply
+ imap c a
+ call feedkeys("Go\<C-R>c\<Esc>", "xt")
+ call assert_equal('cccc', getline('$'))
+ imap a c
+ call feedkeys("Go\<C-R>a\<Esc>", "xt")
+ call assert_equal('bbbb', getline('$'))
+
+ " langmap should not apply in Command-line mode
+ set langmap=+{ nolangremap
+ call feedkeys(":call append(line('$'), '+')\<CR>", "xt")
+ call assert_equal('+', getline('$'))
+
+ iunmap a
+ iunmap c
+ set nomodified
+endfunc
+
+func Test_map_feedkeys()
+ " issue #212 (feedkeys insert mapping at current position)
+ nnoremap . :call feedkeys(".", "in")<cr>
+ call setline('$', ['a b c d', 'a b c d'])
+ $-1
+ call feedkeys("0qqdw.ifoo\<Esc>qj0@q\<Esc>", "xt")
+ call assert_equal(['fooc d', 'fooc d'], getline(line('$') - 1, line('$')))
+ nunmap .
+ set nomodified
+endfunc
+
+func Test_map_cursor()
+ " <c-g>U<cursor> works only within a single line
+ imapclear
+ imap ( ()<c-g>U<left>
+ call feedkeys("G2o\<Esc>ki\<CR>Test1: text with a (here some more text\<Esc>k.", "xt")
+ call assert_equal('Test1: text with a (here some more text)', getline(line('$') - 2))
+ call assert_equal('Test1: text with a (here some more text)', getline(line('$') - 1))
+
+ " test undo
+ call feedkeys("G2o\<Esc>ki\<CR>Test2: text wit a (here some more text [und undo]\<C-G>u\<Esc>k.u", "xt")
+ call assert_equal('', getline(line('$') - 2))
+ call assert_equal('Test2: text wit a (here some more text [und undo])', getline(line('$') - 1))
+ set nomodified
+ imapclear
+endfunc
+
+" This isn't actually testing a mapping, but similar use of CTRL-G U as above.
+func Test_break_undo()
+ :set whichwrap=<,>,[,]
+ call feedkeys("G4o2k", "xt")
+ exe ":norm! iTest3: text with a (parenthesis here\<C-G>U\<Right>new line here\<esc>\<up>\<up>."
+ call assert_equal('new line here', getline(line('$') - 3))
+ call assert_equal('Test3: text with a (parenthesis here', getline(line('$') - 2))
+ call assert_equal('new line here', getline(line('$') - 1))
+ set nomodified
+endfunc
+
+func Test_map_meta_quotes()
+ imap <M-"> foo
+ call feedkeys("Go-\<M-\">-\<Esc>", "xt")
+ call assert_equal("-foo-", getline('$'))
+ set nomodified
+ iunmap <M-">
+endfunc
+
+func Test_abbr_after_line_join()
+ new
+ abbr foo bar
+ set backspace=indent,eol,start
+ exe "normal o\<BS>foo "
+ call assert_equal("bar ", getline(1))
+ bwipe!
+ unabbr foo
+ set backspace&
+endfunc
+
+func Test_map_timeout()
+ if !has('timers')
+ return
+ endif
+ nnoremap aaaa :let got_aaaa = 1<CR>
+ nnoremap bb :let got_bb = 1<CR>
+ nmap b aaa
+ new
+ func ExitInsert(timer)
+ let g:line = getline(1)
+ call feedkeys("\<Esc>", "t")
+ endfunc
+ set timeout timeoutlen=200
+ let timer = timer_start(300, 'ExitInsert')
+ " After the 'b' Vim waits for another character to see if it matches 'bb'.
+ " When it times out it is expanded to "aaa", but there is no wait for
+ " "aaaa". Can't check that reliably though.
+ call feedkeys("b", "xt!")
+ call assert_equal("aa", g:line)
+ call assert_false(exists('got_aaa'))
+ call assert_false(exists('got_bb'))
+
+ bwipe!
+ nunmap aaaa
+ nunmap bb
+ nunmap b
+ set timeoutlen&
+ delfunc ExitInsert
+ call timer_stop(timer)
+endfunc
+
+func Test_map_timeout_with_timer_interrupt()
+ if !has('job') || !has('timers')
+ return
+ endif
+
+ " Confirm the timer invoked in exit_cb of the job doesn't disturb mapped key
+ " sequence.
+ new
+ let g:val = 0
+ nnoremap \12 :let g:val = 1<CR>
+ nnoremap \123 :let g:val = 2<CR>
+ set timeout timeoutlen=1000
+
+ func ExitCb(job, status)
+ let g:timer = timer_start(1, {-> feedkeys("3\<Esc>", 't')})
+ endfunc
+
+ call job_start([&shell, &shellcmdflag, 'echo'], {'exit_cb': 'ExitCb'})
+ call feedkeys('\12', 'xt!')
+ call assert_equal(2, g:val)
+
+ bwipe!
+ nunmap \12
+ nunmap \123
+ set timeoutlen&
+ call WaitFor({-> exists('g:timer')})
+ call timer_stop(g:timer)
+ unlet g:timer
+ unlet g:val
+ delfunc ExitCb
+endfunc
+
+func Test_abbreviation_CR()
+ new
+ func Eatchar(pat)
+ let c = nr2char(getchar(0))
+ return (c =~ a:pat) ? '' : c
+ endfunc
+ iabbrev <buffer><silent> ~~7 <c-r>=repeat('~', 7)<CR><c-r>=Eatchar('\s')<cr>
+ call feedkeys("GA~~7 \<esc>", 'xt')
+ call assert_equal('~~~~~~~', getline('$'))
+ %d
+ call feedkeys("GA~~7\<cr>\<esc>", 'xt')
+ call assert_equal(['~~~~~~~', ''], getline(1,'$'))
+ delfunc Eatchar
+ bw!
+endfunc
+
+func Test_cabbr_visual_mode()
+ cabbr s su
+ call feedkeys(":s \<c-B>\"\<CR>", 'itx')
+ call assert_equal('"su ', getreg(':'))
+ call feedkeys(":'<,'>s \<c-B>\"\<CR>", 'itx')
+ let expected = '"'. "'<,'>su "
+ call assert_equal(expected, getreg(':'))
+ call feedkeys(": '<,'>s \<c-B>\"\<CR>", 'itx')
+ let expected = '" '. "'<,'>su "
+ call assert_equal(expected, getreg(':'))
+ call feedkeys(":'a,'bs \<c-B>\"\<CR>", 'itx')
+ let expected = '"'. "'a,'bsu "
+ call assert_equal(expected, getreg(':'))
+ cunabbr s
+endfunc
+
+func Test_motionforce_omap()
+ func GetCommand()
+ let g:m=mode(1)
+ let [g:lnum1, g:col1] = searchpos('-', 'Wb')
+ if g:lnum1 == 0
+ return "\<Esc>"
+ endif
+ let [g:lnum2, g:col2] = searchpos('-', 'W')
+ if g:lnum2 == 0
+ return "\<Esc>"
+ endif
+ return ":call Select()\<CR>"
+ endfunc
+ func Select()
+ call cursor([g:lnum1, g:col1])
+ exe "normal! 1 ". (strlen(g:m) == 2 ? 'v' : g:m[2])
+ call cursor([g:lnum2, g:col2])
+ execute "normal! \<BS>"
+ endfunc
+ new
+ onoremap <buffer><expr> i- GetCommand()
+ " 1) default omap mapping
+ %d_
+ call setline(1, ['aaa - bbb', 'x', 'ddd - eee'])
+ call cursor(2, 1)
+ norm di-
+ call assert_equal('no', g:m)
+ call assert_equal(['aaa -- eee'], getline(1, '$'))
+ " 2) forced characterwise operation
+ %d_
+ call setline(1, ['aaa - bbb', 'x', 'ddd - eee'])
+ call cursor(2, 1)
+ norm dvi-
+ call assert_equal('nov', g:m)
+ call assert_equal(['aaa -- eee'], getline(1, '$'))
+ " 3) forced linewise operation
+ %d_
+ call setline(1, ['aaa - bbb', 'x', 'ddd - eee'])
+ call cursor(2, 1)
+ norm dVi-
+ call assert_equal('noV', g:m)
+ call assert_equal([''], getline(1, '$'))
+ " 4) forced blockwise operation
+ %d_
+ call setline(1, ['aaa - bbb', 'x', 'ddd - eee'])
+ call cursor(2, 1)
+ exe "norm d\<C-V>i-"
+ call assert_equal("no\<C-V>", g:m)
+ call assert_equal(['aaabbb', 'x', 'dddeee'], getline(1, '$'))
+ bwipe!
+ delfunc Select
+ delfunc GetCommand
+endfunc
diff --git a/src/testdir/test_marks.vim b/src/testdir/test_marks.vim
new file mode 100644
index 0000000..a9bba57
--- /dev/null
+++ b/src/testdir/test_marks.vim
@@ -0,0 +1,176 @@
+
+" Test that a deleted mark is restored after delete-undo-redo-undo.
+func Test_Restore_DelMark()
+ enew!
+ call append(0, [" textline A", " textline B", " textline C"])
+ normal! 2gg
+ set nocp viminfo+=nviminfo
+ exe "normal! i\<C-G>u\<Esc>"
+ exe "normal! maddu\<C-R>u"
+ let pos = getpos("'a")
+ call assert_equal(2, pos[1])
+ call assert_equal(1, pos[2])
+ enew!
+endfunc
+
+" Test that CTRL-A and CTRL-X updates last changed mark '[, '].
+func Test_Incr_Marks()
+ enew!
+ call append(0, ["123 123 123", "123 123 123", "123 123 123"])
+ normal! gg
+ execute "normal! \<C-A>`[v`]rAjwvjw\<C-X>`[v`]rX"
+ call assert_equal("AAA 123 123", getline(1))
+ call assert_equal("123 XXXXXXX", getline(2))
+ call assert_equal("XXX 123 123", getline(3))
+ enew!
+endfunc
+
+func Test_setpos()
+ new one
+ let onebuf = bufnr('%')
+ let onewin = win_getid()
+ call setline(1, ['aaa', 'bbb', 'ccc'])
+ new two
+ let twobuf = bufnr('%')
+ let twowin = win_getid()
+ call setline(1, ['aaa', 'bbb', 'ccc'])
+
+ " for the cursor the buffer number is ignored
+ call setpos(".", [0, 2, 1, 0])
+ call assert_equal([0, 2, 1, 0], getpos("."))
+ call setpos(".", [onebuf, 3, 3, 0])
+ call assert_equal([0, 3, 3, 0], getpos("."))
+
+ call setpos("''", [0, 1, 3, 0])
+ call assert_equal([0, 1, 3, 0], getpos("''"))
+ call setpos("''", [onebuf, 2, 2, 0])
+ call assert_equal([0, 2, 2, 0], getpos("''"))
+
+ " buffer-local marks
+ for mark in ["'a", "'\"", "'[", "']", "'<", "'>"]
+ call win_gotoid(twowin)
+ call setpos(mark, [0, 2, 1, 0])
+ call assert_equal([0, 2, 1, 0], getpos(mark), "for mark " . mark)
+ call setpos(mark, [onebuf, 1, 3, 0])
+ call win_gotoid(onewin)
+ call assert_equal([0, 1, 3, 0], getpos(mark), "for mark " . mark)
+ endfor
+
+ " global marks
+ call win_gotoid(twowin)
+ call setpos("'N", [0, 2, 1, 0])
+ call assert_equal([twobuf, 2, 1, 0], getpos("'N"))
+ call setpos("'N", [onebuf, 1, 3, 0])
+ call assert_equal([onebuf, 1, 3, 0], getpos("'N"))
+
+ call win_gotoid(onewin)
+ bwipe!
+ call win_gotoid(twowin)
+ bwipe!
+endfunc
+
+func Test_marks_cmd()
+ new Xone
+ call setline(1, ['aaa', 'bbb'])
+ norm! maG$mB
+ w!
+ new Xtwo
+ call setline(1, ['ccc', 'ddd'])
+ norm! $mcGmD
+ w!
+
+ b Xone
+ let a = split(execute('marks'), "\n")
+ call assert_equal(9, len(a))
+ call assert_equal('mark line col file/text', a[0])
+ call assert_equal(" ' 2 0 bbb", a[1])
+ call assert_equal(' a 1 0 aaa', a[2])
+ call assert_equal(' B 2 2 bbb', a[3])
+ call assert_equal(' D 2 0 Xtwo', a[4])
+ call assert_equal(' " 1 0 aaa', a[5])
+ call assert_equal(' [ 1 0 aaa', a[6])
+ call assert_equal(' ] 2 0 bbb', a[7])
+ call assert_equal(' . 2 0 bbb', a[8])
+
+ b Xtwo
+ let a = split(execute('marks'), "\n")
+ call assert_equal(9, len(a))
+ call assert_equal('mark line col file/text', a[0])
+ call assert_equal(" ' 1 0 ccc", a[1])
+ call assert_equal(' c 1 2 ccc', a[2])
+ call assert_equal(' B 2 2 Xone', a[3])
+ call assert_equal(' D 2 0 ddd', a[4])
+ call assert_equal(' " 2 0 ddd', a[5])
+ call assert_equal(' [ 1 0 ccc', a[6])
+ call assert_equal(' ] 2 0 ddd', a[7])
+ call assert_equal(' . 2 0 ddd', a[8])
+
+ b Xone
+ delmarks aB
+ let a = split(execute('marks aBcD'), "\n")
+ call assert_equal(2, len(a))
+ call assert_equal('mark line col file/text', a[0])
+ call assert_equal(' D 2 0 Xtwo', a[1])
+
+ b Xtwo
+ delmarks cD
+ call assert_fails('marks aBcD', 'E283:')
+
+ call delete('Xone')
+ call delete('Xtwo')
+ %bwipe
+endfunc
+
+func Test_marks_cmd_multibyte()
+ new Xone
+ call setline(1, [repeat('á', &columns)])
+ norm! ma
+
+ let a = split(execute('marks a'), "\n")
+ call assert_equal(2, len(a))
+ let expected = ' a 1 0 ' . repeat('á', &columns - 16)
+ call assert_equal(expected, a[1])
+
+ bwipe!
+endfunc
+
+func Test_delmarks()
+ new
+ norm mx
+ norm `x
+ delmarks x
+ call assert_fails('norm `x', 'E20:')
+
+ " Deleting an already deleted mark should not fail.
+ delmarks x
+
+ " Test deleting a range of marks.
+ norm ma
+ norm mb
+ norm mc
+ norm mz
+ delmarks b-z
+ norm `a
+ call assert_fails('norm `b', 'E20:')
+ call assert_fails('norm `c', 'E20:')
+ call assert_fails('norm `z', 'E20:')
+ call assert_fails('delmarks z-b', 'E475:')
+
+ call assert_fails('delmarks', 'E471:')
+ call assert_fails('delmarks /', 'E475:')
+
+ " Test delmarks!
+ norm mx
+ norm `x
+ delmarks!
+ call assert_fails('norm `x', 'E20:')
+ call assert_fails('delmarks! x', 'E474:')
+
+ bwipe!
+endfunc
+
+func Test_mark_error()
+ call assert_fails('mark', 'E471:')
+ call assert_fails('mark xx', 'E488:')
+ call assert_fails('mark _', 'E191:')
+endfunc
diff --git a/src/testdir/test_match.vim b/src/testdir/test_match.vim
new file mode 100644
index 0000000..94bca9a
--- /dev/null
+++ b/src/testdir/test_match.vim
@@ -0,0 +1,241 @@
+" Test for :match, :2match, :3match, clearmatches(), getmatches(), matchadd(),
+" matchaddpos(), matcharg(), matchdelete(), and setmatches().
+
+function Test_match()
+ highlight MyGroup1 term=bold ctermbg=red guibg=red
+ highlight MyGroup2 term=italic ctermbg=green guibg=green
+ highlight MyGroup3 term=underline ctermbg=blue guibg=blue
+
+ " --- Check that "matcharg()" returns the correct group and pattern if a match
+ " --- is defined.
+ match MyGroup1 /TODO/
+ 2match MyGroup2 /FIXME/
+ 3match MyGroup3 /XXX/
+ call assert_equal(['MyGroup1', 'TODO'], matcharg(1))
+ call assert_equal(['MyGroup2', 'FIXME'], matcharg(2))
+ call assert_equal(['MyGroup3', 'XXX'], matcharg(3))
+
+ " --- Check that "matcharg()" returns an empty list if the argument is not 1,
+ " --- 2 or 3 (only 0 and 4 are tested).
+ call assert_equal([], matcharg(0))
+ call assert_equal([], matcharg(4))
+
+ " --- Check that "matcharg()" returns ['', ''] if a match is not defined.
+ match
+ 2match
+ 3match
+ call assert_equal(['', ''], matcharg(1))
+ call assert_equal(['', ''], matcharg(2))
+ call assert_equal(['', ''], matcharg(3))
+
+ " --- Check that "matchadd()" and "getmatches()" agree on added matches and
+ " --- that default values apply.
+ let m1 = matchadd("MyGroup1", "TODO")
+ let m2 = matchadd("MyGroup2", "FIXME", 42)
+ let m3 = matchadd("MyGroup3", "XXX", 60, 17)
+ let ans = [{'group': 'MyGroup1', 'pattern': 'TODO', 'priority': 10, 'id': 4},
+ \ {'group': 'MyGroup2', 'pattern': 'FIXME', 'priority': 42, 'id': 5},
+ \ {'group': 'MyGroup3', 'pattern': 'XXX', 'priority': 60, 'id': 17}]
+ call assert_equal(ans, getmatches())
+
+ " --- Check that "matchdelete()" deletes the matches defined in the previous
+ " --- test correctly.
+ call matchdelete(m1)
+ call matchdelete(m2)
+ call matchdelete(m3)
+ call assert_equal([], getmatches())
+
+ " --- Check that "matchdelete()" returns 0 if successful and otherwise -1.
+ let m = matchadd("MyGroup1", "TODO")
+ call assert_equal(0, matchdelete(m))
+ call assert_fails('call matchdelete(42)', 'E803:')
+
+ " --- Check that "clearmatches()" clears all matches defined by ":match" and
+ " --- "matchadd()".
+ let m1 = matchadd("MyGroup1", "TODO")
+ let m2 = matchadd("MyGroup2", "FIXME", 42)
+ let m3 = matchadd("MyGroup3", "XXX", 60, 17)
+ match MyGroup1 /COFFEE/
+ 2match MyGroup2 /HUMPPA/
+ 3match MyGroup3 /VIM/
+ call clearmatches()
+ call assert_equal([], getmatches())
+
+ " --- Check that "setmatches()" restores a list of matches saved by
+ " --- "getmatches()" without changes. (Matches with equal priority must also
+ " --- remain in the same order.)
+ let m1 = matchadd("MyGroup1", "TODO")
+ let m2 = matchadd("MyGroup2", "FIXME", 42)
+ let m3 = matchadd("MyGroup3", "XXX", 60, 17)
+ match MyGroup1 /COFFEE/
+ 2match MyGroup2 /HUMPPA/
+ 3match MyGroup3 /VIM/
+ let ml = getmatches()
+ call clearmatches()
+ call setmatches(ml)
+ call assert_equal(ml, getmatches())
+ call clearmatches()
+
+ " --- Check that "setmatches()" will not add two matches with the same ID. The
+ " --- expected behaviour (for now) is to add the first match but not the
+ " --- second and to return 0 (even though it is a matter of debate whether
+ " --- this can be considered successful behaviour).
+ let data = [{'group': 'MyGroup1', 'pattern': 'TODO', 'priority': 10, 'id': 1},
+ \ {'group': 'MyGroup2', 'pattern': 'FIXME', 'priority': 10, 'id': 1}]
+ call assert_fails('call setmatches(data)', 'E801:')
+ call assert_equal([data[0]], getmatches())
+ call clearmatches()
+
+ " --- Check that "setmatches()" returns 0 if successful and otherwise -1.
+ " --- (A range of valid and invalid input values are tried out to generate the
+ " --- return values.)
+ call assert_equal(0, setmatches([]))
+ call assert_equal(0, setmatches([{'group': 'MyGroup1', 'pattern': 'TODO', 'priority': 10, 'id': 1}]))
+ call clearmatches()
+ call assert_fails('call setmatches(0)', 'E714:')
+ call assert_fails('call setmatches([0])', 'E474:')
+ call assert_fails("call setmatches([{'wrong key': 'wrong value'}])", 'E474:')
+
+ call setline(1, 'abcdefghijklmnopq')
+ call matchaddpos("MyGroup1", [[1, 5], [1, 8, 3]], 10, 3)
+ 1
+ redraw!
+ let v1 = screenattr(1, 1)
+ let v5 = screenattr(1, 5)
+ let v6 = screenattr(1, 6)
+ let v8 = screenattr(1, 8)
+ let v10 = screenattr(1, 10)
+ let v11 = screenattr(1, 11)
+ call assert_notequal(v1, v5)
+ call assert_equal(v6, v1)
+ call assert_equal(v8, v5)
+ call assert_equal(v10, v5)
+ call assert_equal(v11, v1)
+ call assert_equal([{'group': 'MyGroup1', 'id': 3, 'priority': 10, 'pos1': [1, 5, 1], 'pos2': [1, 8, 3]}], getmatches())
+ call clearmatches()
+
+ call setline(1, 'abcdΣabcdef')
+ call matchaddpos("MyGroup1", [[1, 4, 2], [1, 9, 2]])
+ 1
+ redraw!
+ let v1 = screenattr(1, 1)
+ let v4 = screenattr(1, 4)
+ let v5 = screenattr(1, 5)
+ let v6 = screenattr(1, 6)
+ let v7 = screenattr(1, 7)
+ let v8 = screenattr(1, 8)
+ let v9 = screenattr(1, 9)
+ let v10 = screenattr(1, 10)
+ call assert_equal([{'group': 'MyGroup1', 'id': 11, 'priority': 10, 'pos1': [1, 4, 2], 'pos2': [1, 9, 2]}], getmatches())
+ call assert_notequal(v1, v4)
+ call assert_equal(v5, v4)
+ call assert_equal(v6, v1)
+ call assert_equal(v7, v1)
+ call assert_equal(v8, v4)
+ call assert_equal(v9, v4)
+ call assert_equal(v10, v1)
+
+ " Check, that setmatches() can correctly restore the matches from matchaddpos()
+ call matchadd('MyGroup1', '\%2lmatchadd')
+ let m=getmatches()
+ call clearmatches()
+ call setmatches(m)
+ call assert_equal([{'group': 'MyGroup1', 'id': 11, 'priority': 10, 'pos1': [1, 4, 2], 'pos2': [1,9, 2]}, {'group': 'MyGroup1', 'pattern': '\%2lmatchadd', 'priority': 10, 'id': 12}], getmatches())
+
+ highlight MyGroup1 NONE
+ highlight MyGroup2 NONE
+ highlight MyGroup3 NONE
+endfunc
+
+func Test_matchaddpos()
+ syntax on
+ set hlsearch
+
+ call setline(1, ['12345', 'NP'])
+ call matchaddpos('Error', [[1,2], [1,6], [2,2]])
+ redraw!
+ call assert_notequal(screenattr(2,2), 0)
+ call assert_equal(screenattr(2,2), screenattr(1,2))
+ call assert_notequal(screenattr(2,2), screenattr(1,6))
+ 1
+ call matchadd('Search', 'N\|\n')
+ redraw!
+ call assert_notequal(screenattr(2,1), 0)
+ call assert_equal(screenattr(2,1), screenattr(1,6))
+ exec "norm! i0\<Esc>"
+ redraw!
+ call assert_equal(screenattr(2,2), screenattr(1,6))
+
+ " Check overlapping pos
+ call clearmatches()
+ call setline(1, ['1234567890', 'NH'])
+ call matchaddpos('Error', [[1,1,5], [1,3,5], [2,2]])
+ redraw!
+ call assert_notequal(screenattr(2,2), 0)
+ call assert_equal(screenattr(2,2), screenattr(1,5))
+ call assert_equal(screenattr(2,2), screenattr(1,7))
+ call assert_notequal(screenattr(2,2), screenattr(1,8))
+
+ call clearmatches()
+ call matchaddpos('Error', [[1], [2,2]])
+ redraw!
+ call assert_equal(screenattr(2,2), screenattr(1,1))
+ call assert_equal(screenattr(2,2), screenattr(1,10))
+ call assert_notequal(screenattr(2,2), screenattr(1,11))
+
+ nohl
+ call clearmatches()
+ syntax off
+ set hlsearch&
+endfunc
+
+func Test_matchaddpos_otherwin()
+ syntax on
+ new
+ call setline(1, ['12345', 'NP'])
+ let winid = win_getid()
+
+ wincmd w
+ call matchadd('Search', '4', 10, -1, {'window': winid})
+ call matchaddpos('Error', [[1,2], [2,2]], 10, -1, {'window': winid})
+ redraw!
+ call assert_notequal(screenattr(1,2), 0)
+ call assert_notequal(screenattr(1,4), 0)
+ call assert_notequal(screenattr(2,2), 0)
+ call assert_equal(screenattr(1,2), screenattr(2,2))
+ call assert_notequal(screenattr(1,2), screenattr(1,4))
+
+ wincmd w
+ bwipe!
+ call clearmatches()
+ syntax off
+endfunc
+
+func Test_matchaddpos_using_negative_priority()
+ set hlsearch
+
+ call clearmatches()
+
+ call setline(1, 'x')
+ let @/='x'
+ redraw!
+ let search_attr = screenattr(1,1)
+
+ let @/=''
+ call matchaddpos('Error', [1], 10)
+ redraw!
+ let error_attr = screenattr(1,1)
+
+ call setline(2, '-1 match priority')
+ call matchaddpos('Error', [2], -1)
+ redraw!
+ let negative_match_priority_attr = screenattr(2,1)
+
+ call assert_notequal(negative_match_priority_attr, search_attr, "Match with negative priority is incorrectly highlighted with Search highlight.")
+ call assert_equal(negative_match_priority_attr, error_attr)
+
+ nohl
+ set hlsearch&
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/test_matchadd_conceal.vim b/src/testdir/test_matchadd_conceal.vim
new file mode 100644
index 0000000..8d774a0
--- /dev/null
+++ b/src/testdir/test_matchadd_conceal.vim
@@ -0,0 +1,279 @@
+" Test for matchadd() and conceal feature
+if !has('conceal')
+ finish
+endif
+
+if !has('gui_running') && has('unix')
+ set term=ansi
+endif
+
+source shared.vim
+
+func Test_simple_matchadd()
+ new
+
+ 1put='# This is a Test'
+ " 1234567890123456
+ let expect = '# This is a Test'
+
+ call cursor(1, 1)
+ call matchadd('Conceal', '\%2l ')
+ redraw!
+ let lnum = 2
+ call assert_equal(expect, Screenline(lnum))
+ call assert_notequal(screenattr(lnum, 1), screenattr(lnum, 2))
+ call assert_notequal(screenattr(lnum, 1), screenattr(lnum, 2))
+ call assert_equal(screenattr(lnum, 2), screenattr(lnum, 7))
+ call assert_equal(screenattr(lnum, 2), screenattr(lnum, 10))
+ call assert_equal(screenattr(lnum, 2), screenattr(lnum, 12))
+ call assert_equal(screenattr(lnum, 1), screenattr(lnum, 16))
+
+ quit!
+endfunc
+
+func Test_simple_matchadd_and_conceal()
+ new
+ setlocal concealcursor=n conceallevel=1
+
+ 1put='# This is a Test'
+ " 1234567890123456
+ let expect = '#XThisXisXaXTest'
+
+ call cursor(1, 1)
+ call matchadd('Conceal', '\%2l ', 10, -1, {'conceal': 'X'})
+ redraw!
+ let lnum = 2
+ call assert_equal(expect, Screenline(lnum))
+ call assert_notequal(screenattr(lnum, 1), screenattr(lnum, 2))
+ call assert_equal(screenattr(lnum, 2), screenattr(lnum, 7))
+ call assert_equal(screenattr(lnum, 2), screenattr(lnum, 10))
+ call assert_equal(screenattr(lnum, 2), screenattr(lnum, 12))
+ call assert_equal(screenattr(lnum, 1), screenattr(lnum, 16))
+
+ quit!
+endfunc
+
+func Test_matchadd_and_conceallevel_3()
+ new
+
+ setlocal conceallevel=3
+ " set filetype and :syntax on to change screenattr()
+ setlocal filetype=conf
+ syntax on
+
+ 1put='# This is a Test'
+ " 1234567890123456
+ let expect = '#ThisisaTest'
+
+ call cursor(1, 1)
+ call matchadd('Conceal', '\%2l ', 10, -1, {'conceal': 'X'})
+ redraw!
+ let lnum = 2
+ call assert_equal(expect, Screenline(lnum))
+ call assert_equal(screenattr(lnum, 1), screenattr(lnum, 2))
+ call assert_equal(screenattr(lnum, 2), screenattr(lnum, 7))
+ call assert_equal(screenattr(lnum, 2), screenattr(lnum, 10))
+ call assert_equal(screenattr(lnum, 2), screenattr(lnum, 12))
+ call assert_notequal(screenattr(lnum, 1), screenattr(lnum, 16))
+
+ " more matchadd()
+ " 1234567890123456
+ let expect = '#Thisisa Test'
+
+ call matchadd('ErrorMsg', '\%2l Test', 20, -1, {'conceal': 'X'})
+ redraw!
+ call assert_equal(expect, Screenline(lnum))
+ call assert_equal(screenattr(lnum, 1) , screenattr(lnum, 2))
+ call assert_equal(screenattr(lnum, 2) , screenattr(lnum, 7))
+ call assert_notequal(screenattr(lnum, 1) , screenattr(lnum, 10))
+ call assert_equal(screenattr(lnum, 10), screenattr(lnum, 12))
+ call assert_notequal(screenattr(lnum, 1) , screenattr(lnum, 16))
+ call assert_notequal(screenattr(lnum, 10), screenattr(lnum, 16))
+
+ syntax off
+ quit!
+endfunc
+
+func Test_default_conceal_char()
+ new
+ setlocal concealcursor=n conceallevel=1
+
+ 1put='# This is a Test'
+ " 1234567890123456
+ let expect = '# This is a Test'
+
+ call cursor(1, 1)
+ call matchadd('Conceal', '\%2l ', 10, -1, {})
+ redraw!
+ let lnum = 2
+ call assert_equal(expect, Screenline(lnum))
+ call assert_notequal(screenattr(lnum, 1), screenattr(lnum, 2))
+ call assert_equal(screenattr(lnum, 2), screenattr(lnum, 7))
+ call assert_equal(screenattr(lnum, 2), screenattr(lnum, 10))
+ call assert_equal(screenattr(lnum, 2), screenattr(lnum, 12))
+ call assert_equal(screenattr(lnum, 1), screenattr(lnum, 16))
+
+ " 1234567890123456
+ let expect = '#+This+is+a+Test'
+ let listchars_save = &listchars
+ set listchars=conceal:+
+ redraw!
+
+ call assert_equal(expect, Screenline(lnum))
+ call assert_notequal(screenattr(lnum, 1), screenattr(lnum, 2))
+ call assert_equal(screenattr(lnum, 2), screenattr(lnum, 7))
+ call assert_equal(screenattr(lnum, 2), screenattr(lnum, 10))
+ call assert_equal(screenattr(lnum, 2), screenattr(lnum, 12))
+ call assert_equal(screenattr(lnum, 1), screenattr(lnum, 16))
+
+ let &listchars = listchars_save
+ quit!
+endfunc
+
+func Test_syn_and_match_conceal()
+ new
+ setlocal concealcursor=n conceallevel=1
+
+ 1put='# This is a Test'
+ " 1234567890123456
+ let expect = '#ZThisZisZaZTest'
+
+ call cursor(1, 1)
+ call matchadd('Conceal', '\%2l ', 10, -1, {'conceal': 'Z'})
+ syntax match MyConceal /\%2l / conceal containedin=ALL cchar=*
+ redraw!
+ let lnum = 2
+ call assert_equal(expect, Screenline(lnum))
+ call assert_notequal(screenattr(lnum, 1), screenattr(lnum, 2))
+ call assert_equal(screenattr(lnum, 2), screenattr(lnum, 7))
+ call assert_equal(screenattr(lnum, 2), screenattr(lnum, 10))
+ call assert_equal(screenattr(lnum, 2), screenattr(lnum, 12))
+ call assert_equal(screenattr(lnum, 1), screenattr(lnum, 16))
+
+ " 1234567890123456
+ let expect = '#*This*is*a*Test'
+ call clearmatches()
+ redraw!
+
+ call assert_equal(expect, Screenline(lnum))
+ call assert_notequal(screenattr(lnum, 1), screenattr(lnum, 2))
+ call assert_equal(screenattr(lnum, 2), screenattr(lnum, 7))
+ call assert_equal(screenattr(lnum, 2), screenattr(lnum, 10))
+ call assert_equal(screenattr(lnum, 2), screenattr(lnum, 12))
+ call assert_equal(screenattr(lnum, 1), screenattr(lnum, 16))
+
+ syntax off
+ quit!
+endfunc
+
+func Test_clearmatches()
+ new
+ setlocal concealcursor=n conceallevel=1
+
+ 1put='# This is a Test'
+ " 1234567890123456
+ let expect = '# This is a Test'
+
+ call cursor(1, 1)
+ call matchadd('Conceal', '\%2l ', 10, -1, {'conceal': 'Z'})
+ let a = getmatches()
+ call clearmatches()
+ redraw!
+
+ let lnum = 2
+ call assert_equal(expect, Screenline(lnum))
+ call assert_equal(screenattr(lnum, 1), screenattr(lnum, 2))
+ call assert_equal(screenattr(lnum, 2), screenattr(lnum, 7))
+ call assert_equal(screenattr(lnum, 2), screenattr(lnum, 10))
+ call assert_equal(screenattr(lnum, 2), screenattr(lnum, 12))
+ call assert_equal(screenattr(lnum, 1), screenattr(lnum, 16))
+
+ " reset match using setmatches()
+ " 1234567890123456
+ let expect = '#ZThisZisZaZTest'
+ call setmatches(a)
+ redraw!
+
+ call assert_equal(expect, Screenline(lnum))
+ call assert_notequal(screenattr(lnum, 1), screenattr(lnum, 2))
+ call assert_equal(screenattr(lnum, 2), screenattr(lnum, 7))
+ call assert_equal(screenattr(lnum, 2), screenattr(lnum, 10))
+ call assert_equal(screenattr(lnum, 2), screenattr(lnum, 12))
+ call assert_equal(screenattr(lnum, 1), screenattr(lnum, 16))
+ call assert_equal({'group': 'Conceal', 'pattern': '\%2l ', 'priority': 10, 'id': a[0].id, 'conceal': 'Z'}, a[0])
+
+ quit!
+endfunc
+
+func Test_using_matchaddpos()
+ new
+ setlocal concealcursor=n conceallevel=1
+ " set filetype and :syntax on to change screenattr()
+ setlocal filetype=conf
+ syntax on
+
+ 1put='# This is a Test'
+ " 1234567890123456
+ let expect = '#Pis a Test'
+
+ call cursor(1, 1)
+ call matchaddpos('Conceal', [[2,2,6]], 10, -1, {'conceal': 'P'})
+ let a = getmatches()
+ redraw!
+
+ let lnum = 2
+ call assert_equal(expect, Screenline(lnum))
+ call assert_notequal(screenattr(lnum, 1) , screenattr(lnum, 2))
+ call assert_notequal(screenattr(lnum, 2) , screenattr(lnum, 7))
+ call assert_equal(screenattr(lnum, 1) , screenattr(lnum, 7))
+ call assert_equal(screenattr(lnum, 1) , screenattr(lnum, 10))
+ call assert_notequal(screenattr(lnum, 1) , screenattr(lnum, 12))
+ call assert_notequal(screenattr(lnum, 1) , screenattr(lnum, 16))
+ call assert_equal(screenattr(lnum, 12), screenattr(lnum, 16))
+ call assert_equal({'group': 'Conceal', 'id': a[0].id, 'priority': 10, 'pos1': [2, 2, 6], 'conceal': 'P'}, a[0])
+
+ syntax off
+ quit!
+endfunc
+
+func Test_matchadd_repeat_conceal_with_syntax_off()
+ new
+
+ " To test targets in the same line string is replaced with conceal char
+ " correctly, repeat 'TARGET'
+ 1put ='TARGET_TARGETTARGET'
+ call cursor(1, 1)
+ redraw
+ call assert_equal('TARGET_TARGETTARGET', Screenline(2))
+
+ setlocal conceallevel=2
+ call matchadd('Conceal', 'TARGET', 10, -1, {'conceal': 't'})
+
+ redraw
+ call assert_equal('t_tt', Screenline(2))
+
+ quit!
+endfunc
+
+func Test_matchadd_and_syn_conceal()
+ new
+ let cnt='Inductive bool : Type := | true : bool | false : bool.'
+ let expect = 'Inductive - : Type := | true : - | false : -.'
+ 0put =cnt
+ " set filetype and :syntax on to change screenattr()
+ set cole=1 cocu=nv
+ hi link CheckedByCoq WarningMsg
+ syntax on
+ syntax keyword coqKwd bool conceal cchar=-
+ redraw!
+ call assert_equal(expect, Screenline(1))
+ call assert_notequal(screenattr(1, 10) , screenattr(1, 11))
+ call assert_notequal(screenattr(1, 11) , screenattr(1, 12))
+ call assert_equal(screenattr(1, 11) , screenattr(1, 32))
+ call matchadd('CheckedByCoq', '\%<2l\%>9c\%<16c')
+ redraw!
+ call assert_equal(expect, Screenline(1))
+ call assert_notequal(screenattr(1, 10) , screenattr(1, 11))
+ call assert_notequal(screenattr(1, 11) , screenattr(1, 12))
+ call assert_equal(screenattr(1, 11) , screenattr(1, 32))
+endfunc
diff --git a/src/testdir/test_matchadd_conceal_utf8.vim b/src/testdir/test_matchadd_conceal_utf8.vim
new file mode 100644
index 0000000..d280c15
--- /dev/null
+++ b/src/testdir/test_matchadd_conceal_utf8.vim
@@ -0,0 +1,43 @@
+" Test for matchadd() and conceal feature using utf-8.
+if !has('conceal')
+ finish
+endif
+
+if !has('gui_running') && has('unix')
+ set term=ansi
+endif
+
+func s:screenline(lnum) abort
+ let line = []
+ for c in range(1, winwidth(0))
+ call add(line, nr2char(screenchar(a:lnum, c)))
+ endfor
+ return s:trim(join(line, ''))
+endfunc
+
+func s:trim(str) abort
+ return matchstr(a:str,'^\s*\zs.\{-}\ze\s*$')
+endfunc
+
+func Test_match_using_multibyte_conceal_char()
+ new
+ setlocal concealcursor=n conceallevel=1
+
+ 1put='# This is a Test'
+ " 1234567890123456
+ let expect = '#ˑThisˑisˑaˑTest'
+
+ call cursor(1, 1)
+ call matchadd('Conceal', '\%2l ', 20, -1, {'conceal': "\u02d1"})
+ redraw!
+
+ let lnum = 2
+ call assert_equal(expect, s:screenline(lnum))
+ call assert_notequal(screenattr(lnum, 1), screenattr(lnum, 2))
+ call assert_equal(screenattr(lnum, 2), screenattr(lnum, 7))
+ call assert_equal(screenattr(lnum, 2), screenattr(lnum, 10))
+ call assert_equal(screenattr(lnum, 2), screenattr(lnum, 12))
+ call assert_equal(screenattr(lnum, 1), screenattr(lnum, 16))
+
+ quit!
+endfunc
diff --git a/src/testdir/test_menu.vim b/src/testdir/test_menu.vim
new file mode 100644
index 0000000..6462d51
--- /dev/null
+++ b/src/testdir/test_menu.vim
@@ -0,0 +1,66 @@
+" Test that the system menu can be loaded.
+
+if !has('menu')
+ finish
+endif
+
+func Test_load_menu()
+ try
+ source $VIMRUNTIME/menu.vim
+ catch
+ call assert_report('error while loading menus: ' . v:exception)
+ endtry
+ call assert_match('browse confirm w', execute(':menu File.Save'))
+ source $VIMRUNTIME/delmenu.vim
+endfunc
+
+func Test_translate_menu()
+ if !has('multi_lang')
+ return
+ endif
+ if !filereadable($VIMRUNTIME . '/lang/menu_de_de.latin1.vim')
+ throw 'Skipped: translated menu not found'
+ endif
+
+ " First delete any English menus.
+ source $VIMRUNTIME/delmenu.vim
+ set langmenu=de_de
+ source $VIMRUNTIME/menu.vim
+ call assert_match('browse confirm w', execute(':menu Datei.Speichern'))
+
+ source $VIMRUNTIME/delmenu.vim
+endfunc
+
+func Test_menu_commands()
+ nmenu 2 Test.FooBar :let g:did_menu = 'normal'<CR>
+ vmenu 2 Test.FooBar :let g:did_menu = 'visual'<CR>
+ smenu 2 Test.FooBar :let g:did_menu = 'select'<CR>
+ omenu 2 Test.FooBar :let g:did_menu = 'op-pending'<CR>
+ tlmenu 2 Test.FooBar :let g:did_menu = 'terminal'<CR>
+ imenu 2 Test.FooBar :let g:did_menu = 'insert'<CR>
+ cmenu 2 Test.FooBar :let g:did_menu = 'cmdline'<CR>
+ emenu n Test.FooBar
+ call assert_equal('normal', g:did_menu)
+ emenu v Test.FooBar
+ call assert_equal('visual', g:did_menu)
+ emenu s Test.FooBar
+ call assert_equal('select', g:did_menu)
+ emenu o Test.FooBar
+ call assert_equal('op-pending', g:did_menu)
+ emenu t Test.FooBar
+ call assert_equal('terminal', g:did_menu)
+ emenu i Test.FooBar
+ call assert_equal('insert', g:did_menu)
+ emenu c Test.FooBar
+ call assert_equal('cmdline', g:did_menu)
+
+ aunmenu Test.FooBar
+ tlunmenu Test.FooBar
+ call assert_fails('emenu n Test.FooBar', 'E334:')
+
+ nmenu 2 Test.FooBar.Child :let g:did_menu = 'foobar'<CR>
+ call assert_fails('emenu n Test.FooBar', 'E333:')
+ nunmenu Test.FooBar.Child
+
+ unlet g:did_menu
+endfun
diff --git a/src/testdir/test_messages.vim b/src/testdir/test_messages.vim
new file mode 100644
index 0000000..4bdc136
--- /dev/null
+++ b/src/testdir/test_messages.vim
@@ -0,0 +1,94 @@
+" Tests for :messages, :echomsg, :echoerr
+
+function Test_messages()
+ let oldmore = &more
+ try
+ set nomore
+ " Avoid the "message maintainer" line.
+ let $LANG = ''
+
+ let arr = map(range(10), '"hello" . v:val')
+ for s in arr
+ echomsg s | redraw
+ endfor
+ let result = ''
+
+ " get last two messages
+ redir => result
+ 2messages | redraw
+ redir END
+ let msg_list = split(result, "\n")
+ call assert_equal(["hello8", "hello9"], msg_list)
+
+ " clear messages without last one
+ 1messages clear
+ redir => result
+ redraw | messages
+ redir END
+ let msg_list = split(result, "\n")
+ call assert_equal(['hello9'], msg_list)
+
+ " clear all messages
+ messages clear
+ redir => result
+ redraw | messages
+ redir END
+ call assert_equal('', result)
+ finally
+ let &more = oldmore
+ endtry
+endfunction
+
+" Patch 7.4.1696 defined the "clearmode()" function for clearing the mode
+" indicator (e.g., "-- INSERT --") when ":stopinsert" is invoked. Message
+" output could then be disturbed when 'cmdheight' was greater than one.
+" This test ensures that the bugfix for this issue remains in place.
+func Test_stopinsert_does_not_break_message_output()
+ set cmdheight=2
+ redraw!
+
+ stopinsert | echo 'test echo'
+ call assert_equal(116, screenchar(&lines - 1, 1))
+ call assert_equal(32, screenchar(&lines, 1))
+ redraw!
+
+ stopinsert | echomsg 'test echomsg'
+ call assert_equal(116, screenchar(&lines - 1, 1))
+ call assert_equal(32, screenchar(&lines, 1))
+ redraw!
+
+ set cmdheight&
+endfunc
+
+func Test_message_completion()
+ call feedkeys(":message \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"message clear', @:)
+endfunc
+
+func Test_echomsg()
+ call assert_equal("\nhello", execute(':echomsg "hello"'))
+ call assert_equal("\n", execute(':echomsg ""'))
+ call assert_equal("\n12345", execute(':echomsg 12345'))
+ call assert_equal("\n[]", execute(':echomsg []'))
+ call assert_equal("\n[1, 2, 3]", execute(':echomsg [1, 2, 3]'))
+ call assert_equal("\n{}", execute(':echomsg {}'))
+ call assert_equal("\n{'a': 1, 'b': 2}", execute(':echomsg {"a": 1, "b": 2}'))
+ if has('float')
+ call assert_equal("\n1.23", execute(':echomsg 1.23'))
+ endif
+ call assert_match("function('<lambda>\\d*')", execute(':echomsg {-> 1234}'))
+endfunc
+
+func Test_echoerr()
+ call test_ignore_error('IgNoRe')
+ call assert_equal("\nIgNoRe hello", execute(':echoerr "IgNoRe hello"'))
+ call assert_equal("\n12345 IgNoRe", execute(':echoerr 12345 "IgNoRe"'))
+ call assert_equal("\n[1, 2, 'IgNoRe']", execute(':echoerr [1, 2, "IgNoRe"]'))
+ call assert_equal("\n{'IgNoRe': 2, 'a': 1}", execute(':echoerr {"a": 1, "IgNoRe": 2}'))
+ if has('float')
+ call assert_equal("\n1.23 IgNoRe", execute(':echoerr 1.23 "IgNoRe"'))
+ endif
+ call test_ignore_error('<lambda>')
+ call assert_match("function('<lambda>\\d*')", execute(':echoerr {-> 1234}'))
+ call test_ignore_error('RESET')
+endfunc
diff --git a/src/testdir/test_mksession.vim b/src/testdir/test_mksession.vim
new file mode 100644
index 0000000..456cd1e
--- /dev/null
+++ b/src/testdir/test_mksession.vim
@@ -0,0 +1,498 @@
+" Test for :mksession, :mkview and :loadview in latin1 encoding
+
+set encoding=latin1
+scriptencoding latin1
+
+if !has('mksession')
+ finish
+endif
+
+source shared.vim
+
+func Test_mksession()
+ tabnew
+ let wrap_save = &wrap
+ set sessionoptions=buffers splitbelow fileencoding=latin1
+ call setline(1, [
+ \ 'start:',
+ \ 'no multibyte chAracter',
+ \ ' one leaDing tab',
+ \ ' four leadinG spaces',
+ \ 'two consecutive tabs',
+ \ 'two tabs in one line',
+ \ 'one ä multibyteCharacter',
+ \ 'aä Ä two multiByte characters',
+ \ 'Aäöü three mulTibyte characters',
+ \ 'short line',
+ \ ])
+ let tmpfile = 'Xtemp'
+ exec 'w! ' . tmpfile
+ /^start:
+ set wrap
+ vsplit
+ norm! j16|
+ split
+ norm! j16|
+ split
+ norm! j16|
+ split
+ norm! j8|
+ split
+ norm! j8|
+ split
+ norm! j16|
+ split
+ norm! j16|
+ split
+ norm! j16|
+ split
+ norm! j$
+ wincmd l
+
+ set nowrap
+ /^start:
+ norm! j16|3zl
+ split
+ norm! j016|3zl
+ split
+ norm! j016|3zl
+ split
+ norm! j08|3zl
+ split
+ norm! j08|3zl
+ split
+ norm! j016|3zl
+ split
+ norm! j016|3zl
+ split
+ norm! j016|3zl
+ split
+ call wincol()
+ mksession! Xtest_mks.out
+ let li = filter(readfile('Xtest_mks.out'), 'v:val =~# "\\(^ *normal! [0$]\\|^ *exe ''normal!\\)"')
+ let expected = [
+ \ 'normal! 016|',
+ \ 'normal! 016|',
+ \ 'normal! 016|',
+ \ 'normal! 08|',
+ \ 'normal! 08|',
+ \ 'normal! 016|',
+ \ 'normal! 016|',
+ \ 'normal! 016|',
+ \ 'normal! $',
+ \ " exe 'normal! ' . s:c . '|zs' . 16 . '|'",
+ \ " normal! 016|",
+ \ " exe 'normal! ' . s:c . '|zs' . 16 . '|'",
+ \ " normal! 016|",
+ \ " exe 'normal! ' . s:c . '|zs' . 16 . '|'",
+ \ " normal! 016|",
+ \ " exe 'normal! ' . s:c . '|zs' . 8 . '|'",
+ \ " normal! 08|",
+ \ " exe 'normal! ' . s:c . '|zs' . 8 . '|'",
+ \ " normal! 08|",
+ \ " exe 'normal! ' . s:c . '|zs' . 16 . '|'",
+ \ " normal! 016|",
+ \ " exe 'normal! ' . s:c . '|zs' . 16 . '|'",
+ \ " normal! 016|",
+ \ " exe 'normal! ' . s:c . '|zs' . 16 . '|'",
+ \ " normal! 016|",
+ \ " exe 'normal! ' . s:c . '|zs' . 16 . '|'",
+ \ " normal! 016|"
+ \ ]
+ call assert_equal(expected, li)
+ tabclose!
+
+ call delete('Xtest_mks.out')
+ call delete(tmpfile)
+ let &wrap = wrap_save
+ set sessionoptions&
+endfunc
+
+func Test_mksession_winheight()
+ new
+ set winheight=10
+ set winminheight=2
+ mksession! Xtest_mks.out
+ source Xtest_mks.out
+
+ call delete('Xtest_mks.out')
+endfunc
+
+func Test_mksession_large_winheight()
+ set winheight=999
+ mksession! Xtest_mks_winheight.out
+ set winheight&
+ source Xtest_mks_winheight.out
+ call delete('Xtest_mks_winheight.out')
+endfunc
+
+func Test_mksession_rtp()
+ if has('win32')
+ " TODO: fix problem with backslashes
+ return
+ endif
+ new
+ let _rtp=&rtp
+ " Make a real long (invalid) runtimepath value,
+ " that should exceed PATH_MAX (hopefully)
+ let newrtp=&rtp.',~'.repeat('/foobar', 1000)
+ let newrtp.=",".expand("$HOME")."/.vim"
+ let &rtp=newrtp
+
+ " determine expected value
+ let expected=split(&rtp, ',')
+ let expected = map(expected, '"set runtimepath+=".v:val')
+ let expected = ['set runtimepath='] + expected
+ let expected = map(expected, {v,w -> substitute(w, $HOME, "~", "g")})
+
+ mksession! Xtest_mks.out
+ let &rtp=_rtp
+ let li = filter(readfile('Xtest_mks.out'), 'v:val =~# "runtimepath"')
+ call assert_equal(expected, li)
+
+ call delete('Xtest_mks.out')
+endfunc
+
+func Test_mksession_arglist()
+ argdel *
+ next file1 file2 file3 file4
+ mksession! Xtest_mks.out
+ source Xtest_mks.out
+ call assert_equal(['file1', 'file2', 'file3', 'file4'], argv())
+
+ call delete('Xtest_mks.out')
+ argdel *
+endfunc
+
+func Test_mksession_one_buffer_two_windows()
+ edit Xtest1
+ new Xtest2
+ split
+ mksession! Xtest_mks.out
+ let lines = readfile('Xtest_mks.out')
+ let count1 = 0
+ let count2 = 0
+ let count2buf = 0
+ for line in lines
+ if line =~ 'edit \f*Xtest1$'
+ let count1 += 1
+ endif
+ if line =~ 'edit \f\{-}Xtest2'
+ let count2 += 1
+ endif
+ if line =~ 'buffer \f\{-}Xtest2'
+ let count2buf += 1
+ endif
+ endfor
+ call assert_equal(1, count1, 'Xtest1 count')
+ call assert_equal(2, count2, 'Xtest2 count')
+ call assert_equal(2, count2buf, 'Xtest2 buffer count')
+
+ close
+ bwipe!
+ call delete('Xtest_mks.out')
+endfunc
+
+func Test_mksession_lcd_multiple_tabs()
+ tabnew
+ tabnew
+ lcd .
+ tabfirst
+ lcd .
+ mksession! Xtest_mks.out
+ tabonly
+ source Xtest_mks.out
+ call assert_true(haslocaldir(), 'Tab 1 localdir')
+ tabnext 2
+ call assert_true(!haslocaldir(), 'Tab 2 localdir')
+ tabnext 3
+ call assert_true(haslocaldir(), 'Tab 3 localdir')
+ call delete('Xtest_mks.out')
+endfunc
+
+func Test_mksession_blank_tabs()
+ tabnew
+ tabnew
+ tabnew
+ tabnext 3
+ mksession! Xtest_mks.out
+ tabnew
+ tabnew
+ tabnext 2
+ source Xtest_mks.out
+ call assert_equal(4, tabpagenr('$'), 'session restore should restore number of tabs')
+ call assert_equal(3, tabpagenr(), 'session restore should restore the active tab')
+ call delete('Xtest_mks.out')
+endfunc
+
+func Test_mksession_buffer_count()
+ set hidden
+
+ " Edit exactly three files in the current session.
+ %bwipe!
+ e Xfoo | tabe Xbar | tabe Xbaz
+ tabdo write
+ mksession! Xtest_mks.out
+
+ " Verify that loading the session does not create additional buffers.
+ %bwipe!
+ source Xtest_mks.out
+ call assert_equal(3, len(getbufinfo()))
+
+ " Clean up.
+ call delete('Xfoo')
+ call delete('Xbar')
+ call delete('Xbaz')
+ call delete('Xtest_mks.out')
+ %bwipe!
+ set hidden&
+endfunc
+
+if has('extra_search')
+
+func Test_mksession_hlsearch()
+ set hlsearch
+ mksession! Xtest_mks.out
+ nohlsearch
+ source Xtest_mks.out
+ call assert_equal(1, v:hlsearch, 'session should restore search highlighting state')
+ nohlsearch
+ mksession! Xtest_mks.out
+ source Xtest_mks.out
+ call assert_equal(0, v:hlsearch, 'session should restore search highlighting state')
+ call delete('Xtest_mks.out')
+endfunc
+
+endif
+
+
+func Test_mksession_blank_windows()
+ split
+ split
+ split
+ 3 wincmd w
+ mksession! Xtest_mks.out
+ split
+ split
+ 2 wincmd w
+ source Xtest_mks.out
+ call assert_equal(4, winnr('$'), 'session restore should restore number of windows')
+ call assert_equal(3, winnr(), 'session restore should restore the active window')
+ call delete('Xtest_mks.out')
+endfunc
+
+if has('terminal')
+
+func Test_mksession_terminal_shell()
+ terminal
+ mksession! Xtest_mks.out
+ let lines = readfile('Xtest_mks.out')
+ let term_cmd = ''
+ for line in lines
+ if line =~ '^terminal'
+ let term_cmd = line
+ elseif line =~ 'badd.*' . &shell
+ call assert_report('unexpected shell line: ' . line)
+ endif
+ endfor
+ call assert_match('terminal ++curwin ++cols=\d\+ ++rows=\d\+\s*.*$', term_cmd)
+
+ call Stop_shell_in_terminal(bufnr('%'))
+ call delete('Xtest_mks.out')
+endfunc
+
+func Test_mksession_terminal_no_restore_cmdarg()
+ terminal ++norestore
+ mksession! Xtest_mks.out
+ let lines = readfile('Xtest_mks.out')
+ let term_cmd = ''
+ for line in lines
+ if line =~ '^terminal'
+ call assert_report('session must not restore teminal')
+ endif
+ endfor
+
+ call Stop_shell_in_terminal(bufnr('%'))
+ call delete('Xtest_mks.out')
+endfunc
+
+func Test_mksession_terminal_no_restore_funcarg()
+ call term_start(&shell, {'norestore': 1})
+ mksession! Xtest_mks.out
+ let lines = readfile('Xtest_mks.out')
+ let term_cmd = ''
+ for line in lines
+ if line =~ '^terminal'
+ call assert_report('session must not restore teminal')
+ endif
+ endfor
+
+ call Stop_shell_in_terminal(bufnr('%'))
+ call delete('Xtest_mks.out')
+endfunc
+
+func Test_mksession_terminal_no_restore_func()
+ terminal
+ call term_setrestore(bufnr('%'), 'NONE')
+ mksession! Xtest_mks.out
+ let lines = readfile('Xtest_mks.out')
+ let term_cmd = ''
+ for line in lines
+ if line =~ '^terminal'
+ call assert_report('session must not restore teminal')
+ endif
+ endfor
+
+ call Stop_shell_in_terminal(bufnr('%'))
+ call delete('Xtest_mks.out')
+endfunc
+
+func Test_mksession_terminal_no_ssop()
+ terminal
+ set sessionoptions-=terminal
+ mksession! Xtest_mks.out
+ let lines = readfile('Xtest_mks.out')
+ let term_cmd = ''
+ for line in lines
+ if line =~ '^terminal'
+ call assert_report('session must not restore teminal')
+ endif
+ endfor
+
+ call Stop_shell_in_terminal(bufnr('%'))
+ call delete('Xtest_mks.out')
+ set sessionoptions&
+endfunc
+
+func Test_mksession_terminal_restore_other()
+ terminal
+ call term_setrestore(bufnr('%'), 'other')
+ mksession! Xtest_mks.out
+ let lines = readfile('Xtest_mks.out')
+ let term_cmd = ''
+ for line in lines
+ if line =~ '^terminal'
+ let term_cmd = line
+ endif
+ endfor
+ call assert_match('terminal ++curwin ++cols=\d\+ ++rows=\d\+.*other', term_cmd)
+
+ call Stop_shell_in_terminal(bufnr('%'))
+ call delete('Xtest_mks.out')
+endfunc
+
+endif " has('terminal')
+
+" Test :mkview with a file argument.
+func Test_mkview_file()
+ " Create a view with line number and a fold.
+ help :mkview
+ set number
+ norm! V}zf0
+ let pos = getpos('.')
+ let linefoldclosed1 = foldclosed('.')
+ mkview! Xview
+ set nonumber
+ norm! zrj
+ " We can close the help window, as mkview with a file name should
+ " generate a command to edit the file.
+ helpclose
+
+ source Xview
+ call assert_equal(1, &number)
+ call assert_match('\*:mkview\*$', getline('.'))
+ call assert_equal(pos, getpos('.'))
+ call assert_equal(linefoldclosed1, foldclosed('.'))
+
+ " Creating a view again with the same file name should fail (file
+ " already exists). But with a !, the previous view should be
+ " overwritten without error.
+ help :loadview
+ call assert_fails('mkview Xview', 'E189:')
+ call assert_match('\*:loadview\*$', getline('.'))
+ mkview! Xview
+ call assert_match('\*:loadview\*$', getline('.'))
+
+ call delete('Xview')
+ bwipe
+endfunc
+
+" Test :mkview and :loadview with a custom 'viewdir'.
+func Test_mkview_loadview_with_viewdir()
+ set viewdir=Xviewdir
+
+ help :mkview
+ set number
+ norm! V}zf
+ let pos = getpos('.')
+ let linefoldclosed1 = foldclosed('.')
+ mkview 1
+ set nonumber
+ norm! zrj
+
+ loadview 1
+
+ " The directory Xviewdir/ should have been created and the view
+ " should be stored in that directory.
+ call assert_equal('Xviewdir/' .
+ \ substitute(
+ \ substitute(
+ \ expand('%:p'), '/', '=+', 'g'), ':', '=-', 'g') . '=1.vim',
+ \ glob('Xviewdir/*'))
+ call assert_equal(1, &number)
+ call assert_match('\*:mkview\*$', getline('.'))
+ call assert_equal(pos, getpos('.'))
+ call assert_equal(linefoldclosed1, foldclosed('.'))
+
+ call delete('Xviewdir', 'rf')
+ set viewdir&
+ helpclose
+endfunc
+
+func Test_mkview_no_file_name()
+ new
+ " :mkview or :mkview {nr} should fail in a unnamed buffer.
+ call assert_fails('mkview', 'E32:')
+ call assert_fails('mkview 1', 'E32:')
+
+ " :mkview {file} should succeed in a unnamed buffer.
+ mkview Xview
+ help
+ source Xview
+ call assert_equal('', bufname('%'))
+
+ call delete('Xview')
+ %bwipe
+endfunc
+
+" A clean session (one empty buffer, one window, and one tab) should not
+" set any error messages when sourced because no commands should fail.
+func Test_mksession_no_errmsg()
+ let v:errmsg = ''
+ %bwipe!
+ mksession! Xtest_mks.out
+ source Xtest_mks.out
+ call assert_equal('', v:errmsg)
+ call delete('Xtest_mks.out')
+endfunc
+
+func Test_mksession_quote_in_filename()
+ if !has('unix')
+ " only Unix can handle this weird filename
+ return
+ endif
+ let v:errmsg = ''
+ %bwipe!
+ split another
+ split x'y\"z
+ mksession! Xtest_mks_quoted.out
+ %bwipe!
+ source Xtest_mks_quoted.out
+ call assert_true(bufexists("x'y\"z"))
+
+ %bwipe!
+ call delete('Xtest_mks_quoted.out')
+endfunc
+
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/test_mksession_utf8.vim b/src/testdir/test_mksession_utf8.vim
new file mode 100644
index 0000000..67af3a9
--- /dev/null
+++ b/src/testdir/test_mksession_utf8.vim
@@ -0,0 +1,105 @@
+" Test for :mksession, :mkview and :loadview in utf-8 encoding
+
+set encoding=utf-8
+scriptencoding utf-8
+
+if !has('mksession')
+ finish
+endif
+
+func Test_mksession_utf8()
+ tabnew
+ let wrap_save = &wrap
+ set sessionoptions=buffers splitbelow fileencoding=utf-8
+ call setline(1, [
+ \ 'start:',
+ \ 'no multibyte chAracter',
+ \ ' one leaDing tab',
+ \ ' four leadinG spaces',
+ \ 'two consecutive tabs',
+ \ 'two tabs in one line',
+ \ 'one … multibyteCharacter',
+ \ 'a “b†two multiByte characters',
+ \ '“câ€1€ three mulTibyte characters'
+ \ ])
+ let tmpfile = tempname()
+ exec 'w! ' . tmpfile
+ /^start:
+ set wrap
+ vsplit
+ norm! j16|
+ split
+ norm! j16|
+ split
+ norm! j16|
+ split
+ norm! j8|
+ split
+ norm! j8|
+ split
+ norm! j16|
+ split
+ norm! j16|
+ split
+ norm! j16|
+ wincmd l
+
+ set nowrap
+ /^start:
+ norm! j16|3zl
+ split
+ norm! j016|3zl
+ split
+ norm! j016|3zl
+ split
+ norm! j08|3zl
+ split
+ norm! j08|3zl
+ split
+ norm! j016|3zl
+ split
+ norm! j016|3zl
+ split
+ norm! j016|3zl
+ split
+ call wincol()
+ mksession! test_mks.out
+ let li = filter(readfile('test_mks.out'), 'v:val =~# "\\(^ *normal! 0\\|^ *exe ''normal!\\)"')
+ let expected = [
+ \ 'normal! 016|',
+ \ 'normal! 016|',
+ \ 'normal! 016|',
+ \ 'normal! 08|',
+ \ 'normal! 08|',
+ \ 'normal! 016|',
+ \ 'normal! 016|',
+ \ 'normal! 016|',
+ \ " exe 'normal! ' . s:c . '|zs' . 16 . '|'",
+ \ " normal! 016|",
+ \ " exe 'normal! ' . s:c . '|zs' . 16 . '|'",
+ \ " normal! 016|",
+ \ " exe 'normal! ' . s:c . '|zs' . 16 . '|'",
+ \ " normal! 016|",
+ \ " exe 'normal! ' . s:c . '|zs' . 8 . '|'",
+ \ " normal! 08|",
+ \ " exe 'normal! ' . s:c . '|zs' . 8 . '|'",
+ \ " normal! 08|",
+ \ " exe 'normal! ' . s:c . '|zs' . 16 . '|'",
+ \ " normal! 016|",
+ \ " exe 'normal! ' . s:c . '|zs' . 16 . '|'",
+ \ " normal! 016|",
+ \ " exe 'normal! ' . s:c . '|zs' . 16 . '|'",
+ \ " normal! 016|",
+ \ " exe 'normal! ' . s:c . '|zs' . 16 . '|'",
+ \ " normal! 016|"
+ \ ]
+ call assert_equal(expected, li)
+ tabclose!
+
+ call delete('test_mks.out')
+ call delete(tmpfile)
+ let &wrap = wrap_save
+ set sessionoptions& splitbelow& fileencoding&
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/test_modeline.vim b/src/testdir/test_modeline.vim
new file mode 100644
index 0000000..e0f97c4
--- /dev/null
+++ b/src/testdir/test_modeline.vim
@@ -0,0 +1,94 @@
+" Tests for parsing the modeline.
+
+func Test_modeline_invalid()
+ " This was reading allocated memory in the past.
+ call writefile(['vi:0', 'nothing'], 'Xmodeline')
+ let modeline = &modeline
+ set modeline
+ call assert_fails('split Xmodeline', 'E518:')
+
+ let &modeline = modeline
+ bwipe!
+ call delete('Xmodeline')
+endfunc
+
+func Test_modeline_filetype()
+ call writefile(['vim: set ft=c :', 'nothing'], 'Xmodeline_filetype')
+ let modeline = &modeline
+ set modeline
+ filetype plugin on
+ split Xmodeline_filetype
+ call assert_equal("c", &filetype)
+ call assert_equal(1, b:did_ftplugin)
+ call assert_equal("ccomplete#Complete", &ofu)
+
+ bwipe!
+ call delete('Xmodeline_filetype')
+ let &modeline = modeline
+ filetype plugin off
+endfunc
+
+func Test_modeline_syntax()
+ call writefile(['vim: set syn=c :', 'nothing'], 'Xmodeline_syntax')
+ let modeline = &modeline
+ set modeline
+ syntax enable
+ split Xmodeline_syntax
+ call assert_equal("c", &syntax)
+ call assert_equal("c", b:current_syntax)
+
+ bwipe!
+ call delete('Xmodeline_syntax')
+ let &modeline = modeline
+ syntax off
+endfunc
+
+func Test_modeline_keymap()
+ if !has('keymap')
+ return
+ endif
+ call writefile(['vim: set keymap=greek :', 'nothing'], 'Xmodeline_keymap')
+ let modeline = &modeline
+ set modeline
+ split Xmodeline_keymap
+ call assert_equal("greek", &keymap)
+ call assert_match('greek\|grk', b:keymap_name)
+
+ bwipe!
+ call delete('Xmodeline_keymap')
+ let &modeline = modeline
+ set keymap= iminsert=0 imsearch=-1
+endfunc
+
+func s:modeline_fails(what, text)
+ let fname = "Xmodeline_fails_" . a:what
+ call writefile(['vim: set ' . a:text . ' :', 'nothing'], fname)
+ let modeline = &modeline
+ set modeline
+ filetype plugin on
+ syntax enable
+ call assert_fails('split ' . fname, 'E474:')
+ call assert_equal("", &filetype)
+ call assert_equal("", &syntax)
+
+ bwipe!
+ call delete(fname)
+ let &modeline = modeline
+ filetype plugin off
+ syntax off
+endfunc
+
+func Test_modeline_filetype_fails()
+ call s:modeline_fails('filetype', 'ft=evil$CMD')
+endfunc
+
+func Test_modeline_syntax_fails()
+ call s:modeline_fails('syntax', 'syn=evil$CMD')
+endfunc
+
+func Test_modeline_keymap_fails()
+ if !has('keymap')
+ return
+ endif
+ call s:modeline_fails('keymap', 'keymap=evil$CMD')
+endfunc
diff --git a/src/testdir/test_move.vim b/src/testdir/test_move.vim
new file mode 100644
index 0000000..d774c93
--- /dev/null
+++ b/src/testdir/test_move.vim
@@ -0,0 +1,40 @@
+" Test the ":move" command.
+
+func Test_move()
+ enew!
+ call append(0, ['line 1', 'line 2', 'line 3'])
+ g /^$/ delete _
+ set nomodified
+
+ move .
+ call assert_equal(['line 1', 'line 2', 'line 3'], getline(1, 3))
+ call assert_false(&modified)
+
+ 1,2move 0
+ call assert_equal(['line 1', 'line 2', 'line 3'], getline(1, 3))
+ call assert_false(&modified)
+
+ 1,3move 3
+ call assert_equal(['line 1', 'line 2', 'line 3'], getline(1, 3))
+ call assert_false(&modified)
+
+ 1move 2
+ call assert_equal(['line 2', 'line 1', 'line 3'], getline(1, 3))
+ call assert_true(&modified)
+ set nomodified
+
+ 3move 0
+ call assert_equal(['line 3', 'line 2', 'line 1'], getline(1, 3))
+ call assert_true(&modified)
+ set nomodified
+
+ 2,3move 0
+ call assert_equal(['line 2', 'line 1', 'line 3'], getline(1, 3))
+ call assert_true(&modified)
+ set nomodified
+
+ call assert_fails('1,2move 1', 'E134')
+ call assert_fails('2,3move 2', 'E134')
+
+ %bwipeout!
+endfunc
diff --git a/src/testdir/test_nested_function.vim b/src/testdir/test_nested_function.vim
new file mode 100644
index 0000000..ec48f03
--- /dev/null
+++ b/src/testdir/test_nested_function.vim
@@ -0,0 +1,67 @@
+"Tests for nested functions
+"
+func NestedFunc()
+ func! Func1()
+ let g:text .= 'Func1 '
+ endfunc
+ call Func1()
+ func! s:func2()
+ let g:text .= 's:func2 '
+ endfunc
+ call s:func2()
+ func! s:_func3()
+ let g:text .= 's:_func3 '
+ endfunc
+ call s:_func3()
+ let fn = 'Func4'
+ func! {fn}()
+ let g:text .= 'Func4 '
+ endfunc
+ call {fn}()
+ let fn = 'func5'
+ func! s:{fn}()
+ let g:text .= 's:func5'
+ endfunc
+ call s:{fn}()
+endfunc
+
+func Test_nested_functions()
+ let g:text = ''
+ call NestedFunc()
+ call assert_equal('Func1 s:func2 s:_func3 Func4 s:func5', g:text)
+endfunction
+
+func Test_nested_argument()
+ func g:X()
+ let g:Y = function('sort')
+ endfunc
+ let g:Y = function('sort')
+ echo g:Y([], g:X())
+ delfunc g:X
+ unlet g:Y
+endfunc
+
+func Recurse(count)
+ if a:count > 0
+ call Recurse(a:count - 1)
+ endif
+endfunc
+
+func Test_max_nesting()
+ " TODO: why does this fail on Windows? Runs out of stack perhaps?
+ if has('win32')
+ return
+ endif
+ let call_depth_here = 2
+ let ex_depth_here = 5
+ set mfd&
+
+ call Recurse(99 - call_depth_here)
+ call assert_fails('call Recurse(' . (100 - call_depth_here) . ')', 'E132:')
+
+ set mfd=210
+ call Recurse(209 - ex_depth_here)
+ call assert_fails('call Recurse(' . (210 - ex_depth_here) . ')', 'E169:')
+
+ set mfd&
+endfunc
diff --git a/src/testdir/test_netbeans.py b/src/testdir/test_netbeans.py
new file mode 100644
index 0000000..bdebb54
--- /dev/null
+++ b/src/testdir/test_netbeans.py
@@ -0,0 +1,91 @@
+#!/usr/bin/python
+#
+# Server that will communicate with Vim through the netbeans interface.
+# Used by test_netbeans.vim.
+#
+# This requires Python 2.6 or later.
+
+from __future__ import print_function
+import socket
+import sys
+import time
+import threading
+
+try:
+ # Python 3
+ import socketserver
+except ImportError:
+ # Python 2
+ import SocketServer as socketserver
+
+class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
+
+ def handle(self):
+ print("=== socket opened ===")
+ while True:
+ try:
+ received = self.request.recv(4096).decode('utf-8')
+ except socket.error:
+ print("=== socket error ===")
+ break
+ except IOError:
+ print("=== socket closed ===")
+ break
+ if received == '':
+ print("=== socket closed ===")
+ break
+ print("received: {0}".format(received))
+
+ # Write the received line into the file, so that the test can check
+ # what happened.
+ with open("Xnetbeans", "a") as myfile:
+ myfile.write(received)
+
+ response = ''
+ if received.find('XREADME.txt') > 0:
+ name = received.split('"')[1]
+ response = '5:putBufferNumber!33 "' + name + '"\n'
+ response += '5:setDot!1 3/19\n'
+ elif received.find('disconnect') > 0:
+ # we're done
+ self.server.shutdown()
+ return
+
+ if len(response) > 0:
+ self.request.sendall(response.encode('utf-8'))
+ # Write the respoinse into the file, so that the test can knows
+ # the command was sent.
+ with open("Xnetbeans", "a") as myfile:
+ myfile.write('send: ' + response)
+
+class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
+ pass
+
+def writePortInFile(port):
+ # Write the port number in Xportnr, so that the test knows it.
+ f = open("Xportnr", "w")
+ f.write("{0}".format(port))
+ f.close()
+
+if __name__ == "__main__":
+ HOST, PORT = "localhost", 0
+
+ server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)
+ ip, port = server.server_address
+
+ # Start a thread with the server. That thread will then start a new thread
+ # for each connection.
+ server_thread = threading.Thread(target=server.serve_forever)
+ server_thread.start()
+
+ writePortInFile(port)
+
+ print("Listening on port {0}".format(port))
+
+ # Main thread terminates, but the server continues running
+ # until server.shutdown() is called.
+ try:
+ while server_thread.isAlive():
+ server_thread.join(1)
+ except (KeyboardInterrupt, SystemExit):
+ server.shutdown()
diff --git a/src/testdir/test_netbeans.vim b/src/testdir/test_netbeans.vim
new file mode 100644
index 0000000..66177ad
--- /dev/null
+++ b/src/testdir/test_netbeans.vim
@@ -0,0 +1,86 @@
+" Test the netbeans interface.
+
+if !has('netbeans_intg')
+ finish
+endif
+
+source shared.vim
+
+let s:python = PythonProg()
+if s:python == ''
+ " Can't run this test.
+ finish
+endif
+
+" Run "testfunc" after sarting the server and stop the server afterwards.
+func s:run_server(testfunc, ...)
+ call RunServer('test_netbeans.py', a:testfunc, a:000)
+endfunc
+
+func Nb_basic(port)
+ call delete("Xnetbeans")
+ call writefile([], "Xnetbeans")
+ call writefile(repeat(['abcdefghijklmnopqrstuvwxyz'], 5), "XREADME.txt")
+ exe 'nbstart :localhost:' . a:port . ':bunny'
+ call assert_true(has("netbeans_enabled"))
+
+ call WaitFor('len(readfile("Xnetbeans")) > 2')
+ split +$ XREADME.txt
+
+ " Opening XREADME.txt will result in a setDot command
+ call WaitFor('len(readfile("Xnetbeans")) > 4')
+ call WaitFor('getcurpos()[1] == 3')
+ let pos = getcurpos()
+ call assert_equal(3, pos[1])
+ call assert_equal(20, pos[2])
+ close
+ nbclose
+
+ call WaitFor('len(readfile("Xnetbeans")) > 6')
+ call assert_false(has("netbeans_enabled"))
+ let lines = readfile("Xnetbeans")
+ call assert_equal('AUTH bunny', lines[0])
+ call assert_equal('0:version=0 "2.5"', lines[1])
+ call assert_equal('0:startupDone=0', lines[2])
+ call assert_equal('0:fileOpened=0 "XREADME.txt" T F', substitute(lines[3], '".*/', '"', ''))
+
+ call assert_equal('0:disconnect=1', lines[6])
+
+ call delete("Xnetbeans")
+ call delete("XREADME.txt")
+endfunc
+
+func Test_nb_basic()
+ call ch_log('Test_nb_basic')
+ call s:run_server('Nb_basic')
+endfunc
+
+func Nb_file_auth(port)
+ call delete("Xnetbeans")
+ call writefile([], "Xnetbeans")
+
+ call assert_fails('nbstart =notexist', 'E660:')
+ call writefile(['host=localhost', 'port=' . a:port, 'auth=bunny'], 'Xnbauth')
+ if has('unix')
+ call setfperm('Xnbauth', "rw-r--r--")
+ call assert_fails('nbstart =Xnbauth', 'E668:')
+ endif
+ call setfperm('Xnbauth', "rw-------")
+ exe 'nbstart =Xnbauth'
+ call assert_true(has("netbeans_enabled"))
+
+ call WaitFor('len(readfile("Xnetbeans")) > 2')
+ nbclose
+ let lines = readfile("Xnetbeans")
+ call assert_equal('AUTH bunny', lines[0])
+ call assert_equal('0:version=0 "2.5"', lines[1])
+ call assert_equal('0:startupDone=0', lines[2])
+
+ call delete("Xnbauth")
+ call delete("Xnetbeans")
+endfunc
+
+func Test_nb_file_auth()
+ call ch_log('Test_nb_file_auth')
+ call s:run_server('Nb_file_auth')
+endfunc
diff --git a/src/testdir/test_normal.vim b/src/testdir/test_normal.vim
new file mode 100644
index 0000000..1224a3f
--- /dev/null
+++ b/src/testdir/test_normal.vim
@@ -0,0 +1,2544 @@
+" Test for various Normal mode commands
+
+func Setup_NewWindow()
+ 10new
+ call setline(1, range(1,100))
+endfunc
+
+func MyFormatExpr()
+ " Adds '->$' at lines having numbers followed by trailing whitespace
+ for ln in range(v:lnum, v:lnum+v:count-1)
+ let line = getline(ln)
+ if getline(ln) =~# '\d\s\+$'
+ call setline(ln, substitute(line, '\s\+$', '', '') . '->$')
+ endif
+ endfor
+endfunc
+
+func CountSpaces(type, ...)
+ " for testing operatorfunc
+ " will count the number of spaces
+ " and return the result in g:a
+ let sel_save = &selection
+ let &selection = "inclusive"
+ let reg_save = @@
+
+ if a:0 " Invoked from Visual mode, use gv command.
+ silent exe "normal! gvy"
+ elseif a:type == 'line'
+ silent exe "normal! '[V']y"
+ else
+ silent exe "normal! `[v`]y"
+ endif
+ let g:a=strlen(substitute(@@, '[^ ]', '', 'g'))
+ let &selection = sel_save
+ let @@ = reg_save
+endfunc
+
+func OpfuncDummy(type, ...)
+ " for testing operatorfunc
+ let g:opt=&linebreak
+
+ if a:0 " Invoked from Visual mode, use gv command.
+ silent exe "normal! gvy"
+ elseif a:type == 'line'
+ silent exe "normal! '[V']y"
+ else
+ silent exe "normal! `[v`]y"
+ endif
+ " Create a new dummy window
+ new
+ let g:bufnr=bufnr('%')
+endfunc
+
+fun! Test_normal00_optrans()
+ new
+ call append(0, ['1 This is a simple test: abcd', '2 This is the second line', '3 this is the third line'])
+ 1
+ exe "norm! Sfoobar\<esc>"
+ call assert_equal(['foobar', '2 This is the second line', '3 this is the third line', ''], getline(1,'$'))
+ 2
+ exe "norm! $vbsone"
+ call assert_equal(['foobar', '2 This is the second one', '3 this is the third line', ''], getline(1,'$'))
+ norm! VS Second line here
+ call assert_equal(['foobar', ' Second line here', '3 this is the third line', ''], getline(1, '$'))
+ %d
+ call append(0, ['4 This is a simple test: abcd', '5 This is the second line', '6 this is the third line'])
+ call append(0, ['1 This is a simple test: abcd', '2 This is the second line', '3 this is the third line'])
+
+ 1
+ norm! 2D
+ call assert_equal(['3 this is the third line', '4 This is a simple test: abcd', '5 This is the second line', '6 this is the third line', ''], getline(1,'$'))
+ set cpo+=#
+ norm! 4D
+ call assert_equal(['', '4 This is a simple test: abcd', '5 This is the second line', '6 this is the third line', ''], getline(1,'$'))
+
+ " clean up
+ set cpo-=#
+ bw!
+endfunc
+
+func Test_normal01_keymodel()
+ call Setup_NewWindow()
+ " Test 1: depending on 'keymodel' <s-down> does something different
+ 50
+ call feedkeys("V\<S-Up>y", 'tx')
+ call assert_equal(['47', '48', '49', '50'], getline("'<", "'>"))
+ set keymodel=startsel
+ 50
+ call feedkeys("V\<S-Up>y", 'tx')
+ call assert_equal(['49', '50'], getline("'<", "'>"))
+ " Start visual mode when keymodel = startsel
+ 50
+ call feedkeys("\<S-Up>y", 'tx')
+ call assert_equal(['49', '5'], getreg(0, 0, 1))
+ " Do not start visual mode when keymodel=
+ set keymodel=
+ 50
+ call feedkeys("\<S-Up>y$", 'tx')
+ call assert_equal(['42'], getreg(0, 0, 1))
+ " Stop visual mode when keymodel=stopsel
+ set keymodel=stopsel
+ 50
+ call feedkeys("Vkk\<Up>yy", 'tx')
+ call assert_equal(['47'], getreg(0, 0, 1))
+
+ set keymodel=
+ 50
+ call feedkeys("Vkk\<Up>yy", 'tx')
+ call assert_equal(['47', '48', '49', '50'], getreg(0, 0, 1))
+
+ " clean up
+ bw!
+endfunc
+
+func Test_normal02_selectmode()
+ " some basic select mode tests
+ call Setup_NewWindow()
+ 50
+ norm! gHy
+ call assert_equal('y51', getline('.'))
+ call setline(1, range(1,100))
+ 50
+ exe ":norm! V9jo\<c-g>y"
+ call assert_equal('y60', getline('.'))
+ " clean up
+ bw!
+endfunc
+
+func Test_normal02_selectmode2()
+ " some basic select mode tests
+ call Setup_NewWindow()
+ 50
+ call feedkeys(":set im\n\<c-o>gHc\<c-o>:set noim\n", 'tx')
+ call assert_equal('c51', getline('.'))
+ " clean up
+ bw!
+endfunc
+
+func Test_normal03_join()
+ " basic join test
+ call Setup_NewWindow()
+ 50
+ norm! VJ
+ call assert_equal('50 51', getline('.'))
+ $
+ norm! J
+ call assert_equal('100', getline('.'))
+ $
+ norm! V9-gJ
+ call assert_equal('919293949596979899100', getline('.'))
+ call setline(1, range(1,100))
+ $
+ :j 10
+ call assert_equal('100', getline('.'))
+ " clean up
+ bw!
+endfunc
+
+func Test_normal04_filter()
+ " basic filter test
+ " only test on non windows platform
+ if has('win32')
+ return
+ endif
+ call Setup_NewWindow()
+ 1
+ call feedkeys("!!sed -e 's/^/| /'\n", 'tx')
+ call assert_equal('| 1', getline('.'))
+ 90
+ :sil :!echo one
+ call feedkeys('.', 'tx')
+ call assert_equal('| 90', getline('.'))
+ 95
+ set cpo+=!
+ " 2 <CR>, 1: for executing the command,
+ " 2: clear hit-enter-prompt
+ call feedkeys("!!\n", 'tx')
+ call feedkeys(":!echo one\n\n", 'tx')
+ call feedkeys(".", 'tx')
+ call assert_equal('one', getline('.'))
+ set cpo-=!
+ bw!
+endfunc
+
+func Test_normal05_formatexpr()
+ " basic formatexpr test
+ call Setup_NewWindow()
+ %d_
+ call setline(1, ['here: 1 ', '2', 'here: 3 ', '4', 'not here: '])
+ 1
+ set formatexpr=MyFormatExpr()
+ norm! gqG
+ call assert_equal(['here: 1->$', '2', 'here: 3->$', '4', 'not here: '], getline(1,'$'))
+ set formatexpr=
+ bw!
+endfunc
+
+func Test_normal05_formatexpr_newbuf()
+ " Edit another buffer in the 'formatexpr' function
+ new
+ func! Format()
+ edit another
+ endfunc
+ set formatexpr=Format()
+ norm gqG
+ bw!
+ set formatexpr=
+endfunc
+
+func Test_normal05_formatexpr_setopt()
+ " Change the 'formatexpr' value in the function
+ new
+ func! Format()
+ set formatexpr=
+ endfunc
+ set formatexpr=Format()
+ norm gqG
+ bw!
+ set formatexpr=
+endfunc
+
+func Test_normal06_formatprg()
+ " basic test for formatprg
+ " only test on non windows platform
+ if has('win32')
+ return
+ endif
+
+ " uses sed to number non-empty lines
+ call writefile(['#!/bin/sh', 'sed ''/./=''|sed ''/./{', 'N', 's/\n/ /', '}'''], 'Xsed_format.sh')
+ call system('chmod +x ./Xsed_format.sh')
+ let text = ['a', '', 'c', '', ' ', 'd', 'e']
+ let expected = ['1 a', '', '3 c', '', '5 ', '6 d', '7 e']
+
+ 10new
+ call setline(1, text)
+ set formatprg=./Xsed_format.sh
+ norm! gggqG
+ call assert_equal(expected, getline(1, '$'))
+ bw!
+
+ 10new
+ call setline(1, text)
+ set formatprg=donothing
+ setlocal formatprg=./Xsed_format.sh
+ norm! gggqG
+ call assert_equal(expected, getline(1, '$'))
+ bw!
+
+ " clean up
+ set formatprg=
+ setlocal formatprg=
+ call delete('Xsed_format.sh')
+endfunc
+
+func Test_normal07_internalfmt()
+ " basic test for internal formmatter to textwidth of 12
+ let list=range(1,11)
+ call map(list, 'v:val." "')
+ 10new
+ call setline(1, list)
+ set tw=12
+ norm! gggqG
+ call assert_equal(['1 2 3', '4 5 6', '7 8 9', '10 11 '], getline(1, '$'))
+ " clean up
+ set tw=0
+ bw!
+endfunc
+
+func Test_normal08_fold()
+ " basic tests for foldopen/folddelete
+ if !has("folding")
+ return
+ endif
+ call Setup_NewWindow()
+ 50
+ setl foldenable fdm=marker
+ " First fold
+ norm! V4jzf
+ " check that folds have been created
+ call assert_equal(['50/*{{{*/', '51', '52', '53', '54/*}}}*/'], getline(50,54))
+ " Second fold
+ 46
+ norm! V10jzf
+ " check that folds have been created
+ call assert_equal('46/*{{{*/', getline(46))
+ call assert_equal('60/*}}}*/', getline(60))
+ norm! k
+ call assert_equal('45', getline('.'))
+ norm! j
+ call assert_equal('46/*{{{*/', getline('.'))
+ norm! j
+ call assert_equal('61', getline('.'))
+ norm! k
+ " open a fold
+ norm! Vzo
+ norm! k
+ call assert_equal('45', getline('.'))
+ norm! j
+ call assert_equal('46/*{{{*/', getline('.'))
+ norm! j
+ call assert_equal('47', getline('.'))
+ norm! k
+ norm! zcVzO
+ call assert_equal('46/*{{{*/', getline('.'))
+ norm! j
+ call assert_equal('47', getline('.'))
+ norm! j
+ call assert_equal('48', getline('.'))
+ norm! j
+ call assert_equal('49', getline('.'))
+ norm! j
+ call assert_equal('50/*{{{*/', getline('.'))
+ norm! j
+ call assert_equal('51', getline('.'))
+ " delete folds
+ :46
+ " collapse fold
+ norm! V14jzC
+ " delete all folds recursively
+ norm! VzD
+ call assert_equal(['46', '47', '48', '49', '50', '51', '52', '53', '54', '55', '56', '57', '58', '59', '60'], getline(46,60))
+
+ " clean up
+ setl nofoldenable fdm=marker
+ bw!
+endfunc
+
+func Test_normal09_operatorfunc()
+ " Test operatorfunc
+ call Setup_NewWindow()
+ " Add some spaces for counting
+ 50,60s/$/ /
+ unlet! g:a
+ let g:a=0
+ nmap <buffer><silent> ,, :set opfunc=CountSpaces<CR>g@
+ vmap <buffer><silent> ,, :<C-U>call CountSpaces(visualmode(), 1)<CR>
+ 50
+ norm V2j,,
+ call assert_equal(6, g:a)
+ norm V,,
+ call assert_equal(2, g:a)
+ norm ,,l
+ call assert_equal(0, g:a)
+ 50
+ exe "norm 0\<c-v>10j2l,,"
+ call assert_equal(11, g:a)
+ 50
+ norm V10j,,
+ call assert_equal(22, g:a)
+
+ " clean up
+ unmap <buffer> ,,
+ set opfunc=
+ unlet! g:a
+ bw!
+endfunc
+
+func Test_normal09a_operatorfunc()
+ " Test operatorfunc
+ call Setup_NewWindow()
+ " Add some spaces for counting
+ 50,60s/$/ /
+ unlet! g:opt
+ set linebreak
+ nmap <buffer><silent> ,, :set opfunc=OpfuncDummy<CR>g@
+ 50
+ norm ,,j
+ exe "bd!" g:bufnr
+ call assert_true(&linebreak)
+ call assert_equal(g:opt, &linebreak)
+ set nolinebreak
+ norm ,,j
+ exe "bd!" g:bufnr
+ call assert_false(&linebreak)
+ call assert_equal(g:opt, &linebreak)
+
+ " clean up
+ unmap <buffer> ,,
+ set opfunc=
+ bw!
+ unlet! g:opt
+endfunc
+
+func Test_normal10_expand()
+ " Test for expand()
+ 10new
+ call setline(1, ['1', 'ifooar,,cbar'])
+ 2
+ norm! $
+ call assert_equal('cbar', expand('<cword>'))
+ call assert_equal('ifooar,,cbar', expand('<cWORD>'))
+
+ call setline(1, ['prx = list[idx];'])
+ 1
+ let expected = ['', 'prx', 'prx', 'prx',
+ \ 'list', 'list', 'list', 'list', 'list', 'list', 'list',
+ \ 'idx', 'idx', 'idx', 'idx',
+ \ 'list[idx]',
+ \ '];',
+ \ ]
+ for i in range(1, 16)
+ exe 'norm ' . i . '|'
+ call assert_equal(expected[i], expand('<cexpr>'), 'i == ' . i)
+ endfor
+
+ if executable('echo')
+ " Test expand(`...`) i.e. backticks command expansion.
+ " MS-Windows has a trailing space.
+ call assert_match('^abcde *$', expand('`echo abcde`'))
+ endif
+
+ " Test expand(`=...`) i.e. backticks expression expansion
+ call assert_equal('5', expand('`=2+3`'))
+
+ " clean up
+ bw!
+endfunc
+
+func Test_normal11_showcmd()
+ " test for 'showcmd'
+ 10new
+ exe "norm! ofoobar\<esc>"
+ call assert_equal(2, line('$'))
+ set showcmd
+ exe "norm! ofoobar2\<esc>"
+ call assert_equal(3, line('$'))
+ exe "norm! VAfoobar3\<esc>"
+ call assert_equal(3, line('$'))
+ exe "norm! 0d3\<del>2l"
+ call assert_equal('obar2foobar3', getline('.'))
+ bw!
+endfunc
+
+func Test_normal12_nv_error()
+ " Test for nv_error
+ 10new
+ call setline(1, range(1,5))
+ " should not do anything, just beep
+ exe "norm! <c-k>"
+ call assert_equal(map(range(1,5), 'string(v:val)'), getline(1,'$'))
+ bw!
+endfunc
+
+func Test_normal13_help()
+ " Test for F1
+ call assert_equal(1, winnr())
+ call feedkeys("\<f1>", 'txi')
+ call assert_match('help\.txt', bufname('%'))
+ call assert_equal(2, winnr('$'))
+ bw!
+endfunc
+
+func Test_normal14_page()
+ " basic test for Ctrl-F and Ctrl-B
+ call Setup_NewWindow()
+ exe "norm! \<c-f>"
+ call assert_equal('9', getline('.'))
+ exe "norm! 2\<c-f>"
+ call assert_equal('25', getline('.'))
+ exe "norm! 2\<c-b>"
+ call assert_equal('18', getline('.'))
+ 1
+ set scrolloff=5
+ exe "norm! 2\<c-f>"
+ call assert_equal('21', getline('.'))
+ exe "norm! \<c-b>"
+ call assert_equal('13', getline('.'))
+ 1
+ set scrolloff=99
+ exe "norm! \<c-f>"
+ call assert_equal('13', getline('.'))
+ set scrolloff=0
+ 100
+ exe "norm! $\<c-b>"
+ call assert_equal('92', getline('.'))
+ call assert_equal([0, 92, 1, 0, 1], getcurpos())
+ 100
+ set nostartofline
+ exe "norm! $\<c-b>"
+ call assert_equal('92', getline('.'))
+ call assert_equal([0, 92, 2, 0, 2147483647], getcurpos())
+ " cleanup
+ set startofline
+ bw!
+endfunc
+
+func Test_normal14_page_eol()
+ 10new
+ norm oxxxxxxx
+ exe "norm 2\<c-f>"
+ " check with valgrind that cursor is put back in column 1
+ exe "norm 2\<c-b>"
+ bw!
+endfunc
+
+func Test_normal15_z_scroll_vert()
+ " basic test for z commands that scroll the window
+ call Setup_NewWindow()
+ 100
+ norm! >>
+ " Test for z<cr>
+ exe "norm! z\<cr>"
+ call assert_equal(' 100', getline('.'))
+ call assert_equal(100, winsaveview()['topline'])
+ call assert_equal([0, 100, 2, 0, 9], getcurpos())
+
+ " Test for zt
+ 21
+ norm! >>0zt
+ call assert_equal(' 21', getline('.'))
+ call assert_equal(21, winsaveview()['topline'])
+ call assert_equal([0, 21, 1, 0, 8], getcurpos())
+
+ " Test for zb
+ 30
+ norm! >>$ztzb
+ call assert_equal(' 30', getline('.'))
+ call assert_equal(30, winsaveview()['topline']+winheight(0)-1)
+ call assert_equal([0, 30, 3, 0, 2147483647], getcurpos())
+
+ " Test for z-
+ 1
+ 30
+ norm! 0z-
+ call assert_equal(' 30', getline('.'))
+ call assert_equal(30, winsaveview()['topline']+winheight(0)-1)
+ call assert_equal([0, 30, 2, 0, 9], getcurpos())
+
+ " Test for z{height}<cr>
+ call assert_equal(10, winheight(0))
+ exe "norm! z12\<cr>"
+ call assert_equal(12, winheight(0))
+ exe "norm! z10\<cr>"
+ call assert_equal(10, winheight(0))
+
+ " Test for z.
+ 1
+ 21
+ norm! 0z.
+ call assert_equal(' 21', getline('.'))
+ call assert_equal(17, winsaveview()['topline'])
+ call assert_equal([0, 21, 2, 0, 9], getcurpos())
+
+ " Test for zz
+ 1
+ 21
+ norm! 0zz
+ call assert_equal(' 21', getline('.'))
+ call assert_equal(17, winsaveview()['topline'])
+ call assert_equal([0, 21, 1, 0, 8], getcurpos())
+
+ " Test for z+
+ 11
+ norm! zt
+ norm! z+
+ call assert_equal(' 21', getline('.'))
+ call assert_equal(21, winsaveview()['topline'])
+ call assert_equal([0, 21, 2, 0, 9], getcurpos())
+
+ " Test for [count]z+
+ 1
+ norm! 21z+
+ call assert_equal(' 21', getline('.'))
+ call assert_equal(21, winsaveview()['topline'])
+ call assert_equal([0, 21, 2, 0, 9], getcurpos())
+
+ " Test for z^
+ norm! 22z+0
+ norm! z^
+ call assert_equal(' 21', getline('.'))
+ call assert_equal(12, winsaveview()['topline'])
+ call assert_equal([0, 21, 2, 0, 9], getcurpos())
+
+ " Test for [count]z^
+ 1
+ norm! 30z^
+ call assert_equal(' 21', getline('.'))
+ call assert_equal(12, winsaveview()['topline'])
+ call assert_equal([0, 21, 2, 0, 9], getcurpos())
+
+ " cleanup
+ bw!
+endfunc
+
+func Test_normal16_z_scroll_hor()
+ " basic test for z commands that scroll the window
+ 10new
+ 15vsp
+ set nowrap listchars=
+ let lineA='abcdefghijklmnopqrstuvwxyz'
+ let lineB='0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+ $put =lineA
+ $put =lineB
+ 1d
+
+ " Test for zl
+ 1
+ norm! 5zl
+ call assert_equal(lineA, getline('.'))
+ call assert_equal(6, col('.'))
+ call assert_equal(5, winsaveview()['leftcol'])
+ norm! yl
+ call assert_equal('f', @0)
+
+ " Test for zh
+ norm! 2zh
+ call assert_equal(lineA, getline('.'))
+ call assert_equal(6, col('.'))
+ norm! yl
+ call assert_equal('f', @0)
+ call assert_equal(3, winsaveview()['leftcol'])
+
+ " Test for zL
+ norm! zL
+ call assert_equal(11, col('.'))
+ norm! yl
+ call assert_equal('k', @0)
+ call assert_equal(10, winsaveview()['leftcol'])
+ norm! 2zL
+ call assert_equal(25, col('.'))
+ norm! yl
+ call assert_equal('y', @0)
+ call assert_equal(24, winsaveview()['leftcol'])
+
+ " Test for zH
+ norm! 2zH
+ call assert_equal(25, col('.'))
+ call assert_equal(10, winsaveview()['leftcol'])
+ norm! yl
+ call assert_equal('y', @0)
+
+ " Test for zs
+ norm! $zs
+ call assert_equal(26, col('.'))
+ call assert_equal(25, winsaveview()['leftcol'])
+ norm! yl
+ call assert_equal('z', @0)
+
+ " Test for ze
+ norm! ze
+ call assert_equal(26, col('.'))
+ call assert_equal(11, winsaveview()['leftcol'])
+ norm! yl
+ call assert_equal('z', @0)
+
+ " cleanup
+ set wrap listchars=eol:$
+ bw!
+endfunc
+
+func Test_normal17_z_scroll_hor2()
+ " basic test for z commands that scroll the window
+ " using 'sidescrolloff' setting
+ 10new
+ 20vsp
+ set nowrap listchars= sidescrolloff=5
+ let lineA='abcdefghijklmnopqrstuvwxyz'
+ let lineB='0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+ $put =lineA
+ $put =lineB
+ 1d
+
+ " Test for zl
+ 1
+ norm! 5zl
+ call assert_equal(lineA, getline('.'))
+ call assert_equal(11, col('.'))
+ call assert_equal(5, winsaveview()['leftcol'])
+ norm! yl
+ call assert_equal('k', @0)
+
+ " Test for zh
+ norm! 2zh
+ call assert_equal(lineA, getline('.'))
+ call assert_equal(11, col('.'))
+ norm! yl
+ call assert_equal('k', @0)
+ call assert_equal(3, winsaveview()['leftcol'])
+
+ " Test for zL
+ norm! 0zL
+ call assert_equal(16, col('.'))
+ norm! yl
+ call assert_equal('p', @0)
+ call assert_equal(10, winsaveview()['leftcol'])
+ norm! 2zL
+ call assert_equal(26, col('.'))
+ norm! yl
+ call assert_equal('z', @0)
+ call assert_equal(15, winsaveview()['leftcol'])
+
+ " Test for zH
+ norm! 2zH
+ call assert_equal(15, col('.'))
+ call assert_equal(0, winsaveview()['leftcol'])
+ norm! yl
+ call assert_equal('o', @0)
+
+ " Test for zs
+ norm! $zs
+ call assert_equal(26, col('.'))
+ call assert_equal(20, winsaveview()['leftcol'])
+ norm! yl
+ call assert_equal('z', @0)
+
+ " Test for ze
+ norm! ze
+ call assert_equal(26, col('.'))
+ call assert_equal(11, winsaveview()['leftcol'])
+ norm! yl
+ call assert_equal('z', @0)
+
+ " cleanup
+ set wrap listchars=eol:$ sidescrolloff=0
+ bw!
+endfunc
+
+func Test_normal18_z_fold()
+ " basic tests for foldopen/folddelete
+ if !has("folding")
+ return
+ endif
+ call Setup_NewWindow()
+ 50
+ setl foldenable fdm=marker foldlevel=5
+
+ " Test for zF
+ " First fold
+ norm! 4zF
+ " check that folds have been created
+ call assert_equal(['50/*{{{*/', '51', '52', '53/*}}}*/'], getline(50,53))
+
+ " Test for zd
+ 51
+ norm! 2zF
+ call assert_equal(2, foldlevel('.'))
+ norm! kzd
+ call assert_equal(['50', '51/*{{{*/', '52/*}}}*/', '53'], getline(50,53))
+ norm! j
+ call assert_equal(1, foldlevel('.'))
+
+ " Test for zD
+ " also deletes partially selected folds recursively
+ 51
+ norm! zF
+ call assert_equal(2, foldlevel('.'))
+ norm! kV2jzD
+ call assert_equal(['50', '51', '52', '53'], getline(50,53))
+
+ " Test for zE
+ 85
+ norm! 4zF
+ 86
+ norm! 2zF
+ 90
+ norm! 4zF
+ call assert_equal(['85/*{{{*/', '86/*{{{*/', '87/*}}}*/', '88/*}}}*/', '89', '90/*{{{*/', '91', '92', '93/*}}}*/'], getline(85,93))
+ norm! zE
+ call assert_equal(['85', '86', '87', '88', '89', '90', '91', '92', '93'], getline(85,93))
+
+ " Test for zn
+ 50
+ set foldlevel=0
+ norm! 2zF
+ norm! zn
+ norm! k
+ call assert_equal('49', getline('.'))
+ norm! j
+ call assert_equal('50/*{{{*/', getline('.'))
+ norm! j
+ call assert_equal('51/*}}}*/', getline('.'))
+ norm! j
+ call assert_equal('52', getline('.'))
+ call assert_equal(0, &foldenable)
+
+ " Test for zN
+ 49
+ norm! zN
+ call assert_equal('49', getline('.'))
+ norm! j
+ call assert_equal('50/*{{{*/', getline('.'))
+ norm! j
+ call assert_equal('52', getline('.'))
+ call assert_equal(1, &foldenable)
+
+ " Test for zi
+ norm! zi
+ call assert_equal(0, &foldenable)
+ norm! zi
+ call assert_equal(1, &foldenable)
+ norm! zi
+ call assert_equal(0, &foldenable)
+ norm! zi
+ call assert_equal(1, &foldenable)
+
+ " Test for za
+ 50
+ norm! za
+ norm! k
+ call assert_equal('49', getline('.'))
+ norm! j
+ call assert_equal('50/*{{{*/', getline('.'))
+ norm! j
+ call assert_equal('51/*}}}*/', getline('.'))
+ norm! j
+ call assert_equal('52', getline('.'))
+ 50
+ norm! za
+ norm! k
+ call assert_equal('49', getline('.'))
+ norm! j
+ call assert_equal('50/*{{{*/', getline('.'))
+ norm! j
+ call assert_equal('52', getline('.'))
+
+ 49
+ norm! 5zF
+ norm! k
+ call assert_equal('48', getline('.'))
+ norm! j
+ call assert_equal('49/*{{{*/', getline('.'))
+ norm! j
+ call assert_equal('55', getline('.'))
+ 49
+ norm! za
+ call assert_equal('49/*{{{*/', getline('.'))
+ norm! j
+ call assert_equal('50/*{{{*/', getline('.'))
+ norm! j
+ call assert_equal('52', getline('.'))
+ set nofoldenable
+ " close fold and set foldenable
+ norm! za
+ call assert_equal(1, &foldenable)
+
+ 50
+ " have to use {count}za to open all folds and make the cursor visible
+ norm! 2za
+ norm! 2k
+ call assert_equal('48', getline('.'))
+ norm! j
+ call assert_equal('49/*{{{*/', getline('.'))
+ norm! j
+ call assert_equal('50/*{{{*/', getline('.'))
+ norm! j
+ call assert_equal('51/*}}}*/', getline('.'))
+ norm! j
+ call assert_equal('52', getline('.'))
+
+ " Test for zA
+ 49
+ set foldlevel=0
+ 50
+ norm! zA
+ norm! 2k
+ call assert_equal('48', getline('.'))
+ norm! j
+ call assert_equal('49/*{{{*/', getline('.'))
+ norm! j
+ call assert_equal('50/*{{{*/', getline('.'))
+ norm! j
+ call assert_equal('51/*}}}*/', getline('.'))
+ norm! j
+ call assert_equal('52', getline('.'))
+
+ " zA on a opened fold when foldenable is not set
+ 50
+ set nofoldenable
+ norm! zA
+ call assert_equal(1, &foldenable)
+ norm! k
+ call assert_equal('48', getline('.'))
+ norm! j
+ call assert_equal('49/*{{{*/', getline('.'))
+ norm! j
+ call assert_equal('55', getline('.'))
+
+ " Test for zc
+ norm! zE
+ 50
+ norm! 2zF
+ 49
+ norm! 5zF
+ set nofoldenable
+ 50
+ " There most likely is a bug somewhere:
+ " https://groups.google.com/d/msg/vim_dev/v2EkfJ_KQjI/u-Cvv94uCAAJ
+ " TODO: Should this only close the inner most fold or both folds?
+ norm! zc
+ call assert_equal(1, &foldenable)
+ norm! k
+ call assert_equal('48', getline('.'))
+ norm! j
+ call assert_equal('49/*{{{*/', getline('.'))
+ norm! j
+ call assert_equal('55', getline('.'))
+ set nofoldenable
+ 50
+ norm! Vjzc
+ norm! k
+ call assert_equal('48', getline('.'))
+ norm! j
+ call assert_equal('49/*{{{*/', getline('.'))
+ norm! j
+ call assert_equal('55', getline('.'))
+
+ " Test for zC
+ set nofoldenable
+ 50
+ norm! zCk
+ call assert_equal('48', getline('.'))
+ norm! j
+ call assert_equal('49/*{{{*/', getline('.'))
+ norm! j
+ call assert_equal('55', getline('.'))
+
+ " Test for zx
+ " 1) close folds at line 49-54
+ set nofoldenable
+ 48
+ norm! zx
+ call assert_equal(1, &foldenable)
+ norm! j
+ call assert_equal('49/*{{{*/', getline('.'))
+ norm! j
+ call assert_equal('55', getline('.'))
+
+ " 2) do not close fold under cursor
+ 51
+ set nofoldenable
+ norm! zx
+ call assert_equal(1, &foldenable)
+ norm! 3k
+ call assert_equal('48', getline('.'))
+ norm! j
+ call assert_equal('49/*{{{*/', getline('.'))
+ norm! j
+ call assert_equal('50/*{{{*/', getline('.'))
+ norm! j
+ call assert_equal('51/*}}}*/', getline('.'))
+ norm! j
+ call assert_equal('52', getline('.'))
+ norm! j
+ call assert_equal('53', getline('.'))
+ norm! j
+ call assert_equal('54/*}}}*/', getline('.'))
+ norm! j
+ call assert_equal('55', getline('.'))
+
+ " 3) close one level of folds
+ 48
+ set nofoldenable
+ set foldlevel=1
+ norm! zx
+ call assert_equal(1, &foldenable)
+ call assert_equal('48', getline('.'))
+ norm! j
+ call assert_equal('49/*{{{*/', getline('.'))
+ norm! j
+ call assert_equal('50/*{{{*/', getline('.'))
+ norm! j
+ call assert_equal('52', getline('.'))
+ norm! j
+ call assert_equal('53', getline('.'))
+ norm! j
+ call assert_equal('54/*}}}*/', getline('.'))
+ norm! j
+ call assert_equal('55', getline('.'))
+
+ " Test for zX
+ " Close all folds
+ set foldlevel=0 nofoldenable
+ 50
+ norm! zX
+ call assert_equal(1, &foldenable)
+ norm! k
+ call assert_equal('48', getline('.'))
+ norm! j
+ call assert_equal('49/*{{{*/', getline('.'))
+ norm! j
+ call assert_equal('55', getline('.'))
+
+ " Test for zm
+ 50
+ set nofoldenable foldlevel=2
+ norm! zm
+ call assert_equal(1, &foldenable)
+ call assert_equal(1, &foldlevel)
+ norm! zm
+ call assert_equal(0, &foldlevel)
+ norm! zm
+ call assert_equal(0, &foldlevel)
+ norm! k
+ call assert_equal('48', getline('.'))
+ norm! j
+ call assert_equal('49/*{{{*/', getline('.'))
+ norm! j
+ call assert_equal('55', getline('.'))
+
+ " Test for zM
+ 48
+ set nofoldenable foldlevel=99
+ norm! zM
+ call assert_equal(1, &foldenable)
+ call assert_equal(0, &foldlevel)
+ call assert_equal('48', getline('.'))
+ norm! j
+ call assert_equal('49/*{{{*/', getline('.'))
+ norm! j
+ call assert_equal('55', getline('.'))
+
+ " Test for zr
+ 48
+ set nofoldenable foldlevel=0
+ norm! zr
+ call assert_equal(0, &foldenable)
+ call assert_equal(1, &foldlevel)
+ set foldlevel=0 foldenable
+ norm! zr
+ call assert_equal(1, &foldenable)
+ call assert_equal(1, &foldlevel)
+ norm! zr
+ call assert_equal(2, &foldlevel)
+ call assert_equal('48', getline('.'))
+ norm! j
+ call assert_equal('49/*{{{*/', getline('.'))
+ norm! j
+ call assert_equal('50/*{{{*/', getline('.'))
+ norm! j
+ call assert_equal('51/*}}}*/', getline('.'))
+ norm! j
+ call assert_equal('52', getline('.'))
+
+ " Test for zR
+ 48
+ set nofoldenable foldlevel=0
+ norm! zR
+ call assert_equal(0, &foldenable)
+ call assert_equal(2, &foldlevel)
+ set foldenable foldlevel=0
+ norm! zR
+ call assert_equal(1, &foldenable)
+ call assert_equal(2, &foldlevel)
+ call assert_equal('48', getline('.'))
+ norm! j
+ call assert_equal('49/*{{{*/', getline('.'))
+ norm! j
+ call assert_equal('50/*{{{*/', getline('.'))
+ norm! j
+ call assert_equal('51/*}}}*/', getline('.'))
+ norm! j
+ call assert_equal('52', getline('.'))
+ call append(50, ['a /*{{{*/', 'b /*}}}*/'])
+ 48
+ call assert_equal('48', getline('.'))
+ norm! j
+ call assert_equal('49/*{{{*/', getline('.'))
+ norm! j
+ call assert_equal('50/*{{{*/', getline('.'))
+ norm! j
+ call assert_equal('a /*{{{*/', getline('.'))
+ norm! j
+ call assert_equal('51/*}}}*/', getline('.'))
+ norm! j
+ call assert_equal('52', getline('.'))
+ 48
+ norm! zR
+ call assert_equal(1, &foldenable)
+ call assert_equal(3, &foldlevel)
+ call assert_equal('48', getline('.'))
+ norm! j
+ call assert_equal('49/*{{{*/', getline('.'))
+ norm! j
+ call assert_equal('50/*{{{*/', getline('.'))
+ norm! j
+ call assert_equal('a /*{{{*/', getline('.'))
+ norm! j
+ call assert_equal('b /*}}}*/', getline('.'))
+ norm! j
+ call assert_equal('51/*}}}*/', getline('.'))
+ norm! j
+ call assert_equal('52', getline('.'))
+
+ " clean up
+ setl nofoldenable fdm=marker foldlevel=0
+ bw!
+endfunc
+
+func Test_normal19_z_spell()
+ if !has("spell") || !has('syntax')
+ return
+ endif
+ new
+ call append(0, ['1 good', '2 goood', '3 goood'])
+ set spell spellfile=./Xspellfile.add spelllang=en
+ let oldlang=v:lang
+ lang C
+
+ " Test for zg
+ 1
+ norm! ]s
+ call assert_equal('2 goood', getline('.'))
+ norm! zg
+ 1
+ let a=execute('unsilent :norm! ]s')
+ call assert_equal('1 good', getline('.'))
+ call assert_equal('search hit BOTTOM, continuing at TOP', a[1:])
+ let cnt=readfile('./Xspellfile.add')
+ call assert_equal('goood', cnt[0])
+
+ " Test for zw
+ 2
+ norm! $zw
+ 1
+ norm! ]s
+ call assert_equal('2 goood', getline('.'))
+ let cnt=readfile('./Xspellfile.add')
+ call assert_equal('#oood', cnt[0])
+ call assert_equal('goood/!', cnt[1])
+
+ " Test for zg in visual mode
+ let a=execute('unsilent :norm! V$zg')
+ call assert_equal("Word '2 goood' added to ./Xspellfile.add", a[1:])
+ 1
+ norm! ]s
+ call assert_equal('3 goood', getline('.'))
+ let cnt=readfile('./Xspellfile.add')
+ call assert_equal('2 goood', cnt[2])
+ " Remove "2 good" from spellfile
+ 2
+ let a=execute('unsilent norm! V$zw')
+ call assert_equal("Word '2 goood' added to ./Xspellfile.add", a[1:])
+ let cnt=readfile('./Xspellfile.add')
+ call assert_equal('2 goood/!', cnt[3])
+
+ " Test for zG
+ let a=execute('unsilent norm! V$zG')
+ call assert_match("Word '2 goood' added to .*", a)
+ let fname=matchstr(a, 'to\s\+\zs\f\+$')
+ let cnt=readfile(fname)
+ call assert_equal('2 goood', cnt[0])
+
+ " Test for zW
+ let a=execute('unsilent norm! V$zW')
+ call assert_match("Word '2 goood' added to .*", a)
+ let cnt=readfile(fname)
+ call assert_equal('# goood', cnt[0])
+ call assert_equal('2 goood/!', cnt[1])
+
+ " Test for zuW
+ let a=execute('unsilent norm! V$zuW')
+ call assert_match("Word '2 goood' removed from .*", a)
+ let cnt=readfile(fname)
+ call assert_equal('# goood', cnt[0])
+ call assert_equal('# goood/!', cnt[1])
+
+ " Test for zuG
+ let a=execute('unsilent norm! $zG')
+ call assert_match("Word 'goood' added to .*", a)
+ let cnt=readfile(fname)
+ call assert_equal('# goood', cnt[0])
+ call assert_equal('# goood/!', cnt[1])
+ call assert_equal('goood', cnt[2])
+ let a=execute('unsilent norm! $zuG')
+ let cnt=readfile(fname)
+ call assert_match("Word 'goood' removed from .*", a)
+ call assert_equal('# goood', cnt[0])
+ call assert_equal('# goood/!', cnt[1])
+ call assert_equal('#oood', cnt[2])
+ " word not found in wordlist
+ let a=execute('unsilent norm! V$zuG')
+ let cnt=readfile(fname)
+ call assert_match("", a)
+ call assert_equal('# goood', cnt[0])
+ call assert_equal('# goood/!', cnt[1])
+ call assert_equal('#oood', cnt[2])
+
+ " Test for zug
+ call delete('./Xspellfile.add')
+ 2
+ let a=execute('unsilent norm! $zg')
+ let cnt=readfile('./Xspellfile.add')
+ call assert_equal('goood', cnt[0])
+ let a=execute('unsilent norm! $zug')
+ call assert_match("Word 'goood' removed from \./Xspellfile.add", a)
+ let cnt=readfile('./Xspellfile.add')
+ call assert_equal('#oood', cnt[0])
+ " word not in wordlist
+ let a=execute('unsilent norm! V$zug')
+ call assert_match('', a)
+ let cnt=readfile('./Xspellfile.add')
+ call assert_equal('#oood', cnt[0])
+
+ " Test for zuw
+ call delete('./Xspellfile.add')
+ 2
+ let a=execute('unsilent norm! Vzw')
+ let cnt=readfile('./Xspellfile.add')
+ call assert_equal('2 goood/!', cnt[0])
+ let a=execute('unsilent norm! Vzuw')
+ call assert_match("Word '2 goood' removed from \./Xspellfile.add", a)
+ let cnt=readfile('./Xspellfile.add')
+ call assert_equal('# goood/!', cnt[0])
+ " word not in wordlist
+ let a=execute('unsilent norm! $zug')
+ call assert_match('', a)
+ let cnt=readfile('./Xspellfile.add')
+ call assert_equal('# goood/!', cnt[0])
+
+ " add second entry to spellfile setting
+ set spellfile=./Xspellfile.add,./Xspellfile2.add
+ call delete('./Xspellfile.add')
+ 2
+ let a=execute('unsilent norm! $2zg')
+ let cnt=readfile('./Xspellfile2.add')
+ call assert_match("Word 'goood' added to ./Xspellfile2.add", a)
+ call assert_equal('goood', cnt[0])
+
+ " Test for :spellgood!
+ let temp = execute(':spe!0/0')
+ call assert_match('Invalid region', temp)
+ let spellfile = matchstr(temp, 'Invalid region nr in \zs.*\ze line \d: 0')
+ call assert_equal(['# goood', '# goood/!', '#oood', '0/0'], readfile(spellfile))
+ call delete(spellfile)
+
+ " clean up
+ exe "lang" oldlang
+ call delete("./Xspellfile.add")
+ call delete("./Xspellfile2.add")
+ call delete("./Xspellfile.add.spl")
+ call delete("./Xspellfile2.add.spl")
+
+ " zux -> no-op
+ 2
+ norm! $zux
+ call assert_equal([], glob('Xspellfile.add',0,1))
+ call assert_equal([], glob('Xspellfile2.add',0,1))
+
+ set spellfile=
+ bw!
+endfunc
+
+func Test_normal20_exmode()
+ if !has("unix")
+ " Reading from redirected file doesn't work on MS-Windows
+ return
+ endif
+ call writefile(['1a', 'foo', 'bar', '.', 'w! Xfile2', 'q!'], 'Xscript')
+ call writefile(['1', '2'], 'Xfile')
+ call system(v:progpath .' -e -s < Xscript Xfile')
+ let a=readfile('Xfile2')
+ call assert_equal(['1', 'foo', 'bar', '2'], a)
+
+ " clean up
+ for file in ['Xfile', 'Xfile2', 'Xscript']
+ call delete(file)
+ endfor
+ bw!
+endfunc
+
+func Test_normal21_nv_hat()
+
+ " Edit a fresh file and wipe the buffer list so that there is no alternate
+ " file present. Next, check for the expected command failures.
+ edit Xfoo | %bw
+ call assert_fails(':buffer #', 'E86')
+ call assert_fails(':execute "normal! \<C-^>"', 'E23')
+
+ " Test for the expected behavior when switching between two named buffers.
+ edit Xfoo | edit Xbar
+ call feedkeys("\<C-^>", 'tx')
+ call assert_equal('Xfoo', fnamemodify(bufname('%'), ':t'))
+ call feedkeys("\<C-^>", 'tx')
+ call assert_equal('Xbar', fnamemodify(bufname('%'), ':t'))
+
+ " Test for the expected behavior when only one buffer is named.
+ enew | let l:nr = bufnr('%')
+ call feedkeys("\<C-^>", 'tx')
+ call assert_equal('Xbar', fnamemodify(bufname('%'), ':t'))
+ call feedkeys("\<C-^>", 'tx')
+ call assert_equal('', bufname('%'))
+ call assert_equal(l:nr, bufnr('%'))
+
+ " Test that no action is taken by "<C-^>" when an operator is pending.
+ edit Xfoo
+ call feedkeys("ci\<C-^>", 'tx')
+ call assert_equal('Xfoo', fnamemodify(bufname('%'), ':t'))
+
+ %bw!
+endfunc
+
+func Test_normal22_zet()
+ " Test for ZZ
+ " let shell = &shell
+ " let &shell = 'sh'
+ call writefile(['1', '2'], 'Xfile')
+ let args = ' -u NONE -N -U NONE -i NONE --noplugins -X --not-a-term'
+ call system(v:progpath . args . ' -c "%d" -c ":norm! ZZ" Xfile')
+ let a = readfile('Xfile')
+ call assert_equal([], a)
+ " Test for ZQ
+ call writefile(['1', '2'], 'Xfile')
+ call system(v:progpath . args . ' -c "%d" -c ":norm! ZQ" Xfile')
+ let a = readfile('Xfile')
+ call assert_equal(['1', '2'], a)
+
+ " clean up
+ for file in ['Xfile']
+ call delete(file)
+ endfor
+ " let &shell = shell
+endfunc
+
+func Test_normal23_K()
+ " Test for K command
+ new
+ call append(0, ['version8.txt', 'man', 'aa%bb', 'cc|dd'])
+ let k = &keywordprg
+ set keywordprg=:help
+ 1
+ norm! VK
+ call assert_equal('version8.txt', fnamemodify(bufname('%'), ':t'))
+ call assert_equal('help', &ft)
+ call assert_match('\*version8.txt\*', getline('.'))
+ helpclose
+ norm! 0K
+ call assert_equal('version8.txt', fnamemodify(bufname('%'), ':t'))
+ call assert_equal('help', &ft)
+ call assert_match('\*version8\.\d\*', getline('.'))
+ helpclose
+
+ set keywordprg=:new
+ set iskeyword+=%
+ set iskeyword+=\|
+ 2
+ norm! K
+ call assert_equal('man', fnamemodify(bufname('%'), ':t'))
+ bwipe!
+ 3
+ norm! K
+ call assert_equal('aa%bb', fnamemodify(bufname('%'), ':t'))
+ bwipe!
+ if !has('win32')
+ 4
+ norm! K
+ call assert_equal('cc|dd', fnamemodify(bufname('%'), ':t'))
+ bwipe!
+ endif
+ set iskeyword-=%
+ set iskeyword-=\|
+
+ " Only expect "man" to work on Unix
+ if !has("unix")
+ let &keywordprg = k
+ bw!
+ return
+ endif
+ set keywordprg=man\ --pager=cat
+ " Test for using man
+ 2
+ let a = execute('unsilent norm! K')
+ call assert_match("man --pager=cat 'man'", a)
+
+ " clean up
+ let &keywordprg = k
+ bw!
+endfunc
+
+func Test_normal24_rot13()
+ " Testing for g?? g?g?
+ new
+ call append(0, 'abcdefghijklmnopqrstuvwxyzäüö')
+ 1
+ norm! g??
+ call assert_equal('nopqrstuvwxyzabcdefghijklmäüö', getline('.'))
+ norm! g?g?
+ call assert_equal('abcdefghijklmnopqrstuvwxyzäüö', getline('.'))
+
+ " clean up
+ bw!
+endfunc
+
+func Test_normal25_tag()
+ " Testing for CTRL-] g CTRL-] g]
+ " CTRL-W g] CTRL-W CTRL-] CTRL-W g CTRL-]
+ h
+ " Test for CTRL-]
+ call search('\<x\>$')
+ exe "norm! \<c-]>"
+ call assert_equal("change.txt", fnamemodify(bufname('%'), ':t'))
+ norm! yiW
+ call assert_equal("*x*", @0)
+ exe ":norm \<c-o>"
+
+ " Test for g_CTRL-]
+ call search('\<v_u\>$')
+ exe "norm! g\<c-]>"
+ call assert_equal("change.txt", fnamemodify(bufname('%'), ':t'))
+ norm! yiW
+ call assert_equal("*v_u*", @0)
+ exe ":norm \<c-o>"
+
+ " Test for g]
+ call search('\<i_<Esc>$')
+ let a = execute(":norm! g]")
+ call assert_match('i_<Esc>.*insert.txt', a)
+
+ if !empty(exepath('cscope')) && has('cscope')
+ " setting cscopetag changes how g] works
+ set cst
+ exe "norm! g]"
+ call assert_equal("insert.txt", fnamemodify(bufname('%'), ':t'))
+ norm! yiW
+ call assert_equal("*i_<Esc>*", @0)
+ exe ":norm \<c-o>"
+ " Test for CTRL-W g]
+ exe "norm! \<C-W>g]"
+ call assert_equal("insert.txt", fnamemodify(bufname('%'), ':t'))
+ norm! yiW
+ call assert_equal("*i_<Esc>*", @0)
+ call assert_equal(3, winnr('$'))
+ helpclose
+ set nocst
+ endif
+
+ " Test for CTRL-W g]
+ let a = execute("norm! \<C-W>g]")
+ call assert_match('i_<Esc>.*insert.txt', a)
+
+ " Test for CTRL-W CTRL-]
+ exe "norm! \<C-W>\<C-]>"
+ call assert_equal("insert.txt", fnamemodify(bufname('%'), ':t'))
+ norm! yiW
+ call assert_equal("*i_<Esc>*", @0)
+ call assert_equal(3, winnr('$'))
+ helpclose
+
+ " Test for CTRL-W g CTRL-]
+ exe "norm! \<C-W>g\<C-]>"
+ call assert_equal("insert.txt", fnamemodify(bufname('%'), ':t'))
+ norm! yiW
+ call assert_equal("*i_<Esc>*", @0)
+ call assert_equal(3, winnr('$'))
+ helpclose
+
+ " clean up
+ helpclose
+endfunc
+
+func Test_normal26_put()
+ " Test for ]p ]P [p and [P
+ new
+ call append(0, ['while read LINE', 'do', ' ((count++))', ' if [ $? -ne 0 ]; then', " echo 'Error writing file'", ' fi', 'done'])
+ 1
+ /Error/y a
+ 2
+ norm! "a]pj"a[p
+ call assert_equal(['do', "echo 'Error writing file'", " echo 'Error writing file'", ' ((count++))'], getline(2,5))
+ 1
+ /^\s\{4}/
+ exe "norm! \"a]P3Eldt'"
+ exe "norm! j\"a[P2Eldt'"
+ call assert_equal([' if [ $? -ne 0 ]; then', " echo 'Error writing'", " echo 'Error'", " echo 'Error writing file'", ' fi'], getline(6,10))
+
+ " clean up
+ bw!
+endfunc
+
+func Test_normal27_bracket()
+ " Test for [' [` ]' ]`
+ call Setup_NewWindow()
+ 1,21s/.\+/ & b/
+ 1
+ norm! $ma
+ 5
+ norm! $mb
+ 10
+ norm! $mc
+ 15
+ norm! $md
+ 20
+ norm! $me
+
+ " Test for ['
+ 9
+ norm! 2['
+ call assert_equal(' 1 b', getline('.'))
+ call assert_equal(1, line('.'))
+ call assert_equal(3, col('.'))
+
+ " Test for ]'
+ norm! ]'
+ call assert_equal(' 5 b', getline('.'))
+ call assert_equal(5, line('.'))
+ call assert_equal(3, col('.'))
+
+ " No mark after line 21, cursor moves to first non blank on current line
+ 21
+ norm! $]'
+ call assert_equal(' 21 b', getline('.'))
+ call assert_equal(21, line('.'))
+ call assert_equal(3, col('.'))
+
+ " Test for [`
+ norm! 2[`
+ call assert_equal(' 15 b', getline('.'))
+ call assert_equal(15, line('.'))
+ call assert_equal(8, col('.'))
+
+ " Test for ]`
+ norm! ]`
+ call assert_equal(' 20 b', getline('.'))
+ call assert_equal(20, line('.'))
+ call assert_equal(8, col('.'))
+
+ " clean up
+ bw!
+endfunc
+
+func Test_normal28_parenthesis()
+ " basic testing for ( and )
+ new
+ call append(0, ['This is a test. With some sentences!', '', 'Even with a question? And one more. And no sentence here'])
+
+ $
+ norm! d(
+ call assert_equal(['This is a test. With some sentences!', '', 'Even with a question? And one more. ', ''], getline(1, '$'))
+ norm! 2d(
+ call assert_equal(['This is a test. With some sentences!', '', ' ', ''], getline(1, '$'))
+ 1
+ norm! 0d)
+ call assert_equal(['With some sentences!', '', ' ', ''], getline(1, '$'))
+
+ call append('$', ['This is a long sentence', '', 'spanning', 'over several lines. '])
+ $
+ norm! $d(
+ call assert_equal(['With some sentences!', '', ' ', '', 'This is a long sentence', ''], getline(1, '$'))
+
+ " clean up
+ bw!
+endfunc
+
+fun! Test_normal29_brace()
+ " basic test for { and } movements
+ let text= ['A paragraph begins after each empty line, and also at each of a set of',
+ \ 'paragraph macros, specified by the pairs of characters in the ''paragraphs''',
+ \ 'option. The default is "IPLPPPQPP TPHPLIPpLpItpplpipbp", which corresponds to',
+ \ 'the macros ".IP", ".LP", etc. (These are nroff macros, so the dot must be in',
+ \ 'the first column). A section boundary is also a paragraph boundary.',
+ \ 'Note that a blank line (only containing white space) is NOT a paragraph',
+ \ 'boundary.',
+ \ '',
+ \ '',
+ \ 'Also note that this does not include a ''{'' or ''}'' in the first column. When',
+ \ 'the ''{'' flag is in ''cpoptions'' then ''{'' in the first column is used as a',
+ \ 'paragraph boundary |posix|.',
+ \ '{',
+ \ 'This is no paragraph',
+ \ 'unless the ''{'' is set',
+ \ 'in ''cpoptions''',
+ \ '}',
+ \ '.IP',
+ \ 'The nroff macros IP separates a paragraph',
+ \ 'That means, it must be a ''.''',
+ \ 'followed by IP',
+ \ '.LPIt does not matter, if afterwards some',
+ \ 'more characters follow.',
+ \ '.SHAlso section boundaries from the nroff',
+ \ 'macros terminate a paragraph. That means',
+ \ 'a character like this:',
+ \ '.NH',
+ \ 'End of text here']
+ new
+ call append(0, text)
+ 1
+ norm! 0d2}
+ call assert_equal(['.IP',
+ \ 'The nroff macros IP separates a paragraph', 'That means, it must be a ''.''', 'followed by IP',
+ \ '.LPIt does not matter, if afterwards some', 'more characters follow.', '.SHAlso section boundaries from the nroff',
+ \ 'macros terminate a paragraph. That means', 'a character like this:', '.NH', 'End of text here', ''], getline(1,'$'))
+ norm! 0d}
+ call assert_equal(['.LPIt does not matter, if afterwards some', 'more characters follow.',
+ \ '.SHAlso section boundaries from the nroff', 'macros terminate a paragraph. That means',
+ \ 'a character like this:', '.NH', 'End of text here', ''], getline(1, '$'))
+ $
+ norm! d{
+ call assert_equal(['.LPIt does not matter, if afterwards some', 'more characters follow.',
+ \ '.SHAlso section boundaries from the nroff', 'macros terminate a paragraph. That means', 'a character like this:', ''], getline(1, '$'))
+ norm! d{
+ call assert_equal(['.LPIt does not matter, if afterwards some', 'more characters follow.', ''], getline(1,'$'))
+ " Test with { in cpooptions
+ %d
+ call append(0, text)
+ set cpo+={
+ 1
+ norm! 0d2}
+ call assert_equal(['{', 'This is no paragraph', 'unless the ''{'' is set', 'in ''cpoptions''', '}',
+ \ '.IP', 'The nroff macros IP separates a paragraph', 'That means, it must be a ''.''',
+ \ 'followed by IP', '.LPIt does not matter, if afterwards some', 'more characters follow.',
+ \ '.SHAlso section boundaries from the nroff', 'macros terminate a paragraph. That means',
+ \ 'a character like this:', '.NH', 'End of text here', ''], getline(1,'$'))
+ $
+ norm! d}
+ call assert_equal(['{', 'This is no paragraph', 'unless the ''{'' is set', 'in ''cpoptions''', '}',
+ \ '.IP', 'The nroff macros IP separates a paragraph', 'That means, it must be a ''.''',
+ \ 'followed by IP', '.LPIt does not matter, if afterwards some', 'more characters follow.',
+ \ '.SHAlso section boundaries from the nroff', 'macros terminate a paragraph. That means',
+ \ 'a character like this:', '.NH', 'End of text here', ''], getline(1,'$'))
+ norm! gg}
+ norm! d5}
+ call assert_equal(['{', 'This is no paragraph', 'unless the ''{'' is set', 'in ''cpoptions''', '}', ''], getline(1,'$'))
+
+ " clean up
+ set cpo-={
+ bw!
+endfunc
+
+fun! Test_normal30_changecase()
+ new
+ call append(0, 'This is a simple test: äüöß')
+ norm! 1ggVu
+ call assert_equal('this is a simple test: äüöß', getline('.'))
+ norm! VU
+ call assert_equal('THIS IS A SIMPLE TEST: ÄÜÖSS', getline('.'))
+ norm! guu
+ call assert_equal('this is a simple test: äüöss', getline('.'))
+ norm! gUgU
+ call assert_equal('THIS IS A SIMPLE TEST: ÄÜÖSS', getline('.'))
+ norm! gugu
+ call assert_equal('this is a simple test: äüöss', getline('.'))
+ norm! gUU
+ call assert_equal('THIS IS A SIMPLE TEST: ÄÜÖSS', getline('.'))
+ norm! 010~
+ call assert_equal('this is a SIMPLE TEST: ÄÜÖSS', getline('.'))
+ norm! V~
+ call assert_equal('THIS IS A simple test: äüöss', getline('.'))
+
+ " Turkish ASCII turns to multi-byte. On some systems Turkish locale
+ " is available but toupper()/tolower() don't do the right thing.
+ try
+ lang tr_TR.UTF-8
+ set casemap=
+ let iupper = toupper('i')
+ if iupper == "\u0130"
+ call setline(1, 'iI')
+ 1normal gUU
+ call assert_equal("\u0130I", getline(1))
+ call assert_equal("\u0130I", toupper("iI"))
+
+ call setline(1, 'iI')
+ 1normal guu
+ call assert_equal("i\u0131", getline(1))
+ call assert_equal("i\u0131", tolower("iI"))
+ elseif iupper == "I"
+ call setline(1, 'iI')
+ 1normal gUU
+ call assert_equal("II", getline(1))
+ call assert_equal("II", toupper("iI"))
+
+ call setline(1, 'iI')
+ 1normal guu
+ call assert_equal("ii", getline(1))
+ call assert_equal("ii", tolower("iI"))
+ else
+ call assert_true(false, "expected toupper('i') to be either 'I' or '\u0130'")
+ endif
+ set casemap&
+ call setline(1, 'iI')
+ 1normal gUU
+ call assert_equal("II", getline(1))
+ call assert_equal("II", toupper("iI"))
+
+ call setline(1, 'iI')
+ 1normal guu
+ call assert_equal("ii", getline(1))
+ call assert_equal("ii", tolower("iI"))
+
+ lang en_US.UTF-8
+ catch /E197:/
+ " can't use Turkish locale
+ throw 'Skipped: Turkish locale not available'
+ endtry
+
+ " clean up
+ bw!
+endfunc
+
+fun! Test_normal31_r_cmd()
+ " Test for r command
+ new
+ call append(0, 'This is a simple test: abcd')
+ exe "norm! 1gg$r\<cr>"
+ call assert_equal(['This is a simple test: abc', '', ''], getline(1,'$'))
+ exe "norm! 1gg2wlr\<cr>"
+ call assert_equal(['This is a', 'simple test: abc', '', ''], getline(1,'$'))
+ exe "norm! 2gg0W5r\<cr>"
+ call assert_equal(['This is a', 'simple ', ' abc', '', ''], getline('1', '$'))
+ set autoindent
+ call setline(2, ['simple test: abc', ''])
+ exe "norm! 2gg0W5r\<cr>"
+ call assert_equal(['This is a', 'simple ', 'abc', '', '', ''], getline('1', '$'))
+ exe "norm! 1ggVr\<cr>"
+ call assert_equal('^M^M^M^M^M^M^M^M^M', strtrans(getline(1)))
+ call setline(1, 'This is a')
+ exe "norm! 1gg05rf"
+ call assert_equal('fffffis a', getline(1))
+
+ " clean up
+ set noautoindent
+ bw!
+endfunc
+
+func Test_normal32_g_cmd1()
+ " Test for g*, g#
+ new
+ call append(0, ['abc.x_foo', 'x_foobar.abc'])
+ 1
+ norm! $g*
+ call assert_equal('x_foo', @/)
+ call assert_equal('x_foobar.abc', getline('.'))
+ norm! $g#
+ call assert_equal('abc', @/)
+ call assert_equal('abc.x_foo', getline('.'))
+
+ " clean up
+ bw!
+endfunc
+
+fun! Test_normal33_g_cmd2()
+ if !has("jumplist")
+ return
+ endif
+ " Tests for g cmds
+ call Setup_NewWindow()
+ " Test for g`
+ clearjumps
+ norm! ma10j
+ let a=execute(':jumps')
+ " empty jumplist
+ call assert_equal('>', a[-1:])
+ norm! g`a
+ call assert_equal('>', a[-1:])
+ call assert_equal(1, line('.'))
+ call assert_equal('1', getline('.'))
+
+ " Test for g; and g,
+ norm! g;
+ " there is only one change in the changelist
+ " currently, when we setup the window
+ call assert_equal(2, line('.'))
+ call assert_fails(':norm! g;', 'E662')
+ call assert_fails(':norm! g,', 'E663')
+ let &ul=&ul
+ call append('$', ['a', 'b', 'c', 'd'])
+ let &ul=&ul
+ call append('$', ['Z', 'Y', 'X', 'W'])
+ let a = execute(':changes')
+ call assert_match('2\s\+0\s\+2', a)
+ call assert_match('101\s\+0\s\+a', a)
+ call assert_match('105\s\+0\s\+Z', a)
+ norm! 3g;
+ call assert_equal(2, line('.'))
+ norm! 2g,
+ call assert_equal(105, line('.'))
+
+ " Test for g& - global substitute
+ %d
+ call setline(1, range(1,10))
+ call append('$', ['a', 'b', 'c', 'd'])
+ $s/\w/&&/g
+ exe "norm! /[1-8]\<cr>"
+ norm! g&
+ call assert_equal(['11', '22', '33', '44', '55', '66', '77', '88', '9', '110', 'a', 'b', 'c', 'dd'], getline(1, '$'))
+
+ " Test for gv
+ %d
+ call append('$', repeat(['abcdefgh'], 8))
+ exe "norm! 2gg02l\<c-v>2j2ly"
+ call assert_equal(['cde', 'cde', 'cde'], getreg(0, 1, 1))
+ " in visual mode, gv swaps current and last selected region
+ exe "norm! G0\<c-v>4k4lgvd"
+ call assert_equal(['', 'abfgh', 'abfgh', 'abfgh', 'abcdefgh', 'abcdefgh', 'abcdefgh', 'abcdefgh', 'abcdefgh'], getline(1,'$'))
+ exe "norm! G0\<c-v>4k4ly"
+ exe "norm! gvood"
+ call assert_equal(['', 'abfgh', 'abfgh', 'abfgh', 'fgh', 'fgh', 'fgh', 'fgh', 'fgh'], getline(1,'$'))
+
+ " Test for gk/gj
+ %d
+ 15vsp
+ set wrap listchars= sbr=
+ let lineA='abcdefghijklmnopqrstuvwxyz'
+ let lineB='0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+ $put =lineA
+ $put =lineB
+
+ norm! 3gg0dgk
+ call assert_equal(['', 'abcdefghijklmno', '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'], getline(1, '$'))
+ set nu
+ norm! 3gg0gjdgj
+ call assert_equal(['', 'abcdefghijklmno', '0123456789AMNOPQRSTUVWXYZ'], getline(1,'$'))
+
+ " Test for gJ
+ norm! 2gggJ
+ call assert_equal(['', 'abcdefghijklmno0123456789AMNOPQRSTUVWXYZ'], getline(1,'$'))
+ call assert_equal(16, col('.'))
+ " shouldn't do anything
+ norm! 10gJ
+ call assert_equal(1, col('.'))
+
+ " Test for g0 g^ gm g$
+ exe "norm! 2gg0gji "
+ call assert_equal(['', 'abcdefghijk lmno0123456789AMNOPQRSTUVWXYZ'], getline(1,'$'))
+ norm! g0yl
+ call assert_equal(12, col('.'))
+ call assert_equal(' ', getreg(0))
+ norm! g$yl
+ call assert_equal(22, col('.'))
+ call assert_equal('3', getreg(0))
+ norm! gmyl
+ call assert_equal(17, col('.'))
+ call assert_equal('n', getreg(0))
+ norm! g^yl
+ call assert_equal(15, col('.'))
+ call assert_equal('l', getreg(0))
+
+ " Test for gI
+ norm! gIfoo
+ call assert_equal(['', 'fooabcdefghijk lmno0123456789AMNOPQRSTUVWXYZ'], getline(1,'$'))
+
+ " Test for gi
+ wincmd c
+ %d
+ set tw=0
+ call setline(1, ['foobar', 'new line'])
+ norm! A next word
+ $put ='third line'
+ norm! gi another word
+ call assert_equal(['foobar next word another word', 'new line', 'third line'], getline(1,'$'))
+
+ " clean up
+ bw!
+endfunc
+
+func Test_g_ctrl_g()
+ new
+
+ let a = execute(":norm! g\<c-g>")
+ call assert_equal("\n--No lines in buffer--", a)
+
+ call setline(1, ['first line', 'second line'])
+
+ " Test g CTRL-g with dos, mac and unix file type.
+ norm! gojll
+ set ff=dos
+ let a = execute(":norm! g\<c-g>")
+ call assert_equal("\nCol 3 of 11; Line 2 of 2; Word 3 of 4; Byte 15 of 25", a)
+
+ set ff=mac
+ let a = execute(":norm! g\<c-g>")
+ call assert_equal("\nCol 3 of 11; Line 2 of 2; Word 3 of 4; Byte 14 of 23", a)
+
+ set ff=unix
+ let a = execute(":norm! g\<c-g>")
+ call assert_equal("\nCol 3 of 11; Line 2 of 2; Word 3 of 4; Byte 14 of 23", a)
+
+ " Test g CTRL-g in visual mode (v)
+ let a = execute(":norm! gojllvlg\<c-g>")
+ call assert_equal("\nSelected 1 of 2 Lines; 1 of 4 Words; 2 of 23 Bytes", a)
+
+ " Test g CTRL-g in visual mode (CTRL-V) with end col > start col
+ let a = execute(":norm! \<Esc>gojll\<C-V>kllg\<c-g>")
+ call assert_equal("\nSelected 3 Cols; 2 of 2 Lines; 2 of 4 Words; 6 of 23 Bytes", a)
+
+ " Test g_CTRL-g in visual mode (CTRL-V) with end col < start col
+ let a = execute(":norm! \<Esc>goll\<C-V>jhhg\<c-g>")
+ call assert_equal("\nSelected 3 Cols; 2 of 2 Lines; 2 of 4 Words; 6 of 23 Bytes", a)
+
+ " Test g CTRL-g in visual mode (CTRL-V) with end_vcol being MAXCOL
+ let a = execute(":norm! \<Esc>gojll\<C-V>k$g\<c-g>")
+ call assert_equal("\nSelected 2 of 2 Lines; 4 of 4 Words; 17 of 23 Bytes", a)
+
+ " There should be one byte less with noeol
+ set bin noeol
+ let a = execute(":norm! \<Esc>gog\<c-g>")
+ call assert_equal("\nCol 1 of 10; Line 1 of 2; Word 1 of 4; Char 1 of 23; Byte 1 of 22", a)
+ set bin & eol&
+
+ call setline(1, ['Français', '日本語'])
+
+ let a = execute(":norm! \<Esc>gojlg\<c-g>")
+ call assert_equal("\nCol 4-3 of 9-6; Line 2 of 2; Word 2 of 2; Char 11 of 13; Byte 16 of 20", a)
+
+ let a = execute(":norm! \<Esc>gojvlg\<c-g>")
+ call assert_equal("\nSelected 1 of 2 Lines; 1 of 2 Words; 2 of 13 Chars; 6 of 20 Bytes", a)
+
+ let a = execute(":norm! \<Esc>goll\<c-v>jlg\<c-g>")
+ call assert_equal("\nSelected 4 Cols; 2 of 2 Lines; 2 of 2 Words; 6 of 13 Chars; 11 of 20 Bytes", a)
+
+ set fenc=utf8 bomb
+ let a = execute(":norm! \<Esc>gojlg\<c-g>")
+ call assert_equal("\nCol 4-3 of 9-6; Line 2 of 2; Word 2 of 2; Char 11 of 13; Byte 16 of 20(+3 for BOM)", a)
+
+ set fenc=utf16 bomb
+ let a = execute(":norm! g\<c-g>")
+ call assert_equal("\nCol 4-3 of 9-6; Line 2 of 2; Word 2 of 2; Char 11 of 13; Byte 16 of 20(+2 for BOM)", a)
+
+ set fenc=utf32 bomb
+ let a = execute(":norm! g\<c-g>")
+ call assert_equal("\nCol 4-3 of 9-6; Line 2 of 2; Word 2 of 2; Char 11 of 13; Byte 16 of 20(+4 for BOM)", a)
+
+ set fenc& bomb&
+
+ set ff&
+ bwipe!
+endfunc
+
+fun! Test_normal34_g_cmd3()
+ " Test for g8
+ new
+ let a=execute(':norm! 1G0g8')
+ call assert_equal("\nNUL", a)
+
+ call setline(1, 'abcdefghijklmnopqrstuvwxyzäüö')
+ let a=execute(':norm! 1G$g8')
+ call assert_equal("\nc3 b6 ", a)
+
+ call setline(1, "a\u0302")
+ let a=execute(':norm! 1G0g8')
+ call assert_equal("\n61 + cc 82 ", a)
+
+ " clean up
+ bw!
+endfunc
+
+func Test_normal_8g8()
+ new
+
+ " Test 8g8 which finds invalid utf8 at or after the cursor.
+
+ " With invalid byte.
+ call setline(1, "___\xff___")
+ norm! 1G08g8g
+ call assert_equal([0, 1, 4, 0, 1], getcurpos())
+
+ " With invalid byte before the cursor.
+ call setline(1, "___\xff___")
+ norm! 1G$h8g8g
+ call assert_equal([0, 1, 6, 0, 9], getcurpos())
+
+ " With truncated sequence.
+ call setline(1, "___\xE2\x82___")
+ norm! 1G08g8g
+ call assert_equal([0, 1, 4, 0, 1], getcurpos())
+
+ " With overlong sequence.
+ call setline(1, "___\xF0\x82\x82\xAC___")
+ norm! 1G08g8g
+ call assert_equal([0, 1, 4, 0, 1], getcurpos())
+
+ " With valid utf8.
+ call setline(1, "café")
+ norm! 1G08g8
+ call assert_equal([0, 1, 1, 0, 1], getcurpos())
+
+ bw!
+endfunc
+
+fun! Test_normal35_g_cmd4()
+ " Test for g<
+ " Cannot capture its output,
+ " probably a bug, therefore, test disabled:
+ throw "Skipped: output of g< can't be tested currently"
+ echo "a\nb\nc\nd"
+ let b=execute(':norm! g<')
+ call assert_true(!empty(b), 'failed `execute(g<)`')
+endfunc
+
+fun! Test_normal36_g_cmd5()
+ new
+ call append(0, 'abcdefghijklmnopqrstuvwxyz')
+ set ff=unix
+ " Test for gp gP
+ call append(1, range(1,10))
+ 1
+ norm! 1yy
+ 3
+ norm! gp
+ call assert_equal([0, 5, 1, 0, 1], getcurpos())
+ $
+ norm! gP
+ call assert_equal([0, 14, 1, 0, 1], getcurpos())
+
+ " Test for go
+ norm! 26go
+ call assert_equal([0, 1, 26, 0, 26], getcurpos())
+ norm! 27go
+ call assert_equal([0, 1, 26, 0, 26], getcurpos())
+ norm! 28go
+ call assert_equal([0, 2, 1, 0, 1], getcurpos())
+ set ff=dos
+ norm! 29go
+ call assert_equal([0, 2, 1, 0, 1], getcurpos())
+ set ff=unix
+ norm! gg0
+ norm! 101go
+ call assert_equal([0, 13, 26, 0, 26], getcurpos())
+ norm! 103go
+ call assert_equal([0, 14, 1, 0, 1], getcurpos())
+ " count > buffer content
+ norm! 120go
+ call assert_equal([0, 14, 1, 0, 2147483647], getcurpos())
+ " clean up
+ bw!
+endfunc
+
+fun! Test_normal37_g_cmd6()
+ " basic test for gt and gT
+ tabnew 1.txt
+ tabnew 2.txt
+ tabnew 3.txt
+ norm! 1gt
+ call assert_equal(1, tabpagenr())
+ norm! 3gt
+ call assert_equal(3, tabpagenr())
+ norm! 1gT
+ " count gT goes not to the absolute tabpagenumber
+ " but, but goes to the count previous tabpagenumber
+ call assert_equal(2, tabpagenr())
+ " wrap around
+ norm! 3gT
+ call assert_equal(3, tabpagenr())
+ " gt does not wrap around
+ norm! 5gt
+ call assert_equal(3, tabpagenr())
+
+ for i in range(3)
+ tabclose
+ endfor
+ " clean up
+ call assert_fails(':tabclose', 'E784')
+endfunc
+
+fun! Test_normal38_nvhome()
+ " Test for <Home> and <C-Home> key
+ new
+ call setline(1, range(10))
+ $
+ setl et sw=2
+ norm! V10>$
+ " count is ignored
+ exe "norm! 10\<home>"
+ call assert_equal(1, col('.'))
+ exe "norm! \<home>"
+ call assert_equal([0, 10, 1, 0, 1], getcurpos())
+ exe "norm! 5\<c-home>"
+ call assert_equal([0, 5, 1, 0, 1], getcurpos())
+ exe "norm! \<c-home>"
+ call assert_equal([0, 1, 1, 0, 1], getcurpos())
+
+ " clean up
+ bw!
+endfunc
+
+fun! Test_normal39_cw()
+ " Test for cw and cW on whitespace
+ " and cpo+=w setting
+ new
+ set tw=0
+ call append(0, 'here are some words')
+ norm! 1gg0elcwZZZ
+ call assert_equal('hereZZZare some words', getline('.'))
+ norm! 1gg0elcWYYY
+ call assert_equal('hereZZZareYYYsome words', getline('.'))
+ set cpo+=w
+ call setline(1, 'here are some words')
+ norm! 1gg0elcwZZZ
+ call assert_equal('hereZZZ are some words', getline('.'))
+ norm! 1gg2elcWYYY
+ call assert_equal('hereZZZ areYYY some words', getline('.'))
+ set cpo-=w
+ norm! 2gg0cwfoo
+ call assert_equal('foo', getline('.'))
+
+ " clean up
+ bw!
+endfunc
+
+fun! Test_normal40_ctrl_bsl()
+ " Basic test for CTRL-\ commands
+ new
+ call append(0, 'here are some words')
+ exe "norm! 1gg0a\<C-\>\<C-N>"
+ call assert_equal('n', mode())
+ call assert_equal(1, col('.'))
+ call assert_equal('', visualmode())
+ exe "norm! 1gg0viw\<C-\>\<C-N>"
+ call assert_equal('n', mode())
+ call assert_equal(4, col('.'))
+ exe "norm! 1gg0a\<C-\>\<C-G>"
+ call assert_equal('n', mode())
+ call assert_equal(1, col('.'))
+ "imap <buffer> , <c-\><c-n>
+ set im
+ exe ":norm! \<c-\>\<c-n>dw"
+ set noim
+ call assert_equal('are some words', getline(1))
+ call assert_false(&insertmode)
+
+ " clean up
+ bw!
+endfunc
+
+fun! Test_normal41_insert_reg()
+ " Test for <c-r>=, <c-r><c-r>= and <c-r><c-o>=
+ " in insert mode
+ new
+ set sts=2 sw=2 ts=8 tw=0
+ call append(0, ["aaa\tbbb\tccc", '', '', ''])
+ let a=getline(1)
+ norm! 2gg0
+ exe "norm! a\<c-r>=a\<cr>"
+ norm! 3gg0
+ exe "norm! a\<c-r>\<c-r>=a\<cr>"
+ norm! 4gg0
+ exe "norm! a\<c-r>\<c-o>=a\<cr>"
+ call assert_equal(['aaa bbb ccc', 'aaa bbb ccc', 'aaa bbb ccc', 'aaa bbb ccc', ''], getline(1, '$'))
+
+ " clean up
+ set sts=0 sw=8 ts=8
+ bw!
+endfunc
+
+func Test_normal42_halfpage()
+ " basic test for Ctrl-D and Ctrl-U
+ call Setup_NewWindow()
+ call assert_equal(5, &scroll)
+ exe "norm! \<c-d>"
+ call assert_equal('6', getline('.'))
+ exe "norm! 2\<c-d>"
+ call assert_equal('8', getline('.'))
+ call assert_equal(2, &scroll)
+ set scroll=5
+ exe "norm! \<c-u>"
+ call assert_equal('3', getline('.'))
+ 1
+ set scrolloff=5
+ exe "norm! \<c-d>"
+ call assert_equal('10', getline('.'))
+ exe "norm! \<c-u>"
+ call assert_equal('5', getline('.'))
+ 1
+ set scrolloff=99
+ exe "norm! \<c-d>"
+ call assert_equal('10', getline('.'))
+ set scrolloff=0
+ 100
+ exe "norm! $\<c-u>"
+ call assert_equal('95', getline('.'))
+ call assert_equal([0, 95, 1, 0, 1], getcurpos())
+ 100
+ set nostartofline
+ exe "norm! $\<c-u>"
+ call assert_equal('95', getline('.'))
+ call assert_equal([0, 95, 2, 0, 2147483647], getcurpos())
+ " cleanup
+ set startofline
+ bw!
+endfunc
+
+fun! Test_normal43_textobject1()
+ " basic tests for text object aw
+ new
+ call append(0, ['foobar,eins,foobar', 'foo,zwei,foo '])
+ " diw
+ norm! 1gg0diw
+ call assert_equal([',eins,foobar', 'foo,zwei,foo ', ''], getline(1,'$'))
+ " daw
+ norm! 2ggEdaw
+ call assert_equal([',eins,foobar', 'foo,zwei,', ''], getline(1, '$'))
+ %d
+ call append(0, ["foo\teins\tfoobar", "foo\tzwei\tfoo "])
+ " diW
+ norm! 2ggwd2iW
+ call assert_equal(['foo eins foobar', 'foo foo ', ''], getline(1,'$'))
+ " daW
+ norm! 1ggd2aW
+ call assert_equal(['foobar', 'foo foo ', ''], getline(1,'$'))
+
+ %d
+ call append(0, ["foo\teins\tfoobar", "foo\tzwei\tfoo "])
+ " aw in visual line mode switches to characterwise mode
+ norm! 2gg$Vawd
+ call assert_equal(['foo eins foobar', 'foo zwei foo'], getline(1,'$'))
+ norm! 1gg$Viwd
+ call assert_equal(['foo eins ', 'foo zwei foo'], getline(1,'$'))
+
+ " clean up
+ bw!
+endfunc
+
+func Test_normal44_textobjects2()
+ " basic testing for is and as text objects
+ new
+ call append(0, ['This is a test. With some sentences!', '', 'Even with a question? And one more. And no sentence here'])
+ " Test for dis - does not remove trailing whitespace
+ norm! 1gg0dis
+ call assert_equal([' With some sentences!', '', 'Even with a question? And one more. And no sentence here', ''], getline(1,'$'))
+ " Test for das - removes leading whitespace
+ norm! 3ggf?ldas
+ call assert_equal([' With some sentences!', '', 'Even with a question? And no sentence here', ''], getline(1,'$'))
+ " when used in visual mode, is made characterwise
+ norm! 3gg$Visy
+ call assert_equal('v', visualmode())
+ " reset visualmode()
+ norm! 3ggVy
+ norm! 3gg$Vasy
+ call assert_equal('v', visualmode())
+ " basic testing for textobjects a< and at
+ %d
+ call setline(1, ['<div> ','<a href="foobar" class="foo">xyz</a>',' </div>', ' '])
+ " a<
+ norm! 1gg0da<
+ call assert_equal([' ', '<a href="foobar" class="foo">xyz</a>', ' </div>', ' '], getline(1,'$'))
+ norm! 1pj
+ call assert_equal([' <div>', '<a href="foobar" class="foo">xyz</a>', ' </div>', ' '], getline(1,'$'))
+ " at
+ norm! d2at
+ call assert_equal([' '], getline(1,'$'))
+ %d
+ call setline(1, ['<div> ','<a href="foobar" class="foo">xyz</a>',' </div>', ' '])
+ " i<
+ norm! 1gg0di<
+ call assert_equal(['<> ', '<a href="foobar" class="foo">xyz</a>', ' </div>', ' '], getline(1,'$'))
+ norm! 1Pj
+ call assert_equal(['<div> ', '<a href="foobar" class="foo">xyz</a>', ' </div>', ' '], getline(1,'$'))
+ norm! d2it
+ call assert_equal(['<div></div>',' '], getline(1,'$'))
+ " basic testing for a[ and i[ text object
+ %d
+ call setline(1, [' ', '[', 'one [two]', 'thre', ']'])
+ norm! 3gg0di[
+ call assert_equal([' ', '[', ']'], getline(1,'$'))
+ call setline(1, [' ', '[', 'one [two]', 'thre', ']'])
+ norm! 3gg0ftd2a[
+ call assert_equal([' '], getline(1,'$'))
+ %d
+ " Test for i" when cursor is in front of a quoted object
+ call append(0, 'foo "bar"')
+ norm! 1gg0di"
+ call assert_equal(['foo ""', ''], getline(1,'$'))
+
+ " clean up
+ bw!
+endfunc
+
+func Test_normal45_drop()
+ if !has('dnd')
+ " The ~ register does not exist
+ call assert_beeps('norm! "~')
+ return
+ endif
+
+ " basic test for drag-n-drop
+ " unfortunately, without a gui, we can't really test much here,
+ " so simply test that ~p fails (which uses the drop register)
+ new
+ call assert_fails(':norm! "~p', 'E353')
+ call assert_equal([], getreg('~', 1, 1))
+ " the ~ register is read only
+ call assert_fails(':let @~="1"', 'E354')
+ bw!
+endfunc
+
+func Test_normal46_ignore()
+ new
+ " How to test this?
+ " let's just for now test, that the buffer
+ " does not change
+ call feedkeys("\<c-s>", 't')
+ call assert_equal([''], getline(1,'$'))
+
+ " no valid commands
+ exe "norm! \<char-0x100>"
+ call assert_equal([''], getline(1,'$'))
+
+ exe "norm! ä"
+ call assert_equal([''], getline(1,'$'))
+
+ " clean up
+ bw!
+endfunc
+
+func Test_normal47_visual_buf_wipe()
+ " This was causing a crash or ml_get error.
+ enew!
+ call setline(1,'xxx')
+ normal $
+ new
+ call setline(1, range(1,2))
+ 2
+ exe "norm \<C-V>$"
+ bw!
+ norm yp
+ set nomodified
+endfunc
+
+func Test_normal47_autocmd()
+ " disabled, does not seem to be possible currently
+ throw "Skipped: not possible to test cursorhold autocmd while waiting for input in normal_cmd"
+ new
+ call append(0, repeat('-',20))
+ au CursorHold * call feedkeys('2l', '')
+ 1
+ set updatetime=20
+ " should delete 12 chars (d12l)
+ call feedkeys('d1', '!')
+ call assert_equal('--------', getline(1))
+
+ " clean up
+ au! CursorHold
+ set updatetime=4000
+ bw!
+endfunc
+
+func Test_normal48_wincmd()
+ new
+ exe "norm! \<c-w>c"
+ call assert_equal(1, winnr('$'))
+ call assert_fails(":norm! \<c-w>c", "E444")
+endfunc
+
+func Test_normal49_counts()
+ new
+ call setline(1, 'one two three four five six seven eight nine ten')
+ 1
+ norm! 3d2w
+ call assert_equal('seven eight nine ten', getline(1))
+ bw!
+endfunc
+
+func Test_normal50_commandline()
+ if !has("timers") || !has("cmdline_hist")
+ return
+ endif
+ func! DoTimerWork(id)
+ call assert_equal('[Command Line]', bufname(''))
+ " should fail, with E11, but does fail with E23?
+ "call feedkeys("\<c-^>", 'tm')
+
+ " should also fail with E11
+ call assert_fails(":wincmd p", 'E11')
+ " return from commandline window
+ call feedkeys("\<cr>")
+ endfunc
+
+ let oldlang=v:lang
+ lang C
+ set updatetime=20
+ call timer_start(100, 'DoTimerWork')
+ try
+ " throws E23, for whatever reason...
+ call feedkeys('q:', 'x!')
+ catch /E23/
+ " no-op
+ endtry
+ " clean up
+ set updatetime=4000
+ exe "lang" oldlang
+ bw!
+endfunc
+
+func Test_normal51_FileChangedRO()
+ if !has("autocmd")
+ return
+ endif
+ " Don't sleep after the warning message.
+ call test_settime(1)
+ call writefile(['foo'], 'Xreadonly.log')
+ new Xreadonly.log
+ setl ro
+ au FileChangedRO <buffer> :call feedkeys("\<c-^>", 'tix')
+ call assert_fails(":norm! Af", 'E788')
+ call assert_equal(['foo'], getline(1,'$'))
+ call assert_equal('Xreadonly.log', bufname(''))
+
+ " cleanup
+ call test_settime(0)
+ bw!
+ call delete("Xreadonly.log")
+endfunc
+
+func Test_normal52_rl()
+ if !has("rightleft")
+ return
+ endif
+ new
+ call setline(1, 'abcde fghij klmnopq')
+ norm! 1gg$
+ set rl
+ call assert_equal(19, col('.'))
+ call feedkeys('l', 'tx')
+ call assert_equal(18, col('.'))
+ call feedkeys('h', 'tx')
+ call assert_equal(19, col('.'))
+ call feedkeys("\<right>", 'tx')
+ call assert_equal(18, col('.'))
+ call feedkeys("\<s-right>", 'tx')
+ call assert_equal(13, col('.'))
+ call feedkeys("\<c-right>", 'tx')
+ call assert_equal(7, col('.'))
+ call feedkeys("\<c-left>", 'tx')
+ call assert_equal(13, col('.'))
+ call feedkeys("\<s-left>", 'tx')
+ call assert_equal(19, col('.'))
+ call feedkeys("<<", 'tx')
+ call assert_equal(' abcde fghij klmnopq',getline(1))
+ call feedkeys(">>", 'tx')
+ call assert_equal('abcde fghij klmnopq',getline(1))
+
+ " cleanup
+ set norl
+ bw!
+endfunc
+
+func Test_normal53_digraph()
+ if !has('digraphs')
+ return
+ endif
+ new
+ call setline(1, 'abcdefgh|')
+ exe "norm! 1gg0f\<c-k>!!"
+ call assert_equal(9, col('.'))
+ set cpo+=D
+ exe "norm! 1gg0f\<c-k>!!"
+ call assert_equal(1, col('.'))
+
+ set cpo-=D
+ bw!
+endfunc
+
+func Test_normal54_Ctrl_bsl()
+ new
+ call setline(1, 'abcdefghijklmn')
+ exe "norm! df\<c-\>\<c-n>"
+ call assert_equal(['abcdefghijklmn'], getline(1,'$'))
+ exe "norm! df\<c-\>\<c-g>"
+ call assert_equal(['abcdefghijklmn'], getline(1,'$'))
+ exe "norm! df\<c-\>m"
+ call assert_equal(['abcdefghijklmn'], getline(1,'$'))
+
+ call setline(2, 'abcdefghijklmnÄf')
+ norm! 2gg0
+ exe "norm! df\<Char-0x101>"
+ call assert_equal(['abcdefghijklmn', 'f'], getline(1,'$'))
+ norm! 1gg0
+ exe "norm! df\<esc>"
+ call assert_equal(['abcdefghijklmn', 'f'], getline(1,'$'))
+
+ " clean up
+ bw!
+endfunc
+
+func Test_normal_large_count()
+ " This may fail with 32bit long, how do we detect that?
+ new
+ normal o
+ normal 6666666666dL
+ bwipe!
+endfunc
+
+func Test_delete_until_paragraph()
+ new
+ normal grádv}
+ call assert_equal('á', getline(1))
+ normal grád}
+ call assert_equal('', getline(1))
+ bwipe!
+endfunc
+
+" Test for the gr (virtual replace) command
+" Test for the bug fixed by 7.4.387
+func Test_gr_command()
+ enew!
+ let save_cpo = &cpo
+ call append(0, ['First line', 'Second line', 'Third line'])
+ exe "normal i\<C-G>u"
+ call cursor(2, 1)
+ set cpo-=X
+ normal 4gro
+ call assert_equal('oooond line', getline(2))
+ undo
+ set cpo+=X
+ normal 4gro
+ call assert_equal('ooooecond line', getline(2))
+ let &cpo = save_cpo
+ enew!
+endfunc
+
+" When splitting a window the changelist position is wrong.
+" Test the changelist position after splitting a window.
+" Test for the bug fixed by 7.4.386
+func Test_changelist()
+ let save_ul = &ul
+ enew!
+ call append('$', ['1', '2'])
+ exe "normal i\<C-G>u"
+ exe "normal Gkylpa\<C-G>u"
+ set ul=100
+ exe "normal Gylpa\<C-G>u"
+ set ul=100
+ normal gg
+ vsplit
+ normal g;
+ call assert_equal([3, 2], [line('.'), col('.')])
+ normal g;
+ call assert_equal([2, 2], [line('.'), col('.')])
+ call assert_fails('normal g;', 'E662:')
+ %bwipe!
+ let &ul = save_ul
+endfunc
+
+func Test_nv_hat_count()
+ %bwipeout!
+ let l:nr = bufnr('%') + 1
+ call assert_fails(':execute "normal! ' . l:nr . '\<C-^>"', 'E92')
+
+ edit Xfoo
+ let l:foo_nr = bufnr('Xfoo')
+
+ edit Xbar
+ let l:bar_nr = bufnr('Xbar')
+
+ " Make sure we are not just using the alternate file.
+ edit Xbaz
+
+ call feedkeys(l:foo_nr . "\<C-^>", 'tx')
+ call assert_equal('Xfoo', fnamemodify(bufname('%'), ':t'))
+
+ call feedkeys(l:bar_nr . "\<C-^>", 'tx')
+ call assert_equal('Xbar', fnamemodify(bufname('%'), ':t'))
+
+ %bwipeout!
+endfunc
diff --git a/src/testdir/test_number.vim b/src/testdir/test_number.vim
new file mode 100644
index 0000000..415aefc
--- /dev/null
+++ b/src/testdir/test_number.vim
@@ -0,0 +1,254 @@
+" Test for 'number' and 'relativenumber'
+
+source view_util.vim
+
+func s:screen_lines(start, end) abort
+ return ScreenLines([a:start, a:end], 8)
+endfunc
+
+func s:compare_lines(expect, actual)
+ call assert_equal(a:expect, a:actual)
+endfunc
+
+func s:test_windows(h, w) abort
+ call NewWindow(a:h, a:w)
+endfunc
+
+func s:close_windows() abort
+ call CloseWindow()
+endfunc
+
+func s:validate_cursor() abort
+ " update skipcol.
+ " wincol():
+ " f_wincol
+ " -> validate_cursor
+ " -> curs_columns
+ call wincol()
+endfunc
+
+func Test_set_options()
+ set nu rnu
+ call assert_equal(1, &nu)
+ call assert_equal(1, &rnu)
+
+ call s:test_windows(10, 20)
+ call assert_equal(1, &nu)
+ call assert_equal(1, &rnu)
+ call s:close_windows()
+
+ set nu& rnu&
+endfunc
+
+func Test_set_global_and_local()
+ " setlocal must NOT reset the other global value
+ set nonu nornu
+ setglobal nu
+ setlocal rnu
+ call assert_equal(1, &g:nu)
+
+ set nonu nornu
+ setglobal rnu
+ setlocal nu
+ call assert_equal(1, &g:rnu)
+
+ " setglobal MUST reset the other global value
+ set nonu nornu
+ setglobal nu
+ setglobal rnu
+ call assert_equal(1, &g:nu)
+
+ set nonu nornu
+ setglobal rnu
+ setglobal nu
+ call assert_equal(1, &g:rnu)
+
+ " set MUST reset the other global value
+ set nonu nornu
+ set nu
+ set rnu
+ call assert_equal(1, &g:nu)
+
+ set nonu nornu
+ set rnu
+ set nu
+ call assert_equal(1, &g:rnu)
+
+ set nu& rnu&
+endfunc
+
+func Test_number()
+ call s:test_windows(10, 20)
+ call setline(1, ["abcdefghij", "klmnopqrst", "uvwxyzABCD", "EFGHIJKLMN", "OPQRSTUVWX", "YZ"])
+ setl number
+ let lines = s:screen_lines(1, 4)
+ let expect = [
+\ " 1 abcd",
+\ " 2 klmn",
+\ " 3 uvwx",
+\ " 4 EFGH",
+\ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows()
+endfunc
+
+func Test_relativenumber()
+ call s:test_windows(10, 20)
+ call setline(1, ["abcdefghij", "klmnopqrst", "uvwxyzABCD", "EFGHIJKLMN", "OPQRSTUVWX", "YZ"])
+ 3
+ setl relativenumber
+ let lines = s:screen_lines(1, 6)
+ let expect = [
+\ " 2 abcd",
+\ " 1 klmn",
+\ " 0 uvwx",
+\ " 1 EFGH",
+\ " 2 OPQR",
+\ " 3 YZ ",
+\ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows()
+endfunc
+
+func Test_number_with_relativenumber()
+ call s:test_windows(10, 20)
+ call setline(1, ["abcdefghij", "klmnopqrst", "uvwxyzABCD", "EFGHIJKLMN", "OPQRSTUVWX", "YZ"])
+ 4
+ setl number relativenumber
+ let lines = s:screen_lines(1, 6)
+ let expect = [
+\ " 3 abcd",
+\ " 2 klmn",
+\ " 1 uvwx",
+\ "4 EFGH",
+\ " 1 OPQR",
+\ " 2 YZ ",
+\ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows()
+endfunc
+
+func Test_number_with_linewrap1()
+ call s:test_windows(3, 20)
+ normal! 61ia
+ setl number wrap
+ call s:validate_cursor()
+ let lines = s:screen_lines(1, 3)
+ let expect = [
+\ "--1 aaaa",
+\ " aaaa",
+\ " aaaa",
+\ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows()
+endfunc
+
+" Pending: https://groups.google.com/forum/#!topic/vim_dev/tzNKP7EDWYI
+func XTest_number_with_linewrap2()
+ call s:test_windows(3, 20)
+ normal! 61ia
+ setl number wrap
+ call s:validate_cursor()
+ 0
+ call s:validate_cursor()
+ let lines = s:screen_lines(1, 3)
+ let expect = [
+\ " 1 aaaa",
+\ " aaaa",
+\ " aaaa",
+\ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows()
+endfunc
+
+" Pending: https://groups.google.com/forum/#!topic/vim_dev/tzNKP7EDWYI
+func XTest_number_with_linewrap3()
+ call s:test_windows(4, 20)
+ normal! 81ia
+ setl number wrap
+ call s:validate_cursor()
+ setl nonumber
+ call s:validate_cursor()
+ let lines = s:screen_lines(1, 4)
+ let expect = [
+\ "aaaaaaaa",
+\ "aaaaaaaa",
+\ "aaaaaaaa",
+\ "a ",
+\ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows()
+endfunc
+
+func Test_numberwidth()
+ call s:test_windows(10, 20)
+ call setline(1, repeat(['aaaa'], 10))
+ setl number numberwidth=6
+ let lines = s:screen_lines(1, 3)
+ let expect = [
+\ " 1 aa",
+\ " 2 aa",
+\ " 3 aa",
+\ ]
+ call s:compare_lines(expect, lines)
+
+ set relativenumber
+ let lines = s:screen_lines(1, 3)
+ let expect = [
+\ "1 aa",
+\ " 1 aa",
+\ " 2 aa",
+\ ]
+ call s:compare_lines(expect, lines)
+
+ set nonumber
+ let lines = s:screen_lines(1, 3)
+ let expect = [
+\ " 0 aa",
+\ " 1 aa",
+\ " 2 aa",
+\ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows()
+endfunc
+
+func Test_numberwidth_adjusted()
+ call s:test_windows(10, 20)
+ call setline(1, repeat(['aaaa'], 10000))
+ setl number numberwidth=4
+ let lines = s:screen_lines(1, 3)
+ let expect = [
+\ " 1 aa",
+\ " 2 aa",
+\ " 3 aa",
+\ ]
+ call s:compare_lines(expect, lines)
+
+ $
+ let lines = s:screen_lines(8, 10)
+ let expect = [
+\ " 9998 aa",
+\ " 9999 aa",
+\ "10000 aa",
+\ ]
+ call s:compare_lines(expect, lines)
+
+ setl relativenumber
+ let lines = s:screen_lines(8, 10)
+ let expect = [
+\ " 2 aa",
+\ " 1 aa",
+\ "10000 aa",
+\ ]
+ call s:compare_lines(expect, lines)
+
+ setl nonumber
+ let lines = s:screen_lines(8, 10)
+ let expect = [
+\ " 2 aaaa",
+\ " 1 aaaa",
+\ " 0 aaaa",
+\ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows()
+endfunc
diff --git a/src/testdir/test_options.vim b/src/testdir/test_options.vim
new file mode 100644
index 0000000..83b315d
--- /dev/null
+++ b/src/testdir/test_options.vim
@@ -0,0 +1,520 @@
+" Test for options
+
+func Test_whichwrap()
+ set whichwrap=b,s
+ call assert_equal('b,s', &whichwrap)
+
+ set whichwrap+=h,l
+ call assert_equal('b,s,h,l', &whichwrap)
+
+ set whichwrap+=h,l
+ call assert_equal('b,s,h,l', &whichwrap)
+
+ set whichwrap+=h,l
+ call assert_equal('b,s,h,l', &whichwrap)
+
+ set whichwrap=h,h
+ call assert_equal('h', &whichwrap)
+
+ set whichwrap=h,h,h
+ call assert_equal('h', &whichwrap)
+
+ set whichwrap&
+endfunc
+
+func Test_isfname()
+ " This used to cause Vim to access uninitialized memory.
+ set isfname=
+ call assert_equal("~X", expand("~X"))
+ set isfname&
+endfunc
+
+func Test_wildchar()
+ " Empty 'wildchar' used to access invalid memory.
+ call assert_fails('set wildchar=', 'E521:')
+ call assert_fails('set wildchar=abc', 'E521:')
+ set wildchar=<Esc>
+ let a=execute('set wildchar?')
+ call assert_equal("\n wildchar=<Esc>", a)
+ set wildchar=27
+ let a=execute('set wildchar?')
+ call assert_equal("\n wildchar=<Esc>", a)
+ set wildchar&
+endfunc
+
+func Test_options()
+ let caught = 'ok'
+ try
+ options
+ catch
+ let caught = v:throwpoint . "\n" . v:exception
+ endtry
+ call assert_equal('ok', caught)
+
+ " close option-window
+ close
+endfunc
+
+func Test_path_keep_commas()
+ " Test that changing 'path' keeps two commas.
+ set path=foo,,bar
+ set path-=bar
+ set path+=bar
+ call assert_equal('foo,,bar', &path)
+
+ set path&
+endfunc
+
+func Test_signcolumn()
+ if has('signs')
+ call assert_equal("auto", &signcolumn)
+ set signcolumn=yes
+ set signcolumn=no
+ call assert_fails('set signcolumn=nope')
+ endif
+endfunc
+
+func Test_filetype_valid()
+ set ft=valid_name
+ call assert_equal("valid_name", &filetype)
+ set ft=valid-name
+ call assert_equal("valid-name", &filetype)
+
+ call assert_fails(":set ft=wrong;name", "E474:")
+ call assert_fails(":set ft=wrong\\\\name", "E474:")
+ call assert_fails(":set ft=wrong\\|name", "E474:")
+ call assert_fails(":set ft=wrong/name", "E474:")
+ call assert_fails(":set ft=wrong\\\nname", "E474:")
+ call assert_equal("valid-name", &filetype)
+
+ exe "set ft=trunc\x00name"
+ call assert_equal("trunc", &filetype)
+endfunc
+
+func Test_syntax_valid()
+ if !has('syntax')
+ return
+ endif
+ set syn=valid_name
+ call assert_equal("valid_name", &syntax)
+ set syn=valid-name
+ call assert_equal("valid-name", &syntax)
+
+ call assert_fails(":set syn=wrong;name", "E474:")
+ call assert_fails(":set syn=wrong\\\\name", "E474:")
+ call assert_fails(":set syn=wrong\\|name", "E474:")
+ call assert_fails(":set syn=wrong/name", "E474:")
+ call assert_fails(":set syn=wrong\\\nname", "E474:")
+ call assert_equal("valid-name", &syntax)
+
+ exe "set syn=trunc\x00name"
+ call assert_equal("trunc", &syntax)
+endfunc
+
+func Test_keymap_valid()
+ if !has('keymap')
+ return
+ endif
+ call assert_fails(":set kmp=valid_name", "E544:")
+ call assert_fails(":set kmp=valid_name", "valid_name")
+ call assert_fails(":set kmp=valid-name", "E544:")
+ call assert_fails(":set kmp=valid-name", "valid-name")
+
+ call assert_fails(":set kmp=wrong;name", "E474:")
+ call assert_fails(":set kmp=wrong\\\\name", "E474:")
+ call assert_fails(":set kmp=wrong\\|name", "E474:")
+ call assert_fails(":set kmp=wrong/name", "E474:")
+ call assert_fails(":set kmp=wrong\\\nname", "E474:")
+
+ call assert_fails(":set kmp=trunc\x00name", "E544:")
+ call assert_fails(":set kmp=trunc\x00name", "trunc")
+endfunc
+
+func Check_dir_option(name)
+ " Check that it's possible to set the option.
+ exe 'set ' . a:name . '=/usr/share/dict/words'
+ call assert_equal('/usr/share/dict/words', eval('&' . a:name))
+ exe 'set ' . a:name . '=/usr/share/dict/words,/and/there'
+ call assert_equal('/usr/share/dict/words,/and/there', eval('&' . a:name))
+ exe 'set ' . a:name . '=/usr/share/dict\ words'
+ call assert_equal('/usr/share/dict words', eval('&' . a:name))
+
+ " Check rejecting weird characters.
+ call assert_fails("set " . a:name . "=/not&there", "E474:")
+ call assert_fails("set " . a:name . "=/not>there", "E474:")
+ call assert_fails("set " . a:name . "=/not.*there", "E474:")
+endfunc
+
+func Test_cinkeys()
+ " This used to cause invalid memory access
+ set cindent cinkeys=0
+ norm a
+ set cindent& cinkeys&
+endfunc
+
+func Test_dictionary()
+ call Check_dir_option('dictionary')
+endfunc
+
+func Test_thesaurus()
+ call Check_dir_option('thesaurus')
+endfun
+
+func Test_complete()
+ " Trailing single backslash used to cause invalid memory access.
+ set complete=s\
+ new
+ call feedkeys("i\<C-N>\<Esc>", 'xt')
+ bwipe!
+ set complete&
+endfun
+
+func Test_set_completion()
+ call feedkeys(":set di\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"set dictionary diff diffexpr diffopt digraph directory display', @:)
+
+ " Expand boolan options. When doing :set no<Tab>
+ " vim displays the options names without "no" but completion uses "no...".
+ call feedkeys(":set nodi\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"set nodiff digraph', @:)
+
+ call feedkeys(":set invdi\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"set invdiff digraph', @:)
+
+ " Expand abbreviation of options.
+ call feedkeys(":set ts\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"set tabstop thesaurus ttyscroll', @:)
+
+ " Expand current value
+ call feedkeys(":set fileencodings=\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"set fileencodings=ucs-bom,utf-8,default,latin1', @:)
+
+ call feedkeys(":set fileencodings:\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"set fileencodings:ucs-bom,utf-8,default,latin1', @:)
+
+ " Expand key codes.
+ call feedkeys(":set <H\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"set <Help> <Home>', @:)
+
+ " Expand terminal options.
+ call feedkeys(":set t_A\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"set t_AB t_AF t_AL', @:)
+
+ " Expand directories.
+ call feedkeys(":set cdpath=./\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_match(' ./samples/ ', @:)
+ call assert_notmatch(' ./small.vim ', @:)
+
+ " Expand files and directories.
+ call feedkeys(":set tags=./\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_match(' ./samples/.* ./small.vim', @:)
+
+ call feedkeys(":set tags=./\\\\ dif\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"set tags=./\\ diff diffexpr diffopt', @:)
+endfunc
+
+func Test_set_errors()
+ call assert_fails('set scroll=-1', 'E49:')
+ call assert_fails('set backupcopy=', 'E474:')
+ call assert_fails('set regexpengine=3', 'E474:')
+ call assert_fails('set history=10001', 'E474:')
+ call assert_fails('set numberwidth=11', 'E474:')
+ call assert_fails('set colorcolumn=-a')
+ call assert_fails('set colorcolumn=a')
+ call assert_fails('set colorcolumn=1,')
+ call assert_fails('set cmdheight=-1', 'E487:')
+ call assert_fails('set cmdwinheight=-1', 'E487:')
+ if has('conceal')
+ call assert_fails('set conceallevel=-1', 'E487:')
+ call assert_fails('set conceallevel=4', 'E474:')
+ endif
+ call assert_fails('set helpheight=-1', 'E487:')
+ call assert_fails('set history=-1', 'E487:')
+ call assert_fails('set report=-1', 'E487:')
+ call assert_fails('set shiftwidth=-1', 'E487:')
+ call assert_fails('set sidescroll=-1', 'E487:')
+ call assert_fails('set tabstop=-1', 'E487:')
+ call assert_fails('set textwidth=-1', 'E487:')
+ call assert_fails('set timeoutlen=-1', 'E487:')
+ call assert_fails('set updatecount=-1', 'E487:')
+ call assert_fails('set updatetime=-1', 'E487:')
+ call assert_fails('set winheight=-1', 'E487:')
+ call assert_fails('set tabstop!', 'E488:')
+ call assert_fails('set xxx', 'E518:')
+ call assert_fails('set beautify?', 'E519:')
+ call assert_fails('set undolevels=x', 'E521:')
+ call assert_fails('set tabstop=', 'E521:')
+ call assert_fails('set comments=-', 'E524:')
+ call assert_fails('set comments=a', 'E525:')
+ call assert_fails('set foldmarker=x', 'E536:')
+ call assert_fails('set commentstring=x', 'E537:')
+ call assert_fails('set complete=x', 'E539:')
+ call assert_fails('set statusline=%{', 'E540:')
+ call assert_fails('set statusline=' . repeat("%p", 81), 'E541:')
+ call assert_fails('set statusline=%(', 'E542:')
+ if has('cursorshape')
+ " This invalid value for 'guicursor' used to cause Vim to crash.
+ call assert_fails('set guicursor=i-ci,r-cr:h', 'E545:')
+ call assert_fails('set guicursor=i-ci', 'E545:')
+ call assert_fails('set guicursor=x', 'E545:')
+ call assert_fails('set guicursor=r-cr:horx', 'E548:')
+ call assert_fails('set guicursor=r-cr:hor0', 'E549:')
+ endif
+ call assert_fails('set backupext=~ patchmode=~', 'E589:')
+ call assert_fails('set winminheight=10 winheight=9', 'E591:')
+ call assert_fails('set winminwidth=10 winwidth=9', 'E592:')
+ call assert_fails("set showbreak=\x01", 'E595:')
+ call assert_fails('set t_foo=', 'E846:')
+endfunc
+
+" Must be executed before other tests that set 'term'.
+func Test_000_term_option_verbose()
+ if has('gui_running')
+ return
+ endif
+ let verb_cm = execute('verbose set t_cm')
+ call assert_notmatch('Last set from', verb_cm)
+
+ let term_save = &term
+ set term=ansi
+ let verb_cm = execute('verbose set t_cm')
+ call assert_match('Last set from.*test_options.vim', verb_cm)
+ let &term = term_save
+endfunc
+
+func Test_set_ttytype()
+ if !has('gui_running') && has('unix')
+ " Setting 'ttytype' used to cause a double-free when exiting vim and
+ " when vim is compiled with -DEXITFREE.
+ set ttytype=ansi
+ call assert_equal('ansi', &ttytype)
+ call assert_equal(&ttytype, &term)
+ set ttytype=xterm
+ call assert_equal('xterm', &ttytype)
+ call assert_equal(&ttytype, &term)
+ " "set ttytype=" gives E522 instead of E529
+ " in travis on some builds. Why? Catch both for now
+ try
+ set ttytype=
+ call assert_report('set ttytype= did not fail')
+ catch /E529\|E522/
+ endtry
+
+ " Some systems accept any terminal name and return dumb settings,
+ " check for failure of finding the entry and for missing 'cm' entry.
+ try
+ set ttytype=xxx
+ call assert_report('set ttytype=xxx did not fail')
+ catch /E522\|E437/
+ endtry
+
+ set ttytype&
+ call assert_equal(&ttytype, &term)
+ endif
+endfunc
+
+func Test_set_all()
+ set tw=75
+ set iskeyword=a-z,A-Z
+ set nosplitbelow
+ let out = execute('set all')
+ call assert_match('textwidth=75', out)
+ call assert_match('iskeyword=a-z,A-Z', out)
+ call assert_match('nosplitbelow', out)
+ set tw& iskeyword& splitbelow&
+endfunc
+
+func Test_set_values()
+ if filereadable('opt_test.vim')
+ source opt_test.vim
+ else
+ throw 'Skipped: opt_test.vim does not exist'
+ endif
+endfunc
+
+func ResetIndentexpr()
+ set indentexpr=
+endfunc
+
+func Test_set_indentexpr()
+ " this was causing usage of freed memory
+ set indentexpr=ResetIndentexpr()
+ new
+ call feedkeys("i\<c-f>", 'x')
+ call assert_equal('', &indentexpr)
+ bwipe!
+endfunc
+
+func Test_backupskip()
+ " Option 'backupskip' may contain several comma-separated path
+ " specifications if one or more of the environment variables TMPDIR, TMP,
+ " or TEMP is defined. To simplify testing, convert the string value into a
+ " list.
+ let bsklist = split(&bsk, ',')
+
+ if has("mac")
+ let found = (index(bsklist, '/private/tmp/*') >= 0)
+ call assert_true(found, '/private/tmp not in option bsk: ' . &bsk)
+ elseif has("unix")
+ let found = (index(bsklist, '/tmp/*') >= 0)
+ call assert_true(found, '/tmp not in option bsk: ' . &bsk)
+ endif
+
+ " If our test platform is Windows, the path(s) in option bsk will use
+ " backslash for the path separator and the components could be in short
+ " (8.3) format. As such, we need to replace the backslashes with forward
+ " slashes and convert the path components to long format. The expand()
+ " function will do this but it cannot handle comma-separated paths. This is
+ " why bsk was converted from a string into a list of strings above.
+ "
+ " One final complication is that the wildcard "/*" is at the end of each
+ " path and so expand() might return a list of matching files. To prevent
+ " this, we need to remove the wildcard before calling expand() and then
+ " append it afterwards.
+ if has('win32')
+ let item_nbr = 0
+ while item_nbr < len(bsklist)
+ let path_spec = bsklist[item_nbr]
+ let path_spec = strcharpart(path_spec, 0, strlen(path_spec)-2)
+ let path_spec = substitute(expand(path_spec), '\\', '/', 'g')
+ let bsklist[item_nbr] = path_spec . '/*'
+ let item_nbr += 1
+ endwhile
+ endif
+
+ " Option bsk will also include these environment variables if defined.
+ " If they're defined, verify they appear in the option value.
+ for var in ['$TMPDIR', '$TMP', '$TEMP']
+ if exists(var)
+ let varvalue = substitute(expand(var), '\\', '/', 'g')
+ let varvalue = substitute(varvalue, '/$', '', '')
+ let varvalue .= '/*'
+ let found = (index(bsklist, varvalue) >= 0)
+ call assert_true(found, var . ' (' . varvalue . ') not in option bsk: ' . &bsk)
+ endif
+ endfor
+endfunc
+
+func Test_copy_winopt()
+ set hidden
+
+ " Test copy option from current buffer in window
+ split
+ enew
+ setlocal numberwidth=5
+ wincmd w
+ call assert_equal(4,&numberwidth)
+ bnext
+ call assert_equal(5,&numberwidth)
+ bw!
+ call assert_equal(4,&numberwidth)
+
+ " Test copy value from window that used to be display the buffer
+ split
+ enew
+ setlocal numberwidth=6
+ bnext
+ wincmd w
+ call assert_equal(4,&numberwidth)
+ bnext
+ call assert_equal(6,&numberwidth)
+ bw!
+
+ " Test that if buffer is current, don't use the stale cached value
+ " from the last time the buffer was displayed.
+ split
+ enew
+ setlocal numberwidth=7
+ bnext
+ bnext
+ setlocal numberwidth=8
+ wincmd w
+ call assert_equal(4,&numberwidth)
+ bnext
+ call assert_equal(8,&numberwidth)
+ bw!
+
+ " Test value is not copied if window already has seen the buffer
+ enew
+ split
+ setlocal numberwidth=9
+ bnext
+ setlocal numberwidth=10
+ wincmd w
+ call assert_equal(4,&numberwidth)
+ bnext
+ call assert_equal(4,&numberwidth)
+ bw!
+
+ set hidden&
+endfunc
+
+func Test_shortmess_F()
+ new
+ call assert_match('\[No Name\]', execute('file'))
+ set shortmess+=F
+ call assert_match('\[No Name\]', execute('file'))
+ call assert_match('^\s*$', execute('file foo'))
+ call assert_match('foo', execute('file'))
+ set shortmess-=F
+ call assert_match('bar', execute('file bar'))
+ call assert_match('bar', execute('file'))
+ set shortmess&
+ bwipe
+endfunc
+
+func Test_shortmess_F2()
+ e file1
+ e file2
+ call assert_match('file1', execute('bn', ''))
+ call assert_match('file2', execute('bn', ''))
+ set shortmess+=F
+ call assert_true(empty(execute('bn', '')))
+ call assert_true(empty(execute('bn', '')))
+ set hidden
+ call assert_true(empty(execute('bn', '')))
+ call assert_true(empty(execute('bn', '')))
+ set nohidden
+ call assert_true(empty(execute('bn', '')))
+ call assert_true(empty(execute('bn', '')))
+ set shortmess&
+ call assert_match('file1', execute('bn', ''))
+ call assert_match('file2', execute('bn', ''))
+ bwipe
+ bwipe
+endfunc
+
+func Test_local_scrolloff()
+ set so=5
+ set siso=7
+ split
+ call assert_equal(5, &so)
+ setlocal so=3
+ call assert_equal(3, &so)
+ wincmd w
+ call assert_equal(5, &so)
+ wincmd w
+ setlocal so<
+ call assert_equal(5, &so)
+ setlocal so=0
+ call assert_equal(0, &so)
+ setlocal so=-1
+ call assert_equal(5, &so)
+
+ call assert_equal(7, &siso)
+ setlocal siso=3
+ call assert_equal(3, &siso)
+ wincmd w
+ call assert_equal(7, &siso)
+ wincmd w
+ setlocal siso<
+ call assert_equal(7, &siso)
+ setlocal siso=0
+ call assert_equal(0, &siso)
+ setlocal siso=-1
+ call assert_equal(7, &siso)
+
+ close
+ set so&
+ set siso&
+endfunc
diff --git a/src/testdir/test_packadd.vim b/src/testdir/test_packadd.vim
new file mode 100644
index 0000000..6d0565b
--- /dev/null
+++ b/src/testdir/test_packadd.vim
@@ -0,0 +1,357 @@
+" Tests for 'packpath' and :packadd
+
+
+func SetUp()
+ let s:topdir = getcwd() . '/Xdir'
+ exe 'set packpath=' . s:topdir
+ let s:plugdir = s:topdir . '/pack/mine/opt/mytest'
+endfunc
+
+func TearDown()
+ call delete(s:topdir, 'rf')
+endfunc
+
+func Test_packadd()
+ if !exists('s:plugdir')
+ echomsg 'when running this test manually, call SetUp() first'
+ return
+ endif
+
+ call mkdir(s:plugdir . '/plugin/also', 'p')
+ call mkdir(s:plugdir . '/ftdetect', 'p')
+ call mkdir(s:plugdir . '/after', 'p')
+ set rtp&
+ let rtp = &rtp
+ filetype on
+
+ let rtp_entries = split(rtp, ',')
+ for entry in rtp_entries
+ if entry =~? '\<after\>'
+ let first_after_entry = entry
+ break
+ endif
+ endfor
+
+ exe 'split ' . s:plugdir . '/plugin/test.vim'
+ call setline(1, 'let g:plugin_works = 42')
+ wq
+
+ exe 'split ' . s:plugdir . '/plugin/also/loaded.vim'
+ call setline(1, 'let g:plugin_also_works = 77')
+ wq
+
+ exe 'split ' . s:plugdir . '/ftdetect/test.vim'
+ call setline(1, 'let g:ftdetect_works = 17')
+ wq
+
+ packadd mytest
+
+ call assert_equal(42, g:plugin_works)
+ call assert_equal(77, g:plugin_also_works)
+ call assert_equal(17, g:ftdetect_works)
+ call assert_true(len(&rtp) > len(rtp))
+ call assert_match('/testdir/Xdir/pack/mine/opt/mytest\($\|,\)', &rtp)
+
+ let new_after = match(&rtp, '/testdir/Xdir/pack/mine/opt/mytest/after,')
+ let forwarded = substitute(first_after_entry, '\\', '[/\\\\]', 'g')
+ let old_after = match(&rtp, ',' . forwarded . '\>')
+ call assert_true(new_after > 0, 'rtp is ' . &rtp)
+ call assert_true(old_after > 0, 'match ' . forwarded . ' in ' . &rtp)
+ call assert_true(new_after < old_after, 'rtp is ' . &rtp)
+
+ " NOTE: '/.../opt/myte' forwardly matches with '/.../opt/mytest'
+ call mkdir(fnamemodify(s:plugdir, ':h') . '/myte', 'p')
+ let rtp = &rtp
+ packadd myte
+
+ " Check the path of 'myte' is added
+ call assert_true(len(&rtp) > len(rtp))
+ call assert_match('/testdir/Xdir/pack/mine/opt/myte\($\|,\)', &rtp)
+
+ " Check exception
+ call assert_fails("packadd directorynotfound", 'E919:')
+ call assert_fails("packadd", 'E471:')
+endfunc
+
+func Test_packadd_start()
+ let plugdir = s:topdir . '/pack/mine/start/other'
+ call mkdir(plugdir . '/plugin', 'p')
+ set rtp&
+ let rtp = &rtp
+ filetype on
+
+ exe 'split ' . plugdir . '/plugin/test.vim'
+ call setline(1, 'let g:plugin_works = 24')
+ wq
+
+ packadd other
+
+ call assert_equal(24, g:plugin_works)
+ call assert_true(len(&rtp) > len(rtp))
+ call assert_match('/testdir/Xdir/pack/mine/start/other\($\|,\)', &rtp)
+endfunc
+
+func Test_packadd_noload()
+ call mkdir(s:plugdir . '/plugin', 'p')
+ call mkdir(s:plugdir . '/syntax', 'p')
+ set rtp&
+ let rtp = &rtp
+
+ exe 'split ' . s:plugdir . '/plugin/test.vim'
+ call setline(1, 'let g:plugin_works = 42')
+ wq
+ let g:plugin_works = 0
+
+ packadd! mytest
+
+ call assert_true(len(&rtp) > len(rtp))
+ call assert_match('testdir/Xdir/pack/mine/opt/mytest\($\|,\)', &rtp)
+ call assert_equal(0, g:plugin_works)
+
+ " check the path is not added twice
+ let new_rtp = &rtp
+ packadd! mytest
+ call assert_equal(new_rtp, &rtp)
+endfunc
+
+func Test_packadd_symlink_dir()
+ if !has('unix')
+ return
+ endif
+ let top2_dir = s:topdir . '/Xdir2'
+ let real_dir = s:topdir . '/Xsym'
+ call mkdir(real_dir, 'p')
+ exec "silent !ln -s Xsym" top2_dir
+ let &rtp = top2_dir . ',' . top2_dir . '/after'
+ let &packpath = &rtp
+
+ let s:plugdir = top2_dir . '/pack/mine/opt/mytest'
+ call mkdir(s:plugdir . '/plugin', 'p')
+
+ exe 'split ' . s:plugdir . '/plugin/test.vim'
+ call setline(1, 'let g:plugin_works = 44')
+ wq
+ let g:plugin_works = 0
+
+ packadd mytest
+
+ " Must have been inserted in the middle, not at the end
+ call assert_match('/pack/mine/opt/mytest,', &rtp)
+ call assert_equal(44, g:plugin_works)
+
+ " No change when doing it again.
+ let rtp_before = &rtp
+ packadd mytest
+ call assert_equal(rtp_before, &rtp)
+
+ set rtp&
+ let rtp = &rtp
+ exec "silent !rm" top2_dir
+endfunc
+
+func Test_packadd_symlink_dir2()
+ if !has('unix')
+ return
+ endif
+ let top2_dir = s:topdir . '/Xdir2'
+ let real_dir = s:topdir . '/Xsym/pack'
+ call mkdir(top2_dir, 'p')
+ call mkdir(real_dir, 'p')
+ let &rtp = top2_dir . ',' . top2_dir . '/after'
+ let &packpath = &rtp
+
+ exec "silent !ln -s ../Xsym/pack" top2_dir . '/pack'
+ let s:plugdir = top2_dir . '/pack/mine/opt/mytest'
+ call mkdir(s:plugdir . '/plugin', 'p')
+
+ exe 'split ' . s:plugdir . '/plugin/test.vim'
+ call setline(1, 'let g:plugin_works = 48')
+ wq
+ let g:plugin_works = 0
+
+ packadd mytest
+
+ " Must have been inserted in the middle, not at the end
+ call assert_match('/Xdir2/pack/mine/opt/mytest,', &rtp)
+ call assert_equal(48, g:plugin_works)
+
+ " No change when doing it again.
+ let rtp_before = &rtp
+ packadd mytest
+ call assert_equal(rtp_before, &rtp)
+
+ set rtp&
+ let rtp = &rtp
+ exec "silent !rm" top2_dir . '/pack'
+ exec "silent !rmdir" top2_dir
+endfunc
+
+" Check command-line completion for 'packadd'
+func Test_packadd_completion()
+ let optdir1 = &packpath . '/pack/mine/opt'
+ let optdir2 = &packpath . '/pack/candidate/opt'
+
+ call mkdir(optdir1 . '/pluginA', 'p')
+ call mkdir(optdir1 . '/pluginC', 'p')
+ call mkdir(optdir2 . '/pluginB', 'p')
+ call mkdir(optdir2 . '/pluginC', 'p')
+
+ let li = []
+ call feedkeys(":packadd \<Tab>')\<C-B>call add(li, '\<CR>", 't')
+ call feedkeys(":packadd " . repeat("\<Tab>", 2) . "')\<C-B>call add(li, '\<CR>", 't')
+ call feedkeys(":packadd " . repeat("\<Tab>", 3) . "')\<C-B>call add(li, '\<CR>", 't')
+ call feedkeys(":packadd " . repeat("\<Tab>", 4) . "')\<C-B>call add(li, '\<CR>", 'tx')
+ call assert_equal("packadd pluginA", li[0])
+ call assert_equal("packadd pluginB", li[1])
+ call assert_equal("packadd pluginC", li[2])
+ call assert_equal("packadd ", li[3])
+endfunc
+
+func Test_packloadall()
+ " plugin foo with an autoload directory
+ let fooplugindir = &packpath . '/pack/mine/start/foo/plugin'
+ call mkdir(fooplugindir, 'p')
+ call writefile(['let g:plugin_foo_number = 1234',
+ \ 'let g:plugin_foo_auto = bbb#value',
+ \ 'let g:plugin_extra_auto = extra#value'], fooplugindir . '/bar.vim')
+ let fooautodir = &packpath . '/pack/mine/start/foo/autoload'
+ call mkdir(fooautodir, 'p')
+ call writefile(['let bar#value = 77'], fooautodir . '/bar.vim')
+
+ " plugin aaa with an autoload directory
+ let aaaplugindir = &packpath . '/pack/mine/start/aaa/plugin'
+ call mkdir(aaaplugindir, 'p')
+ call writefile(['let g:plugin_aaa_number = 333',
+ \ 'let g:plugin_aaa_auto = bar#value'], aaaplugindir . '/bbb.vim')
+ let aaaautodir = &packpath . '/pack/mine/start/aaa/autoload'
+ call mkdir(aaaautodir, 'p')
+ call writefile(['let bbb#value = 55'], aaaautodir . '/bbb.vim')
+
+ " plugin extra with only an autoload directory
+ let extraautodir = &packpath . '/pack/mine/start/extra/autoload'
+ call mkdir(extraautodir, 'p')
+ call writefile(['let extra#value = 99'], extraautodir . '/extra.vim')
+
+ packloadall
+ call assert_equal(1234, g:plugin_foo_number)
+ call assert_equal(55, g:plugin_foo_auto)
+ call assert_equal(99, g:plugin_extra_auto)
+ call assert_equal(333, g:plugin_aaa_number)
+ call assert_equal(77, g:plugin_aaa_auto)
+
+ " only works once
+ call writefile(['let g:plugin_bar_number = 4321'], fooplugindir . '/bar2.vim')
+ packloadall
+ call assert_false(exists('g:plugin_bar_number'))
+
+ " works when ! used
+ packloadall!
+ call assert_equal(4321, g:plugin_bar_number)
+endfunc
+
+func Test_helptags()
+ let docdir1 = &packpath . '/pack/mine/start/foo/doc'
+ let docdir2 = &packpath . '/pack/mine/start/bar/doc'
+ call mkdir(docdir1, 'p')
+ call mkdir(docdir2, 'p')
+ call writefile(['look here: *look-here*'], docdir1 . '/bar.txt')
+ call writefile(['look away: *look-away*'], docdir2 . '/foo.txt')
+ exe 'set rtp=' . &packpath . '/pack/mine/start/foo,' . &packpath . '/pack/mine/start/bar'
+
+ helptags ALL
+
+ let tags1 = readfile(docdir1 . '/tags')
+ call assert_match('look-here', tags1[0])
+ let tags2 = readfile(docdir2 . '/tags')
+ call assert_match('look-away', tags2[0])
+endfunc
+
+func Test_colorscheme()
+ let colordirrun = &packpath . '/runtime/colors'
+ let colordirstart = &packpath . '/pack/mine/start/foo/colors'
+ let colordiropt = &packpath . '/pack/mine/opt/bar/colors'
+ call mkdir(colordirrun, 'p')
+ call mkdir(colordirstart, 'p')
+ call mkdir(colordiropt, 'p')
+ call writefile(['let g:found_one = 1'], colordirrun . '/one.vim')
+ call writefile(['let g:found_two = 1'], colordirstart . '/two.vim')
+ call writefile(['let g:found_three = 1'], colordiropt . '/three.vim')
+ exe 'set rtp=' . &packpath . '/runtime'
+
+ colorscheme one
+ call assert_equal(1, g:found_one)
+ colorscheme two
+ call assert_equal(1, g:found_two)
+ colorscheme three
+ call assert_equal(1, g:found_three)
+endfunc
+
+func Test_colorscheme_completion()
+ let colordirrun = &packpath . '/runtime/colors'
+ let colordirstart = &packpath . '/pack/mine/start/foo/colors'
+ let colordiropt = &packpath . '/pack/mine/opt/bar/colors'
+ call mkdir(colordirrun, 'p')
+ call mkdir(colordirstart, 'p')
+ call mkdir(colordiropt, 'p')
+ call writefile(['let g:found_one = 1'], colordirrun . '/one.vim')
+ call writefile(['let g:found_two = 1'], colordirstart . '/two.vim')
+ call writefile(['let g:found_three = 1'], colordiropt . '/three.vim')
+ exe 'set rtp=' . &packpath . '/runtime'
+
+ let li=[]
+ call feedkeys(":colorscheme " . repeat("\<Tab>", 1) . "')\<C-B>call add(li, '\<CR>", 't')
+ call feedkeys(":colorscheme " . repeat("\<Tab>", 2) . "')\<C-B>call add(li, '\<CR>", 't')
+ call feedkeys(":colorscheme " . repeat("\<Tab>", 3) . "')\<C-B>call add(li, '\<CR>", 't')
+ call feedkeys(":colorscheme " . repeat("\<Tab>", 4) . "')\<C-B>call add(li, '\<CR>", 'tx')
+ call assert_equal("colorscheme one", li[0])
+ call assert_equal("colorscheme three", li[1])
+ call assert_equal("colorscheme two", li[2])
+ call assert_equal("colorscheme ", li[3])
+endfunc
+
+func Test_runtime()
+ let rundir = &packpath . '/runtime/extra'
+ let startdir = &packpath . '/pack/mine/start/foo/extra'
+ let optdir = &packpath . '/pack/mine/opt/bar/extra'
+ call mkdir(rundir, 'p')
+ call mkdir(startdir, 'p')
+ call mkdir(optdir, 'p')
+ call writefile(['let g:sequence .= "run"'], rundir . '/bar.vim')
+ call writefile(['let g:sequence .= "start"'], startdir . '/bar.vim')
+ call writefile(['let g:sequence .= "foostart"'], startdir . '/foo.vim')
+ call writefile(['let g:sequence .= "opt"'], optdir . '/bar.vim')
+ call writefile(['let g:sequence .= "xxxopt"'], optdir . '/xxx.vim')
+ exe 'set rtp=' . &packpath . '/runtime'
+
+ let g:sequence = ''
+ runtime extra/bar.vim
+ call assert_equal('run', g:sequence)
+ let g:sequence = ''
+ runtime START extra/bar.vim
+ call assert_equal('start', g:sequence)
+ let g:sequence = ''
+ runtime OPT extra/bar.vim
+ call assert_equal('opt', g:sequence)
+ let g:sequence = ''
+ runtime PACK extra/bar.vim
+ call assert_equal('start', g:sequence)
+ let g:sequence = ''
+ runtime! PACK extra/bar.vim
+ call assert_equal('startopt', g:sequence)
+ let g:sequence = ''
+ runtime PACK extra/xxx.vim
+ call assert_equal('xxxopt', g:sequence)
+
+ let g:sequence = ''
+ runtime ALL extra/bar.vim
+ call assert_equal('run', g:sequence)
+ let g:sequence = ''
+ runtime ALL extra/foo.vim
+ call assert_equal('foostart', g:sequence)
+ let g:sequence = ''
+ runtime! ALL extra/xxx.vim
+ call assert_equal('xxxopt', g:sequence)
+ let g:sequence = ''
+ runtime! ALL extra/bar.vim
+ call assert_equal('runstartopt', g:sequence)
+endfunc
diff --git a/src/testdir/test_partial.vim b/src/testdir/test_partial.vim
new file mode 100644
index 0000000..b180510
--- /dev/null
+++ b/src/testdir/test_partial.vim
@@ -0,0 +1,386 @@
+" Test binding arguments to a Funcref.
+
+func MyFunc(arg1, arg2, arg3)
+ return a:arg1 . '/' . a:arg2 . '/' . a:arg3
+endfunc
+
+func MySort(up, one, two)
+ if a:one == a:two
+ return 0
+ endif
+ if a:up
+ return a:one > a:two ? 1 : -1
+ endif
+ return a:one < a:two ? 1 : -1
+endfunc
+
+func MyMap(sub, index, val)
+ return a:val - a:sub
+endfunc
+
+func MyFilter(threshold, index, val)
+ return a:val > a:threshold
+endfunc
+
+func Test_partial_args()
+ let Cb = function('MyFunc', ["foo", "bar"])
+
+ call Cb("zzz")
+ call assert_equal("foo/bar/xxx", Cb("xxx"))
+ call assert_equal("foo/bar/yyy", call(Cb, ["yyy"]))
+ let Cb2 = function(Cb)
+ call assert_equal("foo/bar/zzz", Cb2("zzz"))
+ let Cb3 = function(Cb, ["www"])
+ call assert_equal("foo/bar/www", Cb3())
+
+ let Cb = function('MyFunc', [])
+ call assert_equal("a/b/c", Cb("a", "b", "c"))
+ let Cb2 = function(Cb, [])
+ call assert_equal("a/b/d", Cb2("a", "b", "d"))
+ let Cb3 = function(Cb, ["a", "b"])
+ call assert_equal("a/b/e", Cb3("e"))
+
+ let Sort = function('MySort', [1])
+ call assert_equal([1, 2, 3], sort([3, 1, 2], Sort))
+ let Sort = function('MySort', [0])
+ call assert_equal([3, 2, 1], sort([3, 1, 2], Sort))
+
+ let Map = function('MyMap', [2])
+ call assert_equal([-1, 0, 1], map([1, 2, 3], Map))
+ let Map = function('MyMap', [3])
+ call assert_equal([-2, -1, 0], map([1, 2, 3], Map))
+
+ let Filter = function('MyFilter', [1])
+ call assert_equal([2, 3], filter([1, 2, 3], Filter))
+ let Filter = function('MyFilter', [2])
+ call assert_equal([3], filter([1, 2, 3], Filter))
+endfunc
+
+func MyDictFunc(arg1, arg2) dict
+ return self.name . '/' . a:arg1 . '/' . a:arg2
+endfunc
+
+func Test_partial_dict()
+ let dict = {'name': 'hello'}
+ let Cb = function('MyDictFunc', ["foo", "bar"], dict)
+ call assert_equal("hello/foo/bar", Cb())
+ call assert_fails('Cb("xxx")', 'E492:')
+
+ let Cb = function('MyDictFunc', ["foo"], dict)
+ call assert_equal("hello/foo/xxx", Cb("xxx"))
+ call assert_fails('Cb()', 'E492:')
+
+ let Cb = function('MyDictFunc', [], dict)
+ call assert_equal("hello/ttt/xxx", Cb("ttt", "xxx"))
+ call assert_fails('Cb("yyy")', 'E492:')
+
+ let Cb = function('MyDictFunc', dict)
+ call assert_equal("hello/xxx/yyy", Cb("xxx", "yyy"))
+ call assert_fails('Cb("fff")', 'E492:')
+
+ let Cb = function('MyDictFunc', dict)
+ call assert_equal({"foo": "hello/foo/1", "bar": "hello/bar/2"}, map({"foo": 1, "bar": 2}, Cb))
+
+ let dict = {"tr": function('tr', ['hello', 'h', 'H'])}
+ call assert_equal("Hello", dict.tr())
+endfunc
+
+func Test_partial_implicit()
+ let dict = {'name': 'foo'}
+ func dict.MyFunc(arg) dict
+ return self.name . '/' . a:arg
+ endfunc
+
+ call assert_equal('foo/bar', dict.MyFunc('bar'))
+
+ call assert_fails('let func = dict.MyFunc', 'E704:')
+ let Func = dict.MyFunc
+ call assert_equal('foo/aaa', Func('aaa'))
+
+ let Func = function(dict.MyFunc, ['bbb'])
+ call assert_equal('foo/bbb', Func())
+endfunc
+
+fun InnerCall(funcref)
+ return a:funcref
+endfu
+
+fun OuterCall()
+ let opt = { 'func' : function('sin') }
+ call InnerCall(opt.func)
+endfu
+
+func Test_function_in_dict()
+ call OuterCall()
+endfunc
+
+func s:cache_clear() dict
+ return self.name
+endfunc
+
+func Test_script_function_in_dict()
+ let s:obj = {'name': 'foo'}
+ let s:obj2 = {'name': 'bar'}
+
+ let s:obj['clear'] = function('s:cache_clear')
+
+ call assert_equal('foo', s:obj.clear())
+ let F = s:obj.clear
+ call assert_equal('foo', F())
+ call assert_equal('foo', call(s:obj.clear, [], s:obj))
+ call assert_equal('bar', call(s:obj.clear, [], s:obj2))
+
+ let s:obj2['clear'] = function('s:cache_clear')
+ call assert_equal('bar', s:obj2.clear())
+ let B = s:obj2.clear
+ call assert_equal('bar', B())
+endfunc
+
+func s:cache_arg(arg) dict
+ let s:result = self.name . '/' . a:arg
+ return s:result
+endfunc
+
+func Test_script_function_in_dict_arg()
+ let s:obj = {'name': 'foo'}
+ let s:obj['clear'] = function('s:cache_arg')
+
+ call assert_equal('foo/bar', s:obj.clear('bar'))
+ let F = s:obj.clear
+ let s:result = ''
+ call assert_equal('foo/bar', F('bar'))
+ call assert_equal('foo/bar', s:result)
+
+ let s:obj['clear'] = function('s:cache_arg', ['bar'])
+ call assert_equal('foo/bar', s:obj.clear())
+ let s:result = ''
+ call s:obj.clear()
+ call assert_equal('foo/bar', s:result)
+
+ let F = s:obj.clear
+ call assert_equal('foo/bar', F())
+ let s:result = ''
+ call F()
+ call assert_equal('foo/bar', s:result)
+
+ call assert_equal('foo/bar', call(s:obj.clear, [], s:obj))
+endfunc
+
+func Test_partial_exists()
+ let F = function('MyFunc')
+ call assert_true(exists('*F'))
+ let lF = [F]
+ call assert_true(exists('*lF[0]'))
+
+ let F = function('MyFunc', ['arg'])
+ call assert_true(exists('*F'))
+ let lF = [F]
+ call assert_true(exists('*lF[0]'))
+endfunc
+
+func Test_partial_string()
+ let F = function('MyFunc')
+ call assert_equal("function('MyFunc')", string(F))
+ let F = function('MyFunc', ['foo'])
+ call assert_equal("function('MyFunc', ['foo'])", string(F))
+ let F = function('MyFunc', ['foo', 'bar'])
+ call assert_equal("function('MyFunc', ['foo', 'bar'])", string(F))
+ let d = {'one': 1}
+ let F = function('MyFunc', d)
+ call assert_equal("function('MyFunc', {'one': 1})", string(F))
+ let F = function('MyFunc', ['foo'], d)
+ call assert_equal("function('MyFunc', ['foo'], {'one': 1})", string(F))
+endfunc
+
+func Test_func_unref()
+ let obj = {}
+ function! obj.func() abort
+ endfunction
+ let funcnumber = matchstr(string(obj.func), '^function(''\zs.\{-}\ze''')
+ call assert_true(exists('*{' . funcnumber . '}'))
+ unlet obj
+ call assert_false(exists('*{' . funcnumber . '}'))
+endfunc
+
+func Test_tostring()
+ let d = {}
+ let d.d = d
+ function d.test3()
+ echo 42
+ endfunction
+ try
+ call string(d.test3)
+ catch
+ call assert_true(v:false, v:exception)
+ endtry
+endfunc
+
+func Test_redefine_dict_func()
+ let d = {}
+ function d.test4()
+ endfunction
+ let d.test4 = d.test4
+ try
+ function! d.test4(name)
+ endfunction
+ catch
+ call assert_true(v:errmsg, v:exception)
+ endtry
+endfunc
+
+func Test_bind_in_python()
+ if has('python')
+ let g:d = {}
+ function g:d.test2()
+ endfunction
+ python import vim
+ try
+ call assert_equal(pyeval('vim.bindeval("g:d.test2")'), g:d.test2)
+ catch
+ call assert_true(v:false, v:exception)
+ endtry
+ endif
+endfunc
+
+" This caused double free on exit if EXITFREE is defined.
+func Test_cyclic_list_arg()
+ let l = []
+ let Pt = function('string', [l])
+ call add(l, Pt)
+ unlet l
+ unlet Pt
+endfunc
+
+" This caused double free on exit if EXITFREE is defined.
+func Test_cyclic_dict_arg()
+ let d = {}
+ let Pt = function('string', [d])
+ let d.Pt = Pt
+ unlet d
+ unlet Pt
+endfunc
+
+func Ignored3(job1, job2, status)
+endfunc
+
+func Test_cycle_partial_job()
+ if has('job')
+ let job = job_start('echo')
+ call job_setoptions(job, {'exit_cb': function('Ignored3', [job])})
+ unlet job
+ endif
+endfunc
+
+func Ignored2(job, status)
+endfunc
+
+func Test_ref_job_partial_dict()
+ if has('job')
+ let g:ref_job = job_start('echo')
+ let d = {'a': 'b'}
+ call job_setoptions(g:ref_job, {'exit_cb': function('Ignored2', [], d)})
+ endif
+endfunc
+
+func Test_auto_partial_rebind()
+ let dict1 = {'name': 'dict1'}
+ func! dict1.f1()
+ return self.name
+ endfunc
+ let dict1.f2 = function(dict1.f1, dict1)
+
+ call assert_equal('dict1', dict1.f1())
+ call assert_equal('dict1', dict1['f1']())
+ call assert_equal('dict1', dict1.f2())
+ call assert_equal('dict1', dict1['f2']())
+
+ let dict2 = {'name': 'dict2'}
+ let dict2.f1 = dict1.f1
+ let dict2.f2 = dict1.f2
+
+ call assert_equal('dict2', dict2.f1())
+ call assert_equal('dict2', dict2['f1']())
+ call assert_equal('dict1', dict2.f2())
+ call assert_equal('dict1', dict2['f2']())
+endfunc
+
+func Test_get_partial_items()
+ let dict = {'name': 'hello'}
+ let args = ["foo", "bar"]
+ let Func = function('MyDictFunc')
+ let Cb = function('MyDictFunc', args, dict)
+
+ call assert_equal(Func, get(Cb, 'func'))
+ call assert_equal('MyDictFunc', get(Cb, 'name'))
+ call assert_equal(args, get(Cb, 'args'))
+ call assert_equal(dict, get(Cb, 'dict'))
+ call assert_fails('call get(Cb, "xxx")', 'E475:')
+
+ call assert_equal(Func, get(Func, 'func'))
+ call assert_equal('MyDictFunc', get(Func, 'name'))
+ call assert_equal([], get(Func, 'args'))
+ call assert_true(empty( get(Func, 'dict')))
+endfunc
+
+func Test_compare_partials()
+ let d1 = {}
+ let d2 = {}
+
+ function d1.f1() dict
+ endfunction
+
+ function d1.f2() dict
+ endfunction
+
+ let F1 = get(d1, 'f1')
+ let F2 = get(d1, 'f2')
+
+ let F1d1 = function(F1, d1)
+ let F2d1 = function(F2, d2)
+ let F1d1a1 = function(F1d1, [1])
+ let F1d1a12 = function(F1d1, [1, 2])
+ let F1a1 = function(F1, [1])
+ let F1a2 = function(F1, [2])
+ let F1d2 = function(F1, d2)
+ let d3 = {'f1': F1, 'f2': F2}
+ let F1d3 = function(F1, d3)
+ let F1ad1 = function(F1, [d1])
+ let F1ad3 = function(F1, [d3])
+
+ call assert_match('^function(''\d\+'')$', string(F1)) " Not a partial
+ call assert_match('^function(''\d\+'')$', string(F2)) " Not a partial
+ call assert_match('^function(''\d\+'', {.*})$', string(F1d1)) " A partial
+ call assert_match('^function(''\d\+'', {.*})$', string(F2d1)) " A partial
+ call assert_match('^function(''\d\+'', \[.*\])$', string(F1a1)) " No dict
+
+ " !=
+ let X = F1
+ call assert_false(F1 != X) " same function
+ let X = F1d1
+ call assert_false(F1d1 != X) " same partial
+ let X = F1d1a1
+ call assert_false(F1d1a1 != X) " same partial
+ let X = F1a1
+ call assert_false(F1a1 != X) " same partial
+
+ call assert_true(F1 != F2) " Different functions
+ call assert_true(F1 != F1d1) " Partial /= non-partial
+ call assert_true(F1d1a1 != F1d1a12) " Different number of arguments
+ call assert_true(F1a1 != F1d1a12) " One has no dict
+ call assert_true(F1a1 != F1a2) " Different arguments
+ call assert_true(F1d2 != F1d1) " Different dictionaries
+ call assert_false(F1d1 != F1d3) " Equal dictionaries, even though d1 isnot d3
+
+ " isnot, option 1
+ call assert_true(F1 isnot# F2) " Different functions
+ call assert_true(F1 isnot# F1d1) " Partial /= non-partial
+ call assert_true(F1d1 isnot# F1d3) " d1 isnot d3, even though d1 == d3
+ call assert_true(F1a1 isnot# F1d1a12) " One has no dict
+ call assert_true(F1a1 isnot# F1a2) " Different number of arguments
+ call assert_true(F1ad1 isnot# F1ad3) " In arguments d1 isnot d3
+
+ " isnot, option 2
+ call assert_true(F1 isnot# F2) " Different functions
+ call assert_true(F1 isnot# F1d1) " Partial /= non-partial
+ call assert_true(d1.f1 isnot# d1.f1) " handle_subscript creates new partial each time
+endfunc
diff --git a/src/testdir/test_paste.vim b/src/testdir/test_paste.vim
new file mode 100644
index 0000000..65f300c
--- /dev/null
+++ b/src/testdir/test_paste.vim
@@ -0,0 +1,112 @@
+" Tests for bracketed paste and other forms of pasting.
+
+" Bracketed paste only works with "xterm". Not in GUI.
+if has('gui_running')
+ finish
+endif
+set term=xterm
+
+source shared.vim
+
+func Test_paste_normal_mode()
+ new
+ " In first column text is inserted
+ call setline(1, ['a', 'b', 'c'])
+ call cursor(2, 1)
+ call feedkeys("\<Esc>[200~foo\<CR>bar\<Esc>[201~", 'xt')
+ call assert_equal('foo', getline(2))
+ call assert_equal('barb', getline(3))
+ call assert_equal('c', getline(4))
+
+ " When repeating text is appended
+ normal .
+ call assert_equal('barfoo', getline(3))
+ call assert_equal('barb', getline(4))
+ call assert_equal('c', getline(5))
+ bwipe!
+
+ " In second column text is appended
+ call setline(1, ['a', 'bbb', 'c'])
+ call cursor(2, 2)
+ call feedkeys("\<Esc>[200~foo\<CR>bar\<Esc>[201~", 'xt')
+ call assert_equal('bbfoo', getline(2))
+ call assert_equal('barb', getline(3))
+ call assert_equal('c', getline(4))
+
+ " In last column text is appended
+ call setline(1, ['a', 'bbb', 'c'])
+ call cursor(2, 3)
+ call feedkeys("\<Esc>[200~foo\<CR>bar\<Esc>[201~", 'xt')
+ call assert_equal('bbbfoo', getline(2))
+ call assert_equal('bar', getline(3))
+ call assert_equal('c', getline(4))
+endfunc
+
+func Test_paste_insert_mode()
+ new
+ call setline(1, ['a', 'b', 'c'])
+ 2
+ call feedkeys("i\<Esc>[200~foo\<CR>bar\<Esc>[201~ done\<Esc>", 'xt')
+ call assert_equal('foo', getline(2))
+ call assert_equal('bar doneb', getline(3))
+ call assert_equal('c', getline(4))
+
+ normal .
+ call assert_equal('bar donfoo', getline(3))
+ call assert_equal('bar doneeb', getline(4))
+ call assert_equal('c', getline(5))
+
+ set ai et tw=10
+ call setline(1, ['a', ' b', 'c'])
+ 2
+ call feedkeys("A\<Esc>[200~foo\<CR> bar bar bar\<Esc>[201~\<Esc>", 'xt')
+ call assert_equal(' bfoo', getline(2))
+ call assert_equal(' bar bar bar', getline(3))
+ call assert_equal('c', getline(4))
+
+ set ai& et& tw=0
+ bwipe!
+endfunc
+
+func Test_paste_clipboard()
+ if !WorkingClipboard()
+ return
+ endif
+ let @+ = "nasty\<Esc>:!ls\<CR>command"
+ new
+ exe "normal i\<C-R>+\<Esc>"
+ call assert_equal("nasty\<Esc>:!ls\<CR>command", getline(1))
+ bwipe!
+endfunc
+
+func Test_paste_cmdline()
+ call feedkeys(":a\<Esc>[200~foo\<CR>bar\<Esc>[201~b\<Home>\"\<CR>", 'xt')
+ call assert_equal("\"afoo\<CR>barb", getreg(':'))
+endfunc
+
+func Test_paste_visual_mode()
+ new
+ call setline(1, 'here are some words')
+ call feedkeys("0fsve\<Esc>[200~more\<Esc>[201~", 'xt')
+ call assert_equal('here are more words', getline(1))
+ call assert_equal('some', getreg('-'))
+
+ " include last char in the line
+ call feedkeys("0fwve\<Esc>[200~noises\<Esc>[201~", 'xt')
+ call assert_equal('here are more noises', getline(1))
+ call assert_equal('words', getreg('-'))
+
+ " exclude last char in the line
+ call setline(1, 'some words!')
+ call feedkeys("0fwve\<Esc>[200~noises\<Esc>[201~", 'xt')
+ call assert_equal('some noises!', getline(1))
+ call assert_equal('words', getreg('-'))
+
+ " multi-line selection
+ call setline(1, ['some words', 'and more'])
+ call feedkeys("0fwvj0fd\<Esc>[200~letters\<Esc>[201~", 'xt')
+ call assert_equal('some letters more', getline(1))
+ call assert_equal("words\nand", getreg('1'))
+
+ bwipe!
+endfunc
diff --git a/src/testdir/test_perl.vim b/src/testdir/test_perl.vim
new file mode 100644
index 0000000..03c5fa0
--- /dev/null
+++ b/src/testdir/test_perl.vim
@@ -0,0 +1,286 @@
+" Tests for Perl interface
+
+if !has('perl')
+ finish
+end
+
+" FIXME: RunTest don't see any error when Perl abort...
+perl $SIG{__WARN__} = sub { die "Unexpected warnings from perl: @_" };
+
+func Test_change_buffer()
+ call setline(line('$'), ['1 line 1'])
+ perl VIM::DoCommand("normal /^1\n")
+ perl $curline = VIM::Eval("line('.')")
+ perl $curbuf->Set($curline, "1 changed line 1")
+ call assert_equal('1 changed line 1', getline('$'))
+endfunc
+
+func Test_evaluate_list()
+ call setline(line('$'), ['2 line 2'])
+ perl VIM::DoCommand("normal /^2\n")
+ perl $curline = VIM::Eval("line('.')")
+ let l = ["abc", "def"]
+ perl << EOF
+ $l = VIM::Eval("l");
+ $curbuf->Append($curline, $l);
+EOF
+ normal j
+ .perldo s|\n|/|g
+ call assert_equal('abc/def/', getline('$'))
+endfunc
+
+func Test_buffer_Delete()
+ new
+ call setline(1, ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'])
+ perl $curbuf->Delete(7)
+ perl $curbuf->Delete(2, 5)
+ perl $curbuf->Delete(10)
+ call assert_equal(['a', 'f', 'h'], getline(1, '$'))
+ bwipe!
+endfunc
+
+func Test_buffer_Append()
+ new
+ perl $curbuf->Append(1, '1')
+ perl $curbuf->Append(2, '2', '3', '4')
+ perl @l = ('5' ..'7')
+ perl $curbuf->Append(0, @l)
+ call assert_equal(['5', '6', '7', '', '1', '2', '3', '4'], getline(1, '$'))
+ bwipe!
+endfunc
+
+func Test_buffer_Set()
+ new
+ call setline(1, ['1', '2', '3', '4', '5'])
+ perl $curbuf->Set(2, 'a', 'b', 'c')
+ perl $curbuf->Set(4, 'A', 'B', 'C')
+ call assert_equal(['1', 'a', 'b', 'A', 'B'], getline(1, '$'))
+ bwipe!
+endfunc
+
+func Test_buffer_Get()
+ new
+ call setline(1, ['1', '2', '3', '4'])
+ call assert_equal('2:3', perleval('join(":", $curbuf->Get(2, 3))'))
+ bwipe!
+endfunc
+
+func Test_buffer_Count()
+ new
+ call setline(1, ['a', 'b', 'c'])
+ call assert_equal(3, perleval('$curbuf->Count()'))
+ bwipe!
+endfunc
+
+func Test_buffer_Name()
+ new
+ call assert_equal('', perleval('$curbuf->Name()'))
+ bwipe!
+ new Xfoo
+ call assert_equal('Xfoo', perleval('$curbuf->Name()'))
+ bwipe!
+endfunc
+
+func Test_buffer_Number()
+ call assert_equal(bufnr('%'), perleval('$curbuf->Number()'))
+endfunc
+
+func Test_window_Cursor()
+ new
+ call setline(1, ['line1', 'line2'])
+ perl $curwin->Cursor(2, 3)
+ call assert_equal('2:3', perleval('join(":", $curwin->Cursor())'))
+ " Col is numbered from 0 in Perl, and from 1 in Vim script.
+ call assert_equal([0, 2, 4, 0], getpos('.'))
+ bwipe!
+endfunc
+
+func Test_window_SetHeight()
+ new
+ perl $curwin->SetHeight(2)
+ call assert_equal(2, winheight(0))
+ bwipe!
+endfunc
+
+func Test_VIM_Windows()
+ new
+ " VIM::Windows() without argument in scalar and list context.
+ perl $winnr = VIM::Windows()
+ perl @winlist = VIM::Windows()
+ perl $curbuf->Append(0, $winnr, scalar(@winlist))
+ call assert_equal(['2', '2', ''], getline(1, '$'))
+
+ " VIM::Windows() with window number argument.
+ perl VIM::Windows(VIM::Eval('winnr()'))->Buffer()->Set(1, 'bar')
+ call assert_equal('bar', getline(1))
+ bwipe!
+endfunc
+
+func Test_VIM_Buffers()
+ new Xbar
+ " VIM::Buffers() without argument in scalar and list context.
+ perl $nbuf = VIM::Buffers()
+ perl @buflist = VIM::Buffers()
+
+ " VIM::Buffers() with argument.
+ perl $mybuf = (VIM::Buffers('Xbar'))[0]
+ perl $mybuf->Append(0, $nbuf, scalar(@buflist))
+ call assert_equal(['2', '2', ''], getline(1, '$'))
+ bwipe!
+endfunc
+
+func <SID>catch_peval(expr)
+ try
+ call perleval(a:expr)
+ catch
+ return v:exception
+ endtry
+ call assert_report('no exception for `perleval("'.a:expr.'")`')
+ return ''
+endfunc
+
+func Test_perleval()
+ call assert_false(perleval('undef'))
+
+ " scalar
+ call assert_equal(0, perleval('0'))
+ call assert_equal(2, perleval('2'))
+ call assert_equal(-2, perleval('-2'))
+ if has('float')
+ call assert_equal(2.5, perleval('2.5'))
+ else
+ call assert_equal(2, perleval('2.5'))
+ end
+
+ sandbox call assert_equal(2, perleval('2'))
+
+ call assert_equal('abc', perleval('"abc"'))
+ call assert_equal("abc\ndef", perleval('"abc\0def"'))
+
+ " ref
+ call assert_equal([], perleval('[]'))
+ call assert_equal(['word', 42, [42],{}], perleval('["word", 42, [42], {}]'))
+
+ call assert_equal({}, perleval('{}'))
+ call assert_equal({'foo': 'bar'}, perleval('{foo => "bar"}'))
+
+ perl our %h; our @a;
+ let a = perleval('[\(%h, %h, @a, @a)]')
+ call assert_true((a[0] is a[1]))
+ call assert_true((a[2] is a[3]))
+ perl undef %h; undef @a;
+
+ call assert_true(<SID>catch_peval('{"" , 0}') =~ 'Malformed key Dictionary')
+ call assert_true(<SID>catch_peval('{"\0" , 0}') =~ 'Malformed key Dictionary')
+ call assert_true(<SID>catch_peval('{"foo\0bar" , 0}') =~ 'Malformed key Dictionary')
+
+ call assert_equal('*VIM', perleval('"*VIM"'))
+ call assert_true(perleval('\\0') =~ 'SCALAR(0x\x\+)')
+endfunc
+
+func Test_perldo()
+ sp __TEST__
+ exe 'read ' g:testname
+ perldo s/perl/vieux_chameau/g
+ 1
+ call assert_false(search('\Cperl'))
+ bw!
+
+ " Check deleting lines does not trigger ml_get error.
+ new
+ call setline(1, ['one', 'two', 'three'])
+ perldo VIM::DoCommand("%d_")
+ bwipe!
+
+ " Check switching to another buffer does not trigger ml_get error.
+ new
+ let wincount = winnr('$')
+ call setline(1, ['one', 'two', 'three'])
+ perldo VIM::DoCommand("new")
+ call assert_equal(wincount + 1, winnr('$'))
+ bwipe!
+ bwipe!
+endfunc
+
+func Test_VIM_package()
+ perl VIM::DoCommand('let l:var = "foo"')
+ call assert_equal(l:var, 'foo')
+
+ set noet
+ perl VIM::SetOption('et')
+ call assert_true(&et)
+endfunc
+
+func Test_stdio()
+ redir =>l:out
+ perl <<EOF
+ VIM::Msg("&VIM::Msg");
+ print "STDOUT";
+ print STDERR "STDERR";
+EOF
+ redir END
+ call assert_equal(['&VIM::Msg', 'STDOUT', 'STDERR'], split(l:out, "\n"))
+endfunc
+
+" Run first to get a clean namespace
+func Test_000_SvREFCNT()
+ for i in range(8)
+ exec 'new X'.i
+ endfor
+ new t
+ perl <<--perl
+#line 5 "Test_000_SvREFCNT()"
+ my ($b, $w);
+
+ my $num = 0;
+ for ( 0 .. 100 ) {
+ if ( ++$num >= 8 ) { $num = 0 }
+ VIM::DoCommand("buffer X$num");
+ $b = $curbuf;
+ }
+
+ VIM::DoCommand("buffer t");
+
+ $b = $curbuf for 0 .. 100;
+ $w = $curwin for 0 .. 100;
+ () = VIM::Buffers for 0 .. 100;
+ () = VIM::Windows for 0 .. 100;
+
+ VIM::DoCommand('bw! t');
+ if (exists &Internals::SvREFCNT) {
+ my $cb = Internals::SvREFCNT($$b);
+ my $cw = Internals::SvREFCNT($$w);
+ VIM::Eval("assert_equal(2, $cb, 'T1')");
+ VIM::Eval("assert_equal(2, $cw, 'T2')");
+ my $strongref;
+ foreach ( VIM::Buffers, VIM::Windows ) {
+ VIM::DoCommand("%bw!");
+ my $c = Internals::SvREFCNT($_);
+ VIM::Eval("assert_equal(2, $c, 'T3')");
+ $c = Internals::SvREFCNT($$_);
+ next if $c == 2 && !$strongref++;
+ VIM::Eval("assert_equal(1, $c, 'T4')");
+ }
+ $cb = Internals::SvREFCNT($$curbuf);
+ $cw = Internals::SvREFCNT($$curwin);
+ VIM::Eval("assert_equal(3, $cb, 'T5')");
+ VIM::Eval("assert_equal(3, $cw, 'T6')");
+ }
+ VIM::Eval("assert_false($$b)");
+ VIM::Eval("assert_false($$w)");
+--perl
+ %bw!
+endfunc
+
+func Test_set_cursor()
+ " Check that setting the cursor position works.
+ new
+ call setline(1, ['first line', 'second line'])
+ normal gg
+ perldo $curwin->Cursor(1, 5)
+ call assert_equal([1, 6], [line('.'), col('.')])
+
+ " Check that movement after setting cursor position keeps current column.
+ normal j
+ call assert_equal([2, 6], [line('.'), col('.')])
+endfunc
diff --git a/src/testdir/test_plus_arg_edit.vim b/src/testdir/test_plus_arg_edit.vim
new file mode 100644
index 0000000..e31680e
--- /dev/null
+++ b/src/testdir/test_plus_arg_edit.vim
@@ -0,0 +1,34 @@
+" Tests for complicated + argument to :edit command
+function Test_edit()
+ call writefile(["foo|bar"], "Xfile1")
+ call writefile(["foo/bar"], "Xfile2")
+ edit +1|s/|/PIPE/|w Xfile1| e Xfile2|1 | s/\//SLASH/|w
+ call assert_equal(["fooPIPEbar"], readfile("Xfile1"))
+ call assert_equal(["fooSLASHbar"], readfile("Xfile2"))
+ call delete('Xfile1')
+ call delete('Xfile2')
+endfunction
+
+func Test_edit_bad()
+ " Test loading a utf8 file with bad utf8 sequences.
+ call writefile(["[\xff][\xc0][\xe2\x89\xf0][\xc2\xc2]"], "Xfile")
+ new
+
+ " Without ++bad=..., the default behavior is like ++bad=?
+ e! ++enc=utf8 Xfile
+ call assert_equal('[?][?][???][??]', getline(1))
+
+ e! ++enc=utf8 ++bad=_ Xfile
+ call assert_equal('[_][_][___][__]', getline(1))
+
+ e! ++enc=utf8 ++bad=drop Xfile
+ call assert_equal('[][][][]', getline(1))
+
+ e! ++enc=utf8 ++bad=keep Xfile
+ call assert_equal("[\xff][\xc0][\xe2\x89\xf0][\xc2\xc2]", getline(1))
+
+ call assert_fails('e! ++enc=utf8 ++bad=foo Xfile', 'E474:')
+
+ bw!
+ call delete('Xfile')
+endfunc
diff --git a/src/testdir/test_popup.vim b/src/testdir/test_popup.vim
new file mode 100644
index 0000000..663a6a8
--- /dev/null
+++ b/src/testdir/test_popup.vim
@@ -0,0 +1,899 @@
+" Test for completion menu
+
+source shared.vim
+source screendump.vim
+
+let g:months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
+let g:setting = ''
+
+func ListMonths()
+ if g:setting != ''
+ exe ":set" g:setting
+ endif
+ let mth = copy(g:months)
+ let entered = strcharpart(getline('.'),0,col('.'))
+ if !empty(entered)
+ let mth = filter(mth, 'v:val=~"^".entered')
+ endif
+ call complete(1, mth)
+ return ''
+endfunc
+
+func Test_popup_complete2()
+ " Although the popupmenu is not visible, this does not mean completion mode
+ " has ended. After pressing <f5> to complete the currently typed char, Vim
+ " still stays in the first state of the completion (:h ins-completion-menu),
+ " although the popupmenu wasn't shown <c-e> will remove the inserted
+ " completed text (:h complete_CTRL-E), while the following <c-e> will behave
+ " like expected (:h i_CTRL-E)
+ new
+ inoremap <f5> <c-r>=ListMonths()<cr>
+ call append(1, ["December2015"])
+ :1
+ call feedkeys("aD\<f5>\<C-E>\<C-E>\<C-E>\<C-E>\<enter>\<esc>", 'tx')
+ call assert_equal(["Dece", "", "December2015"], getline(1,3))
+ %d
+ bw!
+endfunc
+
+func Test_popup_complete()
+ new
+ inoremap <f5> <c-r>=ListMonths()<cr>
+
+ " <C-E> - select original typed text before the completion started
+ call feedkeys("aJu\<f5>\<down>\<c-e>\<esc>", 'tx')
+ call assert_equal(["Ju"], getline(1,2))
+ %d
+
+ " <C-Y> - accept current match
+ call feedkeys("a\<f5>". repeat("\<down>",7). "\<c-y>\<esc>", 'tx')
+ call assert_equal(["August"], getline(1,2))
+ %d
+
+ " <BS> - Delete one character from the inserted text (state: 1)
+ " TODO: This should not end the completion, but it does.
+ " This should according to the documentation:
+ " January
+ " but instead, this does
+ " Januar
+ " (idea is, C-L inserts the match from the popup menu
+ " but if the menu is closed, it will insert the character <c-l>
+ call feedkeys("aJ\<f5>\<bs>\<c-l>\<esc>", 'tx')
+ call assert_equal(["Januar "], getline(1,2))
+ %d
+
+ " any-non special character: Stop completion without changing the match
+ " and insert the typed character
+ call feedkeys("a\<f5>20", 'tx')
+ call assert_equal(["January20"], getline(1,2))
+ %d
+
+ " any-non printable, non-white character: Add this character and
+ " reduce number of matches
+ call feedkeys("aJu\<f5>\<c-p>l\<c-y>", 'tx')
+ call assert_equal(["Jul"], getline(1,2))
+ %d
+
+ " any-non printable, non-white character: Add this character and
+ " reduce number of matches
+ call feedkeys("aJu\<f5>\<c-p>l\<c-n>\<c-y>", 'tx')
+ call assert_equal(["July"], getline(1,2))
+ %d
+
+ " any-non printable, non-white character: Add this character and
+ " reduce number of matches
+ call feedkeys("aJu\<f5>\<c-p>l\<c-e>", 'tx')
+ call assert_equal(["Jul"], getline(1,2))
+ %d
+
+ " <BS> - Delete one character from the inserted text (state: 2)
+ call feedkeys("a\<f5>\<c-n>\<bs>", 'tx')
+ call assert_equal(["Februar"], getline(1,2))
+ %d
+
+ " <c-l> - Insert one character from the current match
+ call feedkeys("aJ\<f5>".repeat("\<c-n>",3)."\<c-l>\<esc>", 'tx')
+ call assert_equal(["J "], getline(1,2))
+ %d
+
+ " <c-l> - Insert one character from the current match
+ call feedkeys("aJ\<f5>".repeat("\<c-n>",4)."\<c-l>\<esc>", 'tx')
+ call assert_equal(["January "], getline(1,2))
+ %d
+
+ " <c-y> - Accept current selected match
+ call feedkeys("aJ\<f5>\<c-y>\<esc>", 'tx')
+ call assert_equal(["January"], getline(1,2))
+ %d
+
+ " <c-e> - End completion, go back to what was there before selecting a match
+ call feedkeys("aJu\<f5>\<c-e>\<esc>", 'tx')
+ call assert_equal(["Ju"], getline(1,2))
+ %d
+
+ " <PageUp> - Select a match several entries back
+ call feedkeys("a\<f5>\<PageUp>\<c-y>\<esc>", 'tx')
+ call assert_equal([""], getline(1,2))
+ %d
+
+ " <PageUp><PageUp> - Select a match several entries back
+ call feedkeys("a\<f5>\<PageUp>\<PageUp>\<c-y>\<esc>", 'tx')
+ call assert_equal(["December"], getline(1,2))
+ %d
+
+ " <PageUp><PageUp><PageUp> - Select a match several entries back
+ call feedkeys("a\<f5>\<PageUp>\<PageUp>\<PageUp>\<c-y>\<esc>", 'tx')
+ call assert_equal(["February"], getline(1,2))
+ %d
+
+ " <PageDown> - Select a match several entries further
+ call feedkeys("a\<f5>\<PageDown>\<c-y>\<esc>", 'tx')
+ call assert_equal(["November"], getline(1,2))
+ %d
+
+ " <PageDown><PageDown> - Select a match several entries further
+ call feedkeys("a\<f5>\<PageDown>\<PageDown>\<c-y>\<esc>", 'tx')
+ call assert_equal(["December"], getline(1,2))
+ %d
+
+ " <PageDown><PageDown><PageDown> - Select a match several entries further
+ call feedkeys("a\<f5>\<PageDown>\<PageDown>\<PageDown>\<c-y>\<esc>", 'tx')
+ call assert_equal([""], getline(1,2))
+ %d
+
+ " <PageDown><PageDown><PageDown><PageDown> - Select a match several entries further
+ call feedkeys("a\<f5>".repeat("\<PageDown>",4)."\<c-y>\<esc>", 'tx')
+ call assert_equal(["October"], getline(1,2))
+ %d
+
+ " <Up> - Select a match don't insert yet
+ call feedkeys("a\<f5>\<Up>\<c-y>\<esc>", 'tx')
+ call assert_equal([""], getline(1,2))
+ %d
+
+ " <Up><Up> - Select a match don't insert yet
+ call feedkeys("a\<f5>\<Up>\<Up>\<c-y>\<esc>", 'tx')
+ call assert_equal(["December"], getline(1,2))
+ %d
+
+ " <Up><Up><Up> - Select a match don't insert yet
+ call feedkeys("a\<f5>\<Up>\<Up>\<Up>\<c-y>\<esc>", 'tx')
+ call assert_equal(["November"], getline(1,2))
+ %d
+
+ " <Tab> - Stop completion and insert the match
+ call feedkeys("a\<f5>\<Tab>\<c-y>\<esc>", 'tx')
+ call assert_equal(["January "], getline(1,2))
+ %d
+
+ " <Space> - Stop completion and insert the match
+ call feedkeys("a\<f5>".repeat("\<c-p>",5)." \<esc>", 'tx')
+ call assert_equal(["September "], getline(1,2))
+ %d
+
+ " <Enter> - Use the text and insert line break (state: 1)
+ call feedkeys("a\<f5>\<enter>\<esc>", 'tx')
+ call assert_equal(["January", ''], getline(1,2))
+ %d
+
+ " <Enter> - Insert the current selected text (state: 2)
+ call feedkeys("a\<f5>".repeat("\<Up>",5)."\<enter>\<esc>", 'tx')
+ call assert_equal(["September"], getline(1,2))
+ %d
+
+ " Insert match immediately, if there is only one match
+ " <c-y> selects a character from the line above
+ call append(0, ["December2015"])
+ call feedkeys("aD\<f5>\<C-Y>\<C-Y>\<C-Y>\<C-Y>\<enter>\<esc>", 'tx')
+ call assert_equal(["December2015", "December2015", ""], getline(1,3))
+ %d
+
+ " use menuone for 'completeopt'
+ " Since for the first <c-y> the menu is still shown, will only select
+ " three letters from the line above
+ set completeopt&vim
+ set completeopt+=menuone
+ call append(0, ["December2015"])
+ call feedkeys("aD\<f5>\<C-Y>\<C-Y>\<C-Y>\<C-Y>\<enter>\<esc>", 'tx')
+ call assert_equal(["December2015", "December201", ""], getline(1,3))
+ %d
+
+ " use longest for 'completeopt'
+ set completeopt&vim
+ call feedkeys("aM\<f5>\<C-N>\<C-P>\<c-e>\<enter>\<esc>", 'tx')
+ set completeopt+=longest
+ call feedkeys("aM\<f5>\<C-N>\<C-P>\<c-e>\<enter>\<esc>", 'tx')
+ call assert_equal(["M", "Ma", ""], getline(1,3))
+ %d
+
+ " use noselect/noinsert for 'completeopt'
+ set completeopt&vim
+ call feedkeys("aM\<f5>\<enter>\<esc>", 'tx')
+ set completeopt+=noselect
+ call feedkeys("aM\<f5>\<enter>\<esc>", 'tx')
+ set completeopt-=noselect completeopt+=noinsert
+ call feedkeys("aM\<f5>\<enter>\<esc>", 'tx')
+ call assert_equal(["March", "M", "March"], getline(1,4))
+ %d
+endfunc
+
+
+func Test_popup_completion_insertmode()
+ new
+ inoremap <F5> <C-R>=ListMonths()<CR>
+
+ call feedkeys("a\<f5>\<down>\<enter>\<esc>", 'tx')
+ call assert_equal('February', getline(1))
+ %d
+ " Set noinsertmode
+ let g:setting = 'noinsertmode'
+ call feedkeys("a\<f5>\<down>\<enter>\<esc>", 'tx')
+ call assert_equal('February', getline(1))
+ call assert_false(pumvisible())
+ %d
+ " Go through all matches, until none is selected
+ let g:setting = ''
+ call feedkeys("a\<f5>". repeat("\<c-n>",12)."\<enter>\<esc>", 'tx')
+ call assert_equal('', getline(1))
+ %d
+ " select previous entry
+ call feedkeys("a\<f5>\<c-p>\<enter>\<esc>", 'tx')
+ call assert_equal('', getline(1))
+ %d
+ " select last entry
+ call feedkeys("a\<f5>\<c-p>\<c-p>\<enter>\<esc>", 'tx')
+ call assert_equal('December', getline(1))
+
+ iunmap <F5>
+endfunc
+
+func Test_noinsert_complete()
+ func! s:complTest1() abort
+ call complete(1, ['source', 'soundfold'])
+ return ''
+ endfunc
+
+ func! s:complTest2() abort
+ call complete(1, ['source', 'soundfold'])
+ return ''
+ endfunc
+
+ new
+ set completeopt+=noinsert
+ inoremap <F5> <C-R>=s:complTest1()<CR>
+ call feedkeys("i\<F5>soun\<CR>\<CR>\<ESC>.", 'tx')
+ call assert_equal('soundfold', getline(1))
+ call assert_equal('soundfold', getline(2))
+ bwipe!
+
+ new
+ inoremap <F5> <C-R>=s:complTest2()<CR>
+ call feedkeys("i\<F5>\<CR>\<ESC>", 'tx')
+ call assert_equal('source', getline(1))
+ bwipe!
+
+ set completeopt-=noinsert
+ iunmap <F5>
+endfunc
+
+func Test_compl_vim_cmds_after_register_expr()
+ func! s:test_func()
+ return 'autocmd '
+ endfunc
+ augroup AAAAA_Group
+ au!
+ augroup END
+
+ new
+ call feedkeys("i\<c-r>=s:test_func()\<CR>\<C-x>\<C-v>\<Esc>", 'tx')
+ call assert_equal('autocmd AAAAA_Group', getline(1))
+ autocmd! AAAAA_Group
+ augroup! AAAAA_Group
+ bwipe!
+endfunc
+
+func DummyCompleteOne(findstart, base)
+ if a:findstart
+ return 0
+ else
+ wincmd n
+ return ['onedef', 'oneDEF']
+ endif
+endfunc
+
+" Test that nothing happens if the 'completefunc' opens
+" a new window (no completion, no crash)
+func Test_completefunc_opens_new_window_one()
+ new
+ let winid = win_getid()
+ setlocal completefunc=DummyCompleteOne
+ call setline(1, 'one')
+ /^one
+ call assert_fails('call feedkeys("A\<C-X>\<C-U>\<C-N>\<Esc>", "x")', 'E839:')
+ call assert_notequal(winid, win_getid())
+ q!
+ call assert_equal(winid, win_getid())
+ call assert_equal('', getline(1))
+ q!
+endfunc
+
+" Test that nothing happens if the 'completefunc' opens
+" a new window (no completion, no crash)
+func DummyCompleteTwo(findstart, base)
+ if a:findstart
+ wincmd n
+ return 0
+ else
+ return ['twodef', 'twoDEF']
+ endif
+endfunc
+
+" Test that nothing happens if the 'completefunc' opens
+" a new window (no completion, no crash)
+func Test_completefunc_opens_new_window_two()
+ new
+ let winid = win_getid()
+ setlocal completefunc=DummyCompleteTwo
+ call setline(1, 'two')
+ /^two
+ call assert_fails('call feedkeys("A\<C-X>\<C-U>\<C-N>\<Esc>", "x")', 'E764:')
+ call assert_notequal(winid, win_getid())
+ q!
+ call assert_equal(winid, win_getid())
+ call assert_equal('two', getline(1))
+ q!
+endfunc
+
+func DummyCompleteThree(findstart, base)
+ if a:findstart
+ return 0
+ else
+ return ['threedef', 'threeDEF']
+ endif
+endfunc
+
+:"Test that 'completefunc' works when it's OK.
+func Test_completefunc_works()
+ new
+ let winid = win_getid()
+ setlocal completefunc=DummyCompleteThree
+ call setline(1, 'three')
+ /^three
+ call feedkeys("A\<C-X>\<C-U>\<C-N>\<Esc>", "x")
+ call assert_equal(winid, win_getid())
+ call assert_equal('threeDEF', getline(1))
+ q!
+endfunc
+
+func DummyCompleteFour(findstart, base)
+ if a:findstart
+ return 0
+ else
+ call complete_add('four1')
+ call complete_add('four2')
+ call complete_check()
+ call complete_add('four3')
+ call complete_add('four4')
+ call complete_check()
+ call complete_add('four5')
+ call complete_add('four6')
+ return []
+ endif
+endfunc
+
+" Test that 'omnifunc' works when it's OK.
+func Test_omnifunc_with_check()
+ new
+ setlocal omnifunc=DummyCompleteFour
+ call setline(1, 'four')
+ /^four
+ call feedkeys("A\<C-X>\<C-O>\<C-N>\<Esc>", "x")
+ call assert_equal('four2', getline(1))
+
+ call setline(1, 'four')
+ /^four
+ call feedkeys("A\<C-X>\<C-O>\<C-N>\<C-N>\<Esc>", "x")
+ call assert_equal('four3', getline(1))
+
+ call setline(1, 'four')
+ /^four
+ call feedkeys("A\<C-X>\<C-O>\<C-N>\<C-N>\<C-N>\<C-N>\<Esc>", "x")
+ call assert_equal('four5', getline(1))
+
+ q!
+endfunc
+
+func UndoComplete()
+ call complete(1, ['January', 'February', 'March',
+ \ 'April', 'May', 'June', 'July', 'August', 'September',
+ \ 'October', 'November', 'December'])
+ return ''
+endfunc
+
+" Test that no undo item is created when no completion is inserted
+func Test_complete_no_undo()
+ set completeopt=menu,preview,noinsert,noselect
+ inoremap <Right> <C-R>=UndoComplete()<CR>
+ new
+ call feedkeys("ixxx\<CR>\<CR>yyy\<Esc>k", 'xt')
+ call feedkeys("iaaa\<Esc>0", 'xt')
+ call assert_equal('aaa', getline(2))
+ call feedkeys("i\<Right>\<Esc>", 'xt')
+ call assert_equal('aaa', getline(2))
+ call feedkeys("u", 'xt')
+ call assert_equal('', getline(2))
+
+ call feedkeys("ibbb\<Esc>0", 'xt')
+ call assert_equal('bbb', getline(2))
+ call feedkeys("A\<Right>\<Down>\<CR>\<Esc>", 'xt')
+ call assert_equal('January', getline(2))
+ call feedkeys("u", 'xt')
+ call assert_equal('bbb', getline(2))
+
+ call feedkeys("A\<Right>\<C-N>\<Esc>", 'xt')
+ call assert_equal('January', getline(2))
+ call feedkeys("u", 'xt')
+ call assert_equal('bbb', getline(2))
+
+ iunmap <Right>
+ set completeopt&
+ q!
+endfunc
+
+func DummyCompleteFive(findstart, base)
+ if a:findstart
+ return 0
+ else
+ return [
+ \ { 'word': 'January', 'info': "info1-1\n1-2\n1-3" },
+ \ { 'word': 'February', 'info': "info2-1\n2-2\n2-3" },
+ \ { 'word': 'March', 'info': "info3-1\n3-2\n3-3" },
+ \ { 'word': 'April', 'info': "info4-1\n4-2\n4-3" },
+ \ { 'word': 'May', 'info': "info5-1\n5-2\n5-3" },
+ \ ]
+ endif
+endfunc
+
+" Test that 'completefunc' on Scratch buffer with preview window works when
+" it's OK.
+func Test_completefunc_with_scratch_buffer()
+ new +setlocal\ buftype=nofile\ bufhidden=wipe\ noswapfile
+ set completeopt+=preview
+ setlocal completefunc=DummyCompleteFive
+ call feedkeys("A\<C-X>\<C-U>\<C-N>\<C-N>\<C-N>\<Esc>", "x")
+ call assert_equal(['April'], getline(1, '$'))
+ pclose
+ q!
+ set completeopt&
+endfunc
+
+" <C-E> - select original typed text before the completion started without
+" auto-wrap text.
+func Test_completion_ctrl_e_without_autowrap()
+ new
+ let tw_save = &tw
+ set tw=78
+ let li = [
+ \ '" zzz',
+ \ '" zzzyyyyyyyyyyyyyyyyyyy']
+ call setline(1, li)
+ 0
+ call feedkeys("A\<C-X>\<C-N>\<C-E>\<Esc>", "tx")
+ call assert_equal(li, getline(1, '$'))
+
+ let &tw = tw_save
+ q!
+endfunc
+
+func DummyCompleteSix()
+ call complete(1, ['Hello', 'World'])
+ return ''
+endfunction
+
+" complete() correctly clears the list of autocomplete candidates
+" See #1411
+func Test_completion_clear_candidate_list()
+ new
+ %d
+ " select first entry from the completion popup
+ call feedkeys("a xxx\<C-N>\<C-R>=DummyCompleteSix()\<CR>", "tx")
+ call assert_equal('Hello', getline(1))
+ %d
+ " select second entry from the completion popup
+ call feedkeys("a xxx\<C-N>\<C-R>=DummyCompleteSix()\<CR>\<C-N>", "tx")
+ call assert_equal('World', getline(1))
+ %d
+ " select original text
+ call feedkeys("a xxx\<C-N>\<C-R>=DummyCompleteSix()\<CR>\<C-N>\<C-N>", "tx")
+ call assert_equal(' xxx', getline(1))
+ %d
+ " back at first entry from completion list
+ call feedkeys("a xxx\<C-N>\<C-R>=DummyCompleteSix()\<CR>\<C-N>\<C-N>\<C-N>", "tx")
+ call assert_equal('Hello', getline(1))
+
+ bw!
+endfunc
+
+func Test_completion_respect_bs_option()
+ new
+ let li = ["aaa", "aaa12345", "aaaabcdef", "aaaABC"]
+
+ set bs=indent,eol
+ call setline(1, li)
+ 1
+ call feedkeys("A\<C-X>\<C-N>\<C-P>\<BS>\<BS>\<BS>\<Esc>", "tx")
+ call assert_equal('aaa', getline(1))
+
+ %d
+ set bs=indent,eol,start
+ call setline(1, li)
+ 1
+ call feedkeys("A\<C-X>\<C-N>\<C-P>\<BS>\<BS>\<BS>\<Esc>", "tx")
+ call assert_equal('', getline(1))
+
+ bw!
+endfunc
+
+func CompleteUndo() abort
+ call complete(1, g:months)
+ return ''
+endfunc
+
+func Test_completion_can_undo()
+ inoremap <Right> <c-r>=CompleteUndo()<cr>
+ set completeopt+=noinsert,noselect
+
+ new
+ call feedkeys("a\<Right>a\<Esc>", 'xt')
+ call assert_equal('a', getline(1))
+ undo
+ call assert_equal('', getline(1))
+
+ bwipe!
+ set completeopt&
+ iunmap <Right>
+endfunc
+
+func Test_completion_comment_formatting()
+ new
+ setl formatoptions=tcqro
+ call feedkeys("o/*\<cr>\<cr>/\<esc>", 'tx')
+ call assert_equal(['', '/*', ' *', ' */'], getline(1,4))
+ %d
+ call feedkeys("o/*\<cr>foobar\<cr>/\<esc>", 'tx')
+ call assert_equal(['', '/*', ' * foobar', ' */'], getline(1,4))
+ %d
+ try
+ call feedkeys("o/*\<cr>\<cr>\<c-x>\<c-u>/\<esc>", 'tx')
+ call assert_report('completefunc not set, should have failed')
+ catch
+ call assert_exception('E764:')
+ endtry
+ call assert_equal(['', '/*', ' *', ' */'], getline(1,4))
+ bwipe!
+endfunc
+
+func MessCompleteMonths()
+ for m in split("Jan Feb Mar Apr May Jun Jul Aug Sep")
+ call complete_add(m)
+ if complete_check()
+ break
+ endif
+ endfor
+ return []
+endfunc
+
+func MessCompleteMore()
+ call complete(1, split("Oct Nov Dec"))
+ return []
+endfunc
+
+func MessComplete(findstart, base)
+ if a:findstart
+ let line = getline('.')
+ let start = col('.') - 1
+ while start > 0 && line[start - 1] =~ '\a'
+ let start -= 1
+ endwhile
+ return start
+ else
+ call MessCompleteMonths()
+ call MessCompleteMore()
+ return []
+ endif
+endfunc
+
+func Test_complete_func_mess()
+ " Calling complete() after complete_add() in 'completefunc' is wrong, but it
+ " should not crash.
+ set completefunc=MessComplete
+ new
+ call setline(1, 'Ju')
+ call feedkeys("A\<c-x>\<c-u>/\<esc>", 'tx')
+ call assert_equal('Oct/Oct', getline(1))
+ bwipe!
+ set completefunc=
+endfunc
+
+func Test_complete_CTRLN_startofbuffer()
+ new
+ call setline(1, [ 'organize(cupboard, 3, 2);',
+ \ 'prioritize(bureau, 8, 7);',
+ \ 'realize(bannister, 4, 4);',
+ \ 'moralize(railing, 3,9);'])
+ let expected=['cupboard.organize(3, 2);',
+ \ 'bureau.prioritize(8, 7);',
+ \ 'bannister.realize(4, 4);',
+ \ 'railing.moralize(3,9);']
+ call feedkeys("qai\<c-n>\<c-n>.\<esc>3wdW\<cr>q3@a", 'tx')
+ call assert_equal(expected, getline(1,'$'))
+ bwipe!
+endfunc
+
+func Test_popup_and_window_resize()
+ if !has('terminal') || has('gui_running')
+ return
+ endif
+ let h = winheight(0)
+ if h < 15
+ return
+ endif
+ let rows = h / 3
+ let buf = term_start([GetVimProg(), '--clean', '-c', 'set noswapfile'], {'term_rows': rows})
+ call term_sendkeys(buf, (h / 3 - 1) . "o\<esc>")
+ " Wait for the nested Vim to exit insert mode, where it will show the ruler.
+ " Need to trigger a redraw.
+ call WaitFor({-> execute("redraw") == "" && term_getline(buf, rows) =~ '\<' . rows . ',.*Bot'})
+
+ call term_sendkeys(buf, "Gi\<c-x>")
+ call term_sendkeys(buf, "\<c-v>")
+ call term_wait(buf, 100)
+ " popup first entry "!" must be at the top
+ call WaitForAssert({-> assert_match('^!\s*$', term_getline(buf, 1))})
+ exe 'resize +' . (h - 1)
+ call term_wait(buf, 100)
+ redraw!
+ " popup shifted down, first line is now empty
+ call WaitForAssert({-> assert_equal('', term_getline(buf, 1))})
+ sleep 100m
+ " popup is below cursor line and shows first match "!"
+ call WaitForAssert({-> assert_match('^!\s*$', term_getline(buf, term_getcursor(buf)[0] + 1))})
+ " cursor line also shows !
+ call assert_match('^!\s*$', term_getline(buf, term_getcursor(buf)[0]))
+ bwipe!
+endfunc
+
+func Test_popup_and_preview_autocommand()
+ " This used to crash Vim
+ if !has('python')
+ return
+ endif
+ let h = winheight(0)
+ if h < 15
+ return
+ endif
+ new
+ augroup MyBufAdd
+ au!
+ au BufAdd * nested tab sball
+ augroup END
+ set omnifunc=pythoncomplete#Complete
+ call setline(1, 'import os')
+ " make the line long
+ call setline(2, ' os.')
+ $
+ call feedkeys("A\<C-X>\<C-O>\<C-N>\<C-N>\<C-N>\<enter>\<esc>", 'tx')
+ call assert_equal("import os", getline(1))
+ call assert_match(' os.\(EX_IOERR\|O_CREAT\)$', getline(2))
+ call assert_equal(1, winnr('$'))
+ " previewwindow option is not set
+ call assert_equal(0, &previewwindow)
+ norm! gt
+ call assert_equal(0, &previewwindow)
+ norm! gT
+ call assert_equal(10, tabpagenr('$'))
+ tabonly
+ pclose
+ augroup MyBufAdd
+ au!
+ augroup END
+ augroup! MyBufAdd
+ bw!
+endfunc
+
+func Test_popup_and_previewwindow_dump()
+ if !CanRunVimInTerminal()
+ return
+ endif
+ call writefile([
+ \ 'set previewheight=9',
+ \ 'silent! pedit',
+ \ 'call setline(1, map(repeat(["ab"], 10), "v:val. v:key"))',
+ \ 'exec "norm! G\<C-E>\<C-E>"',
+ \ ], 'Xscript')
+ let buf = RunVimInTerminal('-S Xscript', {})
+
+ " Test that popup and previewwindow do not overlap.
+ call term_sendkeys(buf, "o\<C-X>\<C-N>")
+ sleep 100m
+ call VerifyScreenDump(buf, 'Test_popup_and_previewwindow_01', {})
+
+ call term_sendkeys(buf, "\<Esc>u")
+ call StopVimInTerminal(buf)
+ call delete('Xscript')
+endfunc
+
+func Test_balloon_split()
+ if !exists('*balloon_split')
+ return
+ endif
+ call assert_equal([
+ \ 'tempname: 0x555555e380a0 "/home/mool/.viminfz.tmp"',
+ \ ], balloon_split(
+ \ 'tempname: 0x555555e380a0 "/home/mool/.viminfz.tmp"'))
+ call assert_equal([
+ \ 'one two three four one two three four one two thre',
+ \ 'e four',
+ \ ], balloon_split(
+ \ 'one two three four one two three four one two three four'))
+
+ call assert_equal([
+ \ 'struct = {',
+ \ ' one = 1,',
+ \ ' two = 2,',
+ \ ' three = 3}',
+ \ ], balloon_split(
+ \ 'struct = {one = 1, two = 2, three = 3}'))
+
+ call assert_equal([
+ \ 'struct = {',
+ \ ' one = 1,',
+ \ ' nested = {',
+ \ ' n1 = "yes",',
+ \ ' n2 = "no"}',
+ \ ' two = 2}',
+ \ ], balloon_split(
+ \ 'struct = {one = 1, nested = {n1 = "yes", n2 = "no"} two = 2}'))
+ call assert_equal([
+ \ 'struct = 0x234 {',
+ \ ' long = 2343 "\\"some long string that will be wr',
+ \ 'apped in two\\"",',
+ \ ' next = 123}',
+ \ ], balloon_split(
+ \ 'struct = 0x234 {long = 2343 "\\"some long string that will be wrapped in two\\"", next = 123}'))
+endfunc
+
+func Test_popup_position()
+ if !CanRunVimInTerminal()
+ return
+ endif
+ call writefile([
+ \ '123456789_123456789_123456789_a',
+ \ '123456789_123456789_123456789_b',
+ \ ' 123',
+ \ ], 'Xtest')
+ let buf = RunVimInTerminal('Xtest', {})
+ call term_sendkeys(buf, ":vsplit\<CR>")
+
+ " default pumwidth in left window: overlap in right window
+ call term_sendkeys(buf, "GA\<C-N>")
+ call VerifyScreenDump(buf, 'Test_popup_position_01', {'rows': 8})
+ call term_sendkeys(buf, "\<Esc>u")
+
+ " default pumwidth: fill until right of window
+ call term_sendkeys(buf, "\<C-W>l")
+ call term_sendkeys(buf, "GA\<C-N>")
+ call VerifyScreenDump(buf, 'Test_popup_position_02', {'rows': 8})
+
+ " larger pumwidth: used as minimum width
+ call term_sendkeys(buf, "\<Esc>u")
+ call term_sendkeys(buf, ":set pumwidth=30\<CR>")
+ call term_sendkeys(buf, "GA\<C-N>")
+ call VerifyScreenDump(buf, 'Test_popup_position_03', {'rows': 8})
+
+ " completed text wider than the window and 'pumwidth' smaller than available
+ " space
+ call term_sendkeys(buf, "\<Esc>u")
+ call term_sendkeys(buf, ":set pumwidth=20\<CR>")
+ call term_sendkeys(buf, "ggI123456789_\<Esc>")
+ call term_sendkeys(buf, "jI123456789_\<Esc>")
+ call term_sendkeys(buf, "GA\<C-N>")
+ call VerifyScreenDump(buf, 'Test_popup_position_04', {'rows': 10})
+
+ call term_sendkeys(buf, "\<Esc>u")
+ call StopVimInTerminal(buf)
+ call delete('Xtest')
+endfunc
+
+func Test_popup_command()
+ if !CanRunVimInTerminal() || !has('menu')
+ return
+ endif
+
+ call writefile([
+ \ 'one two three four five',
+ \ 'and one two Xthree four five',
+ \ 'one more two three four five',
+ \ ], 'Xtest')
+ let buf = RunVimInTerminal('Xtest', {})
+ call term_sendkeys(buf, ":source $VIMRUNTIME/menu.vim\<CR>")
+ call term_sendkeys(buf, "/X\<CR>:popup PopUp\<CR>")
+ call VerifyScreenDump(buf, 'Test_popup_command_01', {})
+
+ " Select a word
+ call term_sendkeys(buf, "jj")
+ call VerifyScreenDump(buf, 'Test_popup_command_02', {})
+
+ " Select a word
+ call term_sendkeys(buf, "j\<CR>")
+ call VerifyScreenDump(buf, 'Test_popup_command_03', {})
+
+ call term_sendkeys(buf, "\<Esc>")
+ call StopVimInTerminal(buf)
+ call delete('Xtest')
+endfunc
+
+func Test_popup_complete_backwards()
+ new
+ call setline(1, ['Post', 'Port', 'Po'])
+ let expected=['Post', 'Port', 'Port']
+ call cursor(3,2)
+ call feedkeys("A\<C-X>". repeat("\<C-P>", 3). "rt\<cr>", 'tx')
+ call assert_equal(expected, getline(1,'$'))
+ bwipe!
+endfunc
+
+func Test_popup_complete_backwards_ctrl_p()
+ new
+ call setline(1, ['Post', 'Port', 'Po'])
+ let expected=['Post', 'Port', 'Port']
+ call cursor(3,2)
+ call feedkeys("A\<C-P>\<C-N>rt\<cr>", 'tx')
+ call assert_equal(expected, getline(1,'$'))
+ bwipe!
+endfunc
+
+func Test_complete_o_tab()
+ let s:o_char_pressed = 0
+
+ fun! s:act_on_text_changed()
+ if s:o_char_pressed
+ let s:o_char_pressed = 0
+ call feedkeys("\<c-x>\<c-n>", 'i')
+ endif
+ endfunc
+
+ set completeopt=menu,noselect
+ new
+ imap <expr> <buffer> <tab> pumvisible() ? "\<c-p>" : "X"
+ autocmd! InsertCharPre <buffer> let s:o_char_pressed = (v:char ==# 'o')
+ autocmd! TextChangedI <buffer> call <sid>act_on_text_changed()
+ call setline(1, ['hoard', 'hoax', 'hoarse', ''])
+ let l:expected = ['hoard', 'hoax', 'hoarse', 'hoax', 'hoax']
+ call cursor(4,1)
+ call test_override("char_avail", 1)
+ call feedkeys("Ahoa\<tab>\<tab>\<c-y>\<esc>", 'tx')
+ call feedkeys("oho\<tab>\<tab>\<c-y>\<esc>", 'tx')
+ call assert_equal(l:expected, getline(1,'$'))
+
+ call test_override("char_avail", 0)
+ bwipe!
+ set completeopt&
+ delfunc s:act_on_text_changed
+endfunc
+
+func Test_menu_only_exists_in_terminal()
+ if !exists(':tlmenu') || has('gui_running')
+ return
+ endif
+ tlnoremenu &Edit.&Paste<Tab>"+gP <C-W>"+
+ aunmenu *
+ try
+ popup Edit
+ call assert_false(1, 'command should have failed')
+ catch
+ call assert_exception('E328:')
+ endtry
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/test_preview.vim b/src/testdir/test_preview.vim
new file mode 100644
index 0000000..91923fb
--- /dev/null
+++ b/src/testdir/test_preview.vim
@@ -0,0 +1,13 @@
+" Tests for the preview window
+
+func Test_Psearch()
+ " this used to cause ml_get errors
+ help
+ let wincount = winnr('$')
+ 0f
+ ps.
+ call assert_equal(wincount + 1, winnr('$'))
+ pclose
+ call assert_equal(wincount, winnr('$'))
+ bwipe
+endfunc
diff --git a/src/testdir/test_profile.vim b/src/testdir/test_profile.vim
new file mode 100644
index 0000000..d6e9c03
--- /dev/null
+++ b/src/testdir/test_profile.vim
@@ -0,0 +1,520 @@
+" Test Vim profiler
+if !has('profile')
+ finish
+endif
+
+func Test_profile_func()
+ let lines = [
+ \ 'profile start Xprofile_func.log',
+ \ 'profile func Foo*"',
+ \ "func! Foo1()",
+ \ "endfunc",
+ \ "func! Foo2()",
+ \ " let l:count = 100",
+ \ " while l:count > 0",
+ \ " let l:count = l:count - 1",
+ \ " endwhile",
+ \ "endfunc",
+ \ "func! Foo3()",
+ \ "endfunc",
+ \ "func! Bar()",
+ \ "endfunc",
+ \ "call Foo1()",
+ \ "call Foo1()",
+ \ "profile pause",
+ \ "call Foo1()",
+ \ "profile continue",
+ \ "call Foo2()",
+ \ "call Foo3()",
+ \ "call Bar()",
+ \ "if !v:profiling",
+ \ " delfunc Foo2",
+ \ "endif",
+ \ "delfunc Foo3",
+ \ ]
+
+ call writefile(lines, 'Xprofile_func.vim')
+ call system(v:progpath
+ \ . ' -es --clean'
+ \ . ' -c "so Xprofile_func.vim"'
+ \ . ' -c "qall!"')
+ call assert_equal(0, v:shell_error)
+
+ let lines = readfile('Xprofile_func.log')
+
+ " - Foo1() is called 3 times but should be reported as called twice
+ " since one call is in between "profile pause" .. "profile continue".
+ " - Foo2() should come before Foo1() since Foo1() does much more work.
+ " - Foo3() is not reported because function is deleted.
+ " - Unlike Foo3(), Foo2() should not be deleted since there is a check
+ " for v:profiling.
+ " - Bar() is not reported since it does not match "profile func Foo*".
+ call assert_equal(30, len(lines))
+
+ call assert_equal('FUNCTION Foo1()', lines[0])
+ call assert_match('Defined:.*Xprofile_func.vim', lines[1])
+ call assert_equal('Called 2 times', lines[2])
+ call assert_match('^Total time:\s\+\d\+\.\d\+$', lines[3])
+ call assert_match('^ Self time:\s\+\d\+\.\d\+$', lines[4])
+ call assert_equal('', lines[5])
+ call assert_equal('count total (s) self (s)', lines[6])
+ call assert_equal('', lines[7])
+ call assert_equal('FUNCTION Foo2()', lines[8])
+ call assert_equal('Called 1 time', lines[10])
+ call assert_match('^Total time:\s\+\d\+\.\d\+$', lines[11])
+ call assert_match('^ Self time:\s\+\d\+\.\d\+$', lines[12])
+ call assert_equal('', lines[13])
+ call assert_equal('count total (s) self (s)', lines[14])
+ call assert_match('^\s*1\s\+.*\slet l:count = 100$', lines[15])
+ call assert_match('^\s*101\s\+.*\swhile l:count > 0$', lines[16])
+ call assert_match('^\s*100\s\+.*\s let l:count = l:count - 1$', lines[17])
+ call assert_match('^\s*101\s\+.*\sendwhile$', lines[18])
+ call assert_equal('', lines[19])
+ call assert_equal('FUNCTIONS SORTED ON TOTAL TIME', lines[20])
+ call assert_equal('count total (s) self (s) function', lines[21])
+ call assert_match('^\s*1\s\+\d\+\.\d\+\s\+Foo2()$', lines[22])
+ call assert_match('^\s*2\s\+\d\+\.\d\+\s\+Foo1()$', lines[23])
+ call assert_equal('', lines[24])
+ call assert_equal('FUNCTIONS SORTED ON SELF TIME', lines[25])
+ call assert_equal('count total (s) self (s) function', lines[26])
+ call assert_match('^\s*1\s\+\d\+\.\d\+\s\+Foo2()$', lines[27])
+ call assert_match('^\s*2\s\+\d\+\.\d\+\s\+Foo1()$', lines[28])
+ call assert_equal('', lines[29])
+
+ call delete('Xprofile_func.vim')
+ call delete('Xprofile_func.log')
+endfunc
+
+func Test_profile_func_with_ifelse()
+ let lines = [
+ \ "func! Foo1()",
+ \ " if 1",
+ \ " let x = 0",
+ \ " elseif 1",
+ \ " let x = 1",
+ \ " else",
+ \ " let x = 2",
+ \ " endif",
+ \ "endfunc",
+ \ "func! Foo2()",
+ \ " if 0",
+ \ " let x = 0",
+ \ " elseif 1",
+ \ " let x = 1",
+ \ " else",
+ \ " let x = 2",
+ \ " endif",
+ \ "endfunc",
+ \ "func! Foo3()",
+ \ " if 0",
+ \ " let x = 0",
+ \ " elseif 0",
+ \ " let x = 1",
+ \ " else",
+ \ " let x = 2",
+ \ " endif",
+ \ "endfunc",
+ \ "call Foo1()",
+ \ "call Foo2()",
+ \ "call Foo3()",
+ \ ]
+
+ call writefile(lines, 'Xprofile_func.vim')
+ call system(v:progpath
+ \ . ' -es -u NONE -U NONE -i NONE --noplugin'
+ \ . ' -c "profile start Xprofile_func.log"'
+ \ . ' -c "profile func Foo*"'
+ \ . ' -c "so Xprofile_func.vim"'
+ \ . ' -c "qall!"')
+ call assert_equal(0, v:shell_error)
+
+ let lines = readfile('Xprofile_func.log')
+
+ " - Foo1() should pass 'if' block.
+ " - Foo2() should pass 'elseif' block.
+ " - Foo3() should pass 'else' block.
+ call assert_equal(57, len(lines))
+
+ call assert_equal('FUNCTION Foo1()', lines[0])
+ call assert_match('Defined:.*Xprofile_func.vim', lines[1])
+ call assert_equal('Called 1 time', lines[2])
+ call assert_match('^Total time:\s\+\d\+\.\d\+$', lines[3])
+ call assert_match('^ Self time:\s\+\d\+\.\d\+$', lines[4])
+ call assert_equal('', lines[5])
+ call assert_equal('count total (s) self (s)', lines[6])
+ call assert_match('^\s*1\s\+.*\sif 1$', lines[7])
+ call assert_match('^\s*1\s\+.*\s let x = 0$', lines[8])
+ call assert_match( '^\s\+elseif 1$', lines[9])
+ call assert_match( '^\s\+let x = 1$', lines[10])
+ call assert_match( '^\s\+else$', lines[11])
+ call assert_match( '^\s\+let x = 2$', lines[12])
+ call assert_match('^\s*1\s\+.*\sendif$', lines[13])
+ call assert_equal('', lines[14])
+ call assert_equal('FUNCTION Foo2()', lines[15])
+ call assert_equal('Called 1 time', lines[17])
+ call assert_match('^Total time:\s\+\d\+\.\d\+$', lines[18])
+ call assert_match('^ Self time:\s\+\d\+\.\d\+$', lines[19])
+ call assert_equal('', lines[20])
+ call assert_equal('count total (s) self (s)', lines[21])
+ call assert_match('^\s*1\s\+.*\sif 0$', lines[22])
+ call assert_match( '^\s\+let x = 0$', lines[23])
+ call assert_match('^\s*1\s\+.*\selseif 1$', lines[24])
+ call assert_match('^\s*1\s\+.*\s let x = 1$', lines[25])
+ call assert_match( '^\s\+else$', lines[26])
+ call assert_match( '^\s\+let x = 2$', lines[27])
+ call assert_match('^\s*1\s\+.*\sendif$', lines[28])
+ call assert_equal('', lines[29])
+ call assert_equal('FUNCTION Foo3()', lines[30])
+ call assert_equal('Called 1 time', lines[32])
+ call assert_match('^Total time:\s\+\d\+\.\d\+$', lines[33])
+ call assert_match('^ Self time:\s\+\d\+\.\d\+$', lines[34])
+ call assert_equal('', lines[35])
+ call assert_equal('count total (s) self (s)', lines[36])
+ call assert_match('^\s*1\s\+.*\sif 0$', lines[37])
+ call assert_match( '^\s\+let x = 0$', lines[38])
+ call assert_match('^\s*1\s\+.*\selseif 0$', lines[39])
+ call assert_match( '^\s\+let x = 1$', lines[40])
+ call assert_match('^\s*1\s\+.*\selse$', lines[41])
+ call assert_match('^\s*1\s\+.*\s let x = 2$', lines[42])
+ call assert_match('^\s*1\s\+.*\sendif$', lines[43])
+ call assert_equal('', lines[44])
+ call assert_equal('FUNCTIONS SORTED ON TOTAL TIME', lines[45])
+ call assert_equal('count total (s) self (s) function', lines[46])
+ call assert_match('^\s*1\s\+\d\+\.\d\+\s\+Foo.()$', lines[47])
+ call assert_match('^\s*1\s\+\d\+\.\d\+\s\+Foo.()$', lines[48])
+ call assert_match('^\s*1\s\+\d\+\.\d\+\s\+Foo.()$', lines[49])
+ call assert_equal('', lines[50])
+ call assert_equal('FUNCTIONS SORTED ON SELF TIME', lines[51])
+ call assert_equal('count total (s) self (s) function', lines[52])
+ call assert_match('^\s*1\s\+\d\+\.\d\+\s\+Foo.()$', lines[53])
+ call assert_match('^\s*1\s\+\d\+\.\d\+\s\+Foo.()$', lines[54])
+ call assert_match('^\s*1\s\+\d\+\.\d\+\s\+Foo.()$', lines[55])
+ call assert_equal('', lines[56])
+
+ call delete('Xprofile_func.vim')
+ call delete('Xprofile_func.log')
+endfunc
+
+func Test_profile_func_with_trycatch()
+ let lines = [
+ \ "func! Foo1()",
+ \ " try",
+ \ " let x = 0",
+ \ " catch",
+ \ " let x = 1",
+ \ " finally",
+ \ " let x = 2",
+ \ " endtry",
+ \ "endfunc",
+ \ "func! Foo2()",
+ \ " try",
+ \ " throw 0",
+ \ " catch",
+ \ " let x = 1",
+ \ " finally",
+ \ " let x = 2",
+ \ " endtry",
+ \ "endfunc",
+ \ "func! Foo3()",
+ \ " try",
+ \ " throw 0",
+ \ " catch",
+ \ " throw 1",
+ \ " finally",
+ \ " let x = 2",
+ \ " endtry",
+ \ "endfunc",
+ \ "call Foo1()",
+ \ "call Foo2()",
+ \ "try",
+ \ " call Foo3()",
+ \ "catch",
+ \ "endtry",
+ \ ]
+
+ call writefile(lines, 'Xprofile_func.vim')
+ call system(v:progpath
+ \ . ' -es -u NONE -U NONE -i NONE --noplugin'
+ \ . ' -c "profile start Xprofile_func.log"'
+ \ . ' -c "profile func Foo*"'
+ \ . ' -c "so Xprofile_func.vim"'
+ \ . ' -c "qall!"')
+ call assert_equal(0, v:shell_error)
+
+ let lines = readfile('Xprofile_func.log')
+
+ " - Foo1() should pass 'try' 'finally' blocks.
+ " - Foo2() should pass 'catch' 'finally' blocks.
+ " - Foo3() should not pass 'endtry'.
+ call assert_equal(57, len(lines))
+
+ call assert_equal('FUNCTION Foo1()', lines[0])
+ call assert_match('Defined:.*Xprofile_func.vim', lines[1])
+ call assert_equal('Called 1 time', lines[2])
+ call assert_match('^Total time:\s\+\d\+\.\d\+$', lines[3])
+ call assert_match('^ Self time:\s\+\d\+\.\d\+$', lines[4])
+ call assert_equal('', lines[5])
+ call assert_equal('count total (s) self (s)', lines[6])
+ call assert_match('^\s*1\s\+.*\stry$', lines[7])
+ call assert_match('^\s*1\s\+.*\s let x = 0$', lines[8])
+ call assert_match( '^\s\+catch$', lines[9])
+ call assert_match( '^\s\+let x = 1$', lines[10])
+ call assert_match('^\s*1\s\+.*\sfinally$', lines[11])
+ call assert_match('^\s*1\s\+.*\s let x = 2$', lines[12])
+ call assert_match('^\s*1\s\+.*\sendtry$', lines[13])
+ call assert_equal('', lines[14])
+ call assert_equal('FUNCTION Foo2()', lines[15])
+ call assert_equal('Called 1 time', lines[17])
+ call assert_match('^Total time:\s\+\d\+\.\d\+$', lines[18])
+ call assert_match('^ Self time:\s\+\d\+\.\d\+$', lines[19])
+ call assert_equal('', lines[20])
+ call assert_equal('count total (s) self (s)', lines[21])
+ call assert_match('^\s*1\s\+.*\stry$', lines[22])
+ call assert_match('^\s*1\s\+.*\s throw 0$', lines[23])
+ call assert_match('^\s*1\s\+.*\scatch$', lines[24])
+ call assert_match('^\s*1\s\+.*\s let x = 1$', lines[25])
+ call assert_match('^\s*1\s\+.*\sfinally$', lines[26])
+ call assert_match('^\s*1\s\+.*\s let x = 2$', lines[27])
+ call assert_match('^\s*1\s\+.*\sendtry$', lines[28])
+ call assert_equal('', lines[29])
+ call assert_equal('FUNCTION Foo3()', lines[30])
+ call assert_equal('Called 1 time', lines[32])
+ call assert_match('^Total time:\s\+\d\+\.\d\+$', lines[33])
+ call assert_match('^ Self time:\s\+\d\+\.\d\+$', lines[34])
+ call assert_equal('', lines[35])
+ call assert_equal('count total (s) self (s)', lines[36])
+ call assert_match('^\s*1\s\+.*\stry$', lines[37])
+ call assert_match('^\s*1\s\+.*\s throw 0$', lines[38])
+ call assert_match('^\s*1\s\+.*\scatch$', lines[39])
+ call assert_match('^\s*1\s\+.*\s throw 1$', lines[40])
+ call assert_match('^\s*1\s\+.*\sfinally$', lines[41])
+ call assert_match('^\s*1\s\+.*\s let x = 2$', lines[42])
+ call assert_match( '^\s\+endtry$', lines[43])
+ call assert_equal('', lines[44])
+ call assert_equal('FUNCTIONS SORTED ON TOTAL TIME', lines[45])
+ call assert_equal('count total (s) self (s) function', lines[46])
+ call assert_match('^\s*1\s\+\d\+\.\d\+\s\+Foo.()$', lines[47])
+ call assert_match('^\s*1\s\+\d\+\.\d\+\s\+Foo.()$', lines[48])
+ call assert_match('^\s*1\s\+\d\+\.\d\+\s\+Foo.()$', lines[49])
+ call assert_equal('', lines[50])
+ call assert_equal('FUNCTIONS SORTED ON SELF TIME', lines[51])
+ call assert_equal('count total (s) self (s) function', lines[52])
+ call assert_match('^\s*1\s\+\d\+\.\d\+\s\+Foo.()$', lines[53])
+ call assert_match('^\s*1\s\+\d\+\.\d\+\s\+Foo.()$', lines[54])
+ call assert_match('^\s*1\s\+\d\+\.\d\+\s\+Foo.()$', lines[55])
+ call assert_equal('', lines[56])
+
+ call delete('Xprofile_func.vim')
+ call delete('Xprofile_func.log')
+endfunc
+
+func Test_profile_file()
+ let lines = [
+ \ 'func! Foo()',
+ \ 'endfunc',
+ \ 'for i in range(10)',
+ \ ' " a comment',
+ \ ' call Foo()',
+ \ 'endfor',
+ \ 'call Foo()',
+ \ ]
+
+ call writefile(lines, 'Xprofile_file.vim')
+ call system(v:progpath
+ \ . ' -es --clean'
+ \ . ' -c "profile start Xprofile_file.log"'
+ \ . ' -c "profile file Xprofile_file.vim"'
+ \ . ' -c "so Xprofile_file.vim"'
+ \ . ' -c "so Xprofile_file.vim"'
+ \ . ' -c "qall!"')
+ call assert_equal(0, v:shell_error)
+
+ let lines = readfile('Xprofile_file.log')
+
+ call assert_equal(14, len(lines))
+
+ call assert_match('^SCRIPT .*Xprofile_file.vim$', lines[0])
+ call assert_equal('Sourced 2 times', lines[1])
+ call assert_match('^Total time:\s\+\d\+\.\d\+$', lines[2])
+ call assert_match('^ Self time:\s\+\d\+\.\d\+$', lines[3])
+ call assert_equal('', lines[4])
+ call assert_equal('count total (s) self (s)', lines[5])
+ call assert_match(' 2 0.\d\+ func! Foo()', lines[6])
+ call assert_equal(' endfunc', lines[7])
+ " Loop iterates 10 times. Since script runs twice, body executes 20 times.
+ " First line of loop executes one more time than body to detect end of loop.
+ call assert_match('^\s*22\s\+\d\+\.\d\+\s\+for i in range(10)$', lines[8])
+ call assert_equal(' " a comment', lines[9])
+ " if self and total are equal we only get one number
+ call assert_match('^\s*20\s\+\(\d\+\.\d\+\s\+\)\=\d\+\.\d\+\s\+call Foo()$', lines[10])
+ call assert_match('^\s*22\s\+\d\+\.\d\+\s\+endfor$', lines[11])
+ " if self and total are equal we only get one number
+ call assert_match('^\s*2\s\+\(\d\+\.\d\+\s\+\)\=\d\+\.\d\+\s\+call Foo()$', lines[12])
+ call assert_equal('', lines[13])
+
+ call delete('Xprofile_file.vim')
+ call delete('Xprofile_file.log')
+endfunc
+
+func Test_profile_file_with_cont()
+ let lines = [
+ \ 'echo "hello',
+ \ ' \ world"',
+ \ 'echo "foo ',
+ \ ' \bar"',
+ \ ]
+
+ call writefile(lines, 'Xprofile_file.vim')
+ call system(v:progpath
+ \ . ' -es --clean'
+ \ . ' -c "profile start Xprofile_file.log"'
+ \ . ' -c "profile file Xprofile_file.vim"'
+ \ . ' -c "so Xprofile_file.vim"'
+ \ . ' -c "qall!"')
+ call assert_equal(0, v:shell_error)
+
+ let lines = readfile('Xprofile_file.log')
+ call assert_equal(11, len(lines))
+
+ call assert_match('^SCRIPT .*Xprofile_file.vim$', lines[0])
+ call assert_equal('Sourced 1 time', lines[1])
+ call assert_match('^Total time:\s\+\d\+\.\d\+$', lines[2])
+ call assert_match('^ Self time:\s\+\d\+\.\d\+$', lines[3])
+ call assert_equal('', lines[4])
+ call assert_equal('count total (s) self (s)', lines[5])
+ call assert_match(' 1 0.\d\+ echo "hello', lines[6])
+ call assert_equal(' \ world"', lines[7])
+ call assert_match(' 1 0.\d\+ echo "foo ', lines[8])
+ call assert_equal(' \bar"', lines[9])
+ call assert_equal('', lines[10])
+
+ call delete('Xprofile_file.vim')
+ call delete('Xprofile_file.log')
+endfunc
+
+func Test_profile_completion()
+ call feedkeys(":profile \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"profile continue file func pause start', @:)
+
+ call feedkeys(":profile start test_prof\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_match('^"profile start.* test_profile\.vim', @:)
+endfunc
+
+func Test_profile_errors()
+ call assert_fails("profile func Foo", 'E750:')
+ call assert_fails("profile pause", 'E750:')
+ call assert_fails("profile continue", 'E750:')
+endfunc
+
+func Test_profile_truncate_mbyte()
+ if &enc !=# 'utf-8'
+ return
+ endif
+
+ let lines = [
+ \ 'scriptencoding utf-8',
+ \ 'func! Foo()',
+ \ ' return [',
+ \ ' \ "' . join(map(range(0x4E00, 0x4E00 + 340), 'nr2char(v:val)'), '') . '",',
+ \ ' \ "' . join(map(range(0x4F00, 0x4F00 + 340), 'nr2char(v:val)'), '') . '",',
+ \ ' \ ]',
+ \ 'endfunc',
+ \ 'call Foo()',
+ \ ]
+
+ call writefile(lines, 'Xprofile_file.vim')
+ call system(v:progpath
+ \ . ' -es --clean --cmd "set enc=utf-8"'
+ \ . ' -c "profile start Xprofile_file.log"'
+ \ . ' -c "profile file Xprofile_file.vim"'
+ \ . ' -c "so Xprofile_file.vim"'
+ \ . ' -c "qall!"')
+ call assert_equal(0, v:shell_error)
+
+ split Xprofile_file.log
+ if &fenc != ''
+ call assert_equal('utf-8', &fenc)
+ endif
+ /func! Foo()
+ let lnum = line('.')
+ call assert_match('^\s*return \[$', getline(lnum + 1))
+ call assert_match("\u4F52$", getline(lnum + 2))
+ call assert_match("\u5052$", getline(lnum + 3))
+ call assert_match('^\s*\\ \]$', getline(lnum + 4))
+ bwipe!
+
+ call delete('Xprofile_file.vim')
+ call delete('Xprofile_file.log')
+endfunc
+
+func Test_profdel_func()
+ let lines = [
+ \ 'profile start Xprofile_file.log',
+ \ 'func! Foo1()',
+ \ 'endfunc',
+ \ 'func! Foo2()',
+ \ 'endfunc',
+ \ 'func! Foo3()',
+ \ 'endfunc',
+ \ '',
+ \ 'profile func Foo1',
+ \ 'profile func Foo2',
+ \ 'call Foo1()',
+ \ 'call Foo2()',
+ \ '',
+ \ 'profile func Foo3',
+ \ 'profdel func Foo2',
+ \ 'profdel func Foo3',
+ \ 'call Foo1()',
+ \ 'call Foo2()',
+ \ 'call Foo3()' ]
+ call writefile(lines, 'Xprofile_file.vim')
+ call system(v:progpath . ' -es --clean -c "so Xprofile_file.vim" -c q')
+ call assert_equal(0, v:shell_error)
+
+ let lines = readfile('Xprofile_file.log')
+ call assert_equal(26, len(lines))
+
+ " Check that:
+ " - Foo1() is called twice (profdel not invoked)
+ " - Foo2() is called once (profdel invoked after it was called)
+ " - Foo3() is not called (profdel invoked before it was called)
+ call assert_equal('FUNCTION Foo1()', lines[0])
+ call assert_match('Defined:.*Xprofile_file.vim', lines[1])
+ call assert_equal('Called 2 times', lines[2])
+ call assert_equal('FUNCTION Foo2()', lines[8])
+ call assert_equal('Called 1 time', lines[10])
+ call assert_equal('FUNCTIONS SORTED ON TOTAL TIME', lines[16])
+ call assert_equal('FUNCTIONS SORTED ON SELF TIME', lines[21])
+
+ call delete('Xprofile_file.vim')
+ call delete('Xprofile_file.log')
+endfunc
+
+func Test_profdel_star()
+ " Foo() is invoked once before and once after 'profdel *'.
+ " So profiling should report it only once.
+ let lines = [
+ \ 'profile start Xprofile_file.log',
+ \ 'func! Foo()',
+ \ 'endfunc',
+ \ 'profile func Foo',
+ \ 'call Foo()',
+ \ 'profdel *',
+ \ 'call Foo()' ]
+ call writefile(lines, 'Xprofile_file.vim')
+ call system(v:progpath . ' -es --clean -c "so Xprofile_file.vim" -c q')
+ call assert_equal(0, v:shell_error)
+
+ let lines = readfile('Xprofile_file.log')
+ call assert_equal(16, len(lines))
+
+ call assert_equal('FUNCTION Foo()', lines[0])
+ call assert_match('Defined:.*Xprofile_file.vim', lines[1])
+ call assert_equal('Called 1 time', lines[2])
+ call assert_equal('FUNCTIONS SORTED ON TOTAL TIME', lines[8])
+ call assert_equal('FUNCTIONS SORTED ON SELF TIME', lines[12])
+
+ call delete('Xprofile_file.vim')
+ call delete('Xprofile_file.log')
+endfunc
diff --git a/src/testdir/test_prompt_buffer.vim b/src/testdir/test_prompt_buffer.vim
new file mode 100644
index 0000000..1b8a1ec
--- /dev/null
+++ b/src/testdir/test_prompt_buffer.vim
@@ -0,0 +1,105 @@
+" Tests for setting 'buftype' to "prompt"
+
+if !has('channel')
+ finish
+endif
+
+source shared.vim
+source screendump.vim
+
+func CanTestPromptBuffer()
+ " We need to use a terminal window to be able to feed keys without leaving
+ " Insert mode.
+ if !has('terminal')
+ return 0
+ endif
+ if has('win32')
+ " TODO: make the tests work on MS-Windows
+ return 0
+ endif
+ return 1
+endfunc
+
+func WriteScript(name)
+ call writefile([
+ \ 'func TextEntered(text)',
+ \ ' if a:text == "exit"',
+ \ ' " Reset &modified to allow the buffer to be closed.',
+ \ ' set nomodified',
+ \ ' stopinsert',
+ \ ' close',
+ \ ' else',
+ \ ' " Add the output above the current prompt.',
+ \ ' call append(line("$") - 1, "Command: \"" . a:text . "\"")',
+ \ ' " Reset &modified to allow the buffer to be closed.',
+ \ ' set nomodified',
+ \ ' call timer_start(20, {id -> TimerFunc(a:text)})',
+ \ ' endif',
+ \ 'endfunc',
+ \ '',
+ \ 'func TimerFunc(text)',
+ \ ' " Add the output above the current prompt.',
+ \ ' call append(line("$") - 1, "Result: \"" . a:text . "\"")',
+ \ ' " Reset &modified to allow the buffer to be closed.',
+ \ ' set nomodified',
+ \ 'endfunc',
+ \ '',
+ \ 'call setline(1, "other buffer")',
+ \ 'set nomodified',
+ \ 'new',
+ \ 'set buftype=prompt',
+ \ 'call prompt_setcallback(bufnr(""), function("TextEntered"))',
+ \ 'startinsert',
+ \ ], a:name)
+endfunc
+
+func Test_prompt_basic()
+ if !CanTestPromptBuffer()
+ return
+ endif
+ let scriptName = 'XpromptscriptBasic'
+ call WriteScript(scriptName)
+
+ let buf = RunVimInTerminal('-S ' . scriptName, {})
+ call WaitForAssert({-> assert_equal('%', term_getline(buf, 1))})
+
+ call term_sendkeys(buf, "hello\<CR>")
+ call WaitForAssert({-> assert_equal('% hello', term_getline(buf, 1))})
+ call WaitForAssert({-> assert_equal('Command: "hello"', term_getline(buf, 2))})
+ call WaitForAssert({-> assert_equal('Result: "hello"', term_getline(buf, 3))})
+
+ call term_sendkeys(buf, "exit\<CR>")
+ call WaitForAssert({-> assert_equal('other buffer', term_getline(buf, 1))})
+
+ call StopVimInTerminal(buf)
+ call delete(scriptName)
+endfunc
+
+func Test_prompt_editing()
+ if !CanTestPromptBuffer()
+ return
+ endif
+ let scriptName = 'XpromptscriptEditing'
+ call WriteScript(scriptName)
+
+ let buf = RunVimInTerminal('-S ' . scriptName, {})
+ call WaitForAssert({-> assert_equal('%', term_getline(buf, 1))})
+
+ let bs = "\<BS>"
+ call term_sendkeys(buf, "hello" . bs . bs)
+ call WaitForAssert({-> assert_equal('% hel', term_getline(buf, 1))})
+
+ let left = "\<Left>"
+ call term_sendkeys(buf, left . left . left . bs . '-')
+ call WaitForAssert({-> assert_equal('% -hel', term_getline(buf, 1))})
+
+ let end = "\<End>"
+ call term_sendkeys(buf, end . "x")
+ call WaitForAssert({-> assert_equal('% -helx', term_getline(buf, 1))})
+
+ call term_sendkeys(buf, "\<C-U>exit\<CR>")
+ call WaitForAssert({-> assert_equal('other buffer', term_getline(buf, 1))})
+
+ call StopVimInTerminal(buf)
+ call delete(scriptName)
+endfunc
diff --git a/src/testdir/test_put.vim b/src/testdir/test_put.vim
new file mode 100644
index 0000000..2a9e8a3
--- /dev/null
+++ b/src/testdir/test_put.vim
@@ -0,0 +1,103 @@
+" Tests for put commands, e.g. ":put", "p", "gp", "P", "gP", etc.
+
+func Test_put_block()
+ new
+ call feedkeys("i\<C-V>u2500\<CR>x\<ESC>", 'x')
+ call feedkeys("\<C-V>y", 'x')
+ call feedkeys("gg0p", 'x')
+ call assert_equal("\u2500x", getline(1))
+ bwipe!
+endfunc
+
+func Test_put_char_block()
+ new
+ call setline(1, ['Line 1', 'Line 2'])
+ f Xfile_put
+ " visually select both lines and put the cursor at the top of the visual
+ " selection and then put the buffer name over it
+ exe "norm! G0\<c-v>ke\"%p"
+ call assert_equal(['Xfile_put 1', 'Xfile_put 2'], getline(1,2))
+ bw!
+endfunc
+
+func Test_put_char_block2()
+ new
+ let a = [ getreg('a'), getregtype('a') ]
+ call setreg('a', ' one ', 'v')
+ call setline(1, ['Line 1', '', 'Line 3', ''])
+ " visually select the first 3 lines and put register a over it
+ exe "norm! ggl\<c-v>2j2l\"ap"
+ call assert_equal(['L one 1', '', 'L one 3', ''], getline(1,4))
+ " clean up
+ bw!
+ call setreg('a', a[0], a[1])
+endfunc
+
+func Test_put_lines()
+ new
+ let a = [ getreg('a'), getregtype('a') ]
+ call setline(1, ['Line 1', 'Line2', 'Line 3', ''])
+ exe 'norm! gg"add"AddG""p'
+ call assert_equal(['Line 3', '', 'Line 1', 'Line2'], getline(1,'$'))
+ " clean up
+ bw!
+ call setreg('a', a[0], a[1])
+endfunc
+
+func Test_put_expr()
+ new
+ call setline(1, repeat(['A'], 6))
+ exec "1norm! \"=line('.')\<cr>p"
+ norm! j0.
+ norm! j0.
+ exec "4norm! \"=\<cr>P"
+ norm! j0.
+ norm! j0.
+ call assert_equal(['A1','A2','A3','4A','5A','6A'], getline(1,'$'))
+ bw!
+endfunc
+
+func Test_put_fails_when_nomodifiable()
+ new
+ setlocal nomodifiable
+
+ normal! yy
+ call assert_fails(':put', 'E21')
+ call assert_fails(':put!', 'E21')
+ call assert_fails(':normal! p', 'E21')
+ call assert_fails(':normal! gp', 'E21')
+ call assert_fails(':normal! P', 'E21')
+ call assert_fails(':normal! gP', 'E21')
+
+ if has('mouse')
+ set mouse=n
+ call assert_fails('execute "normal! \<MiddleMouse>"', 'E21')
+ set mouse&
+ endif
+
+ bwipeout!
+endfunc
+
+" A bug was discovered where the Normal mode put commands (e.g., "p") would
+" output duplicate error messages when invoked in a non-modifiable buffer.
+func Test_put_p_errmsg_nodup()
+ new
+ setlocal nomodifiable
+
+ normal! yy
+
+ func Capture_p_error()
+ redir => s:p_err
+ normal! p
+ redir END
+ endfunc
+
+ silent! call Capture_p_error()
+
+ " Error message output within a function should be three lines (the function
+ " name, the line number, and the error message).
+ call assert_equal(3, count(s:p_err, "\n"))
+
+ delfunction Capture_p_error
+ bwipeout!
+endfunc
diff --git a/src/testdir/test_python2.vim b/src/testdir/test_python2.vim
new file mode 100644
index 0000000..d79400d
--- /dev/null
+++ b/src/testdir/test_python2.vim
@@ -0,0 +1,65 @@
+" Test for python 2 commands.
+" TODO: move tests from test87.in here.
+
+if !has('python')
+ finish
+endif
+
+func Test_pydo()
+ " Check deleting lines does not trigger ml_get error.
+ py import vim
+ new
+ call setline(1, ['one', 'two', 'three'])
+ pydo vim.command("%d_")
+ bwipe!
+
+ " Check switching to another buffer does not trigger ml_get error.
+ new
+ let wincount = winnr('$')
+ call setline(1, ['one', 'two', 'three'])
+ pydo vim.command("new")
+ call assert_equal(wincount + 1, winnr('$'))
+ bwipe!
+ bwipe!
+endfunc
+
+func Test_set_cursor()
+ " Check that setting the cursor position works.
+ py import vim
+ new
+ call setline(1, ['first line', 'second line'])
+ normal gg
+ pydo vim.current.window.cursor = (1, 5)
+ call assert_equal([1, 6], [line('.'), col('.')])
+
+ " Check that movement after setting cursor position keeps current column.
+ normal j
+ call assert_equal([2, 6], [line('.'), col('.')])
+endfunc
+
+func Test_vim_function()
+ " Check creating vim.Function object
+ py import vim
+
+ func s:foo()
+ return matchstr(expand('<sfile>'), '<SNR>\zs\d\+_foo$')
+ endfunc
+ let name = '<SNR>' . s:foo()
+
+ try
+ py f = vim.bindeval('function("s:foo")')
+ call assert_equal(name, pyeval('f.name'))
+ catch
+ call assert_false(v:exception)
+ endtry
+
+ try
+ py f = vim.Function('\x80\xfdR' + vim.eval('s:foo()'))
+ call assert_equal(name, pyeval('f.name'))
+ catch
+ call assert_false(v:exception)
+ endtry
+
+ py del f
+ delfunc s:foo
+endfunc
diff --git a/src/testdir/test_python3.vim b/src/testdir/test_python3.vim
new file mode 100644
index 0000000..344034a
--- /dev/null
+++ b/src/testdir/test_python3.vim
@@ -0,0 +1,65 @@
+" Test for python 3 commands.
+" TODO: move tests from test88.in here.
+
+if !has('python3')
+ finish
+endif
+
+func Test_py3do()
+ " Check deleting lines does not trigger an ml_get error.
+ py3 import vim
+ new
+ call setline(1, ['one', 'two', 'three'])
+ py3do vim.command("%d_")
+ bwipe!
+
+ " Check switching to another buffer does not trigger an ml_get error.
+ new
+ let wincount = winnr('$')
+ call setline(1, ['one', 'two', 'three'])
+ py3do vim.command("new")
+ call assert_equal(wincount + 1, winnr('$'))
+ bwipe!
+ bwipe!
+endfunc
+
+func Test_set_cursor()
+ " Check that setting the cursor position works.
+ py3 import vim
+ new
+ call setline(1, ['first line', 'second line'])
+ normal gg
+ py3do vim.current.window.cursor = (1, 5)
+ call assert_equal([1, 6], [line('.'), col('.')])
+
+ " Check that movement after setting cursor position keeps current column.
+ normal j
+ call assert_equal([2, 6], [line('.'), col('.')])
+endfunc
+
+func Test_vim_function()
+ " Check creating vim.Function object
+ py3 import vim
+
+ func s:foo()
+ return matchstr(expand('<sfile>'), '<SNR>\zs\d\+_foo$')
+ endfunc
+ let name = '<SNR>' . s:foo()
+
+ try
+ py3 f = vim.bindeval('function("s:foo")')
+ call assert_equal(name, py3eval('f.name'))
+ catch
+ call assert_false(v:exception)
+ endtry
+
+ try
+ py3 f = vim.Function(b'\x80\xfdR' + vim.eval('s:foo()').encode())
+ call assert_equal(name, py3eval('f.name'))
+ catch
+ call assert_false(v:exception)
+ endtry
+
+ py3 del f
+ delfunc s:foo
+endfunc
diff --git a/src/testdir/test_pyx2.vim b/src/testdir/test_pyx2.vim
new file mode 100644
index 0000000..50e57c3
--- /dev/null
+++ b/src/testdir/test_pyx2.vim
@@ -0,0 +1,74 @@
+" Test for pyx* commands and functions with Python 2.
+
+set pyx=2
+if !has('python')
+ finish
+endif
+
+let s:py2pattern = '^2\.[0-7]\.\d\+'
+let s:py3pattern = '^3\.\d\+\.\d\+'
+
+
+func Test_has_pythonx()
+ call assert_true(has('pythonx'))
+endfunc
+
+
+func Test_pyx()
+ redir => var
+ pyx << EOF
+import sys
+print(sys.version)
+EOF
+ redir END
+ call assert_match(s:py2pattern, split(var)[0])
+endfunc
+
+
+func Test_pyxdo()
+ pyx import sys
+ enew
+ pyxdo return sys.version.split("\n")[0]
+ call assert_match(s:py2pattern, split(getline('.'))[0])
+endfunc
+
+
+func Test_pyxeval()
+ pyx import sys
+ call assert_match(s:py2pattern, split(pyxeval('sys.version'))[0])
+endfunc
+
+
+func Test_pyxfile()
+ " No special comments nor shebangs
+ redir => var
+ pyxfile pyxfile/pyx.py
+ redir END
+ call assert_match(s:py2pattern, split(var)[0])
+
+ " Python 2 special comment
+ redir => var
+ pyxfile pyxfile/py2_magic.py
+ redir END
+ call assert_match(s:py2pattern, split(var)[0])
+
+ " Python 2 shebang
+ redir => var
+ pyxfile pyxfile/py2_shebang.py
+ redir END
+ call assert_match(s:py2pattern, split(var)[0])
+
+ if has('python3')
+ " Python 3 special comment
+ redir => var
+ pyxfile pyxfile/py3_magic.py
+ redir END
+ call assert_match(s:py3pattern, split(var)[0])
+
+ " Python 3 shebang
+ redir => var
+ pyxfile pyxfile/py3_shebang.py
+ redir END
+ call assert_match(s:py3pattern, split(var)[0])
+ endif
+endfunc
diff --git a/src/testdir/test_pyx3.vim b/src/testdir/test_pyx3.vim
new file mode 100644
index 0000000..64546b4
--- /dev/null
+++ b/src/testdir/test_pyx3.vim
@@ -0,0 +1,74 @@
+" Test for pyx* commands and functions with Python 3.
+
+set pyx=3
+if !has('python3')
+ finish
+endif
+
+let s:py2pattern = '^2\.[0-7]\.\d\+'
+let s:py3pattern = '^3\.\d\+\.\d\+'
+
+
+func Test_has_pythonx()
+ call assert_true(has('pythonx'))
+endfunc
+
+
+func Test_pyx()
+ redir => var
+ pyx << EOF
+import sys
+print(sys.version)
+EOF
+ redir END
+ call assert_match(s:py3pattern, split(var)[0])
+endfunc
+
+
+func Test_pyxdo()
+ pyx import sys
+ enew
+ pyxdo return sys.version.split("\n")[0]
+ call assert_match(s:py3pattern, split(getline('.'))[0])
+endfunc
+
+
+func Test_pyxeval()
+ pyx import sys
+ call assert_match(s:py3pattern, split(pyxeval('sys.version'))[0])
+endfunc
+
+
+func Test_pyxfile()
+ " No special comments nor shebangs
+ redir => var
+ pyxfile pyxfile/pyx.py
+ redir END
+ call assert_match(s:py3pattern, split(var)[0])
+
+ " Python 3 special comment
+ redir => var
+ pyxfile pyxfile/py3_magic.py
+ redir END
+ call assert_match(s:py3pattern, split(var)[0])
+
+ " Python 3 shebang
+ redir => var
+ pyxfile pyxfile/py3_shebang.py
+ redir END
+ call assert_match(s:py3pattern, split(var)[0])
+
+ if has('python')
+ " Python 2 special comment
+ redir => var
+ pyxfile pyxfile/py2_magic.py
+ redir END
+ call assert_match(s:py2pattern, split(var)[0])
+
+ " Python 2 shebang
+ redir => var
+ pyxfile pyxfile/py2_shebang.py
+ redir END
+ call assert_match(s:py2pattern, split(var)[0])
+ endif
+endfunc
diff --git a/src/testdir/test_quickfix.vim b/src/testdir/test_quickfix.vim
new file mode 100644
index 0000000..e7aa41e
--- /dev/null
+++ b/src/testdir/test_quickfix.vim
@@ -0,0 +1,3901 @@
+" Test for the quickfix commands.
+
+if !has('quickfix')
+ finish
+endif
+
+set encoding=utf-8
+
+func s:setup_commands(cchar)
+ if a:cchar == 'c'
+ command! -nargs=* -bang Xlist <mods>clist<bang> <args>
+ command! -nargs=* Xgetexpr <mods>cgetexpr <args>
+ command! -nargs=* Xaddexpr <mods>caddexpr <args>
+ command! -nargs=* -count Xolder <mods><count>colder <args>
+ command! -nargs=* Xnewer <mods>cnewer <args>
+ command! -nargs=* Xopen <mods>copen <args>
+ command! -nargs=* Xwindow <mods>cwindow <args>
+ command! -nargs=* Xbottom <mods>cbottom <args>
+ command! -nargs=* Xclose <mods>cclose <args>
+ command! -nargs=* -bang Xfile <mods>cfile<bang> <args>
+ command! -nargs=* Xgetfile <mods>cgetfile <args>
+ command! -nargs=* Xaddfile <mods>caddfile <args>
+ command! -nargs=* -bang Xbuffer <mods>cbuffer<bang> <args>
+ command! -nargs=* Xgetbuffer <mods>cgetbuffer <args>
+ command! -nargs=* Xaddbuffer <mods>caddbuffer <args>
+ command! -nargs=* Xrewind <mods>crewind <args>
+ command! -count -nargs=* -bang Xnext <mods><count>cnext<bang> <args>
+ command! -count -nargs=* -bang Xprev <mods><count>cprev<bang> <args>
+ command! -nargs=* -bang Xfirst <mods>cfirst<bang> <args>
+ command! -nargs=* -bang Xlast <mods>clast<bang> <args>
+ command! -nargs=* -bang -range Xnfile <mods><count>cnfile<bang> <args>
+ command! -nargs=* -bang Xpfile <mods>cpfile<bang> <args>
+ command! -nargs=* Xexpr <mods>cexpr <args>
+ command! -range -nargs=* Xvimgrep <mods><count>vimgrep <args>
+ command! -nargs=* Xvimgrepadd <mods>vimgrepadd <args>
+ command! -nargs=* Xgrep <mods> grep <args>
+ command! -nargs=* Xgrepadd <mods> grepadd <args>
+ command! -nargs=* Xhelpgrep helpgrep <args>
+ command! -nargs=0 -count Xcc <count>cc
+ let g:Xgetlist = function('getqflist')
+ let g:Xsetlist = function('setqflist')
+ call setqflist([], 'f')
+ else
+ command! -nargs=* -bang Xlist <mods>llist<bang> <args>
+ command! -nargs=* Xgetexpr <mods>lgetexpr <args>
+ command! -nargs=* Xaddexpr <mods>laddexpr <args>
+ command! -nargs=* -count Xolder <mods><count>lolder <args>
+ command! -nargs=* Xnewer <mods>lnewer <args>
+ command! -nargs=* Xopen <mods>lopen <args>
+ command! -nargs=* Xwindow <mods>lwindow <args>
+ command! -nargs=* Xbottom <mods>lbottom <args>
+ command! -nargs=* Xclose <mods>lclose <args>
+ command! -nargs=* -bang Xfile <mods>lfile<bang> <args>
+ command! -nargs=* Xgetfile <mods>lgetfile <args>
+ command! -nargs=* Xaddfile <mods>laddfile <args>
+ command! -nargs=* -bang Xbuffer <mods>lbuffer<bang> <args>
+ command! -nargs=* Xgetbuffer <mods>lgetbuffer <args>
+ command! -nargs=* Xaddbuffer <mods>laddbuffer <args>
+ command! -nargs=* Xrewind <mods>lrewind <args>
+ command! -count -nargs=* -bang Xnext <mods><count>lnext<bang> <args>
+ command! -count -nargs=* -bang Xprev <mods><count>lprev<bang> <args>
+ command! -nargs=* -bang Xfirst <mods>lfirst<bang> <args>
+ command! -nargs=* -bang Xlast <mods>llast<bang> <args>
+ command! -nargs=* -bang -range Xnfile <mods><count>lnfile<bang> <args>
+ command! -nargs=* -bang Xpfile <mods>lpfile<bang> <args>
+ command! -nargs=* Xexpr <mods>lexpr <args>
+ command! -range -nargs=* Xvimgrep <mods><count>lvimgrep <args>
+ command! -nargs=* Xvimgrepadd <mods>lvimgrepadd <args>
+ command! -nargs=* Xgrep <mods> lgrep <args>
+ command! -nargs=* Xgrepadd <mods> lgrepadd <args>
+ command! -nargs=* Xhelpgrep lhelpgrep <args>
+ command! -nargs=0 -count Xcc <count>ll
+ let g:Xgetlist = function('getloclist', [0])
+ let g:Xsetlist = function('setloclist', [0])
+ call setloclist(0, [], 'f')
+ endif
+endfunc
+
+" Tests for the :clist and :llist commands
+func XlistTests(cchar)
+ call s:setup_commands(a:cchar)
+
+ if a:cchar == 'l'
+ call assert_fails('llist', 'E776:')
+ endif
+ " With an empty list, command should return error
+ Xgetexpr []
+ silent! Xlist
+ call assert_true(v:errmsg ==# 'E42: No Errors')
+
+ " Populate the list and then try
+ Xgetexpr ['non-error 1', 'Xtestfile1:1:3:Line1',
+ \ 'non-error 2', 'Xtestfile2:2:2:Line2',
+ \ 'non-error 3', 'Xtestfile3:3:1:Line3']
+
+ " List only valid entries
+ let l = split(execute('Xlist', ''), "\n")
+ call assert_equal([' 2 Xtestfile1:1 col 3: Line1',
+ \ ' 4 Xtestfile2:2 col 2: Line2',
+ \ ' 6 Xtestfile3:3 col 1: Line3'], l)
+
+ " List all the entries
+ let l = split(execute('Xlist!', ''), "\n")
+ call assert_equal([' 1: non-error 1', ' 2 Xtestfile1:1 col 3: Line1',
+ \ ' 3: non-error 2', ' 4 Xtestfile2:2 col 2: Line2',
+ \ ' 5: non-error 3', ' 6 Xtestfile3:3 col 1: Line3'], l)
+
+ " List a range of errors
+ let l = split(execute('Xlist 3,6', ''), "\n")
+ call assert_equal([' 4 Xtestfile2:2 col 2: Line2',
+ \ ' 6 Xtestfile3:3 col 1: Line3'], l)
+
+ let l = split(execute('Xlist! 3,4', ''), "\n")
+ call assert_equal([' 3: non-error 2', ' 4 Xtestfile2:2 col 2: Line2'], l)
+
+ let l = split(execute('Xlist -6,-4', ''), "\n")
+ call assert_equal([' 2 Xtestfile1:1 col 3: Line1'], l)
+
+ let l = split(execute('Xlist! -5,-3', ''), "\n")
+ call assert_equal([' 2 Xtestfile1:1 col 3: Line1',
+ \ ' 3: non-error 2', ' 4 Xtestfile2:2 col 2: Line2'], l)
+
+ " Test for '+'
+ let l = split(execute('Xlist! +2', ''), "\n")
+ call assert_equal([' 2 Xtestfile1:1 col 3: Line1',
+ \ ' 3: non-error 2', ' 4 Xtestfile2:2 col 2: Line2'], l)
+
+ " Different types of errors
+ call g:Xsetlist([{'lnum':10,'col':5,'type':'W', 'text':'Warning','nr':11},
+ \ {'lnum':20,'col':10,'type':'e','text':'Error','nr':22},
+ \ {'lnum':30,'col':15,'type':'i','text':'Info','nr':33},
+ \ {'lnum':40,'col':20,'type':'x', 'text':'Other','nr':44},
+ \ {'lnum':50,'col':25,'type':"\<C-A>",'text':'one','nr':55}])
+ let l = split(execute('Xlist', ""), "\n")
+ call assert_equal([' 1:10 col 5 warning 11: Warning',
+ \ ' 2:20 col 10 error 22: Error',
+ \ ' 3:30 col 15 info 33: Info',
+ \ ' 4:40 col 20 x 44: Other',
+ \ ' 5:50 col 25 55: one'], l)
+
+ " Test for module names, one needs to explicitly set `'valid':v:true` so
+ call g:Xsetlist([
+ \ {'lnum':10,'col':5,'type':'W','module':'Data.Text','text':'ModuleWarning','nr':11,'valid':v:true},
+ \ {'lnum':20,'col':10,'type':'W','module':'Data.Text','filename':'Data/Text.hs','text':'ModuleWarning','nr':22,'valid':v:true},
+ \ {'lnum':30,'col':15,'type':'W','filename':'Data/Text.hs','text':'FileWarning','nr':33,'valid':v:true}])
+ let l = split(execute('Xlist', ""), "\n")
+ call assert_equal([' 1 Data.Text:10 col 5 warning 11: ModuleWarning',
+ \ ' 2 Data.Text:20 col 10 warning 22: ModuleWarning',
+ \ ' 3 Data/Text.hs:30 col 15 warning 33: FileWarning'], l)
+
+ " Error cases
+ call assert_fails('Xlist abc', 'E488:')
+endfunc
+
+func Test_clist()
+ call XlistTests('c')
+ call XlistTests('l')
+endfunc
+
+" Tests for the :colder, :cnewer, :lolder and :lnewer commands
+" Note that this test assumes that a quickfix/location list is
+" already set by the caller.
+func XageTests(cchar)
+ call s:setup_commands(a:cchar)
+
+ let list = [{'bufnr': bufnr('%'), 'lnum': 1}]
+ call g:Xsetlist(list)
+
+ " Jumping to a non existent list should return error
+ silent! Xolder 99
+ call assert_true(v:errmsg ==# 'E380: At bottom of quickfix stack')
+
+ silent! Xnewer 99
+ call assert_true(v:errmsg ==# 'E381: At top of quickfix stack')
+
+ " Add three quickfix/location lists
+ Xgetexpr ['Xtestfile1:1:3:Line1']
+ Xgetexpr ['Xtestfile2:2:2:Line2']
+ Xgetexpr ['Xtestfile3:3:1:Line3']
+
+ " Go back two lists
+ Xolder
+ let l = g:Xgetlist()
+ call assert_equal('Line2', l[0].text)
+
+ " Go forward two lists
+ Xnewer
+ let l = g:Xgetlist()
+ call assert_equal('Line3', l[0].text)
+
+ " Test for the optional count argument
+ Xolder 2
+ let l = g:Xgetlist()
+ call assert_equal('Line1', l[0].text)
+
+ Xnewer 2
+ let l = g:Xgetlist()
+ call assert_equal('Line3', l[0].text)
+endfunc
+
+func Test_cage()
+ call XageTests('c')
+ call XageTests('l')
+endfunc
+
+" Tests for the :cwindow, :lwindow :cclose, :lclose, :copen and :lopen
+" commands
+func XwindowTests(cchar)
+ call s:setup_commands(a:cchar)
+
+ " Opening the location list window without any errors should fail
+ if a:cchar == 'l'
+ call assert_fails('lopen', 'E776:')
+ endif
+
+ " Create a list with no valid entries
+ Xgetexpr ['non-error 1', 'non-error 2', 'non-error 3']
+
+ " Quickfix/Location window should not open with no valid errors
+ Xwindow
+ call assert_true(winnr('$') == 1)
+
+ " Create a list with valid entries
+ Xgetexpr ['Xtestfile1:1:3:Line1', 'Xtestfile2:2:2:Line2',
+ \ 'Xtestfile3:3:1:Line3']
+
+ " Open the window
+ Xwindow
+ call assert_true(winnr('$') == 2 && winnr() == 2 &&
+ \ getline('.') ==# 'Xtestfile1|1 col 3| Line1')
+ redraw!
+
+ " Close the window
+ Xclose
+ call assert_true(winnr('$') == 1)
+
+ " Create a list with no valid entries
+ Xgetexpr ['non-error 1', 'non-error 2', 'non-error 3']
+
+ " Open the window
+ Xopen 5
+ call assert_true(winnr('$') == 2 && getline('.') ==# '|| non-error 1'
+ \ && winheight('.') == 5)
+
+ " Opening the window again, should move the cursor to that window
+ wincmd t
+ Xopen 7
+ call assert_true(winnr('$') == 2 && winnr() == 2 &&
+ \ winheight('.') == 7 &&
+ \ getline('.') ==# '|| non-error 1')
+
+
+ " Calling cwindow should close the quickfix window with no valid errors
+ Xwindow
+ call assert_true(winnr('$') == 1)
+
+ if a:cchar == 'c'
+ " Opening the quickfix window in multiple tab pages should reuse the
+ " quickfix buffer
+ Xgetexpr ['Xtestfile1:1:3:Line1', 'Xtestfile2:2:2:Line2',
+ \ 'Xtestfile3:3:1:Line3']
+ Xopen
+ let qfbufnum = bufnr('%')
+ tabnew
+ Xopen
+ call assert_equal(qfbufnum, bufnr('%'))
+ new | only | tabonly
+ endif
+endfunc
+
+func Test_cwindow()
+ call XwindowTests('c')
+ call XwindowTests('l')
+endfunc
+
+" Tests for the :cfile, :lfile, :caddfile, :laddfile, :cgetfile and :lgetfile
+" commands.
+func XfileTests(cchar)
+ call s:setup_commands(a:cchar)
+
+ call writefile(['Xtestfile1:700:10:Line 700',
+ \ 'Xtestfile2:800:15:Line 800'], 'Xqftestfile1')
+
+ enew!
+ Xfile Xqftestfile1
+ let l = g:Xgetlist()
+ call assert_true(len(l) == 2 &&
+ \ l[0].lnum == 700 && l[0].col == 10 && l[0].text ==# 'Line 700' &&
+ \ l[1].lnum == 800 && l[1].col == 15 && l[1].text ==# 'Line 800')
+
+ " Test with a non existent file
+ call assert_fails('Xfile non_existent_file', 'E40')
+
+ " Run cfile/lfile from a modified buffer
+ enew!
+ silent! put ='Quickfix'
+ silent! Xfile Xqftestfile1
+ call assert_true(v:errmsg ==# 'E37: No write since last change (add ! to override)')
+
+ call writefile(['Xtestfile3:900:30:Line 900'], 'Xqftestfile1')
+ Xaddfile Xqftestfile1
+ let l = g:Xgetlist()
+ call assert_true(len(l) == 3 &&
+ \ l[2].lnum == 900 && l[2].col == 30 && l[2].text ==# 'Line 900')
+
+ call writefile(['Xtestfile1:222:77:Line 222',
+ \ 'Xtestfile2:333:88:Line 333'], 'Xqftestfile1')
+
+ enew!
+ Xgetfile Xqftestfile1
+ let l = g:Xgetlist()
+ call assert_true(len(l) == 2 &&
+ \ l[0].lnum == 222 && l[0].col == 77 && l[0].text ==# 'Line 222' &&
+ \ l[1].lnum == 333 && l[1].col == 88 && l[1].text ==# 'Line 333')
+
+ call delete('Xqftestfile1')
+endfunc
+
+func Test_cfile()
+ call XfileTests('c')
+ call XfileTests('l')
+endfunc
+
+" Tests for the :cbuffer, :lbuffer, :caddbuffer, :laddbuffer, :cgetbuffer and
+" :lgetbuffer commands.
+func XbufferTests(cchar)
+ call s:setup_commands(a:cchar)
+
+ enew!
+ silent! call setline(1, ['Xtestfile7:700:10:Line 700',
+ \ 'Xtestfile8:800:15:Line 800'])
+ Xbuffer!
+ let l = g:Xgetlist()
+ call assert_true(len(l) == 2 &&
+ \ l[0].lnum == 700 && l[0].col == 10 && l[0].text ==# 'Line 700' &&
+ \ l[1].lnum == 800 && l[1].col == 15 && l[1].text ==# 'Line 800')
+
+ enew!
+ silent! call setline(1, ['Xtestfile9:900:55:Line 900',
+ \ 'Xtestfile10:950:66:Line 950'])
+ Xgetbuffer
+ let l = g:Xgetlist()
+ call assert_true(len(l) == 2 &&
+ \ l[0].lnum == 900 && l[0].col == 55 && l[0].text ==# 'Line 900' &&
+ \ l[1].lnum == 950 && l[1].col == 66 && l[1].text ==# 'Line 950')
+
+ enew!
+ silent! call setline(1, ['Xtestfile11:700:20:Line 700',
+ \ 'Xtestfile12:750:25:Line 750'])
+ Xaddbuffer
+ let l = g:Xgetlist()
+ call assert_true(len(l) == 4 &&
+ \ l[1].lnum == 950 && l[1].col == 66 && l[1].text ==# 'Line 950' &&
+ \ l[2].lnum == 700 && l[2].col == 20 && l[2].text ==# 'Line 700' &&
+ \ l[3].lnum == 750 && l[3].col == 25 && l[3].text ==# 'Line 750')
+ enew!
+
+ " Check for invalid buffer
+ call assert_fails('Xbuffer 199', 'E474:')
+
+ " Check for unloaded buffer
+ edit Xtestfile1
+ let bnr = bufnr('%')
+ enew!
+ call assert_fails('Xbuffer ' . bnr, 'E681:')
+
+ " Check for invalid range
+ " Using Xbuffer will not run the range check in the cbuffer/lbuffer
+ " commands. So directly call the commands.
+ if (a:cchar == 'c')
+ call assert_fails('900,999cbuffer', 'E16:')
+ else
+ call assert_fails('900,999lbuffer', 'E16:')
+ endif
+endfunc
+
+func Test_cbuffer()
+ call XbufferTests('c')
+ call XbufferTests('l')
+endfunc
+
+func XexprTests(cchar)
+ call s:setup_commands(a:cchar)
+
+ call assert_fails('Xexpr 10', 'E777:')
+endfunc
+
+func Test_cexpr()
+ call XexprTests('c')
+ call XexprTests('l')
+endfunc
+
+" Tests for :cnext, :cprev, :cfirst, :clast commands
+func Xtest_browse(cchar)
+ call s:setup_commands(a:cchar)
+
+ call g:Xsetlist([], 'f')
+ " Jumping to first or next location list entry without any error should
+ " result in failure
+ if a:cchar == 'c'
+ let err = 'E42:'
+ else
+ let err = 'E776:'
+ endif
+ call assert_fails('Xnext', err)
+ call assert_fails('Xprev', err)
+ call assert_fails('Xnfile', err)
+ call assert_fails('Xpfile', err)
+
+ call s:create_test_file('Xqftestfile1')
+ call s:create_test_file('Xqftestfile2')
+
+ Xgetexpr ['Xqftestfile1:5:Line5',
+ \ 'Xqftestfile1:6:Line6',
+ \ 'Xqftestfile2:10:Line10',
+ \ 'Xqftestfile2:11:Line11',
+ \ 'RegularLine1',
+ \ 'RegularLine2']
+
+ Xfirst
+ call assert_fails('Xprev', 'E553')
+ call assert_fails('Xpfile', 'E553')
+ Xnfile
+ call assert_equal('Xqftestfile2', bufname('%'))
+ call assert_equal(10, line('.'))
+ Xpfile
+ call assert_equal('Xqftestfile1', bufname('%'))
+ call assert_equal(6, line('.'))
+ 5Xcc
+ call assert_equal(5, g:Xgetlist({'idx':0}).idx)
+ 2Xcc
+ call assert_equal(2, g:Xgetlist({'idx':0}).idx)
+ 10Xcc
+ call assert_equal(6, g:Xgetlist({'idx':0}).idx)
+ Xlast
+ Xprev
+ call assert_equal('Xqftestfile2', bufname('%'))
+ call assert_equal(11, line('.'))
+ call assert_fails('Xnext', 'E553')
+ call assert_fails('Xnfile', 'E553')
+ Xrewind
+ call assert_equal('Xqftestfile1', bufname('%'))
+ call assert_equal(5, line('.'))
+
+ 10Xnext
+ call assert_equal('Xqftestfile2', bufname('%'))
+ call assert_equal(11, line('.'))
+ 10Xprev
+ call assert_equal('Xqftestfile1', bufname('%'))
+ call assert_equal(5, line('.'))
+
+ " Jumping to an error from the error window using cc command
+ Xgetexpr ['Xqftestfile1:5:Line5',
+ \ 'Xqftestfile1:6:Line6',
+ \ 'Xqftestfile2:10:Line10',
+ \ 'Xqftestfile2:11:Line11']
+ Xopen
+ 10Xcc
+ call assert_equal(11, line('.'))
+ call assert_equal('Xqftestfile2', bufname('%'))
+
+ " Jumping to an error from the error window (when only the error window is
+ " present)
+ Xopen | only
+ Xlast 1
+ call assert_equal(5, line('.'))
+ call assert_equal('Xqftestfile1', bufname('%'))
+
+ Xexpr ""
+ call assert_fails('Xnext', 'E42:')
+
+ call delete('Xqftestfile1')
+ call delete('Xqftestfile2')
+
+ " Should be able to use next/prev with invalid entries
+ Xexpr ""
+ call assert_equal(0, g:Xgetlist({'idx' : 0}).idx)
+ call assert_equal(0, g:Xgetlist({'size' : 0}).size)
+ Xaddexpr ['foo', 'bar', 'baz', 'quux', 'shmoo']
+ call assert_equal(5, g:Xgetlist({'size' : 0}).size)
+ Xlast
+ call assert_equal(5, g:Xgetlist({'idx' : 0}).idx)
+ Xfirst
+ call assert_equal(1, g:Xgetlist({'idx' : 0}).idx)
+ 2Xnext
+ call assert_equal(3, g:Xgetlist({'idx' : 0}).idx)
+endfunc
+
+func Test_browse()
+ call Xtest_browse('c')
+ call Xtest_browse('l')
+endfunc
+
+func Test_nomem()
+ call test_alloc_fail(GetAllocId('qf_dirname_start'), 0, 0)
+ call assert_fails('vimgrep vim runtest.vim', 'E342:')
+
+ call test_alloc_fail(GetAllocId('qf_dirname_now'), 0, 0)
+ call assert_fails('vimgrep vim runtest.vim', 'E342:')
+
+ call test_alloc_fail(GetAllocId('qf_namebuf'), 0, 0)
+ call assert_fails('cfile runtest.vim', 'E342:')
+
+ call test_alloc_fail(GetAllocId('qf_errmsg'), 0, 0)
+ call assert_fails('cfile runtest.vim', 'E342:')
+
+ call test_alloc_fail(GetAllocId('qf_pattern'), 0, 0)
+ call assert_fails('cfile runtest.vim', 'E342:')
+
+endfunc
+
+func s:test_xhelpgrep(cchar)
+ call s:setup_commands(a:cchar)
+ Xhelpgrep quickfix
+ Xopen
+ if a:cchar == 'c'
+ let title_text = ':helpgrep quickfix'
+ else
+ let title_text = ':lhelpgrep quickfix'
+ endif
+ call assert_true(w:quickfix_title =~ title_text, w:quickfix_title)
+
+ " Jumping to a help topic should open the help window
+ only
+ Xnext
+ call assert_true(&buftype == 'help')
+ call assert_true(winnr('$') == 2)
+ " Jumping to the next match should reuse the help window
+ Xnext
+ call assert_true(&buftype == 'help')
+ call assert_true(winnr() == 1)
+ call assert_true(winnr('$') == 2)
+ " Jumping to the next match from the quickfix window should reuse the help
+ " window
+ Xopen
+ Xnext
+ call assert_true(&buftype == 'help')
+ call assert_true(winnr() == 1)
+ call assert_true(winnr('$') == 2)
+
+ " This wipes out the buffer, make sure that doesn't cause trouble.
+ Xclose
+
+ if a:cchar == 'l'
+ " When a help window is present, running :lhelpgrep should reuse the
+ " help window and not the current window
+ new | only
+ call g:Xsetlist([], 'f')
+ help index.txt
+ wincmd w
+ lhelpgrep quickfix
+ call assert_equal(1, winnr())
+ call assert_notequal([], getloclist(1))
+ call assert_equal([], getloclist(2))
+ endif
+
+ new | only
+
+ " Search for non existing help string
+ call assert_fails('Xhelpgrep a1b2c3', 'E480:')
+ " Invalid regular expression
+ call assert_fails('Xhelpgrep \@<!', 'E480:')
+endfunc
+
+func Test_helpgrep()
+ call s:test_xhelpgrep('c')
+ helpclose
+ call s:test_xhelpgrep('l')
+endfunc
+
+func Test_errortitle()
+ augroup QfBufWinEnter
+ au!
+ au BufWinEnter * :let g:a=get(w:, 'quickfix_title', 'NONE')
+ augroup END
+ copen
+ let a=[{'lnum': 308, 'bufnr': bufnr(''), 'col': 58, 'valid': 1, 'vcol': 0, 'nr': 0, 'type': '', 'pattern': '', 'text': ' au BufWinEnter * :let g:a=get(w:, ''quickfix_title'', ''NONE'')'}]
+ call setqflist(a)
+ call assert_equal(':setqflist()', g:a)
+ augroup QfBufWinEnter
+ au!
+ augroup END
+ augroup! QfBufWinEnter
+endfunc
+
+func Test_vimgreptitle()
+ augroup QfBufWinEnter
+ au!
+ au BufWinEnter * :let g:a=get(w:, 'quickfix_title', 'NONE')
+ augroup END
+ try
+ vimgrep /pattern/j file
+ catch /E480/
+ endtry
+ copen
+ call assert_equal(': vimgrep /pattern/j file', g:a)
+ augroup QfBufWinEnter
+ au!
+ augroup END
+ augroup! QfBufWinEnter
+endfunc
+
+func XqfTitleTests(cchar)
+ call s:setup_commands(a:cchar)
+
+ Xgetexpr ['file:1:1:message']
+ let l = g:Xgetlist()
+ if a:cchar == 'c'
+ call setqflist(l, 'r')
+ else
+ call setloclist(0, l, 'r')
+ endif
+
+ Xopen
+ if a:cchar == 'c'
+ let title = ':setqflist()'
+ else
+ let title = ':setloclist()'
+ endif
+ call assert_equal(title, w:quickfix_title)
+ Xclose
+endfunc
+
+" Tests for quickfix window's title
+func Test_qf_title()
+ call XqfTitleTests('c')
+ call XqfTitleTests('l')
+endfunc
+
+" Tests for 'errorformat'
+func Test_efm()
+ let save_efm = &efm
+ set efm=%EEEE%m,%WWWW%m,%+CCCC%.%#,%-GGGG%.%#
+ cgetexpr ['WWWW', 'EEEE', 'CCCC']
+ let l = strtrans(string(map(getqflist(), '[v:val.text, v:val.valid]')))
+ call assert_equal("[['W', 1], ['E^@CCCC', 1]]", l)
+ cgetexpr ['WWWW', 'GGGG', 'EEEE', 'CCCC']
+ let l = strtrans(string(map(getqflist(), '[v:val.text, v:val.valid]')))
+ call assert_equal("[['W', 1], ['E^@CCCC', 1]]", l)
+ cgetexpr ['WWWW', 'GGGG', 'ZZZZ', 'EEEE', 'CCCC', 'YYYY']
+ let l = strtrans(string(map(getqflist(), '[v:val.text, v:val.valid]')))
+ call assert_equal("[['W', 1], ['ZZZZ', 0], ['E^@CCCC', 1], ['YYYY', 0]]", l)
+ let &efm = save_efm
+endfunc
+
+" This will test for problems in quickfix:
+" A. incorrectly copying location lists which caused the location list to show
+" a different name than the file that was actually being displayed.
+" B. not reusing the window for which the location list window is opened but
+" instead creating new windows.
+" C. make sure that the location list window is not reused instead of the
+" window it belongs to.
+"
+" Set up the test environment:
+func ReadTestProtocol(name)
+ let base = substitute(a:name, '\v^test://(.*)%(\.[^.]+)?', '\1', '')
+ let word = substitute(base, '\v(.*)\..*', '\1', '')
+
+ setl modifiable
+ setl noreadonly
+ setl noswapfile
+ setl bufhidden=delete
+ %del _
+ " For problem 2:
+ " 'buftype' has to be set to reproduce the constant opening of new windows
+ setl buftype=nofile
+
+ call setline(1, word)
+
+ setl nomodified
+ setl nomodifiable
+ setl readonly
+ exe 'doautocmd BufRead ' . substitute(a:name, '\v^test://(.*)', '\1', '')
+endfunc
+
+func Test_locationlist()
+ enew
+
+ augroup testgroup
+ au!
+ autocmd BufReadCmd test://* call ReadTestProtocol(expand("<amatch>"))
+ augroup END
+
+ let words = [ "foo", "bar", "baz", "quux", "shmoo", "spam", "eggs" ]
+
+ let qflist = []
+ for word in words
+ call add(qflist, {'filename': 'test://' . word . '.txt', 'text': 'file ' . word . '.txt', })
+ " NOTE: problem 1:
+ " intentionally not setting 'lnum' so that the quickfix entries are not
+ " valid
+ call setloclist(0, qflist, ' ')
+ endfor
+
+ " Test A
+ lrewind
+ enew
+ lopen
+ 4lnext
+ vert split
+ wincmd L
+ lopen
+ wincmd p
+ lnext
+ let fileName = expand("%")
+ wincmd p
+ let locationListFileName = substitute(getline(line('.')), '\([^|]*\)|.*', '\1', '')
+ let fileName = substitute(fileName, '\\', '/', 'g')
+ let locationListFileName = substitute(locationListFileName, '\\', '/', 'g')
+ call assert_equal("test://bar.txt", fileName)
+ call assert_equal("test://bar.txt", locationListFileName)
+
+ wincmd n | only
+
+ " Test B:
+ lrewind
+ lopen
+ 2
+ exe "normal \<CR>"
+ wincmd p
+ 3
+ exe "normal \<CR>"
+ wincmd p
+ 4
+ exe "normal \<CR>"
+ call assert_equal(2, winnr('$'))
+ wincmd n | only
+
+ " Test C:
+ lrewind
+ lopen
+ " Let's move the location list window to the top to check whether it (the
+ " first window found) will be reused when we try to open new windows:
+ wincmd K
+ 2
+ exe "normal \<CR>"
+ wincmd p
+ 3
+ exe "normal \<CR>"
+ wincmd p
+ 4
+ exe "normal \<CR>"
+ 1wincmd w
+ call assert_equal('quickfix', &buftype)
+ 2wincmd w
+ let bufferName = expand("%")
+ let bufferName = substitute(bufferName, '\\', '/', 'g')
+ call assert_equal('test://quux.txt', bufferName)
+
+ wincmd n | only
+
+ augroup! testgroup
+endfunc
+
+func Test_locationlist_curwin_was_closed()
+ augroup testgroup
+ au!
+ autocmd BufReadCmd test_curwin.txt call R(expand("<amatch>"))
+ augroup END
+
+ func! R(n)
+ quit
+ endfunc
+
+ new
+ let q = []
+ call add(q, {'filename': 'test_curwin.txt' })
+ call setloclist(0, q)
+ call assert_fails('lrewind', 'E924:')
+
+ augroup! testgroup
+endfunc
+
+func Test_locationlist_cross_tab_jump()
+ call writefile(['loclistfoo'], 'loclistfoo')
+ call writefile(['loclistbar'], 'loclistbar')
+ set switchbuf=usetab
+
+ edit loclistfoo
+ tabedit loclistbar
+ silent lgrep loclistfoo loclist*
+ call assert_equal(1, tabpagenr())
+
+ enew | only | tabonly
+ set switchbuf&vim
+ call delete('loclistfoo')
+ call delete('loclistbar')
+endfunc
+
+" More tests for 'errorformat'
+func Test_efm1()
+ if !has('unix')
+ " The 'errorformat' setting is different on non-Unix systems.
+ " This test works only on Unix-like systems.
+ return
+ endif
+
+ let l = [
+ \ '"Xtestfile", line 4.12: 1506-045 (S) Undeclared identifier fd_set.',
+ \ '"Xtestfile", line 6 col 19; this is an error',
+ \ 'gcc -c -DHAVE_CONFIsing-prototypes -I/usr/X11R6/include version.c',
+ \ 'Xtestfile:9: parse error before `asd''',
+ \ 'make: *** [vim] Error 1',
+ \ 'in file "Xtestfile" linenr 10: there is an error',
+ \ '',
+ \ '2 returned',
+ \ '"Xtestfile", line 11 col 1; this is an error',
+ \ '"Xtestfile", line 12 col 2; this is another error',
+ \ '"Xtestfile", line 14:10; this is an error in column 10',
+ \ '=Xtestfile=, line 15:10; this is another error, but in vcol 10 this time',
+ \ '"Xtestfile", linenr 16: yet another problem',
+ \ 'Error in "Xtestfile" at line 17:',
+ \ 'x should be a dot',
+ \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 17',
+ \ ' ^',
+ \ 'Error in "Xtestfile" at line 18:',
+ \ 'x should be a dot',
+ \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 18',
+ \ '.............^',
+ \ 'Error in "Xtestfile" at line 19:',
+ \ 'x should be a dot',
+ \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 19',
+ \ '--------------^',
+ \ 'Error in "Xtestfile" at line 20:',
+ \ 'x should be a dot',
+ \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 20',
+ \ ' ^',
+ \ '',
+ \ 'Does anyone know what is the problem and how to correction it?',
+ \ '"Xtestfile", line 21 col 9: What is the title of the quickfix window?',
+ \ '"Xtestfile", line 22 col 9: What is the title of the quickfix window?'
+ \ ]
+
+ call writefile(l, 'Xerrorfile1')
+ call writefile(l[:-2], 'Xerrorfile2')
+
+ let m = [
+ \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 2',
+ \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 3',
+ \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 4',
+ \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 5',
+ \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 6',
+ \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 7',
+ \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 8',
+ \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 9',
+ \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 10',
+ \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 11',
+ \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 12',
+ \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 13',
+ \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 14',
+ \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 15',
+ \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 16',
+ \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 17',
+ \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 18',
+ \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 19',
+ \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 20',
+ \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 21',
+ \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 22'
+ \ ]
+ call writefile(m, 'Xtestfile')
+
+ let save_efm = &efm
+ set efm+==%f=\\,\ line\ %l%*\\D%v%*[^\ ]\ %m
+ set efm^=%AError\ in\ \"%f\"\ at\ line\ %l:,%Z%p^,%C%m
+
+ exe 'cf Xerrorfile2'
+ clast
+ copen
+ call assert_equal(':cf Xerrorfile2', w:quickfix_title)
+ wincmd p
+
+ exe 'cf Xerrorfile1'
+ call assert_equal([4, 12], [line('.'), col('.')])
+ cn
+ call assert_equal([6, 19], [line('.'), col('.')])
+ cn
+ call assert_equal([9, 2], [line('.'), col('.')])
+ cn
+ call assert_equal([10, 2], [line('.'), col('.')])
+ cn
+ call assert_equal([11, 1], [line('.'), col('.')])
+ cn
+ call assert_equal([12, 2], [line('.'), col('.')])
+ cn
+ call assert_equal([14, 10], [line('.'), col('.')])
+ cn
+ call assert_equal([15, 3, 10], [line('.'), col('.'), virtcol('.')])
+ cn
+ call assert_equal([16, 2], [line('.'), col('.')])
+ cn
+ call assert_equal([17, 6], [line('.'), col('.')])
+ cn
+ call assert_equal([18, 7], [line('.'), col('.')])
+ cn
+ call assert_equal([19, 8], [line('.'), col('.')])
+ cn
+ call assert_equal([20, 9], [line('.'), col('.')])
+ clast
+ cprev
+ cprev
+ wincmd w
+ call assert_equal(':cf Xerrorfile1', w:quickfix_title)
+ wincmd p
+
+ let &efm = save_efm
+ call delete('Xerrorfile1')
+ call delete('Xerrorfile2')
+ call delete('Xtestfile')
+endfunc
+
+" Test for quickfix directory stack support
+func s:dir_stack_tests(cchar)
+ call s:setup_commands(a:cchar)
+
+ let save_efm=&efm
+ set efm=%DEntering\ dir\ '%f',%f:%l:%m,%XLeaving\ dir\ '%f'
+
+ let lines = ["Entering dir 'dir1/a'",
+ \ 'habits2.txt:1:Nine Healthy Habits',
+ \ "Entering dir 'b'",
+ \ 'habits3.txt:2:0 Hours of television',
+ \ 'habits2.txt:7:5 Small meals',
+ \ "Entering dir 'dir1/c'",
+ \ 'habits4.txt:3:1 Hour of exercise',
+ \ "Leaving dir 'dir1/c'",
+ \ "Leaving dir 'dir1/a'",
+ \ 'habits1.txt:4:2 Liters of water',
+ \ "Entering dir 'dir2'",
+ \ 'habits5.txt:5:3 Cups of hot green tea',
+ \ "Leaving dir 'dir2'"
+ \]
+
+ Xexpr ""
+ for l in lines
+ Xaddexpr l
+ endfor
+
+ let qf = g:Xgetlist()
+
+ call assert_equal('dir1/a/habits2.txt', bufname(qf[1].bufnr))
+ call assert_equal(1, qf[1].lnum)
+ call assert_equal('dir1/a/b/habits3.txt', bufname(qf[3].bufnr))
+ call assert_equal(2, qf[3].lnum)
+ call assert_equal('dir1/a/habits2.txt', bufname(qf[4].bufnr))
+ call assert_equal(7, qf[4].lnum)
+ call assert_equal('dir1/c/habits4.txt', bufname(qf[6].bufnr))
+ call assert_equal(3, qf[6].lnum)
+ call assert_equal('habits1.txt', bufname(qf[9].bufnr))
+ call assert_equal(4, qf[9].lnum)
+ call assert_equal('dir2/habits5.txt', bufname(qf[11].bufnr))
+ call assert_equal(5, qf[11].lnum)
+
+ let &efm=save_efm
+endfunc
+
+" Tests for %D and %X errorformat options
+func Test_efm_dirstack()
+ " Create the directory stack and files
+ call mkdir('dir1')
+ call mkdir('dir1/a')
+ call mkdir('dir1/a/b')
+ call mkdir('dir1/c')
+ call mkdir('dir2')
+
+ let lines = ["Nine Healthy Habits",
+ \ "0 Hours of television",
+ \ "1 Hour of exercise",
+ \ "2 Liters of water",
+ \ "3 Cups of hot green tea",
+ \ "4 Short mental breaks",
+ \ "5 Small meals",
+ \ "6 AM wake up time",
+ \ "7 Minutes of laughter",
+ \ "8 Hours of sleep (at least)",
+ \ "9 PM end of the day and off to bed"
+ \ ]
+ call writefile(lines, 'habits1.txt')
+ call writefile(lines, 'dir1/a/habits2.txt')
+ call writefile(lines, 'dir1/a/b/habits3.txt')
+ call writefile(lines, 'dir1/c/habits4.txt')
+ call writefile(lines, 'dir2/habits5.txt')
+
+ call s:dir_stack_tests('c')
+ call s:dir_stack_tests('l')
+
+ call delete('dir1', 'rf')
+ call delete('dir2', 'rf')
+ call delete('habits1.txt')
+endfunc
+
+" Test for resync after continuing an ignored message
+func Xefm_ignore_continuations(cchar)
+ call s:setup_commands(a:cchar)
+
+ let save_efm = &efm
+
+ let &efm =
+ \ '%Eerror %m %l,' .
+ \ '%-Wignored %m %l,' .
+ \ '%+Cmore ignored %m %l,' .
+ \ '%Zignored end'
+ Xgetexpr ['ignored warning 1', 'more ignored continuation 2', 'ignored end', 'error resync 4']
+ let l = map(g:Xgetlist(), '[v:val.text, v:val.valid, v:val.lnum, v:val.type]')
+ call assert_equal([['resync', 1, 4, 'E']], l)
+
+ let &efm = save_efm
+endfunc
+
+func Test_efm_ignore_continuations()
+ call Xefm_ignore_continuations('c')
+ call Xefm_ignore_continuations('l')
+endfunc
+
+" Tests for invalid error format specifies
+func Xinvalid_efm_Tests(cchar)
+ call s:setup_commands(a:cchar)
+
+ let save_efm = &efm
+
+ set efm=%f:%l:%m,%f:%f:%l:%m
+ call assert_fails('Xexpr "abc.txt:1:Hello world"', 'E372:')
+
+ set efm=%f:%l:%m,%f:%l:%r:%m
+ call assert_fails('Xexpr "abc.txt:1:Hello world"', 'E373:')
+
+ set efm=%f:%l:%m,%O:%f:%l:%m
+ call assert_fails('Xexpr "abc.txt:1:Hello world"', 'E373:')
+
+ set efm=%f:%l:%m,%f:%l:%*[^a-z
+ call assert_fails('Xexpr "abc.txt:1:Hello world"', 'E374:')
+
+ set efm=%f:%l:%m,%f:%l:%*c
+ call assert_fails('Xexpr "abc.txt:1:Hello world"', 'E375:')
+
+ set efm=%f:%l:%m,%L%M%N
+ call assert_fails('Xexpr "abc.txt:1:Hello world"', 'E376:')
+
+ set efm=%f:%l:%m,%f:%l:%m:%R
+ call assert_fails('Xexpr "abc.txt:1:Hello world"', 'E377:')
+
+ set efm=
+ call assert_fails('Xexpr "abc.txt:1:Hello world"', 'E378:')
+
+ set efm=%DEntering\ dir\ abc,%f:%l:%m
+ call assert_fails('Xexpr ["Entering dir abc", "abc.txt:1:Hello world"]', 'E379:')
+
+ let &efm = save_efm
+endfunc
+
+func Test_invalid_efm()
+ call Xinvalid_efm_Tests('c')
+ call Xinvalid_efm_Tests('l')
+endfunc
+
+" TODO:
+" Add tests for the following formats in 'errorformat'
+" %r %O
+func Test_efm2()
+ let save_efm = &efm
+
+ " Test for %s format in efm
+ set efm=%f:%s
+ cexpr 'Xtestfile:Line search text'
+ let l = getqflist()
+ call assert_equal(l[0].pattern, '^\VLine search text\$')
+ call assert_equal(l[0].lnum, 0)
+
+ let l = split(execute('clist', ''), "\n")
+ call assert_equal([' 1 Xtestfile:^\VLine search text\$: '], l)
+
+ " Test for %P, %Q and %t format specifiers
+ let lines=["[Xtestfile1]",
+ \ "(1,17) error: ';' missing",
+ \ "(21,2) warning: variable 'z' not defined",
+ \ "(67,3) error: end of file found before string ended",
+ \ "--",
+ \ "",
+ \ "[Xtestfile2]",
+ \ "--",
+ \ "",
+ \ "[Xtestfile3]",
+ \ "NEW compiler v1.1",
+ \ "(2,2) warning: variable 'x' not defined",
+ \ "(67,3) warning: 's' already defined",
+ \ "--"
+ \]
+ set efm=%+P[%f]%r,(%l\\,%c)%*[\ ]%t%*[^:]:\ %m,%+Q--%r
+ " To exercise the push/pop file functionality in quickfix, the test files
+ " need to be created.
+ call writefile(['Line1'], 'Xtestfile1')
+ call writefile(['Line2'], 'Xtestfile2')
+ call writefile(['Line3'], 'Xtestfile3')
+ cexpr ""
+ for l in lines
+ caddexpr l
+ endfor
+ let l = getqflist()
+ call assert_equal(12, len(l))
+ call assert_equal(21, l[2].lnum)
+ call assert_equal(2, l[2].col)
+ call assert_equal('w', l[2].type)
+ call assert_equal('e', l[3].type)
+ call delete('Xtestfile1')
+ call delete('Xtestfile2')
+ call delete('Xtestfile3')
+
+ " Tests for %E, %C and %Z format specifiers
+ let lines = ["Error 275",
+ \ "line 42",
+ \ "column 3",
+ \ "' ' expected after '--'"
+ \]
+ set efm=%EError\ %n,%Cline\ %l,%Ccolumn\ %c,%Z%m
+ cgetexpr lines
+ let l = getqflist()
+ call assert_equal(275, l[0].nr)
+ call assert_equal(42, l[0].lnum)
+ call assert_equal(3, l[0].col)
+ call assert_equal('E', l[0].type)
+ call assert_equal("\n' ' expected after '--'", l[0].text)
+
+ " Test for %>
+ let lines = ["Error in line 147 of foo.c:",
+ \"unknown variable 'i'"
+ \]
+ set efm=unknown\ variable\ %m,%E%>Error\ in\ line\ %l\ of\ %f:,%Z%m
+ cgetexpr lines
+ let l = getqflist()
+ call assert_equal(147, l[0].lnum)
+ call assert_equal('E', l[0].type)
+ call assert_equal("\nunknown variable 'i'", l[0].text)
+
+ " Test for %A, %C and other formats
+ let lines = [
+ \"==============================================================",
+ \"FAIL: testGetTypeIdCachesResult (dbfacadeTest.DjsDBFacadeTest)",
+ \"--------------------------------------------------------------",
+ \"Traceback (most recent call last):",
+ \' File "unittests/dbfacadeTest.py", line 89, in testFoo',
+ \" self.assertEquals(34, dtid)",
+ \' File "/usr/lib/python2.2/unittest.py", line 286, in',
+ \" failUnlessEqual",
+ \" raise self.failureException, \\",
+ \"AssertionError: 34 != 33",
+ \"",
+ \"--------------------------------------------------------------",
+ \"Ran 27 tests in 0.063s"
+ \]
+ set efm=%C\ %.%#,%A\ \ File\ \"%f\"\\,\ line\ %l%.%#,%Z%[%^\ ]%\\@=%m
+ cgetexpr lines
+ let l = getqflist()
+ call assert_equal(8, len(l))
+ call assert_equal(89, l[4].lnum)
+ call assert_equal(1, l[4].valid)
+ call assert_equal('unittests/dbfacadeTest.py', bufname(l[4].bufnr))
+
+ " Test for %o
+ set efm=%f(%o):%l\ %m
+ cgetexpr ['Xotestfile(Language.PureScript.Types):20 Error']
+ call writefile(['Line1'], 'Xotestfile')
+ let l = getqflist()
+ call assert_equal(1, len(l), string(l))
+ call assert_equal('Language.PureScript.Types', l[0].module)
+ copen
+ call assert_equal('Language.PureScript.Types|20| Error', getline(1))
+ call feedkeys("\<CR>", 'xn')
+ call assert_equal('Xotestfile', expand('%:t'))
+ cclose
+ bd
+ call delete("Xotestfile")
+
+ " The following sequence of commands used to crash Vim
+ set efm=%W%m
+ cgetexpr ['msg1']
+ let l = getqflist()
+ call assert_equal(1, len(l), string(l))
+ call assert_equal('msg1', l[0].text)
+ set efm=%C%m
+ lexpr 'msg2'
+ let l = getloclist(0)
+ call assert_equal(1, len(l), string(l))
+ call assert_equal('msg2', l[0].text)
+ lopen
+ call setqflist([], 'r')
+ caddbuf
+ let l = getqflist()
+ call assert_equal(1, len(l), string(l))
+ call assert_equal('|| msg2', l[0].text)
+
+ " When matching error lines, case should be ignored. Test for this.
+ set noignorecase
+ let l=getqflist({'lines' : ['Xtest:FOO10:Line 20'], 'efm':'%f:foo%l:%m'})
+ call assert_equal(10, l.items[0].lnum)
+ call assert_equal('Line 20', l.items[0].text)
+ set ignorecase&
+
+ new | only
+ let &efm = save_efm
+endfunc
+
+func XquickfixChangedByAutocmd(cchar)
+ call s:setup_commands(a:cchar)
+ if a:cchar == 'c'
+ let ErrorNr = 'E925'
+ func! ReadFunc()
+ colder
+ cgetexpr []
+ endfunc
+ else
+ let ErrorNr = 'E926'
+ func! ReadFunc()
+ lolder
+ lgetexpr []
+ endfunc
+ endif
+
+ augroup testgroup
+ au!
+ autocmd BufReadCmd test_changed.txt call ReadFunc()
+ augroup END
+
+ new | only
+ let words = [ "a", "b" ]
+ let qflist = []
+ for word in words
+ call add(qflist, {'filename': 'test_changed.txt'})
+ call g:Xsetlist(qflist, ' ')
+ endfor
+ call assert_fails('Xrewind', ErrorNr . ':')
+
+ augroup! testgroup
+endfunc
+
+func Test_quickfix_was_changed_by_autocmd()
+ call XquickfixChangedByAutocmd('c')
+ call XquickfixChangedByAutocmd('l')
+endfunc
+
+func Test_caddbuffer_to_empty()
+ helpgr quickfix
+ call setqflist([], 'r')
+ cad
+ try
+ cn
+ catch
+ " number of matches is unknown
+ call assert_true(v:exception =~ 'E553:')
+ endtry
+ quit!
+endfunc
+
+func Test_cgetexpr_works()
+ " this must not crash Vim
+ cgetexpr [$x]
+ lgetexpr [$x]
+endfunc
+
+" Tests for the setqflist() and setloclist() functions
+func SetXlistTests(cchar, bnum)
+ call s:setup_commands(a:cchar)
+
+ call g:Xsetlist([{'bufnr': a:bnum, 'lnum': 1},
+ \ {'bufnr': a:bnum, 'lnum': 2}])
+ let l = g:Xgetlist()
+ call assert_equal(2, len(l))
+ call assert_equal(2, l[1].lnum)
+
+ Xnext
+ call g:Xsetlist([{'bufnr': a:bnum, 'lnum': 3}], 'a')
+ let l = g:Xgetlist()
+ call assert_equal(3, len(l))
+ Xnext
+ call assert_equal(3, line('.'))
+
+ " Appending entries to the list should not change the cursor position
+ " in the quickfix window
+ Xwindow
+ 1
+ call g:Xsetlist([{'bufnr': a:bnum, 'lnum': 4},
+ \ {'bufnr': a:bnum, 'lnum': 5}], 'a')
+ call assert_equal(1, line('.'))
+ close
+
+ call g:Xsetlist([{'bufnr': a:bnum, 'lnum': 3},
+ \ {'bufnr': a:bnum, 'lnum': 4},
+ \ {'bufnr': a:bnum, 'lnum': 5}], 'r')
+ let l = g:Xgetlist()
+ call assert_equal(3, len(l))
+ call assert_equal(5, l[2].lnum)
+
+ call g:Xsetlist([])
+ let l = g:Xgetlist()
+ call assert_equal(0, len(l))
+
+ " Tests for setting the 'valid' flag
+ call g:Xsetlist([{'bufnr':a:bnum, 'lnum':4, 'valid':0}])
+ Xwindow
+ call assert_equal(1, winnr('$'))
+ let l = g:Xgetlist()
+ call g:Xsetlist(l)
+ call assert_equal(0, g:Xgetlist()[0].valid)
+ " Adding a non-valid entry should not mark the list as having valid entries
+ call g:Xsetlist([{'bufnr':a:bnum, 'lnum':5, 'valid':0}], 'a')
+ Xwindow
+ call assert_equal(1, winnr('$'))
+
+ " :cnext/:cprev should still work even with invalid entries in the list
+ let l = [{'bufnr' : a:bnum, 'lnum' : 1, 'text' : '1', 'valid' : 0},
+ \ {'bufnr' : a:bnum, 'lnum' : 2, 'text' : '2', 'valid' : 0}]
+ call g:Xsetlist(l)
+ Xnext
+ call assert_equal(2, g:Xgetlist({'idx' : 0}).idx)
+ Xprev
+ call assert_equal(1, g:Xgetlist({'idx' : 0}).idx)
+ " :cnext/:cprev should still work after appending invalid entries to an
+ " empty list
+ call g:Xsetlist([])
+ call g:Xsetlist(l, 'a')
+ Xnext
+ call assert_equal(2, g:Xgetlist({'idx' : 0}).idx)
+ Xprev
+ call assert_equal(1, g:Xgetlist({'idx' : 0}).idx)
+
+ call g:Xsetlist([{'text':'Text1', 'valid':1}])
+ Xwindow
+ call assert_equal(2, winnr('$'))
+ Xclose
+ let save_efm = &efm
+ set efm=%m
+ Xgetexpr 'TestMessage'
+ let l = g:Xgetlist()
+ call g:Xsetlist(l)
+ call assert_equal(1, g:Xgetlist()[0].valid)
+ let &efm = save_efm
+
+ " Error cases:
+ " Refer to a non-existing buffer and pass a non-dictionary type
+ call assert_fails("call g:Xsetlist([{'bufnr':998, 'lnum':4}," .
+ \ " {'bufnr':999, 'lnum':5}])", 'E92:')
+ call g:Xsetlist([[1, 2,3]])
+ call assert_equal(0, len(g:Xgetlist()))
+endfunc
+
+func Test_setqflist()
+ new Xtestfile | only
+ let bnum = bufnr('%')
+ call setline(1, range(1,5))
+
+ call SetXlistTests('c', bnum)
+ call SetXlistTests('l', bnum)
+
+ enew!
+ call delete('Xtestfile')
+endfunc
+
+func Xlist_empty_middle(cchar)
+ call s:setup_commands(a:cchar)
+
+ " create three quickfix lists
+ let @/ = 'Test_'
+ Xvimgrep // test_quickfix.vim
+ let testlen = len(g:Xgetlist())
+ call assert_true(testlen > 0)
+ Xvimgrep empty test_quickfix.vim
+ call assert_true(len(g:Xgetlist()) > 0)
+ Xvimgrep matches test_quickfix.vim
+ let matchlen = len(g:Xgetlist())
+ call assert_true(matchlen > 0)
+ Xolder
+ " make the middle list empty
+ call g:Xsetlist([], 'r')
+ call assert_true(len(g:Xgetlist()) == 0)
+ Xolder
+ call assert_equal(testlen, len(g:Xgetlist()))
+ Xnewer
+ Xnewer
+ call assert_equal(matchlen, len(g:Xgetlist()))
+endfunc
+
+func Test_setqflist_empty_middle()
+ call Xlist_empty_middle('c')
+ call Xlist_empty_middle('l')
+endfunc
+
+func Xlist_empty_older(cchar)
+ call s:setup_commands(a:cchar)
+
+ " create three quickfix lists
+ Xvimgrep one test_quickfix.vim
+ let onelen = len(g:Xgetlist())
+ call assert_true(onelen > 0)
+ Xvimgrep two test_quickfix.vim
+ let twolen = len(g:Xgetlist())
+ call assert_true(twolen > 0)
+ Xvimgrep three test_quickfix.vim
+ let threelen = len(g:Xgetlist())
+ call assert_true(threelen > 0)
+ Xolder 2
+ " make the first list empty, check the others didn't change
+ call g:Xsetlist([], 'r')
+ call assert_true(len(g:Xgetlist()) == 0)
+ Xnewer
+ call assert_equal(twolen, len(g:Xgetlist()))
+ Xnewer
+ call assert_equal(threelen, len(g:Xgetlist()))
+endfunc
+
+func Test_setqflist_empty_older()
+ call Xlist_empty_older('c')
+ call Xlist_empty_older('l')
+endfunc
+
+func XquickfixSetListWithAct(cchar)
+ call s:setup_commands(a:cchar)
+
+ let list1 = [{'filename': 'fnameA', 'text': 'A'},
+ \ {'filename': 'fnameB', 'text': 'B'}]
+ let list2 = [{'filename': 'fnameC', 'text': 'C'},
+ \ {'filename': 'fnameD', 'text': 'D'},
+ \ {'filename': 'fnameE', 'text': 'E'}]
+
+ " {action} is unspecified. Same as specifing ' '.
+ new | only
+ silent! Xnewer 99
+ call g:Xsetlist(list1)
+ call g:Xsetlist(list2)
+ let li = g:Xgetlist()
+ call assert_equal(3, len(li))
+ call assert_equal('C', li[0]['text'])
+ call assert_equal('D', li[1]['text'])
+ call assert_equal('E', li[2]['text'])
+ silent! Xolder
+ let li = g:Xgetlist()
+ call assert_equal(2, len(li))
+ call assert_equal('A', li[0]['text'])
+ call assert_equal('B', li[1]['text'])
+
+ " {action} is specified ' '.
+ new | only
+ silent! Xnewer 99
+ call g:Xsetlist(list1)
+ call g:Xsetlist(list2, ' ')
+ let li = g:Xgetlist()
+ call assert_equal(3, len(li))
+ call assert_equal('C', li[0]['text'])
+ call assert_equal('D', li[1]['text'])
+ call assert_equal('E', li[2]['text'])
+ silent! Xolder
+ let li = g:Xgetlist()
+ call assert_equal(2, len(li))
+ call assert_equal('A', li[0]['text'])
+ call assert_equal('B', li[1]['text'])
+
+ " {action} is specified 'a'.
+ new | only
+ silent! Xnewer 99
+ call g:Xsetlist(list1)
+ call g:Xsetlist(list2, 'a')
+ let li = g:Xgetlist()
+ call assert_equal(5, len(li))
+ call assert_equal('A', li[0]['text'])
+ call assert_equal('B', li[1]['text'])
+ call assert_equal('C', li[2]['text'])
+ call assert_equal('D', li[3]['text'])
+ call assert_equal('E', li[4]['text'])
+
+ " {action} is specified 'r'.
+ new | only
+ silent! Xnewer 99
+ call g:Xsetlist(list1)
+ call g:Xsetlist(list2, 'r')
+ let li = g:Xgetlist()
+ call assert_equal(3, len(li))
+ call assert_equal('C', li[0]['text'])
+ call assert_equal('D', li[1]['text'])
+ call assert_equal('E', li[2]['text'])
+
+ " Test for wrong value.
+ new | only
+ call assert_fails("call g:Xsetlist(0)", 'E714:')
+ call assert_fails("call g:Xsetlist(list1, '')", 'E927:')
+ call assert_fails("call g:Xsetlist(list1, 'aa')", 'E927:')
+ call assert_fails("call g:Xsetlist(list1, ' a')", 'E927:')
+ call assert_fails("call g:Xsetlist(list1, 0)", 'E928:')
+endfunc
+
+func Test_setqflist_invalid_nr()
+ " The following command used to crash Vim
+ call setqflist([], ' ', {'nr' : $XXX_DOES_NOT_EXIST})
+endfunc
+
+func Test_quickfix_set_list_with_act()
+ call XquickfixSetListWithAct('c')
+ call XquickfixSetListWithAct('l')
+endfunc
+
+func XLongLinesTests(cchar)
+ let l = g:Xgetlist()
+
+ call assert_equal(4, len(l))
+ call assert_equal(1, l[0].lnum)
+ call assert_equal(1, l[0].col)
+ call assert_equal(1975, len(l[0].text))
+ call assert_equal(2, l[1].lnum)
+ call assert_equal(1, l[1].col)
+ call assert_equal(4070, len(l[1].text))
+ call assert_equal(3, l[2].lnum)
+ call assert_equal(1, l[2].col)
+ call assert_equal(4070, len(l[2].text))
+ call assert_equal(4, l[3].lnum)
+ call assert_equal(1, l[3].col)
+ call assert_equal(10, len(l[3].text))
+
+ call g:Xsetlist([], 'r')
+endfunc
+
+func s:long_lines_tests(cchar)
+ call s:setup_commands(a:cchar)
+
+ let testfile = 'samples/quickfix.txt'
+
+ " file
+ exe 'Xgetfile' testfile
+ call XLongLinesTests(a:cchar)
+
+ " list
+ Xexpr readfile(testfile)
+ call XLongLinesTests(a:cchar)
+
+ " string
+ Xexpr join(readfile(testfile), "\n")
+ call XLongLinesTests(a:cchar)
+
+ " buffer
+ exe 'edit' testfile
+ exe 'Xbuffer' bufnr('%')
+ call XLongLinesTests(a:cchar)
+endfunc
+
+func Test_long_lines()
+ call s:long_lines_tests('c')
+ call s:long_lines_tests('l')
+endfunc
+
+func s:create_test_file(filename)
+ let l = []
+ for i in range(1, 20)
+ call add(l, 'Line' . i)
+ endfor
+ call writefile(l, a:filename)
+endfunc
+
+func Test_switchbuf()
+ call s:create_test_file('Xqftestfile1')
+ call s:create_test_file('Xqftestfile2')
+ call s:create_test_file('Xqftestfile3')
+
+ new | only
+ edit Xqftestfile1
+ let file1_winid = win_getid()
+ new Xqftestfile2
+ let file2_winid = win_getid()
+ cgetexpr ['Xqftestfile1:5:Line5',
+ \ 'Xqftestfile1:6:Line6',
+ \ 'Xqftestfile2:10:Line10',
+ \ 'Xqftestfile2:11:Line11',
+ \ 'Xqftestfile3:15:Line15',
+ \ 'Xqftestfile3:16:Line16']
+
+ new
+ let winid = win_getid()
+ cfirst | cnext
+ call assert_equal(winid, win_getid())
+ 2cnext
+ call assert_equal(winid, win_getid())
+ 2cnext
+ call assert_equal(winid, win_getid())
+ enew
+
+ set switchbuf=useopen
+ cfirst | cnext
+ call assert_equal(file1_winid, win_getid())
+ 2cnext
+ call assert_equal(file2_winid, win_getid())
+ 2cnext
+ call assert_equal(file2_winid, win_getid())
+
+ enew | only
+ set switchbuf=usetab
+ tabedit Xqftestfile1
+ tabedit Xqftestfile2
+ tabedit Xqftestfile3
+ tabfirst
+ cfirst | cnext
+ call assert_equal(2, tabpagenr())
+ 2cnext
+ call assert_equal(3, tabpagenr())
+ 6cnext
+ call assert_equal(4, tabpagenr())
+ 2cpfile
+ call assert_equal(2, tabpagenr())
+ 2cnfile
+ call assert_equal(4, tabpagenr())
+ tabfirst | tabonly | enew
+
+ set switchbuf=split
+ cfirst | cnext
+ call assert_equal(1, winnr('$'))
+ cnext | cnext
+ call assert_equal(2, winnr('$'))
+ cnext | cnext
+ call assert_equal(3, winnr('$'))
+ enew | only
+
+ set switchbuf=newtab
+ cfirst | cnext
+ call assert_equal(1, tabpagenr('$'))
+ cnext | cnext
+ call assert_equal(2, tabpagenr('$'))
+ cnext | cnext
+ call assert_equal(3, tabpagenr('$'))
+ tabfirst | enew | tabonly | only
+
+ set switchbuf=
+ edit Xqftestfile1
+ let file1_winid = win_getid()
+ new Xqftestfile2
+ let file2_winid = win_getid()
+ copen
+ exe "normal 1G\<CR>"
+ call assert_equal(file1_winid, win_getid())
+ copen
+ exe "normal 3G\<CR>"
+ call assert_equal(file2_winid, win_getid())
+ copen | only
+ exe "normal 5G\<CR>"
+ call assert_equal(2, winnr('$'))
+ call assert_equal(1, bufwinnr('Xqftestfile3'))
+
+ " If only quickfix window is open in the current tabpage, jumping to an
+ " entry with 'switchubf' set to 'usetab' should search in other tabpages.
+ enew | only
+ set switchbuf=usetab
+ tabedit Xqftestfile1
+ tabedit Xqftestfile2
+ tabedit Xqftestfile3
+ tabfirst
+ copen | only
+ clast
+ call assert_equal(4, tabpagenr())
+ tabfirst | tabonly | enew | only
+
+ call delete('Xqftestfile1')
+ call delete('Xqftestfile2')
+ call delete('Xqftestfile3')
+ set switchbuf&vim
+
+ enew | only
+endfunc
+
+func Xadjust_qflnum(cchar)
+ call s:setup_commands(a:cchar)
+
+ enew | only
+
+ let fname = 'Xqftestfile' . a:cchar
+ call s:create_test_file(fname)
+ exe 'edit ' . fname
+
+ Xgetexpr [fname . ':5:Line5',
+ \ fname . ':10:Line10',
+ \ fname . ':15:Line15',
+ \ fname . ':20:Line20']
+
+ 6,14delete
+ call append(6, ['Buffer', 'Window'])
+
+ let l = g:Xgetlist()
+
+ call assert_equal(5, l[0].lnum)
+ call assert_equal(6, l[2].lnum)
+ call assert_equal(13, l[3].lnum)
+
+ enew!
+ call delete(fname)
+endfunc
+
+func Test_adjust_lnum()
+ call setloclist(0, [])
+ call Xadjust_qflnum('c')
+ call setqflist([])
+ call Xadjust_qflnum('l')
+endfunc
+
+" Tests for the :grep/:lgrep and :grepadd/:lgrepadd commands
+func s:test_xgrep(cchar)
+ call s:setup_commands(a:cchar)
+
+ " The following lines are used for the grep test. Don't remove.
+ " Grep_Test_Text: Match 1
+ " Grep_Test_Text: Match 2
+ " GrepAdd_Test_Text: Match 1
+ " GrepAdd_Test_Text: Match 2
+ enew! | only
+ set makeef&vim
+ silent Xgrep Grep_Test_Text: test_quickfix.vim
+ call assert_true(len(g:Xgetlist()) == 3)
+ Xopen
+ call assert_true(w:quickfix_title =~ '^:grep')
+ Xclose
+ enew
+ set makeef=Temp_File_##
+ silent Xgrepadd GrepAdd_Test_Text: test_quickfix.vim
+ call assert_true(len(g:Xgetlist()) == 6)
+endfunc
+
+func Test_grep()
+ if !has('unix')
+ " The grepprg may not be set on non-Unix systems
+ return
+ endif
+
+ call s:test_xgrep('c')
+ call s:test_xgrep('l')
+endfunc
+
+func Test_two_windows()
+ " Use one 'errorformat' for two windows. Add an expression to each of them,
+ " make sure they each keep their own state.
+ set efm=%DEntering\ dir\ '%f',%f:%l:%m,%XLeaving\ dir\ '%f'
+ call mkdir('Xone/a', 'p')
+ call mkdir('Xtwo/a', 'p')
+ let lines = ['1', '2', 'one one one', '4', 'two two two', '6', '7']
+ call writefile(lines, 'Xone/a/one.txt')
+ call writefile(lines, 'Xtwo/a/two.txt')
+
+ new one
+ let one_id = win_getid()
+ lexpr ""
+ new two
+ let two_id = win_getid()
+ lexpr ""
+
+ laddexpr "Entering dir 'Xtwo/a'"
+ call win_gotoid(one_id)
+ laddexpr "Entering dir 'Xone/a'"
+ call win_gotoid(two_id)
+ laddexpr 'two.txt:5:two two two'
+ call win_gotoid(one_id)
+ laddexpr 'one.txt:3:one one one'
+
+ let loc_one = getloclist(one_id)
+ call assert_equal('Xone/a/one.txt', bufname(loc_one[1].bufnr))
+ call assert_equal(3, loc_one[1].lnum)
+
+ let loc_two = getloclist(two_id)
+ call assert_equal('Xtwo/a/two.txt', bufname(loc_two[1].bufnr))
+ call assert_equal(5, loc_two[1].lnum)
+
+ call win_gotoid(one_id)
+ bwipe!
+ call win_gotoid(two_id)
+ bwipe!
+ call delete('Xone', 'rf')
+ call delete('Xtwo', 'rf')
+endfunc
+
+func XbottomTests(cchar)
+ call s:setup_commands(a:cchar)
+
+ " Calling lbottom without any errors should fail
+ if a:cchar == 'l'
+ call assert_fails('lbottom', 'E776:')
+ endif
+
+ call g:Xsetlist([{'filename': 'foo', 'lnum': 42}])
+ Xopen
+ let wid = win_getid()
+ call assert_equal(1, line('.'))
+ wincmd w
+ call g:Xsetlist([{'filename': 'var', 'lnum': 24}], 'a')
+ Xbottom
+ call win_gotoid(wid)
+ call assert_equal(2, line('.'))
+ Xclose
+endfunc
+
+" Tests for the :cbottom and :lbottom commands
+func Test_cbottom()
+ call XbottomTests('c')
+ call XbottomTests('l')
+endfunc
+
+func HistoryTest(cchar)
+ call s:setup_commands(a:cchar)
+
+ " clear all lists after the first one, then replace the first one.
+ call g:Xsetlist([])
+ call assert_fails('Xolder 99', 'E380:')
+ let entry = {'filename': 'foo', 'lnum': 42}
+ call g:Xsetlist([entry], 'r')
+ call g:Xsetlist([entry, entry])
+ call g:Xsetlist([entry, entry, entry])
+ let res = split(execute(a:cchar . 'hist'), "\n")
+ call assert_equal(3, len(res))
+ let common = 'errors :set' . (a:cchar == 'c' ? 'qf' : 'loc') . 'list()'
+ call assert_equal(' error list 1 of 3; 1 ' . common, res[0])
+ call assert_equal(' error list 2 of 3; 2 ' . common, res[1])
+ call assert_equal('> error list 3 of 3; 3 ' . common, res[2])
+
+ call g:Xsetlist([], 'f')
+ let l = split(execute(a:cchar . 'hist'), "\n")
+ call assert_equal('No entries', l[0])
+
+ " An empty list should still show the stack history
+ call g:Xsetlist([])
+ let res = split(execute(a:cchar . 'hist'), "\n")
+ call assert_equal('> error list 1 of 1; 0 ' . common, res[0])
+
+ call g:Xsetlist([], 'f')
+endfunc
+
+func Test_history()
+ call HistoryTest('c')
+ call HistoryTest('l')
+endfunc
+
+func Test_duplicate_buf()
+ " make sure we can get the highest buffer number
+ edit DoesNotExist
+ edit DoesNotExist2
+ let last_buffer = bufnr("$")
+
+ " make sure only one buffer is created
+ call writefile(['this one', 'that one'], 'Xgrepthis')
+ vimgrep one Xgrepthis
+ vimgrep one Xgrepthis
+ call assert_equal(last_buffer + 1, bufnr("$"))
+
+ call delete('Xgrepthis')
+endfunc
+
+" Quickfix/Location list set/get properties tests
+func Xproperty_tests(cchar)
+ call s:setup_commands(a:cchar)
+
+ " Error cases
+ call assert_fails('call g:Xgetlist(99)', 'E715:')
+ call assert_fails('call g:Xsetlist(99)', 'E714:')
+ call assert_fails('call g:Xsetlist([], "a", [])', 'E715:')
+
+ " Set and get the title
+ call g:Xsetlist([])
+ Xopen
+ wincmd p
+ call g:Xsetlist([{'filename':'foo', 'lnum':27}])
+ let s = g:Xsetlist([], 'a', {'title' : 'Sample'})
+ call assert_equal(0, s)
+ let d = g:Xgetlist({"title":1})
+ call assert_equal('Sample', d.title)
+ " Try setting title to a non-string value
+ call assert_equal(-1, g:Xsetlist([], 'a', {'title' : ['Test']}))
+ call assert_equal('Sample', g:Xgetlist({"title":1}).title)
+
+ Xopen
+ call assert_equal('Sample', w:quickfix_title)
+ Xclose
+
+ " Tests for action argument
+ silent! Xolder 999
+ let qfnr = g:Xgetlist({'all':1}).nr
+ call g:Xsetlist([], 'r', {'title' : 'N1'})
+ call assert_equal('N1', g:Xgetlist({'all':1}).title)
+ call g:Xsetlist([], ' ', {'title' : 'N2'})
+ call assert_equal(qfnr + 1, g:Xgetlist({'all':1}).nr)
+
+ let res = g:Xgetlist({'nr': 0})
+ call assert_equal(qfnr + 1, res.nr)
+ call assert_equal(['nr'], keys(res))
+
+ call g:Xsetlist([], ' ', {'title' : 'N3'})
+ call assert_equal('N2', g:Xgetlist({'nr':2, 'title':1}).title)
+
+ " Changing the title of an earlier quickfix list
+ call g:Xsetlist([], 'r', {'title' : 'NewTitle', 'nr' : 2})
+ call assert_equal('NewTitle', g:Xgetlist({'nr':2, 'title':1}).title)
+
+ " Changing the title of an invalid quickfix list
+ call assert_equal(-1, g:Xsetlist([], ' ',
+ \ {'title' : 'SomeTitle', 'nr' : 99}))
+ call assert_equal(-1, g:Xsetlist([], ' ',
+ \ {'title' : 'SomeTitle', 'nr' : 'abc'}))
+
+ if a:cchar == 'c'
+ copen
+ call assert_equal({'winid':win_getid()}, getqflist({'winid':1}))
+ cclose
+ endif
+
+ " Invalid arguments
+ call assert_fails('call g:Xgetlist([])', 'E715')
+ call assert_fails('call g:Xsetlist([], "a", [])', 'E715')
+ let s = g:Xsetlist([], 'a', {'abc':1})
+ call assert_equal(-1, s)
+
+ call assert_equal({}, g:Xgetlist({'abc':1}))
+ call assert_equal('', g:Xgetlist({'nr':99, 'title':1}).title)
+ call assert_equal('', g:Xgetlist({'nr':[], 'title':1}).title)
+
+ if a:cchar == 'l'
+ call assert_equal({}, getloclist(99, {'title': 1}))
+ endif
+
+ " Context related tests
+ let s = g:Xsetlist([], 'a', {'context':[1,2,3]})
+ call assert_equal(0, s)
+ call test_garbagecollect_now()
+ let d = g:Xgetlist({'context':1})
+ call assert_equal([1,2,3], d.context)
+ call g:Xsetlist([], 'a', {'context':{'color':'green'}})
+ let d = g:Xgetlist({'context':1})
+ call assert_equal({'color':'green'}, d.context)
+ call g:Xsetlist([], 'a', {'context':"Context info"})
+ let d = g:Xgetlist({'context':1})
+ call assert_equal("Context info", d.context)
+ call g:Xsetlist([], 'a', {'context':246})
+ let d = g:Xgetlist({'context':1})
+ call assert_equal(246, d.context)
+ if a:cchar == 'l'
+ " Test for copying context across two different location lists
+ new | only
+ let w1_id = win_getid()
+ let l = [1]
+ call setloclist(0, [], 'a', {'context':l})
+ new
+ let w2_id = win_getid()
+ call add(l, 2)
+ call assert_equal([1, 2], getloclist(w1_id, {'context':1}).context)
+ call assert_equal([1, 2], getloclist(w2_id, {'context':1}).context)
+ unlet! l
+ call assert_equal([1, 2], getloclist(w2_id, {'context':1}).context)
+ only
+ call setloclist(0, [], 'f')
+ call assert_equal('', getloclist(0, {'context':1}).context)
+ endif
+
+ " Test for changing the context of previous quickfix lists
+ call g:Xsetlist([], 'f')
+ Xexpr "One"
+ Xexpr "Two"
+ Xexpr "Three"
+ call g:Xsetlist([], 'r', {'context' : [1], 'nr' : 1})
+ call g:Xsetlist([], 'a', {'context' : [2], 'nr' : 2})
+ " Also, check for setting the context using quickfix list number zero.
+ call g:Xsetlist([], 'r', {'context' : [3], 'nr' : 0})
+ call test_garbagecollect_now()
+ let l = g:Xgetlist({'nr' : 1, 'context' : 1})
+ call assert_equal([1], l.context)
+ let l = g:Xgetlist({'nr' : 2, 'context' : 1})
+ call assert_equal([2], l.context)
+ let l = g:Xgetlist({'nr' : 3, 'context' : 1})
+ call assert_equal([3], l.context)
+
+ " Test for changing the context through reference and for garbage
+ " collection of quickfix context
+ let l = ["red"]
+ call g:Xsetlist([], ' ', {'context' : l})
+ call add(l, "blue")
+ let x = g:Xgetlist({'context' : 1})
+ call add(x.context, "green")
+ call assert_equal(["red", "blue", "green"], l)
+ call assert_equal(["red", "blue", "green"], x.context)
+ unlet l
+ call test_garbagecollect_now()
+ let m = g:Xgetlist({'context' : 1})
+ call assert_equal(["red", "blue", "green"], m.context)
+
+ " Test for setting/getting items
+ Xexpr ""
+ let qfprev = g:Xgetlist({'nr':0})
+ let s = g:Xsetlist([], ' ', {'title':'Green',
+ \ 'items' : [{'filename':'F1', 'lnum':10}]})
+ call assert_equal(0, s)
+ let qfcur = g:Xgetlist({'nr':0})
+ call assert_true(qfcur.nr == qfprev.nr + 1)
+ let l = g:Xgetlist({'items':1})
+ call assert_equal('F1', bufname(l.items[0].bufnr))
+ call assert_equal(10, l.items[0].lnum)
+ call g:Xsetlist([], 'a', {'items' : [{'filename':'F2', 'lnum':20},
+ \ {'filename':'F2', 'lnum':30}]})
+ let l = g:Xgetlist({'items':1})
+ call assert_equal('F2', bufname(l.items[2].bufnr))
+ call assert_equal(30, l.items[2].lnum)
+ call g:Xsetlist([], 'r', {'items' : [{'filename':'F3', 'lnum':40}]})
+ let l = g:Xgetlist({'items':1})
+ call assert_equal('F3', bufname(l.items[0].bufnr))
+ call assert_equal(40, l.items[0].lnum)
+ call g:Xsetlist([], 'r', {'items' : []})
+ let l = g:Xgetlist({'items':1})
+ call assert_equal(0, len(l.items))
+
+ call g:Xsetlist([], 'r', {'title' : 'TestTitle'})
+ call g:Xsetlist([], 'r', {'items' : [{'filename' : 'F1', 'lnum' : 10, 'text' : 'L10'}]})
+ call g:Xsetlist([], 'r', {'items' : [{'filename' : 'F1', 'lnum' : 10, 'text' : 'L10'}]})
+ call assert_equal('TestTitle', g:Xgetlist({'title' : 1}).title)
+
+ " Test for getting id of window associated with a location list window
+ if a:cchar == 'l'
+ only
+ call assert_equal(0, g:Xgetlist({'all' : 1}).filewinid)
+ let wid = win_getid()
+ Xopen
+ call assert_equal(wid, g:Xgetlist({'filewinid' : 1}).filewinid)
+ wincmd w
+ call assert_equal(0, g:Xgetlist({'filewinid' : 1}).filewinid)
+ only
+ endif
+
+ " The following used to crash Vim with address sanitizer
+ call g:Xsetlist([], 'f')
+ call g:Xsetlist([], 'a', {'items' : [{'filename':'F1', 'lnum':10}]})
+ call assert_equal(10, g:Xgetlist({'items':1}).items[0].lnum)
+
+ " Try setting the items using a string
+ call assert_equal(-1, g:Xsetlist([], ' ', {'items' : 'Test'}))
+
+ " Save and restore the quickfix stack
+ call g:Xsetlist([], 'f')
+ call assert_equal(0, g:Xgetlist({'nr':'$'}).nr)
+ Xexpr "File1:10:Line1"
+ Xexpr "File2:20:Line2"
+ Xexpr "File3:30:Line3"
+ let last_qf = g:Xgetlist({'nr':'$'}).nr
+ call assert_equal(3, last_qf)
+ let qstack = []
+ for i in range(1, last_qf)
+ let qstack = add(qstack, g:Xgetlist({'nr':i, 'all':1}))
+ endfor
+ call g:Xsetlist([], 'f')
+ for i in range(len(qstack))
+ call g:Xsetlist([], ' ', qstack[i])
+ endfor
+ call assert_equal(3, g:Xgetlist({'nr':'$'}).nr)
+ call assert_equal(10, g:Xgetlist({'nr':1, 'items':1}).items[0].lnum)
+ call assert_equal(20, g:Xgetlist({'nr':2, 'items':1}).items[0].lnum)
+ call assert_equal(30, g:Xgetlist({'nr':3, 'items':1}).items[0].lnum)
+ call g:Xsetlist([], 'f')
+
+ " Swap two quickfix lists
+ Xexpr "File1:10:Line10"
+ Xexpr "File2:20:Line20"
+ Xexpr "File3:30:Line30"
+ call g:Xsetlist([], 'r', {'nr':1,'title':'Colors','context':['Colors']})
+ call g:Xsetlist([], 'r', {'nr':2,'title':'Fruits','context':['Fruits']})
+ let l1=g:Xgetlist({'nr':1,'all':1})
+ let l2=g:Xgetlist({'nr':2,'all':1})
+ let save_id = l1.id
+ let l1.id=l2.id
+ let l2.id=save_id
+ call g:Xsetlist([], 'r', l1)
+ call g:Xsetlist([], 'r', l2)
+ let newl1=g:Xgetlist({'nr':1,'all':1})
+ let newl2=g:Xgetlist({'nr':2,'all':1})
+ call assert_equal('Fruits', newl1.title)
+ call assert_equal(['Fruits'], newl1.context)
+ call assert_equal('Line20', newl1.items[0].text)
+ call assert_equal('Colors', newl2.title)
+ call assert_equal(['Colors'], newl2.context)
+ call assert_equal('Line10', newl2.items[0].text)
+ call g:Xsetlist([], 'f')
+endfunc
+
+func Test_qf_property()
+ call Xproperty_tests('c')
+ call Xproperty_tests('l')
+endfunc
+
+" Test for setting the current index in the location/quickfix list
+func Xtest_setqfidx(cchar)
+ call s:setup_commands(a:cchar)
+
+ Xgetexpr "F1:10:1:Line1\nF2:20:2:Line2\nF3:30:3:Line3"
+ Xgetexpr "F4:10:1:Line1\nF5:20:2:Line2\nF6:30:3:Line3"
+ Xgetexpr "F7:10:1:Line1\nF8:20:2:Line2\nF9:30:3:Line3"
+
+ call g:Xsetlist([], 'a', {'nr' : 3, 'idx' : 2})
+ call g:Xsetlist([], 'a', {'nr' : 2, 'idx' : 2})
+ call g:Xsetlist([], 'a', {'nr' : 1, 'idx' : 3})
+ Xolder 2
+ Xopen
+ call assert_equal(3, line('.'))
+ Xnewer
+ call assert_equal(2, line('.'))
+ Xnewer
+ call assert_equal(2, line('.'))
+ " Update the current index with the quickfix window open
+ wincmd w
+ call g:Xsetlist([], 'a', {'nr' : 3, 'idx' : 3})
+ Xopen
+ call assert_equal(3, line('.'))
+ Xclose
+
+ " Set the current index to the last entry
+ call g:Xsetlist([], 'a', {'nr' : 1, 'idx' : '$'})
+ call assert_equal(3, g:Xgetlist({'nr' : 1, 'idx' : 0}).idx)
+ " A large value should set the index to the last index
+ call g:Xsetlist([], 'a', {'nr' : 1, 'idx' : 1})
+ call g:Xsetlist([], 'a', {'nr' : 1, 'idx' : 999})
+ call assert_equal(3, g:Xgetlist({'nr' : 1, 'idx' : 0}).idx)
+ " Invalid index values
+ call g:Xsetlist([], 'a', {'nr' : 1, 'idx' : -1})
+ call assert_equal(3, g:Xgetlist({'nr' : 1, 'idx' : 0}).idx)
+ call g:Xsetlist([], 'a', {'nr' : 1, 'idx' : 0})
+ call assert_equal(3, g:Xgetlist({'nr' : 1, 'idx' : 0}).idx)
+ call g:Xsetlist([], 'a', {'nr' : 1, 'idx' : 'xx'})
+ call assert_equal(3, g:Xgetlist({'nr' : 1, 'idx' : 0}).idx)
+ call assert_fails("call g:Xsetlist([], 'a', {'nr':1, 'idx':[]})", 'E745:')
+
+ call g:Xsetlist([], 'f')
+ new | only
+endfunc
+
+func Test_setqfidx()
+ call Xtest_setqfidx('c')
+ call Xtest_setqfidx('l')
+endfunc
+
+" Tests for the QuickFixCmdPre/QuickFixCmdPost autocommands
+func QfAutoCmdHandler(loc, cmd)
+ call add(g:acmds, a:loc . a:cmd)
+endfunc
+
+func Test_Autocmd()
+ autocmd QuickFixCmdPre * call QfAutoCmdHandler('pre', expand('<amatch>'))
+ autocmd QuickFixCmdPost * call QfAutoCmdHandler('post', expand('<amatch>'))
+
+ let g:acmds = []
+ cexpr "F1:10:Line 10"
+ caddexpr "F1:20:Line 20"
+ cgetexpr "F1:30:Line 30"
+ cexpr ""
+ caddexpr ""
+ cgetexpr ""
+ silent! cexpr non_existing_func()
+ silent! caddexpr non_existing_func()
+ silent! cgetexpr non_existing_func()
+ let l = ['precexpr',
+ \ 'postcexpr',
+ \ 'precaddexpr',
+ \ 'postcaddexpr',
+ \ 'precgetexpr',
+ \ 'postcgetexpr',
+ \ 'precexpr',
+ \ 'postcexpr',
+ \ 'precaddexpr',
+ \ 'postcaddexpr',
+ \ 'precgetexpr',
+ \ 'postcgetexpr',
+ \ 'precexpr',
+ \ 'precaddexpr',
+ \ 'precgetexpr']
+ call assert_equal(l, g:acmds)
+
+ let g:acmds = []
+ enew! | call append(0, "F2:10:Line 10")
+ cbuffer!
+ enew! | call append(0, "F2:20:Line 20")
+ cgetbuffer
+ enew! | call append(0, "F2:30:Line 30")
+ caddbuffer
+ new
+ let bnum = bufnr('%')
+ bunload
+ exe 'silent! cbuffer! ' . bnum
+ exe 'silent! cgetbuffer ' . bnum
+ exe 'silent! caddbuffer ' . bnum
+ enew!
+ let l = ['precbuffer',
+ \ 'postcbuffer',
+ \ 'precgetbuffer',
+ \ 'postcgetbuffer',
+ \ 'precaddbuffer',
+ \ 'postcaddbuffer',
+ \ 'precbuffer',
+ \ 'precgetbuffer',
+ \ 'precaddbuffer']
+ call assert_equal(l, g:acmds)
+
+ call writefile(['Xtest:1:Line1'], 'Xtest')
+ call writefile([], 'Xempty')
+ let g:acmds = []
+ cfile Xtest
+ caddfile Xtest
+ cgetfile Xtest
+ cfile Xempty
+ caddfile Xempty
+ cgetfile Xempty
+ silent! cfile do_not_exist
+ silent! caddfile do_not_exist
+ silent! cgetfile do_not_exist
+ let l = ['precfile',
+ \ 'postcfile',
+ \ 'precaddfile',
+ \ 'postcaddfile',
+ \ 'precgetfile',
+ \ 'postcgetfile',
+ \ 'precfile',
+ \ 'postcfile',
+ \ 'precaddfile',
+ \ 'postcaddfile',
+ \ 'precgetfile',
+ \ 'postcgetfile',
+ \ 'precfile',
+ \ 'postcfile',
+ \ 'precaddfile',
+ \ 'postcaddfile',
+ \ 'precgetfile',
+ \ 'postcgetfile']
+ call assert_equal(l, g:acmds)
+
+ let g:acmds = []
+ helpgrep quickfix
+ silent! helpgrep non_existing_help_topic
+ vimgrep test Xtest
+ vimgrepadd test Xtest
+ silent! vimgrep non_existing_test Xtest
+ silent! vimgrepadd non_existing_test Xtest
+ set makeprg=
+ silent! make
+ set makeprg&
+ let l = ['prehelpgrep',
+ \ 'posthelpgrep',
+ \ 'prehelpgrep',
+ \ 'posthelpgrep',
+ \ 'previmgrep',
+ \ 'postvimgrep',
+ \ 'previmgrepadd',
+ \ 'postvimgrepadd',
+ \ 'previmgrep',
+ \ 'postvimgrep',
+ \ 'previmgrepadd',
+ \ 'postvimgrepadd',
+ \ 'premake',
+ \ 'postmake']
+ call assert_equal(l, g:acmds)
+
+ if has('unix')
+ " Run this test only on Unix-like systems. The grepprg may not be set on
+ " non-Unix systems.
+ " The following lines are used for the grep test. Don't remove.
+ " Grep_Autocmd_Text: Match 1
+ " GrepAdd_Autocmd_Text: Match 2
+ let g:acmds = []
+ silent grep Grep_Autocmd_Text test_quickfix.vim
+ silent grepadd GrepAdd_Autocmd_Text test_quickfix.vim
+ silent grep abc123def Xtest
+ silent grepadd abc123def Xtest
+ let l = ['pregrep',
+ \ 'postgrep',
+ \ 'pregrepadd',
+ \ 'postgrepadd',
+ \ 'pregrep',
+ \ 'postgrep',
+ \ 'pregrepadd',
+ \ 'postgrepadd']
+ call assert_equal(l, g:acmds)
+ endif
+
+ call delete('Xtest')
+ call delete('Xempty')
+ au! QuickFixCmdPre
+ au! QuickFixCmdPost
+endfunc
+
+func Test_Autocmd_Exception()
+ set efm=%m
+ lgetexpr '?'
+
+ try
+ call DoesNotExit()
+ catch
+ lgetexpr '1'
+ finally
+ lgetexpr '1'
+ endtry
+
+ call assert_equal('1', getloclist(0)[0].text)
+
+ set efm&vim
+endfunc
+
+func Test_caddbuffer_wrong()
+ " This used to cause a memory access in freed memory.
+ let save_efm = &efm
+ set efm=%EEEE%m,%WWWW,%+CCCC%>%#,%GGGG%.#
+ cgetexpr ['WWWW', 'EEEE', 'CCCC']
+ let &efm = save_efm
+ caddbuffer
+ bwipe!
+endfunc
+
+func Test_caddexpr_wrong()
+ " This used to cause a memory access in freed memory.
+ cbuffer
+ cbuffer
+ copen
+ let save_efm = &efm
+ set efm=%
+ call assert_fails('caddexpr ""', 'E376:')
+ let &efm = save_efm
+endfunc
+
+func Test_dirstack_cleanup()
+ " This used to cause a memory access in freed memory.
+ let save_efm = &efm
+ lexpr '0'
+ lopen
+ fun X(c)
+ let save_efm=&efm
+ set efm=%D%f
+ if a:c == 'c'
+ caddexpr '::'
+ else
+ laddexpr ':0:0'
+ endif
+ let &efm=save_efm
+ endfun
+ call X('c')
+ call X('l')
+ call setqflist([], 'r')
+ caddbuffer
+ let &efm = save_efm
+endfunc
+
+" Tests for jumping to entries from the location list window and quickfix
+" window
+func Test_cwindow_jump()
+ set efm=%f%%%l%%%m
+ lgetexpr ["F1%10%Line 10", "F2%20%Line 20", "F3%30%Line 30"]
+ lopen | only
+ lfirst
+ call assert_true(winnr('$') == 2)
+ call assert_true(winnr() == 1)
+ " Location list for the new window should be set
+ call assert_true(getloclist(0)[2].text == 'Line 30')
+
+ " Open a scratch buffer
+ " Open a new window and create a location list
+ " Open the location list window and close the other window
+ " Jump to an entry.
+ " Should create a new window and jump to the entry. The scrtach buffer
+ " should not be used.
+ enew | only
+ set buftype=nofile
+ below new
+ lgetexpr ["F1%10%Line 10", "F2%20%Line 20", "F3%30%Line 30"]
+ lopen
+ 2wincmd c
+ lnext
+ call assert_true(winnr('$') == 3)
+ call assert_true(winnr() == 2)
+
+ " Open two windows with two different location lists
+ " Open the location list window and close the previous window
+ " Jump to an entry in the location list window
+ " Should open the file in the first window and not set the location list.
+ enew | only
+ lgetexpr ["F1%5%Line 5"]
+ below new
+ lgetexpr ["F1%10%Line 10", "F2%20%Line 20", "F3%30%Line 30"]
+ lopen
+ 2wincmd c
+ lnext
+ call assert_true(winnr() == 1)
+ call assert_true(getloclist(0)[0].text == 'Line 5')
+
+ enew | only
+ cgetexpr ["F1%10%Line 10", "F2%20%Line 20", "F3%30%Line 30"]
+ copen
+ cnext
+ call assert_true(winnr('$') == 2)
+ call assert_true(winnr() == 1)
+
+ enew | only
+ set efm&vim
+endfunc
+
+func XvimgrepTests(cchar)
+ call s:setup_commands(a:cchar)
+
+ call writefile(['Editor:VIM vim',
+ \ 'Editor:Emacs EmAcS',
+ \ 'Editor:Notepad NOTEPAD'], 'Xtestfile1')
+ call writefile(['Linux', 'MacOS', 'MS-Windows'], 'Xtestfile2')
+
+ " Error cases
+ call assert_fails('Xvimgrep /abc *', 'E682:')
+
+ let @/=''
+ call assert_fails('Xvimgrep // *', 'E35:')
+
+ call assert_fails('Xvimgrep abc', 'E683:')
+ call assert_fails('Xvimgrep a1b2c3 Xtestfile1', 'E480:')
+ call assert_fails('Xvimgrep pat Xa1b2c3', 'E480:')
+
+ Xexpr ""
+ Xvimgrepadd Notepad Xtestfile1
+ Xvimgrepadd MacOS Xtestfile2
+ let l = g:Xgetlist()
+ call assert_equal(2, len(l))
+ call assert_equal('Editor:Notepad NOTEPAD', l[0].text)
+
+ Xvimgrep #\cvim#g Xtestfile?
+ let l = g:Xgetlist()
+ call assert_equal(2, len(l))
+ call assert_equal(8, l[0].col)
+ call assert_equal(12, l[1].col)
+
+ 1Xvimgrep ?Editor? Xtestfile*
+ let l = g:Xgetlist()
+ call assert_equal(1, len(l))
+ call assert_equal('Editor:VIM vim', l[0].text)
+
+ edit +3 Xtestfile2
+ Xvimgrep +\cemacs+j Xtestfile1
+ let l = g:Xgetlist()
+ call assert_equal('Xtestfile2', bufname(''))
+ call assert_equal('Editor:Emacs EmAcS', l[0].text)
+
+ " Test for unloading a buffer after vimgrep searched the buffer
+ %bwipe
+ Xvimgrep /Editor/j Xtestfile*
+ call assert_equal(0, getbufinfo('Xtestfile1')[0].loaded)
+ call assert_equal([], getbufinfo('Xtestfile2'))
+
+ call delete('Xtestfile1')
+ call delete('Xtestfile2')
+endfunc
+
+" Tests for the :vimgrep command
+func Test_vimgrep()
+ call XvimgrepTests('c')
+ call XvimgrepTests('l')
+endfunc
+
+" Test for incsearch highlighting of the :vimgrep pattern
+" This test used to cause "E315: ml_get: invalid lnum" errors.
+func Test_vimgrep_incsearch()
+ enew
+ set incsearch
+ call test_override("char_avail", 1)
+
+ call feedkeys(":2vimgrep assert test_quickfix.vim test_cdo.vim\<CR>", "ntx")
+ let l = getqflist()
+ call assert_equal(2, len(l))
+
+ call test_override("ALL", 0)
+ set noincsearch
+endfunc
+
+func XfreeTests(cchar)
+ call s:setup_commands(a:cchar)
+
+ enew | only
+
+ " Deleting the quickfix stack should work even When the current list is
+ " somewhere in the middle of the stack
+ Xexpr ['Xfile1:10:10:Line 10', 'Xfile1:15:15:Line 15']
+ Xexpr ['Xfile2:20:20:Line 20', 'Xfile2:25:25:Line 25']
+ Xexpr ['Xfile3:30:30:Line 30', 'Xfile3:35:35:Line 35']
+ Xolder
+ call g:Xsetlist([], 'f')
+ call assert_equal(0, len(g:Xgetlist()))
+
+ " After deleting the stack, adding a new list should create a stack with a
+ " single list.
+ Xexpr ['Xfile1:10:10:Line 10', 'Xfile1:15:15:Line 15']
+ call assert_equal(1, g:Xgetlist({'all':1}).nr)
+
+ " Deleting the stack from a quickfix window should update/clear the
+ " quickfix/location list window.
+ Xexpr ['Xfile1:10:10:Line 10', 'Xfile1:15:15:Line 15']
+ Xexpr ['Xfile2:20:20:Line 20', 'Xfile2:25:25:Line 25']
+ Xexpr ['Xfile3:30:30:Line 30', 'Xfile3:35:35:Line 35']
+ Xolder
+ Xwindow
+ call g:Xsetlist([], 'f')
+ call assert_equal(2, winnr('$'))
+ call assert_equal(1, line('$'))
+ Xclose
+
+ " Deleting the stack from a non-quickfix window should update/clear the
+ " quickfix/location list window.
+ Xexpr ['Xfile1:10:10:Line 10', 'Xfile1:15:15:Line 15']
+ Xexpr ['Xfile2:20:20:Line 20', 'Xfile2:25:25:Line 25']
+ Xexpr ['Xfile3:30:30:Line 30', 'Xfile3:35:35:Line 35']
+ Xolder
+ Xwindow
+ wincmd p
+ call g:Xsetlist([], 'f')
+ call assert_equal(0, len(g:Xgetlist()))
+ wincmd p
+ call assert_equal(2, winnr('$'))
+ call assert_equal(1, line('$'))
+
+ " After deleting the location list stack, if the location list window is
+ " opened, then a new location list should be created. So opening the
+ " location list window again should not create a new window.
+ if a:cchar == 'l'
+ lexpr ['Xfile1:10:10:Line 10', 'Xfile1:15:15:Line 15']
+ wincmd p
+ lopen
+ call assert_equal(2, winnr('$'))
+ endif
+ Xclose
+endfunc
+
+" Tests for the quickfix free functionality
+func Test_qf_free()
+ call XfreeTests('c')
+ call XfreeTests('l')
+endfunc
+
+" Test for buffer overflow when parsing lines and adding new entries to
+" the quickfix list.
+func Test_bufoverflow()
+ set efm=%f:%l:%m
+ cgetexpr ['File1:100:' . repeat('x', 1025)]
+
+ set efm=%+GCompiler:\ %.%#,%f:%l:%m
+ cgetexpr ['Compiler: ' . repeat('a', 1015), 'File1:10:Hello World']
+
+ set efm=%DEntering\ directory\ %f,%f:%l:%m
+ cgetexpr ['Entering directory ' . repeat('a', 1006),
+ \ 'File1:10:Hello World']
+ set efm&vim
+endfunc
+
+" Tests for getting the quickfix stack size
+func XsizeTests(cchar)
+ call s:setup_commands(a:cchar)
+
+ call g:Xsetlist([], 'f')
+ call assert_equal(0, g:Xgetlist({'nr':'$'}).nr)
+ call assert_equal('', g:Xgetlist({'nr':'$', 'all':1}).title)
+ call assert_equal(0, g:Xgetlist({'nr':0}).nr)
+
+ Xexpr "File1:10:Line1"
+ Xexpr "File2:20:Line2"
+ Xexpr "File3:30:Line3"
+ Xolder | Xolder
+ call assert_equal(3, g:Xgetlist({'nr':'$'}).nr)
+ call g:Xsetlist([], 'f')
+
+ Xexpr "File1:10:Line1"
+ Xexpr "File2:20:Line2"
+ Xexpr "File3:30:Line3"
+ Xolder | Xolder
+ call g:Xsetlist([], 'a', {'nr':'$', 'title':'Compiler'})
+ call assert_equal('Compiler', g:Xgetlist({'nr':3, 'all':1}).title)
+endfunc
+
+func Test_Qf_Size()
+ call XsizeTests('c')
+ call XsizeTests('l')
+endfunc
+
+func Test_cclose_from_copen()
+ augroup QF_Test
+ au!
+ au FileType qf :call assert_fails(':cclose', 'E788')
+ augroup END
+ copen
+ augroup QF_Test
+ au!
+ augroup END
+ augroup! QF_Test
+endfunc
+
+func Test_cclose_in_autocmd()
+ " Problem is only triggered if "starting" is zero, so that the OptionsSet
+ " event will be triggered.
+ call test_override('starting', 1)
+ augroup QF_Test
+ au!
+ au FileType qf :call assert_fails(':cclose', 'E788')
+ augroup END
+ copen
+ augroup QF_Test
+ au!
+ augroup END
+ augroup! QF_Test
+ call test_override('starting', 0)
+endfunc
+
+" Check that ":file" without an argument is possible even when "curbuf_lock"
+" is set.
+func Test_file_from_copen()
+ " Works without argument.
+ augroup QF_Test
+ au!
+ au FileType qf file
+ augroup END
+ copen
+
+ augroup QF_Test
+ au!
+ augroup END
+ cclose
+
+ " Fails with argument.
+ augroup QF_Test
+ au!
+ au FileType qf call assert_fails(':file foo', 'E788')
+ augroup END
+ copen
+ augroup QF_Test
+ au!
+ augroup END
+ cclose
+
+ augroup! QF_Test
+endfunction
+
+func Test_resize_from_copen()
+ augroup QF_Test
+ au!
+ au FileType qf resize 5
+ augroup END
+ try
+ " This should succeed without any exception. No other buffers are
+ " involved in the autocmd.
+ copen
+ finally
+ augroup QF_Test
+ au!
+ augroup END
+ augroup! QF_Test
+ endtry
+endfunc
+
+" Tests for the quickfix buffer b:changedtick variable
+func Xchangedtick_tests(cchar)
+ call s:setup_commands(a:cchar)
+
+ new | only
+
+ Xexpr "" | Xexpr "" | Xexpr ""
+
+ Xopen
+ Xolder
+ Xolder
+ Xaddexpr "F1:10:Line10"
+ Xaddexpr "F2:20:Line20"
+ call g:Xsetlist([{"filename":"F3", "lnum":30, "text":"Line30"}], 'a')
+ call g:Xsetlist([], 'f')
+ call assert_equal(8, getbufvar('%', 'changedtick'))
+ Xclose
+endfunc
+
+func Test_changedtick()
+ call Xchangedtick_tests('c')
+ call Xchangedtick_tests('l')
+endfunc
+
+" Tests for parsing an expression using setqflist()
+func Xsetexpr_tests(cchar)
+ call s:setup_commands(a:cchar)
+
+ let t = ["File1:10:Line10", "File1:20:Line20"]
+ call g:Xsetlist([], ' ', {'lines' : t})
+ call g:Xsetlist([], 'a', {'lines' : ["File1:30:Line30"]})
+
+ let l = g:Xgetlist()
+ call assert_equal(3, len(l))
+ call assert_equal(20, l[1].lnum)
+ call assert_equal('Line30', l[2].text)
+ call g:Xsetlist([], 'r', {'lines' : ["File2:5:Line5"]})
+ let l = g:Xgetlist()
+ call assert_equal(1, len(l))
+ call assert_equal('Line5', l[0].text)
+ call assert_equal(-1, g:Xsetlist([], 'a', {'lines' : 10}))
+ call assert_equal(-1, g:Xsetlist([], 'a', {'lines' : "F1:10:L10"}))
+
+ call g:Xsetlist([], 'f')
+ " Add entries to multiple lists
+ call g:Xsetlist([], 'a', {'nr' : 1, 'lines' : ["File1:10:Line10"]})
+ call g:Xsetlist([], 'a', {'nr' : 2, 'lines' : ["File2:20:Line20"]})
+ call g:Xsetlist([], 'a', {'nr' : 1, 'lines' : ["File1:15:Line15"]})
+ call g:Xsetlist([], 'a', {'nr' : 2, 'lines' : ["File2:25:Line25"]})
+ call assert_equal('Line15', g:Xgetlist({'nr':1, 'items':1}).items[1].text)
+ call assert_equal('Line25', g:Xgetlist({'nr':2, 'items':1}).items[1].text)
+
+ " Adding entries using a custom efm
+ set efm&
+ call g:Xsetlist([], ' ', {'efm' : '%f#%l#%m',
+ \ 'lines' : ["F1#10#L10", "F2#20#L20"]})
+ call assert_equal(20, g:Xgetlist({'items':1}).items[1].lnum)
+ call g:Xsetlist([], 'a', {'efm' : '%f#%l#%m', 'lines' : ["F3:30:L30"]})
+ call assert_equal('F3:30:L30', g:Xgetlist({'items':1}).items[2].text)
+ call assert_equal(20, g:Xgetlist({'items':1}).items[1].lnum)
+ call assert_equal(-1, g:Xsetlist([], 'a', {'efm' : [],
+ \ 'lines' : ['F1:10:L10']}))
+endfunc
+
+func Test_setexpr()
+ call Xsetexpr_tests('c')
+ call Xsetexpr_tests('l')
+endfunc
+
+" Tests for per quickfix/location list directory stack
+func Xmultidirstack_tests(cchar)
+ call s:setup_commands(a:cchar)
+
+ call g:Xsetlist([], 'f')
+ Xexpr "" | Xexpr ""
+
+ call g:Xsetlist([], 'a', {'nr' : 1, 'lines' : ["Entering dir 'Xone/a'"]})
+ call g:Xsetlist([], 'a', {'nr' : 2, 'lines' : ["Entering dir 'Xtwo/a'"]})
+ call g:Xsetlist([], 'a', {'nr' : 1, 'lines' : ["one.txt:3:one one one"]})
+ call g:Xsetlist([], 'a', {'nr' : 2, 'lines' : ["two.txt:5:two two two"]})
+
+ let l1 = g:Xgetlist({'nr':1, 'items':1})
+ let l2 = g:Xgetlist({'nr':2, 'items':1})
+ call assert_equal('Xone/a/one.txt', bufname(l1.items[1].bufnr))
+ call assert_equal(3, l1.items[1].lnum)
+ call assert_equal('Xtwo/a/two.txt', bufname(l2.items[1].bufnr))
+ call assert_equal(5, l2.items[1].lnum)
+endfunc
+
+func Test_multidirstack()
+ call mkdir('Xone/a', 'p')
+ call mkdir('Xtwo/a', 'p')
+ let lines = ['1', '2', 'one one one', '4', 'two two two', '6', '7']
+ call writefile(lines, 'Xone/a/one.txt')
+ call writefile(lines, 'Xtwo/a/two.txt')
+ let save_efm = &efm
+ set efm=%DEntering\ dir\ '%f',%f:%l:%m,%XLeaving\ dir\ '%f'
+
+ call Xmultidirstack_tests('c')
+ call Xmultidirstack_tests('l')
+
+ let &efm = save_efm
+ call delete('Xone', 'rf')
+ call delete('Xtwo', 'rf')
+endfunc
+
+" Tests for per quickfix/location list file stack
+func Xmultifilestack_tests(cchar)
+ call s:setup_commands(a:cchar)
+
+ call g:Xsetlist([], 'f')
+ Xexpr "" | Xexpr ""
+
+ call g:Xsetlist([], 'a', {'nr' : 1, 'lines' : ["[one.txt]"]})
+ call g:Xsetlist([], 'a', {'nr' : 2, 'lines' : ["[two.txt]"]})
+ call g:Xsetlist([], 'a', {'nr' : 1, 'lines' : ["(3,5) one one one"]})
+ call g:Xsetlist([], 'a', {'nr' : 2, 'lines' : ["(5,9) two two two"]})
+
+ let l1 = g:Xgetlist({'nr':1, 'items':1})
+ let l2 = g:Xgetlist({'nr':2, 'items':1})
+ call assert_equal('one.txt', bufname(l1.items[1].bufnr))
+ call assert_equal(3, l1.items[1].lnum)
+ call assert_equal('two.txt', bufname(l2.items[1].bufnr))
+ call assert_equal(5, l2.items[1].lnum)
+
+ " Test for start of a new error line in the same line where a previous
+ " error line ends with a file stack.
+ let efm_val = 'Error\ l%l\ in\ %f,'
+ let efm_val .= '%-P%>(%f%r,Error\ l%l\ in\ %m,%-Q)%r'
+ let l = g:Xgetlist({'lines' : [
+ \ '(one.txt',
+ \ 'Error l4 in one.txt',
+ \ ') (two.txt',
+ \ 'Error l6 in two.txt',
+ \ ')',
+ \ 'Error l8 in one.txt'
+ \ ], 'efm' : efm_val})
+ call assert_equal(3, len(l.items))
+ call assert_equal('one.txt', bufname(l.items[0].bufnr))
+ call assert_equal(4, l.items[0].lnum)
+ call assert_equal('one.txt', l.items[0].text)
+ call assert_equal('two.txt', bufname(l.items[1].bufnr))
+ call assert_equal(6, l.items[1].lnum)
+ call assert_equal('two.txt', l.items[1].text)
+ call assert_equal('one.txt', bufname(l.items[2].bufnr))
+ call assert_equal(8, l.items[2].lnum)
+ call assert_equal('', l.items[2].text)
+endfunc
+
+func Test_multifilestack()
+ let lines = ['1', '2', 'one one one', '4', 'two two two', '6', '7']
+ call writefile(lines, 'one.txt')
+ call writefile(lines, 'two.txt')
+ let save_efm = &efm
+ set efm=%+P[%f],(%l\\,%c)\ %m,%-Q
+
+ call Xmultifilestack_tests('c')
+ call Xmultifilestack_tests('l')
+
+ let &efm = save_efm
+ call delete('one.txt')
+ call delete('two.txt')
+endfunc
+
+" Tests for per buffer 'efm' setting
+func Test_perbuf_efm()
+ call writefile(["File1-10-Line10"], 'one.txt')
+ call writefile(["File2#20#Line20"], 'two.txt')
+ set efm=%f#%l#%m
+ new | only
+ new
+ setlocal efm=%f-%l-%m
+ cfile one.txt
+ wincmd w
+ caddfile two.txt
+
+ let l = getqflist()
+ call assert_equal(10, l[0].lnum)
+ call assert_equal('Line20', l[1].text)
+
+ set efm&
+ new | only
+ call delete('one.txt')
+ call delete('two.txt')
+endfunc
+
+" Open multiple help windows using ":lhelpgrep
+" This test used to crash Vim
+func Test_Multi_LL_Help()
+ new | only
+ lhelpgrep window
+ lopen
+ e#
+ lhelpgrep buffer
+ call assert_equal(3, winnr('$'))
+ call assert_true(len(getloclist(1)) != 0)
+ call assert_true(len(getloclist(2)) != 0)
+ new | only
+endfunc
+
+" Tests for adding new quickfix lists using setqflist()
+func XaddQf_tests(cchar)
+ call s:setup_commands(a:cchar)
+
+ " Create a new list using ' ' for action
+ call g:Xsetlist([], 'f')
+ call g:Xsetlist([], ' ', {'title' : 'Test1'})
+ let l = g:Xgetlist({'nr' : '$', 'all' : 1})
+ call assert_equal(1, l.nr)
+ call assert_equal('Test1', l.title)
+
+ " Create a new list using ' ' for action and '$' for 'nr'
+ call g:Xsetlist([], 'f')
+ call g:Xsetlist([], ' ', {'title' : 'Test2', 'nr' : '$'})
+ let l = g:Xgetlist({'nr' : '$', 'all' : 1})
+ call assert_equal(1, l.nr)
+ call assert_equal('Test2', l.title)
+
+ " Create a new list using 'a' for action
+ call g:Xsetlist([], 'f')
+ call g:Xsetlist([], 'a', {'title' : 'Test3'})
+ let l = g:Xgetlist({'nr' : '$', 'all' : 1})
+ call assert_equal(1, l.nr)
+ call assert_equal('Test3', l.title)
+
+ " Create a new list using 'a' for action and '$' for 'nr'
+ call g:Xsetlist([], 'f')
+ call g:Xsetlist([], 'a', {'title' : 'Test3', 'nr' : '$'})
+ call g:Xsetlist([], 'a', {'title' : 'Test4'})
+ let l = g:Xgetlist({'nr' : '$', 'all' : 1})
+ call assert_equal(1, l.nr)
+ call assert_equal('Test4', l.title)
+
+ " Adding a quickfix list should remove all the lists following the current
+ " list.
+ Xexpr "" | Xexpr "" | Xexpr ""
+ silent! 10Xolder
+ call g:Xsetlist([], ' ', {'title' : 'Test5'})
+ let l = g:Xgetlist({'nr' : '$', 'all' : 1})
+ call assert_equal(2, l.nr)
+ call assert_equal('Test5', l.title)
+
+ " Add a quickfix list using '$' as the list number.
+ let lastqf = g:Xgetlist({'nr':'$'}).nr
+ silent! 99Xolder
+ call g:Xsetlist([], ' ', {'nr' : '$', 'title' : 'Test6'})
+ let l = g:Xgetlist({'nr' : '$', 'all' : 1})
+ call assert_equal(lastqf + 1, l.nr)
+ call assert_equal('Test6', l.title)
+
+ " Add a quickfix list using 'nr' set to one more than the quickfix
+ " list size.
+ let lastqf = g:Xgetlist({'nr':'$'}).nr
+ silent! 99Xolder
+ call g:Xsetlist([], ' ', {'nr' : lastqf + 1, 'title' : 'Test7'})
+ let l = g:Xgetlist({'nr' : '$', 'all' : 1})
+ call assert_equal(lastqf + 1, l.nr)
+ call assert_equal('Test7', l.title)
+
+ " Add a quickfix list to a stack with 10 lists using 'nr' set to '$'
+ exe repeat('Xexpr "" |', 9) . 'Xexpr ""'
+ silent! 99Xolder
+ call g:Xsetlist([], ' ', {'nr' : '$', 'title' : 'Test8'})
+ let l = g:Xgetlist({'nr' : '$', 'all' : 1})
+ call assert_equal(10, l.nr)
+ call assert_equal('Test8', l.title)
+
+ " Add a quickfix list using 'nr' set to a value greater than 10
+ call assert_equal(-1, g:Xsetlist([], ' ', {'nr' : 12, 'title' : 'Test9'}))
+
+ " Try adding a quickfix list with 'nr' set to a value greater than the
+ " quickfix list size but less than 10.
+ call g:Xsetlist([], 'f')
+ Xexpr "" | Xexpr "" | Xexpr ""
+ silent! 99Xolder
+ call assert_equal(-1, g:Xsetlist([], ' ', {'nr' : 8, 'title' : 'Test10'}))
+
+ " Add a quickfix list using 'nr' set to a some string or list
+ call assert_equal(-1, g:Xsetlist([], ' ', {'nr' : [1,2], 'title' : 'Test11'}))
+endfunc
+
+func Test_add_qf()
+ call XaddQf_tests('c')
+ call XaddQf_tests('l')
+endfunc
+
+" Test for getting the quickfix list items from some text without modifying
+" the quickfix stack
+func XgetListFromLines(cchar)
+ call s:setup_commands(a:cchar)
+ call g:Xsetlist([], 'f')
+
+ let l = g:Xgetlist({'lines' : ["File2:20:Line20", "File2:30:Line30"]}).items
+ call assert_equal(2, len(l))
+ call assert_equal(30, l[1].lnum)
+
+ call assert_equal({}, g:Xgetlist({'lines' : 10}))
+ call assert_equal({}, g:Xgetlist({'lines' : 'File1:10:Line10'}))
+ call assert_equal([], g:Xgetlist({'lines' : []}).items)
+ call assert_equal([], g:Xgetlist({'lines' : [10, 20]}).items)
+
+ " Parse text using a custom efm
+ set efm&
+ let l = g:Xgetlist({'lines':['File3#30#Line30'], 'efm' : '%f#%l#%m'}).items
+ call assert_equal('Line30', l[0].text)
+ let l = g:Xgetlist({'lines':['File3:30:Line30'], 'efm' : '%f-%l-%m'}).items
+ call assert_equal('File3:30:Line30', l[0].text)
+ let l = g:Xgetlist({'lines':['File3:30:Line30'], 'efm' : [1,2]})
+ call assert_equal({}, l)
+ call assert_fails("call g:Xgetlist({'lines':['abc'], 'efm':'%2'})", 'E376:')
+ call assert_fails("call g:Xgetlist({'lines':['abc'], 'efm':''})", 'E378:')
+
+ " Make sure that the quickfix stack is not modified
+ call assert_equal(0, g:Xgetlist({'nr' : '$'}).nr)
+endfunc
+
+func Test_get_list_from_lines()
+ call XgetListFromLines('c')
+ call XgetListFromLines('l')
+endfunc
+
+" Tests for the quickfix list id
+func Xqfid_tests(cchar)
+ call s:setup_commands(a:cchar)
+
+ call g:Xsetlist([], 'f')
+ call assert_equal(0, g:Xgetlist({'id':0}).id)
+ Xexpr ''
+ let start_id = g:Xgetlist({'id' : 0}).id
+ Xexpr '' | Xexpr ''
+ Xolder
+ call assert_equal(start_id, g:Xgetlist({'id':0, 'nr':1}).id)
+ call assert_equal(start_id + 1, g:Xgetlist({'id':0, 'nr':0}).id)
+ call assert_equal(start_id + 2, g:Xgetlist({'id':0, 'nr':'$'}).id)
+ call assert_equal(0, g:Xgetlist({'id':0, 'nr':99}).id)
+ call assert_equal(2, g:Xgetlist({'id':start_id + 1, 'nr':0}).nr)
+ call assert_equal(0, g:Xgetlist({'id':99, 'nr':0}).id)
+ call assert_equal(0, g:Xgetlist({'id':"abc", 'nr':0}).id)
+
+ call g:Xsetlist([], 'a', {'id':start_id, 'context':[1,2]})
+ call assert_equal([1,2], g:Xgetlist({'nr':1, 'context':1}).context)
+ call g:Xsetlist([], 'a', {'id':start_id+1, 'lines':['F1:10:L10']})
+ call assert_equal('L10', g:Xgetlist({'nr':2, 'items':1}).items[0].text)
+ call assert_equal(-1, g:Xsetlist([], 'a', {'id':999, 'title':'Vim'}))
+ call assert_equal(-1, g:Xsetlist([], 'a', {'id':'abc', 'title':'Vim'}))
+
+ let qfid = g:Xgetlist({'id':0, 'nr':0})
+ call g:Xsetlist([], 'f')
+ call assert_equal(0, g:Xgetlist({'id':qfid, 'nr':0}).id)
+endfunc
+
+func Test_qf_id()
+ call Xqfid_tests('c')
+ call Xqfid_tests('l')
+endfunc
+
+func Xqfjump_tests(cchar)
+ call s:setup_commands(a:cchar)
+
+ call writefile(["Line1\tFoo", "Line2"], 'F1')
+ call writefile(["Line1\tBar", "Line2"], 'F2')
+ call writefile(["Line1\tBaz", "Line2"], 'F3')
+
+ call g:Xsetlist([], 'f')
+
+ " Tests for
+ " Jumping to a line using a pattern
+ " Jumping to a column greater than the last column in a line
+ " Jumping to a line greater than the last line in the file
+ let l = []
+ for i in range(1, 7)
+ call add(l, {})
+ endfor
+ let l[0].filename='F1'
+ let l[0].pattern='Line1'
+ let l[1].filename='F2'
+ let l[1].pattern='Line1'
+ let l[2].filename='F3'
+ let l[2].pattern='Line1'
+ let l[3].filename='F3'
+ let l[3].lnum=1
+ let l[3].col=9
+ let l[3].vcol=1
+ let l[4].filename='F3'
+ let l[4].lnum=99
+ let l[5].filename='F3'
+ let l[5].lnum=1
+ let l[5].col=99
+ let l[5].vcol=1
+ let l[6].filename='F3'
+ let l[6].pattern='abcxyz'
+
+ call g:Xsetlist([], ' ', {'items' : l})
+ Xopen | only
+ 2Xnext
+ call assert_equal(3, g:Xgetlist({'idx' : 0}).idx)
+ call assert_equal('F3', bufname('%'))
+ Xnext
+ call assert_equal(7, col('.'))
+ Xnext
+ call assert_equal(2, line('.'))
+ Xnext
+ call assert_equal(9, col('.'))
+ 2
+ Xnext
+ call assert_equal(2, line('.'))
+
+ if a:cchar == 'l'
+ " When jumping to a location list entry in the location list window and
+ " no usable windows are available, then a new window should be opened.
+ enew! | new | only
+ call g:Xsetlist([], 'f')
+ setlocal buftype=nofile
+ new
+ call g:Xsetlist([], ' ', {'lines' : ['F1:1:1:Line1', 'F1:2:2:Line2', 'F2:1:1:Line1', 'F2:2:2:Line2', 'F3:1:1:Line1', 'F3:2:2:Line2']})
+ Xopen
+ let winid = win_getid()
+ wincmd p
+ close
+ call win_gotoid(winid)
+ Xnext
+ call assert_equal(3, winnr('$'))
+ call assert_equal(1, winnr())
+ call assert_equal(2, line('.'))
+
+ " When jumping to an entry in the location list window and the window
+ " associated with the location list is not present and a window containing
+ " the file is already present, then that window should be used.
+ close
+ belowright new
+ call g:Xsetlist([], 'f')
+ edit F3
+ call win_gotoid(winid)
+ Xlast
+ call assert_equal(3, winnr())
+ call assert_equal(6, g:Xgetlist({'size' : 1}).size)
+ call assert_equal(winid, g:Xgetlist({'winid' : 1}).winid)
+ endif
+
+ " Cleanup
+ enew!
+ new | only
+
+ call delete('F1')
+ call delete('F2')
+ call delete('F3')
+endfunc
+
+func Test_qfjump()
+ call Xqfjump_tests('c')
+ call Xqfjump_tests('l')
+endfunc
+
+" Tests for the getqflist() and getloclist() functions when the list is not
+" present or is empty
+func Xgetlist_empty_tests(cchar)
+ call s:setup_commands(a:cchar)
+
+ " Empty quickfix stack
+ call g:Xsetlist([], 'f')
+ call assert_equal('', g:Xgetlist({'context' : 0}).context)
+ call assert_equal(0, g:Xgetlist({'id' : 0}).id)
+ call assert_equal(0, g:Xgetlist({'idx' : 0}).idx)
+ call assert_equal([], g:Xgetlist({'items' : 0}).items)
+ call assert_equal(0, g:Xgetlist({'nr' : 0}).nr)
+ call assert_equal(0, g:Xgetlist({'size' : 0}).size)
+ call assert_equal('', g:Xgetlist({'title' : 0}).title)
+ call assert_equal(0, g:Xgetlist({'winid' : 0}).winid)
+ call assert_equal(0, g:Xgetlist({'changedtick' : 0}).changedtick)
+ if a:cchar == 'c'
+ call assert_equal({'context' : '', 'id' : 0, 'idx' : 0,
+ \ 'items' : [], 'nr' : 0, 'size' : 0,
+ \ 'title' : '', 'winid' : 0, 'changedtick': 0},
+ \ g:Xgetlist({'all' : 0}))
+ else
+ call assert_equal({'context' : '', 'id' : 0, 'idx' : 0,
+ \ 'items' : [], 'nr' : 0, 'size' : 0, 'title' : '',
+ \ 'winid' : 0, 'changedtick': 0, 'filewinid' : 0},
+ \ g:Xgetlist({'all' : 0}))
+ endif
+
+ " Quickfix window with empty stack
+ silent! Xopen
+ let qfwinid = (a:cchar == 'c') ? win_getid() : 0
+ call assert_equal(qfwinid, g:Xgetlist({'winid' : 0}).winid)
+ Xclose
+
+ " Empty quickfix list
+ Xexpr ""
+ call assert_equal('', g:Xgetlist({'context' : 0}).context)
+ call assert_notequal(0, g:Xgetlist({'id' : 0}).id)
+ call assert_equal(0, g:Xgetlist({'idx' : 0}).idx)
+ call assert_equal([], g:Xgetlist({'items' : 0}).items)
+ call assert_notequal(0, g:Xgetlist({'nr' : 0}).nr)
+ call assert_equal(0, g:Xgetlist({'size' : 0}).size)
+ call assert_notequal('', g:Xgetlist({'title' : 0}).title)
+ call assert_equal(0, g:Xgetlist({'winid' : 0}).winid)
+ call assert_equal(1, g:Xgetlist({'changedtick' : 0}).changedtick)
+
+ let qfid = g:Xgetlist({'id' : 0}).id
+ call g:Xsetlist([], 'f')
+
+ " Non-existing quickfix identifier
+ call assert_equal('', g:Xgetlist({'id' : qfid, 'context' : 0}).context)
+ call assert_equal(0, g:Xgetlist({'id' : qfid}).id)
+ call assert_equal(0, g:Xgetlist({'id' : qfid, 'idx' : 0}).idx)
+ call assert_equal([], g:Xgetlist({'id' : qfid, 'items' : 0}).items)
+ call assert_equal(0, g:Xgetlist({'id' : qfid, 'nr' : 0}).nr)
+ call assert_equal(0, g:Xgetlist({'id' : qfid, 'size' : 0}).size)
+ call assert_equal('', g:Xgetlist({'id' : qfid, 'title' : 0}).title)
+ call assert_equal(0, g:Xgetlist({'id' : qfid, 'winid' : 0}).winid)
+ call assert_equal(0, g:Xgetlist({'id' : qfid, 'changedtick' : 0}).changedtick)
+ if a:cchar == 'c'
+ call assert_equal({'context' : '', 'id' : 0, 'idx' : 0, 'items' : [],
+ \ 'nr' : 0, 'size' : 0, 'title' : '', 'winid' : 0,
+ \ 'changedtick' : 0}, g:Xgetlist({'id' : qfid, 'all' : 0}))
+ else
+ call assert_equal({'context' : '', 'id' : 0, 'idx' : 0, 'items' : [],
+ \ 'nr' : 0, 'size' : 0, 'title' : '', 'winid' : 0,
+ \ 'changedtick' : 0, 'filewinid' : 0},
+ \ g:Xgetlist({'id' : qfid, 'all' : 0}))
+ endif
+
+ " Non-existing quickfix list number
+ call assert_equal('', g:Xgetlist({'nr' : 5, 'context' : 0}).context)
+ call assert_equal(0, g:Xgetlist({'nr' : 5}).nr)
+ call assert_equal(0, g:Xgetlist({'nr' : 5, 'idx' : 0}).idx)
+ call assert_equal([], g:Xgetlist({'nr' : 5, 'items' : 0}).items)
+ call assert_equal(0, g:Xgetlist({'nr' : 5, 'id' : 0}).id)
+ call assert_equal(0, g:Xgetlist({'nr' : 5, 'size' : 0}).size)
+ call assert_equal('', g:Xgetlist({'nr' : 5, 'title' : 0}).title)
+ call assert_equal(0, g:Xgetlist({'nr' : 5, 'winid' : 0}).winid)
+ call assert_equal(0, g:Xgetlist({'nr' : 5, 'changedtick' : 0}).changedtick)
+ if a:cchar == 'c'
+ call assert_equal({'context' : '', 'id' : 0, 'idx' : 0, 'items' : [],
+ \ 'nr' : 0, 'size' : 0, 'title' : '', 'winid' : 0,
+ \ 'changedtick' : 0}, g:Xgetlist({'nr' : 5, 'all' : 0}))
+ else
+ call assert_equal({'context' : '', 'id' : 0, 'idx' : 0, 'items' : [],
+ \ 'nr' : 0, 'size' : 0, 'title' : '', 'winid' : 0,
+ \ 'changedtick' : 0, 'filewinid' : 0},
+ \ g:Xgetlist({'nr' : 5, 'all' : 0}))
+ endif
+endfunc
+
+func Test_getqflist()
+ call Xgetlist_empty_tests('c')
+ call Xgetlist_empty_tests('l')
+endfunc
+
+func Test_getqflist_invalid_nr()
+ " The following commands used to crash Vim
+ cexpr ""
+ call getqflist({'nr' : $XXX_DOES_NOT_EXIST_XXX})
+
+ " Cleanup
+ call setqflist([], 'r')
+endfunc
+
+" Tests for the quickfix/location list changedtick
+func Xqftick_tests(cchar)
+ call s:setup_commands(a:cchar)
+
+ call g:Xsetlist([], 'f')
+
+ Xexpr "F1:10:Line10"
+ let qfid = g:Xgetlist({'id' : 0}).id
+ call assert_equal(1, g:Xgetlist({'changedtick' : 0}).changedtick)
+ Xaddexpr "F2:20:Line20\nF2:21:Line21"
+ call assert_equal(2, g:Xgetlist({'changedtick' : 0}).changedtick)
+ call g:Xsetlist([], 'a', {'lines' : ["F3:30:Line30", "F3:31:Line31"]})
+ call assert_equal(3, g:Xgetlist({'changedtick' : 0}).changedtick)
+ call g:Xsetlist([], 'r', {'lines' : ["F4:40:Line40"]})
+ call assert_equal(4, g:Xgetlist({'changedtick' : 0}).changedtick)
+ call g:Xsetlist([], 'a', {'title' : 'New Title'})
+ call assert_equal(5, g:Xgetlist({'changedtick' : 0}).changedtick)
+
+ enew!
+ call append(0, ["F5:50:L50", "F6:60:L60"])
+ Xaddbuffer
+ call assert_equal(6, g:Xgetlist({'changedtick' : 0}).changedtick)
+ enew!
+
+ call g:Xsetlist([], 'a', {'context' : {'bus' : 'pci'}})
+ call assert_equal(7, g:Xgetlist({'changedtick' : 0}).changedtick)
+ call g:Xsetlist([{'filename' : 'F7', 'lnum' : 10, 'text' : 'L7'},
+ \ {'filename' : 'F7', 'lnum' : 11, 'text' : 'L11'}], 'a')
+ call assert_equal(8, g:Xgetlist({'changedtick' : 0}).changedtick)
+ call g:Xsetlist([{'filename' : 'F7', 'lnum' : 10, 'text' : 'L7'},
+ \ {'filename' : 'F7', 'lnum' : 11, 'text' : 'L11'}], ' ')
+ call assert_equal(1, g:Xgetlist({'changedtick' : 0}).changedtick)
+ call g:Xsetlist([{'filename' : 'F7', 'lnum' : 10, 'text' : 'L7'},
+ \ {'filename' : 'F7', 'lnum' : 11, 'text' : 'L11'}], 'r')
+ call assert_equal(2, g:Xgetlist({'changedtick' : 0}).changedtick)
+
+ call writefile(["F8:80:L80", "F8:81:L81"], "Xone")
+ Xfile Xone
+ call assert_equal(1, g:Xgetlist({'changedtick' : 0}).changedtick)
+ Xaddfile Xone
+ call assert_equal(2, g:Xgetlist({'changedtick' : 0}).changedtick)
+
+ " Test case for updating a non-current quickfix list
+ call g:Xsetlist([], 'f')
+ Xexpr "F1:1:L1"
+ Xexpr "F2:2:L2"
+ call g:Xsetlist([], 'a', {'nr' : 1, "lines" : ["F10:10:L10"]})
+ call assert_equal(1, g:Xgetlist({'changedtick' : 0}).changedtick)
+ call assert_equal(2, g:Xgetlist({'nr' : 1, 'changedtick' : 0}).changedtick)
+
+ call delete("Xone")
+endfunc
+
+func Test_qf_tick()
+ call Xqftick_tests('c')
+ call Xqftick_tests('l')
+endfunc
+
+" Test helpgrep with lang specifier
+func Xtest_helpgrep_with_lang_specifier(cchar)
+ call s:setup_commands(a:cchar)
+ Xhelpgrep Vim@en
+ call assert_equal('help', &filetype)
+ call assert_notequal(0, g:Xgetlist({'nr' : '$'}).nr)
+ new | only
+endfunc
+
+func Test_helpgrep_with_lang_specifier()
+ call Xtest_helpgrep_with_lang_specifier('c')
+ call Xtest_helpgrep_with_lang_specifier('l')
+endfunc
+
+" The following test used to crash Vim.
+" Open the location list window and close the regular window associated with
+" the location list. When the garbage collection runs now, it incorrectly
+" marks the location list context as not in use and frees the context.
+func Test_ll_window_ctx()
+ call setloclist(0, [], 'f')
+ call setloclist(0, [], 'a', {'context' : []})
+ lopen | only
+ call test_garbagecollect_now()
+ echo getloclist(0, {'context' : 1}).context
+ enew | only
+endfunc
+
+" The following test used to crash vim
+func Test_lfile_crash()
+ sp Xtest
+ au QuickFixCmdPre * bw
+ call assert_fails('lfile', 'E40')
+ au! QuickFixCmdPre
+endfunc
+
+" The following test used to crash vim
+func Test_lbuffer_crash()
+ sv Xtest
+ augroup QF_Test
+ au!
+ au * * bw
+ augroup END
+ lbuffer
+ augroup QF_Test
+ au!
+ augroup END
+endfunc
+
+" The following test used to crash vim
+func Test_lexpr_crash()
+ augroup QF_Test
+ au!
+ au * * call setloclist(0, [], 'f')
+ augroup END
+ lexpr ""
+ augroup QF_Test
+ au!
+ augroup END
+
+ enew | only
+ augroup QF_Test
+ au!
+ au BufNew * call setloclist(0, [], 'f')
+ augroup END
+ lexpr 'x:1:x'
+ augroup QF_Test
+ au!
+ augroup END
+
+ enew | only
+ lexpr ''
+ lopen
+ augroup QF_Test
+ au!
+ au FileType * call setloclist(0, [], 'f')
+ augroup END
+ lexpr ''
+ augroup QF_Test
+ au!
+ augroup END
+endfunc
+
+" The following test used to crash Vim
+func Test_lvimgrep_crash()
+ sv Xtest
+ augroup QF_Test
+ au!
+ au * * call setloclist(0, [], 'f')
+ augroup END
+ lvimgrep quickfix test_quickfix.vim
+ augroup QF_Test
+ au!
+ augroup END
+
+ new | only
+ augroup QF_Test
+ au!
+ au BufEnter * call setloclist(0, [], 'r')
+ augroup END
+ call assert_fails('lvimgrep Test_lvimgrep_crash *', 'E926:')
+ augroup QF_Test
+ au!
+ augroup END
+
+ enew | only
+endfunc
+
+" Test for the position of the quickfix and location list window
+func Test_qfwin_pos()
+ " Open two windows
+ new | only
+ new
+ cexpr ['F1:10:L10']
+ copen
+ " Quickfix window should be the bottom most window
+ call assert_equal(3, winnr())
+ close
+ " Open at the very top
+ wincmd t
+ topleft copen
+ call assert_equal(1, winnr())
+ close
+ " open left of the current window
+ wincmd t
+ below new
+ leftabove copen
+ call assert_equal(2, winnr())
+ close
+ " open right of the current window
+ rightbelow copen
+ call assert_equal(3, winnr())
+ close
+endfunc
+
+" Tests for quickfix/location lists changed by autocommands when
+" :vimgrep/:lvimgrep commands are running.
+func Test_vimgrep_autocmd()
+ call setqflist([], 'f')
+ call writefile(['stars'], 'Xtest1.txt')
+ call writefile(['stars'], 'Xtest2.txt')
+
+ " Test 1:
+ " When searching for a pattern using :vimgrep, if the quickfix list is
+ " changed by an autocmd, the results should be added to the correct quickfix
+ " list.
+ autocmd BufRead Xtest2.txt cexpr '' | cexpr ''
+ silent vimgrep stars Xtest*.txt
+ call assert_equal(1, getqflist({'nr' : 0}).nr)
+ call assert_equal(3, getqflist({'nr' : '$'}).nr)
+ call assert_equal('Xtest2.txt', bufname(getqflist()[1].bufnr))
+ au! BufRead Xtest2.txt
+
+ " Test 2:
+ " When searching for a pattern using :vimgrep, if the quickfix list is
+ " freed, then a error should be given.
+ silent! %bwipe!
+ call setqflist([], 'f')
+ autocmd BufRead Xtest2.txt for i in range(10) | cexpr '' | endfor
+ call assert_fails('vimgrep stars Xtest*.txt', 'E925:')
+ au! BufRead Xtest2.txt
+
+ " Test 3:
+ " When searching for a pattern using :lvimgrep, if the location list is
+ " freed, then the command should error out.
+ silent! %bwipe!
+ let g:save_winid = win_getid()
+ autocmd BufRead Xtest2.txt call setloclist(g:save_winid, [], 'f')
+ call assert_fails('lvimgrep stars Xtest*.txt', 'E926:')
+ au! BufRead Xtest2.txt
+
+ call delete('Xtest1.txt')
+ call delete('Xtest2.txt')
+ call setqflist([], 'f')
+endfunc
+
+" The following test used to crash Vim
+func Test_lhelpgrep_autocmd()
+ lhelpgrep quickfix
+ autocmd QuickFixCmdPost * call setloclist(0, [], 'f')
+ lhelpgrep buffer
+ call assert_equal('help', &filetype)
+ call assert_equal(0, getloclist(0, {'nr' : '$'}).nr)
+ lhelpgrep tabpage
+ call assert_equal('help', &filetype)
+ call assert_equal(1, getloclist(0, {'nr' : '$'}).nr)
+ au! QuickFixCmdPost
+
+ new | only
+ augroup QF_Test
+ au!
+ au BufEnter * call setqflist([], 'f')
+ augroup END
+ call assert_fails('helpgrep quickfix', 'E925:')
+ augroup QF_Test
+ au! BufEnter
+ augroup END
+
+ new | only
+ augroup QF_Test
+ au!
+ au BufEnter * call setqflist([], 'r')
+ augroup END
+ call assert_fails('helpgrep quickfix', 'E925:')
+ augroup QF_Test
+ au! BufEnter
+ augroup END
+
+ new | only
+ augroup QF_Test
+ au!
+ au BufEnter * call setloclist(0, [], 'r')
+ augroup END
+ call assert_fails('lhelpgrep quickfix', 'E926:')
+ augroup QF_Test
+ au! BufEnter
+ augroup END
+
+ new | only
+endfunc
+
+" Test for shortening/simplifying the file name when opening the
+" quickfix window or when displaying the quickfix list
+func Test_shorten_fname()
+ if !has('unix')
+ return
+ endif
+ %bwipe
+ " Create a quickfix list with a absolute path filename
+ let fname = getcwd() . '/test_quickfix.vim'
+ call setqflist([], ' ', {'lines':[fname . ":20:Line20"], 'efm':'%f:%l:%m'})
+ call assert_equal(fname, bufname('test_quickfix.vim'))
+ " Opening the quickfix window should simplify the file path
+ cwindow
+ call assert_equal('test_quickfix.vim', bufname('test_quickfix.vim'))
+ cclose
+ %bwipe
+ " Create a quickfix list with a absolute path filename
+ call setqflist([], ' ', {'lines':[fname . ":20:Line20"], 'efm':'%f:%l:%m'})
+ call assert_equal(fname, bufname('test_quickfix.vim'))
+ " Displaying the quickfix list should simplify the file path
+ silent! clist
+ call assert_equal('test_quickfix.vim', bufname('test_quickfix.vim'))
+endfunc
+
+" Quickfix title tests
+" In the below tests, 'exe "cmd"' is used to invoke the quickfix commands.
+" Otherwise due to indentation, the title is set with spaces at the beginning
+" of the command.
+func Test_qftitle()
+ call writefile(["F1:1:Line1"], 'Xerr')
+
+ " :cexpr
+ exe "cexpr readfile('Xerr')"
+ call assert_equal(":cexpr readfile('Xerr')", getqflist({'title' : 1}).title)
+
+ " :cgetexpr
+ exe "cgetexpr readfile('Xerr')"
+ call assert_equal(":cgetexpr readfile('Xerr')",
+ \ getqflist({'title' : 1}).title)
+
+ " :caddexpr
+ call setqflist([], 'f')
+ exe "caddexpr readfile('Xerr')"
+ call assert_equal(":caddexpr readfile('Xerr')",
+ \ getqflist({'title' : 1}).title)
+
+ " :cbuffer
+ new Xerr
+ exe "cbuffer"
+ call assert_equal(':cbuffer (Xerr)', getqflist({'title' : 1}).title)
+
+ " :cgetbuffer
+ edit Xerr
+ exe "cgetbuffer"
+ call assert_equal(':cgetbuffer (Xerr)', getqflist({'title' : 1}).title)
+
+ " :caddbuffer
+ call setqflist([], 'f')
+ edit Xerr
+ exe "caddbuffer"
+ call assert_equal(':caddbuffer (Xerr)', getqflist({'title' : 1}).title)
+
+ " :cfile
+ exe "cfile Xerr"
+ call assert_equal(':cfile Xerr', getqflist({'title' : 1}).title)
+
+ " :cgetfile
+ exe "cgetfile Xerr"
+ call assert_equal(':cgetfile Xerr', getqflist({'title' : 1}).title)
+
+ " :caddfile
+ call setqflist([], 'f')
+ exe "caddfile Xerr"
+ call assert_equal(':caddfile Xerr', getqflist({'title' : 1}).title)
+
+ " :grep
+ set grepprg=internal
+ exe "grep F1 Xerr"
+ call assert_equal(':grep F1 Xerr', getqflist({'title' : 1}).title)
+
+ " :grepadd
+ call setqflist([], 'f')
+ exe "grepadd F1 Xerr"
+ call assert_equal(':grepadd F1 Xerr', getqflist({'title' : 1}).title)
+ set grepprg&vim
+
+ " :vimgrep
+ exe "vimgrep F1 Xerr"
+ call assert_equal(':vimgrep F1 Xerr', getqflist({'title' : 1}).title)
+
+ " :vimgrepadd
+ call setqflist([], 'f')
+ exe "vimgrepadd F1 Xerr"
+ call assert_equal(':vimgrepadd F1 Xerr', getqflist({'title' : 1}).title)
+
+ call setqflist(['F1:10:L10'], ' ')
+ call assert_equal(':setqflist()', getqflist({'title' : 1}).title)
+
+ call setqflist([], 'f')
+ call setqflist(['F1:10:L10'], 'a')
+ call assert_equal(':setqflist()', getqflist({'title' : 1}).title)
+
+ call setqflist([], 'f')
+ call setqflist(['F1:10:L10'], 'r')
+ call assert_equal(':setqflist()', getqflist({'title' : 1}).title)
+
+ close
+ call delete('Xerr')
+
+ call setqflist([], ' ', {'title' : 'Errors'})
+ copen
+ call assert_equal('Errors', w:quickfix_title)
+ call setqflist([], 'r', {'items' : [{'filename' : 'a.c', 'lnum' : 10}]})
+ call assert_equal('Errors', w:quickfix_title)
+ cclose
+endfunc
+
+func Test_lbuffer_with_bwipe()
+ new
+ new
+ augroup nasty
+ au * * bwipe
+ augroup END
+ lbuffer
+ augroup nasty
+ au!
+ augroup END
+endfunc
+
+" Test for an autocmd freeing the quickfix/location list when cexpr/lexpr is
+" running
+func Xexpr_acmd_freelist(cchar)
+ call s:setup_commands(a:cchar)
+
+ " This was using freed memory.
+ augroup nasty
+ au * * call g:Xsetlist([], 'f')
+ augroup END
+ Xexpr "x"
+ augroup nasty
+ au!
+ augroup END
+endfunc
+
+func Test_cexpr_acmd_freelist()
+ call Xexpr_acmd_freelist('c')
+ call Xexpr_acmd_freelist('l')
+endfunc
+
+" Test for commands that create a new quickfix/location list and jump to the
+" first error automatically.
+func Xjumpto_first_error_test(cchar)
+ call s:setup_commands(a:cchar)
+
+ call s:create_test_file('Xtestfile1')
+ call s:create_test_file('Xtestfile2')
+ let l = ['Xtestfile1:2:Line2', 'Xtestfile2:4:Line4']
+
+ " Test for cexpr/lexpr
+ enew
+ Xexpr l
+ call assert_equal('Xtestfile1', bufname(''))
+ call assert_equal(2, line('.'))
+
+ " Test for cfile/lfile
+ enew
+ call writefile(l, 'Xerr')
+ Xfile Xerr
+ call assert_equal('Xtestfile1', bufname(''))
+ call assert_equal(2, line('.'))
+
+ " Test for cbuffer/lbuffer
+ edit Xerr
+ Xbuffer
+ call assert_equal('Xtestfile1', bufname(''))
+ call assert_equal(2, line('.'))
+
+ call delete('Xerr')
+ call delete('Xtestfile1')
+ call delete('Xtestfile2')
+endfunc
+
+func Test_jumpto_first_error()
+ call Xjumpto_first_error_test('c')
+ call Xjumpto_first_error_test('l')
+endfunc
+
+" Test for a quickfix autocmd changing the quickfix/location list before
+" jumping to the first error in the new list.
+func Xautocmd_changelist(cchar)
+ call s:setup_commands(a:cchar)
+
+ " Test for cfile/lfile
+ call s:create_test_file('Xtestfile1')
+ call s:create_test_file('Xtestfile2')
+ Xexpr 'Xtestfile1:2:Line2'
+ autocmd QuickFixCmdPost * Xolder
+ call writefile(['Xtestfile2:4:Line4'], 'Xerr')
+ Xfile Xerr
+ call assert_equal('Xtestfile2', bufname(''))
+ call assert_equal(4, line('.'))
+ autocmd! QuickFixCmdPost
+
+ " Test for cbuffer/lbuffer
+ call g:Xsetlist([], 'f')
+ Xexpr 'Xtestfile1:2:Line2'
+ autocmd QuickFixCmdPost * Xolder
+ call writefile(['Xtestfile2:4:Line4'], 'Xerr')
+ edit Xerr
+ Xbuffer
+ call assert_equal('Xtestfile2', bufname(''))
+ call assert_equal(4, line('.'))
+ autocmd! QuickFixCmdPost
+
+ " Test for cexpr/lexpr
+ call g:Xsetlist([], 'f')
+ Xexpr 'Xtestfile1:2:Line2'
+ autocmd QuickFixCmdPost * Xolder
+ Xexpr 'Xtestfile2:4:Line4'
+ call assert_equal('Xtestfile2', bufname(''))
+ call assert_equal(4, line('.'))
+ autocmd! QuickFixCmdPost
+
+ " The grepprg may not be set on non-Unix systems
+ if has('unix')
+ " Test for grep/lgrep
+ call g:Xsetlist([], 'f')
+ Xexpr 'Xtestfile1:2:Line2'
+ autocmd QuickFixCmdPost * Xolder
+ silent Xgrep Line5 Xtestfile2
+ call assert_equal('Xtestfile2', bufname(''))
+ call assert_equal(5, line('.'))
+ autocmd! QuickFixCmdPost
+ endif
+
+ " Test for vimgrep/lvimgrep
+ call g:Xsetlist([], 'f')
+ Xexpr 'Xtestfile1:2:Line2'
+ autocmd QuickFixCmdPost * Xolder
+ silent Xvimgrep Line5 Xtestfile2
+ call assert_equal('Xtestfile2', bufname(''))
+ call assert_equal(5, line('.'))
+ autocmd! QuickFixCmdPost
+
+ " Test for autocommands clearing the quickfix list before jumping to the
+ " first error. This should not result in an error
+ autocmd QuickFixCmdPost * call g:Xsetlist([], 'r')
+ let v:errmsg = ''
+ " Test for cfile/lfile
+ Xfile Xerr
+ call assert_true(v:errmsg !~# 'E42:')
+ " Test for cbuffer/lbuffer
+ edit Xerr
+ Xbuffer
+ call assert_true(v:errmsg !~# 'E42:')
+ " Test for cexpr/lexpr
+ Xexpr 'Xtestfile2:4:Line4'
+ call assert_true(v:errmsg !~# 'E42:')
+ " Test for grep/lgrep
+ " The grepprg may not be set on non-Unix systems
+ if has('unix')
+ silent Xgrep Line5 Xtestfile2
+ call assert_true(v:errmsg !~# 'E42:')
+ endif
+ " Test for vimgrep/lvimgrep
+ call assert_fails('silent Xvimgrep Line5 Xtestfile2', 'E480:')
+ autocmd! QuickFixCmdPost
+
+ call delete('Xerr')
+ call delete('Xtestfile1')
+ call delete('Xtestfile2')
+endfunc
+
+func Test_autocmd_changelist()
+ call Xautocmd_changelist('c')
+ call Xautocmd_changelist('l')
+endfunc
+
+" Tests for the ':filter /pat/ clist' command
+func Test_filter_clist()
+ cexpr ['Xfile1:10:10:Line 10', 'Xfile2:15:15:Line 15']
+ call assert_equal([' 2 Xfile2:15 col 15: Line 15'],
+ \ split(execute('filter /Line 15/ clist'), "\n"))
+ call assert_equal([' 1 Xfile1:10 col 10: Line 10'],
+ \ split(execute('filter /Xfile1/ clist'), "\n"))
+ call assert_equal([], split(execute('filter /abc/ clist'), "\n"))
+
+ call setqflist([{'module' : 'abc', 'pattern' : 'pat1'},
+ \ {'module' : 'pqr', 'pattern' : 'pat2'}], ' ')
+ call assert_equal([' 2 pqr:pat2: '],
+ \ split(execute('filter /pqr/ clist'), "\n"))
+ call assert_equal([' 1 abc:pat1: '],
+ \ split(execute('filter /pat1/ clist'), "\n"))
+endfunc
+
+" Tests for the "CTRL-W <CR>" command.
+func Xview_result_split_tests(cchar)
+ call s:setup_commands(a:cchar)
+
+ " Test that "CTRL-W <CR>" in a qf/ll window fails with empty list.
+ call g:Xsetlist([])
+ Xopen
+ let l:win_count = winnr('$')
+ call assert_fails('execute "normal! \<C-W>\<CR>"', 'E42')
+ call assert_equal(l:win_count, winnr('$'))
+ Xclose
+endfunc
+
+func Test_view_result_split()
+ call Xview_result_split_tests('c')
+ call Xview_result_split_tests('l')
+endfunc
+
+" Test that :cc sets curswant
+func Test_curswant()
+ helpgrep quickfix
+ normal! llll
+ 1cc
+ call assert_equal(getcurpos()[4], virtcol('.'))
+ cclose | helpclose
+endfunc
+
+" Test for opening a file from the quickfix window using CTRL-W <Enter>
+" doesn't leave an empty buffer around.
+func Test_splitview()
+ call s:create_test_file('Xtestfile1')
+ call s:create_test_file('Xtestfile2')
+ new | only
+ let last_bufnr = bufnr('Test_sv_1', 1)
+ let l = ['Xtestfile1:2:Line2', 'Xtestfile2:4:Line4']
+ cgetexpr l
+ copen
+ let numbufs = len(getbufinfo())
+ exe "normal \<C-W>\<CR>"
+ copen
+ exe "normal j\<C-W>\<CR>"
+ " Make sure new empty buffers are not created
+ call assert_equal(numbufs, len(getbufinfo()))
+ " Creating a new buffer should use the next available buffer number
+ call assert_equal(last_bufnr + 4, bufnr("Test_sv_2", 1))
+ bwipe Test_sv_1
+ bwipe Test_sv_2
+ new | only
+
+ " When split opening files from location list window, make sure that two
+ " windows doesn't refer to the same location list
+ lgetexpr l
+ let locid = getloclist(0, {'id' : 0}).id
+ lopen
+ exe "normal \<C-W>\<CR>"
+ call assert_notequal(locid, getloclist(0, {'id' : 0}).id)
+ call assert_equal(0, getloclist(0, {'winid' : 0}).winid)
+ new | only
+
+ " When split opening files from a helpgrep location list window, a new help
+ " window should be opend with a copy of the location list.
+ lhelpgrep window
+ let locid = getloclist(0, {'id' : 0}).id
+ lwindow
+ exe "normal j\<C-W>\<CR>"
+ call assert_notequal(locid, getloclist(0, {'id' : 0}).id)
+ call assert_equal(0, getloclist(0, {'winid' : 0}).winid)
+ new | only
+
+ call delete('Xtestfile1')
+ call delete('Xtestfile2')
+endfunc
+
+" Test for parsing entries using visual screen column
+func Test_viscol()
+ enew
+ call writefile(["Col1\tCol2\tCol3"], 'Xfile1')
+ edit Xfile1
+
+ " Use byte offset for column number
+ set efm&
+ cexpr "Xfile1:1:5:XX\nXfile1:1:9:YY\nXfile1:1:20:ZZ"
+ call assert_equal([5, 8], [col('.'), virtcol('.')])
+ cnext
+ call assert_equal([9, 12], [col('.'), virtcol('.')])
+ cnext
+ call assert_equal([14, 20], [col('.'), virtcol('.')])
+
+ " Use screen column offset for column number
+ set efm=%f:%l:%v:%m
+ cexpr "Xfile1:1:8:XX\nXfile1:1:12:YY\nXfile1:1:20:ZZ"
+ call assert_equal([5, 8], [col('.'), virtcol('.')])
+ cnext
+ call assert_equal([9, 12], [col('.'), virtcol('.')])
+ cnext
+ call assert_equal([14, 20], [col('.'), virtcol('.')])
+ cexpr "Xfile1:1:6:XX\nXfile1:1:15:YY\nXfile1:1:24:ZZ"
+ call assert_equal([5, 8], [col('.'), virtcol('.')])
+ cnext
+ call assert_equal([10, 16], [col('.'), virtcol('.')])
+ cnext
+ call assert_equal([14, 20], [col('.'), virtcol('.')])
+
+ enew
+ call writefile(["Col1\täü\töß\tCol4"], 'Xfile1')
+
+ " Use byte offset for column number
+ set efm&
+ cexpr "Xfile1:1:8:XX\nXfile1:1:11:YY\nXfile1:1:16:ZZ"
+ call assert_equal([8, 10], [col('.'), virtcol('.')])
+ cnext
+ call assert_equal([11, 17], [col('.'), virtcol('.')])
+ cnext
+ call assert_equal([16, 25], [col('.'), virtcol('.')])
+
+ " Use screen column offset for column number
+ set efm=%f:%l:%v:%m
+ cexpr "Xfile1:1:10:XX\nXfile1:1:17:YY\nXfile1:1:25:ZZ"
+ call assert_equal([8, 10], [col('.'), virtcol('.')])
+ cnext
+ call assert_equal([11, 17], [col('.'), virtcol('.')])
+ cnext
+ call assert_equal([16, 25], [col('.'), virtcol('.')])
+
+ enew | only
+ set efm&
+ call delete('Xfile1')
+endfunc
diff --git a/src/testdir/test_quotestar.vim b/src/testdir/test_quotestar.vim
new file mode 100644
index 0000000..ce5a9ee
--- /dev/null
+++ b/src/testdir/test_quotestar.vim
@@ -0,0 +1,154 @@
+" *-register (quotestar) tests
+
+if !has('clipboard')
+ finish
+endif
+
+source shared.vim
+
+func Do_test_quotestar_for_macunix()
+ if empty(exepath('pbcopy')) || empty(exepath('pbpaste'))
+ return 'Test requires pbcopy(1) and pbpaste(1)'
+ endif
+
+ let @* = ''
+
+ " Test #1: Pasteboard to Vim
+ let test_msg = "text from pasteboard to vim via quotestar"
+ " Write a piece of text to the pasteboard.
+ call system('/bin/echo -n "' . test_msg . '" | pbcopy')
+ " See if the *-register is changed as expected.
+ call assert_equal(test_msg, @*)
+
+ " Test #2: Vim to Pasteboard
+ let test_msg = "text from vim to pasteboard via quotestar"
+ " Write a piece of text to the *-register.
+ let @* = test_msg
+ " See if the pasteboard is changed as expected.
+ call assert_equal(test_msg, system('pbpaste'))
+
+ return ''
+endfunc
+
+func Do_test_quotestar_for_x11()
+ if !has('clientserver') || !has('job')
+ return 'Test requires the client-server and job features'
+ endif
+
+ let cmd = GetVimCommand()
+ if cmd == ''
+ return 'GetVimCommand() failed'
+ endif
+ try
+ call remote_send('xxx', '')
+ catch
+ if v:exception =~ 'E240:'
+ " No connection to the X server, give up.
+ return
+ endif
+ " ignore other errors
+ endtry
+
+ let name = 'XVIMCLIPBOARD'
+
+ " Make sure a previous server has exited
+ try
+ call remote_send(name, ":qa!\<CR>")
+ catch /E241:/
+ endtry
+ call WaitForAssert({-> assert_notmatch(name, serverlist())})
+
+ let cmd .= ' --servername ' . name
+ let job = job_start(cmd, {'stoponexit': 'kill', 'out_io': 'null'})
+ call WaitForAssert({-> assert_equal("run", job_status(job))})
+
+ " Takes a short while for the server to be active.
+ call WaitForAssert({-> assert_match(name, serverlist())})
+
+ " Wait for the server to be up and answering requests. One second is not
+ " always sufficient.
+ call WaitForAssert({-> assert_notequal('', remote_expr(name, "v:version", "", 2))})
+
+ " Clear the *-register of this vim instance and wait for it to be picked up
+ " by the server.
+ let @* = 'no'
+ call remote_foreground(name)
+ call WaitForAssert({-> assert_equal("no", remote_expr(name, "@*", "", 1))})
+
+ " Set the * register on the server.
+ call remote_send(name, ":let @* = 'yes'\<CR>")
+ call WaitForAssert({-> assert_equal("yes", remote_expr(name, "@*", "", 1))})
+
+ " Check that the *-register of this vim instance is changed as expected.
+ call WaitForAssert({-> assert_equal("yes", @*)})
+
+ " Handle the large selection over 262040 byte.
+ let length = 262044
+ let sample = 'a' . repeat('b', length - 2) . 'c'
+ let @* = sample
+ call WaitFor('remote_expr("' . name . '", "len(@*) >= ' . length . '", "", 1)')
+ let res = remote_expr(name, "@*", "", 2)
+ call assert_equal(length, len(res))
+ " Check length to prevent a large amount of output at assertion failure.
+ if length == len(res)
+ call assert_equal(sample, res)
+ endif
+
+ if has('unix') && has('gui') && !has('gui_running')
+ let @* = ''
+
+ " Running in a terminal and the GUI is avaiable: Tell the server to open
+ " the GUI and check that the remote command still works.
+ " Need to wait for the GUI to start up, otherwise the send hangs in trying
+ " to send to the terminal window.
+ if has('gui_athena') || has('gui_motif')
+ " For those GUIs, ignore the 'failed to create input context' error.
+ call remote_send(name, ":call test_ignore_error('E285') | gui -f\<CR>")
+ else
+ call remote_send(name, ":gui -f\<CR>")
+ endif
+ " Wait for the server in the GUI to be up and answering requests.
+ call WaitForAssert({-> assert_match("1", remote_expr(name, "has('gui_running')", "", 1))})
+
+ call remote_send(name, ":let @* = 'maybe'\<CR>")
+ call WaitForAssert({-> assert_equal("maybe", remote_expr(name, "@*", "", 2))})
+
+ call assert_equal('maybe', @*)
+ endif
+
+ call remote_send(name, ":qa!\<CR>")
+ try
+ call WaitForAssert({-> assert_equal("dead", job_status(job))})
+ finally
+ if job_status(job) != 'dead'
+ call assert_report('Server did not exit')
+ call job_stop(job, 'kill')
+ endif
+ endtry
+
+ return ''
+endfunc
+
+func Test_quotestar()
+ let skipped = ''
+
+ let quotestar_saved = @*
+
+ if has('macunix')
+ let skipped = Do_test_quotestar_for_macunix()
+ elseif has('x11')
+ if empty($DISPLAY)
+ let skipped = "Test can only run when $DISPLAY is set."
+ else
+ let skipped = Do_test_quotestar_for_x11()
+ endif
+ else
+ let skipped = "Test is not implemented yet for this platform."
+ endif
+
+ let @* = quotestar_saved
+
+ if !empty(skipped)
+ throw 'Skipped: ' . skipped
+ endif
+endfunc
diff --git a/src/testdir/test_recover.vim b/src/testdir/test_recover.vim
new file mode 100644
index 0000000..a9934a1
--- /dev/null
+++ b/src/testdir/test_recover.vim
@@ -0,0 +1,62 @@
+" Test :recover
+
+func Test_recover_root_dir()
+ " This used to access invalid memory.
+ split Xtest
+ set dir=/
+ call assert_fails('recover', 'E305:')
+ close!
+
+ if has('win32') || filewritable('/') == 2
+ " can write in / directory on MS-Windows
+ set dir=/notexist/
+ endif
+ call assert_fails('split Xtest', 'E303:')
+ set dir&
+endfunc
+
+" Inserts 10000 lines with text to fill the swap file with two levels of pointer
+" blocks. Then recovers from the swap file and checks all text is restored.
+"
+" We need about 10000 lines of 100 characters to get two levels of pointer
+" blocks.
+func Test_swap_file()
+ set fileformat=unix undolevels=-1
+ edit! Xtest
+ let text = "\tabcdefghijklmnoparstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnoparstuvwxyz0123456789"
+ let i = 1
+ let linecount = 10000
+ while i <= linecount
+ call append(i - 1, i . text)
+ let i += 1
+ endwhile
+ $delete
+ preserve
+ " get the name of the swap file
+ let swname = split(execute("swapname"))[0]
+ let swname = substitute(swname, '[[:blank:][:cntrl:]]*\(.\{-}\)[[:blank:][:cntrl:]]*$', '\1', '')
+ " make a copy of the swap file in Xswap
+ set binary
+ exe 'sp ' . swname
+ w! Xswap
+ set nobinary
+ new
+ only!
+ bwipe! Xtest
+ call rename('Xswap', swname)
+ recover Xtest
+ call delete(swname)
+ let linedollar = line('$')
+ call assert_equal(linecount, linedollar)
+ if linedollar < linecount
+ let linecount = linedollar
+ endif
+ let i = 1
+ while i <= linecount
+ call assert_equal(i . text, getline(i))
+ let i += 1
+ endwhile
+
+ set undolevels&
+ enew! | only
+endfunc
diff --git a/src/testdir/test_regex_char_classes.vim b/src/testdir/test_regex_char_classes.vim
new file mode 100644
index 0000000..c1a4202
--- /dev/null
+++ b/src/testdir/test_regex_char_classes.vim
@@ -0,0 +1,295 @@
+" Tests for regexp with backslash and other special characters inside []
+" Also test backslash for hex/octal numbered character.
+"
+
+scriptencoding utf-8
+
+function RunSTest(value, calls, expected)
+ new
+ call feedkeys("i" . a:value, "mx")
+ exec a:calls
+ call assert_equal(a:expected, getline(1), printf("wrong result for %s", a:calls))
+ quit!
+endfunction
+
+function RunXTest(value, search_exp, expected)
+ new
+ call feedkeys("i" . a:value, "mx")
+ call feedkeys("gg" . a:search_exp . "\nx", "mx")
+ call assert_equal(a:expected, getline(1), printf("wrong result for %s", a:search_exp))
+ quit!
+endfunction
+
+
+function Test_x_search()
+ let res = "test text test text"
+ call RunXTest("test \\text test text", "/[\\x]", res)
+ call RunXTest("test \ttext test text", "/[\\t\\]]", res)
+ call RunXTest("test text ]test text", "/[]y]", res)
+ call RunXTest("test ]text test text", "/[\\]]", res)
+ call RunXTest("test text te^st text", "/[y^]", res)
+ call RunXTest("test te$xt test text", "/[$y]", res)
+ call RunXTest("test taext test text", "/[\\x61]", res)
+ call RunXTest("test tbext test text","/[\\x60-\\x64]", res)
+ call RunXTest("test 5text test text","/[\\x785]", res)
+ call RunXTest("testc text test text","/[\\o143]", res)
+ call RunXTest("tesdt text test text","/[\\o140-\\o144]", res)
+ call RunXTest("test7 text test text", "/[\\o417]", res)
+ call RunXTest("test text tBest text", "/\\%x42", res)
+ call RunXTest("test text teCst text", "/\\%o103", res)
+ call RunXTest("test text \<C-V>x00test text", "/[\\x00]", res)
+endfunction
+
+function Test_s_search()
+ let res = "test text test text"
+ call RunSTest("test te\<C-V>x00xt t\<C-V>x04est t\<C-V>x10ext", "s/[\\x00-\\x10]//g", res)
+ call RunSTest("test \\xyztext test text", "s/[\\x-z]\\+//", res)
+ call RunSTest("test text tev\\uyst text", "s/[\\u-z]\\{2,}//", res)
+ call RunSTest("xx aaaaa xx a", "s/\\(a\\)\\+//", "xx xx a")
+ call RunSTest("xx aaaaa xx a", "s/\\(a*\\)\\+//", "xx aaaaa xx a")
+ call RunSTest("xx aaaaa xx a", "s/\\(a*\\)*//", "xx aaaaa xx a")
+ call RunSTest("xx aaaaa xx", "s/\\(a\\)\\{2,3}/A/", "xx Aaa xx")
+ call RunSTest("xx aaaaa xx", "s/\\(a\\)\\{-2,3}/A/", "xx Aaaa xx")
+ call RunSTest("xx aaa12aa xx", "s/\\(a\\)*\\(12\\)\\@>/A/", "xx Aaa xx")
+ call RunSTest("xx foobar xbar xx", "s/\\(foo\\)\\@<!bar/A/", "xx foobar xA xx")
+ call RunSTest("xx an file xx", "s/\\(an\\_s\\+\\)\\@<=file/A/", "xx an A xx")
+ call RunSTest("x= 9;", "s/^\\(\\h\\w*\\%(->\\|\\.\\)\\=\\)\\+=/XX/", "XX 9;")
+ call RunSTest("hh= 77;", "s/^\\(\\h\\w*\\%(->\\|\\.\\)\\=\\)\\+=/YY/", "YY 77;")
+ call RunSTest(" aaa ", "s/aaa/xyz/", " xyz ")
+ call RunSTest(" xyz", "s/~/bcd/", " bcd")
+ call RunSTest(" bcdbcdbcd", "s/~\\+/BB/", " BB")
+endfunction
+
+" Test character classes in regexp using regexpengine 0, 1, 2.
+func Test_regex_char_classes()
+ new
+ let save_enc = &encoding
+ set encoding=utf-8
+
+ let input = "\t\<C-L>\<C-M> !\"#$%&'()#+'-./0123456789:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~\<C-?>\u0080\u0082\u0090\u009b¦±¼ÇÓé"
+
+ " Format is [cmd_to_run, expected_output]
+ let tests = [
+ \ [':s/\%#=0\d//g',
+ \ "\t\<C-L>\<C-M> !\"#$%&'()#+'-./:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~\<C-?>\u0080\u0082\u0090\u009b¦±¼ÇÓé"],
+ \ [':s/\%#=1\d//g',
+ \ "\t\<C-L>\<C-M> !\"#$%&'()#+'-./:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~\<C-?>\u0080\u0082\u0090\u009b¦±¼ÇÓé"],
+ \ [':s/\%#=2\d//g',
+ \ "\t\<C-L>\<C-M> !\"#$%&'()#+'-./:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~\<C-?>\u0080\u0082\u0090\u009b¦±¼ÇÓé"],
+ \ [':s/\%#=0[0-9]//g',
+ \ "\t\<C-L>\<C-M> !\"#$%&'()#+'-./:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~\<C-?>\u0080\u0082\u0090\u009b¦±¼ÇÓé"],
+ \ [':s/\%#=1[0-9]//g',
+ \ "\t\<C-L>\<C-M> !\"#$%&'()#+'-./:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~\<C-?>\u0080\u0082\u0090\u009b¦±¼ÇÓé"],
+ \ [':s/\%#=2[0-9]//g',
+ \ "\t\<C-L>\<C-M> !\"#$%&'()#+'-./:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~\<C-?>\u0080\u0082\u0090\u009b¦±¼ÇÓé"],
+ \ [':s/\%#=0\D//g',
+ \ "0123456789"],
+ \ [':s/\%#=1\D//g',
+ \ "0123456789"],
+ \ [':s/\%#=2\D//g',
+ \ "0123456789"],
+ \ [':s/\%#=0[^0-9]//g',
+ \ "0123456789"],
+ \ [':s/\%#=1[^0-9]//g',
+ \ "0123456789"],
+ \ [':s/\%#=2[^0-9]//g',
+ \ "0123456789"],
+ \ [':s/\%#=0\o//g',
+ \ "\t\<C-L>\<C-M> !\"#$%&'()#+'-./89:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~\<C-?>\u0080\u0082\u0090\u009b¦±¼ÇÓé"],
+ \ [':s/\%#=1\o//g',
+ \ "\t\<C-L>\<C-M> !\"#$%&'()#+'-./89:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~\<C-?>\u0080\u0082\u0090\u009b¦±¼ÇÓé"],
+ \ [':s/\%#=2\o//g',
+ \ "\t\<C-L>\<C-M> !\"#$%&'()#+'-./89:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~\<C-?>\u0080\u0082\u0090\u009b¦±¼ÇÓé"],
+ \ [':s/\%#=0[0-7]//g',
+ \ "\t\<C-L>\<C-M> !\"#$%&'()#+'-./89:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~\<C-?>\u0080\u0082\u0090\u009b¦±¼ÇÓé"],
+ \ [':s/\%#=1[0-7]//g',
+ \ "\t\<C-L>\<C-M> !\"#$%&'()#+'-./89:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~\<C-?>\u0080\u0082\u0090\u009b¦±¼ÇÓé"],
+ \ [':s/\%#=2[0-7]//g',
+ \ "\t\<C-L>\<C-M> !\"#$%&'()#+'-./89:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~\<C-?>\u0080\u0082\u0090\u009b¦±¼ÇÓé"],
+ \ [':s/\%#=0\O//g',
+ \ "01234567"],
+ \ [':s/\%#=1\O//g',
+ \ "01234567"],
+ \ [':s/\%#=2\O//g',
+ \ "01234567"],
+ \ [':s/\%#=0[^0-7]//g',
+ \ "01234567"],
+ \ [':s/\%#=1[^0-7]//g',
+ \ "01234567"],
+ \ [':s/\%#=2[^0-7]//g',
+ \ "01234567"],
+ \ [':s/\%#=0\x//g',
+ \ "\t\<C-L>\<C-M> !\"#$%&'()#+'-./:;<=>?@GHIXYZ[\]^_`ghiwxyz{|}~\<C-?>\u0080\u0082\u0090\u009b¦±¼ÇÓé"],
+ \ [':s/\%#=1\x//g',
+ \ "\t\<C-L>\<C-M> !\"#$%&'()#+'-./:;<=>?@GHIXYZ[\]^_`ghiwxyz{|}~\<C-?>\u0080\u0082\u0090\u009b¦±¼ÇÓé"],
+ \ [':s/\%#=2\x//g',
+ \ "\t\<C-L>\<C-M> !\"#$%&'()#+'-./:;<=>?@GHIXYZ[\]^_`ghiwxyz{|}~\<C-?>\u0080\u0082\u0090\u009b¦±¼ÇÓé"],
+ \ [':s/\%#=0[0-9A-Fa-f]//g',
+ \ "\t\<C-L>\<C-M> !\"#$%&'()#+'-./:;<=>?@GHIXYZ[\]^_`ghiwxyz{|}~\<C-?>\u0080\u0082\u0090\u009b¦±¼ÇÓé"],
+ \ [':s/\%#=1[0-9A-Fa-f]//g',
+ \ "\t\<C-L>\<C-M> !\"#$%&'()#+'-./:;<=>?@GHIXYZ[\]^_`ghiwxyz{|}~\<C-?>\u0080\u0082\u0090\u009b¦±¼ÇÓé"],
+ \ [':s/\%#=2[0-9A-Fa-f]//g',
+ \ "\t\<C-L>\<C-M> !\"#$%&'()#+'-./:;<=>?@GHIXYZ[\]^_`ghiwxyz{|}~\<C-?>\u0080\u0082\u0090\u009b¦±¼ÇÓé"],
+ \ [':s/\%#=0\X//g',
+ \ "0123456789ABCDEFabcdef"],
+ \ [':s/\%#=1\X//g',
+ \ "0123456789ABCDEFabcdef"],
+ \ [':s/\%#=2\X//g',
+ \ "0123456789ABCDEFabcdef"],
+ \ [':s/\%#=0[^0-9A-Fa-f]//g',
+ \ "0123456789ABCDEFabcdef"],
+ \ [':s/\%#=1[^0-9A-Fa-f]//g',
+ \ "0123456789ABCDEFabcdef"],
+ \ [':s/\%#=2[^0-9A-Fa-f]//g',
+ \ "0123456789ABCDEFabcdef"],
+ \ [':s/\%#=0\w//g',
+ \ "\t\<C-L>\<C-M> !\"#$%&'()#+'-./:;<=>?@[\]^`{|}~\<C-?>\u0080\u0082\u0090\u009b¦±¼ÇÓé"],
+ \ [':s/\%#=1\w//g',
+ \ "\t\<C-L>\<C-M> !\"#$%&'()#+'-./:;<=>?@[\]^`{|}~\<C-?>\u0080\u0082\u0090\u009b¦±¼ÇÓé"],
+ \ [':s/\%#=2\w//g',
+ \ "\t\<C-L>\<C-M> !\"#$%&'()#+'-./:;<=>?@[\]^`{|}~\<C-?>\u0080\u0082\u0090\u009b¦±¼ÇÓé"],
+ \ [':s/\%#=0[0-9A-Za-z_]//g',
+ \ "\t\<C-L>\<C-M> !\"#$%&'()#+'-./:;<=>?@[\]^`{|}~\<C-?>\u0080\u0082\u0090\u009b¦±¼ÇÓé"],
+ \ [':s/\%#=1[0-9A-Za-z_]//g',
+ \ "\t\<C-L>\<C-M> !\"#$%&'()#+'-./:;<=>?@[\]^`{|}~\<C-?>\u0080\u0082\u0090\u009b¦±¼ÇÓé"],
+ \ [':s/\%#=2[0-9A-Za-z_]//g',
+ \ "\t\<C-L>\<C-M> !\"#$%&'()#+'-./:;<=>?@[\]^`{|}~\<C-?>\u0080\u0082\u0090\u009b¦±¼ÇÓé"],
+ \ [':s/\%#=0\W//g',
+ \ "0123456789ABCDEFGHIXYZ_abcdefghiwxyz"],
+ \ [':s/\%#=1\W//g',
+ \ "0123456789ABCDEFGHIXYZ_abcdefghiwxyz"],
+ \ [':s/\%#=2\W//g',
+ \ "0123456789ABCDEFGHIXYZ_abcdefghiwxyz"],
+ \ [':s/\%#=0[^0-9A-Za-z_]//g',
+ \ "0123456789ABCDEFGHIXYZ_abcdefghiwxyz"],
+ \ [':s/\%#=1[^0-9A-Za-z_]//g',
+ \ "0123456789ABCDEFGHIXYZ_abcdefghiwxyz"],
+ \ [':s/\%#=2[^0-9A-Za-z_]//g',
+ \ "0123456789ABCDEFGHIXYZ_abcdefghiwxyz"],
+ \ [':s/\%#=0\h//g',
+ \ "\t\<C-L>\<C-M> !\"#$%&'()#+'-./0123456789:;<=>?@[\]^`{|}~\<C-?>\u0080\u0082\u0090\u009b¦±¼ÇÓé"],
+ \ [':s/\%#=1\h//g',
+ \ "\t\<C-L>\<C-M> !\"#$%&'()#+'-./0123456789:;<=>?@[\]^`{|}~\<C-?>\u0080\u0082\u0090\u009b¦±¼ÇÓé"],
+ \ [':s/\%#=2\h//g',
+ \ "\t\<C-L>\<C-M> !\"#$%&'()#+'-./0123456789:;<=>?@[\]^`{|}~\<C-?>\u0080\u0082\u0090\u009b¦±¼ÇÓé"],
+ \ [':s/\%#=0[A-Za-z_]//g',
+ \ "\t\<C-L>\<C-M> !\"#$%&'()#+'-./0123456789:;<=>?@[\]^`{|}~\<C-?>\u0080\u0082\u0090\u009b¦±¼ÇÓé"],
+ \ [':s/\%#=1[A-Za-z_]//g',
+ \ "\t\<C-L>\<C-M> !\"#$%&'()#+'-./0123456789:;<=>?@[\]^`{|}~\<C-?>\u0080\u0082\u0090\u009b¦±¼ÇÓé"],
+ \ [':s/\%#=2[A-Za-z_]//g',
+ \ "\t\<C-L>\<C-M> !\"#$%&'()#+'-./0123456789:;<=>?@[\]^`{|}~\<C-?>\u0080\u0082\u0090\u009b¦±¼ÇÓé"],
+ \ [':s/\%#=0\H//g',
+ \ "ABCDEFGHIXYZ_abcdefghiwxyz"],
+ \ [':s/\%#=1\H//g',
+ \ "ABCDEFGHIXYZ_abcdefghiwxyz"],
+ \ [':s/\%#=2\H//g',
+ \ "ABCDEFGHIXYZ_abcdefghiwxyz"],
+ \ [':s/\%#=0[^A-Za-z_]//g',
+ \ "ABCDEFGHIXYZ_abcdefghiwxyz"],
+ \ [':s/\%#=1[^A-Za-z_]//g',
+ \ "ABCDEFGHIXYZ_abcdefghiwxyz"],
+ \ [':s/\%#=2[^A-Za-z_]//g',
+ \ "ABCDEFGHIXYZ_abcdefghiwxyz"],
+ \ [':s/\%#=0\a//g',
+ \ "\t\<C-L>\<C-M> !\"#$%&'()#+'-./0123456789:;<=>?@[\]^_`{|}~\<C-?>\u0080\u0082\u0090\u009b¦±¼ÇÓé"],
+ \ [':s/\%#=1\a//g',
+ \ "\t\<C-L>\<C-M> !\"#$%&'()#+'-./0123456789:;<=>?@[\]^_`{|}~\<C-?>\u0080\u0082\u0090\u009b¦±¼ÇÓé"],
+ \ [':s/\%#=2\a//g',
+ \ "\t\<C-L>\<C-M> !\"#$%&'()#+'-./0123456789:;<=>?@[\]^_`{|}~\<C-?>\u0080\u0082\u0090\u009b¦±¼ÇÓé"],
+ \ [':s/\%#=0[A-Za-z]//g',
+ \ "\t\<C-L>\<C-M> !\"#$%&'()#+'-./0123456789:;<=>?@[\]^_`{|}~\<C-?>\u0080\u0082\u0090\u009b¦±¼ÇÓé"],
+ \ [':s/\%#=1[A-Za-z]//g',
+ \ "\t\<C-L>\<C-M> !\"#$%&'()#+'-./0123456789:;<=>?@[\]^_`{|}~\<C-?>\u0080\u0082\u0090\u009b¦±¼ÇÓé"],
+ \ [':s/\%#=2[A-Za-z]//g',
+ \ "\t\<C-L>\<C-M> !\"#$%&'()#+'-./0123456789:;<=>?@[\]^_`{|}~\<C-?>\u0080\u0082\u0090\u009b¦±¼ÇÓé"],
+ \ [':s/\%#=0\A//g',
+ \ "ABCDEFGHIXYZabcdefghiwxyz"],
+ \ [':s/\%#=1\A//g',
+ \ "ABCDEFGHIXYZabcdefghiwxyz"],
+ \ [':s/\%#=2\A//g',
+ \ "ABCDEFGHIXYZabcdefghiwxyz"],
+ \ [':s/\%#=0[^A-Za-z]//g',
+ \ "ABCDEFGHIXYZabcdefghiwxyz"],
+ \ [':s/\%#=1[^A-Za-z]//g',
+ \ "ABCDEFGHIXYZabcdefghiwxyz"],
+ \ [':s/\%#=2[^A-Za-z]//g',
+ \ "ABCDEFGHIXYZabcdefghiwxyz"],
+ \ [':s/\%#=0\l//g',
+ \ "\t\<C-L>\<C-M> !\"#$%&'()#+'-./0123456789:;<=>?@ABCDEFGHIXYZ[\]^_`{|}~\<C-?>\u0080\u0082\u0090\u009b¦±¼ÇÓé"],
+ \ [':s/\%#=1\l//g',
+ \ "\t\<C-L>\<C-M> !\"#$%&'()#+'-./0123456789:;<=>?@ABCDEFGHIXYZ[\]^_`{|}~\<C-?>\u0080\u0082\u0090\u009b¦±¼ÇÓé"],
+ \ [':s/\%#=2\l//g',
+ \ "\t\<C-L>\<C-M> !\"#$%&'()#+'-./0123456789:;<=>?@ABCDEFGHIXYZ[\]^_`{|}~\<C-?>\u0080\u0082\u0090\u009b¦±¼ÇÓé"],
+ \ [':s/\%#=0[a-z]//g',
+ \ "\t\<C-L>\<C-M> !\"#$%&'()#+'-./0123456789:;<=>?@ABCDEFGHIXYZ[\]^_`{|}~\<C-?>\u0080\u0082\u0090\u009b¦±¼ÇÓé"],
+ \ [':s/\%#=1[a-z]//g',
+ \ "\t\<C-L>\<C-M> !\"#$%&'()#+'-./0123456789:;<=>?@ABCDEFGHIXYZ[\]^_`{|}~\<C-?>\u0080\u0082\u0090\u009b¦±¼ÇÓé"],
+ \ [':s/\%#=2[a-z]//g',
+ \ "\t\<C-L>\<C-M> !\"#$%&'()#+'-./0123456789:;<=>?@ABCDEFGHIXYZ[\]^_`{|}~\<C-?>\u0080\u0082\u0090\u009b¦±¼ÇÓé"],
+ \ [':s/\%#=0\L//g',
+ \ "abcdefghiwxyz"],
+ \ [':s/\%#=1\L//g',
+ \ "abcdefghiwxyz"],
+ \ [':s/\%#=2\L//g',
+ \ "abcdefghiwxyz"],
+ \ [':s/\%#=0[^a-z]//g',
+ \ "abcdefghiwxyz"],
+ \ [':s/\%#=1[^a-z]//g',
+ \ "abcdefghiwxyz"],
+ \ [':s/\%#=2[^a-z]//g',
+ \ "abcdefghiwxyz"],
+ \ [':s/\%#=0\u//g',
+ \ "\t\<C-L>\<C-M> !\"#$%&'()#+'-./0123456789:;<=>?@[\]^_`abcdefghiwxyz{|}~\<C-?>\u0080\u0082\u0090\u009b¦±¼ÇÓé"],
+ \ [':s/\%#=1\u//g',
+ \ "\t\<C-L>\<C-M> !\"#$%&'()#+'-./0123456789:;<=>?@[\]^_`abcdefghiwxyz{|}~\<C-?>\u0080\u0082\u0090\u009b¦±¼ÇÓé"],
+ \ [':s/\%#=2\u//g',
+ \ "\t\<C-L>\<C-M> !\"#$%&'()#+'-./0123456789:;<=>?@[\]^_`abcdefghiwxyz{|}~\<C-?>\u0080\u0082\u0090\u009b¦±¼ÇÓé"],
+ \ [':s/\%#=0[A-Z]//g',
+ \ "\t\<C-L>\<C-M> !\"#$%&'()#+'-./0123456789:;<=>?@[\]^_`abcdefghiwxyz{|}~\<C-?>\u0080\u0082\u0090\u009b¦±¼ÇÓé"],
+ \ [':s/\%#=1[A-Z]//g',
+ \ "\t\<C-L>\<C-M> !\"#$%&'()#+'-./0123456789:;<=>?@[\]^_`abcdefghiwxyz{|}~\<C-?>\u0080\u0082\u0090\u009b¦±¼ÇÓé"],
+ \ [':s/\%#=2[A-Z]//g',
+ \ "\t\<C-L>\<C-M> !\"#$%&'()#+'-./0123456789:;<=>?@[\]^_`abcdefghiwxyz{|}~\<C-?>\u0080\u0082\u0090\u009b¦±¼ÇÓé"],
+ \ [':s/\%#=0\U//g',
+ \ "ABCDEFGHIXYZ"],
+ \ [':s/\%#=1\U//g',
+ \ "ABCDEFGHIXYZ"],
+ \ [':s/\%#=2\U//g',
+ \ "ABCDEFGHIXYZ"],
+ \ [':s/\%#=0[^A-Z]//g',
+ \ "ABCDEFGHIXYZ"],
+ \ [':s/\%#=1[^A-Z]//g',
+ \ "ABCDEFGHIXYZ"],
+ \ [':s/\%#=2[^A-Z]//g',
+ \ "ABCDEFGHIXYZ"],
+ \ [':s/\%#=0\%' . line('.') . 'l^\t...//g',
+ \ "!\"#$%&'()#+'-./0123456789:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~\<C-?>\u0080\u0082\u0090\u009b¦±¼ÇÓé"],
+ \ [':s/\%#=1\%' . line('.') . 'l^\t...//g',
+ \ "!\"#$%&'()#+'-./0123456789:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~\<C-?>\u0080\u0082\u0090\u009b¦±¼ÇÓé"],
+ \ [':s/\%#=2\%' . line('.') . 'l^\t...//g',
+ \ "!\"#$%&'()#+'-./0123456789:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~\<C-?>\u0080\u0082\u0090\u009b¦±¼ÇÓé"],
+ \ [':s/\%#=0[0-z]//g',
+ \ "\t\<C-L>\<C-M> !\"#$%&'()#+'-./{|}~\<C-?>\u0080\u0082\u0090\u009b¦±¼ÇÓé"],
+ \ [':s/\%#=1[0-z]//g',
+ \ "\t\<C-L>\<C-M> !\"#$%&'()#+'-./{|}~\<C-?>\u0080\u0082\u0090\u009b¦±¼ÇÓé"],
+ \ [':s/\%#=2[0-z]//g',
+ \ "\t\<C-L>\<C-M> !\"#$%&'()#+'-./{|}~\<C-?>\u0080\u0082\u0090\u009b¦±¼ÇÓé"],
+ \ [':s/\%#=0[^0-z]//g',
+ \ "0123456789:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz"],
+ \ [':s/\%#=1[^0-z]//g',
+ \ "0123456789:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz"],
+ \ [':s/\%#=2[^0-z]//g',
+ \ "0123456789:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz"]
+ \]
+
+ for [cmd, expected] in tests
+ call append(0, input)
+ call cursor(1, 1)
+ exe cmd
+ call assert_equal(expected, getline(1), cmd)
+ endfor
+
+ let &encoding = save_enc
+ enew!
+ close
+endfunc
diff --git a/src/testdir/test_regexp_latin.vim b/src/testdir/test_regexp_latin.vim
new file mode 100644
index 0000000..1524945
--- /dev/null
+++ b/src/testdir/test_regexp_latin.vim
@@ -0,0 +1,86 @@
+" Tests for regexp in latin1 encoding
+set encoding=latin1
+scriptencoding latin1
+
+func s:equivalence_test()
+ let str = "AÀÁÂÃÄÅ B C D EÈÉÊË F G H IÌÍÎÏ J K L M NÑ OÒÓÔÕÖØ P Q R S T UÙÚÛÜ V W X YÝ Z aàáâãäå b c d eèéêë f g h iìíîï j k l m nñ oòóôõöø p q r s t uùúûü v w x yýÿ z"
+ let groups = split(str)
+ for group1 in groups
+ for c in split(group1, '\zs')
+ " next statement confirms that equivalence class matches every
+ " character in group
+ call assert_match('^[[=' . c . '=]]*$', group1)
+ for group2 in groups
+ if group2 != group1
+ " next statement converts that equivalence class doesn't match
+ " a character in any other group
+ call assert_equal(-1, match(group2, '[[=' . c . '=]]'))
+ endif
+ endfor
+ endfor
+ endfor
+endfunc
+
+func Test_equivalence_re1()
+ set re=1
+ call s:equivalence_test()
+endfunc
+
+func Test_equivalence_re2()
+ set re=2
+ call s:equivalence_test()
+endfunc
+
+func Test_recursive_substitute()
+ new
+ s/^/\=execute("s#^##gn")
+ " check we are now not in the sandbox
+ call setwinvar(1, 'myvar', 1)
+ bwipe!
+endfunc
+
+func Test_nested_backrefs()
+ " Check example in change.txt.
+ new
+ for re in range(0, 2)
+ exe 'set re=' . re
+ call setline(1, 'aa ab x')
+ 1s/\(\(a[a-d] \)*\)\(x\)/-\1- -\2- -\3-/
+ call assert_equal('-aa ab - -ab - -x-', getline(1))
+
+ call assert_equal('-aa ab - -ab - -x-', substitute('aa ab x', '\(\(a[a-d] \)*\)\(x\)', '-\1- -\2- -\3-', ''))
+ endfor
+ bwipe!
+ set re=0
+endfunc
+
+func Test_eow_with_optional()
+ let expected = ['abc def', 'abc', 'def', '', '', '', '', '', '', '']
+ for re in range(0, 2)
+ exe 'set re=' . re
+ let actual = matchlist('abc def', '\(abc\>\)\?\s*\(def\)')
+ call assert_equal(expected, actual)
+ endfor
+endfunc
+
+func Test_backref()
+ new
+ call setline(1, ['one', 'two', 'three', 'four', 'five'])
+ call assert_equal(3, search('\%#=1\(e\)\1'))
+ call assert_equal(3, search('\%#=2\(e\)\1'))
+ call assert_fails('call search("\\%#=1\\(e\\1\\)")', 'E65:')
+ call assert_fails('call search("\\%#=2\\(e\\1\\)")', 'E65:')
+ bwipe!
+endfunc
+
+func Test_multi_failure()
+ set re=1
+ call assert_fails('/a**', 'E61:')
+ call assert_fails('/a*\+', 'E62:')
+ call assert_fails('/a\{a}', 'E554:')
+ set re=2
+ call assert_fails('/a**', 'E871:')
+ call assert_fails('/a*\+', 'E871:')
+ call assert_fails('/a\{a}', 'E870:')
+ set re=0
+endfunc
diff --git a/src/testdir/test_regexp_utf8.vim b/src/testdir/test_regexp_utf8.vim
new file mode 100644
index 0000000..98b9e73
--- /dev/null
+++ b/src/testdir/test_regexp_utf8.vim
@@ -0,0 +1,208 @@
+" Tests for regexp in utf8 encoding
+
+func s:equivalence_test()
+ let str = "AÀÃÂÃÄÅĀĂĄÇǞǠẢ BḂḆ CÇĆĈĊČ DÄŽÄḊḎḠEÈÉÊËĒĔĖĘĚẺẼ FḞ GĜĞĠĢǤǦǴḠ HĤĦḢḦḨ IÃŒÃÃŽÃĨĪĬĮİÇỈ JÄ´ KĶǨḰḴ LĹĻĽĿÅḺ MḾṀ NÑŃŅŇṄṈ OÒÓÔÕÖØŌŎÅƠǑǪǬỎ PṔṖ Q RŔŖŘṘṞ SŚŜŞŠṠ TŢŤŦṪṮ UÙÚÛÜŨŪŬŮŰŲƯǓỦ Vá¹¼ WŴẀẂẄẆ XẊẌ YÃŶŸẎỲỶỸ ZŹŻŽƵáºáº” aàáâãäåÄăąǎǟǡả bḃḇ cÃ§Ä‡Ä‰Ä‹Ä dÄđḋá¸á¸‘ eèéêëēĕėęěẻẽ fḟ gÄğġģǥǧǵḡ hĥħḣḧḩẖ iìíîïĩīĭįÇỉ jĵǰ kķǩḱḵ lĺļľŀłḻ mḿṠnñńņňʼnṅṉ oòóôõöøÅÅÅ‘Æ¡Ç’Ç«Ç­á» pṕṗ q rŕŗřṙṟ sÅ›Åşšṡ tţťŧṫṯẗ uùúûüũūŭůűųưǔủ vá¹½ wŵáºáºƒáº…ẇẘ xẋẠyýÿŷáºáº™á»³á»·á»¹ zźżžƶẑẕ"
+ let groups = split(str)
+ for group1 in groups
+ for c in split(group1, '\zs')
+ " next statement confirms that equivalence class matches every
+ " character in group
+ call assert_match('^[[=' . c . '=]]*$', group1)
+ for group2 in groups
+ if group2 != group1
+ " next statement converts that equivalence class doesn't match
+ " character in any other group
+ call assert_equal(-1, match(group2, '[[=' . c . '=]]'))
+ endif
+ endfor
+ endfor
+ endfor
+endfunc
+
+func Test_equivalence_re1()
+ set re=1
+ call s:equivalence_test()
+ set re=0
+endfunc
+
+func Test_equivalence_re2()
+ set re=2
+ call s:equivalence_test()
+ set re=0
+endfunc
+
+func s:classes_test()
+ set isprint=@,161-255
+ call assert_equal('Motörhead', matchstr('Motörhead', '[[:print:]]\+'))
+
+ let alnumchars = ''
+ let alphachars = ''
+ let backspacechar = ''
+ let blankchars = ''
+ let cntrlchars = ''
+ let digitchars = ''
+ let escapechar = ''
+ let graphchars = ''
+ let lowerchars = ''
+ let printchars = ''
+ let punctchars = ''
+ let returnchar = ''
+ let spacechars = ''
+ let tabchar = ''
+ let upperchars = ''
+ let xdigitchars = ''
+ let identchars = ''
+ let identchars1 = ''
+ let kwordchars = ''
+ let kwordchars1 = ''
+ let fnamechars = ''
+ let fnamechars1 = ''
+ let i = 1
+ while i <= 255
+ let c = nr2char(i)
+ if c =~ '[[:alpha:]]'
+ let alphachars .= c
+ endif
+ if c =~ '[[:alnum:]]'
+ let alnumchars .= c
+ endif
+ if c =~ '[[:backspace:]]'
+ let backspacechar .= c
+ endif
+ if c =~ '[[:blank:]]'
+ let blankchars .= c
+ endif
+ if c =~ '[[:cntrl:]]'
+ let cntrlchars .= c
+ endif
+ if c =~ '[[:digit:]]'
+ let digitchars .= c
+ endif
+ if c =~ '[[:escape:]]'
+ let escapechar .= c
+ endif
+ if c =~ '[[:graph:]]'
+ let graphchars .= c
+ endif
+ if c =~ '[[:lower:]]'
+ let lowerchars .= c
+ endif
+ if c =~ '[[:print:]]'
+ let printchars .= c
+ endif
+ if c =~ '[[:punct:]]'
+ let punctchars .= c
+ endif
+ if c =~ '[[:return:]]'
+ let returnchar .= c
+ endif
+ if c =~ '[[:space:]]'
+ let spacechars .= c
+ endif
+ if c =~ '[[:tab:]]'
+ let tabchar .= c
+ endif
+ if c =~ '[[:upper:]]'
+ let upperchars .= c
+ endif
+ if c =~ '[[:xdigit:]]'
+ let xdigitchars .= c
+ endif
+ if c =~ '[[:ident:]]'
+ let identchars .= c
+ endif
+ if c =~ '\i'
+ let identchars1 .= c
+ endif
+ if c =~ '[[:keyword:]]'
+ let kwordchars .= c
+ endif
+ if c =~ '\k'
+ let kwordchars1 .= c
+ endif
+ if c =~ '[[:fname:]]'
+ let fnamechars .= c
+ endif
+ if c =~ '\f'
+ let fnamechars1 .= c
+ endif
+ let i += 1
+ endwhile
+
+ call assert_equal('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', alphachars)
+ call assert_equal('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', alnumchars)
+ call assert_equal("\b", backspacechar)
+ call assert_equal("\t ", blankchars)
+ call assert_equal("\x01\x02\x03\x04\x05\x06\x07\b\t\n\x0b\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\e\x1c\x1d\x1e\x1f\x7f", cntrlchars)
+ call assert_equal("0123456789", digitchars)
+ call assert_equal("\<Esc>", escapechar)
+ call assert_equal('!"#$%&''()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~', graphchars)
+ call assert_equal('abcdefghijklmnopqrstuvwxyzµßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿ', lowerchars)
+ call assert_equal(' !"#$%&''()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÃÂÃÄÅÆÇÈÉÊËÌÃÃŽÃÃÑÒÓÔÕÖ×ØÙÚÛÜÃÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ', printchars)
+ call assert_equal('!"#$%&''()*+,-./:;<=>?@[\]^_`{|}~', punctchars)
+ call assert_equal('ABCDEFGHIJKLMNOPQRSTUVWXYZÀÃÂÃÄÅÆÇÈÉÊËÌÃÃŽÃÃÑÒÓÔÕÖØÙÚÛÜÃÞ', upperchars)
+ call assert_equal("\r", returnchar)
+ call assert_equal("\t\n\x0b\f\r ", spacechars)
+ call assert_equal("\t", tabchar)
+ call assert_equal('0123456789ABCDEFabcdef', xdigitchars)
+
+ if has('win32')
+ let identchars_ok = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz€Â‚ƒ„…†‡ˆ‰Š‹ŒÂŽ‘’“”•–—˜™š›œÂžŸ ¡¢£¤¥¦§µÀÃÂÃÄÅÆÇÈÉÊËÌÃÃŽÃÃÑÒÓÔÕÖØÙÚÛÜÃÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿ'
+ let kwordchars_ok = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyzµÀÃÂÃÄÅÆÇÈÉÊËÌÃÃŽÃÃÑÒÓÔÕÖ×ØÙÚÛÜÃÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ'
+ elseif has('ebcdic')
+ let identchars_ok = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz€ŒÂŽœž¬®µº¿ÀÃÂÃÄÅÆÇÈÉÊËÌÃÃŽÃÃÑÒÓÔÕÖØÙÚÛÜÃÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ'
+ let kwordchars_ok = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz€ŒÂŽœž¬®µº¿ÀÃÂÃÄÅÆÇÈÉÊËÌÃÃŽÃÃÑÒÓÔÕÖØÙÚÛÜÃÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ'
+ else
+ let identchars_ok = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyzµÀÃÂÃÄÅÆÇÈÉÊËÌÃÃŽÃÃÑÒÓÔÕÖ×ØÙÚÛÜÃÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ'
+ let kwordchars_ok = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyzµÀÃÂÃÄÅÆÇÈÉÊËÌÃÃŽÃÃÑÒÓÔÕÖ×ØÙÚÛÜÃÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ'
+ endif
+
+ if has('win32')
+ let fnamechars_ok = '!#$%+,-./0123456789:=@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]_abcdefghijklmnopqrstuvwxyz{}~ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÃÂÃÄÅÆÇÈÉÊËÌÃÃŽÃÃÑÒÓÔÕÖ×ØÙÚÛÜÃÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ'
+ elseif has('amiga')
+ let fnamechars_ok = '$+,-./0123456789:ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÃÂÃÄÅÆÇÈÉÊËÌÃÃŽÃÃÑÒÓÔÕÖ×ØÙÚÛÜÃÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ'
+ elseif has('vms')
+ let fnamechars_ok = '#$%+,-./0123456789:;<>ABCDEFGHIJKLMNOPQRSTUVWXYZ[]_abcdefghijklmnopqrstuvwxyz~ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÃÂÃÄÅÆÇÈÉÊËÌÃÃŽÃÃÑÒÓÔÕÖ×ØÙÚÛÜÃÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ'
+ elseif has('ebcdic')
+ let fnamechars_ok = '#$%+,-./=ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÃÂÃÄÅÆÇÈÉÊËÌÃÃŽÃÃÑÒÓÔÕÖ×ØÙÚÛÜÃÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ'
+ else
+ let fnamechars_ok = '#$%+,-./0123456789=ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÃÂÃÄÅÆÇÈÉÊËÌÃÃŽÃÃÑÒÓÔÕÖ×ØÙÚÛÜÃÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ'
+ endif
+
+ call assert_equal(identchars_ok, identchars)
+ call assert_equal(kwordchars_ok, kwordchars)
+ call assert_equal(fnamechars_ok, fnamechars)
+
+ call assert_equal(identchars1, identchars)
+ call assert_equal(kwordchars1, kwordchars)
+ call assert_equal(fnamechars1, fnamechars)
+endfunc
+
+func Test_classes_re1()
+ set re=1
+ call s:classes_test()
+ set re=0
+endfunc
+
+func Test_classes_re2()
+ set re=2
+ call s:classes_test()
+ set re=0
+endfunc
+
+func Test_reversed_range()
+ for re in range(0, 2)
+ exe 'set re=' . re
+ call assert_fails('call match("abc def", "[c-a]")', 'E944:')
+ endfor
+ set re=0
+endfunc
+
+func Test_large_class()
+ set re=1
+ call assert_fails('call match("abc def", "[\u3000-\u4000]")', 'E945:')
+ set re=2
+ call assert_equal(0, 'abc def' =~# '[\u3000-\u4000]')
+ call assert_equal(1, "\u3042" =~# '[\u3000-\u4000]')
+ set re=0
+endfunc
diff --git a/src/testdir/test_registers.vim b/src/testdir/test_registers.vim
new file mode 100644
index 0000000..d7b6de5
--- /dev/null
+++ b/src/testdir/test_registers.vim
@@ -0,0 +1,65 @@
+
+func Test_yank_shows_register()
+ enew
+ set report=0
+ call setline(1, ['foo', 'bar'])
+ " Line-wise
+ exe 'norm! yy'
+ call assert_equal('1 line yanked', v:statusmsg)
+ exe 'norm! "zyy'
+ call assert_equal('1 line yanked into "z', v:statusmsg)
+ exe 'norm! yj'
+ call assert_equal('2 lines yanked', v:statusmsg)
+ exe 'norm! "zyj'
+ call assert_equal('2 lines yanked into "z', v:statusmsg)
+
+ " Block-wise
+ exe "norm! \<C-V>y"
+ call assert_equal('block of 1 line yanked', v:statusmsg)
+ exe "norm! \<C-V>\"zy"
+ call assert_equal('block of 1 line yanked into "z', v:statusmsg)
+ exe "norm! \<C-V>jy"
+ call assert_equal('block of 2 lines yanked', v:statusmsg)
+ exe "norm! \<C-V>j\"zy"
+ call assert_equal('block of 2 lines yanked into "z', v:statusmsg)
+
+ bwipe!
+endfunc
+
+func Test_display_registers()
+ e file1
+ e file2
+ call setline(1, ['foo', 'bar'])
+ /bar
+ exe 'norm! y2l"axx'
+ call feedkeys("i\<C-R>=2*4\n\<esc>")
+ call feedkeys(":ls\n", 'xt')
+
+ let a = execute('display')
+ let b = execute('registers')
+
+ call assert_equal(a, b)
+ call assert_match('^\n--- Registers ---\n'
+ \ . '"" a\n'
+ \ . '"0 ba\n'
+ \ . '"1 b\n'
+ \ . '"a b\n'
+ \ . '.*'
+ \ . '"- a\n'
+ \ . '.*'
+ \ . '": ls\n'
+ \ . '"% file2\n'
+ \ . '"# file1\n'
+ \ . '"/ bar\n'
+ \ . '"= 2\*4', a)
+
+ let a = execute('registers a')
+ call assert_match('^\n--- Registers ---\n'
+ \ . '"a b', a)
+
+ let a = execute('registers :')
+ call assert_match('^\n--- Registers ---\n'
+ \ . '": ls', a)
+
+ bwipe!
+endfunc
diff --git a/src/testdir/test_reltime.vim b/src/testdir/test_reltime.vim
new file mode 100644
index 0000000..adabf16
--- /dev/null
+++ b/src/testdir/test_reltime.vim
@@ -0,0 +1,26 @@
+" Tests for reltime()
+
+if !has('reltime') || !has('float')
+ finish
+endif
+
+func Test_reltime()
+ let now = reltime()
+ sleep 10m
+ let later = reltime()
+ let elapsed = reltime(now)
+ call assert_true(reltimestr(elapsed) =~ '0\.0')
+ call assert_true(reltimestr(elapsed) != '0.0')
+ call assert_true(reltimefloat(elapsed) < 0.1)
+ call assert_true(reltimefloat(elapsed) > 0.0)
+
+ let same = reltime(now, now)
+ call assert_equal('0.000', split(reltimestr(same))[0][:4])
+ call assert_equal(0.0, reltimefloat(same))
+
+ let differs = reltime(now, later)
+ call assert_true(reltimestr(differs) =~ '0\.0')
+ call assert_true(reltimestr(differs) != '0.0')
+ call assert_true(reltimefloat(differs) < 0.1)
+ call assert_true(reltimefloat(differs) > 0.0)
+endfunc
diff --git a/src/testdir/test_retab.vim b/src/testdir/test_retab.vim
new file mode 100644
index 0000000..f11a32b
--- /dev/null
+++ b/src/testdir/test_retab.vim
@@ -0,0 +1,77 @@
+" Test :retab
+func SetUp()
+ new
+ call setline(1, "\ta \t b c ")
+endfunc
+
+func TearDown()
+ bwipe!
+endfunc
+
+func Retab(bang, n)
+ let l:old_tabstop = &tabstop
+ let l:old_line = getline(1)
+ exe "retab" . a:bang . a:n
+ let l:line = getline(1)
+ call setline(1, l:old_line)
+ if a:n > 0
+ " :retab changes 'tabstop' to n with argument n > 0.
+ call assert_equal(a:n, &tabstop)
+ exe 'set tabstop=' . l:old_tabstop
+ else
+ " :retab does not change 'tabstop' with empty or n <= 0.
+ call assert_equal(l:old_tabstop, &tabstop)
+ endif
+ return l:line
+endfunc
+
+func Test_retab()
+ set tabstop=8 noexpandtab
+ call assert_equal("\ta\t b c ", Retab('', ''))
+ call assert_equal("\ta\t b c ", Retab('', 0))
+ call assert_equal("\ta\t b c ", Retab('', 8))
+ call assert_equal("\ta\t b\t c\t ", Retab('!', ''))
+ call assert_equal("\ta\t b\t c\t ", Retab('!', 0))
+ call assert_equal("\ta\t b\t c\t ", Retab('!', 8))
+
+ call assert_equal("\t\ta\t\t\tb c ", Retab('', 4))
+ call assert_equal("\t\ta\t\t\tb\t\t c\t ", Retab('!', 4))
+
+ call assert_equal(" a\t\tb c ", Retab('', 10))
+ call assert_equal(" a\t\tb c ", Retab('!', 10))
+
+ set tabstop=8 expandtab
+ call assert_equal(" a b c ", Retab('', ''))
+ call assert_equal(" a b c ", Retab('', 0))
+ call assert_equal(" a b c ", Retab('', 8))
+ call assert_equal(" a b c ", Retab('!', ''))
+ call assert_equal(" a b c ", Retab('!', 0))
+ call assert_equal(" a b c ", Retab('!', 8))
+
+ call assert_equal(" a b c ", Retab(' ', 4))
+ call assert_equal(" a b c ", Retab('!', 4))
+
+ call assert_equal(" a b c ", Retab(' ', 10))
+ call assert_equal(" a b c ", Retab('!', 10))
+
+ set tabstop=4 noexpandtab
+ call assert_equal("\ta\t\tb c ", Retab('', ''))
+ call assert_equal("\ta\t\tb\t\t c\t ", Retab('!', ''))
+ call assert_equal("\t a\t\t\tb c ", Retab('', 3))
+ call assert_equal("\t a\t\t\tb\t\t\tc\t ", Retab('!', 3))
+ call assert_equal(" a\t b c ", Retab('', 5))
+ call assert_equal(" a\t b\t\t c\t ", Retab('!', 5))
+
+ set tabstop=4 expandtab
+ call assert_equal(" a b c ", Retab('', ''))
+ call assert_equal(" a b c ", Retab('!', ''))
+ call assert_equal(" a b c ", Retab('', 3))
+ call assert_equal(" a b c ", Retab('!', 3))
+ call assert_equal(" a b c ", Retab('', 5))
+ call assert_equal(" a b c ", Retab('!', 5))
+endfunc
+
+func Test_retab_error()
+ call assert_fails('retab -1', 'E487:')
+ call assert_fails('retab! -1', 'E487:')
+endfunc
diff --git a/src/testdir/test_ruby.vim b/src/testdir/test_ruby.vim
new file mode 100644
index 0000000..5476e51
--- /dev/null
+++ b/src/testdir/test_ruby.vim
@@ -0,0 +1,379 @@
+" Tests for ruby interface
+
+if !has('ruby')
+ finish
+end
+
+" Helper function as there is no builtin rubyeval() function similar
+" to perleval, luaevel() or pyeval().
+func RubyEval(ruby_expr)
+ let s = split(execute('ruby print ' . a:ruby_expr), "\n")
+ return (len(s) == 0) ? '' : s[-1]
+endfunc
+
+func Test_ruby_change_buffer()
+ call setline(line('$'), ['1 line 1'])
+ ruby Vim.command("normal /^1\n")
+ ruby $curbuf.line = "1 changed line 1"
+ call assert_equal('1 changed line 1', getline('$'))
+endfunc
+
+func Test_rubydo()
+ " Check deleting lines does not trigger ml_get error.
+ new
+ call setline(1, ['one', 'two', 'three'])
+ rubydo Vim.command("%d_")
+ bwipe!
+
+ " Check switching to another buffer does not trigger ml_get error.
+ new
+ let wincount = winnr('$')
+ call setline(1, ['one', 'two', 'three'])
+ rubydo Vim.command("new")
+ call assert_equal(wincount + 1, winnr('$'))
+ %bwipe!
+endfunc
+
+func Test_rubyfile()
+ " Check :rubyfile does not SEGV with Ruby level exception but just fails
+ let tempfile = tempname() . '.rb'
+ call writefile(['raise "vim!"'], tempfile)
+ call assert_fails('rubyfile ' . tempfile)
+ call delete(tempfile)
+endfunc
+
+func Test_set_cursor()
+ " Check that setting the cursor position works.
+ new
+ call setline(1, ['first line', 'second line'])
+ normal gg
+ rubydo $curwin.cursor = [1, 5]
+ call assert_equal([1, 6], [line('.'), col('.')])
+ call assert_equal('[1, 5]', RubyEval('$curwin.cursor'))
+
+ " Check that movement after setting cursor position keeps current column.
+ normal j
+ call assert_equal([2, 6], [line('.'), col('.')])
+ call assert_equal('[2, 5]', RubyEval('$curwin.cursor'))
+
+ call assert_fails('ruby $curwin.cursor = [1]',
+ \ 'ArgumentError: array length must be 2')
+ bwipe!
+endfunc
+
+" Test buffer.count and buffer.length (number of lines in buffer)
+func Test_buffer_count()
+ new
+ call setline(1, ['one', 'two', 'three'])
+ call assert_equal('3', RubyEval('$curbuf.count'))
+ call assert_equal('3', RubyEval('$curbuf.length'))
+ bwipe!
+endfunc
+
+" Test buffer.name (buffer name)
+func Test_buffer_name()
+ new Xfoo
+ call assert_equal(expand('%:p'), RubyEval('$curbuf.name'))
+ bwipe
+ call assert_equal('', RubyEval('$curbuf.name'))
+endfunc
+
+" Test buffer.number (number of the buffer).
+func Test_buffer_number()
+ new
+ call assert_equal(string(bufnr('%')), RubyEval('$curbuf.number'))
+ new
+ call assert_equal(string(bufnr('%')), RubyEval('$curbuf.number'))
+
+ %bwipe
+endfunc
+
+" Test buffer.delete({n}) (delete line {n})
+func Test_buffer_delete()
+ new
+ call setline(1, ['one', 'two', 'three'])
+ ruby $curbuf.delete(2)
+ call assert_equal(['one', 'three'], getline(1, '$'))
+
+ call assert_fails('ruby $curbuf.delete(0)', 'IndexError: line number 0 out of range')
+ call assert_fails('ruby $curbuf.delete(3)', 'IndexError: line number 3 out of range')
+
+ bwipe!
+endfunc
+
+" Test buffer.append({str}, str) (append line {str} after line {n})
+func Test_buffer_append()
+ new
+ ruby $curbuf.append(0, 'one')
+ ruby $curbuf.append(1, 'three')
+ ruby $curbuf.append(1, 'two')
+ ruby $curbuf.append(4, 'four')
+
+ call assert_equal(['one', 'two', 'three', '', 'four'], getline(1, '$'))
+
+ call assert_fails('ruby $curbuf.append(-1, "x")',
+ \ 'IndexError: line number -1 out of range')
+ call assert_fails('ruby $curbuf.append(6, "x")',
+ \ 'IndexError: line number 6 out of range')
+
+ bwipe!
+endfunc
+
+" Test buffer.line (get or set the current line)
+func Test_buffer_line()
+ new
+ call setline(1, ['one', 'two', 'three'])
+ 2
+ call assert_equal('two', RubyEval('$curbuf.line'))
+
+ ruby $curbuf.line = 'TWO'
+ call assert_equal(['one', 'TWO', 'three'], getline(1, '$'))
+
+ bwipe!
+endfunc
+
+" Test buffer.line_number (get current line number)
+func Test_buffer_line_number()
+ new
+ call setline(1, ['one', 'two', 'three'])
+ 2
+ call assert_equal('2', RubyEval('$curbuf.line_number'))
+
+ bwipe!
+endfunc
+
+func Test_buffer_get()
+ new
+ call setline(1, ['one', 'two'])
+ call assert_equal('one', RubyEval('$curbuf[1]'))
+ call assert_equal('two', RubyEval('$curbuf[2]'))
+
+ call assert_fails('ruby $curbuf[0]',
+ \ 'IndexError: line number 0 out of range')
+ call assert_fails('ruby $curbuf[3]',
+ \ 'IndexError: line number 3 out of range')
+
+ bwipe!
+endfunc
+
+func Test_buffer_set()
+ new
+ call setline(1, ['one', 'two'])
+ ruby $curbuf[2] = 'TWO'
+ ruby $curbuf[1] = 'ONE'
+
+ call assert_fails('ruby $curbuf[0] = "ZERO"',
+ \ 'IndexError: line number 0 out of range')
+ call assert_fails('ruby $curbuf[3] = "THREE"',
+ \ 'IndexError: line number 3 out of range')
+ bwipe!
+endfunc
+
+" Test window.width (get or set window height).
+func Test_window_height()
+ new
+
+ " Test setting window height
+ ruby $curwin.height = 2
+ call assert_equal(2, winheight(0))
+
+ " Test getting window height
+ call assert_equal('2', RubyEval('$curwin.height'))
+
+ bwipe
+endfunc
+
+" Test window.width (get or set window width).
+func Test_window_width()
+ vnew
+
+ " Test setting window width
+ ruby $curwin.width = 2
+ call assert_equal(2, winwidth(0))
+
+ " Test getting window width
+ call assert_equal('2', RubyEval('$curwin.width'))
+
+ bwipe
+endfunc
+
+" Test window.buffer (get buffer object of a window object).
+func Test_window_buffer()
+ new Xfoo1
+ new Xfoo2
+ ruby $b2 = $curwin.buffer
+ ruby $w2 = $curwin
+ wincmd j
+ ruby $b1 = $curwin.buffer
+ ruby $w1 = $curwin
+
+ call assert_equal(RubyEval('$b1'), RubyEval('$w1.buffer'))
+ call assert_equal(RubyEval('$b2'), RubyEval('$w2.buffer'))
+ call assert_equal(string(bufnr('Xfoo1')), RubyEval('$w1.buffer.number'))
+ call assert_equal(string(bufnr('Xfoo2')), RubyEval('$w2.buffer.number'))
+
+ ruby $b1, $w1, $b2, $w2 = nil
+ %bwipe
+endfunc
+
+" Test Vim::Window.current (get current window object)
+func Test_Vim_window_current()
+ let cw = RubyEval('$curwin')
+ call assert_equal(cw, RubyEval('Vim::Window.current'))
+ call assert_match('^#<Vim::Window:0x\x\+>$', cw)
+endfunc
+
+" Test Vim::Window.count (number of windows)
+func Test_Vim_window_count()
+ new Xfoo1
+ new Xfoo2
+ split
+ call assert_equal('4', RubyEval('Vim::Window.count'))
+ %bwipe
+ call assert_equal('1', RubyEval('Vim::Window.count'))
+endfunc
+
+" Test Vim::Window[n] (get window object of window n)
+func Test_Vim_window_get()
+ new Xfoo1
+ new Xfoo2
+ call assert_match('Xfoo2$', RubyEval('Vim::Window[0].buffer.name'))
+ wincmd j
+ call assert_match('Xfoo1$', RubyEval('Vim::Window[1].buffer.name'))
+ wincmd j
+ call assert_equal('', RubyEval('Vim::Window[2].buffer.name'))
+ %bwipe
+endfunc
+
+" Test Vim::Buffer.current (return the buffer object of current buffer)
+func Test_Vim_buffer_current()
+ let cb = RubyEval('$curbuf')
+ call assert_equal(cb, RubyEval('Vim::Buffer.current'))
+ call assert_match('^#<Vim::Buffer:0x\x\+>$', cb)
+endfunc
+
+" Test Vim::Buffer:.count (return the number of buffers)
+func Test_Vim_buffer_count()
+ new Xfoo1
+ new Xfoo2
+ call assert_equal('3', RubyEval('Vim::Buffer.count'))
+ %bwipe
+ call assert_equal('1', RubyEval('Vim::Buffer.count'))
+endfunc
+
+" Test Vim::buffer[n] (return the buffer object of buffer number n)
+func Test_Vim_buffer_get()
+ new Xfoo1
+ new Xfoo2
+
+ " Index of Vim::Buffer[n] goes from 0 to the number of buffers.
+ call assert_equal('', RubyEval('Vim::Buffer[0].name'))
+ call assert_match('Xfoo1$', RubyEval('Vim::Buffer[1].name'))
+ call assert_match('Xfoo2$', RubyEval('Vim::Buffer[2].name'))
+ call assert_fails('ruby print Vim::Buffer[3].name',
+ \ "NoMethodError: undefined method `name' for nil:NilClass")
+ %bwipe
+endfunc
+
+" Test Vim::command({cmd}) (execute a Ex command))
+" Test Vim::command({cmd})
+func Test_Vim_command()
+ new
+ call setline(1, ['one', 'two', 'three', 'four'])
+ ruby Vim::command('2,3d')
+ call assert_equal(['one', 'four'], getline(1, '$'))
+ bwipe!
+endfunc
+
+" Test Vim::set_option (set a vim option)
+func Test_Vim_set_option()
+ call assert_equal(0, &number)
+ ruby Vim::set_option('number')
+ call assert_equal(1, &number)
+ ruby Vim::set_option('nonumber')
+ call assert_equal(0, &number)
+endfunc
+
+func Test_Vim_evaluate()
+ call assert_equal('123', RubyEval('Vim::evaluate("123")'))
+ " Vim::evaluate("123").class gives Integer or Fixnum depending
+ " on versions of Ruby.
+ call assert_match('^Integer\|Fixnum$', RubyEval('Vim::evaluate("123").class'))
+
+ call assert_equal('1.23', RubyEval('Vim::evaluate("1.23")'))
+ call assert_equal('Float', RubyEval('Vim::evaluate("1.23").class'))
+
+ call assert_equal('foo', RubyEval('Vim::evaluate("\"foo\"")'))
+ call assert_equal('String', RubyEval('Vim::evaluate("\"foo\"").class'))
+
+ call assert_equal('[1, 2]', RubyEval('Vim::evaluate("[1, 2]")'))
+ call assert_equal('Array', RubyEval('Vim::evaluate("[1, 2]").class'))
+
+ call assert_equal('{"1"=>2}', RubyEval('Vim::evaluate("{1:2}")'))
+ call assert_equal('Hash', RubyEval('Vim::evaluate("{1:2}").class'))
+
+ call assert_equal('', RubyEval('Vim::evaluate("v:null")'))
+ call assert_equal('NilClass', RubyEval('Vim::evaluate("v:null").class'))
+
+ call assert_equal('', RubyEval('Vim::evaluate("v:none")'))
+ call assert_equal('NilClass', RubyEval('Vim::evaluate("v:none").class'))
+
+ call assert_equal('true', RubyEval('Vim::evaluate("v:true")'))
+ call assert_equal('TrueClass', RubyEval('Vim::evaluate("v:true").class'))
+ call assert_equal('false', RubyEval('Vim::evaluate("v:false")'))
+ call assert_equal('FalseClass',RubyEval('Vim::evaluate("v:false").class'))
+endfunc
+
+func Test_Vim_evaluate_list()
+ call setline(line('$'), ['2 line 2'])
+ ruby Vim.command("normal /^2\n")
+ let l = ["abc", "def"]
+ ruby << EOF
+ curline = $curbuf.line_number
+ l = Vim.evaluate("l");
+ $curbuf.append(curline, l.join("\n"))
+EOF
+ normal j
+ .rubydo $_ = $_.gsub(/\n/, '/')
+ call assert_equal('abc/def', getline('$'))
+endfunc
+
+func Test_Vim_evaluate_dict()
+ let d = {'a': 'foo', 'b': 123}
+ redir => l:out
+ ruby d = Vim.evaluate("d"); print d
+ redir END
+ call assert_equal(['{"a"=>"foo", "b"=>123}'], split(l:out, "\n"))
+endfunc
+
+" Test Vim::message({msg}) (display message {msg})
+func Test_Vim_message()
+ ruby Vim::message('A message')
+ let messages = split(execute('message'), "\n")
+ call assert_equal('A message', messages[-1])
+endfunc
+
+func Test_print()
+ ruby print "Hello World!"
+ let messages = split(execute('message'), "\n")
+ call assert_equal('Hello World!', messages[-1])
+endfunc
+
+func Test_p()
+ ruby p 'Just a test'
+ let messages = split(execute('message'), "\n")
+ call assert_equal('"Just a test"', messages[-1])
+
+ " Check return values of p method
+
+ call assert_equal('123', RubyEval('p(123)'))
+ call assert_equal('[1, 2, 3]', RubyEval('p(1, 2, 3)'))
+
+ " Avoid the "message maintainer" line.
+ let $LANG = ''
+ messages clear
+ call assert_equal('true', RubyEval('p() == nil'))
+
+ let messages = split(execute('message'), "\n")
+ call assert_equal(0, len(messages))
+endfunc
diff --git a/src/testdir/test_scriptnames.vim b/src/testdir/test_scriptnames.vim
new file mode 100644
index 0000000..fc6c910
--- /dev/null
+++ b/src/testdir/test_scriptnames.vim
@@ -0,0 +1,26 @@
+" Test for :scriptnames
+
+func Test_scriptnames()
+ call writefile(['let did_load_script = 123'], 'Xscripting')
+ source Xscripting
+ call assert_equal(123, g:did_load_script)
+
+ let scripts = split(execute('scriptnames'), "\n")
+ let last = scripts[-1]
+ call assert_match('\<Xscripting\>', last)
+ let lastnr = substitute(last, '\D*\(\d\+\):.*', '\1', '')
+ exe 'script ' . lastnr
+ call assert_equal('Xscripting', expand('%:t'))
+
+ call assert_fails('script ' . (lastnr + 1), 'E474:')
+ call assert_fails('script 0', 'E939:')
+
+ new
+ call setline(1, 'nothing')
+ call assert_fails('script ' . lastnr, 'E37:')
+ exe 'script! ' . lastnr
+ call assert_equal('Xscripting', expand('%:t'))
+
+ bwipe
+ call delete('Xscripting')
+endfunc
diff --git a/src/testdir/test_scroll_opt.vim b/src/testdir/test_scroll_opt.vim
new file mode 100644
index 0000000..77920eb
--- /dev/null
+++ b/src/testdir/test_scroll_opt.vim
@@ -0,0 +1,36 @@
+" Test for reset 'scroll'
+"
+
+func Test_reset_scroll()
+ let scr = &l:scroll
+
+ setlocal scroll=1
+ setlocal scroll&
+ call assert_equal(scr, &l:scroll)
+
+ setlocal scroll=1
+ setlocal scroll=0
+ call assert_equal(scr, &l:scroll)
+
+ try
+ execute 'setlocal scroll=' . (winheight(0) + 1)
+ " not reached
+ call assert_false(1)
+ catch
+ call assert_exception('E49:')
+ endtry
+
+ split
+
+ let scr = &l:scroll
+
+ setlocal scroll=1
+ setlocal scroll&
+ call assert_equal(scr, &l:scroll)
+
+ setlocal scroll=1
+ setlocal scroll=0
+ call assert_equal(scr, &l:scroll)
+
+ quit!
+endfunc
diff --git a/src/testdir/test_scrollbind.vim b/src/testdir/test_scrollbind.vim
new file mode 100644
index 0000000..baa24f1
--- /dev/null
+++ b/src/testdir/test_scrollbind.vim
@@ -0,0 +1,32 @@
+" Test for 'scrollbind' causing an unexpected scroll of one of the windows.
+func Test_scrollbind()
+ " We don't want the status line to cause problems:
+ set laststatus=0
+ let totalLines = &lines * 20
+ let middle = totalLines / 2
+ new | only
+ for i in range(1, totalLines)
+ call setline(i, 'LINE ' . i)
+ endfor
+ exe string(middle)
+ normal zt
+ normal M
+ aboveleft vert new
+ for i in range(1, totalLines)
+ call setline(i, 'line ' . i)
+ endfor
+ exe string(middle)
+ normal zt
+ normal M
+ " Execute the following two commands at once to reproduce the problem.
+ setl scb | wincmd p
+ setl scb
+ wincmd w
+ let topLineLeft = line('w0')
+ wincmd p
+ let topLineRight = line('w0')
+ setl noscrollbind
+ wincmd p
+ setl noscrollbind
+ call assert_equal(0, topLineLeft - topLineRight)
+endfunc
diff --git a/src/testdir/test_search.vim b/src/testdir/test_search.vim
new file mode 100644
index 0000000..0dfea49
--- /dev/null
+++ b/src/testdir/test_search.vim
@@ -0,0 +1,1189 @@
+" Test for the search command
+
+source shared.vim
+source screendump.vim
+
+func Test_search_cmdline()
+ if !exists('+incsearch')
+ return
+ endif
+ " need to disable char_avail,
+ " so that expansion of commandline works
+ call test_override("char_avail", 1)
+ new
+ call setline(1, [' 1', ' 2 these', ' 3 the', ' 4 their', ' 5 there', ' 6 their', ' 7 the', ' 8 them', ' 9 these', ' 10 foobar'])
+ " Test 1
+ " CTRL-N / CTRL-P skips through the previous search history
+ set noincsearch
+ :1
+ call feedkeys("/foobar\<cr>", 'tx')
+ call feedkeys("/the\<cr>",'tx')
+ call assert_equal('the', @/)
+ call feedkeys("/thes\<C-P>\<C-P>\<cr>",'tx')
+ call assert_equal('foobar', @/)
+
+ " Test 2
+ " Ctrl-G goes from one match to the next
+ " until the end of the buffer
+ set incsearch nowrapscan
+ :1
+ " first match
+ call feedkeys("/the\<cr>", 'tx')
+ call assert_equal(' 2 these', getline('.'))
+ :1
+ " second match
+ call feedkeys("/the\<C-G>\<cr>", 'tx')
+ call assert_equal(' 3 the', getline('.'))
+ call assert_equal([0, 0, 0, 0], getpos('"'))
+ :1
+ " third match
+ call feedkeys("/the".repeat("\<C-G>", 2)."\<cr>", 'tx')
+ call assert_equal(' 4 their', getline('.'))
+ :1
+ " fourth match
+ call feedkeys("/the".repeat("\<C-G>", 3)."\<cr>", 'tx')
+ call assert_equal(' 5 there', getline('.'))
+ :1
+ " fifth match
+ call feedkeys("/the".repeat("\<C-G>", 4)."\<cr>", 'tx')
+ call assert_equal(' 6 their', getline('.'))
+ :1
+ " sixth match
+ call feedkeys("/the".repeat("\<C-G>", 5)."\<cr>", 'tx')
+ call assert_equal(' 7 the', getline('.'))
+ :1
+ " seventh match
+ call feedkeys("/the".repeat("\<C-G>", 6)."\<cr>", 'tx')
+ call assert_equal(' 8 them', getline('.'))
+ :1
+ " eigth match
+ call feedkeys("/the".repeat("\<C-G>", 7)."\<cr>", 'tx')
+ call assert_equal(' 9 these', getline('.'))
+ :1
+ " no further match
+ call feedkeys("/the".repeat("\<C-G>", 8)."\<cr>", 'tx')
+ call assert_equal(' 9 these', getline('.'))
+ call assert_equal([0, 0, 0, 0], getpos('"'))
+
+ " Test 3
+ " Ctrl-G goes from one match to the next
+ " and continues back at the top
+ set incsearch wrapscan
+ :1
+ " first match
+ call feedkeys("/the\<cr>", 'tx')
+ call assert_equal(' 2 these', getline('.'))
+ :1
+ " second match
+ call feedkeys("/the\<C-G>\<cr>", 'tx')
+ call assert_equal(' 3 the', getline('.'))
+ :1
+ " third match
+ call feedkeys("/the".repeat("\<C-G>", 2)."\<cr>", 'tx')
+ call assert_equal(' 4 their', getline('.'))
+ :1
+ " fourth match
+ call feedkeys("/the".repeat("\<C-G>", 3)."\<cr>", 'tx')
+ call assert_equal(' 5 there', getline('.'))
+ :1
+ " fifth match
+ call feedkeys("/the".repeat("\<C-G>", 4)."\<cr>", 'tx')
+ call assert_equal(' 6 their', getline('.'))
+ :1
+ " sixth match
+ call feedkeys("/the".repeat("\<C-G>", 5)."\<cr>", 'tx')
+ call assert_equal(' 7 the', getline('.'))
+ :1
+ " seventh match
+ call feedkeys("/the".repeat("\<C-G>", 6)."\<cr>", 'tx')
+ call assert_equal(' 8 them', getline('.'))
+ :1
+ " eigth match
+ call feedkeys("/the".repeat("\<C-G>", 7)."\<cr>", 'tx')
+ call assert_equal(' 9 these', getline('.'))
+ :1
+ " back at first match
+ call feedkeys("/the".repeat("\<C-G>", 8)."\<cr>", 'tx')
+ call assert_equal(' 2 these', getline('.'))
+
+ " Test 4
+ " CTRL-T goes to the previous match
+ set incsearch nowrapscan
+ $
+ " first match
+ call feedkeys("?the\<cr>", 'tx')
+ call assert_equal(' 9 these', getline('.'))
+ $
+ " first match
+ call feedkeys("?the\<C-G>\<cr>", 'tx')
+ call assert_equal(' 9 these', getline('.'))
+ $
+ " second match
+ call feedkeys("?the".repeat("\<C-T>", 1)."\<cr>", 'tx')
+ call assert_equal(' 8 them', getline('.'))
+ $
+ " last match
+ call feedkeys("?the".repeat("\<C-T>", 7)."\<cr>", 'tx')
+ call assert_equal(' 2 these', getline('.'))
+ $
+ " last match
+ call feedkeys("?the".repeat("\<C-T>", 8)."\<cr>", 'tx')
+ call assert_equal(' 2 these', getline('.'))
+
+ " Test 5
+ " CTRL-T goes to the previous match
+ set incsearch wrapscan
+ $
+ " first match
+ call feedkeys("?the\<cr>", 'tx')
+ call assert_equal(' 9 these', getline('.'))
+ $
+ " first match at the top
+ call feedkeys("?the\<C-G>\<cr>", 'tx')
+ call assert_equal(' 2 these', getline('.'))
+ $
+ " second match
+ call feedkeys("?the".repeat("\<C-T>", 1)."\<cr>", 'tx')
+ call assert_equal(' 8 them', getline('.'))
+ $
+ " last match
+ call feedkeys("?the".repeat("\<C-T>", 7)."\<cr>", 'tx')
+ call assert_equal(' 2 these', getline('.'))
+ $
+ " back at the bottom of the buffer
+ call feedkeys("?the".repeat("\<C-T>", 8)."\<cr>", 'tx')
+ call assert_equal(' 9 these', getline('.'))
+
+ " Test 6
+ " CTRL-L adds to the search pattern
+ set incsearch wrapscan
+ 1
+ " first match
+ call feedkeys("/the\<c-l>\<cr>", 'tx')
+ call assert_equal(' 2 these', getline('.'))
+ 1
+ " go to next match of 'thes'
+ call feedkeys("/the\<c-l>\<C-G>\<cr>", 'tx')
+ call assert_equal(' 9 these', getline('.'))
+ 1
+ " wrap around
+ call feedkeys("/the\<c-l>\<C-G>\<C-G>\<cr>", 'tx')
+ call assert_equal(' 2 these', getline('.'))
+ 1
+ " wrap around
+ set nowrapscan
+ call feedkeys("/the\<c-l>\<C-G>\<C-G>\<cr>", 'tx')
+ call assert_equal(' 9 these', getline('.'))
+
+ " Test 7
+ " <bs> remove from match, but stay at current match
+ set incsearch wrapscan
+ 1
+ " first match
+ call feedkeys("/thei\<cr>", 'tx')
+ call assert_equal(' 4 their', getline('.'))
+ 1
+ " delete one char, add another
+ call feedkeys("/thei\<bs>s\<cr>", 'tx')
+ call assert_equal(' 2 these', getline('.'))
+ 1
+ " delete one char, add another, go to previous match, add one char
+ call feedkeys("/thei\<bs>s\<bs>\<C-T>\<c-l>\<cr>", 'tx')
+ call assert_equal(' 9 these', getline('.'))
+ 1
+ " delete all chars, start from the beginning again
+ call feedkeys("/them". repeat("\<bs>",4).'the\>'."\<cr>", 'tx')
+ call assert_equal(' 3 the', getline('.'))
+
+ " clean up
+ call test_override("char_avail", 0)
+ bw!
+endfunc
+
+func Test_search_cmdline2()
+ if !exists('+incsearch')
+ return
+ endif
+ " need to disable char_avail,
+ " so that expansion of commandline works
+ call test_override("char_avail", 1)
+ new
+ call setline(1, [' 1', ' 2 these', ' 3 the theother'])
+ " Test 1
+ " Ctrl-T goes correctly back and forth
+ set incsearch
+ 1
+ " first match
+ call feedkeys("/the\<cr>", 'tx')
+ call assert_equal(' 2 these', getline('.'))
+ 1
+ " go to next match (on next line)
+ call feedkeys("/the\<C-G>\<cr>", 'tx')
+ call assert_equal(' 3 the theother', getline('.'))
+ 1
+ " go to next match (still on line 3)
+ call feedkeys("/the\<C-G>\<C-G>\<cr>", 'tx')
+ call assert_equal(' 3 the theother', getline('.'))
+ 1
+ " go to next match (still on line 3)
+ call feedkeys("/the\<C-G>\<C-G>\<C-G>\<cr>", 'tx')
+ call assert_equal(' 3 the theother', getline('.'))
+ 1
+ " go to previous match (on line 3)
+ call feedkeys("/the\<C-G>\<C-G>\<C-G>\<C-T>\<cr>", 'tx')
+ call assert_equal(' 3 the theother', getline('.'))
+ 1
+ " go to previous match (on line 3)
+ call feedkeys("/the\<C-G>\<C-G>\<C-G>\<C-T>\<C-T>\<cr>", 'tx')
+ call assert_equal(' 3 the theother', getline('.'))
+ 1
+ " go to previous match (on line 2)
+ call feedkeys("/the\<C-G>\<C-G>\<C-G>\<C-T>\<C-T>\<C-T>\<cr>", 'tx')
+ call assert_equal(' 2 these', getline('.'))
+
+ " Test 2: keep the view,
+ " after deleting a character from the search cmd
+ call setline(1, [' 1', ' 2 these', ' 3 the', ' 4 their', ' 5 there', ' 6 their', ' 7 the', ' 8 them', ' 9 these', ' 10 foobar'])
+ resize 5
+ 1
+ call feedkeys("/foo\<bs>\<cr>", 'tx')
+ redraw
+ call assert_equal({'lnum': 10, 'leftcol': 0, 'col': 4, 'topfill': 0, 'topline': 6, 'coladd': 0, 'skipcol': 0, 'curswant': 4}, winsaveview())
+
+ " remove all history entries
+ for i in range(10)
+ call histdel('/')
+ endfor
+
+ " Test 3: reset the view,
+ " after deleting all characters from the search cmd
+ norm! 1gg0
+ " unfortunately, neither "/foo\<c-w>\<cr>", nor "/foo\<bs>\<bs>\<bs>\<cr>",
+ " nor "/foo\<c-u>\<cr>" works to delete the commandline.
+ " In that case Vim should return "E35 no previous regular expression",
+ " but it looks like Vim still sees /foo and therefore the test fails.
+ " Therefore, disableing this test
+ "call assert_fails(feedkeys("/foo\<c-w>\<cr>", 'tx'), 'E35')
+ "call assert_equal({'lnum': 1, 'leftcol': 0, 'col': 0, 'topfill': 0, 'topline': 1, 'coladd': 0, 'skipcol': 0, 'curswant': 0}, winsaveview())
+
+ " clean up
+ set noincsearch
+ call test_override("char_avail", 0)
+ bw!
+endfunc
+
+func Test_use_sub_pat()
+ split
+ let @/ = ''
+ func X()
+ s/^/a/
+ /
+ endfunc
+ call X()
+ bwipe!
+endfunc
+
+func Test_searchpair()
+ new
+ call setline(1, ['other code here', '', '[', '" cursor here', ']'])
+ 4
+ let a = searchpair('\[','',']','bW')
+ call assert_equal(3, a)
+ set nomagic
+ 4
+ let a = searchpair('\[','',']','bW')
+ call assert_equal(3, a)
+ set magic
+ q!
+endfunc
+
+func Test_searchpair_errors()
+ call assert_fails("call searchpair([0], 'middle', 'end', 'bW', 'skip', 99, 100)", 'E730: using List as a String')
+ call assert_fails("call searchpair('start', {-> 0}, 'end', 'bW', 'skip', 99, 100)", 'E729: using Funcref as a String')
+ call assert_fails("call searchpair('start', 'middle', {'one': 1}, 'bW', 'skip', 99, 100)", 'E731: using Dictionary as a String')
+ call assert_fails("call searchpair('start', 'middle', 'end', 'flags', 'skip', 99, 100)", 'E475: Invalid argument: flags')
+ call assert_fails("call searchpair('start', 'middle', 'end', 'bW', 0, 99, 100)", 'E475: Invalid argument: 0')
+ call assert_fails("call searchpair('start', 'middle', 'end', 'bW', 'func', -99, 100)", 'E475: Invalid argument: -99')
+ call assert_fails("call searchpair('start', 'middle', 'end', 'bW', 'func', 99, -100)", 'E475: Invalid argument: -100')
+endfunc
+
+func Test_searchpair_skip()
+ func Zero()
+ return 0
+ endfunc
+ func Partial(x)
+ return a:x
+ endfunc
+ new
+ call setline(1, ['{', 'foo', 'foo', 'foo', '}'])
+ 3 | call assert_equal(1, searchpair('{', '', '}', 'bWn', ''))
+ 3 | call assert_equal(1, searchpair('{', '', '}', 'bWn', '0'))
+ 3 | call assert_equal(1, searchpair('{', '', '}', 'bWn', {-> 0}))
+ 3 | call assert_equal(1, searchpair('{', '', '}', 'bWn', function('Zero')))
+ 3 | call assert_equal(1, searchpair('{', '', '}', 'bWn', function('Partial', [0])))
+ bw!
+endfunc
+
+func Test_searchpair_leak()
+ new
+ call setline(1, 'if one else another endif')
+
+ " The error in the skip expression caused memory to leak.
+ call assert_fails("call searchpair('\\<if\\>', '\\<else\\>', '\\<endif\\>', '', '\"foo\" 2')", 'E15:')
+
+ bwipe!
+endfunc
+
+func Test_searchc()
+ " These commands used to cause memory overflow in searchc().
+ new
+ norm ixx
+ exe "norm 0t\u93cf"
+ bw!
+endfunc
+
+func Cmdline3_prep()
+ " need to disable char_avail,
+ " so that expansion of commandline works
+ call test_override("char_avail", 1)
+ new
+ call setline(1, [' 1', ' 2 the~e', ' 3 the theother'])
+ set incsearch
+endfunc
+
+func Incsearch_cleanup()
+ set noincsearch
+ call test_override("char_avail", 0)
+ bw!
+endfunc
+
+func Test_search_cmdline3()
+ if !exists('+incsearch')
+ return
+ endif
+ call Cmdline3_prep()
+ 1
+ " first match
+ call feedkeys("/the\<c-l>\<cr>", 'tx')
+ call assert_equal(' 2 the~e', getline('.'))
+
+ call Incsearch_cleanup()
+endfunc
+
+func Test_search_cmdline3s()
+ if !exists('+incsearch')
+ return
+ endif
+ call Cmdline3_prep()
+ 1
+ call feedkeys(":%s/the\<c-l>/xxx\<cr>", 'tx')
+ call assert_equal(' 2 xxxe', getline('.'))
+ undo
+ call feedkeys(":%subs/the\<c-l>/xxx\<cr>", 'tx')
+ call assert_equal(' 2 xxxe', getline('.'))
+ undo
+ call feedkeys(":%substitute/the\<c-l>/xxx\<cr>", 'tx')
+ call assert_equal(' 2 xxxe', getline('.'))
+ undo
+ call feedkeys(":%smagic/the.e/xxx\<cr>", 'tx')
+ call assert_equal(' 2 xxx', getline('.'))
+ undo
+ call assert_fails(":%snomagic/the.e/xxx\<cr>", 'E486')
+ "
+ call feedkeys(":%snomagic/the\\.e/xxx\<cr>", 'tx')
+ call assert_equal(' 2 xxx', getline('.'))
+
+ call Incsearch_cleanup()
+endfunc
+
+func Test_search_cmdline3g()
+ if !exists('+incsearch')
+ return
+ endif
+ call Cmdline3_prep()
+ 1
+ call feedkeys(":g/the\<c-l>/d\<cr>", 'tx')
+ call assert_equal(' 3 the theother', getline(2))
+ undo
+ call feedkeys(":global/the\<c-l>/d\<cr>", 'tx')
+ call assert_equal(' 3 the theother', getline(2))
+ undo
+ call feedkeys(":g!/the\<c-l>/d\<cr>", 'tx')
+ call assert_equal(1, line('$'))
+ call assert_equal(' 2 the~e', getline(1))
+ undo
+ call feedkeys(":global!/the\<c-l>/d\<cr>", 'tx')
+ call assert_equal(1, line('$'))
+ call assert_equal(' 2 the~e', getline(1))
+
+ call Incsearch_cleanup()
+endfunc
+
+func Test_search_cmdline3v()
+ if !exists('+incsearch')
+ return
+ endif
+ call Cmdline3_prep()
+ 1
+ call feedkeys(":v/the\<c-l>/d\<cr>", 'tx')
+ call assert_equal(1, line('$'))
+ call assert_equal(' 2 the~e', getline(1))
+ undo
+ call feedkeys(":vglobal/the\<c-l>/d\<cr>", 'tx')
+ call assert_equal(1, line('$'))
+ call assert_equal(' 2 the~e', getline(1))
+
+ call Incsearch_cleanup()
+endfunc
+
+func Test_search_cmdline4()
+ if !exists('+incsearch')
+ return
+ endif
+ " need to disable char_avail,
+ " so that expansion of commandline works
+ call test_override("char_avail", 1)
+ new
+ call setline(1, [' 1 the first', ' 2 the second', ' 3 the third'])
+ set incsearch
+ $
+ call feedkeys("?the\<c-g>\<cr>", 'tx')
+ call assert_equal(' 3 the third', getline('.'))
+ $
+ call feedkeys("?the\<c-g>\<c-g>\<cr>", 'tx')
+ call assert_equal(' 1 the first', getline('.'))
+ $
+ call feedkeys("?the\<c-g>\<c-g>\<c-g>\<cr>", 'tx')
+ call assert_equal(' 2 the second', getline('.'))
+ $
+ call feedkeys("?the\<c-t>\<cr>", 'tx')
+ call assert_equal(' 1 the first', getline('.'))
+ $
+ call feedkeys("?the\<c-t>\<c-t>\<cr>", 'tx')
+ call assert_equal(' 3 the third', getline('.'))
+ $
+ call feedkeys("?the\<c-t>\<c-t>\<c-t>\<cr>", 'tx')
+ call assert_equal(' 2 the second', getline('.'))
+ " clean up
+ set noincsearch
+ call test_override("char_avail", 0)
+ bw!
+endfunc
+
+func Test_search_cmdline5()
+ if !exists('+incsearch')
+ return
+ endif
+ " Do not call test_override("char_avail", 1) so that <C-g> and <C-t> work
+ " regardless char_avail.
+ new
+ call setline(1, [' 1 the first', ' 2 the second', ' 3 the third'])
+ set incsearch
+ 1
+ call feedkeys("/the\<c-g>\<c-g>\<cr>", 'tx')
+ call assert_equal(' 3 the third', getline('.'))
+ $
+ call feedkeys("?the\<c-t>\<c-t>\<c-t>\<cr>", 'tx')
+ call assert_equal(' 2 the second', getline('.'))
+ " clean up
+ set noincsearch
+ bw!
+endfunc
+
+func Test_search_cmdline6()
+ " Test that consecutive matches
+ " are caught by <c-g>/<c-t>
+ if !exists('+incsearch')
+ return
+ endif
+ " need to disable char_avail,
+ " so that expansion of commandline works
+ call test_override("char_avail", 1)
+ new
+ call setline(1, [' bbvimb', ''])
+ set incsearch
+ " first match
+ norm! gg0
+ call feedkeys("/b\<cr>", 'tx')
+ call assert_equal([0,1,2,0], getpos('.'))
+ " second match
+ norm! gg0
+ call feedkeys("/b\<c-g>\<cr>", 'tx')
+ call assert_equal([0,1,3,0], getpos('.'))
+ " third match
+ norm! gg0
+ call feedkeys("/b\<c-g>\<c-g>\<cr>", 'tx')
+ call assert_equal([0,1,7,0], getpos('.'))
+ " first match again
+ norm! gg0
+ call feedkeys("/b\<c-g>\<c-g>\<c-g>\<cr>", 'tx')
+ call assert_equal([0,1,2,0], getpos('.'))
+ set nowrapscan
+ " last match
+ norm! gg0
+ call feedkeys("/b\<c-g>\<c-g>\<c-g>\<cr>", 'tx')
+ call assert_equal([0,1,7,0], getpos('.'))
+ " clean up
+ set wrapscan&vim
+ set noincsearch
+ call test_override("char_avail", 0)
+ bw!
+endfunc
+
+func Test_search_cmdline7()
+ " Test that an pressing <c-g> in an empty command line
+ " does not move the cursor
+ if !exists('+incsearch')
+ return
+ endif
+ " need to disable char_avail,
+ " so that expansion of commandline works
+ call test_override("char_avail", 1)
+ new
+ let @/ = 'b'
+ call setline(1, [' bbvimb', ''])
+ set incsearch
+ " first match
+ norm! gg0
+ " moves to next match of previous search pattern, just like /<cr>
+ call feedkeys("/\<c-g>\<cr>", 'tx')
+ call assert_equal([0,1,2,0], getpos('.'))
+ " moves to next match of previous search pattern, just like /<cr>
+ call feedkeys("/\<cr>", 'tx')
+ call assert_equal([0,1,3,0], getpos('.'))
+ " moves to next match of previous search pattern, just like /<cr>
+ call feedkeys("/\<c-t>\<cr>", 'tx')
+ call assert_equal([0,1,7,0], getpos('.'))
+
+ " using an offset uses the last search pattern
+ call cursor(1, 1)
+ call setline(1, ['1 bbvimb', ' 2 bbvimb'])
+ let @/ = 'b'
+ call feedkeys("//e\<c-g>\<cr>", 'tx')
+ call assert_equal('1 bbvimb', getline('.'))
+ call assert_equal(4, col('.'))
+
+ set noincsearch
+ call test_override("char_avail", 0)
+ bw!
+endfunc
+
+func Test_search_cmdline8()
+ " Highlighting is cleared in all windows
+ " since hls applies to all windows
+ if !exists('+incsearch') || !has('terminal') || has('gui_running') || winwidth(0) < 30
+ return
+ endif
+ if has("win32")
+ throw "Skipped: Bug with sending <ESC> to terminal window not fixed yet"
+ endif
+ let h = winheight(0)
+ if h < 3
+ return
+ endif
+ " Prepare buffer text
+ let lines = ['abb vim vim vi', 'vimvivim']
+ call writefile(lines, 'Xsearch.txt')
+ let buf = term_start([GetVimProg(), '--clean', '-c', 'set noswapfile', 'Xsearch.txt'], {'term_rows': 3})
+
+ call WaitForAssert({-> assert_equal(lines, [term_getline(buf, 1), term_getline(buf, 2)])})
+
+ call term_sendkeys(buf, ":set incsearch hlsearch\<cr>")
+ call term_sendkeys(buf, ":14vsp\<cr>")
+ call term_sendkeys(buf, "/vim\<cr>")
+ call term_sendkeys(buf, "/b\<esc>")
+ call term_sendkeys(buf, "gg0")
+ call term_wait(buf, 500)
+ let screen_line = term_scrape(buf, 1)
+ let [a0,a1,a2,a3] = [screen_line[3].attr, screen_line[4].attr,
+ \ screen_line[18].attr, screen_line[19].attr]
+ call assert_notequal(a0, a1)
+ call assert_notequal(a0, a3)
+ call assert_notequal(a1, a2)
+ call assert_equal(a0, a2)
+ call assert_equal(a1, a3)
+ " clean up
+ call delete('Xsearch.txt')
+
+ bwipe!
+endfunc
+
+" Tests for regexp with various magic settings
+func Test_search_regexp()
+ enew!
+
+ put ='1 a aa abb abbccc'
+ exe 'normal! /a*b\{2}c\+/e' . "\<CR>"
+ call assert_equal([0, 2, 17, 0], getpos('.'))
+
+ put ='2 d dd dee deefff'
+ exe 'normal! /\Md\*e\{2}f\+/e' . "\<CR>"
+ call assert_equal([0, 3, 17, 0], getpos('.'))
+
+ set nomagic
+ put ='3 g gg ghh ghhiii'
+ exe 'normal! /g\*h\{2}i\+/e' . "\<CR>"
+ call assert_equal([0, 4, 17, 0], getpos('.'))
+
+ put ='4 j jj jkk jkklll'
+ exe 'normal! /\mj*k\{2}l\+/e' . "\<CR>"
+ call assert_equal([0, 5, 17, 0], getpos('.'))
+
+ put ='5 m mm mnn mnnooo'
+ exe 'normal! /\vm*n{2}o+/e' . "\<CR>"
+ call assert_equal([0, 6, 17, 0], getpos('.'))
+
+ put ='6 x ^aa$ x'
+ exe 'normal! /\V^aa$' . "\<CR>"
+ call assert_equal([0, 7, 5, 0], getpos('.'))
+
+ set magic
+ put ='7 (a)(b) abbaa'
+ exe 'normal! /\v(a)(b)\2\1\1/e' . "\<CR>"
+ call assert_equal([0, 8, 14, 0], getpos('.'))
+
+ put ='8 axx [ab]xx'
+ exe 'normal! /\V[ab]\(\[xy]\)\1' . "\<CR>"
+ call assert_equal([0, 9, 7, 0], getpos('.'))
+
+ set undolevels=100
+ put ='9 foobar'
+ put =''
+ exe "normal! a\<C-G>u\<Esc>"
+ normal G
+ exe 'normal! dv?bar?' . "\<CR>"
+ call assert_equal('9 foo', getline('.'))
+ call assert_equal([0, 10, 5, 0], getpos('.'))
+ call assert_equal(10, line('$'))
+ normal u
+ call assert_equal('9 foobar', getline('.'))
+ call assert_equal([0, 10, 6, 0], getpos('.'))
+ call assert_equal(11, line('$'))
+
+ set undolevels&
+ enew!
+endfunc
+
+func Test_search_cmdline_incsearch_highlight()
+ if !exists('+incsearch')
+ return
+ endif
+ set incsearch hlsearch
+ " need to disable char_avail,
+ " so that expansion of commandline works
+ call test_override("char_avail", 1)
+ new
+ call setline(1, ['aaa 1 the first', ' 2 the second', ' 3 the third'])
+
+ 1
+ call feedkeys("/second\<cr>", 'tx')
+ call assert_equal('second', @/)
+ call assert_equal(' 2 the second', getline('.'))
+
+ " Canceling search won't change @/
+ 1
+ let @/ = 'last pattern'
+ call feedkeys("/third\<C-c>", 'tx')
+ call assert_equal('last pattern', @/)
+ call feedkeys("/third\<Esc>", 'tx')
+ call assert_equal('last pattern', @/)
+ call feedkeys("/3\<bs>\<bs>", 'tx')
+ call assert_equal('last pattern', @/)
+ call feedkeys("/third\<c-g>\<c-t>\<Esc>", 'tx')
+ call assert_equal('last pattern', @/)
+
+ " clean up
+ set noincsearch nohlsearch
+ bw!
+endfunc
+
+func Test_search_cmdline_incsearch_highlight_attr()
+ if !exists('+incsearch') || !has('terminal') || has('gui_running')
+ return
+ endif
+ let h = winheight(0)
+ if h < 3
+ return
+ endif
+
+ " Prepare buffer text
+ let lines = ['abb vim vim vi', 'vimvivim']
+ call writefile(lines, 'Xsearch.txt')
+ let buf = term_start([GetVimProg(), '--clean', '-c', 'set noswapfile', 'Xsearch.txt'], {'term_rows': 3})
+
+ call WaitForAssert({-> assert_equal(lines, [term_getline(buf, 1), term_getline(buf, 2)])})
+ " wait for vim to complete initialization
+ call term_wait(buf)
+
+ " Get attr of normal(a0), incsearch(a1), hlsearch(a2) highlight
+ call term_sendkeys(buf, ":set incsearch hlsearch\<cr>")
+ call term_sendkeys(buf, '/b')
+ call term_wait(buf, 200)
+ let screen_line1 = term_scrape(buf, 1)
+ call assert_true(len(screen_line1) > 2)
+ " a0: attr_normal
+ let a0 = screen_line1[0].attr
+ " a1: attr_incsearch
+ let a1 = screen_line1[1].attr
+ " a2: attr_hlsearch
+ let a2 = screen_line1[2].attr
+ call assert_notequal(a0, a1)
+ call assert_notequal(a0, a2)
+ call assert_notequal(a1, a2)
+ call term_sendkeys(buf, "\<cr>gg0")
+
+ " Test incremental highlight search
+ call term_sendkeys(buf, "/vim")
+ call term_wait(buf, 200)
+ " Buffer:
+ " abb vim vim vi
+ " vimvivim
+ " Search: /vim
+ let attr_line1 = [a0,a0,a0,a0,a1,a1,a1,a0,a2,a2,a2,a0,a0,a0]
+ let attr_line2 = [a2,a2,a2,a0,a0,a2,a2,a2]
+ call assert_equal(attr_line1, map(term_scrape(buf, 1)[:len(attr_line1)-1], 'v:val.attr'))
+ call assert_equal(attr_line2, map(term_scrape(buf, 2)[:len(attr_line2)-1], 'v:val.attr'))
+
+ " Test <C-g>
+ call term_sendkeys(buf, "\<C-g>\<C-g>")
+ call term_wait(buf, 200)
+ let attr_line1 = [a0,a0,a0,a0,a2,a2,a2,a0,a2,a2,a2,a0,a0,a0]
+ let attr_line2 = [a1,a1,a1,a0,a0,a2,a2,a2]
+ call assert_equal(attr_line1, map(term_scrape(buf, 1)[:len(attr_line1)-1], 'v:val.attr'))
+ call assert_equal(attr_line2, map(term_scrape(buf, 2)[:len(attr_line2)-1], 'v:val.attr'))
+
+ " Test <C-t>
+ call term_sendkeys(buf, "\<C-t>")
+ call term_wait(buf, 200)
+ let attr_line1 = [a0,a0,a0,a0,a2,a2,a2,a0,a1,a1,a1,a0,a0,a0]
+ let attr_line2 = [a2,a2,a2,a0,a0,a2,a2,a2]
+ call assert_equal(attr_line1, map(term_scrape(buf, 1)[:len(attr_line1)-1], 'v:val.attr'))
+ call assert_equal(attr_line2, map(term_scrape(buf, 2)[:len(attr_line2)-1], 'v:val.attr'))
+
+ " Type Enter and a1(incsearch highlight) should become a2(hlsearch highlight)
+ call term_sendkeys(buf, "\<cr>")
+ call term_wait(buf, 200)
+ let attr_line1 = [a0,a0,a0,a0,a2,a2,a2,a0,a2,a2,a2,a0,a0,a0]
+ let attr_line2 = [a2,a2,a2,a0,a0,a2,a2,a2]
+ call assert_equal(attr_line1, map(term_scrape(buf, 1)[:len(attr_line1)-1], 'v:val.attr'))
+ call assert_equal(attr_line2, map(term_scrape(buf, 2)[:len(attr_line2)-1], 'v:val.attr'))
+
+ " Test nohlsearch. a2(hlsearch highlight) should become a0(normal highlight)
+ call term_sendkeys(buf, ":1\<cr>")
+ call term_sendkeys(buf, ":set nohlsearch\<cr>")
+ call term_sendkeys(buf, "/vim")
+ call term_wait(buf, 200)
+ let attr_line1 = [a0,a0,a0,a0,a1,a1,a1,a0,a0,a0,a0,a0,a0,a0]
+ let attr_line2 = [a0,a0,a0,a0,a0,a0,a0,a0]
+ call assert_equal(attr_line1, map(term_scrape(buf, 1)[:len(attr_line1)-1], 'v:val.attr'))
+ call assert_equal(attr_line2, map(term_scrape(buf, 2)[:len(attr_line2)-1], 'v:val.attr'))
+ call delete('Xsearch.txt')
+
+ call delete('Xsearch.txt')
+ bwipe!
+endfunc
+
+func Test_incsearch_cmdline_modifier()
+ if !exists('+incsearch')
+ return
+ endif
+ call test_override("char_avail", 1)
+ new
+ call setline(1, ['foo'])
+ set incsearch
+ " Test that error E14 does not occur in parsing command modifier.
+ call feedkeys("V:tab", 'tx')
+
+ call Incsearch_cleanup()
+endfunc
+
+func Test_incsearch_scrolling()
+ if !CanRunVimInTerminal()
+ return
+ endif
+ call assert_equal(0, &scrolloff)
+ call writefile([
+ \ 'let dots = repeat(".", 120)',
+ \ 'set incsearch cmdheight=2 scrolloff=0',
+ \ 'call setline(1, [dots, dots, dots, "", "target", dots, dots])',
+ \ 'normal gg',
+ \ 'redraw',
+ \ ], 'Xscript')
+ let buf = RunVimInTerminal('-S Xscript', {'rows': 9, 'cols': 70})
+ " Need to send one key at a time to force a redraw
+ call term_sendkeys(buf, '/')
+ sleep 100m
+ call term_sendkeys(buf, 't')
+ sleep 100m
+ call term_sendkeys(buf, 'a')
+ sleep 100m
+ call term_sendkeys(buf, 'r')
+ sleep 100m
+ call term_sendkeys(buf, 'g')
+ call VerifyScreenDump(buf, 'Test_incsearch_scrolling_01', {})
+
+ call term_sendkeys(buf, "\<Esc>")
+ call StopVimInTerminal(buf)
+ call delete('Xscript')
+endfunc
+
+func Test_incsearch_search_dump()
+ if !exists('+incsearch')
+ return
+ endif
+ if !CanRunVimInTerminal()
+ return
+ endif
+ call writefile([
+ \ 'set incsearch hlsearch scrolloff=0',
+ \ 'for n in range(1, 8)',
+ \ ' call setline(n, "foo " . n)',
+ \ 'endfor',
+ \ '3',
+ \ ], 'Xis_search_script')
+ let buf = RunVimInTerminal('-S Xis_search_script', {'rows': 9, 'cols': 70})
+ " Give Vim a chance to redraw to get rid of the spaces in line 2 caused by
+ " the 'ambiwidth' check.
+ sleep 100m
+
+ " Need to send one key at a time to force a redraw.
+ call term_sendkeys(buf, '/fo')
+ call VerifyScreenDump(buf, 'Test_incsearch_search_01', {})
+ call term_sendkeys(buf, "\<Esc>")
+ sleep 100m
+
+ call term_sendkeys(buf, '/\v')
+ call VerifyScreenDump(buf, 'Test_incsearch_search_02', {})
+ call term_sendkeys(buf, "\<Esc>")
+
+ call StopVimInTerminal(buf)
+ call delete('Xis_search_script')
+endfunc
+
+func Test_incsearch_substitute()
+ if !exists('+incsearch')
+ return
+ endif
+ call test_override("char_avail", 1)
+ new
+ set incsearch
+ for n in range(1, 10)
+ call setline(n, 'foo ' . n)
+ endfor
+ 4
+ call feedkeys(":.,.+2s/foo\<BS>o\<BS>o/xxx\<cr>", 'tx')
+ call assert_equal('foo 3', getline(3))
+ call assert_equal('xxx 4', getline(4))
+ call assert_equal('xxx 5', getline(5))
+ call assert_equal('xxx 6', getline(6))
+ call assert_equal('foo 7', getline(7))
+
+ call Incsearch_cleanup()
+endfunc
+
+" Similar to Test_incsearch_substitute() but with a screendump halfway.
+func Test_incsearch_substitute_dump()
+ if !exists('+incsearch')
+ return
+ endif
+ if !CanRunVimInTerminal()
+ return
+ endif
+ call writefile([
+ \ 'set incsearch hlsearch scrolloff=0',
+ \ 'for n in range(1, 10)',
+ \ ' call setline(n, "foo " . n)',
+ \ 'endfor',
+ \ 'call setline(11, "bar 11")',
+ \ '3',
+ \ ], 'Xis_subst_script')
+ let buf = RunVimInTerminal('-S Xis_subst_script', {'rows': 9, 'cols': 70})
+ " Give Vim a chance to redraw to get rid of the spaces in line 2 caused by
+ " the 'ambiwidth' check.
+ sleep 100m
+
+ " Need to send one key at a time to force a redraw.
+ " Select three lines at the cursor with typed pattern.
+ call term_sendkeys(buf, ':.,.+2s/')
+ sleep 100m
+ call term_sendkeys(buf, 'f')
+ sleep 100m
+ call term_sendkeys(buf, 'o')
+ sleep 100m
+ call term_sendkeys(buf, 'o')
+ call VerifyScreenDump(buf, 'Test_incsearch_substitute_01', {})
+ call term_sendkeys(buf, "\<Esc>")
+
+ " Select three lines at the cursor using previous pattern.
+ call term_sendkeys(buf, "/foo\<CR>")
+ sleep 100m
+ call term_sendkeys(buf, ':.,.+2s//')
+ call VerifyScreenDump(buf, 'Test_incsearch_substitute_02', {})
+
+ " Deleting last slash should remove the match.
+ call term_sendkeys(buf, "\<BS>")
+ call VerifyScreenDump(buf, 'Test_incsearch_substitute_03', {})
+ call term_sendkeys(buf, "\<Esc>")
+
+ " Reverse range is accepted
+ call term_sendkeys(buf, ':5,2s/foo')
+ call VerifyScreenDump(buf, 'Test_incsearch_substitute_04', {})
+ call term_sendkeys(buf, "\<Esc>")
+
+ " White space after the command is skipped
+ call term_sendkeys(buf, ':2,3sub /fo')
+ call VerifyScreenDump(buf, 'Test_incsearch_substitute_05', {})
+ call term_sendkeys(buf, "\<Esc>")
+
+ " Command modifiers are skipped
+ call term_sendkeys(buf, ':above below browse botr confirm keepmar keepalt keeppat keepjum filter xxx hide lockm leftabove noau noswap rightbel sandbox silent silent! $tab top unsil vert verbose 4,5s/fo.')
+ call VerifyScreenDump(buf, 'Test_incsearch_substitute_06', {})
+ call term_sendkeys(buf, "\<Esc>")
+
+ " Cursorline highlighting at match
+ call term_sendkeys(buf, ":set cursorline\<CR>")
+ call term_sendkeys(buf, 'G9G')
+ call term_sendkeys(buf, ':9,11s/bar')
+ call VerifyScreenDump(buf, 'Test_incsearch_substitute_07', {})
+ call term_sendkeys(buf, "\<Esc>")
+
+ " Cursorline highlighting at cursor when no match
+ call term_sendkeys(buf, ':9,10s/bar')
+ call VerifyScreenDump(buf, 'Test_incsearch_substitute_08', {})
+ call term_sendkeys(buf, "\<Esc>")
+
+ " Only \v handled as empty pattern, does not move cursor
+ call term_sendkeys(buf, '3G4G')
+ call term_sendkeys(buf, ":nohlsearch\<CR>")
+ call term_sendkeys(buf, ':6,7s/\v')
+ call VerifyScreenDump(buf, 'Test_incsearch_substitute_09', {})
+ call term_sendkeys(buf, "\<Esc>")
+
+ call term_sendkeys(buf, ":set nocursorline\<CR>")
+
+ " All matches are highlighted for 'hlsearch' after the incsearch canceled
+ call term_sendkeys(buf, "1G*")
+ call term_sendkeys(buf, ":2,5s/foo")
+ sleep 100m
+ call term_sendkeys(buf, "\<Esc>")
+ call VerifyScreenDump(buf, 'Test_incsearch_substitute_10', {})
+
+ call term_sendkeys(buf, ":split\<CR>")
+ call term_sendkeys(buf, ":let @/ = 'xyz'\<CR>")
+ call term_sendkeys(buf, ":%s/.")
+ call VerifyScreenDump(buf, 'Test_incsearch_substitute_11', {})
+ call term_sendkeys(buf, "\<BS>")
+ call VerifyScreenDump(buf, 'Test_incsearch_substitute_12', {})
+ call term_sendkeys(buf, "\<Esc>")
+ call VerifyScreenDump(buf, 'Test_incsearch_substitute_13', {})
+
+ call StopVimInTerminal(buf)
+ call delete('Xis_subst_script')
+endfunc
+
+" Similar to Test_incsearch_substitute_dump() for :sort
+func Test_incsearch_sort_dump()
+ if !exists('+incsearch')
+ return
+ endif
+ if !CanRunVimInTerminal()
+ return
+ endif
+ call writefile([
+ \ 'set incsearch hlsearch scrolloff=0',
+ \ 'call setline(1, ["another one 2", "that one 3", "the one 1"])',
+ \ ], 'Xis_sort_script')
+ let buf = RunVimInTerminal('-S Xis_sort_script', {'rows': 9, 'cols': 70})
+ " Give Vim a chance to redraw to get rid of the spaces in line 2 caused by
+ " the 'ambiwidth' check.
+ sleep 100m
+
+ " Need to send one key at a time to force a redraw.
+ call term_sendkeys(buf, ':sort ni u /on')
+ call VerifyScreenDump(buf, 'Test_incsearch_sort_01', {})
+ call term_sendkeys(buf, "\<Esc>")
+
+ call StopVimInTerminal(buf)
+ call delete('Xis_sort_script')
+endfunc
+
+" Similar to Test_incsearch_substitute_dump() for :vimgrep famiry
+func Test_incsearch_vimgrep_dump()
+ if !exists('+incsearch')
+ return
+ endif
+ if !CanRunVimInTerminal()
+ return
+ endif
+ call writefile([
+ \ 'set incsearch hlsearch scrolloff=0',
+ \ 'call setline(1, ["another one 2", "that one 3", "the one 1"])',
+ \ ], 'Xis_vimgrep_script')
+ let buf = RunVimInTerminal('-S Xis_vimgrep_script', {'rows': 9, 'cols': 70})
+ " Give Vim a chance to redraw to get rid of the spaces in line 2 caused by
+ " the 'ambiwidth' check.
+ sleep 100m
+
+ " Need to send one key at a time to force a redraw.
+ call term_sendkeys(buf, ':vimgrep on')
+ call VerifyScreenDump(buf, 'Test_incsearch_vimgrep_01', {})
+ call term_sendkeys(buf, "\<Esc>")
+
+ call term_sendkeys(buf, ':vimg /on/ *.txt')
+ call VerifyScreenDump(buf, 'Test_incsearch_vimgrep_02', {})
+ call term_sendkeys(buf, "\<Esc>")
+
+ call term_sendkeys(buf, ':vimgrepadd "\<on')
+ call VerifyScreenDump(buf, 'Test_incsearch_vimgrep_03', {})
+ call term_sendkeys(buf, "\<Esc>")
+
+ call term_sendkeys(buf, ':lv "tha')
+ call VerifyScreenDump(buf, 'Test_incsearch_vimgrep_04', {})
+ call term_sendkeys(buf, "\<Esc>")
+
+ call term_sendkeys(buf, ':lvimgrepa "the" **/*.txt')
+ call VerifyScreenDump(buf, 'Test_incsearch_vimgrep_05', {})
+ call term_sendkeys(buf, "\<Esc>")
+
+ call StopVimInTerminal(buf)
+ call delete('Xis_vimgrep_script')
+endfunc
+
+func Test_keep_last_search_pattern()
+ if !exists('+incsearch')
+ return
+ endif
+ new
+ call setline(1, ['foo', 'foo', 'foo'])
+ set incsearch
+ call test_override("char_avail", 1)
+ let @/ = 'bar'
+ call feedkeys(":/foo/s//\<Esc>", 'ntx')
+ call assert_equal('bar', @/)
+
+ " no error message if pattern not found
+ call feedkeys(":/xyz/s//\<Esc>", 'ntx')
+ call assert_equal('bar', @/)
+
+ bwipe!
+ call test_override("ALL", 0)
+ set noincsearch
+endfunc
+
+func Test_word_under_cursor_after_match()
+ if !exists('+incsearch')
+ return
+ endif
+ new
+ call setline(1, 'foo bar')
+ set incsearch
+ call test_override("char_avail", 1)
+ try
+ call feedkeys("/foo\<C-R>\<C-W>\<CR>", 'ntx')
+ catch /E486:/
+ endtry
+ call assert_equal('foobar', @/)
+
+ bwipe!
+ call test_override("ALL", 0)
+ set noincsearch
+endfunc
+
+func Test_subst_word_under_cursor()
+ if !exists('+incsearch')
+ return
+ endif
+ new
+ call setline(1, ['int SomeLongName;', 'for (xxx = 1; xxx < len; ++xxx)'])
+ set incsearch
+ call test_override("char_avail", 1)
+ call feedkeys("/LongName\<CR>", 'ntx')
+ call feedkeys(":%s/xxx/\<C-R>\<C-W>/g\<CR>", 'ntx')
+ call assert_equal('for (SomeLongName = 1; SomeLongName < len; ++SomeLongName)', getline(2))
+
+ bwipe!
+ call test_override("ALL", 0)
+ set noincsearch
+endfunc
+
+func Test_search_undefined_behaviour()
+ if !has("terminal")
+ return
+ endif
+ let h = winheight(0)
+ if h < 3
+ return
+ endif
+ " did cause an undefined left shift
+ let g:buf = term_start([GetVimProg(), '--clean', '-e', '-s', '-c', 'call search(getline("."))', 'samples/test000'], {'term_rows': 3})
+ call assert_equal([''], getline(1, '$'))
+ call term_sendkeys(g:buf, ":qa!\<cr>")
+ bwipe!
+endfunc
+
+func Test_search_undefined_behaviour2()
+ call search("\%UC0000000")
+endfunc
+
+" Test for search('multi-byte char', 'bce')
+func Test_search_multibyte()
+ let save_enc = &encoding
+ set encoding=utf8
+ enew!
+ call append('$', 'A')
+ call cursor(2, 1)
+ call assert_equal(2, search('A', 'bce', line('.')))
+ enew!
+ let &encoding = save_enc
+endfunc
+
+" This was causing E874. Also causes an invalid read?
+func Test_look_behind()
+ new
+ call setline(1, '0\|\&\n\@<=')
+ call search(getline("."))
+ bwipe!
+endfunc
+
+func Test_search_sentence()
+ new
+ " this used to cause a crash
+ call assert_fails("/\\%')", 'E486')
+ call assert_fails("/", 'E486')
+ /\%'(
+ /
+endfunc
+
+" Test that there is no crash when there is a last search pattern but no last
+" substitute pattern.
+func Test_no_last_substitute_pat()
+ " Use viminfo to set the last search pattern to a string and make the last
+ " substitute pattern the most recent used and make it empty (NULL).
+ call writefile(['~MSle0/bar', '~MSle0~&'], 'Xviminfo')
+ rviminfo! Xviminfo
+ call assert_fails('normal n', 'E35:')
+
+ call delete('Xviminfo')
+endfunc
+
+func Test_search_Ctrl_L_combining()
+ " Make sure, that Ctrl-L works correctly with combining characters.
+ " It uses an artificial example of an 'a' with 4 combining chars:
+ " 'a' U+0061 Dec:97 LATIN SMALL LETTER A &#x61; /\%u61\Z "\u0061"
+ " ' ̀' U+0300 Dec:768 COMBINING GRAVE ACCENT &#x300; /\%u300\Z "\u0300"
+ " ' Ì' U+0301 Dec:769 COMBINING ACUTE ACCENT &#x301; /\%u301\Z "\u0301"
+ " ' ̇' U+0307 Dec:775 COMBINING DOT ABOVE &#x307; /\%u307\Z "\u0307"
+ " ' ̣' U+0323 Dec:803 COMBINING DOT BELOW &#x323; /\%u323 "\u0323"
+ " Those should also appear on the commandline
+ if !exists('+incsearch')
+ return
+ endif
+ call Cmdline3_prep()
+ 1
+ let bufcontent = ['', 'MiaÌ€Ị̀̇m']
+ call append('$', bufcontent)
+ call feedkeys("/Mi\<c-l>\<c-l>\<cr>", 'tx')
+ call assert_equal(5, line('.'))
+ call assert_equal(bufcontent[1], @/)
+ call Incsearch_cleanup()
+endfunc
diff --git a/src/testdir/test_searchpos.vim b/src/testdir/test_searchpos.vim
new file mode 100644
index 0000000..8dffddc
--- /dev/null
+++ b/src/testdir/test_searchpos.vim
@@ -0,0 +1,28 @@
+" Tests for searchpos()
+
+func Test_searchpos()
+ new one
+ 0put ='1a3'
+ 1put ='123xyz'
+ call cursor(1, 1)
+ call assert_equal([1, 1, 2], searchpos('\%(\([a-z]\)\|\_.\)\{-}xyz', 'pcW'))
+ call cursor(1, 2)
+ call assert_equal([2, 1, 1], searchpos('\%(\([a-z]\)\|\_.\)\{-}xyz', 'pcW'))
+ set cpo-=c
+ call cursor(1, 2)
+ call assert_equal([1, 2, 2], searchpos('\%(\([a-z]\)\|\_.\)\{-}xyz', 'pcW'))
+ call cursor(1, 3)
+ call assert_equal([1, 3, 1], searchpos('\%(\([a-z]\)\|\_.\)\{-}xyz', 'pcW'))
+
+ " Now with \zs, first match is in column 0, "a" is matched.
+ call cursor(1, 3)
+ call assert_equal([2, 4, 2], searchpos('\%(\([a-z]\)\|\_.\)\{-}\zsxyz', 'pcW'))
+ " With z flag start at cursor column, don't see the "a".
+ call cursor(1, 3)
+ call assert_equal([2, 4, 1], searchpos('\%(\([a-z]\)\|\_.\)\{-}\zsxyz', 'pcWz'))
+
+ set cpo+=c
+ " close the window
+ q!
+
+endfunc
diff --git a/src/testdir/test_set.vim b/src/testdir/test_set.vim
new file mode 100644
index 0000000..b980463
--- /dev/null
+++ b/src/testdir/test_set.vim
@@ -0,0 +1,27 @@
+" Tests for the :set command
+
+function Test_set_backslash()
+ let isk_save = &isk
+
+ set isk=a,b,c
+ set isk+=d
+ call assert_equal('a,b,c,d', &isk)
+ set isk+=\\,e
+ call assert_equal('a,b,c,d,\,e', &isk)
+ set isk-=e
+ call assert_equal('a,b,c,d,\', &isk)
+ set isk-=\\
+ call assert_equal('a,b,c,d', &isk)
+
+ let &isk = isk_save
+endfunction
+
+function Test_set_add()
+ let wig_save = &wig
+
+ set wildignore=*.png,
+ set wildignore+=*.jpg
+ call assert_equal('*.png,*.jpg', &wig)
+
+ let &wig = wig_save
+endfunction
diff --git a/src/testdir/test_sha256.vim b/src/testdir/test_sha256.vim
new file mode 100644
index 0000000..dd47079
--- /dev/null
+++ b/src/testdir/test_sha256.vim
@@ -0,0 +1,22 @@
+" Tests for the sha256() function.
+
+if !has('cryptv') || !exists('*sha256')
+ finish
+endif
+
+function Test_sha256()
+ " test for empty string:
+ call assert_equal(sha256(""), 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855')
+
+ "'test for 1 char:
+ call assert_equal(sha256("a"), 'ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb')
+ "
+ "test for 3 chars:
+ call assert_equal(sha256("abc"), 'ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad')
+
+ " test for contains meta char:
+ call assert_equal(sha256("foo\nbar"), '807eff6267f3f926a21d234f7b0cf867a86f47e07a532f15e8cc39ed110ca776')
+
+ " test for contains non-ascii char:
+ call assert_equal(sha256("\xde\xad\xbe\xef"), '5f78c33274e43fa9de5659265c1d917e25c03722dcb0b8d27db8d5feaa813953')
+endfunction
diff --git a/src/testdir/test_short_sleep.py b/src/testdir/test_short_sleep.py
new file mode 100644
index 0000000..a290443
--- /dev/null
+++ b/src/testdir/test_short_sleep.py
@@ -0,0 +1,11 @@
+#!/usr/bin/python
+#
+# Program that sleeps for 100 msec
+#
+# This requires Python 2.6 or later.
+
+import time
+
+if __name__ == "__main__":
+
+ time.sleep(0.1) # sleep 100 msec
diff --git a/src/testdir/test_shortpathname.vim b/src/testdir/test_shortpathname.vim
new file mode 100644
index 0000000..f151788
--- /dev/null
+++ b/src/testdir/test_shortpathname.vim
@@ -0,0 +1,70 @@
+" Test for shortpathname ':8' extension.
+" Only for use on Win32 systems!
+
+if !has('win32')
+ finish
+endif
+
+func TestIt(file, bits, expected)
+ let res = fnamemodify(a:file, a:bits)
+ if a:expected != ''
+ call assert_equal(substitute(a:expected, '/', '\\', 'g'),
+ \ substitute(res, '/', '\\', 'g'),
+ \ "'" . a:file . "'->(" . a:bits . ")->'" . res . "'")
+ endif
+endfunc
+
+func Test_ColonEight()
+ let save_dir = getcwd()
+
+ " This could change for CygWin to //cygdrive/c
+ let dir1 = 'c:/x.x.y'
+ if filereadable(dir1) || isdirectory(dir1)
+ call assert_report("Fatal: '" . dir1 . "' exists, cannot run test")
+ return
+ endif
+
+ let file1 = dir1 . '/zz.y.txt'
+ let nofile1 = dir1 . '/z.y.txt'
+ let dir2 = dir1 . '/VimIsTheGreatestSinceSlicedBread'
+ let file2 = dir2 . '/z.txt'
+ let nofile2 = dir2 . '/zz.txt'
+
+ call mkdir(dir1)
+ let resdir1 = substitute(fnamemodify(dir1, ':p:8'), '/$', '', '')
+ call assert_match('\V\^c:/XX\x\x\x\x~1.Y\$', resdir1)
+
+ let resfile1 = resdir1 . '/ZZY~1.TXT'
+ let resnofile1 = resdir1 . '/z.y.txt'
+ let resdir2 = resdir1 . '/VIMIST~1'
+ let resfile2 = resdir2 . '/z.txt'
+ let resnofile2 = resdir2 . '/zz.txt'
+
+ call mkdir(dir2)
+ call writefile([], file1)
+ call writefile([], file2)
+
+ call TestIt(file1, ':p:8', resfile1)
+ call TestIt(nofile1, ':p:8', resnofile1)
+ call TestIt(file2, ':p:8', resfile2)
+ call TestIt(nofile2, ':p:8', resnofile2)
+ call TestIt(nofile2, ':p:8:h', fnamemodify(resnofile2, ':h'))
+ exe 'cd ' . dir1
+ call TestIt(file1, ':.:8', strpart(resfile1, strlen(resdir1)+1))
+ call TestIt(nofile1, ':.:8', strpart(resnofile1, strlen(resdir1)+1))
+ call TestIt(file2, ':.:8', strpart(resfile2, strlen(resdir1)+1))
+ call TestIt(nofile2, ':.:8', strpart(resnofile2, strlen(resdir1)+1))
+ let $HOME=dir1
+ call TestIt(file1, ':~:8', '~' . strpart(resfile1, strlen(resdir1)))
+ call TestIt(nofile1, ':~:8', '~' . strpart(resnofile1, strlen(resdir1)))
+ call TestIt(file2, ':~:8', '~' . strpart(resfile2, strlen(resdir1)))
+ call TestIt(nofile2, ':~:8', '~' . strpart(resnofile2, strlen(resdir1)))
+
+ cd c:/
+ call delete(file2)
+ call delete(file1)
+ call delete(dir2, 'd')
+ call delete(dir1, 'd')
+
+ exe "cd " . save_dir
+endfunc
diff --git a/src/testdir/test_signs.vim b/src/testdir/test_signs.vim
new file mode 100644
index 0000000..49bd986
--- /dev/null
+++ b/src/testdir/test_signs.vim
@@ -0,0 +1,1340 @@
+" Test for signs
+
+if !has('signs')
+ finish
+endif
+
+func Test_sign()
+ new
+ call setline(1, ['a', 'b', 'c', 'd'])
+
+ " Define some signs.
+ " We can specify icons even if not all versions of vim support icons as
+ " icon is ignored when not supported. "(not supported)" is shown after
+ " the icon name when listing signs.
+ sign define Sign1 text=x
+ try
+ sign define Sign2 text=xy texthl=Title linehl=Error
+ \ icon=../../pixmaps/stock_vim_find_help.png
+ catch /E255:/
+ " Ignore error: E255: Couldn't read in sign data!
+ " This error can happen when running in the GUI.
+ " Some gui like Motif do not support the png icon format.
+ endtry
+
+ " Test listing signs.
+ let a=execute('sign list')
+ call assert_match('^\nsign Sign1 text=x \nsign Sign2 ' .
+ \ 'icon=../../pixmaps/stock_vim_find_help.png .*text=xy ' .
+ \ 'linehl=Error texthl=Title$', a)
+
+ let a=execute('sign list Sign1')
+ call assert_equal("\nsign Sign1 text=x ", a)
+
+ " Split the window to the bottom to verify sign jump will stay in the
+ " current window if the buffer is displayed there.
+ let bn = bufnr('%')
+ let wn = winnr()
+ exe 'sign place 41 line=3 name=Sign1 buffer=' . bn
+ 1
+ bot split
+ exe 'sign jump 41 buffer=' . bufnr('%')
+ call assert_equal('c', getline('.'))
+ call assert_equal(3, winnr())
+ call assert_equal(bn, bufnr('%'))
+ call assert_notequal(wn, winnr())
+
+ " Create a new buffer and check that ":sign jump" switches to the old buffer.
+ 1
+ new foo
+ call assert_notequal(bn, bufnr('%'))
+ exe 'sign jump 41 buffer=' . bn
+ call assert_equal(bn, bufnr('%'))
+ call assert_equal('c', getline('.'))
+
+ " Redraw to make sure that screen redraw with sign gets exercised,
+ " with and without 'rightleft'.
+ if has('rightleft')
+ set rightleft
+ redraw
+ set norightleft
+ endif
+ redraw
+
+ " Check that we can't change sign.
+ call assert_fails("sign place 40 name=Sign1 buffer=" . bufnr('%'), 'E885:')
+
+ " Check placed signs
+ let a=execute('sign place')
+ call assert_equal("\n--- Signs ---\nSigns for [NULL]:\n" .
+ \ " line=3 id=41 name=Sign1 priority=10\n", a)
+
+ " Unplace the sign and try jumping to it again should fail.
+ sign unplace 41
+ 1
+ call assert_fails("sign jump 41 buffer=" . bufnr('%'), 'E157:')
+ call assert_equal('a', getline('.'))
+
+ " Unplace sign on current line.
+ exe 'sign place 42 line=4 name=Sign2 buffer=' . bufnr('%')
+ 4
+ sign unplace
+ let a=execute('sign place')
+ call assert_equal("\n--- Signs ---\n", a)
+
+ " Try again to unplace sign on current line, it should fail this time.
+ call assert_fails('sign unplace', 'E159:')
+
+ " Unplace all signs.
+ exe 'sign place 41 line=3 name=Sign1 buffer=' . bufnr('%')
+ sign unplace *
+ let a=execute('sign place')
+ call assert_equal("\n--- Signs ---\n", a)
+
+ " Place a sign without specifying the filename or buffer
+ sign place 77 line=9 name=Sign2
+ let a=execute('sign place')
+ call assert_equal("\n--- Signs ---\nSigns for [NULL]:\n" .
+ \ " line=9 id=77 name=Sign2 priority=10\n", a)
+ sign unplace *
+
+ " Check :jump with file=...
+ edit foo
+ call setline(1, ['A', 'B', 'C', 'D'])
+
+ try
+ sign define Sign3 text=y texthl=DoesNotExist linehl=DoesNotExist
+ \ icon=doesnotexist.xpm
+ catch /E255:/
+ " ignore error: E255: it can happens for guis.
+ endtry
+
+ let fn = expand('%:p')
+ exe 'sign place 43 line=2 name=Sign3 file=' . fn
+ edit bar
+ call assert_notequal(fn, expand('%:p'))
+ exe 'sign jump 43 file=' . fn
+ call assert_equal('B', getline('.'))
+
+ " Check for jumping to a sign in a hidden buffer
+ enew! | only!
+ edit foo
+ call setline(1, ['A', 'B', 'C', 'D'])
+ let fn = expand('%:p')
+ exe 'sign place 21 line=3 name=Sign3 file=' . fn
+ hide edit bar
+ exe 'sign jump 21 file=' . fn
+ call assert_equal('C', getline('.'))
+
+ " can't define a sign with a non-printable character as text
+ call assert_fails("sign define Sign4 text=\e linehl=Comment", 'E239:')
+ call assert_fails("sign define Sign4 text=a\e linehl=Comment", 'E239:')
+ call assert_fails("sign define Sign4 text=\ea linehl=Comment", 'E239:')
+
+ " Only 1 or 2 character text is allowed
+ call assert_fails("sign define Sign4 text=abc linehl=Comment", 'E239:')
+ call assert_fails("sign define Sign4 text= linehl=Comment", 'E239:')
+ call assert_fails("sign define Sign4 text=\\ ab linehl=Comment", 'E239:')
+
+ " define sign with whitespace
+ sign define Sign4 text=\ X linehl=Comment
+ sign undefine Sign4
+ sign define Sign4 linehl=Comment text=\ X
+ sign undefine Sign4
+
+ sign define Sign5 text=X\ linehl=Comment
+ sign undefine Sign5
+ sign define Sign5 linehl=Comment text=X\
+ sign undefine Sign5
+
+ " define sign with backslash
+ sign define Sign4 text=\\\\ linehl=Comment
+ sign undefine Sign4
+ sign define Sign4 text=\\ linehl=Comment
+ sign undefine Sign4
+
+ " define a sign with a leading 0 in the name
+ sign unplace *
+ sign define 004 text=#> linehl=Comment
+ let a = execute('sign list 4')
+ call assert_equal("\nsign 4 text=#> linehl=Comment", a)
+ exe 'sign place 20 line=3 name=004 buffer=' . bufnr('')
+ let a = execute('sign place')
+ call assert_equal("\n--- Signs ---\nSigns for foo:\n" .
+ \ " line=3 id=20 name=4 priority=10\n", a)
+ exe 'sign unplace 20 buffer=' . bufnr('')
+ sign undefine 004
+ call assert_fails('sign list 4', 'E155:')
+
+ " After undefining the sign, we should no longer be able to place it.
+ sign undefine Sign1
+ sign undefine Sign2
+ sign undefine Sign3
+ call assert_fails("sign place 41 line=3 name=Sign1 buffer=" .
+ \ bufnr('%'), 'E155:')
+endfunc
+
+" Undefining placed sign is not recommended.
+" Quoting :help sign
+"
+" :sign undefine {name}
+" Deletes a previously defined sign. If signs with this {name}
+" are still placed this will cause trouble.
+func Test_sign_undefine_still_placed()
+ new foobar
+ sign define Sign text=x
+ exe 'sign place 41 line=1 name=Sign buffer=' . bufnr('%')
+ sign undefine Sign
+
+ " Listing placed sign should show that sign is deleted.
+ let a=execute('sign place')
+ call assert_equal("\n--- Signs ---\nSigns for foobar:\n" .
+ \ " line=1 id=41 name=[Deleted] priority=10\n", a)
+
+ sign unplace 41
+ let a=execute('sign place')
+ call assert_equal("\n--- Signs ---\n", a)
+endfunc
+
+func Test_sign_completion()
+ sign define Sign1 text=x
+ sign define Sign2 text=y
+
+ call feedkeys(":sign \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"sign define jump list place undefine unplace', @:)
+
+ call feedkeys(":sign define Sign \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"sign define Sign icon= linehl= text= texthl=', @:)
+
+ call feedkeys(":sign define Sign linehl=Spell\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"sign define Sign linehl=SpellBad SpellCap ' .
+ \ 'SpellLocal SpellRare', @:)
+
+ call writefile(['foo'], 'XsignOne')
+ call writefile(['bar'], 'XsignTwo')
+ call feedkeys(":sign define Sign icon=Xsig\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"sign define Sign icon=XsignOne XsignTwo', @:)
+ call delete('XsignOne')
+ call delete('XsignTwo')
+
+ call feedkeys(":sign undefine \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"sign undefine Sign1 Sign2', @:)
+
+ call feedkeys(":sign place 1 \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"sign place 1 buffer= file= group= line= name= priority=',
+ \ @:)
+
+ call feedkeys(":sign place 1 name=\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"sign place 1 name=Sign1 Sign2', @:)
+
+ call feedkeys(":sign unplace 1 \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"sign unplace 1 buffer= file= group=', @:)
+
+ call feedkeys(":sign list \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"sign list Sign1 Sign2', @:)
+
+ call feedkeys(":sign jump 1 \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"sign jump 1 buffer= file= group=', @:)
+
+ sign undefine Sign1
+ sign undefine Sign2
+endfunc
+
+func Test_sign_invalid_commands()
+ sign define Sign1 text=x
+
+ call assert_fails('sign', 'E471:')
+ call assert_fails('sign jump', 'E471:')
+ call assert_fails('sign xxx', 'E160:')
+ call assert_fails('sign define', 'E156:')
+ call assert_fails('sign define Sign1 xxx', 'E475:')
+ call assert_fails('sign undefine', 'E156:')
+ call assert_fails('sign list xxx', 'E155:')
+ call assert_fails('sign place 1 buffer=999', 'E158:')
+ call assert_fails('sign place 1 name=Sign1 buffer=999', 'E158:')
+ call assert_fails('sign place buffer=999', 'E158:')
+ call assert_fails('sign jump buffer=999', 'E158:')
+ call assert_fails('sign jump 1 file=', 'E158:')
+ call assert_fails('sign jump 1 group=', 'E474:')
+ call assert_fails('sign jump 1 name=', 'E474:')
+ call assert_fails('sign jump 1 name=Sign1', 'E474:')
+ call assert_fails('sign jump 1 line=100', '474:')
+ call assert_fails('sign define Sign2 text=', 'E239:')
+ " Non-numeric identifier for :sign place
+ call assert_fails("sign place abc line=3 name=Sign1 buffer=" . bufnr(''),
+ \ 'E474:')
+ " Non-numeric identifier for :sign unplace
+ call assert_fails("sign unplace abc name=Sign1 buffer=" . bufnr(''),
+ \ 'E474:')
+ " Number followed by an alphabet as sign identifier for :sign place
+ call assert_fails("sign place 1abc line=3 name=Sign1 buffer=" . bufnr(''),
+ \ 'E474:')
+ " Number followed by an alphabet as sign identifier for :sign unplace
+ call assert_fails("sign unplace 2abc name=Sign1 buffer=" . bufnr(''),
+ \ 'E474:')
+ " Sign identifier and '*' for :sign unplace
+ call assert_fails("sign unplace 2 *", 'E474:')
+ " Trailing characters after buffer number for :sign place
+ call assert_fails("sign place 1 line=3 name=Sign1 buffer=" .
+ \ bufnr('%') . 'xxx', 'E488:')
+ " Trailing characters after buffer number for :sign unplace
+ call assert_fails("sign unplace 1 buffer=" . bufnr('%') . 'xxx', 'E488:')
+ call assert_fails("sign unplace * buffer=" . bufnr('%') . 'xxx', 'E488:')
+ call assert_fails("sign unplace 1 xxx", 'E474:')
+ call assert_fails("sign unplace * xxx", 'E474:')
+ call assert_fails("sign unplace xxx", 'E474:')
+ " Placing a sign without line number
+ call assert_fails("sign place name=Sign1 buffer=" . bufnr('%'), 'E474:')
+ " Placing a sign without sign name
+ call assert_fails("sign place line=10 buffer=" . bufnr('%'), 'E474:')
+ " Unplacing a sign with line number
+ call assert_fails("sign unplace 2 line=10 buffer=" . bufnr('%'), 'E474:')
+ " Unplacing a sign with sign name
+ call assert_fails("sign unplace 2 name=Sign1 buffer=" . bufnr('%'), 'E474:')
+ " Placing a sign without sign name
+ call assert_fails("sign place 2 line=3 buffer=" . bufnr('%'), 'E474:')
+ " Placing a sign with only sign identifier
+ call assert_fails("sign place 2", 'E474:')
+ " Placing a sign with only a name
+ call assert_fails("sign place abc", 'E474:')
+ " Placing a sign with only line number
+ call assert_fails("sign place 5 line=3", 'E474:')
+ " Placing a sign with only sign group
+ call assert_fails("sign place 5 group=g1", 'E474:')
+ call assert_fails("sign place 5 group=*", 'E474:')
+ " Placing a sign with only sign priority
+ call assert_fails("sign place 5 priority=10", 'E474:')
+
+ sign undefine Sign1
+endfunc
+
+func Test_sign_delete_buffer()
+ new
+ sign define Sign text=x
+ let bufnr = bufnr('%')
+ new
+ exe 'bd ' . bufnr
+ exe 'sign place 61 line=3 name=Sign buffer=' . bufnr
+ call assert_fails('sign jump 61 buffer=' . bufnr, 'E934:')
+ sign unplace 61
+ sign undefine Sign
+endfunc
+
+" Test for Vim script functions for managing signs
+func Test_sign_funcs()
+ " Remove all the signs
+ call sign_unplace('*')
+ call sign_undefine()
+
+ " Tests for sign_define()
+ let attr = {'text' : '=>', 'linehl' : 'Search', 'texthl' : 'Error'}
+ call assert_equal(0, sign_define("sign1", attr))
+ call assert_equal([{'name' : 'sign1', 'texthl' : 'Error',
+ \ 'linehl' : 'Search', 'text' : '=>'}], sign_getdefined())
+
+ " Define a new sign without attributes and then update it
+ call sign_define("sign2")
+ let attr = {'text' : '!!', 'linehl' : 'DiffAdd', 'texthl' : 'DiffChange',
+ \ 'icon' : 'sign2.ico'}
+ try
+ call sign_define("sign2", attr)
+ catch /E255:/
+ " ignore error: E255: Couldn't read in sign data!
+ " This error can happen when running in gui.
+ endtry
+ call assert_equal([{'name' : 'sign2', 'texthl' : 'DiffChange',
+ \ 'linehl' : 'DiffAdd', 'text' : '!!', 'icon' : 'sign2.ico'}],
+ \ sign_getdefined("sign2"))
+
+ " Test for a sign name with digits
+ call assert_equal(0, sign_define(0002, {'linehl' : 'StatusLine'}))
+ call assert_equal([{'name' : '2', 'linehl' : 'StatusLine'}],
+ \ sign_getdefined(0002))
+ call sign_undefine(0002)
+
+ " Tests for invalid arguments to sign_define()
+ call assert_fails('call sign_define("sign4", {"text" : "===>"})', 'E239:')
+ call assert_fails('call sign_define("sign5", {"text" : ""})', 'E239:')
+ call assert_fails('call sign_define([])', 'E730:')
+ call assert_fails('call sign_define("sign6", [])', 'E715:')
+
+ " Tests for sign_getdefined()
+ call assert_equal([], sign_getdefined("none"))
+ call assert_fails('call sign_getdefined({})', 'E731:')
+
+ " Tests for sign_place()
+ call writefile(repeat(["Sun is shining"], 30), "Xsign")
+ edit Xsign
+
+ call assert_equal(10, sign_place(10, '', 'sign1', 'Xsign',
+ \ {'lnum' : 20}))
+ call assert_equal([{'bufnr' : bufnr(''), 'signs' :
+ \ [{'id' : 10, 'group' : '', 'lnum' : 20, 'name' : 'sign1',
+ \ 'priority' : 10}]}], sign_getplaced('Xsign'))
+ call assert_equal([{'bufnr' : bufnr(''), 'signs' :
+ \ [{'id' : 10, 'group' : '', 'lnum' : 20, 'name' : 'sign1',
+ \ 'priority' : 10}]}],
+ \ sign_getplaced('%', {'lnum' : 20}))
+ call assert_equal([{'bufnr' : bufnr(''), 'signs' :
+ \ [{'id' : 10, 'group' : '', 'lnum' : 20, 'name' : 'sign1',
+ \ 'priority' : 10}]}],
+ \ sign_getplaced('', {'id' : 10}))
+
+ " Tests for invalid arguments to sign_place()
+ call assert_fails('call sign_place([], "", "mySign", 1)', 'E745:')
+ call assert_fails('call sign_place(5, "", "mySign", -1)', 'E158:')
+ call assert_fails('call sign_place(-1, "", "sign1", "Xsign", [])',
+ \ 'E474:')
+ call assert_fails('call sign_place(-1, "", "sign1", "Xsign",
+ \ {"lnum" : 30})', 'E474:')
+ call assert_fails('call sign_place(10, "", "xsign1x", "Xsign",
+ \ {"lnum" : 30})', 'E155:')
+ call assert_fails('call sign_place(10, "", "", "Xsign",
+ \ {"lnum" : 30})', 'E155:')
+ call assert_fails('call sign_place(10, "", [], "Xsign",
+ \ {"lnum" : 30})', 'E730:')
+ call assert_fails('call sign_place(5, "", "sign1", "abcxyz.xxx",
+ \ {"lnum" : 10})', 'E158:')
+ call assert_fails('call sign_place(5, "", "sign1", "@", {"lnum" : 10})',
+ \ 'E158:')
+ call assert_fails('call sign_place(5, "", "sign1", [], {"lnum" : 10})',
+ \ 'E158:')
+ call assert_fails('call sign_place(21, "", "sign1", "Xsign",
+ \ {"lnum" : -1})', 'E885:')
+ call assert_fails('call sign_place(22, "", "sign1", "Xsign",
+ \ {"lnum" : 0})', 'E885:')
+ call assert_fails('call sign_place(22, "", "sign1", "Xsign",
+ \ {"lnum" : []})', 'E745:')
+ call assert_equal(-1, sign_place(1, "*", "sign1", "Xsign", {"lnum" : 10}))
+
+ " Tests for sign_getplaced()
+ call assert_equal([{'bufnr' : bufnr(''), 'signs' :
+ \ [{'id' : 10, 'group' : '', 'lnum' : 20, 'name' : 'sign1',
+ \ 'priority' : 10}]}],
+ \ sign_getplaced(bufnr('Xsign')))
+ call assert_equal([{'bufnr' : bufnr(''), 'signs' :
+ \ [{'id' : 10, 'group' : '', 'lnum' : 20, 'name' : 'sign1',
+ \ 'priority' : 10}]}],
+ \ sign_getplaced())
+ call assert_fails("call sign_getplaced('dummy.sign')", 'E158:')
+ call assert_fails('call sign_getplaced("&")', 'E158:')
+ call assert_fails('call sign_getplaced(-1)', 'E158:')
+ call assert_fails('call sign_getplaced("Xsign", [])', 'E715:')
+ call assert_equal([{'bufnr' : bufnr(''), 'signs' : []}],
+ \ sign_getplaced('Xsign', {'lnum' : 1000000}))
+ call assert_fails("call sign_getplaced('Xsign', {'lnum' : []})",
+ \ 'E745:')
+ call assert_equal([{'bufnr' : bufnr(''), 'signs' : []}],
+ \ sign_getplaced('Xsign', {'id' : 44}))
+ call assert_fails("call sign_getplaced('Xsign', {'id' : []})",
+ \ 'E745:')
+
+ " Tests for sign_unplace()
+ call sign_place(20, '', 'sign2', 'Xsign', {"lnum" : 30})
+ call assert_equal(0, sign_unplace('',
+ \ {'id' : 20, 'buffer' : 'Xsign'}))
+ call assert_equal(-1, sign_unplace('',
+ \ {'id' : 30, 'buffer' : 'Xsign'}))
+ call sign_place(20, '', 'sign2', 'Xsign', {"lnum" : 30})
+ call assert_fails("call sign_unplace('',
+ \ {'id' : 20, 'buffer' : 'buffer.c'})", 'E158:')
+ call assert_fails("call sign_unplace('',
+ \ {'id' : 20, 'buffer' : '&'})", 'E158:')
+ call assert_fails("call sign_unplace('g1',
+ \ {'id' : 20, 'buffer' : 200})", 'E158:')
+ call assert_fails("call sign_unplace('g1', 'mySign')", 'E715:')
+
+ " Tests for sign_undefine()
+ call assert_equal(0, sign_undefine("sign1"))
+ call assert_equal([], sign_getdefined("sign1"))
+ call assert_fails('call sign_undefine("none")', 'E155:')
+ call assert_fails('call sign_undefine([])', 'E730:')
+
+ call delete("Xsign")
+ call sign_unplace('*')
+ call sign_undefine()
+ enew | only
+endfunc
+
+" Tests for sign groups
+func Test_sign_group()
+ enew | only
+ " Remove all the signs
+ call sign_unplace('*')
+ call sign_undefine()
+
+ call writefile(repeat(["Sun is shining"], 30), "Xsign")
+
+ let attr = {'text' : '=>', 'linehl' : 'Search', 'texthl' : 'Error'}
+ call assert_equal(0, sign_define("sign1", attr))
+
+ edit Xsign
+ let bnum = bufnr('%')
+
+ " Error case
+ call assert_fails("call sign_place(5, [], 'sign1', 'Xsign',
+ \ {'lnum' : 30})", 'E730:')
+
+ " place three signs with the same identifier. One in the global group and
+ " others in the named groups
+ call assert_equal(5, sign_place(5, '', 'sign1', 'Xsign',
+ \ {'lnum' : 10}))
+ call assert_equal(5, sign_place(5, 'g1', 'sign1', bnum, {'lnum' : 20}))
+ call assert_equal(5, sign_place(5, 'g2', 'sign1', bnum, {'lnum' : 30}))
+
+ " Test for sign_getplaced() with group
+ let s = sign_getplaced('Xsign')
+ call assert_equal(1, len(s[0].signs))
+ call assert_equal(s[0].signs[0].group, '')
+ let s = sign_getplaced(bnum, {'group' : ''})
+ call assert_equal([{'id' : 5, 'group' : '', 'name' : 'sign1', 'lnum' : 10,
+ \ 'priority' : 10}], s[0].signs)
+ call assert_equal(1, len(s[0].signs))
+ let s = sign_getplaced(bnum, {'group' : 'g2'})
+ call assert_equal('g2', s[0].signs[0].group)
+ let s = sign_getplaced(bnum, {'group' : 'g3'})
+ call assert_equal([], s[0].signs)
+ let s = sign_getplaced(bnum, {'group' : '*'})
+ call assert_equal([{'id' : 5, 'group' : '', 'name' : 'sign1', 'lnum' : 10,
+ \ 'priority' : 10},
+ \ {'id' : 5, 'group' : 'g1', 'name' : 'sign1', 'lnum' : 20,
+ \ 'priority' : 10},
+ \ {'id' : 5, 'group' : 'g2', 'name' : 'sign1', 'lnum' : 30,
+ \ 'priority' : 10}],
+ \ s[0].signs)
+
+ " Test for sign_getplaced() with id
+ let s = sign_getplaced(bnum, {'id' : 5})
+ call assert_equal([{'id' : 5, 'group' : '', 'name' : 'sign1', 'lnum' : 10,
+ \ 'priority' : 10}],
+ \ s[0].signs)
+ let s = sign_getplaced(bnum, {'id' : 5, 'group' : 'g2'})
+ call assert_equal(
+ \ [{'id' : 5, 'name' : 'sign1', 'lnum' : 30, 'group' : 'g2',
+ \ 'priority' : 10}],
+ \ s[0].signs)
+ let s = sign_getplaced(bnum, {'id' : 5, 'group' : '*'})
+ call assert_equal([{'id' : 5, 'group' : '', 'name' : 'sign1', 'lnum' : 10,
+ \ 'priority' : 10},
+ \ {'id' : 5, 'group' : 'g1', 'name' : 'sign1', 'lnum' : 20,
+ \ 'priority' : 10},
+ \ {'id' : 5, 'group' : 'g2', 'name' : 'sign1', 'lnum' : 30,
+ \ 'priority' : 10}],
+ \ s[0].signs)
+ let s = sign_getplaced(bnum, {'id' : 5, 'group' : 'g3'})
+ call assert_equal([], s[0].signs)
+
+ " Test for sign_getplaced() with lnum
+ let s = sign_getplaced(bnum, {'lnum' : 20})
+ call assert_equal([], s[0].signs)
+ let s = sign_getplaced(bnum, {'lnum' : 20, 'group' : 'g1'})
+ call assert_equal(
+ \ [{'id' : 5, 'name' : 'sign1', 'lnum' : 20, 'group' : 'g1',
+ \ 'priority' : 10}],
+ \ s[0].signs)
+ let s = sign_getplaced(bnum, {'lnum' : 30, 'group' : '*'})
+ call assert_equal(
+ \ [{'id' : 5, 'name' : 'sign1', 'lnum' : 30, 'group' : 'g2',
+ \ 'priority' : 10}],
+ \ s[0].signs)
+ let s = sign_getplaced(bnum, {'lnum' : 40, 'group' : '*'})
+ call assert_equal([], s[0].signs)
+
+ " Error case
+ call assert_fails("call sign_getplaced(bnum, {'group' : []})",
+ \ 'E730:')
+
+ " Clear the sign in global group
+ call sign_unplace('', {'id' : 5, 'buffer' : bnum})
+ let s = sign_getplaced(bnum, {'group' : '*'})
+ call assert_equal([
+ \ {'id' : 5, 'name' : 'sign1', 'lnum' : 20, 'group' : 'g1',
+ \ 'priority' : 10},
+ \ {'id' : 5, 'name' : 'sign1', 'lnum' : 30, 'group' : 'g2',
+ \ 'priority' : 10}],
+ \ s[0].signs)
+
+ " Clear the sign in one of the groups
+ call sign_unplace('g1', {'buffer' : 'Xsign'})
+ let s = sign_getplaced(bnum, {'group' : '*'})
+ call assert_equal([
+ \ {'id' : 5, 'name' : 'sign1', 'lnum' : 30, 'group' : 'g2',
+ \ 'priority' : 10}],
+ \ s[0].signs)
+
+ " Clear all the signs from the buffer
+ call sign_unplace('*', {'buffer' : bnum})
+ call assert_equal([], sign_getplaced(bnum, {'group' : '*'})[0].signs)
+
+ " Clear sign across groups using an identifier
+ call sign_place(25, '', 'sign1', bnum, {'lnum' : 10})
+ call sign_place(25, 'g1', 'sign1', bnum, {'lnum' : 11})
+ call sign_place(25, 'g2', 'sign1', bnum, {'lnum' : 12})
+ call assert_equal(0, sign_unplace('*', {'id' : 25}))
+ call assert_equal([], sign_getplaced(bnum, {'group' : '*'})[0].signs)
+
+ " Error case
+ call assert_fails("call sign_unplace([])", 'E474:')
+
+ " Place a sign in the global group and try to delete it using a group
+ call assert_equal(5, sign_place(5, '', 'sign1', bnum, {'lnum' : 10}))
+ call assert_equal(-1, sign_unplace('g1', {'id' : 5}))
+
+ " Place signs in multiple groups and delete all the signs in one of the
+ " group
+ call assert_equal(5, sign_place(5, '', 'sign1', bnum, {'lnum' : 10}))
+ call assert_equal(6, sign_place(6, '', 'sign1', bnum, {'lnum' : 11}))
+ call assert_equal(5, sign_place(5, 'g1', 'sign1', bnum, {'lnum' : 10}))
+ call assert_equal(5, sign_place(5, 'g2', 'sign1', bnum, {'lnum' : 10}))
+ call assert_equal(6, sign_place(6, 'g1', 'sign1', bnum, {'lnum' : 11}))
+ call assert_equal(6, sign_place(6, 'g2', 'sign1', bnum, {'lnum' : 11}))
+ call assert_equal(0, sign_unplace('g1'))
+ let s = sign_getplaced(bnum, {'group' : 'g1'})
+ call assert_equal([], s[0].signs)
+ let s = sign_getplaced(bnum)
+ call assert_equal(2, len(s[0].signs))
+ let s = sign_getplaced(bnum, {'group' : 'g2'})
+ call assert_equal('g2', s[0].signs[0].group)
+ call assert_equal(0, sign_unplace('', {'id' : 5}))
+ call assert_equal(0, sign_unplace('', {'id' : 6}))
+ let s = sign_getplaced(bnum, {'group' : 'g2'})
+ call assert_equal('g2', s[0].signs[0].group)
+ call assert_equal(0, sign_unplace('', {'buffer' : bnum}))
+
+ call sign_unplace('*')
+
+ " Test for :sign command and groups
+ sign place 5 line=10 name=sign1 file=Xsign
+ sign place 5 group=g1 line=10 name=sign1 file=Xsign
+ sign place 5 group=g2 line=10 name=sign1 file=Xsign
+
+ " Tests for the ':sign place' command
+
+ " :sign place file={fname}
+ let a = execute('sign place file=Xsign')
+ call assert_equal("\n--- Signs ---\nSigns for Xsign:\n" .
+ \ " line=10 id=5 name=sign1 priority=10\n", a)
+
+ " :sign place group={group} file={fname}
+ let a = execute('sign place group=g2 file=Xsign')
+ call assert_equal("\n--- Signs ---\nSigns for Xsign:\n" .
+ \ " line=10 id=5 group=g2 name=sign1 priority=10\n", a)
+
+ " :sign place group=* file={fname}
+ let a = execute('sign place group=* file=Xsign')
+ call assert_equal("\n--- Signs ---\nSigns for Xsign:\n" .
+ \ " line=10 id=5 group=g2 name=sign1 priority=10\n" .
+ \ " line=10 id=5 group=g1 name=sign1 priority=10\n" .
+ \ " line=10 id=5 name=sign1 priority=10\n", a)
+
+ " Error case: non-existing group
+ let a = execute('sign place group=xyz file=Xsign')
+ call assert_equal("\n--- Signs ---\nSigns for Xsign:\n", a)
+
+ call sign_unplace('*')
+ let bnum = bufnr('Xsign')
+ exe 'sign place 5 line=10 name=sign1 buffer=' . bnum
+ exe 'sign place 5 group=g1 line=11 name=sign1 buffer=' . bnum
+ exe 'sign place 5 group=g2 line=12 name=sign1 buffer=' . bnum
+
+ " :sign place buffer={fname}
+ let a = execute('sign place buffer=' . bnum)
+ call assert_equal("\n--- Signs ---\nSigns for Xsign:\n" .
+ \ " line=10 id=5 name=sign1 priority=10\n", a)
+
+ " :sign place group={group} buffer={fname}
+ let a = execute('sign place group=g2 buffer=' . bnum)
+ call assert_equal("\n--- Signs ---\nSigns for Xsign:\n" .
+ \ " line=12 id=5 group=g2 name=sign1 priority=10\n", a)
+
+ " :sign place group=* buffer={fname}
+ let a = execute('sign place group=* buffer=' . bnum)
+ call assert_equal("\n--- Signs ---\nSigns for Xsign:\n" .
+ \ " line=10 id=5 name=sign1 priority=10\n" .
+ \ " line=11 id=5 group=g1 name=sign1 priority=10\n" .
+ \ " line=12 id=5 group=g2 name=sign1 priority=10\n", a)
+
+ " Error case: non-existing group
+ let a = execute('sign place group=xyz buffer=' . bnum)
+ call assert_equal("\n--- Signs ---\nSigns for Xsign:\n", a)
+
+ " :sign place
+ let a = execute('sign place')
+ call assert_equal("\n--- Signs ---\nSigns for Xsign:\n" .
+ \ " line=10 id=5 name=sign1 priority=10\n", a)
+
+ " Place signs in more than one buffer and list the signs
+ split foo
+ set buftype=nofile
+ sign place 25 line=76 name=sign1 priority=99 file=foo
+ let a = execute('sign place')
+ call assert_equal("\n--- Signs ---\nSigns for Xsign:\n" .
+ \ " line=10 id=5 name=sign1 priority=10\n" .
+ \ "Signs for foo:\n" .
+ \ " line=76 id=25 name=sign1 priority=99\n", a)
+ close
+ bwipe foo
+
+ " :sign place group={group}
+ let a = execute('sign place group=g1')
+ call assert_equal("\n--- Signs ---\nSigns for Xsign:\n" .
+ \ " line=11 id=5 group=g1 name=sign1 priority=10\n", a)
+
+ " :sign place group=*
+ let a = execute('sign place group=*')
+ call assert_equal("\n--- Signs ---\nSigns for Xsign:\n" .
+ \ " line=10 id=5 name=sign1 priority=10\n" .
+ \ " line=11 id=5 group=g1 name=sign1 priority=10\n" .
+ \ " line=12 id=5 group=g2 name=sign1 priority=10\n", a)
+
+ " Test for ':sign jump' command with groups
+ sign jump 5 group=g1 file=Xsign
+ call assert_equal(11, line('.'))
+ call assert_equal('Xsign', bufname(''))
+ sign jump 5 group=g2 file=Xsign
+ call assert_equal(12, line('.'))
+
+ " Test for :sign jump command without the filename or buffer
+ sign jump 5
+ call assert_equal(10, line('.'))
+ sign jump 5 group=g1
+ call assert_equal(11, line('.'))
+
+ " Error cases
+ call assert_fails("sign place 3 group= name=sign1 buffer=" . bnum, 'E474:')
+
+ call delete("Xsign")
+ call sign_unplace('*')
+ call sign_undefine()
+ enew | only
+endfunc
+
+" Place signs used for ":sign unplace" command test
+func Place_signs_for_test()
+ call sign_unplace('*')
+
+ sign place 3 line=10 name=sign1 file=Xsign1
+ sign place 3 group=g1 line=11 name=sign1 file=Xsign1
+ sign place 3 group=g2 line=12 name=sign1 file=Xsign1
+ sign place 4 line=15 name=sign1 file=Xsign1
+ sign place 4 group=g1 line=16 name=sign1 file=Xsign1
+ sign place 4 group=g2 line=17 name=sign1 file=Xsign1
+ sign place 5 line=20 name=sign1 file=Xsign2
+ sign place 5 group=g1 line=21 name=sign1 file=Xsign2
+ sign place 5 group=g2 line=22 name=sign1 file=Xsign2
+ sign place 6 line=25 name=sign1 file=Xsign2
+ sign place 6 group=g1 line=26 name=sign1 file=Xsign2
+ sign place 6 group=g2 line=27 name=sign1 file=Xsign2
+endfunc
+
+" Place multiple signs in a single line for test
+func Place_signs_at_line_for_test()
+ call sign_unplace('*')
+ sign place 3 line=13 name=sign1 file=Xsign1
+ sign place 3 group=g1 line=13 name=sign1 file=Xsign1
+ sign place 3 group=g2 line=13 name=sign1 file=Xsign1
+ sign place 4 line=13 name=sign1 file=Xsign1
+ sign place 4 group=g1 line=13 name=sign1 file=Xsign1
+ sign place 4 group=g2 line=13 name=sign1 file=Xsign1
+endfunc
+
+" Tests for the ':sign unplace' command
+func Test_sign_unplace()
+ enew | only
+ " Remove all the signs
+ call sign_unplace('*')
+ call sign_undefine()
+
+ " Create two files and define signs
+ call writefile(repeat(["Sun is shining"], 30), "Xsign1")
+ call writefile(repeat(["It is beautiful"], 30), "Xsign2")
+
+ let attr = {'text' : '=>', 'linehl' : 'Search', 'texthl' : 'Error'}
+ call sign_define("sign1", attr)
+
+ edit Xsign1
+ let bnum1 = bufnr('%')
+ split Xsign2
+ let bnum2 = bufnr('%')
+
+ let signs1 = [{'id' : 3, 'name' : 'sign1', 'lnum' : 10, 'group' : '',
+ \ 'priority' : 10},
+ \ {'id' : 3, 'name' : 'sign1', 'lnum' : 11, 'group' : 'g1',
+ \ 'priority' : 10},
+ \ {'id' : 3, 'name' : 'sign1', 'lnum' : 12, 'group' : 'g2',
+ \ 'priority' : 10},
+ \ {'id' : 4, 'name' : 'sign1', 'lnum' : 15, 'group' : '',
+ \ 'priority' : 10},
+ \ {'id' : 4, 'name' : 'sign1', 'lnum' : 16, 'group' : 'g1',
+ \ 'priority' : 10},
+ \ {'id' : 4, 'name' : 'sign1', 'lnum' : 17, 'group' : 'g2',
+ \ 'priority' : 10},]
+ let signs2 = [{'id' : 5, 'name' : 'sign1', 'lnum' : 20, 'group' : '',
+ \ 'priority' : 10},
+ \ {'id' : 5, 'name' : 'sign1', 'lnum' : 21, 'group' : 'g1',
+ \ 'priority' : 10},
+ \ {'id' : 5, 'name' : 'sign1', 'lnum' : 22, 'group' : 'g2',
+ \ 'priority' : 10},
+ \ {'id' : 6, 'name' : 'sign1', 'lnum' : 25, 'group' : '',
+ \ 'priority' : 10},
+ \ {'id' : 6, 'name' : 'sign1', 'lnum' : 26, 'group' : 'g1',
+ \ 'priority' : 10},
+ \ {'id' : 6, 'name' : 'sign1', 'lnum' : 27, 'group' : 'g2',
+ \ 'priority' : 10},]
+
+ " Test for :sign unplace {id} file={fname}
+ call Place_signs_for_test()
+ sign unplace 3 file=Xsign1
+ sign unplace 6 file=Xsign2
+ call assert_equal(
+ \ filter(copy(signs1),
+ \ {idx, val -> val.id != 3 || val.group != ''}),
+ \ sign_getplaced('Xsign1', {'group' : '*'})[0].signs)
+ call assert_equal(
+ \ filter(copy(signs2),
+ \ {idx, val -> val.id != 6 || val.group != ''}),
+ \ sign_getplaced('Xsign2', {'group' : '*'})[0].signs)
+
+ " Test for :sign unplace {id} group={group} file={fname}
+ call Place_signs_for_test()
+ sign unplace 4 group=g1 file=Xsign1
+ sign unplace 5 group=g2 file=Xsign2
+ call assert_equal(
+ \ filter(copy(signs1),
+ \ {idx, val -> val.id != 4 || val.group != 'g1'}),
+ \ sign_getplaced('Xsign1', {'group' : '*'})[0].signs)
+ call assert_equal(
+ \ filter(copy(signs2),
+ \ {idx, val -> val.id != 5 || val.group != 'g2'}),
+ \ sign_getplaced('Xsign2', {'group' : '*'})[0].signs)
+
+ " Test for :sign unplace {id} group=* file={fname}
+ call Place_signs_for_test()
+ sign unplace 3 group=* file=Xsign1
+ sign unplace 6 group=* file=Xsign2
+ call assert_equal(
+ \ filter(copy(signs1),
+ \ {idx, val -> val.id != 3}),
+ \ sign_getplaced('Xsign1', {'group' : '*'})[0].signs)
+ call assert_equal(
+ \ filter(copy(signs2),
+ \ {idx, val -> val.id != 6}),
+ \ sign_getplaced('Xsign2', {'group' : '*'})[0].signs)
+
+ " Test for :sign unplace * file={fname}
+ call Place_signs_for_test()
+ sign unplace * file=Xsign1
+ call assert_equal(
+ \ filter(copy(signs1),
+ \ {idx, val -> val.group != ''}),
+ \ sign_getplaced('Xsign1', {'group' : '*'})[0].signs)
+ call assert_equal(signs2, sign_getplaced('Xsign2', {'group' : '*'})[0].signs)
+
+ " Test for :sign unplace * group={group} file={fname}
+ call Place_signs_for_test()
+ sign unplace * group=g1 file=Xsign1
+ sign unplace * group=g2 file=Xsign2
+ call assert_equal(
+ \ filter(copy(signs1),
+ \ {idx, val -> val.group != 'g1'}),
+ \ sign_getplaced('Xsign1', {'group' : '*'})[0].signs)
+ call assert_equal(
+ \ filter(copy(signs2),
+ \ {idx, val -> val.group != 'g2'}),
+ \ sign_getplaced('Xsign2', {'group' : '*'})[0].signs)
+
+ " Test for :sign unplace * group=* file={fname}
+ call Place_signs_for_test()
+ sign unplace * group=* file=Xsign2
+ call assert_equal(signs1, sign_getplaced('Xsign1', {'group' : '*'})[0].signs)
+ call assert_equal([], sign_getplaced('Xsign2', {'group' : '*'})[0].signs)
+
+ " Test for :sign unplace {id} buffer={nr}
+ call Place_signs_for_test()
+ exe 'sign unplace 3 buffer=' . bnum1
+ exe 'sign unplace 6 buffer=' . bnum2
+ call assert_equal(
+ \ filter(copy(signs1),
+ \ {idx, val -> val.id != 3 || val.group != ''}),
+ \ sign_getplaced(bnum1, {'group' : '*'})[0].signs)
+ call assert_equal(
+ \ filter(copy(signs2),
+ \ {idx, val -> val.id != 6 || val.group != ''}),
+ \ sign_getplaced(bnum2, {'group' : '*'})[0].signs)
+
+ " Test for :sign unplace {id} group={group} buffer={nr}
+ call Place_signs_for_test()
+ exe 'sign unplace 4 group=g1 buffer=' . bnum1
+ exe 'sign unplace 5 group=g2 buffer=' . bnum2
+ call assert_equal(
+ \ filter(copy(signs1),
+ \ {idx, val -> val.id != 4 || val.group != 'g1'}),
+ \ sign_getplaced(bnum1, {'group' : '*'})[0].signs)
+ call assert_equal(
+ \ filter(copy(signs2),
+ \ {idx, val -> val.id != 5 || val.group != 'g2'}),
+ \ sign_getplaced(bnum2, {'group' : '*'})[0].signs)
+
+ " Test for :sign unplace {id} group=* buffer={nr}
+ call Place_signs_for_test()
+ exe 'sign unplace 3 group=* buffer=' . bnum1
+ exe 'sign unplace 6 group=* buffer=' . bnum2
+ call assert_equal(
+ \ filter(copy(signs1),
+ \ {idx, val -> val.id != 3}),
+ \ sign_getplaced(bnum1, {'group' : '*'})[0].signs)
+ call assert_equal(
+ \ filter(copy(signs2),
+ \ {idx, val -> val.id != 6}),
+ \ sign_getplaced(bnum2, {'group' : '*'})[0].signs)
+
+ " Test for :sign unplace * buffer={nr}
+ call Place_signs_for_test()
+ exe 'sign unplace * buffer=' . bnum1
+ call assert_equal(
+ \ filter(copy(signs1),
+ \ {idx, val -> val.group != ''}),
+ \ sign_getplaced(bnum1, {'group' : '*'})[0].signs)
+ call assert_equal(signs2, sign_getplaced(bnum2, {'group' : '*'})[0].signs)
+
+ " Test for :sign unplace * group={group} buffer={nr}
+ call Place_signs_for_test()
+ exe 'sign unplace * group=g1 buffer=' . bnum1
+ exe 'sign unplace * group=g2 buffer=' . bnum2
+ call assert_equal(
+ \ filter(copy(signs1),
+ \ {idx, val -> val.group != 'g1'}),
+ \ sign_getplaced(bnum1, {'group' : '*'})[0].signs)
+ call assert_equal(
+ \ filter(copy(signs2),
+ \ {idx, val -> val.group != 'g2'}),
+ \ sign_getplaced(bnum2, {'group' : '*'})[0].signs)
+
+ " Test for :sign unplace * group=* buffer={nr}
+ call Place_signs_for_test()
+ exe 'sign unplace * group=* buffer=' . bnum2
+ call assert_equal(signs1, sign_getplaced(bnum1, {'group' : '*'})[0].signs)
+ call assert_equal([], sign_getplaced(bnum2, {'group' : '*'})[0].signs)
+
+ " Test for :sign unplace {id}
+ call Place_signs_for_test()
+ sign unplace 4
+ sign unplace 6
+ call assert_equal(
+ \ filter(copy(signs1),
+ \ {idx, val -> val.id != 4 || val.group != ''}),
+ \ sign_getplaced('Xsign1', {'group' : '*'})[0].signs)
+ call assert_equal(
+ \ filter(copy(signs2),
+ \ {idx, val -> val.id != 6 || val.group != ''}),
+ \ sign_getplaced('Xsign2', {'group' : '*'})[0].signs)
+
+ " Test for :sign unplace {id} group={group}
+ call Place_signs_for_test()
+ sign unplace 4 group=g1
+ sign unplace 6 group=g2
+ call assert_equal(
+ \ filter(copy(signs1),
+ \ {idx, val -> val.id != 4 || val.group != 'g1'}),
+ \ sign_getplaced('Xsign1', {'group' : '*'})[0].signs)
+ call assert_equal(
+ \ filter(copy(signs2),
+ \ {idx, val -> val.id != 6 || val.group != 'g2'}),
+ \ sign_getplaced('Xsign2', {'group' : '*'})[0].signs)
+
+ " Test for :sign unplace {id} group=*
+ call Place_signs_for_test()
+ sign unplace 3 group=*
+ sign unplace 5 group=*
+ call assert_equal(
+ \ filter(copy(signs1),
+ \ {idx, val -> val.id != 3}),
+ \ sign_getplaced('Xsign1', {'group' : '*'})[0].signs)
+ call assert_equal(
+ \ filter(copy(signs2),
+ \ {idx, val -> val.id != 5}),
+ \ sign_getplaced('Xsign2', {'group' : '*'})[0].signs)
+
+ " Test for :sign unplace *
+ call Place_signs_for_test()
+ sign unplace *
+ call assert_equal(
+ \ filter(copy(signs1),
+ \ {idx, val -> val.group != ''}),
+ \ sign_getplaced('Xsign1', {'group' : '*'})[0].signs)
+ call assert_equal(
+ \ filter(copy(signs2),
+ \ {idx, val -> val.group != ''}),
+ \ sign_getplaced('Xsign2', {'group' : '*'})[0].signs)
+
+ " Test for :sign unplace * group={group}
+ call Place_signs_for_test()
+ sign unplace * group=g1
+ call assert_equal(
+ \ filter(copy(signs1),
+ \ {idx, val -> val.group != 'g1'}),
+ \ sign_getplaced('Xsign1', {'group' : '*'})[0].signs)
+ call assert_equal(
+ \ filter(copy(signs2),
+ \ {idx, val -> val.group != 'g1'}),
+ \ sign_getplaced('Xsign2', {'group' : '*'})[0].signs)
+
+ " Test for :sign unplace * group=*
+ call Place_signs_for_test()
+ sign unplace * group=*
+ call assert_equal([], sign_getplaced('Xsign1', {'group' : '*'})[0].signs)
+ call assert_equal([], sign_getplaced('Xsign2', {'group' : '*'})[0].signs)
+
+ " Negative test cases
+ call Place_signs_for_test()
+ sign unplace 3 group=xy file=Xsign1
+ sign unplace * group=xy file=Xsign1
+ silent! sign unplace * group=* file=FileNotPresent
+ call assert_equal(signs1, sign_getplaced('Xsign1', {'group' : '*'})[0].signs)
+ call assert_equal(signs2, sign_getplaced('Xsign2', {'group' : '*'})[0].signs)
+
+ " Tests for removing sign at the current cursor position
+
+ " Test for ':sign unplace'
+ let signs1 = [{'id' : 4, 'name' : 'sign1', 'lnum' : 13, 'group' : 'g2',
+ \ 'priority' : 10},
+ \ {'id' : 4, 'name' : 'sign1', 'lnum' : 13, 'group' : 'g1',
+ \ 'priority' : 10},
+ \ {'id' : 4, 'name' : 'sign1', 'lnum' : 13, 'group' : '',
+ \ 'priority' : 10},
+ \ {'id' : 3, 'name' : 'sign1', 'lnum' : 13, 'group' : 'g2',
+ \ 'priority' : 10},
+ \ {'id' : 3, 'name' : 'sign1', 'lnum' : 13, 'group' : 'g1',
+ \ 'priority' : 10},
+ \ {'id' : 3, 'name' : 'sign1', 'lnum' : 13, 'group' : '',
+ \ 'priority' : 10},]
+ exe bufwinnr('Xsign1') . 'wincmd w'
+ call cursor(13, 1)
+
+ " Should remove only one sign in the global group
+ call Place_signs_at_line_for_test()
+ sign unplace
+ call assert_equal(
+ \ filter(copy(signs1),
+ \ {idx, val -> val.id != 4 || val.group != ''}),
+ \ sign_getplaced('Xsign1', {'group' : '*'})[0].signs)
+ " Should remove the second sign in the global group
+ sign unplace
+ call assert_equal(
+ \ filter(copy(signs1),
+ \ {idx, val -> val.group != ''}),
+ \ sign_getplaced('Xsign1', {'group' : '*'})[0].signs)
+
+ " Test for ':sign unplace group={group}'
+ call Place_signs_at_line_for_test()
+ " Should remove only one sign in group g1
+ sign unplace group=g1
+ call assert_equal(
+ \ filter(copy(signs1),
+ \ {idx, val -> val.id != 4 || val.group != 'g1'}),
+ \ sign_getplaced('Xsign1', {'group' : '*'})[0].signs)
+ sign unplace group=g2
+ call assert_equal(
+ \ filter(copy(signs1),
+ \ {idx, val -> val.id != 4 || val.group == ''}),
+ \ sign_getplaced('Xsign1', {'group' : '*'})[0].signs)
+
+ " Test for ':sign unplace group=*'
+ call Place_signs_at_line_for_test()
+ sign unplace group=*
+ sign unplace group=*
+ sign unplace group=*
+ call assert_equal(
+ \ filter(copy(signs1),
+ \ {idx, val -> val.id != 4}),
+ \ sign_getplaced('Xsign1', {'group' : '*'})[0].signs)
+ sign unplace group=*
+ sign unplace group=*
+ sign unplace group=*
+ call assert_equal([], sign_getplaced('Xsign1', {'group' : '*'})[0].signs)
+
+ call sign_unplace('*')
+ call sign_undefine()
+ enew | only
+ call delete("Xsign1")
+ call delete("Xsign2")
+endfunc
+
+" Tests for auto-generating the sign identifier
+func Test_sign_id_autogen()
+ enew | only
+ call sign_unplace('*')
+ call sign_undefine()
+
+ let attr = {'text' : '=>', 'linehl' : 'Search', 'texthl' : 'Error'}
+ call assert_equal(0, sign_define("sign1", attr))
+
+ call writefile(repeat(["Sun is shining"], 30), "Xsign")
+ edit Xsign
+
+ call assert_equal(1, sign_place(0, '', 'sign1', 'Xsign',
+ \ {'lnum' : 10}))
+ call assert_equal(2, sign_place(2, '', 'sign1', 'Xsign',
+ \ {'lnum' : 12}))
+ call assert_equal(3, sign_place(0, '', 'sign1', 'Xsign',
+ \ {'lnum' : 14}))
+ call sign_unplace('', {'buffer' : 'Xsign', 'id' : 2})
+ call assert_equal(4, sign_place(0, '', 'sign1', 'Xsign',
+ \ {'lnum' : 12}))
+
+ call assert_equal(1, sign_place(0, 'g1', 'sign1', 'Xsign',
+ \ {'lnum' : 11}))
+ " Check for the next generated sign id in this group
+ call assert_equal(2, sign_place(0, 'g1', 'sign1', 'Xsign',
+ \ {'lnum' : 12}))
+ call assert_equal(0, sign_unplace('g1', {'id' : 1}))
+ call assert_equal(10,
+ \ sign_getplaced('Xsign', {'id' : 1})[0].signs[0].lnum)
+
+ call delete("Xsign")
+ call sign_unplace('*')
+ call sign_undefine()
+ enew | only
+endfunc
+
+" Test for sign priority
+func Test_sign_priority()
+ enew | only
+ call sign_unplace('*')
+ call sign_undefine()
+
+ let attr = {'text' : '=>', 'linehl' : 'Search', 'texthl' : 'Search'}
+ call sign_define("sign1", attr)
+ call sign_define("sign2", attr)
+ call sign_define("sign3", attr)
+
+ " Place three signs with different priority in the same line
+ call writefile(repeat(["Sun is shining"], 30), "Xsign")
+ edit Xsign
+
+ call sign_place(1, 'g1', 'sign1', 'Xsign',
+ \ {'lnum' : 11, 'priority' : 50})
+ call sign_place(2, 'g2', 'sign2', 'Xsign',
+ \ {'lnum' : 11, 'priority' : 100})
+ call sign_place(3, '', 'sign3', 'Xsign', {'lnum' : 11})
+ let s = sign_getplaced('Xsign', {'group' : '*'})
+ call assert_equal([
+ \ {'id' : 2, 'name' : 'sign2', 'lnum' : 11, 'group' : 'g2',
+ \ 'priority' : 100},
+ \ {'id' : 1, 'name' : 'sign1', 'lnum' : 11, 'group' : 'g1',
+ \ 'priority' : 50},
+ \ {'id' : 3, 'name' : 'sign3', 'lnum' : 11, 'group' : '',
+ \ 'priority' : 10}],
+ \ s[0].signs)
+
+ " Error case
+ call assert_fails("call sign_place(1, 'g1', 'sign1', 'Xsign',
+ \ [])", 'E715:')
+ call assert_fails("call sign_place(1, 'g1', 'sign1', 'Xsign',
+ \ {'priority' : []})", 'E745:')
+ call sign_unplace('*')
+
+ " Tests for the :sign place command with priority
+ sign place 5 line=10 name=sign1 priority=30 file=Xsign
+ sign place 5 group=g1 line=10 name=sign1 priority=20 file=Xsign
+ sign place 5 group=g2 line=10 name=sign1 priority=25 file=Xsign
+ let a = execute('sign place group=*')
+ call assert_equal("\n--- Signs ---\nSigns for Xsign:\n" .
+ \ " line=10 id=5 name=sign1 priority=30\n" .
+ \ " line=10 id=5 group=g2 name=sign1 priority=25\n" .
+ \ " line=10 id=5 group=g1 name=sign1 priority=20\n", a)
+
+ " Test for :sign place group={group}
+ let a = execute('sign place group=g1')
+ call assert_equal("\n--- Signs ---\nSigns for Xsign:\n" .
+ \ " line=10 id=5 group=g1 name=sign1 priority=20\n", a)
+
+ call sign_unplace('*')
+ call sign_undefine()
+ enew | only
+ call delete("Xsign")
+endfunc
+
+" Tests for memory allocation failures in sign functions
+func Test_sign_memfailures()
+ call writefile(repeat(["Sun is shining"], 30), "Xsign")
+ edit Xsign
+
+ call test_alloc_fail(GetAllocId('sign_getdefined'), 0, 0)
+ call assert_fails('call sign_getdefined("sign1")', 'E342:')
+ call test_alloc_fail(GetAllocId('sign_getplaced'), 0, 0)
+ call assert_fails('call sign_getplaced("Xsign")', 'E342:')
+ call test_alloc_fail(GetAllocId('sign_define_by_name'), 0, 0)
+ let attr = {'text' : '=>', 'linehl' : 'Search', 'texthl' : 'Error'}
+ call assert_fails('call sign_define("sign1", attr)', 'E342:')
+
+ let attr = {'text' : '=>', 'linehl' : 'Search', 'texthl' : 'Error'}
+ call sign_define("sign1", attr)
+ call test_alloc_fail(GetAllocId('sign_getlist'), 0, 0)
+ call assert_fails('call sign_getdefined("sign1")', 'E342:')
+
+ call sign_place(3, 'g1', 'sign1', 'Xsign', {'lnum' : 10})
+ call test_alloc_fail(GetAllocId('sign_getplaced_dict'), 0, 0)
+ call assert_fails('call sign_getplaced("Xsign")', 'E342:')
+ call test_alloc_fail(GetAllocId('sign_getplaced_list'), 0, 0)
+ call assert_fails('call sign_getplaced("Xsign")', 'E342:')
+
+ call test_alloc_fail(GetAllocId('insert_sign'), 0, 0)
+ call assert_fails('call sign_place(4, "g1", "sign1", "Xsign", {"lnum" : 11})',
+ \ 'E342:')
+
+ call test_alloc_fail(GetAllocId('sign_getinfo'), 0, 0)
+ call assert_fails('call getbufinfo()', 'E342:')
+ call sign_place(4, 'g1', 'sign1', 'Xsign', {'lnum' : 11})
+ call test_alloc_fail(GetAllocId('sign_getinfo'), 0, 0)
+ call assert_fails('let binfo=getbufinfo("Xsign")', 'E342:')
+ call assert_equal([{'lnum': 11, 'id': 4, 'name': 'sign1',
+ \ 'priority': 10, 'group': 'g1'}], binfo[0].signs)
+
+ call sign_unplace('*')
+ call sign_undefine()
+ enew | only
+ call delete("Xsign")
+endfunc
+
+" Test for auto-adjusting the line number of a placed sign.
+func Test_sign_lnum_adjust()
+ enew! | only!
+
+ sign define sign1 text=#> linehl=Comment
+ call setline(1, ['A', 'B', 'C', 'D', 'E'])
+ exe 'sign place 5 line=3 name=sign1 buffer=' . bufnr('')
+ let l = sign_getplaced(bufnr(''))
+ call assert_equal(3, l[0].signs[0].lnum)
+
+ " Add some lines before the sign and check the sign line number
+ call append(2, ['BA', 'BB', 'BC'])
+ let l = sign_getplaced(bufnr(''))
+ call assert_equal(6, l[0].signs[0].lnum)
+
+ " Delete some lines before the sign and check the sign line number
+ call deletebufline('%', 1, 2)
+ let l = sign_getplaced(bufnr(''))
+ call assert_equal(4, l[0].signs[0].lnum)
+
+ " Insert some lines after the sign and check the sign line number
+ call append(5, ['DA', 'DB'])
+ let l = sign_getplaced(bufnr(''))
+ call assert_equal(4, l[0].signs[0].lnum)
+
+ " Delete some lines after the sign and check the sign line number
+ call deletebufline('', 6, 7)
+ let l = sign_getplaced(bufnr(''))
+ call assert_equal(4, l[0].signs[0].lnum)
+
+ " Break the undo. Otherwise the undo operation below will undo all the
+ " changes made by this function.
+ let &undolevels=&undolevels
+
+ " Delete the line with the sign
+ call deletebufline('', 4)
+ let l = sign_getplaced(bufnr(''))
+ call assert_equal(4, l[0].signs[0].lnum)
+
+ " Undo the delete operation
+ undo
+ let l = sign_getplaced(bufnr(''))
+ call assert_equal(5, l[0].signs[0].lnum)
+
+ " Break the undo
+ let &undolevels=&undolevels
+
+ " Delete few lines at the end of the buffer including the line with the sign
+ " Sign line number should not change (as it is placed outside of the buffer)
+ call deletebufline('', 3, 6)
+ let l = sign_getplaced(bufnr(''))
+ call assert_equal(5, l[0].signs[0].lnum)
+
+ " Undo the delete operation. Sign should be restored to the previous line
+ undo
+ let l = sign_getplaced(bufnr(''))
+ call assert_equal(5, l[0].signs[0].lnum)
+
+ sign unplace * group=*
+ sign undefine sign1
+ enew!
+endfunc
+
+" Test for changing the type of a placed sign
+func Test_sign_change_type()
+ enew! | only!
+
+ sign define sign1 text=#> linehl=Comment
+ sign define sign2 text=@@ linehl=Comment
+
+ call setline(1, ['A', 'B', 'C', 'D'])
+ exe 'sign place 4 line=3 name=sign1 buffer=' . bufnr('')
+ let l = sign_getplaced(bufnr(''))
+ call assert_equal('sign1', l[0].signs[0].name)
+ exe 'sign place 4 name=sign2 buffer=' . bufnr('')
+ let l = sign_getplaced(bufnr(''))
+ call assert_equal('sign2', l[0].signs[0].name)
+ call sign_place(4, '', 'sign1', '')
+ let l = sign_getplaced(bufnr(''))
+ call assert_equal('sign1', l[0].signs[0].name)
+
+ exe 'sign place 4 group=g1 line=4 name=sign1 buffer=' . bufnr('')
+ let l = sign_getplaced(bufnr(''), {'group' : 'g1'})
+ call assert_equal('sign1', l[0].signs[0].name)
+ exe 'sign place 4 group=g1 name=sign2 buffer=' . bufnr('')
+ let l = sign_getplaced(bufnr(''), {'group' : 'g1'})
+ call assert_equal('sign2', l[0].signs[0].name)
+ call sign_place(4, 'g1', 'sign1', '')
+ let l = sign_getplaced(bufnr(''), {'group' : 'g1'})
+ call assert_equal('sign1', l[0].signs[0].name)
+
+ sign unplace * group=*
+ sign undefine sign1
+ sign undefine sign2
+ enew!
+endfunc
+
+" Test for the sign_jump() function
+func Test_sign_jump_func()
+ enew! | only!
+
+ sign define sign1 text=#> linehl=Comment
+
+ edit foo
+ set buftype=nofile
+ call setline(1, ['A', 'B', 'C', 'D', 'E'])
+ call sign_place(5, '', 'sign1', '', {'lnum' : 2})
+ call sign_place(5, 'g1', 'sign1', '', {'lnum' : 3})
+ call sign_place(6, '', 'sign1', '', {'lnum' : 4})
+ call sign_place(6, 'g1', 'sign1', '', {'lnum' : 5})
+ split bar
+ set buftype=nofile
+ call setline(1, ['P', 'Q', 'R', 'S', 'T'])
+ call sign_place(5, '', 'sign1', '', {'lnum' : 2})
+ call sign_place(5, 'g1', 'sign1', '', {'lnum' : 3})
+ call sign_place(6, '', 'sign1', '', {'lnum' : 4})
+ call sign_place(6, 'g1', 'sign1', '', {'lnum' : 5})
+
+ let r = sign_jump(5, '', 'foo')
+ call assert_equal(2, r)
+ call assert_equal(2, line('.'))
+ let r = sign_jump(6, 'g1', 'foo')
+ call assert_equal(5, r)
+ call assert_equal(5, line('.'))
+ let r = sign_jump(5, '', 'bar')
+ call assert_equal(2, r)
+ call assert_equal(2, line('.'))
+
+ " Error cases
+ call assert_fails("call sign_jump(99, '', 'bar')", 'E157:')
+ call assert_fails("call sign_jump(0, '', 'foo')", 'E474:')
+ call assert_fails("call sign_jump(5, 'g5', 'foo')", 'E157:')
+ call assert_fails('call sign_jump([], "", "foo")', 'E745:')
+ call assert_fails('call sign_jump(2, [], "foo")', 'E730:')
+ call assert_fails('call sign_jump(2, "", {})', 'E158:')
+ call assert_fails('call sign_jump(2, "", "baz")', 'E158:')
+
+ sign unplace * group=*
+ sign undefine sign1
+ enew! | only!
+endfunc
diff --git a/src/testdir/test_smartindent.vim b/src/testdir/test_smartindent.vim
new file mode 100644
index 0000000..e89ad19
--- /dev/null
+++ b/src/testdir/test_smartindent.vim
@@ -0,0 +1,41 @@
+" Tests for smartindent
+
+" Tests for not doing smart indenting when it isn't set.
+func Test_nosmartindent()
+ new
+ call append(0, [" some test text",
+ \ " test text",
+ \ "test text",
+ \ " test text"])
+ set nocindent nosmartindent autoindent
+ exe "normal! gg/some\<CR>"
+ exe "normal! 2cc#test\<Esc>"
+ call assert_equal(" #test", getline(1))
+ enew! | close
+endfunc
+
+func MyIndent()
+endfunc
+
+" When 'indentexpr' is set, setting 'si' has no effect.
+func Test_smartindent_has_no_effect()
+ new
+ exe "normal! i\<Tab>one\<Esc>"
+ set noautoindent
+ set smartindent
+ set indentexpr=
+ exe "normal! Gotwo\<Esc>"
+ call assert_equal("\ttwo", getline("$"))
+
+ set indentexpr=MyIndent
+ exe "normal! Gothree\<Esc>"
+ call assert_equal("three", getline("$"))
+
+ delfunction! MyIndent
+ set autoindent&
+ set smartindent&
+ set indentexpr&
+ bwipe!
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/test_sort.vim b/src/testdir/test_sort.vim
new file mode 100644
index 0000000..14d008a
--- /dev/null
+++ b/src/testdir/test_sort.vim
@@ -0,0 +1,1253 @@
+" Tests for the "sort()" function and for the ":sort" command.
+
+func Compare1(a, b) abort
+ call sort(range(3), 'Compare2')
+ return a:a - a:b
+endfunc
+
+func Compare2(a, b) abort
+ return a:a - a:b
+endfunc
+
+func Test_sort_strings()
+ " numbers compared as strings
+ call assert_equal([1, 2, 3], sort([3, 2, 1]))
+ call assert_equal([13, 28, 3], sort([3, 28, 13]))
+endfunc
+
+func Test_sort_numeric()
+ call assert_equal([1, 2, 3], sort([3, 2, 1], 'n'))
+ call assert_equal([3, 13, 28], sort([13, 28, 3], 'n'))
+ " strings are not sorted
+ call assert_equal(['13', '28', '3'], sort(['13', '28', '3'], 'n'))
+endfunc
+
+func Test_sort_numbers()
+ call assert_equal([3, 13, 28], sort([13, 28, 3], 'N'))
+ call assert_equal(['3', '13', '28'], sort(['13', '28', '3'], 'N'))
+endfunc
+
+func Test_sort_float()
+ call assert_equal([0.28, 3, 13.5], sort([13.5, 0.28, 3], 'f'))
+endfunc
+
+func Test_sort_nested()
+ " test ability to call sort() from a compare function
+ call assert_equal([1, 3, 5], sort([3, 1, 5], 'Compare1'))
+endfunc
+
+func Test_sort_default()
+ " docs say omitted, empty or zero argument sorts on string representation.
+ call assert_equal(['2', 'A', 'AA', 'a', 1, 3.3], sort([3.3, 1, "2", "A", "a", "AA"]))
+ call assert_equal(['2', 'A', 'AA', 'a', 1, 3.3], sort([3.3, 1, "2", "A", "a", "AA"], ''))
+ call assert_equal(['2', 'A', 'AA', 'a', 1, 3.3], sort([3.3, 1, "2", "A", "a", "AA"], 0))
+ call assert_equal(['2', 'A', 'a', 'AA', 1, 3.3], sort([3.3, 1, "2", "A", "a", "AA"], 1))
+ call assert_fails('call sort([3.3, 1, "2"], 3)', "E474")
+endfunc
+
+" Tests for the ":sort" command.
+func Test_sort_cmd()
+ let tests = [
+ \ {
+ \ 'name' : 'Alphabetical sort',
+ \ 'cmd' : '%sort',
+ \ 'input' : [
+ \ 'abc',
+ \ 'ab',
+ \ 'a',
+ \ 'a321',
+ \ 'a123',
+ \ 'a122',
+ \ 'b321',
+ \ 'b123',
+ \ 'c123d',
+ \ ' 123b',
+ \ 'c321d',
+ \ 'b322b',
+ \ 'b321',
+ \ 'b321b'
+ \ ],
+ \ 'expected' : [
+ \ ' 123b',
+ \ 'a',
+ \ 'a122',
+ \ 'a123',
+ \ 'a321',
+ \ 'ab',
+ \ 'abc',
+ \ 'b123',
+ \ 'b321',
+ \ 'b321',
+ \ 'b321b',
+ \ 'b322b',
+ \ 'c123d',
+ \ 'c321d'
+ \ ]
+ \ },
+ \ {
+ \ 'name' : 'Numeric sort',
+ \ 'cmd' : '%sort n',
+ \ 'input' : [
+ \ 'abc',
+ \ 'ab',
+ \ 'a321',
+ \ 'a123',
+ \ 'a122',
+ \ 'a',
+ \ 'x-22',
+ \ 'b321',
+ \ 'b123',
+ \ '',
+ \ 'c123d',
+ \ '-24',
+ \ ' 123b',
+ \ 'c321d',
+ \ '0',
+ \ 'b322b',
+ \ 'b321',
+ \ 'b321b'
+ \ ],
+ \ 'expected' : [
+ \ 'abc',
+ \ 'ab',
+ \ 'a',
+ \ '',
+ \ '-24',
+ \ 'x-22',
+ \ '0',
+ \ 'a122',
+ \ 'a123',
+ \ 'b123',
+ \ 'c123d',
+ \ ' 123b',
+ \ 'a321',
+ \ 'b321',
+ \ 'c321d',
+ \ 'b321',
+ \ 'b321b',
+ \ 'b322b'
+ \ ]
+ \ },
+ \ {
+ \ 'name' : 'Hexadecimal sort',
+ \ 'cmd' : '%sort x',
+ \ 'input' : [
+ \ 'abc',
+ \ 'ab',
+ \ 'a',
+ \ 'a321',
+ \ 'a123',
+ \ 'a122',
+ \ 'b321',
+ \ 'b123',
+ \ 'c123d',
+ \ ' 123b',
+ \ 'c321d',
+ \ 'b322b',
+ \ 'b321',
+ \ 'b321b'
+ \ ],
+ \ 'expected' : [
+ \ 'a',
+ \ 'ab',
+ \ 'abc',
+ \ ' 123b',
+ \ 'a122',
+ \ 'a123',
+ \ 'a321',
+ \ 'b123',
+ \ 'b321',
+ \ 'b321',
+ \ 'b321b',
+ \ 'b322b',
+ \ 'c123d',
+ \ 'c321d'
+ \ ]
+ \ },
+ \ {
+ \ 'name' : 'Alphabetical unique sort',
+ \ 'cmd' : '%sort u',
+ \ 'input' : [
+ \ 'abc',
+ \ 'ab',
+ \ 'a',
+ \ 'a321',
+ \ 'a123',
+ \ 'a122',
+ \ 'b321',
+ \ 'b123',
+ \ 'c123d',
+ \ ' 123b',
+ \ 'c321d',
+ \ 'b322b',
+ \ 'b321',
+ \ 'b321b'
+ \ ],
+ \ 'expected' : [
+ \ ' 123b',
+ \ 'a',
+ \ 'a122',
+ \ 'a123',
+ \ 'a321',
+ \ 'ab',
+ \ 'abc',
+ \ 'b123',
+ \ 'b321',
+ \ 'b321b',
+ \ 'b322b',
+ \ 'c123d',
+ \ 'c321d'
+ \ ]
+ \ },
+ \ {
+ \ 'name' : 'Alphabetical reverse sort',
+ \ 'cmd' : '%sort!',
+ \ 'input' : [
+ \ 'abc',
+ \ 'ab',
+ \ 'a',
+ \ 'a321',
+ \ 'a123',
+ \ 'a122',
+ \ 'b321',
+ \ 'b123',
+ \ 'c123d',
+ \ ' 123b',
+ \ 'c321d',
+ \ 'b322b',
+ \ 'b321',
+ \ 'b321b'
+ \ ],
+ \ 'expected' : [
+ \ 'c321d',
+ \ 'c123d',
+ \ 'b322b',
+ \ 'b321b',
+ \ 'b321',
+ \ 'b321',
+ \ 'b123',
+ \ 'abc',
+ \ 'ab',
+ \ 'a321',
+ \ 'a123',
+ \ 'a122',
+ \ 'a',
+ \ ' 123b',
+ \ ]
+ \ },
+ \ {
+ \ 'name' : 'Numeric reverse sort',
+ \ 'cmd' : '%sort! n',
+ \ 'input' : [
+ \ 'abc',
+ \ 'ab',
+ \ 'a',
+ \ 'a321',
+ \ 'a123',
+ \ 'a122',
+ \ 'b321',
+ \ 'b123',
+ \ 'c123d',
+ \ ' 123b',
+ \ 'c321d',
+ \ 'b322b',
+ \ 'b321',
+ \ 'b321b'
+ \ ],
+ \ 'expected' : [
+ \ 'b322b',
+ \ 'b321b',
+ \ 'b321',
+ \ 'c321d',
+ \ 'b321',
+ \ 'a321',
+ \ ' 123b',
+ \ 'c123d',
+ \ 'b123',
+ \ 'a123',
+ \ 'a122',
+ \ 'a',
+ \ 'ab',
+ \ 'abc'
+ \ ]
+ \ },
+ \ {
+ \ 'name' : 'Unique reverse sort',
+ \ 'cmd' : 'sort! u',
+ \ 'input' : [
+ \ 'abc',
+ \ 'ab',
+ \ 'a',
+ \ 'a321',
+ \ 'a123',
+ \ 'a122',
+ \ 'b321',
+ \ 'b123',
+ \ 'c123d',
+ \ ' 123b',
+ \ 'c321d',
+ \ 'b322b',
+ \ 'b321',
+ \ 'b321b'
+ \ ],
+ \ 'expected' : [
+ \ 'c321d',
+ \ 'c123d',
+ \ 'b322b',
+ \ 'b321b',
+ \ 'b321',
+ \ 'b123',
+ \ 'abc',
+ \ 'ab',
+ \ 'a321',
+ \ 'a123',
+ \ 'a122',
+ \ 'a',
+ \ ' 123b',
+ \ ]
+ \ },
+ \ {
+ \ 'name' : 'Octal sort',
+ \ 'cmd' : 'sort o',
+ \ 'input' : [
+ \ 'abc',
+ \ 'ab',
+ \ 'a',
+ \ 'a321',
+ \ 'a123',
+ \ 'a122',
+ \ 'b321',
+ \ 'b123',
+ \ 'c123d',
+ \ ' 123b',
+ \ 'c321d',
+ \ 'b322b',
+ \ 'b321',
+ \ 'b321b',
+ \ '',
+ \ ''
+ \ ],
+ \ 'expected' : [
+ \ 'abc',
+ \ 'ab',
+ \ 'a',
+ \ '',
+ \ '',
+ \ 'a122',
+ \ 'a123',
+ \ 'b123',
+ \ 'c123d',
+ \ ' 123b',
+ \ 'a321',
+ \ 'b321',
+ \ 'c321d',
+ \ 'b321',
+ \ 'b321b',
+ \ 'b322b'
+ \ ]
+ \ },
+ \ {
+ \ 'name' : 'Reverse hexadecimal sort',
+ \ 'cmd' : 'sort! x',
+ \ 'input' : [
+ \ 'abc',
+ \ 'ab',
+ \ 'a',
+ \ 'a321',
+ \ 'a123',
+ \ 'a122',
+ \ 'b321',
+ \ 'b123',
+ \ 'c123d',
+ \ ' 123b',
+ \ 'c321d',
+ \ 'b322b',
+ \ 'b321',
+ \ 'b321b',
+ \ '',
+ \ ''
+ \ ],
+ \ 'expected' : [
+ \ 'c321d',
+ \ 'c123d',
+ \ 'b322b',
+ \ 'b321b',
+ \ 'b321',
+ \ 'b321',
+ \ 'b123',
+ \ 'a321',
+ \ 'a123',
+ \ 'a122',
+ \ ' 123b',
+ \ 'abc',
+ \ 'ab',
+ \ 'a',
+ \ '',
+ \ ''
+ \ ]
+ \ },
+ \ {
+ \ 'name' : 'Alpha (skip first character) sort',
+ \ 'cmd' : 'sort/./',
+ \ 'input' : [
+ \ 'abc',
+ \ 'ab',
+ \ 'a',
+ \ 'a321',
+ \ 'a123',
+ \ 'a122',
+ \ 'b321',
+ \ 'b123',
+ \ 'c123d',
+ \ ' 123b',
+ \ 'c321d',
+ \ 'b322b',
+ \ 'b321',
+ \ 'b321b',
+ \ '',
+ \ ''
+ \ ],
+ \ 'expected' : [
+ \ 'a',
+ \ '',
+ \ '',
+ \ 'a122',
+ \ 'a123',
+ \ 'b123',
+ \ ' 123b',
+ \ 'c123d',
+ \ 'a321',
+ \ 'b321',
+ \ 'b321',
+ \ 'b321b',
+ \ 'c321d',
+ \ 'b322b',
+ \ 'ab',
+ \ 'abc'
+ \ ]
+ \ },
+ \ {
+ \ 'name' : 'Alpha (skip first 2 characters) sort',
+ \ 'cmd' : 'sort/../',
+ \ 'input' : [
+ \ 'abc',
+ \ 'ab',
+ \ 'a',
+ \ 'a321',
+ \ 'a123',
+ \ 'a122',
+ \ 'b321',
+ \ 'b123',
+ \ 'c123d',
+ \ ' 123b',
+ \ 'c321d',
+ \ 'b322b',
+ \ 'b321',
+ \ 'b321b',
+ \ '',
+ \ ''
+ \ ],
+ \ 'expected' : [
+ \ 'ab',
+ \ 'a',
+ \ '',
+ \ '',
+ \ 'a321',
+ \ 'b321',
+ \ 'b321',
+ \ 'b321b',
+ \ 'c321d',
+ \ 'a122',
+ \ 'b322b',
+ \ 'a123',
+ \ 'b123',
+ \ ' 123b',
+ \ 'c123d',
+ \ 'abc'
+ \ ]
+ \ },
+ \ {
+ \ 'name' : 'alpha, unique, skip first 2 characters',
+ \ 'cmd' : 'sort/../u',
+ \ 'input' : [
+ \ 'abc',
+ \ 'ab',
+ \ 'a',
+ \ 'a321',
+ \ 'a123',
+ \ 'a122',
+ \ 'b321',
+ \ 'b123',
+ \ 'c123d',
+ \ ' 123b',
+ \ 'c321d',
+ \ 'b322b',
+ \ 'b321',
+ \ 'b321b',
+ \ '',
+ \ ''
+ \ ],
+ \ 'expected' : [
+ \ 'ab',
+ \ 'a',
+ \ '',
+ \ 'a321',
+ \ 'b321',
+ \ 'b321b',
+ \ 'c321d',
+ \ 'a122',
+ \ 'b322b',
+ \ 'a123',
+ \ 'b123',
+ \ ' 123b',
+ \ 'c123d',
+ \ 'abc'
+ \ ]
+ \ },
+ \ {
+ \ 'name' : 'numeric, skip first character',
+ \ 'cmd' : 'sort/./n',
+ \ 'input' : [
+ \ 'abc',
+ \ 'ab',
+ \ 'a',
+ \ 'a321',
+ \ 'a123',
+ \ 'a122',
+ \ 'b321',
+ \ 'b123',
+ \ 'c123d',
+ \ ' 123b',
+ \ 'c321d',
+ \ 'b322b',
+ \ 'b321',
+ \ 'b321b',
+ \ '',
+ \ ''
+ \ ],
+ \ 'expected' : [
+ \ 'abc',
+ \ 'ab',
+ \ 'a',
+ \ '',
+ \ '',
+ \ 'a122',
+ \ 'a123',
+ \ 'b123',
+ \ 'c123d',
+ \ ' 123b',
+ \ 'a321',
+ \ 'b321',
+ \ 'c321d',
+ \ 'b321',
+ \ 'b321b',
+ \ 'b322b'
+ \ ]
+ \ },
+ \ {
+ \ 'name' : 'alpha, sort on first character',
+ \ 'cmd' : 'sort/./r',
+ \ 'input' : [
+ \ 'abc',
+ \ 'ab',
+ \ 'a',
+ \ 'a321',
+ \ 'a123',
+ \ 'a122',
+ \ 'b321',
+ \ 'b123',
+ \ 'c123d',
+ \ ' 123b',
+ \ 'c321d',
+ \ 'b322b',
+ \ 'b321',
+ \ 'b321b',
+ \ '',
+ \ ''
+ \ ],
+ \ 'expected' : [
+ \ '',
+ \ '',
+ \ ' 123b',
+ \ 'abc',
+ \ 'ab',
+ \ 'a',
+ \ 'a321',
+ \ 'a123',
+ \ 'a122',
+ \ 'b321',
+ \ 'b123',
+ \ 'b322b',
+ \ 'b321',
+ \ 'b321b',
+ \ 'c123d',
+ \ 'c321d'
+ \ ]
+ \ },
+ \ {
+ \ 'name' : 'alpha, sort on first 2 characters',
+ \ 'cmd' : 'sort/../r',
+ \ 'input' : [
+ \ 'abc',
+ \ 'ab',
+ \ 'a',
+ \ 'a321',
+ \ 'a123',
+ \ 'a122',
+ \ 'b321',
+ \ 'b123',
+ \ 'c123d',
+ \ ' 123b',
+ \ 'c321d',
+ \ 'b322b',
+ \ 'b321',
+ \ 'b321b',
+ \ '',
+ \ ''
+ \ ],
+ \ 'expected' : [
+ \ 'a',
+ \ '',
+ \ '',
+ \ ' 123b',
+ \ 'a123',
+ \ 'a122',
+ \ 'a321',
+ \ 'abc',
+ \ 'ab',
+ \ 'b123',
+ \ 'b321',
+ \ 'b322b',
+ \ 'b321',
+ \ 'b321b',
+ \ 'c123d',
+ \ 'c321d'
+ \ ]
+ \ },
+ \ {
+ \ 'name' : 'numeric, sort on first character',
+ \ 'cmd' : 'sort/./rn',
+ \ 'input' : [
+ \ 'abc',
+ \ 'ab',
+ \ 'a',
+ \ 'a321',
+ \ 'a123',
+ \ 'a122',
+ \ 'b321',
+ \ 'b123',
+ \ 'c123d',
+ \ ' 123b',
+ \ 'c321d',
+ \ 'b322b',
+ \ 'b321',
+ \ 'b321b',
+ \ '',
+ \ ''
+ \ ],
+ \ 'expected' : [
+ \ 'abc',
+ \ 'ab',
+ \ 'a',
+ \ 'a321',
+ \ 'a123',
+ \ 'a122',
+ \ 'b321',
+ \ 'b123',
+ \ 'c123d',
+ \ ' 123b',
+ \ 'c321d',
+ \ 'b322b',
+ \ 'b321',
+ \ 'b321b',
+ \ '',
+ \ ''
+ \ ]
+ \ },
+ \ {
+ \ 'name' : 'alpha, skip past first digit',
+ \ 'cmd' : 'sort/\d/',
+ \ 'input' : [
+ \ 'abc',
+ \ 'ab',
+ \ 'a',
+ \ 'a321',
+ \ 'a123',
+ \ 'a122',
+ \ 'b321',
+ \ 'b123',
+ \ 'c123d',
+ \ ' 123b',
+ \ 'c321d',
+ \ 'b322b',
+ \ 'b321',
+ \ 'b321b',
+ \ '',
+ \ ''
+ \ ],
+ \ 'expected' : [
+ \ 'abc',
+ \ 'ab',
+ \ 'a',
+ \ '',
+ \ '',
+ \ 'a321',
+ \ 'b321',
+ \ 'b321',
+ \ 'b321b',
+ \ 'c321d',
+ \ 'a122',
+ \ 'b322b',
+ \ 'a123',
+ \ 'b123',
+ \ ' 123b',
+ \ 'c123d'
+ \ ]
+ \ },
+ \ {
+ \ 'name' : 'alpha, sort on first digit',
+ \ 'cmd' : 'sort/\d/r',
+ \ 'input' : [
+ \ 'abc',
+ \ 'ab',
+ \ 'a',
+ \ 'a321',
+ \ 'a123',
+ \ 'a122',
+ \ 'b321',
+ \ 'b123',
+ \ 'c123d',
+ \ ' 123b',
+ \ 'c321d',
+ \ 'b322b',
+ \ 'b321',
+ \ 'b321b',
+ \ '',
+ \ ''
+ \ ],
+ \ 'expected' : [
+ \ 'abc',
+ \ 'ab',
+ \ 'a',
+ \ '',
+ \ '',
+ \ 'a123',
+ \ 'a122',
+ \ 'b123',
+ \ 'c123d',
+ \ ' 123b',
+ \ 'a321',
+ \ 'b321',
+ \ 'c321d',
+ \ 'b322b',
+ \ 'b321',
+ \ 'b321b'
+ \ ]
+ \ },
+ \ {
+ \ 'name' : 'numeric, skip past first digit',
+ \ 'cmd' : 'sort/\d/n',
+ \ 'input' : [
+ \ 'abc',
+ \ 'ab',
+ \ 'a',
+ \ 'a321',
+ \ 'a123',
+ \ 'a122',
+ \ 'b321',
+ \ 'b123',
+ \ 'c123d',
+ \ ' 123b',
+ \ 'c321d',
+ \ 'b322b',
+ \ 'b321',
+ \ 'b321b',
+ \ '',
+ \ ''
+ \ ],
+ \ 'expected' : [
+ \ 'abc',
+ \ 'ab',
+ \ 'a',
+ \ '',
+ \ '',
+ \ 'a321',
+ \ 'b321',
+ \ 'c321d',
+ \ 'b321',
+ \ 'b321b',
+ \ 'a122',
+ \ 'b322b',
+ \ 'a123',
+ \ 'b123',
+ \ 'c123d',
+ \ ' 123b'
+ \ ]
+ \ },
+ \ {
+ \ 'name' : 'numeric, sort on first digit',
+ \ 'cmd' : 'sort/\d/rn',
+ \ 'input' : [
+ \ 'abc',
+ \ 'ab',
+ \ 'a',
+ \ 'a321',
+ \ 'a123',
+ \ 'a122',
+ \ 'b321',
+ \ 'b123',
+ \ 'c123d',
+ \ ' 123b',
+ \ 'c321d',
+ \ 'b322b',
+ \ 'b321',
+ \ 'b321b',
+ \ '',
+ \ ''
+ \ ],
+ \ 'expected' : [
+ \ 'abc',
+ \ 'ab',
+ \ 'a',
+ \ '',
+ \ '',
+ \ 'a123',
+ \ 'a122',
+ \ 'b123',
+ \ 'c123d',
+ \ ' 123b',
+ \ 'a321',
+ \ 'b321',
+ \ 'c321d',
+ \ 'b322b',
+ \ 'b321',
+ \ 'b321b'
+ \ ]
+ \ },
+ \ {
+ \ 'name' : 'alpha, skip past first 2 digits',
+ \ 'cmd' : 'sort/\d\d/',
+ \ 'input' : [
+ \ 'abc',
+ \ 'ab',
+ \ 'a',
+ \ 'a321',
+ \ 'a123',
+ \ 'a122',
+ \ 'b321',
+ \ 'b123',
+ \ 'c123d',
+ \ ' 123b',
+ \ 'c321d',
+ \ 'b322b',
+ \ 'b321',
+ \ 'b321b',
+ \ '',
+ \ ''
+ \ ],
+ \ 'expected' : [
+ \ 'abc',
+ \ 'ab',
+ \ 'a',
+ \ '',
+ \ '',
+ \ 'a321',
+ \ 'b321',
+ \ 'b321',
+ \ 'b321b',
+ \ 'c321d',
+ \ 'a122',
+ \ 'b322b',
+ \ 'a123',
+ \ 'b123',
+ \ ' 123b',
+ \ 'c123d'
+ \ ]
+ \ },
+ \ {
+ \ 'name' : 'numeric, skip past first 2 digits',
+ \ 'cmd' : 'sort/\d\d/n',
+ \ 'input' : [
+ \ 'abc',
+ \ 'ab',
+ \ 'a',
+ \ 'a321',
+ \ 'a123',
+ \ 'a122',
+ \ 'b321',
+ \ 'b123',
+ \ 'c123d',
+ \ ' 123b',
+ \ 'c321d',
+ \ 'b322b',
+ \ 'b321',
+ \ 'b321b',
+ \ '',
+ \ ''
+ \ ],
+ \ 'expected' : [
+ \ 'abc',
+ \ 'ab',
+ \ 'a',
+ \ '',
+ \ '',
+ \ 'a321',
+ \ 'b321',
+ \ 'c321d',
+ \ 'b321',
+ \ 'b321b',
+ \ 'a122',
+ \ 'b322b',
+ \ 'a123',
+ \ 'b123',
+ \ 'c123d',
+ \ ' 123b'
+ \ ]
+ \ },
+ \ {
+ \ 'name' : 'hexadecimal, skip past first 2 digits',
+ \ 'cmd' : 'sort/\d\d/x',
+ \ 'input' : [
+ \ 'abc',
+ \ 'ab',
+ \ 'a',
+ \ 'a321',
+ \ 'a123',
+ \ 'a122',
+ \ 'b321',
+ \ 'b123',
+ \ 'c123d',
+ \ ' 123b',
+ \ 'c321d',
+ \ 'b322b',
+ \ 'b321',
+ \ 'b321b',
+ \ '',
+ \ ''
+ \ ],
+ \ 'expected' : [
+ \ 'abc',
+ \ 'ab',
+ \ 'a',
+ \ '',
+ \ '',
+ \ 'a321',
+ \ 'b321',
+ \ 'b321',
+ \ 'a122',
+ \ 'a123',
+ \ 'b123',
+ \ 'b321b',
+ \ 'c321d',
+ \ 'b322b',
+ \ ' 123b',
+ \ 'c123d'
+ \ ]
+ \ },
+ \ {
+ \ 'name' : 'alpha, sort on first 2 digits',
+ \ 'cmd' : 'sort/\d\d/r',
+ \ 'input' : [
+ \ 'abc',
+ \ 'ab',
+ \ 'a',
+ \ 'a321',
+ \ 'a123',
+ \ 'a122',
+ \ 'b321',
+ \ 'b123',
+ \ 'c123d',
+ \ ' 123b',
+ \ 'c321d',
+ \ 'b322b',
+ \ 'b321',
+ \ 'b321b',
+ \ '',
+ \ ''
+ \ ],
+ \ 'expected' : [
+ \ 'abc',
+ \ 'ab',
+ \ 'a',
+ \ '',
+ \ '',
+ \ 'a123',
+ \ 'a122',
+ \ 'b123',
+ \ 'c123d',
+ \ ' 123b',
+ \ 'a321',
+ \ 'b321',
+ \ 'c321d',
+ \ 'b322b',
+ \ 'b321',
+ \ 'b321b'
+ \ ]
+ \ },
+ \ {
+ \ 'name' : 'numeric, sort on first 2 digits',
+ \ 'cmd' : 'sort/\d\d/rn',
+ \ 'input' : [
+ \ 'abc',
+ \ 'ab',
+ \ 'a',
+ \ 'a321',
+ \ 'a123',
+ \ 'a122',
+ \ 'b321',
+ \ 'b123',
+ \ 'c123d',
+ \ ' 123b',
+ \ 'c321d',
+ \ 'b322b',
+ \ 'b321',
+ \ 'b321b',
+ \ '',
+ \ ''
+ \ ],
+ \ 'expected' : [
+ \ 'abc',
+ \ 'ab',
+ \ 'a',
+ \ '',
+ \ '',
+ \ 'a123',
+ \ 'a122',
+ \ 'b123',
+ \ 'c123d',
+ \ ' 123b',
+ \ 'a321',
+ \ 'b321',
+ \ 'c321d',
+ \ 'b322b',
+ \ 'b321',
+ \ 'b321b'
+ \ ]
+ \ },
+ \ {
+ \ 'name' : 'hexadecimal, sort on first 2 digits',
+ \ 'cmd' : 'sort/\d\d/rx',
+ \ 'input' : [
+ \ 'abc',
+ \ 'ab',
+ \ 'a',
+ \ 'a321',
+ \ 'a123',
+ \ 'a122',
+ \ 'b321',
+ \ 'b123',
+ \ 'c123d',
+ \ ' 123b',
+ \ 'c321d',
+ \ 'b322b',
+ \ 'b321',
+ \ 'b321b',
+ \ '',
+ \ ''
+ \ ],
+ \ 'expected' : [
+ \ 'abc',
+ \ 'ab',
+ \ 'a',
+ \ '',
+ \ '',
+ \ 'a123',
+ \ 'a122',
+ \ 'b123',
+ \ 'c123d',
+ \ ' 123b',
+ \ 'a321',
+ \ 'b321',
+ \ 'c321d',
+ \ 'b322b',
+ \ 'b321',
+ \ 'b321b'
+ \ ]
+ \ },
+ \ {
+ \ 'name' : 'binary',
+ \ 'cmd' : 'sort b',
+ \ 'input' : [
+ \ '0b111000',
+ \ '0b101100',
+ \ '0b101001',
+ \ '0b101001',
+ \ '0b101000',
+ \ '0b000000',
+ \ '0b001000',
+ \ '0b010000',
+ \ '0b101000',
+ \ '0b100000',
+ \ '0b101010',
+ \ '0b100010',
+ \ '0b100100',
+ \ '0b100010',
+ \ '',
+ \ ''
+ \ ],
+ \ 'expected' : [
+ \ '',
+ \ '',
+ \ '0b000000',
+ \ '0b001000',
+ \ '0b010000',
+ \ '0b100000',
+ \ '0b100010',
+ \ '0b100010',
+ \ '0b100100',
+ \ '0b101000',
+ \ '0b101000',
+ \ '0b101001',
+ \ '0b101001',
+ \ '0b101010',
+ \ '0b101100',
+ \ '0b111000'
+ \ ]
+ \ },
+ \ {
+ \ 'name' : 'binary with leading characters',
+ \ 'cmd' : 'sort b',
+ \ 'input' : [
+ \ '0b100010',
+ \ '0b010000',
+ \ ' 0b101001',
+ \ 'b0b101100',
+ \ '0b100010',
+ \ ' 0b100100',
+ \ 'a0b001000',
+ \ '0b101000',
+ \ '0b101000',
+ \ 'a0b101001',
+ \ 'ab0b100000',
+ \ '0b101010',
+ \ '0b000000',
+ \ 'b0b111000',
+ \ '',
+ \ ''
+ \ ],
+ \ 'expected' : [
+ \ '',
+ \ '',
+ \ '0b000000',
+ \ 'a0b001000',
+ \ '0b010000',
+ \ 'ab0b100000',
+ \ '0b100010',
+ \ '0b100010',
+ \ ' 0b100100',
+ \ '0b101000',
+ \ '0b101000',
+ \ ' 0b101001',
+ \ 'a0b101001',
+ \ '0b101010',
+ \ 'b0b101100',
+ \ 'b0b111000'
+ \ ]
+ \ },
+ \ {
+ \ 'name' : 'float',
+ \ 'cmd' : 'sort f',
+ \ 'input' : [
+ \ '1.234',
+ \ '0.88',
+ \ '123.456',
+ \ '1.15e-6',
+ \ '-1.1e3',
+ \ '-1.01e3',
+ \ '',
+ \ ''
+ \ ],
+ \ 'expected' : [
+ \ '',
+ \ '',
+ \ '-1.1e3',
+ \ '-1.01e3',
+ \ '1.15e-6',
+ \ '0.88',
+ \ '1.234',
+ \ '123.456'
+ \ ]
+ \ },
+ \ {
+ \ 'name' : 'alphabetical, sorted input',
+ \ 'cmd' : 'sort',
+ \ 'input' : [
+ \ 'a',
+ \ 'b',
+ \ 'c',
+ \ ],
+ \ 'expected' : [
+ \ 'a',
+ \ 'b',
+ \ 'c',
+ \ ]
+ \ },
+ \ {
+ \ 'name' : 'alphabetical, sorted input, unique at end',
+ \ 'cmd' : 'sort u',
+ \ 'input' : [
+ \ 'aa',
+ \ 'bb',
+ \ 'cc',
+ \ 'cc',
+ \ ],
+ \ 'expected' : [
+ \ 'aa',
+ \ 'bb',
+ \ 'cc',
+ \ ]
+ \ },
+ \ ]
+
+ for t in tests
+ enew!
+ call append(0, t.input)
+ $delete _
+ setlocal nomodified
+ execute t.cmd
+
+ call assert_equal(t.expected, getline(1, '$'), t.name)
+
+ " Previously, the ":sort" command would set 'modified' even if the buffer
+ " contents did not change. Here, we check that this problem is fixed.
+ if t.input == t.expected
+ call assert_false(&modified, t.name . ': &mod is not correct')
+ else
+ call assert_true(&modified, t.name . ': &mod is not correct')
+ endif
+ endfor
+
+ call assert_fails('sort no', 'E474')
+
+ enew!
+endfunc
+
+func Test_sort_cmd_report()
+ enew!
+ call append(0, repeat([1], 3) + repeat([2], 3) + repeat([3], 3))
+ $delete _
+ setlocal nomodified
+ let res = execute('%sort u')
+
+ call assert_equal([1,2,3], map(getline(1, '$'), 'v:val+0'))
+ call assert_match("6 fewer lines", res)
+ enew!
+ call append(0, repeat([1], 3) + repeat([2], 3) + repeat([3], 3))
+ $delete _
+ setlocal nomodified report=10
+ let res = execute('%sort u')
+
+ call assert_equal([1,2,3], map(getline(1, '$'), 'v:val+0'))
+ call assert_equal("", res)
+ enew!
+ call append(0, repeat([1], 3) + repeat([2], 3) + repeat([3], 3))
+ $delete _
+ setl report&vim
+ setlocal nomodified
+ let res = execute('1g/^/%sort u')
+
+ call assert_equal([1,2,3], map(getline(1, '$'), 'v:val+0'))
+ " the output comes from the :g command, not from the :sort
+ call assert_match("6 fewer lines", res)
+ enew!
+ endfunc
diff --git a/src/testdir/test_source.vim b/src/testdir/test_source.vim
new file mode 100644
index 0000000..a33d286
--- /dev/null
+++ b/src/testdir/test_source.vim
@@ -0,0 +1,38 @@
+" Tests for the :source command.
+
+func Test_source_autocmd()
+ call writefile([
+ \ 'let did_source = 1',
+ \ ], 'Xsourced')
+ au SourcePre *source* let did_source_pre = 1
+ au SourcePost *source* let did_source_post = 1
+
+ source Xsourced
+
+ call assert_equal(g:did_source, 1)
+ call assert_equal(g:did_source_pre, 1)
+ call assert_equal(g:did_source_post, 1)
+
+ call delete('Xsourced')
+ au! SourcePre
+ au! SourcePost
+ unlet g:did_source
+ unlet g:did_source_pre
+ unlet g:did_source_post
+endfunc
+
+func Test_source_cmd()
+ au SourceCmd *source* let did_source = expand('<afile>')
+ au SourcePre *source* let did_source_pre = 2
+ au SourcePost *source* let did_source_post = 2
+
+ source Xsourced
+
+ call assert_equal(g:did_source, 'Xsourced')
+ call assert_false(exists('g:did_source_pre'))
+ call assert_equal(g:did_source_post, 2)
+
+ au! SourceCmd
+ au! SourcePre
+ au! SourcePost
+endfunc
diff --git a/src/testdir/test_source_utf8.vim b/src/testdir/test_source_utf8.vim
new file mode 100644
index 0000000..e93ea29
--- /dev/null
+++ b/src/testdir/test_source_utf8.vim
@@ -0,0 +1,60 @@
+" Test the :source! command
+
+func Test_source_utf8()
+ " check that sourcing a script with 0x80 as second byte works
+ new
+ call setline(1, [':%s/àx/--à1234--/g', ':%s/Àx/--À1234--/g'])
+ write! Xscript
+ bwipe!
+ new
+ call setline(1, [' àx ', ' Àx '])
+ source! Xscript | echo
+ call assert_equal(' --à1234-- ', getline(1))
+ call assert_equal(' --À1234-- ', getline(2))
+ bwipe!
+ call delete('Xscript')
+endfunc
+
+func Test_source_latin()
+ " check that sourcing a latin1 script with a 0xc0 byte works
+ new
+ call setline(1, ["call feedkeys('r')", "call feedkeys('\xc0', 'xt')"])
+ write! Xscript
+ bwipe!
+ new
+ call setline(1, ['xxx'])
+ source Xscript
+ call assert_equal("\u00c0xx", getline(1))
+ bwipe!
+ call delete('Xscript')
+endfunc
+
+" Test for sourcing a file with CTRL-V's at the end of the line
+func Test_source_ctrl_v()
+ call writefile(['map __1 afirst',
+ \ 'map __2 asecond',
+ \ 'map __3 athird',
+ \ 'map __4 afourth',
+ \ 'map __5 afifth',
+ \ "map __1 asd\<C-V>",
+ \ "map __2 asd\<C-V>\<C-V>",
+ \ "map __3 asd\<C-V>\<C-V>",
+ \ "map __4 asd\<C-V>\<C-V>\<C-V>",
+ \ "map __5 asd\<C-V>\<C-V>\<C-V>",
+ \ ], 'Xtestfile')
+ source Xtestfile
+ enew!
+ exe "normal __1\<Esc>\<Esc>__2\<Esc>__3\<Esc>\<Esc>__4\<Esc>__5\<Esc>"
+ exe "%s/\<C-J>/0/g"
+ call assert_equal(['sd',
+ \ "map __2 asd\<Esc>secondsd\<Esc>sd0map __5 asd0fifth"],
+ \ getline(1, 2))
+
+ enew!
+ call delete('Xtestfile')
+ unmap __1
+ unmap __2
+ unmap __3
+ unmap __4
+ unmap __5
+endfunc
diff --git a/src/testdir/test_spell.vim b/src/testdir/test_spell.vim
new file mode 100644
index 0000000..76ad12e
--- /dev/null
+++ b/src/testdir/test_spell.vim
@@ -0,0 +1,887 @@
+" Test spell checking
+
+if !has('spell')
+ finish
+endif
+
+func TearDown()
+ set nospell
+ call delete('Xtest.aff')
+ call delete('Xtest.dic')
+ call delete('Xtest.latin1.add')
+ call delete('Xtest.latin1.add.spl')
+ call delete('Xtest.latin1.spl')
+ call delete('Xtest.latin1.sug')
+endfunc
+
+func Test_wrap_search()
+ new
+ call setline(1, ['The', '', 'A plong line with two zpelling mistakes', '', 'End'])
+ set spell wrapscan
+ normal ]s
+ call assert_equal('plong', expand('<cword>'))
+ normal ]s
+ call assert_equal('zpelling', expand('<cword>'))
+ normal ]s
+ call assert_equal('plong', expand('<cword>'))
+ bwipe!
+ set nospell
+endfunc
+
+func Test_curswant()
+ new
+ call setline(1, ['Another plong line', 'abcdefghijklmnopq'])
+ set spell wrapscan
+ normal 0]s
+ call assert_equal('plong', expand('<cword>'))
+ normal j
+ call assert_equal(9, getcurpos()[2])
+ normal 0[s
+ call assert_equal('plong', expand('<cword>'))
+ normal j
+ call assert_equal(9, getcurpos()[2])
+
+ normal 0]S
+ call assert_equal('plong', expand('<cword>'))
+ normal j
+ call assert_equal(9, getcurpos()[2])
+ normal 0[S
+ call assert_equal('plong', expand('<cword>'))
+ normal j
+ call assert_equal(9, getcurpos()[2])
+
+ normal 1G0
+ call assert_equal('plong', spellbadword()[0])
+ normal j
+ call assert_equal(9, getcurpos()[2])
+
+ bwipe!
+ set nospell
+endfunc
+
+func Test_z_equal_on_invalid_utf8_word()
+ split
+ set spell
+ call setline(1, "\xff")
+ norm z=
+ set nospell
+ bwipe!
+endfunc
+
+" Test spellbadword() with argument
+func Test_spellbadword()
+ set spell
+
+ call assert_equal(['bycycle', 'bad'], spellbadword('My bycycle.'))
+ call assert_equal(['another', 'caps'], spellbadword('A sentence. another sentence'))
+
+ set spelllang=en
+ call assert_equal(['', ''], spellbadword('centre'))
+ call assert_equal(['', ''], spellbadword('center'))
+ set spelllang=en_us
+ call assert_equal(['centre', 'local'], spellbadword('centre'))
+ call assert_equal(['', ''], spellbadword('center'))
+ set spelllang=en_gb
+ call assert_equal(['', ''], spellbadword('centre'))
+ call assert_equal(['center', 'local'], spellbadword('center'))
+
+ " Create a small word list to test that spellbadword('...')
+ " can return ['...', 'rare'].
+ e Xwords
+ insert
+foo
+foobar/?
+.
+ w!
+ mkspell! Xwords.spl Xwords
+ set spelllang=Xwords.spl
+ call assert_equal(['foobar', 'rare'], spellbadword('foo foobar'))
+
+ " Typo should not be detected without the 'spell' option.
+ set spelllang=en_gb nospell
+ call assert_equal(['', ''], spellbadword('centre'))
+ call assert_equal(['', ''], spellbadword('My bycycle.'))
+ call assert_equal(['', ''], spellbadword('A sentence. another sentence'))
+
+ call delete('Xwords.spl')
+ call delete('Xwords')
+ set spelllang&
+ set spell&
+endfunc
+
+func Test_spellreall()
+ new
+ set spell
+ call assert_fails('spellrepall', 'E752:')
+ call setline(1, ['A speling mistake. The same speling mistake.',
+ \ 'Another speling mistake.'])
+ call feedkeys(']s1z=', 'tx')
+ call assert_equal('A spelling mistake. The same speling mistake.', getline(1))
+ call assert_equal('Another speling mistake.', getline(2))
+ spellrepall
+ call assert_equal('A spelling mistake. The same spelling mistake.', getline(1))
+ call assert_equal('Another spelling mistake.', getline(2))
+ call assert_fails('spellrepall', 'E753:')
+ set spell&
+ bwipe!
+endfunc
+
+func Test_spellinfo()
+ new
+
+ set enc=latin1 spell spelllang=en
+ call assert_match("^\nfile: .*/runtime/spell/en.latin1.spl\n$", execute('spellinfo'))
+
+ set enc=cp1250 spell spelllang=en
+ call assert_match("^\nfile: .*/runtime/spell/en.ascii.spl\n$", execute('spellinfo'))
+
+ set enc=utf-8 spell spelllang=en
+ call assert_match("^\nfile: .*/runtime/spell/en.utf-8.spl\n$", execute('spellinfo'))
+
+ set enc=latin1 spell spelllang=en_us,en_nz
+ call assert_match("^\n" .
+ \ "file: .*/runtime/spell/en.latin1.spl\n" .
+ \ "file: .*/runtime/spell/en.latin1.spl\n$", execute('spellinfo'))
+
+ set spell spelllang=
+ call assert_fails('spellinfo', 'E756:')
+
+ set nospell spelllang=en
+ call assert_fails('spellinfo', 'E756:')
+
+ set enc& spell& spelllang&
+ bwipe
+endfunc
+
+func Test_zz_basic()
+ call LoadAffAndDic(g:test_data_aff1, g:test_data_dic1)
+ call RunGoodBad("wrong OK puts. Test the end",
+ \ "bad: inputs comment ok Ok. test d\xE9\xF4l end the",
+ \["Comment", "deol", "d\xE9\xF4r", "input", "OK", "output", "outputs", "outtest", "put", "puts",
+ \ "test", "testen", "testn", "the end", "uk", "wrong"],
+ \[
+ \ ["bad", ["put", "uk", "OK"]],
+ \ ["inputs", ["input", "puts", "outputs"]],
+ \ ["comment", ["Comment", "outtest", "the end"]],
+ \ ["ok", ["OK", "uk", "put"]],
+ \ ["Ok", ["OK", "Uk", "Put"]],
+ \ ["test", ["Test", "testn", "testen"]],
+ \ ["d\xE9\xF4l", ["deol", "d\xE9\xF4r", "test"]],
+ \ ["end", ["put", "uk", "test"]],
+ \ ["the", ["put", "uk", "test"]],
+ \ ]
+ \ )
+
+ call assert_equal("gebletegek", soundfold('goobledygoook'))
+ call assert_equal("kepereneven", soundfold('kóopërÿnôven'))
+ call assert_equal("everles gesvets etele", soundfold('oeverloos gezwets edale'))
+endfunc
+
+" Postponed prefixes
+func Test_zz_prefixes()
+ call LoadAffAndDic(g:test_data_aff2, g:test_data_dic1)
+ call RunGoodBad("puts",
+ \ "bad: inputs comment ok Ok end the. test d\xE9\xF4l",
+ \ ["Comment", "deol", "d\xE9\xF4r", "OK", "put", "input", "output", "puts", "outputs", "test", "outtest", "testen", "testn", "the end", "uk", "wrong"],
+ \ [
+ \ ["bad", ["put", "uk", "OK"]],
+ \ ["inputs", ["input", "puts", "outputs"]],
+ \ ["comment", ["Comment"]],
+ \ ["ok", ["OK", "uk", "put"]],
+ \ ["Ok", ["OK", "Uk", "Put"]],
+ \ ["end", ["put", "uk", "deol"]],
+ \ ["the", ["put", "uk", "test"]],
+ \ ["test", ["Test", "testn", "testen"]],
+ \ ["d\xE9\xF4l", ["deol", "d\xE9\xF4r", "test"]],
+ \ ])
+endfunc
+
+"Compound words
+func Test_zz_compound()
+ call LoadAffAndDic(g:test_data_aff3, g:test_data_dic3)
+ call RunGoodBad("foo m\xEF foobar foofoobar barfoo barbarfoo",
+ \ "bad: bar la foom\xEF barm\xEF m\xEFfoo m\xEFbar m\xEFm\xEF lala m\xEFla lam\xEF foola labar",
+ \ ["foo", "m\xEF"],
+ \ [
+ \ ["bad", ["foo", "m\xEF"]],
+ \ ["bar", ["barfoo", "foobar", "foo"]],
+ \ ["la", ["m\xEF", "foo"]],
+ \ ["foom\xEF", ["foo m\xEF", "foo", "foofoo"]],
+ \ ["barm\xEF", ["barfoo", "m\xEF", "barbar"]],
+ \ ["m\xEFfoo", ["m\xEF foo", "foo", "foofoo"]],
+ \ ["m\xEFbar", ["foobar", "barbar", "m\xEF"]],
+ \ ["m\xEFm\xEF", ["m\xEF m\xEF", "m\xEF"]],
+ \ ["lala", []],
+ \ ["m\xEFla", ["m\xEF", "m\xEF m\xEF"]],
+ \ ["lam\xEF", ["m\xEF", "m\xEF m\xEF"]],
+ \ ["foola", ["foo", "foobar", "foofoo"]],
+ \ ["labar", ["barbar", "foobar"]],
+ \ ])
+
+ call LoadAffAndDic(g:test_data_aff4, g:test_data_dic4)
+ call RunGoodBad("word util bork prebork start end wordutil wordutils pro-ok bork borkbork borkborkbork borkborkborkbork borkborkborkborkbork tomato tomatotomato startend startword startwordword startwordend startwordwordend startwordwordwordend prebork preborkbork preborkborkbork nouword",
+ \ "bad: wordutilize pro borkborkborkborkborkbork tomatotomatotomato endstart endend startstart wordend wordstart preborkprebork preborkpreborkbork startwordwordwordwordend borkpreborkpreborkbork utilsbork startnouword",
+ \ ["bork", "prebork", "end", "pro-ok", "start", "tomato", "util", "utilize", "utils", "word", "nouword"],
+ \ [
+ \ ["bad", ["end", "bork", "word"]],
+ \ ["wordutilize", ["word utilize", "wordutils", "wordutil"]],
+ \ ["pro", ["bork", "word", "end"]],
+ \ ["borkborkborkborkborkbork", ["bork borkborkborkborkbork", "borkbork borkborkborkbork", "borkborkbork borkborkbork"]],
+ \ ["tomatotomatotomato", ["tomato tomatotomato", "tomatotomato tomato", "tomato tomato tomato"]],
+ \ ["endstart", ["end start", "start"]],
+ \ ["endend", ["end end", "end"]],
+ \ ["startstart", ["start start"]],
+ \ ["wordend", ["word end", "word", "wordword"]],
+ \ ["wordstart", ["word start", "bork start"]],
+ \ ["preborkprebork", ["prebork prebork", "preborkbork", "preborkborkbork"]],
+ \ ["preborkpreborkbork", ["prebork preborkbork", "preborkborkbork", "preborkborkborkbork"]],
+ \ ["startwordwordwordwordend", ["startwordwordwordword end", "startwordwordwordword", "start wordwordwordword end"]],
+ \ ["borkpreborkpreborkbork", ["bork preborkpreborkbork", "bork prebork preborkbork", "bork preborkprebork bork"]],
+ \ ["utilsbork", ["utilbork", "utils bork", "util bork"]],
+ \ ["startnouword", ["start nouword", "startword", "startborkword"]],
+ \ ])
+
+endfunc
+
+"Test affix flags with two characters
+func Test_zz_affix()
+ call LoadAffAndDic(g:test_data_aff5, g:test_data_dic5)
+ call RunGoodBad("fooa1 fooa\xE9 bar prebar barbork prebarbork startprebar start end startend startmiddleend nouend",
+ \ "bad: foo fooa2 prabar probarbirk middle startmiddle middleend endstart startprobar startnouend",
+ \ ["bar", "barbork", "end", "fooa1", "fooa\xE9", "nouend", "prebar", "prebarbork", "start"],
+ \ [
+ \ ["bad", ["bar", "end", "fooa1"]],
+ \ ["foo", ["fooa1", "fooa\xE9", "bar"]],
+ \ ["fooa2", ["fooa1", "fooa\xE9", "bar"]],
+ \ ["prabar", ["prebar", "bar", "bar bar"]],
+ \ ["probarbirk", ["prebarbork"]],
+ \ ["middle", []],
+ \ ["startmiddle", ["startmiddleend", "startmiddlebar"]],
+ \ ["middleend", []],
+ \ ["endstart", ["end start", "start"]],
+ \ ["startprobar", ["startprebar", "start prebar", "startbar"]],
+ \ ["startnouend", ["start nouend", "startend"]],
+ \ ])
+
+ call LoadAffAndDic(g:test_data_aff6, g:test_data_dic6)
+ call RunGoodBad("meea1 meea\xE9 bar prebar barbork prebarbork leadprebar lead end leadend leadmiddleend",
+ \ "bad: mee meea2 prabar probarbirk middle leadmiddle middleend endlead leadprobar",
+ \ ["bar", "barbork", "end", "lead", "meea1", "meea\xE9", "prebar", "prebarbork"],
+ \ [
+ \ ["bad", ["bar", "end", "lead"]],
+ \ ["mee", ["meea1", "meea\xE9", "bar"]],
+ \ ["meea2", ["meea1", "meea\xE9", "lead"]],
+ \ ["prabar", ["prebar", "bar", "leadbar"]],
+ \ ["probarbirk", ["prebarbork"]],
+ \ ["middle", []],
+ \ ["leadmiddle", ["leadmiddleend", "leadmiddlebar"]],
+ \ ["middleend", []],
+ \ ["endlead", ["end lead", "lead", "end end"]],
+ \ ["leadprobar", ["leadprebar", "lead prebar", "leadbar"]],
+ \ ])
+
+ call LoadAffAndDic(g:test_data_aff7, g:test_data_dic7)
+ call RunGoodBad("meea1 meea\xE9 bar prebar barmeat prebarmeat leadprebar lead tail leadtail leadmiddletail",
+ \ "bad: mee meea2 prabar probarmaat middle leadmiddle middletail taillead leadprobar",
+ \ ["bar", "barmeat", "lead", "meea1", "meea\xE9", "prebar", "prebarmeat", "tail"],
+ \ [
+ \ ["bad", ["bar", "lead", "tail"]],
+ \ ["mee", ["meea1", "meea\xE9", "bar"]],
+ \ ["meea2", ["meea1", "meea\xE9", "lead"]],
+ \ ["prabar", ["prebar", "bar", "leadbar"]],
+ \ ["probarmaat", ["prebarmeat"]],
+ \ ["middle", []],
+ \ ["leadmiddle", ["leadmiddlebar"]],
+ \ ["middletail", []],
+ \ ["taillead", ["tail lead", "tail"]],
+ \ ["leadprobar", ["leadprebar", "lead prebar", "leadbar"]],
+ \ ])
+endfunc
+
+func Test_zz_NOSLITSUGS()
+ call LoadAffAndDic(g:test_data_aff8, g:test_data_dic8)
+ call RunGoodBad("foo bar faabar", "bad: foobar barfoo",
+ \ ["bar", "faabar", "foo"],
+ \ [
+ \ ["bad", ["bar", "foo"]],
+ \ ["foobar", ["faabar", "foo bar", "bar"]],
+ \ ["barfoo", ["bar foo", "bar", "foo"]],
+ \ ])
+endfunc
+
+" Numbers
+func Test_zz_Numbers()
+ call LoadAffAndDic(g:test_data_aff9, g:test_data_dic9)
+ call RunGoodBad("0b1011 0777 1234 0x01ff", "",
+ \ ["bar", "foo"],
+ \ [
+ \ ])
+endfunc
+
+function FirstSpellWord()
+ call feedkeys("/^start:\n", 'tx')
+ normal ]smm
+ let [str, a] = spellbadword()
+ return str
+endfunc
+
+function SecondSpellWord()
+ normal `m]s
+ let [str, a] = spellbadword()
+ return str
+endfunc
+
+"Test with SAL instead of SOFO items; test automatic reloading
+func Test_zz_sal_and_addition()
+ set enc=latin1
+ set spellfile=
+ call writefile(g:test_data_dic1, "Xtest.dic")
+ call writefile(g:test_data_aff_sal, "Xtest.aff")
+ mkspell! Xtest Xtest
+ set spl=Xtest.latin1.spl spell
+ call assert_equal('kbltykk', soundfold('goobledygoook'))
+ call assert_equal('kprnfn', soundfold('kóopërÿnôven'))
+ call assert_equal('*fls kswts tl', soundfold('oeverloos gezwets edale'))
+
+ "also use an addition file
+ call writefile(["/regions=usgbnz", "elequint/2", "elekwint/3"], "Xtest.latin1.add")
+ mkspell! Xtest.latin1.add.spl Xtest.latin1.add
+
+ bwipe!
+ call setline(1, ["start: elequint test elekwint test elekwent asdf"])
+
+ set spellfile=Xtest.latin1.add
+ call assert_equal("elekwent", FirstSpellWord())
+
+ set spl=Xtest_us.latin1.spl
+ call assert_equal("elequint", FirstSpellWord())
+ call assert_equal("elekwint", SecondSpellWord())
+
+ set spl=Xtest_gb.latin1.spl
+ call assert_equal("elekwint", FirstSpellWord())
+ call assert_equal("elekwent", SecondSpellWord())
+
+ set spl=Xtest_nz.latin1.spl
+ call assert_equal("elequint", FirstSpellWord())
+ call assert_equal("elekwent", SecondSpellWord())
+
+ set spl=Xtest_ca.latin1.spl
+ call assert_equal("elequint", FirstSpellWord())
+ call assert_equal("elekwint", SecondSpellWord())
+endfunc
+
+func Test_region_error()
+ messages clear
+ call writefile(["/regions=usgbnz", "elequint/0"], "Xtest.latin1.add")
+ mkspell! Xtest.latin1.add.spl Xtest.latin1.add
+ call assert_match('Invalid region nr in Xtest.latin1.add line 2: 0', execute('messages'))
+ call delete('Xtest.latin1.add')
+ call delete('Xtest.latin1.add.spl')
+endfunc
+
+" Check using z= in new buffer (crash fixed by patch 7.4a.028).
+func Test_zeq_crash()
+ new
+ set maxmem=512 spell
+ call feedkeys('iasdz=:\"', 'tx')
+
+ bwipe!
+endfunc
+
+func LoadAffAndDic(aff_contents, dic_contents)
+ set enc=latin1
+ set spellfile=
+ call writefile(a:aff_contents, "Xtest.aff")
+ call writefile(a:dic_contents, "Xtest.dic")
+ " Generate a .spl file from a .dic and .aff file.
+ mkspell! Xtest Xtest
+ " use that spell file
+ set spl=Xtest.latin1.spl spell
+endfunc
+
+func ListWords()
+ spelldump
+ %yank
+ quit
+ return split(@", "\n")
+endfunc
+
+func TestGoodBadBase()
+ exe '1;/^good:'
+ normal 0f:]s
+ let prevbad = ''
+ let result = []
+ while 1
+ let [bad, a] = spellbadword()
+ if bad == '' || bad == prevbad || bad == 'badend'
+ break
+ endif
+ let prevbad = bad
+ let lst = spellsuggest(bad, 3)
+ normal mm
+
+ call add(result, [bad, lst])
+ normal `m]s
+ endwhile
+ return result
+endfunc
+
+func RunGoodBad(good, bad, expected_words, expected_bad_words)
+ bwipe!
+ call setline(1, ["good: ", a:good, a:bad, " badend "])
+ let words = ListWords()
+ call assert_equal(a:expected_words, words[1:-1])
+ let bad_words = TestGoodBadBase()
+ call assert_equal(a:expected_bad_words, bad_words)
+ bwipe!
+endfunc
+
+let g:test_data_aff1 = [
+ \"SET ISO8859-1",
+ \"TRY esianrtolcdugmphbyfvkwjkqxz-\xEB\xE9\xE8\xEA\xEF\xEE\xE4\xE0\xE2\xF6\xFC\xFB'ESIANRTOLCDUGMPHBYFVKWJKQXZ",
+ \"",
+ \"FOL \xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xDF\xFF",
+ \"LOW \xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xDF\xFF",
+ \"UPP \xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF\xD0\xD1\xD2\xD3\xD4\xD5\xD6\xD8\xD9\xDA\xDB\xDC\xDD\xDE\xDF\xFF",
+ \"",
+ \"SOFOFROM abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xDF\xFF\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF\xD0\xD1\xD2\xD3\xD4\xD5\xD6\xD8\xD9\xDA\xDB\xDC\xDD\xDE\xBF",
+ \"SOFOTO ebctefghejklnnepkrstevvkesebctefghejklnnepkrstevvkeseeeeeeeceeeeeeeedneeeeeeeeeeepseeeeeeeeceeeeeeeedneeeeeeeeeeep?",
+ \"",
+ \"MIDWORD\t'-",
+ \"",
+ \"KEP =",
+ \"RAR ?",
+ \"BAD !",
+ \"",
+ \"PFX I N 1",
+ \"PFX I 0 in .",
+ \"",
+ \"PFX O Y 1",
+ \"PFX O 0 out .",
+ \"",
+ \"SFX S Y 2",
+ \"SFX S 0 s [^s]",
+ \"SFX S 0 es s",
+ \"",
+ \"SFX N N 3",
+ \"SFX N 0 en [^n]",
+ \"SFX N 0 nen n",
+ \"SFX N 0 n .",
+ \"",
+ \"REP 3",
+ \"REP g ch",
+ \"REP ch g",
+ \"REP svp s.v.p.",
+ \"",
+ \"MAP 9",
+ \"MAP a\xE0\xE1\xE2\xE3\xE4\xE5",
+ \"MAP e\xE8\xE9\xEA\xEB",
+ \"MAP i\xEC\xED\xEE\xEF",
+ \"MAP o\xF2\xF3\xF4\xF5\xF6",
+ \"MAP u\xF9\xFA\xFB\xFC",
+ \"MAP n\xF1",
+ \"MAP c\xE7",
+ \"MAP y\xFF\xFD",
+ \"MAP s\xDF",
+ \ ]
+let g:test_data_dic1 = [
+ \"123456",
+ \"test/NO",
+ \"# comment",
+ \"wrong",
+ \"Comment",
+ \"OK",
+ \"uk",
+ \"put/ISO",
+ \"the end",
+ \"deol",
+ \"d\xE9\xF4r",
+ \ ]
+let g:test_data_aff2 = [
+ \"SET ISO8859-1",
+ \"",
+ \"FOL \xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xDF\xFF",
+ \"LOW \xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xDF\xFF",
+ \"UPP \xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF\xD0\xD1\xD2\xD3\xD4\xD5\xD6\xD8\xD9\xDA\xDB\xDC\xDD\xDE\xDF\xFF",
+ \"",
+ \"PFXPOSTPONE",
+ \"",
+ \"MIDWORD\t'-",
+ \"",
+ \"KEP =",
+ \"RAR ?",
+ \"BAD !",
+ \"",
+ \"PFX I N 1",
+ \"PFX I 0 in .",
+ \"",
+ \"PFX O Y 1",
+ \"PFX O 0 out [a-z]",
+ \"",
+ \"SFX S Y 2",
+ \"SFX S 0 s [^s]",
+ \"SFX S 0 es s",
+ \"",
+ \"SFX N N 3",
+ \"SFX N 0 en [^n]",
+ \"SFX N 0 nen n",
+ \"SFX N 0 n .",
+ \"",
+ \"REP 3",
+ \"REP g ch",
+ \"REP ch g",
+ \"REP svp s.v.p.",
+ \"",
+ \"MAP 9",
+ \"MAP a\xE0\xE1\xE2\xE3\xE4\xE5",
+ \"MAP e\xE8\xE9\xEA\xEB",
+ \"MAP i\xEC\xED\xEE\xEF",
+ \"MAP o\xF2\xF3\xF4\xF5\xF6",
+ \"MAP u\xF9\xFA\xFB\xFC",
+ \"MAP n\xF1",
+ \"MAP c\xE7",
+ \"MAP y\xFF\xFD",
+ \"MAP s\xDF",
+ \ ]
+let g:test_data_aff3 = [
+ \"SET ISO8859-1",
+ \"",
+ \"COMPOUNDMIN 3",
+ \"COMPOUNDRULE m*",
+ \"NEEDCOMPOUND x",
+ \ ]
+let g:test_data_dic3 = [
+ \"1234",
+ \"foo/m",
+ \"bar/mx",
+ \"m\xEF/m",
+ \"la/mx",
+ \ ]
+let g:test_data_aff4 = [
+ \"SET ISO8859-1",
+ \"",
+ \"FOL \xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xDF\xFF",
+ \"LOW \xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xDF\xFF",
+ \"UPP \xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF\xD0\xD1\xD2\xD3\xD4\xD5\xD6\xD8\xD9\xDA\xDB\xDC\xDD\xDE\xDF\xFF",
+ \"",
+ \"COMPOUNDRULE m+",
+ \"COMPOUNDRULE sm*e",
+ \"COMPOUNDRULE sm+",
+ \"COMPOUNDMIN 3",
+ \"COMPOUNDWORDMAX 3",
+ \"COMPOUNDFORBIDFLAG t",
+ \"",
+ \"COMPOUNDSYLMAX 5",
+ \"SYLLABLE a\xE1e\xE9i\xEDo\xF3\xF6\xF5u\xFA\xFC\xFBy/aa/au/ea/ee/ei/ie/oa/oe/oo/ou/uu/ui",
+ \"",
+ \"MAP 9",
+ \"MAP a\xE0\xE1\xE2\xE3\xE4\xE5",
+ \"MAP e\xE8\xE9\xEA\xEB",
+ \"MAP i\xEC\xED\xEE\xEF",
+ \"MAP o\xF2\xF3\xF4\xF5\xF6",
+ \"MAP u\xF9\xFA\xFB\xFC",
+ \"MAP n\xF1",
+ \"MAP c\xE7",
+ \"MAP y\xFF\xFD",
+ \"MAP s\xDF",
+ \"",
+ \"NEEDAFFIX x",
+ \"",
+ \"PFXPOSTPONE",
+ \"",
+ \"MIDWORD '-",
+ \"",
+ \"SFX q N 1",
+ \"SFX q 0 -ok .",
+ \"",
+ \"SFX a Y 2",
+ \"SFX a 0 s .",
+ \"SFX a 0 ize/t .",
+ \"",
+ \"PFX p N 1",
+ \"PFX p 0 pre .",
+ \"",
+ \"PFX P N 1",
+ \"PFX P 0 nou .",
+ \ ]
+let g:test_data_dic4 = [
+ \"1234",
+ \"word/mP",
+ \"util/am",
+ \"pro/xq",
+ \"tomato/m",
+ \"bork/mp",
+ \"start/s",
+ \"end/e",
+ \ ]
+let g:test_data_aff5 = [
+ \"SET ISO8859-1",
+ \"",
+ \"FLAG long",
+ \"",
+ \"NEEDAFFIX !!",
+ \"",
+ \"COMPOUNDRULE ssmm*ee",
+ \"",
+ \"NEEDCOMPOUND xx",
+ \"COMPOUNDPERMITFLAG pp",
+ \"",
+ \"SFX 13 Y 1",
+ \"SFX 13 0 bork .",
+ \"",
+ \"SFX a1 Y 1",
+ \"SFX a1 0 a1 .",
+ \"",
+ \"SFX a\xE9 Y 1",
+ \"SFX a\xE9 0 a\xE9 .",
+ \"",
+ \"PFX zz Y 1",
+ \"PFX zz 0 pre/pp .",
+ \"",
+ \"PFX yy Y 1",
+ \"PFX yy 0 nou .",
+ \ ]
+let g:test_data_dic5 = [
+ \"1234",
+ \"foo/a1a\xE9!!",
+ \"bar/zz13ee",
+ \"start/ss",
+ \"end/eeyy",
+ \"middle/mmxx",
+ \ ]
+let g:test_data_aff6 = [
+ \"SET ISO8859-1",
+ \"",
+ \"FLAG caplong",
+ \"",
+ \"NEEDAFFIX A!",
+ \"",
+ \"COMPOUNDRULE sMm*Ee",
+ \"",
+ \"NEEDCOMPOUND Xx",
+ \"",
+ \"COMPOUNDPERMITFLAG p",
+ \"",
+ \"SFX N3 Y 1",
+ \"SFX N3 0 bork .",
+ \"",
+ \"SFX A1 Y 1",
+ \"SFX A1 0 a1 .",
+ \"",
+ \"SFX A\xE9 Y 1",
+ \"SFX A\xE9 0 a\xE9 .",
+ \"",
+ \"PFX Zz Y 1",
+ \"PFX Zz 0 pre/p .",
+ \ ]
+let g:test_data_dic6 = [
+ \"1234",
+ \"mee/A1A\xE9A!",
+ \"bar/ZzN3Ee",
+ \"lead/s",
+ \"end/Ee",
+ \"middle/MmXx",
+ \ ]
+let g:test_data_aff7 = [
+ \"SET ISO8859-1",
+ \"",
+ \"FLAG num",
+ \"",
+ \"NEEDAFFIX 9999",
+ \"",
+ \"COMPOUNDRULE 2,77*123",
+ \"",
+ \"NEEDCOMPOUND 1",
+ \"COMPOUNDPERMITFLAG 432",
+ \"",
+ \"SFX 61003 Y 1",
+ \"SFX 61003 0 meat .",
+ \"",
+ \"SFX 391 Y 1",
+ \"SFX 391 0 a1 .",
+ \"",
+ \"SFX 111 Y 1",
+ \"SFX 111 0 a\xE9 .",
+ \"",
+ \"PFX 17 Y 1",
+ \"PFX 17 0 pre/432 .",
+ \ ]
+let g:test_data_dic7 = [
+ \"1234",
+ \"mee/391,111,9999",
+ \"bar/17,61003,123",
+ \"lead/2",
+ \"tail/123",
+ \"middle/77,1",
+ \ ]
+let g:test_data_aff8 = [
+ \"SET ISO8859-1",
+ \"",
+ \"NOSPLITSUGS",
+ \ ]
+let g:test_data_dic8 = [
+ \"1234",
+ \"foo",
+ \"bar",
+ \"faabar",
+ \ ]
+let g:test_data_aff9 = [
+ \ ]
+let g:test_data_dic9 = [
+ \"1234",
+ \"foo",
+ \"bar",
+ \ ]
+let g:test_data_aff_sal = [
+ \"SET ISO8859-1",
+ \"TRY esianrtolcdugmphbyfvkwjkqxz-\xEB\xE9\xE8\xEA\xEF\xEE\xE4\xE0\xE2\xF6\xFC\xFB'ESIANRTOLCDUGMPHBYFVKWJKQXZ",
+ \"",
+ \"FOL \xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xDF\xFF",
+ \"LOW \xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xDF\xFF",
+ \"UPP \xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF\xD0\xD1\xD2\xD3\xD4\xD5\xD6\xD8\xD9\xDA\xDB\xDC\xDD\xDE\xDF\xFF",
+ \"",
+ \"MIDWORD\t'-",
+ \"",
+ \"KEP =",
+ \"RAR ?",
+ \"BAD !",
+ \"",
+ \"PFX I N 1",
+ \"PFX I 0 in .",
+ \"",
+ \"PFX O Y 1",
+ \"PFX O 0 out .",
+ \"",
+ \"SFX S Y 2",
+ \"SFX S 0 s [^s]",
+ \"SFX S 0 es s",
+ \"",
+ \"SFX N N 3",
+ \"SFX N 0 en [^n]",
+ \"SFX N 0 nen n",
+ \"SFX N 0 n .",
+ \"",
+ \"REP 3",
+ \"REP g ch",
+ \"REP ch g",
+ \"REP svp s.v.p.",
+ \"",
+ \"MAP 9",
+ \"MAP a\xE0\xE1\xE2\xE3\xE4\xE5",
+ \"MAP e\xE8\xE9\xEA\xEB",
+ \"MAP i\xEC\xED\xEE\xEF",
+ \"MAP o\xF2\xF3\xF4\xF5\xF6",
+ \"MAP u\xF9\xFA\xFB\xFC",
+ \"MAP n\xF1",
+ \"MAP c\xE7",
+ \"MAP y\xFF\xFD",
+ \"MAP s\xDF",
+ \"",
+ \"SAL AH(AEIOUY)-^ *H",
+ \"SAL AR(AEIOUY)-^ *R",
+ \"SAL A(HR)^ *",
+ \"SAL A^ *",
+ \"SAL AH(AEIOUY)- H",
+ \"SAL AR(AEIOUY)- R",
+ \"SAL A(HR) _",
+ \"SAL \xC0^ *",
+ \"SAL \xC5^ *",
+ \"SAL BB- _",
+ \"SAL B B",
+ \"SAL CQ- _",
+ \"SAL CIA X",
+ \"SAL CH X",
+ \"SAL C(EIY)- S",
+ \"SAL CK K",
+ \"SAL COUGH^ KF",
+ \"SAL CC< C",
+ \"SAL C K",
+ \"SAL DG(EIY) K",
+ \"SAL DD- _",
+ \"SAL D T",
+ \"SAL \xC9< E",
+ \"SAL EH(AEIOUY)-^ *H",
+ \"SAL ER(AEIOUY)-^ *R",
+ \"SAL E(HR)^ *",
+ \"SAL ENOUGH^$ *NF",
+ \"SAL E^ *",
+ \"SAL EH(AEIOUY)- H",
+ \"SAL ER(AEIOUY)- R",
+ \"SAL E(HR) _",
+ \"SAL FF- _",
+ \"SAL F F",
+ \"SAL GN^ N",
+ \"SAL GN$ N",
+ \"SAL GNS$ NS",
+ \"SAL GNED$ N",
+ \"SAL GH(AEIOUY)- K",
+ \"SAL GH _",
+ \"SAL GG9 K",
+ \"SAL G K",
+ \"SAL H H",
+ \"SAL IH(AEIOUY)-^ *H",
+ \"SAL IR(AEIOUY)-^ *R",
+ \"SAL I(HR)^ *",
+ \"SAL I^ *",
+ \"SAL ING6 N",
+ \"SAL IH(AEIOUY)- H",
+ \"SAL IR(AEIOUY)- R",
+ \"SAL I(HR) _",
+ \"SAL J K",
+ \"SAL KN^ N",
+ \"SAL KK- _",
+ \"SAL K K",
+ \"SAL LAUGH^ LF",
+ \"SAL LL- _",
+ \"SAL L L",
+ \"SAL MB$ M",
+ \"SAL MM M",
+ \"SAL M M",
+ \"SAL NN- _",
+ \"SAL N N",
+ \"SAL OH(AEIOUY)-^ *H",
+ \"SAL OR(AEIOUY)-^ *R",
+ \"SAL O(HR)^ *",
+ \"SAL O^ *",
+ \"SAL OH(AEIOUY)- H",
+ \"SAL OR(AEIOUY)- R",
+ \"SAL O(HR) _",
+ \"SAL PH F",
+ \"SAL PN^ N",
+ \"SAL PP- _",
+ \"SAL P P",
+ \"SAL Q K",
+ \"SAL RH^ R",
+ \"SAL ROUGH^ RF",
+ \"SAL RR- _",
+ \"SAL R R",
+ \"SAL SCH(EOU)- SK",
+ \"SAL SC(IEY)- S",
+ \"SAL SH X",
+ \"SAL SI(AO)- X",
+ \"SAL SS- _",
+ \"SAL S S",
+ \"SAL TI(AO)- X",
+ \"SAL TH @",
+ \"SAL TCH-- _",
+ \"SAL TOUGH^ TF",
+ \"SAL TT- _",
+ \"SAL T T",
+ \"SAL UH(AEIOUY)-^ *H",
+ \"SAL UR(AEIOUY)-^ *R",
+ \"SAL U(HR)^ *",
+ \"SAL U^ *",
+ \"SAL UH(AEIOUY)- H",
+ \"SAL UR(AEIOUY)- R",
+ \"SAL U(HR) _",
+ \"SAL V^ W",
+ \"SAL V F",
+ \"SAL WR^ R",
+ \"SAL WH^ W",
+ \"SAL W(AEIOU)- W",
+ \"SAL X^ S",
+ \"SAL X KS",
+ \"SAL Y(AEIOU)- Y",
+ \"SAL ZZ- _",
+ \"SAL Z S",
+ \ ]
diff --git a/src/testdir/test_startup.vim b/src/testdir/test_startup.vim
new file mode 100644
index 0000000..16b202f
--- /dev/null
+++ b/src/testdir/test_startup.vim
@@ -0,0 +1,539 @@
+" Tests for startup.
+
+source shared.vim
+
+" Check that loading startup.vim works.
+func Test_startup_script()
+ set compatible
+ source $VIMRUNTIME/defaults.vim
+
+ call assert_equal(0, &compatible)
+endfunc
+
+" Verify the order in which plugins are loaded:
+" 1. plugins in non-after directories
+" 2. packages
+" 3. plugins in after directories
+func Test_after_comes_later()
+ if !has('packages')
+ return
+ endif
+ let before = [
+ \ 'set nocp viminfo+=nviminfo',
+ \ 'set guioptions+=M',
+ \ 'let $HOME = "/does/not/exist"',
+ \ 'set loadplugins',
+ \ 'set rtp=Xhere,Xafter,Xanother',
+ \ 'set packpath=Xhere,Xafter',
+ \ 'set nomore',
+ \ 'let g:sequence = ""',
+ \ ]
+ let after = [
+ \ 'redir! > Xtestout',
+ \ 'scriptnames',
+ \ 'redir END',
+ \ 'redir! > Xsequence',
+ \ 'echo g:sequence',
+ \ 'redir END',
+ \ 'quit',
+ \ ]
+ call mkdir('Xhere/plugin', 'p')
+ call writefile(['let g:sequence .= "here "'], 'Xhere/plugin/here.vim')
+ call mkdir('Xanother/plugin', 'p')
+ call writefile(['let g:sequence .= "another "'], 'Xanother/plugin/another.vim')
+ call mkdir('Xhere/pack/foo/start/foobar/plugin', 'p')
+ call writefile(['let g:sequence .= "pack "'], 'Xhere/pack/foo/start/foobar/plugin/foo.vim')
+
+ call mkdir('Xafter/plugin', 'p')
+ call writefile(['let g:sequence .= "after "'], 'Xafter/plugin/later.vim')
+
+ if RunVim(before, after, '')
+
+ let lines = readfile('Xtestout')
+ let expected = ['Xbefore.vim', 'here.vim', 'another.vim', 'foo.vim', 'later.vim', 'Xafter.vim']
+ let found = []
+ for line in lines
+ for one in expected
+ if line =~ one
+ call add(found, one)
+ endif
+ endfor
+ endfor
+ call assert_equal(expected, found)
+ endif
+
+ call assert_equal('here another pack after', substitute(join(readfile('Xsequence', 1), ''), '\s\+$', '', ''))
+
+ call delete('Xtestout')
+ call delete('Xsequence')
+ call delete('Xhere', 'rf')
+ call delete('Xanother', 'rf')
+ call delete('Xafter', 'rf')
+endfunc
+
+func Test_pack_in_rtp_when_plugins_run()
+ if !has('packages')
+ return
+ endif
+ let before = [
+ \ 'set nocp viminfo+=nviminfo',
+ \ 'set guioptions+=M',
+ \ 'let $HOME = "/does/not/exist"',
+ \ 'set loadplugins',
+ \ 'set rtp=Xhere',
+ \ 'set packpath=Xhere',
+ \ 'set nomore',
+ \ ]
+ let after = [
+ \ 'quit',
+ \ ]
+ call mkdir('Xhere/plugin', 'p')
+ call writefile(['redir! > Xtestout', 'silent set runtimepath?', 'silent! call foo#Trigger()', 'redir END'], 'Xhere/plugin/here.vim')
+ call mkdir('Xhere/pack/foo/start/foobar/autoload', 'p')
+ call writefile(['function! foo#Trigger()', 'echo "autoloaded foo"', 'endfunction'], 'Xhere/pack/foo/start/foobar/autoload/foo.vim')
+
+ if RunVim(before, after, '')
+
+ let lines = filter(readfile('Xtestout'), '!empty(v:val)')
+ call assert_match('Xhere[/\\]pack[/\\]foo[/\\]start[/\\]foobar', get(lines, 0))
+ call assert_match('autoloaded foo', get(lines, 1))
+ endif
+
+ call delete('Xtestout')
+ call delete('Xhere', 'rf')
+endfunc
+
+func Test_help_arg()
+ if !has('unix') && has('gui')
+ " this doesn't work with gvim on MS-Windows
+ return
+ endif
+ if RunVim([], [], '--help >Xtestout')
+ let lines = readfile('Xtestout')
+ call assert_true(len(lines) > 20)
+ call assert_match('Vi IMproved', lines[0])
+
+ " check if couple of lines are there
+ let found = []
+ for line in lines
+ if line =~ '-R.*Readonly mode'
+ call add(found, 'Readonly mode')
+ endif
+ " Watch out for a second --version line in the Gnome version.
+ if line =~ '--version.*Print version information and exit'
+ call add(found, "--version")
+ endif
+ endfor
+ call assert_equal(['Readonly mode', '--version'], found)
+ endif
+ call delete('Xtestout')
+endfunc
+
+func Test_compatible_args()
+ let after = [
+ \ 'call writefile([string(&compatible)], "Xtestout")',
+ \ 'set viminfo+=nviminfo',
+ \ 'quit',
+ \ ]
+ if RunVim([], after, '-C')
+ let lines = readfile('Xtestout')
+ call assert_equal('1', lines[0])
+ endif
+
+ if RunVim([], after, '-N')
+ let lines = readfile('Xtestout')
+ call assert_equal('0', lines[0])
+ endif
+
+ call delete('Xtestout')
+endfunc
+
+" Test the -o[N] and -O[N] arguments to open N windows split
+" horizontally or vertically.
+func Test_o_arg()
+ let after = [
+ \ 'call writefile([winnr("$"),
+ \ winheight(1), winheight(2), &lines,
+ \ winwidth(1), winwidth(2), &columns,
+ \ bufname(winbufnr(1)), bufname(winbufnr(2))],
+ \ "Xtestout")',
+ \ 'qall',
+ \ ]
+ if RunVim([], after, '-o2')
+ " Open 2 windows split horizontally. Expect:
+ " - 2 windows
+ " - both windows should have the same or almost the same height
+ " - sum of both windows height (+ 3 for both statusline and Ex command)
+ " should be equal to the number of lines
+ " - both windows should have the same width which should be equal to the
+ " number of columns
+ " - buffer of both windows should have no name
+ let [wn, wh1, wh2, ln, ww1, ww2, cn, bn1, bn2] = readfile('Xtestout')
+ call assert_equal('2', wn)
+ call assert_inrange(0, 1, wh1 - wh2)
+ call assert_equal(string(wh1 + wh2 + 3), ln)
+ call assert_equal(ww1, ww2)
+ call assert_equal(ww1, cn)
+ call assert_equal('', bn1)
+ call assert_equal('', bn2)
+ endif
+
+ if RunVim([], after, '-o foo bar')
+ " Same expectations as for -o2 but buffer names should be foo and bar
+ let [wn, wh1, wh2, ln, ww1, ww2, cn, bn1, bn2] = readfile('Xtestout')
+ call assert_equal('2', wn)
+ call assert_inrange(0, 1, wh1 - wh2)
+ call assert_equal(string(wh1 + wh2 + 3), ln)
+ call assert_equal(ww1, ww2)
+ call assert_equal(ww1, cn)
+ call assert_equal('foo', bn1)
+ call assert_equal('bar', bn2)
+ endif
+
+ if RunVim([], after, '-O2')
+ " Open 2 windows split vertically. Expect:
+ " - 2 windows
+ " - both windows should have the same or almost the same width
+ " - sum of both windows width (+ 1 for the separator) should be equal to
+ " the number of columns
+ " - both windows should have the same height
+ " - window height (+ 2 for the statusline and Ex command) should be equal
+ " to the number of lines
+ " - buffer of both windows should have no name
+ let [wn, wh1, wh2, ln, ww1, ww2, cn, bn1, bn2] = readfile('Xtestout')
+ call assert_equal('2', wn)
+ call assert_inrange(0, 1, ww1 - ww2)
+ call assert_equal(string(ww1 + ww2 + 1), cn)
+ call assert_equal(wh1, wh2)
+ call assert_equal(string(wh1 + 2), ln)
+ call assert_equal('', bn1)
+ call assert_equal('', bn2)
+ endif
+
+ if RunVim([], after, '-O foo bar')
+ " Same expectations as for -O2 but buffer names should be foo and bar
+ let [wn, wh1, wh2, ln, ww1, ww2, cn, bn1, bn2] = readfile('Xtestout')
+ call assert_equal('2', wn)
+ call assert_inrange(0, 1, ww1 - ww2)
+ call assert_equal(string(ww1 + ww2 + 1), cn)
+ call assert_equal(wh1, wh2)
+ call assert_equal(string(wh1 + 2), ln)
+ call assert_equal('foo', bn1)
+ call assert_equal('bar', bn2)
+ endif
+
+ call delete('Xtestout')
+endfunc
+
+" Test the -p[N] argument to open N tabpages.
+func Test_p_arg()
+ let after = [
+ \ 'call writefile(split(execute("tabs"), "\n"), "Xtestout")',
+ \ 'qall',
+ \ ]
+ if RunVim([], after, '-p2')
+ let lines = readfile('Xtestout')
+ call assert_equal(4, len(lines))
+ call assert_equal('Tab page 1', lines[0])
+ call assert_equal('> [No Name]', lines[1])
+ call assert_equal('Tab page 2', lines[2])
+ call assert_equal(' [No Name]', lines[3])
+ endif
+
+ if RunVim([], after, '-p foo bar')
+ let lines = readfile('Xtestout')
+ call assert_equal(4, len(lines))
+ call assert_equal('Tab page 1', lines[0])
+ call assert_equal('> foo', lines[1])
+ call assert_equal('Tab page 2', lines[2])
+ call assert_equal(' bar', lines[3])
+ endif
+
+ call delete('Xtestout')
+endfunc
+
+" Test the -V[N] argument to set the 'verbose' option to [N]
+func Test_V_arg()
+ if has('gui_running')
+ " Can't catch the output of gvim.
+ return
+ endif
+ let out = system(GetVimCommand() . ' --clean -es -X -V0 -c "set verbose?" -cq')
+ call assert_equal(" verbose=0\n", out)
+
+ let out = system(GetVimCommand() . ' --clean -es -X -V2 -c "set verbose?" -cq')
+ call assert_match("sourcing \"$VIMRUNTIME[\\/]defaults\.vim\"\r\nSearching for \"filetype\.vim\".*\n", out)
+ call assert_match(" verbose=2\n", out)
+
+ let out = system(GetVimCommand() . ' --clean -es -X -V15 -c "set verbose?" -cq')
+ call assert_match("sourcing \"$VIMRUNTIME[\\/]defaults\.vim\"\r\nline 1: \" The default vimrc file\..* verbose=15\n", out)
+endfunc
+
+" Test the '-q [errorfile]' argument.
+func Test_q_arg()
+ let source_file = has('win32') ? '..\memfile.c' : '../memfile.c'
+ let after = [
+ \ 'call writefile([&errorfile, string(getpos("."))], "Xtestout")',
+ \ 'copen',
+ \ 'w >> Xtestout',
+ \ 'qall'
+ \ ]
+
+ " Test with default argument '-q'.
+ call assert_equal('errors.err', &errorfile)
+ call writefile(["../memfile.c:1482:5: error: expected ';' before '}' token"], 'errors.err')
+ if RunVim([], after, '-q')
+ let lines = readfile('Xtestout')
+ call assert_equal(['errors.err',
+ \ '[0, 1482, 5, 0]',
+ \ source_file . "|1482 col 5| error: expected ';' before '}' token"],
+ \ lines)
+ endif
+ call delete('Xtestout')
+ call delete('errors.err')
+
+ " Test with explicit argument '-q Xerrors' (with space).
+ call writefile(["../memfile.c:1482:5: error: expected ';' before '}' token"], 'Xerrors')
+ if RunVim([], after, '-q Xerrors')
+ let lines = readfile('Xtestout')
+ call assert_equal(['Xerrors',
+ \ '[0, 1482, 5, 0]',
+ \ source_file . "|1482 col 5| error: expected ';' before '}' token"],
+ \ lines)
+ endif
+ call delete('Xtestout')
+
+ " Test with explicit argument '-qXerrors' (without space).
+ if RunVim([], after, '-qXerrors')
+ let lines = readfile('Xtestout')
+ call assert_equal(['Xerrors',
+ \ '[0, 1482, 5, 0]',
+ \ source_file . "|1482 col 5| error: expected ';' before '}' token"],
+ \ lines)
+ endif
+
+ call delete('Xtestout')
+ call delete('Xerrors')
+endfunc
+
+" Test the -V[N]{filename} argument to set the 'verbose' option to N
+" and set 'verbosefile' to filename.
+func Test_V_file_arg()
+ if RunVim([], [], ' --clean -V2Xverbosefile -c "set verbose? verbosefile?" -cq')
+ let out = join(readfile('Xverbosefile'), "\n")
+ call assert_match("sourcing \"$VIMRUNTIME[\\/]defaults\.vim\"\n", out)
+ call assert_match("\n verbose=2\n", out)
+ call assert_match("\n verbosefile=Xverbosefile", out)
+ endif
+
+ call delete('Xverbosefile')
+endfunc
+
+" Test the -m, -M and -R arguments:
+" -m resets 'write'
+" -M resets 'modifiable' and 'write'
+" -R sets 'readonly'
+func Test_m_M_R()
+ let after = [
+ \ 'call writefile([&write, &modifiable, &readonly, &updatecount], "Xtestout")',
+ \ 'qall',
+ \ ]
+ if RunVim([], after, '')
+ let lines = readfile('Xtestout')
+ call assert_equal(['1', '1', '0', '200'], lines)
+ endif
+ if RunVim([], after, '-m')
+ let lines = readfile('Xtestout')
+ call assert_equal(['0', '1', '0', '200'], lines)
+ endif
+ if RunVim([], after, '-M')
+ let lines = readfile('Xtestout')
+ call assert_equal(['0', '0', '0', '200'], lines)
+ endif
+ if RunVim([], after, '-R')
+ let lines = readfile('Xtestout')
+ call assert_equal(['1', '1', '1', '10000'], lines)
+ endif
+
+ call delete('Xtestout')
+endfunc
+
+" Test the -A, -F and -H arguments (Arabic, Farsi and Hebrew modes).
+func Test_A_F_H_arg()
+ let after = [
+ \ 'call writefile([&rightleft, &arabic, &fkmap, &hkmap], "Xtestout")',
+ \ 'qall',
+ \ ]
+ " Use silent Ex mode to avoid the hit-Enter prompt for the warning that
+ " 'encoding' is not utf-8.
+ if has('arabic') && &encoding == 'utf-8' && RunVim([], after, '-e -s -A')
+ let lines = readfile('Xtestout')
+ call assert_equal(['1', '1', '0', '0'], lines)
+ endif
+
+ if has('farsi') && RunVim([], after, '-F')
+ let lines = readfile('Xtestout')
+ call assert_equal(['1', '0', '1', '0'], lines)
+ endif
+
+ if has('rightleft') && RunVim([], after, '-H')
+ let lines = readfile('Xtestout')
+ call assert_equal(['1', '0', '0', '1'], lines)
+ endif
+
+ call delete('Xtestout')
+endfunc
+
+func Test_file_args()
+ let after = [
+ \ 'call writefile(argv(), "Xtestout")',
+ \ 'qall',
+ \ ]
+ if RunVim([], after, '')
+ let lines = readfile('Xtestout')
+ call assert_equal(0, len(lines))
+ endif
+
+ if RunVim([], after, 'one')
+ let lines = readfile('Xtestout')
+ call assert_equal(1, len(lines))
+ call assert_equal('one', lines[0])
+ endif
+
+ if RunVim([], after, 'one two three')
+ let lines = readfile('Xtestout')
+ call assert_equal(3, len(lines))
+ call assert_equal('one', lines[0])
+ call assert_equal('two', lines[1])
+ call assert_equal('three', lines[2])
+ endif
+
+ if RunVim([], after, 'one -c echo two')
+ let lines = readfile('Xtestout')
+ call assert_equal(2, len(lines))
+ call assert_equal('one', lines[0])
+ call assert_equal('two', lines[1])
+ endif
+
+ if RunVim([], after, 'one -- -c echo two')
+ let lines = readfile('Xtestout')
+ call assert_equal(4, len(lines))
+ call assert_equal('one', lines[0])
+ call assert_equal('-c', lines[1])
+ call assert_equal('echo', lines[2])
+ call assert_equal('two', lines[3])
+ endif
+
+ call delete('Xtestout')
+endfunc
+
+func Test_startuptime()
+ if !has('startuptime')
+ return
+ endif
+ let after = ['qall']
+ if RunVim([], after, '--startuptime Xtestout one')
+ let lines = readfile('Xtestout')
+ let expected = ['--- VIM STARTING ---', 'parsing arguments',
+ \ 'shell init', 'inits 3', 'start termcap', 'opening buffers']
+ let found = []
+ for line in lines
+ for exp in expected
+ if line =~ exp
+ call add(found, exp)
+ endif
+ endfor
+ endfor
+ call assert_equal(expected, found)
+ endif
+ call delete('Xtestout')
+endfunc
+
+func Test_read_stdin()
+ let after = [
+ \ 'write Xtestout',
+ \ 'quit!',
+ \ ]
+ if RunVimPiped([], after, '-', 'echo something | ')
+ let lines = readfile('Xtestout')
+ " MS-Windows adds a space after the word
+ call assert_equal(['something'], split(lines[0]))
+ endif
+ call delete('Xtestout')
+endfunc
+
+func Test_set_shell()
+ let after = [
+ \ 'call writefile([&shell], "Xtestout")',
+ \ 'quit!',
+ \ ]
+ let $SHELL = '/bin/with space/sh'
+ if RunVimPiped([], after, '', '')
+ let lines = readfile('Xtestout')
+ " MS-Windows adds a space after the word
+ call assert_equal('/bin/with\ space/sh', lines[0])
+ endif
+ call delete('Xtestout')
+endfunc
+
+func Test_progpath()
+ " Tests normally run with "./vim" or "../vim", these must have been expanded
+ " to a full path.
+ if has('unix')
+ call assert_equal('/', v:progpath[0])
+ elseif has('win32')
+ call assert_equal(':', v:progpath[1])
+ call assert_match('[/\\]', v:progpath[2])
+ endif
+
+ " Only expect "vim" to appear in v:progname.
+ call assert_match('vim\c', v:progname)
+endfunc
+
+func Test_silent_ex_mode()
+ if !has('unix') || has('gui_running')
+ " can't get output of Vim.
+ return
+ endif
+
+ " This caused an ml_get error.
+ let out = system(GetVimCommand() . '-u NONE -es -c''set verbose=1|h|exe "%norm\<c-y>\<c-d>"'' -c cq')
+ call assert_notmatch('E315:', out)
+endfunc
+
+func Test_default_term()
+ if !has('unix') || has('gui_running')
+ " can't get output of Vim.
+ return
+ endif
+
+ let save_term = $TERM
+ let $TERM = 'unknownxxx'
+ let out = system(GetVimCommand() . ' -c''set term'' -c cq')
+ call assert_match("defaulting to 'ansi'", out)
+ let $TERM = save_term
+endfunc
+
+func Test_zzz_startinsert()
+ " Test :startinsert
+ call writefile(['123456'], 'Xtestout')
+ let after = [
+ \ ':startinsert',
+ \ 'call feedkeys("foobar\<c-o>:wq\<cr>","t")'
+ \ ]
+ if RunVim([], after, 'Xtestout')
+ let lines = readfile('Xtestout')
+ call assert_equal(['foobar123456'], lines)
+ endif
+ " Test :startinsert!
+ call writefile(['123456'], 'Xtestout')
+ let after = [
+ \ ':startinsert!',
+ \ 'call feedkeys("foobar\<c-o>:wq\<cr>","t")'
+ \ ]
+ if RunVim([], after, 'Xtestout')
+ let lines = readfile('Xtestout')
+ call assert_equal(['123456foobar'], lines)
+ endif
+ call delete('Xtestout')
+endfunc
diff --git a/src/testdir/test_startup_utf8.vim b/src/testdir/test_startup_utf8.vim
new file mode 100644
index 0000000..8b3eca1
--- /dev/null
+++ b/src/testdir/test_startup_utf8.vim
@@ -0,0 +1,83 @@
+" Tests for startup using utf-8.
+
+source shared.vim
+source screendump.vim
+
+func Test_read_stdin_utf8()
+ let linesin = ['テスト', '€ÀÈÌÒÙ']
+ call writefile(linesin, 'Xtestin')
+ let before = [
+ \ 'set enc=utf-8',
+ \ 'set fencs=cp932,utf-8',
+ \ ]
+ let after = [
+ \ 'write ++enc=utf-8 Xtestout',
+ \ 'quit!',
+ \ ]
+ if has('win32')
+ let pipecmd = 'type Xtestin | '
+ else
+ let pipecmd = 'cat Xtestin | '
+ endif
+ if RunVimPiped(before, after, '-', pipecmd)
+ let lines = readfile('Xtestout')
+ call assert_equal(linesin, lines)
+ else
+ call assert_equal('', 'RunVimPiped failed.')
+ endif
+ call delete('Xtestout')
+ call delete('Xtestin')
+endfunc
+
+func Test_read_fifo_utf8()
+ if !has('unix')
+ return
+ endif
+ " Using bash/zsh's process substitution.
+ if executable('bash')
+ set shell=bash
+ elseif executable('zsh')
+ set shell=zsh
+ else
+ return
+ endif
+ let linesin = ['テスト', '€ÀÈÌÒÙ']
+ call writefile(linesin, 'Xtestin')
+ let before = [
+ \ 'set enc=utf-8',
+ \ 'set fencs=cp932,utf-8',
+ \ ]
+ let after = [
+ \ 'write ++enc=utf-8 Xtestout',
+ \ 'quit!',
+ \ ]
+ if RunVim(before, after, '<(cat Xtestin)')
+ let lines = readfile('Xtestout')
+ call assert_equal(linesin, lines)
+ else
+ call assert_equal('', 'RunVim failed.')
+ endif
+ call delete('Xtestout')
+ call delete('Xtestin')
+endfunc
+
+func Test_detect_ambiwidth()
+ if !CanRunVimInTerminal()
+ return
+ endif
+
+ " Use the title termcap entries to output the escape sequence.
+ call writefile([
+ \ 'set enc=utf-8',
+ \ 'set ambiwidth=double',
+ \ 'call test_option_not_set("ambiwidth")',
+ \ 'redraw',
+ \ ], 'Xscript')
+ let buf = RunVimInTerminal('-S Xscript', {})
+ call term_wait(buf)
+ call term_sendkeys(buf, "S\<C-R>=&ambiwidth\<CR>\<Esc>")
+ call WaitForAssert({-> assert_match('single', term_getline(buf, 1))})
+
+ call StopVimInTerminal(buf)
+ call delete('Xscript')
+endfunc
diff --git a/src/testdir/test_stat.vim b/src/testdir/test_stat.vim
new file mode 100644
index 0000000..e48e887
--- /dev/null
+++ b/src/testdir/test_stat.vim
@@ -0,0 +1,185 @@
+" Tests for stat functions and checktime
+
+func CheckFileTime(doSleep)
+ let fnames = ['Xtest1.tmp', 'Xtest2.tmp', 'Xtest3.tmp']
+ let times = []
+ let result = 0
+
+ " Use three files istead of localtim(), with a network filesystem the file
+ " times may differ at bit
+ let fl = ['Hello World!']
+ for fname in fnames
+ call writefile(fl, fname)
+ call add(times, getftime(fname))
+ if a:doSleep
+ sleep 1
+ endif
+ endfor
+
+ let time_correct = (times[0] <= times[1] && times[1] <= times[2])
+ if a:doSleep || time_correct
+ call assert_true(time_correct, printf('Expected %s <= %s <= %s', times[0], times[1], times[2]))
+ call assert_equal(strlen(fl[0] . "\n"), getfsize(fnames[0]))
+ call assert_equal('file', getftype(fnames[0]))
+ call assert_equal('rw-', getfperm(fnames[0])[0:2])
+ let result = 1
+ endif
+
+ for fname in fnames
+ call delete(fname)
+ endfor
+ return result
+endfunc
+
+func Test_existent_file()
+ " On some systems the file timestamp is rounded to a multiple of 2 seconds.
+ " We need to sleep to handle that, but that makes the test slow. First try
+ " without the sleep, and if it fails try again with the sleep.
+ if CheckFileTime(0) == 0
+ call CheckFileTime(1)
+ endif
+endfunc
+
+func Test_existent_directory()
+ let dname = '.'
+
+ call assert_equal(0, getfsize(dname))
+ call assert_equal('dir', getftype(dname))
+ call assert_equal('rwx', getfperm(dname)[0:2])
+endfunc
+
+func SleepForTimestamp()
+ " FAT has a granularity of 2 seconds, otherwise it's usually 1 second
+ if has('win32')
+ sleep 2
+ else
+ sleep 1
+ endif
+endfunc
+
+func Test_checktime()
+ let fname = 'Xtest.tmp'
+
+ let fl = ['Hello World!']
+ call writefile(fl, fname)
+ set autoread
+ exec 'e' fname
+ call SleepForTimestamp()
+ let fl = readfile(fname)
+ let fl[0] .= ' - checktime'
+ call writefile(fl, fname)
+ checktime
+ call assert_equal(fl[0], getline(1))
+
+ call delete(fname)
+endfunc
+
+func Test_autoread_file_deleted()
+ new Xautoread
+ set autoread
+ call setline(1, 'original')
+ w!
+
+ call SleepForTimestamp()
+ if has('win32')
+ silent !echo changed > Xautoread
+ else
+ silent !echo 'changed' > Xautoread
+ endif
+ checktime
+ call assert_equal('changed', trim(getline(1)))
+
+ call SleepForTimestamp()
+ messages clear
+ if has('win32')
+ silent !del Xautoread
+ else
+ silent !rm Xautoread
+ endif
+ checktime
+ call assert_match('E211:', execute('messages'))
+ call assert_equal('changed', trim(getline(1)))
+
+ call SleepForTimestamp()
+ if has('win32')
+ silent !echo recreated > Xautoread
+ else
+ silent !echo 'recreated' > Xautoread
+ endif
+ checktime
+ call assert_equal('recreated', trim(getline(1)))
+
+ call delete('Xautoread')
+ bwipe!
+endfunc
+
+
+func Test_nonexistent_file()
+ let fname = 'Xtest.tmp'
+
+ call delete(fname)
+ call assert_equal(-1, getftime(fname))
+ call assert_equal(-1, getfsize(fname))
+ call assert_equal('', getftype(fname))
+ call assert_equal('', getfperm(fname))
+endfunc
+
+func Test_getftype()
+ call assert_equal('file', getftype(v:progpath))
+ call assert_equal('dir', getftype('.'))
+
+ if !has('unix')
+ return
+ endif
+
+ silent !ln -s Xfile Xlink
+ call assert_equal('link', getftype('Xlink'))
+ call delete('Xlink')
+
+ if executable('mkfifo')
+ silent !mkfifo Xfifo
+ call assert_equal('fifo', getftype('Xfifo'))
+ call delete('Xfifo')
+ endif
+
+ for cdevfile in systemlist('find /dev -type c -maxdepth 2 2>/dev/null')
+ let type = getftype(cdevfile)
+ " ignore empty result, can happen if the file disappeared
+ if type != ''
+ call assert_equal('cdev', type)
+ endif
+ endfor
+
+ for bdevfile in systemlist('find /dev -type b -maxdepth 2 2>/dev/null')
+ let type = getftype(bdevfile)
+ " ignore empty result, can happen if the file disappeared
+ if type != ''
+ call assert_equal('bdev', type)
+ endif
+ endfor
+
+ " The /run/ directory typically contains socket files.
+ " If it does not, test won't fail but will not test socket files.
+ for socketfile in systemlist('find /run -type s -maxdepth 2 2>/dev/null')
+ let type = getftype(socketfile)
+ " ignore empty result, can happen if the file disappeared
+ if type != ''
+ call assert_equal('socket', type)
+ endif
+ endfor
+
+ " TODO: file type 'other' is not tested. How can we test it?
+endfunc
+
+func Test_win32_symlink_dir()
+ " On Windows, non-admin users cannot create symlinks.
+ " So we use an existing symlink for this test.
+ if has('win32')
+ " Check if 'C:\Users\All Users' is a symlink to a directory.
+ let res = system('dir C:\Users /a')
+ if match(res, '\C<SYMLINKD> *All Users') >= 0
+ " Get the filetype of the symlink.
+ call assert_equal('dir', getftype('C:\Users\All Users'))
+ endif
+ endif
+endfunc
diff --git a/src/testdir/test_statusline.vim b/src/testdir/test_statusline.vim
new file mode 100644
index 0000000..eafbecd
--- /dev/null
+++ b/src/testdir/test_statusline.vim
@@ -0,0 +1,343 @@
+" Test 'statusline'
+"
+" Not tested yet:
+" %a
+" %N
+" %T
+" %X
+
+source view_util.vim
+
+func s:get_statusline()
+ return ScreenLines(&lines - 1, &columns)[0]
+endfunc
+
+func StatuslineWithCaughtError()
+ let s:func_in_statusline_called = 1
+ try
+ call eval('unknown expression')
+ catch
+ endtry
+ return ''
+endfunc
+
+func StatuslineWithError()
+ let s:func_in_statusline_called = 1
+ call eval('unknown expression')
+ return ''
+endfunc
+
+" Function used to display syntax group.
+func SyntaxItem()
+ return synIDattr(synID(line("."),col("."),1),"name")
+endfunc
+
+func Test_caught_error_in_statusline()
+ let s:func_in_statusline_called = 0
+ set laststatus=2
+ let statusline = '%{StatuslineWithCaughtError()}'
+ let &statusline = statusline
+ redrawstatus
+ call assert_true(s:func_in_statusline_called)
+ call assert_equal(statusline, &statusline)
+ set statusline=
+endfunc
+
+func Test_statusline_will_be_disabled_with_error()
+ let s:func_in_statusline_called = 0
+ set laststatus=2
+ let statusline = '%{StatuslineWithError()}'
+ try
+ let &statusline = statusline
+ redrawstatus
+ catch
+ endtry
+ call assert_true(s:func_in_statusline_called)
+ call assert_equal('', &statusline)
+ set statusline=
+endfunc
+
+func Test_statusline()
+ new Xstatusline
+ only
+ set laststatus=2
+ set splitbelow
+ call setline(1, range(1, 200))
+
+ " %b: Value of character under cursor.
+ " %B: As above, in hexadecimal.
+ call cursor(180, 2)
+ set statusline=%b,%B
+ call assert_match('^56,38\s*$', s:get_statusline())
+
+ " %o: Byte number in file of byte under cursor, first byte is 1.
+ " %O: As above, in hexadecimal.
+ set statusline=%o,%O
+ set fileformat=dos
+ call assert_match('^789,315\s*$', s:get_statusline())
+ set fileformat=mac
+ call assert_match('^610,262\s*$', s:get_statusline())
+ set fileformat=unix
+ call assert_match('^610,262\s*$', s:get_statusline())
+ set fileformat&
+
+ " %f: Path to the file in the buffer, as typed or relative to current dir.
+ set statusline=%f
+ call assert_match('^Xstatusline\s*$', s:get_statusline())
+
+ " %F: Full path to the file in the buffer.
+ set statusline=%F
+ call assert_match('/testdir/Xstatusline\s*$', s:get_statusline())
+
+ " %h: Help buffer flag, text is "[help]".
+ " %H: Help buffer flag, text is ",HLP".
+ set statusline=%h,%H
+ call assert_match('^,\s*$', s:get_statusline())
+ help
+ call assert_match('^\[Help\],HLP\s*$', s:get_statusline())
+ helpclose
+
+ " %k: Value of "b:keymap_name" or 'keymap'
+ " when :lmap mappings are being used: <keymap>"
+ set statusline=%k
+ if has('keymap')
+ set keymap=esperanto
+ call assert_match('^<Eo>\s*$', s:get_statusline())
+ set keymap&
+ else
+ call assert_match('^\s*$', s:get_statusline())
+ endif
+
+ " %l: Line number.
+ " %L: Number of line in buffer.
+ " %c: Column number.
+ set statusline=%l/%L,%c
+ call assert_match('^180/200,2\s*$', s:get_statusline())
+
+ " %m: Modified flag, text is "[+]", "[-]" if 'modifiable' is off.
+ " %M: Modified flag, text is ",+" or ",-".
+ set statusline=%m%M
+ call assert_match('^\[+\],+\s*$', s:get_statusline())
+ set nomodifiable
+ call assert_match('^\[+-\],+-\s*$', s:get_statusline())
+ write
+ call assert_match('^\[-\],-\s*$', s:get_statusline())
+ set modifiable&
+ call assert_match('^\s*$', s:get_statusline())
+
+ " %n: Buffer number.
+ set statusline=%n
+ call assert_match('^'.bufnr('%').'\s*$', s:get_statusline())
+
+ " %p: Percentage through file in lines as in CTRL-G.
+ " %P: Percentage through file of displayed window.
+ set statusline=%p,%P
+ 0
+ call assert_match('^0,Top\s*$', s:get_statusline())
+ norm G
+ call assert_match('^100,Bot\s*$', s:get_statusline())
+ 180
+ " Don't check the exact percentage as it depends on the window size
+ call assert_match('^90,\(Top\|Bot\|\d\+%\)\s*$', s:get_statusline())
+
+ " %q: "[Quickfix List]", "[Location List]" or empty.
+ set statusline=%q
+ call assert_match('^\s*$', s:get_statusline())
+ copen
+ call assert_match('^\[Quickfix List\]\s*$', s:get_statusline())
+ cclose
+ lexpr getline(1, 2)
+ lopen
+ call assert_match('^\[Location List\]\s*$', s:get_statusline())
+ lclose
+
+ " %r: Readonly flag, text is "[RO]".
+ " %R: Readonly flag, text is ",RO".
+ set statusline=%r,%R
+ call assert_match('^,\s*$', s:get_statusline())
+ help
+ call assert_match('^\[RO\],RO\s*$', s:get_statusline())
+ helpclose
+
+ " %t: File name (tail) of file in the buffer.
+ set statusline=%t
+ call assert_match('^Xstatusline\s*$', s:get_statusline())
+
+ " %v: Virtual column number.
+ " %V: Virtual column number as -{num}. Not displayed if equal to 'c'.
+ call cursor(180, 2)
+ set statusline=%v,%V
+ call assert_match('^2,\s*$', s:get_statusline())
+ set virtualedit=all
+ norm 10|
+ call assert_match('^10,-10\s*$', s:get_statusline())
+ set virtualedit&
+
+ " %w: Preview window flag, text is "[Preview]".
+ " %W: Preview window flag, text is ",PRV".
+ set statusline=%w%W
+ call assert_match('^\s*$', s:get_statusline())
+ pedit
+ wincmd j
+ call assert_match('^\[Preview\],PRV\s*$', s:get_statusline())
+ pclose
+
+ " %y: Type of file in the buffer, e.g., "[vim]". See 'filetype'.
+ " %Y: Type of file in the buffer, e.g., ",VIM". See 'filetype'.
+ set statusline=%y\ %Y
+ call assert_match('^\s*$', s:get_statusline())
+ setfiletype vim
+ call assert_match('^\[vim\] VIM\s*$', s:get_statusline())
+
+ " %=: Separation point between left and right aligned items.
+ set statusline=foo%=bar
+ call assert_match('^foo\s\+bar\s*$', s:get_statusline())
+
+ " Test min/max width, leading zeroes, left/right justify.
+ set statusline=%04B
+ call cursor(180, 2)
+ call assert_match('^0038\s*$', s:get_statusline())
+ set statusline=#%4B#
+ call assert_match('^# 38#\s*$', s:get_statusline())
+ set statusline=#%-4B#
+ call assert_match('^#38 #\s*$', s:get_statusline())
+ set statusline=%.6f
+ call assert_match('^<sline\s*$', s:get_statusline())
+
+ " %<: Where to truncate.
+ exe 'set statusline=a%<b' . repeat('c', 1000) . 'd'
+ call assert_match('^a<c*d$', s:get_statusline())
+ exe 'set statusline=a' . repeat('b', 1000) . '%<c'
+ call assert_match('^ab*>$', s:get_statusline())
+
+ "%{: Evaluate expression between '%{' and '}' and substitute result.
+ syntax on
+ set statusline=%{SyntaxItem()}
+ call assert_match('^vimNumber\s*$', s:get_statusline())
+ s/^/"/
+ call assert_match('^vimLineComment\s*$', s:get_statusline())
+ syntax off
+
+ "%(: Start of item group.
+ set statusline=ab%(cd%q%)de
+ call assert_match('^abde\s*$', s:get_statusline())
+ copen
+ call assert_match('^abcd\[Quickfix List]de\s*$', s:get_statusline())
+ cclose
+
+ " %#: Set highlight group. The name must follow and then a # again.
+ set statusline=ab%#Todo#cd%#Error#ef
+ call assert_match('^abcdef\s*$', s:get_statusline())
+ let sa1=screenattr(&lines - 1, 1)
+ let sa2=screenattr(&lines - 1, 3)
+ let sa3=screenattr(&lines - 1, 5)
+ call assert_notequal(sa1, sa2)
+ call assert_notequal(sa1, sa3)
+ call assert_notequal(sa2, sa3)
+ call assert_equal(sa1, screenattr(&lines - 1, 2))
+ call assert_equal(sa2, screenattr(&lines - 1, 4))
+ call assert_equal(sa3, screenattr(&lines - 1, 6))
+ call assert_equal(sa3, screenattr(&lines - 1, 7))
+
+ " %*: Set highlight group to User{N}
+ set statusline=a%1*b%0*c
+ call assert_match('^abc\s*$', s:get_statusline())
+ let sa1=screenattr(&lines - 1, 1)
+ let sa2=screenattr(&lines - 1, 2)
+ let sa3=screenattr(&lines - 1, 3)
+ call assert_equal(sa1, sa3)
+ call assert_notequal(sa1, sa2)
+
+ " An empty group that contains highlight changes
+ let g:a = ''
+ set statusline=ab%(cd%1*%{g:a}%*%)de
+ call assert_match('^abde\s*$', s:get_statusline())
+ let sa1=screenattr(&lines - 1, 1)
+ let sa2=screenattr(&lines - 1, 4)
+ call assert_equal(sa1, sa2)
+ let g:a = 'X'
+ call assert_match('^abcdXde\s*$', s:get_statusline())
+ let sa1=screenattr(&lines - 1, 1)
+ let sa2=screenattr(&lines - 1, 5)
+ let sa3=screenattr(&lines - 1, 7)
+ call assert_equal(sa1, sa3)
+ call assert_notequal(sa1, sa2)
+
+ let g:a = ''
+ set statusline=ab%1*%(cd%*%{g:a}%1*%)de
+ call assert_match('^abde\s*$', s:get_statusline())
+ let sa1=screenattr(&lines - 1, 1)
+ let sa2=screenattr(&lines - 1, 4)
+ call assert_notequal(sa1, sa2)
+ let g:a = 'X'
+ call assert_match('^abcdXde\s*$', s:get_statusline())
+ let sa1=screenattr(&lines - 1, 1)
+ let sa2=screenattr(&lines - 1, 3)
+ let sa3=screenattr(&lines - 1, 5)
+ let sa4=screenattr(&lines - 1, 7)
+ call assert_notequal(sa1, sa2)
+ call assert_equal(sa1, sa3)
+ call assert_equal(sa2, sa4)
+
+ " An empty group that contains highlight changes and doesn't reset them
+ let g:a = ''
+ set statusline=ab%(cd%1*%{g:a}%)de
+ call assert_match('^abcdde\s*$', s:get_statusline())
+ let sa1=screenattr(&lines - 1, 1)
+ let sa2=screenattr(&lines - 1, 5)
+ call assert_notequal(sa1, sa2)
+ let g:a = 'X'
+ call assert_match('^abcdXde\s*$', s:get_statusline())
+ let sa1=screenattr(&lines - 1, 1)
+ let sa2=screenattr(&lines - 1, 5)
+ let sa3=screenattr(&lines - 1, 7)
+ call assert_notequal(sa1, sa2)
+ call assert_equal(sa2, sa3)
+
+ let g:a = ''
+ set statusline=ab%1*%(cd%*%{g:a}%)de
+ call assert_match('^abcdde\s*$', s:get_statusline())
+ let sa1=screenattr(&lines - 1, 1)
+ let sa2=screenattr(&lines - 1, 3)
+ let sa3=screenattr(&lines - 1, 5)
+ call assert_notequal(sa1, sa2)
+ call assert_equal(sa1, sa3)
+ let g:a = 'X'
+ call assert_match('^abcdXde\s*$', s:get_statusline())
+ let sa1=screenattr(&lines - 1, 1)
+ let sa2=screenattr(&lines - 1, 3)
+ let sa3=screenattr(&lines - 1, 5)
+ let sa4=screenattr(&lines - 1, 7)
+ call assert_notequal(sa1, sa2)
+ call assert_equal(sa1, sa3)
+ call assert_equal(sa1, sa4)
+
+ let g:a = ''
+ set statusline=%#Error#{%(\ %{g:a}\ %)}
+ call assert_match('^{}\s*$', s:get_statusline())
+ let g:a = 'X'
+ call assert_match('^{ X }\s*$', s:get_statusline())
+
+ " %%: a percent sign.
+ set statusline=10%%
+ call assert_match('^10%\s*$', s:get_statusline())
+
+ " %!: evaluated expression is used as the option value
+ set statusline=%!2*3+1
+ call assert_match('7\s*$', s:get_statusline())
+
+ " Check statusline in current and non-current window
+ " with the 'fillchars' option.
+ set fillchars=stl:^,stlnc:=,vert:\|,fold:-,diff:-
+ vsplit
+ set statusline=x%=y
+ call assert_match('^x^\+y^x=\+y$', s:get_statusline())
+ set fillchars&
+ close
+
+ %bw!
+ call delete('Xstatusline')
+ set statusline&
+ set laststatus&
+ set splitbelow&
+endfunc
diff --git a/src/testdir/test_substitute.vim b/src/testdir/test_substitute.vim
new file mode 100644
index 0000000..d84daa7
--- /dev/null
+++ b/src/testdir/test_substitute.vim
@@ -0,0 +1,502 @@
+" Tests for multi-line regexps with ":s".
+
+func Test_multiline_subst()
+ enew!
+ call append(0, ["1 aa",
+ \ "bb",
+ \ "cc",
+ \ "2 dd",
+ \ "ee",
+ \ "3 ef",
+ \ "gh",
+ \ "4 ij",
+ \ "5 a8",
+ \ "8b c9",
+ \ "9d",
+ \ "6 e7",
+ \ "77f",
+ \ "xxxxx"])
+
+ 1
+ " test if replacing a line break works with a back reference
+ /^1/,/^2/s/\n\(.\)/ \1/
+ " test if inserting a line break works with a back reference
+ /^3/,/^4/s/\(.\)$/\r\1/
+ " test if replacing a line break with another line break works
+ /^5/,/^6/s/\(\_d\{3}\)/x\1x/
+ call assert_equal('1 aa bb cc 2 dd ee', getline(1))
+ call assert_equal('3 e', getline(2))
+ call assert_equal('f', getline(3))
+ call assert_equal('g', getline(4))
+ call assert_equal('h', getline(5))
+ call assert_equal('4 i', getline(6))
+ call assert_equal('j', getline(7))
+ call assert_equal('5 ax8', getline(8))
+ call assert_equal('8xb cx9', getline(9))
+ call assert_equal('9xd', getline(10))
+ call assert_equal('6 ex7', getline(11))
+ call assert_equal('7x7f', getline(12))
+ call assert_equal('xxxxx', getline(13))
+ enew!
+endfunc
+
+func Test_substitute_variants()
+ " Validate that all the 2-/3-letter variants which embed the flags into the
+ " command name actually work.
+ enew!
+ let ln = 'Testing string'
+ let variants = [
+ \ { 'cmd': ':s/Test/test/c', 'exp': 'testing string', 'prompt': 'y' },
+ \ { 'cmd': ':s/foo/bar/ce', 'exp': ln },
+ \ { 'cmd': ':s/t/r/cg', 'exp': 'Tesring srring', 'prompt': 'a' },
+ \ { 'cmd': ':s/t/r/ci', 'exp': 'resting string', 'prompt': 'y' },
+ \ { 'cmd': ':s/t/r/cI', 'exp': 'Tesring string', 'prompt': 'y' },
+ \ { 'cmd': ':s/t/r/cn', 'exp': ln },
+ \ { 'cmd': ':s/t/r/cp', 'exp': 'Tesring string', 'prompt': 'y' },
+ \ { 'cmd': ':s/t/r/cl', 'exp': 'Tesring string', 'prompt': 'y' },
+ \ { 'cmd': ':s/t/r/gc', 'exp': 'Tesring srring', 'prompt': 'a' },
+ \ { 'cmd': ':s/foo/bar/ge', 'exp': ln },
+ \ { 'cmd': ':s/t/r/g', 'exp': 'Tesring srring' },
+ \ { 'cmd': ':s/t/r/gi', 'exp': 'resring srring' },
+ \ { 'cmd': ':s/t/r/gI', 'exp': 'Tesring srring' },
+ \ { 'cmd': ':s/t/r/gn', 'exp': ln },
+ \ { 'cmd': ':s/t/r/gp', 'exp': 'Tesring srring' },
+ \ { 'cmd': ':s/t/r/gl', 'exp': 'Tesring srring' },
+ \ { 'cmd': ':s//r/gr', 'exp': 'Testr strr' },
+ \ { 'cmd': ':s/t/r/ic', 'exp': 'resting string', 'prompt': 'y' },
+ \ { 'cmd': ':s/foo/bar/ie', 'exp': ln },
+ \ { 'cmd': ':s/t/r/i', 'exp': 'resting string' },
+ \ { 'cmd': ':s/t/r/iI', 'exp': 'Tesring string' },
+ \ { 'cmd': ':s/t/r/in', 'exp': ln },
+ \ { 'cmd': ':s/t/r/ip', 'exp': 'resting string' },
+ \ { 'cmd': ':s//r/ir', 'exp': 'Testr string' },
+ \ { 'cmd': ':s/t/r/Ic', 'exp': 'Tesring string', 'prompt': 'y' },
+ \ { 'cmd': ':s/foo/bar/Ie', 'exp': ln },
+ \ { 'cmd': ':s/t/r/Ig', 'exp': 'Tesring srring' },
+ \ { 'cmd': ':s/t/r/Ii', 'exp': 'resting string' },
+ \ { 'cmd': ':s/t/r/I', 'exp': 'Tesring string' },
+ \ { 'cmd': ':s/t/r/Ip', 'exp': 'Tesring string' },
+ \ { 'cmd': ':s/t/r/Il', 'exp': 'Tesring string' },
+ \ { 'cmd': ':s//r/Ir', 'exp': 'Testr string' },
+ \ { 'cmd': ':s//r/rc', 'exp': 'Testr string', 'prompt': 'y' },
+ \ { 'cmd': ':s//r/rg', 'exp': 'Testr strr' },
+ \ { 'cmd': ':s//r/ri', 'exp': 'Testr string' },
+ \ { 'cmd': ':s//r/rI', 'exp': 'Testr string' },
+ \ { 'cmd': ':s//r/rn', 'exp': 'Testing string' },
+ \ { 'cmd': ':s//r/rp', 'exp': 'Testr string' },
+ \ { 'cmd': ':s//r/rl', 'exp': 'Testr string' },
+ \ { 'cmd': ':s//r/r', 'exp': 'Testr string' },
+ \]
+
+ for var in variants
+ for run in [1, 2]
+ let cmd = var.cmd
+ if run == 2 && cmd =~ "/.*/.*/."
+ " Change :s/from/to/{flags} to :s{flags}
+ let cmd = substitute(cmd, '/.*/', '', '')
+ endif
+ call setline(1, [ln])
+ let msg = printf('using "%s"', cmd)
+ let @/='ing'
+ let v:errmsg = ''
+ call feedkeys(cmd . "\<CR>" . get(var, 'prompt', ''), 'ntx')
+ " No error should exist (matters for testing e flag)
+ call assert_equal('', v:errmsg, msg)
+ call assert_equal(var.exp, getline('.'), msg)
+ endfor
+ endfor
+endfunc
+
+func Test_substitute_repeat()
+ " This caused an invalid memory access.
+ split Xfile
+ s/^/x
+ call feedkeys("Qsc\<CR>y", 'tx')
+ bwipe!
+endfunc
+
+" Test for *sub-replace-special* and *sub-replace-expression* on substitute().
+func Test_sub_replace_1()
+ " Run the tests with 'magic' on
+ set magic
+ set cpo&
+ call assert_equal('AA', substitute('A', 'A', '&&', ''))
+ call assert_equal('&', substitute('B', 'B', '\&', ''))
+ call assert_equal('C123456789987654321', substitute('C123456789', 'C\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)', '\0\9\8\7\6\5\4\3\2\1', ''))
+ call assert_equal('d', substitute('D', 'D', 'd', ''))
+ call assert_equal('~', substitute('E', 'E', '~', ''))
+ call assert_equal('~', substitute('F', 'F', '\~', ''))
+ call assert_equal('Gg', substitute('G', 'G', '\ugg', ''))
+ call assert_equal('Hh', substitute('H', 'H', '\Uh\Eh', ''))
+ call assert_equal('iI', substitute('I', 'I', '\lII', ''))
+ call assert_equal('jJ', substitute('J', 'J', '\LJ\EJ', ''))
+ call assert_equal('Kk', substitute('K', 'K', '\Uk\ek', ''))
+ call assert_equal("l\<C-V>\<C-M>l",
+ \ substitute('lLl', 'L', "\<C-V>\<C-M>", ''))
+ call assert_equal("m\<C-M>m", substitute('mMm', 'M', '\r', ''))
+ call assert_equal("n\<C-V>\<C-M>n",
+ \ substitute('nNn', 'N', "\\\<C-V>\<C-M>", ''))
+ call assert_equal("o\no", substitute('oOo', 'O', '\n', ''))
+ call assert_equal("p\<C-H>p", substitute('pPp', 'P', '\b', ''))
+ call assert_equal("q\tq", substitute('qQq', 'Q', '\t', ''))
+ call assert_equal('r\r', substitute('rRr', 'R', '\\', ''))
+ call assert_equal('scs', substitute('sSs', 'S', '\c', ''))
+ call assert_equal("u\nu", substitute('uUu', 'U', "\n", ''))
+ call assert_equal("v\<C-H>v", substitute('vVv', 'V', "\b", ''))
+ call assert_equal("w\\w", substitute('wWw', 'W', "\\", ''))
+ call assert_equal("x\<C-M>x", substitute('xXx', 'X', "\r", ''))
+ call assert_equal("YyyY", substitute('Y', 'Y', '\L\uyYy\l\EY', ''))
+ call assert_equal("zZZz", substitute('Z', 'Z', '\U\lZzZ\u\Ez', ''))
+endfunc
+
+func Test_sub_replace_2()
+ " Run the tests with 'magic' off
+ set nomagic
+ set cpo&
+ call assert_equal('AA', substitute('A', 'A', '&&', ''))
+ call assert_equal('&', substitute('B', 'B', '\&', ''))
+ call assert_equal('C123456789987654321', substitute('C123456789', 'C\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)', '\0\9\8\7\6\5\4\3\2\1', ''))
+ call assert_equal('d', substitute('D', 'D', 'd', ''))
+ call assert_equal('~', substitute('E', 'E', '~', ''))
+ call assert_equal('~', substitute('F', 'F', '\~', ''))
+ call assert_equal('Gg', substitute('G', 'G', '\ugg', ''))
+ call assert_equal('Hh', substitute('H', 'H', '\Uh\Eh', ''))
+ call assert_equal('iI', substitute('I', 'I', '\lII', ''))
+ call assert_equal('jJ', substitute('J', 'J', '\LJ\EJ', ''))
+ call assert_equal('Kk', substitute('K', 'K', '\Uk\ek', ''))
+ call assert_equal("l\<C-V>\<C-M>l",
+ \ substitute('lLl', 'L', "\<C-V>\<C-M>", ''))
+ call assert_equal("m\<C-M>m", substitute('mMm', 'M', '\r', ''))
+ call assert_equal("n\<C-V>\<C-M>n",
+ \ substitute('nNn', 'N', "\\\<C-V>\<C-M>", ''))
+ call assert_equal("o\no", substitute('oOo', 'O', '\n', ''))
+ call assert_equal("p\<C-H>p", substitute('pPp', 'P', '\b', ''))
+ call assert_equal("q\tq", substitute('qQq', 'Q', '\t', ''))
+ call assert_equal('r\r', substitute('rRr', 'R', '\\', ''))
+ call assert_equal('scs', substitute('sSs', 'S', '\c', ''))
+ call assert_equal("t\<C-M>t", substitute('tTt', 'T', "\r", ''))
+ call assert_equal("u\nu", substitute('uUu', 'U', "\n", ''))
+ call assert_equal("v\<C-H>v", substitute('vVv', 'V', "\b", ''))
+ call assert_equal('w\w', substitute('wWw', 'W', "\\", ''))
+ call assert_equal('XxxX', substitute('X', 'X', '\L\uxXx\l\EX', ''))
+ call assert_equal('yYYy', substitute('Y', 'Y', '\U\lYyY\u\Ey', ''))
+endfunc
+
+func Test_sub_replace_3()
+ set magic&
+ set cpo&
+ call assert_equal('a\a', substitute('aAa', 'A', '\="\\"', ''))
+ call assert_equal('b\\b', substitute('bBb', 'B', '\="\\\\"', ''))
+ call assert_equal("c\rc", substitute('cCc', 'C', "\\=\"\r\"", ''))
+ call assert_equal("d\\\rd", substitute('dDd', 'D', "\\=\"\\\\\r\"", ''))
+ call assert_equal("e\\\\\re", substitute('eEe', 'E', "\\=\"\\\\\\\\\r\"", ''))
+ call assert_equal('f\rf', substitute('fFf', 'F', '\="\\r"', ''))
+ call assert_equal('j\nj', substitute('jJj', 'J', '\="\\n"', ''))
+ call assert_equal("k\<C-M>k", substitute('kKk', 'K', '\="\r"', ''))
+ call assert_equal("l\nl", substitute('lLl', 'L', '\="\n"', ''))
+endfunc
+
+" Test for submatch() on substitute().
+func Test_sub_replace_4()
+ set magic&
+ set cpo&
+ call assert_equal('a\a', substitute('aAa', 'A',
+ \ '\=substitute(submatch(0), ".", "\\", "")', ''))
+ call assert_equal('b\b', substitute('bBb', 'B',
+ \ '\=substitute(submatch(0), ".", "\\\\", "")', ''))
+ call assert_equal("c\<C-V>\<C-M>c", substitute('cCc', 'C', '\=substitute(submatch(0), ".", "\<C-V>\<C-M>", "")', ''))
+ call assert_equal("d\<C-V>\<C-M>d", substitute('dDd', 'D', '\=substitute(submatch(0), ".", "\\\<C-V>\<C-M>", "")', ''))
+ call assert_equal("e\\\<C-V>\<C-M>e", substitute('eEe', 'E', '\=substitute(submatch(0), ".", "\\\\\<C-V>\<C-M>", "")', ''))
+ call assert_equal("f\<C-M>f", substitute('fFf', 'F', '\=substitute(submatch(0), ".", "\\r", "")', ''))
+ call assert_equal("j\nj", substitute('jJj', 'J', '\=substitute(submatch(0), ".", "\\n", "")', ''))
+ call assert_equal("k\rk", substitute('kKk', 'K', '\=substitute(submatch(0), ".", "\r", "")', ''))
+ call assert_equal("l\nl", substitute('lLl', 'L', '\=substitute(submatch(0), ".", "\n", "")', ''))
+endfunc
+
+func Test_sub_replace_5()
+ set magic&
+ set cpo&
+ call assert_equal('A123456789987654321', substitute('A123456789',
+ \ 'A\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)',
+ \ '\=submatch(0) . submatch(9) . submatch(8) . ' .
+ \ 'submatch(7) . submatch(6) . submatch(5) . ' .
+ \ 'submatch(4) . submatch(3) . submatch(2) . submatch(1)',
+ \ ''))
+ call assert_equal("[['A123456789'], ['9'], ['8'], ['7'], ['6'], " .
+ \ "['5'], ['4'], ['3'], ['2'], ['1']]",
+ \ substitute('A123456789',
+ \ 'A\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)',
+ \ '\=string([submatch(0, 1), submatch(9, 1), ' .
+ \ 'submatch(8, 1), submatch(7, 1), submatch(6, 1), ' .
+ \ 'submatch(5, 1), submatch(4, 1), submatch(3, 1), ' .
+ \ 'submatch(2, 1), submatch(1, 1)])',
+ \ ''))
+endfunc
+
+func Test_sub_replace_6()
+ set magic&
+ set cpo+=/
+ call assert_equal('a', substitute('A', 'A', 'a', ''))
+ call assert_equal('%', substitute('B', 'B', '%', ''))
+ set cpo-=/
+ call assert_equal('c', substitute('C', 'C', 'c', ''))
+ call assert_equal('%', substitute('D', 'D', '%', ''))
+endfunc
+
+func Test_sub_replace_7()
+ set magic&
+ set cpo&
+ call assert_equal('AA', substitute('AA', 'A.', '\=submatch(0)', ''))
+ call assert_equal("B\nB", substitute("B\nB", 'B.', '\=submatch(0)', ''))
+ call assert_equal("['B\n']B", substitute("B\nB", 'B.', '\=string(submatch(0, 1))', ''))
+ call assert_equal('-abab', substitute('-bb', '\zeb', 'a', 'g'))
+ call assert_equal('c-cbcbc', substitute('-bb', '\ze', 'c', 'g'))
+endfunc
+
+" Test for *:s%* on :substitute.
+func Test_sub_replace_8()
+ new
+ set magic&
+ set cpo&
+ $put =',,X'
+ s/\(^\|,\)\ze\(,\|X\)/\1N/g
+ call assert_equal('N,,NX', getline("$"))
+ $put =',,Y'
+ let cmd = ':s/\(^\|,\)\ze\(,\|Y\)/\1N/gc'
+ call feedkeys(cmd . "\<CR>a", "xt")
+ call assert_equal('N,,NY', getline("$"))
+ :$put =',,Z'
+ let cmd = ':s/\(^\|,\)\ze\(,\|Z\)/\1N/gc'
+ call feedkeys(cmd . "\<CR>yy", "xt")
+ call assert_equal('N,,NZ', getline("$"))
+ enew! | close
+endfunc
+
+func Test_sub_replace_9()
+ new
+ set magic&
+ set cpo&
+ $put ='xxx'
+ call feedkeys(":s/x/X/gc\<CR>yyq", "xt")
+ call assert_equal('XXx', getline("$"))
+ enew! | close
+endfunc
+
+func Test_sub_replace_10()
+ set magic&
+ set cpo&
+ call assert_equal('a1a2a3a', substitute('123', '\zs', 'a', 'g'))
+ call assert_equal('aaa', substitute('123', '\zs.', 'a', 'g'))
+ call assert_equal('1a2a3a', substitute('123', '.\zs', 'a', 'g'))
+ call assert_equal('a1a2a3a', substitute('123', '\ze', 'a', 'g'))
+ call assert_equal('a1a2a3', substitute('123', '\ze.', 'a', 'g'))
+ call assert_equal('aaa', substitute('123', '.\ze', 'a', 'g'))
+ call assert_equal('aa2a3a', substitute('123', '1\|\ze', 'a', 'g'))
+ call assert_equal('1aaa', substitute('123', '1\zs\|[23]', 'a', 'g'))
+endfunc
+
+" Tests for *sub-replace-special* and *sub-replace-expression* on :substitute.
+
+" Execute a list of :substitute command tests
+func Run_SubCmd_Tests(tests)
+ enew!
+ for t in a:tests
+ let start = line('.') + 1
+ let end = start + len(t[2]) - 1
+ exe "normal o" . t[0]
+ call cursor(start, 1)
+ exe t[1]
+ call assert_equal(t[2], getline(start, end), t[1])
+ endfor
+ enew!
+endfunc
+
+func Test_sub_cmd_1()
+ set magic
+ set cpo&
+
+ " List entry format: [input, cmd, output]
+ let tests = [['A', 's/A/&&/', ['AA']],
+ \ ['B', 's/B/\&/', ['&']],
+ \ ['C123456789', 's/C\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)/\0\9\8\7\6\5\4\3\2\1/', ['C123456789987654321']],
+ \ ['D', 's/D/d/', ['d']],
+ \ ['E', 's/E/~/', ['d']],
+ \ ['F', 's/F/\~/', ['~']],
+ \ ['G', 's/G/\ugg/', ['Gg']],
+ \ ['H', 's/H/\Uh\Eh/', ['Hh']],
+ \ ['I', 's/I/\lII/', ['iI']],
+ \ ['J', 's/J/\LJ\EJ/', ['jJ']],
+ \ ['K', 's/K/\Uk\ek/', ['Kk']],
+ \ ['lLl', "s/L/\<C-V>\<C-M>/", ["l\<C-V>", 'l']],
+ \ ['mMm', 's/M/\r/', ['m', 'm']],
+ \ ['nNn', "s/N/\\\<C-V>\<C-M>/", ["n\<C-V>", 'n']],
+ \ ['oOo', 's/O/\n/', ["o\no"]],
+ \ ['pPp', 's/P/\b/', ["p\<C-H>p"]],
+ \ ['qQq', 's/Q/\t/', ["q\tq"]],
+ \ ['rRr', 's/R/\\/', ['r\r']],
+ \ ['sSs', 's/S/\c/', ['scs']],
+ \ ['tTt', "s/T/\<C-V>\<C-J>/", ["t\<C-V>\<C-J>t"]],
+ \ ['U', 's/U/\L\uuUu\l\EU/', ['UuuU']],
+ \ ['V', 's/V/\U\lVvV\u\Ev/', ['vVVv']]
+ \ ]
+ call Run_SubCmd_Tests(tests)
+endfunc
+
+func Test_sub_cmd_2()
+ set nomagic
+ set cpo&
+
+ " List entry format: [input, cmd, output]
+ let tests = [['A', 's/A/&&/', ['&&']],
+ \ ['B', 's/B/\&/', ['B']],
+ \ ['C123456789', 's/\mC\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)/\0\9\8\7\6\5\4\3\2\1/', ['C123456789987654321']],
+ \ ['D', 's/D/d/', ['d']],
+ \ ['E', 's/E/~/', ['~']],
+ \ ['F', 's/F/\~/', ['~']],
+ \ ['G', 's/G/\ugg/', ['Gg']],
+ \ ['H', 's/H/\Uh\Eh/', ['Hh']],
+ \ ['I', 's/I/\lII/', ['iI']],
+ \ ['J', 's/J/\LJ\EJ/', ['jJ']],
+ \ ['K', 's/K/\Uk\ek/', ['Kk']],
+ \ ['lLl', "s/L/\<C-V>\<C-M>/", ["l\<C-V>", 'l']],
+ \ ['mMm', 's/M/\r/', ['m', 'm']],
+ \ ['nNn', "s/N/\\\<C-V>\<C-M>/", ["n\<C-V>", 'n']],
+ \ ['oOo', 's/O/\n/', ["o\no"]],
+ \ ['pPp', 's/P/\b/', ["p\<C-H>p"]],
+ \ ['qQq', 's/Q/\t/', ["q\tq"]],
+ \ ['rRr', 's/R/\\/', ['r\r']],
+ \ ['sSs', 's/S/\c/', ['scs']],
+ \ ['tTt', "s/T/\<C-V>\<C-J>/", ["t\<C-V>\<C-J>t"]],
+ \ ['U', 's/U/\L\uuUu\l\EU/', ['UuuU']],
+ \ ['V', 's/V/\U\lVvV\u\Ev/', ['vVVv']]
+ \ ]
+ call Run_SubCmd_Tests(tests)
+endfunc
+
+func Test_sub_cmd_3()
+ set nomagic
+ set cpo&
+
+ " List entry format: [input, cmd, output]
+ let tests = [['aAa', "s/A/\\='\\'/", ['a\a']],
+ \ ['bBb', "s/B/\\='\\\\'/", ['b\\b']],
+ \ ['cCc', "s/C/\\='\<C-V>\<C-M>'/", ["c\<C-V>", 'c']],
+ \ ['dDd', "s/D/\\='\\\<C-V>\<C-M>'/", ["d\\\<C-V>", 'd']],
+ \ ['eEe', "s/E/\\='\\\\\<C-V>\<C-M>'/", ["e\\\\\<C-V>", 'e']],
+ \ ['fFf', "s/F/\\='\r'/", ['f', 'f']],
+ \ ['gGg', "s/G/\\='\<C-V>\<C-J>'/", ["g\<C-V>", 'g']],
+ \ ['hHh', "s/H/\\='\\\<C-V>\<C-J>'/", ["h\\\<C-V>", 'h']],
+ \ ['iIi', "s/I/\\='\\\\\<C-V>\<C-J>'/", ["i\\\\\<C-V>", 'i']],
+ \ ['jJj', "s/J/\\='\n'/", ['j', 'j']],
+ \ ['kKk', 's/K/\="\r"/', ['k', 'k']],
+ \ ['lLl', 's/L/\="\n"/', ['l', 'l']]
+ \ ]
+ call Run_SubCmd_Tests(tests)
+endfunc
+
+" Test for submatch() on :substitue.
+func Test_sub_cmd_4()
+ set magic&
+ set cpo&
+
+ " List entry format: [input, cmd, output]
+ let tests = [ ['aAa', "s/A/\\=substitute(submatch(0), '.', '\\', '')/",
+ \ ['a\a']],
+ \ ['bBb', "s/B/\\=substitute(submatch(0), '.', '\\', '')/",
+ \ ['b\b']],
+ \ ['cCc', "s/C/\\=substitute(submatch(0), '.', '\<C-V>\<C-M>', '')/",
+ \ ["c\<C-V>", 'c']],
+ \ ['dDd', "s/D/\\=substitute(submatch(0), '.', '\\\<C-V>\<C-M>', '')/",
+ \ ["d\<C-V>", 'd']],
+ \ ['eEe', "s/E/\\=substitute(submatch(0), '.', '\\\\\<C-V>\<C-M>', '')/",
+ \ ["e\\\<C-V>", 'e']],
+ \ ['fFf', "s/F/\\=substitute(submatch(0), '.', '\\r', '')/",
+ \ ['f', 'f']],
+ \ ['gGg', 's/G/\=substitute(submatch(0), ".", "\<C-V>\<C-J>", "")/',
+ \ ["g\<C-V>", 'g']],
+ \ ['hHh', 's/H/\=substitute(submatch(0), ".", "\\\<C-V>\<C-J>", "")/',
+ \ ["h\<C-V>", 'h']],
+ \ ['iIi', 's/I/\=substitute(submatch(0), ".", "\\\\\<C-V>\<C-J>", "")/',
+ \ ["i\\\<C-V>", 'i']],
+ \ ['jJj', "s/J/\\=substitute(submatch(0), '.', '\\n', '')/",
+ \ ['j', 'j']],
+ \ ['kKk', "s/K/\\=substitute(submatch(0), '.', '\\r', '')/",
+ \ ['k', 'k']],
+ \ ['lLl', "s/L/\\=substitute(submatch(0), '.', '\\n', '')/",
+ \ ['l', 'l']],
+ \ ]
+ call Run_SubCmd_Tests(tests)
+endfunc
+
+func Test_sub_cmd_5()
+ set magic&
+ set cpo&
+
+ " List entry format: [input, cmd, output]
+ let tests = [ ['A123456789', 's/A\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)/\=submatch(0) . submatch(9) . submatch(8) . submatch(7) . submatch(6) . submatch(5) . submatch(4) . submatch(3) . submatch(2) . submatch(1)/', ['A123456789987654321']],
+ \ ['B123456789', 's/B\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)/\=string([submatch(0, 1), submatch(9, 1), submatch(8, 1), submatch(7, 1), submatch(6, 1), submatch(5, 1), submatch(4, 1), submatch(3, 1), submatch(2, 1), submatch(1, 1)])/', ["[['B123456789'], ['9'], ['8'], ['7'], ['6'], ['5'], ['4'], ['3'], ['2'], ['1']]"]],
+ \ ]
+ call Run_SubCmd_Tests(tests)
+endfunc
+
+" Test for *:s%* on :substitute.
+func Test_sub_cmd_6()
+ set magic&
+ set cpo+=/
+
+ " List entry format: [input, cmd, output]
+ let tests = [ ['A', 's/A/a/', ['a']],
+ \ ['B', 's/B/%/', ['a']],
+ \ ]
+ call Run_SubCmd_Tests(tests)
+
+ set cpo-=/
+ let tests = [ ['C', 's/C/c/', ['c']],
+ \ ['D', 's/D/%/', ['%']],
+ \ ]
+ call Run_SubCmd_Tests(tests)
+
+ set cpo&
+endfunc
+
+" Test for :s replacing \n with line break.
+func Test_sub_cmd_7()
+ set magic&
+ set cpo&
+
+ " List entry format: [input, cmd, output]
+ let tests = [ ["A\<C-V>\<C-M>A", 's/A./\=submatch(0)/', ['A', 'A']],
+ \ ["B\<C-V>\<C-J>B", 's/B./\=submatch(0)/', ['B', 'B']],
+ \ ["C\<C-V>\<C-J>C", 's/C./\=strtrans(string(submatch(0, 1)))/', [strtrans("['C\<C-J>']C")]],
+ \ ["D\<C-V>\<C-J>\nD", 's/D.\nD/\=strtrans(string(submatch(0, 1)))/', [strtrans("['D\<C-J>', 'D']")]],
+ \ ["E\<C-V>\<C-J>\n\<C-V>\<C-J>\n\<C-V>\<C-J>\n\<C-V>\<C-J>\n\<C-V>\<C-J>E", 's/E\_.\{-}E/\=strtrans(string(submatch(0, 1)))/', [strtrans("['E\<C-J>', '\<C-J>', '\<C-J>', '\<C-J>', '\<C-J>E']")]],
+ \ ]
+ call Run_SubCmd_Tests(tests)
+
+ exe "normal oQ\nQ\<Esc>k"
+ call assert_fails('s/Q[^\n]Q/\=submatch(0)."foobar"/', 'E486')
+ enew!
+endfunc
+
+func TitleString()
+ let check = 'foo' =~ 'bar'
+ return ""
+endfunc
+
+func Test_sub_cmd_8()
+ set titlestring=%{TitleString()}
+
+ enew!
+ call append(0, ['', 'test_one', 'test_two'])
+ call cursor(1,1)
+ /^test_one/s/.*/\="foo\nbar"/
+ call assert_equal('foo', getline(2))
+ call assert_equal('bar', getline(3))
+ call feedkeys(':/^test_two/s/.*/\="foo\nbar"/c', "t")
+ call feedkeys("\<CR>y", "xt")
+ call assert_equal('foo', getline(4))
+ call assert_equal('bar', getline(5))
+
+ enew!
+ set titlestring&
+endfunc
diff --git a/src/testdir/test_suspend.vim b/src/testdir/test_suspend.vim
new file mode 100644
index 0000000..e569e49
--- /dev/null
+++ b/src/testdir/test_suspend.vim
@@ -0,0 +1,55 @@
+" Test :suspend
+
+source shared.vim
+
+func Test_suspend()
+ if !has('terminal') || !executable('/bin/sh')
+ return
+ endif
+
+ let buf = term_start('/bin/sh')
+ " Wait for shell prompt.
+ call WaitForAssert({-> assert_match('[$#] $', term_getline(buf, '.'))})
+
+ call term_sendkeys(buf, v:progpath
+ \ . " --clean -X"
+ \ . " -c 'set nu'"
+ \ . " -c 'call setline(1, \"foo\")'"
+ \ . " Xfoo\<CR>")
+ " Cursor in terminal buffer should be on first line in spawned vim.
+ call WaitForAssert({-> assert_equal(' 1 foo', term_getline(buf, '.'))})
+
+ for suspend_cmd in [":suspend\<CR>",
+ \ ":stop\<CR>",
+ \ ":suspend!\<CR>",
+ \ ":stop!\<CR>",
+ \ "\<C-Z>"]
+ " Suspend and wait for shell prompt.
+ call term_sendkeys(buf, suspend_cmd)
+ call WaitForAssert({-> assert_match('[$#] $', term_getline(buf, '.'))})
+
+ " Without 'autowrite', buffer should not be written.
+ call assert_equal(0, filereadable('Xfoo'))
+
+ call term_sendkeys(buf, "fg\<CR>")
+ call WaitForAssert({-> assert_equal(' 1 foo', term_getline(buf, '.'))})
+ endfor
+
+ " Test that :suspend! with 'autowrite' writes content of buffers if modified.
+ call term_sendkeys(buf, ":set autowrite\<CR>")
+ call assert_equal(0, filereadable('Xfoo'))
+ call term_sendkeys(buf, ":suspend\<CR>")
+ " Wait for shell prompt.
+ call WaitForAssert({-> assert_match('[$#] $', term_getline(buf, '.'))})
+ call assert_equal(['foo'], readfile('Xfoo'))
+ call term_sendkeys(buf, "fg\<CR>")
+ call WaitForAssert({-> assert_equal(' 1 foo', term_getline(buf, '.'))})
+
+ " Quit gracefully to dump coverage information.
+ call term_sendkeys(buf, ":qall!\<CR>")
+ call term_wait(buf)
+ call Stop_shell_in_terminal(buf)
+
+ exe buf . 'bwipe!'
+ call delete('Xfoo')
+endfunc
diff --git a/src/testdir/test_swap.vim b/src/testdir/test_swap.vim
new file mode 100644
index 0000000..ce52578
--- /dev/null
+++ b/src/testdir/test_swap.vim
@@ -0,0 +1,166 @@
+" Tests for the swap feature
+
+func s:swapname()
+ return trim(execute('swapname'))
+endfunc
+
+" Tests for 'directory' option.
+func Test_swap_directory()
+ if !has("unix")
+ return
+ endif
+ let content = ['start of testfile',
+ \ 'line 2 Abcdefghij',
+ \ 'line 3 Abcdefghij',
+ \ 'end of testfile']
+ call writefile(content, 'Xtest1')
+
+ " '.', swap file in the same directory as file
+ set dir=.,~
+
+ " Verify that the swap file doesn't exist in the current directory
+ call assert_equal([], glob(".Xtest1*.swp", 1, 1, 1))
+ edit Xtest1
+ let swfname = s:swapname()
+ call assert_equal([swfname], glob(swfname, 1, 1, 1))
+
+ " './dir', swap file in a directory relative to the file
+ set dir=./Xtest2,.,~
+
+ call mkdir("Xtest2")
+ edit Xtest1
+ call assert_equal([], glob(swfname, 1, 1, 1))
+ let swfname = "Xtest2/Xtest1.swp"
+ call assert_equal(swfname, s:swapname())
+ call assert_equal([swfname], glob("Xtest2/*", 1, 1, 1))
+
+ " 'dir', swap file in directory relative to the current dir
+ set dir=Xtest.je,~
+
+ call mkdir("Xtest.je")
+ call writefile(content, 'Xtest2/Xtest3')
+ edit Xtest2/Xtest3
+ call assert_equal(["Xtest2/Xtest3"], glob("Xtest2/*", 1, 1, 1))
+ let swfname = "Xtest.je/Xtest3.swp"
+ call assert_equal(swfname, s:swapname())
+ call assert_equal([swfname], glob("Xtest.je/*", 1, 1, 1))
+
+ set dir&
+ call delete("Xtest1")
+ call delete("Xtest2", "rf")
+ call delete("Xtest.je", "rf")
+endfunc
+
+func Test_swap_group()
+ if !has("unix")
+ return
+ endif
+ let groups = split(system('groups'))
+ if len(groups) <= 1
+ throw 'Skipped: need at least two groups, got ' . string(groups)
+ endif
+
+ try
+ call delete('Xtest')
+ split Xtest
+ call setline(1, 'just some text')
+ wq
+ if system('ls -l Xtest') !~ ' ' . groups[0] . ' \d'
+ throw 'Skipped: test file does not have the first group'
+ else
+ silent !chmod 640 Xtest
+ call system('chgrp ' . groups[1] . ' Xtest')
+ if system('ls -l Xtest') !~ ' ' . groups[1] . ' \d'
+ throw 'Skipped: cannot set second group on test file'
+ else
+ split Xtest
+ let swapname = s:swapname()
+ call assert_match('Xtest', swapname)
+ " Group of swapfile must now match original file.
+ call assert_match(' ' . groups[1] . ' \d', system('ls -l ' . swapname))
+
+ bwipe!
+ endif
+ endif
+ finally
+ call delete('Xtest')
+ endtry
+endfunc
+
+func Test_missing_dir()
+ call mkdir('Xswapdir')
+ exe 'set directory=' . getcwd() . '/Xswapdir'
+
+ call assert_equal('', glob('foo'))
+ call assert_equal('', glob('bar'))
+ edit foo/x.txt
+ " This should not give a warning for an existing swap file.
+ split bar/x.txt
+ only
+
+ " Delete the buffer so that swap file is removed before we try to delete the
+ " directory. That fails on MS-Windows.
+ %bdelete!
+ set directory&
+ call delete('Xswapdir', 'rf')
+endfunc
+
+func Test_swapinfo()
+ new Xswapinfo
+ call setline(1, ['one', 'two', 'three'])
+ w
+ let fname = s:swapname()
+ call assert_match('Xswapinfo', fname)
+ let info = swapinfo(fname)
+
+ let ver = printf('VIM %d.%d', v:version / 100, v:version % 100)
+ call assert_equal(ver, info.version)
+
+ call assert_match('\w', info.user)
+ " host name is truncated to 39 bytes in the swap file
+ call assert_equal(hostname()[:38], info.host)
+ call assert_match('Xswapinfo', info.fname)
+ call assert_match(0, info.dirty)
+ call assert_equal(getpid(), info.pid)
+ call assert_match('^\d*$', info.mtime)
+ if has_key(info, 'inode')
+ call assert_match('\d', info.inode)
+ endif
+ bwipe!
+ call delete(fname)
+ call delete('Xswapinfo')
+
+ let info = swapinfo('doesnotexist')
+ call assert_equal('Cannot open file', info.error)
+
+ call writefile(['burp'], 'Xnotaswapfile')
+ let info = swapinfo('Xnotaswapfile')
+ call assert_equal('Cannot read file', info.error)
+ call delete('Xnotaswapfile')
+
+ call writefile([repeat('x', 10000)], 'Xnotaswapfile')
+ let info = swapinfo('Xnotaswapfile')
+ call assert_equal('Not a swap file', info.error)
+ call delete('Xnotaswapfile')
+endfunc
+
+func Test_swapname()
+ edit Xtest1
+ let expected = s:swapname()
+ call assert_equal(expected, swapname('%'))
+
+ new Xtest2
+ let buf = bufnr('%')
+ let expected = s:swapname()
+ wincmd p
+ call assert_equal(expected, swapname(buf))
+
+ new Xtest3
+ setlocal noswapfile
+ call assert_equal('', swapname('%'))
+
+ bwipe!
+ call delete('Xtest1')
+ call delete('Xtest2')
+ call delete('Xtest3')
+endfunc
diff --git a/src/testdir/test_syn_attr.vim b/src/testdir/test_syn_attr.vim
new file mode 100644
index 0000000..27f9fc0
--- /dev/null
+++ b/src/testdir/test_syn_attr.vim
@@ -0,0 +1,818 @@
+" Test syntax highlighting functions.
+
+func Test_missing_attr()
+ hi Mine term=bold cterm=italic
+ call assert_equal('Mine', synIDattr(hlID("Mine"), "name"))
+ call assert_equal('', synIDattr(hlID("Mine"), "bg", 'term'))
+ call assert_equal('1', synIDattr(hlID("Mine"), "bold", 'term'))
+ call assert_equal('1', synIDattr(hlID("Mine"), "italic", 'cterm'))
+ hi Mine term=reverse cterm=inverse
+ call assert_equal('1', synIDattr(hlID("Mine"), "reverse", 'term'))
+ call assert_equal('1', synIDattr(hlID("Mine"), "inverse", 'cterm'))
+ hi Mine term=underline cterm=standout gui=undercurl
+ call assert_equal('1', synIDattr(hlID("Mine"), "underline", 'term'))
+ call assert_equal('1', synIDattr(hlID("Mine"), "standout", 'cterm'))
+ call assert_equal('1', synIDattr(hlID("Mine"), "undercurl", 'gui'))
+ hi Mine term=NONE cterm=NONE gui=NONE
+ call assert_equal('', synIDattr(hlID("Mine"), "bold", 'term'))
+ call assert_equal('', synIDattr(hlID("Mine"), "italic", 'cterm'))
+ call assert_equal('', synIDattr(hlID("Mine"), "reverse", 'term'))
+ call assert_equal('', synIDattr(hlID("Mine"), "inverse", 'cterm'))
+ call assert_equal('', synIDattr(hlID("Mine"), "underline", 'term'))
+ call assert_equal('', synIDattr(hlID("Mine"), "standout", 'cterm'))
+ call assert_equal('', synIDattr(hlID("Mine"), "undercurl", 'gui'))
+
+ if has('gui')
+ let fontname = getfontname()
+ if fontname == ''
+ let fontname = 'something'
+ endif
+ exe "hi Mine guifg=blue guibg=red font='" . fontname . "'"
+ call assert_equal('blue', synIDattr(hlID("Mine"), "fg", 'gui'))
+ call assert_equal('red', synIDattr(hlID("Mine"), "bg", 'gui'))
+ call assert_equal(fontname, synIDattr(hlID("Mine"), "font", 'gui'))
+ endif
+endfunc
+
+func Test_color_names()
+ let colors = [
+ \ 'AliceBlue',
+ \ 'AntiqueWhite',
+ \ 'AntiqueWhite1',
+ \ 'AntiqueWhite2',
+ \ 'AntiqueWhite3',
+ \ 'AntiqueWhite4',
+ \ 'BlanchedAlmond',
+ \ 'BlueViolet',
+ \ 'CadetBlue',
+ \ 'CadetBlue1',
+ \ 'CadetBlue2',
+ \ 'CadetBlue3',
+ \ 'CadetBlue4',
+ \ 'CornflowerBlue',
+ \ 'DarkBlue',
+ \ 'DarkCyan',
+ \ 'DarkGoldenrod',
+ \ 'DarkGoldenrod1',
+ \ 'DarkGoldenrod2',
+ \ 'DarkGoldenrod3',
+ \ 'DarkGoldenrod4',
+ \ 'DarkGray',
+ \ 'DarkGreen',
+ \ 'DarkGrey',
+ \ 'DarkKhaki',
+ \ 'DarkMagenta',
+ \ 'DarkOliveGreen',
+ \ 'DarkOliveGreen1',
+ \ 'DarkOliveGreen2',
+ \ 'DarkOliveGreen3',
+ \ 'DarkOliveGreen4',
+ \ 'DarkOrange',
+ \ 'DarkOrange1',
+ \ 'DarkOrange2',
+ \ 'DarkOrange3',
+ \ 'DarkOrange4',
+ \ 'DarkOrchid',
+ \ 'DarkOrchid1',
+ \ 'DarkOrchid2',
+ \ 'DarkOrchid3',
+ \ 'DarkOrchid4',
+ \ 'DarkRed',
+ \ 'DarkSalmon',
+ \ 'DarkSeaGreen',
+ \ 'DarkSeaGreen1',
+ \ 'DarkSeaGreen2',
+ \ 'DarkSeaGreen3',
+ \ 'DarkSeaGreen4',
+ \ 'DarkSlateBlue',
+ \ 'DarkSlateGray',
+ \ 'DarkSlateGray1',
+ \ 'DarkSlateGray2',
+ \ 'DarkSlateGray3',
+ \ 'DarkSlateGray4',
+ \ 'DarkSlateGrey',
+ \ 'DarkTurquoise',
+ \ 'DarkViolet',
+ \ 'DeepPink',
+ \ 'DeepPink1',
+ \ 'DeepPink2',
+ \ 'DeepPink3',
+ \ 'DeepPink4',
+ \ 'DeepSkyBlue',
+ \ 'DeepSkyBlue1',
+ \ 'DeepSkyBlue2',
+ \ 'DeepSkyBlue3',
+ \ 'DeepSkyBlue4',
+ \ 'DimGray',
+ \ 'DimGrey',
+ \ 'DodgerBlue',
+ \ 'DodgerBlue1',
+ \ 'DodgerBlue2',
+ \ 'DodgerBlue3',
+ \ 'DodgerBlue4',
+ \ 'FloralWhite',
+ \ 'ForestGreen',
+ \ 'GhostWhite',
+ \ 'GreenYellow',
+ \ 'HotPink',
+ \ 'HotPink1',
+ \ 'HotPink2',
+ \ 'HotPink3',
+ \ 'HotPink4',
+ \ 'IndianRed',
+ \ 'IndianRed1',
+ \ 'IndianRed2',
+ \ 'IndianRed3',
+ \ 'IndianRed4',
+ \ 'LavenderBlush',
+ \ 'LavenderBlush1',
+ \ 'LavenderBlush2',
+ \ 'LavenderBlush3',
+ \ 'LavenderBlush4',
+ \ 'LawnGreen',
+ \ 'LemonChiffon',
+ \ 'LemonChiffon1',
+ \ 'LemonChiffon2',
+ \ 'LemonChiffon3',
+ \ 'LemonChiffon4',
+ \ 'LightBlue',
+ \ 'LightBlue1',
+ \ 'LightBlue2',
+ \ 'LightBlue3',
+ \ 'LightBlue4',
+ \ 'LightCoral',
+ \ 'LightCyan',
+ \ 'LightCyan1',
+ \ 'LightCyan2',
+ \ 'LightCyan3',
+ \ 'LightCyan4',
+ \ 'LightGoldenrod',
+ \ 'LightGoldenrod1',
+ \ 'LightGoldenrod2',
+ \ 'LightGoldenrod3',
+ \ 'LightGoldenrod4',
+ \ 'LightGoldenrodYellow',
+ \ 'LightGray',
+ \ 'LightGreen',
+ \ 'LightGrey',
+ \ 'LightPink',
+ \ 'LightPink1',
+ \ 'LightPink2',
+ \ 'LightPink3',
+ \ 'LightPink4',
+ \ 'LightSalmon',
+ \ 'LightSalmon1',
+ \ 'LightSalmon2',
+ \ 'LightSalmon3',
+ \ 'LightSalmon4',
+ \ 'LightSeaGreen',
+ \ 'LightSkyBlue',
+ \ 'LightSkyBlue1',
+ \ 'LightSkyBlue2',
+ \ 'LightSkyBlue3',
+ \ 'LightSkyBlue4',
+ \ 'LightSlateBlue',
+ \ 'LightSlateGray',
+ \ 'LightSlateGrey',
+ \ 'LightSteelBlue',
+ \ 'LightSteelBlue1',
+ \ 'LightSteelBlue2',
+ \ 'LightSteelBlue3',
+ \ 'LightSteelBlue4',
+ \ 'LightYellow',
+ \ 'LightYellow1',
+ \ 'LightYellow2',
+ \ 'LightYellow3',
+ \ 'LightYellow4',
+ \ 'LimeGreen',
+ \ 'MediumAquamarine',
+ \ 'MediumBlue',
+ \ 'MediumOrchid',
+ \ 'MediumOrchid1',
+ \ 'MediumOrchid2',
+ \ 'MediumOrchid3',
+ \ 'MediumOrchid4',
+ \ 'MediumPurple',
+ \ 'MediumPurple1',
+ \ 'MediumPurple2',
+ \ 'MediumPurple3',
+ \ 'MediumPurple4',
+ \ 'MediumSeaGreen',
+ \ 'MediumSlateBlue',
+ \ 'MediumSpringGreen',
+ \ 'MediumTurquoise',
+ \ 'MediumVioletRed',
+ \ 'MidnightBlue',
+ \ 'MintCream',
+ \ 'MistyRose',
+ \ 'MistyRose1',
+ \ 'MistyRose2',
+ \ 'MistyRose3',
+ \ 'MistyRose4',
+ \ 'NavajoWhite',
+ \ 'NavajoWhite1',
+ \ 'NavajoWhite2',
+ \ 'NavajoWhite3',
+ \ 'NavajoWhite4',
+ \ 'NavyBlue',
+ \ 'OldLace',
+ \ 'OliveDrab',
+ \ 'OliveDrab1',
+ \ 'OliveDrab2',
+ \ 'OliveDrab3',
+ \ 'OliveDrab4',
+ \ 'OrangeRed',
+ \ 'OrangeRed1',
+ \ 'OrangeRed2',
+ \ 'OrangeRed3',
+ \ 'OrangeRed4',
+ \ 'PaleGoldenrod',
+ \ 'PaleGreen',
+ \ 'PaleGreen1',
+ \ 'PaleGreen2',
+ \ 'PaleGreen3',
+ \ 'PaleGreen4',
+ \ 'PaleTurquoise',
+ \ 'PaleTurquoise1',
+ \ 'PaleTurquoise2',
+ \ 'PaleTurquoise3',
+ \ 'PaleTurquoise4',
+ \ 'PaleVioletRed',
+ \ 'PaleVioletRed1',
+ \ 'PaleVioletRed2',
+ \ 'PaleVioletRed3',
+ \ 'PaleVioletRed4',
+ \ 'PapayaWhip',
+ \ 'PeachPuff',
+ \ 'PeachPuff1',
+ \ 'PeachPuff2',
+ \ 'PeachPuff3',
+ \ 'PeachPuff4',
+ \ 'PowderBlue',
+ \ 'RosyBrown',
+ \ 'RosyBrown1',
+ \ 'RosyBrown2',
+ \ 'RosyBrown3',
+ \ 'RosyBrown4',
+ \ 'RoyalBlue',
+ \ 'RoyalBlue1',
+ \ 'RoyalBlue2',
+ \ 'RoyalBlue3',
+ \ 'RoyalBlue4',
+ \ 'SaddleBrown',
+ \ 'SandyBrown',
+ \ 'SeaGreen',
+ \ 'SeaGreen1',
+ \ 'SeaGreen2',
+ \ 'SeaGreen3',
+ \ 'SeaGreen4',
+ \ 'SkyBlue',
+ \ 'SkyBlue1',
+ \ 'SkyBlue2',
+ \ 'SkyBlue3',
+ \ 'SkyBlue4',
+ \ 'SlateBlue',
+ \ 'SlateBlue1',
+ \ 'SlateBlue2',
+ \ 'SlateBlue3',
+ \ 'SlateBlue4',
+ \ 'SlateGray',
+ \ 'SlateGray1',
+ \ 'SlateGray2',
+ \ 'SlateGray3',
+ \ 'SlateGray4',
+ \ 'SlateGrey',
+ \ 'SpringGreen',
+ \ 'SpringGreen1',
+ \ 'SpringGreen2',
+ \ 'SpringGreen3',
+ \ 'SpringGreen4',
+ \ 'SteelBlue',
+ \ 'SteelBlue1',
+ \ 'SteelBlue2',
+ \ 'SteelBlue3',
+ \ 'SteelBlue4',
+ \ 'VioletRed',
+ \ 'VioletRed1',
+ \ 'VioletRed2',
+ \ 'VioletRed3',
+ \ 'VioletRed4',
+ \ 'WhiteSmoke',
+ \ 'YellowGreen',
+ \ 'alice blue',
+ \ 'antique white',
+ \ 'aquamarine',
+ \ 'aquamarine1',
+ \ 'aquamarine2',
+ \ 'aquamarine3',
+ \ 'aquamarine4',
+ \ 'azure',
+ \ 'azure1',
+ \ 'azure2',
+ \ 'azure3',
+ \ 'azure4',
+ \ 'beige',
+ \ 'bisque',
+ \ 'bisque1',
+ \ 'bisque2',
+ \ 'bisque3',
+ \ 'bisque4',
+ \ 'black',
+ \ 'blanched almond',
+ \ 'blue violet',
+ \ 'blue',
+ \ 'blue1',
+ \ 'blue2',
+ \ 'blue3',
+ \ 'blue4',
+ \ 'brown',
+ \ 'brown1',
+ \ 'brown2',
+ \ 'brown3',
+ \ 'brown4',
+ \ 'burlywood',
+ \ 'burlywood1',
+ \ 'burlywood2',
+ \ 'burlywood3',
+ \ 'burlywood4',
+ \ 'cadet blue',
+ \ 'chartreuse',
+ \ 'chartreuse1',
+ \ 'chartreuse2',
+ \ 'chartreuse3',
+ \ 'chartreuse4',
+ \ 'chocolate',
+ \ 'chocolate1',
+ \ 'chocolate2',
+ \ 'chocolate3',
+ \ 'chocolate4',
+ \ 'coral',
+ \ 'coral1',
+ \ 'coral2',
+ \ 'coral3',
+ \ 'coral4',
+ \ 'cornflower blue',
+ \ 'cornsilk',
+ \ 'cornsilk1',
+ \ 'cornsilk2',
+ \ 'cornsilk3',
+ \ 'cornsilk4',
+ \ 'cyan',
+ \ 'cyan1',
+ \ 'cyan2',
+ \ 'cyan3',
+ \ 'cyan4',
+ \ 'dark blue',
+ \ 'dark cyan',
+ \ 'dark goldenrod',
+ \ 'dark gray',
+ \ 'dark green',
+ \ 'dark grey',
+ \ 'dark khaki',
+ \ 'dark magenta',
+ \ 'dark olive green',
+ \ 'dark orange',
+ \ 'dark orchid',
+ \ 'dark red',
+ \ 'dark salmon',
+ \ 'dark sea green',
+ \ 'dark slate blue',
+ \ 'dark slate gray',
+ \ 'dark slate grey',
+ \ 'dark turquoise',
+ \ 'dark violet',
+ \ 'darkblue',
+ \ 'darkcyan',
+ \ 'darkgray',
+ \ 'darkgreen',
+ \ 'darkgrey',
+ \ 'darkmagenta',
+ \ 'darkred',
+ \ 'darkyellow',
+ \ 'deep pink',
+ \ 'deep sky blue',
+ \ 'dim gray',
+ \ 'dim grey',
+ \ 'dodger blue',
+ \ 'firebrick',
+ \ 'firebrick1',
+ \ 'firebrick2',
+ \ 'firebrick3',
+ \ 'firebrick4',
+ \ 'floral white',
+ \ 'forest green',
+ \ 'gainsboro',
+ \ 'ghost white',
+ \ 'gold',
+ \ 'gold1',
+ \ 'gold2',
+ \ 'gold3',
+ \ 'gold4',
+ \ 'goldenrod',
+ \ 'goldenrod1',
+ \ 'goldenrod2',
+ \ 'goldenrod3',
+ \ 'goldenrod4',
+ \ 'gray',
+ \ 'gray0',
+ \ 'gray1',
+ \ 'gray10',
+ \ 'gray100',
+ \ 'gray11',
+ \ 'gray12',
+ \ 'gray13',
+ \ 'gray14',
+ \ 'gray15',
+ \ 'gray16',
+ \ 'gray17',
+ \ 'gray18',
+ \ 'gray19',
+ \ 'gray2',
+ \ 'gray20',
+ \ 'gray21',
+ \ 'gray22',
+ \ 'gray23',
+ \ 'gray24',
+ \ 'gray25',
+ \ 'gray26',
+ \ 'gray27',
+ \ 'gray28',
+ \ 'gray29',
+ \ 'gray3',
+ \ 'gray30',
+ \ 'gray31',
+ \ 'gray32',
+ \ 'gray33',
+ \ 'gray34',
+ \ 'gray35',
+ \ 'gray36',
+ \ 'gray37',
+ \ 'gray38',
+ \ 'gray39',
+ \ 'gray4',
+ \ 'gray40',
+ \ 'gray41',
+ \ 'gray42',
+ \ 'gray43',
+ \ 'gray44',
+ \ 'gray45',
+ \ 'gray46',
+ \ 'gray47',
+ \ 'gray48',
+ \ 'gray49',
+ \ 'gray5',
+ \ 'gray50',
+ \ 'gray51',
+ \ 'gray52',
+ \ 'gray53',
+ \ 'gray54',
+ \ 'gray55',
+ \ 'gray56',
+ \ 'gray57',
+ \ 'gray58',
+ \ 'gray59',
+ \ 'gray6',
+ \ 'gray60',
+ \ 'gray61',
+ \ 'gray62',
+ \ 'gray63',
+ \ 'gray64',
+ \ 'gray65',
+ \ 'gray66',
+ \ 'gray67',
+ \ 'gray68',
+ \ 'gray69',
+ \ 'gray7',
+ \ 'gray70',
+ \ 'gray71',
+ \ 'gray72',
+ \ 'gray73',
+ \ 'gray74',
+ \ 'gray75',
+ \ 'gray76',
+ \ 'gray77',
+ \ 'gray78',
+ \ 'gray79',
+ \ 'gray8',
+ \ 'gray80',
+ \ 'gray81',
+ \ 'gray82',
+ \ 'gray83',
+ \ 'gray84',
+ \ 'gray85',
+ \ 'gray86',
+ \ 'gray87',
+ \ 'gray88',
+ \ 'gray89',
+ \ 'gray9',
+ \ 'gray90',
+ \ 'gray91',
+ \ 'gray92',
+ \ 'gray93',
+ \ 'gray94',
+ \ 'gray95',
+ \ 'gray96',
+ \ 'gray97',
+ \ 'gray98',
+ \ 'gray99',
+ \ 'green yellow',
+ \ 'green',
+ \ 'green1',
+ \ 'green2',
+ \ 'green3',
+ \ 'green4',
+ \ 'grey',
+ \ 'grey0',
+ \ 'grey1',
+ \ 'grey10',
+ \ 'grey100',
+ \ 'grey11',
+ \ 'grey12',
+ \ 'grey13',
+ \ 'grey14',
+ \ 'grey15',
+ \ 'grey16',
+ \ 'grey17',
+ \ 'grey18',
+ \ 'grey19',
+ \ 'grey2',
+ \ 'grey20',
+ \ 'grey21',
+ \ 'grey22',
+ \ 'grey23',
+ \ 'grey24',
+ \ 'grey25',
+ \ 'grey26',
+ \ 'grey27',
+ \ 'grey28',
+ \ 'grey29',
+ \ 'grey3',
+ \ 'grey30',
+ \ 'grey31',
+ \ 'grey32',
+ \ 'grey33',
+ \ 'grey34',
+ \ 'grey35',
+ \ 'grey36',
+ \ 'grey37',
+ \ 'grey38',
+ \ 'grey39',
+ \ 'grey4',
+ \ 'grey40',
+ \ 'grey41',
+ \ 'grey42',
+ \ 'grey43',
+ \ 'grey44',
+ \ 'grey45',
+ \ 'grey46',
+ \ 'grey47',
+ \ 'grey48',
+ \ 'grey49',
+ \ 'grey5',
+ \ 'grey50',
+ \ 'grey51',
+ \ 'grey52',
+ \ 'grey53',
+ \ 'grey54',
+ \ 'grey55',
+ \ 'grey56',
+ \ 'grey57',
+ \ 'grey58',
+ \ 'grey59',
+ \ 'grey6',
+ \ 'grey60',
+ \ 'grey61',
+ \ 'grey62',
+ \ 'grey63',
+ \ 'grey64',
+ \ 'grey65',
+ \ 'grey66',
+ \ 'grey67',
+ \ 'grey68',
+ \ 'grey69',
+ \ 'grey7',
+ \ 'grey70',
+ \ 'grey71',
+ \ 'grey72',
+ \ 'grey73',
+ \ 'grey74',
+ \ 'grey75',
+ \ 'grey76',
+ \ 'grey77',
+ \ 'grey78',
+ \ 'grey79',
+ \ 'grey8',
+ \ 'grey80',
+ \ 'grey81',
+ \ 'grey82',
+ \ 'grey83',
+ \ 'grey84',
+ \ 'grey85',
+ \ 'grey86',
+ \ 'grey87',
+ \ 'grey88',
+ \ 'grey89',
+ \ 'grey9',
+ \ 'grey90',
+ \ 'grey91',
+ \ 'grey92',
+ \ 'grey93',
+ \ 'grey94',
+ \ 'grey95',
+ \ 'grey96',
+ \ 'grey97',
+ \ 'grey98',
+ \ 'grey99',
+ \ 'honeydew',
+ \ 'honeydew1',
+ \ 'honeydew2',
+ \ 'honeydew3',
+ \ 'honeydew4',
+ \ 'hot pink',
+ \ 'indian red',
+ \ 'ivory',
+ \ 'ivory1',
+ \ 'ivory2',
+ \ 'ivory3',
+ \ 'ivory4',
+ \ 'khaki',
+ \ 'khaki1',
+ \ 'khaki2',
+ \ 'khaki3',
+ \ 'khaki4',
+ \ 'lavender blush',
+ \ 'lavender',
+ \ 'lawn green',
+ \ 'lemon chiffon',
+ \ 'light blue',
+ \ 'light coral',
+ \ 'light cyan',
+ \ 'light goldenrod yellow',
+ \ 'light goldenrod',
+ \ 'light gray',
+ \ 'light green',
+ \ 'light grey',
+ \ 'light pink',
+ \ 'light salmon',
+ \ 'light sea green',
+ \ 'light sky blue',
+ \ 'light slate blue',
+ \ 'light slate gray',
+ \ 'light slate grey',
+ \ 'light steel blue',
+ \ 'light yellow',
+ \ 'lightblue',
+ \ 'lightcyan',
+ \ 'lightgray',
+ \ 'lightgreen',
+ \ 'lightgrey',
+ \ 'lightmagenta',
+ \ 'lightred',
+ \ 'lightyellow',
+ \ 'lime green',
+ \ 'linen',
+ \ 'magenta',
+ \ 'magenta1',
+ \ 'magenta2',
+ \ 'magenta3',
+ \ 'magenta4',
+ \ 'maroon',
+ \ 'maroon1',
+ \ 'maroon2',
+ \ 'maroon3',
+ \ 'maroon4',
+ \ 'medium aquamarine',
+ \ 'medium blue',
+ \ 'medium orchid',
+ \ 'medium purple',
+ \ 'medium sea green',
+ \ 'medium slate blue',
+ \ 'medium spring green',
+ \ 'medium turquoise',
+ \ 'medium violet red',
+ \ 'midnight blue',
+ \ 'mint cream',
+ \ 'misty rose',
+ \ 'moccasin',
+ \ 'navajo white',
+ \ 'navy blue',
+ \ 'navy',
+ \ 'old lace',
+ \ 'olive drab',
+ \ 'orange red',
+ \ 'orange',
+ \ 'orange1',
+ \ 'orange2',
+ \ 'orange3',
+ \ 'orange4',
+ \ 'orchid',
+ \ 'orchid1',
+ \ 'orchid2',
+ \ 'orchid3',
+ \ 'orchid4',
+ \ 'pale goldenrod',
+ \ 'pale green',
+ \ 'pale turquoise',
+ \ 'pale violet red',
+ \ 'papaya whip',
+ \ 'peach puff',
+ \ 'peru',
+ \ 'pink',
+ \ 'pink1',
+ \ 'pink2',
+ \ 'pink3',
+ \ 'pink4',
+ \ 'plum',
+ \ 'plum1',
+ \ 'plum2',
+ \ 'plum3',
+ \ 'plum4',
+ \ 'powder blue',
+ \ 'purple',
+ \ 'purple1',
+ \ 'purple2',
+ \ 'purple3',
+ \ 'purple4',
+ \ 'red',
+ \ 'red1',
+ \ 'red2',
+ \ 'red3',
+ \ 'red4',
+ \ 'rosy brown',
+ \ 'royal blue',
+ \ 'saddle brown',
+ \ 'salmon',
+ \ 'salmon1',
+ \ 'salmon2',
+ \ 'salmon3',
+ \ 'salmon4',
+ \ 'sandy brown',
+ \ 'sea green',
+ \ 'seagreen',
+ \ 'seashell',
+ \ 'seashell1',
+ \ 'seashell2',
+ \ 'seashell3',
+ \ 'seashell4',
+ \ 'sienna',
+ \ 'sienna1',
+ \ 'sienna2',
+ \ 'sienna3',
+ \ 'sienna4',
+ \ 'sky blue',
+ \ 'slate blue',
+ \ 'slate gray',
+ \ 'slate grey',
+ \ 'slateblue',
+ \ 'snow',
+ \ 'snow1',
+ \ 'snow2',
+ \ 'snow3',
+ \ 'snow4',
+ \ 'spring green',
+ \ 'steel blue',
+ \ 'tan',
+ \ 'tan1',
+ \ 'tan2',
+ \ 'tan3',
+ \ 'tan4',
+ \ 'thistle',
+ \ 'thistle1',
+ \ 'thistle2',
+ \ 'thistle3',
+ \ 'thistle4',
+ \ 'tomato',
+ \ 'tomato1',
+ \ 'tomato2',
+ \ 'tomato3',
+ \ 'tomato4',
+ \ 'turquoise',
+ \ 'turquoise1',
+ \ 'turquoise2',
+ \ 'turquoise3',
+ \ 'turquoise4',
+ \ 'violet red',
+ \ 'violet',
+ \ 'wheat',
+ \ 'wheat1',
+ \ 'wheat2',
+ \ 'wheat3',
+ \ 'wheat4',
+ \ 'white smoke',
+ \ 'white',
+ \ 'yellow green',
+ \ 'yellow',
+ \ 'yellow1',
+ \ 'yellow2',
+ \ 'yellow3',
+ \ 'yellow4',
+ \ ]
+ for color in colors
+ " just test that the color name can be found.
+ exe "hi Mine guifg='" . color . "'"
+ endfor
+
+ " case is ignored
+ hi Mine guifg=blanchedalmond
+ hi Mine guifg=BLANCHEDALMOND
+endfunc
diff --git a/src/testdir/test_syntax.vim b/src/testdir/test_syntax.vim
new file mode 100644
index 0000000..c0be4a0
--- /dev/null
+++ b/src/testdir/test_syntax.vim
@@ -0,0 +1,585 @@
+" Test for syntax and syntax iskeyword option
+
+if !has("syntax")
+ finish
+endif
+
+source view_util.vim
+source screendump.vim
+
+func GetSyntaxItem(pat)
+ let c = ''
+ let a = ['a', getreg('a'), getregtype('a')]
+ 0
+ redraw!
+ call search(a:pat, 'W')
+ let synid = synID(line('.'), col('.'), 1)
+ while synid == synID(line('.'), col('.'), 1)
+ norm! v"ay
+ " stop at whitespace
+ if @a =~# '\s'
+ break
+ endif
+ let c .= @a
+ norm! l
+ endw
+ call call('setreg', a)
+ 0
+ return c
+endfunc
+
+func Test_syn_iskeyword()
+ new
+ call setline(1, [
+ \ 'CREATE TABLE FOOBAR(',
+ \ ' DLTD_BY VARCHAR2(100)',
+ \ ');',
+ \ ''])
+
+ syntax on
+ set ft=sql
+ syn match SYN /C\k\+\>/
+ hi link SYN ErrorMsg
+ call assert_equal('DLTD_BY', GetSyntaxItem('DLTD'))
+ /\<D\k\+\>/:norm! ygn
+ call assert_equal('DLTD_BY', @0)
+ redir @c
+ syn iskeyword
+ redir END
+ call assert_equal("\nsyntax iskeyword not set", @c)
+
+ syn iskeyword @,48-57,_,192-255
+ redir @c
+ syn iskeyword
+ redir END
+ call assert_equal("\nsyntax iskeyword @,48-57,_,192-255", @c)
+
+ setlocal isk-=_
+ call assert_equal('DLTD_BY', GetSyntaxItem('DLTD'))
+ /\<D\k\+\>/:norm! ygn
+ let b2 = @0
+ call assert_equal('DLTD', @0)
+
+ syn iskeyword clear
+ redir @c
+ syn iskeyword
+ redir END
+ call assert_equal("\nsyntax iskeyword not set", @c)
+
+ quit!
+endfunc
+
+func Test_syntax_after_reload()
+ split Xsomefile
+ call setline(1, ['hello', 'there'])
+ w!
+ only!
+ setl filetype=hello
+ au FileType hello let g:gotit = 1
+ call assert_false(exists('g:gotit'))
+ edit other
+ buf Xsomefile
+ call assert_equal('hello', &filetype)
+ call assert_true(exists('g:gotit'))
+ call delete('Xsomefile')
+endfunc
+
+func Test_syntime()
+ if !has('profile')
+ return
+ endif
+
+ syntax on
+ syntime on
+ let a = execute('syntime report')
+ call assert_equal("\nNo Syntax items defined for this buffer", a)
+
+ view ../memfile_test.c
+ setfiletype cpp
+ redraw
+ let a = execute('syntime report')
+ call assert_match('^ TOTAL *COUNT *MATCH *SLOWEST *AVERAGE *NAME *PATTERN', a)
+ call assert_match(' \d*\.\d* \+[^0]\d* .* cppRawString ', a)
+ call assert_match(' \d*\.\d* \+[^0]\d* .* cppNumber ', a)
+
+ syntime off
+ syntime clear
+ let a = execute('syntime report')
+ call assert_match('^ TOTAL *COUNT *MATCH *SLOWEST *AVERAGE *NAME *PATTERN', a)
+ call assert_notmatch('.* cppRawString *', a)
+ call assert_notmatch('.* cppNumber*', a)
+ call assert_notmatch('[1-9]', a)
+
+ call assert_fails('syntime abc', 'E475')
+
+ syntax clear
+ let a = execute('syntime report')
+ call assert_equal("\nNo Syntax items defined for this buffer", a)
+
+ bd
+endfunc
+
+func Test_syntime_completion()
+ if !has('profile')
+ return
+ endif
+
+ call feedkeys(":syntime \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"syntime clear off on report', @:)
+endfunc
+
+func Test_syntax_list()
+ syntax on
+ let a = execute('syntax list')
+ call assert_equal("\nNo Syntax items defined for this buffer", a)
+
+ view ../memfile_test.c
+ setfiletype c
+
+ let a = execute('syntax list')
+ call assert_match('cInclude*', a)
+ call assert_match('cDefine', a)
+
+ let a = execute('syntax list cDefine')
+ call assert_notmatch('cInclude*', a)
+ call assert_match('cDefine', a)
+ call assert_match(' links to Macro$', a)
+
+ call assert_fails('syntax list ABCD', 'E28:')
+ call assert_fails('syntax list @ABCD', 'E392:')
+
+ syntax clear
+ let a = execute('syntax list')
+ call assert_equal("\nNo Syntax items defined for this buffer", a)
+
+ bd
+endfunc
+
+func Test_syntax_completion()
+ call feedkeys(":syn \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"syn case clear cluster conceal enable include iskeyword keyword list manual match off on region reset spell sync', @:)
+
+ call feedkeys(":syn case \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"syn case ignore match', @:)
+
+ call feedkeys(":syn spell \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"syn spell default notoplevel toplevel', @:)
+
+ call feedkeys(":syn sync \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"syn sync ccomment clear fromstart linebreaks= linecont lines= match maxlines= minlines= region', @:)
+
+ " Check that clearing "Aap" avoids it showing up before Boolean.
+ hi Aap ctermfg=blue
+ call feedkeys(":syn list \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_match('^"syn list Aap Boolean Character ', @:)
+ hi clear Aap
+
+ call feedkeys(":syn list \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_match('^"syn list Boolean Character ', @:)
+
+ call feedkeys(":syn match \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_match('^"syn match Boolean Character ', @:)
+endfunc
+
+func Test_syntax_arg_skipped()
+ syn clear
+ syntax case ignore
+ if 0
+ syntax case match
+ endif
+ call assert_match('case ignore', execute('syntax case'))
+
+ syn keyword Foo foo
+ call assert_match('Foo', execute('syntax'))
+ syn clear
+ call assert_match('case match', execute('syntax case'))
+ call assert_notmatch('Foo', execute('syntax'))
+
+ if has('conceal')
+ syn clear
+ syntax conceal on
+ if 0
+ syntax conceal off
+ endif
+ call assert_match('conceal on', execute('syntax conceal'))
+ syn clear
+ call assert_match('conceal off', execute('syntax conceal'))
+
+ syntax conceal on
+ syntax conceal off
+ call assert_match('conceal off', execute('syntax conceal'))
+ endif
+
+ syntax region Bar start=/</ end=/>/
+ if 0
+ syntax region NotTest start=/</ end=/>/ contains=@Spell
+ endif
+ call assert_match('Bar', execute('syntax'))
+ call assert_notmatch('NotTest', execute('syntax'))
+ call assert_notmatch('Spell', execute('syntax'))
+
+ hi Foo ctermfg=blue
+ let a = execute('hi Foo')
+ if 0
+ syntax rest
+ endif
+ call assert_equal(a, execute('hi Foo'))
+ hi clear Bar
+ hi clear Foo
+
+ set ft=tags
+ syn off
+ if 0
+ syntax enable
+ endif
+ call assert_match('No Syntax items defined', execute('syntax'))
+ syntax enable
+ call assert_match('tagComment', execute('syntax'))
+ set ft=
+
+ syn clear
+ if 0
+ syntax include @Spell nothing
+ endif
+ call assert_notmatch('Spell', execute('syntax'))
+
+ syn clear
+ syn iskeyword 48-57,$,_
+ call assert_match('48-57,$,_', execute('syntax iskeyword'))
+ if 0
+ syn clear
+ syn iskeyword clear
+ endif
+ call assert_match('48-57,$,_', execute('syntax iskeyword'))
+ syn iskeyword clear
+ call assert_match('not set', execute('syntax iskeyword'))
+ syn iskeyword 48-57,$,_
+ syn clear
+ call assert_match('not set', execute('syntax iskeyword'))
+
+ syn clear
+ syn keyword Foo foo
+ if 0
+ syn keyword NotAdded bar
+ endif
+ call assert_match('Foo', execute('syntax'))
+ call assert_notmatch('NotAdded', execute('highlight'))
+
+ syn clear
+ syn keyword Foo foo
+ call assert_match('Foo', execute('syntax'))
+ call assert_match('Foo', execute('syntax list'))
+ call assert_notmatch('Foo', execute('if 0 | syntax | endif'))
+ call assert_notmatch('Foo', execute('if 0 | syntax list | endif'))
+
+ syn clear
+ syn match Fopi /asdf/
+ if 0
+ syn match Fopx /asdf/
+ endif
+ call assert_match('Fopi', execute('syntax'))
+ call assert_notmatch('Fopx', execute('syntax'))
+
+ syn clear
+ syn spell toplevel
+ call assert_match('spell toplevel', execute('syntax spell'))
+ if 0
+ syn spell notoplevel
+ endif
+ call assert_match('spell toplevel', execute('syntax spell'))
+ syn spell notoplevel
+ call assert_match('spell notoplevel', execute('syntax spell'))
+ syn spell default
+ call assert_match('spell default', execute('syntax spell'))
+
+ syn clear
+ if 0
+ syntax cluster Spell
+ endif
+ call assert_notmatch('Spell', execute('syntax'))
+
+ syn clear
+ syn keyword Foo foo
+ syn sync ccomment
+ syn sync maxlines=5
+ if 0
+ syn sync maxlines=11
+ endif
+ call assert_match('on C-style comments', execute('syntax sync'))
+ call assert_match('maximal 5 lines', execute('syntax sync'))
+ syn sync clear
+ if 0
+ syn sync ccomment
+ endif
+ call assert_notmatch('on C-style comments', execute('syntax sync'))
+
+ syn clear
+endfunc
+
+func Test_syntax_invalid_arg()
+ call assert_fails('syntax case asdf', 'E390:')
+ if has('conceal')
+ call assert_fails('syntax conceal asdf', 'E390:')
+ endif
+ call assert_fails('syntax spell asdf', 'E390:')
+ call assert_fails('syntax clear @ABCD', 'E391:')
+ call assert_fails('syntax include @Xxx', 'E397:')
+ call assert_fails('syntax region X start="{"', 'E399:')
+ call assert_fails('syntax sync x', 'E404:')
+ call assert_fails('syntax keyword Abc a[', 'E789:')
+ call assert_fails('syntax keyword Abc a[bc]d', 'E890:')
+endfunc
+
+func Test_syn_sync()
+ syntax region HereGroup start=/this/ end=/that/
+ syntax sync match SyncHere grouphere HereGroup "pattern"
+ call assert_match('SyncHere', execute('syntax sync'))
+ syn sync clear
+ call assert_notmatch('SyncHere', execute('syntax sync'))
+ syn clear
+endfunc
+
+func Test_syn_clear()
+ syntax keyword Foo foo
+ syntax keyword Bar tar
+ call assert_match('Foo', execute('syntax'))
+ call assert_match('Bar', execute('syntax'))
+ call assert_equal('Foo', synIDattr(hlID("Foo"), "name"))
+ syn clear Foo
+ call assert_notmatch('Foo', execute('syntax'))
+ call assert_match('Bar', execute('syntax'))
+ call assert_equal('Foo', synIDattr(hlID("Foo"), "name"))
+ syn clear Foo Bar
+ call assert_notmatch('Foo', execute('syntax'))
+ call assert_notmatch('Bar', execute('syntax'))
+ hi clear Foo
+ call assert_equal('Foo', synIDattr(hlID("Foo"), "name"))
+ hi clear Bar
+endfunc
+
+func Test_invalid_name()
+ syn clear
+ syn keyword Nop yes
+ call assert_fails("syntax keyword Wr\x17ong bar", 'E669:')
+ syntax keyword @Wrong bar
+ call assert_match('W18:', execute('1messages'))
+ syn clear
+ hi clear Nop
+ hi clear @Wrong
+endfunc
+
+func Test_ownsyntax()
+ new Xfoo
+ call setline(1, '#define FOO')
+ syntax on
+ set filetype=c
+ ownsyntax perl
+ call assert_equal('perlComment', synIDattr(synID(line('.'), col('.'), 1), 'name'))
+ call assert_equal('c', b:current_syntax)
+ call assert_equal('perl', w:current_syntax)
+
+ " A new split window should have the original syntax.
+ split
+ call assert_equal('cDefine', synIDattr(synID(line('.'), col('.'), 1), 'name'))
+ call assert_equal('c', b:current_syntax)
+ call assert_equal(0, exists('w:current_syntax'))
+
+ wincmd x
+ call assert_equal('perlComment', synIDattr(synID(line("."), col("."), 1), "name"))
+
+ syntax off
+ set filetype&
+ %bw!
+endfunc
+
+func Test_ownsyntax_completion()
+ call feedkeys(":ownsyntax java\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"ownsyntax java javacc javascript', @:)
+endfunc
+
+func Test_highlight_invalid_arg()
+ if has('gui_running')
+ call assert_fails('hi XXX guifg=xxx', 'E254:')
+ endif
+ call assert_fails('hi DoesNotExist', 'E411:')
+ call assert_fails('hi link', 'E412:')
+ call assert_fails('hi link a', 'E412:')
+ call assert_fails('hi link a b c', 'E413:')
+ call assert_fails('hi XXX =', 'E415:')
+ call assert_fails('hi XXX cterm', 'E416:')
+ call assert_fails('hi XXX cterm=', 'E417:')
+ call assert_fails('hi XXX cterm=DoesNotExist', 'E418:')
+ call assert_fails('hi XXX ctermfg=DoesNotExist', 'E421:')
+ call assert_fails('hi XXX xxx=White', 'E423:')
+endfunc
+
+func Test_bg_detection()
+ if has('gui_running')
+ return
+ endif
+ " auto-detection of &bg, make sure sure it isn't set anywhere before
+ " this test
+ hi Normal ctermbg=0
+ call assert_equal('dark', &bg)
+ hi Normal ctermbg=4
+ call assert_equal('dark', &bg)
+ hi Normal ctermbg=12
+ call assert_equal('light', &bg)
+ hi Normal ctermbg=15
+ call assert_equal('light', &bg)
+
+ " manually-set &bg takes precedence over auto-detection
+ set bg=light
+ hi Normal ctermbg=4
+ call assert_equal('light', &bg)
+ set bg=dark
+ hi Normal ctermbg=12
+ call assert_equal('dark', &bg)
+
+ hi Normal ctermbg=NONE
+endfunc
+
+func Test_syntax_hangs()
+ if !has('reltime') || !has('float') || !has('syntax')
+ return
+ endif
+
+ " This pattern takes a long time to match, it should timeout.
+ new
+ call setline(1, ['aaa', repeat('abc ', 1000), 'ccc'])
+ let start = reltime()
+ set nolazyredraw redrawtime=101
+ syn match Error /\%#=1a*.*X\@<=b*/
+ redraw
+ let elapsed = reltimefloat(reltime(start))
+ call assert_true(elapsed > 0.1)
+ call assert_true(elapsed < 1.0)
+
+ " second time syntax HL is disabled
+ let start = reltime()
+ redraw
+ let elapsed = reltimefloat(reltime(start))
+ call assert_true(elapsed < 0.1)
+
+ " after CTRL-L the timeout flag is reset
+ let start = reltime()
+ exe "normal \<C-L>"
+ redraw
+ let elapsed = reltimefloat(reltime(start))
+ call assert_true(elapsed > 0.1)
+ call assert_true(elapsed < 1.0)
+
+ set redrawtime&
+ bwipe!
+endfunc
+
+func Test_conceal()
+ if !has('conceal')
+ return
+ endif
+
+ new
+ call setline(1, ['', '123456'])
+ syn match test23 "23" conceal cchar=X
+ syn match test45 "45" conceal
+
+ set conceallevel=0
+ call assert_equal('123456 ', ScreenLines(2, 7)[0])
+ call assert_equal([[0, '', 0], [0, '', 0], [0, '', 0], [0, '', 0], [0, '', 0], [0, '', 0]], map(range(1, 6), 'synconcealed(2, v:val)'))
+
+ set conceallevel=1
+ call assert_equal('1X 6 ', ScreenLines(2, 7)[0])
+ call assert_equal([[0, '', 0], [1, 'X', 1], [1, 'X', 1], [1, ' ', 2], [1, ' ', 2], [0, '', 0]], map(range(1, 6), 'synconcealed(2, v:val)'))
+
+ set conceallevel=1
+ set listchars=conceal:Y
+ call assert_equal([[0, '', 0], [1, 'X', 1], [1, 'X', 1], [1, 'Y', 2], [1, 'Y', 2], [0, '', 0]], map(range(1, 6), 'synconcealed(2, v:val)'))
+ call assert_equal('1XY6 ', ScreenLines(2, 7)[0])
+
+ set conceallevel=2
+ call assert_match('1X6 ', ScreenLines(2, 7)[0])
+ call assert_equal([[0, '', 0], [1, 'X', 1], [1, 'X', 1], [1, '', 2], [1, '', 2], [0, '', 0]], map(range(1, 6), 'synconcealed(2, v:val)'))
+
+ set conceallevel=3
+ call assert_match('16 ', ScreenLines(2, 7)[0])
+ call assert_equal([[0, '', 0], [1, '', 1], [1, '', 1], [1, '', 2], [1, '', 2], [0, '', 0]], map(range(1, 6), 'synconcealed(2, v:val)'))
+
+ syn clear
+ set conceallevel&
+ bw!
+endfunc
+
+func Test_synstack_synIDtrans()
+ new
+ setfiletype c
+ syntax on
+ call setline(1, ' /* A comment with a TODO */')
+
+ call assert_equal([], synstack(1, 1))
+
+ norm f/
+ call assert_equal(['cComment', 'cCommentStart'], map(synstack(line("."), col(".")), 'synIDattr(v:val, "name")'))
+ call assert_equal(['Comment', 'Comment'], map(synstack(line("."), col(".")), 'synIDattr(synIDtrans(v:val), "name")'))
+
+ norm fA
+ call assert_equal(['cComment'], map(synstack(line("."), col(".")), 'synIDattr(v:val, "name")'))
+ call assert_equal(['Comment'], map(synstack(line("."), col(".")), 'synIDattr(synIDtrans(v:val), "name")'))
+
+ norm fT
+ call assert_equal(['cComment', 'cTodo'], map(synstack(line("."), col(".")), 'synIDattr(v:val, "name")'))
+ call assert_equal(['Comment', 'Todo'], map(synstack(line("."), col(".")), 'synIDattr(synIDtrans(v:val), "name")'))
+
+ syn clear
+ bw!
+endfunc
+
+" Check highlighting for a small piece of C code with a screen dump.
+func Test_syntax_c()
+ if !CanRunVimInTerminal()
+ return
+ endif
+ call writefile([
+ \ '/* comment line at the top */',
+ \ ' int',
+ \ 'main(int argc, char **argv)// another comment',
+ \ '{',
+ \ '#if 0',
+ \ ' int not_used;',
+ \ '#else',
+ \ ' int used;',
+ \ '#endif',
+ \ ' printf("Just an example piece of C code\n");',
+ \ ' return 0x0ff;',
+ \ '}',
+ \ ' static void',
+ \ 'myFunction(const double count, struct nothing, long there) {',
+ \ ' // 123: nothing to read here',
+ \ ' for (int i = 0; i < count; ++i) {',
+ \ ' break;',
+ \ ' }',
+ \ '}',
+ \ ], 'Xtest.c')
+
+ " This makes the default for 'background' use "dark", check that the
+ " response to t_RB corrects it to "light".
+ let $COLORFGBG = '15;0'
+
+ let buf = RunVimInTerminal('Xtest.c', {})
+ call VerifyScreenDump(buf, 'Test_syntax_c_01', {})
+ call StopVimInTerminal(buf)
+
+ let $COLORFGBG = ''
+ call delete('Xtest.c')
+endfun
+
+" Using \z() in a region with NFA failing should not crash.
+func Test_syn_wrong_z_one()
+ new
+ call setline(1, ['just some text', 'with foo and bar to match with'])
+ syn region FooBar start="foo\z(.*\)bar" end="\z1"
+ call test_override("nfa_fail", 1)
+ redraw!
+ redraw!
+ call test_override("ALL", 0)
+ bwipe!
+endfunc
diff --git a/src/testdir/test_system.vim b/src/testdir/test_system.vim
new file mode 100644
index 0000000..25061ea
--- /dev/null
+++ b/src/testdir/test_system.vim
@@ -0,0 +1,92 @@
+" Tests for system() and systemlist()
+
+func Test_System()
+ if !executable('echo') || !executable('cat') || !executable('wc')
+ return
+ endif
+ let out = system('echo 123')
+ " On Windows we may get a trailing space.
+ if out != "123 \n"
+ call assert_equal("123\n", out)
+ endif
+
+ let out = systemlist('echo 123')
+ " On Windows we may get a trailing space and CR.
+ if out != ["123 \r"]
+ call assert_equal(['123'], out)
+ endif
+
+ call assert_equal('123', system('cat', '123'))
+ call assert_equal(['123'], systemlist('cat', '123'))
+ call assert_equal(["as\<NL>df"], systemlist('cat', ["as\<NL>df"]))
+
+ new Xdummy
+ call setline(1, ['asdf', "pw\<NL>er", 'xxxx'])
+ let out = system('wc -l', bufnr('%'))
+ " On OS/X we get leading spaces
+ let out = substitute(out, '^ *', '', '')
+ call assert_equal("3\n", out)
+
+ let out = systemlist('wc -l', bufnr('%'))
+ " On Windows we may get a trailing CR.
+ if out != ["3\r"]
+ " On OS/X we get leading spaces
+ if type(out) == v:t_list
+ let out[0] = substitute(out[0], '^ *', '', '')
+ endif
+ call assert_equal(['3'], out)
+ endif
+
+ let out = systemlist('cat', bufnr('%'))
+ " On Windows we may get a trailing CR.
+ if out != ["asdf\r", "pw\<NL>er\r", "xxxx\r"]
+ call assert_equal(['asdf', "pw\<NL>er", 'xxxx'], out)
+ endif
+ bwipe!
+
+ call assert_fails('call system("wc -l", 99999)', 'E86:')
+endfunc
+
+func Test_system_exmode()
+ if has('unix') " echo $? only works on Unix
+ let cmd = ' -es -u NONE -c "source Xscript" +q; echo "result=$?"'
+ " Need to put this in a script, "catch" isn't found after an unknown
+ " function.
+ call writefile(['try', 'call doesnotexist()', 'catch', 'endtry'], 'Xscript')
+ let a = system(v:progpath . cmd)
+ call assert_match('result=0', a)
+ call assert_equal(0, v:shell_error)
+ endif
+
+ " Error before try does set error flag.
+ call writefile(['call nosuchfunction()', 'try', 'call doesnotexist()', 'catch', 'endtry'], 'Xscript')
+ if has('unix') " echo $? only works on Unix
+ let a = system(v:progpath . cmd)
+ call assert_notequal('0', a[0])
+ endif
+
+ let cmd = ' -es -u NONE -c "source Xscript" +q'
+ let a = system(v:progpath . cmd)
+ call assert_notequal(0, v:shell_error)
+ call delete('Xscript')
+
+ if has('unix') " echo $? only works on Unix
+ let cmd = ' -es -u NONE -c "call doesnotexist()" +q; echo $?'
+ let a = system(v:progpath. cmd)
+ call assert_notequal(0, a[0])
+ endif
+
+ let cmd = ' -es -u NONE -c "call doesnotexist()" +q'
+ let a = system(v:progpath. cmd)
+ call assert_notequal(0, v:shell_error)
+
+ if has('unix') " echo $? only works on Unix
+ let cmd = ' -es -u NONE -c "call doesnotexist()|let a=1" +q; echo $?'
+ let a = system(v:progpath. cmd)
+ call assert_notequal(0, a[0])
+ endif
+
+ let cmd = ' -es -u NONE -c "call doesnotexist()|let a=1" +q'
+ let a = system(v:progpath. cmd)
+ call assert_notequal(0, v:shell_error)
+endfunc
diff --git a/src/testdir/test_tab.vim b/src/testdir/test_tab.vim
new file mode 100644
index 0000000..b8e8dfe
--- /dev/null
+++ b/src/testdir/test_tab.vim
@@ -0,0 +1,90 @@
+" Various tests for inserting a Tab.
+
+" Tests for "r<Tab>" with 'smarttab' and 'expandtab' set/not set.
+" Also test that dv_ works correctly
+func Test_smarttab()
+ enew!
+ set smarttab expandtab ts=8 sw=4
+ " make sure that backspace works, no matter what termcap is used
+ exe "set t_kD=\<C-V>x7f t_kb=\<C-V>x08"
+ call append(0, ['start text',
+ \ "\t\tsome test text",
+ \ 'test text',
+ \ "\t\tother test text",
+ \ ' a cde',
+ \ ' f ghi',
+ \ 'test text',
+ \ ' Second line beginning with whitespace'
+ \ ])
+ call cursor(1, 1)
+ exe "normal /some\<CR>"
+ exe "normal r\t"
+ call assert_equal("\t\t ome test text", getline('.'))
+ set noexpandtab
+ exe "normal /other\<CR>"
+ exe "normal r\t"
+ call assert_equal("\t\t ther test text", getline('.'))
+
+ " Test replacing with Tabs and then backspacing to undo it
+ exe "normal j0wR\t\t\t\<BS>\<BS>\<BS>"
+ call assert_equal(" a cde", getline('.'))
+ " Test replacing with Tabs
+ exe "normal j0wR\t\t\t"
+ call assert_equal(" \t\thi", getline('.'))
+
+ " Test that copyindent works with expandtab set
+ set expandtab smartindent copyindent ts=8 sw=8 sts=8
+ exe "normal jo{\<CR>x"
+ call assert_equal('{', getline(line('.') - 1))
+ call assert_equal(' x', getline('.'))
+ set nosol
+ exe "normal /Second line/\<CR>"
+ exe "normal fwdv_"
+ call assert_equal(' with whitespace', getline('.'))
+ enew!
+ set expandtab& smartindent& copyindent& ts& sw& sts&
+endfunc
+
+func Test_softtabstop()
+ new
+ set sts=0 sw=0
+ exe "normal ix\<Tab>x\<Esc>"
+ call assert_equal("x\tx", getline(1))
+
+ call setline(1, '')
+ set sts=4
+ exe "normal ix\<Tab>x\<Esc>"
+ call assert_equal("x x", getline(1))
+
+ call setline(1, '')
+ set sts=-1 sw=4
+ exe "normal ix\<Tab>x\<Esc>"
+ call assert_equal("x x", getline(1))
+
+ call setline(1, 'x ')
+ set sts=0 sw=0 backspace=start
+ exe "normal A\<BS>x\<Esc>"
+ call assert_equal("x x", getline(1))
+
+ call setline(1, 'x ')
+ set sts=4
+ exe "normal A\<BS>x\<Esc>"
+ call assert_equal("x x", getline(1))
+
+ call setline(1, 'x ')
+ set sts=-1 sw=4
+ exe "normal A\<BS>x\<Esc>"
+ call assert_equal("x x", getline(1))
+
+ call setline(1, 'x')
+ set sts=-1 sw=0 smarttab
+ exe "normal I\<Tab>\<Esc>"
+ call assert_equal("\tx", getline(1))
+
+ call setline(1, 'x')
+ exe "normal I\<Tab>\<BS>\<Esc>"
+ call assert_equal("x", getline(1))
+
+ set sts=0 sw=0 backspace& nosmarttab
+ bwipe!
+endfunc
diff --git a/src/testdir/test_tabline.vim b/src/testdir/test_tabline.vim
new file mode 100644
index 0000000..383d239
--- /dev/null
+++ b/src/testdir/test_tabline.vim
@@ -0,0 +1,72 @@
+
+source shared.vim
+
+func TablineWithCaughtError()
+ let s:func_in_tabline_called = 1
+ try
+ call eval('unknown expression')
+ catch
+ endtry
+ return ''
+endfunc
+
+func TablineWithError()
+ let s:func_in_tabline_called = 1
+ call eval('unknown expression')
+ return ''
+endfunc
+
+func Test_caught_error_in_tabline()
+ if has('gui')
+ set guioptions-=e
+ endif
+ let showtabline_save = &showtabline
+ set showtabline=2
+ let s:func_in_tabline_called = 0
+ let tabline = '%{TablineWithCaughtError()}'
+ let &tabline = tabline
+ redraw!
+ call assert_true(s:func_in_tabline_called)
+ call assert_equal(tabline, &tabline)
+ set tabline=
+ let &showtabline = showtabline_save
+endfunc
+
+func Test_tabline_will_be_disabled_with_error()
+ if has('gui')
+ set guioptions-=e
+ endif
+ let showtabline_save = &showtabline
+ set showtabline=2
+ let s:func_in_tabline_called = 0
+ let tabline = '%{TablineWithError()}'
+ try
+ let &tabline = tabline
+ redraw!
+ catch
+ endtry
+ call assert_true(s:func_in_tabline_called)
+ call assert_equal('', &tabline)
+ set tabline=
+ let &showtabline = showtabline_save
+endfunc
+
+func Test_redrawtabline()
+ if has('gui')
+ set guioptions-=e
+ endif
+ let showtabline_save = &showtabline
+ set showtabline=2
+ set tabline=%{bufnr('$')}
+ edit Xtabline1
+ edit Xtabline2
+ redraw
+ call assert_match(bufnr('$') . '', Screenline(1))
+ au BufAdd * redrawtabline
+ badd Xtabline3
+ call assert_match(bufnr('$') . '', Screenline(1))
+
+ set tabline=
+ let &showtabline = showtabline_save
+ au! Bufadd
+endfunc
diff --git a/src/testdir/test_tabpage.vim b/src/testdir/test_tabpage.vim
new file mode 100644
index 0000000..48ac6eb
--- /dev/null
+++ b/src/testdir/test_tabpage.vim
@@ -0,0 +1,558 @@
+" Tests for tabpage
+
+
+function Test_tabpage()
+ bw!
+ " Simple test for opening and closing a tab page
+ tabnew
+ call assert_equal(2, tabpagenr())
+ quit
+
+ " Open three tab pages and use ":tabdo"
+ 0tabnew
+ 1tabnew
+ $tabnew
+ %del
+ tabdo call append(line('$'), tabpagenr())
+ tabclose! 2
+ tabrewind
+ let line1 = getline('$')
+ undo
+ q
+ tablast
+ let line2 = getline('$')
+ q!
+ call append(line('$'), line1)
+ call append(line('$'), line2)
+ unlet line1 line2
+ call assert_equal(['', '3', '1', '4'], getline(1, '$'))
+ "
+ " Test for settabvar() and gettabvar() functions. Open a new tab page and
+ " set 3 variables to a number, string and a list. Verify that the variables
+ " are correctly set.
+ tabnew
+ tabfirst
+ call settabvar(2, 'val_num', 100)
+ call settabvar(2, 'val_str', 'SetTabVar test')
+ call settabvar(2, 'val_list', ['red', 'blue', 'green'])
+ "
+ call assert_true(gettabvar(2, 'val_num') == 100 && gettabvar(2, 'val_str') == 'SetTabVar test' && gettabvar(2, 'val_list') == ['red', 'blue', 'green'])
+
+ tabnext 2
+ call assert_true(t:val_num == 100 && t:val_str == 'SetTabVar test' && t:val_list == ['red', 'blue', 'green'])
+ tabclose
+
+ " Test for ":tab drop exist-file" to keep current window.
+ sp test1
+ tab drop test1
+ call assert_true(tabpagenr('$') == 1 && winnr('$') == 2 && winnr() == 1)
+ close
+ "
+ "
+ " Test for ":tab drop new-file" to keep current window of tabpage 1.
+ split
+ tab drop newfile
+ call assert_true(tabpagenr('$') == 2 && tabpagewinnr(1, '$') == 2 && tabpagewinnr(1) == 1)
+ tabclose
+ q
+ "
+ "
+ " Test for ":tab drop multi-opend-file" to keep current tabpage and window.
+ new test1
+ tabnew
+ new test1
+ tab drop test1
+ call assert_true(tabpagenr() == 2 && tabpagewinnr(2, '$') == 2 && tabpagewinnr(2) == 1)
+ tabclose
+ q
+ "
+ "
+ " Test for ":tab drop vertical-split-window" to jump test1 buffer
+ tabedit test1
+ vnew
+ tabfirst
+ tab drop test1
+ call assert_equal([2, 2, 2, 2], [tabpagenr('$'), tabpagenr(), tabpagewinnr(2, '$'), tabpagewinnr(2)])
+ 1tabonly
+ "
+ "
+ for i in range(9) | tabnew | endfor
+ normal! 1gt
+ call assert_equal(1, tabpagenr())
+ tabmove 5
+ call assert_equal(5, tabpagenr())
+ .tabmove
+ call assert_equal(5, tabpagenr())
+ tabmove -
+ call assert_equal(4, tabpagenr())
+ tabmove +
+ call assert_equal(5, tabpagenr())
+ tabmove -2
+ call assert_equal(3, tabpagenr())
+ tabmove +4
+ call assert_equal(7, tabpagenr())
+ tabmove
+ call assert_equal(10, tabpagenr())
+ 0tabmove
+ call assert_equal(1, tabpagenr())
+ $tabmove
+ call assert_equal(10, tabpagenr())
+ tabmove 0
+ call assert_equal(1, tabpagenr())
+ tabmove $
+ call assert_equal(10, tabpagenr())
+ 3tabmove
+ call assert_equal(4, tabpagenr())
+ 7tabmove 5
+ call assert_equal(5, tabpagenr())
+ -tabmove
+ call assert_equal(4, tabpagenr())
+ +tabmove
+ call assert_equal(5, tabpagenr())
+ -2tabmove
+ call assert_equal(3, tabpagenr())
+ +3tabmove
+ call assert_equal(6, tabpagenr())
+
+ " The following are a no-op
+ norm! 2gt
+ call assert_equal(2, tabpagenr())
+ tabmove 2
+ call assert_equal(2, tabpagenr())
+ 2tabmove
+ call assert_equal(2, tabpagenr())
+ tabmove 1
+ call assert_equal(2, tabpagenr())
+ 1tabmove
+ call assert_equal(2, tabpagenr())
+
+ call assert_fails("99tabmove", 'E16:')
+ call assert_fails("+99tabmove", 'E16:')
+ call assert_fails("-99tabmove", 'E16:')
+ call assert_fails("tabmove foo", 'E474:')
+ call assert_fails("tabmove 99", 'E474:')
+ call assert_fails("tabmove +99", 'E474:')
+ call assert_fails("tabmove -99", 'E474:')
+ call assert_fails("tabmove -3+", 'E474:')
+ call assert_fails("tabmove $3", 'E474:')
+ 1tabonly!
+endfunc
+
+" Test autocommands
+function Test_tabpage_with_autocmd()
+ if !has('autocmd')
+ return
+ endif
+ command -nargs=1 -bar C :call add(s:li, '=== ' . <q-args> . ' ===')|<args>
+ augroup TestTabpageGroup
+ au!
+ autocmd TabEnter * call add(s:li, 'TabEnter')
+ autocmd WinEnter * call add(s:li, 'WinEnter')
+ autocmd BufEnter * call add(s:li, 'BufEnter')
+ autocmd TabLeave * call add(s:li, 'TabLeave')
+ autocmd WinLeave * call add(s:li, 'WinLeave')
+ autocmd BufLeave * call add(s:li, 'BufLeave')
+ augroup END
+
+ let s:li = []
+ let t:a='a'
+ C tab split
+ call assert_equal(['=== tab split ===', 'WinLeave', 'TabLeave', 'WinEnter', 'TabEnter'], s:li)
+ let s:li = []
+ let t:a='b'
+ C tabnew
+ call assert_equal(['=== tabnew ===', 'WinLeave', 'TabLeave', 'WinEnter', 'TabEnter', 'BufLeave', 'BufEnter'], s:li)
+ let t:a='c'
+ let s:li = split(join(map(range(1, tabpagenr('$')), 'gettabvar(v:val, "a")')) , '\s\+')
+ call assert_equal(['a', 'b', 'c'], s:li)
+
+ let s:li = []
+ C call map(range(1, tabpagenr('$')), 'settabvar(v:val, ''a'', v:val*2)')
+ call assert_equal(["=== call map(range(1, tabpagenr('$')), 'settabvar(v:val, ''a'', v:val*2)') ==="], s:li)
+ let s:li = split(join(map(range(1, tabpagenr('$')), 'gettabvar(v:val, "a")')) , '\s\+')
+ call assert_equal(['2', '4', '6'], s:li)
+
+ let s:li = []
+ let w:a='a'
+ C vsplit
+ call assert_equal(['=== vsplit ===', 'WinLeave', 'WinEnter'], s:li)
+ let s:li = []
+ let w:a='a'
+ let tabn=tabpagenr()
+ let winr=range(1, winnr('$'))
+ C tabnext 1
+ call assert_equal(['=== tabnext 1 ===', 'BufLeave', 'WinLeave', 'TabLeave', 'WinEnter', 'TabEnter', 'BufEnter'], s:li)
+ let s:li = split(join(map(copy(winr), 'gettabwinvar('.tabn.', v:val, "a")')), '\s\+')
+ call assert_equal(['a', 'a'], s:li)
+ let s:li = []
+ C call map(copy(winr), 'settabwinvar('.tabn.', v:val, ''a'', v:val*2)')
+ let s:li = split(join(map(copy(winr), 'gettabwinvar('.tabn.', v:val, "a")')), '\s\+')
+ call assert_equal(['2', '4'], s:li)
+
+ augroup TabDestructive
+ autocmd TabEnter * :C tabnext 2 | C tabclose 3
+ augroup END
+ let s:li = []
+ C tabnext 3
+ call assert_equal(['=== tabnext 3 ===', 'BufLeave', 'WinLeave', 'TabLeave', 'WinEnter', 'TabEnter', '=== tabnext 2 ===', '=== tabclose 3 ==='], s:li)
+ call assert_equal(['2/2'], [tabpagenr().'/'.tabpagenr('$')])
+
+ autocmd! TabDestructive TabEnter
+ let s:li = []
+ C tabnew
+ call assert_equal(['=== tabnew ===', 'WinLeave', 'TabLeave', 'WinEnter', 'TabEnter', 'BufLeave', 'BufEnter'], s:li)
+ let s:li = []
+ C tabnext 1
+ call assert_equal(['=== tabnext 1 ===', 'BufLeave', 'WinLeave', 'TabLeave', 'WinEnter', 'TabEnter', 'BufEnter'], s:li)
+
+ autocmd TabDestructive TabEnter * nested :C tabnext 2 | C tabclose 3
+ let s:li = []
+ call assert_equal(3, tabpagenr('$'))
+ C tabnext 2
+ call assert_equal(2, tabpagenr('$'))
+ call assert_equal(['=== tabnext 2 ===', 'WinLeave', 'TabLeave', 'WinEnter', 'TabEnter', '=== tabnext 2 ===', '=== tabclose 3 ==='], s:li)
+ call assert_equal(['2/2'], [tabpagenr().'/'.tabpagenr('$')])
+
+ delcommand C
+ autocmd! TabDestructive
+ augroup! TabDestructive
+ autocmd! TestTabpageGroup
+ augroup! TestTabpageGroup
+ 1tabonly!
+endfunction
+
+function Test_tabpage_with_tab_modifier()
+ for n in range(4)
+ tabedit
+ endfor
+
+ function s:check_tab(pre_nr, cmd, post_nr)
+ exec 'tabnext ' . a:pre_nr
+ exec a:cmd
+ call assert_equal(a:post_nr, tabpagenr())
+ call assert_equal('help', &buftype)
+ helpclose
+ endfunc
+
+ call s:check_tab(1, 'tab help', 2)
+ call s:check_tab(1, '3tab help', 4)
+ call s:check_tab(1, '.tab help', 2)
+ call s:check_tab(1, '.+1tab help', 3)
+ call s:check_tab(1, '0tab help', 1)
+ call s:check_tab(2, '+tab help', 4)
+ call s:check_tab(2, '+2tab help', 5)
+ call s:check_tab(4, '-tab help', 4)
+ call s:check_tab(4, '-2tab help', 3)
+ call s:check_tab(3, '$tab help', 6)
+ call assert_fails('99tab help', 'E16:')
+ call assert_fails('+99tab help', 'E16:')
+ call assert_fails('-99tab help', 'E16:')
+
+ delfunction s:check_tab
+ 1tabonly!
+endfunction
+
+function Check_tab_count(pre_nr, cmd, post_nr)
+ exec 'tabnext' a:pre_nr
+ normal! G
+ exec a:cmd
+ call assert_equal(a:post_nr, tabpagenr(), a:cmd)
+endfunc
+
+" Test for [count] of tabnext
+function Test_tabpage_with_tabnext()
+ for n in range(4)
+ tabedit
+ call setline(1, ['', '', '3'])
+ endfor
+
+ call Check_tab_count(1, 'tabnext', 2)
+ call Check_tab_count(1, '3tabnext', 3)
+ call Check_tab_count(1, '.tabnext', 1)
+ call Check_tab_count(1, '.+1tabnext', 2)
+ call Check_tab_count(2, '+tabnext', 3)
+ call Check_tab_count(2, '+2tabnext', 4)
+ call Check_tab_count(4, '-tabnext', 3)
+ call Check_tab_count(4, '-2tabnext', 2)
+ call Check_tab_count(3, '$tabnext', 5)
+ call assert_fails('0tabnext', 'E16:')
+ call assert_fails('99tabnext', 'E16:')
+ call assert_fails('+99tabnext', 'E16:')
+ call assert_fails('-99tabnext', 'E16:')
+ call Check_tab_count(1, 'tabnext 3', 3)
+ call Check_tab_count(2, 'tabnext +', 3)
+ call Check_tab_count(2, 'tabnext +2', 4)
+ call Check_tab_count(4, 'tabnext -', 3)
+ call Check_tab_count(4, 'tabnext -2', 2)
+ call Check_tab_count(3, 'tabnext $', 5)
+ call assert_fails('tabnext 0', 'E474:')
+ call assert_fails('tabnext .', 'E474:')
+ call assert_fails('tabnext -+', 'E474:')
+ call assert_fails('tabnext +2-', 'E474:')
+ call assert_fails('tabnext $3', 'E474:')
+ call assert_fails('tabnext 99', 'E474:')
+ call assert_fails('tabnext +99', 'E474:')
+ call assert_fails('tabnext -99', 'E474:')
+
+ 1tabonly!
+endfunction
+
+" Test for [count] of tabprevious
+function Test_tabpage_with_tabprevious()
+ for n in range(5)
+ tabedit
+ call setline(1, ['', '', '3'])
+ endfor
+
+ for cmd in ['tabNext', 'tabprevious']
+ call Check_tab_count(6, cmd, 5)
+ call Check_tab_count(6, '3' . cmd, 3)
+ call Check_tab_count(6, '8' . cmd, 4)
+ call Check_tab_count(6, cmd . ' 3', 3)
+ call Check_tab_count(6, cmd . ' 8', 4)
+ for n in range(2)
+ for c in ['0', '.+3', '+', '+2' , '-', '-2' , '$', '+99', '-99']
+ if n == 0 " pre count
+ let entire_cmd = c . cmd
+ let err_code = 'E16:'
+ else
+ let entire_cmd = cmd . ' ' . c
+ let err_code = 'E474:'
+ endif
+ call assert_fails(entire_cmd, err_code)
+ endfor
+ endfor
+ endfor
+
+ 1tabonly!
+endfunction
+
+function s:reconstruct_tabpage_for_test(nr)
+ let n = (a:nr > 2) ? a:nr - 2 : 1
+ 1tabonly!
+ 0tabedit n0
+ for n in range(1, n)
+ exec '$tabedit n' . n
+ if n == 1
+ call setline(1, ['', '', '3'])
+ endif
+ endfor
+endfunc
+
+func Test_tabpage_ctrl_pgup_pgdown()
+ enew!
+ tabnew tab1
+ tabnew tab2
+
+ call assert_equal(3, tabpagenr())
+ exe "norm! \<C-PageUp>"
+ call assert_equal(2, tabpagenr())
+ exe "norm! \<C-PageDown>"
+ call assert_equal(3, tabpagenr())
+
+ " Check wrapping at last or first page.
+ exe "norm! \<C-PageDown>"
+ call assert_equal(1, tabpagenr())
+ exe "norm! \<C-PageUp>"
+ call assert_equal(3, tabpagenr())
+
+ " With a count, <C-PageUp> and <C-PageDown> are not symmetrical somehow:
+ " - {count}<C-PageUp> goes {count} pages downward (relative count)
+ " - {count}<C-PageDown> goes to page number {count} (absolute count)
+ exe "norm! 2\<C-PageUp>"
+ call assert_equal(1, tabpagenr())
+ exe "norm! 2\<C-PageDown>"
+ call assert_equal(2, tabpagenr())
+
+ 1tabonly!
+endfunc
+
+" Test for [count] of tabclose
+function Test_tabpage_with_tabclose()
+
+ " pre count
+ call s:reconstruct_tabpage_for_test(6)
+ call Check_tab_count(3, 'tabclose!', 3)
+ call Check_tab_count(1, '3tabclose', 1)
+ call Check_tab_count(4, '4tabclose', 3)
+ call Check_tab_count(3, '1tabclose', 2)
+ call Check_tab_count(2, 'tabclose', 1)
+ call assert_equal(1, tabpagenr('$'))
+ call assert_equal('', bufname(''))
+
+ call s:reconstruct_tabpage_for_test(6)
+ call Check_tab_count(2, '$tabclose', 2)
+ call Check_tab_count(4, '.tabclose', 4)
+ call Check_tab_count(3, '.+tabclose', 3)
+ call Check_tab_count(3, '.-2tabclose', 2)
+ call Check_tab_count(1, '.+1tabclose!', 1)
+ call assert_equal(1, tabpagenr('$'))
+ call assert_equal('', bufname(''))
+
+ " post count
+ call s:reconstruct_tabpage_for_test(6)
+ call Check_tab_count(3, 'tabclose!', 3)
+ call Check_tab_count(1, 'tabclose 3', 1)
+ call Check_tab_count(4, 'tabclose 4', 3)
+ call Check_tab_count(3, 'tabclose 1', 2)
+ call Check_tab_count(2, 'tabclose', 1)
+ call assert_equal(1, tabpagenr('$'))
+ call assert_equal('', bufname(''))
+
+ call s:reconstruct_tabpage_for_test(6)
+ call Check_tab_count(2, 'tabclose $', 2)
+ call Check_tab_count(4, 'tabclose', 4)
+ call Check_tab_count(3, 'tabclose +', 3)
+ call Check_tab_count(3, 'tabclose -2', 2)
+ call Check_tab_count(1, 'tabclose! +1', 1)
+ call assert_equal(1, tabpagenr('$'))
+ call assert_equal('', bufname(''))
+
+ call s:reconstruct_tabpage_for_test(6)
+ for n in range(2)
+ for c in ['0', '$3', '99', '+99', '-99']
+ if n == 0 " pre count
+ let entire_cmd = c . 'tabclose'
+ let err_code = 'E16:'
+ else
+ let entire_cmd = 'tabclose ' . c
+ let err_code = 'E474:'
+ endif
+ call assert_fails(entire_cmd, err_code)
+ call assert_equal(6, tabpagenr('$'))
+ endfor
+ endfor
+
+ call assert_fails('3tabclose', 'E37:')
+ call assert_fails('tabclose 3', 'E37:')
+ call assert_fails('tabclose -+', 'E474:')
+ call assert_fails('tabclose +2-', 'E474:')
+ call assert_equal(6, tabpagenr('$'))
+
+ 1tabonly!
+endfunction
+
+" Test for [count] of tabonly
+function Test_tabpage_with_tabonly()
+
+ " Test for the normal behavior (pre count only)
+ let tc = [ [4, '.', '!'], [2, '.+', ''], [3, '.-2', '!'], [1, '.+1', '!'] ]
+ for c in tc
+ call s:reconstruct_tabpage_for_test(6)
+ let entire_cmd = c[1] . 'tabonly' . c[2]
+ call Check_tab_count(c[0], entire_cmd, 1)
+ call assert_equal(1, tabpagenr('$'))
+ endfor
+
+ " Test for the normal behavior
+ let tc2 = [ [3, '', ''], [1, '3', ''], [4, '4', '!'], [3, '1', '!'],
+ \ [2, '', '!'],
+ \ [2, '$', '!'], [3, '+', '!'], [3, '-2', '!'], [3, '+1', '!']
+ \ ]
+ for n in range(2)
+ for c in tc2
+ call s:reconstruct_tabpage_for_test(6)
+ if n == 0 " pre count
+ let entire_cmd = c[1] . 'tabonly' . c[2]
+ else
+ let entire_cmd = 'tabonly' . c[2] . ' ' . c[1]
+ endif
+ call Check_tab_count(c[0], entire_cmd, 1)
+ call assert_equal(1, tabpagenr('$'))
+ endfor
+ endfor
+
+ " Test for the error behavior
+ for n in range(2)
+ for c in ['0', '$3', '99', '+99', '-99']
+ call s:reconstruct_tabpage_for_test(6)
+ if n == 0 " pre count
+ let entire_cmd = c . 'tabonly'
+ let err_code = 'E16:'
+ else
+ let entire_cmd = 'tabonly ' . c
+ let err_code = 'E474:'
+ endif
+ call assert_fails(entire_cmd, err_code)
+ call assert_equal(6, tabpagenr('$'))
+ endfor
+ endfor
+
+ " Test for the error behavior (post count only)
+ for c in tc
+ call s:reconstruct_tabpage_for_test(6)
+ let entire_cmd = 'tabonly' . c[2] . ' ' . c[1]
+ let err_code = 'E474:'
+ call assert_fails(entire_cmd, err_code)
+ call assert_equal(6, tabpagenr('$'))
+ endfor
+
+ call assert_fails('tabonly -+', 'E474:')
+ call assert_fails('tabonly +2-', 'E474:')
+ call assert_equal(6, tabpagenr('$'))
+
+ 1tabonly!
+ new
+ only!
+endfunction
+
+func Test_tabnext_on_buf_unload1()
+ " This once caused a crash
+ new
+ tabedit
+ tabfirst
+ au BufUnload <buffer> tabnext
+ q
+
+ while tabpagenr('$') > 1
+ bwipe!
+ endwhile
+endfunc
+
+func Test_tabnext_on_buf_unload2()
+ " This once caused a crash
+ tabedit
+ autocmd BufUnload <buffer> tabnext
+ file x
+ edit y
+
+ while tabpagenr('$') > 1
+ bwipe!
+ endwhile
+endfunc
+
+func Test_close_on_quitpre()
+ " This once caused a crash
+ edit Xtest
+ new
+ only
+ set bufhidden=delete
+ au QuitPre <buffer> close
+ tabnew tab1
+ tabnew tab2
+ 1tabn
+ q!
+ call assert_equal(1, tabpagenr())
+ call assert_equal(2, tabpagenr('$'))
+ " clean up
+ while tabpagenr('$') > 1
+ bwipe!
+ endwhile
+ buf Xtest
+endfunc
+
+func Test_tabs()
+ enew!
+ tabnew tab1
+ norm ixxx
+ let a=split(execute(':tabs'), "\n")
+ call assert_equal(['Tab page 1',
+ \ ' [No Name]',
+ \ 'Tab page 2',
+ \ '> + tab1'], a)
+
+ 1tabonly!
+ bw!
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/test_tagcase.vim b/src/testdir/test_tagcase.vim
new file mode 100644
index 0000000..83e5328
--- /dev/null
+++ b/src/testdir/test_tagcase.vim
@@ -0,0 +1,73 @@
+" test 'tagcase' option
+
+func Test_tagcase()
+ call writefile(["Bar\tXtext\t3", "Foo\tXtext\t2", "foo\tXtext\t4"], 'Xtags')
+ set tags=Xtags
+ e Xtext
+
+ for &ic in [0, 1]
+ for &scs in [0, 1]
+ for &g:tc in ["followic", "ignore", "match", "followscs", "smart"]
+ for &l:tc in ["", "followic", "ignore", "match", "followscs", "smart"]
+ let smart = 0
+ if &l:tc != ''
+ let tc = &l:tc
+ else
+ let tc = &g:tc
+ endif
+ if tc == 'followic'
+ let ic = &ic
+ elseif tc == 'ignore'
+ let ic = 1
+ elseif tc == 'followscs'
+ let ic = &ic
+ let smart = &scs
+ elseif tc == 'smart'
+ let ic = 1
+ let smart = 1
+ else
+ let ic = 0
+ endif
+ if ic && smart
+ call assert_equal(['foo', 'Foo'], map(taglist("^foo$"), {i, v -> v.name}))
+ call assert_equal(['Foo'], map(taglist("^Foo$"), {i, v -> v.name}))
+ elseif ic
+ call assert_equal(['foo', 'Foo'], map(taglist("^foo$"), {i, v -> v.name}))
+ call assert_equal(['Foo', 'foo'], map(taglist("^Foo$"), {i, v -> v.name}))
+ else
+ call assert_equal(['foo'], map(taglist("^foo$"), {i, v -> v.name}))
+ call assert_equal(['Foo'], map(taglist("^Foo$"), {i, v -> v.name}))
+ endif
+ endfor
+ endfor
+ endfor
+ endfor
+
+ call delete('Xtags')
+ set ic&
+ setg tc&
+ setl tc&
+ set scs&
+endfunc
+
+func Test_set_tagcase()
+ " Verify default values.
+ set ic&
+ setg tc&
+ setl tc&
+ call assert_equal(0, &ic)
+ call assert_equal('followic', &g:tc)
+ call assert_equal('followic', &l:tc)
+ call assert_equal('followic', &tc)
+
+ " Verify that the local setting accepts <empty> but that the global setting
+ " does not. The first of these (setting the local value to <empty>) should
+ " succeed; the other two should fail.
+ setl tc=
+ call assert_fails('setg tc=', 'E474:')
+ call assert_fails('set tc=', 'E474:')
+
+ set ic&
+ setg tc&
+ setl tc&
+endfunc
diff --git a/src/testdir/test_tagjump.vim b/src/testdir/test_tagjump.vim
new file mode 100644
index 0000000..ae47a69
--- /dev/null
+++ b/src/testdir/test_tagjump.vim
@@ -0,0 +1,369 @@
+" Tests for tagjump (tags and special searches)
+
+" SEGV occurs in older versions. (At least 7.4.1748 or older)
+func Test_ptag_with_notagstack()
+ set notagstack
+ call assert_fails('ptag does_not_exist_tag_name', 'E426')
+ set tagstack&vim
+endfunc
+
+func Test_cancel_ptjump()
+ set tags=Xtags
+ call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
+ \ "word\tfile1\tcmd1",
+ \ "word\tfile2\tcmd2"],
+ \ 'Xtags')
+
+ only!
+ call feedkeys(":ptjump word\<CR>\<CR>", "xt")
+ help
+ call assert_equal(2, winnr('$'))
+
+ call delete('Xtags')
+ quit
+endfunc
+
+func Test_static_tagjump()
+ set tags=Xtags
+ call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
+ \ "one\tXfile1\t/^one/;\"\tf\tfile:\tsignature:(void)",
+ \ "word\tXfile2\tcmd2"],
+ \ 'Xtags')
+ new Xfile1
+ call setline(1, ['empty', 'one()', 'empty'])
+ write
+ tag one
+ call assert_equal(2, line('.'))
+
+ bwipe!
+ set tags&
+ call delete('Xtags')
+ call delete('Xfile1')
+endfunc
+
+func Test_duplicate_tagjump()
+ set tags=Xtags
+ call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
+ \ "thesame\tXfile1\t1;\"\td\tfile:",
+ \ "thesame\tXfile1\t2;\"\td\tfile:",
+ \ "thesame\tXfile1\t3;\"\td\tfile:",
+ \ ],
+ \ 'Xtags')
+ new Xfile1
+ call setline(1, ['thesame one', 'thesame two', 'thesame three'])
+ write
+ tag thesame
+ call assert_equal(1, line('.'))
+ tnext
+ call assert_equal(2, line('.'))
+ tnext
+ call assert_equal(3, line('.'))
+
+ bwipe!
+ set tags&
+ call delete('Xtags')
+ call delete('Xfile1')
+endfunc
+
+func Test_tagjump_switchbuf()
+ set tags=Xtags
+ call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
+ \ "second\tXfile1\t2",
+ \ "third\tXfile1\t3",],
+ \ 'Xtags')
+ call writefile(['first', 'second', 'third'], 'Xfile1')
+
+ enew | only
+ set switchbuf=
+ stag second
+ call assert_equal(2, winnr('$'))
+ call assert_equal(2, line('.'))
+ stag third
+ call assert_equal(3, winnr('$'))
+ call assert_equal(3, line('.'))
+
+ enew | only
+ set switchbuf=useopen
+ stag second
+ call assert_equal(2, winnr('$'))
+ call assert_equal(2, line('.'))
+ stag third
+ call assert_equal(2, winnr('$'))
+ call assert_equal(3, line('.'))
+
+ enew | only
+ set switchbuf=usetab
+ tab stag second
+ call assert_equal(2, tabpagenr('$'))
+ call assert_equal(2, line('.'))
+ 1tabnext | stag third
+ call assert_equal(2, tabpagenr('$'))
+ call assert_equal(3, line('.'))
+
+ tabclose!
+ enew | only
+ call delete('Xfile1')
+ call delete('Xtags')
+ set switchbuf&vim
+endfunc
+
+" Tests for [ CTRL-I and CTRL-W CTRL-I commands
+function Test_keyword_jump()
+ call writefile(["#include Xinclude", "",
+ \ "",
+ \ "/* test text test tex start here",
+ \ " some text",
+ \ " test text",
+ \ " start OK if found this line",
+ \ " start found wrong line",
+ \ "test text"], 'Xtestfile')
+ call writefile(["/* test text test tex start here",
+ \ " some text",
+ \ " test text",
+ \ " start OK if found this line",
+ \ " start found wrong line",
+ \ "test text"], 'Xinclude')
+ new Xtestfile
+ call cursor(1,1)
+ call search("start")
+ exe "normal! 5[\<C-I>"
+ call assert_equal(" start OK if found this line", getline('.'))
+ call cursor(1,1)
+ call search("start")
+ exe "normal! 5\<C-W>\<C-I>"
+ call assert_equal(" start OK if found this line", getline('.'))
+ enew! | only
+ call delete('Xtestfile')
+ call delete('Xinclude')
+endfunction
+
+" Test for jumping to a tag with 'hidden' set, with symbolic link in path of
+" tag. This only works for Unix, because of the symbolic link.
+func Test_tag_symbolic()
+ if !has('unix')
+ return
+ endif
+ set hidden
+ call delete("Xtest.dir", "rf")
+ call system("ln -s . Xtest.dir")
+ " Create a tags file with the current directory name inserted.
+ call writefile([
+ \ "SECTION_OFF " . getcwd() . "/Xtest.dir/Xtest.c /^#define SECTION_OFF 3$/",
+ \ '',
+ \ ], 'Xtags')
+ call writefile(['#define SECTION_OFF 3',
+ \ '#define NUM_SECTIONS 3'], 'Xtest.c')
+
+ " Try jumping to a tag, but with a path that contains a symbolic link. When
+ " wrong, this will give the ATTENTION message. The next space will then be
+ " eaten by hit-return, instead of moving the cursor to 'd'.
+ set tags=Xtags
+ enew!
+ call append(0, 'SECTION_OFF')
+ call cursor(1,1)
+ exe "normal \<C-]> "
+ call assert_equal('Xtest.c', expand('%:t'))
+ call assert_equal(2, col('.'))
+
+ set hidden&
+ set tags&
+ enew!
+ call delete('Xtags')
+ call delete('Xtest.c')
+ call delete("Xtest.dir", "rf")
+ %bwipe!
+endfunc
+
+" Tests for tag search with !_TAG_FILE_ENCODING.
+" Depends on the test83-tags2 and test83-tags3 files.
+func Test_tag_file_encoding()
+ if has('vms')
+ return
+ endif
+
+ if !has('iconv') || iconv("\x82\x60", "cp932", "utf-8") != "\uff21"
+ return
+ endif
+
+ let save_enc = &encoding
+ set encoding=utf8
+
+ let content = ['text for tags1', 'abcdefghijklmnopqrs']
+ call writefile(content, 'Xtags1.txt')
+ let content = ['text for tags2', 'ABC']
+ call writefile(content, 'Xtags2.txt')
+ let content = ['text for tags3', 'ABC']
+ call writefile(content, 'Xtags3.txt')
+ let content = ['!_TAG_FILE_ENCODING utf-8 //', 'abcdefghijklmnopqrs Xtags1.txt /abcdefghijklmnopqrs']
+ call writefile(content, 'Xtags1')
+
+ " case1:
+ new
+ set tags=Xtags1
+ tag abcdefghijklmnopqrs
+ call assert_equal('Xtags1.txt', expand('%:t'))
+ call assert_equal('abcdefghijklmnopqrs', getline('.'))
+ close
+
+ " case2:
+ new
+ set tags=test83-tags2
+ tag /.BC
+ call assert_equal('Xtags2.txt', expand('%:t'))
+ call assert_equal('ABC', getline('.'))
+ close
+
+ " case3:
+ new
+ set tags=test83-tags3
+ tag abc50
+ call assert_equal('Xtags3.txt', expand('%:t'))
+ call assert_equal('ABC', getline('.'))
+ close
+
+ set tags&
+ let &encoding = save_enc
+ call delete('Xtags1.txt')
+ call delete('Xtags2.txt')
+ call delete('Xtags3.txt')
+ call delete('Xtags1')
+endfunc
+
+func Test_tagjump_etags()
+ if !has('emacs_tags')
+ return
+ endif
+ call writefile([
+ \ "void foo() {}",
+ \ "int main(int argc, char **argv)",
+ \ "{",
+ \ "\tfoo();",
+ \ "\treturn 0;",
+ \ "}",
+ \ ], 'Xmain.c')
+
+ call writefile([
+ \ "\x0c",
+ \ "Xmain.c,64",
+ \ "void foo() {}\x7ffoo\x011,0",
+ \ "int main(int argc, char **argv)\x7fmain\x012,14",
+ \ ], 'Xtags')
+ set tags=Xtags
+ ta foo
+ call assert_equal('void foo() {}', getline('.'))
+
+ call delete('Xtags')
+ call delete('Xmain.c')
+ bwipe!
+endfunc
+
+" Test for getting and modifying the tag stack
+func Test_getsettagstack()
+ call writefile(['line1', 'line2', 'line3'], 'Xfile1')
+ call writefile(['line1', 'line2', 'line3'], 'Xfile2')
+ call writefile(['line1', 'line2', 'line3'], 'Xfile3')
+
+ enew | only
+ call settagstack(1, {'items' : []})
+ call assert_equal(0, gettagstack(1).length)
+ call assert_equal([], gettagstack(1).items)
+ " Error cases
+ call assert_equal({}, gettagstack(100))
+ call assert_equal(-1, settagstack(100, {'items' : []}))
+ call assert_fails('call settagstack(1, [1, 10])', 'E715')
+ call assert_fails("call settagstack(1, {'items' : 10})", 'E714')
+ call assert_fails("call settagstack(1, {'items' : []}, 10)", 'E928')
+ call assert_fails("call settagstack(1, {'items' : []}, 'b')", 'E962')
+
+ set tags=Xtags
+ call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
+ \ "one\tXfile1\t1",
+ \ "three\tXfile3\t3",
+ \ "two\tXfile2\t2"],
+ \ 'Xtags')
+
+ let stk = []
+ call add(stk, {'bufnr' : bufnr('%'), 'tagname' : 'one',
+ \ 'from' : [bufnr('%'), line('.'), col('.'), 0], 'matchnr' : 1})
+ tag one
+ call add(stk, {'bufnr' : bufnr('%'), 'tagname' : 'two',
+ \ 'from' : [bufnr('%'), line('.'), col('.'), 0], 'matchnr' : 1})
+ tag two
+ call add(stk, {'bufnr' : bufnr('%'), 'tagname' : 'three',
+ \ 'from' : [bufnr('%'), line('.'), col('.'), 0], 'matchnr' : 1})
+ tag three
+ call assert_equal(3, gettagstack(1).length)
+ call assert_equal(stk, gettagstack(1).items)
+ " Check for default - current window
+ call assert_equal(3, gettagstack().length)
+ call assert_equal(stk, gettagstack().items)
+
+ " Try to set current index to invalid values
+ call settagstack(1, {'curidx' : -1})
+ call assert_equal(1, gettagstack().curidx)
+ call settagstack(1, {'curidx' : 50})
+ call assert_equal(4, gettagstack().curidx)
+
+ " Try pushing invalid items onto the stack
+ call settagstack(1, {'items' : []})
+ call settagstack(1, {'items' : ["plate"]}, 'a')
+ call assert_equal(0, gettagstack().length)
+ call assert_equal([], gettagstack().items)
+ call settagstack(1, {'items' : [{"tagname" : "abc"}]}, 'a')
+ call assert_equal(0, gettagstack().length)
+ call assert_equal([], gettagstack().items)
+ call settagstack(1, {'items' : [{"from" : 100}]}, 'a')
+ call assert_equal(0, gettagstack().length)
+ call assert_equal([], gettagstack().items)
+ call settagstack(1, {'items' : [{"from" : [2, 1, 0, 0]}]}, 'a')
+ call assert_equal(0, gettagstack().length)
+ call assert_equal([], gettagstack().items)
+
+ " Push one item at a time to the stack
+ call settagstack(1, {'items' : []})
+ call settagstack(1, {'items' : [stk[0]]}, 'a')
+ call settagstack(1, {'items' : [stk[1]]}, 'a')
+ call settagstack(1, {'items' : [stk[2]]}, 'a')
+ call settagstack(1, {'curidx' : 4})
+ call assert_equal({'length' : 3, 'curidx' : 4, 'items' : stk},
+ \ gettagstack(1))
+
+ " Try pushing items onto a full stack
+ for i in range(7)
+ call settagstack(1, {'items' : stk}, 'a')
+ endfor
+ call assert_equal(20, gettagstack().length)
+ call settagstack(1,
+ \ {'items' : [{'tagname' : 'abc', 'from' : [1, 10, 1, 0]}]}, 'a')
+ call assert_equal('abc', gettagstack().items[19].tagname)
+
+ " Tag with multiple matches
+ call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
+ \ "two\tXfile1\t1",
+ \ "two\tXfile2\t3",
+ \ "two\tXfile3\t2"],
+ \ 'Xtags')
+ call settagstack(1, {'items' : []})
+ tag two
+ tnext
+ tnext
+ call assert_equal(1, gettagstack().length)
+ call assert_equal(3, gettagstack().items[0].matchnr)
+
+ " Memory allocation failures
+ call test_alloc_fail(GetAllocId('tagstack_items'), 0, 0)
+ call assert_fails('call gettagstack()', 'E342:')
+ call test_alloc_fail(GetAllocId('tagstack_from'), 0, 0)
+ call assert_fails('call gettagstack()', 'E342:')
+ call test_alloc_fail(GetAllocId('tagstack_details'), 0, 0)
+ call assert_fails('call gettagstack()', 'E342:')
+
+ call settagstack(1, {'items' : []})
+ call delete('Xfile1')
+ call delete('Xfile2')
+ call delete('Xfile3')
+ call delete('Xtags')
+ set tags&
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/test_taglist.vim b/src/testdir/test_taglist.vim
new file mode 100644
index 0000000..0a9350a
--- /dev/null
+++ b/src/testdir/test_taglist.vim
@@ -0,0 +1,86 @@
+" test taglist(), tagfiles() functions and :tags command
+
+func Test_taglist()
+ call writefile([
+ \ "FFoo\tXfoo\t1",
+ \ "FBar\tXfoo\t2",
+ \ "BFoo\tXbar\t1",
+ \ "BBar\tXbar\t2"
+ \ ], 'Xtags')
+ set tags=Xtags
+ split Xtext
+
+ call assert_equal(['FFoo', 'BFoo'], map(taglist("Foo"), {i, v -> v.name}))
+ call assert_equal(['FFoo', 'BFoo'], map(taglist("Foo", "Xtext"), {i, v -> v.name}))
+ call assert_equal(['FFoo', 'BFoo'], map(taglist("Foo", "Xfoo"), {i, v -> v.name}))
+ call assert_equal(['BFoo', 'FFoo'], map(taglist("Foo", "Xbar"), {i, v -> v.name}))
+
+ call delete('Xtags')
+ bwipe
+endfunc
+
+func Test_taglist_native_etags()
+ if !has('emacs_tags')
+ return
+ endif
+ call writefile([
+ \ "\x0c",
+ \ "src/os_unix.c,13491",
+ \ "set_signals(\x7f1335,32699",
+ \ "reset_signals(\x7f1407,34136",
+ \ ], 'Xtags')
+
+ set tags=Xtags
+
+ call assert_equal([['set_signals', '1335,32699'], ['reset_signals', '1407,34136']],
+ \ map(taglist('set_signals'), {i, v -> [v.name, v.cmd]}))
+
+ call delete('Xtags')
+endfunc
+
+func Test_taglist_ctags_etags()
+ if !has('emacs_tags')
+ return
+ endif
+ call writefile([
+ \ "\x0c",
+ \ "src/os_unix.c,13491",
+ \ "set_signals(void)\x7fset_signals\x011335,32699",
+ \ "reset_signals(void)\x7freset_signals\x011407,34136",
+ \ ], 'Xtags')
+
+ set tags=Xtags
+
+ call assert_equal([['set_signals', '1335,32699'], ['reset_signals', '1407,34136']],
+ \ map(taglist('set_signals'), {i, v -> [v.name, v.cmd]}))
+
+ call delete('Xtags')
+endfunc
+
+func Test_tags_too_long()
+ call assert_fails('tag ' . repeat('x', 1020), 'E426')
+ tags
+endfunc
+
+func Test_tagfiles()
+ call assert_equal([], tagfiles())
+
+ call writefile(["FFoo\tXfoo\t1"], 'Xtags1')
+ call writefile(["FBar\tXbar\t1"], 'Xtags2')
+ set tags=Xtags1,Xtags2
+ call assert_equal(['Xtags1', 'Xtags2'], tagfiles())
+
+ help
+ let tf = tagfiles()
+ call assert_equal(1, len(tf))
+ call assert_equal(fnamemodify(expand('$VIMRUNTIME/doc/tags'), ':p:gs?\\?/?'),
+ \ fnamemodify(tf[0], ':p:gs?\\?/?'))
+ helpclose
+ call assert_equal(['Xtags1', 'Xtags2'], tagfiles())
+ set tags&
+ call assert_equal([], tagfiles())
+
+ call delete('Xtags1')
+ call delete('Xtags2')
+ bd
+endfunc
diff --git a/src/testdir/test_tcl.vim b/src/testdir/test_tcl.vim
new file mode 100644
index 0000000..c0eadc6
--- /dev/null
+++ b/src/testdir/test_tcl.vim
@@ -0,0 +1,680 @@
+" Tests for the Tcl interface.
+
+if !has('tcl')
+ finish
+end
+
+" Helper function as there is no builtin tcleval() function similar
+" to perleval, luaevel(), pyeval(), etc.
+func TclEval(tcl_expr)
+ let s = split(execute('tcl ' . a:tcl_expr), "\n")
+ return (len(s) == 0) ? '' : s[-1]
+endfunc
+
+func Test_tcldo()
+ " Check deleting lines does not trigger ml_get error.
+ new
+ call setline(1, ['one', 'two', 'three'])
+ tcldo ::vim::command %d_
+ bwipe!
+
+ " Check that switching to another buffer does not trigger ml_get error.
+ new
+ let wincount = winnr('$')
+ call setline(1, ['one', 'two', 'three'])
+ tcldo ::vim::command new
+ call assert_equal(wincount + 1, winnr('$'))
+ %bwipe!
+endfunc
+
+" Test :tcldo with a range
+func Test_tcldo_range()
+ new
+ call setline(1, ['line1', 'line2', 'line3', 'line4'])
+ 2,3tcldo set line [string toupper $line]
+ call assert_equal(['line1', 'LINE2', 'LINE3', 'line4'], getline(1, '$'))
+ bwipe!
+endfunc
+
+" Test ::vim::beep
+func Test_vim_beep()
+ call assert_beeps('tcl ::vim::beep')
+ call assert_fails('tcl ::vim::beep x', 'wrong # args: should be "::vim::beep"')
+endfunc
+
+" Test ::vim::buffer
+func Test_vim_buffer()
+ " Test ::vim::buffer {nr}
+ e Xfoo1
+ call setline(1, ['foobar'])
+ let bn1 = bufnr('%')
+ let b1 = TclEval('::vim::buffer ' . bn1)
+ call assert_equal(b1, TclEval('set ::vim::current(buffer)'))
+
+ new Xfoo2
+ call setline(1, ['barfoo'])
+ let bn2 = bufnr('%')
+ let b2 = TclEval('::vim::buffer ' . bn2)
+ call assert_equal(b2, TclEval('set ::vim::current(buffer)'))
+
+ call assert_match('Xfoo1$', TclEval(b1 . ' name'))
+ call assert_match('Xfoo2$', TclEval(b2 . ' name'))
+
+ " Test ::vim::buffer exists {nr}
+ call assert_match('^[1-9]\d*$', TclEval('::vim::buffer exists ' . bn1))
+ call assert_match('^[1-9]\d*$', TclEval('::vim::buffer exists ' . bn2))
+ call assert_equal('0', TclEval('::vim::buffer exists 54321'))
+
+ " Test ::vim::buffer list
+ call assert_equal('2', TclEval('llength [::vim::buffer list]'))
+ call assert_equal(b1.' '.b2, TclEval('::vim::buffer list'))
+ tcl <<EOF
+ proc eachbuf { cmd } {
+ foreach b [::vim::buffer list] { $b command $cmd }
+ }
+EOF
+ tcl eachbuf %s/foo/FOO/g
+ b! Xfoo1
+ call assert_equal(['FOObar'], getline(1, '$'))
+ b! Xfoo2
+ call assert_equal(['barFOO'], getline(1, '$'))
+
+ call assert_fails('tcl ::vim::buffer',
+ \ 'wrong # args: should be "::vim::buffer option"')
+ call assert_fails('tcl ::vim::buffer ' . bn1 . ' x',
+ \ 'wrong # args: should be "::vim::buffer bufNumber"')
+ call assert_fails('tcl ::vim::buffer 4321', 'invalid buffer number')
+ call assert_fails('tcl ::vim::buffer x',
+ \ 'bad option "x": must be exists or list')
+ call assert_fails('tcl ::vim::buffer exists',
+ \ 'wrong # args: should be "::vim::buffer exists bufNumber"')
+ call assert_fails('tcl ::vim::buffer exists x',
+ \ 'expected integer but got "x"')
+ call assert_fails('tcl ::vim::buffer list x',
+ \ 'wrong # args: should be "::vim::buffer list "')
+
+ tcl rename eachbuf ""
+ %bwipe!
+endfunc
+
+" Test ::vim::option
+func Test_vim_option()
+ set cc=3,5
+
+ " Test getting option 'cc'
+ call assert_equal('3,5', TclEval('::vim::option cc'))
+ call assert_equal('3,5', &cc)
+
+ " Test setting option 'cc' (it returns the old option value)
+ call assert_equal('3,5', TclEval('::vim::option cc +4'))
+ call assert_equal('+4', &cc)
+ call assert_equal('+4', TclEval('::vim::option cc'))
+
+ " Test boolean option with 'toggle', 'on' and 'off' keywords.
+ call assert_equal('0', TclEval('::vim::option nu toggle'))
+ call assert_equal(1, &nu)
+ call assert_equal('1', TclEval('::vim::option nu toggle'))
+ call assert_equal(0, &nu)
+ call assert_equal('0', TclEval('::vim::option nu on'))
+ call assert_equal(1, &nu)
+ call assert_equal('1', TclEval('::vim::option nu off'))
+ call assert_equal(0, &nu)
+
+ call assert_fails('tcl ::vim::option nu x', 'expected integer but got "x"')
+ call assert_fails('tcl ::vim::option xxx', 'unknown vimOption')
+ call assert_fails('tcl ::vim::option',
+ \ 'wrong # args: should be "::vim::option vimOption ?value?"')
+
+ set cc&
+endfunc
+
+" Test ::vim::expr
+func Test_vim_expr()
+ call assert_equal(string(char2nr('X')),
+ \ TclEval('::vim::expr char2nr("X")'))
+
+ call assert_fails('tcl ::vim::expr x y',
+ \ 'wrong # args: should be "::vim::expr vimExpr"')
+ call assert_fails('tcl ::vim::expr 1-', 'E15: Invalid expression: 1-')
+endfunc
+
+" Test ::vim::command
+func Test_vim_command()
+ call assert_equal('hello world',
+ \ TclEval('::vim::command {echo "hello world"}'))
+
+ " Check that if ::vim::command created a new Tcl interpreter, it is removed.
+ tcl set foo 123
+ call assert_equal('321', TclEval('::vim::command "tcl set foo 321"'))
+ call assert_equal('123', TclEval('set foo'))
+
+ " With the -quiet option, the error should silently be ignored.
+ call assert_equal('', TclEval('::vim::command -quiet xyz'))
+
+ call assert_fails('tcl ::vim::command',
+ \ 'wrong # args: should be "::vim::command ?-quiet? exCommand"')
+ call assert_fails('tcl ::vim::command -foo xyz', 'unknown flag: -foo')
+ call assert_fails('tcl ::vim::command xyz',
+ \ 'E492: Not an editor command: xyz')
+
+ " With the -quiet option, the error should silently be ignored.
+ call assert_equal('', TclEval('::vim::command -quiet xyz'))
+
+ tcl unset foo
+endfunc
+
+" Test ::vim::window list
+func Test_vim_window_list()
+ e Xfoo1
+ new Xfoo2
+ let w2 = TclEval('set ::vim::current(window)')
+ wincmd j
+ let w1 = TclEval('set ::vim::current(window)')
+
+ call assert_equal('2', TclEval('llength [::vim::window list]'))
+ call assert_equal(w2.' '.w1, TclEval('::vim::window list'))
+
+ call assert_fails('tcl ::vim::window x', 'unknown option')
+ call assert_fails('tcl ::vim::window list x',
+ \ 'wrong # args: should be "::vim::window option"')
+
+ %bwipe
+endfunc
+
+" Test output messages
+func Test_output()
+ call assert_fails('tcl puts vimerr "error #1"', 'error #1')
+ call assert_fails('tcl puts stderr "error #2"', 'error #2')
+ tcl puts vimout "message #1"
+ tcl puts stdout "message #2"
+ tcl puts "message #3"
+ let messages = split(execute('message'), "\n")
+ call assert_equal('message #3', messages[-1])
+ call assert_equal('message #2', messages[-2])
+ call assert_equal('message #1', messages[-3])
+
+ call assert_fails('tcl puts',
+ \ 'wrong # args: should be "puts ?-nonewline? ?channelId? string"')
+endfunc
+
+" Test $win height (get and set window height)
+func Test_window_height()
+ new
+
+ " Test setting window height
+ tcl $::vim::current(window) height 2
+ call assert_equal(2, winheight(0))
+
+ " Test getting window height
+ call assert_equal('2', TclEval('$::vim::current(window) height'))
+
+ call assert_fails('tcl $::vim::current(window) height 2 2', 'wrong # args:')
+ call assert_fails('tcl $::vim::current(window) height x',
+ \ 'expected integer but got "x"')
+ bwipe
+endfunc
+
+" Test $win cursor (get and set cursor)
+func Test_window_cursor()
+ new
+ call setline(1, ['line1', 'line2', 'line3', 'line5'])
+ tcl set win $::vim::current(window)
+
+ tcl $win cursor 2 4
+ call assert_equal([0, 2, 4, 0], getpos('.'))
+ call assert_equal('row 2 column 4', TclEval('$win cursor'))
+
+ " When setting ::vim::lbase to 0, line/col are counted from 0
+ " instead of 1.
+ tcl set ::vim::lbase 0
+ call assert_equal([0, 2, 4, 0], getpos('.'))
+ call assert_equal('row 1 column 3', TclEval('$win cursor'))
+ tcl $win cursor 2 4
+ call assert_equal([0, 3, 5, 0], getpos('.'))
+ call assert_equal('row 2 column 4', TclEval('$win cursor'))
+ tcl set ::vim::lbase 1
+ call assert_equal('row 3 column 5', TclEval('$win cursor'))
+ call assert_equal([0, 3, 5, 0], getpos('.'))
+
+ " test $win cursor {$var}
+ call cursor(2, 3)
+ tcl array set here [$win cursor]
+ call assert_equal([0, 2, 3, 0], getpos('.'))
+ call cursor(3, 1)
+ call assert_equal([0, 3, 1, 0], getpos('.'))
+ tcl $win cursor here
+ call assert_equal([0, 2, 3, 0], getpos('.'))
+ call cursor(3, 1)
+ call assert_equal([0, 3, 1, 0], getpos('.'))
+ tcl $win cursor $here(row) $here(column)
+ call assert_equal([0, 2, 3, 0], getpos('.'))
+
+ call assert_fails('tcl $win cursor 1 1 1', 'wrong # args:')
+
+ tcl unset win here
+ bwipe!
+endfunc
+
+" Test $win buffer
+func Test_window_buffer()
+ new Xfoo1
+ new Xfoo2
+ tcl set b2 $::vim::current(buffer)
+ tcl set w2 $::vim::current(window)
+ wincmd j
+ tcl set b1 $::vim::current(buffer)
+ tcl set w1 $::vim::current(window)
+
+ call assert_equal(TclEval('set b1'), TclEval('$w1 buffer'))
+ call assert_equal(TclEval('set b2'), TclEval('$w2 buffer'))
+ call assert_equal(string(bufnr('Xfoo1')), TclEval('[$w1 buffer] number'))
+ call assert_equal(string(bufnr('Xfoo2')), TclEval('[$w2 buffer] number'))
+
+ call assert_fails('tcl $w1 buffer x', 'wrong # args:')
+
+ tcl unset b1 b2 w1 w2
+ %bwipe
+endfunc
+
+" Test $win command
+func Test_window_command()
+ new Xfoo1
+ call setline(1, ['FOObar'])
+ new Xfoo2
+ call setline(1, ['fooBAR'])
+ tcl set w2 $::vim::current(window)
+ wincmd j
+ tcl set w1 $::vim::current(window)
+
+ tcl $w1 command "norm VU"
+ tcl $w2 command "norm Vu"
+ b! Xfoo1
+ call assert_equal('FOOBAR', getline(1))
+ b! Xfoo2
+ call assert_equal('foobar', getline(1))
+
+ call assert_fails('tcl $w1 command xyz',
+ \ 'E492: Not an editor command: xyz')
+ tcl $w1 command -quiet xyz
+
+ tcl unset w1 w2
+ %bwipe!
+endfunc
+
+" Test $win expr
+func Test_window_expr()
+ new Xfoo1
+ new Xfoo2
+ tcl set w2 $::vim::current(window)
+ wincmd j
+ tcl set w1 $::vim::current(window)
+
+ call assert_equal('Xfoo1', TclEval('$w1 expr bufname("%")'))
+ call assert_equal('Xfoo2', TclEval('$w2 expr bufname("%")'))
+
+ call assert_fails('tcl $w1 expr', 'wrong # args:')
+ call assert_fails('tcl $w1 expr x x', 'wrong # args:')
+
+ tcl unset w1 w2
+ %bwipe
+endfunc
+
+" Test $win option
+func Test_window_option()
+ new Xfoo1
+ new Xfoo2
+ tcl set w2 $::vim::current(window)
+ wincmd j
+ tcl set w1 $::vim::current(window)
+
+ " Test setting window option
+ tcl $w1 option syntax java
+ tcl $w2 option syntax rust
+
+ call assert_equal('java', &syntax)
+ wincmd k
+ call assert_equal('rust', &syntax)
+
+ " Test getting window option
+ call assert_equal('java', TclEval('$w1 option syntax'))
+ call assert_equal('rust', TclEval('$w2 option syntax'))
+
+ tcl unset w1 w2
+ %bwipe
+endfunc
+
+" Test $win delcmd {cmd}
+func Test_window_delcmd()
+ new
+ tcl $::vim::current(window) delcmd [list set msg "window deleted"]
+ call assert_fails('tcl set msg', "can't read \"msg\": no such variable")
+ q
+ call assert_equal('window deleted', TclEval('set msg'))
+
+ call assert_fails('tcl $::vim::current(window) delcmd', 'wrong # args')
+
+ tcl unset msg
+ bwipe
+endfunc
+
+" Test $buf name
+func Test_buffer_name()
+ " Test buffer name with a named buffer
+ new Xfoo
+ call assert_equal(expand('%:p'), TclEval('$::vim::current(buffer) name'))
+ bwipe
+
+ " Test buffer name with an unnamed buffer
+ new
+ call assert_equal('', TclEval('$::vim::current(buffer) name'))
+
+ call assert_fails('tcl $::vim::current(buffer) name x', 'wrong # args:')
+
+ bwipe
+endfunc
+
+" Test $buf number
+func Test_buffer_number()
+ new
+ call assert_equal(string(bufnr('%')), TclEval('$::vim::current(buffer) number'))
+ new
+ call assert_equal(string(bufnr('%')), TclEval('$::vim::current(buffer) number'))
+
+ call assert_fails('tcl $::vim::current(buffer) number x', 'wrong # args:')
+
+ %bwipe
+endfunc
+
+" Test $buf count and $buf last
+func Test_buffer_count()
+ new
+ call setline(1, ['one', 'two', 'three'])
+ call assert_equal('3', TclEval('$::vim::current(buffer) count'))
+ call assert_equal('3', TclEval('$::vim::current(buffer) last'))
+
+ " Check that $buf count and $buf last differ when ::vim::lbase is 0.
+ tcl set ::vim::lbase 0
+ call assert_equal('3', TclEval('$::vim::current(buffer) count'))
+ call assert_equal('2', TclEval('$::vim::current(buffer) last'))
+
+ call assert_fails('tcl $::vim::current(buffer) count x', 'wrong # args:')
+ call assert_fails('tcl $::vim::current(buffer) last x', 'wrong # args:')
+
+ tcl set ::vim::lbase 1
+ bwipe!
+endfunc
+
+" Test $buf delete (delete line(s) in buffer)
+func Test_buffer_delete()
+ new
+ call setline(1, ['one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight'])
+ tcl $::vim::current(buffer) delete 4 6
+ tcl $::vim::current(buffer) delete 2
+ call assert_equal(['one', 'three', 'seven', 'eight'], getline(1, '$'))
+
+ call assert_fails('tcl $::vim::current(buffer) delete -1', 'line number out of range')
+ call assert_fails('tcl $::vim::current(buffer) delete 0', 'line number out of range')
+ call assert_fails('tcl $::vim::current(buffer) delete 5', 'line number out of range')
+
+ call assert_fails('tcl $::vim::current(buffer) delete', 'wrong # args:')
+ call assert_fails('tcl $::vim::current(buffer) delete 1 2 3', 'wrong # args:')
+
+ bwipe!
+endfunc
+
+" Test $buf insert (insert line(s) in buffer)
+func Test_buffer_insert()
+ new
+ tcl set buf $::vim::current(buffer)
+ tcl $buf insert 1 "first"
+ tcl $buf insert 2 "second"
+ tcl $buf insert 2 "third"
+ tcl $buf insert 4 "fourth"
+ tcl $buf insert 1 "fifth"
+ call assert_equal(['fifth', 'first', 'third', 'second', 'fourth', ''], getline(1, '$'))
+
+ call assert_fails('tcl $buf insert -1 "x"', 'line number out of range')
+ call assert_fails('tcl $buf insert 0 "x"', 'line number out of range')
+ call assert_fails('tcl $buf insert 7 "x"', 'line number out of range')
+
+ tcl unset buf
+ bwipe!
+endfunc
+
+" Test $buf append (append line in buffer)
+func Test_buffer_append()
+ new
+ tcl set buf $::vim::current(buffer)
+ tcl $buf append 1 "first"
+ tcl $buf append 2 "second"
+ tcl $buf append 2 "third"
+ tcl $buf append 4 "fourth"
+ tcl $buf append 1 "fifth"
+ call assert_equal(['', 'fifth', 'first', 'third', 'second', 'fourth'], getline(1, '$'))
+
+ call assert_fails('tcl $buf append -1 "x"', 'line number out of range')
+ call assert_fails('tcl $buf append 0 "x"', 'line number out of range')
+ call assert_fails('tcl $buf append 7 "x"', 'line number out of range')
+
+ call assert_fails('tcl $buf append', 'wrong # args:')
+ call assert_fails('tcl $buf append 1 x x', 'wrong # args:')
+
+ tcl unset buf
+ bwipe!
+endfunc
+
+" Test $buf set (replacing line(s) in a buffer)
+func Test_buffer_set()
+ new
+ call setline(1, ['line1', 'line2', 'line3', 'line4', 'line5'])
+ tcl $::vim::current(buffer) set 2 a
+ call assert_equal(['line1', 'a', 'line3', 'line4', 'line5'], getline(1, '$'))
+
+ " Test with fewer replacing lines than replaced lines: lines get deleted.
+ tcl $::vim::current(buffer) set 3 4 b
+ call assert_equal(['line1', 'a', 'b', 'line5'], getline(1, '$'))
+ tcl $::vim::current(buffer) set 4 3 c
+ call assert_equal(['line1', 'a', 'c'], getline(1, '$'))
+
+ " Test with more replacing lines than replaced lines: lines get added.
+ tcl $::vim::current(buffer) set 2 3 {x y z}
+ call assert_equal(['line1', 'x', 'y', 'z'], getline(1, '$'))
+ tcl $::vim::current(buffer) set 3 2 {X Y Z}
+ call assert_equal(['line1', 'X', 'Y', 'Z', 'z'], getline(1, '$'))
+
+ call assert_fails('tcl $::vim::current(buffer) set 0 "x"', 'line number out of range')
+ call assert_fails('tcl $::vim::current(buffer) set 6 "x"', 'line number out of range')
+
+ call assert_fails('tcl $::vim::current(buffer) set', 'wrong # args:')
+ bwipe!
+endfunc
+
+" Test $buf get (get line(s) from buffer)
+func Test_buffer_get()
+ new
+ call setline(1, ['first line', 'two', 'three', 'last line'])
+ tcl set buf $::vim::current(buffer)
+
+ call assert_equal('first line', TclEval('$buf get top'))
+ call assert_equal('first line', TclEval('$buf get begin'))
+ call assert_equal('last line', TclEval('$buf get bottom'))
+ call assert_equal('last line', TclEval('$buf get last'))
+
+ call assert_equal('first line', TclEval('$buf get 1'))
+ call assert_equal('two', TclEval('$buf get 2'))
+ call assert_equal('three', TclEval('$buf get 3'))
+ call assert_equal('last line', TclEval('$buf get 4'))
+
+ call assert_equal('two three', TclEval('$buf get 2 3'))
+ call assert_equal('two three', TclEval('$buf get 3 2'))
+ call assert_equal('three {last line}', TclEval('$buf get 3 last'))
+
+ call assert_fails('tcl $buf get -1', 'line number out of range')
+ call assert_fails('tcl $buf get 0', 'line number out of range')
+ call assert_fails('tcl $buf get 5', 'line number out of range')
+ call assert_fails('tcl $buf get 0 1', 'line number out of range')
+
+ call assert_fails('tcl $::vim::current(buffer) get x', 'expected integer but got "x"')
+ call assert_fails('tcl $::vim::current(buffer) get 1 1 1', 'wrong # args:')
+
+ tcl unset buf
+ bwipe!
+endfunc
+
+" Test $buf mark (get position of a mark)
+func Test_buffer_mark()
+ new
+ call setline(1, ['one', 'two', 'three', 'four'])
+ /three
+ norm! ma
+ norm! jllmB
+
+ call assert_equal('row 3 column 1', TclEval('$::vim::current(buffer) mark a'))
+ call assert_equal('row 4 column 3', TclEval('$::vim::current(buffer) mark B'))
+
+ call assert_fails('tcl $::vim::current(buffer) mark /', 'invalid mark name')
+ call assert_fails('tcl $::vim::current(buffer) mark z', 'mark not set')
+ call assert_fails('tcl $::vim::current(buffer) mark', 'wrong # args:')
+
+ delmarks aB
+ bwipe!
+endfunc
+
+" Test $buf option (test and set option in context of a buffer)
+func Test_buffer_option()
+ new Xfoo1
+ tcl set b1 $::vim::current(buffer)
+ new Xfoo2
+ tcl set b2 $::vim::current(buffer)
+
+ tcl $b1 option foldcolumn 2
+ tcl $b2 option foldcolumn 3
+
+ call assert_equal(3, &foldcolumn)
+ wincmd j
+ call assert_equal(2, &foldcolumn)
+
+ call assert_equal('2', TclEval('$b1 option foldcolumn'))
+ call assert_equal('3', TclEval('$b2 option foldcolumn'))
+
+ call assert_fails('tcl $::vim::current(buffer) option', 'wrong # args:')
+
+ set foldcolumn&
+ tcl unset b1 b2
+ %bwipe
+endfunc
+
+" Test $buf expr (evaluate vim expression)
+func Test_buffer_expr()
+ new Xfoo1
+ norm ifoo1
+ tcl set b1 $::vim::current(buffer)
+
+ new Xfoo2
+ norm ifoo2
+ tcl set b2 $::vim::current(buffer)
+
+ call assert_equal('foo1', TclEval('$b1 expr getline(1)'))
+ call assert_equal('foo2', TclEval('$b2 expr getline(1)'))
+
+ call assert_fails('tcl expr', 'wrong # args:')
+
+ tcl unset b1 b2
+ %bwipe!
+endfunc
+
+" Test $buf delcmd {cmd} (command executed when buffer is deleted)
+func Test_buffer_delcmd()
+ new Xfoo
+ split
+ tcl $::vim::current(buffer) delcmd [list set msg "buffer deleted"]
+ q
+ call assert_fails('tcl set msg', "can't read \"msg\": no such variable")
+ q
+ call assert_equal('buffer deleted', TclEval('set msg'))
+
+ call assert_fails('tcl $::vim::current(window) delcmd', 'wrong # args')
+ call assert_fails('tcl $::vim::current(window) delcmd x x', 'wrong # args')
+
+ tcl unset msg
+ %bwipe
+endfunc
+
+func Test_vim_current()
+ " Only test errors as ::vim::current(...) is already indirectly
+ " tested by many other tests.
+ call assert_fails('tcl $::vim::current(buffer)', 'wrong # args:')
+ call assert_fails('tcl $::vim::current(window)', 'wrong # args:')
+endfunc
+
+" Test $buf windows (windows list of a buffer)
+func Test_buffer_windows()
+ new Xfoo
+ split
+ new Xbar
+ split
+ vsplit
+
+ tcl set bar_wl [$::vim::current(buffer) windows]
+ 2wincmd j
+ tcl set foo_wl [$::vim::current(buffer) windows]
+
+ call assert_equal('2', TclEval('llength $foo_wl'))
+ call assert_equal('3', TclEval('llength $bar_wl'))
+
+ call assert_fails('tcl $::vim::current(buffer) windows x', 'wrong # args:')
+
+ tcl unset bar_wl foo_wl
+ %bwipe
+endfunc
+
+" Test :tclfile
+func Test_tclfile()
+ call delete('Xtcl_file')
+ call writefile(['set pi [format "%.2f" [expr acos(-1.0)]]'], 'Xtcl_file')
+ call setfperm('Xtcl_file', 'r-xr-xr-x')
+
+ tclfile Xtcl_file
+ call assert_equal('3.14', TclEval('set pi'))
+
+ tcl unset pi
+ call delete('Xtcl_file')
+endfunc
+
+" Test :tclfile with syntax error in tcl script
+func Test_tclfile_error()
+ call delete('Xtcl_file')
+ call writefile(['xyz'], 'Xtcl_file')
+ call setfperm('Xtcl_file', 'r-xr-xr-x')
+
+ call assert_fails('tclfile Xtcl_file', 'invalid command name "xyz"')
+
+ call delete('Xtcl_file')
+endfunc
+
+" Test exiting current Tcl interpreter and re-creating one.
+func Test_tcl_exit()
+ tcl set foo "foo"
+ call assert_fails('tcl exit 3', 'E572: exit code 3')
+
+ " The Tcl interpreter should have been deleted and a new one
+ " is re-created with the next :tcl command.
+ call assert_fails('tcl set foo', "can't read \"foo\": no such variable")
+ tcl set bar "bar"
+ call assert_equal('bar', TclEval('set bar'))
+
+ tcl unset bar
+endfunc
+
+func Test_set_cursor()
+ " Check that setting the cursor position works.
+ new
+ call setline(1, ['first line', 'second line'])
+ normal gg
+ tcldo $::vim::current(window) cursor 1 5
+ call assert_equal([1, 5], [line('.'), col('.')])
+
+ " Check that movement after setting cursor position keeps current column.
+ normal j
+ call assert_equal([2, 5], [line('.'), col('.')])
+endfunc
diff --git a/src/testdir/test_termencoding.vim b/src/testdir/test_termencoding.vim
new file mode 100644
index 0000000..f4f5c5a
--- /dev/null
+++ b/src/testdir/test_termencoding.vim
@@ -0,0 +1,37 @@
+" Test for setting 'encoding' to something else than the terminal uses, then
+" setting 'termencoding' to make it work.
+
+" This only works with "iconv".
+if !has('iconv')
+ finish
+endif
+
+source screendump.vim
+if !CanRunVimInTerminal()
+ finish
+endif
+
+" This Vim is running with 'encoding' "utf-8", the Vim in the terminal is
+" running with 'encoding' "euc-jp". We need to make sure the text is in the
+" right encoding, this is a bit tricky.
+func Test_termencoding_euc_jp()
+ new
+ call setline(1, 'E89: ãƒãƒƒãƒ•ã‚¡ %ld ã®å¤‰æ›´ã¯ä¿å­˜ã•ã‚Œã¦ã„ã¾ã›ã‚“ (! ã§å¤‰æ›´ã‚’破棄)')
+ write ++enc=euc-jp Xeuc_jp.txt
+ quit
+
+ call writefile([
+ \ 'set encoding=euc-jp',
+ \ 'set termencoding=utf-8',
+ \ 'scriptencoding utf-8',
+ \ 'exe "normal aE83: ãƒãƒƒãƒ•ã‚¡ã‚’作æˆã§ããªã„ã®ã§ã€ä»–ã®ã‚’使用ã—ã¾ã™...\<Esc>"',
+ \ 'split Xeuc_jp.txt',
+ \ ], 'XTest_tenc_euc_jp')
+ let buf = RunVimInTerminal('-S XTest_tenc_euc_jp', {'rows': 10})
+ call VerifyScreenDump(buf, 'Test_tenc_euc_jp_01', {})
+
+ " clean up
+ call StopVimInTerminal(buf)
+ call delete('Xeuc_jp.txt')
+ call delete('XTest_tenc_euc_jp')
+endfunc
diff --git a/src/testdir/test_terminal.vim b/src/testdir/test_terminal.vim
new file mode 100644
index 0000000..8eb43a0
--- /dev/null
+++ b/src/testdir/test_terminal.vim
@@ -0,0 +1,1758 @@
+" Tests for the terminal window.
+
+if !has('terminal')
+ finish
+endif
+
+source shared.vim
+source screendump.vim
+
+let s:python = PythonProg()
+
+" Open a terminal with a shell, assign the job to g:job and return the buffer
+" number.
+func Run_shell_in_terminal(options)
+ if has('win32')
+ let buf = term_start([&shell,'/k'], a:options)
+ else
+ let buf = term_start(&shell, a:options)
+ endif
+
+ let termlist = term_list()
+ call assert_equal(1, len(termlist))
+ call assert_equal(buf, termlist[0])
+
+ let g:job = term_getjob(buf)
+ call assert_equal(v:t_job, type(g:job))
+
+ let string = string({'job': term_getjob(buf)})
+ call assert_match("{'job': 'process \\d\\+ run'}", string)
+
+ return buf
+endfunc
+
+func Test_terminal_basic()
+ au TerminalOpen * let b:done = 'yes'
+ let buf = Run_shell_in_terminal({})
+
+ if has("unix")
+ call assert_match('^/dev/', job_info(g:job).tty_out)
+ call assert_match('^/dev/', term_gettty(''))
+ else
+ " ConPTY works on anonymous pipe.
+ if !has('conpty')
+ call assert_match('^\\\\.\\pipe\\', job_info(g:job).tty_out)
+ call assert_match('^\\\\.\\pipe\\', term_gettty(''))
+ endif
+ endif
+ call assert_equal('t', mode())
+ call assert_equal('yes', b:done)
+ call assert_match('%aR[^\n]*running]', execute('ls'))
+ call assert_match('%aR[^\n]*running]', execute('ls R'))
+ call assert_notmatch('%[^\n]*running]', execute('ls F'))
+ call assert_notmatch('%[^\n]*running]', execute('ls ?'))
+
+ call Stop_shell_in_terminal(buf)
+ call term_wait(buf)
+ call assert_equal('n', mode())
+ call assert_match('%aF[^\n]*finished]', execute('ls'))
+ call assert_match('%aF[^\n]*finished]', execute('ls F'))
+ call assert_notmatch('%[^\n]*finished]', execute('ls R'))
+ call assert_notmatch('%[^\n]*finished]', execute('ls ?'))
+
+ " closing window wipes out the terminal buffer a with finished job
+ close
+ call assert_equal("", bufname(buf))
+
+ au! TerminalOpen
+ unlet g:job
+endfunc
+
+func Test_terminal_make_change()
+ let buf = Run_shell_in_terminal({})
+ call Stop_shell_in_terminal(buf)
+ call term_wait(buf)
+
+ setlocal modifiable
+ exe "normal Axxx\<Esc>"
+ call assert_fails(buf . 'bwipe', 'E517')
+ undo
+
+ exe buf . 'bwipe'
+ unlet g:job
+endfunc
+
+func Test_terminal_wipe_buffer()
+ let buf = Run_shell_in_terminal({})
+ call assert_fails(buf . 'bwipe', 'E517')
+ exe buf . 'bwipe!'
+ call WaitForAssert({-> assert_equal('dead', job_status(g:job))})
+ call assert_equal("", bufname(buf))
+
+ unlet g:job
+endfunc
+
+func Test_terminal_split_quit()
+ let buf = Run_shell_in_terminal({})
+ call term_wait(buf)
+ split
+ quit!
+ call term_wait(buf)
+ sleep 50m
+ call assert_equal('run', job_status(g:job))
+
+ quit!
+ call WaitForAssert({-> assert_equal('dead', job_status(g:job))})
+
+ exe buf . 'bwipe'
+ unlet g:job
+endfunc
+
+func Test_terminal_hide_buffer()
+ let buf = Run_shell_in_terminal({})
+ setlocal bufhidden=hide
+ quit
+ for nr in range(1, winnr('$'))
+ call assert_notequal(winbufnr(nr), buf)
+ endfor
+ call assert_true(bufloaded(buf))
+ call assert_true(buflisted(buf))
+
+ exe 'split ' . buf . 'buf'
+ call Stop_shell_in_terminal(buf)
+ exe buf . 'bwipe'
+
+ unlet g:job
+endfunc
+
+func s:Nasty_exit_cb(job, st)
+ exe g:buf . 'bwipe!'
+ let g:buf = 0
+endfunc
+
+func Get_cat_123_cmd()
+ if has('win32')
+ if !has('conpty')
+ return 'cmd /c "cls && color 2 && echo 123"'
+ else
+ " When clearing twice, extra sequence is not output.
+ return 'cmd /c "cls && cls && color 2 && echo 123"'
+ endif
+ else
+ call writefile(["\<Esc>[32m123"], 'Xtext')
+ return "cat Xtext"
+ endif
+endfunc
+
+func Test_terminal_nasty_cb()
+ let cmd = Get_cat_123_cmd()
+ let g:buf = term_start(cmd, {'exit_cb': function('s:Nasty_exit_cb')})
+ let g:job = term_getjob(g:buf)
+
+ call WaitForAssert({-> assert_equal("dead", job_status(g:job))})
+ call WaitForAssert({-> assert_equal(0, g:buf)})
+ unlet g:job
+ unlet g:buf
+ call delete('Xtext')
+endfunc
+
+func Check_123(buf)
+ let l = term_scrape(a:buf, 0)
+ call assert_true(len(l) == 0)
+ let l = term_scrape(a:buf, 999)
+ call assert_true(len(l) == 0)
+ let l = term_scrape(a:buf, 1)
+ call assert_true(len(l) > 0)
+ call assert_equal('1', l[0].chars)
+ call assert_equal('2', l[1].chars)
+ call assert_equal('3', l[2].chars)
+ call assert_equal('#00e000', l[0].fg)
+ if has('win32')
+ " On Windows 'background' always defaults to dark, even though the terminal
+ " may use a light background. Therefore accept both white and black.
+ call assert_match('#ffffff\|#000000', l[0].bg)
+ else
+ if &background == 'light'
+ call assert_equal('#ffffff', l[0].bg)
+ else
+ call assert_equal('#000000', l[0].bg)
+ endif
+ endif
+
+ let l = term_getline(a:buf, -1)
+ call assert_equal('', l)
+ let l = term_getline(a:buf, 0)
+ call assert_equal('', l)
+ let l = term_getline(a:buf, 999)
+ call assert_equal('', l)
+ let l = term_getline(a:buf, 1)
+ call assert_equal('123', l)
+endfunc
+
+func Test_terminal_scrape_123()
+ let cmd = Get_cat_123_cmd()
+ let buf = term_start(cmd)
+
+ let termlist = term_list()
+ call assert_equal(1, len(termlist))
+ call assert_equal(buf, termlist[0])
+
+ " Nothing happens with invalid buffer number
+ call term_wait(1234)
+
+ call term_wait(buf)
+ " On MS-Windows we first get a startup message of two lines, wait for the
+ " "cls" to happen, after that we have one line with three characters.
+ call WaitForAssert({-> assert_equal(3, len(term_scrape(buf, 1)))})
+ call Check_123(buf)
+
+ " Must still work after the job ended.
+ let job = term_getjob(buf)
+ call WaitForAssert({-> assert_equal("dead", job_status(job))})
+ call term_wait(buf)
+ call Check_123(buf)
+
+ exe buf . 'bwipe'
+ call delete('Xtext')
+endfunc
+
+func Test_terminal_scrape_multibyte()
+ call writefile(["léttã¾rs"], 'Xtext')
+ if has('win32')
+ " Run cmd with UTF-8 codepage to make the type command print the expected
+ " multibyte characters.
+ let buf = term_start("cmd /K chcp 65001")
+ call term_sendkeys(buf, "type Xtext\<CR>")
+ call term_sendkeys(buf, "exit\<CR>")
+ let line = 4
+ else
+ let buf = term_start("cat Xtext")
+ let line = 1
+ endif
+
+ call WaitFor({-> len(term_scrape(buf, line)) >= 7 && term_scrape(buf, line)[0].chars == "l"})
+ let l = term_scrape(buf, line)
+ call assert_true(len(l) >= 7)
+ call assert_equal('l', l[0].chars)
+ call assert_equal('é', l[1].chars)
+ call assert_equal(1, l[1].width)
+ call assert_equal('t', l[2].chars)
+ call assert_equal('t', l[3].chars)
+ call assert_equal('ã¾', l[4].chars)
+ call assert_equal(2, l[4].width)
+ call assert_equal('r', l[5].chars)
+ call assert_equal('s', l[6].chars)
+
+ let job = term_getjob(buf)
+ call WaitForAssert({-> assert_equal("dead", job_status(job))})
+ call term_wait(buf)
+
+ exe buf . 'bwipe'
+ call delete('Xtext')
+endfunc
+
+func Test_terminal_scroll()
+ call writefile(range(1, 200), 'Xtext')
+ if has('win32')
+ let cmd = 'cmd /c "type Xtext"'
+ else
+ let cmd = "cat Xtext"
+ endif
+ let buf = term_start(cmd)
+
+ let job = term_getjob(buf)
+ call WaitForAssert({-> assert_equal("dead", job_status(job))})
+ call term_wait(buf)
+ if has('win32')
+ " TODO: this should not be needed
+ sleep 100m
+ endif
+
+ let scrolled = term_getscrolled(buf)
+ call assert_equal('1', getline(1))
+ call assert_equal('1', term_getline(buf, 1 - scrolled))
+ call assert_equal('49', getline(49))
+ call assert_equal('49', term_getline(buf, 49 - scrolled))
+ call assert_equal('200', getline(200))
+ call assert_equal('200', term_getline(buf, 200 - scrolled))
+
+ exe buf . 'bwipe'
+ call delete('Xtext')
+endfunc
+
+func Test_terminal_scrollback()
+ let buf = Run_shell_in_terminal({'term_rows': 15})
+ set termwinscroll=100
+ call writefile(range(150), 'Xtext')
+ if has('win32')
+ call term_sendkeys(buf, "type Xtext\<CR>")
+ else
+ call term_sendkeys(buf, "cat Xtext\<CR>")
+ endif
+ let rows = term_getsize(buf)[0]
+ " On MS-Windows there is an empty line, check both last line and above it.
+ call WaitForAssert({-> assert_match( '149', term_getline(buf, rows - 1) . term_getline(buf, rows - 2))})
+ let lines = line('$')
+ call assert_inrange(91, 100, lines)
+
+ call Stop_shell_in_terminal(buf)
+ call term_wait(buf)
+ exe buf . 'bwipe'
+ set termwinscroll&
+endfunc
+
+func Test_terminal_size()
+ let cmd = Get_cat_123_cmd()
+
+ exe 'terminal ++rows=5 ' . cmd
+ let size = term_getsize('')
+ bwipe!
+ call assert_equal(5, size[0])
+
+ call term_start(cmd, {'term_rows': 6})
+ let size = term_getsize('')
+ bwipe!
+ call assert_equal(6, size[0])
+
+ vsplit
+ exe 'terminal ++rows=5 ++cols=33 ' . cmd
+ call assert_equal([5, 33], term_getsize(''))
+
+ call term_setsize('', 6, 0)
+ call assert_equal([6, 33], term_getsize(''))
+
+ call term_setsize('', 0, 35)
+ call assert_equal([6, 35], term_getsize(''))
+
+ call term_setsize('', 7, 30)
+ call assert_equal([7, 30], term_getsize(''))
+
+ bwipe!
+ call assert_fails("call term_setsize('', 7, 30)", "E955:")
+
+ call term_start(cmd, {'term_rows': 6, 'term_cols': 36})
+ let size = term_getsize('')
+ bwipe!
+ call assert_equal([6, 36], size)
+
+ exe 'vertical terminal ++cols=20 ' . cmd
+ let size = term_getsize('')
+ bwipe!
+ call assert_equal(20, size[1])
+
+ call term_start(cmd, {'vertical': 1, 'term_cols': 26})
+ let size = term_getsize('')
+ bwipe!
+ call assert_equal(26, size[1])
+
+ split
+ exe 'vertical terminal ++rows=6 ++cols=20 ' . cmd
+ let size = term_getsize('')
+ bwipe!
+ call assert_equal([6, 20], size)
+
+ call term_start(cmd, {'vertical': 1, 'term_rows': 7, 'term_cols': 27})
+ let size = term_getsize('')
+ bwipe!
+ call assert_equal([7, 27], size)
+
+ call delete('Xtext')
+endfunc
+
+func Test_terminal_curwin()
+ let cmd = Get_cat_123_cmd()
+ call assert_equal(1, winnr('$'))
+
+ split dummy
+ exe 'terminal ++curwin ' . cmd
+ call assert_equal(2, winnr('$'))
+ bwipe!
+
+ split dummy
+ call term_start(cmd, {'curwin': 1})
+ call assert_equal(2, winnr('$'))
+ bwipe!
+
+ split dummy
+ call setline(1, 'change')
+ call assert_fails('terminal ++curwin ' . cmd, 'E37:')
+ call assert_equal(2, winnr('$'))
+ exe 'terminal! ++curwin ' . cmd
+ call assert_equal(2, winnr('$'))
+ bwipe!
+
+ split dummy
+ call setline(1, 'change')
+ call assert_fails("call term_start(cmd, {'curwin': 1})", 'E37:')
+ call assert_equal(2, winnr('$'))
+ bwipe!
+
+ split dummy
+ bwipe!
+ call delete('Xtext')
+endfunc
+
+func s:get_sleep_cmd()
+ if s:python != ''
+ let cmd = s:python . " test_short_sleep.py"
+ " 500 was not enough for Travis
+ let waittime = 900
+ else
+ echo 'This will take five seconds...'
+ let waittime = 2000
+ if has('win32')
+ let cmd = $windir . '\system32\timeout.exe 1'
+ else
+ let cmd = 'sleep 1'
+ endif
+ endif
+ return [cmd, waittime]
+endfunc
+
+func Test_terminal_finish_open_close()
+ call assert_equal(1, winnr('$'))
+
+ let [cmd, waittime] = s:get_sleep_cmd()
+
+ " shell terminal closes automatically
+ terminal
+ let buf = bufnr('%')
+ call assert_equal(2, winnr('$'))
+ " Wait for the shell to display a prompt
+ call WaitForAssert({-> assert_notequal('', term_getline(buf, 1))})
+ call Stop_shell_in_terminal(buf)
+ call WaitForAssert({-> assert_equal(1, winnr('$'))}, waittime)
+
+ " shell terminal that does not close automatically
+ terminal ++noclose
+ let buf = bufnr('%')
+ call assert_equal(2, winnr('$'))
+ " Wait for the shell to display a prompt
+ call WaitForAssert({-> assert_notequal('', term_getline(buf, 1))})
+ call Stop_shell_in_terminal(buf)
+ call assert_equal(2, winnr('$'))
+ quit
+ call assert_equal(1, winnr('$'))
+
+ exe 'terminal ++close ' . cmd
+ call assert_equal(2, winnr('$'))
+ wincmd p
+ call WaitForAssert({-> assert_equal(1, winnr('$'))}, waittime)
+
+ call term_start(cmd, {'term_finish': 'close'})
+ call assert_equal(2, winnr('$'))
+ wincmd p
+ call WaitForAssert({-> assert_equal(1, winnr('$'))}, waittime)
+ call assert_equal(1, winnr('$'))
+
+ exe 'terminal ++open ' . cmd
+ close!
+ call WaitForAssert({-> assert_equal(2, winnr('$'))}, waittime)
+ bwipe
+
+ call term_start(cmd, {'term_finish': 'open'})
+ close!
+ call WaitForAssert({-> assert_equal(2, winnr('$'))}, waittime)
+ bwipe
+
+ exe 'terminal ++hidden ++open ' . cmd
+ call assert_equal(1, winnr('$'))
+ call WaitForAssert({-> assert_equal(2, winnr('$'))}, waittime)
+ bwipe
+
+ call term_start(cmd, {'term_finish': 'open', 'hidden': 1})
+ call assert_equal(1, winnr('$'))
+ call WaitForAssert({-> assert_equal(2, winnr('$'))}, waittime)
+ bwipe
+
+ call assert_fails("call term_start(cmd, {'term_opencmd': 'open'})", 'E475:')
+ call assert_fails("call term_start(cmd, {'term_opencmd': 'split %x'})", 'E475:')
+ call assert_fails("call term_start(cmd, {'term_opencmd': 'split %d and %s'})", 'E475:')
+ call assert_fails("call term_start(cmd, {'term_opencmd': 'split % and %d'})", 'E475:')
+
+ call term_start(cmd, {'term_finish': 'open', 'term_opencmd': '4split | buffer %d'})
+ close!
+ call WaitForAssert({-> assert_equal(2, winnr('$'))}, waittime)
+ call assert_equal(4, winheight(0))
+ bwipe
+endfunc
+
+func Test_terminal_cwd()
+ if !executable('pwd')
+ return
+ endif
+ call mkdir('Xdir')
+ let buf = term_start('pwd', {'cwd': 'Xdir'})
+ call WaitForAssert({-> assert_equal('Xdir', fnamemodify(getline(1), ":t"))})
+
+ exe buf . 'bwipe'
+ call delete('Xdir', 'rf')
+endfunc
+
+func Test_terminal_cwd_failure()
+ " Case 1: Provided directory is not actually a directory. Attempt to make
+ " the file executable as well.
+ call writefile([], 'Xfile')
+ call setfperm('Xfile', 'rwx------')
+ call assert_fails("call term_start(&shell, {'cwd': 'Xfile'})", 'E475:')
+ call delete('Xfile')
+
+ " Case 2: Directory does not exist.
+ call assert_fails("call term_start(&shell, {'cwd': 'Xdir'})", 'E475:')
+
+ " Case 3: Directory exists but is not accessible.
+ " Skip this for root, it will be accessible anyway.
+ if $USER != 'root'
+ call mkdir('XdirNoAccess', '', '0600')
+ " return early if the directory permissions could not be set properly
+ if getfperm('XdirNoAccess')[2] == 'x'
+ call delete('XdirNoAccess', 'rf')
+ return
+ endif
+ call assert_fails("call term_start(&shell, {'cwd': 'XdirNoAccess'})", 'E475:')
+ call delete('XdirNoAccess', 'rf')
+ endif
+endfunc
+
+func Test_terminal_servername()
+ if !has('clientserver')
+ return
+ endif
+ call s:test_environment("VIM_SERVERNAME", v:servername)
+endfunc
+
+func Test_terminal_version()
+ call s:test_environment("VIM_TERMINAL", string(v:version))
+endfunc
+
+func s:test_environment(name, value)
+ let buf = Run_shell_in_terminal({})
+ " Wait for the shell to display a prompt
+ call WaitForAssert({-> assert_notequal('', term_getline(buf, 1))})
+ if has('win32')
+ call term_sendkeys(buf, "echo %" . a:name . "%\r")
+ else
+ call term_sendkeys(buf, "echo $" . a:name . "\r")
+ endif
+ call term_wait(buf)
+ call Stop_shell_in_terminal(buf)
+ call WaitForAssert({-> assert_equal(a:value, getline(2))})
+
+ exe buf . 'bwipe'
+ unlet buf
+endfunc
+
+func Test_terminal_env()
+ let buf = Run_shell_in_terminal({'env': {'TESTENV': 'correct'}})
+ " Wait for the shell to display a prompt
+ call WaitForAssert({-> assert_notequal('', term_getline(buf, 1))})
+ if has('win32')
+ call term_sendkeys(buf, "echo %TESTENV%\r")
+ else
+ call term_sendkeys(buf, "echo $TESTENV\r")
+ endif
+ call term_wait(buf)
+ call Stop_shell_in_terminal(buf)
+ call WaitForAssert({-> assert_equal('correct', getline(2))})
+
+ exe buf . 'bwipe'
+endfunc
+
+func Test_terminal_list_args()
+ let buf = term_start([&shell, &shellcmdflag, 'echo "123"'])
+ call assert_fails(buf . 'bwipe', 'E517')
+ exe buf . 'bwipe!'
+ call assert_equal("", bufname(buf))
+endfunction
+
+func Test_terminal_noblock()
+ let buf = term_start(&shell)
+ if has('bsd') || has('mac') || has('sun')
+ " The shell or something else has a problem dealing with more than 1000
+ " characters at the same time.
+ let len = 1000
+ " NPFS is used in Windows, nonblocking mode does not work properly.
+ elseif has('win32')
+ let len = 1
+ else
+ let len = 5000
+ endif
+
+ for c in ['a','b','c','d','e','f','g','h','i','j','k']
+ call term_sendkeys(buf, 'echo ' . repeat(c, len) . "\<cr>")
+ endfor
+ call term_sendkeys(buf, "echo done\<cr>")
+
+ " On MS-Windows there is an extra empty line below "done". Find "done" in
+ " the last-but-one or the last-but-two line.
+ let lnum = term_getsize(buf)[0] - 1
+ call WaitFor({-> term_getline(buf, lnum) =~ "done" || term_getline(buf, lnum - 1) =~ "done"}, 10000)
+ let line = term_getline(buf, lnum)
+ if line !~ 'done'
+ let line = term_getline(buf, lnum - 1)
+ endif
+ call assert_match('done', line)
+
+ let g:job = term_getjob(buf)
+ call Stop_shell_in_terminal(buf)
+ call term_wait(buf)
+ unlet g:job
+ bwipe
+endfunc
+
+func Test_terminal_write_stdin()
+ if !executable('wc')
+ throw 'skipped: wc command not available'
+ endif
+ if has('win32')
+ " TODO: enable once writing to stdin works on MS-Windows
+ return
+ endif
+ new
+ call setline(1, ['one', 'two', 'three'])
+ %term wc
+ call WaitForAssert({-> assert_match('3', getline("$"))})
+ let nrs = split(getline('$'))
+ call assert_equal(['3', '3', '14'], nrs)
+ bwipe
+
+ new
+ call setline(1, ['one', 'two', 'three', 'four'])
+ 2,3term wc
+ call WaitForAssert({-> assert_match('2', getline("$"))})
+ let nrs = split(getline('$'))
+ call assert_equal(['2', '2', '10'], nrs)
+ bwipe
+
+ if executable('python')
+ new
+ call setline(1, ['print("hello")'])
+ 1term ++eof=exit() python
+ " MS-Windows echoes the input, Unix doesn't.
+ call WaitFor('getline("$") =~ "exit" || getline(1) =~ "hello"')
+ if getline(1) =~ 'hello'
+ call assert_equal('hello', getline(1))
+ else
+ call assert_equal('hello', getline(line('$') - 1))
+ endif
+ bwipe
+
+ if has('win32')
+ new
+ call setline(1, ['print("hello")'])
+ 1term ++eof=<C-Z> python
+ call WaitForAssert({-> assert_match('Z', getline("$"))})
+ call assert_equal('hello', getline(line('$') - 1))
+ bwipe
+ endif
+ endif
+
+ bwipe!
+endfunc
+
+func Test_terminal_no_cmd()
+ let buf = term_start('NONE', {})
+ call assert_notequal(0, buf)
+
+ let pty = job_info(term_getjob(buf))['tty_out']
+ call assert_notequal('', pty)
+ if has('gui_running') && !has('win32')
+ " In the GUI job_start() doesn't work, it does not read from the pty.
+ call system('echo "look here" > ' . pty)
+ else
+ " Otherwise using a job works on all systems.
+ call job_start([&shell, &shellcmdflag, 'echo "look here" > ' . pty])
+ endif
+ call WaitForAssert({-> assert_match('look here', term_getline(buf, 1))})
+
+ bwipe!
+endfunc
+
+func Test_terminal_special_chars()
+ " this file name only works on Unix
+ if !has('unix')
+ return
+ endif
+ call mkdir('Xdir with spaces')
+ call writefile(['x'], 'Xdir with spaces/quoted"file')
+ term ls Xdir\ with\ spaces/quoted\"file
+ call WaitForAssert({-> assert_match('quoted"file', term_getline('', 1))})
+ call term_wait('')
+
+ call delete('Xdir with spaces', 'rf')
+ bwipe
+endfunc
+
+func Test_terminal_wrong_options()
+ call assert_fails('call term_start(&shell, {
+ \ "in_io": "file",
+ \ "in_name": "xxx",
+ \ "out_io": "file",
+ \ "out_name": "xxx",
+ \ "err_io": "file",
+ \ "err_name": "xxx"
+ \ })', 'E474:')
+ call assert_fails('call term_start(&shell, {
+ \ "out_buf": bufnr("%")
+ \ })', 'E474:')
+ call assert_fails('call term_start(&shell, {
+ \ "err_buf": bufnr("%")
+ \ })', 'E474:')
+endfunc
+
+func Test_terminal_redir_file()
+ let cmd = Get_cat_123_cmd()
+ let buf = term_start(cmd, {'out_io': 'file', 'out_name': 'Xfile'})
+ call term_wait(buf)
+ " ConPTY may precede escape sequence. There are things that are not so.
+ if !has('conpty')
+ call WaitForAssert({-> assert_notequal(0, len(readfile("Xfile")))})
+ call assert_match('123', readfile('Xfile')[0])
+ endif
+ let g:job = term_getjob(buf)
+ call WaitForAssert({-> assert_equal("dead", job_status(g:job))})
+ call delete('Xfile')
+ bwipe
+
+ if has('unix')
+ call writefile(['one line'], 'Xfile')
+ let buf = term_start('cat', {'in_io': 'file', 'in_name': 'Xfile'})
+ call term_wait(buf)
+ call WaitForAssert({-> assert_equal('one line', term_getline(buf, 1))})
+ let g:job = term_getjob(buf)
+ call WaitForAssert({-> assert_equal('dead', job_status(g:job))})
+ bwipe
+ call delete('Xfile')
+ endif
+endfunc
+
+func TerminalTmap(remap)
+ let buf = Run_shell_in_terminal({})
+ call assert_equal('t', mode())
+
+ if a:remap
+ tmap 123 456
+ else
+ tnoremap 123 456
+ endif
+ " don't use abcde, it's an existing command
+ tmap 456 abxde
+ call assert_equal('456', maparg('123', 't'))
+ call assert_equal('abxde', maparg('456', 't'))
+ call feedkeys("123", 'tx')
+ call WaitForAssert({-> assert_match('abxde\|456', term_getline(buf, term_getcursor(buf)[0]))})
+ let lnum = term_getcursor(buf)[0]
+ if a:remap
+ call assert_match('abxde', term_getline(buf, lnum))
+ else
+ call assert_match('456', term_getline(buf, lnum))
+ endif
+
+ call term_sendkeys(buf, "\r")
+ call Stop_shell_in_terminal(buf)
+ call term_wait(buf)
+
+ tunmap 123
+ tunmap 456
+ call assert_equal('', maparg('123', 't'))
+ close
+ unlet g:job
+endfunc
+
+func Test_terminal_tmap()
+ call TerminalTmap(1)
+ call TerminalTmap(0)
+endfunc
+
+func Test_terminal_wall()
+ let buf = Run_shell_in_terminal({})
+ wall
+ call Stop_shell_in_terminal(buf)
+ call term_wait(buf)
+ exe buf . 'bwipe'
+ unlet g:job
+endfunc
+
+func Test_terminal_wqall()
+ let buf = Run_shell_in_terminal({})
+ call assert_fails('wqall', 'E948')
+ call Stop_shell_in_terminal(buf)
+ call term_wait(buf)
+ exe buf . 'bwipe'
+ unlet g:job
+endfunc
+
+func Test_terminal_composing_unicode()
+ let save_enc = &encoding
+ set encoding=utf-8
+
+ if has('win32')
+ let cmd = "cmd /K chcp 65001"
+ let lnum = [3, 6, 9]
+ else
+ let cmd = &shell
+ let lnum = [1, 3, 5]
+ endif
+
+ enew
+ let buf = term_start(cmd, {'curwin': bufnr('')})
+ let g:job = term_getjob(buf)
+ call term_wait(buf, 50)
+
+ if has('win32')
+ call assert_equal('cmd', job_info(g:job).cmd[0])
+ else
+ call assert_equal(&shell, job_info(g:job).cmd[0])
+ endif
+
+ " ascii + composing
+ let txt = "a\u0308bc"
+ call term_sendkeys(buf, "echo " . txt . "\r")
+ call term_wait(buf, 50)
+ call assert_match("echo " . txt, term_getline(buf, lnum[0]))
+ call assert_equal(txt, term_getline(buf, lnum[0] + 1))
+ let l = term_scrape(buf, lnum[0] + 1)
+ call assert_equal("a\u0308", l[0].chars)
+ call assert_equal("b", l[1].chars)
+ call assert_equal("c", l[2].chars)
+
+ " multibyte + composing
+ let txt = "\u304b\u3099\u304e\u304f\u3099\u3052\u3053\u3099"
+ call term_sendkeys(buf, "echo " . txt . "\r")
+ call term_wait(buf, 50)
+ call assert_match("echo " . txt, term_getline(buf, lnum[1]))
+ call assert_equal(txt, term_getline(buf, lnum[1] + 1))
+ let l = term_scrape(buf, lnum[1] + 1)
+ call assert_equal("\u304b\u3099", l[0].chars)
+ call assert_equal("\u304e", l[1].chars)
+ call assert_equal("\u304f\u3099", l[2].chars)
+ call assert_equal("\u3052", l[3].chars)
+ call assert_equal("\u3053\u3099", l[4].chars)
+
+ " \u00a0 + composing
+ let txt = "abc\u00a0\u0308"
+ call term_sendkeys(buf, "echo " . txt . "\r")
+ call term_wait(buf, 50)
+ call assert_match("echo " . txt, term_getline(buf, lnum[2]))
+ call assert_equal(txt, term_getline(buf, lnum[2] + 1))
+ let l = term_scrape(buf, lnum[2] + 1)
+ call assert_equal("\u00a0\u0308", l[3].chars)
+
+ call term_sendkeys(buf, "exit\r")
+ call WaitForAssert({-> assert_equal('dead', job_status(g:job))})
+ bwipe!
+ unlet g:job
+ let &encoding = save_enc
+endfunc
+
+func Test_terminal_aucmd_on_close()
+ fun Nop()
+ let s:called = 1
+ endfun
+
+ aug repro
+ au!
+ au BufWinLeave * call Nop()
+ aug END
+
+ let [cmd, waittime] = s:get_sleep_cmd()
+
+ call assert_equal(1, winnr('$'))
+ new
+ call setline(1, ['one', 'two'])
+ exe 'term ++close ' . cmd
+ wincmd p
+ call WaitForAssert({-> assert_equal(2, winnr('$'))}, waittime)
+ call assert_equal(1, s:called)
+ bwipe!
+
+ unlet s:called
+ au! repro
+ delfunc Nop
+endfunc
+
+func Test_terminal_term_start_empty_command()
+ let cmd = "call term_start('', {'curwin' : 1, 'term_finish' : 'close'})"
+ call assert_fails(cmd, 'E474')
+ let cmd = "call term_start('', {'curwin' : 1, 'term_finish' : 'close'})"
+ call assert_fails(cmd, 'E474')
+ let cmd = "call term_start({}, {'curwin' : 1, 'term_finish' : 'close'})"
+ call assert_fails(cmd, 'E474')
+ let cmd = "call term_start(0, {'curwin' : 1, 'term_finish' : 'close'})"
+ call assert_fails(cmd, 'E474')
+endfunc
+
+func Test_terminal_response_to_control_sequence()
+ if !has('unix')
+ return
+ endif
+
+ let buf = Run_shell_in_terminal({})
+ call WaitForAssert({-> assert_notequal('', term_getline(buf, 1))})
+
+ call term_sendkeys(buf, "cat\<CR>")
+ call WaitForAssert({-> assert_match('cat', term_getline(buf, 1))})
+
+ " Request the cursor position.
+ call term_sendkeys(buf, "\x1b[6n\<CR>")
+
+ " Wait for output from tty to display, below an empty line.
+ call WaitForAssert({-> assert_match('3;1R', term_getline(buf, 4))})
+
+ " End "cat" gently.
+ call term_sendkeys(buf, "\<CR>\<C-D>")
+
+ call Stop_shell_in_terminal(buf)
+ exe buf . 'bwipe'
+ unlet g:job
+endfunc
+
+" Run Vim, start a terminal in that Vim with the kill argument,
+" :qall works.
+func Run_terminal_qall_kill(line1, line2)
+ " 1. Open a terminal window and wait for the prompt to appear
+ " 2. set kill using term_setkill()
+ " 3. make Vim exit, it will kill the shell
+ let after = [
+ \ a:line1,
+ \ 'let buf = bufnr("%")',
+ \ 'while term_getline(buf, 1) =~ "^\\s*$"',
+ \ ' sleep 10m',
+ \ 'endwhile',
+ \ a:line2,
+ \ 'au VimLeavePre * call writefile(["done"], "Xdone")',
+ \ 'qall',
+ \ ]
+ if !RunVim([], after, '')
+ return
+ endif
+ call assert_equal("done", readfile("Xdone")[0])
+ call delete("Xdone")
+endfunc
+
+" Run Vim in a terminal, then start a terminal in that Vim with a kill
+" argument, check that :qall works.
+func Test_terminal_qall_kill_arg()
+ call Run_terminal_qall_kill('term ++kill=kill', '')
+endfunc
+
+" Run Vim, start a terminal in that Vim, set the kill argument with
+" term_setkill(), check that :qall works.
+func Test_terminal_qall_kill_func()
+ call Run_terminal_qall_kill('term', 'call term_setkill(buf, "kill")')
+endfunc
+
+" Run Vim, start a terminal in that Vim without the kill argument,
+" check that :qall does not exit, :qall! does.
+func Test_terminal_qall_exit()
+ let after = [
+ \ 'term',
+ \ 'let buf = bufnr("%")',
+ \ 'while term_getline(buf, 1) =~ "^\\s*$"',
+ \ ' sleep 10m',
+ \ 'endwhile',
+ \ 'set nomore',
+ \ 'au VimLeavePre * call writefile(["too early"], "Xdone")',
+ \ 'qall',
+ \ 'au! VimLeavePre * exe buf . "bwipe!" | call writefile(["done"], "Xdone")',
+ \ 'cquit',
+ \ ]
+ if !RunVim([], after, '')
+ return
+ endif
+ call assert_equal("done", readfile("Xdone")[0])
+ call delete("Xdone")
+endfunc
+
+" Run Vim in a terminal, then start a terminal in that Vim without a kill
+" argument, check that :confirm qall works.
+func Test_terminal_qall_prompt()
+ if !CanRunVimInTerminal()
+ return
+ endif
+ let buf = RunVimInTerminal('', {})
+
+ " Open a terminal window and wait for the prompt to appear
+ call term_sendkeys(buf, ":term\<CR>")
+ call WaitForAssert({-> assert_match('\[running]', term_getline(buf, 10))})
+ call WaitForAssert({-> assert_notmatch('^\s*$', term_getline(buf, 1))})
+
+ " make Vim exit, it will prompt to kill the shell
+ call term_sendkeys(buf, "\<C-W>:confirm qall\<CR>")
+ call WaitForAssert({-> assert_match('ancel:', term_getline(buf, 20))})
+ call term_sendkeys(buf, "y")
+ call WaitForAssert({-> assert_equal('finished', term_getstatus(buf))})
+
+ " close the terminal window where Vim was running
+ quit
+endfunc
+
+func Test_terminal_open_autocmd()
+ augroup repro
+ au!
+ au TerminalOpen * let s:called += 1
+ augroup END
+
+ let s:called = 0
+
+ " Open a terminal window with :terminal
+ terminal
+ call assert_equal(1, s:called)
+ bwipe!
+
+ " Open a terminal window with term_start()
+ call term_start(&shell)
+ call assert_equal(2, s:called)
+ bwipe!
+
+ " Open a hidden terminal buffer with :terminal
+ terminal ++hidden
+ call assert_equal(3, s:called)
+ for buf in term_list()
+ exe buf . "bwipe!"
+ endfor
+
+ " Open a hidden terminal buffer with term_start()
+ let buf = term_start(&shell, {'hidden': 1})
+ call assert_equal(4, s:called)
+ exe buf . "bwipe!"
+
+ unlet s:called
+ au! repro
+endfunction
+
+func Check_dump01(off)
+ call assert_equal('one two three four five', trim(getline(a:off + 1)))
+ call assert_equal('~ Select Word', trim(getline(a:off + 7)))
+ call assert_equal(':popup PopUp', trim(getline(a:off + 20)))
+endfunc
+
+func Test_terminal_dumpwrite_composing()
+ if !CanRunVimInTerminal()
+ return
+ endif
+ let save_enc = &encoding
+ set encoding=utf-8
+ call assert_equal(1, winnr('$'))
+
+ let text = " a\u0300 e\u0302 o\u0308"
+ call writefile([text], 'Xcomposing')
+ let buf = RunVimInTerminal('--cmd "set encoding=utf-8" Xcomposing', {})
+ call WaitForAssert({-> assert_match(text, term_getline(buf, 1))})
+ call term_dumpwrite(buf, 'Xdump')
+ let dumpline = readfile('Xdump')[0]
+ call assert_match('|à| |ê| |ö', dumpline)
+
+ call StopVimInTerminal(buf)
+ call delete('Xcomposing')
+ call delete('Xdump')
+ let &encoding = save_enc
+endfunc
+
+" just testing basic functionality.
+func Test_terminal_dumpload()
+ call assert_equal(1, winnr('$'))
+ call term_dumpload('dumps/Test_popup_command_01.dump')
+ call assert_equal(2, winnr('$'))
+ call assert_equal(20, line('$'))
+ call Check_dump01(0)
+ quit
+endfunc
+
+func Test_terminal_dumpdiff()
+ call assert_equal(1, winnr('$'))
+ call term_dumpdiff('dumps/Test_popup_command_01.dump', 'dumps/Test_popup_command_02.dump')
+ call assert_equal(2, winnr('$'))
+ call assert_equal(62, line('$'))
+ call Check_dump01(0)
+ call Check_dump01(42)
+ call assert_equal(' bbbbbbbbbbbbbbbbbb ', getline(26)[0:29])
+ quit
+endfunc
+
+func Test_terminal_dumpdiff_options()
+ set laststatus=0
+ call assert_equal(1, winnr('$'))
+ let height = winheight(0)
+ call term_dumpdiff('dumps/Test_popup_command_01.dump', 'dumps/Test_popup_command_02.dump', {'vertical': 1, 'term_cols': 33})
+ call assert_equal(2, winnr('$'))
+ call assert_equal(height, winheight(winnr()))
+ call assert_equal(33, winwidth(winnr()))
+ call assert_equal('dump diff dumps/Test_popup_command_01.dump', bufname('%'))
+ quit
+
+ call assert_equal(1, winnr('$'))
+ let width = winwidth(0)
+ call term_dumpdiff('dumps/Test_popup_command_01.dump', 'dumps/Test_popup_command_02.dump', {'vertical': 0, 'term_rows': 13, 'term_name': 'something else'})
+ call assert_equal(2, winnr('$'))
+ call assert_equal(width, winwidth(winnr()))
+ call assert_equal(13, winheight(winnr()))
+ call assert_equal('something else', bufname('%'))
+ quit
+
+ call assert_equal(1, winnr('$'))
+ call term_dumpdiff('dumps/Test_popup_command_01.dump', 'dumps/Test_popup_command_02.dump', {'curwin': 1})
+ call assert_equal(1, winnr('$'))
+ bwipe
+
+ set laststatus&
+endfunc
+
+func Api_drop_common(options)
+ call assert_equal(1, winnr('$'))
+
+ " Use the title termcap entries to output the escape sequence.
+ call writefile([
+ \ 'set title',
+ \ 'exe "set t_ts=\<Esc>]51; t_fs=\x07"',
+ \ 'let &titlestring = ''["drop","Xtextfile"' . a:options . ']''',
+ \ 'redraw',
+ \ "set t_ts=",
+ \ ], 'Xscript')
+ let buf = RunVimInTerminal('-S Xscript', {})
+ call WaitFor({-> bufnr('Xtextfile') > 0})
+ call assert_equal('Xtextfile', expand('%:t'))
+ call assert_true(winnr('$') >= 3)
+ return buf
+endfunc
+
+func Test_terminal_api_drop_newwin()
+ if !CanRunVimInTerminal()
+ return
+ endif
+ let buf = Api_drop_common('')
+ call assert_equal(0, &bin)
+ call assert_equal('', &fenc)
+
+ call StopVimInTerminal(buf)
+ call delete('Xscript')
+ bwipe Xtextfile
+endfunc
+
+func Test_terminal_api_drop_newwin_bin()
+ if !CanRunVimInTerminal()
+ return
+ endif
+ let buf = Api_drop_common(',{"bin":1}')
+ call assert_equal(1, &bin)
+
+ call StopVimInTerminal(buf)
+ call delete('Xscript')
+ bwipe Xtextfile
+endfunc
+
+func Test_terminal_api_drop_newwin_binary()
+ if !CanRunVimInTerminal()
+ return
+ endif
+ let buf = Api_drop_common(',{"binary":1}')
+ call assert_equal(1, &bin)
+
+ call StopVimInTerminal(buf)
+ call delete('Xscript')
+ bwipe Xtextfile
+endfunc
+
+func Test_terminal_api_drop_newwin_nobin()
+ if !CanRunVimInTerminal()
+ return
+ endif
+ set binary
+ let buf = Api_drop_common(',{"nobin":1}')
+ call assert_equal(0, &bin)
+
+ call StopVimInTerminal(buf)
+ call delete('Xscript')
+ bwipe Xtextfile
+ set nobinary
+endfunc
+
+func Test_terminal_api_drop_newwin_nobinary()
+ if !CanRunVimInTerminal()
+ return
+ endif
+ set binary
+ let buf = Api_drop_common(',{"nobinary":1}')
+ call assert_equal(0, &bin)
+
+ call StopVimInTerminal(buf)
+ call delete('Xscript')
+ bwipe Xtextfile
+ set nobinary
+endfunc
+
+func Test_terminal_api_drop_newwin_ff()
+ if !CanRunVimInTerminal()
+ return
+ endif
+ let buf = Api_drop_common(',{"ff":"dos"}')
+ call assert_equal("dos", &ff)
+
+ call StopVimInTerminal(buf)
+ call delete('Xscript')
+ bwipe Xtextfile
+endfunc
+
+func Test_terminal_api_drop_newwin_fileformat()
+ if !CanRunVimInTerminal()
+ return
+ endif
+ let buf = Api_drop_common(',{"fileformat":"dos"}')
+ call assert_equal("dos", &ff)
+
+ call StopVimInTerminal(buf)
+ call delete('Xscript')
+ bwipe Xtextfile
+endfunc
+
+func Test_terminal_api_drop_newwin_enc()
+ if !CanRunVimInTerminal()
+ return
+ endif
+ let buf = Api_drop_common(',{"enc":"utf-16"}')
+ call assert_equal("utf-16", &fenc)
+
+ call StopVimInTerminal(buf)
+ call delete('Xscript')
+ bwipe Xtextfile
+endfunc
+
+func Test_terminal_api_drop_newwin_encoding()
+ if !CanRunVimInTerminal()
+ return
+ endif
+ let buf = Api_drop_common(',{"encoding":"utf-16"}')
+ call assert_equal("utf-16", &fenc)
+
+ call StopVimInTerminal(buf)
+ call delete('Xscript')
+ bwipe Xtextfile
+endfunc
+
+func Test_terminal_api_drop_oldwin()
+ if !CanRunVimInTerminal()
+ return
+ endif
+ let firstwinid = win_getid()
+ split Xtextfile
+ let textfile_winid = win_getid()
+ call assert_equal(2, winnr('$'))
+ call win_gotoid(firstwinid)
+
+ " Use the title termcap entries to output the escape sequence.
+ call writefile([
+ \ 'set title',
+ \ 'exe "set t_ts=\<Esc>]51; t_fs=\x07"',
+ \ 'let &titlestring = ''["drop","Xtextfile"]''',
+ \ 'redraw',
+ \ "set t_ts=",
+ \ ], 'Xscript')
+ let buf = RunVimInTerminal('-S Xscript', {'rows': 10})
+ call WaitForAssert({-> assert_equal('Xtextfile', expand('%:t'))})
+ call assert_equal(textfile_winid, win_getid())
+
+ call StopVimInTerminal(buf)
+ call delete('Xscript')
+ bwipe Xtextfile
+endfunc
+
+func Tapi_TryThis(bufnum, arg)
+ let g:called_bufnum = a:bufnum
+ let g:called_arg = a:arg
+endfunc
+
+func WriteApiCall(funcname)
+ " Use the title termcap entries to output the escape sequence.
+ call writefile([
+ \ 'set title',
+ \ 'exe "set t_ts=\<Esc>]51; t_fs=\x07"',
+ \ 'let &titlestring = ''["call","' . a:funcname . '",["hello",123]]''',
+ \ 'redraw',
+ \ "set t_ts=",
+ \ ], 'Xscript')
+endfunc
+
+func Test_terminal_api_call()
+ if !CanRunVimInTerminal()
+ return
+ endif
+
+ call WriteApiCall('Tapi_TryThis')
+ let buf = RunVimInTerminal('-S Xscript', {})
+ call WaitFor({-> exists('g:called_bufnum')})
+ call assert_equal(buf, g:called_bufnum)
+ call assert_equal(['hello', 123], g:called_arg)
+
+ call StopVimInTerminal(buf)
+ call delete('Xscript')
+ unlet g:called_bufnum
+ unlet g:called_arg
+endfunc
+
+func Test_terminal_api_call_fails()
+ if !CanRunVimInTerminal()
+ return
+ endif
+
+ call WriteApiCall('TryThis')
+ call ch_logfile('Xlog', 'w')
+ let buf = RunVimInTerminal('-S Xscript', {})
+ call WaitForAssert({-> assert_match('Invalid function name: TryThis', string(readfile('Xlog')))})
+
+ call StopVimInTerminal(buf)
+ call delete('Xscript')
+ call ch_logfile('', '')
+ call delete('Xlog')
+endfunc
+
+let s:caught_e937 = 0
+
+func Tapi_Delete(bufnum, arg)
+ try
+ execute 'bdelete!' a:bufnum
+ catch /E937:/
+ let s:caught_e937 = 1
+ endtry
+endfunc
+
+func Test_terminal_api_call_fail_delete()
+ if !CanRunVimInTerminal()
+ return
+ endif
+
+ call WriteApiCall('Tapi_Delete')
+ let buf = RunVimInTerminal('-S Xscript', {})
+ call WaitForAssert({-> assert_equal(1, s:caught_e937)})
+
+ call StopVimInTerminal(buf)
+ call delete('Xscript')
+ call ch_logfile('', '')
+endfunc
+
+func Test_terminal_ansicolors_default()
+ let colors = [
+ \ '#000000', '#e00000',
+ \ '#00e000', '#e0e000',
+ \ '#0000e0', '#e000e0',
+ \ '#00e0e0', '#e0e0e0',
+ \ '#808080', '#ff4040',
+ \ '#40ff40', '#ffff40',
+ \ '#4040ff', '#ff40ff',
+ \ '#40ffff', '#ffffff',
+ \]
+
+ let buf = Run_shell_in_terminal({})
+ call assert_equal(colors, term_getansicolors(buf))
+ call Stop_shell_in_terminal(buf)
+ call term_wait(buf)
+
+ exe buf . 'bwipe'
+endfunc
+
+let s:test_colors = [
+ \ '#616e64', '#0d0a79',
+ \ '#6d610d', '#0a7373',
+ \ '#690d0a', '#6d696e',
+ \ '#0d0a6f', '#616e0d',
+ \ '#0a6479', '#6d0d0a',
+ \ '#617373', '#0d0a69',
+ \ '#6d690d', '#0a6e6f',
+ \ '#610d0a', '#6e6479',
+ \]
+
+func Test_terminal_ansicolors_global()
+ let g:terminal_ansi_colors = reverse(copy(s:test_colors))
+ let buf = Run_shell_in_terminal({})
+ call assert_equal(g:terminal_ansi_colors, term_getansicolors(buf))
+ call Stop_shell_in_terminal(buf)
+ call term_wait(buf)
+
+ exe buf . 'bwipe'
+ unlet g:terminal_ansi_colors
+endfunc
+
+func Test_terminal_ansicolors_func()
+ let g:terminal_ansi_colors = reverse(copy(s:test_colors))
+ let buf = Run_shell_in_terminal({'ansi_colors': s:test_colors})
+ call assert_equal(s:test_colors, term_getansicolors(buf))
+
+ call term_setansicolors(buf, g:terminal_ansi_colors)
+ call assert_equal(g:terminal_ansi_colors, term_getansicolors(buf))
+
+ let colors = [
+ \ 'ivory', 'AliceBlue',
+ \ 'grey67', 'dark goldenrod',
+ \ 'SteelBlue3', 'PaleVioletRed4',
+ \ 'MediumPurple2', 'yellow2',
+ \ 'RosyBrown3', 'OrangeRed2',
+ \ 'white smoke', 'navy blue',
+ \ 'grey47', 'gray97',
+ \ 'MistyRose2', 'DodgerBlue4',
+ \]
+ call term_setansicolors(buf, colors)
+
+ let colors[4] = 'Invalid'
+ call assert_fails('call term_setansicolors(buf, colors)', 'E474:')
+
+ call Stop_shell_in_terminal(buf)
+ call term_wait(buf)
+ exe buf . 'bwipe'
+endfunc
+
+func Test_terminal_termwinsize_option_fixed()
+ if !CanRunVimInTerminal()
+ return
+ endif
+ set termwinsize=6x40
+ let text = []
+ for n in range(10)
+ call add(text, repeat(n, 50))
+ endfor
+ call writefile(text, 'Xwinsize')
+ let buf = RunVimInTerminal('Xwinsize', {})
+ let win = bufwinid(buf)
+ call assert_equal([6, 40], term_getsize(buf))
+ call assert_equal(6, winheight(win))
+ call assert_equal(40, winwidth(win))
+
+ " resizing the window doesn't resize the terminal.
+ resize 10
+ vertical resize 60
+ call assert_equal([6, 40], term_getsize(buf))
+ call assert_equal(10, winheight(win))
+ call assert_equal(60, winwidth(win))
+
+ call StopVimInTerminal(buf)
+ call delete('Xwinsize')
+
+ call assert_fails('set termwinsize=40', 'E474')
+ call assert_fails('set termwinsize=10+40', 'E474')
+ call assert_fails('set termwinsize=abc', 'E474')
+
+ set termwinsize=
+endfunc
+
+func Test_terminal_termwinsize_option_zero()
+ set termwinsize=0x0
+ let buf = Run_shell_in_terminal({})
+ let win = bufwinid(buf)
+ call assert_equal([winheight(win), winwidth(win)], term_getsize(buf))
+ call Stop_shell_in_terminal(buf)
+ call term_wait(buf)
+ exe buf . 'bwipe'
+
+ set termwinsize=7x0
+ let buf = Run_shell_in_terminal({})
+ let win = bufwinid(buf)
+ call assert_equal([7, winwidth(win)], term_getsize(buf))
+ call Stop_shell_in_terminal(buf)
+ call term_wait(buf)
+ exe buf . 'bwipe'
+
+ set termwinsize=0x33
+ let buf = Run_shell_in_terminal({})
+ let win = bufwinid(buf)
+ call assert_equal([winheight(win), 33], term_getsize(buf))
+ call Stop_shell_in_terminal(buf)
+ call term_wait(buf)
+ exe buf . 'bwipe'
+
+ set termwinsize=
+endfunc
+
+func Test_terminal_termwinsize_mininmum()
+ set termwinsize=10*50
+ vsplit
+ let buf = Run_shell_in_terminal({})
+ let win = bufwinid(buf)
+ call assert_inrange(10, 1000, winheight(win))
+ call assert_inrange(50, 1000, winwidth(win))
+ call assert_equal([winheight(win), winwidth(win)], term_getsize(buf))
+
+ resize 15
+ vertical resize 60
+ redraw
+ call assert_equal([15, 60], term_getsize(buf))
+ call assert_equal(15, winheight(win))
+ call assert_equal(60, winwidth(win))
+
+ resize 7
+ vertical resize 30
+ redraw
+ call assert_equal([10, 50], term_getsize(buf))
+ call assert_equal(7, winheight(win))
+ call assert_equal(30, winwidth(win))
+
+ call Stop_shell_in_terminal(buf)
+ call term_wait(buf)
+ exe buf . 'bwipe'
+
+ set termwinsize=0*0
+ let buf = Run_shell_in_terminal({})
+ let win = bufwinid(buf)
+ call assert_equal([winheight(win), winwidth(win)], term_getsize(buf))
+ call Stop_shell_in_terminal(buf)
+ call term_wait(buf)
+ exe buf . 'bwipe'
+
+ set termwinsize=
+endfunc
+
+func Test_terminal_termwinkey()
+ call assert_equal(1, winnr('$'))
+ let thiswin = win_getid()
+
+ let buf = Run_shell_in_terminal({})
+ let termwin = bufwinid(buf)
+ set termwinkey=<C-L>
+ call feedkeys("\<C-L>w", 'tx')
+ call assert_equal(thiswin, win_getid())
+ call feedkeys("\<C-W>w", 'tx')
+
+ let job = term_getjob(buf)
+ call feedkeys("\<C-L>\<C-C>", 'tx')
+ call WaitForAssert({-> assert_equal("dead", job_status(job))})
+endfunc
+
+func Test_terminal_out_err()
+ if !has('unix')
+ return
+ endif
+ call writefile([
+ \ '#!/bin/sh',
+ \ 'echo "this is standard error" >&2',
+ \ 'echo "this is standard out" >&1',
+ \ ], 'Xechoerrout.sh')
+ call setfperm('Xechoerrout.sh', 'rwxrwx---')
+
+ let outfile = 'Xtermstdout'
+ let buf = term_start(['./Xechoerrout.sh'], {'out_io': 'file', 'out_name': outfile})
+
+ call WaitFor({-> !empty(readfile(outfile)) && !empty(term_getline(buf, 1))})
+ call assert_equal(['this is standard out'], readfile(outfile))
+ call assert_equal('this is standard error', term_getline(buf, 1))
+
+ call WaitForAssert({-> assert_equal('dead', job_status(term_getjob(buf)))})
+ exe buf . 'bwipe'
+ call delete('Xechoerrout.sh')
+ call delete(outfile)
+endfunc
+
+func Test_terminwinscroll()
+ if !has('unix')
+ return
+ endif
+
+ " Let the terminal output more than 'termwinscroll' lines, some at the start
+ " will be dropped.
+ exe 'set termwinscroll=' . &lines
+ let buf = term_start('/bin/sh')
+ for i in range(1, &lines)
+ call feedkeys("echo " . i . "\<CR>", 'xt')
+ call WaitForAssert({-> assert_match(string(i), term_getline(buf, term_getcursor(buf)[0] - 1))})
+ endfor
+ " Go to Terminal-Normal mode to update the buffer.
+ call feedkeys("\<C-W>N", 'xt')
+ call assert_inrange(&lines, &lines * 110 / 100 + winheight(0), line('$'))
+
+ " Every "echo nr" must only appear once
+ let lines = getline(1, line('$'))
+ for i in range(&lines - len(lines) / 2 + 2, &lines)
+ let filtered = filter(copy(lines), {idx, val -> val =~ 'echo ' . i . '\>'})
+ call assert_equal(1, len(filtered), 'for "echo ' . i . '"')
+ endfor
+
+ exe buf . 'bwipe!'
+endfunc
+
+" Resizing the terminal window caused an ml_get error.
+" TODO: This does not reproduce the original problem.
+func Test_terminal_resize()
+ set statusline=x
+ terminal
+ call assert_equal(2, winnr('$'))
+
+ " Fill the terminal with text.
+ if has('win32')
+ call feedkeys("dir\<CR>", 'xt')
+ else
+ call feedkeys("ls\<CR>", 'xt')
+ endif
+ " Go to Terminal-Normal mode for a moment.
+ call feedkeys("\<C-W>N", 'xt')
+ " Open a new window
+ call feedkeys("i\<C-W>n", 'xt')
+ call assert_equal(3, winnr('$'))
+ redraw
+
+ close
+ call assert_equal(2, winnr('$'))
+ call feedkeys("exit\<CR>", 'xt')
+ set statusline&
+endfunc
+
+" must be nearly the last, we can't go back from GUI to terminal
+func Test_zz1_terminal_in_gui()
+ if !CanRunGui()
+ return
+ endif
+
+ " Ignore the "failed to create input context" error.
+ call test_ignore_error('E285:')
+
+ gui -f
+
+ call assert_equal(1, winnr('$'))
+ let buf = Run_shell_in_terminal({'term_finish': 'close'})
+ call Stop_shell_in_terminal(buf)
+ call term_wait(buf)
+
+ " closing window wipes out the terminal buffer a with finished job
+ call WaitForAssert({-> assert_equal(1, winnr('$'))})
+ call assert_equal("", bufname(buf))
+
+ unlet g:job
+endfunc
+
+func Test_zz2_terminal_guioptions_bang()
+ if !has('gui_running')
+ return
+ endif
+ set guioptions+=!
+
+ let filename = 'Xtestscript'
+ if has('win32')
+ let filename .= '.bat'
+ let prefix = ''
+ let contents = ['@echo off', 'exit %1']
+ else
+ let filename .= '.sh'
+ let prefix = './'
+ let contents = ['#!/bin/sh', 'exit $1']
+ endif
+ call writefile(contents, filename)
+ call setfperm(filename, 'rwxrwx---')
+
+ " Check if v:shell_error is equal to the exit status.
+ let exitval = 0
+ execute printf(':!%s%s %d', prefix, filename, exitval)
+ call assert_equal(exitval, v:shell_error)
+
+ let exitval = 9
+ execute printf(':!%s%s %d', prefix, filename, exitval)
+ call assert_equal(exitval, v:shell_error)
+
+ set guioptions&
+ call delete(filename)
+endfunc
+
+func Test_terminal_hidden()
+ if !has('unix')
+ return
+ endif
+ term ++hidden cat
+ let bnr = bufnr('$')
+ call assert_equal('terminal', getbufvar(bnr, '&buftype'))
+ exe 'sbuf ' . bnr
+ call assert_equal('terminal', &buftype)
+ call term_sendkeys(bnr, "asdf\<CR>")
+ call WaitForAssert({-> assert_match('asdf', term_getline(bnr, 2))})
+ call term_sendkeys(bnr, "\<C-D>")
+ call WaitForAssert({-> assert_equal('finished', term_getstatus(bnr))})
+ bwipe!
+endfunc
+
+func Test_terminal_hidden_and_close()
+ if !has('unix')
+ return
+ endif
+ call assert_equal(1, winnr('$'))
+ term ++hidden ++close ls
+ let bnr = bufnr('$')
+ call assert_equal('terminal', getbufvar(bnr, '&buftype'))
+ call WaitForAssert({-> assert_false(bufexists(bnr))})
+ call assert_equal(1, winnr('$'))
+endfunc
+
+func Test_terminal_does_not_truncate_last_newlines()
+ " This test does not pass through ConPTY.
+ if has('conpty')
+ return
+ endif
+ let contents = [
+ \ [ 'One', '', 'X' ],
+ \ [ 'Two', '', '' ],
+ \ [ 'Three' ] + repeat([''], 30)
+ \ ]
+
+ for c in contents
+ call writefile(c, 'Xfile')
+ if has('win32')
+ term cmd /c type Xfile
+ else
+ term cat Xfile
+ endif
+ let bnr = bufnr('$')
+ call assert_equal('terminal', getbufvar(bnr, '&buftype'))
+ call WaitForAssert({-> assert_equal('finished', term_getstatus(bnr))})
+ sleep 100m
+ call assert_equal(c, getline(1, line('$')))
+ quit
+ endfor
+
+ call delete('Xfile')
+endfunc
+
+func Test_terminal_no_job()
+ let term = term_start('false', {'term_finish': 'close'})
+ call WaitForAssert({-> assert_equal(v:null, term_getjob(term)) })
+endfunc
+
+func Test_term_gettitle()
+ if !has('title') || empty(&t_ts)
+ return
+ endif
+ " TODO: this fails on Travis
+ return
+
+ " term_gettitle() returns an empty string for a non-terminal buffer
+ " or for a non-existing buffer.
+ call assert_equal('', term_gettitle(bufnr('%')))
+ call assert_equal('', term_gettitle(bufnr('$') + 1))
+
+ let term = term_start([GetVimProg(), '--clean', '-c', 'set noswapfile'])
+ call WaitForAssert({-> assert_equal('[No Name] - VIM', term_gettitle(term)) })
+
+ call term_sendkeys(term, ":e Xfoo\r")
+ call WaitForAssert({-> assert_match('Xfoo (.*[/\\]testdir) - VIM', term_gettitle(term)) })
+
+ call term_sendkeys(term, ":set titlestring=foo\r")
+ call WaitForAssert({-> assert_equal('foo', term_gettitle(term)) })
+
+ exe term . 'bwipe!'
+endfunc
+
+" When drawing the statusline the cursor position may not have been updated
+" yet.
+" 1. create a terminal, make it show 2 lines
+" 2. 0.5 sec later: leave terminal window, execute "i"
+" 3. 0.5 sec later: clear terminal window, now it's 1 line
+" 4. 0.5 sec later: redraw, including statusline (used to trigger bug)
+" 4. 0.5 sec later: should be done, clean up
+func Test_terminal_statusline()
+ if !has('unix')
+ return
+ endif
+ set statusline=x
+ terminal
+ let tbuf = bufnr('')
+ call term_sendkeys(tbuf, "clear; echo a; echo b; sleep 1; clear\n")
+ call timer_start(500, { tid -> feedkeys("\<C-w>j", 'tx') })
+ call timer_start(1500, { tid -> feedkeys("\<C-l>", 'tx') })
+ au BufLeave * if &buftype == 'terminal' | silent! normal i | endif
+
+ sleep 2
+ exe tbuf . 'bwipe!'
+ au! BufLeave
+ set statusline=
+endfunc
diff --git a/src/testdir/test_terminal_fail.vim b/src/testdir/test_terminal_fail.vim
new file mode 100644
index 0000000..aad4b98
--- /dev/null
+++ b/src/testdir/test_terminal_fail.vim
@@ -0,0 +1,21 @@
+" This test is in a separate file, because it usually causes reports for memory
+" leaks under valgrind. That is because when fork/exec fails memory is not
+" freed. Since the process exists right away it's not a real leak.
+
+if !has('terminal')
+ finish
+endif
+
+source shared.vim
+
+func Test_terminal_redir_fails()
+ if has('unix')
+ let buf = term_start('xyzabc', {'err_io': 'file', 'err_name': 'Xfile'})
+ call term_wait(buf)
+ call WaitFor('len(readfile("Xfile")) > 0')
+ call assert_match('executing job failed', readfile('Xfile')[0])
+ call WaitFor('!&modified')
+ call delete('Xfile')
+ bwipe
+ endif
+endfunc
diff --git a/src/testdir/test_textformat.vim b/src/testdir/test_textformat.vim
new file mode 100644
index 0000000..13fb50b
--- /dev/null
+++ b/src/testdir/test_textformat.vim
@@ -0,0 +1,491 @@
+" Tests for the various 'formatoptions' settings
+func Test_text_format()
+ enew!
+
+ setl noai tw=2 fo=t
+ call append('$', [
+ \ '{',
+ \ ' ',
+ \ '',
+ \ '}'])
+ exe "normal /^{/+1\n0"
+ normal gRa b
+ let lnum = line('.')
+ call assert_equal([
+ \ 'a',
+ \ 'b'], getline(lnum - 1, lnum))
+
+ normal ggdG
+ setl ai tw=2 fo=tw
+ call append('$', [
+ \ '{',
+ \ 'a b ',
+ \ '',
+ \ 'a ',
+ \ '}'])
+ exe "normal /^{/+1\n0"
+ normal gqgqjjllab
+ let lnum = line('.')
+ call assert_equal([
+ \ 'a ',
+ \ 'b ',
+ \ '',
+ \ 'a ',
+ \ 'b'], getline(lnum - 4, lnum))
+
+ normal ggdG
+ setl tw=3 fo=t
+ call append('$', [
+ \ '{',
+ \ "a \<C-A>",
+ \ '}'])
+ exe "normal /^{/+1\n0"
+ exe "normal gqgqo\na \<C-V>\<C-A>"
+ let lnum = line('.')
+ call assert_equal([
+ \ 'a',
+ \ "\<C-A>",
+ \ '',
+ \ 'a',
+ \ "\<C-A>"], getline(lnum - 4, lnum))
+
+ normal ggdG
+ setl tw=2 fo=tcq1 comments=:#
+ call append('$', [
+ \ '{',
+ \ 'a b',
+ \ '#a b',
+ \ '}'])
+ exe "normal /^{/+1\n0"
+ exe "normal gqgqjgqgqo\na b\n#a b"
+ let lnum = line('.')
+ call assert_equal([
+ \ 'a b',
+ \ '#a b',
+ \ '',
+ \ 'a b',
+ \ '#a b'], getline(lnum - 4, lnum))
+
+ normal ggdG
+ setl tw=5 fo=tcn comments=:#
+ call append('$', [
+ \ '{',
+ \ ' 1 a',
+ \ '# 1 a',
+ \ '}'])
+ exe "normal /^{/+1\n0"
+ exe "normal A b\<Esc>jA b"
+ let lnum = line('.')
+ call assert_equal([
+ \ ' 1 a',
+ \ ' b',
+ \ '# 1 a',
+ \ '# b'], getline(lnum - 3, lnum))
+
+ normal ggdG
+ setl tw=5 fo=t2a si
+ call append('$', [
+ \ '{',
+ \ '',
+ \ ' x a',
+ \ ' b',
+ \ ' c',
+ \ '',
+ \ '}'])
+ exe "normal /^{/+3\n0"
+ exe "normal i \<Esc>A_"
+ let lnum = line('.')
+ call assert_equal([
+ \ '',
+ \ ' x a',
+ \ ' b_',
+ \ ' c',
+ \ ''], getline(lnum - 2, lnum + 2))
+
+ normal ggdG
+ setl tw=5 fo=qn comments=:#
+ call append('$', [
+ \ '{',
+ \ '# 1 a b',
+ \ '}'])
+ exe "normal /^{/+1\n5|"
+ normal gwap
+ call assert_equal(5, col('.'))
+ let lnum = line('.')
+ call assert_equal([
+ \ '# 1 a',
+ \ '# b'], getline(lnum, lnum + 1))
+
+ normal ggdG
+ setl tw=5 fo=q2 comments=:#
+ call append('$', [
+ \ '{',
+ \ '# x',
+ \ '# a b',
+ \ '}'])
+ exe "normal /^{/+1\n0"
+ normal gwap
+ let lnum = line('.')
+ call assert_equal([
+ \ '# x a',
+ \ '# b'], getline(lnum, lnum + 1))
+
+ normal ggdG
+ setl tw& fo=a
+ call append('$', [
+ \ '{',
+ \ ' 1aa',
+ \ ' 2bb',
+ \ '}'])
+ exe "normal /^{/+2\n0"
+ normal I^^
+ call assert_equal('{ 1aa ^^2bb }', getline('.'))
+
+ normal ggdG
+ setl tw=20 fo=an12wcq comments=s1:/*,mb:*,ex:*/
+ call append('$', [
+ \ '/* abc def ghi jkl ',
+ \ ' * mno pqr stu',
+ \ ' */'])
+ exe "normal /mno pqr/\n"
+ normal A vwx yz
+ let lnum = line('.')
+ call assert_equal([
+ \ ' * mno pqr stu ',
+ \ ' * vwx yz',
+ \ ' */'], getline(lnum - 1, lnum + 1))
+
+ normal ggdG
+ setl tw=12 fo=tqnc comments=:#
+ call setline('.', '# 1 xxxxx')
+ normal A foobar
+ call assert_equal([
+ \ '# 1 xxxxx',
+ \ '# foobar'], getline(1, 2))
+
+ " Test the 'p' flag for 'formatoptions'
+ " First test without the flag: that it will break "Mr. Feynman" at the space
+ normal ggdG
+ setl tw=28 fo=tcq
+ call setline('.', 'Surely you''re joking, Mr. Feynman!')
+ normal gqq
+ call assert_equal([
+ \ 'Surely you''re joking, Mr.',
+ \ 'Feynman!'], getline(1, 2))
+ " Now test with the flag: that it will push the name with the title onto the
+ " next line
+ normal ggdG
+ setl fo+=p
+ call setline('.', 'Surely you''re joking, Mr. Feynman!')
+ normal gqq
+ call assert_equal([
+ \ 'Surely you''re joking,',
+ \ 'Mr. Feynman!'], getline(1, 2))
+ " Ensure that it will still break if two spaces are entered
+ normal ggdG
+ call setline('.', 'Surely you''re joking, Mr. Feynman!')
+ normal gqq
+ call assert_equal([
+ \ 'Surely you''re joking, Mr.',
+ \ 'Feynman!'], getline(1, 2))
+
+ setl ai& tw& fo& si& comments&
+ enew!
+endfunc
+
+" Tests for :right, :center and :left on text with embedded TAB.
+func Test_format_align()
+ enew!
+ set tw=65
+
+ " :left alignment
+ call append(0, [
+ \ " test for :left",
+ \ " a a",
+ \ " fa a",
+ \ " dfa a",
+ \ " sdfa a",
+ \ " asdfa a",
+ \ " xasdfa a",
+ \ "asxxdfa a",
+ \ ])
+ %left
+ call assert_equal([
+ \ "test for :left",
+ \ "a a",
+ \ "fa a",
+ \ "dfa a",
+ \ "sdfa a",
+ \ "asdfa a",
+ \ "xasdfa a",
+ \ "asxxdfa a",
+ \ ""
+ \ ], getline(1, '$'))
+ enew!
+
+ " :center alignment
+ call append(0, [
+ \ " test for :center",
+ \ " a a",
+ \ " fa afd asdf",
+ \ " dfa a",
+ \ " sdfa afd asdf",
+ \ " asdfa a",
+ \ " xasdfa asdfasdfasdfasdfasdf",
+ \ "asxxdfa a"
+ \ ])
+ %center
+ call assert_equal([
+ \ " test for :center",
+ \ " a a",
+ \ " fa afd asdf",
+ \ " dfa a",
+ \ " sdfa afd asdf",
+ \ " asdfa a",
+ \ " xasdfa asdfasdfasdfasdfasdf",
+ \ " asxxdfa a",
+ \ ""
+ \ ], getline(1, '$'))
+ enew!
+
+ " :right alignment
+ call append(0, [
+ \ " test for :right",
+ \ " a a",
+ \ " fa a",
+ \ " dfa a",
+ \ " sdfa a",
+ \ " asdfa a",
+ \ " xasdfa a",
+ \ " asxxdfa a",
+ \ " asxa;ofa a",
+ \ " asdfaqwer a",
+ \ " a ax",
+ \ " fa ax",
+ \ " dfa ax",
+ \ " sdfa ax",
+ \ " asdfa ax",
+ \ " xasdfa ax",
+ \ " asxxdfa ax",
+ \ " asxa;ofa ax",
+ \ " asdfaqwer ax",
+ \ " a axx",
+ \ " fa axx",
+ \ " dfa axx",
+ \ " sdfa axx",
+ \ " asdfa axx",
+ \ " xasdfa axx",
+ \ " asxxdfa axx",
+ \ " asxa;ofa axx",
+ \ " asdfaqwer axx",
+ \ " a axxx",
+ \ " fa axxx",
+ \ " dfa axxx",
+ \ " sdfa axxx",
+ \ " asdfa axxx",
+ \ " xasdfa axxx",
+ \ " asxxdfa axxx",
+ \ " asxa;ofa axxx",
+ \ " asdfaqwer axxx",
+ \ " a axxxo",
+ \ " fa axxxo",
+ \ " dfa axxxo",
+ \ " sdfa axxxo",
+ \ " asdfa axxxo",
+ \ " xasdfa axxxo",
+ \ " asxxdfa axxxo",
+ \ " asxa;ofa axxxo",
+ \ " asdfaqwer axxxo",
+ \ " a axxxoi",
+ \ " fa axxxoi",
+ \ " dfa axxxoi",
+ \ " sdfa axxxoi",
+ \ " asdfa axxxoi",
+ \ " xasdfa axxxoi",
+ \ " asxxdfa axxxoi",
+ \ " asxa;ofa axxxoi",
+ \ " asdfaqwer axxxoi",
+ \ " a axxxoik",
+ \ " fa axxxoik",
+ \ " dfa axxxoik",
+ \ " sdfa axxxoik",
+ \ " asdfa axxxoik",
+ \ " xasdfa axxxoik",
+ \ " asxxdfa axxxoik",
+ \ " asxa;ofa axxxoik",
+ \ " asdfaqwer axxxoik",
+ \ " a axxxoike",
+ \ " fa axxxoike",
+ \ " dfa axxxoike",
+ \ " sdfa axxxoike",
+ \ " asdfa axxxoike",
+ \ " xasdfa axxxoike",
+ \ " asxxdfa axxxoike",
+ \ " asxa;ofa axxxoike",
+ \ " asdfaqwer axxxoike",
+ \ " a axxxoikey",
+ \ " fa axxxoikey",
+ \ " dfa axxxoikey",
+ \ " sdfa axxxoikey",
+ \ " asdfa axxxoikey",
+ \ " xasdfa axxxoikey",
+ \ " asxxdfa axxxoikey",
+ \ " asxa;ofa axxxoikey",
+ \ " asdfaqwer axxxoikey",
+ \ ])
+ %right
+ call assert_equal([
+ \ "\t\t\t\t test for :right",
+ \ "\t\t\t\t a a",
+ \ "\t\t\t\t fa a",
+ \ "\t\t\t\t dfa a",
+ \ "\t\t\t\t sdfa a",
+ \ "\t\t\t\t asdfa a",
+ \ "\t\t\t\t xasdfa a",
+ \ "\t\t\t\t asxxdfa a",
+ \ "\t\t\t\t asxa;ofa a",
+ \ "\t\t\t\t asdfaqwer a",
+ \ "\t\t\t\t a ax",
+ \ "\t\t\t\t fa ax",
+ \ "\t\t\t\t dfa ax",
+ \ "\t\t\t\t sdfa ax",
+ \ "\t\t\t\t asdfa ax",
+ \ "\t\t\t\t xasdfa ax",
+ \ "\t\t\t\t asxxdfa ax",
+ \ "\t\t\t\t asxa;ofa ax",
+ \ "\t\t\t\t asdfaqwer ax",
+ \ "\t\t\t\t a axx",
+ \ "\t\t\t\t fa axx",
+ \ "\t\t\t\t dfa axx",
+ \ "\t\t\t\t sdfa axx",
+ \ "\t\t\t\t asdfa axx",
+ \ "\t\t\t\t xasdfa axx",
+ \ "\t\t\t\t asxxdfa axx",
+ \ "\t\t\t\t asxa;ofa axx",
+ \ "\t\t\t\t asdfaqwer axx",
+ \ "\t\t\t\t a axxx",
+ \ "\t\t\t\t fa axxx",
+ \ "\t\t\t\t dfa axxx",
+ \ "\t\t\t\t sdfa axxx",
+ \ "\t\t\t\t asdfa axxx",
+ \ "\t\t\t\t xasdfa axxx",
+ \ "\t\t\t\t asxxdfa axxx",
+ \ "\t\t\t\t asxa;ofa axxx",
+ \ "\t\t\t\t asdfaqwer axxx",
+ \ "\t\t\t\t a axxxo",
+ \ "\t\t\t\t fa axxxo",
+ \ "\t\t\t\t dfa axxxo",
+ \ "\t\t\t\t sdfa axxxo",
+ \ "\t\t\t\t asdfa axxxo",
+ \ "\t\t\t\t xasdfa axxxo",
+ \ "\t\t\t\t asxxdfa axxxo",
+ \ "\t\t\t\t asxa;ofa axxxo",
+ \ "\t\t\t\t asdfaqwer axxxo",
+ \ "\t\t\t\t a axxxoi",
+ \ "\t\t\t\t fa axxxoi",
+ \ "\t\t\t\t dfa axxxoi",
+ \ "\t\t\t\t sdfa axxxoi",
+ \ "\t\t\t\t asdfa axxxoi",
+ \ "\t\t\t\t xasdfa axxxoi",
+ \ "\t\t\t\t asxxdfa axxxoi",
+ \ "\t\t\t\t asxa;ofa axxxoi",
+ \ "\t\t\t\t asdfaqwer axxxoi",
+ \ "\t\t\t\t a axxxoik",
+ \ "\t\t\t\t fa axxxoik",
+ \ "\t\t\t\t dfa axxxoik",
+ \ "\t\t\t\t sdfa axxxoik",
+ \ "\t\t\t\t asdfa axxxoik",
+ \ "\t\t\t\t xasdfa axxxoik",
+ \ "\t\t\t\t asxxdfa axxxoik",
+ \ "\t\t\t\t asxa;ofa axxxoik",
+ \ "\t\t\t\t asdfaqwer axxxoik",
+ \ "\t\t\t\t a axxxoike",
+ \ "\t\t\t\t fa axxxoike",
+ \ "\t\t\t\t dfa axxxoike",
+ \ "\t\t\t\t sdfa axxxoike",
+ \ "\t\t\t\t asdfa axxxoike",
+ \ "\t\t\t\t xasdfa axxxoike",
+ \ "\t\t\t\t asxxdfa axxxoike",
+ \ "\t\t\t\t asxa;ofa axxxoike",
+ \ "\t\t\t\t asdfaqwer axxxoike",
+ \ "\t\t\t\t a axxxoikey",
+ \ "\t\t\t\t fa axxxoikey",
+ \ "\t\t\t\t dfa axxxoikey",
+ \ "\t\t\t\t sdfa axxxoikey",
+ \ "\t\t\t\t asdfa axxxoikey",
+ \ "\t\t\t\t xasdfa axxxoikey",
+ \ "\t\t\t\t asxxdfa axxxoikey",
+ \ "\t\t\t\t asxa;ofa axxxoikey",
+ \ "\t\t\t\t asdfaqwer axxxoikey",
+ \ ""
+ \ ], getline(1, '$'))
+ enew!
+
+ set tw&
+endfunc
+
+" Test formatting a paragraph.
+func Test_format_para()
+ enew!
+ set fo+=tcroql tw=72
+
+ call append(0, [
+ \ "xxxxx xx xxxxxx ",
+ \ "xxxxxxx xxxxxxxxx xxx xxxx xxxxx xxxxx xxx xx",
+ \ "xxxxxxxxxxxxxxxxxx xxxxx xxxx, xxxx xxxx xxxx xxxx xxx xx xx",
+ \ "xx xxxxxxx. xxxx xxxx.",
+ \ "",
+ \ "> xx xx, xxxx xxxx xxx xxxx xxx xxxxx xxx xxx xxxxxxx xxx xxxxx",
+ \ "> xxxxxx xxxxxxx: xxxx xxxxxxx, xx xxxxxx xxxx xxxxxxxxxx"
+ \ ])
+ exe "normal /xxxxxxxx$\<CR>"
+ normal 0gq6kk
+ call assert_equal([
+ \ "xxxxx xx xxxxxx xxxxxxx xxxxxxxxx xxx xxxx xxxxx xxxxx xxx xx",
+ \ "xxxxxxxxxxxxxxxxxx xxxxx xxxx, xxxx xxxx xxxx xxxx xxx xx xx xx xxxxxxx.",
+ \ "xxxx xxxx.",
+ \ "",
+ \ "> xx xx, xxxx xxxx xxx xxxx xxx xxxxx xxx xxx xxxxxxx xxx xxxxx xxxxxx",
+ \ "> xxxxxxx: xxxx xxxxxxx, xx xxxxxx xxxx xxxxxxxxxx",
+ \ ""
+ \ ], getline(1, '$'))
+
+ set fo& tw&
+ enew!
+endfunc
+
+" Test undo after ":%s" and formatting.
+func Test_format_undo()
+ enew!
+ map gg :.,.+2s/^/x/<CR>kk:set tw=3<CR>gqq
+
+ call append(0, [
+ \ "aa aa aa aa",
+ \ "bb bb bb bb",
+ \ "cc cc cc cc"
+ \ ])
+ " undo/redo here to make the next undo only work on the following changes
+ exe "normal i\<C-G>u"
+ call cursor(1,1)
+ normal ggu
+ call assert_equal([
+ \ "aa aa aa aa",
+ \ "bb bb bb bb",
+ \ "cc cc cc cc",
+ \ ""
+ \ ], getline(1, '$'))
+
+ unmap gg
+ set tw&
+ enew!
+endfunc
+
+func Test_format_list_auto()
+ new
+ call setline(1, ['1. abc', '2. def', '3. ghi'])
+ set fo=tan ai bs=2
+ call feedkeys("3G0lli\<BS>\<BS>x\<Esc>", 'tx')
+ call assert_equal('2. defx ghi', getline(2))
+ bwipe!
+ set fo& ai& bs&
+endfunc
diff --git a/src/testdir/test_textobjects.vim b/src/testdir/test_textobjects.vim
new file mode 100644
index 0000000..3c403ab
--- /dev/null
+++ b/src/testdir/test_textobjects.vim
@@ -0,0 +1,259 @@
+" Test for textobjects
+
+if !has('textobjects')
+ finish
+endif
+
+func CpoM(line, useM, expected)
+ new
+
+ if a:useM
+ set cpoptions+=M
+ else
+ set cpoptions-=M
+ endif
+
+ call setline(1, a:line)
+
+ call setreg('"', '')
+ normal! ggfrmavi)y
+ call assert_equal(getreg('"'), a:expected[0])
+
+ call setreg('"', '')
+ normal! `afbmavi)y
+ call assert_equal(getreg('"'), a:expected[1])
+
+ call setreg('"', '')
+ normal! `afgmavi)y
+ call assert_equal(getreg('"'), a:expected[2])
+
+ q!
+endfunc
+
+func Test_inner_block_without_cpo_M()
+ call CpoM('(red \(blue) green)', 0, ['red \(blue', 'red \(blue', ''])
+endfunc
+
+func Test_inner_block_with_cpo_M_left_backslash()
+ call CpoM('(red \(blue) green)', 1, ['red \(blue) green', 'blue', 'red \(blue) green'])
+endfunc
+
+func Test_inner_block_with_cpo_M_right_backslash()
+ call CpoM('(red (blue\) green)', 1, ['red (blue\) green', 'blue\', 'red (blue\) green'])
+endfunc
+
+func Test_quote_selection_selection_exclusive()
+ new
+ call setline(1, "a 'bcde' f")
+ set selection=exclusive
+ exe "norm! fdvhi'y"
+ call assert_equal('bcde', @")
+ set selection&vim
+ bw!
+endfunc
+
+" Tests for string and html text objects
+func Test_string_html_objects()
+ enew!
+
+ let t = '"wo\"rd\\" foo'
+ put =t
+ normal! da"
+ call assert_equal('foo', getline('.'))
+
+ let t = "'foo' 'bar' 'piep'"
+ put =t
+ normal! 0va'a'rx
+ call assert_equal("xxxxxxxxxxxx'piep'", getline('.'))
+
+ let t = "bla bla `quote` blah"
+ put =t
+ normal! 02f`da`
+ call assert_equal("bla bla blah", getline('.'))
+
+ let t = 'out " in "noXno"'
+ put =t
+ normal! 0fXdi"
+ call assert_equal('out " in ""', getline('.'))
+
+ let t = "\"'\" 'blah' rep 'buh'"
+ put =t
+ normal! 03f'vi'ry
+ call assert_equal("\"'\" 'blah'yyyyy'buh'", getline('.'))
+
+ set quoteescape=+*-
+ let t = "bla `s*`d-`+++`l**` b`la"
+ put =t
+ normal! di`
+ call assert_equal("bla `` b`la", getline('.'))
+
+ let t = 'voo "nah" sdf " asdf" sdf " sdf" sd'
+ put =t
+ normal! $F"va"oha"i"rz
+ call assert_equal('voo "zzzzzzzzzzzzzzzzzzzzzzzzzzzzsd', getline('.'))
+
+ let t = "-<b>asdf<i>Xasdf</i>asdf</b>-"
+ put =t
+ normal! fXdit
+ call assert_equal('-<b>asdf<i></i>asdf</b>-', getline('.'))
+
+ let t = "-<b>asdX<i>a<i />sdf</i>asdf</b>-"
+ put =t
+ normal! 0fXdit
+ call assert_equal('-<b></b>-', getline('.'))
+
+ let t = "-<b>asdf<i>Xasdf</i>asdf</b>-"
+ put =t
+ normal! fXdat
+ call assert_equal('-<b>asdfasdf</b>-', getline('.'))
+
+ let t = "-<b>asdX<i>as<b />df</i>asdf</b>-"
+ put =t
+ normal! 0fXdat
+ call assert_equal('--', getline('.'))
+
+ let t = "-<b>\ninnertext object\n</b>"
+ put =t
+ normal! dit
+ call assert_equal('-<b></b>', getline('.'))
+
+ set quoteescape&
+ enew!
+endfunc
+
+func Test_empty_html_tag()
+ new
+ call setline(1, '<div></div>')
+ normal 0citxxx
+ call assert_equal('<div>xxx</div>', getline(1))
+
+ call setline(1, '<div></div>')
+ normal 0f<cityyy
+ call assert_equal('<div>yyy</div>', getline(1))
+
+ call setline(1, '<div></div>')
+ normal 0f<vitsaaa
+ call assert_equal('aaa', getline(1))
+
+ bwipe!
+endfunc
+
+" Tests for match() and matchstr()
+func Test_match()
+ call assert_equal("b", matchstr("abcd", ".", 0, 2))
+ call assert_equal("bc", matchstr("abcd", "..", 0, 2))
+ call assert_equal("c", matchstr("abcd", ".", 2, 0))
+ call assert_equal("a", matchstr("abcd", ".", 0, -1))
+ call assert_equal(-1, match("abcd", ".", 0, 5))
+ call assert_equal(0 , match("abcd", ".", 0, -1))
+ call assert_equal(0 , match('abc', '.', 0, 1))
+ call assert_equal(1 , match('abc', '.', 0, 2))
+ call assert_equal(2 , match('abc', '.', 0, 3))
+ call assert_equal(-1, match('abc', '.', 0, 4))
+ call assert_equal(1 , match('abc', '.', 1, 1))
+ call assert_equal(2 , match('abc', '.', 2, 1))
+ call assert_equal(-1, match('abc', '.', 3, 1))
+ call assert_equal(3 , match('abc', '$', 0, 1))
+ call assert_equal(-1, match('abc', '$', 0, 2))
+ call assert_equal(3 , match('abc', '$', 1, 1))
+ call assert_equal(3 , match('abc', '$', 2, 1))
+ call assert_equal(3 , match('abc', '$', 3, 1))
+ call assert_equal(-1, match('abc', '$', 4, 1))
+ call assert_equal(0 , match('abc', '\zs', 0, 1))
+ call assert_equal(1 , match('abc', '\zs', 0, 2))
+ call assert_equal(2 , match('abc', '\zs', 0, 3))
+ call assert_equal(3 , match('abc', '\zs', 0, 4))
+ call assert_equal(-1, match('abc', '\zs', 0, 5))
+ call assert_equal(1 , match('abc', '\zs', 1, 1))
+ call assert_equal(2 , match('abc', '\zs', 2, 1))
+ call assert_equal(3 , match('abc', '\zs', 3, 1))
+ call assert_equal(-1, match('abc', '\zs', 4, 1))
+endfunc
+
+" This was causing an illegal memory access
+func Test_inner_tag()
+ new
+ norm ixxx
+ call feedkeys("v", 'xt')
+ insert
+x
+x
+.
+ norm it
+ q!
+endfunc
+
+func Test_sentence()
+ enew!
+ call setline(1, 'A sentence. A sentence? A sentence!')
+
+ normal yis
+ call assert_equal('A sentence.', @")
+ normal yas
+ call assert_equal('A sentence. ', @")
+
+ normal )
+
+ normal yis
+ call assert_equal('A sentence?', @")
+ normal yas
+ call assert_equal('A sentence? ', @")
+
+ normal )
+
+ normal yis
+ call assert_equal('A sentence!', @")
+ normal yas
+ call assert_equal(' A sentence!', @")
+
+ normal 0
+ normal 2yis
+ call assert_equal('A sentence. ', @")
+ normal 3yis
+ call assert_equal('A sentence. A sentence?', @")
+ normal 2yas
+ call assert_equal('A sentence. A sentence? ', @")
+
+ %delete _
+endfunc
+
+func Test_sentence_with_quotes()
+ enew!
+ call setline(1, 'A "sentence." A sentence.')
+
+ normal yis
+ call assert_equal('A "sentence."', @")
+ normal yas
+ call assert_equal('A "sentence." ', @")
+
+ normal )
+
+ normal yis
+ call assert_equal('A sentence.', @")
+ normal yas
+ call assert_equal(' A sentence.', @")
+
+ %delete _
+endfunc
+
+func Test_sentence_with_cursor_on_delimiter()
+ enew!
+ call setline(1, "A '([sentence.])' A sentence.")
+
+ normal! 15|yis
+ call assert_equal("A '([sentence.])'", @")
+ normal! 15|yas
+ call assert_equal("A '([sentence.])' ", @")
+
+ normal! 16|yis
+ call assert_equal("A '([sentence.])'", @")
+ normal! 16|yas
+ call assert_equal("A '([sentence.])' ", @")
+
+ normal! 17|yis
+ call assert_equal("A '([sentence.])'", @")
+ normal! 17|yas
+ call assert_equal("A '([sentence.])' ", @")
+
+ %delete _
+endfunc
diff --git a/src/testdir/test_textprop.vim b/src/testdir/test_textprop.vim
new file mode 100644
index 0000000..311f30f
--- /dev/null
+++ b/src/testdir/test_textprop.vim
@@ -0,0 +1,552 @@
+" Tests for defining text property types and adding text properties to the
+" buffer.
+
+if !has('textprop')
+ finish
+endif
+
+source screendump.vim
+
+" test length zero
+
+func Test_proptype_global()
+ call prop_type_add('comment', {'highlight': 'Directory', 'priority': 123, 'start_incl': 1, 'end_incl': 1})
+ let proptypes = prop_type_list()
+ call assert_equal(1, len(proptypes))
+ call assert_equal('comment', proptypes[0])
+
+ let proptype = prop_type_get('comment')
+ call assert_equal('Directory', proptype['highlight'])
+ call assert_equal(123, proptype['priority'])
+ call assert_equal(1, proptype['start_incl'])
+ call assert_equal(1, proptype['end_incl'])
+
+ call prop_type_delete('comment')
+ call assert_equal(0, len(prop_type_list()))
+
+ call prop_type_add('one', {})
+ call assert_equal(1, len(prop_type_list()))
+ let proptype = prop_type_get('one')
+ call assert_false(has_key(proptype, 'highlight'))
+ call assert_equal(0, proptype['priority'])
+ call assert_equal(0, proptype['start_incl'])
+ call assert_equal(0, proptype['end_incl'])
+
+ call prop_type_add('two', {})
+ call assert_equal(2, len(prop_type_list()))
+ call prop_type_delete('one')
+ call assert_equal(1, len(prop_type_list()))
+ call prop_type_delete('two')
+ call assert_equal(0, len(prop_type_list()))
+endfunc
+
+func Test_proptype_buf()
+ let bufnr = bufnr('')
+ call prop_type_add('comment', {'bufnr': bufnr, 'highlight': 'Directory', 'priority': 123, 'start_incl': 1, 'end_incl': 1})
+ let proptypes = prop_type_list({'bufnr': bufnr})
+ call assert_equal(1, len(proptypes))
+ call assert_equal('comment', proptypes[0])
+
+ let proptype = prop_type_get('comment', {'bufnr': bufnr})
+ call assert_equal('Directory', proptype['highlight'])
+ call assert_equal(123, proptype['priority'])
+ call assert_equal(1, proptype['start_incl'])
+ call assert_equal(1, proptype['end_incl'])
+
+ call prop_type_delete('comment', {'bufnr': bufnr})
+ call assert_equal(0, len(prop_type_list({'bufnr': bufnr})))
+
+ call prop_type_add('one', {'bufnr': bufnr})
+ let proptype = prop_type_get('one', {'bufnr': bufnr})
+ call assert_false(has_key(proptype, 'highlight'))
+ call assert_equal(0, proptype['priority'])
+ call assert_equal(0, proptype['start_incl'])
+ call assert_equal(0, proptype['end_incl'])
+
+ call prop_type_add('two', {'bufnr': bufnr})
+ call assert_equal(2, len(prop_type_list({'bufnr': bufnr})))
+ call prop_type_delete('one', {'bufnr': bufnr})
+ call assert_equal(1, len(prop_type_list({'bufnr': bufnr})))
+ call prop_type_delete('two', {'bufnr': bufnr})
+ call assert_equal(0, len(prop_type_list({'bufnr': bufnr})))
+endfunc
+
+func AddPropTypes()
+ call prop_type_add('one', {})
+ call prop_type_add('two', {})
+ call prop_type_add('three', {})
+ call prop_type_add('whole', {})
+endfunc
+
+func DeletePropTypes()
+ call prop_type_delete('one')
+ call prop_type_delete('two')
+ call prop_type_delete('three')
+ call prop_type_delete('whole')
+endfunc
+
+func SetupPropsInFirstLine()
+ call setline(1, 'one two three')
+ call prop_add(1, 1, {'length': 3, 'id': 11, 'type': 'one'})
+ call prop_add(1, 5, {'length': 3, 'id': 12, 'type': 'two'})
+ call prop_add(1, 9, {'length': 5, 'id': 13, 'type': 'three'})
+ call prop_add(1, 1, {'length': 13, 'id': 14, 'type': 'whole'})
+endfunc
+
+func Get_expected_props()
+ return [
+ \ {'col': 1, 'length': 13, 'id': 14, 'type': 'whole', 'start': 1, 'end': 1},
+ \ {'col': 1, 'length': 3, 'id': 11, 'type': 'one', 'start': 1, 'end': 1},
+ \ {'col': 5, 'length': 3, 'id': 12, 'type': 'two', 'start': 1, 'end': 1},
+ \ {'col': 9, 'length': 5, 'id': 13, 'type': 'three', 'start': 1, 'end': 1},
+ \ ]
+endfunc
+
+func Test_prop_add()
+ new
+ call AddPropTypes()
+ call SetupPropsInFirstLine()
+ let expected_props = Get_expected_props()
+ call assert_equal(expected_props, prop_list(1))
+ call assert_fails("call prop_add(10, 1, {'length': 1, 'id': 14, 'type': 'whole'})", 'E966:')
+ call assert_fails("call prop_add(1, 22, {'length': 1, 'id': 14, 'type': 'whole'})", 'E964:')
+
+ " Insert a line above, text props must still be there.
+ call append(0, 'empty')
+ call assert_equal(expected_props, prop_list(2))
+ " Delete a line above, text props must still be there.
+ 1del
+ call assert_equal(expected_props, prop_list(1))
+
+ " Prop without length or end column is zero length
+ call prop_clear(1)
+ call prop_add(1, 5, {'type': 'two'})
+ let expected = [{'col': 5, 'length': 0, 'type': 'two', 'id': 0, 'start': 1, 'end': 1}]
+ call assert_equal(expected, prop_list(1))
+
+ call DeletePropTypes()
+ bwipe!
+endfunc
+
+func Test_prop_remove()
+ new
+ call AddPropTypes()
+ call SetupPropsInFirstLine()
+ let props = Get_expected_props()
+ call assert_equal(props, prop_list(1))
+
+ " remove by id
+ call prop_remove({'id': 12}, 1)
+ unlet props[2]
+ call assert_equal(props, prop_list(1))
+
+ " remove by type
+ call prop_remove({'type': 'one'}, 1)
+ unlet props[1]
+ call assert_equal(props, prop_list(1))
+
+ call DeletePropTypes()
+ bwipe!
+endfunc
+
+func SetupOneLine()
+ call setline(1, 'xonex xtwoxx')
+ call AddPropTypes()
+ call prop_add(1, 2, {'length': 3, 'id': 11, 'type': 'one'})
+ call prop_add(1, 8, {'length': 3, 'id': 12, 'type': 'two'})
+ let expected = [
+ \ {'col': 2, 'length': 3, 'id': 11, 'type': 'one', 'start': 1, 'end': 1},
+ \ {'col': 8, 'length': 3, 'id': 12, 'type': 'two', 'start': 1, 'end': 1},
+ \]
+ call assert_equal(expected, prop_list(1))
+ return expected
+endfunc
+
+func Test_prop_add_remove_buf()
+ new
+ let bufnr = bufnr('')
+ call AddPropTypes()
+ call setline(1, 'one two three')
+ wincmd w
+ call prop_add(1, 1, {'length': 3, 'id': 11, 'type': 'one', 'bufnr': bufnr})
+ call prop_add(1, 5, {'length': 3, 'id': 12, 'type': 'two', 'bufnr': bufnr})
+ call prop_add(1, 11, {'length': 3, 'id': 13, 'type': 'three', 'bufnr': bufnr})
+
+ let props = [
+ \ {'col': 1, 'length': 3, 'id': 11, 'type': 'one', 'start': 1, 'end': 1},
+ \ {'col': 5, 'length': 3, 'id': 12, 'type': 'two', 'start': 1, 'end': 1},
+ \ {'col': 11, 'length': 3, 'id': 13, 'type': 'three', 'start': 1, 'end': 1},
+ \]
+ call assert_equal(props, prop_list(1, {'bufnr': bufnr}))
+
+ " remove by id
+ call prop_remove({'id': 12, 'bufnr': bufnr}, 1)
+ unlet props[1]
+ call assert_equal(props, prop_list(1, {'bufnr': bufnr}))
+
+ " remove by type
+ call prop_remove({'type': 'one', 'bufnr': bufnr}, 1)
+ unlet props[0]
+ call assert_equal(props, prop_list(1, {'bufnr': bufnr}))
+
+ call DeletePropTypes()
+ wincmd w
+ bwipe!
+endfunc
+
+func Test_prop_backspace()
+ new
+ set bs=2
+ let expected = SetupOneLine() " 'xonex xtwoxx'
+
+ exe "normal 0li\<BS>\<Esc>fxli\<BS>\<Esc>"
+ call assert_equal('one xtwoxx', getline(1))
+ let expected[0].col = 1
+ let expected[1].col = 6
+ call assert_equal(expected, prop_list(1))
+
+ call DeletePropTypes()
+ bwipe!
+ set bs&
+endfunc
+
+func Test_prop_replace()
+ new
+ set bs=2
+ let expected = SetupOneLine() " 'xonex xtwoxx'
+
+ exe "normal 0Ryyy\<Esc>"
+ call assert_equal('yyyex xtwoxx', getline(1))
+ call assert_equal(expected, prop_list(1))
+
+ exe "normal ftRyy\<BS>"
+ call assert_equal('yyyex xywoxx', getline(1))
+ call assert_equal(expected, prop_list(1))
+
+ exe "normal 0fwRyy\<BS>"
+ call assert_equal('yyyex xyyoxx', getline(1))
+ call assert_equal(expected, prop_list(1))
+
+ exe "normal 0foRyy\<BS>\<BS>"
+ call assert_equal('yyyex xyyoxx', getline(1))
+ call assert_equal(expected, prop_list(1))
+
+ call DeletePropTypes()
+ bwipe!
+ set bs&
+endfunc
+
+func Test_prop_clear()
+ new
+ call AddPropTypes()
+ call SetupPropsInFirstLine()
+ call assert_equal(Get_expected_props(), prop_list(1))
+
+ call prop_clear(1)
+ call assert_equal([], prop_list(1))
+
+ call DeletePropTypes()
+ bwipe!
+endfunc
+
+func Test_prop_clear_buf()
+ new
+ call AddPropTypes()
+ call SetupPropsInFirstLine()
+ let bufnr = bufnr('')
+ wincmd w
+ call assert_equal(Get_expected_props(), prop_list(1, {'bufnr': bufnr}))
+
+ call prop_clear(1, 1, {'bufnr': bufnr})
+ call assert_equal([], prop_list(1, {'bufnr': bufnr}))
+
+ wincmd w
+ call DeletePropTypes()
+ bwipe!
+endfunc
+
+func Test_prop_setline()
+ new
+ call AddPropTypes()
+ call SetupPropsInFirstLine()
+ call assert_equal(Get_expected_props(), prop_list(1))
+
+ call setline(1, 'foobar')
+ call assert_equal([], prop_list(1))
+
+ call DeletePropTypes()
+ bwipe!
+endfunc
+
+func Test_prop_setbufline()
+ new
+ call AddPropTypes()
+ call SetupPropsInFirstLine()
+ let bufnr = bufnr('')
+ wincmd w
+ call assert_equal(Get_expected_props(), prop_list(1, {'bufnr': bufnr}))
+
+ call setbufline(bufnr, 1, 'foobar')
+ call assert_equal([], prop_list(1, {'bufnr': bufnr}))
+
+ wincmd w
+ call DeletePropTypes()
+ bwipe!
+endfunc
+
+func Test_prop_substitute()
+ new
+ " Set first line to 'one two three'
+ call AddPropTypes()
+ call SetupPropsInFirstLine()
+ let expected_props = Get_expected_props()
+ call assert_equal(expected_props, prop_list(1))
+
+ " Change "n" in "one" to XX: 'oXXe two three'
+ s/n/XX/
+ let expected_props[0].length += 1
+ let expected_props[1].length += 1
+ let expected_props[2].col += 1
+ let expected_props[3].col += 1
+ call assert_equal(expected_props, prop_list(1))
+
+ " Delete "t" in "two" and "three" to XX: 'oXXe wo hree'
+ s/t//g
+ let expected_props[0].length -= 2
+ let expected_props[2].length -= 1
+ let expected_props[3].length -= 1
+ let expected_props[3].col -= 1
+ call assert_equal(expected_props, prop_list(1))
+
+ " Split the line by changing w to line break: 'oXXe ', 'o hree'
+ " The long prop is split and spans both lines.
+ " The props on "two" and "three" move to the next line.
+ s/w/\r/
+ let new_props = [
+ \ copy(expected_props[0]),
+ \ copy(expected_props[2]),
+ \ copy(expected_props[3]),
+ \ ]
+ let expected_props[0].length = 5
+ unlet expected_props[3]
+ unlet expected_props[2]
+ call assert_equal(expected_props, prop_list(1))
+
+ let new_props[0].length = 6
+ let new_props[1].col = 1
+ let new_props[1].length = 1
+ let new_props[2].col = 3
+ call assert_equal(new_props, prop_list(2))
+
+ call DeletePropTypes()
+ bwipe!
+endfunc
+
+func Test_prop_change_indent()
+ call prop_type_add('comment', {'highlight': 'Directory'})
+ new
+ call setline(1, [' xxx', 'yyyyy'])
+ call prop_add(2, 2, {'length': 2, 'type': 'comment'})
+ let expect = {'col': 2, 'length': 2, 'type': 'comment', 'start': 1, 'end': 1, 'id': 0}
+ call assert_equal([expect], prop_list(2))
+
+ set shiftwidth=3
+ normal 2G>>
+ call assert_equal(' yyyyy', getline(2))
+ let expect.col += 3
+ call assert_equal([expect], prop_list(2))
+
+ normal 2G==
+ call assert_equal(' yyyyy', getline(2))
+ let expect.col = 6
+ call assert_equal([expect], prop_list(2))
+
+ call prop_clear(2)
+ call prop_add(2, 2, {'length': 5, 'type': 'comment'})
+ let expect.col = 2
+ let expect.length = 5
+ call assert_equal([expect], prop_list(2))
+
+ normal 2G<<
+ call assert_equal(' yyyyy', getline(2))
+ let expect.length = 2
+ call assert_equal([expect], prop_list(2))
+
+ set shiftwidth&
+ call prop_type_delete('comment')
+endfunc
+
+" Setup a three line prop in lines 2 - 4.
+" Add short props in line 1 and 5.
+func Setup_three_line_prop()
+ new
+ call setline(1, ['one', 'twotwo', 'three', 'fourfour', 'five'])
+ call prop_add(1, 2, {'length': 1, 'type': 'comment'})
+ call prop_add(2, 4, {'end_lnum': 4, 'end_col': 5, 'type': 'comment'})
+ call prop_add(5, 2, {'length': 1, 'type': 'comment'})
+endfunc
+
+func Test_prop_multiline()
+ call prop_type_add('comment', {'highlight': 'Directory'})
+ new
+ call setline(1, ['xxxxxxx', 'yyyyyyyyy', 'zzzzzzzz'])
+
+ " start halfway line 1, end halfway line 3
+ call prop_add(1, 3, {'end_lnum': 3, 'end_col': 5, 'type': 'comment'})
+ let expect1 = {'col': 3, 'length': 6, 'type': 'comment', 'start': 1, 'end': 0, 'id': 0}
+ call assert_equal([expect1], prop_list(1))
+ let expect2 = {'col': 1, 'length': 10, 'type': 'comment', 'start': 0, 'end': 0, 'id': 0}
+ call assert_equal([expect2], prop_list(2))
+ let expect3 = {'col': 1, 'length': 4, 'type': 'comment', 'start': 0, 'end': 1, 'id': 0}
+ call assert_equal([expect3], prop_list(3))
+ call prop_clear(1, 3)
+
+ " include all three lines
+ call prop_add(1, 1, {'end_lnum': 3, 'end_col': 999, 'type': 'comment'})
+ let expect1.col = 1
+ let expect1.length = 8
+ call assert_equal([expect1], prop_list(1))
+ call assert_equal([expect2], prop_list(2))
+ let expect3.length = 9
+ call assert_equal([expect3], prop_list(3))
+ call prop_clear(1, 3)
+
+ bwipe!
+
+ " Test deleting the first line of a multi-line prop.
+ call Setup_three_line_prop()
+ let expect_short = {'col': 2, 'length': 1, 'type': 'comment', 'start': 1, 'end': 1, 'id': 0}
+ call assert_equal([expect_short], prop_list(1))
+ let expect2 = {'col': 4, 'length': 4, 'type': 'comment', 'start': 1, 'end': 0, 'id': 0}
+ call assert_equal([expect2], prop_list(2))
+ 2del
+ call assert_equal([expect_short], prop_list(1))
+ let expect2 = {'col': 1, 'length': 6, 'type': 'comment', 'start': 1, 'end': 0, 'id': 0}
+ call assert_equal([expect2], prop_list(2))
+ bwipe!
+
+ " Test deleting the last line of a multi-line prop.
+ call Setup_three_line_prop()
+ let expect3 = {'col': 1, 'length': 6, 'type': 'comment', 'start': 0, 'end': 0, 'id': 0}
+ call assert_equal([expect3], prop_list(3))
+ let expect4 = {'col': 1, 'length': 4, 'type': 'comment', 'start': 0, 'end': 1, 'id': 0}
+ call assert_equal([expect4], prop_list(4))
+ 4del
+ let expect3.end = 1
+ call assert_equal([expect3], prop_list(3))
+ call assert_equal([expect_short], prop_list(4))
+ bwipe!
+
+ " Test appending a line below the multi-line text prop start.
+ call Setup_three_line_prop()
+ let expect2 = {'col': 4, 'length': 4, 'type': 'comment', 'start': 1, 'end': 0, 'id': 0}
+ call assert_equal([expect2], prop_list(2))
+ call append(2, "new line")
+ call assert_equal([expect2], prop_list(2))
+ let expect3 = {'col': 1, 'length': 9, 'type': 'comment', 'start': 0, 'end': 0, 'id': 0}
+ call assert_equal([expect3], prop_list(3))
+ bwipe!
+
+ call prop_type_delete('comment')
+endfunc
+
+func Test_prop_byteoff()
+ call prop_type_add('comment', {'highlight': 'Directory'})
+ new
+ call setline(1, ['line1', 'second line', ''])
+ set ff=unix
+ call assert_equal(19, line2byte(3))
+ call prop_add(1, 1, {'end_col': 3, 'type': 'comment'})
+ call assert_equal(19, line2byte(3))
+
+ bwipe!
+ call prop_type_delete('comment')
+endfunc
+
+func Test_prop_undo()
+ new
+ call prop_type_add('comment', {'highlight': 'Directory'})
+ call setline(1, ['oneone', 'twotwo', 'three'])
+ " Set 'undolevels' to break changes into undo-able pieces.
+ set ul&
+
+ call prop_add(1, 3, {'end_col': 5, 'type': 'comment'})
+ let expected = [{'col': 3, 'length': 2, 'id': 0, 'type': 'comment', 'start': 1, 'end': 1} ]
+ call assert_equal(expected, prop_list(1))
+
+ " Insert a character, then undo.
+ exe "normal 0lllix\<Esc>"
+ set ul&
+ let expected[0].length = 3
+ call assert_equal(expected, prop_list(1))
+ undo
+ let expected[0].length = 2
+ call assert_equal(expected, prop_list(1))
+
+ " Delete a character, then undo
+ exe "normal 0lllx"
+ set ul&
+ let expected[0].length = 1
+ call assert_equal(expected, prop_list(1))
+ undo
+ let expected[0].length = 2
+ call assert_equal(expected, prop_list(1))
+
+ " Delete the line, then undo
+ 1d
+ set ul&
+ call assert_equal([], prop_list(1))
+ undo
+ call assert_equal(expected, prop_list(1))
+
+ " Insert a character, delete two characters, then undo with "U"
+ exe "normal 0lllix\<Esc>"
+ set ul&
+ let expected[0].length = 3
+ call assert_equal(expected, prop_list(1))
+ exe "normal 0lllxx"
+ set ul&
+ let expected[0].length = 1
+ call assert_equal(expected, prop_list(1))
+ normal U
+ let expected[0].length = 2
+ call assert_equal(expected, prop_list(1))
+
+ bwipe!
+ call prop_type_delete('comment')
+endfunc
+
+" screenshot test with textprop highlighting
+funct Test_textprop_screenshots()
+ if !CanRunVimInTerminal() || &encoding != 'utf-8'
+ return
+ endif
+ call writefile([
+ \ "call setline(1, ['One two', 'Numbér 123 änd thœn 4¾7.', '--aa--bb--cc--dd--'])",
+ \ "hi NumberProp ctermfg=blue",
+ \ "hi LongProp ctermbg=yellow",
+ \ "call prop_type_add('number', {'highlight': 'NumberProp'})",
+ \ "call prop_type_add('long', {'highlight': 'LongProp'})",
+ \ "call prop_type_add('start', {'highlight': 'NumberProp', 'start_incl': 1})",
+ \ "call prop_type_add('end', {'highlight': 'NumberProp', 'end_incl': 1})",
+ \ "call prop_type_add('both', {'highlight': 'NumberProp', 'start_incl': 1, 'end_incl': 1})",
+ \ "call prop_add(1, 4, {'end_lnum': 3, 'end_col': 3, 'type': 'long'})",
+ \ "call prop_add(2, 9, {'length': 3, 'type': 'number'})",
+ \ "call prop_add(2, 24, {'length': 4, 'type': 'number'})",
+ \ "call prop_add(3, 3, {'length': 2, 'type': 'number'})",
+ \ "call prop_add(3, 7, {'length': 2, 'type': 'start'})",
+ \ "call prop_add(3, 11, {'length': 2, 'type': 'end'})",
+ \ "call prop_add(3, 15, {'length': 2, 'type': 'both'})",
+ \ "set number",
+ \ "hi clear SpellBad",
+ \ "set spell",
+ \ "normal 3G0llix\<Esc>lllix\<Esc>lllix\<Esc>lllix\<Esc>lllix\<Esc>lllix\<Esc>lllix\<Esc>lllix\<Esc>",
+ \ "normal 3G0lli\<BS>\<Esc>",
+ \], 'XtestProp')
+ let buf = RunVimInTerminal('-S XtestProp', {'rows': 6})
+ call VerifyScreenDump(buf, 'Test_textprop_01', {})
+
+ " clean up
+ call StopVimInTerminal(buf)
+ call delete('XtestProp')
+endfunc
diff --git a/src/testdir/test_timers.vim b/src/testdir/test_timers.vim
new file mode 100644
index 0000000..e900b1f
--- /dev/null
+++ b/src/testdir/test_timers.vim
@@ -0,0 +1,313 @@
+" Test for timers
+
+if !has('timers')
+ finish
+endif
+
+source shared.vim
+source screendump.vim
+
+func MyHandler(timer)
+ let g:val += 1
+endfunc
+
+func MyHandlerWithLists(lists, timer)
+ let x = string(a:lists)
+endfunc
+
+func Test_oneshot()
+ let g:val = 0
+ let timer = timer_start(50, 'MyHandler')
+ let slept = WaitFor('g:val == 1')
+ call assert_equal(1, g:val)
+ if has('reltime')
+ call assert_inrange(49, 100, slept)
+ else
+ call assert_inrange(20, 100, slept)
+ endif
+endfunc
+
+func Test_repeat_three()
+ let g:val = 0
+ let timer = timer_start(50, 'MyHandler', {'repeat': 3})
+ let slept = WaitFor('g:val == 3')
+ call assert_equal(3, g:val)
+ if has('reltime')
+ call assert_inrange(149, 250, slept)
+ else
+ call assert_inrange(80, 200, slept)
+ endif
+endfunc
+
+func Test_repeat_many()
+ let g:val = 0
+ let timer = timer_start(50, 'MyHandler', {'repeat': -1})
+ sleep 200m
+ call timer_stop(timer)
+ call assert_inrange(2, 4, g:val)
+endfunc
+
+func Test_with_partial_callback()
+ let g:val = 0
+ let meow = {'one': 1}
+ function meow.bite(...)
+ let g:val += self.one
+ endfunction
+
+ call timer_start(50, meow.bite)
+ let slept = WaitFor('g:val == 1')
+ call assert_equal(1, g:val)
+ if has('reltime')
+ call assert_inrange(49, 130, slept)
+ else
+ call assert_inrange(20, 100, slept)
+ endif
+endfunc
+
+func Test_retain_partial()
+ call timer_start(50, function('MyHandlerWithLists', [['a']]))
+ call test_garbagecollect_now()
+ sleep 100m
+endfunc
+
+func Test_info()
+ let id = timer_start(1000, 'MyHandler')
+ let info = timer_info(id)
+ call assert_equal(id, info[0]['id'])
+ call assert_equal(1000, info[0]['time'])
+ call assert_true(info[0]['remaining'] > 500)
+ call assert_true(info[0]['remaining'] <= 1000)
+ call assert_equal(1, info[0]['repeat'])
+ call assert_equal("function('MyHandler')", string(info[0]['callback']))
+
+ let found = 0
+ for info in timer_info()
+ if info['id'] == id
+ let found += 1
+ endif
+ endfor
+ call assert_equal(1, found)
+
+ call timer_stop(id)
+ call assert_equal([], timer_info(id))
+endfunc
+
+func Test_stopall()
+ let id1 = timer_start(1000, 'MyHandler')
+ let id2 = timer_start(2000, 'MyHandler')
+ let info = timer_info()
+ call assert_equal(2, len(info))
+
+ call timer_stopall()
+ let info = timer_info()
+ call assert_equal(0, len(info))
+endfunc
+
+func Test_paused()
+ let g:val = 0
+
+ let id = timer_start(50, 'MyHandler')
+ let info = timer_info(id)
+ call assert_equal(0, info[0]['paused'])
+
+ call timer_pause(id, 1)
+ let info = timer_info(id)
+ call assert_equal(1, info[0]['paused'])
+ sleep 100m
+ call assert_equal(0, g:val)
+
+ call timer_pause(id, 0)
+ let info = timer_info(id)
+ call assert_equal(0, info[0]['paused'])
+
+ let slept = WaitFor('g:val == 1')
+ call assert_equal(1, g:val)
+ if has('reltime')
+ if has('mac')
+ " The travis Mac machines appear to be very busy.
+ call assert_inrange(0, 50, slept)
+ else
+ call assert_inrange(0, 30, slept)
+ endif
+ else
+ call assert_inrange(0, 10, slept)
+ endif
+endfunc
+
+func StopMyself(timer)
+ let g:called += 1
+ if g:called == 2
+ call timer_stop(a:timer)
+ endif
+endfunc
+
+func Test_delete_myself()
+ let g:called = 0
+ let t = timer_start(10, 'StopMyself', {'repeat': -1})
+ call WaitForAssert({-> assert_equal(2, g:called)})
+ call assert_equal(2, g:called)
+ call assert_equal([], timer_info(t))
+endfunc
+
+func StopTimer1(timer)
+ let g:timer2 = timer_start(10, 'StopTimer2')
+ " avoid maxfuncdepth error
+ call timer_pause(g:timer1, 1)
+ sleep 40m
+endfunc
+
+func StopTimer2(timer)
+ call timer_stop(g:timer1)
+endfunc
+
+func Test_stop_in_callback()
+ let g:timer1 = timer_start(10, 'StopTimer1')
+ sleep 40m
+endfunc
+
+func StopTimerAll(timer)
+ call timer_stopall()
+endfunc
+
+func Test_stop_all_in_callback()
+ let g:timer1 = timer_start(10, 'StopTimerAll')
+ let info = timer_info()
+ call assert_equal(1, len(info))
+ sleep 40m
+ let info = timer_info()
+ call assert_equal(0, len(info))
+endfunc
+
+func FeedkeysCb(timer)
+ call feedkeys("hello\<CR>", 'nt')
+endfunc
+
+func InputCb(timer)
+ call timer_start(10, 'FeedkeysCb')
+ let g:val = input('?')
+ call Resume()
+endfunc
+
+func Test_input_in_timer()
+ let g:val = ''
+ call timer_start(10, 'InputCb')
+ call Standby(1000)
+ call assert_equal('hello', g:val)
+endfunc
+
+func FuncWithError(timer)
+ let g:call_count += 1
+ if g:call_count == 4
+ return
+ endif
+ doesnotexist
+endfunc
+
+func Test_timer_errors()
+ let g:call_count = 0
+ let timer = timer_start(10, 'FuncWithError', {'repeat': -1})
+ " Timer will be stopped after failing 3 out of 3 times.
+ call WaitForAssert({-> assert_equal(3, g:call_count)})
+ sleep 50m
+ call assert_equal(3, g:call_count)
+endfunc
+
+func FuncWithCaughtError(timer)
+ let g:call_count += 1
+ try
+ doesnotexist
+ catch
+ " nop
+ endtry
+endfunc
+
+func Test_timer_catch_error()
+ let g:call_count = 0
+ let timer = timer_start(10, 'FuncWithCaughtError', {'repeat': 4})
+ " Timer will not be stopped.
+ call WaitForAssert({-> assert_equal(4, g:call_count)})
+ sleep 50m
+ call assert_equal(4, g:call_count)
+endfunc
+
+func FeedAndPeek(timer)
+ call test_feedinput('a')
+ call getchar(1)
+endfunc
+
+func Interrupt(timer)
+ call test_feedinput("\<C-C>")
+endfunc
+
+func Test_peek_and_get_char()
+ if !has('unix') && !has('gui_running')
+ return
+ endif
+ call timer_start(0, 'FeedAndPeek')
+ let intr = timer_start(100, 'Interrupt')
+ let c = getchar()
+ call assert_equal(char2nr('a'), c)
+ call timer_stop(intr)
+endfunc
+
+func Test_getchar_zero()
+ if has('win32') && !has('gui_running')
+ " Console: no low-level input
+ return
+ endif
+
+ " Measure the elapsed time to avoid a hang when it fails.
+ let start = reltime()
+ let id = timer_start(20, {-> feedkeys('x', 'L')})
+ let c = 0
+ while c == 0 && reltimefloat(reltime(start)) < 0.2
+ let c = getchar(0)
+ sleep 10m
+ endwhile
+ call assert_equal('x', nr2char(c))
+ call timer_stop(id)
+endfunc
+
+func Test_ex_mode()
+ " Function with an empty line.
+ func Foo(...)
+
+ endfunc
+ let timer = timer_start(40, function('g:Foo'), {'repeat':-1})
+ " This used to throw error E749.
+ exe "normal Qsleep 100m\rvi\r"
+ call timer_stop(timer)
+endfunc
+
+func Test_restore_count()
+ if !CanRunVimInTerminal()
+ return
+ endif
+ " Check that v:count is saved and restored, not changed by a timer.
+ call writefile([
+ \ 'nnoremap <expr><silent> L v:count ? v:count . "l" : "l"',
+ \ 'func Doit(id)',
+ \ ' normal 3j',
+ \ 'endfunc',
+ \ 'call timer_start(100, "Doit")',
+ \ ], 'Xtrcscript')
+ call writefile([
+ \ '1-1234',
+ \ '2-1234',
+ \ '3-1234',
+ \ ], 'Xtrctext')
+ let buf = RunVimInTerminal('-S Xtrcscript Xtrctext', {})
+
+ " Wait for the timer to move the cursor to the third line.
+ call WaitForAssert({-> assert_equal(3, term_getcursor(buf)[0])})
+ call assert_equal(1, term_getcursor(buf)[1])
+ " Now check that v:count has not been set to 3
+ call term_sendkeys(buf, 'L')
+ call WaitForAssert({-> assert_equal(2, term_getcursor(buf)[1])})
+
+ call StopVimInTerminal(buf)
+ call delete('Xtrcscript')
+ call delete('Xtrctext')
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/test_true_false.vim b/src/testdir/test_true_false.vim
new file mode 100644
index 0000000..a23f2cc
--- /dev/null
+++ b/src/testdir/test_true_false.vim
@@ -0,0 +1,150 @@
+" Test behavior of boolean-like values.
+
+" Test what is explained at ":help TRUE" and ":help FALSE".
+func Test_if()
+ if v:false
+ call assert_true(false, 'v:false is false')
+ endif
+ if 0
+ call assert_true(false, 'zero is false')
+ endif
+ if "0"
+ call assert_true(false, 'zero string is false')
+ endif
+ if "foo"
+ call assert_true(false, 'foo is false')
+ endif
+ if " "
+ call assert_true(false, 'space is false')
+ endif
+ if empty("foo")
+ call assert_true(false, 'foo is not empty')
+ endif
+
+ if v:true
+ else
+ call assert_true(false, 'v:true is true')
+ endif
+ if 1
+ else
+ call assert_true(false, 'one is true')
+ endif
+ if "1"
+ else
+ call assert_true(false, 'one string is true')
+ endif
+ if "1foo"
+ else
+ call assert_true(false, 'one in string is true')
+ endif
+
+ call assert_fails('if [1]', 'E745')
+ call assert_fails('if {1: 1}', 'E728')
+ call assert_fails('if function("string")', 'E703')
+ call assert_fails('if 1.3")', 'E805')
+endfunc
+
+function Try_arg_true_false(expr, false_val, true_val)
+ for v in ['v:false', '0', '"0"', '"foo"', '" "']
+ let r = eval(substitute(a:expr, '%v%', v, ''))
+ call assert_equal(a:false_val, r, 'result for ' . v . ' is not ' . string(a:false_val) . ' but ' . string(r))
+ endfor
+ for v in ['v:true', '1', '"1"', '"1foo"']
+ let r = eval(substitute(a:expr, '%v%', v, ''))
+ call assert_equal(a:true_val, r, 'result for ' . v . ' is not ' . string(a:true_val) . ' but ' . string(r))
+ endfor
+endfunc
+
+" Test using TRUE or FALSE values for an argument.
+func Test_true_false_arg()
+ call Try_arg_true_false('count(["a", "A"], "a", %v%)', 1, 2)
+
+ set wildignore=*.swp
+ call Try_arg_true_false('expand("foo.swp", %v%)', "", "foo.swp")
+ call Try_arg_true_false('expand("foo.vim", 0, %v%)', "foo.vim", ["foo.vim"])
+
+ call setreg('a', ['x', 'y'])
+ call Try_arg_true_false('getreg("a", 1, %v%)', "x\ny\n", ['x', 'y'])
+
+ set wildignore=*.vim
+ call Try_arg_true_false('glob("runtest.vim", %v%)', "", "runtest.vim")
+ set wildignore=*.swp
+ call Try_arg_true_false('glob("runtest.vim", 0, %v%)', "runtest.vim", ["runtest.vim"])
+ if has('unix')
+ silent !ln -s doesntexit Xlink
+ call Try_arg_true_false('glob("Xlink", 0, 0, %v%)', "", "Xlink")
+ silent !rm Xlink
+ endif
+
+ set wildignore=*.vim
+ call Try_arg_true_false('globpath(".", "runtest.vim", %v%)', "", "./runtest.vim")
+ set wildignore=*.swp
+ call Try_arg_true_false('globpath(".", "runtest.vim", 0, %v%)', "./runtest.vim", ["./runtest.vim"])
+ if has('unix')
+ silent !ln -s doesntexit Xlink
+ call Try_arg_true_false('globpath(".", "Xlink", 0, 0, %v%)', "", "./Xlink")
+ silent !rm Xlink
+ endif
+
+ abbr asdf asdff
+ call Try_arg_true_false('hasmapto("asdff", "i", %v%)', 0, 1)
+
+ call Try_arg_true_false('index(["a", "A"], "A", 0, %v%)', 1, 0)
+
+ function FilterMapArg(d)
+ if type(a:d) == type({})
+ return filter(a:d, 'v:key == "rhs"')
+ endif
+ return a:d
+ endfunction
+ call Try_arg_true_false('maparg("asdf", "i", %v%)', "", "asdff")
+ call Try_arg_true_false('FilterMapArg(maparg("asdf", "i", 1, %v%))', "asdff", {'rhs': 'asdff'})
+
+ call Try_arg_true_false('hasmapto("asdf", "i", %v%)', 0, 1)
+
+ new colored
+ call setline(1, '<here>')
+ syn match brackets "<.*>"
+ syn match here "here" transparent
+ let brackets_id = synID(1, 1, 0)
+ let here_id = synID(1, 3, 0)
+ call Try_arg_true_false('synID(1, 3, %v%)', here_id, brackets_id)
+ bwipe!
+endfunc
+
+function Try_arg_non_zero(expr, false_val, true_val)
+ for v in ['v:false', '0', '[1]', '{2:3}', '3.4']
+ let r = eval(substitute(a:expr, '%v%', v, ''))
+ call assert_equal(a:false_val, r, 'result for ' . v . ' is not ' . a:false_val . ' but ' . r)
+ endfor
+ for v in ['v:true', '1', '" "', '"0"']
+ let r = eval(substitute(a:expr, '%v%', v, ''))
+ call assert_equal(a:true_val, r, 'result for ' . v . ' is not ' . a:true_val . ' but ' . r)
+ endfor
+endfunc
+
+
+" Test using non-zero-arg for an argument.
+func Test_non_zero_arg()
+ call test_settime(93784)
+ call Try_arg_non_zero("mode(%v%)", 'x', 'x!')
+ call test_settime(0)
+
+ call Try_arg_non_zero("shellescape('foo%', %v%)", "'foo%'", "'foo\\%'")
+
+ " visualmode() needs to be called twice to check
+ for v in [v:false, 0, [1], {2:3}, 3.4]
+ normal vv
+ let r = visualmode(v)
+ call assert_equal('v', r, 'result for ' . string(v) . ' is not "v" but ' . r)
+ let r = visualmode(v)
+ call assert_equal('v', r, 'result for ' . string(v) . ' is not "v" but ' . r)
+ endfor
+ for v in [v:true, 1, " ", "0"]
+ normal vv
+ let r = visualmode(v)
+ call assert_equal('v', r, 'result for ' . v . ' is not "v" but ' . r)
+ let r = visualmode(v)
+ call assert_equal('', r, 'result for ' . v . ' is not "" but ' . r)
+ endfor
+endfunc
diff --git a/src/testdir/test_undo.vim b/src/testdir/test_undo.vim
new file mode 100644
index 0000000..7c93e23
--- /dev/null
+++ b/src/testdir/test_undo.vim
@@ -0,0 +1,444 @@
+" Tests for the undo tree.
+" Since this script is sourced we need to explicitly break changes up in
+" undo-able pieces. Do that by setting 'undolevels'.
+" Also tests :earlier and :later.
+
+func Test_undotree()
+ new
+
+ normal! Aabc
+ set ul=100
+ let d = undotree()
+ call assert_equal(1, d.seq_last)
+ call assert_equal(1, d.seq_cur)
+ call assert_equal(0, d.save_last)
+ call assert_equal(0, d.save_cur)
+ call assert_equal(1, len(d.entries))
+ call assert_equal(1, d.entries[0].newhead)
+ call assert_equal(1, d.entries[0].seq)
+ call assert_true(d.entries[0].time <= d.time_cur)
+
+ normal! Adef
+ set ul=100
+ let d = undotree()
+ call assert_equal(2, d.seq_last)
+ call assert_equal(2, d.seq_cur)
+ call assert_equal(0, d.save_last)
+ call assert_equal(0, d.save_cur)
+ call assert_equal(2, len(d.entries))
+ call assert_equal(1, d.entries[0].seq)
+ call assert_equal(1, d.entries[1].newhead)
+ call assert_equal(2, d.entries[1].seq)
+ call assert_true(d.entries[1].time <= d.time_cur)
+
+ undo
+ set ul=100
+ let d = undotree()
+ call assert_equal(2, d.seq_last)
+ call assert_equal(1, d.seq_cur)
+ call assert_equal(0, d.save_last)
+ call assert_equal(0, d.save_cur)
+ call assert_equal(2, len(d.entries))
+ call assert_equal(1, d.entries[0].seq)
+ call assert_equal(1, d.entries[1].curhead)
+ call assert_equal(1, d.entries[1].newhead)
+ call assert_equal(2, d.entries[1].seq)
+ call assert_true(d.entries[1].time == d.time_cur)
+
+ normal! Aghi
+ set ul=100
+ let d = undotree()
+ call assert_equal(3, d.seq_last)
+ call assert_equal(3, d.seq_cur)
+ call assert_equal(0, d.save_last)
+ call assert_equal(0, d.save_cur)
+ call assert_equal(2, len(d.entries))
+ call assert_equal(1, d.entries[0].seq)
+ call assert_equal(2, d.entries[1].alt[0].seq)
+ call assert_equal(1, d.entries[1].newhead)
+ call assert_equal(3, d.entries[1].seq)
+ call assert_true(d.entries[1].time <= d.time_cur)
+
+ undo
+ set ul=100
+ let d = undotree()
+ call assert_equal(3, d.seq_last)
+ call assert_equal(1, d.seq_cur)
+ call assert_equal(0, d.save_last)
+ call assert_equal(0, d.save_cur)
+ call assert_equal(2, len(d.entries))
+ call assert_equal(1, d.entries[0].seq)
+ call assert_equal(2, d.entries[1].alt[0].seq)
+ call assert_equal(1, d.entries[1].curhead)
+ call assert_equal(1, d.entries[1].newhead)
+ call assert_equal(3, d.entries[1].seq)
+ call assert_true(d.entries[1].time == d.time_cur)
+
+ w! Xtest
+ let d = undotree()
+ call assert_equal(1, d.save_cur)
+ call assert_equal(1, d.save_last)
+ call delete('Xtest')
+ bwipe! Xtest
+endfunc
+
+func FillBuffer()
+ for i in range(1,13)
+ put=i
+ " Set 'undolevels' to split undo.
+ exe "setg ul=" . &g:ul
+ endfor
+endfunc
+
+func Test_global_local_undolevels()
+ new one
+ set undolevels=5
+ call FillBuffer()
+ " will only undo the last 5 changes, end up with 13 - (5 + 1) = 7 lines
+ earlier 10
+ call assert_equal(5, &g:undolevels)
+ call assert_equal(-123456, &l:undolevels)
+ call assert_equal('7', getline('$'))
+
+ new two
+ setlocal undolevels=2
+ call FillBuffer()
+ " will only undo the last 2 changes, end up with 13 - (2 + 1) = 10 lines
+ earlier 10
+ call assert_equal(5, &g:undolevels)
+ call assert_equal(2, &l:undolevels)
+ call assert_equal('10', getline('$'))
+
+ setlocal ul=10
+ call assert_equal(5, &g:undolevels)
+ call assert_equal(10, &l:undolevels)
+
+ " Setting local value in "two" must not change local value in "one"
+ wincmd p
+ call assert_equal(5, &g:undolevels)
+ call assert_equal(-123456, &l:undolevels)
+
+ new three
+ setglobal ul=50
+ call assert_equal(50, &g:undolevels)
+ call assert_equal(-123456, &l:undolevels)
+
+ " Drop created windows
+ set ul&
+ new
+ only!
+endfunc
+
+func BackOne(expected)
+ call feedkeys('g-', 'xt')
+ call assert_equal(a:expected, getline(1))
+endfunc
+
+func Test_undo_del_chars()
+ " Setup a buffer without creating undo entries
+ new
+ set ul=-1
+ call setline(1, ['123-456'])
+ set ul=100
+ 1
+ call test_settime(100)
+
+ " Delete three characters and undo with g-
+ call feedkeys('x', 'xt')
+ call feedkeys('x', 'xt')
+ call feedkeys('x', 'xt')
+ call assert_equal('-456', getline(1))
+ call BackOne('3-456')
+ call BackOne('23-456')
+ call BackOne('123-456')
+ call assert_fails("BackOne('123-456')")
+
+ :" Delete three other characters and go back in time with g-
+ call feedkeys('$x', 'xt')
+ call feedkeys('x', 'xt')
+ call feedkeys('x', 'xt')
+ call assert_equal('123-', getline(1))
+ call test_settime(101)
+
+ call BackOne('123-4')
+ call BackOne('123-45')
+ " skips '123-456' because it's older
+ call BackOne('-456')
+ call BackOne('3-456')
+ call BackOne('23-456')
+ call BackOne('123-456')
+ call assert_fails("BackOne('123-456')")
+ normal 10g+
+ call assert_equal('123-', getline(1))
+
+ :" Jump two seconds and go some seconds forward and backward
+ call test_settime(103)
+ call feedkeys("Aa\<Esc>", 'xt')
+ call feedkeys("Ab\<Esc>", 'xt')
+ call feedkeys("Ac\<Esc>", 'xt')
+ call assert_equal('123-abc', getline(1))
+ earlier 1s
+ call assert_equal('123-', getline(1))
+ earlier 3s
+ call assert_equal('123-456', getline(1))
+ later 1s
+ call assert_equal('123-', getline(1))
+ later 1h
+ call assert_equal('123-abc', getline(1))
+
+ close!
+endfunc
+
+func Test_undolist()
+ new
+ set ul=100
+
+ let a = execute('undolist')
+ call assert_equal("\nNothing to undo", a)
+
+ " 1 leaf (2 changes).
+ call feedkeys('achange1', 'xt')
+ call feedkeys('achange2', 'xt')
+ let a = execute('undolist')
+ call assert_match("^\nnumber changes when *saved\n *2 *2 .*$", a)
+
+ " 2 leaves.
+ call feedkeys('u', 'xt')
+ call feedkeys('achange3\<Esc>', 'xt')
+ let a = execute('undolist')
+ call assert_match("^\nnumber changes when *saved\n *2 *2 *.*\n *3 *2 .*$", a)
+ close!
+endfunc
+
+func Test_U_command()
+ new
+ set ul=100
+ call feedkeys("achange1\<Esc>", 'xt')
+ call feedkeys("achange2\<Esc>", 'xt')
+ norm! U
+ call assert_equal('', getline(1))
+ norm! U
+ call assert_equal('change1change2', getline(1))
+ close!
+endfunc
+
+func Test_undojoin()
+ new
+ call feedkeys("Goaaaa\<Esc>", 'xt')
+ call feedkeys("obbbb\<Esc>", 'xt')
+ call assert_equal(['aaaa', 'bbbb'], getline(2, '$'))
+ call feedkeys("u", 'xt')
+ call assert_equal(['aaaa'], getline(2, '$'))
+ call feedkeys("obbbb\<Esc>", 'xt')
+ undojoin
+ " Note: next change must not be as if typed
+ call feedkeys("occcc\<Esc>", 'x')
+ call assert_equal(['aaaa', 'bbbb', 'cccc'], getline(2, '$'))
+ call feedkeys("u", 'xt')
+ call assert_equal(['aaaa'], getline(2, '$'))
+ bwipe!
+endfunc
+
+func Test_undojoin_redo()
+ new
+ call setline(1, ['first line', 'second line'])
+ call feedkeys("ixx\<Esc>", 'xt')
+ call feedkeys(":undojoin | redo\<CR>", 'xt')
+ call assert_equal('xxfirst line', getline(1))
+ call assert_equal('second line', getline(2))
+ bwipe!
+endfunc
+
+func Test_undo_write()
+ call delete('Xtest')
+ split Xtest
+ call feedkeys("ione one one\<Esc>", 'xt')
+ w!
+ call feedkeys("otwo\<Esc>", 'xt')
+ call feedkeys("otwo\<Esc>", 'xt')
+ w
+ call feedkeys("othree\<Esc>", 'xt')
+ call assert_equal(['one one one', 'two', 'two', 'three'], getline(1, '$'))
+ earlier 1f
+ call assert_equal(['one one one', 'two', 'two'], getline(1, '$'))
+ earlier 1f
+ call assert_equal(['one one one'], getline(1, '$'))
+ earlier 1f
+ call assert_equal([''], getline(1, '$'))
+ later 1f
+ call assert_equal(['one one one'], getline(1, '$'))
+ later 1f
+ call assert_equal(['one one one', 'two', 'two'], getline(1, '$'))
+ later 1f
+ call assert_equal(['one one one', 'two', 'two', 'three'], getline(1, '$'))
+
+ close!
+ call delete('Xtest')
+ bwipe! Xtest
+endfunc
+
+func Test_insert_expr()
+ new
+ " calling setline() triggers undo sync
+ call feedkeys("oa\<Esc>", 'xt')
+ call feedkeys("ob\<Esc>", 'xt')
+ set ul=100
+ call feedkeys("o1\<Esc>a2\<C-R>=setline('.','1234')\<CR>\<CR>\<Esc>", 'x')
+ call assert_equal(['a', 'b', '120', '34'], getline(2, '$'))
+ call feedkeys("u", 'x')
+ call assert_equal(['a', 'b', '12'], getline(2, '$'))
+ call feedkeys("u", 'x')
+ call assert_equal(['a', 'b'], getline(2, '$'))
+
+ call feedkeys("oc\<Esc>", 'xt')
+ set ul=100
+ call feedkeys("o1\<Esc>a2\<C-R>=setline('.','1234')\<CR>\<CR>\<Esc>", 'x')
+ call assert_equal(['a', 'b', 'c', '120', '34'], getline(2, '$'))
+ call feedkeys("u", 'x')
+ call assert_equal(['a', 'b', 'c', '12'], getline(2, '$'))
+
+ call feedkeys("od\<Esc>", 'xt')
+ set ul=100
+ call feedkeys("o1\<Esc>a2\<C-R>=string(123)\<CR>\<Esc>", 'x')
+ call assert_equal(['a', 'b', 'c', '12', 'd', '12123'], getline(2, '$'))
+ call feedkeys("u", 'x')
+ call assert_equal(['a', 'b', 'c', '12', 'd'], getline(2, '$'))
+
+ close!
+endfunc
+
+func Test_undofile_earlier()
+ " Issue #1254
+ " create undofile with timestamps older than Vim startup time.
+ let t0 = localtime() - 43200
+ call test_settime(t0)
+ new Xfile
+ call feedkeys("ione\<Esc>", 'xt')
+ set ul=100
+ call test_settime(t0 + 1)
+ call feedkeys("otwo\<Esc>", 'xt')
+ set ul=100
+ call test_settime(t0 + 2)
+ call feedkeys("othree\<Esc>", 'xt')
+ set ul=100
+ w
+ wundo Xundofile
+ bwipe!
+ " restore normal timestamps.
+ call test_settime(0)
+ new Xfile
+ rundo Xundofile
+ earlier 1d
+ call assert_equal('', getline(1))
+ bwipe!
+ call delete('Xfile')
+ call delete('Xundofile')
+endfunc
+
+" Test for undo working properly when executing commands from a register.
+" Also test this in an empty buffer.
+func Test_cmd_in_reg_undo()
+ enew!
+ let @a = "Ox\<Esc>jAy\<Esc>kdd"
+ edit +/^$ test_undo.vim
+ normal @au
+ call assert_equal(0, &modified)
+ return
+ new
+ normal @au
+ call assert_equal(0, &modified)
+ only!
+ let @a = ''
+endfunc
+
+" This used to cause an illegal memory access
+func Test_undo_append()
+ new
+ call feedkeys("axx\<Esc>v", 'xt')
+ undo
+ norm o
+ quit
+endfunc
+
+func Test_undo_0()
+ new
+ set ul=100
+ normal i1
+ undo
+ normal i2
+ undo
+ normal i3
+
+ undo 0
+ let d = undotree()
+ call assert_equal('', getline(1))
+ call assert_equal(0, d.seq_cur)
+
+ redo
+ let d = undotree()
+ call assert_equal('3', getline(1))
+ call assert_equal(3, d.seq_cur)
+
+ undo 2
+ undo 0
+ let d = undotree()
+ call assert_equal('', getline(1))
+ call assert_equal(0, d.seq_cur)
+
+ redo
+ let d = undotree()
+ call assert_equal('2', getline(1))
+ call assert_equal(2, d.seq_cur)
+
+ undo 1
+ undo 0
+ let d = undotree()
+ call assert_equal('', getline(1))
+ call assert_equal(0, d.seq_cur)
+
+ redo
+ let d = undotree()
+ call assert_equal('1', getline(1))
+ call assert_equal(1, d.seq_cur)
+
+ bwipe!
+endfunc
+
+func Test_redo_empty_line()
+ new
+ exe "norm\x16r\x160"
+ exe "norm."
+ bwipe!
+endfunc
+
+funct Test_undofile()
+ " Test undofile() without setting 'undodir'.
+ if has('persistent_undo')
+ call assert_equal(fnamemodify('.Xundofoo.un~', ':p'), undofile('Xundofoo'))
+ else
+ call assert_equal('', undofile('Xundofoo'))
+ endif
+ call assert_equal('', undofile(''))
+
+ " Test undofile() with 'undodir' set to to an existing directory.
+ call mkdir('Xundodir')
+ set undodir=Xundodir
+ let cwd = getcwd()
+ if has('win32')
+ " Replace windows drive such as C:... into C%...
+ let cwd = substitute(cwd, '^\([a-zA-Z]\):', '\1%', 'g')
+ endif
+ let cwd = substitute(cwd . '/Xundofoo', '/', '%', 'g')
+ if has('persistent_undo')
+ call assert_equal('Xundodir/' . cwd, undofile('Xundofoo'))
+ else
+ call assert_equal('', undofile('Xundofoo'))
+ endif
+ call assert_equal('', undofile(''))
+ call delete('Xundodir', 'd')
+
+ " Test undofile() with 'undodir' set to a non-existing directory.
+ call assert_equal('', undofile('Xundofoo'))
+
+ set undodir&
+endfunc
diff --git a/src/testdir/test_unlet.vim b/src/testdir/test_unlet.vim
new file mode 100644
index 0000000..0a9f3c6
--- /dev/null
+++ b/src/testdir/test_unlet.vim
@@ -0,0 +1,57 @@
+" Tests for :unlet
+
+func Test_read_only()
+ " these caused a crash
+ call assert_fails('unlet count', 'E795:')
+ call assert_fails('unlet errmsg', 'E795:')
+endfunc
+
+func Test_existing()
+ let does_exist = 1
+ call assert_true(exists('does_exist'))
+ unlet does_exist
+ call assert_false(exists('does_exist'))
+endfunc
+
+func Test_not_existing()
+ unlet! does_not_exist
+ call assert_fails('unlet does_not_exist', 'E108:')
+endfunc
+
+func Test_unlet_fails()
+ call assert_fails('unlet v:["count"]', 'E46:')
+endfunc
+
+func Test_unlet_env()
+ let envcmd = has('win32') ? 'set' : 'env'
+
+ let $FOOBAR = 'test'
+ let found = 0
+ for kv in split(system(envcmd), "\r*\n")
+ if kv == 'FOOBAR=test'
+ let found = 1
+ endif
+ endfor
+ call assert_equal(1, found)
+
+ unlet $FOOBAR
+ let found = 0
+ for kv in split(system(envcmd), "\r*\n")
+ if kv == 'FOOBAR=test'
+ let found = 1
+ endif
+ endfor
+ call assert_equal(0, found)
+
+ unlet $MUST_NOT_BE_AN_ERROR
+endfunc
+
+func Test_unlet_complete()
+ let g:FOOBAR = 1
+ call feedkeys(":unlet g:FOO\t\n", 'tx')
+ call assert_true(!exists('g:FOOBAR'))
+
+ let $FOOBAR = 1
+ call feedkeys(":unlet $FOO\t\n", 'tx')
+ call assert_true(!exists('$FOOBAR') || empty($FOOBAR))
+endfunc
diff --git a/src/testdir/test_user_func.vim b/src/testdir/test_user_func.vim
new file mode 100644
index 0000000..e7a3701
--- /dev/null
+++ b/src/testdir/test_user_func.vim
@@ -0,0 +1,96 @@
+" Test for user functions.
+" Also test an <expr> mapping calling a function.
+" Also test that a builtin function cannot be replaced.
+" Also test for regression when calling arbitrary expression.
+
+func Table(title, ...)
+ let ret = a:title
+ let idx = 1
+ while idx <= a:0
+ exe "let ret = ret . a:" . idx
+ let idx = idx + 1
+ endwhile
+ return ret
+endfunc
+
+func Compute(n1, n2, divname)
+ if a:n2 == 0
+ return "fail"
+ endif
+ exe "let g:" . a:divname . " = ". a:n1 / a:n2
+ return "ok"
+endfunc
+
+func Expr1()
+ silent! normal! v
+ return "111"
+endfunc
+
+func Expr2()
+ call search('XX', 'b')
+ return "222"
+endfunc
+
+func ListItem()
+ let g:counter += 1
+ return g:counter . '. '
+endfunc
+
+func ListReset()
+ let g:counter = 0
+ return ''
+endfunc
+
+func FuncWithRef(a)
+ unlet g:FuncRef
+ return a:a
+endfunc
+
+func Test_user_func()
+ let g:FuncRef=function("FuncWithRef")
+ let g:counter = 0
+ inoremap <expr> ( ListItem()
+ inoremap <expr> [ ListReset()
+ imap <expr> + Expr1()
+ imap <expr> * Expr2()
+ let g:retval = "nop"
+
+ call assert_equal('xxx4asdf', Table("xxx", 4, "asdf"))
+ call assert_equal('fail', Compute(45, 0, "retval"))
+ call assert_equal('nop', g:retval)
+ call assert_equal('ok', Compute(45, 5, "retval"))
+ call assert_equal(9, g:retval)
+ call assert_equal(333, g:FuncRef(333))
+
+ enew
+
+ normal oXX+-XX
+ call assert_equal('XX111-XX', getline('.'))
+ normal o---*---
+ call assert_equal('---222---', getline('.'))
+ normal o(one
+ call assert_equal('1. one', getline('.'))
+ normal o(two
+ call assert_equal('2. two', getline('.'))
+ normal o[(one again
+ call assert_equal('1. one again', getline('.'))
+
+ call assert_equal(3, max([1, 2, 3]))
+ call assert_fails("call extend(g:, {'max': function('min')})", 'E704')
+ call assert_equal(3, max([1, 2, 3]))
+
+ " Regression: the first line below used to throw ?E110: Missing ')'?
+ " Second is here just to prove that this line is correct when not skipping
+ " rhs of &&.
+ call assert_equal(0, (0 && (function('tr'))(1, 2, 3)))
+ call assert_equal(1, (1 && (function('tr'))(1, 2, 3)))
+
+ delfunc Table
+ delfunc Compute
+ delfunc Expr1
+ delfunc Expr2
+ delfunc ListItem
+ delfunc ListReset
+ unlet g:retval g:counter
+ enew!
+endfunc
diff --git a/src/testdir/test_usercommands.vim b/src/testdir/test_usercommands.vim
new file mode 100644
index 0000000..06b0a67
--- /dev/null
+++ b/src/testdir/test_usercommands.vim
@@ -0,0 +1,306 @@
+" Tests for user defined commands
+
+" Test for <mods> in user defined commands
+function Test_cmdmods()
+ let g:mods = ''
+
+ command! -nargs=* MyCmd let g:mods .= '<mods> '
+
+ MyCmd
+ aboveleft MyCmd
+ abo MyCmd
+ belowright MyCmd
+ bel MyCmd
+ botright MyCmd
+ bo MyCmd
+ browse MyCmd
+ bro MyCmd
+ confirm MyCmd
+ conf MyCmd
+ hide MyCmd
+ hid MyCmd
+ keepalt MyCmd
+ keepa MyCmd
+ keepjumps MyCmd
+ keepj MyCmd
+ keepmarks MyCmd
+ kee MyCmd
+ keeppatterns MyCmd
+ keepp MyCmd
+ leftabove MyCmd " results in :aboveleft
+ lefta MyCmd
+ lockmarks MyCmd
+ loc MyCmd
+ " noautocmd MyCmd
+ noswapfile MyCmd
+ nos MyCmd
+ rightbelow MyCmd " results in :belowright
+ rightb MyCmd
+ " sandbox MyCmd
+ silent MyCmd
+ sil MyCmd
+ tab MyCmd
+ topleft MyCmd
+ to MyCmd
+ " unsilent MyCmd
+ verbose MyCmd
+ verb MyCmd
+ vertical MyCmd
+ vert MyCmd
+
+ aboveleft belowright botright browse confirm hide keepalt keepjumps
+ \ keepmarks keeppatterns lockmarks noswapfile silent tab
+ \ topleft verbose vertical MyCmd
+
+ call assert_equal(' aboveleft aboveleft belowright belowright botright ' .
+ \ 'botright browse browse confirm confirm hide hide ' .
+ \ 'keepalt keepalt keepjumps keepjumps keepmarks keepmarks ' .
+ \ 'keeppatterns keeppatterns aboveleft aboveleft lockmarks lockmarks noswapfile ' .
+ \ 'noswapfile belowright belowright silent silent tab topleft topleft verbose verbose ' .
+ \ 'vertical vertical ' .
+ \ 'aboveleft belowright botright browse confirm hide keepalt keepjumps ' .
+ \ 'keepmarks keeppatterns lockmarks noswapfile silent tab topleft ' .
+ \ 'verbose vertical ', g:mods)
+
+ let g:mods = ''
+ command! -nargs=* MyQCmd let g:mods .= '<q-mods> '
+
+ vertical MyQCmd
+ call assert_equal('"vertical" ', g:mods)
+
+ delcommand MyCmd
+ delcommand MyQCmd
+ unlet g:mods
+endfunction
+
+func Test_Ambiguous()
+ command Doit let g:didit = 'yes'
+ command Dothat let g:didthat = 'also'
+ call assert_fails('Do', 'E464:')
+ Doit
+ call assert_equal('yes', g:didit)
+ Dothat
+ call assert_equal('also', g:didthat)
+ unlet g:didit
+ unlet g:didthat
+
+ delcommand Doit
+ Do
+ call assert_equal('also', g:didthat)
+ delcommand Dothat
+endfunc
+
+func Test_redefine_on_reload()
+ call writefile(['command ExistingCommand echo "yes"'], 'Xcommandexists')
+ call assert_equal(0, exists(':ExistingCommand'))
+ source Xcommandexists
+ call assert_equal(2, exists(':ExistingCommand'))
+ " Redefining a command when reloading a script is OK.
+ source Xcommandexists
+ call assert_equal(2, exists(':ExistingCommand'))
+
+ " But redefining in another script is not OK.
+ call writefile(['command ExistingCommand echo "yes"'], 'Xcommandexists2')
+ call assert_fails('source Xcommandexists2', 'E174:')
+ call delete('Xcommandexists2')
+
+ " And defining twice in one script is not OK.
+ delcommand ExistingCommand
+ call assert_equal(0, exists(':ExistingCommand'))
+ call writefile([
+ \ 'command ExistingCommand echo "yes"',
+ \ 'command ExistingCommand echo "no"',
+ \ ], 'Xcommandexists')
+ call assert_fails('source Xcommandexists', 'E174:')
+ call assert_equal(2, exists(':ExistingCommand'))
+
+ call delete('Xcommandexists')
+ delcommand ExistingCommand
+endfunc
+
+func Test_CmdUndefined()
+ call assert_fails('Doit', 'E492:')
+ au CmdUndefined Doit :command Doit let g:didit = 'yes'
+ Doit
+ call assert_equal('yes', g:didit)
+ delcommand Doit
+
+ call assert_fails('Dothat', 'E492:')
+ au CmdUndefined * let g:didnot = 'yes'
+ call assert_fails('Dothat', 'E492:')
+ call assert_equal('yes', g:didnot)
+endfunc
+
+func Test_CmdErrors()
+ call assert_fails('com! docmd :', 'E183:')
+ call assert_fails('com! \<Tab> :', 'E182:')
+ call assert_fails('com! _ :', 'E182:')
+ call assert_fails('com! X :', 'E841:')
+ call assert_fails('com! - DoCmd :', 'E175:')
+ call assert_fails('com! -xxx DoCmd :', 'E181:')
+ call assert_fails('com! -addr DoCmd :', 'E179:')
+ call assert_fails('com! -complete DoCmd :', 'E179:')
+ call assert_fails('com! -complete=xxx DoCmd :', 'E180:')
+ call assert_fails('com! -complete=custom DoCmd :', 'E467:')
+ call assert_fails('com! -complete=customlist DoCmd :', 'E467:')
+ call assert_fails('com! -complete=behave,CustomComplete DoCmd :', 'E468:')
+ call assert_fails('com! -nargs=x DoCmd :', 'E176:')
+ call assert_fails('com! -count=1 -count=2 DoCmd :', 'E177:')
+ call assert_fails('com! -count=x DoCmd :', 'E178:')
+ call assert_fails('com! -range=x DoCmd :', 'E178:')
+
+ com! -nargs=0 DoCmd :
+ call assert_fails('DoCmd x', 'E488:')
+
+ com! -nargs=1 DoCmd :
+ call assert_fails('DoCmd', 'E471:')
+
+ com! -nargs=+ DoCmd :
+ call assert_fails('DoCmd', 'E471:')
+
+ call assert_fails('com DoCmd :', 'E174:')
+ comclear
+ call assert_fails('delcom DoCmd', 'E184:')
+endfunc
+
+func CustomComplete(A, L, P)
+ return "January\nFebruary\nMars\n"
+endfunc
+
+func CustomCompleteList(A, L, P)
+ return [ "Monday", "Tuesday", "Wednesday" ]
+endfunc
+
+func Test_CmdCompletion()
+ call feedkeys(":com -\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"com -addr bang bar buffer complete count nargs range register', @:)
+
+ call feedkeys(":com -nargs=0 -\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"com -nargs=0 -addr bang bar buffer complete count nargs range register', @:)
+
+ call feedkeys(":com -nargs=\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"com -nargs=* + 0 1 ?', @:)
+
+ call feedkeys(":com -addr=\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"com -addr=arguments buffers lines loaded_buffers other quickfix tabs windows', @:)
+
+ call feedkeys(":com -complete=co\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"com -complete=color command compiler', @:)
+
+ command! DoCmd1 :
+ command! DoCmd2 :
+ call feedkeys(":com \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"com DoCmd1 DoCmd2', @:)
+
+ call feedkeys(":DoC\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"DoCmd1 DoCmd2', @:)
+
+ call feedkeys(":delcom DoC\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"delcom DoCmd1 DoCmd2', @:)
+
+ delcom DoCmd1
+ call feedkeys(":delcom DoC\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"delcom DoCmd2', @:)
+
+ call feedkeys(":com DoC\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"com DoCmd2', @:)
+
+ delcom DoCmd2
+ call feedkeys(":delcom DoC\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"delcom DoC', @:)
+
+ call feedkeys(":com DoC\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"com DoC', @:)
+
+ com! -complete=behave DoCmd :
+ call feedkeys(":DoCmd \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"DoCmd mswin xterm', @:)
+
+ " This does not work. Why?
+ "call feedkeys(":DoCmd x\<C-A>\<C-B>\"\<CR>", 'tx')
+ "call assert_equal('"DoCmd xterm', @:)
+
+ com! -complete=custom,CustomComplete DoCmd :
+ call feedkeys(":DoCmd \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"DoCmd January February Mars', @:)
+
+ com! -complete=customlist,CustomCompleteList DoCmd :
+ call feedkeys(":DoCmd \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"DoCmd Monday Tuesday Wednesday', @:)
+
+ com! -complete=custom,CustomCompleteList DoCmd :
+ call assert_fails("call feedkeys(':DoCmd \<C-D>', 'tx')", 'E730:')
+
+ com! -complete=customlist,CustomComp DoCmd :
+ call assert_fails("call feedkeys(':DoCmd \<C-D>', 'tx')", 'E117:')
+endfunc
+
+func CallExecute(A, L, P)
+ " Drop first '\n'
+ return execute('echo "hi"')[1:]
+endfunc
+
+func Test_use_execute_in_completion()
+ command! -nargs=* -complete=custom,CallExecute DoExec :
+ call feedkeys(":DoExec \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"DoExec hi', @:)
+ delcommand DoExec
+endfunc
+
+func Test_addr_all()
+ command! -addr=lines DoSomething let g:a1 = <line1> | let g:a2 = <line2>
+ %DoSomething
+ call assert_equal(1, g:a1)
+ call assert_equal(line('$'), g:a2)
+
+ command! -addr=arguments DoSomething let g:a1 = <line1> | let g:a2 = <line2>
+ args one two three
+ %DoSomething
+ call assert_equal(1, g:a1)
+ call assert_equal(3, g:a2)
+
+ command! -addr=buffers DoSomething let g:a1 = <line1> | let g:a2 = <line2>
+ %DoSomething
+ for low in range(1, bufnr('$'))
+ if buflisted(low)
+ break
+ endif
+ endfor
+ call assert_equal(low, g:a1)
+ call assert_equal(bufnr('$'), g:a2)
+
+ command! -addr=loaded_buffers DoSomething let g:a1 = <line1> | let g:a2 = <line2>
+ %DoSomething
+ for low in range(1, bufnr('$'))
+ if bufloaded(low)
+ break
+ endif
+ endfor
+ call assert_equal(low, g:a1)
+ for up in range(bufnr('$'), 1, -1)
+ if bufloaded(up)
+ break
+ endif
+ endfor
+ call assert_equal(up, g:a2)
+
+ command! -addr=windows DoSomething let g:a1 = <line1> | let g:a2 = <line2>
+ new
+ %DoSomething
+ call assert_equal(1, g:a1)
+ call assert_equal(winnr('$'), g:a2)
+ bwipe
+
+ command! -addr=tabs DoSomething let g:a1 = <line1> | let g:a2 = <line2>
+ tabnew
+ %DoSomething
+ call assert_equal(1, g:a1)
+ call assert_equal(len(gettabinfo()), g:a2)
+ bwipe
+
+ command! -addr=other DoSomething echo 'nothing'
+ DoSomething
+ call assert_fails('%DoSomething')
+
+ delcommand DoSomething
+endfunc
diff --git a/src/testdir/test_utf8.vim b/src/testdir/test_utf8.vim
new file mode 100644
index 0000000..8a71f50
--- /dev/null
+++ b/src/testdir/test_utf8.vim
@@ -0,0 +1,62 @@
+" Tests for Unicode manipulations
+
+
+" Visual block Insert adjusts for multi-byte char
+func Test_visual_block_insert()
+ new
+ call setline(1, ["aaa", "ã‚ã‚ã‚", "bbb"])
+ exe ":norm! gg0l\<C-V>jjIx\<Esc>"
+ call assert_equal(['axaa', 'xã‚ã‚ã‚', 'bxbb'], getline(1, '$'))
+ bwipeout!
+endfunc
+
+" Test for built-in function strchars()
+func Test_strchars()
+ let inp = ["a", "ã‚ã„a", "A\u20dd", "A\u20dd\u20dd", "\u20dd"]
+ let exp = [[1, 1, 1], [3, 3, 3], [2, 2, 1], [3, 3, 1], [1, 1, 1]]
+ for i in range(len(inp))
+ call assert_equal(exp[i][0], strchars(inp[i]))
+ call assert_equal(exp[i][1], strchars(inp[i], 0))
+ call assert_equal(exp[i][2], strchars(inp[i], 1))
+ endfor
+endfunc
+
+" Test for customlist completion
+func CustomComplete1(lead, line, pos)
+ return ['ã‚', 'ã„']
+endfunc
+
+func CustomComplete2(lead, line, pos)
+ return ['ã‚ãŸã—', 'ã‚ãŸã¾', 'ã‚ãŸã‚Šã‚']
+endfunc
+
+func CustomComplete3(lead, line, pos)
+ return ['Nã“', 'Nã‚“', 'Nã¶']
+endfunc
+
+func Test_customlist_completion()
+ command -nargs=1 -complete=customlist,CustomComplete1 Test1 echo
+ call feedkeys(":Test1 \<C-L>\<C-B>\"\<CR>", 'itx')
+ call assert_equal('"Test1 ', getreg(':'))
+
+ command -nargs=1 -complete=customlist,CustomComplete2 Test2 echo
+ call feedkeys(":Test2 \<C-L>\<C-B>\"\<CR>", 'itx')
+ call assert_equal('"Test2 ã‚ãŸ', getreg(':'))
+
+ command -nargs=1 -complete=customlist,CustomComplete3 Test3 echo
+ call feedkeys(":Test3 \<C-L>\<C-B>\"\<CR>", 'itx')
+ call assert_equal('"Test3 N', getreg(':'))
+
+ call garbagecollect(1)
+endfunc
+
+" Yank one 3 byte character and check the mark columns.
+func Test_getvcol()
+ new
+ call setline(1, "x\u2500x")
+ normal 0lvy
+ call assert_equal(2, col("'["))
+ call assert_equal(4, col("']"))
+ call assert_equal(2, virtcol("'["))
+ call assert_equal(2, virtcol("']"))
+endfunc
diff --git a/src/testdir/test_utf8_comparisons.vim b/src/testdir/test_utf8_comparisons.vim
new file mode 100644
index 0000000..312925b
--- /dev/null
+++ b/src/testdir/test_utf8_comparisons.vim
@@ -0,0 +1,91 @@
+" Tests for case-insensitive UTF-8 comparisons (utf_strnicmp() in mbyte.c)
+" Also test "g~ap".
+
+func Ch(a, op, b, expected)
+ call assert_equal(eval(printf('"%s" %s "%s"', a:a, a:op, a:b)), a:expected,
+ \ printf('"%s" %s "%s" should return %d', a:a, a:op, a:b, a:expected))
+endfunc
+
+func Chk(a, b, result)
+ if a:result == 0
+ call Ch(a:a, '==?', a:b, 1)
+ call Ch(a:a, '!=?', a:b, 0)
+ call Ch(a:a, '<=?', a:b, 1)
+ call Ch(a:a, '>=?', a:b, 1)
+ call Ch(a:a, '<?', a:b, 0)
+ call Ch(a:a, '>?', a:b, 0)
+ elseif a:result > 0
+ call Ch(a:a, '==?', a:b, 0)
+ call Ch(a:a, '!=?', a:b, 1)
+ call Ch(a:a, '<=?', a:b, 0)
+ call Ch(a:a, '>=?', a:b, 1)
+ call Ch(a:a, '<?', a:b, 0)
+ call Ch(a:a, '>?', a:b, 1)
+ else
+ call Ch(a:a, '==?', a:b, 0)
+ call Ch(a:a, '!=?', a:b, 1)
+ call Ch(a:a, '<=?', a:b, 1)
+ call Ch(a:a, '>=?', a:b, 0)
+ call Ch(a:a, '<?', a:b, 1)
+ call Ch(a:a, '>?', a:b, 0)
+ endif
+endfunc
+
+func Check(a, b, result)
+ call Chk(a:a, a:b, a:result)
+ call Chk(a:b, a:a, -a:result)
+endfunc
+
+func LT(a, b)
+ call Check(a:a, a:b, -1)
+endfunc
+
+func GT(a, b)
+ call Check(a:a, a:b, 1)
+endfunc
+
+func EQ(a, b)
+ call Check(a:a, a:b, 0)
+endfunc
+
+func Test_comparisons()
+ call EQ('', '')
+ call LT('', 'a')
+ call EQ('abc', 'abc')
+ call EQ('Abc', 'abC')
+ call LT('ab', 'abc')
+ call LT('AB', 'abc')
+ call LT('ab', 'aBc')
+ call EQ('\xd0\xb9\xd1\x86\xd1\x83\xd0\xba\xd0\xb5\xd0\xbd', '\xd0\xb9\xd0\xa6\xd0\xa3\xd0\xba\xd0\x95\xd0\xbd')
+ call LT('\xd0\xb9\xd1\x86\xd1\x83\xd0\xba\xd0\xb5\xd0\xbd', '\xd0\xaf\xd1\x86\xd1\x83\xd0\xba\xd0\xb5\xd0\xbd')
+ call EQ('\xe2\x84\xaa', 'k')
+ call LT('\xe2\x84\xaa', 'kkkkkk')
+ call EQ('\xe2\x84\xaa\xe2\x84\xaa\xe2\x84\xaa', 'kkk')
+ call LT('kk', '\xe2\x84\xaa\xe2\x84\xaa\xe2\x84\xaa')
+ call EQ('\xe2\x84\xaa\xe2\x84\xa6k\xe2\x84\xaak\xcf\x89', 'k\xcf\x89\xe2\x84\xaakk\xe2\x84\xa6')
+ call EQ('Abc\x80', 'AbC\x80')
+ call LT('Abc\x80', 'AbC\x81')
+ call LT('Abc', 'AbC\x80')
+ call LT('abc\x80DEF', 'abc\x80def') " case folding stops at the first bad character
+ call LT('\xc3XYZ', '\xc3xyz')
+ call EQ('\xef\xbc\xba', '\xef\xbd\x9a') " FF3A (upper), FF5A (lower)
+ call GT('\xef\xbc\xba', '\xef\xbc\xff') " first string is ok and equals \xef\xbd\x9a after folding, second string is illegal and was left unchanged, then the strings were bytewise compared
+ call LT('\xc3', '\xc3\x83')
+ call EQ('\xc3\xa3xYz', '\xc3\x83XyZ')
+ for n in range(0x60, 0xFF)
+ call LT(printf('xYz\x%.2X', n-1), printf('XyZ\x%.2X', n))
+ endfor
+ for n in range(0x80, 0xBF)
+ call EQ(printf('xYz\xc2\x%.2XUvW', n), printf('XyZ\xc2\x%.2XuVw', n))
+ endfor
+ for n in range(0xC0, 0xFF)
+ call LT(printf('xYz\xc2\x%.2XUvW', n), printf('XyZ\xc2\x%.2XuVw', n))
+ endfor
+endfunc
+
+" test that g~ap changes one paragraph only.
+func Test_gap()
+ new
+ call feedkeys("iabcd\n\ndefggg0g~ap", "tx")
+ call assert_equal(["ABCD", "", "defg"], getline(1,3))
+endfunc
diff --git a/src/testdir/test_vartabs.vim b/src/testdir/test_vartabs.vim
new file mode 100644
index 0000000..0d14aad
--- /dev/null
+++ b/src/testdir/test_vartabs.vim
@@ -0,0 +1,374 @@
+" Test for variable tabstops
+
+if !has("vartabs")
+ finish
+endif
+
+source view_util.vim
+func s:compare_lines(expect, actual)
+ call assert_equal(join(a:expect, "\n"), join(a:actual, "\n"))
+endfunc
+
+func Test_vartabs()
+ new
+ %d
+
+ " Test normal operation of tabstops ...
+ set ts=4
+ call setline(1, join(split('aaaaa', '\zs'), "\t"))
+ retab 8
+ let expect = "a a\<tab>a a\<tab>a"
+ call assert_equal(expect, getline(1))
+
+ " ... and softtabstops
+ set ts=8 sts=6
+ exe "norm! Sb\<tab>b\<tab>b\<tab>b\<tab>b"
+ let expect = "b b\<tab> b\<tab> b\<tab>b"
+ call assert_equal(expect, getline(1))
+
+ " Test variable tabstops.
+ set sts=0 vts=4,8,4,8
+ exe "norm! Sc\<tab>c\<tab>c\<tab>c\<tab>c\<tab>c"
+ retab 8
+ let expect = "c c\<tab> c\<tab>c\<tab>c\<tab>c"
+ call assert_equal(expect, getline(1))
+
+ set et vts=4,8,4,8
+ exe "norm! Sd\<tab>d\<tab>d\<tab>d\<tab>d\<tab>d"
+ let expect = "d d d d d d"
+ call assert_equal(expect, getline(1))
+
+ " Changing ts should have no effect if vts is in use.
+ call cursor(1, 1)
+ set ts=6
+ exe "norm! Se\<tab>e\<tab>e\<tab>e\<tab>e\<tab>e"
+ let expect = "e e e e e e"
+ call assert_equal(expect, getline(1))
+
+ " Clearing vts should revert to using ts.
+ set vts=
+ exe "norm! Sf\<tab>f\<tab>f\<tab>f\<tab>f\<tab>f"
+ let expect = "f f f f f f"
+ call assert_equal(expect, getline(1))
+
+ " Test variable softtabstops.
+ set noet ts=8 vsts=12,2,6
+ exe "norm! Sg\<tab>g\<tab>g\<tab>g\<tab>g\<tab>g"
+ let expect = "g\<tab> g g\<tab> g\<tab> g\<tab>g"
+ call assert_equal(expect, getline(1))
+
+ " Variable tabstops and softtabstops combined.
+ set vsts=6,12,8 vts=4,6,8
+ exe "norm! Sh\<tab>h\<tab>h\<tab>h\<tab>h"
+ let expect = "h\<tab> h\<tab>\<tab>h\<tab>h\<tab>h"
+ call assert_equal(expect, getline(1))
+
+ " Retab with a single value, not using vts.
+ set ts=8 sts=0 vts= vsts=
+ exe "norm! Si\<tab>i\<tab>i\<tab>i\<tab>i"
+ retab 4
+ let expect = "i\<tab>\<tab>i\<tab>\<tab>i\<tab>\<tab>i\<tab>\<tab>i"
+ call assert_equal(expect, getline(1))
+
+ " Retab with a single value, using vts.
+ set ts=8 sts=0 vts=6 vsts=
+ exe "norm! Sj\<tab>j\<tab>j\<tab>j\<tab>j"
+ retab 4
+ let expect = "j\<tab> j\<tab>\<tab>j\<tab> j\<tab>\<tab>j"
+ call assert_equal(expect, getline(1))
+
+ " Retab with multiple values, not using vts.
+ set ts=6 sts=0 vts= vsts=
+ exe "norm! Sk\<tab>k\<tab>k\<tab>k\<tab>k\<tab>k"
+ retab 4,8
+ let expect = "k\<tab> k\<tab>k k\<tab> k\<tab> k"
+ call assert_equal(expect, getline(1))
+
+ " Retab with multiple values, using vts.
+ set ts=8 sts=0 vts=6 vsts=
+ exe "norm! Sl\<tab>l\<tab>l\<tab>l\<tab>l\<tab>l"
+ retab 4,8
+ let expect = "l\<tab> l\<tab>l l\<tab> l\<tab> l"
+ call assert_equal(expect, getline(1))
+
+ " Check that global and local values are set.
+ set ts=4 vts=6 sts=8 vsts=10
+ call assert_equal(&ts, 4)
+ call assert_equal(&vts, '6')
+ call assert_equal(&sts, 8)
+ call assert_equal(&vsts, '10')
+ new
+ call assert_equal(&ts, 4)
+ call assert_equal(&vts, '6')
+ call assert_equal(&sts, 8)
+ call assert_equal(&vsts, '10')
+ bwipeout!
+
+ " Check that local values only are set.
+ setlocal ts=5 vts=7 sts=9 vsts=11
+ call assert_equal(&ts, 5)
+ call assert_equal(&vts, '7')
+ call assert_equal(&sts, 9)
+ call assert_equal(&vsts, '11')
+ new
+ call assert_equal(&ts, 4)
+ call assert_equal(&vts, '6')
+ call assert_equal(&sts, 8)
+ call assert_equal(&vsts, '10')
+ bwipeout!
+
+ " Check that global values only are set.
+ setglobal ts=6 vts=8 sts=10 vsts=12
+ call assert_equal(&ts, 5)
+ call assert_equal(&vts, '7')
+ call assert_equal(&sts, 9)
+ call assert_equal(&vsts, '11')
+ new
+ call assert_equal(&ts, 6)
+ call assert_equal(&vts, '8')
+ call assert_equal(&sts, 10)
+ call assert_equal(&vsts, '12')
+ bwipeout!
+
+ set ts& vts& sts& vsts& et&
+ bwipeout!
+endfunc
+
+func Test_vartabs_breakindent()
+ if !exists("+breakindent")
+ return
+ endif
+ new
+ %d
+
+ " Test normal operation of tabstops ...
+ set ts=4
+ call setline(1, join(split('aaaaa', '\zs'), "\t"))
+ retab 8
+ let expect = "a a\<tab>a a\<tab>a"
+ call assert_equal(expect, getline(1))
+
+ " ... and softtabstops
+ set ts=8 sts=6
+ exe "norm! Sb\<tab>b\<tab>b\<tab>b\<tab>b"
+ let expect = "b b\<tab> b\<tab> b\<tab>b"
+ call assert_equal(expect, getline(1))
+
+ " Test variable tabstops.
+ set sts=0 vts=4,8,4,8
+ exe "norm! Sc\<tab>c\<tab>c\<tab>c\<tab>c\<tab>c"
+ retab 8
+ let expect = "c c\<tab> c\<tab>c\<tab>c\<tab>c"
+ call assert_equal(expect, getline(1))
+
+ set et vts=4,8,4,8
+ exe "norm! Sd\<tab>d\<tab>d\<tab>d\<tab>d\<tab>d"
+ let expect = "d d d d d d"
+ call assert_equal(expect, getline(1))
+
+ " Changing ts should have no effect if vts is in use.
+ call cursor(1, 1)
+ set ts=6
+ exe "norm! Se\<tab>e\<tab>e\<tab>e\<tab>e\<tab>e"
+ let expect = "e e e e e e"
+ call assert_equal(expect, getline(1))
+
+ " Clearing vts should revert to using ts.
+ set vts=
+ exe "norm! Sf\<tab>f\<tab>f\<tab>f\<tab>f\<tab>f"
+ let expect = "f f f f f f"
+ call assert_equal(expect, getline(1))
+
+ " Test variable softtabstops.
+ set noet ts=8 vsts=12,2,6
+ exe "norm! Sg\<tab>g\<tab>g\<tab>g\<tab>g\<tab>g"
+ let expect = "g\<tab> g g\<tab> g\<tab> g\<tab>g"
+ call assert_equal(expect, getline(1))
+
+ " Variable tabstops and softtabstops combined.
+ set vsts=6,12,8 vts=4,6,8
+ exe "norm! Sh\<tab>h\<tab>h\<tab>h\<tab>h"
+ let expect = "h\<tab> h\<tab>\<tab>h\<tab>h\<tab>h"
+ call assert_equal(expect, getline(1))
+
+ " Retab with a single value, not using vts.
+ set ts=8 sts=0 vts= vsts=
+ exe "norm! Si\<tab>i\<tab>i\<tab>i\<tab>i"
+ retab 4
+ let expect = "i\<tab>\<tab>i\<tab>\<tab>i\<tab>\<tab>i\<tab>\<tab>i"
+ call assert_equal(expect, getline(1))
+
+ " Retab with a single value, using vts.
+ set ts=8 sts=0 vts=6 vsts=
+ exe "norm! Sj\<tab>j\<tab>j\<tab>j\<tab>j"
+ retab 4
+ let expect = "j\<tab> j\<tab>\<tab>j\<tab> j\<tab>\<tab>j"
+ call assert_equal(expect, getline(1))
+
+ " Retab with multiple values, not using vts.
+ set ts=6 sts=0 vts= vsts=
+ exe "norm! Sk\<tab>k\<tab>k\<tab>k\<tab>k\<tab>k"
+ retab 4,8
+ let expect = "k\<tab> k\<tab>k k\<tab> k\<tab> k"
+ call assert_equal(expect, getline(1))
+
+ " Retab with multiple values, using vts.
+ set ts=8 sts=0 vts=6 vsts=
+ exe "norm! Sl\<tab>l\<tab>l\<tab>l\<tab>l\<tab>l"
+ retab 4,8
+ let expect = "l\<tab> l\<tab>l l\<tab> l\<tab> l"
+ call assert_equal(expect, getline(1))
+
+ " Check that global and local values are set.
+ set ts=4 vts=6 sts=8 vsts=10
+ call assert_equal(&ts, 4)
+ call assert_equal(&vts, '6')
+ call assert_equal(&sts, 8)
+ call assert_equal(&vsts, '10')
+ new
+ call assert_equal(&ts, 4)
+ call assert_equal(&vts, '6')
+ call assert_equal(&sts, 8)
+ call assert_equal(&vsts, '10')
+ bwipeout!
+
+ " Check that local values only are set.
+ setlocal ts=5 vts=7 sts=9 vsts=11
+ call assert_equal(&ts, 5)
+ call assert_equal(&vts, '7')
+ call assert_equal(&sts, 9)
+ call assert_equal(&vsts, '11')
+ new
+ call assert_equal(&ts, 4)
+ call assert_equal(&vts, '6')
+ call assert_equal(&sts, 8)
+ call assert_equal(&vsts, '10')
+ bwipeout!
+
+ " Check that global values only are set.
+ setglobal ts=6 vts=8 sts=10 vsts=12
+ call assert_equal(&ts, 5)
+ call assert_equal(&vts, '7')
+ call assert_equal(&sts, 9)
+ call assert_equal(&vsts, '11')
+ new
+ call assert_equal(&ts, 6)
+ call assert_equal(&vts, '8')
+ call assert_equal(&sts, 10)
+ call assert_equal(&vsts, '12')
+ bwipeout!
+
+ bwipeout!
+endfunc
+
+func Test_vartabs_linebreak()
+ if winwidth(0) < 40
+ return
+ endif
+ new
+ 40vnew
+ %d
+ setl linebreak vartabstop=10,20,30,40
+ call setline(1, "\tx\tx\tx\tx")
+
+ let expect = [' x ',
+ \ 'x x ',
+ \ 'x ']
+ let lines = ScreenLines([1, 3], winwidth(0))
+ call s:compare_lines(expect, lines)
+ setl list listchars=tab:>-
+ let expect = ['>---------x>------------------ ',
+ \ 'x>------------------x>------------------',
+ \ 'x ']
+ let lines = ScreenLines([1, 3], winwidth(0))
+ call s:compare_lines(expect, lines)
+ setl linebreak vartabstop=40
+ let expect = ['>---------------------------------------',
+ \ 'x>--------------------------------------',
+ \ 'x>--------------------------------------',
+ \ 'x>--------------------------------------',
+ \ 'x ']
+ let lines = ScreenLines([1, 5], winwidth(0))
+ call s:compare_lines(expect, lines)
+
+ " cleanup
+ bw!
+ bw!
+ set nolist listchars&vim
+endfunc
+
+func Test_vartabs_shiftwidth()
+ "return
+ if winwidth(0) < 40
+ return
+ endif
+ new
+ 40vnew
+ %d
+" setl varsofttabstop=10,20,30,40
+ setl shiftwidth=0 vartabstop=10,20,30,40
+ call setline(1, "x")
+
+ " Check without any change.
+ let expect = ['x ']
+ let lines = ScreenLines(1, winwidth(0))
+ call s:compare_lines(expect, lines)
+ " Test 1:
+ " shiftwidth depends on the indent, first check with cursor at the end of the
+ " line (which is the same as the start of the line, since there is only one
+ " character).
+ norm! $>>
+ let expect1 = [' x ']
+ let lines = ScreenLines(1, winwidth(0))
+ call s:compare_lines(expect1, lines)
+ call assert_equal(10, shiftwidth())
+ call assert_equal(10, shiftwidth(1))
+ call assert_equal(20, shiftwidth(virtcol('.')))
+ norm! $>>
+ let expect2 = [' x ', '~ ']
+ let lines = ScreenLines([1, 2], winwidth(0))
+ call s:compare_lines(expect2, lines)
+ call assert_equal(20, shiftwidth(virtcol('.')-2))
+ call assert_equal(30, shiftwidth(virtcol('.')))
+ norm! $>>
+ let expect3 = [' ', ' x ', '~ ']
+ let lines = ScreenLines([1, 3], winwidth(0))
+ call s:compare_lines(expect3, lines)
+ call assert_equal(30, shiftwidth(virtcol('.')-2))
+ call assert_equal(40, shiftwidth(virtcol('.')))
+ norm! $>>
+ let expect4 = [' ', ' ', ' x ']
+ let lines = ScreenLines([1, 3], winwidth(0))
+ call assert_equal(40, shiftwidth(virtcol('.')))
+ call s:compare_lines(expect4, lines)
+
+ " Test 2: Put the cursor at the first column, result should be the same
+ call setline(1, "x")
+ norm! 0>>
+ let lines = ScreenLines(1, winwidth(0))
+ call s:compare_lines(expect1, lines)
+ norm! 0>>
+ let lines = ScreenLines([1, 2], winwidth(0))
+ call s:compare_lines(expect2, lines)
+ norm! 0>>
+ let lines = ScreenLines([1, 3], winwidth(0))
+ call s:compare_lines(expect3, lines)
+ norm! 0>>
+ let lines = ScreenLines([1, 3], winwidth(0))
+ call s:compare_lines(expect4, lines)
+
+ " cleanup
+ bw!
+ bw!
+endfunc
+
+func Test_vartabs_failures()
+ call assert_fails('set vts=8,')
+ call assert_fails('set vsts=8,')
+ call assert_fails('set vts=8,,8')
+ call assert_fails('set vsts=8,,8')
+ call assert_fails('set vts=8,,8,')
+ call assert_fails('set vsts=8,,8,')
+ call assert_fails('set vts=,8')
+ call assert_fails('set vsts=,8')
+endfunc
diff --git a/src/testdir/test_viminfo.vim b/src/testdir/test_viminfo.vim
new file mode 100644
index 0000000..cea78e5
--- /dev/null
+++ b/src/testdir/test_viminfo.vim
@@ -0,0 +1,534 @@
+" Test for reading and writing .viminfo
+
+function Test_viminfo_read_and_write()
+ call histdel(':')
+ let lines = [
+ \ '# comment line',
+ \ '*encoding=utf-8',
+ \ '~MSle0~/asdf',
+ \ '|copied as-is',
+ \ '|and one more',
+ \ ]
+ call writefile(lines, 'Xviminfo')
+ rviminfo Xviminfo
+ call assert_equal('asdf', @/)
+
+ wviminfo Xviminfo
+ let lines = readfile('Xviminfo')
+ let done = 0
+ for line in lines
+ if line[0] == '|' && line !~ '^|[234],' && line !~ '^|<'
+ if done == 0
+ call assert_equal('|1,4', line)
+ elseif done == 1
+ call assert_equal('|copied as-is', line)
+ elseif done == 2
+ call assert_equal('|and one more', line)
+ endif
+ let done += 1
+ endif
+ endfor
+ call assert_equal(3, done)
+
+ call delete('Xviminfo')
+endfunc
+
+func Test_global_vars()
+ let test_dict = {'foo': 1, 'bar': 0, 'longvarible': 1000}
+ let g:MY_GLOBAL_DICT = test_dict
+ " store a really long list, so line wrapping will occur in viminfo file
+ let test_list = range(1,100)
+ let g:MY_GLOBAL_LIST = test_list
+ let test_blob = 0z00112233445566778899aabbccddeeff
+ let g:MY_GLOBAL_BLOB = test_blob
+ let test_false = v:false
+ let g:MY_GLOBAL_FALSE = test_false
+ let test_true = v:true
+ let g:MY_GLOBAL_TRUE = test_true
+ let test_null = v:null
+ let g:MY_GLOBAL_NULL = test_null
+ let test_none = v:none
+ let g:MY_GLOBAL_NONE = test_none
+
+ set viminfo='100,<50,s10,h,!,nviminfo
+ wv! Xviminfo
+
+ unlet g:MY_GLOBAL_DICT
+ unlet g:MY_GLOBAL_LIST
+ unlet g:MY_GLOBAL_BLOB
+ unlet g:MY_GLOBAL_FALSE
+ unlet g:MY_GLOBAL_TRUE
+ unlet g:MY_GLOBAL_NULL
+ unlet g:MY_GLOBAL_NONE
+
+ rv! Xviminfo
+ call assert_equal(test_dict, g:MY_GLOBAL_DICT)
+ call assert_equal(test_list, g:MY_GLOBAL_LIST)
+ call assert_equal(test_blob, g:MY_GLOBAL_BLOB)
+ call assert_equal(test_false, g:MY_GLOBAL_FALSE)
+ call assert_equal(test_true, g:MY_GLOBAL_TRUE)
+ call assert_equal(test_null, g:MY_GLOBAL_NULL)
+ call assert_equal(test_none, g:MY_GLOBAL_NONE)
+
+ call delete('Xviminfo')
+ set viminfo-=!
+endfunc
+
+func Test_cmdline_history()
+ call histdel(':')
+ call test_settime(11)
+ call histadd(':', "echo 'one'")
+ call test_settime(12)
+ " split into two lines
+ let long800 = repeat(" 'eight'", 100)
+ call histadd(':', "echo " . long800)
+ call test_settime(13)
+ " split into three lines
+ let long1400 = repeat(" 'fourteeeeen'", 100)
+ call histadd(':', "echo " . long1400)
+ wviminfo Xviminfo
+ let lines = readfile('Xviminfo')
+ let done_colon = 0
+ let done_bar = 0
+ let lnum = 0
+ while lnum < len(lines)
+ let line = lines[lnum] | let lnum += 1
+ if line[0] == ':'
+ if done_colon == 0
+ call assert_equal(":\x161408", line)
+ let line = lines[lnum] | let lnum += 1
+ call assert_equal('<echo ' . long1400, line)
+ elseif done_colon == 1
+ call assert_equal(":\x16808", line)
+ let line = lines[lnum] | let lnum += 1
+ call assert_equal("<echo " . long800, line)
+ elseif done_colon == 2
+ call assert_equal(":echo 'one'", line)
+ endif
+ let done_colon += 1
+ elseif line[0:4] == '|2,0,'
+ if done_bar == 0
+ call assert_equal("|2,0,13,,>1407", line)
+ let line = lines[lnum] | let lnum += 1
+ call assert_equal('|<"echo ' . long1400[0:484], line)
+ let line = lines[lnum] | let lnum += 1
+ call assert_equal('|<' . long1400[485:974], line)
+ let line = lines[lnum] | let lnum += 1
+ call assert_equal('|<' . long1400[975:] . '"', line)
+ elseif done_bar == 1
+ call assert_equal('|2,0,12,,>807', line)
+ let line = lines[lnum] | let lnum += 1
+ call assert_equal('|<"echo ' . long800[0:484], line)
+ let line = lines[lnum] | let lnum += 1
+ call assert_equal('|<' . long800[485:] . '"', line)
+ elseif done_bar == 2
+ call assert_equal("|2,0,11,,\"echo 'one'\"", line)
+ endif
+ let done_bar += 1
+ endif
+ endwhile
+ call assert_equal(3, done_colon)
+ call assert_equal(3, done_bar)
+
+ call histdel(':')
+ rviminfo Xviminfo
+ call assert_equal("echo " . long1400, histget(':', -1))
+ call assert_equal("echo " . long800, histget(':', -2))
+ call assert_equal("echo 'one'", histget(':', -3))
+
+ call delete('Xviminfo')
+endfunc
+
+func Test_cmdline_history_order()
+ call histdel(':')
+ call test_settime(11)
+ call histadd(':', "echo '11'")
+ call test_settime(22)
+ call histadd(':', "echo '22'")
+ call test_settime(33)
+ call histadd(':', "echo '33'")
+ wviminfo Xviminfo
+
+ call histdel(':')
+ " items go in between
+ call test_settime(15)
+ call histadd(':', "echo '15'")
+ call test_settime(27)
+ call histadd(':', "echo '27'")
+
+ rviminfo Xviminfo
+ call assert_equal("echo '33'", histget(':', -1))
+ call assert_equal("echo '27'", histget(':', -2))
+ call assert_equal("echo '22'", histget(':', -3))
+ call assert_equal("echo '15'", histget(':', -4))
+ call assert_equal("echo '11'", histget(':', -5))
+
+ call histdel(':')
+ " items go before and after
+ call test_settime(8)
+ call histadd(':', "echo '8'")
+ call test_settime(39)
+ call histadd(':', "echo '39'")
+
+ rviminfo Xviminfo
+ call assert_equal("echo '39'", histget(':', -1))
+ call assert_equal("echo '33'", histget(':', -2))
+ call assert_equal("echo '22'", histget(':', -3))
+ call assert_equal("echo '11'", histget(':', -4))
+ call assert_equal("echo '8'", histget(':', -5))
+
+ " Check sorting works when writing with merge.
+ call histdel(':')
+ call test_settime(8)
+ call histadd(':', "echo '8'")
+ call test_settime(15)
+ call histadd(':', "echo '15'")
+ call test_settime(27)
+ call histadd(':', "echo '27'")
+ call test_settime(39)
+ call histadd(':', "echo '39'")
+ wviminfo Xviminfo
+
+ call histdel(':')
+ rviminfo Xviminfo
+ call assert_equal("echo '39'", histget(':', -1))
+ call assert_equal("echo '33'", histget(':', -2))
+ call assert_equal("echo '27'", histget(':', -3))
+ call assert_equal("echo '22'", histget(':', -4))
+ call assert_equal("echo '15'", histget(':', -5))
+ call assert_equal("echo '11'", histget(':', -6))
+ call assert_equal("echo '8'", histget(':', -7))
+
+ call delete('Xviminfo')
+endfunc
+
+func Test_viminfo_registers()
+ call test_settime(8)
+ call setreg('a', "eight", 'c')
+ call test_settime(20)
+ call setreg('b', ["twenty", "again"], 'l')
+ call test_settime(40)
+ call setreg('c', ["four", "agai"], 'b4')
+ let l = []
+ set viminfo='100,<600,s10,h,!,nviminfo
+ for i in range(500)
+ call add(l, 'something')
+ endfor
+ call setreg('d', l, 'l')
+ wviminfo Xviminfo
+
+ call test_settime(10)
+ call setreg('a', '', 'b10')
+ call test_settime(15)
+ call setreg('b', 'drop')
+ call test_settime(50)
+ call setreg('c', 'keep', 'l')
+ call test_settime(30)
+ call setreg('d', 'drop', 'l')
+ rviminfo Xviminfo
+
+ call assert_equal("", getreg('a'))
+ call assert_equal("\<C-V>10", getregtype('a'))
+ call assert_equal("twenty\nagain\n", getreg('b'))
+ call assert_equal("V", getregtype('b'))
+ call assert_equal("keep\n", getreg('c'))
+ call assert_equal("V", getregtype('c'))
+ call assert_equal(l, getreg('d', 1, 1))
+ call assert_equal("V", getregtype('d'))
+
+ " Length around 440 switches to line continuation.
+ let len = 434
+ while len < 445
+ let s = repeat('a', len)
+ call setreg('"', s)
+ wviminfo Xviminfo
+ call setreg('"', '')
+ rviminfo Xviminfo
+ call assert_equal(s, getreg('"'), 'wrong register at length: ' . len)
+
+ let len += 1
+ endwhile
+
+ call delete('Xviminfo')
+endfunc
+
+func Test_viminfo_marks()
+ sp bufa
+ let bufa = bufnr('%')
+ sp bufb
+ let bufb = bufnr('%')
+
+ call test_settime(8)
+ call setpos("'A", [bufa, 1, 1, 0])
+ call test_settime(20)
+ call setpos("'B", [bufb, 9, 1, 0])
+ call setpos("'C", [bufa, 7, 1, 0])
+
+ delmark 0-9
+ call test_settime(25)
+ call setpos("'1", [bufb, 12, 1, 0])
+ call test_settime(35)
+ call setpos("'0", [bufa, 11, 1, 0])
+
+ call test_settime(45)
+ wviminfo Xviminfo
+
+ " Writing viminfo inserts the '0 mark.
+ call assert_equal([bufb, 1, 1, 0], getpos("'0"))
+ call assert_equal([bufa, 11, 1, 0], getpos("'1"))
+ call assert_equal([bufb, 12, 1, 0], getpos("'2"))
+
+ call test_settime(4)
+ call setpos("'A", [bufa, 9, 1, 0])
+ call test_settime(30)
+ call setpos("'B", [bufb, 2, 3, 0])
+ delmark C
+
+ delmark 0-9
+ call test_settime(30)
+ call setpos("'1", [bufb, 22, 1, 0])
+ call test_settime(55)
+ call setpos("'0", [bufa, 21, 1, 0])
+
+ rviminfo Xviminfo
+
+ call assert_equal([bufa, 1, 1, 0], getpos("'A"))
+ call assert_equal([bufb, 2, 3, 0], getpos("'B"))
+ call assert_equal([bufa, 7, 1, 0], getpos("'C"))
+
+ " numbered marks are merged
+ call assert_equal([bufa, 21, 1, 0], getpos("'0")) " time 55
+ call assert_equal([bufb, 1, 1, 0], getpos("'1")) " time 45
+ call assert_equal([bufa, 11, 1, 0], getpos("'2")) " time 35
+ call assert_equal([bufb, 22, 1, 0], getpos("'3")) " time 30
+ call assert_equal([bufb, 12, 1, 0], getpos("'4")) " time 25
+
+ call delete('Xviminfo')
+ exe 'bwipe ' . bufa
+ exe 'bwipe ' . bufb
+endfunc
+
+func Test_viminfo_jumplist()
+ split testbuf
+ clearjumps
+ call setline(1, ['time 05', 'time 10', 'time 15', 'time 20', 'time 30', 'last pos'])
+ call cursor(2, 1)
+ call test_settime(10)
+ exe "normal /20\r"
+ call test_settime(20)
+ exe "normal /30\r"
+ call test_settime(30)
+ exe "normal /last pos\r"
+ wviminfo Xviminfo
+
+ clearjumps
+ call cursor(1, 1)
+ call test_settime(5)
+ exe "normal /15\r"
+ call test_settime(15)
+ exe "normal /last pos\r"
+ call test_settime(40)
+ exe "normal ?30\r"
+ rviminfo Xviminfo
+
+ call assert_equal('time 30', getline('.'))
+ exe "normal \<C-O>"
+ call assert_equal('last pos', getline('.'))
+ exe "normal \<C-O>"
+ " duplicate for 'time 30' was removed
+ call assert_equal('time 20', getline('.'))
+ exe "normal \<C-O>"
+ call assert_equal('time 15', getline('.'))
+ exe "normal \<C-O>"
+ call assert_equal('time 10', getline('.'))
+ exe "normal \<C-O>"
+ call assert_equal('time 05', getline('.'))
+
+ clearjumps
+ call cursor(1, 1)
+ call test_settime(5)
+ exe "normal /15\r"
+ call test_settime(15)
+ exe "normal /last pos\r"
+ call test_settime(40)
+ exe "normal ?30\r"
+ " Test merge when writing
+ wviminfo Xviminfo
+ clearjumps
+ rviminfo Xviminfo
+
+ let last_line = line('.')
+ exe "normal \<C-O>"
+ call assert_equal('time 30', getline('.'))
+ exe "normal \<C-O>"
+ call assert_equal('last pos', getline('.'))
+ exe "normal \<C-O>"
+ " duplicate for 'time 30' was removed
+ call assert_equal('time 20', getline('.'))
+ exe "normal \<C-O>"
+ call assert_equal('time 15', getline('.'))
+ exe "normal \<C-O>"
+ call assert_equal('time 10', getline('.'))
+ exe "normal \<C-O>"
+ call assert_equal('time 05', getline('.'))
+
+ " Test with jumplist full.
+ clearjumps
+ call setline(1, repeat(['match here'], 101))
+ call cursor(1, 1)
+ call test_settime(10)
+ for i in range(100)
+ exe "normal /here\r"
+ endfor
+ rviminfo Xviminfo
+
+ " must be newest mark that comes from viminfo.
+ exe "normal \<C-O>"
+ call assert_equal(last_line, line('.'))
+
+ bwipe!
+ call delete('Xviminfo')
+endfunc
+
+func Test_viminfo_encoding()
+ set enc=latin1
+ call histdel(':')
+ call histadd(':', "echo '\xe9'")
+ wviminfo Xviminfo
+
+ set fencs=utf-8,latin1
+ set enc=utf-8
+ sp Xviminfo
+ call assert_equal('latin1', &fenc)
+ close
+
+ call histdel(':')
+ rviminfo Xviminfo
+ call assert_equal("echo 'é'", histget(':', -1))
+
+ call delete('Xviminfo')
+endfunc
+
+func Test_viminfo_bad_syntax()
+ let lines = []
+ call add(lines, '|<') " empty continuation line
+ call add(lines, '|234234234234234324,nothing')
+ call add(lines, '|1+"no comma"')
+ call add(lines, '|1,2,3,4,5,6,7') " too many items
+ call add(lines, '|1,"string version"')
+ call add(lines, '|1,>x') " bad continuation line
+ call add(lines, '|1,"x') " missing quote
+ call add(lines, '|1,"x\') " trailing backslash
+ call add(lines, '|1,,,,') "trailing comma
+ call add(lines, '|1,>234') " trailing continuation line
+ call writefile(lines, 'Xviminfo')
+ rviminfo Xviminfo
+
+ call delete('Xviminfo')
+endfunc
+
+func Test_viminfo_file_marks()
+ silent! bwipe test_viminfo.vim
+ silent! bwipe Xviminfo
+
+ call test_settime(10)
+ edit ten
+ call test_settime(25)
+ edit again
+ call test_settime(30)
+ edit thirty
+ wviminfo Xviminfo
+
+ call test_settime(20)
+ edit twenty
+ call test_settime(35)
+ edit again
+ call test_settime(40)
+ edit fourty
+ wviminfo Xviminfo
+
+ sp Xviminfo
+ 1
+ for name in ['fourty', 'again', 'thirty', 'twenty', 'ten']
+ /^>
+ call assert_equal(name, substitute(getline('.'), '.*/', '', ''))
+ endfor
+ close
+
+ call delete('Xviminfo')
+endfunc
+
+func Test_viminfo_file_mark_tabclose()
+ tabnew Xtestfileintab
+ call setline(1, ['a','b','c','d','e'])
+ 4
+ q!
+ wviminfo Xviminfo
+ sp Xviminfo
+ /^> .*Xtestfileintab
+ let lnum = line('.')
+ while 1
+ if lnum == line('$')
+ call assert_report('mark not found in Xtestfileintab')
+ break
+ endif
+ let lnum += 1
+ let line = getline(lnum)
+ if line == ''
+ call assert_report('mark not found in Xtestfileintab')
+ break
+ endif
+ if line =~ "^\t\""
+ call assert_equal('4', substitute(line, ".*\"\t\\(\\d\\).*", '\1', ''))
+ break
+ endif
+ endwhile
+
+ call delete('Xviminfo')
+ silent! bwipe Xtestfileintab
+endfunc
+
+func Test_viminfo_file_mark_zero_time()
+ let lines = [
+ \ '# Viminfo version',
+ \ '|1,4',
+ \ '',
+ \ '*encoding=utf-8',
+ \ '',
+ \ '# File marks:',
+ \ "'B 1 0 /tmp/nothing",
+ \ '|4,66,1,0,0,"/tmp/nothing"',
+ \ "",
+ \ ]
+ call writefile(lines, 'Xviminfo')
+ delmark B
+ rviminfo Xviminfo
+ call delete('Xviminfo')
+ call assert_equal(1, line("'B"))
+ delmark B
+endfunc
+
+func Test_viminfo_oldfiles()
+ let v:oldfiles = []
+ let lines = [
+ \ '# comment line',
+ \ '*encoding=utf-8',
+ \ '',
+ \ "> /tmp/file_one.txt",
+ \ "\t\"\t11\t0",
+ \ "",
+ \ "> /tmp/file_two.txt",
+ \ "\t\"\t11\t0",
+ \ "",
+ \ "> /tmp/another.txt",
+ \ "\t\"\t11\t0",
+ \ "",
+ \ ]
+ call writefile(lines, 'Xviminfo')
+ rviminfo! Xviminfo
+ call delete('Xviminfo')
+
+ call assert_equal(['1: /tmp/file_one.txt', '2: /tmp/file_two.txt', '3: /tmp/another.txt'], filter(split(execute('oldfiles'), "\n"), {i, v -> v =~ '/tmp/'}))
+ call assert_equal(['1: /tmp/file_one.txt', '2: /tmp/file_two.txt'], filter(split(execute('filter file_ oldfiles'), "\n"), {i, v -> v =~ '/tmp/'}))
+ call assert_equal(['3: /tmp/another.txt'], filter(split(execute('filter /another/ oldfiles'), "\n"), {i, v -> v =~ '/tmp/'}))
+endfunc
diff --git a/src/testdir/test_vimscript.vim b/src/testdir/test_vimscript.vim
new file mode 100644
index 0000000..9de0a62
--- /dev/null
+++ b/src/testdir/test_vimscript.vim
@@ -0,0 +1,1448 @@
+" Test various aspects of the Vim script language.
+" Most of this was formerly in test49.
+
+"-------------------------------------------------------------------------------
+" Test environment {{{1
+"-------------------------------------------------------------------------------
+
+com! XpathINIT let g:Xpath = ''
+com! -nargs=1 -bar Xpath let g:Xpath = g:Xpath . <args>
+
+" Append a message to the "messages" file
+func Xout(text)
+ split messages
+ $put =a:text
+ wq
+endfunc
+
+com! -nargs=1 Xout call Xout(<args>)
+
+" 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 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.
+func 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/\<a:\(\h\w*\)/g:\1/ge
+ normal gg0
+ let cnt = 0
+ while search('\<call\s*\%(\u\|s:\)\w*\s*(.*)', 'W') > 0
+ let cnt = cnt + 1
+ s/\<call\s*\%(\u\|s:\)\w*\s*(.*)/\='source ' . a:{cnt}/
+ endwhile
+ g/^\s*$/d
+ write
+ bwipeout
+ return script
+endfunc
+
+" ExecAsScript - Source a temporary script made from a function. {{{2
+"
+" Make a temporary script file from the function a:funcname, ":source" it, and
+" delete it afterwards. However, if an exception is thrown the file may remain,
+" the caller should call DeleteTheScript() afterwards.
+let s:script_name = ''
+function! ExecAsScript(funcname)
+ " Make a script from the function passed as argument.
+ let s:script_name = MakeScript(a:funcname)
+
+ " Source and delete the script.
+ exec "source" s:script_name
+ call delete(s:script_name)
+ let s:script_name = ''
+endfunction
+
+function! DeleteTheScript()
+ if s:script_name
+ call delete(s:script_name)
+ let s:script_name = ''
+ endif
+endfunc
+
+com! -nargs=1 -bar ExecAsScript call ExecAsScript(<f-args>)
+
+
+"-------------------------------------------------------------------------------
+" Test 1: :endwhile in function {{{1
+"
+" Detect if a broken loop is (incorrectly) reactivated by the
+" :endwhile. Use a :return to prevent an endless loop, and make
+" this test first to get a meaningful result on an error before other
+" tests will hang.
+"-------------------------------------------------------------------------------
+
+function! T1_F()
+ Xpath 'a'
+ let first = 1
+ while 1
+ Xpath 'b'
+ if first
+ Xpath 'c'
+ let first = 0
+ break
+ else
+ Xpath 'd'
+ return
+ endif
+ endwhile
+endfunction
+
+function! T1_G()
+ Xpath 'h'
+ let first = 1
+ while 1
+ Xpath 'i'
+ if first
+ Xpath 'j'
+ let first = 0
+ break
+ else
+ Xpath 'k'
+ return
+ endif
+ if 1 " unmatched :if
+ endwhile
+endfunction
+
+func Test_endwhile_function()
+ XpathINIT
+ call T1_F()
+ Xpath 'F'
+
+ try
+ call T1_G()
+ catch
+ " Catch missing :endif
+ call assert_true(v:exception =~ 'E171')
+ Xpath 'x'
+ endtry
+ Xpath 'G'
+
+ call assert_equal('abcFhijxG', g:Xpath)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 2: :endwhile in script {{{1
+"
+" Detect if a broken loop is (incorrectly) reactivated by the
+" :endwhile. Use a :finish to prevent an endless loop, and place
+" this test before others that might hang to get a meaningful result
+" on an error.
+"
+" This test executes the bodies of the functions T1_F and T1_G from
+" the previous test as script files (:return replaced by :finish).
+"-------------------------------------------------------------------------------
+
+func Test_endwhile_script()
+ XpathINIT
+ ExecAsScript T1_F
+ Xpath 'F'
+ call DeleteTheScript()
+
+ try
+ ExecAsScript T1_G
+ catch
+ " Catch missing :endif
+ call assert_true(v:exception =~ 'E171')
+ Xpath 'x'
+ endtry
+ Xpath 'G'
+ call DeleteTheScript()
+
+ call assert_equal('abcFhijxG', g:Xpath)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 3: :if, :elseif, :while, :continue, :break {{{1
+"-------------------------------------------------------------------------------
+
+function Test_if_while()
+ XpathINIT
+ if 1
+ Xpath 'a'
+ let loops = 3
+ while loops > -1 " main loop: loops == 3, 2, 1 (which breaks)
+ if loops <= 0
+ let break_err = 1
+ let loops = -1
+ else
+ Xpath 'b' . loops
+ endif
+ if (loops == 2)
+ while loops == 2 " dummy loop
+ Xpath 'c' . loops
+ let loops = loops - 1
+ continue " stop dummy loop
+ Xpath 'd' . loops
+ endwhile
+ continue " continue main loop
+ Xpath 'e' . loops
+ elseif (loops == 1)
+ let p = 1
+ while p " dummy loop
+ Xpath 'f' . loops
+ let p = 0
+ break " break dummy loop
+ Xpath 'g' . loops
+ endwhile
+ Xpath 'h' . loops
+ unlet p
+ break " break main loop
+ Xpath 'i' . loops
+ endif
+ if (loops > 0)
+ Xpath 'j' . loops
+ endif
+ while loops == 3 " dummy loop
+ let loops = loops - 1
+ endwhile " end dummy loop
+ endwhile " end main loop
+ Xpath 'k'
+ else
+ Xpath 'l'
+ endif
+ Xpath 'm'
+ if exists("break_err")
+ Xpath 'm'
+ unlet break_err
+ endif
+
+ unlet loops
+
+ call assert_equal('ab3j3b2c2b1f1h1km', g:Xpath)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 4: :return {{{1
+"-------------------------------------------------------------------------------
+
+function! T4_F()
+ if 1
+ Xpath 'a'
+ let loops = 3
+ while loops > 0 " 3: 2: 1:
+ Xpath 'b' . loops
+ if (loops == 2)
+ Xpath 'c' . loops
+ return
+ Xpath 'd' . loops
+ endif
+ Xpath 'e' . loops
+ let loops = loops - 1
+ endwhile
+ Xpath 'f'
+ else
+ Xpath 'g'
+ endif
+endfunction
+
+function Test_return()
+ XpathINIT
+ call T4_F()
+ Xpath '4'
+
+ call assert_equal('ab3e3b2c24', g:Xpath)
+endfunction
+
+
+"-------------------------------------------------------------------------------
+" Test 5: :finish {{{1
+"
+" This test executes the body of the function T4_F from the previous
+" test as a script file (:return replaced by :finish).
+"-------------------------------------------------------------------------------
+
+function Test_finish()
+ XpathINIT
+ ExecAsScript T4_F
+ Xpath '5'
+ call DeleteTheScript()
+
+ call assert_equal('ab3e3b2c25', g:Xpath)
+endfunction
+
+
+
+"-------------------------------------------------------------------------------
+" Test 6: Defining functions in :while loops {{{1
+"
+" Functions can be defined inside other functions. An inner function
+" gets defined when the outer function is executed. Functions may
+" also be defined inside while loops. Expressions in braces for
+" defining the function name are allowed.
+"
+" The functions are defined when sourcing the script, only the
+" resulting path is checked in the test function.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+" The command CALL collects the argument of all its invocations in "calls"
+" when used from a function (that is, when the global variable "calls" needs
+" the "g:" prefix). This is to check that the function code is skipped when
+" the function is defined. For inner functions, do so only if the outer
+" function is not being executed.
+"
+let calls = ""
+com! -nargs=1 CALL
+ \ if !exists("calls") && !exists("outer") |
+ \ let g:calls = g:calls . <args> |
+ \ endif
+
+let i = 0
+while i < 3
+ let i = i + 1
+ if i == 1
+ Xpath 'a'
+ function! F1(arg)
+ CALL a:arg
+ let outer = 1
+
+ let j = 0
+ while j < 1
+ Xpath 'b'
+ let j = j + 1
+ function! G1(arg)
+ CALL a:arg
+ endfunction
+ Xpath 'c'
+ endwhile
+ endfunction
+ Xpath 'd'
+
+ continue
+ endif
+
+ Xpath 'e' . i
+ function! F{i}(i, arg)
+ CALL a:arg
+ let outer = 1
+
+ if a:i == 3
+ Xpath 'f'
+ endif
+ let k = 0
+ while k < 3
+ Xpath 'g' . k
+ let k = k + 1
+ function! G{a:i}{k}(arg)
+ CALL a:arg
+ endfunction
+ Xpath 'h' . k
+ endwhile
+ endfunction
+ Xpath 'i'
+
+endwhile
+
+if exists("*G1")
+ Xpath 'j'
+endif
+if exists("*F1")
+ call F1("F1")
+ if exists("*G1")
+ call G1("G1")
+ endif
+endif
+
+if exists("G21") || exists("G22") || exists("G23")
+ Xpath 'k'
+endif
+if exists("*F2")
+ call F2(2, "F2")
+ if exists("*G21")
+ call G21("G21")
+ endif
+ if exists("*G22")
+ call G22("G22")
+ endif
+ if exists("*G23")
+ call G23("G23")
+ endif
+endif
+
+if exists("G31") || exists("G32") || exists("G33")
+ Xpath 'l'
+endif
+if exists("*F3")
+ call F3(3, "F3")
+ if exists("*G31")
+ call G31("G31")
+ endif
+ if exists("*G32")
+ call G32("G32")
+ endif
+ if exists("*G33")
+ call G33("G33")
+ endif
+endif
+
+Xpath 'm'
+
+let g:test6_result = g:Xpath
+let g:test6_calls = calls
+
+unlet calls
+delfunction F1
+delfunction G1
+delfunction F2
+delfunction G21
+delfunction G22
+delfunction G23
+delfunction G31
+delfunction G32
+delfunction G33
+
+function Test_defining_functions()
+ call assert_equal('ade2ie3ibcg0h1g1h2g2h3fg0h1g1h2g2h3m', g:test6_result)
+ call assert_equal('F1G1F2G21G22G23F3G31G32G33', g:test6_calls)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 7: Continuing on errors outside functions {{{1
+"
+" On an error outside a function, the script processing continues
+" at the line following the outermost :endif or :endwhile. When not
+" inside an :if or :while, the script processing continues at the next
+" line.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+if 1
+ Xpath 'a'
+ while 1
+ Xpath 'b'
+ asdf
+ Xpath 'c'
+ break
+ endwhile | Xpath 'd'
+ Xpath 'e'
+endif | Xpath 'f'
+Xpath 'g'
+
+while 1
+ Xpath 'h'
+ if 1
+ Xpath 'i'
+ asdf
+ Xpath 'j'
+ endif | Xpath 'k'
+ Xpath 'l'
+ break
+endwhile | Xpath 'm'
+Xpath 'n'
+
+asdf
+Xpath 'o'
+
+asdf | Xpath 'p'
+Xpath 'q'
+
+let g:test7_result = g:Xpath
+
+func Test_error_in_script()
+ call assert_equal('abghinoq', g:test7_result)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 8: Aborting and continuing on errors inside functions {{{1
+"
+" On an error inside a function without the "abort" attribute, the
+" script processing continues at the next line (unless the error was
+" in a :return command). On an error inside a function with the
+" "abort" attribute, the function is aborted and the script processing
+" continues after the function call; the value -1 is returned then.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+function! T8_F()
+ if 1
+ Xpath 'a'
+ while 1
+ Xpath 'b'
+ asdf
+ Xpath 'c'
+ asdf | Xpath 'd'
+ Xpath 'e'
+ break
+ endwhile
+ Xpath 'f'
+ endif | Xpath 'g'
+ Xpath 'h'
+
+ while 1
+ Xpath 'i'
+ if 1
+ Xpath 'j'
+ asdf
+ Xpath 'k'
+ asdf | Xpath 'l'
+ Xpath 'm'
+ endif
+ Xpath 'n'
+ break
+ endwhile | Xpath 'o'
+ Xpath 'p'
+
+ return novar " returns (default return value 0)
+ Xpath 'q'
+ return 1 " not reached
+endfunction
+
+function! T8_G() abort
+ if 1
+ Xpath 'r'
+ while 1
+ Xpath 's'
+ asdf " returns -1
+ Xpath 't'
+ break
+ endwhile
+ Xpath 'v'
+ endif | Xpath 'w'
+ Xpath 'x'
+
+ return -4 " not reached
+endfunction
+
+function! T8_H() abort
+ while 1
+ Xpath 'A'
+ if 1
+ Xpath 'B'
+ asdf " returns -1
+ Xpath 'C'
+ endif
+ Xpath 'D'
+ break
+ endwhile | Xpath 'E'
+ Xpath 'F'
+
+ return -4 " not reached
+endfunction
+
+" Aborted functions (T8_G and T8_H) return -1.
+let g:test8_sum = (T8_F() + 1) - 4 * T8_G() - 8 * T8_H()
+Xpath 'X'
+let g:test8_result = g:Xpath
+
+func Test_error_in_function()
+ call assert_equal(13, g:test8_sum)
+ call assert_equal('abcefghijkmnoprsABX', g:test8_result)
+
+ delfunction T8_F
+ delfunction T8_G
+ delfunction T8_H
+endfunc
+
+
+"-------------------------------------------------------------------------------
+" Test 9: Continuing after aborted functions {{{1
+"
+" When a function with the "abort" attribute is aborted due to an
+" error, the next function back in the call hierarchy without an
+" "abort" attribute continues; the value -1 is returned then.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+function! F() abort
+ Xpath 'a'
+ let result = G() " not aborted
+ Xpath 'b'
+ if result != 2
+ Xpath 'c'
+ endif
+ return 1
+endfunction
+
+function! G() " no abort attribute
+ Xpath 'd'
+ if H() != -1 " aborted
+ Xpath 'e'
+ endif
+ Xpath 'f'
+ return 2
+endfunction
+
+function! H() abort
+ Xpath 'g'
+ call I() " aborted
+ Xpath 'h'
+ return 4
+endfunction
+
+function! I() abort
+ Xpath 'i'
+ asdf " error
+ Xpath 'j'
+ return 8
+endfunction
+
+if F() != 1
+ Xpath 'k'
+endif
+
+let g:test9_result = g:Xpath
+
+delfunction F
+delfunction G
+delfunction H
+delfunction I
+
+func Test_func_abort()
+ call assert_equal('adgifb', g:test9_result)
+endfunc
+
+
+"-------------------------------------------------------------------------------
+" Test 10: :if, :elseif, :while argument parsing {{{1
+"
+" A '"' or '|' in an argument expression must not be mixed up with
+" a comment or a next command after a bar. Parsing errors should
+" be recognized.
+"-------------------------------------------------------------------------------
+
+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
+endfunc
+
+if 1 || strlen("\"") | Xpath 'a'
+ Xpath 'b'
+endif
+Xpath 'c'
+
+if 0
+elseif 1 || strlen("\"") | Xpath 'd'
+ Xpath 'e'
+endif
+Xpath 'f'
+
+while 1 || strlen("\"") | Xpath 'g'
+ Xpath 'h'
+ break
+endwhile
+Xpath 'i'
+
+let v:errmsg = ""
+if 1 ||| strlen("\"") | Xpath 'j'
+ Xpath 'k'
+endif
+Xpath 'l'
+if !MSG('E15', "Invalid expression")
+ Xpath 'm'
+endif
+
+let v:errmsg = ""
+if 0
+elseif 1 ||| strlen("\"") | Xpath 'n'
+ Xpath 'o'
+endif
+Xpath 'p'
+if !MSG('E15', "Invalid expression")
+ Xpath 'q'
+endif
+
+let v:errmsg = ""
+while 1 ||| strlen("\"") | Xpath 'r'
+ Xpath 's'
+ break
+endwhile
+Xpath 't'
+if !MSG('E15', "Invalid expression")
+ Xpath 'u'
+endif
+
+let g:test10_result = g:Xpath
+delfunction MSG
+
+func Test_expr_parsing()
+ call assert_equal('abcdefghilpt', g:test10_result)
+endfunc
+
+
+"-------------------------------------------------------------------------------
+" Test 11: :if, :elseif, :while argument evaluation after abort {{{1
+"
+" When code is skipped over due to an error, the boolean argument to
+" an :if, :elseif, or :while must not be evaluated.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+let calls = 0
+
+function! P(num)
+ let g:calls = g:calls + a:num " side effect on call
+ return 0
+endfunction
+
+if 1
+ Xpath 'a'
+ asdf " error
+ Xpath 'b'
+ if P(1) " should not be called
+ Xpath 'c'
+ elseif !P(2) " should not be called
+ Xpath 'd'
+ else
+ Xpath 'e'
+ endif
+ Xpath 'f'
+ while P(4) " should not be called
+ Xpath 'g'
+ endwhile
+ Xpath 'h'
+endif
+Xpath 'x'
+
+let g:test11_calls = calls
+let g:test11_result = g:Xpath
+
+unlet calls
+delfunction P
+
+func Test_arg_abort()
+ call assert_equal(0, g:test11_calls)
+ call assert_equal('ax', g:test11_result)
+endfunc
+
+
+"-------------------------------------------------------------------------------
+" Test 12: Expressions in braces in skipped code {{{1
+"
+" In code skipped over due to an error or inactive conditional,
+" an expression in braces as part of a variable or function name
+" should not be evaluated.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+function! NULL()
+ Xpath 'a'
+ return 0
+endfunction
+
+function! ZERO()
+ Xpath 'b'
+ return 0
+endfunction
+
+function! F0()
+ Xpath 'c'
+endfunction
+
+function! F1(arg)
+ Xpath 'e'
+endfunction
+
+let V0 = 1
+
+Xpath 'f'
+echo 0 ? F{NULL() + V{ZERO()}}() : 1
+
+Xpath 'g'
+if 0
+ Xpath 'h'
+ call F{NULL() + V{ZERO()}}()
+endif
+
+Xpath 'i'
+if 1
+ asdf " error
+ Xpath 'j'
+ call F1(F{NULL() + V{ZERO()}}())
+endif
+
+Xpath 'k'
+if 1
+ asdf " error
+ Xpath 'l'
+ call F{NULL() + V{ZERO()}}()
+endif
+
+let g:test12_result = g:Xpath
+
+func Test_braces_skipped()
+ call assert_equal('fgik', g:test12_result)
+endfunc
+
+
+"-------------------------------------------------------------------------------
+" Test 13: Failure in argument evaluation for :while {{{1
+"
+" A failure in the expression evaluation for the condition of a :while
+" causes the whole :while loop until the matching :endwhile being
+" ignored. Continuation is at the next following line.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+Xpath 'a'
+while asdf
+ Xpath 'b'
+ while 1
+ Xpath 'c'
+ break
+ endwhile
+ Xpath 'd'
+ break
+endwhile
+Xpath 'e'
+
+while asdf | Xpath 'f' | endwhile | Xpath 'g'
+Xpath 'h'
+let g:test13_result = g:Xpath
+
+func Test_while_fail()
+ call assert_equal('aeh', g:test13_result)
+endfunc
+
+
+"-------------------------------------------------------------------------------
+" Test 14: Failure in argument evaluation for :if {{{1
+"
+" A failure in the expression evaluation for the condition of an :if
+" does not cause the corresponding :else or :endif being matched to
+" a previous :if/:elseif. Neither of both branches of the failed :if
+" are executed.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+function! F()
+ Xpath 'a'
+ let x = 0
+ if x " false
+ Xpath 'b'
+ elseif !x " always true
+ Xpath 'c'
+ let x = 1
+ if g:boolvar " possibly undefined
+ Xpath 'd'
+ else
+ Xpath 'e'
+ endif
+ Xpath 'f'
+ elseif x " never executed
+ Xpath 'g'
+ endif
+ Xpath 'h'
+endfunction
+
+let boolvar = 1
+call F()
+Xpath '-'
+
+unlet boolvar
+call F()
+let g:test14_result = g:Xpath
+
+delfunction F
+
+func Test_if_fail()
+ call assert_equal('acdfh-acfh', g:test14_result)
+endfunc
+
+
+"-------------------------------------------------------------------------------
+" Test 15: Failure in argument evaluation for :if (bar) {{{1
+"
+" Like previous test, except that the failing :if ... | ... | :endif
+" is in a single line.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+function! F()
+ Xpath 'a'
+ let x = 0
+ if x " false
+ Xpath 'b'
+ elseif !x " always true
+ Xpath 'c'
+ let x = 1
+ if g:boolvar | Xpath 'd' | else | Xpath 'e' | endif
+ Xpath 'f'
+ elseif x " never executed
+ Xpath 'g'
+ endif
+ Xpath 'h'
+endfunction
+
+let boolvar = 1
+call F()
+Xpath '-'
+
+unlet boolvar
+call F()
+let g:test15_result = g:Xpath
+
+delfunction F
+
+func Test_if_bar_fail()
+ call assert_equal('acdfh-acfh', g:test15_result)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 90: Recognizing {} in variable name. {{{1
+"-------------------------------------------------------------------------------
+
+func Test_curlies()
+ let s:var = 66
+ let ns = 's'
+ call assert_equal(66, {ns}:var)
+
+ let g:a = {}
+ let g:b = 't'
+ let g:a[g:b] = 77
+ call assert_equal(77, g:a['t'])
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 91: using type(). {{{1
+"-------------------------------------------------------------------------------
+
+func Test_type()
+ call assert_equal(0, type(0))
+ call assert_equal(1, type(""))
+ call assert_equal(2, type(function("tr")))
+ call assert_equal(2, type(function("tr", [8])))
+ call assert_equal(3, type([]))
+ call assert_equal(4, type({}))
+ call assert_equal(5, type(0.0))
+ call assert_equal(6, type(v:false))
+ call assert_equal(6, type(v:true))
+ call assert_equal(7, type(v:none))
+ call assert_equal(7, type(v:null))
+ call assert_equal(8, v:t_job)
+ call assert_equal(9, v:t_channel)
+ call assert_equal(v:t_number, type(0))
+ call assert_equal(v:t_string, type(""))
+ call assert_equal(v:t_func, type(function("tr")))
+ call assert_equal(v:t_func, type(function("tr", [8])))
+ call assert_equal(v:t_list, type([]))
+ call assert_equal(v:t_dict, type({}))
+ call assert_equal(v:t_float, type(0.0))
+ call assert_equal(v:t_bool, type(v:false))
+ call assert_equal(v:t_bool, type(v:true))
+ call assert_equal(v:t_none, type(v:none))
+ call assert_equal(v:t_none, type(v:null))
+
+
+ call assert_equal(0, 0 + v:false)
+ call assert_equal(1, 0 + v:true)
+ call assert_equal(0, 0 + v:none)
+ call assert_equal(0, 0 + v:null)
+
+ call assert_equal('v:false', '' . v:false)
+ call assert_equal('v:true', '' . v:true)
+ call assert_equal('v:none', '' . v:none)
+ call assert_equal('v:null', '' . v:null)
+
+ call assert_true(v:false == 0)
+ call assert_false(v:false != 0)
+ call assert_true(v:true == 1)
+ call assert_false(v:true != 1)
+ call assert_false(v:true == v:false)
+ call assert_true(v:true != v:false)
+
+ call assert_true(v:null == 0)
+ call assert_false(v:null != 0)
+ call assert_true(v:none == 0)
+ call assert_false(v:none != 0)
+
+ call assert_true(v:false is v:false)
+ call assert_true(v:true is v:true)
+ call assert_true(v:none is v:none)
+ call assert_true(v:null is v:null)
+
+ call assert_false(v:false isnot v:false)
+ call assert_false(v:true isnot v:true)
+ call assert_false(v:none isnot v:none)
+ call assert_false(v:null isnot v:null)
+
+ call assert_false(v:false is 0)
+ call assert_false(v:true is 1)
+ call assert_false(v:true is v:false)
+ call assert_false(v:none is 0)
+ call assert_false(v:null is 0)
+ call assert_false(v:null is v:none)
+
+ call assert_true(v:false isnot 0)
+ call assert_true(v:true isnot 1)
+ call assert_true(v:true isnot v:false)
+ call assert_true(v:none isnot 0)
+ call assert_true(v:null isnot 0)
+ call assert_true(v:null isnot v:none)
+
+ call assert_equal(v:false, eval(string(v:false)))
+ call assert_equal(v:true, eval(string(v:true)))
+ call assert_equal(v:none, eval(string(v:none)))
+ call assert_equal(v:null, eval(string(v:null)))
+
+ call assert_equal(v:false, copy(v:false))
+ call assert_equal(v:true, copy(v:true))
+ call assert_equal(v:none, copy(v:none))
+ call assert_equal(v:null, copy(v:null))
+
+ call assert_equal([v:false], deepcopy([v:false]))
+ call assert_equal([v:true], deepcopy([v:true]))
+ call assert_equal([v:none], deepcopy([v:none]))
+ call assert_equal([v:null], deepcopy([v:null]))
+
+ call assert_true(empty(v:false))
+ call assert_false(empty(v:true))
+ call assert_true(empty(v:null))
+ call assert_true(empty(v:none))
+
+ func ChangeYourMind()
+ try
+ return v:true
+ finally
+ return 'something else'
+ endtry
+ endfunc
+
+ call ChangeYourMind()
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 92: skipping code {{{1
+"-------------------------------------------------------------------------------
+
+func Test_skip()
+ let Fn = function('Test_type')
+ call assert_false(0 && Fn[1])
+ call assert_false(0 && string(Fn))
+ call assert_false(0 && len(Fn))
+ let l = []
+ call assert_false(0 && l[1])
+ call assert_false(0 && string(l))
+ call assert_false(0 && len(l))
+ let f = 1.0
+ call assert_false(0 && f[1])
+ call assert_false(0 && string(f))
+ call assert_false(0 && len(f))
+ let sp = v:null
+ call assert_false(0 && sp[1])
+ call assert_false(0 && string(sp))
+ call assert_false(0 && len(sp))
+
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 93: :echo and string() {{{1
+"-------------------------------------------------------------------------------
+
+func Test_echo_and_string()
+ " String
+ let a = 'foo bar'
+ redir => result
+ echo a
+ echo string(a)
+ redir END
+ let l = split(result, "\n")
+ call assert_equal(["foo bar",
+ \ "'foo bar'"], l)
+
+ " Float
+ if has('float')
+ let a = -1.2e0
+ redir => result
+ echo a
+ echo string(a)
+ redir END
+ let l = split(result, "\n")
+ call assert_equal(["-1.2",
+ \ "-1.2"], l)
+ endif
+
+ " Funcref
+ redir => result
+ echo function('string')
+ echo string(function('string'))
+ redir END
+ let l = split(result, "\n")
+ call assert_equal(["string",
+ \ "function('string')"], l)
+
+ " Recursive dictionary
+ let a = {}
+ let a["a"] = a
+ redir => result
+ echo a
+ echo string(a)
+ redir END
+ let l = split(result, "\n")
+ call assert_equal(["{'a': {...}}",
+ \ "{'a': {...}}"], l)
+
+ " Recursive list
+ let a = [0]
+ let a[0] = a
+ redir => result
+ echo a
+ echo string(a)
+ redir END
+ let l = split(result, "\n")
+ call assert_equal(["[[...]]",
+ \ "[[...]]"], l)
+
+ " Empty dictionaries in a list
+ let a = {}
+ redir => result
+ echo [a, a, a]
+ echo string([a, a, a])
+ redir END
+ let l = split(result, "\n")
+ call assert_equal(["[{}, {}, {}]",
+ \ "[{}, {}, {}]"], l)
+
+ " Empty dictionaries in a dictionary
+ let a = {}
+ let b = {"a": a, "b": a}
+ redir => result
+ echo b
+ echo string(b)
+ redir END
+ let l = split(result, "\n")
+ call assert_equal(["{'a': {}, 'b': {}}",
+ \ "{'a': {}, 'b': {}}"], l)
+
+ " Empty lists in a list
+ let a = []
+ redir => result
+ echo [a, a, a]
+ echo string([a, a, a])
+ redir END
+ let l = split(result, "\n")
+ call assert_equal(["[[], [], []]",
+ \ "[[], [], []]"], l)
+
+ " Empty lists in a dictionary
+ let a = []
+ let b = {"a": a, "b": a}
+ redir => result
+ echo b
+ echo string(b)
+ redir END
+ let l = split(result, "\n")
+ call assert_equal(["{'a': [], 'b': []}",
+ \ "{'a': [], 'b': []}"], l)
+
+ " Dictionaries in a list
+ let a = {"one": "yes", "two": "yes", "three": "yes"}
+ redir => result
+ echo [a, a, a]
+ echo string([a, a, a])
+ redir END
+ let l = split(result, "\n")
+ call assert_equal(["[{'one': 'yes', 'two': 'yes', 'three': 'yes'}, {...}, {...}]",
+ \ "[{'one': 'yes', 'two': 'yes', 'three': 'yes'}, {'one': 'yes', 'two': 'yes', 'three': 'yes'}, {'one': 'yes', 'two': 'yes', 'three': 'yes'}]"], l)
+
+ " Dictionaries in a dictionary
+ let a = {"one": "yes", "two": "yes", "three": "yes"}
+ let b = {"a": a, "b": a}
+ redir => result
+ echo b
+ echo string(b)
+ redir END
+ let l = split(result, "\n")
+ call assert_equal(["{'a': {'one': 'yes', 'two': 'yes', 'three': 'yes'}, 'b': {...}}",
+ \ "{'a': {'one': 'yes', 'two': 'yes', 'three': 'yes'}, 'b': {'one': 'yes', 'two': 'yes', 'three': 'yes'}}"], l)
+
+ " Lists in a list
+ let a = [1, 2, 3]
+ redir => result
+ echo [a, a, a]
+ echo string([a, a, a])
+ redir END
+ let l = split(result, "\n")
+ call assert_equal(["[[1, 2, 3], [...], [...]]",
+ \ "[[1, 2, 3], [1, 2, 3], [1, 2, 3]]"], l)
+
+ " Lists in a dictionary
+ let a = [1, 2, 3]
+ let b = {"a": a, "b": a}
+ redir => result
+ echo b
+ echo string(b)
+ redir END
+ let l = split(result, "\n")
+ call assert_equal(["{'a': [1, 2, 3], 'b': [...]}",
+ \ "{'a': [1, 2, 3], 'b': [1, 2, 3]}"], l)
+
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 94: 64-bit Numbers {{{1
+"-------------------------------------------------------------------------------
+
+func Test_num64()
+ if !has('num64')
+ return
+ endif
+
+ call assert_notequal( 4294967296, 0)
+ call assert_notequal(-4294967296, 0)
+ call assert_equal( 4294967296, 0xFFFFffff + 1)
+ call assert_equal(-4294967296, -0xFFFFffff - 1)
+
+ call assert_equal( 9223372036854775807, 1 / 0)
+ call assert_equal(-9223372036854775807, -1 / 0)
+ call assert_equal(-9223372036854775807 - 1, 0 / 0)
+
+ call assert_equal( 0x7FFFffffFFFFffff, float2nr( 1.0e150))
+ call assert_equal(-0x7FFFffffFFFFffff, float2nr(-1.0e150))
+
+ let rng = range(0xFFFFffff, 0x100000001)
+ call assert_equal([0xFFFFffff, 0x100000000, 0x100000001], rng)
+ call assert_equal(0x100000001, max(rng))
+ call assert_equal(0xFFFFffff, min(rng))
+ call assert_equal(rng, sort(range(0x100000001, 0xFFFFffff, -1), 'N'))
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 95: lines of :append, :change, :insert {{{1
+"-------------------------------------------------------------------------------
+
+function! DefineFunction(name, body)
+ let func = join(['function! ' . a:name . '()'] + a:body + ['endfunction'], "\n")
+ exec func
+endfunction
+
+func Test_script_lines()
+ " :append
+ try
+ call DefineFunction('T_Append', [
+ \ 'append',
+ \ 'py <<EOS',
+ \ '.',
+ \ ])
+ catch
+ call assert_report("Can't define function")
+ endtry
+ try
+ call DefineFunction('T_Append', [
+ \ 'append',
+ \ 'abc',
+ \ ])
+ call assert_report("Shouldn't be able to define function")
+ catch
+ call assert_exception('Vim(function):E126: Missing :endfunction')
+ endtry
+
+ " :change
+ try
+ call DefineFunction('T_Change', [
+ \ 'change',
+ \ 'py <<EOS',
+ \ '.',
+ \ ])
+ catch
+ call assert_report("Can't define function")
+ endtry
+ try
+ call DefineFunction('T_Change', [
+ \ 'change',
+ \ 'abc',
+ \ ])
+ call assert_report("Shouldn't be able to define function")
+ catch
+ call assert_exception('Vim(function):E126: Missing :endfunction')
+ endtry
+
+ " :insert
+ try
+ call DefineFunction('T_Insert', [
+ \ 'insert',
+ \ 'py <<EOS',
+ \ '.',
+ \ ])
+ catch
+ call assert_report("Can't define function")
+ endtry
+ try
+ call DefineFunction('T_Insert', [
+ \ 'insert',
+ \ 'abc',
+ \ ])
+ call assert_report("Shouldn't be able to define function")
+ catch
+ call assert_exception('Vim(function):E126: Missing :endfunction')
+ endtry
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 96: line continuation {{{1
+"
+" Undefined behavior was detected by ubsan with line continuation
+" after an empty line.
+"-------------------------------------------------------------------------------
+func Test_script_emty_line_continuation()
+
+ \
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 97: bitwise functions {{{1
+"-------------------------------------------------------------------------------
+func Test_bitwise_functions()
+ " and
+ call assert_equal(127, and(127, 127))
+ call assert_equal(16, and(127, 16))
+ call assert_equal(0, and(127, 128))
+ call assert_fails("call and(1.0, 1)", 'E805:')
+ call assert_fails("call and([], 1)", 'E745:')
+ call assert_fails("call and({}, 1)", 'E728:')
+ call assert_fails("call and(1, 1.0)", 'E805:')
+ call assert_fails("call and(1, [])", 'E745:')
+ call assert_fails("call and(1, {})", 'E728:')
+ " or
+ call assert_equal(23, or(16, 7))
+ call assert_equal(15, or(8, 7))
+ call assert_equal(123, or(0, 123))
+ call assert_fails("call or(1.0, 1)", 'E805:')
+ call assert_fails("call or([], 1)", 'E745:')
+ call assert_fails("call or({}, 1)", 'E728:')
+ call assert_fails("call or(1, 1.0)", 'E805:')
+ call assert_fails("call or(1, [])", 'E745:')
+ call assert_fails("call or(1, {})", 'E728:')
+ " xor
+ call assert_equal(0, xor(127, 127))
+ call assert_equal(111, xor(127, 16))
+ call assert_equal(255, xor(127, 128))
+ call assert_fails("call xor(1.0, 1)", 'E805:')
+ call assert_fails("call xor([], 1)", 'E745:')
+ call assert_fails("call xor({}, 1)", 'E728:')
+ call assert_fails("call xor(1, 1.0)", 'E805:')
+ call assert_fails("call xor(1, [])", 'E745:')
+ call assert_fails("call xor(1, {})", 'E728:')
+ " invert
+ call assert_equal(65408, and(invert(127), 65535))
+ call assert_equal(65519, and(invert(16), 65535))
+ call assert_equal(65407, and(invert(128), 65535))
+ call assert_fails("call invert(1.0)", 'E805:')
+ call assert_fails("call invert([])", 'E745:')
+ call assert_fails("call invert({})", 'E728:')
+endfunc
+
+" Test trailing text after :endfunction {{{1
+func Test_endfunction_trailing()
+ call assert_false(exists('*Xtest'))
+
+ exe "func Xtest()\necho 'hello'\nendfunc\nlet done = 'yes'"
+ call assert_true(exists('*Xtest'))
+ call assert_equal('yes', done)
+ delfunc Xtest
+ unlet done
+
+ exe "func Xtest()\necho 'hello'\nendfunc|let done = 'yes'"
+ call assert_true(exists('*Xtest'))
+ call assert_equal('yes', done)
+ delfunc Xtest
+ unlet done
+
+ " trailing line break
+ exe "func Xtest()\necho 'hello'\nendfunc\n"
+ call assert_true(exists('*Xtest'))
+ delfunc Xtest
+
+ set verbose=1
+ exe "func Xtest()\necho 'hello'\nendfunc \" garbage"
+ call assert_notmatch('W22:', split(execute('1messages'), "\n")[0])
+ call assert_true(exists('*Xtest'))
+ delfunc Xtest
+
+ exe "func Xtest()\necho 'hello'\nendfunc garbage"
+ call assert_match('W22:', split(execute('1messages'), "\n")[0])
+ call assert_true(exists('*Xtest'))
+ delfunc Xtest
+ set verbose=0
+
+ function Foo()
+ echo 'hello'
+ endfunction | echo 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
+ delfunc Foo
+endfunc
+
+func Test_delfunction_force()
+ delfunc! Xtest
+ delfunc! Xtest
+ func Xtest()
+ echo 'nothing'
+ endfunc
+ delfunc! Xtest
+ delfunc! Xtest
+endfunc
+
+" Test using bang after user command {{{1
+func Test_user_command_with_bang()
+ command -bang Nieuw let nieuw = 1
+ Ni!
+ call assert_equal(1, nieuw)
+ unlet nieuw
+ delcommand Nieuw
+endfunc
+
+" Test for script-local function
+func <SID>DoLast()
+ call append(line('$'), "last line")
+endfunc
+
+func s:DoNothing()
+ call append(line('$'), "nothing line")
+endfunc
+
+func Test_script_local_func()
+ set nocp viminfo+=nviminfo
+ new
+ nnoremap <buffer> _x :call <SID>DoNothing()<bar>call <SID>DoLast()<bar>delfunc <SID>DoNothing<bar>delfunc <SID>DoLast<cr>
+
+ normal _x
+ call assert_equal('nothing line', getline(2))
+ call assert_equal('last line', getline(3))
+ enew! | close
+endfunc
+
+"-------------------------------------------------------------------------------
+" Modelines {{{1
+" vim: ts=8 sw=4 tw=80 fdm=marker
+" vim: fdt=substitute(substitute(foldtext(),\ '\\%(^+--\\)\\@<=\\(\\s*\\)\\(.\\{-}\\)\:\ \\%(\"\ \\)\\=\\(Test\ \\d*\\)\:\\s*',\ '\\3\ (\\2)\:\ \\1',\ \"\"),\ '\\(Test\\s*\\)\\(\\d\\)\\D\\@=',\ '\\1\ \\2',\ "")
+"-------------------------------------------------------------------------------
diff --git a/src/testdir/test_virtualedit.vim b/src/testdir/test_virtualedit.vim
new file mode 100644
index 0000000..67adede
--- /dev/null
+++ b/src/testdir/test_virtualedit.vim
@@ -0,0 +1,75 @@
+" Tests for 'virtualedit'.
+
+func Test_yank_move_change()
+ new
+ call setline(1, [
+ \ "func foo() error {",
+ \ "\tif n, err := bar();",
+ \ "\terr != nil {",
+ \ "\t\treturn err",
+ \ "\t}",
+ \ "\tn = n * n",
+ \ ])
+ set virtualedit=all
+ set ts=4
+ function! MoveSelectionDown(count) abort
+ normal! m`
+ silent! exe "'<,'>move'>+".a:count
+ norm! ``
+ endfunction
+
+ xmap ]e :<C-U>call MoveSelectionDown(v:count1)<CR>
+ 2
+ normal 2gg
+ normal J
+ normal jVj
+ normal ]e
+ normal ce
+ bwipe!
+ set virtualedit=
+ set ts=8
+endfunc
+
+func Test_paste_end_of_line()
+ new
+ set virtualedit=all
+ call setline(1, ['456', '123'])
+ normal! gg0"ay$
+ exe "normal! 2G$lllA\<C-O>:normal! \"agP\r"
+ call assert_equal('123456', getline(2))
+
+ bwipe!
+ set virtualedit=
+endfunc
+
+func Test_replace_end_of_line()
+ new
+ set virtualedit=all
+ call setline(1, range(20))
+ exe "normal! gg2jv10lr-"
+ call assert_equal(["1", "-----------", "3"], getline(2,4))
+ call setline(1, range(20))
+ exe "normal! gg2jv10lr\<c-k>hh"
+ call assert_equal(["1", "───────────", "3"], getline(2,4))
+
+ bwipe!
+ set virtualedit=
+endfunc
+
+func Test_edit_CTRL_G()
+ new
+ set virtualedit=insert
+ call setline(1, ['123', '1', '12'])
+ exe "normal! ggA\<c-g>jx\<c-g>jx"
+ call assert_equal(['123', '1 x', '12 x'], getline(1,'$'))
+
+ set virtualedit=all
+ %d_
+ call setline(1, ['1', '12'])
+ exe "normal! ggllix\<c-g>jx"
+ call assert_equal(['1 x', '12x'], getline(1,'$'))
+
+
+ bwipe!
+ set virtualedit=
+endfunc
diff --git a/src/testdir/test_visual.vim b/src/testdir/test_visual.vim
new file mode 100644
index 0000000..77064ba
--- /dev/null
+++ b/src/testdir/test_visual.vim
@@ -0,0 +1,399 @@
+" Tests for various Visual mode.
+if !has('visual')
+ finish
+endif
+
+
+func Test_block_shift_multibyte()
+ " Uses double-wide character.
+ split
+ call setline(1, ['xヹxxx', 'ヹxxx'])
+ exe "normal 1G0l\<C-V>jl>"
+ call assert_equal('x ヹxxx', getline(1))
+ call assert_equal(' ヹxxx', getline(2))
+ q!
+endfunc
+
+func Test_block_shift_overflow()
+ " This used to cause a multiplication overflow followed by a crash.
+ new
+ normal ii
+ exe "normal \<C-V>876543210>"
+ q!
+endfunc
+
+func Test_dotregister_paste()
+ new
+ exe "norm! ihello world\<esc>"
+ norm! 0ve".p
+ call assert_equal('hello world world', getline(1))
+ q!
+endfunc
+
+func Test_Visual_ctrl_o()
+ new
+ call setline(1, ['one', 'two', 'three'])
+ call cursor(1,2)
+ set noshowmode
+ set tw=0
+ call feedkeys("\<c-v>jjlIa\<c-\>\<c-o>:set tw=88\<cr>\<esc>", 'tx')
+ call assert_equal(['oane', 'tawo', 'tahree'], getline(1, 3))
+ call assert_equal(88, &tw)
+ set tw&
+ bw!
+endfu
+
+func Test_Visual_vapo()
+ new
+ normal oxx
+ normal vapo
+ bwipe!
+endfunc
+
+func Test_Visual_inner_quote()
+ new
+ normal oxX
+ normal vki'
+ bwipe!
+endfunc
+
+" Test for Visual mode not being reset causing E315 error.
+func TriggerTheProblem()
+ " At this point there is no visual selection because :call reset it.
+ " Let's restore the selection:
+ normal gv
+ '<,'>del _
+ try
+ exe "normal \<Esc>"
+ catch /^Vim\%((\a\+)\)\=:E315/
+ echom 'Snap! E315 error!'
+ let g:msg = 'Snap! E315 error!'
+ endtry
+endfunc
+
+func Test_visual_mode_reset()
+ enew
+ let g:msg = "Everything's fine."
+ enew
+ setl buftype=nofile
+ call append(line('$'), 'Delete this line.')
+
+ " NOTE: this has to be done by a call to a function because executing :del
+ " the ex-way will require the colon operator which resets the visual mode
+ " thus preventing the problem:
+ exe "normal! GV:call TriggerTheProblem()\<CR>"
+ call assert_equal("Everything's fine.", g:msg)
+
+endfunc
+
+" Test for visual block shift and tab characters.
+func Test_block_shift_tab()
+ enew!
+ call append(0, repeat(['one two three'], 5))
+ call cursor(1,1)
+ exe "normal i\<C-G>u"
+ exe "normal fe\<C-V>4jR\<Esc>ugvr1"
+ call assert_equal('on1 two three', getline(1))
+ call assert_equal('on1 two three', getline(2))
+ call assert_equal('on1 two three', getline(5))
+
+ enew!
+ call append(0, repeat(['abcdefghijklmnopqrstuvwxyz'], 5))
+ call cursor(1,1)
+ exe "normal \<C-V>4jI \<Esc>j<<11|D"
+ exe "normal j7|a\<Tab>\<Tab>"
+ exe "normal j7|a\<Tab>\<Tab> "
+ exe "normal j7|a\<Tab> \<Tab>\<Esc>4k13|\<C-V>4j<"
+ call assert_equal(' abcdefghijklmnopqrstuvwxyz', getline(1))
+ call assert_equal('abcdefghij', getline(2))
+ call assert_equal(" abc\<Tab> defghijklmnopqrstuvwxyz", getline(3))
+ call assert_equal(" abc\<Tab> defghijklmnopqrstuvwxyz", getline(4))
+ call assert_equal(" abc\<Tab> defghijklmnopqrstuvwxyz", getline(5))
+
+ %s/\s\+//g
+ call cursor(1,1)
+ exe "normal \<C-V>4jI \<Esc>j<<"
+ exe "normal j7|a\<Tab>\<Tab>"
+ exe "normal j7|a\<Tab>\<Tab>\<Tab>\<Tab>\<Tab>"
+ exe "normal j7|a\<Tab> \<Tab>\<Tab>\<Esc>4k13|\<C-V>4j3<"
+ call assert_equal(' abcdefghijklmnopqrstuvwxyz', getline(1))
+ call assert_equal('abcdefghij', getline(2))
+ call assert_equal(" abc\<Tab> defghijklmnopqrstuvwxyz", getline(3))
+ call assert_equal(" abc\<Tab>\<Tab>defghijklmnopqrstuvwxyz", getline(4))
+ call assert_equal(" abc\<Tab> defghijklmnopqrstuvwxyz", getline(5))
+
+ enew!
+endfunc
+
+" Tests Blockwise Visual when there are TABs before the text.
+func Test_blockwise_visual()
+ enew!
+ call append(0, ['123456',
+ \ '234567',
+ \ '345678',
+ \ '',
+ \ 'test text test tex start here',
+ \ "\t\tsome text",
+ \ "\t\ttest text",
+ \ 'test text'])
+ call cursor(1,1)
+ exe "normal /start here$\<CR>"
+ exe 'normal "by$' . "\<C-V>jjlld"
+ exe "normal /456$\<CR>"
+ exe "normal \<C-V>jj" . '"bP'
+ call assert_equal(['123start here56',
+ \ '234start here67',
+ \ '345start here78',
+ \ '',
+ \ 'test text test tex rt here',
+ \ "\t\tsomext",
+ \ "\t\ttesext"], getline(1, 7))
+
+ enew!
+endfunc
+
+" Test swapping corners in blockwise visual mode with o and O
+func Test_blockwise_visual_o_O()
+ enew!
+
+ exe "norm! 10i.\<Esc>Y4P3lj\<C-V>4l2jr "
+ exe "norm! gvO\<Esc>ra"
+ exe "norm! gvO\<Esc>rb"
+ exe "norm! gvo\<C-c>rc"
+ exe "norm! gvO\<C-c>rd"
+
+ call assert_equal(['..........',
+ \ '...c d..',
+ \ '... ..',
+ \ '...a b..',
+ \ '..........'], getline(1, '$'))
+
+ enew!
+endfun
+
+" Test Virtual replace mode.
+func Test_virtual_replace()
+ if exists('&t_kD')
+ let save_t_kD = &t_kD
+ endif
+ if exists('&t_kb')
+ let save_t_kb = &t_kb
+ endif
+ exe "set t_kD=\<C-V>x7f t_kb=\<C-V>x08"
+ enew!
+ exe "normal a\nabcdefghi\njk\tlmn\n opq rst\n\<C-D>uvwxyz"
+ call cursor(1,1)
+ set ai bs=2
+ exe "normal gR0\<C-D> 1\nA\nBCDEFGHIJ\n\tKL\nMNO\nPQR"
+ call assert_equal([' 1',
+ \ ' A',
+ \ ' BCDEFGHIJ',
+ \ ' KL',
+ \ ' MNO',
+ \ ' PQR',
+ \ ], getline(1, 6))
+ normal G
+ mark a
+ exe "normal o0\<C-D>\nabcdefghi\njk\tlmn\n opq\trst\n\<C-D>uvwxyz\n"
+ exe "normal 'ajgR0\<C-D> 1\nA\nBCDEFGHIJ\n\tKL\nMNO\nPQR" . repeat("\<BS>", 29)
+ call assert_equal([' 1',
+ \ 'abcdefghi',
+ \ 'jk lmn',
+ \ ' opq rst',
+ \ 'uvwxyz'], getline(7, 11))
+ normal G
+ exe "normal iab\tcdefghi\tjkl"
+ exe "normal 0gRAB......CDEFGHI.J\<Esc>o"
+ exe "normal iabcdefghijklmnopqrst\<Esc>0gRAB\tIJKLMNO\tQR"
+ call assert_equal(['AB......CDEFGHI.Jkl',
+ \ 'AB IJKLMNO QRst'], getline(12, 13))
+ enew!
+ set noai bs&vim
+ if exists('save_t_kD')
+ let &t_kD = save_t_kD
+ endif
+ if exists('save_t_kb')
+ let &t_kb = save_t_kb
+ endif
+endfunc
+
+" Test Virtual replace mode.
+func Test_virtual_replace2()
+ enew!
+ set bs=2
+ exe "normal a\nabcdefghi\njk\tlmn\n opq rst\n\<C-D>uvwxyz"
+ call cursor(1,1)
+ " Test 1: Test that del deletes the newline
+ exe "normal gR0\<del> 1\nA\nBCDEFGHIJ\n\tKL\nMNO\nPQR"
+ call assert_equal(['0 1',
+ \ 'A',
+ \ 'BCDEFGHIJ',
+ \ ' KL',
+ \ 'MNO',
+ \ 'PQR',
+ \ ], getline(1, 6))
+ " Test 2:
+ " a newline is not deleted, if no newline has been added in virtual replace mode
+ %d_
+ call setline(1, ['abcd', 'efgh', 'ijkl'])
+ call cursor(2,1)
+ exe "norm! gR1234\<cr>5\<bs>\<bs>\<bs>"
+ call assert_equal(['abcd',
+ \ '123h',
+ \ 'ijkl'], getline(1, '$'))
+ " Test 3:
+ " a newline is deleted, if a newline has been inserted before in virtual replace mode
+ %d_
+ call setline(1, ['abcd', 'efgh', 'ijkl'])
+ call cursor(2,1)
+ exe "norm! gR1234\<cr>\<cr>56\<bs>\<bs>\<bs>"
+ call assert_equal(['abcd',
+ \ '1234',
+ \ 'ijkl'], getline(1, '$'))
+ " Test 4:
+ " delete add a newline, delete it, add it again and check undo
+ %d_
+ call setline(1, ['abcd', 'efgh', 'ijkl'])
+ call cursor(2,1)
+ " break undo sequence explicitly
+ let &ul = &ul
+ exe "norm! gR1234\<cr>\<bs>\<del>56\<cr>"
+ let &ul = &ul
+ call assert_equal(['abcd',
+ \ '123456',
+ \ ''], getline(1, '$'))
+ norm! u
+ call assert_equal(['abcd',
+ \ 'efgh',
+ \ 'ijkl'], getline(1, '$'))
+ " clean up
+ %d_
+ set bs&vim
+endfunc
+
+func Test_Visual_word_textobject()
+ new
+ call setline(1, ['First sentence. Second sentence.'])
+
+ " When start and end of visual area are identical, 'aw' or 'iw' select
+ " the whole word.
+ norm! 1go2fcvawy
+ call assert_equal('Second ', @")
+ norm! 1go2fcviwy
+ call assert_equal('Second', @")
+
+ " When start and end of visual area are not identical, 'aw' or 'iw'
+ " extend the word in direction of the end of the visual area.
+ norm! 1go2fcvlawy
+ call assert_equal('cond ', @")
+ norm! gv2awy
+ call assert_equal('cond sentence.', @")
+
+ norm! 1go2fcvliwy
+ call assert_equal('cond', @")
+ norm! gv2iwy
+ call assert_equal('cond sentence', @")
+
+ " Extend visual area in opposite direction.
+ norm! 1go2fcvhawy
+ call assert_equal(' Sec', @")
+ norm! gv2awy
+ call assert_equal(' sentence. Sec', @")
+
+ norm! 1go2fcvhiwy
+ call assert_equal('Sec', @")
+ norm! gv2iwy
+ call assert_equal('. Sec', @")
+
+ bwipe!
+endfunc
+
+func Test_Visual_sentence_textobject()
+ new
+ call setline(1, ['First sentence. Second sentence. Third', 'sentence. Fourth sentence'])
+
+ " When start and end of visual area are identical, 'as' or 'is' select
+ " the whole sentence.
+ norm! 1gofdvasy
+ call assert_equal('Second sentence. ', @")
+ norm! 1gofdvisy
+ call assert_equal('Second sentence.', @")
+
+ " When start and end of visual area are not identical, 'as' or 'is'
+ " extend the sentence in direction of the end of the visual area.
+ norm! 1gofdvlasy
+ call assert_equal('d sentence. ', @")
+ norm! gvasy
+ call assert_equal("d sentence. Third\nsentence. ", @")
+
+ norm! 1gofdvlisy
+ call assert_equal('d sentence.', @")
+ norm! gvisy
+ call assert_equal('d sentence. ', @")
+ norm! gvisy
+ call assert_equal("d sentence. Third\nsentence.", @")
+
+ " Extend visual area in opposite direction.
+ norm! 1gofdvhasy
+ call assert_equal(' Second', @")
+ norm! gvasy
+ call assert_equal("First sentence. Second", @")
+
+ norm! 1gofdvhisy
+ call assert_equal('Second', @")
+ norm! gvisy
+ call assert_equal(' Second', @")
+ norm! gvisy
+ call assert_equal('First sentence. Second', @")
+
+ bwipe!
+endfunc
+
+func Test_Visual_paragraph_textobject()
+ new
+ call setline(1, ['First line.',
+ \ '',
+ \ 'Second line.',
+ \ 'Third line.',
+ \ 'Fourth line.',
+ \ 'Fifth line.',
+ \ '',
+ \ 'Sixth line.'])
+
+ " When start and end of visual area are identical, 'ap' or 'ip' select
+ " the whole paragraph.
+ norm! 4ggvapy
+ call assert_equal("Second line.\nThird line.\nFourth line.\nFifth line.\n\n", @")
+ norm! 4ggvipy
+ call assert_equal("Second line.\nThird line.\nFourth line.\nFifth line.\n", @")
+
+ " When start and end of visual area are not identical, 'ap' or 'ip'
+ " extend the sentence in direction of the end of the visual area.
+ " FIXME: actually, it is not sufficient to have different start and
+ " end of visual selection, the start line and end line have to differ,
+ " which is not consistent with the documentation.
+ norm! 4ggVjapy
+ call assert_equal("Third line.\nFourth line.\nFifth line.\n\n", @")
+ norm! gvapy
+ call assert_equal("Third line.\nFourth line.\nFifth line.\n\nSixth line.\n", @")
+ norm! 4ggVjipy
+ call assert_equal("Third line.\nFourth line.\nFifth line.\n", @")
+ norm! gvipy
+ call assert_equal("Third line.\nFourth line.\nFifth line.\n\n", @")
+ norm! gvipy
+ call assert_equal("Third line.\nFourth line.\nFifth line.\n\nSixth line.\n", @")
+
+ " Extend visual area in opposite direction.
+ norm! 5ggVkapy
+ call assert_equal("\nSecond line.\nThird line.\nFourth line.\n", @")
+ norm! gvapy
+ call assert_equal("First line.\n\nSecond line.\nThird line.\nFourth line.\n", @")
+ norm! 5ggVkipy
+ call assert_equal("Second line.\nThird line.\nFourth line.\n", @")
+ norma gvipy
+ call assert_equal("\nSecond line.\nThird line.\nFourth line.\n", @")
+ norm! gvipy
+ call assert_equal("First line.\n\nSecond line.\nThird line.\nFourth line.\n", @")
+
+ bwipe!
+endfunc
diff --git a/src/testdir/test_winbar.vim b/src/testdir/test_winbar.vim
new file mode 100644
index 0000000..1961607
--- /dev/null
+++ b/src/testdir/test_winbar.vim
@@ -0,0 +1,23 @@
+" Test WinBar
+
+if !has('menu')
+ finish
+endif
+
+func Test_add_remove_menu()
+ new
+ amenu 1.10 WinBar.Next :let g:did_next = 11<CR>
+ amenu 1.20 WinBar.Cont :let g:did_cont = 12<CR>
+ emenu WinBar.Next
+ call assert_equal(11, g:did_next)
+ emenu WinBar.Cont
+ call assert_equal(12, g:did_cont)
+
+ wincmd w
+ call assert_fails('emenu WinBar.Next', 'E334')
+ wincmd p
+
+ aunmenu WinBar.Next
+ aunmenu WinBar.Cont
+ close
+endfunc
diff --git a/src/testdir/test_winbuf_close.vim b/src/testdir/test_winbuf_close.vim
new file mode 100644
index 0000000..e461861
--- /dev/null
+++ b/src/testdir/test_winbuf_close.vim
@@ -0,0 +1,160 @@
+" Test for commands that close windows and/or buffers:
+" :quit
+" :close
+" :hide
+" :only
+" :sall
+" :all
+" :ball
+" :buf
+" :edit
+"
+func Test_winbuf_close()
+ enew | only
+
+ call writefile(['testtext 1'], 'Xtest1')
+ call writefile(['testtext 2'], 'Xtest2')
+ call writefile(['testtext 3'], 'Xtest3')
+
+ next! Xtest1 Xtest2
+ call setline(1, 'testtext 1 1')
+
+ " test for working :n when hidden set
+ set hidden
+ next
+ call assert_equal('Xtest2', bufname('%'))
+
+ " test for failing :rew when hidden not set
+ set nohidden
+ call setline(1, 'testtext 2 2')
+ call assert_fails('rewind', 'E37')
+ call assert_equal('Xtest2', bufname('%'))
+ call assert_equal('testtext 2 2', getline(1))
+
+ " test for working :rew when hidden set
+ set hidden
+ rewind
+ call assert_equal('Xtest1', bufname('%'))
+ call assert_equal('testtext 1 1', getline(1))
+
+ " test for :all keeping a buffer when it's modified
+ set nohidden
+ call setline(1, 'testtext 1 1 1')
+ split
+ next Xtest2 Xtest3
+ all
+ 1wincmd w
+ call assert_equal('Xtest1', bufname('%'))
+ call assert_equal('testtext 1 1 1', getline(1))
+
+ " test abandoning changed buffer, should be unloaded even when 'hidden' set
+ set hidden
+ call setline(1, 'testtext 1 1 1 1')
+ quit!
+ call assert_equal('Xtest2', bufname('%'))
+ call assert_equal('testtext 2 2', getline(1))
+ unhide
+ call assert_equal('Xtest2', bufname('%'))
+ call assert_equal('testtext 2 2', getline(1))
+
+ " test ":hide" hides anyway when 'hidden' not set
+ set nohidden
+ call setline(1, 'testtext 2 2 2')
+ hide
+ call assert_equal('Xtest3', bufname('%'))
+ call assert_equal('testtext 3', getline(1))
+
+ " test ":edit" failing in modified buffer when 'hidden' not set
+ call setline(1, 'testtext 3 3')
+ call assert_fails('edit Xtest1', 'E37')
+ call assert_equal('Xtest3', bufname('%'))
+ call assert_equal('testtext 3 3', getline(1))
+
+ " test ":edit" working in modified buffer when 'hidden' set
+ set hidden
+ edit Xtest1
+ call assert_equal('Xtest1', bufname('%'))
+ call assert_equal('testtext 1', getline(1))
+
+ " test ":close" not hiding when 'hidden' not set in modified buffer
+ split Xtest3
+ set nohidden
+ call setline(1, 'testtext 3 3 3')
+ call assert_fails('close', 'E37')
+ call assert_equal('Xtest3', bufname('%'))
+ call assert_equal('testtext 3 3 3', getline(1))
+
+ " test ":close!" does hide when 'hidden' not set in modified buffer;
+ call setline(1, 'testtext 3 3 3 3')
+ close!
+ call assert_equal('Xtest1', bufname('%'))
+ call assert_equal('testtext 1', getline(1))
+
+ set nohidden
+
+ " test ":all!" hides changed buffer
+ split Xtest4
+ call setline(1, 'testtext 4')
+ all!
+ 1wincmd w
+ call assert_equal('Xtest2', bufname('%'))
+ call assert_equal('testtext 2 2 2', getline(1))
+
+ " test ":q!" and hidden buffer.
+ bwipe! Xtest1 Xtest2 Xtest3 Xtest4
+ split Xtest1
+ wincmd w
+ bwipe!
+ set modified
+ bot split Xtest2
+ set modified
+ bot split Xtest3
+ set modified
+ wincmd t
+ hide
+ call assert_equal('Xtest2', bufname('%'))
+ quit!
+ call assert_equal('Xtest3', bufname('%'))
+ call assert_fails('silent! quit!', 'E162')
+ call assert_equal('Xtest1', bufname('%'))
+
+ call delete('Xtest1')
+ call delete('Xtest2')
+ call delete('Xtest3')
+endfunc
+
+" Test that ":close" will respect 'winfixheight' when possible.
+func Test_winfixheight_on_close()
+ set nosplitbelow nosplitright
+
+ split | split | vsplit
+
+ $wincmd w
+ setlocal winfixheight
+ let l:height = winheight(0)
+
+ 3close
+
+ call assert_equal(l:height, winheight(0))
+
+ %bwipeout!
+ setlocal nowinfixheight splitbelow& splitright&
+endfunc
+
+" Test that ":close" will respect 'winfixwidth' when possible.
+func Test_winfixwidth_on_close()
+ set nosplitbelow nosplitright
+
+ vsplit | vsplit | split
+
+ $wincmd w
+ setlocal winfixwidth
+ let l:width = winwidth(0)
+
+ 3close
+
+ call assert_equal(l:width, winwidth(0))
+
+ %bwipeout!
+ setlocal nowinfixwidth splitbelow& splitright&
+endfunction
diff --git a/src/testdir/test_window_cmd.vim b/src/testdir/test_window_cmd.vim
new file mode 100644
index 0000000..587ae23
--- /dev/null
+++ b/src/testdir/test_window_cmd.vim
@@ -0,0 +1,618 @@
+" Tests for window cmd (:wincmd, :split, :vsplit, :resize and etc...)
+
+func Test_window_cmd_ls0_with_split()
+ set ls=0
+ set splitbelow
+ split
+ quit
+ call assert_equal(0, &lines - &cmdheight - winheight(0))
+ new | only!
+ "
+ set splitbelow&vim
+ botright split
+ quit
+ call assert_equal(0, &lines - &cmdheight - winheight(0))
+ new | only!
+ set ls&vim
+endfunc
+
+func Test_window_cmd_cmdwin_with_vsp()
+ let efmt = 'Expected 0 but got %d (in ls=%d, %s window)'
+ for v in range(0, 2)
+ exec "set ls=" . v
+ vsplit
+ call feedkeys("q:\<CR>")
+ let ac = &lines - (&cmdheight + winheight(0) + !!v)
+ let emsg = printf(efmt, ac, v, 'left')
+ call assert_equal(0, ac, emsg)
+ wincmd w
+ let ac = &lines - (&cmdheight + winheight(0) + !!v)
+ let emsg = printf(efmt, ac, v, 'right')
+ call assert_equal(0, ac, emsg)
+ new | only!
+ endfor
+ set ls&vim
+endfunc
+
+function Test_window_cmd_wincmd_gf()
+ let fname = 'test_gf.txt'
+ let swp_fname = '.' . fname . '.swp'
+ call writefile([], fname)
+ call writefile([], swp_fname)
+ function s:swap_exists()
+ let v:swapchoice = s:swap_choice
+ endfunc
+ augroup test_window_cmd_wincmd_gf
+ autocmd!
+ exec "autocmd SwapExists " . fname . " call s:swap_exists()"
+ augroup END
+
+ call setline(1, fname)
+ " (E)dit anyway
+ let s:swap_choice = 'e'
+ wincmd gf
+ call assert_equal(2, tabpagenr())
+ call assert_equal(fname, bufname("%"))
+ quit!
+
+ " (Q)uit
+ let s:swap_choice = 'q'
+ wincmd gf
+ call assert_equal(1, tabpagenr())
+ call assert_notequal(fname, bufname("%"))
+ new | only!
+
+ call delete(fname)
+ call delete(swp_fname)
+ augroup! test_window_cmd_wincmd_gf
+endfunc
+
+func Test_window_quit()
+ e Xa
+ split Xb
+ call assert_equal(2, winnr('$'))
+ call assert_equal('Xb', bufname(winbufnr(1)))
+ call assert_equal('Xa', bufname(winbufnr(2)))
+
+ wincmd q
+ call assert_equal(1, winnr('$'))
+ call assert_equal('Xa', bufname(winbufnr(1)))
+
+ bw Xa Xb
+endfunc
+
+func Test_window_horizontal_split()
+ call assert_equal(1, winnr('$'))
+ 3wincmd s
+ call assert_equal(2, winnr('$'))
+ call assert_equal(3, winheight(0))
+ call assert_equal(winwidth(1), winwidth(2))
+
+ call assert_fails('botright topleft wincmd s', 'E442:')
+ bw
+endfunc
+
+func Test_window_vertical_split()
+ call assert_equal(1, winnr('$'))
+ 3wincmd v
+ call assert_equal(2, winnr('$'))
+ call assert_equal(3, winwidth(0))
+ call assert_equal(winheight(1), winheight(2))
+
+ call assert_fails('botright topleft wincmd v', 'E442:')
+ bw
+endfunc
+
+" Test the ":wincmd ^" and "<C-W>^" commands.
+func Test_window_split_edit_alternate()
+
+ " Test for failure when the alternate buffer/file no longer exists.
+ edit Xfoo | %bw
+ call assert_fails(':wincmd ^', 'E23')
+
+ " Test for the expected behavior when we have two named buffers.
+ edit Xfoo | edit Xbar
+ wincmd ^
+ call assert_equal('Xfoo', bufname(winbufnr(1)))
+ call assert_equal('Xbar', bufname(winbufnr(2)))
+ only
+
+ " Test for the expected behavior when the alternate buffer is not named.
+ enew | let l:nr1 = bufnr('%')
+ edit Xfoo | let l:nr2 = bufnr('%')
+ wincmd ^
+ call assert_equal(l:nr1, winbufnr(1))
+ call assert_equal(l:nr2, winbufnr(2))
+ only
+
+ " FIXME: this currently fails on AppVeyor, but passes locally
+ if !has('win32')
+ " Test the Normal mode command.
+ call feedkeys("\<C-W>\<C-^>", 'tx')
+ call assert_equal(l:nr2, winbufnr(1))
+ call assert_equal(l:nr1, winbufnr(2))
+ endif
+
+ %bw!
+endfunc
+
+" Test the ":[count]wincmd ^" and "[count]<C-W>^" commands.
+func Test_window_split_edit_bufnr()
+
+ %bwipeout
+ let l:nr = bufnr('%') + 1
+ call assert_fails(':execute "normal! ' . l:nr . '\<C-W>\<C-^>"', 'E92')
+ call assert_fails(':' . l:nr . 'wincmd ^', 'E16')
+ call assert_fails(':0wincmd ^', 'E16')
+
+ edit Xfoo | edit Xbar | edit Xbaz
+ let l:foo_nr = bufnr('Xfoo')
+ let l:bar_nr = bufnr('Xbar')
+ let l:baz_nr = bufnr('Xbaz')
+
+ " FIXME: this currently fails on AppVeyor, but passes locally
+ if !has('win32')
+ call feedkeys(l:foo_nr . "\<C-W>\<C-^>", 'tx')
+ call assert_equal('Xfoo', bufname(winbufnr(1)))
+ call assert_equal('Xbaz', bufname(winbufnr(2)))
+ only
+
+ call feedkeys(l:bar_nr . "\<C-W>\<C-^>", 'tx')
+ call assert_equal('Xbar', bufname(winbufnr(1)))
+ call assert_equal('Xfoo', bufname(winbufnr(2)))
+ only
+
+ execute l:baz_nr . 'wincmd ^'
+ call assert_equal('Xbaz', bufname(winbufnr(1)))
+ call assert_equal('Xbar', bufname(winbufnr(2)))
+ endif
+
+ %bw!
+endfunc
+
+func Test_window_preview()
+ " Open a preview window
+ pedit Xa
+ call assert_equal(2, winnr('$'))
+ call assert_equal(0, &previewwindow)
+
+ " Go to the preview window
+ wincmd P
+ call assert_equal(1, &previewwindow)
+
+ " Close preview window
+ wincmd z
+ call assert_equal(1, winnr('$'))
+ call assert_equal(0, &previewwindow)
+
+ call assert_fails('wincmd P', 'E441:')
+endfunc
+
+func Test_window_exchange()
+ e Xa
+
+ " Nothing happens with window exchange when there is 1 window
+ wincmd x
+ call assert_equal(1, winnr('$'))
+
+ split Xb
+ split Xc
+
+ call assert_equal('Xc', bufname(winbufnr(1)))
+ call assert_equal('Xb', bufname(winbufnr(2)))
+ call assert_equal('Xa', bufname(winbufnr(3)))
+
+ " Exchange current window 1 with window 3
+ 3wincmd x
+ call assert_equal('Xa', bufname(winbufnr(1)))
+ call assert_equal('Xb', bufname(winbufnr(2)))
+ call assert_equal('Xc', bufname(winbufnr(3)))
+
+ " Exchange window with next when at the top window
+ wincmd x
+ call assert_equal('Xb', bufname(winbufnr(1)))
+ call assert_equal('Xa', bufname(winbufnr(2)))
+ call assert_equal('Xc', bufname(winbufnr(3)))
+
+ " Exchange window with next when at the middle window
+ wincmd j
+ wincmd x
+ call assert_equal('Xb', bufname(winbufnr(1)))
+ call assert_equal('Xc', bufname(winbufnr(2)))
+ call assert_equal('Xa', bufname(winbufnr(3)))
+
+ " Exchange window with next when at the bottom window.
+ " When there is no next window, it exchanges with the previous window.
+ wincmd j
+ wincmd x
+ call assert_equal('Xb', bufname(winbufnr(1)))
+ call assert_equal('Xa', bufname(winbufnr(2)))
+ call assert_equal('Xc', bufname(winbufnr(3)))
+
+ bw Xa Xb Xc
+endfunc
+
+func Test_window_rotate()
+ e Xa
+ split Xb
+ split Xc
+ call assert_equal('Xc', bufname(winbufnr(1)))
+ call assert_equal('Xb', bufname(winbufnr(2)))
+ call assert_equal('Xa', bufname(winbufnr(3)))
+
+ " Rotate downwards
+ wincmd r
+ call assert_equal('Xa', bufname(winbufnr(1)))
+ call assert_equal('Xc', bufname(winbufnr(2)))
+ call assert_equal('Xb', bufname(winbufnr(3)))
+
+ 2wincmd r
+ call assert_equal('Xc', bufname(winbufnr(1)))
+ call assert_equal('Xb', bufname(winbufnr(2)))
+ call assert_equal('Xa', bufname(winbufnr(3)))
+
+ " Rotate upwards
+ wincmd R
+ call assert_equal('Xb', bufname(winbufnr(1)))
+ call assert_equal('Xa', bufname(winbufnr(2)))
+ call assert_equal('Xc', bufname(winbufnr(3)))
+
+ 2wincmd R
+ call assert_equal('Xc', bufname(winbufnr(1)))
+ call assert_equal('Xb', bufname(winbufnr(2)))
+ call assert_equal('Xa', bufname(winbufnr(3)))
+
+ bot vsplit
+ call assert_fails('wincmd R', 'E443:')
+
+ bw Xa Xb Xc
+endfunc
+
+func Test_window_height()
+ e Xa
+ split Xb
+
+ let [wh1, wh2] = [winheight(1), winheight(2)]
+ " Active window (1) should have the same height or 1 more
+ " than the other window.
+ call assert_inrange(wh2, wh2 + 1, wh1)
+
+ wincmd -
+ call assert_equal(wh1 - 1, winheight(1))
+ call assert_equal(wh2 + 1, winheight(2))
+
+ wincmd +
+ call assert_equal(wh1, winheight(1))
+ call assert_equal(wh2, winheight(2))
+
+ 2wincmd _
+ call assert_equal(2, winheight(1))
+ call assert_equal(wh1 + wh2 - 2, winheight(2))
+
+ wincmd =
+ call assert_equal(wh1, winheight(1))
+ call assert_equal(wh2, winheight(2))
+
+ 2wincmd _
+ set winfixheight
+ split Xc
+ let [wh1, wh2, wh3] = [winheight(1), winheight(2), winheight(3)]
+ call assert_equal(2, winheight(2))
+ call assert_inrange(wh3, wh3 + 1, wh1)
+ 3wincmd +
+ call assert_equal(2, winheight(2))
+ call assert_equal(wh1 + 3, winheight(1))
+ call assert_equal(wh3 - 3, winheight(3))
+ wincmd =
+ call assert_equal(2, winheight(2))
+ call assert_equal(wh1, winheight(1))
+ call assert_equal(wh3, winheight(3))
+
+ wincmd j
+ set winfixheight&
+
+ wincmd =
+ let [wh1, wh2, wh3] = [winheight(1), winheight(2), winheight(3)]
+ " Current window (2) should have the same height or 1 more
+ " than the other windows.
+ call assert_inrange(wh1, wh1 + 1, wh2)
+ call assert_inrange(wh3, wh3 + 1, wh2)
+
+ bw Xa Xb Xc
+endfunc
+
+func Test_window_width()
+ e Xa
+ vsplit Xb
+
+ let [ww1, ww2] = [winwidth(1), winwidth(2)]
+ " Active window (1) should have the same width or 1 more
+ " than the other window.
+ call assert_inrange(ww2, ww2 + 1, ww1)
+
+ wincmd <
+ call assert_equal(ww1 - 1, winwidth(1))
+ call assert_equal(ww2 + 1, winwidth(2))
+
+ wincmd >
+ call assert_equal(ww1, winwidth(1))
+ call assert_equal(ww2, winwidth(2))
+
+ 2wincmd |
+ call assert_equal(2, winwidth(1))
+ call assert_equal(ww1 + ww2 - 2, winwidth(2))
+
+ wincmd =
+ call assert_equal(ww1, winwidth(1))
+ call assert_equal(ww2, winwidth(2))
+
+ 2wincmd |
+ set winfixwidth
+ vsplit Xc
+ let [ww1, ww2, ww3] = [winwidth(1), winwidth(2), winwidth(3)]
+ call assert_equal(2, winwidth(2))
+ call assert_inrange(ww3, ww3 + 1, ww1)
+ 3wincmd >
+ call assert_equal(2, winwidth(2))
+ call assert_equal(ww1 + 3, winwidth(1))
+ call assert_equal(ww3 - 3, winwidth(3))
+ wincmd =
+ call assert_equal(2, winwidth(2))
+ call assert_equal(ww1, winwidth(1))
+ call assert_equal(ww3, winwidth(3))
+
+ wincmd l
+ set winfixwidth&
+
+ wincmd =
+ let [ww1, ww2, ww3] = [winwidth(1), winwidth(2), winwidth(3)]
+ " Current window (2) should have the same width or 1 more
+ " than the other windows.
+ call assert_inrange(ww1, ww1 + 1, ww2)
+ call assert_inrange(ww3, ww3 + 1, ww2)
+
+ bw Xa Xb Xc
+endfunc
+
+func Test_equalalways_on_close()
+ set equalalways
+ vsplit
+ windo split
+ split
+ wincmd J
+ " now we have a frame top-left with two windows, a frame top-right with two
+ " windows and a frame at the bottom, full-width.
+ let height_1 = winheight(1)
+ let height_2 = winheight(2)
+ let height_3 = winheight(3)
+ let height_4 = winheight(4)
+ " closing the bottom window causes all windows to be resized.
+ close
+ call assert_notequal(height_1, winheight(1))
+ call assert_notequal(height_2, winheight(2))
+ call assert_notequal(height_3, winheight(3))
+ call assert_notequal(height_4, winheight(4))
+ call assert_equal(winheight(1), winheight(3))
+ call assert_equal(winheight(2), winheight(4))
+
+ 1wincmd w
+ split
+ 4wincmd w
+ resize + 5
+ " left column has three windows, equalized heights.
+ " right column has two windows, top one a bit higher
+ let height_1 = winheight(1)
+ let height_2 = winheight(2)
+ let height_4 = winheight(4)
+ let height_5 = winheight(5)
+ 3wincmd w
+ " closing window in left column equalizes heights in left column but not in
+ " the right column
+ close
+ call assert_notequal(height_1, winheight(1))
+ call assert_notequal(height_2, winheight(2))
+ call assert_equal(height_4, winheight(3))
+ call assert_equal(height_5, winheight(4))
+
+ only
+ set equalalways&
+endfunc
+
+func Test_win_screenpos()
+ call assert_equal(1, winnr('$'))
+ split
+ vsplit
+ 10wincmd _
+ 30wincmd |
+ call assert_equal([1, 1], win_screenpos(1))
+ call assert_equal([1, 32], win_screenpos(2))
+ call assert_equal([12, 1], win_screenpos(3))
+ call assert_equal([0, 0], win_screenpos(4))
+ only
+endfunc
+
+func Test_window_jump_tag()
+ help
+ /iccf
+ call assert_match('^|iccf|', getline('.'))
+ call assert_equal(2, winnr('$'))
+ 2wincmd }
+ call assert_equal(3, winnr('$'))
+ call assert_match('^|iccf|', getline('.'))
+ wincmd k
+ call assert_match('\*iccf\*', getline('.'))
+ call assert_equal(2, winheight(0))
+
+ wincmd z
+ set previewheight=4
+ help
+ /bugs
+ wincmd }
+ wincmd k
+ call assert_match('\*bugs\*', getline('.'))
+ call assert_equal(4, winheight(0))
+ set previewheight&
+
+ %bw!
+endfunc
+
+func Test_window_newtab()
+ e Xa
+
+ call assert_equal(1, tabpagenr('$'))
+ call assert_equal("\nAlready only one window", execute('wincmd T'))
+
+ split Xb
+ split Xc
+
+ wincmd T
+ call assert_equal(2, tabpagenr('$'))
+ call assert_equal(['Xb', 'Xa'], map(tabpagebuflist(1), 'bufname(v:val)'))
+ call assert_equal(['Xc' ], map(tabpagebuflist(2), 'bufname(v:val)'))
+
+ %bw!
+endfunc
+
+func Test_next_split_all()
+ " This was causing an illegal memory access.
+ n x
+ norm axxx
+ split
+ split
+ s/x
+ s/x
+ all
+ bwipe!
+endfunc
+
+" Tests for adjusting window and contents
+func GetScreenStr(row)
+ let str = ""
+ for c in range(1,3)
+ let str .= nr2char(screenchar(a:row, c))
+ endfor
+ return str
+endfunc
+
+func Test_window_contents()
+ enew! | only | new
+ call setline(1, range(1,256))
+
+ exe "norm! \<C-W>t\<C-W>=1Gzt\<C-W>w\<C-W>+"
+ redraw
+ let s3 = GetScreenStr(1)
+ wincmd p
+ call assert_equal(1, line("w0"))
+ call assert_equal('1 ', s3)
+
+ exe "norm! \<C-W>t\<C-W>=50Gzt\<C-W>w\<C-W>+"
+ redraw
+ let s3 = GetScreenStr(1)
+ wincmd p
+ call assert_equal(50, line("w0"))
+ call assert_equal('50 ', s3)
+
+ exe "norm! \<C-W>t\<C-W>=59Gzt\<C-W>w\<C-W>+"
+ redraw
+ let s3 = GetScreenStr(1)
+ wincmd p
+ call assert_equal(59, line("w0"))
+ call assert_equal('59 ', s3)
+
+ bwipeout!
+ call test_garbagecollect_now()
+endfunc
+
+func Test_window_colon_command()
+ " This was reading invalid memory.
+ exe "norm! v\<C-W>:\<C-U>echo v:version"
+endfunc
+
+func Test_access_freed_mem()
+ " This was accessing freed memory
+ au * 0 vs xxx
+ arg 0
+ argadd
+ all
+ all
+ au!
+ bwipe xxx
+endfunc
+
+func Test_visual_cleared_after_window_split()
+ new | only!
+ let smd_save = &showmode
+ set showmode
+ let ls_save = &laststatus
+ set laststatus=1
+ call setline(1, ['a', 'b', 'c', 'd', ''])
+ norm! G
+ exe "norm! kkvk"
+ redraw
+ exe "norm! \<C-W>v"
+ redraw
+ " check if '-- VISUAL --' disappeared from command line
+ let columns = range(1, &columns)
+ let cmdlinechars = map(columns, 'nr2char(screenchar(&lines, v:val))')
+ let cmdline = join(cmdlinechars, '')
+ let cmdline_ltrim = substitute(cmdline, '^\s*', "", "")
+ let mode_shown = substitute(cmdline_ltrim, '\s*$', "", "")
+ call assert_equal('', mode_shown)
+ let &showmode = smd_save
+ let &laststatus = ls_save
+ bwipe!
+endfunc
+
+func Test_winrestcmd()
+ 2split
+ 3vsplit
+ let a = winrestcmd()
+ call assert_equal(2, winheight(0))
+ call assert_equal(3, winwidth(0))
+ wincmd =
+ call assert_notequal(2, winheight(0))
+ call assert_notequal(3, winwidth(0))
+ exe a
+ call assert_equal(2, winheight(0))
+ call assert_equal(3, winwidth(0))
+ only
+endfunc
+
+func Fun_RenewFile()
+ sleep 2
+ silent execute '!echo "1" > tmp.txt'
+ sp
+ wincmd p
+ edit! tmp.txt
+endfunc
+
+func Test_window_prevwin()
+ " Can we make this work on MS-Windows?
+ if !has('unix')
+ return
+ endif
+
+ set hidden autoread
+ call writefile(['2'], 'tmp.txt')
+ new tmp.txt
+ q
+ " Need to wait a bit for the timestamp to be older.
+ call Fun_RenewFile()
+ call assert_equal(2, winnr())
+ wincmd p
+ call assert_equal(1, winnr())
+ wincmd p
+ q
+ call Fun_RenewFile()
+ call assert_equal(2, winnr())
+ wincmd p
+ call assert_equal(1, winnr())
+ wincmd p
+ " reset
+ q
+ call delete('tmp.txt')
+ set hidden&vim autoread&vim
+ delfunc Fun_RenewFile
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/test_window_id.vim b/src/testdir/test_window_id.vim
new file mode 100644
index 0000000..d10d831
--- /dev/null
+++ b/src/testdir/test_window_id.vim
@@ -0,0 +1,123 @@
+" Test using the window ID.
+
+func Test_win_getid()
+ edit one
+ let id1 = win_getid()
+ let w:one = 'one'
+ split two
+ let id2 = win_getid()
+ let bufnr2 = bufnr('%')
+ let w:two = 'two'
+ split three
+ let id3 = win_getid()
+ let w:three = 'three'
+ tabnew
+ edit four
+ let id4 = win_getid()
+ let w:four = 'four'
+ split five
+ let id5 = win_getid()
+ let bufnr5 = bufnr('%')
+ let w:five = 'five'
+ tabnext
+
+ wincmd w
+ call assert_equal("two", expand("%"))
+ call assert_equal(id2, win_getid())
+ let nr2 = winnr()
+ wincmd w
+ call assert_equal("one", expand("%"))
+ call assert_equal(id1, win_getid())
+ let nr1 = winnr()
+ wincmd w
+ call assert_equal("three", expand("%"))
+ call assert_equal(id3, win_getid())
+ let nr3 = winnr()
+ call assert_equal('one', getwinvar(id1, 'one'))
+ call assert_equal('two', getwinvar(id2, 'two'))
+ call assert_equal('three', getwinvar(id3, 'three'))
+ tabnext
+ call assert_equal("five", expand("%"))
+ call assert_equal(id5, win_getid())
+ let nr5 = winnr()
+ wincmd w
+ call assert_equal("four", expand("%"))
+ call assert_equal(id4, win_getid())
+ let nr4 = winnr()
+ call assert_equal('four', getwinvar(id4, 'four'))
+ call assert_equal('five', getwinvar(id5, 'five'))
+ call settabwinvar(1, id2, 'two', '2')
+ call setwinvar(id4, 'four', '4')
+ tabnext
+ call assert_equal('4', gettabwinvar(2, id4, 'four'))
+ call assert_equal('five', gettabwinvar(2, id5, 'five'))
+ call assert_equal('2', getwinvar(id2, 'two'))
+
+ exe nr1 . "wincmd w"
+ call assert_equal(id1, win_getid())
+ exe nr2 . "wincmd w"
+ call assert_equal(id2, win_getid())
+ exe nr3 . "wincmd w"
+ call assert_equal(id3, win_getid())
+ tabnext
+ exe nr4 . "wincmd w"
+ call assert_equal(id4, win_getid())
+ exe nr5 . "wincmd w"
+ call assert_equal(id5, win_getid())
+
+ call win_gotoid(id2)
+ call assert_equal("two", expand("%"))
+ call win_gotoid(id4)
+ call assert_equal("four", expand("%"))
+ call win_gotoid(id1)
+ call assert_equal("one", expand("%"))
+ call win_gotoid(id5)
+ call assert_equal("five", expand("%"))
+
+ call assert_equal(0, win_id2win(9999))
+ call assert_equal(nr5, win_id2win(id5))
+ call assert_equal(0, win_id2win(id1))
+ tabnext
+ call assert_equal(nr1, win_id2win(id1))
+
+ call assert_equal([0, 0], win_id2tabwin(9999))
+ call assert_equal([1, nr2], win_id2tabwin(id2))
+ call assert_equal([2, nr4], win_id2tabwin(id4))
+
+ call assert_equal([], win_findbuf(9999))
+ call assert_equal([id2], win_findbuf(bufnr2))
+ call win_gotoid(id5)
+ split
+ call assert_equal(sort([id5, win_getid()]), sort(win_findbuf(bufnr5)))
+
+ only!
+endfunc
+
+func Test_win_getid_curtab()
+ tabedit X
+ tabfirst
+ copen
+ only
+ call assert_equal(win_getid(1), win_getid(1, 1))
+ tabclose!
+endfunc
+
+func Test_winlayout()
+ let w1 = win_getid()
+ call assert_equal(['leaf', w1], winlayout())
+
+ split
+ let w2 = win_getid()
+ call assert_equal(['col', [['leaf', w2], ['leaf', w1]]], winlayout())
+
+ split
+ let w3 = win_getid()
+ call assert_equal(['col', [['leaf', w3], ['leaf', w2], ['leaf', w1]]], winlayout())
+
+ 2wincmd w
+ vsplit
+ let w4 = win_getid()
+ call assert_equal(['col', [['leaf', w3], ['row', [['leaf', w4], ['leaf', w2]]], ['leaf', w1]]], winlayout())
+
+ only!
+endfunc
diff --git a/src/testdir/test_windows_home.vim b/src/testdir/test_windows_home.vim
new file mode 100644
index 0000000..2e311b9
--- /dev/null
+++ b/src/testdir/test_windows_home.vim
@@ -0,0 +1,121 @@
+" Test for $HOME on Windows.
+
+if !has('win32')
+ finish
+endif
+
+let s:env = {}
+
+func s:restore_env()
+ for i in keys(s:env)
+ exe 'let ' . i . '=s:env["' . i . '"]'
+ endfor
+endfunc
+
+func s:save_env(...)
+ for i in a:000
+ exe 'let s:env["' . i . '"]=' . i
+ endfor
+endfunc
+
+func s:unlet_env(...)
+ for i in a:000
+ exe 'let ' . i . '=""'
+ endfor
+endfunc
+
+func CheckHomeIsMissingFromSubprocessEnvironment()
+ silent! let out = system('set')
+ let env = filter(split(out, "\n"), 'v:val=~"^HOME="')
+ call assert_equal(0, len(env))
+endfunc
+
+func CheckHomeIsInSubprocessEnvironment(exp)
+ silent! let out = system('set')
+ let env = filter(split(out, "\n"), 'v:val=~"^HOME="')
+ let home = len(env) == 0 ? "" : substitute(env[0], '[^=]\+=', '', '')
+ call assert_equal(a:exp, home)
+endfunc
+
+func CheckHome(exp, ...)
+ call assert_equal(a:exp, $HOME)
+ call assert_equal(a:exp, expand('~', ':p'))
+ if !a:0
+ call CheckHomeIsMissingFromSubprocessEnvironment()
+ else
+ call CheckHomeIsInSubprocessEnvironment(a:1)
+ endif
+endfunc
+
+func Test_WindowsHome()
+ command! -nargs=* SaveEnv call <SID>save_env(<f-args>)
+ command! -nargs=* RestoreEnv call <SID>restore_env()
+ command! -nargs=* UnletEnv call <SID>unlet_env(<f-args>)
+ set noshellslash
+
+ let save_home = $HOME
+ SaveEnv $USERPROFILE $HOMEDRIVE $HOMEPATH
+ try
+ " Normal behavior: use $HOMEDRIVE and $HOMEPATH, ignore $USERPROFILE
+ let $USERPROFILE = 'unused'
+ let $HOMEDRIVE = 'C:'
+ let $HOMEPATH = '\foobar'
+ let $HOME = '' " Force recomputing "homedir"
+ call CheckHome('C:\foobar')
+
+ " Same, but with $HOMEPATH not set
+ UnletEnv $HOMEPATH
+ let $HOME = '' " Force recomputing "homedir"
+ call CheckHome('C:\')
+
+ " Use $USERPROFILE if $HOMEPATH and $HOMEDRIVE are empty
+ UnletEnv $HOMEDRIVE $HOMEPATH
+ let $USERPROFILE = 'C:\foo'
+ let $HOME = '' " Force recomputing "homedir"
+ call CheckHome('C:\foo')
+
+ " If $HOME is set the others don't matter
+ let $HOME = 'C:\bar'
+ let $USERPROFILE = 'unused'
+ let $HOMEDRIVE = 'unused'
+ let $HOMEPATH = 'unused'
+ call CheckHome('C:\bar', 'C:\bar')
+
+ " If $HOME contains %USERPROFILE% it is expanded
+ let $USERPROFILE = 'C:\foo'
+ let $HOME = '%USERPROFILE%\bar'
+ let $HOMEDRIVE = 'unused'
+ let $HOMEPATH = 'unused'
+ call CheckHome('C:\foo\bar', '%USERPROFILE%\bar')
+
+ " Invalid $HOME is kept
+ let $USERPROFILE = 'C:\foo'
+ let $HOME = '%USERPROFILE'
+ let $HOMEDRIVE = 'unused'
+ let $HOMEPATH = 'unused'
+ call CheckHome('%USERPROFILE', '%USERPROFILE')
+
+ " %USERPROFILE% not at start of $HOME is not expanded
+ let $USERPROFILE = 'unused'
+ let $HOME = 'C:\%USERPROFILE%'
+ let $HOMEDRIVE = 'unused'
+ let $HOMEPATH = 'unused'
+ call CheckHome('C:\%USERPROFILE%', 'C:\%USERPROFILE%')
+
+ if has('channel')
+ RestoreEnv
+ let $HOME = save_home
+ let env = ''
+ let job = job_start('cmd /c set', {'out_cb': {ch,x->[env,execute('let env=x')]}})
+ sleep 1
+ let env = filter(split(env, "\n"), 'v:val=="HOME"')
+ let home = len(env) == 0 ? "" : env[0]
+ call assert_equal('', home)
+ endif
+ finally
+ RestoreEnv
+ delcommand SaveEnv
+ delcommand RestoreEnv
+ delcommand UnletEnv
+ endtry
+endfunc
diff --git a/src/testdir/test_wordcount.vim b/src/testdir/test_wordcount.vim
new file mode 100644
index 0000000..6a3d410
--- /dev/null
+++ b/src/testdir/test_wordcount.vim
@@ -0,0 +1,104 @@
+" Test for wordcount() function
+
+func Test_wordcount()
+ let save_enc = &enc
+ set encoding=utf-8
+ set selection=inclusive fileformat=unix fileformats=unix
+
+ new
+
+ " Test 1: empty window
+ call assert_equal({'chars': 0, 'cursor_chars': 0, 'words': 0, 'cursor_words': 0,
+ \ 'bytes': 0, 'cursor_bytes': 0}, wordcount())
+
+ " Test 2: some words, cursor at start
+ call append(1, 'one two three')
+ call cursor([1, 1, 0])
+ call assert_equal({'chars': 15, 'cursor_chars': 1, 'words': 3, 'cursor_words': 0,
+ \ 'bytes': 15, 'cursor_bytes': 1}, wordcount())
+
+ " Test 3: some words, cursor at end
+ %d _
+ call append(1, 'one two three')
+ call cursor([2, 99, 0])
+ call assert_equal({'chars': 15, 'cursor_chars': 14, 'words': 3, 'cursor_words': 3,
+ \ 'bytes': 15, 'cursor_bytes': 14}, wordcount())
+
+ " Test 4: some words, cursor at end, ve=all
+ set ve=all
+ %d _
+ call append(1, 'one two three')
+ call cursor([2, 99, 0])
+ call assert_equal({'chars': 15, 'cursor_chars': 15, 'words': 3, 'cursor_words': 3,
+ \ 'bytes': 15, 'cursor_bytes': 15}, wordcount())
+ set ve=
+
+ " Test 5: several lines with words
+ %d _
+ call append(1, ['one two three', 'one two three', 'one two three'])
+ call cursor([4, 99, 0])
+ call assert_equal({'chars': 43, 'cursor_chars': 42, 'words': 9, 'cursor_words': 9,
+ \ 'bytes': 43, 'cursor_bytes': 42}, wordcount())
+
+ " Test 6: one line with BOM set
+ %d _
+ call append(1, 'one two three')
+ set bomb
+ w! Xtest
+ call cursor([2, 99, 0])
+ call assert_equal({'chars': 15, 'cursor_chars': 14, 'words': 3, 'cursor_words': 3,
+ \ 'bytes': 18, 'cursor_bytes': 14}, wordcount())
+ set nobomb
+ w!
+ call delete('Xtest')
+
+ " Test 7: one line with multibyte words
+ %d _
+ call append(1, ['Äne M¤ne Müh'])
+ call cursor([2, 99, 0])
+ call assert_equal({'chars': 14, 'cursor_chars': 13, 'words': 3, 'cursor_words': 3,
+ \ 'bytes': 17, 'cursor_bytes': 16}, wordcount())
+
+ " Test 8: several lines with multibyte words
+ %d _
+ call append(1, ['Äne M¤ne Müh', 'und raus bist dü!'])
+ call cursor([3, 99, 0])
+ call assert_equal({'chars': 32, 'cursor_chars': 31, 'words': 7, 'cursor_words': 7,
+ \ 'bytes': 36, 'cursor_bytes': 35}, wordcount())
+
+ " Visual map to capture wordcount() in visual mode
+ vnoremap <expr> <F2> execute("let g:visual_stat = wordcount()")
+
+ " Test 9: visual mode, complete buffer
+ let g:visual_stat = {}
+ %d _
+ call append(1, ['Äne M¤ne Müh', 'und raus bist dü!'])
+ " start visual mode and select the complete buffer
+ 0
+ exe "normal V2j\<F2>y"
+ call assert_equal({'chars': 32, 'words': 7, 'bytes': 36, 'visual_chars': 32,
+ \ 'visual_words': 7, 'visual_bytes': 36}, g:visual_stat)
+
+ " Test 10: visual mode (empty)
+ %d _
+ call append(1, ['Äne M¤ne Müh', 'und raus bist dü!'])
+ " start visual mode and select the complete buffer
+ 0
+ exe "normal v$\<F2>y"
+ call assert_equal({'chars': 32, 'words': 7, 'bytes': 36, 'visual_chars': 1,
+ \ 'visual_words': 0, 'visual_bytes': 1}, g:visual_stat)
+
+ " Test 11: visual mode, single line
+ %d _
+ call append(1, ['Äne M¤ne Müh', 'und raus bist dü!'])
+ " start visual mode and select the complete buffer
+ 2
+ exe "normal 0v$\<F2>y"
+ call assert_equal({'chars': 32, 'words': 7, 'bytes': 36, 'visual_chars': 13,
+ \ 'visual_words': 3, 'visual_bytes': 16}, g:visual_stat)
+
+ set selection& fileformat& fileformats&
+ let &enc = save_enc
+ enew!
+ close
+endfunc
diff --git a/src/testdir/test_writefile.vim b/src/testdir/test_writefile.vim
new file mode 100644
index 0000000..ff36756
--- /dev/null
+++ b/src/testdir/test_writefile.vim
@@ -0,0 +1,152 @@
+" Tests for the writefile() function.
+
+func Test_writefile()
+ let f = tempname()
+ call writefile(["over","written"], f, "b")
+ call writefile(["hello","world"], f, "b")
+ call writefile(["!", "good"], f, "a")
+ call writefile(["morning"], f, "ab")
+ call writefile(["", "vimmers"], f, "ab")
+ let l = readfile(f)
+ call assert_equal("hello", l[0])
+ call assert_equal("world!", l[1])
+ call assert_equal("good", l[2])
+ call assert_equal("morning", l[3])
+ call assert_equal("vimmers", l[4])
+ call delete(f)
+endfunc
+
+func Test_writefile_fails_gently()
+ call assert_fails('call writefile(["test"], "Xfile", [])', 'E730:')
+ call assert_false(filereadable("Xfile"))
+ call delete("Xfile")
+
+ call assert_fails('call writefile(["test", [], [], [], "tset"], "Xfile")', 'E730:')
+ call assert_false(filereadable("Xfile"))
+ call delete("Xfile")
+
+ call assert_fails('call writefile([], "Xfile", [])', 'E730:')
+ call assert_false(filereadable("Xfile"))
+ call delete("Xfile")
+
+ call assert_fails('call writefile([], [])', 'E730:')
+endfunc
+
+func Test_writefile_fails_conversion()
+ if !has('iconv') || has('sun')
+ return
+ endif
+ set nobackup nowritebackup
+ new
+ let contents = ["line one", "line two"]
+ call writefile(contents, 'Xfile')
+ edit Xfile
+ call setline(1, ["first line", "cannot convert \u010b", "third line"])
+ call assert_fails('write ++enc=cp932')
+ call assert_equal(contents, readfile('Xfile'))
+
+ call delete('Xfile')
+ bwipe!
+ set backup& writebackup&
+endfunc
+
+func SetFlag(timer)
+ let g:flag = 1
+endfunc
+
+func Test_write_quit_split()
+ " Prevent exiting by splitting window on file write.
+ augroup testgroup
+ autocmd BufWritePre * split
+ augroup END
+ e! Xfile
+ call setline(1, 'nothing')
+ wq
+
+ if has('timers')
+ " timer will not run if "exiting" is still set
+ let g:flag = 0
+ call timer_start(1, 'SetFlag')
+ sleep 50m
+ call assert_equal(1, g:flag)
+ unlet g:flag
+ endif
+ au! testgroup
+ bwipe Xfile
+ call delete('Xfile')
+endfunc
+
+func Test_nowrite_quit_split()
+ " Prevent exiting by opening a help window.
+ e! Xfile
+ help
+ wincmd w
+ exe winnr() . 'q'
+
+ if has('timers')
+ " timer will not run if "exiting" is still set
+ let g:flag = 0
+ call timer_start(1, 'SetFlag')
+ sleep 50m
+ call assert_equal(1, g:flag)
+ unlet g:flag
+ endif
+ bwipe Xfile
+endfunc
+
+func Test_writefile_sync_arg()
+ " This doesn't check if fsync() works, only that the argument is accepted.
+ call writefile(['one'], 'Xtest', 's')
+ call writefile(['two'], 'Xtest', 'S')
+ call delete('Xtest')
+endfunc
+
+func Test_writefile_sync_dev_stdout()
+ if !has('unix')
+ return
+ endif
+ if filewritable('/dev/stdout')
+ " Just check that this doesn't cause an error.
+ call writefile(['one'], '/dev/stdout')
+ else
+ throw 'Skipped: /dev/stdout is not writable'
+ endif
+endfunc
+
+func Test_writefile_autowrite()
+ set autowrite
+ new
+ next Xa Xb Xc
+ call setline(1, 'aaa')
+ next
+ call assert_equal(['aaa'], readfile('Xa'))
+ call setline(1, 'bbb')
+ call assert_fails('edit XX')
+ call assert_false(filereadable('Xb'))
+
+ set autowriteall
+ edit XX
+ call assert_equal(['bbb'], readfile('Xb'))
+
+ bwipe!
+ call delete('Xa')
+ call delete('Xb')
+ set noautowrite
+endfunc
+
+func Test_writefile_autowrite_nowrite()
+ set autowrite
+ new
+ next Xa Xb Xc
+ set buftype=nowrite
+ call setline(1, 'aaa')
+ let buf = bufnr('%')
+ " buffer contents silently lost
+ edit XX
+ call assert_false(filereadable('Xa'))
+ rewind
+ call assert_equal('', getline(1))
+
+ bwipe!
+ set noautowrite
+endfunc
diff --git a/src/testdir/test_xxd.vim b/src/testdir/test_xxd.vim
new file mode 100644
index 0000000..e4e7755
--- /dev/null
+++ b/src/testdir/test_xxd.vim
@@ -0,0 +1,183 @@
+" Test for the xxd command
+if empty($XXD) && executable('..\xxd\xxd.exe')
+ let s:xxd_cmd = '..\xxd\xxd.exe'
+elseif empty($XXD) || !executable($XXD)
+ finish
+else
+ let s:xxd_cmd = $XXD
+endif
+
+func PrepareBuffer(lines)
+ new
+ call append(0, a:lines)
+ $d
+endfunc
+
+func s:Mess(counter)
+ return printf("Failed xxd test %d:", a:counter)
+endfunc
+
+func Test_xxd()
+ call PrepareBuffer(range(1,30))
+ set ff=unix
+ w! XXDfile
+
+ " Test 1: simple, filter the result through xxd
+ let s:test = 1
+ exe '%!' . s:xxd_cmd . ' %'
+ let expected = [
+ \ '00000000: 310a 320a 330a 340a 350a 360a 370a 380a 1.2.3.4.5.6.7.8.',
+ \ '00000010: 390a 3130 0a31 310a 3132 0a31 330a 3134 9.10.11.12.13.14',
+ \ '00000020: 0a31 350a 3136 0a31 370a 3138 0a31 390a .15.16.17.18.19.',
+ \ '00000030: 3230 0a32 310a 3232 0a32 330a 3234 0a32 20.21.22.23.24.2',
+ \ '00000040: 350a 3236 0a32 370a 3238 0a32 390a 3330 5.26.27.28.29.30',
+ \ '00000050: 0a .']
+ call assert_equal(expected, getline(1,'$'), s:Mess(s:test))
+
+ " Test 2: reverse the result
+ let s:test += 1
+ exe '%!' . s:xxd_cmd . ' -r'
+ call assert_equal(map(range(1,30), {v,c -> string(c)}), getline(1,'$'), s:Mess(s:test))
+
+ " Test 3: Skip the first 0x30 bytes
+ let s:test += 1
+ for arg in ['-s 0x30', '-s0x30', '-s+0x30', '-skip 0x030', '-seek 0x30', '-seek +0x30 --']
+ exe '%!' . s:xxd_cmd . ' ' . arg . ' %'
+ call assert_equal(expected[3:], getline(1,'$'), s:Mess(s:test))
+ endfor
+
+ " Test 4: Skip the first 30 bytes
+ let s:test += 1
+ for arg in ['-s -0x31', '-s-0x31']
+ exe '%!' . s:xxd_cmd . ' ' . arg . ' %'
+ call assert_equal(expected[2:], getline(1,'$'), s:Mess(s:test))
+ endfor
+
+ " The following tests use the xxd man page.
+ " For these tests to pass, the fileformat must be "unix".
+ let man_copy = 'Xxd.1'
+ let man_page = '../../runtime/doc/xxd.1'
+ if has('win32') && !filereadable(man_page)
+ let man_page = '../../doc/xxd.1'
+ endif
+ %d
+ exe '0r ' man_page '| set ff=unix | $d | w' man_copy '| bwipe!' man_copy
+
+ " Test 5: Print 120 bytes as continuous hexdump with 20 octets per line
+ let s:test += 1
+ %d
+ exe '0r! ' . s:xxd_cmd . ' -l 120 -ps -c20 ' . man_copy
+ $d
+ let expected = [
+ \ '2e54482058584420312022417567757374203139',
+ \ '39362220224d616e75616c207061676520666f72',
+ \ '20787864220a2e5c220a2e5c222032317374204d',
+ \ '617920313939360a2e5c22204d616e2070616765',
+ \ '20617574686f723a0a2e5c2220202020546f6e79',
+ \ '204e7567656e74203c746f6e79407363746e7567']
+ call assert_equal(expected, getline(1,'$'), s:Mess(s:test))
+
+ " Test 6: Print the date from xxd.1
+ let s:test += 1
+ for arg in ['-l 13', '-l13', '-len 13']
+ %d
+ exe '0r! ' . s:xxd_cmd . ' -s 0x36 ' . arg . ' -cols 13 ' . man_copy
+ $d
+ call assert_equal('00000036: 3231 7374 204d 6179 2031 3939 36 21st May 1996', getline(1), s:Mess(s:test))
+ endfor
+
+ " Cleanup after tests 5 and 6
+ call delete(man_copy)
+
+ " Test 7: Print C include
+ let s:test += 1
+ call writefile(['TESTabcd09'], 'XXDfile')
+ %d
+ exe '0r! ' . s:xxd_cmd . ' -i XXDfile'
+ $d
+ let expected = ['unsigned char XXDfile[] = {',
+ \ ' 0x54, 0x45, 0x53, 0x54, 0x61, 0x62, 0x63, 0x64, 0x30, 0x39, 0x0a', '};',
+ \ 'unsigned int XXDfile_len = 11;']
+ call assert_equal(expected, getline(1,'$'), s:Mess(s:test))
+
+ " Test 8: Print C include capitalized
+ let s:test += 1
+ for arg in ['-C', '-capitalize']
+ call writefile(['TESTabcd09'], 'XXDfile')
+ %d
+ exe '0r! ' . s:xxd_cmd . ' -i ' . arg . ' XXDfile'
+ $d
+ let expected = ['unsigned char XXDFILE[] = {',
+ \ ' 0x54, 0x45, 0x53, 0x54, 0x61, 0x62, 0x63, 0x64, 0x30, 0x39, 0x0a', '};',
+ \ 'unsigned int XXDFILE_LEN = 11;']
+ call assert_equal(expected, getline(1,'$'), s:Mess(s:test))
+ endfor
+
+ " Test 9: Create a file with containing a single 'A'
+ let s:test += 1
+ call delete('XXDfile')
+ bwipe! XXDfile
+ if has('unix')
+ call system('echo "010000: 41"|' . s:xxd_cmd . ' -r -s -0x10000 > XXDfile')
+ else
+ call writefile(['010000: 41'], 'Xinput')
+ silent exe '!' . s:xxd_cmd . ' -r -s -0x10000 < Xinput > XXDfile'
+ call delete('Xinput')
+ endif
+ call PrepareBuffer(readfile('XXDfile')[0])
+ call assert_equal('A', getline(1), s:Mess(s:test))
+ call delete('XXDfile')
+
+ " Test 10: group with 4 octets
+ let s:test += 1
+ for arg in ['-g 4', '-group 4', '-g4']
+ call writefile(['TESTabcd09'], 'XXDfile')
+ %d
+ exe '0r! ' . s:xxd_cmd . ' ' . arg . ' XXDfile'
+ $d
+ let expected = ['00000000: 54455354 61626364 30390a TESTabcd09.']
+ call assert_equal(expected, getline(1,'$'), s:Mess(s:test))
+ call delete('XXDfile')
+ endfor
+
+ " Test 11: reverse with CR, hex upper, Postscript style with a TAB
+ let s:test += 1
+ call writefile([" 54455354\t610B6364 30390A TESTa\0x0bcd09.\r"], 'Xinput')
+ silent exe '!' . s:xxd_cmd . ' -r -p < Xinput > XXDfile'
+ let blob = readfile('XXDfile', 'B')
+ call assert_equal(0z54455354.610B6364.30390A, blob)
+ call delete('Xinput')
+ call delete('XXDfile')
+
+ " Test 12: reverse with seek
+ let s:test += 1
+ call writefile(["00000000: 54455354\t610B6364 30390A TESTa\0x0bcd09.\r"], 'Xinput')
+ silent exe '!' . s:xxd_cmd . ' -r -seek 5 < Xinput > XXDfile'
+ let blob = readfile('XXDfile', 'B')
+ call assert_equal(0z0000000000.54455354.610B6364.30390A, blob)
+ call delete('Xinput')
+ call delete('XXDfile')
+
+ " TODO:
+ " -o -offset
+
+ %d
+ bw!
+endfunc
+
+" Various ways with wrong arguments that trigger the usage output.
+func Test_xxd_usage()
+ for arg in ['-c', '-g', '-o', '-s', '-l', '-X', 'one two three']
+ new
+ exe 'r! ' . s:xxd_cmd . ' ' . arg
+ call assert_match("Usage:", join(getline(1, 3)))
+ bwipe!
+ endfor
+endfunc
+
+func Test_xxd_version()
+ new
+ exe 'r! ' . s:xxd_cmd . ' -v'
+ call assert_match("xxd V1.10 .* by Juergen Weigert", join(getline(1, 3)))
+ bwipe!
+endfunc
diff --git a/src/testdir/unix.vim b/src/testdir/unix.vim
new file mode 100644
index 0000000..b82c63c
--- /dev/null
+++ b/src/testdir/unix.vim
@@ -0,0 +1,13 @@
+" Settings for test script execution
+" Always use "sh", don't use the value of "$SHELL".
+set shell=sh
+
+" Only when the +eval feature is present.
+if 1
+ " While some tests overwrite $HOME to prevent them from polluting user files,
+ " we need to remember the original value so that we can tell external systems
+ " where to ask about their own user settings.
+ let g:tester_HOME = $HOME
+endif
+
+source setup.vim
diff --git a/src/testdir/view_util.vim b/src/testdir/view_util.vim
new file mode 100644
index 0000000..29ea073
--- /dev/null
+++ b/src/testdir/view_util.vim
@@ -0,0 +1,51 @@
+" Functions about view shared by several tests
+
+" Only load this script once.
+if exists('*ScreenLines')
+ finish
+endif
+
+" ScreenLines(lnum, width) or
+" ScreenLines([start, end], width)
+function! ScreenLines(lnum, width) abort
+ redraw!
+ if type(a:lnum) == v:t_list
+ let start = a:lnum[0]
+ let end = a:lnum[1]
+ else
+ let start = a:lnum
+ let end = a:lnum
+ endif
+ let lines = []
+ for l in range(start, end)
+ let lines += [join(map(range(1, a:width), 'nr2char(screenchar(l, v:val))'), '')]
+ endfor
+ return lines
+endfunction
+
+function! ScreenAttrs(lnum, width) abort
+ redraw!
+ if type(a:lnum) == v:t_list
+ let start = a:lnum[0]
+ let end = a:lnum[1]
+ else
+ let start = a:lnum
+ let end = a:lnum
+ endif
+ let attrs = []
+ for l in range(start, end)
+ let attrs += [map(range(1, a:width), 'screenattr(l, v:val)')]
+ endfor
+ return attrs
+endfunction
+
+function! NewWindow(height, width) abort
+ exe a:height . 'new'
+ exe a:width . 'vsp'
+ redraw!
+endfunction
+
+function! CloseWindow() abort
+ bw!
+ redraw!
+endfunction
diff --git a/src/testdir/vms.vim b/src/testdir/vms.vim
new file mode 100644
index 0000000..64b390e
--- /dev/null
+++ b/src/testdir/vms.vim
@@ -0,0 +1,6 @@
+" Settings for test script execution under OpenVMS
+
+" Do not use any swap files
+set noswapfile
+
+source setup.vim
diff --git a/src/textprop.c b/src/textprop.c
new file mode 100644
index 0000000..637ee7f
--- /dev/null
+++ b/src/textprop.c
@@ -0,0 +1,1081 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * Text properties implementation.
+ *
+ * Text properties are attached to the text. They move with the text when
+ * text is inserted/deleted.
+ *
+ * Text properties have a user specified ID number, which can be unique.
+ * Text properties have a type, which can be used to specify highlighting.
+ *
+ * TODO:
+ * - Adjust text property column and length when text is inserted/deleted.
+ * -> a :substitute with a multi-line match
+ * -> search for changed_bytes() from misc1.c
+ * - Perhaps we only need TP_FLAG_CONT_NEXT and can drop TP_FLAG_CONT_PREV?
+ * - Add an arrray for global_proptypes, to quickly lookup a prop type by ID
+ * - Add an arrray for b_proptypes, to quickly lookup a prop type by ID
+ * - Checking the text length to detect text properties is slow. Use a flag in
+ * the index, like DB_MARKED?
+ * - Also test line2byte() with many lines, so that ml_updatechunk() is taken
+ * into account.
+ * - add mechanism to keep track of changed lines.
+ */
+
+#include "vim.h"
+
+#if defined(FEAT_TEXT_PROP) || defined(PROTO)
+
+/*
+ * In a hashtable item "hi_key" points to "pt_name" in a proptype_T.
+ * This avoids adding a pointer to the hashtable item.
+ * PT2HIKEY() converts a proptype pointer to a hashitem key pointer.
+ * HIKEY2PT() converts a hashitem key pointer to a proptype pointer.
+ * HI2PT() converts a hashitem pointer to a proptype pointer.
+ */
+#define PT2HIKEY(p) ((p)->pt_name)
+#define HIKEY2PT(p) ((proptype_T *)((p) - offsetof(proptype_T, pt_name)))
+#define HI2PT(hi) HIKEY2PT((hi)->hi_key)
+
+// The global text property types.
+static hashtab_T *global_proptypes = NULL;
+
+// The last used text property type ID.
+static int proptype_id = 0;
+
+static char_u e_type_not_exist[] = N_("E971: Property type %s does not exist");
+static char_u e_invalid_col[] = N_("E964: Invalid column number: %ld");
+static char_u e_invalid_lnum[] = N_("E966: Invalid line number: %ld");
+
+/*
+ * Find a property type by name, return the hashitem.
+ * Returns NULL if the item can't be found.
+ */
+ static hashitem_T *
+find_prop_hi(char_u *name, buf_T *buf)
+{
+ hashtab_T *ht;
+ hashitem_T *hi;
+
+ if (*name == NUL)
+ return NULL;
+ if (buf == NULL)
+ ht = global_proptypes;
+ else
+ ht = buf->b_proptypes;
+
+ if (ht == NULL)
+ return NULL;
+ hi = hash_find(ht, name);
+ if (HASHITEM_EMPTY(hi))
+ return NULL;
+ return hi;
+}
+
+/*
+ * Like find_prop_hi() but return the property type.
+ */
+ static proptype_T *
+find_prop(char_u *name, buf_T *buf)
+{
+ hashitem_T *hi = find_prop_hi(name, buf);
+
+ if (hi == NULL)
+ return NULL;
+ return HI2PT(hi);
+}
+
+/*
+ * Lookup a property type by name. First in "buf" and when not found in the
+ * global types.
+ * When not found gives an error message and returns NULL.
+ */
+ static proptype_T *
+lookup_prop_type(char_u *name, buf_T *buf)
+{
+ proptype_T *type = find_prop(name, buf);
+
+ if (type == NULL)
+ type = find_prop(name, NULL);
+ if (type == NULL)
+ semsg(_(e_type_not_exist), name);
+ return type;
+}
+
+/*
+ * Get an optional "bufnr" item from the dict in "arg".
+ * When the argument is not used or "bufnr" is not present then "buf" is
+ * unchanged.
+ * If "bufnr" is valid or not present return OK.
+ * When "arg" is not a dict or "bufnr" is invalide return FAIL.
+ */
+ static int
+get_bufnr_from_arg(typval_T *arg, buf_T **buf)
+{
+ dictitem_T *di;
+
+ if (arg->v_type != VAR_DICT)
+ {
+ emsg(_(e_dictreq));
+ return FAIL;
+ }
+ if (arg->vval.v_dict == NULL)
+ return OK; // NULL dict is like an empty dict
+ di = dict_find(arg->vval.v_dict, (char_u *)"bufnr", -1);
+ if (di != NULL)
+ {
+ *buf = tv_get_buf(&di->di_tv, FALSE);
+ if (*buf == NULL)
+ return FAIL;
+ }
+ return OK;
+}
+
+/*
+ * prop_add({lnum}, {col}, {props})
+ */
+ void
+f_prop_add(typval_T *argvars, typval_T *rettv UNUSED)
+{
+ linenr_T lnum;
+ linenr_T start_lnum;
+ linenr_T end_lnum;
+ colnr_T start_col;
+ colnr_T end_col;
+ dict_T *dict;
+ char_u *type_name;
+ proptype_T *type;
+ buf_T *buf = curbuf;
+ int id = 0;
+ char_u *newtext;
+ int proplen;
+ size_t textlen;
+ char_u *props;
+ char_u *newprops;
+ textprop_T tmp_prop;
+ int i;
+
+ start_lnum = tv_get_number(&argvars[0]);
+ start_col = tv_get_number(&argvars[1]);
+ if (start_col < 1)
+ {
+ semsg(_(e_invalid_col), (long)start_col);
+ return;
+ }
+ if (argvars[2].v_type != VAR_DICT)
+ {
+ emsg(_(e_dictreq));
+ return;
+ }
+ dict = argvars[2].vval.v_dict;
+
+ if (dict == NULL || dict_find(dict, (char_u *)"type", -1) == NULL)
+ {
+ emsg(_("E965: missing property type name"));
+ return;
+ }
+ type_name = dict_get_string(dict, (char_u *)"type", FALSE);
+
+ if (dict_find(dict, (char_u *)"end_lnum", -1) != NULL)
+ {
+ end_lnum = dict_get_number(dict, (char_u *)"end_lnum");
+ if (end_lnum < start_lnum)
+ {
+ semsg(_(e_invargval), "end_lnum");
+ return;
+ }
+ }
+ else
+ end_lnum = start_lnum;
+
+ if (dict_find(dict, (char_u *)"length", -1) != NULL)
+ {
+ long length = dict_get_number(dict, (char_u *)"length");
+
+ if (length < 0 || end_lnum > start_lnum)
+ {
+ semsg(_(e_invargval), "length");
+ return;
+ }
+ end_col = start_col + length;
+ }
+ else if (dict_find(dict, (char_u *)"end_col", -1) != NULL)
+ {
+ end_col = dict_get_number(dict, (char_u *)"end_col");
+ if (end_col <= 0)
+ {
+ semsg(_(e_invargval), "end_col");
+ return;
+ }
+ }
+ else if (start_lnum == end_lnum)
+ end_col = start_col;
+ else
+ end_col = 1;
+
+ if (dict_find(dict, (char_u *)"id", -1) != NULL)
+ id = dict_get_number(dict, (char_u *)"id");
+
+ if (get_bufnr_from_arg(&argvars[2], &buf) == FAIL)
+ return;
+
+ type = lookup_prop_type(type_name, buf);
+ if (type == NULL)
+ return;
+
+ if (start_lnum < 1 || start_lnum > buf->b_ml.ml_line_count)
+ {
+ semsg(_(e_invalid_lnum), (long)start_lnum);
+ return;
+ }
+ if (end_lnum < start_lnum || end_lnum > buf->b_ml.ml_line_count)
+ {
+ semsg(_(e_invalid_lnum), (long)end_lnum);
+ return;
+ }
+
+ for (lnum = start_lnum; lnum <= end_lnum; ++lnum)
+ {
+ colnr_T col; // start column
+ long length; // in bytes
+
+ // Fetch the line to get the ml_line_len field updated.
+ proplen = get_text_props(buf, lnum, &props, TRUE);
+ textlen = buf->b_ml.ml_line_len - proplen * sizeof(textprop_T);
+
+ if (lnum == start_lnum)
+ col = start_col;
+ else
+ col = 1;
+ if (col - 1 > (colnr_T)textlen)
+ {
+ semsg(_(e_invalid_col), (long)start_col);
+ return;
+ }
+
+ if (lnum == end_lnum)
+ length = end_col - col;
+ else
+ length = (int)textlen - col + 1;
+ if (length > (long)textlen)
+ length = (int)textlen; // can include the end-of-line
+ if (length < 0)
+ length = 0; // zero-width property
+
+ // Allocate the new line with space for the new proprety.
+ newtext = alloc(buf->b_ml.ml_line_len + sizeof(textprop_T));
+ if (newtext == NULL)
+ return;
+ // Copy the text, including terminating NUL.
+ mch_memmove(newtext, buf->b_ml.ml_line_ptr, textlen);
+
+ // Find the index where to insert the new property.
+ // Since the text properties are not aligned properly when stored with the
+ // text, we need to copy them as bytes before using it as a struct.
+ for (i = 0; i < proplen; ++i)
+ {
+ mch_memmove(&tmp_prop, props + i * sizeof(textprop_T),
+ sizeof(textprop_T));
+ if (tmp_prop.tp_col >= col)
+ break;
+ }
+ newprops = newtext + textlen;
+ if (i > 0)
+ mch_memmove(newprops, props, sizeof(textprop_T) * i);
+
+ tmp_prop.tp_col = col;
+ tmp_prop.tp_len = length;
+ tmp_prop.tp_id = id;
+ tmp_prop.tp_type = type->pt_id;
+ tmp_prop.tp_flags = (lnum > start_lnum ? TP_FLAG_CONT_PREV : 0)
+ | (lnum < end_lnum ? TP_FLAG_CONT_NEXT : 0);
+ mch_memmove(newprops + i * sizeof(textprop_T), &tmp_prop,
+ sizeof(textprop_T));
+
+ if (i < proplen)
+ mch_memmove(newprops + (i + 1) * sizeof(textprop_T),
+ props + i * sizeof(textprop_T),
+ sizeof(textprop_T) * (proplen - i));
+
+ if (buf->b_ml.ml_flags & ML_LINE_DIRTY)
+ vim_free(buf->b_ml.ml_line_ptr);
+ buf->b_ml.ml_line_ptr = newtext;
+ buf->b_ml.ml_line_len += sizeof(textprop_T);
+ buf->b_ml.ml_flags |= ML_LINE_DIRTY;
+ }
+
+ buf->b_has_textprop = TRUE; // this is never reset
+ redraw_buf_later(buf, NOT_VALID);
+}
+
+/*
+ * Fetch the text properties for line "lnum" in buffer "buf".
+ * Returns the number of text properties and, when non-zero, a pointer to the
+ * first one in "props" (note that it is not aligned, therefore the char_u
+ * pointer).
+ */
+ int
+get_text_props(buf_T *buf, linenr_T lnum, char_u **props, int will_change)
+{
+ char_u *text;
+ size_t textlen;
+ size_t proplen;
+
+ // Be quick when no text property types have been defined or the buffer,
+ // unless we are adding one.
+ if (!buf->b_has_textprop && !will_change)
+ return 0;
+
+ // Fetch the line to get the ml_line_len field updated.
+ text = ml_get_buf(buf, lnum, will_change);
+ textlen = STRLEN(text) + 1;
+ proplen = buf->b_ml.ml_line_len - textlen;
+ if (proplen % sizeof(textprop_T) != 0)
+ {
+ iemsg(_("E967: text property info corrupted"));
+ return 0;
+ }
+ if (proplen > 0)
+ *props = text + textlen;
+ return (int)(proplen / sizeof(textprop_T));
+}
+
+/*
+ * Set the text properties for line "lnum" to "props" with length "len".
+ * If "len" is zero text properties are removed, "props" is not used.
+ * Any existing text properties are dropped.
+ * Only works for the current buffer.
+ */
+ static void
+set_text_props(linenr_T lnum, char_u *props, int len)
+{
+ char_u *text;
+ char_u *newtext;
+ int textlen;
+
+ text = ml_get(lnum);
+ textlen = (int)STRLEN(text) + 1;
+ newtext = alloc(textlen + len);
+ if (newtext == NULL)
+ return;
+ mch_memmove(newtext, text, textlen);
+ if (len > 0)
+ mch_memmove(newtext + textlen, props, len);
+ if (curbuf->b_ml.ml_flags & ML_LINE_DIRTY)
+ vim_free(curbuf->b_ml.ml_line_ptr);
+ curbuf->b_ml.ml_line_ptr = newtext;
+ curbuf->b_ml.ml_line_len = textlen + len;
+ curbuf->b_ml.ml_flags |= ML_LINE_DIRTY;
+}
+
+ static proptype_T *
+find_type_by_id(hashtab_T *ht, int id)
+{
+ long todo;
+ hashitem_T *hi;
+
+ if (ht == NULL)
+ return NULL;
+
+ // TODO: Make this faster by keeping a list of types sorted on ID and use
+ // a binary search.
+
+ todo = (long)ht->ht_used;
+ for (hi = ht->ht_array; todo > 0; ++hi)
+ {
+ if (!HASHITEM_EMPTY(hi))
+ {
+ proptype_T *prop = HI2PT(hi);
+
+ if (prop->pt_id == id)
+ return prop;
+ --todo;
+ }
+ }
+ return NULL;
+}
+
+/*
+ * Find a property type by ID in "buf" or globally.
+ * Returns NULL if not found.
+ */
+ proptype_T *
+text_prop_type_by_id(buf_T *buf, int id)
+{
+ proptype_T *type;
+
+ type = find_type_by_id(buf->b_proptypes, id);
+ if (type == NULL)
+ type = find_type_by_id(global_proptypes, id);
+ return type;
+}
+
+/*
+ * prop_clear({lnum} [, {lnum_end} [, {bufnr}]])
+ */
+ void
+f_prop_clear(typval_T *argvars, typval_T *rettv UNUSED)
+{
+ linenr_T start = tv_get_number(&argvars[0]);
+ linenr_T end = start;
+ linenr_T lnum;
+ buf_T *buf = curbuf;
+
+ if (argvars[1].v_type != VAR_UNKNOWN)
+ {
+ end = tv_get_number(&argvars[1]);
+ if (argvars[2].v_type != VAR_UNKNOWN)
+ {
+ if (get_bufnr_from_arg(&argvars[2], &buf) == FAIL)
+ return;
+ }
+ }
+ if (start < 1 || end < 1)
+ {
+ emsg(_(e_invrange));
+ return;
+ }
+
+ for (lnum = start; lnum <= end; ++lnum)
+ {
+ char_u *text;
+ size_t len;
+
+ if (lnum > buf->b_ml.ml_line_count)
+ break;
+ text = ml_get_buf(buf, lnum, FALSE);
+ len = STRLEN(text) + 1;
+ if ((size_t)buf->b_ml.ml_line_len > len)
+ {
+ if (!(buf->b_ml.ml_flags & ML_LINE_DIRTY))
+ {
+ char_u *newtext = vim_strsave(text);
+
+ // need to allocate the line now
+ if (newtext == NULL)
+ return;
+ buf->b_ml.ml_line_ptr = newtext;
+ buf->b_ml.ml_flags |= ML_LINE_DIRTY;
+ }
+ buf->b_ml.ml_line_len = (int)len;
+ }
+ }
+ redraw_buf_later(buf, NOT_VALID);
+}
+
+/*
+ * prop_list({lnum} [, {bufnr}])
+ */
+ void
+f_prop_list(typval_T *argvars, typval_T *rettv)
+{
+ linenr_T lnum = tv_get_number(&argvars[0]);
+ buf_T *buf = curbuf;
+
+ if (argvars[1].v_type != VAR_UNKNOWN)
+ {
+ if (get_bufnr_from_arg(&argvars[1], &buf) == FAIL)
+ return;
+ }
+ if (lnum < 1 || lnum > buf->b_ml.ml_line_count)
+ {
+ emsg(_(e_invrange));
+ return;
+ }
+
+ if (rettv_list_alloc(rettv) == OK)
+ {
+ char_u *text = ml_get_buf(buf, lnum, FALSE);
+ size_t textlen = STRLEN(text) + 1;
+ int count = (int)((buf->b_ml.ml_line_len - textlen)
+ / sizeof(textprop_T));
+ int i;
+ textprop_T prop;
+ proptype_T *pt;
+
+ for (i = 0; i < count; ++i)
+ {
+ dict_T *d = dict_alloc();
+
+ if (d == NULL)
+ break;
+ mch_memmove(&prop, text + textlen + i * sizeof(textprop_T),
+ sizeof(textprop_T));
+ dict_add_number(d, "col", prop.tp_col);
+ dict_add_number(d, "length", prop.tp_len);
+ dict_add_number(d, "id", prop.tp_id);
+ dict_add_number(d, "start", !(prop.tp_flags & TP_FLAG_CONT_PREV));
+ dict_add_number(d, "end", !(prop.tp_flags & TP_FLAG_CONT_NEXT));
+ pt = text_prop_type_by_id(buf, prop.tp_type);
+ if (pt != NULL)
+ dict_add_string(d, "type", pt->pt_name);
+
+ list_append_dict(rettv->vval.v_list, d);
+ }
+ }
+}
+
+/*
+ * prop_remove({props} [, {lnum} [, {lnum_end}]])
+ */
+ void
+f_prop_remove(typval_T *argvars, typval_T *rettv)
+{
+ linenr_T start = 1;
+ linenr_T end = 0;
+ linenr_T lnum;
+ dict_T *dict;
+ buf_T *buf = curbuf;
+ dictitem_T *di;
+ int do_all = FALSE;
+ int id = -1;
+ int type_id = -1;
+
+ rettv->vval.v_number = 0;
+ if (argvars[0].v_type != VAR_DICT || argvars[0].vval.v_dict == NULL)
+ {
+ emsg(_(e_invarg));
+ return;
+ }
+
+ if (argvars[1].v_type != VAR_UNKNOWN)
+ {
+ start = tv_get_number(&argvars[1]);
+ end = start;
+ if (argvars[2].v_type != VAR_UNKNOWN)
+ end = tv_get_number(&argvars[2]);
+ if (start < 1 || end < 1)
+ {
+ emsg(_(e_invrange));
+ return;
+ }
+ }
+
+ dict = argvars[0].vval.v_dict;
+ di = dict_find(dict, (char_u *)"bufnr", -1);
+ if (di != NULL)
+ {
+ buf = tv_get_buf(&di->di_tv, FALSE);
+ if (buf == NULL)
+ return;
+ }
+
+ di = dict_find(dict, (char_u*)"all", -1);
+ if (di != NULL)
+ do_all = dict_get_number(dict, (char_u *)"all");
+
+ if (dict_find(dict, (char_u *)"id", -1) != NULL)
+ id = dict_get_number(dict, (char_u *)"id");
+ if (dict_find(dict, (char_u *)"type", -1))
+ {
+ char_u *name = dict_get_string(dict, (char_u *)"type", FALSE);
+ proptype_T *type = lookup_prop_type(name, buf);
+
+ if (type == NULL)
+ return;
+ type_id = type->pt_id;
+ }
+ if (id == -1 && type_id == -1)
+ {
+ emsg(_("E968: Need at least one of 'id' or 'type'"));
+ return;
+ }
+
+ if (end == 0)
+ end = buf->b_ml.ml_line_count;
+ for (lnum = start; lnum <= end; ++lnum)
+ {
+ char_u *text;
+ size_t len;
+
+ if (lnum > buf->b_ml.ml_line_count)
+ break;
+ text = ml_get_buf(buf, lnum, FALSE);
+ len = STRLEN(text) + 1;
+ if ((size_t)buf->b_ml.ml_line_len > len)
+ {
+ static textprop_T textprop; // static because of alignment
+ unsigned idx;
+
+ for (idx = 0; idx < (buf->b_ml.ml_line_len - len)
+ / sizeof(textprop_T); ++idx)
+ {
+ char_u *cur_prop = buf->b_ml.ml_line_ptr + len
+ + idx * sizeof(textprop_T);
+ size_t taillen;
+
+ mch_memmove(&textprop, cur_prop, sizeof(textprop_T));
+ if (textprop.tp_id == id || textprop.tp_type == type_id)
+ {
+ if (!(buf->b_ml.ml_flags & ML_LINE_DIRTY))
+ {
+ char_u *newptr = alloc(buf->b_ml.ml_line_len);
+
+ // need to allocate the line to be able to change it
+ if (newptr == NULL)
+ return;
+ mch_memmove(newptr, buf->b_ml.ml_line_ptr,
+ buf->b_ml.ml_line_len);
+ buf->b_ml.ml_line_ptr = newptr;
+ curbuf->b_ml.ml_flags |= ML_LINE_DIRTY;
+ }
+
+ taillen = buf->b_ml.ml_line_len - len
+ - (idx + 1) * sizeof(textprop_T);
+ if (taillen > 0)
+ mch_memmove(cur_prop, cur_prop + sizeof(textprop_T),
+ taillen);
+ buf->b_ml.ml_line_len -= sizeof(textprop_T);
+ --idx;
+
+ ++rettv->vval.v_number;
+ if (!do_all)
+ break;
+ }
+ }
+ }
+ }
+ redraw_buf_later(buf, NOT_VALID);
+}
+
+/*
+ * Common for f_prop_type_add() and f_prop_type_change().
+ */
+ void
+prop_type_set(typval_T *argvars, int add)
+{
+ char_u *name;
+ buf_T *buf = NULL;
+ dict_T *dict;
+ dictitem_T *di;
+ proptype_T *prop;
+
+ name = tv_get_string(&argvars[0]);
+ if (*name == NUL)
+ {
+ emsg(_(e_invarg));
+ return;
+ }
+
+ if (get_bufnr_from_arg(&argvars[1], &buf) == FAIL)
+ return;
+ dict = argvars[1].vval.v_dict;
+
+ prop = find_prop(name, buf);
+ if (add)
+ {
+ hashtab_T **htp;
+
+ if (prop != NULL)
+ {
+ semsg(_("E969: Property type %s already defined"), name);
+ return;
+ }
+ prop = (proptype_T *)alloc_clear((int)(sizeof(proptype_T) + STRLEN(name)));
+ if (prop == NULL)
+ return;
+ STRCPY(prop->pt_name, name);
+ prop->pt_id = ++proptype_id;
+ htp = buf == NULL ? &global_proptypes : &buf->b_proptypes;
+ if (*htp == NULL)
+ {
+ *htp = (hashtab_T *)alloc(sizeof(hashtab_T));
+ if (*htp == NULL)
+ {
+ vim_free(prop);
+ return;
+ }
+ hash_init(*htp);
+ }
+ hash_add(*htp, PT2HIKEY(prop));
+ }
+ else
+ {
+ if (prop == NULL)
+ {
+ semsg(_(e_type_not_exist), name);
+ return;
+ }
+ }
+
+ if (dict != NULL)
+ {
+ di = dict_find(dict, (char_u *)"highlight", -1);
+ if (di != NULL)
+ {
+ char_u *highlight;
+ int hl_id = 0;
+
+ highlight = dict_get_string(dict, (char_u *)"highlight", FALSE);
+ if (highlight != NULL && *highlight != NUL)
+ hl_id = syn_name2id(highlight);
+ if (hl_id <= 0)
+ {
+ semsg(_("E970: Unknown highlight group name: '%s'"),
+ highlight == NULL ? (char_u *)"" : highlight);
+ return;
+ }
+ prop->pt_hl_id = hl_id;
+ }
+
+ di = dict_find(dict, (char_u *)"priority", -1);
+ if (di != NULL)
+ prop->pt_priority = tv_get_number(&di->di_tv);
+
+ di = dict_find(dict, (char_u *)"start_incl", -1);
+ if (di != NULL)
+ {
+ if (tv_get_number(&di->di_tv))
+ prop->pt_flags |= PT_FLAG_INS_START_INCL;
+ else
+ prop->pt_flags &= ~PT_FLAG_INS_START_INCL;
+ }
+
+ di = dict_find(dict, (char_u *)"end_incl", -1);
+ if (di != NULL)
+ {
+ if (tv_get_number(&di->di_tv))
+ prop->pt_flags |= PT_FLAG_INS_END_INCL;
+ else
+ prop->pt_flags &= ~PT_FLAG_INS_END_INCL;
+ }
+ }
+}
+
+/*
+ * prop_type_add({name}, {props})
+ */
+ void
+f_prop_type_add(typval_T *argvars, typval_T *rettv UNUSED)
+{
+ prop_type_set(argvars, TRUE);
+}
+
+/*
+ * prop_type_change({name}, {props})
+ */
+ void
+f_prop_type_change(typval_T *argvars, typval_T *rettv UNUSED)
+{
+ prop_type_set(argvars, FALSE);
+}
+
+/*
+ * prop_type_delete({name} [, {bufnr}])
+ */
+ void
+f_prop_type_delete(typval_T *argvars, typval_T *rettv UNUSED)
+{
+ char_u *name;
+ buf_T *buf = NULL;
+ hashitem_T *hi;
+
+ name = tv_get_string(&argvars[0]);
+ if (*name == NUL)
+ {
+ emsg(_(e_invarg));
+ return;
+ }
+
+ if (argvars[1].v_type != VAR_UNKNOWN)
+ {
+ if (get_bufnr_from_arg(&argvars[1], &buf) == FAIL)
+ return;
+ }
+
+ hi = find_prop_hi(name, buf);
+ if (hi != NULL)
+ {
+ hashtab_T *ht;
+ proptype_T *prop = HI2PT(hi);
+
+ if (buf == NULL)
+ ht = global_proptypes;
+ else
+ ht = buf->b_proptypes;
+ hash_remove(ht, hi);
+ vim_free(prop);
+ }
+}
+
+/*
+ * prop_type_get({name} [, {bufnr}])
+ */
+ void
+f_prop_type_get(typval_T *argvars, typval_T *rettv UNUSED)
+{
+ char_u *name = tv_get_string(&argvars[0]);
+
+ if (*name == NUL)
+ {
+ emsg(_(e_invarg));
+ return;
+ }
+ if (rettv_dict_alloc(rettv) == OK)
+ {
+ proptype_T *prop = NULL;
+ buf_T *buf = NULL;
+
+ if (argvars[1].v_type != VAR_UNKNOWN)
+ {
+ if (get_bufnr_from_arg(&argvars[1], &buf) == FAIL)
+ return;
+ }
+
+ prop = find_prop(name, buf);
+ if (prop != NULL)
+ {
+ dict_T *d = rettv->vval.v_dict;
+
+ if (prop->pt_hl_id > 0)
+ dict_add_string(d, "highlight", syn_id2name(prop->pt_hl_id));
+ dict_add_number(d, "priority", prop->pt_priority);
+ dict_add_number(d, "start_incl",
+ (prop->pt_flags & PT_FLAG_INS_START_INCL) ? 1 : 0);
+ dict_add_number(d, "end_incl",
+ (prop->pt_flags & PT_FLAG_INS_END_INCL) ? 1 : 0);
+ if (buf != NULL)
+ dict_add_number(d, "bufnr", buf->b_fnum);
+ }
+ }
+}
+
+ static void
+list_types(hashtab_T *ht, list_T *l)
+{
+ long todo;
+ hashitem_T *hi;
+
+ todo = (long)ht->ht_used;
+ for (hi = ht->ht_array; todo > 0; ++hi)
+ {
+ if (!HASHITEM_EMPTY(hi))
+ {
+ proptype_T *prop = HI2PT(hi);
+
+ list_append_string(l, prop->pt_name, -1);
+ --todo;
+ }
+ }
+}
+
+/*
+ * prop_type_list([{bufnr}])
+ */
+ void
+f_prop_type_list(typval_T *argvars, typval_T *rettv UNUSED)
+{
+ buf_T *buf = NULL;
+
+ if (rettv_list_alloc(rettv) == OK)
+ {
+ if (argvars[0].v_type != VAR_UNKNOWN)
+ {
+ if (get_bufnr_from_arg(&argvars[0], &buf) == FAIL)
+ return;
+ }
+ if (buf == NULL)
+ {
+ if (global_proptypes != NULL)
+ list_types(global_proptypes, rettv->vval.v_list);
+ }
+ else if (buf->b_proptypes != NULL)
+ list_types(buf->b_proptypes, rettv->vval.v_list);
+ }
+}
+
+/*
+ * Free all property types in "ht".
+ */
+ static void
+clear_ht_prop_types(hashtab_T *ht)
+{
+ long todo;
+ hashitem_T *hi;
+
+ if (ht == NULL)
+ return;
+
+ todo = (long)ht->ht_used;
+ for (hi = ht->ht_array; todo > 0; ++hi)
+ {
+ if (!HASHITEM_EMPTY(hi))
+ {
+ proptype_T *prop = HI2PT(hi);
+
+ vim_free(prop);
+ --todo;
+ }
+ }
+
+ hash_clear(ht);
+ vim_free(ht);
+}
+
+#if defined(EXITFREE) || defined(PROTO)
+/*
+ * Free all global property types.
+ */
+ void
+clear_global_prop_types(void)
+{
+ clear_ht_prop_types(global_proptypes);
+ global_proptypes = NULL;
+}
+#endif
+
+/*
+ * Free all property types for "buf".
+ */
+ void
+clear_buf_prop_types(buf_T *buf)
+{
+ clear_ht_prop_types(buf->b_proptypes);
+ buf->b_proptypes = NULL;
+}
+
+/*
+ * Adjust the columns of text properties in line "lnum" after position "col" to
+ * shift by "bytes_added" (can be negative).
+ * Note that "col" is zero-based, while tp_col is one-based.
+ * Only for the current buffer.
+ * Called is expected to check b_has_textprop and "bytes_added" being non-zero.
+ */
+ void
+adjust_prop_columns(
+ linenr_T lnum,
+ colnr_T col,
+ int bytes_added)
+{
+ int proplen;
+ char_u *props;
+ textprop_T tmp_prop;
+ proptype_T *pt;
+ int dirty = FALSE;
+ int ri, wi;
+ size_t textlen;
+
+ if (text_prop_frozen > 0)
+ return;
+
+ proplen = get_text_props(curbuf, lnum, &props, TRUE);
+ if (proplen == 0)
+ return;
+ textlen = curbuf->b_ml.ml_line_len - proplen * sizeof(textprop_T);
+
+ wi = 0; // write index
+ for (ri = 0; ri < proplen; ++ri)
+ {
+ mch_memmove(&tmp_prop, props + ri * sizeof(textprop_T),
+ sizeof(textprop_T));
+ pt = text_prop_type_by_id(curbuf, tmp_prop.tp_type);
+
+ if (bytes_added > 0
+ ? (tmp_prop.tp_col >= col
+ + (pt != NULL && (pt->pt_flags & PT_FLAG_INS_START_INCL)
+ ? 2 : 1))
+ : (tmp_prop.tp_col > col + 1))
+ {
+ tmp_prop.tp_col += bytes_added;
+ dirty = TRUE;
+ }
+ else if (tmp_prop.tp_len > 0
+ && tmp_prop.tp_col + tmp_prop.tp_len > col
+ + ((pt != NULL && (pt->pt_flags & PT_FLAG_INS_END_INCL))
+ ? 0 : 1))
+ {
+ tmp_prop.tp_len += bytes_added;
+ dirty = TRUE;
+ if (tmp_prop.tp_len <= 0)
+ continue; // drop this text property
+ }
+ mch_memmove(props + wi * sizeof(textprop_T), &tmp_prop,
+ sizeof(textprop_T));
+ ++wi;
+ }
+ if (dirty)
+ {
+ colnr_T newlen = (int)textlen + wi * (colnr_T)sizeof(textprop_T);
+
+ if ((curbuf->b_ml.ml_flags & ML_LINE_DIRTY) == 0)
+ curbuf->b_ml.ml_line_ptr =
+ vim_memsave(curbuf->b_ml.ml_line_ptr, newlen);
+ curbuf->b_ml.ml_flags |= ML_LINE_DIRTY;
+ curbuf->b_ml.ml_line_len = newlen;
+ }
+}
+
+/*
+ * Adjust text properties for a line that was split in two.
+ * "lnum" is the newly inserted line. The text properties are now on the line
+ * below it. "kept" is the number of bytes kept in the first line, while
+ * "deleted" is the number of bytes deleted.
+ */
+ void
+adjust_props_for_split(linenr_T lnum, int kept, int deleted)
+{
+ char_u *props;
+ int count;
+ garray_T prevprop;
+ garray_T nextprop;
+ int i;
+ int skipped = kept + deleted;
+
+ if (!curbuf->b_has_textprop)
+ return;
+ count = get_text_props(curbuf, lnum + 1, &props, FALSE);
+ ga_init2(&prevprop, sizeof(textprop_T), 10);
+ ga_init2(&nextprop, sizeof(textprop_T), 10);
+
+ // Get the text properties, which are at "lnum + 1".
+ // Keep the relevant ones in the first line, reducing the length if needed.
+ // Copy the ones that include the split to the second line.
+ // Move the ones after the split to the second line.
+ for (i = 0; i < count; ++i)
+ {
+ textprop_T prop;
+ textprop_T *p;
+
+ // copy the prop to an aligned structure
+ mch_memmove(&prop, props + i * sizeof(textprop_T), sizeof(textprop_T));
+
+ if (prop.tp_col < kept && ga_grow(&prevprop, 1) == OK)
+ {
+ p = ((textprop_T *)prevprop.ga_data) + prevprop.ga_len;
+ *p = prop;
+ if (p->tp_col + p->tp_len >= kept)
+ p->tp_len = kept - p->tp_col;
+ ++prevprop.ga_len;
+ }
+
+ if (prop.tp_col + prop.tp_len >= skipped && ga_grow(&nextprop, 1) == OK)
+ {
+ p = ((textprop_T *)nextprop.ga_data) + nextprop.ga_len;
+ *p = prop;
+ if (p->tp_col > skipped)
+ p->tp_col -= skipped - 1;
+ else
+ {
+ p->tp_len -= skipped - p->tp_col;
+ p->tp_col = 1;
+ }
+ ++nextprop.ga_len;
+ }
+ }
+
+ set_text_props(lnum, prevprop.ga_data, prevprop.ga_len * sizeof(textprop_T));
+ ga_clear(&prevprop);
+
+ set_text_props(lnum + 1, nextprop.ga_data, nextprop.ga_len * sizeof(textprop_T));
+ ga_clear(&nextprop);
+}
+
+#endif // FEAT_TEXT_PROP
diff --git a/src/toolbar.phi b/src/toolbar.phi
new file mode 100644
index 0000000..cf9043c
--- /dev/null
+++ b/src/toolbar.phi
@@ -0,0 +1,1283 @@
+/* Builtin icons for the toolbar in photon */
+
+static PgColor_t tb_palette[] = {
+ PgRGB(0,0,0),
+ PgRGB(128,0,0),
+ PgRGB(128,128,0),
+ PgRGB(128,128,128),
+ PgRGB(192,192,192),
+ PgRGB(255,0,0),
+ PgRGB(255,255,0),
+ PgRGB(255,255,255),
+};
+
+static uint8_t tb_close_data[] = {
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x14,0x44,0x44,0x44,0x14,0x44,0x44,
+ 0x44,0x41,0x51,0x00,0x00,0x01,0x51,0x04,0x44,
+ 0x44,0x15,0x55,0x14,0x44,0x15,0x55,0x13,0x44,
+ 0x44,0x41,0x55,0x51,0x41,0x55,0x51,0x03,0x44,
+ 0x44,0x40,0x15,0x55,0x15,0x55,0x17,0x03,0x44,
+ 0x44,0x40,0x41,0x55,0x55,0x51,0x47,0x03,0x44,
+ 0x44,0x40,0x44,0x15,0x55,0x14,0x47,0x03,0x44,
+ 0x44,0x40,0x41,0x55,0x55,0x51,0x47,0x03,0x44,
+ 0x44,0x40,0x15,0x55,0x15,0x55,0x17,0x03,0x44,
+ 0x44,0x41,0x55,0x51,0x41,0x55,0x51,0x03,0x44,
+ 0x44,0x15,0x55,0x14,0x44,0x15,0x55,0x13,0x44,
+ 0x44,0x41,0x51,0x44,0x44,0x41,0x55,0x51,0x44,
+ 0x44,0x40,0x14,0x44,0x44,0x44,0x15,0x13,0x44,
+ 0x44,0x40,0x77,0x77,0x77,0x77,0x41,0x03,0x44,
+ 0x44,0x40,0x00,0x00,0x00,0x00,0x00,0x03,0x44,
+ 0x44,0x44,0x44,0x33,0x33,0x33,0x33,0x33,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+};
+
+static PhImage_t tb_close_phi = {
+ Pg_IMAGE_PALETTE_NIBBLE,
+ 0,
+ 9,
+ { 18,18 },
+ 420393992,
+ 8,
+ NULL,
+ PgGrey(0xc0),
+ 0,
+ Ph_USE_TRANSPARENCY,
+ 0,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ tb_palette,
+ tb_close_data
+};
+
+static uint8_t tb_copy_data[] = {
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x40,0x00,0x00,0x00,0x00,0x04,0x44,0x44,0x44,
+ 0x40,0x77,0x77,0x77,0x77,0x03,0x44,0x44,0x44,
+ 0x40,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x44,
+ 0x40,0x77,0x77,0x07,0x77,0x77,0x77,0x70,0x44,
+ 0x40,0x70,0x00,0x07,0x00,0x00,0x00,0x70,0x34,
+ 0x40,0x77,0x77,0x07,0x77,0x77,0x77,0x70,0x34,
+ 0x40,0x70,0x00,0x07,0x00,0x00,0x00,0x70,0x34,
+ 0x40,0x77,0x77,0x07,0x77,0x77,0x77,0x70,0x34,
+ 0x40,0x70,0x07,0x07,0x00,0x00,0x00,0x70,0x34,
+ 0x40,0x77,0x77,0x07,0x77,0x77,0x77,0x70,0x34,
+ 0x40,0x00,0x00,0x07,0x00,0x77,0x77,0x70,0x34,
+ 0x44,0x33,0x33,0x07,0x77,0x77,0x77,0x70,0x34,
+ 0x44,0x44,0x44,0x00,0x00,0x00,0x00,0x00,0x34,
+ 0x44,0x44,0x44,0x44,0x33,0x33,0x33,0x33,0x34,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+};
+
+static PhImage_t tb_copy_phi = {
+ Pg_IMAGE_PALETTE_NIBBLE,
+ 0,
+ 9,
+ { 18,18 },
+ 420393992,
+ 8,
+ NULL,
+ PgGrey(0xc0),
+ 0,
+ Ph_USE_TRANSPARENCY,
+ 0,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ tb_palette,
+ tb_copy_data
+};
+
+static uint8_t tb_ctags_data[] = {
+ 0x44,0x44,0x40,0x04,0x00,0x00,0x04,0x44,0x44,
+ 0x44,0x44,0x07,0x70,0x77,0x77,0x70,0x44,0x44,
+ 0x44,0x44,0x07,0x77,0x77,0x77,0x77,0x04,0x44,
+ 0x44,0x44,0x07,0x70,0x77,0x77,0x00,0x70,0x44,
+ 0x44,0x44,0x40,0x04,0x00,0x00,0x34,0x00,0x44,
+ 0x44,0x42,0x24,0x42,0x40,0x00,0x42,0x40,0x44,
+ 0x44,0x23,0x66,0x66,0x60,0x00,0x36,0x66,0x03,
+ 0x42,0x36,0x66,0x66,0x60,0x00,0x36,0x66,0x03,
+ 0x23,0x64,0x34,0x66,0x60,0x00,0x36,0x66,0x03,
+ 0x26,0x63,0x03,0x66,0x60,0x00,0x36,0x66,0x03,
+ 0x36,0x64,0x34,0x66,0x60,0x00,0x36,0x66,0x03,
+ 0x30,0x66,0x66,0x66,0x60,0x00,0x36,0x66,0x03,
+ 0x43,0x06,0x66,0x66,0x60,0x00,0x36,0x66,0x03,
+ 0x44,0x30,0x00,0x00,0x00,0x00,0x30,0x00,0x03,
+ 0x44,0x43,0x33,0x33,0x30,0x00,0x33,0x33,0x33,
+ 0x44,0x44,0x44,0x44,0x40,0x00,0x34,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x40,0x00,0x34,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x33,0x34,0x44,0x44,
+};
+
+static PhImage_t tb_ctags_phi = {
+ Pg_IMAGE_PALETTE_NIBBLE,
+ 0,
+ 9,
+ { 18,18 },
+ 420393992,
+ 8,
+ NULL,
+ PgGrey(0xc0),
+ 0,
+ Ph_USE_TRANSPARENCY,
+ 0,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ tb_palette,
+ tb_ctags_data
+};
+
+static uint8_t tb_cut_data[] = {
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x40,0x44,0x44,0x40,0x34,0x44,0x44,
+ 0x44,0x44,0x40,0x34,0x44,0x40,0x34,0x44,0x44,
+ 0x44,0x44,0x44,0x04,0x44,0x03,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x03,0x44,0x03,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x40,0x40,0x34,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x40,0x30,0x34,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x03,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x40,0x00,0x34,0x44,0x44,0x44,
+ 0x44,0x44,0x43,0x03,0x44,0x03,0x44,0x44,0x44,
+ 0x44,0x44,0x00,0x03,0x44,0x00,0x04,0x44,0x44,
+ 0x44,0x40,0x33,0x03,0x44,0x03,0x40,0x44,0x44,
+ 0x44,0x40,0x44,0x03,0x44,0x03,0x40,0x34,0x44,
+ 0x44,0x40,0x44,0x03,0x44,0x03,0x40,0x34,0x44,
+ 0x44,0x44,0x00,0x33,0x44,0x40,0x03,0x44,0x44,
+ 0x44,0x44,0x33,0x44,0x44,0x43,0x34,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+};
+
+static PhImage_t tb_cut_phi = {
+ Pg_IMAGE_PALETTE_NIBBLE,
+ 0,
+ 9,
+ { 18,18 },
+ 420393992,
+ 8,
+ NULL,
+ PgGrey(0xc0),
+ 0,
+ Ph_USE_TRANSPARENCY,
+ 0,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ tb_palette,
+ tb_cut_data
+};
+
+static uint8_t tb_find_data[] = {
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x40,0x00,0x00,0x00,0x00,0x44,0x44,0x44,0x44,
+ 0x40,0x77,0x77,0x77,0x70,0x04,0x44,0x44,0x44,
+ 0x40,0x77,0x77,0x77,0x70,0x40,0x44,0x44,0x44,
+ 0x40,0x77,0x77,0x77,0x70,0x00,0x04,0x44,0x44,
+ 0x40,0x77,0x77,0x77,0x77,0x77,0x04,0x44,0x44,
+ 0x40,0x77,0x77,0x77,0x70,0x00,0x04,0x44,0x44,
+ 0x40,0x77,0x77,0x77,0x04,0x44,0x40,0x44,0x44,
+ 0x40,0x77,0x77,0x70,0x47,0x74,0x44,0x04,0x44,
+ 0x40,0x77,0x77,0x70,0x47,0x44,0x44,0x04,0x44,
+ 0x40,0x77,0x77,0x70,0x44,0x44,0x44,0x04,0x44,
+ 0x40,0x77,0x77,0x70,0x44,0x47,0x44,0x04,0x44,
+ 0x40,0x77,0x77,0x77,0x04,0x44,0x40,0x44,0x44,
+ 0x40,0x77,0x77,0x77,0x70,0x00,0x04,0x00,0x44,
+ 0x40,0x77,0x77,0x77,0x77,0x77,0x04,0x00,0x04,
+ 0x40,0x00,0x00,0x00,0x00,0x00,0x04,0x40,0x04,
+ 0x44,0x44,0x33,0x33,0x33,0x33,0x33,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+};
+
+static PhImage_t tb_find_phi = {
+ Pg_IMAGE_PALETTE_NIBBLE,
+ 0,
+ 9,
+ { 18,18 },
+ 420393992,
+ 8,
+ NULL,
+ PgGrey(0xc0),
+ 0,
+ Ph_USE_TRANSPARENCY,
+ 0,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ tb_palette,
+ tb_find_data
+};
+
+static uint8_t tb_find_help_data[] = {
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x00,0x00,0x03,0x44,0x44,0x44,0x44,
+ 0x44,0x40,0x04,0x43,0x00,0x34,0x44,0x44,0x44,
+ 0x44,0x00,0x34,0x44,0x00,0x04,0x44,0x44,0x44,
+ 0x44,0x00,0x34,0x44,0x00,0x00,0x44,0x44,0x44,
+ 0x44,0x30,0x04,0x40,0x47,0x74,0x04,0x44,0x44,
+ 0x44,0x44,0x44,0x04,0x44,0x74,0x40,0x44,0x44,
+ 0x44,0x44,0x44,0x07,0x77,0x74,0x70,0x44,0x44,
+ 0x44,0x44,0x40,0x04,0x77,0x44,0x40,0x44,0x44,
+ 0x44,0x44,0x40,0x00,0x47,0x74,0x03,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x00,0x00,0x30,0x04,0x44,
+ 0x44,0x44,0x40,0x03,0x44,0x44,0x40,0x00,0x44,
+ 0x44,0x44,0x40,0x03,0x44,0x44,0x44,0x00,0x44,
+ 0x44,0x44,0x40,0x03,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x33,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+};
+
+static PhImage_t tb_find_help_phi = {
+ Pg_IMAGE_PALETTE_NIBBLE,
+ 0,
+ 9,
+ { 18,18 },
+ 420393992,
+ 8,
+ NULL,
+ PgGrey(0xc0),
+ 0,
+ Ph_USE_TRANSPARENCY,
+ 0,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ tb_palette,
+ tb_find_help_data
+};
+
+static uint8_t tb_find_next_data[] = {
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x00,0x00,0x00,0x00,0x04,0x44,0x44,0x44,
+ 0x44,0x07,0x77,0x77,0x77,0x00,0x44,0x44,0x44,
+ 0x44,0x07,0x77,0x77,0x77,0x04,0x04,0x44,0x44,
+ 0x44,0x07,0x17,0x77,0x77,0x00,0x00,0x44,0x44,
+ 0x44,0x77,0x11,0x77,0x77,0x77,0x70,0x44,0x44,
+ 0x11,0x11,0x15,0x17,0x77,0x00,0x00,0x44,0x44,
+ 0x15,0x55,0x55,0x51,0x70,0x44,0x44,0x04,0x44,
+ 0x15,0x55,0x55,0x55,0x14,0x77,0x44,0x40,0x44,
+ 0x15,0x55,0x55,0x51,0x04,0x74,0x44,0x40,0x44,
+ 0x11,0x11,0x15,0x17,0x04,0x44,0x44,0x40,0x44,
+ 0x44,0x77,0x11,0x77,0x04,0x44,0x74,0x40,0x44,
+ 0x44,0x07,0x17,0x77,0x70,0x44,0x44,0x04,0x44,
+ 0x44,0x07,0x77,0x77,0x77,0x00,0x00,0x40,0x04,
+ 0x44,0x07,0x77,0x77,0x77,0x77,0x70,0x40,0x00,
+ 0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x44,0x00,
+ 0x44,0x44,0x43,0x33,0x33,0x33,0x33,0x34,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+};
+
+static PhImage_t tb_find_next_phi = {
+ Pg_IMAGE_PALETTE_NIBBLE,
+ 0,
+ 9,
+ { 18,18 },
+ 420393992,
+ 8,
+ NULL,
+ PgGrey(0xc0),
+ 0,
+ Ph_USE_TRANSPARENCY,
+ 0,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ tb_palette,
+ tb_find_next_data
+};
+
+static uint8_t tb_find_prev_data[] = {
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x00,0x00,0x00,0x00,0x04,0x44,0x44,0x44,
+ 0x44,0x07,0x77,0x77,0x77,0x00,0x44,0x44,0x44,
+ 0x44,0x07,0x77,0x77,0x77,0x04,0x04,0x44,0x44,
+ 0x44,0x47,0x17,0x77,0x77,0x00,0x00,0x44,0x44,
+ 0x44,0x71,0x17,0x77,0x77,0x77,0x70,0x44,0x44,
+ 0x44,0x15,0x11,0x11,0x17,0x00,0x00,0x44,0x44,
+ 0x41,0x55,0x55,0x55,0x10,0x44,0x44,0x04,0x44,
+ 0x15,0x55,0x55,0x55,0x04,0x77,0x44,0x40,0x44,
+ 0x41,0x55,0x55,0x55,0x04,0x74,0x44,0x40,0x44,
+ 0x44,0x15,0x11,0x11,0x04,0x44,0x44,0x40,0x44,
+ 0x44,0x71,0x17,0x77,0x04,0x44,0x74,0x40,0x44,
+ 0x44,0x47,0x17,0x77,0x70,0x44,0x44,0x04,0x44,
+ 0x44,0x07,0x77,0x77,0x77,0x00,0x00,0x40,0x04,
+ 0x44,0x07,0x77,0x77,0x77,0x77,0x70,0x40,0x00,
+ 0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x44,0x00,
+ 0x44,0x44,0x43,0x33,0x33,0x33,0x33,0x34,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+};
+
+static PhImage_t tb_find_prev_phi = {
+ Pg_IMAGE_PALETTE_NIBBLE,
+ 0,
+ 9,
+ { 18,18 },
+ 420393992,
+ 8,
+ NULL,
+ PgGrey(0xc0),
+ 0,
+ Ph_USE_TRANSPARENCY,
+ 0,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ tb_palette,
+ tb_find_prev_data
+};
+
+static uint8_t tb_help_data[] = {
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x00,0x00,0x03,0x44,0x44,0x44,
+ 0x44,0x44,0x40,0x04,0x43,0x00,0x34,0x44,0x44,
+ 0x44,0x44,0x00,0x34,0x44,0x00,0x04,0x44,0x44,
+ 0x44,0x44,0x00,0x34,0x44,0x00,0x04,0x44,0x44,
+ 0x44,0x44,0x30,0x04,0x43,0x00,0x34,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x40,0x03,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x00,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x40,0x03,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x40,0x03,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x40,0x03,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x40,0x03,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x40,0x03,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x33,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+};
+
+static PhImage_t tb_help_phi = {
+ Pg_IMAGE_PALETTE_NIBBLE,
+ 0,
+ 9,
+ { 18,18 },
+ 420393992,
+ 8,
+ NULL,
+ PgGrey(0xc0),
+ 0,
+ Ph_USE_TRANSPARENCY,
+ 0,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ tb_palette,
+ tb_help_data
+};
+
+static uint8_t tb_jump_data[] = {
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x42,0x22,0x22,0x22,0x22,0x22,0x22,0x24,
+ 0x44,0x23,0x66,0x66,0x66,0x66,0x66,0x66,0x03,
+ 0x42,0x36,0x66,0x66,0x66,0x66,0x66,0x66,0x03,
+ 0x23,0x64,0x34,0x66,0x66,0x66,0x66,0x66,0x03,
+ 0x26,0x63,0x03,0x66,0x66,0x66,0x66,0x66,0x03,
+ 0x36,0x64,0x34,0x66,0x66,0x66,0x66,0x66,0x03,
+ 0x30,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x03,
+ 0x43,0x06,0x66,0x66,0x66,0x66,0x66,0x66,0x03,
+ 0x44,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x03,
+ 0x44,0x43,0x33,0x33,0x33,0x33,0x33,0x33,0x33,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+};
+
+static PhImage_t tb_jump_phi = {
+ Pg_IMAGE_PALETTE_NIBBLE,
+ 0,
+ 9,
+ { 18,18 },
+ 420393992,
+ 8,
+ NULL,
+ PgGrey(0xc0),
+ 0,
+ Ph_USE_TRANSPARENCY,
+ 0,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ tb_palette,
+ tb_jump_data
+};
+
+static uint8_t tb_load_session_data[] = {
+ 0x44,0x44,0x44,0x44,0x11,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x41,0x55,0x14,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x15,0x55,0x51,0x44,0x44,0x44,
+ 0x44,0x44,0x41,0x11,0x55,0x11,0x14,0x44,0x44,
+ 0x44,0x44,0x44,0x41,0x55,0x14,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x41,0x55,0x14,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x41,0x55,0x14,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x41,0x11,0x14,0x44,0x44,0x44,
+ 0x44,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x44,
+ 0x44,0x07,0x77,0x77,0x77,0x77,0x74,0x43,0x04,
+ 0x40,0x77,0x77,0x77,0x77,0x77,0x77,0x33,0x04,
+ 0x40,0x74,0x44,0x44,0x44,0x44,0x55,0x33,0x04,
+ 0x40,0x74,0x44,0x44,0x44,0x44,0x44,0x33,0x04,
+ 0x40,0x70,0x00,0x00,0x00,0x00,0x04,0x33,0x03,
+ 0x40,0x77,0x77,0x77,0x77,0x77,0x74,0x33,0x03,
+ 0x40,0x43,0x33,0x33,0x33,0x33,0x33,0x30,0x34,
+ 0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x44,
+ 0x44,0x44,0x33,0x33,0x33,0x33,0x33,0x34,0x44,
+};
+
+static PhImage_t tb_load_session_phi = {
+ Pg_IMAGE_PALETTE_NIBBLE,
+ 0,
+ 9,
+ { 18,18 },
+ 420393992,
+ 8,
+ NULL,
+ PgGrey(0xc0),
+ 0,
+ Ph_USE_TRANSPARENCY,
+ 0,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ tb_palette,
+ tb_load_session_data
+};
+
+static uint8_t tb_macro_data[] = {
+ 0x44,0x44,0x43,0x00,0x34,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x30,0x77,0x03,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x07,0x77,0x70,0x34,0x44,0x44,0x44,
+ 0x44,0x43,0x07,0x77,0x70,0x34,0x44,0x44,0x44,
+ 0x44,0x44,0x30,0x77,0x03,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x40,0x00,0x00,0x34,0x44,0x44,0x44,
+ 0x44,0x40,0x00,0x00,0x70,0x34,0x44,0x44,0x44,
+ 0x44,0x30,0x77,0x77,0x77,0x04,0x44,0x44,0x44,
+ 0x44,0x00,0x77,0x77,0x77,0x00,0x44,0x44,0x44,
+ 0x44,0x43,0x00,0x00,0x77,0x30,0x44,0x44,0x44,
+ 0x44,0x44,0x30,0x00,0x77,0x70,0x34,0x44,0x44,
+ 0x44,0x44,0x00,0x77,0x77,0x70,0x04,0x44,0x44,
+ 0x44,0x43,0x07,0x77,0x77,0x77,0x00,0x44,0x44,
+ 0x44,0x40,0x77,0x70,0x00,0x77,0x70,0x04,0x44,
+ 0x44,0x07,0x77,0x03,0x40,0x07,0x77,0x70,0x44,
+ 0x44,0x07,0x70,0x34,0x44,0x30,0x77,0x70,0x44,
+ 0x44,0x30,0x00,0x44,0x44,0x43,0x00,0x03,0x44,
+ 0x44,0x43,0x34,0x44,0x44,0x44,0x43,0x04,0x44,
+};
+
+static PhImage_t tb_macro_phi = {
+ Pg_IMAGE_PALETTE_NIBBLE,
+ 0,
+ 9,
+ { 18,18 },
+ 420393992,
+ 8,
+ NULL,
+ PgGrey(0xc0),
+ 0,
+ Ph_USE_TRANSPARENCY,
+ 0,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ tb_palette,
+ tb_macro_data
+};
+
+static uint8_t tb_make_data[] = {
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x00,0x40,0x00,0x00,0x44,0x44,0x44,
+ 0x44,0x40,0x77,0x07,0x77,0x77,0x04,0x44,0x44,
+ 0x44,0x40,0x77,0x77,0x77,0x77,0x70,0x44,0x44,
+ 0x44,0x40,0x73,0x07,0x77,0x70,0x07,0x04,0x44,
+ 0x44,0x44,0x00,0x40,0x00,0x03,0x40,0x04,0x44,
+ 0x44,0x44,0x44,0x44,0x00,0x04,0x44,0x04,0x44,
+ 0x44,0x44,0x44,0x44,0x00,0x03,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x00,0x03,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x00,0x03,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x00,0x03,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x00,0x03,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x00,0x03,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x00,0x03,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x00,0x03,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x00,0x03,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x43,0x33,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+};
+
+static PhImage_t tb_make_phi = {
+ Pg_IMAGE_PALETTE_NIBBLE,
+ 0,
+ 9,
+ { 18,18 },
+ 420393992,
+ 8,
+ NULL,
+ PgGrey(0xc0),
+ 0,
+ Ph_USE_TRANSPARENCY,
+ 0,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ tb_palette,
+ tb_make_data
+};
+
+static uint8_t tb_maximize_data[] = {
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x70,0x00,0x00,0x00,0x00,0x00,0x44,0x44,
+ 0x44,0x70,0x44,0x44,0x44,0x44,0x70,0x44,0x44,
+ 0x44,0x70,0x44,0x74,0x44,0x44,0x70,0x34,0x44,
+ 0x44,0x70,0x47,0x74,0x04,0x44,0x70,0x34,0x44,
+ 0x44,0x70,0x44,0x40,0x00,0x44,0x70,0x34,0x44,
+ 0x44,0x70,0x44,0x00,0x00,0x04,0x70,0x34,0x44,
+ 0x44,0x70,0x44,0x44,0x44,0x44,0x70,0x34,0x44,
+ 0x44,0x70,0x44,0x44,0x44,0x44,0x70,0x34,0x44,
+ 0x44,0x70,0x44,0x00,0x00,0x04,0x70,0x34,0x44,
+ 0x44,0x70,0x44,0x40,0x00,0x44,0x70,0x34,0x44,
+ 0x44,0x70,0x44,0x44,0x04,0x44,0x70,0x34,0x44,
+ 0x44,0x70,0x44,0x44,0x44,0x44,0x70,0x34,0x44,
+ 0x44,0x70,0x44,0x44,0x44,0x44,0x70,0x34,0x44,
+ 0x44,0x70,0x77,0x77,0x77,0x77,0x70,0x34,0x44,
+ 0x44,0x70,0x00,0x00,0x00,0x00,0x00,0x34,0x44,
+ 0x44,0x44,0x43,0x33,0x33,0x33,0x33,0x34,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+};
+
+static PhImage_t tb_maximize_phi = {
+ Pg_IMAGE_PALETTE_NIBBLE,
+ 0,
+ 9,
+ { 18,18 },
+ 420393992,
+ 8,
+ NULL,
+ PgGrey(0xc0),
+ 0,
+ Ph_USE_TRANSPARENCY,
+ 0,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ tb_palette,
+ tb_maximize_data
+};
+
+static uint8_t tb_maxwidth_data[] = {
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,
+ 0x70,0x44,0x44,0x44,0x44,0x44,0x44,0x47,0x04,
+ 0x70,0x44,0x74,0x40,0x44,0x04,0x44,0x47,0x03,
+ 0x70,0x47,0x74,0x00,0x44,0x00,0x44,0x47,0x03,
+ 0x70,0x44,0x40,0x00,0x44,0x00,0x04,0x47,0x03,
+ 0x70,0x44,0x44,0x00,0x44,0x00,0x44,0x47,0x03,
+ 0x70,0x44,0x44,0x40,0x44,0x04,0x44,0x47,0x03,
+ 0x70,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x03,
+ 0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,
+ 0x44,0x43,0x33,0x33,0x33,0x33,0x33,0x33,0x33,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+};
+
+static PhImage_t tb_maxwidth_phi = {
+ Pg_IMAGE_PALETTE_NIBBLE,
+ 0,
+ 9,
+ { 18,18 },
+ 420393992,
+ 8,
+ NULL,
+ PgGrey(0xc0),
+ 0,
+ Ph_USE_TRANSPARENCY,
+ 0,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ tb_palette,
+ tb_maxwidth_data
+};
+
+static uint8_t tb_minimize_data[] = {
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x40,0x00,0x00,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x00,0x04,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x40,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x47,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x44,
+ 0x47,0x04,0x44,0x44,0x44,0x44,0x47,0x04,0x44,
+ 0x47,0x04,0x47,0x44,0x44,0x44,0x47,0x03,0x44,
+ 0x47,0x04,0x44,0x44,0x44,0x44,0x47,0x03,0x44,
+ 0x47,0x04,0x44,0x44,0x44,0x44,0x77,0x03,0x44,
+ 0x47,0x07,0x77,0x77,0x77,0x77,0x77,0x03,0x44,
+ 0x47,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x44,
+ 0x44,0x44,0x33,0x33,0x33,0x33,0x33,0x33,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x40,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x00,0x04,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x40,0x00,0x00,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+};
+
+static PhImage_t tb_minimize_phi = {
+ Pg_IMAGE_PALETTE_NIBBLE,
+ 0,
+ 9,
+ { 18,18 },
+ 420393992,
+ 8,
+ NULL,
+ PgGrey(0xc0),
+ 0,
+ Ph_USE_TRANSPARENCY,
+ 0,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ tb_palette,
+ tb_minimize_data
+};
+
+static uint8_t tb_minwidth_data[] = {
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x47,0x00,0x00,0x00,0x44,0x44,0x44,
+ 0x44,0x44,0x47,0x04,0x44,0x70,0x44,0x44,0x44,
+ 0x40,0x44,0x47,0x04,0x74,0x70,0x34,0x44,0x04,
+ 0x40,0x04,0x47,0x04,0x44,0x70,0x34,0x40,0x04,
+ 0x40,0x00,0x47,0x04,0x44,0x70,0x34,0x00,0x04,
+ 0x40,0x04,0x47,0x04,0x44,0x70,0x34,0x40,0x04,
+ 0x40,0x44,0x47,0x04,0x44,0x70,0x34,0x44,0x04,
+ 0x44,0x44,0x47,0x07,0x77,0x70,0x34,0x44,0x44,
+ 0x44,0x44,0x47,0x00,0x00,0x00,0x34,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x33,0x33,0x34,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+};
+
+static PhImage_t tb_minwidth_phi = {
+ Pg_IMAGE_PALETTE_NIBBLE,
+ 0,
+ 9,
+ { 18,18 },
+ 420393992,
+ 8,
+ NULL,
+ PgGrey(0xc0),
+ 0,
+ Ph_USE_TRANSPARENCY,
+ 0,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ tb_palette,
+ tb_minwidth_data
+};
+
+static uint8_t tb_new_data[] = {
+ 0x44,0x44,0x44,0x44,0x43,0x44,0x37,0x34,0x44,
+ 0x44,0x44,0x44,0x44,0x47,0x34,0x37,0x34,0x73,
+ 0x44,0x44,0x44,0x44,0x44,0x73,0x07,0x07,0x37,
+ 0x40,0x00,0x00,0x00,0x00,0x07,0x77,0x70,0x33,
+ 0x40,0x44,0x44,0x44,0x44,0x77,0x77,0x77,0x77,
+ 0x40,0x44,0x74,0x44,0x44,0x07,0x07,0x70,0x33,
+ 0x40,0x47,0x74,0x44,0x43,0x47,0x07,0x07,0x44,
+ 0x40,0x44,0x44,0x44,0x34,0x47,0x07,0x33,0x74,
+ 0x40,0x44,0x44,0x44,0x44,0x47,0x07,0x34,0x37,
+ 0x40,0x44,0x44,0x44,0x44,0x47,0x03,0x44,0x43,
+ 0x40,0x44,0x44,0x44,0x44,0x47,0x03,0x44,0x44,
+ 0x40,0x44,0x44,0x44,0x44,0x47,0x03,0x44,0x44,
+ 0x40,0x44,0x44,0x44,0x44,0x47,0x03,0x44,0x44,
+ 0x40,0x44,0x44,0x44,0x44,0x47,0x03,0x44,0x44,
+ 0x40,0x44,0x44,0x44,0x44,0x47,0x03,0x44,0x44,
+ 0x40,0x77,0x77,0x77,0x77,0x77,0x03,0x44,0x44,
+ 0x40,0x00,0x00,0x00,0x00,0x00,0x03,0x44,0x44,
+ 0x44,0x44,0x33,0x33,0x33,0x33,0x33,0x44,0x44,
+};
+
+static PhImage_t tb_new_phi = {
+ Pg_IMAGE_PALETTE_NIBBLE,
+ 0,
+ 9,
+ { 18,18 },
+ 420393992,
+ 8,
+ NULL,
+ PgGrey(0xc0),
+ 0,
+ Ph_USE_TRANSPARENCY,
+ 0,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ tb_palette,
+ tb_new_data
+};
+
+static uint8_t tb_new_session_data[] = {
+ 0x44,0x44,0x34,0x43,0x73,0x44,0x34,0x44,0x44,
+ 0x44,0x44,0x43,0x40,0x70,0x43,0x44,0x44,0x44,
+ 0x44,0x44,0x33,0x07,0x77,0x03,0x34,0x44,0x44,
+ 0x44,0x44,0x77,0x77,0x77,0x77,0x74,0x44,0x44,
+ 0x44,0x44,0x33,0x07,0x77,0x03,0x34,0x44,0x44,
+ 0x44,0x44,0x43,0x40,0x70,0x43,0x44,0x44,0x44,
+ 0x44,0x44,0x34,0x43,0x73,0x44,0x34,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x34,0x44,0x44,0x44,0x44,
+ 0x44,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x44,
+ 0x44,0x07,0x77,0x77,0x77,0x77,0x74,0x43,0x04,
+ 0x40,0x77,0x77,0x77,0x77,0x77,0x77,0x33,0x04,
+ 0x40,0x74,0x44,0x44,0x44,0x44,0x55,0x33,0x04,
+ 0x40,0x74,0x44,0x44,0x44,0x44,0x44,0x33,0x04,
+ 0x40,0x70,0x00,0x00,0x00,0x00,0x04,0x33,0x03,
+ 0x40,0x77,0x77,0x77,0x77,0x77,0x74,0x33,0x03,
+ 0x40,0x43,0x33,0x33,0x33,0x33,0x33,0x30,0x34,
+ 0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x44,
+ 0x44,0x44,0x33,0x33,0x33,0x33,0x33,0x34,0x44,
+};
+
+static PhImage_t tb_new_session_phi = {
+ Pg_IMAGE_PALETTE_NIBBLE,
+ 0,
+ 9,
+ { 18,18 },
+ 420393992,
+ 8,
+ NULL,
+ PgGrey(0xc0),
+ 0,
+ Ph_USE_TRANSPARENCY,
+ 0,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ tb_palette,
+ tb_new_session_data
+};
+
+static uint8_t tb_open_data[] = {
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x00,0x00,0x00,0x00,0x03,0x44,0x44,
+ 0x44,0x44,0x07,0x77,0x77,0x70,0x70,0x34,0x44,
+ 0x44,0x44,0x07,0x77,0x77,0x70,0x77,0x03,0x44,
+ 0x44,0x44,0x07,0x77,0x77,0x70,0x00,0x03,0x44,
+ 0x44,0x00,0x07,0x77,0x77,0x77,0x77,0x00,0x04,
+ 0x44,0x04,0x04,0x44,0x44,0x44,0x47,0x04,0x04,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x03,0x03,
+ 0x07,0x77,0x77,0x77,0x77,0x77,0x70,0x03,0x03,
+ 0x40,0x74,0x44,0x44,0x44,0x44,0x43,0x03,0x03,
+ 0x40,0x74,0x44,0x44,0x44,0x44,0x44,0x03,0x03,
+ 0x44,0x07,0x44,0x44,0x44,0x44,0x44,0x30,0x03,
+ 0x44,0x07,0x44,0x44,0x44,0x44,0x44,0x40,0x03,
+ 0x44,0x40,0x73,0x33,0x33,0x33,0x33,0x33,0x03,
+ 0x44,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x03,
+ 0x44,0x44,0x43,0x33,0x33,0x33,0x33,0x33,0x33,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+};
+
+static PhImage_t tb_open_phi = {
+ Pg_IMAGE_PALETTE_NIBBLE,
+ 0,
+ 9,
+ { 18,18 },
+ 420393992,
+ 8,
+ NULL,
+ PgGrey(0xc0),
+ 0,
+ Ph_USE_TRANSPARENCY,
+ 0,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ tb_palette,
+ tb_open_data
+};
+
+static uint8_t tb_paste_data[] = {
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x40,0x00,0x04,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x40,0x00,0x04,0x44,0x44,0x44,0x44,
+ 0x44,0x00,0x04,0x44,0x40,0x00,0x34,0x44,0x44,
+ 0x40,0x43,0x00,0x00,0x00,0x33,0x03,0x44,0x44,
+ 0x40,0x43,0x33,0x33,0x33,0x33,0x03,0x44,0x44,
+ 0x40,0x43,0x34,0x00,0x00,0x00,0x00,0x00,0x44,
+ 0x40,0x43,0x34,0x07,0x77,0x77,0x77,0x70,0x44,
+ 0x40,0x43,0x34,0x07,0x00,0x00,0x00,0x70,0x34,
+ 0x40,0x43,0x34,0x07,0x77,0x77,0x77,0x70,0x34,
+ 0x40,0x43,0x34,0x07,0x77,0x77,0x77,0x70,0x34,
+ 0x40,0x43,0x34,0x07,0x00,0x00,0x00,0x70,0x34,
+ 0x40,0x43,0x34,0x07,0x77,0x77,0x77,0x70,0x34,
+ 0x44,0x00,0x00,0x07,0x00,0x77,0x77,0x70,0x34,
+ 0x44,0x43,0x33,0x07,0x77,0x77,0x77,0x70,0x34,
+ 0x44,0x44,0x44,0x00,0x00,0x00,0x00,0x00,0x34,
+ 0x44,0x44,0x44,0x44,0x33,0x33,0x33,0x33,0x34,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+};
+
+static PhImage_t tb_paste_phi = {
+ Pg_IMAGE_PALETTE_NIBBLE,
+ 0,
+ 9,
+ { 18,18 },
+ 420393992,
+ 8,
+ NULL,
+ PgGrey(0xc0),
+ 0,
+ Ph_USE_TRANSPARENCY,
+ 0,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ tb_palette,
+ tb_paste_data
+};
+
+static uint8_t tb_print_data[] = {
+ 0x44,0x40,0x00,0x00,0x00,0x00,0x04,0x44,0x44,
+ 0x44,0x40,0x77,0x77,0x77,0x77,0x04,0x44,0x44,
+ 0x44,0x40,0x70,0x00,0x77,0x77,0x03,0x44,0x44,
+ 0x44,0x40,0x77,0x77,0x77,0x77,0x03,0x44,0x44,
+ 0x44,0x40,0x70,0x00,0x77,0x77,0x03,0x44,0x44,
+ 0x44,0x40,0x77,0x77,0x77,0x77,0x03,0x44,0x44,
+ 0x44,0x40,0x70,0x00,0x00,0x77,0x03,0x44,0x44,
+ 0x44,0x40,0x77,0x77,0x77,0x77,0x03,0x44,0x44,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x44,
+ 0x07,0x77,0x77,0x77,0x77,0x77,0x77,0x30,0x44,
+ 0x07,0x55,0x44,0x44,0x44,0x44,0x44,0x30,0x34,
+ 0x07,0x44,0x44,0x44,0x44,0x44,0x44,0x30,0x34,
+ 0x07,0x44,0x44,0x44,0x44,0x44,0x44,0x30,0x34,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x34,
+ 0x40,0x44,0x44,0x44,0x44,0x44,0x44,0x03,0x34,
+ 0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x44,
+ 0x44,0x43,0x33,0x33,0x33,0x33,0x33,0x33,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+};
+
+static PhImage_t tb_print_phi = {
+ Pg_IMAGE_PALETTE_NIBBLE,
+ 0,
+ 9,
+ { 18,18 },
+ 420393992,
+ 8,
+ NULL,
+ PgGrey(0xc0),
+ 0,
+ Ph_USE_TRANSPARENCY,
+ 0,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ tb_palette,
+ tb_print_data
+};
+
+static uint8_t tb_redo_data[] = {
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x00,0x00,0x04,0x40,0x04,0x44,
+ 0x44,0x44,0x00,0x77,0x77,0x70,0x07,0x03,0x44,
+ 0x44,0x40,0x77,0x77,0x77,0x77,0x77,0x03,0x44,
+ 0x44,0x40,0x77,0x00,0x00,0x77,0x77,0x03,0x44,
+ 0x44,0x07,0x70,0x33,0x30,0x77,0x77,0x03,0x44,
+ 0x44,0x07,0x70,0x34,0x07,0x77,0x77,0x03,0x44,
+ 0x44,0x07,0x70,0x34,0x00,0x00,0x00,0x03,0x44,
+ 0x44,0x07,0x70,0x34,0x43,0x33,0x03,0x33,0x44,
+ 0x44,0x07,0x70,0x34,0x44,0x40,0x70,0x44,0x44,
+ 0x44,0x40,0x77,0x00,0x00,0x07,0x70,0x34,0x44,
+ 0x44,0x40,0x77,0x77,0x77,0x77,0x03,0x34,0x44,
+ 0x44,0x44,0x00,0x77,0x77,0x70,0x33,0x44,0x44,
+ 0x44,0x44,0x44,0x00,0x00,0x03,0x34,0x44,0x44,
+ 0x44,0x44,0x44,0x43,0x33,0x33,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+};
+
+static PhImage_t tb_redo_phi = {
+ Pg_IMAGE_PALETTE_NIBBLE,
+ 0,
+ 9,
+ { 18,18 },
+ 420393992,
+ 8,
+ NULL,
+ PgGrey(0xc0),
+ 0,
+ Ph_USE_TRANSPARENCY,
+ 0,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ tb_palette,
+ tb_redo_data
+};
+
+static uint8_t tb_replace_data[] = {
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x00,0x00,0x00,0x00,0x04,0x44,0x44,0x44,
+ 0x44,0x07,0x77,0x77,0x77,0x00,0x44,0x44,0x44,
+ 0x44,0x07,0x00,0x77,0x77,0x07,0x04,0x44,0x44,
+ 0x44,0x34,0x00,0x37,0x77,0x00,0x00,0x44,0x44,
+ 0x44,0x40,0x70,0x07,0x77,0x77,0x70,0x44,0x44,
+ 0x44,0x30,0x00,0x03,0x77,0x77,0x70,0x34,0x44,
+ 0x44,0x07,0x77,0x00,0x77,0x77,0x70,0x34,0x44,
+ 0x40,0x03,0x73,0x00,0x07,0x77,0x40,0x34,0x44,
+ 0x44,0x47,0x77,0x77,0x77,0x77,0x74,0x34,0x44,
+ 0x44,0x07,0x55,0x44,0x57,0x77,0x00,0x00,0x44,
+ 0x44,0x07,0x35,0x44,0x55,0x77,0x03,0x70,0x04,
+ 0x44,0x07,0x73,0x55,0x55,0x57,0x00,0x00,0x44,
+ 0x44,0x07,0x77,0x77,0x55,0x77,0x03,0x70,0x04,
+ 0x44,0x07,0x77,0x77,0x57,0x77,0x03,0x70,0x04,
+ 0x44,0x00,0x00,0x00,0x40,0x04,0x00,0x00,0x44,
+ 0x44,0x44,0x43,0x33,0x33,0x33,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+};
+
+static PhImage_t tb_replace_phi = {
+ Pg_IMAGE_PALETTE_NIBBLE,
+ 0,
+ 9,
+ { 18,18 },
+ 420393992,
+ 8,
+ NULL,
+ PgGrey(0xc0),
+ 0,
+ Ph_USE_TRANSPARENCY,
+ 0,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ tb_palette,
+ tb_replace_data
+};
+
+static uint8_t tb_save_data[] = {
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x44,
+ 0x44,0x04,0x07,0x77,0x77,0x77,0x70,0x40,0x44,
+ 0x44,0x04,0x07,0x77,0x77,0x77,0x70,0x00,0x34,
+ 0x44,0x04,0x07,0x77,0x77,0x77,0x70,0x40,0x34,
+ 0x44,0x04,0x07,0x77,0x77,0x77,0x70,0x40,0x34,
+ 0x44,0x04,0x07,0x77,0x77,0x77,0x70,0x40,0x34,
+ 0x44,0x04,0x07,0x77,0x77,0x77,0x70,0x40,0x34,
+ 0x44,0x04,0x40,0x00,0x00,0x00,0x04,0x40,0x34,
+ 0x44,0x04,0x44,0x44,0x44,0x44,0x44,0x40,0x34,
+ 0x44,0x04,0x40,0x00,0x00,0x00,0x00,0x40,0x34,
+ 0x44,0x04,0x40,0x00,0x00,0x04,0x40,0x40,0x34,
+ 0x44,0x04,0x40,0x00,0x00,0x04,0x40,0x40,0x34,
+ 0x44,0x04,0x40,0x00,0x00,0x04,0x40,0x40,0x34,
+ 0x44,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x34,
+ 0x44,0x44,0x33,0x33,0x33,0x33,0x33,0x33,0x34,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+};
+
+static PhImage_t tb_save_phi = {
+ Pg_IMAGE_PALETTE_NIBBLE,
+ 0,
+ 9,
+ { 18,18 },
+ 420393992,
+ 8,
+ NULL,
+ PgGrey(0xc0),
+ 0,
+ Ph_USE_TRANSPARENCY,
+ 0,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ tb_palette,
+ tb_save_data
+};
+
+static uint8_t tb_save_all_data[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x44,0x44,
+ 0x04,0x07,0x77,0x77,0x77,0x70,0x70,0x44,0x44,
+ 0x04,0x07,0x77,0x77,0x77,0x70,0x00,0x34,0x44,
+ 0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,
+ 0x04,0x00,0x40,0x77,0x77,0x77,0x77,0x07,0x04,
+ 0x04,0x00,0x40,0x77,0x77,0x77,0x77,0x00,0x03,
+ 0x04,0x00,0x40,0x77,0x77,0x77,0x77,0x04,0x03,
+ 0x04,0x40,0x40,0x77,0x77,0x77,0x77,0x04,0x03,
+ 0x04,0x40,0x40,0x77,0x77,0x77,0x77,0x04,0x03,
+ 0x04,0x40,0x40,0x77,0x77,0x77,0x77,0x04,0x03,
+ 0x04,0x40,0x44,0x00,0x00,0x00,0x00,0x44,0x03,
+ 0x04,0x40,0x44,0x44,0x44,0x44,0x44,0x44,0x03,
+ 0x04,0x40,0x44,0x00,0x00,0x00,0x00,0x04,0x03,
+ 0x40,0x00,0x44,0x00,0x00,0x00,0x77,0x04,0x03,
+ 0x44,0x30,0x44,0x00,0x00,0x00,0x77,0x04,0x03,
+ 0x44,0x40,0x44,0x00,0x00,0x00,0x77,0x04,0x03,
+ 0x44,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x03,
+ 0x44,0x44,0x43,0x33,0x33,0x33,0x33,0x33,0x34,
+};
+
+static PhImage_t tb_save_all_phi = {
+ Pg_IMAGE_PALETTE_NIBBLE,
+ 0,
+ 9,
+ { 18,18 },
+ 420393992,
+ 8,
+ NULL,
+ PgGrey(0xc0),
+ 0,
+ Ph_USE_TRANSPARENCY,
+ 0,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ tb_palette,
+ tb_save_all_data
+};
+
+static uint8_t tb_save_session_data[] = {
+ 0x44,0x44,0x44,0x41,0x11,0x14,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x41,0x55,0x14,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x41,0x55,0x14,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x41,0x55,0x14,0x44,0x44,0x44,
+ 0x44,0x44,0x41,0x11,0x55,0x11,0x14,0x44,0x44,
+ 0x44,0x44,0x44,0x15,0x55,0x51,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x41,0x55,0x14,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x11,0x44,0x44,0x44,0x44,
+ 0x44,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x44,
+ 0x44,0x07,0x77,0x77,0x77,0x77,0x74,0x43,0x04,
+ 0x40,0x77,0x77,0x77,0x77,0x77,0x77,0x33,0x04,
+ 0x40,0x74,0x44,0x44,0x44,0x44,0x55,0x33,0x04,
+ 0x40,0x74,0x44,0x44,0x44,0x44,0x44,0x33,0x04,
+ 0x40,0x70,0x00,0x00,0x00,0x00,0x04,0x33,0x03,
+ 0x40,0x77,0x77,0x77,0x77,0x77,0x74,0x33,0x03,
+ 0x40,0x43,0x33,0x33,0x33,0x33,0x33,0x30,0x34,
+ 0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x44,
+ 0x44,0x44,0x33,0x33,0x33,0x33,0x33,0x34,0x44,
+};
+
+static PhImage_t tb_save_session_phi = {
+ Pg_IMAGE_PALETTE_NIBBLE,
+ 0,
+ 9,
+ { 18,18 },
+ 420393992,
+ 8,
+ NULL,
+ PgGrey(0xc0),
+ 0,
+ Ph_USE_TRANSPARENCY,
+ 0,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ tb_palette,
+ tb_save_session_data
+};
+
+static uint8_t tb_shell_data[] = {
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x40,0x00,0x40,0x00,0x44,0x44,0x44,
+ 0x44,0x44,0x03,0x43,0x33,0x43,0x04,0x44,0x44,
+ 0x44,0x40,0x47,0x43,0x03,0x47,0x40,0x44,0x44,
+ 0x44,0x40,0x34,0x74,0x34,0x74,0x30,0x44,0x44,
+ 0x44,0x03,0x44,0x44,0x04,0x44,0x43,0x04,0x44,
+ 0x40,0x34,0x03,0x74,0x34,0x73,0x04,0x30,0x44,
+ 0x40,0x44,0x43,0x74,0x04,0x73,0x44,0x40,0x44,
+ 0x40,0x47,0x40,0x37,0x37,0x30,0x47,0x40,0x34,
+ 0x40,0x34,0x74,0x04,0x04,0x04,0x74,0x30,0x34,
+ 0x44,0x03,0x74,0x34,0x44,0x34,0x73,0x03,0x44,
+ 0x44,0x40,0x34,0x44,0x74,0x44,0x30,0x34,0x44,
+ 0x44,0x44,0x04,0x47,0x77,0x44,0x03,0x44,0x44,
+ 0x44,0x44,0x00,0x34,0x44,0x30,0x03,0x44,0x44,
+ 0x44,0x40,0x34,0x44,0x44,0x44,0x30,0x34,0x44,
+ 0x44,0x40,0x00,0x00,0x00,0x00,0x00,0x34,0x44,
+ 0x44,0x44,0x43,0x33,0x33,0x33,0x33,0x34,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+};
+
+static PhImage_t tb_shell_phi = {
+ Pg_IMAGE_PALETTE_NIBBLE,
+ 0,
+ 9,
+ { 18,18 },
+ 420393992,
+ 8,
+ NULL,
+ PgGrey(0xc0),
+ 0,
+ Ph_USE_TRANSPARENCY,
+ 0,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ tb_palette,
+ tb_shell_data
+};
+
+static uint8_t tb_split_data[] = {
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x70,0x00,0x00,0x00,0x00,0x00,0x44,0x44,
+ 0x44,0x70,0x44,0x44,0x44,0x44,0x70,0x44,0x44,
+ 0x44,0x70,0x44,0x74,0x44,0x44,0x70,0x34,0x44,
+ 0x44,0x70,0x47,0x74,0x44,0x44,0x70,0x34,0x44,
+ 0x44,0x70,0x44,0x44,0x44,0x44,0x70,0x34,0x44,
+ 0x44,0x70,0x44,0x44,0x44,0x44,0x70,0x34,0x44,
+ 0x44,0x70,0x77,0x77,0x77,0x77,0x70,0x34,0x44,
+ 0x44,0x70,0x00,0x00,0x00,0x00,0x00,0x34,0x44,
+ 0x44,0x70,0x33,0x33,0x33,0x33,0x70,0x34,0x44,
+ 0x44,0x70,0x44,0x74,0x44,0x44,0x70,0x34,0x44,
+ 0x44,0x70,0x47,0x74,0x44,0x44,0x70,0x34,0x44,
+ 0x44,0x70,0x44,0x44,0x44,0x44,0x70,0x34,0x44,
+ 0x44,0x70,0x44,0x44,0x44,0x44,0x70,0x34,0x44,
+ 0x44,0x70,0x77,0x77,0x77,0x77,0x70,0x34,0x44,
+ 0x44,0x70,0x00,0x00,0x00,0x00,0x00,0x34,0x44,
+ 0x44,0x44,0x43,0x33,0x33,0x33,0x33,0x34,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+};
+
+static PhImage_t tb_split_phi = {
+ Pg_IMAGE_PALETTE_NIBBLE,
+ 0,
+ 9,
+ { 18,18 },
+ 420393992,
+ 8,
+ NULL,
+ PgGrey(0xc0),
+ 0,
+ Ph_USE_TRANSPARENCY,
+ 0,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ tb_palette,
+ tb_split_data
+};
+
+static uint8_t tb_undo_data[] = {
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x00,0x44,0x00,0x00,0x04,0x44,0x44,0x44,
+ 0x44,0x07,0x00,0x77,0x77,0x70,0x04,0x44,0x44,
+ 0x44,0x07,0x77,0x77,0x77,0x77,0x70,0x44,0x44,
+ 0x44,0x07,0x77,0x70,0x00,0x07,0x70,0x34,0x44,
+ 0x44,0x07,0x77,0x70,0x33,0x30,0x77,0x04,0x44,
+ 0x44,0x07,0x77,0x77,0x04,0x40,0x77,0x03,0x44,
+ 0x44,0x00,0x00,0x00,0x03,0x40,0x77,0x03,0x44,
+ 0x44,0x43,0x03,0x33,0x33,0x40,0x77,0x03,0x44,
+ 0x44,0x40,0x70,0x44,0x44,0x40,0x77,0x03,0x44,
+ 0x44,0x40,0x77,0x00,0x00,0x07,0x70,0x33,0x44,
+ 0x44,0x44,0x07,0x77,0x77,0x77,0x70,0x34,0x44,
+ 0x44,0x44,0x40,0x77,0x77,0x70,0x03,0x34,0x44,
+ 0x44,0x44,0x44,0x00,0x00,0x03,0x33,0x44,0x44,
+ 0x44,0x44,0x44,0x43,0x33,0x33,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+};
+
+static PhImage_t tb_undo_phi = {
+ Pg_IMAGE_PALETTE_NIBBLE,
+ 0,
+ 9,
+ { 18,18 },
+ 420393992,
+ 8,
+ NULL,
+ PgGrey(0xc0),
+ 0,
+ Ph_USE_TRANSPARENCY,
+ 0,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ tb_palette,
+ tb_undo_data
+};
+
+static uint8_t tb_vsplit_data[] = {
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+ 0x47,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x44,
+ 0x47,0x04,0x44,0x47,0x03,0x44,0x44,0x70,0x44,
+ 0x47,0x04,0x47,0x47,0x03,0x44,0x74,0x70,0x34,
+ 0x47,0x04,0x77,0x47,0x03,0x47,0x74,0x70,0x34,
+ 0x47,0x04,0x44,0x47,0x03,0x44,0x44,0x70,0x34,
+ 0x47,0x04,0x44,0x47,0x03,0x44,0x44,0x70,0x34,
+ 0x47,0x04,0x44,0x47,0x03,0x44,0x44,0x70,0x34,
+ 0x47,0x04,0x44,0x47,0x03,0x44,0x44,0x70,0x34,
+ 0x47,0x04,0x44,0x47,0x03,0x44,0x44,0x70,0x34,
+ 0x47,0x04,0x44,0x47,0x03,0x44,0x44,0x70,0x34,
+ 0x47,0x04,0x44,0x47,0x03,0x44,0x44,0x70,0x34,
+ 0x47,0x04,0x44,0x47,0x03,0x44,0x44,0x70,0x34,
+ 0x47,0x04,0x44,0x47,0x03,0x44,0x44,0x70,0x34,
+ 0x47,0x07,0x77,0x77,0x07,0x77,0x77,0x70,0x34,
+ 0x47,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x34,
+ 0x44,0x44,0x33,0x33,0x33,0x33,0x33,0x33,0x34,
+ 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+};
+
+static PhImage_t tb_vsplit_phi = {
+ Pg_IMAGE_PALETTE_NIBBLE,
+ 0,
+ 9,
+ { 18,18 },
+ 420393992,
+ 8,
+ NULL,
+ PgGrey(0xc0),
+ 0,
+ Ph_USE_TRANSPARENCY,
+ 0,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ tb_palette,
+ tb_vsplit_data
+};
diff --git a/src/toolcheck b/src/toolcheck
new file mode 100755
index 0000000..b05118a
--- /dev/null
+++ b/src/toolcheck
@@ -0,0 +1,36 @@
+#!/bin/sh
+# toolcheck -- check for tools that have severe bugs. Good that all the buggy
+# tools identify by version numbers. This is the spirit of GNU :-)
+#
+# 24.7.95 jw.
+
+retval=0
+reply="`sh -version -c exit 2>&1 < /dev/null`"
+case "$reply" in
+ GNU*1.14.3*)
+ echo "- sh is '$reply'";
+ echo " CAUTION: This shell has a buggy 'trap' command.";
+ echo " The configure script may fail silently.";
+ retval=1;
+ ;;
+ GNU*)
+ echo "- sh is '$reply' - probably OK.";
+ ;;
+ *) ;;
+esac
+
+reply="`sed --version 2>&1 < /dev/null`"
+case "$reply" in
+ GNU\ sed\ version\ 2.0[34])
+ echo "- sed is '$reply'";
+ echo " CAUTION: This sed cannot configure screen properly."
+ retval=1;
+ ;;
+ GNU\ sed\ version\ 2.05|GNU\ sed\ version\ 2.03\ kevin)
+ echo "- sed is '$reply' - good.";
+ ;;
+ GNU*) echo "- sed is '$reply'.";
+ ;;
+ *) ;;
+esac
+exit $retval
diff --git a/src/tools.bmp b/src/tools.bmp
new file mode 100644
index 0000000..5b821d7
--- /dev/null
+++ b/src/tools.bmp
Binary files differ
diff --git a/src/typemap b/src/typemap
new file mode 100644
index 0000000..ca1600e
--- /dev/null
+++ b/src/typemap
@@ -0,0 +1,14 @@
+TYPEMAP
+VIWIN T_VIOBJNOMUNGE
+VIBUF T_VIOBJNOMUNGE
+
+INPUT
+T_VIOBJNOMUNGE
+ if (sv_isa($arg, \"${ntype}\")) {
+ IV tmp = SvIV((SV*)SvRV($arg));
+ $var = INT2PTR($type, tmp);
+ if (!tmp)
+ croak(\"$ntype no longer exists\");
+ }
+ else
+ croak(\"$var is not of type ${ntype}\")
diff --git a/src/ui.c b/src/ui.c
new file mode 100644
index 0000000..0823d2d
--- /dev/null
+++ b/src/ui.c
@@ -0,0 +1,3533 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * ui.c: functions that handle the user interface.
+ * 1. Keyboard input stuff, and a bit of windowing stuff. These are called
+ * before the machine specific stuff (mch_*) so that we can call the GUI
+ * stuff instead if the GUI is running.
+ * 2. Clipboard stuff.
+ * 3. Input buffer stuff.
+ */
+
+#include "vim.h"
+
+#ifdef FEAT_CYGWIN_WIN32_CLIPBOARD
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+# include "winclip.pro"
+#endif
+
+ void
+ui_write(char_u *s, int len)
+{
+#ifdef FEAT_GUI
+ if (gui.in_use && !gui.dying && !gui.starting)
+ {
+ gui_write(s, len);
+ if (p_wd)
+ gui_wait_for_chars(p_wd, typebuf.tb_change_cnt);
+ return;
+ }
+#endif
+#ifndef NO_CONSOLE
+ /* Don't output anything in silent mode ("ex -s") unless 'verbose' set */
+ if (!(silent_mode && p_verbose == 0))
+ {
+#if !defined(WIN3264)
+ char_u *tofree = NULL;
+
+ if (output_conv.vc_type != CONV_NONE)
+ {
+ /* Convert characters from 'encoding' to 'termencoding'. */
+ tofree = string_convert(&output_conv, s, &len);
+ if (tofree != NULL)
+ s = tofree;
+ }
+#endif
+
+ mch_write(s, len);
+
+# if !defined(WIN3264)
+ if (output_conv.vc_type != CONV_NONE)
+ vim_free(tofree);
+# endif
+ }
+#endif
+}
+
+#if defined(UNIX) || defined(VMS) || defined(PROTO) || defined(WIN3264)
+/*
+ * When executing an external program, there may be some typed characters that
+ * are not consumed by it. Give them back to ui_inchar() and they are stored
+ * here for the next call.
+ */
+static char_u *ta_str = NULL;
+static int ta_off; /* offset for next char to use when ta_str != NULL */
+static int ta_len; /* length of ta_str when it's not NULL*/
+
+ void
+ui_inchar_undo(char_u *s, int len)
+{
+ char_u *new;
+ int newlen;
+
+ newlen = len;
+ if (ta_str != NULL)
+ newlen += ta_len - ta_off;
+ new = alloc(newlen);
+ if (new != NULL)
+ {
+ if (ta_str != NULL)
+ {
+ mch_memmove(new, ta_str + ta_off, (size_t)(ta_len - ta_off));
+ mch_memmove(new + ta_len - ta_off, s, (size_t)len);
+ vim_free(ta_str);
+ }
+ else
+ mch_memmove(new, s, (size_t)len);
+ ta_str = new;
+ ta_len = newlen;
+ ta_off = 0;
+ }
+}
+#endif
+
+/*
+ * ui_inchar(): low level input function.
+ * Get characters from the keyboard.
+ * Return the number of characters that are available.
+ * If "wtime" == 0 do not wait for characters.
+ * If "wtime" == -1 wait forever for characters.
+ * If "wtime" > 0 wait "wtime" milliseconds for a character.
+ *
+ * "tb_change_cnt" is the value of typebuf.tb_change_cnt if "buf" points into
+ * it. When typebuf.tb_change_cnt changes (e.g., when a message is received
+ * from a remote client) "buf" can no longer be used. "tb_change_cnt" is NULL
+ * otherwise.
+ */
+ int
+ui_inchar(
+ char_u *buf,
+ int maxlen,
+ long wtime, /* don't use "time", MIPS cannot handle it */
+ int tb_change_cnt)
+{
+ int retval = 0;
+
+#if defined(FEAT_GUI) && (defined(UNIX) || defined(VMS))
+ /*
+ * Use the typeahead if there is any.
+ */
+ if (ta_str != NULL)
+ {
+ if (maxlen >= ta_len - ta_off)
+ {
+ mch_memmove(buf, ta_str + ta_off, (size_t)ta_len);
+ VIM_CLEAR(ta_str);
+ return ta_len;
+ }
+ mch_memmove(buf, ta_str + ta_off, (size_t)maxlen);
+ ta_off += maxlen;
+ return maxlen;
+ }
+#endif
+
+#ifdef FEAT_PROFILE
+ if (do_profiling == PROF_YES && wtime != 0)
+ prof_inchar_enter();
+#endif
+
+#ifdef NO_CONSOLE_INPUT
+ /* Don't wait for character input when the window hasn't been opened yet.
+ * Do try reading, this works when redirecting stdin from a file.
+ * Must return something, otherwise we'll loop forever. If we run into
+ * this very often we probably got stuck, exit Vim. */
+ if (no_console_input())
+ {
+ static int count = 0;
+
+# ifndef NO_CONSOLE
+ retval = mch_inchar(buf, maxlen, wtime, tb_change_cnt);
+ if (retval > 0 || typebuf_changed(tb_change_cnt) || wtime >= 0)
+ goto theend;
+# endif
+ if (wtime == -1 && ++count == 1000)
+ read_error_exit();
+ buf[0] = CAR;
+ retval = 1;
+ goto theend;
+ }
+#endif
+
+ /* If we are going to wait for some time or block... */
+ if (wtime == -1 || wtime > 100L)
+ {
+ /* ... allow signals to kill us. */
+ (void)vim_handle_signal(SIGNAL_UNBLOCK);
+
+ /* ... there is no need for CTRL-C to interrupt something, don't let
+ * it set got_int when it was mapped. */
+ if ((mapped_ctrl_c | curbuf->b_mapped_ctrl_c) & get_real_state())
+ ctrl_c_interrupts = FALSE;
+ }
+
+ /*
+ * Here we call gui_inchar() or mch_inchar(), the GUI or machine-dependent
+ * input function. The functionality they implement is like this:
+ *
+ * while (not timed out)
+ * {
+ * handle-resize;
+ * parse-queued-messages;
+ * if (waited for 'updatetime')
+ * trigger-cursorhold;
+ * ui_wait_for_chars_or_timer()
+ * if (character available)
+ * break;
+ * }
+ *
+ * ui_wait_for_chars_or_timer() does:
+ *
+ * while (not timed out)
+ * {
+ * if (any-timer-triggered)
+ * invoke-timer-callback;
+ * wait-for-character();
+ * if (character available)
+ * break;
+ * }
+ *
+ * wait-for-character() does:
+ * while (not timed out)
+ * {
+ * Wait for event;
+ * if (something on channel)
+ * read/write channel;
+ * else if (resized)
+ * handle_resize();
+ * else if (system event)
+ * deal-with-system-event;
+ * else if (character available)
+ * break;
+ * }
+ *
+ */
+
+#ifdef FEAT_GUI
+ if (gui.in_use)
+ retval = gui_inchar(buf, maxlen, wtime, tb_change_cnt);
+#endif
+#ifndef NO_CONSOLE
+# ifdef FEAT_GUI
+ else
+# endif
+ retval = mch_inchar(buf, maxlen, wtime, tb_change_cnt);
+#endif
+
+ if (wtime == -1 || wtime > 100L)
+ /* block SIGHUP et al. */
+ (void)vim_handle_signal(SIGNAL_BLOCK);
+
+ ctrl_c_interrupts = TRUE;
+
+#ifdef NO_CONSOLE_INPUT
+theend:
+#endif
+#ifdef FEAT_PROFILE
+ if (do_profiling == PROF_YES && wtime != 0)
+ prof_inchar_exit();
+#endif
+ return retval;
+}
+
+#if defined(UNIX) || defined(FEAT_GUI) || defined(PROTO)
+/*
+ * Common code for mch_inchar() and gui_inchar(): Wait for a while or
+ * indefinitely until characters are available, dealing with timers and
+ * messages on channels.
+ *
+ * "buf" may be NULL if the available characters are not to be returned, only
+ * check if they are available.
+ *
+ * Return the number of characters that are available.
+ * If "wtime" == 0 do not wait for characters.
+ * If "wtime" == n wait a short time for characters.
+ * If "wtime" == -1 wait forever for characters.
+ */
+ int
+inchar_loop(
+ char_u *buf,
+ int maxlen,
+ long wtime, // don't use "time", MIPS cannot handle it
+ int tb_change_cnt,
+ int (*wait_func)(long wtime, int *interrupted, int ignore_input),
+ int (*resize_func)(int check_only))
+{
+ int len;
+ int interrupted = FALSE;
+ int did_call_wait_func = FALSE;
+ int did_start_blocking = FALSE;
+ long wait_time;
+ long elapsed_time = 0;
+#ifdef ELAPSED_FUNC
+ elapsed_T start_tv;
+
+ ELAPSED_INIT(start_tv);
+#endif
+
+ /* repeat until we got a character or waited long enough */
+ for (;;)
+ {
+ /* Check if window changed size while we were busy, perhaps the ":set
+ * columns=99" command was used. */
+ if (resize_func != NULL)
+ resize_func(FALSE);
+
+#ifdef MESSAGE_QUEUE
+ // Only process messages when waiting.
+ if (wtime != 0)
+ {
+ parse_queued_messages();
+ // If input was put directly in typeahead buffer bail out here.
+ if (typebuf_changed(tb_change_cnt))
+ return 0;
+ }
+#endif
+ if (wtime < 0 && did_start_blocking)
+ // blocking and already waited for p_ut
+ wait_time = -1;
+ else
+ {
+ if (wtime >= 0)
+ wait_time = wtime;
+ else
+ // going to block after p_ut
+ wait_time = p_ut;
+#ifdef ELAPSED_FUNC
+ elapsed_time = ELAPSED_FUNC(start_tv);
+#endif
+ wait_time -= elapsed_time;
+
+ // If the waiting time is now zero or less, we timed out. However,
+ // loop at least once to check for characters and events. Matters
+ // when "wtime" is zero.
+ if (wait_time <= 0 && did_call_wait_func)
+ {
+ if (wtime >= 0)
+ // no character available within "wtime"
+ return 0;
+
+ // No character available within 'updatetime'.
+ did_start_blocking = TRUE;
+ if (trigger_cursorhold() && maxlen >= 3
+ && !typebuf_changed(tb_change_cnt))
+ {
+ // Put K_CURSORHOLD in the input buffer or return it.
+ if (buf == NULL)
+ {
+ char_u ibuf[3];
+
+ ibuf[0] = CSI;
+ ibuf[1] = KS_EXTRA;
+ ibuf[2] = (int)KE_CURSORHOLD;
+ add_to_input_buf(ibuf, 3);
+ }
+ else
+ {
+ buf[0] = K_SPECIAL;
+ buf[1] = KS_EXTRA;
+ buf[2] = (int)KE_CURSORHOLD;
+ }
+ return 3;
+ }
+
+ // There is no character available within 'updatetime' seconds:
+ // flush all the swap files to disk. Also done when
+ // interrupted by SIGWINCH.
+ before_blocking();
+ continue;
+ }
+ }
+
+#ifdef FEAT_JOB_CHANNEL
+ if (wait_time < 0 || wait_time > 100L)
+ {
+ // Checking if a job ended requires polling. Do this at least
+ // every 100 msec.
+ if (has_pending_job())
+ wait_time = 100L;
+
+ // If there is readahead then parse_queued_messages() timed out and
+ // we should call it again soon.
+ if (channel_any_readahead())
+ wait_time = 10L;
+ }
+#endif
+#ifdef FEAT_BEVAL_GUI
+ if (p_beval && wait_time > 100L)
+ // The 'balloonexpr' may indirectly invoke a callback while waiting
+ // for a character, need to check often.
+ wait_time = 100L;
+#endif
+
+ // Wait for a character to be typed or another event, such as the winch
+ // signal or an event on the monitored file descriptors.
+ did_call_wait_func = TRUE;
+ if (wait_func(wait_time, &interrupted, FALSE))
+ {
+ // If input was put directly in typeahead buffer bail out here.
+ if (typebuf_changed(tb_change_cnt))
+ return 0;
+
+ // We might have something to return now.
+ if (buf == NULL)
+ // "buf" is NULL, we were just waiting, not actually getting
+ // input.
+ return input_available();
+
+ len = read_from_input_buf(buf, (long)maxlen);
+ if (len > 0)
+ return len;
+ continue;
+ }
+ // Timed out or interrupted with no character available.
+
+#ifndef ELAPSED_FUNC
+ // estimate the elapsed time
+ elapsed_time += wait_time;
+#endif
+
+ if ((resize_func != NULL && resize_func(TRUE))
+#if defined(FEAT_CLIENTSERVER) && defined(UNIX)
+ || server_waiting()
+#endif
+#ifdef MESSAGE_QUEUE
+ || interrupted
+#endif
+ || wait_time > 0
+ || (wtime < 0 && !did_start_blocking))
+ // no character available, but something to be done, keep going
+ continue;
+
+ // no character available or interrupted, return zero
+ break;
+ }
+ return 0;
+}
+#endif
+
+#if defined(FEAT_TIMERS) || defined(PROTO)
+/*
+ * Wait for a timer to fire or "wait_func" to return non-zero.
+ * Returns OK when something was read.
+ * Returns FAIL when it timed out or was interrupted.
+ */
+ int
+ui_wait_for_chars_or_timer(
+ long wtime,
+ int (*wait_func)(long wtime, int *interrupted, int ignore_input),
+ int *interrupted,
+ int ignore_input)
+{
+ int due_time;
+ long remaining = wtime;
+ int tb_change_cnt = typebuf.tb_change_cnt;
+# ifdef FEAT_JOB_CHANNEL
+ int brief_wait = FALSE;
+# endif
+
+ // When waiting very briefly don't trigger timers.
+ if (wtime >= 0 && wtime < 10L)
+ return wait_func(wtime, NULL, ignore_input);
+
+ while (wtime < 0 || remaining > 0)
+ {
+ // Trigger timers and then get the time in wtime until the next one is
+ // due. Wait up to that time.
+ due_time = check_due_timer();
+ if (typebuf.tb_change_cnt != tb_change_cnt)
+ {
+ /* timer may have used feedkeys() */
+ return FAIL;
+ }
+ if (due_time <= 0 || (wtime > 0 && due_time > remaining))
+ due_time = remaining;
+# ifdef FEAT_JOB_CHANNEL
+ if ((due_time < 0 || due_time > 10L)
+# ifdef FEAT_GUI
+ && !gui.in_use
+# endif
+ && (has_pending_job() || channel_any_readahead()))
+ {
+ // There is a pending job or channel, should return soon in order
+ // to handle them ASAP. Do check for input briefly.
+ due_time = 10L;
+ brief_wait = TRUE;
+ }
+# endif
+ if (wait_func(due_time, interrupted, ignore_input))
+ return OK;
+ if ((interrupted != NULL && *interrupted)
+# ifdef FEAT_JOB_CHANNEL
+ || brief_wait
+# endif
+ )
+ // Nothing available, but need to return so that side effects get
+ // handled, such as handling a message on a channel.
+ return FAIL;
+ if (wtime > 0)
+ remaining -= due_time;
+ }
+ return FAIL;
+}
+#endif
+
+/*
+ * Return non-zero if a character is available.
+ */
+ int
+ui_char_avail(void)
+{
+#ifdef FEAT_GUI
+ if (gui.in_use)
+ {
+ gui_mch_update();
+ return input_available();
+ }
+#endif
+#ifndef NO_CONSOLE
+# ifdef NO_CONSOLE_INPUT
+ if (no_console_input())
+ return 0;
+# endif
+ return mch_char_avail();
+#else
+ return 0;
+#endif
+}
+
+/*
+ * Delay for the given number of milliseconds. If ignoreinput is FALSE then we
+ * cancel the delay if a key is hit.
+ */
+ void
+ui_delay(long msec, int ignoreinput)
+{
+#ifdef FEAT_GUI
+ if (gui.in_use && !ignoreinput)
+ gui_wait_for_chars(msec, typebuf.tb_change_cnt);
+ else
+#endif
+ mch_delay(msec, ignoreinput);
+}
+
+/*
+ * If the machine has job control, use it to suspend the program,
+ * otherwise fake it by starting a new shell.
+ * When running the GUI iconify the window.
+ */
+ void
+ui_suspend(void)
+{
+#ifdef FEAT_GUI
+ if (gui.in_use)
+ {
+ gui_mch_iconify();
+ return;
+ }
+#endif
+ mch_suspend();
+}
+
+#if !defined(UNIX) || !defined(SIGTSTP) || defined(PROTO) || defined(__BEOS__)
+/*
+ * When the OS can't really suspend, call this function to start a shell.
+ * This is never called in the GUI.
+ */
+ void
+suspend_shell(void)
+{
+ if (*p_sh == NUL)
+ emsg(_(e_shellempty));
+ else
+ {
+ msg_puts(_("new shell started\n"));
+ do_shell(NULL, 0);
+ }
+}
+#endif
+
+/*
+ * Try to get the current Vim shell size. Put the result in Rows and Columns.
+ * Use the new sizes as defaults for 'columns' and 'lines'.
+ * Return OK when size could be determined, FAIL otherwise.
+ */
+ int
+ui_get_shellsize(void)
+{
+ int retval;
+
+#ifdef FEAT_GUI
+ if (gui.in_use)
+ retval = gui_get_shellsize();
+ else
+#endif
+ retval = mch_get_shellsize();
+
+ check_shellsize();
+
+ /* adjust the default for 'lines' and 'columns' */
+ if (retval == OK)
+ {
+ set_number_default("lines", Rows);
+ set_number_default("columns", Columns);
+ }
+ return retval;
+}
+
+/*
+ * Set the size of the Vim shell according to Rows and Columns, if possible.
+ * The gui_set_shellsize() or mch_set_shellsize() function will try to set the
+ * new size. If this is not possible, it will adjust Rows and Columns.
+ */
+ void
+ui_set_shellsize(
+ int mustset UNUSED) /* set by the user */
+{
+#ifdef FEAT_GUI
+ if (gui.in_use)
+ gui_set_shellsize(mustset, TRUE, RESIZE_BOTH);
+ else
+#endif
+ mch_set_shellsize();
+}
+
+/*
+ * Called when Rows and/or Columns changed. Adjust scroll region and mouse
+ * region.
+ */
+ void
+ui_new_shellsize(void)
+{
+ if (full_screen && !exiting)
+ {
+#ifdef FEAT_GUI
+ if (gui.in_use)
+ gui_new_shellsize();
+ else
+#endif
+ mch_new_shellsize();
+ }
+}
+
+ void
+ui_breakcheck(void)
+{
+ ui_breakcheck_force(FALSE);
+}
+
+/*
+ * When "force" is true also check when the terminal is not in raw mode.
+ * This is useful to read input on channels.
+ */
+ void
+ui_breakcheck_force(int force)
+{
+ static int recursive = FALSE;
+ int save_updating_screen = updating_screen;
+
+ // We could be called recursively if stderr is redirected, calling
+ // fill_input_buf() calls settmode() when stdin isn't a tty. settmode()
+ // calls vgetorpeek() which calls ui_breakcheck() again.
+ if (recursive)
+ return;
+ recursive = TRUE;
+
+ // We do not want gui_resize_shell() to redraw the screen here.
+ ++updating_screen;
+
+#ifdef FEAT_GUI
+ if (gui.in_use)
+ gui_mch_update();
+ else
+#endif
+ mch_breakcheck(force);
+
+ if (save_updating_screen)
+ updating_screen = TRUE;
+ else
+ reset_updating_screen(FALSE);
+
+ recursive = FALSE;
+}
+
+/*****************************************************************************
+ * Functions for copying and pasting text between applications.
+ * This is always included in a GUI version, but may also be included when the
+ * clipboard and mouse is available to a terminal version such as xterm.
+ * Note: there are some more functions in ops.c that handle selection stuff.
+ *
+ * Also note that the majority of functions here deal with the X 'primary'
+ * (visible - for Visual mode use) selection, and only that. There are no
+ * versions of these for the 'clipboard' selection, as Visual mode has no use
+ * for them.
+ */
+
+#if defined(FEAT_CLIPBOARD) || defined(PROTO)
+
+/*
+ * Selection stuff using Visual mode, for cutting and pasting text to other
+ * windows.
+ */
+
+/*
+ * Call this to initialise the clipboard. Pass it FALSE if the clipboard code
+ * is included, but the clipboard can not be used, or TRUE if the clipboard can
+ * be used. Eg unix may call this with FALSE, then call it again with TRUE if
+ * the GUI starts.
+ */
+ void
+clip_init(int can_use)
+{
+ VimClipboard *cb;
+
+ cb = &clip_star;
+ for (;;)
+ {
+ cb->available = can_use;
+ cb->owned = FALSE;
+ cb->start.lnum = 0;
+ cb->start.col = 0;
+ cb->end.lnum = 0;
+ cb->end.col = 0;
+ cb->state = SELECT_CLEARED;
+
+ if (cb == &clip_plus)
+ break;
+ cb = &clip_plus;
+ }
+}
+
+/*
+ * Check whether the VIsual area has changed, and if so try to become the owner
+ * of the selection, and free any old converted selection we may still have
+ * lying around. If the VIsual mode has ended, make a copy of what was
+ * selected so we can still give it to others. Will probably have to make sure
+ * this is called whenever VIsual mode is ended.
+ */
+ void
+clip_update_selection(VimClipboard *clip)
+{
+ pos_T start, end;
+
+ /* If visual mode is only due to a redo command ("."), then ignore it */
+ if (!redo_VIsual_busy && VIsual_active && (State & NORMAL))
+ {
+ if (LT_POS(VIsual, curwin->w_cursor))
+ {
+ start = VIsual;
+ end = curwin->w_cursor;
+ if (has_mbyte)
+ end.col += (*mb_ptr2len)(ml_get_cursor()) - 1;
+ }
+ else
+ {
+ start = curwin->w_cursor;
+ end = VIsual;
+ }
+ if (!EQUAL_POS(clip->start, start)
+ || !EQUAL_POS(clip->end, end)
+ || clip->vmode != VIsual_mode)
+ {
+ clip_clear_selection(clip);
+ clip->start = start;
+ clip->end = end;
+ clip->vmode = VIsual_mode;
+ clip_free_selection(clip);
+ clip_own_selection(clip);
+ clip_gen_set_selection(clip);
+ }
+ }
+}
+
+ void
+clip_own_selection(VimClipboard *cbd)
+{
+ /*
+ * Also want to check somehow that we are reading from the keyboard rather
+ * than a mapping etc.
+ */
+#ifdef FEAT_X11
+ /* Always own the selection, we might have lost it without being
+ * notified, e.g. during a ":sh" command. */
+ if (cbd->available)
+ {
+ int was_owned = cbd->owned;
+
+ cbd->owned = (clip_gen_own_selection(cbd) == OK);
+ if (!was_owned && (cbd == &clip_star || cbd == &clip_plus))
+ {
+ /* May have to show a different kind of highlighting for the
+ * selected area. There is no specific redraw command for this,
+ * just redraw all windows on the current buffer. */
+ if (cbd->owned
+ && (get_real_state() == VISUAL
+ || get_real_state() == SELECTMODE)
+ && (cbd == &clip_star ? clip_isautosel_star()
+ : clip_isautosel_plus())
+ && HL_ATTR(HLF_V) != HL_ATTR(HLF_VNC))
+ redraw_curbuf_later(INVERTED_ALL);
+ }
+ }
+#else
+ /* Only own the clipboard when we didn't own it yet. */
+ if (!cbd->owned && cbd->available)
+ cbd->owned = (clip_gen_own_selection(cbd) == OK);
+#endif
+}
+
+ void
+clip_lose_selection(VimClipboard *cbd)
+{
+#ifdef FEAT_X11
+ int was_owned = cbd->owned;
+#endif
+ int visual_selection = FALSE;
+
+ if (cbd == &clip_star || cbd == &clip_plus)
+ visual_selection = TRUE;
+
+ clip_free_selection(cbd);
+ cbd->owned = FALSE;
+ if (visual_selection)
+ clip_clear_selection(cbd);
+ clip_gen_lose_selection(cbd);
+#ifdef FEAT_X11
+ if (visual_selection)
+ {
+ /* May have to show a different kind of highlighting for the selected
+ * area. There is no specific redraw command for this, just redraw all
+ * windows on the current buffer. */
+ if (was_owned
+ && (get_real_state() == VISUAL
+ || get_real_state() == SELECTMODE)
+ && (cbd == &clip_star ?
+ clip_isautosel_star() : clip_isautosel_plus())
+ && HL_ATTR(HLF_V) != HL_ATTR(HLF_VNC))
+ {
+ update_curbuf(INVERTED_ALL);
+ setcursor();
+ cursor_on();
+ out_flush_cursor(TRUE, FALSE);
+ }
+ }
+#endif
+}
+
+ static void
+clip_copy_selection(VimClipboard *clip)
+{
+ if (VIsual_active && (State & NORMAL) && clip->available)
+ {
+ clip_update_selection(clip);
+ clip_free_selection(clip);
+ clip_own_selection(clip);
+ if (clip->owned)
+ clip_get_selection(clip);
+ clip_gen_set_selection(clip);
+ }
+}
+
+/*
+ * Save and restore clip_unnamed before doing possibly many changes. This
+ * prevents accessing the clipboard very often which might slow down Vim
+ * considerably.
+ */
+static int global_change_count = 0; /* if set, inside a start_global_changes */
+static int clipboard_needs_update = FALSE; /* clipboard needs to be updated */
+static int clip_did_set_selection = TRUE;
+
+/*
+ * Save clip_unnamed and reset it.
+ */
+ void
+start_global_changes(void)
+{
+ if (++global_change_count > 1)
+ return;
+ clip_unnamed_saved = clip_unnamed;
+ clipboard_needs_update = FALSE;
+
+ if (clip_did_set_selection)
+ {
+ clip_unnamed = FALSE;
+ clip_did_set_selection = FALSE;
+ }
+}
+
+/*
+ * Return TRUE if setting the clipboard was postponed, it already contains the
+ * right text.
+ */
+ int
+is_clipboard_needs_update()
+{
+ return clipboard_needs_update;
+}
+
+/*
+ * Restore clip_unnamed and set the selection when needed.
+ */
+ void
+end_global_changes(void)
+{
+ if (--global_change_count > 0)
+ /* recursive */
+ return;
+ if (!clip_did_set_selection)
+ {
+ clip_did_set_selection = TRUE;
+ clip_unnamed = clip_unnamed_saved;
+ clip_unnamed_saved = FALSE;
+ if (clipboard_needs_update)
+ {
+ /* only store something in the clipboard,
+ * if we have yanked anything to it */
+ if (clip_unnamed & CLIP_UNNAMED)
+ {
+ clip_own_selection(&clip_star);
+ clip_gen_set_selection(&clip_star);
+ }
+ if (clip_unnamed & CLIP_UNNAMED_PLUS)
+ {
+ clip_own_selection(&clip_plus);
+ clip_gen_set_selection(&clip_plus);
+ }
+ }
+ }
+ clipboard_needs_update = FALSE;
+}
+
+/*
+ * Called when Visual mode is ended: update the selection.
+ */
+ void
+clip_auto_select(void)
+{
+ if (clip_isautosel_star())
+ clip_copy_selection(&clip_star);
+ if (clip_isautosel_plus())
+ clip_copy_selection(&clip_plus);
+}
+
+/*
+ * Return TRUE if automatic selection of Visual area is desired for the *
+ * register.
+ */
+ int
+clip_isautosel_star(void)
+{
+ return (
+#ifdef FEAT_GUI
+ gui.in_use ? (vim_strchr(p_go, GO_ASEL) != NULL) :
+#endif
+ clip_autoselect_star);
+}
+
+/*
+ * Return TRUE if automatic selection of Visual area is desired for the +
+ * register.
+ */
+ int
+clip_isautosel_plus(void)
+{
+ return (
+#ifdef FEAT_GUI
+ gui.in_use ? (vim_strchr(p_go, GO_ASELPLUS) != NULL) :
+#endif
+ clip_autoselect_plus);
+}
+
+
+/*
+ * Stuff for general mouse selection, without using Visual mode.
+ */
+
+static void clip_invert_area(int, int, int, int, int how);
+static void clip_invert_rectangle(int row, int col, int height, int width, int invert);
+static void clip_get_word_boundaries(VimClipboard *, int, int);
+static int clip_get_line_end(int);
+static void clip_update_modeless_selection(VimClipboard *, int, int,
+ int, int);
+
+/* flags for clip_invert_area() */
+#define CLIP_CLEAR 1
+#define CLIP_SET 2
+#define CLIP_TOGGLE 3
+
+/*
+ * Start, continue or end a modeless selection. Used when editing the
+ * command-line and in the cmdline window.
+ */
+ void
+clip_modeless(int button, int is_click, int is_drag)
+{
+ int repeat;
+
+ repeat = ((clip_star.mode == SELECT_MODE_CHAR
+ || clip_star.mode == SELECT_MODE_LINE)
+ && (mod_mask & MOD_MASK_2CLICK))
+ || (clip_star.mode == SELECT_MODE_WORD
+ && (mod_mask & MOD_MASK_3CLICK));
+ if (is_click && button == MOUSE_RIGHT)
+ {
+ /* Right mouse button: If there was no selection, start one.
+ * Otherwise extend the existing selection. */
+ if (clip_star.state == SELECT_CLEARED)
+ clip_start_selection(mouse_col, mouse_row, FALSE);
+ clip_process_selection(button, mouse_col, mouse_row, repeat);
+ }
+ else if (is_click)
+ clip_start_selection(mouse_col, mouse_row, repeat);
+ else if (is_drag)
+ {
+ /* Don't try extending a selection if there isn't one. Happens when
+ * button-down is in the cmdline and them moving mouse upwards. */
+ if (clip_star.state != SELECT_CLEARED)
+ clip_process_selection(button, mouse_col, mouse_row, repeat);
+ }
+ else /* release */
+ clip_process_selection(MOUSE_RELEASE, mouse_col, mouse_row, FALSE);
+}
+
+/*
+ * Compare two screen positions ala strcmp()
+ */
+ static int
+clip_compare_pos(
+ int row1,
+ int col1,
+ int row2,
+ int col2)
+{
+ if (row1 > row2) return(1);
+ if (row1 < row2) return(-1);
+ if (col1 > col2) return(1);
+ if (col1 < col2) return(-1);
+ return(0);
+}
+
+/*
+ * Start the selection
+ */
+ void
+clip_start_selection(int col, int row, int repeated_click)
+{
+ VimClipboard *cb = &clip_star;
+
+ if (cb->state == SELECT_DONE)
+ clip_clear_selection(cb);
+
+ row = check_row(row);
+ col = check_col(col);
+ col = mb_fix_col(col, row);
+
+ cb->start.lnum = row;
+ cb->start.col = col;
+ cb->end = cb->start;
+ cb->origin_row = (short_u)cb->start.lnum;
+ cb->state = SELECT_IN_PROGRESS;
+
+ if (repeated_click)
+ {
+ if (++cb->mode > SELECT_MODE_LINE)
+ cb->mode = SELECT_MODE_CHAR;
+ }
+ else
+ cb->mode = SELECT_MODE_CHAR;
+
+#ifdef FEAT_GUI
+ /* clear the cursor until the selection is made */
+ if (gui.in_use)
+ gui_undraw_cursor();
+#endif
+
+ switch (cb->mode)
+ {
+ case SELECT_MODE_CHAR:
+ cb->origin_start_col = cb->start.col;
+ cb->word_end_col = clip_get_line_end((int)cb->start.lnum);
+ break;
+
+ case SELECT_MODE_WORD:
+ clip_get_word_boundaries(cb, (int)cb->start.lnum, cb->start.col);
+ cb->origin_start_col = cb->word_start_col;
+ cb->origin_end_col = cb->word_end_col;
+
+ clip_invert_area((int)cb->start.lnum, cb->word_start_col,
+ (int)cb->end.lnum, cb->word_end_col, CLIP_SET);
+ cb->start.col = cb->word_start_col;
+ cb->end.col = cb->word_end_col;
+ break;
+
+ case SELECT_MODE_LINE:
+ clip_invert_area((int)cb->start.lnum, 0, (int)cb->start.lnum,
+ (int)Columns, CLIP_SET);
+ cb->start.col = 0;
+ cb->end.col = Columns;
+ break;
+ }
+
+ cb->prev = cb->start;
+
+#ifdef DEBUG_SELECTION
+ printf("Selection started at (%u,%u)\n", cb->start.lnum, cb->start.col);
+#endif
+}
+
+/*
+ * Continue processing the selection
+ */
+ void
+clip_process_selection(
+ int button,
+ int col,
+ int row,
+ int_u repeated_click)
+{
+ VimClipboard *cb = &clip_star;
+ int diff;
+ int slen = 1; /* cursor shape width */
+
+ if (button == MOUSE_RELEASE)
+ {
+ /* Check to make sure we have something selected */
+ if (cb->start.lnum == cb->end.lnum && cb->start.col == cb->end.col)
+ {
+#ifdef FEAT_GUI
+ if (gui.in_use)
+ gui_update_cursor(FALSE, FALSE);
+#endif
+ cb->state = SELECT_CLEARED;
+ return;
+ }
+
+#ifdef DEBUG_SELECTION
+ printf("Selection ended: (%u,%u) to (%u,%u)\n", cb->start.lnum,
+ cb->start.col, cb->end.lnum, cb->end.col);
+#endif
+ if (clip_isautosel_star()
+ || (
+#ifdef FEAT_GUI
+ gui.in_use ? (vim_strchr(p_go, GO_ASELML) != NULL) :
+#endif
+ clip_autoselectml))
+ clip_copy_modeless_selection(FALSE);
+#ifdef FEAT_GUI
+ if (gui.in_use)
+ gui_update_cursor(FALSE, FALSE);
+#endif
+
+ cb->state = SELECT_DONE;
+ return;
+ }
+
+ row = check_row(row);
+ col = check_col(col);
+ col = mb_fix_col(col, row);
+
+ if (col == (int)cb->prev.col && row == cb->prev.lnum && !repeated_click)
+ return;
+
+ /*
+ * When extending the selection with the right mouse button, swap the
+ * start and end if the position is before half the selection
+ */
+ if (cb->state == SELECT_DONE && button == MOUSE_RIGHT)
+ {
+ /*
+ * If the click is before the start, or the click is inside the
+ * selection and the start is the closest side, set the origin to the
+ * end of the selection.
+ */
+ if (clip_compare_pos(row, col, (int)cb->start.lnum, cb->start.col) < 0
+ || (clip_compare_pos(row, col,
+ (int)cb->end.lnum, cb->end.col) < 0
+ && (((cb->start.lnum == cb->end.lnum
+ && cb->end.col - col > col - cb->start.col))
+ || ((diff = (cb->end.lnum - row) -
+ (row - cb->start.lnum)) > 0
+ || (diff == 0 && col < (int)(cb->start.col +
+ cb->end.col) / 2)))))
+ {
+ cb->origin_row = (short_u)cb->end.lnum;
+ cb->origin_start_col = cb->end.col - 1;
+ cb->origin_end_col = cb->end.col;
+ }
+ else
+ {
+ cb->origin_row = (short_u)cb->start.lnum;
+ cb->origin_start_col = cb->start.col;
+ cb->origin_end_col = cb->start.col;
+ }
+ if (cb->mode == SELECT_MODE_WORD && !repeated_click)
+ cb->mode = SELECT_MODE_CHAR;
+ }
+
+ /* set state, for when using the right mouse button */
+ cb->state = SELECT_IN_PROGRESS;
+
+#ifdef DEBUG_SELECTION
+ printf("Selection extending to (%d,%d)\n", row, col);
+#endif
+
+ if (repeated_click && ++cb->mode > SELECT_MODE_LINE)
+ cb->mode = SELECT_MODE_CHAR;
+
+ switch (cb->mode)
+ {
+ case SELECT_MODE_CHAR:
+ /* If we're on a different line, find where the line ends */
+ if (row != cb->prev.lnum)
+ cb->word_end_col = clip_get_line_end(row);
+
+ /* See if we are before or after the origin of the selection */
+ if (clip_compare_pos(row, col, cb->origin_row,
+ cb->origin_start_col) >= 0)
+ {
+ if (col >= (int)cb->word_end_col)
+ clip_update_modeless_selection(cb, cb->origin_row,
+ cb->origin_start_col, row, (int)Columns);
+ else
+ {
+ if (has_mbyte && mb_lefthalve(row, col))
+ slen = 2;
+ clip_update_modeless_selection(cb, cb->origin_row,
+ cb->origin_start_col, row, col + slen);
+ }
+ }
+ else
+ {
+ if (has_mbyte
+ && mb_lefthalve(cb->origin_row, cb->origin_start_col))
+ slen = 2;
+ if (col >= (int)cb->word_end_col)
+ clip_update_modeless_selection(cb, row, cb->word_end_col,
+ cb->origin_row, cb->origin_start_col + slen);
+ else
+ clip_update_modeless_selection(cb, row, col,
+ cb->origin_row, cb->origin_start_col + slen);
+ }
+ break;
+
+ case SELECT_MODE_WORD:
+ /* If we are still within the same word, do nothing */
+ if (row == cb->prev.lnum && col >= (int)cb->word_start_col
+ && col < (int)cb->word_end_col && !repeated_click)
+ return;
+
+ /* Get new word boundaries */
+ clip_get_word_boundaries(cb, row, col);
+
+ /* Handle being after the origin point of selection */
+ if (clip_compare_pos(row, col, cb->origin_row,
+ cb->origin_start_col) >= 0)
+ clip_update_modeless_selection(cb, cb->origin_row,
+ cb->origin_start_col, row, cb->word_end_col);
+ else
+ clip_update_modeless_selection(cb, row, cb->word_start_col,
+ cb->origin_row, cb->origin_end_col);
+ break;
+
+ case SELECT_MODE_LINE:
+ if (row == cb->prev.lnum && !repeated_click)
+ return;
+
+ if (clip_compare_pos(row, col, cb->origin_row,
+ cb->origin_start_col) >= 0)
+ clip_update_modeless_selection(cb, cb->origin_row, 0, row,
+ (int)Columns);
+ else
+ clip_update_modeless_selection(cb, row, 0, cb->origin_row,
+ (int)Columns);
+ break;
+ }
+
+ cb->prev.lnum = row;
+ cb->prev.col = col;
+
+#ifdef DEBUG_SELECTION
+ printf("Selection is: (%u,%u) to (%u,%u)\n", cb->start.lnum,
+ cb->start.col, cb->end.lnum, cb->end.col);
+#endif
+}
+
+# if defined(FEAT_GUI) || defined(PROTO)
+/*
+ * Redraw part of the selection if character at "row,col" is inside of it.
+ * Only used for the GUI.
+ */
+ void
+clip_may_redraw_selection(int row, int col, int len)
+{
+ int start = col;
+ int end = col + len;
+
+ if (clip_star.state != SELECT_CLEARED
+ && row >= clip_star.start.lnum
+ && row <= clip_star.end.lnum)
+ {
+ if (row == clip_star.start.lnum && start < (int)clip_star.start.col)
+ start = clip_star.start.col;
+ if (row == clip_star.end.lnum && end > (int)clip_star.end.col)
+ end = clip_star.end.col;
+ if (end > start)
+ clip_invert_area(row, start, row, end, 0);
+ }
+}
+# endif
+
+/*
+ * Called from outside to clear selected region from the display
+ */
+ void
+clip_clear_selection(VimClipboard *cbd)
+{
+
+ if (cbd->state == SELECT_CLEARED)
+ return;
+
+ clip_invert_area((int)cbd->start.lnum, cbd->start.col, (int)cbd->end.lnum,
+ cbd->end.col, CLIP_CLEAR);
+ cbd->state = SELECT_CLEARED;
+}
+
+/*
+ * Clear the selection if any lines from "row1" to "row2" are inside of it.
+ */
+ void
+clip_may_clear_selection(int row1, int row2)
+{
+ if (clip_star.state == SELECT_DONE
+ && row2 >= clip_star.start.lnum
+ && row1 <= clip_star.end.lnum)
+ clip_clear_selection(&clip_star);
+}
+
+/*
+ * Called before the screen is scrolled up or down. Adjusts the line numbers
+ * of the selection. Call with big number when clearing the screen.
+ */
+ void
+clip_scroll_selection(
+ int rows) /* negative for scroll down */
+{
+ int lnum;
+
+ if (clip_star.state == SELECT_CLEARED)
+ return;
+
+ lnum = clip_star.start.lnum - rows;
+ if (lnum <= 0)
+ clip_star.start.lnum = 0;
+ else if (lnum >= screen_Rows) /* scrolled off of the screen */
+ clip_star.state = SELECT_CLEARED;
+ else
+ clip_star.start.lnum = lnum;
+
+ lnum = clip_star.end.lnum - rows;
+ if (lnum < 0) /* scrolled off of the screen */
+ clip_star.state = SELECT_CLEARED;
+ else if (lnum >= screen_Rows)
+ clip_star.end.lnum = screen_Rows - 1;
+ else
+ clip_star.end.lnum = lnum;
+}
+
+/*
+ * Invert a region of the display between a starting and ending row and column
+ * Values for "how":
+ * CLIP_CLEAR: undo inversion
+ * CLIP_SET: set inversion
+ * CLIP_TOGGLE: set inversion if pos1 < pos2, undo inversion otherwise.
+ * 0: invert (GUI only).
+ */
+ static void
+clip_invert_area(
+ int row1,
+ int col1,
+ int row2,
+ int col2,
+ int how)
+{
+ int invert = FALSE;
+
+ if (how == CLIP_SET)
+ invert = TRUE;
+
+ /* Swap the from and to positions so the from is always before */
+ if (clip_compare_pos(row1, col1, row2, col2) > 0)
+ {
+ int tmp_row, tmp_col;
+
+ tmp_row = row1;
+ tmp_col = col1;
+ row1 = row2;
+ col1 = col2;
+ row2 = tmp_row;
+ col2 = tmp_col;
+ }
+ else if (how == CLIP_TOGGLE)
+ invert = TRUE;
+
+ /* If all on the same line, do it the easy way */
+ if (row1 == row2)
+ {
+ clip_invert_rectangle(row1, col1, 1, col2 - col1, invert);
+ }
+ else
+ {
+ /* Handle a piece of the first line */
+ if (col1 > 0)
+ {
+ clip_invert_rectangle(row1, col1, 1, (int)Columns - col1, invert);
+ row1++;
+ }
+
+ /* Handle a piece of the last line */
+ if (col2 < Columns - 1)
+ {
+ clip_invert_rectangle(row2, 0, 1, col2, invert);
+ row2--;
+ }
+
+ /* Handle the rectangle thats left */
+ if (row2 >= row1)
+ clip_invert_rectangle(row1, 0, row2 - row1 + 1, (int)Columns,
+ invert);
+ }
+}
+
+/*
+ * Invert or un-invert a rectangle of the screen.
+ * "invert" is true if the result is inverted.
+ */
+ static void
+clip_invert_rectangle(
+ int row,
+ int col,
+ int height,
+ int width,
+ int invert)
+{
+#ifdef FEAT_GUI
+ if (gui.in_use)
+ gui_mch_invert_rectangle(row, col, height, width);
+ else
+#endif
+ screen_draw_rectangle(row, col, height, width, invert);
+}
+
+/*
+ * Copy the currently selected area into the '*' register so it will be
+ * available for pasting.
+ * When "both" is TRUE also copy to the '+' register.
+ */
+ void
+clip_copy_modeless_selection(int both UNUSED)
+{
+ char_u *buffer;
+ char_u *bufp;
+ int row;
+ int start_col;
+ int end_col;
+ int line_end_col;
+ int add_newline_flag = FALSE;
+ int len;
+ char_u *p;
+ int row1 = clip_star.start.lnum;
+ int col1 = clip_star.start.col;
+ int row2 = clip_star.end.lnum;
+ int col2 = clip_star.end.col;
+
+ /* Can't use ScreenLines unless initialized */
+ if (ScreenLines == NULL)
+ return;
+
+ /*
+ * Make sure row1 <= row2, and if row1 == row2 that col1 <= col2.
+ */
+ if (row1 > row2)
+ {
+ row = row1; row1 = row2; row2 = row;
+ row = col1; col1 = col2; col2 = row;
+ }
+ else if (row1 == row2 && col1 > col2)
+ {
+ row = col1; col1 = col2; col2 = row;
+ }
+ /* correct starting point for being on right halve of double-wide char */
+ p = ScreenLines + LineOffset[row1];
+ if (enc_dbcs != 0)
+ col1 -= (*mb_head_off)(p, p + col1);
+ else if (enc_utf8 && p[col1] == 0)
+ --col1;
+
+ /* Create a temporary buffer for storing the text */
+ len = (row2 - row1 + 1) * Columns + 1;
+ if (enc_dbcs != 0)
+ len *= 2; /* max. 2 bytes per display cell */
+ else if (enc_utf8)
+ len *= MB_MAXBYTES;
+ buffer = lalloc((long_u)len, TRUE);
+ if (buffer == NULL) /* out of memory */
+ return;
+
+ /* Process each row in the selection */
+ for (bufp = buffer, row = row1; row <= row2; row++)
+ {
+ if (row == row1)
+ start_col = col1;
+ else
+ start_col = 0;
+
+ if (row == row2)
+ end_col = col2;
+ else
+ end_col = Columns;
+
+ line_end_col = clip_get_line_end(row);
+
+ /* See if we need to nuke some trailing whitespace */
+ if (end_col >= Columns && (row < row2 || end_col > line_end_col))
+ {
+ /* Get rid of trailing whitespace */
+ end_col = line_end_col;
+ if (end_col < start_col)
+ end_col = start_col;
+
+ /* If the last line extended to the end, add an extra newline */
+ if (row == row2)
+ add_newline_flag = TRUE;
+ }
+
+ /* If after the first row, we need to always add a newline */
+ if (row > row1 && !LineWraps[row - 1])
+ *bufp++ = NL;
+
+ if (row < screen_Rows && end_col <= screen_Columns)
+ {
+ if (enc_dbcs != 0)
+ {
+ int i;
+
+ p = ScreenLines + LineOffset[row];
+ for (i = start_col; i < end_col; ++i)
+ if (enc_dbcs == DBCS_JPNU && p[i] == 0x8e)
+ {
+ /* single-width double-byte char */
+ *bufp++ = 0x8e;
+ *bufp++ = ScreenLines2[LineOffset[row] + i];
+ }
+ else
+ {
+ *bufp++ = p[i];
+ if (MB_BYTE2LEN(p[i]) == 2)
+ *bufp++ = p[++i];
+ }
+ }
+ else if (enc_utf8)
+ {
+ int off;
+ int i;
+ int ci;
+
+ off = LineOffset[row];
+ for (i = start_col; i < end_col; ++i)
+ {
+ /* The base character is either in ScreenLinesUC[] or
+ * ScreenLines[]. */
+ if (ScreenLinesUC[off + i] == 0)
+ *bufp++ = ScreenLines[off + i];
+ else
+ {
+ bufp += utf_char2bytes(ScreenLinesUC[off + i], bufp);
+ for (ci = 0; ci < Screen_mco; ++ci)
+ {
+ /* Add a composing character. */
+ if (ScreenLinesC[ci][off + i] == 0)
+ break;
+ bufp += utf_char2bytes(ScreenLinesC[ci][off + i],
+ bufp);
+ }
+ }
+ /* Skip right halve of double-wide character. */
+ if (ScreenLines[off + i + 1] == 0)
+ ++i;
+ }
+ }
+ else
+ {
+ STRNCPY(bufp, ScreenLines + LineOffset[row] + start_col,
+ end_col - start_col);
+ bufp += end_col - start_col;
+ }
+ }
+ }
+
+ /* Add a newline at the end if the selection ended there */
+ if (add_newline_flag)
+ *bufp++ = NL;
+
+ /* First cleanup any old selection and become the owner. */
+ clip_free_selection(&clip_star);
+ clip_own_selection(&clip_star);
+
+ /* Yank the text into the '*' register. */
+ clip_yank_selection(MCHAR, buffer, (long)(bufp - buffer), &clip_star);
+
+ /* Make the register contents available to the outside world. */
+ clip_gen_set_selection(&clip_star);
+
+#ifdef FEAT_X11
+ if (both)
+ {
+ /* Do the same for the '+' register. */
+ clip_free_selection(&clip_plus);
+ clip_own_selection(&clip_plus);
+ clip_yank_selection(MCHAR, buffer, (long)(bufp - buffer), &clip_plus);
+ clip_gen_set_selection(&clip_plus);
+ }
+#endif
+ vim_free(buffer);
+}
+
+/*
+ * Find the starting and ending positions of the word at the given row and
+ * column. Only white-separated words are recognized here.
+ */
+#define CHAR_CLASS(c) (c <= ' ' ? ' ' : vim_iswordc(c))
+
+ static void
+clip_get_word_boundaries(VimClipboard *cb, int row, int col)
+{
+ int start_class;
+ int temp_col;
+ char_u *p;
+ int mboff;
+
+ if (row >= screen_Rows || col >= screen_Columns || ScreenLines == NULL)
+ return;
+
+ p = ScreenLines + LineOffset[row];
+ /* Correct for starting in the right halve of a double-wide char */
+ if (enc_dbcs != 0)
+ col -= dbcs_screen_head_off(p, p + col);
+ else if (enc_utf8 && p[col] == 0)
+ --col;
+ start_class = CHAR_CLASS(p[col]);
+
+ temp_col = col;
+ for ( ; temp_col > 0; temp_col--)
+ if (enc_dbcs != 0
+ && (mboff = dbcs_screen_head_off(p, p + temp_col - 1)) > 0)
+ temp_col -= mboff;
+ else if (CHAR_CLASS(p[temp_col - 1]) != start_class
+ && !(enc_utf8 && p[temp_col - 1] == 0))
+ break;
+ cb->word_start_col = temp_col;
+
+ temp_col = col;
+ for ( ; temp_col < screen_Columns; temp_col++)
+ if (enc_dbcs != 0 && dbcs_ptr2cells(p + temp_col) == 2)
+ ++temp_col;
+ else if (CHAR_CLASS(p[temp_col]) != start_class
+ && !(enc_utf8 && p[temp_col] == 0))
+ break;
+ cb->word_end_col = temp_col;
+}
+
+/*
+ * Find the column position for the last non-whitespace character on the given
+ * line.
+ */
+ static int
+clip_get_line_end(int row)
+{
+ int i;
+
+ if (row >= screen_Rows || ScreenLines == NULL)
+ return 0;
+ for (i = screen_Columns; i > 0; i--)
+ if (ScreenLines[LineOffset[row] + i - 1] != ' ')
+ break;
+ return i;
+}
+
+/*
+ * Update the currently selected region by adding and/or subtracting from the
+ * beginning or end and inverting the changed area(s).
+ */
+ static void
+clip_update_modeless_selection(
+ VimClipboard *cb,
+ int row1,
+ int col1,
+ int row2,
+ int col2)
+{
+ /* See if we changed at the beginning of the selection */
+ if (row1 != cb->start.lnum || col1 != (int)cb->start.col)
+ {
+ clip_invert_area(row1, col1, (int)cb->start.lnum, cb->start.col,
+ CLIP_TOGGLE);
+ cb->start.lnum = row1;
+ cb->start.col = col1;
+ }
+
+ /* See if we changed at the end of the selection */
+ if (row2 != cb->end.lnum || col2 != (int)cb->end.col)
+ {
+ clip_invert_area((int)cb->end.lnum, cb->end.col, row2, col2,
+ CLIP_TOGGLE);
+ cb->end.lnum = row2;
+ cb->end.col = col2;
+ }
+}
+
+ int
+clip_gen_own_selection(VimClipboard *cbd)
+{
+#ifdef FEAT_XCLIPBOARD
+# ifdef FEAT_GUI
+ if (gui.in_use)
+ return clip_mch_own_selection(cbd);
+ else
+# endif
+ return clip_xterm_own_selection(cbd);
+#else
+ return clip_mch_own_selection(cbd);
+#endif
+}
+
+ void
+clip_gen_lose_selection(VimClipboard *cbd)
+{
+#ifdef FEAT_XCLIPBOARD
+# ifdef FEAT_GUI
+ if (gui.in_use)
+ clip_mch_lose_selection(cbd);
+ else
+# endif
+ clip_xterm_lose_selection(cbd);
+#else
+ clip_mch_lose_selection(cbd);
+#endif
+}
+
+ void
+clip_gen_set_selection(VimClipboard *cbd)
+{
+ if (!clip_did_set_selection)
+ {
+ /* Updating postponed, so that accessing the system clipboard won't
+ * hang Vim when accessing it many times (e.g. on a :g comand). */
+ if ((cbd == &clip_plus && (clip_unnamed_saved & CLIP_UNNAMED_PLUS))
+ || (cbd == &clip_star && (clip_unnamed_saved & CLIP_UNNAMED)))
+ {
+ clipboard_needs_update = TRUE;
+ return;
+ }
+ }
+#ifdef FEAT_XCLIPBOARD
+# ifdef FEAT_GUI
+ if (gui.in_use)
+ clip_mch_set_selection(cbd);
+ else
+# endif
+ clip_xterm_set_selection(cbd);
+#else
+ clip_mch_set_selection(cbd);
+#endif
+}
+
+ void
+clip_gen_request_selection(VimClipboard *cbd)
+{
+#ifdef FEAT_XCLIPBOARD
+# ifdef FEAT_GUI
+ if (gui.in_use)
+ clip_mch_request_selection(cbd);
+ else
+# endif
+ clip_xterm_request_selection(cbd);
+#else
+ clip_mch_request_selection(cbd);
+#endif
+}
+
+#if (defined(FEAT_X11) && defined(USE_SYSTEM)) || defined(PROTO)
+ int
+clip_gen_owner_exists(VimClipboard *cbd UNUSED)
+{
+#ifdef FEAT_XCLIPBOARD
+# ifdef FEAT_GUI_GTK
+ if (gui.in_use)
+ return clip_gtk_owner_exists(cbd);
+ else
+# endif
+ return clip_x11_owner_exists(cbd);
+#else
+ return TRUE;
+#endif
+}
+#endif
+
+#endif /* FEAT_CLIPBOARD */
+
+/*****************************************************************************
+ * Functions that handle the input buffer.
+ * This is used for any GUI version, and the unix terminal version.
+ *
+ * For Unix, the input characters are buffered to be able to check for a
+ * CTRL-C. This should be done with signals, but I don't know how to do that
+ * in a portable way for a tty in RAW mode.
+ *
+ * For the client-server code in the console the received keys are put in the
+ * input buffer.
+ */
+
+#if defined(USE_INPUT_BUF) || defined(PROTO)
+
+/*
+ * Internal typeahead buffer. Includes extra space for long key code
+ * descriptions which would otherwise overflow. The buffer is considered full
+ * when only this extra space (or part of it) remains.
+ */
+#if defined(FEAT_JOB_CHANNEL) || defined(FEAT_CLIENTSERVER)
+ /*
+ * NetBeans stuffs debugger commands into the input buffer.
+ * This requires a larger buffer...
+ * (Madsen) Go with this for remote input as well ...
+ */
+# define INBUFLEN 4096
+#else
+# define INBUFLEN 250
+#endif
+
+static char_u inbuf[INBUFLEN + MAX_KEY_CODE_LEN];
+static int inbufcount = 0; /* number of chars in inbuf[] */
+
+/*
+ * vim_is_input_buf_full(), vim_is_input_buf_empty(), add_to_input_buf(), and
+ * trash_input_buf() are functions for manipulating the input buffer. These
+ * are used by the gui_* calls when a GUI is used to handle keyboard input.
+ */
+
+ int
+vim_is_input_buf_full(void)
+{
+ return (inbufcount >= INBUFLEN);
+}
+
+ int
+vim_is_input_buf_empty(void)
+{
+ return (inbufcount == 0);
+}
+
+#if defined(FEAT_OLE) || defined(PROTO)
+ int
+vim_free_in_input_buf(void)
+{
+ return (INBUFLEN - inbufcount);
+}
+#endif
+
+#if defined(FEAT_GUI_GTK) || defined(PROTO)
+ int
+vim_used_in_input_buf(void)
+{
+ return inbufcount;
+}
+#endif
+
+/*
+ * Return the current contents of the input buffer and make it empty.
+ * The returned pointer must be passed to set_input_buf() later.
+ */
+ char_u *
+get_input_buf(void)
+{
+ garray_T *gap;
+
+ /* We use a growarray to store the data pointer and the length. */
+ gap = (garray_T *)alloc((unsigned)sizeof(garray_T));
+ if (gap != NULL)
+ {
+ /* Add one to avoid a zero size. */
+ gap->ga_data = alloc((unsigned)inbufcount + 1);
+ if (gap->ga_data != NULL)
+ mch_memmove(gap->ga_data, inbuf, (size_t)inbufcount);
+ gap->ga_len = inbufcount;
+ }
+ trash_input_buf();
+ return (char_u *)gap;
+}
+
+/*
+ * Restore the input buffer with a pointer returned from get_input_buf().
+ * The allocated memory is freed, this only works once!
+ */
+ void
+set_input_buf(char_u *p)
+{
+ garray_T *gap = (garray_T *)p;
+
+ if (gap != NULL)
+ {
+ if (gap->ga_data != NULL)
+ {
+ mch_memmove(inbuf, gap->ga_data, gap->ga_len);
+ inbufcount = gap->ga_len;
+ vim_free(gap->ga_data);
+ }
+ vim_free(gap);
+ }
+}
+
+/*
+ * Add the given bytes to the input buffer
+ * Special keys start with CSI. A real CSI must have been translated to
+ * CSI KS_EXTRA KE_CSI. K_SPECIAL doesn't require translation.
+ */
+ void
+add_to_input_buf(char_u *s, int len)
+{
+ if (inbufcount + len > INBUFLEN + MAX_KEY_CODE_LEN)
+ return; /* Shouldn't ever happen! */
+
+#ifdef FEAT_HANGULIN
+ if ((State & (INSERT|CMDLINE)) && hangul_input_state_get())
+ if ((len = hangul_input_process(s, len)) == 0)
+ return;
+#endif
+
+ while (len--)
+ inbuf[inbufcount++] = *s++;
+}
+
+/*
+ * Add "str[len]" to the input buffer while escaping CSI bytes.
+ */
+ void
+add_to_input_buf_csi(char_u *str, int len)
+{
+ int i;
+ char_u buf[2];
+
+ for (i = 0; i < len; ++i)
+ {
+ add_to_input_buf(str + i, 1);
+ if (str[i] == CSI)
+ {
+ /* Turn CSI into K_CSI. */
+ buf[0] = KS_EXTRA;
+ buf[1] = (int)KE_CSI;
+ add_to_input_buf(buf, 2);
+ }
+ }
+}
+
+#if defined(FEAT_HANGULIN) || defined(PROTO)
+ void
+push_raw_key(char_u *s, int len)
+{
+ char_u *tmpbuf;
+ char_u *inp = s;
+
+ /* use the conversion result if possible */
+ tmpbuf = hangul_string_convert(s, &len);
+ if (tmpbuf != NULL)
+ inp = tmpbuf;
+
+ for (; len--; inp++)
+ {
+ inbuf[inbufcount++] = *inp;
+ if (*inp == CSI)
+ {
+ /* Turn CSI into K_CSI. */
+ inbuf[inbufcount++] = KS_EXTRA;
+ inbuf[inbufcount++] = (int)KE_CSI;
+ }
+ }
+ vim_free(tmpbuf);
+}
+#endif
+
+/* Remove everything from the input buffer. Called when ^C is found */
+ void
+trash_input_buf(void)
+{
+ inbufcount = 0;
+}
+
+/*
+ * Read as much data from the input buffer as possible up to maxlen, and store
+ * it in buf.
+ */
+ int
+read_from_input_buf(char_u *buf, long maxlen)
+{
+ if (inbufcount == 0) /* if the buffer is empty, fill it */
+ fill_input_buf(TRUE);
+ if (maxlen > inbufcount)
+ maxlen = inbufcount;
+ mch_memmove(buf, inbuf, (size_t)maxlen);
+ inbufcount -= maxlen;
+ if (inbufcount)
+ mch_memmove(inbuf, inbuf + maxlen, (size_t)inbufcount);
+ return (int)maxlen;
+}
+
+ void
+fill_input_buf(int exit_on_error UNUSED)
+{
+#if defined(UNIX) || defined(VMS) || defined(MACOS_X)
+ int len;
+ int try;
+ static int did_read_something = FALSE;
+ static char_u *rest = NULL; /* unconverted rest of previous read */
+ static int restlen = 0;
+ int unconverted;
+#endif
+
+#ifdef FEAT_GUI
+ if (gui.in_use
+# ifdef NO_CONSOLE_INPUT
+ /* Don't use the GUI input when the window hasn't been opened yet.
+ * We get here from ui_inchar() when we should try reading from stdin. */
+ && !no_console_input()
+# endif
+ )
+ {
+ gui_mch_update();
+ return;
+ }
+#endif
+#if defined(UNIX) || defined(VMS) || defined(MACOS_X)
+ if (vim_is_input_buf_full())
+ return;
+ /*
+ * Fill_input_buf() is only called when we really need a character.
+ * If we can't get any, but there is some in the buffer, just return.
+ * If we can't get any, and there isn't any in the buffer, we give up and
+ * exit Vim.
+ */
+# ifdef __BEOS__
+ /*
+ * On the BeBox version (for now), all input is secretly performed within
+ * beos_select() which is called from RealWaitForChar().
+ */
+ while (!vim_is_input_buf_full() && RealWaitForChar(read_cmd_fd, 0, NULL))
+ ;
+ len = inbufcount;
+ inbufcount = 0;
+# else
+
+ if (rest != NULL)
+ {
+ /* Use remainder of previous call, starts with an invalid character
+ * that may become valid when reading more. */
+ if (restlen > INBUFLEN - inbufcount)
+ unconverted = INBUFLEN - inbufcount;
+ else
+ unconverted = restlen;
+ mch_memmove(inbuf + inbufcount, rest, unconverted);
+ if (unconverted == restlen)
+ VIM_CLEAR(rest);
+ else
+ {
+ restlen -= unconverted;
+ mch_memmove(rest, rest + unconverted, restlen);
+ }
+ inbufcount += unconverted;
+ }
+ else
+ unconverted = 0;
+
+ len = 0; /* to avoid gcc warning */
+ for (try = 0; try < 100; ++try)
+ {
+ size_t readlen = (size_t)((INBUFLEN - inbufcount)
+ / input_conv.vc_factor);
+# ifdef VMS
+ len = vms_read((char *)inbuf + inbufcount, readlen);
+# else
+ len = read(read_cmd_fd, (char *)inbuf + inbufcount, readlen);
+# endif
+
+ if (len > 0 || got_int)
+ break;
+ /*
+ * If reading stdin results in an error, continue reading stderr.
+ * This helps when using "foo | xargs vim".
+ */
+ if (!did_read_something && !isatty(read_cmd_fd) && read_cmd_fd == 0)
+ {
+ int m = cur_tmode;
+
+ /* We probably set the wrong file descriptor to raw mode. Switch
+ * back to cooked mode, use another descriptor and set the mode to
+ * what it was. */
+ settmode(TMODE_COOK);
+#ifdef HAVE_DUP
+ /* Use stderr for stdin, also works for shell commands. */
+ close(0);
+ vim_ignored = dup(2);
+#else
+ read_cmd_fd = 2; /* read from stderr instead of stdin */
+#endif
+ settmode(m);
+ }
+ if (!exit_on_error)
+ return;
+ }
+# endif
+ if (len <= 0 && !got_int)
+ read_error_exit();
+ if (len > 0)
+ did_read_something = TRUE;
+ if (got_int)
+ {
+ /* Interrupted, pretend a CTRL-C was typed. */
+ inbuf[0] = 3;
+ inbufcount = 1;
+ }
+ else
+ {
+ /*
+ * May perform conversion on the input characters.
+ * Include the unconverted rest of the previous call.
+ * If there is an incomplete char at the end it is kept for the next
+ * time, reading more bytes should make conversion possible.
+ * Don't do this in the unlikely event that the input buffer is too
+ * small ("rest" still contains more bytes).
+ */
+ if (input_conv.vc_type != CONV_NONE)
+ {
+ inbufcount -= unconverted;
+ len = convert_input_safe(inbuf + inbufcount,
+ len + unconverted, INBUFLEN - inbufcount,
+ rest == NULL ? &rest : NULL, &restlen);
+ }
+ while (len-- > 0)
+ {
+ /*
+ * if a CTRL-C was typed, remove it from the buffer and set got_int
+ */
+ if (inbuf[inbufcount] == 3 && ctrl_c_interrupts)
+ {
+ /* remove everything typed before the CTRL-C */
+ mch_memmove(inbuf, inbuf + inbufcount, (size_t)(len + 1));
+ inbufcount = 0;
+ got_int = TRUE;
+ }
+ ++inbufcount;
+ }
+ }
+#endif /* UNIX or VMS*/
+}
+#endif /* defined(UNIX) || defined(FEAT_GUI) || defined(VMS) */
+
+/*
+ * Exit because of an input read error.
+ */
+ void
+read_error_exit(void)
+{
+ if (silent_mode) /* Normal way to exit for "ex -s" */
+ getout(0);
+ STRCPY(IObuff, _("Vim: Error reading input, exiting...\n"));
+ preserve_exit();
+}
+
+#if defined(CURSOR_SHAPE) || defined(PROTO)
+/*
+ * May update the shape of the cursor.
+ */
+ void
+ui_cursor_shape_forced(int forced)
+{
+# ifdef FEAT_GUI
+ if (gui.in_use)
+ gui_update_cursor_later();
+ else
+# endif
+ term_cursor_mode(forced);
+
+# ifdef MCH_CURSOR_SHAPE
+ mch_update_cursor();
+# endif
+
+# ifdef FEAT_CONCEAL
+ conceal_check_cursor_line();
+# endif
+}
+
+ void
+ui_cursor_shape(void)
+{
+ ui_cursor_shape_forced(FALSE);
+}
+#endif
+
+/*
+ * Check bounds for column number
+ */
+ int
+check_col(int col)
+{
+ if (col < 0)
+ return 0;
+ if (col >= (int)screen_Columns)
+ return (int)screen_Columns - 1;
+ return col;
+}
+
+/*
+ * Check bounds for row number
+ */
+ int
+check_row(int row)
+{
+ if (row < 0)
+ return 0;
+ if (row >= (int)screen_Rows)
+ return (int)screen_Rows - 1;
+ return row;
+}
+
+/*
+ * Stuff for the X clipboard. Shared between VMS and Unix.
+ */
+
+#if defined(FEAT_XCLIPBOARD) || defined(FEAT_GUI_X11) || defined(PROTO)
+# include <X11/Xatom.h>
+# include <X11/Intrinsic.h>
+
+/*
+ * Open the application context (if it hasn't been opened yet).
+ * Used for Motif and Athena GUI and the xterm clipboard.
+ */
+ void
+open_app_context(void)
+{
+ if (app_context == NULL)
+ {
+ XtToolkitInitialize();
+ app_context = XtCreateApplicationContext();
+ }
+}
+
+static Atom vim_atom; /* Vim's own special selection format */
+static Atom vimenc_atom; /* Vim's extended selection format */
+static Atom utf8_atom;
+static Atom compound_text_atom;
+static Atom text_atom;
+static Atom targets_atom;
+static Atom timestamp_atom; /* Used to get a timestamp */
+
+ void
+x11_setup_atoms(Display *dpy)
+{
+ vim_atom = XInternAtom(dpy, VIM_ATOM_NAME, False);
+ vimenc_atom = XInternAtom(dpy, VIMENC_ATOM_NAME,False);
+ utf8_atom = XInternAtom(dpy, "UTF8_STRING", False);
+ compound_text_atom = XInternAtom(dpy, "COMPOUND_TEXT", False);
+ text_atom = XInternAtom(dpy, "TEXT", False);
+ targets_atom = XInternAtom(dpy, "TARGETS", False);
+ clip_star.sel_atom = XA_PRIMARY;
+ clip_plus.sel_atom = XInternAtom(dpy, "CLIPBOARD", False);
+ timestamp_atom = XInternAtom(dpy, "TIMESTAMP", False);
+}
+
+/*
+ * X Selection stuff, for cutting and pasting text to other windows.
+ */
+
+static Boolean clip_x11_convert_selection_cb(Widget w, Atom *sel_atom, Atom *target, Atom *type, XtPointer *value, long_u *length, int *format);
+static void clip_x11_lose_ownership_cb(Widget w, Atom *sel_atom);
+static void clip_x11_notify_cb(Widget w, Atom *sel_atom, Atom *target);
+
+/*
+ * Property callback to get a timestamp for XtOwnSelection.
+ */
+ static void
+clip_x11_timestamp_cb(
+ Widget w,
+ XtPointer n UNUSED,
+ XEvent *event,
+ Boolean *cont UNUSED)
+{
+ Atom actual_type;
+ int format;
+ unsigned long nitems, bytes_after;
+ unsigned char *prop=NULL;
+ XPropertyEvent *xproperty=&event->xproperty;
+
+ /* Must be a property notify, state can't be Delete (True), has to be
+ * one of the supported selection types. */
+ if (event->type != PropertyNotify || xproperty->state
+ || (xproperty->atom != clip_star.sel_atom
+ && xproperty->atom != clip_plus.sel_atom))
+ return;
+
+ if (XGetWindowProperty(xproperty->display, xproperty->window,
+ xproperty->atom, 0, 0, False, timestamp_atom, &actual_type, &format,
+ &nitems, &bytes_after, &prop))
+ return;
+
+ if (prop)
+ XFree(prop);
+
+ /* Make sure the property type is "TIMESTAMP" and it's 32 bits. */
+ if (actual_type != timestamp_atom || format != 32)
+ return;
+
+ /* Get the selection, using the event timestamp. */
+ if (XtOwnSelection(w, xproperty->atom, xproperty->time,
+ clip_x11_convert_selection_cb, clip_x11_lose_ownership_cb,
+ clip_x11_notify_cb) == OK)
+ {
+ /* Set the "owned" flag now, there may have been a call to
+ * lose_ownership_cb in between. */
+ if (xproperty->atom == clip_plus.sel_atom)
+ clip_plus.owned = TRUE;
+ else
+ clip_star.owned = TRUE;
+ }
+}
+
+ void
+x11_setup_selection(Widget w)
+{
+ XtAddEventHandler(w, PropertyChangeMask, False,
+ /*(XtEventHandler)*/clip_x11_timestamp_cb, (XtPointer)NULL);
+}
+
+ static void
+clip_x11_request_selection_cb(
+ Widget w UNUSED,
+ XtPointer success,
+ Atom *sel_atom,
+ Atom *type,
+ XtPointer value,
+ long_u *length,
+ int *format)
+{
+ int motion_type = MAUTO;
+ long_u len;
+ char_u *p;
+ char **text_list = NULL;
+ VimClipboard *cbd;
+ char_u *tmpbuf = NULL;
+
+ if (*sel_atom == clip_plus.sel_atom)
+ cbd = &clip_plus;
+ else
+ cbd = &clip_star;
+
+ if (value == NULL || *length == 0)
+ {
+ clip_free_selection(cbd); /* nothing received, clear register */
+ *(int *)success = FALSE;
+ return;
+ }
+ p = (char_u *)value;
+ len = *length;
+ if (*type == vim_atom)
+ {
+ motion_type = *p++;
+ len--;
+ }
+
+ else if (*type == vimenc_atom)
+ {
+ char_u *enc;
+ vimconv_T conv;
+ int convlen;
+
+ motion_type = *p++;
+ --len;
+
+ enc = p;
+ p += STRLEN(p) + 1;
+ len -= p - enc;
+
+ /* If the encoding of the text is different from 'encoding', attempt
+ * converting it. */
+ conv.vc_type = CONV_NONE;
+ convert_setup(&conv, enc, p_enc);
+ if (conv.vc_type != CONV_NONE)
+ {
+ convlen = len; /* Need to use an int here. */
+ tmpbuf = string_convert(&conv, p, &convlen);
+ len = convlen;
+ if (tmpbuf != NULL)
+ p = tmpbuf;
+ convert_setup(&conv, NULL, NULL);
+ }
+ }
+
+ else if (*type == compound_text_atom
+ || *type == utf8_atom
+ || (enc_dbcs != 0 && *type == text_atom))
+ {
+ XTextProperty text_prop;
+ int n_text = 0;
+ int status;
+
+ text_prop.value = (unsigned char *)value;
+ text_prop.encoding = *type;
+ text_prop.format = *format;
+ text_prop.nitems = len;
+#if defined(X_HAVE_UTF8_STRING)
+ if (*type == utf8_atom)
+ status = Xutf8TextPropertyToTextList(X_DISPLAY, &text_prop,
+ &text_list, &n_text);
+ else
+#endif
+ status = XmbTextPropertyToTextList(X_DISPLAY, &text_prop,
+ &text_list, &n_text);
+ if (status != Success || n_text < 1)
+ {
+ *(int *)success = FALSE;
+ return;
+ }
+ p = (char_u *)text_list[0];
+ len = STRLEN(p);
+ }
+ clip_yank_selection(motion_type, p, (long)len, cbd);
+
+ if (text_list != NULL)
+ XFreeStringList(text_list);
+ vim_free(tmpbuf);
+ XtFree((char *)value);
+ *(int *)success = TRUE;
+}
+
+ void
+clip_x11_request_selection(
+ Widget myShell,
+ Display *dpy,
+ VimClipboard *cbd)
+{
+ XEvent event;
+ Atom type;
+ static int success;
+ int i;
+ time_t start_time;
+ int timed_out = FALSE;
+
+ for (i = 0; i < 6; i++)
+ {
+ switch (i)
+ {
+ case 0: type = vimenc_atom; break;
+ case 1: type = vim_atom; break;
+ case 2: type = utf8_atom; break;
+ case 3: type = compound_text_atom; break;
+ case 4: type = text_atom; break;
+ default: type = XA_STRING;
+ }
+ if (type == utf8_atom
+# if defined(X_HAVE_UTF8_STRING)
+ && !enc_utf8
+# endif
+ )
+ /* Only request utf-8 when 'encoding' is utf8 and
+ * Xutf8TextPropertyToTextList is available. */
+ continue;
+ success = MAYBE;
+ XtGetSelectionValue(myShell, cbd->sel_atom, type,
+ clip_x11_request_selection_cb, (XtPointer)&success, CurrentTime);
+
+ /* Make sure the request for the selection goes out before waiting for
+ * a response. */
+ XFlush(dpy);
+
+ /*
+ * Wait for result of selection request, otherwise if we type more
+ * characters, then they will appear before the one that requested the
+ * paste! Don't worry, we will catch up with any other events later.
+ */
+ start_time = time(NULL);
+ while (success == MAYBE)
+ {
+ if (XCheckTypedEvent(dpy, PropertyNotify, &event)
+ || XCheckTypedEvent(dpy, SelectionNotify, &event)
+ || XCheckTypedEvent(dpy, SelectionRequest, &event))
+ {
+ /* This is where clip_x11_request_selection_cb() should be
+ * called. It may actually happen a bit later, so we loop
+ * until "success" changes.
+ * We may get a SelectionRequest here and if we don't handle
+ * it we hang. KDE klipper does this, for example.
+ * We need to handle a PropertyNotify for large selections. */
+ XtDispatchEvent(&event);
+ continue;
+ }
+
+ /* Time out after 2 to 3 seconds to avoid that we hang when the
+ * other process doesn't respond. Note that the SelectionNotify
+ * event may still come later when the selection owner comes back
+ * to life and the text gets inserted unexpectedly. Don't know
+ * why that happens or how to avoid that :-(. */
+ if (time(NULL) > start_time + 2)
+ {
+ timed_out = TRUE;
+ break;
+ }
+
+ /* Do we need this? Probably not. */
+ XSync(dpy, False);
+
+ /* Wait for 1 msec to avoid that we eat up all CPU time. */
+ ui_delay(1L, TRUE);
+ }
+
+ if (success == TRUE)
+ return;
+
+ /* don't do a retry with another type after timing out, otherwise we
+ * hang for 15 seconds. */
+ if (timed_out)
+ break;
+ }
+
+ /* Final fallback position - use the X CUT_BUFFER0 store */
+ yank_cut_buffer0(dpy, cbd);
+}
+
+ static Boolean
+clip_x11_convert_selection_cb(
+ Widget w UNUSED,
+ Atom *sel_atom,
+ Atom *target,
+ Atom *type,
+ XtPointer *value,
+ long_u *length,
+ int *format)
+{
+ static char_u *save_result = NULL;
+ static long_u save_length = 0;
+ char_u *string;
+ int motion_type;
+ VimClipboard *cbd;
+ int i;
+
+ if (*sel_atom == clip_plus.sel_atom)
+ cbd = &clip_plus;
+ else
+ cbd = &clip_star;
+
+ if (!cbd->owned)
+ return False; /* Shouldn't ever happen */
+
+ /* requestor wants to know what target types we support */
+ if (*target == targets_atom)
+ {
+ static Atom array[7];
+
+ *value = (XtPointer)array;
+ i = 0;
+ array[i++] = targets_atom;
+ array[i++] = vimenc_atom;
+ array[i++] = vim_atom;
+ if (enc_utf8)
+ array[i++] = utf8_atom;
+ array[i++] = XA_STRING;
+ array[i++] = text_atom;
+ array[i++] = compound_text_atom;
+
+ *type = XA_ATOM;
+ /* This used to be: *format = sizeof(Atom) * 8; but that caused
+ * crashes on 64 bit machines. (Peter Derr) */
+ *format = 32;
+ *length = i;
+ return True;
+ }
+
+ if ( *target != XA_STRING
+ && *target != vimenc_atom
+ && (*target != utf8_atom || !enc_utf8)
+ && *target != vim_atom
+ && *target != text_atom
+ && *target != compound_text_atom)
+ return False;
+
+ clip_get_selection(cbd);
+ motion_type = clip_convert_selection(&string, length, cbd);
+ if (motion_type < 0)
+ return False;
+
+ /* For our own format, the first byte contains the motion type */
+ if (*target == vim_atom)
+ (*length)++;
+
+ /* Our own format with encoding: motion 'encoding' NUL text */
+ if (*target == vimenc_atom)
+ *length += STRLEN(p_enc) + 2;
+
+ if (save_length < *length || save_length / 2 >= *length)
+ *value = XtRealloc((char *)save_result, (Cardinal)*length + 1);
+ else
+ *value = save_result;
+ if (*value == NULL)
+ {
+ vim_free(string);
+ return False;
+ }
+ save_result = (char_u *)*value;
+ save_length = *length;
+
+ if (*target == XA_STRING || (*target == utf8_atom && enc_utf8))
+ {
+ mch_memmove(save_result, string, (size_t)(*length));
+ *type = *target;
+ }
+ else if (*target == compound_text_atom || *target == text_atom)
+ {
+ XTextProperty text_prop;
+ char *string_nt = (char *)save_result;
+ int conv_result;
+
+ /* create NUL terminated string which XmbTextListToTextProperty wants */
+ mch_memmove(string_nt, string, (size_t)*length);
+ string_nt[*length] = NUL;
+ conv_result = XmbTextListToTextProperty(X_DISPLAY, (char **)&string_nt,
+ 1, XCompoundTextStyle, &text_prop);
+ if (conv_result != Success)
+ {
+ vim_free(string);
+ return False;
+ }
+ *value = (XtPointer)(text_prop.value); /* from plain text */
+ *length = text_prop.nitems;
+ *type = compound_text_atom;
+ XtFree((char *)save_result);
+ save_result = (char_u *)*value;
+ save_length = *length;
+ }
+ else if (*target == vimenc_atom)
+ {
+ int l = STRLEN(p_enc);
+
+ save_result[0] = motion_type;
+ STRCPY(save_result + 1, p_enc);
+ mch_memmove(save_result + l + 2, string, (size_t)(*length - l - 2));
+ *type = vimenc_atom;
+ }
+ else
+ {
+ save_result[0] = motion_type;
+ mch_memmove(save_result + 1, string, (size_t)(*length - 1));
+ *type = vim_atom;
+ }
+ *format = 8; /* 8 bits per char */
+ vim_free(string);
+ return True;
+}
+
+ static void
+clip_x11_lose_ownership_cb(Widget w UNUSED, Atom *sel_atom)
+{
+ if (*sel_atom == clip_plus.sel_atom)
+ clip_lose_selection(&clip_plus);
+ else
+ clip_lose_selection(&clip_star);
+}
+
+ void
+clip_x11_lose_selection(Widget myShell, VimClipboard *cbd)
+{
+ XtDisownSelection(myShell, cbd->sel_atom,
+ XtLastTimestampProcessed(XtDisplay(myShell)));
+}
+
+ static void
+clip_x11_notify_cb(Widget w UNUSED, Atom *sel_atom UNUSED, Atom *target UNUSED)
+{
+ /* To prevent automatically freeing the selection value. */
+}
+
+ int
+clip_x11_own_selection(Widget myShell, VimClipboard *cbd)
+{
+ /* When using the GUI we have proper timestamps, use the one of the last
+ * event. When in the console we don't get events (the terminal gets
+ * them), Get the time by a zero-length append, clip_x11_timestamp_cb will
+ * be called with the current timestamp. */
+#ifdef FEAT_GUI
+ if (gui.in_use)
+ {
+ if (XtOwnSelection(myShell, cbd->sel_atom,
+ XtLastTimestampProcessed(XtDisplay(myShell)),
+ clip_x11_convert_selection_cb, clip_x11_lose_ownership_cb,
+ clip_x11_notify_cb) == False)
+ return FAIL;
+ }
+ else
+#endif
+ {
+ if (!XChangeProperty(XtDisplay(myShell), XtWindow(myShell),
+ cbd->sel_atom, timestamp_atom, 32, PropModeAppend, NULL, 0))
+ return FAIL;
+ }
+ /* Flush is required in a terminal as nothing else is doing it. */
+ XFlush(XtDisplay(myShell));
+ return OK;
+}
+
+/*
+ * Send the current selection to the clipboard. Do nothing for X because we
+ * will fill in the selection only when requested by another app.
+ */
+ void
+clip_x11_set_selection(VimClipboard *cbd UNUSED)
+{
+}
+
+#if (defined(FEAT_X11) && defined(FEAT_XCLIPBOARD) && defined(USE_SYSTEM)) \
+ || defined(PROTO)
+ int
+clip_x11_owner_exists(VimClipboard *cbd)
+{
+ return XGetSelectionOwner(X_DISPLAY, cbd->sel_atom) != None;
+}
+#endif
+#endif
+
+#if defined(FEAT_XCLIPBOARD) || defined(FEAT_GUI_X11) \
+ || defined(FEAT_GUI_GTK) || defined(PROTO)
+/*
+ * Get the contents of the X CUT_BUFFER0 and put it in "cbd".
+ */
+ void
+yank_cut_buffer0(Display *dpy, VimClipboard *cbd)
+{
+ int nbytes = 0;
+ char_u *buffer = (char_u *)XFetchBuffer(dpy, &nbytes, 0);
+
+ if (nbytes > 0)
+ {
+ int done = FALSE;
+
+ /* CUT_BUFFER0 is supposed to be always latin1. Convert to 'enc' when
+ * using a multi-byte encoding. Conversion between two 8-bit
+ * character sets usually fails and the text might actually be in
+ * 'enc' anyway. */
+ if (has_mbyte)
+ {
+ char_u *conv_buf;
+ vimconv_T vc;
+
+ vc.vc_type = CONV_NONE;
+ if (convert_setup(&vc, (char_u *)"latin1", p_enc) == OK)
+ {
+ conv_buf = string_convert(&vc, buffer, &nbytes);
+ if (conv_buf != NULL)
+ {
+ clip_yank_selection(MCHAR, conv_buf, (long)nbytes, cbd);
+ vim_free(conv_buf);
+ done = TRUE;
+ }
+ convert_setup(&vc, NULL, NULL);
+ }
+ }
+ if (!done) /* use the text without conversion */
+ clip_yank_selection(MCHAR, buffer, (long)nbytes, cbd);
+ XFree((void *)buffer);
+ if (p_verbose > 0)
+ {
+ verbose_enter();
+ verb_msg(_("Used CUT_BUFFER0 instead of empty selection"));
+ verbose_leave();
+ }
+ }
+}
+#endif
+
+#if defined(FEAT_MOUSE) || defined(PROTO)
+
+/*
+ * Move the cursor to the specified row and column on the screen.
+ * Change current window if necessary. Returns an integer with the
+ * CURSOR_MOVED bit set if the cursor has moved or unset otherwise.
+ *
+ * The MOUSE_FOLD_CLOSE bit is set when clicked on the '-' in a fold column.
+ * The MOUSE_FOLD_OPEN bit is set when clicked on the '+' in a fold column.
+ *
+ * If flags has MOUSE_FOCUS, then the current window will not be changed, and
+ * if the mouse is outside the window then the text will scroll, or if the
+ * mouse was previously on a status line, then the status line may be dragged.
+ *
+ * If flags has MOUSE_MAY_VIS, then VIsual mode will be started before the
+ * cursor is moved unless the cursor was on a status line.
+ * This function returns one of IN_UNKNOWN, IN_BUFFER, IN_STATUS_LINE or
+ * IN_SEP_LINE depending on where the cursor was clicked.
+ *
+ * If flags has MOUSE_MAY_STOP_VIS, then Visual mode will be stopped, unless
+ * the mouse is on the status line of the same window.
+ *
+ * If flags has MOUSE_DID_MOVE, nothing is done if the mouse didn't move since
+ * the last call.
+ *
+ * If flags has MOUSE_SETPOS, nothing is done, only the current position is
+ * remembered.
+ */
+ int
+jump_to_mouse(
+ int flags,
+ int *inclusive, /* used for inclusive operator, can be NULL */
+ int which_button) /* MOUSE_LEFT, MOUSE_RIGHT, MOUSE_MIDDLE */
+{
+ static int on_status_line = 0; /* #lines below bottom of window */
+ static int on_sep_line = 0; /* on separator right of window */
+#ifdef FEAT_MENU
+ static int in_winbar = FALSE;
+#endif
+ static int prev_row = -1;
+ static int prev_col = -1;
+ static win_T *dragwin = NULL; /* window being dragged */
+ static int did_drag = FALSE; /* drag was noticed */
+
+ win_T *wp, *old_curwin;
+ pos_T old_cursor;
+ int count;
+ int first;
+ int row = mouse_row;
+ int col = mouse_col;
+#ifdef FEAT_FOLDING
+ int mouse_char;
+#endif
+
+ mouse_past_bottom = FALSE;
+ mouse_past_eol = FALSE;
+
+ if (flags & MOUSE_RELEASED)
+ {
+ /* On button release we may change window focus if positioned on a
+ * status line and no dragging happened. */
+ if (dragwin != NULL && !did_drag)
+ flags &= ~(MOUSE_FOCUS | MOUSE_DID_MOVE);
+ dragwin = NULL;
+ did_drag = FALSE;
+ }
+
+ if ((flags & MOUSE_DID_MOVE)
+ && prev_row == mouse_row
+ && prev_col == mouse_col)
+ {
+retnomove:
+ /* before moving the cursor for a left click which is NOT in a status
+ * line, stop Visual mode */
+ if (on_status_line)
+ return IN_STATUS_LINE;
+ if (on_sep_line)
+ return IN_SEP_LINE;
+#ifdef FEAT_MENU
+ if (in_winbar)
+ {
+ /* A quick second click may arrive as a double-click, but we use it
+ * as a second click in the WinBar. */
+ if ((mod_mask & MOD_MASK_MULTI_CLICK) && !(flags & MOUSE_RELEASED))
+ {
+ wp = mouse_find_win(&row, &col);
+ if (wp == NULL)
+ return IN_UNKNOWN;
+ winbar_click(wp, col);
+ }
+ return IN_OTHER_WIN | MOUSE_WINBAR;
+ }
+#endif
+ if (flags & MOUSE_MAY_STOP_VIS)
+ {
+ end_visual_mode();
+ redraw_curbuf_later(INVERTED); /* delete the inversion */
+ }
+#if defined(FEAT_CMDWIN) && defined(FEAT_CLIPBOARD)
+ /* Continue a modeless selection in another window. */
+ if (cmdwin_type != 0 && row < curwin->w_winrow)
+ return IN_OTHER_WIN;
+#endif
+ return IN_BUFFER;
+ }
+
+ prev_row = mouse_row;
+ prev_col = mouse_col;
+
+ if (flags & MOUSE_SETPOS)
+ goto retnomove; /* ugly goto... */
+
+#ifdef FEAT_FOLDING
+ /* Remember the character under the mouse, it might be a '-' or '+' in the
+ * fold column. */
+ if (row >= 0 && row < Rows && col >= 0 && col <= Columns
+ && ScreenLines != NULL)
+ mouse_char = ScreenLines[LineOffset[row] + col];
+ else
+ mouse_char = ' ';
+#endif
+
+ old_curwin = curwin;
+ old_cursor = curwin->w_cursor;
+
+ if (!(flags & MOUSE_FOCUS))
+ {
+ if (row < 0 || col < 0) /* check if it makes sense */
+ return IN_UNKNOWN;
+
+ /* find the window where the row is in */
+ wp = mouse_find_win(&row, &col);
+ if (wp == NULL)
+ return IN_UNKNOWN;
+ dragwin = NULL;
+
+#ifdef FEAT_MENU
+ if (row == -1)
+ {
+ /* A click in the window toolbar does not enter another window or
+ * change Visual highlighting. */
+ winbar_click(wp, col);
+ in_winbar = TRUE;
+ return IN_OTHER_WIN | MOUSE_WINBAR;
+ }
+ in_winbar = FALSE;
+#endif
+
+ /*
+ * winpos and height may change in win_enter()!
+ */
+ if (row >= wp->w_height) /* In (or below) status line */
+ {
+ on_status_line = row - wp->w_height + 1;
+ dragwin = wp;
+ }
+ else
+ on_status_line = 0;
+ if (col >= wp->w_width) /* In separator line */
+ {
+ on_sep_line = col - wp->w_width + 1;
+ dragwin = wp;
+ }
+ else
+ on_sep_line = 0;
+
+ /* The rightmost character of the status line might be a vertical
+ * separator character if there is no connecting window to the right. */
+ if (on_status_line && on_sep_line)
+ {
+ if (stl_connected(wp))
+ on_sep_line = 0;
+ else
+ on_status_line = 0;
+ }
+
+ /* Before jumping to another buffer, or moving the cursor for a left
+ * click, stop Visual mode. */
+ if (VIsual_active
+ && (wp->w_buffer != curwin->w_buffer
+ || (!on_status_line && !on_sep_line
+#ifdef FEAT_FOLDING
+ && (
+# ifdef FEAT_RIGHTLEFT
+ wp->w_p_rl ? col < wp->w_width - wp->w_p_fdc :
+# endif
+ col >= wp->w_p_fdc
+# ifdef FEAT_CMDWIN
+ + (cmdwin_type == 0 && wp == curwin ? 0 : 1)
+# endif
+ )
+#endif
+ && (flags & MOUSE_MAY_STOP_VIS))))
+ {
+ end_visual_mode();
+ redraw_curbuf_later(INVERTED); /* delete the inversion */
+ }
+#ifdef FEAT_CMDWIN
+ if (cmdwin_type != 0 && wp != curwin)
+ {
+ /* A click outside the command-line window: Use modeless
+ * selection if possible. Allow dragging the status lines. */
+ on_sep_line = 0;
+# ifdef FEAT_CLIPBOARD
+ if (on_status_line)
+ return IN_STATUS_LINE;
+ return IN_OTHER_WIN;
+# else
+ row = 0;
+ col += wp->w_wincol;
+ wp = curwin;
+# endif
+ }
+#endif
+ /* Only change window focus when not clicking on or dragging the
+ * status line. Do change focus when releasing the mouse button
+ * (MOUSE_FOCUS was set above if we dragged first). */
+ if (dragwin == NULL || (flags & MOUSE_RELEASED))
+ win_enter(wp, TRUE); /* can make wp invalid! */
+
+ if (curwin != old_curwin)
+ {
+#ifdef CHECK_DOUBLE_CLICK
+ /* set topline, to be able to check for double click ourselves */
+ set_mouse_topline(curwin);
+#endif
+#ifdef FEAT_TERMINAL
+ /* when entering a terminal window may change state */
+ term_win_entered();
+#endif
+ }
+ if (on_status_line) /* In (or below) status line */
+ {
+ /* Don't use start_arrow() if we're in the same window */
+ if (curwin == old_curwin)
+ return IN_STATUS_LINE;
+ else
+ return IN_STATUS_LINE | CURSOR_MOVED;
+ }
+ if (on_sep_line) /* In (or below) status line */
+ {
+ /* Don't use start_arrow() if we're in the same window */
+ if (curwin == old_curwin)
+ return IN_SEP_LINE;
+ else
+ return IN_SEP_LINE | CURSOR_MOVED;
+ }
+
+ curwin->w_cursor.lnum = curwin->w_topline;
+#ifdef FEAT_GUI
+ /* remember topline, needed for double click */
+ gui_prev_topline = curwin->w_topline;
+# ifdef FEAT_DIFF
+ gui_prev_topfill = curwin->w_topfill;
+# endif
+#endif
+ }
+ else if (on_status_line && which_button == MOUSE_LEFT)
+ {
+ if (dragwin != NULL)
+ {
+ /* Drag the status line */
+ count = row - dragwin->w_winrow - dragwin->w_height + 1
+ - on_status_line;
+ win_drag_status_line(dragwin, count);
+ did_drag |= count;
+ }
+ return IN_STATUS_LINE; /* Cursor didn't move */
+ }
+ else if (on_sep_line && which_button == MOUSE_LEFT)
+ {
+ if (dragwin != NULL)
+ {
+ /* Drag the separator column */
+ count = col - dragwin->w_wincol - dragwin->w_width + 1
+ - on_sep_line;
+ win_drag_vsep_line(dragwin, count);
+ did_drag |= count;
+ }
+ return IN_SEP_LINE; /* Cursor didn't move */
+ }
+#ifdef FEAT_MENU
+ else if (in_winbar)
+ {
+ /* After a click on the window toolbar don't start Visual mode. */
+ return IN_OTHER_WIN | MOUSE_WINBAR;
+ }
+#endif
+ else /* keep_window_focus must be TRUE */
+ {
+ /* before moving the cursor for a left click, stop Visual mode */
+ if (flags & MOUSE_MAY_STOP_VIS)
+ {
+ end_visual_mode();
+ redraw_curbuf_later(INVERTED); /* delete the inversion */
+ }
+
+#if defined(FEAT_CMDWIN) && defined(FEAT_CLIPBOARD)
+ /* Continue a modeless selection in another window. */
+ if (cmdwin_type != 0 && row < curwin->w_winrow)
+ return IN_OTHER_WIN;
+#endif
+
+ row -= W_WINROW(curwin);
+ col -= curwin->w_wincol;
+
+ /*
+ * When clicking beyond the end of the window, scroll the screen.
+ * Scroll by however many rows outside the window we are.
+ */
+ if (row < 0)
+ {
+ count = 0;
+ for (first = TRUE; curwin->w_topline > 1; )
+ {
+#ifdef FEAT_DIFF
+ if (curwin->w_topfill < diff_check(curwin, curwin->w_topline))
+ ++count;
+ else
+#endif
+ count += plines(curwin->w_topline - 1);
+ if (!first && count > -row)
+ break;
+ first = FALSE;
+#ifdef FEAT_FOLDING
+ (void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
+#endif
+#ifdef FEAT_DIFF
+ if (curwin->w_topfill < diff_check(curwin, curwin->w_topline))
+ ++curwin->w_topfill;
+ else
+#endif
+ {
+ --curwin->w_topline;
+#ifdef FEAT_DIFF
+ curwin->w_topfill = 0;
+#endif
+ }
+ }
+#ifdef FEAT_DIFF
+ check_topfill(curwin, FALSE);
+#endif
+ curwin->w_valid &=
+ ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP);
+ redraw_later(VALID);
+ row = 0;
+ }
+ else if (row >= curwin->w_height)
+ {
+ count = 0;
+ for (first = TRUE; curwin->w_topline < curbuf->b_ml.ml_line_count; )
+ {
+#ifdef FEAT_DIFF
+ if (curwin->w_topfill > 0)
+ ++count;
+ else
+#endif
+ count += plines(curwin->w_topline);
+ if (!first && count > row - curwin->w_height + 1)
+ break;
+ first = FALSE;
+#ifdef FEAT_FOLDING
+ if (hasFolding(curwin->w_topline, NULL, &curwin->w_topline)
+ && curwin->w_topline == curbuf->b_ml.ml_line_count)
+ break;
+#endif
+#ifdef FEAT_DIFF
+ if (curwin->w_topfill > 0)
+ --curwin->w_topfill;
+ else
+#endif
+ {
+ ++curwin->w_topline;
+#ifdef FEAT_DIFF
+ curwin->w_topfill =
+ diff_check_fill(curwin, curwin->w_topline);
+#endif
+ }
+ }
+#ifdef FEAT_DIFF
+ check_topfill(curwin, FALSE);
+#endif
+ redraw_later(VALID);
+ curwin->w_valid &=
+ ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP);
+ row = curwin->w_height - 1;
+ }
+ else if (row == 0)
+ {
+ /* When dragging the mouse, while the text has been scrolled up as
+ * far as it goes, moving the mouse in the top line should scroll
+ * the text down (done later when recomputing w_topline). */
+ if (mouse_dragging > 0
+ && curwin->w_cursor.lnum
+ == curwin->w_buffer->b_ml.ml_line_count
+ && curwin->w_cursor.lnum == curwin->w_topline)
+ curwin->w_valid &= ~(VALID_TOPLINE);
+ }
+ }
+
+#ifdef FEAT_FOLDING
+ /* Check for position outside of the fold column. */
+ if (
+# ifdef FEAT_RIGHTLEFT
+ curwin->w_p_rl ? col < curwin->w_width - curwin->w_p_fdc :
+# endif
+ col >= curwin->w_p_fdc
+# ifdef FEAT_CMDWIN
+ + (cmdwin_type == 0 ? 0 : 1)
+# endif
+ )
+ mouse_char = ' ';
+#endif
+
+ /* compute the position in the buffer line from the posn on the screen */
+ if (mouse_comp_pos(curwin, &row, &col, &curwin->w_cursor.lnum))
+ mouse_past_bottom = TRUE;
+
+ /* Start Visual mode before coladvance(), for when 'sel' != "old" */
+ if ((flags & MOUSE_MAY_VIS) && !VIsual_active)
+ {
+ check_visual_highlight();
+ VIsual = old_cursor;
+ VIsual_active = TRUE;
+ VIsual_reselect = TRUE;
+ /* if 'selectmode' contains "mouse", start Select mode */
+ may_start_select('o');
+ setmouse();
+ if (p_smd && msg_silent == 0)
+ redraw_cmdline = TRUE; /* show visual mode later */
+ }
+
+ curwin->w_curswant = col;
+ curwin->w_set_curswant = FALSE; /* May still have been TRUE */
+ if (coladvance(col) == FAIL) /* Mouse click beyond end of line */
+ {
+ if (inclusive != NULL)
+ *inclusive = TRUE;
+ mouse_past_eol = TRUE;
+ }
+ else if (inclusive != NULL)
+ *inclusive = FALSE;
+
+ count = IN_BUFFER;
+ if (curwin != old_curwin || curwin->w_cursor.lnum != old_cursor.lnum
+ || curwin->w_cursor.col != old_cursor.col)
+ count |= CURSOR_MOVED; /* Cursor has moved */
+
+#ifdef FEAT_FOLDING
+ if (mouse_char == '+')
+ count |= MOUSE_FOLD_OPEN;
+ else if (mouse_char != ' ')
+ count |= MOUSE_FOLD_CLOSE;
+#endif
+
+ return count;
+}
+
+/*
+ * Compute the position in the buffer line from the posn on the screen in
+ * window "win".
+ * Returns TRUE if the position is below the last line.
+ */
+ int
+mouse_comp_pos(
+ win_T *win,
+ int *rowp,
+ int *colp,
+ linenr_T *lnump)
+{
+ int col = *colp;
+ int row = *rowp;
+ linenr_T lnum;
+ int retval = FALSE;
+ int off;
+ int count;
+
+#ifdef FEAT_RIGHTLEFT
+ if (win->w_p_rl)
+ col = win->w_width - 1 - col;
+#endif
+
+ lnum = win->w_topline;
+
+ while (row > 0)
+ {
+#ifdef FEAT_DIFF
+ /* Don't include filler lines in "count" */
+ if (win->w_p_diff
+# ifdef FEAT_FOLDING
+ && !hasFoldingWin(win, lnum, NULL, NULL, TRUE, NULL)
+# endif
+ )
+ {
+ if (lnum == win->w_topline)
+ row -= win->w_topfill;
+ else
+ row -= diff_check_fill(win, lnum);
+ count = plines_win_nofill(win, lnum, TRUE);
+ }
+ else
+#endif
+ count = plines_win(win, lnum, TRUE);
+ if (count > row)
+ break; /* Position is in this buffer line. */
+#ifdef FEAT_FOLDING
+ (void)hasFoldingWin(win, lnum, NULL, &lnum, TRUE, NULL);
+#endif
+ if (lnum == win->w_buffer->b_ml.ml_line_count)
+ {
+ retval = TRUE;
+ break; /* past end of file */
+ }
+ row -= count;
+ ++lnum;
+ }
+
+ if (!retval)
+ {
+ /* Compute the column without wrapping. */
+ off = win_col_off(win) - win_col_off2(win);
+ if (col < off)
+ col = off;
+ col += row * (win->w_width - off);
+ /* add skip column (for long wrapping line) */
+ col += win->w_skipcol;
+ }
+
+ if (!win->w_p_wrap)
+ col += win->w_leftcol;
+
+ /* skip line number and fold column in front of the line */
+ col -= win_col_off(win);
+ if (col < 0)
+ {
+#ifdef FEAT_NETBEANS_INTG
+ netbeans_gutter_click(lnum);
+#endif
+ col = 0;
+ }
+
+ *colp = col;
+ *rowp = row;
+ *lnump = lnum;
+ return retval;
+}
+
+/*
+ * Find the window at screen position "*rowp" and "*colp". The positions are
+ * updated to become relative to the top-left of the window.
+ * Returns NULL when something is wrong.
+ */
+ win_T *
+mouse_find_win(int *rowp, int *colp UNUSED)
+{
+ frame_T *fp;
+ win_T *wp;
+
+ fp = topframe;
+ *rowp -= firstwin->w_winrow;
+ for (;;)
+ {
+ if (fp->fr_layout == FR_LEAF)
+ break;
+ if (fp->fr_layout == FR_ROW)
+ {
+ for (fp = fp->fr_child; fp->fr_next != NULL; fp = fp->fr_next)
+ {
+ if (*colp < fp->fr_width)
+ break;
+ *colp -= fp->fr_width;
+ }
+ }
+ else /* fr_layout == FR_COL */
+ {
+ for (fp = fp->fr_child; fp->fr_next != NULL; fp = fp->fr_next)
+ {
+ if (*rowp < fp->fr_height)
+ break;
+ *rowp -= fp->fr_height;
+ }
+ }
+ }
+ /* When using a timer that closes a window the window might not actually
+ * exist. */
+ FOR_ALL_WINDOWS(wp)
+ if (wp == fp->fr_win)
+ {
+#ifdef FEAT_MENU
+ *rowp -= wp->w_winbar_height;
+#endif
+ return wp;
+ }
+ return NULL;
+}
+
+#if defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_GTK) || defined(FEAT_GUI_MAC) \
+ || defined(FEAT_GUI_ATHENA) || defined(FEAT_GUI_MSWIN) \
+ || defined(FEAT_GUI_PHOTON) || defined(FEAT_TERM_POPUP_MENU) \
+ || defined(PROTO)
+/*
+ * Translate window coordinates to buffer position without any side effects
+ */
+ int
+get_fpos_of_mouse(pos_T *mpos)
+{
+ win_T *wp;
+ int row = mouse_row;
+ int col = mouse_col;
+
+ if (row < 0 || col < 0) /* check if it makes sense */
+ return IN_UNKNOWN;
+
+ /* find the window where the row is in */
+ wp = mouse_find_win(&row, &col);
+ if (wp == NULL)
+ return IN_UNKNOWN;
+ /*
+ * winpos and height may change in win_enter()!
+ */
+ if (row >= wp->w_height) /* In (or below) status line */
+ return IN_STATUS_LINE;
+ if (col >= wp->w_width) /* In vertical separator line */
+ return IN_SEP_LINE;
+
+ if (wp != curwin)
+ return IN_UNKNOWN;
+
+ /* compute the position in the buffer line from the posn on the screen */
+ if (mouse_comp_pos(curwin, &row, &col, &mpos->lnum))
+ return IN_STATUS_LINE; /* past bottom */
+
+ mpos->col = vcol2col(wp, mpos->lnum, col);
+
+ if (mpos->col > 0)
+ --mpos->col;
+ mpos->coladd = 0;
+ return IN_BUFFER;
+}
+#endif
+
+#if defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_GTK) || defined(FEAT_GUI_MAC) \
+ || defined(FEAT_GUI_ATHENA) || defined(FEAT_GUI_MSWIN) \
+ || defined(FEAT_GUI_PHOTON) || defined(FEAT_BEVAL) \
+ || defined(FEAT_TERM_POPUP_MENU) || defined(PROTO)
+/*
+ * Convert a virtual (screen) column to a character column.
+ * The first column is one.
+ */
+ int
+vcol2col(win_T *wp, linenr_T lnum, int vcol)
+{
+ /* try to advance to the specified column */
+ int count = 0;
+ char_u *ptr;
+ char_u *line;
+
+ line = ptr = ml_get_buf(wp->w_buffer, lnum, FALSE);
+ while (count < vcol && *ptr != NUL)
+ {
+ count += win_lbr_chartabsize(wp, line, ptr, count, NULL);
+ MB_PTR_ADV(ptr);
+ }
+ return (int)(ptr - line);
+}
+#endif
+
+#endif /* FEAT_MOUSE */
+
+#if defined(FEAT_GUI) || defined(WIN3264) || defined(PROTO)
+/*
+ * Called when focus changed. Used for the GUI or for systems where this can
+ * be done in the console (Win32).
+ */
+ void
+ui_focus_change(
+ int in_focus) /* TRUE if focus gained. */
+{
+ static time_t last_time = (time_t)0;
+ int need_redraw = FALSE;
+
+ /* When activated: Check if any file was modified outside of Vim.
+ * Only do this when not done within the last two seconds (could get
+ * several events in a row). */
+ if (in_focus && last_time + 2 < time(NULL))
+ {
+ need_redraw = check_timestamps(
+# ifdef FEAT_GUI
+ gui.in_use
+# else
+ FALSE
+# endif
+ );
+ last_time = time(NULL);
+ }
+
+ /*
+ * Fire the focus gained/lost autocommand.
+ */
+ need_redraw |= apply_autocmds(in_focus ? EVENT_FOCUSGAINED
+ : EVENT_FOCUSLOST, NULL, NULL, FALSE, curbuf);
+
+ if (need_redraw)
+ {
+ /* Something was executed, make sure the cursor is put back where it
+ * belongs. */
+ need_wait_return = FALSE;
+
+ if (State & CMDLINE)
+ redrawcmdline();
+ else if (State == HITRETURN || State == SETWSIZE || State == ASKMORE
+ || State == EXTERNCMD || State == CONFIRM || exmode_active)
+ repeat_message();
+ else if ((State & NORMAL) || (State & INSERT))
+ {
+ if (must_redraw != 0)
+ update_screen(0);
+ setcursor();
+ }
+ cursor_on(); /* redrawing may have switched it off */
+ out_flush_cursor(FALSE, TRUE);
+# ifdef FEAT_GUI
+ if (gui.in_use)
+ gui_update_scrollbars(FALSE);
+# endif
+ }
+#ifdef FEAT_TITLE
+ /* File may have been changed from 'readonly' to 'noreadonly' */
+ if (need_maketitle)
+ maketitle();
+#endif
+}
+#endif
+
+#if defined(HAVE_INPUT_METHOD) || defined(PROTO)
+/*
+ * Save current Input Method status to specified place.
+ */
+ void
+im_save_status(long *psave)
+{
+ /* Don't save when 'imdisable' is set or "xic" is NULL, IM is always
+ * disabled then (but might start later).
+ * Also don't save when inside a mapping, vgetc_im_active has not been set
+ * then.
+ * And don't save when the keys were stuffed (e.g., for a "." command).
+ * And don't save when the GUI is running but our window doesn't have
+ * input focus (e.g., when a find dialog is open). */
+ if (!p_imdisable && KeyTyped && !KeyStuffed
+# ifdef FEAT_XIM
+ && xic != NULL
+# endif
+# ifdef FEAT_GUI
+ && (!gui.in_use || gui.in_focus)
+# endif
+ )
+ {
+ /* Do save when IM is on, or IM is off and saved status is on. */
+ if (vgetc_im_active)
+ *psave = B_IMODE_IM;
+ else if (*psave == B_IMODE_IM)
+ *psave = B_IMODE_NONE;
+ }
+}
+#endif
diff --git a/src/undo.c b/src/undo.c
new file mode 100644
index 0000000..6b6dd47
--- /dev/null
+++ b/src/undo.c
@@ -0,0 +1,3592 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * undo.c: multi level undo facility
+ *
+ * The saved lines are stored in a list of lists (one for each buffer):
+ *
+ * b_u_oldhead------------------------------------------------+
+ * |
+ * V
+ * +--------------+ +--------------+ +--------------+
+ * b_u_newhead--->| u_header | | u_header | | u_header |
+ * | uh_next------>| uh_next------>| uh_next---->NULL
+ * NULL<--------uh_prev |<---------uh_prev |<---------uh_prev |
+ * | uh_entry | | uh_entry | | uh_entry |
+ * +--------|-----+ +--------|-----+ +--------|-----+
+ * | | |
+ * V V V
+ * +--------------+ +--------------+ +--------------+
+ * | u_entry | | u_entry | | u_entry |
+ * | ue_next | | ue_next | | ue_next |
+ * +--------|-----+ +--------|-----+ +--------|-----+
+ * | | |
+ * V V V
+ * +--------------+ NULL NULL
+ * | u_entry |
+ * | ue_next |
+ * +--------|-----+
+ * |
+ * V
+ * etc.
+ *
+ * Each u_entry list contains the information for one undo or redo.
+ * curbuf->b_u_curhead points to the header of the last undo (the next redo),
+ * or is NULL if nothing has been undone (end of the branch).
+ *
+ * For keeping alternate undo/redo branches the uh_alt field is used. Thus at
+ * each point in the list a branch may appear for an alternate to redo. The
+ * uh_seq field is numbered sequentially to be able to find a newer or older
+ * branch.
+ *
+ * +---------------+ +---------------+
+ * b_u_oldhead --->| u_header | | u_header |
+ * | uh_alt_next ---->| uh_alt_next ----> NULL
+ * NULL <----- uh_alt_prev |<------ uh_alt_prev |
+ * | uh_prev | | uh_prev |
+ * +-----|---------+ +-----|---------+
+ * | |
+ * V V
+ * +---------------+ +---------------+
+ * | u_header | | u_header |
+ * | uh_alt_next | | uh_alt_next |
+ * b_u_newhead --->| uh_alt_prev | | uh_alt_prev |
+ * | uh_prev | | uh_prev |
+ * +-----|---------+ +-----|---------+
+ * | |
+ * V V
+ * NULL +---------------+ +---------------+
+ * | u_header | | u_header |
+ * | uh_alt_next ---->| uh_alt_next |
+ * | uh_alt_prev |<------ uh_alt_prev |
+ * | uh_prev | | uh_prev |
+ * +-----|---------+ +-----|---------+
+ * | |
+ * etc. etc.
+ *
+ *
+ * All data is allocated and will all be freed when the buffer is unloaded.
+ */
+
+/* Uncomment the next line for including the u_check() function. This warns
+ * for errors in the debug information. */
+/* #define U_DEBUG 1 */
+#define UH_MAGIC 0x18dade /* value for uh_magic when in use */
+#define UE_MAGIC 0xabc123 /* value for ue_magic when in use */
+
+/* Size of buffer used for encryption. */
+#define CRYPT_BUF_SIZE 8192
+
+#include "vim.h"
+
+/* Structure passed around between functions.
+ * Avoids passing cryptstate_T when encryption not available. */
+typedef struct {
+ buf_T *bi_buf;
+ FILE *bi_fp;
+#ifdef FEAT_CRYPT
+ cryptstate_T *bi_state;
+ char_u *bi_buffer; /* CRYPT_BUF_SIZE, NULL when not buffering */
+ size_t bi_used; /* bytes written to/read from bi_buffer */
+ size_t bi_avail; /* bytes available in bi_buffer */
+#endif
+} bufinfo_T;
+
+
+static void u_unch_branch(u_header_T *uhp);
+static u_entry_T *u_get_headentry(void);
+static void u_getbot(void);
+static void u_doit(int count);
+static void u_undoredo(int undo);
+static void u_undo_end(int did_undo, int absolute);
+static void u_add_time(char_u *buf, size_t buflen, time_t tt);
+static void u_freeheader(buf_T *buf, u_header_T *uhp, u_header_T **uhpp);
+static void u_freebranch(buf_T *buf, u_header_T *uhp, u_header_T **uhpp);
+static void u_freeentries(buf_T *buf, u_header_T *uhp, u_header_T **uhpp);
+static void u_freeentry(u_entry_T *, long);
+#ifdef FEAT_PERSISTENT_UNDO
+# ifdef FEAT_CRYPT
+static int undo_flush(bufinfo_T *bi);
+# endif
+static int undo_read(bufinfo_T *bi, char_u *buffer, size_t size);
+static int serialize_uep(bufinfo_T *bi, u_entry_T *uep);
+static u_entry_T *unserialize_uep(bufinfo_T *bi, int *error, char_u *file_name);
+static void serialize_pos(bufinfo_T *bi, pos_T pos);
+static void unserialize_pos(bufinfo_T *bi, pos_T *pos);
+static void serialize_visualinfo(bufinfo_T *bi, visualinfo_T *info);
+static void unserialize_visualinfo(bufinfo_T *bi, visualinfo_T *info);
+#endif
+
+#define U_ALLOC_LINE(size) lalloc((long_u)(size), FALSE)
+
+/* used in undo_end() to report number of added and deleted lines */
+static long u_newcount, u_oldcount;
+
+/*
+ * When 'u' flag included in 'cpoptions', we behave like vi. Need to remember
+ * the action that "u" should do.
+ */
+static int undo_undoes = FALSE;
+
+static int lastmark = 0;
+
+#if defined(U_DEBUG) || defined(PROTO)
+/*
+ * Check the undo structures for being valid. Print a warning when something
+ * looks wrong.
+ */
+static int seen_b_u_curhead;
+static int seen_b_u_newhead;
+static int header_count;
+
+ static void
+u_check_tree(u_header_T *uhp,
+ u_header_T *exp_uh_next,
+ u_header_T *exp_uh_alt_prev)
+{
+ u_entry_T *uep;
+
+ if (uhp == NULL)
+ return;
+ ++header_count;
+ if (uhp == curbuf->b_u_curhead && ++seen_b_u_curhead > 1)
+ {
+ emsg("b_u_curhead found twice (looping?)");
+ return;
+ }
+ if (uhp == curbuf->b_u_newhead && ++seen_b_u_newhead > 1)
+ {
+ emsg("b_u_newhead found twice (looping?)");
+ return;
+ }
+
+ if (uhp->uh_magic != UH_MAGIC)
+ emsg("uh_magic wrong (may be using freed memory)");
+ else
+ {
+ /* Check pointers back are correct. */
+ if (uhp->uh_next.ptr != exp_uh_next)
+ {
+ emsg("uh_next wrong");
+ smsg("expected: 0x%x, actual: 0x%x",
+ exp_uh_next, uhp->uh_next.ptr);
+ }
+ if (uhp->uh_alt_prev.ptr != exp_uh_alt_prev)
+ {
+ emsg("uh_alt_prev wrong");
+ smsg("expected: 0x%x, actual: 0x%x",
+ exp_uh_alt_prev, uhp->uh_alt_prev.ptr);
+ }
+
+ /* Check the undo tree at this header. */
+ for (uep = uhp->uh_entry; uep != NULL; uep = uep->ue_next)
+ {
+ if (uep->ue_magic != UE_MAGIC)
+ {
+ emsg("ue_magic wrong (may be using freed memory)");
+ break;
+ }
+ }
+
+ /* Check the next alt tree. */
+ u_check_tree(uhp->uh_alt_next.ptr, uhp->uh_next.ptr, uhp);
+
+ /* Check the next header in this branch. */
+ u_check_tree(uhp->uh_prev.ptr, uhp, NULL);
+ }
+}
+
+ static void
+u_check(int newhead_may_be_NULL)
+{
+ seen_b_u_newhead = 0;
+ seen_b_u_curhead = 0;
+ header_count = 0;
+
+ u_check_tree(curbuf->b_u_oldhead, NULL, NULL);
+
+ if (seen_b_u_newhead == 0 && curbuf->b_u_oldhead != NULL
+ && !(newhead_may_be_NULL && curbuf->b_u_newhead == NULL))
+ semsg("b_u_newhead invalid: 0x%x", curbuf->b_u_newhead);
+ if (curbuf->b_u_curhead != NULL && seen_b_u_curhead == 0)
+ semsg("b_u_curhead invalid: 0x%x", curbuf->b_u_curhead);
+ if (header_count != curbuf->b_u_numhead)
+ {
+ emsg("b_u_numhead invalid");
+ smsg("expected: %ld, actual: %ld",
+ (long)header_count, (long)curbuf->b_u_numhead);
+ }
+}
+#endif
+
+/*
+ * Save the current line for both the "u" and "U" command.
+ * Careful: may trigger autocommands that reload the buffer.
+ * Returns OK or FAIL.
+ */
+ int
+u_save_cursor(void)
+{
+ return (u_save((linenr_T)(curwin->w_cursor.lnum - 1),
+ (linenr_T)(curwin->w_cursor.lnum + 1)));
+}
+
+/*
+ * Save the lines between "top" and "bot" for both the "u" and "U" command.
+ * "top" may be 0 and bot may be curbuf->b_ml.ml_line_count + 1.
+ * Careful: may trigger autocommands that reload the buffer.
+ * Returns FAIL when lines could not be saved, OK otherwise.
+ */
+ int
+u_save(linenr_T top, linenr_T bot)
+{
+ if (undo_off)
+ return OK;
+
+ if (top >= bot || bot > curbuf->b_ml.ml_line_count + 1)
+ return FAIL; // rely on caller to give an error message
+
+ if (top + 2 == bot)
+ u_saveline((linenr_T)(top + 1));
+
+ return (u_savecommon(top, bot, (linenr_T)0, FALSE));
+}
+
+/*
+ * Save the line "lnum" (used by ":s" and "~" command).
+ * The line is replaced, so the new bottom line is lnum + 1.
+ * Careful: may trigger autocommands that reload the buffer.
+ * Returns FAIL when lines could not be saved, OK otherwise.
+ */
+ int
+u_savesub(linenr_T lnum)
+{
+ if (undo_off)
+ return OK;
+
+ return (u_savecommon(lnum - 1, lnum + 1, lnum + 1, FALSE));
+}
+
+/*
+ * A new line is inserted before line "lnum" (used by :s command).
+ * The line is inserted, so the new bottom line is lnum + 1.
+ * Careful: may trigger autocommands that reload the buffer.
+ * Returns FAIL when lines could not be saved, OK otherwise.
+ */
+ int
+u_inssub(linenr_T lnum)
+{
+ if (undo_off)
+ return OK;
+
+ return (u_savecommon(lnum - 1, lnum, lnum + 1, FALSE));
+}
+
+/*
+ * Save the lines "lnum" - "lnum" + nlines (used by delete command).
+ * The lines are deleted, so the new bottom line is lnum, unless the buffer
+ * becomes empty.
+ * Careful: may trigger autocommands that reload the buffer.
+ * Returns FAIL when lines could not be saved, OK otherwise.
+ */
+ int
+u_savedel(linenr_T lnum, long nlines)
+{
+ if (undo_off)
+ return OK;
+
+ return (u_savecommon(lnum - 1, lnum + nlines,
+ nlines == curbuf->b_ml.ml_line_count ? 2 : lnum, FALSE));
+}
+
+/*
+ * Return TRUE when undo is allowed. Otherwise give an error message and
+ * return FALSE.
+ */
+ int
+undo_allowed(void)
+{
+ /* Don't allow changes when 'modifiable' is off. */
+ if (!curbuf->b_p_ma)
+ {
+ emsg(_(e_modifiable));
+ return FALSE;
+ }
+
+#ifdef HAVE_SANDBOX
+ /* In the sandbox it's not allowed to change the text. */
+ if (sandbox != 0)
+ {
+ emsg(_(e_sandbox));
+ return FALSE;
+ }
+#endif
+
+ /* Don't allow changes in the buffer while editing the cmdline. The
+ * caller of getcmdline() may get confused. */
+ if (textlock != 0)
+ {
+ emsg(_(e_secure));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/*
+ * Get the undolevle value for the current buffer.
+ */
+ static long
+get_undolevel(void)
+{
+ if (curbuf->b_p_ul == NO_LOCAL_UNDOLEVEL)
+ return p_ul;
+ return curbuf->b_p_ul;
+}
+
+/*
+ * u_save_line(): save an allocated copy of line "lnum" into "ul".
+ * Returns FAIL when out of memory.
+ */
+ static int
+u_save_line(undoline_T *ul, linenr_T lnum)
+{
+ char_u *line = ml_get(lnum);
+
+ if (curbuf->b_ml.ml_line_len == 0)
+ {
+ ul->ul_len = 1;
+ ul->ul_line = vim_strsave((char_u *)"");
+ }
+ else
+ {
+ ul->ul_len = curbuf->b_ml.ml_line_len;
+ ul->ul_line = vim_memsave(line, ul->ul_len);
+ }
+ return ul->ul_line == NULL ? FAIL : OK;
+}
+
+/*
+ * Common code for various ways to save text before a change.
+ * "top" is the line above the first changed line.
+ * "bot" is the line below the last changed line.
+ * "newbot" is the new bottom line. Use zero when not known.
+ * "reload" is TRUE when saving for a buffer reload.
+ * Careful: may trigger autocommands that reload the buffer.
+ * Returns FAIL when lines could not be saved, OK otherwise.
+ */
+ int
+u_savecommon(
+ linenr_T top,
+ linenr_T bot,
+ linenr_T newbot,
+ int reload)
+{
+ linenr_T lnum;
+ long i;
+ u_header_T *uhp;
+ u_header_T *old_curhead;
+ u_entry_T *uep;
+ u_entry_T *prev_uep;
+ long size;
+
+ if (!reload)
+ {
+ /* When making changes is not allowed return FAIL. It's a crude way
+ * to make all change commands fail. */
+ if (!undo_allowed())
+ return FAIL;
+
+#ifdef FEAT_NETBEANS_INTG
+ /*
+ * Netbeans defines areas that cannot be modified. Bail out here when
+ * trying to change text in a guarded area.
+ */
+ if (netbeans_active())
+ {
+ if (netbeans_is_guarded(top, bot))
+ {
+ emsg(_(e_guarded));
+ return FAIL;
+ }
+ if (curbuf->b_p_ro)
+ {
+ emsg(_(e_nbreadonly));
+ return FAIL;
+ }
+ }
+#endif
+#ifdef FEAT_TERMINAL
+ /* A change in a terminal buffer removes the highlighting. */
+ term_change_in_curbuf();
+#endif
+
+ /*
+ * Saving text for undo means we are going to make a change. Give a
+ * warning for a read-only file before making the change, so that the
+ * FileChangedRO event can replace the buffer with a read-write version
+ * (e.g., obtained from a source control system).
+ */
+ change_warning(0);
+ if (bot > curbuf->b_ml.ml_line_count + 1)
+ {
+ /* This happens when the FileChangedRO autocommand changes the
+ * file in a way it becomes shorter. */
+ emsg(_("E881: Line count changed unexpectedly"));
+ return FAIL;
+ }
+ }
+
+#ifdef U_DEBUG
+ u_check(FALSE);
+#endif
+
+ size = bot - top - 1;
+
+ /*
+ * If curbuf->b_u_synced == TRUE make a new header.
+ */
+ if (curbuf->b_u_synced)
+ {
+#ifdef FEAT_JUMPLIST
+ /* Need to create new entry in b_changelist. */
+ curbuf->b_new_change = TRUE;
+#endif
+
+ if (get_undolevel() >= 0)
+ {
+ /*
+ * Make a new header entry. Do this first so that we don't mess
+ * up the undo info when out of memory.
+ */
+ uhp = (u_header_T *)U_ALLOC_LINE(sizeof(u_header_T));
+ if (uhp == NULL)
+ goto nomem;
+#ifdef U_DEBUG
+ uhp->uh_magic = UH_MAGIC;
+#endif
+ }
+ else
+ uhp = NULL;
+
+ /*
+ * If we undid more than we redid, move the entry lists before and
+ * including curbuf->b_u_curhead to an alternate branch.
+ */
+ old_curhead = curbuf->b_u_curhead;
+ if (old_curhead != NULL)
+ {
+ curbuf->b_u_newhead = old_curhead->uh_next.ptr;
+ curbuf->b_u_curhead = NULL;
+ }
+
+ /*
+ * free headers to keep the size right
+ */
+ while (curbuf->b_u_numhead > get_undolevel()
+ && curbuf->b_u_oldhead != NULL)
+ {
+ u_header_T *uhfree = curbuf->b_u_oldhead;
+
+ if (uhfree == old_curhead)
+ /* Can't reconnect the branch, delete all of it. */
+ u_freebranch(curbuf, uhfree, &old_curhead);
+ else if (uhfree->uh_alt_next.ptr == NULL)
+ /* There is no branch, only free one header. */
+ u_freeheader(curbuf, uhfree, &old_curhead);
+ else
+ {
+ /* Free the oldest alternate branch as a whole. */
+ while (uhfree->uh_alt_next.ptr != NULL)
+ uhfree = uhfree->uh_alt_next.ptr;
+ u_freebranch(curbuf, uhfree, &old_curhead);
+ }
+#ifdef U_DEBUG
+ u_check(TRUE);
+#endif
+ }
+
+ if (uhp == NULL) /* no undo at all */
+ {
+ if (old_curhead != NULL)
+ u_freebranch(curbuf, old_curhead, NULL);
+ curbuf->b_u_synced = FALSE;
+ return OK;
+ }
+
+ uhp->uh_prev.ptr = NULL;
+ uhp->uh_next.ptr = curbuf->b_u_newhead;
+ uhp->uh_alt_next.ptr = old_curhead;
+ if (old_curhead != NULL)
+ {
+ uhp->uh_alt_prev.ptr = old_curhead->uh_alt_prev.ptr;
+ if (uhp->uh_alt_prev.ptr != NULL)
+ uhp->uh_alt_prev.ptr->uh_alt_next.ptr = uhp;
+ old_curhead->uh_alt_prev.ptr = uhp;
+ if (curbuf->b_u_oldhead == old_curhead)
+ curbuf->b_u_oldhead = uhp;
+ }
+ else
+ uhp->uh_alt_prev.ptr = NULL;
+ if (curbuf->b_u_newhead != NULL)
+ curbuf->b_u_newhead->uh_prev.ptr = uhp;
+
+ uhp->uh_seq = ++curbuf->b_u_seq_last;
+ curbuf->b_u_seq_cur = uhp->uh_seq;
+ uhp->uh_time = vim_time();
+ uhp->uh_save_nr = 0;
+ curbuf->b_u_time_cur = uhp->uh_time + 1;
+
+ uhp->uh_walk = 0;
+ uhp->uh_entry = NULL;
+ uhp->uh_getbot_entry = NULL;
+ uhp->uh_cursor = curwin->w_cursor; /* save cursor pos. for undo */
+ if (virtual_active() && curwin->w_cursor.coladd > 0)
+ uhp->uh_cursor_vcol = getviscol();
+ else
+ uhp->uh_cursor_vcol = -1;
+
+ /* save changed and buffer empty flag for undo */
+ uhp->uh_flags = (curbuf->b_changed ? UH_CHANGED : 0) +
+ ((curbuf->b_ml.ml_flags & ML_EMPTY) ? UH_EMPTYBUF : 0);
+
+ /* save named marks and Visual marks for undo */
+ mch_memmove(uhp->uh_namedm, curbuf->b_namedm, sizeof(pos_T) * NMARKS);
+ uhp->uh_visual = curbuf->b_visual;
+
+ curbuf->b_u_newhead = uhp;
+ if (curbuf->b_u_oldhead == NULL)
+ curbuf->b_u_oldhead = uhp;
+ ++curbuf->b_u_numhead;
+ }
+ else
+ {
+ if (get_undolevel() < 0) /* no undo at all */
+ return OK;
+
+ /*
+ * When saving a single line, and it has been saved just before, it
+ * doesn't make sense saving it again. Saves a lot of memory when
+ * making lots of changes inside the same line.
+ * This is only possible if the previous change didn't increase or
+ * decrease the number of lines.
+ * Check the ten last changes. More doesn't make sense and takes too
+ * long.
+ */
+ if (size == 1)
+ {
+ uep = u_get_headentry();
+ prev_uep = NULL;
+ for (i = 0; i < 10; ++i)
+ {
+ if (uep == NULL)
+ break;
+
+ /* If lines have been inserted/deleted we give up.
+ * Also when the line was included in a multi-line save. */
+ if ((curbuf->b_u_newhead->uh_getbot_entry != uep
+ ? (uep->ue_top + uep->ue_size + 1
+ != (uep->ue_bot == 0
+ ? curbuf->b_ml.ml_line_count + 1
+ : uep->ue_bot))
+ : uep->ue_lcount != curbuf->b_ml.ml_line_count)
+ || (uep->ue_size > 1
+ && top >= uep->ue_top
+ && top + 2 <= uep->ue_top + uep->ue_size + 1))
+ break;
+
+ /* If it's the same line we can skip saving it again. */
+ if (uep->ue_size == 1 && uep->ue_top == top)
+ {
+ if (i > 0)
+ {
+ /* It's not the last entry: get ue_bot for the last
+ * entry now. Following deleted/inserted lines go to
+ * the re-used entry. */
+ u_getbot();
+ curbuf->b_u_synced = FALSE;
+
+ /* Move the found entry to become the last entry. The
+ * order of undo/redo doesn't matter for the entries
+ * we move it over, since they don't change the line
+ * count and don't include this line. It does matter
+ * for the found entry if the line count is changed by
+ * the executed command. */
+ prev_uep->ue_next = uep->ue_next;
+ uep->ue_next = curbuf->b_u_newhead->uh_entry;
+ curbuf->b_u_newhead->uh_entry = uep;
+ }
+
+ /* The executed command may change the line count. */
+ if (newbot != 0)
+ uep->ue_bot = newbot;
+ else if (bot > curbuf->b_ml.ml_line_count)
+ uep->ue_bot = 0;
+ else
+ {
+ uep->ue_lcount = curbuf->b_ml.ml_line_count;
+ curbuf->b_u_newhead->uh_getbot_entry = uep;
+ }
+ return OK;
+ }
+ prev_uep = uep;
+ uep = uep->ue_next;
+ }
+ }
+
+ /* find line number for ue_bot for previous u_save() */
+ u_getbot();
+ }
+
+#if !defined(UNIX) && !defined(WIN32)
+ /*
+ * With Amiga we can't handle big undo's, because
+ * then u_alloc_line would have to allocate a block larger than 32K
+ */
+ if (size >= 8000)
+ goto nomem;
+#endif
+
+ /*
+ * add lines in front of entry list
+ */
+ uep = (u_entry_T *)U_ALLOC_LINE(sizeof(u_entry_T));
+ if (uep == NULL)
+ goto nomem;
+ vim_memset(uep, 0, sizeof(u_entry_T));
+#ifdef U_DEBUG
+ uep->ue_magic = UE_MAGIC;
+#endif
+
+ uep->ue_size = size;
+ uep->ue_top = top;
+ if (newbot != 0)
+ uep->ue_bot = newbot;
+ /*
+ * Use 0 for ue_bot if bot is below last line.
+ * Otherwise we have to compute ue_bot later.
+ */
+ else if (bot > curbuf->b_ml.ml_line_count)
+ uep->ue_bot = 0;
+ else
+ {
+ uep->ue_lcount = curbuf->b_ml.ml_line_count;
+ curbuf->b_u_newhead->uh_getbot_entry = uep;
+ }
+
+ if (size > 0)
+ {
+ if ((uep->ue_array = (undoline_T *)U_ALLOC_LINE(
+ sizeof(undoline_T) * size)) == NULL)
+ {
+ u_freeentry(uep, 0L);
+ goto nomem;
+ }
+ for (i = 0, lnum = top + 1; i < size; ++i)
+ {
+ fast_breakcheck();
+ if (got_int)
+ {
+ u_freeentry(uep, i);
+ return FAIL;
+ }
+ if (u_save_line(&uep->ue_array[i], lnum++) == FAIL)
+ {
+ u_freeentry(uep, i);
+ goto nomem;
+ }
+ }
+ }
+ else
+ uep->ue_array = NULL;
+ uep->ue_next = curbuf->b_u_newhead->uh_entry;
+ curbuf->b_u_newhead->uh_entry = uep;
+ curbuf->b_u_synced = FALSE;
+ undo_undoes = FALSE;
+
+#ifdef U_DEBUG
+ u_check(FALSE);
+#endif
+ return OK;
+
+nomem:
+ msg_silent = 0; /* must display the prompt */
+ if (ask_yesno((char_u *)_("No undo possible; continue anyway"), TRUE)
+ == 'y')
+ {
+ undo_off = TRUE; /* will be reset when character typed */
+ return OK;
+ }
+ do_outofmem_msg((long_u)0);
+ return FAIL;
+}
+
+#if defined(FEAT_PERSISTENT_UNDO) || defined(PROTO)
+
+# define UF_START_MAGIC "Vim\237UnDo\345" /* magic at start of undofile */
+# define UF_START_MAGIC_LEN 9
+# define UF_HEADER_MAGIC 0x5fd0 /* magic at start of header */
+# define UF_HEADER_END_MAGIC 0xe7aa /* magic after last header */
+# define UF_ENTRY_MAGIC 0xf518 /* magic at start of entry */
+# define UF_ENTRY_END_MAGIC 0x3581 /* magic after last entry */
+# define UF_VERSION 2 /* 2-byte undofile version number */
+# define UF_VERSION_CRYPT 0x8002 /* idem, encrypted */
+
+/* extra fields for header */
+# define UF_LAST_SAVE_NR 1
+
+/* extra fields for uhp */
+# define UHP_SAVE_NR 1
+
+static char_u e_not_open[] = N_("E828: Cannot open undo file for writing: %s");
+
+/*
+ * Compute the hash for the current buffer text into hash[UNDO_HASH_SIZE].
+ */
+ void
+u_compute_hash(char_u *hash)
+{
+ context_sha256_T ctx;
+ linenr_T lnum;
+ char_u *p;
+
+ sha256_start(&ctx);
+ for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count; ++lnum)
+ {
+ p = ml_get(lnum);
+ sha256_update(&ctx, p, (UINT32_T)(STRLEN(p) + 1));
+ }
+ sha256_finish(&ctx, hash);
+}
+
+/*
+ * Return an allocated string of the full path of the target undofile.
+ * When "reading" is TRUE find the file to read, go over all directories in
+ * 'undodir'.
+ * When "reading" is FALSE use the first name where the directory exists.
+ * Returns NULL when there is no place to write or no file to read.
+ */
+ char_u *
+u_get_undo_file_name(char_u *buf_ffname, int reading)
+{
+ char_u *dirp;
+ char_u dir_name[IOSIZE + 1];
+ char_u *munged_name = NULL;
+ char_u *undo_file_name = NULL;
+ int dir_len;
+ char_u *p;
+ stat_T st;
+ char_u *ffname = buf_ffname;
+#ifdef HAVE_READLINK
+ char_u fname_buf[MAXPATHL];
+#endif
+
+ if (ffname == NULL)
+ return NULL;
+
+#ifdef HAVE_READLINK
+ /* Expand symlink in the file name, so that we put the undo file with the
+ * actual file instead of with the symlink. */
+ if (resolve_symlink(ffname, fname_buf) == OK)
+ ffname = fname_buf;
+#endif
+
+ /* Loop over 'undodir'. When reading find the first file that exists.
+ * When not reading use the first directory that exists or ".". */
+ dirp = p_udir;
+ while (*dirp != NUL)
+ {
+ dir_len = copy_option_part(&dirp, dir_name, IOSIZE, ",");
+ if (dir_len == 1 && dir_name[0] == '.')
+ {
+ /* Use same directory as the ffname,
+ * "dir/name" -> "dir/.name.un~" */
+ undo_file_name = vim_strnsave(ffname, (int)(STRLEN(ffname) + 5));
+ if (undo_file_name == NULL)
+ break;
+ p = gettail(undo_file_name);
+#ifdef VMS
+ /* VMS can not handle more than one dot in the filenames
+ * use "dir/name" -> "dir/_un_name" - add _un_
+ * at the beginning to keep the extension */
+ mch_memmove(p + 4, p, STRLEN(p) + 1);
+ mch_memmove(p, "_un_", 4);
+
+#else
+ /* Use same directory as the ffname,
+ * "dir/name" -> "dir/.name.un~" */
+ mch_memmove(p + 1, p, STRLEN(p) + 1);
+ *p = '.';
+ STRCAT(p, ".un~");
+#endif
+ }
+ else
+ {
+ dir_name[dir_len] = NUL;
+ if (mch_isdir(dir_name))
+ {
+ if (munged_name == NULL)
+ {
+ munged_name = vim_strsave(ffname);
+ if (munged_name == NULL)
+ return NULL;
+ for (p = munged_name; *p != NUL; MB_PTR_ADV(p))
+ if (vim_ispathsep(*p))
+ *p = '%';
+ }
+ undo_file_name = concat_fnames(dir_name, munged_name, TRUE);
+ }
+ }
+
+ /* When reading check if the file exists. */
+ if (undo_file_name != NULL && (!reading
+ || mch_stat((char *)undo_file_name, &st) >= 0))
+ break;
+ VIM_CLEAR(undo_file_name);
+ }
+
+ vim_free(munged_name);
+ return undo_file_name;
+}
+
+ static void
+corruption_error(char *mesg, char_u *file_name)
+{
+ semsg(_("E825: Corrupted undo file (%s): %s"), mesg, file_name);
+}
+
+ static void
+u_free_uhp(u_header_T *uhp)
+{
+ u_entry_T *nuep;
+ u_entry_T *uep;
+
+ uep = uhp->uh_entry;
+ while (uep != NULL)
+ {
+ nuep = uep->ue_next;
+ u_freeentry(uep, uep->ue_size);
+ uep = nuep;
+ }
+ vim_free(uhp);
+}
+
+/*
+ * Write a sequence of bytes to the undo file.
+ * Buffers and encrypts as needed.
+ * Returns OK or FAIL.
+ */
+ static int
+undo_write(bufinfo_T *bi, char_u *ptr, size_t len)
+{
+#ifdef FEAT_CRYPT
+ if (bi->bi_buffer != NULL)
+ {
+ size_t len_todo = len;
+ char_u *p = ptr;
+
+ while (bi->bi_used + len_todo >= CRYPT_BUF_SIZE)
+ {
+ size_t n = CRYPT_BUF_SIZE - bi->bi_used;
+
+ mch_memmove(bi->bi_buffer + bi->bi_used, p, n);
+ len_todo -= n;
+ p += n;
+ bi->bi_used = CRYPT_BUF_SIZE;
+ if (undo_flush(bi) == FAIL)
+ return FAIL;
+ }
+ if (len_todo > 0)
+ {
+ mch_memmove(bi->bi_buffer + bi->bi_used, p, len_todo);
+ bi->bi_used += len_todo;
+ }
+ return OK;
+ }
+#endif
+ if (fwrite(ptr, len, (size_t)1, bi->bi_fp) != 1)
+ return FAIL;
+ return OK;
+}
+
+#ifdef FEAT_CRYPT
+ static int
+undo_flush(bufinfo_T *bi)
+{
+ if (bi->bi_buffer != NULL && bi->bi_state != NULL && bi->bi_used > 0)
+ {
+ crypt_encode_inplace(bi->bi_state, bi->bi_buffer, bi->bi_used);
+ if (fwrite(bi->bi_buffer, bi->bi_used, (size_t)1, bi->bi_fp) != 1)
+ return FAIL;
+ bi->bi_used = 0;
+ }
+ return OK;
+}
+#endif
+
+/*
+ * Write "ptr[len]" and crypt the bytes when needed.
+ * Returns OK or FAIL.
+ */
+ static int
+fwrite_crypt(bufinfo_T *bi, char_u *ptr, size_t len)
+{
+#ifdef FEAT_CRYPT
+ char_u *copy;
+ char_u small_buf[100];
+ size_t i;
+
+ if (bi->bi_state != NULL && bi->bi_buffer == NULL)
+ {
+ /* crypting every piece of text separately */
+ if (len < 100)
+ copy = small_buf; /* no malloc()/free() for short strings */
+ else
+ {
+ copy = lalloc(len, FALSE);
+ if (copy == NULL)
+ return 0;
+ }
+ crypt_encode(bi->bi_state, ptr, len, copy);
+ i = fwrite(copy, len, (size_t)1, bi->bi_fp);
+ if (copy != small_buf)
+ vim_free(copy);
+ return i == 1 ? OK : FAIL;
+ }
+#endif
+ return undo_write(bi, ptr, len);
+}
+
+/*
+ * Write a number, MSB first, in "len" bytes.
+ * Must match with undo_read_?c() functions.
+ * Returns OK or FAIL.
+ */
+ static int
+undo_write_bytes(bufinfo_T *bi, long_u nr, int len)
+{
+ char_u buf[8];
+ int i;
+ int bufi = 0;
+
+ for (i = len - 1; i >= 0; --i)
+ buf[bufi++] = (char_u)(nr >> (i * 8));
+ return undo_write(bi, buf, (size_t)len);
+}
+
+/*
+ * Write the pointer to an undo header. Instead of writing the pointer itself
+ * we use the sequence number of the header. This is converted back to
+ * pointers when reading. */
+ static void
+put_header_ptr(bufinfo_T *bi, u_header_T *uhp)
+{
+ undo_write_bytes(bi, (long_u)(uhp != NULL ? uhp->uh_seq : 0), 4);
+}
+
+ static int
+undo_read_4c(bufinfo_T *bi)
+{
+#ifdef FEAT_CRYPT
+ if (bi->bi_buffer != NULL)
+ {
+ char_u buf[4];
+ int n;
+
+ undo_read(bi, buf, (size_t)4);
+ n = ((unsigned)buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3];
+ return n;
+ }
+#endif
+ return get4c(bi->bi_fp);
+}
+
+ static int
+undo_read_2c(bufinfo_T *bi)
+{
+#ifdef FEAT_CRYPT
+ if (bi->bi_buffer != NULL)
+ {
+ char_u buf[2];
+ int n;
+
+ undo_read(bi, buf, (size_t)2);
+ n = (buf[0] << 8) + buf[1];
+ return n;
+ }
+#endif
+ return get2c(bi->bi_fp);
+}
+
+ static int
+undo_read_byte(bufinfo_T *bi)
+{
+#ifdef FEAT_CRYPT
+ if (bi->bi_buffer != NULL)
+ {
+ char_u buf[1];
+
+ undo_read(bi, buf, (size_t)1);
+ return buf[0];
+ }
+#endif
+ return getc(bi->bi_fp);
+}
+
+ static time_t
+undo_read_time(bufinfo_T *bi)
+{
+#ifdef FEAT_CRYPT
+ if (bi->bi_buffer != NULL)
+ {
+ char_u buf[8];
+ time_t n = 0;
+ int i;
+
+ undo_read(bi, buf, (size_t)8);
+ for (i = 0; i < 8; ++i)
+ n = (n << 8) + buf[i];
+ return n;
+ }
+#endif
+ return get8ctime(bi->bi_fp);
+}
+
+/*
+ * Read "buffer[size]" from the undo file.
+ * Return OK or FAIL.
+ */
+ static int
+undo_read(bufinfo_T *bi, char_u *buffer, size_t size)
+{
+ int retval = OK;
+
+#ifdef FEAT_CRYPT
+ if (bi->bi_buffer != NULL)
+ {
+ int size_todo = (int)size;
+ char_u *p = buffer;
+
+ while (size_todo > 0)
+ {
+ size_t n;
+
+ if (bi->bi_used >= bi->bi_avail)
+ {
+ n = fread(bi->bi_buffer, 1, (size_t)CRYPT_BUF_SIZE, bi->bi_fp);
+ if (n == 0)
+ {
+ retval = FAIL;
+ break;
+ }
+ bi->bi_avail = n;
+ bi->bi_used = 0;
+ crypt_decode_inplace(bi->bi_state, bi->bi_buffer, bi->bi_avail);
+ }
+ n = size_todo;
+ if (n > bi->bi_avail - bi->bi_used)
+ n = bi->bi_avail - bi->bi_used;
+ mch_memmove(p, bi->bi_buffer + bi->bi_used, n);
+ bi->bi_used += n;
+ size_todo -= (int)n;
+ p += n;
+ }
+ }
+ else
+#endif
+ if (fread(buffer, (size_t)size, 1, bi->bi_fp) != 1)
+ retval = FAIL;
+
+ if (retval == FAIL)
+ /* Error may be checked for only later. Fill with zeros,
+ * so that the reader won't use garbage. */
+ vim_memset(buffer, 0, size);
+ return retval;
+}
+
+/*
+ * Read a string of length "len" from "bi->bi_fd".
+ * "len" can be zero to allocate an empty line.
+ * Decrypt the bytes if needed.
+ * Append a NUL.
+ * Returns a pointer to allocated memory or NULL for failure.
+ */
+ static char_u *
+read_string_decrypt(bufinfo_T *bi, int len)
+{
+ char_u *ptr = alloc((unsigned)len + 1);
+
+ if (ptr != NULL)
+ {
+ if (len > 0 && undo_read(bi, ptr, len) == FAIL)
+ {
+ vim_free(ptr);
+ return NULL;
+ }
+ // In case there are text properties there already is a NUL, but
+ // checking for that is more expensive than just adding a dummy byte.
+ ptr[len] = NUL;
+#ifdef FEAT_CRYPT
+ if (bi->bi_state != NULL && bi->bi_buffer == NULL)
+ crypt_decode_inplace(bi->bi_state, ptr, len);
+#endif
+ }
+ return ptr;
+}
+
+/*
+ * Writes the (not encrypted) header and initializes encryption if needed.
+ */
+ static int
+serialize_header(bufinfo_T *bi, char_u *hash)
+{
+ long len;
+ buf_T *buf = bi->bi_buf;
+ FILE *fp = bi->bi_fp;
+ char_u time_buf[8];
+
+ /* Start writing, first the magic marker and undo info version. */
+ if (fwrite(UF_START_MAGIC, (size_t)UF_START_MAGIC_LEN, (size_t)1, fp) != 1)
+ return FAIL;
+
+ /* If the buffer is encrypted then all text bytes following will be
+ * encrypted. Numbers and other info is not crypted. */
+#ifdef FEAT_CRYPT
+ if (*buf->b_p_key != NUL)
+ {
+ char_u *header;
+ int header_len;
+
+ undo_write_bytes(bi, (long_u)UF_VERSION_CRYPT, 2);
+ bi->bi_state = crypt_create_for_writing(crypt_get_method_nr(buf),
+ buf->b_p_key, &header, &header_len);
+ if (bi->bi_state == NULL)
+ return FAIL;
+ len = (long)fwrite(header, (size_t)header_len, (size_t)1, fp);
+ vim_free(header);
+ if (len != 1)
+ {
+ crypt_free_state(bi->bi_state);
+ bi->bi_state = NULL;
+ return FAIL;
+ }
+
+ if (crypt_whole_undofile(crypt_get_method_nr(buf)))
+ {
+ bi->bi_buffer = alloc(CRYPT_BUF_SIZE);
+ if (bi->bi_buffer == NULL)
+ {
+ crypt_free_state(bi->bi_state);
+ bi->bi_state = NULL;
+ return FAIL;
+ }
+ bi->bi_used = 0;
+ }
+ }
+ else
+#endif
+ undo_write_bytes(bi, (long_u)UF_VERSION, 2);
+
+
+ /* Write a hash of the buffer text, so that we can verify it is still the
+ * same when reading the buffer text. */
+ if (undo_write(bi, hash, (size_t)UNDO_HASH_SIZE) == FAIL)
+ return FAIL;
+
+ /* buffer-specific data */
+ undo_write_bytes(bi, (long_u)buf->b_ml.ml_line_count, 4);
+ len = buf->b_u_line_ptr.ul_line == NULL
+ ? 0L : (long)STRLEN(buf->b_u_line_ptr.ul_line);
+ undo_write_bytes(bi, (long_u)len, 4);
+ if (len > 0 && fwrite_crypt(bi, buf->b_u_line_ptr.ul_line, (size_t)len)
+ == FAIL)
+ return FAIL;
+ undo_write_bytes(bi, (long_u)buf->b_u_line_lnum, 4);
+ undo_write_bytes(bi, (long_u)buf->b_u_line_colnr, 4);
+
+ /* Undo structures header data */
+ put_header_ptr(bi, buf->b_u_oldhead);
+ put_header_ptr(bi, buf->b_u_newhead);
+ put_header_ptr(bi, buf->b_u_curhead);
+
+ undo_write_bytes(bi, (long_u)buf->b_u_numhead, 4);
+ undo_write_bytes(bi, (long_u)buf->b_u_seq_last, 4);
+ undo_write_bytes(bi, (long_u)buf->b_u_seq_cur, 4);
+ time_to_bytes(buf->b_u_time_cur, time_buf);
+ undo_write(bi, time_buf, 8);
+
+ /* Optional fields. */
+ undo_write_bytes(bi, 4, 1);
+ undo_write_bytes(bi, UF_LAST_SAVE_NR, 1);
+ undo_write_bytes(bi, (long_u)buf->b_u_save_nr_last, 4);
+
+ undo_write_bytes(bi, 0, 1); /* end marker */
+
+ return OK;
+}
+
+ static int
+serialize_uhp(bufinfo_T *bi, u_header_T *uhp)
+{
+ int i;
+ u_entry_T *uep;
+ char_u time_buf[8];
+
+ if (undo_write_bytes(bi, (long_u)UF_HEADER_MAGIC, 2) == FAIL)
+ return FAIL;
+
+ put_header_ptr(bi, uhp->uh_next.ptr);
+ put_header_ptr(bi, uhp->uh_prev.ptr);
+ put_header_ptr(bi, uhp->uh_alt_next.ptr);
+ put_header_ptr(bi, uhp->uh_alt_prev.ptr);
+ undo_write_bytes(bi, uhp->uh_seq, 4);
+ serialize_pos(bi, uhp->uh_cursor);
+ undo_write_bytes(bi, (long_u)uhp->uh_cursor_vcol, 4);
+ undo_write_bytes(bi, (long_u)uhp->uh_flags, 2);
+ /* Assume NMARKS will stay the same. */
+ for (i = 0; i < NMARKS; ++i)
+ serialize_pos(bi, uhp->uh_namedm[i]);
+ serialize_visualinfo(bi, &uhp->uh_visual);
+ time_to_bytes(uhp->uh_time, time_buf);
+ undo_write(bi, time_buf, 8);
+
+ /* Optional fields. */
+ undo_write_bytes(bi, 4, 1);
+ undo_write_bytes(bi, UHP_SAVE_NR, 1);
+ undo_write_bytes(bi, (long_u)uhp->uh_save_nr, 4);
+
+ undo_write_bytes(bi, 0, 1); /* end marker */
+
+ /* Write all the entries. */
+ for (uep = uhp->uh_entry; uep != NULL; uep = uep->ue_next)
+ {
+ undo_write_bytes(bi, (long_u)UF_ENTRY_MAGIC, 2);
+ if (serialize_uep(bi, uep) == FAIL)
+ return FAIL;
+ }
+ undo_write_bytes(bi, (long_u)UF_ENTRY_END_MAGIC, 2);
+ return OK;
+}
+
+ static u_header_T *
+unserialize_uhp(bufinfo_T *bi, char_u *file_name)
+{
+ u_header_T *uhp;
+ int i;
+ u_entry_T *uep, *last_uep;
+ int c;
+ int error;
+
+ uhp = (u_header_T *)U_ALLOC_LINE(sizeof(u_header_T));
+ if (uhp == NULL)
+ return NULL;
+ vim_memset(uhp, 0, sizeof(u_header_T));
+#ifdef U_DEBUG
+ uhp->uh_magic = UH_MAGIC;
+#endif
+ uhp->uh_next.seq = undo_read_4c(bi);
+ uhp->uh_prev.seq = undo_read_4c(bi);
+ uhp->uh_alt_next.seq = undo_read_4c(bi);
+ uhp->uh_alt_prev.seq = undo_read_4c(bi);
+ uhp->uh_seq = undo_read_4c(bi);
+ if (uhp->uh_seq <= 0)
+ {
+ corruption_error("uh_seq", file_name);
+ vim_free(uhp);
+ return NULL;
+ }
+ unserialize_pos(bi, &uhp->uh_cursor);
+ uhp->uh_cursor_vcol = undo_read_4c(bi);
+ uhp->uh_flags = undo_read_2c(bi);
+ for (i = 0; i < NMARKS; ++i)
+ unserialize_pos(bi, &uhp->uh_namedm[i]);
+ unserialize_visualinfo(bi, &uhp->uh_visual);
+ uhp->uh_time = undo_read_time(bi);
+
+ /* Optional fields. */
+ for (;;)
+ {
+ int len = undo_read_byte(bi);
+ int what;
+
+ if (len == 0)
+ break;
+ what = undo_read_byte(bi);
+ switch (what)
+ {
+ case UHP_SAVE_NR:
+ uhp->uh_save_nr = undo_read_4c(bi);
+ break;
+ default:
+ /* field not supported, skip */
+ while (--len >= 0)
+ (void)undo_read_byte(bi);
+ }
+ }
+
+ /* Unserialize the uep list. */
+ last_uep = NULL;
+ while ((c = undo_read_2c(bi)) == UF_ENTRY_MAGIC)
+ {
+ error = FALSE;
+ uep = unserialize_uep(bi, &error, file_name);
+ if (last_uep == NULL)
+ uhp->uh_entry = uep;
+ else
+ last_uep->ue_next = uep;
+ last_uep = uep;
+ if (uep == NULL || error)
+ {
+ u_free_uhp(uhp);
+ return NULL;
+ }
+ }
+ if (c != UF_ENTRY_END_MAGIC)
+ {
+ corruption_error("entry end", file_name);
+ u_free_uhp(uhp);
+ return NULL;
+ }
+
+ return uhp;
+}
+
+/*
+ * Serialize "uep".
+ */
+ static int
+serialize_uep(
+ bufinfo_T *bi,
+ u_entry_T *uep)
+{
+ int i;
+ size_t len;
+
+ undo_write_bytes(bi, (long_u)uep->ue_top, 4);
+ undo_write_bytes(bi, (long_u)uep->ue_bot, 4);
+ undo_write_bytes(bi, (long_u)uep->ue_lcount, 4);
+ undo_write_bytes(bi, (long_u)uep->ue_size, 4);
+ for (i = 0; i < uep->ue_size; ++i)
+ {
+ // Text is written without the text properties, since we cannot restore
+ // the text property types.
+ len = STRLEN(uep->ue_array[i].ul_line);
+ if (undo_write_bytes(bi, (long_u)len, 4) == FAIL)
+ return FAIL;
+ if (len > 0 && fwrite_crypt(bi, uep->ue_array[i].ul_line, len) == FAIL)
+ return FAIL;
+ }
+ return OK;
+}
+
+ static u_entry_T *
+unserialize_uep(bufinfo_T *bi, int *error, char_u *file_name)
+{
+ int i;
+ u_entry_T *uep;
+ undoline_T *array = NULL;
+ char_u *line;
+ int line_len;
+
+ uep = (u_entry_T *)U_ALLOC_LINE(sizeof(u_entry_T));
+ if (uep == NULL)
+ return NULL;
+ vim_memset(uep, 0, sizeof(u_entry_T));
+#ifdef U_DEBUG
+ uep->ue_magic = UE_MAGIC;
+#endif
+ uep->ue_top = undo_read_4c(bi);
+ uep->ue_bot = undo_read_4c(bi);
+ uep->ue_lcount = undo_read_4c(bi);
+ uep->ue_size = undo_read_4c(bi);
+ if (uep->ue_size > 0)
+ {
+ if (uep->ue_size < LONG_MAX / (int)sizeof(char_u *))
+ array = (undoline_T *)U_ALLOC_LINE(sizeof(undoline_T) * uep->ue_size);
+ if (array == NULL)
+ {
+ *error = TRUE;
+ return uep;
+ }
+ vim_memset(array, 0, sizeof(undoline_T) * uep->ue_size);
+ }
+ uep->ue_array = array;
+
+ for (i = 0; i < uep->ue_size; ++i)
+ {
+ line_len = undo_read_4c(bi);
+ if (line_len >= 0)
+ line = read_string_decrypt(bi, line_len);
+ else
+ {
+ line = NULL;
+ corruption_error("line length", file_name);
+ }
+ if (line == NULL)
+ {
+ *error = TRUE;
+ return uep;
+ }
+ array[i].ul_line = line;
+ array[i].ul_len = line_len + 1;
+ }
+ return uep;
+}
+
+/*
+ * Serialize "pos".
+ */
+ static void
+serialize_pos(bufinfo_T *bi, pos_T pos)
+{
+ undo_write_bytes(bi, (long_u)pos.lnum, 4);
+ undo_write_bytes(bi, (long_u)pos.col, 4);
+ undo_write_bytes(bi, (long_u)pos.coladd, 4);
+}
+
+/*
+ * Unserialize the pos_T at the current position.
+ */
+ static void
+unserialize_pos(bufinfo_T *bi, pos_T *pos)
+{
+ pos->lnum = undo_read_4c(bi);
+ if (pos->lnum < 0)
+ pos->lnum = 0;
+ pos->col = undo_read_4c(bi);
+ if (pos->col < 0)
+ pos->col = 0;
+ pos->coladd = undo_read_4c(bi);
+ if (pos->coladd < 0)
+ pos->coladd = 0;
+}
+
+/*
+ * Serialize "info".
+ */
+ static void
+serialize_visualinfo(bufinfo_T *bi, visualinfo_T *info)
+{
+ serialize_pos(bi, info->vi_start);
+ serialize_pos(bi, info->vi_end);
+ undo_write_bytes(bi, (long_u)info->vi_mode, 4);
+ undo_write_bytes(bi, (long_u)info->vi_curswant, 4);
+}
+
+/*
+ * Unserialize the visualinfo_T at the current position.
+ */
+ static void
+unserialize_visualinfo(bufinfo_T *bi, visualinfo_T *info)
+{
+ unserialize_pos(bi, &info->vi_start);
+ unserialize_pos(bi, &info->vi_end);
+ info->vi_mode = undo_read_4c(bi);
+ info->vi_curswant = undo_read_4c(bi);
+}
+
+/*
+ * Write the undo tree in an undo file.
+ * When "name" is not NULL, use it as the name of the undo file.
+ * Otherwise use buf->b_ffname to generate the undo file name.
+ * "buf" must never be null, buf->b_ffname is used to obtain the original file
+ * permissions.
+ * "forceit" is TRUE for ":wundo!", FALSE otherwise.
+ * "hash[UNDO_HASH_SIZE]" must be the hash value of the buffer text.
+ */
+ void
+u_write_undo(
+ char_u *name,
+ int forceit,
+ buf_T *buf,
+ char_u *hash)
+{
+ u_header_T *uhp;
+ char_u *file_name;
+ int mark;
+#ifdef U_DEBUG
+ int headers_written = 0;
+#endif
+ int fd;
+ FILE *fp = NULL;
+ int perm;
+ int write_ok = FALSE;
+#ifdef UNIX
+ int st_old_valid = FALSE;
+ stat_T st_old;
+ stat_T st_new;
+#endif
+ bufinfo_T bi;
+
+ vim_memset(&bi, 0, sizeof(bi));
+
+ if (name == NULL)
+ {
+ file_name = u_get_undo_file_name(buf->b_ffname, FALSE);
+ if (file_name == NULL)
+ {
+ if (p_verbose > 0)
+ {
+ verbose_enter();
+ smsg(
+ _("Cannot write undo file in any directory in 'undodir'"));
+ verbose_leave();
+ }
+ return;
+ }
+ }
+ else
+ file_name = name;
+
+ /*
+ * Decide about the permission to use for the undo file. If the buffer
+ * has a name use the permission of the original file. Otherwise only
+ * allow the user to access the undo file.
+ */
+ perm = 0600;
+ if (buf->b_ffname != NULL)
+ {
+#ifdef UNIX
+ if (mch_stat((char *)buf->b_ffname, &st_old) >= 0)
+ {
+ perm = st_old.st_mode;
+ st_old_valid = TRUE;
+ }
+#else
+ perm = mch_getperm(buf->b_ffname);
+ if (perm < 0)
+ perm = 0600;
+#endif
+ }
+
+ /* strip any s-bit and executable bit */
+ perm = perm & 0666;
+
+ /* If the undo file already exists, verify that it actually is an undo
+ * file, and delete it. */
+ if (mch_getperm(file_name) >= 0)
+ {
+ if (name == NULL || !forceit)
+ {
+ /* Check we can read it and it's an undo file. */
+ fd = mch_open((char *)file_name, O_RDONLY|O_EXTRA, 0);
+ if (fd < 0)
+ {
+ if (name != NULL || p_verbose > 0)
+ {
+ if (name == NULL)
+ verbose_enter();
+ smsg(
+ _("Will not overwrite with undo file, cannot read: %s"),
+ file_name);
+ if (name == NULL)
+ verbose_leave();
+ }
+ goto theend;
+ }
+ else
+ {
+ char_u mbuf[UF_START_MAGIC_LEN];
+ int len;
+
+ len = read_eintr(fd, mbuf, UF_START_MAGIC_LEN);
+ close(fd);
+ if (len < UF_START_MAGIC_LEN
+ || memcmp(mbuf, UF_START_MAGIC, UF_START_MAGIC_LEN) != 0)
+ {
+ if (name != NULL || p_verbose > 0)
+ {
+ if (name == NULL)
+ verbose_enter();
+ smsg(
+ _("Will not overwrite, this is not an undo file: %s"),
+ file_name);
+ if (name == NULL)
+ verbose_leave();
+ }
+ goto theend;
+ }
+ }
+ }
+ mch_remove(file_name);
+ }
+
+ /* If there is no undo information at all, quit here after deleting any
+ * existing undo file. */
+ if (buf->b_u_numhead == 0 && buf->b_u_line_ptr.ul_line == NULL)
+ {
+ if (p_verbose > 0)
+ verb_msg(_("Skipping undo file write, nothing to undo"));
+ goto theend;
+ }
+
+ fd = mch_open((char *)file_name,
+ O_CREAT|O_EXTRA|O_WRONLY|O_EXCL|O_NOFOLLOW, perm);
+ if (fd < 0)
+ {
+ semsg(_(e_not_open), file_name);
+ goto theend;
+ }
+ (void)mch_setperm(file_name, perm);
+ if (p_verbose > 0)
+ {
+ verbose_enter();
+ smsg(_("Writing undo file: %s"), file_name);
+ verbose_leave();
+ }
+
+#ifdef U_DEBUG
+ /* Check there is no problem in undo info before writing. */
+ u_check(FALSE);
+#endif
+
+#ifdef UNIX
+ /*
+ * Try to set the group of the undo file same as the original file. If
+ * this fails, set the protection bits for the group same as the
+ * protection bits for others.
+ */
+ if (st_old_valid
+ && mch_stat((char *)file_name, &st_new) >= 0
+ && st_new.st_gid != st_old.st_gid
+# ifdef HAVE_FCHOWN /* sequent-ptx lacks fchown() */
+ && fchown(fd, (uid_t)-1, st_old.st_gid) != 0
+# endif
+ )
+ mch_setperm(file_name, (perm & 0707) | ((perm & 07) << 3));
+# if defined(HAVE_SELINUX) || defined(HAVE_SMACK)
+ if (buf->b_ffname != NULL)
+ mch_copy_sec(buf->b_ffname, file_name);
+# endif
+#endif
+
+ fp = fdopen(fd, "w");
+ if (fp == NULL)
+ {
+ semsg(_(e_not_open), file_name);
+ close(fd);
+ mch_remove(file_name);
+ goto theend;
+ }
+
+ /* Undo must be synced. */
+ u_sync(TRUE);
+
+ /*
+ * Write the header. Initializes encryption, if enabled.
+ */
+ bi.bi_buf = buf;
+ bi.bi_fp = fp;
+ if (serialize_header(&bi, hash) == FAIL)
+ goto write_error;
+
+ /*
+ * Iteratively serialize UHPs and their UEPs from the top down.
+ */
+ mark = ++lastmark;
+ uhp = buf->b_u_oldhead;
+ while (uhp != NULL)
+ {
+ /* Serialize current UHP if we haven't seen it */
+ if (uhp->uh_walk != mark)
+ {
+ uhp->uh_walk = mark;
+#ifdef U_DEBUG
+ ++headers_written;
+#endif
+ if (serialize_uhp(&bi, uhp) == FAIL)
+ goto write_error;
+ }
+
+ /* Now walk through the tree - algorithm from undo_time(). */
+ if (uhp->uh_prev.ptr != NULL && uhp->uh_prev.ptr->uh_walk != mark)
+ uhp = uhp->uh_prev.ptr;
+ else if (uhp->uh_alt_next.ptr != NULL
+ && uhp->uh_alt_next.ptr->uh_walk != mark)
+ uhp = uhp->uh_alt_next.ptr;
+ else if (uhp->uh_next.ptr != NULL && uhp->uh_alt_prev.ptr == NULL
+ && uhp->uh_next.ptr->uh_walk != mark)
+ uhp = uhp->uh_next.ptr;
+ else if (uhp->uh_alt_prev.ptr != NULL)
+ uhp = uhp->uh_alt_prev.ptr;
+ else
+ uhp = uhp->uh_next.ptr;
+ }
+
+ if (undo_write_bytes(&bi, (long_u)UF_HEADER_END_MAGIC, 2) == OK)
+ write_ok = TRUE;
+#ifdef U_DEBUG
+ if (headers_written != buf->b_u_numhead)
+ {
+ semsg("Written %ld headers, ...", headers_written);
+ semsg("... but numhead is %ld", buf->b_u_numhead);
+ }
+#endif
+
+#ifdef FEAT_CRYPT
+ if (bi.bi_state != NULL && undo_flush(&bi) == FAIL)
+ write_ok = FALSE;
+#endif
+
+write_error:
+ fclose(fp);
+ if (!write_ok)
+ semsg(_("E829: write error in undo file: %s"), file_name);
+
+#if defined(WIN3264)
+ /* Copy file attributes; for systems where this can only be done after
+ * closing the file. */
+ if (buf->b_ffname != NULL)
+ (void)mch_copy_file_attribute(buf->b_ffname, file_name);
+#endif
+#ifdef HAVE_ACL
+ if (buf->b_ffname != NULL)
+ {
+ vim_acl_T acl;
+
+ /* For systems that support ACL: get the ACL from the original file. */
+ acl = mch_get_acl(buf->b_ffname);
+ mch_set_acl(file_name, acl);
+ mch_free_acl(acl);
+ }
+#endif
+
+theend:
+#ifdef FEAT_CRYPT
+ if (bi.bi_state != NULL)
+ crypt_free_state(bi.bi_state);
+ vim_free(bi.bi_buffer);
+#endif
+ if (file_name != name)
+ vim_free(file_name);
+}
+
+/*
+ * Load the undo tree from an undo file.
+ * If "name" is not NULL use it as the undo file name. This also means being
+ * a bit more verbose.
+ * Otherwise use curbuf->b_ffname to generate the undo file name.
+ * "hash[UNDO_HASH_SIZE]" must be the hash value of the buffer text.
+ */
+ void
+u_read_undo(char_u *name, char_u *hash, char_u *orig_name)
+{
+ char_u *file_name;
+ FILE *fp;
+ long version, str_len;
+ undoline_T line_ptr;
+ linenr_T line_lnum;
+ colnr_T line_colnr;
+ linenr_T line_count;
+ long num_head = 0;
+ long old_header_seq, new_header_seq, cur_header_seq;
+ long seq_last, seq_cur;
+ long last_save_nr = 0;
+ short old_idx = -1, new_idx = -1, cur_idx = -1;
+ long num_read_uhps = 0;
+ time_t seq_time;
+ int i, j;
+ int c;
+ u_header_T *uhp;
+ u_header_T **uhp_table = NULL;
+ char_u read_hash[UNDO_HASH_SIZE];
+ char_u magic_buf[UF_START_MAGIC_LEN];
+#ifdef U_DEBUG
+ int *uhp_table_used;
+#endif
+#ifdef UNIX
+ stat_T st_orig;
+ stat_T st_undo;
+#endif
+ bufinfo_T bi;
+
+ vim_memset(&bi, 0, sizeof(bi));
+ line_ptr.ul_len = 0;
+ line_ptr.ul_line = NULL;
+
+ if (name == NULL)
+ {
+ file_name = u_get_undo_file_name(curbuf->b_ffname, TRUE);
+ if (file_name == NULL)
+ return;
+
+#ifdef UNIX
+ /* For safety we only read an undo file if the owner is equal to the
+ * owner of the text file or equal to the current user. */
+ if (mch_stat((char *)orig_name, &st_orig) >= 0
+ && mch_stat((char *)file_name, &st_undo) >= 0
+ && st_orig.st_uid != st_undo.st_uid
+ && st_undo.st_uid != getuid())
+ {
+ if (p_verbose > 0)
+ {
+ verbose_enter();
+ smsg(_("Not reading undo file, owner differs: %s"),
+ file_name);
+ verbose_leave();
+ }
+ return;
+ }
+#endif
+ }
+ else
+ file_name = name;
+
+ if (p_verbose > 0)
+ {
+ verbose_enter();
+ smsg(_("Reading undo file: %s"), file_name);
+ verbose_leave();
+ }
+
+ fp = mch_fopen((char *)file_name, "r");
+ if (fp == NULL)
+ {
+ if (name != NULL || p_verbose > 0)
+ semsg(_("E822: Cannot open undo file for reading: %s"), file_name);
+ goto error;
+ }
+ bi.bi_buf = curbuf;
+ bi.bi_fp = fp;
+
+ /*
+ * Read the undo file header.
+ */
+ if (fread(magic_buf, UF_START_MAGIC_LEN, 1, fp) != 1
+ || memcmp(magic_buf, UF_START_MAGIC, UF_START_MAGIC_LEN) != 0)
+ {
+ semsg(_("E823: Not an undo file: %s"), file_name);
+ goto error;
+ }
+ version = get2c(fp);
+ if (version == UF_VERSION_CRYPT)
+ {
+#ifdef FEAT_CRYPT
+ if (*curbuf->b_p_key == NUL)
+ {
+ semsg(_("E832: Non-encrypted file has encrypted undo file: %s"),
+ file_name);
+ goto error;
+ }
+ bi.bi_state = crypt_create_from_file(fp, curbuf->b_p_key);
+ if (bi.bi_state == NULL)
+ {
+ semsg(_("E826: Undo file decryption failed: %s"), file_name);
+ goto error;
+ }
+ if (crypt_whole_undofile(bi.bi_state->method_nr))
+ {
+ bi.bi_buffer = alloc(CRYPT_BUF_SIZE);
+ if (bi.bi_buffer == NULL)
+ {
+ crypt_free_state(bi.bi_state);
+ bi.bi_state = NULL;
+ goto error;
+ }
+ bi.bi_avail = 0;
+ bi.bi_used = 0;
+ }
+#else
+ semsg(_("E827: Undo file is encrypted: %s"), file_name);
+ goto error;
+#endif
+ }
+ else if (version != UF_VERSION)
+ {
+ semsg(_("E824: Incompatible undo file: %s"), file_name);
+ goto error;
+ }
+
+ if (undo_read(&bi, read_hash, (size_t)UNDO_HASH_SIZE) == FAIL)
+ {
+ corruption_error("hash", file_name);
+ goto error;
+ }
+ line_count = (linenr_T)undo_read_4c(&bi);
+ if (memcmp(hash, read_hash, UNDO_HASH_SIZE) != 0
+ || line_count != curbuf->b_ml.ml_line_count)
+ {
+ if (p_verbose > 0 || name != NULL)
+ {
+ if (name == NULL)
+ verbose_enter();
+ give_warning((char_u *)
+ _("File contents changed, cannot use undo info"), TRUE);
+ if (name == NULL)
+ verbose_leave();
+ }
+ goto error;
+ }
+
+ /* Read undo data for "U" command. */
+ str_len = undo_read_4c(&bi);
+ if (str_len < 0)
+ goto error;
+ if (str_len > 0)
+ {
+ line_ptr.ul_line = read_string_decrypt(&bi, str_len);
+ line_ptr.ul_len = str_len + 1;
+ }
+ line_lnum = (linenr_T)undo_read_4c(&bi);
+ line_colnr = (colnr_T)undo_read_4c(&bi);
+ if (line_lnum < 0 || line_colnr < 0)
+ {
+ corruption_error("line lnum/col", file_name);
+ goto error;
+ }
+
+ /* Begin general undo data */
+ old_header_seq = undo_read_4c(&bi);
+ new_header_seq = undo_read_4c(&bi);
+ cur_header_seq = undo_read_4c(&bi);
+ num_head = undo_read_4c(&bi);
+ seq_last = undo_read_4c(&bi);
+ seq_cur = undo_read_4c(&bi);
+ seq_time = undo_read_time(&bi);
+
+ /* Optional header fields. */
+ for (;;)
+ {
+ int len = undo_read_byte(&bi);
+ int what;
+
+ if (len == 0 || len == EOF)
+ break;
+ what = undo_read_byte(&bi);
+ switch (what)
+ {
+ case UF_LAST_SAVE_NR:
+ last_save_nr = undo_read_4c(&bi);
+ break;
+ default:
+ /* field not supported, skip */
+ while (--len >= 0)
+ (void)undo_read_byte(&bi);
+ }
+ }
+
+ /* uhp_table will store the freshly created undo headers we allocate
+ * until we insert them into curbuf. The table remains sorted by the
+ * sequence numbers of the headers.
+ * When there are no headers uhp_table is NULL. */
+ if (num_head > 0)
+ {
+ if (num_head < LONG_MAX / (long)sizeof(u_header_T *))
+ uhp_table = (u_header_T **)U_ALLOC_LINE(
+ num_head * sizeof(u_header_T *));
+ if (uhp_table == NULL)
+ goto error;
+ }
+
+ while ((c = undo_read_2c(&bi)) == UF_HEADER_MAGIC)
+ {
+ if (num_read_uhps >= num_head)
+ {
+ corruption_error("num_head too small", file_name);
+ goto error;
+ }
+
+ uhp = unserialize_uhp(&bi, file_name);
+ if (uhp == NULL)
+ goto error;
+ uhp_table[num_read_uhps++] = uhp;
+ }
+
+ if (num_read_uhps != num_head)
+ {
+ corruption_error("num_head", file_name);
+ goto error;
+ }
+ if (c != UF_HEADER_END_MAGIC)
+ {
+ corruption_error("end marker", file_name);
+ goto error;
+ }
+
+#ifdef U_DEBUG
+ uhp_table_used = (int *)alloc_clear(
+ (unsigned)(sizeof(int) * num_head + 1));
+# define SET_FLAG(j) ++uhp_table_used[j]
+#else
+# define SET_FLAG(j)
+#endif
+
+ /* We have put all of the headers into a table. Now we iterate through the
+ * table and swizzle each sequence number we have stored in uh_*_seq into
+ * a pointer corresponding to the header with that sequence number. */
+ for (i = 0; i < num_head; i++)
+ {
+ uhp = uhp_table[i];
+ if (uhp == NULL)
+ continue;
+ for (j = 0; j < num_head; j++)
+ if (uhp_table[j] != NULL && i != j
+ && uhp_table[i]->uh_seq == uhp_table[j]->uh_seq)
+ {
+ corruption_error("duplicate uh_seq", file_name);
+ goto error;
+ }
+ for (j = 0; j < num_head; j++)
+ if (uhp_table[j] != NULL
+ && uhp_table[j]->uh_seq == uhp->uh_next.seq)
+ {
+ uhp->uh_next.ptr = uhp_table[j];
+ SET_FLAG(j);
+ break;
+ }
+ for (j = 0; j < num_head; j++)
+ if (uhp_table[j] != NULL
+ && uhp_table[j]->uh_seq == uhp->uh_prev.seq)
+ {
+ uhp->uh_prev.ptr = uhp_table[j];
+ SET_FLAG(j);
+ break;
+ }
+ for (j = 0; j < num_head; j++)
+ if (uhp_table[j] != NULL
+ && uhp_table[j]->uh_seq == uhp->uh_alt_next.seq)
+ {
+ uhp->uh_alt_next.ptr = uhp_table[j];
+ SET_FLAG(j);
+ break;
+ }
+ for (j = 0; j < num_head; j++)
+ if (uhp_table[j] != NULL
+ && uhp_table[j]->uh_seq == uhp->uh_alt_prev.seq)
+ {
+ uhp->uh_alt_prev.ptr = uhp_table[j];
+ SET_FLAG(j);
+ break;
+ }
+ if (old_header_seq > 0 && old_idx < 0 && uhp->uh_seq == old_header_seq)
+ {
+ old_idx = i;
+ SET_FLAG(i);
+ }
+ if (new_header_seq > 0 && new_idx < 0 && uhp->uh_seq == new_header_seq)
+ {
+ new_idx = i;
+ SET_FLAG(i);
+ }
+ if (cur_header_seq > 0 && cur_idx < 0 && uhp->uh_seq == cur_header_seq)
+ {
+ cur_idx = i;
+ SET_FLAG(i);
+ }
+ }
+
+ /* Now that we have read the undo info successfully, free the current undo
+ * info and use the info from the file. */
+ u_blockfree(curbuf);
+ curbuf->b_u_oldhead = old_idx < 0 ? NULL : uhp_table[old_idx];
+ curbuf->b_u_newhead = new_idx < 0 ? NULL : uhp_table[new_idx];
+ curbuf->b_u_curhead = cur_idx < 0 ? NULL : uhp_table[cur_idx];
+ curbuf->b_u_line_ptr = line_ptr;
+ curbuf->b_u_line_lnum = line_lnum;
+ curbuf->b_u_line_colnr = line_colnr;
+ curbuf->b_u_numhead = num_head;
+ curbuf->b_u_seq_last = seq_last;
+ curbuf->b_u_seq_cur = seq_cur;
+ curbuf->b_u_time_cur = seq_time;
+ curbuf->b_u_save_nr_last = last_save_nr;
+ curbuf->b_u_save_nr_cur = last_save_nr;
+
+ curbuf->b_u_synced = TRUE;
+ vim_free(uhp_table);
+
+#ifdef U_DEBUG
+ for (i = 0; i < num_head; ++i)
+ if (uhp_table_used[i] == 0)
+ semsg("uhp_table entry %ld not used, leaking memory", i);
+ vim_free(uhp_table_used);
+ u_check(TRUE);
+#endif
+
+ if (name != NULL)
+ smsg(_("Finished reading undo file %s"), file_name);
+ goto theend;
+
+error:
+ vim_free(line_ptr.ul_line);
+ if (uhp_table != NULL)
+ {
+ for (i = 0; i < num_read_uhps; i++)
+ if (uhp_table[i] != NULL)
+ u_free_uhp(uhp_table[i]);
+ vim_free(uhp_table);
+ }
+
+theend:
+#ifdef FEAT_CRYPT
+ if (bi.bi_state != NULL)
+ crypt_free_state(bi.bi_state);
+ vim_free(bi.bi_buffer);
+#endif
+ if (fp != NULL)
+ fclose(fp);
+ if (file_name != name)
+ vim_free(file_name);
+ return;
+}
+
+#endif /* FEAT_PERSISTENT_UNDO */
+
+
+/*
+ * If 'cpoptions' contains 'u': Undo the previous undo or redo (vi compatible).
+ * If 'cpoptions' does not contain 'u': Always undo.
+ */
+ void
+u_undo(int count)
+{
+ /*
+ * If we get an undo command while executing a macro, we behave like the
+ * original vi. If this happens twice in one macro the result will not
+ * be compatible.
+ */
+ if (curbuf->b_u_synced == FALSE)
+ {
+ u_sync(TRUE);
+ count = 1;
+ }
+
+ if (vim_strchr(p_cpo, CPO_UNDO) == NULL)
+ undo_undoes = TRUE;
+ else
+ undo_undoes = !undo_undoes;
+ u_doit(count);
+}
+
+/*
+ * If 'cpoptions' contains 'u': Repeat the previous undo or redo.
+ * If 'cpoptions' does not contain 'u': Always redo.
+ */
+ void
+u_redo(int count)
+{
+ if (vim_strchr(p_cpo, CPO_UNDO) == NULL)
+ undo_undoes = FALSE;
+ u_doit(count);
+}
+
+/*
+ * Undo or redo, depending on 'undo_undoes', 'count' times.
+ */
+ static void
+u_doit(int startcount)
+{
+ int count = startcount;
+
+ if (!undo_allowed())
+ return;
+
+ u_newcount = 0;
+ u_oldcount = 0;
+ if (curbuf->b_ml.ml_flags & ML_EMPTY)
+ u_oldcount = -1;
+ while (count--)
+ {
+ /* Do the change warning now, so that it triggers FileChangedRO when
+ * needed. This may cause the file to be reloaded, that must happen
+ * before we do anything, because it may change curbuf->b_u_curhead
+ * and more. */
+ change_warning(0);
+
+ if (undo_undoes)
+ {
+ if (curbuf->b_u_curhead == NULL) /* first undo */
+ curbuf->b_u_curhead = curbuf->b_u_newhead;
+ else if (get_undolevel() > 0) /* multi level undo */
+ /* get next undo */
+ curbuf->b_u_curhead = curbuf->b_u_curhead->uh_next.ptr;
+ /* nothing to undo */
+ if (curbuf->b_u_numhead == 0 || curbuf->b_u_curhead == NULL)
+ {
+ /* stick curbuf->b_u_curhead at end */
+ curbuf->b_u_curhead = curbuf->b_u_oldhead;
+ beep_flush();
+ if (count == startcount - 1)
+ {
+ msg(_("Already at oldest change"));
+ return;
+ }
+ break;
+ }
+
+ u_undoredo(TRUE);
+ }
+ else
+ {
+ if (curbuf->b_u_curhead == NULL || get_undolevel() <= 0)
+ {
+ beep_flush(); /* nothing to redo */
+ if (count == startcount - 1)
+ {
+ msg(_("Already at newest change"));
+ return;
+ }
+ break;
+ }
+
+ u_undoredo(FALSE);
+
+ /* Advance for next redo. Set "newhead" when at the end of the
+ * redoable changes. */
+ if (curbuf->b_u_curhead->uh_prev.ptr == NULL)
+ curbuf->b_u_newhead = curbuf->b_u_curhead;
+ curbuf->b_u_curhead = curbuf->b_u_curhead->uh_prev.ptr;
+ }
+ }
+ u_undo_end(undo_undoes, FALSE);
+}
+
+/*
+ * Undo or redo over the timeline.
+ * When "step" is negative go back in time, otherwise goes forward in time.
+ * When "sec" is FALSE make "step" steps, when "sec" is TRUE use "step" as
+ * seconds.
+ * When "file" is TRUE use "step" as a number of file writes.
+ * When "absolute" is TRUE use "step" as the sequence number to jump to.
+ * "sec" must be FALSE then.
+ */
+ void
+undo_time(
+ long step,
+ int sec,
+ int file,
+ int absolute)
+{
+ long target;
+ long closest;
+ long closest_start;
+ long closest_seq = 0;
+ long val;
+ u_header_T *uhp = NULL;
+ u_header_T *last;
+ int mark;
+ int nomark;
+ int round;
+ int dosec = sec;
+ int dofile = file;
+ int above = FALSE;
+ int did_undo = TRUE;
+
+ /* First make sure the current undoable change is synced. */
+ if (curbuf->b_u_synced == FALSE)
+ u_sync(TRUE);
+
+ u_newcount = 0;
+ u_oldcount = 0;
+ if (curbuf->b_ml.ml_flags & ML_EMPTY)
+ u_oldcount = -1;
+
+ /* "target" is the node below which we want to be.
+ * Init "closest" to a value we can't reach. */
+ if (absolute)
+ {
+ target = step;
+ closest = -1;
+ }
+ else
+ {
+ if (dosec)
+ target = (long)(curbuf->b_u_time_cur) + step;
+ else if (dofile)
+ {
+ if (step < 0)
+ {
+ /* Going back to a previous write. If there were changes after
+ * the last write, count that as moving one file-write, so
+ * that ":earlier 1f" undoes all changes since the last save. */
+ uhp = curbuf->b_u_curhead;
+ if (uhp != NULL)
+ uhp = uhp->uh_next.ptr;
+ else
+ uhp = curbuf->b_u_newhead;
+ if (uhp != NULL && uhp->uh_save_nr != 0)
+ /* "uh_save_nr" was set in the last block, that means
+ * there were no changes since the last write */
+ target = curbuf->b_u_save_nr_cur + step;
+ else
+ /* count the changes since the last write as one step */
+ target = curbuf->b_u_save_nr_cur + step + 1;
+ if (target <= 0)
+ /* Go to before first write: before the oldest change. Use
+ * the sequence number for that. */
+ dofile = FALSE;
+ }
+ else
+ {
+ /* Moving forward to a newer write. */
+ target = curbuf->b_u_save_nr_cur + step;
+ if (target > curbuf->b_u_save_nr_last)
+ {
+ /* Go to after last write: after the latest change. Use
+ * the sequence number for that. */
+ target = curbuf->b_u_seq_last + 1;
+ dofile = FALSE;
+ }
+ }
+ }
+ else
+ target = curbuf->b_u_seq_cur + step;
+ if (step < 0)
+ {
+ if (target < 0)
+ target = 0;
+ closest = -1;
+ }
+ else
+ {
+ if (dosec)
+ closest = (long)(vim_time() + 1);
+ else if (dofile)
+ closest = curbuf->b_u_save_nr_last + 2;
+ else
+ closest = curbuf->b_u_seq_last + 2;
+ if (target >= closest)
+ target = closest - 1;
+ }
+ }
+ closest_start = closest;
+ closest_seq = curbuf->b_u_seq_cur;
+
+ /* When "target" is 0; Back to origin. */
+ if (target == 0)
+ {
+ mark = lastmark; /* avoid that GCC complains */
+ goto target_zero;
+ }
+
+ /*
+ * May do this twice:
+ * 1. Search for "target", update "closest" to the best match found.
+ * 2. If "target" not found search for "closest".
+ *
+ * When using the closest time we use the sequence number in the second
+ * round, because there may be several entries with the same time.
+ */
+ for (round = 1; round <= 2; ++round)
+ {
+ /* Find the path from the current state to where we want to go. The
+ * desired state can be anywhere in the undo tree, need to go all over
+ * it. We put "nomark" in uh_walk where we have been without success,
+ * "mark" where it could possibly be. */
+ mark = ++lastmark;
+ nomark = ++lastmark;
+
+ if (curbuf->b_u_curhead == NULL) /* at leaf of the tree */
+ uhp = curbuf->b_u_newhead;
+ else
+ uhp = curbuf->b_u_curhead;
+
+ while (uhp != NULL)
+ {
+ uhp->uh_walk = mark;
+ if (dosec)
+ val = (long)(uhp->uh_time);
+ else if (dofile)
+ val = uhp->uh_save_nr;
+ else
+ val = uhp->uh_seq;
+
+ if (round == 1 && !(dofile && val == 0))
+ {
+ /* Remember the header that is closest to the target.
+ * It must be at least in the right direction (checked with
+ * "b_u_seq_cur"). When the timestamp is equal find the
+ * highest/lowest sequence number. */
+ if ((step < 0 ? uhp->uh_seq <= curbuf->b_u_seq_cur
+ : uhp->uh_seq > curbuf->b_u_seq_cur)
+ && ((dosec && val == closest)
+ ? (step < 0
+ ? uhp->uh_seq < closest_seq
+ : uhp->uh_seq > closest_seq)
+ : closest == closest_start
+ || (val > target
+ ? (closest > target
+ ? val - target <= closest - target
+ : val - target <= target - closest)
+ : (closest > target
+ ? target - val <= closest - target
+ : target - val <= target - closest))))
+ {
+ closest = val;
+ closest_seq = uhp->uh_seq;
+ }
+ }
+
+ /* Quit searching when we found a match. But when searching for a
+ * time we need to continue looking for the best uh_seq. */
+ if (target == val && !dosec)
+ {
+ target = uhp->uh_seq;
+ break;
+ }
+
+ /* go down in the tree if we haven't been there */
+ if (uhp->uh_prev.ptr != NULL && uhp->uh_prev.ptr->uh_walk != nomark
+ && uhp->uh_prev.ptr->uh_walk != mark)
+ uhp = uhp->uh_prev.ptr;
+
+ /* go to alternate branch if we haven't been there */
+ else if (uhp->uh_alt_next.ptr != NULL
+ && uhp->uh_alt_next.ptr->uh_walk != nomark
+ && uhp->uh_alt_next.ptr->uh_walk != mark)
+ uhp = uhp->uh_alt_next.ptr;
+
+ /* go up in the tree if we haven't been there and we are at the
+ * start of alternate branches */
+ else if (uhp->uh_next.ptr != NULL && uhp->uh_alt_prev.ptr == NULL
+ && uhp->uh_next.ptr->uh_walk != nomark
+ && uhp->uh_next.ptr->uh_walk != mark)
+ {
+ /* If still at the start we don't go through this change. */
+ if (uhp == curbuf->b_u_curhead)
+ uhp->uh_walk = nomark;
+ uhp = uhp->uh_next.ptr;
+ }
+
+ else
+ {
+ /* need to backtrack; mark this node as useless */
+ uhp->uh_walk = nomark;
+ if (uhp->uh_alt_prev.ptr != NULL)
+ uhp = uhp->uh_alt_prev.ptr;
+ else
+ uhp = uhp->uh_next.ptr;
+ }
+ }
+
+ if (uhp != NULL) /* found it */
+ break;
+
+ if (absolute)
+ {
+ semsg(_("E830: Undo number %ld not found"), step);
+ return;
+ }
+
+ if (closest == closest_start)
+ {
+ if (step < 0)
+ msg(_("Already at oldest change"));
+ else
+ msg(_("Already at newest change"));
+ return;
+ }
+
+ target = closest_seq;
+ dosec = FALSE;
+ dofile = FALSE;
+ if (step < 0)
+ above = TRUE; /* stop above the header */
+ }
+
+target_zero:
+ /* If we found it: Follow the path to go to where we want to be. */
+ if (uhp != NULL || target == 0)
+ {
+ /*
+ * First go up the tree as much as needed.
+ */
+ while (!got_int)
+ {
+ /* Do the change warning now, for the same reason as above. */
+ change_warning(0);
+
+ uhp = curbuf->b_u_curhead;
+ if (uhp == NULL)
+ uhp = curbuf->b_u_newhead;
+ else
+ uhp = uhp->uh_next.ptr;
+ if (uhp == NULL || (target > 0 && uhp->uh_walk != mark)
+ || (uhp->uh_seq == target && !above))
+ break;
+ curbuf->b_u_curhead = uhp;
+ u_undoredo(TRUE);
+ if (target > 0)
+ uhp->uh_walk = nomark; /* don't go back down here */
+ }
+
+ /* When back to origin, redo is not needed. */
+ if (target > 0)
+ {
+ /*
+ * And now go down the tree (redo), branching off where needed.
+ */
+ while (!got_int)
+ {
+ /* Do the change warning now, for the same reason as above. */
+ change_warning(0);
+
+ uhp = curbuf->b_u_curhead;
+ if (uhp == NULL)
+ break;
+
+ /* Go back to the first branch with a mark. */
+ while (uhp->uh_alt_prev.ptr != NULL
+ && uhp->uh_alt_prev.ptr->uh_walk == mark)
+ uhp = uhp->uh_alt_prev.ptr;
+
+ /* Find the last branch with a mark, that's the one. */
+ last = uhp;
+ while (last->uh_alt_next.ptr != NULL
+ && last->uh_alt_next.ptr->uh_walk == mark)
+ last = last->uh_alt_next.ptr;
+ if (last != uhp)
+ {
+ /* Make the used branch the first entry in the list of
+ * alternatives to make "u" and CTRL-R take this branch. */
+ while (uhp->uh_alt_prev.ptr != NULL)
+ uhp = uhp->uh_alt_prev.ptr;
+ if (last->uh_alt_next.ptr != NULL)
+ last->uh_alt_next.ptr->uh_alt_prev.ptr =
+ last->uh_alt_prev.ptr;
+ last->uh_alt_prev.ptr->uh_alt_next.ptr =
+ last->uh_alt_next.ptr;
+ last->uh_alt_prev.ptr = NULL;
+ last->uh_alt_next.ptr = uhp;
+ uhp->uh_alt_prev.ptr = last;
+
+ if (curbuf->b_u_oldhead == uhp)
+ curbuf->b_u_oldhead = last;
+ uhp = last;
+ if (uhp->uh_next.ptr != NULL)
+ uhp->uh_next.ptr->uh_prev.ptr = uhp;
+ }
+ curbuf->b_u_curhead = uhp;
+
+ if (uhp->uh_walk != mark)
+ break; /* must have reached the target */
+
+ /* Stop when going backwards in time and didn't find the exact
+ * header we were looking for. */
+ if (uhp->uh_seq == target && above)
+ {
+ curbuf->b_u_seq_cur = target - 1;
+ break;
+ }
+
+ u_undoredo(FALSE);
+
+ /* Advance "curhead" to below the header we last used. If it
+ * becomes NULL then we need to set "newhead" to this leaf. */
+ if (uhp->uh_prev.ptr == NULL)
+ curbuf->b_u_newhead = uhp;
+ curbuf->b_u_curhead = uhp->uh_prev.ptr;
+ did_undo = FALSE;
+
+ if (uhp->uh_seq == target) /* found it! */
+ break;
+
+ uhp = uhp->uh_prev.ptr;
+ if (uhp == NULL || uhp->uh_walk != mark)
+ {
+ /* Need to redo more but can't find it... */
+ internal_error("undo_time()");
+ break;
+ }
+ }
+ }
+ }
+ u_undo_end(did_undo, absolute);
+}
+
+/*
+ * u_undoredo: common code for undo and redo
+ *
+ * The lines in the file are replaced by the lines in the entry list at
+ * curbuf->b_u_curhead. The replaced lines in the file are saved in the entry
+ * list for the next undo/redo.
+ *
+ * When "undo" is TRUE we go up in the tree, when FALSE we go down.
+ */
+ static void
+u_undoredo(int undo)
+{
+ undoline_T *newarray = NULL;
+ linenr_T oldsize;
+ linenr_T newsize;
+ linenr_T top, bot;
+ linenr_T lnum;
+ linenr_T newlnum = MAXLNUM;
+ long i;
+ u_entry_T *uep, *nuep;
+ u_entry_T *newlist = NULL;
+ int old_flags;
+ int new_flags;
+ pos_T namedm[NMARKS];
+ visualinfo_T visualinfo;
+ int empty_buffer; /* buffer became empty */
+ u_header_T *curhead = curbuf->b_u_curhead;
+
+ /* Don't want autocommands using the undo structures here, they are
+ * invalid till the end. */
+ block_autocmds();
+
+#ifdef U_DEBUG
+ u_check(FALSE);
+#endif
+ old_flags = curhead->uh_flags;
+ new_flags = (curbuf->b_changed ? UH_CHANGED : 0) +
+ ((curbuf->b_ml.ml_flags & ML_EMPTY) ? UH_EMPTYBUF : 0);
+ setpcmark();
+
+ /*
+ * save marks before undo/redo
+ */
+ mch_memmove(namedm, curbuf->b_namedm, sizeof(pos_T) * NMARKS);
+ visualinfo = curbuf->b_visual;
+ curbuf->b_op_start.lnum = curbuf->b_ml.ml_line_count;
+ curbuf->b_op_start.col = 0;
+ curbuf->b_op_end.lnum = 0;
+ curbuf->b_op_end.col = 0;
+
+ for (uep = curhead->uh_entry; uep != NULL; uep = nuep)
+ {
+ top = uep->ue_top;
+ bot = uep->ue_bot;
+ if (bot == 0)
+ bot = curbuf->b_ml.ml_line_count + 1;
+ if (top > curbuf->b_ml.ml_line_count || top >= bot
+ || bot > curbuf->b_ml.ml_line_count + 1)
+ {
+ unblock_autocmds();
+ iemsg(_("E438: u_undo: line numbers wrong"));
+ changed(); /* don't want UNCHANGED now */
+ return;
+ }
+
+ oldsize = bot - top - 1; /* number of lines before undo */
+ newsize = uep->ue_size; /* number of lines after undo */
+
+ if (top < newlnum)
+ {
+ /* If the saved cursor is somewhere in this undo block, move it to
+ * the remembered position. Makes "gwap" put the cursor back
+ * where it was. */
+ lnum = curhead->uh_cursor.lnum;
+ if (lnum >= top && lnum <= top + newsize + 1)
+ {
+ curwin->w_cursor = curhead->uh_cursor;
+ newlnum = curwin->w_cursor.lnum - 1;
+ }
+ else
+ {
+ /* Use the first line that actually changed. Avoids that
+ * undoing auto-formatting puts the cursor in the previous
+ * line. */
+ for (i = 0; i < newsize && i < oldsize; ++i)
+ {
+ char_u *p = ml_get(top + 1 + i);
+
+ if (curbuf->b_ml.ml_line_len != uep->ue_array[i].ul_len
+ || memcmp(uep->ue_array[i].ul_line, p, curbuf->b_ml.ml_line_len) != 0)
+ break;
+ }
+ if (i == newsize && newlnum == MAXLNUM && uep->ue_next == NULL)
+ {
+ newlnum = top;
+ curwin->w_cursor.lnum = newlnum + 1;
+ }
+ else if (i < newsize)
+ {
+ newlnum = top + i;
+ curwin->w_cursor.lnum = newlnum + 1;
+ }
+ }
+ }
+
+ empty_buffer = FALSE;
+
+ /* delete the lines between top and bot and save them in newarray */
+ if (oldsize > 0)
+ {
+ if ((newarray = (undoline_T *)U_ALLOC_LINE(
+ sizeof(undoline_T) * oldsize)) == NULL)
+ {
+ do_outofmem_msg((long_u)(sizeof(undoline_T) * oldsize));
+ /*
+ * We have messed up the entry list, repair is impossible.
+ * we have to free the rest of the list.
+ */
+ while (uep != NULL)
+ {
+ nuep = uep->ue_next;
+ u_freeentry(uep, uep->ue_size);
+ uep = nuep;
+ }
+ break;
+ }
+ /* delete backwards, it goes faster in most cases */
+ for (lnum = bot - 1, i = oldsize; --i >= 0; --lnum)
+ {
+ /* what can we do when we run out of memory? */
+ if (u_save_line(&newarray[i], lnum) == FAIL)
+ do_outofmem_msg((long_u)0);
+ /* remember we deleted the last line in the buffer, and a
+ * dummy empty line will be inserted */
+ if (curbuf->b_ml.ml_line_count == 1)
+ empty_buffer = TRUE;
+ ml_delete(lnum, FALSE);
+ }
+ }
+ else
+ newarray = NULL;
+
+ /* insert the lines in u_array between top and bot */
+ if (newsize)
+ {
+ for (lnum = top, i = 0; i < newsize; ++i, ++lnum)
+ {
+ // If the file is empty, there is an empty line 1 that we
+ // should get rid of, by replacing it with the new line.
+ if (empty_buffer && lnum == 0)
+ ml_replace_len((linenr_T)1, uep->ue_array[i].ul_line, uep->ue_array[i].ul_len, TRUE, TRUE);
+ else
+ ml_append(lnum, uep->ue_array[i].ul_line, (colnr_T)uep->ue_array[i].ul_len, FALSE);
+ vim_free(uep->ue_array[i].ul_line);
+ }
+ vim_free((char_u *)uep->ue_array);
+ }
+
+ /* adjust marks */
+ if (oldsize != newsize)
+ {
+ mark_adjust(top + 1, top + oldsize, (long)MAXLNUM,
+ (long)newsize - (long)oldsize);
+ if (curbuf->b_op_start.lnum > top + oldsize)
+ curbuf->b_op_start.lnum += newsize - oldsize;
+ if (curbuf->b_op_end.lnum > top + oldsize)
+ curbuf->b_op_end.lnum += newsize - oldsize;
+ }
+
+ changed_lines(top + 1, 0, bot, newsize - oldsize);
+
+ /* set '[ and '] mark */
+ if (top + 1 < curbuf->b_op_start.lnum)
+ curbuf->b_op_start.lnum = top + 1;
+ if (newsize == 0 && top + 1 > curbuf->b_op_end.lnum)
+ curbuf->b_op_end.lnum = top + 1;
+ else if (top + newsize > curbuf->b_op_end.lnum)
+ curbuf->b_op_end.lnum = top + newsize;
+
+ u_newcount += newsize;
+ u_oldcount += oldsize;
+ uep->ue_size = oldsize;
+ uep->ue_array = newarray;
+ uep->ue_bot = top + newsize + 1;
+
+ /*
+ * insert this entry in front of the new entry list
+ */
+ nuep = uep->ue_next;
+ uep->ue_next = newlist;
+ newlist = uep;
+ }
+
+ curhead->uh_entry = newlist;
+ curhead->uh_flags = new_flags;
+ if ((old_flags & UH_EMPTYBUF) && BUFEMPTY())
+ curbuf->b_ml.ml_flags |= ML_EMPTY;
+ if (old_flags & UH_CHANGED)
+ changed();
+ else
+#ifdef FEAT_NETBEANS_INTG
+ /* per netbeans undo rules, keep it as modified */
+ if (!isNetbeansModified(curbuf))
+#endif
+ unchanged(curbuf, FALSE);
+
+ /*
+ * restore marks from before undo/redo
+ */
+ for (i = 0; i < NMARKS; ++i)
+ {
+ if (curhead->uh_namedm[i].lnum != 0)
+ curbuf->b_namedm[i] = curhead->uh_namedm[i];
+ if (namedm[i].lnum != 0)
+ curhead->uh_namedm[i] = namedm[i];
+ else
+ curhead->uh_namedm[i].lnum = 0;
+ }
+ if (curhead->uh_visual.vi_start.lnum != 0)
+ {
+ curbuf->b_visual = curhead->uh_visual;
+ curhead->uh_visual = visualinfo;
+ }
+
+ /*
+ * If the cursor is only off by one line, put it at the same position as
+ * before starting the change (for the "o" command).
+ * Otherwise the cursor should go to the first undone line.
+ */
+ if (curhead->uh_cursor.lnum + 1 == curwin->w_cursor.lnum
+ && curwin->w_cursor.lnum > 1)
+ --curwin->w_cursor.lnum;
+ if (curwin->w_cursor.lnum <= curbuf->b_ml.ml_line_count)
+ {
+ if (curhead->uh_cursor.lnum == curwin->w_cursor.lnum)
+ {
+ curwin->w_cursor.col = curhead->uh_cursor.col;
+ if (virtual_active() && curhead->uh_cursor_vcol >= 0)
+ coladvance((colnr_T)curhead->uh_cursor_vcol);
+ else
+ curwin->w_cursor.coladd = 0;
+ }
+ else
+ beginline(BL_SOL | BL_FIX);
+ }
+ else
+ {
+ /* We get here with the current cursor line being past the end (eg
+ * after adding lines at the end of the file, and then undoing it).
+ * check_cursor() will move the cursor to the last line. Move it to
+ * the first column here. */
+ curwin->w_cursor.col = 0;
+ curwin->w_cursor.coladd = 0;
+ }
+
+ /* Make sure the cursor is on an existing line and column. */
+ check_cursor();
+
+ /* Remember where we are for "g-" and ":earlier 10s". */
+ curbuf->b_u_seq_cur = curhead->uh_seq;
+ if (undo)
+ {
+ /* We are below the previous undo. However, to make ":earlier 1s"
+ * work we compute this as being just above the just undone change. */
+ if (curhead->uh_next.ptr != NULL)
+ curbuf->b_u_seq_cur = curhead->uh_next.ptr->uh_seq;
+ else
+ curbuf->b_u_seq_cur = 0;
+ }
+
+ /* Remember where we are for ":earlier 1f" and ":later 1f". */
+ if (curhead->uh_save_nr != 0)
+ {
+ if (undo)
+ curbuf->b_u_save_nr_cur = curhead->uh_save_nr - 1;
+ else
+ curbuf->b_u_save_nr_cur = curhead->uh_save_nr;
+ }
+
+ /* The timestamp can be the same for multiple changes, just use the one of
+ * the undone/redone change. */
+ curbuf->b_u_time_cur = curhead->uh_time;
+
+ unblock_autocmds();
+#ifdef U_DEBUG
+ u_check(FALSE);
+#endif
+}
+
+/*
+ * If we deleted or added lines, report the number of less/more lines.
+ * Otherwise, report the number of changes (this may be incorrect
+ * in some cases, but it's better than nothing).
+ */
+ static void
+u_undo_end(
+ int did_undo, /* just did an undo */
+ int absolute) /* used ":undo N" */
+{
+ char *msgstr;
+ u_header_T *uhp;
+ char_u msgbuf[80];
+
+#ifdef FEAT_FOLDING
+ if ((fdo_flags & FDO_UNDO) && KeyTyped)
+ foldOpenCursor();
+#endif
+
+ if (global_busy /* no messages now, wait until global is finished */
+ || !messaging()) /* 'lazyredraw' set, don't do messages now */
+ return;
+
+ if (curbuf->b_ml.ml_flags & ML_EMPTY)
+ --u_newcount;
+
+ u_oldcount -= u_newcount;
+ if (u_oldcount == -1)
+ msgstr = N_("more line");
+ else if (u_oldcount < 0)
+ msgstr = N_("more lines");
+ else if (u_oldcount == 1)
+ msgstr = N_("line less");
+ else if (u_oldcount > 1)
+ msgstr = N_("fewer lines");
+ else
+ {
+ u_oldcount = u_newcount;
+ if (u_newcount == 1)
+ msgstr = N_("change");
+ else
+ msgstr = N_("changes");
+ }
+
+ if (curbuf->b_u_curhead != NULL)
+ {
+ /* For ":undo N" we prefer a "after #N" message. */
+ if (absolute && curbuf->b_u_curhead->uh_next.ptr != NULL)
+ {
+ uhp = curbuf->b_u_curhead->uh_next.ptr;
+ did_undo = FALSE;
+ }
+ else if (did_undo)
+ uhp = curbuf->b_u_curhead;
+ else
+ uhp = curbuf->b_u_curhead->uh_next.ptr;
+ }
+ else
+ uhp = curbuf->b_u_newhead;
+
+ if (uhp == NULL)
+ *msgbuf = NUL;
+ else
+ u_add_time(msgbuf, sizeof(msgbuf), uhp->uh_time);
+
+#ifdef FEAT_CONCEAL
+ {
+ win_T *wp;
+
+ FOR_ALL_WINDOWS(wp)
+ {
+ if (wp->w_buffer == curbuf && wp->w_p_cole > 0)
+ redraw_win_later(wp, NOT_VALID);
+ }
+ }
+#endif
+
+ smsg_attr_keep(0, _("%ld %s; %s #%ld %s"),
+ u_oldcount < 0 ? -u_oldcount : u_oldcount,
+ _(msgstr),
+ did_undo ? _("before") : _("after"),
+ uhp == NULL ? 0L : uhp->uh_seq,
+ msgbuf);
+}
+
+/*
+ * u_sync: stop adding to the current entry list
+ */
+ void
+u_sync(
+ int force) /* Also sync when no_u_sync is set. */
+{
+ /* Skip it when already synced or syncing is disabled. */
+ if (curbuf->b_u_synced || (!force && no_u_sync > 0))
+ return;
+#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
+ if (p_imst == IM_ON_THE_SPOT && im_is_preediting())
+ return; /* XIM is busy, don't break an undo sequence */
+#endif
+ if (get_undolevel() < 0)
+ curbuf->b_u_synced = TRUE; /* no entries, nothing to do */
+ else
+ {
+ u_getbot(); /* compute ue_bot of previous u_save */
+ curbuf->b_u_curhead = NULL;
+ }
+}
+
+/*
+ * ":undolist": List the leafs of the undo tree
+ */
+ void
+ex_undolist(exarg_T *eap UNUSED)
+{
+ garray_T ga;
+ u_header_T *uhp;
+ int mark;
+ int nomark;
+ int changes = 1;
+ int i;
+
+ /*
+ * 1: walk the tree to find all leafs, put the info in "ga".
+ * 2: sort the lines
+ * 3: display the list
+ */
+ mark = ++lastmark;
+ nomark = ++lastmark;
+ ga_init2(&ga, (int)sizeof(char *), 20);
+
+ uhp = curbuf->b_u_oldhead;
+ while (uhp != NULL)
+ {
+ if (uhp->uh_prev.ptr == NULL && uhp->uh_walk != nomark
+ && uhp->uh_walk != mark)
+ {
+ if (ga_grow(&ga, 1) == FAIL)
+ break;
+ vim_snprintf((char *)IObuff, IOSIZE, "%6ld %7d ",
+ uhp->uh_seq, changes);
+ u_add_time(IObuff + STRLEN(IObuff), IOSIZE - STRLEN(IObuff),
+ uhp->uh_time);
+ if (uhp->uh_save_nr > 0)
+ {
+ while (STRLEN(IObuff) < 33)
+ STRCAT(IObuff, " ");
+ vim_snprintf_add((char *)IObuff, IOSIZE,
+ " %3ld", uhp->uh_save_nr);
+ }
+ ((char_u **)(ga.ga_data))[ga.ga_len++] = vim_strsave(IObuff);
+ }
+
+ uhp->uh_walk = mark;
+
+ /* go down in the tree if we haven't been there */
+ if (uhp->uh_prev.ptr != NULL && uhp->uh_prev.ptr->uh_walk != nomark
+ && uhp->uh_prev.ptr->uh_walk != mark)
+ {
+ uhp = uhp->uh_prev.ptr;
+ ++changes;
+ }
+
+ /* go to alternate branch if we haven't been there */
+ else if (uhp->uh_alt_next.ptr != NULL
+ && uhp->uh_alt_next.ptr->uh_walk != nomark
+ && uhp->uh_alt_next.ptr->uh_walk != mark)
+ uhp = uhp->uh_alt_next.ptr;
+
+ /* go up in the tree if we haven't been there and we are at the
+ * start of alternate branches */
+ else if (uhp->uh_next.ptr != NULL && uhp->uh_alt_prev.ptr == NULL
+ && uhp->uh_next.ptr->uh_walk != nomark
+ && uhp->uh_next.ptr->uh_walk != mark)
+ {
+ uhp = uhp->uh_next.ptr;
+ --changes;
+ }
+
+ else
+ {
+ /* need to backtrack; mark this node as done */
+ uhp->uh_walk = nomark;
+ if (uhp->uh_alt_prev.ptr != NULL)
+ uhp = uhp->uh_alt_prev.ptr;
+ else
+ {
+ uhp = uhp->uh_next.ptr;
+ --changes;
+ }
+ }
+ }
+
+ if (ga.ga_len == 0)
+ msg(_("Nothing to undo"));
+ else
+ {
+ sort_strings((char_u **)ga.ga_data, ga.ga_len);
+
+ msg_start();
+ msg_puts_attr(_("number changes when saved"),
+ HL_ATTR(HLF_T));
+ for (i = 0; i < ga.ga_len && !got_int; ++i)
+ {
+ msg_putchar('\n');
+ if (got_int)
+ break;
+ msg_puts(((char **)ga.ga_data)[i]);
+ }
+ msg_end();
+
+ ga_clear_strings(&ga);
+ }
+}
+
+/*
+ * Put the timestamp of an undo header in "buf[buflen]" in a nice format.
+ */
+ static void
+u_add_time(char_u *buf, size_t buflen, time_t tt)
+{
+#ifdef HAVE_STRFTIME
+ struct tm *curtime;
+
+ if (vim_time() - tt >= 100)
+ {
+ curtime = localtime(&tt);
+ if (vim_time() - tt < (60L * 60L * 12L))
+ /* within 12 hours */
+ (void)strftime((char *)buf, buflen, "%H:%M:%S", curtime);
+ else
+ /* longer ago */
+ (void)strftime((char *)buf, buflen, "%Y/%m/%d %H:%M:%S", curtime);
+ }
+ else
+#endif
+ {
+ long seconds = (long)(vim_time() - tt);
+
+ vim_snprintf((char *)buf, buflen,
+ NGETTEXT("%ld second ago", "%ld seconds ago", seconds),
+ seconds);
+ }
+}
+
+/*
+ * ":undojoin": continue adding to the last entry list
+ */
+ void
+ex_undojoin(exarg_T *eap UNUSED)
+{
+ if (curbuf->b_u_newhead == NULL)
+ return; /* nothing changed before */
+ if (curbuf->b_u_curhead != NULL)
+ {
+ emsg(_("E790: undojoin is not allowed after undo"));
+ return;
+ }
+ if (!curbuf->b_u_synced)
+ return; /* already unsynced */
+ if (get_undolevel() < 0)
+ return; /* no entries, nothing to do */
+ else
+ /* Append next change to the last entry */
+ curbuf->b_u_synced = FALSE;
+}
+
+/*
+ * Called after writing or reloading the file and setting b_changed to FALSE.
+ * Now an undo means that the buffer is modified.
+ */
+ void
+u_unchanged(buf_T *buf)
+{
+ u_unch_branch(buf->b_u_oldhead);
+ buf->b_did_warn = FALSE;
+}
+
+/*
+ * After reloading a buffer which was saved for 'undoreload': Find the first
+ * line that was changed and set the cursor there.
+ */
+ void
+u_find_first_changed(void)
+{
+ u_header_T *uhp = curbuf->b_u_newhead;
+ u_entry_T *uep;
+ linenr_T lnum;
+
+ if (curbuf->b_u_curhead != NULL || uhp == NULL)
+ return; /* undid something in an autocmd? */
+
+ /* Check that the last undo block was for the whole file. */
+ uep = uhp->uh_entry;
+ if (uep->ue_top != 0 || uep->ue_bot != 0)
+ return;
+
+ for (lnum = 1; lnum < curbuf->b_ml.ml_line_count
+ && lnum <= uep->ue_size; ++lnum)
+ {
+ char_u *p = ml_get_buf(curbuf, lnum, FALSE);
+
+ if (uep->ue_array[lnum - 1].ul_len != curbuf->b_ml.ml_line_len
+ || memcmp(p, uep->ue_array[lnum - 1].ul_line, uep->ue_array[lnum - 1].ul_len) != 0)
+ {
+ CLEAR_POS(&(uhp->uh_cursor));
+ uhp->uh_cursor.lnum = lnum;
+ return;
+ }
+ }
+ if (curbuf->b_ml.ml_line_count != uep->ue_size)
+ {
+ /* lines added or deleted at the end, put the cursor there */
+ CLEAR_POS(&(uhp->uh_cursor));
+ uhp->uh_cursor.lnum = lnum;
+ }
+}
+
+/*
+ * Increase the write count, store it in the last undo header, what would be
+ * used for "u".
+ */
+ void
+u_update_save_nr(buf_T *buf)
+{
+ u_header_T *uhp;
+
+ ++buf->b_u_save_nr_last;
+ buf->b_u_save_nr_cur = buf->b_u_save_nr_last;
+ uhp = buf->b_u_curhead;
+ if (uhp != NULL)
+ uhp = uhp->uh_next.ptr;
+ else
+ uhp = buf->b_u_newhead;
+ if (uhp != NULL)
+ uhp->uh_save_nr = buf->b_u_save_nr_last;
+}
+
+ static void
+u_unch_branch(u_header_T *uhp)
+{
+ u_header_T *uh;
+
+ for (uh = uhp; uh != NULL; uh = uh->uh_prev.ptr)
+ {
+ uh->uh_flags |= UH_CHANGED;
+ if (uh->uh_alt_next.ptr != NULL)
+ u_unch_branch(uh->uh_alt_next.ptr); /* recursive */
+ }
+}
+
+/*
+ * Get pointer to last added entry.
+ * If it's not valid, give an error message and return NULL.
+ */
+ static u_entry_T *
+u_get_headentry(void)
+{
+ if (curbuf->b_u_newhead == NULL || curbuf->b_u_newhead->uh_entry == NULL)
+ {
+ iemsg(_("E439: undo list corrupt"));
+ return NULL;
+ }
+ return curbuf->b_u_newhead->uh_entry;
+}
+
+/*
+ * u_getbot(): compute the line number of the previous u_save
+ * It is called only when b_u_synced is FALSE.
+ */
+ static void
+u_getbot(void)
+{
+ u_entry_T *uep;
+ linenr_T extra;
+
+ uep = u_get_headentry(); /* check for corrupt undo list */
+ if (uep == NULL)
+ return;
+
+ uep = curbuf->b_u_newhead->uh_getbot_entry;
+ if (uep != NULL)
+ {
+ /*
+ * the new ue_bot is computed from the number of lines that has been
+ * inserted (0 - deleted) since calling u_save. This is equal to the
+ * old line count subtracted from the current line count.
+ */
+ extra = curbuf->b_ml.ml_line_count - uep->ue_lcount;
+ uep->ue_bot = uep->ue_top + uep->ue_size + 1 + extra;
+ if (uep->ue_bot < 1 || uep->ue_bot > curbuf->b_ml.ml_line_count)
+ {
+ iemsg(_("E440: undo line missing"));
+ uep->ue_bot = uep->ue_top + 1; /* assume all lines deleted, will
+ * get all the old lines back
+ * without deleting the current
+ * ones */
+ }
+
+ curbuf->b_u_newhead->uh_getbot_entry = NULL;
+ }
+
+ curbuf->b_u_synced = TRUE;
+}
+
+/*
+ * Free one header "uhp" and its entry list and adjust the pointers.
+ */
+ static void
+u_freeheader(
+ buf_T *buf,
+ u_header_T *uhp,
+ u_header_T **uhpp) /* if not NULL reset when freeing this header */
+{
+ u_header_T *uhap;
+
+ /* When there is an alternate redo list free that branch completely,
+ * because we can never go there. */
+ if (uhp->uh_alt_next.ptr != NULL)
+ u_freebranch(buf, uhp->uh_alt_next.ptr, uhpp);
+
+ if (uhp->uh_alt_prev.ptr != NULL)
+ uhp->uh_alt_prev.ptr->uh_alt_next.ptr = NULL;
+
+ /* Update the links in the list to remove the header. */
+ if (uhp->uh_next.ptr == NULL)
+ buf->b_u_oldhead = uhp->uh_prev.ptr;
+ else
+ uhp->uh_next.ptr->uh_prev.ptr = uhp->uh_prev.ptr;
+
+ if (uhp->uh_prev.ptr == NULL)
+ buf->b_u_newhead = uhp->uh_next.ptr;
+ else
+ for (uhap = uhp->uh_prev.ptr; uhap != NULL;
+ uhap = uhap->uh_alt_next.ptr)
+ uhap->uh_next.ptr = uhp->uh_next.ptr;
+
+ u_freeentries(buf, uhp, uhpp);
+}
+
+/*
+ * Free an alternate branch and any following alternate branches.
+ */
+ static void
+u_freebranch(
+ buf_T *buf,
+ u_header_T *uhp,
+ u_header_T **uhpp) /* if not NULL reset when freeing this header */
+{
+ u_header_T *tofree, *next;
+
+ /* If this is the top branch we may need to use u_freeheader() to update
+ * all the pointers. */
+ if (uhp == buf->b_u_oldhead)
+ {
+ while (buf->b_u_oldhead != NULL)
+ u_freeheader(buf, buf->b_u_oldhead, uhpp);
+ return;
+ }
+
+ if (uhp->uh_alt_prev.ptr != NULL)
+ uhp->uh_alt_prev.ptr->uh_alt_next.ptr = NULL;
+
+ next = uhp;
+ while (next != NULL)
+ {
+ tofree = next;
+ if (tofree->uh_alt_next.ptr != NULL)
+ u_freebranch(buf, tofree->uh_alt_next.ptr, uhpp); /* recursive */
+ next = tofree->uh_prev.ptr;
+ u_freeentries(buf, tofree, uhpp);
+ }
+}
+
+/*
+ * Free all the undo entries for one header and the header itself.
+ * This means that "uhp" is invalid when returning.
+ */
+ static void
+u_freeentries(
+ buf_T *buf,
+ u_header_T *uhp,
+ u_header_T **uhpp) /* if not NULL reset when freeing this header */
+{
+ u_entry_T *uep, *nuep;
+
+ /* Check for pointers to the header that become invalid now. */
+ if (buf->b_u_curhead == uhp)
+ buf->b_u_curhead = NULL;
+ if (buf->b_u_newhead == uhp)
+ buf->b_u_newhead = NULL; /* freeing the newest entry */
+ if (uhpp != NULL && uhp == *uhpp)
+ *uhpp = NULL;
+
+ for (uep = uhp->uh_entry; uep != NULL; uep = nuep)
+ {
+ nuep = uep->ue_next;
+ u_freeentry(uep, uep->ue_size);
+ }
+
+#ifdef U_DEBUG
+ uhp->uh_magic = 0;
+#endif
+ vim_free((char_u *)uhp);
+ --buf->b_u_numhead;
+}
+
+/*
+ * free entry 'uep' and 'n' lines in uep->ue_array[]
+ */
+ static void
+u_freeentry(u_entry_T *uep, long n)
+{
+ while (n > 0)
+ vim_free(uep->ue_array[--n].ul_line);
+ vim_free((char_u *)uep->ue_array);
+#ifdef U_DEBUG
+ uep->ue_magic = 0;
+#endif
+ vim_free((char_u *)uep);
+}
+
+/*
+ * invalidate the undo buffer; called when storage has already been released
+ */
+ void
+u_clearall(buf_T *buf)
+{
+ buf->b_u_newhead = buf->b_u_oldhead = buf->b_u_curhead = NULL;
+ buf->b_u_synced = TRUE;
+ buf->b_u_numhead = 0;
+ buf->b_u_line_ptr.ul_line = NULL;
+ buf->b_u_line_ptr.ul_len = 0;
+ buf->b_u_line_lnum = 0;
+}
+
+/*
+ * Save the line "lnum" for the "U" command.
+ */
+ void
+u_saveline(linenr_T lnum)
+{
+ if (lnum == curbuf->b_u_line_lnum) /* line is already saved */
+ return;
+ if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count) /* should never happen */
+ return;
+ u_clearline();
+ curbuf->b_u_line_lnum = lnum;
+ if (curwin->w_cursor.lnum == lnum)
+ curbuf->b_u_line_colnr = curwin->w_cursor.col;
+ else
+ curbuf->b_u_line_colnr = 0;
+ if (u_save_line(&curbuf->b_u_line_ptr, lnum) == FAIL)
+ do_outofmem_msg((long_u)0);
+}
+
+/*
+ * clear the line saved for the "U" command
+ * (this is used externally for crossing a line while in insert mode)
+ */
+ void
+u_clearline(void)
+{
+ if (curbuf->b_u_line_ptr.ul_line != NULL)
+ {
+ VIM_CLEAR(curbuf->b_u_line_ptr.ul_line);
+ curbuf->b_u_line_ptr.ul_len = 0;
+ curbuf->b_u_line_lnum = 0;
+ }
+}
+
+/*
+ * Implementation of the "U" command.
+ * Differentiation from vi: "U" can be undone with the next "U".
+ * We also allow the cursor to be in another line.
+ * Careful: may trigger autocommands that reload the buffer.
+ */
+ void
+u_undoline(void)
+{
+ colnr_T t;
+ undoline_T oldp;
+
+ if (undo_off)
+ return;
+
+ if (curbuf->b_u_line_ptr.ul_line == NULL
+ || curbuf->b_u_line_lnum > curbuf->b_ml.ml_line_count)
+ {
+ beep_flush();
+ return;
+ }
+
+ // first save the line for the 'u' command
+ if (u_savecommon(curbuf->b_u_line_lnum - 1,
+ curbuf->b_u_line_lnum + 1, (linenr_T)0, FALSE) == FAIL)
+ return;
+ if (u_save_line(&oldp, curbuf->b_u_line_lnum) == FAIL)
+ {
+ do_outofmem_msg((long_u)0);
+ return;
+ }
+ ml_replace_len(curbuf->b_u_line_lnum, curbuf->b_u_line_ptr.ul_line, curbuf->b_u_line_ptr.ul_len, TRUE, FALSE);
+ changed_bytes(curbuf->b_u_line_lnum, 0);
+ curbuf->b_u_line_ptr = oldp;
+
+ t = curbuf->b_u_line_colnr;
+ if (curwin->w_cursor.lnum == curbuf->b_u_line_lnum)
+ curbuf->b_u_line_colnr = curwin->w_cursor.col;
+ curwin->w_cursor.col = t;
+ curwin->w_cursor.lnum = curbuf->b_u_line_lnum;
+ check_cursor_col();
+}
+
+/*
+ * Free all allocated memory blocks for the buffer 'buf'.
+ */
+ void
+u_blockfree(buf_T *buf)
+{
+ while (buf->b_u_oldhead != NULL)
+ u_freeheader(buf, buf->b_u_oldhead, NULL);
+ vim_free(buf->b_u_line_ptr.ul_line);
+}
+
+/*
+ * Check if the 'modified' flag is set, or 'ff' has changed (only need to
+ * check the first character, because it can only be "dos", "unix" or "mac").
+ * "nofile" and "scratch" type buffers are considered to always be unchanged.
+ * Also considers a buffer changed when a terminal window contains a running
+ * job.
+ */
+ int
+bufIsChanged(buf_T *buf)
+{
+#ifdef FEAT_TERMINAL
+ if (term_job_running(buf->b_term))
+ return TRUE;
+#endif
+ return bufIsChangedNotTerm(buf);
+}
+
+/*
+ * Like bufIsChanged() but ignoring a terminal window.
+ */
+ int
+bufIsChangedNotTerm(buf_T *buf)
+{
+ // In a "prompt" buffer we do respect 'modified', so that we can control
+ // closing the window by setting or resetting that option.
+ return (!bt_dontwrite(buf) || bt_prompt(buf))
+ && (buf->b_changed || file_ff_differs(buf, TRUE));
+}
+
+ int
+curbufIsChanged(void)
+{
+ return bufIsChanged(curbuf);
+}
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * For undotree(): Append the list of undo blocks at "first_uhp" to "list".
+ * Recursive.
+ */
+ void
+u_eval_tree(u_header_T *first_uhp, list_T *list)
+{
+ u_header_T *uhp = first_uhp;
+ dict_T *dict;
+
+ while (uhp != NULL)
+ {
+ dict = dict_alloc();
+ if (dict == NULL)
+ return;
+ dict_add_number(dict, "seq", uhp->uh_seq);
+ dict_add_number(dict, "time", (long)uhp->uh_time);
+ if (uhp == curbuf->b_u_newhead)
+ dict_add_number(dict, "newhead", 1);
+ if (uhp == curbuf->b_u_curhead)
+ dict_add_number(dict, "curhead", 1);
+ if (uhp->uh_save_nr > 0)
+ dict_add_number(dict, "save", uhp->uh_save_nr);
+
+ if (uhp->uh_alt_next.ptr != NULL)
+ {
+ list_T *alt_list = list_alloc();
+
+ if (alt_list != NULL)
+ {
+ /* Recursive call to add alternate undo tree. */
+ u_eval_tree(uhp->uh_alt_next.ptr, alt_list);
+ dict_add_list(dict, "alt", alt_list);
+ }
+ }
+
+ list_append_dict(list, dict);
+ uhp = uhp->uh_prev.ptr;
+ }
+}
+#endif
diff --git a/src/uninstal.c b/src/uninstal.c
new file mode 100644
index 0000000..11b6c62
--- /dev/null
+++ b/src/uninstal.c
@@ -0,0 +1,428 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * uninstal.c: Minimalistic uninstall program for Vim on MS-Windows
+ * Removes:
+ * - the "Edit with Vim" popup menu entry
+ * - the Vim "Open With..." popup menu entry
+ * - any Vim Batch files in the path
+ * - icons for Vim on the Desktop
+ * - the Vim entry in the Start Menu
+ */
+
+/* Include common code for dosinst.c and uninstal.c. */
+#include "dosinst.h"
+
+/*
+ * Return TRUE if the user types a 'y' or 'Y', FALSE otherwise.
+ */
+ static int
+confirm(void)
+{
+ char answer[10];
+
+ fflush(stdout);
+ return (scanf(" %c", answer) == 1 && toupper(answer[0]) == 'Y');
+}
+
+ static int
+reg_delete_key(HKEY hRootKey, const char *key, DWORD flag)
+{
+ static int did_load = FALSE;
+ static HANDLE advapi_lib = NULL;
+ static LONG (WINAPI *delete_key_ex)(HKEY, LPCTSTR, REGSAM, DWORD) = NULL;
+
+ if (!did_load)
+ {
+ /* The RegDeleteKeyEx() function is only available on new systems. It
+ * is required for 64-bit registry access. For other systems fall
+ * back to RegDeleteKey(). */
+ did_load = TRUE;
+ advapi_lib = LoadLibrary("ADVAPI32.DLL");
+ if (advapi_lib != NULL)
+ delete_key_ex = (LONG (WINAPI *)(HKEY, LPCTSTR, REGSAM, DWORD))GetProcAddress(advapi_lib, "RegDeleteKeyExA");
+ }
+ if (delete_key_ex != NULL) {
+ return (*delete_key_ex)(hRootKey, key, flag, 0);
+ }
+ return RegDeleteKey(hRootKey, key);
+}
+
+/*
+ * Check if the popup menu entry exists and what gvim it refers to.
+ * Returns non-zero when it's found.
+ */
+ static int
+popup_gvim_path(char *buf)
+{
+ HKEY key_handle;
+ DWORD value_type;
+ DWORD bufsize = BUFSIZE;
+ int r;
+
+ /* Open the key where the path to gvim.exe is stored. */
+ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Vim\\Gvim", 0,
+ KEY_WOW64_64KEY | KEY_READ, &key_handle) != ERROR_SUCCESS)
+ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Vim\\Gvim", 0,
+ KEY_WOW64_32KEY | KEY_READ, &key_handle) != ERROR_SUCCESS)
+ return 0;
+
+ /* get the DisplayName out of it to show the user */
+ r = RegQueryValueEx(key_handle, "path", 0,
+ &value_type, (LPBYTE)buf, &bufsize);
+ RegCloseKey(key_handle);
+
+ return (r == ERROR_SUCCESS);
+}
+
+/*
+ * Check if the "Open With..." menu entry exists and what gvim it refers to.
+ * Returns non-zero when it's found.
+ */
+ static int
+openwith_gvim_path(char *buf)
+{
+ HKEY key_handle;
+ DWORD value_type;
+ DWORD bufsize = BUFSIZE;
+ int r;
+
+ /* Open the key where the path to gvim.exe is stored. */
+ if (RegOpenKeyEx(HKEY_CLASSES_ROOT,
+ "Applications\\gvim.exe\\shell\\edit\\command", 0,
+ KEY_WOW64_64KEY | KEY_READ, &key_handle) != ERROR_SUCCESS)
+ return 0;
+
+ /* get the DisplayName out of it to show the user */
+ r = RegQueryValueEx(key_handle, "", 0, &value_type, (LPBYTE)buf, &bufsize);
+ RegCloseKey(key_handle);
+
+ return (r == ERROR_SUCCESS);
+}
+
+ static void
+remove_popup(void)
+{
+ int fail = 0;
+ int i;
+ int loop = is_64bit_os() ? 2 : 1;
+ int maxfail = loop * 6;
+ DWORD flag;
+ HKEY kh;
+
+ for (i = 0; i < loop; i++)
+ {
+ if (i == 0)
+ flag = KEY_WOW64_32KEY;
+ else
+ flag = KEY_WOW64_64KEY;
+
+ if (reg_delete_key(HKEY_CLASSES_ROOT, "CLSID\\{51EEE242-AD87-11d3-9C1E-0090278BBD99}\\InProcServer32", flag) != ERROR_SUCCESS)
+ ++fail;
+ if (reg_delete_key(HKEY_CLASSES_ROOT, "CLSID\\{51EEE242-AD87-11d3-9C1E-0090278BBD99}", flag) != ERROR_SUCCESS)
+ ++fail;
+ if (reg_delete_key(HKEY_CLASSES_ROOT, "*\\shellex\\ContextMenuHandlers\\gvim", flag) != ERROR_SUCCESS)
+ ++fail;
+ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved", 0,
+ flag | KEY_ALL_ACCESS, &kh) != ERROR_SUCCESS)
+ ++fail;
+ else
+ {
+ if (RegDeleteValue(kh, "{51EEE242-AD87-11d3-9C1E-0090278BBD99}") != ERROR_SUCCESS)
+ ++fail;
+ RegCloseKey(kh);
+ }
+ if (reg_delete_key(HKEY_LOCAL_MACHINE, "Software\\Vim\\Gvim", flag) != ERROR_SUCCESS)
+ ++fail;
+ if (reg_delete_key(HKEY_LOCAL_MACHINE, "Software\\Vim", flag) != ERROR_SUCCESS)
+ ++fail;
+ }
+
+ if (fail == maxfail)
+ printf("No Vim popup registry entries could be removed\n");
+ else if (fail > 0)
+ printf("Some Vim popup registry entries could not be removed\n");
+ else
+ printf("The Vim popup registry entries have been removed\n");
+}
+
+ static void
+remove_openwith(void)
+{
+ int fail = 0;
+ int i;
+ int loop = is_64bit_os() ? 2 : 1;
+ int maxfail = loop * 7;
+ DWORD flag;
+
+ for (i = 0; i < loop; i++)
+ {
+ if (i == 0)
+ flag = KEY_WOW64_32KEY;
+ else
+ flag = KEY_WOW64_64KEY;
+
+ if (reg_delete_key(HKEY_CLASSES_ROOT, "Applications\\gvim.exe\\shell\\edit\\command", flag) != ERROR_SUCCESS)
+ ++fail;
+ if (reg_delete_key(HKEY_CLASSES_ROOT, "Applications\\gvim.exe\\shell\\edit", flag) != ERROR_SUCCESS)
+ ++fail;
+ if (reg_delete_key(HKEY_CLASSES_ROOT, "Applications\\gvim.exe\\shell", flag) != ERROR_SUCCESS)
+ ++fail;
+ if (reg_delete_key(HKEY_CLASSES_ROOT, "Applications\\gvim.exe", flag) != ERROR_SUCCESS)
+ ++fail;
+ if (reg_delete_key(HKEY_CLASSES_ROOT, ".htm\\OpenWithList\\gvim.exe", flag) != ERROR_SUCCESS)
+ ++fail;
+ if (reg_delete_key(HKEY_CLASSES_ROOT, ".vim\\OpenWithList\\gvim.exe", flag) != ERROR_SUCCESS)
+ ++fail;
+ if (reg_delete_key(HKEY_CLASSES_ROOT, "*\\OpenWithList\\gvim.exe", flag) != ERROR_SUCCESS)
+ ++fail;
+ }
+
+ if (fail == maxfail)
+ printf("No Vim open-with registry entries could be removed\n");
+ else if (fail > 0)
+ printf("Some Vim open-with registry entries could not be removed\n");
+ else
+ printf("The Vim open-with registry entries have been removed\n");
+}
+
+/*
+ * Check if a batch file is really for the current version. Don't delete a
+ * batch file that was written for another (possibly newer) version.
+ */
+ static int
+batfile_thisversion(char *path)
+{
+ FILE *fd;
+ char line[BUFSIZE];
+ char *p;
+ int ver_len = strlen(VIM_VERSION_NODOT);
+ int found = FALSE;
+
+ fd = fopen(path, "r");
+ if (fd != NULL)
+ {
+ while (fgets(line, BUFSIZE, fd) != NULL)
+ {
+ for (p = line; *p != 0; ++p)
+ /* don't accept "vim60an" when looking for "vim60". */
+ if (strnicmp(p, VIM_VERSION_NODOT, ver_len) == 0
+ && !isdigit(p[ver_len])
+ && !isalpha(p[ver_len]))
+ {
+ found = TRUE;
+ break;
+ }
+ if (found)
+ break;
+ }
+ fclose(fd);
+ }
+ return found;
+}
+
+ static int
+remove_batfiles(int doit)
+{
+ char *batfile_path;
+ int i;
+ int found = 0;
+
+ for (i = 1; i < TARGET_COUNT; ++i)
+ {
+ batfile_path = searchpath_save(targets[i].batname);
+ if (batfile_path != NULL && batfile_thisversion(batfile_path))
+ {
+ ++found;
+ if (doit)
+ {
+ printf("removing %s\n", batfile_path);
+ remove(batfile_path);
+ }
+ else
+ printf(" - the batch file %s\n", batfile_path);
+ free(batfile_path);
+ }
+ }
+ return found;
+}
+
+ static void
+remove_if_exists(char *path, char *filename)
+{
+ char buf[BUFSIZE];
+ FILE *fd;
+
+ sprintf(buf, "%s\\%s", path, filename);
+
+ fd = fopen(buf, "r");
+ if (fd != NULL)
+ {
+ fclose(fd);
+ printf("removing %s\n", buf);
+ remove(buf);
+ }
+}
+
+ static void
+remove_icons(void)
+{
+ char path[BUFSIZE];
+ int i;
+
+ if (get_shell_folder_path(path, "desktop"))
+ for (i = 0; i < ICON_COUNT; ++i)
+ remove_if_exists(path, icon_link_names[i]);
+}
+
+ static void
+remove_start_menu(void)
+{
+ char path[BUFSIZE];
+ int i;
+ struct stat st;
+
+ if (get_shell_folder_path(path, VIM_STARTMENU))
+ {
+ for (i = 1; i < TARGET_COUNT; ++i)
+ remove_if_exists(path, targets[i].lnkname);
+ remove_if_exists(path, "uninstall.lnk");
+ remove_if_exists(path, "Help.lnk");
+ /* Win95 uses .pif, WinNT uses .lnk */
+ remove_if_exists(path, "Vim tutor.pif");
+ remove_if_exists(path, "Vim tutor.lnk");
+ remove_if_exists(path, "Vim online.url");
+ if (stat(path, &st) == 0)
+ {
+ printf("removing %s\n", path);
+ rmdir(path);
+ }
+ }
+}
+
+ static void
+delete_uninstall_key(void)
+{
+ reg_delete_key(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Vim " VIM_VERSION_SHORT, KEY_WOW64_64KEY);
+}
+
+ int
+main(int argc, char *argv[])
+{
+ int found = 0;
+ FILE *fd;
+ int i;
+ struct stat st;
+ char icon[BUFSIZE];
+ char path[BUFSIZE];
+ char popup_path[BUFSIZE];
+
+ /* The nsis uninstaller calls us with a "-nsis" argument. */
+ if (argc == 2 && stricmp(argv[1], "-nsis") == 0)
+ interactive = FALSE;
+ else
+ interactive = TRUE;
+
+ /* Initialize this program. */
+ do_inits(argv);
+
+ printf("This program will remove the following items:\n");
+
+ if (popup_gvim_path(popup_path))
+ {
+ printf(" - the \"Edit with Vim\" entry in the popup menu\n");
+ printf(" which uses \"%s\"\n", popup_path);
+ if (interactive)
+ printf("\nRemove it (y/n)? ");
+ if (!interactive || confirm())
+ {
+ remove_popup();
+ /* Assume the "Open With" entry can be removed as well, don't
+ * bother the user with asking him again. */
+ remove_openwith();
+ }
+ }
+ else if (openwith_gvim_path(popup_path))
+ {
+ printf(" - the Vim \"Open With...\" entry in the popup menu\n");
+ printf(" which uses \"%s\"\n", popup_path);
+ printf("\nRemove it (y/n)? ");
+ if (confirm())
+ remove_openwith();
+ }
+
+ if (get_shell_folder_path(path, "desktop"))
+ {
+ printf("\n");
+ for (i = 0; i < ICON_COUNT; ++i)
+ {
+ sprintf(icon, "%s\\%s", path, icon_link_names[i]);
+ if (stat(icon, &st) == 0)
+ {
+ printf(" - the \"%s\" icon on the desktop\n", icon_names[i]);
+ ++found;
+ }
+ }
+ if (found > 0)
+ {
+ if (interactive)
+ printf("\nRemove %s (y/n)? ", found > 1 ? "them" : "it");
+ if (!interactive || confirm())
+ remove_icons();
+ }
+ }
+
+ if (get_shell_folder_path(path, VIM_STARTMENU)
+ && stat(path, &st) == 0)
+ {
+ printf("\n - the \"%s\" entry in the Start Menu\n", VIM_STARTMENU);
+ if (interactive)
+ printf("\nRemove it (y/n)? ");
+ if (!interactive || confirm())
+ remove_start_menu();
+ }
+
+ printf("\n");
+ found = remove_batfiles(0);
+ if (found > 0)
+ {
+ if (interactive)
+ printf("\nRemove %s (y/n)? ", found > 1 ? "them" : "it");
+ if (!interactive || confirm())
+ remove_batfiles(1);
+ }
+
+ fd = fopen("gvim.exe", "r");
+ if (fd != NULL)
+ {
+ fclose(fd);
+ printf("gvim.exe detected. Attempting to unregister gvim with OLE\n");
+ system("gvim.exe -silent -unregister");
+ }
+
+ delete_uninstall_key();
+
+ if (interactive)
+ {
+ printf("\nYou may now want to delete the Vim executables and runtime files.\n");
+ printf("(They are still where you unpacked them.)\n");
+ }
+
+ if (interactive)
+ {
+ rewind(stdin);
+ printf("\nPress Enter to exit...");
+ (void)getchar();
+ }
+ else
+ sleep(3);
+
+ return 0;
+}
diff --git a/src/userfunc.c b/src/userfunc.c
new file mode 100644
index 0000000..acbab90
--- /dev/null
+++ b/src/userfunc.c
@@ -0,0 +1,3956 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * eval.c: User defined function support
+ */
+
+#include "vim.h"
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+// flags used in uf_flags
+#define FC_ABORT 0x01 // abort function on error
+#define FC_RANGE 0x02 // function accepts range
+#define FC_DICT 0x04 // Dict function, uses "self"
+#define FC_CLOSURE 0x08 // closure, uses outer scope variables
+#define FC_DELETED 0x10 // :delfunction used while uf_refcount > 0
+#define FC_REMOVED 0x20 // function redefined while uf_refcount > 0
+#define FC_SANDBOX 0x40 // function defined in the sandbox
+
+/* From user function to hashitem and back. */
+#define UF2HIKEY(fp) ((fp)->uf_name)
+#define HIKEY2UF(p) ((ufunc_T *)((p) - offsetof(ufunc_T, uf_name)))
+#define HI2UF(hi) HIKEY2UF((hi)->hi_key)
+
+#define FUNCARG(fp, j) ((char_u **)(fp->uf_args.ga_data))[j]
+#define FUNCLINE(fp, j) ((char_u **)(fp->uf_lines.ga_data))[j]
+
+/*
+ * All user-defined functions are found in this hashtable.
+ */
+static hashtab_T func_hashtab;
+
+/* Used by get_func_tv() */
+static garray_T funcargs = GA_EMPTY;
+
+/* pointer to funccal for currently active function */
+funccall_T *current_funccal = NULL;
+
+/* Pointer to list of previously used funccal, still around because some
+ * item in it is still being used. */
+funccall_T *previous_funccal = NULL;
+
+static char *e_funcexts = N_("E122: Function %s already exists, add ! to replace it");
+static char *e_funcdict = N_("E717: Dictionary entry already exists");
+static char *e_funcref = N_("E718: Funcref required");
+static char *e_nofunc = N_("E130: Unknown function: %s");
+
+#ifdef FEAT_PROFILE
+static void func_do_profile(ufunc_T *fp);
+static void prof_sort_list(FILE *fd, ufunc_T **sorttab, int st_len, char *title, int prefer_self);
+static void prof_func_line(FILE *fd, int count, proftime_T *total, proftime_T *self, int prefer_self);
+static int
+# ifdef __BORLANDC__
+ _RTLENTRYF
+# endif
+ prof_total_cmp(const void *s1, const void *s2);
+static int
+# ifdef __BORLANDC__
+ _RTLENTRYF
+# endif
+ prof_self_cmp(const void *s1, const void *s2);
+#endif
+static void funccal_unref(funccall_T *fc, ufunc_T *fp, int force);
+
+ void
+func_init()
+{
+ hash_init(&func_hashtab);
+}
+
+/*
+ * Get function arguments.
+ */
+ static int
+get_function_args(
+ char_u **argp,
+ char_u endchar,
+ garray_T *newargs,
+ int *varargs,
+ int skip)
+{
+ int mustend = FALSE;
+ char_u *arg = *argp;
+ char_u *p = arg;
+ int c;
+ int i;
+
+ if (newargs != NULL)
+ ga_init2(newargs, (int)sizeof(char_u *), 3);
+
+ if (varargs != NULL)
+ *varargs = FALSE;
+
+ /*
+ * Isolate the arguments: "arg1, arg2, ...)"
+ */
+ while (*p != endchar)
+ {
+ if (p[0] == '.' && p[1] == '.' && p[2] == '.')
+ {
+ if (varargs != NULL)
+ *varargs = TRUE;
+ p += 3;
+ mustend = TRUE;
+ }
+ else
+ {
+ arg = p;
+ while (ASCII_ISALNUM(*p) || *p == '_')
+ ++p;
+ if (arg == p || isdigit(*arg)
+ || (p - arg == 9 && STRNCMP(arg, "firstline", 9) == 0)
+ || (p - arg == 8 && STRNCMP(arg, "lastline", 8) == 0))
+ {
+ if (!skip)
+ semsg(_("E125: Illegal argument: %s"), arg);
+ break;
+ }
+ if (newargs != NULL && ga_grow(newargs, 1) == FAIL)
+ goto err_ret;
+ if (newargs != NULL)
+ {
+ c = *p;
+ *p = NUL;
+ arg = vim_strsave(arg);
+ if (arg == NULL)
+ {
+ *p = c;
+ goto err_ret;
+ }
+
+ /* Check for duplicate argument name. */
+ for (i = 0; i < newargs->ga_len; ++i)
+ if (STRCMP(((char_u **)(newargs->ga_data))[i], arg) == 0)
+ {
+ semsg(_("E853: Duplicate argument name: %s"), arg);
+ vim_free(arg);
+ goto err_ret;
+ }
+ ((char_u **)(newargs->ga_data))[newargs->ga_len] = arg;
+ newargs->ga_len++;
+
+ *p = c;
+ }
+ if (*p == ',')
+ ++p;
+ else
+ mustend = TRUE;
+ }
+ p = skipwhite(p);
+ if (mustend && *p != endchar)
+ {
+ if (!skip)
+ semsg(_(e_invarg2), *argp);
+ break;
+ }
+ }
+ if (*p != endchar)
+ goto err_ret;
+ ++p; /* skip "endchar" */
+
+ *argp = p;
+ return OK;
+
+err_ret:
+ if (newargs != NULL)
+ ga_clear_strings(newargs);
+ return FAIL;
+}
+
+/*
+ * Register function "fp" as using "current_funccal" as its scope.
+ */
+ static int
+register_closure(ufunc_T *fp)
+{
+ if (fp->uf_scoped == current_funccal)
+ /* no change */
+ return OK;
+ funccal_unref(fp->uf_scoped, fp, FALSE);
+ fp->uf_scoped = current_funccal;
+ current_funccal->fc_refcount++;
+
+ if (ga_grow(&current_funccal->fc_funcs, 1) == FAIL)
+ return FAIL;
+ ((ufunc_T **)current_funccal->fc_funcs.ga_data)
+ [current_funccal->fc_funcs.ga_len++] = fp;
+ return OK;
+}
+
+/*
+ * Parse a lambda expression and get a Funcref from "*arg".
+ * Return OK or FAIL. Returns NOTDONE for dict or {expr}.
+ */
+ int
+get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate)
+{
+ garray_T newargs;
+ garray_T newlines;
+ garray_T *pnewargs;
+ ufunc_T *fp = NULL;
+ int varargs;
+ int ret;
+ char_u *start = skipwhite(*arg + 1);
+ char_u *s, *e;
+ static int lambda_no = 0;
+ int *old_eval_lavars = eval_lavars_used;
+ int eval_lavars = FALSE;
+
+ ga_init(&newargs);
+ ga_init(&newlines);
+
+ /* First, check if this is a lambda expression. "->" must exist. */
+ ret = get_function_args(&start, '-', NULL, NULL, TRUE);
+ if (ret == FAIL || *start != '>')
+ return NOTDONE;
+
+ /* Parse the arguments again. */
+ if (evaluate)
+ pnewargs = &newargs;
+ else
+ pnewargs = NULL;
+ *arg = skipwhite(*arg + 1);
+ ret = get_function_args(arg, '-', pnewargs, &varargs, FALSE);
+ if (ret == FAIL || **arg != '>')
+ goto errret;
+
+ /* Set up a flag for checking local variables and arguments. */
+ if (evaluate)
+ eval_lavars_used = &eval_lavars;
+
+ /* Get the start and the end of the expression. */
+ *arg = skipwhite(*arg + 1);
+ s = *arg;
+ ret = skip_expr(arg);
+ if (ret == FAIL)
+ goto errret;
+ e = *arg;
+ *arg = skipwhite(*arg);
+ if (**arg != '}')
+ goto errret;
+ ++*arg;
+
+ if (evaluate)
+ {
+ int len, flags = 0;
+ char_u *p;
+ char_u name[20];
+ partial_T *pt;
+
+ sprintf((char*)name, "<lambda>%d", ++lambda_no);
+
+ fp = (ufunc_T *)alloc_clear((unsigned)(sizeof(ufunc_T) + STRLEN(name)));
+ if (fp == NULL)
+ goto errret;
+ pt = (partial_T *)alloc_clear((unsigned)sizeof(partial_T));
+ if (pt == NULL)
+ {
+ vim_free(fp);
+ goto errret;
+ }
+
+ ga_init2(&newlines, (int)sizeof(char_u *), 1);
+ if (ga_grow(&newlines, 1) == FAIL)
+ goto errret;
+
+ /* Add "return " before the expression. */
+ len = 7 + e - s + 1;
+ p = (char_u *)alloc(len);
+ if (p == NULL)
+ goto errret;
+ ((char_u **)(newlines.ga_data))[newlines.ga_len++] = p;
+ STRCPY(p, "return ");
+ vim_strncpy(p + 7, s, e - s);
+
+ fp->uf_refcount = 1;
+ STRCPY(fp->uf_name, name);
+ hash_add(&func_hashtab, UF2HIKEY(fp));
+ fp->uf_args = newargs;
+ fp->uf_lines = newlines;
+ if (current_funccal != NULL && eval_lavars)
+ {
+ flags |= FC_CLOSURE;
+ if (register_closure(fp) == FAIL)
+ goto errret;
+ }
+ else
+ fp->uf_scoped = NULL;
+
+#ifdef FEAT_PROFILE
+ if (prof_def_func())
+ func_do_profile(fp);
+#endif
+ if (sandbox)
+ flags |= FC_SANDBOX;
+ fp->uf_varargs = TRUE;
+ fp->uf_flags = flags;
+ fp->uf_calls = 0;
+ fp->uf_script_ctx = current_sctx;
+ fp->uf_script_ctx.sc_lnum += sourcing_lnum - newlines.ga_len;
+
+ pt->pt_func = fp;
+ pt->pt_refcount = 1;
+ rettv->vval.v_partial = pt;
+ rettv->v_type = VAR_PARTIAL;
+ }
+
+ eval_lavars_used = old_eval_lavars;
+ return OK;
+
+errret:
+ ga_clear_strings(&newargs);
+ ga_clear_strings(&newlines);
+ vim_free(fp);
+ eval_lavars_used = old_eval_lavars;
+ return FAIL;
+}
+
+/*
+ * Check if "name" is a variable of type VAR_FUNC. If so, return the function
+ * name it contains, otherwise return "name".
+ * If "partialp" is not NULL, and "name" is of type VAR_PARTIAL also set
+ * "partialp".
+ */
+ char_u *
+deref_func_name(char_u *name, int *lenp, partial_T **partialp, int no_autoload)
+{
+ dictitem_T *v;
+ int cc;
+ char_u *s;
+
+ if (partialp != NULL)
+ *partialp = NULL;
+
+ cc = name[*lenp];
+ name[*lenp] = NUL;
+ v = find_var(name, NULL, no_autoload);
+ name[*lenp] = cc;
+ if (v != NULL && v->di_tv.v_type == VAR_FUNC)
+ {
+ if (v->di_tv.vval.v_string == NULL)
+ {
+ *lenp = 0;
+ return (char_u *)""; /* just in case */
+ }
+ s = v->di_tv.vval.v_string;
+ *lenp = (int)STRLEN(s);
+ return s;
+ }
+
+ if (v != NULL && v->di_tv.v_type == VAR_PARTIAL)
+ {
+ partial_T *pt = v->di_tv.vval.v_partial;
+
+ if (pt == NULL)
+ {
+ *lenp = 0;
+ return (char_u *)""; /* just in case */
+ }
+ if (partialp != NULL)
+ *partialp = pt;
+ s = partial_name(pt);
+ *lenp = (int)STRLEN(s);
+ return s;
+ }
+
+ return name;
+}
+
+/*
+ * Give an error message with a function name. Handle <SNR> things.
+ * "ermsg" is to be passed without translation, use N_() instead of _().
+ */
+ static void
+emsg_funcname(char *ermsg, char_u *name)
+{
+ char_u *p;
+
+ if (*name == K_SPECIAL)
+ p = concat_str((char_u *)"<SNR>", name + 3);
+ else
+ p = name;
+ semsg(_(ermsg), p);
+ if (p != name)
+ vim_free(p);
+}
+
+/*
+ * Allocate a variable for the result of a function.
+ * Return OK or FAIL.
+ */
+ int
+get_func_tv(
+ char_u *name, /* name of the function */
+ int len, /* length of "name" */
+ typval_T *rettv,
+ char_u **arg, /* argument, pointing to the '(' */
+ linenr_T firstline, /* first line of range */
+ linenr_T lastline, /* last line of range */
+ int *doesrange, /* return: function handled range */
+ int evaluate,
+ partial_T *partial, /* for extra arguments */
+ dict_T *selfdict) /* Dictionary for "self" */
+{
+ char_u *argp;
+ int ret = OK;
+ typval_T argvars[MAX_FUNC_ARGS + 1]; /* vars for arguments */
+ int argcount = 0; /* number of arguments found */
+
+ /*
+ * Get the arguments.
+ */
+ argp = *arg;
+ while (argcount < MAX_FUNC_ARGS - (partial == NULL ? 0 : partial->pt_argc))
+ {
+ argp = skipwhite(argp + 1); /* skip the '(' or ',' */
+ if (*argp == ')' || *argp == ',' || *argp == NUL)
+ break;
+ if (eval1(&argp, &argvars[argcount], evaluate) == FAIL)
+ {
+ ret = FAIL;
+ break;
+ }
+ ++argcount;
+ if (*argp != ',')
+ break;
+ }
+ if (*argp == ')')
+ ++argp;
+ else
+ ret = FAIL;
+
+ if (ret == OK)
+ {
+ int i = 0;
+
+ if (get_vim_var_nr(VV_TESTING))
+ {
+ /* Prepare for calling test_garbagecollect_now(), need to know
+ * what variables are used on the call stack. */
+ if (funcargs.ga_itemsize == 0)
+ ga_init2(&funcargs, (int)sizeof(typval_T *), 50);
+ for (i = 0; i < argcount; ++i)
+ if (ga_grow(&funcargs, 1) == OK)
+ ((typval_T **)funcargs.ga_data)[funcargs.ga_len++] =
+ &argvars[i];
+ }
+
+ ret = call_func(name, len, rettv, argcount, argvars, NULL,
+ firstline, lastline, doesrange, evaluate, partial, selfdict);
+
+ funcargs.ga_len -= i;
+ }
+ else if (!aborting())
+ {
+ if (argcount == MAX_FUNC_ARGS)
+ emsg_funcname(N_("E740: Too many arguments for function %s"), name);
+ else
+ emsg_funcname(N_("E116: Invalid arguments for function %s"), name);
+ }
+
+ while (--argcount >= 0)
+ clear_tv(&argvars[argcount]);
+
+ *arg = skipwhite(argp);
+ return ret;
+}
+
+#define FLEN_FIXED 40
+
+/*
+ * Return TRUE if "p" starts with "<SID>" or "s:".
+ * Only works if eval_fname_script() returned non-zero for "p"!
+ */
+ static int
+eval_fname_sid(char_u *p)
+{
+ return (*p == 's' || TOUPPER_ASC(p[2]) == 'I');
+}
+
+/*
+ * In a script change <SID>name() and s:name() to K_SNR 123_name().
+ * Change <SNR>123_name() to K_SNR 123_name().
+ * Use "fname_buf[FLEN_FIXED + 1]" when it fits, otherwise allocate memory
+ * (slow).
+ */
+ static char_u *
+fname_trans_sid(char_u *name, char_u *fname_buf, char_u **tofree, int *error)
+{
+ int llen;
+ char_u *fname;
+ int i;
+
+ llen = eval_fname_script(name);
+ if (llen > 0)
+ {
+ fname_buf[0] = K_SPECIAL;
+ fname_buf[1] = KS_EXTRA;
+ fname_buf[2] = (int)KE_SNR;
+ i = 3;
+ if (eval_fname_sid(name)) /* "<SID>" or "s:" */
+ {
+ if (current_sctx.sc_sid <= 0)
+ *error = ERROR_SCRIPT;
+ else
+ {
+ sprintf((char *)fname_buf + 3, "%ld_", (long)current_sctx.sc_sid);
+ i = (int)STRLEN(fname_buf);
+ }
+ }
+ if (i + STRLEN(name + llen) < FLEN_FIXED)
+ {
+ STRCPY(fname_buf + i, name + llen);
+ fname = fname_buf;
+ }
+ else
+ {
+ fname = alloc((unsigned)(i + STRLEN(name + llen) + 1));
+ if (fname == NULL)
+ *error = ERROR_OTHER;
+ else
+ {
+ *tofree = fname;
+ mch_memmove(fname, fname_buf, (size_t)i);
+ STRCPY(fname + i, name + llen);
+ }
+ }
+ }
+ else
+ fname = name;
+ return fname;
+}
+
+/*
+ * Find a function by name, return pointer to it in ufuncs.
+ * Return NULL for unknown function.
+ */
+ ufunc_T *
+find_func(char_u *name)
+{
+ hashitem_T *hi;
+
+ hi = hash_find(&func_hashtab, name);
+ if (!HASHITEM_EMPTY(hi))
+ return HI2UF(hi);
+ return NULL;
+}
+
+/*
+ * Copy the function name of "fp" to buffer "buf".
+ * "buf" must be able to hold the function name plus three bytes.
+ * Takes care of script-local function names.
+ */
+ static void
+cat_func_name(char_u *buf, ufunc_T *fp)
+{
+ if (fp->uf_name[0] == K_SPECIAL)
+ {
+ STRCPY(buf, "<SNR>");
+ STRCAT(buf, fp->uf_name + 3);
+ }
+ else
+ STRCPY(buf, fp->uf_name);
+}
+
+/*
+ * Add a number variable "name" to dict "dp" with value "nr".
+ */
+ static void
+add_nr_var(
+ dict_T *dp,
+ dictitem_T *v,
+ char *name,
+ varnumber_T nr)
+{
+ STRCPY(v->di_key, name);
+ v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
+ hash_add(&dp->dv_hashtab, DI2HIKEY(v));
+ v->di_tv.v_type = VAR_NUMBER;
+ v->di_tv.v_lock = VAR_FIXED;
+ v->di_tv.vval.v_number = nr;
+}
+
+/*
+ * Free "fc" and what it contains.
+ */
+ static void
+free_funccal(
+ funccall_T *fc,
+ int free_val) /* a: vars were allocated */
+{
+ listitem_T *li;
+ int i;
+
+ for (i = 0; i < fc->fc_funcs.ga_len; ++i)
+ {
+ ufunc_T *fp = ((ufunc_T **)(fc->fc_funcs.ga_data))[i];
+
+ /* When garbage collecting a funccall_T may be freed before the
+ * function that references it, clear its uf_scoped field.
+ * The function may have been redefined and point to another
+ * funccall_T, don't clear it then. */
+ if (fp != NULL && fp->uf_scoped == fc)
+ fp->uf_scoped = NULL;
+ }
+ ga_clear(&fc->fc_funcs);
+
+ /* The a: variables typevals may not have been allocated, only free the
+ * allocated variables. */
+ vars_clear_ext(&fc->l_avars.dv_hashtab, free_val);
+
+ /* free all l: variables */
+ vars_clear(&fc->l_vars.dv_hashtab);
+
+ /* Free the a:000 variables if they were allocated. */
+ if (free_val)
+ for (li = fc->l_varlist.lv_first; li != NULL; li = li->li_next)
+ clear_tv(&li->li_tv);
+
+ func_ptr_unref(fc->func);
+ vim_free(fc);
+}
+
+/*
+ * Handle the last part of returning from a function: free the local hashtable.
+ * Unless it is still in use by a closure.
+ */
+ static void
+cleanup_function_call(funccall_T *fc)
+{
+ current_funccal = fc->caller;
+
+ /* If the a:000 list and the l: and a: dicts are not referenced and there
+ * is no closure using it, we can free the funccall_T and what's in it. */
+ if (fc->l_varlist.lv_refcount == DO_NOT_FREE_CNT
+ && fc->l_vars.dv_refcount == DO_NOT_FREE_CNT
+ && fc->l_avars.dv_refcount == DO_NOT_FREE_CNT
+ && fc->fc_refcount <= 0)
+ {
+ free_funccal(fc, FALSE);
+ }
+ else
+ {
+ hashitem_T *hi;
+ listitem_T *li;
+ int todo;
+ dictitem_T *v;
+ static int made_copy = 0;
+
+ /* "fc" is still in use. This can happen when returning "a:000",
+ * assigning "l:" to a global variable or defining a closure.
+ * Link "fc" in the list for garbage collection later. */
+ fc->caller = previous_funccal;
+ previous_funccal = fc;
+
+ /* Make a copy of the a: variables, since we didn't do that above. */
+ todo = (int)fc->l_avars.dv_hashtab.ht_used;
+ for (hi = fc->l_avars.dv_hashtab.ht_array; todo > 0; ++hi)
+ {
+ if (!HASHITEM_EMPTY(hi))
+ {
+ --todo;
+ v = HI2DI(hi);
+ copy_tv(&v->di_tv, &v->di_tv);
+ }
+ }
+
+ /* Make a copy of the a:000 items, since we didn't do that above. */
+ for (li = fc->l_varlist.lv_first; li != NULL; li = li->li_next)
+ copy_tv(&li->li_tv, &li->li_tv);
+
+ if (++made_copy == 10000)
+ {
+ // We have made a lot of copies. This can happen when
+ // repetitively calling a function that creates a reference to
+ // itself somehow. Call the garbage collector soon to avoid using
+ // too much memory.
+ made_copy = 0;
+ want_garbage_collect = TRUE;
+ }
+ }
+}
+
+/*
+ * Call a user function.
+ */
+ static void
+call_user_func(
+ ufunc_T *fp, /* pointer to function */
+ int argcount, /* nr of args */
+ typval_T *argvars, /* arguments */
+ typval_T *rettv, /* return value */
+ linenr_T firstline, /* first line of range */
+ linenr_T lastline, /* last line of range */
+ dict_T *selfdict) /* Dictionary for "self" */
+{
+ char_u *save_sourcing_name;
+ linenr_T save_sourcing_lnum;
+ sctx_T save_current_sctx;
+ int using_sandbox = FALSE;
+ funccall_T *fc;
+ int save_did_emsg;
+ static int depth = 0;
+ dictitem_T *v;
+ int fixvar_idx = 0; /* index in fixvar[] */
+ int i;
+ int ai;
+ int islambda = FALSE;
+ char_u numbuf[NUMBUFLEN];
+ char_u *name;
+ size_t len;
+#ifdef FEAT_PROFILE
+ proftime_T wait_start;
+ proftime_T call_start;
+ int started_profiling = FALSE;
+#endif
+
+ /* If depth of calling is getting too high, don't execute the function */
+ if (depth >= p_mfd)
+ {
+ emsg(_("E132: Function call depth is higher than 'maxfuncdepth'"));
+ rettv->v_type = VAR_NUMBER;
+ rettv->vval.v_number = -1;
+ return;
+ }
+ ++depth;
+
+ line_breakcheck(); /* check for CTRL-C hit */
+
+ fc = (funccall_T *)alloc(sizeof(funccall_T));
+ if (fc == NULL)
+ return;
+ fc->caller = current_funccal;
+ current_funccal = fc;
+ fc->func = fp;
+ fc->rettv = rettv;
+ rettv->vval.v_number = 0;
+ fc->linenr = 0;
+ fc->returned = FALSE;
+ fc->level = ex_nesting_level;
+ /* Check if this function has a breakpoint. */
+ fc->breakpoint = dbg_find_breakpoint(FALSE, fp->uf_name, (linenr_T)0);
+ fc->dbg_tick = debug_tick;
+ /* Set up fields for closure. */
+ fc->fc_refcount = 0;
+ fc->fc_copyID = 0;
+ ga_init2(&fc->fc_funcs, sizeof(ufunc_T *), 1);
+ func_ptr_ref(fp);
+
+ if (STRNCMP(fp->uf_name, "<lambda>", 8) == 0)
+ islambda = TRUE;
+
+ /*
+ * Note about using fc->fixvar[]: This is an array of FIXVAR_CNT variables
+ * with names up to VAR_SHORT_LEN long. This avoids having to alloc/free
+ * each argument variable and saves a lot of time.
+ */
+ /*
+ * Init l: variables.
+ */
+ init_var_dict(&fc->l_vars, &fc->l_vars_var, VAR_DEF_SCOPE);
+ if (selfdict != NULL)
+ {
+ /* Set l:self to "selfdict". Use "name" to avoid a warning from
+ * some compiler that checks the destination size. */
+ v = &fc->fixvar[fixvar_idx++].var;
+ name = v->di_key;
+ STRCPY(name, "self");
+ v->di_flags = DI_FLAGS_RO + DI_FLAGS_FIX;
+ hash_add(&fc->l_vars.dv_hashtab, DI2HIKEY(v));
+ v->di_tv.v_type = VAR_DICT;
+ v->di_tv.v_lock = 0;
+ v->di_tv.vval.v_dict = selfdict;
+ ++selfdict->dv_refcount;
+ }
+
+ /*
+ * Init a: variables.
+ * Set a:0 to "argcount".
+ * Set a:000 to a list with room for the "..." arguments.
+ */
+ init_var_dict(&fc->l_avars, &fc->l_avars_var, VAR_SCOPE);
+ add_nr_var(&fc->l_avars, &fc->fixvar[fixvar_idx++].var, "0",
+ (varnumber_T)(argcount - fp->uf_args.ga_len));
+ /* Use "name" to avoid a warning from some compiler that checks the
+ * destination size. */
+ v = &fc->fixvar[fixvar_idx++].var;
+ name = v->di_key;
+ STRCPY(name, "000");
+ v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
+ hash_add(&fc->l_avars.dv_hashtab, DI2HIKEY(v));
+ v->di_tv.v_type = VAR_LIST;
+ v->di_tv.v_lock = VAR_FIXED;
+ v->di_tv.vval.v_list = &fc->l_varlist;
+ vim_memset(&fc->l_varlist, 0, sizeof(list_T));
+ fc->l_varlist.lv_refcount = DO_NOT_FREE_CNT;
+ fc->l_varlist.lv_lock = VAR_FIXED;
+
+ /*
+ * Set a:firstline to "firstline" and a:lastline to "lastline".
+ * Set a:name to named arguments.
+ * Set a:N to the "..." arguments.
+ */
+ add_nr_var(&fc->l_avars, &fc->fixvar[fixvar_idx++].var, "firstline",
+ (varnumber_T)firstline);
+ add_nr_var(&fc->l_avars, &fc->fixvar[fixvar_idx++].var, "lastline",
+ (varnumber_T)lastline);
+ for (i = 0; i < argcount; ++i)
+ {
+ int addlocal = FALSE;
+
+ ai = i - fp->uf_args.ga_len;
+ if (ai < 0)
+ {
+ /* named argument a:name */
+ name = FUNCARG(fp, i);
+ if (islambda)
+ addlocal = TRUE;
+ }
+ else
+ {
+ /* "..." argument a:1, a:2, etc. */
+ sprintf((char *)numbuf, "%d", ai + 1);
+ name = numbuf;
+ }
+ if (fixvar_idx < FIXVAR_CNT && STRLEN(name) <= VAR_SHORT_LEN)
+ {
+ v = &fc->fixvar[fixvar_idx++].var;
+ v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
+ }
+ else
+ {
+ v = (dictitem_T *)alloc((unsigned)(sizeof(dictitem_T)
+ + STRLEN(name)));
+ if (v == NULL)
+ break;
+ v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX | DI_FLAGS_ALLOC;
+ }
+ STRCPY(v->di_key, name);
+
+ /* Note: the values are copied directly to avoid alloc/free.
+ * "argvars" must have VAR_FIXED for v_lock. */
+ v->di_tv = argvars[i];
+ v->di_tv.v_lock = VAR_FIXED;
+
+ if (addlocal)
+ {
+ /* Named arguments should be accessed without the "a:" prefix in
+ * lambda expressions. Add to the l: dict. */
+ copy_tv(&v->di_tv, &v->di_tv);
+ hash_add(&fc->l_vars.dv_hashtab, DI2HIKEY(v));
+ }
+ else
+ hash_add(&fc->l_avars.dv_hashtab, DI2HIKEY(v));
+
+ if (ai >= 0 && ai < MAX_FUNC_ARGS)
+ {
+ list_append(&fc->l_varlist, &fc->l_listitems[ai]);
+ fc->l_listitems[ai].li_tv = argvars[i];
+ fc->l_listitems[ai].li_tv.v_lock = VAR_FIXED;
+ }
+ }
+
+ /* Don't redraw while executing the function. */
+ ++RedrawingDisabled;
+ save_sourcing_name = sourcing_name;
+ save_sourcing_lnum = sourcing_lnum;
+ sourcing_lnum = 1;
+
+ if (fp->uf_flags & FC_SANDBOX)
+ {
+ using_sandbox = TRUE;
+ ++sandbox;
+ }
+
+ /* need space for function name + ("function " + 3) or "[number]" */
+ len = (save_sourcing_name == NULL ? 0 : STRLEN(save_sourcing_name))
+ + STRLEN(fp->uf_name) + 20;
+ sourcing_name = alloc((unsigned)len);
+ if (sourcing_name != NULL)
+ {
+ if (save_sourcing_name != NULL
+ && STRNCMP(save_sourcing_name, "function ", 9) == 0)
+ sprintf((char *)sourcing_name, "%s[%d]..",
+ save_sourcing_name, (int)save_sourcing_lnum);
+ else
+ STRCPY(sourcing_name, "function ");
+ cat_func_name(sourcing_name + STRLEN(sourcing_name), fp);
+
+ if (p_verbose >= 12)
+ {
+ ++no_wait_return;
+ verbose_enter_scroll();
+
+ smsg(_("calling %s"), sourcing_name);
+ if (p_verbose >= 14)
+ {
+ char_u buf[MSG_BUF_LEN];
+ char_u numbuf2[NUMBUFLEN];
+ char_u *tofree;
+ char_u *s;
+
+ msg_puts("(");
+ for (i = 0; i < argcount; ++i)
+ {
+ if (i > 0)
+ msg_puts(", ");
+ if (argvars[i].v_type == VAR_NUMBER)
+ msg_outnum((long)argvars[i].vval.v_number);
+ else
+ {
+ /* Do not want errors such as E724 here. */
+ ++emsg_off;
+ s = tv2string(&argvars[i], &tofree, numbuf2, 0);
+ --emsg_off;
+ if (s != NULL)
+ {
+ if (vim_strsize(s) > MSG_BUF_CLEN)
+ {
+ trunc_string(s, buf, MSG_BUF_CLEN, MSG_BUF_LEN);
+ s = buf;
+ }
+ msg_puts((char *)s);
+ vim_free(tofree);
+ }
+ }
+ }
+ msg_puts(")");
+ }
+ msg_puts("\n"); /* don't overwrite this either */
+
+ verbose_leave_scroll();
+ --no_wait_return;
+ }
+ }
+#ifdef FEAT_PROFILE
+ if (do_profiling == PROF_YES)
+ {
+ if (!fp->uf_profiling && has_profiling(FALSE, fp->uf_name, NULL))
+ {
+ started_profiling = TRUE;
+ func_do_profile(fp);
+ }
+ if (fp->uf_profiling
+ || (fc->caller != NULL && fc->caller->func->uf_profiling))
+ {
+ ++fp->uf_tm_count;
+ profile_start(&call_start);
+ profile_zero(&fp->uf_tm_children);
+ }
+ script_prof_save(&wait_start);
+ }
+#endif
+
+ save_current_sctx = current_sctx;
+ current_sctx = fp->uf_script_ctx;
+ save_did_emsg = did_emsg;
+ did_emsg = FALSE;
+
+ /* call do_cmdline() to execute the lines */
+ do_cmdline(NULL, get_func_line, (void *)fc,
+ DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT);
+
+ --RedrawingDisabled;
+
+ /* when the function was aborted because of an error, return -1 */
+ if ((did_emsg && (fp->uf_flags & FC_ABORT)) || rettv->v_type == VAR_UNKNOWN)
+ {
+ clear_tv(rettv);
+ rettv->v_type = VAR_NUMBER;
+ rettv->vval.v_number = -1;
+ }
+
+#ifdef FEAT_PROFILE
+ if (do_profiling == PROF_YES && (fp->uf_profiling
+ || (fc->caller != NULL && fc->caller->func->uf_profiling)))
+ {
+ profile_end(&call_start);
+ profile_sub_wait(&wait_start, &call_start);
+ profile_add(&fp->uf_tm_total, &call_start);
+ profile_self(&fp->uf_tm_self, &call_start, &fp->uf_tm_children);
+ if (fc->caller != NULL && fc->caller->func->uf_profiling)
+ {
+ profile_add(&fc->caller->func->uf_tm_children, &call_start);
+ profile_add(&fc->caller->func->uf_tml_children, &call_start);
+ }
+ if (started_profiling)
+ // make a ":profdel func" stop profiling the function
+ fp->uf_profiling = FALSE;
+ }
+#endif
+
+ /* when being verbose, mention the return value */
+ if (p_verbose >= 12)
+ {
+ ++no_wait_return;
+ verbose_enter_scroll();
+
+ if (aborting())
+ smsg(_("%s aborted"), sourcing_name);
+ else if (fc->rettv->v_type == VAR_NUMBER)
+ smsg(_("%s returning #%ld"), sourcing_name,
+ (long)fc->rettv->vval.v_number);
+ else
+ {
+ char_u buf[MSG_BUF_LEN];
+ char_u numbuf2[NUMBUFLEN];
+ char_u *tofree;
+ char_u *s;
+
+ /* The value may be very long. Skip the middle part, so that we
+ * have some idea how it starts and ends. smsg() would always
+ * truncate it at the end. Don't want errors such as E724 here. */
+ ++emsg_off;
+ s = tv2string(fc->rettv, &tofree, numbuf2, 0);
+ --emsg_off;
+ if (s != NULL)
+ {
+ if (vim_strsize(s) > MSG_BUF_CLEN)
+ {
+ trunc_string(s, buf, MSG_BUF_CLEN, MSG_BUF_LEN);
+ s = buf;
+ }
+ smsg(_("%s returning %s"), sourcing_name, s);
+ vim_free(tofree);
+ }
+ }
+ msg_puts("\n"); /* don't overwrite this either */
+
+ verbose_leave_scroll();
+ --no_wait_return;
+ }
+
+ vim_free(sourcing_name);
+ sourcing_name = save_sourcing_name;
+ sourcing_lnum = save_sourcing_lnum;
+ current_sctx = save_current_sctx;
+#ifdef FEAT_PROFILE
+ if (do_profiling == PROF_YES)
+ script_prof_restore(&wait_start);
+#endif
+ if (using_sandbox)
+ --sandbox;
+
+ if (p_verbose >= 12 && sourcing_name != NULL)
+ {
+ ++no_wait_return;
+ verbose_enter_scroll();
+
+ smsg(_("continuing in %s"), sourcing_name);
+ msg_puts("\n"); /* don't overwrite this either */
+
+ verbose_leave_scroll();
+ --no_wait_return;
+ }
+
+ did_emsg |= save_did_emsg;
+ --depth;
+
+ cleanup_function_call(fc);
+}
+
+/*
+ * Unreference "fc": decrement the reference count and free it when it
+ * becomes zero. "fp" is detached from "fc".
+ * When "force" is TRUE we are exiting.
+ */
+ static void
+funccal_unref(funccall_T *fc, ufunc_T *fp, int force)
+{
+ funccall_T **pfc;
+ int i;
+
+ if (fc == NULL)
+ return;
+
+ if (--fc->fc_refcount <= 0 && (force || (
+ fc->l_varlist.lv_refcount == DO_NOT_FREE_CNT
+ && fc->l_vars.dv_refcount == DO_NOT_FREE_CNT
+ && fc->l_avars.dv_refcount == DO_NOT_FREE_CNT)))
+ for (pfc = &previous_funccal; *pfc != NULL; pfc = &(*pfc)->caller)
+ {
+ if (fc == *pfc)
+ {
+ *pfc = fc->caller;
+ free_funccal(fc, TRUE);
+ return;
+ }
+ }
+ for (i = 0; i < fc->fc_funcs.ga_len; ++i)
+ if (((ufunc_T **)(fc->fc_funcs.ga_data))[i] == fp)
+ ((ufunc_T **)(fc->fc_funcs.ga_data))[i] = NULL;
+}
+
+/*
+ * Remove the function from the function hashtable. If the function was
+ * deleted while it still has references this was already done.
+ * Return TRUE if the entry was deleted, FALSE if it wasn't found.
+ */
+ static int
+func_remove(ufunc_T *fp)
+{
+ hashitem_T *hi = hash_find(&func_hashtab, UF2HIKEY(fp));
+
+ if (!HASHITEM_EMPTY(hi))
+ {
+ hash_remove(&func_hashtab, hi);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+ static void
+func_clear_items(ufunc_T *fp)
+{
+ ga_clear_strings(&(fp->uf_args));
+ ga_clear_strings(&(fp->uf_lines));
+#ifdef FEAT_PROFILE
+ vim_free(fp->uf_tml_count);
+ fp->uf_tml_count = NULL;
+ vim_free(fp->uf_tml_total);
+ fp->uf_tml_total = NULL;
+ vim_free(fp->uf_tml_self);
+ fp->uf_tml_self = NULL;
+#endif
+}
+
+/*
+ * Free all things that a function contains. Does not free the function
+ * itself, use func_free() for that.
+ * When "force" is TRUE we are exiting.
+ */
+ static void
+func_clear(ufunc_T *fp, int force)
+{
+ if (fp->uf_cleared)
+ return;
+ fp->uf_cleared = TRUE;
+
+ /* clear this function */
+ func_clear_items(fp);
+ funccal_unref(fp->uf_scoped, fp, force);
+}
+
+/*
+ * Free a function and remove it from the list of functions. Does not free
+ * what a function contains, call func_clear() first.
+ */
+ static void
+func_free(ufunc_T *fp)
+{
+ /* only remove it when not done already, otherwise we would remove a newer
+ * version of the function */
+ if ((fp->uf_flags & (FC_DELETED | FC_REMOVED)) == 0)
+ func_remove(fp);
+
+ vim_free(fp);
+}
+
+/*
+ * Free all things that a function contains and free the function itself.
+ * When "force" is TRUE we are exiting.
+ */
+ static void
+func_clear_free(ufunc_T *fp, int force)
+{
+ func_clear(fp, force);
+ func_free(fp);
+}
+
+/*
+ * There are two kinds of function names:
+ * 1. ordinary names, function defined with :function
+ * 2. numbered functions and lambdas
+ * For the first we only count the name stored in func_hashtab as a reference,
+ * using function() does not count as a reference, because the function is
+ * looked up by name.
+ */
+ static int
+func_name_refcount(char_u *name)
+{
+ return isdigit(*name) || *name == '<';
+}
+
+static funccal_entry_T *funccal_stack = NULL;
+
+/*
+ * Save the current function call pointer, and set it to NULL.
+ * Used when executing autocommands and for ":source".
+ */
+ void
+save_funccal(funccal_entry_T *entry)
+{
+ entry->top_funccal = current_funccal;
+ entry->next = funccal_stack;
+ funccal_stack = entry;
+ current_funccal = NULL;
+}
+
+ void
+restore_funccal(void)
+{
+ if (funccal_stack == NULL)
+ iemsg("INTERNAL: restore_funccal()");
+ else
+ {
+ current_funccal = funccal_stack->top_funccal;
+ funccal_stack = funccal_stack->next;
+ }
+}
+
+#if defined(EXITFREE) || defined(PROTO)
+ void
+free_all_functions(void)
+{
+ hashitem_T *hi;
+ ufunc_T *fp;
+ long_u skipped = 0;
+ long_u todo = 1;
+ long_u used;
+
+ /* Clean up the current_funccal chain and the funccal stack. */
+ while (current_funccal != NULL)
+ {
+ clear_tv(current_funccal->rettv);
+ cleanup_function_call(current_funccal);
+ if (current_funccal == NULL && funccal_stack != NULL)
+ restore_funccal();
+ }
+
+ /* First clear what the functions contain. Since this may lower the
+ * reference count of a function, it may also free a function and change
+ * the hash table. Restart if that happens. */
+ while (todo > 0)
+ {
+ todo = func_hashtab.ht_used;
+ for (hi = func_hashtab.ht_array; todo > 0; ++hi)
+ if (!HASHITEM_EMPTY(hi))
+ {
+ /* Only free functions that are not refcounted, those are
+ * supposed to be freed when no longer referenced. */
+ fp = HI2UF(hi);
+ if (func_name_refcount(fp->uf_name))
+ ++skipped;
+ else
+ {
+ used = func_hashtab.ht_used;
+ func_clear(fp, TRUE);
+ if (used != func_hashtab.ht_used)
+ {
+ skipped = 0;
+ break;
+ }
+ }
+ --todo;
+ }
+ }
+
+ /* Now actually free the functions. Need to start all over every time,
+ * because func_free() may change the hash table. */
+ skipped = 0;
+ while (func_hashtab.ht_used > skipped)
+ {
+ todo = func_hashtab.ht_used;
+ for (hi = func_hashtab.ht_array; todo > 0; ++hi)
+ if (!HASHITEM_EMPTY(hi))
+ {
+ --todo;
+ /* Only free functions that are not refcounted, those are
+ * supposed to be freed when no longer referenced. */
+ fp = HI2UF(hi);
+ if (func_name_refcount(fp->uf_name))
+ ++skipped;
+ else
+ {
+ func_free(fp);
+ skipped = 0;
+ break;
+ }
+ }
+ }
+ if (skipped == 0)
+ hash_clear(&func_hashtab);
+}
+#endif
+
+/*
+ * Return TRUE if "name" looks like a builtin function name: starts with a
+ * lower case letter and doesn't contain AUTOLOAD_CHAR.
+ * "len" is the length of "name", or -1 for NUL terminated.
+ */
+ static int
+builtin_function(char_u *name, int len)
+{
+ char_u *p;
+
+ if (!ASCII_ISLOWER(name[0]))
+ return FALSE;
+ p = vim_strchr(name, AUTOLOAD_CHAR);
+ return p == NULL || (len > 0 && p > name + len);
+}
+
+ int
+func_call(
+ char_u *name,
+ typval_T *args,
+ partial_T *partial,
+ dict_T *selfdict,
+ typval_T *rettv)
+{
+ listitem_T *item;
+ typval_T argv[MAX_FUNC_ARGS + 1];
+ int argc = 0;
+ int dummy;
+ int r = 0;
+
+ for (item = args->vval.v_list->lv_first; item != NULL;
+ item = item->li_next)
+ {
+ if (argc == MAX_FUNC_ARGS - (partial == NULL ? 0 : partial->pt_argc))
+ {
+ emsg(_("E699: Too many arguments"));
+ break;
+ }
+ /* Make a copy of each argument. This is needed to be able to set
+ * v_lock to VAR_FIXED in the copy without changing the original list.
+ */
+ copy_tv(&item->li_tv, &argv[argc++]);
+ }
+
+ if (item == NULL)
+ r = call_func(name, (int)STRLEN(name), rettv, argc, argv, NULL,
+ curwin->w_cursor.lnum, curwin->w_cursor.lnum,
+ &dummy, TRUE, partial, selfdict);
+
+ /* Free the arguments. */
+ while (argc > 0)
+ clear_tv(&argv[--argc]);
+
+ return r;
+}
+
+/*
+ * Call a function with its resolved parameters
+ *
+ * "argv_func", when not NULL, can be used to fill in arguments only when the
+ * invoked function uses them. It is called like this:
+ * new_argcount = argv_func(current_argcount, argv, called_func_argcount)
+ *
+ * Return FAIL when the function can't be called, OK otherwise.
+ * Also returns OK when an error was encountered while executing the function.
+ */
+ int
+call_func(
+ char_u *funcname, /* name of the function */
+ int len, /* length of "name" */
+ typval_T *rettv, /* return value goes here */
+ int argcount_in, /* number of "argvars" */
+ typval_T *argvars_in, /* vars for arguments, must have "argcount"
+ PLUS ONE elements! */
+ int (* argv_func)(int, typval_T *, int),
+ /* function to fill in argvars */
+ linenr_T firstline, /* first line of range */
+ linenr_T lastline, /* last line of range */
+ int *doesrange, /* return: function handled range */
+ int evaluate,
+ partial_T *partial, /* optional, can be NULL */
+ dict_T *selfdict_in) /* Dictionary for "self" */
+{
+ int ret = FAIL;
+ int error = ERROR_NONE;
+ int i;
+ ufunc_T *fp;
+ char_u fname_buf[FLEN_FIXED + 1];
+ char_u *tofree = NULL;
+ char_u *fname;
+ char_u *name;
+ int argcount = argcount_in;
+ typval_T *argvars = argvars_in;
+ dict_T *selfdict = selfdict_in;
+ typval_T argv[MAX_FUNC_ARGS + 1]; /* used when "partial" is not NULL */
+ int argv_clear = 0;
+
+ /* Make a copy of the name, if it comes from a funcref variable it could
+ * be changed or deleted in the called function. */
+ name = vim_strnsave(funcname, len);
+ if (name == NULL)
+ return ret;
+
+ fname = fname_trans_sid(name, fname_buf, &tofree, &error);
+
+ *doesrange = FALSE;
+
+ if (partial != NULL)
+ {
+ /* When the function has a partial with a dict and there is a dict
+ * argument, use the dict argument. That is backwards compatible.
+ * When the dict was bound explicitly use the one from the partial. */
+ if (partial->pt_dict != NULL
+ && (selfdict_in == NULL || !partial->pt_auto))
+ selfdict = partial->pt_dict;
+ if (error == ERROR_NONE && partial->pt_argc > 0)
+ {
+ for (argv_clear = 0; argv_clear < partial->pt_argc; ++argv_clear)
+ copy_tv(&partial->pt_argv[argv_clear], &argv[argv_clear]);
+ for (i = 0; i < argcount_in; ++i)
+ argv[i + argv_clear] = argvars_in[i];
+ argvars = argv;
+ argcount = partial->pt_argc + argcount_in;
+ }
+ }
+
+
+ /*
+ * Execute the function if executing and no errors were detected.
+ */
+ if (!evaluate)
+ {
+ // Not evaluating, which means the return value is unknown. This
+ // matters for giving error messages.
+ rettv->v_type = VAR_UNKNOWN;
+ }
+ else if (error == ERROR_NONE)
+ {
+ char_u *rfname = fname;
+
+ /* Ignore "g:" before a function name. */
+ if (fname[0] == 'g' && fname[1] == ':')
+ rfname = fname + 2;
+
+ rettv->v_type = VAR_NUMBER; /* default rettv is number zero */
+ rettv->vval.v_number = 0;
+ error = ERROR_UNKNOWN;
+
+ if (!builtin_function(rfname, -1))
+ {
+ /*
+ * User defined function.
+ */
+ if (partial != NULL && partial->pt_func != NULL)
+ fp = partial->pt_func;
+ else
+ fp = find_func(rfname);
+
+ /* Trigger FuncUndefined event, may load the function. */
+ if (fp == NULL
+ && apply_autocmds(EVENT_FUNCUNDEFINED,
+ rfname, rfname, TRUE, NULL)
+ && !aborting())
+ {
+ /* executed an autocommand, search for the function again */
+ fp = find_func(rfname);
+ }
+ /* Try loading a package. */
+ if (fp == NULL && script_autoload(rfname, TRUE) && !aborting())
+ {
+ /* loaded a package, search for the function again */
+ fp = find_func(rfname);
+ }
+
+ if (fp != NULL && (fp->uf_flags & FC_DELETED))
+ error = ERROR_DELETED;
+ else if (fp != NULL)
+ {
+ if (argv_func != NULL)
+ argcount = argv_func(argcount, argvars, fp->uf_args.ga_len);
+
+ if (fp->uf_flags & FC_RANGE)
+ *doesrange = TRUE;
+ if (argcount < fp->uf_args.ga_len)
+ error = ERROR_TOOFEW;
+ else if (!fp->uf_varargs && argcount > fp->uf_args.ga_len)
+ error = ERROR_TOOMANY;
+ else if ((fp->uf_flags & FC_DICT) && selfdict == NULL)
+ error = ERROR_DICT;
+ else
+ {
+ int did_save_redo = FALSE;
+ save_redo_T save_redo;
+
+ /*
+ * Call the user function.
+ * Save and restore search patterns, script variables and
+ * redo buffer.
+ */
+ save_search_patterns();
+#ifdef FEAT_INS_EXPAND
+ if (!ins_compl_active())
+#endif
+ {
+ saveRedobuff(&save_redo);
+ did_save_redo = TRUE;
+ }
+ ++fp->uf_calls;
+ call_user_func(fp, argcount, argvars, rettv,
+ firstline, lastline,
+ (fp->uf_flags & FC_DICT) ? selfdict : NULL);
+ if (--fp->uf_calls <= 0 && fp->uf_refcount <= 0)
+ /* Function was unreferenced while being used, free it
+ * now. */
+ func_clear_free(fp, FALSE);
+ if (did_save_redo)
+ restoreRedobuff(&save_redo);
+ restore_search_patterns();
+ error = ERROR_NONE;
+ }
+ }
+ }
+ else
+ {
+ /*
+ * Find the function name in the table, call its implementation.
+ */
+ error = call_internal_func(fname, argcount, argvars, rettv);
+ }
+ /*
+ * The function call (or "FuncUndefined" autocommand sequence) might
+ * have been aborted by an error, an interrupt, or an explicitly thrown
+ * exception that has not been caught so far. This situation can be
+ * tested for by calling aborting(). For an error in an internal
+ * function or for the "E132" error in call_user_func(), however, the
+ * throw point at which the "force_abort" flag (temporarily reset by
+ * emsg()) is normally updated has not been reached yet. We need to
+ * update that flag first to make aborting() reliable.
+ */
+ update_force_abort();
+ }
+ if (error == ERROR_NONE)
+ ret = OK;
+
+ /*
+ * Report an error unless the argument evaluation or function call has been
+ * cancelled due to an aborting error, an interrupt, or an exception.
+ */
+ if (!aborting())
+ {
+ switch (error)
+ {
+ case ERROR_UNKNOWN:
+ emsg_funcname(N_("E117: Unknown function: %s"), name);
+ break;
+ case ERROR_DELETED:
+ emsg_funcname(N_("E933: Function was deleted: %s"), name);
+ break;
+ case ERROR_TOOMANY:
+ emsg_funcname((char *)e_toomanyarg, name);
+ break;
+ case ERROR_TOOFEW:
+ emsg_funcname(N_("E119: Not enough arguments for function: %s"),
+ name);
+ break;
+ case ERROR_SCRIPT:
+ emsg_funcname(N_("E120: Using <SID> not in a script context: %s"),
+ name);
+ break;
+ case ERROR_DICT:
+ emsg_funcname(N_("E725: Calling dict function without Dictionary: %s"),
+ name);
+ break;
+ }
+ }
+
+ while (argv_clear > 0)
+ clear_tv(&argv[--argv_clear]);
+ vim_free(tofree);
+ vim_free(name);
+
+ return ret;
+}
+
+/*
+ * List the head of the function: "name(arg1, arg2)".
+ */
+ static void
+list_func_head(ufunc_T *fp, int indent)
+{
+ int j;
+
+ msg_start();
+ if (indent)
+ msg_puts(" ");
+ msg_puts("function ");
+ if (fp->uf_name[0] == K_SPECIAL)
+ {
+ msg_puts_attr("<SNR>", HL_ATTR(HLF_8));
+ msg_puts((char *)fp->uf_name + 3);
+ }
+ else
+ msg_puts((char *)fp->uf_name);
+ msg_putchar('(');
+ for (j = 0; j < fp->uf_args.ga_len; ++j)
+ {
+ if (j)
+ msg_puts(", ");
+ msg_puts((char *)FUNCARG(fp, j));
+ }
+ if (fp->uf_varargs)
+ {
+ if (j)
+ msg_puts(", ");
+ msg_puts("...");
+ }
+ msg_putchar(')');
+ if (fp->uf_flags & FC_ABORT)
+ msg_puts(" abort");
+ if (fp->uf_flags & FC_RANGE)
+ msg_puts(" range");
+ if (fp->uf_flags & FC_DICT)
+ msg_puts(" dict");
+ if (fp->uf_flags & FC_CLOSURE)
+ msg_puts(" closure");
+ msg_clr_eos();
+ if (p_verbose > 0)
+ last_set_msg(fp->uf_script_ctx);
+}
+
+/*
+ * Get a function name, translating "<SID>" and "<SNR>".
+ * Also handles a Funcref in a List or Dictionary.
+ * Returns the function name in allocated memory, or NULL for failure.
+ * flags:
+ * TFN_INT: internal function name OK
+ * TFN_QUIET: be quiet
+ * TFN_NO_AUTOLOAD: do not use script autoloading
+ * TFN_NO_DEREF: do not dereference a Funcref
+ * Advances "pp" to just after the function name (if no error).
+ */
+ char_u *
+trans_function_name(
+ char_u **pp,
+ int skip, /* only find the end, don't evaluate */
+ int flags,
+ funcdict_T *fdp, /* return: info about dictionary used */
+ partial_T **partial) /* return: partial of a FuncRef */
+{
+ char_u *name = NULL;
+ char_u *start;
+ char_u *end;
+ int lead;
+ char_u sid_buf[20];
+ int len;
+ lval_T lv;
+
+ if (fdp != NULL)
+ vim_memset(fdp, 0, sizeof(funcdict_T));
+ start = *pp;
+
+ /* Check for hard coded <SNR>: already translated function ID (from a user
+ * command). */
+ if ((*pp)[0] == K_SPECIAL && (*pp)[1] == KS_EXTRA
+ && (*pp)[2] == (int)KE_SNR)
+ {
+ *pp += 3;
+ len = get_id_len(pp) + 3;
+ return vim_strnsave(start, len);
+ }
+
+ /* A name starting with "<SID>" or "<SNR>" is local to a script. But
+ * don't skip over "s:", get_lval() needs it for "s:dict.func". */
+ lead = eval_fname_script(start);
+ if (lead > 2)
+ start += lead;
+
+ /* Note that TFN_ flags use the same values as GLV_ flags. */
+ end = get_lval(start, NULL, &lv, FALSE, skip, flags | GLV_READ_ONLY,
+ lead > 2 ? 0 : FNE_CHECK_START);
+ if (end == start)
+ {
+ if (!skip)
+ emsg(_("E129: Function name required"));
+ goto theend;
+ }
+ if (end == NULL || (lv.ll_tv != NULL && (lead > 2 || lv.ll_range)))
+ {
+ /*
+ * Report an invalid expression in braces, unless the expression
+ * evaluation has been cancelled due to an aborting error, an
+ * interrupt, or an exception.
+ */
+ if (!aborting())
+ {
+ if (end != NULL)
+ semsg(_(e_invarg2), start);
+ }
+ else
+ *pp = find_name_end(start, NULL, NULL, FNE_INCL_BR);
+ goto theend;
+ }
+
+ if (lv.ll_tv != NULL)
+ {
+ if (fdp != NULL)
+ {
+ fdp->fd_dict = lv.ll_dict;
+ fdp->fd_newkey = lv.ll_newkey;
+ lv.ll_newkey = NULL;
+ fdp->fd_di = lv.ll_di;
+ }
+ if (lv.ll_tv->v_type == VAR_FUNC && lv.ll_tv->vval.v_string != NULL)
+ {
+ name = vim_strsave(lv.ll_tv->vval.v_string);
+ *pp = end;
+ }
+ else if (lv.ll_tv->v_type == VAR_PARTIAL
+ && lv.ll_tv->vval.v_partial != NULL)
+ {
+ name = vim_strsave(partial_name(lv.ll_tv->vval.v_partial));
+ *pp = end;
+ if (partial != NULL)
+ *partial = lv.ll_tv->vval.v_partial;
+ }
+ else
+ {
+ if (!skip && !(flags & TFN_QUIET) && (fdp == NULL
+ || lv.ll_dict == NULL || fdp->fd_newkey == NULL))
+ emsg(_(e_funcref));
+ else
+ *pp = end;
+ name = NULL;
+ }
+ goto theend;
+ }
+
+ if (lv.ll_name == NULL)
+ {
+ /* Error found, but continue after the function name. */
+ *pp = end;
+ goto theend;
+ }
+
+ /* Check if the name is a Funcref. If so, use the value. */
+ if (lv.ll_exp_name != NULL)
+ {
+ len = (int)STRLEN(lv.ll_exp_name);
+ name = deref_func_name(lv.ll_exp_name, &len, partial,
+ flags & TFN_NO_AUTOLOAD);
+ if (name == lv.ll_exp_name)
+ name = NULL;
+ }
+ else if (!(flags & TFN_NO_DEREF))
+ {
+ len = (int)(end - *pp);
+ name = deref_func_name(*pp, &len, partial, flags & TFN_NO_AUTOLOAD);
+ if (name == *pp)
+ name = NULL;
+ }
+ if (name != NULL)
+ {
+ name = vim_strsave(name);
+ *pp = end;
+ if (STRNCMP(name, "<SNR>", 5) == 0)
+ {
+ /* Change "<SNR>" to the byte sequence. */
+ name[0] = K_SPECIAL;
+ name[1] = KS_EXTRA;
+ name[2] = (int)KE_SNR;
+ mch_memmove(name + 3, name + 5, STRLEN(name + 5) + 1);
+ }
+ goto theend;
+ }
+
+ if (lv.ll_exp_name != NULL)
+ {
+ len = (int)STRLEN(lv.ll_exp_name);
+ if (lead <= 2 && lv.ll_name == lv.ll_exp_name
+ && STRNCMP(lv.ll_name, "s:", 2) == 0)
+ {
+ /* When there was "s:" already or the name expanded to get a
+ * leading "s:" then remove it. */
+ lv.ll_name += 2;
+ len -= 2;
+ lead = 2;
+ }
+ }
+ else
+ {
+ /* skip over "s:" and "g:" */
+ if (lead == 2 || (lv.ll_name[0] == 'g' && lv.ll_name[1] == ':'))
+ lv.ll_name += 2;
+ len = (int)(end - lv.ll_name);
+ }
+
+ /*
+ * Copy the function name to allocated memory.
+ * Accept <SID>name() inside a script, translate into <SNR>123_name().
+ * Accept <SNR>123_name() outside a script.
+ */
+ if (skip)
+ lead = 0; /* do nothing */
+ else if (lead > 0)
+ {
+ lead = 3;
+ if ((lv.ll_exp_name != NULL && eval_fname_sid(lv.ll_exp_name))
+ || eval_fname_sid(*pp))
+ {
+ /* It's "s:" or "<SID>" */
+ if (current_sctx.sc_sid <= 0)
+ {
+ emsg(_(e_usingsid));
+ goto theend;
+ }
+ sprintf((char *)sid_buf, "%ld_", (long)current_sctx.sc_sid);
+ lead += (int)STRLEN(sid_buf);
+ }
+ }
+ else if (!(flags & TFN_INT) && builtin_function(lv.ll_name, len))
+ {
+ semsg(_("E128: Function name must start with a capital or \"s:\": %s"),
+ start);
+ goto theend;
+ }
+ if (!skip && !(flags & TFN_QUIET) && !(flags & TFN_NO_DEREF))
+ {
+ char_u *cp = vim_strchr(lv.ll_name, ':');
+
+ if (cp != NULL && cp < end)
+ {
+ semsg(_("E884: Function name cannot contain a colon: %s"), start);
+ goto theend;
+ }
+ }
+
+ name = alloc((unsigned)(len + lead + 1));
+ if (name != NULL)
+ {
+ if (lead > 0)
+ {
+ name[0] = K_SPECIAL;
+ name[1] = KS_EXTRA;
+ name[2] = (int)KE_SNR;
+ if (lead > 3) /* If it's "<SID>" */
+ STRCPY(name + 3, sid_buf);
+ }
+ mch_memmove(name + lead, lv.ll_name, (size_t)len);
+ name[lead + len] = NUL;
+ }
+ *pp = end;
+
+theend:
+ clear_lval(&lv);
+ return name;
+}
+
+/*
+ * ":function"
+ */
+ void
+ex_function(exarg_T *eap)
+{
+ char_u *theline;
+ char_u *line_to_free = NULL;
+ int j;
+ int c;
+ int saved_did_emsg;
+ int saved_wait_return = need_wait_return;
+ char_u *name = NULL;
+ char_u *p;
+ char_u *arg;
+ char_u *line_arg = NULL;
+ garray_T newargs;
+ garray_T newlines;
+ int varargs = FALSE;
+ int flags = 0;
+ ufunc_T *fp;
+ int overwrite = FALSE;
+ int indent;
+ int nesting;
+ char_u *skip_until = NULL;
+ dictitem_T *v;
+ funcdict_T fudi;
+ static int func_nr = 0; /* number for nameless function */
+ int paren;
+ hashtab_T *ht;
+ int todo;
+ hashitem_T *hi;
+ int sourcing_lnum_off;
+
+ /*
+ * ":function" without argument: list functions.
+ */
+ if (ends_excmd(*eap->arg))
+ {
+ if (!eap->skip)
+ {
+ todo = (int)func_hashtab.ht_used;
+ for (hi = func_hashtab.ht_array; todo > 0 && !got_int; ++hi)
+ {
+ if (!HASHITEM_EMPTY(hi))
+ {
+ --todo;
+ fp = HI2UF(hi);
+ if (message_filtered(fp->uf_name))
+ continue;
+ if (!func_name_refcount(fp->uf_name))
+ list_func_head(fp, FALSE);
+ }
+ }
+ }
+ eap->nextcmd = check_nextcmd(eap->arg);
+ return;
+ }
+
+ /*
+ * ":function /pat": list functions matching pattern.
+ */
+ if (*eap->arg == '/')
+ {
+ p = skip_regexp(eap->arg + 1, '/', TRUE, NULL);
+ if (!eap->skip)
+ {
+ regmatch_T regmatch;
+
+ c = *p;
+ *p = NUL;
+ regmatch.regprog = vim_regcomp(eap->arg + 1, RE_MAGIC);
+ *p = c;
+ if (regmatch.regprog != NULL)
+ {
+ regmatch.rm_ic = p_ic;
+
+ todo = (int)func_hashtab.ht_used;
+ for (hi = func_hashtab.ht_array; todo > 0 && !got_int; ++hi)
+ {
+ if (!HASHITEM_EMPTY(hi))
+ {
+ --todo;
+ fp = HI2UF(hi);
+ if (!isdigit(*fp->uf_name)
+ && vim_regexec(&regmatch, fp->uf_name, 0))
+ list_func_head(fp, FALSE);
+ }
+ }
+ vim_regfree(regmatch.regprog);
+ }
+ }
+ if (*p == '/')
+ ++p;
+ eap->nextcmd = check_nextcmd(p);
+ return;
+ }
+
+ /*
+ * Get the function name. There are these situations:
+ * func normal function name
+ * "name" == func, "fudi.fd_dict" == NULL
+ * dict.func new dictionary entry
+ * "name" == NULL, "fudi.fd_dict" set,
+ * "fudi.fd_di" == NULL, "fudi.fd_newkey" == func
+ * dict.func existing dict entry with a Funcref
+ * "name" == func, "fudi.fd_dict" set,
+ * "fudi.fd_di" set, "fudi.fd_newkey" == NULL
+ * dict.func existing dict entry that's not a Funcref
+ * "name" == NULL, "fudi.fd_dict" set,
+ * "fudi.fd_di" set, "fudi.fd_newkey" == NULL
+ * s:func script-local function name
+ * g:func global function name, same as "func"
+ */
+ p = eap->arg;
+ name = trans_function_name(&p, eap->skip, TFN_NO_AUTOLOAD, &fudi, NULL);
+ paren = (vim_strchr(p, '(') != NULL);
+ if (name == NULL && (fudi.fd_dict == NULL || !paren) && !eap->skip)
+ {
+ /*
+ * Return on an invalid expression in braces, unless the expression
+ * evaluation has been cancelled due to an aborting error, an
+ * interrupt, or an exception.
+ */
+ if (!aborting())
+ {
+ if (!eap->skip && fudi.fd_newkey != NULL)
+ semsg(_(e_dictkey), fudi.fd_newkey);
+ vim_free(fudi.fd_newkey);
+ return;
+ }
+ else
+ eap->skip = TRUE;
+ }
+
+ /* An error in a function call during evaluation of an expression in magic
+ * braces should not cause the function not to be defined. */
+ saved_did_emsg = did_emsg;
+ did_emsg = FALSE;
+
+ /*
+ * ":function func" with only function name: list function.
+ */
+ if (!paren)
+ {
+ if (!ends_excmd(*skipwhite(p)))
+ {
+ emsg(_(e_trailing));
+ goto ret_free;
+ }
+ eap->nextcmd = check_nextcmd(p);
+ if (eap->nextcmd != NULL)
+ *p = NUL;
+ if (!eap->skip && !got_int)
+ {
+ fp = find_func(name);
+ if (fp != NULL)
+ {
+ list_func_head(fp, TRUE);
+ for (j = 0; j < fp->uf_lines.ga_len && !got_int; ++j)
+ {
+ if (FUNCLINE(fp, j) == NULL)
+ continue;
+ msg_putchar('\n');
+ msg_outnum((long)(j + 1));
+ if (j < 9)
+ msg_putchar(' ');
+ if (j < 99)
+ msg_putchar(' ');
+ msg_prt_line(FUNCLINE(fp, j), FALSE);
+ out_flush(); /* show a line at a time */
+ ui_breakcheck();
+ }
+ if (!got_int)
+ {
+ msg_putchar('\n');
+ msg_puts(" endfunction");
+ }
+ }
+ else
+ emsg_funcname(N_("E123: Undefined function: %s"), name);
+ }
+ goto ret_free;
+ }
+
+ /*
+ * ":function name(arg1, arg2)" Define function.
+ */
+ p = skipwhite(p);
+ if (*p != '(')
+ {
+ if (!eap->skip)
+ {
+ semsg(_("E124: Missing '(': %s"), eap->arg);
+ goto ret_free;
+ }
+ /* attempt to continue by skipping some text */
+ if (vim_strchr(p, '(') != NULL)
+ p = vim_strchr(p, '(');
+ }
+ p = skipwhite(p + 1);
+
+ ga_init2(&newlines, (int)sizeof(char_u *), 3);
+
+ if (!eap->skip)
+ {
+ /* Check the name of the function. Unless it's a dictionary function
+ * (that we are overwriting). */
+ if (name != NULL)
+ arg = name;
+ else
+ arg = fudi.fd_newkey;
+ if (arg != NULL && (fudi.fd_di == NULL
+ || (fudi.fd_di->di_tv.v_type != VAR_FUNC
+ && fudi.fd_di->di_tv.v_type != VAR_PARTIAL)))
+ {
+ if (*arg == K_SPECIAL)
+ j = 3;
+ else
+ j = 0;
+ while (arg[j] != NUL && (j == 0 ? eval_isnamec1(arg[j])
+ : eval_isnamec(arg[j])))
+ ++j;
+ if (arg[j] != NUL)
+ emsg_funcname((char *)e_invarg2, arg);
+ }
+ /* Disallow using the g: dict. */
+ if (fudi.fd_dict != NULL && fudi.fd_dict->dv_scope == VAR_DEF_SCOPE)
+ emsg(_("E862: Cannot use g: here"));
+ }
+
+ if (get_function_args(&p, ')', &newargs, &varargs, eap->skip) == FAIL)
+ goto errret_2;
+
+ /* find extra arguments "range", "dict", "abort" and "closure" */
+ for (;;)
+ {
+ p = skipwhite(p);
+ if (STRNCMP(p, "range", 5) == 0)
+ {
+ flags |= FC_RANGE;
+ p += 5;
+ }
+ else if (STRNCMP(p, "dict", 4) == 0)
+ {
+ flags |= FC_DICT;
+ p += 4;
+ }
+ else if (STRNCMP(p, "abort", 5) == 0)
+ {
+ flags |= FC_ABORT;
+ p += 5;
+ }
+ else if (STRNCMP(p, "closure", 7) == 0)
+ {
+ flags |= FC_CLOSURE;
+ p += 7;
+ if (current_funccal == NULL)
+ {
+ emsg_funcname(N_("E932: Closure function should not be at top level: %s"),
+ name == NULL ? (char_u *)"" : name);
+ goto erret;
+ }
+ }
+ else
+ break;
+ }
+
+ /* When there is a line break use what follows for the function body.
+ * Makes 'exe "func Test()\n...\nendfunc"' work. */
+ if (*p == '\n')
+ line_arg = p + 1;
+ else if (*p != NUL && *p != '"' && !eap->skip && !did_emsg)
+ emsg(_(e_trailing));
+
+ /*
+ * Read the body of the function, until ":endfunction" is found.
+ */
+ if (KeyTyped)
+ {
+ /* Check if the function already exists, don't let the user type the
+ * whole function before telling him it doesn't work! For a script we
+ * need to skip the body to be able to find what follows. */
+ if (!eap->skip && !eap->forceit)
+ {
+ if (fudi.fd_dict != NULL && fudi.fd_newkey == NULL)
+ emsg(_(e_funcdict));
+ else if (name != NULL && find_func(name) != NULL)
+ emsg_funcname(e_funcexts, name);
+ }
+
+ if (!eap->skip && did_emsg)
+ goto erret;
+
+ msg_putchar('\n'); /* don't overwrite the function name */
+ cmdline_row = msg_row;
+ }
+
+ indent = 2;
+ nesting = 0;
+ for (;;)
+ {
+ if (KeyTyped)
+ {
+ msg_scroll = TRUE;
+ saved_wait_return = FALSE;
+ }
+ need_wait_return = FALSE;
+ sourcing_lnum_off = sourcing_lnum;
+
+ if (line_arg != NULL)
+ {
+ /* Use eap->arg, split up in parts by line breaks. */
+ theline = line_arg;
+ p = vim_strchr(theline, '\n');
+ if (p == NULL)
+ line_arg += STRLEN(line_arg);
+ else
+ {
+ *p = NUL;
+ line_arg = p + 1;
+ }
+ }
+ else
+ {
+ vim_free(line_to_free);
+ if (eap->getline == NULL)
+ theline = getcmdline(':', 0L, indent);
+ else
+ theline = eap->getline(':', eap->cookie, indent);
+ line_to_free = theline;
+ }
+ if (KeyTyped)
+ lines_left = Rows - 1;
+ if (theline == NULL)
+ {
+ emsg(_("E126: Missing :endfunction"));
+ goto erret;
+ }
+
+ /* Detect line continuation: sourcing_lnum increased more than one. */
+ if (sourcing_lnum > sourcing_lnum_off + 1)
+ sourcing_lnum_off = sourcing_lnum - sourcing_lnum_off - 1;
+ else
+ sourcing_lnum_off = 0;
+
+ if (skip_until != NULL)
+ {
+ /* between ":append" and "." and between ":python <<EOF" and "EOF"
+ * don't check for ":endfunc". */
+ if (STRCMP(theline, skip_until) == 0)
+ VIM_CLEAR(skip_until);
+ }
+ else
+ {
+ /* skip ':' and blanks*/
+ for (p = theline; VIM_ISWHITE(*p) || *p == ':'; ++p)
+ ;
+
+ /* Check for "endfunction". */
+ if (checkforcmd(&p, "endfunction", 4) && nesting-- == 0)
+ {
+ char_u *nextcmd = NULL;
+
+ if (*p == '|')
+ nextcmd = p + 1;
+ else if (line_arg != NULL && *skipwhite(line_arg) != NUL)
+ nextcmd = line_arg;
+ else if (*p != NUL && *p != '"' && p_verbose > 0)
+ give_warning2(
+ (char_u *)_("W22: Text found after :endfunction: %s"),
+ p, TRUE);
+ if (nextcmd != NULL)
+ {
+ /* Another command follows. If the line came from "eap" we
+ * can simply point into it, otherwise we need to change
+ * "eap->cmdlinep". */
+ eap->nextcmd = nextcmd;
+ if (line_to_free != NULL)
+ {
+ vim_free(*eap->cmdlinep);
+ *eap->cmdlinep = line_to_free;
+ line_to_free = NULL;
+ }
+ }
+ break;
+ }
+
+ /* Increase indent inside "if", "while", "for" and "try", decrease
+ * at "end". */
+ if (indent > 2 && STRNCMP(p, "end", 3) == 0)
+ indent -= 2;
+ else if (STRNCMP(p, "if", 2) == 0
+ || STRNCMP(p, "wh", 2) == 0
+ || STRNCMP(p, "for", 3) == 0
+ || STRNCMP(p, "try", 3) == 0)
+ indent += 2;
+
+ /* Check for defining a function inside this function. */
+ if (checkforcmd(&p, "function", 2))
+ {
+ if (*p == '!')
+ p = skipwhite(p + 1);
+ p += eval_fname_script(p);
+ vim_free(trans_function_name(&p, TRUE, 0, NULL, NULL));
+ if (*skipwhite(p) == '(')
+ {
+ ++nesting;
+ indent += 2;
+ }
+ }
+
+ /* Check for ":append", ":change", ":insert". */
+ p = skip_range(p, NULL);
+ if ((p[0] == 'a' && (!ASCII_ISALPHA(p[1]) || p[1] == 'p'))
+ || (p[0] == 'c'
+ && (!ASCII_ISALPHA(p[1]) || (p[1] == 'h'
+ && (!ASCII_ISALPHA(p[2]) || (p[2] == 'a'
+ && (STRNCMP(&p[3], "nge", 3) != 0
+ || !ASCII_ISALPHA(p[6])))))))
+ || (p[0] == 'i'
+ && (!ASCII_ISALPHA(p[1]) || (p[1] == 'n'
+ && (!ASCII_ISALPHA(p[2]) || (p[2] == 's'))))))
+ skip_until = vim_strsave((char_u *)".");
+
+ /* Check for ":python <<EOF", ":tcl <<EOF", etc. */
+ arg = skipwhite(skiptowhite(p));
+ if (arg[0] == '<' && arg[1] =='<'
+ && ((p[0] == 'p' && p[1] == 'y'
+ && (!ASCII_ISALNUM(p[2]) || p[2] == 't'
+ || ((p[2] == '3' || p[2] == 'x')
+ && !ASCII_ISALPHA(p[3]))))
+ || (p[0] == 'p' && p[1] == 'e'
+ && (!ASCII_ISALPHA(p[2]) || p[2] == 'r'))
+ || (p[0] == 't' && p[1] == 'c'
+ && (!ASCII_ISALPHA(p[2]) || p[2] == 'l'))
+ || (p[0] == 'l' && p[1] == 'u' && p[2] == 'a'
+ && !ASCII_ISALPHA(p[3]))
+ || (p[0] == 'r' && p[1] == 'u' && p[2] == 'b'
+ && (!ASCII_ISALPHA(p[3]) || p[3] == 'y'))
+ || (p[0] == 'm' && p[1] == 'z'
+ && (!ASCII_ISALPHA(p[2]) || p[2] == 's'))
+ ))
+ {
+ /* ":python <<" continues until a dot, like ":append" */
+ p = skipwhite(arg + 2);
+ if (*p == NUL)
+ skip_until = vim_strsave((char_u *)".");
+ else
+ skip_until = vim_strsave(p);
+ }
+ }
+
+ /* Add the line to the function. */
+ if (ga_grow(&newlines, 1 + sourcing_lnum_off) == FAIL)
+ goto erret;
+
+ /* Copy the line to newly allocated memory. get_one_sourceline()
+ * allocates 250 bytes per line, this saves 80% on average. The cost
+ * is an extra alloc/free. */
+ p = vim_strsave(theline);
+ if (p == NULL)
+ goto erret;
+ ((char_u **)(newlines.ga_data))[newlines.ga_len++] = p;
+
+ /* Add NULL lines for continuation lines, so that the line count is
+ * equal to the index in the growarray. */
+ while (sourcing_lnum_off-- > 0)
+ ((char_u **)(newlines.ga_data))[newlines.ga_len++] = NULL;
+
+ /* Check for end of eap->arg. */
+ if (line_arg != NULL && *line_arg == NUL)
+ line_arg = NULL;
+ }
+
+ /* Don't define the function when skipping commands or when an error was
+ * detected. */
+ if (eap->skip || did_emsg)
+ goto erret;
+
+ /*
+ * If there are no errors, add the function
+ */
+ if (fudi.fd_dict == NULL)
+ {
+ v = find_var(name, &ht, FALSE);
+ if (v != NULL && v->di_tv.v_type == VAR_FUNC)
+ {
+ emsg_funcname(N_("E707: Function name conflicts with variable: %s"),
+ name);
+ goto erret;
+ }
+
+ fp = find_func(name);
+ if (fp != NULL)
+ {
+ // Function can be replaced with "function!" and when sourcing the
+ // same script again, but only once.
+ if (!eap->forceit
+ && (fp->uf_script_ctx.sc_sid != current_sctx.sc_sid
+ || fp->uf_script_ctx.sc_seq == current_sctx.sc_seq))
+ {
+ emsg_funcname(e_funcexts, name);
+ goto erret;
+ }
+ if (fp->uf_calls > 0)
+ {
+ emsg_funcname(
+ N_("E127: Cannot redefine function %s: It is in use"),
+ name);
+ goto erret;
+ }
+ if (fp->uf_refcount > 1)
+ {
+ /* This function is referenced somewhere, don't redefine it but
+ * create a new one. */
+ --fp->uf_refcount;
+ fp->uf_flags |= FC_REMOVED;
+ fp = NULL;
+ overwrite = TRUE;
+ }
+ else
+ {
+ /* redefine existing function */
+ VIM_CLEAR(name);
+ func_clear_items(fp);
+#ifdef FEAT_PROFILE
+ fp->uf_profiling = FALSE;
+ fp->uf_prof_initialized = FALSE;
+#endif
+ }
+ }
+ }
+ else
+ {
+ char numbuf[20];
+
+ fp = NULL;
+ if (fudi.fd_newkey == NULL && !eap->forceit)
+ {
+ emsg(_(e_funcdict));
+ goto erret;
+ }
+ if (fudi.fd_di == NULL)
+ {
+ /* Can't add a function to a locked dictionary */
+ if (tv_check_lock(fudi.fd_dict->dv_lock, eap->arg, FALSE))
+ goto erret;
+ }
+ /* Can't change an existing function if it is locked */
+ else if (tv_check_lock(fudi.fd_di->di_tv.v_lock, eap->arg, FALSE))
+ goto erret;
+
+ /* Give the function a sequential number. Can only be used with a
+ * Funcref! */
+ vim_free(name);
+ sprintf(numbuf, "%d", ++func_nr);
+ name = vim_strsave((char_u *)numbuf);
+ if (name == NULL)
+ goto erret;
+ }
+
+ if (fp == NULL)
+ {
+ if (fudi.fd_dict == NULL && vim_strchr(name, AUTOLOAD_CHAR) != NULL)
+ {
+ int slen, plen;
+ char_u *scriptname;
+
+ /* Check that the autoload name matches the script name. */
+ j = FAIL;
+ if (sourcing_name != NULL)
+ {
+ scriptname = autoload_name(name);
+ if (scriptname != NULL)
+ {
+ p = vim_strchr(scriptname, '/');
+ plen = (int)STRLEN(p);
+ slen = (int)STRLEN(sourcing_name);
+ if (slen > plen && fnamecmp(p,
+ sourcing_name + slen - plen) == 0)
+ j = OK;
+ vim_free(scriptname);
+ }
+ }
+ if (j == FAIL)
+ {
+ semsg(_("E746: Function name does not match script file name: %s"), name);
+ goto erret;
+ }
+ }
+
+ fp = (ufunc_T *)alloc_clear((unsigned)(sizeof(ufunc_T) + STRLEN(name)));
+ if (fp == NULL)
+ goto erret;
+
+ if (fudi.fd_dict != NULL)
+ {
+ if (fudi.fd_di == NULL)
+ {
+ /* add new dict entry */
+ fudi.fd_di = dictitem_alloc(fudi.fd_newkey);
+ if (fudi.fd_di == NULL)
+ {
+ vim_free(fp);
+ goto erret;
+ }
+ if (dict_add(fudi.fd_dict, fudi.fd_di) == FAIL)
+ {
+ vim_free(fudi.fd_di);
+ vim_free(fp);
+ goto erret;
+ }
+ }
+ else
+ /* overwrite existing dict entry */
+ clear_tv(&fudi.fd_di->di_tv);
+ fudi.fd_di->di_tv.v_type = VAR_FUNC;
+ fudi.fd_di->di_tv.vval.v_string = vim_strsave(name);
+
+ /* behave like "dict" was used */
+ flags |= FC_DICT;
+ }
+
+ /* insert the new function in the function list */
+ STRCPY(fp->uf_name, name);
+ if (overwrite)
+ {
+ hi = hash_find(&func_hashtab, name);
+ hi->hi_key = UF2HIKEY(fp);
+ }
+ else if (hash_add(&func_hashtab, UF2HIKEY(fp)) == FAIL)
+ {
+ vim_free(fp);
+ goto erret;
+ }
+ fp->uf_refcount = 1;
+ }
+ fp->uf_args = newargs;
+ fp->uf_lines = newlines;
+ if ((flags & FC_CLOSURE) != 0)
+ {
+ if (register_closure(fp) == FAIL)
+ goto erret;
+ }
+ else
+ fp->uf_scoped = NULL;
+
+#ifdef FEAT_PROFILE
+ if (prof_def_func())
+ func_do_profile(fp);
+#endif
+ fp->uf_varargs = varargs;
+ if (sandbox)
+ flags |= FC_SANDBOX;
+ fp->uf_flags = flags;
+ fp->uf_calls = 0;
+ fp->uf_script_ctx = current_sctx;
+ fp->uf_script_ctx.sc_lnum += sourcing_lnum - newlines.ga_len - 1;
+ goto ret_free;
+
+erret:
+ ga_clear_strings(&newargs);
+errret_2:
+ ga_clear_strings(&newlines);
+ret_free:
+ vim_free(skip_until);
+ vim_free(line_to_free);
+ vim_free(fudi.fd_newkey);
+ vim_free(name);
+ did_emsg |= saved_did_emsg;
+ need_wait_return |= saved_wait_return;
+}
+
+/*
+ * Return 5 if "p" starts with "<SID>" or "<SNR>" (ignoring case).
+ * Return 2 if "p" starts with "s:".
+ * Return 0 otherwise.
+ */
+ int
+eval_fname_script(char_u *p)
+{
+ /* Use MB_STRICMP() because in Turkish comparing the "I" may not work with
+ * the standard library function. */
+ if (p[0] == '<' && (MB_STRNICMP(p + 1, "SID>", 4) == 0
+ || MB_STRNICMP(p + 1, "SNR>", 4) == 0))
+ return 5;
+ if (p[0] == 's' && p[1] == ':')
+ return 2;
+ return 0;
+}
+
+ int
+translated_function_exists(char_u *name)
+{
+ if (builtin_function(name, -1))
+ return find_internal_func(name) >= 0;
+ return find_func(name) != NULL;
+}
+
+/*
+ * Return TRUE if a function "name" exists.
+ * If "no_defef" is TRUE, do not dereference a Funcref.
+ */
+ int
+function_exists(char_u *name, int no_deref)
+{
+ char_u *nm = name;
+ char_u *p;
+ int n = FALSE;
+ int flag;
+
+ flag = TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD;
+ if (no_deref)
+ flag |= TFN_NO_DEREF;
+ p = trans_function_name(&nm, FALSE, flag, NULL, NULL);
+ nm = skipwhite(nm);
+
+ /* Only accept "funcname", "funcname ", "funcname (..." and
+ * "funcname(...", not "funcname!...". */
+ if (p != NULL && (*nm == NUL || *nm == '('))
+ n = translated_function_exists(p);
+ vim_free(p);
+ return n;
+}
+
+#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) || defined(PROTO)
+ char_u *
+get_expanded_name(char_u *name, int check)
+{
+ char_u *nm = name;
+ char_u *p;
+
+ p = trans_function_name(&nm, FALSE, TFN_INT|TFN_QUIET, NULL, NULL);
+
+ if (p != NULL && *nm == NUL)
+ if (!check || translated_function_exists(p))
+ return p;
+
+ vim_free(p);
+ return NULL;
+}
+#endif
+
+#if defined(FEAT_PROFILE) || defined(PROTO)
+/*
+ * Start profiling function "fp".
+ */
+ static void
+func_do_profile(ufunc_T *fp)
+{
+ int len = fp->uf_lines.ga_len;
+
+ if (!fp->uf_prof_initialized)
+ {
+ if (len == 0)
+ len = 1; /* avoid getting error for allocating zero bytes */
+ fp->uf_tm_count = 0;
+ profile_zero(&fp->uf_tm_self);
+ profile_zero(&fp->uf_tm_total);
+ if (fp->uf_tml_count == NULL)
+ fp->uf_tml_count = (int *)alloc_clear(
+ (unsigned)(sizeof(int) * len));
+ if (fp->uf_tml_total == NULL)
+ fp->uf_tml_total = (proftime_T *)alloc_clear(
+ (unsigned)(sizeof(proftime_T) * len));
+ if (fp->uf_tml_self == NULL)
+ fp->uf_tml_self = (proftime_T *)alloc_clear(
+ (unsigned)(sizeof(proftime_T) * len));
+ fp->uf_tml_idx = -1;
+ if (fp->uf_tml_count == NULL || fp->uf_tml_total == NULL
+ || fp->uf_tml_self == NULL)
+ return; /* out of memory */
+ fp->uf_prof_initialized = TRUE;
+ }
+
+ fp->uf_profiling = TRUE;
+}
+
+/*
+ * Dump the profiling results for all functions in file "fd".
+ */
+ void
+func_dump_profile(FILE *fd)
+{
+ hashitem_T *hi;
+ int todo;
+ ufunc_T *fp;
+ int i;
+ ufunc_T **sorttab;
+ int st_len = 0;
+ char_u *p;
+
+ todo = (int)func_hashtab.ht_used;
+ if (todo == 0)
+ return; /* nothing to dump */
+
+ sorttab = (ufunc_T **)alloc((unsigned)(sizeof(ufunc_T *) * todo));
+
+ for (hi = func_hashtab.ht_array; todo > 0; ++hi)
+ {
+ if (!HASHITEM_EMPTY(hi))
+ {
+ --todo;
+ fp = HI2UF(hi);
+ if (fp->uf_prof_initialized)
+ {
+ if (sorttab != NULL)
+ sorttab[st_len++] = fp;
+
+ if (fp->uf_name[0] == K_SPECIAL)
+ fprintf(fd, "FUNCTION <SNR>%s()\n", fp->uf_name + 3);
+ else
+ fprintf(fd, "FUNCTION %s()\n", fp->uf_name);
+ p = home_replace_save(NULL,
+ get_scriptname(fp->uf_script_ctx.sc_sid));
+ if (p != NULL)
+ {
+ fprintf(fd, " Defined: %s line %ld\n",
+ p, (long)fp->uf_script_ctx.sc_lnum);
+ vim_free(p);
+ }
+ if (fp->uf_tm_count == 1)
+ fprintf(fd, "Called 1 time\n");
+ else
+ fprintf(fd, "Called %d times\n", fp->uf_tm_count);
+ fprintf(fd, "Total time: %s\n", profile_msg(&fp->uf_tm_total));
+ fprintf(fd, " Self time: %s\n", profile_msg(&fp->uf_tm_self));
+ fprintf(fd, "\n");
+ fprintf(fd, "count total (s) self (s)\n");
+
+ for (i = 0; i < fp->uf_lines.ga_len; ++i)
+ {
+ if (FUNCLINE(fp, i) == NULL)
+ continue;
+ prof_func_line(fd, fp->uf_tml_count[i],
+ &fp->uf_tml_total[i], &fp->uf_tml_self[i], TRUE);
+ fprintf(fd, "%s\n", FUNCLINE(fp, i));
+ }
+ fprintf(fd, "\n");
+ }
+ }
+ }
+
+ if (sorttab != NULL && st_len > 0)
+ {
+ qsort((void *)sorttab, (size_t)st_len, sizeof(ufunc_T *),
+ prof_total_cmp);
+ prof_sort_list(fd, sorttab, st_len, "TOTAL", FALSE);
+ qsort((void *)sorttab, (size_t)st_len, sizeof(ufunc_T *),
+ prof_self_cmp);
+ prof_sort_list(fd, sorttab, st_len, "SELF", TRUE);
+ }
+
+ vim_free(sorttab);
+}
+
+ static void
+prof_sort_list(
+ FILE *fd,
+ ufunc_T **sorttab,
+ int st_len,
+ char *title,
+ int prefer_self) /* when equal print only self time */
+{
+ int i;
+ ufunc_T *fp;
+
+ fprintf(fd, "FUNCTIONS SORTED ON %s TIME\n", title);
+ fprintf(fd, "count total (s) self (s) function\n");
+ for (i = 0; i < 20 && i < st_len; ++i)
+ {
+ fp = sorttab[i];
+ prof_func_line(fd, fp->uf_tm_count, &fp->uf_tm_total, &fp->uf_tm_self,
+ prefer_self);
+ if (fp->uf_name[0] == K_SPECIAL)
+ fprintf(fd, " <SNR>%s()\n", fp->uf_name + 3);
+ else
+ fprintf(fd, " %s()\n", fp->uf_name);
+ }
+ fprintf(fd, "\n");
+}
+
+/*
+ * Print the count and times for one function or function line.
+ */
+ static void
+prof_func_line(
+ FILE *fd,
+ int count,
+ proftime_T *total,
+ proftime_T *self,
+ int prefer_self) /* when equal print only self time */
+{
+ if (count > 0)
+ {
+ fprintf(fd, "%5d ", count);
+ if (prefer_self && profile_equal(total, self))
+ fprintf(fd, " ");
+ else
+ fprintf(fd, "%s ", profile_msg(total));
+ if (!prefer_self && profile_equal(total, self))
+ fprintf(fd, " ");
+ else
+ fprintf(fd, "%s ", profile_msg(self));
+ }
+ else
+ fprintf(fd, " ");
+}
+
+/*
+ * Compare function for total time sorting.
+ */
+ static int
+#ifdef __BORLANDC__
+_RTLENTRYF
+#endif
+prof_total_cmp(const void *s1, const void *s2)
+{
+ ufunc_T *p1, *p2;
+
+ p1 = *(ufunc_T **)s1;
+ p2 = *(ufunc_T **)s2;
+ return profile_cmp(&p1->uf_tm_total, &p2->uf_tm_total);
+}
+
+/*
+ * Compare function for self time sorting.
+ */
+ static int
+#ifdef __BORLANDC__
+_RTLENTRYF
+#endif
+prof_self_cmp(const void *s1, const void *s2)
+{
+ ufunc_T *p1, *p2;
+
+ p1 = *(ufunc_T **)s1;
+ p2 = *(ufunc_T **)s2;
+ return profile_cmp(&p1->uf_tm_self, &p2->uf_tm_self);
+}
+
+/*
+ * Prepare profiling for entering a child or something else that is not
+ * counted for the script/function itself.
+ * Should always be called in pair with prof_child_exit().
+ */
+ void
+prof_child_enter(
+ proftime_T *tm) /* place to store waittime */
+{
+ funccall_T *fc = current_funccal;
+
+ if (fc != NULL && fc->func->uf_profiling)
+ profile_start(&fc->prof_child);
+ script_prof_save(tm);
+}
+
+/*
+ * Take care of time spent in a child.
+ * Should always be called after prof_child_enter().
+ */
+ void
+prof_child_exit(
+ proftime_T *tm) /* where waittime was stored */
+{
+ funccall_T *fc = current_funccal;
+
+ if (fc != NULL && fc->func->uf_profiling)
+ {
+ profile_end(&fc->prof_child);
+ profile_sub_wait(tm, &fc->prof_child); /* don't count waiting time */
+ profile_add(&fc->func->uf_tm_children, &fc->prof_child);
+ profile_add(&fc->func->uf_tml_children, &fc->prof_child);
+ }
+ script_prof_restore(tm);
+}
+
+#endif /* FEAT_PROFILE */
+
+#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
+
+/*
+ * Function given to ExpandGeneric() to obtain the list of user defined
+ * function names.
+ */
+ char_u *
+get_user_func_name(expand_T *xp, int idx)
+{
+ static long_u done;
+ static hashitem_T *hi;
+ ufunc_T *fp;
+
+ if (idx == 0)
+ {
+ done = 0;
+ hi = func_hashtab.ht_array;
+ }
+ if (done < func_hashtab.ht_used)
+ {
+ if (done++ > 0)
+ ++hi;
+ while (HASHITEM_EMPTY(hi))
+ ++hi;
+ fp = HI2UF(hi);
+
+ if ((fp->uf_flags & FC_DICT)
+ || STRNCMP(fp->uf_name, "<lambda>", 8) == 0)
+ return (char_u *)""; /* don't show dict and lambda functions */
+
+ if (STRLEN(fp->uf_name) + 4 >= IOSIZE)
+ return fp->uf_name; /* prevents overflow */
+
+ cat_func_name(IObuff, fp);
+ if (xp->xp_context != EXPAND_USER_FUNC)
+ {
+ STRCAT(IObuff, "(");
+ if (!fp->uf_varargs && fp->uf_args.ga_len == 0)
+ STRCAT(IObuff, ")");
+ }
+ return IObuff;
+ }
+ return NULL;
+}
+
+#endif /* FEAT_CMDL_COMPL */
+
+/*
+ * ":delfunction {name}"
+ */
+ void
+ex_delfunction(exarg_T *eap)
+{
+ ufunc_T *fp = NULL;
+ char_u *p;
+ char_u *name;
+ funcdict_T fudi;
+
+ p = eap->arg;
+ name = trans_function_name(&p, eap->skip, 0, &fudi, NULL);
+ vim_free(fudi.fd_newkey);
+ if (name == NULL)
+ {
+ if (fudi.fd_dict != NULL && !eap->skip)
+ emsg(_(e_funcref));
+ return;
+ }
+ if (!ends_excmd(*skipwhite(p)))
+ {
+ vim_free(name);
+ emsg(_(e_trailing));
+ return;
+ }
+ eap->nextcmd = check_nextcmd(p);
+ if (eap->nextcmd != NULL)
+ *p = NUL;
+
+ if (!eap->skip)
+ fp = find_func(name);
+ vim_free(name);
+
+ if (!eap->skip)
+ {
+ if (fp == NULL)
+ {
+ if (!eap->forceit)
+ semsg(_(e_nofunc), eap->arg);
+ return;
+ }
+ if (fp->uf_calls > 0)
+ {
+ semsg(_("E131: Cannot delete function %s: It is in use"), eap->arg);
+ return;
+ }
+
+ if (fudi.fd_dict != NULL)
+ {
+ /* Delete the dict item that refers to the function, it will
+ * invoke func_unref() and possibly delete the function. */
+ dictitem_remove(fudi.fd_dict, fudi.fd_di);
+ }
+ else
+ {
+ /* A normal function (not a numbered function or lambda) has a
+ * refcount of 1 for the entry in the hashtable. When deleting
+ * it and the refcount is more than one, it should be kept.
+ * A numbered function and lambda should be kept if the refcount is
+ * one or more. */
+ if (fp->uf_refcount > (func_name_refcount(fp->uf_name) ? 0 : 1))
+ {
+ /* Function is still referenced somewhere. Don't free it but
+ * do remove it from the hashtable. */
+ if (func_remove(fp))
+ fp->uf_refcount--;
+ fp->uf_flags |= FC_DELETED;
+ }
+ else
+ func_clear_free(fp, FALSE);
+ }
+ }
+}
+
+/*
+ * Unreference a Function: decrement the reference count and free it when it
+ * becomes zero.
+ */
+ void
+func_unref(char_u *name)
+{
+ ufunc_T *fp = NULL;
+
+ if (name == NULL || !func_name_refcount(name))
+ return;
+ fp = find_func(name);
+ if (fp == NULL && isdigit(*name))
+ {
+#ifdef EXITFREE
+ if (!entered_free_all_mem)
+#endif
+ internal_error("func_unref()");
+ }
+ if (fp != NULL && --fp->uf_refcount <= 0)
+ {
+ /* Only delete it when it's not being used. Otherwise it's done
+ * when "uf_calls" becomes zero. */
+ if (fp->uf_calls == 0)
+ func_clear_free(fp, FALSE);
+ }
+}
+
+/*
+ * Unreference a Function: decrement the reference count and free it when it
+ * becomes zero.
+ */
+ void
+func_ptr_unref(ufunc_T *fp)
+{
+ if (fp != NULL && --fp->uf_refcount <= 0)
+ {
+ /* Only delete it when it's not being used. Otherwise it's done
+ * when "uf_calls" becomes zero. */
+ if (fp->uf_calls == 0)
+ func_clear_free(fp, FALSE);
+ }
+}
+
+/*
+ * Count a reference to a Function.
+ */
+ void
+func_ref(char_u *name)
+{
+ ufunc_T *fp;
+
+ if (name == NULL || !func_name_refcount(name))
+ return;
+ fp = find_func(name);
+ if (fp != NULL)
+ ++fp->uf_refcount;
+ else if (isdigit(*name))
+ /* Only give an error for a numbered function.
+ * Fail silently, when named or lambda function isn't found. */
+ internal_error("func_ref()");
+}
+
+/*
+ * Count a reference to a Function.
+ */
+ void
+func_ptr_ref(ufunc_T *fp)
+{
+ if (fp != NULL)
+ ++fp->uf_refcount;
+}
+
+/*
+ * Return TRUE if items in "fc" do not have "copyID". That means they are not
+ * referenced from anywhere that is in use.
+ */
+ static int
+can_free_funccal(funccall_T *fc, int copyID)
+{
+ return (fc->l_varlist.lv_copyID != copyID
+ && fc->l_vars.dv_copyID != copyID
+ && fc->l_avars.dv_copyID != copyID
+ && fc->fc_copyID != copyID);
+}
+
+/*
+ * ":return [expr]"
+ */
+ void
+ex_return(exarg_T *eap)
+{
+ char_u *arg = eap->arg;
+ typval_T rettv;
+ int returning = FALSE;
+
+ if (current_funccal == NULL)
+ {
+ emsg(_("E133: :return not inside a function"));
+ return;
+ }
+
+ if (eap->skip)
+ ++emsg_skip;
+
+ eap->nextcmd = NULL;
+ if ((*arg != NUL && *arg != '|' && *arg != '\n')
+ && eval0(arg, &rettv, &eap->nextcmd, !eap->skip) != FAIL)
+ {
+ if (!eap->skip)
+ returning = do_return(eap, FALSE, TRUE, &rettv);
+ else
+ clear_tv(&rettv);
+ }
+ /* It's safer to return also on error. */
+ else if (!eap->skip)
+ {
+ /* In return statement, cause_abort should be force_abort. */
+ update_force_abort();
+
+ /*
+ * Return unless the expression evaluation has been cancelled due to an
+ * aborting error, an interrupt, or an exception.
+ */
+ if (!aborting())
+ returning = do_return(eap, FALSE, TRUE, NULL);
+ }
+
+ /* When skipping or the return gets pending, advance to the next command
+ * in this line (!returning). Otherwise, ignore the rest of the line.
+ * Following lines will be ignored by get_func_line(). */
+ if (returning)
+ eap->nextcmd = NULL;
+ else if (eap->nextcmd == NULL) /* no argument */
+ eap->nextcmd = check_nextcmd(arg);
+
+ if (eap->skip)
+ --emsg_skip;
+}
+
+/*
+ * ":1,25call func(arg1, arg2)" function call.
+ */
+ void
+ex_call(exarg_T *eap)
+{
+ char_u *arg = eap->arg;
+ char_u *startarg;
+ char_u *name;
+ char_u *tofree;
+ int len;
+ typval_T rettv;
+ linenr_T lnum;
+ int doesrange;
+ int failed = FALSE;
+ funcdict_T fudi;
+ partial_T *partial = NULL;
+
+ if (eap->skip)
+ {
+ /* trans_function_name() doesn't work well when skipping, use eval0()
+ * instead to skip to any following command, e.g. for:
+ * :if 0 | call dict.foo().bar() | endif */
+ ++emsg_skip;
+ if (eval0(eap->arg, &rettv, &eap->nextcmd, FALSE) != FAIL)
+ clear_tv(&rettv);
+ --emsg_skip;
+ return;
+ }
+
+ tofree = trans_function_name(&arg, eap->skip, TFN_INT, &fudi, &partial);
+ if (fudi.fd_newkey != NULL)
+ {
+ /* Still need to give an error message for missing key. */
+ semsg(_(e_dictkey), fudi.fd_newkey);
+ vim_free(fudi.fd_newkey);
+ }
+ if (tofree == NULL)
+ return;
+
+ /* Increase refcount on dictionary, it could get deleted when evaluating
+ * the arguments. */
+ if (fudi.fd_dict != NULL)
+ ++fudi.fd_dict->dv_refcount;
+
+ /* If it is the name of a variable of type VAR_FUNC or VAR_PARTIAL use its
+ * contents. For VAR_PARTIAL get its partial, unless we already have one
+ * from trans_function_name(). */
+ len = (int)STRLEN(tofree);
+ name = deref_func_name(tofree, &len,
+ partial != NULL ? NULL : &partial, FALSE);
+
+ /* Skip white space to allow ":call func ()". Not good, but required for
+ * backward compatibility. */
+ startarg = skipwhite(arg);
+ rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */
+
+ if (*startarg != '(')
+ {
+ semsg(_("E107: Missing parentheses: %s"), eap->arg);
+ goto end;
+ }
+
+ /*
+ * When skipping, evaluate the function once, to find the end of the
+ * arguments.
+ * When the function takes a range, this is discovered after the first
+ * call, and the loop is broken.
+ */
+ if (eap->skip)
+ {
+ ++emsg_skip;
+ lnum = eap->line2; /* do it once, also with an invalid range */
+ }
+ else
+ lnum = eap->line1;
+ for ( ; lnum <= eap->line2; ++lnum)
+ {
+ if (!eap->skip && eap->addr_count > 0)
+ {
+ if (lnum > curbuf->b_ml.ml_line_count)
+ {
+ // If the function deleted lines or switched to another buffer
+ // the line number may become invalid.
+ emsg(_(e_invrange));
+ break;
+ }
+ curwin->w_cursor.lnum = lnum;
+ curwin->w_cursor.col = 0;
+ curwin->w_cursor.coladd = 0;
+ }
+ arg = startarg;
+ if (get_func_tv(name, (int)STRLEN(name), &rettv, &arg,
+ eap->line1, eap->line2, &doesrange,
+ !eap->skip, partial, fudi.fd_dict) == FAIL)
+ {
+ failed = TRUE;
+ break;
+ }
+ if (has_watchexpr())
+ dbg_check_breakpoint(eap);
+
+ /* Handle a function returning a Funcref, Dictionary or List. */
+ if (handle_subscript(&arg, &rettv, !eap->skip, TRUE) == FAIL)
+ {
+ failed = TRUE;
+ break;
+ }
+
+ clear_tv(&rettv);
+ if (doesrange || eap->skip)
+ break;
+
+ /* Stop when immediately aborting on error, or when an interrupt
+ * occurred or an exception was thrown but not caught.
+ * get_func_tv() returned OK, so that the check for trailing
+ * characters below is executed. */
+ if (aborting())
+ break;
+ }
+ if (eap->skip)
+ --emsg_skip;
+
+ if (!failed)
+ {
+ /* Check for trailing illegal characters and a following command. */
+ if (!ends_excmd(*arg))
+ {
+ emsg_severe = TRUE;
+ emsg(_(e_trailing));
+ }
+ else
+ eap->nextcmd = check_nextcmd(arg);
+ }
+
+end:
+ dict_unref(fudi.fd_dict);
+ vim_free(tofree);
+}
+
+/*
+ * Return from a function. Possibly makes the return pending. Also called
+ * for a pending return at the ":endtry" or after returning from an extra
+ * do_cmdline(). "reanimate" is used in the latter case. "is_cmd" is set
+ * when called due to a ":return" command. "rettv" may point to a typval_T
+ * with the return rettv. Returns TRUE when the return can be carried out,
+ * FALSE when the return gets pending.
+ */
+ int
+do_return(
+ exarg_T *eap,
+ int reanimate,
+ int is_cmd,
+ void *rettv)
+{
+ int idx;
+ struct condstack *cstack = eap->cstack;
+
+ if (reanimate)
+ /* Undo the return. */
+ current_funccal->returned = FALSE;
+
+ /*
+ * Cleanup (and inactivate) conditionals, but stop when a try conditional
+ * not in its finally clause (which then is to be executed next) is found.
+ * In this case, make the ":return" pending for execution at the ":endtry".
+ * Otherwise, return normally.
+ */
+ idx = cleanup_conditionals(eap->cstack, 0, TRUE);
+ if (idx >= 0)
+ {
+ cstack->cs_pending[idx] = CSTP_RETURN;
+
+ if (!is_cmd && !reanimate)
+ /* A pending return again gets pending. "rettv" points to an
+ * allocated variable with the rettv of the original ":return"'s
+ * argument if present or is NULL else. */
+ cstack->cs_rettv[idx] = rettv;
+ else
+ {
+ /* When undoing a return in order to make it pending, get the stored
+ * return rettv. */
+ if (reanimate)
+ rettv = current_funccal->rettv;
+
+ if (rettv != NULL)
+ {
+ /* Store the value of the pending return. */
+ if ((cstack->cs_rettv[idx] = alloc_tv()) != NULL)
+ *(typval_T *)cstack->cs_rettv[idx] = *(typval_T *)rettv;
+ else
+ emsg(_(e_outofmem));
+ }
+ else
+ cstack->cs_rettv[idx] = NULL;
+
+ if (reanimate)
+ {
+ /* The pending return value could be overwritten by a ":return"
+ * without argument in a finally clause; reset the default
+ * return value. */
+ current_funccal->rettv->v_type = VAR_NUMBER;
+ current_funccal->rettv->vval.v_number = 0;
+ }
+ }
+ report_make_pending(CSTP_RETURN, rettv);
+ }
+ else
+ {
+ current_funccal->returned = TRUE;
+
+ /* If the return is carried out now, store the return value. For
+ * a return immediately after reanimation, the value is already
+ * there. */
+ if (!reanimate && rettv != NULL)
+ {
+ clear_tv(current_funccal->rettv);
+ *current_funccal->rettv = *(typval_T *)rettv;
+ if (!is_cmd)
+ vim_free(rettv);
+ }
+ }
+
+ return idx < 0;
+}
+
+/*
+ * Free the variable with a pending return value.
+ */
+ void
+discard_pending_return(void *rettv)
+{
+ free_tv((typval_T *)rettv);
+}
+
+/*
+ * Generate a return command for producing the value of "rettv". The result
+ * is an allocated string. Used by report_pending() for verbose messages.
+ */
+ char_u *
+get_return_cmd(void *rettv)
+{
+ char_u *s = NULL;
+ char_u *tofree = NULL;
+ char_u numbuf[NUMBUFLEN];
+
+ if (rettv != NULL)
+ s = echo_string((typval_T *)rettv, &tofree, numbuf, 0);
+ if (s == NULL)
+ s = (char_u *)"";
+
+ STRCPY(IObuff, ":return ");
+ STRNCPY(IObuff + 8, s, IOSIZE - 8);
+ if (STRLEN(s) + 8 >= IOSIZE)
+ STRCPY(IObuff + IOSIZE - 4, "...");
+ vim_free(tofree);
+ return vim_strsave(IObuff);
+}
+
+/*
+ * Get next function line.
+ * Called by do_cmdline() to get the next line.
+ * Returns allocated string, or NULL for end of function.
+ */
+ char_u *
+get_func_line(
+ int c UNUSED,
+ void *cookie,
+ int indent UNUSED)
+{
+ funccall_T *fcp = (funccall_T *)cookie;
+ ufunc_T *fp = fcp->func;
+ char_u *retval;
+ garray_T *gap; /* growarray with function lines */
+
+ /* If breakpoints have been added/deleted need to check for it. */
+ if (fcp->dbg_tick != debug_tick)
+ {
+ fcp->breakpoint = dbg_find_breakpoint(FALSE, fp->uf_name,
+ sourcing_lnum);
+ fcp->dbg_tick = debug_tick;
+ }
+#ifdef FEAT_PROFILE
+ if (do_profiling == PROF_YES)
+ func_line_end(cookie);
+#endif
+
+ gap = &fp->uf_lines;
+ if (((fp->uf_flags & FC_ABORT) && did_emsg && !aborted_in_try())
+ || fcp->returned)
+ retval = NULL;
+ else
+ {
+ /* Skip NULL lines (continuation lines). */
+ while (fcp->linenr < gap->ga_len
+ && ((char_u **)(gap->ga_data))[fcp->linenr] == NULL)
+ ++fcp->linenr;
+ if (fcp->linenr >= gap->ga_len)
+ retval = NULL;
+ else
+ {
+ retval = vim_strsave(((char_u **)(gap->ga_data))[fcp->linenr++]);
+ sourcing_lnum = fcp->linenr;
+#ifdef FEAT_PROFILE
+ if (do_profiling == PROF_YES)
+ func_line_start(cookie);
+#endif
+ }
+ }
+
+ /* Did we encounter a breakpoint? */
+ if (fcp->breakpoint != 0 && fcp->breakpoint <= sourcing_lnum)
+ {
+ dbg_breakpoint(fp->uf_name, sourcing_lnum);
+ /* Find next breakpoint. */
+ fcp->breakpoint = dbg_find_breakpoint(FALSE, fp->uf_name,
+ sourcing_lnum);
+ fcp->dbg_tick = debug_tick;
+ }
+
+ return retval;
+}
+
+#if defined(FEAT_PROFILE) || defined(PROTO)
+/*
+ * Called when starting to read a function line.
+ * "sourcing_lnum" must be correct!
+ * When skipping lines it may not actually be executed, but we won't find out
+ * until later and we need to store the time now.
+ */
+ void
+func_line_start(void *cookie)
+{
+ funccall_T *fcp = (funccall_T *)cookie;
+ ufunc_T *fp = fcp->func;
+
+ if (fp->uf_profiling && sourcing_lnum >= 1
+ && sourcing_lnum <= fp->uf_lines.ga_len)
+ {
+ fp->uf_tml_idx = sourcing_lnum - 1;
+ /* Skip continuation lines. */
+ while (fp->uf_tml_idx > 0 && FUNCLINE(fp, fp->uf_tml_idx) == NULL)
+ --fp->uf_tml_idx;
+ fp->uf_tml_execed = FALSE;
+ profile_start(&fp->uf_tml_start);
+ profile_zero(&fp->uf_tml_children);
+ profile_get_wait(&fp->uf_tml_wait);
+ }
+}
+
+/*
+ * Called when actually executing a function line.
+ */
+ void
+func_line_exec(void *cookie)
+{
+ funccall_T *fcp = (funccall_T *)cookie;
+ ufunc_T *fp = fcp->func;
+
+ if (fp->uf_profiling && fp->uf_tml_idx >= 0)
+ fp->uf_tml_execed = TRUE;
+}
+
+/*
+ * Called when done with a function line.
+ */
+ void
+func_line_end(void *cookie)
+{
+ funccall_T *fcp = (funccall_T *)cookie;
+ ufunc_T *fp = fcp->func;
+
+ if (fp->uf_profiling && fp->uf_tml_idx >= 0)
+ {
+ if (fp->uf_tml_execed)
+ {
+ ++fp->uf_tml_count[fp->uf_tml_idx];
+ profile_end(&fp->uf_tml_start);
+ profile_sub_wait(&fp->uf_tml_wait, &fp->uf_tml_start);
+ profile_add(&fp->uf_tml_total[fp->uf_tml_idx], &fp->uf_tml_start);
+ profile_self(&fp->uf_tml_self[fp->uf_tml_idx], &fp->uf_tml_start,
+ &fp->uf_tml_children);
+ }
+ fp->uf_tml_idx = -1;
+ }
+}
+#endif
+
+/*
+ * Return TRUE if the currently active function should be ended, because a
+ * return was encountered or an error occurred. Used inside a ":while".
+ */
+ int
+func_has_ended(void *cookie)
+{
+ funccall_T *fcp = (funccall_T *)cookie;
+
+ /* Ignore the "abort" flag if the abortion behavior has been changed due to
+ * an error inside a try conditional. */
+ return (((fcp->func->uf_flags & FC_ABORT) && did_emsg && !aborted_in_try())
+ || fcp->returned);
+}
+
+/*
+ * return TRUE if cookie indicates a function which "abort"s on errors.
+ */
+ int
+func_has_abort(
+ void *cookie)
+{
+ return ((funccall_T *)cookie)->func->uf_flags & FC_ABORT;
+}
+
+
+/*
+ * Turn "dict.Func" into a partial for "Func" bound to "dict".
+ * Don't do this when "Func" is already a partial that was bound
+ * explicitly (pt_auto is FALSE).
+ * Changes "rettv" in-place.
+ * Returns the updated "selfdict_in".
+ */
+ dict_T *
+make_partial(dict_T *selfdict_in, typval_T *rettv)
+{
+ char_u *fname;
+ char_u *tofree = NULL;
+ ufunc_T *fp;
+ char_u fname_buf[FLEN_FIXED + 1];
+ int error;
+ dict_T *selfdict = selfdict_in;
+
+ if (rettv->v_type == VAR_PARTIAL && rettv->vval.v_partial->pt_func != NULL)
+ fp = rettv->vval.v_partial->pt_func;
+ else
+ {
+ fname = rettv->v_type == VAR_FUNC ? rettv->vval.v_string
+ : rettv->vval.v_partial->pt_name;
+ /* Translate "s:func" to the stored function name. */
+ fname = fname_trans_sid(fname, fname_buf, &tofree, &error);
+ fp = find_func(fname);
+ vim_free(tofree);
+ }
+
+ if (fp != NULL && (fp->uf_flags & FC_DICT))
+ {
+ partial_T *pt = (partial_T *)alloc_clear(sizeof(partial_T));
+
+ if (pt != NULL)
+ {
+ pt->pt_refcount = 1;
+ pt->pt_dict = selfdict;
+ pt->pt_auto = TRUE;
+ selfdict = NULL;
+ if (rettv->v_type == VAR_FUNC)
+ {
+ /* Just a function: Take over the function name and use
+ * selfdict. */
+ pt->pt_name = rettv->vval.v_string;
+ }
+ else
+ {
+ partial_T *ret_pt = rettv->vval.v_partial;
+ int i;
+
+ /* Partial: copy the function name, use selfdict and copy
+ * args. Can't take over name or args, the partial might
+ * be referenced elsewhere. */
+ if (ret_pt->pt_name != NULL)
+ {
+ pt->pt_name = vim_strsave(ret_pt->pt_name);
+ func_ref(pt->pt_name);
+ }
+ else
+ {
+ pt->pt_func = ret_pt->pt_func;
+ func_ptr_ref(pt->pt_func);
+ }
+ if (ret_pt->pt_argc > 0)
+ {
+ pt->pt_argv = (typval_T *)alloc(
+ sizeof(typval_T) * ret_pt->pt_argc);
+ if (pt->pt_argv == NULL)
+ /* out of memory: drop the arguments */
+ pt->pt_argc = 0;
+ else
+ {
+ pt->pt_argc = ret_pt->pt_argc;
+ for (i = 0; i < pt->pt_argc; i++)
+ copy_tv(&ret_pt->pt_argv[i], &pt->pt_argv[i]);
+ }
+ }
+ partial_unref(ret_pt);
+ }
+ rettv->v_type = VAR_PARTIAL;
+ rettv->vval.v_partial = pt;
+ }
+ }
+ return selfdict;
+}
+
+/*
+ * Return the name of the executed function.
+ */
+ char_u *
+func_name(void *cookie)
+{
+ return ((funccall_T *)cookie)->func->uf_name;
+}
+
+/*
+ * Return the address holding the next breakpoint line for a funccall cookie.
+ */
+ linenr_T *
+func_breakpoint(void *cookie)
+{
+ return &((funccall_T *)cookie)->breakpoint;
+}
+
+/*
+ * Return the address holding the debug tick for a funccall cookie.
+ */
+ int *
+func_dbg_tick(void *cookie)
+{
+ return &((funccall_T *)cookie)->dbg_tick;
+}
+
+/*
+ * Return the nesting level for a funccall cookie.
+ */
+ int
+func_level(void *cookie)
+{
+ return ((funccall_T *)cookie)->level;
+}
+
+/*
+ * Return TRUE when a function was ended by a ":return" command.
+ */
+ int
+current_func_returned(void)
+{
+ return current_funccal->returned;
+}
+
+ int
+free_unref_funccal(int copyID, int testing)
+{
+ int did_free = FALSE;
+ int did_free_funccal = FALSE;
+ funccall_T *fc, **pfc;
+
+ for (pfc = &previous_funccal; *pfc != NULL; )
+ {
+ if (can_free_funccal(*pfc, copyID))
+ {
+ fc = *pfc;
+ *pfc = fc->caller;
+ free_funccal(fc, TRUE);
+ did_free = TRUE;
+ did_free_funccal = TRUE;
+ }
+ else
+ pfc = &(*pfc)->caller;
+ }
+ if (did_free_funccal)
+ /* When a funccal was freed some more items might be garbage
+ * collected, so run again. */
+ (void)garbage_collect(testing);
+
+ return did_free;
+}
+
+/*
+ * Get function call environment based on backtrace debug level
+ */
+ static funccall_T *
+get_funccal(void)
+{
+ int i;
+ funccall_T *funccal;
+ funccall_T *temp_funccal;
+
+ funccal = current_funccal;
+ if (debug_backtrace_level > 0)
+ {
+ for (i = 0; i < debug_backtrace_level; i++)
+ {
+ temp_funccal = funccal->caller;
+ if (temp_funccal)
+ funccal = temp_funccal;
+ else
+ /* backtrace level overflow. reset to max */
+ debug_backtrace_level = i;
+ }
+ }
+ return funccal;
+}
+
+/*
+ * Return the hashtable used for local variables in the current funccal.
+ * Return NULL if there is no current funccal.
+ */
+ hashtab_T *
+get_funccal_local_ht()
+{
+ if (current_funccal == NULL)
+ return NULL;
+ return &get_funccal()->l_vars.dv_hashtab;
+}
+
+/*
+ * Return the l: scope variable.
+ * Return NULL if there is no current funccal.
+ */
+ dictitem_T *
+get_funccal_local_var()
+{
+ if (current_funccal == NULL)
+ return NULL;
+ return &get_funccal()->l_vars_var;
+}
+
+/*
+ * Return the hashtable used for argument in the current funccal.
+ * Return NULL if there is no current funccal.
+ */
+ hashtab_T *
+get_funccal_args_ht()
+{
+ if (current_funccal == NULL)
+ return NULL;
+ return &get_funccal()->l_avars.dv_hashtab;
+}
+
+/*
+ * Return the a: scope variable.
+ * Return NULL if there is no current funccal.
+ */
+ dictitem_T *
+get_funccal_args_var()
+{
+ if (current_funccal == NULL)
+ return NULL;
+ return &get_funccal()->l_avars_var;
+}
+
+/*
+ * List function variables, if there is a function.
+ */
+ void
+list_func_vars(int *first)
+{
+ if (current_funccal != NULL)
+ list_hashtable_vars(&current_funccal->l_vars.dv_hashtab,
+ "l:", FALSE, first);
+}
+
+/*
+ * If "ht" is the hashtable for local variables in the current funccal, return
+ * the dict that contains it.
+ * Otherwise return NULL.
+ */
+ dict_T *
+get_current_funccal_dict(hashtab_T *ht)
+{
+ if (current_funccal != NULL
+ && ht == &current_funccal->l_vars.dv_hashtab)
+ return &current_funccal->l_vars;
+ return NULL;
+}
+
+/*
+ * Search hashitem in parent scope.
+ */
+ hashitem_T *
+find_hi_in_scoped_ht(char_u *name, hashtab_T **pht)
+{
+ funccall_T *old_current_funccal = current_funccal;
+ hashtab_T *ht;
+ hashitem_T *hi = NULL;
+ char_u *varname;
+
+ if (current_funccal == NULL || current_funccal->func->uf_scoped == NULL)
+ return NULL;
+
+ /* Search in parent scope which is possible to reference from lambda */
+ current_funccal = current_funccal->func->uf_scoped;
+ while (current_funccal != NULL)
+ {
+ ht = find_var_ht(name, &varname);
+ if (ht != NULL && *varname != NUL)
+ {
+ hi = hash_find(ht, varname);
+ if (!HASHITEM_EMPTY(hi))
+ {
+ *pht = ht;
+ break;
+ }
+ }
+ if (current_funccal == current_funccal->func->uf_scoped)
+ break;
+ current_funccal = current_funccal->func->uf_scoped;
+ }
+ current_funccal = old_current_funccal;
+
+ return hi;
+}
+
+/*
+ * Search variable in parent scope.
+ */
+ dictitem_T *
+find_var_in_scoped_ht(char_u *name, int no_autoload)
+{
+ dictitem_T *v = NULL;
+ funccall_T *old_current_funccal = current_funccal;
+ hashtab_T *ht;
+ char_u *varname;
+
+ if (current_funccal == NULL || current_funccal->func->uf_scoped == NULL)
+ return NULL;
+
+ /* Search in parent scope which is possible to reference from lambda */
+ current_funccal = current_funccal->func->uf_scoped;
+ while (current_funccal)
+ {
+ ht = find_var_ht(name, &varname);
+ if (ht != NULL && *varname != NUL)
+ {
+ v = find_var_in_ht(ht, *name, varname, no_autoload);
+ if (v != NULL)
+ break;
+ }
+ if (current_funccal == current_funccal->func->uf_scoped)
+ break;
+ current_funccal = current_funccal->func->uf_scoped;
+ }
+ current_funccal = old_current_funccal;
+
+ return v;
+}
+
+/*
+ * Set "copyID + 1" in previous_funccal and callers.
+ */
+ int
+set_ref_in_previous_funccal(int copyID)
+{
+ int abort = FALSE;
+ funccall_T *fc;
+
+ for (fc = previous_funccal; fc != NULL; fc = fc->caller)
+ {
+ fc->fc_copyID = copyID + 1;
+ abort = abort || set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID + 1,
+ NULL);
+ abort = abort || set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID + 1,
+ NULL);
+ }
+ return abort;
+}
+
+ static int
+set_ref_in_funccal(funccall_T *fc, int copyID)
+{
+ int abort = FALSE;
+
+ if (fc->fc_copyID != copyID)
+ {
+ fc->fc_copyID = copyID;
+ abort = abort || set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID, NULL);
+ abort = abort || set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID, NULL);
+ abort = abort || set_ref_in_func(NULL, fc->func, copyID);
+ }
+ return abort;
+}
+
+/*
+ * Set "copyID" in all local vars and arguments in the call stack.
+ */
+ int
+set_ref_in_call_stack(int copyID)
+{
+ int abort = FALSE;
+ funccall_T *fc;
+
+ for (fc = current_funccal; fc != NULL; fc = fc->caller)
+ abort = abort || set_ref_in_funccal(fc, copyID);
+ return abort;
+}
+
+/*
+ * Set "copyID" in all functions available by name.
+ */
+ int
+set_ref_in_functions(int copyID)
+{
+ int todo;
+ hashitem_T *hi = NULL;
+ int abort = FALSE;
+ ufunc_T *fp;
+
+ todo = (int)func_hashtab.ht_used;
+ for (hi = func_hashtab.ht_array; todo > 0 && !got_int; ++hi)
+ {
+ if (!HASHITEM_EMPTY(hi))
+ {
+ --todo;
+ fp = HI2UF(hi);
+ if (!func_name_refcount(fp->uf_name))
+ abort = abort || set_ref_in_func(NULL, fp, copyID);
+ }
+ }
+ return abort;
+}
+
+/*
+ * Set "copyID" in all function arguments.
+ */
+ int
+set_ref_in_func_args(int copyID)
+{
+ int i;
+ int abort = FALSE;
+
+ for (i = 0; i < funcargs.ga_len; ++i)
+ abort = abort || set_ref_in_item(((typval_T **)funcargs.ga_data)[i],
+ copyID, NULL, NULL);
+ return abort;
+}
+
+/*
+ * Mark all lists and dicts referenced through function "name" with "copyID".
+ * Returns TRUE if setting references failed somehow.
+ */
+ int
+set_ref_in_func(char_u *name, ufunc_T *fp_in, int copyID)
+{
+ ufunc_T *fp = fp_in;
+ funccall_T *fc;
+ int error = ERROR_NONE;
+ char_u fname_buf[FLEN_FIXED + 1];
+ char_u *tofree = NULL;
+ char_u *fname;
+ int abort = FALSE;
+
+ if (name == NULL && fp_in == NULL)
+ return FALSE;
+
+ if (fp_in == NULL)
+ {
+ fname = fname_trans_sid(name, fname_buf, &tofree, &error);
+ fp = find_func(fname);
+ }
+ if (fp != NULL)
+ {
+ for (fc = fp->uf_scoped; fc != NULL; fc = fc->func->uf_scoped)
+ abort = abort || set_ref_in_funccal(fc, copyID);
+ }
+ vim_free(tofree);
+ return abort;
+}
+
+#endif /* FEAT_EVAL */
diff --git a/src/version.c b/src/version.c
new file mode 100644
index 0000000..9b2e7c9
--- /dev/null
+++ b/src/version.c
@@ -0,0 +1,3205 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+#include "vim.h"
+
+#ifdef AMIGA
+# include <time.h> /* for time() */
+#endif
+
+/*
+ * Vim originated from Stevie version 3.6 (Fish disk 217) by GRWalter (Fred)
+ * It has been changed beyond recognition since then.
+ *
+ * Differences between version 7.4 and 8.x can be found with ":help version8".
+ * Differences between version 6.4 and 7.x can be found with ":help version7".
+ * Differences between version 5.8 and 6.x can be found with ":help version6".
+ * Differences between version 4.x and 5.x can be found with ":help version5".
+ * Differences between version 3.0 and 4.x can be found with ":help version4".
+ * All the remarks about older versions have been removed, they are not very
+ * interesting.
+ */
+
+#include "version.h"
+
+char *Version = VIM_VERSION_SHORT;
+static char *mediumVersion = VIM_VERSION_MEDIUM;
+
+#if defined(HAVE_DATE_TIME) || defined(PROTO)
+# if (defined(VMS) && defined(VAXC)) || defined(PROTO)
+char longVersion[sizeof(VIM_VERSION_LONG_DATE) + sizeof(__DATE__)
+ + sizeof(__TIME__) + 3];
+
+ void
+init_longVersion(void)
+{
+ /*
+ * Construct the long version string. Necessary because
+ * VAX C can't catenate strings in the preprocessor.
+ */
+ strcpy(longVersion, VIM_VERSION_LONG_DATE);
+ strcat(longVersion, __DATE__);
+ strcat(longVersion, " ");
+ strcat(longVersion, __TIME__);
+ strcat(longVersion, ")");
+}
+
+# else
+ void
+init_longVersion(void)
+{
+ char *date_time = __DATE__ " " __TIME__;
+ char *msg = _("%s (%s, compiled %s)");
+ size_t len = strlen(msg)
+ + strlen(VIM_VERSION_LONG_ONLY)
+ + strlen(VIM_VERSION_DATE_ONLY)
+ + strlen(date_time);
+
+ longVersion = (char *)alloc((unsigned)len);
+ if (longVersion == NULL)
+ longVersion = VIM_VERSION_LONG;
+ else
+ vim_snprintf(longVersion, len, msg,
+ VIM_VERSION_LONG_ONLY, VIM_VERSION_DATE_ONLY, date_time);
+}
+# endif
+#else
+char *longVersion = VIM_VERSION_LONG;
+
+ void
+init_longVersion(void)
+{
+ // nothing to do
+}
+#endif
+
+static char *(features[]) =
+{
+#ifdef HAVE_ACL
+ "+acl",
+#else
+ "-acl",
+#endif
+#ifdef AMIGA /* only for Amiga systems */
+# ifdef FEAT_ARP
+ "+ARP",
+# else
+ "-ARP",
+# endif
+#endif
+#ifdef FEAT_ARABIC
+ "+arabic",
+#else
+ "-arabic",
+#endif
+ "+autocmd",
+#ifdef FEAT_AUTOCHDIR
+ "+autochdir",
+#else
+ "-autochdir",
+#endif
+#ifdef FEAT_AUTOSERVERNAME
+ "+autoservername",
+#else
+ "-autoservername",
+#endif
+#ifdef FEAT_BEVAL_GUI
+ "+balloon_eval",
+#else
+ "-balloon_eval",
+#endif
+#ifdef FEAT_BEVAL_TERM
+ "+balloon_eval_term",
+#else
+ "-balloon_eval_term",
+#endif
+#ifdef FEAT_BROWSE
+ "+browse",
+#else
+ "-browse",
+#endif
+#ifdef NO_BUILTIN_TCAPS
+ "-builtin_terms",
+#endif
+#ifdef SOME_BUILTIN_TCAPS
+ "+builtin_terms",
+#endif
+#ifdef ALL_BUILTIN_TCAPS
+ "++builtin_terms",
+#endif
+#ifdef FEAT_BYTEOFF
+ "+byte_offset",
+#else
+ "-byte_offset",
+#endif
+#ifdef FEAT_JOB_CHANNEL
+ "+channel",
+#else
+ "-channel",
+#endif
+#ifdef FEAT_CINDENT
+ "+cindent",
+#else
+ "-cindent",
+#endif
+#ifdef FEAT_CLIENTSERVER
+ "+clientserver",
+#else
+ "-clientserver",
+#endif
+#ifdef FEAT_CLIPBOARD
+ "+clipboard",
+#else
+ "-clipboard",
+#endif
+#ifdef FEAT_CMDL_COMPL
+ "+cmdline_compl",
+#else
+ "-cmdline_compl",
+#endif
+#ifdef FEAT_CMDHIST
+ "+cmdline_hist",
+#else
+ "-cmdline_hist",
+#endif
+#ifdef FEAT_CMDL_INFO
+ "+cmdline_info",
+#else
+ "-cmdline_info",
+#endif
+#ifdef FEAT_COMMENTS
+ "+comments",
+#else
+ "-comments",
+#endif
+#ifdef FEAT_CONCEAL
+ "+conceal",
+#else
+ "-conceal",
+#endif
+#ifdef FEAT_CRYPT
+ "+cryptv",
+#else
+ "-cryptv",
+#endif
+#ifdef FEAT_CSCOPE
+ "+cscope",
+#else
+ "-cscope",
+#endif
+ "+cursorbind",
+#ifdef CURSOR_SHAPE
+ "+cursorshape",
+#else
+ "-cursorshape",
+#endif
+#if defined(FEAT_CON_DIALOG) && defined(FEAT_GUI_DIALOG)
+ "+dialog_con_gui",
+#else
+# if defined(FEAT_CON_DIALOG)
+ "+dialog_con",
+# else
+# if defined(FEAT_GUI_DIALOG)
+ "+dialog_gui",
+# else
+ "-dialog",
+# endif
+# endif
+#endif
+#ifdef FEAT_DIFF
+ "+diff",
+#else
+ "-diff",
+#endif
+#ifdef FEAT_DIGRAPHS
+ "+digraphs",
+#else
+ "-digraphs",
+#endif
+#ifdef FEAT_GUI_W32
+# ifdef FEAT_DIRECTX
+ "+directx",
+# else
+ "-directx",
+# endif
+#endif
+#ifdef FEAT_DND
+ "+dnd",
+#else
+ "-dnd",
+#endif
+#ifdef EBCDIC
+ "+ebcdic",
+#else
+ "-ebcdic",
+#endif
+#ifdef FEAT_EMACS_TAGS
+ "+emacs_tags",
+#else
+ "-emacs_tags",
+#endif
+#ifdef FEAT_EVAL
+ "+eval",
+#else
+ "-eval",
+#endif
+ "+ex_extra",
+#ifdef FEAT_SEARCH_EXTRA
+ "+extra_search",
+#else
+ "-extra_search",
+#endif
+#ifdef FEAT_FKMAP
+ "+farsi",
+#else
+ "-farsi",
+#endif
+#ifdef FEAT_SEARCHPATH
+ "+file_in_path",
+#else
+ "-file_in_path",
+#endif
+#ifdef FEAT_FIND_ID
+ "+find_in_path",
+#else
+ "-find_in_path",
+#endif
+#ifdef FEAT_FLOAT
+ "+float",
+#else
+ "-float",
+#endif
+#ifdef FEAT_FOLDING
+ "+folding",
+#else
+ "-folding",
+#endif
+#ifdef FEAT_FOOTER
+ "+footer",
+#else
+ "-footer",
+#endif
+ /* only interesting on Unix systems */
+#if !defined(USE_SYSTEM) && defined(UNIX)
+ "+fork()",
+#endif
+#ifdef FEAT_GETTEXT
+# ifdef DYNAMIC_GETTEXT
+ "+gettext/dyn",
+# else
+ "+gettext",
+# endif
+#else
+ "-gettext",
+#endif
+#ifdef FEAT_HANGULIN
+ "+hangul_input",
+#else
+ "-hangul_input",
+#endif
+#if (defined(HAVE_ICONV_H) && defined(USE_ICONV)) || defined(DYNAMIC_ICONV)
+# ifdef DYNAMIC_ICONV
+ "+iconv/dyn",
+# else
+ "+iconv",
+# endif
+#else
+ "-iconv",
+#endif
+#ifdef FEAT_INS_EXPAND
+ "+insert_expand",
+#else
+ "-insert_expand",
+#endif
+#ifdef FEAT_JOB_CHANNEL
+ "+job",
+#else
+ "-job",
+#endif
+#ifdef FEAT_JUMPLIST
+ "+jumplist",
+#else
+ "-jumplist",
+#endif
+#ifdef FEAT_KEYMAP
+ "+keymap",
+#else
+ "-keymap",
+#endif
+#ifdef FEAT_EVAL
+ "+lambda",
+#else
+ "-lambda",
+#endif
+#ifdef FEAT_LANGMAP
+ "+langmap",
+#else
+ "-langmap",
+#endif
+#ifdef FEAT_LIBCALL
+ "+libcall",
+#else
+ "-libcall",
+#endif
+#ifdef FEAT_LINEBREAK
+ "+linebreak",
+#else
+ "-linebreak",
+#endif
+#ifdef FEAT_LISP
+ "+lispindent",
+#else
+ "-lispindent",
+#endif
+ "+listcmds",
+#ifdef FEAT_LOCALMAP
+ "+localmap",
+#else
+ "-localmap",
+#endif
+#ifdef FEAT_LUA
+# ifdef DYNAMIC_LUA
+ "+lua/dyn",
+# else
+ "+lua",
+# endif
+#else
+ "-lua",
+#endif
+#ifdef FEAT_MENU
+ "+menu",
+#else
+ "-menu",
+#endif
+#ifdef FEAT_SESSION
+ "+mksession",
+#else
+ "-mksession",
+#endif
+#ifdef FEAT_MODIFY_FNAME
+ "+modify_fname",
+#else
+ "-modify_fname",
+#endif
+#ifdef FEAT_MOUSE
+ "+mouse",
+# ifdef FEAT_MOUSESHAPE
+ "+mouseshape",
+# else
+ "-mouseshape",
+# endif
+# else
+ "-mouse",
+#endif
+
+#if defined(UNIX) || defined(VMS)
+# ifdef FEAT_MOUSE_DEC
+ "+mouse_dec",
+# else
+ "-mouse_dec",
+# endif
+# ifdef FEAT_MOUSE_GPM
+ "+mouse_gpm",
+# else
+ "-mouse_gpm",
+# endif
+# ifdef FEAT_MOUSE_JSB
+ "+mouse_jsbterm",
+# else
+ "-mouse_jsbterm",
+# endif
+# ifdef FEAT_MOUSE_NET
+ "+mouse_netterm",
+# else
+ "-mouse_netterm",
+# endif
+#endif
+
+#ifdef __QNX__
+# ifdef FEAT_MOUSE_PTERM
+ "+mouse_pterm",
+# else
+ "-mouse_pterm",
+# endif
+#endif
+
+#if defined(UNIX) || defined(VMS)
+# ifdef FEAT_MOUSE_SGR
+ "+mouse_sgr",
+# else
+ "-mouse_sgr",
+# endif
+# ifdef FEAT_SYSMOUSE
+ "+mouse_sysmouse",
+# else
+ "-mouse_sysmouse",
+# endif
+# ifdef FEAT_MOUSE_URXVT
+ "+mouse_urxvt",
+# else
+ "-mouse_urxvt",
+# endif
+# ifdef FEAT_MOUSE_XTERM
+ "+mouse_xterm",
+# else
+ "-mouse_xterm",
+# endif
+#endif
+
+#ifdef FEAT_MBYTE_IME
+# ifdef DYNAMIC_IME
+ "+multi_byte_ime/dyn",
+# else
+ "+multi_byte_ime",
+# endif
+#else
+ "+multi_byte",
+#endif
+#ifdef FEAT_MULTI_LANG
+ "+multi_lang",
+#else
+ "-multi_lang",
+#endif
+#ifdef FEAT_MZSCHEME
+# ifdef DYNAMIC_MZSCHEME
+ "+mzscheme/dyn",
+# else
+ "+mzscheme",
+# endif
+#else
+ "-mzscheme",
+#endif
+#ifdef FEAT_NETBEANS_INTG
+ "+netbeans_intg",
+#else
+ "-netbeans_intg",
+#endif
+#ifdef FEAT_NUM64
+ "+num64",
+#else
+ "-num64",
+#endif
+#ifdef FEAT_GUI_W32
+# ifdef FEAT_OLE
+ "+ole",
+# else
+ "-ole",
+# endif
+#endif
+#ifdef FEAT_EVAL
+ "+packages",
+#else
+ "-packages",
+#endif
+#ifdef FEAT_PATH_EXTRA
+ "+path_extra",
+#else
+ "-path_extra",
+#endif
+#ifdef FEAT_PERL
+# ifdef DYNAMIC_PERL
+ "+perl/dyn",
+# else
+ "+perl",
+# endif
+#else
+ "-perl",
+#endif
+#ifdef FEAT_PERSISTENT_UNDO
+ "+persistent_undo",
+#else
+ "-persistent_undo",
+#endif
+#ifdef FEAT_PRINTER
+# ifdef FEAT_POSTSCRIPT
+ "+postscript",
+# else
+ "-postscript",
+# endif
+ "+printer",
+#else
+ "-printer",
+#endif
+#ifdef FEAT_PROFILE
+ "+profile",
+#else
+ "-profile",
+#endif
+#ifdef FEAT_PYTHON
+# ifdef DYNAMIC_PYTHON
+ "+python/dyn",
+# else
+ "+python",
+# endif
+#else
+ "-python",
+#endif
+#ifdef FEAT_PYTHON3
+# ifdef DYNAMIC_PYTHON3
+ "+python3/dyn",
+# else
+ "+python3",
+# endif
+#else
+ "-python3",
+#endif
+#ifdef FEAT_QUICKFIX
+ "+quickfix",
+#else
+ "-quickfix",
+#endif
+#ifdef FEAT_RELTIME
+ "+reltime",
+#else
+ "-reltime",
+#endif
+#ifdef FEAT_RIGHTLEFT
+ "+rightleft",
+#else
+ "-rightleft",
+#endif
+#ifdef FEAT_RUBY
+# ifdef DYNAMIC_RUBY
+ "+ruby/dyn",
+# else
+ "+ruby",
+# endif
+#else
+ "-ruby",
+#endif
+ "+scrollbind",
+#ifdef FEAT_SIGNS
+ "+signs",
+#else
+ "-signs",
+#endif
+#ifdef FEAT_SMARTINDENT
+ "+smartindent",
+#else
+ "-smartindent",
+#endif
+#ifdef STARTUPTIME
+ "+startuptime",
+#else
+ "-startuptime",
+#endif
+#ifdef FEAT_STL_OPT
+ "+statusline",
+#else
+ "-statusline",
+#endif
+ "-sun_workshop",
+#ifdef FEAT_SYN_HL
+ "+syntax",
+#else
+ "-syntax",
+#endif
+ /* only interesting on Unix systems */
+#if defined(USE_SYSTEM) && defined(UNIX)
+ "+system()",
+#endif
+#ifdef FEAT_TAG_BINS
+ "+tag_binary",
+#else
+ "-tag_binary",
+#endif
+#ifdef FEAT_TAG_OLDSTATIC
+ "+tag_old_static",
+#else
+ "-tag_old_static",
+#endif
+#ifdef FEAT_TAG_ANYWHITE
+ "+tag_any_white",
+#else
+ "-tag_any_white",
+#endif
+#ifdef FEAT_TCL
+# ifdef DYNAMIC_TCL
+ "+tcl/dyn",
+# else
+ "+tcl",
+# endif
+#else
+ "-tcl",
+#endif
+#ifdef FEAT_TERMGUICOLORS
+ "+termguicolors",
+#else
+ "-termguicolors",
+#endif
+#ifdef FEAT_TERMINAL
+ "+terminal",
+#else
+ "-terminal",
+#endif
+#if defined(UNIX)
+/* only Unix can have terminfo instead of termcap */
+# ifdef TERMINFO
+ "+terminfo",
+# else
+ "-terminfo",
+# endif
+#endif
+#ifdef FEAT_TERMRESPONSE
+ "+termresponse",
+#else
+ "-termresponse",
+#endif
+#ifdef FEAT_TEXTOBJ
+ "+textobjects",
+#else
+ "-textobjects",
+#endif
+#ifdef FEAT_TEXT_PROP
+ "+textprop",
+#else
+ "-textprop",
+#endif
+#if !defined(UNIX)
+/* unix always includes termcap support */
+# ifdef HAVE_TGETENT
+ "+tgetent",
+# else
+ "-tgetent",
+# endif
+#endif
+#ifdef FEAT_TIMERS
+ "+timers",
+#else
+ "-timers",
+#endif
+#ifdef FEAT_TITLE
+ "+title",
+#else
+ "-title",
+#endif
+#ifdef FEAT_TOOLBAR
+ "+toolbar",
+#else
+ "-toolbar",
+#endif
+#ifdef FEAT_USR_CMDS
+ "+user_commands",
+#else
+ "-user_commands",
+#endif
+#ifdef FEAT_VARTABS
+ "+vartabs",
+#else
+ "-vartabs",
+#endif
+ "+vertsplit",
+ "+virtualedit",
+ "+visual",
+ "+visualextra",
+#ifdef FEAT_VIMINFO
+ "+viminfo",
+#else
+ "-viminfo",
+#endif
+ "+vreplace",
+#ifdef WIN3264
+# ifdef FEAT_VTP
+ "+vtp",
+# else
+ "-vtp",
+# endif
+#endif
+#ifdef FEAT_WILDIGN
+ "+wildignore",
+#else
+ "-wildignore",
+#endif
+#ifdef FEAT_WILDMENU
+ "+wildmenu",
+#else
+ "-wildmenu",
+#endif
+ "+windows",
+#ifdef FEAT_WRITEBACKUP
+ "+writebackup",
+#else
+ "-writebackup",
+#endif
+#if defined(UNIX) || defined(VMS)
+# ifdef FEAT_X11
+ "+X11",
+# else
+ "-X11",
+# endif
+#endif
+#ifdef FEAT_XFONTSET
+ "+xfontset",
+#else
+ "-xfontset",
+#endif
+#ifdef FEAT_XIM
+ "+xim",
+#else
+ "-xim",
+#endif
+#ifdef WIN3264
+# ifdef FEAT_XPM_W32
+ "+xpm_w32",
+# else
+ "-xpm_w32",
+# endif
+#else
+# ifdef HAVE_XPM
+ "+xpm",
+# else
+ "-xpm",
+# endif
+#endif
+#if defined(UNIX) || defined(VMS)
+# ifdef USE_XSMP_INTERACT
+ "+xsmp_interact",
+# else
+# ifdef USE_XSMP
+ "+xsmp",
+# else
+ "-xsmp",
+# endif
+# endif
+# ifdef FEAT_XCLIPBOARD
+ "+xterm_clipboard",
+# else
+ "-xterm_clipboard",
+# endif
+#endif
+#ifdef FEAT_XTERM_SAVE
+ "+xterm_save",
+#else
+ "-xterm_save",
+#endif
+ NULL
+};
+
+static int included_patches[] =
+{ /* Add new patch number below this line */
+/**/
+ 875,
+/**/
+ 874,
+/**/
+ 873,
+/**/
+ 872,
+/**/
+ 871,
+/**/
+ 870,
+/**/
+ 869,
+/**/
+ 868,
+/**/
+ 867,
+/**/
+ 866,
+/**/
+ 865,
+/**/
+ 864,
+/**/
+ 863,
+/**/
+ 862,
+/**/
+ 861,
+/**/
+ 860,
+/**/
+ 859,
+/**/
+ 858,
+/**/
+ 857,
+/**/
+ 856,
+/**/
+ 855,
+/**/
+ 854,
+/**/
+ 853,
+/**/
+ 852,
+/**/
+ 851,
+/**/
+ 850,
+/**/
+ 849,
+/**/
+ 848,
+/**/
+ 847,
+/**/
+ 846,
+/**/
+ 845,
+/**/
+ 844,
+/**/
+ 843,
+/**/
+ 842,
+/**/
+ 841,
+/**/
+ 840,
+/**/
+ 839,
+/**/
+ 838,
+/**/
+ 837,
+/**/
+ 836,
+/**/
+ 835,
+/**/
+ 834,
+/**/
+ 833,
+/**/
+ 832,
+/**/
+ 831,
+/**/
+ 830,
+/**/
+ 829,
+/**/
+ 828,
+/**/
+ 827,
+/**/
+ 826,
+/**/
+ 825,
+/**/
+ 824,
+/**/
+ 823,
+/**/
+ 822,
+/**/
+ 821,
+/**/
+ 820,
+/**/
+ 819,
+/**/
+ 818,
+/**/
+ 817,
+/**/
+ 816,
+/**/
+ 815,
+/**/
+ 814,
+/**/
+ 813,
+/**/
+ 812,
+/**/
+ 811,
+/**/
+ 810,
+/**/
+ 809,
+/**/
+ 808,
+/**/
+ 807,
+/**/
+ 806,
+/**/
+ 805,
+/**/
+ 804,
+/**/
+ 803,
+/**/
+ 802,
+/**/
+ 801,
+/**/
+ 800,
+/**/
+ 799,
+/**/
+ 798,
+/**/
+ 797,
+/**/
+ 796,
+/**/
+ 795,
+/**/
+ 794,
+/**/
+ 793,
+/**/
+ 792,
+/**/
+ 791,
+/**/
+ 790,
+/**/
+ 789,
+/**/
+ 788,
+/**/
+ 787,
+/**/
+ 786,
+/**/
+ 785,
+/**/
+ 784,
+/**/
+ 783,
+/**/
+ 782,
+/**/
+ 781,
+/**/
+ 780,
+/**/
+ 779,
+/**/
+ 778,
+/**/
+ 777,
+/**/
+ 776,
+/**/
+ 775,
+/**/
+ 774,
+/**/
+ 773,
+/**/
+ 772,
+/**/
+ 771,
+/**/
+ 770,
+/**/
+ 769,
+/**/
+ 768,
+/**/
+ 767,
+/**/
+ 766,
+/**/
+ 765,
+/**/
+ 764,
+/**/
+ 763,
+/**/
+ 762,
+/**/
+ 761,
+/**/
+ 760,
+/**/
+ 759,
+/**/
+ 758,
+/**/
+ 757,
+/**/
+ 756,
+/**/
+ 755,
+/**/
+ 754,
+/**/
+ 753,
+/**/
+ 752,
+/**/
+ 751,
+/**/
+ 750,
+/**/
+ 749,
+/**/
+ 748,
+/**/
+ 747,
+/**/
+ 746,
+/**/
+ 745,
+/**/
+ 744,
+/**/
+ 743,
+/**/
+ 742,
+/**/
+ 741,
+/**/
+ 740,
+/**/
+ 739,
+/**/
+ 738,
+/**/
+ 737,
+/**/
+ 736,
+/**/
+ 735,
+/**/
+ 734,
+/**/
+ 733,
+/**/
+ 732,
+/**/
+ 731,
+/**/
+ 730,
+/**/
+ 729,
+/**/
+ 728,
+/**/
+ 727,
+/**/
+ 726,
+/**/
+ 725,
+/**/
+ 724,
+/**/
+ 723,
+/**/
+ 722,
+/**/
+ 721,
+/**/
+ 720,
+/**/
+ 719,
+/**/
+ 718,
+/**/
+ 717,
+/**/
+ 716,
+/**/
+ 715,
+/**/
+ 714,
+/**/
+ 713,
+/**/
+ 712,
+/**/
+ 711,
+/**/
+ 710,
+/**/
+ 709,
+/**/
+ 708,
+/**/
+ 707,
+/**/
+ 706,
+/**/
+ 705,
+/**/
+ 704,
+/**/
+ 703,
+/**/
+ 702,
+/**/
+ 701,
+/**/
+ 700,
+/**/
+ 699,
+/**/
+ 698,
+/**/
+ 697,
+/**/
+ 696,
+/**/
+ 695,
+/**/
+ 694,
+/**/
+ 693,
+/**/
+ 692,
+/**/
+ 691,
+/**/
+ 690,
+/**/
+ 689,
+/**/
+ 688,
+/**/
+ 687,
+/**/
+ 686,
+/**/
+ 685,
+/**/
+ 684,
+/**/
+ 683,
+/**/
+ 682,
+/**/
+ 681,
+/**/
+ 680,
+/**/
+ 679,
+/**/
+ 678,
+/**/
+ 677,
+/**/
+ 676,
+/**/
+ 675,
+/**/
+ 674,
+/**/
+ 673,
+/**/
+ 672,
+/**/
+ 671,
+/**/
+ 670,
+/**/
+ 669,
+/**/
+ 668,
+/**/
+ 667,
+/**/
+ 666,
+/**/
+ 665,
+/**/
+ 664,
+/**/
+ 663,
+/**/
+ 662,
+/**/
+ 661,
+/**/
+ 660,
+/**/
+ 659,
+/**/
+ 658,
+/**/
+ 657,
+/**/
+ 656,
+/**/
+ 655,
+/**/
+ 654,
+/**/
+ 653,
+/**/
+ 652,
+/**/
+ 651,
+/**/
+ 650,
+/**/
+ 649,
+/**/
+ 648,
+/**/
+ 647,
+/**/
+ 646,
+/**/
+ 645,
+/**/
+ 644,
+/**/
+ 643,
+/**/
+ 642,
+/**/
+ 641,
+/**/
+ 640,
+/**/
+ 639,
+/**/
+ 638,
+/**/
+ 637,
+/**/
+ 636,
+/**/
+ 635,
+/**/
+ 634,
+/**/
+ 633,
+/**/
+ 632,
+/**/
+ 631,
+/**/
+ 630,
+/**/
+ 629,
+/**/
+ 628,
+/**/
+ 627,
+/**/
+ 626,
+/**/
+ 625,
+/**/
+ 624,
+/**/
+ 623,
+/**/
+ 622,
+/**/
+ 621,
+/**/
+ 620,
+/**/
+ 619,
+/**/
+ 618,
+/**/
+ 617,
+/**/
+ 616,
+/**/
+ 615,
+/**/
+ 614,
+/**/
+ 613,
+/**/
+ 612,
+/**/
+ 611,
+/**/
+ 610,
+/**/
+ 609,
+/**/
+ 608,
+/**/
+ 607,
+/**/
+ 606,
+/**/
+ 605,
+/**/
+ 604,
+/**/
+ 603,
+/**/
+ 602,
+/**/
+ 601,
+/**/
+ 600,
+/**/
+ 599,
+/**/
+ 598,
+/**/
+ 597,
+/**/
+ 596,
+/**/
+ 595,
+/**/
+ 594,
+/**/
+ 593,
+/**/
+ 592,
+/**/
+ 591,
+/**/
+ 590,
+/**/
+ 589,
+/**/
+ 588,
+/**/
+ 587,
+/**/
+ 586,
+/**/
+ 585,
+/**/
+ 584,
+/**/
+ 583,
+/**/
+ 582,
+/**/
+ 581,
+/**/
+ 580,
+/**/
+ 579,
+/**/
+ 578,
+/**/
+ 577,
+/**/
+ 576,
+/**/
+ 575,
+/**/
+ 574,
+/**/
+ 573,
+/**/
+ 572,
+/**/
+ 571,
+/**/
+ 570,
+/**/
+ 569,
+/**/
+ 568,
+/**/
+ 567,
+/**/
+ 566,
+/**/
+ 565,
+/**/
+ 564,
+/**/
+ 563,
+/**/
+ 562,
+/**/
+ 561,
+/**/
+ 560,
+/**/
+ 559,
+/**/
+ 558,
+/**/
+ 557,
+/**/
+ 556,
+/**/
+ 555,
+/**/
+ 554,
+/**/
+ 553,
+/**/
+ 552,
+/**/
+ 551,
+/**/
+ 550,
+/**/
+ 549,
+/**/
+ 548,
+/**/
+ 547,
+/**/
+ 546,
+/**/
+ 545,
+/**/
+ 544,
+/**/
+ 543,
+/**/
+ 542,
+/**/
+ 541,
+/**/
+ 540,
+/**/
+ 539,
+/**/
+ 538,
+/**/
+ 537,
+/**/
+ 536,
+/**/
+ 535,
+/**/
+ 534,
+/**/
+ 533,
+/**/
+ 532,
+/**/
+ 531,
+/**/
+ 530,
+/**/
+ 529,
+/**/
+ 528,
+/**/
+ 527,
+/**/
+ 526,
+/**/
+ 525,
+/**/
+ 524,
+/**/
+ 523,
+/**/
+ 522,
+/**/
+ 521,
+/**/
+ 520,
+/**/
+ 519,
+/**/
+ 518,
+/**/
+ 517,
+/**/
+ 516,
+/**/
+ 515,
+/**/
+ 514,
+/**/
+ 513,
+/**/
+ 512,
+/**/
+ 511,
+/**/
+ 510,
+/**/
+ 509,
+/**/
+ 508,
+/**/
+ 507,
+/**/
+ 506,
+/**/
+ 505,
+/**/
+ 504,
+/**/
+ 503,
+/**/
+ 502,
+/**/
+ 501,
+/**/
+ 500,
+/**/
+ 499,
+/**/
+ 498,
+/**/
+ 497,
+/**/
+ 496,
+/**/
+ 495,
+/**/
+ 494,
+/**/
+ 493,
+/**/
+ 492,
+/**/
+ 491,
+/**/
+ 490,
+/**/
+ 489,
+/**/
+ 488,
+/**/
+ 487,
+/**/
+ 486,
+/**/
+ 485,
+/**/
+ 484,
+/**/
+ 483,
+/**/
+ 482,
+/**/
+ 481,
+/**/
+ 480,
+/**/
+ 479,
+/**/
+ 478,
+/**/
+ 477,
+/**/
+ 476,
+/**/
+ 475,
+/**/
+ 474,
+/**/
+ 473,
+/**/
+ 472,
+/**/
+ 471,
+/**/
+ 470,
+/**/
+ 469,
+/**/
+ 468,
+/**/
+ 467,
+/**/
+ 466,
+/**/
+ 465,
+/**/
+ 464,
+/**/
+ 463,
+/**/
+ 462,
+/**/
+ 461,
+/**/
+ 460,
+/**/
+ 459,
+/**/
+ 458,
+/**/
+ 457,
+/**/
+ 456,
+/**/
+ 455,
+/**/
+ 454,
+/**/
+ 453,
+/**/
+ 452,
+/**/
+ 451,
+/**/
+ 450,
+/**/
+ 449,
+/**/
+ 448,
+/**/
+ 447,
+/**/
+ 446,
+/**/
+ 445,
+/**/
+ 444,
+/**/
+ 443,
+/**/
+ 442,
+/**/
+ 441,
+/**/
+ 440,
+/**/
+ 439,
+/**/
+ 438,
+/**/
+ 437,
+/**/
+ 436,
+/**/
+ 435,
+/**/
+ 434,
+/**/
+ 433,
+/**/
+ 432,
+/**/
+ 431,
+/**/
+ 430,
+/**/
+ 429,
+/**/
+ 428,
+/**/
+ 427,
+/**/
+ 426,
+/**/
+ 425,
+/**/
+ 424,
+/**/
+ 423,
+/**/
+ 422,
+/**/
+ 421,
+/**/
+ 420,
+/**/
+ 419,
+/**/
+ 418,
+/**/
+ 417,
+/**/
+ 416,
+/**/
+ 415,
+/**/
+ 414,
+/**/
+ 413,
+/**/
+ 412,
+/**/
+ 411,
+/**/
+ 410,
+/**/
+ 409,
+/**/
+ 408,
+/**/
+ 407,
+/**/
+ 406,
+/**/
+ 405,
+/**/
+ 404,
+/**/
+ 403,
+/**/
+ 402,
+/**/
+ 401,
+/**/
+ 400,
+/**/
+ 399,
+/**/
+ 398,
+/**/
+ 397,
+/**/
+ 396,
+/**/
+ 395,
+/**/
+ 394,
+/**/
+ 393,
+/**/
+ 392,
+/**/
+ 391,
+/**/
+ 390,
+/**/
+ 389,
+/**/
+ 388,
+/**/
+ 387,
+/**/
+ 386,
+/**/
+ 385,
+/**/
+ 384,
+/**/
+ 383,
+/**/
+ 382,
+/**/
+ 381,
+/**/
+ 380,
+/**/
+ 379,
+/**/
+ 378,
+/**/
+ 377,
+/**/
+ 376,
+/**/
+ 375,
+/**/
+ 374,
+/**/
+ 373,
+/**/
+ 372,
+/**/
+ 371,
+/**/
+ 370,
+/**/
+ 369,
+/**/
+ 368,
+/**/
+ 367,
+/**/
+ 366,
+/**/
+ 365,
+/**/
+ 364,
+/**/
+ 363,
+/**/
+ 362,
+/**/
+ 361,
+/**/
+ 360,
+/**/
+ 359,
+/**/
+ 358,
+/**/
+ 357,
+/**/
+ 356,
+/**/
+ 355,
+/**/
+ 354,
+/**/
+ 353,
+/**/
+ 352,
+/**/
+ 351,
+/**/
+ 350,
+/**/
+ 349,
+/**/
+ 348,
+/**/
+ 347,
+/**/
+ 346,
+/**/
+ 345,
+/**/
+ 344,
+/**/
+ 343,
+/**/
+ 342,
+/**/
+ 341,
+/**/
+ 340,
+/**/
+ 339,
+/**/
+ 338,
+/**/
+ 337,
+/**/
+ 336,
+/**/
+ 335,
+/**/
+ 334,
+/**/
+ 333,
+/**/
+ 332,
+/**/
+ 331,
+/**/
+ 330,
+/**/
+ 329,
+/**/
+ 328,
+/**/
+ 327,
+/**/
+ 326,
+/**/
+ 325,
+/**/
+ 324,
+/**/
+ 323,
+/**/
+ 322,
+/**/
+ 321,
+/**/
+ 320,
+/**/
+ 319,
+/**/
+ 318,
+/**/
+ 317,
+/**/
+ 316,
+/**/
+ 315,
+/**/
+ 314,
+/**/
+ 313,
+/**/
+ 312,
+/**/
+ 311,
+/**/
+ 310,
+/**/
+ 309,
+/**/
+ 308,
+/**/
+ 307,
+/**/
+ 306,
+/**/
+ 305,
+/**/
+ 304,
+/**/
+ 303,
+/**/
+ 302,
+/**/
+ 301,
+/**/
+ 300,
+/**/
+ 299,
+/**/
+ 298,
+/**/
+ 297,
+/**/
+ 296,
+/**/
+ 295,
+/**/
+ 294,
+/**/
+ 293,
+/**/
+ 292,
+/**/
+ 291,
+/**/
+ 290,
+/**/
+ 289,
+/**/
+ 288,
+/**/
+ 287,
+/**/
+ 286,
+/**/
+ 285,
+/**/
+ 284,
+/**/
+ 283,
+/**/
+ 282,
+/**/
+ 281,
+/**/
+ 280,
+/**/
+ 279,
+/**/
+ 278,
+/**/
+ 277,
+/**/
+ 276,
+/**/
+ 275,
+/**/
+ 274,
+/**/
+ 273,
+/**/
+ 272,
+/**/
+ 271,
+/**/
+ 270,
+/**/
+ 269,
+/**/
+ 268,
+/**/
+ 267,
+/**/
+ 266,
+/**/
+ 265,
+/**/
+ 264,
+/**/
+ 263,
+/**/
+ 262,
+/**/
+ 261,
+/**/
+ 260,
+/**/
+ 259,
+/**/
+ 258,
+/**/
+ 257,
+/**/
+ 256,
+/**/
+ 255,
+/**/
+ 254,
+/**/
+ 253,
+/**/
+ 252,
+/**/
+ 251,
+/**/
+ 250,
+/**/
+ 249,
+/**/
+ 248,
+/**/
+ 247,
+/**/
+ 246,
+/**/
+ 245,
+/**/
+ 244,
+/**/
+ 243,
+/**/
+ 242,
+/**/
+ 241,
+/**/
+ 240,
+/**/
+ 239,
+/**/
+ 238,
+/**/
+ 237,
+/**/
+ 236,
+/**/
+ 235,
+/**/
+ 234,
+/**/
+ 233,
+/**/
+ 232,
+/**/
+ 231,
+/**/
+ 230,
+/**/
+ 229,
+/**/
+ 228,
+/**/
+ 227,
+/**/
+ 226,
+/**/
+ 225,
+/**/
+ 224,
+/**/
+ 223,
+/**/
+ 222,
+/**/
+ 221,
+/**/
+ 220,
+/**/
+ 219,
+/**/
+ 218,
+/**/
+ 217,
+/**/
+ 216,
+/**/
+ 215,
+/**/
+ 214,
+/**/
+ 213,
+/**/
+ 212,
+/**/
+ 211,
+/**/
+ 210,
+/**/
+ 209,
+/**/
+ 208,
+/**/
+ 207,
+/**/
+ 206,
+/**/
+ 205,
+/**/
+ 204,
+/**/
+ 203,
+/**/
+ 202,
+/**/
+ 201,
+/**/
+ 200,
+/**/
+ 199,
+/**/
+ 198,
+/**/
+ 197,
+/**/
+ 196,
+/**/
+ 195,
+/**/
+ 194,
+/**/
+ 193,
+/**/
+ 192,
+/**/
+ 191,
+/**/
+ 190,
+/**/
+ 189,
+/**/
+ 188,
+/**/
+ 187,
+/**/
+ 186,
+/**/
+ 185,
+/**/
+ 184,
+/**/
+ 183,
+/**/
+ 182,
+/**/
+ 181,
+/**/
+ 180,
+/**/
+ 179,
+/**/
+ 178,
+/**/
+ 177,
+/**/
+ 176,
+/**/
+ 175,
+/**/
+ 174,
+/**/
+ 173,
+/**/
+ 172,
+/**/
+ 171,
+/**/
+ 170,
+/**/
+ 169,
+/**/
+ 168,
+/**/
+ 167,
+/**/
+ 166,
+/**/
+ 165,
+/**/
+ 164,
+/**/
+ 163,
+/**/
+ 162,
+/**/
+ 161,
+/**/
+ 160,
+/**/
+ 159,
+/**/
+ 158,
+/**/
+ 157,
+/**/
+ 156,
+/**/
+ 155,
+/**/
+ 154,
+/**/
+ 153,
+/**/
+ 152,
+/**/
+ 151,
+/**/
+ 150,
+/**/
+ 149,
+/**/
+ 148,
+/**/
+ 147,
+/**/
+ 146,
+/**/
+ 145,
+/**/
+ 144,
+/**/
+ 143,
+/**/
+ 142,
+/**/
+ 141,
+/**/
+ 140,
+/**/
+ 139,
+/**/
+ 138,
+/**/
+ 137,
+/**/
+ 136,
+/**/
+ 135,
+/**/
+ 134,
+/**/
+ 133,
+/**/
+ 132,
+/**/
+ 131,
+/**/
+ 130,
+/**/
+ 129,
+/**/
+ 128,
+/**/
+ 127,
+/**/
+ 126,
+/**/
+ 125,
+/**/
+ 124,
+/**/
+ 123,
+/**/
+ 122,
+/**/
+ 121,
+/**/
+ 120,
+/**/
+ 119,
+/**/
+ 118,
+/**/
+ 117,
+/**/
+ 116,
+/**/
+ 115,
+/**/
+ 114,
+/**/
+ 113,
+/**/
+ 112,
+/**/
+ 111,
+/**/
+ 110,
+/**/
+ 109,
+/**/
+ 108,
+/**/
+ 107,
+/**/
+ 106,
+/**/
+ 105,
+/**/
+ 104,
+/**/
+ 103,
+/**/
+ 102,
+/**/
+ 101,
+/**/
+ 100,
+/**/
+ 99,
+/**/
+ 98,
+/**/
+ 97,
+/**/
+ 96,
+/**/
+ 95,
+/**/
+ 94,
+/**/
+ 93,
+/**/
+ 92,
+/**/
+ 91,
+/**/
+ 90,
+/**/
+ 89,
+/**/
+ 88,
+/**/
+ 87,
+/**/
+ 86,
+/**/
+ 85,
+/**/
+ 84,
+/**/
+ 83,
+/**/
+ 82,
+/**/
+ 81,
+/**/
+ 80,
+/**/
+ 79,
+/**/
+ 78,
+/**/
+ 77,
+/**/
+ 76,
+/**/
+ 75,
+/**/
+ 74,
+/**/
+ 73,
+/**/
+ 72,
+/**/
+ 71,
+/**/
+ 70,
+/**/
+ 69,
+/**/
+ 68,
+/**/
+ 67,
+/**/
+ 66,
+/**/
+ 65,
+/**/
+ 64,
+/**/
+ 63,
+/**/
+ 62,
+/**/
+ 61,
+/**/
+ 60,
+/**/
+ 59,
+/**/
+ 58,
+/**/
+ 57,
+/**/
+ 56,
+/**/
+ 55,
+/**/
+ 54,
+/**/
+ 53,
+/**/
+ 52,
+/**/
+ 51,
+/**/
+ 50,
+/**/
+ 49,
+/**/
+ 48,
+/**/
+ 47,
+/**/
+ 46,
+/**/
+ 45,
+/**/
+ 44,
+/**/
+ 43,
+/**/
+ 42,
+/**/
+ 41,
+/**/
+ 40,
+/**/
+ 39,
+/**/
+ 38,
+/**/
+ 37,
+/**/
+ 36,
+/**/
+ 35,
+/**/
+ 34,
+/**/
+ 33,
+/**/
+ 32,
+/**/
+ 31,
+/**/
+ 30,
+/**/
+ 29,
+/**/
+ 28,
+/**/
+ 27,
+/**/
+ 26,
+/**/
+ 25,
+/**/
+ 24,
+/**/
+ 23,
+/**/
+ 22,
+/**/
+ 21,
+/**/
+ 20,
+/**/
+ 19,
+/**/
+ 18,
+/**/
+ 17,
+/**/
+ 16,
+/**/
+ 15,
+/**/
+ 14,
+/**/
+ 13,
+/**/
+ 12,
+/**/
+ 11,
+/**/
+ 10,
+/**/
+ 9,
+/**/
+ 8,
+/**/
+ 7,
+/**/
+ 6,
+/**/
+ 5,
+/**/
+ 4,
+/**/
+ 3,
+/**/
+ 2,
+/**/
+ 1,
+/**/
+ 0
+};
+
+/*
+ * Place to put a short description when adding a feature with a patch.
+ * Keep it short, e.g.,: "relative numbers", "persistent undo".
+ * Also add a comment marker to separate the lines.
+ * See the official Vim patches for the diff format: It must use a context of
+ * one line only. Create it by hand or use "diff -C2" and edit the patch.
+ */
+static char *(extra_patches[]) =
+{ /* Add your patch description below this line */
+/**/
+ NULL
+};
+
+ int
+highest_patch(void)
+{
+ int i;
+ int h = 0;
+
+ for (i = 0; included_patches[i] != 0; ++i)
+ if (included_patches[i] > h)
+ h = included_patches[i];
+ return h;
+}
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * Return TRUE if patch "n" has been included.
+ */
+ int
+has_patch(int n)
+{
+ int i;
+
+ for (i = 0; included_patches[i] != 0; ++i)
+ if (included_patches[i] == n)
+ return TRUE;
+ return FALSE;
+}
+#endif
+
+ void
+ex_version(exarg_T *eap)
+{
+ /*
+ * Ignore a ":version 9.99" command.
+ */
+ if (*eap->arg == NUL)
+ {
+ msg_putchar('\n');
+ list_version();
+ }
+}
+
+/*
+ * Output a string for the version message. If it's going to wrap, output a
+ * newline, unless the message is too long to fit on the screen anyway.
+ * When "wrap" is TRUE wrap the string in [].
+ */
+ static void
+version_msg_wrap(char_u *s, int wrap)
+{
+ int len = (int)vim_strsize(s) + (wrap ? 2 : 0);
+
+ if (!got_int && len < (int)Columns && msg_col + len >= (int)Columns
+ && *s != '\n')
+ msg_putchar('\n');
+ if (!got_int)
+ {
+ if (wrap)
+ msg_puts("[");
+ msg_puts((char *)s);
+ if (wrap)
+ msg_puts("]");
+ }
+}
+
+ static void
+version_msg(char *s)
+{
+ version_msg_wrap((char_u *)s, FALSE);
+}
+
+/*
+ * List all features aligned in columns, dictionary style.
+ */
+ static void
+list_features(void)
+{
+ list_in_columns((char_u **)features, -1, -1);
+}
+
+/*
+ * List string items nicely aligned in columns.
+ * When "size" is < 0 then the last entry is marked with NULL.
+ * The entry with index "current" is inclosed in [].
+ */
+ void
+list_in_columns(char_u **items, int size, int current)
+{
+ int i;
+ int ncol;
+ int nrow;
+ int item_count = 0;
+ int width = 0;
+#ifdef FEAT_SYN_HL
+ int use_highlight = (items == (char_u **)features);
+#endif
+
+ /* Find the length of the longest item, use that + 1 as the column
+ * width. */
+ for (i = 0; size < 0 ? items[i] != NULL : i < size; ++i)
+ {
+ int l = (int)vim_strsize(items[i]) + (i == current ? 2 : 0);
+
+ if (l > width)
+ width = l;
+ ++item_count;
+ }
+ width += 1;
+
+ if (Columns < width)
+ {
+ /* Not enough screen columns - show one per line */
+ for (i = 0; i < item_count; ++i)
+ {
+ version_msg_wrap(items[i], i == current);
+ if (msg_col > 0)
+ msg_putchar('\n');
+ }
+ return;
+ }
+
+ /* The rightmost column doesn't need a separator.
+ * Sacrifice it to fit in one more column if possible. */
+ ncol = (int) (Columns + 1) / width;
+ nrow = item_count / ncol + (item_count % ncol ? 1 : 0);
+
+ /* i counts columns then rows. idx counts rows then columns. */
+ for (i = 0; !got_int && i < nrow * ncol; ++i)
+ {
+ int idx = (i / ncol) + (i % ncol) * nrow;
+
+ if (idx < item_count)
+ {
+ int last_col = (i + 1) % ncol == 0;
+
+ if (idx == current)
+ msg_putchar('[');
+#ifdef FEAT_SYN_HL
+ if (use_highlight && items[idx][0] == '-')
+ msg_puts_attr((char *)items[idx], HL_ATTR(HLF_W));
+ else
+#endif
+ msg_puts((char *)items[idx]);
+ if (idx == current)
+ msg_putchar(']');
+ if (last_col)
+ {
+ if (msg_col > 0)
+ msg_putchar('\n');
+ }
+ else
+ {
+ while (msg_col % width)
+ msg_putchar(' ');
+ }
+ }
+ else
+ {
+ if (msg_col > 0)
+ msg_putchar('\n');
+ }
+ }
+}
+
+ void
+list_version(void)
+{
+ int i;
+ int first;
+ char *s = "";
+
+ /*
+ * When adding features here, don't forget to update the list of
+ * internal variables in eval.c!
+ */
+ init_longVersion();
+ msg(longVersion);
+#ifdef WIN3264
+# ifdef FEAT_GUI_W32
+# ifdef _WIN64
+ msg_puts(_("\nMS-Windows 64-bit GUI version"));
+# else
+ msg_puts(_("\nMS-Windows 32-bit GUI version"));
+# endif
+# ifdef FEAT_OLE
+ msg_puts(_(" with OLE support"));
+# endif
+# else
+# ifdef _WIN64
+ msg_puts(_("\nMS-Windows 64-bit console version"));
+# else
+ msg_puts(_("\nMS-Windows 32-bit console version"));
+# endif
+# endif
+#endif
+#if defined(MACOS_X)
+# if defined(MACOS_X_DARWIN)
+ msg_puts(_("\nmacOS version"));
+# else
+ msg_puts(_("\nmacOS version w/o darwin feat."));
+# endif
+#endif
+
+#ifdef VMS
+ msg_puts(_("\nOpenVMS version"));
+# ifdef HAVE_PATHDEF
+ if (*compiled_arch != NUL)
+ {
+ msg_puts(" - ");
+ msg_puts((char *)compiled_arch);
+ }
+# endif
+
+#endif
+
+ /* Print the list of patch numbers if there is at least one. */
+ /* Print a range when patches are consecutive: "1-10, 12, 15-40, 42-45" */
+ if (included_patches[0] != 0)
+ {
+ msg_puts(_("\nIncluded patches: "));
+ first = -1;
+ /* find last one */
+ for (i = 0; included_patches[i] != 0; ++i)
+ ;
+ while (--i >= 0)
+ {
+ if (first < 0)
+ first = included_patches[i];
+ if (i == 0 || included_patches[i - 1] != included_patches[i] + 1)
+ {
+ msg_puts(s);
+ s = ", ";
+ msg_outnum((long)first);
+ if (first != included_patches[i])
+ {
+ msg_puts("-");
+ msg_outnum((long)included_patches[i]);
+ }
+ first = -1;
+ }
+ }
+ }
+
+ /* Print the list of extra patch descriptions if there is at least one. */
+ if (extra_patches[0] != NULL)
+ {
+ msg_puts(_("\nExtra patches: "));
+ s = "";
+ for (i = 0; extra_patches[i] != NULL; ++i)
+ {
+ msg_puts(s);
+ s = ", ";
+ msg_puts(extra_patches[i]);
+ }
+ }
+
+#ifdef MODIFIED_BY
+ msg_puts("\n");
+ msg_puts(_("Modified by "));
+ msg_puts(MODIFIED_BY);
+#endif
+
+#ifdef HAVE_PATHDEF
+ if (*compiled_user != NUL || *compiled_sys != NUL)
+ {
+ msg_puts(_("\nCompiled "));
+ if (*compiled_user != NUL)
+ {
+ msg_puts(_("by "));
+ msg_puts((char *)compiled_user);
+ }
+ if (*compiled_sys != NUL)
+ {
+ msg_puts("@");
+ msg_puts((char *)compiled_sys);
+ }
+ }
+#endif
+
+#ifdef FEAT_HUGE
+ msg_puts(_("\nHuge version "));
+#else
+# ifdef FEAT_BIG
+ msg_puts(_("\nBig version "));
+# else
+# ifdef FEAT_NORMAL
+ msg_puts(_("\nNormal version "));
+# else
+# ifdef FEAT_SMALL
+ msg_puts(_("\nSmall version "));
+# else
+ msg_puts(_("\nTiny version "));
+# endif
+# endif
+# endif
+#endif
+#ifndef FEAT_GUI
+ msg_puts(_("without GUI."));
+#else
+# ifdef FEAT_GUI_GTK
+# ifdef USE_GTK3
+ msg_puts(_("with GTK3 GUI."));
+# else
+# ifdef FEAT_GUI_GNOME
+ msg_puts(_("with GTK2-GNOME GUI."));
+# else
+ msg_puts(_("with GTK2 GUI."));
+# endif
+# endif
+# else
+# ifdef FEAT_GUI_MOTIF
+ msg_puts(_("with X11-Motif GUI."));
+# else
+# ifdef FEAT_GUI_ATHENA
+# ifdef FEAT_GUI_NEXTAW
+ msg_puts(_("with X11-neXtaw GUI."));
+# else
+ msg_puts(_("with X11-Athena GUI."));
+# endif
+# else
+# ifdef FEAT_GUI_PHOTON
+ msg_puts(_("with Photon GUI."));
+# else
+# if defined(MSWIN)
+ msg_puts(_("with 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
+ version_msg(_(" Features included (+) or not (-):\n"));
+
+ list_features();
+
+#ifdef SYS_VIMRC_FILE
+ version_msg(_(" system vimrc file: \""));
+ version_msg(SYS_VIMRC_FILE);
+ version_msg("\"\n");
+#endif
+#ifdef USR_VIMRC_FILE
+ version_msg(_(" user vimrc file: \""));
+ version_msg(USR_VIMRC_FILE);
+ version_msg("\"\n");
+#endif
+#ifdef USR_VIMRC_FILE2
+ version_msg(_(" 2nd user vimrc file: \""));
+ version_msg(USR_VIMRC_FILE2);
+ version_msg("\"\n");
+#endif
+#ifdef USR_VIMRC_FILE3
+ version_msg(_(" 3rd user vimrc file: \""));
+ version_msg(USR_VIMRC_FILE3);
+ version_msg("\"\n");
+#endif
+#ifdef USR_EXRC_FILE
+ version_msg(_(" user exrc file: \""));
+ version_msg(USR_EXRC_FILE);
+ version_msg("\"\n");
+#endif
+#ifdef USR_EXRC_FILE2
+ version_msg(_(" 2nd user exrc file: \""));
+ version_msg(USR_EXRC_FILE2);
+ version_msg("\"\n");
+#endif
+#ifdef FEAT_GUI
+# ifdef SYS_GVIMRC_FILE
+ version_msg(_(" system gvimrc file: \""));
+ version_msg(SYS_GVIMRC_FILE);
+ version_msg("\"\n");
+# endif
+ version_msg(_(" user gvimrc file: \""));
+ version_msg(USR_GVIMRC_FILE);
+ version_msg("\"\n");
+# ifdef USR_GVIMRC_FILE2
+ version_msg(_("2nd user gvimrc file: \""));
+ version_msg(USR_GVIMRC_FILE2);
+ version_msg("\"\n");
+# endif
+# ifdef USR_GVIMRC_FILE3
+ version_msg(_("3rd user gvimrc file: \""));
+ version_msg(USR_GVIMRC_FILE3);
+ version_msg("\"\n");
+# endif
+#endif
+ version_msg(_(" defaults file: \""));
+ version_msg(VIM_DEFAULTS_FILE);
+ version_msg("\"\n");
+#ifdef FEAT_GUI
+# ifdef SYS_MENU_FILE
+ version_msg(_(" system menu file: \""));
+ version_msg(SYS_MENU_FILE);
+ version_msg("\"\n");
+# endif
+#endif
+#ifdef HAVE_PATHDEF
+ if (*default_vim_dir != NUL)
+ {
+ version_msg(_(" fall-back for $VIM: \""));
+ version_msg((char *)default_vim_dir);
+ version_msg("\"\n");
+ }
+ if (*default_vimruntime_dir != NUL)
+ {
+ version_msg(_(" f-b for $VIMRUNTIME: \""));
+ version_msg((char *)default_vimruntime_dir);
+ version_msg("\"\n");
+ }
+ version_msg(_("Compilation: "));
+ version_msg((char *)all_cflags);
+ version_msg("\n");
+#ifdef VMS
+ if (*compiler_version != NUL)
+ {
+ version_msg(_("Compiler: "));
+ version_msg((char *)compiler_version);
+ version_msg("\n");
+ }
+#endif
+ version_msg(_("Linking: "));
+ version_msg((char *)all_lflags);
+#endif
+#ifdef DEBUG
+ version_msg("\n");
+ version_msg(_(" DEBUG BUILD"));
+#endif
+}
+
+static void do_intro_line(int row, char_u *mesg, int add_version, int attr);
+
+/*
+ * Show the intro message when not editing a file.
+ */
+ void
+maybe_intro_message(void)
+{
+ if (BUFEMPTY()
+ && curbuf->b_fname == NULL
+ && firstwin->w_next == NULL
+ && vim_strchr(p_shm, SHM_INTRO) == NULL)
+ intro_message(FALSE);
+}
+
+/*
+ * Give an introductory message about Vim.
+ * Only used when starting Vim on an empty file, without a file name.
+ * Or with the ":intro" command (for Sven :-).
+ */
+ void
+intro_message(
+ int colon) /* TRUE for ":intro" */
+{
+ int i;
+ int row;
+ int blanklines;
+ int sponsor;
+ char *p;
+ static char *(lines[]) =
+ {
+ N_("VIM - Vi IMproved"),
+ "",
+ N_("version "),
+ N_("by Bram Moolenaar et al."),
+#ifdef MODIFIED_BY
+ " ",
+#endif
+ N_("Vim is open source and freely distributable"),
+ "",
+ N_("Help poor children in Uganda!"),
+ N_("type :help iccf<Enter> for information "),
+ "",
+ N_("type :q<Enter> to exit "),
+ N_("type :help<Enter> or <F1> for on-line help"),
+ N_("type :help version8<Enter> for version info"),
+ NULL,
+ "",
+ N_("Running in Vi compatible mode"),
+ N_("type :set nocp<Enter> for Vim defaults"),
+ N_("type :help cp-default<Enter> for info on this"),
+ };
+#ifdef FEAT_GUI
+ static char *(gui_lines[]) =
+ {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+#ifdef MODIFIED_BY
+ NULL,
+#endif
+ NULL,
+ NULL,
+ NULL,
+ N_("menu Help->Orphans for information "),
+ NULL,
+ N_("Running modeless, typed text is inserted"),
+ N_("menu Edit->Global Settings->Toggle Insert Mode "),
+ N_(" for two modes "),
+ NULL,
+ NULL,
+ NULL,
+ N_("menu Edit->Global Settings->Toggle Vi Compatible"),
+ N_(" for Vim defaults "),
+ };
+#endif
+
+ /* blanklines = screen height - # message lines */
+ blanklines = (int)Rows - ((sizeof(lines) / sizeof(char *)) - 1);
+ if (!p_cp)
+ blanklines += 4; /* add 4 for not showing "Vi compatible" message */
+
+ /* Don't overwrite a statusline. Depends on 'cmdheight'. */
+ if (p_ls > 1)
+ blanklines -= Rows - topframe->fr_height;
+ if (blanklines < 0)
+ blanklines = 0;
+
+ /* Show the sponsor and register message one out of four times, the Uganda
+ * message two out of four times. */
+ sponsor = (int)time(NULL);
+ sponsor = ((sponsor & 2) == 0) - ((sponsor & 4) == 0);
+
+ /* start displaying the message lines after half of the blank lines */
+ row = blanklines / 2;
+ if ((row >= 2 && Columns >= 50) || colon)
+ {
+ for (i = 0; i < (int)(sizeof(lines) / sizeof(char *)); ++i)
+ {
+ p = lines[i];
+#ifdef FEAT_GUI
+ if (p_im && gui.in_use && gui_lines[i] != NULL)
+ p = gui_lines[i];
+#endif
+ if (p == NULL)
+ {
+ if (!p_cp)
+ break;
+ continue;
+ }
+ if (sponsor != 0)
+ {
+ if (strstr(p, "children") != NULL)
+ p = sponsor < 0
+ ? N_("Sponsor Vim development!")
+ : N_("Become a registered Vim user!");
+ else if (strstr(p, "iccf") != NULL)
+ p = sponsor < 0
+ ? N_("type :help sponsor<Enter> for information ")
+ : N_("type :help register<Enter> for information ");
+ else if (strstr(p, "Orphans") != NULL)
+ p = N_("menu Help->Sponsor/Register for information ");
+ }
+ if (*p != NUL)
+ do_intro_line(row, (char_u *)_(p), i == 2, 0);
+ ++row;
+ }
+ }
+
+ /* Make the wait-return message appear just below the text. */
+ if (colon)
+ msg_row = row;
+}
+
+ static void
+do_intro_line(
+ int row,
+ char_u *mesg,
+ int add_version,
+ int attr)
+{
+ char_u vers[20];
+ int col;
+ char_u *p;
+ int l;
+ int clen;
+#ifdef MODIFIED_BY
+# define MODBY_LEN 150
+ char_u modby[MODBY_LEN];
+
+ if (*mesg == ' ')
+ {
+ vim_strncpy(modby, (char_u *)_("Modified by "), MODBY_LEN - 1);
+ l = (int)STRLEN(modby);
+ vim_strncpy(modby + l, (char_u *)MODIFIED_BY, MODBY_LEN - l - 1);
+ mesg = modby;
+ }
+#endif
+
+ /* Center the message horizontally. */
+ col = vim_strsize(mesg);
+ if (add_version)
+ {
+ STRCPY(vers, mediumVersion);
+ if (highest_patch())
+ {
+ /* Check for 9.9x or 9.9xx, alpha/beta version */
+ if (isalpha((int)vers[3]))
+ {
+ int len = (isalpha((int)vers[4])) ? 5 : 4;
+ sprintf((char *)vers + len, ".%d%s", highest_patch(),
+ mediumVersion + len);
+ }
+ else
+ sprintf((char *)vers + 3, ".%d", highest_patch());
+ }
+ col += (int)STRLEN(vers);
+ }
+ col = (Columns - col) / 2;
+ if (col < 0)
+ col = 0;
+
+ /* Split up in parts to highlight <> items differently. */
+ for (p = mesg; *p != NUL; p += l)
+ {
+ clen = 0;
+ for (l = 0; p[l] != NUL
+ && (l == 0 || (p[l] != '<' && p[l - 1] != '>')); ++l)
+ {
+ if (has_mbyte)
+ {
+ clen += ptr2cells(p + l);
+ l += (*mb_ptr2len)(p + l) - 1;
+ }
+ else
+ clen += byte2cells(p[l]);
+ }
+ screen_puts_len(p, l, row, col, *p == '<' ? HL_ATTR(HLF_8) : attr);
+ col += clen;
+ }
+
+ /* Add the version number to the version line. */
+ if (add_version)
+ screen_puts(vers, row, col, 0);
+}
+
+/*
+ * ":intro": clear screen, display intro screen and wait for return.
+ */
+ void
+ex_intro(exarg_T *eap UNUSED)
+{
+ screenclear();
+ intro_message(TRUE);
+ wait_return(TRUE);
+}
diff --git a/src/version.h b/src/version.h
new file mode 100644
index 0000000..b94ab7e
--- /dev/null
+++ b/src/version.h
@@ -0,0 +1,42 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * Do ":help uganda" in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ */
+
+/*
+ * Define the version number, name, etc.
+ * The patchlevel is in included_patches[], in version.c.
+ *
+ * This doesn't use string concatenation, some compilers don't support it.
+ */
+
+#define VIM_VERSION_MAJOR 8
+#define VIM_VERSION_MAJOR_STR "8"
+#define VIM_VERSION_MINOR 1
+#define VIM_VERSION_MINOR_STR "1"
+#define VIM_VERSION_100 (VIM_VERSION_MAJOR * 100 + VIM_VERSION_MINOR)
+
+#define VIM_VERSION_BUILD 282
+#define VIM_VERSION_BUILD_BCD 0x11a
+#define VIM_VERSION_BUILD_STR "282"
+#define VIM_VERSION_PATCHLEVEL 0
+#define VIM_VERSION_PATCHLEVEL_STR "0"
+/* Used by MacOS port should be one of: development, alpha, beta, final */
+#define VIM_VERSION_RELEASE final
+
+/*
+ * VIM_VERSION_NODOT is used for the runtime directory name.
+ * VIM_VERSION_SHORT is copied into the swap file (max. length is 6 chars).
+ * VIM_VERSION_MEDIUM is used for the startup-screen.
+ * VIM_VERSION_LONG is used for the ":version" command and "Vim -h".
+ */
+#define VIM_VERSION_NODOT "vim81"
+#define VIM_VERSION_SHORT "8.1"
+#define VIM_VERSION_MEDIUM "8.1"
+#define VIM_VERSION_LONG "VIM - Vi IMproved 8.1 (2018 May 18)"
+#define VIM_VERSION_LONG_DATE "VIM - Vi IMproved 8.1 (2018 May 18, compiled "
+#define VIM_VERSION_LONG_ONLY "VIM - Vi IMproved 8.1"
+#define VIM_VERSION_DATE_ONLY "2018 May 18"
diff --git a/src/vim.def b/src/vim.def
new file mode 100644
index 0000000..e0368fc
--- /dev/null
+++ b/src/vim.def
@@ -0,0 +1,4 @@
+CODE PRELOAD EXECUTEONLY
+DATA MULTIPLE SHARED
+DESCRIPTION 'Vim 8.1'
+HEAPSIZE 0,0
diff --git a/src/vim.h b/src/vim.h
new file mode 100644
index 0000000..7ee164a
--- /dev/null
+++ b/src/vim.h
@@ -0,0 +1,2609 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * Do ":help uganda" in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ */
+
+#ifndef VIM__H
+# define VIM__H
+
+#include "protodef.h"
+
+/* use fastcall for Borland, when compiling for Win32 */
+#if defined(__BORLANDC__) && defined(WIN32) && !defined(DEBUG)
+#if defined(FEAT_PERL) || \
+ defined(FEAT_PYTHON) || \
+ defined(FEAT_PYTHON3) || \
+ defined(FEAT_RUBY) || \
+ defined(FEAT_TCL) || \
+ defined(FEAT_MZSCHEME) || \
+ defined(DYNAMIC_GETTEXT) || \
+ defined(DYNAMIC_ICONV) || \
+ defined(DYNAMIC_IME) || \
+ defined(XPM)
+ #pragma option -pc
+# else
+ #pragma option -pr
+# endif
+#endif
+
+#if defined(WIN32) || defined(_WIN64)
+# include "vimio.h"
+#endif
+
+/* ============ the header file puzzle (ca. 50-100 pieces) ========= */
+
+#ifdef HAVE_CONFIG_H /* GNU autoconf (or something else) was here */
+# include "auto/config.h"
+# define HAVE_PATHDEF
+
+/*
+ * Check if configure correctly managed to find sizeof(int). If this failed,
+ * it becomes zero. This is likely a problem of not being able to run the
+ * test program. Other items from configure may also be wrong then!
+ */
+# if (VIM_SIZEOF_INT == 0)
+ Error: configure did not run properly. Check auto/config.log.
+# endif
+
+/*
+ * Cygwin may have fchdir() in a newer release, but in most versions it
+ * doesn't work well and avoiding it keeps the binary backward compatible.
+ */
+# if defined(__CYGWIN32__) && defined(HAVE_FCHDIR)
+# undef HAVE_FCHDIR
+# endif
+
+/* We may need to define the uint32_t on non-Unix system, but using the same
+ * identifier causes conflicts. Therefore use UINT32_T. */
+# define UINT32_TYPEDEF uint32_t
+#endif
+
+#if !defined(UINT32_TYPEDEF)
+# if defined(uint32_t) /* this doesn't catch typedefs, unfortunately */
+# define UINT32_TYPEDEF uint32_t
+# else
+ /* Fall back to assuming unsigned int is 32 bit. If this is wrong then the
+ * test in blowfish.c will fail. */
+# define UINT32_TYPEDEF unsigned int
+# endif
+#endif
+
+/* user ID of root is usually zero, but not for everybody */
+#ifdef __TANDEM
+# ifndef _TANDEM_SOURCE
+# define _TANDEM_SOURCE
+# endif
+# include <floss.h>
+# define ROOT_UID 65535
+# define OLDXAW
+# if (_TANDEM_ARCH_ == 2 && __H_Series_RVU >= 621)
+# define SA_ONSTACK_COMPATIBILITY
+# endif
+#else
+# define ROOT_UID 0
+#endif
+
+/*
+ * MACOS_X compiling for Mac OS X
+ * MACOS_X_DARWIN integrating the darwin feature into MACOS_X
+ */
+#if defined(MACOS_X_DARWIN) && !defined(MACOS_X)
+# define MACOS_X
+#endif
+/* 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) \
+ || defined(FEAT_GUI_GTK) \
+ || defined(FEAT_GUI_ATHENA) \
+ || defined(FEAT_GUI_MAC) \
+ || defined(FEAT_GUI_W32) \
+ || defined(FEAT_GUI_PHOTON)
+# define FEAT_GUI_ENABLED /* also defined with NO_X11_INCLUDES */
+# if !defined(FEAT_GUI) && !defined(NO_X11_INCLUDES)
+# define FEAT_GUI
+# endif
+#endif
+
+/* Check support for rendering options */
+#ifdef FEAT_GUI
+# if defined(FEAT_DIRECTX)
+# define FEAT_RENDER_OPTIONS
+# endif
+#endif
+
+/* Visual Studio 2005 has 'deprecated' many of the standard CRT functions */
+#if _MSC_VER >= 1400
+# define _CRT_SECURE_NO_DEPRECATE
+# define _CRT_NONSTDC_NO_DEPRECATE
+#endif
+
+#if defined(FEAT_GUI_W32)
+# define FEAT_GUI_MSWIN
+#endif
+#if defined(WIN32) || defined(_WIN64)
+# define MSWIN
+#endif
+/* Practically everything is common to both Win32 and Win64 */
+#if defined(WIN32) || defined(_WIN64)
+# define WIN3264
+#endif
+
+/*
+ * VIM_SIZEOF_INT is used in feature.h, and the system-specific included files
+ * need items from feature.h. Therefore define VIM_SIZEOF_INT here.
+ */
+#ifdef WIN3264
+# define VIM_SIZEOF_INT 4
+#endif
+
+#ifdef AMIGA
+ /* Be conservative about sizeof(int). It could be 4 too. */
+# ifndef FEAT_GUI_GTK /* avoid problems when generating prototypes */
+# ifdef __GNUC__
+# define VIM_SIZEOF_INT 4
+# else
+# define VIM_SIZEOF_INT 2
+# endif
+# endif
+#endif
+#if defined(MACOS_X) && !defined(HAVE_CONFIG_H)
+# define VIM_SIZEOF_INT __SIZEOF_INT__
+#endif
+
+#if VIM_SIZEOF_INT < 4 && !defined(PROTO)
+ Error: Vim only works with 32 bit int or larger
+#endif
+
+/*
+ * #defines for optionals and features
+ * Also defines FEAT_TINY, FEAT_SMALL, etc. when FEAT_HUGE is defined.
+ */
+#include "feature.h"
+
+#if defined(MACOS_X_DARWIN)
+# if defined(FEAT_SMALL) && !defined(FEAT_CLIPBOARD)
+# define FEAT_CLIPBOARD
+# endif
+# if defined(FEAT_SMALL) && !defined(FEAT_MOUSE)
+# define FEAT_MOUSE
+# endif
+#endif
+
+/* +x11 is only enabled when it's both available and wanted. */
+#if defined(HAVE_X11) && defined(WANT_X11)
+# define FEAT_X11
+#endif
+
+#ifdef NO_X11_INCLUDES
+ /* In os_mac_conv.c and os_macosx.m NO_X11_INCLUDES is defined to avoid
+ * X11 headers. Disable all X11 related things to avoid conflicts. */
+# ifdef FEAT_X11
+# undef FEAT_X11
+# endif
+# ifdef FEAT_GUI_X11
+# undef FEAT_GUI_X11
+# endif
+# ifdef FEAT_XCLIPBOARD
+# undef FEAT_XCLIPBOARD
+# endif
+# ifdef FEAT_GUI_MOTIF
+# undef FEAT_GUI_MOTIF
+# endif
+# ifdef FEAT_GUI_ATHENA
+# undef FEAT_GUI_ATHENA
+# endif
+# ifdef FEAT_GUI_GTK
+# undef FEAT_GUI_GTK
+# endif
+# ifdef FEAT_BEVAL_TIP
+# undef FEAT_BEVAL_TIP
+# endif
+# ifdef FEAT_XIM
+# undef FEAT_XIM
+# endif
+# ifdef FEAT_CLIENTSERVER
+# undef FEAT_CLIENTSERVER
+# endif
+#endif
+
+/* The Mac conversion stuff doesn't work under X11. */
+#if defined(MACOS_X_DARWIN)
+# define MACOS_CONVERT
+#endif
+
+/* Can't use "PACKAGE" here, conflicts with a Perl include file. */
+#ifndef VIMPACKAGE
+# define VIMPACKAGE "vim"
+#endif
+
+/*
+ * Find out if function definitions should include argument types
+ */
+#ifdef AZTEC_C
+# include <functions.h>
+#endif
+
+#ifdef SASC
+# include <clib/exec_protos.h>
+#endif
+
+#ifdef _DCC
+# include <clib/exec_protos.h>
+#endif
+
+#ifdef __BEOS__
+# include "os_beos.h"
+#endif
+
+#if (defined(UNIX) || defined(VMS)) \
+ && (!defined(MACOS_X) || defined(HAVE_CONFIG_H))
+# include "os_unix.h" /* bring lots of system header files */
+#endif
+
+/* Mark unused function arguments with UNUSED, so that gcc -Wunused-parameter
+ * can be used to check for mistakes. */
+#ifdef HAVE_ATTRIBUTE_UNUSED
+# define UNUSED __attribute__((unused))
+#else
+# define UNUSED
+#endif
+
+/* Used to check for "sun", "__sun" is used by newer compilers. */
+#if defined(__sun)
+# define SUN_SYSTEM
+#endif
+
+/* If we're compiling in C++ (currently only KVim), the system
+ * headers must have the correct prototypes or nothing will build.
+ * Conversely, our prototypes might clash due to throw() specifiers and
+ * cause compilation failures even though the headers are correct. For
+ * a concrete example, gcc-3.2 enforces exception specifications, and
+ * glibc-2.2.5 has them in their system headers.
+ */
+#if !defined(__cplusplus) && defined(UNIX) \
+ && !defined(MACOS_X) /* MACOS_X doesn't yet support osdef.h */
+# include "auto/osdef.h" /* bring missing declarations in */
+#endif
+
+#ifdef AMIGA
+# include "os_amiga.h"
+#endif
+
+#ifdef WIN3264
+# include "os_win32.h"
+#endif
+
+#ifdef __MINT__
+# include "os_mint.h"
+#endif
+
+#if defined(MACOS_X)
+# include "os_mac.h"
+#endif
+
+#ifdef __QNX__
+# include "os_qnx.h"
+#endif
+
+#ifdef X_LOCALE
+# include <X11/Xlocale.h>
+#else
+# ifdef HAVE_LOCALE_H
+# include <locale.h>
+# endif
+#endif
+
+/*
+ * Maximum length of a path (for non-unix systems) Make it a bit long, to stay
+ * on the safe side. But not too long to put on the stack.
+ */
+#ifndef MAXPATHL
+# ifdef MAXPATHLEN
+# define MAXPATHL MAXPATHLEN
+# else
+# define MAXPATHL 256
+# endif
+#endif
+#ifdef BACKSLASH_IN_FILENAME
+# define PATH_ESC_CHARS ((char_u *)" \t\n*?[{`%#'\"|!<")
+#else
+# ifdef VMS
+ /* VMS allows a lot of characters in the file name */
+# define PATH_ESC_CHARS ((char_u *)" \t\n*?{`\\%#'\"|!")
+# define SHELL_ESC_CHARS ((char_u *)" \t\n*?{`\\%#'|!()&")
+# else
+# define PATH_ESC_CHARS ((char_u *)" \t\n*?[{`$\\%#'\"|!<")
+# define SHELL_ESC_CHARS ((char_u *)" \t\n*?[{`$\\%#'\"|!<>();&")
+# endif
+#endif
+
+/* length of a buffer to store a number in ASCII (64 bits binary + NUL) */
+#define NUMBUFLEN 65
+
+/* flags for vim_str2nr() */
+#define STR2NR_BIN 1
+#define STR2NR_OCT 2
+#define STR2NR_HEX 4
+#define STR2NR_ALL (STR2NR_BIN + STR2NR_OCT + STR2NR_HEX)
+#define STR2NR_FORCE 8 /* only when ONE of the above is used */
+
+/*
+ * Shorthand for unsigned variables. Many systems, but not all, have u_char
+ * already defined, so we use char_u to avoid trouble.
+ */
+typedef unsigned char char_u;
+typedef unsigned short short_u;
+typedef unsigned int int_u;
+
+/* Older systems do not have support for long long
+ * use a typedef instead of hadcoded long long */
+#ifdef HAVE_NO_LONG_LONG
+ typedef long long_long_T;
+ typedef long unsigned long_long_u_T;
+#else
+ typedef long long long_long_T;
+ typedef long long unsigned long_long_u_T;
+#endif
+
+/* Make sure long_u is big enough to hold a pointer.
+ * On Win64, longs are 32 bits and pointers are 64 bits.
+ * For printf() and scanf(), we need to take care of long_u specifically. */
+#ifdef _WIN64
+typedef unsigned __int64 long_u;
+typedef __int64 long_i;
+# define SCANF_HEX_LONG_U "%Ix"
+# define SCANF_DECIMAL_LONG_U "%Iu"
+# define PRINTF_HEX_LONG_U "0x%Ix"
+#else
+ /* Microsoft-specific. The __w64 keyword should be specified on any typedefs
+ * that change size between 32-bit and 64-bit platforms. For any such type,
+ * __w64 should appear only on the 32-bit definition of the typedef.
+ * Define __w64 as an empty token for everything but MSVC 7.x or later.
+ */
+# if !defined(_MSC_VER) || (_MSC_VER < 1300)
+# define __w64
+# endif
+typedef unsigned long __w64 long_u;
+typedef long __w64 long_i;
+# define SCANF_HEX_LONG_U "%lx"
+# define SCANF_DECIMAL_LONG_U "%lu"
+# define PRINTF_HEX_LONG_U "0x%lx"
+#endif
+#define PRINTF_DECIMAL_LONG_U SCANF_DECIMAL_LONG_U
+
+/*
+ * Only systems which use configure will have SIZEOF_OFF_T and VIM_SIZEOF_LONG
+ * defined, which is ok since those are the same systems which can have
+ * varying sizes for off_t. The other systems will continue to use "%ld" to
+ * print off_t since off_t is simply a typedef to long for them.
+ */
+#if defined(SIZEOF_OFF_T) && (SIZEOF_OFF_T > VIM_SIZEOF_LONG)
+# define LONG_LONG_OFF_T
+#endif
+
+/*
+ * We use 64-bit file functions here, if available. E.g. ftello() returns
+ * off_t instead of long, which helps if long is 32 bit and off_t is 64 bit.
+ * We assume that when fseeko() is available then ftello() is too.
+ * Note that Windows has different function names.
+ */
+#if (defined(_MSC_VER) && (_MSC_VER >= 1300)) || defined(__MINGW32__)
+typedef __int64 off_T;
+# ifdef __MINGW32__
+# define vim_lseek lseek64
+# define vim_fseek fseeko64
+# define vim_ftell ftello64
+# else
+# define vim_lseek _lseeki64
+# define vim_fseek _fseeki64
+# define vim_ftell _ftelli64
+# endif
+#else
+# ifdef PROTO
+typedef long off_T;
+# else
+typedef off_t off_T;
+# endif
+# ifdef HAVE_FSEEKO
+# define vim_lseek lseek
+# define vim_ftell ftello
+# define vim_fseek fseeko
+# else
+# define vim_lseek lseek
+# define vim_ftell ftell
+# define vim_fseek(a, b, c) fseek(a, (long)b, c)
+# endif
+#endif
+
+/*
+ * The characters and attributes cached for the screen.
+ */
+typedef char_u schar_T;
+typedef unsigned short sattr_T;
+#define MAX_TYPENR 65535
+
+/*
+ * The u8char_T can hold one decoded UTF-8 character.
+ * We use 32 bits, since some Asian characters don't fit in 16 bits.
+ */
+typedef unsigned int u8char_T; // int is 32 bits or more
+
+#ifndef UNIX /* For Unix this is included in os_unix.h */
+# include <stdio.h>
+# include <ctype.h>
+#endif
+
+#include "ascii.h"
+#include "keymap.h"
+#include "term.h"
+#include "macros.h"
+
+#ifdef LATTICE
+# include <sys/types.h>
+# include <sys/stat.h>
+#endif
+#ifdef _DCC
+# include <sys/stat.h>
+#endif
+#if defined(MSWIN)
+# include <sys/stat.h>
+#endif
+
+#if defined(HAVE_ERRNO_H) \
+ || defined(WIN32) || defined(_WIN64)
+# include <errno.h>
+#endif
+
+/* for INT_MAX et al. */
+#include <limits.h>
+
+/*
+ * Allow other (non-unix) systems to configure themselves now
+ * These are also in os_unix.h, because osdef.sh needs them there.
+ */
+#ifndef UNIX
+/* Note: Some systems need both string.h and strings.h (Savage). If the
+ * system can't handle this, define NO_STRINGS_WITH_STRING_H. */
+# ifdef HAVE_STRING_H
+# include <string.h>
+# endif
+# if defined(HAVE_STRINGS_H) && !defined(NO_STRINGS_WITH_STRING_H)
+# include <strings.h>
+# endif
+# ifdef HAVE_STAT_H
+# include <stat.h>
+# endif
+# ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif /* NON-UNIX */
+
+#include <assert.h>
+
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#ifdef HAVE_WCTYPE_H
+# include <wctype.h>
+#endif
+#include <stdarg.h>
+
+/* for offsetof() */
+#include <stddef.h>
+
+#if defined(HAVE_SYS_SELECT_H) && \
+ (!defined(HAVE_SYS_TIME_H) || defined(SYS_SELECT_WITH_SYS_TIME))
+# include <sys/select.h>
+#endif
+
+#ifndef HAVE_SELECT
+# ifdef HAVE_SYS_POLL_H
+# include <sys/poll.h>
+# elif defined(WIN32)
+# define HAVE_SELECT
+# else
+# ifdef HAVE_POLL_H
+# include <poll.h>
+# endif
+# endif
+#endif
+
+/* ================ end of the header file puzzle =============== */
+
+/*
+ * For dynamically loaded imm library. Currently, only for Win32.
+ */
+#ifdef DYNAMIC_IME
+# ifndef FEAT_MBYTE_IME
+# define FEAT_MBYTE_IME
+# endif
+#endif
+
+/*
+ * For dynamically loaded gettext library. Currently, only for Win32.
+ */
+#ifdef DYNAMIC_GETTEXT
+# ifndef FEAT_GETTEXT
+# define FEAT_GETTEXT
+# endif
+/* These are in os_win32.c */
+extern char *(*dyn_libintl_gettext)(const char *msgid);
+extern char *(*dyn_libintl_ngettext)(const char *msgid, const char *msgid_plural, unsigned long n);
+extern char *(*dyn_libintl_bindtextdomain)(const char *domainname, const char *dirname);
+extern char *(*dyn_libintl_bind_textdomain_codeset)(const char *domainname, const char *codeset);
+extern char *(*dyn_libintl_textdomain)(const char *domainname);
+extern int (*dyn_libintl_putenv)(const char *envstring);
+#endif
+
+
+/*
+ * The _() stuff is for using gettext(). It is a no-op when libintl.h is not
+ * found or the +multilang feature is disabled.
+ * Use NGETTEXT(single, multi, number) to get plural behavior:
+ * - single - message for singular form
+ * - multi - message for plural form
+ * - number - the count
+ */
+#ifdef FEAT_GETTEXT
+# ifdef DYNAMIC_GETTEXT
+# define _(x) (*dyn_libintl_gettext)((char *)(x))
+# define NGETTEXT(x, xs, n) (*dyn_libintl_ngettext)((char *)(x), (char *)(xs), (n))
+# define N_(x) x
+# define bindtextdomain(domain, dir) (*dyn_libintl_bindtextdomain)((domain), (dir))
+# define bind_textdomain_codeset(domain, codeset) (*dyn_libintl_bind_textdomain_codeset)((domain), (codeset))
+# if !defined(HAVE_BIND_TEXTDOMAIN_CODESET)
+# define HAVE_BIND_TEXTDOMAIN_CODESET 1
+# endif
+# define textdomain(domain) (*dyn_libintl_textdomain)(domain)
+# define libintl_putenv(envstring) (*dyn_libintl_putenv)(envstring)
+# define libintl_wputenv(envstring) (*dyn_libintl_wputenv)(envstring)
+# else
+# include <libintl.h>
+# define _(x) gettext((char *)(x))
+# define NGETTEXT(x, xs, n) ngettext((x), (xs), (n))
+# ifdef gettext_noop
+# define N_(x) gettext_noop(x)
+# else
+# define N_(x) x
+# endif
+# endif
+#else
+# define _(x) ((char *)(x))
+# define NGETTEXT(x, xs, n) (((n) == 1) ? (char *)(x) : (char *)(xs))
+# define N_(x) x
+# ifdef bindtextdomain
+# undef bindtextdomain
+# endif
+# define bindtextdomain(x, y) /* empty */
+# ifdef bind_textdomain_codeset
+# undef bind_textdomain_codeset
+# endif
+# define bind_textdomain_codeset(x, y) /* empty */
+# ifdef textdomain
+# undef textdomain
+# endif
+# define textdomain(x) /* empty */
+#endif
+
+/*
+ * flags for update_screen()
+ * The higher the value, the higher the priority
+ */
+#define VALID_NO_UPDATE 5 /* no new changes, keep the command line if
+ possible */
+#define VALID 10 /* buffer not changed, or changes marked
+ with b_mod_* */
+#define INVERTED 20 /* redisplay inverted part that changed */
+#define INVERTED_ALL 25 /* redisplay whole inverted part */
+#define REDRAW_TOP 30 /* display first w_upd_rows screen lines */
+#define SOME_VALID 35 /* like NOT_VALID but may scroll */
+#define NOT_VALID 40 /* buffer needs complete redraw */
+#define CLEAR 50 /* screen messed up, clear it */
+
+/*
+ * Flags for w_valid.
+ * These are set when something in a window structure becomes invalid, except
+ * when the cursor is moved. Call check_cursor_moved() before testing one of
+ * the flags.
+ * These are reset when that thing has been updated and is valid again.
+ *
+ * Every function that invalidates one of these must call one of the
+ * invalidate_* functions.
+ *
+ * w_valid is supposed to be used only in screen.c. From other files, use the
+ * functions that set or reset the flags.
+ *
+ * VALID_BOTLINE VALID_BOTLINE_AP
+ * on on w_botline valid
+ * off on w_botline approximated
+ * off off w_botline not valid
+ * on off not possible
+ */
+#define VALID_WROW 0x01 /* w_wrow (window row) is valid */
+#define VALID_WCOL 0x02 /* w_wcol (window col) is valid */
+#define VALID_VIRTCOL 0x04 /* w_virtcol (file col) is valid */
+#define VALID_CHEIGHT 0x08 /* w_cline_height and w_cline_folded valid */
+#define VALID_CROW 0x10 /* w_cline_row is valid */
+#define VALID_BOTLINE 0x20 /* w_botine and w_empty_rows are valid */
+#define VALID_BOTLINE_AP 0x40 /* w_botine is approximated */
+#define VALID_TOPLINE 0x80 /* w_topline is valid (for cursor position) */
+
+/*
+ * Terminal highlighting attribute bits.
+ * Attributes above HL_ALL are used for syntax highlighting.
+ */
+#define HL_NORMAL 0x00
+#define HL_INVERSE 0x01
+#define HL_BOLD 0x02
+#define HL_ITALIC 0x04
+#define HL_UNDERLINE 0x08
+#define HL_UNDERCURL 0x10
+#define HL_STANDOUT 0x20
+#define HL_NOCOMBINE 0x40
+#define HL_STRIKETHROUGH 0x80
+#define HL_ALL 0xff
+
+/* special attribute addition: Put message in history */
+#define MSG_HIST 0x1000
+
+/*
+ * values for State
+ *
+ * The lower bits up to 0x20 are used to distinguish normal/visual/op_pending
+ * and cmdline/insert+replace mode. This is used for mapping. If none of
+ * these bits are set, no mapping is done.
+ * The upper bits are used to distinguish between other states.
+ */
+#define NORMAL 0x01 /* Normal mode, command expected */
+#define VISUAL 0x02 /* Visual mode - use get_real_state() */
+#define OP_PENDING 0x04 /* Normal mode, operator is pending - use
+ get_real_state() */
+#define CMDLINE 0x08 /* Editing command line */
+#define INSERT 0x10 /* Insert mode */
+#define LANGMAP 0x20 /* Language mapping, can be combined with
+ INSERT and CMDLINE */
+
+#define REPLACE_FLAG 0x40 /* Replace mode flag */
+#define REPLACE (REPLACE_FLAG + INSERT)
+#define VREPLACE_FLAG 0x80 /* Virtual-replace mode flag */
+#define VREPLACE (REPLACE_FLAG + VREPLACE_FLAG + INSERT)
+#define LREPLACE (REPLACE_FLAG + LANGMAP)
+
+#define NORMAL_BUSY (0x100 + NORMAL) /* Normal mode, busy with a command */
+#define HITRETURN (0x200 + NORMAL) /* waiting for return or command */
+#define ASKMORE 0x300 /* Asking if you want --more-- */
+#define SETWSIZE 0x400 /* window size has changed */
+#define ABBREV 0x500 /* abbreviation instead of mapping */
+#define EXTERNCMD 0x600 /* executing an external command */
+#define SHOWMATCH (0x700 + INSERT) /* show matching paren */
+#define CONFIRM 0x800 /* ":confirm" prompt */
+#define SELECTMODE 0x1000 /* Select mode, only for mappings */
+#define TERMINAL 0x2000 /* Terminal mode */
+
+/* all mode bits used for mapping */
+#define MAP_ALL_MODES (0x3f | SELECTMODE | TERMINAL)
+
+/* directions */
+#define FORWARD 1
+#define BACKWARD (-1)
+#define FORWARD_FILE 3
+#define BACKWARD_FILE (-3)
+
+/* return values for functions */
+#if !(defined(OK) && (OK == 1))
+/* OK already defined to 1 in MacOS X curses, skip this */
+# define OK 1
+#endif
+#define FAIL 0
+#define NOTDONE 2 /* not OK or FAIL but skipped */
+
+/* flags for b_flags */
+#define BF_RECOVERED 0x01 /* buffer has been recovered */
+#define BF_CHECK_RO 0x02 /* need to check readonly when loading file
+ into buffer (set by ":e", may be reset by
+ ":buf" */
+#define BF_NEVERLOADED 0x04 /* file has never been loaded into buffer,
+ many variables still need to be set */
+#define BF_NOTEDITED 0x08 /* Set when file name is changed after
+ starting to edit, reset when file is
+ written out. */
+#define BF_NEW 0x10 /* file didn't exist when editing started */
+#define BF_NEW_W 0x20 /* Warned for BF_NEW and file created */
+#define BF_READERR 0x40 /* got errors while reading the file */
+#define BF_DUMMY 0x80 /* dummy buffer, only used internally */
+#define BF_PRESERVED 0x100 /* ":preserve" was used */
+
+/* Mask to check for flags that prevent normal writing */
+#define BF_WRITE_MASK (BF_NOTEDITED + BF_NEW + BF_READERR)
+
+/*
+ * values for xp_context when doing command line completion
+ */
+#define EXPAND_UNSUCCESSFUL (-2)
+#define EXPAND_OK (-1)
+#define EXPAND_NOTHING 0
+#define EXPAND_COMMANDS 1
+#define EXPAND_FILES 2
+#define EXPAND_DIRECTORIES 3
+#define EXPAND_SETTINGS 4
+#define EXPAND_BOOL_SETTINGS 5
+#define EXPAND_TAGS 6
+#define EXPAND_OLD_SETTING 7
+#define EXPAND_HELP 8
+#define EXPAND_BUFFERS 9
+#define EXPAND_EVENTS 10
+#define EXPAND_MENUS 11
+#define EXPAND_SYNTAX 12
+#define EXPAND_HIGHLIGHT 13
+#define EXPAND_AUGROUP 14
+#define EXPAND_USER_VARS 15
+#define EXPAND_MAPPINGS 16
+#define EXPAND_TAGS_LISTFILES 17
+#define EXPAND_FUNCTIONS 18
+#define EXPAND_USER_FUNC 19
+#define EXPAND_EXPRESSION 20
+#define EXPAND_MENUNAMES 21
+#define EXPAND_USER_COMMANDS 22
+#define EXPAND_USER_CMD_FLAGS 23
+#define EXPAND_USER_NARGS 24
+#define EXPAND_USER_COMPLETE 25
+#define EXPAND_ENV_VARS 26
+#define EXPAND_LANGUAGE 27
+#define EXPAND_COLORS 28
+#define EXPAND_COMPILER 29
+#define EXPAND_USER_DEFINED 30
+#define EXPAND_USER_LIST 31
+#define EXPAND_SHELLCMD 32
+#define EXPAND_CSCOPE 33
+#define EXPAND_SIGN 34
+#define EXPAND_PROFILE 35
+#define EXPAND_BEHAVE 36
+#define EXPAND_FILETYPE 37
+#define EXPAND_FILES_IN_PATH 38
+#define EXPAND_OWNSYNTAX 39
+#define EXPAND_LOCALES 40
+#define EXPAND_HISTORY 41
+#define EXPAND_USER 42
+#define EXPAND_SYNTIME 43
+#define EXPAND_USER_ADDR_TYPE 44
+#define EXPAND_PACKADD 45
+#define EXPAND_MESSAGES 46
+#define EXPAND_MAPCLEAR 47
+#define EXPAND_ARGLIST 48
+
+/* Values for exmode_active (0 is no exmode) */
+#define EXMODE_NORMAL 1
+#define EXMODE_VIM 2
+
+/* Values for nextwild() and ExpandOne(). See ExpandOne() for meaning. */
+#define WILD_FREE 1
+#define WILD_EXPAND_FREE 2
+#define WILD_EXPAND_KEEP 3
+#define WILD_NEXT 4
+#define WILD_PREV 5
+#define WILD_ALL 6
+#define WILD_LONGEST 7
+#define WILD_ALL_KEEP 8
+
+#define WILD_LIST_NOTFOUND 0x01
+#define WILD_HOME_REPLACE 0x02
+#define WILD_USE_NL 0x04
+#define WILD_NO_BEEP 0x08
+#define WILD_ADD_SLASH 0x10
+#define WILD_KEEP_ALL 0x20
+#define WILD_SILENT 0x40
+#define WILD_ESCAPE 0x80
+#define WILD_ICASE 0x100
+#define WILD_ALLLINKS 0x200
+
+/* Flags for expand_wildcards() */
+#define EW_DIR 0x01 /* include directory names */
+#define EW_FILE 0x02 /* include file names */
+#define EW_NOTFOUND 0x04 /* include not found names */
+#define EW_ADDSLASH 0x08 /* append slash to directory name */
+#define EW_KEEPALL 0x10 /* keep all matches */
+#define EW_SILENT 0x20 /* don't print "1 returned" from shell */
+#define EW_EXEC 0x40 /* executable files */
+#define EW_PATH 0x80 /* search in 'path' too */
+#define EW_ICASE 0x100 /* ignore case */
+#define EW_NOERROR 0x200 /* no error for bad regexp */
+#define EW_NOTWILD 0x400 /* add match with literal name if exists */
+#define EW_KEEPDOLLAR 0x800 /* do not escape $, $var is expanded */
+/* Note: mostly EW_NOTFOUND and EW_SILENT are mutually exclusive: EW_NOTFOUND
+ * is used when executing commands and EW_SILENT for interactive expanding. */
+#define EW_ALLLINKS 0x1000 /* also links not pointing to existing file */
+#define EW_SHELLCMD 0x2000 /* called from expand_shellcmd(), don't check
+ * if executable is in $PATH */
+#define EW_DODOT 0x4000 /* also files starting with a dot */
+#define EW_EMPTYOK 0x8000 /* no matches is not an error */
+
+/* Flags for find_file_*() functions. */
+#define FINDFILE_FILE 0 /* only files */
+#define FINDFILE_DIR 1 /* only directories */
+#define FINDFILE_BOTH 2 /* files and directories */
+
+#define W_ENDCOL(wp) (wp->w_wincol + wp->w_width)
+#ifdef FEAT_MENU
+# define W_WINROW(wp) (wp->w_winrow + wp->w_winbar_height)
+#else
+# define W_WINROW(wp) (wp->w_winrow)
+#endif
+
+#ifdef NO_EXPANDPATH
+# define gen_expand_wildcards mch_expand_wildcards
+#endif
+
+/* Values for the find_pattern_in_path() function args 'type' and 'action': */
+#define FIND_ANY 1
+#define FIND_DEFINE 2
+#define CHECK_PATH 3
+
+#define ACTION_SHOW 1
+#define ACTION_GOTO 2
+#define ACTION_SPLIT 3
+#define ACTION_SHOW_ALL 4
+#ifdef FEAT_INS_EXPAND
+# define ACTION_EXPAND 5
+#endif
+
+#ifdef FEAT_SYN_HL
+# define SST_MIN_ENTRIES 150 /* minimal size for state stack array */
+# define SST_MAX_ENTRIES 1000 /* maximal size for state stack array */
+# define SST_FIX_STATES 7 /* size of sst_stack[]. */
+# define SST_DIST 16 /* normal distance between entries */
+# define SST_INVALID (synstate_T *)-1 /* invalid syn_state pointer */
+
+# define HL_CONTAINED 0x01 /* not used on toplevel */
+# define HL_TRANSP 0x02 /* has no highlighting */
+# define HL_ONELINE 0x04 /* match within one line only */
+# define HL_HAS_EOL 0x08 /* end pattern that matches with $ */
+# define HL_SYNC_HERE 0x10 /* sync point after this item (syncing only) */
+# define HL_SYNC_THERE 0x20 /* sync point at current line (syncing only) */
+# define HL_MATCH 0x40 /* use match ID instead of item ID */
+# define HL_SKIPNL 0x80 /* nextgroup can skip newlines */
+# define HL_SKIPWHITE 0x100 /* nextgroup can skip white space */
+# define HL_SKIPEMPTY 0x200 /* nextgroup can skip empty lines */
+# define HL_KEEPEND 0x400 /* end match always kept */
+# define HL_EXCLUDENL 0x800 /* exclude NL from match */
+# define HL_DISPLAY 0x1000 /* only used for displaying, not syncing */
+# define HL_FOLD 0x2000 /* define fold */
+# define HL_EXTEND 0x4000 /* ignore a keepend */
+# define HL_MATCHCONT 0x8000 /* match continued from previous line */
+# define HL_TRANS_CONT 0x10000 /* transparent item without contains arg */
+# define HL_CONCEAL 0x20000 /* can be concealed */
+# define HL_CONCEALENDS 0x40000 /* can be concealed */
+#endif
+
+/* Values for 'options' argument in do_search() and searchit() */
+#define SEARCH_REV 0x01 /* go in reverse of previous dir. */
+#define SEARCH_ECHO 0x02 /* echo the search command and handle options */
+#define SEARCH_MSG 0x0c /* give messages (yes, it's not 0x04) */
+#define SEARCH_NFMSG 0x08 /* give all messages except not found */
+#define SEARCH_OPT 0x10 /* interpret optional flags */
+#define SEARCH_HIS 0x20 /* put search pattern in history */
+#define SEARCH_END 0x40 /* put cursor at end of match */
+#define SEARCH_NOOF 0x80 /* don't add offset to position */
+#define SEARCH_START 0x100 /* start search without col offset */
+#define SEARCH_MARK 0x200 /* set previous context mark */
+#define SEARCH_KEEP 0x400 /* keep previous search pattern */
+#define SEARCH_PEEK 0x800 /* peek for typed char, cancel search */
+#define SEARCH_COL 0x1000 /* start at specified column instead of zero */
+
+/* Values for find_ident_under_cursor() */
+#define FIND_IDENT 1 /* find identifier (word) */
+#define FIND_STRING 2 /* find any string (WORD) */
+#define FIND_EVAL 4 /* include "->", "[]" and "." */
+
+/* Values for file_name_in_line() */
+#define FNAME_MESS 1 /* give error message */
+#define FNAME_EXP 2 /* expand to path */
+#define FNAME_HYP 4 /* check for hypertext link */
+#define FNAME_INCL 8 /* apply 'includeexpr' */
+#define FNAME_REL 16 /* ".." and "./" are relative to the (current)
+ file instead of the current directory */
+#define FNAME_UNESC 32 /* remove backslashes used for escaping */
+
+/* Values for buflist_getfile() */
+#define GETF_SETMARK 0x01 /* set pcmark before jumping */
+#define GETF_ALT 0x02 /* jumping to alternate file (not buf num) */
+#define GETF_SWITCH 0x04 /* respect 'switchbuf' settings when jumping */
+
+/* Return values of getfile() */
+#define GETFILE_ERROR 1 /* normal error */
+#define GETFILE_NOT_WRITTEN 2 /* "not written" error */
+#define GETFILE_SAME_FILE 0 /* success, same file */
+#define GETFILE_OPEN_OTHER -1 /* success, opened another file */
+#define GETFILE_UNUSED 8
+#define GETFILE_SUCCESS(x) ((x) <= 0)
+
+/* Values for buflist_new() flags */
+#define BLN_CURBUF 1 /* may re-use curbuf for new buffer */
+#define BLN_LISTED 2 /* put new buffer in buffer list */
+#define BLN_DUMMY 4 /* allocating dummy buffer */
+#define BLN_NEW 8 /* create a new buffer */
+#define BLN_NOOPT 16 /* don't copy options to existing buffer */
+#define BLN_DUMMY_OK 32 /* also find an existing dummy buffer */
+
+/* Values for in_cinkeys() */
+#define KEY_OPEN_FORW 0x101
+#define KEY_OPEN_BACK 0x102
+#define KEY_COMPLETE 0x103 /* end of completion */
+
+/* Values for "noremap" argument of ins_typebuf(). Also used for
+ * map->m_noremap and menu->noremap[]. */
+#define REMAP_YES 0 /* allow remapping */
+#define REMAP_NONE -1 /* no remapping */
+#define REMAP_SCRIPT -2 /* remap script-local mappings only */
+#define REMAP_SKIP -3 /* no remapping for first char */
+
+/* Values for mch_call_shell() second argument */
+#define SHELL_FILTER 1 /* filtering text */
+#define SHELL_EXPAND 2 /* expanding wildcards */
+#define SHELL_COOKED 4 /* set term to cooked mode */
+#define SHELL_DOOUT 8 /* redirecting output */
+#define SHELL_SILENT 16 /* don't print error returned by command */
+#define SHELL_READ 32 /* read lines and insert into buffer */
+#define SHELL_WRITE 64 /* write lines from buffer */
+
+/* Values returned by mch_nodetype() */
+#define NODE_NORMAL 0 /* file or directory, check with mch_isdir()*/
+#define NODE_WRITABLE 1 /* something we can write to (character
+ device, fifo, socket, ..) */
+#define NODE_OTHER 2 /* non-writable thing (e.g., block device) */
+
+/* Values for readfile() flags */
+#define READ_NEW 0x01 /* read a file into a new buffer */
+#define READ_FILTER 0x02 /* read filter output */
+#define READ_STDIN 0x04 /* read from stdin */
+#define READ_BUFFER 0x08 /* read from curbuf (converting stdin) */
+#define READ_DUMMY 0x10 /* reading into a dummy buffer */
+#define READ_KEEP_UNDO 0x20 /* keep undo info */
+#define READ_FIFO 0x40 /* read from fifo or socket */
+
+/* Values for change_indent() */
+#define INDENT_SET 1 /* set indent */
+#define INDENT_INC 2 /* increase indent */
+#define INDENT_DEC 3 /* decrease indent */
+
+/* Values for flags argument for findmatchlimit() */
+#define FM_BACKWARD 0x01 /* search backwards */
+#define FM_FORWARD 0x02 /* search forwards */
+#define FM_BLOCKSTOP 0x04 /* stop at start/end of block */
+#define FM_SKIPCOMM 0x08 /* skip comments */
+
+/* Values for action argument for do_buffer() */
+#define DOBUF_GOTO 0 /* go to specified buffer */
+#define DOBUF_SPLIT 1 /* split window and go to specified buffer */
+#define DOBUF_UNLOAD 2 /* unload specified buffer(s) */
+#define DOBUF_DEL 3 /* delete specified buffer(s) from buflist */
+#define DOBUF_WIPE 4 /* delete specified buffer(s) really */
+
+/* Values for start argument for do_buffer() */
+#define DOBUF_CURRENT 0 /* "count" buffer from current buffer */
+#define DOBUF_FIRST 1 /* "count" buffer from first buffer */
+#define DOBUF_LAST 2 /* "count" buffer from last buffer */
+#define DOBUF_MOD 3 /* "count" mod. buffer from current buffer */
+
+/* Values for sub_cmd and which_pat argument for search_regcomp() */
+/* Also used for which_pat argument for searchit() */
+#define RE_SEARCH 0 /* save/use pat in/from search_pattern */
+#define RE_SUBST 1 /* save/use pat in/from subst_pattern */
+#define RE_BOTH 2 /* save pat in both patterns */
+#define RE_LAST 2 /* use last used pattern if "pat" is NULL */
+
+/* Second argument for vim_regcomp(). */
+#define RE_MAGIC 1 /* 'magic' option */
+#define RE_STRING 2 /* match in string instead of buffer text */
+#define RE_STRICT 4 /* don't allow [abc] without ] */
+#define RE_AUTO 8 /* automatic engine selection */
+
+#ifdef FEAT_SYN_HL
+/* values for reg_do_extmatch */
+# define REX_SET 1 /* to allow \z\(...\), */
+# define REX_USE 2 /* to allow \z\1 et al. */
+# define REX_ALL (REX_SET | REX_USE)
+#endif
+
+/* Return values for fullpathcmp() */
+/* Note: can use (fullpathcmp() & FPC_SAME) to check for equal files */
+#define FPC_SAME 1 /* both exist and are the same file. */
+#define FPC_DIFF 2 /* both exist and are different files. */
+#define FPC_NOTX 4 /* both don't exist. */
+#define FPC_DIFFX 6 /* one of them doesn't exist. */
+#define FPC_SAMEX 7 /* both don't exist and file names are same. */
+
+/* flags for do_ecmd() */
+#define ECMD_HIDE 0x01 /* don't free the current buffer */
+#define ECMD_SET_HELP 0x02 /* set b_help flag of (new) buffer before
+ opening file */
+#define ECMD_OLDBUF 0x04 /* use existing buffer if it exists */
+#define ECMD_FORCEIT 0x08 /* ! used in Ex command */
+#define ECMD_ADDBUF 0x10 /* don't edit, just add to buffer list */
+
+/* for lnum argument in do_ecmd() */
+#define ECMD_LASTL (linenr_T)0 /* use last position in loaded file */
+#define ECMD_LAST (linenr_T)-1 /* use last position in all files */
+#define ECMD_ONE (linenr_T)1 /* use first line */
+
+/* flags for do_cmdline() */
+#define DOCMD_VERBOSE 0x01 /* included command in error message */
+#define DOCMD_NOWAIT 0x02 /* don't call wait_return() and friends */
+#define DOCMD_REPEAT 0x04 /* repeat exec. until getline() returns NULL */
+#define DOCMD_KEYTYPED 0x08 /* don't reset KeyTyped */
+#define DOCMD_EXCRESET 0x10 /* reset exception environment (for debugging)*/
+#define DOCMD_KEEPLINE 0x20 /* keep typed line for repeating with "." */
+
+/* flags for beginline() */
+#define BL_WHITE 1 /* cursor on first non-white in the line */
+#define BL_SOL 2 /* use 'sol' option */
+#define BL_FIX 4 /* don't leave cursor on a NUL */
+
+/* flags for mf_sync() */
+#define MFS_ALL 1 /* also sync blocks with negative numbers */
+#define MFS_STOP 2 /* stop syncing when a character is available */
+#define MFS_FLUSH 4 /* flushed file to disk */
+#define MFS_ZERO 8 /* only write block 0 */
+
+/* flags for buf_copy_options() */
+#define BCO_ENTER 1 /* going to enter the buffer */
+#define BCO_ALWAYS 2 /* always copy the options */
+#define BCO_NOHELP 4 /* don't touch the help related options */
+
+/* flags for do_put() */
+#define PUT_FIXINDENT 1 /* make indent look nice */
+#define PUT_CURSEND 2 /* leave cursor after end of new text */
+#define PUT_CURSLINE 4 /* leave cursor on last line of new text */
+#define PUT_LINE 8 /* put register as lines */
+#define PUT_LINE_SPLIT 16 /* split line for linewise register */
+#define PUT_LINE_FORWARD 32 /* put linewise register below Visual sel. */
+
+/* flags for set_indent() */
+#define SIN_CHANGED 1 /* call changed_bytes() when line changed */
+#define SIN_INSERT 2 /* insert indent before existing text */
+#define SIN_UNDO 4 /* save line for undo before changing it */
+
+/* flags for insertchar() */
+#define INSCHAR_FORMAT 1 /* force formatting */
+#define INSCHAR_DO_COM 2 /* format comments */
+#define INSCHAR_CTRLV 4 /* char typed just after CTRL-V */
+#define INSCHAR_NO_FEX 8 /* don't use 'formatexpr' */
+#define INSCHAR_COM_LIST 16 /* format comments with list/2nd line indent */
+
+/* flags for open_line() */
+#define OPENLINE_DELSPACES 1 /* delete spaces after cursor */
+#define OPENLINE_DO_COM 2 /* format comments */
+#define OPENLINE_KEEPTRAIL 4 /* keep trailing spaces */
+#define OPENLINE_MARKFIX 8 /* fix mark positions */
+#define OPENLINE_COM_LIST 16 /* format comments with list/2nd line indent */
+
+/*
+ * There are five history tables:
+ */
+#define HIST_CMD 0 /* colon commands */
+#define HIST_SEARCH 1 /* search commands */
+#define HIST_EXPR 2 /* expressions (from entering = register) */
+#define HIST_INPUT 3 /* input() lines */
+#define HIST_DEBUG 4 /* debug commands */
+#define HIST_COUNT 5 /* number of history tables */
+
+/* The type numbers are fixed for backwards compatibility. */
+#define BARTYPE_VERSION 1
+#define BARTYPE_HISTORY 2
+#define BARTYPE_REGISTER 3
+#define BARTYPE_MARK 4
+
+#define VIMINFO_VERSION 4
+#define VIMINFO_VERSION_WITH_HISTORY 2
+#define VIMINFO_VERSION_WITH_REGISTERS 3
+#define VIMINFO_VERSION_WITH_MARKS 4
+
+typedef enum {
+ BVAL_NR,
+ BVAL_STRING,
+ BVAL_EMPTY
+} btype_T;
+
+typedef struct {
+ btype_T bv_type;
+ long bv_nr;
+ char_u *bv_string;
+ int bv_len; /* length of bv_string */
+ int bv_allocated; /* bv_string was allocated */
+} bval_T;
+
+/*
+ * Values for do_tag().
+ */
+#define DT_TAG 1 /* jump to newer position or same tag again */
+#define DT_POP 2 /* jump to older position */
+#define DT_NEXT 3 /* jump to next match of same tag */
+#define DT_PREV 4 /* jump to previous match of same tag */
+#define DT_FIRST 5 /* jump to first match of same tag */
+#define DT_LAST 6 /* jump to first match of same tag */
+#define DT_SELECT 7 /* jump to selection from list */
+#define DT_HELP 8 /* like DT_TAG, but no wildcards */
+#define DT_JUMP 9 /* jump to new tag or selection from list */
+#define DT_CSCOPE 10 /* cscope find command (like tjump) */
+#define DT_LTAG 11 /* tag using location list */
+#define DT_FREE 99 /* free cached matches */
+
+/*
+ * flags for find_tags().
+ */
+#define TAG_HELP 1 /* only search for help tags */
+#define TAG_NAMES 2 /* only return name of tag */
+#define TAG_REGEXP 4 /* use tag pattern as regexp */
+#define TAG_NOIC 8 /* don't always ignore case */
+#ifdef FEAT_CSCOPE
+# define TAG_CSCOPE 16 /* cscope tag */
+#endif
+#define TAG_VERBOSE 32 /* message verbosity */
+#define TAG_INS_COMP 64 /* Currently doing insert completion */
+#define TAG_KEEP_LANG 128 /* keep current language */
+
+#define TAG_MANY 300 /* When finding many tags (for completion),
+ find up to this many tags */
+
+/*
+ * Types of dialogs passed to do_vim_dialog().
+ */
+#define VIM_GENERIC 0
+#define VIM_ERROR 1
+#define VIM_WARNING 2
+#define VIM_INFO 3
+#define VIM_QUESTION 4
+#define VIM_LAST_TYPE 4 /* sentinel value */
+
+/*
+ * Return values for functions like gui_yesnocancel()
+ */
+#define VIM_YES 2
+#define VIM_NO 3
+#define VIM_CANCEL 4
+#define VIM_ALL 5
+#define VIM_DISCARDALL 6
+
+/*
+ * arguments for win_split()
+ */
+#define WSP_ROOM 1 /* require enough room */
+#define WSP_VERT 2 /* split vertically */
+#define WSP_TOP 4 /* window at top-left of shell */
+#define WSP_BOT 8 /* window at bottom-right of shell */
+#define WSP_HELP 16 /* creating the help window */
+#define WSP_BELOW 32 /* put new window below/right */
+#define WSP_ABOVE 64 /* put new window above/left */
+#define WSP_NEWLOC 128 /* don't copy location list */
+
+/*
+ * arguments for gui_set_shellsize()
+ */
+#define RESIZE_VERT 1 /* resize vertically */
+#define RESIZE_HOR 2 /* resize horizontally */
+#define RESIZE_BOTH 15 /* resize in both directions */
+
+/*
+ * flags for check_changed()
+ */
+#define CCGD_AW 1 /* do autowrite if buffer was changed */
+#define CCGD_MULTWIN 2 /* check also when several wins for the buf */
+#define CCGD_FORCEIT 4 /* ! used */
+#define CCGD_ALLBUF 8 /* may write all buffers */
+#define CCGD_EXCMD 16 /* may suggest using ! */
+
+/*
+ * "flags" values for option-setting functions.
+ * When OPT_GLOBAL and OPT_LOCAL are both missing, set both local and global
+ * values, get local value.
+ */
+#define OPT_FREE 1 /* free old value if it was allocated */
+#define OPT_GLOBAL 2 /* use global value */
+#define OPT_LOCAL 4 /* use local value */
+#define OPT_MODELINE 8 /* option in modeline */
+#define OPT_WINONLY 16 /* only set window-local options */
+#define OPT_NOWIN 32 /* don't set window-local options */
+
+/* Magic chars used in confirm dialog strings */
+#define DLG_BUTTON_SEP '\n'
+#define DLG_HOTKEY_CHAR '&'
+
+/* Values for "starting" */
+#define NO_SCREEN 2 /* no screen updating yet */
+#define NO_BUFFERS 1 /* not all buffers loaded yet */
+/* 0 not starting anymore */
+
+/* Values for swap_exists_action: what to do when swap file already exists */
+#define SEA_NONE 0 /* don't use dialog */
+#define SEA_DIALOG 1 /* use dialog when possible */
+#define SEA_QUIT 2 /* quit editing the file */
+#define SEA_RECOVER 3 /* recover the file */
+
+/*
+ * Minimal size for block 0 of a swap file.
+ * NOTE: This depends on size of struct block0! It's not done with a sizeof(),
+ * because struct block0 is defined in memline.c (Sorry).
+ * The maximal block size is arbitrary.
+ */
+#define MIN_SWAP_PAGE_SIZE 1048
+#define MAX_SWAP_PAGE_SIZE 50000
+
+/* Special values for current_sctx.sc_sid. */
+#define SID_MODELINE -1 /* when using a modeline */
+#define SID_CMDARG -2 /* for "--cmd" argument */
+#define SID_CARG -3 /* for "-c" argument */
+#define SID_ENV -4 /* for sourcing environment variable */
+#define SID_ERROR -5 /* option was reset because of an error */
+#define SID_NONE -6 /* don't set scriptID */
+
+/*
+ * Events for autocommands.
+ */
+enum auto_event
+{
+ EVENT_BUFADD = 0, // after adding a buffer to the buffer list
+ EVENT_BUFDELETE, // deleting a buffer from the buffer list
+ EVENT_BUFENTER, // after entering a buffer
+ EVENT_BUFFILEPOST, // after renaming a buffer
+ EVENT_BUFFILEPRE, // before renaming a buffer
+ EVENT_BUFHIDDEN, // just after buffer becomes hidden
+ EVENT_BUFLEAVE, // before leaving a buffer
+ EVENT_BUFNEW, // after creating any buffer
+ EVENT_BUFNEWFILE, // when creating a buffer for a new file
+ EVENT_BUFREADCMD, // read buffer using command
+ EVENT_BUFREADPOST, // after reading a buffer
+ EVENT_BUFREADPRE, // before reading a buffer
+ EVENT_BUFUNLOAD, // just before unloading a buffer
+ EVENT_BUFWINENTER, // after showing a buffer in a window
+ EVENT_BUFWINLEAVE, // just after buffer removed from window
+ EVENT_BUFWIPEOUT, // just before really deleting a buffer
+ EVENT_BUFWRITECMD, // write buffer using command
+ EVENT_BUFWRITEPOST, // after writing a buffer
+ EVENT_BUFWRITEPRE, // before writing a buffer
+ EVENT_CMDLINECHANGED, // command line was modified
+ EVENT_CMDLINEENTER, // after entering the command line
+ EVENT_CMDLINELEAVE, // before leaving the command line
+ EVENT_CMDUNDEFINED, // command undefined
+ EVENT_CMDWINENTER, // after entering the cmdline window
+ EVENT_CMDWINLEAVE, // before leaving the cmdline window
+ EVENT_COLORSCHEME, // after loading a colorscheme
+ EVENT_COLORSCHEMEPRE, // before loading a colorscheme
+ EVENT_COMPLETEDONE, // after finishing insert complete
+ EVENT_CURSORHOLD, // cursor in same position for a while
+ EVENT_CURSORHOLDI, // idem, in Insert mode
+ EVENT_CURSORMOVED, // cursor was moved
+ EVENT_CURSORMOVEDI, // cursor was moved in Insert mode
+ EVENT_DIFFUPDATED, // after diffs were updated
+ EVENT_DIRCHANGED, // after user changed directory
+ EVENT_ENCODINGCHANGED, // after changing the 'encoding' option
+ EVENT_EXITPRE, // before exiting
+ EVENT_FILEAPPENDCMD, // append to a file using command
+ EVENT_FILEAPPENDPOST, // after appending to a file
+ EVENT_FILEAPPENDPRE, // before appending to a file
+ EVENT_FILECHANGEDRO, // before first change to read-only file
+ EVENT_FILECHANGEDSHELL, // after shell command that changed file
+ EVENT_FILECHANGEDSHELLPOST, // after (not) reloading changed file
+ EVENT_FILEREADCMD, // read from a file using command
+ EVENT_FILEREADPOST, // after reading a file
+ EVENT_FILEREADPRE, // before reading a file
+ EVENT_FILETYPE, // new file type detected (user defined)
+ EVENT_FILEWRITECMD, // write to a file using command
+ EVENT_FILEWRITEPOST, // after writing a file
+ EVENT_FILEWRITEPRE, // before writing a file
+ EVENT_FILTERREADPOST, // after reading from a filter
+ EVENT_FILTERREADPRE, // before reading from a filter
+ EVENT_FILTERWRITEPOST, // after writing to a filter
+ EVENT_FILTERWRITEPRE, // before writing to a filter
+ EVENT_FOCUSGAINED, // got the focus
+ EVENT_FOCUSLOST, // lost the focus to another app
+ EVENT_FUNCUNDEFINED, // if calling a function which doesn't exist
+ EVENT_GUIENTER, // after starting the GUI
+ EVENT_GUIFAILED, // after starting the GUI failed
+ EVENT_INSERTCHANGE, // when changing Insert/Replace mode
+ EVENT_INSERTCHARPRE, // before inserting a char
+ EVENT_INSERTENTER, // when entering Insert mode
+ EVENT_INSERTLEAVE, // when leaving Insert mode
+ EVENT_MENUPOPUP, // just before popup menu is displayed
+ EVENT_OPTIONSET, // option was set
+ EVENT_QUICKFIXCMDPOST, // after :make, :grep etc.
+ EVENT_QUICKFIXCMDPRE, // before :make, :grep etc.
+ EVENT_QUITPRE, // before :quit
+ EVENT_REMOTEREPLY, // upon string reception from a remote vim
+ EVENT_SESSIONLOADPOST, // after loading a session file
+ EVENT_SHELLCMDPOST, // after ":!cmd"
+ EVENT_SHELLFILTERPOST, // after ":1,2!cmd", ":w !cmd", ":r !cmd".
+ EVENT_SOURCECMD, // sourcing a Vim script using command
+ EVENT_SOURCEPRE, // before sourcing a Vim script
+ EVENT_SOURCEPOST, // after sourcing a Vim script
+ EVENT_SPELLFILEMISSING, // spell file missing
+ EVENT_STDINREADPOST, // after reading from stdin
+ EVENT_STDINREADPRE, // before reading from stdin
+ EVENT_SWAPEXISTS, // found existing swap file
+ EVENT_SYNTAX, // syntax selected
+ EVENT_TABCLOSED, // after closing a tab page
+ EVENT_TABENTER, // after entering a tab page
+ EVENT_TABLEAVE, // before leaving a tab page
+ EVENT_TABNEW, // when entering a new tab page
+ EVENT_TERMCHANGED, // after changing 'term'
+ EVENT_TERMINALOPEN, // after a terminal buffer was created
+ EVENT_TERMRESPONSE, // after setting "v:termresponse"
+ EVENT_TEXTCHANGED, // text was modified not in Insert mode
+ EVENT_TEXTCHANGEDI, // text was modified in Insert mode
+ EVENT_TEXTCHANGEDP, // TextChangedI with popup menu visible
+ EVENT_TEXTYANKPOST, // after some text was yanked
+ EVENT_USER, // user defined autocommand
+ EVENT_VIMENTER, // after starting Vim
+ EVENT_VIMLEAVE, // before exiting Vim
+ EVENT_VIMLEAVEPRE, // before exiting Vim and writing .viminfo
+ EVENT_VIMRESIZED, // after Vim window was resized
+ EVENT_WINENTER, // after entering a window
+ EVENT_WINLEAVE, // before leaving a window
+ EVENT_WINNEW, // when entering a new window
+
+ NUM_EVENTS // MUST be the last one
+};
+
+typedef enum auto_event event_T;
+
+/*
+ * Values for index in highlight_attr[].
+ * When making changes, also update HL_FLAGS below! And update the default
+ * value of 'highlight' in option.c.
+ */
+typedef enum
+{
+ HLF_8 = 0 /* Meta & special keys listed with ":map", text that is
+ displayed different from what it is */
+ , HLF_EOB /* after the last line in the buffer */
+ , HLF_AT /* @ characters at end of screen, characters that
+ don't really exist in the text */
+ , HLF_D /* directories in CTRL-D listing */
+ , HLF_E /* error messages */
+ , HLF_H /* obsolete, ignored */
+ , HLF_I /* incremental search */
+ , HLF_L /* last search string */
+ , HLF_M /* "--More--" message */
+ , HLF_CM /* Mode (e.g., "-- INSERT --") */
+ , HLF_N /* line number for ":number" and ":#" commands */
+ , HLF_CLN /* current line number */
+ , HLF_R /* return to continue message and yes/no questions */
+ , HLF_S /* status lines */
+ , HLF_SNC /* status lines of not-current windows */
+ , HLF_C /* column to separate vertically split windows */
+ , HLF_T /* Titles for output from ":set all", ":autocmd" etc. */
+ , HLF_V /* Visual mode */
+ , HLF_VNC /* Visual mode, autoselecting and not clipboard owner */
+ , HLF_W /* warning messages */
+ , HLF_WM /* Wildmenu highlight */
+ , HLF_FL /* Folded line */
+ , HLF_FC /* Fold column */
+ , HLF_ADD /* Added diff line */
+ , HLF_CHD /* Changed diff line */
+ , HLF_DED /* Deleted diff line */
+ , HLF_TXD /* Text Changed in diff line */
+ , HLF_CONCEAL /* Concealed text */
+ , HLF_SC /* Sign column */
+ , HLF_SPB /* SpellBad */
+ , HLF_SPC /* SpellCap */
+ , HLF_SPR /* SpellRare */
+ , HLF_SPL /* SpellLocal */
+ , HLF_PNI /* popup menu normal item */
+ , HLF_PSI /* popup menu selected item */
+ , HLF_PSB /* popup menu scrollbar */
+ , HLF_PST /* popup menu scrollbar thumb */
+ , HLF_TP /* tabpage line */
+ , HLF_TPS /* tabpage line selected */
+ , HLF_TPF /* tabpage line filler */
+ , HLF_CUC /* 'cursorcolumn' */
+ , HLF_CUL /* 'cursorline' */
+ , HLF_MC /* 'colorcolumn' */
+ , HLF_QFL /* quickfix window line currently selected */
+ , HLF_ST /* status lines of terminal windows */
+ , HLF_STNC /* status lines of not-current terminal windows */
+ , HLF_COUNT /* MUST be the last one */
+} hlf_T;
+
+/* The HL_FLAGS must be in the same order as the HLF_ enums!
+ * When changing this also adjust the default for 'highlight'. */
+#define HL_FLAGS {'8', '~', '@', 'd', 'e', 'h', 'i', 'l', 'm', 'M', \
+ 'n', 'N', 'r', 's', 'S', 'c', 't', 'v', 'V', 'w', 'W', \
+ 'f', 'F', 'A', 'C', 'D', 'T', '-', '>', \
+ 'B', 'P', 'R', 'L', \
+ '+', '=', 'x', 'X', '*', '#', '_', '!', '.', 'o', 'q', \
+ 'z', 'Z'}
+
+/*
+ * Boolean constants
+ */
+#ifndef TRUE
+# define FALSE 0 /* note: this is an int, not a long! */
+# define TRUE 1
+#endif
+
+#define MAYBE 2 /* sometimes used for a variant on TRUE */
+
+#ifndef UINT32_T
+typedef UINT32_TYPEDEF UINT32_T;
+#endif
+
+/*
+ * Operator IDs; The order must correspond to opchars[] in ops.c!
+ */
+#define OP_NOP 0 /* no pending operation */
+#define OP_DELETE 1 /* "d" delete operator */
+#define OP_YANK 2 /* "y" yank operator */
+#define OP_CHANGE 3 /* "c" change operator */
+#define OP_LSHIFT 4 /* "<" left shift operator */
+#define OP_RSHIFT 5 /* ">" right shift operator */
+#define OP_FILTER 6 /* "!" filter operator */
+#define OP_TILDE 7 /* "g~" switch case operator */
+#define OP_INDENT 8 /* "=" indent operator */
+#define OP_FORMAT 9 /* "gq" format operator */
+#define OP_COLON 10 /* ":" colon operator */
+#define OP_UPPER 11 /* "gU" make upper case operator */
+#define OP_LOWER 12 /* "gu" make lower case operator */
+#define OP_JOIN 13 /* "J" join operator, only for Visual mode */
+#define OP_JOIN_NS 14 /* "gJ" join operator, only for Visual mode */
+#define OP_ROT13 15 /* "g?" rot-13 encoding */
+#define OP_REPLACE 16 /* "r" replace chars, only for Visual mode */
+#define OP_INSERT 17 /* "I" Insert column, only for Visual mode */
+#define OP_APPEND 18 /* "A" Append column, only for Visual mode */
+#define OP_FOLD 19 /* "zf" define a fold */
+#define OP_FOLDOPEN 20 /* "zo" open folds */
+#define OP_FOLDOPENREC 21 /* "zO" open folds recursively */
+#define OP_FOLDCLOSE 22 /* "zc" close folds */
+#define OP_FOLDCLOSEREC 23 /* "zC" close folds recursively */
+#define OP_FOLDDEL 24 /* "zd" delete folds */
+#define OP_FOLDDELREC 25 /* "zD" delete folds recursively */
+#define OP_FORMAT2 26 /* "gw" format operator, keeps cursor pos */
+#define OP_FUNCTION 27 /* "g@" call 'operatorfunc' */
+#define OP_NR_ADD 28 /* "<C-A>" Add to the number or alphabetic
+ character (OP_ADD conflicts with Perl) */
+#define OP_NR_SUB 29 /* "<C-X>" Subtract from the number or
+ alphabetic character */
+
+/*
+ * Motion types, used for operators and for yank/delete registers.
+ */
+#define MCHAR 0 /* character-wise movement/register */
+#define MLINE 1 /* line-wise movement/register */
+#define MBLOCK 2 /* block-wise register */
+
+#define MAUTO 0xff /* Decide between MLINE/MCHAR */
+
+/*
+ * Minimum screen size
+ */
+#define MIN_COLUMNS 12 /* minimal columns for screen */
+#define MIN_LINES 2 /* minimal lines for screen */
+#define STATUS_HEIGHT 1 /* height of a status line under a window */
+#ifdef FEAT_MENU /* height of a status line under a window */
+# define WINBAR_HEIGHT(wp) (wp)->w_winbar_height
+# define VISIBLE_HEIGHT(wp) ((wp)->w_height + (wp)->w_winbar_height)
+#else
+# define WINBAR_HEIGHT(wp) 0
+# define VISIBLE_HEIGHT(wp) (wp)->w_height
+#endif
+#define QF_WINHEIGHT 10 /* default height for quickfix window */
+
+/*
+ * Buffer sizes
+ */
+#ifndef CMDBUFFSIZE
+# define CMDBUFFSIZE 256 /* size of the command processing buffer */
+#endif
+
+#define LSIZE 512 /* max. size of a line in the tags file */
+
+#define IOSIZE (1024+1) /* file i/o and sprintf buffer size */
+
+#define DIALOG_MSG_SIZE 1000 /* buffer size for dialog_msg() */
+
+#define MSG_BUF_LEN 480 /* length of buffer for small messages */
+#define MSG_BUF_CLEN (MSG_BUF_LEN / 6) /* cell length (worst case: utf-8
+ takes 6 bytes for one cell) */
+
+#define FOLD_TEXT_LEN 51 /* buffer size for get_foldtext() */
+
+/* Size of the buffer used for tgetent(). Unfortunately this is largely
+ * undocumented, some systems use 1024. Using a buffer that is too small
+ * causes a buffer overrun and a crash. Use the maximum known value to stay
+ * on the safe side. */
+#define TBUFSZ 2048 /* buffer size for termcap entry */
+
+/*
+ * Maximum length of key sequence to be mapped.
+ * Must be able to hold an Amiga resize report.
+ */
+#define MAXMAPLEN 50
+
+/* Size in bytes of the hash used in the undo file. */
+#define UNDO_HASH_SIZE 32
+
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+
+#ifdef BINARY_FILE_IO
+# define WRITEBIN "wb" /* no CR-LF translation */
+# define READBIN "rb"
+# define APPENDBIN "ab"
+#else
+# define WRITEBIN "w"
+# define READBIN "r"
+# define APPENDBIN "a"
+#endif
+
+/*
+ * EMX doesn't have a global way of making open() use binary I/O.
+ * Use O_BINARY for all open() calls.
+ */
+#if defined(__CYGWIN32__)
+# define O_EXTRA O_BINARY
+#else
+# define O_EXTRA 0
+#endif
+
+#ifndef O_NOFOLLOW
+# define O_NOFOLLOW 0
+#endif
+
+#ifndef W_OK
+# define W_OK 2 /* for systems that don't have W_OK in unistd.h */
+#endif
+#ifndef R_OK
+# define R_OK 4 /* for systems that don't have R_OK in unistd.h */
+#endif
+
+/*
+ * defines to avoid typecasts from (char_u *) to (char *) and back
+ * (vim_strchr() and vim_strrchr() are now in alloc.c)
+ */
+#define STRLEN(s) strlen((char *)(s))
+#define STRCPY(d, s) strcpy((char *)(d), (char *)(s))
+#define STRNCPY(d, s, n) strncpy((char *)(d), (char *)(s), (size_t)(n))
+#define STRCMP(d, s) strcmp((char *)(d), (char *)(s))
+#define STRNCMP(d, s, n) strncmp((char *)(d), (char *)(s), (size_t)(n))
+#ifdef HAVE_STRCASECMP
+# define STRICMP(d, s) strcasecmp((char *)(d), (char *)(s))
+#else
+# ifdef HAVE_STRICMP
+# define STRICMP(d, s) stricmp((char *)(d), (char *)(s))
+# else
+# define STRICMP(d, s) vim_stricmp((char *)(d), (char *)(s))
+# endif
+#endif
+
+/* Like strcpy() but allows overlapped source and destination. */
+#define STRMOVE(d, s) mch_memmove((d), (s), STRLEN(s) + 1)
+
+#ifdef HAVE_STRNCASECMP
+# define STRNICMP(d, s, n) strncasecmp((char *)(d), (char *)(s), (size_t)(n))
+#else
+# ifdef HAVE_STRNICMP
+# define STRNICMP(d, s, n) strnicmp((char *)(d), (char *)(s), (size_t)(n))
+# else
+# define STRNICMP(d, s, n) vim_strnicmp((char *)(d), (char *)(s), (size_t)(n))
+# endif
+#endif
+
+/* We need to call mb_stricmp() even when we aren't dealing with a multi-byte
+ * encoding because mb_stricmp() takes care of all ascii and non-ascii
+ * encodings, including characters with umlauts in latin1, etc., while
+ * STRICMP() only handles the system locale version, which often does not
+ * handle non-ascii properly. */
+
+# define MB_STRICMP(d, s) mb_strnicmp((char_u *)(d), (char_u *)(s), (int)MAXCOL)
+# define MB_STRNICMP(d, s, n) mb_strnicmp((char_u *)(d), (char_u *)(s), (int)(n))
+
+#define STRCAT(d, s) strcat((char *)(d), (char *)(s))
+#define STRNCAT(d, s, n) strncat((char *)(d), (char *)(s), (size_t)(n))
+
+#ifdef HAVE_STRPBRK
+# define vim_strpbrk(s, cs) (char_u *)strpbrk((char *)(s), (char *)(cs))
+#endif
+
+#define OUT_STR(s) out_str((char_u *)(s))
+#define OUT_STR_NF(s) out_str_nf((char_u *)(s))
+
+#ifdef FEAT_GUI
+# ifdef FEAT_TERMGUICOLORS
+# define GUI_FUNCTION(f) (gui.in_use ? gui_##f : termgui_##f)
+# define GUI_FUNCTION2(f, pixel) (gui.in_use \
+ ? ((pixel) != INVALCOLOR \
+ ? gui_##f((pixel)) \
+ : INVALCOLOR) \
+ : termgui_##f((pixel)))
+# define USE_24BIT (gui.in_use || p_tgc)
+# else
+# define GUI_FUNCTION(f) gui_##f
+# define GUI_FUNCTION2(f,pixel) ((pixel) != INVALCOLOR \
+ ? gui_##f((pixel)) \
+ : INVALCOLOR)
+# define USE_24BIT gui.in_use
+# endif
+#else
+# ifdef FEAT_TERMGUICOLORS
+# define GUI_FUNCTION(f) termgui_##f
+# define GUI_FUNCTION2(f, pixel) termgui_##f((pixel))
+# define USE_24BIT p_tgc
+# endif
+#endif
+#ifdef FEAT_TERMGUICOLORS
+# define IS_CTERM (t_colors > 1 || p_tgc)
+#else
+# define IS_CTERM (t_colors > 1)
+#endif
+#ifdef GUI_FUNCTION
+# define GUI_MCH_GET_RGB GUI_FUNCTION(mch_get_rgb)
+# define GUI_MCH_GET_RGB2(pixel) GUI_FUNCTION2(mch_get_rgb, (pixel))
+# define GUI_MCH_GET_COLOR GUI_FUNCTION(mch_get_color)
+# define GUI_GET_COLOR GUI_FUNCTION(get_color)
+#endif
+
+/* Prefer using emsgf(), because perror() may send the output to the wrong
+ * destination and mess up the screen. */
+#ifdef HAVE_STRERROR
+# define PERROR(msg) (void)semsg("%s: %s", (char *)msg, strerror(errno))
+#else
+# define PERROR(msg) do_perror(msg)
+#endif
+
+typedef long linenr_T; /* line number type */
+typedef int colnr_T; /* column number type */
+typedef unsigned short disptick_T; /* display tick type */
+
+/*
+ * Well, you won't believe it, but some S/390 machines ("host", now also known
+ * as zServer) use 31 bit pointers. There are also some newer machines, that
+ * use 64 bit pointers. I don't know how to distinguish between 31 and 64 bit
+ * machines, so the best way is to assume 31 bits whenever we detect OS/390
+ * Unix.
+ * With this we restrict the maximum line length to 1073741823. I guess this is
+ * not a real problem. BTW: Longer lines are split.
+ */
+#ifdef __MVS__
+# define MAXCOL (0x3fffffffL) /* maximum column number, 30 bits */
+# define MAXLNUM (0x3fffffffL) /* maximum (invalid) line number */
+#else
+# define MAXCOL (0x7fffffffL) /* maximum column number, 31 bits */
+# define MAXLNUM (0x7fffffffL) /* maximum (invalid) line number */
+#endif
+
+#define SHOWCMD_COLS 10 /* columns needed by shown command */
+#define STL_MAX_ITEM 80 /* max nr of %<flag> in statusline */
+
+typedef void *vim_acl_T; /* dummy to pass an ACL to a function */
+
+#ifndef mch_memmove
+# define mch_memmove(to, from, len) memmove((char*)(to), (char*)(from), (size_t)(len))
+#endif
+
+/*
+ * fnamecmp() is used to compare file names.
+ * On some systems case in a file name does not matter, on others it does.
+ * (this does not account for maximum name lengths and things like "../dir",
+ * thus it is not 100% accurate!)
+ */
+#define fnamecmp(x, y) vim_fnamecmp((char_u *)(x), (char_u *)(y))
+#define fnamencmp(x, y, n) vim_fnamencmp((char_u *)(x), (char_u *)(y), (size_t)(n))
+
+#ifdef HAVE_MEMSET
+# define vim_memset(ptr, c, size) memset((ptr), (c), (size))
+#else
+void *vim_memset(void *, int, size_t);
+#endif
+
+#if defined(UNIX) || defined(FEAT_GUI) || defined(VMS) \
+ || defined(FEAT_CLIENTSERVER)
+# define USE_INPUT_BUF
+#endif
+
+#ifndef EINTR
+# define read_eintr(fd, buf, count) vim_read((fd), (buf), (count))
+# define write_eintr(fd, buf, count) vim_write((fd), (buf), (count))
+#endif
+
+#ifdef MSWIN
+/* On MS-Windows the third argument isn't size_t. This matters for Win64,
+ * where sizeof(size_t)==8, not 4 */
+# define vim_read(fd, buf, count) read((fd), (char *)(buf), (unsigned int)(count))
+# define vim_write(fd, buf, count) write((fd), (char *)(buf), (unsigned int)(count))
+#else
+# define vim_read(fd, buf, count) read((fd), (char *)(buf), (size_t) (count))
+# define vim_write(fd, buf, count) write((fd), (char *)(buf), (size_t) (count))
+#endif
+
+/*
+ * Enums need a typecast to be used as array index (for Ultrix).
+ */
+#define HL_ATTR(n) highlight_attr[(int)(n)]
+#define TERM_STR(n) term_strings[(int)(n)]
+
+/*
+ * EXTERN is only defined in main.c. That's where global variables are
+ * actually defined and initialized.
+ */
+#ifndef EXTERN
+# define EXTERN extern
+# define INIT(x)
+#else
+# ifndef INIT
+# define INIT(x) x
+# define DO_INIT
+# define COMMA ,
+# endif
+#endif
+
+#define MAX_MCO 6 /* maximum value for 'maxcombine' */
+
+/* Maximum number of bytes in a multi-byte character. It can be one 32-bit
+ * character of up to 6 bytes, or one 16-bit character of up to three bytes
+ * plus six following composing characters of three bytes each. */
+#define MB_MAXBYTES 21
+
+#if (defined(FEAT_PROFILE) || defined(FEAT_RELTIME)) && !defined(PROTO)
+# ifdef WIN3264
+typedef LARGE_INTEGER proftime_T;
+# else
+typedef struct timeval proftime_T;
+# endif
+#else
+typedef int proftime_T; /* dummy for function prototypes */
+#endif
+
+/*
+ * When compiling with 32 bit Perl time_t is 32 bits in the Perl code but 64
+ * bits elsewhere. That causes memory corruption. Define time_T and use it
+ * for global variables to avoid that.
+ */
+#ifdef PROTO
+typedef long time_T;
+#else
+# ifdef WIN3264
+typedef __time64_t time_T;
+# else
+typedef time_t time_T;
+# endif
+#endif
+
+#ifdef _WIN64
+typedef __int64 sock_T;
+#else
+typedef int sock_T;
+#endif
+
+/* Include option.h before structs.h, because the number of window-local and
+ * buffer-local options is used there. */
+#include "option.h" /* options and default values */
+
+#include "beval.h" /* BalloonEval */
+
+/* Note that gui.h is included by structs.h */
+
+#include "structs.h" /* defines many structures */
+
+#include "alloc.h"
+
+/* Values for "do_profiling". */
+#define PROF_NONE 0 /* profiling not started */
+#define PROF_YES 1 /* profiling busy */
+#define PROF_PAUSED 2 /* profiling paused */
+
+#ifdef FEAT_MOUSE
+
+/* Codes for mouse button events in lower three bits: */
+# define MOUSE_LEFT 0x00
+# define MOUSE_MIDDLE 0x01
+# define MOUSE_RIGHT 0x02
+# define MOUSE_RELEASE 0x03
+
+/* bit masks for modifiers: */
+# define MOUSE_SHIFT 0x04
+# define MOUSE_ALT 0x08
+# define MOUSE_CTRL 0x10
+
+/* mouse buttons that are handled like a key press (GUI only) */
+/* Note that the scroll wheel keys are inverted: MOUSE_5 scrolls lines up but
+ * the result of this is that the window moves down, similarly MOUSE_6 scrolls
+ * columns left but the window moves right. */
+# define MOUSE_4 0x100 /* scroll wheel down */
+# define MOUSE_5 0x200 /* scroll wheel up */
+
+# define MOUSE_X1 0x300 /* Mouse-button X1 (6th) */
+# define MOUSE_X2 0x400 /* Mouse-button X2 */
+
+# define MOUSE_6 0x500 /* scroll wheel left */
+# define MOUSE_7 0x600 /* scroll wheel right */
+
+/* 0x20 is reserved by xterm */
+# define MOUSE_DRAG_XTERM 0x40
+
+# define MOUSE_DRAG (0x40 | MOUSE_RELEASE)
+
+/* Lowest button code for using the mouse wheel (xterm only) */
+# define MOUSEWHEEL_LOW 0x60
+
+# define MOUSE_CLICK_MASK 0x03
+
+# define NUM_MOUSE_CLICKS(code) \
+ (((unsigned)((code) & 0xC0) >> 6) + 1)
+
+# define SET_NUM_MOUSE_CLICKS(code, num) \
+ (code) = ((code) & 0x3f) | ((((num) - 1) & 3) << 6)
+
+/* Added to mouse column for GUI when 'mousefocus' wants to give focus to a
+ * window by simulating a click on its status line. We could use up to 128 *
+ * 128 = 16384 columns, now it's reduced to 10000. */
+# define MOUSE_COLOFF 10000
+
+/*
+ * jump_to_mouse() returns one of first four these values, possibly with
+ * some of the other three added.
+ */
+# define IN_UNKNOWN 0
+# define IN_BUFFER 1
+# define IN_STATUS_LINE 2 /* on status or command line */
+# define IN_SEP_LINE 4 /* on vertical separator line */
+# define IN_OTHER_WIN 8 /* in other window but can't go there */
+# define CURSOR_MOVED 0x100
+# define MOUSE_FOLD_CLOSE 0x200 /* clicked on '-' in fold column */
+# define MOUSE_FOLD_OPEN 0x400 /* clicked on '+' in fold column */
+# define MOUSE_WINBAR 0x800 /* in window toolbar */
+
+/* flags for jump_to_mouse() */
+# define MOUSE_FOCUS 0x01 /* need to stay in this window */
+# define MOUSE_MAY_VIS 0x02 /* may start Visual mode */
+# define MOUSE_DID_MOVE 0x04 /* only act when mouse has moved */
+# define MOUSE_SETPOS 0x08 /* only set current mouse position */
+# define MOUSE_MAY_STOP_VIS 0x10 /* may stop Visual mode */
+# define MOUSE_RELEASED 0x20 /* button was released */
+
+# if defined(UNIX) && defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
+# define CHECK_DOUBLE_CLICK 1 /* Checking for double clicks ourselves. */
+# endif
+
+#endif /* FEAT_MOUSE */
+
+/* defines for eval_vars() */
+#define VALID_PATH 1
+#define VALID_HEAD 2
+
+/* Defines for Vim variables. These must match vimvars[] in eval.c! */
+#define VV_COUNT 0
+#define VV_COUNT1 1
+#define VV_PREVCOUNT 2
+#define VV_ERRMSG 3
+#define VV_WARNINGMSG 4
+#define VV_STATUSMSG 5
+#define VV_SHELL_ERROR 6
+#define VV_THIS_SESSION 7
+#define VV_VERSION 8
+#define VV_LNUM 9
+#define VV_TERMRESPONSE 10
+#define VV_FNAME 11
+#define VV_LANG 12
+#define VV_LC_TIME 13
+#define VV_CTYPE 14
+#define VV_CC_FROM 15
+#define VV_CC_TO 16
+#define VV_FNAME_IN 17
+#define VV_FNAME_OUT 18
+#define VV_FNAME_NEW 19
+#define VV_FNAME_DIFF 20
+#define VV_CMDARG 21
+#define VV_FOLDSTART 22
+#define VV_FOLDEND 23
+#define VV_FOLDDASHES 24
+#define VV_FOLDLEVEL 25
+#define VV_PROGNAME 26
+#define VV_SEND_SERVER 27
+#define VV_DYING 28
+#define VV_EXCEPTION 29
+#define VV_THROWPOINT 30
+#define VV_REG 31
+#define VV_CMDBANG 32
+#define VV_INSERTMODE 33
+#define VV_VAL 34
+#define VV_KEY 35
+#define VV_PROFILING 36
+#define VV_FCS_REASON 37
+#define VV_FCS_CHOICE 38
+#define VV_BEVAL_BUFNR 39
+#define VV_BEVAL_WINNR 40
+#define VV_BEVAL_WINID 41
+#define VV_BEVAL_LNUM 42
+#define VV_BEVAL_COL 43
+#define VV_BEVAL_TEXT 44
+#define VV_SCROLLSTART 45
+#define VV_SWAPNAME 46
+#define VV_SWAPCHOICE 47
+#define VV_SWAPCOMMAND 48
+#define VV_CHAR 49
+#define VV_MOUSE_WIN 50
+#define VV_MOUSE_WINID 51
+#define VV_MOUSE_LNUM 52
+#define VV_MOUSE_COL 53
+#define VV_OP 54
+#define VV_SEARCHFORWARD 55
+#define VV_HLSEARCH 56
+#define VV_OLDFILES 57
+#define VV_WINDOWID 58
+#define VV_PROGPATH 59
+#define VV_COMPLETED_ITEM 60
+#define VV_OPTION_NEW 61
+#define VV_OPTION_OLD 62
+#define VV_OPTION_TYPE 63
+#define VV_ERRORS 64
+#define VV_FALSE 65
+#define VV_TRUE 66
+#define VV_NULL 67
+#define VV_NONE 68
+#define VV_VIM_DID_ENTER 69
+#define VV_TESTING 70
+#define VV_TYPE_NUMBER 71
+#define VV_TYPE_STRING 72
+#define VV_TYPE_FUNC 73
+#define VV_TYPE_LIST 74
+#define VV_TYPE_DICT 75
+#define VV_TYPE_FLOAT 76
+#define VV_TYPE_BOOL 77
+#define VV_TYPE_NONE 78
+#define VV_TYPE_JOB 79
+#define VV_TYPE_CHANNEL 80
+#define VV_TYPE_BLOB 81
+#define VV_TERMRFGRESP 82
+#define VV_TERMRBGRESP 83
+#define VV_TERMU7RESP 84
+#define VV_TERMSTYLERESP 85
+#define VV_TERMBLINKRESP 86
+#define VV_EVENT 87
+#define VV_LEN 88 /* number of v: vars */
+
+/* used for v_number in VAR_SPECIAL */
+#define VVAL_FALSE 0L
+#define VVAL_TRUE 1L
+#define VVAL_NONE 2L
+#define VVAL_NULL 3L
+
+/* Type values for type(). */
+#define VAR_TYPE_NUMBER 0
+#define VAR_TYPE_STRING 1
+#define VAR_TYPE_FUNC 2
+#define VAR_TYPE_LIST 3
+#define VAR_TYPE_DICT 4
+#define VAR_TYPE_FLOAT 5
+#define VAR_TYPE_BOOL 6
+#define VAR_TYPE_NONE 7
+#define VAR_TYPE_JOB 8
+#define VAR_TYPE_CHANNEL 9
+#define VAR_TYPE_BLOB 10
+
+#ifdef FEAT_CLIPBOARD
+
+/* VIM_ATOM_NAME is the older Vim-specific selection type for X11. Still
+ * supported for when a mix of Vim versions is used. VIMENC_ATOM_NAME includes
+ * the encoding to support Vims using different 'encoding' values. */
+# define VIM_ATOM_NAME "_VIM_TEXT"
+# define VIMENC_ATOM_NAME "_VIMENC_TEXT"
+
+/* Selection states for modeless selection */
+# define SELECT_CLEARED 0
+# define SELECT_IN_PROGRESS 1
+# define SELECT_DONE 2
+
+# define SELECT_MODE_CHAR 0
+# define SELECT_MODE_WORD 1
+# define SELECT_MODE_LINE 2
+
+# ifdef FEAT_GUI_W32
+# ifdef FEAT_OLE
+# define WM_OLE (WM_APP+0)
+# endif
+# endif
+
+/* Info about selected text */
+typedef struct VimClipboard
+{
+ int available; /* Is clipboard available? */
+ int owned; /* Flag: do we own the selection? */
+ pos_T start; /* Start of selected area */
+ pos_T end; /* End of selected area */
+ int vmode; /* Visual mode character */
+
+ /* Fields for selection that doesn't use Visual mode */
+ short_u origin_row;
+ short_u origin_start_col;
+ short_u origin_end_col;
+ short_u word_start_col;
+ short_u word_end_col;
+
+ pos_T prev; /* Previous position */
+ short_u state; /* Current selection state */
+ short_u mode; /* Select by char, word, or line. */
+
+# if defined(FEAT_GUI_X11) || defined(FEAT_XCLIPBOARD)
+ Atom sel_atom; /* PRIMARY/CLIPBOARD selection ID */
+# endif
+
+# ifdef FEAT_GUI_GTK
+ GdkAtom gtk_sel_atom; /* PRIMARY/CLIPBOARD selection ID */
+# endif
+
+# if defined(MSWIN) || defined(FEAT_CYGWIN_WIN32_CLIPBOARD)
+ int_u format; /* Vim's own special clipboard format */
+ int_u format_raw; /* Vim's raw text clipboard format */
+# endif
+} VimClipboard;
+#else
+typedef int VimClipboard; /* This is required for the prototypes. */
+#endif
+
+/* Use 64-bit stat structure if available. */
+#if (defined(_MSC_VER) && (_MSC_VER >= 1300)) || defined(__MINGW32__)
+# define HAVE_STAT64
+typedef struct _stat64 stat_T;
+#else
+typedef struct stat stat_T;
+#endif
+
+#if defined(__GNUC__) && !defined(__MINGW32__)
+# define USE_PRINTF_FORMAT_ATTRIBUTE
+#endif
+
+typedef enum
+{
+ ASSERT_EQUAL,
+ ASSERT_NOTEQUAL,
+ ASSERT_MATCH,
+ ASSERT_NOTMATCH,
+ ASSERT_OTHER
+} assert_type_T;
+
+/* Mode for bracketed_paste(). */
+typedef enum {
+ PASTE_INSERT, /* insert mode */
+ PASTE_CMDLINE, /* command line */
+ PASTE_EX, /* ex mode line */
+ PASTE_ONE_CHAR /* return first character */
+} paste_mode_T;
+
+// Argument for flush_buffers().
+typedef enum {
+ FLUSH_MINIMAL,
+ FLUSH_TYPEAHEAD, // flush current typebuf contents
+ FLUSH_INPUT // flush typebuf and inchar() input
+} flush_buffers_T;
+
+#include "ex_cmds.h" /* Ex command defines */
+#include "spell.h" /* spell checking stuff */
+
+#include "proto.h" /* function prototypes */
+
+/* This has to go after the include of proto.h, as proto/gui.pro declares
+ * functions of these names. The declarations would break if the defines had
+ * been seen at that stage. But it must be before globals.h, where error_ga
+ * is declared. */
+#if !defined(FEAT_GUI_W32) && !defined(FEAT_GUI_X11) \
+ && !defined(FEAT_GUI_GTK) && !defined(FEAT_GUI_MAC) && !defined(PROTO)
+# define mch_errmsg(str) fprintf(stderr, "%s", (str))
+# define display_errors() fflush(stderr)
+# define mch_msg(str) printf("%s", (str))
+#else
+# define USE_MCH_ERRMSG
+#endif
+
+# if defined(FEAT_EVAL) \
+ && (!defined(FEAT_GUI_W32) \
+ || !(defined(FEAT_MBYTE_IME) || defined(GLOBAL_IME))) \
+ && !(defined(FEAT_GUI_MAC) && defined(MACOS_CONVERT))
+/* 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
+ * MACOS_CONVERT is defined. */
+# define IME_WITHOUT_XIM
+#endif
+
+#if defined(FEAT_XIM) \
+ || defined(IME_WITHOUT_XIM) \
+ || (defined(FEAT_GUI_W32) \
+ && (defined(FEAT_MBYTE_IME) || defined(GLOBAL_IME))) \
+ || defined(FEAT_GUI_MAC)
+/* im_set_active() is available */
+# define HAVE_INPUT_METHOD
+#endif
+
+#ifndef FEAT_LINEBREAK
+/* Without the 'numberwidth' option line numbers are always 7 chars. */
+# define number_width(x) 7
+#endif
+
+/* This must come after including proto.h.
+ * For VMS this is defined in macros.h. */
+#if !defined(WIN3264) && !defined(VMS)
+# define mch_open(n, m, p) open((n), (m), (p))
+# define mch_fopen(n, p) fopen((n), (p))
+#endif
+
+#include "globals.h" /* global variables and messages */
+
+/*
+ * If console dialog not supported, but GUI dialog is, use the GUI one.
+ */
+#if defined(FEAT_GUI_DIALOG) && !defined(FEAT_CON_DIALOG)
+# define do_dialog gui_mch_dialog
+#endif
+
+/*
+ * Default filters for gui_mch_browse().
+ * The filters are almost system independent. Except for the difference
+ * between "*" and "*.*" for MSDOS-like systems.
+ * NOTE: Motif only uses the very first pattern. Therefore
+ * BROWSE_FILTER_DEFAULT should start with a "*" pattern.
+ */
+#ifdef FEAT_BROWSE
+# ifdef BACKSLASH_IN_FILENAME
+# define BROWSE_FILTER_MACROS \
+ (char_u *)N_("Vim macro files (*.vim)\t*.vim\nAll Files (*.*)\t*.*\n")
+# define BROWSE_FILTER_ALL_FILES (char_u *)N_("All Files (*.*)\t*.*\n")
+# define BROWSE_FILTER_DEFAULT \
+ (char_u *)N_("All Files (*.*)\t*.*\nC source (*.c, *.h)\t*.c;*.h\nC++ source (*.cpp, *.hpp)\t*.cpp;*.hpp\nVB code (*.bas, *.frm)\t*.bas;*.frm\nVim files (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n")
+# else
+# define BROWSE_FILTER_MACROS \
+ (char_u *)N_("Vim macro files (*.vim)\t*.vim\nAll Files (*)\t*\n")
+# define BROWSE_FILTER_ALL_FILES (char_u *)N_("All Files (*)\t*\n")
+# define BROWSE_FILTER_DEFAULT \
+ (char_u *)N_("All Files (*)\t*\nC source (*.c, *.h)\t*.c;*.h\nC++ source (*.cpp, *.hpp)\t*.cpp;*.hpp\nVim files (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n")
+# endif
+# define BROWSE_SAVE 1 /* flag for do_browse() */
+# define BROWSE_DIR 2 /* flag for do_browse() */
+#endif
+
+/* stop using fastcall for Borland */
+#if defined(__BORLANDC__) && defined(WIN32) && !defined(DEBUG)
+ #pragma option -p.
+#endif
+
+#ifdef _MSC_VER
+/* Avoid useless warning "conversion from X to Y of greater size". */
+ #pragma warning(disable : 4312)
+/* Avoid warning for old style function declarators */
+ #pragma warning(disable : 4131)
+/* Avoid warning for conversion to type with smaller range */
+ #pragma warning(disable : 4244)
+/* Avoid warning for conversion to larger size */
+ #pragma warning(disable : 4306)
+/* Avoid warning for unreferenced formal parameter */
+ #pragma warning(disable : 4100)
+/* Avoid warning for differs in indirection to slightly different base type */
+ #pragma warning(disable : 4057)
+/* Avoid warning for constant conditional expression */
+ #pragma warning(disable : 4127)
+/* Avoid warning for assignment within conditional */
+ #pragma warning(disable : 4706)
+#endif
+
+/* Note: a NULL argument for vim_realloc() is not portable, don't use it. */
+#if defined(MEM_PROFILE)
+# define vim_realloc(ptr, size) mem_realloc((ptr), (size))
+#else
+# define vim_realloc(ptr, size) realloc((ptr), (size))
+#endif
+
+/*
+ * Return byte length of character that starts with byte "b".
+ * Returns 1 for a single-byte character.
+ * MB_BYTE2LEN_CHECK() can be used to count a special key as one byte.
+ * Don't call MB_BYTE2LEN(b) with b < 0 or b > 255!
+ */
+#define MB_BYTE2LEN(b) mb_bytelen_tab[b]
+#define MB_BYTE2LEN_CHECK(b) (((b) < 0 || (b) > 255) ? 1 : mb_bytelen_tab[b])
+
+/* properties used in enc_canon_table[] (first three mutually exclusive) */
+#define ENC_8BIT 0x01
+#define ENC_DBCS 0x02
+#define ENC_UNICODE 0x04
+
+#define ENC_ENDIAN_B 0x10 /* Unicode: Big endian */
+#define ENC_ENDIAN_L 0x20 /* Unicode: Little endian */
+
+#define ENC_2BYTE 0x40 /* Unicode: UCS-2 */
+#define ENC_4BYTE 0x80 /* Unicode: UCS-4 */
+#define ENC_2WORD 0x100 /* Unicode: UTF-16 */
+
+#define ENC_LATIN1 0x200 /* Latin1 */
+#define ENC_LATIN9 0x400 /* Latin9 */
+#define ENC_MACROMAN 0x800 /* Mac Roman (not Macro Man! :-) */
+
+#ifdef USE_ICONV
+# ifndef EILSEQ
+# define EILSEQ 123
+# endif
+# ifdef DYNAMIC_ICONV
+/* On Win32 iconv.dll is dynamically loaded. */
+# define ICONV_ERRNO (*iconv_errno())
+# define ICONV_E2BIG 7
+# define ICONV_EINVAL 22
+# define ICONV_EILSEQ 42
+# else
+# define ICONV_ERRNO errno
+# define ICONV_E2BIG E2BIG
+# define ICONV_EINVAL EINVAL
+# define ICONV_EILSEQ EILSEQ
+# endif
+#endif
+
+#define SIGN_BYTE 1 /* byte value used where sign is displayed;
+ attribute value is sign type */
+
+#ifdef FEAT_NETBEANS_INTG
+# define MULTISIGN_BYTE 2 /* byte value used where sign is displayed if
+ multiple signs exist on the line */
+#endif
+
+#if defined(FEAT_GUI) && defined(FEAT_XCLIPBOARD)
+# ifdef FEAT_GUI_GTK
+ /* Avoid using a global variable for the X display. It's ugly
+ * and is likely to cause trouble in multihead environments. */
+# define X_DISPLAY ((gui.in_use) ? gui_mch_get_display() : xterm_dpy)
+# else
+# define X_DISPLAY (gui.in_use ? gui.dpy : xterm_dpy)
+# endif
+#else
+# ifdef FEAT_GUI
+# ifdef FEAT_GUI_GTK
+# define X_DISPLAY ((gui.in_use) ? gui_mch_get_display() : (Display *)NULL)
+# else
+# define X_DISPLAY gui.dpy
+# endif
+# else
+# define X_DISPLAY xterm_dpy
+# endif
+#endif
+
+#if defined(FEAT_BROWSE) && defined(GTK_CHECK_VERSION)
+# if GTK_CHECK_VERSION(2,4,0)
+# define USE_FILE_CHOOSER
+# endif
+#endif
+
+#ifdef FEAT_GUI_GTK
+# if !GTK_CHECK_VERSION(2,14,0)
+# define gtk_widget_get_window(wid) ((wid)->window)
+# define gtk_plug_get_socket_window(wid) ((wid)->socket_window)
+# define gtk_selection_data_get_data(sel) ((sel)->data)
+# define gtk_selection_data_get_data_type(sel) ((sel)->type)
+# define gtk_selection_data_get_format(sel) ((sel)->format)
+# define gtk_selection_data_get_length(sel) ((sel)->length)
+# define gtk_adjustment_set_lower(adj, low) \
+ do { (adj)->lower = low; } while (0)
+# define gtk_adjustment_set_upper(adj, up) \
+ do { (adj)->upper = up; } while (0)
+# define gtk_adjustment_set_page_size(adj, size) \
+ do { (adj)->page_size = size; } while (0)
+# define gtk_adjustment_set_page_increment(adj, inc) \
+ do { (adj)->page_increment = inc; } while (0)
+# define gtk_adjustment_set_step_increment(adj, inc) \
+ do { (adj)->step_increment = inc; } while (0)
+# endif
+# if !GTK_CHECK_VERSION(2,16,0)
+# define gtk_selection_data_get_selection(sel) ((sel)->selection)
+# endif
+# if !GTK_CHECK_VERSION(2,18,0)
+# define gtk_widget_get_allocation(wid, alloc) \
+ do { *(alloc) = (wid)->allocation; } while (0)
+# define gtk_widget_set_allocation(wid, alloc) \
+ do { (wid)->allocation = *(alloc); } while (0)
+# define gtk_widget_get_has_window(wid) !GTK_WIDGET_NO_WINDOW(wid)
+# define gtk_widget_get_sensitive(wid) GTK_WIDGET_SENSITIVE(wid)
+# define gtk_widget_get_visible(wid) GTK_WIDGET_VISIBLE(wid)
+# define gtk_widget_has_focus(wid) GTK_WIDGET_HAS_FOCUS(wid)
+# define gtk_widget_set_window(wid, win) \
+ do { (wid)->window = (win); } while (0)
+# define gtk_widget_set_can_default(wid, can) \
+ do { if (can) { GTK_WIDGET_SET_FLAGS(wid, GTK_CAN_DEFAULT); } \
+ else { GTK_WIDGET_UNSET_FLAGS(wid, GTK_CAN_DEFAULT); } } while (0)
+# define gtk_widget_set_can_focus(wid, can) \
+ do { if (can) { GTK_WIDGET_SET_FLAGS(wid, GTK_CAN_FOCUS); } \
+ else { GTK_WIDGET_UNSET_FLAGS(wid, GTK_CAN_FOCUS); } } while (0)
+# define gtk_widget_set_visible(wid, vis) \
+ do { if (vis) { gtk_widget_show(wid); } \
+ else { gtk_widget_hide(wid); } } while (0)
+# endif
+# if !GTK_CHECK_VERSION(2,20,0)
+# define gtk_widget_get_mapped(wid) GTK_WIDGET_MAPPED(wid)
+# define gtk_widget_get_realized(wid) GTK_WIDGET_REALIZED(wid)
+# define gtk_widget_set_mapped(wid, map) \
+ do { if (map) { GTK_WIDGET_SET_FLAGS(wid, GTK_MAPPED); } \
+ else { GTK_WIDGET_UNSET_FLAGS(wid, GTK_MAPPED); } } while (0)
+# define gtk_widget_set_realized(wid, rea) \
+ do { if (rea) { GTK_WIDGET_SET_FLAGS(wid, GTK_REALIZED); } \
+ else { GTK_WIDGET_UNSET_FLAGS(wid, GTK_REALIZED); } } while (0)
+# endif
+#endif
+
+#ifndef FEAT_NETBEANS_INTG
+# undef NBDEBUG
+#endif
+#ifdef NBDEBUG /* Netbeans debugging. */
+# include "nbdebug.h"
+#else
+# define nbdebug(a)
+#endif
+
+#ifdef IN_PERL_FILE
+ /*
+ * Avoid clashes between Perl and Vim namespace.
+ */
+# undef NORMAL
+# undef STRLEN
+# undef FF
+# undef OP_DELETE
+# undef OP_JOIN
+# ifdef __BORLANDC__
+# define NOPROTO 1
+# endif
+ /* remove MAX and MIN, included by glib.h, redefined by sys/param.h */
+# ifdef MAX
+# undef MAX
+# endif
+# ifdef MIN
+# undef MIN
+# endif
+ /* We use _() for gettext(), Perl uses it for function prototypes... */
+# ifdef _
+# undef _
+# endif
+# ifdef DEBUG
+# undef DEBUG
+# endif
+# ifdef _DEBUG
+# undef _DEBUG
+# endif
+# ifdef instr
+# undef instr
+# endif
+ /* bool may cause trouble on some old versions of Mac OS X but is required
+ * on a few other systems and for Perl */
+# if (defined(MACOS_X) && !defined(MAC_OS_X_VERSION_10_6)) \
+ && defined(bool) && !defined(FEAT_PERL)
+# undef bool
+# endif
+
+# ifdef __BORLANDC__
+ /* Borland has the structure stati64 but not _stati64 */
+# define _stati64 stati64
+# endif
+#endif
+
+/* values for vim_handle_signal() that are not a signal */
+#define SIGNAL_BLOCK -1
+#define SIGNAL_UNBLOCK -2
+#if !defined(UNIX) && !defined(VMS)
+# define vim_handle_signal(x) 0
+#endif
+
+/* flags for skip_vimgrep_pat() */
+#define VGR_GLOBAL 1
+#define VGR_NOJUMP 2
+
+/* behavior for bad character, "++bad=" argument */
+#define BAD_REPLACE '?' /* replace it with '?' (default) */
+#define BAD_KEEP -1 /* leave it */
+#define BAD_DROP -2 /* erase it */
+
+/* last argument for do_source() */
+#define DOSO_NONE 0
+#define DOSO_VIMRC 1 /* loading vimrc file */
+#define DOSO_GVIMRC 2 /* loading gvimrc file */
+
+/* flags for read_viminfo() and children */
+#define VIF_WANT_INFO 1 /* load non-mark info */
+#define VIF_WANT_MARKS 2 /* load file marks */
+#define VIF_FORCEIT 4 /* overwrite info already read */
+#define VIF_GET_OLDFILES 8 /* load v:oldfiles */
+
+/* flags for buf_freeall() */
+#define BFA_DEL 1 /* buffer is going to be deleted */
+#define BFA_WIPE 2 /* buffer is going to be wiped out */
+#define BFA_KEEP_UNDO 4 /* do not free undo information */
+
+/* direction for nv_mousescroll() and ins_mousescroll() */
+#define MSCR_DOWN 0 /* DOWN must be FALSE */
+#define MSCR_UP 1
+#define MSCR_LEFT -1
+#define MSCR_RIGHT -2
+
+#define KEYLEN_PART_KEY -1 /* keylen value for incomplete key-code */
+#define KEYLEN_PART_MAP -2 /* keylen value for incomplete mapping */
+#define KEYLEN_REMOVED 9999 /* keylen value for removed sequence */
+
+/* Return values from win32_fileinfo(). */
+#define FILEINFO_OK 0
+#define FILEINFO_ENC_FAIL 1 /* enc_to_utf16() failed */
+#define FILEINFO_READ_FAIL 2 /* CreateFile() failed */
+#define FILEINFO_INFO_FAIL 3 /* GetFileInformationByHandle() failed */
+
+/* Return value from get_option_value_strict */
+#define SOPT_BOOL 0x01 /* Boolean option */
+#define SOPT_NUM 0x02 /* Number option */
+#define SOPT_STRING 0x04 /* String option */
+#define SOPT_GLOBAL 0x08 /* Option has global value */
+#define SOPT_WIN 0x10 /* Option has window-local value */
+#define SOPT_BUF 0x20 /* Option has buffer-local value */
+#define SOPT_UNSET 0x40 /* Option does not have local value set */
+
+/* Option types for various functions in option.c */
+#define SREQ_GLOBAL 0 /* Request global option */
+#define SREQ_WIN 1 /* Request window-local option */
+#define SREQ_BUF 2 /* Request buffer-local option */
+
+/* Flags for get_reg_contents */
+#define GREG_NO_EXPR 1 /* Do not allow expression register */
+#define GREG_EXPR_SRC 2 /* Return expression itself for "=" register */
+#define GREG_LIST 4 /* Return list */
+
+/* Character used as separated in autoload function/variable names. */
+#define AUTOLOAD_CHAR '#'
+
+#ifdef FEAT_JOB_CHANNEL
+# define MAX_OPEN_CHANNELS 10
+#else
+# define MAX_OPEN_CHANNELS 0
+#endif
+
+#if defined(WIN32)
+# define MAX_NAMED_PIPE_SIZE 65535
+#endif
+
+/* Options for json_encode() and json_decode. */
+#define JSON_JS 1 /* use JS instead of JSON */
+#define JSON_NO_NONE 2 /* v:none item not allowed */
+#define JSON_NL 4 /* append a NL */
+
+/* Used for flags of do_in_path() */
+#define DIP_ALL 0x01 /* all matches, not just the first one */
+#define DIP_DIR 0x02 /* find directories instead of files. */
+#define DIP_ERR 0x04 /* give an error message when none found. */
+#define DIP_START 0x08 /* also use "start" directory in 'packpath' */
+#define DIP_OPT 0x10 /* also use "opt" directory in 'packpath' */
+#define DIP_NORTP 0x20 /* do not use 'runtimepath' */
+#define DIP_NOAFTER 0x40 /* skip "after" directories */
+#define DIP_AFTER 0x80 /* only use "after" directories */
+
+/* Lowest number used for window ID. Cannot have this many windows. */
+#define LOWEST_WIN_ID 1000
+
+/* Used by the garbage collector. */
+#define COPYID_INC 2
+#define COPYID_MASK (~0x1)
+
+/* Values for trans_function_name() argument: */
+#define TFN_INT 1 /* internal function name OK */
+#define TFN_QUIET 2 /* no error messages */
+#define TFN_NO_AUTOLOAD 4 /* do not use script autoloading */
+#define TFN_NO_DEREF 8 /* do not dereference a Funcref */
+#define TFN_READ_ONLY 16 /* will not change the var */
+
+/* Values for get_lval() flags argument: */
+#define GLV_QUIET TFN_QUIET /* no error messages */
+#define GLV_NO_AUTOLOAD TFN_NO_AUTOLOAD /* do not use script autoloading */
+#define GLV_READ_ONLY TFN_READ_ONLY /* will not change the var */
+
+#define DO_NOT_FREE_CNT 99999 /* refcount for dict or list that should not
+ be freed. */
+
+/* errors for when calling a function */
+#define ERROR_UNKNOWN 0
+#define ERROR_TOOMANY 1
+#define ERROR_TOOFEW 2
+#define ERROR_SCRIPT 3
+#define ERROR_DICT 4
+#define ERROR_NONE 5
+#define ERROR_OTHER 6
+#define ERROR_DELETED 7
+
+/* flags for find_name_end() */
+#define FNE_INCL_BR 1 /* include [] in name */
+#define FNE_CHECK_START 2 /* check name starts with valid character */
+
+/* BSD is supposed to cover FreeBSD and similar systems. */
+#if (defined(SUN_SYSTEM) || defined(BSD) || defined(__FreeBSD_kernel__)) \
+ && (defined(S_ISCHR) || defined(S_IFCHR))
+# define OPEN_CHR_FILES
+#endif
+
+/* stat macros */
+#ifndef S_ISDIR
+# ifdef S_IFDIR
+# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+# else
+# define S_ISDIR(m) 0
+# endif
+#endif
+#ifndef S_ISREG
+# ifdef S_IFREG
+# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+# else
+# define S_ISREG(m) 0
+# endif
+#endif
+#ifndef S_ISBLK
+# ifdef S_IFBLK
+# define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
+# else
+# define S_ISBLK(m) 0
+# endif
+#endif
+#ifndef S_ISSOCK
+# ifdef S_IFSOCK
+# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
+# else
+# define S_ISSOCK(m) 0
+# endif
+#endif
+#ifndef S_ISFIFO
+# ifdef S_IFIFO
+# define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
+# else
+# define S_ISFIFO(m) 0
+# endif
+#endif
+#ifndef S_ISCHR
+# ifdef S_IFCHR
+# define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
+# else
+# define S_ISCHR(m) 0
+# endif
+#endif
+#ifndef S_ISLNK
+# ifdef S_IFLNK
+# define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
+# else
+# define S_ISLNK(m) 0
+# endif
+#endif
+
+#if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
+# define ELAPSED_TIMEVAL
+# define ELAPSED_INIT(v) gettimeofday(&v, NULL)
+# define ELAPSED_FUNC(v) elapsed(&v)
+typedef struct timeval elapsed_T;
+long elapsed(struct timeval *start_tv);
+#elif defined(WIN32)
+# define ELAPSED_TICKCOUNT
+# define ELAPSED_INIT(v) v = GetTickCount()
+# define ELAPSED_FUNC(v) elapsed(v)
+# ifdef PROTO
+typedef int DWORD;
+# endif
+typedef DWORD elapsed_T;
+# ifndef PROTO
+long elapsed(DWORD start_tick);
+# endif
+#endif
+
+/* Replacement for nchar used by nv_replace(). */
+#define REPLACE_CR_NCHAR -1
+#define REPLACE_NL_NCHAR -2
+
+/* flags for term_start() */
+#define TERM_START_NOJOB 1
+#define TERM_START_FORCEIT 2
+#define TERM_START_SYSTEM 4
+
+// Used for icon/title save and restore.
+#define SAVE_RESTORE_TITLE 1
+#define SAVE_RESTORE_ICON 2
+#define SAVE_RESTORE_BOTH (SAVE_RESTORE_TITLE | SAVE_RESTORE_ICON)
+
+#endif /* VIM__H */
diff --git a/src/vim.ico b/src/vim.ico
new file mode 100644
index 0000000..5e94092
--- /dev/null
+++ b/src/vim.ico
Binary files differ
diff --git a/src/vim.rc b/src/vim.rc
new file mode 100644
index 0000000..492c74b
--- /dev/null
+++ b/src/vim.rc
@@ -0,0 +1,123 @@
+// vi:set ts=8 sts=4 sw=4 noet:
+//
+// VIM - Vi IMproved by Bram Moolenaar
+//
+// Do ":help uganda" in Vim to read copying and usage conditions.
+// Do ":help credits" in Vim to see a list of people who contributed.
+
+// vim.rc
+// Icon and version information for the Win32 version of Vim
+// Must be in DOS format <CR><NL>!
+
+#include <winver.h>
+#include "version.h"
+#include "gui_w32_rc.h"
+// #if defined(__BORLANDC__) || defined(__CYGWIN32__) || defined(__MINGW32__)
+# include <winresrc.h>
+// #else
+// # include <winres.h>
+// #endif
+
+//
+// Icons
+//
+IDR_VIM ICON "vim.ico"
+
+#ifdef FEAT_GUI_W32
+IDR_VIM_ERROR ICON "vim_error.ico"
+IDR_VIM_ALERT ICON "vim_alert.ico"
+IDR_VIM_INFO ICON "vim_info.ico"
+IDR_VIM_QUESTION ICON "vim_quest.ico"
+
+//
+// Bitmaps
+//
+IDB_TEAROFF BITMAP DISCARDABLE "tearoff.bmp"
+IDR_TOOLBAR1 BITMAP DISCARDABLE "tools.bmp"
+
+//
+// WinXP theme support
+//
+#ifndef CREATEPROCESS_MANIFEST_RESOURCE_ID
+# define CREATEPROCESS_MANIFEST_RESOURCE_ID 1
+#endif
+#ifndef RT_MANIFEST
+# define RT_MANIFEST 24
+#endif
+
+CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "gvim.exe.mnf"
+#endif // FEAT_GUI_W32
+
+//
+// Type Library
+//
+#ifdef FEAT_OLE
+ 1 TYPELIB "vim.tlb"
+#endif
+
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION VIM_VERSION_MAJOR,VIM_VERSION_MINOR,VIM_VERSION_BUILD,VIM_VERSION_PATCHLEVEL
+ PRODUCTVERSION VIM_VERSION_MAJOR,VIM_VERSION_MINOR,VIM_VERSION_BUILD,VIM_VERSION_PATCHLEVEL
+ FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+
+#if VIM_VERSION_PATCHLEVEL > 0
+ #ifdef _DEBUG
+ FILEFLAGS VS_FF_PRERELEASE | VS_FF_DEBUG | VS_FF_PATCHED
+ #else
+ FILEFLAGS VS_FF_PRERELEASE | VS_FF_PATCHED
+ #endif
+#else
+ #ifdef _DEBUG
+ FILEFLAGS VS_FF_PRERELEASE | VS_FF_DEBUG
+ #else
+ FILEFLAGS VS_FF_PRERELEASE
+ #endif
+#endif
+
+ FILEOS VOS__WINDOWS32
+ FILETYPE VFT_APP
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ // 0x0409 == U.S. English; 0x04E4 => Windows Multilingual
+ BLOCK "040904E4"
+ BEGIN
+ VALUE "CompanyName", "Vim Developers\0"
+ VALUE "FileDescription", "Vi Improved - A Text Editor\0"
+ VALUE "FileVersion", VIM_VERSION_MAJOR_STR ", " VIM_VERSION_MINOR_STR ", " VIM_VERSION_BUILD_STR ", " VIM_VERSION_PATCHLEVEL_STR "\0"
+ VALUE "InternalName", "VIM\0"
+ VALUE "LegalCopyright", "Copyright \251 1996\0"
+ VALUE "LegalTrademarks", "Vim\0"
+ VALUE "OriginalFilename", "VIM.EXE\0"
+ VALUE "ProductName", "Vim\0"
+ VALUE "ProductVersion", VIM_VERSION_MAJOR_STR ", " VIM_VERSION_MINOR_STR ", " VIM_VERSION_BUILD_STR ", " VIM_VERSION_PATCHLEVEL_STR "\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 0x4E4
+ END
+END
+
+/*
+ * Printing Status Dialog (should only be used when FEAT_PRINTER is defined)
+ */
+#define IDC_BOX1 400
+#define IDC_PRINTTEXT1 401
+#define IDC_PRINTTEXT2 402
+#define IDC_PROGRESS 403
+PRINTDLGBOX DIALOG 115, 63, 210, 80
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+FONT 8, "Helv"
+BEGIN
+ DEFPUSHBUTTON "Cancel", IDCANCEL, 85, 60, 40, 14
+ CTEXT "Printing",IDC_PRINTTEXT1,23,15,157,9
+ CTEXT " ",IDC_PRINTTEXT2,23,25,157,9
+ CTEXT "Initializing...",IDC_PROGRESS,24,38,157,9
+ GROUPBOX "",IDC_BOX1,19,9,170,47
+END
diff --git a/src/vim.tlb b/src/vim.tlb
new file mode 100644
index 0000000..cb2606c
--- /dev/null
+++ b/src/vim.tlb
Binary files differ
diff --git a/src/vim_alert.ico b/src/vim_alert.ico
new file mode 100644
index 0000000..93d982b
--- /dev/null
+++ b/src/vim_alert.ico
Binary files differ
diff --git a/src/vim_error.ico b/src/vim_error.ico
new file mode 100644
index 0000000..b3fbacf
--- /dev/null
+++ b/src/vim_error.ico
Binary files differ
diff --git a/src/vim_icon.xbm b/src/vim_icon.xbm
new file mode 100644
index 0000000..62a24bb
--- /dev/null
+++ b/src/vim_icon.xbm
@@ -0,0 +1,14 @@
+#define vim_icon_width 32
+#define vim_icon_height 32
+static unsigned char vim_icon_bits[] = {
+ 0x00, 0x80, 0x01, 0x00, 0x00, 0xc0, 0x03, 0x00, 0xfc, 0xff, 0xff, 0x3f,
+ 0x04, 0x80, 0x03, 0x20, 0x04, 0x80, 0x0f, 0x40, 0x08, 0xc0, 0x1f, 0x60,
+ 0x10, 0xe0, 0x3f, 0x60, 0x10, 0xe0, 0x1f, 0x30, 0x10, 0xe0, 0x0f, 0x18,
+ 0x10, 0xe0, 0x07, 0x0e, 0x10, 0xe0, 0x03, 0x07, 0x10, 0xe0, 0x81, 0x0f,
+ 0x18, 0xe0, 0x80, 0x1f, 0x1c, 0x60, 0xe0, 0x3f, 0x1e, 0x20, 0xf0, 0x7f,
+ 0x1f, 0x00, 0xf8, 0xff, 0x1f, 0x00, 0xfc, 0xff, 0x1e, 0x00, 0xfc, 0x7f,
+ 0x1c, 0x00, 0xff, 0x3f, 0x18, 0x80, 0xfc, 0x1f, 0x10, 0x80, 0xfc, 0x0f,
+ 0x10, 0xc0, 0xff, 0x5f, 0x10, 0x60, 0x44, 0x24, 0x10, 0x50, 0x0c, 0x40,
+ 0x10, 0x70, 0xce, 0x24, 0x10, 0x7c, 0x6e, 0x26, 0x10, 0x7a, 0x66, 0x26,
+ 0x10, 0x3d, 0x22, 0x13, 0xa0, 0x32, 0x32, 0x67, 0xd0, 0xe1, 0xdf, 0x1c,
+ 0x00, 0xc0, 0x43, 0x00, 0x00, 0x80, 0x01, 0x00};
diff --git a/src/vim_info.ico b/src/vim_info.ico
new file mode 100644
index 0000000..df043a5
--- /dev/null
+++ b/src/vim_info.ico
Binary files differ
diff --git a/src/vim_mask.xbm b/src/vim_mask.xbm
new file mode 100644
index 0000000..96dd929
--- /dev/null
+++ b/src/vim_mask.xbm
@@ -0,0 +1,14 @@
+#define vim_mask_icon_width 32
+#define vim_mask_icon_height 32
+static unsigned char vim_mask_icon_bits[] = {
+ 0x00, 0x80, 0x01, 0x00, 0x00, 0xc0, 0x03, 0x00, 0xfc, 0xff, 0xff, 0x3f,
+ 0xfc, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0x7f, 0xf8, 0xff, 0xff, 0x7f,
+ 0xf0, 0xff, 0xff, 0x7f, 0xf0, 0xff, 0xff, 0x3f, 0xf0, 0xff, 0xff, 0x1f,
+ 0xf0, 0xff, 0xff, 0x0f, 0xf0, 0xff, 0xff, 0x07, 0xf0, 0xff, 0xff, 0x0f,
+ 0xf8, 0xff, 0xff, 0x1f, 0xfc, 0xff, 0xff, 0x3f, 0xfe, 0xff, 0xff, 0x7f,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0x7f,
+ 0xfc, 0xff, 0xff, 0x3f, 0xf8, 0xff, 0xff, 0x1f, 0xf0, 0xff, 0xff, 0x0f,
+ 0xf0, 0xff, 0xff, 0x5f, 0xf0, 0xff, 0xff, 0x3f, 0xf0, 0xff, 0xff, 0x7f,
+ 0xf0, 0xff, 0xff, 0x3f, 0xf0, 0xff, 0xff, 0x3f, 0xf0, 0xff, 0xff, 0x3f,
+ 0xf0, 0xff, 0xff, 0x3f, 0xf0, 0xff, 0xff, 0x7f, 0xd0, 0xe1, 0xdf, 0x1c,
+ 0x00, 0xc0, 0x43, 0x00, 0x00, 0x80, 0x01, 0x00};
diff --git a/src/vim_quest.ico b/src/vim_quest.ico
new file mode 100644
index 0000000..d6c2239
--- /dev/null
+++ b/src/vim_quest.ico
Binary files differ
diff --git a/src/vimio.h b/src/vimio.h
new file mode 100644
index 0000000..9b031ed
--- /dev/null
+++ b/src/vimio.h
@@ -0,0 +1,19 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/* Visual Studio 2005 has 'deprecated' many of the standard CRT functions */
+#if _MSC_VER >= 1400
+# define _CRT_SECURE_NO_DEPRECATE
+# define _CRT_NONSTDC_NO_DEPRECATE
+#endif
+
+/* cproto fails on missing include files */
+#ifndef PROTO
+# include <io.h>
+#endif
diff --git a/src/vimrun.c b/src/vimrun.c
new file mode 100644
index 0000000..13efd91
--- /dev/null
+++ b/src/vimrun.c
@@ -0,0 +1,96 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ * this file by Vince Negri
+ *
+ * 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.
+ */
+
+/*
+ * vimrun.c - Tiny Win32 program to safely run an external command in a
+ * DOS console.
+ * This program is required to avoid that typing CTRL-C in the DOS
+ * console kills Vim. Now it only kills vimrun.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <conio.h>
+#ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+
+#ifdef __BORLANDC__
+# define _kbhit kbhit
+# define _getch getch
+#endif
+
+ int
+main(void)
+{
+ const wchar_t *p;
+ int retval;
+ int inquote = 0;
+ int silent = 0;
+ HANDLE hstdout;
+ DWORD written;
+
+ p = (const wchar_t *)GetCommandLineW();
+
+ /*
+ * Skip the executable name, which might be in "".
+ */
+ while (*p)
+ {
+ if (*p == L'"')
+ inquote = !inquote;
+ else if (!inquote && *p == L' ')
+ {
+ ++p;
+ break;
+ }
+ ++p;
+ }
+ while (*p == L' ')
+ ++p;
+
+ /*
+ * "-s" argument: don't wait for a key hit.
+ */
+ if (p[0] == L'-' && p[1] == L's' && p[2] == L' ')
+ {
+ silent = 1;
+ p += 3;
+ while (*p == L' ')
+ ++p;
+ }
+
+ /* Print the command, including quotes and redirection. */
+ hstdout = GetStdHandle(STD_OUTPUT_HANDLE);
+ WriteConsoleW(hstdout, p, wcslen(p), &written, NULL);
+ WriteConsoleW(hstdout, L"\r\n", 2, &written, NULL);
+
+ /*
+ * Do it!
+ */
+ retval = _wsystem(p);
+
+ if (retval == -1)
+ perror("vimrun system(): ");
+ else if (retval != 0)
+ printf("shell returned %d\n", retval);
+
+ if (!silent)
+ {
+ puts("Hit any key to close this window...");
+
+ while (_kbhit())
+ (void)_getch();
+ (void)_getch();
+ }
+
+ return retval;
+}
diff --git a/src/vimtutor b/src/vimtutor
new file mode 100755
index 0000000..1e8769b
--- /dev/null
+++ b/src/vimtutor
@@ -0,0 +1,74 @@
+#! /bin/sh
+
+# Start Vim on a copy of the tutor file.
+
+# Usage: vimtutor [-g] [xx]
+# Where optional argument -g starts vimtutor in gvim (GUI) instead of vim.
+# and xx is a language code like "es" or "nl".
+# When an argument is given, it tries loading that tutor.
+# When this fails or no argument was given, it tries using 'v:lang'
+# When that also fails, it uses the English version.
+
+# Vim could be called "vim" or "vi". Also check for "vimN", for people who
+# have Vim installed with its version number.
+# We anticipate up to a future Vim 8.1 version :-).
+seq="vim vim81 vim80 vim8 vim74 vim73 vim72 vim71 vim70 vim7 vim6 vi"
+if test "$1" = "-g"; then
+ # Try to use the GUI version of Vim if possible, it will fall back
+ # on Vim if Gvim is not installed.
+ seq="gvim gvim81 gvim80 gvim8 gvim74 gvim73 gvim72 gvim71 gvim70 gvim7 gvim6 $seq"
+ shift
+fi
+
+xx=$1
+export xx
+
+# We need a temp file for the copy. First try using a standard command.
+tmp="${TMPDIR-/tmp}"
+TUTORCOPY=`mktemp $tmp/tutorXXXXXX || tempfile -p tutor || echo none`
+
+# If the standard commands failed then create a directory to put the copy in.
+# That is a secure way to make a temp file.
+if test "$TUTORCOPY" = none; then
+ tmpdir=$tmp/vimtutor$$
+ OLD_UMASK=`umask`
+ umask 077
+ getout=no
+ mkdir $tmpdir || getout=yes
+ umask $OLD_UMASK
+ if test $getout = yes; then
+ echo "Could not create directory for tutor copy, exiting."
+ exit 1
+ fi
+ TUTORCOPY=$tmpdir/tutorcopy
+ touch $TUTORCOPY
+ TODELETE=$tmpdir
+else
+ TODELETE=$TUTORCOPY
+fi
+
+export TUTORCOPY
+
+# remove the copy of the tutor on exit
+trap "rm -rf $TODELETE" 0 1 2 3 9 11 13 15
+
+for i in $seq; do
+ testvim=`which $i 2>/dev/null`
+ if test -f "$testvim"; then
+ VIM=$i
+ break
+ fi
+done
+
+# When no Vim version was found fall back to "vim", you'll get an error message
+# below.
+if test -z "$VIM"; then
+ VIM=vim
+fi
+
+# Use Vim to copy the tutor, it knows the value of $VIMRUNTIME
+# The script tutor.vim tells Vim which file to copy
+$VIM -f -u NONE -c 'so $VIMRUNTIME/tutor/tutor.vim'
+
+# Start vim without any .vimrc, set 'nocompatible' and 'showcmd'
+$VIM -f -u NONE -c "set nocp showcmd" $TUTORCOPY
diff --git a/src/which.sh b/src/which.sh
new file mode 100755
index 0000000..8c2c698
--- /dev/null
+++ b/src/which.sh
@@ -0,0 +1,12 @@
+#! /bin/sh
+#
+# which.sh -- find where an executable is located. It's here because the
+# "which" command is not supported everywhere. Used by Makefile.
+
+IFS=":"
+for ac_dir in $PATH; do
+ if test -f "$ac_dir/$1"; then
+ echo "$ac_dir/$1"
+ break
+ fi
+done
diff --git a/src/winclip.c b/src/winclip.c
new file mode 100644
index 0000000..0285dc5
--- /dev/null
+++ b/src/winclip.c
@@ -0,0 +1,799 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * 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.
+ */
+
+/*
+ * winclip.c
+ *
+ * Routines for Win32 clipboard handling.
+ * Also used by Cygwin, using os_unix.c.
+ */
+
+#include "vimio.h"
+#include "vim.h"
+
+/*
+ * Compile only the clipboard handling features when compiling for cygwin
+ * posix environment.
+ */
+#ifdef FEAT_CYGWIN_WIN32_CLIPBOARD
+# define WIN3264
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+# include "winclip.pro"
+#endif
+
+/*
+ * When generating prototypes for Win32 on Unix, these lines make the syntax
+ * errors disappear. They do not need to be correct.
+ */
+#ifdef PROTO
+#define WINAPI
+#define WINBASEAPI
+typedef int DWORD;
+typedef int LPBOOL;
+typedef int LPCSTR;
+typedef int LPCWSTR;
+typedef int LPSTR;
+typedef int LPWSTR;
+typedef int UINT;
+#endif
+
+/*
+ * Convert an UTF-8 string to UTF-16.
+ * "instr[inlen]" is the input. "inlen" is in bytes.
+ * When "outstr" is NULL only return the number of UTF-16 words produced.
+ * Otherwise "outstr" must be a buffer of sufficient size.
+ * Returns the number of UTF-16 words produced.
+ */
+ int
+utf8_to_utf16(char_u *instr, int inlen, short_u *outstr, int *unconvlenp)
+{
+ int outlen = 0;
+ char_u *p = instr;
+ int todo = inlen;
+ int l;
+ int ch;
+
+ while (todo > 0)
+ {
+ /* Only convert if we have a complete sequence. */
+ l = utf_ptr2len_len(p, todo);
+ if (l > todo)
+ {
+ /* Return length of incomplete sequence. */
+ if (unconvlenp != NULL)
+ *unconvlenp = todo;
+ break;
+ }
+
+ ch = utf_ptr2char(p);
+ if (ch >= 0x10000)
+ {
+ /* non-BMP character, encoding with surrogate pairs */
+ ++outlen;
+ if (outstr != NULL)
+ {
+ *outstr++ = (0xD800 - (0x10000 >> 10)) + (ch >> 10);
+ *outstr++ = 0xDC00 | (ch & 0x3FF);
+ }
+ }
+ else if (outstr != NULL)
+ *outstr++ = ch;
+ ++outlen;
+ p += l;
+ todo -= l;
+ }
+
+ return outlen;
+}
+
+/*
+ * Convert an UTF-16 string to UTF-8.
+ * The input is "instr[inlen]" with "inlen" in number of UTF-16 words.
+ * When "outstr" is NULL only return the required number of bytes.
+ * Otherwise "outstr" must be a buffer of sufficient size.
+ * Return the number of bytes produced.
+ */
+ int
+utf16_to_utf8(short_u *instr, int inlen, char_u *outstr)
+{
+ int outlen = 0;
+ int todo = inlen;
+ short_u *p = instr;
+ int l;
+ int ch, ch2;
+
+ while (todo > 0)
+ {
+ ch = *p;
+ if (ch >= 0xD800 && ch <= 0xDBFF && todo > 1)
+ {
+ /* surrogate pairs handling */
+ ch2 = p[1];
+ if (ch2 >= 0xDC00 && ch2 <= 0xDFFF)
+ {
+ ch = ((ch - 0xD800) << 10) + (ch2 & 0x3FF) + 0x10000;
+ ++p;
+ --todo;
+ }
+ }
+ if (outstr != NULL)
+ {
+ l = utf_char2bytes(ch, outstr);
+ outstr += l;
+ }
+ else
+ l = utf_char2len(ch);
+ ++p;
+ outlen += l;
+ --todo;
+ }
+
+ return outlen;
+}
+
+/*
+ * Call MultiByteToWideChar() and allocate memory for the result.
+ * Returns the result in "*out[*outlen]" with an extra zero appended.
+ * "outlen" is in words.
+ */
+ void
+MultiByteToWideChar_alloc(UINT cp, DWORD flags,
+ LPCSTR in, int inlen,
+ LPWSTR *out, int *outlen)
+{
+ *outlen = MultiByteToWideChar(cp, flags, in, inlen, 0, 0);
+ /* Add one one word to avoid a zero-length alloc(). */
+ *out = (LPWSTR)alloc(sizeof(WCHAR) * (*outlen + 1));
+ if (*out != NULL)
+ {
+ MultiByteToWideChar(cp, flags, in, inlen, *out, *outlen);
+ (*out)[*outlen] = 0;
+ }
+}
+
+/*
+ * Call WideCharToMultiByte() and allocate memory for the result.
+ * Returns the result in "*out[*outlen]" with an extra NUL appended.
+ */
+ void
+WideCharToMultiByte_alloc(UINT cp, DWORD flags,
+ LPCWSTR in, int inlen,
+ LPSTR *out, int *outlen,
+ LPCSTR def, LPBOOL useddef)
+{
+ *outlen = WideCharToMultiByte(cp, flags, in, inlen, NULL, 0, def, useddef);
+ /* Add one one byte to avoid a zero-length alloc(). */
+ *out = (LPSTR)alloc((unsigned)*outlen + 1);
+ if (*out != NULL)
+ {
+ WideCharToMultiByte(cp, flags, in, inlen, *out, *outlen, def, useddef);
+ (*out)[*outlen] = 0;
+ }
+}
+
+
+#ifdef FEAT_CLIPBOARD
+/*
+ * Clipboard stuff, for cutting and pasting text to other windows.
+ */
+
+ void
+win_clip_init(void)
+{
+ clip_init(TRUE);
+
+ /*
+ * Vim's own clipboard format recognises whether the text is char, line,
+ * or rectangular block. Only useful for copying between two Vims.
+ * "VimClipboard" was used for previous versions, using the first
+ * character to specify MCHAR, MLINE or MBLOCK.
+ */
+ clip_star.format = RegisterClipboardFormat("VimClipboard2");
+ clip_star.format_raw = RegisterClipboardFormat("VimRawBytes");
+}
+
+/* Type used for the clipboard type of Vim's data. */
+typedef struct
+{
+ int type; /* MCHAR, MBLOCK or MLINE */
+ int txtlen; /* length of CF_TEXT in bytes */
+ int ucslen; /* length of CF_UNICODETEXT in words */
+ int rawlen; /* length of clip_star.format_raw, including encoding,
+ excluding terminating NUL */
+} VimClipType_t;
+
+/*
+ * Make vim the owner of the current selection. Return OK upon success.
+ */
+ int
+clip_mch_own_selection(VimClipboard *cbd UNUSED)
+{
+ /*
+ * Never actually own the clipboard. If another application sets the
+ * clipboard, we don't want to think that we still own it.
+ */
+ return FAIL;
+}
+
+/*
+ * Make vim NOT the owner of the current selection.
+ */
+ void
+clip_mch_lose_selection(VimClipboard *cbd UNUSED)
+{
+ /* Nothing needs to be done here */
+}
+
+/*
+ * Copy "str[*size]" into allocated memory, changing CR-NL to NL.
+ * Return the allocated result and the size in "*size".
+ * Returns NULL when out of memory.
+ */
+ static char_u *
+crnl_to_nl(const char_u *str, int *size)
+{
+ int pos = 0;
+ int str_len = *size;
+ char_u *ret;
+ char_u *retp;
+
+ /* Avoid allocating zero bytes, it generates an error message. */
+ ret = lalloc((long_u)(str_len == 0 ? 1 : str_len), TRUE);
+ if (ret != NULL)
+ {
+ retp = ret;
+ for (pos = 0; pos < str_len; ++pos)
+ {
+ if (str[pos] == '\r' && str[pos + 1] == '\n')
+ {
+ ++pos;
+ --(*size);
+ }
+ *retp++ = str[pos];
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * Wait for another process to Close the Clipboard.
+ * Returns TRUE for success.
+ */
+ static int
+vim_open_clipboard(void)
+{
+ int delay = 10;
+
+ while (!OpenClipboard(NULL))
+ {
+ if (delay > 500)
+ return FALSE; /* waited too long, give up */
+ Sleep(delay);
+ delay *= 2; /* wait for 10, 20, 40, 80, etc. msec */
+ }
+ return TRUE;
+}
+
+/*
+ * Get the current selection and put it in the clipboard register.
+ *
+ * NOTE: Must use GlobalLock/Unlock here to ensure Win32s compatibility.
+ * On NT/W95 the clipboard data is a fixed global memory object and
+ * so its handle = its pointer.
+ * On Win32s, however, co-operation with the Win16 system means that
+ * the clipboard data is moveable and its handle is not a pointer at all,
+ * so we can't just cast the return value of GetClipboardData to (char_u*).
+ * <VN>
+ */
+ void
+clip_mch_request_selection(VimClipboard *cbd)
+{
+ VimClipType_t metadata = { -1, -1, -1, -1 };
+ HGLOBAL hMem = NULL;
+ char_u *str = NULL;
+#if defined(WIN3264)
+ char_u *to_free = NULL;
+#endif
+ HGLOBAL rawh = NULL;
+ int str_size = 0;
+ int maxlen;
+ size_t n;
+
+ /*
+ * Don't pass GetActiveWindow() as an argument to OpenClipboard() because
+ * then we can't paste back into the same window for some reason - webb.
+ */
+ if (!vim_open_clipboard())
+ return;
+
+ /* Check for vim's own clipboard format first. This only gets the type of
+ * the data, still need to use CF_UNICODETEXT or CF_TEXT for the text. */
+ if (IsClipboardFormatAvailable(cbd->format))
+ {
+ VimClipType_t *meta_p;
+ HGLOBAL meta_h;
+
+ /* We have metadata on the clipboard; try to get it. */
+ if ((meta_h = GetClipboardData(cbd->format)) != NULL
+ && (meta_p = (VimClipType_t *)GlobalLock(meta_h)) != NULL)
+ {
+ /* The size of "VimClipType_t" changed, "rawlen" was added later.
+ * Only copy what is available for backwards compatibility. */
+ n = sizeof(VimClipType_t);
+ if (GlobalSize(meta_h) < n)
+ n = GlobalSize(meta_h);
+ memcpy(&metadata, meta_p, n);
+ GlobalUnlock(meta_h);
+ }
+ }
+
+ /* Check for Vim's raw clipboard format first. This is used without
+ * conversion, but only if 'encoding' matches. */
+ if (IsClipboardFormatAvailable(cbd->format_raw)
+ && metadata.rawlen > (int)STRLEN(p_enc))
+ {
+ /* We have raw data on the clipboard; try to get it. */
+ if ((rawh = GetClipboardData(cbd->format_raw)) != NULL)
+ {
+ char_u *rawp;
+
+ rawp = (char_u *)GlobalLock(rawh);
+ if (rawp != NULL && STRCMP(p_enc, rawp) == 0)
+ {
+ n = STRLEN(p_enc) + 1;
+ str = rawp + n;
+ str_size = (int)(metadata.rawlen - n);
+ }
+ else
+ {
+ GlobalUnlock(rawh);
+ rawh = NULL;
+ }
+ }
+ }
+ if (str == NULL)
+ {
+#if defined(WIN3264)
+ /* Try to get the clipboard in Unicode if it's not an empty string. */
+ if (IsClipboardFormatAvailable(CF_UNICODETEXT) && metadata.ucslen != 0)
+ {
+ HGLOBAL hMemW;
+
+ if ((hMemW = GetClipboardData(CF_UNICODETEXT)) != NULL)
+ {
+ WCHAR *hMemWstr = (WCHAR *)GlobalLock(hMemW);
+
+ /* Use the length of our metadata if possible, but limit it to
+ * the GlobalSize() for safety. */
+ maxlen = (int)(GlobalSize(hMemW) / sizeof(WCHAR));
+ if (metadata.ucslen >= 0)
+ {
+ if (metadata.ucslen > maxlen)
+ str_size = maxlen;
+ else
+ str_size = metadata.ucslen;
+ }
+ else
+ {
+ for (str_size = 0; str_size < maxlen; ++str_size)
+ if (hMemWstr[str_size] == NUL)
+ break;
+ }
+ to_free = str = utf16_to_enc((short_u *)hMemWstr, &str_size);
+ GlobalUnlock(hMemW);
+ }
+ }
+ else
+#endif
+ /* Get the clipboard in the Active codepage. */
+ if (IsClipboardFormatAvailable(CF_TEXT))
+ {
+ if ((hMem = GetClipboardData(CF_TEXT)) != NULL)
+ {
+ str = (char_u *)GlobalLock(hMem);
+
+ /* The length is either what our metadata says or the strlen().
+ * But limit it to the GlobalSize() for safety. */
+ maxlen = (int)GlobalSize(hMem);
+ if (metadata.txtlen >= 0)
+ {
+ if (metadata.txtlen > maxlen)
+ str_size = maxlen;
+ else
+ str_size = metadata.txtlen;
+ }
+ else
+ {
+ for (str_size = 0; str_size < maxlen; ++str_size)
+ if (str[str_size] == NUL)
+ break;
+ }
+
+#if defined(WIN3264)
+ /* The text is in the active codepage. Convert to
+ * 'encoding', going through UTF-16. */
+ acp_to_enc(str, str_size, &to_free, &maxlen);
+ if (to_free != NULL)
+ {
+ str_size = maxlen;
+ str = to_free;
+ }
+#endif
+ }
+ }
+ }
+
+ if (str != NULL && *str != NUL)
+ {
+ char_u *temp_clipboard;
+
+ /* If the type is not known detect it. */
+ if (metadata.type == -1)
+ metadata.type = MAUTO;
+
+ /* Translate <CR><NL> into <NL>. */
+ temp_clipboard = crnl_to_nl(str, &str_size);
+ if (temp_clipboard != NULL)
+ {
+ clip_yank_selection(metadata.type, temp_clipboard, str_size, cbd);
+ vim_free(temp_clipboard);
+ }
+ }
+
+ /* unlock the global object */
+ if (hMem != NULL)
+ GlobalUnlock(hMem);
+ if (rawh != NULL)
+ GlobalUnlock(rawh);
+ CloseClipboard();
+#if defined(WIN3264)
+ vim_free(to_free);
+#endif
+}
+
+/*
+ * Send the current selection to the clipboard.
+ */
+ void
+clip_mch_set_selection(VimClipboard *cbd)
+{
+ char_u *str = NULL;
+ VimClipType_t metadata;
+ long_u txtlen;
+ HGLOBAL hMemRaw = NULL;
+ HGLOBAL hMem = NULL;
+ HGLOBAL hMemVim = NULL;
+# if defined(WIN3264)
+ HGLOBAL hMemW = NULL;
+# endif
+
+ /* If the '*' register isn't already filled in, fill it in now */
+ cbd->owned = TRUE;
+ clip_get_selection(cbd);
+ cbd->owned = FALSE;
+
+ /* Get the text to be put on the clipboard, with CR-LF. */
+ metadata.type = clip_convert_selection(&str, &txtlen, cbd);
+ if (metadata.type < 0)
+ return;
+ metadata.txtlen = (int)txtlen;
+ metadata.ucslen = 0;
+ metadata.rawlen = 0;
+
+ /* Always set the raw bytes: 'encoding', NUL and the text. This is used
+ * when copy/paste from/to Vim with the same 'encoding', so that illegal
+ * bytes can also be copied and no conversion is needed. */
+ {
+ LPSTR lpszMemRaw;
+
+ metadata.rawlen = (int)(txtlen + STRLEN(p_enc) + 1);
+ hMemRaw = (LPSTR)GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE,
+ metadata.rawlen + 1);
+ lpszMemRaw = (LPSTR)GlobalLock(hMemRaw);
+ if (lpszMemRaw != NULL)
+ {
+ STRCPY(lpszMemRaw, p_enc);
+ memcpy(lpszMemRaw + STRLEN(p_enc) + 1, str, txtlen + 1);
+ GlobalUnlock(hMemRaw);
+ }
+ else
+ metadata.rawlen = 0;
+ }
+
+# if defined(WIN3264)
+ {
+ WCHAR *out;
+ int len = metadata.txtlen;
+
+ /* Convert the text to UTF-16. This is put on the clipboard as
+ * CF_UNICODETEXT. */
+ out = (WCHAR *)enc_to_utf16(str, &len);
+ if (out != NULL)
+ {
+ WCHAR *lpszMemW;
+
+ /* Convert the text for CF_TEXT to Active codepage. Otherwise it's
+ * p_enc, which has no relation to the Active codepage. */
+ metadata.txtlen = WideCharToMultiByte(GetACP(), 0, out, len,
+ NULL, 0, 0, 0);
+ vim_free(str);
+ str = (char_u *)alloc((unsigned)(metadata.txtlen == 0 ? 1
+ : metadata.txtlen));
+ if (str == NULL)
+ {
+ vim_free(out);
+ return; /* out of memory */
+ }
+ WideCharToMultiByte(GetACP(), 0, out, len,
+ (LPSTR)str, metadata.txtlen, 0, 0);
+
+ /* Allocate memory for the UTF-16 text, add one NUL word to
+ * terminate the string. */
+ hMemW = (LPSTR)GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE,
+ (len + 1) * sizeof(WCHAR));
+ lpszMemW = (WCHAR *)GlobalLock(hMemW);
+ if (lpszMemW != NULL)
+ {
+ memcpy(lpszMemW, out, len * sizeof(WCHAR));
+ lpszMemW[len] = NUL;
+ GlobalUnlock(hMemW);
+ }
+ vim_free(out);
+ metadata.ucslen = len;
+ }
+ }
+# endif
+
+ /* Allocate memory for the text, add one NUL byte to terminate the string.
+ */
+ hMem = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, metadata.txtlen + 1);
+ {
+ LPSTR lpszMem = (LPSTR)GlobalLock(hMem);
+
+ if (lpszMem)
+ {
+ vim_strncpy((char_u *)lpszMem, str, metadata.txtlen);
+ GlobalUnlock(hMem);
+ }
+ }
+
+ /* Set up metadata: */
+ {
+ VimClipType_t *lpszMemVim = NULL;
+
+ hMemVim = GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE,
+ sizeof(VimClipType_t));
+ lpszMemVim = (VimClipType_t *)GlobalLock(hMemVim);
+ memcpy(lpszMemVim, &metadata, sizeof(metadata));
+ GlobalUnlock(hMemVim);
+ }
+
+ /*
+ * Open the clipboard, clear it and put our text on it.
+ * Always set our Vim format. Put Unicode and plain text on it.
+ *
+ * Don't pass GetActiveWindow() as an argument to OpenClipboard()
+ * because then we can't paste back into the same window for some
+ * reason - webb.
+ */
+ if (vim_open_clipboard())
+ {
+ if (EmptyClipboard())
+ {
+ SetClipboardData(cbd->format, hMemVim);
+ hMemVim = 0;
+# if defined(WIN3264)
+ if (hMemW != NULL)
+ {
+ if (SetClipboardData(CF_UNICODETEXT, hMemW) != NULL)
+ hMemW = NULL;
+ }
+# endif
+ /* Always use CF_TEXT. On Win98 Notepad won't obtain the
+ * CF_UNICODETEXT text, only CF_TEXT. */
+ SetClipboardData(CF_TEXT, hMem);
+ hMem = 0;
+ }
+ CloseClipboard();
+ }
+
+ vim_free(str);
+ /* Free any allocations we didn't give to the clipboard: */
+ if (hMemRaw)
+ GlobalFree(hMemRaw);
+ if (hMem)
+ GlobalFree(hMem);
+# if defined(WIN3264)
+ if (hMemW)
+ GlobalFree(hMemW);
+# endif
+ if (hMemVim)
+ GlobalFree(hMemVim);
+}
+
+#endif /* FEAT_CLIPBOARD */
+
+/*
+ * Note: the following two functions are only guaranteed to work when using
+ * valid MS-Windows codepages or when iconv() is available.
+ */
+
+/*
+ * Convert "str" from 'encoding' to UTF-16.
+ * Input in "str" with length "*lenp". When "lenp" is NULL, use strlen().
+ * Output is returned as an allocated string. "*lenp" is set to the length of
+ * the result. A trailing NUL is always added.
+ * Returns NULL when out of memory.
+ */
+ short_u *
+enc_to_utf16(char_u *str, int *lenp)
+{
+ vimconv_T conv;
+ WCHAR *ret;
+ char_u *allocbuf = NULL;
+ int len_loc;
+ int length;
+
+ if (lenp == NULL)
+ {
+ len_loc = (int)STRLEN(str) + 1;
+ lenp = &len_loc;
+ }
+
+ if (enc_codepage > 0)
+ {
+ /* We can do any CP### -> UTF-16 in one pass, and we can do it
+ * without iconv() (convert_* may need iconv). */
+ MultiByteToWideChar_alloc(enc_codepage, 0, (LPCSTR)str, *lenp,
+ &ret, &length);
+ }
+ else
+ {
+ /* Use "latin1" by default, we might be called before we have p_enc
+ * set up. Convert to utf-8 first, works better with iconv(). Does
+ * nothing if 'encoding' is "utf-8". */
+ conv.vc_type = CONV_NONE;
+ if (convert_setup(&conv, p_enc ? p_enc : (char_u *)"latin1",
+ (char_u *)"utf-8") == FAIL)
+ return NULL;
+ if (conv.vc_type != CONV_NONE)
+ {
+ str = allocbuf = string_convert(&conv, str, lenp);
+ if (str == NULL)
+ return NULL;
+ }
+ convert_setup(&conv, NULL, NULL);
+
+ length = utf8_to_utf16(str, *lenp, NULL, NULL);
+ ret = (WCHAR *)alloc((unsigned)((length + 1) * sizeof(WCHAR)));
+ if (ret != NULL)
+ {
+ utf8_to_utf16(str, *lenp, (short_u *)ret, NULL);
+ ret[length] = 0;
+ }
+
+ vim_free(allocbuf);
+ }
+
+ *lenp = length;
+ return (short_u *)ret;
+}
+
+/*
+ * Convert an UTF-16 string to 'encoding'.
+ * Input in "str" with length (counted in wide characters) "*lenp". When
+ * "lenp" is NULL, use wcslen().
+ * Output is returned as an allocated string. If "*lenp" is not NULL it is
+ * set to the length of the result.
+ * Returns NULL when out of memory.
+ */
+ char_u *
+utf16_to_enc(short_u *str, int *lenp)
+{
+ vimconv_T conv;
+ char_u *utf8_str = NULL, *enc_str = NULL;
+ int len_loc;
+
+ if (lenp == NULL)
+ {
+ len_loc = (int)wcslen(str) + 1;
+ lenp = &len_loc;
+ }
+
+ if (enc_codepage > 0)
+ {
+ /* We can do any UTF-16 -> CP### in one pass. */
+ int length;
+
+ WideCharToMultiByte_alloc(enc_codepage, 0, str, *lenp,
+ (LPSTR *)&enc_str, &length, 0, 0);
+ *lenp = length;
+ return enc_str;
+ }
+
+ /* Avoid allocating zero bytes, it generates an error message. */
+ utf8_str = alloc(utf16_to_utf8(str, *lenp == 0 ? 1 : *lenp, NULL));
+ if (utf8_str != NULL)
+ {
+ *lenp = utf16_to_utf8(str, *lenp, utf8_str);
+
+ /* We might be called before we have p_enc set up. */
+ conv.vc_type = CONV_NONE;
+ convert_setup(&conv, (char_u *)"utf-8",
+ p_enc? p_enc: (char_u *)"latin1");
+ if (conv.vc_type == CONV_NONE)
+ {
+ /* p_enc is utf-8, so we're done. */
+ enc_str = utf8_str;
+ }
+ else
+ {
+ enc_str = string_convert(&conv, utf8_str, lenp);
+ vim_free(utf8_str);
+ }
+
+ convert_setup(&conv, NULL, NULL);
+ }
+
+ return enc_str;
+}
+
+#if defined(WIN3264) || defined(PROTO)
+/*
+ * Convert from the active codepage to 'encoding'.
+ * Input is "str[str_size]".
+ * The result is in allocated memory: "out[outlen]". With terminating NUL.
+ */
+ void
+acp_to_enc(
+ char_u *str,
+ int str_size,
+ char_u **out,
+ int *outlen)
+
+{
+ LPWSTR widestr;
+
+ MultiByteToWideChar_alloc(GetACP(), 0, (LPCSTR)str, str_size,
+ &widestr, outlen);
+ if (widestr != NULL)
+ {
+ ++*outlen; /* Include the 0 after the string */
+ *out = utf16_to_enc((short_u *)widestr, outlen);
+ vim_free(widestr);
+ }
+}
+
+/*
+ * Convert from 'encoding' to the active codepage.
+ * Input is "str[str_size]".
+ * The result is in allocated memory: "out[outlen]". With terminating NUL.
+ */
+ void
+enc_to_acp(
+ char_u *str,
+ int str_size,
+ char_u **out,
+ int *outlen)
+
+{
+ LPWSTR widestr;
+ int len = str_size;
+
+ widestr = (WCHAR *)enc_to_utf16(str, &len);
+ if (widestr != NULL)
+ {
+ WideCharToMultiByte_alloc(GetACP(), 0, widestr, len,
+ (LPSTR *)out, outlen, 0, 0);
+ vim_free(widestr);
+ }
+}
+#endif
diff --git a/src/window.c b/src/window.c
new file mode 100644
index 0000000..f78fcca
--- /dev/null
+++ b/src/window.c
@@ -0,0 +1,7286 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * Do ":help uganda" in Vim to read a list of people who contributed.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ * See README.txt for an overview of the Vim source code.
+ */
+
+#include "vim.h"
+
+static int path_is_url(char_u *p);
+static void cmd_with_count(char *cmd, char_u *bufp, size_t bufsize, long Prenum);
+static void win_init(win_T *newp, win_T *oldp, int flags);
+static void win_init_some(win_T *newp, win_T *oldp);
+static void frame_comp_pos(frame_T *topfrp, int *row, int *col);
+static void frame_setheight(frame_T *curfrp, int height);
+static void frame_setwidth(frame_T *curfrp, int width);
+static void win_exchange(long);
+static void win_rotate(int, int);
+static void win_totop(int size, int flags);
+static void win_equal_rec(win_T *next_curwin, int current, frame_T *topfr, int dir, int col, int row, int width, int height);
+static win_T *win_free_mem(win_T *win, int *dirp, tabpage_T *tp);
+static frame_T *win_altframe(win_T *win, tabpage_T *tp);
+static tabpage_T *alt_tabpage(void);
+static win_T *frame2win(frame_T *frp);
+static int frame_has_win(frame_T *frp, win_T *wp);
+static void frame_new_height(frame_T *topfrp, int height, int topfirst, int wfh);
+static int frame_fixed_height(frame_T *frp);
+static int frame_fixed_width(frame_T *frp);
+static void frame_add_statusline(frame_T *frp);
+static void frame_new_width(frame_T *topfrp, int width, int leftfirst, int wfw);
+static void frame_add_vsep(frame_T *frp);
+static int frame_minwidth(frame_T *topfrp, win_T *next_curwin);
+static void frame_fix_width(win_T *wp);
+static int win_alloc_firstwin(win_T *oldwin);
+static void new_frame(win_T *wp);
+static tabpage_T *alloc_tabpage(void);
+static int leave_tabpage(buf_T *new_curbuf, int trigger_leave_autocmds);
+static void enter_tabpage(tabpage_T *tp, buf_T *old_curbuf, int trigger_enter_autocmds, int trigger_leave_autocmds);
+static void frame_fix_height(win_T *wp);
+static int frame_minheight(frame_T *topfrp, win_T *next_curwin);
+static void win_enter_ext(win_T *wp, int undo_sync, int no_curwin, int trigger_new_autocmds, int trigger_enter_autocmds, int trigger_leave_autocmds);
+static void win_free(win_T *wp, tabpage_T *tp);
+static void frame_append(frame_T *after, frame_T *frp);
+static void frame_insert(frame_T *before, frame_T *frp);
+static void frame_remove(frame_T *frp);
+static void win_goto_ver(int up, long count);
+static void win_goto_hor(int left, long count);
+static void frame_add_height(frame_T *frp, int n);
+static void last_status_rec(frame_T *fr, int statusline);
+
+static void make_snapshot_rec(frame_T *fr, frame_T **frp);
+static void clear_snapshot(tabpage_T *tp, int idx);
+static void clear_snapshot_rec(frame_T *fr);
+static int check_snapshot_rec(frame_T *sn, frame_T *fr);
+static win_T *restore_snapshot_rec(frame_T *sn, frame_T *fr);
+
+static int frame_check_height(frame_T *topfrp, int height);
+static int frame_check_width(frame_T *topfrp, int width);
+
+static win_T *win_alloc(win_T *after, int hidden);
+
+#define URL_SLASH 1 /* path_is_url() has found "://" */
+#define URL_BACKSLASH 2 /* path_is_url() has found ":\\" */
+
+#define NOWIN (win_T *)-1 /* non-existing window */
+
+#define ROWS_AVAIL (Rows - p_ch - tabline_height())
+
+static char *m_onlyone = N_("Already only one window");
+
+/*
+ * all CTRL-W window commands are handled here, called from normal_cmd().
+ */
+ void
+do_window(
+ int nchar,
+ long Prenum,
+ int xchar) /* extra char from ":wincmd gx" or NUL */
+{
+ long Prenum1;
+ win_T *wp;
+#if defined(FEAT_SEARCHPATH) || defined(FEAT_FIND_ID)
+ char_u *ptr;
+ linenr_T lnum = -1;
+#endif
+#ifdef FEAT_FIND_ID
+ int type = FIND_DEFINE;
+ int len;
+#endif
+ char_u cbuf[40];
+
+ if (Prenum == 0)
+ Prenum1 = 1;
+ else
+ Prenum1 = Prenum;
+
+#ifdef FEAT_CMDWIN
+# define CHECK_CMDWIN \
+ do { \
+ if (cmdwin_type != 0) \
+ { \
+ emsg(_(e_cmdwin)); \
+ return; \
+ } \
+ } while (0)
+#else
+# define CHECK_CMDWIN do { /**/ } while (0)
+#endif
+
+ switch (nchar)
+ {
+/* split current window in two parts, horizontally */
+ case 'S':
+ case Ctrl_S:
+ case 's':
+ CHECK_CMDWIN;
+ reset_VIsual_and_resel(); /* stop Visual mode */
+#ifdef FEAT_QUICKFIX
+ /* When splitting the quickfix window open a new buffer in it,
+ * don't replicate the quickfix buffer. */
+ if (bt_quickfix(curbuf))
+ goto newwindow;
+#endif
+#ifdef FEAT_GUI
+ need_mouse_correct = TRUE;
+#endif
+ (void)win_split((int)Prenum, 0);
+ break;
+
+/* split current window in two parts, vertically */
+ case Ctrl_V:
+ case 'v':
+ CHECK_CMDWIN;
+ reset_VIsual_and_resel(); /* stop Visual mode */
+#ifdef FEAT_QUICKFIX
+ /* When splitting the quickfix window open a new buffer in it,
+ * don't replicate the quickfix buffer. */
+ if (bt_quickfix(curbuf))
+ goto newwindow;
+#endif
+#ifdef FEAT_GUI
+ need_mouse_correct = TRUE;
+#endif
+ (void)win_split((int)Prenum, WSP_VERT);
+ break;
+
+/* split current window and edit alternate file */
+ case Ctrl_HAT:
+ case '^':
+ CHECK_CMDWIN;
+ reset_VIsual_and_resel(); /* stop Visual mode */
+
+ if (buflist_findnr(Prenum == 0
+ ? curwin->w_alt_fnum : Prenum) == NULL)
+ {
+ if (Prenum == 0)
+ emsg(_(e_noalt));
+ else
+ semsg(_("E92: Buffer %ld not found"), Prenum);
+ break;
+ }
+
+ if (!curbuf_locked() && win_split(0, 0) == OK)
+ (void)buflist_getfile(
+ Prenum == 0 ? curwin->w_alt_fnum : Prenum,
+ (linenr_T)0, GETF_ALT, FALSE);
+ break;
+
+/* open new window */
+ case Ctrl_N:
+ case 'n':
+ CHECK_CMDWIN;
+ reset_VIsual_and_resel(); /* stop Visual mode */
+#ifdef FEAT_QUICKFIX
+newwindow:
+#endif
+ if (Prenum)
+ /* window height */
+ vim_snprintf((char *)cbuf, sizeof(cbuf) - 5, "%ld", Prenum);
+ else
+ cbuf[0] = NUL;
+#if defined(FEAT_QUICKFIX)
+ if (nchar == 'v' || nchar == Ctrl_V)
+ STRCAT(cbuf, "v");
+#endif
+ STRCAT(cbuf, "new");
+ do_cmdline_cmd(cbuf);
+ break;
+
+/* quit current window */
+ case Ctrl_Q:
+ case 'q':
+ reset_VIsual_and_resel(); /* stop Visual mode */
+ cmd_with_count("quit", cbuf, sizeof(cbuf), Prenum);
+ do_cmdline_cmd(cbuf);
+ break;
+
+/* close current window */
+ case Ctrl_C:
+ case 'c':
+ reset_VIsual_and_resel(); /* stop Visual mode */
+ cmd_with_count("close", cbuf, sizeof(cbuf), Prenum);
+ do_cmdline_cmd(cbuf);
+ break;
+
+#if defined(FEAT_QUICKFIX)
+/* close preview window */
+ case Ctrl_Z:
+ case 'z':
+ CHECK_CMDWIN;
+ reset_VIsual_and_resel(); /* stop Visual mode */
+ do_cmdline_cmd((char_u *)"pclose");
+ break;
+
+/* cursor to preview window */
+ case 'P':
+ FOR_ALL_WINDOWS(wp)
+ if (wp->w_p_pvw)
+ break;
+ if (wp == NULL)
+ emsg(_("E441: There is no preview window"));
+ else
+ win_goto(wp);
+ break;
+#endif
+
+/* close all but current window */
+ case Ctrl_O:
+ case 'o':
+ CHECK_CMDWIN;
+ reset_VIsual_and_resel(); /* stop Visual mode */
+ cmd_with_count("only", cbuf, sizeof(cbuf), Prenum);
+ do_cmdline_cmd(cbuf);
+ break;
+
+/* cursor to next window with wrap around */
+ case Ctrl_W:
+ case 'w':
+/* cursor to previous window with wrap around */
+ case 'W':
+ CHECK_CMDWIN;
+ if (ONE_WINDOW && Prenum != 1) /* just one window */
+ beep_flush();
+ else
+ {
+ if (Prenum) /* go to specified window */
+ {
+ for (wp = firstwin; --Prenum > 0; )
+ {
+ if (wp->w_next == NULL)
+ break;
+ else
+ wp = wp->w_next;
+ }
+ }
+ else
+ {
+ if (nchar == 'W') /* go to previous window */
+ {
+ wp = curwin->w_prev;
+ if (wp == NULL)
+ wp = lastwin; /* wrap around */
+ }
+ else /* go to next window */
+ {
+ wp = curwin->w_next;
+ if (wp == NULL)
+ wp = firstwin; /* wrap around */
+ }
+ }
+ win_goto(wp);
+ }
+ break;
+
+/* cursor to window below */
+ case 'j':
+ case K_DOWN:
+ case Ctrl_J:
+ CHECK_CMDWIN;
+ win_goto_ver(FALSE, Prenum1);
+ break;
+
+/* cursor to window above */
+ case 'k':
+ case K_UP:
+ case Ctrl_K:
+ CHECK_CMDWIN;
+ win_goto_ver(TRUE, Prenum1);
+ break;
+
+/* cursor to left window */
+ case 'h':
+ case K_LEFT:
+ case Ctrl_H:
+ case K_BS:
+ CHECK_CMDWIN;
+ win_goto_hor(TRUE, Prenum1);
+ break;
+
+/* cursor to right window */
+ case 'l':
+ case K_RIGHT:
+ case Ctrl_L:
+ CHECK_CMDWIN;
+ win_goto_hor(FALSE, Prenum1);
+ break;
+
+/* move window to new tab page */
+ case 'T':
+ if (one_window())
+ msg(_(m_onlyone));
+ else
+ {
+ tabpage_T *oldtab = curtab;
+ tabpage_T *newtab;
+
+ /* First create a new tab with the window, then go back to
+ * the old tab and close the window there. */
+ wp = curwin;
+ if (win_new_tabpage((int)Prenum) == OK
+ && valid_tabpage(oldtab))
+ {
+ newtab = curtab;
+ goto_tabpage_tp(oldtab, TRUE, TRUE);
+ if (curwin == wp)
+ win_close(curwin, FALSE);
+ if (valid_tabpage(newtab))
+ goto_tabpage_tp(newtab, TRUE, TRUE);
+ }
+ }
+ break;
+
+/* cursor to top-left window */
+ case 't':
+ case Ctrl_T:
+ win_goto(firstwin);
+ break;
+
+/* cursor to bottom-right window */
+ case 'b':
+ case Ctrl_B:
+ win_goto(lastwin);
+ break;
+
+/* cursor to last accessed (previous) window */
+ case 'p':
+ case Ctrl_P:
+ if (!win_valid(prevwin))
+ beep_flush();
+ else
+ win_goto(prevwin);
+ break;
+
+/* exchange current and next window */
+ case 'x':
+ case Ctrl_X:
+ CHECK_CMDWIN;
+ win_exchange(Prenum);
+ break;
+
+/* rotate windows downwards */
+ case Ctrl_R:
+ case 'r':
+ CHECK_CMDWIN;
+ reset_VIsual_and_resel(); /* stop Visual mode */
+ win_rotate(FALSE, (int)Prenum1); /* downwards */
+ break;
+
+/* rotate windows upwards */
+ case 'R':
+ CHECK_CMDWIN;
+ reset_VIsual_and_resel(); /* stop Visual mode */
+ win_rotate(TRUE, (int)Prenum1); /* upwards */
+ break;
+
+/* move window to the very top/bottom/left/right */
+ case 'K':
+ case 'J':
+ case 'H':
+ case 'L':
+ CHECK_CMDWIN;
+ win_totop((int)Prenum,
+ ((nchar == 'H' || nchar == 'L') ? WSP_VERT : 0)
+ | ((nchar == 'H' || nchar == 'K') ? WSP_TOP : WSP_BOT));
+ break;
+
+/* make all windows the same height */
+ case '=':
+#ifdef FEAT_GUI
+ need_mouse_correct = TRUE;
+#endif
+ win_equal(NULL, FALSE, 'b');
+ break;
+
+/* increase current window height */
+ case '+':
+#ifdef FEAT_GUI
+ need_mouse_correct = TRUE;
+#endif
+ win_setheight(curwin->w_height + (int)Prenum1);
+ break;
+
+/* decrease current window height */
+ case '-':
+#ifdef FEAT_GUI
+ need_mouse_correct = TRUE;
+#endif
+ win_setheight(curwin->w_height - (int)Prenum1);
+ break;
+
+/* set current window height */
+ case Ctrl__:
+ case '_':
+#ifdef FEAT_GUI
+ need_mouse_correct = TRUE;
+#endif
+ win_setheight(Prenum ? (int)Prenum : 9999);
+ break;
+
+/* increase current window width */
+ case '>':
+#ifdef FEAT_GUI
+ need_mouse_correct = TRUE;
+#endif
+ win_setwidth(curwin->w_width + (int)Prenum1);
+ break;
+
+/* decrease current window width */
+ case '<':
+#ifdef FEAT_GUI
+ need_mouse_correct = TRUE;
+#endif
+ win_setwidth(curwin->w_width - (int)Prenum1);
+ break;
+
+/* set current window width */
+ case '|':
+#ifdef FEAT_GUI
+ need_mouse_correct = TRUE;
+#endif
+ win_setwidth(Prenum != 0 ? (int)Prenum : 9999);
+ break;
+
+/* jump to tag and split window if tag exists (in preview window) */
+#if defined(FEAT_QUICKFIX)
+ case '}':
+ CHECK_CMDWIN;
+ if (Prenum)
+ g_do_tagpreview = Prenum;
+ else
+ g_do_tagpreview = p_pvh;
+#endif
+ /* FALLTHROUGH */
+ case ']':
+ case Ctrl_RSB:
+ CHECK_CMDWIN;
+ /* keep Visual mode, can select words to use as a tag */
+ if (Prenum)
+ postponed_split = Prenum;
+ else
+ postponed_split = -1;
+#ifdef FEAT_QUICKFIX
+ if (nchar != '}')
+ g_do_tagpreview = 0;
+#endif
+
+ /* Execute the command right here, required when "wincmd ]"
+ * was used in a function. */
+ do_nv_ident(Ctrl_RSB, NUL);
+ break;
+
+#ifdef FEAT_SEARCHPATH
+/* edit file name under cursor in a new window */
+ case 'f':
+ case 'F':
+ case Ctrl_F:
+wingotofile:
+ CHECK_CMDWIN;
+
+ ptr = grab_file_name(Prenum1, &lnum);
+ if (ptr != NULL)
+ {
+ tabpage_T *oldtab = curtab;
+ win_T *oldwin = curwin;
+# ifdef FEAT_GUI
+ need_mouse_correct = TRUE;
+# endif
+ setpcmark();
+ if (win_split(0, 0) == OK)
+ {
+ RESET_BINDING(curwin);
+ if (do_ecmd(0, ptr, NULL, NULL, ECMD_LASTL,
+ ECMD_HIDE, NULL) == FAIL)
+ {
+ /* Failed to open the file, close the window
+ * opened for it. */
+ win_close(curwin, FALSE);
+ goto_tabpage_win(oldtab, oldwin);
+ }
+ else if (nchar == 'F' && lnum >= 0)
+ {
+ curwin->w_cursor.lnum = lnum;
+ check_cursor_lnum();
+ beginline(BL_SOL | BL_FIX);
+ }
+ }
+ vim_free(ptr);
+ }
+ break;
+#endif
+
+#ifdef FEAT_FIND_ID
+/* Go to the first occurrence of the identifier under cursor along path in a
+ * new window -- webb
+ */
+ case 'i': /* Go to any match */
+ case Ctrl_I:
+ type = FIND_ANY;
+ /* FALLTHROUGH */
+ case 'd': /* Go to definition, using 'define' */
+ case Ctrl_D:
+ CHECK_CMDWIN;
+ if ((len = find_ident_under_cursor(&ptr, FIND_IDENT)) == 0)
+ break;
+ find_pattern_in_path(ptr, 0, len, TRUE,
+ Prenum == 0 ? TRUE : FALSE, type,
+ Prenum1, ACTION_SPLIT, (linenr_T)1, (linenr_T)MAXLNUM);
+ curwin->w_set_curswant = TRUE;
+ break;
+#endif
+
+/* Quickfix window only: view the result under the cursor in a new split. */
+#if defined(FEAT_QUICKFIX)
+ case K_KENTER:
+ case CAR:
+ if (bt_quickfix(curbuf))
+ qf_view_result(TRUE);
+ break;
+#endif
+
+/* CTRL-W g extended commands */
+ case 'g':
+ case Ctrl_G:
+ CHECK_CMDWIN;
+#ifdef USE_ON_FLY_SCROLL
+ dont_scroll = TRUE; /* disallow scrolling here */
+#endif
+ ++no_mapping;
+ ++allow_keys; /* no mapping for xchar, but allow key codes */
+ if (xchar == NUL)
+ xchar = plain_vgetc();
+ LANGMAP_ADJUST(xchar, TRUE);
+ --no_mapping;
+ --allow_keys;
+#ifdef FEAT_CMDL_INFO
+ (void)add_to_showcmd(xchar);
+#endif
+ switch (xchar)
+ {
+#if defined(FEAT_QUICKFIX)
+ case '}':
+ xchar = Ctrl_RSB;
+ if (Prenum)
+ g_do_tagpreview = Prenum;
+ else
+ g_do_tagpreview = p_pvh;
+#endif
+ /* FALLTHROUGH */
+ case ']':
+ case Ctrl_RSB:
+ /* keep Visual mode, can select words to use as a tag */
+ if (Prenum)
+ postponed_split = Prenum;
+ else
+ postponed_split = -1;
+
+ /* Execute the command right here, required when
+ * "wincmd g}" was used in a function. */
+ do_nv_ident('g', xchar);
+ break;
+
+#ifdef FEAT_SEARCHPATH
+ case 'f': /* CTRL-W gf: "gf" in a new tab page */
+ case 'F': /* CTRL-W gF: "gF" in a new tab page */
+ cmdmod.tab = tabpage_index(curtab) + 1;
+ nchar = xchar;
+ goto wingotofile;
+#endif
+ default:
+ beep_flush();
+ break;
+ }
+ break;
+
+ default: beep_flush();
+ break;
+ }
+}
+
+/*
+ * Figure out the address type for ":wnncmd".
+ */
+ void
+get_wincmd_addr_type(char_u *arg, exarg_T *eap)
+{
+ switch (*arg)
+ {
+ case 'S':
+ case Ctrl_S:
+ case 's':
+ case Ctrl_N:
+ case 'n':
+ case 'j':
+ case Ctrl_J:
+ case 'k':
+ case Ctrl_K:
+ case 'T':
+ case Ctrl_R:
+ case 'r':
+ case 'R':
+ case 'K':
+ case 'J':
+ case '+':
+ case '-':
+ case Ctrl__:
+ case '_':
+ case '|':
+ case ']':
+ case Ctrl_RSB:
+ case 'g':
+ case Ctrl_G:
+ case Ctrl_V:
+ case 'v':
+ case 'h':
+ case Ctrl_H:
+ case 'l':
+ case Ctrl_L:
+ case 'H':
+ case 'L':
+ case '>':
+ case '<':
+#if defined(FEAT_QUICKFIX)
+ case '}':
+#endif
+#ifdef FEAT_SEARCHPATH
+ case 'f':
+ case 'F':
+ case Ctrl_F:
+#endif
+#ifdef FEAT_FIND_ID
+ case 'i':
+ case Ctrl_I:
+ case 'd':
+ case Ctrl_D:
+#endif
+ /* window size or any count */
+ eap->addr_type = ADDR_LINES;
+ break;
+
+ case Ctrl_HAT:
+ case '^':
+ /* buffer number */
+ eap->addr_type = ADDR_BUFFERS;
+ break;
+
+ case Ctrl_Q:
+ case 'q':
+ case Ctrl_C:
+ case 'c':
+ case Ctrl_O:
+ case 'o':
+ case Ctrl_W:
+ case 'w':
+ case 'W':
+ case 'x':
+ case Ctrl_X:
+ /* window number */
+ eap->addr_type = ADDR_WINDOWS;
+ break;
+
+#if defined(FEAT_QUICKFIX)
+ case Ctrl_Z:
+ case 'z':
+ case 'P':
+#endif
+ case 't':
+ case Ctrl_T:
+ case 'b':
+ case Ctrl_B:
+ case 'p':
+ case Ctrl_P:
+ case '=':
+ case CAR:
+ /* no count */
+ eap->addr_type = 0;
+ break;
+ }
+}
+
+ static void
+cmd_with_count(
+ char *cmd,
+ char_u *bufp,
+ size_t bufsize,
+ long Prenum)
+{
+ size_t len = STRLEN(cmd);
+
+ STRCPY(bufp, cmd);
+ if (Prenum > 0)
+ vim_snprintf((char *)bufp + len, bufsize - len, "%ld", Prenum);
+}
+
+/*
+ * split the current window, implements CTRL-W s and :split
+ *
+ * "size" is the height or width for the new window, 0 to use half of current
+ * height or width.
+ *
+ * "flags":
+ * WSP_ROOM: require enough room for new window
+ * WSP_VERT: vertical split.
+ * WSP_TOP: open window at the top-left of the shell (help window).
+ * WSP_BOT: open window at the bottom-right of the shell (quickfix window).
+ * WSP_HELP: creating the help window, keep layout snapshot
+ *
+ * return FAIL for failure, OK otherwise
+ */
+ int
+win_split(int size, int flags)
+{
+ /* When the ":tab" modifier was used open a new tab page instead. */
+ if (may_open_tabpage() == OK)
+ return OK;
+
+ /* Add flags from ":vertical", ":topleft" and ":botright". */
+ flags |= cmdmod.split;
+ if ((flags & WSP_TOP) && (flags & WSP_BOT))
+ {
+ emsg(_("E442: Can't split topleft and botright at the same time"));
+ return FAIL;
+ }
+
+ /* When creating the help window make a snapshot of the window layout.
+ * Otherwise clear the snapshot, it's now invalid. */
+ if (flags & WSP_HELP)
+ make_snapshot(SNAP_HELP_IDX);
+ else
+ clear_snapshot(curtab, SNAP_HELP_IDX);
+
+ return win_split_ins(size, flags, NULL, 0);
+}
+
+/*
+ * When "new_wp" is NULL: split the current window in two.
+ * When "new_wp" is not NULL: insert this window at the far
+ * top/left/right/bottom.
+ * return FAIL for failure, OK otherwise
+ */
+ int
+win_split_ins(
+ int size,
+ int flags,
+ win_T *new_wp,
+ int dir)
+{
+ win_T *wp = new_wp;
+ win_T *oldwin;
+ int new_size = size;
+ int i;
+ int need_status = 0;
+ int do_equal = FALSE;
+ int needed;
+ int available;
+ int oldwin_height = 0;
+ int layout;
+ frame_T *frp, *curfrp, *frp2, *prevfrp;
+ int before;
+ int minheight;
+ int wmh1;
+ int did_set_fraction = FALSE;
+
+ if (flags & WSP_TOP)
+ oldwin = firstwin;
+ else if (flags & WSP_BOT)
+ oldwin = lastwin;
+ else
+ oldwin = curwin;
+
+ /* add a status line when p_ls == 1 and splitting the first window */
+ if (ONE_WINDOW && p_ls == 1 && oldwin->w_status_height == 0)
+ {
+ if (VISIBLE_HEIGHT(oldwin) <= p_wmh && new_wp == NULL)
+ {
+ emsg(_(e_noroom));
+ return FAIL;
+ }
+ need_status = STATUS_HEIGHT;
+ }
+
+#ifdef FEAT_GUI
+ /* May be needed for the scrollbars that are going to change. */
+ if (gui.in_use)
+ out_flush();
+#endif
+
+ if (flags & WSP_VERT)
+ {
+ int wmw1;
+ int minwidth;
+
+ layout = FR_ROW;
+
+ /*
+ * Check if we are able to split the current window and compute its
+ * width.
+ */
+ /* Current window requires at least 1 space. */
+ wmw1 = (p_wmw == 0 ? 1 : p_wmw);
+ needed = wmw1 + 1;
+ if (flags & WSP_ROOM)
+ needed += p_wiw - wmw1;
+ if (flags & (WSP_BOT | WSP_TOP))
+ {
+ minwidth = frame_minwidth(topframe, NOWIN);
+ available = topframe->fr_width;
+ needed += minwidth;
+ }
+ else if (p_ea)
+ {
+ minwidth = frame_minwidth(oldwin->w_frame, NOWIN);
+ prevfrp = oldwin->w_frame;
+ for (frp = oldwin->w_frame->fr_parent; frp != NULL;
+ frp = frp->fr_parent)
+ {
+ if (frp->fr_layout == FR_ROW)
+ FOR_ALL_FRAMES(frp2, frp->fr_child)
+ if (frp2 != prevfrp)
+ minwidth += frame_minwidth(frp2, NOWIN);
+ prevfrp = frp;
+ }
+ available = topframe->fr_width;
+ needed += minwidth;
+ }
+ else
+ {
+ minwidth = frame_minwidth(oldwin->w_frame, NOWIN);
+ available = oldwin->w_frame->fr_width;
+ needed += minwidth;
+ }
+ if (available < needed && new_wp == NULL)
+ {
+ emsg(_(e_noroom));
+ return FAIL;
+ }
+ if (new_size == 0)
+ new_size = oldwin->w_width / 2;
+ if (new_size > available - minwidth - 1)
+ new_size = available - minwidth - 1;
+ if (new_size < wmw1)
+ new_size = wmw1;
+
+ /* if it doesn't fit in the current window, need win_equal() */
+ if (oldwin->w_width - new_size - 1 < p_wmw)
+ do_equal = TRUE;
+
+ /* We don't like to take lines for the new window from a
+ * 'winfixwidth' window. Take them from a window to the left or right
+ * instead, if possible. Add one for the separator. */
+ if (oldwin->w_p_wfw)
+ win_setwidth_win(oldwin->w_width + new_size + 1, oldwin);
+
+ /* Only make all windows the same width if one of them (except oldwin)
+ * is wider than one of the split windows. */
+ if (!do_equal && p_ea && size == 0 && *p_ead != 'v'
+ && oldwin->w_frame->fr_parent != NULL)
+ {
+ frp = oldwin->w_frame->fr_parent->fr_child;
+ while (frp != NULL)
+ {
+ if (frp->fr_win != oldwin && frp->fr_win != NULL
+ && (frp->fr_win->w_width > new_size
+ || frp->fr_win->w_width > oldwin->w_width
+ - new_size - 1))
+ {
+ do_equal = TRUE;
+ break;
+ }
+ frp = frp->fr_next;
+ }
+ }
+ }
+ else
+ {
+ layout = FR_COL;
+
+ /*
+ * Check if we are able to split the current window and compute its
+ * height.
+ */
+ /* Current window requires at least 1 space. */
+ wmh1 = (p_wmh == 0 ? 1 : p_wmh) + WINBAR_HEIGHT(curwin);
+ needed = wmh1 + STATUS_HEIGHT;
+ if (flags & WSP_ROOM)
+ needed += p_wh - wmh1;
+ if (flags & (WSP_BOT | WSP_TOP))
+ {
+ minheight = frame_minheight(topframe, NOWIN) + need_status;
+ available = topframe->fr_height;
+ needed += minheight;
+ }
+ else if (p_ea)
+ {
+ minheight = frame_minheight(oldwin->w_frame, NOWIN) + need_status;
+ prevfrp = oldwin->w_frame;
+ for (frp = oldwin->w_frame->fr_parent; frp != NULL;
+ frp = frp->fr_parent)
+ {
+ if (frp->fr_layout == FR_COL)
+ FOR_ALL_FRAMES(frp2, frp->fr_child)
+ if (frp2 != prevfrp)
+ minheight += frame_minheight(frp2, NOWIN);
+ prevfrp = frp;
+ }
+ available = topframe->fr_height;
+ needed += minheight;
+ }
+ else
+ {
+ minheight = frame_minheight(oldwin->w_frame, NOWIN) + need_status;
+ available = oldwin->w_frame->fr_height;
+ needed += minheight;
+ }
+ if (available < needed && new_wp == NULL)
+ {
+ emsg(_(e_noroom));
+ return FAIL;
+ }
+ oldwin_height = oldwin->w_height;
+ if (need_status)
+ {
+ oldwin->w_status_height = STATUS_HEIGHT;
+ oldwin_height -= STATUS_HEIGHT;
+ }
+ if (new_size == 0)
+ new_size = oldwin_height / 2;
+ if (new_size > available - minheight - STATUS_HEIGHT)
+ new_size = available - minheight - STATUS_HEIGHT;
+ if (new_size < wmh1)
+ new_size = wmh1;
+
+ /* if it doesn't fit in the current window, need win_equal() */
+ if (oldwin_height - new_size - STATUS_HEIGHT < p_wmh)
+ do_equal = TRUE;
+
+ /* We don't like to take lines for the new window from a
+ * 'winfixheight' window. Take them from a window above or below
+ * instead, if possible. */
+ if (oldwin->w_p_wfh)
+ {
+ /* Set w_fraction now so that the cursor keeps the same relative
+ * vertical position using the old height. */
+ set_fraction(oldwin);
+ did_set_fraction = TRUE;
+
+ win_setheight_win(oldwin->w_height + new_size + STATUS_HEIGHT,
+ oldwin);
+ oldwin_height = oldwin->w_height;
+ if (need_status)
+ oldwin_height -= STATUS_HEIGHT;
+ }
+
+ /* Only make all windows the same height if one of them (except oldwin)
+ * is higher than one of the split windows. */
+ if (!do_equal && p_ea && size == 0 && *p_ead != 'h'
+ && oldwin->w_frame->fr_parent != NULL)
+ {
+ frp = oldwin->w_frame->fr_parent->fr_child;
+ while (frp != NULL)
+ {
+ if (frp->fr_win != oldwin && frp->fr_win != NULL
+ && (frp->fr_win->w_height > new_size
+ || frp->fr_win->w_height > oldwin_height - new_size
+ - STATUS_HEIGHT))
+ {
+ do_equal = TRUE;
+ break;
+ }
+ frp = frp->fr_next;
+ }
+ }
+ }
+
+ /*
+ * allocate new window structure and link it in the window list
+ */
+ if ((flags & WSP_TOP) == 0
+ && ((flags & WSP_BOT)
+ || (flags & WSP_BELOW)
+ || (!(flags & WSP_ABOVE)
+ && ( (flags & WSP_VERT) ? p_spr : p_sb))))
+ {
+ /* new window below/right of current one */
+ if (new_wp == NULL)
+ wp = win_alloc(oldwin, FALSE);
+ else
+ win_append(oldwin, wp);
+ }
+ else
+ {
+ if (new_wp == NULL)
+ wp = win_alloc(oldwin->w_prev, FALSE);
+ else
+ win_append(oldwin->w_prev, wp);
+ }
+
+ if (new_wp == NULL)
+ {
+ if (wp == NULL)
+ return FAIL;
+
+ new_frame(wp);
+ if (wp->w_frame == NULL)
+ {
+ win_free(wp, NULL);
+ return FAIL;
+ }
+
+ /* make the contents of the new window the same as the current one */
+ win_init(wp, curwin, flags);
+ }
+
+ /*
+ * Reorganise the tree of frames to insert the new window.
+ */
+ if (flags & (WSP_TOP | WSP_BOT))
+ {
+ if ((topframe->fr_layout == FR_COL && (flags & WSP_VERT) == 0)
+ || (topframe->fr_layout == FR_ROW && (flags & WSP_VERT) != 0))
+ {
+ curfrp = topframe->fr_child;
+ if (flags & WSP_BOT)
+ while (curfrp->fr_next != NULL)
+ curfrp = curfrp->fr_next;
+ }
+ else
+ curfrp = topframe;
+ before = (flags & WSP_TOP);
+ }
+ else
+ {
+ curfrp = oldwin->w_frame;
+ if (flags & WSP_BELOW)
+ before = FALSE;
+ else if (flags & WSP_ABOVE)
+ before = TRUE;
+ else if (flags & WSP_VERT)
+ before = !p_spr;
+ else
+ before = !p_sb;
+ }
+ if (curfrp->fr_parent == NULL || curfrp->fr_parent->fr_layout != layout)
+ {
+ /* Need to create a new frame in the tree to make a branch. */
+ frp = (frame_T *)alloc_clear((unsigned)sizeof(frame_T));
+ *frp = *curfrp;
+ curfrp->fr_layout = layout;
+ frp->fr_parent = curfrp;
+ frp->fr_next = NULL;
+ frp->fr_prev = NULL;
+ curfrp->fr_child = frp;
+ curfrp->fr_win = NULL;
+ curfrp = frp;
+ if (frp->fr_win != NULL)
+ oldwin->w_frame = frp;
+ else
+ FOR_ALL_FRAMES(frp, frp->fr_child)
+ frp->fr_parent = curfrp;
+ }
+
+ if (new_wp == NULL)
+ frp = wp->w_frame;
+ else
+ frp = new_wp->w_frame;
+ frp->fr_parent = curfrp->fr_parent;
+
+ /* Insert the new frame at the right place in the frame list. */
+ if (before)
+ frame_insert(curfrp, frp);
+ else
+ frame_append(curfrp, frp);
+
+ /* Set w_fraction now so that the cursor keeps the same relative
+ * vertical position. */
+ if (!did_set_fraction)
+ set_fraction(oldwin);
+ wp->w_fraction = oldwin->w_fraction;
+
+ if (flags & WSP_VERT)
+ {
+ wp->w_p_scr = curwin->w_p_scr;
+
+ if (need_status)
+ {
+ win_new_height(oldwin, oldwin->w_height - 1);
+ oldwin->w_status_height = need_status;
+ }
+ if (flags & (WSP_TOP | WSP_BOT))
+ {
+ /* set height and row of new window to full height */
+ wp->w_winrow = tabline_height();
+ win_new_height(wp, curfrp->fr_height - (p_ls > 0)
+ - WINBAR_HEIGHT(wp));
+ wp->w_status_height = (p_ls > 0);
+ }
+ else
+ {
+ /* height and row of new window is same as current window */
+ wp->w_winrow = oldwin->w_winrow;
+ win_new_height(wp, VISIBLE_HEIGHT(oldwin));
+ wp->w_status_height = oldwin->w_status_height;
+ }
+ frp->fr_height = curfrp->fr_height;
+
+ /* "new_size" of the current window goes to the new window, use
+ * one column for the vertical separator */
+ win_new_width(wp, new_size);
+ if (before)
+ wp->w_vsep_width = 1;
+ else
+ {
+ wp->w_vsep_width = oldwin->w_vsep_width;
+ oldwin->w_vsep_width = 1;
+ }
+ if (flags & (WSP_TOP | WSP_BOT))
+ {
+ if (flags & WSP_BOT)
+ frame_add_vsep(curfrp);
+ /* Set width of neighbor frame */
+ frame_new_width(curfrp, curfrp->fr_width
+ - (new_size + ((flags & WSP_TOP) != 0)), flags & WSP_TOP,
+ FALSE);
+ }
+ else
+ win_new_width(oldwin, oldwin->w_width - (new_size + 1));
+ if (before) /* new window left of current one */
+ {
+ wp->w_wincol = oldwin->w_wincol;
+ oldwin->w_wincol += new_size + 1;
+ }
+ else /* new window right of current one */
+ wp->w_wincol = oldwin->w_wincol + oldwin->w_width + 1;
+ frame_fix_width(oldwin);
+ frame_fix_width(wp);
+ }
+ else
+ {
+ /* width and column of new window is same as current window */
+ if (flags & (WSP_TOP | WSP_BOT))
+ {
+ wp->w_wincol = 0;
+ win_new_width(wp, Columns);
+ wp->w_vsep_width = 0;
+ }
+ else
+ {
+ wp->w_wincol = oldwin->w_wincol;
+ win_new_width(wp, oldwin->w_width);
+ wp->w_vsep_width = oldwin->w_vsep_width;
+ }
+ frp->fr_width = curfrp->fr_width;
+
+ /* "new_size" of the current window goes to the new window, use
+ * one row for the status line */
+ win_new_height(wp, new_size);
+ if (flags & (WSP_TOP | WSP_BOT))
+ {
+ int new_fr_height = curfrp->fr_height - new_size
+ + WINBAR_HEIGHT(wp) ;
+
+ if (!((flags & WSP_BOT) && p_ls == 0))
+ new_fr_height -= STATUS_HEIGHT;
+ frame_new_height(curfrp, new_fr_height, flags & WSP_TOP, FALSE);
+ }
+ else
+ win_new_height(oldwin, oldwin_height - (new_size + STATUS_HEIGHT));
+ if (before) /* new window above current one */
+ {
+ wp->w_winrow = oldwin->w_winrow;
+ wp->w_status_height = STATUS_HEIGHT;
+ oldwin->w_winrow += wp->w_height + STATUS_HEIGHT;
+ }
+ else /* new window below current one */
+ {
+ wp->w_winrow = oldwin->w_winrow + VISIBLE_HEIGHT(oldwin)
+ + STATUS_HEIGHT;
+ wp->w_status_height = oldwin->w_status_height;
+ if (!(flags & WSP_BOT))
+ oldwin->w_status_height = STATUS_HEIGHT;
+ }
+ if (flags & WSP_BOT)
+ frame_add_statusline(curfrp);
+ frame_fix_height(wp);
+ frame_fix_height(oldwin);
+ }
+
+ if (flags & (WSP_TOP | WSP_BOT))
+ (void)win_comp_pos();
+
+ /*
+ * Both windows need redrawing
+ */
+ redraw_win_later(wp, NOT_VALID);
+ wp->w_redr_status = TRUE;
+ redraw_win_later(oldwin, NOT_VALID);
+ oldwin->w_redr_status = TRUE;
+
+ if (need_status)
+ {
+ msg_row = Rows - 1;
+ msg_col = sc_col;
+ msg_clr_eos_force(); /* Old command/ruler may still be there */
+ comp_col();
+ msg_row = Rows - 1;
+ msg_col = 0; /* put position back at start of line */
+ }
+
+ /*
+ * equalize the window sizes.
+ */
+ if (do_equal || dir != 0)
+ win_equal(wp, TRUE,
+ (flags & WSP_VERT) ? (dir == 'v' ? 'b' : 'h')
+ : dir == 'h' ? 'b' : 'v');
+
+ /* Don't change the window height/width to 'winheight' / 'winwidth' if a
+ * size was given. */
+ if (flags & WSP_VERT)
+ {
+ i = p_wiw;
+ if (size != 0)
+ p_wiw = size;
+
+# ifdef FEAT_GUI
+ /* When 'guioptions' includes 'L' or 'R' may have to add scrollbars. */
+ if (gui.in_use)
+ gui_init_which_components(NULL);
+# endif
+ }
+ else
+ {
+ i = p_wh;
+ if (size != 0)
+ p_wh = size;
+ }
+
+#ifdef FEAT_JUMPLIST
+ /* Keep same changelist position in new window. */
+ wp->w_changelistidx = oldwin->w_changelistidx;
+#endif
+
+ /*
+ * make the new window the current window
+ */
+ win_enter_ext(wp, FALSE, FALSE, TRUE, TRUE, TRUE);
+ if (flags & WSP_VERT)
+ p_wiw = i;
+ else
+ p_wh = i;
+
+ return OK;
+}
+
+
+/*
+ * Initialize window "newp" from window "oldp".
+ * Used when splitting a window and when creating a new tab page.
+ * The windows will both edit the same buffer.
+ * WSP_NEWLOC may be specified in flags to prevent the location list from
+ * being copied.
+ */
+ static void
+win_init(win_T *newp, win_T *oldp, int flags UNUSED)
+{
+ int i;
+
+ newp->w_buffer = oldp->w_buffer;
+#ifdef FEAT_SYN_HL
+ newp->w_s = &(oldp->w_buffer->b_s);
+#endif
+ oldp->w_buffer->b_nwindows++;
+ newp->w_cursor = oldp->w_cursor;
+ newp->w_valid = 0;
+ newp->w_curswant = oldp->w_curswant;
+ newp->w_set_curswant = oldp->w_set_curswant;
+ newp->w_topline = oldp->w_topline;
+#ifdef FEAT_DIFF
+ newp->w_topfill = oldp->w_topfill;
+#endif
+ newp->w_leftcol = oldp->w_leftcol;
+ newp->w_pcmark = oldp->w_pcmark;
+ newp->w_prev_pcmark = oldp->w_prev_pcmark;
+ newp->w_alt_fnum = oldp->w_alt_fnum;
+ newp->w_wrow = oldp->w_wrow;
+ newp->w_fraction = oldp->w_fraction;
+ newp->w_prev_fraction_row = oldp->w_prev_fraction_row;
+#ifdef FEAT_JUMPLIST
+ copy_jumplist(oldp, newp);
+#endif
+#ifdef FEAT_QUICKFIX
+ if (flags & WSP_NEWLOC)
+ {
+ /* Don't copy the location list. */
+ newp->w_llist = NULL;
+ newp->w_llist_ref = NULL;
+ }
+ else
+ copy_loclist_stack(oldp, newp);
+#endif
+ newp->w_localdir = (oldp->w_localdir == NULL)
+ ? NULL : vim_strsave(oldp->w_localdir);
+
+ /* copy tagstack and folds */
+ for (i = 0; i < oldp->w_tagstacklen; i++)
+ {
+ newp->w_tagstack[i] = oldp->w_tagstack[i];
+ if (newp->w_tagstack[i].tagname != NULL)
+ newp->w_tagstack[i].tagname =
+ vim_strsave(newp->w_tagstack[i].tagname);
+ }
+ newp->w_tagstackidx = oldp->w_tagstackidx;
+ newp->w_tagstacklen = oldp->w_tagstacklen;
+#ifdef FEAT_FOLDING
+ copyFoldingState(oldp, newp);
+#endif
+
+ win_init_some(newp, oldp);
+
+#ifdef FEAT_SYN_HL
+ check_colorcolumn(newp);
+#endif
+}
+
+/*
+ * Initialize window "newp" from window "old".
+ * Only the essential things are copied.
+ */
+ static void
+win_init_some(win_T *newp, win_T *oldp)
+{
+ /* Use the same argument list. */
+ newp->w_alist = oldp->w_alist;
+ ++newp->w_alist->al_refcount;
+ newp->w_arg_idx = oldp->w_arg_idx;
+
+ /* copy options from existing window */
+ win_copy_options(oldp, newp);
+}
+
+
+/*
+ * Check if "win" is a pointer to an existing window in the current tab page.
+ */
+ int
+win_valid(win_T *win)
+{
+ win_T *wp;
+
+ if (win == NULL)
+ return FALSE;
+ FOR_ALL_WINDOWS(wp)
+ if (wp == win)
+ return TRUE;
+ return FALSE;
+}
+
+/*
+ * Check if "win" is a pointer to an existing window in any tab page.
+ */
+ int
+win_valid_any_tab(win_T *win)
+{
+ win_T *wp;
+ tabpage_T *tp;
+
+ if (win == NULL)
+ return FALSE;
+ FOR_ALL_TABPAGES(tp)
+ {
+ FOR_ALL_WINDOWS_IN_TAB(tp, wp)
+ {
+ if (wp == win)
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/*
+ * Return the number of windows.
+ */
+ int
+win_count(void)
+{
+ win_T *wp;
+ int count = 0;
+
+ FOR_ALL_WINDOWS(wp)
+ ++count;
+ return count;
+}
+
+/*
+ * Make "count" windows on the screen.
+ * Return actual number of windows on the screen.
+ * Must be called when there is just one window, filling the whole screen
+ * (excluding the command line).
+ */
+ int
+make_windows(
+ int count,
+ int vertical UNUSED) /* split windows vertically if TRUE */
+{
+ int maxcount;
+ int todo;
+
+ if (vertical)
+ {
+ /* Each windows needs at least 'winminwidth' lines and a separator
+ * column. */
+ maxcount = (curwin->w_width + curwin->w_vsep_width
+ - (p_wiw - p_wmw)) / (p_wmw + 1);
+ }
+ else
+ {
+ /* Each window needs at least 'winminheight' lines and a status line. */
+ maxcount = (VISIBLE_HEIGHT(curwin) + curwin->w_status_height
+ - (p_wh - p_wmh)) / (p_wmh + STATUS_HEIGHT);
+ }
+
+ if (maxcount < 2)
+ maxcount = 2;
+ if (count > maxcount)
+ count = maxcount;
+
+ /*
+ * add status line now, otherwise first window will be too big
+ */
+ if (count > 1)
+ last_status(TRUE);
+
+ /*
+ * Don't execute autocommands while creating the windows. Must do that
+ * when putting the buffers in the windows.
+ */
+ block_autocmds();
+
+ /* todo is number of windows left to create */
+ for (todo = count - 1; todo > 0; --todo)
+ if (vertical)
+ {
+ if (win_split(curwin->w_width - (curwin->w_width - todo)
+ / (todo + 1) - 1, WSP_VERT | WSP_ABOVE) == FAIL)
+ break;
+ }
+ else
+ {
+ if (win_split(curwin->w_height - (curwin->w_height - todo
+ * STATUS_HEIGHT) / (todo + 1)
+ - STATUS_HEIGHT, WSP_ABOVE) == FAIL)
+ break;
+ }
+
+ unblock_autocmds();
+
+ /* return actual number of windows */
+ return (count - todo);
+}
+
+/*
+ * Exchange current and next window
+ */
+ static void
+win_exchange(long Prenum)
+{
+ frame_T *frp;
+ frame_T *frp2;
+ win_T *wp;
+ win_T *wp2;
+ int temp;
+
+ if (ONE_WINDOW) /* just one window */
+ {
+ beep_flush();
+ return;
+ }
+
+#ifdef FEAT_GUI
+ need_mouse_correct = TRUE;
+#endif
+
+ /*
+ * find window to exchange with
+ */
+ if (Prenum)
+ {
+ frp = curwin->w_frame->fr_parent->fr_child;
+ while (frp != NULL && --Prenum > 0)
+ frp = frp->fr_next;
+ }
+ else if (curwin->w_frame->fr_next != NULL) /* Swap with next */
+ frp = curwin->w_frame->fr_next;
+ else /* Swap last window in row/col with previous */
+ frp = curwin->w_frame->fr_prev;
+
+ /* We can only exchange a window with another window, not with a frame
+ * containing windows. */
+ if (frp == NULL || frp->fr_win == NULL || frp->fr_win == curwin)
+ return;
+ wp = frp->fr_win;
+
+/*
+ * 1. remove curwin from the list. Remember after which window it was in wp2
+ * 2. insert curwin before wp in the list
+ * if wp != wp2
+ * 3. remove wp from the list
+ * 4. insert wp after wp2
+ * 5. exchange the status line height and vsep width.
+ */
+ wp2 = curwin->w_prev;
+ frp2 = curwin->w_frame->fr_prev;
+ if (wp->w_prev != curwin)
+ {
+ win_remove(curwin, NULL);
+ frame_remove(curwin->w_frame);
+ win_append(wp->w_prev, curwin);
+ frame_insert(frp, curwin->w_frame);
+ }
+ if (wp != wp2)
+ {
+ win_remove(wp, NULL);
+ frame_remove(wp->w_frame);
+ win_append(wp2, wp);
+ if (frp2 == NULL)
+ frame_insert(wp->w_frame->fr_parent->fr_child, wp->w_frame);
+ else
+ frame_append(frp2, wp->w_frame);
+ }
+ temp = curwin->w_status_height;
+ curwin->w_status_height = wp->w_status_height;
+ wp->w_status_height = temp;
+ temp = curwin->w_vsep_width;
+ curwin->w_vsep_width = wp->w_vsep_width;
+ wp->w_vsep_width = temp;
+
+ /* If the windows are not in the same frame, exchange the sizes to avoid
+ * messing up the window layout. Otherwise fix the frame sizes. */
+ if (curwin->w_frame->fr_parent != wp->w_frame->fr_parent)
+ {
+ temp = curwin->w_height;
+ curwin->w_height = wp->w_height;
+ wp->w_height = temp;
+ temp = curwin->w_width;
+ curwin->w_width = wp->w_width;
+ wp->w_width = temp;
+ }
+ else
+ {
+ frame_fix_height(curwin);
+ frame_fix_height(wp);
+ frame_fix_width(curwin);
+ frame_fix_width(wp);
+ }
+
+ (void)win_comp_pos(); /* recompute window positions */
+
+ win_enter(wp, TRUE);
+ redraw_all_later(NOT_VALID);
+}
+
+/*
+ * rotate windows: if upwards TRUE the second window becomes the first one
+ * if upwards FALSE the first window becomes the second one
+ */
+ static void
+win_rotate(int upwards, int count)
+{
+ win_T *wp1;
+ win_T *wp2;
+ frame_T *frp;
+ int n;
+
+ if (ONE_WINDOW) /* nothing to do */
+ {
+ beep_flush();
+ return;
+ }
+
+#ifdef FEAT_GUI
+ need_mouse_correct = TRUE;
+#endif
+
+ /* Check if all frames in this row/col have one window. */
+ FOR_ALL_FRAMES(frp, curwin->w_frame->fr_parent->fr_child)
+ if (frp->fr_win == NULL)
+ {
+ emsg(_("E443: Cannot rotate when another window is split"));
+ return;
+ }
+
+ while (count--)
+ {
+ if (upwards) /* first window becomes last window */
+ {
+ /* remove first window/frame from the list */
+ frp = curwin->w_frame->fr_parent->fr_child;
+ wp1 = frp->fr_win;
+ win_remove(wp1, NULL);
+ frame_remove(frp);
+
+ /* find last frame and append removed window/frame after it */
+ for ( ; frp->fr_next != NULL; frp = frp->fr_next)
+ ;
+ win_append(frp->fr_win, wp1);
+ frame_append(frp, wp1->w_frame);
+
+ wp2 = frp->fr_win; /* previously last window */
+ }
+ else /* last window becomes first window */
+ {
+ /* find last window/frame in the list and remove it */
+ for (frp = curwin->w_frame; frp->fr_next != NULL;
+ frp = frp->fr_next)
+ ;
+ wp1 = frp->fr_win;
+ wp2 = wp1->w_prev; /* will become last window */
+ win_remove(wp1, NULL);
+ frame_remove(frp);
+
+ /* append the removed window/frame before the first in the list */
+ win_append(frp->fr_parent->fr_child->fr_win->w_prev, wp1);
+ frame_insert(frp->fr_parent->fr_child, frp);
+ }
+
+ /* exchange status height and vsep width of old and new last window */
+ n = wp2->w_status_height;
+ wp2->w_status_height = wp1->w_status_height;
+ wp1->w_status_height = n;
+ frame_fix_height(wp1);
+ frame_fix_height(wp2);
+ n = wp2->w_vsep_width;
+ wp2->w_vsep_width = wp1->w_vsep_width;
+ wp1->w_vsep_width = n;
+ frame_fix_width(wp1);
+ frame_fix_width(wp2);
+
+ /* recompute w_winrow and w_wincol for all windows */
+ (void)win_comp_pos();
+ }
+
+ redraw_all_later(NOT_VALID);
+}
+
+/*
+ * Move the current window to the very top/bottom/left/right of the screen.
+ */
+ static void
+win_totop(int size, int flags)
+{
+ int dir;
+ int height = curwin->w_height;
+
+ if (ONE_WINDOW)
+ {
+ beep_flush();
+ return;
+ }
+
+ /* Remove the window and frame from the tree of frames. */
+ (void)winframe_remove(curwin, &dir, NULL);
+ win_remove(curwin, NULL);
+ last_status(FALSE); /* may need to remove last status line */
+ (void)win_comp_pos(); /* recompute window positions */
+
+ /* Split a window on the desired side and put the window there. */
+ (void)win_split_ins(size, flags, curwin, dir);
+ if (!(flags & WSP_VERT))
+ {
+ win_setheight(height);
+ if (p_ea)
+ win_equal(curwin, TRUE, 'v');
+ }
+
+#if defined(FEAT_GUI)
+ /* When 'guioptions' includes 'L' or 'R' may have to remove or add
+ * scrollbars. Have to update them anyway. */
+ gui_may_update_scrollbars();
+#endif
+}
+
+/*
+ * Move window "win1" to below/right of "win2" and make "win1" the current
+ * window. Only works within the same frame!
+ */
+ void
+win_move_after(win_T *win1, win_T *win2)
+{
+ int height;
+
+ /* check if the arguments are reasonable */
+ if (win1 == win2)
+ return;
+
+ /* check if there is something to do */
+ if (win2->w_next != win1)
+ {
+ /* may need move the status line/vertical separator of the last window
+ * */
+ if (win1 == lastwin)
+ {
+ height = win1->w_prev->w_status_height;
+ win1->w_prev->w_status_height = win1->w_status_height;
+ win1->w_status_height = height;
+ if (win1->w_prev->w_vsep_width == 1)
+ {
+ /* Remove the vertical separator from the last-but-one window,
+ * add it to the last window. Adjust the frame widths. */
+ win1->w_prev->w_vsep_width = 0;
+ win1->w_prev->w_frame->fr_width -= 1;
+ win1->w_vsep_width = 1;
+ win1->w_frame->fr_width += 1;
+ }
+ }
+ else if (win2 == lastwin)
+ {
+ height = win1->w_status_height;
+ win1->w_status_height = win2->w_status_height;
+ win2->w_status_height = height;
+ if (win1->w_vsep_width == 1)
+ {
+ /* Remove the vertical separator from win1, add it to the last
+ * window, win2. Adjust the frame widths. */
+ win2->w_vsep_width = 1;
+ win2->w_frame->fr_width += 1;
+ win1->w_vsep_width = 0;
+ win1->w_frame->fr_width -= 1;
+ }
+ }
+ win_remove(win1, NULL);
+ frame_remove(win1->w_frame);
+ win_append(win2, win1);
+ frame_append(win2->w_frame, win1->w_frame);
+
+ (void)win_comp_pos(); /* recompute w_winrow for all windows */
+ redraw_later(NOT_VALID);
+ }
+ win_enter(win1, FALSE);
+}
+
+/*
+ * Make all windows the same height.
+ * 'next_curwin' will soon be the current window, make sure it has enough
+ * rows.
+ */
+ void
+win_equal(
+ win_T *next_curwin, /* pointer to current window to be or NULL */
+ int current, /* do only frame with current window */
+ int dir) /* 'v' for vertically, 'h' for horizontally,
+ 'b' for both, 0 for using p_ead */
+{
+ if (dir == 0)
+ dir = *p_ead;
+ win_equal_rec(next_curwin == NULL ? curwin : next_curwin, current,
+ topframe, dir, 0, tabline_height(),
+ (int)Columns, topframe->fr_height);
+}
+
+/*
+ * Set a frame to a new position and height, spreading the available room
+ * equally over contained frames.
+ * The window "next_curwin" (if not NULL) should at least get the size from
+ * 'winheight' and 'winwidth' if possible.
+ */
+ static void
+win_equal_rec(
+ win_T *next_curwin, /* pointer to current window to be or NULL */
+ int current, /* do only frame with current window */
+ frame_T *topfr, /* frame to set size off */
+ int dir, /* 'v', 'h' or 'b', see win_equal() */
+ int col, /* horizontal position for frame */
+ int row, /* vertical position for frame */
+ int width, /* new width of frame */
+ int height) /* new height of frame */
+{
+ int n, m;
+ int extra_sep = 0;
+ int wincount, totwincount = 0;
+ frame_T *fr;
+ int next_curwin_size = 0;
+ int room = 0;
+ int new_size;
+ int has_next_curwin = 0;
+ int hnc;
+
+ if (topfr->fr_layout == FR_LEAF)
+ {
+ /* Set the width/height of this frame.
+ * Redraw when size or position changes */
+ if (topfr->fr_height != height || topfr->fr_win->w_winrow != row
+ || topfr->fr_width != width || topfr->fr_win->w_wincol != col
+ )
+ {
+ topfr->fr_win->w_winrow = row;
+ frame_new_height(topfr, height, FALSE, FALSE);
+ topfr->fr_win->w_wincol = col;
+ frame_new_width(topfr, width, FALSE, FALSE);
+ redraw_all_later(NOT_VALID);
+ }
+ }
+ else if (topfr->fr_layout == FR_ROW)
+ {
+ topfr->fr_width = width;
+ topfr->fr_height = height;
+
+ if (dir != 'v') /* equalize frame widths */
+ {
+ /* Compute the maximum number of windows horizontally in this
+ * frame. */
+ n = frame_minwidth(topfr, NOWIN);
+ /* add one for the rightmost window, it doesn't have a separator */
+ if (col + width == Columns)
+ extra_sep = 1;
+ else
+ extra_sep = 0;
+ totwincount = (n + extra_sep) / (p_wmw + 1);
+ has_next_curwin = frame_has_win(topfr, next_curwin);
+
+ /*
+ * Compute width for "next_curwin" window and room available for
+ * other windows.
+ * "m" is the minimal width when counting p_wiw for "next_curwin".
+ */
+ m = frame_minwidth(topfr, next_curwin);
+ room = width - m;
+ if (room < 0)
+ {
+ next_curwin_size = p_wiw + room;
+ room = 0;
+ }
+ else
+ {
+ next_curwin_size = -1;
+ FOR_ALL_FRAMES(fr, topfr->fr_child)
+ {
+ /* If 'winfixwidth' set keep the window width if
+ * possible.
+ * Watch out for this window being the next_curwin. */
+ if (frame_fixed_width(fr))
+ {
+ n = frame_minwidth(fr, NOWIN);
+ new_size = fr->fr_width;
+ if (frame_has_win(fr, next_curwin))
+ {
+ room += p_wiw - p_wmw;
+ next_curwin_size = 0;
+ if (new_size < p_wiw)
+ new_size = p_wiw;
+ }
+ else
+ /* These windows don't use up room. */
+ totwincount -= (n + (fr->fr_next == NULL
+ ? extra_sep : 0)) / (p_wmw + 1);
+ room -= new_size - n;
+ if (room < 0)
+ {
+ new_size += room;
+ room = 0;
+ }
+ fr->fr_newwidth = new_size;
+ }
+ }
+ if (next_curwin_size == -1)
+ {
+ if (!has_next_curwin)
+ next_curwin_size = 0;
+ else if (totwincount > 1
+ && (room + (totwincount - 2))
+ / (totwincount - 1) > p_wiw)
+ {
+ /* Can make all windows wider than 'winwidth', spread
+ * the room equally. */
+ next_curwin_size = (room + p_wiw
+ + (totwincount - 1) * p_wmw
+ + (totwincount - 1)) / totwincount;
+ room -= next_curwin_size - p_wiw;
+ }
+ else
+ next_curwin_size = p_wiw;
+ }
+ }
+
+ if (has_next_curwin)
+ --totwincount; /* don't count curwin */
+ }
+
+ FOR_ALL_FRAMES(fr, topfr->fr_child)
+ {
+ wincount = 1;
+ if (fr->fr_next == NULL)
+ /* last frame gets all that remains (avoid roundoff error) */
+ new_size = width;
+ else if (dir == 'v')
+ new_size = fr->fr_width;
+ else if (frame_fixed_width(fr))
+ {
+ new_size = fr->fr_newwidth;
+ wincount = 0; /* doesn't count as a sizeable window */
+ }
+ else
+ {
+ /* Compute the maximum number of windows horiz. in "fr". */
+ n = frame_minwidth(fr, NOWIN);
+ wincount = (n + (fr->fr_next == NULL ? extra_sep : 0))
+ / (p_wmw + 1);
+ m = frame_minwidth(fr, next_curwin);
+ if (has_next_curwin)
+ hnc = frame_has_win(fr, next_curwin);
+ else
+ hnc = FALSE;
+ if (hnc) /* don't count next_curwin */
+ --wincount;
+ if (totwincount == 0)
+ new_size = room;
+ else
+ new_size = (wincount * room + ((unsigned)totwincount >> 1))
+ / totwincount;
+ if (hnc) /* add next_curwin size */
+ {
+ next_curwin_size -= p_wiw - (m - n);
+ new_size += next_curwin_size;
+ room -= new_size - next_curwin_size;
+ }
+ else
+ room -= new_size;
+ new_size += n;
+ }
+
+ /* Skip frame that is full width when splitting or closing a
+ * window, unless equalizing all frames. */
+ if (!current || dir != 'v' || topfr->fr_parent != NULL
+ || (new_size != fr->fr_width)
+ || frame_has_win(fr, next_curwin))
+ win_equal_rec(next_curwin, current, fr, dir, col, row,
+ new_size, height);
+ col += new_size;
+ width -= new_size;
+ totwincount -= wincount;
+ }
+ }
+ else /* topfr->fr_layout == FR_COL */
+ {
+ topfr->fr_width = width;
+ topfr->fr_height = height;
+
+ if (dir != 'h') /* equalize frame heights */
+ {
+ /* Compute maximum number of windows vertically in this frame. */
+ n = frame_minheight(topfr, NOWIN);
+ /* add one for the bottom window if it doesn't have a statusline */
+ if (row + height == cmdline_row && p_ls == 0)
+ extra_sep = 1;
+ else
+ extra_sep = 0;
+ totwincount = (n + extra_sep) / (p_wmh + 1);
+ has_next_curwin = frame_has_win(topfr, next_curwin);
+
+ /*
+ * Compute height for "next_curwin" window and room available for
+ * other windows.
+ * "m" is the minimal height when counting p_wh for "next_curwin".
+ */
+ m = frame_minheight(topfr, next_curwin);
+ room = height - m;
+ if (room < 0)
+ {
+ /* The room is less then 'winheight', use all space for the
+ * current window. */
+ next_curwin_size = p_wh + room;
+ room = 0;
+ }
+ else
+ {
+ next_curwin_size = -1;
+ FOR_ALL_FRAMES(fr, topfr->fr_child)
+ {
+ /* If 'winfixheight' set keep the window height if
+ * possible.
+ * Watch out for this window being the next_curwin. */
+ if (frame_fixed_height(fr))
+ {
+ n = frame_minheight(fr, NOWIN);
+ new_size = fr->fr_height;
+ if (frame_has_win(fr, next_curwin))
+ {
+ room += p_wh - p_wmh;
+ next_curwin_size = 0;
+ if (new_size < p_wh)
+ new_size = p_wh;
+ }
+ else
+ /* These windows don't use up room. */
+ totwincount -= (n + (fr->fr_next == NULL
+ ? extra_sep : 0)) / (p_wmh + 1);
+ room -= new_size - n;
+ if (room < 0)
+ {
+ new_size += room;
+ room = 0;
+ }
+ fr->fr_newheight = new_size;
+ }
+ }
+ if (next_curwin_size == -1)
+ {
+ if (!has_next_curwin)
+ next_curwin_size = 0;
+ else if (totwincount > 1
+ && (room + (totwincount - 2))
+ / (totwincount - 1) > p_wh)
+ {
+ /* can make all windows higher than 'winheight',
+ * spread the room equally. */
+ next_curwin_size = (room + p_wh
+ + (totwincount - 1) * p_wmh
+ + (totwincount - 1)) / totwincount;
+ room -= next_curwin_size - p_wh;
+ }
+ else
+ next_curwin_size = p_wh;
+ }
+ }
+
+ if (has_next_curwin)
+ --totwincount; /* don't count curwin */
+ }
+
+ FOR_ALL_FRAMES(fr, topfr->fr_child)
+ {
+ wincount = 1;
+ if (fr->fr_next == NULL)
+ /* last frame gets all that remains (avoid roundoff error) */
+ new_size = height;
+ else if (dir == 'h')
+ new_size = fr->fr_height;
+ else if (frame_fixed_height(fr))
+ {
+ new_size = fr->fr_newheight;
+ wincount = 0; /* doesn't count as a sizeable window */
+ }
+ else
+ {
+ /* Compute the maximum number of windows vert. in "fr". */
+ n = frame_minheight(fr, NOWIN);
+ wincount = (n + (fr->fr_next == NULL ? extra_sep : 0))
+ / (p_wmh + 1);
+ m = frame_minheight(fr, next_curwin);
+ if (has_next_curwin)
+ hnc = frame_has_win(fr, next_curwin);
+ else
+ hnc = FALSE;
+ if (hnc) /* don't count next_curwin */
+ --wincount;
+ if (totwincount == 0)
+ new_size = room;
+ else
+ new_size = (wincount * room + ((unsigned)totwincount >> 1))
+ / totwincount;
+ if (hnc) /* add next_curwin size */
+ {
+ next_curwin_size -= p_wh - (m - n);
+ new_size += next_curwin_size;
+ room -= new_size - next_curwin_size;
+ }
+ else
+ room -= new_size;
+ new_size += n;
+ }
+ /* Skip frame that is full width when splitting or closing a
+ * window, unless equalizing all frames. */
+ if (!current || dir != 'h' || topfr->fr_parent != NULL
+ || (new_size != fr->fr_height)
+ || frame_has_win(fr, next_curwin))
+ win_equal_rec(next_curwin, current, fr, dir, col, row,
+ width, new_size);
+ row += new_size;
+ height -= new_size;
+ totwincount -= wincount;
+ }
+ }
+}
+
+#ifdef FEAT_JOB_CHANNEL
+ static void
+leaving_window(win_T *win)
+{
+ // Only matters for a prompt window.
+ if (!bt_prompt(win->w_buffer))
+ return;
+
+ // When leaving a prompt window stop Insert mode and perhaps restart
+ // it when entering that window again.
+ win->w_buffer->b_prompt_insert = restart_edit;
+ if (restart_edit != 0 && mode_displayed)
+ clear_cmdline = TRUE; /* unshow mode later */
+ restart_edit = NUL;
+
+ // When leaving the window (or closing the window) was done from a
+ // callback we need to break out of the Insert mode loop and restart Insert
+ // mode when entering the window again.
+ if (State & INSERT)
+ {
+ stop_insert_mode = TRUE;
+ if (win->w_buffer->b_prompt_insert == NUL)
+ win->w_buffer->b_prompt_insert = 'A';
+ }
+}
+
+ static void
+entering_window(win_T *win)
+{
+ // Only matters for a prompt window.
+ if (!bt_prompt(win->w_buffer))
+ return;
+
+ // When switching to a prompt buffer that was in Insert mode, don't stop
+ // Insert mode, it may have been set in leaving_window().
+ if (win->w_buffer->b_prompt_insert != NUL)
+ stop_insert_mode = FALSE;
+
+ // When entering the prompt window restart Insert mode if we were in Insert
+ // mode when we left it.
+ restart_edit = win->w_buffer->b_prompt_insert;
+}
+#endif
+
+/*
+ * Close all windows for buffer "buf".
+ */
+ void
+close_windows(
+ buf_T *buf,
+ int keep_curwin) /* don't close "curwin" */
+{
+ win_T *wp;
+ tabpage_T *tp, *nexttp;
+ int h = tabline_height();
+ int count = tabpage_index(NULL);
+
+ ++RedrawingDisabled;
+
+ for (wp = firstwin; wp != NULL && !ONE_WINDOW; )
+ {
+ if (wp->w_buffer == buf && (!keep_curwin || wp != curwin)
+ && !(wp->w_closing || wp->w_buffer->b_locked > 0))
+ {
+ if (win_close(wp, FALSE) == FAIL)
+ /* If closing the window fails give up, to avoid looping
+ * forever. */
+ break;
+
+ /* Start all over, autocommands may change the window layout. */
+ wp = firstwin;
+ }
+ else
+ wp = wp->w_next;
+ }
+
+ /* Also check windows in other tab pages. */
+ for (tp = first_tabpage; tp != NULL; tp = nexttp)
+ {
+ nexttp = tp->tp_next;
+ if (tp != curtab)
+ for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next)
+ if (wp->w_buffer == buf
+ && !(wp->w_closing || wp->w_buffer->b_locked > 0))
+ {
+ win_close_othertab(wp, FALSE, tp);
+
+ /* Start all over, the tab page may be closed and
+ * autocommands may change the window layout. */
+ nexttp = first_tabpage;
+ break;
+ }
+ }
+
+ --RedrawingDisabled;
+
+ if (count != tabpage_index(NULL))
+ apply_autocmds(EVENT_TABCLOSED, NULL, NULL, FALSE, curbuf);
+
+ redraw_tabline = TRUE;
+ if (h != tabline_height())
+ shell_new_rows();
+}
+
+/*
+ * Return TRUE if the current window is the only window that exists (ignoring
+ * "aucmd_win").
+ * Returns FALSE if there is a window, possibly in another tab page.
+ */
+ static int
+last_window(void)
+{
+ return (one_window() && first_tabpage->tp_next == NULL);
+}
+
+/*
+ * Return TRUE if there is only one window other than "aucmd_win" in the
+ * current tab page.
+ */
+ int
+one_window(void)
+{
+ win_T *wp;
+ int seen_one = FALSE;
+
+ FOR_ALL_WINDOWS(wp)
+ {
+ if (wp != aucmd_win)
+ {
+ if (seen_one)
+ return FALSE;
+ seen_one = TRUE;
+ }
+ }
+ return TRUE;
+}
+
+/*
+ * Close the possibly last window in a tab page.
+ * Returns TRUE when the window was closed already.
+ */
+ static int
+close_last_window_tabpage(
+ win_T *win,
+ int free_buf,
+ tabpage_T *prev_curtab)
+{
+ if (ONE_WINDOW)
+ {
+ buf_T *old_curbuf = curbuf;
+
+ /*
+ * Closing the last window in a tab page. First go to another tab
+ * page and then close the window and the tab page. This avoids that
+ * curwin and curtab are invalid while we are freeing memory, they may
+ * be used in GUI events.
+ * Don't trigger autocommands yet, they may use wrong values, so do
+ * that below.
+ */
+ goto_tabpage_tp(alt_tabpage(), FALSE, TRUE);
+ redraw_tabline = TRUE;
+
+ /* Safety check: Autocommands may have closed the window when jumping
+ * to the other tab page. */
+ if (valid_tabpage(prev_curtab) && prev_curtab->tp_firstwin == win)
+ {
+ int h = tabline_height();
+
+ win_close_othertab(win, free_buf, prev_curtab);
+ if (h != tabline_height())
+ shell_new_rows();
+ }
+#ifdef FEAT_JOB_CHANNEL
+ entering_window(curwin);
+#endif
+ /* Since goto_tabpage_tp above did not trigger *Enter autocommands, do
+ * that now. */
+ apply_autocmds(EVENT_TABCLOSED, NULL, NULL, FALSE, curbuf);
+ apply_autocmds(EVENT_WINENTER, NULL, NULL, FALSE, curbuf);
+ apply_autocmds(EVENT_TABENTER, NULL, NULL, FALSE, curbuf);
+ if (old_curbuf != curbuf)
+ apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * Close window "win". Only works for the current tab page.
+ * If "free_buf" is TRUE related buffer may be unloaded.
+ *
+ * Called by :quit, :close, :xit, :wq and findtag().
+ * Returns FAIL when the window was not closed.
+ */
+ int
+win_close(win_T *win, int free_buf)
+{
+ win_T *wp;
+ int other_buffer = FALSE;
+ int close_curwin = FALSE;
+ int dir;
+ int help_window = FALSE;
+ tabpage_T *prev_curtab = curtab;
+ frame_T *win_frame = win->w_frame->fr_parent;
+
+ if (last_window())
+ {
+ emsg(_("E444: Cannot close last window"));
+ return FAIL;
+ }
+
+ if (win->w_closing || (win->w_buffer != NULL
+ && win->w_buffer->b_locked > 0))
+ return FAIL; /* window is already being closed */
+ if (win == aucmd_win)
+ {
+ emsg(_("E813: Cannot close autocmd window"));
+ return FAIL;
+ }
+ if ((firstwin == aucmd_win || lastwin == aucmd_win) && one_window())
+ {
+ emsg(_("E814: Cannot close window, only autocmd window would remain"));
+ return FAIL;
+ }
+
+ /* When closing the last window in a tab page first go to another tab page
+ * and then close the window and the tab page to avoid that curwin and
+ * curtab are invalid while we are freeing memory. */
+ if (close_last_window_tabpage(win, free_buf, prev_curtab))
+ return FAIL;
+
+ /* When closing the help window, try restoring a snapshot after closing
+ * the window. Otherwise clear the snapshot, it's now invalid. */
+ if (bt_help(win->w_buffer))
+ help_window = TRUE;
+ else
+ clear_snapshot(curtab, SNAP_HELP_IDX);
+
+ if (win == curwin)
+ {
+#ifdef FEAT_JOB_CHANNEL
+ leaving_window(curwin);
+#endif
+ /*
+ * Guess which window is going to be the new current window.
+ * This may change because of the autocommands (sigh).
+ */
+ wp = frame2win(win_altframe(win, NULL));
+
+ /*
+ * Be careful: If autocommands delete the window or cause this window
+ * to be the last one left, return now.
+ */
+ if (wp->w_buffer != curbuf)
+ {
+ other_buffer = TRUE;
+ win->w_closing = TRUE;
+ apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, FALSE, curbuf);
+ if (!win_valid(win))
+ return FAIL;
+ win->w_closing = FALSE;
+ if (last_window())
+ return FAIL;
+ }
+ win->w_closing = TRUE;
+ apply_autocmds(EVENT_WINLEAVE, NULL, NULL, FALSE, curbuf);
+ if (!win_valid(win))
+ return FAIL;
+ win->w_closing = FALSE;
+ if (last_window())
+ return FAIL;
+#ifdef FEAT_EVAL
+ /* autocmds may abort script processing */
+ if (aborting())
+ return FAIL;
+#endif
+ }
+
+#ifdef FEAT_GUI
+ /* Avoid trouble with scrollbars that are going to be deleted in
+ * win_free(). */
+ if (gui.in_use)
+ out_flush();
+#endif
+
+#ifdef FEAT_SYN_HL
+ /* Free independent synblock before the buffer is freed. */
+ if (win->w_buffer != NULL)
+ reset_synblock(win);
+#endif
+
+ /*
+ * Close the link to the buffer.
+ */
+ if (win->w_buffer != NULL)
+ {
+ bufref_T bufref;
+
+ set_bufref(&bufref, curbuf);
+ win->w_closing = TRUE;
+ close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0, TRUE);
+ if (win_valid_any_tab(win))
+ win->w_closing = FALSE;
+ /* Make sure curbuf is valid. It can become invalid if 'bufhidden' is
+ * "wipe". */
+ if (!bufref_valid(&bufref))
+ curbuf = firstbuf;
+ }
+
+ if (only_one_window() && win_valid(win) && win->w_buffer == NULL
+ && (last_window() || curtab != prev_curtab
+ || close_last_window_tabpage(win, free_buf, prev_curtab)))
+ {
+ /* Autocommands have closed all windows, quit now. Restore
+ * curwin->w_buffer, otherwise writing viminfo may fail. */
+ if (curwin->w_buffer == NULL)
+ curwin->w_buffer = curbuf;
+ getout(0);
+ }
+
+ /* Autocommands may have moved to another tab page. */
+ if (curtab != prev_curtab && win_valid_any_tab(win)
+ && win->w_buffer == NULL)
+ {
+ /* Need to close the window anyway, since the buffer is NULL. */
+ win_close_othertab(win, FALSE, prev_curtab);
+ return FAIL;
+ }
+
+ /* Autocommands may have closed the window already or closed the only
+ * other window. */
+ if (!win_valid(win) || last_window()
+ || close_last_window_tabpage(win, free_buf, prev_curtab))
+ return FAIL;
+
+ /* Free the memory used for the window and get the window that received
+ * the screen space. */
+ wp = win_free_mem(win, &dir, NULL);
+
+ /* Make sure curwin isn't invalid. It can cause severe trouble when
+ * printing an error message. For win_equal() curbuf needs to be valid
+ * too. */
+ if (win == curwin)
+ {
+ curwin = wp;
+#ifdef FEAT_QUICKFIX
+ if (wp->w_p_pvw || bt_quickfix(wp->w_buffer))
+ {
+ /*
+ * If the cursor goes to the preview or the quickfix window, try
+ * finding another window to go to.
+ */
+ for (;;)
+ {
+ if (wp->w_next == NULL)
+ wp = firstwin;
+ else
+ wp = wp->w_next;
+ if (wp == curwin)
+ break;
+ if (!wp->w_p_pvw && !bt_quickfix(wp->w_buffer))
+ {
+ curwin = wp;
+ break;
+ }
+ }
+ }
+#endif
+ curbuf = curwin->w_buffer;
+ close_curwin = TRUE;
+
+ /* The cursor position may be invalid if the buffer changed after last
+ * using the window. */
+ check_cursor();
+ }
+ if (p_ea && (*p_ead == 'b' || *p_ead == dir))
+ /* If the frame of the closed window contains the new current window,
+ * only resize that frame. Otherwise resize all windows. */
+ win_equal(curwin, curwin->w_frame->fr_parent == win_frame, dir);
+ else
+ win_comp_pos();
+ if (close_curwin)
+ {
+ win_enter_ext(wp, FALSE, TRUE, FALSE, TRUE, TRUE);
+ if (other_buffer)
+ /* careful: after this wp and win may be invalid! */
+ apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf);
+ }
+
+ /*
+ * If last window has a status line now and we don't want one,
+ * remove the status line.
+ */
+ last_status(FALSE);
+
+ /* After closing the help window, try restoring the window layout from
+ * before it was opened. */
+ if (help_window)
+ restore_snapshot(SNAP_HELP_IDX, close_curwin);
+
+#if defined(FEAT_GUI)
+ /* When 'guioptions' includes 'L' or 'R' may have to remove scrollbars. */
+ if (gui.in_use && !win_hasvertsplit())
+ gui_init_which_components(NULL);
+#endif
+
+ redraw_all_later(NOT_VALID);
+ return OK;
+}
+
+/*
+ * Close window "win" in tab page "tp", which is not the current tab page.
+ * This may be the last window in that tab page and result in closing the tab,
+ * thus "tp" may become invalid!
+ * Caller must check if buffer is hidden and whether the tabline needs to be
+ * updated.
+ */
+ void
+win_close_othertab(win_T *win, int free_buf, tabpage_T *tp)
+{
+ win_T *wp;
+ int dir;
+ tabpage_T *ptp = NULL;
+ int free_tp = FALSE;
+
+ /* Get here with win->w_buffer == NULL when win_close() detects the tab
+ * page changed. */
+ if (win->w_closing || (win->w_buffer != NULL
+ && win->w_buffer->b_locked > 0))
+ return; /* window is already being closed */
+
+ if (win->w_buffer != NULL)
+ /* Close the link to the buffer. */
+ close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0, FALSE);
+
+ /* Careful: Autocommands may have closed the tab page or made it the
+ * current tab page. */
+ for (ptp = first_tabpage; ptp != NULL && ptp != tp; ptp = ptp->tp_next)
+ ;
+ if (ptp == NULL || tp == curtab)
+ return;
+
+ /* Autocommands may have closed the window already. */
+ for (wp = tp->tp_firstwin; wp != NULL && wp != win; wp = wp->w_next)
+ ;
+ if (wp == NULL)
+ return;
+
+ /* When closing the last window in a tab page remove the tab page. */
+ if (tp->tp_firstwin == tp->tp_lastwin)
+ {
+ if (tp == first_tabpage)
+ first_tabpage = tp->tp_next;
+ else
+ {
+ for (ptp = first_tabpage; ptp != NULL && ptp->tp_next != tp;
+ ptp = ptp->tp_next)
+ ;
+ if (ptp == NULL)
+ {
+ internal_error("win_close_othertab()");
+ return;
+ }
+ ptp->tp_next = tp->tp_next;
+ }
+ free_tp = TRUE;
+ }
+
+ /* Free the memory used for the window. */
+ win_free_mem(win, &dir, tp);
+
+ if (free_tp)
+ free_tabpage(tp);
+}
+
+/*
+ * Free the memory used for a window.
+ * Returns a pointer to the window that got the freed up space.
+ */
+ static win_T *
+win_free_mem(
+ win_T *win,
+ int *dirp, /* set to 'v' or 'h' for direction if 'ea' */
+ tabpage_T *tp) /* tab page "win" is in, NULL for current */
+{
+ frame_T *frp;
+ win_T *wp;
+
+ /* Remove the window and its frame from the tree of frames. */
+ frp = win->w_frame;
+ wp = winframe_remove(win, dirp, tp);
+ vim_free(frp);
+ win_free(win, tp);
+
+ /* When deleting the current window of another tab page select a new
+ * current window. */
+ if (tp != NULL && win == tp->tp_curwin)
+ tp->tp_curwin = wp;
+
+ return wp;
+}
+
+#if defined(EXITFREE) || defined(PROTO)
+ void
+win_free_all(void)
+{
+ int dummy;
+
+ while (first_tabpage->tp_next != NULL)
+ tabpage_close(TRUE);
+
+ if (aucmd_win != NULL)
+ {
+ (void)win_free_mem(aucmd_win, &dummy, NULL);
+ aucmd_win = NULL;
+ }
+
+ while (firstwin != NULL)
+ (void)win_free_mem(firstwin, &dummy, NULL);
+
+ /* No window should be used after this. Set curwin to NULL to crash
+ * instead of using freed memory. */
+ curwin = NULL;
+}
+#endif
+
+/*
+ * Remove a window and its frame from the tree of frames.
+ * Returns a pointer to the window that got the freed up space.
+ */
+ win_T *
+winframe_remove(
+ win_T *win,
+ int *dirp UNUSED, /* set to 'v' or 'h' for direction if 'ea' */
+ tabpage_T *tp) /* tab page "win" is in, NULL for current */
+{
+ frame_T *frp, *frp2, *frp3;
+ frame_T *frp_close = win->w_frame;
+ win_T *wp;
+
+ /*
+ * If there is only one window there is nothing to remove.
+ */
+ if (tp == NULL ? ONE_WINDOW : tp->tp_firstwin == tp->tp_lastwin)
+ return NULL;
+
+ /*
+ * Remove the window from its frame.
+ */
+ frp2 = win_altframe(win, tp);
+ wp = frame2win(frp2);
+
+ /* Remove this frame from the list of frames. */
+ frame_remove(frp_close);
+
+ if (frp_close->fr_parent->fr_layout == FR_COL)
+ {
+ /* When 'winfixheight' is set, try to find another frame in the column
+ * (as close to the closed frame as possible) to distribute the height
+ * to. */
+ if (frp2->fr_win != NULL && frp2->fr_win->w_p_wfh)
+ {
+ frp = frp_close->fr_prev;
+ frp3 = frp_close->fr_next;
+ while (frp != NULL || frp3 != NULL)
+ {
+ if (frp != NULL)
+ {
+ if (frp->fr_win != NULL && !frp->fr_win->w_p_wfh)
+ {
+ frp2 = frp;
+ wp = frp->fr_win;
+ break;
+ }
+ frp = frp->fr_prev;
+ }
+ if (frp3 != NULL)
+ {
+ if (frp3->fr_win != NULL && !frp3->fr_win->w_p_wfh)
+ {
+ frp2 = frp3;
+ wp = frp3->fr_win;
+ break;
+ }
+ frp3 = frp3->fr_next;
+ }
+ }
+ }
+ frame_new_height(frp2, frp2->fr_height + frp_close->fr_height,
+ frp2 == frp_close->fr_next ? TRUE : FALSE, FALSE);
+ *dirp = 'v';
+ }
+ else
+ {
+ /* When 'winfixwidth' is set, try to find another frame in the column
+ * (as close to the closed frame as possible) to distribute the width
+ * to. */
+ if (frp2->fr_win != NULL && frp2->fr_win->w_p_wfw)
+ {
+ frp = frp_close->fr_prev;
+ frp3 = frp_close->fr_next;
+ while (frp != NULL || frp3 != NULL)
+ {
+ if (frp != NULL)
+ {
+ if (frp->fr_win != NULL && !frp->fr_win->w_p_wfw)
+ {
+ frp2 = frp;
+ wp = frp->fr_win;
+ break;
+ }
+ frp = frp->fr_prev;
+ }
+ if (frp3 != NULL)
+ {
+ if (frp3->fr_win != NULL && !frp3->fr_win->w_p_wfw)
+ {
+ frp2 = frp3;
+ wp = frp3->fr_win;
+ break;
+ }
+ frp3 = frp3->fr_next;
+ }
+ }
+ }
+ frame_new_width(frp2, frp2->fr_width + frp_close->fr_width,
+ frp2 == frp_close->fr_next ? TRUE : FALSE, FALSE);
+ *dirp = 'h';
+ }
+
+ /* If rows/columns go to a window below/right its positions need to be
+ * updated. Can only be done after the sizes have been updated. */
+ if (frp2 == frp_close->fr_next)
+ {
+ int row = win->w_winrow;
+ int col = win->w_wincol;
+
+ frame_comp_pos(frp2, &row, &col);
+ }
+
+ if (frp2->fr_next == NULL && frp2->fr_prev == NULL)
+ {
+ /* There is no other frame in this list, move its info to the parent
+ * and remove it. */
+ frp2->fr_parent->fr_layout = frp2->fr_layout;
+ frp2->fr_parent->fr_child = frp2->fr_child;
+ FOR_ALL_FRAMES(frp, frp2->fr_child)
+ frp->fr_parent = frp2->fr_parent;
+ frp2->fr_parent->fr_win = frp2->fr_win;
+ if (frp2->fr_win != NULL)
+ frp2->fr_win->w_frame = frp2->fr_parent;
+ frp = frp2->fr_parent;
+ if (topframe->fr_child == frp2)
+ topframe->fr_child = frp;
+ vim_free(frp2);
+
+ frp2 = frp->fr_parent;
+ if (frp2 != NULL && frp2->fr_layout == frp->fr_layout)
+ {
+ /* The frame above the parent has the same layout, have to merge
+ * the frames into this list. */
+ if (frp2->fr_child == frp)
+ frp2->fr_child = frp->fr_child;
+ frp->fr_child->fr_prev = frp->fr_prev;
+ if (frp->fr_prev != NULL)
+ frp->fr_prev->fr_next = frp->fr_child;
+ for (frp3 = frp->fr_child; ; frp3 = frp3->fr_next)
+ {
+ frp3->fr_parent = frp2;
+ if (frp3->fr_next == NULL)
+ {
+ frp3->fr_next = frp->fr_next;
+ if (frp->fr_next != NULL)
+ frp->fr_next->fr_prev = frp3;
+ break;
+ }
+ }
+ if (topframe->fr_child == frp)
+ topframe->fr_child = frp2;
+ vim_free(frp);
+ }
+ }
+
+ return wp;
+}
+
+/*
+ * Return a pointer to the frame that will receive the empty screen space that
+ * is left over after "win" is closed.
+ *
+ * If 'splitbelow' or 'splitright' is set, the space goes above or to the left
+ * by default. Otherwise, the free space goes below or to the right. The
+ * result is that opening a window and then immediately closing it will
+ * preserve the initial window layout. The 'wfh' and 'wfw' settings are
+ * respected when possible.
+ */
+ static frame_T *
+win_altframe(
+ win_T *win,
+ tabpage_T *tp) /* tab page "win" is in, NULL for current */
+{
+ frame_T *frp;
+ frame_T *other_fr, *target_fr;
+
+ if (tp == NULL ? ONE_WINDOW : tp->tp_firstwin == tp->tp_lastwin)
+ return alt_tabpage()->tp_curwin->w_frame;
+
+ frp = win->w_frame;
+
+ if (frp->fr_prev == NULL)
+ return frp->fr_next;
+ if (frp->fr_next == NULL)
+ return frp->fr_prev;
+
+ target_fr = frp->fr_next;
+ other_fr = frp->fr_prev;
+ if (p_spr || p_sb)
+ {
+ target_fr = frp->fr_prev;
+ other_fr = frp->fr_next;
+ }
+
+ /* If 'wfh' or 'wfw' is set for the target and not for the alternate
+ * window, reverse the selection. */
+ if (frp->fr_parent != NULL && frp->fr_parent->fr_layout == FR_ROW)
+ {
+ if (frame_fixed_width(target_fr) && !frame_fixed_width(other_fr))
+ target_fr = other_fr;
+ }
+ else
+ {
+ if (frame_fixed_height(target_fr) && !frame_fixed_height(other_fr))
+ target_fr = other_fr;
+ }
+
+ return target_fr;
+}
+
+/*
+ * Return the tabpage that will be used if the current one is closed.
+ */
+ static tabpage_T *
+alt_tabpage(void)
+{
+ tabpage_T *tp;
+
+ /* Use the next tab page if possible. */
+ if (curtab->tp_next != NULL)
+ return curtab->tp_next;
+
+ /* Find the last but one tab page. */
+ for (tp = first_tabpage; tp->tp_next != curtab; tp = tp->tp_next)
+ ;
+ return tp;
+}
+
+/*
+ * Find the left-upper window in frame "frp".
+ */
+ static win_T *
+frame2win(frame_T *frp)
+{
+ while (frp->fr_win == NULL)
+ frp = frp->fr_child;
+ return frp->fr_win;
+}
+
+/*
+ * Return TRUE if frame "frp" contains window "wp".
+ */
+ static int
+frame_has_win(frame_T *frp, win_T *wp)
+{
+ frame_T *p;
+
+ if (frp->fr_layout == FR_LEAF)
+ return frp->fr_win == wp;
+
+ FOR_ALL_FRAMES(p, frp->fr_child)
+ if (frame_has_win(p, wp))
+ return TRUE;
+ return FALSE;
+}
+
+/*
+ * Set a new height for a frame. Recursively sets the height for contained
+ * frames and windows. Caller must take care of positions.
+ */
+ static void
+frame_new_height(
+ frame_T *topfrp,
+ int height,
+ int topfirst, /* resize topmost contained frame first */
+ int wfh) /* obey 'winfixheight' when there is a choice;
+ may cause the height not to be set */
+{
+ frame_T *frp;
+ int extra_lines;
+ int h;
+
+ if (topfrp->fr_win != NULL)
+ {
+ /* Simple case: just one window. */
+ win_new_height(topfrp->fr_win,
+ height - topfrp->fr_win->w_status_height
+ - WINBAR_HEIGHT(topfrp->fr_win));
+ }
+ else if (topfrp->fr_layout == FR_ROW)
+ {
+ do
+ {
+ /* All frames in this row get the same new height. */
+ FOR_ALL_FRAMES(frp, topfrp->fr_child)
+ {
+ frame_new_height(frp, height, topfirst, wfh);
+ if (frp->fr_height > height)
+ {
+ /* Could not fit the windows, make the whole row higher. */
+ height = frp->fr_height;
+ break;
+ }
+ }
+ }
+ while (frp != NULL);
+ }
+ else /* fr_layout == FR_COL */
+ {
+ /* Complicated case: Resize a column of frames. Resize the bottom
+ * frame first, frames above that when needed. */
+
+ frp = topfrp->fr_child;
+ if (wfh)
+ /* Advance past frames with one window with 'wfh' set. */
+ while (frame_fixed_height(frp))
+ {
+ frp = frp->fr_next;
+ if (frp == NULL)
+ return; /* no frame without 'wfh', give up */
+ }
+ if (!topfirst)
+ {
+ /* Find the bottom frame of this column */
+ while (frp->fr_next != NULL)
+ frp = frp->fr_next;
+ if (wfh)
+ /* Advance back for frames with one window with 'wfh' set. */
+ while (frame_fixed_height(frp))
+ frp = frp->fr_prev;
+ }
+
+ extra_lines = height - topfrp->fr_height;
+ if (extra_lines < 0)
+ {
+ /* reduce height of contained frames, bottom or top frame first */
+ while (frp != NULL)
+ {
+ h = frame_minheight(frp, NULL);
+ if (frp->fr_height + extra_lines < h)
+ {
+ extra_lines += frp->fr_height - h;
+ frame_new_height(frp, h, topfirst, wfh);
+ }
+ else
+ {
+ frame_new_height(frp, frp->fr_height + extra_lines,
+ topfirst, wfh);
+ break;
+ }
+ if (topfirst)
+ {
+ do
+ frp = frp->fr_next;
+ while (wfh && frp != NULL && frame_fixed_height(frp));
+ }
+ else
+ {
+ do
+ frp = frp->fr_prev;
+ while (wfh && frp != NULL && frame_fixed_height(frp));
+ }
+ /* Increase "height" if we could not reduce enough frames. */
+ if (frp == NULL)
+ height -= extra_lines;
+ }
+ }
+ else if (extra_lines > 0)
+ {
+ /* increase height of bottom or top frame */
+ frame_new_height(frp, frp->fr_height + extra_lines, topfirst, wfh);
+ }
+ }
+ topfrp->fr_height = height;
+}
+
+/*
+ * Return TRUE if height of frame "frp" should not be changed because of
+ * the 'winfixheight' option.
+ */
+ static int
+frame_fixed_height(frame_T *frp)
+{
+ /* frame with one window: fixed height if 'winfixheight' set. */
+ if (frp->fr_win != NULL)
+ return frp->fr_win->w_p_wfh;
+
+ if (frp->fr_layout == FR_ROW)
+ {
+ /* The frame is fixed height if one of the frames in the row is fixed
+ * height. */
+ FOR_ALL_FRAMES(frp, frp->fr_child)
+ if (frame_fixed_height(frp))
+ return TRUE;
+ return FALSE;
+ }
+
+ /* frp->fr_layout == FR_COL: The frame is fixed height if all of the
+ * frames in the row are fixed height. */
+ FOR_ALL_FRAMES(frp, frp->fr_child)
+ if (!frame_fixed_height(frp))
+ return FALSE;
+ return TRUE;
+}
+
+/*
+ * Return TRUE if width of frame "frp" should not be changed because of
+ * the 'winfixwidth' option.
+ */
+ static int
+frame_fixed_width(frame_T *frp)
+{
+ /* frame with one window: fixed width if 'winfixwidth' set. */
+ if (frp->fr_win != NULL)
+ return frp->fr_win->w_p_wfw;
+
+ if (frp->fr_layout == FR_COL)
+ {
+ /* The frame is fixed width if one of the frames in the row is fixed
+ * width. */
+ FOR_ALL_FRAMES(frp, frp->fr_child)
+ if (frame_fixed_width(frp))
+ return TRUE;
+ return FALSE;
+ }
+
+ /* frp->fr_layout == FR_ROW: The frame is fixed width if all of the
+ * frames in the row are fixed width. */
+ FOR_ALL_FRAMES(frp, frp->fr_child)
+ if (!frame_fixed_width(frp))
+ return FALSE;
+ return TRUE;
+}
+
+/*
+ * Add a status line to windows at the bottom of "frp".
+ * Note: Does not check if there is room!
+ */
+ static void
+frame_add_statusline(frame_T *frp)
+{
+ win_T *wp;
+
+ if (frp->fr_layout == FR_LEAF)
+ {
+ wp = frp->fr_win;
+ if (wp->w_status_height == 0)
+ {
+ if (wp->w_height > 0) /* don't make it negative */
+ --wp->w_height;
+ wp->w_status_height = STATUS_HEIGHT;
+ }
+ }
+ else if (frp->fr_layout == FR_ROW)
+ {
+ /* Handle all the frames in the row. */
+ FOR_ALL_FRAMES(frp, frp->fr_child)
+ frame_add_statusline(frp);
+ }
+ else /* frp->fr_layout == FR_COL */
+ {
+ /* Only need to handle the last frame in the column. */
+ for (frp = frp->fr_child; frp->fr_next != NULL; frp = frp->fr_next)
+ ;
+ frame_add_statusline(frp);
+ }
+}
+
+/*
+ * Set width of a frame. Handles recursively going through contained frames.
+ * May remove separator line for windows at the right side (for win_close()).
+ */
+ static void
+frame_new_width(
+ frame_T *topfrp,
+ int width,
+ int leftfirst, /* resize leftmost contained frame first */
+ int wfw) /* obey 'winfixwidth' when there is a choice;
+ may cause the width not to be set */
+{
+ frame_T *frp;
+ int extra_cols;
+ int w;
+ win_T *wp;
+
+ if (topfrp->fr_layout == FR_LEAF)
+ {
+ /* Simple case: just one window. */
+ wp = topfrp->fr_win;
+ /* Find out if there are any windows right of this one. */
+ for (frp = topfrp; frp->fr_parent != NULL; frp = frp->fr_parent)
+ if (frp->fr_parent->fr_layout == FR_ROW && frp->fr_next != NULL)
+ break;
+ if (frp->fr_parent == NULL)
+ wp->w_vsep_width = 0;
+ win_new_width(wp, width - wp->w_vsep_width);
+ }
+ else if (topfrp->fr_layout == FR_COL)
+ {
+ do
+ {
+ /* All frames in this column get the same new width. */
+ FOR_ALL_FRAMES(frp, topfrp->fr_child)
+ {
+ frame_new_width(frp, width, leftfirst, wfw);
+ if (frp->fr_width > width)
+ {
+ /* Could not fit the windows, make whole column wider. */
+ width = frp->fr_width;
+ break;
+ }
+ }
+ } while (frp != NULL);
+ }
+ else /* fr_layout == FR_ROW */
+ {
+ /* Complicated case: Resize a row of frames. Resize the rightmost
+ * frame first, frames left of it when needed. */
+
+ frp = topfrp->fr_child;
+ if (wfw)
+ /* Advance past frames with one window with 'wfw' set. */
+ while (frame_fixed_width(frp))
+ {
+ frp = frp->fr_next;
+ if (frp == NULL)
+ return; /* no frame without 'wfw', give up */
+ }
+ if (!leftfirst)
+ {
+ /* Find the rightmost frame of this row */
+ while (frp->fr_next != NULL)
+ frp = frp->fr_next;
+ if (wfw)
+ /* Advance back for frames with one window with 'wfw' set. */
+ while (frame_fixed_width(frp))
+ frp = frp->fr_prev;
+ }
+
+ extra_cols = width - topfrp->fr_width;
+ if (extra_cols < 0)
+ {
+ /* reduce frame width, rightmost frame first */
+ while (frp != NULL)
+ {
+ w = frame_minwidth(frp, NULL);
+ if (frp->fr_width + extra_cols < w)
+ {
+ extra_cols += frp->fr_width - w;
+ frame_new_width(frp, w, leftfirst, wfw);
+ }
+ else
+ {
+ frame_new_width(frp, frp->fr_width + extra_cols,
+ leftfirst, wfw);
+ break;
+ }
+ if (leftfirst)
+ {
+ do
+ frp = frp->fr_next;
+ while (wfw && frp != NULL && frame_fixed_width(frp));
+ }
+ else
+ {
+ do
+ frp = frp->fr_prev;
+ while (wfw && frp != NULL && frame_fixed_width(frp));
+ }
+ /* Increase "width" if we could not reduce enough frames. */
+ if (frp == NULL)
+ width -= extra_cols;
+ }
+ }
+ else if (extra_cols > 0)
+ {
+ /* increase width of rightmost frame */
+ frame_new_width(frp, frp->fr_width + extra_cols, leftfirst, wfw);
+ }
+ }
+ topfrp->fr_width = width;
+}
+
+/*
+ * Add the vertical separator to windows at the right side of "frp".
+ * Note: Does not check if there is room!
+ */
+ static void
+frame_add_vsep(frame_T *frp)
+{
+ win_T *wp;
+
+ if (frp->fr_layout == FR_LEAF)
+ {
+ wp = frp->fr_win;
+ if (wp->w_vsep_width == 0)
+ {
+ if (wp->w_width > 0) /* don't make it negative */
+ --wp->w_width;
+ wp->w_vsep_width = 1;
+ }
+ }
+ else if (frp->fr_layout == FR_COL)
+ {
+ /* Handle all the frames in the column. */
+ FOR_ALL_FRAMES(frp, frp->fr_child)
+ frame_add_vsep(frp);
+ }
+ else /* frp->fr_layout == FR_ROW */
+ {
+ /* Only need to handle the last frame in the row. */
+ frp = frp->fr_child;
+ while (frp->fr_next != NULL)
+ frp = frp->fr_next;
+ frame_add_vsep(frp);
+ }
+}
+
+/*
+ * Set frame width from the window it contains.
+ */
+ static void
+frame_fix_width(win_T *wp)
+{
+ wp->w_frame->fr_width = wp->w_width + wp->w_vsep_width;
+}
+
+/*
+ * Set frame height from the window it contains.
+ */
+ static void
+frame_fix_height(win_T *wp)
+{
+ wp->w_frame->fr_height = VISIBLE_HEIGHT(wp) + wp->w_status_height;
+}
+
+/*
+ * Compute the minimal height for frame "topfrp".
+ * Uses the 'winminheight' option.
+ * When "next_curwin" isn't NULL, use p_wh for this window.
+ * When "next_curwin" is NOWIN, don't use at least one line for the current
+ * window.
+ */
+ static int
+frame_minheight(frame_T *topfrp, win_T *next_curwin)
+{
+ frame_T *frp;
+ int m;
+ int n;
+
+ if (topfrp->fr_win != NULL)
+ {
+ if (topfrp->fr_win == next_curwin)
+ m = p_wh + topfrp->fr_win->w_status_height;
+ else
+ {
+ /* window: minimal height of the window plus status line */
+ m = p_wmh + topfrp->fr_win->w_status_height;
+ if (topfrp->fr_win == curwin && next_curwin == NULL)
+ {
+ /* Current window is minimal one line high and WinBar is
+ * visible. */
+ if (p_wmh == 0)
+ ++m;
+ m += WINBAR_HEIGHT(curwin);
+ }
+ }
+ }
+ else if (topfrp->fr_layout == FR_ROW)
+ {
+ /* get the minimal height from each frame in this row */
+ m = 0;
+ FOR_ALL_FRAMES(frp, topfrp->fr_child)
+ {
+ n = frame_minheight(frp, next_curwin);
+ if (n > m)
+ m = n;
+ }
+ }
+ else
+ {
+ /* Add up the minimal heights for all frames in this column. */
+ m = 0;
+ FOR_ALL_FRAMES(frp, topfrp->fr_child)
+ m += frame_minheight(frp, next_curwin);
+ }
+
+ return m;
+}
+
+/*
+ * Compute the minimal width for frame "topfrp".
+ * When "next_curwin" isn't NULL, use p_wiw for this window.
+ * When "next_curwin" is NOWIN, don't use at least one column for the current
+ * window.
+ */
+ static int
+frame_minwidth(
+ frame_T *topfrp,
+ win_T *next_curwin) /* use p_wh and p_wiw for next_curwin */
+{
+ frame_T *frp;
+ int m, n;
+
+ if (topfrp->fr_win != NULL)
+ {
+ if (topfrp->fr_win == next_curwin)
+ m = p_wiw + topfrp->fr_win->w_vsep_width;
+ else
+ {
+ /* window: minimal width of the window plus separator column */
+ m = p_wmw + topfrp->fr_win->w_vsep_width;
+ /* Current window is minimal one column wide */
+ if (p_wmw == 0 && topfrp->fr_win == curwin && next_curwin == NULL)
+ ++m;
+ }
+ }
+ else if (topfrp->fr_layout == FR_COL)
+ {
+ /* get the minimal width from each frame in this column */
+ m = 0;
+ FOR_ALL_FRAMES(frp, topfrp->fr_child)
+ {
+ n = frame_minwidth(frp, next_curwin);
+ if (n > m)
+ m = n;
+ }
+ }
+ else
+ {
+ /* Add up the minimal widths for all frames in this row. */
+ m = 0;
+ FOR_ALL_FRAMES(frp, topfrp->fr_child)
+ m += frame_minwidth(frp, next_curwin);
+ }
+
+ return m;
+}
+
+
+/*
+ * Try to close all windows except current one.
+ * Buffers in the other windows become hidden if 'hidden' is set, or '!' is
+ * used and the buffer was modified.
+ *
+ * Used by ":bdel" and ":only".
+ */
+ void
+close_others(
+ int message,
+ int forceit) /* always hide all other windows */
+{
+ win_T *wp;
+ win_T *nextwp;
+ int r;
+
+ if (one_window())
+ {
+ if (message && !autocmd_busy)
+ msg(_(m_onlyone));
+ return;
+ }
+
+ /* Be very careful here: autocommands may change the window layout. */
+ for (wp = firstwin; win_valid(wp); wp = nextwp)
+ {
+ nextwp = wp->w_next;
+ if (wp != curwin) /* don't close current window */
+ {
+
+ /* Check if it's allowed to abandon this window */
+ r = can_abandon(wp->w_buffer, forceit);
+ if (!win_valid(wp)) /* autocommands messed wp up */
+ {
+ nextwp = firstwin;
+ continue;
+ }
+ if (!r)
+ {
+#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
+ if (message && (p_confirm || cmdmod.confirm) && p_write)
+ {
+ dialog_changed(wp->w_buffer, FALSE);
+ if (!win_valid(wp)) /* autocommands messed wp up */
+ {
+ nextwp = firstwin;
+ continue;
+ }
+ }
+ if (bufIsChanged(wp->w_buffer))
+#endif
+ continue;
+ }
+ win_close(wp, !buf_hide(wp->w_buffer)
+ && !bufIsChanged(wp->w_buffer));
+ }
+ }
+
+ if (message && !ONE_WINDOW)
+ emsg(_("E445: Other window contains changes"));
+}
+
+/*
+ * Init the current window "curwin".
+ * Called when a new file is being edited.
+ */
+ void
+curwin_init(void)
+{
+ win_init_empty(curwin);
+}
+
+ void
+win_init_empty(win_T *wp)
+{
+ redraw_win_later(wp, NOT_VALID);
+ wp->w_lines_valid = 0;
+ wp->w_cursor.lnum = 1;
+ wp->w_curswant = wp->w_cursor.col = 0;
+ wp->w_cursor.coladd = 0;
+ wp->w_pcmark.lnum = 1; /* pcmark not cleared but set to line 1 */
+ wp->w_pcmark.col = 0;
+ wp->w_prev_pcmark.lnum = 0;
+ wp->w_prev_pcmark.col = 0;
+ wp->w_topline = 1;
+#ifdef FEAT_DIFF
+ wp->w_topfill = 0;
+#endif
+ wp->w_botline = 2;
+#ifdef FEAT_FKMAP
+ if (wp->w_p_rl)
+ wp->w_farsi = W_CONV + W_R_L;
+ else
+ wp->w_farsi = W_CONV;
+#endif
+#ifdef FEAT_SYN_HL
+ wp->w_s = &wp->w_buffer->b_s;
+#endif
+}
+
+/*
+ * Allocate the first window and put an empty buffer in it.
+ * Called from main().
+ * Return FAIL when something goes wrong (out of memory).
+ */
+ int
+win_alloc_first(void)
+{
+ if (win_alloc_firstwin(NULL) == FAIL)
+ return FAIL;
+
+ first_tabpage = alloc_tabpage();
+ if (first_tabpage == NULL)
+ return FAIL;
+ first_tabpage->tp_topframe = topframe;
+ curtab = first_tabpage;
+
+ return OK;
+}
+
+/*
+ * Init "aucmd_win". This can only be done after the first
+ * window is fully initialized, thus it can't be in win_alloc_first().
+ */
+ void
+win_alloc_aucmd_win(void)
+{
+ aucmd_win = win_alloc(NULL, TRUE);
+ if (aucmd_win != NULL)
+ {
+ win_init_some(aucmd_win, curwin);
+ RESET_BINDING(aucmd_win);
+ new_frame(aucmd_win);
+ }
+}
+
+/*
+ * Allocate the first window or the first window in a new tab page.
+ * When "oldwin" is NULL create an empty buffer for it.
+ * When "oldwin" is not NULL copy info from it to the new window.
+ * Return FAIL when something goes wrong (out of memory).
+ */
+ static int
+win_alloc_firstwin(win_T *oldwin)
+{
+ curwin = win_alloc(NULL, FALSE);
+ if (oldwin == NULL)
+ {
+ /* Very first window, need to create an empty buffer for it and
+ * initialize from scratch. */
+ curbuf = buflist_new(NULL, NULL, 1L, BLN_LISTED);
+ if (curwin == NULL || curbuf == NULL)
+ return FAIL;
+ curwin->w_buffer = curbuf;
+#ifdef FEAT_SYN_HL
+ curwin->w_s = &(curbuf->b_s);
+#endif
+ curbuf->b_nwindows = 1; /* there is one window */
+ curwin->w_alist = &global_alist;
+ curwin_init(); /* init current window */
+ }
+ else
+ {
+ /* First window in new tab page, initialize it from "oldwin". */
+ win_init(curwin, oldwin, 0);
+
+ /* We don't want cursor- and scroll-binding in the first window. */
+ RESET_BINDING(curwin);
+ }
+
+ new_frame(curwin);
+ if (curwin->w_frame == NULL)
+ return FAIL;
+ topframe = curwin->w_frame;
+ topframe->fr_width = Columns;
+ topframe->fr_height = Rows - p_ch;
+
+ return OK;
+}
+
+/*
+ * Create a frame for window "wp".
+ */
+ static void
+new_frame(win_T *wp)
+{
+ frame_T *frp = (frame_T *)alloc_clear((unsigned)sizeof(frame_T));
+
+ wp->w_frame = frp;
+ if (frp != NULL)
+ {
+ frp->fr_layout = FR_LEAF;
+ frp->fr_win = wp;
+ }
+}
+
+/*
+ * Initialize the window and frame size to the maximum.
+ */
+ void
+win_init_size(void)
+{
+ firstwin->w_height = ROWS_AVAIL;
+ topframe->fr_height = ROWS_AVAIL;
+ firstwin->w_width = Columns;
+ topframe->fr_width = Columns;
+}
+
+/*
+ * Allocate a new tabpage_T and init the values.
+ * Returns NULL when out of memory.
+ */
+ static tabpage_T *
+alloc_tabpage(void)
+{
+ tabpage_T *tp;
+# ifdef FEAT_GUI
+ int i;
+# endif
+
+
+ tp = (tabpage_T *)alloc_clear((unsigned)sizeof(tabpage_T));
+ if (tp == NULL)
+ return NULL;
+
+# ifdef FEAT_EVAL
+ /* init t: variables */
+ tp->tp_vars = dict_alloc();
+ if (tp->tp_vars == NULL)
+ {
+ vim_free(tp);
+ return NULL;
+ }
+ init_var_dict(tp->tp_vars, &tp->tp_winvar, VAR_SCOPE);
+# endif
+
+# ifdef FEAT_GUI
+ for (i = 0; i < 3; i++)
+ tp->tp_prev_which_scrollbars[i] = -1;
+# endif
+# ifdef FEAT_DIFF
+ tp->tp_diff_invalid = TRUE;
+# endif
+ tp->tp_ch_used = p_ch;
+
+ return tp;
+}
+
+ void
+free_tabpage(tabpage_T *tp)
+{
+ int idx;
+
+# ifdef FEAT_DIFF
+ diff_clear(tp);
+# endif
+ for (idx = 0; idx < SNAP_COUNT; ++idx)
+ clear_snapshot(tp, idx);
+#ifdef FEAT_EVAL
+ vars_clear(&tp->tp_vars->dv_hashtab); /* free all t: variables */
+ hash_init(&tp->tp_vars->dv_hashtab);
+ unref_var_dict(tp->tp_vars);
+#endif
+
+#ifdef FEAT_PYTHON
+ python_tabpage_free(tp);
+#endif
+
+#ifdef FEAT_PYTHON3
+ python3_tabpage_free(tp);
+#endif
+
+ vim_free(tp);
+}
+
+/*
+ * Create a new Tab page with one window.
+ * It will edit the current buffer, like after ":split".
+ * When "after" is 0 put it just after the current Tab page.
+ * Otherwise put it just before tab page "after".
+ * Return FAIL or OK.
+ */
+ int
+win_new_tabpage(int after)
+{
+ tabpage_T *tp = curtab;
+ tabpage_T *newtp;
+ int n;
+
+ newtp = alloc_tabpage();
+ if (newtp == NULL)
+ return FAIL;
+
+ /* Remember the current windows in this Tab page. */
+ if (leave_tabpage(curbuf, TRUE) == FAIL)
+ {
+ vim_free(newtp);
+ return FAIL;
+ }
+ curtab = newtp;
+
+ /* Create a new empty window. */
+ if (win_alloc_firstwin(tp->tp_curwin) == OK)
+ {
+ /* Make the new Tab page the new topframe. */
+ if (after == 1)
+ {
+ /* New tab page becomes the first one. */
+ newtp->tp_next = first_tabpage;
+ first_tabpage = newtp;
+ }
+ else
+ {
+ if (after > 0)
+ {
+ /* Put new tab page before tab page "after". */
+ n = 2;
+ for (tp = first_tabpage; tp->tp_next != NULL
+ && n < after; tp = tp->tp_next)
+ ++n;
+ }
+ newtp->tp_next = tp->tp_next;
+ tp->tp_next = newtp;
+ }
+ win_init_size();
+ firstwin->w_winrow = tabline_height();
+ win_comp_scroll(curwin);
+
+ newtp->tp_topframe = topframe;
+ last_status(FALSE);
+
+#if defined(FEAT_GUI)
+ /* When 'guioptions' includes 'L' or 'R' may have to remove or add
+ * scrollbars. Have to update them anyway. */
+ gui_may_update_scrollbars();
+#endif
+#ifdef FEAT_JOB_CHANNEL
+ entering_window(curwin);
+#endif
+
+ redraw_all_later(NOT_VALID);
+ apply_autocmds(EVENT_WINNEW, NULL, NULL, FALSE, curbuf);
+ apply_autocmds(EVENT_WINENTER, NULL, NULL, FALSE, curbuf);
+ apply_autocmds(EVENT_TABNEW, NULL, NULL, FALSE, curbuf);
+ apply_autocmds(EVENT_TABENTER, NULL, NULL, FALSE, curbuf);
+ return OK;
+ }
+
+ /* Failed, get back the previous Tab page */
+ enter_tabpage(curtab, curbuf, TRUE, TRUE);
+ return FAIL;
+}
+
+/*
+ * Open a new tab page if ":tab cmd" was used. It will edit the same buffer,
+ * like with ":split".
+ * Returns OK if a new tab page was created, FAIL otherwise.
+ */
+ int
+may_open_tabpage(void)
+{
+ int n = (cmdmod.tab == 0) ? postponed_split_tab : cmdmod.tab;
+
+ if (n != 0)
+ {
+ cmdmod.tab = 0; /* reset it to avoid doing it twice */
+ postponed_split_tab = 0;
+ return win_new_tabpage(n);
+ }
+ return FAIL;
+}
+
+/*
+ * Create up to "maxcount" tabpages with empty windows.
+ * Returns the number of resulting tab pages.
+ */
+ int
+make_tabpages(int maxcount)
+{
+ int count = maxcount;
+ int todo;
+
+ /* Limit to 'tabpagemax' tabs. */
+ if (count > p_tpm)
+ count = p_tpm;
+
+ /*
+ * Don't execute autocommands while creating the tab pages. Must do that
+ * when putting the buffers in the windows.
+ */
+ block_autocmds();
+
+ for (todo = count - 1; todo > 0; --todo)
+ if (win_new_tabpage(0) == FAIL)
+ break;
+
+ unblock_autocmds();
+
+ /* return actual number of tab pages */
+ return (count - todo);
+}
+
+/*
+ * Return TRUE when "tpc" points to a valid tab page.
+ */
+ int
+valid_tabpage(tabpage_T *tpc)
+{
+ tabpage_T *tp;
+
+ FOR_ALL_TABPAGES(tp)
+ if (tp == tpc)
+ return TRUE;
+ return FALSE;
+}
+
+/*
+ * Return TRUE when "tpc" points to a valid tab page and at least one window is
+ * valid.
+ */
+ int
+valid_tabpage_win(tabpage_T *tpc)
+{
+ tabpage_T *tp;
+ win_T *wp;
+
+ FOR_ALL_TABPAGES(tp)
+ {
+ if (tp == tpc)
+ {
+ FOR_ALL_WINDOWS_IN_TAB(tp, wp)
+ {
+ if (win_valid_any_tab(wp))
+ return TRUE;
+ }
+ return FALSE;
+ }
+ }
+ /* shouldn't happen */
+ return FALSE;
+}
+
+/*
+ * Close tabpage "tab", assuming it has no windows in it.
+ * There must be another tabpage or this will crash.
+ */
+ void
+close_tabpage(tabpage_T *tab)
+{
+ tabpage_T *ptp;
+
+ if (tab == first_tabpage)
+ {
+ first_tabpage = tab->tp_next;
+ ptp = first_tabpage;
+ }
+ else
+ {
+ for (ptp = first_tabpage; ptp != NULL && ptp->tp_next != tab;
+ ptp = ptp->tp_next)
+ ;
+ assert(ptp != NULL);
+ ptp->tp_next = tab->tp_next;
+ }
+
+ goto_tabpage_tp(ptp, FALSE, FALSE);
+ free_tabpage(tab);
+}
+
+/*
+ * Find tab page "n" (first one is 1). Returns NULL when not found.
+ */
+ tabpage_T *
+find_tabpage(int n)
+{
+ tabpage_T *tp;
+ int i = 1;
+
+ for (tp = first_tabpage; tp != NULL && i != n; tp = tp->tp_next)
+ ++i;
+ return tp;
+}
+
+/*
+ * Get index of tab page "tp". First one has index 1.
+ * When not found returns number of tab pages plus one.
+ */
+ int
+tabpage_index(tabpage_T *ftp)
+{
+ int i = 1;
+ tabpage_T *tp;
+
+ for (tp = first_tabpage; tp != NULL && tp != ftp; tp = tp->tp_next)
+ ++i;
+ return i;
+}
+
+/*
+ * Prepare for leaving the current tab page.
+ * When autocommands change "curtab" we don't leave the tab page and return
+ * FAIL.
+ * Careful: When OK is returned need to get a new tab page very very soon!
+ */
+ static int
+leave_tabpage(
+ buf_T *new_curbuf UNUSED, /* what is going to be the new curbuf,
+ NULL if unknown */
+ int trigger_leave_autocmds UNUSED)
+{
+ tabpage_T *tp = curtab;
+
+#ifdef FEAT_JOB_CHANNEL
+ leaving_window(curwin);
+#endif
+ reset_VIsual_and_resel(); /* stop Visual mode */
+ if (trigger_leave_autocmds)
+ {
+ if (new_curbuf != curbuf)
+ {
+ apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, FALSE, curbuf);
+ if (curtab != tp)
+ return FAIL;
+ }
+ apply_autocmds(EVENT_WINLEAVE, NULL, NULL, FALSE, curbuf);
+ if (curtab != tp)
+ return FAIL;
+ apply_autocmds(EVENT_TABLEAVE, NULL, NULL, FALSE, curbuf);
+ if (curtab != tp)
+ return FAIL;
+ }
+#if defined(FEAT_GUI)
+ /* Remove the scrollbars. They may be added back later. */
+ if (gui.in_use)
+ gui_remove_scrollbars();
+#endif
+ tp->tp_curwin = curwin;
+ tp->tp_prevwin = prevwin;
+ tp->tp_firstwin = firstwin;
+ tp->tp_lastwin = lastwin;
+ tp->tp_old_Rows = Rows;
+ tp->tp_old_Columns = Columns;
+ firstwin = NULL;
+ lastwin = NULL;
+ return OK;
+}
+
+/*
+ * Start using tab page "tp".
+ * Only to be used after leave_tabpage() or freeing the current tab page.
+ * Only trigger *Enter autocommands when trigger_enter_autocmds is TRUE.
+ * Only trigger *Leave autocommands when trigger_leave_autocmds is TRUE.
+ */
+ static void
+enter_tabpage(
+ tabpage_T *tp,
+ buf_T *old_curbuf UNUSED,
+ int trigger_enter_autocmds,
+ int trigger_leave_autocmds)
+{
+ int old_off = tp->tp_firstwin->w_winrow;
+ win_T *next_prevwin = tp->tp_prevwin;
+
+ curtab = tp;
+ firstwin = tp->tp_firstwin;
+ lastwin = tp->tp_lastwin;
+ topframe = tp->tp_topframe;
+
+ /* We would like doing the TabEnter event first, but we don't have a
+ * valid current window yet, which may break some commands.
+ * This triggers autocommands, thus may make "tp" invalid. */
+ win_enter_ext(tp->tp_curwin, FALSE, TRUE, FALSE,
+ trigger_enter_autocmds, trigger_leave_autocmds);
+ prevwin = next_prevwin;
+
+ last_status(FALSE); /* status line may appear or disappear */
+ (void)win_comp_pos(); /* recompute w_winrow for all windows */
+#ifdef FEAT_DIFF
+ diff_need_scrollbind = TRUE;
+#endif
+
+ /* The tabpage line may have appeared or disappeared, may need to resize
+ * the frames for that. When the Vim window was resized need to update
+ * frame sizes too. Use the stored value of p_ch, so that it can be
+ * different for each tab page. */
+ p_ch = curtab->tp_ch_used;
+ if (curtab->tp_old_Rows != Rows || (old_off != firstwin->w_winrow
+#ifdef FEAT_GUI_TABLINE
+ && !gui_use_tabline()
+#endif
+ ))
+ shell_new_rows();
+ if (curtab->tp_old_Columns != Columns && starting == 0)
+ shell_new_columns(); /* update window widths */
+
+#if defined(FEAT_GUI)
+ /* When 'guioptions' includes 'L' or 'R' may have to remove or add
+ * scrollbars. Have to update them anyway. */
+ gui_may_update_scrollbars();
+#endif
+
+ /* Apply autocommands after updating the display, when 'rows' and
+ * 'columns' have been set correctly. */
+ if (trigger_enter_autocmds)
+ {
+ apply_autocmds(EVENT_TABENTER, NULL, NULL, FALSE, curbuf);
+ if (old_curbuf != curbuf)
+ apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf);
+ }
+
+ redraw_all_later(NOT_VALID);
+}
+
+/*
+ * Go to tab page "n". For ":tab N" and "Ngt".
+ * When "n" is 9999 go to the last tab page.
+ */
+ void
+goto_tabpage(int n)
+{
+ tabpage_T *tp;
+ tabpage_T *ttp;
+ int i;
+
+ if (text_locked())
+ {
+ /* Not allowed when editing the command line. */
+ text_locked_msg();
+ return;
+ }
+
+ /* If there is only one it can't work. */
+ if (first_tabpage->tp_next == NULL)
+ {
+ if (n > 1)
+ beep_flush();
+ return;
+ }
+
+ if (n == 0)
+ {
+ /* No count, go to next tab page, wrap around end. */
+ if (curtab->tp_next == NULL)
+ tp = first_tabpage;
+ else
+ tp = curtab->tp_next;
+ }
+ else if (n < 0)
+ {
+ /* "gT": go to previous tab page, wrap around end. "N gT" repeats
+ * this N times. */
+ ttp = curtab;
+ for (i = n; i < 0; ++i)
+ {
+ for (tp = first_tabpage; tp->tp_next != ttp && tp->tp_next != NULL;
+ tp = tp->tp_next)
+ ;
+ ttp = tp;
+ }
+ }
+ else if (n == 9999)
+ {
+ /* Go to last tab page. */
+ for (tp = first_tabpage; tp->tp_next != NULL; tp = tp->tp_next)
+ ;
+ }
+ else
+ {
+ /* Go to tab page "n". */
+ tp = find_tabpage(n);
+ if (tp == NULL)
+ {
+ beep_flush();
+ return;
+ }
+ }
+
+ goto_tabpage_tp(tp, TRUE, TRUE);
+
+#ifdef FEAT_GUI_TABLINE
+ if (gui_use_tabline())
+ gui_mch_set_curtab(tabpage_index(curtab));
+#endif
+}
+
+/*
+ * Go to tabpage "tp".
+ * Only trigger *Enter autocommands when trigger_enter_autocmds is TRUE.
+ * Only trigger *Leave autocommands when trigger_leave_autocmds is TRUE.
+ * Note: doesn't update the GUI tab.
+ */
+ void
+goto_tabpage_tp(
+ tabpage_T *tp,
+ int trigger_enter_autocmds,
+ int trigger_leave_autocmds)
+{
+ /* Don't repeat a message in another tab page. */
+ set_keep_msg(NULL, 0);
+
+ if (tp != curtab && leave_tabpage(tp->tp_curwin->w_buffer,
+ trigger_leave_autocmds) == OK)
+ {
+ if (valid_tabpage(tp))
+ enter_tabpage(tp, curbuf, trigger_enter_autocmds,
+ trigger_leave_autocmds);
+ else
+ enter_tabpage(curtab, curbuf, trigger_enter_autocmds,
+ trigger_leave_autocmds);
+ }
+}
+
+/*
+ * Enter window "wp" in tab page "tp".
+ * Also updates the GUI tab.
+ */
+ void
+goto_tabpage_win(tabpage_T *tp, win_T *wp)
+{
+ goto_tabpage_tp(tp, TRUE, TRUE);
+ if (curtab == tp && win_valid(wp))
+ {
+ win_enter(wp, TRUE);
+# ifdef FEAT_GUI_TABLINE
+ if (gui_use_tabline())
+ gui_mch_set_curtab(tabpage_index(curtab));
+# endif
+ }
+}
+
+/*
+ * Move the current tab page to after tab page "nr".
+ */
+ void
+tabpage_move(int nr)
+{
+ int n = 1;
+ tabpage_T *tp, *tp_dst;
+
+ if (first_tabpage->tp_next == NULL)
+ return;
+
+ for (tp = first_tabpage; tp->tp_next != NULL && n < nr; tp = tp->tp_next)
+ ++n;
+
+ if (tp == curtab || (nr > 0 && tp->tp_next != NULL
+ && tp->tp_next == curtab))
+ return;
+
+ tp_dst = tp;
+
+ /* Remove the current tab page from the list of tab pages. */
+ if (curtab == first_tabpage)
+ first_tabpage = curtab->tp_next;
+ else
+ {
+ FOR_ALL_TABPAGES(tp)
+ if (tp->tp_next == curtab)
+ break;
+ if (tp == NULL) /* "cannot happen" */
+ return;
+ tp->tp_next = curtab->tp_next;
+ }
+
+ /* Re-insert it at the specified position. */
+ if (nr <= 0)
+ {
+ curtab->tp_next = first_tabpage;
+ first_tabpage = curtab;
+ }
+ else
+ {
+ curtab->tp_next = tp_dst->tp_next;
+ tp_dst->tp_next = curtab;
+ }
+
+ /* Need to redraw the tabline. Tab page contents doesn't change. */
+ redraw_tabline = TRUE;
+}
+
+
+/*
+ * Go to another window.
+ * When jumping to another buffer, stop Visual mode. Do this before
+ * changing windows so we can yank the selection into the '*' register.
+ * When jumping to another window on the same buffer, adjust its cursor
+ * position to keep the same Visual area.
+ */
+ void
+win_goto(win_T *wp)
+{
+#ifdef FEAT_CONCEAL
+ win_T *owp = curwin;
+#endif
+
+ if (text_locked())
+ {
+ beep_flush();
+ text_locked_msg();
+ return;
+ }
+ if (curbuf_locked())
+ return;
+
+ if (wp->w_buffer != curbuf)
+ reset_VIsual_and_resel();
+ else if (VIsual_active)
+ wp->w_cursor = curwin->w_cursor;
+
+#ifdef FEAT_GUI
+ need_mouse_correct = TRUE;
+#endif
+ win_enter(wp, TRUE);
+
+#ifdef FEAT_CONCEAL
+ // Conceal cursor line in previous window, unconceal in current window.
+ if (win_valid(owp) && owp->w_p_cole > 0 && !msg_scrolled)
+ redrawWinline(owp, owp->w_cursor.lnum);
+ if (curwin->w_p_cole > 0 && !msg_scrolled)
+ need_cursor_line_redraw = TRUE;
+#endif
+}
+
+#if defined(FEAT_PERL) || defined(PROTO)
+/*
+ * Find window number "winnr" (counting top to bottom).
+ */
+ win_T *
+win_find_nr(int winnr)
+{
+ win_T *wp;
+
+ FOR_ALL_WINDOWS(wp)
+ if (--winnr == 0)
+ break;
+ return wp;
+}
+#endif
+
+#if ((defined(FEAT_PYTHON) || defined(FEAT_PYTHON3))) || defined(PROTO)
+/*
+ * Find the tabpage for window "win".
+ */
+ tabpage_T *
+win_find_tabpage(win_T *win)
+{
+ win_T *wp;
+ tabpage_T *tp;
+
+ FOR_ALL_TAB_WINDOWS(tp, wp)
+ if (wp == win)
+ return tp;
+ return NULL;
+}
+#endif
+
+/*
+ * Move to window above or below "count" times.
+ */
+ static void
+win_goto_ver(
+ int up, /* TRUE to go to win above */
+ long count)
+{
+ frame_T *fr;
+ frame_T *nfr;
+ frame_T *foundfr;
+
+ foundfr = curwin->w_frame;
+ while (count--)
+ {
+ /*
+ * First go upwards in the tree of frames until we find a upwards or
+ * downwards neighbor.
+ */
+ fr = foundfr;
+ for (;;)
+ {
+ if (fr == topframe)
+ goto end;
+ if (up)
+ nfr = fr->fr_prev;
+ else
+ nfr = fr->fr_next;
+ if (fr->fr_parent->fr_layout == FR_COL && nfr != NULL)
+ break;
+ fr = fr->fr_parent;
+ }
+
+ /*
+ * Now go downwards to find the bottom or top frame in it.
+ */
+ for (;;)
+ {
+ if (nfr->fr_layout == FR_LEAF)
+ {
+ foundfr = nfr;
+ break;
+ }
+ fr = nfr->fr_child;
+ if (nfr->fr_layout == FR_ROW)
+ {
+ /* Find the frame at the cursor row. */
+ while (fr->fr_next != NULL
+ && frame2win(fr)->w_wincol + fr->fr_width
+ <= curwin->w_wincol + curwin->w_wcol)
+ fr = fr->fr_next;
+ }
+ if (nfr->fr_layout == FR_COL && up)
+ while (fr->fr_next != NULL)
+ fr = fr->fr_next;
+ nfr = fr;
+ }
+ }
+end:
+ if (foundfr != NULL)
+ win_goto(foundfr->fr_win);
+}
+
+/*
+ * Move to left or right window.
+ */
+ static void
+win_goto_hor(
+ int left, /* TRUE to go to left win */
+ long count)
+{
+ frame_T *fr;
+ frame_T *nfr;
+ frame_T *foundfr;
+
+ foundfr = curwin->w_frame;
+ while (count--)
+ {
+ /*
+ * First go upwards in the tree of frames until we find a left or
+ * right neighbor.
+ */
+ fr = foundfr;
+ for (;;)
+ {
+ if (fr == topframe)
+ goto end;
+ if (left)
+ nfr = fr->fr_prev;
+ else
+ nfr = fr->fr_next;
+ if (fr->fr_parent->fr_layout == FR_ROW && nfr != NULL)
+ break;
+ fr = fr->fr_parent;
+ }
+
+ /*
+ * Now go downwards to find the leftmost or rightmost frame in it.
+ */
+ for (;;)
+ {
+ if (nfr->fr_layout == FR_LEAF)
+ {
+ foundfr = nfr;
+ break;
+ }
+ fr = nfr->fr_child;
+ if (nfr->fr_layout == FR_COL)
+ {
+ /* Find the frame at the cursor row. */
+ while (fr->fr_next != NULL
+ && frame2win(fr)->w_winrow + fr->fr_height
+ <= curwin->w_winrow + curwin->w_wrow)
+ fr = fr->fr_next;
+ }
+ if (nfr->fr_layout == FR_ROW && left)
+ while (fr->fr_next != NULL)
+ fr = fr->fr_next;
+ nfr = fr;
+ }
+ }
+end:
+ if (foundfr != NULL)
+ win_goto(foundfr->fr_win);
+}
+
+/*
+ * Make window "wp" the current window.
+ */
+ void
+win_enter(win_T *wp, int undo_sync)
+{
+ win_enter_ext(wp, undo_sync, FALSE, FALSE, TRUE, TRUE);
+}
+
+/*
+ * Make window wp the current window.
+ * Can be called with "curwin_invalid" TRUE, which means that curwin has just
+ * been closed and isn't valid.
+ */
+ static void
+win_enter_ext(
+ win_T *wp,
+ int undo_sync,
+ int curwin_invalid,
+ int trigger_new_autocmds,
+ int trigger_enter_autocmds,
+ int trigger_leave_autocmds)
+{
+ int other_buffer = FALSE;
+
+ if (wp == curwin && !curwin_invalid) /* nothing to do */
+ return;
+
+#ifdef FEAT_JOB_CHANNEL
+ if (!curwin_invalid)
+ leaving_window(curwin);
+#endif
+
+ if (!curwin_invalid && trigger_leave_autocmds)
+ {
+ /*
+ * Be careful: If autocommands delete the window, return now.
+ */
+ if (wp->w_buffer != curbuf)
+ {
+ apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, FALSE, curbuf);
+ other_buffer = TRUE;
+ if (!win_valid(wp))
+ return;
+ }
+ apply_autocmds(EVENT_WINLEAVE, NULL, NULL, FALSE, curbuf);
+ if (!win_valid(wp))
+ return;
+#ifdef FEAT_EVAL
+ /* autocmds may abort script processing */
+ if (aborting())
+ return;
+#endif
+ }
+
+ /* sync undo before leaving the current buffer */
+ if (undo_sync && curbuf != wp->w_buffer)
+ u_sync(FALSE);
+
+ /* Might need to scroll the old window before switching, e.g., when the
+ * cursor was moved. */
+ update_topline();
+
+ /* may have to copy the buffer options when 'cpo' contains 'S' */
+ if (wp->w_buffer != curbuf)
+ buf_copy_options(wp->w_buffer, BCO_ENTER | BCO_NOHELP);
+ if (!curwin_invalid)
+ {
+ prevwin = curwin; /* remember for CTRL-W p */
+ curwin->w_redr_status = TRUE;
+ }
+ curwin = wp;
+ curbuf = wp->w_buffer;
+ check_cursor();
+ if (!virtual_active())
+ curwin->w_cursor.coladd = 0;
+ changed_line_abv_curs(); /* assume cursor position needs updating */
+
+ if (curwin->w_localdir != NULL)
+ {
+ /* Window has a local directory: Save current directory as global
+ * directory (unless that was done already) and change to the local
+ * directory. */
+ if (globaldir == NULL)
+ {
+ char_u cwd[MAXPATHL];
+
+ if (mch_dirname(cwd, MAXPATHL) == OK)
+ globaldir = vim_strsave(cwd);
+ }
+ if (mch_chdir((char *)curwin->w_localdir) == 0)
+ shorten_fnames(TRUE);
+ }
+ else if (globaldir != NULL)
+ {
+ /* Window doesn't have a local directory and we are not in the global
+ * directory: Change to the global directory. */
+ vim_ignored = mch_chdir((char *)globaldir);
+ VIM_CLEAR(globaldir);
+ shorten_fnames(TRUE);
+ }
+
+#ifdef FEAT_JOB_CHANNEL
+ entering_window(curwin);
+#endif
+ if (trigger_new_autocmds)
+ apply_autocmds(EVENT_WINNEW, NULL, NULL, FALSE, curbuf);
+ if (trigger_enter_autocmds)
+ {
+ apply_autocmds(EVENT_WINENTER, NULL, NULL, FALSE, curbuf);
+ if (other_buffer)
+ apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf);
+ }
+
+#ifdef FEAT_TITLE
+ maketitle();
+#endif
+ curwin->w_redr_status = TRUE;
+ redraw_tabline = TRUE;
+ if (restart_edit)
+ redraw_later(VALID); /* causes status line redraw */
+
+ /* set window height to desired minimal value */
+ if (curwin->w_height < p_wh && !curwin->w_p_wfh)
+ win_setheight((int)p_wh);
+ else if (curwin->w_height == 0)
+ win_setheight(1);
+
+ /* set window width to desired minimal value */
+ if (curwin->w_width < p_wiw && !curwin->w_p_wfw)
+ win_setwidth((int)p_wiw);
+
+#ifdef FEAT_MOUSE
+ setmouse(); /* in case jumped to/from help buffer */
+#endif
+
+ /* Change directories when the 'acd' option is set. */
+ DO_AUTOCHDIR;
+}
+
+
+/*
+ * Jump to the first open window that contains buffer "buf", if one exists.
+ * Returns a pointer to the window found, otherwise NULL.
+ */
+ win_T *
+buf_jump_open_win(buf_T *buf)
+{
+ win_T *wp = NULL;
+
+ if (curwin->w_buffer == buf)
+ wp = curwin;
+ else
+ FOR_ALL_WINDOWS(wp)
+ if (wp->w_buffer == buf)
+ break;
+ if (wp != NULL)
+ win_enter(wp, FALSE);
+ return wp;
+}
+
+/*
+ * Jump to the first open window in any tab page that contains buffer "buf",
+ * if one exists.
+ * Returns a pointer to the window found, otherwise NULL.
+ */
+ win_T *
+buf_jump_open_tab(buf_T *buf)
+{
+ win_T *wp = buf_jump_open_win(buf);
+ tabpage_T *tp;
+
+ if (wp != NULL)
+ return wp;
+
+ FOR_ALL_TABPAGES(tp)
+ if (tp != curtab)
+ {
+ for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next)
+ if (wp->w_buffer == buf)
+ break;
+ if (wp != NULL)
+ {
+ goto_tabpage_win(tp, wp);
+ if (curwin != wp)
+ wp = NULL; /* something went wrong */
+ break;
+ }
+ }
+ return wp;
+}
+
+static int last_win_id = LOWEST_WIN_ID - 1;
+
+/*
+ * Allocate a window structure and link it in the window list when "hidden" is
+ * FALSE.
+ */
+ static win_T *
+win_alloc(win_T *after UNUSED, int hidden UNUSED)
+{
+ win_T *new_wp;
+
+ /*
+ * allocate window structure and linesizes arrays
+ */
+ new_wp = (win_T *)alloc_clear((unsigned)sizeof(win_T));
+ if (new_wp == NULL)
+ return NULL;
+
+ if (win_alloc_lines(new_wp) == FAIL)
+ {
+ vim_free(new_wp);
+ return NULL;
+ }
+
+ new_wp->w_id = ++last_win_id;
+
+#ifdef FEAT_EVAL
+ /* init w: variables */
+ new_wp->w_vars = dict_alloc();
+ if (new_wp->w_vars == NULL)
+ {
+ win_free_lsize(new_wp);
+ vim_free(new_wp);
+ return NULL;
+ }
+ init_var_dict(new_wp->w_vars, &new_wp->w_winvar, VAR_SCOPE);
+#endif
+
+ /* Don't execute autocommands while the window is not properly
+ * initialized yet. gui_create_scrollbar() may trigger a FocusGained
+ * event. */
+ block_autocmds();
+
+ /*
+ * link the window in the window list
+ */
+ if (!hidden)
+ win_append(after, new_wp);
+ new_wp->w_wincol = 0;
+ new_wp->w_width = Columns;
+
+ /* position the display and the cursor at the top of the file. */
+ new_wp->w_topline = 1;
+#ifdef FEAT_DIFF
+ new_wp->w_topfill = 0;
+#endif
+ new_wp->w_botline = 2;
+ new_wp->w_cursor.lnum = 1;
+ new_wp->w_scbind_pos = 1;
+
+ // use global option value for global-local options
+ new_wp->w_p_so = -1;
+ new_wp->w_p_siso = -1;
+
+ /* We won't calculate w_fraction until resizing the window */
+ new_wp->w_fraction = 0;
+ new_wp->w_prev_fraction_row = -1;
+
+#ifdef FEAT_GUI
+ if (gui.in_use)
+ {
+ gui_create_scrollbar(&new_wp->w_scrollbars[SBAR_LEFT],
+ SBAR_LEFT, new_wp);
+ gui_create_scrollbar(&new_wp->w_scrollbars[SBAR_RIGHT],
+ SBAR_RIGHT, new_wp);
+ }
+#endif
+#ifdef FEAT_FOLDING
+ foldInitWin(new_wp);
+#endif
+ unblock_autocmds();
+#ifdef FEAT_SEARCH_EXTRA
+ new_wp->w_match_head = NULL;
+ new_wp->w_next_match_id = 4;
+#endif
+ return new_wp;
+}
+
+/*
+ * Remove window 'wp' from the window list and free the structure.
+ */
+ static void
+win_free(
+ win_T *wp,
+ tabpage_T *tp) /* tab page "win" is in, NULL for current */
+{
+ int i;
+ buf_T *buf;
+ wininfo_T *wip;
+
+#ifdef FEAT_FOLDING
+ clearFolding(wp);
+#endif
+
+ /* reduce the reference count to the argument list. */
+ alist_unlink(wp->w_alist);
+
+ /* Don't execute autocommands while the window is halfway being deleted.
+ * gui_mch_destroy_scrollbar() may trigger a FocusGained event. */
+ block_autocmds();
+
+#ifdef FEAT_LUA
+ lua_window_free(wp);
+#endif
+
+#ifdef FEAT_MZSCHEME
+ mzscheme_window_free(wp);
+#endif
+
+#ifdef FEAT_PERL
+ perl_win_free(wp);
+#endif
+
+#ifdef FEAT_PYTHON
+ python_window_free(wp);
+#endif
+
+#ifdef FEAT_PYTHON3
+ python3_window_free(wp);
+#endif
+
+#ifdef FEAT_TCL
+ tcl_window_free(wp);
+#endif
+
+#ifdef FEAT_RUBY
+ ruby_window_free(wp);
+#endif
+
+ clear_winopt(&wp->w_onebuf_opt);
+ clear_winopt(&wp->w_allbuf_opt);
+
+#ifdef FEAT_EVAL
+ vars_clear(&wp->w_vars->dv_hashtab); /* free all w: variables */
+ hash_init(&wp->w_vars->dv_hashtab);
+ unref_var_dict(wp->w_vars);
+#endif
+
+ {
+ tabpage_T *ttp;
+
+ if (prevwin == wp)
+ prevwin = NULL;
+ FOR_ALL_TABPAGES(ttp)
+ if (ttp->tp_prevwin == wp)
+ ttp->tp_prevwin = NULL;
+ }
+ win_free_lsize(wp);
+
+ for (i = 0; i < wp->w_tagstacklen; ++i)
+ vim_free(wp->w_tagstack[i].tagname);
+
+ vim_free(wp->w_localdir);
+
+ /* Remove the window from the b_wininfo lists, it may happen that the
+ * freed memory is re-used for another window. */
+ FOR_ALL_BUFFERS(buf)
+ for (wip = buf->b_wininfo; wip != NULL; wip = wip->wi_next)
+ if (wip->wi_win == wp)
+ wip->wi_win = NULL;
+
+#ifdef FEAT_SEARCH_EXTRA
+ clear_matches(wp);
+#endif
+
+#ifdef FEAT_JUMPLIST
+ free_jumplist(wp);
+#endif
+
+#ifdef FEAT_QUICKFIX
+ qf_free_all(wp);
+#endif
+
+#ifdef FEAT_GUI
+ if (gui.in_use)
+ {
+ gui_mch_destroy_scrollbar(&wp->w_scrollbars[SBAR_LEFT]);
+ gui_mch_destroy_scrollbar(&wp->w_scrollbars[SBAR_RIGHT]);
+ }
+#endif /* FEAT_GUI */
+
+#ifdef FEAT_MENU
+ remove_winbar(wp);
+#endif
+
+#ifdef FEAT_SYN_HL
+ vim_free(wp->w_p_cc_cols);
+#endif
+
+ if (wp != aucmd_win)
+ win_remove(wp, tp);
+ if (autocmd_busy)
+ {
+ wp->w_next = au_pending_free_win;
+ au_pending_free_win = wp;
+ }
+ else
+ vim_free(wp);
+
+ unblock_autocmds();
+}
+
+/*
+ * Append window "wp" in the window list after window "after".
+ */
+ void
+win_append(win_T *after, win_T *wp)
+{
+ win_T *before;
+
+ if (after == NULL) /* after NULL is in front of the first */
+ before = firstwin;
+ else
+ before = after->w_next;
+
+ wp->w_next = before;
+ wp->w_prev = after;
+ if (after == NULL)
+ firstwin = wp;
+ else
+ after->w_next = wp;
+ if (before == NULL)
+ lastwin = wp;
+ else
+ before->w_prev = wp;
+}
+
+/*
+ * Remove a window from the window list.
+ */
+ void
+win_remove(
+ win_T *wp,
+ tabpage_T *tp) /* tab page "win" is in, NULL for current */
+{
+ if (wp->w_prev != NULL)
+ wp->w_prev->w_next = wp->w_next;
+ else if (tp == NULL)
+ firstwin = curtab->tp_firstwin = wp->w_next;
+ else
+ tp->tp_firstwin = wp->w_next;
+
+ if (wp->w_next != NULL)
+ wp->w_next->w_prev = wp->w_prev;
+ else if (tp == NULL)
+ lastwin = curtab->tp_lastwin = wp->w_prev;
+ else
+ tp->tp_lastwin = wp->w_prev;
+}
+
+/*
+ * Append frame "frp" in a frame list after frame "after".
+ */
+ static void
+frame_append(frame_T *after, frame_T *frp)
+{
+ frp->fr_next = after->fr_next;
+ after->fr_next = frp;
+ if (frp->fr_next != NULL)
+ frp->fr_next->fr_prev = frp;
+ frp->fr_prev = after;
+}
+
+/*
+ * Insert frame "frp" in a frame list before frame "before".
+ */
+ static void
+frame_insert(frame_T *before, frame_T *frp)
+{
+ frp->fr_next = before;
+ frp->fr_prev = before->fr_prev;
+ before->fr_prev = frp;
+ if (frp->fr_prev != NULL)
+ frp->fr_prev->fr_next = frp;
+ else
+ frp->fr_parent->fr_child = frp;
+}
+
+/*
+ * Remove a frame from a frame list.
+ */
+ static void
+frame_remove(frame_T *frp)
+{
+ if (frp->fr_prev != NULL)
+ frp->fr_prev->fr_next = frp->fr_next;
+ else
+ {
+ frp->fr_parent->fr_child = frp->fr_next;
+ /* special case: topframe->fr_child == frp */
+ if (topframe->fr_child == frp)
+ topframe->fr_child = frp->fr_next;
+ }
+ if (frp->fr_next != NULL)
+ frp->fr_next->fr_prev = frp->fr_prev;
+}
+
+/*
+ * Allocate w_lines[] for window "wp".
+ * Return FAIL for failure, OK for success.
+ */
+ int
+win_alloc_lines(win_T *wp)
+{
+ wp->w_lines_valid = 0;
+ wp->w_lines = (wline_T *)alloc_clear((unsigned)(Rows * sizeof(wline_T)));
+ if (wp->w_lines == NULL)
+ return FAIL;
+ return OK;
+}
+
+/*
+ * free lsize arrays for a window
+ */
+ void
+win_free_lsize(win_T *wp)
+{
+ /* TODO: why would wp be NULL here? */
+ if (wp != NULL)
+ VIM_CLEAR(wp->w_lines);
+}
+
+/*
+ * Called from win_new_shellsize() after Rows changed.
+ * This only does the current tab page, others must be done when made active.
+ */
+ void
+shell_new_rows(void)
+{
+ int h = (int)ROWS_AVAIL;
+
+ if (firstwin == NULL) /* not initialized yet */
+ return;
+ if (h < frame_minheight(topframe, NULL))
+ h = frame_minheight(topframe, NULL);
+
+ /* First try setting the heights of windows with 'winfixheight'. If
+ * that doesn't result in the right height, forget about that option. */
+ frame_new_height(topframe, h, FALSE, TRUE);
+ if (!frame_check_height(topframe, h))
+ frame_new_height(topframe, h, FALSE, FALSE);
+
+ (void)win_comp_pos(); /* recompute w_winrow and w_wincol */
+ compute_cmdrow();
+ curtab->tp_ch_used = p_ch;
+
+#if 0
+ /* Disabled: don't want making the screen smaller make a window larger. */
+ if (p_ea)
+ win_equal(curwin, FALSE, 'v');
+#endif
+}
+
+/*
+ * Called from win_new_shellsize() after Columns changed.
+ */
+ void
+shell_new_columns(void)
+{
+ if (firstwin == NULL) /* not initialized yet */
+ return;
+
+ /* First try setting the widths of windows with 'winfixwidth'. If that
+ * doesn't result in the right width, forget about that option. */
+ frame_new_width(topframe, (int)Columns, FALSE, TRUE);
+ if (!frame_check_width(topframe, Columns))
+ frame_new_width(topframe, (int)Columns, FALSE, FALSE);
+
+ (void)win_comp_pos(); /* recompute w_winrow and w_wincol */
+#if 0
+ /* Disabled: don't want making the screen smaller make a window larger. */
+ if (p_ea)
+ win_equal(curwin, FALSE, 'h');
+#endif
+}
+
+#if defined(FEAT_CMDWIN) || defined(PROTO)
+/*
+ * Save the size of all windows in "gap".
+ */
+ void
+win_size_save(garray_T *gap)
+
+{
+ win_T *wp;
+
+ ga_init2(gap, (int)sizeof(int), 1);
+ if (ga_grow(gap, win_count() * 2) == OK)
+ FOR_ALL_WINDOWS(wp)
+ {
+ ((int *)gap->ga_data)[gap->ga_len++] =
+ wp->w_width + wp->w_vsep_width;
+ ((int *)gap->ga_data)[gap->ga_len++] = wp->w_height;
+ }
+}
+
+/*
+ * Restore window sizes, but only if the number of windows is still the same.
+ * Does not free the growarray.
+ */
+ void
+win_size_restore(garray_T *gap)
+{
+ win_T *wp;
+ int i, j;
+
+ if (win_count() * 2 == gap->ga_len)
+ {
+ /* The order matters, because frames contain other frames, but it's
+ * difficult to get right. The easy way out is to do it twice. */
+ for (j = 0; j < 2; ++j)
+ {
+ i = 0;
+ FOR_ALL_WINDOWS(wp)
+ {
+ frame_setwidth(wp->w_frame, ((int *)gap->ga_data)[i++]);
+ win_setheight_win(((int *)gap->ga_data)[i++], wp);
+ }
+ }
+ /* recompute the window positions */
+ (void)win_comp_pos();
+ }
+}
+#endif /* FEAT_CMDWIN */
+
+/*
+ * Update the position for all windows, using the width and height of the
+ * frames.
+ * Returns the row just after the last window.
+ */
+ int
+win_comp_pos(void)
+{
+ int row = tabline_height();
+ int col = 0;
+
+ frame_comp_pos(topframe, &row, &col);
+ return row;
+}
+
+/*
+ * Update the position of the windows in frame "topfrp", using the width and
+ * height of the frames.
+ * "*row" and "*col" are the top-left position of the frame. They are updated
+ * to the bottom-right position plus one.
+ */
+ static void
+frame_comp_pos(frame_T *topfrp, int *row, int *col)
+{
+ win_T *wp;
+ frame_T *frp;
+ int startcol;
+ int startrow;
+ int h;
+
+ wp = topfrp->fr_win;
+ if (wp != NULL)
+ {
+ if (wp->w_winrow != *row || wp->w_wincol != *col)
+ {
+ /* position changed, redraw */
+ wp->w_winrow = *row;
+ wp->w_wincol = *col;
+ redraw_win_later(wp, NOT_VALID);
+ wp->w_redr_status = TRUE;
+ }
+ /* WinBar will not show if the window height is zero */
+ h = VISIBLE_HEIGHT(wp) + wp->w_status_height;
+ *row += h > topfrp->fr_height ? topfrp->fr_height : h;
+ *col += wp->w_width + wp->w_vsep_width;
+ }
+ else
+ {
+ startrow = *row;
+ startcol = *col;
+ FOR_ALL_FRAMES(frp, topfrp->fr_child)
+ {
+ if (topfrp->fr_layout == FR_ROW)
+ *row = startrow; /* all frames are at the same row */
+ else
+ *col = startcol; /* all frames are at the same col */
+ frame_comp_pos(frp, row, col);
+ }
+ }
+}
+
+/*
+ * Set current window height and take care of repositioning other windows to
+ * fit around it.
+ */
+ void
+win_setheight(int height)
+{
+ win_setheight_win(height, curwin);
+}
+
+/*
+ * Set the window height of window "win" and take care of repositioning other
+ * windows to fit around it.
+ */
+ void
+win_setheight_win(int height, win_T *win)
+{
+ int row;
+
+ if (win == curwin)
+ {
+ /* Always keep current window at least one line high, even when
+ * 'winminheight' is zero. */
+ if (height < p_wmh)
+ height = p_wmh;
+ if (height == 0)
+ height = 1;
+ height += WINBAR_HEIGHT(curwin);
+ }
+
+ frame_setheight(win->w_frame, height + win->w_status_height);
+
+ /* recompute the window positions */
+ row = win_comp_pos();
+
+ /*
+ * If there is extra space created between the last window and the command
+ * line, clear it.
+ */
+ if (full_screen && msg_scrolled == 0 && row < cmdline_row)
+ screen_fill(row, cmdline_row, 0, (int)Columns, ' ', ' ', 0);
+ cmdline_row = row;
+ msg_row = row;
+ msg_col = 0;
+
+ redraw_all_later(NOT_VALID);
+}
+
+/*
+ * Set the height of a frame to "height" and take care that all frames and
+ * windows inside it are resized. Also resize frames on the left and right if
+ * the are in the same FR_ROW frame.
+ *
+ * Strategy:
+ * If the frame is part of a FR_COL frame, try fitting the frame in that
+ * frame. If that doesn't work (the FR_COL frame is too small), recursively
+ * go to containing frames to resize them and make room.
+ * If the frame is part of a FR_ROW frame, all frames must be resized as well.
+ * Check for the minimal height of the FR_ROW frame.
+ * At the top level we can also use change the command line height.
+ */
+ static void
+frame_setheight(frame_T *curfrp, int height)
+{
+ int room; /* total number of lines available */
+ int take; /* number of lines taken from other windows */
+ int room_cmdline; /* lines available from cmdline */
+ int run;
+ frame_T *frp;
+ int h;
+ int room_reserved;
+
+ /* If the height already is the desired value, nothing to do. */
+ if (curfrp->fr_height == height)
+ return;
+
+ if (curfrp->fr_parent == NULL)
+ {
+ /* topframe: can only change the command line */
+ if (height > ROWS_AVAIL)
+ height = ROWS_AVAIL;
+ if (height > 0)
+ frame_new_height(curfrp, height, FALSE, FALSE);
+ }
+ else if (curfrp->fr_parent->fr_layout == FR_ROW)
+ {
+ /* Row of frames: Also need to resize frames left and right of this
+ * one. First check for the minimal height of these. */
+ h = frame_minheight(curfrp->fr_parent, NULL);
+ if (height < h)
+ height = h;
+ frame_setheight(curfrp->fr_parent, height);
+ }
+ else
+ {
+ /*
+ * Column of frames: try to change only frames in this column.
+ */
+ /*
+ * Do this twice:
+ * 1: compute room available, if it's not enough try resizing the
+ * containing frame.
+ * 2: compute the room available and adjust the height to it.
+ * Try not to reduce the height of a window with 'winfixheight' set.
+ */
+ for (run = 1; run <= 2; ++run)
+ {
+ room = 0;
+ room_reserved = 0;
+ FOR_ALL_FRAMES(frp, curfrp->fr_parent->fr_child)
+ {
+ if (frp != curfrp
+ && frp->fr_win != NULL
+ && frp->fr_win->w_p_wfh)
+ room_reserved += frp->fr_height;
+ room += frp->fr_height;
+ if (frp != curfrp)
+ room -= frame_minheight(frp, NULL);
+ }
+ if (curfrp->fr_width != Columns)
+ room_cmdline = 0;
+ else
+ {
+ room_cmdline = Rows - p_ch - (lastwin->w_winrow
+ + VISIBLE_HEIGHT(lastwin)
+ + lastwin->w_status_height);
+ if (room_cmdline < 0)
+ room_cmdline = 0;
+ }
+
+ if (height <= room + room_cmdline)
+ break;
+ if (run == 2 || curfrp->fr_width == Columns)
+ {
+ if (height > room + room_cmdline)
+ height = room + room_cmdline;
+ break;
+ }
+ frame_setheight(curfrp->fr_parent, height
+ + frame_minheight(curfrp->fr_parent, NOWIN) - (int)p_wmh - 1);
+ }
+
+ /*
+ * Compute the number of lines we will take from others frames (can be
+ * negative!).
+ */
+ take = height - curfrp->fr_height;
+
+ /* If there is not enough room, also reduce the height of a window
+ * with 'winfixheight' set. */
+ if (height > room + room_cmdline - room_reserved)
+ room_reserved = room + room_cmdline - height;
+ /* If there is only a 'winfixheight' window and making the
+ * window smaller, need to make the other window taller. */
+ if (take < 0 && room - curfrp->fr_height < room_reserved)
+ room_reserved = 0;
+
+ if (take > 0 && room_cmdline > 0)
+ {
+ /* use lines from cmdline first */
+ if (take < room_cmdline)
+ room_cmdline = take;
+ take -= room_cmdline;
+ topframe->fr_height += room_cmdline;
+ }
+
+ /*
+ * set the current frame to the new height
+ */
+ frame_new_height(curfrp, height, FALSE, FALSE);
+
+ /*
+ * First take lines from the frames after the current frame. If
+ * that is not enough, takes lines from frames above the current
+ * frame.
+ */
+ for (run = 0; run < 2; ++run)
+ {
+ if (run == 0)
+ frp = curfrp->fr_next; /* 1st run: start with next window */
+ else
+ frp = curfrp->fr_prev; /* 2nd run: start with prev window */
+ while (frp != NULL && take != 0)
+ {
+ h = frame_minheight(frp, NULL);
+ if (room_reserved > 0
+ && frp->fr_win != NULL
+ && frp->fr_win->w_p_wfh)
+ {
+ if (room_reserved >= frp->fr_height)
+ room_reserved -= frp->fr_height;
+ else
+ {
+ if (frp->fr_height - room_reserved > take)
+ room_reserved = frp->fr_height - take;
+ take -= frp->fr_height - room_reserved;
+ frame_new_height(frp, room_reserved, FALSE, FALSE);
+ room_reserved = 0;
+ }
+ }
+ else
+ {
+ if (frp->fr_height - take < h)
+ {
+ take -= frp->fr_height - h;
+ frame_new_height(frp, h, FALSE, FALSE);
+ }
+ else
+ {
+ frame_new_height(frp, frp->fr_height - take,
+ FALSE, FALSE);
+ take = 0;
+ }
+ }
+ if (run == 0)
+ frp = frp->fr_next;
+ else
+ frp = frp->fr_prev;
+ }
+ }
+ }
+}
+
+/*
+ * Set current window width and take care of repositioning other windows to
+ * fit around it.
+ */
+ void
+win_setwidth(int width)
+{
+ win_setwidth_win(width, curwin);
+}
+
+ void
+win_setwidth_win(int width, win_T *wp)
+{
+ /* Always keep current window at least one column wide, even when
+ * 'winminwidth' is zero. */
+ if (wp == curwin)
+ {
+ if (width < p_wmw)
+ width = p_wmw;
+ if (width == 0)
+ width = 1;
+ }
+
+ frame_setwidth(wp->w_frame, width + wp->w_vsep_width);
+
+ /* recompute the window positions */
+ (void)win_comp_pos();
+
+ redraw_all_later(NOT_VALID);
+}
+
+/*
+ * Set the width of a frame to "width" and take care that all frames and
+ * windows inside it are resized. Also resize frames above and below if the
+ * are in the same FR_ROW frame.
+ *
+ * Strategy is similar to frame_setheight().
+ */
+ static void
+frame_setwidth(frame_T *curfrp, int width)
+{
+ int room; /* total number of lines available */
+ int take; /* number of lines taken from other windows */
+ int run;
+ frame_T *frp;
+ int w;
+ int room_reserved;
+
+ /* If the width already is the desired value, nothing to do. */
+ if (curfrp->fr_width == width)
+ return;
+
+ if (curfrp->fr_parent == NULL)
+ /* topframe: can't change width */
+ return;
+
+ if (curfrp->fr_parent->fr_layout == FR_COL)
+ {
+ /* Column of frames: Also need to resize frames above and below of
+ * this one. First check for the minimal width of these. */
+ w = frame_minwidth(curfrp->fr_parent, NULL);
+ if (width < w)
+ width = w;
+ frame_setwidth(curfrp->fr_parent, width);
+ }
+ else
+ {
+ /*
+ * Row of frames: try to change only frames in this row.
+ *
+ * Do this twice:
+ * 1: compute room available, if it's not enough try resizing the
+ * containing frame.
+ * 2: compute the room available and adjust the width to it.
+ */
+ for (run = 1; run <= 2; ++run)
+ {
+ room = 0;
+ room_reserved = 0;
+ FOR_ALL_FRAMES(frp, curfrp->fr_parent->fr_child)
+ {
+ if (frp != curfrp
+ && frp->fr_win != NULL
+ && frp->fr_win->w_p_wfw)
+ room_reserved += frp->fr_width;
+ room += frp->fr_width;
+ if (frp != curfrp)
+ room -= frame_minwidth(frp, NULL);
+ }
+
+ if (width <= room)
+ break;
+ if (run == 2 || curfrp->fr_height >= ROWS_AVAIL)
+ {
+ if (width > room)
+ width = room;
+ break;
+ }
+ frame_setwidth(curfrp->fr_parent, width
+ + frame_minwidth(curfrp->fr_parent, NOWIN) - (int)p_wmw - 1);
+ }
+
+ /*
+ * Compute the number of lines we will take from others frames (can be
+ * negative!).
+ */
+ take = width - curfrp->fr_width;
+
+ /* If there is not enough room, also reduce the width of a window
+ * with 'winfixwidth' set. */
+ if (width > room - room_reserved)
+ room_reserved = room - width;
+ /* If there is only a 'winfixwidth' window and making the
+ * window smaller, need to make the other window narrower. */
+ if (take < 0 && room - curfrp->fr_width < room_reserved)
+ room_reserved = 0;
+
+ /*
+ * set the current frame to the new width
+ */
+ frame_new_width(curfrp, width, FALSE, FALSE);
+
+ /*
+ * First take lines from the frames right of the current frame. If
+ * that is not enough, takes lines from frames left of the current
+ * frame.
+ */
+ for (run = 0; run < 2; ++run)
+ {
+ if (run == 0)
+ frp = curfrp->fr_next; /* 1st run: start with next window */
+ else
+ frp = curfrp->fr_prev; /* 2nd run: start with prev window */
+ while (frp != NULL && take != 0)
+ {
+ w = frame_minwidth(frp, NULL);
+ if (room_reserved > 0
+ && frp->fr_win != NULL
+ && frp->fr_win->w_p_wfw)
+ {
+ if (room_reserved >= frp->fr_width)
+ room_reserved -= frp->fr_width;
+ else
+ {
+ if (frp->fr_width - room_reserved > take)
+ room_reserved = frp->fr_width - take;
+ take -= frp->fr_width - room_reserved;
+ frame_new_width(frp, room_reserved, FALSE, FALSE);
+ room_reserved = 0;
+ }
+ }
+ else
+ {
+ if (frp->fr_width - take < w)
+ {
+ take -= frp->fr_width - w;
+ frame_new_width(frp, w, FALSE, FALSE);
+ }
+ else
+ {
+ frame_new_width(frp, frp->fr_width - take,
+ FALSE, FALSE);
+ take = 0;
+ }
+ }
+ if (run == 0)
+ frp = frp->fr_next;
+ else
+ frp = frp->fr_prev;
+ }
+ }
+ }
+}
+
+/*
+ * Check 'winminheight' for a valid value and reduce it if needed.
+ */
+ void
+win_setminheight(void)
+{
+ int room;
+ int needed;
+ int first = TRUE;
+
+ // loop until there is a 'winminheight' that is possible
+ while (p_wmh > 0)
+ {
+ room = Rows - p_ch;
+ needed = frame_minheight(topframe, NULL);
+ if (room >= needed)
+ break;
+ --p_wmh;
+ if (first)
+ {
+ emsg(_(e_noroom));
+ first = FALSE;
+ }
+ }
+}
+
+/*
+ * Check 'winminwidth' for a valid value and reduce it if needed.
+ */
+ void
+win_setminwidth(void)
+{
+ int room;
+ int needed;
+ int first = TRUE;
+
+ // loop until there is a 'winminheight' that is possible
+ while (p_wmw > 0)
+ {
+ room = Columns;
+ needed = frame_minwidth(topframe, NULL);
+ if (room >= needed)
+ break;
+ --p_wmw;
+ if (first)
+ {
+ emsg(_(e_noroom));
+ first = FALSE;
+ }
+ }
+}
+
+#if defined(FEAT_MOUSE) || defined(PROTO)
+
+/*
+ * Status line of dragwin is dragged "offset" lines down (negative is up).
+ */
+ void
+win_drag_status_line(win_T *dragwin, int offset)
+{
+ frame_T *curfr;
+ frame_T *fr;
+ int room;
+ int row;
+ int up; /* if TRUE, drag status line up, otherwise down */
+ int n;
+
+ fr = dragwin->w_frame;
+ curfr = fr;
+ if (fr != topframe) /* more than one window */
+ {
+ fr = fr->fr_parent;
+ /* When the parent frame is not a column of frames, its parent should
+ * be. */
+ if (fr->fr_layout != FR_COL)
+ {
+ curfr = fr;
+ if (fr != topframe) /* only a row of windows, may drag statusline */
+ fr = fr->fr_parent;
+ }
+ }
+
+ /* If this is the last frame in a column, may want to resize the parent
+ * frame instead (go two up to skip a row of frames). */
+ while (curfr != topframe && curfr->fr_next == NULL)
+ {
+ if (fr != topframe)
+ fr = fr->fr_parent;
+ curfr = fr;
+ if (fr != topframe)
+ fr = fr->fr_parent;
+ }
+
+ if (offset < 0) /* drag up */
+ {
+ up = TRUE;
+ offset = -offset;
+ /* sum up the room of the current frame and above it */
+ if (fr == curfr)
+ {
+ /* only one window */
+ room = fr->fr_height - frame_minheight(fr, NULL);
+ }
+ else
+ {
+ room = 0;
+ for (fr = fr->fr_child; ; fr = fr->fr_next)
+ {
+ room += fr->fr_height - frame_minheight(fr, NULL);
+ if (fr == curfr)
+ break;
+ }
+ }
+ fr = curfr->fr_next; /* put fr at frame that grows */
+ }
+ else /* drag down */
+ {
+ up = FALSE;
+ /*
+ * Only dragging the last status line can reduce p_ch.
+ */
+ room = Rows - cmdline_row;
+ if (curfr->fr_next == NULL)
+ room -= 1;
+ else
+ room -= p_ch;
+ if (room < 0)
+ room = 0;
+ /* sum up the room of frames below of the current one */
+ FOR_ALL_FRAMES(fr, curfr->fr_next)
+ room += fr->fr_height - frame_minheight(fr, NULL);
+ fr = curfr; /* put fr at window that grows */
+ }
+
+ if (room < offset) /* Not enough room */
+ offset = room; /* Move as far as we can */
+ if (offset <= 0)
+ return;
+
+ /*
+ * Grow frame fr by "offset" lines.
+ * Doesn't happen when dragging the last status line up.
+ */
+ if (fr != NULL)
+ frame_new_height(fr, fr->fr_height + offset, up, FALSE);
+
+ if (up)
+ fr = curfr; /* current frame gets smaller */
+ else
+ fr = curfr->fr_next; /* next frame gets smaller */
+
+ /*
+ * Now make the other frames smaller.
+ */
+ while (fr != NULL && offset > 0)
+ {
+ n = frame_minheight(fr, NULL);
+ if (fr->fr_height - offset <= n)
+ {
+ offset -= fr->fr_height - n;
+ frame_new_height(fr, n, !up, FALSE);
+ }
+ else
+ {
+ frame_new_height(fr, fr->fr_height - offset, !up, FALSE);
+ break;
+ }
+ if (up)
+ fr = fr->fr_prev;
+ else
+ fr = fr->fr_next;
+ }
+ row = win_comp_pos();
+ screen_fill(row, cmdline_row, 0, (int)Columns, ' ', ' ', 0);
+ cmdline_row = row;
+ p_ch = Rows - cmdline_row;
+ if (p_ch < 1)
+ p_ch = 1;
+ curtab->tp_ch_used = p_ch;
+ redraw_all_later(SOME_VALID);
+ showmode();
+}
+
+/*
+ * Separator line of dragwin is dragged "offset" lines right (negative is left).
+ */
+ void
+win_drag_vsep_line(win_T *dragwin, int offset)
+{
+ frame_T *curfr;
+ frame_T *fr;
+ int room;
+ int left; /* if TRUE, drag separator line left, otherwise right */
+ int n;
+
+ fr = dragwin->w_frame;
+ if (fr == topframe) /* only one window (cannot happen?) */
+ return;
+ curfr = fr;
+ fr = fr->fr_parent;
+ /* When the parent frame is not a row of frames, its parent should be. */
+ if (fr->fr_layout != FR_ROW)
+ {
+ if (fr == topframe) /* only a column of windows (cannot happen?) */
+ return;
+ curfr = fr;
+ fr = fr->fr_parent;
+ }
+
+ /* If this is the last frame in a row, may want to resize a parent
+ * frame instead. */
+ while (curfr->fr_next == NULL)
+ {
+ if (fr == topframe)
+ break;
+ curfr = fr;
+ fr = fr->fr_parent;
+ if (fr != topframe)
+ {
+ curfr = fr;
+ fr = fr->fr_parent;
+ }
+ }
+
+ if (offset < 0) /* drag left */
+ {
+ left = TRUE;
+ offset = -offset;
+ /* sum up the room of the current frame and left of it */
+ room = 0;
+ for (fr = fr->fr_child; ; fr = fr->fr_next)
+ {
+ room += fr->fr_width - frame_minwidth(fr, NULL);
+ if (fr == curfr)
+ break;
+ }
+ fr = curfr->fr_next; /* put fr at frame that grows */
+ }
+ else /* drag right */
+ {
+ left = FALSE;
+ /* sum up the room of frames right of the current one */
+ room = 0;
+ FOR_ALL_FRAMES(fr, curfr->fr_next)
+ room += fr->fr_width - frame_minwidth(fr, NULL);
+ fr = curfr; /* put fr at window that grows */
+ }
+
+ if (room < offset) /* Not enough room */
+ offset = room; /* Move as far as we can */
+ if (offset <= 0) /* No room at all, quit. */
+ return;
+ if (fr == NULL)
+ return; /* Safety check, should not happen. */
+
+ /* grow frame fr by offset lines */
+ frame_new_width(fr, fr->fr_width + offset, left, FALSE);
+
+ /* shrink other frames: current and at the left or at the right */
+ if (left)
+ fr = curfr; /* current frame gets smaller */
+ else
+ fr = curfr->fr_next; /* next frame gets smaller */
+
+ while (fr != NULL && offset > 0)
+ {
+ n = frame_minwidth(fr, NULL);
+ if (fr->fr_width - offset <= n)
+ {
+ offset -= fr->fr_width - n;
+ frame_new_width(fr, n, !left, FALSE);
+ }
+ else
+ {
+ frame_new_width(fr, fr->fr_width - offset, !left, FALSE);
+ break;
+ }
+ if (left)
+ fr = fr->fr_prev;
+ else
+ fr = fr->fr_next;
+ }
+ (void)win_comp_pos();
+ redraw_all_later(NOT_VALID);
+}
+#endif /* FEAT_MOUSE */
+
+#define FRACTION_MULT 16384L
+
+/*
+ * Set wp->w_fraction for the current w_wrow and w_height.
+ * Has no effect when the window is less than two lines.
+ */
+ void
+set_fraction(win_T *wp)
+{
+ if (wp->w_height > 1)
+ wp->w_fraction = ((long)wp->w_wrow * FRACTION_MULT
+ + wp->w_height / 2) / (long)wp->w_height;
+}
+
+/*
+ * Set the height of a window.
+ * "height" excludes any window toolbar.
+ * This takes care of the things inside the window, not what happens to the
+ * window position, the frame or to other windows.
+ */
+ void
+win_new_height(win_T *wp, int height)
+{
+ int prev_height = wp->w_height;
+
+ /* Don't want a negative height. Happens when splitting a tiny window.
+ * Will equalize heights soon to fix it. */
+ if (height < 0)
+ height = 0;
+ if (wp->w_height == height)
+ return; /* nothing to do */
+
+ if (wp->w_height > 0)
+ {
+ if (wp == curwin)
+ /* w_wrow needs to be valid. When setting 'laststatus' this may
+ * call win_new_height() recursively. */
+ validate_cursor();
+ if (wp->w_height != prev_height)
+ return; /* Recursive call already changed the size, bail out here
+ to avoid the following to mess things up. */
+ if (wp->w_wrow != wp->w_prev_fraction_row)
+ set_fraction(wp);
+ }
+
+ wp->w_height = height;
+ wp->w_skipcol = 0;
+
+ /* There is no point in adjusting the scroll position when exiting. Some
+ * values might be invalid. */
+ if (!exiting)
+ scroll_to_fraction(wp, prev_height);
+}
+
+ void
+scroll_to_fraction(win_T *wp, int prev_height)
+{
+ linenr_T lnum;
+ int sline, line_size;
+ int height = wp->w_height;
+
+ /* Don't change w_topline when height is zero. Don't set w_topline when
+ * 'scrollbind' is set and this isn't the current window. */
+ if (height > 0 && (!wp->w_p_scb || wp == curwin))
+ {
+ /*
+ * Find a value for w_topline that shows the cursor at the same
+ * relative position in the window as before (more or less).
+ */
+ lnum = wp->w_cursor.lnum;
+ if (lnum < 1) /* can happen when starting up */
+ lnum = 1;
+ wp->w_wrow = ((long)wp->w_fraction * (long)height - 1L
+ + FRACTION_MULT / 2) / FRACTION_MULT;
+ line_size = plines_win_col(wp, lnum, (long)(wp->w_cursor.col)) - 1;
+ sline = wp->w_wrow - line_size;
+
+ if (sline >= 0)
+ {
+ /* Make sure the whole cursor line is visible, if possible. */
+ int rows = plines_win(wp, lnum, FALSE);
+
+ if (sline > wp->w_height - rows)
+ {
+ sline = wp->w_height - rows;
+ wp->w_wrow -= rows - line_size;
+ }
+ }
+
+ if (sline < 0)
+ {
+ /*
+ * Cursor line would go off top of screen if w_wrow was this high.
+ * Make cursor line the first line in the window. If not enough
+ * room use w_skipcol;
+ */
+ wp->w_wrow = line_size;
+ if (wp->w_wrow >= wp->w_height
+ && (wp->w_width - win_col_off(wp)) > 0)
+ {
+ wp->w_skipcol += wp->w_width - win_col_off(wp);
+ --wp->w_wrow;
+ while (wp->w_wrow >= wp->w_height)
+ {
+ wp->w_skipcol += wp->w_width - win_col_off(wp)
+ + win_col_off2(wp);
+ --wp->w_wrow;
+ }
+ }
+ set_topline(wp, lnum);
+ }
+ else if (sline > 0)
+ {
+ while (sline > 0 && lnum > 1)
+ {
+#ifdef FEAT_FOLDING
+ hasFoldingWin(wp, lnum, &lnum, NULL, TRUE, NULL);
+ if (lnum == 1)
+ {
+ /* first line in buffer is folded */
+ line_size = 1;
+ --sline;
+ break;
+ }
+#endif
+ --lnum;
+#ifdef FEAT_DIFF
+ if (lnum == wp->w_topline)
+ line_size = plines_win_nofill(wp, lnum, TRUE)
+ + wp->w_topfill;
+ else
+#endif
+ line_size = plines_win(wp, lnum, TRUE);
+ sline -= line_size;
+ }
+
+ if (sline < 0)
+ {
+ /*
+ * Line we want at top would go off top of screen. Use next
+ * line instead.
+ */
+#ifdef FEAT_FOLDING
+ hasFoldingWin(wp, lnum, NULL, &lnum, TRUE, NULL);
+#endif
+ lnum++;
+ wp->w_wrow -= line_size + sline;
+ }
+ else if (sline > 0)
+ {
+ /* First line of file reached, use that as topline. */
+ lnum = 1;
+ wp->w_wrow -= sline;
+ }
+
+ set_topline(wp, lnum);
+ }
+ }
+
+ if (wp == curwin)
+ {
+ if (get_scrolloff_value())
+ update_topline();
+ curs_columns(FALSE); /* validate w_wrow */
+ }
+ if (prev_height > 0)
+ wp->w_prev_fraction_row = wp->w_wrow;
+
+ win_comp_scroll(wp);
+ redraw_win_later(wp, SOME_VALID);
+ wp->w_redr_status = TRUE;
+ invalidate_botline_win(wp);
+}
+
+/*
+ * Set the width of a window.
+ */
+ void
+win_new_width(win_T *wp, int width)
+{
+ wp->w_width = width;
+ wp->w_lines_valid = 0;
+ changed_line_abv_curs_win(wp);
+ invalidate_botline_win(wp);
+ if (wp == curwin)
+ {
+ update_topline();
+ curs_columns(TRUE); /* validate w_wrow */
+ }
+ redraw_win_later(wp, NOT_VALID);
+ wp->w_redr_status = TRUE;
+}
+
+ void
+win_comp_scroll(win_T *wp)
+{
+ wp->w_p_scr = ((unsigned)wp->w_height >> 1);
+ if (wp->w_p_scr == 0)
+ wp->w_p_scr = 1;
+}
+
+/*
+ * command_height: called whenever p_ch has been changed
+ */
+ void
+command_height(void)
+{
+ int h;
+ frame_T *frp;
+ int old_p_ch = curtab->tp_ch_used;
+
+ /* Use the value of p_ch that we remembered. This is needed for when the
+ * GUI starts up, we can't be sure in what order things happen. And when
+ * p_ch was changed in another tab page. */
+ curtab->tp_ch_used = p_ch;
+
+ /* Find bottom frame with width of screen. */
+ frp = lastwin->w_frame;
+ while (frp->fr_width != Columns && frp->fr_parent != NULL)
+ frp = frp->fr_parent;
+
+ /* Avoid changing the height of a window with 'winfixheight' set. */
+ while (frp->fr_prev != NULL && frp->fr_layout == FR_LEAF
+ && frp->fr_win->w_p_wfh)
+ frp = frp->fr_prev;
+
+ if (starting != NO_SCREEN)
+ {
+ cmdline_row = Rows - p_ch;
+
+ if (p_ch > old_p_ch) /* p_ch got bigger */
+ {
+ while (p_ch > old_p_ch)
+ {
+ if (frp == NULL)
+ {
+ emsg(_(e_noroom));
+ p_ch = old_p_ch;
+ curtab->tp_ch_used = p_ch;
+ cmdline_row = Rows - p_ch;
+ break;
+ }
+ h = frp->fr_height - frame_minheight(frp, NULL);
+ if (h > p_ch - old_p_ch)
+ h = p_ch - old_p_ch;
+ old_p_ch += h;
+ frame_add_height(frp, -h);
+ frp = frp->fr_prev;
+ }
+
+ /* Recompute window positions. */
+ (void)win_comp_pos();
+
+ /* clear the lines added to cmdline */
+ if (full_screen)
+ screen_fill((int)(cmdline_row), (int)Rows, 0,
+ (int)Columns, ' ', ' ', 0);
+ msg_row = cmdline_row;
+ redraw_cmdline = TRUE;
+ return;
+ }
+
+ if (msg_row < cmdline_row)
+ msg_row = cmdline_row;
+ redraw_cmdline = TRUE;
+ }
+ frame_add_height(frp, (int)(old_p_ch - p_ch));
+
+ /* Recompute window positions. */
+ if (frp != lastwin->w_frame)
+ (void)win_comp_pos();
+}
+
+/*
+ * Resize frame "frp" to be "n" lines higher (negative for less high).
+ * Also resize the frames it is contained in.
+ */
+ static void
+frame_add_height(frame_T *frp, int n)
+{
+ frame_new_height(frp, frp->fr_height + n, FALSE, FALSE);
+ for (;;)
+ {
+ frp = frp->fr_parent;
+ if (frp == NULL)
+ break;
+ frp->fr_height += n;
+ }
+}
+
+/*
+ * Add or remove a status line for the bottom window(s), according to the
+ * value of 'laststatus'.
+ */
+ void
+last_status(
+ int morewin) /* pretend there are two or more windows */
+{
+ /* Don't make a difference between horizontal or vertical split. */
+ last_status_rec(topframe, (p_ls == 2
+ || (p_ls == 1 && (morewin || !ONE_WINDOW))));
+}
+
+ static void
+last_status_rec(frame_T *fr, int statusline)
+{
+ frame_T *fp;
+ win_T *wp;
+
+ if (fr->fr_layout == FR_LEAF)
+ {
+ wp = fr->fr_win;
+ if (wp->w_status_height != 0 && !statusline)
+ {
+ /* remove status line */
+ win_new_height(wp, wp->w_height + 1);
+ wp->w_status_height = 0;
+ comp_col();
+ }
+ else if (wp->w_status_height == 0 && statusline)
+ {
+ /* Find a frame to take a line from. */
+ fp = fr;
+ while (fp->fr_height <= frame_minheight(fp, NULL))
+ {
+ if (fp == topframe)
+ {
+ emsg(_(e_noroom));
+ return;
+ }
+ /* In a column of frames: go to frame above. If already at
+ * the top or in a row of frames: go to parent. */
+ if (fp->fr_parent->fr_layout == FR_COL && fp->fr_prev != NULL)
+ fp = fp->fr_prev;
+ else
+ fp = fp->fr_parent;
+ }
+ wp->w_status_height = 1;
+ if (fp != fr)
+ {
+ frame_new_height(fp, fp->fr_height - 1, FALSE, FALSE);
+ frame_fix_height(wp);
+ (void)win_comp_pos();
+ }
+ else
+ win_new_height(wp, wp->w_height - 1);
+ comp_col();
+ redraw_all_later(SOME_VALID);
+ }
+ }
+ else if (fr->fr_layout == FR_ROW)
+ {
+ /* vertically split windows, set status line for each one */
+ FOR_ALL_FRAMES(fp, fr->fr_child)
+ last_status_rec(fp, statusline);
+ }
+ else
+ {
+ /* horizontally split window, set status line for last one */
+ for (fp = fr->fr_child; fp->fr_next != NULL; fp = fp->fr_next)
+ ;
+ last_status_rec(fp, statusline);
+ }
+}
+
+/*
+ * Return the number of lines used by the tab page line.
+ */
+ int
+tabline_height(void)
+{
+#ifdef FEAT_GUI_TABLINE
+ /* When the GUI has the tabline then this always returns zero. */
+ if (gui_use_tabline())
+ return 0;
+#endif
+ switch (p_stal)
+ {
+ case 0: return 0;
+ case 1: return (first_tabpage->tp_next == NULL) ? 0 : 1;
+ }
+ return 1;
+}
+
+#if defined(FEAT_SEARCHPATH) || defined(PROTO)
+/*
+ * Get the file name at the cursor.
+ * If Visual mode is active, use the selected text if it's in one line.
+ * Returns the name in allocated memory, NULL for failure.
+ */
+ char_u *
+grab_file_name(long count, linenr_T *file_lnum)
+{
+ int options = FNAME_MESS|FNAME_EXP|FNAME_REL|FNAME_UNESC;
+
+ if (VIsual_active)
+ {
+ int len;
+ char_u *ptr;
+
+ if (get_visual_text(NULL, &ptr, &len) == FAIL)
+ return NULL;
+ return find_file_name_in_path(ptr, len, options,
+ count, curbuf->b_ffname);
+ }
+ return file_name_at_cursor(options | FNAME_HYP, count, file_lnum);
+}
+
+/*
+ * Return the file name under or after the cursor.
+ *
+ * The 'path' option is searched if the file name is not absolute.
+ * The string returned has been alloc'ed and should be freed by the caller.
+ * NULL is returned if the file name or file is not found.
+ *
+ * options:
+ * FNAME_MESS give error messages
+ * FNAME_EXP expand to path
+ * FNAME_HYP check for hypertext link
+ * FNAME_INCL apply "includeexpr"
+ */
+ char_u *
+file_name_at_cursor(int options, long count, linenr_T *file_lnum)
+{
+ return file_name_in_line(ml_get_curline(),
+ curwin->w_cursor.col, options, count, curbuf->b_ffname,
+ file_lnum);
+}
+
+/*
+ * Return the name of the file under or after ptr[col].
+ * Otherwise like file_name_at_cursor().
+ */
+ char_u *
+file_name_in_line(
+ char_u *line,
+ int col,
+ int options,
+ long count,
+ char_u *rel_fname, /* file we are searching relative to */
+ linenr_T *file_lnum) /* line number after the file name */
+{
+ char_u *ptr;
+ int len;
+ int in_type = TRUE;
+ int is_url = FALSE;
+
+ /*
+ * search forward for what could be the start of a file name
+ */
+ ptr = line + col;
+ while (*ptr != NUL && !vim_isfilec(*ptr))
+ MB_PTR_ADV(ptr);
+ if (*ptr == NUL) /* nothing found */
+ {
+ if (options & FNAME_MESS)
+ emsg(_("E446: No file name under cursor"));
+ return NULL;
+ }
+
+ /*
+ * Search backward for first char of the file name.
+ * Go one char back to ":" before "//" even when ':' is not in 'isfname'.
+ */
+ while (ptr > line)
+ {
+ if (has_mbyte && (len = (*mb_head_off)(line, ptr - 1)) > 0)
+ ptr -= len + 1;
+ else if (vim_isfilec(ptr[-1])
+ || ((options & FNAME_HYP) && path_is_url(ptr - 1)))
+ --ptr;
+ else
+ break;
+ }
+
+ /*
+ * Search forward for the last char of the file name.
+ * Also allow "://" when ':' is not in 'isfname'.
+ */
+ len = 0;
+ while (vim_isfilec(ptr[len]) || (ptr[len] == '\\' && ptr[len + 1] == ' ')
+ || ((options & FNAME_HYP) && path_is_url(ptr + len))
+ || (is_url && vim_strchr((char_u *)"?&=", ptr[len]) != NULL))
+ {
+ /* After type:// we also include ?, & and = as valid characters, so that
+ * http://google.com?q=this&that=ok works. */
+ if ((ptr[len] >= 'A' && ptr[len] <= 'Z') || (ptr[len] >= 'a' && ptr[len] <= 'z'))
+ {
+ if (in_type && path_is_url(ptr + len + 1))
+ is_url = TRUE;
+ }
+ else
+ in_type = FALSE;
+
+ if (ptr[len] == '\\')
+ /* Skip over the "\" in "\ ". */
+ ++len;
+ if (has_mbyte)
+ len += (*mb_ptr2len)(ptr + len);
+ else
+ ++len;
+ }
+
+ /*
+ * If there is trailing punctuation, remove it.
+ * But don't remove "..", could be a directory name.
+ */
+ if (len > 2 && vim_strchr((char_u *)".,:;!", ptr[len - 1]) != NULL
+ && ptr[len - 2] != '.')
+ --len;
+
+ if (file_lnum != NULL)
+ {
+ char_u *p;
+
+ /* Get the number after the file name and a separator character */
+ p = ptr + len;
+ p = skipwhite(p);
+ if (*p != NUL)
+ {
+ if (!isdigit(*p))
+ ++p; /* skip the separator */
+ p = skipwhite(p);
+ if (isdigit(*p))
+ *file_lnum = (int)getdigits(&p);
+ }
+ }
+
+ return find_file_name_in_path(ptr, len, options, count, rel_fname);
+}
+
+# if defined(FEAT_FIND_ID) && defined(FEAT_EVAL)
+ static char_u *
+eval_includeexpr(char_u *ptr, int len)
+{
+ char_u *res;
+
+ set_vim_var_string(VV_FNAME, ptr, len);
+ res = eval_to_string_safe(curbuf->b_p_inex, NULL,
+ was_set_insecurely((char_u *)"includeexpr", OPT_LOCAL));
+ set_vim_var_string(VV_FNAME, NULL, 0);
+ return res;
+}
+#endif
+
+/*
+ * Return the name of the file ptr[len] in 'path'.
+ * Otherwise like file_name_at_cursor().
+ */
+ char_u *
+find_file_name_in_path(
+ char_u *ptr,
+ int len,
+ int options,
+ long count,
+ char_u *rel_fname) /* file we are searching relative to */
+{
+ char_u *file_name;
+ int c;
+# if defined(FEAT_FIND_ID) && defined(FEAT_EVAL)
+ char_u *tofree = NULL;
+
+ if ((options & FNAME_INCL) && *curbuf->b_p_inex != NUL)
+ {
+ tofree = eval_includeexpr(ptr, len);
+ if (tofree != NULL)
+ {
+ ptr = tofree;
+ len = (int)STRLEN(ptr);
+ }
+ }
+# endif
+
+ if (options & FNAME_EXP)
+ {
+ file_name = find_file_in_path(ptr, len, options & ~FNAME_MESS,
+ TRUE, rel_fname);
+
+# if defined(FEAT_FIND_ID) && defined(FEAT_EVAL)
+ /*
+ * If the file could not be found in a normal way, try applying
+ * 'includeexpr' (unless done already).
+ */
+ if (file_name == NULL
+ && !(options & FNAME_INCL) && *curbuf->b_p_inex != NUL)
+ {
+ tofree = eval_includeexpr(ptr, len);
+ if (tofree != NULL)
+ {
+ ptr = tofree;
+ len = (int)STRLEN(ptr);
+ file_name = find_file_in_path(ptr, len, options & ~FNAME_MESS,
+ TRUE, rel_fname);
+ }
+ }
+# endif
+ if (file_name == NULL && (options & FNAME_MESS))
+ {
+ c = ptr[len];
+ ptr[len] = NUL;
+ semsg(_("E447: Can't find file \"%s\" in path"), ptr);
+ ptr[len] = c;
+ }
+
+ /* Repeat finding the file "count" times. This matters when it
+ * appears several times in the path. */
+ while (file_name != NULL && --count > 0)
+ {
+ vim_free(file_name);
+ file_name = find_file_in_path(ptr, len, options, FALSE, rel_fname);
+ }
+ }
+ else
+ file_name = vim_strnsave(ptr, len);
+
+# if defined(FEAT_FIND_ID) && defined(FEAT_EVAL)
+ vim_free(tofree);
+# endif
+
+ return file_name;
+}
+#endif /* FEAT_SEARCHPATH */
+
+/*
+ * Check if the "://" of a URL is at the pointer, return URL_SLASH.
+ * Also check for ":\\", which MS Internet Explorer accepts, return
+ * URL_BACKSLASH.
+ */
+ static int
+path_is_url(char_u *p)
+{
+ if (STRNCMP(p, "://", (size_t)3) == 0)
+ return URL_SLASH;
+ else if (STRNCMP(p, ":\\\\", (size_t)3) == 0)
+ return URL_BACKSLASH;
+ return 0;
+}
+
+/*
+ * Check if "fname" starts with "name://". Return URL_SLASH if it does.
+ * Return URL_BACKSLASH for "name:\\".
+ * Return zero otherwise.
+ */
+ int
+path_with_url(char_u *fname)
+{
+ char_u *p;
+
+ for (p = fname; isalpha(*p); ++p)
+ ;
+ return path_is_url(p);
+}
+
+/*
+ * Return TRUE if "name" is a full (absolute) path name or URL.
+ */
+ int
+vim_isAbsName(char_u *name)
+{
+ return (path_with_url(name) != 0 || mch_isFullName(name));
+}
+
+/*
+ * Get absolute file name into buffer "buf[len]".
+ *
+ * return FAIL for failure, OK otherwise
+ */
+ int
+vim_FullName(
+ char_u *fname,
+ char_u *buf,
+ int len,
+ int force) /* force expansion even when already absolute */
+{
+ int retval = OK;
+ int url;
+
+ *buf = NUL;
+ if (fname == NULL)
+ return FAIL;
+
+ url = path_with_url(fname);
+ if (!url)
+ retval = mch_FullName(fname, buf, len, force);
+ if (url || retval == FAIL)
+ {
+ /* something failed; use the file name (truncate when too long) */
+ vim_strncpy(buf, fname, len - 1);
+ }
+#if defined(MSWIN)
+ slash_adjust(buf);
+#endif
+ return retval;
+}
+
+/*
+ * Return the minimal number of rows that is needed on the screen to display
+ * the current number of windows.
+ */
+ int
+min_rows(void)
+{
+ int total;
+ tabpage_T *tp;
+ int n;
+
+ if (firstwin == NULL) /* not initialized yet */
+ return MIN_LINES;
+
+ total = 0;
+ FOR_ALL_TABPAGES(tp)
+ {
+ n = frame_minheight(tp->tp_topframe, NULL);
+ if (total < n)
+ total = n;
+ }
+ total += tabline_height();
+ total += 1; /* count the room for the command line */
+ return total;
+}
+
+/*
+ * Return TRUE if there is only one window (in the current tab page), not
+ * counting a help or preview window, unless it is the current window.
+ * Does not count "aucmd_win".
+ */
+ int
+only_one_window(void)
+{
+ int count = 0;
+ win_T *wp;
+
+ /* If there is another tab page there always is another window. */
+ if (first_tabpage->tp_next != NULL)
+ return FALSE;
+
+ FOR_ALL_WINDOWS(wp)
+ if (wp->w_buffer != NULL
+ && (!((bt_help(wp->w_buffer) && !bt_help(curbuf))
+# ifdef FEAT_QUICKFIX
+ || wp->w_p_pvw
+# endif
+ ) || wp == curwin) && wp != aucmd_win)
+ ++count;
+ return (count <= 1);
+}
+
+/*
+ * Correct the cursor line number in other windows. Used after changing the
+ * current buffer, and before applying autocommands.
+ * When "do_curwin" is TRUE, also check current window.
+ */
+ void
+check_lnums(int do_curwin)
+{
+ win_T *wp;
+ tabpage_T *tp;
+
+ FOR_ALL_TAB_WINDOWS(tp, wp)
+ if ((do_curwin || wp != curwin) && wp->w_buffer == curbuf)
+ {
+ if (wp->w_cursor.lnum > curbuf->b_ml.ml_line_count)
+ wp->w_cursor.lnum = curbuf->b_ml.ml_line_count;
+ if (wp->w_topline > curbuf->b_ml.ml_line_count)
+ wp->w_topline = curbuf->b_ml.ml_line_count;
+ }
+}
+
+/*
+ * A snapshot of the window sizes, to restore them after closing the help
+ * window.
+ * Only these fields are used:
+ * fr_layout
+ * fr_width
+ * fr_height
+ * fr_next
+ * fr_child
+ * fr_win (only valid for the old curwin, NULL otherwise)
+ */
+
+/*
+ * Create a snapshot of the current frame sizes.
+ */
+ void
+make_snapshot(int idx)
+{
+ clear_snapshot(curtab, idx);
+ make_snapshot_rec(topframe, &curtab->tp_snapshot[idx]);
+}
+
+ static void
+make_snapshot_rec(frame_T *fr, frame_T **frp)
+{
+ *frp = (frame_T *)alloc_clear((unsigned)sizeof(frame_T));
+ if (*frp == NULL)
+ return;
+ (*frp)->fr_layout = fr->fr_layout;
+ (*frp)->fr_width = fr->fr_width;
+ (*frp)->fr_height = fr->fr_height;
+ if (fr->fr_next != NULL)
+ make_snapshot_rec(fr->fr_next, &((*frp)->fr_next));
+ if (fr->fr_child != NULL)
+ make_snapshot_rec(fr->fr_child, &((*frp)->fr_child));
+ if (fr->fr_layout == FR_LEAF && fr->fr_win == curwin)
+ (*frp)->fr_win = curwin;
+}
+
+/*
+ * Remove any existing snapshot.
+ */
+ static void
+clear_snapshot(tabpage_T *tp, int idx)
+{
+ clear_snapshot_rec(tp->tp_snapshot[idx]);
+ tp->tp_snapshot[idx] = NULL;
+}
+
+ static void
+clear_snapshot_rec(frame_T *fr)
+{
+ if (fr != NULL)
+ {
+ clear_snapshot_rec(fr->fr_next);
+ clear_snapshot_rec(fr->fr_child);
+ vim_free(fr);
+ }
+}
+
+/*
+ * Restore a previously created snapshot, if there is any.
+ * This is only done if the screen size didn't change and the window layout is
+ * still the same.
+ */
+ void
+restore_snapshot(
+ int idx,
+ int close_curwin) /* closing current window */
+{
+ win_T *wp;
+
+ if (curtab->tp_snapshot[idx] != NULL
+ && curtab->tp_snapshot[idx]->fr_width == topframe->fr_width
+ && curtab->tp_snapshot[idx]->fr_height == topframe->fr_height
+ && check_snapshot_rec(curtab->tp_snapshot[idx], topframe) == OK)
+ {
+ wp = restore_snapshot_rec(curtab->tp_snapshot[idx], topframe);
+ win_comp_pos();
+ if (wp != NULL && close_curwin)
+ win_goto(wp);
+ redraw_all_later(NOT_VALID);
+ }
+ clear_snapshot(curtab, idx);
+}
+
+/*
+ * Check if frames "sn" and "fr" have the same layout, same following frames
+ * and same children. And the window pointer is valid.
+ */
+ static int
+check_snapshot_rec(frame_T *sn, frame_T *fr)
+{
+ if (sn->fr_layout != fr->fr_layout
+ || (sn->fr_next == NULL) != (fr->fr_next == NULL)
+ || (sn->fr_child == NULL) != (fr->fr_child == NULL)
+ || (sn->fr_next != NULL
+ && check_snapshot_rec(sn->fr_next, fr->fr_next) == FAIL)
+ || (sn->fr_child != NULL
+ && check_snapshot_rec(sn->fr_child, fr->fr_child) == FAIL)
+ || (sn->fr_win != NULL && !win_valid(sn->fr_win)))
+ return FAIL;
+ return OK;
+}
+
+/*
+ * Copy the size of snapshot frame "sn" to frame "fr". Do the same for all
+ * following frames and children.
+ * Returns a pointer to the old current window, or NULL.
+ */
+ static win_T *
+restore_snapshot_rec(frame_T *sn, frame_T *fr)
+{
+ win_T *wp = NULL;
+ win_T *wp2;
+
+ fr->fr_height = sn->fr_height;
+ fr->fr_width = sn->fr_width;
+ if (fr->fr_layout == FR_LEAF)
+ {
+ frame_new_height(fr, fr->fr_height, FALSE, FALSE);
+ frame_new_width(fr, fr->fr_width, FALSE, FALSE);
+ wp = sn->fr_win;
+ }
+ if (sn->fr_next != NULL)
+ {
+ wp2 = restore_snapshot_rec(sn->fr_next, fr->fr_next);
+ if (wp2 != NULL)
+ wp = wp2;
+ }
+ if (sn->fr_child != NULL)
+ {
+ wp2 = restore_snapshot_rec(sn->fr_child, fr->fr_child);
+ if (wp2 != NULL)
+ wp = wp2;
+ }
+ return wp;
+}
+
+#if defined(FEAT_EVAL) || defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) \
+ || defined(PROTO)
+/*
+ * Set "win" to be the curwin and "tp" to be the current tab page.
+ * restore_win() MUST be called to undo, also when FAIL is returned.
+ * No autocommands will be executed until restore_win() is called.
+ * When "no_display" is TRUE the display won't be affected, no redraw is
+ * triggered, another tabpage access is limited.
+ * Returns FAIL if switching to "win" failed.
+ */
+ int
+switch_win(
+ win_T **save_curwin,
+ tabpage_T **save_curtab,
+ win_T *win,
+ tabpage_T *tp,
+ int no_display)
+{
+ block_autocmds();
+ *save_curwin = curwin;
+ if (tp != NULL)
+ {
+ *save_curtab = curtab;
+ if (no_display)
+ {
+ curtab->tp_firstwin = firstwin;
+ curtab->tp_lastwin = lastwin;
+ curtab = tp;
+ firstwin = curtab->tp_firstwin;
+ lastwin = curtab->tp_lastwin;
+ }
+ else
+ goto_tabpage_tp(tp, FALSE, FALSE);
+ }
+ if (!win_valid(win))
+ return FAIL;
+ curwin = win;
+ curbuf = curwin->w_buffer;
+ return OK;
+}
+
+/*
+ * Restore current tabpage and window saved by switch_win(), if still valid.
+ * When "no_display" is TRUE the display won't be affected, no redraw is
+ * triggered.
+ */
+ void
+restore_win(
+ win_T *save_curwin UNUSED,
+ tabpage_T *save_curtab UNUSED,
+ int no_display UNUSED)
+{
+ if (save_curtab != NULL && valid_tabpage(save_curtab))
+ {
+ if (no_display)
+ {
+ curtab->tp_firstwin = firstwin;
+ curtab->tp_lastwin = lastwin;
+ curtab = save_curtab;
+ firstwin = curtab->tp_firstwin;
+ lastwin = curtab->tp_lastwin;
+ }
+ else
+ goto_tabpage_tp(save_curtab, FALSE, FALSE);
+ }
+ if (win_valid(save_curwin))
+ {
+ curwin = save_curwin;
+ curbuf = curwin->w_buffer;
+ }
+ unblock_autocmds();
+}
+
+/*
+ * Make "buf" the current buffer. restore_buffer() MUST be called to undo.
+ * No autocommands will be executed. Use aucmd_prepbuf() if there are any.
+ */
+ void
+switch_buffer(bufref_T *save_curbuf, buf_T *buf)
+{
+ block_autocmds();
+ set_bufref(save_curbuf, curbuf);
+ --curbuf->b_nwindows;
+ curbuf = buf;
+ curwin->w_buffer = buf;
+ ++curbuf->b_nwindows;
+}
+
+/*
+ * Restore the current buffer after using switch_buffer().
+ */
+ void
+restore_buffer(bufref_T *save_curbuf)
+{
+ unblock_autocmds();
+ /* Check for valid buffer, just in case. */
+ if (bufref_valid(save_curbuf))
+ {
+ --curbuf->b_nwindows;
+ curwin->w_buffer = save_curbuf->br_buf;
+ curbuf = save_curbuf->br_buf;
+ ++curbuf->b_nwindows;
+ }
+}
+#endif
+
+#if defined(FEAT_GUI) || defined(PROTO)
+/*
+ * Return TRUE if there is any vertically split window.
+ */
+ int
+win_hasvertsplit(void)
+{
+ frame_T *fr;
+
+ if (topframe->fr_layout == FR_ROW)
+ return TRUE;
+
+ if (topframe->fr_layout == FR_COL)
+ FOR_ALL_FRAMES(fr, topframe->fr_child)
+ if (fr->fr_layout == FR_ROW)
+ return TRUE;
+
+ return FALSE;
+}
+#endif
+
+#if defined(FEAT_SEARCH_EXTRA) || defined(PROTO)
+/*
+ * Add match to the match list of window 'wp'. The pattern 'pat' will be
+ * highlighted with the group 'grp' with priority 'prio'.
+ * Optionally, a desired ID 'id' can be specified (greater than or equal to 1).
+ * If no particular ID is desired, -1 must be specified for 'id'.
+ * Return ID of added match, -1 on failure.
+ */
+ int
+match_add(
+ win_T *wp,
+ char_u *grp,
+ char_u *pat,
+ int prio,
+ int id,
+ list_T *pos_list,
+ char_u *conceal_char UNUSED) /* pointer to conceal replacement char */
+{
+ matchitem_T *cur;
+ matchitem_T *prev;
+ matchitem_T *m;
+ int hlg_id;
+ regprog_T *regprog = NULL;
+ int rtype = SOME_VALID;
+
+ if (*grp == NUL || (pat != NULL && *pat == NUL))
+ return -1;
+ if (id < -1 || id == 0)
+ {
+ semsg(_("E799: Invalid ID: %d (must be greater than or equal to 1)"), id);
+ return -1;
+ }
+ if (id != -1)
+ {
+ cur = wp->w_match_head;
+ while (cur != NULL)
+ {
+ if (cur->id == id)
+ {
+ semsg(_("E801: ID already taken: %d"), id);
+ return -1;
+ }
+ cur = cur->next;
+ }
+ }
+ if ((hlg_id = syn_namen2id(grp, (int)STRLEN(grp))) == 0)
+ {
+ semsg(_(e_nogroup), grp);
+ return -1;
+ }
+ if (pat != NULL && (regprog = vim_regcomp(pat, RE_MAGIC)) == NULL)
+ {
+ semsg(_(e_invarg2), pat);
+ return -1;
+ }
+
+ /* Find available match ID. */
+ while (id == -1)
+ {
+ cur = wp->w_match_head;
+ while (cur != NULL && cur->id != wp->w_next_match_id)
+ cur = cur->next;
+ if (cur == NULL)
+ id = wp->w_next_match_id;
+ wp->w_next_match_id++;
+ }
+
+ /* Build new match. */
+ m = (matchitem_T *)alloc_clear(sizeof(matchitem_T));
+ m->id = id;
+ m->priority = prio;
+ m->pattern = pat == NULL ? NULL : vim_strsave(pat);
+ m->hlg_id = hlg_id;
+ m->match.regprog = regprog;
+ m->match.rmm_ic = FALSE;
+ m->match.rmm_maxcol = 0;
+# if defined(FEAT_CONCEAL)
+ m->conceal_char = 0;
+ if (conceal_char != NULL)
+ m->conceal_char = (*mb_ptr2char)(conceal_char);
+# endif
+
+ /* Set up position matches */
+ if (pos_list != NULL)
+ {
+ linenr_T toplnum = 0;
+ linenr_T botlnum = 0;
+ listitem_T *li;
+ int i;
+
+ for (i = 0, li = pos_list->lv_first; li != NULL && i < MAXPOSMATCH;
+ i++, li = li->li_next)
+ {
+ linenr_T lnum = 0;
+ colnr_T col = 0;
+ int len = 1;
+ list_T *subl;
+ listitem_T *subli;
+ int error = FALSE;
+
+ if (li->li_tv.v_type == VAR_LIST)
+ {
+ subl = li->li_tv.vval.v_list;
+ if (subl == NULL)
+ goto fail;
+ subli = subl->lv_first;
+ if (subli == NULL)
+ goto fail;
+ lnum = tv_get_number_chk(&subli->li_tv, &error);
+ if (error == TRUE)
+ goto fail;
+ if (lnum == 0)
+ {
+ --i;
+ continue;
+ }
+ m->pos.pos[i].lnum = lnum;
+ subli = subli->li_next;
+ if (subli != NULL)
+ {
+ col = tv_get_number_chk(&subli->li_tv, &error);
+ if (error == TRUE)
+ goto fail;
+ subli = subli->li_next;
+ if (subli != NULL)
+ {
+ len = tv_get_number_chk(&subli->li_tv, &error);
+ if (error == TRUE)
+ goto fail;
+ }
+ }
+ m->pos.pos[i].col = col;
+ m->pos.pos[i].len = len;
+ }
+ else if (li->li_tv.v_type == VAR_NUMBER)
+ {
+ if (li->li_tv.vval.v_number == 0)
+ {
+ --i;
+ continue;
+ }
+ m->pos.pos[i].lnum = li->li_tv.vval.v_number;
+ m->pos.pos[i].col = 0;
+ m->pos.pos[i].len = 0;
+ }
+ else
+ {
+ emsg(_("List or number required"));
+ goto fail;
+ }
+ if (toplnum == 0 || lnum < toplnum)
+ toplnum = lnum;
+ if (botlnum == 0 || lnum >= botlnum)
+ botlnum = lnum + 1;
+ }
+
+ /* Calculate top and bottom lines for redrawing area */
+ if (toplnum != 0)
+ {
+ if (wp->w_buffer->b_mod_set)
+ {
+ if (wp->w_buffer->b_mod_top > toplnum)
+ wp->w_buffer->b_mod_top = toplnum;
+ if (wp->w_buffer->b_mod_bot < botlnum)
+ wp->w_buffer->b_mod_bot = botlnum;
+ }
+ else
+ {
+ wp->w_buffer->b_mod_set = TRUE;
+ wp->w_buffer->b_mod_top = toplnum;
+ wp->w_buffer->b_mod_bot = botlnum;
+ wp->w_buffer->b_mod_xlines = 0;
+ }
+ m->pos.toplnum = toplnum;
+ m->pos.botlnum = botlnum;
+ rtype = VALID;
+ }
+ }
+
+ /* Insert new match. The match list is in ascending order with regard to
+ * the match priorities. */
+ cur = wp->w_match_head;
+ prev = cur;
+ while (cur != NULL && prio >= cur->priority)
+ {
+ prev = cur;
+ cur = cur->next;
+ }
+ if (cur == prev)
+ wp->w_match_head = m;
+ else
+ prev->next = m;
+ m->next = cur;
+
+ redraw_later(rtype);
+ return id;
+
+fail:
+ vim_free(m);
+ return -1;
+}
+
+/*
+ * Delete match with ID 'id' in the match list of window 'wp'.
+ * Print error messages if 'perr' is TRUE.
+ */
+ int
+match_delete(win_T *wp, int id, int perr)
+{
+ matchitem_T *cur = wp->w_match_head;
+ matchitem_T *prev = cur;
+ int rtype = SOME_VALID;
+
+ if (id < 1)
+ {
+ if (perr == TRUE)
+ semsg(_("E802: Invalid ID: %d (must be greater than or equal to 1)"),
+ id);
+ return -1;
+ }
+ while (cur != NULL && cur->id != id)
+ {
+ prev = cur;
+ cur = cur->next;
+ }
+ if (cur == NULL)
+ {
+ if (perr == TRUE)
+ semsg(_("E803: ID not found: %d"), id);
+ return -1;
+ }
+ if (cur == prev)
+ wp->w_match_head = cur->next;
+ else
+ prev->next = cur->next;
+ vim_regfree(cur->match.regprog);
+ vim_free(cur->pattern);
+ if (cur->pos.toplnum != 0)
+ {
+ if (wp->w_buffer->b_mod_set)
+ {
+ if (wp->w_buffer->b_mod_top > cur->pos.toplnum)
+ wp->w_buffer->b_mod_top = cur->pos.toplnum;
+ if (wp->w_buffer->b_mod_bot < cur->pos.botlnum)
+ wp->w_buffer->b_mod_bot = cur->pos.botlnum;
+ }
+ else
+ {
+ wp->w_buffer->b_mod_set = TRUE;
+ wp->w_buffer->b_mod_top = cur->pos.toplnum;
+ wp->w_buffer->b_mod_bot = cur->pos.botlnum;
+ wp->w_buffer->b_mod_xlines = 0;
+ }
+ rtype = VALID;
+ }
+ vim_free(cur);
+ redraw_later(rtype);
+ return 0;
+}
+
+/*
+ * Delete all matches in the match list of window 'wp'.
+ */
+ void
+clear_matches(win_T *wp)
+{
+ matchitem_T *m;
+
+ while (wp->w_match_head != NULL)
+ {
+ m = wp->w_match_head->next;
+ vim_regfree(wp->w_match_head->match.regprog);
+ vim_free(wp->w_match_head->pattern);
+ vim_free(wp->w_match_head);
+ wp->w_match_head = m;
+ }
+ redraw_later(SOME_VALID);
+}
+
+/*
+ * Get match from ID 'id' in window 'wp'.
+ * Return NULL if match not found.
+ */
+ matchitem_T *
+get_match(win_T *wp, int id)
+{
+ matchitem_T *cur = wp->w_match_head;
+
+ while (cur != NULL && cur->id != id)
+ cur = cur->next;
+ return cur;
+}
+#endif
+
+#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) || defined(PROTO)
+ int
+get_win_number(win_T *wp, win_T *first_win)
+{
+ int i = 1;
+ win_T *w;
+
+ for (w = first_win; w != NULL && w != wp; w = W_NEXT(w))
+ ++i;
+
+ if (w == NULL)
+ return 0;
+ else
+ return i;
+}
+
+ int
+get_tab_number(tabpage_T *tp UNUSED)
+{
+ int i = 1;
+ tabpage_T *t;
+
+ for (t = first_tabpage; t != NULL && t != tp; t = t->tp_next)
+ ++i;
+
+ if (t == NULL)
+ return 0;
+ else
+ return i;
+}
+#endif
+
+/*
+ * Return TRUE if "topfrp" and its children are at the right height.
+ */
+ static int
+frame_check_height(frame_T *topfrp, int height)
+{
+ frame_T *frp;
+
+ if (topfrp->fr_height != height)
+ return FALSE;
+
+ if (topfrp->fr_layout == FR_ROW)
+ FOR_ALL_FRAMES(frp, topfrp->fr_child)
+ if (frp->fr_height != height)
+ return FALSE;
+
+ return TRUE;
+}
+
+/*
+ * Return TRUE if "topfrp" and its children are at the right width.
+ */
+ static int
+frame_check_width(frame_T *topfrp, int width)
+{
+ frame_T *frp;
+
+ if (topfrp->fr_width != width)
+ return FALSE;
+
+ if (topfrp->fr_layout == FR_COL)
+ FOR_ALL_FRAMES(frp, topfrp->fr_child)
+ if (frp->fr_width != width)
+ return FALSE;
+
+ return TRUE;
+}
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+ int
+win_getid(typval_T *argvars)
+{
+ int winnr;
+ win_T *wp;
+
+ if (argvars[0].v_type == VAR_UNKNOWN)
+ return curwin->w_id;
+ winnr = tv_get_number(&argvars[0]);
+ if (winnr > 0)
+ {
+ if (argvars[1].v_type == VAR_UNKNOWN)
+ wp = firstwin;
+ else
+ {
+ tabpage_T *tp;
+ int tabnr = tv_get_number(&argvars[1]);
+
+ FOR_ALL_TABPAGES(tp)
+ if (--tabnr == 0)
+ break;
+ if (tp == NULL)
+ return -1;
+ if (tp == curtab)
+ wp = firstwin;
+ else
+ wp = tp->tp_firstwin;
+ }
+ for ( ; wp != NULL; wp = wp->w_next)
+ if (--winnr == 0)
+ return wp->w_id;
+ }
+ return 0;
+}
+
+ int
+win_gotoid(typval_T *argvars)
+{
+ win_T *wp;
+ tabpage_T *tp;
+ int id = tv_get_number(&argvars[0]);
+
+ FOR_ALL_TAB_WINDOWS(tp, wp)
+ if (wp->w_id == id)
+ {
+ goto_tabpage_win(tp, wp);
+ return 1;
+ }
+ return 0;
+}
+
+ void
+win_id2tabwin(typval_T *argvars, list_T *list)
+{
+ win_T *wp;
+ tabpage_T *tp;
+ int winnr = 1;
+ int tabnr = 1;
+ int id = tv_get_number(&argvars[0]);
+
+ FOR_ALL_TABPAGES(tp)
+ {
+ FOR_ALL_WINDOWS_IN_TAB(tp, wp)
+ {
+ if (wp->w_id == id)
+ {
+ list_append_number(list, tabnr);
+ list_append_number(list, winnr);
+ return;
+ }
+ ++winnr;
+ }
+ ++tabnr;
+ winnr = 1;
+ }
+ list_append_number(list, 0);
+ list_append_number(list, 0);
+}
+
+ win_T *
+win_id2wp(typval_T *argvars)
+{
+ win_T *wp;
+ tabpage_T *tp;
+ int id = tv_get_number(&argvars[0]);
+
+ FOR_ALL_TAB_WINDOWS(tp, wp)
+ if (wp->w_id == id)
+ return wp;
+
+ return NULL;
+}
+
+ int
+win_id2win(typval_T *argvars)
+{
+ win_T *wp;
+ int nr = 1;
+ int id = tv_get_number(&argvars[0]);
+
+ FOR_ALL_WINDOWS(wp)
+ {
+ if (wp->w_id == id)
+ return nr;
+ ++nr;
+ }
+ return 0;
+}
+
+ void
+win_findbuf(typval_T *argvars, list_T *list)
+{
+ win_T *wp;
+ tabpage_T *tp;
+ int bufnr = tv_get_number(&argvars[0]);
+
+ FOR_ALL_TAB_WINDOWS(tp, wp)
+ if (wp->w_buffer->b_fnum == bufnr)
+ list_append_number(list, wp->w_id);
+}
+
+/*
+ * Get the layout of the given tab page for winlayout().
+ */
+ void
+get_framelayout(frame_T *fr, list_T *l, int outer)
+{
+ frame_T *child;
+ list_T *fr_list;
+ list_T *win_list;
+
+ if (fr == NULL)
+ return;
+
+ if (outer)
+ // outermost call from f_winlayout()
+ fr_list = l;
+ else
+ {
+ fr_list = list_alloc();
+ if (fr_list == NULL)
+ return;
+ list_append_list(l, fr_list);
+ }
+
+ if (fr->fr_layout == FR_LEAF)
+ {
+ if (fr->fr_win != NULL)
+ {
+ list_append_string(fr_list, (char_u *)"leaf", -1);
+ list_append_number(fr_list, fr->fr_win->w_id);
+ }
+ }
+ else
+ {
+ list_append_string(fr_list,
+ fr->fr_layout == FR_ROW ? (char_u *)"row" : (char_u *)"col", -1);
+
+ win_list = list_alloc();
+ if (win_list == NULL)
+ return;
+ list_append_list(fr_list, win_list);
+ child = fr->fr_child;
+ while (child != NULL)
+ {
+ get_framelayout(child, win_list, FALSE);
+ child = child->fr_next;
+ }
+ }
+}
+#endif
diff --git a/src/xdiff/COPYING b/src/xdiff/COPYING
new file mode 100644
index 0000000..f3f1b3b
--- /dev/null
+++ b/src/xdiff/COPYING
@@ -0,0 +1,504 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/src/xdiff/README.txt b/src/xdiff/README.txt
new file mode 100644
index 0000000..1afe740
--- /dev/null
+++ b/src/xdiff/README.txt
@@ -0,0 +1,16 @@
+The files in this directory come from the xdiff implementation in git.
+You can find it here: https://github.com/git/git/tree/master/xdiff
+The files were last updated 2018 September 10.
+
+This is originally based on libxdiff, which can be found here:
+http://www.xmailserver.org/xdiff-lib.html
+
+The git version was used because it has been maintained and improved.
+And since it's part of git it is expected to be reliable.
+
+The code is distributed under the GNU LGPL license. It is included in the
+COPYING file.
+
+Changes in these files were made to avoid compiler warnings.
+
+The first work for including xdiff in Vim was done by Christian Brabandt.
diff --git a/src/xdiff/xdiff.h b/src/xdiff/xdiff.h
new file mode 100644
index 0000000..783dc9d
--- /dev/null
+++ b/src/xdiff/xdiff.h
@@ -0,0 +1,147 @@
+/*
+ * LibXDiff by Davide Libenzi ( File Differential Library )
+ * Copyright (C) 2003 Davide Libenzi
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Davide Libenzi <davidel@xmailserver.org>
+ *
+ */
+
+#if !defined(XDIFF_H)
+#define XDIFF_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* #ifdef __cplusplus */
+
+/* xpparm_t.flags */
+#define XDF_NEED_MINIMAL (1 << 0)
+
+#define XDF_IGNORE_WHITESPACE (1 << 1)
+#define XDF_IGNORE_WHITESPACE_CHANGE (1 << 2)
+#define XDF_IGNORE_WHITESPACE_AT_EOL (1 << 3)
+#define XDF_IGNORE_CR_AT_EOL (1 << 4)
+#define XDF_WHITESPACE_FLAGS (XDF_IGNORE_WHITESPACE | \
+ XDF_IGNORE_WHITESPACE_CHANGE | \
+ XDF_IGNORE_WHITESPACE_AT_EOL | \
+ XDF_IGNORE_CR_AT_EOL)
+
+#define XDF_IGNORE_BLANK_LINES (1 << 7)
+
+#define XDF_PATIENCE_DIFF (1 << 14)
+#define XDF_HISTOGRAM_DIFF (1 << 15)
+#define XDF_DIFF_ALGORITHM_MASK (XDF_PATIENCE_DIFF | XDF_HISTOGRAM_DIFF)
+#define XDF_DIFF_ALG(x) ((x) & XDF_DIFF_ALGORITHM_MASK)
+
+#define XDF_INDENT_HEURISTIC (1 << 23)
+
+/* xdemitconf_t.flags */
+#define XDL_EMIT_FUNCNAMES (1 << 0)
+#define XDL_EMIT_FUNCCONTEXT (1 << 2)
+
+/* merge simplification levels */
+#define XDL_MERGE_MINIMAL 0
+#define XDL_MERGE_EAGER 1
+#define XDL_MERGE_ZEALOUS 2
+#define XDL_MERGE_ZEALOUS_ALNUM 3
+
+/* merge favor modes */
+#define XDL_MERGE_FAVOR_OURS 1
+#define XDL_MERGE_FAVOR_THEIRS 2
+#define XDL_MERGE_FAVOR_UNION 3
+
+/* merge output styles */
+#define XDL_MERGE_DIFF3 1
+
+typedef struct s_mmfile {
+ char *ptr;
+ long size;
+} mmfile_t;
+
+typedef struct s_mmbuffer {
+ char *ptr;
+ long size;
+} mmbuffer_t;
+
+typedef struct s_xpparam {
+ unsigned long flags;
+
+ /* See Documentation/diff-options.txt. */
+ char **anchors;
+ size_t anchors_nr;
+} xpparam_t;
+
+typedef struct s_xdemitcb {
+ void *priv;
+ int (*outf)(void *, mmbuffer_t *, int);
+} xdemitcb_t;
+
+typedef long (*find_func_t)(const char *line, long line_len, char *buffer, long buffer_size, void *priv);
+
+typedef int (*xdl_emit_hunk_consume_func_t)(long start_a, long count_a,
+ long start_b, long count_b,
+ void *cb_data);
+
+typedef struct s_xdemitconf {
+ long ctxlen;
+ long interhunkctxlen;
+ unsigned long flags;
+ find_func_t find_func;
+ void *find_func_priv;
+ xdl_emit_hunk_consume_func_t hunk_func;
+} xdemitconf_t;
+
+typedef struct s_bdiffparam {
+ long bsize;
+} bdiffparam_t;
+
+#ifdef VMS
+# include "[]vim.h"
+#else
+# include "../vim.h"
+#endif
+
+#define xdl_malloc(x) lalloc((x), TRUE)
+#define xdl_free(ptr) vim_free(ptr)
+#define xdl_realloc(ptr,x) vim_realloc((ptr),(x))
+
+void *xdl_mmfile_first(mmfile_t *mmf, long *size);
+long xdl_mmfile_size(mmfile_t *mmf);
+
+int xdl_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,
+ xdemitconf_t const *xecfg, xdemitcb_t *ecb);
+
+typedef struct s_xmparam {
+ xpparam_t xpp;
+ int marker_size;
+ int level;
+ int favor;
+ int style;
+ const char *ancestor; /* label for orig */
+ const char *file1; /* label for mf1 */
+ const char *file2; /* label for mf2 */
+} xmparam_t;
+
+#define DEFAULT_CONFLICT_MARKER_SIZE 7
+
+int xdl_merge(mmfile_t *orig, mmfile_t *mf1, mmfile_t *mf2,
+ xmparam_t const *xmp, mmbuffer_t *result);
+
+#ifdef __cplusplus
+}
+#endif /* #ifdef __cplusplus */
+
+#endif /* #if !defined(XDIFF_H) */
diff --git a/src/xdiff/xdiffi.c b/src/xdiff/xdiffi.c
new file mode 100644
index 0000000..96d5277
--- /dev/null
+++ b/src/xdiff/xdiffi.c
@@ -0,0 +1,1043 @@
+/*
+ * LibXDiff by Davide Libenzi ( File Differential Library )
+ * Copyright (C) 2003 Davide Libenzi
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Davide Libenzi <davidel@xmailserver.org>
+ *
+ */
+
+#include "xinclude.h"
+
+#define XDL_MAX_COST_MIN 256
+#define XDL_HEUR_MIN_COST 256
+#define XDL_LINE_MAX (long)((1UL << (CHAR_BIT * sizeof(long) - 1)) - 1)
+#define XDL_SNAKE_CNT 20
+#define XDL_K_HEUR 4
+
+typedef struct s_xdpsplit {
+ long i1, i2;
+ int min_lo, min_hi;
+} xdpsplit_t;
+
+/*
+ * See "An O(ND) Difference Algorithm and its Variations", by Eugene Myers.
+ * Basically considers a "box" (off1, off2, lim1, lim2) and scan from both
+ * the forward diagonal starting from (off1, off2) and the backward diagonal
+ * starting from (lim1, lim2). If the K values on the same diagonal crosses
+ * returns the furthest point of reach. We might end up having to expensive
+ * cases using this algorithm is full, so a little bit of heuristic is needed
+ * to cut the search and to return a suboptimal point.
+ */
+static long xdl_split(unsigned long const *ha1, long off1, long lim1,
+ unsigned long const *ha2, long off2, long lim2,
+ long *kvdf, long *kvdb, int need_min, xdpsplit_t *spl,
+ xdalgoenv_t *xenv) {
+ long dmin = off1 - lim2, dmax = lim1 - off2;
+ long fmid = off1 - off2, bmid = lim1 - lim2;
+ long odd = (fmid - bmid) & 1;
+ long fmin = fmid, fmax = fmid;
+ long bmin = bmid, bmax = bmid;
+ long ec, d, i1, i2, prev1, best, dd, v, k;
+
+ /*
+ * Set initial diagonal values for both forward and backward path.
+ */
+ kvdf[fmid] = off1;
+ kvdb[bmid] = lim1;
+
+ for (ec = 1;; ec++) {
+ int got_snake = 0;
+
+ /*
+ * We need to extent the diagonal "domain" by one. If the next
+ * values exits the box boundaries we need to change it in the
+ * opposite direction because (max - min) must be a power of two.
+ * Also we initialize the external K value to -1 so that we can
+ * avoid extra conditions check inside the core loop.
+ */
+ if (fmin > dmin)
+ kvdf[--fmin - 1] = -1;
+ else
+ ++fmin;
+ if (fmax < dmax)
+ kvdf[++fmax + 1] = -1;
+ else
+ --fmax;
+
+ for (d = fmax; d >= fmin; d -= 2) {
+ if (kvdf[d - 1] >= kvdf[d + 1])
+ i1 = kvdf[d - 1] + 1;
+ else
+ i1 = kvdf[d + 1];
+ prev1 = i1;
+ i2 = i1 - d;
+ for (; i1 < lim1 && i2 < lim2 && ha1[i1] == ha2[i2]; i1++, i2++);
+ if (i1 - prev1 > xenv->snake_cnt)
+ got_snake = 1;
+ kvdf[d] = i1;
+ if (odd && bmin <= d && d <= bmax && kvdb[d] <= i1) {
+ spl->i1 = i1;
+ spl->i2 = i2;
+ spl->min_lo = spl->min_hi = 1;
+ return ec;
+ }
+ }
+
+ /*
+ * We need to extent the diagonal "domain" by one. If the next
+ * values exits the box boundaries we need to change it in the
+ * opposite direction because (max - min) must be a power of two.
+ * Also we initialize the external K value to -1 so that we can
+ * avoid extra conditions check inside the core loop.
+ */
+ if (bmin > dmin)
+ kvdb[--bmin - 1] = XDL_LINE_MAX;
+ else
+ ++bmin;
+ if (bmax < dmax)
+ kvdb[++bmax + 1] = XDL_LINE_MAX;
+ else
+ --bmax;
+
+ for (d = bmax; d >= bmin; d -= 2) {
+ if (kvdb[d - 1] < kvdb[d + 1])
+ i1 = kvdb[d - 1];
+ else
+ i1 = kvdb[d + 1] - 1;
+ prev1 = i1;
+ i2 = i1 - d;
+ for (; i1 > off1 && i2 > off2 && ha1[i1 - 1] == ha2[i2 - 1]; i1--, i2--);
+ if (prev1 - i1 > xenv->snake_cnt)
+ got_snake = 1;
+ kvdb[d] = i1;
+ if (!odd && fmin <= d && d <= fmax && i1 <= kvdf[d]) {
+ spl->i1 = i1;
+ spl->i2 = i2;
+ spl->min_lo = spl->min_hi = 1;
+ return ec;
+ }
+ }
+
+ if (need_min)
+ continue;
+
+ /*
+ * If the edit cost is above the heuristic trigger and if
+ * we got a good snake, we sample current diagonals to see
+ * if some of the, have reached an "interesting" path. Our
+ * measure is a function of the distance from the diagonal
+ * corner (i1 + i2) penalized with the distance from the
+ * mid diagonal itself. If this value is above the current
+ * edit cost times a magic factor (XDL_K_HEUR) we consider
+ * it interesting.
+ */
+ if (got_snake && ec > xenv->heur_min) {
+ for (best = 0, d = fmax; d >= fmin; d -= 2) {
+ dd = d > fmid ? d - fmid: fmid - d;
+ i1 = kvdf[d];
+ i2 = i1 - d;
+ v = (i1 - off1) + (i2 - off2) - dd;
+
+ if (v > XDL_K_HEUR * ec && v > best &&
+ off1 + xenv->snake_cnt <= i1 && i1 < lim1 &&
+ off2 + xenv->snake_cnt <= i2 && i2 < lim2) {
+ for (k = 1; ha1[i1 - k] == ha2[i2 - k]; k++)
+ if (k == xenv->snake_cnt) {
+ best = v;
+ spl->i1 = i1;
+ spl->i2 = i2;
+ break;
+ }
+ }
+ }
+ if (best > 0) {
+ spl->min_lo = 1;
+ spl->min_hi = 0;
+ return ec;
+ }
+
+ for (best = 0, d = bmax; d >= bmin; d -= 2) {
+ dd = d > bmid ? d - bmid: bmid - d;
+ i1 = kvdb[d];
+ i2 = i1 - d;
+ v = (lim1 - i1) + (lim2 - i2) - dd;
+
+ if (v > XDL_K_HEUR * ec && v > best &&
+ off1 < i1 && i1 <= lim1 - xenv->snake_cnt &&
+ off2 < i2 && i2 <= lim2 - xenv->snake_cnt) {
+ for (k = 0; ha1[i1 + k] == ha2[i2 + k]; k++)
+ if (k == xenv->snake_cnt - 1) {
+ best = v;
+ spl->i1 = i1;
+ spl->i2 = i2;
+ break;
+ }
+ }
+ }
+ if (best > 0) {
+ spl->min_lo = 0;
+ spl->min_hi = 1;
+ return ec;
+ }
+ }
+
+ /*
+ * Enough is enough. We spent too much time here and now we collect
+ * the furthest reaching path using the (i1 + i2) measure.
+ */
+ if (ec >= xenv->mxcost) {
+ long fbest, fbest1, bbest, bbest1;
+
+ fbest = fbest1 = -1;
+ for (d = fmax; d >= fmin; d -= 2) {
+ i1 = XDL_MIN(kvdf[d], lim1);
+ i2 = i1 - d;
+ if (lim2 < i2)
+ i1 = lim2 + d, i2 = lim2;
+ if (fbest < i1 + i2) {
+ fbest = i1 + i2;
+ fbest1 = i1;
+ }
+ }
+
+ bbest = bbest1 = XDL_LINE_MAX;
+ for (d = bmax; d >= bmin; d -= 2) {
+ i1 = XDL_MAX(off1, kvdb[d]);
+ i2 = i1 - d;
+ if (i2 < off2)
+ i1 = off2 + d, i2 = off2;
+ if (i1 + i2 < bbest) {
+ bbest = i1 + i2;
+ bbest1 = i1;
+ }
+ }
+
+ if ((lim1 + lim2) - bbest < fbest - (off1 + off2)) {
+ spl->i1 = fbest1;
+ spl->i2 = fbest - fbest1;
+ spl->min_lo = 1;
+ spl->min_hi = 0;
+ } else {
+ spl->i1 = bbest1;
+ spl->i2 = bbest - bbest1;
+ spl->min_lo = 0;
+ spl->min_hi = 1;
+ }
+ return ec;
+ }
+ }
+}
+
+
+/*
+ * Rule: "Divide et Impera". Recursively split the box in sub-boxes by calling
+ * the box splitting function. Note that the real job (marking changed lines)
+ * is done in the two boundary reaching checks.
+ */
+int xdl_recs_cmp(diffdata_t *dd1, long off1, long lim1,
+ diffdata_t *dd2, long off2, long lim2,
+ long *kvdf, long *kvdb, int need_min, xdalgoenv_t *xenv) {
+ unsigned long const *ha1 = dd1->ha, *ha2 = dd2->ha;
+
+ /*
+ * Shrink the box by walking through each diagonal snake (SW and NE).
+ */
+ for (; off1 < lim1 && off2 < lim2 && ha1[off1] == ha2[off2]; off1++, off2++);
+ for (; off1 < lim1 && off2 < lim2 && ha1[lim1 - 1] == ha2[lim2 - 1]; lim1--, lim2--);
+
+ /*
+ * If one dimension is empty, then all records on the other one must
+ * be obviously changed.
+ */
+ if (off1 == lim1) {
+ char *rchg2 = dd2->rchg;
+ long *rindex2 = dd2->rindex;
+
+ for (; off2 < lim2; off2++)
+ rchg2[rindex2[off2]] = 1;
+ } else if (off2 == lim2) {
+ char *rchg1 = dd1->rchg;
+ long *rindex1 = dd1->rindex;
+
+ for (; off1 < lim1; off1++)
+ rchg1[rindex1[off1]] = 1;
+ } else {
+ xdpsplit_t spl;
+ spl.i1 = spl.i2 = 0;
+
+ /*
+ * Divide ...
+ */
+ if (xdl_split(ha1, off1, lim1, ha2, off2, lim2, kvdf, kvdb,
+ need_min, &spl, xenv) < 0) {
+
+ return -1;
+ }
+
+ /*
+ * ... et Impera.
+ */
+ if (xdl_recs_cmp(dd1, off1, spl.i1, dd2, off2, spl.i2,
+ kvdf, kvdb, spl.min_lo, xenv) < 0 ||
+ xdl_recs_cmp(dd1, spl.i1, lim1, dd2, spl.i2, lim2,
+ kvdf, kvdb, spl.min_hi, xenv) < 0) {
+
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+int xdl_do_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,
+ xdfenv_t *xe) {
+ long ndiags;
+ long *kvd, *kvdf, *kvdb;
+ xdalgoenv_t xenv;
+ diffdata_t dd1, dd2;
+
+ if (XDF_DIFF_ALG(xpp->flags) == XDF_PATIENCE_DIFF)
+ return xdl_do_patience_diff(mf1, mf2, xpp, xe);
+
+ if (XDF_DIFF_ALG(xpp->flags) == XDF_HISTOGRAM_DIFF)
+ return xdl_do_histogram_diff(mf1, mf2, xpp, xe);
+
+ if (xdl_prepare_env(mf1, mf2, xpp, xe) < 0) {
+
+ return -1;
+ }
+
+ /*
+ * Allocate and setup K vectors to be used by the differential algorithm.
+ * One is to store the forward path and one to store the backward path.
+ */
+ ndiags = xe->xdf1.nreff + xe->xdf2.nreff + 3;
+ if (!(kvd = (long *) xdl_malloc((2 * ndiags + 2) * sizeof(long)))) {
+
+ xdl_free_env(xe);
+ return -1;
+ }
+ kvdf = kvd;
+ kvdb = kvdf + ndiags;
+ kvdf += xe->xdf2.nreff + 1;
+ kvdb += xe->xdf2.nreff + 1;
+
+ xenv.mxcost = xdl_bogosqrt(ndiags);
+ if (xenv.mxcost < XDL_MAX_COST_MIN)
+ xenv.mxcost = XDL_MAX_COST_MIN;
+ xenv.snake_cnt = XDL_SNAKE_CNT;
+ xenv.heur_min = XDL_HEUR_MIN_COST;
+
+ dd1.nrec = xe->xdf1.nreff;
+ dd1.ha = xe->xdf1.ha;
+ dd1.rchg = xe->xdf1.rchg;
+ dd1.rindex = xe->xdf1.rindex;
+ dd2.nrec = xe->xdf2.nreff;
+ dd2.ha = xe->xdf2.ha;
+ dd2.rchg = xe->xdf2.rchg;
+ dd2.rindex = xe->xdf2.rindex;
+
+ if (xdl_recs_cmp(&dd1, 0, dd1.nrec, &dd2, 0, dd2.nrec,
+ kvdf, kvdb, (xpp->flags & XDF_NEED_MINIMAL) != 0, &xenv) < 0) {
+
+ xdl_free(kvd);
+ xdl_free_env(xe);
+ return -1;
+ }
+
+ xdl_free(kvd);
+
+ return 0;
+}
+
+
+static xdchange_t *xdl_add_change(xdchange_t *xscr, long i1, long i2, long chg1, long chg2) {
+ xdchange_t *xch;
+
+ if (!(xch = (xdchange_t *) xdl_malloc(sizeof(xdchange_t))))
+ return NULL;
+
+ xch->next = xscr;
+ xch->i1 = i1;
+ xch->i2 = i2;
+ xch->chg1 = chg1;
+ xch->chg2 = chg2;
+ xch->ignore = 0;
+
+ return xch;
+}
+
+
+static int recs_match(xrecord_t *rec1, xrecord_t *rec2, long flags)
+{
+ return (rec1->ha == rec2->ha &&
+ xdl_recmatch(rec1->ptr, rec1->size,
+ rec2->ptr, rec2->size,
+ flags));
+}
+
+/*
+ * If a line is indented more than this, xget_indent() just returns this value.
+ * This avoids having to do absurd amounts of work for data that are not
+ * human-readable text, and also ensures that the output of xget_indent fits within
+ * an int.
+ */
+#define MAX_INDENT 200
+
+/*
+ * Return the amount of indentation of the specified line, treating TAB as 8
+ * columns. Return -1 if line is empty or contains only whitespace. Clamp the
+ * output value at MAX_INDENT.
+ */
+static int xget_indent(xrecord_t *rec)
+{
+ long i;
+ int ret = 0;
+
+ for (i = 0; i < rec->size; i++) {
+ char c = rec->ptr[i];
+
+ if (!XDL_ISSPACE(c))
+ return ret;
+ else if (c == ' ')
+ ret += 1;
+ else if (c == '\t')
+ ret += 8 - ret % 8;
+ /* ignore other whitespace characters */
+
+ if (ret >= MAX_INDENT)
+ return MAX_INDENT;
+ }
+
+ /* The line contains only whitespace. */
+ return -1;
+}
+
+/*
+ * If more than this number of consecutive blank rows are found, just return this
+ * value. This avoids requiring O(N^2) work for pathological cases, and also
+ * ensures that the output of score_split fits in an int.
+ */
+#define MAX_BLANKS 20
+
+/* Characteristics measured about a hypothetical split position. */
+struct split_measurement {
+ /*
+ * Is the split at the end of the file (aside from any blank lines)?
+ */
+ int end_of_file;
+
+ /*
+ * How much is the line immediately following the split indented (or -1 if
+ * the line is blank):
+ */
+ int indent;
+
+ /*
+ * How many consecutive lines above the split are blank?
+ */
+ int pre_blank;
+
+ /*
+ * How much is the nearest non-blank line above the split indented (or -1
+ * if there is no such line)?
+ */
+ int pre_indent;
+
+ /*
+ * How many lines after the line following the split are blank?
+ */
+ int post_blank;
+
+ /*
+ * How much is the nearest non-blank line after the line following the
+ * split indented (or -1 if there is no such line)?
+ */
+ int post_indent;
+};
+
+struct split_score {
+ /* The effective indent of this split (smaller is preferred). */
+ int effective_indent;
+
+ /* Penalty for this split (smaller is preferred). */
+ int penalty;
+};
+
+/*
+ * Fill m with information about a hypothetical split of xdf above line split.
+ */
+static void measure_split(const xdfile_t *xdf, long split,
+ struct split_measurement *m)
+{
+ long i;
+
+ if (split >= xdf->nrec) {
+ m->end_of_file = 1;
+ m->indent = -1;
+ } else {
+ m->end_of_file = 0;
+ m->indent = xget_indent(xdf->recs[split]);
+ }
+
+ m->pre_blank = 0;
+ m->pre_indent = -1;
+ for (i = split - 1; i >= 0; i--) {
+ m->pre_indent = xget_indent(xdf->recs[i]);
+ if (m->pre_indent != -1)
+ break;
+ m->pre_blank += 1;
+ if (m->pre_blank == MAX_BLANKS) {
+ m->pre_indent = 0;
+ break;
+ }
+ }
+
+ m->post_blank = 0;
+ m->post_indent = -1;
+ for (i = split + 1; i < xdf->nrec; i++) {
+ m->post_indent = xget_indent(xdf->recs[i]);
+ if (m->post_indent != -1)
+ break;
+ m->post_blank += 1;
+ if (m->post_blank == MAX_BLANKS) {
+ m->post_indent = 0;
+ break;
+ }
+ }
+}
+
+/*
+ * The empirically-determined weight factors used by score_split() below.
+ * Larger values means that the position is a less favorable place to split.
+ *
+ * Note that scores are only ever compared against each other, so multiplying
+ * all of these weight/penalty values by the same factor wouldn't change the
+ * heuristic's behavior. Still, we need to set that arbitrary scale *somehow*.
+ * In practice, these numbers are chosen to be large enough that they can be
+ * adjusted relative to each other with sufficient precision despite using
+ * integer math.
+ */
+
+/* Penalty if there are no non-blank lines before the split */
+#define START_OF_FILE_PENALTY 1
+
+/* Penalty if there are no non-blank lines after the split */
+#define END_OF_FILE_PENALTY 21
+
+/* Multiplier for the number of blank lines around the split */
+#define TOTAL_BLANK_WEIGHT (-30)
+
+/* Multiplier for the number of blank lines after the split */
+#define POST_BLANK_WEIGHT 6
+
+/*
+ * Penalties applied if the line is indented more than its predecessor
+ */
+#define RELATIVE_INDENT_PENALTY (-4)
+#define RELATIVE_INDENT_WITH_BLANK_PENALTY 10
+
+/*
+ * Penalties applied if the line is indented less than both its predecessor and
+ * its successor
+ */
+#define RELATIVE_OUTDENT_PENALTY 24
+#define RELATIVE_OUTDENT_WITH_BLANK_PENALTY 17
+
+/*
+ * Penalties applied if the line is indented less than its predecessor but not
+ * less than its successor
+ */
+#define RELATIVE_DEDENT_PENALTY 23
+#define RELATIVE_DEDENT_WITH_BLANK_PENALTY 17
+
+/*
+ * We only consider whether the sum of the effective indents for splits are
+ * less than (-1), equal to (0), or greater than (+1) each other. The resulting
+ * value is multiplied by the following weight and combined with the penalty to
+ * determine the better of two scores.
+ */
+#define INDENT_WEIGHT 60
+
+/*
+ * How far do we slide a hunk at most?
+ */
+#define INDENT_HEURISTIC_MAX_SLIDING 100
+
+/*
+ * Compute a badness score for the hypothetical split whose measurements are
+ * stored in m. The weight factors were determined empirically using the tools and
+ * corpus described in
+ *
+ * https://github.com/mhagger/diff-slider-tools
+ *
+ * Also see that project if you want to improve the weights based on, for example,
+ * a larger or more diverse corpus.
+ */
+static void score_add_split(const struct split_measurement *m, struct split_score *s)
+{
+ /*
+ * A place to accumulate penalty factors (positive makes this index more
+ * favored):
+ */
+ int post_blank, total_blank, indent, any_blanks;
+
+ if (m->pre_indent == -1 && m->pre_blank == 0)
+ s->penalty += START_OF_FILE_PENALTY;
+
+ if (m->end_of_file)
+ s->penalty += END_OF_FILE_PENALTY;
+
+ /*
+ * Set post_blank to the number of blank lines following the split,
+ * including the line immediately after the split:
+ */
+ post_blank = (m->indent == -1) ? 1 + m->post_blank : 0;
+ total_blank = m->pre_blank + post_blank;
+
+ /* Penalties based on nearby blank lines: */
+ s->penalty += TOTAL_BLANK_WEIGHT * total_blank;
+ s->penalty += POST_BLANK_WEIGHT * post_blank;
+
+ if (m->indent != -1)
+ indent = m->indent;
+ else
+ indent = m->post_indent;
+
+ any_blanks = (total_blank != 0);
+
+ /* Note that the effective indent is -1 at the end of the file: */
+ s->effective_indent += indent;
+
+ if (indent == -1) {
+ /* No additional adjustments needed. */
+ } else if (m->pre_indent == -1) {
+ /* No additional adjustments needed. */
+ } else if (indent > m->pre_indent) {
+ /*
+ * The line is indented more than its predecessor.
+ */
+ s->penalty += any_blanks ?
+ RELATIVE_INDENT_WITH_BLANK_PENALTY :
+ RELATIVE_INDENT_PENALTY;
+ } else if (indent == m->pre_indent) {
+ /*
+ * The line has the same indentation level as its predecessor.
+ * No additional adjustments needed.
+ */
+ } else {
+ /*
+ * The line is indented less than its predecessor. It could be
+ * the block terminator of the previous block, but it could
+ * also be the start of a new block (e.g., an "else" block, or
+ * maybe the previous block didn't have a block terminator).
+ * Try to distinguish those cases based on what comes next:
+ */
+ if (m->post_indent != -1 && m->post_indent > indent) {
+ /*
+ * The following line is indented more. So it is likely
+ * that this line is the start of a block.
+ */
+ s->penalty += any_blanks ?
+ RELATIVE_OUTDENT_WITH_BLANK_PENALTY :
+ RELATIVE_OUTDENT_PENALTY;
+ } else {
+ /*
+ * That was probably the end of a block.
+ */
+ s->penalty += any_blanks ?
+ RELATIVE_DEDENT_WITH_BLANK_PENALTY :
+ RELATIVE_DEDENT_PENALTY;
+ }
+ }
+}
+
+static int score_cmp(struct split_score *s1, struct split_score *s2)
+{
+ /* -1 if s1.effective_indent < s2->effective_indent, etc. */
+ int cmp_indents = ((s1->effective_indent > s2->effective_indent) -
+ (s1->effective_indent < s2->effective_indent));
+
+ return INDENT_WEIGHT * cmp_indents + (s1->penalty - s2->penalty);
+}
+
+/*
+ * Represent a group of changed lines in an xdfile_t (i.e., a contiguous group
+ * of lines that was inserted or deleted from the corresponding version of the
+ * file). We consider there to be such a group at the beginning of the file, at
+ * the end of the file, and between any two unchanged lines, though most such
+ * groups will usually be empty.
+ *
+ * If the first line in a group is equal to the line following the group, then
+ * the group can be slid down. Similarly, if the last line in a group is equal
+ * to the line preceding the group, then the group can be slid up. See
+ * group_slide_down() and group_slide_up().
+ *
+ * Note that loops that are testing for changed lines in xdf->rchg do not need
+ * index bounding since the array is prepared with a zero at position -1 and N.
+ */
+struct xdlgroup {
+ /*
+ * The index of the first changed line in the group, or the index of
+ * the unchanged line above which the (empty) group is located.
+ */
+ long start;
+
+ /*
+ * The index of the first unchanged line after the group. For an empty
+ * group, end is equal to start.
+ */
+ long end;
+};
+
+/*
+ * Initialize g to point at the first group in xdf.
+ */
+static void group_init(xdfile_t *xdf, struct xdlgroup *g)
+{
+ g->start = g->end = 0;
+ while (xdf->rchg[g->end])
+ g->end++;
+}
+
+/*
+ * Move g to describe the next (possibly empty) group in xdf and return 0. If g
+ * is already at the end of the file, do nothing and return -1.
+ */
+static inline int group_next(xdfile_t *xdf, struct xdlgroup *g)
+{
+ if (g->end == xdf->nrec)
+ return -1;
+
+ g->start = g->end + 1;
+ for (g->end = g->start; xdf->rchg[g->end]; g->end++)
+ ;
+
+ return 0;
+}
+
+/*
+ * Move g to describe the previous (possibly empty) group in xdf and return 0.
+ * If g is already at the beginning of the file, do nothing and return -1.
+ */
+static inline int group_previous(xdfile_t *xdf, struct xdlgroup *g)
+{
+ if (g->start == 0)
+ return -1;
+
+ g->end = g->start - 1;
+ for (g->start = g->end; xdf->rchg[g->start - 1]; g->start--)
+ ;
+
+ return 0;
+}
+
+/*
+ * If g can be slid toward the end of the file, do so, and if it bumps into a
+ * following group, expand this group to include it. Return 0 on success or -1
+ * if g cannot be slid down.
+ */
+static int group_slide_down(xdfile_t *xdf, struct xdlgroup *g, long flags)
+{
+ if (g->end < xdf->nrec &&
+ recs_match(xdf->recs[g->start], xdf->recs[g->end], flags)) {
+ xdf->rchg[g->start++] = 0;
+ xdf->rchg[g->end++] = 1;
+
+ while (xdf->rchg[g->end])
+ g->end++;
+
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
+/*
+ * If g can be slid toward the beginning of the file, do so, and if it bumps
+ * into a previous group, expand this group to include it. Return 0 on success
+ * or -1 if g cannot be slid up.
+ */
+static int group_slide_up(xdfile_t *xdf, struct xdlgroup *g, long flags)
+{
+ if (g->start > 0 &&
+ recs_match(xdf->recs[g->start - 1], xdf->recs[g->end - 1], flags)) {
+ xdf->rchg[--g->start] = 1;
+ xdf->rchg[--g->end] = 0;
+
+ while (xdf->rchg[g->start - 1])
+ g->start--;
+
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
+static void xdl_bug(const char *msg)
+{
+ fprintf(stderr, "BUG: %s\n", msg);
+ exit(1);
+}
+
+/*
+ * Move back and forward change groups for a consistent and pretty diff output.
+ * This also helps in finding joinable change groups and reducing the diff
+ * size.
+ */
+int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) {
+ struct xdlgroup g, go;
+ long earliest_end, end_matching_other;
+ long groupsize;
+
+ group_init(xdf, &g);
+ group_init(xdfo, &go);
+
+ while (1) {
+ /* If the group is empty in the to-be-compacted file, skip it: */
+ if (g.end == g.start)
+ goto next;
+
+ /*
+ * Now shift the change up and then down as far as possible in
+ * each direction. If it bumps into any other changes, merge them.
+ */
+ do {
+ groupsize = g.end - g.start;
+
+ /*
+ * Keep track of the last "end" index that causes this
+ * group to align with a group of changed lines in the
+ * other file. -1 indicates that we haven't found such
+ * a match yet:
+ */
+ end_matching_other = -1;
+
+ /* Shift the group backward as much as possible: */
+ while (!group_slide_up(xdf, &g, flags))
+ if (group_previous(xdfo, &go))
+ xdl_bug("group sync broken sliding up");
+
+ /*
+ * This is this highest that this group can be shifted.
+ * Record its end index:
+ */
+ earliest_end = g.end;
+
+ if (go.end > go.start)
+ end_matching_other = g.end;
+
+ /* Now shift the group forward as far as possible: */
+ while (1) {
+ if (group_slide_down(xdf, &g, flags))
+ break;
+ if (group_next(xdfo, &go))
+ xdl_bug("group sync broken sliding down");
+
+ if (go.end > go.start)
+ end_matching_other = g.end;
+ }
+ } while (groupsize != g.end - g.start);
+
+ /*
+ * If the group can be shifted, then we can possibly use this
+ * freedom to produce a more intuitive diff.
+ *
+ * The group is currently shifted as far down as possible, so the
+ * heuristics below only have to handle upwards shifts.
+ */
+
+ if (g.end == earliest_end) {
+ /* no shifting was possible */
+ } else if (end_matching_other != -1) {
+ /*
+ * Move the possibly merged group of changes back to line
+ * up with the last group of changes from the other file
+ * that it can align with.
+ */
+ while (go.end == go.start) {
+ if (group_slide_up(xdf, &g, flags))
+ xdl_bug("match disappeared");
+ if (group_previous(xdfo, &go))
+ xdl_bug("group sync broken sliding to match");
+ }
+ } else if (flags & XDF_INDENT_HEURISTIC) {
+ /*
+ * Indent heuristic: a group of pure add/delete lines
+ * implies two splits, one between the end of the "before"
+ * context and the start of the group, and another between
+ * the end of the group and the beginning of the "after"
+ * context. Some splits are aesthetically better and some
+ * are worse. We compute a badness "score" for each split,
+ * and add the scores for the two splits to define a
+ * "score" for each position that the group can be shifted
+ * to. Then we pick the shift with the lowest score.
+ */
+ long shift, best_shift = -1;
+ struct split_score best_score;
+
+ shift = earliest_end;
+ if (g.end - groupsize - 1 > shift)
+ shift = g.end - groupsize - 1;
+ if (g.end - INDENT_HEURISTIC_MAX_SLIDING > shift)
+ shift = g.end - INDENT_HEURISTIC_MAX_SLIDING;
+ for (; shift <= g.end; shift++) {
+ struct split_measurement m;
+ struct split_score score = {0, 0};
+
+ measure_split(xdf, shift, &m);
+ score_add_split(&m, &score);
+ measure_split(xdf, shift - groupsize, &m);
+ score_add_split(&m, &score);
+ if (best_shift == -1 ||
+ score_cmp(&score, &best_score) <= 0) {
+ best_score.effective_indent = score.effective_indent;
+ best_score.penalty = score.penalty;
+ best_shift = shift;
+ }
+ }
+
+ while (g.end > best_shift) {
+ if (group_slide_up(xdf, &g, flags))
+ xdl_bug("best shift unreached");
+ if (group_previous(xdfo, &go))
+ xdl_bug("group sync broken sliding to blank line");
+ }
+ }
+
+ next:
+ /* Move past the just-processed group: */
+ if (group_next(xdf, &g))
+ break;
+ if (group_next(xdfo, &go))
+ xdl_bug("group sync broken moving to next group");
+ }
+
+ if (!group_next(xdfo, &go))
+ xdl_bug("group sync broken at end of file");
+
+ return 0;
+}
+
+
+int xdl_build_script(xdfenv_t *xe, xdchange_t **xscr) {
+ xdchange_t *cscr = NULL, *xch;
+ char *rchg1 = xe->xdf1.rchg, *rchg2 = xe->xdf2.rchg;
+ long i1, i2, l1, l2;
+
+ /*
+ * Trivial. Collects "groups" of changes and creates an edit script.
+ */
+ for (i1 = xe->xdf1.nrec, i2 = xe->xdf2.nrec; i1 >= 0 || i2 >= 0; i1--, i2--)
+ if (rchg1[i1 - 1] || rchg2[i2 - 1]) {
+ for (l1 = i1; rchg1[i1 - 1]; i1--);
+ for (l2 = i2; rchg2[i2 - 1]; i2--);
+
+ if (!(xch = xdl_add_change(cscr, i1, i2, l1 - i1, l2 - i2))) {
+ xdl_free_script(cscr);
+ return -1;
+ }
+ cscr = xch;
+ }
+
+ *xscr = cscr;
+
+ return 0;
+}
+
+
+void xdl_free_script(xdchange_t *xscr) {
+ xdchange_t *xch;
+
+ while ((xch = xscr) != NULL) {
+ xscr = xscr->next;
+ xdl_free(xch);
+ }
+}
+
+static int xdl_call_hunk_func(xdfenv_t *xe UNUSED, xdchange_t *xscr, xdemitcb_t *ecb,
+ xdemitconf_t const *xecfg)
+{
+ xdchange_t *xch, *xche;
+
+ for (xch = xscr; xch; xch = xche->next) {
+ xche = xdl_get_hunk(&xch, xecfg);
+ if (!xch)
+ break;
+ if (xecfg->hunk_func(xch->i1, xche->i1 + xche->chg1 - xch->i1,
+ xch->i2, xche->i2 + xche->chg2 - xch->i2,
+ ecb->priv) < 0)
+ return -1;
+ }
+ return 0;
+}
+
+static void xdl_mark_ignorable(xdchange_t *xscr, xdfenv_t *xe, long flags)
+{
+ xdchange_t *xch;
+
+ for (xch = xscr; xch; xch = xch->next) {
+ int ignore = 1;
+ xrecord_t **rec;
+ long i;
+
+ rec = &xe->xdf1.recs[xch->i1];
+ for (i = 0; i < xch->chg1 && ignore; i++)
+ ignore = xdl_blankline(rec[i]->ptr, rec[i]->size, flags);
+
+ rec = &xe->xdf2.recs[xch->i2];
+ for (i = 0; i < xch->chg2 && ignore; i++)
+ ignore = xdl_blankline(rec[i]->ptr, rec[i]->size, flags);
+
+ xch->ignore = ignore;
+ }
+}
+
+int xdl_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,
+ xdemitconf_t const *xecfg, xdemitcb_t *ecb) {
+ xdchange_t *xscr;
+ xdfenv_t xe;
+ emit_func_t ef = xecfg->hunk_func ? xdl_call_hunk_func : xdl_emit_diff;
+
+ if (xdl_do_diff(mf1, mf2, xpp, &xe) < 0) {
+
+ return -1;
+ }
+ if (xdl_change_compact(&xe.xdf1, &xe.xdf2, xpp->flags) < 0 ||
+ xdl_change_compact(&xe.xdf2, &xe.xdf1, xpp->flags) < 0 ||
+ xdl_build_script(&xe, &xscr) < 0) {
+
+ xdl_free_env(&xe);
+ return -1;
+ }
+ if (xscr) {
+ if (xpp->flags & XDF_IGNORE_BLANK_LINES)
+ xdl_mark_ignorable(xscr, &xe, xpp->flags);
+
+ if (ef(&xe, xscr, ecb, xecfg) < 0) {
+
+ xdl_free_script(xscr);
+ xdl_free_env(&xe);
+ return -1;
+ }
+ xdl_free_script(xscr);
+ }
+ xdl_free_env(&xe);
+
+ return 0;
+}
diff --git a/src/xdiff/xdiffi.h b/src/xdiff/xdiffi.h
new file mode 100644
index 0000000..8f1c7c8
--- /dev/null
+++ b/src/xdiff/xdiffi.h
@@ -0,0 +1,64 @@
+/*
+ * LibXDiff by Davide Libenzi ( File Differential Library )
+ * Copyright (C) 2003 Davide Libenzi
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Davide Libenzi <davidel@xmailserver.org>
+ *
+ */
+
+#if !defined(XDIFFI_H)
+#define XDIFFI_H
+
+
+typedef struct s_diffdata {
+ long nrec;
+ unsigned long const *ha;
+ long *rindex;
+ char *rchg;
+} diffdata_t;
+
+typedef struct s_xdalgoenv {
+ long mxcost;
+ long snake_cnt;
+ long heur_min;
+} xdalgoenv_t;
+
+typedef struct s_xdchange {
+ struct s_xdchange *next;
+ long i1, i2;
+ long chg1, chg2;
+ int ignore;
+} xdchange_t;
+
+
+
+int xdl_recs_cmp(diffdata_t *dd1, long off1, long lim1,
+ diffdata_t *dd2, long off2, long lim2,
+ long *kvdf, long *kvdb, int need_min, xdalgoenv_t *xenv);
+int xdl_do_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,
+ xdfenv_t *xe);
+int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags);
+int xdl_build_script(xdfenv_t *xe, xdchange_t **xscr);
+void xdl_free_script(xdchange_t *xscr);
+int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
+ xdemitconf_t const *xecfg);
+int xdl_do_patience_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,
+ xdfenv_t *env);
+int xdl_do_histogram_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,
+ xdfenv_t *env);
+
+#endif /* #if !defined(XDIFFI_H) */
diff --git a/src/xdiff/xemit.c b/src/xdiff/xemit.c
new file mode 100644
index 0000000..d8a6f1e
--- /dev/null
+++ b/src/xdiff/xemit.c
@@ -0,0 +1,332 @@
+/*
+ * LibXDiff by Davide Libenzi ( File Differential Library )
+ * Copyright (C) 2003 Davide Libenzi
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Davide Libenzi <davidel@xmailserver.org>
+ *
+ */
+
+#include "xinclude.h"
+
+static long xdl_get_rec(xdfile_t *xdf, long ri, char const **rec) {
+
+ *rec = xdf->recs[ri]->ptr;
+
+ return xdf->recs[ri]->size;
+}
+
+
+static int xdl_emit_record(xdfile_t *xdf, long ri, char const *pre, xdemitcb_t *ecb) {
+ long size, psize = (long)strlen(pre);
+ char const *rec;
+
+ size = xdl_get_rec(xdf, ri, &rec);
+ if (xdl_emit_diffrec(rec, size, pre, psize, ecb) < 0) {
+
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/*
+ * Starting at the passed change atom, find the latest change atom to be included
+ * inside the differential hunk according to the specified configuration.
+ * Also advance xscr if the first changes must be discarded.
+ */
+xdchange_t *xdl_get_hunk(xdchange_t **xscr, xdemitconf_t const *xecfg)
+{
+ xdchange_t *xch, *xchp, *lxch;
+ long max_common = 2 * xecfg->ctxlen + xecfg->interhunkctxlen;
+ long max_ignorable = xecfg->ctxlen;
+ unsigned long ignored = 0; /* number of ignored blank lines */
+
+ /* remove ignorable changes that are too far before other changes */
+ for (xchp = *xscr; xchp && xchp->ignore; xchp = xchp->next) {
+ xch = xchp->next;
+
+ if (xch == NULL ||
+ xch->i1 - (xchp->i1 + xchp->chg1) >= max_ignorable)
+ *xscr = xch;
+ }
+
+ if (*xscr == NULL)
+ return NULL;
+
+ lxch = *xscr;
+
+ for (xchp = *xscr, xch = xchp->next; xch; xchp = xch, xch = xch->next) {
+ long distance = xch->i1 - (xchp->i1 + xchp->chg1);
+ if (distance > max_common)
+ break;
+
+ if (distance < max_ignorable && (!xch->ignore || lxch == xchp)) {
+ lxch = xch;
+ ignored = 0;
+ } else if (distance < max_ignorable && xch->ignore) {
+ ignored += xch->chg2;
+ } else if (lxch != xchp &&
+ xch->i1 + (long)ignored - (lxch->i1 + lxch->chg1) > max_common) {
+ break;
+ } else if (!xch->ignore) {
+ lxch = xch;
+ ignored = 0;
+ } else {
+ ignored += xch->chg2;
+ }
+ }
+
+ return lxch;
+}
+
+
+#if 0
+static long def_ff(const char *rec, long len, char *buf, long sz, void *priv UNUSED)
+{
+ if (len > 0 &&
+ (isalpha((unsigned char)*rec) || /* identifier? */
+ *rec == '_' || /* also identifier? */
+ *rec == '$')) { /* identifiers from VMS and other esoterico */
+ if (len > sz)
+ len = sz;
+ while (0 < len && isspace((unsigned char)rec[len - 1]))
+ len--;
+ memcpy(buf, rec, len);
+ return len;
+ }
+ return -1;
+}
+#endif
+
+#if 0
+static long match_func_rec(xdfile_t *xdf, xdemitconf_t const *xecfg, long ri,
+ char *buf, long sz)
+{
+ const char *rec;
+ long len = xdl_get_rec(xdf, ri, &rec);
+ if (!xecfg->find_func)
+ return def_ff(rec, len, buf, sz, xecfg->find_func_priv);
+ return xecfg->find_func(rec, len, buf, sz, xecfg->find_func_priv);
+}
+#endif
+
+#if 0
+static int is_func_rec(xdfile_t *xdf, xdemitconf_t const *xecfg, long ri)
+{
+ char dummy[1];
+ return match_func_rec(xdf, xecfg, ri, dummy, sizeof(dummy)) >= 0;
+}
+#endif
+
+struct func_line {
+ long len;
+ char buf[80];
+};
+
+#if 0
+static long get_func_line(xdfenv_t *xe, xdemitconf_t const *xecfg,
+ struct func_line *func_line, long start, long limit)
+{
+ long l, size, step = (start > limit) ? -1 : 1;
+ char *buf, dummy[1];
+
+ buf = func_line ? func_line->buf : dummy;
+ size = func_line ? sizeof(func_line->buf) : sizeof(dummy);
+
+ for (l = start; l != limit && 0 <= l && l < xe->xdf1.nrec; l += step) {
+ long len = match_func_rec(&xe->xdf1, xecfg, l, buf, size);
+ if (len >= 0) {
+ if (func_line)
+ func_line->len = len;
+ return l;
+ }
+ }
+ return -1;
+}
+#endif
+
+#if 0
+static int is_empty_rec(xdfile_t *xdf, long ri)
+{
+ const char *rec;
+ long len = xdl_get_rec(xdf, ri, &rec);
+
+ while (len > 0 && XDL_ISSPACE(*rec)) {
+ rec++;
+ len--;
+ }
+ return !len;
+}
+#endif
+
+int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
+ xdemitconf_t const *xecfg) {
+ long s1, s2, e1, e2, lctx;
+ xdchange_t *xch, *xche;
+#if 0
+ long funclineprev = -1;
+#endif
+ struct func_line func_line;
+
+ func_line.len = 0;
+
+ for (xch = xscr; xch; xch = xche->next) {
+ xche = xdl_get_hunk(&xch, xecfg);
+ if (!xch)
+ break;
+
+ s1 = XDL_MAX(xch->i1 - xecfg->ctxlen, 0);
+ s2 = XDL_MAX(xch->i2 - xecfg->ctxlen, 0);
+
+#if 0
+ if (xecfg->flags & XDL_EMIT_FUNCCONTEXT) {
+ long fs1, i1 = xch->i1;
+
+ /* Appended chunk? */
+ if (i1 >= xe->xdf1.nrec) {
+ long i2 = xch->i2;
+
+ /*
+ * We don't need additional context if
+ * a whole function was added.
+ */
+ while (i2 < xe->xdf2.nrec) {
+ if (is_func_rec(&xe->xdf2, xecfg, i2))
+ goto post_context_calculation;
+ i2++;
+ }
+
+ /*
+ * Otherwise get more context from the
+ * pre-image.
+ */
+ i1 = xe->xdf1.nrec - 1;
+ }
+
+ fs1 = get_func_line(xe, xecfg, NULL, i1, -1);
+ while (fs1 > 0 && !is_empty_rec(&xe->xdf1, fs1 - 1) &&
+ !is_func_rec(&xe->xdf1, xecfg, fs1 - 1))
+ fs1--;
+ if (fs1 < 0)
+ fs1 = 0;
+ if (fs1 < s1) {
+ s2 -= s1 - fs1;
+ s1 = fs1;
+ }
+ }
+
+ post_context_calculation:
+#endif
+ lctx = xecfg->ctxlen;
+ lctx = XDL_MIN(lctx, xe->xdf1.nrec - (xche->i1 + xche->chg1));
+ lctx = XDL_MIN(lctx, xe->xdf2.nrec - (xche->i2 + xche->chg2));
+
+ e1 = xche->i1 + xche->chg1 + lctx;
+ e2 = xche->i2 + xche->chg2 + lctx;
+
+#if 0
+ if (xecfg->flags & XDL_EMIT_FUNCCONTEXT) {
+ long fe1 = get_func_line(xe, xecfg, NULL,
+ xche->i1 + xche->chg1,
+ xe->xdf1.nrec);
+ while (fe1 > 0 && is_empty_rec(&xe->xdf1, fe1 - 1))
+ fe1--;
+ if (fe1 < 0)
+ fe1 = xe->xdf1.nrec;
+ if (fe1 > e1) {
+ e2 += fe1 - e1;
+ e1 = fe1;
+ }
+
+ /*
+ * Overlap with next change? Then include it
+ * in the current hunk and start over to find
+ * its new end.
+ */
+ if (xche->next) {
+ long l = XDL_MIN(xche->next->i1,
+ xe->xdf1.nrec - 1);
+ if (l - xecfg->ctxlen <= e1 ||
+ get_func_line(xe, xecfg, NULL, l, e1) < 0) {
+ xche = xche->next;
+ goto post_context_calculation;
+ }
+ }
+ }
+#endif
+
+ /*
+ * Emit current hunk header.
+ */
+
+#if 0
+ if (xecfg->flags & XDL_EMIT_FUNCNAMES) {
+ get_func_line(xe, xecfg, &func_line,
+ s1 - 1, funclineprev);
+ funclineprev = s1 - 1;
+ }
+#endif
+ if (xdl_emit_hunk_hdr(s1 + 1, e1 - s1, s2 + 1, e2 - s2,
+ func_line.buf, func_line.len, ecb) < 0)
+ return -1;
+
+ /*
+ * Emit pre-context.
+ */
+ for (; s2 < xch->i2; s2++)
+ if (xdl_emit_record(&xe->xdf2, s2, " ", ecb) < 0)
+ return -1;
+
+ for (s1 = xch->i1, s2 = xch->i2;; xch = xch->next) {
+ /*
+ * Merge previous with current change atom.
+ */
+ for (; s1 < xch->i1 && s2 < xch->i2; s1++, s2++)
+ if (xdl_emit_record(&xe->xdf2, s2, " ", ecb) < 0)
+ return -1;
+
+ /*
+ * Removes lines from the first file.
+ */
+ for (s1 = xch->i1; s1 < xch->i1 + xch->chg1; s1++)
+ if (xdl_emit_record(&xe->xdf1, s1, "-", ecb) < 0)
+ return -1;
+
+ /*
+ * Adds lines from the second file.
+ */
+ for (s2 = xch->i2; s2 < xch->i2 + xch->chg2; s2++)
+ if (xdl_emit_record(&xe->xdf2, s2, "+", ecb) < 0)
+ return -1;
+
+ if (xch == xche)
+ break;
+ s1 = xch->i1 + xch->chg1;
+ s2 = xch->i2 + xch->chg2;
+ }
+
+ /*
+ * Emit post-context.
+ */
+ for (s2 = xche->i2 + xche->chg2; s2 < e2; s2++)
+ if (xdl_emit_record(&xe->xdf2, s2, " ", ecb) < 0)
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/src/xdiff/xemit.h b/src/xdiff/xemit.h
new file mode 100644
index 0000000..1b9887e
--- /dev/null
+++ b/src/xdiff/xemit.h
@@ -0,0 +1,36 @@
+/*
+ * LibXDiff by Davide Libenzi ( File Differential Library )
+ * Copyright (C) 2003 Davide Libenzi
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Davide Libenzi <davidel@xmailserver.org>
+ *
+ */
+
+#if !defined(XEMIT_H)
+#define XEMIT_H
+
+
+typedef int (*emit_func_t)(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
+ xdemitconf_t const *xecfg);
+
+xdchange_t *xdl_get_hunk(xdchange_t **xscr, xdemitconf_t const *xecfg);
+int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
+ xdemitconf_t const *xecfg);
+
+
+
+#endif /* #if !defined(XEMIT_H) */
diff --git a/src/xdiff/xhistogram.c b/src/xdiff/xhistogram.c
new file mode 100644
index 0000000..3fb8974
--- /dev/null
+++ b/src/xdiff/xhistogram.c
@@ -0,0 +1,386 @@
+/*
+ * Copyright (C) 2010, Google Inc.
+ * and other copyright owners as documented in JGit's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "xinclude.h"
+#include "xtypes.h"
+#include "xdiff.h"
+
+#define MAX_PTR INT_MAX
+#define MAX_CNT INT_MAX
+
+#define LINE_END(n) (line##n + count##n - 1)
+#define LINE_END_PTR(n) (*line##n + *count##n - 1)
+
+struct histindex {
+ struct record {
+ unsigned int ptr, cnt;
+ struct record *next;
+ } **records, /* an occurrence */
+ **line_map; /* map of line to record chain */
+ chastore_t rcha;
+ unsigned int *next_ptrs;
+ unsigned int table_bits,
+ records_size,
+ line_map_size;
+
+ unsigned int max_chain_length,
+ key_shift,
+ ptr_shift;
+
+ unsigned int cnt,
+ has_common;
+
+ xdfenv_t *env;
+ xpparam_t const *xpp;
+};
+
+struct region {
+ unsigned int begin1, end1;
+ unsigned int begin2, end2;
+};
+
+#define LINE_MAP(i, a) (i->line_map[(a) - i->ptr_shift])
+
+#define NEXT_PTR(index, ptr) \
+ (index->next_ptrs[(ptr) - index->ptr_shift])
+
+#define CNT(index, ptr) \
+ ((LINE_MAP(index, ptr))->cnt)
+
+#define REC(env, s, l) \
+ (env->xdf##s.recs[l - 1])
+
+static int cmp_recs(xpparam_t const *xpp,
+ xrecord_t *r1, xrecord_t *r2)
+{
+ return r1->ha == r2->ha &&
+ xdl_recmatch(r1->ptr, r1->size, r2->ptr, r2->size,
+ xpp->flags);
+}
+
+#define CMP_ENV(xpp, env, s1, l1, s2, l2) \
+ (cmp_recs(xpp, REC(env, s1, l1), REC(env, s2, l2)))
+
+#define CMP(i, s1, l1, s2, l2) \
+ (cmp_recs(i->xpp, REC(i->env, s1, l1), REC(i->env, s2, l2)))
+
+#define TABLE_HASH(index, side, line) \
+ XDL_HASHLONG((REC(index->env, side, line))->ha, index->table_bits)
+
+static int scanA(struct histindex *index, int line1, int count1)
+{
+ int ptr, tbl_idx;
+ unsigned int chain_len;
+ struct record **rec_chain, *rec;
+
+ for (ptr = LINE_END(1); line1 <= ptr; ptr--) {
+ tbl_idx = TABLE_HASH(index, 1, ptr);
+ rec_chain = index->records + tbl_idx;
+ rec = *rec_chain;
+
+ chain_len = 0;
+ while (rec) {
+ if (CMP(index, 1, rec->ptr, 1, ptr)) {
+ /*
+ * ptr is identical to another element. Insert
+ * it onto the front of the existing element
+ * chain.
+ */
+ NEXT_PTR(index, ptr) = rec->ptr;
+ rec->ptr = ptr;
+ /* cap rec->cnt at MAX_CNT */
+ rec->cnt = XDL_MIN(MAX_CNT, rec->cnt + 1);
+ LINE_MAP(index, ptr) = rec;
+ goto continue_scan;
+ }
+
+ rec = rec->next;
+ chain_len++;
+ }
+
+ if (chain_len == index->max_chain_length)
+ return -1;
+
+ /*
+ * This is the first time we have ever seen this particular
+ * element in the sequence. Construct a new chain for it.
+ */
+ if (!(rec = xdl_cha_alloc(&index->rcha)))
+ return -1;
+ rec->ptr = ptr;
+ rec->cnt = 1;
+ rec->next = *rec_chain;
+ *rec_chain = rec;
+ LINE_MAP(index, ptr) = rec;
+
+continue_scan:
+ ; /* no op */
+ }
+
+ return 0;
+}
+
+static int try_lcs(struct histindex *index, struct region *lcs, int b_ptr,
+ int line1, int count1, int line2, int count2)
+{
+ unsigned int b_next = b_ptr + 1;
+ struct record *rec = index->records[TABLE_HASH(index, 2, b_ptr)];
+ unsigned int as, ae, bs, be, np, rc;
+ int should_break;
+
+ for (; rec; rec = rec->next) {
+ if (rec->cnt > index->cnt) {
+ if (!index->has_common)
+ index->has_common = CMP(index, 1, rec->ptr, 2, b_ptr);
+ continue;
+ }
+
+ as = rec->ptr;
+ if (!CMP(index, 1, as, 2, b_ptr))
+ continue;
+
+ index->has_common = 1;
+ for (;;) {
+ should_break = 0;
+ np = NEXT_PTR(index, as);
+ bs = b_ptr;
+ ae = as;
+ be = bs;
+ rc = rec->cnt;
+
+ while (line1 < (int)as && line2 < (int)bs
+ && CMP(index, 1, as - 1, 2, bs - 1)) {
+ as--;
+ bs--;
+ if (1 < rc)
+ rc = XDL_MIN(rc, CNT(index, as));
+ }
+ while ((int)ae < LINE_END(1) && (int)be < LINE_END(2)
+ && CMP(index, 1, ae + 1, 2, be + 1)) {
+ ae++;
+ be++;
+ if (1 < rc)
+ rc = XDL_MIN(rc, CNT(index, ae));
+ }
+
+ if (b_next <= be)
+ b_next = be + 1;
+ if (lcs->end1 - lcs->begin1 < ae - as || rc < index->cnt) {
+ lcs->begin1 = as;
+ lcs->begin2 = bs;
+ lcs->end1 = ae;
+ lcs->end2 = be;
+ index->cnt = rc;
+ }
+
+ if (np == 0)
+ break;
+
+ while (np <= ae) {
+ np = NEXT_PTR(index, np);
+ if (np == 0) {
+ should_break = 1;
+ break;
+ }
+ }
+
+ if (should_break)
+ break;
+
+ as = np;
+ }
+ }
+ return b_next;
+}
+
+static int fall_back_to_classic_diff(xpparam_t const *xpp, xdfenv_t *env,
+ int line1, int count1, int line2, int count2)
+{
+ xpparam_t xpparam;
+ xpparam.flags = xpp->flags & ~XDF_DIFF_ALGORITHM_MASK;
+
+ return xdl_fall_back_diff(env, &xpparam,
+ line1, count1, line2, count2);
+}
+
+static inline void free_index(struct histindex *index)
+{
+ xdl_free(index->records);
+ xdl_free(index->line_map);
+ xdl_free(index->next_ptrs);
+ xdl_cha_free(&index->rcha);
+}
+
+static int find_lcs(xpparam_t const *xpp, xdfenv_t *env,
+ struct region *lcs,
+ int line1, int count1, int line2, int count2)
+{
+ int b_ptr;
+ int sz, ret = -1;
+ struct histindex index;
+
+ memset(&index, 0, sizeof(index));
+
+ index.env = env;
+ index.xpp = xpp;
+
+ index.records = NULL;
+ index.line_map = NULL;
+ /* in case of early xdl_cha_free() */
+ index.rcha.head = NULL;
+
+ index.table_bits = xdl_hashbits(count1);
+ sz = index.records_size = 1 << index.table_bits;
+ sz *= sizeof(struct record *);
+ if (!(index.records = (struct record **) xdl_malloc(sz)))
+ goto cleanup;
+ memset(index.records, 0, sz);
+
+ sz = index.line_map_size = count1;
+ sz *= sizeof(struct record *);
+ if (!(index.line_map = (struct record **) xdl_malloc(sz)))
+ goto cleanup;
+ memset(index.line_map, 0, sz);
+
+ sz = index.line_map_size;
+ sz *= sizeof(unsigned int);
+ if (!(index.next_ptrs = (unsigned int *) xdl_malloc(sz)))
+ goto cleanup;
+ memset(index.next_ptrs, 0, sz);
+
+ /* lines / 4 + 1 comes from xprepare.c:xdl_prepare_ctx() */
+ if (xdl_cha_init(&index.rcha, sizeof(struct record), count1 / 4 + 1) < 0)
+ goto cleanup;
+
+ index.ptr_shift = line1;
+ index.max_chain_length = 64;
+
+ if (scanA(&index, line1, count1))
+ goto cleanup;
+
+ index.cnt = index.max_chain_length + 1;
+
+ for (b_ptr = line2; b_ptr <= LINE_END(2); )
+ b_ptr = try_lcs(&index, lcs, b_ptr, line1, count1, line2, count2);
+
+ if (index.has_common && index.max_chain_length < index.cnt)
+ ret = 1;
+ else
+ ret = 0;
+
+cleanup:
+ free_index(&index);
+ return ret;
+}
+
+static int histogram_diff(xpparam_t const *xpp, xdfenv_t *env,
+ int line1, int count1, int line2, int count2)
+{
+ struct region lcs;
+ int lcs_found;
+ int result;
+redo:
+ result = -1;
+
+ if (count1 <= 0 && count2 <= 0)
+ return 0;
+
+ if (LINE_END(1) >= MAX_PTR)
+ return -1;
+
+ if (!count1) {
+ while(count2--)
+ env->xdf2.rchg[line2++ - 1] = 1;
+ return 0;
+ } else if (!count2) {
+ while(count1--)
+ env->xdf1.rchg[line1++ - 1] = 1;
+ return 0;
+ }
+
+ memset(&lcs, 0, sizeof(lcs));
+ lcs_found = find_lcs(xpp, env, &lcs, line1, count1, line2, count2);
+ if (lcs_found < 0)
+ goto out;
+ else if (lcs_found)
+ result = fall_back_to_classic_diff(xpp, env, line1, count1, line2, count2);
+ else {
+ if (lcs.begin1 == 0 && lcs.begin2 == 0) {
+ while (count1--)
+ env->xdf1.rchg[line1++ - 1] = 1;
+ while (count2--)
+ env->xdf2.rchg[line2++ - 1] = 1;
+ result = 0;
+ } else {
+ result = histogram_diff(xpp, env,
+ line1, lcs.begin1 - line1,
+ line2, lcs.begin2 - line2);
+ if (result)
+ goto out;
+ /*
+ * result = histogram_diff(xpp, env,
+ * lcs.end1 + 1, LINE_END(1) - lcs.end1,
+ * lcs.end2 + 1, LINE_END(2) - lcs.end2);
+ * but let's optimize tail recursion ourself:
+ */
+ count1 = LINE_END(1) - lcs.end1;
+ line1 = lcs.end1 + 1;
+ count2 = LINE_END(2) - lcs.end2;
+ line2 = lcs.end2 + 1;
+ goto redo;
+ }
+ }
+out:
+ return result;
+}
+
+int xdl_do_histogram_diff(mmfile_t *file1, mmfile_t *file2,
+ xpparam_t const *xpp, xdfenv_t *env)
+{
+ if (xdl_prepare_env(file1, file2, xpp, env) < 0)
+ return -1;
+
+ return histogram_diff(xpp, env,
+ env->xdf1.dstart + 1, env->xdf1.dend - env->xdf1.dstart + 1,
+ env->xdf2.dstart + 1, env->xdf2.dend - env->xdf2.dstart + 1);
+}
diff --git a/src/xdiff/xinclude.h b/src/xdiff/xinclude.h
new file mode 100644
index 0000000..752c9f3
--- /dev/null
+++ b/src/xdiff/xinclude.h
@@ -0,0 +1,65 @@
+/*
+ * LibXDiff by Davide Libenzi ( File Differential Library )
+ * Copyright (C) 2003 Davide Libenzi
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Davide Libenzi <davidel@xmailserver.org>
+ *
+ */
+
+/* defines HAVE_ATTRIBUTE_UNUSED */
+#ifdef HAVE_CONFIG_H
+# ifdef VMS
+# include "[.auto]config.h"
+# else
+# include "../auto/config.h"
+# endif
+#endif
+
+/* Mark unused function arguments with UNUSED, so that gcc -Wunused-parameter
+ * can be used to check for mistakes. */
+#ifdef HAVE_ATTRIBUTE_UNUSED
+# define UNUSED __attribute__((unused))
+#else
+# define UNUSED
+#endif
+
+#if defined(_MSC_VER)
+# define inline __inline
+#endif
+
+#if !defined(XINCLUDE_H)
+#define XINCLUDE_H
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#if !defined(_WIN32)
+#include <unistd.h>
+#endif
+#include <string.h>
+#include <limits.h>
+
+#include "xmacros.h"
+#include "xdiff.h"
+#include "xtypes.h"
+#include "xutils.h"
+#include "xprepare.h"
+#include "xdiffi.h"
+#include "xemit.h"
+
+
+#endif /* #if !defined(XINCLUDE_H) */
diff --git a/src/xdiff/xmacros.h b/src/xdiff/xmacros.h
new file mode 100644
index 0000000..2809a28
--- /dev/null
+++ b/src/xdiff/xmacros.h
@@ -0,0 +1,54 @@
+/*
+ * LibXDiff by Davide Libenzi ( File Differential Library )
+ * Copyright (C) 2003 Davide Libenzi
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Davide Libenzi <davidel@xmailserver.org>
+ *
+ */
+
+#if !defined(XMACROS_H)
+#define XMACROS_H
+
+
+
+
+#define XDL_MIN(a, b) ((a) < (b) ? (a): (b))
+#define XDL_MAX(a, b) ((a) > (b) ? (a): (b))
+#define XDL_ABS(v) ((v) >= 0 ? (v): -(v))
+#define XDL_ISDIGIT(c) ((c) >= '0' && (c) <= '9')
+#define XDL_ISSPACE(c) (isspace((unsigned char)(c)))
+#define XDL_ADDBITS(v,b) ((v) + ((v) >> (b)))
+#define XDL_MASKBITS(b) ((1UL << (b)) - 1)
+#define XDL_HASHLONG(v,b) (XDL_ADDBITS((unsigned long)(v), b) & XDL_MASKBITS(b))
+#define XDL_PTRFREE(p) do { if (p) { xdl_free(p); (p) = NULL; } } while (0)
+#define XDL_LE32_PUT(p, v) \
+do { \
+ unsigned char *__p = (unsigned char *) (p); \
+ *__p++ = (unsigned char) (v); \
+ *__p++ = (unsigned char) ((v) >> 8); \
+ *__p++ = (unsigned char) ((v) >> 16); \
+ *__p = (unsigned char) ((v) >> 24); \
+} while (0)
+#define XDL_LE32_GET(p, v) \
+do { \
+ unsigned char const *__p = (unsigned char const *) (p); \
+ (v) = (unsigned long) __p[0] | ((unsigned long) __p[1]) << 8 | \
+ ((unsigned long) __p[2]) << 16 | ((unsigned long) __p[3]) << 24; \
+} while (0)
+
+
+#endif /* #if !defined(XMACROS_H) */
diff --git a/src/xdiff/xpatience.c b/src/xdiff/xpatience.c
new file mode 100644
index 0000000..2c65aac
--- /dev/null
+++ b/src/xdiff/xpatience.c
@@ -0,0 +1,393 @@
+/*
+ * LibXDiff by Davide Libenzi ( File Differential Library )
+ * Copyright (C) 2003-2016 Davide Libenzi, Johannes E. Schindelin
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Davide Libenzi <davidel@xmailserver.org>
+ *
+ */
+#include "xinclude.h"
+#include "xtypes.h"
+#include "xdiff.h"
+
+/*
+ * The basic idea of patience diff is to find lines that are unique in
+ * both files. These are intuitively the ones that we want to see as
+ * common lines.
+ *
+ * The maximal ordered sequence of such line pairs (where ordered means
+ * that the order in the sequence agrees with the order of the lines in
+ * both files) naturally defines an initial set of common lines.
+ *
+ * Now, the algorithm tries to extend the set of common lines by growing
+ * the line ranges where the files have identical lines.
+ *
+ * Between those common lines, the patience diff algorithm is applied
+ * recursively, until no unique line pairs can be found; these line ranges
+ * are handled by the well-known Myers algorithm.
+ */
+
+#define NON_UNIQUE ULONG_MAX
+
+/*
+ * This is a hash mapping from line hash to line numbers in the first and
+ * second file.
+ */
+struct hashmap {
+ int nr, alloc;
+ struct entry {
+ unsigned long hash;
+ /*
+ * 0 = unused entry, 1 = first line, 2 = second, etc.
+ * line2 is NON_UNIQUE if the line is not unique
+ * in either the first or the second file.
+ */
+ unsigned long line1, line2;
+ /*
+ * "next" & "previous" are used for the longest common
+ * sequence;
+ * initially, "next" reflects only the order in file1.
+ */
+ struct entry *next, *previous;
+
+ /*
+ * If 1, this entry can serve as an anchor. See
+ * Documentation/diff-options.txt for more information.
+ */
+ unsigned anchor : 1;
+ } *entries, *first, *last;
+ /* were common records found? */
+ unsigned long has_matches;
+ mmfile_t *file1, *file2;
+ xdfenv_t *env;
+ xpparam_t const *xpp;
+};
+
+static int is_anchor(xpparam_t const *xpp, const char *line)
+{
+ size_t i;
+ for (i = 0; i < xpp->anchors_nr; i++) {
+ if (!strncmp(line, xpp->anchors[i], strlen(xpp->anchors[i])))
+ return 1;
+ }
+ return 0;
+}
+
+/* The argument "pass" is 1 for the first file, 2 for the second. */
+static void insert_record(xpparam_t const *xpp, int line, struct hashmap *map,
+ int pass)
+{
+ xrecord_t **records = pass == 1 ?
+ map->env->xdf1.recs : map->env->xdf2.recs;
+ xrecord_t *record = records[line - 1], *other;
+ /*
+ * After xdl_prepare_env() (or more precisely, due to
+ * xdl_classify_record()), the "ha" member of the records (AKA lines)
+ * is _not_ the hash anymore, but a linearized version of it. In
+ * other words, the "ha" member is guaranteed to start with 0 and
+ * the second record's ha can only be 0 or 1, etc.
+ *
+ * So we multiply ha by 2 in the hope that the hashing was
+ * "unique enough".
+ */
+ int index = (int)((record->ha << 1) % map->alloc);
+
+ while (map->entries[index].line1) {
+ other = map->env->xdf1.recs[map->entries[index].line1 - 1];
+ if (map->entries[index].hash != record->ha ||
+ !xdl_recmatch(record->ptr, record->size,
+ other->ptr, other->size,
+ map->xpp->flags)) {
+ if (++index >= map->alloc)
+ index = 0;
+ continue;
+ }
+ if (pass == 2)
+ map->has_matches = 1;
+ if (pass == 1 || map->entries[index].line2)
+ map->entries[index].line2 = NON_UNIQUE;
+ else
+ map->entries[index].line2 = line;
+ return;
+ }
+ if (pass == 2)
+ return;
+ map->entries[index].line1 = line;
+ map->entries[index].hash = record->ha;
+ map->entries[index].anchor = is_anchor(xpp, map->env->xdf1.recs[line - 1]->ptr);
+ if (!map->first)
+ map->first = map->entries + index;
+ if (map->last) {
+ map->last->next = map->entries + index;
+ map->entries[index].previous = map->last;
+ }
+ map->last = map->entries + index;
+ map->nr++;
+}
+
+/*
+ * This function has to be called for each recursion into the inter-hunk
+ * parts, as previously non-unique lines can become unique when being
+ * restricted to a smaller part of the files.
+ *
+ * It is assumed that env has been prepared using xdl_prepare().
+ */
+static int fill_hashmap(mmfile_t *file1, mmfile_t *file2,
+ xpparam_t const *xpp, xdfenv_t *env,
+ struct hashmap *result,
+ int line1, int count1, int line2, int count2)
+{
+ result->file1 = file1;
+ result->file2 = file2;
+ result->xpp = xpp;
+ result->env = env;
+
+ /* We know exactly how large we want the hash map */
+ result->alloc = count1 * 2;
+ result->entries = (struct entry *)
+ xdl_malloc(result->alloc * sizeof(struct entry));
+ if (!result->entries)
+ return -1;
+ memset(result->entries, 0, result->alloc * sizeof(struct entry));
+
+ /* First, fill with entries from the first file */
+ while (count1--)
+ insert_record(xpp, line1++, result, 1);
+
+ /* Then search for matches in the second file */
+ while (count2--)
+ insert_record(xpp, line2++, result, 2);
+
+ return 0;
+}
+
+/*
+ * Find the longest sequence with a smaller last element (meaning a smaller
+ * line2, as we construct the sequence with entries ordered by line1).
+ */
+static int binary_search(struct entry **sequence, int longest,
+ struct entry *entry)
+{
+ int left = -1, right = longest;
+
+ while (left + 1 < right) {
+ int middle = left + (right - left) / 2;
+ /* by construction, no two entries can be equal */
+ if (sequence[middle]->line2 > entry->line2)
+ right = middle;
+ else
+ left = middle;
+ }
+ /* return the index in "sequence", _not_ the sequence length */
+ return left;
+}
+
+/*
+ * The idea is to start with the list of common unique lines sorted by
+ * the order in file1. For each of these pairs, the longest (partial)
+ * sequence whose last element's line2 is smaller is determined.
+ *
+ * For efficiency, the sequences are kept in a list containing exactly one
+ * item per sequence length: the sequence with the smallest last
+ * element (in terms of line2).
+ */
+static struct entry *find_longest_common_sequence(struct hashmap *map)
+{
+ struct entry **sequence = (struct entry **)xdl_malloc(map->nr * sizeof(struct entry *));
+ int longest = 0, i;
+ struct entry *entry;
+ /*
+ * If not -1, this entry in sequence must never be overridden.
+ * Therefore, overriding entries before this has no effect, so
+ * do not do that either.
+ */
+ int anchor_i = -1;
+
+ /* Added to silence Coverity. */
+ if (sequence == NULL)
+ return map->first;
+
+ for (entry = map->first; entry; entry = entry->next) {
+ if (!entry->line2 || entry->line2 == NON_UNIQUE)
+ continue;
+ i = binary_search(sequence, longest, entry);
+ entry->previous = i < 0 ? NULL : sequence[i];
+ ++i;
+ if (i <= anchor_i)
+ continue;
+ sequence[i] = entry;
+ if (entry->anchor) {
+ anchor_i = i;
+ longest = anchor_i + 1;
+ } else if (i == longest) {
+ longest++;
+ }
+ }
+
+ /* No common unique lines were found */
+ if (!longest) {
+ xdl_free(sequence);
+ return NULL;
+ }
+
+ /* Iterate starting at the last element, adjusting the "next" members */
+ entry = sequence[longest - 1];
+ entry->next = NULL;
+ while (entry->previous) {
+ entry->previous->next = entry;
+ entry = entry->previous;
+ }
+ xdl_free(sequence);
+ return entry;
+}
+
+static int match(struct hashmap *map, int line1, int line2)
+{
+ xrecord_t *record1 = map->env->xdf1.recs[line1 - 1];
+ xrecord_t *record2 = map->env->xdf2.recs[line2 - 1];
+ return xdl_recmatch(record1->ptr, record1->size,
+ record2->ptr, record2->size, map->xpp->flags);
+}
+
+static int patience_diff(mmfile_t *file1, mmfile_t *file2,
+ xpparam_t const *xpp, xdfenv_t *env,
+ int line1, int count1, int line2, int count2);
+
+static int walk_common_sequence(struct hashmap *map, struct entry *first,
+ int line1, int count1, int line2, int count2)
+{
+ int end1 = line1 + count1, end2 = line2 + count2;
+ int next1, next2;
+
+ for (;;) {
+ /* Try to grow the line ranges of common lines */
+ if (first) {
+ next1 = first->line1;
+ next2 = first->line2;
+ while (next1 > line1 && next2 > line2 &&
+ match(map, next1 - 1, next2 - 1)) {
+ next1--;
+ next2--;
+ }
+ } else {
+ next1 = end1;
+ next2 = end2;
+ }
+ while (line1 < next1 && line2 < next2 &&
+ match(map, line1, line2)) {
+ line1++;
+ line2++;
+ }
+
+ /* Recurse */
+ if (next1 > line1 || next2 > line2) {
+ struct hashmap submap;
+
+ memset(&submap, 0, sizeof(submap));
+ if (patience_diff(map->file1, map->file2,
+ map->xpp, map->env,
+ line1, next1 - line1,
+ line2, next2 - line2))
+ return -1;
+ }
+
+ if (!first)
+ return 0;
+
+ while (first->next &&
+ first->next->line1 == first->line1 + 1 &&
+ first->next->line2 == first->line2 + 1)
+ first = first->next;
+
+ line1 = first->line1 + 1;
+ line2 = first->line2 + 1;
+
+ first = first->next;
+ }
+}
+
+static int fall_back_to_classic_diff(struct hashmap *map,
+ int line1, int count1, int line2, int count2)
+{
+ xpparam_t xpp;
+ xpp.flags = map->xpp->flags & ~XDF_DIFF_ALGORITHM_MASK;
+
+ return xdl_fall_back_diff(map->env, &xpp,
+ line1, count1, line2, count2);
+}
+
+/*
+ * Recursively find the longest common sequence of unique lines,
+ * and if none was found, ask xdl_do_diff() to do the job.
+ *
+ * This function assumes that env was prepared with xdl_prepare_env().
+ */
+static int patience_diff(mmfile_t *file1, mmfile_t *file2,
+ xpparam_t const *xpp, xdfenv_t *env,
+ int line1, int count1, int line2, int count2)
+{
+ struct hashmap map;
+ struct entry *first;
+ int result = 0;
+
+ /* trivial case: one side is empty */
+ if (!count1) {
+ while(count2--)
+ env->xdf2.rchg[line2++ - 1] = 1;
+ return 0;
+ } else if (!count2) {
+ while(count1--)
+ env->xdf1.rchg[line1++ - 1] = 1;
+ return 0;
+ }
+
+ memset(&map, 0, sizeof(map));
+ if (fill_hashmap(file1, file2, xpp, env, &map,
+ line1, count1, line2, count2))
+ return -1;
+
+ /* are there any matching lines at all? */
+ if (!map.has_matches) {
+ while(count1--)
+ env->xdf1.rchg[line1++ - 1] = 1;
+ while(count2--)
+ env->xdf2.rchg[line2++ - 1] = 1;
+ xdl_free(map.entries);
+ return 0;
+ }
+
+ first = find_longest_common_sequence(&map);
+ if (first)
+ result = walk_common_sequence(&map, first,
+ line1, count1, line2, count2);
+ else
+ result = fall_back_to_classic_diff(&map,
+ line1, count1, line2, count2);
+
+ xdl_free(map.entries);
+ return result;
+}
+
+int xdl_do_patience_diff(mmfile_t *file1, mmfile_t *file2,
+ xpparam_t const *xpp, xdfenv_t *env)
+{
+ if (xdl_prepare_env(file1, file2, xpp, env) < 0)
+ return -1;
+
+ /* environment is cleaned up in xdl_diff() */
+ return patience_diff(file1, file2, xpp, env,
+ 1, env->xdf1.nrec, 1, env->xdf2.nrec);
+}
diff --git a/src/xdiff/xprepare.c b/src/xdiff/xprepare.c
new file mode 100644
index 0000000..abeb8fb
--- /dev/null
+++ b/src/xdiff/xprepare.c
@@ -0,0 +1,483 @@
+/*
+ * LibXDiff by Davide Libenzi ( File Differential Library )
+ * Copyright (C) 2003 Davide Libenzi
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Davide Libenzi <davidel@xmailserver.org>
+ *
+ */
+
+#include "xinclude.h"
+
+
+#define XDL_KPDIS_RUN 4
+#define XDL_MAX_EQLIMIT 1024
+#define XDL_SIMSCAN_WINDOW 100
+#define XDL_GUESS_NLINES1 256
+#define XDL_GUESS_NLINES2 20
+
+
+typedef struct s_xdlclass {
+ struct s_xdlclass *next;
+ unsigned long ha;
+ char const *line;
+ long size;
+ long idx;
+ long len1, len2;
+} xdlclass_t;
+
+typedef struct s_xdlclassifier {
+ unsigned int hbits;
+ long hsize;
+ xdlclass_t **rchash;
+ chastore_t ncha;
+ xdlclass_t **rcrecs;
+ long alloc;
+ long count;
+ long flags;
+} xdlclassifier_t;
+
+
+
+
+static int xdl_init_classifier(xdlclassifier_t *cf, long size, long flags);
+static void xdl_free_classifier(xdlclassifier_t *cf);
+static int xdl_classify_record(unsigned int pass, xdlclassifier_t *cf, xrecord_t **rhash,
+ unsigned int hbits, xrecord_t *rec);
+static int xdl_prepare_ctx(unsigned int pass, mmfile_t *mf, long narec, xpparam_t const *xpp,
+ xdlclassifier_t *cf, xdfile_t *xdf);
+static void xdl_free_ctx(xdfile_t *xdf);
+static int xdl_clean_mmatch(char const *dis, long i, long s, long e);
+static int xdl_cleanup_records(xdlclassifier_t *cf, xdfile_t *xdf1, xdfile_t *xdf2);
+static int xdl_trim_ends(xdfile_t *xdf1, xdfile_t *xdf2);
+static int xdl_optimize_ctxs(xdlclassifier_t *cf, xdfile_t *xdf1, xdfile_t *xdf2);
+
+
+
+
+static int xdl_init_classifier(xdlclassifier_t *cf, long size, long flags) {
+ cf->flags = flags;
+
+ cf->hbits = xdl_hashbits((unsigned int) size);
+ cf->hsize = 1 << cf->hbits;
+
+ if (xdl_cha_init(&cf->ncha, sizeof(xdlclass_t), size / 4 + 1) < 0) {
+
+ return -1;
+ }
+ if (!(cf->rchash = (xdlclass_t **) xdl_malloc(cf->hsize * sizeof(xdlclass_t *)))) {
+
+ xdl_cha_free(&cf->ncha);
+ return -1;
+ }
+ memset(cf->rchash, 0, cf->hsize * sizeof(xdlclass_t *));
+
+ cf->alloc = size;
+ if (!(cf->rcrecs = (xdlclass_t **) xdl_malloc(cf->alloc * sizeof(xdlclass_t *)))) {
+
+ xdl_free(cf->rchash);
+ xdl_cha_free(&cf->ncha);
+ return -1;
+ }
+
+ cf->count = 0;
+
+ return 0;
+}
+
+
+static void xdl_free_classifier(xdlclassifier_t *cf) {
+
+ xdl_free(cf->rcrecs);
+ xdl_free(cf->rchash);
+ xdl_cha_free(&cf->ncha);
+}
+
+
+static int xdl_classify_record(unsigned int pass, xdlclassifier_t *cf, xrecord_t **rhash,
+ unsigned int hbits, xrecord_t *rec) {
+ long hi;
+ char const *line;
+ xdlclass_t *rcrec;
+ xdlclass_t **rcrecs;
+
+ line = rec->ptr;
+ hi = (long) XDL_HASHLONG(rec->ha, cf->hbits);
+ for (rcrec = cf->rchash[hi]; rcrec; rcrec = rcrec->next)
+ if (rcrec->ha == rec->ha &&
+ xdl_recmatch(rcrec->line, rcrec->size,
+ rec->ptr, rec->size, cf->flags))
+ break;
+
+ if (!rcrec) {
+ if (!(rcrec = xdl_cha_alloc(&cf->ncha))) {
+
+ return -1;
+ }
+ rcrec->idx = cf->count++;
+ if (cf->count > cf->alloc) {
+ cf->alloc *= 2;
+ if (!(rcrecs = (xdlclass_t **) xdl_realloc(cf->rcrecs, cf->alloc * sizeof(xdlclass_t *)))) {
+
+ return -1;
+ }
+ cf->rcrecs = rcrecs;
+ }
+ cf->rcrecs[rcrec->idx] = rcrec;
+ rcrec->line = line;
+ rcrec->size = rec->size;
+ rcrec->ha = rec->ha;
+ rcrec->len1 = rcrec->len2 = 0;
+ rcrec->next = cf->rchash[hi];
+ cf->rchash[hi] = rcrec;
+ }
+
+ (pass == 1) ? rcrec->len1++ : rcrec->len2++;
+
+ rec->ha = (unsigned long) rcrec->idx;
+
+ hi = (long) XDL_HASHLONG(rec->ha, hbits);
+ rec->next = rhash[hi];
+ rhash[hi] = rec;
+
+ return 0;
+}
+
+
+static int xdl_prepare_ctx(unsigned int pass, mmfile_t *mf, long narec, xpparam_t const *xpp,
+ xdlclassifier_t *cf, xdfile_t *xdf) {
+ unsigned int hbits;
+ long nrec, hsize, bsize;
+ unsigned long hav;
+ char const *blk, *cur, *top, *prev;
+ xrecord_t *crec;
+ xrecord_t **recs, **rrecs;
+ xrecord_t **rhash;
+ unsigned long *ha;
+ char *rchg;
+ long *rindex;
+
+ ha = NULL;
+ rindex = NULL;
+ rchg = NULL;
+ rhash = NULL;
+ recs = NULL;
+
+ if (xdl_cha_init(&xdf->rcha, sizeof(xrecord_t), narec / 4 + 1) < 0)
+ goto abort;
+ if (!(recs = (xrecord_t **) xdl_malloc(narec * sizeof(xrecord_t *))))
+ goto abort;
+
+ if (XDF_DIFF_ALG(xpp->flags) == XDF_HISTOGRAM_DIFF)
+ hbits = hsize = 0;
+ else {
+ hbits = xdl_hashbits((unsigned int) narec);
+ hsize = 1 << hbits;
+ if (!(rhash = (xrecord_t **) xdl_malloc(hsize * sizeof(xrecord_t *))))
+ goto abort;
+ memset(rhash, 0, hsize * sizeof(xrecord_t *));
+ }
+
+ nrec = 0;
+ if ((cur = blk = xdl_mmfile_first(mf, &bsize)) != NULL) {
+ for (top = blk + bsize; cur < top; ) {
+ prev = cur;
+ hav = xdl_hash_record(&cur, top, xpp->flags);
+ if (nrec >= narec) {
+ narec *= 2;
+ if (!(rrecs = (xrecord_t **) xdl_realloc(recs, narec * sizeof(xrecord_t *))))
+ goto abort;
+ recs = rrecs;
+ }
+ if (!(crec = xdl_cha_alloc(&xdf->rcha)))
+ goto abort;
+ crec->ptr = prev;
+ crec->size = (long) (cur - prev);
+ crec->ha = hav;
+ recs[nrec++] = crec;
+
+ if ((XDF_DIFF_ALG(xpp->flags) != XDF_HISTOGRAM_DIFF) &&
+ xdl_classify_record(pass, cf, rhash, hbits, crec) < 0)
+ goto abort;
+ }
+ }
+
+ if (!(rchg = (char *) xdl_malloc((nrec + 2) * sizeof(char))))
+ goto abort;
+ memset(rchg, 0, (nrec + 2) * sizeof(char));
+
+ if (!(rindex = (long *) xdl_malloc((nrec + 1) * sizeof(long))))
+ goto abort;
+ if (!(ha = (unsigned long *) xdl_malloc((nrec + 1) * sizeof(unsigned long))))
+ goto abort;
+
+ xdf->nrec = nrec;
+ xdf->recs = recs;
+ xdf->hbits = hbits;
+ xdf->rhash = rhash;
+ xdf->rchg = rchg + 1;
+ xdf->rindex = rindex;
+ xdf->nreff = 0;
+ xdf->ha = ha;
+ xdf->dstart = 0;
+ xdf->dend = nrec - 1;
+
+ return 0;
+
+abort:
+ xdl_free(ha);
+ xdl_free(rindex);
+ xdl_free(rchg);
+ xdl_free(rhash);
+ xdl_free(recs);
+ xdl_cha_free(&xdf->rcha);
+ return -1;
+}
+
+
+static void xdl_free_ctx(xdfile_t *xdf) {
+
+ xdl_free(xdf->rhash);
+ xdl_free(xdf->rindex);
+ xdl_free(xdf->rchg - 1);
+ xdl_free(xdf->ha);
+ xdl_free(xdf->recs);
+ xdl_cha_free(&xdf->rcha);
+}
+
+
+int xdl_prepare_env(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,
+ xdfenv_t *xe) {
+ long enl1, enl2, sample;
+ xdlclassifier_t cf;
+
+ memset(&cf, 0, sizeof(cf));
+
+ /*
+ * For histogram diff, we can afford a smaller sample size and
+ * thus a poorer estimate of the number of lines, as the hash
+ * table (rhash) won't be filled up/grown. The number of lines
+ * (nrecs) will be updated correctly anyway by
+ * xdl_prepare_ctx().
+ */
+ sample = (XDF_DIFF_ALG(xpp->flags) == XDF_HISTOGRAM_DIFF
+ ? XDL_GUESS_NLINES2 : XDL_GUESS_NLINES1);
+
+ enl1 = xdl_guess_lines(mf1, sample) + 1;
+ enl2 = xdl_guess_lines(mf2, sample) + 1;
+
+ if (XDF_DIFF_ALG(xpp->flags) != XDF_HISTOGRAM_DIFF &&
+ xdl_init_classifier(&cf, enl1 + enl2 + 1, xpp->flags) < 0)
+ return -1;
+
+ if (xdl_prepare_ctx(1, mf1, enl1, xpp, &cf, &xe->xdf1) < 0) {
+
+ xdl_free_classifier(&cf);
+ return -1;
+ }
+ if (xdl_prepare_ctx(2, mf2, enl2, xpp, &cf, &xe->xdf2) < 0) {
+
+ xdl_free_ctx(&xe->xdf1);
+ xdl_free_classifier(&cf);
+ return -1;
+ }
+
+ if ((XDF_DIFF_ALG(xpp->flags) != XDF_PATIENCE_DIFF) &&
+ (XDF_DIFF_ALG(xpp->flags) != XDF_HISTOGRAM_DIFF) &&
+ xdl_optimize_ctxs(&cf, &xe->xdf1, &xe->xdf2) < 0) {
+
+ xdl_free_ctx(&xe->xdf2);
+ xdl_free_ctx(&xe->xdf1);
+ xdl_free_classifier(&cf);
+ return -1;
+ }
+
+ if (XDF_DIFF_ALG(xpp->flags) != XDF_HISTOGRAM_DIFF)
+ xdl_free_classifier(&cf);
+
+ return 0;
+}
+
+
+void xdl_free_env(xdfenv_t *xe) {
+
+ xdl_free_ctx(&xe->xdf2);
+ xdl_free_ctx(&xe->xdf1);
+}
+
+
+static int xdl_clean_mmatch(char const *dis, long i, long s, long e) {
+ long r, rdis0, rpdis0, rdis1, rpdis1;
+
+ /*
+ * Limits the window the is examined during the similar-lines
+ * scan. The loops below stops when dis[i - r] == 1 (line that
+ * has no match), but there are corner cases where the loop
+ * proceed all the way to the extremities by causing huge
+ * performance penalties in case of big files.
+ */
+ if (i - s > XDL_SIMSCAN_WINDOW)
+ s = i - XDL_SIMSCAN_WINDOW;
+ if (e - i > XDL_SIMSCAN_WINDOW)
+ e = i + XDL_SIMSCAN_WINDOW;
+
+ /*
+ * Scans the lines before 'i' to find a run of lines that either
+ * have no match (dis[j] == 0) or have multiple matches (dis[j] > 1).
+ * Note that we always call this function with dis[i] > 1, so the
+ * current line (i) is already a multimatch line.
+ */
+ for (r = 1, rdis0 = 0, rpdis0 = 1; (i - r) >= s; r++) {
+ if (!dis[i - r])
+ rdis0++;
+ else if (dis[i - r] == 2)
+ rpdis0++;
+ else
+ break;
+ }
+ /*
+ * If the run before the line 'i' found only multimatch lines, we
+ * return 0 and hence we don't make the current line (i) discarded.
+ * We want to discard multimatch lines only when they appear in the
+ * middle of runs with nomatch lines (dis[j] == 0).
+ */
+ if (rdis0 == 0)
+ return 0;
+ for (r = 1, rdis1 = 0, rpdis1 = 1; (i + r) <= e; r++) {
+ if (!dis[i + r])
+ rdis1++;
+ else if (dis[i + r] == 2)
+ rpdis1++;
+ else
+ break;
+ }
+ /*
+ * If the run after the line 'i' found only multimatch lines, we
+ * return 0 and hence we don't make the current line (i) discarded.
+ */
+ if (rdis1 == 0)
+ return 0;
+ rdis1 += rdis0;
+ rpdis1 += rpdis0;
+
+ return rpdis1 * XDL_KPDIS_RUN < (rpdis1 + rdis1);
+}
+
+
+/*
+ * Try to reduce the problem complexity, discard records that have no
+ * matches on the other file. Also, lines that have multiple matches
+ * might be potentially discarded if they happear in a run of discardable.
+ */
+static int xdl_cleanup_records(xdlclassifier_t *cf, xdfile_t *xdf1, xdfile_t *xdf2) {
+ long i, nm, nreff, mlim;
+ xrecord_t **recs;
+ xdlclass_t *rcrec;
+ char *dis, *dis1, *dis2;
+
+ if (!(dis = (char *) xdl_malloc(xdf1->nrec + xdf2->nrec + 2))) {
+
+ return -1;
+ }
+ memset(dis, 0, xdf1->nrec + xdf2->nrec + 2);
+ dis1 = dis;
+ dis2 = dis1 + xdf1->nrec + 1;
+
+ if ((mlim = xdl_bogosqrt(xdf1->nrec)) > XDL_MAX_EQLIMIT)
+ mlim = XDL_MAX_EQLIMIT;
+ for (i = xdf1->dstart, recs = &xdf1->recs[xdf1->dstart]; i <= xdf1->dend; i++, recs++) {
+ rcrec = cf->rcrecs[(*recs)->ha];
+ nm = rcrec ? rcrec->len2 : 0;
+ dis1[i] = (nm == 0) ? 0: (nm >= mlim) ? 2: 1;
+ }
+
+ if ((mlim = xdl_bogosqrt(xdf2->nrec)) > XDL_MAX_EQLIMIT)
+ mlim = XDL_MAX_EQLIMIT;
+ for (i = xdf2->dstart, recs = &xdf2->recs[xdf2->dstart]; i <= xdf2->dend; i++, recs++) {
+ rcrec = cf->rcrecs[(*recs)->ha];
+ nm = rcrec ? rcrec->len1 : 0;
+ dis2[i] = (nm == 0) ? 0: (nm >= mlim) ? 2: 1;
+ }
+
+ for (nreff = 0, i = xdf1->dstart, recs = &xdf1->recs[xdf1->dstart];
+ i <= xdf1->dend; i++, recs++) {
+ if (dis1[i] == 1 ||
+ (dis1[i] == 2 && !xdl_clean_mmatch(dis1, i, xdf1->dstart, xdf1->dend))) {
+ xdf1->rindex[nreff] = i;
+ xdf1->ha[nreff] = (*recs)->ha;
+ nreff++;
+ } else
+ xdf1->rchg[i] = 1;
+ }
+ xdf1->nreff = nreff;
+
+ for (nreff = 0, i = xdf2->dstart, recs = &xdf2->recs[xdf2->dstart];
+ i <= xdf2->dend; i++, recs++) {
+ if (dis2[i] == 1 ||
+ (dis2[i] == 2 && !xdl_clean_mmatch(dis2, i, xdf2->dstart, xdf2->dend))) {
+ xdf2->rindex[nreff] = i;
+ xdf2->ha[nreff] = (*recs)->ha;
+ nreff++;
+ } else
+ xdf2->rchg[i] = 1;
+ }
+ xdf2->nreff = nreff;
+
+ xdl_free(dis);
+
+ return 0;
+}
+
+
+/*
+ * Early trim initial and terminal matching records.
+ */
+static int xdl_trim_ends(xdfile_t *xdf1, xdfile_t *xdf2) {
+ long i, lim;
+ xrecord_t **recs1, **recs2;
+
+ recs1 = xdf1->recs;
+ recs2 = xdf2->recs;
+ for (i = 0, lim = XDL_MIN(xdf1->nrec, xdf2->nrec); i < lim;
+ i++, recs1++, recs2++)
+ if ((*recs1)->ha != (*recs2)->ha)
+ break;
+
+ xdf1->dstart = xdf2->dstart = i;
+
+ recs1 = xdf1->recs + xdf1->nrec - 1;
+ recs2 = xdf2->recs + xdf2->nrec - 1;
+ for (lim -= i, i = 0; i < lim; i++, recs1--, recs2--)
+ if ((*recs1)->ha != (*recs2)->ha)
+ break;
+
+ xdf1->dend = xdf1->nrec - i - 1;
+ xdf2->dend = xdf2->nrec - i - 1;
+
+ return 0;
+}
+
+
+static int xdl_optimize_ctxs(xdlclassifier_t *cf, xdfile_t *xdf1, xdfile_t *xdf2) {
+
+ if (xdl_trim_ends(xdf1, xdf2) < 0 ||
+ xdl_cleanup_records(cf, xdf1, xdf2) < 0) {
+
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/src/xdiff/xprepare.h b/src/xdiff/xprepare.h
new file mode 100644
index 0000000..947d9fc
--- /dev/null
+++ b/src/xdiff/xprepare.h
@@ -0,0 +1,34 @@
+/*
+ * LibXDiff by Davide Libenzi ( File Differential Library )
+ * Copyright (C) 2003 Davide Libenzi
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Davide Libenzi <davidel@xmailserver.org>
+ *
+ */
+
+#if !defined(XPREPARE_H)
+#define XPREPARE_H
+
+
+
+int xdl_prepare_env(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,
+ xdfenv_t *xe);
+void xdl_free_env(xdfenv_t *xe);
+
+
+
+#endif /* #if !defined(XPREPARE_H) */
diff --git a/src/xdiff/xtypes.h b/src/xdiff/xtypes.h
new file mode 100644
index 0000000..8442bd4
--- /dev/null
+++ b/src/xdiff/xtypes.h
@@ -0,0 +1,67 @@
+/*
+ * LibXDiff by Davide Libenzi ( File Differential Library )
+ * Copyright (C) 2003 Davide Libenzi
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Davide Libenzi <davidel@xmailserver.org>
+ *
+ */
+
+#if !defined(XTYPES_H)
+#define XTYPES_H
+
+
+
+typedef struct s_chanode {
+ struct s_chanode *next;
+ long icurr;
+} chanode_t;
+
+typedef struct s_chastore {
+ chanode_t *head, *tail;
+ long isize, nsize;
+ chanode_t *ancur;
+ chanode_t *sncur;
+ long scurr;
+} chastore_t;
+
+typedef struct s_xrecord {
+ struct s_xrecord *next;
+ char const *ptr;
+ long size;
+ unsigned long ha;
+} xrecord_t;
+
+typedef struct s_xdfile {
+ chastore_t rcha;
+ long nrec;
+ unsigned int hbits;
+ xrecord_t **rhash;
+ long dstart, dend;
+ xrecord_t **recs;
+ char *rchg;
+ long *rindex;
+ long nreff;
+ unsigned long *ha;
+} xdfile_t;
+
+typedef struct s_xdfenv {
+ xdfile_t xdf1, xdf2;
+} xdfenv_t;
+
+
+
+#endif /* #if !defined(XTYPES_H) */
diff --git a/src/xdiff/xutils.c b/src/xdiff/xutils.c
new file mode 100644
index 0000000..25a090f
--- /dev/null
+++ b/src/xdiff/xutils.c
@@ -0,0 +1,425 @@
+/*
+ * LibXDiff by Davide Libenzi ( File Differential Library )
+ * Copyright (C) 2003 Davide Libenzi
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Davide Libenzi <davidel@xmailserver.org>
+ *
+ */
+
+#include <limits.h>
+#include <assert.h>
+#include "xinclude.h"
+
+
+
+
+long xdl_bogosqrt(long n) {
+ long i;
+
+ /*
+ * Classical integer square root approximation using shifts.
+ */
+ for (i = 1; n > 0; n >>= 2)
+ i <<= 1;
+
+ return i;
+}
+
+
+int xdl_emit_diffrec(char const *rec, long size, char const *pre, long psize,
+ xdemitcb_t *ecb) {
+ int i = 2;
+ mmbuffer_t mb[3];
+
+ mb[0].ptr = (char *) pre;
+ mb[0].size = psize;
+ mb[1].ptr = (char *) rec;
+ mb[1].size = size;
+ if (size > 0 && rec[size - 1] != '\n') {
+ mb[2].ptr = (char *) "\n\\ No newline at end of file\n";
+ mb[2].size = (long)strlen(mb[2].ptr);
+ i++;
+ }
+ if (ecb->outf(ecb->priv, mb, i) < 0) {
+
+ return -1;
+ }
+
+ return 0;
+}
+
+void *xdl_mmfile_first(mmfile_t *mmf, long *size)
+{
+ *size = mmf->size;
+ return mmf->ptr;
+}
+
+
+long xdl_mmfile_size(mmfile_t *mmf)
+{
+ return mmf->size;
+}
+
+
+int xdl_cha_init(chastore_t *cha, long isize, long icount) {
+
+ cha->head = cha->tail = NULL;
+ cha->isize = isize;
+ cha->nsize = icount * isize;
+ cha->ancur = cha->sncur = NULL;
+ cha->scurr = 0;
+
+ return 0;
+}
+
+
+void xdl_cha_free(chastore_t *cha) {
+ chanode_t *cur, *tmp;
+
+ for (cur = cha->head; (tmp = cur) != NULL;) {
+ cur = cur->next;
+ xdl_free(tmp);
+ }
+}
+
+
+void *xdl_cha_alloc(chastore_t *cha) {
+ chanode_t *ancur;
+ void *data;
+
+ if (!(ancur = cha->ancur) || ancur->icurr == cha->nsize) {
+ if (!(ancur = (chanode_t *) xdl_malloc(sizeof(chanode_t) + cha->nsize))) {
+
+ return NULL;
+ }
+ ancur->icurr = 0;
+ ancur->next = NULL;
+ if (cha->tail)
+ cha->tail->next = ancur;
+ if (!cha->head)
+ cha->head = ancur;
+ cha->tail = ancur;
+ cha->ancur = ancur;
+ }
+
+ data = (char *) ancur + sizeof(chanode_t) + ancur->icurr;
+ ancur->icurr += cha->isize;
+
+ return data;
+}
+
+long xdl_guess_lines(mmfile_t *mf, long sample) {
+ long nl = 0, size, tsize = 0;
+ char const *data, *cur, *top;
+
+ if ((cur = data = xdl_mmfile_first(mf, &size)) != NULL) {
+ for (top = data + size; nl < sample && cur < top; ) {
+ nl++;
+ if (!(cur = memchr(cur, '\n', top - cur)))
+ cur = top;
+ else
+ cur++;
+ }
+ tsize += (long) (cur - data);
+ }
+
+ if (nl && tsize)
+ nl = xdl_mmfile_size(mf) / (tsize / nl);
+
+ return nl + 1;
+}
+
+int xdl_blankline(const char *line, long size, long flags)
+{
+ long i;
+
+ if (!(flags & XDF_WHITESPACE_FLAGS))
+ return (size <= 1);
+
+ for (i = 0; i < size && XDL_ISSPACE(line[i]); i++)
+ ;
+
+ return (i == size);
+}
+
+/*
+ * Have we eaten everything on the line, except for an optional
+ * CR at the very end?
+ */
+static int ends_with_optional_cr(const char *l, long s, long i)
+{
+ int complete = s && l[s-1] == '\n';
+
+ if (complete)
+ s--;
+ if (s == i)
+ return 1;
+ /* do not ignore CR at the end of an incomplete line */
+ if (complete && s == i + 1 && l[i] == '\r')
+ return 1;
+ return 0;
+}
+
+int xdl_recmatch(const char *l1, long s1, const char *l2, long s2, long flags)
+{
+ int i1, i2;
+
+ if (s1 == s2 && !memcmp(l1, l2, s1))
+ return 1;
+ if (!(flags & XDF_WHITESPACE_FLAGS))
+ return 0;
+
+ i1 = 0;
+ i2 = 0;
+
+ /*
+ * -w matches everything that matches with -b, and -b in turn
+ * matches everything that matches with --ignore-space-at-eol,
+ * which in turn matches everything that matches with --ignore-cr-at-eol.
+ *
+ * Each flavor of ignoring needs different logic to skip whitespaces
+ * while we have both sides to compare.
+ */
+ if (flags & XDF_IGNORE_WHITESPACE) {
+ goto skip_ws;
+ while (i1 < s1 && i2 < s2) {
+ if (l1[i1++] != l2[i2++])
+ return 0;
+ skip_ws:
+ while (i1 < s1 && XDL_ISSPACE(l1[i1]))
+ i1++;
+ while (i2 < s2 && XDL_ISSPACE(l2[i2]))
+ i2++;
+ }
+ } else if (flags & XDF_IGNORE_WHITESPACE_CHANGE) {
+ while (i1 < s1 && i2 < s2) {
+ if (XDL_ISSPACE(l1[i1]) && XDL_ISSPACE(l2[i2])) {
+ /* Skip matching spaces and try again */
+ while (i1 < s1 && XDL_ISSPACE(l1[i1]))
+ i1++;
+ while (i2 < s2 && XDL_ISSPACE(l2[i2]))
+ i2++;
+ continue;
+ }
+ if (l1[i1++] != l2[i2++])
+ return 0;
+ }
+ } else if (flags & XDF_IGNORE_WHITESPACE_AT_EOL) {
+ while (i1 < s1 && i2 < s2 && l1[i1] == l2[i2]) {
+ i1++;
+ i2++;
+ }
+ } else if (flags & XDF_IGNORE_CR_AT_EOL) {
+ /* Find the first difference and see how the line ends */
+ while (i1 < s1 && i2 < s2 && l1[i1] == l2[i2]) {
+ i1++;
+ i2++;
+ }
+ return (ends_with_optional_cr(l1, s1, i1) &&
+ ends_with_optional_cr(l2, s2, i2));
+ }
+
+ /*
+ * After running out of one side, the remaining side must have
+ * nothing but whitespace for the lines to match. Note that
+ * ignore-whitespace-at-eol case may break out of the loop
+ * while there still are characters remaining on both lines.
+ */
+ if (i1 < s1) {
+ while (i1 < s1 && XDL_ISSPACE(l1[i1]))
+ i1++;
+ if (s1 != i1)
+ return 0;
+ }
+ if (i2 < s2) {
+ while (i2 < s2 && XDL_ISSPACE(l2[i2]))
+ i2++;
+ return (s2 == i2);
+ }
+ return 1;
+}
+
+static unsigned long xdl_hash_record_with_whitespace(char const **data,
+ char const *top, long flags) {
+ unsigned long ha = 5381;
+ char const *ptr = *data;
+ int cr_at_eol_only = (flags & XDF_WHITESPACE_FLAGS) == XDF_IGNORE_CR_AT_EOL;
+
+ for (; ptr < top && *ptr != '\n'; ptr++) {
+ if (cr_at_eol_only) {
+ /* do not ignore CR at the end of an incomplete line */
+ if (*ptr == '\r' &&
+ (ptr + 1 < top && ptr[1] == '\n'))
+ continue;
+ }
+ else if (XDL_ISSPACE(*ptr)) {
+ const char *ptr2 = ptr;
+ int at_eol;
+ while (ptr + 1 < top && XDL_ISSPACE(ptr[1])
+ && ptr[1] != '\n')
+ ptr++;
+ at_eol = (top <= ptr + 1 || ptr[1] == '\n');
+ if (flags & XDF_IGNORE_WHITESPACE)
+ ; /* already handled */
+ else if (flags & XDF_IGNORE_WHITESPACE_CHANGE
+ && !at_eol) {
+ ha += (ha << 5);
+ ha ^= (unsigned long) ' ';
+ }
+ else if (flags & XDF_IGNORE_WHITESPACE_AT_EOL
+ && !at_eol) {
+ while (ptr2 != ptr + 1) {
+ ha += (ha << 5);
+ ha ^= (unsigned long) *ptr2;
+ ptr2++;
+ }
+ }
+ continue;
+ }
+ ha += (ha << 5);
+ ha ^= (unsigned long) *ptr;
+ }
+ *data = ptr < top ? ptr + 1: ptr;
+
+ return ha;
+}
+
+unsigned long xdl_hash_record(char const **data, char const *top, long flags) {
+ unsigned long ha = 5381;
+ char const *ptr = *data;
+
+ if (flags & XDF_WHITESPACE_FLAGS)
+ return xdl_hash_record_with_whitespace(data, top, flags);
+
+ for (; ptr < top && *ptr != '\n'; ptr++) {
+ ha += (ha << 5);
+ ha ^= (unsigned long) *ptr;
+ }
+ *data = ptr < top ? ptr + 1: ptr;
+
+ return ha;
+}
+
+unsigned int xdl_hashbits(unsigned int size) {
+ unsigned int val = 1, bits = 0;
+
+ for (; val < size && bits < CHAR_BIT * sizeof(unsigned int); val <<= 1, bits++);
+ return bits ? bits: 1;
+}
+
+
+int xdl_num_out(char *out, long val) {
+ char *ptr, *str = out;
+ char buf[32];
+
+ ptr = buf + sizeof(buf) - 1;
+ *ptr = '\0';
+ if (val < 0) {
+ *--ptr = '-';
+ val = -val;
+ }
+ for (; val && ptr > buf; val /= 10)
+ *--ptr = "0123456789"[val % 10];
+ if (*ptr)
+ for (; *ptr; ptr++, str++)
+ *str = *ptr;
+ else
+ *str++ = '0';
+ *str = '\0';
+
+ return str - out;
+}
+
+int xdl_emit_hunk_hdr(long s1, long c1, long s2, long c2,
+ const char *func, long funclen, xdemitcb_t *ecb) {
+ int nb = 0;
+ mmbuffer_t mb;
+ char buf[128];
+
+ memcpy(buf, "@@ -", 4);
+ nb += 4;
+
+ nb += xdl_num_out(buf + nb, c1 ? s1: s1 - 1);
+
+ if (c1 != 1) {
+ memcpy(buf + nb, ",", 1);
+ nb += 1;
+
+ nb += xdl_num_out(buf + nb, c1);
+ }
+
+ memcpy(buf + nb, " +", 2);
+ nb += 2;
+
+ nb += xdl_num_out(buf + nb, c2 ? s2: s2 - 1);
+
+ if (c2 != 1) {
+ memcpy(buf + nb, ",", 1);
+ nb += 1;
+
+ nb += xdl_num_out(buf + nb, c2);
+ }
+
+ memcpy(buf + nb, " @@", 3);
+ nb += 3;
+ if (func && funclen) {
+ buf[nb++] = ' ';
+ if (funclen > (long)sizeof(buf) - nb - 1)
+ funclen = sizeof(buf) - nb - 1;
+ memcpy(buf + nb, func, funclen);
+ nb += funclen;
+ }
+ buf[nb++] = '\n';
+
+ mb.ptr = buf;
+ mb.size = nb;
+ if (ecb->outf(ecb->priv, &mb, 1) < 0)
+ return -1;
+
+ return 0;
+}
+
+int xdl_fall_back_diff(xdfenv_t *diff_env, xpparam_t const *xpp,
+ int line1, int count1, int line2, int count2)
+{
+ /*
+ * This probably does not work outside Git, since
+ * we have a very simple mmfile structure.
+ *
+ * Note: ideally, we would reuse the prepared environment, but
+ * the libxdiff interface does not (yet) allow for diffing only
+ * ranges of lines instead of the whole files.
+ */
+ mmfile_t subfile1, subfile2;
+ xdfenv_t env;
+
+ subfile1.ptr = (char *)diff_env->xdf1.recs[line1 - 1]->ptr;
+ subfile1.size = diff_env->xdf1.recs[line1 + count1 - 2]->ptr +
+ diff_env->xdf1.recs[line1 + count1 - 2]->size - subfile1.ptr;
+ subfile2.ptr = (char *)diff_env->xdf2.recs[line2 - 1]->ptr;
+ subfile2.size = diff_env->xdf2.recs[line2 + count2 - 2]->ptr +
+ diff_env->xdf2.recs[line2 + count2 - 2]->size - subfile2.ptr;
+ if (xdl_do_diff(&subfile1, &subfile2, xpp, &env) < 0)
+ return -1;
+
+ memcpy(diff_env->xdf1.rchg + line1 - 1, env.xdf1.rchg, count1);
+ memcpy(diff_env->xdf2.rchg + line2 - 1, env.xdf2.rchg, count2);
+
+ xdl_free_env(&env);
+
+ return 0;
+}
diff --git a/src/xdiff/xutils.h b/src/xdiff/xutils.h
new file mode 100644
index 0000000..fba7bae
--- /dev/null
+++ b/src/xdiff/xutils.h
@@ -0,0 +1,47 @@
+/*
+ * LibXDiff by Davide Libenzi ( File Differential Library )
+ * Copyright (C) 2003 Davide Libenzi
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Davide Libenzi <davidel@xmailserver.org>
+ *
+ */
+
+#if !defined(XUTILS_H)
+#define XUTILS_H
+
+
+
+long xdl_bogosqrt(long n);
+int xdl_emit_diffrec(char const *rec, long size, char const *pre, long psize,
+ xdemitcb_t *ecb);
+int xdl_cha_init(chastore_t *cha, long isize, long icount);
+void xdl_cha_free(chastore_t *cha);
+void *xdl_cha_alloc(chastore_t *cha);
+long xdl_guess_lines(mmfile_t *mf, long sample);
+int xdl_blankline(const char *line, long size, long flags);
+int xdl_recmatch(const char *l1, long s1, const char *l2, long s2, long flags);
+unsigned long xdl_hash_record(char const **data, char const *top, long flags);
+unsigned int xdl_hashbits(unsigned int size);
+int xdl_num_out(char *out, long val);
+int xdl_emit_hunk_hdr(long s1, long c1, long s2, long c2,
+ const char *func, long funclen, xdemitcb_t *ecb);
+int xdl_fall_back_diff(xdfenv_t *diff_env, xpparam_t const *xpp,
+ int line1, int count1, int line2, int count2);
+
+
+
+#endif /* #if !defined(XUTILS_H) */
diff --git a/src/xpm/COPYRIGHT b/src/xpm/COPYRIGHT
new file mode 100644
index 0000000..446fa4c
--- /dev/null
+++ b/src/xpm/COPYRIGHT
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 1989-95 GROUPE BULL
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * GROUPE BULL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the name of GROUPE BULL shall not be
+ * used in advertising or otherwise to promote the sale, use or other dealings
+ * in this Software without prior written authorization from GROUPE BULL.
+ */
+
+Arnaud LE HORS BULL Research FRANCE -- Koala Project
+ (XPM - X PixMap format version 2 & 3)
+ Internet: lehors@sophia.inria.fr
+Surface Mail: Arnaud LE HORS, INRIA - Sophia Antipolis,
+ 2004, route des Lucioles, 06565 Valbonne Cedex -- FRANCE
+ Voice phone: (33) 93.65.77.71, Fax: (33) 93 65 77 66, Telex: 97 00 50 F
diff --git a/src/xpm/README.txt b/src/xpm/README.txt
new file mode 100644
index 0000000..25f3831
--- /dev/null
+++ b/src/xpm/README.txt
@@ -0,0 +1,30 @@
+This is XPM library compiled for Windows which is intended for use with Vim
+'signs' feature.
+
+Libraries in x86 directory were compiled with MSVC6 and MinGW. Proposed
+commands to compile Vim are:
+
+If you want to build XPM library by yourself, you may want to use the
+following Win32 port:
+https://github.com/koron/libXpm-win32
+
+Any version of MSVC starting from version 6.0:
+nmake -f Make_mvc.mak GUI=yes CSCOPE=yes NETBEANS=yes XPM=e:\hg\xpm\x86
+
+MinGW:
+mingw32-make -f Make_ming.mak GUI=yes CSCOPE=yes XPM=e:/hg/xpm/x86
+
+MinGW 64 for x64:
+mingw32-make -f Make_ming.mak GUI=yes ARCH=x86-64 XPM=E:\HG\xpm\x64
+
+Microsoft Visual C++ on x64 (tested with versions 2008 and 2010):
+nmake -f Make_mvc.mak GUI=yes CSCOPE=yes XPM=E:\HG\xpm\x64
+
+To test, open some file in Vim and execute commands below:
+:exe 'sign define vimxpm icon='.$VIMRUNTIME.'\\vim32x32.xpm'
+:exe 'sign place 1 line=1 name=vimxpm file='.expand('%:p')
+
+
+See COPYRIGHT for XPM licence.
+
+If you have questions please email sergey.khorev@gmail.com.
diff --git a/src/xpm/include/simx.h b/src/xpm/include/simx.h
new file mode 100644
index 0000000..001cfdb
--- /dev/null
+++ b/src/xpm/include/simx.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 1989-95 GROUPE BULL
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * GROUPE BULL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the name of GROUPE BULL shall not be
+ * used in advertising or otherwise to promote the sale, use or other dealings
+ * in this Software without prior written authorization from GROUPE BULL.
+ */
+
+/*****************************************************************************\
+* simx.h: 0.1a *
+* *
+* This emulates some Xlib functionality for MSW. It's not a general solution, *
+* it is close related to XPM-lib. It is only intended to satisfy what is need *
+* there. Thus allowing to read XPM files under MS windows. *
+* *
+* Developed by HeDu 3/94 (hedu@cul-ipn.uni-kiel.de) *
+\*****************************************************************************/
+
+
+#ifndef _SIMX_H
+#define _SIMX_H
+
+#ifdef FOR_MSW
+
+#include "windows.h" /* MS windows GDI types */
+
+/*
+ * minimal portability layer between ansi and KR C
+ */
+/* this comes from xpm.h, and is here again, to avoid complicated
+ includes, since this is included from xpm.h */
+/* these defines get undefed at the end of this file */
+#if __STDC__ || defined(__cplusplus) || defined(c_plusplus)
+ /* ANSI || C++ */
+#define FUNC(f, t, p) extern t f p
+#define LFUNC(f, t, p) static t f p
+#else /* k&R */
+#define FUNC(f, t, p) extern t f()
+#define LFUNC(f, t, p) static t f()
+#endif
+
+
+FUNC(boundCheckingMalloc, void *, (long s));
+FUNC(boundCheckingCalloc, void *, (long num, long s));
+FUNC(boundCheckingRealloc, void *, (void *p, long s));
+
+/* define MSW types for X window types,
+ I don't know much about MSW, but the following defines do the job */
+
+typedef HDC Display; /* this should be similar */
+typedef void *Screen; /* not used */
+typedef void *Visual; /* not used yet, is for GRAY, COLOR,
+ * MONO */
+
+typedef void *Colormap; /* should be COLORPALETTE, not done
+ * yet */
+
+typedef COLORREF Pixel;
+
+#define PIXEL_ALREADY_TYPEDEFED /* to let xpm.h know about it */
+
+typedef struct {
+ Pixel pixel;
+ BYTE red, green, blue;
+} XColor;
+
+typedef struct {
+ HBITMAP bitmap;
+ unsigned int width;
+ unsigned int height;
+ unsigned int depth;
+} XImage;
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+/* some replacements for X... functions */
+
+/* XDefaultXXX */
+ FUNC(XDefaultVisual, Visual *, (Display *display, Screen *screen));
+ FUNC(XDefaultScreen, Screen *, (Display *d));
+ FUNC(XDefaultColormap, Colormap *, (Display *display, Screen *screen));
+ FUNC(XDefaultDepth, int, (Display *d, Screen *s));
+
+/* color related */
+ FUNC(XParseColor, int, (Display *, Colormap *, char *, XColor *));
+ FUNC(XAllocColor, int, (Display *, Colormap *, XColor *));
+ FUNC(XQueryColors, void, (Display *display, Colormap *colormap,
+ XColor *xcolors, int ncolors));
+ FUNC(XFreeColors, int, (Display *d, Colormap cmap,
+ unsigned long pixels[],
+ int npixels, unsigned long planes));
+/* XImage */
+ FUNC(XCreateImage, XImage *, (Display *, Visual *, int depth, int format,
+ int x, int y, int width, int height,
+ int pad, int foo));
+
+/* free and destroy bitmap */
+ FUNC(XDestroyImage, void /* ? */ , (XImage *));
+/* free only, bitmap remains */
+ FUNC(XImageFree, void, (XImage *));
+#if defined(__cplusplus) || defined(c_plusplus)
+} /* end of extern "C" */
+#endif /* cplusplus */
+
+#define ZPixmap 1 /* not really used */
+#define XYBitmap 1 /* not really used */
+
+#ifndef True
+#define True 1
+#define False 0
+#endif
+#ifndef Bool
+typedef BOOL Bool; /* take MSW bool */
+#endif
+/* make these local here, simx.c gets the same from xpm.h */
+#undef LFUNC
+#undef FUNC
+
+#endif /* def FOR_MSW */
+
+#endif /* _SIMX_H */
diff --git a/src/xpm/include/xpm.h b/src/xpm/include/xpm.h
new file mode 100644
index 0000000..0e9969b
--- /dev/null
+++ b/src/xpm/include/xpm.h
@@ -0,0 +1,501 @@
+/*
+ * Copyright (C) 1989-95 GROUPE BULL
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * GROUPE BULL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the name of GROUPE BULL shall not be
+ * used in advertising or otherwise to promote the sale, use or other dealings
+ * in this Software without prior written authorization from GROUPE BULL.
+ */
+
+/*****************************************************************************\
+* xpm.h: *
+* *
+* XPM library *
+* Include file *
+* *
+* Developed by Arnaud Le Hors *
+\*****************************************************************************/
+
+/*
+ * The code related to FOR_MSW has been added by
+ * HeDu (hedu@cul-ipn.uni-kiel.de) 4/94
+ */
+
+/*
+ * The code related to AMIGA has been added by
+ * Lorens Younes (d93-hyo@nada.kth.se) 4/96
+ */
+
+#ifndef XPM_h
+#define XPM_h
+
+/*
+ * first some identification numbers:
+ * the version and revision numbers are determined with the following rule:
+ * SO Major number = LIB minor version number.
+ * SO Minor number = LIB sub-minor version number.
+ * e.g: Xpm version 3.2f
+ * we forget the 3 which is the format number, 2 gives 2, and f gives 6.
+ * thus we have XpmVersion = 2 and XpmRevision = 6
+ * which gives SOXPMLIBREV = 2.6
+ *
+ * Then the XpmIncludeVersion number is built from these numbers.
+ */
+#define XpmFormat 3
+#define XpmVersion 4
+#define XpmRevision 11
+#define XpmIncludeVersion ((XpmFormat * 100 + XpmVersion) * 100 + XpmRevision)
+
+#ifndef XPM_NUMBERS
+
+#ifdef FOR_MSW
+# define SYSV /* uses memcpy string.h etc. */
+# include <malloc.h>
+# include "simx.h" /* defines some X stuff using MSW types */
+#define NEED_STRCASECMP /* at least for MSVC++ */
+#else /* FOR_MSW */
+# ifdef AMIGA
+# include "amigax.h"
+# else /* not AMIGA */
+# include <X11/Xlib.h>
+# include <X11/Xutil.h>
+# endif /* not AMIGA */
+#endif /* FOR_MSW */
+
+/* let's define Pixel if it is not done yet */
+#if ! defined(_XtIntrinsic_h) && ! defined(PIXEL_ALREADY_TYPEDEFED)
+typedef unsigned long Pixel; /* Index into colormap */
+# define PIXEL_ALREADY_TYPEDEFED
+#endif
+
+/* make sure we know whether function prototypes are needed or not */
+#ifndef NeedFunctionPrototypes
+# if defined(__STDC__) || defined(__cplusplus) || defined(c_plusplus)
+# define NeedFunctionPrototypes 1
+# else
+# define NeedFunctionPrototypes 0
+# endif
+#endif
+
+
+/* Return ErrorStatus codes:
+ * null if full success
+ * positive if partial success
+ * negative if failure
+ */
+
+#define XpmColorError 1
+#define XpmSuccess 0
+#define XpmOpenFailed -1
+#define XpmFileInvalid -2
+#define XpmNoMemory -3
+#define XpmColorFailed -4
+
+typedef struct {
+ char *name; /* Symbolic color name */
+ char *value; /* Color value */
+ Pixel pixel; /* Color pixel */
+} XpmColorSymbol;
+
+typedef struct {
+ char *name; /* name of the extension */
+ unsigned int nlines; /* number of lines in this extension */
+ char **lines; /* pointer to the extension array of strings */
+} XpmExtension;
+
+typedef struct {
+ char *string; /* characters string */
+ char *symbolic; /* symbolic name */
+ char *m_color; /* monochrom default */
+ char *g4_color; /* 4 level grayscale default */
+ char *g_color; /* other level grayscale default */
+ char *c_color; /* color default */
+} XpmColor;
+
+typedef struct {
+ unsigned int width; /* image width */
+ unsigned int height; /* image height */
+ unsigned int cpp; /* number of characters per pixel */
+ unsigned int ncolors; /* number of colors */
+ XpmColor *colorTable; /* list of related colors */
+ unsigned int *data; /* image data */
+} XpmImage;
+
+typedef struct {
+ unsigned long valuemask; /* Specifies which attributes are defined */
+ char *hints_cmt; /* Comment of the hints section */
+ char *colors_cmt; /* Comment of the colors section */
+ char *pixels_cmt; /* Comment of the pixels section */
+ unsigned int x_hotspot; /* Returns the x hotspot's coordinate */
+ unsigned int y_hotspot; /* Returns the y hotspot's coordinate */
+ unsigned int nextensions; /* number of extensions */
+ XpmExtension *extensions; /* pointer to array of extensions */
+} XpmInfo;
+
+typedef int (*XpmAllocColorFunc)(
+#if NeedFunctionPrototypes
+ Display* /* display */,
+ Colormap /* colormap */,
+ char* /* colorname */,
+ XColor* /* xcolor */,
+ void* /* closure */
+#endif
+);
+
+typedef int (*XpmFreeColorsFunc)(
+#if NeedFunctionPrototypes
+ Display* /* display */,
+ Colormap /* colormap */,
+ Pixel* /* pixels */,
+ int /* npixels */,
+ void* /* closure */
+#endif
+);
+
+typedef struct {
+ unsigned long valuemask; /* Specifies which attributes are
+ defined */
+
+ Visual *visual; /* Specifies the visual to use */
+ Colormap colormap; /* Specifies the colormap to use */
+ unsigned int depth; /* Specifies the depth */
+ unsigned int width; /* Returns the width of the created
+ pixmap */
+ unsigned int height; /* Returns the height of the created
+ pixmap */
+ unsigned int x_hotspot; /* Returns the x hotspot's
+ coordinate */
+ unsigned int y_hotspot; /* Returns the y hotspot's
+ coordinate */
+ unsigned int cpp; /* Specifies the number of char per
+ pixel */
+ Pixel *pixels; /* List of used color pixels */
+ unsigned int npixels; /* Number of used pixels */
+ XpmColorSymbol *colorsymbols; /* List of color symbols to override */
+ unsigned int numsymbols; /* Number of symbols */
+ char *rgb_fname; /* RGB text file name */
+ unsigned int nextensions; /* Number of extensions */
+ XpmExtension *extensions; /* List of extensions */
+
+ unsigned int ncolors; /* Number of colors */
+ XpmColor *colorTable; /* List of colors */
+/* 3.2 backward compatibility code */
+ char *hints_cmt; /* Comment of the hints section */
+ char *colors_cmt; /* Comment of the colors section */
+ char *pixels_cmt; /* Comment of the pixels section */
+/* end 3.2 bc */
+ unsigned int mask_pixel; /* Color table index of transparent
+ color */
+
+ /* Color Allocation Directives */
+ Bool exactColors; /* Only use exact colors for visual */
+ unsigned int closeness; /* Allowable RGB deviation */
+ unsigned int red_closeness; /* Allowable red deviation */
+ unsigned int green_closeness; /* Allowable green deviation */
+ unsigned int blue_closeness; /* Allowable blue deviation */
+ int color_key; /* Use colors from this color set */
+
+ Pixel *alloc_pixels; /* Returns the list of alloc'ed color
+ pixels */
+ int nalloc_pixels; /* Returns the number of alloc'ed
+ color pixels */
+
+ Bool alloc_close_colors; /* Specify whether close colors should
+ be allocated using XAllocColor
+ or not */
+ int bitmap_format; /* Specify the format of 1bit depth
+ images: ZPixmap or XYBitmap */
+
+ /* Color functions */
+ XpmAllocColorFunc alloc_color; /* Application color allocator */
+ XpmFreeColorsFunc free_colors; /* Application color de-allocator */
+ void *color_closure; /* Application private data to pass to
+ alloc_color and free_colors */
+
+} XpmAttributes;
+
+/* XpmAttributes value masks bits */
+#define XpmVisual (1L<<0)
+#define XpmColormap (1L<<1)
+#define XpmDepth (1L<<2)
+#define XpmSize (1L<<3) /* width & height */
+#define XpmHotspot (1L<<4) /* x_hotspot & y_hotspot */
+#define XpmCharsPerPixel (1L<<5)
+#define XpmColorSymbols (1L<<6)
+#define XpmRgbFilename (1L<<7)
+/* 3.2 backward compatibility code */
+#define XpmInfos (1L<<8)
+#define XpmReturnInfos XpmInfos
+/* end 3.2 bc */
+#define XpmReturnPixels (1L<<9)
+#define XpmExtensions (1L<<10)
+#define XpmReturnExtensions XpmExtensions
+
+#define XpmExactColors (1L<<11)
+#define XpmCloseness (1L<<12)
+#define XpmRGBCloseness (1L<<13)
+#define XpmColorKey (1L<<14)
+
+#define XpmColorTable (1L<<15)
+#define XpmReturnColorTable XpmColorTable
+
+#define XpmReturnAllocPixels (1L<<16)
+#define XpmAllocCloseColors (1L<<17)
+#define XpmBitmapFormat (1L<<18)
+
+#define XpmAllocColor (1L<<19)
+#define XpmFreeColors (1L<<20)
+#define XpmColorClosure (1L<<21)
+
+
+/* XpmInfo value masks bits */
+#define XpmComments XpmInfos
+#define XpmReturnComments XpmComments
+
+/* XpmAttributes mask_pixel value when there is no mask */
+#ifndef FOR_MSW
+#define XpmUndefPixel 0x80000000
+#else
+/* int is only 16 bit for MSW */
+#define XpmUndefPixel 0x8000
+#endif
+
+/*
+ * color keys for visual type, they must fit along with the number key of
+ * each related element in xpmColorKeys[] defined in XpmI.h
+ */
+#define XPM_MONO 2
+#define XPM_GREY4 3
+#define XPM_GRAY4 3
+#define XPM_GREY 4
+#define XPM_GRAY 4
+#define XPM_COLOR 5
+
+
+/* macros for forward declarations of functions with prototypes */
+#if NeedFunctionPrototypes
+#define FUNC(f, t, p) extern t f p
+#define LFUNC(f, t, p) static t f p
+#else
+#define FUNC(f, t, p) extern t f()
+#define LFUNC(f, t, p) static t f()
+#endif
+
+
+/*
+ * functions declarations
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* FOR_MSW, all ..Pixmap.. are excluded, only the ..XImage.. are used */
+/* Same for Amiga! */
+
+#if !defined(FOR_MSW) && !defined(AMIGA)
+ FUNC(XpmCreatePixmapFromData, int, (Display *display,
+ Drawable d,
+ char **data,
+ Pixmap *pixmap_return,
+ Pixmap *shapemask_return,
+ XpmAttributes *attributes));
+
+ FUNC(XpmCreateDataFromPixmap, int, (Display *display,
+ char ***data_return,
+ Pixmap pixmap,
+ Pixmap shapemask,
+ XpmAttributes *attributes));
+
+ FUNC(XpmReadFileToPixmap, int, (Display *display,
+ Drawable d,
+ char *filename,
+ Pixmap *pixmap_return,
+ Pixmap *shapemask_return,
+ XpmAttributes *attributes));
+
+ FUNC(XpmWriteFileFromPixmap, int, (Display *display,
+ char *filename,
+ Pixmap pixmap,
+ Pixmap shapemask,
+ XpmAttributes *attributes));
+#endif
+
+ FUNC(XpmCreateImageFromData, int, (Display *display,
+ char **data,
+ XImage **image_return,
+ XImage **shapemask_return,
+ XpmAttributes *attributes));
+
+ FUNC(XpmCreateDataFromImage, int, (Display *display,
+ char ***data_return,
+ XImage *image,
+ XImage *shapeimage,
+ XpmAttributes *attributes));
+
+ FUNC(XpmReadFileToImage, int, (Display *display,
+ char *filename,
+ XImage **image_return,
+ XImage **shapeimage_return,
+ XpmAttributes *attributes));
+
+ FUNC(XpmWriteFileFromImage, int, (Display *display,
+ char *filename,
+ XImage *image,
+ XImage *shapeimage,
+ XpmAttributes *attributes));
+
+ FUNC(XpmCreateImageFromBuffer, int, (Display *display,
+ char *buffer,
+ XImage **image_return,
+ XImage **shapemask_return,
+ XpmAttributes *attributes));
+#if !defined(FOR_MSW) && !defined(AMIGA)
+ FUNC(XpmCreatePixmapFromBuffer, int, (Display *display,
+ Drawable d,
+ char *buffer,
+ Pixmap *pixmap_return,
+ Pixmap *shapemask_return,
+ XpmAttributes *attributes));
+
+ FUNC(XpmCreateBufferFromImage, int, (Display *display,
+ char **buffer_return,
+ XImage *image,
+ XImage *shapeimage,
+ XpmAttributes *attributes));
+
+ FUNC(XpmCreateBufferFromPixmap, int, (Display *display,
+ char **buffer_return,
+ Pixmap pixmap,
+ Pixmap shapemask,
+ XpmAttributes *attributes));
+#endif
+ FUNC(XpmReadFileToBuffer, int, (char *filename, char **buffer_return));
+ FUNC(XpmWriteFileFromBuffer, int, (char *filename, char *buffer));
+
+ FUNC(XpmReadFileToData, int, (char *filename, char ***data_return));
+ FUNC(XpmWriteFileFromData, int, (char *filename, char **data));
+
+ FUNC(XpmAttributesSize, int, ());
+ FUNC(XpmFreeAttributes, void, (XpmAttributes *attributes));
+ FUNC(XpmFreeExtensions, void, (XpmExtension *extensions,
+ int nextensions));
+
+ FUNC(XpmFreeXpmImage, void, (XpmImage *image));
+ FUNC(XpmFreeXpmInfo, void, (XpmInfo *info));
+ FUNC(XpmGetErrorString, char *, (int errcode));
+ FUNC(XpmLibraryVersion, int, ());
+
+ /* XpmImage functions */
+ FUNC(XpmReadFileToXpmImage, int, (char *filename,
+ XpmImage *image,
+ XpmInfo *info));
+
+ FUNC(XpmWriteFileFromXpmImage, int, (char *filename,
+ XpmImage *image,
+ XpmInfo *info));
+#if !defined(FOR_MSW) && !defined(AMIGA)
+ FUNC(XpmCreatePixmapFromXpmImage, int, (Display *display,
+ Drawable d,
+ XpmImage *image,
+ Pixmap *pixmap_return,
+ Pixmap *shapemask_return,
+ XpmAttributes *attributes));
+#endif
+ FUNC(XpmCreateImageFromXpmImage, int, (Display *display,
+ XpmImage *image,
+ XImage **image_return,
+ XImage **shapeimage_return,
+ XpmAttributes *attributes));
+
+ FUNC(XpmCreateXpmImageFromImage, int, (Display *display,
+ XImage *image,
+ XImage *shapeimage,
+ XpmImage *xpmimage,
+ XpmAttributes *attributes));
+#if !defined(FOR_MSW) && !defined(AMIGA)
+ FUNC(XpmCreateXpmImageFromPixmap, int, (Display *display,
+ Pixmap pixmap,
+ Pixmap shapemask,
+ XpmImage *xpmimage,
+ XpmAttributes *attributes));
+#endif
+ FUNC(XpmCreateDataFromXpmImage, int, (char ***data_return,
+ XpmImage *image,
+ XpmInfo *info));
+
+ FUNC(XpmCreateXpmImageFromData, int, (char **data,
+ XpmImage *image,
+ XpmInfo *info));
+
+ FUNC(XpmCreateXpmImageFromBuffer, int, (char *buffer,
+ XpmImage *image,
+ XpmInfo *info));
+
+ FUNC(XpmCreateBufferFromXpmImage, int, (char **buffer_return,
+ XpmImage *image,
+ XpmInfo *info));
+
+ FUNC(XpmGetParseError, int, (char *filename,
+ int *linenum_return,
+ int *charnum_return));
+
+ FUNC(XpmFree, void, (void *ptr));
+
+#ifdef __cplusplus
+} /* for C++ V2.0 */
+#endif
+
+
+/* backward compatibility */
+
+/* for version 3.0c */
+#define XpmPixmapColorError XpmColorError
+#define XpmPixmapSuccess XpmSuccess
+#define XpmPixmapOpenFailed XpmOpenFailed
+#define XpmPixmapFileInvalid XpmFileInvalid
+#define XpmPixmapNoMemory XpmNoMemory
+#define XpmPixmapColorFailed XpmColorFailed
+
+#define XpmReadPixmapFile(dpy, d, file, pix, mask, att) \
+ XpmReadFileToPixmap(dpy, d, file, pix, mask, att)
+#define XpmWritePixmapFile(dpy, file, pix, mask, att) \
+ XpmWriteFileFromPixmap(dpy, file, pix, mask, att)
+
+/* for version 3.0b */
+#define PixmapColorError XpmColorError
+#define PixmapSuccess XpmSuccess
+#define PixmapOpenFailed XpmOpenFailed
+#define PixmapFileInvalid XpmFileInvalid
+#define PixmapNoMemory XpmNoMemory
+#define PixmapColorFailed XpmColorFailed
+
+#define ColorSymbol XpmColorSymbol
+
+#define XReadPixmapFile(dpy, d, file, pix, mask, att) \
+ XpmReadFileToPixmap(dpy, d, file, pix, mask, att)
+#define XWritePixmapFile(dpy, file, pix, mask, att) \
+ XpmWriteFileFromPixmap(dpy, file, pix, mask, att)
+#define XCreatePixmapFromData(dpy, d, data, pix, mask, att) \
+ XpmCreatePixmapFromData(dpy, d, data, pix, mask, att)
+#define XCreateDataFromPixmap(dpy, data, pix, mask, att) \
+ XpmCreateDataFromPixmap(dpy, data, pix, mask, att)
+
+#endif /* XPM_NUMBERS */
+#endif
diff --git a/src/xpm/x64/lib-vc14/libXpm.lib b/src/xpm/x64/lib-vc14/libXpm.lib
new file mode 100644
index 0000000..db79b4a
--- /dev/null
+++ b/src/xpm/x64/lib-vc14/libXpm.lib
Binary files differ
diff --git a/src/xpm/x64/lib/libXpm.a b/src/xpm/x64/lib/libXpm.a
new file mode 100644
index 0000000..cd8bb7e
--- /dev/null
+++ b/src/xpm/x64/lib/libXpm.a
Binary files differ
diff --git a/src/xpm/x64/lib/libXpm.lib b/src/xpm/x64/lib/libXpm.lib
new file mode 100644
index 0000000..ea25709
--- /dev/null
+++ b/src/xpm/x64/lib/libXpm.lib
Binary files differ
diff --git a/src/xpm/x86/lib-vc14/libXpm.lib b/src/xpm/x86/lib-vc14/libXpm.lib
new file mode 100644
index 0000000..7010d30
--- /dev/null
+++ b/src/xpm/x86/lib-vc14/libXpm.lib
Binary files differ
diff --git a/src/xpm/x86/lib/libXpm.a b/src/xpm/x86/lib/libXpm.a
new file mode 100644
index 0000000..de633b4
--- /dev/null
+++ b/src/xpm/x86/lib/libXpm.a
Binary files differ
diff --git a/src/xpm/x86/lib/libXpm.lib b/src/xpm/x86/lib/libXpm.lib
new file mode 100644
index 0000000..97bd7d3
--- /dev/null
+++ b/src/xpm/x86/lib/libXpm.lib
Binary files differ
diff --git a/src/xpm_w32.c b/src/xpm_w32.c
new file mode 100644
index 0000000..20612c5
--- /dev/null
+++ b/src/xpm_w32.c
@@ -0,0 +1,56 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * Load XPM image.
+ *
+ * This function is placed in separate file because Xpm headers conflict with
+ * Vim ones :(
+ *
+ * Written by Sergey Khorev.
+ * http://iamphet.nm.ru/vim/index.html
+ */
+
+#ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+
+#include "xpm_w32.h"
+
+/* Engage Windows support in libXpm */
+#define FOR_MSW
+
+#include "xpm.h"
+
+/*
+ * Tries to load an Xpm image from the file "filename".
+ * Returns -1 on failure.
+ * Returns 0 on success and stores image and mask BITMAPS in "hImage" and
+ * "hShape".
+ */
+ int
+LoadXpmImage(
+ char *filename,
+ HBITMAP *hImage,
+ HBITMAP *hShape)
+{
+ XImage *img; /* loaded image */
+ XImage *shp; /* shapeimage */
+ XpmAttributes attr;
+ int res;
+ HDC hdc = CreateCompatibleDC(NULL);
+
+ attr.valuemask = 0;
+ res = XpmReadFileToImage(&hdc, filename, &img, &shp, &attr);
+ DeleteDC(hdc);
+ if (res < 0)
+ return -1;
+ if (shp == NULL)
+ {
+ if (img)
+ XDestroyImage(img);
+ return -1;
+ }
+ *hImage = img->bitmap;
+ *hShape = shp->bitmap;
+ return 0;
+}
diff --git a/src/xpm_w32.h b/src/xpm_w32.h
new file mode 100644
index 0000000..914739b
--- /dev/null
+++ b/src/xpm_w32.h
@@ -0,0 +1,7 @@
+/*
+ * Header file for xpm_w32.c
+ */
+
+#ifndef XPM_W32__H
+int LoadXpmImage(char *filename, HBITMAP *hImage, HBITMAP *hShape);
+#endif
diff --git a/src/xxd/Make_amiga.mak b/src/xxd/Make_amiga.mak
new file mode 100644
index 0000000..be38202
--- /dev/null
+++ b/src/xxd/Make_amiga.mak
@@ -0,0 +1,18 @@
+# Makefile for xxd on the Amiga, using Aztec/Manx C 5.0 or later
+#
+
+#>>>>> choose between debugging (-bs) or optimizing (-so)
+OPTIONS = -so
+#OPTIONS = -bs
+
+#>>>>>> choose -g for debugging
+LN_DEBUG =
+#LN_DEBUG = -g
+
+CFLAGS = $(OPTIONS) -wapruq -ps -qf -DAMIGA -Dconst=
+
+Xxd: xxd.o
+ ln +q -m $(LN_DEBUG) -o Xxd xxd.o -lc16
+
+xxd.o: xxd.c
+ cc $(CFLAGS) xxd.c -o xxd.o
diff --git a/src/xxd/Make_bc5.mak b/src/xxd/Make_bc5.mak
new file mode 100644
index 0000000..4f44622
--- /dev/null
+++ b/src/xxd/Make_bc5.mak
@@ -0,0 +1,18 @@
+# The most simplistic Makefile for Win32 (NT and Windows 95).
+# Used for Borland C++.
+
+!if ("$(BOR)"=="")
+BOR = c:\bc5
+!endif
+!if ("$(BCC)"=="")
+BCC = bcc32
+!endif
+
+xxd: xxd.exe
+
+xxd.exe: xxd.c
+ $(BCC) -I$(BOR)\include -L$(BOR)\lib -DWIN32 xxd.c $(BOR)\lib\wildargs.obj
+
+clean:
+ - del xxd.obj
+ - del xxd.exe
diff --git a/src/xxd/Make_ming.mak b/src/xxd/Make_ming.mak
new file mode 100644
index 0000000..2d32261
--- /dev/null
+++ b/src/xxd/Make_ming.mak
@@ -0,0 +1,28 @@
+# The most simplistic Makefile, for MinGW and Cygwin gcc on MS-DOS
+
+ifndef USEDLL
+USEDLL = no
+endif
+
+ifeq (yes, $(USEDLL))
+DEFINES =
+LIBS = -lc
+else
+DEFINES =
+LIBS =
+endif
+
+CC = gcc
+CFLAGS = -O2 -Wall -DWIN32 $(DEFINES)
+
+ifneq (sh.exe, $(SHELL))
+DEL = rm
+else
+DEL = del
+endif
+
+xxd.exe: xxd.c
+ $(CC) $(CFLAGS) -s -o xxd.exe xxd.c $(LIBS)
+
+clean:
+ -$(DEL) xxd.exe
diff --git a/src/xxd/Make_mvc.mak b/src/xxd/Make_mvc.mak
new file mode 100644
index 0000000..0133d73
--- /dev/null
+++ b/src/xxd/Make_mvc.mak
@@ -0,0 +1,19 @@
+# The most simplistic Makefile for Win32 using Microsoft Visual C++
+# (NT and Windows 95)
+
+SUBSYSTEM = console
+!if "$(SUBSYSTEM_VER)" != ""
+SUBSYSTEM = $(SUBSYSTEM),$(SUBSYSTEM_VER)
+!endif
+
+xxd: xxd.exe
+
+xxd.exe: xxd.c
+ cl /nologo -DWIN32 xxd.c -link -subsystem:$(SUBSYSTEM)
+
+# This was for an older compiler
+# cl /nologo -DWIN32 xxd.c /link setargv.obj
+
+clean:
+ - if exist xxd.obj del xxd.obj
+ - if exist xxd.exe del xxd.exe
diff --git a/src/xxd/Make_vms.mms b/src/xxd/Make_vms.mms
new file mode 100644
index 0000000..872cd75
--- /dev/null
+++ b/src/xxd/Make_vms.mms
@@ -0,0 +1,69 @@
+# VMS MM[KS] makefile for XXD
+# tested with MMK and MMS as well.
+#
+# Maintained by Zoltan Arpadffy <arpadffy@polarhome.com>
+#
+# Edit the lines in the Configuration section below to select.
+#
+# To build: use the following command line:
+#
+# mms/descrip=Make_vms.mms
+# or if you use mmk
+# mmk/descrip=Make_vms.mms
+#
+
+######################################################################
+# Configuration section.
+######################################################################
+# Compiler selection.
+# Comment out if you use the VAXC compiler
+######################################################################
+# DECC = YES
+
+#####################################################################
+# Uncomment if want a debug version. Resulting executable is DVIM.EXE
+######################################################################
+# DEBUG = YES
+
+######################################################################
+# End of configuration section.
+#
+# Please, do not change anything below without programming experience.
+######################################################################
+
+CC = cc
+
+.IFDEF DECC
+CC_DEF = $(CC)/decc
+PREFIX = /prefix=all
+.ELSE
+CC_DEF = $(CC)
+PREFIX =
+.ENDIF
+
+LD_DEF = link
+
+.IFDEF DEBUG
+TARGET = dxxd.exe
+CFLAGS = /debug/noopt$(PREFIX)/cross_reference/include=[]
+LDFLAGS = /debug
+.ELSE
+TARGET = xxd.exe
+CFLAGS = /opt$(PREFIX)/include=[]
+LDFLAGS =
+.ENDIF
+
+.SUFFIXES : .obj .c
+
+SOURCES = xxd.c
+OBJ = xxd.obj
+
+.obj.c :
+ $(CC_DEF) $(CFLAGS) $<
+
+$(TARGET) : $(OBJ)
+ $(LD_DEF) $(LDFLAGS) /exe=$(TARGET) $+
+
+clean :
+ -@ if "''F$SEARCH("*.obj")'" .NES. "" then delete/noconfirm/nolog *.obj;*
+ -@ if "''F$SEARCH("*.exe")'" .NES. "" then delete/noconfirm/nolog *.exe;*
diff --git a/src/xxd/Makefile b/src/xxd/Makefile
new file mode 100644
index 0000000..97bbcc7
--- /dev/null
+++ b/src/xxd/Makefile
@@ -0,0 +1,7 @@
+# The most simplistic Makefile
+
+xxd: xxd.c
+ $(CC) $(CFLAGS) $(LDFLAGS) -DUNIX -o xxd xxd.c
+
+clean:
+ rm -f xxd xxd.o
diff --git a/src/xxd/xxd.c b/src/xxd/xxd.c
new file mode 100644
index 0000000..c24089e
--- /dev/null
+++ b/src/xxd/xxd.c
@@ -0,0 +1,890 @@
+/* xxd: my hexdump facility. jw
+ *
+ * 2.10.90 changed to word output
+ * 3.03.93 new indent style, dumb bug inserted and fixed.
+ * -c option, mls
+ * 26.04.94 better option parser, -ps, -l, -s added.
+ * 1.07.94 -r badly needs - as input file. Per default autoskip over
+ * consecutive lines of zeroes, as unix od does.
+ * -a shows them too.
+ * -i dump as c-style #include "file.h"
+ * 1.11.95 if "xxd -i" knows the filename, an 'unsigned char filename_bits[]'
+ * array is written in correct c-syntax.
+ * -s improved, now defaults to absolute seek, relative requires a '+'.
+ * -r improved, now -r -s -0x... is supported.
+ * change/suppress leading '\0' bytes.
+ * -l n improved: stops exactly after n bytes.
+ * -r improved, better handling of partial lines with trailing garbage.
+ * -r improved, now -r -p works again!
+ * -r improved, less flushing, much faster now! (that was silly)
+ * 3.04.96 Per repeated request of a single person: autoskip defaults to off.
+ * 15.05.96 -v added. They want to know the version.
+ * -a fixed, to show last line inf file ends in all zeros.
+ * -u added: Print upper case hex-letters, as preferred by unix bc.
+ * -h added to usage message. Usage message extended.
+ * Now using outfile if specified even in normal mode, aehem.
+ * No longer mixing of ints and longs. May help doze people.
+ * Added binify ioctl for same reason. (Enough Doze stress for 1996!)
+ * 16.05.96 -p improved, removed occasional superfluous linefeed.
+ * 20.05.96 -l 0 fixed. tried to read anyway.
+ * 21.05.96 -i fixed. now honours -u, and prepends __ to numeric filenames.
+ * compile -DWIN32 for NT or W95. George V. Reilly, * -v improved :-)
+ * support --gnuish-longhorn-options
+ * 25.05.96 MAC support added: CodeWarrior already uses ``outline'' in Types.h
+ * which is included by MacHeaders (Axel Kielhorn). Renamed to
+ * xxdline().
+ * 7.06.96 -i printed 'int' instead of 'char'. *blush*
+ * added Bram's OS2 ifdefs...
+ * 18.07.96 gcc -Wall @ SunOS4 is now slient.
+ * Added osver for MSDOS/DJGPP/WIN32.
+ * 29.08.96 Added size_t to strncmp() for Amiga.
+ * 24.03.97 Windows NT support (Phil Hanna). Clean exit for Amiga WB (Bram)
+ * 02.04.97 Added -E option, to have EBCDIC translation instead of ASCII
+ * (azc10@yahoo.com)
+ * 22.05.97 added -g (group octets) option (jcook@namerica.kla.com).
+ * 23.09.98 nasty -p -r misfeature fixed: slightly wrong output, when -c was
+ * missing or wrong.
+ * 26.09.98 Fixed: 'xxd -i infile outfile' did not truncate outfile.
+ * 27.10.98 Fixed: -g option parser required blank.
+ * option -b added: 01000101 binary output in normal format.
+ * 16.05.00 Added VAXC changes by Stephen P. Wall
+ * 16.05.00 Improved MMS file and merge for VMS by Zoltan Arpadffy
+ * 2011 March Better error handling by Florian Zumbiehl.
+ * 2011 April Formatting by Bram Moolenaar
+ * 08.06.2013 Little-endian hexdump (-e) and offset (-o) by Vadim Vygonets.
+ * 11.01.2019 Add full 64/32 bit range to -o and output by Christer Jensen.
+ *
+ * (c) 1990-1998 by Juergen Weigert (jnweiger@informatik.uni-erlangen.de)
+ *
+ * I hereby grant permission to distribute and use xxd
+ * under X11-MIT or GPL-2.0 (at the user's choice).
+ *
+ * Small changes made afterwards by Bram Moolenaar et al.
+ *
+ * Distribute freely and credit me,
+ * make money and share with me,
+ * lose money and don't ask me.
+ */
+
+/* Visual Studio 2005 has 'deprecated' many of the standard CRT functions */
+#if _MSC_VER >= 1400
+# define _CRT_SECURE_NO_DEPRECATE
+# define _CRT_NONSTDC_NO_DEPRECATE
+#endif
+#if !defined(CYGWIN) && (defined(CYGWIN32) || defined(__CYGWIN__) || defined(__CYGWIN32__))
+# define CYGWIN
+#endif
+
+#include <stdio.h>
+#ifdef VAXC
+# include <file.h>
+#else
+# include <fcntl.h>
+#endif
+#if defined(WIN32) || defined(__BORLANDC__) || defined(CYGWIN)
+# include <io.h> /* for setmode() */
+#else
+# ifdef UNIX
+# include <unistd.h>
+# endif
+#endif
+#include <stdlib.h>
+#include <string.h> /* for strncmp() */
+#include <ctype.h> /* for isalnum() */
+#include <limits.h>
+#if __MWERKS__ && !defined(BEBOX)
+# include <unix.h> /* for fdopen() on MAC */
+#endif
+
+#if defined(__BORLANDC__) && __BORLANDC__ <= 0x0410 && !defined(fileno)
+/* Missing define and prototype grabbed from the BC 4.0 <stdio.h> */
+# define fileno(f) ((f)->fd)
+FILE _FAR *_Cdecl _FARFUNC fdopen(int __handle, char _FAR *__type);
+#endif
+
+
+/* This corrects the problem of missing prototypes for certain functions
+ * in some GNU installations (e.g. SunOS 4.1.x).
+ * Darren Hiebert <darren@hmi.com> (sparc-sun-sunos4.1.3_U1/2.7.2.2)
+ */
+#if defined(__GNUC__) && defined(__STDC__)
+# ifndef __USE_FIXED_PROTOTYPES__
+# define __USE_FIXED_PROTOTYPES__
+# endif
+#endif
+
+#ifndef __USE_FIXED_PROTOTYPES__
+/*
+ * This is historic and works only if the compiler really has no prototypes:
+ *
+ * Include prototypes for Sun OS 4.x, when using an ANSI compiler.
+ * FILE is defined on OS 4.x, not on 5.x (Solaris).
+ * if __SVR4 is defined (some Solaris versions), don't include this.
+ */
+#if defined(sun) && defined(FILE) && !defined(__SVR4) && defined(__STDC__)
+# define __P(a) a
+/* excerpt from my sun_stdlib.h */
+extern int fprintf __P((FILE *, char *, ...));
+extern int fputs __P((char *, FILE *));
+extern int _flsbuf __P((unsigned char, FILE *));
+extern int _filbuf __P((FILE *));
+extern int fflush __P((FILE *));
+extern int fclose __P((FILE *));
+extern int fseek __P((FILE *, long, int));
+extern int rewind __P((FILE *));
+
+extern void perror __P((char *));
+# endif
+#endif
+
+extern long int strtol();
+extern long int ftell();
+
+char version[] = "xxd V1.10 27oct98 by Juergen Weigert";
+#ifdef WIN32
+char osver[] = " (Win32)";
+#else
+char osver[] = "";
+#endif
+
+#if defined(WIN32)
+# define BIN_READ(yes) ((yes) ? "rb" : "rt")
+# define BIN_WRITE(yes) ((yes) ? "wb" : "wt")
+# define BIN_CREAT(yes) ((yes) ? (O_CREAT|O_BINARY) : O_CREAT)
+# define BIN_ASSIGN(fp, yes) setmode(fileno(fp), (yes) ? O_BINARY : O_TEXT)
+# define PATH_SEP '\\'
+#elif defined(CYGWIN)
+# define BIN_READ(yes) ((yes) ? "rb" : "rt")
+# define BIN_WRITE(yes) ((yes) ? "wb" : "w")
+# define BIN_CREAT(yes) ((yes) ? (O_CREAT|O_BINARY) : O_CREAT)
+# define BIN_ASSIGN(fp, yes) ((yes) ? (void) setmode(fileno(fp), O_BINARY) : (void) (fp))
+# define PATH_SEP '/'
+#else
+# ifdef VMS
+# define BIN_READ(dummy) "r"
+# define BIN_WRITE(dummy) "w"
+# define BIN_CREAT(dummy) O_CREAT
+# define BIN_ASSIGN(fp, dummy) fp
+# define PATH_SEP ']'
+# define FILE_SEP '.'
+# else
+# define BIN_READ(dummy) "r"
+# define BIN_WRITE(dummy) "w"
+# define BIN_CREAT(dummy) O_CREAT
+# define BIN_ASSIGN(fp, dummy) fp
+# define PATH_SEP '/'
+# endif
+#endif
+
+/* open has only to arguments on the Mac */
+#if __MWERKS__
+# define OPEN(name, mode, umask) open(name, mode)
+#else
+# define OPEN(name, mode, umask) open(name, mode, umask)
+#endif
+
+#ifdef AMIGA
+# define STRNCMP(s1, s2, l) strncmp(s1, s2, (size_t)l)
+#else
+# define STRNCMP(s1, s2, l) strncmp(s1, s2, l)
+#endif
+
+#ifndef __P
+# if defined(__STDC__) || defined(WIN32) || defined(__BORLANDC__)
+# define __P(a) a
+# else
+# define __P(a) ()
+# endif
+#endif
+
+/* Let's collect some prototypes */
+/* CodeWarrior is really picky about missing prototypes */
+static void exit_with_usage __P((void));
+static void die __P((int));
+static int huntype __P((FILE *, FILE *, FILE *, int, int, long));
+static void xxdline __P((FILE *, char *, int));
+
+#define TRY_SEEK /* attempt to use lseek, or skip forward by reading */
+#define COLS 256 /* change here, if you ever need more columns */
+#define LLEN ((2*(int)sizeof(unsigned long)) + 4 + (9*COLS-1) + COLS + 2)
+
+char hexxa[] = "0123456789abcdef0123456789ABCDEF", *hexx = hexxa;
+
+/* the different hextypes known by this program: */
+#define HEX_NORMAL 0
+#define HEX_POSTSCRIPT 1
+#define HEX_CINCLUDE 2
+#define HEX_BITS 3 /* not hex a dump, but bits: 01111001 */
+#define HEX_LITTLEENDIAN 4
+
+#define CONDITIONAL_CAPITALIZE(c) (capitalize ? toupper((int)c) : c)
+
+static char *pname;
+
+ static void
+exit_with_usage(void)
+{
+ fprintf(stderr, "Usage:\n %s [options] [infile [outfile]]\n", pname);
+ fprintf(stderr, " or\n %s -r [-s [-]offset] [-c cols] [-ps] [infile [outfile]]\n", pname);
+ fprintf(stderr, "Options:\n");
+ fprintf(stderr, " -a toggle autoskip: A single '*' replaces nul-lines. Default off.\n");
+ fprintf(stderr, " -b binary digit dump (incompatible with -ps,-i,-r). Default hex.\n");
+ fprintf(stderr, " -C capitalize variable names in C include file style (-i).\n");
+ fprintf(stderr, " -c cols format <cols> octets per line. Default 16 (-i: 12, -ps: 30).\n");
+ fprintf(stderr, " -E show characters in EBCDIC. Default ASCII.\n");
+ fprintf(stderr, " -e little-endian dump (incompatible with -ps,-i,-r).\n");
+ fprintf(stderr, " -g number of octets per group in normal output. Default 2 (-e: 4).\n");
+ fprintf(stderr, " -h print this summary.\n");
+ fprintf(stderr, " -i output in C include file style.\n");
+ fprintf(stderr, " -l len stop after <len> octets.\n");
+ fprintf(stderr, " -o off add <off> to the displayed file position.\n");
+ fprintf(stderr, " -ps output in postscript plain hexdump style.\n");
+ fprintf(stderr, " -r reverse operation: convert (or patch) hexdump into binary.\n");
+ fprintf(stderr, " -r -s off revert with <off> added to file positions found in hexdump.\n");
+ fprintf(stderr, " -s %sseek start at <seek> bytes abs. %sinfile offset.\n",
+#ifdef TRY_SEEK
+ "[+][-]", "(or +: rel.) ");
+#else
+ "", "");
+#endif
+ fprintf(stderr, " -u use upper case hex letters.\n");
+ fprintf(stderr, " -v show version: \"%s%s\".\n", version, osver);
+ exit(1);
+}
+
+ static void
+die(int ret)
+{
+ fprintf(stderr, "%s: ", pname);
+ perror(NULL);
+ exit(ret);
+}
+
+/*
+ * Max. cols binary characters are decoded from the input stream per line.
+ * Two adjacent garbage characters after evaluated data delimit valid data.
+ * Everything up to the next newline is discarded.
+ *
+ * The name is historic and came from 'undo type opt h'.
+ */
+ static int
+huntype(
+ FILE *fpi,
+ FILE *fpo,
+ FILE *fperr,
+ int cols,
+ int hextype,
+ long base_off)
+{
+ int c, ign_garb = 1, n1 = -1, n2 = 0, n3, p = cols;
+ long have_off = 0, want_off = 0;
+
+ rewind(fpi);
+
+ while ((c = getc(fpi)) != EOF)
+ {
+ if (c == '\r') /* Doze style input file? */
+ continue;
+
+ /* Allow multiple spaces. This doesn't work when there is normal text
+ * after the hex codes in the last line that looks like hex, thus only
+ * use it for PostScript format. */
+ if (hextype == HEX_POSTSCRIPT && (c == ' ' || c == '\n' || c == '\t'))
+ continue;
+
+ n3 = n2;
+ n2 = n1;
+
+ if (c >= '0' && c <= '9')
+ n1 = c - '0';
+ else if (c >= 'a' && c <= 'f')
+ n1 = c - 'a' + 10;
+ else if (c >= 'A' && c <= 'F')
+ n1 = c - 'A' + 10;
+ else
+ {
+ n1 = -1;
+ if (ign_garb)
+ continue;
+ }
+
+ ign_garb = 0;
+
+ if (p >= cols)
+ {
+ if (!hextype)
+ {
+ if (n1 < 0)
+ {
+ p = 0;
+ continue;
+ }
+ want_off = (want_off << 4) | n1;
+ continue;
+ }
+ else
+ p = 0;
+ }
+
+ if (base_off + want_off != have_off)
+ {
+ if (fflush(fpo) != 0)
+ die(3);
+#ifdef TRY_SEEK
+ c = fseek(fpo, base_off + want_off - have_off, 1);
+ if (c >= 0)
+ have_off = base_off + want_off;
+#endif
+ if (base_off + want_off < have_off)
+ {
+ fprintf(fperr, "%s: sorry, cannot seek backwards.\n", pname);
+ return 5;
+ }
+ for (; have_off < base_off + want_off; have_off++)
+ if (putc(0, fpo) == EOF)
+ die(3);
+ }
+
+ if (n2 >= 0 && n1 >= 0)
+ {
+ if (putc((n2 << 4) | n1, fpo) == EOF)
+ die(3);
+ have_off++;
+ want_off++;
+ n1 = -1;
+ if ((++p >= cols) && !hextype)
+ {
+ /* skip rest of line as garbage */
+ want_off = 0;
+ while ((c = getc(fpi)) != '\n' && c != EOF)
+ ;
+ if (c == EOF && ferror(fpi))
+ die(2);
+ ign_garb = 1;
+ }
+ }
+ else if (n1 < 0 && n2 < 0 && n3 < 0)
+ {
+ /* already stumbled into garbage, skip line, wait and see */
+ if (!hextype)
+ want_off = 0;
+ while ((c = getc(fpi)) != '\n' && c != EOF)
+ ;
+ if (c == EOF && ferror(fpi))
+ die(2);
+ ign_garb = 1;
+ }
+ }
+ if (fflush(fpo) != 0)
+ die(3);
+#ifdef TRY_SEEK
+ fseek(fpo, 0L, 2);
+#endif
+ if (fclose(fpo) != 0)
+ die(3);
+ if (fclose(fpi) != 0)
+ die(2);
+ return 0;
+}
+
+/*
+ * Print line l. If nz is false, xxdline regards the line a line of
+ * zeroes. If there are three or more consecutive lines of zeroes,
+ * they are replaced by a single '*' character.
+ *
+ * If the output ends with more than two lines of zeroes, you
+ * should call xxdline again with l being the last line and nz
+ * negative. This ensures that the last line is shown even when
+ * it is all zeroes.
+ *
+ * If nz is always positive, lines are never suppressed.
+ */
+ static void
+xxdline(FILE *fp, char *l, int nz)
+{
+ static char z[LLEN+1];
+ static int zero_seen = 0;
+
+ if (!nz && zero_seen == 1)
+ strcpy(z, l);
+
+ if (nz || !zero_seen++)
+ {
+ if (nz)
+ {
+ if (nz < 0)
+ zero_seen--;
+ if (zero_seen == 2)
+ if (fputs(z, fp) == EOF)
+ die(3);
+ if (zero_seen > 2)
+ if (fputs("*\n", fp) == EOF)
+ die(3);
+ }
+ if (nz >= 0 || zero_seen > 0)
+ if (fputs(l, fp) == EOF)
+ die(3);
+ if (nz)
+ zero_seen = 0;
+ }
+}
+
+/* This is an EBCDIC to ASCII conversion table */
+/* from a proposed BTL standard April 16, 1979 */
+static unsigned char etoa64[] =
+{
+ 0040,0240,0241,0242,0243,0244,0245,0246,
+ 0247,0250,0325,0056,0074,0050,0053,0174,
+ 0046,0251,0252,0253,0254,0255,0256,0257,
+ 0260,0261,0041,0044,0052,0051,0073,0176,
+ 0055,0057,0262,0263,0264,0265,0266,0267,
+ 0270,0271,0313,0054,0045,0137,0076,0077,
+ 0272,0273,0274,0275,0276,0277,0300,0301,
+ 0302,0140,0072,0043,0100,0047,0075,0042,
+ 0303,0141,0142,0143,0144,0145,0146,0147,
+ 0150,0151,0304,0305,0306,0307,0310,0311,
+ 0312,0152,0153,0154,0155,0156,0157,0160,
+ 0161,0162,0136,0314,0315,0316,0317,0320,
+ 0321,0345,0163,0164,0165,0166,0167,0170,
+ 0171,0172,0322,0323,0324,0133,0326,0327,
+ 0330,0331,0332,0333,0334,0335,0336,0337,
+ 0340,0341,0342,0343,0344,0135,0346,0347,
+ 0173,0101,0102,0103,0104,0105,0106,0107,
+ 0110,0111,0350,0351,0352,0353,0354,0355,
+ 0175,0112,0113,0114,0115,0116,0117,0120,
+ 0121,0122,0356,0357,0360,0361,0362,0363,
+ 0134,0237,0123,0124,0125,0126,0127,0130,
+ 0131,0132,0364,0365,0366,0367,0370,0371,
+ 0060,0061,0062,0063,0064,0065,0066,0067,
+ 0070,0071,0372,0373,0374,0375,0376,0377
+};
+
+ int
+main(int argc, char *argv[])
+{
+ FILE *fp, *fpo;
+ int c, e, p = 0, relseek = 1, negseek = 0, revert = 0;
+ int cols = 0, nonzero = 0, autoskip = 0, hextype = HEX_NORMAL, capitalize = 0;
+ int ebcdic = 0;
+ int octspergrp = -1; /* number of octets grouped in output */
+ int grplen; /* total chars per octet group */
+ long length = -1, n = 0, seekoff = 0;
+ unsigned long displayoff = 0;
+ static char l[LLEN+1]; /* static because it may be too big for stack */
+ char *pp;
+ int addrlen = 9;
+
+#ifdef AMIGA
+ /* This program doesn't work when started from the Workbench */
+ if (argc == 0)
+ exit(1);
+#endif
+
+ pname = argv[0];
+ for (pp = pname; *pp; )
+ if (*pp++ == PATH_SEP)
+ pname = pp;
+#ifdef FILE_SEP
+ for (pp = pname; *pp; pp++)
+ if (*pp == FILE_SEP)
+ {
+ *pp = '\0';
+ break;
+ }
+#endif
+
+ while (argc >= 2)
+ {
+ pp = argv[1] + (!STRNCMP(argv[1], "--", 2) && argv[1][2]);
+ if (!STRNCMP(pp, "-a", 2)) autoskip = 1 - autoskip;
+ else if (!STRNCMP(pp, "-b", 2)) hextype = HEX_BITS;
+ else if (!STRNCMP(pp, "-e", 2)) hextype = HEX_LITTLEENDIAN;
+ else if (!STRNCMP(pp, "-u", 2)) hexx = hexxa + 16;
+ else if (!STRNCMP(pp, "-p", 2)) hextype = HEX_POSTSCRIPT;
+ else if (!STRNCMP(pp, "-i", 2)) hextype = HEX_CINCLUDE;
+ else if (!STRNCMP(pp, "-C", 2)) capitalize = 1;
+ else if (!STRNCMP(pp, "-r", 2)) revert++;
+ else if (!STRNCMP(pp, "-E", 2)) ebcdic++;
+ else if (!STRNCMP(pp, "-v", 2))
+ {
+ fprintf(stderr, "%s%s\n", version, osver);
+ exit(0);
+ }
+ else if (!STRNCMP(pp, "-c", 2))
+ {
+ if (pp[2] && !STRNCMP("apitalize", pp + 2, 9))
+ capitalize = 1;
+ else if (pp[2] && STRNCMP("ols", pp + 2, 3))
+ cols = (int)strtol(pp + 2, NULL, 0);
+ else
+ {
+ if (!argv[2])
+ exit_with_usage();
+ cols = (int)strtol(argv[2], NULL, 0);
+ argv++;
+ argc--;
+ }
+ }
+ else if (!STRNCMP(pp, "-g", 2))
+ {
+ if (pp[2] && STRNCMP("roup", pp + 2, 4))
+ octspergrp = (int)strtol(pp + 2, NULL, 0);
+ else
+ {
+ if (!argv[2])
+ exit_with_usage();
+ octspergrp = (int)strtol(argv[2], NULL, 0);
+ argv++;
+ argc--;
+ }
+ }
+ else if (!STRNCMP(pp, "-o", 2))
+ {
+ int reloffset = 0;
+ int negoffset = 0;
+ if (pp[2] && STRNCMP("ffset", pp + 2, 5))
+ displayoff = strtoul(pp + 2, NULL, 0);
+ else
+ {
+ if (!argv[2])
+ exit_with_usage();
+
+ if (argv[2][0] == '+')
+ reloffset++;
+ if (argv[2][reloffset] == '-')
+ negoffset++;
+
+ if (negoffset)
+ displayoff = ULONG_MAX - strtoul(argv[2] + reloffset+negoffset, NULL, 0) + 1;
+ else
+ displayoff = strtoul(argv[2] + reloffset+negoffset, NULL, 0);
+
+ argv++;
+ argc--;
+ }
+ }
+ else if (!STRNCMP(pp, "-s", 2))
+ {
+ relseek = 0;
+ negseek = 0;
+ if (pp[2] && STRNCMP("kip", pp+2, 3) && STRNCMP("eek", pp+2, 3))
+ {
+#ifdef TRY_SEEK
+ if (pp[2] == '+')
+ relseek++;
+ if (pp[2+relseek] == '-')
+ negseek++;
+#endif
+ seekoff = strtol(pp + 2+relseek+negseek, (char **)NULL, 0);
+ }
+ else
+ {
+ if (!argv[2])
+ exit_with_usage();
+#ifdef TRY_SEEK
+ if (argv[2][0] == '+')
+ relseek++;
+ if (argv[2][relseek] == '-')
+ negseek++;
+#endif
+ seekoff = strtol(argv[2] + relseek+negseek, (char **)NULL, 0);
+ argv++;
+ argc--;
+ }
+ }
+ else if (!STRNCMP(pp, "-l", 2))
+ {
+ if (pp[2] && STRNCMP("en", pp + 2, 2))
+ length = strtol(pp + 2, (char **)NULL, 0);
+ else
+ {
+ if (!argv[2])
+ exit_with_usage();
+ length = strtol(argv[2], (char **)NULL, 0);
+ argv++;
+ argc--;
+ }
+ }
+ else if (!strcmp(pp, "--")) /* end of options */
+ {
+ argv++;
+ argc--;
+ break;
+ }
+ else if (pp[0] == '-' && pp[1]) /* unknown option */
+ exit_with_usage();
+ else
+ break; /* not an option */
+
+ argv++; /* advance to next argument */
+ argc--;
+ }
+
+ if (!cols)
+ switch (hextype)
+ {
+ case HEX_POSTSCRIPT: cols = 30; break;
+ case HEX_CINCLUDE: cols = 12; break;
+ case HEX_BITS: cols = 6; break;
+ case HEX_NORMAL:
+ case HEX_LITTLEENDIAN:
+ default: cols = 16; break;
+ }
+
+ if (octspergrp < 0)
+ switch (hextype)
+ {
+ case HEX_BITS: octspergrp = 1; break;
+ case HEX_NORMAL: octspergrp = 2; break;
+ case HEX_LITTLEENDIAN: octspergrp = 4; break;
+ case HEX_POSTSCRIPT:
+ case HEX_CINCLUDE:
+ default: octspergrp = 0; break;
+ }
+
+ if (cols < 1 || ((hextype == HEX_NORMAL || hextype == HEX_BITS || hextype == HEX_LITTLEENDIAN)
+ && (cols > COLS)))
+ {
+ fprintf(stderr, "%s: invalid number of columns (max. %d).\n", pname, COLS);
+ exit(1);
+ }
+
+ if (octspergrp < 1 || octspergrp > cols)
+ octspergrp = cols;
+ else if (hextype == HEX_LITTLEENDIAN && (octspergrp & (octspergrp-1)))
+ {
+ fprintf(stderr,
+ "%s: number of octets per group must be a power of 2 with -e.\n",
+ pname);
+ exit(1);
+ }
+
+ if (argc > 3)
+ exit_with_usage();
+
+ if (argc == 1 || (argv[1][0] == '-' && !argv[1][1]))
+ BIN_ASSIGN(fp = stdin, !revert);
+ else
+ {
+ if ((fp = fopen(argv[1], BIN_READ(!revert))) == NULL)
+ {
+ fprintf(stderr,"%s: ", pname);
+ perror(argv[1]);
+ return 2;
+ }
+ }
+
+ if (argc < 3 || (argv[2][0] == '-' && !argv[2][1]))
+ BIN_ASSIGN(fpo = stdout, revert);
+ else
+ {
+ int fd;
+ int mode = revert ? O_WRONLY : (O_TRUNC|O_WRONLY);
+
+ if (((fd = OPEN(argv[2], mode | BIN_CREAT(revert), 0666)) < 0) ||
+ (fpo = fdopen(fd, BIN_WRITE(revert))) == NULL)
+ {
+ fprintf(stderr, "%s: ", pname);
+ perror(argv[2]);
+ return 3;
+ }
+ rewind(fpo);
+ }
+
+ if (revert)
+ {
+ if (hextype && (hextype != HEX_POSTSCRIPT))
+ {
+ fprintf(stderr, "%s: sorry, cannot revert this type of hexdump\n", pname);
+ return -1;
+ }
+ return huntype(fp, fpo, stderr, cols, hextype,
+ negseek ? -seekoff : seekoff);
+ }
+
+ if (seekoff || negseek || !relseek)
+ {
+#ifdef TRY_SEEK
+ if (relseek)
+ e = fseek(fp, negseek ? -seekoff : seekoff, 1);
+ else
+ e = fseek(fp, negseek ? -seekoff : seekoff, negseek ? 2 : 0);
+ if (e < 0 && negseek)
+ {
+ fprintf(stderr, "%s: sorry cannot seek.\n", pname);
+ return 4;
+ }
+ if (e >= 0)
+ seekoff = ftell(fp);
+ else
+#endif
+ {
+ long s = seekoff;
+
+ while (s--)
+ if (getc(fp) == EOF)
+ {
+ if (ferror(fp))
+ {
+ die(2);
+ }
+ else
+ {
+ fprintf(stderr, "%s: sorry cannot seek.\n", pname);
+ return 4;
+ }
+ }
+ }
+ }
+
+ if (hextype == HEX_CINCLUDE)
+ {
+ if (fp != stdin)
+ {
+ if (fprintf(fpo, "unsigned char %s", isdigit((int)argv[1][0]) ? "__" : "") < 0)
+ die(3);
+ for (e = 0; (c = argv[1][e]) != 0; e++)
+ if (putc(isalnum(c) ? CONDITIONAL_CAPITALIZE(c) : '_', fpo) == EOF)
+ die(3);
+ if (fputs("[] = {\n", fpo) == EOF)
+ die(3);
+ }
+
+ p = 0;
+ c = 0;
+ while ((length < 0 || p < length) && (c = getc(fp)) != EOF)
+ {
+ if (fprintf(fpo, (hexx == hexxa) ? "%s0x%02x" : "%s0X%02X",
+ (p % cols) ? ", " : &",\n "[2*!p], c) < 0)
+ die(3);
+ p++;
+ }
+ if (c == EOF && ferror(fp))
+ die(2);
+
+ if (p && fputs("\n", fpo) == EOF)
+ die(3);
+ if (fputs(&"};\n"[3 * (fp == stdin)], fpo) == EOF)
+ die(3);
+
+ if (fp != stdin)
+ {
+ if (fprintf(fpo, "unsigned int %s", isdigit((int)argv[1][0]) ? "__" : "") < 0)
+ die(3);
+ for (e = 0; (c = argv[1][e]) != 0; e++)
+ if (putc(isalnum(c) ? CONDITIONAL_CAPITALIZE(c) : '_', fpo) == EOF)
+ die(3);
+ if (fprintf(fpo, "_%s = %d;\n", capitalize ? "LEN" : "len", p) < 0)
+ die(3);
+ }
+
+ if (fclose(fp))
+ die(2);
+ if (fclose(fpo))
+ die(3);
+ return 0;
+ }
+
+ if (hextype == HEX_POSTSCRIPT)
+ {
+ p = cols;
+ e = 0;
+ while ((length < 0 || n < length) && (e = getc(fp)) != EOF)
+ {
+ if (putc(hexx[(e >> 4) & 0xf], fpo) == EOF
+ || putc(hexx[e & 0xf], fpo) == EOF)
+ die(3);
+ n++;
+ if (!--p)
+ {
+ if (putc('\n', fpo) == EOF)
+ die(3);
+ p = cols;
+ }
+ }
+ if (e == EOF && ferror(fp))
+ die(2);
+ if (p < cols)
+ if (putc('\n', fpo) == EOF)
+ die(3);
+ if (fclose(fp))
+ die(2);
+ if (fclose(fpo))
+ die(3);
+ return 0;
+ }
+
+ /* hextype: HEX_NORMAL or HEX_BITS or HEX_LITTLEENDIAN */
+
+ if (hextype != HEX_BITS)
+ grplen = octspergrp + octspergrp + 1; /* chars per octet group */
+ else /* hextype == HEX_BITS */
+ grplen = 8 * octspergrp + 1;
+
+ e = 0;
+ while ((length < 0 || n < length) && (e = getc(fp)) != EOF)
+ {
+ if (p == 0)
+ {
+ addrlen = sprintf(l, "%08lx:",
+ ((unsigned long)(n + seekoff + displayoff)));
+ for (c = addrlen; c < LLEN; l[c++] = ' ');
+ }
+ if (hextype == HEX_NORMAL)
+ {
+ l[c = (addrlen + 1 + (grplen * p) / octspergrp)] = hexx[(e >> 4) & 0xf];
+ l[++c] = hexx[ e & 0xf];
+ }
+ else if (hextype == HEX_LITTLEENDIAN)
+ {
+ int x = p ^ (octspergrp-1);
+ l[c = (addrlen + 1 + (grplen * x) / octspergrp)] = hexx[(e >> 4) & 0xf];
+ l[++c] = hexx[ e & 0xf];
+ }
+ else /* hextype == HEX_BITS */
+ {
+ int i;
+
+ c = (addrlen + 1 + (grplen * p) / octspergrp) - 1;
+ for (i = 7; i >= 0; i--)
+ l[++c] = (e & (1 << i)) ? '1' : '0';
+ }
+ if (e)
+ nonzero++;
+ if (ebcdic)
+ e = (e < 64) ? '.' : etoa64[e-64];
+ /* When changing this update definition of LLEN above. */
+ l[addrlen + 3 + (grplen * cols - 1)/octspergrp + p] =
+#ifdef __MVS__
+ (e >= 64)
+#else
+ (e > 31 && e < 127)
+#endif
+ ? e : '.';
+ n++;
+ if (++p == cols)
+ {
+ l[c = (addrlen + 3 + (grplen * cols - 1)/octspergrp + p)] = '\n'; l[++c] = '\0';
+ xxdline(fpo, l, autoskip ? nonzero : 1);
+ nonzero = 0;
+ p = 0;
+ }
+ }
+ if (e == EOF && ferror(fp))
+ die(2);
+ if (p)
+ {
+ l[c = (addrlen + 3 + (grplen * cols - 1)/octspergrp + p)] = '\n'; l[++c] = '\0';
+ xxdline(fpo, l, 1);
+ }
+ else if (autoskip)
+ xxdline(fpo, l, -1); /* last chance to flush out suppressed lines */
+
+ if (fclose(fp))
+ die(2);
+ if (fclose(fpo))
+ die(3);
+ return 0;
+}
+
+/* vi:set ts=8 sw=4 sts=2 cino+={2 cino+=n-2 : */